salmon-loop 0.2.13 → 0.2.16

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 (218) hide show
  1. package/dist/cli/argv/headless-detection.js +27 -0
  2. package/dist/cli/chat-flow.js +11 -0
  3. package/dist/cli/chat.js +160 -24
  4. package/dist/cli/commands/chat.js +14 -7
  5. package/dist/cli/commands/flow-mode.js +63 -0
  6. package/dist/cli/commands/registry.js +2 -0
  7. package/dist/cli/commands/run/benchmark-artifacts.js +41 -0
  8. package/dist/cli/commands/run/early-errors.js +23 -0
  9. package/dist/cli/commands/run/handler.js +115 -27
  10. package/dist/cli/commands/run/headless-error-writer.js +8 -0
  11. package/dist/cli/commands/run/loop-params.js +2 -0
  12. package/dist/cli/commands/run/mode.js +2 -5
  13. package/dist/cli/commands/run/parse-options.js +16 -0
  14. package/dist/cli/commands/run/persist-session.js +10 -1
  15. package/dist/cli/commands/run/preflight.js +10 -0
  16. package/dist/cli/commands/run/reporter-factory.js +4 -0
  17. package/dist/cli/commands/run/runtime-llm.js +38 -11
  18. package/dist/cli/commands/run/runtime-options.js +2 -2
  19. package/dist/cli/commands/serve.js +91 -71
  20. package/dist/cli/commands/tool-names.js +78 -78
  21. package/dist/cli/headless/anthropic-stream-normalized-encoder.js +6 -1
  22. package/dist/cli/headless/json-protocol.js +37 -0
  23. package/dist/cli/headless/native-stream-normalized-encoder.js +6 -1
  24. package/dist/cli/headless/protocol-metadata.js +22 -0
  25. package/dist/cli/headless/stream-json-protocol.js +34 -1
  26. package/dist/cli/index.js +6 -4
  27. package/dist/cli/locales/en.js +30 -6
  28. package/dist/cli/program-bootstrap.js +8 -3
  29. package/dist/cli/program-commands.js +5 -1
  30. package/dist/cli/reporters/anthropic-stream.js +7 -1
  31. package/dist/cli/reporters/json.js +4 -0
  32. package/dist/cli/reporters/stream-json.js +17 -2
  33. package/dist/cli/run-cli.js +5 -3
  34. package/dist/cli/slash/runtime.js +27 -12
  35. package/dist/cli/ui/components/CommandInput.js +7 -3
  36. package/dist/cli/ui/components/CommandSuggestionList.js +1 -1
  37. package/dist/cli/utils/command-option-source.js +13 -0
  38. package/dist/cli/utils/verify-resolver.js +8 -4
  39. package/dist/cli/utils/worktree-prepare-resolver.js +7 -3
  40. package/dist/core/adapters/fs/file-adapter.js +6 -0
  41. package/dist/core/adapters/fs/filesystem.js +2 -1
  42. package/dist/core/adapters/git/git-adapter.js +78 -1
  43. package/dist/core/benchmark/patch-artifact.js +124 -0
  44. package/dist/core/benchmark/swe-bench.js +25 -0
  45. package/dist/core/config/load.js +18 -11
  46. package/dist/core/config/resolve-llm.js +12 -0
  47. package/dist/core/config/resolvers/server.js +0 -6
  48. package/dist/core/config/validate.js +73 -21
  49. package/dist/core/context/gatherers/metadata-gatherer.js +1 -0
  50. package/dist/core/context/gatherers/ripgrep-gatherer.js +84 -2
  51. package/dist/core/context/keywords.js +18 -4
  52. package/dist/core/context/service-deps.js +2 -2
  53. package/dist/core/context/service.js +8 -0
  54. package/dist/core/context/steps/context-gather.js +38 -0
  55. package/dist/core/context/summarization/summarizer.js +55 -12
  56. package/dist/core/context/targeting/target-resolver.js +4 -4
  57. package/dist/core/extensions/index.js +23 -5
  58. package/dist/core/extensions/paths.js +31 -0
  59. package/dist/core/extensions/schemas.js +8 -5
  60. package/dist/core/facades/cli-chat.js +6 -2
  61. package/dist/core/facades/cli-command-chat.js +1 -0
  62. package/dist/core/facades/cli-command-tool-names.js +2 -0
  63. package/dist/core/facades/cli-observability.js +1 -1
  64. package/dist/core/facades/cli-run-handler.js +4 -2
  65. package/dist/core/facades/cli-run-persist-session.js +1 -0
  66. package/dist/core/facades/cli-serve.js +2 -4
  67. package/dist/core/facades/cli-utils-worktree.js +1 -1
  68. package/dist/core/failure/diagnostics.js +53 -1
  69. package/dist/core/grizzco/dsl/llm-strategy.js +4 -1
  70. package/dist/core/grizzco/engine/outcome/loop-result-mapper.js +67 -9
  71. package/dist/core/grizzco/engine/pipeline/pipeline.js +6 -2
  72. package/dist/core/grizzco/engine/transaction/attempt-failure.js +90 -15
  73. package/dist/core/grizzco/engine/transaction/report-mapper.js +17 -3
  74. package/dist/core/grizzco/engine/transaction/transaction-runner.js +165 -7
  75. package/dist/core/grizzco/flows/AutopilotFlow.js +18 -0
  76. package/dist/core/grizzco/flows/flow-dispatch.js +11 -0
  77. package/dist/core/grizzco/steps/answer.js +13 -14
  78. package/dist/core/grizzco/steps/autopilot.js +396 -0
  79. package/dist/core/grizzco/steps/cache-sharing.js +29 -0
  80. package/dist/core/grizzco/steps/explore.js +37 -21
  81. package/dist/core/grizzco/steps/generateReview.js +2 -5
  82. package/dist/core/grizzco/steps/patch/apply-check.js +10 -0
  83. package/dist/core/grizzco/steps/patch/diff-normalization.js +70 -0
  84. package/dist/core/grizzco/steps/patch/diff-salvage.js +46 -0
  85. package/dist/core/grizzco/steps/patch/prompt-input.js +42 -0
  86. package/dist/core/grizzco/steps/patch.js +105 -146
  87. package/dist/core/grizzco/steps/plan.js +101 -25
  88. package/dist/core/grizzco/steps/preflight.js +5 -6
  89. package/dist/core/grizzco/steps/request-assembly.js +78 -0
  90. package/dist/core/grizzco/steps/research.js +39 -36
  91. package/dist/core/grizzco/steps/tool-runtime.js +47 -0
  92. package/dist/core/grizzco/steps/verify-shared.js +23 -0
  93. package/dist/core/grizzco/steps/verify.js +13 -21
  94. package/dist/core/llm/ai-sdk/chat-executor.js +2 -0
  95. package/dist/core/llm/ai-sdk/high-level-phase-specs.js +63 -0
  96. package/dist/core/llm/ai-sdk/message-mapper.js +40 -10
  97. package/dist/core/llm/ai-sdk/provider-factory.js +14 -0
  98. package/dist/core/llm/ai-sdk/request-params.js +73 -0
  99. package/dist/core/llm/ai-sdk/result-mapper.js +16 -0
  100. package/dist/core/llm/ai-sdk.js +112 -27
  101. package/dist/core/llm/capabilities.js +12 -0
  102. package/dist/core/llm/contracts/repair.js +36 -30
  103. package/dist/core/llm/errors.js +83 -2
  104. package/dist/core/llm/message-composition.js +7 -22
  105. package/dist/core/llm/phase-router.js +29 -10
  106. package/dist/core/llm/redact.js +28 -3
  107. package/dist/core/llm/registry.js +2 -0
  108. package/dist/core/llm/request-augmentation.js +55 -0
  109. package/dist/core/llm/request-envelope.js +334 -0
  110. package/dist/core/llm/shared-request-assembly.js +35 -0
  111. package/dist/core/llm/stream-utils.js +13 -4
  112. package/dist/core/llm/utils.js +18 -29
  113. package/dist/core/memory/relevant-retrieval.js +144 -0
  114. package/dist/core/observability/logger.js +11 -2
  115. package/dist/core/patch/diff.js +1 -0
  116. package/dist/core/prompts/registry.js +39 -2
  117. package/dist/core/prompts/runtime.js +50 -12
  118. package/dist/core/prompts/templates/phases/patch_user.hbs +2 -5
  119. package/dist/core/prompts/templates/phases/research_user.hbs +11 -0
  120. package/dist/core/prompts/templates/phases/review_user.hbs +3 -0
  121. package/dist/core/prompts/templates/system/answer_system.hbs +5 -0
  122. package/dist/core/prompts/templates/system/autopilot_system.hbs +11 -0
  123. package/dist/core/prompts/templates/system/explore_system.hbs +14 -23
  124. package/dist/core/prompts/templates/system/main_system.hbs +4 -16
  125. package/dist/core/prompts/templates/system/patch_system.hbs +39 -8
  126. package/dist/core/prompts/templates/system/plan_system.hbs +86 -1
  127. package/dist/core/prompts/templates/system/research_system.hbs +2 -0
  128. package/dist/core/protocols/a2a/agent-card.js +3 -2
  129. package/dist/core/protocols/a2a/sdk/executor.js +2 -1
  130. package/dist/core/protocols/a2a/sdk/server.js +0 -1
  131. package/dist/core/protocols/acp/formal-agent.js +74 -51
  132. package/dist/core/protocols/acp/handlers.js +5 -1
  133. package/dist/core/protocols/acp/permission-provider.js +1 -1
  134. package/dist/core/protocols/shared/flow-mode-mapping.js +23 -0
  135. package/dist/core/public-capabilities/flow-mode-metadata.js +39 -0
  136. package/dist/core/public-capabilities/projections.js +29 -0
  137. package/dist/core/public-capabilities/registry.js +26 -0
  138. package/dist/core/public-capabilities/types.js +2 -0
  139. package/dist/core/runtime/agent-server-runtime.js +47 -43
  140. package/dist/core/runtime/execution-profile.js +67 -0
  141. package/dist/core/session/artifact-state.js +160 -0
  142. package/dist/core/session/compaction/index.js +183 -0
  143. package/dist/core/session/compaction/microcompact.js +78 -0
  144. package/dist/core/session/compaction/tracking.js +48 -0
  145. package/dist/core/session/compaction/types.js +11 -0
  146. package/dist/core/session/compression.js +8 -0
  147. package/dist/core/session/manager.js +244 -8
  148. package/dist/core/session/pruning-strategy.js +55 -9
  149. package/dist/core/session/replacement-preview-provider.js +24 -0
  150. package/dist/core/session/replacement-state.js +131 -0
  151. package/dist/core/session/resume-repair/pipeline.js +79 -0
  152. package/dist/core/session/resume-repair/stages/load-raw-archive-state.js +40 -0
  153. package/dist/core/session/resume-repair/stages/reattach-runtime-state.js +8 -0
  154. package/dist/core/session/resume-repair/stages/recover-orphaned-branches.js +10 -0
  155. package/dist/core/session/resume-repair/stages/relink-boundary-and-tail.js +36 -0
  156. package/dist/core/session/resume-repair/stages/replay-startup-hooks.js +23 -0
  157. package/dist/core/session/resume-repair/stages/rescue-stale-metadata.js +17 -0
  158. package/dist/core/session/resume-repair/types.js +2 -0
  159. package/dist/core/session/summary-sync.js +164 -13
  160. package/dist/core/session/token-tracker.js +6 -0
  161. package/dist/core/skills/audit.js +34 -0
  162. package/dist/core/skills/bridge.js +84 -7
  163. package/dist/core/skills/discovery.js +94 -0
  164. package/dist/core/skills/feature-flags.js +52 -0
  165. package/dist/core/skills/index.js +1 -1
  166. package/dist/core/skills/loader.js +195 -20
  167. package/dist/core/skills/parser.js +296 -24
  168. package/dist/core/skills/permissions.js +117 -0
  169. package/dist/core/skills/runtime/MicroTaskRunner.js +10 -4
  170. package/dist/core/skills/runtime/SkillRunner.js +240 -61
  171. package/dist/core/strata/layers/shadow-driver/shadow-driver.js +37 -7
  172. package/dist/core/strata/layers/worktree.js +67 -10
  173. package/dist/core/strata/runtime/synchronizer.js +29 -2
  174. package/dist/core/streaming/stream-assembler.js +75 -31
  175. package/dist/core/sub-agent/context-snapshot.js +156 -0
  176. package/dist/core/sub-agent/core/loop.js +1 -1
  177. package/dist/core/sub-agent/core/manager.js +119 -20
  178. package/dist/core/sub-agent/dispatch-policy.js +29 -0
  179. package/dist/core/sub-agent/prefix-consistency.js +48 -0
  180. package/dist/core/sub-agent/registry-defaults.js +4 -0
  181. package/dist/core/sub-agent/tools/task-spawn.js +79 -2
  182. package/dist/core/sub-agent/types.js +134 -5
  183. package/dist/core/tools/audit.js +13 -4
  184. package/dist/core/tools/builtin/ast-grep.js +1 -1
  185. package/dist/core/tools/builtin/ast.js +1 -1
  186. package/dist/core/tools/builtin/benchmark.js +360 -0
  187. package/dist/core/tools/builtin/code-search/backends/rg.js +2 -1
  188. package/dist/core/tools/builtin/code-search/executor.js +6 -1
  189. package/dist/core/tools/builtin/code-search/spec.js +26 -2
  190. package/dist/core/tools/builtin/fs.js +256 -23
  191. package/dist/core/tools/builtin/git.js +2 -2
  192. package/dist/core/tools/builtin/index.js +51 -2
  193. package/dist/core/tools/builtin/interaction.js +8 -1
  194. package/dist/core/tools/builtin/plan.js +37 -15
  195. package/dist/core/tools/builtin/shell.js +1 -1
  196. package/dist/core/tools/loader.js +39 -16
  197. package/dist/core/tools/mapper.js +17 -3
  198. package/dist/core/tools/parallel/scheduler.js +35 -4
  199. package/dist/core/tools/permissions/permission-rules.js +5 -10
  200. package/dist/core/tools/policy.js +6 -1
  201. package/dist/core/tools/recoverable-tool-errors.js +10 -0
  202. package/dist/core/tools/router.js +24 -6
  203. package/dist/core/tools/session.js +458 -48
  204. package/dist/core/tools/tool-visibility.js +62 -0
  205. package/dist/core/tools/types.js +9 -1
  206. package/dist/core/types/execution.js +4 -0
  207. package/dist/core/types/flow-mode.js +8 -0
  208. package/dist/core/utils/path.js +52 -0
  209. package/dist/core/verification/runner.js +4 -1
  210. package/dist/languages/typescript/index.js +4 -1
  211. package/dist/locales/en.js +35 -2
  212. package/dist/utils/eol.js +1 -1
  213. package/package.json +13 -6
  214. package/scripts/fix-es-abstract-compat.js +77 -0
  215. package/dist/core/runtime/fastify-server-bundle.js +0 -26
  216. package/dist/core/runtime/sidecar-fastify-plugin.js +0 -35
  217. package/dist/core/runtime/sidecar-paths.js +0 -47
  218. package/dist/core/runtime/sidecar-route-catalog.js +0 -103
@@ -1,4 +1,5 @@
1
1
  import { getExitCode } from '../../core/facades/cli-headless.js';
2
+ import { HEADLESS_NATIVE_STREAM_PROTOCOL_VERSION, normalizeHeadlessWarnings, } from './protocol-metadata.js';
2
3
  function toIso(date) {
3
4
  return date.toISOString();
4
5
  }
@@ -27,6 +28,8 @@ function encodeEnvelope(params) {
27
28
  return dropUndefined({
28
29
  uuid: params.uuid,
29
30
  session_id: params.sessionId,
31
+ protocol_version: HEADLESS_NATIVE_STREAM_PROTOCOL_VERSION,
32
+ event_seq: params.eventSeq,
30
33
  event: params.event,
31
34
  parent_tool_use_id: params.parentToolUseId,
32
35
  });
@@ -42,6 +45,7 @@ export function encodeStreamStart(params) {
42
45
  repo_path: params.repoPath,
43
46
  instruction: params.instruction,
44
47
  }),
48
+ eventSeq: params.eventSeq,
45
49
  });
46
50
  }
47
51
  export function encodeStreamEvent(params) {
@@ -53,6 +57,7 @@ export function encodeStreamEvent(params) {
53
57
  ...params.event,
54
58
  timestamp: toIso(params.at),
55
59
  }),
60
+ eventSeq: params.eventSeq,
56
61
  });
57
62
  }
58
63
  export function encodeStreamLoopEvent(params) {
@@ -65,10 +70,30 @@ export function encodeStreamLoopEvent(params) {
65
70
  ...mapLoopEventToJson(params.event),
66
71
  timestamp: toIso(params.event.timestamp),
67
72
  }),
73
+ eventSeq: params.eventSeq,
68
74
  });
69
75
  }
70
76
  export function encodeStreamResult(params) {
71
77
  const exitCode = getStreamExitCode(params.loopResult);
78
+ const warnings = normalizeHeadlessWarnings(params.warnings);
79
+ const patchArtifact = params.loopResult.benchmarkPatchArtifact
80
+ ? {
81
+ kind: params.loopResult.benchmarkPatchArtifact.kind,
82
+ path: params.loopResult.benchmarkPatchArtifact.path,
83
+ sha256: params.loopResult.benchmarkPatchArtifact.sha256,
84
+ bytes: params.loopResult.benchmarkPatchArtifact.bytes,
85
+ changed_files: params.loopResult.benchmarkPatchArtifact.changedFiles,
86
+ is_empty: params.loopResult.benchmarkPatchArtifact.isEmpty,
87
+ }
88
+ : undefined;
89
+ const benchmarkArtifact = params.loopResult.benchmarkArtifact
90
+ ? {
91
+ provider: params.loopResult.benchmarkArtifact.provider,
92
+ instance_id: params.loopResult.benchmarkArtifact.instanceId,
93
+ model_name_or_path: params.loopResult.benchmarkArtifact.modelNameOrPath,
94
+ predictions_path: params.loopResult.benchmarkArtifact.predictionsPath,
95
+ }
96
+ : undefined;
72
97
  return encodeEnvelope({
73
98
  uuid: params.uuid,
74
99
  sessionId: params.sessionId,
@@ -83,17 +108,21 @@ export function encodeStreamResult(params) {
83
108
  safe_hint: params.loopResult.safeHint ?? params.loopResult.reason,
84
109
  remediation_steps: params.loopResult.remediationSteps ?? [],
85
110
  attempts: params.loopResult.attempts,
86
- changed_files: params.loopResult.changedFiles,
111
+ changed_files: params.loopResult.changedFiles ?? [],
112
+ patch_artifact: patchArtifact,
113
+ benchmark_artifact: benchmarkArtifact,
87
114
  audit_path: params.loopResult.auditPath,
88
115
  error_code: params.loopResult.errorCode,
89
116
  authorization_summary: params.loopResult.authorizationSummary,
90
117
  result: params.resultText,
118
+ warnings,
91
119
  run_end: {
92
120
  success: Boolean(params.loopResult.success),
93
121
  exit_code: exitCode,
94
122
  timestamp: toIso(params.at),
95
123
  },
96
124
  }),
125
+ eventSeq: params.eventSeq,
97
126
  });
98
127
  }
99
128
  export function encodeStreamFailure(params) {
@@ -103,12 +132,14 @@ export function encodeStreamFailure(params) {
103
132
  event: {
104
133
  type: 'error',
105
134
  timestamp: toIso(params.at),
135
+ audit_path: params.auditPath,
106
136
  error: dropUndefined({
107
137
  name: params.name,
108
138
  message: params.message,
109
139
  stack: params.stack,
110
140
  }),
111
141
  },
142
+ eventSeq: params.eventSeq,
112
143
  });
113
144
  }
114
145
  export function encodeStreamCrash(params) {
@@ -119,6 +150,7 @@ export function encodeStreamCrash(params) {
119
150
  message: params.error.message,
120
151
  name: params.error.name,
121
152
  stack: params.error.stack,
153
+ eventSeq: params.eventSeq,
122
154
  });
123
155
  }
124
156
  export function encodeStreamEnd(params) {
@@ -131,6 +163,7 @@ export function encodeStreamEnd(params) {
131
163
  success: params.success,
132
164
  exit_code: params.exitCode,
133
165
  },
166
+ eventSeq: params.eventSeq,
134
167
  });
135
168
  }
136
169
  //# sourceMappingURL=stream-json-protocol.js.map
package/dist/cli/index.js CHANGED
@@ -1,8 +1,10 @@
1
1
  #!/usr/bin/env bun
2
- // 1. MUST be the very first lines to force all chalk instances (even in node_modules)
3
- // to use color support before they complete initialization.
4
- process.env.FORCE_COLOR = '3';
2
+ import { detectHeadlessOutputFromArgv, shouldForceColorForArgv, } from './argv/headless-detection.js';
3
+ const headlessOutput = Boolean(detectHeadlessOutputFromArgv(process.argv).outputFormat);
4
+ if (!headlessOutput && shouldForceColorForArgv(process.argv)) {
5
+ process.env.FORCE_COLOR = '3';
6
+ }
5
7
  import 'dotenv/config';
6
- import { runCli } from './run-cli.js';
8
+ const { runCli } = await import('./run-cli.js');
7
9
  await runCli(process.argv);
8
10
  //# sourceMappingURL=index.js.map
@@ -3,7 +3,7 @@ export const en = {
3
3
  programDescription: 'A minimal viable loop for automated code patching',
4
4
  runDescription: 'Run the salmon-loop',
5
5
  contextDescription: 'Build and print the context prompt (no LLM call)',
6
- serveDescription: 'Start the A2A + sidecar server',
6
+ serveDescription: 'Start the A2A server and ACP stdio bridge',
7
7
  serveAcpDescription: 'Start the agent-client-protocol (ACP) stdio server only',
8
8
  noColorOption: 'Disable colored output in logs',
9
9
  // Chat mode
@@ -74,6 +74,7 @@ export const en = {
74
74
  commandLlmOutput: 'Set which LLM sections are shown in the UI (advanced)',
75
75
  commandMode: 'Set permission mode (interactive|yolo) and save to config',
76
76
  commandLogMode: 'Set UI verbosity (quiet|normal|debug) and save to config',
77
+ commandFlowMode: 'Set the current chat flow mode for this session',
77
78
  commandConfig: 'Settings hub (mode, log-mode, view, output, allowlist)',
78
79
  commandAuth: 'Manage tool allowlist',
79
80
  commandParallel: 'Manage parallel plans',
@@ -120,6 +121,25 @@ export const en = {
120
121
  modeUpdated: (mode) => `Permission mode updated: ${mode}`,
121
122
  modePersisted: (path) => `Permission mode saved to ${path}`,
122
123
  modePersistFailed: (error) => `Failed to save permission mode: ${error}`,
124
+ flowModeUsage: 'Usage: /flow-mode <patch|review|debug|research|answer|autopilot>',
125
+ flowModeSuggestion: (mode) => {
126
+ if (mode === 'patch')
127
+ return 'Patch code and run verification';
128
+ if (mode === 'review')
129
+ return 'Analyze code without modifying files';
130
+ if (mode === 'debug')
131
+ return 'Investigate issues, then patch and verify';
132
+ if (mode === 'research')
133
+ return 'Research the codebase and summarize findings';
134
+ if (mode === 'answer')
135
+ return 'Answer directly without modifying files';
136
+ if (mode === 'autopilot')
137
+ return 'Let SalmonLoop choose the appropriate flow';
138
+ return `Set flow mode to ${mode}`;
139
+ },
140
+ flowModeCurrent: (mode) => `Current chat flow mode: ${mode}`,
141
+ flowModeInvalid: (mode) => `Invalid flow mode: ${mode}. Expected one of: patch, review, debug, research, answer, autopilot.`,
142
+ flowModeUpdated: (mode) => `Chat flow mode updated: ${mode}`,
123
143
  logModeUsage: 'Usage: /log-mode <quiet|normal|debug>',
124
144
  logModeSuggestion: (mode) => {
125
145
  if (mode === 'quiet')
@@ -159,11 +179,9 @@ export const en = {
159
179
  a2aPortOption: 'A2A listen port (default: 7431)',
160
180
  a2aTokenOption: 'Bearer token for A2A auth (repeatable)',
161
181
  acpStdioDisableOption: 'Disable agent-client-protocol (ACP) stdio server',
162
- sidecarSocketOption: 'UDS path for the sidecar UI server',
163
- sidecarAllowConditionalOption: 'Expose conditional sidecar routes (use with care)',
164
182
  acpStdioStarted: (port) => `ACP (agent-client-protocol) stdio enabled; port ${port}`,
165
183
  invalidA2APort: (value) => `Invalid A2A port: ${value}`,
166
- serveStarted: (host, port, socket) => `A2A listening on ${host}:${port}; sidecar socket at ${socket}`,
184
+ serveStarted: (host, port) => `A2A listening on ${host}:${port}`,
167
185
  configAllowlistUsage: 'Usage: /config allowlist <list|add|remove|clear|hash|reload> [scope] [tool] [phase] [args=<hash>] [effects=a,b] [deny]',
168
186
  authUsage: 'Usage: /allowlist <list|add|remove|clear|hash|reload> [scope] [tool] [phase] [args=<hash>] [effects=a,b] [deny]',
169
187
  authSubcommandHint: (sub) => `Allowlist ${sub} command`,
@@ -243,6 +261,10 @@ export const en = {
243
261
  includePartialMessagesOption: 'Include partial message streaming events in stream-json output (alias for --stream-output).',
244
262
  outputFormatOption: 'Output format (text, json, stream-json)',
245
263
  outputProfileOption: 'Output profile for stream-json (native, anthropic, openai). Only valid with --output-format stream-json.',
264
+ exportPatchOption: 'Write the final workspace git unified diff to a patch file after the run completes.',
265
+ sweBenchInstanceIdOption: 'SWE-bench instance_id to include when writing a predictions JSONL record.',
266
+ sweBenchModelNameOption: 'SWE-bench model_name_or_path to include when writing a predictions JSONL record.',
267
+ sweBenchPredictionsOption: 'Append a SWE-bench predictions JSONL record containing instance_id, model_name_or_path, and model_patch.',
246
268
  headlessIncludeToolInputOption: 'Headless only: include (redacted) tool input in stream-json output. Only valid with --output-format stream-json.',
247
269
  headlessIncludeToolOutputOption: 'Headless only: include tool output summary in stream-json output. Only valid with --output-format stream-json.',
248
270
  headlessIncludeAuthorizationDecisionsOption: 'Headless only: include tool authorization decisions in headless output. Only valid with --output-format json or stream-json.',
@@ -252,7 +274,7 @@ export const en = {
252
274
  auditScopeOption: 'Audit log scope (repo, user)',
253
275
  contextDiffScopeOption: 'Diff scope for context (primary, ast_related)',
254
276
  contextBudgetCharsOption: 'Context budget in characters (e.g., 30000)',
255
- actModeOption: 'Flow mode to run (patch, review, debug, research)',
277
+ actModeOption: 'Flow mode to run (patch, review, debug, research, answer, autopilot)',
256
278
  // Error messages
257
279
  fileSelectionConflict: '--file and --selection are mutually exclusive',
258
280
  instructionRequired: '--instruction is required',
@@ -262,10 +284,12 @@ export const en = {
262
284
  jsonSchemaRequiresJsonOutput: '--json-schema is only valid when --output-format is set to "json".',
263
285
  jsonSchemaLoadFailed: (msg) => `Failed to load JSON schema: ${msg}.`,
264
286
  structuredOutputSchemaFailed: 'Structured output failed schema validation.',
265
- invalidActMode: (mode) => `Invalid --act-mode "${mode}". Expected "patch", "review", "debug", or "research".`,
287
+ invalidActMode: (mode) => `Invalid --act-mode "${mode}". Expected "patch", "review", "debug", "research", "answer", or "autopilot".`,
266
288
  invalidEnvironmentMode: (mode) => `Invalid --environment-mode "${mode}". Expected "strict" or "parity".`,
267
289
  invalidOutputFormat: (format) => `Invalid --output-format "${format}". Expected "text", "stream-json", or "json".`,
268
290
  invalidOutputProfile: (profile) => `Invalid --output-profile "${profile}". Expected "native", "anthropic", or "openai".`,
291
+ sweBenchInstanceRequired: '--swe-bench-predictions requires --swe-bench-instance-id.',
292
+ sweBenchModelRequired: '--swe-bench-predictions requires --swe-bench-model-name.',
269
293
  invalidAuditScope: (scope) => `Invalid --audit-scope "${scope}". Expected "repo" or "user".`,
270
294
  headlessToolPayloadRequiresStreamJson: '--headless-include-tool-input/--headless-include-tool-output are only valid when --output-format is set to "stream-json".',
271
295
  headlessToolPayloadNotSupportedWithOpenAiProfile: '--headless-include-tool-input/--headless-include-tool-output are not supported with --output-profile "openai".',
@@ -2,10 +2,15 @@ import chalk from 'chalk';
2
2
  import { Command } from 'commander';
3
3
  import { initializeRuntime } from '../core/facades/cli-program-bootstrap.js';
4
4
  import { text } from './locales/index.js';
5
- export function bootstrapProgram() {
5
+ export function bootstrapProgram(options = {}) {
6
6
  initializeRuntime();
7
- // Force global chalk level for all output paths.
8
- chalk.level = 3;
7
+ if (!options.headlessDetection?.outputFormat && process.env.NO_COLOR === undefined) {
8
+ // Force global chalk level for interactive output paths.
9
+ chalk.level = 3;
10
+ }
11
+ else {
12
+ chalk.level = 0;
13
+ }
9
14
  const program = new Command();
10
15
  program.exitOverride();
11
16
  program
@@ -22,7 +22,7 @@ export function registerProgramCommands(program) {
22
22
  .option('--force-reset', text.cli.forceResetOption)
23
23
  .option('--validate', text.cli.validateOption)
24
24
  .option('--preflight-policy <policy>', text.cli.preflightPolicyOption, 'lenient')
25
- .option('--act-mode <mode>', text.cli.actModeOption, 'patch')
25
+ .option('--act-mode <mode>', text.cli.actModeOption, 'autopilot')
26
26
  .option('--apply-back-on-dirty <mode>', text.cli.applyBackOnDirtyOption, '3way')
27
27
  .option('--environment-mode <mode>', text.cli.environmentModeOption, 'strict')
28
28
  .option('--worktree-prepare <command>', text.cli.worktreePrepareOption)
@@ -30,6 +30,10 @@ export function registerProgramCommands(program) {
30
30
  .option('--include-partial-messages', text.cli.includePartialMessagesOption)
31
31
  .option('--output-format <format>', text.cli.outputFormatOption, 'text')
32
32
  .option('--output-profile <profile>', text.cli.outputProfileOption)
33
+ .option('--export-patch <path>', text.cli.exportPatchOption)
34
+ .option('--swe-bench-instance-id <id>', text.cli.sweBenchInstanceIdOption)
35
+ .option('--swe-bench-model-name <name>', text.cli.sweBenchModelNameOption)
36
+ .option('--swe-bench-predictions <path>', text.cli.sweBenchPredictionsOption)
33
37
  .option('--headless-include-tool-input', text.cli.headlessIncludeToolInputOption)
34
38
  .option('--headless-include-tool-output', text.cli.headlessIncludeToolOutputOption)
35
39
  .option('--allow-outside-cache-root', text.cli.allowOutsideCacheRootOption)
@@ -8,13 +8,18 @@ export class AnthropicStreamReporter {
8
8
  repoPath;
9
9
  sessionId;
10
10
  writer;
11
+ includeToolInput;
11
12
  lastTextResult;
12
- assembler = new StreamAssembler();
13
+ assembler;
13
14
  constructor(options = {}) {
14
15
  this.mode = options.mode ?? 'run';
15
16
  this.repoPath = options.repoPath;
16
17
  this.sessionId = options.sessionId ?? randomUUID();
17
18
  this.writer = options.writer ?? createStdoutWriter();
19
+ this.includeToolInput = options.includeToolInput ?? false;
20
+ this.assembler = new StreamAssembler({
21
+ deferToolRequestsUntilExecutionInput: this.includeToolInput,
22
+ });
18
23
  }
19
24
  onStart(instruction) {
20
25
  this.emit(encodeAnthropicStart({
@@ -40,6 +45,7 @@ export class AnthropicStreamReporter {
40
45
  const lines = encodeNormalizedToAnthropicStreamLines({
41
46
  sessionId: this.sessionId,
42
47
  event: normalizedEvent,
48
+ includeToolInput: this.includeToolInput,
43
49
  });
44
50
  for (const line of lines)
45
51
  this.emit(line);
@@ -7,6 +7,7 @@ export class JsonReporter {
7
7
  sessionId;
8
8
  getStructuredOutput;
9
9
  getPayloadOverrides;
10
+ getWarnings;
10
11
  now;
11
12
  writer;
12
13
  startedAt = null;
@@ -18,6 +19,7 @@ export class JsonReporter {
18
19
  this.sessionId = options.sessionId ?? randomUUID();
19
20
  this.getStructuredOutput = options.getStructuredOutput;
20
21
  this.getPayloadOverrides = options.getPayloadOverrides;
22
+ this.getWarnings = options.getWarnings;
21
23
  this.now = options.now ?? (() => new Date());
22
24
  this.writer = options.writer ?? createStdoutWriter();
23
25
  }
@@ -48,6 +50,7 @@ export class JsonReporter {
48
50
  structuredOutput,
49
51
  loopResult: result,
50
52
  overrides,
53
+ warnings: this.getWarnings?.(),
51
54
  });
52
55
  this.writer.writeJsonLine(payload);
53
56
  }
@@ -62,6 +65,7 @@ export class JsonReporter {
62
65
  startedAt,
63
66
  endedAt,
64
67
  error,
68
+ warnings: this.getWarnings?.(),
65
69
  });
66
70
  this.writer.writeJsonLine(payload);
67
71
  }
@@ -10,8 +10,11 @@ export class StreamJsonReporter {
10
10
  now;
11
11
  uuid;
12
12
  writer;
13
+ getWarnings;
13
14
  lastTextResult;
14
- assembler = new StreamAssembler();
15
+ nextEventSeq = 0;
16
+ assembler;
17
+ includeToolInput;
15
18
  constructor(options = {}) {
16
19
  this.mode = options.mode ?? 'run';
17
20
  this.repoPath = options.repoPath;
@@ -19,6 +22,11 @@ export class StreamJsonReporter {
19
22
  this.now = options.now ?? (() => new Date());
20
23
  this.uuid = options.uuid ?? randomUUID;
21
24
  this.writer = options.writer ?? createStdoutWriter();
25
+ this.getWarnings = options.getWarnings;
26
+ this.includeToolInput = options.includeToolInput ?? false;
27
+ this.assembler = new StreamAssembler({
28
+ deferToolRequestsUntilExecutionInput: this.includeToolInput,
29
+ });
22
30
  }
23
31
  onStart(instruction) {
24
32
  this.emit(encodeStreamStart({
@@ -47,6 +55,7 @@ export class StreamJsonReporter {
47
55
  sessionId: this.sessionId,
48
56
  uuid: this.uuid,
49
57
  event: normalizedEvent,
58
+ includeToolInput: this.includeToolInput,
50
59
  });
51
60
  for (const line of lines)
52
61
  this.emit(line);
@@ -76,6 +85,7 @@ export class StreamJsonReporter {
76
85
  loopResult: result,
77
86
  at,
78
87
  resultText: this.lastTextResult,
88
+ warnings: this.getWarnings?.(),
79
89
  });
80
90
  this.emit(resultLine);
81
91
  const exitCode = getStreamExitCode(result);
@@ -88,6 +98,7 @@ export class StreamJsonReporter {
88
98
  }));
89
99
  }
90
100
  onError(error) {
101
+ const auditPath = typeof error.auditPath === 'string' ? error.auditPath : undefined;
91
102
  this.emit(encodeStreamFailure({
92
103
  uuid: this.uuid(),
93
104
  sessionId: this.sessionId,
@@ -95,6 +106,7 @@ export class StreamJsonReporter {
95
106
  message: error.message,
96
107
  name: error.name,
97
108
  stack: error.stack,
109
+ auditPath,
98
110
  }));
99
111
  this.emit(encodeStreamEnd({
100
112
  uuid: this.uuid(),
@@ -105,7 +117,10 @@ export class StreamJsonReporter {
105
117
  }));
106
118
  }
107
119
  emit(line) {
108
- this.writer.writeJsonLine(line);
120
+ this.writer.writeJsonLine({
121
+ ...line,
122
+ event_seq: line.event_seq ?? this.nextEventSeq++,
123
+ });
109
124
  }
110
125
  }
111
126
  //# sourceMappingURL=stream-json.js.map
@@ -1,17 +1,19 @@
1
+ import { detectHeadlessOutputFromArgv } from './argv/headless-detection.js';
1
2
  import { createCliRuntimeContext } from './cli-runtime-context.js';
2
3
  import { bootstrapProgram } from './program-bootstrap.js';
3
4
  import { registerProgramCommands } from './program-commands.js';
4
5
  import { configureGlobalProgramOptions } from './program-options.js';
5
6
  import { configureProgramOutputForHeadless } from './program-output-mode.js';
6
7
  import { parseProgramOrExit } from './program-parse.js';
7
- export function buildCliProgram() {
8
- const program = bootstrapProgram();
8
+ export function buildCliProgram(argv = process.argv) {
9
+ const headlessDetection = detectHeadlessOutputFromArgv(argv);
10
+ const program = bootstrapProgram({ headlessDetection });
9
11
  configureGlobalProgramOptions(program);
10
12
  registerProgramCommands(program);
11
13
  return program;
12
14
  }
13
15
  export function createCliContextFromArgv(argv) {
14
- const program = buildCliProgram();
16
+ const program = buildCliProgram(argv);
15
17
  return createCliRuntimeContext(program, argv);
16
18
  }
17
19
  export async function executeCliContext(context) {
@@ -5,14 +5,22 @@ import { text } from '../locales/index.js';
5
5
  function isSafeSkillId(id) {
6
6
  return /^[a-z0-9][a-z0-9-_]*$/i.test(id);
7
7
  }
8
- function skillToSlashSpec(skill) {
9
- const id = String(skill.id || '').trim();
8
+ /**
9
+ * Build a SlashCommandSpec from a Tier 1 catalog entry (lightweight metadata).
10
+ *
11
+ * This supports the AgentSkills progressive disclosure pattern: only name and
12
+ * description are needed at startup to populate the slash command registry.
13
+ * Full skill content is loaded on demand via SkillLoader.activateSkill().
14
+ *
15
+ * @see https://agentskills.io/specification — Progressive disclosure
16
+ */
17
+ function catalogEntryToSlashSpec(entry) {
18
+ const id = String(entry.id || '').trim();
10
19
  if (!id || !isSafeSkillId(id))
11
20
  return null;
12
21
  return {
13
22
  name: `/${id}`,
14
- description: skill.metadata?.description || `Skill: ${id}`,
15
- hidden: skill.metadata?.userInvocable === false,
23
+ description: entry.description || `Skill: ${id}`,
16
24
  order: 220,
17
25
  };
18
26
  }
@@ -28,11 +36,15 @@ function commandToSlashSpec(cmd) {
28
36
  export async function createCliSlashRuntime(options) {
29
37
  const skillLoader = new SkillLoader({
30
38
  repoRoot: options.repoRoot,
31
- useDefaults: options.skillDiscovery?.useDefaults,
32
39
  extraPaths: options.skillDiscovery?.paths,
33
40
  });
34
- const skills = await skillLoader.initialize();
35
- const skillSpecs = skills.map(skillToSlashSpec).filter((s) => Boolean(s));
41
+ // Tier 1: Load lightweight catalog (name + description only, ~50-100 tokens per skill).
42
+ // Full skill content is loaded on demand via activateSkill() (Tier 2).
43
+ // @see https://agentskills.io/specification — Progressive disclosure
44
+ const catalog = await skillLoader.loadCatalog();
45
+ const skillSpecs = catalog
46
+ .map(catalogEntryToSlashSpec)
47
+ .filter((s) => Boolean(s));
36
48
  const commandSpecs = options.baseCommands.map(commandToSlashSpec);
37
49
  // /help is best-effort and must reflect the effective registry (including skills).
38
50
  const helpSpec = {
@@ -51,11 +63,11 @@ export async function createCliSlashRuntime(options) {
51
63
  }
52
64
  }
53
65
  const skillBySlash = new Map();
54
- for (const skill of skills) {
55
- const spec = skillToSlashSpec(skill);
66
+ for (const entry of catalog) {
67
+ const spec = catalogEntryToSlashSpec(entry);
56
68
  if (!spec)
57
69
  continue;
58
- skillBySlash.set(spec.name.toLowerCase(), skill);
70
+ skillBySlash.set(spec.name.toLowerCase(), entry);
59
71
  }
60
72
  const handlers = {
61
73
  getHandler(commandName) {
@@ -115,10 +127,13 @@ export async function createCliSlashRuntime(options) {
115
127
  : undefined,
116
128
  };
117
129
  }
118
- const skill = skillBySlash.get(normalized);
119
- if (skill) {
130
+ const catalogEntry = skillBySlash.get(normalized);
131
+ if (catalogEntry) {
120
132
  return {
121
133
  execute: async (req) => {
134
+ // Tier 2: Activate skill on demand — load full SKILL.md content.
135
+ // @see https://agentskills.io/specification — Progressive disclosure
136
+ const skill = await skillLoader.activateSkill(catalogEntry.id);
122
137
  const meta = (req.meta ?? {});
123
138
  const signal = meta?.signal;
124
139
  // Prepare an isolated worktree environment for governed shell execution.
@@ -9,6 +9,7 @@ import { useCommandSuggestions } from '../hooks/useCommandSuggestions.js';
9
9
  import { useInputHistory } from '../hooks/useInputHistory.js';
10
10
  import { rejectSelection, resolveSelection } from '../selection/bus.js';
11
11
  import { useUIStore } from '../store/context.js';
12
+ import { COLORS } from '../styles/theme.js';
12
13
  import { CommandSuggestionList } from './CommandSuggestionList.js';
13
14
  export const CommandInput = ({ value, onChange, onSubmit, placeholder, getSuggestions, findCommand, }) => {
14
15
  const { state, dispatch } = useUIStore();
@@ -185,16 +186,19 @@ export const CommandInput = ({ value, onChange, onSubmit, placeholder, getSugges
185
186
  : en.gui.selectionPlaceholder
186
187
  : isIntercepting && activeChallenge
187
188
  ? en.gui.confirmationChallenge(activeChallenge)
188
- : placeholder }, inputKey), ghostText && (_jsx(Text, { color: "gray", dimColor: true, children: ghostText }))] }), isIntercepting && (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [_jsx(Text, { color: "yellow", bold: true, children: isSelecting
189
+ : placeholder }, inputKey), ghostText && (_jsx(Text, { color: COLORS.text.muted, dimColor: true, children: ghostText }))] }), isIntercepting && (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: COLORS.semantic.yellow, paddingX: 1, children: [_jsx(Text, { color: COLORS.semantic.yellow, bold: true, children: isSelecting
189
190
  ? pendingSelection?.title
190
191
  : isAuthorizing
191
192
  ? en.gui.authorizationTitle
192
- : en.gui.confirmationTitle }), !isSelecting && (_jsx(Text, { color: "white", children: isAuthorizing ? pendingAuthorization?.message : pendingConfirmation?.message })), _jsx(Text, { color: "gray", dimColor: true, children: isSelecting
193
+ : en.gui.confirmationTitle }), !isSelecting && (_jsx(Text, { color: COLORS.text.primary, children: isAuthorizing ? pendingAuthorization?.message : pendingConfirmation?.message })), _jsx(Text, { color: COLORS.text.muted, dimColor: true, children: isSelecting
193
194
  ? isMultiSelecting
194
195
  ? en.gui.selectionHintMulti
195
196
  : en.gui.selectionHint
196
197
  : isAuthorizing
197
198
  ? en.gui.authorizationWarning
198
- : en.gui.highRiskWarning }), isAuthorizing && (_jsx(Text, { color: "gray", dimColor: true, children: en.gui.authorizationHint })), isSelecting && pendingSelection && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: pendingSelection.items.map((item, idx) => (_jsxs(Text, { color: idx === selectionIndex ? 'green' : 'gray', children: [isMultiSelecting && (_jsx(Text, { color: selectedItems.includes(item.id) ? 'green' : 'gray', children: selectedItems.includes(item.id) ? '[x] ' : '[ ] ' })), item.label, item.description ? ` - ${item.description}` : ''] }, item.id))) }))] })), !isIntercepting && suggestions.length > 0 && !isListClosed && (_jsx(CommandSuggestionList, { suggestions: visibleSuggestions, selectedIndex: selectedIndex - startIndex, parentCommand: activeCommand }))] }));
199
+ : en.gui.highRiskWarning }), isAuthorizing && (_jsx(Text, { color: COLORS.text.muted, dimColor: true, children: en.gui.authorizationHint })), isSelecting && pendingSelection && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: pendingSelection.items.map((item, idx) => {
200
+ const isSelected = idx === selectionIndex;
201
+ return (_jsxs(Text, { color: isSelected ? COLORS.semantic.cyan : COLORS.text.muted, children: [isSelected ? '❯ ' : ' ', isMultiSelecting && (_jsx(Text, { color: selectedItems.includes(item.id) ? COLORS.semantic.cyan : COLORS.text.muted, children: selectedItems.includes(item.id) ? '[x] ' : '[ ] ' })), item.label, item.description ? ` - ${item.description}` : ''] }, item.id));
202
+ }) }))] })), !isIntercepting && suggestions.length > 0 && !isListClosed && (_jsx(CommandSuggestionList, { suggestions: visibleSuggestions, selectedIndex: selectedIndex - startIndex, parentCommand: activeCommand }))] }));
199
203
  };
200
204
  //# sourceMappingURL=CommandInput.js.map
@@ -14,7 +14,7 @@ export const CommandSuggestionList = ({ suggestions, selectedIndex, parentComman
14
14
  return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: COLORS.border.subtle, marginTop: 0, marginBottom: 0, paddingX: 0, width: "100%", children: [_jsx(Box, { flexDirection: "column", paddingY: 0, children: suggestions.map((item, index) => {
15
15
  const isSelected = index === selectedIndex;
16
16
  const hasSubcommands = !!item.command?.subcommands?.length;
17
- return (_jsxs(Box, { flexDirection: "row", paddingX: 1, children: [_jsx(Box, { width: 2, children: _jsx(Text, { color: COLORS.semantic.salmon, children: isSelected ? '│ ' : ' ' }) }), _jsx(Box, { width: maxNameLength + 4, children: _jsx(Text, { color: isSelected ? COLORS.semantic.cyan : COLORS.semantic.blue, bold: isSelected, children: item.name }) }), _jsx(Box, { width: 2, marginRight: 1, children: hasSubcommands ? _jsx(Text, { color: COLORS.text.muted, children: " " }) : _jsx(Text, { children: " " }) }), _jsx(Box, { flexGrow: 1, children: _jsx(Text, { color: isSelected ? COLORS.text.primary : COLORS.text.muted, wrap: "truncate", children: item.description }) })] }, `${item.name}-${index}`));
17
+ return (_jsxs(Box, { flexDirection: "row", paddingX: 1, children: [_jsx(Box, { width: 2, children: _jsx(Text, { color: COLORS.semantic.salmon, children: isSelected ? '│ ' : ' ' }) }), _jsx(Box, { width: maxNameLength + 4, children: _jsx(Text, { color: isSelected ? COLORS.semantic.cyan : COLORS.semantic.blue, bold: isSelected, children: item.name }) }), _jsx(Box, { width: 2, marginRight: 1, children: hasSubcommands ? _jsx(Text, { color: COLORS.text.muted, children: "\u203A" }) : _jsx(Text, { children: " " }) }), _jsx(Box, { flexGrow: 1, children: _jsx(Text, { color: isSelected ? COLORS.text.primary : COLORS.text.muted, wrap: "truncate", children: item.description }) })] }, `${item.name}-${index}`));
18
18
  }) }), suggestions[selectedIndex]?.command?.usage && (_jsxs(Box, { flexDirection: "row", borderStyle: "single", borderTop: true, borderLeft: false, borderRight: false, borderBottom: false, borderColor: COLORS.border.subtle, paddingX: 1, paddingY: 0, children: [_jsx(Text, { color: COLORS.semantic.blue, children: "TIP: " }), _jsx(Text, { color: COLORS.text.muted, children: "Usage: " }), _jsx(Text, { color: COLORS.text.primary, children: suggestions[selectedIndex].command?.usage })] })), _jsxs(Box, { flexDirection: "row", borderStyle: "single", borderTop: true, borderLeft: false, borderRight: false, borderBottom: false, borderColor: COLORS.border.subtle, paddingX: 1, paddingY: 0, justifyContent: "space-between", children: [_jsxs(Box, { children: [_jsx(Text, { color: COLORS.semantic.salmon, children: "\u2502 " }), _jsx(Text, { color: COLORS.semantic.blue, bold: true, children: title })] }), _jsx(Box, { children: _jsx(Text, { color: COLORS.text.muted, dimColor: true, children: "\u2191\u2193 nav \u00B7 \u23CE select \u00B7 esc close" }) })] })] }));
19
19
  };
20
20
  //# sourceMappingURL=CommandSuggestionList.js.map
@@ -0,0 +1,13 @@
1
+ export function getOptionValueSourceWithGlobalFallback(command, optionName) {
2
+ if (typeof command.getOptionValueSource === 'function') {
3
+ const direct = command.getOptionValueSource(optionName);
4
+ if (direct)
5
+ return direct;
6
+ }
7
+ const parent = command.parent;
8
+ if (parent && typeof parent.getOptionValueSource === 'function') {
9
+ return parent.getOptionValueSource(optionName);
10
+ }
11
+ return undefined;
12
+ }
13
+ //# sourceMappingURL=command-option-source.js.map
@@ -1,4 +1,4 @@
1
- import { getLogger } from '../../core/facades/cli-observability.js';
1
+ import { tryGetLogger } from '../../core/facades/cli-observability.js';
2
2
  import { text } from '../../locales/index.js';
3
3
  import { autoDetectVerifyCommand } from './detectors/index.js';
4
4
  /**
@@ -8,11 +8,11 @@ import { autoDetectVerifyCommand } from './detectors/index.js';
8
8
  * 3. Config file command -> "cmd"
9
9
  * 4. Auto-detection -> "detected-cmd"
10
10
  */
11
- export async function resolveVerifyOption(repoPath, cliVerify, configVerify) {
11
+ export async function resolveVerifyOption(repoPath, cliVerify, configVerify, options = {}) {
12
12
  // 1. Explicitly disabled via --no-verify
13
13
  // Commander sets options.verify to false when --no-verify is used
14
14
  if (cliVerify === false) {
15
- getLogger().debug(text.verify.explicitlyDisabled);
15
+ tryGetLogger()?.debug(text.verify.explicitlyDisabled);
16
16
  return undefined;
17
17
  }
18
18
  // 2. Explicitly provided via CLI --verify "cmd"
@@ -26,7 +26,11 @@ export async function resolveVerifyOption(repoPath, cliVerify, configVerify) {
26
26
  // 4. Auto-detect
27
27
  const detected = await autoDetectVerifyCommand(repoPath);
28
28
  if (detected) {
29
- getLogger().info(text.verify.autoDetected(detected));
29
+ const logger = tryGetLogger();
30
+ if (options.quiet)
31
+ logger?.debug(text.verify.autoDetected(detected));
32
+ else
33
+ logger?.info(text.verify.autoDetected(detected));
30
34
  return detected;
31
35
  }
32
36
  return undefined;
@@ -1,7 +1,7 @@
1
- import { getLogger } from '../../core/facades/cli-utils-worktree.js';
1
+ import { tryGetLogger } from '../../core/facades/cli-utils-worktree.js';
2
2
  import { text } from '../../locales/index.js';
3
3
  import { autoDetectWorktreePrepareCommand } from './detectors/index.js';
4
- export async function resolveWorktreePrepareOption(repoPath, strategy, cliWorktreePrepare) {
4
+ export async function resolveWorktreePrepareOption(repoPath, strategy, cliWorktreePrepare, options = {}) {
5
5
  if (typeof cliWorktreePrepare === 'string' && cliWorktreePrepare.trim()) {
6
6
  return cliWorktreePrepare;
7
7
  }
@@ -10,7 +10,11 @@ export async function resolveWorktreePrepareOption(repoPath, strategy, cliWorktr
10
10
  }
11
11
  const detected = await autoDetectWorktreePrepareCommand(repoPath);
12
12
  if (detected) {
13
- getLogger().info(text.verify.autoDetectedWorktreePrepare(detected));
13
+ const logger = tryGetLogger();
14
+ if (options.quiet)
15
+ logger?.debug(text.verify.autoDetectedWorktreePrepare(detected));
16
+ else
17
+ logger?.info(text.verify.autoDetectedWorktreePrepare(detected));
14
18
  return detected;
15
19
  }
16
20
  return undefined;
@@ -73,6 +73,12 @@ export class FileAdapter {
73
73
  async stat(filePath) {
74
74
  return fs.stat(filePath);
75
75
  }
76
+ /**
77
+ * Get file stats without following symlinks.
78
+ */
79
+ async lstat(filePath) {
80
+ return fs.lstat(filePath);
81
+ }
76
82
  /**
77
83
  * Create directory recursively
78
84
  */
@@ -1,3 +1,4 @@
1
+ import { resolveExecutionProfile } from '../../runtime/execution-profile.js';
1
2
  import { FileAdapter } from './file-adapter.js';
2
3
  import { ReadOnlyFileSystem } from './readonly-filesystem.js';
3
4
  class FileAdapterFileSystem {
@@ -23,7 +24,7 @@ class FileAdapterFileSystem {
23
24
  * Review mode returns a ReadOnlyFileSystem to block writes.
24
25
  */
25
26
  export function createFileSystemAdapter(mode, realFs = new FileAdapterFileSystem()) {
26
- if (mode === 'review' || mode === 'research' || mode === 'answer') {
27
+ if (resolveExecutionProfile(mode).readOnly) {
27
28
  return new ReadOnlyFileSystem(realFs);
28
29
  }
29
30
  return realFs;