octwin-cli 0.1.16 → 0.1.21

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
@@ -5,6 +5,142 @@ Format: [Keep a Changelog](https://keepachangelog.com/) — newest first, bucket
5
5
  **Added · Changed · Deprecated · Removed · Fixed · Security**. The platform-wide view lives in the
6
6
  repo root [`CHANGELOG.md`](../../CHANGELOG.md); this file is the CLI-only cut that ships with the package.
7
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
+
8
144
  ## [0.1.16] - 2026-07-26
9
145
 
10
146
  ### Added
package/README.md CHANGED
@@ -43,7 +43,7 @@ git init && git add -A && git commit -m "init pack"
43
43
  # 2. Author it — edit manifest.yaml, flows/tools/main.flow.yaml (+ its locale),
44
44
  # and prompts/identity.md. Everything is pure YAML.
45
45
 
46
- # 3. Point it at your platform: edit pack.json, then log in with a deploy token
46
+ # 3. Point it at your platform one command, no config file
47
47
  # (Octwin console → your workspace → API tokens → Generate)
48
48
  octwin login --url https://your-octwin.example.com --token oct_…
49
49
 
@@ -60,12 +60,13 @@ octwin status # "✓ live and current" once it's warm
60
60
 
61
61
  | Command | What it does |
62
62
  | --- | --- |
63
- | `octwin init <dir>` | Scaffold a new pure-YAML pack into `<dir>` (writes a starter `manifest.yaml`, flow, prompt, and `pack.json`). Options: `--id`, `--description`, `--display-name`. |
63
+ | `octwin init <dir>` | Scaffold a new pure-YAML pack into `<dir>` (writes a starter `manifest.yaml`, flow, prompt, `.gitignore` and `README.md` — pack content only). Options: `--id`, `--description`, `--display-name`. |
64
64
  | `octwin validate` | Check the pack locally (structure + pure-YAML rules). The platform re-validates the full manifest/flow schema on deploy. |
65
- | `octwin login` | Save a deploy token for a platform URL (stored in `~/.octwin/credentials.json`). `--url`, `--token`. |
65
+ | `octwin login` | Save a deploy token for a platform URL **and make that URL the default target** (both stored in `~/.octwin/credentials.json`). `--url`, `--token`. |
66
66
  | `octwin whoami` | Verify the saved/passed token is valid for a tenant. `--url`, `--tenant`. |
67
- | `octwin deploy` | Upload + install the pack onto your tenant's project. `--seed` also runs the pack's demo seed. |
68
- | `octwin status` | Report what the platform has live for this pack — installed version, the **content sha** the instance loaded vs. the one the catalog holds (a redeploy of the *same* version changes it), and its flows. |
67
+ | `octwin deploy` | Upload + install the pack onto your tenant's project. `--seed` also runs the pack's demo seed. Reports the **marketplace-listing verdict** when the manifest carries `listing.public: true`. |
68
+ | `octwin status` | Report what the platform has live for this pack — installed version, the **content sha** the instance loaded vs. the one the catalog holds (a redeploy of the *same* version changes it), its flows, and whether it is live on the public marketplace. |
69
+ | `octwin pull <packId>` | Write a **deployed** pack's source back to disk — the inverse of `deploy`, and how a pack pushed from one machine is recovered. Defaults to the version installed on the target project; `--version` overrides, `--dir` defaults to `./<packId>`, a non-empty dir needs `--force`. You may pull a pack your tenant **owns**. |
69
70
  | `octwin chat "msg"` | Drive a turn through the dev web channel and print **every render with its tap ids**. `--as <handle>` picks the test user; `--tap "<tap-id>"` presses a rendered button/list row; `--json` dumps the raw envelopes. |
70
71
  | `octwin logs` | List recent conversations (handle, status, last activity; `--as` filters), or show one conversation's full event timeline — including what each turn rendered. `--json` for raw payloads. |
71
72
  | `octwin records` | Inspect the pack's XRM data (needs a `records:read` token). No args = list entities. |
@@ -75,7 +76,8 @@ octwin status # "✓ live and current" once it's warm
75
76
  | `octwin analytics` | Stage-by-stage conversion for **any** entity declared with a `pipeline:` (`--overview` / `--milestones` / `--trends` / `--cost`; `--stage <id>` lists the records currently at a stage). Needs `records:read`. |
76
77
  | `octwin catalog` | Commerce products with price / availability / stock, plus the WhatsApp catalog binding. `--readiness` runs the Meta Graph checklist. Needs `catalog:read` + the `catalog` plan feature. |
77
78
  | `octwin scheduling` | The scheduling engine's state, or `--slots <resourceRecordId>` for the slots one bookable resource actually computes — how you verify the availability rules `deploy --seed` created. Needs `scheduling:read`. |
78
- | `octwin platform-kb pull` | Pull the platform's capability reference (built-ins, primitives, render intents, flow-DSL as markdown + JSON) into `.octwin/platform-kb/`, for the **`octwin-pack`** Claude Code authoring plugin to consult. |
79
+ | `octwin media generate "<prompt>"` | AI-generate an image, store it as a public asset, and print its `MEDIA-` handle + serve URL. `--out` downloads the bytes (WhatsApp renders only `.png`/`.jpg`); `--size`; `--json`. Pairs with `octwin chat --media` to drive media-collect flows. Needs `media:generate`. |
80
+ | `octwin platform-kb pull` | Pull the platform's capability reference into `.octwin/platform-kb/` for the **`octwin-pack`** Claude Code authoring plugin: guides as markdown, plus **one JSON file per capability** (`primitives/record_list.json`, `render-intents/carousel.json`, `declarations/xrm.json`, …) and an **`INDEX.md`** mapping every entry to its file — so a lookup is a small targeted read, not a whole catalog. |
79
81
  | `octwin test` | Alias for `octwin validate --remote` — the platform's full manifest + flow-DSL check. |
80
82
  | `octwin help` | Show usage. Every subcommand also answers `--help`. |
81
83
 
@@ -121,33 +123,37 @@ Three things worth knowing when you read the output:
121
123
 
122
124
  ## Configuration
123
125
 
124
- The deploy target has four settings. Three live in a committed **`pack.json`** at the root of your
125
- pack; the **token is a secret** and is kept out of `pack.json` (set it with `octwin login`).
126
+ **`octwin login` is the configuration.** There is no config file in your pack a pack directory
127
+ holds pack content and nothing else, so the same repo deploys from any machine:
128
+
129
+ ```bash
130
+ octwin login --url https://your-octwin.example.com --token oct_…
131
+ ```
132
+
133
+ That stores the token *and* makes the URL your default target, in `~/.octwin/credentials.json`:
126
134
 
127
135
  ```jsonc
128
- // pack.json — created by `octwin init`
129
136
  {
130
- "platform_url": "https://your-octwin.example.com", // your Octwin platform
131
- "tenant": "my-tenant-slug", // your workspace (required)
132
- "project": "main" // defaults to "main"
137
+ "default_url": "https://your-octwin.example.com", // set by the last `octwin login`
138
+ "https://your-octwin.example.com": "oct_…" // token, keyed by platform url
133
139
  }
134
140
  ```
135
141
 
136
- ```bash
137
- octwin login --url https://your-octwin.example.com --token oct_… # saves the token once
138
- ```
142
+ Tenant and project need no setting at all — the **token carries its own tenant**, plus an optional
143
+ project pin. `--tenant` / `--project` exist only as overrides (a multi-workspace human, or an
144
+ unpinned token that must name a project).
139
145
 
140
- Each setting resolves in this order — **flag → environment variable → `pack.json` → default**:
146
+ Each setting resolves **flag → environment variable → saved login**:
141
147
 
142
- | Setting | Flag | Env var | `pack.json` key |
148
+ | Setting | Flag | Env var | Saved login |
143
149
  | --- | --- | --- | --- |
144
- | Platform URL | `--url` | `PACK_PLATFORM_URL` | `platform_url` |
145
- | Tenant slug | `--tenant` | `PACK_TENANT` | `tenant` |
146
- | Project slug | `--project` | `PACK_PROJECT` | `project` (default `main`) |
147
- | Deploy token | `--token` | `PACK_TOKEN` | — *(use `octwin login`)* |
150
+ | Platform URL | `--url` | `PACK_PLATFORM_URL` | `default_url` |
151
+ | Deploy token | `--token` | `PACK_TOKEN` | token for that URL |
152
+ | Tenant slug *(override)* | `--tenant` | `PACK_TENANT` | *(from the token)* |
153
+ | Project slug *(override)* | `--project` | `PACK_PROJECT` | — *(from the token's pin)* |
148
154
 
149
- For **CI**, skip `pack.json`/`login` entirely and pass `PACK_PLATFORM_URL`, `PACK_TENANT`,
150
- `PACK_PROJECT`, and `PACK_TOKEN` as environment variables.
155
+ For **CI**, skip `login` entirely and pass `PACK_PLATFORM_URL` + `PACK_TOKEN` as environment
156
+ variables (add `PACK_PROJECT` only if the token isn't pinned).
151
157
 
152
158
  ## Authentication
153
159
 
@@ -166,8 +172,10 @@ A pack is **pure declarative data** — `.yaml` / `.yml` / `.md` / `.sql` / `.js
166
172
  code (`.ts`/`.js`), HTTP routes, DB clients, and custom primitives are **not** allowed (this is what
167
173
  makes an external pack safe to run on a shared platform; the server enforces it on deploy). For
168
174
  domain records, use Octwin's first-class storage modules — **XRM** (records with stage pipelines),
169
- **catalog** (products), or **casework** (tickets) — declared in `xrm.yaml` / `cases.yaml`, so a pack
170
- needs **no database of its own**.
175
+ **catalog** (products), or **casework** (tickets) — declared in `xrm.yaml` and `worklist.yaml`, so a
176
+ pack needs **no database of its own**. (Casework rides `worklist.yaml`'s `work.<entity>` block;
177
+ there is no ~~`cases.yaml`~~ grammar. `octwin platform-kb pull` ships the authoritative list of
178
+ declaration files — read its `INDEX.md` rather than this paragraph.)
171
179
 
172
180
  ## Links
173
181