@sagentlab/navarch-runtime 0.1.87 → 0.1.88

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/README.md CHANGED
@@ -751,7 +751,7 @@ cli.cts
751
751
  into Docker when NAVARCH_SANDBOX_MODE=docker
752
752
  4. selectAdapter(config.agentType) (adapters/index.cts) picks one AgentAdapter
753
753
  (adapters/types.cts) by NAVARCH_AGENT, then .run(...):
754
- - claudeCodeAdapter (adapters/claude.cts) — `claude -p --mcp-config <path> < prompt`
754
+ - claudeCodeAdapter (adapters/claude.cts) — `claude -p --mcp-config <path> --output-format stream-json --verbose < prompt`
755
755
  - codexAdapter (adapters/codex.cts) — `codex exec - --json -c mcp_servers.*=... < prompt`
756
756
  - geminiAdapter (adapters/gemini.cts) — `gemini --output-format stream-json < prompt`
757
757
  - openCodeAdapter (adapters/opencode.cts) — `opencode run --format json < prompt`
@@ -871,16 +871,17 @@ Claude Code headless → PR opens on GitHub → complete lands with evidence;
871
871
  secrets absent from disk after exit"):
872
872
 
873
873
  - Actually running `claude -p` headless and confirming its real
874
- `--output-format json` shape (WP-13). `adapters/claude.cts` now appends
875
- `--output-format json` by default and best-effort parses stdout as a single
876
- JSON result object shaped like `{ type, subtype, is_error, result,
874
+ result shape (WP-13). `adapters/claude.cts` appends
875
+ `--output-format stream-json --verbose` by default, so the uploaded
876
+ transcript records every message and tool call, and best-effort parses the
877
+ last `type: "result"` record on stdout as a JSON result object shaped like `{ type, subtype, is_error, result,
877
878
  session_id, total_cost_usd, usage: { input_tokens, output_tokens,
878
879
  cache_creation_input_tokens, cache_read_input_tokens } }` (see
879
880
  `exit-conditions.cts#parseClaudeJsonResult` for the exact assumption and
880
881
  fallback behavior). Unit tests (`tests/adapter.test.cts`,
881
882
  `tests/exit-conditions.test.cts`) cover the parsing and arg-construction
882
- logic against fixed JSON strings; what's untested offline is whether a real
883
- `claude -p --output-format json` invocation actually produces this shape.
883
+ logic against fixed JSON strings recorded from Claude Code 2.1; a future
884
+ CLI release could still change this shape.
884
885
  If it doesn't, parsing degrades to `null` and `tokensIn`/`tokensOut`/
885
886
  `costUsd` fall back to 0 (session.cts's existing default) — never a thrown
886
887
  error — but cost/spend data silently goes missing until the shape is
@@ -13,7 +13,7 @@ function hasFlag(args, flag) {
13
13
  }
14
14
  /**
15
15
  * Headless Claude Code adapter (project-plan.md §3.9 / implementation-plan.md
16
- * WP-07): `claude -p --mcp-config platform-mcp.json --output-format json`
16
+ * WP-07): `claude -p --mcp-config platform-mcp.json --output-format stream-json --verbose`
17
17
  * with the context bundle on stdin (`claude -p` reads its prompt from stdin
18
18
  * when none is given; Linux rejects any single argv string over 128 KiB, so
19
19
  * an argv prompt failed `spawn E2BIG` before Claude started). Returns raw stdout/stderr/exit signals (plus
@@ -25,11 +25,10 @@ function hasFlag(args, flag) {
25
25
  * (adapters/types.cts) — see adapters/codex.cts for the Codex CLI sibling
26
26
  * session.cts picks between via NAVARCH_AGENT (config.cts's `agentType`).
27
27
  *
28
- * NEEDS LIVE VERIFICATION (WP-13): `--output-format json` is assumed to make
29
- * `claude -p` print a single JSON result object with a `usage` block, per
30
- * Claude Code's documented headless-mode output. This cannot be confirmed
31
- * without a real `claude` binary in this offline build environment. If the
32
- * real shape differs, parseClaudeJsonResult() returns null and
28
+ * `--output-format stream-json` prints one JSON record per line and ends with
29
+ * the same result object (`type: "result"`, `usage`, `total_cost_usd`) that
30
+ * `--output-format json` prints alone; parseClaudeJsonResult() reads that
31
+ * last record. If the real shape differs, parseClaudeJsonResult() returns null and
33
32
  * tokensIn/tokensOut/costUsd fall back to 0 (session.cts's existing
34
33
  * default) rather than throwing -- see runtime/README.md.
35
34
  */
@@ -135,9 +134,14 @@ async function runClaudeAttempt(options, automaticFallback) {
135
134
  // Only append the default when the caller hasn't already asked for a
136
135
  // specific --output-format (extraArgs wins so an operator can opt back
137
136
  // into plain-text output, e.g. while diagnosing a live-verification
138
- // mismatch, without an adapter code change).
139
- if (!options.extraArgs.includes("--output-format")) {
140
- args.push("--output-format", "json");
137
+ // mismatch, without an adapter code change). stream-json records every
138
+ // message and tool call, which the task transcript viewer renders; plain
139
+ // `json` printed only the final result. Claude Code requires --verbose for
140
+ // stream-json under --print, and its last record is the same result object.
141
+ if (!hasFlag(options.extraArgs, "--output-format")) {
142
+ args.push("--output-format", "stream-json");
143
+ if (!hasFlag(options.extraArgs, "--verbose"))
144
+ args.push("--verbose");
141
145
  }
142
146
  args.push(...options.extraArgs);
143
147
  // Project/task policy is appended after machine-wide extra arguments so a
@@ -157,7 +161,7 @@ async function runClaudeAttempt(options, automaticFallback) {
157
161
  const raw = runOptions.dockerExec ? await runViaDocker(runOptions, args) : await runOnHost(runOptions, args);
158
162
  return attachUsage(raw);
159
163
  }
160
- /** Parses stdout for `claude -p --output-format json` usage and folds it onto the raw result (best-effort; leaves tokensIn/tokensOut/costUsd unset when parsing fails). */
164
+ /** Parses the final `claude -p --output-format stream-json` result record for usage and folds it onto the raw result (best-effort; leaves tokensIn/tokensOut/costUsd unset when parsing fails). */
161
165
  function attachUsage(result) {
162
166
  const parsed = (0, exit_conditions_cjs_1.parseClaudeJsonResult)(result.stdout);
163
167
  if (!parsed)
@@ -24,8 +24,9 @@ function agentAuthFailureReport(detail) {
24
24
  "Log the coding agent in again on this machine (`claude /login` or `codex login`), then resume the agent.";
25
25
  }
26
26
  /**
27
- * Best-effort parse of `claude -p --output-format json` stdout into the
28
- * assumed result shape above. Tries the whole trimmed stdout first (the
27
+ * Best-effort parse of `claude -p --output-format json` (or `stream-json`,
28
+ * whose last result record has the same shape) stdout into the assumed
29
+ * result shape above. Tries the whole trimmed stdout first (the
29
30
  * expected case); if that fails, tries each non-empty line that looks like a
30
31
  * JSON object, in case a warning/log line preceded the result (last such
31
32
  * line wins, since the final result is expected last). Returns null rather
@@ -39,6 +40,9 @@ function parseClaudeJsonResult(stdout) {
39
40
  const isUsableResult = (value) => typeof value === "object" &&
40
41
  value !== null &&
41
42
  !Array.isArray(value) &&
43
+ // stream-json output interleaves typed message/tool records with the
44
+ // final `type: "result"` record; only that record carries the outcome.
45
+ (!("type" in value) || value.type === "result") &&
42
46
  (!("result" in value) || typeof value.result === "string") &&
43
47
  ("result" in value || "usage" in value || "cost_usd" in value || "total_cost_usd" in value);
44
48
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sagentlab/navarch-runtime",
3
- "version": "0.1.87",
3
+ "version": "0.1.88",
4
4
  "description": "Navarch machine-side session manager: claims delivery tasks and runs them through local coding agents.",
5
5
  "type": "commonjs",
6
6
  "license": "MIT",