@theokit/cli 3.0.2 → 4.0.0

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.
Files changed (38) hide show
  1. package/CHANGELOG.md +239 -0
  2. package/LICENSE +2 -2
  3. package/README.md +13 -0
  4. package/dist/bin/theokit.cjs +59 -28
  5. package/dist/bin/theokit.cjs.map +1 -1
  6. package/dist/bin/theokit.js +59 -28
  7. package/dist/bin/theokit.js.map +1 -1
  8. package/dist/index.cjs +59 -28
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.d.cts +127 -10
  11. package/dist/index.d.ts +127 -10
  12. package/dist/index.js +59 -28
  13. package/dist/index.js.map +1 -1
  14. package/package.json +19 -15
  15. package/templates/chatbot/.env.example +14 -0
  16. package/templates/chatbot/README.md +34 -0
  17. package/templates/chatbot/package.json +20 -0
  18. package/templates/chatbot/src/index.ts +88 -0
  19. package/templates/chatbot/tsconfig.json +12 -0
  20. package/templates/minimal/README.md +1 -1
  21. package/templates/multi-agent/.env.example +14 -0
  22. package/templates/multi-agent/README.md +33 -0
  23. package/templates/multi-agent/package.json +20 -0
  24. package/templates/multi-agent/src/index.ts +90 -0
  25. package/templates/multi-agent/tsconfig.json +12 -0
  26. package/templates/rag-agent/.env.example +14 -0
  27. package/templates/rag-agent/README.md +34 -0
  28. package/templates/rag-agent/package.json +21 -0
  29. package/templates/rag-agent/src/index.ts +115 -0
  30. package/templates/rag-agent/tsconfig.json +12 -0
  31. package/templates/telegram-bot/README.md +4 -4
  32. package/templates/telegram-bot/package.json +2 -2
  33. package/templates/telegram-bot/src/index.ts +2 -2
  34. package/templates/workflow-automation/.env.example +14 -0
  35. package/templates/workflow-automation/README.md +33 -0
  36. package/templates/workflow-automation/package.json +20 -0
  37. package/templates/workflow-automation/src/index.ts +86 -0
  38. package/templates/workflow-automation/tsconfig.json +12 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,244 @@
1
1
  # Changelog
2
2
 
3
+ ## 4.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - 0258f3c: Two `theokit` flags that were advertised in `--help` and read by nothing now behave.
8
+
9
+ `tasks cancel --reason <r>` records the reason: `TaskHandle` gains a `cancelReason` field, written
10
+ alongside `cancelledAt` for a queued task and alongside `cancelRequested` for a running one. A task
11
+ that is already terminal is left untouched, reason or not.
12
+
13
+ **Breaking:** `theokit init --here` is removed. It never scaffolded into the current directory, and
14
+ the writer cannot honour it — the tree is built in a temp directory and moved into place with `rm` +
15
+ `rename`, so a destination equal to `cwd` would mean deleting the directory the process is running
16
+ in. An unknown-option error is immediate and clear where silence was not.
17
+
18
+ - 89b25f1: **Breaking:** `theokit setup gworkspace --writable <products>` is removed.
19
+
20
+ It granted nothing. The value was never parsed, never validated and never reached upstream; its
21
+ entire effect was a note printed after the OAuth flow had already completed, and only on one of the
22
+ three code paths. A permissions flag that does not affect permissions misleads in the dangerous
23
+ direction — a user reading `--help` concludes they chose a narrow grant while the consent screen
24
+ grants every scope upstream asks for.
25
+
26
+ Scope narrowing is not something this command can do: OAuth is delegated upstream (ADR D345) and
27
+ the upstream server offers no per-product grant. That fact now lives in the command's own
28
+ documentation, where it applies to every path rather than to one printed note.
29
+
30
+ ### Minor Changes
31
+
32
+ - 7c7b21a: `theokit init` gains four templates — `chatbot`, `multi-agent`, `rag-agent` and
33
+ `workflow-automation` — and its `telegram-bot` template now installs and
34
+ compiles. It imported `createAgentFactory`, which the SE36 rename replaced with
35
+ `AgentFactory.create`, and pinned `@theokit/gateway` to the SDK's own version, so
36
+ a scaffolded project failed at `pnpm install` before any code ran.
37
+
38
+ `@theokit/cli` exports the `eval.config.ts` contract its README tells you to use:
39
+ `EvalConfig`, `DatasetEntry`, `Scorer` and `Score`.
40
+
41
+ `@theokit/sdk` exports `Workflow`, `fn` and `agentStep` from the package root.
42
+ `CronCreateOptions.workflow` types against the copy in the cron chunk, while the
43
+ `./workflow` subpath emits its own declaration of the same class — so a workflow
44
+ built the documented way was rejected by `Cron.create` on a private-field
45
+ mismatch. Importing both from the root now gives one identity.
46
+
47
+ ### Patch Changes
48
+
49
+ - cdb517f: `theokit init` now exits 2 for a symlinked destination, not 1.
50
+
51
+ `theokit --help` publishes `0=success · 1=unknown error · 2=user error`, and a CI job branching on
52
+ that pair routed a plain user mistake to the branch that pages someone. Four of the scaffolder's
53
+ five coded refusals mapped to 2; `dest_is_symlink` was missing from the hand-written copy of that
54
+ list and fell through.
55
+
56
+ The list now lives with the scaffolder as a typed union, so adding a refusal without deciding its
57
+ exit code does not compile.
58
+
59
+ - e3f2a82: Public-API documentation reviewed file by file, and corrected wherever it disagreed
60
+ with the code. The docblocks ship in the `.d.ts`, so these read as behaviour changes
61
+ in an editor even though no behaviour changed.
62
+
63
+ The corrections that change what a caller would do:
64
+
65
+ - **`sdk-cache` documented its own premise backwards.** The header example labelled a
66
+ semantic hit as if it avoided the provider call. `asPlugin()` returns the cached
67
+ answer as `recalledContext`, which the agent loop injects as a `<memory-context>`
68
+ block _before_ the prompt — the request still goes to the provider. The two modes
69
+ are now labelled separately, with a table saying which one short-circuits and which
70
+ one seeds.
71
+ - **`sdk-handoff`'s five error classes said "throw".** Under the plugin wiring the
72
+ handler never throws; every failure becomes a tool result `{"ok":false,…}` handed
73
+ back to the model. Each class now says where it is actually observable. The header
74
+ also told readers to `import { Handoff } from "@theokit/sdk"`, from which it was
75
+ extracted.
76
+ - **`sdk-budget`'s `charge()` claimed idempotency across concurrent calls.** The mutex
77
+ serialises, it does not deduplicate: two identical calls record twice. Related, and
78
+ newly documented: with `maxUsd` set, a model missing from the pricing table denies
79
+ every request rather than passing it — and the table matches by exact string, so
80
+ `"openai/gpt-4o"` does not match `"gpt-4o"`.
81
+ - **The three `memory-*` adapters advertised an env-var fallback they do not read**,
82
+ and their peer dependencies are required rather than optional. Their behavioural
83
+ differences are now stated where they break the "interchangeable adapter"
84
+ assumption — honcho ignores `k` and always throws on `delete`; mem0 recalls across
85
+ sessions by design; supermemory ignores `sessionId` entirely.
86
+ - **`sdk-memory`'s `truncated` flag was documented as its own inverse**, and its
87
+ dreaming sweep claimed a mutex it never takes against the writer it names.
88
+ - **`sdk-tools`** corrected `run_vitest`'s unreachable `no_vitest` code, `truncation`'s
89
+ replacement-character claim, and two return shapes missing a live error code.
90
+ - **`acp`/`cli`** corrected sixteen statements including a named error class that is
91
+ not the one raised, a handler documented as calling `fork()` that refuses
92
+ unconditionally, handlers described as pure that mint ids and mutate a store, a
93
+ config loader credited to Zod in a package that does not import it, and a `--force`
94
+ scaffold described as atomic that deletes the destination before the rename.
95
+
96
+ Undocumented public symbols were documented across every package, with each claim
97
+ checked against the implementation rather than inferred from the name.
98
+
99
+ - e368fc1: Every published declaration file now compiles without `skipLibCheck` (#345). The
100
+ DTS rollup emitted symbols as a re-export from a chunk while omitting them from
101
+ that chunk's `import`, and dropped type-only imports from external packages —
102
+ leaving 51 unresolved references across ten of the twelve packages. Nothing broke
103
+ at runtime, and `tsc` stayed green for anyone with `skipLibCheck` on, but a
104
+ consumer running type-aware lint saw every type reached through one degrade to
105
+ `error`.
106
+
107
+ The declarations are repaired at build time from the compiler's own diagnostics.
108
+ No source or API change.
109
+
110
+ - 63a77c6: `theokit eval --output report.md` no longer emits a lone UTF-16 surrogate when a
111
+ dataset input or model output is truncated (#342). The cut counted code units, so
112
+ a boundary landing between the halves of an emoji kept one half — a lone
113
+ surrogate has no UTF-8 encoding, so writers and markdown renderers downstream
114
+ either substitute U+FFFD or reject the file.
115
+
116
+ Truncation now cuts only on a character boundary. The width budget stays in code
117
+ units, since it exists to keep the table narrow; what changed is where the cut may
118
+ fall.
119
+
120
+ - 1ac974f: **`@theokit/sdk-pty` declares its licence.** Every published version up to now shipped with no `license` field in the manifest. npm reads the field, not the directory, so the tarball was all-rights-reserved to whoever installed it — the terms were sitting in the `LICENSE` file it already shipped, saying nothing. The field now says `Apache-2.0`, which is what that file has always been and what all eleven sibling packages declare.
121
+
122
+ **Four packages now ship the licence they declare.** `@theokit/cli`, `@theokit/memory-honcho`, `@theokit/memory-mem0` and `@theokit/memory-supermemory` declared `Apache-2.0` and listed `LICENSE` in `files`, and no such file existed. npm omits a declared-but-absent path in silence, so every published tarball asserted the licence while carrying none of its terms — and §4(a) requires a copy to travel with the distribution. The file is there now, byte-identical to the one the other packages ship.
123
+
124
+ **Six packages complete the rest of their published metadata.** Each field is here for what its absence costs a consumer:
125
+
126
+ - `homepage` and `bugs` — the npm page renders both; without them someone who hits a defect has no route back to the project.
127
+ - `engines.node` — npm warns on an unsupported runtime only when the range is declared. `@theokit/sdk-pty` declared none, so a Node 18 install failed later and somewhere unrelated.
128
+ - `sideEffects` — a bundler keeps every module of a package that stays silent. Declared only after checking: a clean scan of each built ESM entry found zero top-level statements, the residual hits being closing tokens of declarations. `@theokit/sdk` keeps its path-array form, which is the honest shape for a package whose agent entry registers on import.
129
+ - `publishConfig.access` — a scoped package defaults to `restricted`. Three declared none and reached npm public only because the release flow supplied the flag; the manifest states it now instead of depending on how it is invoked.
130
+ - `@theokit/sdk-pty` also ships its `CHANGELOG.md`, which existed on disk and was absent from `files`.
131
+
132
+ The gate that should have caught any of this covered three packages out of twelve, by way of a hand-written list. It now derives the list from `packages/`, asserts the whole contract, and fails when the sweep discovers nothing rather than passing by having nothing to check.
133
+
134
+ - e699569: **The repository moved to the official `usetheokit` organization.** Every `repository`, `bugs` and `homepage` field now points there, along with the README, `CONTRIBUTING.md`, `SECURITY.md` and the issue templates. Existing clones and any URL already published keep working — GitHub redirects a transferred repository permanently — so this is a correctness fix for the metadata npm renders, not a break.
135
+
136
+ **The Apache-2.0 text every package ships was replaced with the official one.** The copy distributed until now had paragraph 4(d) truncated: it read "except as required for describing the origin of the Work and reproducing the content of the NOTICE file", dropping "reasonable and customary use" from the licensed clause. §4(d) governs what a redistributor must do with attribution notices, and the omission narrowed it.
137
+
138
+ That matters more than a typo would. The manifests declare the SPDX identifier `Apache-2.0`, which is an assertion that the terms are _the_ Apache-2.0 terms — a licence scanner resolves the identifier and never reads the file. A consumer's compliance review, which does read the file, would find a body that no longer matches the identifier and has no name of its own. Every `LICENSE` in this repository is now byte-identical to the canonical text, with the appendix filled in.
139
+
140
+ Nothing else about the terms changed: the licence is the same licence it has always been meant to be, and no package changes what it grants.
141
+
142
+ - f692988: The reference docs no longer ship inside the package. `node_modules/@theokit/sdk/docs/` is gone, along with the `harness-capability-map.md` and `error-codes.md` files it carried — the `docs` entry was removed from the published `files` list and the build step that generated it was removed with it.
143
+
144
+ The exported TypeScript types are now the only reference surface, and they remain the canonical contract: every public primitive carries its import path, signature and JSDoc example, surfaced by your editor. Nothing about the runtime API changed.
145
+
146
+ The scaffolded agent context still ships, unchanged, under `claude-template/`.
147
+
148
+ - c7385d2: Test runs no longer claim every core on the host.
149
+
150
+ None of the package configs capped `maxWorkers`, so vitest's default applied: `os.availableParallelism()`,
151
+ one fork per core, each booting a full test environment. The repo's `test` script is
152
+ `turbo run test --filter='./packages/*'`, so that default is paid once per package _concurrently_ —
153
+ nproc forks times turbo's concurrency, on nproc cores. Measured on a 12-thread machine during an
154
+ unrelated investigation, two vitest pools alone were enough to reach load average 33.89 with the
155
+ desktop unusable; a full fan-out is several times that.
156
+
157
+ `@theokit/sdk` is the interesting case. B-104 recorded on 2026-08-19 that the `poolOptions.forks.*`
158
+ block was 100% dead in Vitest 4, deleted it, and noted that `fileParallelism: false` was forcing
159
+ `maxWorkers` to 1 unconditionally, so a fork-count knob could not act. B-059 then flipped
160
+ `fileParallelism` to `true` on 2026-08-20, which made the knob able to act again — and nothing
161
+ reintroduced one, so the package silently went back to the uncapped default. That comment has been
162
+ corrected along with the config; it claimed no knob existed, which is no longer true.
163
+
164
+ The cap leaves 4 cores free (`Math.max(2, cpus().length - 4)`), scaling with the runner rather than
165
+ hard-coding one machine's core count. It costs no wall-clock: measured in `theokit-ui`, the full
166
+ suite ran 73.96s at 4 workers against 74.36s at 12, so the parallelism above the cap was already
167
+ noise. Verified as resolved config rather than as file contents — `createVitest` reports
168
+ `maxWorkers: 8` on a 12-thread host, which is the formula, not the default.
169
+
170
+ This changes no published behaviour; it is test tooling only. Refs usetheokit/theokit-ui#51.
171
+
172
+ - Updated dependencies [1cb6607]
173
+ - Updated dependencies [034da4d]
174
+ - Updated dependencies [803e3ef]
175
+ - Updated dependencies [2ba468b]
176
+ - Updated dependencies [92a9d6a]
177
+ - Updated dependencies [2c33d98]
178
+ - Updated dependencies [ce6a591]
179
+ - Updated dependencies [aea04f4]
180
+ - Updated dependencies [1471fd7]
181
+ - Updated dependencies [0258f3c]
182
+ - Updated dependencies [521f8c7]
183
+ - Updated dependencies [d0c800c]
184
+ - Updated dependencies [969b36e]
185
+ - Updated dependencies [ba8ebeb]
186
+ - Updated dependencies [d610c2a]
187
+ - Updated dependencies [e3f2a82]
188
+ - Updated dependencies [e368fc1]
189
+ - Updated dependencies [3ac2b08]
190
+ - Updated dependencies [d485b4e]
191
+ - Updated dependencies [29ebaa1]
192
+ - Updated dependencies [0bc18f6]
193
+ - Updated dependencies [b5b5e77]
194
+ - Updated dependencies [14ccb69]
195
+ - Updated dependencies [fbf6721]
196
+ - Updated dependencies [1ac974f]
197
+ - Updated dependencies [240ae12]
198
+ - Updated dependencies [da98560]
199
+ - Updated dependencies [181967f]
200
+ - Updated dependencies [510ee70]
201
+ - Updated dependencies [1362583]
202
+ - Updated dependencies [f33b52b]
203
+ - Updated dependencies [2cdadcc]
204
+ - Updated dependencies [1c94ad3]
205
+ - Updated dependencies [398e7a0]
206
+ - Updated dependencies [3ad398d]
207
+ - Updated dependencies [a8cf443]
208
+ - Updated dependencies [aadc9dd]
209
+ - Updated dependencies [a1cae95]
210
+ - Updated dependencies [8226bc6]
211
+ - Updated dependencies [e699569]
212
+ - Updated dependencies [8d1feaa]
213
+ - Updated dependencies [6950332]
214
+ - Updated dependencies [9e6828e]
215
+ - Updated dependencies [9a27a72]
216
+ - Updated dependencies [e3f2a82]
217
+ - Updated dependencies [f692988]
218
+ - Updated dependencies [ac08996]
219
+ - Updated dependencies [4556488]
220
+ - Updated dependencies [566615c]
221
+ - Updated dependencies [96b28ba]
222
+ - Updated dependencies [f53ee6a]
223
+ - Updated dependencies [1af99fa]
224
+ - Updated dependencies [8f8d3eb]
225
+ - Updated dependencies [4397a90]
226
+ - Updated dependencies [883f473]
227
+ - Updated dependencies [36e5879]
228
+ - Updated dependencies [b68704b]
229
+ - Updated dependencies [7c7b21a]
230
+ - Updated dependencies [9ab1f0d]
231
+ - Updated dependencies [464c390]
232
+ - Updated dependencies [c7385d2]
233
+ - Updated dependencies [9f5cc20]
234
+ - Updated dependencies [5fac0f6]
235
+ - Updated dependencies [e685ccb]
236
+ - Updated dependencies [7fd8c7e]
237
+ - Updated dependencies [60010b4]
238
+ - Updated dependencies [25b7eee]
239
+ - @theokit/sdk@4.54.0
240
+ - @theokit/acp@4.0.0
241
+
3
242
  ## 3.0.2
4
243
 
5
244
  ### Patch Changes
package/LICENSE CHANGED
@@ -137,8 +137,8 @@
137
137
 
138
138
  6. Trademarks. This License does not grant permission to use the trade
139
139
  names, trademarks, service marks, or product names of the Licensor,
140
- except as required for describing the origin of the Work and
141
- reproducing the content of the NOTICE file.
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
142
 
143
143
  7. Disclaimer of Warranty. Unless required by applicable law or
144
144
  agreed to in writing, Licensor provides the Work (and each
package/README.md CHANGED
@@ -124,3 +124,16 @@ See ADRs D193-D201 in `.claude/knowledge-base/adrs/`:
124
124
  - Node 22.12+.
125
125
  - pnpm (recommended) or npm. Templates use pnpm scripts; npm/yarn
126
126
  users can manually translate.
127
+
128
+ ## API reference
129
+
130
+ Every symbol this package exports, with the exact specifier to import it from, is in the generated
131
+ capability map that ships inside `@theokit/sdk`:
132
+
133
+ ```
134
+ node_modules/@theokit/sdk/docs/harness-capability-map.md # symbol -> import specifier
135
+ node_modules/@theokit/sdk/docs/error-codes.md # every `code` an error can carry
136
+ ```
137
+
138
+ Both are generated from the built type declarations, so they describe the version you installed
139
+ rather than the version someone wrote a page about.
@@ -384,7 +384,7 @@ function startRunner(opts) {
384
384
  args.push(opts.entry);
385
385
  const child = child_process.spawn(process.execPath, [tsxBin, ...args], {
386
386
  cwd: opts.cwd,
387
- stdio: "inherit",
387
+ stdio: opts.stdio ?? "inherit",
388
388
  env: process.env
389
389
  });
390
390
  const exited = new Promise((resolve6) => {
@@ -515,7 +515,13 @@ function formatReport(result) {
515
515
  }
516
516
  function truncate(s, max) {
517
517
  if (s.length <= max) return s;
518
- return `${s.slice(0, max - 1)}\u2026`;
518
+ const budget = max - 1;
519
+ let out = "";
520
+ for (const ch of s) {
521
+ if (out.length + ch.length > budget) break;
522
+ out += ch;
523
+ }
524
+ return `${out}\u2026`;
519
525
  }
520
526
  function escapeMd(s) {
521
527
  return s.replaceAll("|", "\\|").replaceAll("\n", " ");
@@ -645,8 +651,8 @@ ${pc5__default.default.green("\u2713")} ${result.aggregate.totalRows} rows \xB7
645
651
  }
646
652
 
647
653
  // src/version.ts
648
- var SDK_VERSION = "4.43.0";
649
- var CLI_VERSION = "3.0.2";
654
+ var SDK_VERSION = "4.54.0";
655
+ var CLI_VERSION = "4.0.0";
650
656
 
651
657
  // src/init/templates.ts
652
658
  var TEMPLATES = [
@@ -660,6 +666,26 @@ var TEMPLATES = [
660
666
  description: "100% local agent via Ollama (no remote API key required).",
661
667
  hint: "Requires `ollama serve` + `ollama pull llama3.2:3b`."
662
668
  },
669
+ {
670
+ name: "chatbot",
671
+ description: "Conversational agent that resumes its own thread across runs.",
672
+ hint: "SESSION_DIR=~/.claude writes sessions the Claude Code CLI can --continue."
673
+ },
674
+ {
675
+ name: "multi-agent",
676
+ description: "A classifier routes to specialists, all from one AgentFactory prefix.",
677
+ hint: 'Pass the input as an argument: `pnpm dev "Translate to French: hello"`.'
678
+ },
679
+ {
680
+ name: "rag-agent",
681
+ description: "Retrieval over your own files \u2014 Memory.openIndex behind a Tool.",
682
+ hint: "Put markdown under .theokit/memory/ first, or there is nothing to cite."
683
+ },
684
+ {
685
+ name: "workflow-automation",
686
+ description: "A committed Workflow (fn -> agentStep -> fn) handed to Cron.",
687
+ hint: "WORKFLOW_CRON overrides the schedule; default is every 5 minutes."
688
+ },
663
689
  {
664
690
  name: "telegram-bot",
665
691
  description: "Telegram bot via @theokit/gateway + grammy.",
@@ -721,6 +747,13 @@ function resolveTemplatesRoot() {
721
747
  `Could not locate bundled templates/ directory (searched up from ${here}). This usually means the published tarball was built without "files": ["templates"] (EC-C regression).`
722
748
  );
723
749
  }
750
+ var SCAFFOLD_USER_ERROR_CODES = [
751
+ "invalid_project_name",
752
+ "unknown_template",
753
+ "invalid_dest",
754
+ "dest_is_symlink",
755
+ "dest_not_empty"
756
+ ];
724
757
  function scaffoldError(code, message) {
725
758
  const err = new Error(message);
726
759
  err.code = code;
@@ -856,12 +889,7 @@ async function resolveTemplate(optsTemplate, skipPrompts) {
856
889
  }
857
890
  return template;
858
891
  }
859
- var USER_ERROR_CODES = /* @__PURE__ */ new Set([
860
- "invalid_project_name",
861
- "dest_not_empty",
862
- "invalid_dest",
863
- "unknown_template"
864
- ]);
892
+ var USER_ERROR_CODES = new Set(SCAFFOLD_USER_ERROR_CODES);
865
893
  async function runScaffold(name, template, force) {
866
894
  try {
867
895
  const result = await scaffold({
@@ -1215,14 +1243,6 @@ ${pc5__default.default.dim(" shape: Desktop OAuth client (installed block prese
1215
1243
  }
1216
1244
  const interactiveCode = await runInteractiveSetup();
1217
1245
  if (interactiveCode !== 0) return interactiveCode;
1218
- if (typeof opts.writable === "string" && opts.writable.length > 0) {
1219
- process.stdout.write(
1220
- `
1221
- ${pc5__default.default.yellow("note:")} you passed --writable=${opts.writable}. The upstream MCP server does not narrow scopes \u2014 all scopes are granted at consent.
1222
- Write tools are gated at runtime by ${pc5__default.default.bold("googleWorkspace({ writable: true })")} in your code.
1223
- `
1224
- );
1225
- }
1226
1246
  process.stdout.write(
1227
1247
  `
1228
1248
  ${pc5__default.default.green("\u2713")} gworkspace setup complete.
@@ -1269,7 +1289,6 @@ function spawnUpstream(args, timeoutMs) {
1269
1289
  async function runSetup(domain, opts) {
1270
1290
  if (domain === "gworkspace") {
1271
1291
  const gworkspaceOpts = {
1272
- writable: opts.writable,
1273
1292
  probe: opts.probe === true,
1274
1293
  nonInteractive: opts.nonInteractive === true,
1275
1294
  ...opts.credentialsPath !== void 0 ? { credentialsPath: opts.credentialsPath } : {}
@@ -1400,7 +1419,7 @@ async function runTasksInspect(id, opts) {
1400
1419
  }
1401
1420
  return 0;
1402
1421
  }
1403
- async function runTasksCancel(id, _opts) {
1422
+ async function runTasksCancel(id, opts) {
1404
1423
  if (!isValidTaskId(id)) {
1405
1424
  process.stderr.write(`tasks: invalid id grammar: ${id}
1406
1425
  `);
@@ -1425,12 +1444,21 @@ async function runTasksCancel(id, _opts) {
1425
1444
  }
1426
1445
  if (handle.state === "queued") {
1427
1446
  const cancelledAt = Date.now();
1428
- await store.update(id, (h) => ({ ...h, state: "cancelled", cancelledAt }));
1447
+ await store.update(id, (h) => ({
1448
+ ...h,
1449
+ state: "cancelled",
1450
+ cancelledAt,
1451
+ ...opts.reason !== void 0 ? { cancelReason: opts.reason } : {}
1452
+ }));
1429
1453
  process.stdout.write(`task ${id} cancelled (was queued)
1430
1454
  `);
1431
1455
  return 0;
1432
1456
  }
1433
- await store.update(id, (h) => ({ ...h, cancelRequested: true }));
1457
+ await store.update(id, (h) => ({
1458
+ ...h,
1459
+ cancelRequested: true,
1460
+ ...opts.reason !== void 0 ? { cancelReason: opts.reason } : {}
1461
+ }));
1434
1462
  process.stdout.write(
1435
1463
  `cancel requested for task ${id}; the owning process will honor it at the next checkpoint
1436
1464
  `
@@ -1440,7 +1468,13 @@ async function runTasksCancel(id, _opts) {
1440
1468
 
1441
1469
  // src/main.ts
1442
1470
  function registerSubcommands(program, setExit) {
1443
- program.command("init [project-name]").description("Scaffold a new agent project from a bundled template.").option("-t, --template <name>", "Template name: minimal | ollama-local | telegram-bot").option("-f, --force", "Overwrite a non-empty destination directory").option("--here", "Scaffold into the current directory").option("-y, --yes", "Skip interactive prompts (CI mode)").action(async (projectName, opts) => {
1471
+ program.command("init [project-name]").description("Scaffold a new agent project from a bundled template.").option(
1472
+ "-t, --template <name>",
1473
+ // Derived from the registry, not restated. This line named three templates while the
1474
+ // registry held seven — a help text that lists options is a second copy of the list, and
1475
+ // the copy is the one that goes stale.
1476
+ `Template name: ${TEMPLATES.map((t) => t.name).join(" | ")}`
1477
+ ).option("-f, --force", "Overwrite a non-empty destination directory").option("-y, --yes", "Skip interactive prompts (CI mode)").action(async (projectName, opts) => {
1444
1478
  setExit(await runInit(projectName, opts));
1445
1479
  });
1446
1480
  program.command("dev").description("Run the agent entry point under tsx --watch (hot-reload).").option("--entry <path>", "Entry file (default: src/index.ts or package.main)").option("--env <path>", "Env file to load (default: .env)").action(async (opts) => {
@@ -1456,15 +1490,12 @@ function registerSubcommands(program, setExit) {
1456
1490
  setExit(await runEval(opts));
1457
1491
  });
1458
1492
  program.command("acp").description(
1459
- "Launch a stdio Agent Client Protocol (ACP) server pointing at the entry file's default-exported agent. Used by Zed/Cursor/Claude Desktop. ADRs D349-D360."
1493
+ "Launch a stdio Agent Client Protocol (ACP) server pointing at the entry file's default-exported agent. Used by ACP-compatible hosts. ADRs D349-D360."
1460
1494
  ).option("--entry <path>", "Entry file (default: src/index.ts or package.main)").option("--permission <mode>", "Tool permission mode: ask | auto | deny (default: ask)").option("--trusted-tools <list>", "Comma-separated tool names that bypass ask").option("--permission-timeout-ms <ms>", "Permission request timeout in ms (default: 60000)").action(async (opts) => {
1461
1495
  setExit(await runAcp(opts));
1462
1496
  });
1463
1497
  program.command("setup <domain>").description(
1464
1498
  "Stage credentials + connectivity probe for a third-party integration. Domains: gworkspace (Google Workspace)."
1465
- ).option(
1466
- "--writable <products>",
1467
- "Comma-separated products to grant write access (e.g., 'drive,calendar')"
1468
1499
  ).option("--probe", "Run upstream connectivity check after staging credentials").option(
1469
1500
  "--credentials-path <path>",
1470
1501
  "Override path to credentials.json (default: ~/.google-mcp/credentials.json)"
@@ -1502,7 +1533,7 @@ function registerSubcommands(program, setExit) {
1502
1533
  setExit(await runTasksInspect(id, opts));
1503
1534
  });
1504
1535
  tasks.command("cancel <id>").description("Cancel a task (best-effort cross-process via cancelRequested flag)").option("--reason <reason>", "Cancellation reason recorded in the registry").action(async (id, opts) => {
1505
- setExit(await runTasksCancel(id));
1536
+ setExit(await runTasksCancel(id, opts));
1506
1537
  });
1507
1538
  }
1508
1539
  function mapCommanderExitCode(code, fallback) {