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
@@ -0,0 +1,360 @@
1
+ import { createHash } from 'crypto';
2
+ import path from 'path';
3
+ import { z } from 'zod';
4
+ import { FileAdapter } from '../../adapters/fs/file-adapter.js';
5
+ import { GitAdapter } from '../../adapters/git/git-adapter.js';
6
+ import { buildBenchmarkPatchArtifact, } from '../../benchmark/patch-artifact.js';
7
+ import { buildSweBenchPrediction, encodeSweBenchPredictionJsonl, parseSweBenchInstance, } from '../../benchmark/swe-bench.js';
8
+ import { normalizeDiff, validateDiff } from '../../patch/diff.js';
9
+ import { Phase } from '../../types/runtime.js';
10
+ import { isCanonicalPathWithinDirectory, isPathWithinDirectory, normalizeRepoRelativePath, } from '../../utils/path.js';
11
+ import { repoResource } from '../parallel/resource-helpers.js';
12
+ const patchInputSchema = z.object({
13
+ patch: z
14
+ .string()
15
+ .optional()
16
+ .describe('Unified diff to check. Defaults to current workspace diff.'),
17
+ });
18
+ const patchCheckOutputSchema = z.object({
19
+ ok: z.boolean(),
20
+ changedFiles: z.array(z.string()),
21
+ fileCount: z.number(),
22
+ lineCount: z.number(),
23
+ error: z.string().optional(),
24
+ });
25
+ export const gitDiffCheckSpec = {
26
+ name: 'git.diff_check',
27
+ source: 'builtin',
28
+ intent: 'INFRA',
29
+ description: 'Validate that a unified diff is structurally valid and within patch limits.',
30
+ riskLevel: 'low',
31
+ sideEffects: ['git_read'],
32
+ concurrency: 'parallel_ok',
33
+ computeResources: (_input, ctx) => [repoResource(ctx)],
34
+ inputSchema: patchInputSchema,
35
+ outputSchema: patchCheckOutputSchema,
36
+ allowedPhases: [Phase.VERIFY],
37
+ };
38
+ export const gitApplyCheckSpec = {
39
+ name: 'git.apply_check',
40
+ source: 'builtin',
41
+ intent: 'INFRA',
42
+ description: 'Run git apply --check against a unified diff without mutating the workspace.',
43
+ riskLevel: 'low',
44
+ sideEffects: ['git_read'],
45
+ concurrency: 'parallel_ok',
46
+ computeResources: (_input, ctx) => [repoResource(ctx)],
47
+ inputSchema: patchInputSchema.extend({
48
+ ignoreWhitespace: z.boolean().default(false),
49
+ }),
50
+ outputSchema: z.object({
51
+ ok: z.boolean(),
52
+ exitCode: z.number().nullable(),
53
+ output: z.string(),
54
+ }),
55
+ allowedPhases: [Phase.VERIFY],
56
+ };
57
+ const benchmarkReportInputSchema = z.object({
58
+ patch: z
59
+ .string()
60
+ .optional()
61
+ .describe('Unified diff to summarize. Defaults to current workspace diff.'),
62
+ });
63
+ const benchmarkReportOutputSchema = z.object({
64
+ provider: z.literal('local'),
65
+ patch: z.object({
66
+ sha256: z.string(),
67
+ bytes: z.number(),
68
+ changedFiles: z.array(z.string()),
69
+ isEmpty: z.boolean(),
70
+ }),
71
+ });
72
+ export const benchmarkReportSpec = {
73
+ name: 'benchmark.report',
74
+ source: 'builtin',
75
+ intent: 'REPORT',
76
+ description: 'Create a local benchmark report for the current workspace patch.',
77
+ riskLevel: 'low',
78
+ sideEffects: ['git_read'],
79
+ concurrency: 'parallel_ok',
80
+ computeResources: (_input, ctx) => [repoResource(ctx)],
81
+ inputSchema: benchmarkReportInputSchema,
82
+ outputSchema: benchmarkReportOutputSchema,
83
+ allowedPhases: [Phase.VERIFY],
84
+ };
85
+ export const sweBenchLoadInstanceSpec = {
86
+ name: 'swebench.load_instance',
87
+ source: 'builtin',
88
+ intent: 'READ',
89
+ description: 'Load a local SWE-bench instance JSON file without network access.',
90
+ riskLevel: 'low',
91
+ sideEffects: ['fs_read'],
92
+ concurrency: 'parallel_ok',
93
+ inputSchema: z.object({
94
+ file: z.string().describe('Repo-relative path to a SWE-bench instance JSON file'),
95
+ }),
96
+ outputSchema: z
97
+ .object({
98
+ instance_id: z.string(),
99
+ repo: z.string().optional(),
100
+ base_commit: z.string().optional(),
101
+ problem_statement: z.string().optional(),
102
+ })
103
+ .passthrough(),
104
+ allowedPhases: [Phase.VERIFY],
105
+ };
106
+ const swePredictionInputSchema = z.object({
107
+ instanceId: z.string().min(1).describe('SWE-bench instance_id'),
108
+ modelNameOrPath: z.string().min(1).describe('SWE-bench model_name_or_path'),
109
+ patch: z
110
+ .string()
111
+ .optional()
112
+ .describe('Unified diff to encode. Defaults to current workspace diff.'),
113
+ });
114
+ const swePredictionOutputSchema = z.object({
115
+ prediction: z.object({
116
+ instance_id: z.string(),
117
+ model_name_or_path: z.string(),
118
+ model_patch: z.string(),
119
+ }),
120
+ jsonl: z.string(),
121
+ });
122
+ export const sweBenchWritePredictionSpec = {
123
+ name: 'swebench.write_prediction',
124
+ source: 'builtin',
125
+ intent: 'REPORT',
126
+ description: 'Encode a SWE-bench prediction JSONL record without writing to disk.',
127
+ riskLevel: 'low',
128
+ sideEffects: ['git_read'],
129
+ concurrency: 'parallel_ok',
130
+ computeResources: (_input, ctx) => [repoResource(ctx)],
131
+ inputSchema: swePredictionInputSchema,
132
+ outputSchema: swePredictionOutputSchema,
133
+ allowedPhases: [Phase.VERIFY],
134
+ };
135
+ export const sweBenchSubmitPredictionsSpec = {
136
+ name: 'swebench.submit_predictions',
137
+ source: 'builtin',
138
+ intent: 'REPORT',
139
+ description: 'Append a SWE-bench prediction JSONL record to a local repo-contained file.',
140
+ riskLevel: 'medium',
141
+ sideEffects: ['fs_write', 'git_read'],
142
+ concurrency: 'serial_only',
143
+ computeResources: (_input, ctx) => [repoResource(ctx)],
144
+ inputSchema: swePredictionInputSchema.extend({
145
+ predictionsFile: z
146
+ .string()
147
+ .default('predictions.jsonl')
148
+ .describe('Repo-relative JSONL file to append the prediction to'),
149
+ }),
150
+ outputSchema: z.object({
151
+ predictionsFile: z.string(),
152
+ appended: z.boolean(),
153
+ prediction: swePredictionOutputSchema.shape.prediction,
154
+ }),
155
+ allowedPhases: [Phase.VERIFY],
156
+ };
157
+ export const sweBenchGetReportSpec = {
158
+ name: 'swebench.get_report',
159
+ source: 'builtin',
160
+ intent: 'READ',
161
+ description: 'Read a local SWE-bench report JSON file without network access.',
162
+ riskLevel: 'low',
163
+ sideEffects: ['fs_read'],
164
+ concurrency: 'parallel_ok',
165
+ inputSchema: z.object({
166
+ file: z.string().describe('Repo-relative path to a SWE-bench report JSON file'),
167
+ }),
168
+ outputSchema: z.object({
169
+ report: z.record(z.string(), z.unknown()),
170
+ }),
171
+ allowedPhases: [Phase.VERIFY],
172
+ };
173
+ async function resolvePatch(ctx, patch, options = {}) {
174
+ if (patch !== undefined) {
175
+ if (patch.trim().length === 0) {
176
+ return {
177
+ patch: '',
178
+ bytes: 0,
179
+ sha256: createHash('sha256').update('', 'utf8').digest('hex'),
180
+ changedFiles: [],
181
+ isEmpty: true,
182
+ };
183
+ }
184
+ const normalizedPatch = normalizeDiff(patch);
185
+ const meta = validateDiff(normalizedPatch);
186
+ const bytes = Buffer.byteLength(normalizedPatch, 'utf8');
187
+ const sha256 = createHash('sha256').update(normalizedPatch, 'utf8').digest('hex');
188
+ return {
189
+ patch: normalizedPatch,
190
+ bytes,
191
+ sha256,
192
+ changedFiles: meta.changedFiles,
193
+ isEmpty: normalizedPatch.length === 0,
194
+ };
195
+ }
196
+ return buildBenchmarkPatchArtifact({
197
+ repoPath: ctx.worktreeRoot || ctx.repoRoot,
198
+ excludePaths: options.excludePaths,
199
+ });
200
+ }
201
+ function resolveRepoFile(ctx, file) {
202
+ const root = ctx.worktreeRoot || ctx.repoRoot;
203
+ if (path.isAbsolute(file)) {
204
+ throw new Error(`Expected a repo-relative path: ${file}`);
205
+ }
206
+ assertNotReservedRepoPrefix(file);
207
+ const absolutePath = path.resolve(root, file);
208
+ if (!isPathWithinDirectory(root, absolutePath, { allowEqual: false })) {
209
+ throw new Error(`Refusing to access path outside repository: ${file}`);
210
+ }
211
+ const relativePath = path.relative(root, absolutePath).replace(/\\/g, '/');
212
+ assertNotReservedRepoPrefix(relativePath);
213
+ return { absolutePath, relativePath };
214
+ }
215
+ function assertNotReservedRepoPrefix(file) {
216
+ const normalized = normalizeRepoRelativePath(file);
217
+ if (normalized === '.git' || normalized.startsWith('.git/')) {
218
+ throw new Error('Access denied: Reserved path prefix: .git/');
219
+ }
220
+ if (normalized === '.salmonloop' || normalized.startsWith('.salmonloop/')) {
221
+ throw new Error('Access denied: Reserved path prefix: .salmonloop/');
222
+ }
223
+ }
224
+ function isMissingPathError(error) {
225
+ return Boolean(error && typeof error === 'object' && error.code === 'ENOENT');
226
+ }
227
+ async function assertNoSymlinkPathComponents(root, absolutePath) {
228
+ const adapter = new FileAdapter();
229
+ const resolvedRoot = path.resolve(root);
230
+ let cursor = absolutePath;
231
+ while (isPathWithinDirectory(resolvedRoot, cursor, { allowEqual: false })) {
232
+ try {
233
+ const stats = await adapter.lstat(cursor);
234
+ if (stats.isSymbolicLink()) {
235
+ throw new Error(`Refusing to follow symlink path component: ${path.relative(resolvedRoot, cursor)}`);
236
+ }
237
+ }
238
+ catch (error) {
239
+ if (!isMissingPathError(error))
240
+ throw error;
241
+ }
242
+ cursor = path.dirname(cursor);
243
+ }
244
+ }
245
+ async function assertCanonicalRepoContainment(root, absolutePath) {
246
+ const adapter = new FileAdapter();
247
+ const realRoot = await adapter.realpath(root);
248
+ let cursor = absolutePath;
249
+ while (true) {
250
+ try {
251
+ const realCursor = await adapter.realpath(cursor);
252
+ if (!isCanonicalPathWithinDirectory(realRoot, realCursor, { allowEqual: true })) {
253
+ throw new Error(`Refusing to access path outside repository: ${path.relative(root, absolutePath)}`);
254
+ }
255
+ return;
256
+ }
257
+ catch (error) {
258
+ if (!isMissingPathError(error))
259
+ throw error;
260
+ const parent = path.dirname(cursor);
261
+ if (parent === cursor)
262
+ throw error;
263
+ cursor = parent;
264
+ }
265
+ }
266
+ }
267
+ async function resolveSafeRepoFile(ctx, file) {
268
+ const resolved = resolveRepoFile(ctx, file);
269
+ const root = ctx.worktreeRoot || ctx.repoRoot;
270
+ await assertNoSymlinkPathComponents(root, resolved.absolutePath);
271
+ await assertCanonicalRepoContainment(root, resolved.absolutePath);
272
+ return resolved;
273
+ }
274
+ export async function executeGitDiffCheck(input, ctx) {
275
+ try {
276
+ const artifact = await resolvePatch(ctx, input.patch);
277
+ if (artifact.isEmpty) {
278
+ return { ok: false, changedFiles: [], fileCount: 0, lineCount: 0, error: 'Patch is empty.' };
279
+ }
280
+ const meta = validateDiff(artifact.patch);
281
+ return {
282
+ ok: true,
283
+ changedFiles: meta.changedFiles,
284
+ fileCount: meta.fileCount,
285
+ lineCount: meta.lineCount,
286
+ };
287
+ }
288
+ catch (error) {
289
+ return {
290
+ ok: false,
291
+ changedFiles: [],
292
+ fileCount: 0,
293
+ lineCount: 0,
294
+ error: error instanceof Error ? error.message : String(error),
295
+ };
296
+ }
297
+ }
298
+ export async function executeGitApplyCheck(input, ctx) {
299
+ const artifact = await resolvePatch(ctx, input.patch);
300
+ if (artifact.isEmpty) {
301
+ return { ok: false, exitCode: null, output: 'Patch is empty.' };
302
+ }
303
+ const git = new GitAdapter(ctx.worktreeRoot || ctx.repoRoot);
304
+ return git.checkPatchApplyability(artifact.patch, {
305
+ ignoreWhitespace: input.ignoreWhitespace,
306
+ env: ctx.env,
307
+ });
308
+ }
309
+ export async function executeBenchmarkReport(input, ctx) {
310
+ const artifact = await resolvePatch(ctx, input.patch);
311
+ return {
312
+ provider: 'local',
313
+ patch: {
314
+ sha256: artifact.sha256,
315
+ bytes: artifact.bytes,
316
+ changedFiles: artifact.changedFiles,
317
+ isEmpty: artifact.isEmpty,
318
+ },
319
+ };
320
+ }
321
+ export async function executeSweBenchLoadInstance(input, ctx) {
322
+ const { absolutePath } = await resolveSafeRepoFile(ctx, input.file);
323
+ return parseSweBenchInstance(await new FileAdapter().readFile(absolutePath, 'utf8'));
324
+ }
325
+ export async function executeSweBenchWritePrediction(input, ctx) {
326
+ return buildSweBenchPredictionOutput(input, ctx);
327
+ }
328
+ async function buildSweBenchPredictionOutput(input, ctx, options = {}) {
329
+ const artifact = await resolvePatch(ctx, input.patch, options);
330
+ const predictionInput = {
331
+ instanceId: input.instanceId,
332
+ modelNameOrPath: input.modelNameOrPath,
333
+ modelPatch: artifact.patch,
334
+ };
335
+ return {
336
+ prediction: buildSweBenchPrediction(predictionInput),
337
+ jsonl: encodeSweBenchPredictionJsonl(predictionInput),
338
+ };
339
+ }
340
+ export async function executeSweBenchSubmitPredictions(input, ctx) {
341
+ const { absolutePath, relativePath } = await resolveSafeRepoFile(ctx, input.predictionsFile);
342
+ const output = await buildSweBenchPredictionOutput(input, ctx, {
343
+ excludePaths: [relativePath],
344
+ });
345
+ await new FileAdapter().appendFile(absolutePath, output.jsonl);
346
+ return {
347
+ predictionsFile: relativePath,
348
+ appended: true,
349
+ prediction: output.prediction,
350
+ };
351
+ }
352
+ export async function executeSweBenchGetReport(input, ctx) {
353
+ const { absolutePath } = await resolveSafeRepoFile(ctx, input.file);
354
+ const parsed = JSON.parse(await new FileAdapter().readFile(absolutePath, 'utf8'));
355
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
356
+ throw new Error('SWE-bench report must be a JSON object.');
357
+ }
358
+ return { report: parsed };
359
+ }
360
+ //# sourceMappingURL=benchmark.js.map
@@ -1,3 +1,4 @@
1
+ import { resolve } from 'path';
1
2
  import { LIMITS } from '../../../../config/limits.js';
2
3
  import { parseRgJson } from '../parse/rg-json.js';
3
4
  export const rgBackend = {
@@ -20,7 +21,7 @@ export const rgBackend = {
20
21
  };
21
22
  },
22
23
  async run(input, ctx) {
23
- const cwd = input.cwd ?? ctx.repoRoot;
24
+ const cwd = input.cwd ?? resolve(ctx.repoRoot);
24
25
  const args = [
25
26
  '--json',
26
27
  '--line-number',
@@ -4,6 +4,7 @@ import { spawnCommand } from '../../../runtime/process-runner.js';
4
4
  import { runWithFallback } from '../../capability/executor.js';
5
5
  import { psBackend } from './backends/powershell.js';
6
6
  import { rgBackend } from './backends/rg.js';
7
+ import { resolveCodeSearchCwd } from './spec.js';
7
8
  /**
8
9
  * The main executor for code.search.
9
10
  * It transforms the general ToolRuntimeCtx into a specialized CapabilityCtx
@@ -11,6 +12,10 @@ import { rgBackend } from './backends/rg.js';
11
12
  */
12
13
  export async function codeSearchExecutor(input, ctx) {
13
14
  getLogger().debug(`Searching for pattern: ${input.pattern}`);
15
+ const normalizedInput = {
16
+ ...input,
17
+ cwd: resolveCodeSearchCwd(ctx.repoRoot, input.cwd),
18
+ };
14
19
  // Construct CapabilityCtx for the underlying backends
15
20
  const capCtx = {
16
21
  repoRoot: ctx.repoRoot,
@@ -75,7 +80,7 @@ export async function codeSearchExecutor(input, ctx) {
75
80
  },
76
81
  };
77
82
  const backends = capCtx.platform === 'win32' ? [rgBackend, psBackend] : [rgBackend];
78
- const { output, meta } = await runWithFallback(backends, input, capCtx, {
83
+ const { output, meta } = await runWithFallback(backends, normalizedInput, capCtx, {
79
84
  fallbackOn: new Set(['UNAVAILABLE', 'TIMEOUT', 'RUNTIME_ERROR', 'NONZERO_EXIT']),
80
85
  maxBackendTries: backends.length,
81
86
  });
@@ -1,4 +1,6 @@
1
+ import { isAbsolute, relative, resolve } from 'path';
1
2
  import { z } from 'zod';
3
+ import { text } from '../../../../locales/index.js';
2
4
  import { Phase } from '../../../types/runtime.js';
3
5
  import { repoResource } from '../../parallel/resource-helpers.js';
4
6
  const CoercedBoolean = z.preprocess((value) => {
@@ -25,7 +27,10 @@ export const CodeSearchInput = z.object({
25
27
  .max(500)
26
28
  .default(100)
27
29
  .describe('Maximum number of matches to return'),
28
- cwd: z.string().optional().describe('Directory to search in (defaults to repo root)'),
30
+ cwd: z
31
+ .string()
32
+ .optional()
33
+ .describe('Directory to search in, relative to the repo root or an absolute path inside it'),
29
34
  isRegex: CoercedBoolean.default(false).describe('Whether to treat the pattern as a regular expression'),
30
35
  });
31
36
  export const CodeSearchMatch = z.object({
@@ -48,6 +53,17 @@ export const CodeSearchOutput = z.object({
48
53
  })
49
54
  .partial(),
50
55
  });
56
+ export function resolveCodeSearchCwd(repoRoot, inputCwd) {
57
+ const absoluteRoot = resolve(repoRoot);
58
+ const absolutePath = isAbsolute(inputCwd ?? '')
59
+ ? resolve(inputCwd ?? absoluteRoot)
60
+ : resolve(absoluteRoot, inputCwd ?? '.');
61
+ const relativePath = relative(absoluteRoot, absolutePath);
62
+ if (relativePath.startsWith('..') || isAbsolute(relativePath)) {
63
+ throw new Error(text.errors.pathOutsideRepo);
64
+ }
65
+ return absolutePath;
66
+ }
51
67
  /**
52
68
  * Specification for the code search tool.
53
69
  * The executor will be bound during tool registration.
@@ -61,7 +77,15 @@ export const CodeSearchSpec = {
61
77
  sideEffects: ['fs_read'],
62
78
  concurrency: 'parallel_ok',
63
79
  computeResources: (_input, ctx) => [repoResource(ctx)],
64
- allowedPhases: [Phase.SLASH, Phase.CONTEXT, Phase.EXPLORE, Phase.PLAN, Phase.PATCH, Phase.VERIFY],
80
+ allowedPhases: [
81
+ Phase.SLASH,
82
+ Phase.CONTEXT,
83
+ Phase.EXPLORE,
84
+ Phase.PLAN,
85
+ Phase.AUTOPILOT,
86
+ Phase.PATCH,
87
+ Phase.VERIFY,
88
+ ],
65
89
  inputSchema: CodeSearchInput,
66
90
  outputSchema: CodeSearchOutput,
67
91
  examples: [