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
|
@@ -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
|
|
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
|
}
|
|
@@ -31,6 +31,7 @@ export function createSalmonTaskExecutor(deps) {
|
|
|
31
31
|
authorizationProvider: options?.authorizationProvider,
|
|
32
32
|
authorizationMode: options?.authorizationMode,
|
|
33
33
|
fileSystemOverride: options?.fileSystemOverride,
|
|
34
|
+
extensions: task.request.extensions,
|
|
34
35
|
});
|
|
35
36
|
});
|
|
36
37
|
if (result.reasonCode === 'AWAITING_INPUT' && result.inputRequired) {
|
|
@@ -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
|
package/dist/core/config/load.js
CHANGED
|
@@ -4,25 +4,32 @@ import { parseConfigText } from './file-format.js';
|
|
|
4
4
|
import { getDefaultRepoConfigPaths, getDefaultUserConfigPaths, resolveConfigPath, } from './paths.js';
|
|
5
5
|
import { validateConfigFileV1 } from './validate.js';
|
|
6
6
|
async function loadFromCandidates(candidatePaths, required) {
|
|
7
|
-
|
|
8
|
-
const absPath = candidatePaths[i];
|
|
7
|
+
const results = await Promise.all(candidatePaths.map(async (absPath) => {
|
|
9
8
|
try {
|
|
10
9
|
const raw = await readFile(absPath, 'utf8');
|
|
11
10
|
const parsed = parseConfigText(raw, absPath);
|
|
12
11
|
const config = validateConfigFileV1(parsed);
|
|
13
|
-
return { path: absPath, config };
|
|
12
|
+
return { ok: true, absPath, loaded: { path: absPath, config } };
|
|
14
13
|
}
|
|
15
14
|
catch (e) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
15
|
+
return { ok: false, absPath, error: e };
|
|
16
|
+
}
|
|
17
|
+
}));
|
|
18
|
+
for (const [i, result] of results.entries()) {
|
|
19
|
+
if (result.ok) {
|
|
20
|
+
return result.loaded;
|
|
21
|
+
}
|
|
22
|
+
const code = result.error && typeof result.error === 'object' && 'code' in result.error
|
|
23
|
+
? result.error.code
|
|
24
|
+
: undefined;
|
|
25
|
+
if (code === 'ENOENT') {
|
|
26
|
+
const isLast = i === results.length - 1;
|
|
27
|
+
if (required && isLast) {
|
|
28
|
+
throw new ConfigError('CONFIG_FILE_NOT_FOUND', { path: result.absPath });
|
|
23
29
|
}
|
|
24
|
-
|
|
30
|
+
continue;
|
|
25
31
|
}
|
|
32
|
+
throw result.error;
|
|
26
33
|
}
|
|
27
34
|
return null;
|
|
28
35
|
}
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import { resolveBaseUrl } from '../llm/base-url.js';
|
|
2
2
|
import { ConfigError } from './errors.js';
|
|
3
3
|
import { firstProviderRef, resolveApiKey, resolveModelId } from './resolve-env.js';
|
|
4
|
+
function mergeCapabilities(providerCapabilities, modelCapabilities) {
|
|
5
|
+
if (!providerCapabilities && !modelCapabilities)
|
|
6
|
+
return undefined;
|
|
7
|
+
return {
|
|
8
|
+
...providerCapabilities,
|
|
9
|
+
...modelCapabilities,
|
|
10
|
+
};
|
|
11
|
+
}
|
|
4
12
|
export function resolveLlmFromConfig(raw) {
|
|
5
13
|
const llm = raw?.llm;
|
|
6
14
|
const providers = llm?.providers || {};
|
|
@@ -49,6 +57,7 @@ export function resolveLlmFromConfig(raw) {
|
|
|
49
57
|
const apiKeyResolution = resolveApiKey(provider.api?.apiKey);
|
|
50
58
|
const baseUrl = resolveBaseUrl(provider.api?.baseUrl);
|
|
51
59
|
const selectedModelId = resolveModelId(activeProfile.id);
|
|
60
|
+
const activeCapabilities = mergeCapabilities(provider.capabilities, activeProfile.capabilities);
|
|
52
61
|
const routing = llm?.routing;
|
|
53
62
|
const phaseToProviderModel = routing?.phaseToModel && typeof routing.phaseToModel === 'object'
|
|
54
63
|
? Object.fromEntries(Object.entries(routing.phaseToModel)
|
|
@@ -76,6 +85,7 @@ export function resolveLlmFromConfig(raw) {
|
|
|
76
85
|
});
|
|
77
86
|
}
|
|
78
87
|
const phaseKey = resolveApiKey(phaseProvider.api?.apiKey);
|
|
88
|
+
const capabilities = mergeCapabilities(phaseProvider.capabilities, profile.capabilities);
|
|
79
89
|
return [
|
|
80
90
|
phase,
|
|
81
91
|
{
|
|
@@ -93,6 +103,7 @@ export function resolveLlmFromConfig(raw) {
|
|
|
93
103
|
id: resolveModelId(profile.id),
|
|
94
104
|
slot: profileSlot,
|
|
95
105
|
},
|
|
106
|
+
capabilities,
|
|
96
107
|
},
|
|
97
108
|
];
|
|
98
109
|
})
|
|
@@ -124,6 +135,7 @@ export function resolveLlmFromConfig(raw) {
|
|
|
124
135
|
selectedModelId,
|
|
125
136
|
selectedModelSlot: activeModelSlot,
|
|
126
137
|
},
|
|
138
|
+
capabilities: activeCapabilities,
|
|
127
139
|
routing: resolvedRouting,
|
|
128
140
|
};
|
|
129
141
|
}
|
|
@@ -10,12 +10,6 @@ export function resolveServerConfig(raw) {
|
|
|
10
10
|
tokens: serverRaw.a2a.tokens,
|
|
11
11
|
};
|
|
12
12
|
}
|
|
13
|
-
if (serverRaw.sidecar) {
|
|
14
|
-
server.sidecar = {
|
|
15
|
-
socket: serverRaw.sidecar.socket,
|
|
16
|
-
allowConditional: serverRaw.sidecar.allowConditional,
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
13
|
if (serverRaw.acp) {
|
|
20
14
|
server.acp = {
|
|
21
15
|
sessionStore: {
|
|
@@ -26,6 +26,59 @@ function isValidMarkdownTheme(value) {
|
|
|
26
26
|
function isValidMarkdownRenderMode(value) {
|
|
27
27
|
return typeof value === 'string' && MARKDOWN_RENDER_MODES.includes(value);
|
|
28
28
|
}
|
|
29
|
+
function validateLlmCapabilities(input, context) {
|
|
30
|
+
if (input === undefined)
|
|
31
|
+
return undefined;
|
|
32
|
+
if (!isRecord(input)) {
|
|
33
|
+
throw new ConfigError('CONFIG_INVALID_LLM_CAPABILITIES', {
|
|
34
|
+
...context,
|
|
35
|
+
expected: 'object',
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
const allowedKeys = new Set(['toolCalling', 'responseFormatJsonObject', 'streaming']);
|
|
39
|
+
for (const key of Object.keys(input)) {
|
|
40
|
+
if (!allowedKeys.has(key)) {
|
|
41
|
+
throw new ConfigError('CONFIG_INVALID_LLM_CAPABILITY', {
|
|
42
|
+
...context,
|
|
43
|
+
capability: key,
|
|
44
|
+
expected: 'toolCalling|responseFormatJsonObject|streaming',
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const cfg = {};
|
|
49
|
+
for (const key of ['toolCalling', 'responseFormatJsonObject', 'streaming']) {
|
|
50
|
+
if (input[key] !== undefined && !isBoolean(input[key])) {
|
|
51
|
+
throw new ConfigError('CONFIG_INVALID_LLM_CAPABILITY', {
|
|
52
|
+
...context,
|
|
53
|
+
capability: key,
|
|
54
|
+
expected: 'boolean',
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
if (input[key] !== undefined) {
|
|
58
|
+
cfg[key] = input[key];
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return cfg;
|
|
62
|
+
}
|
|
63
|
+
function normalizeLlmModelParams(input, context) {
|
|
64
|
+
if (!isRecord(input))
|
|
65
|
+
return undefined;
|
|
66
|
+
for (const key of [
|
|
67
|
+
'capabilities',
|
|
68
|
+
'toolCalling',
|
|
69
|
+
'responseFormatJsonObject',
|
|
70
|
+
'streaming',
|
|
71
|
+
]) {
|
|
72
|
+
if (input[key] !== undefined) {
|
|
73
|
+
throw new ConfigError('CONFIG_INVALID_LLM_CAPABILITY_LOCATION', {
|
|
74
|
+
...context,
|
|
75
|
+
capability: key,
|
|
76
|
+
expected: 'model.capabilities',
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return input;
|
|
81
|
+
}
|
|
29
82
|
export function validateConfigFileV1(input) {
|
|
30
83
|
if (!isRecord(input)) {
|
|
31
84
|
throw new ConfigError('CONFIG_INVALID_ROOT', { expected: 'object' });
|
|
@@ -164,6 +217,11 @@ export function validateConfigFileV1(input) {
|
|
|
164
217
|
if (!isRecord(serverRaw)) {
|
|
165
218
|
throw new ConfigError('CONFIG_INVALID_SERVER', { expected: 'object' });
|
|
166
219
|
}
|
|
220
|
+
for (const key of Object.keys(serverRaw)) {
|
|
221
|
+
if (key !== 'a2a' && key !== 'acp') {
|
|
222
|
+
throw new ConfigError('CONFIG_INVALID_SERVER_UNKNOWN_KEY', { key });
|
|
223
|
+
}
|
|
224
|
+
}
|
|
167
225
|
const server = {};
|
|
168
226
|
if (serverRaw.a2a !== undefined) {
|
|
169
227
|
if (!isRecord(serverRaw.a2a)) {
|
|
@@ -187,24 +245,6 @@ export function validateConfigFileV1(input) {
|
|
|
187
245
|
tokens: a2aRaw.tokens,
|
|
188
246
|
};
|
|
189
247
|
}
|
|
190
|
-
if (serverRaw.sidecar !== undefined) {
|
|
191
|
-
if (!isRecord(serverRaw.sidecar)) {
|
|
192
|
-
throw new ConfigError('CONFIG_INVALID_SERVER_SIDECAR', { expected: 'object' });
|
|
193
|
-
}
|
|
194
|
-
const sidecarRaw = serverRaw.sidecar;
|
|
195
|
-
if (sidecarRaw.socket !== undefined && !isString(sidecarRaw.socket)) {
|
|
196
|
-
throw new ConfigError('CONFIG_INVALID_SERVER_SIDECAR_SOCKET', { expected: 'string' });
|
|
197
|
-
}
|
|
198
|
-
if (sidecarRaw.allowConditional !== undefined && !isBoolean(sidecarRaw.allowConditional)) {
|
|
199
|
-
throw new ConfigError('CONFIG_INVALID_SERVER_SIDECAR_ALLOW_CONDITIONAL', {
|
|
200
|
-
expected: 'boolean',
|
|
201
|
-
});
|
|
202
|
-
}
|
|
203
|
-
server.sidecar = {
|
|
204
|
-
socket: sidecarRaw.socket,
|
|
205
|
-
allowConditional: sidecarRaw.allowConditional,
|
|
206
|
-
};
|
|
207
|
-
}
|
|
208
248
|
if (serverRaw.acp !== undefined) {
|
|
209
249
|
if (!isRecord(serverRaw.acp)) {
|
|
210
250
|
throw new ConfigError('CONFIG_INVALID_SERVER_ACP', { expected: 'object' });
|
|
@@ -561,6 +601,12 @@ export function validateConfigFileV1(input) {
|
|
|
561
601
|
hint: 'use llm.models with provider references',
|
|
562
602
|
});
|
|
563
603
|
}
|
|
604
|
+
const providerCapabilities = validateLlmCapabilities(rawProvider.capabilities, {
|
|
605
|
+
provider: id,
|
|
606
|
+
});
|
|
607
|
+
if (providerCapabilities) {
|
|
608
|
+
p.capabilities = providerCapabilities;
|
|
609
|
+
}
|
|
564
610
|
cfg.llm.providers[id] = p;
|
|
565
611
|
}
|
|
566
612
|
}
|
|
@@ -590,12 +636,18 @@ export function validateConfigFileV1(input) {
|
|
|
590
636
|
expected: 'non_empty_string',
|
|
591
637
|
});
|
|
592
638
|
}
|
|
639
|
+
const params = normalizeLlmModelParams(rawModel.params, {
|
|
640
|
+
model: slot,
|
|
641
|
+
location: 'params',
|
|
642
|
+
});
|
|
643
|
+
const capabilities = validateLlmCapabilities(rawModel.capabilities, {
|
|
644
|
+
model: slot,
|
|
645
|
+
});
|
|
593
646
|
cfg.llm.models[slot] = {
|
|
594
647
|
provider: provider,
|
|
595
648
|
id: rawModel.id,
|
|
596
|
-
params
|
|
597
|
-
|
|
598
|
-
: undefined,
|
|
649
|
+
params,
|
|
650
|
+
capabilities,
|
|
599
651
|
};
|
|
600
652
|
}
|
|
601
653
|
}
|
|
@@ -1,8 +1,89 @@
|
|
|
1
|
+
import { FileAdapter } from '../../adapters/fs/file-adapter.js';
|
|
1
2
|
import { LIMITS } from '../../config/limits.js';
|
|
2
3
|
import { getLogger } from '../../observability/logger.js';
|
|
3
4
|
import { spawnCommand } from '../../runtime/process-runner.js';
|
|
4
|
-
import { normalizePath } from '../../utils/path.js';
|
|
5
|
+
import { ensureInSandbox, normalizePath, safeJoin, safeRelative } from '../../utils/path.js';
|
|
6
|
+
const FALLBACK_EXCLUDED_DIRS = new Set(['.git', 'node_modules']);
|
|
7
|
+
const FALLBACK_MAX_FILES = 2000;
|
|
8
|
+
const FALLBACK_MAX_FILE_BYTES = Math.max(LIMITS.largeFileThresholdBytes, 64 * 1024);
|
|
9
|
+
const fileAdapter = new FileAdapter();
|
|
10
|
+
function isHiddenPathSegment(name) {
|
|
11
|
+
return name.startsWith('.');
|
|
12
|
+
}
|
|
13
|
+
function isBinaryLike(content) {
|
|
14
|
+
return content.includes('\0');
|
|
15
|
+
}
|
|
5
16
|
export class RipgrepGatherer {
|
|
17
|
+
async searchFileSystem(query, cwd, signal) {
|
|
18
|
+
const needle = query.toLowerCase();
|
|
19
|
+
if (!needle)
|
|
20
|
+
return [];
|
|
21
|
+
const results = [];
|
|
22
|
+
let scannedFiles = 0;
|
|
23
|
+
const pending = ['.'];
|
|
24
|
+
while (pending.length > 0 && scannedFiles < FALLBACK_MAX_FILES) {
|
|
25
|
+
if (signal?.aborted)
|
|
26
|
+
throw new Error('Operation cancelled by user');
|
|
27
|
+
const current = pending.shift();
|
|
28
|
+
const absoluteCurrent = ensureInSandbox(cwd, safeJoin(cwd, current));
|
|
29
|
+
let entries;
|
|
30
|
+
try {
|
|
31
|
+
entries = await fileAdapter.readdirWithTypes(absoluteCurrent);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
37
|
+
for (const entry of entries) {
|
|
38
|
+
if (signal?.aborted)
|
|
39
|
+
throw new Error('Operation cancelled by user');
|
|
40
|
+
if (isHiddenPathSegment(entry.name))
|
|
41
|
+
continue;
|
|
42
|
+
if (entry.isSymbolicLink())
|
|
43
|
+
continue;
|
|
44
|
+
const relativePath = normalizePath(safeJoin(current, entry.name)).replace(/^(\.\/|\/)+/, '');
|
|
45
|
+
if (!relativePath)
|
|
46
|
+
continue;
|
|
47
|
+
if (entry.isDirectory()) {
|
|
48
|
+
if (FALLBACK_EXCLUDED_DIRS.has(entry.name))
|
|
49
|
+
continue;
|
|
50
|
+
pending.push(relativePath);
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (!entry.isFile())
|
|
54
|
+
continue;
|
|
55
|
+
scannedFiles += 1;
|
|
56
|
+
if (scannedFiles > FALLBACK_MAX_FILES)
|
|
57
|
+
break;
|
|
58
|
+
const absoluteFile = ensureInSandbox(cwd, safeJoin(cwd, relativePath));
|
|
59
|
+
try {
|
|
60
|
+
const stat = await fileAdapter.stat(absoluteFile);
|
|
61
|
+
if (!stat.isFile() || stat.size > FALLBACK_MAX_FILE_BYTES)
|
|
62
|
+
continue;
|
|
63
|
+
const content = await fileAdapter.readFile(absoluteFile, 'utf-8');
|
|
64
|
+
if (isBinaryLike(content))
|
|
65
|
+
continue;
|
|
66
|
+
const lines = content.split(/\r?\n/);
|
|
67
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
68
|
+
const line = lines[index] ?? '';
|
|
69
|
+
if (!line.toLowerCase().includes(needle))
|
|
70
|
+
continue;
|
|
71
|
+
results.push({
|
|
72
|
+
file: normalizePath(safeRelative(cwd, absoluteFile)),
|
|
73
|
+
line: index + 1,
|
|
74
|
+
content: line,
|
|
75
|
+
});
|
|
76
|
+
if (results.length >= LIMITS.defaultSearchMatches)
|
|
77
|
+
return results;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return results;
|
|
86
|
+
}
|
|
6
87
|
async runRipgrep(query, cwd, signal) {
|
|
7
88
|
getLogger().trace(` [RG] Searching for: "${query}" in ${cwd}`);
|
|
8
89
|
if (signal?.aborted) {
|
|
@@ -38,7 +119,8 @@ export class RipgrepGatherer {
|
|
|
38
119
|
getLogger().trace(` [RG] Process closed with code ${result.code}. Output length: ${output.length}`);
|
|
39
120
|
if (result.error) {
|
|
40
121
|
if (result.error.code === 'ENOENT') {
|
|
41
|
-
getLogger().error('Error: ripgrep (rg) not found in PATH.
|
|
122
|
+
getLogger().error('Error: ripgrep (rg) not found in PATH. Falling back to bounded filesystem search.');
|
|
123
|
+
return await this.searchFileSystem(query, cwd, signal);
|
|
42
124
|
}
|
|
43
125
|
else {
|
|
44
126
|
getLogger().error(`Error running ripgrep: ${result.error.message}`);
|