@illuminis/comprism 0.1.2 → 0.1.4

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 (131) hide show
  1. package/README.md +98 -36
  2. package/out/agent/command.d.ts +75 -4
  3. package/out/agent/command.js +220 -25
  4. package/out/agent/render.d.ts +17 -2
  5. package/out/agent/render.js +157 -14
  6. package/out/agent/session.d.ts +141 -2
  7. package/out/agent/session.js +735 -149
  8. package/out/commands/agents.d.ts +2 -0
  9. package/out/commands/agents.js +79 -0
  10. package/out/commands/ask.d.ts +1 -1
  11. package/out/commands/ask.js +78 -11
  12. package/out/commands/commands-thin.js +79 -17
  13. package/out/commands/config.d.ts +1 -0
  14. package/out/commands/config.js +138 -0
  15. package/out/commands/cost.d.ts +1 -0
  16. package/out/commands/cost.js +167 -0
  17. package/out/commands/hooks.d.ts +1 -0
  18. package/out/commands/hooks.js +83 -0
  19. package/out/commands/install.d.ts +44 -1
  20. package/out/commands/install.js +198 -4
  21. package/out/commands/instructions.d.ts +1 -0
  22. package/out/commands/instructions.js +113 -0
  23. package/out/commands/integrations.d.ts +3 -0
  24. package/out/commands/integrations.js +215 -0
  25. package/out/commands/jobs.d.ts +5 -0
  26. package/out/commands/jobs.js +157 -0
  27. package/out/commands/login.js +188 -36
  28. package/out/commands/memory.d.ts +3 -0
  29. package/out/commands/memory.js +113 -0
  30. package/out/commands/permissions.d.ts +1 -0
  31. package/out/commands/permissions.js +94 -0
  32. package/out/commands/plugins.d.ts +4 -0
  33. package/out/commands/plugins.js +192 -0
  34. package/out/commands/privacy.d.ts +1 -0
  35. package/out/commands/privacy.js +57 -0
  36. package/out/commands/providerKey.d.ts +32 -0
  37. package/out/commands/providerKey.js +108 -0
  38. package/out/commands/repl.d.ts +8 -1
  39. package/out/commands/repl.js +1207 -118
  40. package/out/commands/report.d.ts +39 -0
  41. package/out/commands/report.js +115 -0
  42. package/out/commands/review.d.ts +5 -0
  43. package/out/commands/review.js +223 -0
  44. package/out/commands/sessions.d.ts +23 -0
  45. package/out/commands/sessions.js +115 -0
  46. package/out/commands/settings.d.ts +3 -1
  47. package/out/commands/settings.js +18 -16
  48. package/out/commands/skills.d.ts +21 -0
  49. package/out/commands/skills.js +207 -0
  50. package/out/commands/unattended.d.ts +7 -0
  51. package/out/commands/unattended.js +351 -0
  52. package/out/commands/update.d.ts +1 -0
  53. package/out/commands/update.js +123 -0
  54. package/out/commands/worktrees.d.ts +5 -0
  55. package/out/commands/worktrees.js +186 -0
  56. package/out/executor/browser.d.ts +14 -0
  57. package/out/executor/browser.js +270 -0
  58. package/out/executor/diagnostics.d.ts +2 -0
  59. package/out/executor/diagnostics.js +181 -0
  60. package/out/executor/files.js +270 -40
  61. package/out/executor/git.js +42 -29
  62. package/out/executor/hooks.d.ts +42 -58
  63. package/out/executor/hooks.js +89 -182
  64. package/out/executor/index.d.ts +21 -5
  65. package/out/executor/index.js +160 -14
  66. package/out/executor/paths.d.ts +6 -1
  67. package/out/executor/paths.js +34 -6
  68. package/out/executor/sandbox.d.ts +40 -0
  69. package/out/executor/sandbox.js +299 -0
  70. package/out/executor/shell.d.ts +49 -4
  71. package/out/executor/shell.js +302 -56
  72. package/out/executor/toolservers.d.ts +20 -0
  73. package/out/executor/toolservers.js +189 -0
  74. package/out/executor/worktree.d.ts +9 -0
  75. package/out/executor/worktree.js +119 -0
  76. package/out/graph/read-python.js +2 -1
  77. package/out/lib/attach.d.ts +56 -12
  78. package/out/lib/attach.js +230 -63
  79. package/out/lib/clipboard.d.ts +23 -0
  80. package/out/lib/clipboard.js +182 -0
  81. package/out/lib/commandlist.d.ts +20 -0
  82. package/out/lib/commandlist.js +58 -0
  83. package/out/lib/decision.d.ts +22 -0
  84. package/out/lib/decision.js +50 -0
  85. package/out/lib/fingerprint.d.ts +25 -0
  86. package/out/lib/fingerprint.js +58 -0
  87. package/out/lib/gateway.d.ts +186 -2
  88. package/out/lib/gateway.js +59 -4
  89. package/out/lib/history.d.ts +24 -0
  90. package/out/lib/history.js +137 -0
  91. package/out/lib/ide.d.ts +19 -0
  92. package/out/lib/ide.js +131 -0
  93. package/out/lib/keyboard.d.ts +95 -0
  94. package/out/lib/keyboard.js +383 -0
  95. package/out/lib/machine.d.ts +21 -0
  96. package/out/lib/machine.js +91 -0
  97. package/out/lib/notify.d.ts +4 -0
  98. package/out/lib/notify.js +52 -0
  99. package/out/lib/output.d.ts +48 -0
  100. package/out/lib/output.js +108 -0
  101. package/out/lib/project-ops.d.ts +19 -0
  102. package/out/lib/project-ops.js +146 -0
  103. package/out/lib/project.d.ts +28 -0
  104. package/out/lib/project.js +114 -0
  105. package/out/lib/prompt.js +15 -2
  106. package/out/lib/queue.d.ts +13 -0
  107. package/out/lib/queue.js +116 -0
  108. package/out/lib/readiness.d.ts +19 -0
  109. package/out/lib/readiness.js +170 -1
  110. package/out/lib/self.d.ts +23 -0
  111. package/out/lib/self.js +124 -0
  112. package/out/lib/sessions.d.ts +19 -0
  113. package/out/lib/sessions.js +221 -0
  114. package/out/lib/stdin.d.ts +32 -0
  115. package/out/lib/stdin.js +117 -0
  116. package/out/lib/store.d.ts +40 -0
  117. package/out/lib/store.js +138 -0
  118. package/out/lib/sync.d.ts +18 -0
  119. package/out/lib/sync.js +81 -0
  120. package/out/lib/ui.d.ts +2 -4
  121. package/out/lib/ui.js +31 -25
  122. package/out/lib/voice.js +24 -0
  123. package/out/postinstall.js +42 -14
  124. package/out/providers/anthropic.d.ts +22 -0
  125. package/out/providers/anthropic.js +80 -0
  126. package/out/providers/index.d.ts +8 -0
  127. package/out/providers/index.js +83 -0
  128. package/out/providers/openai.d.ts +11 -0
  129. package/out/providers/openai.js +57 -0
  130. package/out/thin.js +609 -21
  131. package/package.json +9 -49
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.AGENT_HELP = void 0;
36
+ exports.AGENT_HELP = exports.MODES = void 0;
37
37
  exports.runAgent = runAgent;
38
38
  /**
39
39
  * `comprism work` — the coding agent, from a terminal.
@@ -56,8 +56,11 @@ exports.runAgent = runAgent;
56
56
  const fs = __importStar(require("fs"));
57
57
  const readline = __importStar(require("readline"));
58
58
  const connection_1 = require("../lib/connection");
59
+ const project_1 = require("../lib/project");
59
60
  const session_1 = require("./session");
60
61
  const ui = __importStar(require("./render"));
62
+ const output_1 = require("../lib/output");
63
+ const self_1 = require("../lib/self");
61
64
  /** The WebSocket the session needs is a global from Node 22.
62
65
  *
63
66
  * Checked here with a message somebody can act on. Without it the failure is
@@ -70,7 +73,7 @@ function requireWebSocket() {
70
73
  ui.dim(` You are on ${process.version}. Upgrade Node and try again.\n`));
71
74
  return false;
72
75
  }
73
- const MODES = ["read_only", "approve_writes", "auto_edit", "full_auto"];
76
+ exports.MODES = ["read_only", "approve_writes", "auto_edit", "full_auto"];
74
77
  /**
75
78
  * Start a job, hand the terminal back, and keep working.
76
79
  *
@@ -105,28 +108,83 @@ async function runDetached(args) {
105
108
  const log = fs.openSync(logPath, "a");
106
109
  // Detached, with its own process group, so closing the terminal does not take
107
110
  // the job with it. `unref` is what actually lets this process exit.
108
- const child = spawn(process.execPath, [
109
- process.argv[1] ?? "", "agent",
111
+ const child = spawn(...(0, self_1.selfLaunch)([
112
+ "agent",
110
113
  ...args.request,
111
114
  "--mode", mode, "--yes",
112
115
  ...(args.model ? ["--model", args.model] : []),
113
116
  ...(args.pin ? ["--pin"] : []),
114
117
  ...(args.maxSpend ? ["--max-spend", String(args.maxSpend)] : []),
118
+ ...(args.timeout ? ["--timeout", String(args.timeout)] : []),
115
119
  ...(args.allow ?? []).flatMap((c) => ["--allow", c]),
116
120
  ...(args.cwd ? ["--cwd", args.cwd] : []),
117
- ], { detached: true, stdio: ["ignore", log, log], env: { ...process.env, NO_COLOR: "1" } });
121
+ ...(args.addFolders ?? []).flatMap((f) => ["--add-folder", f]),
122
+ ]), {
123
+ detached: true, stdio: ["ignore", log, log],
124
+ // Marked, so the job is recorded as a background job and its log can be
125
+ // found again by `comprism jobs attach` (manual 5.14).
126
+ env: { ...process.env, NO_COLOR: "1", COMPRISM_BACKGROUND: "1", COMPRISM_JOB_LOG: logPath },
127
+ });
118
128
  child.unref();
119
129
  process.stdout.write(ui.green(` Started in the background as process ${child.pid}.\n`)
130
+ + ui.dim(" comprism jobs lists it; comprism jobs attach <job> watches it.\n")
120
131
  + ui.dim(` Follow it: tail -f ${logPath}\n`)
121
132
  + ui.dim(" It keeps working while you do something else. This machine has "
122
133
  + "to stay awake: the files are here, so the work is too.\n"));
123
134
  return 0;
124
135
  }
125
136
  async function runAgent(args) {
137
+ const output = args.output;
138
+ const json = output?.format === "json";
139
+ const streaming = output?.format === "stream";
140
+ // A stream is lines the service built, printed as they come (manual 10.4).
141
+ // If the program reading it goes away, the job is stopped and the exit is
142
+ // 141, with nothing said about it.
143
+ let pipeClosed = false;
144
+ let finishedLine = false;
145
+ let stopJob = null;
146
+ const emit = (items) => {
147
+ for (const item of items) {
148
+ if (pipeClosed)
149
+ return;
150
+ if (item.event === "job_finished")
151
+ finishedLine = true;
152
+ process.stdout.write(JSON.stringify(item) + "\n");
153
+ }
154
+ };
155
+ if (streaming) {
156
+ process.stdout.on("error", (e) => {
157
+ if (e.code !== "EPIPE")
158
+ return;
159
+ pipeClosed = true;
160
+ stopJob?.();
161
+ });
162
+ }
163
+ /** An ending the service never saw: its number, and with --output json the
164
+ * result object in its published shape (manual 10.3, Appendix B). */
165
+ const ended = (reason, why) => {
166
+ if (json)
167
+ (0, output_1.printJson)((0, output_1.localResult)(reason, why));
168
+ if (streaming)
169
+ emit([{ event: "job_finished", ...(0, output_1.localResult)(reason, why) }]);
170
+ return (0, output_1.exitFor)(reason);
171
+ };
172
+ // A folder that does not exist is refused before anything runs or is charged
173
+ // (manual 2.1, exit 2 in Appendix B).
174
+ const folders = [];
175
+ for (const raw of [args.cwd ?? process.cwd(), ...(args.addFolders ?? [])]) {
176
+ const found = (0, project_1.checkFolder)(raw);
177
+ if (!found.ok) {
178
+ process.stderr.write(ui.red(` ${found.why}`) + ui.dim(" Nothing ran and nothing was charged.\n"));
179
+ return 2;
180
+ }
181
+ folders.push(found.path);
182
+ }
183
+ const [startFolder, ...added] = folders;
126
184
  if (!requireWebSocket())
127
185
  return 1;
128
186
  if (args.background)
129
- return runDetached(args);
187
+ return runDetached({ ...args, cwd: startFolder, addFolders: added });
130
188
  const connection = (0, connection_1.readConnection)();
131
189
  if (!connection?.url) {
132
190
  process.stderr.write(
@@ -135,7 +193,7 @@ async function runAgent(args) {
135
193
  // brand new user is given was a dead end.
136
194
  ui.red(" Not signed in.") +
137
195
  ui.dim(" Run `comprism login` first.\n"));
138
- return 1;
196
+ return ended("signed_out", "Not signed in. Run comprism login first.");
139
197
  }
140
198
  // The machine credential, not the session token. The session token belongs to
141
199
  // a browser sign-in and is short lived; this is the long-lived credential
@@ -146,14 +204,28 @@ async function runAgent(args) {
146
204
  if (!credential) {
147
205
  process.stderr.write(ui.red(" This machine has no workspace key.") +
148
206
  ui.dim(" Run `comprism connect` again to mint one.\n"));
149
- return 1;
207
+ return ended("signed_out", "This machine has no workspace key. Run comprism connect again.");
150
208
  }
151
- const root = fs.realpathSync(args.cwd ?? process.cwd());
152
- const mode = args.mode ?? "approve_writes";
153
- if (!MODES.includes(mode)) {
209
+ const project = (0, project_1.resolveProject)(startFolder, added);
210
+ const root = project.root;
211
+ // Absent means the settings decide (manual 2.10): the service resolves the
212
+ // mode from the local and project settings files and your account.
213
+ const mode = args.mode;
214
+ if (mode !== undefined && !exports.MODES.includes(mode)) {
154
215
  process.stderr.write(ui.red(` ${mode} is not a permission mode.`) +
155
- ui.dim(` One of: ${MODES.join(", ")}\n`));
156
- return 1;
216
+ ui.dim(` One of: ${exports.MODES.join(", ")}\n`));
217
+ return ended("usage", `${mode} is not a permission mode.`);
218
+ }
219
+ // `--sandbox` never runs without one (manual 4.12): refused before anything
220
+ // runs or is charged.
221
+ if (args.sandbox) {
222
+ const { availability } = await Promise.resolve().then(() => __importStar(require("../executor/sandbox")));
223
+ const found = availability();
224
+ if (!found.system) {
225
+ process.stderr.write(ui.red(` --sandbox cannot start: ${found.why}.`)
226
+ + ui.dim(" Nothing ran and nothing was charged.\n"));
227
+ return 1;
228
+ }
157
229
  }
158
230
  const request = args.request.join(" ").trim();
159
231
  if (!request && !args.resume) {
@@ -163,33 +235,99 @@ async function runAgent(args) {
163
235
  // Headless when asked for, and also when there is no terminal at all: piped
164
236
  // into a script, nobody is there to answer an approval, and pretending
165
237
  // otherwise would hang the pipeline until it timed out.
166
- const headless = Boolean(args.yes) || !process.stdin.isTTY;
238
+ //
239
+ // Standard input that is a pipe is material, never answers (manual 3.9):
240
+ // questions then go to the terminal the caller opened, and with none the
241
+ // job is unattended.
242
+ const questions = process.stdin.isTTY
243
+ ? process.stdin : args.keyboard ?? null;
244
+ const headless = Boolean(args.yes) || !questions;
245
+ // ONE reader for the whole job when nobody lent a keyboard: it carries what
246
+ // is typed while the agent works, and it answers questions and approvals.
247
+ // Two readers on one keyboard divide the typing, so an answer also arrived
248
+ // as a correction to the job.
249
+ let steering = null;
250
+ let waiting = null;
251
+ const ownPrompt = (question) => new Promise((resolve) => {
252
+ process.stdout.write(` ${question} `);
253
+ waiting = resolve;
254
+ });
255
+ const lent = args.confirm || headless ? {} : {
256
+ prompt: ownPrompt,
257
+ confirm: async (question) => /^y(es)?$/i.test(((await ownPrompt(question)) ?? "").trim()),
258
+ };
259
+ // With standard output going to a script, everything the job says on the
260
+ // way goes to standard error, and only the result goes to standard output
261
+ // (manual 10.2). `--quiet` drops the progress altogether.
262
+ const toErr = output ? (0, output_1.progressToErr)(output) : false;
263
+ const write = output?.quiet || streaming ? () => undefined
264
+ : toErr ? (s) => { process.stderr.write(s); } : (s) => { process.stdout.write(s); };
167
265
  const session = new session_1.TerminalSession({
168
266
  baseUrl: connection.url,
169
267
  credential,
170
268
  root,
269
+ project,
171
270
  permissionMode: mode,
172
271
  planOnly: Boolean(args.plan),
173
272
  planApproved: Boolean(args.approvePlan),
174
273
  model: args.model,
175
274
  pinModel: Boolean(args.pin),
176
275
  maxSpendUsd: args.maxSpend,
276
+ maxSteps: args.maxSteps,
277
+ maxMinutes: args.maxMinutes,
278
+ effort: args.effort,
279
+ sandbox: Boolean(args.sandbox),
280
+ commandTimeoutS: args.timeout,
281
+ issue: args.issue,
282
+ team: args.team,
283
+ review: args.review,
284
+ keepProcesses: Boolean(args.keepProcesses),
177
285
  approvedCommands: args.allow ?? [],
178
286
  attachmentIds: args.attachments ?? [],
287
+ leftOut: args.leftOut ?? [],
179
288
  headless,
180
289
  confirm: args.confirm,
290
+ prompt: args.prompt,
291
+ ...lent,
181
292
  resumeJobId: args.resume,
182
293
  continuesJob: args.continuesJob,
294
+ conversationId: args.conversationId,
183
295
  withoutMap: Boolean(args.noMap),
184
- });
296
+ ...(args.answerSchema ? { answerSchema: args.answerSchema } : {}),
297
+ ...(args.queuedJob ? { queuedJob: args.queuedJob } : {}),
298
+ ...(args.settingsConfig ? { settingsConfig: args.settingsConfig } : {}),
299
+ noPersonal: Boolean(args.noPersonal),
300
+ ...(streaming ? { onStream: emit } : {}),
301
+ }, write);
302
+ stopJob = () => session.cancel();
185
303
  // Ctrl+C stops the JOB, not the process. Killing the process would leave the
186
304
  // job running on the server with nothing watching it, and whatever the agent
187
305
  // had started on this machine would carry on unsupervised.
188
- const onInterrupt = () => session.cancel();
306
+ let interrupted = false;
307
+ const onInterrupt = () => {
308
+ interrupted = true;
309
+ // Ctrl+C at a question answers it as stopped, then stops the job.
310
+ const w = waiting;
311
+ waiting = null;
312
+ if (w) {
313
+ process.stdout.write("\n");
314
+ w(null);
315
+ }
316
+ session.cancel();
317
+ };
189
318
  process.on("SIGINT", onInterrupt);
319
+ session.full = Boolean(args.fullView);
190
320
  args.onStarted?.({
191
321
  cancel: () => session.cancel(),
192
322
  steer: (text) => session.steer(text),
323
+ pause: () => session.pause(),
324
+ carryOn: (text) => session.carryOn(text),
325
+ isPaused: () => session.paused,
326
+ queue: (clear) => session.queue(clear),
327
+ setFull: (on) => { session.full = on; },
328
+ jobId: () => session.jobId,
329
+ helpers: () => [...session.helpers.values()],
330
+ stopHelper: (id) => session.stopHelper(id),
193
331
  });
194
332
  // Anything typed while it works. Not a prompt, deliberately: the run is
195
333
  // printing, and a prompt competing with it for the same lines is unreadable.
@@ -198,10 +336,15 @@ async function runAgent(args) {
198
336
  // `confirm` is that one component owns the terminal; opening a reader here as
199
337
  // well would put the same two owners back on it by another door, and the
200
338
  // caller is the one already reading what gets typed.
201
- let steering = null;
202
339
  if (!headless && !args.confirm) {
203
- steering = readline.createInterface({ input: process.stdin, terminal: false });
340
+ steering = readline.createInterface({ input: questions, terminal: false });
204
341
  steering.on("line", (line) => {
342
+ const w = waiting;
343
+ if (w) {
344
+ waiting = null;
345
+ w(line);
346
+ return;
347
+ }
205
348
  const text = line.trim();
206
349
  if (text)
207
350
  session.steer(text);
@@ -210,14 +353,54 @@ async function runAgent(args) {
210
353
  try {
211
354
  const result = await session.run(request);
212
355
  args.onFinished?.(result);
213
- // A shell needs to know whether it worked. Anything other than finishing
214
- // cleanly is a non-zero exit, so `comprism work ... && next-thing` behaves
215
- // the way a person expects.
216
- return result.outcome === "finished" ? 0 : 1;
356
+ // A job on its own is its session, and it has ended (manual 7.3).
357
+ if (!args.keepProcesses && args.conversationId) {
358
+ const { review } = await Promise.resolve().then(() => __importStar(require("../commands/review")));
359
+ await review("session_ended", { session_id: args.conversationId }).catch(() => undefined);
360
+ }
361
+ // How it ended is the service's reason word; the number comes from the
362
+ // table the service sent with it (manual 10.6, Appendix B). The only
363
+ // endings decided here are the ones the service could not see: a dropped
364
+ // connection with an action in doubt (8.9), Ctrl+C, and never reaching it.
365
+ const reason = result.outcome === "unknown" ? "unknown"
366
+ : interrupted ? "interrupted"
367
+ : result.ending?.reason ?? result.refusalReason
368
+ ?? (result.outcome === "finished" ? "done" : "incomplete");
369
+ if (pipeClosed)
370
+ return (0, output_1.exitFor)("output_closed", result.exitStatus);
371
+ const code = (0, output_1.exitFor)(reason, result.exitStatus);
372
+ if (streaming) {
373
+ // A job refused before it started has sent no stream, so its end is
374
+ // the service's result for the refusal.
375
+ if (!finishedLine) {
376
+ emit([{ event: "job_finished", ...(result.result ?? (0, output_1.localResult)(reason, result.detail ?? reason)) }]);
377
+ }
378
+ if (code !== 0)
379
+ process.stderr.write(` ${result.ending?.line ?? result.detail ?? reason}\n`);
380
+ }
381
+ else if (json) {
382
+ (0, output_1.printJson)(result.result && reason !== "unknown" && !interrupted
383
+ ? result.result : (0, output_1.localResult)(reason, result.detail ?? reason));
384
+ }
385
+ else if (toErr) {
386
+ // The final summary, and nothing else, on standard output (10.2).
387
+ const summary = result.ending?.line ?? result.detail ?? "";
388
+ if (summary)
389
+ process.stdout.write(`${summary}\n`);
390
+ if (result.text.trim() && result.text.trim() !== summary)
391
+ process.stdout.write(`${result.text.trim()}\n`);
392
+ }
393
+ if (code !== 0 && output?.quiet) {
394
+ // A number other than 0 comes with a one line reason on standard error.
395
+ process.stderr.write(` ${result.ending?.line ?? result.detail ?? reason}\n`);
396
+ }
397
+ return code;
217
398
  }
218
399
  catch (err) {
400
+ // The live connection never opened: the service could not be reached
401
+ // (manual 10.14, exit 6).
219
402
  process.stderr.write(ui.red(` ${err.message}\n`));
220
- return 1;
403
+ return ended("unreachable", err.message);
221
404
  }
222
405
  finally {
223
406
  process.off("SIGINT", onInterrupt);
@@ -231,13 +414,15 @@ ${ui.bold("comprism work")} — a coding agent in your terminal
231
414
  comprism work "add a test for the parser and make it pass"
232
415
 
233
416
  ${ui.bold("What it does")}
234
- Reads your project, changes files, runs commands and runs your tests, and
235
- shows you every change before it makes it. Each step is routed to whichever
417
+ Reads your project, changes files, runs commands and runs your tests. It
418
+ shows you every change as it makes it, asks before deleting a file or
419
+ running a command, and can undo the whole job. Each step is routed to whichever
236
420
  model finishes the work for least, and the receipt at the end says what it
237
421
  cost.
238
422
 
239
423
  ${ui.bold("Options")}
240
424
  --mode <mode> read_only, approve_writes (default), auto_edit, full_auto
425
+ --worktree <name> work in a separate copy of the repository on its own branch
241
426
  --plan work out what it would do and change nothing
242
427
  --approve-plan you read the plan and want it built. Files change without
243
428
  being asked about one at a time; commands still ask
@@ -245,12 +430,22 @@ ${ui.bold("Options")}
245
430
  price the saving against it. It may still move you up
246
431
  --pin run --model and nothing else, whatever it would prefer
247
432
  --max-spend <usd> stop at this much rather than running on
433
+ --max-steps <n> stop after this many steps
434
+ --max-minutes <n> start no new step after this many minutes
435
+ --effort <level> low, medium or high: how carefully the model thinks
436
+ --sandbox run commands in the operating system's sandbox
437
+ --timeout <secs> time limit for each command, two minutes unless set
438
+ --issue <n> start from GitHub issue n; its text is information only
439
+ --team <name> lead the team defined in .completionprism/teams/<name>.md
248
440
  --allow "<cmd>" approve one exact command up front, repeatable. The only
249
441
  way an unattended run can verify its own work
250
442
  --yes never ask; anything needing approval is refused instead
251
443
  --background start it and get your terminal back; it keeps working
252
444
  --resume <job> carry on from a job you already started
253
445
  --cwd <path> work in this folder rather than the current one
446
+ --cloud run it on a CompletionPrism worker with a copy of the
447
+ repository; comprism --resume <session> brings it back
448
+ --add-folder <path> also allow this folder, repeatable
254
449
  --no-map do not use the code map for this job; read the files
255
450
 
256
451
  ${ui.bold("While it runs")}
@@ -26,6 +26,11 @@ export declare const red: (t: string) => string;
26
26
  export declare const green: (t: string) => string;
27
27
  export declare const yellow: (t: string) => string;
28
28
  export declare const gray: (t: string) => string;
29
+ /** The brand's violet, for model names and the receipt's label. */
30
+ export declare const violet: (t: string) => string;
31
+ /** `claude-haiku-4-5` as a person says it, `Claude Haiku 4.5`. Other vendors'
32
+ * ids are shown as they arrive: a wrong guess at a name is worse than the id. */
33
+ export declare function modelName(id: string): string;
29
34
  /** Money, at the precision a person can act on.
30
35
  *
31
36
  * Four decimal places below a cent, because a coding step often costs less
@@ -36,6 +41,8 @@ export declare function duration(ms: number | null | undefined): string;
36
41
  /** One action, as it happens. A word as well as a color, so this still reads
37
42
  * when piped to a file. */
38
43
  export declare function action(name: string, target: string, ok: boolean, ms?: number): string;
44
+ /** A connected tool as people write it, `server.tool` (manual 9.10). */
45
+ export declare function actionName(name: string): string;
39
46
  /** The share of a step's context the provider served from its cache, or null
40
47
  * when it reported no counts. Anthropic counts cached tokens OUTSIDE the input
41
48
  * figure, so the whole context is the three counts added together. */
@@ -44,7 +51,7 @@ export declare function reusePct(tokensIn: number | null | undefined, cacheRead:
44
51
  * provider had already seen. The last figure is the one study 005 found
45
52
  * missing from our receipt: without it nobody could tell a warm step from a
46
53
  * cold one, and every step was cold. */
47
- export declare function step(index: number, model: string, usd: number | null, ms: number | null, reused?: number | null): string;
54
+ export declare function step(index: number, model: string, usd: number | null, ms: number | null, reused?: number | null, reason?: string): string;
48
55
  /** The task list, reprinted whenever it changes.
49
56
  *
50
57
  * Reprinted rather than redrawn in place: what the agent intended at each point
@@ -54,12 +61,20 @@ export declare function todos(items: Array<{
54
61
  content: string;
55
62
  status: string;
56
63
  }>): string;
64
+ /** A question from the agent, or the plan question (manual 4.2, 4.3). The
65
+ * wording is the service's; this only lays it out. */
66
+ export declare function question(q: string, options: string[]): string;
57
67
  /** A change, before it is made.
58
68
  *
59
69
  * Full text for a small edit and a summary for a large one. Pasting four
60
70
  * hundred lines into a terminal is not review, it is a wall somebody presses
61
71
  * through, and an approval people press through protects nobody. */
62
- export declare function diff(name: string, input: Record<string, unknown>): string;
72
+ export declare function diff(name: string, input: Record<string, unknown>, withHead?: boolean): string;
73
+ /** What was stopped when a session ended, one line each (manual 5.13). */
74
+ export declare function stoppedLines(stopped: string[]): string;
75
+ /** The first line of a finished job, as the service wrote it (manual 5.15).
76
+ * Colored by its first word only; the words are the service's. */
77
+ export declare function ending(line: string, detail: string | null | undefined): string;
63
78
  /** How the job ended, in the words a person reads. */
64
79
  export declare function outcome(o: string, detail: string | null | undefined): string;
65
80
  /** One model's share of a job, as our server reported it. */