octwin-cli 0.1.21 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,350 +1,478 @@
1
- # Changelog — octwin-cli
2
-
3
- All notable changes to the `octwin` CLI (npm package [`octwin-cli`](https://www.npmjs.com/package/octwin-cli)).
4
- Format: [Keep a Changelog](https://keepachangelog.com/) — newest first, bucketed into
5
- **Added · Changed · Deprecated · Removed · Fixed · Security**. The platform-wide view lives in the
6
- repo root [`CHANGELOG.md`](../../CHANGELOG.md); this file is the CLI-only cut that ships with the package.
7
-
8
- ## [0.1.21] - 2026-07-30
9
-
10
- ### Added
11
- - **`deploy` and `status` report the marketplace-listing verdict.** A manifest carrying
12
- `listing.public: true` put the pack into an operator review queue, and the state existed only in
13
- the console so an author working from the CLI got no acknowledgement that the request had
14
- registered, and never saw a rejection note (which the platform *requires* precisely because it is
15
- their only feedback). Both commands now print it via `printPublicListing`, and stay silent for a
16
- pack that never asked. `status` also distinguishes *approved* from *actually public*: an approval
17
- pins the content sha it reviewed, so any edit returns the pack to the queue on its own.
18
- - **`octwin pull` is discoverable.** It was implemented and answered `--help`, but appeared in
19
- neither `octwin help` nor the README — the one command that recovers a deployed pack's only source
20
- copy was invisible unless you already knew its name. Also added to the scope-requirement table, so
21
- a 403 names `pack:deploy` instead of printing the generic hint.
22
-
23
- ### Fixed
24
- - **The capability-reference drift check no longer fails silently on a narrow token.** The `?meta=1`
25
- poll needs `pack:deploy`, but it rides on every networked command so an author inspecting data
26
- with a `records:read`-only token got no drift signal at all, and a stale reference is exactly what
27
- leads to inventing a primitive from memory. A 401/403 there now says so once.
28
- - **README: casework is declared in `worklist.yaml`, not a `cases.yaml`.** That grammar was retired;
29
- following the README produced a pack whose casework silently never loaded. `octwin media generate`
30
- was also missing from the command table.
31
- - **`records` no longer blames the plan for a route the plan does not gate.** `GET /xrm/entities`
32
- carries only the scope guard, so a 403 on the entity list wrongly cited the `records` plan feature.
33
-
34
- ### Removed
35
- - **Unreachable rename branches in `init`.** The agent-id and `main`-flow renames sat behind
36
- `--agent` / `--flow` options the CLI never parsed, against a template that ships no `main` flow
37
- both branches could never fire, and their patterns would have matched nothing if they had.
38
-
39
- ## [0.1.20] - 2026-07-29
40
-
41
- ### Added
42
- - **`octwin validate` catches primitive arguments the platform would drop offline, no token.** A
43
- primitive takes the arguments it declares and silently ignored the rest, so an invented or
44
- misspelled `args:` key deployed clean, ran clean, and simply did nothing: `record_list args: {
45
- order: }` (the argument is `sort`) never ordered, and `booking_cancel args: { booking_record_id:
46
- }` meant the REQUIRED `record_id` never arrived, so cancelling just failed. Validate now replays
47
- the platform's contract from the pulled KB (`primitives/*.json` `inputSchema`) and names the bad
48
- argument, what the primitive takes, and any required argument that is missing. Scanning the 21
49
- shipped marketplace packs found **ten** such errors across five packs. Keys are checked, values are
50
- not an `args:` value is normally an expression string resolved at runtime.
51
- [`args-check.ts`](src/lib/args-check.ts).
52
- - Silently skipped when the KB has not been pulled yet, like the render-intent check beside it.
53
- - It cannot see inside a `use:` template body (expanding one is the platform's job) — `octwin
54
- validate --remote` covers that case, and now also reports unreachable `$bind.<path>` reads and
55
- `outputs:` port typos, which have no offline equivalent.
56
-
57
- ## [0.1.19] - 2026-07-29
58
-
59
- ### Added
60
- - **`octwin validate` catches render-intent fields the platform would drop offline, no token.** Each
61
- render intent takes a fixed field set; a key outside it used to be swallowed at load and dropped at
62
- render, with no error anywhere just a card missing what the author wrote. Validate now replays the
63
- platform's own contract from the pulled KB (`render-intents/*.json` `allowed_keys`) and names the
64
- bad field, the intent, and what is allowed. Scanning the 21 shipped marketplace packs found two real
65
- instances in 223 intents: a `text_card` carrying `buttons` (the fallback's only escape button never
66
- rendered) and a `list_picker` carrying a non-existent `group_by` (a whole mapper step feeding a
67
- fabricated parameter). Silently skipped when the KB has not been pulled yet.
68
-
69
- ### Changed
70
- - **`octwin platform-kb pull` now explodes the reference and writes an `INDEX.md`.** A pull used to
71
- write ~787 KB across 34 flat files about 225k tokens, more than the pack being authored — so
72
- finding one primitive meant reading a 122 KB catalog. Catalogs the platform describes as
73
- enumerable are now written **one file per entry** (`primitives/record_list.json`,
74
- `render-intents/carousel.json`, `declarations/xrm.json`, …), with `INDEX.md` mapping every doc and
75
- all 171 entries to its file with a one-line summary. Reading one primitive went from ~38k tokens to
76
- ~700. The layout comes from the platform (an `entries` descriptor on the bundle index) rather than
77
- being hardcoded here, so this CLI keeps working against any platform version and a platform that
78
- adds a catalog needs no CLI release. The pulled directory is cleared each pull, so a withdrawn
79
- capability cannot linger as a file the authoring agent reads as current its *contents* are
80
- cleared rather than the directory itself, since on Windows a directory that is any shell's working
81
- directory cannot be removed.
82
-
83
- ## [0.1.18] - 2026-07-29
84
-
85
- ### Fixed
86
- - **The bundle collector and the platform's repo import disagreed about what a pack directory
87
- contains.** `collectBundleFiles` had its own rule and kept three things the operator's GitHub
88
- import drops: `*.ts`/`*.tsx`, `__snapshots__/` and `*.example`. Because the server rejects a
89
- `.ts` outright, the same directory imported cleanly from GitHub and failed to deploy from
90
- disk with `'…': executable code is not allowed` an error blaming a file that was never
91
- meant to ship (a snapshot test beside a flow, or the documented `xrm.yaml.example` template).
92
- The rule now lives in a vendored `lib/pack-source.ts` beside the vendored validator, and a
93
- parity test in the platform drives both copies over one table.
94
-
95
- ### Removed
96
- - **`pack.json` is gone — the saved login IS the deploy target.** The file had eroded to a single
97
- field, `platform_url`, which `octwin login --url --token …` already states; `tenant`/`project`
98
- became optional overrides once deploy tokens started carrying their own tenant and project pin.
99
- So it was a second home for a fact `login` knew, and it cost real things: a machine-specific file
100
- committed into every pack repo, a four-link config-precedence chain to document, and an
101
- exclusion rule duplicated in the bundler and the server (which had already drifted apart).
102
- `octwin init` and `octwin pull` no longer write one, and nothing reads one. **A pack directory is
103
- now pack content and nothing else** the same repo deploys from any machine, and a pulled pack
104
- redeploys with no flags.
105
-
106
- ### Changed
107
- - **`octwin login` now sets the default deploy target**, not just the token: it writes a
108
- `default_url` key alongside the token in `~/.octwin/credentials.json`. Every command resolves
109
- **flags → env (`PACK_PLATFORM_URL`/`PACK_TENANT`/`PACK_PROJECT`/`PACK_TOKEN`) → saved login**.
110
- An existing credentials file simply has no `default_url` until the next `octwin login` — which is
111
- exactly what the "no platform url" error now tells you to run. CI is unaffected (it passes
112
- `PACK_PLATFORM_URL` + `PACK_TOKEN` as env and never had a `pack.json`).
113
-
114
- ## [0.1.17] - 2026-07-27
115
-
116
- ### Added
117
- - **`octwin pull <packId>` write a DEPLOYED pack's source back to disk.** The inverse of
118
- `deploy`. A pack pushed with the CLI lived on the platform as an artifact the runtime served
119
- but nothing could hand back, so its only source copy was the machine that pushed it. Pull it,
120
- fix it, redeploy it. Writes a `pack.json` (retired in 0.1.18 the saved login is now the
121
- target) so the pulled directory redeploys where it came from; `--version` picks a version,
122
- `--force` overwrites a non-empty dir. You may pull a pack
123
- your tenant OWNS (an operator token pulls any) a pack you merely installed is not yours to
124
- read.
125
- - **`octwin chat --script <file>` — drive a whole conversation from one invocation.** One turn per
126
- line, in order, in a single process over a single SSE connection, waiting for each turn to settle
127
- before sending the next. Blank lines and `#` comments are skipped; `tap:<id>` presses a rendered
128
- row/button (the rest of the line is kept verbatim, since a tap id is itself colon-delimited),
129
- `media:<path>` uploads a file, and `media:<path> | caption` attaches one.
130
-
131
- This exists because **chaining invocations races the agent loop.** A turn ends on a quiet gap
132
- (`TURN_SETTLE_MS`), which can arrive while the server-side loop is still running — so
133
- `chat A && chat B` lets B's inbound land mid-turn, and the agent fills required fields with
134
- placeholder text (`service_id: "service-id"`) or starts a second workflow run. Those look exactly
135
- like flow bugs and cost a field author three separate investigations. The one-turn-per-invocation
136
- rule is now stated in `chat --help` and the header usage as well.
137
-
138
- ### Changed
139
- - **`octwin deploy` reports the suspended runs it invalidated.** A redeploy rebuilds the pack's
140
- tools, and in-flight flow runs live in those tools so every suspended conversation is dropped.
141
- The deploy prints `ⓘ N suspended run(s) invalidated` when N > 0, instead of leaving the author to
142
- discover it as a `workflow_resume_stale` on the next tap.
143
-
144
- ## [0.1.16] - 2026-07-26
145
-
146
- ### Added
147
- - **A pack can ship committed images.** `jpg`/`jpeg`/`png`/`webp`/`gif`/`pdf` files in your pack
148
- directory now travel as a separate `blobs` half of the bundle (base64 on the wire, `bytea` in
149
- storage) instead of being rejected as "not an allowed pack file type". Declare each one under the
150
- manifest's `static_assets: [{ file, key }]` and reference it from `config:` with the
151
- `$pack_asset:<key>` sentinel — the platform uploads it to the media system at install and the
152
- sentinel resolves to the served URL. `octwin validate` reports the image count alongside the file
153
- count.
154
- - **The size ceilings fail locally, before upload** 2 MB per file, 32 MB of binary per pack,
155
- mirroring the server. `svg` stays rejected: it is script-capable and these assets are served to
156
- browsers.
157
-
158
- ### Fixed
159
- - **Committed images were silently corrupted.** `collectBundleFiles` read *every* file with
160
- `readFileSync(full, 'utf8')`, so a JPEG went through a lossy UTF-8 decode and arrived mangled
161
- server-side — a deploy that "succeeded" and rendered a broken image. Binary files now split off
162
- into `blobs` and keep their bytes.
163
- - **`octwin status` reported `loaded=(none)` for every pack, always.** It printed a `loaded_version`
164
- field that stopped existing when reload moved to content-sha keying, which also meant the
165
- version-drift warning underneath it could never fire. It now prints the **content sha** the
166
- instance has loaded and the one the catalog holds (with the artifact's `origin`), and warns off the
167
- platform's own `up_to_date` flag. The sha is the more useful fact anyway: re-publishing the *same*
168
- version changes it, which is exactly the author's inner loop. A pack that is live and current but
169
- **withdrawn** from the catalog now says so, rather than reporting a clean bill of health.
170
-
171
- ## [0.1.15] - 2026-07-25
172
-
173
- ### Added
174
- - **`octwin agents [packId::agentId] [--prompt]` see what your agent actually runs as.** The platform
175
- gained *governed* agent settings: an operator platform default can override the `default_model`
176
- (and history window / working-memory toggle) your manifest declares, and that override is invisible
177
- from the pack source. The command prints each governed setting's **effective** value, **which layer
178
- won** (project override platform default pack manifest), and warns explicitly when your pack's
179
- declared value is *not* in force. `--prompt` prints the exact system prompt the LLM sees for this
180
- project (pack instructions + platform protocol + any project overlay).
181
- - **`octwin orders [reference_id]` the commerce a conversation produced.** The list (number,
182
- status/payment, total, contact) or one order with its line items, the
183
- subtotal/tax/shipping/discount/total breakdown, `payment_ref`, and the allowed transitions. On a
184
- `pending`/`none` payment it explains *why that's expected*: the forward payment lifecycle is
185
- **webhook-owned** (not patchable), and the default gateway-less `manual` driver makes
186
- `payment_request` take its `empty` port — so the flow should confirm pay-on-delivery, not error.
187
- - **`octwin analytics [entity]` — stage conversion for any pipelined entity.** The funnel engine that
188
- powered journeys is now generic, so any entity declared with a `pipeline:` charts conversion +
189
- drop-off (`--overview` / `--milestones` / `--trends` / `--cost`, and `--stage <id>` for the records
190
- currently at a stage). An empty result names **both** causes the platform folds into one response
191
- no `pipeline:`, or no `view` grant on `record.<entity>`.
192
- - **`octwin catalog [--readiness]`** commerce products with price, availability and stock
193
- (`untracked` when the SKU isn't inventory-tracked), plus the WhatsApp catalog binding.
194
- `--readiness` runs the Meta Graph checklist with each failing item's suggested fix.
195
- - **`octwin scheduling [--slots <resourceRecordId>]`** the engine state (bookable resource types,
196
- upcoming slots, booked seats) or the computed slots for one resource. This is how you verify the
197
- availability rules a `deploy --seed` created, which 0.1.14 could create but not read back.
198
-
199
- ### Changed
200
- - **Auth failures now name the scope the command needs.** Every 401/403 appends the required scope
201
- (and the plan feature, where the route is entitlement-gated) from one client-side mirror of the
202
- platform's scope registry — replacing the per-command hardcoded strings, several of which named no
203
- scope at all. It also spells out that `pack:deploy` / `media:generate` are direct-grant only, so a
204
- `tenant:admin` preset token does **not** confer them (the most common "but my token is admin" dead end).
205
-
206
- ## [0.1.14] - 2026-07-23
207
-
208
- ### Fixed
209
- - **A failed demo seed no longer reports a clean `✓`.** `deploy` softens non-fatal
210
- install steps (e.g. a demo-seed row) to warning frames, but the summary still printed
211
- `✓ Deployed` and exited 0 so a deploy that seeded ZERO records read as success (the
212
- false-✓ trap). `deploy` now collects those step errors, prints `⚠ Deployed with N
213
- warning(s) — data may be incomplete` with each message, and exits non-zero so CI /
214
- a `deploy && chat` chain catches it.
215
-
216
- ### Added
217
- - **`login` echoes what the token reaches.** After saving, `octwin login` calls
218
- `/api/self/t/whoami` and prints the workspace, project pin, and scopes so a fresh
219
- token self-identifies without a second `octwin whoami` (best-effort; a network failure
220
- never fails the save).
221
- - **`validate --remote` surfaces warnings + the data-store trap.** The remote validate now
222
- renders advisory `⚠` warnings (which don't block deploy) and, for a pack declaring
223
- `required_adapters: [data-store]`, reports the missing-data-store error the deploy would
224
- have 409'd onplus a warning that an `xrm.yaml` pack usually shouldn't declare that
225
- adapter at all. It also now catches (offline) a list-form `entities:` block and a
226
- `localized: true` field seeded with a bare string traps that previously surfaced only
227
- mid-seed at deploy.
228
-
229
- ## [0.1.13] - 2026-07-22
230
-
231
- ### Added
232
- - **A headless media loop — produce + send.** Two paired additions close the coverage hole where any
233
- media-collect flow (e.g. `activate-app`'s registration / ID uploads) stalled at the upload prompt
234
- because the CLI could neither *make* nor *send* an image:
235
- - `octwin media generate "<prompt>" [--out <file.png>] [--size 1024x1024] [--json]` AI-generates an
236
- image on the platform (needs a `media:generate`-scoped token), stores it as a public asset, and prints
237
- its `MEDIA-` handle + serve URL. `--out` downloads the bytes to a file (WhatsApp renders only
238
- `.png`/`.jpg`); `--json` emits `{ media_id, url, mime, width, height, bytes }`.
239
- - `octwin chat --media <file|media-id>` uploads a local file (or a media id from
240
- `media generate --json`) as an image/document/audio inbound; any accompanying `"message"` rides as
241
- its caption. The platform's media pipeline folds the upload into a running collect, so media flows
242
- are now fully drivable headlessly.
243
-
244
- ### Changed
245
- - **The KB-drift nudge now names what changed.** With the platform serving per-entry content hashes, the
246
- post-command nudge appends a `(N changed · M added · K removed)` summary instead of a bare hash pair.
247
- - **`octwin platform-kb` prints a changelog on pull.** Instead of only a doc/catalog count, the pull now
248
- diffs the fresh index against your last pull and lists exactly which docs/catalogs were added (`+`),
249
- changed (`~`), or removed (`-`) so a replaced schema shape is visible, not silent.
250
-
251
- ## [0.1.12] - 2026-07-22
252
-
253
- ### Fixed
254
- - **The KB-drift nudge now fires after `chat` too.** `chat` the command a debugging session runs most —
255
- was missing from the networked-command list, so a chat-heavy session never noticed the platform's
256
- capability reference had moved. The nudge also now shows the concrete drift
257
- (`old-hash new-hash`) so you can see it's real, not a heuristic.
258
-
259
- ### Changed
260
- - **Every networked command announces what it's doing before it does it.** `chat` prints
261
- `→ Connecting to <tenant>/<project> as '<handle>' …` before opening the stream and
262
- `… delivered waiting for the reply (up to Ns)` after the send; `status` / `whoami` /
263
- `platform-kb` / `records` / `logs` / `cases` each print a one-line `→ …` header naming the
264
- action and target before the first network call no more silent seconds followed by a result
265
- (or a hang with no clue what was being attempted). JSON modes (`--json`) stay clean for piping.
266
-
267
- ## [0.1.11] - 2026-07-21
268
-
269
- ### Fixed
270
- - **Auth-failure hint on every command, not just the inspect family** (author-feedback A7). `validate`,
271
- `deploy`, `status`, and the single-record read now print the scope/transient explanation on a 401/403
272
- (the shared `authFailureHint`), instead of a bare `HTTP 401` that left it ambiguous whether the token
273
- lacked a scope or the platform hiccupped.
274
-
275
- ## [0.1.10] - 2026-07-21
276
-
277
- The capability reference is now **pulled, never bundled** the authoring skill dropped its committed KB
278
- snapshot, so `octwin platform-kb pull` is the single source of truth, and the CLI watches it for drift.
279
-
280
- ### Added
281
- - **KB-drift nudge** — after any command that already talks to the platform (`deploy` / `status` /
282
- `test` / `validate --remote` / `records` / `cases` / `logs` / `whoami`), the CLI does one tiny
283
- `octwin-platform-kb?meta=1` GET and prints a one-line "the platform capability reference changed
284
- `octwin platform-kb pull`" when the platform's `content_hash` no longer matches your last pull.
285
- Fail-silent + TTY-only + no-op until you've pulled once — the sibling of the existing CLI-upgrade notice.
286
-
287
- ### Changed
288
- - **`octwin platform-kb pull`** now records the reference's `content_hash` in `.octwin/platform-kb/index.json`
289
- (the fingerprint the drift check compares against).
290
-
291
- The conversation-debugging release driven by the second author-feedback round (xpeng-egypt),
292
- which found the author→validate→deploy loop solid but multi-turn debugging impossible from the CLI.
293
-
294
- ### Added
295
- - **`octwin chat --tap "<tap-id>"`** press a rendered button / list row (sends the web channel's
296
- `type:'interactive'` inbound). Paired with full render printing, any tap-driven flow is now drivable headlessly.
297
- - **Full render printing** every reply prints its complete interactive content: list sections/rows,
298
- buttons, and carousel cards, each with its **tap id**; header/footer/list-button text included.
299
- - **`--json` on `chat` / `logs` / `cases`** — raw SSE envelopes (chat) or raw event/case payloads.
300
- - **`octwin cases [caseId] [--queues]`** — inspect casework (support tickets): the inbox, one case +
301
- timeline + applicable decisions, or queue keys with open counts. Casework packs previously had zero
302
- data-inspection path (`records case` was a dead end).
303
- - **Per-subcommand `--help`/`-h`** intercepted before any network or auth work (previously
304
- `octwin logs --help` made a network call and could die with a 401).
305
- - Multi-message turns: `chat` now collects **all** of a turn's renders (quiet-gap detection) instead
306
- of cutting at the first one.
307
-
308
- ### Changed
309
- - **`octwin logs`**: the conversation list shows contact handle + last activity and filters with
310
- `--as <handle>`; the timeline prints **full** event text (no more 240-char truncation) plus the
311
- renders each turn actually sent; footer points at `--json` / `mastra-messages` for verbatim payloads.
312
- - **Network failures name the target URL** (`platform unreachable at <url>`), and 401s explain
313
- invalid-token vs one-off transient instead of a bare status code.
314
- - `octwin records` on an unknown entity now surfaces the server's error body, and for `case`/`cases`
315
- points at `octwin cases`.
316
-
317
- ### Fixed
318
- - **Multi-turn chat actually works.** Two bugs made consecutive `octwin chat` calls look like "every
319
- call starts fresh": (1) the idempotency `local_id` was a **constant** per handle, so the platform's
320
- 5-minute inbound dedup silently dropped the second message a fresh id is now minted per call;
321
- (2) a fresh SSE connect **replays** recent history and the CLI printed the first render frame — i.e.
322
- the *previous* turn's greeting — as the reply; the CLI now drains the replay and only accepts frames
323
- newer than the connect boundary. The platform always kept one open conversation per `--as` handle —
324
- the same handle genuinely continues the same conversation now.
325
-
326
- ## [0.1.8] - 2026-07-21
327
- - Global-first install guidance (`npm i -g octwin-cli`); upgrade notice suppressed under `npx`.
328
-
329
- ## [0.1.7] - 2026-07-21
330
- - `--version`/`-v` flag; daily fail-silent, TTY-only "newer version available" notice.
331
-
332
- ## [0.1.6] - 2026-07-21
333
- - `octwin init` scaffolds a home-hub menu (`home` list_picker + example `browse` tool) instead of a bare greeting.
334
-
335
- ## [0.1.5] - 2026-07-20
336
- - `octwin validate --remote` (the platform's FULL manifest + flow-DSL check, all errors at once);
337
- headless debugging commands `octwin records` / `octwin logs` / `octwin chat`; `octwin test` became
338
- an alias for `validate --remote`. First author-feedback round.
339
-
340
- ## [0.1.4] - 2026-07-20
341
- - Authoring reliability + DX fixes from the first end-to-end external-pack test.
342
-
343
- ## [0.1.3] - 2026-07-20
344
- - `octwin platform-kb pull` — pull the platform capability reference for the authoring skill.
345
-
346
- ## [0.1.2] - 2026-07-20
347
- - Proper npm README.
348
-
349
- ## [0.1.1] - 2026-07-20
350
- - Initial npm publish: `init` / `validate` / `login` / `whoami` / `deploy` / `status`, `oct_` deploy tokens.
1
+ # Changelog — octwin-cli
2
+
3
+ All notable changes to the `octwin` CLI (npm package [`octwin-cli`](https://www.npmjs.com/package/octwin-cli)).
4
+ Format: [Keep a Changelog](https://keepachangelog.com/) — newest first, bucketed into
5
+ **Added · Changed · Deprecated · Removed · Fixed · Security**. The platform-wide view lives in the
6
+ repo root [`CHANGELOG.md`](../../CHANGELOG.md); this file is the CLI-only cut that ships with the package.
7
+
8
+ ## [0.5.1] - 2026-08-01
9
+
10
+ ### Fixed
11
+ - **`validate --remote` blamed the platform's version for a bad `--project`.** Every 404 from
12
+ `POST /api/self/p/packs/validate` printed *"this platform has no /packs/validate endpoint yet
13
+ (older version)"*. That was accurate when the route resolved nothing, but it now resolves the
14
+ tenant and project **before** validating and an unknown project, or one outside a token's pin,
15
+ answers 404 by design. So a typo in `--project` sent you looking for a version mismatch instead of
16
+ at the flag. The two cases are now told apart by the response **body**, not the status: a missing
17
+ route is Fastify's `error: 'Not Found'` and keeps the old wording, while the platform's own
18
+ `project '<slug>' not found under tenant` is printed as-is, with the flags to check.
19
+
20
+ ## [0.5.0] - 2026-08-01
21
+
22
+ ### Added
23
+ - **`octwin seed [--pack <packId>]`** — apply the pack's demo/reference data to the project it is
24
+ installed on, without redeploying: `xrm.yaml` `demo:` records + scheduling availability, the
25
+ commerce catalog, and the demo operator topology. Reports what **each kind** produced.
26
+ Previously seeding was reachable only as `deploy --seed`, because the platform's seed endpoint was
27
+ keyed on an install id, guarded platform-admin, and carried no tenant/project segments so the
28
+ `/api/self/**` surface could not reach it and a `pack:deploy` token never could. Re-seeding meant
29
+ a full redeploy or asking an operator. Idempotent and cheap to re-run: records upsert, and
30
+ existing media is REUSED rather than regenerated, so a second pass reports zero images.
31
+
32
+ ## [0.4.0] - 2026-08-01
33
+
34
+ ### Added
35
+ - **`octwin projects create` / `octwin projects rm`** a **disposable end-to-end environment** from
36
+ the CLI, which is what marketplace developers have been missing. `octwin deploy` has always needed
37
+ a project that already existed and the CLI could only *list* them, so standing up a throwaway
38
+ full deployment meant opening the console or asking an operator. Now:
39
+ ```bash
40
+ octwin projects create "Scratch" # → slug `scratch`
41
+ octwin deploy --project scratch --seed # publish + install + demo data
42
+ octwin chat "hi" --project scratch # talk to it (--script for a whole conversation)
43
+ octwin projects rm scratch --yes # throw it away
44
+ ```
45
+ A throwaway environment is deliberately **not a special kind of thing** it is an ordinary
46
+ project in your own workspace, so it inherits your plan, entitlements, RBAC and teardown with no
47
+ separate lifecycle. `create` derives the URL slug from the name (`--slug` pins one, `--pack`
48
+ installs an already-published pack). `rm` is a HARD delete the project and everything cascading
49
+ from it, no undo, not the same as archiving so **without `--yes` it only prints what would be
50
+ destroyed**, making the dry run the default; the impact list is derived from `pg_constraint`, the
51
+ same payload the console's confirm dialog renders. Both need `projects:write`, which a
52
+ `pack:deploy` token does **not** confer the CLI names that scope in the 403 hint.
53
+
54
+ ## [0.3.0] - 2026-07-31
55
+
56
+ ### Added
57
+ - **`octwin projects`** — the `--project <slug>` values your token can actually name, with the plan's
58
+ project cap. Every project-scoped command takes that flag and nothing printed the list, so an
59
+ author whose token was not pinned had to guess, and a wrong guess 404s identically to a project
60
+ that exists but has no install. `--archived` includes archived projects; `--json` for raw.
61
+ A `pack:deploy` token reaches it: the platform route was widened to accept `pack:deploy` alongside
62
+ `projects:read`, because `pack:deploy` is `access: 'special'` and confers nothing else the
63
+ command would have 403ed for exactly the person it exists for.
64
+ - **`octwin validate --require-kb`** turn a skipped KB-driven check into a failure, for CI.
65
+
66
+ ### Fixed
67
+ - **`octwin validate` printed with two of its three checks switched off.** The render-intent and
68
+ primitive-argument checks read `<packDir>/.octwin/platform-kb/`, joined onto the pack directory
69
+ EXACTLY — so an author who pulled once at a repo root and then worked in `packs/<name>/` had both
70
+ checks silently disabled, and the printed above them unconditionally while the per-check ✓s lived
71
+ inside the `if`s. An entire batch of platform-backlog entries reached production through that hole.
72
+ Three fixes: the KB is now found by **walking up** (one pull at a repo root covers every pack under
73
+ it, `src/lib/kb-path.ts`); the readers report **three states** absent, malformed, ok — so a
74
+ half-written pull no longer reads as "you haven't pulled yet"; and a skip is **announced on the
75
+ last line printed**, because a caveat above a does not reach a reader who stopped at the ✓.
76
+ Warn-and-exit-0 stays the default (the KB is a gitignored cache and `platform-kb pull` needs
77
+ `pack:deploy`, so a hard failure would break a fresh clone) the defect was the silence, not the skip.
78
+ - **`octwin status` said "live and current" for a pack that could not receive a message.** Every field
79
+ it printed was process-global: `registered` is true for a pack ANY project on that instance loaded.
80
+ Dispatch is per-project and takes the oldest ACTIVE install, ignoring the rest. The route now
81
+ filters `status = 'active'` (an archived install used to report live) and compares against the real
82
+ dispatch target, so status can say plainly that another pack owns this project's messages.
83
+ - **`octwin validate --remote --project does-not-exist` answered `{ ok: true }`** while `deploy` with
84
+ the same flag 404ed. The platform route resolves tenant and project before validating now.
85
+
86
+ ### Changed
87
+ - **`octwin validate --remote` also runs the platform's flow LINT.** It used to run only at pack load,
88
+ so a finding of severity `error` an `assign:` whose value is a quoted literal, a `$t()` key with
89
+ no namespace passed validate and failed the deploy. Offline `validate` cannot do this: the lint
90
+ needs a template-expanded `FlowDef`, which only the server builds.
91
+ - **`record_aggregate` / `record_group` now REQUIRE a scope** (`contact_id` or `all: true`) — a
92
+ platform contract change the offline arg check replays from the KB. Re-pull after upgrading.
93
+
94
+ ## [0.2.0] - 2026-07-30
95
+
96
+ ### Fixed
97
+ - **`records`, `cases`, `orders` and `catalog` printed a correct total and ZERO rows.** The platform
98
+ collapsed its eight per-domain list envelopes into one `Page<T>` whose collection key is `rows`;
99
+ the CLI still read `json.records` / `.cases` / `.orders` / `.products` behind a `?? []`, so the
100
+ fallback turned a key rename into an empty list instead of an error. `octwin records doctor`
101
+ reported *"5 record(s)"* and then *"(none mint a `records:read` token …)"*, blaming the user's
102
+ credentials. All five readers now go through one `readPage` helper
103
+ (`src/lib/page.ts`) with a test pinned to the real envelope a hand-copied key name in an
104
+ untested CLI is what shipped this, so the fix is the single reader, not five edits.
105
+ - **`--flag=value` silently did nothing.** `--limit=5` became the key `limit=5` and the command ran
106
+ with its default. Now parsed; `--set`/`--param` also accept repetition.
107
+ - **`octwin catalog` always printed `Products: 0`** it counted the page, and the route's `total`
108
+ had never been read.
109
+
110
+ ### Added
111
+ - **Write commands a pack author can now exercise the state their pack creates, not just read it.**
112
+ Every one needs the matching `:write` scope; a leading verb (`create`/`note`/`transition`/…) is
113
+ what distinguishes a write from the read that shares its command.
114
+ - `records create|patch|stage|note`, `records tasks`, `records task complete`
115
+ - `cases assign|note|transition|decide` — `decide --dry-run` previews the customer-facing copy and
116
+ resulting status **without committing** (that route needs only `cases:read`)
117
+ - `orders transition|refund` · `catalog availability|stock` · `agents set`
118
+ - `scheduling rules|rule add|rule rm|exception add|exception rm`
119
+ - **`octwin feedback`** submits the pack's `FEEDBACK.md` to the platform team, attaching the pack
120
+ version, this CLI's version and the `content_hash` of the capability reference you pulled the two
121
+ facts that separate a real platform gap from something already fixed or a stale KB. Replaces
122
+ "hand the file to the platform team".
123
+ - **`--offset` on every list**, and a line saying when a list was truncated and what to run next.
124
+ `has_more` was on every response and no command surfaced it, so a partial list looked complete.
125
+
126
+ ### Changed
127
+ - `orders refund` **exits non-zero when the payment gateway refuses.** The route answers `200` with
128
+ the verdict in `gateway`, so reporting the HTTP status would tell an operator money moved when it
129
+ did not.
130
+ - A 403 on a record or case write now says it may be an **RBAC grant gap** rather than a missing
131
+ scope: the scope is checked on the token, then the verb is re-checked against that specific row.
132
+
133
+ ## [0.1.21] - 2026-07-30
134
+
135
+ > **Never published to npm.** Bumped in-repo, then superseded hours later by 0.2.0 everything
136
+ > below ships as part of that release. Kept as its own section because the changes are distinct.
137
+
138
+ ### Added
139
+ - **`deploy` and `status` report the marketplace-listing verdict.** A manifest carrying
140
+ `listing.public: true` put the pack into an operator review queue, and the state existed only in
141
+ the console so an author working from the CLI got no acknowledgement that the request had
142
+ registered, and never saw a rejection note (which the platform *requires* precisely because it is
143
+ their only feedback). Both commands now print it via `printPublicListing`, and stay silent for a
144
+ pack that never asked. `status` also distinguishes *approved* from *actually public*: an approval
145
+ pins the content sha it reviewed, so any edit returns the pack to the queue on its own.
146
+ - **`octwin pull` is discoverable.** It was implemented and answered `--help`, but appeared in
147
+ neither `octwin help` nor the README the one command that recovers a deployed pack's only source
148
+ copy was invisible unless you already knew its name. Also added to the scope-requirement table, so
149
+ a 403 names `pack:deploy` instead of printing the generic hint.
150
+
151
+ ### Fixed
152
+ - **The capability-reference drift check no longer fails silently on a narrow token.** The `?meta=1`
153
+ poll needs `pack:deploy`, but it rides on every networked command — so an author inspecting data
154
+ with a `records:read`-only token got no drift signal at all, and a stale reference is exactly what
155
+ leads to inventing a primitive from memory. A 401/403 there now says so once.
156
+ - **README: casework is declared in `worklist.yaml`, not a `cases.yaml`.** That grammar was retired;
157
+ following the README produced a pack whose casework silently never loaded. `octwin media generate`
158
+ was also missing from the command table.
159
+ - **`records` no longer blames the plan for a route the plan does not gate.** `GET /xrm/entities`
160
+ carries only the scope guard, so a 403 on the entity list wrongly cited the `records` plan feature.
161
+
162
+ ### Removed
163
+ - **Unreachable rename branches in `init`.** The agent-id and `main`-flow renames sat behind
164
+ `--agent` / `--flow` options the CLI never parsed, against a template that ships no `main` flow —
165
+ both branches could never fire, and their patterns would have matched nothing if they had.
166
+
167
+ ## [0.1.20] - 2026-07-29
168
+
169
+ ### Added
170
+ - **`octwin validate` catches primitive arguments the platform would drop — offline, no token.** A
171
+ primitive takes the arguments it declares and silently ignored the rest, so an invented or
172
+ misspelled `args:` key deployed clean, ran clean, and simply did nothing: `record_list args: {
173
+ order: … }` (the argument is `sort`) never ordered, and `booking_cancel args: { booking_record_id:
174
+ }` meant the REQUIRED `record_id` never arrived, so cancelling just failed. Validate now replays
175
+ the platform's contract from the pulled KB (`primitives/*.json` `inputSchema`) and names the bad
176
+ argument, what the primitive takes, and any required argument that is missing. Scanning the 21
177
+ shipped marketplace packs found **ten** such errors across five packs. Keys are checked, values are
178
+ not an `args:` value is normally an expression string resolved at runtime.
179
+ [`args-check.ts`](src/lib/args-check.ts).
180
+ - Silently skipped when the KB has not been pulled yet, like the render-intent check beside it.
181
+ - It cannot see inside a `use:` template body (expanding one is the platform's job) — `octwin
182
+ validate --remote` covers that case, and now also reports unreachable `$bind.<path>` reads and
183
+ `outputs:` port typos, which have no offline equivalent.
184
+
185
+ ## [0.1.19] - 2026-07-29
186
+
187
+ ### Added
188
+ - **`octwin validate` catches render-intent fields the platform would drop offline, no token.** Each
189
+ render intent takes a fixed field set; a key outside it used to be swallowed at load and dropped at
190
+ render, with no error anywhere just a card missing what the author wrote. Validate now replays the
191
+ platform's own contract from the pulled KB (`render-intents/*.json` `allowed_keys`) and names the
192
+ bad field, the intent, and what is allowed. Scanning the 21 shipped marketplace packs found two real
193
+ instances in 223 intents: a `text_card` carrying `buttons` (the fallback's only escape button never
194
+ rendered) and a `list_picker` carrying a non-existent `group_by` (a whole mapper step feeding a
195
+ fabricated parameter). Silently skipped when the KB has not been pulled yet.
196
+
197
+ ### Changed
198
+ - **`octwin platform-kb pull` now explodes the reference and writes an `INDEX.md`.** A pull used to
199
+ write ~787 KB across 34 flat files — about 225k tokens, more than the pack being authored — so
200
+ finding one primitive meant reading a 122 KB catalog. Catalogs the platform describes as
201
+ enumerable are now written **one file per entry** (`primitives/record_list.json`,
202
+ `render-intents/carousel.json`, `declarations/xrm.json`, …), with `INDEX.md` mapping every doc and
203
+ all 171 entries to its file with a one-line summary. Reading one primitive went from ~38k tokens to
204
+ ~700. The layout comes from the platform (an `entries` descriptor on the bundle index) rather than
205
+ being hardcoded here, so this CLI keeps working against any platform version and a platform that
206
+ adds a catalog needs no CLI release. The pulled directory is cleared each pull, so a withdrawn
207
+ capability cannot linger as a file the authoring agent reads as current — its *contents* are
208
+ cleared rather than the directory itself, since on Windows a directory that is any shell's working
209
+ directory cannot be removed.
210
+
211
+ ## [0.1.18] - 2026-07-29
212
+
213
+ ### Fixed
214
+ - **The bundle collector and the platform's repo import disagreed about what a pack directory
215
+ contains.** `collectBundleFiles` had its own rule and kept three things the operator's GitHub
216
+ import drops: `*.ts`/`*.tsx`, `__snapshots__/` and `*.example`. Because the server rejects a
217
+ `.ts` outright, the same directory imported cleanly from GitHub and failed to deploy from
218
+ disk with `'…': executable code is not allowed` an error blaming a file that was never
219
+ meant to ship (a snapshot test beside a flow, or the documented `xrm.yaml.example` template).
220
+ The rule now lives in a vendored `lib/pack-source.ts` beside the vendored validator, and a
221
+ parity test in the platform drives both copies over one table.
222
+
223
+ ### Removed
224
+ - **`pack.json` is gone the saved login IS the deploy target.** The file had eroded to a single
225
+ field, `platform_url`, which `octwin login --url --token …` already states; `tenant`/`project`
226
+ became optional overrides once deploy tokens started carrying their own tenant and project pin.
227
+ So it was a second home for a fact `login` knew, and it cost real things: a machine-specific file
228
+ committed into every pack repo, a four-link config-precedence chain to document, and an
229
+ exclusion rule duplicated in the bundler and the server (which had already drifted apart).
230
+ `octwin init` and `octwin pull` no longer write one, and nothing reads one. **A pack directory is
231
+ now pack content and nothing else** — the same repo deploys from any machine, and a pulled pack
232
+ redeploys with no flags.
233
+
234
+ ### Changed
235
+ - **`octwin login` now sets the default deploy target**, not just the token: it writes a
236
+ `default_url` key alongside the token in `~/.octwin/credentials.json`. Every command resolves
237
+ **flags env (`PACK_PLATFORM_URL`/`PACK_TENANT`/`PACK_PROJECT`/`PACK_TOKEN`) saved login**.
238
+ An existing credentials file simply has no `default_url` until the next `octwin login` which is
239
+ exactly what the "no platform url" error now tells you to run. CI is unaffected (it passes
240
+ `PACK_PLATFORM_URL` + `PACK_TOKEN` as env and never had a `pack.json`).
241
+
242
+ ## [0.1.17] - 2026-07-27
243
+
244
+ ### Added
245
+ - **`octwin pull <packId>` write a DEPLOYED pack's source back to disk.** The inverse of
246
+ `deploy`. A pack pushed with the CLI lived on the platform as an artifact the runtime served
247
+ but nothing could hand back, so its only source copy was the machine that pushed it. Pull it,
248
+ fix it, redeploy it. Writes a `pack.json` (retired in 0.1.18 the saved login is now the
249
+ target) so the pulled directory redeploys where it came from; `--version` picks a version,
250
+ `--force` overwrites a non-empty dir. You may pull a pack
251
+ your tenant OWNS (an operator token pulls any) — a pack you merely installed is not yours to
252
+ read.
253
+ - **`octwin chat --script <file>` — drive a whole conversation from one invocation.** One turn per
254
+ line, in order, in a single process over a single SSE connection, waiting for each turn to settle
255
+ before sending the next. Blank lines and `#` comments are skipped; `tap:<id>` presses a rendered
256
+ row/button (the rest of the line is kept verbatim, since a tap id is itself colon-delimited),
257
+ `media:<path>` uploads a file, and `media:<path> | caption` attaches one.
258
+
259
+ This exists because **chaining invocations races the agent loop.** A turn ends on a quiet gap
260
+ (`TURN_SETTLE_MS`), which can arrive while the server-side loop is still running so
261
+ `chat A && chat B` lets B's inbound land mid-turn, and the agent fills required fields with
262
+ placeholder text (`service_id: "service-id"`) or starts a second workflow run. Those look exactly
263
+ like flow bugs and cost a field author three separate investigations. The one-turn-per-invocation
264
+ rule is now stated in `chat --help` and the header usage as well.
265
+
266
+ ### Changed
267
+ - **`octwin deploy` reports the suspended runs it invalidated.** A redeploy rebuilds the pack's
268
+ tools, and in-flight flow runs live in those tools — so every suspended conversation is dropped.
269
+ The deploy prints `ⓘ N suspended run(s) invalidated` when N > 0, instead of leaving the author to
270
+ discover it as a `workflow_resume_stale` on the next tap.
271
+
272
+ ## [0.1.16] - 2026-07-26
273
+
274
+ ### Added
275
+ - **A pack can ship committed images.** `jpg`/`jpeg`/`png`/`webp`/`gif`/`pdf` files in your pack
276
+ directory now travel as a separate `blobs` half of the bundle (base64 on the wire, `bytea` in
277
+ storage) instead of being rejected as "not an allowed pack file type". Declare each one under the
278
+ manifest's `static_assets: [{ file, key }]` and reference it from `config:` with the
279
+ `$pack_asset:<key>` sentinel — the platform uploads it to the media system at install and the
280
+ sentinel resolves to the served URL. `octwin validate` reports the image count alongside the file
281
+ count.
282
+ - **The size ceilings fail locally, before upload** 2 MB per file, 32 MB of binary per pack,
283
+ mirroring the server. `svg` stays rejected: it is script-capable and these assets are served to
284
+ browsers.
285
+
286
+ ### Fixed
287
+ - **Committed images were silently corrupted.** `collectBundleFiles` read *every* file with
288
+ `readFileSync(full, 'utf8')`, so a JPEG went through a lossy UTF-8 decode and arrived mangled
289
+ server-side a deploy that "succeeded" and rendered a broken image. Binary files now split off
290
+ into `blobs` and keep their bytes.
291
+ - **`octwin status` reported `loaded=(none)` for every pack, always.** It printed a `loaded_version`
292
+ field that stopped existing when reload moved to content-sha keying, which also meant the
293
+ version-drift warning underneath it could never fire. It now prints the **content sha** the
294
+ instance has loaded and the one the catalog holds (with the artifact's `origin`), and warns off the
295
+ platform's own `up_to_date` flag. The sha is the more useful fact anyway: re-publishing the *same*
296
+ version changes it, which is exactly the author's inner loop. A pack that is live and current but
297
+ **withdrawn** from the catalog now says so, rather than reporting a clean bill of health.
298
+
299
+ ## [0.1.15] - 2026-07-25
300
+
301
+ ### Added
302
+ - **`octwin agents [packId::agentId] [--prompt]` see what your agent actually runs as.** The platform
303
+ gained *governed* agent settings: an operator platform default can override the `default_model`
304
+ (and history window / working-memory toggle) your manifest declares, and that override is invisible
305
+ from the pack source. The command prints each governed setting's **effective** value, **which layer
306
+ won** (project override platform default → pack manifest), and warns explicitly when your pack's
307
+ declared value is *not* in force. `--prompt` prints the exact system prompt the LLM sees for this
308
+ project (pack instructions + platform protocol + any project overlay).
309
+ - **`octwin orders [reference_id]` the commerce a conversation produced.** The list (number,
310
+ status/payment, total, contact) or one order with its line items, the
311
+ subtotal/tax/shipping/discount/total breakdown, `payment_ref`, and the allowed transitions. On a
312
+ `pending`/`none` payment it explains *why that's expected*: the forward payment lifecycle is
313
+ **webhook-owned** (not patchable), and the default gateway-less `manual` driver makes
314
+ `payment_request` take its `empty` port so the flow should confirm pay-on-delivery, not error.
315
+ - **`octwin analytics [entity]` — stage conversion for any pipelined entity.** The funnel engine that
316
+ powered journeys is now generic, so any entity declared with a `pipeline:` charts conversion +
317
+ drop-off (`--overview` / `--milestones` / `--trends` / `--cost`, and `--stage <id>` for the records
318
+ currently at a stage). An empty result names **both** causes the platform folds into one response —
319
+ no `pipeline:`, or no `view` grant on `record.<entity>`.
320
+ - **`octwin catalog [--readiness]`**commerce products with price, availability and stock
321
+ (`untracked` when the SKU isn't inventory-tracked), plus the WhatsApp catalog binding.
322
+ `--readiness` runs the Meta Graph checklist with each failing item's suggested fix.
323
+ - **`octwin scheduling [--slots <resourceRecordId>]`** the engine state (bookable resource types,
324
+ upcoming slots, booked seats) or the computed slots for one resource. This is how you verify the
325
+ availability rules a `deploy --seed` created, which 0.1.14 could create but not read back.
326
+
327
+ ### Changed
328
+ - **Auth failures now name the scope the command needs.** Every 401/403 appends the required scope
329
+ (and the plan feature, where the route is entitlement-gated) from one client-side mirror of the
330
+ platform's scope registry replacing the per-command hardcoded strings, several of which named no
331
+ scope at all. It also spells out that `pack:deploy` / `media:generate` are direct-grant only, so a
332
+ `tenant:admin` preset token does **not** confer them (the most common "but my token is admin" dead end).
333
+
334
+ ## [0.1.14] - 2026-07-23
335
+
336
+ ### Fixed
337
+ - **A failed demo seed no longer reports a clean `✓`.** `deploy` softens non-fatal
338
+ install steps (e.g. a demo-seed row) to warning frames, but the summary still printed
339
+ `✓ Deployed` and exited 0 — so a deploy that seeded ZERO records read as success (the
340
+ false-✓ trap). `deploy` now collects those step errors, prints `⚠ Deployed with N
341
+ warning(s) data may be incomplete` with each message, and exits non-zero so CI /
342
+ a `deploy && chat` chain catches it.
343
+
344
+ ### Added
345
+ - **`login` echoes what the token reaches.** After saving, `octwin login` calls
346
+ `/api/self/t/whoami` and prints the workspace, project pin, and scopes — so a fresh
347
+ token self-identifies without a second `octwin whoami` (best-effort; a network failure
348
+ never fails the save).
349
+ - **`validate --remote` surfaces warnings + the data-store trap.** The remote validate now
350
+ renders advisory `⚠` warnings (which don't block deploy) and, for a pack declaring
351
+ `required_adapters: [data-store]`, reports the missing-data-store error the deploy would
352
+ have 409'd on — plus a warning that an `xrm.yaml` pack usually shouldn't declare that
353
+ adapter at all. It also now catches (offline) a list-form `entities:` block and a
354
+ `localized: true` field seeded with a bare string — traps that previously surfaced only
355
+ mid-seed at deploy.
356
+
357
+ ## [0.1.13] - 2026-07-22
358
+
359
+ ### Added
360
+ - **A headless media loop — produce + send.** Two paired additions close the coverage hole where any
361
+ media-collect flow (e.g. `activate-app`'s registration / ID uploads) stalled at the upload prompt
362
+ because the CLI could neither *make* nor *send* an image:
363
+ - `octwin media generate "<prompt>" [--out <file.png>] [--size 1024x1024] [--json]` — AI-generates an
364
+ image on the platform (needs a `media:generate`-scoped token), stores it as a public asset, and prints
365
+ its `MEDIA-` handle + serve URL. `--out` downloads the bytes to a file (WhatsApp renders only
366
+ `.png`/`.jpg`); `--json` emits `{ media_id, url, mime, width, height, bytes }`.
367
+ - `octwin chat --media <file|media-id>` — uploads a local file (or a media id from
368
+ `media generate --json`) as an image/document/audio inbound; any accompanying `"message"` rides as
369
+ its caption. The platform's media pipeline folds the upload into a running collect, so media flows
370
+ are now fully drivable headlessly.
371
+
372
+ ### Changed
373
+ - **The KB-drift nudge now names what changed.** With the platform serving per-entry content hashes, the
374
+ post-command nudge appends a `(N changed · M added · K removed)` summary instead of a bare hash pair.
375
+ - **`octwin platform-kb` prints a changelog on pull.** Instead of only a doc/catalog count, the pull now
376
+ diffs the fresh index against your last pull and lists exactly which docs/catalogs were added (`+`),
377
+ changed (`~`), or removed (`-`) — so a replaced schema shape is visible, not silent.
378
+
379
+ ## [0.1.12] - 2026-07-22
380
+
381
+ ### Fixed
382
+ - **The KB-drift nudge now fires after `chat` too.** `chat` — the command a debugging session runs most —
383
+ was missing from the networked-command list, so a chat-heavy session never noticed the platform's
384
+ capability reference had moved. The nudge also now shows the concrete drift
385
+ (`old-hash → new-hash`) so you can see it's real, not a heuristic.
386
+
387
+ ### Changed
388
+ - **Every networked command announces what it's doing before it does it.** `chat` prints
389
+ `→ Connecting to <tenant>/<project> as '<handle>' …` before opening the stream and
390
+ `… delivered — waiting for the reply (up to Ns)` after the send; `status` / `whoami` /
391
+ `platform-kb` / `records` / `logs` / `cases` each print a one-line `→ …` header naming the
392
+ action and target before the first network call — no more silent seconds followed by a result
393
+ (or a hang with no clue what was being attempted). JSON modes (`--json`) stay clean for piping.
394
+
395
+ ## [0.1.11] - 2026-07-21
396
+
397
+ ### Fixed
398
+ - **Auth-failure hint on every command, not just the inspect family** (author-feedback A7). `validate`,
399
+ `deploy`, `status`, and the single-record read now print the scope/transient explanation on a 401/403
400
+ (the shared `authFailureHint`), instead of a bare `HTTP 401` that left it ambiguous whether the token
401
+ lacked a scope or the platform hiccupped.
402
+
403
+ ## [0.1.10] - 2026-07-21
404
+
405
+ The capability reference is now **pulled, never bundled** — the authoring skill dropped its committed KB
406
+ snapshot, so `octwin platform-kb pull` is the single source of truth, and the CLI watches it for drift.
407
+
408
+ ### Added
409
+ - **KB-drift nudge** — after any command that already talks to the platform (`deploy` / `status` /
410
+ `test` / `validate --remote` / `records` / `cases` / `logs` / `whoami`), the CLI does one tiny
411
+ `octwin-platform-kb?meta=1` GET and prints a one-line "the platform capability reference changed —
412
+ `octwin platform-kb pull`" when the platform's `content_hash` no longer matches your last pull.
413
+ Fail-silent + TTY-only + no-op until you've pulled once — the sibling of the existing CLI-upgrade notice.
414
+
415
+ ### Changed
416
+ - **`octwin platform-kb pull`** now records the reference's `content_hash` in `.octwin/platform-kb/index.json`
417
+ (the fingerprint the drift check compares against).
418
+
419
+ The conversation-debugging release — driven by the second author-feedback round (xpeng-egypt),
420
+ which found the author→validate→deploy loop solid but multi-turn debugging impossible from the CLI.
421
+
422
+ ### Added
423
+ - **`octwin chat --tap "<tap-id>"`** — press a rendered button / list row (sends the web channel's
424
+ `type:'interactive'` inbound). Paired with full render printing, any tap-driven flow is now drivable headlessly.
425
+ - **Full render printing** — every reply prints its complete interactive content: list sections/rows,
426
+ buttons, and carousel cards, each with its **tap id**; header/footer/list-button text included.
427
+ - **`--json` on `chat` / `logs` / `cases`** — raw SSE envelopes (chat) or raw event/case payloads.
428
+ - **`octwin cases [caseId] [--queues]`** — inspect casework (support tickets): the inbox, one case +
429
+ timeline + applicable decisions, or queue keys with open counts. Casework packs previously had zero
430
+ data-inspection path (`records case` was a dead end).
431
+ - **Per-subcommand `--help`/`-h`** — intercepted before any network or auth work (previously
432
+ `octwin logs --help` made a network call and could die with a 401).
433
+ - Multi-message turns: `chat` now collects **all** of a turn's renders (quiet-gap detection) instead
434
+ of cutting at the first one.
435
+
436
+ ### Changed
437
+ - **`octwin logs`**: the conversation list shows contact handle + last activity and filters with
438
+ `--as <handle>`; the timeline prints **full** event text (no more 240-char truncation) plus the
439
+ renders each turn actually sent; footer points at `--json` / `mastra-messages` for verbatim payloads.
440
+ - **Network failures name the target URL** (`platform unreachable at <url>`), and 401s explain
441
+ invalid-token vs one-off transient instead of a bare status code.
442
+ - `octwin records` on an unknown entity now surfaces the server's error body, and for `case`/`cases`
443
+ points at `octwin cases`.
444
+
445
+ ### Fixed
446
+ - **Multi-turn chat actually works.** Two bugs made consecutive `octwin chat` calls look like "every
447
+ call starts fresh": (1) the idempotency `local_id` was a **constant** per handle, so the platform's
448
+ 5-minute inbound dedup silently dropped the second message — a fresh id is now minted per call;
449
+ (2) a fresh SSE connect **replays** recent history and the CLI printed the first render frame — i.e.
450
+ the *previous* turn's greeting — as the reply; the CLI now drains the replay and only accepts frames
451
+ newer than the connect boundary. The platform always kept one open conversation per `--as` handle —
452
+ the same handle genuinely continues the same conversation now.
453
+
454
+ ## [0.1.8] - 2026-07-21
455
+ - Global-first install guidance (`npm i -g octwin-cli`); upgrade notice suppressed under `npx`.
456
+
457
+ ## [0.1.7] - 2026-07-21
458
+ - `--version`/`-v` flag; daily fail-silent, TTY-only "newer version available" notice.
459
+
460
+ ## [0.1.6] - 2026-07-21
461
+ - `octwin init` scaffolds a home-hub menu (`home` list_picker + example `browse` tool) instead of a bare greeting.
462
+
463
+ ## [0.1.5] - 2026-07-20
464
+ - `octwin validate --remote` (the platform's FULL manifest + flow-DSL check, all errors at once);
465
+ headless debugging commands `octwin records` / `octwin logs` / `octwin chat`; `octwin test` became
466
+ an alias for `validate --remote`. First author-feedback round.
467
+
468
+ ## [0.1.4] - 2026-07-20
469
+ - Authoring reliability + DX fixes from the first end-to-end external-pack test.
470
+
471
+ ## [0.1.3] - 2026-07-20
472
+ - `octwin platform-kb pull` — pull the platform capability reference for the authoring skill.
473
+
474
+ ## [0.1.2] - 2026-07-20
475
+ - Proper npm README.
476
+
477
+ ## [0.1.1] - 2026-07-20
478
+ - Initial npm publish: `init` / `validate` / `login` / `whoami` / `deploy` / `status`, `oct_` deploy tokens.