salmon-loop 0.2.13 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/argv/headless-detection.js +27 -0
- package/dist/cli/chat-flow.js +11 -0
- package/dist/cli/chat.js +160 -24
- package/dist/cli/commands/chat.js +14 -7
- package/dist/cli/commands/flow-mode.js +63 -0
- package/dist/cli/commands/registry.js +2 -0
- package/dist/cli/commands/run/benchmark-artifacts.js +41 -0
- package/dist/cli/commands/run/early-errors.js +23 -0
- package/dist/cli/commands/run/handler.js +115 -27
- package/dist/cli/commands/run/headless-error-writer.js +8 -0
- package/dist/cli/commands/run/loop-params.js +2 -0
- package/dist/cli/commands/run/mode.js +2 -5
- package/dist/cli/commands/run/parse-options.js +16 -0
- package/dist/cli/commands/run/persist-session.js +10 -1
- package/dist/cli/commands/run/preflight.js +10 -0
- package/dist/cli/commands/run/reporter-factory.js +4 -0
- package/dist/cli/commands/run/runtime-llm.js +38 -11
- package/dist/cli/commands/run/runtime-options.js +2 -2
- package/dist/cli/commands/serve.js +97 -77
- package/dist/cli/commands/tool-names.js +78 -78
- package/dist/cli/headless/anthropic-stream-normalized-encoder.js +6 -1
- package/dist/cli/headless/json-protocol.js +37 -0
- package/dist/cli/headless/native-stream-normalized-encoder.js +6 -1
- package/dist/cli/headless/protocol-metadata.js +22 -0
- package/dist/cli/headless/stream-json-protocol.js +34 -1
- package/dist/cli/index.js +6 -4
- package/dist/cli/locales/en.js +30 -6
- package/dist/cli/program-bootstrap.js +10 -5
- package/dist/cli/program-commands.js +5 -1
- package/dist/cli/reporters/anthropic-stream.js +7 -1
- package/dist/cli/reporters/json.js +4 -0
- package/dist/cli/reporters/stream-json.js +17 -2
- package/dist/cli/run-cli.js +5 -3
- package/dist/cli/slash/runtime.js +27 -12
- package/dist/cli/ui/components/CommandInput.js +7 -3
- package/dist/cli/ui/components/CommandSuggestionList.js +1 -1
- package/dist/cli/utils/command-option-source.js +13 -0
- package/dist/cli/utils/verify-resolver.js +8 -4
- package/dist/cli/utils/worktree-prepare-resolver.js +7 -3
- package/dist/core/adapters/fs/file-adapter.js +6 -0
- package/dist/core/adapters/fs/filesystem.js +2 -1
- package/dist/core/adapters/git/git-adapter.js +78 -1
- package/dist/core/backends/salmon-loop/task-executor.js +1 -0
- package/dist/core/benchmark/patch-artifact.js +124 -0
- package/dist/core/benchmark/swe-bench.js +25 -0
- package/dist/core/config/load.js +18 -11
- package/dist/core/config/resolve-llm.js +12 -0
- package/dist/core/config/resolvers/server.js +0 -6
- package/dist/core/config/validate.js +73 -21
- package/dist/core/context/gatherers/metadata-gatherer.js +1 -0
- package/dist/core/context/gatherers/ripgrep-gatherer.js +84 -2
- package/dist/core/context/keywords.js +18 -4
- package/dist/core/context/service-deps.js +2 -2
- package/dist/core/context/service.js +8 -0
- package/dist/core/context/steps/context-gather.js +38 -0
- package/dist/core/context/summarization/summarizer.js +55 -12
- package/dist/core/context/targeting/target-resolver.js +4 -4
- package/dist/core/extensions/index.js +23 -5
- package/dist/core/extensions/merge.js +14 -0
- package/dist/core/extensions/paths.js +31 -0
- package/dist/core/extensions/schemas.js +8 -5
- package/dist/core/facades/cli-chat.js +6 -2
- package/dist/core/facades/cli-command-chat.js +1 -0
- package/dist/core/facades/cli-command-tool-names.js +2 -0
- package/dist/core/facades/cli-observability.js +1 -1
- package/dist/core/facades/cli-program-bootstrap.js +1 -0
- package/dist/core/facades/cli-run-handler.js +4 -2
- package/dist/core/facades/cli-run-persist-session.js +1 -0
- package/dist/core/facades/cli-serve.js +4 -4
- package/dist/core/facades/cli-utils-worktree.js +1 -1
- package/dist/core/failure/diagnostics.js +53 -1
- package/dist/core/grizzco/dsl/llm-strategy.js +4 -1
- package/dist/core/grizzco/engine/outcome/loop-result-mapper.js +67 -9
- package/dist/core/grizzco/engine/pipeline/pipeline.js +6 -2
- package/dist/core/grizzco/engine/transaction/attempt-failure.js +90 -15
- package/dist/core/grizzco/engine/transaction/report-mapper.js +17 -3
- package/dist/core/grizzco/engine/transaction/transaction-runner.js +165 -7
- package/dist/core/grizzco/flows/AutopilotFlow.js +18 -0
- package/dist/core/grizzco/flows/flow-dispatch.js +11 -0
- package/dist/core/grizzco/steps/answer.js +13 -14
- package/dist/core/grizzco/steps/autopilot.js +396 -0
- package/dist/core/grizzco/steps/cache-sharing.js +29 -0
- package/dist/core/grizzco/steps/explore.js +37 -21
- package/dist/core/grizzco/steps/generateReview.js +2 -5
- package/dist/core/grizzco/steps/patch/apply-check.js +10 -0
- package/dist/core/grizzco/steps/patch/diff-normalization.js +70 -0
- package/dist/core/grizzco/steps/patch/diff-salvage.js +46 -0
- package/dist/core/grizzco/steps/patch/prompt-input.js +42 -0
- package/dist/core/grizzco/steps/patch.js +105 -146
- package/dist/core/grizzco/steps/plan.js +101 -25
- package/dist/core/grizzco/steps/preflight.js +5 -6
- package/dist/core/grizzco/steps/request-assembly.js +78 -0
- package/dist/core/grizzco/steps/research.js +39 -36
- package/dist/core/grizzco/steps/tool-runtime.js +47 -0
- package/dist/core/grizzco/steps/verify-shared.js +23 -0
- package/dist/core/grizzco/steps/verify.js +13 -21
- package/dist/core/interaction/orchestration/facade.js +1 -1
- package/dist/core/llm/ai-sdk/chat-executor.js +2 -0
- package/dist/core/llm/ai-sdk/high-level-phase-specs.js +63 -0
- package/dist/core/llm/ai-sdk/message-mapper.js +40 -10
- package/dist/core/llm/ai-sdk/provider-factory.js +14 -0
- package/dist/core/llm/ai-sdk/request-params.js +113 -1
- package/dist/core/llm/ai-sdk/result-mapper.js +16 -0
- package/dist/core/llm/ai-sdk.js +112 -27
- package/dist/core/llm/capabilities.js +12 -0
- package/dist/core/llm/contracts/repair.js +36 -30
- package/dist/core/llm/errors.js +83 -2
- package/dist/core/llm/message-composition.js +7 -22
- package/dist/core/llm/phase-router.js +29 -10
- package/dist/core/llm/redact.js +28 -3
- package/dist/core/llm/registry.js +2 -0
- package/dist/core/llm/request-augmentation.js +55 -0
- package/dist/core/llm/request-envelope.js +334 -0
- package/dist/core/llm/shared-request-assembly.js +35 -0
- package/dist/core/llm/stream-utils.js +13 -4
- package/dist/core/llm/utils.js +18 -29
- package/dist/core/memory/relevant-retrieval.js +144 -0
- package/dist/core/observability/logger.js +11 -2
- package/dist/core/patch/diff.js +1 -0
- package/dist/core/prompts/registry.js +39 -2
- package/dist/core/prompts/runtime.js +50 -12
- package/dist/core/prompts/templates/phases/patch_user.hbs +2 -5
- package/dist/core/prompts/templates/phases/research_user.hbs +11 -0
- package/dist/core/prompts/templates/phases/review_user.hbs +3 -0
- package/dist/core/prompts/templates/system/answer_system.hbs +5 -0
- package/dist/core/prompts/templates/system/autopilot_system.hbs +11 -0
- package/dist/core/prompts/templates/system/explore_system.hbs +14 -23
- package/dist/core/prompts/templates/system/main_system.hbs +4 -16
- package/dist/core/prompts/templates/system/patch_system.hbs +39 -8
- package/dist/core/prompts/templates/system/plan_system.hbs +86 -1
- package/dist/core/prompts/templates/system/research_system.hbs +2 -0
- package/dist/core/protocols/a2a/agent-card.js +5 -3
- package/dist/core/protocols/a2a/sdk/executor.js +2 -1
- package/dist/core/protocols/a2a/sdk/server.js +0 -1
- package/dist/core/protocols/acp/formal-agent.js +300 -58
- package/dist/core/protocols/acp/handlers.js +5 -1
- package/dist/core/protocols/acp/permission-provider.js +1 -1
- package/dist/core/protocols/shared/flow-mode-mapping.js +23 -0
- package/dist/core/public-capabilities/flow-mode-metadata.js +39 -0
- package/dist/core/public-capabilities/projections.js +29 -0
- package/dist/core/public-capabilities/registry.js +26 -0
- package/dist/core/public-capabilities/types.js +2 -0
- package/dist/core/runtime/agent-server-runtime.js +47 -43
- package/dist/core/runtime/execution-profile.js +67 -0
- package/dist/core/session/artifact-state.js +160 -0
- package/dist/core/session/compaction/index.js +183 -0
- package/dist/core/session/compaction/microcompact.js +78 -0
- package/dist/core/session/compaction/tracking.js +48 -0
- package/dist/core/session/compaction/types.js +11 -0
- package/dist/core/session/compression.js +8 -0
- package/dist/core/session/manager.js +244 -8
- package/dist/core/session/pruning-strategy.js +55 -9
- package/dist/core/session/replacement-preview-provider.js +24 -0
- package/dist/core/session/replacement-state.js +131 -0
- package/dist/core/session/resume-repair/pipeline.js +79 -0
- package/dist/core/session/resume-repair/stages/load-raw-archive-state.js +40 -0
- package/dist/core/session/resume-repair/stages/reattach-runtime-state.js +8 -0
- package/dist/core/session/resume-repair/stages/recover-orphaned-branches.js +10 -0
- package/dist/core/session/resume-repair/stages/relink-boundary-and-tail.js +36 -0
- package/dist/core/session/resume-repair/stages/replay-startup-hooks.js +23 -0
- package/dist/core/session/resume-repair/stages/rescue-stale-metadata.js +17 -0
- package/dist/core/session/resume-repair/types.js +2 -0
- package/dist/core/session/summary-sync.js +164 -13
- package/dist/core/session/token-tracker.js +6 -0
- package/dist/core/skills/audit.js +34 -0
- package/dist/core/skills/bridge.js +84 -7
- package/dist/core/skills/discovery.js +94 -0
- package/dist/core/skills/feature-flags.js +52 -0
- package/dist/core/skills/index.js +1 -1
- package/dist/core/skills/loader.js +195 -20
- package/dist/core/skills/parser.js +296 -24
- package/dist/core/skills/permissions.js +117 -0
- package/dist/core/skills/runtime/MicroTaskRunner.js +10 -4
- package/dist/core/skills/runtime/SkillRunner.js +240 -61
- package/dist/core/strata/layers/shadow-driver/shadow-driver.js +37 -7
- package/dist/core/strata/layers/worktree.js +67 -10
- package/dist/core/strata/runtime/synchronizer.js +29 -2
- package/dist/core/streaming/stream-assembler.js +75 -31
- package/dist/core/sub-agent/context-snapshot.js +156 -0
- package/dist/core/sub-agent/core/loop.js +1 -1
- package/dist/core/sub-agent/core/manager.js +119 -20
- package/dist/core/sub-agent/dispatch-policy.js +29 -0
- package/dist/core/sub-agent/prefix-consistency.js +48 -0
- package/dist/core/sub-agent/registry-defaults.js +4 -0
- package/dist/core/sub-agent/tools/task-spawn.js +79 -2
- package/dist/core/sub-agent/types.js +134 -5
- package/dist/core/tools/audit.js +13 -4
- package/dist/core/tools/builtin/ast-grep.js +1 -1
- package/dist/core/tools/builtin/ast.js +1 -1
- package/dist/core/tools/builtin/benchmark.js +360 -0
- package/dist/core/tools/builtin/code-search/backends/rg.js +2 -1
- package/dist/core/tools/builtin/code-search/executor.js +6 -1
- package/dist/core/tools/builtin/code-search/spec.js +26 -2
- package/dist/core/tools/builtin/fs.js +256 -23
- package/dist/core/tools/builtin/git.js +2 -2
- package/dist/core/tools/builtin/index.js +51 -2
- package/dist/core/tools/builtin/interaction.js +8 -1
- package/dist/core/tools/builtin/plan.js +37 -15
- package/dist/core/tools/builtin/shell.js +1 -1
- package/dist/core/tools/loader.js +39 -16
- package/dist/core/tools/mapper.js +17 -3
- package/dist/core/tools/mcp/client.js +2 -1
- package/dist/core/tools/parallel/scheduler.js +35 -4
- package/dist/core/tools/permissions/permission-rules.js +5 -10
- package/dist/core/tools/policy.js +6 -1
- package/dist/core/tools/recoverable-tool-errors.js +10 -0
- package/dist/core/tools/router.js +24 -6
- package/dist/core/tools/session.js +458 -48
- package/dist/core/tools/tool-visibility.js +62 -0
- package/dist/core/tools/types.js +9 -1
- package/dist/core/types/execution.js +4 -0
- package/dist/core/types/flow-mode.js +8 -0
- package/dist/core/utils/path.js +52 -0
- package/dist/core/verification/runner.js +4 -1
- package/dist/core/version.js +17 -0
- package/dist/languages/typescript/index.js +4 -1
- package/dist/locales/en.js +35 -2
- package/dist/utils/eol.js +1 -1
- package/package.json +14 -7
- package/scripts/fix-es-abstract-compat.js +77 -0
- package/dist/core/runtime/fastify-server-bundle.js +0 -26
- package/dist/core/runtime/sidecar-fastify-plugin.js +0 -35
- package/dist/core/runtime/sidecar-paths.js +0 -47
- package/dist/core/runtime/sidecar-route-catalog.js +0 -103
|
@@ -2,6 +2,7 @@ import { createInterface } from 'readline';
|
|
|
2
2
|
import { LIMITS } from '../../config/limits.js';
|
|
3
3
|
import { getLogger } from '../../observability/logger.js';
|
|
4
4
|
import { spawnInteractiveProcess } from '../../runtime/process-runner.js';
|
|
5
|
+
import { PACKAGE_VERSION } from '../../version.js';
|
|
5
6
|
import { assertOk, createMcpHeaders, decodeSseEvents, delayMs, isEventStreamResponse, safeDrainResponse, } from './streamable-http.js';
|
|
6
7
|
/**
|
|
7
8
|
* MCP Client handling JSON-RPC communication over stdio with an external server.
|
|
@@ -77,7 +78,7 @@ export class McpClient {
|
|
|
77
78
|
await this.request('initialize', {
|
|
78
79
|
protocolVersion: '2025-11-25',
|
|
79
80
|
capabilities: {},
|
|
80
|
-
clientInfo: { name: 'salmon-loop', version:
|
|
81
|
+
clientInfo: { name: 'salmon-loop', version: PACKAGE_VERSION },
|
|
81
82
|
});
|
|
82
83
|
// Step 2: Signal initialized
|
|
83
84
|
await this.notification('notifications/initialized', {});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isRecoverableToolInputErrorCode } from '../recoverable-tool-errors.js';
|
|
1
2
|
import { IsolationManager } from './isolation.js';
|
|
2
3
|
import { resolveArgsWithResults } from './resolve-args.js';
|
|
3
4
|
import { processResource, repoResource } from './resource-helpers.js';
|
|
@@ -20,6 +21,25 @@ export class ParallelScheduler {
|
|
|
20
21
|
node.spec = spec;
|
|
21
22
|
return spec;
|
|
22
23
|
}
|
|
24
|
+
normalizeArgsForSpec(spec, args) {
|
|
25
|
+
if (!spec.inputSchema || typeof spec.inputSchema.safeParse !== 'function')
|
|
26
|
+
return args;
|
|
27
|
+
const parsed = spec.inputSchema.safeParse(args);
|
|
28
|
+
return parsed.success ? parsed.data : args;
|
|
29
|
+
}
|
|
30
|
+
shouldFallbackFromComputeResources(spec, args, error) {
|
|
31
|
+
const parsed = spec.inputSchema.safeParse(args);
|
|
32
|
+
if (parsed.success)
|
|
33
|
+
return false;
|
|
34
|
+
const issueCode = parsed.error.issues[0]?.code;
|
|
35
|
+
if (issueCode === 'invalid_type' || issueCode === 'invalid_union' || issueCode === 'custom') {
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
const errorCode = typeof error === 'object' && error !== null && 'code' in error
|
|
39
|
+
? error.code
|
|
40
|
+
: undefined;
|
|
41
|
+
return isRecoverableToolInputErrorCode(errorCode);
|
|
42
|
+
}
|
|
23
43
|
deriveDefaultResources(spec, ctx) {
|
|
24
44
|
const writeEffects = new Set(['fs_write', 'git_write', 'snapshot_mutate']);
|
|
25
45
|
const hasWrite = spec.sideEffects.some((effect) => writeEffects.has(effect));
|
|
@@ -163,13 +183,14 @@ export class ParallelScheduler {
|
|
|
163
183
|
}
|
|
164
184
|
// 1. Resolve Arguments
|
|
165
185
|
const resolvedArgs = resolveArgsWithResults(node.args, nodeResults);
|
|
186
|
+
const normalizedArgs = this.normalizeArgsForSpec(spec, resolvedArgs);
|
|
166
187
|
// 1.5 Deferred authorization preflight (avoid holding locks while waiting for user)
|
|
167
188
|
const preflight = typeof this.router.preflightDeferredAuthorization === 'function'
|
|
168
189
|
? await this.router.preflightDeferredAuthorization({
|
|
169
190
|
id: nodeId,
|
|
170
191
|
phase: baseCtx.phase || 'execute',
|
|
171
192
|
toolName: node.toolName,
|
|
172
|
-
args:
|
|
193
|
+
args: normalizedArgs,
|
|
173
194
|
ctx: baseCtx,
|
|
174
195
|
})
|
|
175
196
|
: null;
|
|
@@ -205,8 +226,18 @@ export class ParallelScheduler {
|
|
|
205
226
|
}
|
|
206
227
|
// 2. Compute Resources (JIT)
|
|
207
228
|
const resources = node.resources ??
|
|
208
|
-
|
|
209
|
-
|
|
229
|
+
(() => {
|
|
230
|
+
try {
|
|
231
|
+
return (spec.computeResources?.(normalizedArgs, baseCtx) ??
|
|
232
|
+
this.deriveDefaultResources(spec, baseCtx));
|
|
233
|
+
}
|
|
234
|
+
catch (error) {
|
|
235
|
+
if (!this.shouldFallbackFromComputeResources(spec, normalizedArgs, error)) {
|
|
236
|
+
throw error;
|
|
237
|
+
}
|
|
238
|
+
return this.deriveDefaultResources(spec, baseCtx);
|
|
239
|
+
}
|
|
240
|
+
})();
|
|
210
241
|
node.resources = resources;
|
|
211
242
|
// 3. Acquire Locks
|
|
212
243
|
const mode = lane === 'read' ? 'read' : 'write';
|
|
@@ -221,7 +252,7 @@ export class ParallelScheduler {
|
|
|
221
252
|
id: nodeId,
|
|
222
253
|
phase: baseCtx.phase || 'execute',
|
|
223
254
|
toolName: node.toolName,
|
|
224
|
-
args:
|
|
255
|
+
args: normalizedArgs,
|
|
225
256
|
ctx: isolatedEnv
|
|
226
257
|
? { ...baseCtx, env: { ...baseCtx.env, ...isolatedEnv.env } }
|
|
227
258
|
: baseCtx,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { text } from '../../../locales/index.js';
|
|
2
2
|
import { normalizeDiff, validateDiff } from '../../patch/diff.js';
|
|
3
3
|
import { ArtifactStore } from '../../sub-agent/artifacts/store.js';
|
|
4
|
+
import { normalizeRepoRelativePath } from '../../utils/path.js';
|
|
4
5
|
const DEFAULT_TOOL_ALIASES = {
|
|
5
6
|
bash: 'Bash',
|
|
6
7
|
read: 'Read',
|
|
@@ -15,7 +16,7 @@ const ALIAS_TOOL_TO_INTERNAL_TOOL_NAMES = {
|
|
|
15
16
|
Bash: ['shell.exec', 'test.run'],
|
|
16
17
|
Read: ['fs.read', 'code.read', 'git.cat', 'artifact.read'],
|
|
17
18
|
Edit: ['proposal.apply'],
|
|
18
|
-
LS: ['fs.list', 'git.status'],
|
|
19
|
+
LS: ['fs.list', 'fs.list_directory', 'fs.list_files', 'git.status'],
|
|
19
20
|
Grep: ['code.search'],
|
|
20
21
|
Glob: ['code.search'],
|
|
21
22
|
WebFetch: [],
|
|
@@ -182,14 +183,6 @@ function compileBashMatcher(specifier) {
|
|
|
182
183
|
};
|
|
183
184
|
return { kind: 'pattern', rawSpecifier: specifier, matches, isExactMatch };
|
|
184
185
|
}
|
|
185
|
-
function normalizeRepoRelativePath(input) {
|
|
186
|
-
const raw = String(input ?? '')
|
|
187
|
-
.replace(/\\/g, '/')
|
|
188
|
-
.trim();
|
|
189
|
-
const withoutDot = raw.replace(/^\.\//, '');
|
|
190
|
-
const withoutLeadingSlash = withoutDot.replace(/^\/+/, '');
|
|
191
|
-
return withoutLeadingSlash.replace(/\/{2,}/g, '/');
|
|
192
|
-
}
|
|
193
186
|
function compilePathMatcher(specifier) {
|
|
194
187
|
const spec = normalizeRepoRelativePath(String(specifier ?? '').trim());
|
|
195
188
|
if (!spec || spec === '*') {
|
|
@@ -243,6 +236,8 @@ function compileRule(effect, parsed) {
|
|
|
243
236
|
tool === 'code.read' ||
|
|
244
237
|
tool === 'git.cat' ||
|
|
245
238
|
tool === 'fs.list' ||
|
|
239
|
+
tool === 'fs.list_directory' ||
|
|
240
|
+
tool === 'fs.list_files' ||
|
|
246
241
|
tool === 'artifact.read' ||
|
|
247
242
|
asAlias === 'Read' ||
|
|
248
243
|
asAlias === 'LS';
|
|
@@ -335,7 +330,7 @@ function extractPrimaryPathArg(toolName, args) {
|
|
|
335
330
|
return typeof obj.file === 'string' ? obj.file : undefined;
|
|
336
331
|
if (toolName === 'git.cat')
|
|
337
332
|
return typeof obj.file === 'string' ? obj.file : undefined;
|
|
338
|
-
if (toolName === 'fs.list')
|
|
333
|
+
if (toolName === 'fs.list' || toolName === 'fs.list_directory' || toolName === 'fs.list_files')
|
|
339
334
|
return typeof obj.path === 'string' ? obj.path : undefined;
|
|
340
335
|
return undefined;
|
|
341
336
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { resolveExecutionProfile } from '../runtime/execution-profile.js';
|
|
1
2
|
import { Phase } from '../types/runtime.js';
|
|
2
3
|
export class ToolPolicy {
|
|
3
4
|
/**
|
|
@@ -15,6 +16,10 @@ export class ToolPolicy {
|
|
|
15
16
|
const hasRuntimeWrite = spec.sideEffects.includes('runtime_write');
|
|
16
17
|
const hasProcess = spec.sideEffects.includes('process');
|
|
17
18
|
const hasNetwork = spec.sideEffects.includes('network');
|
|
19
|
+
const profile = ctx.flowMode ? resolveExecutionProfile(ctx.flowMode) : undefined;
|
|
20
|
+
const autopilotDirect = phase === Phase.AUTOPILOT &&
|
|
21
|
+
profile?.mode === 'autopilot' &&
|
|
22
|
+
profile.failurePolicy === 'preserve';
|
|
18
23
|
// 3. APPLY phase is strictly for patch application, NO tool calls allowed
|
|
19
24
|
if (phase === Phase.APPLY) {
|
|
20
25
|
return {
|
|
@@ -32,7 +37,7 @@ export class ToolPolicy {
|
|
|
32
37
|
}
|
|
33
38
|
// 5. Worktree Requirement for Side Effects
|
|
34
39
|
// Any repo-mutating tool or process/network execution MUST have a worktree.
|
|
35
|
-
if ((hasRepoWrite || hasProcess || hasNetwork) && !ctx.worktreeRoot) {
|
|
40
|
+
if ((hasRepoWrite || hasProcess || hasNetwork) && !ctx.worktreeRoot && !autopilotDirect) {
|
|
36
41
|
return {
|
|
37
42
|
allowed: false,
|
|
38
43
|
denyReason: `Tool ${spec.name} has side effects [${spec.sideEffects.join(',')}] and requires worktree isolation`,
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export const RECOVERABLE_TOOL_INPUT_ERROR_CODES = [
|
|
2
|
+
'INVALID_INPUT',
|
|
3
|
+
'INVALID_TOOL_ARGUMENTS_JSON',
|
|
4
|
+
'MALFORMED_TOOL_CALL',
|
|
5
|
+
];
|
|
6
|
+
const RECOVERABLE_TOOL_INPUT_ERROR_CODE_SET = new Set(RECOVERABLE_TOOL_INPUT_ERROR_CODES);
|
|
7
|
+
export function isRecoverableToolInputErrorCode(code) {
|
|
8
|
+
return typeof code === 'string' && RECOVERABLE_TOOL_INPUT_ERROR_CODE_SET.has(code);
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=recoverable-tool-errors.js.map
|
|
@@ -185,7 +185,7 @@ export class ToolRouter {
|
|
|
185
185
|
}
|
|
186
186
|
// 5. Budget Gating & Execution: Concurrency control, timeout, and execution
|
|
187
187
|
const rawOutput = await this.budget.runWithGuards({
|
|
188
|
-
timeoutMs: LIMITS.defaultToolTimeoutMs,
|
|
188
|
+
timeoutMs: spec.defaultTimeoutMs ?? LIMITS.defaultToolTimeoutMs,
|
|
189
189
|
maxOutputBytes: LIMITS.maxToolOutputBytes,
|
|
190
190
|
phase: normalizedEnvelope.phase,
|
|
191
191
|
toolName: spec.name,
|
|
@@ -303,7 +303,7 @@ export class ToolRouter {
|
|
|
303
303
|
if (permissionDecision.kind === 'allow') {
|
|
304
304
|
return { kind: 'ready' };
|
|
305
305
|
}
|
|
306
|
-
const cacheKey = this.buildAuthorizationKey(normalizedEnvelope);
|
|
306
|
+
const cacheKey = this.buildAuthorizationKey(normalizedEnvelope, spec);
|
|
307
307
|
if (this.isAuthorizationCached(cacheKey)) {
|
|
308
308
|
return { kind: 'ready' };
|
|
309
309
|
}
|
|
@@ -370,8 +370,24 @@ export class ToolRouter {
|
|
|
370
370
|
},
|
|
371
371
|
};
|
|
372
372
|
}
|
|
373
|
-
buildAuthorizationKey(envelope) {
|
|
374
|
-
|
|
373
|
+
buildAuthorizationKey(envelope, spec) {
|
|
374
|
+
const base = `${envelope.toolName}:${envelope.phase}`;
|
|
375
|
+
if (this.isHighRiskTool(spec)) {
|
|
376
|
+
const argsHash = this.hashArgs(envelope.args);
|
|
377
|
+
return argsHash ? `${base}:${argsHash}` : base;
|
|
378
|
+
}
|
|
379
|
+
// Low-risk (read-only) tools use toolName:phase only — a single approval
|
|
380
|
+
// covers all argument variations since these tools have no dangerous side effects.
|
|
381
|
+
return base;
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Determines whether a tool is high-risk based on its declared side effects.
|
|
385
|
+
* High-risk tools (process, fs_write, network) require stricter authorization
|
|
386
|
+
* cache scoping — see {@link buildAuthorizationKey}.
|
|
387
|
+
*/
|
|
388
|
+
isHighRiskTool(spec) {
|
|
389
|
+
const HIGH_RISK_EFFECTS = ['process', 'fs_write', 'network'];
|
|
390
|
+
return (spec.sideEffects ?? []).some((e) => HIGH_RISK_EFFECTS.includes(e));
|
|
375
391
|
}
|
|
376
392
|
isAuthorizationCached(key) {
|
|
377
393
|
const entry = this.authorizationCache.get(key);
|
|
@@ -401,6 +417,8 @@ export class ToolRouter {
|
|
|
401
417
|
return undefined;
|
|
402
418
|
try {
|
|
403
419
|
const raw = JSON.stringify(args);
|
|
420
|
+
// Full SHA-256 hex digest (64 chars / 256-bit) for authorization cache keys.
|
|
421
|
+
// Truncation to 16 hex was insufficient collision resistance for security use.
|
|
404
422
|
return crypto.createHash('sha256').update(raw).digest('hex');
|
|
405
423
|
}
|
|
406
424
|
catch {
|
|
@@ -410,7 +428,7 @@ export class ToolRouter {
|
|
|
410
428
|
async authorizeToolCall(envelope, spec) {
|
|
411
429
|
if (!this.authorization)
|
|
412
430
|
return { kind: 'allow' };
|
|
413
|
-
const cacheKey = this.buildAuthorizationKey(envelope);
|
|
431
|
+
const cacheKey = this.buildAuthorizationKey(envelope, spec);
|
|
414
432
|
if (this.isAuthorizationCached(cacheKey)) {
|
|
415
433
|
this.audit.onAuthorization({
|
|
416
434
|
callId: envelope.id,
|
|
@@ -486,7 +504,7 @@ export class ToolRouter {
|
|
|
486
504
|
}
|
|
487
505
|
if (decision.outcome === 'allow_session' || decision.outcome === 'allow') {
|
|
488
506
|
const expiresAt = typeof decision.ttlMs === 'number' ? Date.now() + decision.ttlMs : undefined;
|
|
489
|
-
const cacheKey = this.buildAuthorizationKey(envelope);
|
|
507
|
+
const cacheKey = this.buildAuthorizationKey(envelope, spec);
|
|
490
508
|
this.authorizationCache.set(cacheKey, { expiresAt });
|
|
491
509
|
}
|
|
492
510
|
return { kind: 'allow' };
|