salmon-loop 0.2.3 → 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 (234) 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 +161 -24
  4. package/dist/cli/commands/chat.js +30 -24
  5. package/dist/cli/commands/context.js +15 -3
  6. package/dist/cli/commands/flow-mode.js +63 -0
  7. package/dist/cli/commands/help-format.js +12 -0
  8. package/dist/cli/commands/registry.js +6 -7
  9. package/dist/cli/commands/run/benchmark-artifacts.js +41 -0
  10. package/dist/cli/commands/run/config-resolution.js +30 -24
  11. package/dist/cli/commands/run/early-errors.js +23 -0
  12. package/dist/cli/commands/run/handler.js +131 -44
  13. package/dist/cli/commands/run/headless-error-writer.js +8 -0
  14. package/dist/cli/commands/run/loop-params.js +3 -0
  15. package/dist/cli/commands/run/mode.js +2 -5
  16. package/dist/cli/commands/run/parse-options.js +18 -2
  17. package/dist/cli/commands/run/persist-session.js +10 -1
  18. package/dist/cli/commands/run/preflight.js +10 -0
  19. package/dist/cli/commands/run/reporter-factory.js +4 -0
  20. package/dist/cli/commands/run/runtime-llm.js +38 -11
  21. package/dist/cli/commands/run/runtime-options.js +2 -2
  22. package/dist/cli/commands/run/validate-options.js +0 -5
  23. package/dist/cli/commands/run/verbose.js +2 -7
  24. package/dist/cli/commands/serve.js +117 -90
  25. package/dist/cli/commands/tool-names.js +78 -78
  26. package/dist/cli/headless/anthropic-stream-normalized-encoder.js +6 -1
  27. package/dist/cli/headless/json-protocol.js +37 -0
  28. package/dist/cli/headless/native-stream-normalized-encoder.js +6 -1
  29. package/dist/cli/headless/protocol-metadata.js +22 -0
  30. package/dist/cli/headless/stream-json-protocol.js +34 -1
  31. package/dist/cli/index.js +6 -4
  32. package/dist/cli/locales/en.js +32 -6
  33. package/dist/cli/program-bootstrap.js +14 -4
  34. package/dist/cli/program-commands.js +9 -1
  35. package/dist/cli/program-options.js +1 -0
  36. package/dist/cli/reporters/anthropic-stream.js +7 -1
  37. package/dist/cli/reporters/json.js +4 -0
  38. package/dist/cli/reporters/stream-json.js +17 -2
  39. package/dist/cli/run-cli.js +5 -3
  40. package/dist/cli/slash/runtime.js +30 -15
  41. package/dist/cli/ui/components/CommandInput.js +7 -3
  42. package/dist/cli/ui/components/CommandSuggestionList.js +1 -1
  43. package/dist/cli/utils/command-option-source.js +13 -0
  44. package/dist/cli/utils/output-format.js +6 -0
  45. package/dist/cli/utils/resolve-cli-config.js +98 -0
  46. package/dist/cli/utils/verbose-level.js +8 -0
  47. package/dist/cli/utils/verify-resolver.js +8 -4
  48. package/dist/cli/utils/worktree-prepare-resolver.js +7 -3
  49. package/dist/core/adapters/fs/file-adapter.js +6 -0
  50. package/dist/core/adapters/fs/filesystem.js +2 -1
  51. package/dist/core/adapters/git/git-adapter.js +78 -1
  52. package/dist/core/benchmark/patch-artifact.js +124 -0
  53. package/dist/core/benchmark/swe-bench.js +25 -0
  54. package/dist/core/config/load.js +39 -18
  55. package/dist/core/config/merge.js +27 -0
  56. package/dist/core/config/paths.js +24 -5
  57. package/dist/core/config/resolve-llm.js +12 -0
  58. package/dist/core/config/resolve.js +7 -5
  59. package/dist/core/config/resolvers/server.js +0 -6
  60. package/dist/core/config/validate.js +94 -21
  61. package/dist/core/context/gatherers/metadata-gatherer.js +1 -0
  62. package/dist/core/context/gatherers/ripgrep-gatherer.js +84 -2
  63. package/dist/core/context/keywords.js +18 -4
  64. package/dist/core/context/service-deps.js +2 -2
  65. package/dist/core/context/service.js +8 -0
  66. package/dist/core/context/steps/context-gather.js +38 -0
  67. package/dist/core/context/summarization/summarizer.js +55 -12
  68. package/dist/core/context/targeting/target-resolver.js +4 -4
  69. package/dist/core/extensions/index.js +23 -5
  70. package/dist/core/extensions/paths.js +31 -0
  71. package/dist/core/extensions/schemas.js +8 -5
  72. package/dist/core/facades/cli-chat.js +6 -2
  73. package/dist/core/facades/cli-command-chat.js +2 -1
  74. package/dist/core/facades/cli-command-tool-names.js +2 -0
  75. package/dist/core/facades/cli-context.js +1 -0
  76. package/dist/core/facades/cli-observability.js +1 -1
  77. package/dist/core/facades/cli-run-handler.js +4 -2
  78. package/dist/core/facades/cli-run-persist-session.js +1 -0
  79. package/dist/core/facades/cli-serve.js +2 -4
  80. package/dist/core/facades/cli-utils-worktree.js +1 -1
  81. package/dist/core/failure/diagnostics.js +53 -1
  82. package/dist/core/grizzco/dsl/llm-strategy.js +4 -1
  83. package/dist/core/grizzco/engine/outcome/loop-result-mapper.js +67 -9
  84. package/dist/core/grizzco/engine/pipeline/pipeline.js +6 -2
  85. package/dist/core/grizzco/engine/transaction/attempt-failure.js +90 -15
  86. package/dist/core/grizzco/engine/transaction/report-mapper.js +17 -3
  87. package/dist/core/grizzco/engine/transaction/transaction-runner.js +173 -7
  88. package/dist/core/grizzco/flows/AutopilotFlow.js +18 -0
  89. package/dist/core/grizzco/flows/flow-dispatch.js +11 -0
  90. package/dist/core/grizzco/steps/answer.js +13 -14
  91. package/dist/core/grizzco/steps/autopilot.js +396 -0
  92. package/dist/core/grizzco/steps/cache-sharing.js +29 -0
  93. package/dist/core/grizzco/steps/explore.js +37 -21
  94. package/dist/core/grizzco/steps/generateReview.js +2 -5
  95. package/dist/core/grizzco/steps/patch/apply-check.js +10 -0
  96. package/dist/core/grizzco/steps/patch/diff-normalization.js +70 -0
  97. package/dist/core/grizzco/steps/patch/diff-salvage.js +46 -0
  98. package/dist/core/grizzco/steps/patch/prompt-input.js +42 -0
  99. package/dist/core/grizzco/steps/patch.js +105 -146
  100. package/dist/core/grizzco/steps/plan.js +101 -25
  101. package/dist/core/grizzco/steps/preflight.js +5 -3
  102. package/dist/core/grizzco/steps/request-assembly.js +78 -0
  103. package/dist/core/grizzco/steps/research.js +39 -36
  104. package/dist/core/grizzco/steps/tool-runtime.js +47 -0
  105. package/dist/core/grizzco/steps/verify-shared.js +23 -0
  106. package/dist/core/grizzco/steps/verify.js +13 -21
  107. package/dist/core/intent/chat-intent.js +0 -4
  108. package/dist/core/llm/ai-sdk/chat-executor.js +2 -0
  109. package/dist/core/llm/ai-sdk/high-level-phase-specs.js +63 -0
  110. package/dist/core/llm/ai-sdk/message-mapper.js +40 -10
  111. package/dist/core/llm/ai-sdk/provider-factory.js +14 -0
  112. package/dist/core/llm/ai-sdk/request-params.js +74 -1
  113. package/dist/core/llm/ai-sdk/result-mapper.js +16 -0
  114. package/dist/core/llm/ai-sdk.js +112 -27
  115. package/dist/core/llm/capabilities.js +12 -0
  116. package/dist/core/llm/contracts/repair.js +36 -30
  117. package/dist/core/llm/errors.js +83 -2
  118. package/dist/core/llm/message-composition.js +7 -22
  119. package/dist/core/llm/phase-router.js +29 -10
  120. package/dist/core/llm/redact.js +28 -3
  121. package/dist/core/llm/registry.js +2 -0
  122. package/dist/core/llm/request-augmentation.js +55 -0
  123. package/dist/core/llm/request-envelope.js +334 -0
  124. package/dist/core/llm/shared-request-assembly.js +35 -0
  125. package/dist/core/llm/stream-utils.js +13 -4
  126. package/dist/core/llm/utils.js +18 -29
  127. package/dist/core/memory/relevant-retrieval.js +144 -0
  128. package/dist/core/observability/logger.js +11 -2
  129. package/dist/core/patch/diff.js +1 -0
  130. package/dist/core/prompts/registry.js +39 -2
  131. package/dist/core/prompts/runtime.js +50 -12
  132. package/dist/core/prompts/templates/phases/patch_user.hbs +2 -5
  133. package/dist/core/prompts/templates/phases/research_user.hbs +11 -0
  134. package/dist/core/prompts/templates/phases/review_user.hbs +3 -0
  135. package/dist/core/prompts/templates/system/answer_system.hbs +5 -0
  136. package/dist/core/prompts/templates/system/autopilot_system.hbs +11 -0
  137. package/dist/core/prompts/templates/system/explore_system.hbs +14 -23
  138. package/dist/core/prompts/templates/system/main_system.hbs +4 -16
  139. package/dist/core/prompts/templates/system/patch_system.hbs +39 -8
  140. package/dist/core/prompts/templates/system/plan_system.hbs +86 -1
  141. package/dist/core/prompts/templates/system/research_system.hbs +2 -0
  142. package/dist/core/protocols/a2a/agent-card.js +3 -2
  143. package/dist/core/protocols/a2a/sdk/executor.js +8 -6
  144. package/dist/core/protocols/a2a/sdk/server.js +0 -1
  145. package/dist/core/protocols/acp/formal-agent.js +221 -55
  146. package/dist/core/protocols/acp/handlers.js +5 -1
  147. package/dist/core/protocols/acp/permission-provider.js +21 -1
  148. package/dist/core/protocols/shared/execution-request.js +24 -0
  149. package/dist/core/protocols/shared/flow-mode-mapping.js +23 -0
  150. package/dist/core/public-capabilities/flow-mode-metadata.js +39 -0
  151. package/dist/core/public-capabilities/projections.js +29 -0
  152. package/dist/core/public-capabilities/registry.js +26 -0
  153. package/dist/core/public-capabilities/types.js +2 -0
  154. package/dist/core/runtime/agent-server-runtime.js +47 -43
  155. package/dist/core/runtime/execution-profile.js +67 -0
  156. package/dist/core/session/artifact-state.js +160 -0
  157. package/dist/core/session/compaction/index.js +183 -0
  158. package/dist/core/session/compaction/microcompact.js +78 -0
  159. package/dist/core/session/compaction/tracking.js +48 -0
  160. package/dist/core/session/compaction/types.js +11 -0
  161. package/dist/core/session/compression.js +12 -4
  162. package/dist/core/session/manager.js +247 -10
  163. package/dist/core/session/pruning-strategy.js +55 -9
  164. package/dist/core/session/replacement-preview-provider.js +24 -0
  165. package/dist/core/session/replacement-state.js +131 -0
  166. package/dist/core/session/resume-repair/pipeline.js +79 -0
  167. package/dist/core/session/resume-repair/stages/load-raw-archive-state.js +40 -0
  168. package/dist/core/session/resume-repair/stages/reattach-runtime-state.js +8 -0
  169. package/dist/core/session/resume-repair/stages/recover-orphaned-branches.js +10 -0
  170. package/dist/core/session/resume-repair/stages/relink-boundary-and-tail.js +36 -0
  171. package/dist/core/session/resume-repair/stages/replay-startup-hooks.js +23 -0
  172. package/dist/core/session/resume-repair/stages/rescue-stale-metadata.js +17 -0
  173. package/dist/core/session/resume-repair/types.js +2 -0
  174. package/dist/core/session/summary-sync.js +164 -13
  175. package/dist/core/session/token-tracker.js +6 -0
  176. package/dist/core/skills/audit.js +34 -0
  177. package/dist/core/skills/bridge.js +84 -7
  178. package/dist/core/skills/discovery.js +94 -0
  179. package/dist/core/skills/feature-flags.js +52 -0
  180. package/dist/core/skills/index.js +1 -1
  181. package/dist/core/skills/loader.js +195 -20
  182. package/dist/core/skills/parser.js +296 -24
  183. package/dist/core/skills/permissions.js +117 -0
  184. package/dist/core/skills/runtime/MicroTaskRunner.js +10 -4
  185. package/dist/core/skills/runtime/SkillRunner.js +240 -61
  186. package/dist/core/strata/layers/shadow-driver/shadow-driver.js +37 -7
  187. package/dist/core/strata/layers/worktree.js +70 -13
  188. package/dist/core/strata/runtime/synchronizer.js +29 -2
  189. package/dist/core/streaming/stream-assembler.js +75 -31
  190. package/dist/core/sub-agent/context-snapshot.js +156 -0
  191. package/dist/core/sub-agent/core/loop.js +1 -1
  192. package/dist/core/sub-agent/core/manager.js +119 -20
  193. package/dist/core/sub-agent/dispatch-policy.js +29 -0
  194. package/dist/core/sub-agent/prefix-consistency.js +48 -0
  195. package/dist/core/sub-agent/registry-defaults.js +4 -0
  196. package/dist/core/sub-agent/tools/task-spawn.js +79 -2
  197. package/dist/core/sub-agent/types.js +134 -5
  198. package/dist/core/tools/audit.js +13 -4
  199. package/dist/core/tools/builtin/ast-grep.js +1 -1
  200. package/dist/core/tools/builtin/ast.js +1 -1
  201. package/dist/core/tools/builtin/benchmark.js +360 -0
  202. package/dist/core/tools/builtin/code-search/backends/rg.js +2 -1
  203. package/dist/core/tools/builtin/code-search/executor.js +6 -1
  204. package/dist/core/tools/builtin/code-search/spec.js +26 -2
  205. package/dist/core/tools/builtin/fs.js +256 -23
  206. package/dist/core/tools/builtin/git.js +2 -2
  207. package/dist/core/tools/builtin/index.js +51 -2
  208. package/dist/core/tools/builtin/interaction.js +8 -1
  209. package/dist/core/tools/builtin/plan.js +37 -15
  210. package/dist/core/tools/builtin/shell.js +1 -1
  211. package/dist/core/tools/loader.js +39 -16
  212. package/dist/core/tools/mapper.js +17 -3
  213. package/dist/core/tools/parallel/scheduler.js +35 -4
  214. package/dist/core/tools/permissions/permission-rules.js +5 -10
  215. package/dist/core/tools/policy.js +6 -1
  216. package/dist/core/tools/recoverable-tool-errors.js +10 -0
  217. package/dist/core/tools/router.js +24 -6
  218. package/dist/core/tools/session.js +458 -48
  219. package/dist/core/tools/tool-visibility.js +62 -0
  220. package/dist/core/tools/types.js +9 -1
  221. package/dist/core/types/execution.js +4 -0
  222. package/dist/core/types/flow-mode.js +8 -0
  223. package/dist/core/utils/path.js +52 -0
  224. package/dist/core/verification/runner.js +4 -1
  225. package/dist/interfaces/cli/task-runner.js +4 -3
  226. package/dist/languages/typescript/index.js +4 -1
  227. package/dist/locales/en.js +87 -2
  228. package/dist/utils/eol.js +1 -1
  229. package/package.json +15 -8
  230. package/scripts/fix-es-abstract-compat.js +77 -0
  231. package/dist/core/runtime/fastify-server-bundle.js +0 -26
  232. package/dist/core/runtime/sidecar-fastify-plugin.js +0 -35
  233. package/dist/core/runtime/sidecar-paths.js +0 -47
  234. package/dist/core/runtime/sidecar-route-catalog.js +0 -103
@@ -1,17 +1,26 @@
1
1
  import { createSlashRegistry, createStandardToolstack, executeSkill, logIgnoredError, getLogger, RuntimeEnvironment, SkillLoader, SlashRouter, } from '../../core/facades/cli-slash-runtime.js';
2
+ import { formatHelpRows } from '../commands/help-format.js';
2
3
  import { suggestSubcommands } from '../commands/subcommand-suggestions.js';
3
4
  import { text } from '../locales/index.js';
4
5
  function isSafeSkillId(id) {
5
6
  return /^[a-z0-9][a-z0-9-_]*$/i.test(id);
6
7
  }
7
- function skillToSlashSpec(skill) {
8
- 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();
9
19
  if (!id || !isSafeSkillId(id))
10
20
  return null;
11
21
  return {
12
22
  name: `/${id}`,
13
- description: skill.metadata?.description || `Skill: ${id}`,
14
- hidden: skill.metadata?.userInvocable === false,
23
+ description: entry.description || `Skill: ${id}`,
15
24
  order: 220,
16
25
  };
17
26
  }
@@ -27,11 +36,15 @@ function commandToSlashSpec(cmd) {
27
36
  export async function createCliSlashRuntime(options) {
28
37
  const skillLoader = new SkillLoader({
29
38
  repoRoot: options.repoRoot,
30
- useDefaults: options.skillDiscovery?.useDefaults,
31
39
  extraPaths: options.skillDiscovery?.paths,
32
40
  });
33
- const skills = await skillLoader.initialize();
34
- 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));
35
48
  const commandSpecs = options.baseCommands.map(commandToSlashSpec);
36
49
  // /help is best-effort and must reflect the effective registry (including skills).
37
50
  const helpSpec = {
@@ -50,11 +63,11 @@ export async function createCliSlashRuntime(options) {
50
63
  }
51
64
  }
52
65
  const skillBySlash = new Map();
53
- for (const skill of skills) {
54
- const spec = skillToSlashSpec(skill);
66
+ for (const entry of catalog) {
67
+ const spec = catalogEntryToSlashSpec(entry);
55
68
  if (!spec)
56
69
  continue;
57
- skillBySlash.set(spec.name.toLowerCase(), skill);
70
+ skillBySlash.set(spec.name.toLowerCase(), entry);
58
71
  }
59
72
  const handlers = {
60
73
  getHandler(commandName) {
@@ -63,12 +76,11 @@ export async function createCliSlashRuntime(options) {
63
76
  const handler = {
64
77
  execute: async (_req) => {
65
78
  const visible = registry.list().filter((c) => !c.hidden);
66
- const maxName = Math.max(...visible.map((c) => c.name.length), 0);
67
- const rows = visible.map((c) => `${c.name}`.padEnd(maxName + 2) + c.description);
79
+ const rows = formatHelpRows(visible);
68
80
  options.emit({
69
81
  type: 'log',
70
82
  level: 'info',
71
- message: text.cli.helpAvailableCommands(rows.join('\n')),
83
+ message: text.cli.helpAvailableCommands(rows),
72
84
  timestamp: new Date(),
73
85
  });
74
86
  return { kind: 'consumed' };
@@ -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
@@ -0,0 +1,6 @@
1
+ export function resolveOutputFormat(raw) {
2
+ if (raw === 'text' || raw === 'stream-json' || raw === 'json')
3
+ return raw;
4
+ return undefined;
5
+ }
6
+ //# sourceMappingURL=output-format.js.map
@@ -0,0 +1,98 @@
1
+ import { defaultPathAdapter } from '../../core/adapters/path/path-adapter.js';
2
+ import { ConfigError, normalizeUiLogMode, resolveConfig } from '../../core/config/index.js';
3
+ import { text } from '../locales/index.js';
4
+ import { resolveAuditScope } from './audit-scope.js';
5
+ import { resolveOutputFormat } from './output-format.js';
6
+ import { resolveVerboseLevel } from './verbose-level.js';
7
+ export async function resolveCliConfig(params) {
8
+ const common = resolveCliCommonOptions({
9
+ repoPath: params.repoPath,
10
+ repo: params.repo,
11
+ cwd: params.cwd,
12
+ verbose: params.verbose,
13
+ outputFormat: params.outputFormat,
14
+ });
15
+ if (!common.ok) {
16
+ return { ok: false, message: common.message };
17
+ }
18
+ const { repoPath, verboseLevel, outputFormat, headlessOutput } = common.options;
19
+ let resolvedConfig;
20
+ try {
21
+ resolvedConfig = await resolveConfig({
22
+ repoRoot: repoPath,
23
+ configFilePath: params.configPath,
24
+ enableConfigFile: params.enableConfigFile !== false,
25
+ });
26
+ }
27
+ catch (err) {
28
+ if (err instanceof ConfigError) {
29
+ return {
30
+ ok: false,
31
+ message: text.config.error(err.code || err.message, err.details),
32
+ errorCode: err.code,
33
+ };
34
+ }
35
+ const msg = err instanceof Error ? err.message : String(err);
36
+ return { ok: false, message: text.config.loadFailed(msg) };
37
+ }
38
+ const auditScopeResolution = resolveAuditScope({
39
+ cliValue: params.auditScope,
40
+ configValue: resolvedConfig.observability.audit.scope,
41
+ });
42
+ if (!auditScopeResolution.ok) {
43
+ return {
44
+ ok: false,
45
+ message: text.cli.invalidAuditScope(auditScopeResolution.invalid),
46
+ };
47
+ }
48
+ if (params.logMode !== undefined) {
49
+ const normalized = normalizeUiLogMode(params.logMode);
50
+ if (!normalized) {
51
+ return { ok: false, message: text.cli.logModeInvalid(String(params.logMode)) };
52
+ }
53
+ resolvedConfig = {
54
+ ...resolvedConfig,
55
+ ui: {
56
+ ...resolvedConfig.ui,
57
+ logMode: normalized,
58
+ },
59
+ };
60
+ }
61
+ return {
62
+ ok: true,
63
+ repoPath,
64
+ verboseLevel,
65
+ outputFormat,
66
+ headlessOutput,
67
+ resolvedConfig,
68
+ auditScope: auditScopeResolution.value,
69
+ };
70
+ }
71
+ export function resolveRepoPath(params) {
72
+ return defaultPathAdapter.resolve(params.repo || params.cwd || process.cwd());
73
+ }
74
+ export function resolveCliCommonOptions(params) {
75
+ const repoPath = params.repoPath ?? resolveRepoPath({ repo: params.repo, cwd: params.cwd });
76
+ const verboseLevel = resolveVerboseLevel(params.verbose);
77
+ let outputFormat;
78
+ let headlessOutput;
79
+ if (params.outputFormat !== undefined) {
80
+ const raw = String(params.outputFormat || '');
81
+ const resolved = resolveOutputFormat(raw);
82
+ if (!resolved) {
83
+ return { ok: false, message: text.cli.invalidOutputFormat(raw) };
84
+ }
85
+ outputFormat = resolved;
86
+ headlessOutput = resolved !== 'text';
87
+ }
88
+ return {
89
+ ok: true,
90
+ options: {
91
+ repoPath,
92
+ verboseLevel,
93
+ outputFormat,
94
+ headlessOutput,
95
+ },
96
+ };
97
+ }
98
+ //# sourceMappingURL=resolve-cli-config.js.map
@@ -0,0 +1,8 @@
1
+ export function resolveVerboseLevel(raw) {
2
+ if (raw === true)
3
+ return 'basic';
4
+ if (typeof raw === 'string')
5
+ return raw;
6
+ return undefined;
7
+ }
8
+ //# sourceMappingURL=verbose-level.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;
@@ -8,7 +8,7 @@ import { LIMITS } from '../../config/limits.js';
8
8
  import { logIgnoredError } from '../../observability/ignored-error.js';
9
9
  import { getLogger } from '../../observability/logger.js';
10
10
  import { GitError } from '../../types/index.js';
11
- import { isPathWithinDirectory, normalizePath } from '../../utils/path.js';
11
+ import { isPathWithinDirectory, isSafeRelativePath, normalizePath } from '../../utils/path.js';
12
12
  import { runGitCommand } from './git-runner.js';
13
13
  import { FileHandleManager } from './lock-manager.js';
14
14
  // Singleton map to ensure one lock manager per repository path
@@ -126,6 +126,32 @@ export class GitAdapter {
126
126
  this.assertQueryAllowed(args);
127
127
  return this.exec(args, options);
128
128
  }
129
+ /**
130
+ * Generate a git-formatted patch for one repo-relative file that is not in
131
+ * the index, without staging or otherwise mutating repository state.
132
+ */
133
+ async diffUntrackedFileAgainstNull(relativePath, options = {}) {
134
+ const normalizedPath = normalizePath(relativePath);
135
+ if (!isSafeRelativePath(normalizedPath)) {
136
+ throw new Error(text.git.securityViolation('diff --no-index'));
137
+ }
138
+ return this.execMeta([
139
+ 'diff',
140
+ '--no-index',
141
+ '--binary',
142
+ '--no-color',
143
+ '--no-ext-diff',
144
+ '--src-prefix=a/',
145
+ '--dst-prefix=b/',
146
+ '--',
147
+ '/dev/null',
148
+ normalizedPath,
149
+ ], {
150
+ cwd: options.cwd,
151
+ limits: options.limits,
152
+ timeoutMs: options.timeoutMs,
153
+ });
154
+ }
129
155
  // ==================== Business Layer ====================
130
156
  /**
131
157
  * Generates a blob hash for the given content without writing to the object database.
@@ -363,6 +389,54 @@ export class GitAdapter {
363
389
  await this.lockManager.releaseLock(this.repoPath);
364
390
  }
365
391
  }
392
+ async checkPatchApplyability(diffText, options = {}) {
393
+ const tempFile = path.join(tmpdir(), `salmon-patch-check-${Date.now()}-${randomBytes(4).toString('hex')}.patch`);
394
+ const tempIndex = path.join(tmpdir(), `salmon-patch-check-index-${Date.now()}-${randomBytes(4).toString('hex')}`);
395
+ await fs.writeFile(tempFile, diffText, 'utf8');
396
+ try {
397
+ const readTree = await this.execMeta(['read-tree', 'HEAD'], {
398
+ env: { ...options.env, GIT_INDEX_FILE: tempIndex },
399
+ limits: { maxStdoutBytes: LIMITS.maxToolOutputBytes, maxStderrChars: 16_384 },
400
+ timeoutMs: LIMITS.gitTimeoutMs,
401
+ });
402
+ if (!readTree.ok) {
403
+ const output = [readTree.stdout.toString('utf8'), readTree.stderr]
404
+ .filter(Boolean)
405
+ .join('\n')
406
+ .trim();
407
+ return {
408
+ ok: false,
409
+ exitCode: readTree.code,
410
+ output,
411
+ };
412
+ }
413
+ const args = ['apply', '--cached', '--check', '--recount'];
414
+ if (options.ignoreWhitespace)
415
+ args.push('--ignore-whitespace');
416
+ if (options.contextLines)
417
+ args.push(`-C${options.contextLines}`);
418
+ args.push(tempFile);
419
+ const res = await this.execMeta(args, {
420
+ env: { ...options.env, GIT_INDEX_FILE: tempIndex },
421
+ limits: { maxStdoutBytes: LIMITS.maxToolOutputBytes, maxStderrChars: 16_384 },
422
+ timeoutMs: LIMITS.gitTimeoutMs,
423
+ });
424
+ const output = [res.stdout.toString('utf8'), res.stderr].filter(Boolean).join('\n').trim();
425
+ return {
426
+ ok: res.ok,
427
+ exitCode: res.code,
428
+ output,
429
+ };
430
+ }
431
+ finally {
432
+ await fs
433
+ .unlink(tempFile)
434
+ .catch((error) => logIgnoredError(`[GitAdapter] cleanup ${tempFile}`, error));
435
+ await fs
436
+ .unlink(tempIndex)
437
+ .catch((error) => logIgnoredError(`[GitAdapter] cleanup ${tempIndex}`, error));
438
+ }
439
+ }
366
440
  /**
367
441
  * Precision rollback protecting staged changes.
368
442
  */
@@ -407,6 +481,9 @@ export class GitAdapter {
407
481
  }
408
482
  }
409
483
  catch (error) {
484
+ if (!this.isShadowWorktreePath()) {
485
+ throw error;
486
+ }
410
487
  try {
411
488
  await this.resolveConflicts();
412
489
  }
@@ -0,0 +1,124 @@
1
+ import { createHash } from 'crypto';
2
+ import { EOL } from 'os';
3
+ import path from 'path';
4
+ import { FileAdapter } from '../adapters/fs/file-adapter.js';
5
+ import { GitAdapter } from '../adapters/git/git-adapter.js';
6
+ import { LIMITS } from '../config/limits.js';
7
+ import { isPathWithinDirectory, isSafeRelativePath, normalizePath } from '../utils/path.js';
8
+ export class BenchmarkPatchArtifactError extends Error {
9
+ constructor(message) {
10
+ super(message);
11
+ this.name = 'BenchmarkPatchArtifactError';
12
+ }
13
+ }
14
+ const DIFF_ARGS = [
15
+ 'diff',
16
+ '--binary',
17
+ '--no-color',
18
+ '--no-ext-diff',
19
+ '--src-prefix=a/',
20
+ '--dst-prefix=b/',
21
+ 'HEAD',
22
+ '--',
23
+ '.',
24
+ ];
25
+ function normalizeGitPatch(text) {
26
+ const normalized = text.replace(/\r\n/g, '\n').replace(/\s+$/, '');
27
+ return normalized.length > 0 ? `${normalized}\n` : '';
28
+ }
29
+ function splitLines(text) {
30
+ return text
31
+ .split(/\r?\n/)
32
+ .map((line) => line.trim())
33
+ .filter(Boolean);
34
+ }
35
+ async function buildUntrackedFilePatch(params) {
36
+ if (!isSafeRelativePath(params.relativePath) || params.relativePath.startsWith('.salmonloop/')) {
37
+ throw new BenchmarkPatchArtifactError(`Unsafe untracked patch path: ${params.relativePath}`);
38
+ }
39
+ const result = await params.git.diffUntrackedFileAgainstNull(params.relativePath, {
40
+ cwd: params.repoPath,
41
+ limits: { maxStdoutBytes: LIMITS.maxToolOutputBytes },
42
+ });
43
+ if (result.code !== 0 && result.code !== 1) {
44
+ throw new BenchmarkPatchArtifactError(result.stderr || 'Failed to diff untracked file.');
45
+ }
46
+ return normalizeGitPatch(result.stdout.toString('utf8'));
47
+ }
48
+ function parseChangedFilesFromPatch(patch) {
49
+ const files = new Set();
50
+ for (const line of patch.split('\n')) {
51
+ const match = line.match(/^diff --git a\/(.+?) b\/(.+)$/);
52
+ if (!match)
53
+ continue;
54
+ const next = match[2];
55
+ if (next !== '/dev/null')
56
+ files.add(next);
57
+ }
58
+ return Array.from(files).sort();
59
+ }
60
+ export async function buildBenchmarkPatchArtifact(params) {
61
+ const git = new GitAdapter(params.repoPath);
62
+ const fileAdapter = new FileAdapter();
63
+ const excluded = await resolveRepoRelativeExcludes(params.repoPath, params.excludePaths ?? []);
64
+ const pathspecs = buildPatchPathspecs(excluded);
65
+ const trackedPatch = normalizeGitPatch(await git.query([...DIFF_ARGS, ...pathspecs], {
66
+ trim: false,
67
+ limits: { maxStdoutBytes: LIMITS.maxToolOutputBytes },
68
+ }));
69
+ const candidateUntracked = new Set([
70
+ ...splitLines(await git.query(['ls-files', '--others', '--exclude-standard'])),
71
+ ...(params.changedFilesHint ?? []),
72
+ ]);
73
+ const untrackedPatches = [];
74
+ for (const relativePath of Array.from(candidateUntracked).sort()) {
75
+ const normalizedPath = normalizePath(relativePath);
76
+ if (!normalizedPath || normalizedPath.startsWith('.salmonloop/'))
77
+ continue;
78
+ if (excluded.has(normalizedPath))
79
+ continue;
80
+ const status = await git.getStatusForPath(normalizedPath);
81
+ if (!status?.untracked)
82
+ continue;
83
+ if (!(await fileAdapter.exists(path.join(params.repoPath, normalizedPath))))
84
+ continue;
85
+ untrackedPatches.push(await buildUntrackedFilePatch({
86
+ repoPath: params.repoPath,
87
+ git,
88
+ relativePath: normalizedPath,
89
+ }));
90
+ }
91
+ const patch = normalizeGitPatch([trackedPatch, ...untrackedPatches].filter(Boolean).join(EOL));
92
+ const bytes = Buffer.byteLength(patch, 'utf8');
93
+ return {
94
+ patch,
95
+ bytes,
96
+ sha256: createHash('sha256').update(patch, 'utf8').digest('hex'),
97
+ changedFiles: parseChangedFilesFromPatch(patch),
98
+ isEmpty: patch.length === 0,
99
+ };
100
+ }
101
+ function buildPatchPathspecs(excluded) {
102
+ return Array.from(excluded)
103
+ .sort()
104
+ .map((relativePath) => `:(top,literal,exclude)${relativePath}`);
105
+ }
106
+ async function resolveRepoRelativeExcludes(repoPath, paths) {
107
+ const resolvedRepoPath = path.resolve(repoPath);
108
+ const excluded = new Set();
109
+ for (const candidate of paths) {
110
+ if (!candidate)
111
+ continue;
112
+ const absolutePath = path.isAbsolute(candidate)
113
+ ? path.resolve(candidate)
114
+ : path.resolve(resolvedRepoPath, candidate);
115
+ const relativePath = normalizePath(path.relative(resolvedRepoPath, absolutePath));
116
+ if (!isSafeRelativePath(relativePath))
117
+ continue;
118
+ if (!isPathWithinDirectory(resolvedRepoPath, absolutePath))
119
+ continue;
120
+ excluded.add(relativePath);
121
+ }
122
+ return excluded;
123
+ }
124
+ //# sourceMappingURL=patch-artifact.js.map
@@ -0,0 +1,25 @@
1
+ export function buildSweBenchPrediction(input) {
2
+ return {
3
+ instance_id: input.instanceId,
4
+ model_name_or_path: input.modelNameOrPath,
5
+ model_patch: input.modelPatch,
6
+ };
7
+ }
8
+ export function encodeSweBenchPredictionJsonl(input) {
9
+ return `${JSON.stringify(buildSweBenchPrediction(input))}\n`;
10
+ }
11
+ export function parseSweBenchInstance(raw) {
12
+ const parsed = JSON.parse(raw);
13
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
14
+ throw new Error('SWE-bench instance must be a JSON object.');
15
+ }
16
+ const instance = parsed;
17
+ if (typeof instance.instance_id !== 'string' || !instance.instance_id.trim()) {
18
+ throw new Error('SWE-bench instance requires a non-empty instance_id.');
19
+ }
20
+ return {
21
+ ...instance,
22
+ instance_id: instance.instance_id,
23
+ };
24
+ }
25
+ //# sourceMappingURL=swe-bench.js.map