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 +132 -0
- package/README.md +26 -22
- package/dist/index.js +704 -260
- package/dist/lib/args-check.js +110 -0
- package/dist/lib/pack-source.js +68 -0
- package/dist/lib/render-check.js +85 -0
- package/dist/lib/validate.js +50 -4
- package/package.json +1 -1
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
|
|
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 `
|
|
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.
|
|
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
|
|
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
|
-
|
|
125
|
-
pack
|
|
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
|
-
"
|
|
131
|
-
"
|
|
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
|
-
|
|
137
|
-
|
|
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
|
|
144
|
+
Each setting resolves **flag → environment variable → saved login**:
|
|
141
145
|
|
|
142
|
-
| Setting | Flag | Env var |
|
|
146
|
+
| Setting | Flag | Env var | Saved login |
|
|
143
147
|
| --- | --- | --- | --- |
|
|
144
|
-
| Platform URL | `--url` | `PACK_PLATFORM_URL` | `
|
|
145
|
-
|
|
|
146
|
-
|
|
|
147
|
-
|
|
|
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 `
|
|
150
|
-
|
|
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
|
|