@theokit/cli 3.0.2 → 4.0.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.
Files changed (38) hide show
  1. package/CHANGELOG.md +257 -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 -16
  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/dist/index.d.cts CHANGED
@@ -1,28 +1,145 @@
1
+ import { Agent } from '@theokit/sdk';
2
+
3
+ /**
4
+ * The shape of `eval.config.{ts,mjs}`, consumed by `theokit eval` (T5.1, ADR D199).
5
+ *
6
+ * ```ts
7
+ * import type { EvalConfig } from "@theokit/cli";
8
+ *
9
+ * export default {
10
+ * agent: { model: "gpt-4o-mini" },
11
+ * dataset: [{ input: "2+2?", expected: "4" }],
12
+ * scorers: [{ name: "exact", score: (out, exp) => ({ score: out.trim() === exp ? 1 : 0 }) }],
13
+ * } satisfies EvalConfig;
14
+ * ```
15
+ *
16
+ * The runner now delegates to the SDK's `Eval.create().run()` (D212); this shape survived that swap
17
+ * unchanged, which is what D199 was for.
18
+ *
19
+ * @public
20
+ */
21
+
22
+ /**
23
+ * Outcome of a single scoring decision.
24
+ *
25
+ * Exported because `Scorer` — which IS public — returns it: a user writing a scorer could not name
26
+ * its return type. Same shape as the `MemoryProviderFactory` defect in #335, one level down.
27
+ */
28
+ interface Score {
29
+ /** Numeric score in [0, 1]. Use 1.0 for "pass", 0.0 for "fail". */
30
+ readonly score: number;
31
+ /** Optional human-readable reason for the score (shown in the report). */
32
+ readonly reason?: string;
33
+ }
34
+ /**
35
+ * Grades one agent output. May be sync or async (EC-K); both are awaited.
36
+ *
37
+ * `expected` is whatever the dataset entry carried, `unknown` because nothing constrains it — narrow
38
+ * it yourself. It is `undefined` for entries that declared no `expected`, so a scorer that assumes a
39
+ * string has to handle that.
40
+ *
41
+ * Scoring runs inside the SDK's eval engine, which reports per-ROW failures: a failed row carries an
42
+ * `error` and is counted in `errorRows` rather than aborting the suite.
43
+ */
44
+ type Scorer = (output: string, expected?: unknown) => Score | Promise<Score>;
45
+ /**
46
+ * One evaluation case: the prompt sent to the agent, and an optional expected value handed to every
47
+ * scorer untouched (no comparison is performed for you).
48
+ */
49
+ interface DatasetEntry {
50
+ readonly input: string;
51
+ readonly expected?: unknown;
52
+ }
53
+ /**
54
+ * The `Agent.create()` options object, inferred from the installed `@theokit/sdk` rather than
55
+ * re-declared. Whatever that version accepts — model, tools, plugins — is accepted here.
56
+ */
57
+ type EvalAgentOptions = Parameters<typeof Agent.create>[0];
58
+ /**
59
+ * The DEFAULT export of `eval.config.{ts,mjs}`. A named export is not read.
60
+ *
61
+ * `theokit eval` checks only that `dataset` and `scorers` are arrays and `agent` is an object; every
62
+ * deeper mistake surfaces at run time, from the SDK, per row. An empty `dataset` is accepted and
63
+ * short-circuits to a zero-row report — the run costs nothing and proves nothing.
64
+ *
65
+ * Running it spends real money: each entry is one live agent turn against the configured provider.
66
+ */
67
+ interface EvalConfig {
68
+ /** Cases to run, in order. Empty is legal and produces an empty report. */
69
+ readonly dataset: ReadonlyArray<DatasetEntry>;
70
+ /** Scorers applied to EVERY row. `name` is the column label in the markdown report. */
71
+ readonly scorers: ReadonlyArray<{
72
+ readonly name: string;
73
+ readonly score: Scorer;
74
+ }>;
75
+ /** Options for the agent under test — one agent config for the whole suite. */
76
+ readonly agent: EvalAgentOptions;
77
+ /**
78
+ * Rows evaluated in parallel. Omitted means the key is not forwarded at all, so the SDK's own
79
+ * default applies. Raise it and you raise your provider rate-limit exposure with it.
80
+ */
81
+ readonly concurrency?: number;
82
+ }
83
+
1
84
  /**
2
85
  * Top-level CLI dispatcher via commander (ADR D194).
3
86
  *
4
- * Subcommands: `init`, `dev`, `inspect`, `eval`, `setup`, `acp`, `tasks`.
87
+ * Subcommands: `init`, `dev`, `inspect`, `eval`, `acp`, `setup`, `db`, `tasks`.
5
88
  *
6
- * Exit codes:
7
- * - 0 → success
8
- * - 1 → unknown error
9
- * - 2 → user error (bad flags, unknown subcommand suggestion)
89
+ * Exit codes at this layer:
90
+ * - 0 → success, and also `--help` / `--version`
91
+ * - 1 → unknown error (an exception that escaped a subcommand)
92
+ * - 2 → user error (unknown subcommand, unknown option, bad flag value)
93
+ *
94
+ * Subcommands are free to return codes of their own beyond these — `theokit tasks` uses 3 and 4,
95
+ * `theokit db check-schema-drift` uses 1 to mean "drift found", and `theokit dev` forwards the
96
+ * child process's exit code verbatim. Each command module documents its own.
10
97
  *
11
98
  * @internal
12
99
  */
100
+ /**
101
+ * Parse `argv` and run the matching subcommand, returning the process exit code instead of exiting.
102
+ *
103
+ * `argv` is commander-shaped, i.e. the full `process.argv`: `[execPath, scriptPath, ...args]`. The
104
+ * first two entries are skipped, so passing `["theokit", "init"]` silently drops `init` — pass
105
+ * `["node", "theokit", "init"]` when synthesising one.
106
+ *
107
+ * Never throws and never calls `process.exit`; the caller decides what to do with the code (the
108
+ * bundled `bin/theokit.ts` shim exits with it). Writes to `process.stdout` and `process.stderr`
109
+ * directly, so redirect the streams if you need to capture the output.
110
+ *
111
+ * Returns `0` for success and for `--help` / `--version`, `2` for a user error, `1` for anything
112
+ * that escaped a subcommand as an exception, and otherwise whatever the subcommand returned.
113
+ */
13
114
  declare function main(argv: ReadonlyArray<string>): Promise<number>;
14
115
 
15
116
  /**
16
117
  * Build-time version constants for @theokit/cli.
17
118
  *
18
- * `__SDK_VERSION__` is the sibling `@theokit/sdk` semver (NEVER
19
- * `workspace:*` resolved at build time via tsup `define`). Used by
20
- * `init` templates to pin the SDK dep in scaffolded projects (EC-L
21
- * fix from edge-case review).
119
+ * Both are substituted by tsup `define` at BUILD time, so they are plain string literals in the
120
+ * shipped bundle. The `declare const` below only satisfies the type checker: evaluating this module
121
+ * from unbuilt source, without that substitution, throws a ReferenceError at import.
122
+ *
123
+ * `__SDK_VERSION__` is the sibling `@theokit/sdk` semver (NEVER `workspace:*`). Used by `init`
124
+ * templates to pin the SDK dep in scaffolded projects (EC-L fix from edge-case review).
22
125
  *
23
126
  * `__CLI_VERSION__` is this package's semver. Exposed via `--version`.
24
127
  */
128
+ /**
129
+ * The `@theokit/sdk` semver this CLI was BUILT against — a concrete version, never `workspace:*`.
130
+ *
131
+ * `theokit init` writes it into the scaffolded `package.json`, so it is what a new project pins. It
132
+ * is not a claim about the SDK the current process has loaded, which may be a different version
133
+ * entirely.
134
+ */
25
135
  declare const SDK_VERSION: string;
136
+ /**
137
+ * This package's semver, substituted at build time — what `theokit --version` prints.
138
+ *
139
+ * Distinct from {@link SDK_VERSION}, which is the `@theokit/sdk` version this CLI was built against
140
+ * and the one `theokit init` writes into a scaffolded `package.json`. They move independently, so a
141
+ * bug report should quote both.
142
+ */
26
143
  declare const CLI_VERSION: string;
27
144
 
28
- export { CLI_VERSION, SDK_VERSION, main };
145
+ export { CLI_VERSION, type DatasetEntry, type EvalConfig, SDK_VERSION, type Score, type Scorer, main };
package/dist/index.d.ts CHANGED
@@ -1,28 +1,145 @@
1
+ import { Agent } from '@theokit/sdk';
2
+
3
+ /**
4
+ * The shape of `eval.config.{ts,mjs}`, consumed by `theokit eval` (T5.1, ADR D199).
5
+ *
6
+ * ```ts
7
+ * import type { EvalConfig } from "@theokit/cli";
8
+ *
9
+ * export default {
10
+ * agent: { model: "gpt-4o-mini" },
11
+ * dataset: [{ input: "2+2?", expected: "4" }],
12
+ * scorers: [{ name: "exact", score: (out, exp) => ({ score: out.trim() === exp ? 1 : 0 }) }],
13
+ * } satisfies EvalConfig;
14
+ * ```
15
+ *
16
+ * The runner now delegates to the SDK's `Eval.create().run()` (D212); this shape survived that swap
17
+ * unchanged, which is what D199 was for.
18
+ *
19
+ * @public
20
+ */
21
+
22
+ /**
23
+ * Outcome of a single scoring decision.
24
+ *
25
+ * Exported because `Scorer` — which IS public — returns it: a user writing a scorer could not name
26
+ * its return type. Same shape as the `MemoryProviderFactory` defect in #335, one level down.
27
+ */
28
+ interface Score {
29
+ /** Numeric score in [0, 1]. Use 1.0 for "pass", 0.0 for "fail". */
30
+ readonly score: number;
31
+ /** Optional human-readable reason for the score (shown in the report). */
32
+ readonly reason?: string;
33
+ }
34
+ /**
35
+ * Grades one agent output. May be sync or async (EC-K); both are awaited.
36
+ *
37
+ * `expected` is whatever the dataset entry carried, `unknown` because nothing constrains it — narrow
38
+ * it yourself. It is `undefined` for entries that declared no `expected`, so a scorer that assumes a
39
+ * string has to handle that.
40
+ *
41
+ * Scoring runs inside the SDK's eval engine, which reports per-ROW failures: a failed row carries an
42
+ * `error` and is counted in `errorRows` rather than aborting the suite.
43
+ */
44
+ type Scorer = (output: string, expected?: unknown) => Score | Promise<Score>;
45
+ /**
46
+ * One evaluation case: the prompt sent to the agent, and an optional expected value handed to every
47
+ * scorer untouched (no comparison is performed for you).
48
+ */
49
+ interface DatasetEntry {
50
+ readonly input: string;
51
+ readonly expected?: unknown;
52
+ }
53
+ /**
54
+ * The `Agent.create()` options object, inferred from the installed `@theokit/sdk` rather than
55
+ * re-declared. Whatever that version accepts — model, tools, plugins — is accepted here.
56
+ */
57
+ type EvalAgentOptions = Parameters<typeof Agent.create>[0];
58
+ /**
59
+ * The DEFAULT export of `eval.config.{ts,mjs}`. A named export is not read.
60
+ *
61
+ * `theokit eval` checks only that `dataset` and `scorers` are arrays and `agent` is an object; every
62
+ * deeper mistake surfaces at run time, from the SDK, per row. An empty `dataset` is accepted and
63
+ * short-circuits to a zero-row report — the run costs nothing and proves nothing.
64
+ *
65
+ * Running it spends real money: each entry is one live agent turn against the configured provider.
66
+ */
67
+ interface EvalConfig {
68
+ /** Cases to run, in order. Empty is legal and produces an empty report. */
69
+ readonly dataset: ReadonlyArray<DatasetEntry>;
70
+ /** Scorers applied to EVERY row. `name` is the column label in the markdown report. */
71
+ readonly scorers: ReadonlyArray<{
72
+ readonly name: string;
73
+ readonly score: Scorer;
74
+ }>;
75
+ /** Options for the agent under test — one agent config for the whole suite. */
76
+ readonly agent: EvalAgentOptions;
77
+ /**
78
+ * Rows evaluated in parallel. Omitted means the key is not forwarded at all, so the SDK's own
79
+ * default applies. Raise it and you raise your provider rate-limit exposure with it.
80
+ */
81
+ readonly concurrency?: number;
82
+ }
83
+
1
84
  /**
2
85
  * Top-level CLI dispatcher via commander (ADR D194).
3
86
  *
4
- * Subcommands: `init`, `dev`, `inspect`, `eval`, `setup`, `acp`, `tasks`.
87
+ * Subcommands: `init`, `dev`, `inspect`, `eval`, `acp`, `setup`, `db`, `tasks`.
5
88
  *
6
- * Exit codes:
7
- * - 0 → success
8
- * - 1 → unknown error
9
- * - 2 → user error (bad flags, unknown subcommand suggestion)
89
+ * Exit codes at this layer:
90
+ * - 0 → success, and also `--help` / `--version`
91
+ * - 1 → unknown error (an exception that escaped a subcommand)
92
+ * - 2 → user error (unknown subcommand, unknown option, bad flag value)
93
+ *
94
+ * Subcommands are free to return codes of their own beyond these — `theokit tasks` uses 3 and 4,
95
+ * `theokit db check-schema-drift` uses 1 to mean "drift found", and `theokit dev` forwards the
96
+ * child process's exit code verbatim. Each command module documents its own.
10
97
  *
11
98
  * @internal
12
99
  */
100
+ /**
101
+ * Parse `argv` and run the matching subcommand, returning the process exit code instead of exiting.
102
+ *
103
+ * `argv` is commander-shaped, i.e. the full `process.argv`: `[execPath, scriptPath, ...args]`. The
104
+ * first two entries are skipped, so passing `["theokit", "init"]` silently drops `init` — pass
105
+ * `["node", "theokit", "init"]` when synthesising one.
106
+ *
107
+ * Never throws and never calls `process.exit`; the caller decides what to do with the code (the
108
+ * bundled `bin/theokit.ts` shim exits with it). Writes to `process.stdout` and `process.stderr`
109
+ * directly, so redirect the streams if you need to capture the output.
110
+ *
111
+ * Returns `0` for success and for `--help` / `--version`, `2` for a user error, `1` for anything
112
+ * that escaped a subcommand as an exception, and otherwise whatever the subcommand returned.
113
+ */
13
114
  declare function main(argv: ReadonlyArray<string>): Promise<number>;
14
115
 
15
116
  /**
16
117
  * Build-time version constants for @theokit/cli.
17
118
  *
18
- * `__SDK_VERSION__` is the sibling `@theokit/sdk` semver (NEVER
19
- * `workspace:*` resolved at build time via tsup `define`). Used by
20
- * `init` templates to pin the SDK dep in scaffolded projects (EC-L
21
- * fix from edge-case review).
119
+ * Both are substituted by tsup `define` at BUILD time, so they are plain string literals in the
120
+ * shipped bundle. The `declare const` below only satisfies the type checker: evaluating this module
121
+ * from unbuilt source, without that substitution, throws a ReferenceError at import.
122
+ *
123
+ * `__SDK_VERSION__` is the sibling `@theokit/sdk` semver (NEVER `workspace:*`). Used by `init`
124
+ * templates to pin the SDK dep in scaffolded projects (EC-L fix from edge-case review).
22
125
  *
23
126
  * `__CLI_VERSION__` is this package's semver. Exposed via `--version`.
24
127
  */
128
+ /**
129
+ * The `@theokit/sdk` semver this CLI was BUILT against — a concrete version, never `workspace:*`.
130
+ *
131
+ * `theokit init` writes it into the scaffolded `package.json`, so it is what a new project pins. It
132
+ * is not a claim about the SDK the current process has loaded, which may be a different version
133
+ * entirely.
134
+ */
25
135
  declare const SDK_VERSION: string;
136
+ /**
137
+ * This package's semver, substituted at build time — what `theokit --version` prints.
138
+ *
139
+ * Distinct from {@link SDK_VERSION}, which is the `@theokit/sdk` version this CLI was built against
140
+ * and the one `theokit init` writes into a scaffolded `package.json`. They move independently, so a
141
+ * bug report should quote both.
142
+ */
26
143
  declare const CLI_VERSION: string;
27
144
 
28
- export { CLI_VERSION, SDK_VERSION, main };
145
+ export { CLI_VERSION, type DatasetEntry, type EvalConfig, SDK_VERSION, type Score, type Scorer, main };
package/dist/index.js CHANGED
@@ -358,7 +358,7 @@ function startRunner(opts) {
358
358
  args.push(opts.entry);
359
359
  const child = spawn(process.execPath, [tsxBin, ...args], {
360
360
  cwd: opts.cwd,
361
- stdio: "inherit",
361
+ stdio: opts.stdio ?? "inherit",
362
362
  env: process.env
363
363
  });
364
364
  const exited = new Promise((resolve6) => {
@@ -489,7 +489,13 @@ function formatReport(result) {
489
489
  }
490
490
  function truncate(s, max) {
491
491
  if (s.length <= max) return s;
492
- return `${s.slice(0, max - 1)}\u2026`;
492
+ const budget = max - 1;
493
+ let out = "";
494
+ for (const ch of s) {
495
+ if (out.length + ch.length > budget) break;
496
+ out += ch;
497
+ }
498
+ return `${out}\u2026`;
493
499
  }
494
500
  function escapeMd(s) {
495
501
  return s.replaceAll("|", "\\|").replaceAll("\n", " ");
@@ -619,8 +625,8 @@ ${pc5.green("\u2713")} ${result.aggregate.totalRows} rows \xB7 mean score ${resu
619
625
  }
620
626
 
621
627
  // src/version.ts
622
- var SDK_VERSION = "4.43.0";
623
- var CLI_VERSION = "3.0.2";
628
+ var SDK_VERSION = "4.57.0";
629
+ var CLI_VERSION = "4.0.1";
624
630
 
625
631
  // src/init/templates.ts
626
632
  var TEMPLATES = [
@@ -634,6 +640,26 @@ var TEMPLATES = [
634
640
  description: "100% local agent via Ollama (no remote API key required).",
635
641
  hint: "Requires `ollama serve` + `ollama pull llama3.2:3b`."
636
642
  },
643
+ {
644
+ name: "chatbot",
645
+ description: "Conversational agent that resumes its own thread across runs.",
646
+ hint: "SESSION_DIR=~/.claude writes sessions the Claude Code CLI can --continue."
647
+ },
648
+ {
649
+ name: "multi-agent",
650
+ description: "A classifier routes to specialists, all from one AgentFactory prefix.",
651
+ hint: 'Pass the input as an argument: `pnpm dev "Translate to French: hello"`.'
652
+ },
653
+ {
654
+ name: "rag-agent",
655
+ description: "Retrieval over your own files \u2014 Memory.openIndex behind a Tool.",
656
+ hint: "Put markdown under .theokit/memory/ first, or there is nothing to cite."
657
+ },
658
+ {
659
+ name: "workflow-automation",
660
+ description: "A committed Workflow (fn -> agentStep -> fn) handed to Cron.",
661
+ hint: "WORKFLOW_CRON overrides the schedule; default is every 5 minutes."
662
+ },
637
663
  {
638
664
  name: "telegram-bot",
639
665
  description: "Telegram bot via @theokit/gateway + grammy.",
@@ -695,6 +721,13 @@ function resolveTemplatesRoot() {
695
721
  `Could not locate bundled templates/ directory (searched up from ${here}). This usually means the published tarball was built without "files": ["templates"] (EC-C regression).`
696
722
  );
697
723
  }
724
+ var SCAFFOLD_USER_ERROR_CODES = [
725
+ "invalid_project_name",
726
+ "unknown_template",
727
+ "invalid_dest",
728
+ "dest_is_symlink",
729
+ "dest_not_empty"
730
+ ];
698
731
  function scaffoldError(code, message) {
699
732
  const err = new Error(message);
700
733
  err.code = code;
@@ -830,12 +863,7 @@ async function resolveTemplate(optsTemplate, skipPrompts) {
830
863
  }
831
864
  return template;
832
865
  }
833
- var USER_ERROR_CODES = /* @__PURE__ */ new Set([
834
- "invalid_project_name",
835
- "dest_not_empty",
836
- "invalid_dest",
837
- "unknown_template"
838
- ]);
866
+ var USER_ERROR_CODES = new Set(SCAFFOLD_USER_ERROR_CODES);
839
867
  async function runScaffold(name, template, force) {
840
868
  try {
841
869
  const result = await scaffold({
@@ -1189,14 +1217,6 @@ ${pc5.dim(" shape: Desktop OAuth client (installed block present)")}
1189
1217
  }
1190
1218
  const interactiveCode = await runInteractiveSetup();
1191
1219
  if (interactiveCode !== 0) return interactiveCode;
1192
- if (typeof opts.writable === "string" && opts.writable.length > 0) {
1193
- process.stdout.write(
1194
- `
1195
- ${pc5.yellow("note:")} you passed --writable=${opts.writable}. The upstream MCP server does not narrow scopes \u2014 all scopes are granted at consent.
1196
- Write tools are gated at runtime by ${pc5.bold("googleWorkspace({ writable: true })")} in your code.
1197
- `
1198
- );
1199
- }
1200
1220
  process.stdout.write(
1201
1221
  `
1202
1222
  ${pc5.green("\u2713")} gworkspace setup complete.
@@ -1243,7 +1263,6 @@ function spawnUpstream(args, timeoutMs) {
1243
1263
  async function runSetup(domain, opts) {
1244
1264
  if (domain === "gworkspace") {
1245
1265
  const gworkspaceOpts = {
1246
- writable: opts.writable,
1247
1266
  probe: opts.probe === true,
1248
1267
  nonInteractive: opts.nonInteractive === true,
1249
1268
  ...opts.credentialsPath !== void 0 ? { credentialsPath: opts.credentialsPath } : {}
@@ -1374,7 +1393,7 @@ async function runTasksInspect(id, opts) {
1374
1393
  }
1375
1394
  return 0;
1376
1395
  }
1377
- async function runTasksCancel(id, _opts) {
1396
+ async function runTasksCancel(id, opts) {
1378
1397
  if (!isValidTaskId(id)) {
1379
1398
  process.stderr.write(`tasks: invalid id grammar: ${id}
1380
1399
  `);
@@ -1399,12 +1418,21 @@ async function runTasksCancel(id, _opts) {
1399
1418
  }
1400
1419
  if (handle.state === "queued") {
1401
1420
  const cancelledAt = Date.now();
1402
- await store.update(id, (h) => ({ ...h, state: "cancelled", cancelledAt }));
1421
+ await store.update(id, (h) => ({
1422
+ ...h,
1423
+ state: "cancelled",
1424
+ cancelledAt,
1425
+ ...opts.reason !== void 0 ? { cancelReason: opts.reason } : {}
1426
+ }));
1403
1427
  process.stdout.write(`task ${id} cancelled (was queued)
1404
1428
  `);
1405
1429
  return 0;
1406
1430
  }
1407
- await store.update(id, (h) => ({ ...h, cancelRequested: true }));
1431
+ await store.update(id, (h) => ({
1432
+ ...h,
1433
+ cancelRequested: true,
1434
+ ...opts.reason !== void 0 ? { cancelReason: opts.reason } : {}
1435
+ }));
1408
1436
  process.stdout.write(
1409
1437
  `cancel requested for task ${id}; the owning process will honor it at the next checkpoint
1410
1438
  `
@@ -1414,7 +1442,13 @@ async function runTasksCancel(id, _opts) {
1414
1442
 
1415
1443
  // src/main.ts
1416
1444
  function registerSubcommands(program, setExit) {
1417
- 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) => {
1445
+ program.command("init [project-name]").description("Scaffold a new agent project from a bundled template.").option(
1446
+ "-t, --template <name>",
1447
+ // Derived from the registry, not restated. This line named three templates while the
1448
+ // registry held seven — a help text that lists options is a second copy of the list, and
1449
+ // the copy is the one that goes stale.
1450
+ `Template name: ${TEMPLATES.map((t) => t.name).join(" | ")}`
1451
+ ).option("-f, --force", "Overwrite a non-empty destination directory").option("-y, --yes", "Skip interactive prompts (CI mode)").action(async (projectName, opts) => {
1418
1452
  setExit(await runInit(projectName, opts));
1419
1453
  });
1420
1454
  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) => {
@@ -1430,15 +1464,12 @@ function registerSubcommands(program, setExit) {
1430
1464
  setExit(await runEval(opts));
1431
1465
  });
1432
1466
  program.command("acp").description(
1433
- "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."
1467
+ "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."
1434
1468
  ).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) => {
1435
1469
  setExit(await runAcp(opts));
1436
1470
  });
1437
1471
  program.command("setup <domain>").description(
1438
1472
  "Stage credentials + connectivity probe for a third-party integration. Domains: gworkspace (Google Workspace)."
1439
- ).option(
1440
- "--writable <products>",
1441
- "Comma-separated products to grant write access (e.g., 'drive,calendar')"
1442
1473
  ).option("--probe", "Run upstream connectivity check after staging credentials").option(
1443
1474
  "--credentials-path <path>",
1444
1475
  "Override path to credentials.json (default: ~/.google-mcp/credentials.json)"
@@ -1476,7 +1507,7 @@ function registerSubcommands(program, setExit) {
1476
1507
  setExit(await runTasksInspect(id, opts));
1477
1508
  });
1478
1509
  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) => {
1479
- setExit(await runTasksCancel(id));
1510
+ setExit(await runTasksCancel(id, opts));
1480
1511
  });
1481
1512
  }
1482
1513
  function mapCommanderExitCode(code, fallback) {