octwin-cli 0.1.15 → 0.1.20

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,138 @@ 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.20] - 2026-07-29
9
+
10
+ ### Added
11
+ - **`octwin validate` catches primitive arguments the platform would drop — offline, no token.** A
12
+ primitive takes the arguments it declares and silently ignored the rest, so an invented or
13
+ misspelled `args:` key deployed clean, ran clean, and simply did nothing: `record_list args: {
14
+ order: … }` (the argument is `sort`) never ordered, and `booking_cancel args: { booking_record_id:
15
+ … }` meant the REQUIRED `record_id` never arrived, so cancelling just failed. Validate now replays
16
+ the platform's contract from the pulled KB (`primitives/*.json` → `inputSchema`) and names the bad
17
+ argument, what the primitive takes, and any required argument that is missing. Scanning the 21
18
+ shipped marketplace packs found **ten** such errors across five packs. Keys are checked, values are
19
+ not — an `args:` value is normally an expression string resolved at runtime.
20
+ [`args-check.ts`](src/lib/args-check.ts).
21
+ - Silently skipped when the KB has not been pulled yet, like the render-intent check beside it.
22
+ - It cannot see inside a `use:` template body (expanding one is the platform's job) — `octwin
23
+ validate --remote` covers that case, and now also reports unreachable `$bind.<path>` reads and
24
+ `outputs:` port typos, which have no offline equivalent.
25
+
26
+ ## [0.1.19] - 2026-07-29
27
+
28
+ ### Added
29
+ - **`octwin validate` catches render-intent fields the platform would drop — offline, no token.** Each
30
+ render intent takes a fixed field set; a key outside it used to be swallowed at load and dropped at
31
+ render, with no error anywhere — just a card missing what the author wrote. Validate now replays the
32
+ platform's own contract from the pulled KB (`render-intents/*.json` → `allowed_keys`) and names the
33
+ bad field, the intent, and what is allowed. Scanning the 21 shipped marketplace packs found two real
34
+ instances in 223 intents: a `text_card` carrying `buttons` (the fallback's only escape button never
35
+ rendered) and a `list_picker` carrying a non-existent `group_by` (a whole mapper step feeding a
36
+ fabricated parameter). Silently skipped when the KB has not been pulled yet.
37
+
38
+ ### Changed
39
+ - **`octwin platform-kb pull` now explodes the reference and writes an `INDEX.md`.** A pull used to
40
+ write ~787 KB across 34 flat files — about 225k tokens, more than the pack being authored — so
41
+ finding one primitive meant reading a 122 KB catalog. Catalogs the platform describes as
42
+ enumerable are now written **one file per entry** (`primitives/record_list.json`,
43
+ `render-intents/carousel.json`, `declarations/xrm.json`, …), with `INDEX.md` mapping every doc and
44
+ all 171 entries to its file with a one-line summary. Reading one primitive went from ~38k tokens to
45
+ ~700. The layout comes from the platform (an `entries` descriptor on the bundle index) rather than
46
+ being hardcoded here, so this CLI keeps working against any platform version and a platform that
47
+ adds a catalog needs no CLI release. The pulled directory is cleared each pull, so a withdrawn
48
+ capability cannot linger as a file the authoring agent reads as current — its *contents* are
49
+ cleared rather than the directory itself, since on Windows a directory that is any shell's working
50
+ directory cannot be removed.
51
+
52
+ ## [0.1.18] - 2026-07-29
53
+
54
+ ### Fixed
55
+ - **The bundle collector and the platform's repo import disagreed about what a pack directory
56
+ contains.** `collectBundleFiles` had its own rule and kept three things the operator's GitHub
57
+ import drops: `*.ts`/`*.tsx`, `__snapshots__/` and `*.example`. Because the server rejects a
58
+ `.ts` outright, the same directory imported cleanly from GitHub and failed to deploy from
59
+ disk with `'…': executable code is not allowed` — an error blaming a file that was never
60
+ meant to ship (a snapshot test beside a flow, or the documented `xrm.yaml.example` template).
61
+ The rule now lives in a vendored `lib/pack-source.ts` beside the vendored validator, and a
62
+ parity test in the platform drives both copies over one table.
63
+
64
+ ### Removed
65
+ - **`pack.json` is gone — the saved login IS the deploy target.** The file had eroded to a single
66
+ field, `platform_url`, which `octwin login --url … --token …` already states; `tenant`/`project`
67
+ became optional overrides once deploy tokens started carrying their own tenant and project pin.
68
+ So it was a second home for a fact `login` knew, and it cost real things: a machine-specific file
69
+ committed into every pack repo, a four-link config-precedence chain to document, and an
70
+ exclusion rule duplicated in the bundler and the server (which had already drifted apart).
71
+ `octwin init` and `octwin pull` no longer write one, and nothing reads one. **A pack directory is
72
+ now pack content and nothing else** — the same repo deploys from any machine, and a pulled pack
73
+ redeploys with no flags.
74
+
75
+ ### Changed
76
+ - **`octwin login` now sets the default deploy target**, not just the token: it writes a
77
+ `default_url` key alongside the token in `~/.octwin/credentials.json`. Every command resolves
78
+ **flags → env (`PACK_PLATFORM_URL`/`PACK_TENANT`/`PACK_PROJECT`/`PACK_TOKEN`) → saved login**.
79
+ An existing credentials file simply has no `default_url` until the next `octwin login` — which is
80
+ exactly what the "no platform url" error now tells you to run. CI is unaffected (it passes
81
+ `PACK_PLATFORM_URL` + `PACK_TOKEN` as env and never had a `pack.json`).
82
+
83
+ ## [0.1.17] - 2026-07-27
84
+
85
+ ### Added
86
+ - **`octwin pull <packId>` — write a DEPLOYED pack's source back to disk.** The inverse of
87
+ `deploy`. A pack pushed with the CLI lived on the platform as an artifact the runtime served
88
+ but nothing could hand back, so its only source copy was the machine that pushed it. Pull it,
89
+ fix it, redeploy it. Writes a `pack.json` (retired in 0.1.18 — the saved login is now the
90
+ target) so the pulled directory redeploys where it came from; `--version` picks a version,
91
+ `--force` overwrites a non-empty dir. You may pull a pack
92
+ your tenant OWNS (an operator token pulls any) — a pack you merely installed is not yours to
93
+ read.
94
+ - **`octwin chat --script <file>` — drive a whole conversation from one invocation.** One turn per
95
+ line, in order, in a single process over a single SSE connection, waiting for each turn to settle
96
+ before sending the next. Blank lines and `#` comments are skipped; `tap:<id>` presses a rendered
97
+ row/button (the rest of the line is kept verbatim, since a tap id is itself colon-delimited),
98
+ `media:<path>` uploads a file, and `media:<path> | caption` attaches one.
99
+
100
+ This exists because **chaining invocations races the agent loop.** A turn ends on a quiet gap
101
+ (`TURN_SETTLE_MS`), which can arrive while the server-side loop is still running — so
102
+ `chat A && chat B` lets B's inbound land mid-turn, and the agent fills required fields with
103
+ placeholder text (`service_id: "service-id"`) or starts a second workflow run. Those look exactly
104
+ like flow bugs and cost a field author three separate investigations. The one-turn-per-invocation
105
+ rule is now stated in `chat --help` and the header usage as well.
106
+
107
+ ### Changed
108
+ - **`octwin deploy` reports the suspended runs it invalidated.** A redeploy rebuilds the pack's
109
+ tools, and in-flight flow runs live in those tools — so every suspended conversation is dropped.
110
+ The deploy prints `ⓘ N suspended run(s) invalidated` when N > 0, instead of leaving the author to
111
+ discover it as a `workflow_resume_stale` on the next tap.
112
+
113
+ ## [0.1.16] - 2026-07-26
114
+
115
+ ### Added
116
+ - **A pack can ship committed images.** `jpg`/`jpeg`/`png`/`webp`/`gif`/`pdf` files in your pack
117
+ directory now travel as a separate `blobs` half of the bundle (base64 on the wire, `bytea` in
118
+ storage) instead of being rejected as "not an allowed pack file type". Declare each one under the
119
+ manifest's `static_assets: [{ file, key }]` and reference it from `config:` with the
120
+ `$pack_asset:<key>` sentinel — the platform uploads it to the media system at install and the
121
+ sentinel resolves to the served URL. `octwin validate` reports the image count alongside the file
122
+ count.
123
+ - **The size ceilings fail locally, before upload** — 2 MB per file, 32 MB of binary per pack,
124
+ mirroring the server. `svg` stays rejected: it is script-capable and these assets are served to
125
+ browsers.
126
+
127
+ ### Fixed
128
+ - **Committed images were silently corrupted.** `collectBundleFiles` read *every* file with
129
+ `readFileSync(full, 'utf8')`, so a JPEG went through a lossy UTF-8 decode and arrived mangled
130
+ server-side — a deploy that "succeeded" and rendered a broken image. Binary files now split off
131
+ into `blobs` and keep their bytes.
132
+ - **`octwin status` reported `loaded=(none)` for every pack, always.** It printed a `loaded_version`
133
+ field that stopped existing when reload moved to content-sha keying, which also meant the
134
+ version-drift warning underneath it could never fire. It now prints the **content sha** the
135
+ instance has loaded and the one the catalog holds (with the artifact's `origin`), and warns off the
136
+ platform's own `up_to_date` flag. The sha is the more useful fact anyway: re-publishing the *same*
137
+ version changes it, which is exactly the author's inner loop. A pack that is live and current but
138
+ **withdrawn** from the catalog now says so, rather than reporting a clean bill of health.
139
+
8
140
  ## [0.1.15] - 2026-07-25
9
141
 
10
142
  ### 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,12 @@ 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
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 vs. loaded version, and its flows. |
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. |
69
69
  | `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
70
  | `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
71
  | `octwin records` | Inspect the pack's XRM data (needs a `records:read` token). No args = list entities. |
@@ -75,7 +75,7 @@ octwin status # "✓ live and current" once it's warm
75
75
  | `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
76
  | `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
77
  | `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. |
78
+ | `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
79
  | `octwin test` | Alias for `octwin validate --remote` — the platform's full manifest + flow-DSL check. |
80
80
  | `octwin help` | Show usage. Every subcommand also answers `--help`. |
81
81
 
@@ -121,33 +121,37 @@ Three things worth knowing when you read the output:
121
121
 
122
122
  ## Configuration
123
123
 
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`).
124
+ **`octwin login` is the configuration.** There is no config file in your pack a pack directory
125
+ holds pack content and nothing else, so the same repo deploys from any machine:
126
+
127
+ ```bash
128
+ octwin login --url https://your-octwin.example.com --token oct_…
129
+ ```
130
+
131
+ That stores the token *and* makes the URL your default target, in `~/.octwin/credentials.json`:
126
132
 
127
133
  ```jsonc
128
- // pack.json — created by `octwin init`
129
134
  {
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"
135
+ "default_url": "https://your-octwin.example.com", // set by the last `octwin login`
136
+ "https://your-octwin.example.com": "oct_…" // token, keyed by platform url
133
137
  }
134
138
  ```
135
139
 
136
- ```bash
137
- octwin login --url https://your-octwin.example.com --token oct_… # saves the token once
138
- ```
140
+ Tenant and project need no setting at all — the **token carries its own tenant**, plus an optional
141
+ project pin. `--tenant` / `--project` exist only as overrides (a multi-workspace human, or an
142
+ unpinned token that must name a project).
139
143
 
140
- Each setting resolves in this order — **flag → environment variable → `pack.json` → default**:
144
+ Each setting resolves **flag → environment variable → saved login**:
141
145
 
142
- | Setting | Flag | Env var | `pack.json` key |
146
+ | Setting | Flag | Env var | Saved login |
143
147
  | --- | --- | --- | --- |
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`)* |
148
+ | Platform URL | `--url` | `PACK_PLATFORM_URL` | `default_url` |
149
+ | Deploy token | `--token` | `PACK_TOKEN` | token for that URL |
150
+ | Tenant slug *(override)* | `--tenant` | `PACK_TENANT` | *(from the token)* |
151
+ | Project slug *(override)* | `--project` | `PACK_PROJECT` | — *(from the token's pin)* |
148
152
 
149
- For **CI**, skip `pack.json`/`login` entirely and pass `PACK_PLATFORM_URL`, `PACK_TENANT`,
150
- `PACK_PROJECT`, and `PACK_TOKEN` as environment variables.
153
+ For **CI**, skip `login` entirely and pass `PACK_PLATFORM_URL` + `PACK_TOKEN` as environment
154
+ variables (add `PACK_PROJECT` only if the token isn't pinned).
151
155
 
152
156
  ## Authentication
153
157