salmon-loop 0.2.3 → 0.2.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/argv/headless-detection.js +27 -0
- package/dist/cli/chat-flow.js +11 -0
- package/dist/cli/chat.js +161 -24
- package/dist/cli/commands/chat.js +30 -24
- package/dist/cli/commands/context.js +15 -3
- package/dist/cli/commands/flow-mode.js +63 -0
- package/dist/cli/commands/help-format.js +12 -0
- package/dist/cli/commands/registry.js +6 -7
- package/dist/cli/commands/run/benchmark-artifacts.js +41 -0
- package/dist/cli/commands/run/config-resolution.js +30 -24
- package/dist/cli/commands/run/early-errors.js +23 -0
- package/dist/cli/commands/run/handler.js +131 -44
- package/dist/cli/commands/run/headless-error-writer.js +8 -0
- package/dist/cli/commands/run/loop-params.js +3 -0
- package/dist/cli/commands/run/mode.js +2 -5
- package/dist/cli/commands/run/parse-options.js +18 -2
- 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/run/validate-options.js +0 -5
- package/dist/cli/commands/run/verbose.js +2 -7
- package/dist/cli/commands/serve.js +117 -90
- 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 +32 -6
- package/dist/cli/program-bootstrap.js +14 -4
- package/dist/cli/program-commands.js +9 -1
- package/dist/cli/program-options.js +1 -0
- 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 +30 -15
- 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/output-format.js +6 -0
- package/dist/cli/utils/resolve-cli-config.js +98 -0
- package/dist/cli/utils/verbose-level.js +8 -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/benchmark/patch-artifact.js +124 -0
- package/dist/core/benchmark/swe-bench.js +25 -0
- package/dist/core/config/load.js +39 -18
- package/dist/core/config/merge.js +27 -0
- package/dist/core/config/paths.js +24 -5
- package/dist/core/config/resolve-llm.js +12 -0
- package/dist/core/config/resolve.js +7 -5
- package/dist/core/config/resolvers/server.js +0 -6
- package/dist/core/config/validate.js +94 -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/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 +2 -1
- package/dist/core/facades/cli-command-tool-names.js +2 -0
- package/dist/core/facades/cli-context.js +1 -0
- package/dist/core/facades/cli-observability.js +1 -1
- 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 +2 -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 +173 -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 -3
- 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/intent/chat-intent.js +0 -4
- 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 +74 -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 +3 -2
- package/dist/core/protocols/a2a/sdk/executor.js +8 -6
- package/dist/core/protocols/a2a/sdk/server.js +0 -1
- package/dist/core/protocols/acp/formal-agent.js +221 -55
- package/dist/core/protocols/acp/handlers.js +5 -1
- package/dist/core/protocols/acp/permission-provider.js +21 -1
- package/dist/core/protocols/shared/execution-request.js +24 -0
- 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 +12 -4
- package/dist/core/session/manager.js +247 -10
- 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 +70 -13
- 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/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/interfaces/cli/task-runner.js +4 -3
- package/dist/languages/typescript/index.js +4 -1
- package/dist/locales/en.js +87 -2
- package/dist/utils/eol.js +1 -1
- package/package.json +15 -8
- 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
|
@@ -1,17 +1,26 @@
|
|
|
1
1
|
import { createSlashRegistry, createStandardToolstack, executeSkill, logIgnoredError, getLogger, RuntimeEnvironment, SkillLoader, SlashRouter, } from '../../core/facades/cli-slash-runtime.js';
|
|
2
|
+
import { formatHelpRows } from '../commands/help-format.js';
|
|
2
3
|
import { suggestSubcommands } from '../commands/subcommand-suggestions.js';
|
|
3
4
|
import { text } from '../locales/index.js';
|
|
4
5
|
function isSafeSkillId(id) {
|
|
5
6
|
return /^[a-z0-9][a-z0-9-_]*$/i.test(id);
|
|
6
7
|
}
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Build a SlashCommandSpec from a Tier 1 catalog entry (lightweight metadata).
|
|
10
|
+
*
|
|
11
|
+
* This supports the AgentSkills progressive disclosure pattern: only name and
|
|
12
|
+
* description are needed at startup to populate the slash command registry.
|
|
13
|
+
* Full skill content is loaded on demand via SkillLoader.activateSkill().
|
|
14
|
+
*
|
|
15
|
+
* @see https://agentskills.io/specification — Progressive disclosure
|
|
16
|
+
*/
|
|
17
|
+
function catalogEntryToSlashSpec(entry) {
|
|
18
|
+
const id = String(entry.id || '').trim();
|
|
9
19
|
if (!id || !isSafeSkillId(id))
|
|
10
20
|
return null;
|
|
11
21
|
return {
|
|
12
22
|
name: `/${id}`,
|
|
13
|
-
description:
|
|
14
|
-
hidden: skill.metadata?.userInvocable === false,
|
|
23
|
+
description: entry.description || `Skill: ${id}`,
|
|
15
24
|
order: 220,
|
|
16
25
|
};
|
|
17
26
|
}
|
|
@@ -27,11 +36,15 @@ function commandToSlashSpec(cmd) {
|
|
|
27
36
|
export async function createCliSlashRuntime(options) {
|
|
28
37
|
const skillLoader = new SkillLoader({
|
|
29
38
|
repoRoot: options.repoRoot,
|
|
30
|
-
useDefaults: options.skillDiscovery?.useDefaults,
|
|
31
39
|
extraPaths: options.skillDiscovery?.paths,
|
|
32
40
|
});
|
|
33
|
-
|
|
34
|
-
|
|
41
|
+
// Tier 1: Load lightweight catalog (name + description only, ~50-100 tokens per skill).
|
|
42
|
+
// Full skill content is loaded on demand via activateSkill() (Tier 2).
|
|
43
|
+
// @see https://agentskills.io/specification — Progressive disclosure
|
|
44
|
+
const catalog = await skillLoader.loadCatalog();
|
|
45
|
+
const skillSpecs = catalog
|
|
46
|
+
.map(catalogEntryToSlashSpec)
|
|
47
|
+
.filter((s) => Boolean(s));
|
|
35
48
|
const commandSpecs = options.baseCommands.map(commandToSlashSpec);
|
|
36
49
|
// /help is best-effort and must reflect the effective registry (including skills).
|
|
37
50
|
const helpSpec = {
|
|
@@ -50,11 +63,11 @@ export async function createCliSlashRuntime(options) {
|
|
|
50
63
|
}
|
|
51
64
|
}
|
|
52
65
|
const skillBySlash = new Map();
|
|
53
|
-
for (const
|
|
54
|
-
const spec =
|
|
66
|
+
for (const entry of catalog) {
|
|
67
|
+
const spec = catalogEntryToSlashSpec(entry);
|
|
55
68
|
if (!spec)
|
|
56
69
|
continue;
|
|
57
|
-
skillBySlash.set(spec.name.toLowerCase(),
|
|
70
|
+
skillBySlash.set(spec.name.toLowerCase(), entry);
|
|
58
71
|
}
|
|
59
72
|
const handlers = {
|
|
60
73
|
getHandler(commandName) {
|
|
@@ -63,12 +76,11 @@ export async function createCliSlashRuntime(options) {
|
|
|
63
76
|
const handler = {
|
|
64
77
|
execute: async (_req) => {
|
|
65
78
|
const visible = registry.list().filter((c) => !c.hidden);
|
|
66
|
-
const
|
|
67
|
-
const rows = visible.map((c) => `${c.name}`.padEnd(maxName + 2) + c.description);
|
|
79
|
+
const rows = formatHelpRows(visible);
|
|
68
80
|
options.emit({
|
|
69
81
|
type: 'log',
|
|
70
82
|
level: 'info',
|
|
71
|
-
message: text.cli.helpAvailableCommands(rows
|
|
83
|
+
message: text.cli.helpAvailableCommands(rows),
|
|
72
84
|
timestamp: new Date(),
|
|
73
85
|
});
|
|
74
86
|
return { kind: 'consumed' };
|
|
@@ -115,10 +127,13 @@ export async function createCliSlashRuntime(options) {
|
|
|
115
127
|
: undefined,
|
|
116
128
|
};
|
|
117
129
|
}
|
|
118
|
-
const
|
|
119
|
-
if (
|
|
130
|
+
const catalogEntry = skillBySlash.get(normalized);
|
|
131
|
+
if (catalogEntry) {
|
|
120
132
|
return {
|
|
121
133
|
execute: async (req) => {
|
|
134
|
+
// Tier 2: Activate skill on demand — load full SKILL.md content.
|
|
135
|
+
// @see https://agentskills.io/specification — Progressive disclosure
|
|
136
|
+
const skill = await skillLoader.activateSkill(catalogEntry.id);
|
|
122
137
|
const meta = (req.meta ?? {});
|
|
123
138
|
const signal = meta?.signal;
|
|
124
139
|
// Prepare an isolated worktree environment for governed shell execution.
|
|
@@ -9,6 +9,7 @@ import { useCommandSuggestions } from '../hooks/useCommandSuggestions.js';
|
|
|
9
9
|
import { useInputHistory } from '../hooks/useInputHistory.js';
|
|
10
10
|
import { rejectSelection, resolveSelection } from '../selection/bus.js';
|
|
11
11
|
import { useUIStore } from '../store/context.js';
|
|
12
|
+
import { COLORS } from '../styles/theme.js';
|
|
12
13
|
import { CommandSuggestionList } from './CommandSuggestionList.js';
|
|
13
14
|
export const CommandInput = ({ value, onChange, onSubmit, placeholder, getSuggestions, findCommand, }) => {
|
|
14
15
|
const { state, dispatch } = useUIStore();
|
|
@@ -185,16 +186,19 @@ export const CommandInput = ({ value, onChange, onSubmit, placeholder, getSugges
|
|
|
185
186
|
: en.gui.selectionPlaceholder
|
|
186
187
|
: isIntercepting && activeChallenge
|
|
187
188
|
? en.gui.confirmationChallenge(activeChallenge)
|
|
188
|
-
: placeholder }, inputKey), ghostText && (_jsx(Text, { color:
|
|
189
|
+
: placeholder }, inputKey), ghostText && (_jsx(Text, { color: COLORS.text.muted, dimColor: true, children: ghostText }))] }), isIntercepting && (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: COLORS.semantic.yellow, paddingX: 1, children: [_jsx(Text, { color: COLORS.semantic.yellow, bold: true, children: isSelecting
|
|
189
190
|
? pendingSelection?.title
|
|
190
191
|
: isAuthorizing
|
|
191
192
|
? en.gui.authorizationTitle
|
|
192
|
-
: en.gui.confirmationTitle }), !isSelecting && (_jsx(Text, { color:
|
|
193
|
+
: en.gui.confirmationTitle }), !isSelecting && (_jsx(Text, { color: COLORS.text.primary, children: isAuthorizing ? pendingAuthorization?.message : pendingConfirmation?.message })), _jsx(Text, { color: COLORS.text.muted, dimColor: true, children: isSelecting
|
|
193
194
|
? isMultiSelecting
|
|
194
195
|
? en.gui.selectionHintMulti
|
|
195
196
|
: en.gui.selectionHint
|
|
196
197
|
: isAuthorizing
|
|
197
198
|
? en.gui.authorizationWarning
|
|
198
|
-
: en.gui.highRiskWarning }), isAuthorizing && (_jsx(Text, { color:
|
|
199
|
+
: en.gui.highRiskWarning }), isAuthorizing && (_jsx(Text, { color: COLORS.text.muted, dimColor: true, children: en.gui.authorizationHint })), isSelecting && pendingSelection && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: pendingSelection.items.map((item, idx) => {
|
|
200
|
+
const isSelected = idx === selectionIndex;
|
|
201
|
+
return (_jsxs(Text, { color: isSelected ? COLORS.semantic.cyan : COLORS.text.muted, children: [isSelected ? '❯ ' : ' ', isMultiSelecting && (_jsx(Text, { color: selectedItems.includes(item.id) ? COLORS.semantic.cyan : COLORS.text.muted, children: selectedItems.includes(item.id) ? '[x] ' : '[ ] ' })), item.label, item.description ? ` - ${item.description}` : ''] }, item.id));
|
|
202
|
+
}) }))] })), !isIntercepting && suggestions.length > 0 && !isListClosed && (_jsx(CommandSuggestionList, { suggestions: visibleSuggestions, selectedIndex: selectedIndex - startIndex, parentCommand: activeCommand }))] }));
|
|
199
203
|
};
|
|
200
204
|
//# sourceMappingURL=CommandInput.js.map
|
|
@@ -14,7 +14,7 @@ export const CommandSuggestionList = ({ suggestions, selectedIndex, parentComman
|
|
|
14
14
|
return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: COLORS.border.subtle, marginTop: 0, marginBottom: 0, paddingX: 0, width: "100%", children: [_jsx(Box, { flexDirection: "column", paddingY: 0, children: suggestions.map((item, index) => {
|
|
15
15
|
const isSelected = index === selectedIndex;
|
|
16
16
|
const hasSubcommands = !!item.command?.subcommands?.length;
|
|
17
|
-
return (_jsxs(Box, { flexDirection: "row", paddingX: 1, children: [_jsx(Box, { width: 2, children: _jsx(Text, { color: COLORS.semantic.salmon, children: isSelected ? '│ ' : ' ' }) }), _jsx(Box, { width: maxNameLength + 4, children: _jsx(Text, { color: isSelected ? COLORS.semantic.cyan : COLORS.semantic.blue, bold: isSelected, children: item.name }) }), _jsx(Box, { width: 2, marginRight: 1, children: hasSubcommands ? _jsx(Text, { color: COLORS.text.muted, children: "
|
|
17
|
+
return (_jsxs(Box, { flexDirection: "row", paddingX: 1, children: [_jsx(Box, { width: 2, children: _jsx(Text, { color: COLORS.semantic.salmon, children: isSelected ? '│ ' : ' ' }) }), _jsx(Box, { width: maxNameLength + 4, children: _jsx(Text, { color: isSelected ? COLORS.semantic.cyan : COLORS.semantic.blue, bold: isSelected, children: item.name }) }), _jsx(Box, { width: 2, marginRight: 1, children: hasSubcommands ? _jsx(Text, { color: COLORS.text.muted, children: "\u203A" }) : _jsx(Text, { children: " " }) }), _jsx(Box, { flexGrow: 1, children: _jsx(Text, { color: isSelected ? COLORS.text.primary : COLORS.text.muted, wrap: "truncate", children: item.description }) })] }, `${item.name}-${index}`));
|
|
18
18
|
}) }), suggestions[selectedIndex]?.command?.usage && (_jsxs(Box, { flexDirection: "row", borderStyle: "single", borderTop: true, borderLeft: false, borderRight: false, borderBottom: false, borderColor: COLORS.border.subtle, paddingX: 1, paddingY: 0, children: [_jsx(Text, { color: COLORS.semantic.blue, children: "TIP: " }), _jsx(Text, { color: COLORS.text.muted, children: "Usage: " }), _jsx(Text, { color: COLORS.text.primary, children: suggestions[selectedIndex].command?.usage })] })), _jsxs(Box, { flexDirection: "row", borderStyle: "single", borderTop: true, borderLeft: false, borderRight: false, borderBottom: false, borderColor: COLORS.border.subtle, paddingX: 1, paddingY: 0, justifyContent: "space-between", children: [_jsxs(Box, { children: [_jsx(Text, { color: COLORS.semantic.salmon, children: "\u2502 " }), _jsx(Text, { color: COLORS.semantic.blue, bold: true, children: title })] }), _jsx(Box, { children: _jsx(Text, { color: COLORS.text.muted, dimColor: true, children: "\u2191\u2193 nav \u00B7 \u23CE select \u00B7 esc close" }) })] })] }));
|
|
19
19
|
};
|
|
20
20
|
//# sourceMappingURL=CommandSuggestionList.js.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export function getOptionValueSourceWithGlobalFallback(command, optionName) {
|
|
2
|
+
if (typeof command.getOptionValueSource === 'function') {
|
|
3
|
+
const direct = command.getOptionValueSource(optionName);
|
|
4
|
+
if (direct)
|
|
5
|
+
return direct;
|
|
6
|
+
}
|
|
7
|
+
const parent = command.parent;
|
|
8
|
+
if (parent && typeof parent.getOptionValueSource === 'function') {
|
|
9
|
+
return parent.getOptionValueSource(optionName);
|
|
10
|
+
}
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=command-option-source.js.map
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { defaultPathAdapter } from '../../core/adapters/path/path-adapter.js';
|
|
2
|
+
import { ConfigError, normalizeUiLogMode, resolveConfig } from '../../core/config/index.js';
|
|
3
|
+
import { text } from '../locales/index.js';
|
|
4
|
+
import { resolveAuditScope } from './audit-scope.js';
|
|
5
|
+
import { resolveOutputFormat } from './output-format.js';
|
|
6
|
+
import { resolveVerboseLevel } from './verbose-level.js';
|
|
7
|
+
export async function resolveCliConfig(params) {
|
|
8
|
+
const common = resolveCliCommonOptions({
|
|
9
|
+
repoPath: params.repoPath,
|
|
10
|
+
repo: params.repo,
|
|
11
|
+
cwd: params.cwd,
|
|
12
|
+
verbose: params.verbose,
|
|
13
|
+
outputFormat: params.outputFormat,
|
|
14
|
+
});
|
|
15
|
+
if (!common.ok) {
|
|
16
|
+
return { ok: false, message: common.message };
|
|
17
|
+
}
|
|
18
|
+
const { repoPath, verboseLevel, outputFormat, headlessOutput } = common.options;
|
|
19
|
+
let resolvedConfig;
|
|
20
|
+
try {
|
|
21
|
+
resolvedConfig = await resolveConfig({
|
|
22
|
+
repoRoot: repoPath,
|
|
23
|
+
configFilePath: params.configPath,
|
|
24
|
+
enableConfigFile: params.enableConfigFile !== false,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
catch (err) {
|
|
28
|
+
if (err instanceof ConfigError) {
|
|
29
|
+
return {
|
|
30
|
+
ok: false,
|
|
31
|
+
message: text.config.error(err.code || err.message, err.details),
|
|
32
|
+
errorCode: err.code,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
36
|
+
return { ok: false, message: text.config.loadFailed(msg) };
|
|
37
|
+
}
|
|
38
|
+
const auditScopeResolution = resolveAuditScope({
|
|
39
|
+
cliValue: params.auditScope,
|
|
40
|
+
configValue: resolvedConfig.observability.audit.scope,
|
|
41
|
+
});
|
|
42
|
+
if (!auditScopeResolution.ok) {
|
|
43
|
+
return {
|
|
44
|
+
ok: false,
|
|
45
|
+
message: text.cli.invalidAuditScope(auditScopeResolution.invalid),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
if (params.logMode !== undefined) {
|
|
49
|
+
const normalized = normalizeUiLogMode(params.logMode);
|
|
50
|
+
if (!normalized) {
|
|
51
|
+
return { ok: false, message: text.cli.logModeInvalid(String(params.logMode)) };
|
|
52
|
+
}
|
|
53
|
+
resolvedConfig = {
|
|
54
|
+
...resolvedConfig,
|
|
55
|
+
ui: {
|
|
56
|
+
...resolvedConfig.ui,
|
|
57
|
+
logMode: normalized,
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
ok: true,
|
|
63
|
+
repoPath,
|
|
64
|
+
verboseLevel,
|
|
65
|
+
outputFormat,
|
|
66
|
+
headlessOutput,
|
|
67
|
+
resolvedConfig,
|
|
68
|
+
auditScope: auditScopeResolution.value,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
export function resolveRepoPath(params) {
|
|
72
|
+
return defaultPathAdapter.resolve(params.repo || params.cwd || process.cwd());
|
|
73
|
+
}
|
|
74
|
+
export function resolveCliCommonOptions(params) {
|
|
75
|
+
const repoPath = params.repoPath ?? resolveRepoPath({ repo: params.repo, cwd: params.cwd });
|
|
76
|
+
const verboseLevel = resolveVerboseLevel(params.verbose);
|
|
77
|
+
let outputFormat;
|
|
78
|
+
let headlessOutput;
|
|
79
|
+
if (params.outputFormat !== undefined) {
|
|
80
|
+
const raw = String(params.outputFormat || '');
|
|
81
|
+
const resolved = resolveOutputFormat(raw);
|
|
82
|
+
if (!resolved) {
|
|
83
|
+
return { ok: false, message: text.cli.invalidOutputFormat(raw) };
|
|
84
|
+
}
|
|
85
|
+
outputFormat = resolved;
|
|
86
|
+
headlessOutput = resolved !== 'text';
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
ok: true,
|
|
90
|
+
options: {
|
|
91
|
+
repoPath,
|
|
92
|
+
verboseLevel,
|
|
93
|
+
outputFormat,
|
|
94
|
+
headlessOutput,
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=resolve-cli-config.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { tryGetLogger } from '../../core/facades/cli-observability.js';
|
|
2
2
|
import { text } from '../../locales/index.js';
|
|
3
3
|
import { autoDetectVerifyCommand } from './detectors/index.js';
|
|
4
4
|
/**
|
|
@@ -8,11 +8,11 @@ import { autoDetectVerifyCommand } from './detectors/index.js';
|
|
|
8
8
|
* 3. Config file command -> "cmd"
|
|
9
9
|
* 4. Auto-detection -> "detected-cmd"
|
|
10
10
|
*/
|
|
11
|
-
export async function resolveVerifyOption(repoPath, cliVerify, configVerify) {
|
|
11
|
+
export async function resolveVerifyOption(repoPath, cliVerify, configVerify, options = {}) {
|
|
12
12
|
// 1. Explicitly disabled via --no-verify
|
|
13
13
|
// Commander sets options.verify to false when --no-verify is used
|
|
14
14
|
if (cliVerify === false) {
|
|
15
|
-
|
|
15
|
+
tryGetLogger()?.debug(text.verify.explicitlyDisabled);
|
|
16
16
|
return undefined;
|
|
17
17
|
}
|
|
18
18
|
// 2. Explicitly provided via CLI --verify "cmd"
|
|
@@ -26,7 +26,11 @@ export async function resolveVerifyOption(repoPath, cliVerify, configVerify) {
|
|
|
26
26
|
// 4. Auto-detect
|
|
27
27
|
const detected = await autoDetectVerifyCommand(repoPath);
|
|
28
28
|
if (detected) {
|
|
29
|
-
|
|
29
|
+
const logger = tryGetLogger();
|
|
30
|
+
if (options.quiet)
|
|
31
|
+
logger?.debug(text.verify.autoDetected(detected));
|
|
32
|
+
else
|
|
33
|
+
logger?.info(text.verify.autoDetected(detected));
|
|
30
34
|
return detected;
|
|
31
35
|
}
|
|
32
36
|
return undefined;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { tryGetLogger } from '../../core/facades/cli-utils-worktree.js';
|
|
2
2
|
import { text } from '../../locales/index.js';
|
|
3
3
|
import { autoDetectWorktreePrepareCommand } from './detectors/index.js';
|
|
4
|
-
export async function resolveWorktreePrepareOption(repoPath, strategy, cliWorktreePrepare) {
|
|
4
|
+
export async function resolveWorktreePrepareOption(repoPath, strategy, cliWorktreePrepare, options = {}) {
|
|
5
5
|
if (typeof cliWorktreePrepare === 'string' && cliWorktreePrepare.trim()) {
|
|
6
6
|
return cliWorktreePrepare;
|
|
7
7
|
}
|
|
@@ -10,7 +10,11 @@ export async function resolveWorktreePrepareOption(repoPath, strategy, cliWorktr
|
|
|
10
10
|
}
|
|
11
11
|
const detected = await autoDetectWorktreePrepareCommand(repoPath);
|
|
12
12
|
if (detected) {
|
|
13
|
-
|
|
13
|
+
const logger = tryGetLogger();
|
|
14
|
+
if (options.quiet)
|
|
15
|
+
logger?.debug(text.verify.autoDetectedWorktreePrepare(detected));
|
|
16
|
+
else
|
|
17
|
+
logger?.info(text.verify.autoDetectedWorktreePrepare(detected));
|
|
14
18
|
return detected;
|
|
15
19
|
}
|
|
16
20
|
return undefined;
|
|
@@ -73,6 +73,12 @@ export class FileAdapter {
|
|
|
73
73
|
async stat(filePath) {
|
|
74
74
|
return fs.stat(filePath);
|
|
75
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* Get file stats without following symlinks.
|
|
78
|
+
*/
|
|
79
|
+
async lstat(filePath) {
|
|
80
|
+
return fs.lstat(filePath);
|
|
81
|
+
}
|
|
76
82
|
/**
|
|
77
83
|
* Create directory recursively
|
|
78
84
|
*/
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { resolveExecutionProfile } from '../../runtime/execution-profile.js';
|
|
1
2
|
import { FileAdapter } from './file-adapter.js';
|
|
2
3
|
import { ReadOnlyFileSystem } from './readonly-filesystem.js';
|
|
3
4
|
class FileAdapterFileSystem {
|
|
@@ -23,7 +24,7 @@ class FileAdapterFileSystem {
|
|
|
23
24
|
* Review mode returns a ReadOnlyFileSystem to block writes.
|
|
24
25
|
*/
|
|
25
26
|
export function createFileSystemAdapter(mode, realFs = new FileAdapterFileSystem()) {
|
|
26
|
-
if (mode
|
|
27
|
+
if (resolveExecutionProfile(mode).readOnly) {
|
|
27
28
|
return new ReadOnlyFileSystem(realFs);
|
|
28
29
|
}
|
|
29
30
|
return realFs;
|
|
@@ -8,7 +8,7 @@ import { LIMITS } from '../../config/limits.js';
|
|
|
8
8
|
import { logIgnoredError } from '../../observability/ignored-error.js';
|
|
9
9
|
import { getLogger } from '../../observability/logger.js';
|
|
10
10
|
import { GitError } from '../../types/index.js';
|
|
11
|
-
import { isPathWithinDirectory, normalizePath } from '../../utils/path.js';
|
|
11
|
+
import { isPathWithinDirectory, isSafeRelativePath, normalizePath } from '../../utils/path.js';
|
|
12
12
|
import { runGitCommand } from './git-runner.js';
|
|
13
13
|
import { FileHandleManager } from './lock-manager.js';
|
|
14
14
|
// Singleton map to ensure one lock manager per repository path
|
|
@@ -126,6 +126,32 @@ export class GitAdapter {
|
|
|
126
126
|
this.assertQueryAllowed(args);
|
|
127
127
|
return this.exec(args, options);
|
|
128
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* Generate a git-formatted patch for one repo-relative file that is not in
|
|
131
|
+
* the index, without staging or otherwise mutating repository state.
|
|
132
|
+
*/
|
|
133
|
+
async diffUntrackedFileAgainstNull(relativePath, options = {}) {
|
|
134
|
+
const normalizedPath = normalizePath(relativePath);
|
|
135
|
+
if (!isSafeRelativePath(normalizedPath)) {
|
|
136
|
+
throw new Error(text.git.securityViolation('diff --no-index'));
|
|
137
|
+
}
|
|
138
|
+
return this.execMeta([
|
|
139
|
+
'diff',
|
|
140
|
+
'--no-index',
|
|
141
|
+
'--binary',
|
|
142
|
+
'--no-color',
|
|
143
|
+
'--no-ext-diff',
|
|
144
|
+
'--src-prefix=a/',
|
|
145
|
+
'--dst-prefix=b/',
|
|
146
|
+
'--',
|
|
147
|
+
'/dev/null',
|
|
148
|
+
normalizedPath,
|
|
149
|
+
], {
|
|
150
|
+
cwd: options.cwd,
|
|
151
|
+
limits: options.limits,
|
|
152
|
+
timeoutMs: options.timeoutMs,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
129
155
|
// ==================== Business Layer ====================
|
|
130
156
|
/**
|
|
131
157
|
* Generates a blob hash for the given content without writing to the object database.
|
|
@@ -363,6 +389,54 @@ export class GitAdapter {
|
|
|
363
389
|
await this.lockManager.releaseLock(this.repoPath);
|
|
364
390
|
}
|
|
365
391
|
}
|
|
392
|
+
async checkPatchApplyability(diffText, options = {}) {
|
|
393
|
+
const tempFile = path.join(tmpdir(), `salmon-patch-check-${Date.now()}-${randomBytes(4).toString('hex')}.patch`);
|
|
394
|
+
const tempIndex = path.join(tmpdir(), `salmon-patch-check-index-${Date.now()}-${randomBytes(4).toString('hex')}`);
|
|
395
|
+
await fs.writeFile(tempFile, diffText, 'utf8');
|
|
396
|
+
try {
|
|
397
|
+
const readTree = await this.execMeta(['read-tree', 'HEAD'], {
|
|
398
|
+
env: { ...options.env, GIT_INDEX_FILE: tempIndex },
|
|
399
|
+
limits: { maxStdoutBytes: LIMITS.maxToolOutputBytes, maxStderrChars: 16_384 },
|
|
400
|
+
timeoutMs: LIMITS.gitTimeoutMs,
|
|
401
|
+
});
|
|
402
|
+
if (!readTree.ok) {
|
|
403
|
+
const output = [readTree.stdout.toString('utf8'), readTree.stderr]
|
|
404
|
+
.filter(Boolean)
|
|
405
|
+
.join('\n')
|
|
406
|
+
.trim();
|
|
407
|
+
return {
|
|
408
|
+
ok: false,
|
|
409
|
+
exitCode: readTree.code,
|
|
410
|
+
output,
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
const args = ['apply', '--cached', '--check', '--recount'];
|
|
414
|
+
if (options.ignoreWhitespace)
|
|
415
|
+
args.push('--ignore-whitespace');
|
|
416
|
+
if (options.contextLines)
|
|
417
|
+
args.push(`-C${options.contextLines}`);
|
|
418
|
+
args.push(tempFile);
|
|
419
|
+
const res = await this.execMeta(args, {
|
|
420
|
+
env: { ...options.env, GIT_INDEX_FILE: tempIndex },
|
|
421
|
+
limits: { maxStdoutBytes: LIMITS.maxToolOutputBytes, maxStderrChars: 16_384 },
|
|
422
|
+
timeoutMs: LIMITS.gitTimeoutMs,
|
|
423
|
+
});
|
|
424
|
+
const output = [res.stdout.toString('utf8'), res.stderr].filter(Boolean).join('\n').trim();
|
|
425
|
+
return {
|
|
426
|
+
ok: res.ok,
|
|
427
|
+
exitCode: res.code,
|
|
428
|
+
output,
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
finally {
|
|
432
|
+
await fs
|
|
433
|
+
.unlink(tempFile)
|
|
434
|
+
.catch((error) => logIgnoredError(`[GitAdapter] cleanup ${tempFile}`, error));
|
|
435
|
+
await fs
|
|
436
|
+
.unlink(tempIndex)
|
|
437
|
+
.catch((error) => logIgnoredError(`[GitAdapter] cleanup ${tempIndex}`, error));
|
|
438
|
+
}
|
|
439
|
+
}
|
|
366
440
|
/**
|
|
367
441
|
* Precision rollback protecting staged changes.
|
|
368
442
|
*/
|
|
@@ -407,6 +481,9 @@ export class GitAdapter {
|
|
|
407
481
|
}
|
|
408
482
|
}
|
|
409
483
|
catch (error) {
|
|
484
|
+
if (!this.isShadowWorktreePath()) {
|
|
485
|
+
throw error;
|
|
486
|
+
}
|
|
410
487
|
try {
|
|
411
488
|
await this.resolveConflicts();
|
|
412
489
|
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { createHash } from 'crypto';
|
|
2
|
+
import { EOL } from 'os';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { FileAdapter } from '../adapters/fs/file-adapter.js';
|
|
5
|
+
import { GitAdapter } from '../adapters/git/git-adapter.js';
|
|
6
|
+
import { LIMITS } from '../config/limits.js';
|
|
7
|
+
import { isPathWithinDirectory, isSafeRelativePath, normalizePath } from '../utils/path.js';
|
|
8
|
+
export class BenchmarkPatchArtifactError extends Error {
|
|
9
|
+
constructor(message) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.name = 'BenchmarkPatchArtifactError';
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
const DIFF_ARGS = [
|
|
15
|
+
'diff',
|
|
16
|
+
'--binary',
|
|
17
|
+
'--no-color',
|
|
18
|
+
'--no-ext-diff',
|
|
19
|
+
'--src-prefix=a/',
|
|
20
|
+
'--dst-prefix=b/',
|
|
21
|
+
'HEAD',
|
|
22
|
+
'--',
|
|
23
|
+
'.',
|
|
24
|
+
];
|
|
25
|
+
function normalizeGitPatch(text) {
|
|
26
|
+
const normalized = text.replace(/\r\n/g, '\n').replace(/\s+$/, '');
|
|
27
|
+
return normalized.length > 0 ? `${normalized}\n` : '';
|
|
28
|
+
}
|
|
29
|
+
function splitLines(text) {
|
|
30
|
+
return text
|
|
31
|
+
.split(/\r?\n/)
|
|
32
|
+
.map((line) => line.trim())
|
|
33
|
+
.filter(Boolean);
|
|
34
|
+
}
|
|
35
|
+
async function buildUntrackedFilePatch(params) {
|
|
36
|
+
if (!isSafeRelativePath(params.relativePath) || params.relativePath.startsWith('.salmonloop/')) {
|
|
37
|
+
throw new BenchmarkPatchArtifactError(`Unsafe untracked patch path: ${params.relativePath}`);
|
|
38
|
+
}
|
|
39
|
+
const result = await params.git.diffUntrackedFileAgainstNull(params.relativePath, {
|
|
40
|
+
cwd: params.repoPath,
|
|
41
|
+
limits: { maxStdoutBytes: LIMITS.maxToolOutputBytes },
|
|
42
|
+
});
|
|
43
|
+
if (result.code !== 0 && result.code !== 1) {
|
|
44
|
+
throw new BenchmarkPatchArtifactError(result.stderr || 'Failed to diff untracked file.');
|
|
45
|
+
}
|
|
46
|
+
return normalizeGitPatch(result.stdout.toString('utf8'));
|
|
47
|
+
}
|
|
48
|
+
function parseChangedFilesFromPatch(patch) {
|
|
49
|
+
const files = new Set();
|
|
50
|
+
for (const line of patch.split('\n')) {
|
|
51
|
+
const match = line.match(/^diff --git a\/(.+?) b\/(.+)$/);
|
|
52
|
+
if (!match)
|
|
53
|
+
continue;
|
|
54
|
+
const next = match[2];
|
|
55
|
+
if (next !== '/dev/null')
|
|
56
|
+
files.add(next);
|
|
57
|
+
}
|
|
58
|
+
return Array.from(files).sort();
|
|
59
|
+
}
|
|
60
|
+
export async function buildBenchmarkPatchArtifact(params) {
|
|
61
|
+
const git = new GitAdapter(params.repoPath);
|
|
62
|
+
const fileAdapter = new FileAdapter();
|
|
63
|
+
const excluded = await resolveRepoRelativeExcludes(params.repoPath, params.excludePaths ?? []);
|
|
64
|
+
const pathspecs = buildPatchPathspecs(excluded);
|
|
65
|
+
const trackedPatch = normalizeGitPatch(await git.query([...DIFF_ARGS, ...pathspecs], {
|
|
66
|
+
trim: false,
|
|
67
|
+
limits: { maxStdoutBytes: LIMITS.maxToolOutputBytes },
|
|
68
|
+
}));
|
|
69
|
+
const candidateUntracked = new Set([
|
|
70
|
+
...splitLines(await git.query(['ls-files', '--others', '--exclude-standard'])),
|
|
71
|
+
...(params.changedFilesHint ?? []),
|
|
72
|
+
]);
|
|
73
|
+
const untrackedPatches = [];
|
|
74
|
+
for (const relativePath of Array.from(candidateUntracked).sort()) {
|
|
75
|
+
const normalizedPath = normalizePath(relativePath);
|
|
76
|
+
if (!normalizedPath || normalizedPath.startsWith('.salmonloop/'))
|
|
77
|
+
continue;
|
|
78
|
+
if (excluded.has(normalizedPath))
|
|
79
|
+
continue;
|
|
80
|
+
const status = await git.getStatusForPath(normalizedPath);
|
|
81
|
+
if (!status?.untracked)
|
|
82
|
+
continue;
|
|
83
|
+
if (!(await fileAdapter.exists(path.join(params.repoPath, normalizedPath))))
|
|
84
|
+
continue;
|
|
85
|
+
untrackedPatches.push(await buildUntrackedFilePatch({
|
|
86
|
+
repoPath: params.repoPath,
|
|
87
|
+
git,
|
|
88
|
+
relativePath: normalizedPath,
|
|
89
|
+
}));
|
|
90
|
+
}
|
|
91
|
+
const patch = normalizeGitPatch([trackedPatch, ...untrackedPatches].filter(Boolean).join(EOL));
|
|
92
|
+
const bytes = Buffer.byteLength(patch, 'utf8');
|
|
93
|
+
return {
|
|
94
|
+
patch,
|
|
95
|
+
bytes,
|
|
96
|
+
sha256: createHash('sha256').update(patch, 'utf8').digest('hex'),
|
|
97
|
+
changedFiles: parseChangedFilesFromPatch(patch),
|
|
98
|
+
isEmpty: patch.length === 0,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
function buildPatchPathspecs(excluded) {
|
|
102
|
+
return Array.from(excluded)
|
|
103
|
+
.sort()
|
|
104
|
+
.map((relativePath) => `:(top,literal,exclude)${relativePath}`);
|
|
105
|
+
}
|
|
106
|
+
async function resolveRepoRelativeExcludes(repoPath, paths) {
|
|
107
|
+
const resolvedRepoPath = path.resolve(repoPath);
|
|
108
|
+
const excluded = new Set();
|
|
109
|
+
for (const candidate of paths) {
|
|
110
|
+
if (!candidate)
|
|
111
|
+
continue;
|
|
112
|
+
const absolutePath = path.isAbsolute(candidate)
|
|
113
|
+
? path.resolve(candidate)
|
|
114
|
+
: path.resolve(resolvedRepoPath, candidate);
|
|
115
|
+
const relativePath = normalizePath(path.relative(resolvedRepoPath, absolutePath));
|
|
116
|
+
if (!isSafeRelativePath(relativePath))
|
|
117
|
+
continue;
|
|
118
|
+
if (!isPathWithinDirectory(resolvedRepoPath, absolutePath))
|
|
119
|
+
continue;
|
|
120
|
+
excluded.add(relativePath);
|
|
121
|
+
}
|
|
122
|
+
return excluded;
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=patch-artifact.js.map
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export function buildSweBenchPrediction(input) {
|
|
2
|
+
return {
|
|
3
|
+
instance_id: input.instanceId,
|
|
4
|
+
model_name_or_path: input.modelNameOrPath,
|
|
5
|
+
model_patch: input.modelPatch,
|
|
6
|
+
};
|
|
7
|
+
}
|
|
8
|
+
export function encodeSweBenchPredictionJsonl(input) {
|
|
9
|
+
return `${JSON.stringify(buildSweBenchPrediction(input))}\n`;
|
|
10
|
+
}
|
|
11
|
+
export function parseSweBenchInstance(raw) {
|
|
12
|
+
const parsed = JSON.parse(raw);
|
|
13
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
14
|
+
throw new Error('SWE-bench instance must be a JSON object.');
|
|
15
|
+
}
|
|
16
|
+
const instance = parsed;
|
|
17
|
+
if (typeof instance.instance_id !== 'string' || !instance.instance_id.trim()) {
|
|
18
|
+
throw new Error('SWE-bench instance requires a non-empty instance_id.');
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
...instance,
|
|
22
|
+
instance_id: instance.instance_id,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=swe-bench.js.map
|