@lazyingart/agintiflow 0.20.274 → 0.20.276
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lazyingart/agintiflow",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.276",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "AgInTiFlow is a project-aware agent workspace for hybrid wet-dry R&D, hardware-aware intelligence, software automation, and industrial workflows.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import crypto from "node:crypto";
|
|
3
|
+
import assertStrict from "node:assert/strict";
|
|
3
4
|
import { spawnSync } from "node:child_process";
|
|
4
5
|
import fs from "node:fs/promises";
|
|
5
6
|
import net from "node:net";
|
|
@@ -30,6 +31,7 @@ import {
|
|
|
30
31
|
buildFailedTestRecoveryPacket,
|
|
31
32
|
buildKnownConstrainedPhasePlan,
|
|
32
33
|
buildTaskOwnedCommitCommand,
|
|
34
|
+
changedGitStatusPaths,
|
|
33
35
|
bindPatchContextRepairArguments,
|
|
34
36
|
canonicalizeVerifiedArtifactCompletion,
|
|
35
37
|
completedDeepResearchReuse,
|
|
@@ -52,6 +54,7 @@ import {
|
|
|
52
54
|
mergeDurableGitEvidence,
|
|
53
55
|
nextStepRuntimeConfig,
|
|
54
56
|
patchContextScopeMismatchAttemptCount,
|
|
57
|
+
parseGitPorcelainStatus,
|
|
55
58
|
pythonMainGuardOrderDefects,
|
|
56
59
|
projectAcceptanceFromMarkdown,
|
|
57
60
|
projectTestVerificationFinishBlock,
|
|
@@ -62,6 +65,7 @@ import {
|
|
|
62
65
|
recordCanonicalGeneratedOutputProgress,
|
|
63
66
|
recordAlreadyCommittedRepositoryRepair,
|
|
64
67
|
recordProjectVerificationOutcome,
|
|
68
|
+
repositoryStateInspectionCommand,
|
|
65
69
|
recordExactOutputProgress,
|
|
66
70
|
recordStaticDiscoveryProgress,
|
|
67
71
|
resetGoalScopedRuntimeState,
|
|
@@ -6483,12 +6487,113 @@ try {
|
|
|
6483
6487
|
}),
|
|
6484
6488
|
"a direct clean-worktree assertion was not classified when the traceback omitted the Git helper call"
|
|
6485
6489
|
);
|
|
6490
|
+
assert(
|
|
6491
|
+
failedTestRequiresCleanRepositoryState({
|
|
6492
|
+
failureSummary: "acceptance failed: repository is not clean",
|
|
6493
|
+
}),
|
|
6494
|
+
"a concise authoritative acceptance failure did not activate repository-state repair"
|
|
6495
|
+
);
|
|
6486
6496
|
assert(
|
|
6487
6497
|
!failedTestRequiresCleanRepositoryState({
|
|
6488
6498
|
failureSummary: "The generated prose says the repository worktree is not clean.",
|
|
6489
6499
|
}),
|
|
6490
6500
|
"plain task prose was mistaken for a repository-state gate without Git-status evidence"
|
|
6491
6501
|
);
|
|
6502
|
+
assertStrict.deepEqual(
|
|
6503
|
+
parseGitPorcelainStatus(
|
|
6504
|
+
" M build_deck.py\n D dist/deck.pdf\n?? output/deck.pptx\n?? output/slide 1.png\n"
|
|
6505
|
+
),
|
|
6506
|
+
[
|
|
6507
|
+
{ status: " M", path: "build_deck.py" },
|
|
6508
|
+
{ status: " D", path: "dist/deck.pdf" },
|
|
6509
|
+
{ status: "??", path: "output/deck.pptx" },
|
|
6510
|
+
{ status: "??", path: "output/slide 1.png" },
|
|
6511
|
+
],
|
|
6512
|
+
"bounded porcelain parsing lost a deletion, untracked output, or path containing spaces"
|
|
6513
|
+
);
|
|
6514
|
+
assertStrict.deepEqual(
|
|
6515
|
+
changedGitStatusPaths(
|
|
6516
|
+
{
|
|
6517
|
+
entries: [
|
|
6518
|
+
{ status: " M", path: "unrelated.md", fingerprint: "same" },
|
|
6519
|
+
{ status: " M", path: "build_deck.py", fingerprint: "before" },
|
|
6520
|
+
],
|
|
6521
|
+
},
|
|
6522
|
+
{
|
|
6523
|
+
entries: [
|
|
6524
|
+
{ status: " M", path: "unrelated.md", fingerprint: "same" },
|
|
6525
|
+
{ status: " M", path: "build_deck.py", fingerprint: "after" },
|
|
6526
|
+
{ status: " D", path: "dist/deck.pdf", fingerprint: "missing" },
|
|
6527
|
+
{ status: "??", path: "output/deck.pptx", fingerprint: "file:1" },
|
|
6528
|
+
],
|
|
6529
|
+
}
|
|
6530
|
+
),
|
|
6531
|
+
["build_deck.py", "dist/deck.pdf", "output/deck.pptx"],
|
|
6532
|
+
"command-bound Git capture included untouched pre-existing dirt or lost generated relocation paths"
|
|
6533
|
+
);
|
|
6534
|
+
const producerMutationState = {
|
|
6535
|
+
goal: "Rebuild the generated presentation.",
|
|
6536
|
+
meta: {
|
|
6537
|
+
goalContract: { revision: 3, taskGoal: "Rebuild the generated presentation." },
|
|
6538
|
+
activeExecutionContract: { revision: 3 },
|
|
6539
|
+
},
|
|
6540
|
+
};
|
|
6541
|
+
recordProjectVerificationOutcome(
|
|
6542
|
+
producerMutationState,
|
|
6543
|
+
{
|
|
6544
|
+
toolName: "run_command",
|
|
6545
|
+
ok: true,
|
|
6546
|
+
exitCode: 0,
|
|
6547
|
+
args: { command: "python3 build_deck.py" },
|
|
6548
|
+
commandPolicy: {
|
|
6549
|
+
category: "toolchain",
|
|
6550
|
+
writesWorkspace: true,
|
|
6551
|
+
mayMutateProject: false,
|
|
6552
|
+
},
|
|
6553
|
+
projectMutationPaths: [
|
|
6554
|
+
"build_deck.py",
|
|
6555
|
+
"dist/deck.pdf",
|
|
6556
|
+
"output/deck.pptx",
|
|
6557
|
+
],
|
|
6558
|
+
stdout: "wrote output/deck.pptx",
|
|
6559
|
+
stderr: "",
|
|
6560
|
+
},
|
|
6561
|
+
{ commandCwd: workspace, taskProfile: "slides" }
|
|
6562
|
+
);
|
|
6563
|
+
assertStrict.deepEqual(
|
|
6564
|
+
producerMutationState.meta.projectVerification.mutationHistory.at(-1).paths,
|
|
6565
|
+
["build_deck.py", "dist/deck.pdf", "output/deck.pptx"],
|
|
6566
|
+
"a producer command discarded the exact Git paths captured across its execution boundary"
|
|
6567
|
+
);
|
|
6568
|
+
const inspectedRepositoryState = structuredClone(repositoryCleanGateFailure);
|
|
6569
|
+
inspectedRepositoryState.meta.goalContract = { revision: 4 };
|
|
6570
|
+
const repositoryInspectionResult = {
|
|
6571
|
+
toolName: "run_command",
|
|
6572
|
+
ok: true,
|
|
6573
|
+
exitCode: 0,
|
|
6574
|
+
args: { command: repositoryStateInspectionCommand() },
|
|
6575
|
+
stdout: " D dist/deck.pdf\n?? output/deck.pptx\n",
|
|
6576
|
+
stderr: "",
|
|
6577
|
+
};
|
|
6578
|
+
recordProjectVerificationOutcome(
|
|
6579
|
+
inspectedRepositoryState,
|
|
6580
|
+
repositoryInspectionResult,
|
|
6581
|
+
{
|
|
6582
|
+
commandCwd: workspace,
|
|
6583
|
+
taskProfile: "slides",
|
|
6584
|
+
testFailureRepositoryStateRepair: true,
|
|
6585
|
+
testFailureSignature: "repository-state-gate",
|
|
6586
|
+
}
|
|
6587
|
+
);
|
|
6588
|
+
const inspectedRepositoryRuntime = nextStepRuntimeConfig(
|
|
6589
|
+
{ provider: "deepseek", taskProfile: "slides", commandCwd: workspace },
|
|
6590
|
+
inspectedRepositoryState
|
|
6591
|
+
);
|
|
6592
|
+
assertStrict.deepEqual(
|
|
6593
|
+
inspectedRepositoryRuntime.repositoryStateRepairObservedPaths,
|
|
6594
|
+
["dist/deck.pdf", "output/deck.pptx"],
|
|
6595
|
+
"a bounded dirty-worktree inspection did not persist exact path candidates for the next turn"
|
|
6596
|
+
);
|
|
6492
6597
|
assert(
|
|
6493
6598
|
unchangedFailedTestRerunBlock(
|
|
6494
6599
|
repositoryCleanGateFailure,
|
|
@@ -2003,10 +2003,120 @@ sameNames(
|
|
|
2003
2003
|
"repository-state repair exposed document mutation tools"
|
|
2004
2004
|
);
|
|
2005
2005
|
assert(
|
|
2006
|
-
/
|
|
2006
|
+
/exact bounded Git status inspection once/i.test(
|
|
2007
2007
|
repositoryStateRepairTools.find((item) => item.function.name === "run_command")?.function.description || ""
|
|
2008
2008
|
),
|
|
2009
|
-
"repository-state repair did not
|
|
2009
|
+
"repository-state repair did not constrain the first recovery turn to one status inspection"
|
|
2010
|
+
);
|
|
2011
|
+
assertStrict.deepEqual(
|
|
2012
|
+
repositoryStateRepairTools[0].function.parameters.properties.command.enum,
|
|
2013
|
+
["git status --porcelain=v1 --untracked-files=all"],
|
|
2014
|
+
"repository-state repair exposed an open-ended shell instead of the exact status command"
|
|
2015
|
+
);
|
|
2016
|
+
const conciseRepositoryStateRepairRuntime = nextStepRuntimeConfig(
|
|
2017
|
+
{ provider: "deepseek", taskProfile: "slides" },
|
|
2018
|
+
{
|
|
2019
|
+
meta: {
|
|
2020
|
+
projectVerification: {
|
|
2021
|
+
mutationRevision: 18,
|
|
2022
|
+
testRuns: [{
|
|
2023
|
+
command: "python acceptance.py --root .",
|
|
2024
|
+
mutationRevision: 18,
|
|
2025
|
+
passed: false,
|
|
2026
|
+
failureEvidenceVersion: 2,
|
|
2027
|
+
failureSignature: "concise-repository-state-gate",
|
|
2028
|
+
failureSummary: "acceptance failed: repository is not clean",
|
|
2029
|
+
}],
|
|
2030
|
+
},
|
|
2031
|
+
failedTestRecoveryPacket: {
|
|
2032
|
+
packetVersion: 15,
|
|
2033
|
+
mutationRevision: 18,
|
|
2034
|
+
failureSignature: "concise-repository-state-gate",
|
|
2035
|
+
content: "Retained canonical source evidence from the prior content failure.",
|
|
2036
|
+
},
|
|
2037
|
+
toolLoop: {
|
|
2038
|
+
stagnationEpoch: 4,
|
|
2039
|
+
recent: [],
|
|
2040
|
+
},
|
|
2041
|
+
},
|
|
2042
|
+
messages: [],
|
|
2043
|
+
}
|
|
2044
|
+
);
|
|
2045
|
+
assertStrict.equal(
|
|
2046
|
+
conciseRepositoryStateRepairRuntime.testFailureRepositoryStateRepair,
|
|
2047
|
+
true,
|
|
2048
|
+
"a concise acceptance failure remained in canonical-source repair mode"
|
|
2049
|
+
);
|
|
2050
|
+
assertStrict.equal(
|
|
2051
|
+
conciseRepositoryStateRepairRuntime.testFailureRepairMutationRequired,
|
|
2052
|
+
false,
|
|
2053
|
+
"stale retained source evidence overrode a clean-repository repair gate"
|
|
2054
|
+
);
|
|
2055
|
+
sameNames(
|
|
2056
|
+
selectProgressiveTools(allTools, {
|
|
2057
|
+
config: conciseRepositoryStateRepairRuntime,
|
|
2058
|
+
goal: "Commit the accepted presentation and leave the repository clean.",
|
|
2059
|
+
profile: "slides",
|
|
2060
|
+
}),
|
|
2061
|
+
["run_command", "finish"],
|
|
2062
|
+
"a concise clean-repository acceptance failure exposed content mutation tools"
|
|
2063
|
+
);
|
|
2064
|
+
const observedRepositoryState = {
|
|
2065
|
+
meta: {
|
|
2066
|
+
goalContract: { revision: 7 },
|
|
2067
|
+
projectVerification: {
|
|
2068
|
+
mutationRevision: 18,
|
|
2069
|
+
repositoryStateInspection: {
|
|
2070
|
+
version: 1,
|
|
2071
|
+
mutationRevision: 18,
|
|
2072
|
+
failureSignature: "observed-repository-state-gate",
|
|
2073
|
+
command: "git status --porcelain=v1 --untracked-files=all",
|
|
2074
|
+
entries: [
|
|
2075
|
+
{ status: " D", path: "dist/deck.pdf" },
|
|
2076
|
+
{ status: "??", path: "output/deck.pptx" },
|
|
2077
|
+
{ status: " M", path: "unrelated-notes.md" },
|
|
2078
|
+
],
|
|
2079
|
+
},
|
|
2080
|
+
testRuns: [{
|
|
2081
|
+
command: "python acceptance.py --phase final",
|
|
2082
|
+
mutationRevision: 18,
|
|
2083
|
+
passed: false,
|
|
2084
|
+
failureEvidenceVersion: 2,
|
|
2085
|
+
failureSignature: "observed-repository-state-gate",
|
|
2086
|
+
failureSummary: "acceptance failed: repository is not clean",
|
|
2087
|
+
}],
|
|
2088
|
+
},
|
|
2089
|
+
},
|
|
2090
|
+
messages: [],
|
|
2091
|
+
};
|
|
2092
|
+
const observedRepositoryRuntime = nextStepRuntimeConfig(
|
|
2093
|
+
{ provider: "deepseek", taskProfile: "slides" },
|
|
2094
|
+
observedRepositoryState
|
|
2095
|
+
);
|
|
2096
|
+
assertStrict.deepEqual(
|
|
2097
|
+
observedRepositoryRuntime.repositoryStateRepairObservedPaths,
|
|
2098
|
+
["dist/deck.pdf", "output/deck.pptx", "unrelated-notes.md"],
|
|
2099
|
+
"the clean-state recovery phase lost exact paths from its bounded status observation"
|
|
2100
|
+
);
|
|
2101
|
+
const observedRepositoryTools = selectProgressiveTools(allTools, {
|
|
2102
|
+
config: observedRepositoryRuntime,
|
|
2103
|
+
goal: "Commit only the accepted presentation relocation.",
|
|
2104
|
+
profile: "slides",
|
|
2105
|
+
});
|
|
2106
|
+
sameNames(
|
|
2107
|
+
observedRepositoryTools,
|
|
2108
|
+
["commit_project_changes", "finish"],
|
|
2109
|
+
"an observed clean-state recovery did not replace the shell with path-enumerated commit selection"
|
|
2110
|
+
);
|
|
2111
|
+
assertStrict.deepEqual(
|
|
2112
|
+
observedRepositoryTools[0].function.parameters.required,
|
|
2113
|
+
["paths", "message"],
|
|
2114
|
+
"the observed-path commit did not require explicit task-owned path selection"
|
|
2115
|
+
);
|
|
2116
|
+
assertStrict.deepEqual(
|
|
2117
|
+
observedRepositoryTools[0].function.parameters.properties.paths.items.enum,
|
|
2118
|
+
["dist/deck.pdf", "output/deck.pptx", "unrelated-notes.md"],
|
|
2119
|
+
"the observed-path commit broadened its candidate scope beyond the exact status result"
|
|
2010
2120
|
);
|
|
2011
2121
|
const taskOwnedRepositoryState = {
|
|
2012
2122
|
meta: {
|
package/src/agent-runner.js
CHANGED
|
@@ -2237,6 +2237,11 @@ export function buildKnownConstrainedPhasePlan(
|
|
|
2237
2237
|
Array.isArray(runtimeConfig.repositoryStateRepairCommitPaths) &&
|
|
2238
2238
|
runtimeConfig.repositoryStateRepairCommitPaths.length > 0
|
|
2239
2239
|
);
|
|
2240
|
+
const repositoryObservedCommitReady = Boolean(
|
|
2241
|
+
repositoryStateRepair &&
|
|
2242
|
+
Array.isArray(runtimeConfig.repositoryStateRepairObservedPaths) &&
|
|
2243
|
+
runtimeConfig.repositoryStateRepairObservedPaths.length > 0
|
|
2244
|
+
);
|
|
2240
2245
|
const plan = repositoryStateRepair
|
|
2241
2246
|
? repositoryCommitReady
|
|
2242
2247
|
? [
|
|
@@ -2244,9 +2249,16 @@ export function buildKnownConstrainedPhasePlan(
|
|
|
2244
2249
|
`2. Run the exact retained verification command after that commit: ${command}`,
|
|
2245
2250
|
"3. Finish only after that exact command passes at the current mutation revision.",
|
|
2246
2251
|
].join("\n")
|
|
2252
|
+
: repositoryObservedCommitReady
|
|
2253
|
+
? [
|
|
2254
|
+
"1. Use the offered commit_project_changes tool once and select the complete task-owned subset from the exact observed dirty paths.",
|
|
2255
|
+
"2. Include intended generated-output relocations and deletions, but exclude unrelated pre-existing work.",
|
|
2256
|
+
`3. Run the exact retained verification command after that commit: ${command}`,
|
|
2257
|
+
"4. Finish only after that exact command passes at the current mutation revision.",
|
|
2258
|
+
].join("\n")
|
|
2247
2259
|
: [
|
|
2248
|
-
"1.
|
|
2249
|
-
"2.
|
|
2260
|
+
"1. Run the one exact bounded Git status inspection offered by the runtime.",
|
|
2261
|
+
"2. On the next turn, select and commit only task-owned paths from the runtime-enumerated candidates.",
|
|
2250
2262
|
`3. Run the exact retained verification command after the repository state is clean: ${command}`,
|
|
2251
2263
|
"4. Finish only after that exact command passes at the current mutation revision.",
|
|
2252
2264
|
].join("\n")
|
|
@@ -2294,7 +2306,9 @@ export function buildKnownConstrainedPhasePlan(
|
|
|
2294
2306
|
const recoveryInstruction = repositoryStateRepair
|
|
2295
2307
|
? repositoryCommitReady
|
|
2296
2308
|
? "The current failure is only a repository-state acceptance gate. The runtime already knows the task-owned changed paths, so call commit_project_changes with a concise factual subject. Do not inspect again or invent another source edit."
|
|
2297
|
-
:
|
|
2309
|
+
: repositoryObservedCommitReady
|
|
2310
|
+
? "The bounded status inspection is complete. Select the complete task-owned subset from the exact offered paths and call commit_project_changes once. Do not include unrelated work, inspect again, or invent another source edit."
|
|
2311
|
+
: "The current failure is a repository-state acceptance gate, not a content defect. Run only the exact offered status inspection once. The runtime will convert its result into a bounded path-selection commit phase; do not start a status/diff loop or invent another source edit."
|
|
2298
2312
|
: freshSourceMutation
|
|
2299
2313
|
? runtimeConfig.completionFreshMutationNeedsSourceRead === true
|
|
2300
2314
|
? "Completion was rejected because a fresh canonical source correction is still missing. Read one exact offered project file now; command, test, Git, and finish actions remain intentionally unavailable until the source is grounded and materially patched."
|
|
@@ -6055,6 +6069,15 @@ export function recordProjectVerificationOutcome(state = {}, toolResult = {}, co
|
|
|
6055
6069
|
generatedArtifactProducer
|
|
6056
6070
|
)
|
|
6057
6071
|
);
|
|
6072
|
+
const commandMutationPaths = Array.isArray(toolResult.projectMutationPaths)
|
|
6073
|
+
? [
|
|
6074
|
+
...new Set(
|
|
6075
|
+
toolResult.projectMutationPaths
|
|
6076
|
+
.map(safeTaskOwnedCommitPath)
|
|
6077
|
+
.filter(Boolean)
|
|
6078
|
+
),
|
|
6079
|
+
].slice(0, 64)
|
|
6080
|
+
: [];
|
|
6058
6081
|
let requiredBatch = currentRequiredCommandBatch(verification, requiredCommands);
|
|
6059
6082
|
const activeExecutionContract = state.meta?.activeExecutionContract;
|
|
6060
6083
|
const activeTurnCommands =
|
|
@@ -6074,6 +6097,7 @@ export function recordProjectVerificationOutcome(state = {}, toolResult = {}, co
|
|
|
6074
6097
|
let batchRequiredCommands = requiredBatch?.requiredCommands || requiredCommands;
|
|
6075
6098
|
if (projectContentMutation) {
|
|
6076
6099
|
delete state.meta.verifiedCompletionCandidate;
|
|
6100
|
+
delete verification.repositoryStateInspection;
|
|
6077
6101
|
if (
|
|
6078
6102
|
requiredCommand &&
|
|
6079
6103
|
batchRequiredCommands.includes(requiredCommand) &&
|
|
@@ -6108,7 +6132,7 @@ export function recordProjectVerificationOutcome(state = {}, toolResult = {}, co
|
|
|
6108
6132
|
revision: verification.mutationRevision,
|
|
6109
6133
|
at: now,
|
|
6110
6134
|
toolName,
|
|
6111
|
-
paths:
|
|
6135
|
+
paths: commandMutationPaths,
|
|
6112
6136
|
commandCategory: String(commandPolicy.category || "general-shell"),
|
|
6113
6137
|
}, config);
|
|
6114
6138
|
if (
|
|
@@ -6125,8 +6149,61 @@ export function recordProjectVerificationOutcome(state = {}, toolResult = {}, co
|
|
|
6125
6149
|
generatedArtifactProducer,
|
|
6126
6150
|
]),
|
|
6127
6151
|
].slice(0, 12);
|
|
6152
|
+
if (commandMutationPaths.length) {
|
|
6153
|
+
activeExecutionContract.materialMutationPaths = [
|
|
6154
|
+
...new Set([
|
|
6155
|
+
...(Array.isArray(activeExecutionContract.materialMutationPaths)
|
|
6156
|
+
? activeExecutionContract.materialMutationPaths
|
|
6157
|
+
: []),
|
|
6158
|
+
...commandMutationPaths,
|
|
6159
|
+
]),
|
|
6160
|
+
].slice(0, 24);
|
|
6161
|
+
}
|
|
6128
6162
|
}
|
|
6129
6163
|
}
|
|
6164
|
+
if (commandIncludesGitCommit(command)) {
|
|
6165
|
+
delete verification.repositoryStateInspection;
|
|
6166
|
+
}
|
|
6167
|
+
if (
|
|
6168
|
+
commandSucceeded &&
|
|
6169
|
+
config.testFailureRepositoryStateRepair === true &&
|
|
6170
|
+
projectCommandsEquivalent(
|
|
6171
|
+
command,
|
|
6172
|
+
REPOSITORY_STATE_INSPECTION_COMMAND,
|
|
6173
|
+
config
|
|
6174
|
+
)
|
|
6175
|
+
) {
|
|
6176
|
+
const currentFailure = [...verification.testRuns]
|
|
6177
|
+
.reverse()
|
|
6178
|
+
.find(
|
|
6179
|
+
(candidate) =>
|
|
6180
|
+
candidate?.passed !== true &&
|
|
6181
|
+
Number(candidate?.mutationRevision || 0) ===
|
|
6182
|
+
verification.mutationRevision
|
|
6183
|
+
);
|
|
6184
|
+
const entries = (
|
|
6185
|
+
Array.isArray(toolResult.repositoryStateStatusEntries)
|
|
6186
|
+
? toolResult.repositoryStateStatusEntries
|
|
6187
|
+
.map((entry) => ({
|
|
6188
|
+
status: String(entry?.status || ""),
|
|
6189
|
+
path: safeTaskOwnedCommitPath(entry?.path),
|
|
6190
|
+
}))
|
|
6191
|
+
.filter((entry) => entry.path)
|
|
6192
|
+
: parseGitPorcelainStatus(toolResult.stdout)
|
|
6193
|
+
).slice(0, 64);
|
|
6194
|
+
verification.repositoryStateInspection = {
|
|
6195
|
+
version: REPOSITORY_STATE_INSPECTION_VERSION,
|
|
6196
|
+
mutationRevision: verification.mutationRevision,
|
|
6197
|
+
failureSignature: String(
|
|
6198
|
+
config.testFailureSignature || currentFailure?.failureSignature || ""
|
|
6199
|
+
),
|
|
6200
|
+
command: REPOSITORY_STATE_INSPECTION_COMMAND,
|
|
6201
|
+
entries,
|
|
6202
|
+
at: now,
|
|
6203
|
+
};
|
|
6204
|
+
toolResult.repositoryStateInspection = verification.repositoryStateInspection;
|
|
6205
|
+
toolResult.repositoryStateObservedPaths = entries.map((entry) => entry.path);
|
|
6206
|
+
}
|
|
6130
6207
|
const run = {
|
|
6131
6208
|
command,
|
|
6132
6209
|
at: now,
|
|
@@ -6306,6 +6383,9 @@ export function failedTestRequiresCleanRepositoryState(testRun = {}) {
|
|
|
6306
6383
|
const directCleanStateAssertion =
|
|
6307
6384
|
/(?:assertionerror|assert(?:ion)?(?:\s+failed)?)[^.!;]{0,200}(?:(?:project|repository)\s+)?(?:work\s*tree|worktree|repository)[^.!;]{0,80}(?:is\s+not\s+clean|must\s+be\s+clean|expected\s+(?:to\s+be\s+)?clean)\b/i.test(summary);
|
|
6308
6385
|
if (directCleanStateAssertion) return true;
|
|
6386
|
+
const authoritativeCleanStateFailure =
|
|
6387
|
+
/(?:^|\b)(?:acceptance|validation|verification|contract|test|check)\s+failed\s*:[^.!;]{0,200}(?:(?:project|repository)\s+)?(?:work\s*tree|worktree|repository)[^.!;]{0,80}(?:is\s+not\s+clean|must\s+be\s+clean|expected\s+(?:to\s+be\s+)?clean)\b/i.test(summary);
|
|
6388
|
+
if (authoritativeCleanStateFailure) return true;
|
|
6309
6389
|
const invokesShortStatus =
|
|
6310
6390
|
/git[a-z_]*\s*\([^)]*["']status["'][^)]*(?:["']--short["']|["']--porcelain(?:=[^"']+)?["'])[^)]*\)/i.test(summary) ||
|
|
6311
6391
|
/\bgit\s+status\s+(?:--short|--porcelain(?:=\S+)?)\b/i.test(summary);
|
|
@@ -6397,6 +6477,158 @@ function safeTaskOwnedCommitPath(value = "") {
|
|
|
6397
6477
|
return candidate;
|
|
6398
6478
|
}
|
|
6399
6479
|
|
|
6480
|
+
const REPOSITORY_STATE_INSPECTION_VERSION = 1;
|
|
6481
|
+
const REPOSITORY_STATE_INSPECTION_COMMAND =
|
|
6482
|
+
"git status --porcelain=v1 --untracked-files=all";
|
|
6483
|
+
|
|
6484
|
+
export function repositoryStateInspectionCommand() {
|
|
6485
|
+
return REPOSITORY_STATE_INSPECTION_COMMAND;
|
|
6486
|
+
}
|
|
6487
|
+
|
|
6488
|
+
function decodeGitPorcelainPath(value = "") {
|
|
6489
|
+
const raw = String(value || "").trimEnd();
|
|
6490
|
+
if (!raw.startsWith('"')) return raw;
|
|
6491
|
+
// Git's quoted-path grammar overlaps JSON for ordinary escaped paths. Octal
|
|
6492
|
+
// escapes are deliberately rejected instead of guessing a path that may be
|
|
6493
|
+
// staged later.
|
|
6494
|
+
try {
|
|
6495
|
+
return JSON.parse(raw);
|
|
6496
|
+
} catch {
|
|
6497
|
+
return "";
|
|
6498
|
+
}
|
|
6499
|
+
}
|
|
6500
|
+
|
|
6501
|
+
export function parseGitPorcelainStatus(output = "") {
|
|
6502
|
+
const entries = [];
|
|
6503
|
+
const seen = new Set();
|
|
6504
|
+
for (const line of String(output || "").replace(/\r/g, "").split("\n")) {
|
|
6505
|
+
if (line.length < 4 || line[2] !== " ") continue;
|
|
6506
|
+
const status = line.slice(0, 2);
|
|
6507
|
+
if (!/^[ MADRCUT?!]{2}$/u.test(status)) continue;
|
|
6508
|
+
const candidate = safeTaskOwnedCommitPath(
|
|
6509
|
+
decodeGitPorcelainPath(line.slice(3))
|
|
6510
|
+
);
|
|
6511
|
+
if (!candidate || seen.has(candidate)) continue;
|
|
6512
|
+
seen.add(candidate);
|
|
6513
|
+
entries.push({ status, path: candidate });
|
|
6514
|
+
if (entries.length >= 256) break;
|
|
6515
|
+
}
|
|
6516
|
+
return entries;
|
|
6517
|
+
}
|
|
6518
|
+
|
|
6519
|
+
async function gitStatusPathFingerprint(commandCwd = "", relativePath = "") {
|
|
6520
|
+
const root = path.resolve(commandCwd || process.cwd());
|
|
6521
|
+
const candidate = safeTaskOwnedCommitPath(relativePath);
|
|
6522
|
+
if (!candidate) return "";
|
|
6523
|
+
const absolutePath = path.resolve(root, candidate);
|
|
6524
|
+
const relative = path.relative(root, absolutePath);
|
|
6525
|
+
if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) return "";
|
|
6526
|
+
try {
|
|
6527
|
+
const stat = await fs.lstat(absolutePath);
|
|
6528
|
+
return [
|
|
6529
|
+
stat.isFile() ? "file" : stat.isDirectory() ? "directory" : stat.isSymbolicLink() ? "symlink" : "other",
|
|
6530
|
+
Number(stat.mode || 0),
|
|
6531
|
+
Number(stat.size || 0),
|
|
6532
|
+
Number(stat.mtimeMs || 0),
|
|
6533
|
+
Number(stat.ctimeMs || 0),
|
|
6534
|
+
Number(stat.ino || 0),
|
|
6535
|
+
].join(":");
|
|
6536
|
+
} catch (error) {
|
|
6537
|
+
return error?.code === "ENOENT" ? "missing" : "unavailable";
|
|
6538
|
+
}
|
|
6539
|
+
}
|
|
6540
|
+
|
|
6541
|
+
async function captureGitWorktreeSnapshot(config = {}) {
|
|
6542
|
+
const commandCwd = path.resolve(config.commandCwd || process.cwd());
|
|
6543
|
+
const stdout = await new Promise((resolve) => {
|
|
6544
|
+
let text = "";
|
|
6545
|
+
let settled = false;
|
|
6546
|
+
let timer;
|
|
6547
|
+
const finish = (value = null) => {
|
|
6548
|
+
if (settled) return;
|
|
6549
|
+
settled = true;
|
|
6550
|
+
if (timer) clearTimeout(timer);
|
|
6551
|
+
resolve(value);
|
|
6552
|
+
};
|
|
6553
|
+
const child = spawn(
|
|
6554
|
+
"git",
|
|
6555
|
+
["status", "--porcelain=v1", "--untracked-files=all"],
|
|
6556
|
+
{
|
|
6557
|
+
cwd: commandCwd,
|
|
6558
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
6559
|
+
windowsHide: true,
|
|
6560
|
+
}
|
|
6561
|
+
);
|
|
6562
|
+
timer = setTimeout(() => {
|
|
6563
|
+
child.kill("SIGKILL");
|
|
6564
|
+
finish(null);
|
|
6565
|
+
}, 5000);
|
|
6566
|
+
child.stdout?.on("data", (chunk) => {
|
|
6567
|
+
text += String(chunk || "");
|
|
6568
|
+
if (text.length > 1024 * 1024) {
|
|
6569
|
+
child.kill("SIGKILL");
|
|
6570
|
+
finish(null);
|
|
6571
|
+
}
|
|
6572
|
+
});
|
|
6573
|
+
child.on("error", () => finish(null));
|
|
6574
|
+
child.on("close", (code) => finish(code === 0 ? text : null));
|
|
6575
|
+
});
|
|
6576
|
+
if (typeof stdout !== "string") return null;
|
|
6577
|
+
const parsed = parseGitPorcelainStatus(stdout);
|
|
6578
|
+
if (parsed.length >= 256) return null;
|
|
6579
|
+
const entries = await Promise.all(
|
|
6580
|
+
parsed.map(async (entry) => ({
|
|
6581
|
+
...entry,
|
|
6582
|
+
fingerprint: await gitStatusPathFingerprint(commandCwd, entry.path),
|
|
6583
|
+
}))
|
|
6584
|
+
);
|
|
6585
|
+
return { version: 1, entries };
|
|
6586
|
+
}
|
|
6587
|
+
|
|
6588
|
+
export function changedGitStatusPaths(before = null, after = null) {
|
|
6589
|
+
if (!before || !after || !Array.isArray(before.entries) || !Array.isArray(after.entries)) {
|
|
6590
|
+
return [];
|
|
6591
|
+
}
|
|
6592
|
+
const prior = new Map(
|
|
6593
|
+
before.entries
|
|
6594
|
+
.filter((entry) => safeTaskOwnedCommitPath(entry?.path))
|
|
6595
|
+
.map((entry) => [String(entry.path), entry])
|
|
6596
|
+
);
|
|
6597
|
+
return [
|
|
6598
|
+
...new Set(
|
|
6599
|
+
after.entries
|
|
6600
|
+
.filter((entry) => {
|
|
6601
|
+
const candidate = safeTaskOwnedCommitPath(entry?.path);
|
|
6602
|
+
if (!candidate) return false;
|
|
6603
|
+
const previous = prior.get(candidate);
|
|
6604
|
+
return Boolean(
|
|
6605
|
+
!previous ||
|
|
6606
|
+
String(previous.status || "") !== String(entry.status || "") ||
|
|
6607
|
+
String(previous.fingerprint || "") !== String(entry.fingerprint || "")
|
|
6608
|
+
);
|
|
6609
|
+
})
|
|
6610
|
+
.map((entry) => safeTaskOwnedCommitPath(entry.path))
|
|
6611
|
+
.filter(Boolean)
|
|
6612
|
+
),
|
|
6613
|
+
].slice(0, 64);
|
|
6614
|
+
}
|
|
6615
|
+
|
|
6616
|
+
function currentRepositoryStateInspection(verification = {}, testRun = {}) {
|
|
6617
|
+
const inspection = verification.repositoryStateInspection;
|
|
6618
|
+
if (
|
|
6619
|
+
!inspection ||
|
|
6620
|
+
Number(inspection.version || 0) !== REPOSITORY_STATE_INSPECTION_VERSION ||
|
|
6621
|
+
Number(inspection.mutationRevision || 0) !==
|
|
6622
|
+
Math.max(0, Number(verification.mutationRevision || 0)) ||
|
|
6623
|
+
String(inspection.failureSignature || "") !==
|
|
6624
|
+
String(testRun?.failureSignature || "") ||
|
|
6625
|
+
!Array.isArray(inspection.entries)
|
|
6626
|
+
) {
|
|
6627
|
+
return null;
|
|
6628
|
+
}
|
|
6629
|
+
return inspection;
|
|
6630
|
+
}
|
|
6631
|
+
|
|
6400
6632
|
function taskOwnedMutationPathsSinceLatestCommit(verification = {}) {
|
|
6401
6633
|
const latestCommittedRevision = [...(verification.commandRuns || [])]
|
|
6402
6634
|
.reverse()
|
|
@@ -7929,6 +8161,8 @@ function runCommandResultHasDurableProgress(toolResult = {}) {
|
|
|
7929
8161
|
return Boolean(
|
|
7930
8162
|
policyAllowsMutation ||
|
|
7931
8163
|
policy.substantiveTest === true ||
|
|
8164
|
+
(Array.isArray(toolResult.projectMutationPaths) &&
|
|
8165
|
+
toolResult.projectMutationPaths.length > 0) ||
|
|
7932
8166
|
(Array.isArray(toolResult.verifiedGeneratedOutputPaths) &&
|
|
7933
8167
|
toolResult.verifiedGeneratedOutputPaths.length > 0)
|
|
7934
8168
|
);
|
|
@@ -11941,6 +12175,29 @@ export function nextStepRuntimeConfig(config = {}, state = {}) {
|
|
|
11941
12175
|
runtimeConfig.testFailureRepairPatchTargets = [];
|
|
11942
12176
|
runtimeConfig.repositoryStateRepairCommitPaths =
|
|
11943
12177
|
taskOwnedMutationPathsSinceLatestCommit(verification);
|
|
12178
|
+
const repositoryInspection = currentRepositoryStateInspection(
|
|
12179
|
+
verification,
|
|
12180
|
+
retainedFailedTest
|
|
12181
|
+
);
|
|
12182
|
+
const observedEntries = runtimeConfig.repositoryStateRepairCommitPaths.length
|
|
12183
|
+
? []
|
|
12184
|
+
: (repositoryInspection?.entries || [])
|
|
12185
|
+
.map((entry) => ({
|
|
12186
|
+
status: String(entry?.status || ""),
|
|
12187
|
+
path: safeTaskOwnedCommitPath(entry?.path),
|
|
12188
|
+
}))
|
|
12189
|
+
.filter((entry) => entry.path)
|
|
12190
|
+
.slice(0, 64);
|
|
12191
|
+
runtimeConfig.repositoryStateRepairObservedEntries = observedEntries;
|
|
12192
|
+
runtimeConfig.repositoryStateRepairObservedPaths = observedEntries.map(
|
|
12193
|
+
(entry) => entry.path
|
|
12194
|
+
);
|
|
12195
|
+
runtimeConfig.repositoryStateRepairInspectionCommand =
|
|
12196
|
+
REPOSITORY_STATE_INSPECTION_COMMAND;
|
|
12197
|
+
runtimeConfig.repositoryStateRepairInspectionRequired = Boolean(
|
|
12198
|
+
runtimeConfig.repositoryStateRepairCommitPaths.length === 0 &&
|
|
12199
|
+
!repositoryInspection
|
|
12200
|
+
);
|
|
11944
12201
|
} else if (retainedRepositoryStateRepair) {
|
|
11945
12202
|
delete runtimeConfig.completionFreshMutationRequired;
|
|
11946
12203
|
delete runtimeConfig.completionFreshMutationRevision;
|
|
@@ -14255,20 +14512,45 @@ async function executeTool(browserState, toolCall, snapshot, config, store, obse
|
|
|
14255
14512
|
? config.taskOwnedCommitPaths
|
|
14256
14513
|
: []),
|
|
14257
14514
|
].map(safeTaskOwnedCommitPath).filter(Boolean);
|
|
14515
|
+
const observedRepositoryCommitPaths = Array.isArray(
|
|
14516
|
+
config.repositoryStateRepairObservedPaths
|
|
14517
|
+
)
|
|
14518
|
+
? config.repositoryStateRepairObservedPaths
|
|
14519
|
+
.map(safeTaskOwnedCommitPath)
|
|
14520
|
+
.filter(Boolean)
|
|
14521
|
+
: [];
|
|
14522
|
+
const requestedObservedCommitPaths = Array.isArray(args.paths)
|
|
14523
|
+
? [...new Set(args.paths.map(safeTaskOwnedCommitPath).filter(Boolean))]
|
|
14524
|
+
: [];
|
|
14525
|
+
const observedCommitPathSet = new Set(observedRepositoryCommitPaths);
|
|
14526
|
+
const selectedRepositoryCommitPaths = repositoryCommitPaths.length
|
|
14527
|
+
? repositoryCommitPaths
|
|
14528
|
+
: requestedObservedCommitPaths.length > 0 &&
|
|
14529
|
+
requestedObservedCommitPaths.length === args.paths?.length &&
|
|
14530
|
+
requestedObservedCommitPaths.every((candidate) =>
|
|
14531
|
+
observedCommitPathSet.has(candidate)
|
|
14532
|
+
)
|
|
14533
|
+
? requestedObservedCommitPaths
|
|
14534
|
+
: [];
|
|
14258
14535
|
if (
|
|
14259
14536
|
requestedToolName === "commit_project_changes" &&
|
|
14260
|
-
|
|
14537
|
+
selectedRepositoryCommitPaths.length > 0 &&
|
|
14261
14538
|
typeof args.message === "string" &&
|
|
14262
14539
|
args.message.trim()
|
|
14263
14540
|
) {
|
|
14264
|
-
const commitCommand = buildTaskOwnedCommitCommand(
|
|
14541
|
+
const commitCommand = buildTaskOwnedCommitCommand(
|
|
14542
|
+
selectedRepositoryCommitPaths,
|
|
14543
|
+
args.message
|
|
14544
|
+
);
|
|
14265
14545
|
if (commitCommand) {
|
|
14266
14546
|
args = { command: commitCommand };
|
|
14267
14547
|
toolName = "run_command";
|
|
14268
14548
|
autoCorrection = {
|
|
14269
14549
|
requestedToolName,
|
|
14270
14550
|
toolName,
|
|
14271
|
-
reason:
|
|
14551
|
+
reason: repositoryCommitPaths.length
|
|
14552
|
+
? "evidence-derived-task-owned-commit"
|
|
14553
|
+
: "observed-task-owned-commit-selection",
|
|
14272
14554
|
};
|
|
14273
14555
|
}
|
|
14274
14556
|
}
|
|
@@ -15054,6 +15336,20 @@ async function executeTool(browserState, toolCall, snapshot, config, store, obse
|
|
|
15054
15336
|
const policy = evaluateCommandPolicy(rawCommand, config);
|
|
15055
15337
|
const observedCommand = normalizeProjectCommand(rawCommand);
|
|
15056
15338
|
const observedInnerCommand = explicitExitProbeStatus(observedCommand).command;
|
|
15339
|
+
const repositoryStateInspectionRequested = projectCommandsEquivalent(
|
|
15340
|
+
observedCommand,
|
|
15341
|
+
REPOSITORY_STATE_INSPECTION_COMMAND,
|
|
15342
|
+
config
|
|
15343
|
+
);
|
|
15344
|
+
const generatedArtifactProducer = safeProjectProducerSegment(
|
|
15345
|
+
observedCommand,
|
|
15346
|
+
config
|
|
15347
|
+
);
|
|
15348
|
+
const captureMutationScope = Boolean(
|
|
15349
|
+
policy.writesWorkspace ||
|
|
15350
|
+
policy.mayMutateProject === true ||
|
|
15351
|
+
generatedArtifactProducer
|
|
15352
|
+
);
|
|
15057
15353
|
const requiredCommands = effectiveRequiredProjectCommands(
|
|
15058
15354
|
state,
|
|
15059
15355
|
state.meta?.projectVerification || {},
|
|
@@ -15065,10 +15361,24 @@ async function executeTool(browserState, toolCall, snapshot, config, store, obse
|
|
|
15065
15361
|
const exactOutputSnapshotsBefore = isRequiredCommand && policy.writesWorkspace
|
|
15066
15362
|
? await captureExactOutputSnapshots(state, config)
|
|
15067
15363
|
: [];
|
|
15364
|
+
const gitWorktreeBefore = captureMutationScope
|
|
15365
|
+
? await captureGitWorktreeSnapshot(config)
|
|
15366
|
+
: null;
|
|
15068
15367
|
if (config.useDockerSandbox) {
|
|
15069
15368
|
await ensureDockerSandboxReady(config, observers);
|
|
15070
15369
|
}
|
|
15071
15370
|
const commandResult = await runShellCommand(rawCommand, config, policy);
|
|
15371
|
+
const gitWorktreeAfter = captureMutationScope
|
|
15372
|
+
? await captureGitWorktreeSnapshot(config)
|
|
15373
|
+
: null;
|
|
15374
|
+
const repositoryStateInspectionSnapshot =
|
|
15375
|
+
repositoryStateInspectionRequested && commandResult.ok !== false
|
|
15376
|
+
? await captureGitWorktreeSnapshot(config)
|
|
15377
|
+
: null;
|
|
15378
|
+
const projectMutationPaths = changedGitStatusPaths(
|
|
15379
|
+
gitWorktreeBefore,
|
|
15380
|
+
gitWorktreeAfter
|
|
15381
|
+
);
|
|
15072
15382
|
const generatedOutputPaths = commandResult.ok !== false
|
|
15073
15383
|
? await verifiedGeneratedOutputPaths(state, exactOutputSnapshotsBefore, config)
|
|
15074
15384
|
: [];
|
|
@@ -15103,6 +15413,20 @@ async function executeTool(browserState, toolCall, snapshot, config, store, obse
|
|
|
15103
15413
|
...(generatedOutputPaths.length
|
|
15104
15414
|
? { verifiedGeneratedOutputPaths: generatedOutputPaths }
|
|
15105
15415
|
: {}),
|
|
15416
|
+
...(projectMutationPaths.length
|
|
15417
|
+
? { projectMutationPaths }
|
|
15418
|
+
: {}),
|
|
15419
|
+
...(repositoryStateInspectionSnapshot
|
|
15420
|
+
? {
|
|
15421
|
+
repositoryStateStatusEntries:
|
|
15422
|
+
repositoryStateInspectionSnapshot.entries.map(
|
|
15423
|
+
({ status, path: statusPath }) => ({
|
|
15424
|
+
status,
|
|
15425
|
+
path: statusPath,
|
|
15426
|
+
})
|
|
15427
|
+
),
|
|
15428
|
+
}
|
|
15429
|
+
: {}),
|
|
15106
15430
|
...commandResult,
|
|
15107
15431
|
...(permissionAdvice ? { permissionAdvice } : {}),
|
|
15108
15432
|
};
|
|
@@ -1646,6 +1646,51 @@ function constrainRepositoryStateCommit(tool, paths = []) {
|
|
|
1646
1646
|
};
|
|
1647
1647
|
}
|
|
1648
1648
|
|
|
1649
|
+
function constrainObservedRepositoryStateCommit(tool, paths = []) {
|
|
1650
|
+
if (!tool || !Array.isArray(paths) || paths.length === 0) return null;
|
|
1651
|
+
const candidates = [...new Set(paths.map((item) => String(item || "").trim()).filter(Boolean))]
|
|
1652
|
+
.slice(0, 64);
|
|
1653
|
+
if (!candidates.length) return null;
|
|
1654
|
+
return {
|
|
1655
|
+
...tool,
|
|
1656
|
+
function: {
|
|
1657
|
+
...tool.function,
|
|
1658
|
+
name: "commit_project_changes",
|
|
1659
|
+
description: [
|
|
1660
|
+
"Commit only the task-owned subset of the exact currently dirty paths discovered by the bounded repository inspection.",
|
|
1661
|
+
"Select every intended task source, generated output, relocation deletion, or manifest involved in this task, and exclude unrelated pre-existing work.",
|
|
1662
|
+
"The runtime rejects paths outside this exact observation and stages only the selected paths before creating one local commit.",
|
|
1663
|
+
`Observed candidates: ${candidates.join(", ")}.`,
|
|
1664
|
+
].join(" "),
|
|
1665
|
+
parameters: {
|
|
1666
|
+
type: "object",
|
|
1667
|
+
properties: {
|
|
1668
|
+
paths: {
|
|
1669
|
+
type: "array",
|
|
1670
|
+
minItems: 1,
|
|
1671
|
+
maxItems: candidates.length,
|
|
1672
|
+
uniqueItems: true,
|
|
1673
|
+
items: {
|
|
1674
|
+
type: "string",
|
|
1675
|
+
enum: candidates,
|
|
1676
|
+
},
|
|
1677
|
+
description: "The complete task-owned subset of the exact observed dirty paths.",
|
|
1678
|
+
},
|
|
1679
|
+
message: {
|
|
1680
|
+
type: "string",
|
|
1681
|
+
minLength: 3,
|
|
1682
|
+
maxLength: 120,
|
|
1683
|
+
pattern: "^[^\\r\\n\\u0000]+$",
|
|
1684
|
+
description: "A concise factual Git commit subject for the selected task-owned changes.",
|
|
1685
|
+
},
|
|
1686
|
+
},
|
|
1687
|
+
required: ["paths", "message"],
|
|
1688
|
+
additionalProperties: false,
|
|
1689
|
+
},
|
|
1690
|
+
},
|
|
1691
|
+
};
|
|
1692
|
+
}
|
|
1693
|
+
|
|
1649
1694
|
function roundRobinToolNames(groups) {
|
|
1650
1695
|
const names = [];
|
|
1651
1696
|
const maxLength = Math.max(0, ...groups.map((group) => group.length));
|
|
@@ -2000,18 +2045,18 @@ export function selectProgressiveTools(
|
|
|
2000
2045
|
if (commitProjectChanges) {
|
|
2001
2046
|
return [commitProjectChanges, finish].filter(Boolean);
|
|
2002
2047
|
}
|
|
2003
|
-
const
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2048
|
+
const observedCommit = constrainObservedRepositoryStateCommit(
|
|
2049
|
+
runCommand,
|
|
2050
|
+
config.repositoryStateRepairObservedPaths
|
|
2051
|
+
);
|
|
2052
|
+
if (observedCommit) {
|
|
2053
|
+
return [observedCommit, finish].filter(Boolean);
|
|
2054
|
+
}
|
|
2055
|
+
const repositoryStateTool = constrainRunCommand(
|
|
2056
|
+
runCommand,
|
|
2057
|
+
config.repositoryStateRepairInspectionCommand,
|
|
2058
|
+
"Run this exact bounded Git status inspection once. The runtime records the current dirty paths and will offer a path-enumerated commit tool on the next turn; do not substitute a broader status/diff loop or alter project content."
|
|
2059
|
+
);
|
|
2015
2060
|
return [repositoryStateTool, finish].filter(Boolean);
|
|
2016
2061
|
}
|
|
2017
2062
|
const constrainedRepairPatch = annotateRequiredSymbolRepair(
|