Skip to content

Commit afdb07e

Browse files
committed
Merge origin/main into claude/project-thread-sukiom
Claude-Session: https://claude.ai/code/session_01L6bhgWZ1wrAZ2ocZovnByy Co-authored-by: Claude <noreply@anthropic.com>
2 parents 1a72f69 + f273c9f commit afdb07e

103 files changed

Lines changed: 5467 additions & 719 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
'@objectstack/skills': patch
3+
---
4+
5+
docs(skills): the automation skill's OAuth recipe names a stdio MCP server's credential route as `transport.credentialEnv`
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
Recipe 6 of `objectstack-automation/references/integration-recipes.md` said a `stdio` server's credentials ride `transport.env` — the literal-in-metadata route the `connector-credential-literal` advisory warns against. It now says what the `mcp` provider does: the grant-bearing kinds stay `http` only; a `stdio` server takes a static `auth: { type: 'bearer', credentialRef }`, handed to the child process in the variable `transport.credentialEnv` names, never a literal in `transport.env`. Paid inside the file's token ceiling by dropping the opening paragraph's restatement of two facts that keep their homes: the packaged spec (SKILL.md § Integrations are declared, not coded) and where an `api` hook's secret goes (SKILL.md's `secretRef` row and recipe 4). No eval asserted the old route; none changes.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
'@object-ui/plugin-detail': patch
3+
---
4+
5+
fix(plugin-detail): the record page's activity feed names the record as the reader reads it, as the record's heading does, when the object is named by a formula
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
An activity summary quotes the record's name as its writer read it: `sys_activity.record_label`, and the same text inside `summary`, are stored when the write happens. The server composes the rest of the summary in the reader's language on read, but not the name. For an object whose name field is a formula over `label(record.FIELD)`, that name is in the writer's language, so an en-US reader of a review a zh-CN user created read `Created Review "法务 · Legal Counsel 1"` while the heading above it read `Legal · Legal Counsel 1`.
11+
12+
Each activity row of the page's own record now names the record by the value of the object's name field on the record the page read, which is the heading's name. The change is made where the feed is drawn (`RecordActivityTimeline`), so the activity panel, the 动态 stream and the 动态 panel all read it. Only the name the summary quotes (`"…"`, or `「…」` in Japanese) is replaced.
13+
14+
What stays as stored:
15+
16+
- an object whose name field is a stored field (text and the like): the name a row stored is the name the record had then, and a rename does not rewrite older rows;
17+
- a row about another record, a row that carries no `record_label`, and a summary that does not quote the stored name;
18+
- a page with no record around the feed, or whose record has no name to show.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
'@object-ui/app-shell': patch
3+
'@object-ui/i18n': patch
4+
---
5+
6+
feat(app-shell): the Studio list-view panel configures the selection bar's actions (#30089)
7+
8+
Clause-②: no
9+
Metadata-protocol: none
10+
11+
The list-view panel of an object's grid view gains a "Selection actions" section. It edits two keys the list view already declares, and no other:
12+
13+
- `bulkActions`: pick the object's actions by label, plus the built-in Delete (`delete`). Each runs once per selected record, promoted with the action's own label and params.
14+
- `bulkActionDefs`: add, edit or remove a field update (`operation: 'update'`): a button label, the fields the dialog asks for (one required param per field, carrying a select's options and a lookup's object) and an optional confirmation. A def is written only once it has a label and a field and `BulkActionDefSchema` accepts it.
15+
16+
The section says what happens to the built-in Delete: shown while the view declares neither key, and kept once either is declared only when `bulkActions` names `delete`. A def of another kind (`delete`, an aggregate `custom` dispatch) is listed and can be removed; it is edited in metadata. An emptied key is removed, so a view that declares neither key saves as it was read. On an installed app's read-only view, the first edit goes through the same customization copy as every other setting of the panel. Strings are added in English and Chinese to the `studio` namespace of `@object-ui/i18n`.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
'@object-ui/plugin-grid': minor
3+
---
4+
5+
fix(plugin-grid)!: a list's selection bar and row menu draw only actions the object declares; an undeclared bare `bulkActions` / `rowActions` name draws nothing and warns once in development (#30169)
6+
7+
Clause-②: no (narrowing) — the grid stops drawing a bare `bulkActions` or legacy `rowActions` name that matches no action the object declares, which it drew before by humanized name. `packages/spec/src/ui/bulk-action.zod.ts` already says the member "names an action the object declares", and lint `action-name-undefined` (ADR-0049) refuses any other at authoring. Nothing is widened.
8+
Metadata-protocol: narrowed
9+
Skills-docs: no move — `skills/**` teaches no handler-only bulk or row action name (searched for `bulkActions` / `rowActions` examples and runner-handler text); `content/docs/ui/**` already names only declared actions in its `bulkActions` / `rowActions` examples.
10+
11+
<!-- adr-0087: not-required (no-migration-prescription) No key of any schema, export or stored row changes shape: `bulkActions` and `rowActions` keep their `string[]` form and meaning. What narrows is the renderer's draw set, back to the spec's own sentence. Whether an undeclared name was a misspelling, an action still to declare or a handler the host meant to keep is a judgement about the view, so no rewrite derives the fix; the development warning names each name. -->
12+
13+
**BREAKING** for a host that registered a runner handler under a bare name the object does not declare (`ActionProvider handlers` / `runner.registerHandler('NAME', …)`) and listed that name in a view's `bulkActions` or `rowActions`.
14+
15+
- **Before.** `resolveBulkActions` and `resolveLegacyRowActions` kept a name that matched no declared action, and `ObjectGrid` drew it by humanized name and dispatched it to the runner by name. A name nothing handled toasted "not executable" on click. This is how a list whose app had a package disabled kept a ghost button: the server withholds that package's actions from the served object, so their names matched nothing.
16+
- **Now.** Such a name gets no selection-bar button and no row-menu entry, and in development the console logs one warning per list naming the key, the block and each name. The resolvers return those names as `undeclared` (renamed from `unresolved`), used only for that warning. The canonical `'delete'` (and the row menu's `'edit'` / `'delete'`) keep their own paths, unchanged.
17+
- **Unchanged.** A name that matches a declared action is promoted to that action's def exactly as before, under the action's own label, icon, params, `visible` and `requiredPermissions`.
18+
19+
**Remedy.** No rewrite is derived, because which fix an undeclared name needs is a judgement about the view: declare the named action on the object, or remove the name from `bulkActions` / `rowActions`. The development warning names each one. An action withheld by a disabled package needs nothing: it draws again when the package is enabled.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
'@object-ui/console': patch
3+
'@object-ui/plugin-kanban': patch
4+
'@object-ui/plugin-form': patch
5+
---
6+
7+
fix(ui): the console form page Edit, the kanban drop prompt and the Edit wizard judge a field's `requiredWhen` as the engine does, a transition gate against the stored record
8+
9+
Clause-②: no
10+
Metadata-protocol: none
11+
12+
- **`@object-ui/console` form page (`/forms/:name?recordId=`):** an Edit no longer refuses a record that already sits inside a `requiredWhen` gate without the value (for example a contract activated before its signed-copy rule existed). The field shows no required marker there, and an unrelated edit saves, as REST `PATCH` already accepts. Still refused: the edit that moves a record into the gate without the value, and clearing the value of a record that held it. A create form enforces as before.
13+
- **`@object-ui/plugin-kanban` drop prompt:** dropping a card no longer asks for a field the engine lets rest. A record already inside the gate without the value moves between columns with no dialog; a drop that moves a compliant record into the gate still asks for the value first.
14+
- **`@object-ui/plugin-form` Edit wizard:** the final submit's cross-step check no longer refuses a record that already sits inside a `requiredWhen` gate without the value; it asks `requiredWhenRestsOnStoredRecord` about the record as first read. The record reaches only that stored-record check, so a `visibleWhen` reading `previous` is still unevaluable at that check, as before. Moving a compliant record into the gate is still refused, and a Create wizard enforces as before.
15+
16+
All three read the stored-record verdict `resolveFieldRuleState` already returns (`requiredWhenAtRest`, or its exported check `requiredWhenRestsOnStoredRecord`); no second rule.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
'@objectstack/skills': patch
3+
---
4+
5+
docs(skills): the platform skill names every type a pair's declared override is served for, and that removing the pair's item serves the base's again
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
`skills/objectstack-platform/SKILL.md`, the "Customizing an installed package (ADR-0146)" paragraph: a `.custom` pair's declared override is served for a view, dashboard, report, email_template, translation, flow, page, app, dataset, doc, book or mapping (the paragraph named six), and removing the pair's item (`DELETE …?package=hotcrm.custom`) serves the base's document again (ADR-0146's revert, which the paragraph did not say). The package's evals gain a dataset-and-page override case and a removal case.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
'@objectstack/spec': patch
3+
'@objectstack/platform-objects': patch
4+
'@object-ui/app-shell': patch
5+
---
6+
7+
fix: on a zh-CN console every row of the view properties panel's collapsed sections (表格选项 / 分页 / 终端用户控制 / 导航与共享) reads in Chinese
8+
9+
Clause-②: no
10+
Metadata-protocol: none
11+
12+
- `viewForm` (`@objectstack/spec/ui`) now spells out the children of its `selection`, `pagination`, `userFilters`, `appearance`, `userActions`, `navigation` and `sharing` composites, and gives the rows that had none a hint. Each declared hint is the schema description the panel already showed, so an English console reads the same text; `os i18n extract` now emits a `metadataForms.view.fields['<parent>.<child>']` key per row.
13+
- `userFilters.fields` is enumerated as an inline-table repeater, and `UserFilterFieldSchema`'s six properties carry a `.meta({ title })` (Field / Label / Type / Options / Show Count / Default Values) — the English column heads, unchanged.
14+
- The panel no longer offers `navigation.view` and `sharing.type`: both are `retiredKey()` tombstones that the schema-derived child list used to render as editable rows. A stored value is untouched by a panel save (the composite editor spreads the block it was given).
15+
- The platform metadata-forms catalogs carry zh-CN, ja-JP and es-ES text for every new row, and the console's zh-CN overlay copies the zh-CN rows.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
'@object-ui/app-shell': patch
3+
---
4+
5+
fix(app-shell): every Console surface that names an app draws the served app label as served
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
- **Now.** The app switcher, the sidebar's app title, the top bar's hidden-app menu, Home's app cards, apps strip, recent rows and setup link, the no-access empty state, the AI chat's app names, the marketplace's "Open app" buttons and the report index's other-app links draw the app `label` (and the app card its `description`) the `/meta/app` read served, as given. The server has already translated it, by its label order for an overridden app: a `.custom` pair's own text is kept over the base package's translation. Before, the served label reached the client's `apps.<name>.label` catalog lookup only as its fallback, so the base package's translation of the old name won.
11+
- **Unchanged.** A pending draft under `?preview=draft`, a keyed label and an app with no label or description are still named by the catalog key, then by the machine name as before. An unedited app shows the same text as before, because the server serves the catalog's translation for it.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
'@object-ui/app-shell': patch
3+
'@object-ui/i18n': patch
4+
---
5+
6+
fix(app-shell): Setup → Datasources names the objects that still use a datasource, in the console's language, before and after its delete
7+
8+
Clause-②: yes (widening)
9+
Metadata-protocol: none
10+
11+
- **The confirm.** Opening a datasource's delete reads object metadata and lists every object whose `datasource` names it (label, with the name beside it when they differ). While any is listed, the confirm says the datasource cannot be deleted yet and that each object must be deleted or moved to another datasource first. With none, or when the read fails, the confirm is unchanged.
12+
- **The refusal.** A `400` from `DELETE /api/v1/datasources/:name` re-reads that list. When objects still name the datasource, the toast says, in the console's language, that it was not deleted, which objects still use it, and what to do next. Any other failure, and a `400` with no bound object, keep the server's message in the existing frame. No server text is matched.
13+
- **The widening.** Three new `studio` namespace rows in `@object-ui/i18n` (en and zh): `engine.datasource.deleteBoundBody`, `engine.datasource.deleteBoundRefused` and `engine.datasource.boundObjectSeparator`.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
'@objectstack/spec': minor
3+
'@objectstack/metadata-protocol': minor
4+
'@objectstack/runtime': patch
5+
---
6+
7+
feat(spec,metadata-protocol): the publish receipt's `seedApplied.landed` names the rows a seed created and the rows it only matched, per object, capped at 200 ids per list
8+
9+
Clause-②: yes (widening)
10+
Metadata-protocol: added
11+
12+
- **`@objectstack/spec`: `seedApplied.landed`** on both publish responses (`PublishMetaItemResponseSchema`, `PublishPackageDraftsResponseSchema`), one shared schema `SeedAppliedLandedSchema`: per object, `inserted` (the rows this publish created) and `matched` (pre-existing rows a seed record's key matched: updated, left as they were, or refused an update), each a `SeedAppliedIdListSchema` `{ ids, total, truncated }`. `ids` carries at most `SEED_APPLIED_LANDED_IDS_CAP` (200) ids, in the loader's record order (datasets in load order, records as authored); past it `truncated` is `true` and `total` is the uncut count. Absent `landed` means "not reported" (a load that threw, or a producer that reports no ids), never "nothing landed". Only `inserted` names rows the seed created: a `matched` row may be a customer's own record that shares the seed's natural key, and under `ignore` (the default) such a row is matched without being written.
13+
- **`@objectstack/spec`: `SeedLoadResult.insertedIds`**, the ids among `landedIds` whose row the load created. Per load: a row an earlier load inserted is matched on a replay, so a reader tracking a seed's rows across publishes accumulates `insertedIds` over every load. `landedIds`' TSDoc now says what each seed mode puts in it.
14+
- **`@objectstack/metadata-protocol`**: `applySeedBodies` returns `landed`, so `publishPackageDrafts` and `publishMetaItem` both carry it; the loader records which landed rows it inserted. `seedAppliedLanded(results)` is exported, the one projection both receipt producers fold the loader's ids through.
15+
- **`@objectstack/runtime`**: the package-publish door's fallback seed apply (for protocols that do not self-apply) reports the same `landed`.
16+
- Accepted cost (objectstack-ai/cloud#3598 ruling A): row ids appear on the public publish responses, bounded by the cap.

0 commit comments

Comments
 (0)