@smithers-orchestrator/cli 0.20.3 → 0.20.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smithers-orchestrator/cli",
3
- "version": "0.20.3",
3
+ "version": "0.20.4",
4
4
  "description": "Smithers command-line interface, MCP server, and local workflow tools",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -32,21 +32,21 @@
32
32
  "picocolors": "^1.1.1",
33
33
  "react": "^19.2.5",
34
34
  "zod": "^4.3.6",
35
- "@smithers-orchestrator/accounts": "0.20.3",
36
- "@smithers-orchestrator/agents": "0.20.3",
37
- "@smithers-orchestrator/components": "0.20.3",
38
- "@smithers-orchestrator/db": "0.20.3",
39
- "@smithers-orchestrator/devtools": "0.20.3",
40
- "@smithers-orchestrator/driver": "0.20.3",
41
- "@smithers-orchestrator/engine": "0.20.3",
42
- "@smithers-orchestrator/errors": "0.20.3",
43
- "@smithers-orchestrator/memory": "0.20.3",
44
- "@smithers-orchestrator/observability": "0.20.3",
45
- "@smithers-orchestrator/openapi": "0.20.3",
46
- "@smithers-orchestrator/protocol": "0.20.3",
47
- "@smithers-orchestrator/scheduler": "0.20.3",
48
- "@smithers-orchestrator/server": "0.20.3",
49
- "@smithers-orchestrator/time-travel": "0.20.3"
35
+ "@smithers-orchestrator/accounts": "0.20.4",
36
+ "@smithers-orchestrator/agents": "0.20.4",
37
+ "@smithers-orchestrator/components": "0.20.4",
38
+ "@smithers-orchestrator/db": "0.20.4",
39
+ "@smithers-orchestrator/devtools": "0.20.4",
40
+ "@smithers-orchestrator/driver": "0.20.4",
41
+ "@smithers-orchestrator/errors": "0.20.4",
42
+ "@smithers-orchestrator/observability": "0.20.4",
43
+ "@smithers-orchestrator/protocol": "0.20.4",
44
+ "@smithers-orchestrator/scheduler": "0.20.4",
45
+ "@smithers-orchestrator/engine": "0.20.4",
46
+ "@smithers-orchestrator/server": "0.20.4",
47
+ "@smithers-orchestrator/time-travel": "0.20.4",
48
+ "@smithers-orchestrator/memory": "0.20.4",
49
+ "@smithers-orchestrator/openapi": "0.20.4"
50
50
  },
51
51
  "devDependencies": {
52
52
  "@types/bun": "latest",
@@ -91,7 +91,7 @@ const AGENT_VARIANTS = [
91
91
  displayName: "Claude Sonnet",
92
92
  constructor: {
93
93
  importName: "ClaudeCodeAgent",
94
- expr: 'new SmithersClaudeCodeAgent({ model: "claude-sonnet-4-6", cwd: process.cwd() })',
94
+ expr: 'new SmithersClaudeCodeAgent({ model: "claude-sonnet-4-7", cwd: process.cwd() })',
95
95
  },
96
96
  },
97
97
  ];
@@ -108,7 +108,7 @@ const TIER_PREFERENCES = {
108
108
  const CONSTRUCTORS = {
109
109
  claude: {
110
110
  importName: "ClaudeCodeAgent",
111
- expr: 'new SmithersClaudeCodeAgent({ model: "claude-opus-4-6", cwd: process.cwd() })',
111
+ expr: 'new SmithersClaudeCodeAgent({ model: "claude-opus-4-7", cwd: process.cwd() })',
112
112
  },
113
113
  codex: {
114
114
  importName: "CodexAgent",
@@ -8,6 +8,7 @@ const EVENT_CATEGORY_BY_TYPE = {
8
8
  RunAutoResumeSkipped: "run",
9
9
  RunStarted: "run",
10
10
  RunStatusChanged: "run",
11
+ RunStateChanged: "run",
11
12
  RunFinished: "run",
12
13
  RunFailed: "run",
13
14
  RunCancelled: "run",
@@ -49,6 +50,7 @@ const EVENT_CATEGORY_BY_TYPE = {
49
50
  RevertFinished: "revert",
50
51
  TimeTravelStarted: "revert",
51
52
  TimeTravelFinished: "revert",
53
+ TimeTravelJumped: "revert",
52
54
  WorkflowReloadDetected: "workflow",
53
55
  WorkflowReloaded: "workflow",
54
56
  WorkflowReloadFailed: "workflow",
@@ -67,6 +69,9 @@ const EVENT_CATEGORY_BY_TYPE = {
67
69
  TimerCreated: "timer",
68
70
  TimerFired: "timer",
69
71
  TimerCancelled: "timer",
72
+ AgentTraceEvent: "agent",
73
+ AgentTraceSummary: "agent",
74
+ AgentSessionEvent: "agent",
70
75
  };
71
76
  const CATEGORY_ALIASES = {
72
77
  agent: "agent",
package/src/find-db.js CHANGED
@@ -15,16 +15,16 @@ import { SmithersError } from "@smithers-orchestrator/errors";
15
15
  export function findSmithersDb(from) {
16
16
  let dir = resolve(from ?? process.cwd());
17
17
  const root = resolve("/");
18
- while (true) {
18
+ while (dir !== root) {
19
19
  const candidate = resolve(dir, "smithers.db");
20
20
  if (existsSync(candidate))
21
21
  return candidate;
22
- const parent = dirname(dir);
23
- if (parent === dir || dir === root) {
24
- throw new SmithersError("CLI_DB_NOT_FOUND", "No smithers.db found. Run this command from a directory containing a smithers.db, or use 'smithers up <workflow>' to start a run first.");
25
- }
26
- dir = parent;
22
+ dir = dirname(dir);
27
23
  }
24
+ const rootCandidate = resolve(root, "smithers.db");
25
+ if (existsSync(rootCandidate))
26
+ return rootCandidate;
27
+ throw new SmithersError("CLI_DB_NOT_FOUND", "No smithers.db found. Run this command from a directory containing a smithers.db, or use 'smithers up <workflow>' to start a run first.");
28
28
  }
29
29
  /**
30
30
  * @param {number} ms
package/src/index.js CHANGED
@@ -2301,10 +2301,10 @@ let lastDevtoolsCommandOutcome;
2301
2301
  * friendly typed error the helper already wrote to stderr (finding #2).
2302
2302
  *
2303
2303
  * @param {"tree"|"diff"|"output"|"rewind"} cmd
2304
- * @param {{ args: any; options: any; ok: (d?: unknown) => unknown }} c
2304
+ * @param {{ args: any; options: any }} c
2305
2305
  * @param {() => Promise<number>} handler
2306
2306
  */
2307
- async function runDevtoolsCommandWithTelemetry(cmd, c, handler) {
2307
+ async function* runDevtoolsCommandWithTelemetry(cmd, c, handler) {
2308
2308
  const startedAt = Date.now();
2309
2309
  let exitCode = 0;
2310
2310
  try {
@@ -2362,9 +2362,8 @@ async function runDevtoolsCommandWithTelemetry(cmd, c, handler) {
2362
2362
  // best-effort metrics.
2363
2363
  }
2364
2364
  }
2365
- // Return c.ok(undefined) so incur does not emit an additional
2366
- // envelope on stdout (finding #2).
2367
- return c.ok(undefined);
2365
+ // This is an empty stream so Incur does not emit an additional envelope
2366
+ // or framework CTA on stdout after the helper has already written output.
2368
2367
  }
2369
2368
 
2370
2369
  /**
@@ -3429,8 +3428,8 @@ const cli = Cli.create({
3429
3428
  // =========================================================================
3430
3429
  // smithers inspect <run_id>
3431
3430
  // =========================================================================
3432
- .command("inspect", {
3433
- description: "Output detailed state of a run: steps, agents, approvals, and outputs.",
3431
+ .command("inspect", {
3432
+ description: "Output detailed run state, including steps, agents, approvals, and outputs.",
3434
3433
  args: inspectArgs,
3435
3434
  options: inspectOptions,
3436
3435
  alias: { watch: "w", interval: "i" },
@@ -4356,8 +4355,8 @@ const cli = Cli.create({
4356
4355
  // =========================================================================
4357
4356
  // smithers timetravel <workflow>
4358
4357
  // =========================================================================
4359
- .command("timetravel", {
4360
- description: "Time-travel to a previous task state: revert filesystem, reset DB, and optionally resume.",
4358
+ .command("timetravel", {
4359
+ description: "Time-travel to a previous task state by reverting filesystem state, resetting DB state, and optionally resuming.",
4361
4360
  args: workflowArgs,
4362
4361
  options: z.object({
4363
4362
  runId: z.string().describe("Run ID"),
@@ -4641,7 +4640,7 @@ const cli = Cli.create({
4641
4640
  // rewrites raw `--json` → `-j` for these commands so it lands as a
4642
4641
  // command option, not a format directive.
4643
4642
  alias: { json: "j" },
4644
- async run(c) {
4643
+ run(c) {
4645
4644
  return runDevtoolsCommandWithTelemetry("tree", c, async () => {
4646
4645
  const { runTreeOnce, runTreeWatch } = await import("./tree.js");
4647
4646
  const { adapter, cleanup } = await findAndOpenDb();
@@ -4707,7 +4706,7 @@ const cli = Cli.create({
4707
4706
  color: z.enum(["auto", "always", "never"]).default("auto").describe("Colorize output"),
4708
4707
  }),
4709
4708
  alias: { json: "j" },
4710
- async run(c) {
4709
+ run(c) {
4711
4710
  return runDevtoolsCommandWithTelemetry("diff", c, async () => {
4712
4711
  const { runDiffOnce } = await import("./diff.js");
4713
4712
  const { adapter, cleanup } = await findAndOpenDb();
@@ -4746,7 +4745,7 @@ const cli = Cli.create({
4746
4745
  pretty: z.boolean().default(false).describe("Schema-ordered render"),
4747
4746
  }),
4748
4747
  alias: { json: "j" },
4749
- async run(c) {
4748
+ run(c) {
4750
4749
  return runDevtoolsCommandWithTelemetry("output", c, async () => {
4751
4750
  const { runOutputOnce } = await import("./output.js");
4752
4751
  const { adapter, cleanup } = await findAndOpenDb();
@@ -4782,7 +4781,7 @@ const cli = Cli.create({
4782
4781
  json: z.boolean().default(false).describe("Emit JumpResult JSON"),
4783
4782
  }),
4784
4783
  alias: { json: "j" },
4785
- async run(c) {
4784
+ run(c) {
4786
4785
  return runDevtoolsCommandWithTelemetry("rewind", c, async () => {
4787
4786
  const { runRewindOnce } = await import("./rewind.js");
4788
4787
  const { adapter, cleanup } = await findAndOpenDb();
@@ -5193,6 +5192,54 @@ function argvRequestsJsonMode(argv) {
5193
5192
  }
5194
5193
  return false;
5195
5194
  }
5195
+ /**
5196
+ * Some commands own stdout completely and promise a raw JSON document even
5197
+ * without `--format json`. Run those before Incur can append framework CTAs
5198
+ * such as the stale-skills reminder, which would make stdout unparsable.
5199
+ *
5200
+ * @param {string[]} argv
5201
+ * @returns {boolean}
5202
+ */
5203
+ function runRawJsonAgentCommandIfMatched(argv) {
5204
+ const positionals = [];
5205
+ let jsonOutput = false;
5206
+ for (let index = 0; index < argv.length; index++) {
5207
+ const arg = argv[index];
5208
+ if (arg === "--json") {
5209
+ jsonOutput = true;
5210
+ continue;
5211
+ }
5212
+ if (arg === "--format") {
5213
+ if (argv[index + 1] !== "json") {
5214
+ return false;
5215
+ }
5216
+ jsonOutput = true;
5217
+ index += 1;
5218
+ continue;
5219
+ }
5220
+ if (arg === "--format=json") {
5221
+ jsonOutput = true;
5222
+ continue;
5223
+ }
5224
+ if (arg.startsWith("-")) {
5225
+ return false;
5226
+ }
5227
+ positionals.push(arg);
5228
+ }
5229
+ if (positionals.length !== 2 || positionals[0] !== "agents") {
5230
+ return false;
5231
+ }
5232
+ if (positionals[1] === "capabilities") {
5233
+ process.stdout.write(`${JSON.stringify(getCliAgentCapabilityReport(), null, 2)}\n`);
5234
+ process.exit(0);
5235
+ }
5236
+ if (positionals[1] === "doctor" && jsonOutput) {
5237
+ const report = getCliAgentCapabilityDoctorReport();
5238
+ process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
5239
+ process.exit(report.ok ? 0 : 1);
5240
+ }
5241
+ return false;
5242
+ }
5196
5243
  /**
5197
5244
  * @param {string[]} argv
5198
5245
  */
@@ -5276,7 +5323,7 @@ function normalizeResumeOption(value) {
5276
5323
  const CHAT_CREATE_PROMPT = [
5277
5324
  "Start an interactive chat session with the user and help them directly.",
5278
5325
  "Stay in this conversation until the user is done.",
5279
- 'When you are completely finished and want to hand control back to Smithers, end your final response with an empty JSON object in a ```json fence: {}.',
5326
+ 'When you are completely finished and want to hand control back to Smithers, return ONLY this raw JSON object with no prose, markdown, or code fence: {}.',
5280
5327
  ].join("\n\n");
5281
5328
  /**
5282
5329
  * @param {"claude-code" | "codex" | "gemini"} agentId
@@ -5288,7 +5335,7 @@ async function createChatAgent(agentId, cwd) {
5288
5335
  const { ClaudeCodeAgent } = await import("@smithers-orchestrator/agents/ClaudeCodeAgent");
5289
5336
  return new ClaudeCodeAgent({
5290
5337
  cwd,
5291
- model: "claude-opus-4-6",
5338
+ model: "claude-opus-4-7",
5292
5339
  });
5293
5340
  }
5294
5341
  case "codex": {
@@ -5395,6 +5442,9 @@ async function main() {
5395
5442
  if (argvRequestsJsonMode(argv)) {
5396
5443
  setJsonMode(true);
5397
5444
  }
5445
+ if (runRawJsonAgentCommandIfMatched(argv)) {
5446
+ return;
5447
+ }
5398
5448
  // Finding #1: pre-validate argv for devtools commands so missing-args
5399
5449
  // / invalid-flag errors go to stderr with exit 1 (not incur's
5400
5450
  // remap-to-4 VALIDATION_ERROR envelope on stdout).
@@ -601,8 +601,7 @@ async function listAllEvents(adapter, runId) {
601
601
  break;
602
602
  events.push(...batch);
603
603
  lastSeq = batch[batch.length - 1].seq;
604
- if (batch.length < 1_000)
605
- break;
604
+ if (batch.length < 1_000) break;
606
605
  }
607
606
  return events;
608
607
  }
@@ -89,12 +89,7 @@ function parseErrorSummary(raw) {
89
89
  if (message) {
90
90
  return { message, detail: parsed };
91
91
  }
92
- try {
93
- return { message: JSON.stringify(parsed), detail: parsed };
94
- }
95
- catch {
96
- return { message: String(parsed), detail: parsed };
97
- }
92
+ return { message: JSON.stringify(parsed), detail: parsed };
98
93
  }
99
94
  return { message: String(parsed), detail: parsed };
100
95
  }
package/src/watch.js CHANGED
@@ -110,7 +110,7 @@ export async function runWatchLoop(options) {
110
110
  tickCount += 1;
111
111
  latest = await options.fetch();
112
112
  await renderSnapshot(latest, false);
113
- if (options.isTerminal?.(latest)) {
113
+ if (options.isTerminal?.(latest))
114
114
  return {
115
115
  intervalMs,
116
116
  tickCount,
@@ -118,7 +118,6 @@ export async function runWatchLoop(options) {
118
118
  reachedTerminal: true,
119
119
  lastData: latest,
120
120
  };
121
- }
122
121
  }
123
122
  }
124
123
  finally {
@@ -461,8 +461,7 @@ function computeSignalName(node, descriptor, attempts, events) {
461
461
  correlationId ??
462
462
  parseString(payload.correlationId) ??
463
463
  null;
464
- if (signalName && correlationId)
465
- break;
464
+ if (signalName && correlationId) break;
466
465
  }
467
466
  return { signalName, correlationId };
468
467
  }
@@ -183,7 +183,7 @@ function renderAgentScaffoldFiles() {
183
183
  '// Built-in Claude Code CLI agent (cliEngine: "claude-code").',
184
184
  "// Tweak `model`, `cwd`, or uncomment extra options below to match your setup.",
185
185
  "export const ClaudeCodeAgent = new SmithersClaudeCodeAgent({",
186
- ' model: "claude-opus-4-6",',
186
+ ' model: "claude-opus-4-7",',
187
187
  " cwd: process.cwd(),",
188
188
  ' // systemPrompt: "Add shared instructions for every Claude run.",',
189
189
  " // timeoutMs: 10 * 60 * 1000,",
@@ -279,9 +279,10 @@ function renderPrompts() {
279
279
  "",
280
280
  "Reviewer: {props.reviewer}",
281
281
  "",
282
- "Review the following request and respond with a concise JSON object.",
283
- "Be a very thorough reviewer who only accepts production ready tested",
284
- "code.",
282
+ "Review the following request and return ONLY the required JSON object.",
283
+ "Do not include prose, markdown, headings, commentary, or code fences.",
284
+ "The first character of your response must be `{` and the last character must be `}`.",
285
+ "Be a very thorough reviewer who only accepts production ready tested code.",
285
286
  "",
286
287
  "REQUEST:",
287
288
  "{props.prompt}",
@@ -289,6 +290,8 @@ function renderPrompts() {
289
290
  "REQUIRED OUTPUT:",
290
291
  "{props.schema}",
291
292
  "",
293
+ "Return ONLY raw JSON matching the required output schema.",
294
+ "",
292
295
  ].join("\n"),
293
296
  },
294
297
  {
@@ -3221,7 +3224,7 @@ function renderWorkflows() {
3221
3224
  " return (",
3222
3225
  " <Worktree",
3223
3226
  " key={ticket.slug}",
3224
- " path={`.worktrees/${ticket.slug}`}",
3227
+ ' path={resolve(process.cwd(), ".worktrees", ticket.slug)}',
3225
3228
  " branch={`ticket/${ticket.slug}`}",
3226
3229
  " >",
3227
3230
  " <Sequence>",