@namzu/cli 27.0.0 → 28.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 (113) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/README.md +24 -18
  3. package/dist/cli.d.ts +2 -0
  4. package/dist/cli.d.ts.map +1 -1
  5. package/dist/cli.js +122 -12
  6. package/dist/cli.js.map +1 -1
  7. package/dist/commands/drain.js +2 -2
  8. package/dist/commands/drain.js.map +1 -1
  9. package/dist/commands/{run-flags.d.ts → exec-flags.d.ts} +29 -21
  10. package/dist/commands/exec-flags.d.ts.map +1 -0
  11. package/dist/commands/{run-flags.js → exec-flags.js} +31 -23
  12. package/dist/commands/exec-flags.js.map +1 -0
  13. package/dist/commands/{run-stream.d.ts → exec-json.d.ts} +20 -14
  14. package/dist/commands/exec-json.d.ts.map +1 -0
  15. package/dist/commands/exec-json.js +473 -0
  16. package/dist/commands/exec-json.js.map +1 -0
  17. package/dist/commands/{run.d.ts → exec.d.ts} +14 -13
  18. package/dist/commands/exec.d.ts.map +1 -0
  19. package/dist/commands/exec.js +683 -0
  20. package/dist/commands/exec.js.map +1 -0
  21. package/dist/commands/host-queries.d.ts +12 -0
  22. package/dist/commands/host-queries.d.ts.map +1 -0
  23. package/dist/commands/host-queries.js +149 -0
  24. package/dist/commands/host-queries.js.map +1 -0
  25. package/dist/commands/prior-messages.js +1 -1
  26. package/dist/commands/prior-messages.js.map +1 -1
  27. package/dist/commands/registry.d.ts.map +1 -1
  28. package/dist/commands/registry.js +2 -0
  29. package/dist/commands/registry.js.map +1 -1
  30. package/dist/commands/resident-flags.d.ts +2 -2
  31. package/dist/commands/resident-flags.d.ts.map +1 -1
  32. package/dist/commands/resident-flags.js +4 -2
  33. package/dist/commands/resident-flags.js.map +1 -1
  34. package/dist/commands/resident-learning.js +1 -1
  35. package/dist/commands/resident-learning.js.map +1 -1
  36. package/dist/commands/resident.js +1 -1
  37. package/dist/commands/resident.js.map +1 -1
  38. package/dist/commands/skills.js +1 -1
  39. package/dist/commands/skills.js.map +1 -1
  40. package/dist/commands/stdin.d.ts +5 -5
  41. package/dist/commands/stdin.js +5 -5
  42. package/dist/commands/types.d.ts +2 -0
  43. package/dist/commands/types.d.ts.map +1 -1
  44. package/dist/config/load.d.ts.map +1 -1
  45. package/dist/config/load.js +19 -0
  46. package/dist/config/load.js.map +1 -1
  47. package/dist/config/schema.d.ts +18 -4
  48. package/dist/config/schema.d.ts.map +1 -1
  49. package/dist/config/schema.js.map +1 -1
  50. package/dist/config/{run-limits.d.ts → turn-guards.d.ts} +1 -1
  51. package/dist/config/turn-guards.d.ts.map +1 -0
  52. package/dist/config/{run-limits.js → turn-guards.js} +1 -1
  53. package/dist/config/turn-guards.js.map +1 -0
  54. package/dist/context/project.d.ts +1 -1
  55. package/dist/context/project.js +1 -1
  56. package/dist/doctor/checks/chain.js +2 -2
  57. package/dist/doctor/checks/chain.js.map +1 -1
  58. package/dist/integrations/providers/access.d.ts +4 -1
  59. package/dist/integrations/providers/access.d.ts.map +1 -1
  60. package/dist/integrations/providers/access.js +6 -3
  61. package/dist/integrations/providers/access.js.map +1 -1
  62. package/dist/integrations/providers/zen-catalogue.d.ts +100 -0
  63. package/dist/integrations/providers/zen-catalogue.d.ts.map +1 -0
  64. package/dist/integrations/providers/zen-catalogue.js +196 -0
  65. package/dist/integrations/providers/zen-catalogue.js.map +1 -0
  66. package/dist/integrations/resident/runner-launch.d.ts +3 -3
  67. package/dist/integrations/resident/runner-launch.d.ts.map +1 -1
  68. package/dist/integrations/resident/runner-worker.js +22 -0
  69. package/dist/integrations/resident/runner-worker.js.map +1 -1
  70. package/dist/integrations/resident/session-step.d.ts +2 -2
  71. package/dist/integrations/resident/session-step.d.ts.map +1 -1
  72. package/dist/integrations/resident/session-step.js +1 -1
  73. package/dist/integrations/resident/session-step.js.map +1 -1
  74. package/dist/integrations/subagents/runtime.d.ts.map +1 -1
  75. package/dist/integrations/subagents/runtime.js +1 -1
  76. package/dist/integrations/subagents/runtime.js.map +1 -1
  77. package/dist/integrations/web/search.d.ts +1 -1
  78. package/dist/logging.d.ts +5 -5
  79. package/dist/logging.js +6 -6
  80. package/dist/permissions/headless-trust.d.ts +2 -2
  81. package/dist/permissions/headless-trust.js +3 -3
  82. package/dist/permissions/headless-trust.js.map +1 -1
  83. package/dist/termination.d.ts +1 -1
  84. package/dist/termination.js +1 -1
  85. package/dist/tui/App.js +5 -5
  86. package/dist/tui/App.js.map +1 -1
  87. package/dist/tui/agent.d.ts +4 -4
  88. package/dist/tui/agent.d.ts.map +1 -1
  89. package/dist/tui/agent.js +13 -4
  90. package/dist/tui/agent.js.map +1 -1
  91. package/dist/tui/slashCommands.d.ts +1 -1
  92. package/dist/tui/slashCommands.js +5 -5
  93. package/dist/tui/slashCommands.js.map +1 -1
  94. package/dist/tui/status-panel-layout.js +1 -1
  95. package/dist/tui/status-panel-layout.js.map +1 -1
  96. package/dist/tui/turn-limits-settings.d.ts +1 -1
  97. package/dist/tui/turn-limits-settings.d.ts.map +1 -1
  98. package/dist/tui/turn-limits-settings.js +1 -1
  99. package/dist/tui/turn-limits-settings.js.map +1 -1
  100. package/dist/user-commands/store.d.ts +3 -3
  101. package/dist/user-commands/store.js +4 -4
  102. package/dist/user-commands/store.js.map +1 -1
  103. package/package.json +3 -3
  104. package/dist/commands/run-flags.d.ts.map +0 -1
  105. package/dist/commands/run-flags.js.map +0 -1
  106. package/dist/commands/run-stream.d.ts.map +0 -1
  107. package/dist/commands/run-stream.js +0 -647
  108. package/dist/commands/run-stream.js.map +0 -1
  109. package/dist/commands/run.d.ts.map +0 -1
  110. package/dist/commands/run.js +0 -617
  111. package/dist/commands/run.js.map +0 -1
  112. package/dist/config/run-limits.d.ts.map +0 -1
  113. package/dist/config/run-limits.js.map +0 -1
@@ -0,0 +1,473 @@
1
+ /**
2
+ * `namzu exec --json [--session <key>] "<prompt>"` — the headless one-shot as
3
+ * a STREAM. Same engine as the default mode, but instead of buffering the
4
+ * final text it emits one compact NDJSON line per `AgentEvent` to stdout
5
+ * (`{"kind":"delta","text":…}`, `{"kind":"tool-start",…}`,
6
+ * `{"kind":"error","message":…}`, `{"kind":"done"}`). A host process — a
7
+ * desktop app embedding namzu, say — line-scans stdout and renders the turn
8
+ * live: the equivalent of the TUI, driven from another runtime.
9
+ *
10
+ * History: with `--session <key>` the turn is bound to a persisted
11
+ * conversation in the project the canonical cwd stands for (keyed by the
12
+ * embedder's own session id, recorded on the conversation's
13
+ * `session_started.origin`), so prior turns are folded from its session log as
14
+ * context and the kernel appends this turn to that log as it runs — opaque
15
+ * reasoning and complete tool turns included. That's what lets a reopened
16
+ * session show and replay its past messages (`namzu history --session
17
+ * <key>`). Without `--session`, prior history may be supplied on stdin as a
18
+ * JSON `Message[]` and the turn works in an in-memory log: nothing is
19
+ * persisted (a stateless one-shot).
20
+ *
21
+ * Status lines go to stderr as NDJSON (LOG-05), never stdout, so every
22
+ * stdout line is a valid JSON event, and EVERY failure is reported in band,
23
+ * including the ones that also carry an exit code.
24
+ *
25
+ * ## What the exit code means
26
+ *
27
+ * It used to be explained as "a turn that STARTED and failed exits 0; a refusal
28
+ * to start exits non-zero", and that rule did not sort the cases it was applied
29
+ * to. An unknown option, a missing prompt, a `--cwd` that is not there and a
30
+ * tool server that will not connect are all refusals to start, and all four
31
+ * exited 0 while an untrusted folder exited 77. Neither does the retry argument
32
+ * the old comment appealed to: retrying an unknown option is exactly as
33
+ * pointless as retrying an untrusted folder.
34
+ *
35
+ * The axis that does sort them:
36
+ *
37
+ * CAN THE CALLER REACH THE TURN IT ASKED FOR BY CHANGING WHAT IT SENDS?
38
+ *
39
+ * - **Yes → `0`.** The host reads the `error` event and fixes its own
40
+ * invocation. An unknown option, no prompt, a `--cwd` that does not exist, a
41
+ * `--permission-mode` that is not a mode, an interactive command named
42
+ * headlessly, a provider id that is not a provider.
43
+ * - **A turn that started and failed → `0`.** Unchanged: that is an outcome to
44
+ * render, and possibly to retry.
45
+ * - **Not now → `75`.** The conversation already has an active turn — a
46
+ * paused one waiting on a decision or a drain, or one another process is
47
+ * running — so this turn was not begun. The event is
48
+ * `{"kind":"error","code":"turn_in_progress",...}` naming the turn.
49
+ * - **No → non-zero, because a person has to go and do something.** `77` when
50
+ * the folder is untrusted — kept to that one condition, because being
51
+ * unambiguous is its entire justification. `1` for everything else in this
52
+ * group: a conversation that cannot be opened, no provider available, a
53
+ * credential or driver the session needs, a declared tool server that is not
54
+ * there, a command file that will not parse.
55
+ *
56
+ * `1` rather than a new code because the default mode of `namzu exec` — the
57
+ * same one-shot, differing only in how it prints — already exits `1` for these
58
+ * conditions and `77` for trust. A host that shells to one for a script and the other for a UI must not
59
+ * be handed two tables for one fact.
60
+ *
61
+ * Dropping `--session` is NOT "the caller fixing it": it abandons what was
62
+ * asked for rather than achieving it.
63
+ */
64
+ import { TurnCancelled, generateSessionId, jsonLinesSink, } from '@namzu/sdk';
65
+ /** EX_TEMPFAIL: the conversation already has an active turn; try again later. */
66
+ const EXIT_TURN_IN_PROGRESS = 75;
67
+ import { resolveTrustedProjectContext } from '../config/trusted-project-context.js';
68
+ import { EXIT_FAIL, EXIT_OK, EXIT_UNTRUSTED } from '../exit-codes.js';
69
+ import { closeSessions, loadConversation, openSessions, resolveConversation, } from '../integrations/sessions/store.js';
70
+ import { contextLogging, installCliLogging } from '../logging.js';
71
+ import { decideHeadlessTrust } from '../permissions/headless-trust.js';
72
+ import { resolvePermissionMode } from '../permissions/mode.js';
73
+ import { compilePermissions } from '../permissions/rules.js';
74
+ import { hostCommandNames } from '../tui/slashCommands.js';
75
+ import { expandHeadlessCommand } from '../user-commands/store.js';
76
+ import { applyProviderFlags, buildGate, loadSkillsContext, resolveWorkingDirectory, unknownOptionMessage, } from './exec-flags.js';
77
+ import { parsePriorMessages } from './prior-messages.js';
78
+ import { readStdin } from './stdin.js';
79
+ function defaultPrefs(detected) {
80
+ const first = detected[0];
81
+ return first
82
+ ? {
83
+ version: 3,
84
+ providers: [{ id: first.entry.id }],
85
+ subagents: { active: [] },
86
+ }
87
+ : null;
88
+ }
89
+ /**
90
+ * `exec --json`. `flags` are already parsed; `structuredOutput` is the loaded
91
+ * `--output-schema`, or an error loading it that is reported in band.
92
+ */
93
+ export async function execJson({ ctx: bootstrapCtx }, termination, flags, structuredOutput) {
94
+ let ctx = bootstrapCtx;
95
+ const write = (o) => {
96
+ process.stdout.write(`${JSON.stringify(o)}\n`);
97
+ };
98
+ /**
99
+ * Report and stop.
100
+ *
101
+ * Always in band, always terminated with `done`, and the code says only
102
+ * whether the caller can reach the turn by sending something else. The
103
+ * argument for each case is in this file's header; the two spellings exist
104
+ * so that every call site below has to state which side it is on rather
105
+ * than inheriting a default nobody re-reads.
106
+ */
107
+ const fail = (message) => {
108
+ write({ kind: 'error', message });
109
+ write({ kind: 'done' });
110
+ return EXIT_OK;
111
+ };
112
+ const refuse = (message) => {
113
+ write({ kind: 'error', message });
114
+ write({ kind: 'done' });
115
+ return EXIT_FAIL;
116
+ };
117
+ // The turn's leash: the config file's limits, with a flag overriding each.
118
+ const limitsFromFlags = {
119
+ ...(flags.maxIterations !== null ? { maxIterations: flags.maxIterations } : {}),
120
+ ...(flags.tokenBudget !== null ? { tokenBudget: flags.tokenBudget } : {}),
121
+ };
122
+ if (flags.unknown.length > 0)
123
+ return fail(unknownOptionMessage(flags.unknown));
124
+ if (structuredOutput && 'error' in structuredOutput)
125
+ return fail(structuredOutput.error);
126
+ // `--continue` and `--resume` parse here because both modes share one
127
+ // parser, and this mode reads neither. Accepting a flag and doing
128
+ // nothing with it is the failure mode the shared parser was introduced to
129
+ // end: a host that asked to reopen a conversation was given a stateless
130
+ // turn, reported as an ordinary success, and the next turn had no history
131
+ // with nothing anywhere connecting the two. Refused instead, and named,
132
+ // because a host CAN fix this — `--session` is the flag it wanted.
133
+ if (flags.continueLast || flags.resume !== null) {
134
+ return fail('exec --json does not take --continue or --resume; they belong to the default mode. Bind history with --session <id>, which keys a persisted conversation in this folder.');
135
+ }
136
+ // Same reasoning for the wait budget: this mode streams a pause to its
137
+ // host as an event and the host decides when to resume; a flag it accepted
138
+ // and ignored would promise a wait that never happens.
139
+ if (flags.waitForProviderMs !== null) {
140
+ return fail('exec --json does not take --wait-for-provider; it belongs to the default mode. A host reads the paused event and resumes when it chooses.');
141
+ }
142
+ const sessionKey = flags.session;
143
+ const prompt = flags.rest.join(' ').trim();
144
+ if (!prompt)
145
+ return fail('no prompt — pass it as an argument');
146
+ const resolved = resolveWorkingDirectory(flags.cwd);
147
+ if ('error' in resolved)
148
+ return fail(resolved.error);
149
+ const requestedCwd = resolved.cwd;
150
+ // Before the session store is opened, before anything is read or run in
151
+ // that directory.
152
+ //
153
+ // Reported BOTH ways, which is the one place this command departs from
154
+ // its "every failure is an in-band event and the exit code is 0" rule.
155
+ // That rule is about a turn that STARTED and failed, which a host should
156
+ // render and may sensibly retry. This is a refusal to start at all, and
157
+ // a host that cannot tell the two apart will retry the one that must not
158
+ // be retried — so the event carries the explanation and the exit code
159
+ // carries the fact that nothing ran.
160
+ const trust = decideHeadlessTrust({
161
+ cwd: requestedCwd,
162
+ trustFlag: flags.trust,
163
+ });
164
+ if (!trust.allowed) {
165
+ write({ kind: 'error', message: trust.message ?? 'folder not trusted' });
166
+ write({ kind: 'done' });
167
+ return EXIT_UNTRUSTED;
168
+ }
169
+ const cwd = trust.cwd;
170
+ ctx = resolveTrustedProjectContext(bootstrapCtx, cwd);
171
+ // Project command discovery belongs behind the target folder's trust
172
+ // gate, alongside project config and instructions.
173
+ const expansion = expandHeadlessCommand(prompt, {
174
+ cwd,
175
+ builtins: hostCommandNames(),
176
+ });
177
+ if (expansion.kind === 'refused') {
178
+ return expansion.fixable ? fail(expansion.reason) : refuse(expansion.reason);
179
+ }
180
+ const finalPrompt = expansion.kind === 'expanded' ? expansion.prompt : prompt;
181
+ // Resolve the workspace's central Project for every turn. A session key
182
+ // additionally binds a durable conversation; without one, stdin history
183
+ // remains stateless and no Session record is created.
184
+ let cli;
185
+ let conversationId = null;
186
+ let prior = [];
187
+ if (!sessionKey) {
188
+ const parsed = parsePriorMessages(await readStdin({ deadline: true }));
189
+ if (!parsed.ok)
190
+ return fail(`invalid stdin history: ${parsed.error}`);
191
+ prior = [...parsed.messages];
192
+ }
193
+ try {
194
+ cli = await openSessions(cwd);
195
+ if (sessionKey) {
196
+ conversationId = await resolveConversation(cli, sessionKey);
197
+ prior = await loadConversation(cli, conversationId);
198
+ }
199
+ }
200
+ catch (err) {
201
+ if (sessionKey) {
202
+ // Refused, not run stateless.
203
+ //
204
+ // This used to set `cli = null` and fall through to the branch
205
+ // below, which reads prior turns from STDIN — so a caller who named
206
+ // a conversation got a turn answered against a different history,
207
+ // or none, reported as an ordinary success. The default mode already
208
+ // refuses the equivalent, in those words: someone who asked for a
209
+ // specific conversation and got a new one that looks the same finds
210
+ // out several turns later, having already acted on it.
211
+ //
212
+ // It cannot be softened into a warning, because we cannot say what
213
+ // was lost. `resolveConversation` creates the key on first use, so
214
+ // a fresh key legitimately has no prior turns — and the failure is
215
+ // exactly what stopped us finding out which case this is. "Could
216
+ // not look" is not "there was nothing there."
217
+ //
218
+ // In band, like every other failure here, because that is what the
219
+ // host reads. No session has been built at this point in the flow,
220
+ // so there is nothing to close on the way out.
221
+ //
222
+ // Non-zero, which is the correction #321 is about. `resolveConversation`
223
+ // CREATES the key on first use, so this cannot be a key the host got
224
+ // wrong — the only way here is the store itself: an unwritable
225
+ // `.namzu`, a corrupt map file. Nothing the host sends changes that,
226
+ // so a host treating 0 as "render the error and move on" would loop
227
+ // on an environment fault it could have raised to a person. Dropping
228
+ // `--session` is not a fix; it abandons what was asked for.
229
+ return refuse(`could not open conversation "${sessionKey}": ${err instanceof Error ? err.message : String(err)}. Nothing ran, because continuing the wrong history is worse than not continuing. Drop --session to run this turn stateless.`);
230
+ }
231
+ return refuse(`could not open workspace state: ${err instanceof Error ? err.message : String(err)}. Nothing ran, because generated state could not be bound to this working directory.`);
232
+ }
233
+ // Always NDJSON on stderr, regardless of --log-format/NAMZU_LOG_FORMAT
234
+ // — this is the machine-read channel §6.6 of the logging design
235
+ // describes, and stdout's own protocol is unaffected by anything the
236
+ // operator passes, so stderr here stays that way too. `{ replace:
237
+ // true }`: see `exec.ts`'s identical comment.
238
+ const logging = contextLogging(ctx);
239
+ installCliLogging(jsonLinesSink(process.stderr), logging.level);
240
+ const { probeAgentSession, createAgentSession } = await import('../tui/agent.js');
241
+ const probe = await probeAgentSession();
242
+ let prefs = probe.preferences ?? defaultPrefs(probe.detected);
243
+ if (!prefs) {
244
+ // Nothing detected and nothing configured. `--provider` cannot conjure a
245
+ // credential, so no argument the host changes gets past this line.
246
+ return refuse('no LLM provider available — set a credential (e.g. ANTHROPIC_API_KEY) or run `namzu` to pick one');
247
+ }
248
+ // --provider/--model override the persona's configured provider+model for
249
+ // this turn, so the Namzu tab's picks win over ~/.namzu/preferences.json.
250
+ prefs = applyProviderFlags(prefs, flags);
251
+ // The operator's rules and mode reach this mode too. They did not:
252
+ // `[permissions]` was compiled for the printing one-shot and never for the streaming one, so a
253
+ // host UI ran with an empty rule list whatever the config said — the same
254
+ // shape as a flag that parses and does nothing, one level larger, and
255
+ // silent in exactly the same way.
256
+ const modeResult = resolvePermissionMode({
257
+ flag: flags.permissionMode,
258
+ skipPermissions: flags.skipPermissions,
259
+ interactive: false,
260
+ });
261
+ if ('error' in modeResult)
262
+ return fail(modeResult.error);
263
+ const permissions = compilePermissions(ctx.config.permissions, ctx.config.permissionChecks);
264
+ for (const d of permissions.diagnostics) {
265
+ const where = d.pattern ? `permissions.${d.tool}."${d.pattern}"` : `permissions.${d.tool}`;
266
+ // In band, because a host line-scanning stdout has no other channel —
267
+ // and a permission the operator believes is in force must never be
268
+ // dropped without saying so.
269
+ write({ kind: 'error', message: `${where}: ${d.message}` });
270
+ }
271
+ // The resolved `--cwd` is what the agent's tools resolve against, not just
272
+ // where the session store lives — a turn told to work in another checkout
273
+ // has to glob, read and edit files there.
274
+ const gate = buildGate(flags, cwd);
275
+ const session = await createAgentSession(prefs, probe.detected, {
276
+ cwd,
277
+ ...(structuredOutput ? { structuredOutput } : {}),
278
+ scope: {
279
+ sessionId: conversationId ?? generateSessionId(),
280
+ topicId: cli.topicId,
281
+ projectId: cli.projectId,
282
+ tenantId: cli.tenantId,
283
+ },
284
+ stateRoot: cli.root,
285
+ // A keyed conversation appends to its log; a stateless one runs in an
286
+ // in-memory log, so nothing is written for it.
287
+ ...(conversationId ? { conversationSessions: cli } : { ephemeral: true }),
288
+ rules: permissions.rules,
289
+ // The operator's --gate commands, as a standing condition on the
290
+ // answer. Spread rather than passed as undefined so a turn without
291
+ // gates is byte-identical to the one that shipped before them.
292
+ ...(gate ?? {}),
293
+ permissionMode: modeResult.mode,
294
+ ...(ctx.config.mcpServers ? { mcpServers: ctx.config.mcpServers } : {}),
295
+ ...(ctx.config.plugins ? { plugins: ctx.config.plugins } : {}),
296
+ ...(ctx.config.web ? { web: ctx.config.web } : {}),
297
+ ...(ctx.config.hooks ? { hooks: ctx.config.hooks } : {}),
298
+ ...(ctx.config.compaction ? { compaction: ctx.config.compaction } : {}),
299
+ ...(ctx.config.memory ? { memory: ctx.config.memory } : {}),
300
+ ...(Object.keys({ ...ctx.config.limits, ...limitsFromFlags }).length > 0
301
+ ? { limits: { ...ctx.config.limits, ...limitsFromFlags } }
302
+ : {}),
303
+ ...(ctx.config.sandbox ? { sandbox: ctx.config.sandbox } : {}),
304
+ // `!== undefined`, not truthiness: an empty list is the operator
305
+ // turning the default screen OFF, and a falsy check would drop it.
306
+ ...(ctx.config.toolResultScreens !== undefined
307
+ ? { toolResultScreens: ctx.config.toolResultScreens }
308
+ : {}),
309
+ });
310
+ if (!session.hasProvider) {
311
+ await session.close();
312
+ // The one branch here that is genuinely BOTH. `createAgentSession`
313
+ // refuses an id that is not a provider — which `--provider` put there,
314
+ // so the host fixes it — and, with the same result object, a missing
315
+ // credential, a driver package that would not load, a chain that
316
+ // contradicts itself, a client that would not construct. None of those
317
+ // four move for any argument.
318
+ //
319
+ // The session says which, in a field. Deciding it here by reading its
320
+ // `errorHint` would be the message-matching that `exit-codes.ts` exists
321
+ // to prevent, and would make that sentence unrewordable.
322
+ const message = session.errorHint ?? 'agent is not ready';
323
+ return session.errorKind === 'invocation' ? fail(message) : refuse(message);
324
+ }
325
+ // A configured tool server that is not here means the turn cannot do what
326
+ // the operator set it up to do, and this command answers a host, not a
327
+ // person who might notice. Refused rather than run short — in band, like
328
+ // every other failure here, because that is what the host reads.
329
+ if (session.mcpFailed.length > 0) {
330
+ const said = session.mcpFailed
331
+ .map((f) => `tool server "${f.name}" is not available: ${f.reason}`)
332
+ .join('; ');
333
+ await session.close();
334
+ // The servers come from `namzu.config.json`, not from the invocation, so
335
+ // there is no argument the host can change to bring one up. The default
336
+ // mode already exits 1 here.
337
+ return refuse(said);
338
+ }
339
+ // "Printed on every launch" has to reach a host UI too, or the one caller
340
+ // with no human watching is the one that never hears it. Its own event
341
+ // kind rather than an `error`: the turn is proceeding, and a host that
342
+ // treats this as a failure would be wrong.
343
+ for (const notice of session.configNotices) {
344
+ write({ kind: 'notice', message: notice });
345
+ }
346
+ // --skills <a,b,c>: load the named skills' bodies and inject them as the
347
+ // turn's extra system context (the same channel the TUI's /skill uses).
348
+ const extraSystem = await loadSkillsContext(cwd, flags.skills);
349
+ const userMessage = {
350
+ role: 'user',
351
+ content: finalPrompt,
352
+ timestamp: Date.now(),
353
+ };
354
+ const messages = [...prior, userMessage];
355
+ let terminalEvent;
356
+ let budget;
357
+ let busy;
358
+ // Stopped from outside (SIGTERM, SIGHUP, SIGINT): the conversation's
359
+ // lease is already given back when this runs (`termination.ts`). The host
360
+ // is told in band and last — one `error` of code "terminated", then the
361
+ // stream's one `done` — then the turn is stopped (its tools' processes go
362
+ // with it) and the session closed. Nothing after those two lines is
363
+ // written. What the error says depends on where the signal found the
364
+ // turn: mid-flight it is left interrupted; once the turn has settled (the
365
+ // session still closing, a slow `session_end` hook) it is recorded, and
366
+ // the `done` is the turn's own.
367
+ const turnAbort = new AbortController();
368
+ let stopped = false;
369
+ /** Once the turn has settled: the stream's last line, and what a signal then says. */
370
+ let settled;
371
+ /** The last line has been written; a signal after this writes nothing. */
372
+ let ended = false;
373
+ const inConversation = conversationId ? ` in conversation ${conversationId}` : '';
374
+ termination.onTerminate(async (signal) => {
375
+ stopped = true;
376
+ if (!ended) {
377
+ ended = true;
378
+ try {
379
+ write({
380
+ kind: 'error',
381
+ code: 'terminated',
382
+ message: settled
383
+ ? `stopped by ${signal} ${settled.state}`
384
+ : `stopped by ${signal}; the turn was left interrupted${inConversation}. Close it with /abandon in the TUI, or continue it with /resume or \`namzu drain\`.`,
385
+ });
386
+ write(settled?.last ?? {
387
+ kind: 'done',
388
+ ...(conversationId ? { sessionId: conversationId } : {}),
389
+ });
390
+ }
391
+ catch {
392
+ // The reader is gone (SIGHUP, a closed pipe); there is nobody to tell.
393
+ }
394
+ }
395
+ turnAbort.abort(new TurnCancelled('user'));
396
+ await session.close();
397
+ closeSessions(cli);
398
+ });
399
+ let paused;
400
+ try {
401
+ for await (const event of session.send(messages, {
402
+ signal: turnAbort.signal,
403
+ ...(extraSystem ? { extraSystem } : {}),
404
+ ...(flags.effort !== null ? { effort: flags.effort } : {}),
405
+ })) {
406
+ if (stopped)
407
+ continue;
408
+ if ('budget' in event && event.budget)
409
+ budget = event.budget;
410
+ if (event.kind === 'paused')
411
+ paused = event;
412
+ if (event.kind === 'error' && event.turnInProgress) {
413
+ busy = event.turnInProgress;
414
+ write({ ...event, code: 'turn_in_progress' });
415
+ }
416
+ else if (event.kind === 'done')
417
+ terminalEvent = event;
418
+ else
419
+ write(event);
420
+ }
421
+ }
422
+ catch (err) {
423
+ // The signal handler closes the session and ends the process.
424
+ if (stopped)
425
+ return EXIT_OK;
426
+ const message = err instanceof Error ? err.message : String(err);
427
+ settled = {
428
+ last: { kind: 'done' },
429
+ state: `after the turn failed (${message})${inConversation}.`,
430
+ };
431
+ await session.close();
432
+ closeSessions(cli);
433
+ if (stopped)
434
+ return EXIT_OK;
435
+ ended = true;
436
+ return fail(message);
437
+ }
438
+ if (stopped)
439
+ return EXIT_OK;
440
+ settled = busy
441
+ ? {
442
+ // Nothing was begun, so nothing was recorded: the conversation's
443
+ // active turn is still the one it was. Not now, rather than not ever.
444
+ last: { kind: 'done', sessionId: busy.sessionId },
445
+ state: `; no turn was started in conversation ${busy.sessionId}.`,
446
+ }
447
+ : {
448
+ // The kernel appended this turn to the conversation's log as it ran,
449
+ // so a later `history --session <key>` and the next turn's context
450
+ // see it.
451
+ last: {
452
+ ...(terminalEvent ?? {
453
+ kind: 'done',
454
+ ...(conversationId ? { sessionId: conversationId } : {}),
455
+ }),
456
+ ...(budget ? { budget } : {}),
457
+ },
458
+ state: paused
459
+ ? `while the turn was paused: it keeps checkpoint ${paused.checkpointId}${inConversation}. Continue it with /resume or \`namzu drain\`, or close it with /abandon in the TUI.`
460
+ : `after the turn ended; it is recorded${inConversation}, and nothing is left to close.`,
461
+ };
462
+ // A stdio tool server is a child process; a command that returns without
463
+ // closing leaves it running.
464
+ await session.close();
465
+ closeSessions(cli);
466
+ // A signal during the close has written the last line already.
467
+ if (stopped)
468
+ return EXIT_OK;
469
+ ended = true;
470
+ write(settled.last);
471
+ return busy ? EXIT_TURN_IN_PROGRESS : 0;
472
+ }
473
+ //# sourceMappingURL=exec-json.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exec-json.js","sourceRoot":"","sources":["../../src/commands/exec-json.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,12 @@
1
1
  /**
2
- * `namzu run "<prompt>"` — headless one-shot. Runs a single prompt through
3
- * the same agent the TUI uses and prints the reply to stdout, for scripts
4
- * and CI. The prompt comes from
5
- * the arguments, or from stdin when piped. Status lines go to stderr (info,
6
- * suppressed by `--quiet`); only the answer hits stdout.
2
+ * `namzu exec "<prompt>"` — the headless one-shot. Runs a single prompt
3
+ * through the same agent the TUI uses, for scripts, CI and host UIs.
4
+ *
5
+ * By default it prints the reply to stdout. The prompt comes from the
6
+ * arguments, or from stdin when piped. Status lines go to stderr (info,
7
+ * suppressed by `--quiet`); only the answer hits stdout. With `--json` it
8
+ * streams one JSON event per line instead (`./exec-json.ts`). With
9
+ * `--output-schema <file>` the final answer is bound to that JSON Schema.
7
10
  *
8
11
  * Non-interactive, so there's no approval prompt — tools auto-run, but the
9
12
  * safety gate still hard-denies catastrophic commands. A one-shot is a
@@ -11,11 +14,9 @@
11
14
  * `NAMZU_HOME`, so `--continue` picks it up and `namzu drain` can finish a
12
15
  * turn it parked.
13
16
  *
14
- * Options are parsed, not spoken: this command joined every argument into the
15
- * prompt, so the flags its streaming sibling accepts — `--cwd` above all —
16
- * were read aloud to the model while the turn used this directory anyway. Both
17
- * commands now share one parser (`./run-flags.js`), because they are the same
18
- * one-shot differing only in how they print.
17
+ * Options are parsed, not spoken: both modes share one parser
18
+ * (`./exec-flags.js`), because they are the same one-shot differing only in
19
+ * how they print.
19
20
  */
20
21
  import type { CommandDef } from './types.js';
21
22
  /**
@@ -23,7 +24,7 @@ import type { CommandDef } from './types.js';
23
24
  *
24
25
  * Piped input used to be read only when there was no argument prompt, so
25
26
  *
26
- * cat notes.txt | namzu run "summarise this"
27
+ * cat notes.txt | namzu exec "summarise this"
27
28
  *
28
29
  * sent the model three words and silently dropped the file. Nothing reported
29
30
  * it: the turn succeeded, and the answer was about nothing. A pipe and a
@@ -37,5 +38,5 @@ import type { CommandDef } from './types.js';
37
38
  * Pure so it can be tested without a pipe; the reading happens in the handler.
38
39
  */
39
40
  export declare function composePrompt(fromArgs: string, piped: string): string;
40
- export declare const runCommand: CommandDef;
41
- //# sourceMappingURL=run.d.ts.map
41
+ export declare const execCommand: CommandDef;
42
+ //# sourceMappingURL=exec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../../src/commands/exec.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AA0CH,OAAO,KAAK,EAAE,UAAU,EAAsB,MAAM,YAAY,CAAA;AAEhE;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAMrE;AA0hBD,eAAO,MAAM,WAAW,EAAE,UAwHzB,CAAA"}