From 5dff098c148e8fb575959a43b2023c6148329092 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 13 Nov 2026 16:12:43 +0000 Subject: [PATCH] chore(release): version packages --- .changeset/release-bundle-contracts.md | 10 --- .changeset/rfc45-step3a-renderer.md | 16 ----- .changeset/rfc45-step3b-purges.md | 34 --------- .changeset/rfc45-step4-field-operations.md | 18 ----- .changeset/rfc45-step5-mcp.md | 20 ------ .changeset/rfc45-step6a-studio-editor.md | 10 --- .changeset/rfc45-step6b-studio-builder.md | 10 --- .changeset/rfc45-step7a-fixes.md | 10 --- packages/agent-runtime/CHANGELOG.md | 8 +++ packages/agent-runtime/package.json | 2 +- packages/analytics/CHANGELOG.md | 8 +++ packages/analytics/package.json | 2 +- packages/api/CHANGELOG.md | 58 +++++++++++++++ packages/api/package.json | 2 +- packages/astro-renderer/CHANGELOG.md | 31 ++++++++ packages/astro-renderer/package.json | 2 +- packages/cli/CHANGELOG.md | 36 ++++++++++ packages/cli/package.json | 2 +- packages/cloudflare/CHANGELOG.md | 48 +++++++++++++ packages/cloudflare/package.json | 2 +- packages/comments/CHANGELOG.md | 15 ++++ packages/comments/package.json | 2 +- packages/core-contracts/CHANGELOG.md | 11 +++ packages/core-contracts/package.json | 2 +- packages/core-ts/CHANGELOG.md | 84 ++++++++++++++++++++++ packages/core-ts/package.json | 2 +- packages/create-cloudhal/CHANGELOG.md | 7 ++ packages/create-cloudhal/package.json | 2 +- packages/mcp-server/CHANGELOG.md | 67 +++++++++++++++++ packages/mcp-server/package.json | 2 +- packages/schedules/CHANGELOG.md | 8 +++ packages/schedules/package.json | 2 +- packages/storage/CHANGELOG.md | 7 ++ packages/storage/package.json | 2 +- 34 files changed, 401 insertions(+), 141 deletions(-) delete mode 100644 .changeset/release-bundle-contracts.md delete mode 100644 .changeset/rfc45-step3a-renderer.md delete mode 100644 .changeset/rfc45-step3b-purges.md delete mode 100644 .changeset/rfc45-step4-field-operations.md delete mode 100644 .changeset/rfc45-step5-mcp.md delete mode 100644 .changeset/rfc45-step6a-studio-editor.md delete mode 100644 .changeset/rfc45-step6b-studio-builder.md delete mode 100644 .changeset/rfc45-step7a-fixes.md diff --git a/.changeset/release-bundle-contracts.md b/.changeset/release-bundle-contracts.md deleted file mode 100644 index 1294bd67..00000000 --- a/.changeset/release-bundle-contracts.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -"@cloudhal/core-contracts": patch ---- - -Two new contract roots for signed release bundles (RFC-0046), with golden fixtures and the matching Rust types (`ReleaseManifest`, `ReleaseStatement`): - -- **`release-manifest`** (`cloudhal.release-manifest@1`): the manifest of a release bundle. It lists every built Worker module and static asset by size and SHA-256, with the binding templates, feature levels, migration range and rollback facts a remote deployer needs before it uploads anything. `signing.signature` is `release-statement.sig` for project releases; `manifest.sig` is a legacy form for development keys only. -- **`release-statement`** (`cloudhal.release-statement@1`): the small canonical document a release signs (Ed25519, at most 4096 bytes). It names the version, channel, commit and key id, and pins the SHA-256 and size of `manifest.json` and of the tarball. - -Both roots reference `common.schema.json` only for `SchemaVersion` and `Timestamp`, so a deployer can keep an identical copy under its own `$id`. The package root exports only the release-specific types `ReleaseManifest`, `WorkerArtifact`, `BindingTemplate`, `ReleaseStatement` and `StatementAsset`. The local definitions of the two roots stay local: generic names such as `SiteId` or `Capability` mean something else in the rest of the contracts. A test pins their fingerprints. The release signing key and the steps for verifying a release by hand are in `docs/security/release-signing-keys.md`. Nothing changes for existing contracts. diff --git a/.changeset/rfc45-step3a-renderer.md b/.changeset/rfc45-step3a-renderer.md deleted file mode 100644 index 8813d4cd..00000000 --- a/.changeset/rfc45-step3a-renderer.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -"@cloudhal/astro-renderer": minor -"@cloudhal/core-ts": patch ---- - -RFC-0045 rollout step 3a: the renderer resolves reference and repeater fields. Both types stay refused on every write path until rollout step 7, so nothing changes for existing sites. - -- **`@cloudhal/astro-renderer`.** - - `entryFields` resolves a reference to cards (`RenderedField.references`: `ReferencedEntry` with group id, id, collection, locale, slug, title, summary, the graph `path` to link with (the locale middleware localizes it), the canonical `url`, cover image and `fromFallbackLocale`), in stored order, by `pickMember`'s locale rule among the members the source's view shows, gates included. `depth: 2` adds each card's own fields, with their references as cards without fields. Resolution is breadth-first over a visited set of groups, one `groupMembers` call per level, and spends the request's 200 targets (`PlaceholderBudget.references`; `placeholderBudget()` includes it); past the budget the rest resolve to nothing, with one `console.warn` per request. - - A repeater renders its items' sub-fields (`RenderedField.items`), like fields; empty items are left out. - - An unresolved target leaves nothing behind: no id, no title, no empty item. `value` keeps only the resolved group ids. - - `GraphSource.groupMembers?` and `GraphSource.referencedBy?` on `SnapshotSource` (in memory: gate-independent indexes built once per snapshot, filtered per view) and `LiveSource` (one `entry_refs` read expanded by the `shared` rule, each candidate resolved like the snapshot's index). `referencedBy` lists entries whose resolved values name the group, exactly as each page resolves them (a translation reads its original only while the view shows it), newest first with ties by id, at most 100. - - `GraphSource.conversionEntries?` builds the entry maps of a text ↔ reference conversion while one runs (rollout step 4 adds the conversions). - - `EntryFields.astro` draws references as links (`lang` on a fallback-locale card, a `ul.ch-references` for several) and repeaters as an `ol.ch-items` of nested `dl`s. Old theme copies get both with no change of their own. - - The site Worker's `GET /__cloudhal/features` answers `{ "gates": 2, "fields": 2 }`. -- **`@cloudhal/core-ts`.** `getGroupMembers` and `referrerCandidates` (the live renderer's reads, by `site_id`); `conversionEntries`, `conversionTargets`, `conversionCollections` and `foldText` in `./fields`; `resolveFields` takes an optional fourth argument with the conversion maps (`ConvertContext.entries`). diff --git a/.changeset/rfc45-step3b-purges.md b/.changeset/rfc45-step3b-purges.md deleted file mode 100644 index dafe978c..00000000 --- a/.changeset/rfc45-step3b-purges.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -"@cloudhal/core-ts": patch -"@cloudhal/cloudflare": patch -"@cloudhal/mcp-server": patch ---- - -RFC-0045 rollout step 3b: publishes purge the pages that show references. Nothing changes for sites without reference definitions. Their publish purge plans are the same, with no bundle read. Their release runs send the plan stored at pin time, as before, with no re-plan; the only addition is one read of the published site node, to tell them apart. - -- **The referrer closure** (`references/purge.ts`, called by `planCachePurge`). - - The seeds are the groups of every changed, added or removed entry, and of every entry whose shown asset changed. - - It purges the referrers of those groups, two hops deep, with every language version of each referrer. - - It also purges every member of each group a changed entry names, before or after ("used by"). - - Values are resolved, so a translation that only inherits counts. - - It reads only the `from` and `to` snapshots' bodies, never the working copy or `entry_refs`. -- **Reads and budgets.** A publish that changes no entry and no shown asset reads nothing. Otherwise the closure keeps one hash-keyed cache: - - one bundle (`to`'s, else `from`'s), streamed and cut down as each shard is parsed; - - then the missing hashes, read by the closure itself, six at a time, and cut down the same way. - - A passed budget purges everything: - - bytes (`maxBodyBytes`, 32 MB); - - nodes (`maxNodes`, 50,000); - - reads (`maxReads`, shard reads included); - - tags (`maxTags`). - - So does any field-operation marker on either snapshot's site node, for sites that hold references or convert from them. -- **`readSnapshotBundle`** (`SnapshotReader.readSnapshotBundle`, `SiteGraphStore.readSnapshotBundle`, `readSnapshotBundle` in bundles) takes optional `maxBytes`, `maxNodes`, `keep`, `only` (bodies node by node) and `spent` (a shared byte total). A passed budget throws `BundleBudgetError` before the shard is parsed. No new cache tags. -- **Release runs on sites with references re-plan their purge at run time** (`references/release-purge.ts`), from the pointer they moved to the snapshot they made, instead of sending the plan stored at pin time. - - The test is the published site node, which `publishRelease` now returns (`publishedSite`). That costs one blob read per run with a purger, except on a first publish; the read is counted, never refused. If it fails, the working row decides. - - The re-plan runs over the tick's counting driver. - - The release graph's blob calls (`refreshSearch`, `labelOf`, the re-plan) are charged to one allowance per invocation, shared by the cron's ticks (`ScheduledTickOptions.releaseBlobs`): 350 on Workers Free, 3,000 on Paid. "Publish now" sizes it from the deployment's tick budget (`ReleaseService` and `SchedulesDeps.tickBudget`). - - Past the allowance, or if the re-plan fails, the run purges everything. A re-plan with more distinct terms than reads left purges everything before reading anything. - - The pin-time plan skips the closure (`CachePurgeOptions.references: false`): for these sites it is the expected outcome only. - - `RELEASE_EXECUTOR_COST` is 26 (it counts `refreshSearch` and `recordPurge` now). -- **`@cloudhal/cloudflare`:** the cron handler passes one `releaseBlobs` allowance to both ticks of its invocation (`cronTick`); the alarm and the request backstop run one tick each, with the default allowance. diff --git a/.changeset/rfc45-step4-field-operations.md b/.changeset/rfc45-step4-field-operations.md deleted file mode 100644 index edfde757..00000000 --- a/.changeset/rfc45-step4-field-operations.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -"@cloudhal/core-ts": patch -"@cloudhal/api": patch -"@cloudhal/cli": patch ---- - -RFC-0045 rollout step 4: the four field operations work on reference and repeater fields. The types themselves stay refused on every production write path until step 7 (`fields_unsupported`, now from the dry run's check of the definitions the operation ends with); the shared suites enable them with `SiteGraphStoreOptions.fieldTypes`. Nothing changes for operations on the nine existing types. - -- **`sub`** on all four operations (`FieldOperation.sub`, `FieldMigration.sub`): with it, `rename_field`, `change_field_type` and `remove_field` rename, convert or remove one sub-field of a repeater in every item. An item left empty is dropped, and a list left empty is no value. `set_field_localized` refuses `sub` (sub-fields share their repeater's `localized`). Readers, writers and the rows read items through the marker; a top-level reader ignores a sub-field rename's `fromKey` (`renamedFrom`). -- **New `change_field_type` inputs:** `collections`, `maxItems`, `subFields` and `itemLabel`, each refused where the target type does not take it. A reference changes to a reference only to switch `multiple`. A conversion that carries ids over may only widen the target collections. A repeater converts to text or to a reference only with exactly one matching sub-field. -- **New conversion rows** (`fields/conversions-references.ts`): reference single ↔ multiple, text ↔ reference (through the prefetched `ConvertContext.entries` maps, never the entry's own group), multiline text → repeater, repeater → text, and multiple reference ↔ repeater. The maps are read once per operation pass, and by `EntryEngine.write` while such a conversion runs. -- **Text ↔ reference values** are decided by one rule (`fields/text-reference.ts`), per value, from the `entry_refs` rows that phase C's pending check reads too: each operation pass loads the path's rows once, and a person's write reads its node's. A value with its row is kept; a legacy id-shaped text is written as a reference when its group is usable, else reported; a value that does not convert keeps its rows as they are. Readers use a display rule. Rebuilds (pull, push, import, restore) read a converting path through its earlier type. The renderer's conversion maps read archived entries too, so an archived target lends its title. -- **Phase B's target guard** covers only the ids a rewrite newly names; ids a reshape or a rename carries over stay as stored, rows kept. **`set_field_localized`** updates the rows' `shared` in the batch of its site write (phase A, and the revert's). -- **Revert** drops restored references whose group has no member left in the site, and reports them in `FieldRevertResult.dropped`. -- **Values that stop converting while an operation runs** (a target archived or deleted, a second entry with the same title) are reported in `unconvertible` and keep the operation running. `continueFieldOperation` and `revertFieldOperation` take `onInvalid: "clear"` to drop them, as do the admin API's continue and revert routes (in the body) and `cloudhal fields continue|revert --clear`. -- **Releases (#213):** when the read of the published site node fails, the run retries it once, then purges everything; it no longer falls back to the working site row. -- **`multiple`** on a type change to a type that has none is ignored, as before. -- **CLI:** `cloudhal fields retype` takes `--collections a,b`, `--max-items n` and `--sub-fields `, and every action takes `--sub `. The admin API's operation route parses the same inputs. MCP's operation tools take them with rollout step 5. diff --git a/.changeset/rfc45-step5-mcp.md b/.changeset/rfc45-step5-mcp.md deleted file mode 100644 index 3067eabd..00000000 --- a/.changeset/rfc45-step5-mcp.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -"@cloudhal/mcp-server": patch -"@cloudhal/core-ts": patch -"@cloudhal/api": patch ---- - -RFC-0045 rollout step 5: reference and repeater fields over MCP. The two types stay refused on every production write path until step 7 (`fields_unsupported`), and the field inputs do not list them there; a store with `SiteGraphStoreOptions.fieldTypes` gets tools that do. Nothing changes for the nine existing types, except as listed. - -- **`list_collections`** returns, beside `fieldsSchema`, its strict profile `fieldsSchemaStrict` (every key required, `null` for "leave as it is") and `strictCost` (`properties`, `depth`, `enumValues`, `unions`). Reference targets are named by their collections' labels. -- **`create_entry` / `update_entry`** take `fieldsStrict`, for strict structured output, instead of `fields` (`invalid` when both are given): `null` or a missing key leaves a value as it is (on create, no value); `null` sub-values in repeater items are stripped, and items left empty are dropped and reported in `droppedItems`. `update_entry` also takes `clearFields` (set and clear of one key is `invalid`, an unknown key `unknown_field`); on create it is `invalid`. A given reference or repeater value replaces the whole value. -- **Prechecks are the store's own write plan**, run as a dry run: the new `NodeWriteOptions.dryRun` on `createContentEntry`/`updateContentEntry`, and `deleteContentEntry(entry, { dryRun })`, throw the plan-time refusals (values, links, references, a release hold, gates, assets, terms) and write nothing. So `create_entry` and `update_entry` refuse reference targets (`unknown_entry`), repeater items and the references cap before anyone is asked, and `delete_entry` refuses `entry_referenced` with the published referrers. Behaviour change: those prechecks now also run the store's translation-link and canonical-id checks, which the handler ran anyway. -- **Approval prompts** name targets readably, from the dry run's planned entry (canonical ids): `venue → "Main hall" (entry_…, Places)`, `speakers: 2 items → 3 items (added "Ada Lovelace", Speaker; changed item 1: person → "Grace Hopper" (entry_…, People))`, quoted and truncated. -- **New read-only tool `list_references`** (`content:read`) with `direction: "to"` (referrers, published first, with the members that show them) or `"from"` (the groups an entry names, its original's inherited ones included). 110 → 111 tools. The API's `GET …/entries/:entryId/references` and the tool share core-ts's new `listReferrers` (and `listReferenceTargets`, `referenceCard`). -- **`list_entries`** returns each entry's `groupId`, the value a reference stores. -- **Translation tools**: `get_translation_source` lists a localized repeater's text and rich-text sub-values by item path (`speakers/0/talk`) with the source's `sourceRev`; `save_translation` takes them back with that `sourceRev` (`conflict` when the source changed) and folds them into a copy of the source's list, keeping each item's other sub-values (core-ts `translatedItemValues`). Once the translation holds its own list for that repeater, item paths are refused and the list is sent whole; a whole list given together with item paths must have the source's length (`translation_shape_mismatch`, new code, 409 in the API). A path naming no such value is refused. Keys whose first part is not a repeater (`og/image`) stay plain keys. -- **`normalizeEntryFields`** is exported from `@cloudhal/core-ts`: MCP's approval prompts read stored values through the markers exactly as the store does. -- **`continueFieldOperation`** with `onInvalid: "clear"` reports the values it drops as cleared, without the stored request's `field_values_unconvertible` refusal. -- **Removals during `rename_field`** over MCP: the old and the new key are one field; removing either removes both, so the writer's move cannot bring the value back, and setting one while removing the other is `invalid`. -- **Operation tools** take step 4's inputs: `sub` (`rename_field`, `change_field_type`, `remove_field`), `collections`, `maxItems`, `subFields` and `itemLabel` on `change_field_type`, and `onInvalid: "clear"` on a continuation; results carry `unconvertible`. -- **`defineTools({ referenceTypes })`** and `defaultToolList(referenceTypes)`: `createCloudhalMcpServer` passes whether its store has `fieldTypes`. diff --git a/.changeset/rfc45-step6a-studio-editor.md b/.changeset/rfc45-step6a-studio-editor.md deleted file mode 100644 index 81fee596..00000000 --- a/.changeset/rfc45-step6a-studio-editor.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -"@cloudhal/api": patch -"@cloudhal/core-ts": patch ---- - -RFC-0045 rollout step 6a: reference and repeater fields in Studio's entry editor. The two types stay refused on every production write path until step 7 (`fields_unsupported`), so no production collection can define them yet and Studio looks unchanged there. - -- **New read-only route `GET /api/sites/:siteId/entries/groups?ids=a,b`** (`content:read`, in the playground's allow-list): each translation group's members in the site, any status, as `{groupId, id, title, collection, status, locale}` cards (core-ts `getGroupMembers` and `referenceCard`); a group with no member left answers `[]`. One to 100 well-formed group ids (the per-entry reference cap), 400 otherwise, 404 for an unknown site. Studio reads the chosen targets' titles and states through it. -- **`fieldLabel`, `fieldHelp` and `optionLabel`** (`@cloudhal/core-ts/fields`) also take a repeater's sub-field definitions. -- **Studio** (not published): the entry editor's reference fields (`ReferenceList` and `EntryPicker` over `GET …/entries/pick`), repeaters (`RepeaterField`, focus after add and remove, an undo toast, item errors by path), and a "Used by" card from `GET …/entries/:id/references`, with the new `@cloudhal/ui` blocks `FieldControl`, `RepeaterField`, `ReferenceList`, `EntryPicker` and `UsedByList`. They load with the lazy fields chunk; the initial bundle is unchanged. diff --git a/.changeset/rfc45-step6b-studio-builder.md b/.changeset/rfc45-step6b-studio-builder.md deleted file mode 100644 index 817a4f30..00000000 --- a/.changeset/rfc45-step6b-studio-builder.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -"@cloudhal/api": patch ---- - -RFC-0045 rollout step 6b: Studio's fields builder, delete dialog and publish warnings for reference and repeater fields. Both types stay refused on every production write path until step 7, and the builder offers them only where the server takes them, so production Studio is unchanged. - -- **`/api/instance`** reports `features.referenceFields`: true when the store accepts reference and repeater fields (`SiteGraphStoreOptions.fieldTypes`, MCP's rule). -- **`DELETE /api/sites/:siteId/entries/:entryId?rev=&dryRun=1`** runs the store's delete plan and writes nothing: `{ dryRun: true }`, or the plan's refusal (`entry_referenced` with its referrers, `field_operation_running`, …). -- **New read-only route `GET /api/sites/:siteId/entries/reference-issues`** (`content:read`, in the playground's allow-list): `referenceIssues` over the working copy, the first 50 with each holder's title, and the total. -- **Studio** (not published): reference and list fields in the builder (target collections, "Several", the maximum and conditions; item fields with up/down and ⋯, the maximum and the item name), sub-field operations and reference/list targets in "Change type…", a cleared finish for a run stuck on values that stopped converting, the delete dialog's reference rules (off while published entries show the last entry, drafts that will show nothing, the language that loses the card), publish warnings, and worded API errors for the RFC-0045 refusals. diff --git a/.changeset/rfc45-step7a-fixes.md b/.changeset/rfc45-step7a-fixes.md deleted file mode 100644 index 1834fb6a..00000000 --- a/.changeset/rfc45-step7a-fixes.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -"@cloudhal/core-ts": patch -"@cloudhal/mcp-server": patch ---- - -RFC-0045 rollout step 7a: two fixes ahead of enabling reference and repeater fields. Both types stay refused on every production write path until step 7b; nothing changes for the nine existing types. - -- **core-ts (#215).** While a top-level conversion from references runs without a text ↔ reference path (reference (multiple) ↔ repeater, reference single ↔ multiple, a repeater converting away), a stored value still in the old shape that does not convert keeps its `entry_refs` rows through a person's unrelated write, such as a title edit. Before, the write dropped them, and the target's delete guard under-blocked. The writer holds the rows at the old type's paths, the same ones the import rebuild keeps (one helper, `oldShapePairs`), so the rows no longer depend on which touched the entry last. -- **core-ts: held rows follow their holder's status.** A row a write holds (a value a running conversion did not accept, here or during a text ↔ reference conversion) kept the `source_status` of its last insert, so publishing the holder left the target deletable and unpublishing left it locked. The write now updates the held rows' `source_status` in the same batch, anchored on the entry's new hash. -- **mcp-server, core-ts (#218).** Once a translation holds its own list for a localized repeater, `get_translation_source` returns the source's whole list for that key under `fields` (in the source's order, with every sub-value) instead of item paths, and names it in the new `wholeLists` output: send it back whole, translated. `save_translation` already refused item paths there (`translation_shape_mismatch`); its hint and the tool descriptions now say what to send. `save_translation` also checks a given `sourceRev` against whole repeater lists (`conflict` when the source moved on); without one they save as before. New core-ts export: `translationSourceValues`. diff --git a/packages/agent-runtime/CHANGELOG.md b/packages/agent-runtime/CHANGELOG.md index 509787cc..0a999d3e 100644 --- a/packages/agent-runtime/CHANGELOG.md +++ b/packages/agent-runtime/CHANGELOG.md @@ -1,5 +1,13 @@ # @cloudhal/agent-runtime +## 0.9.0 + +### Patch Changes + +- Updated dependencies [3b8e846] + - @cloudhal/core-contracts@0.9.0 + - @cloudhal/storage@0.9.0 + ## 0.8.0 ### Patch Changes diff --git a/packages/agent-runtime/package.json b/packages/agent-runtime/package.json index 2b417c16..b1bec95a 100644 --- a/packages/agent-runtime/package.json +++ b/packages/agent-runtime/package.json @@ -1,6 +1,6 @@ { "name": "@cloudhal/agent-runtime", - "version": "0.8.0", + "version": "0.9.0", "description": "Cloudhal agent runtime: policy engine (actors, scopes, approvals), skill loader, audit log", "license": "Apache-2.0", "homepage": "https://cloudhal.dev", diff --git a/packages/analytics/CHANGELOG.md b/packages/analytics/CHANGELOG.md index cbf07b98..80acbcd8 100644 --- a/packages/analytics/CHANGELOG.md +++ b/packages/analytics/CHANGELOG.md @@ -1,5 +1,13 @@ # @cloudhal/analytics +## 0.9.0 + +### Patch Changes + +- Updated dependencies [3b8e846] + - @cloudhal/core-contracts@0.9.0 + - @cloudhal/storage@0.9.0 + ## 0.8.0 ### Patch Changes diff --git a/packages/analytics/package.json b/packages/analytics/package.json index aec6ea39..244da050 100644 --- a/packages/analytics/package.json +++ b/packages/analytics/package.json @@ -1,6 +1,6 @@ { "name": "@cloudhal/analytics", - "version": "0.8.0", + "version": "0.9.0", "description": "Cloudhal site analytics (RFC-0006): query model, classifiers, beacon handler, SQLite/D1 store, daily rollups and Workers Analytics Engine adapters. Worker-safe.", "license": "Apache-2.0", "homepage": "https://cloudhal.dev", diff --git a/packages/api/CHANGELOG.md b/packages/api/CHANGELOG.md index 2e039a9c..6b7ed55e 100644 --- a/packages/api/CHANGELOG.md +++ b/packages/api/CHANGELOG.md @@ -1,5 +1,63 @@ # @cloudhal/api +## 0.9.0 + +### Patch Changes + +- bb43a16: RFC-0045 rollout step 4: the four field operations work on reference and repeater fields. The types themselves stay refused on every production write path until step 7 (`fields_unsupported`, now from the dry run's check of the definitions the operation ends with); the shared suites enable them with `SiteGraphStoreOptions.fieldTypes`. Nothing changes for operations on the nine existing types. + + - **`sub`** on all four operations (`FieldOperation.sub`, `FieldMigration.sub`): with it, `rename_field`, `change_field_type` and `remove_field` rename, convert or remove one sub-field of a repeater in every item. An item left empty is dropped, and a list left empty is no value. `set_field_localized` refuses `sub` (sub-fields share their repeater's `localized`). Readers, writers and the rows read items through the marker; a top-level reader ignores a sub-field rename's `fromKey` (`renamedFrom`). + - **New `change_field_type` inputs:** `collections`, `maxItems`, `subFields` and `itemLabel`, each refused where the target type does not take it. A reference changes to a reference only to switch `multiple`. A conversion that carries ids over may only widen the target collections. A repeater converts to text or to a reference only with exactly one matching sub-field. + - **New conversion rows** (`fields/conversions-references.ts`): reference single ↔ multiple, text ↔ reference (through the prefetched `ConvertContext.entries` maps, never the entry's own group), multiline text → repeater, repeater → text, and multiple reference ↔ repeater. The maps are read once per operation pass, and by `EntryEngine.write` while such a conversion runs. + - **Text ↔ reference values** are decided by one rule (`fields/text-reference.ts`), per value, from the `entry_refs` rows that phase C's pending check reads too: each operation pass loads the path's rows once, and a person's write reads its node's. A value with its row is kept; a legacy id-shaped text is written as a reference when its group is usable, else reported; a value that does not convert keeps its rows as they are. Readers use a display rule. Rebuilds (pull, push, import, restore) read a converting path through its earlier type. The renderer's conversion maps read archived entries too, so an archived target lends its title. + - **Phase B's target guard** covers only the ids a rewrite newly names; ids a reshape or a rename carries over stay as stored, rows kept. **`set_field_localized`** updates the rows' `shared` in the batch of its site write (phase A, and the revert's). + - **Revert** drops restored references whose group has no member left in the site, and reports them in `FieldRevertResult.dropped`. + - **Values that stop converting while an operation runs** (a target archived or deleted, a second entry with the same title) are reported in `unconvertible` and keep the operation running. `continueFieldOperation` and `revertFieldOperation` take `onInvalid: "clear"` to drop them, as do the admin API's continue and revert routes (in the body) and `cloudhal fields continue|revert --clear`. + - **Releases (#213):** when the read of the published site node fails, the run retries it once, then purges everything; it no longer falls back to the working site row. + - **`multiple`** on a type change to a type that has none is ignored, as before. + - **CLI:** `cloudhal fields retype` takes `--collections a,b`, `--max-items n` and `--sub-fields `, and every action takes `--sub `. The admin API's operation route parses the same inputs. MCP's operation tools take them with rollout step 5. +- dda55ee: RFC-0045 rollout step 5: reference and repeater fields over MCP. The two types stay refused on every production write path until step 7 (`fields_unsupported`), and the field inputs do not list them there; a store with `SiteGraphStoreOptions.fieldTypes` gets tools that do. Nothing changes for the nine existing types, except as listed. + + - **`list_collections`** returns, beside `fieldsSchema`, its strict profile `fieldsSchemaStrict` (every key required, `null` for "leave as it is") and `strictCost` (`properties`, `depth`, `enumValues`, `unions`). Reference targets are named by their collections' labels. + - **`create_entry` / `update_entry`** take `fieldsStrict`, for strict structured output, instead of `fields` (`invalid` when both are given): `null` or a missing key leaves a value as it is (on create, no value); `null` sub-values in repeater items are stripped, and items left empty are dropped and reported in `droppedItems`. `update_entry` also takes `clearFields` (set and clear of one key is `invalid`, an unknown key `unknown_field`); on create it is `invalid`. A given reference or repeater value replaces the whole value. + - **Prechecks are the store's own write plan**, run as a dry run: the new `NodeWriteOptions.dryRun` on `createContentEntry`/`updateContentEntry`, and `deleteContentEntry(entry, { dryRun })`, throw the plan-time refusals (values, links, references, a release hold, gates, assets, terms) and write nothing. So `create_entry` and `update_entry` refuse reference targets (`unknown_entry`), repeater items and the references cap before anyone is asked, and `delete_entry` refuses `entry_referenced` with the published referrers. Behaviour change: those prechecks now also run the store's translation-link and canonical-id checks, which the handler ran anyway. + - **Approval prompts** name targets readably, from the dry run's planned entry (canonical ids): `venue → "Main hall" (entry_…, Places)`, `speakers: 2 items → 3 items (added "Ada Lovelace", Speaker; changed item 1: person → "Grace Hopper" (entry_…, People))`, quoted and truncated. + - **New read-only tool `list_references`** (`content:read`) with `direction: "to"` (referrers, published first, with the members that show them) or `"from"` (the groups an entry names, its original's inherited ones included). 110 → 111 tools. The API's `GET …/entries/:entryId/references` and the tool share core-ts's new `listReferrers` (and `listReferenceTargets`, `referenceCard`). + - **`list_entries`** returns each entry's `groupId`, the value a reference stores. + - **Translation tools**: `get_translation_source` lists a localized repeater's text and rich-text sub-values by item path (`speakers/0/talk`) with the source's `sourceRev`; `save_translation` takes them back with that `sourceRev` (`conflict` when the source changed) and folds them into a copy of the source's list, keeping each item's other sub-values (core-ts `translatedItemValues`). Once the translation holds its own list for that repeater, item paths are refused and the list is sent whole; a whole list given together with item paths must have the source's length (`translation_shape_mismatch`, new code, 409 in the API). A path naming no such value is refused. Keys whose first part is not a repeater (`og/image`) stay plain keys. + - **`normalizeEntryFields`** is exported from `@cloudhal/core-ts`: MCP's approval prompts read stored values through the markers exactly as the store does. + - **`continueFieldOperation`** with `onInvalid: "clear"` reports the values it drops as cleared, without the stored request's `field_values_unconvertible` refusal. + - **Removals during `rename_field`** over MCP: the old and the new key are one field; removing either removes both, so the writer's move cannot bring the value back, and setting one while removing the other is `invalid`. + - **Operation tools** take step 4's inputs: `sub` (`rename_field`, `change_field_type`, `remove_field`), `collections`, `maxItems`, `subFields` and `itemLabel` on `change_field_type`, and `onInvalid: "clear"` on a continuation; results carry `unconvertible`. + - **`defineTools({ referenceTypes })`** and `defaultToolList(referenceTypes)`: `createCloudhalMcpServer` passes whether its store has `fieldTypes`. +- 3678855: RFC-0045 rollout step 6a: reference and repeater fields in Studio's entry editor. The two types stay refused on every production write path until step 7 (`fields_unsupported`), so no production collection can define them yet and Studio looks unchanged there. + + - **New read-only route `GET /api/sites/:siteId/entries/groups?ids=a,b`** (`content:read`, in the playground's allow-list): each translation group's members in the site, any status, as `{groupId, id, title, collection, status, locale}` cards (core-ts `getGroupMembers` and `referenceCard`); a group with no member left answers `[]`. One to 100 well-formed group ids (the per-entry reference cap), 400 otherwise, 404 for an unknown site. Studio reads the chosen targets' titles and states through it. + - **`fieldLabel`, `fieldHelp` and `optionLabel`** (`@cloudhal/core-ts/fields`) also take a repeater's sub-field definitions. + - **Studio** (not published): the entry editor's reference fields (`ReferenceList` and `EntryPicker` over `GET …/entries/pick`), repeaters (`RepeaterField`, focus after add and remove, an undo toast, item errors by path), and a "Used by" card from `GET …/entries/:id/references`, with the new `@cloudhal/ui` blocks `FieldControl`, `RepeaterField`, `ReferenceList`, `EntryPicker` and `UsedByList`. They load with the lazy fields chunk; the initial bundle is unchanged. +- b7ac2e9: RFC-0045 rollout step 6b: Studio's fields builder, delete dialog and publish warnings for reference and repeater fields. Both types stay refused on every production write path until step 7, and the builder offers them only where the server takes them, so production Studio is unchanged. + + - **`/api/instance`** reports `features.referenceFields`: true when the store accepts reference and repeater fields (`SiteGraphStoreOptions.fieldTypes`, MCP's rule). + - **`DELETE /api/sites/:siteId/entries/:entryId?rev=&dryRun=1`** runs the store's delete plan and writes nothing: `{ dryRun: true }`, or the plan's refusal (`entry_referenced` with its referrers, `field_operation_running`, …). + - **New read-only route `GET /api/sites/:siteId/entries/reference-issues`** (`content:read`, in the playground's allow-list): `referenceIssues` over the working copy, the first 50 with each holder's title, and the total. + - **Studio** (not published): reference and list fields in the builder (target collections, "Several", the maximum and conditions; item fields with up/down and ⋯, the maximum and the item name), sub-field operations and reference/list targets in "Change type…", a cleared finish for a run stuck on values that stopped converting, the delete dialog's reference rules (off while published entries show the last entry, drafts that will show nothing, the language that loses the card), publish warnings, and worded API errors for the RFC-0045 refusals. +- Updated dependencies [3b8e846] +- Updated dependencies [41d783a] +- Updated dependencies [9aa67d3] +- Updated dependencies [bb43a16] +- Updated dependencies [dda55ee] +- Updated dependencies [3678855] +- Updated dependencies [4a5633d] + - @cloudhal/core-contracts@0.9.0 + - @cloudhal/astro-renderer@0.9.0 + - @cloudhal/core-ts@0.9.0 + - @cloudhal/mcp-server@0.9.0 + - @cloudhal/agent-runtime@0.9.0 + - @cloudhal/analytics@0.9.0 + - @cloudhal/comments@0.9.0 + - @cloudhal/schedules@0.9.0 + - @cloudhal/storage@0.9.0 + ## 0.8.0 ### Minor Changes diff --git a/packages/api/package.json b/packages/api/package.json index e322db80..a1d03aee 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -1,6 +1,6 @@ { "name": "@cloudhal/api", - "version": "0.8.0", + "version": "0.9.0", "description": "Cloudhal HTTP API (Hono): sites, pages, entries, snapshots, auth — runs on Node and Cloudflare Workers", "license": "Apache-2.0", "homepage": "https://cloudhal.dev", diff --git a/packages/astro-renderer/CHANGELOG.md b/packages/astro-renderer/CHANGELOG.md index cf6b1356..5c36e83e 100644 --- a/packages/astro-renderer/CHANGELOG.md +++ b/packages/astro-renderer/CHANGELOG.md @@ -1,5 +1,36 @@ # @cloudhal/astro-renderer +## 0.9.0 + +### Minor Changes + +- 41d783a: RFC-0045 rollout step 3a: the renderer resolves reference and repeater fields. Both types stay refused on every write path until rollout step 7, so nothing changes for existing sites. + + - **`@cloudhal/astro-renderer`.** + - `entryFields` resolves a reference to cards (`RenderedField.references`: `ReferencedEntry` with group id, id, collection, locale, slug, title, summary, the graph `path` to link with (the locale middleware localizes it), the canonical `url`, cover image and `fromFallbackLocale`), in stored order, by `pickMember`'s locale rule among the members the source's view shows, gates included. `depth: 2` adds each card's own fields, with their references as cards without fields. Resolution is breadth-first over a visited set of groups, one `groupMembers` call per level, and spends the request's 200 targets (`PlaceholderBudget.references`; `placeholderBudget()` includes it); past the budget the rest resolve to nothing, with one `console.warn` per request. + - A repeater renders its items' sub-fields (`RenderedField.items`), like fields; empty items are left out. + - An unresolved target leaves nothing behind: no id, no title, no empty item. `value` keeps only the resolved group ids. + - `GraphSource.groupMembers?` and `GraphSource.referencedBy?` on `SnapshotSource` (in memory: gate-independent indexes built once per snapshot, filtered per view) and `LiveSource` (one `entry_refs` read expanded by the `shared` rule, each candidate resolved like the snapshot's index). `referencedBy` lists entries whose resolved values name the group, exactly as each page resolves them (a translation reads its original only while the view shows it), newest first with ties by id, at most 100. + - `GraphSource.conversionEntries?` builds the entry maps of a text ↔ reference conversion while one runs (rollout step 4 adds the conversions). + - `EntryFields.astro` draws references as links (`lang` on a fallback-locale card, a `ul.ch-references` for several) and repeaters as an `ol.ch-items` of nested `dl`s. Old theme copies get both with no change of their own. + - The site Worker's `GET /__cloudhal/features` answers `{ "gates": 2, "fields": 2 }`. + - **`@cloudhal/core-ts`.** `getGroupMembers` and `referrerCandidates` (the live renderer's reads, by `site_id`); `conversionEntries`, `conversionTargets`, `conversionCollections` and `foldText` in `./fields`; `resolveFields` takes an optional fourth argument with the conversion maps (`ConvertContext.entries`). + +### Patch Changes + +- Updated dependencies [3b8e846] +- Updated dependencies [41d783a] +- Updated dependencies [9aa67d3] +- Updated dependencies [bb43a16] +- Updated dependencies [dda55ee] +- Updated dependencies [3678855] +- Updated dependencies [4a5633d] + - @cloudhal/core-contracts@0.9.0 + - @cloudhal/core-ts@0.9.0 + - @cloudhal/analytics@0.9.0 + - @cloudhal/comments@0.9.0 + - @cloudhal/storage@0.9.0 + ## 0.8.0 ### Patch Changes diff --git a/packages/astro-renderer/package.json b/packages/astro-renderer/package.json index 52cf9942..72e63f35 100644 --- a/packages/astro-renderer/package.json +++ b/packages/astro-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@cloudhal/astro-renderer", - "version": "0.8.0", + "version": "0.9.0", "description": "Render a Cloudhal Site Graph with Astro: data sources (live/snapshot), section components and the cloudhal() integration", "license": "Apache-2.0", "homepage": "https://cloudhal.dev", diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index 6a5fe237..a977909b 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -1,5 +1,41 @@ # @cloudhal/cli +## 0.9.0 + +### Patch Changes + +- bb43a16: RFC-0045 rollout step 4: the four field operations work on reference and repeater fields. The types themselves stay refused on every production write path until step 7 (`fields_unsupported`, now from the dry run's check of the definitions the operation ends with); the shared suites enable them with `SiteGraphStoreOptions.fieldTypes`. Nothing changes for operations on the nine existing types. + + - **`sub`** on all four operations (`FieldOperation.sub`, `FieldMigration.sub`): with it, `rename_field`, `change_field_type` and `remove_field` rename, convert or remove one sub-field of a repeater in every item. An item left empty is dropped, and a list left empty is no value. `set_field_localized` refuses `sub` (sub-fields share their repeater's `localized`). Readers, writers and the rows read items through the marker; a top-level reader ignores a sub-field rename's `fromKey` (`renamedFrom`). + - **New `change_field_type` inputs:** `collections`, `maxItems`, `subFields` and `itemLabel`, each refused where the target type does not take it. A reference changes to a reference only to switch `multiple`. A conversion that carries ids over may only widen the target collections. A repeater converts to text or to a reference only with exactly one matching sub-field. + - **New conversion rows** (`fields/conversions-references.ts`): reference single ↔ multiple, text ↔ reference (through the prefetched `ConvertContext.entries` maps, never the entry's own group), multiline text → repeater, repeater → text, and multiple reference ↔ repeater. The maps are read once per operation pass, and by `EntryEngine.write` while such a conversion runs. + - **Text ↔ reference values** are decided by one rule (`fields/text-reference.ts`), per value, from the `entry_refs` rows that phase C's pending check reads too: each operation pass loads the path's rows once, and a person's write reads its node's. A value with its row is kept; a legacy id-shaped text is written as a reference when its group is usable, else reported; a value that does not convert keeps its rows as they are. Readers use a display rule. Rebuilds (pull, push, import, restore) read a converting path through its earlier type. The renderer's conversion maps read archived entries too, so an archived target lends its title. + - **Phase B's target guard** covers only the ids a rewrite newly names; ids a reshape or a rename carries over stay as stored, rows kept. **`set_field_localized`** updates the rows' `shared` in the batch of its site write (phase A, and the revert's). + - **Revert** drops restored references whose group has no member left in the site, and reports them in `FieldRevertResult.dropped`. + - **Values that stop converting while an operation runs** (a target archived or deleted, a second entry with the same title) are reported in `unconvertible` and keep the operation running. `continueFieldOperation` and `revertFieldOperation` take `onInvalid: "clear"` to drop them, as do the admin API's continue and revert routes (in the body) and `cloudhal fields continue|revert --clear`. + - **Releases (#213):** when the read of the published site node fails, the run retries it once, then purges everything; it no longer falls back to the working site row. + - **`multiple`** on a type change to a type that has none is ignored, as before. + - **CLI:** `cloudhal fields retype` takes `--collections a,b`, `--max-items n` and `--sub-fields `, and every action takes `--sub `. The admin API's operation route parses the same inputs. MCP's operation tools take them with rollout step 5. +- Updated dependencies [3b8e846] +- Updated dependencies [41d783a] +- Updated dependencies [9aa67d3] +- Updated dependencies [bb43a16] +- Updated dependencies [dda55ee] +- Updated dependencies [3678855] +- Updated dependencies [b7ac2e9] +- Updated dependencies [4a5633d] + - @cloudhal/core-contracts@0.9.0 + - @cloudhal/astro-renderer@0.9.0 + - @cloudhal/core-ts@0.9.0 + - @cloudhal/cloudflare@0.9.0 + - @cloudhal/mcp-server@0.9.0 + - @cloudhal/api@0.9.0 + - @cloudhal/agent-runtime@0.9.0 + - @cloudhal/analytics@0.9.0 + - @cloudhal/comments@0.9.0 + - @cloudhal/schedules@0.9.0 + - @cloudhal/storage@0.9.0 + ## 0.8.0 ### Patch Changes diff --git a/packages/cli/package.json b/packages/cli/package.json index abf7a7ba..d15e418b 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@cloudhal/cli", - "version": "0.8.0", + "version": "0.9.0", "description": "cloudhal — create, run and build Cloudhal sites locally", "license": "Apache-2.0", "homepage": "https://cloudhal.dev", diff --git a/packages/cloudflare/CHANGELOG.md b/packages/cloudflare/CHANGELOG.md index 6a34f4a7..bec89b9c 100644 --- a/packages/cloudflare/CHANGELOG.md +++ b/packages/cloudflare/CHANGELOG.md @@ -1,5 +1,53 @@ # @cloudhal/cloudflare +## 0.9.0 + +### Patch Changes + +- 9aa67d3: RFC-0045 rollout step 3b: publishes purge the pages that show references. Nothing changes for sites without reference definitions. Their publish purge plans are the same, with no bundle read. Their release runs send the plan stored at pin time, as before, with no re-plan; the only addition is one read of the published site node, to tell them apart. + + - **The referrer closure** (`references/purge.ts`, called by `planCachePurge`). + - The seeds are the groups of every changed, added or removed entry, and of every entry whose shown asset changed. + - It purges the referrers of those groups, two hops deep, with every language version of each referrer. + - It also purges every member of each group a changed entry names, before or after ("used by"). + - Values are resolved, so a translation that only inherits counts. + - It reads only the `from` and `to` snapshots' bodies, never the working copy or `entry_refs`. + - **Reads and budgets.** A publish that changes no entry and no shown asset reads nothing. Otherwise the closure keeps one hash-keyed cache: + - one bundle (`to`'s, else `from`'s), streamed and cut down as each shard is parsed; + - then the missing hashes, read by the closure itself, six at a time, and cut down the same way. + + A passed budget purges everything: + - bytes (`maxBodyBytes`, 32 MB); + - nodes (`maxNodes`, 50,000); + - reads (`maxReads`, shard reads included); + - tags (`maxTags`). + + So does any field-operation marker on either snapshot's site node, for sites that hold references or convert from them. + - **`readSnapshotBundle`** (`SnapshotReader.readSnapshotBundle`, `SiteGraphStore.readSnapshotBundle`, `readSnapshotBundle` in bundles) takes optional `maxBytes`, `maxNodes`, `keep`, `only` (bodies node by node) and `spent` (a shared byte total). A passed budget throws `BundleBudgetError` before the shard is parsed. No new cache tags. + - **Release runs on sites with references re-plan their purge at run time** (`references/release-purge.ts`), from the pointer they moved to the snapshot they made, instead of sending the plan stored at pin time. + - The test is the published site node, which `publishRelease` now returns (`publishedSite`). That costs one blob read per run with a purger, except on a first publish; the read is counted, never refused. If it fails, the working row decides. + - The re-plan runs over the tick's counting driver. + - The release graph's blob calls (`refreshSearch`, `labelOf`, the re-plan) are charged to one allowance per invocation, shared by the cron's ticks (`ScheduledTickOptions.releaseBlobs`): 350 on Workers Free, 3,000 on Paid. "Publish now" sizes it from the deployment's tick budget (`ReleaseService` and `SchedulesDeps.tickBudget`). + - Past the allowance, or if the re-plan fails, the run purges everything. A re-plan with more distinct terms than reads left purges everything before reading anything. + - The pin-time plan skips the closure (`CachePurgeOptions.references: false`): for these sites it is the expected outcome only. + - `RELEASE_EXECUTOR_COST` is 26 (it counts `refreshSearch` and `recordPurge` now). + - **`@cloudhal/cloudflare`:** the cron handler passes one `releaseBlobs` allowance to both ticks of its invocation (`cronTick`); the alarm and the request backstop run one tick each, with the default allowance. +- Updated dependencies [41d783a] +- Updated dependencies [9aa67d3] +- Updated dependencies [bb43a16] +- Updated dependencies [dda55ee] +- Updated dependencies [3678855] +- Updated dependencies [b7ac2e9] +- Updated dependencies [4a5633d] + - @cloudhal/core-ts@0.9.0 + - @cloudhal/mcp-server@0.9.0 + - @cloudhal/api@0.9.0 + - @cloudhal/agent-runtime@0.9.0 + - @cloudhal/analytics@0.9.0 + - @cloudhal/comments@0.9.0 + - @cloudhal/schedules@0.9.0 + - @cloudhal/storage@0.9.0 + ## 0.8.0 ### Patch Changes diff --git a/packages/cloudflare/package.json b/packages/cloudflare/package.json index bc7342ab..24c3bd1c 100644 --- a/packages/cloudflare/package.json +++ b/packages/cloudflare/package.json @@ -1,6 +1,6 @@ { "name": "@cloudhal/cloudflare", - "version": "0.8.0", + "version": "0.9.0", "description": "Cloudhal on Cloudflare: the admin Worker (API, auth, MCP, Studio) over D1 + R2", "license": "Apache-2.0", "homepage": "https://cloudhal.dev", diff --git a/packages/comments/CHANGELOG.md b/packages/comments/CHANGELOG.md index e2f326ca..c7d8439e 100644 --- a/packages/comments/CHANGELOG.md +++ b/packages/comments/CHANGELOG.md @@ -1,5 +1,20 @@ # @cloudhal/comments +## 0.9.0 + +### Patch Changes + +- Updated dependencies [3b8e846] +- Updated dependencies [41d783a] +- Updated dependencies [9aa67d3] +- Updated dependencies [bb43a16] +- Updated dependencies [dda55ee] +- Updated dependencies [3678855] +- Updated dependencies [4a5633d] + - @cloudhal/core-contracts@0.9.0 + - @cloudhal/core-ts@0.9.0 + - @cloudhal/storage@0.9.0 + ## 0.8.0 ### Patch Changes diff --git a/packages/comments/package.json b/packages/comments/package.json index fd3aa4a2..c713b959 100644 --- a/packages/comments/package.json +++ b/packages/comments/package.json @@ -1,6 +1,6 @@ { "name": "@cloudhal/comments", - "version": "0.8.0", + "version": "0.9.0", "description": "Cloudhal reader comments (RFC-0007): settings and thread state, text normalising and content rules, linkify, first-party proof of work, the submission pipeline, purge planner, retention plan and the SQLite/D1 store. Worker-safe.", "license": "Apache-2.0", "homepage": "https://cloudhal.dev", diff --git a/packages/core-contracts/CHANGELOG.md b/packages/core-contracts/CHANGELOG.md index 5239fec0..f0669b90 100644 --- a/packages/core-contracts/CHANGELOG.md +++ b/packages/core-contracts/CHANGELOG.md @@ -1,5 +1,16 @@ # @cloudhal/core-contracts +## 0.9.0 + +### Patch Changes + +- 3b8e846: Two new contract roots for signed release bundles (RFC-0046), with golden fixtures and the matching Rust types (`ReleaseManifest`, `ReleaseStatement`): + + - **`release-manifest`** (`cloudhal.release-manifest@1`): the manifest of a release bundle. It lists every built Worker module and static asset by size and SHA-256, with the binding templates, feature levels, migration range and rollback facts a remote deployer needs before it uploads anything. `signing.signature` is `release-statement.sig` for project releases; `manifest.sig` is a legacy form for development keys only. + - **`release-statement`** (`cloudhal.release-statement@1`): the small canonical document a release signs (Ed25519, at most 4096 bytes). It names the version, channel, commit and key id, and pins the SHA-256 and size of `manifest.json` and of the tarball. + + Both roots reference `common.schema.json` only for `SchemaVersion` and `Timestamp`, so a deployer can keep an identical copy under its own `$id`. The package root exports only the release-specific types `ReleaseManifest`, `WorkerArtifact`, `BindingTemplate`, `ReleaseStatement` and `StatementAsset`. The local definitions of the two roots stay local: generic names such as `SiteId` or `Capability` mean something else in the rest of the contracts. A test pins their fingerprints. The release signing key and the steps for verifying a release by hand are in `docs/security/release-signing-keys.md`. Nothing changes for existing contracts. + ## 0.8.0 ### Minor Changes diff --git a/packages/core-contracts/package.json b/packages/core-contracts/package.json index d793bfa1..1549b990 100644 --- a/packages/core-contracts/package.json +++ b/packages/core-contracts/package.json @@ -1,6 +1,6 @@ { "name": "@cloudhal/core-contracts", - "version": "0.8.0", + "version": "0.9.0", "description": "Cloudhal domain contracts: JSON Schema source of truth plus generated TypeScript types", "license": "Apache-2.0", "homepage": "https://cloudhal.dev", diff --git a/packages/core-ts/CHANGELOG.md b/packages/core-ts/CHANGELOG.md index 3b465ee9..4ddc5934 100644 --- a/packages/core-ts/CHANGELOG.md +++ b/packages/core-ts/CHANGELOG.md @@ -1,5 +1,89 @@ # @cloudhal/core-ts +## 0.9.0 + +### Patch Changes + +- 41d783a: RFC-0045 rollout step 3a: the renderer resolves reference and repeater fields. Both types stay refused on every write path until rollout step 7, so nothing changes for existing sites. + + - **`@cloudhal/astro-renderer`.** + - `entryFields` resolves a reference to cards (`RenderedField.references`: `ReferencedEntry` with group id, id, collection, locale, slug, title, summary, the graph `path` to link with (the locale middleware localizes it), the canonical `url`, cover image and `fromFallbackLocale`), in stored order, by `pickMember`'s locale rule among the members the source's view shows, gates included. `depth: 2` adds each card's own fields, with their references as cards without fields. Resolution is breadth-first over a visited set of groups, one `groupMembers` call per level, and spends the request's 200 targets (`PlaceholderBudget.references`; `placeholderBudget()` includes it); past the budget the rest resolve to nothing, with one `console.warn` per request. + - A repeater renders its items' sub-fields (`RenderedField.items`), like fields; empty items are left out. + - An unresolved target leaves nothing behind: no id, no title, no empty item. `value` keeps only the resolved group ids. + - `GraphSource.groupMembers?` and `GraphSource.referencedBy?` on `SnapshotSource` (in memory: gate-independent indexes built once per snapshot, filtered per view) and `LiveSource` (one `entry_refs` read expanded by the `shared` rule, each candidate resolved like the snapshot's index). `referencedBy` lists entries whose resolved values name the group, exactly as each page resolves them (a translation reads its original only while the view shows it), newest first with ties by id, at most 100. + - `GraphSource.conversionEntries?` builds the entry maps of a text ↔ reference conversion while one runs (rollout step 4 adds the conversions). + - `EntryFields.astro` draws references as links (`lang` on a fallback-locale card, a `ul.ch-references` for several) and repeaters as an `ol.ch-items` of nested `dl`s. Old theme copies get both with no change of their own. + - The site Worker's `GET /__cloudhal/features` answers `{ "gates": 2, "fields": 2 }`. + - **`@cloudhal/core-ts`.** `getGroupMembers` and `referrerCandidates` (the live renderer's reads, by `site_id`); `conversionEntries`, `conversionTargets`, `conversionCollections` and `foldText` in `./fields`; `resolveFields` takes an optional fourth argument with the conversion maps (`ConvertContext.entries`). +- 9aa67d3: RFC-0045 rollout step 3b: publishes purge the pages that show references. Nothing changes for sites without reference definitions. Their publish purge plans are the same, with no bundle read. Their release runs send the plan stored at pin time, as before, with no re-plan; the only addition is one read of the published site node, to tell them apart. + + - **The referrer closure** (`references/purge.ts`, called by `planCachePurge`). + - The seeds are the groups of every changed, added or removed entry, and of every entry whose shown asset changed. + - It purges the referrers of those groups, two hops deep, with every language version of each referrer. + - It also purges every member of each group a changed entry names, before or after ("used by"). + - Values are resolved, so a translation that only inherits counts. + - It reads only the `from` and `to` snapshots' bodies, never the working copy or `entry_refs`. + - **Reads and budgets.** A publish that changes no entry and no shown asset reads nothing. Otherwise the closure keeps one hash-keyed cache: + - one bundle (`to`'s, else `from`'s), streamed and cut down as each shard is parsed; + - then the missing hashes, read by the closure itself, six at a time, and cut down the same way. + + A passed budget purges everything: + - bytes (`maxBodyBytes`, 32 MB); + - nodes (`maxNodes`, 50,000); + - reads (`maxReads`, shard reads included); + - tags (`maxTags`). + + So does any field-operation marker on either snapshot's site node, for sites that hold references or convert from them. + - **`readSnapshotBundle`** (`SnapshotReader.readSnapshotBundle`, `SiteGraphStore.readSnapshotBundle`, `readSnapshotBundle` in bundles) takes optional `maxBytes`, `maxNodes`, `keep`, `only` (bodies node by node) and `spent` (a shared byte total). A passed budget throws `BundleBudgetError` before the shard is parsed. No new cache tags. + - **Release runs on sites with references re-plan their purge at run time** (`references/release-purge.ts`), from the pointer they moved to the snapshot they made, instead of sending the plan stored at pin time. + - The test is the published site node, which `publishRelease` now returns (`publishedSite`). That costs one blob read per run with a purger, except on a first publish; the read is counted, never refused. If it fails, the working row decides. + - The re-plan runs over the tick's counting driver. + - The release graph's blob calls (`refreshSearch`, `labelOf`, the re-plan) are charged to one allowance per invocation, shared by the cron's ticks (`ScheduledTickOptions.releaseBlobs`): 350 on Workers Free, 3,000 on Paid. "Publish now" sizes it from the deployment's tick budget (`ReleaseService` and `SchedulesDeps.tickBudget`). + - Past the allowance, or if the re-plan fails, the run purges everything. A re-plan with more distinct terms than reads left purges everything before reading anything. + - The pin-time plan skips the closure (`CachePurgeOptions.references: false`): for these sites it is the expected outcome only. + - `RELEASE_EXECUTOR_COST` is 26 (it counts `refreshSearch` and `recordPurge` now). + - **`@cloudhal/cloudflare`:** the cron handler passes one `releaseBlobs` allowance to both ticks of its invocation (`cronTick`); the alarm and the request backstop run one tick each, with the default allowance. +- bb43a16: RFC-0045 rollout step 4: the four field operations work on reference and repeater fields. The types themselves stay refused on every production write path until step 7 (`fields_unsupported`, now from the dry run's check of the definitions the operation ends with); the shared suites enable them with `SiteGraphStoreOptions.fieldTypes`. Nothing changes for operations on the nine existing types. + + - **`sub`** on all four operations (`FieldOperation.sub`, `FieldMigration.sub`): with it, `rename_field`, `change_field_type` and `remove_field` rename, convert or remove one sub-field of a repeater in every item. An item left empty is dropped, and a list left empty is no value. `set_field_localized` refuses `sub` (sub-fields share their repeater's `localized`). Readers, writers and the rows read items through the marker; a top-level reader ignores a sub-field rename's `fromKey` (`renamedFrom`). + - **New `change_field_type` inputs:** `collections`, `maxItems`, `subFields` and `itemLabel`, each refused where the target type does not take it. A reference changes to a reference only to switch `multiple`. A conversion that carries ids over may only widen the target collections. A repeater converts to text or to a reference only with exactly one matching sub-field. + - **New conversion rows** (`fields/conversions-references.ts`): reference single ↔ multiple, text ↔ reference (through the prefetched `ConvertContext.entries` maps, never the entry's own group), multiline text → repeater, repeater → text, and multiple reference ↔ repeater. The maps are read once per operation pass, and by `EntryEngine.write` while such a conversion runs. + - **Text ↔ reference values** are decided by one rule (`fields/text-reference.ts`), per value, from the `entry_refs` rows that phase C's pending check reads too: each operation pass loads the path's rows once, and a person's write reads its node's. A value with its row is kept; a legacy id-shaped text is written as a reference when its group is usable, else reported; a value that does not convert keeps its rows as they are. Readers use a display rule. Rebuilds (pull, push, import, restore) read a converting path through its earlier type. The renderer's conversion maps read archived entries too, so an archived target lends its title. + - **Phase B's target guard** covers only the ids a rewrite newly names; ids a reshape or a rename carries over stay as stored, rows kept. **`set_field_localized`** updates the rows' `shared` in the batch of its site write (phase A, and the revert's). + - **Revert** drops restored references whose group has no member left in the site, and reports them in `FieldRevertResult.dropped`. + - **Values that stop converting while an operation runs** (a target archived or deleted, a second entry with the same title) are reported in `unconvertible` and keep the operation running. `continueFieldOperation` and `revertFieldOperation` take `onInvalid: "clear"` to drop them, as do the admin API's continue and revert routes (in the body) and `cloudhal fields continue|revert --clear`. + - **Releases (#213):** when the read of the published site node fails, the run retries it once, then purges everything; it no longer falls back to the working site row. + - **`multiple`** on a type change to a type that has none is ignored, as before. + - **CLI:** `cloudhal fields retype` takes `--collections a,b`, `--max-items n` and `--sub-fields `, and every action takes `--sub `. The admin API's operation route parses the same inputs. MCP's operation tools take them with rollout step 5. +- dda55ee: RFC-0045 rollout step 5: reference and repeater fields over MCP. The two types stay refused on every production write path until step 7 (`fields_unsupported`), and the field inputs do not list them there; a store with `SiteGraphStoreOptions.fieldTypes` gets tools that do. Nothing changes for the nine existing types, except as listed. + + - **`list_collections`** returns, beside `fieldsSchema`, its strict profile `fieldsSchemaStrict` (every key required, `null` for "leave as it is") and `strictCost` (`properties`, `depth`, `enumValues`, `unions`). Reference targets are named by their collections' labels. + - **`create_entry` / `update_entry`** take `fieldsStrict`, for strict structured output, instead of `fields` (`invalid` when both are given): `null` or a missing key leaves a value as it is (on create, no value); `null` sub-values in repeater items are stripped, and items left empty are dropped and reported in `droppedItems`. `update_entry` also takes `clearFields` (set and clear of one key is `invalid`, an unknown key `unknown_field`); on create it is `invalid`. A given reference or repeater value replaces the whole value. + - **Prechecks are the store's own write plan**, run as a dry run: the new `NodeWriteOptions.dryRun` on `createContentEntry`/`updateContentEntry`, and `deleteContentEntry(entry, { dryRun })`, throw the plan-time refusals (values, links, references, a release hold, gates, assets, terms) and write nothing. So `create_entry` and `update_entry` refuse reference targets (`unknown_entry`), repeater items and the references cap before anyone is asked, and `delete_entry` refuses `entry_referenced` with the published referrers. Behaviour change: those prechecks now also run the store's translation-link and canonical-id checks, which the handler ran anyway. + - **Approval prompts** name targets readably, from the dry run's planned entry (canonical ids): `venue → "Main hall" (entry_…, Places)`, `speakers: 2 items → 3 items (added "Ada Lovelace", Speaker; changed item 1: person → "Grace Hopper" (entry_…, People))`, quoted and truncated. + - **New read-only tool `list_references`** (`content:read`) with `direction: "to"` (referrers, published first, with the members that show them) or `"from"` (the groups an entry names, its original's inherited ones included). 110 → 111 tools. The API's `GET …/entries/:entryId/references` and the tool share core-ts's new `listReferrers` (and `listReferenceTargets`, `referenceCard`). + - **`list_entries`** returns each entry's `groupId`, the value a reference stores. + - **Translation tools**: `get_translation_source` lists a localized repeater's text and rich-text sub-values by item path (`speakers/0/talk`) with the source's `sourceRev`; `save_translation` takes them back with that `sourceRev` (`conflict` when the source changed) and folds them into a copy of the source's list, keeping each item's other sub-values (core-ts `translatedItemValues`). Once the translation holds its own list for that repeater, item paths are refused and the list is sent whole; a whole list given together with item paths must have the source's length (`translation_shape_mismatch`, new code, 409 in the API). A path naming no such value is refused. Keys whose first part is not a repeater (`og/image`) stay plain keys. + - **`normalizeEntryFields`** is exported from `@cloudhal/core-ts`: MCP's approval prompts read stored values through the markers exactly as the store does. + - **`continueFieldOperation`** with `onInvalid: "clear"` reports the values it drops as cleared, without the stored request's `field_values_unconvertible` refusal. + - **Removals during `rename_field`** over MCP: the old and the new key are one field; removing either removes both, so the writer's move cannot bring the value back, and setting one while removing the other is `invalid`. + - **Operation tools** take step 4's inputs: `sub` (`rename_field`, `change_field_type`, `remove_field`), `collections`, `maxItems`, `subFields` and `itemLabel` on `change_field_type`, and `onInvalid: "clear"` on a continuation; results carry `unconvertible`. + - **`defineTools({ referenceTypes })`** and `defaultToolList(referenceTypes)`: `createCloudhalMcpServer` passes whether its store has `fieldTypes`. +- 3678855: RFC-0045 rollout step 6a: reference and repeater fields in Studio's entry editor. The two types stay refused on every production write path until step 7 (`fields_unsupported`), so no production collection can define them yet and Studio looks unchanged there. + + - **New read-only route `GET /api/sites/:siteId/entries/groups?ids=a,b`** (`content:read`, in the playground's allow-list): each translation group's members in the site, any status, as `{groupId, id, title, collection, status, locale}` cards (core-ts `getGroupMembers` and `referenceCard`); a group with no member left answers `[]`. One to 100 well-formed group ids (the per-entry reference cap), 400 otherwise, 404 for an unknown site. Studio reads the chosen targets' titles and states through it. + - **`fieldLabel`, `fieldHelp` and `optionLabel`** (`@cloudhal/core-ts/fields`) also take a repeater's sub-field definitions. + - **Studio** (not published): the entry editor's reference fields (`ReferenceList` and `EntryPicker` over `GET …/entries/pick`), repeaters (`RepeaterField`, focus after add and remove, an undo toast, item errors by path), and a "Used by" card from `GET …/entries/:id/references`, with the new `@cloudhal/ui` blocks `FieldControl`, `RepeaterField`, `ReferenceList`, `EntryPicker` and `UsedByList`. They load with the lazy fields chunk; the initial bundle is unchanged. +- 4a5633d: RFC-0045 rollout step 7a: two fixes ahead of enabling reference and repeater fields. Both types stay refused on every production write path until step 7b; nothing changes for the nine existing types. + + - **core-ts (#215).** While a top-level conversion from references runs without a text ↔ reference path (reference (multiple) ↔ repeater, reference single ↔ multiple, a repeater converting away), a stored value still in the old shape that does not convert keeps its `entry_refs` rows through a person's unrelated write, such as a title edit. Before, the write dropped them, and the target's delete guard under-blocked. The writer holds the rows at the old type's paths, the same ones the import rebuild keeps (one helper, `oldShapePairs`), so the rows no longer depend on which touched the entry last. + - **core-ts: held rows follow their holder's status.** A row a write holds (a value a running conversion did not accept, here or during a text ↔ reference conversion) kept the `source_status` of its last insert, so publishing the holder left the target deletable and unpublishing left it locked. The write now updates the held rows' `source_status` in the same batch, anchored on the entry's new hash. + - **mcp-server, core-ts (#218).** Once a translation holds its own list for a localized repeater, `get_translation_source` returns the source's whole list for that key under `fields` (in the source's order, with every sub-value) instead of item paths, and names it in the new `wholeLists` output: send it back whole, translated. `save_translation` already refused item paths there (`translation_shape_mismatch`); its hint and the tool descriptions now say what to send. `save_translation` also checks a given `sourceRev` against whole repeater lists (`conflict` when the source moved on); without one they save as before. New core-ts export: `translationSourceValues`. +- Updated dependencies [3b8e846] + - @cloudhal/core-contracts@0.9.0 + - @cloudhal/schedules@0.9.0 + - @cloudhal/storage@0.9.0 + ## 0.8.0 ### Minor Changes diff --git a/packages/core-ts/package.json b/packages/core-ts/package.json index 77653539..43e68d68 100644 --- a/packages/core-ts/package.json +++ b/packages/core-ts/package.json @@ -1,6 +1,6 @@ { "name": "@cloudhal/core-ts", - "version": "0.8.0", + "version": "0.9.0", "description": "Cloudhal Site Graph core (TypeScript): load/save nodes with optimistic locking, snapshots, diff, publish and rollback; taxonomies, terms, redirects and menus", "license": "Apache-2.0", "homepage": "https://cloudhal.dev", diff --git a/packages/create-cloudhal/CHANGELOG.md b/packages/create-cloudhal/CHANGELOG.md index 6583ba14..f4012703 100644 --- a/packages/create-cloudhal/CHANGELOG.md +++ b/packages/create-cloudhal/CHANGELOG.md @@ -1,5 +1,12 @@ # create-cloudhal +## 0.9.0 + +### Patch Changes + +- Updated dependencies [bb43a16] + - @cloudhal/cli@0.9.0 + ## 0.8.0 ### Patch Changes diff --git a/packages/create-cloudhal/package.json b/packages/create-cloudhal/package.json index a431b49f..90227101 100644 --- a/packages/create-cloudhal/package.json +++ b/packages/create-cloudhal/package.json @@ -1,6 +1,6 @@ { "name": "create-cloudhal", - "version": "0.8.0", + "version": "0.9.0", "description": "Create a Cloudhal site: npm create cloudhal@latest", "license": "Apache-2.0", "homepage": "https://cloudhal.dev", diff --git a/packages/mcp-server/CHANGELOG.md b/packages/mcp-server/CHANGELOG.md index ee201eee..4d94540b 100644 --- a/packages/mcp-server/CHANGELOG.md +++ b/packages/mcp-server/CHANGELOG.md @@ -1,5 +1,72 @@ # @cloudhal/mcp-server +## 0.9.0 + +### Patch Changes + +- 9aa67d3: RFC-0045 rollout step 3b: publishes purge the pages that show references. Nothing changes for sites without reference definitions. Their publish purge plans are the same, with no bundle read. Their release runs send the plan stored at pin time, as before, with no re-plan; the only addition is one read of the published site node, to tell them apart. + + - **The referrer closure** (`references/purge.ts`, called by `planCachePurge`). + - The seeds are the groups of every changed, added or removed entry, and of every entry whose shown asset changed. + - It purges the referrers of those groups, two hops deep, with every language version of each referrer. + - It also purges every member of each group a changed entry names, before or after ("used by"). + - Values are resolved, so a translation that only inherits counts. + - It reads only the `from` and `to` snapshots' bodies, never the working copy or `entry_refs`. + - **Reads and budgets.** A publish that changes no entry and no shown asset reads nothing. Otherwise the closure keeps one hash-keyed cache: + - one bundle (`to`'s, else `from`'s), streamed and cut down as each shard is parsed; + - then the missing hashes, read by the closure itself, six at a time, and cut down the same way. + + A passed budget purges everything: + - bytes (`maxBodyBytes`, 32 MB); + - nodes (`maxNodes`, 50,000); + - reads (`maxReads`, shard reads included); + - tags (`maxTags`). + + So does any field-operation marker on either snapshot's site node, for sites that hold references or convert from them. + - **`readSnapshotBundle`** (`SnapshotReader.readSnapshotBundle`, `SiteGraphStore.readSnapshotBundle`, `readSnapshotBundle` in bundles) takes optional `maxBytes`, `maxNodes`, `keep`, `only` (bodies node by node) and `spent` (a shared byte total). A passed budget throws `BundleBudgetError` before the shard is parsed. No new cache tags. + - **Release runs on sites with references re-plan their purge at run time** (`references/release-purge.ts`), from the pointer they moved to the snapshot they made, instead of sending the plan stored at pin time. + - The test is the published site node, which `publishRelease` now returns (`publishedSite`). That costs one blob read per run with a purger, except on a first publish; the read is counted, never refused. If it fails, the working row decides. + - The re-plan runs over the tick's counting driver. + - The release graph's blob calls (`refreshSearch`, `labelOf`, the re-plan) are charged to one allowance per invocation, shared by the cron's ticks (`ScheduledTickOptions.releaseBlobs`): 350 on Workers Free, 3,000 on Paid. "Publish now" sizes it from the deployment's tick budget (`ReleaseService` and `SchedulesDeps.tickBudget`). + - Past the allowance, or if the re-plan fails, the run purges everything. A re-plan with more distinct terms than reads left purges everything before reading anything. + - The pin-time plan skips the closure (`CachePurgeOptions.references: false`): for these sites it is the expected outcome only. + - `RELEASE_EXECUTOR_COST` is 26 (it counts `refreshSearch` and `recordPurge` now). + - **`@cloudhal/cloudflare`:** the cron handler passes one `releaseBlobs` allowance to both ticks of its invocation (`cronTick`); the alarm and the request backstop run one tick each, with the default allowance. +- dda55ee: RFC-0045 rollout step 5: reference and repeater fields over MCP. The two types stay refused on every production write path until step 7 (`fields_unsupported`), and the field inputs do not list them there; a store with `SiteGraphStoreOptions.fieldTypes` gets tools that do. Nothing changes for the nine existing types, except as listed. + + - **`list_collections`** returns, beside `fieldsSchema`, its strict profile `fieldsSchemaStrict` (every key required, `null` for "leave as it is") and `strictCost` (`properties`, `depth`, `enumValues`, `unions`). Reference targets are named by their collections' labels. + - **`create_entry` / `update_entry`** take `fieldsStrict`, for strict structured output, instead of `fields` (`invalid` when both are given): `null` or a missing key leaves a value as it is (on create, no value); `null` sub-values in repeater items are stripped, and items left empty are dropped and reported in `droppedItems`. `update_entry` also takes `clearFields` (set and clear of one key is `invalid`, an unknown key `unknown_field`); on create it is `invalid`. A given reference or repeater value replaces the whole value. + - **Prechecks are the store's own write plan**, run as a dry run: the new `NodeWriteOptions.dryRun` on `createContentEntry`/`updateContentEntry`, and `deleteContentEntry(entry, { dryRun })`, throw the plan-time refusals (values, links, references, a release hold, gates, assets, terms) and write nothing. So `create_entry` and `update_entry` refuse reference targets (`unknown_entry`), repeater items and the references cap before anyone is asked, and `delete_entry` refuses `entry_referenced` with the published referrers. Behaviour change: those prechecks now also run the store's translation-link and canonical-id checks, which the handler ran anyway. + - **Approval prompts** name targets readably, from the dry run's planned entry (canonical ids): `venue → "Main hall" (entry_…, Places)`, `speakers: 2 items → 3 items (added "Ada Lovelace", Speaker; changed item 1: person → "Grace Hopper" (entry_…, People))`, quoted and truncated. + - **New read-only tool `list_references`** (`content:read`) with `direction: "to"` (referrers, published first, with the members that show them) or `"from"` (the groups an entry names, its original's inherited ones included). 110 → 111 tools. The API's `GET …/entries/:entryId/references` and the tool share core-ts's new `listReferrers` (and `listReferenceTargets`, `referenceCard`). + - **`list_entries`** returns each entry's `groupId`, the value a reference stores. + - **Translation tools**: `get_translation_source` lists a localized repeater's text and rich-text sub-values by item path (`speakers/0/talk`) with the source's `sourceRev`; `save_translation` takes them back with that `sourceRev` (`conflict` when the source changed) and folds them into a copy of the source's list, keeping each item's other sub-values (core-ts `translatedItemValues`). Once the translation holds its own list for that repeater, item paths are refused and the list is sent whole; a whole list given together with item paths must have the source's length (`translation_shape_mismatch`, new code, 409 in the API). A path naming no such value is refused. Keys whose first part is not a repeater (`og/image`) stay plain keys. + - **`normalizeEntryFields`** is exported from `@cloudhal/core-ts`: MCP's approval prompts read stored values through the markers exactly as the store does. + - **`continueFieldOperation`** with `onInvalid: "clear"` reports the values it drops as cleared, without the stored request's `field_values_unconvertible` refusal. + - **Removals during `rename_field`** over MCP: the old and the new key are one field; removing either removes both, so the writer's move cannot bring the value back, and setting one while removing the other is `invalid`. + - **Operation tools** take step 4's inputs: `sub` (`rename_field`, `change_field_type`, `remove_field`), `collections`, `maxItems`, `subFields` and `itemLabel` on `change_field_type`, and `onInvalid: "clear"` on a continuation; results carry `unconvertible`. + - **`defineTools({ referenceTypes })`** and `defaultToolList(referenceTypes)`: `createCloudhalMcpServer` passes whether its store has `fieldTypes`. +- 4a5633d: RFC-0045 rollout step 7a: two fixes ahead of enabling reference and repeater fields. Both types stay refused on every production write path until step 7b; nothing changes for the nine existing types. + + - **core-ts (#215).** While a top-level conversion from references runs without a text ↔ reference path (reference (multiple) ↔ repeater, reference single ↔ multiple, a repeater converting away), a stored value still in the old shape that does not convert keeps its `entry_refs` rows through a person's unrelated write, such as a title edit. Before, the write dropped them, and the target's delete guard under-blocked. The writer holds the rows at the old type's paths, the same ones the import rebuild keeps (one helper, `oldShapePairs`), so the rows no longer depend on which touched the entry last. + - **core-ts: held rows follow their holder's status.** A row a write holds (a value a running conversion did not accept, here or during a text ↔ reference conversion) kept the `source_status` of its last insert, so publishing the holder left the target deletable and unpublishing left it locked. The write now updates the held rows' `source_status` in the same batch, anchored on the entry's new hash. + - **mcp-server, core-ts (#218).** Once a translation holds its own list for a localized repeater, `get_translation_source` returns the source's whole list for that key under `fields` (in the source's order, with every sub-value) instead of item paths, and names it in the new `wholeLists` output: send it back whole, translated. `save_translation` already refused item paths there (`translation_shape_mismatch`); its hint and the tool descriptions now say what to send. `save_translation` also checks a given `sourceRev` against whole repeater lists (`conflict` when the source moved on); without one they save as before. New core-ts export: `translationSourceValues`. +- Updated dependencies [3b8e846] +- Updated dependencies [41d783a] +- Updated dependencies [9aa67d3] +- Updated dependencies [bb43a16] +- Updated dependencies [dda55ee] +- Updated dependencies [3678855] +- Updated dependencies [4a5633d] + - @cloudhal/core-contracts@0.9.0 + - @cloudhal/astro-renderer@0.9.0 + - @cloudhal/core-ts@0.9.0 + - @cloudhal/agent-runtime@0.9.0 + - @cloudhal/analytics@0.9.0 + - @cloudhal/comments@0.9.0 + - @cloudhal/schedules@0.9.0 + - @cloudhal/storage@0.9.0 + ## 0.8.0 ### Patch Changes diff --git a/packages/mcp-server/package.json b/packages/mcp-server/package.json index 788472cf..7fd42966 100644 --- a/packages/mcp-server/package.json +++ b/packages/mcp-server/package.json @@ -1,6 +1,6 @@ { "name": "@cloudhal/mcp-server", - "version": "0.8.0", + "version": "0.9.0", "description": "Cloudhal MCP server: semantic site tools (pages, articles, snapshots, preview, publish) governed by the policy engine", "license": "Apache-2.0", "homepage": "https://cloudhal.dev", diff --git a/packages/schedules/CHANGELOG.md b/packages/schedules/CHANGELOG.md index 1d9ccd42..149abaee 100644 --- a/packages/schedules/CHANGELOG.md +++ b/packages/schedules/CHANGELOG.md @@ -1,5 +1,13 @@ # @cloudhal/schedules +## 0.9.0 + +### Patch Changes + +- Updated dependencies [3b8e846] + - @cloudhal/core-contracts@0.9.0 + - @cloudhal/storage@0.9.0 + ## 0.8.0 ### Patch Changes diff --git a/packages/schedules/package.json b/packages/schedules/package.json index 850d6134..4a4c434e 100644 --- a/packages/schedules/package.json +++ b/packages/schedules/package.json @@ -1,6 +1,6 @@ { "name": "@cloudhal/schedules", - "version": "0.8.0", + "version": "0.9.0", "description": "Cloudhal schedules (RFC-0008): the time model, the RRULE subset and its sentences, releases (pin, closure, rl1: hash, compose, conflicts, state machine), automation and run state, taint and budget accounting, the Scheduler and runDue, and the SQLite/D1 store. Worker-safe.", "license": "Apache-2.0", "homepage": "https://cloudhal.dev", diff --git a/packages/storage/CHANGELOG.md b/packages/storage/CHANGELOG.md index 687e935c..0ddd211f 100644 --- a/packages/storage/CHANGELOG.md +++ b/packages/storage/CHANGELOG.md @@ -1,5 +1,12 @@ # @cloudhal/storage +## 0.9.0 + +### Patch Changes + +- Updated dependencies [3b8e846] + - @cloudhal/core-contracts@0.9.0 + ## 0.8.0 ### Minor Changes diff --git a/packages/storage/package.json b/packages/storage/package.json index bce58e4e..434dfa0d 100644 --- a/packages/storage/package.json +++ b/packages/storage/package.json @@ -1,6 +1,6 @@ { "name": "@cloudhal/storage", - "version": "0.8.0", + "version": "0.9.0", "description": "Cloudhal storage interfaces (SQL driver, blob store) with Cloudflare D1/R2/Durable Object SQLite and local SQLite/filesystem adapters", "license": "Apache-2.0", "homepage": "https://cloudhal.dev",