You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 8136eb7
Browse filesBrowse the repository at this point in the historyBrowse files
MCP stdio, email, knowledge, queue, SMS, storage and record-trigger refusals, warnings and template descriptions no longer cite tracker numbers; each one states the decision behind it in words
12
+
13
+
Clause-②: no
14
+
15
+
Some strings these seven packages show to operators, administrators and flow authors pointed at an issue-tracker number for the reason behind them. The number goes; where the sentence did not already say what was decided, it now does.
16
+
17
+
-`@objectstack/connector-mcp`: the declarative stdio refusals say a stdio transport launches a local process, so stack metadata may only name a command the host's own code allows, and that an http transport is not gated by this policy.
18
+
-`@objectstack/plugin-email`: the built-in change-email notice template's description, in all four locales, says the notice goes to the previous address so a hijacked session cannot move the account identity unannounced; the internal-headers refusal says a missing header does not announce itself, so the send would succeed while silently deviating from what was authored; the over-limit attachments line says the storage capability holds large content outside the row while the row keeps a reference and the attachment's audit metadata.
19
+
-`@objectstack/service-knowledge`: the no-identity retrieval warning says a missing identity is not a grant of authority, so retrieval fails closed rather than searching the whole corpus unscoped; the predicate-write warning says the lifecycle reap guard de-indexes retention-swept rows before they are deleted.
20
+
-`@objectstack/service-queue`: the missing-retention refusal says the one platform reaper sweeps completed rows by that declaration, so the adapter does not sweep the table itself; the rejected-floor error says the floor is what makes the lifecycle service refuse an override below the idempotency window.
21
+
-`@objectstack/service-sms`: the unreadable-counter warning says a quota the platform cannot count must not refuse the one-time codes users sign in with; the counter store's lines name the daily SMS send quota without a number.
22
+
-`@objectstack/service-storage`: the reclamation-gate line says deleting bytes cannot be undone, so it waits for a verified migration with no deviation on record, while reversible work carries on.
23
+
-`@objectstack/trigger-record-change`: the array-trigger warning says multi-event arrays are deferred until two independent projects need a combination other than created-or-updated.
24
+
25
+
Text only: no status, error code, field, route or control flow moves. A client or log filter that matches the old text (for example a tracker-number suffix) needs the new spelling.
feat(cli): `objectstack generate picklist NAME` scaffolds a shared option list, and the metadata summary counts picklists
6
+
7
+
Clause-②: yes (widening)
8
+
9
+
-**`objectstack generate picklist NAME`** (alias `os g picklist`) writes `src/picklists/NAME.picklist.ts`, a list declared with `definePicklist({ name, label, options })`, and adds its export line to `src/picklists/index.ts`. The list is collected under the `picklists` stack key. A select field takes its options from the list by naming it, `Field.select({ picklist: 'NAME' })`, in place of options of its own. The server serves that field with the list's options resolved onto it, together with any options other packages add through `picklistExtensions`, and judges writes against them. `objectstack validate` and `objectstack build` refuse a field whose `picklist` names no list the stack declares, and so does the boot.
10
+
-**`objectstack init`** wires the new `src/picklists` barrel in the `app` and `plugin` templates, the same way it wires every other directory `objectstack generate` writes into: an empty `src/picklists/index.ts` and a `picklists: exportsOf(picklists)` key in `objectstack.config.ts`. A project scaffolded by an earlier release keeps its config. `objectstack generate picklist` then reports the list as not wired and prints the import line and the `defineStack` key to add.
11
+
-**The metadata summary** that `objectstack validate`, `objectstack build` and `objectstack info` print counts the picklists a stack declares, in the `Data:` row: `Data: 1 Objects 3 Fields 1 Picklists`. A stack that declares none prints the row it printed before. The `stats` object in the `--json` output of the same three commands gains a `picklists` count. A `picklistExtensions` entry is not counted as a list.
feat(create-objectstack): the blank starter wires a `src/picklists` barrel for `objectstack generate picklist`
6
+
7
+
Clause-②: yes (widening)
8
+
9
+
A new blank project ships an empty `src/picklists/index.ts`, and its `objectstack.config.ts` imports it and hands its exports to `defineStack` under `picklists`, as it already does for every other directory `objectstack generate` writes into. `objectstack generate picklist NAME` then writes `src/picklists/NAME.picklist.ts` and its export line, and the list is part of the stack with no edit to the config. A select field takes its options from the list with `Field.select({ picklist: 'NAME' })`, and the server serves that field with the list's options.
10
+
11
+
A project scaffolded by an earlier release keeps its config. There, `objectstack generate picklist NAME` writes the list, reports that it does not reach the stack, and prints the import line and the `defineStack` key that wire `src/picklists`.
docs(spec): an `object-master-detail-form` detail entry's `inlineMode` and `formFields` describes say what happens when the key is omitted on both of the renderer's paths (#21284)
6
+
7
+
Clause-②: no
8
+
9
+
-**Derived entry** (any entry that does not name both `relationshipField` and at least one column): an omitted `inlineMode` is resolved from the relationship field's `inlineEdit`, else from the child object's shape, and an omitted `formFields` is derived from the child object's fields. This is unchanged.
10
+
-**Entry kept as authored** (one that names both `relationshipField` and at least one column): the renderer resolves and derives nothing. An omitted `inlineMode` renders the collection as a grid, which offers the per-row form only when `formFields` lists more fields than `columns`. An omitted `formFields` means the per-row form is offered only when `inlineMode` is `form`, and it then draws the child object's full field list.
11
+
- The `inlineMode` describe used to say only "resolved from the relationship field's `inlineEdit` when omitted", and the `formFields` describe only "derived from the child object's editable fields when omitted". Neither holds for an entry kept as authored. The `formFields` describe also no longer says "editable": the derived list keeps `readonly` fields, as `deriveInlineRowFormFields` (`@objectstack/spec/data`) does.
12
+
- No schema accepts or refuses anything new. Only the two describes, the reference page that lifts them, and one source comment change.
The published `package.json` no longer declares `oclif.plugins`, and the package no longer lists `@oclif/plugin-help` or `@oclif/plugin-plugins` as devDependencies. The array named both plugins, but they were only devDependencies, and oclif loads an `oclif.plugins` entry only when the same name is in `dependencies`. Neither plugin ever loaded.
6
+
7
+
Clause-②: no
8
+
9
+
**What changes for an operator.** Nothing. `os --help`, every command and topic, and the output of `os help` and `os plugins` read byte-identical before and after the change. `os help` and `os plugins …` were never commands, and each still exits 2 with `command … not found`. Use `os --help` or `os <command> --help` for help.
10
+
11
+
**What the README now says.** It said `os plugins install`, `uninstall` and `update` came from `@oclif/plugin-plugins` and installed CLI extensions. That was never true. This CLI ships no plugin manager. To add commands to it, build an `os` distribution: a package whose own `package.json` lists the extension in both `oclif.plugins` and `dependencies`.
| `skill` | `src/skills/` | `NAME.skill.ts` | `skills` | AI skill — the ADR-0063 extension primitive |
1503
+
| `picklist` | `src/picklists/` | `NAME.picklist.ts` | `picklists` | Shared option list that select fields reference by name |
1502
1504
1503
1505
<Callout type="info" title="Why generated files carry a type infix">
1504
1506
Every scaffold is written as `NAME.TYPE.ts`, and the infix is read from the
@@ -1555,7 +1557,7 @@ the rules a JSON Schema can express and names the rest under
1555
1557
1556
1558
**What it does:**
1557
1559
1. For a type that names an object (`object`, `view`, `action`, `flow`, `app`), reads `manifest.namespace` from the project config (`objectstack.config.ts`, `.js` or `.mjs`) and prefixes the object name with it (see above)
1558
-
2. Creates the TypeScript file — an `object` declared with `ObjectSchema.create({ … })`, the same shape the `os init` templates write; a `skill` declared with `defineSkill({ … })`; the other types as typed literals (`UI.View`, `UI.Action`, `Automation.Flow`, `UI.Dashboard`, `UI.App`)
1560
+
2. Creates the TypeScript file — an `object` declared with `ObjectSchema.create({ … })`, the same shape the `os init` templates write; a `skill` declared with `defineSkill({ … })`; a `picklist` declared with `definePicklist({ … })`, which a select field names with `Field.select({ picklist: 'NAME' })` in place of its own `options`, and which the server resolves into that field's `options`; the other types as typed literals (`UI.View`, `UI.Action`, `Automation.Flow`, `UI.Dashboard`, `UI.App`)
1559
1561
3. Creates or updates the barrel `index.ts` in the target directory
Copy file name to clipboardExpand all lines: content/docs/references/ui/component.mdx
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -976,8 +976,8 @@ Sort field and direction pair
976
976
|**childObject**|`string`| ✅ | Child object whose records are entered inline |
977
977
|**relationshipField**|`string`| optional | FK on the child pointing back to the parent (auto-detected from the child's master_detail/lookup field when omitted) |
978
978
|**columns**|`{ name: string; label?: string; type?: Enum<'text' \| 'number' \| 'currency' \| 'date' \| 'datetime' \| 'time' \| 'select' \| 'lookup' \| 'file'>; width?: number; … }[]`| optional | Editable grid columns (derived from the child object when omitted). Each entry is the strict, name-keyed inline grid column a relationship field's `inlineColumns` takes (`{ name, label?, type?, … }` — objectui GridColumn); identity-only entries (`{ name }`) hydrate everything else from the child object's fields. Unknown keys and the retired `field` spelling are refused at parse. |
979
-
|**formFields**|`string[]`| optional | Child field names for the per-row expand form (derived from the child object's editable fields when omitted)|
980
-
|**inlineMode**|`Enum<'grid' \| 'form'>`| optional | Inline-edit form factor: 'grid' = editable cells; 'form' = read-only list + per-row full form. Resolved from the relationship field's `inlineEdit`when omitted|
979
+
|**formFields**|`string[]`| optional | Child field names for the per-row expand form. When omitted they are derived from the child object's fields — except on an entry that names both `relationshipField` and at least one column, which is kept as authored: nothing is derived, and the per-row form is offered only when `inlineMode` is 'form', where it draws the child object's full field list|
980
+
|**inlineMode**|`Enum<'grid' \| 'form'>`| optional | Inline-edit form factor: 'grid' = editable cells; 'form' = read-only list + per-row full form. When omitted it is resolved from the relationship field's `inlineEdit`, else from the child object's shape — except on an entry that names both `relationshipField` and at least one column, which is kept as authored: nothing is resolved, the collection renders as a grid, and the per-row form is offered only when `formFields` lists more fields than `columns`|
981
981
|**amountField**|`string`| optional | Numeric child column summed for the running total |
982
982
|**sortField**|`string`| optional | Child field holding the line sort position, stamped on drag-reorder (derived from a `position` / `sort_order` / … field when omitted) |
983
983
|**totalField**|`string`| optional | Parent field to receive the rolled-up sum |
{ "revision": 1, "date": "2026-08-07", "change": "new item: flag/command error UX with the full registered command surface enumerated from src/commands/ as variants, and never-executed-anyway as the load-bearing negative", "ref": "claude/platform-test-checklist-ocwugl" }
662
+
{ "revision": 1, "date": "2026-08-07", "change": "new item: flag/command error UX with the full registered command surface enumerated from src/commands/ as variants, and never-executed-anyway as the load-bearing negative", "ref": "claude/platform-test-checklist-ocwugl" },
663
+
{ "revision": 2, "date": "2026-10-02", "change": "source: package.json no longer declares oclif.plugins — the two listed plugins sat in devDependencies and never loaded, so the array was dropped; the registered surface and the unknown-command hard-error are unchanged (os --help and the full command table read byte-identical before and after)", "ref": "claude/issue-21285-drop-dead-oclif-plugins" }
0 commit comments