@lazyingart/agintiflow 0.20.239 → 0.20.240
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 +1 -1
- package/scripts/smoke-dynamic-step-budget.js +106 -0
- package/src/agent-runner.js +45 -1
- package/src/command-policy.js +19 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lazyingart/agintiflow",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.240",
|
|
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",
|
|
@@ -2302,6 +2302,112 @@ try {
|
|
|
2302
2302
|
shellMutationState.meta.projectVerification?.mutationRevision === 1,
|
|
2303
2303
|
"metadata-only Git chain with observational output invalidated current verification"
|
|
2304
2304
|
);
|
|
2305
|
+
assert(
|
|
2306
|
+
classifyCommand("md5sum output/report.pdf").writesWorkspace === false &&
|
|
2307
|
+
classifyCommand("md5sum -c .aginti/verification/source-hashes.txt").writesWorkspace === false &&
|
|
2308
|
+
classifyCommand("diff .aginti/verification/run-1.txt .aginti/verification/run-2.txt").writesWorkspace === false,
|
|
2309
|
+
"checksum or diff evidence probes were not classified as read-only"
|
|
2310
|
+
);
|
|
2311
|
+
const privateEvidenceState = {
|
|
2312
|
+
meta: {
|
|
2313
|
+
goalContract: { revision: 1 },
|
|
2314
|
+
projectVerification: { requiredCommands: ["bash build.sh"] },
|
|
2315
|
+
},
|
|
2316
|
+
};
|
|
2317
|
+
const privateEvidenceBuild = {
|
|
2318
|
+
toolName: "run_command",
|
|
2319
|
+
ok: true,
|
|
2320
|
+
exitCode: 0,
|
|
2321
|
+
args: { command: "bash build.sh" },
|
|
2322
|
+
stdout: "build complete\n",
|
|
2323
|
+
stderr: "",
|
|
2324
|
+
};
|
|
2325
|
+
recordProjectVerificationOutcome(privateEvidenceState, privateEvidenceBuild, {
|
|
2326
|
+
commandCwd: workspace,
|
|
2327
|
+
taskProfile: "writing",
|
|
2328
|
+
allowShellTool: true,
|
|
2329
|
+
sandboxMode: "host",
|
|
2330
|
+
});
|
|
2331
|
+
const privateEvidenceRevision =
|
|
2332
|
+
privateEvidenceState.meta.projectVerification?.mutationRevision;
|
|
2333
|
+
const privateEvidenceCommand = {
|
|
2334
|
+
toolName: "run_command",
|
|
2335
|
+
ok: true,
|
|
2336
|
+
exitCode: 0,
|
|
2337
|
+
args: {
|
|
2338
|
+
command:
|
|
2339
|
+
"md5sum output/report.pdf > .aginti/verification/hashes-final.txt && cat .aginti/verification/hashes-final.txt && diff .aginti/verification/hashes-run1.txt .aginti/verification/hashes-final.txt && md5sum -c .aginti/verification/source-hashes.txt && git status --porcelain",
|
|
2340
|
+
},
|
|
2341
|
+
stdout: "MATCH\n",
|
|
2342
|
+
stderr: "",
|
|
2343
|
+
};
|
|
2344
|
+
recordProjectVerificationOutcome(privateEvidenceState, privateEvidenceCommand, {
|
|
2345
|
+
commandCwd: workspace,
|
|
2346
|
+
taskProfile: "writing",
|
|
2347
|
+
allowShellTool: true,
|
|
2348
|
+
sandboxMode: "host",
|
|
2349
|
+
});
|
|
2350
|
+
const privateEvidenceWrite = {
|
|
2351
|
+
toolName: "write_file",
|
|
2352
|
+
ok: true,
|
|
2353
|
+
path: ".aginti/verification/visual-check.txt",
|
|
2354
|
+
changes: [
|
|
2355
|
+
{
|
|
2356
|
+
path: ".aginti/verification/visual-check.txt",
|
|
2357
|
+
created: true,
|
|
2358
|
+
beforeHash: "",
|
|
2359
|
+
afterHash: "private-evidence",
|
|
2360
|
+
},
|
|
2361
|
+
],
|
|
2362
|
+
};
|
|
2363
|
+
recordProjectVerificationOutcome(privateEvidenceState, privateEvidenceWrite, {
|
|
2364
|
+
commandCwd: workspace,
|
|
2365
|
+
taskProfile: "writing",
|
|
2366
|
+
});
|
|
2367
|
+
const privateEvidenceContract = augmentScsTaskContractWithProjectVerification(
|
|
2368
|
+
{
|
|
2369
|
+
requiresExternalEvidence: false,
|
|
2370
|
+
requiredEvidence: [],
|
|
2371
|
+
requiredToolCalls: [],
|
|
2372
|
+
requiredGitActions: [],
|
|
2373
|
+
taskProfile: "writing",
|
|
2374
|
+
},
|
|
2375
|
+
privateEvidenceState,
|
|
2376
|
+
{ taskProfile: "writing" }
|
|
2377
|
+
);
|
|
2378
|
+
const privateEvidenceLedger = buildScsEvidenceLedger({
|
|
2379
|
+
state: {
|
|
2380
|
+
messages: [privateEvidenceBuild, privateEvidenceCommand, privateEvidenceWrite].map((result) =>
|
|
2381
|
+
toolMessage(result)
|
|
2382
|
+
),
|
|
2383
|
+
},
|
|
2384
|
+
});
|
|
2385
|
+
assert(
|
|
2386
|
+
privateEvidenceRevision === 1 &&
|
|
2387
|
+
privateEvidenceState.meta.projectVerification?.mutationRevision === 1 &&
|
|
2388
|
+
privateEvidenceState.meta.projectVerification?.requiredCommandBatch?.complete === true &&
|
|
2389
|
+
evaluateScsEvidence(privateEvidenceContract, privateEvidenceLedger).ok,
|
|
2390
|
+
"ignored private verification evidence invalidated a successful canonical build"
|
|
2391
|
+
);
|
|
2392
|
+
const publicEvidenceMutation = {
|
|
2393
|
+
toolName: "run_command",
|
|
2394
|
+
ok: true,
|
|
2395
|
+
exitCode: 0,
|
|
2396
|
+
args: { command: "md5sum output/report.pdf > output/hashes-final.txt" },
|
|
2397
|
+
stdout: "",
|
|
2398
|
+
stderr: "",
|
|
2399
|
+
};
|
|
2400
|
+
recordProjectVerificationOutcome(privateEvidenceState, publicEvidenceMutation, {
|
|
2401
|
+
commandCwd: workspace,
|
|
2402
|
+
taskProfile: "writing",
|
|
2403
|
+
allowShellTool: true,
|
|
2404
|
+
sandboxMode: "host",
|
|
2405
|
+
});
|
|
2406
|
+
assert(
|
|
2407
|
+
privateEvidenceState.meta.projectVerification?.mutationRevision === 2 &&
|
|
2408
|
+
!privateEvidenceState.meta.projectVerification?.requiredCommandBatch,
|
|
2409
|
+
"a non-private output write was incorrectly exempted from project mutation tracking"
|
|
2410
|
+
);
|
|
2305
2411
|
const gitCheckoutResult = {
|
|
2306
2412
|
toolName: "run_command",
|
|
2307
2413
|
ok: true,
|
package/src/agent-runner.js
CHANGED
|
@@ -5991,6 +5991,49 @@ const WORKTREE_CHANGING_GIT_ACTIONS = new Set([
|
|
|
5991
5991
|
"switch",
|
|
5992
5992
|
]);
|
|
5993
5993
|
|
|
5994
|
+
function isPrivateVerificationEvidencePath(value = "") {
|
|
5995
|
+
const normalized = String(value || "")
|
|
5996
|
+
.trim()
|
|
5997
|
+
.replace(/^["']|["']$/g, "")
|
|
5998
|
+
.replace(/\\/g, "/")
|
|
5999
|
+
.replace(/^\.\//, "");
|
|
6000
|
+
return Boolean(
|
|
6001
|
+
normalized === ".aginti/verification" ||
|
|
6002
|
+
normalized.startsWith(".aginti/verification/") ||
|
|
6003
|
+
normalized.includes("/.aginti/verification/")
|
|
6004
|
+
);
|
|
6005
|
+
}
|
|
6006
|
+
|
|
6007
|
+
function commandWritesOnlyPrivateVerificationEvidence(command = "") {
|
|
6008
|
+
const normalized = String(command || "").trim();
|
|
6009
|
+
if (!normalized) return false;
|
|
6010
|
+
const tokens = tokenizeShellWords(normalized);
|
|
6011
|
+
if (tokens[0] === "tee") {
|
|
6012
|
+
let index = 1;
|
|
6013
|
+
if (["-a", "--append"].includes(tokens[index])) index += 1;
|
|
6014
|
+
if (tokens[index] === "--") index += 1;
|
|
6015
|
+
const targets = tokens.slice(index);
|
|
6016
|
+
return targets.length > 0 && targets.every(isPrivateVerificationEvidencePath);
|
|
6017
|
+
}
|
|
6018
|
+
if (tokens[0] === "mkdir") {
|
|
6019
|
+
const targets = tokens.slice(1).filter((token) => token !== "-p" && token !== "--");
|
|
6020
|
+
return targets.length > 0 && targets.every(isPrivateVerificationEvidencePath);
|
|
6021
|
+
}
|
|
6022
|
+
|
|
6023
|
+
let strippedPrivateRedirect = false;
|
|
6024
|
+
const withoutPrivateRedirects = normalized.replace(
|
|
6025
|
+
/(^|\s)(?:\d*>>?|&>>?)\s*("[^"]+"|'[^']+'|[^\s;&|]+)/g,
|
|
6026
|
+
(match, prefix, target) => {
|
|
6027
|
+
if (!isPrivateVerificationEvidencePath(target)) return match;
|
|
6028
|
+
strippedPrivateRedirect = true;
|
|
6029
|
+
return prefix;
|
|
6030
|
+
}
|
|
6031
|
+
).trim();
|
|
6032
|
+
if (!strippedPrivateRedirect || !withoutPrivateRedirects) return false;
|
|
6033
|
+
const underlyingPolicy = classifyCommand(withoutPrivateRedirects);
|
|
6034
|
+
return underlyingPolicy.writesWorkspace !== true && underlyingPolicy.mayMutateProject !== true;
|
|
6035
|
+
}
|
|
6036
|
+
|
|
5994
6037
|
function commandCanMutateProjectContent(command = "", commandPolicy = {}) {
|
|
5995
6038
|
if (commandPolicy.writesWorkspace !== true && commandPolicy.mayMutateProject !== true) return false;
|
|
5996
6039
|
const sequence = parseTopLevelShellSequence(String(command || ""));
|
|
@@ -6004,6 +6047,7 @@ function commandCanMutateProjectContent(command = "", commandPolicy = {}) {
|
|
|
6004
6047
|
commandCanMutateProjectContent(segment, classifyCommand(segment))
|
|
6005
6048
|
);
|
|
6006
6049
|
}
|
|
6050
|
+
if (commandWritesOnlyPrivateVerificationEvidence(command)) return false;
|
|
6007
6051
|
const category = String(commandPolicy.category || "");
|
|
6008
6052
|
if (!["git-workflow", "git-remote"].includes(category)) return true;
|
|
6009
6053
|
if (/\bgit\s+clone\b/i.test(String(command || ""))) return true;
|
|
@@ -6490,7 +6534,7 @@ function successfulProjectMutationPaths(toolResult = {}) {
|
|
|
6490
6534
|
[
|
|
6491
6535
|
toolResult.path,
|
|
6492
6536
|
...actualChanges.flatMap((change) => [change.path, change.fromPath]),
|
|
6493
|
-
].filter(
|
|
6537
|
+
].filter((candidate) => candidate && !isPrivateVerificationEvidencePath(candidate))
|
|
6494
6538
|
),
|
|
6495
6539
|
];
|
|
6496
6540
|
}
|
package/src/command-policy.js
CHANGED
|
@@ -108,17 +108,31 @@ function isReadOnlyUniqFilter(command = "") {
|
|
|
108
108
|
);
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
function
|
|
111
|
+
function isReadOnlyDigestCommand(command = "") {
|
|
112
112
|
const normalized = stripBenignRedirections(command);
|
|
113
113
|
if (hasActiveShellExpansion(normalized)) return false;
|
|
114
114
|
const tokens = tokenizeShellWords(normalized);
|
|
115
|
-
if (
|
|
116
|
-
|
|
115
|
+
if (!["md5sum", "sha256sum"].includes(tokens[0]) || tokens.length < 2) return false;
|
|
116
|
+
let index = 1;
|
|
117
|
+
if (["-c", "--check"].includes(tokens[index])) index += 1;
|
|
118
|
+
if (tokens[index] === "--") index += 1;
|
|
119
|
+
const paths = tokens.slice(index);
|
|
117
120
|
return paths.length > 0 && paths.every((token) =>
|
|
118
121
|
!token.startsWith("-") && READ_ONLY_FOR_LOOP_LITERAL_PATTERN.test(token)
|
|
119
122
|
);
|
|
120
123
|
}
|
|
121
124
|
|
|
125
|
+
function isReadOnlyDiffCommand(command = "") {
|
|
126
|
+
const normalized = stripBenignRedirections(command);
|
|
127
|
+
if (hasActiveShellExpansion(normalized)) return false;
|
|
128
|
+
const tokens = tokenizeShellWords(normalized);
|
|
129
|
+
if (tokens[0] !== "diff" || tokens.length < 3) return false;
|
|
130
|
+
const operands = tokens.slice(1).filter((token) => token !== "--" && !token.startsWith("-"));
|
|
131
|
+
return operands.length === 2 && operands.every((token) =>
|
|
132
|
+
READ_ONLY_FOR_LOOP_LITERAL_PATTERN.test(token)
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
122
136
|
function isReadOnlyFindCommand(command = "") {
|
|
123
137
|
const normalized = stripBenignRedirections(command);
|
|
124
138
|
if (!/^find\s+/.test(normalized)) return false;
|
|
@@ -1511,7 +1525,8 @@ function classifySimpleCommand(normalized) {
|
|
|
1511
1525
|
isReadOnlyPrintfCommand(commandForPatternMatching) ||
|
|
1512
1526
|
isReadOnlyTrDeleteFilter(commandForPatternMatching) ||
|
|
1513
1527
|
isReadOnlyUniqFilter(commandForPatternMatching) ||
|
|
1514
|
-
|
|
1528
|
+
isReadOnlyDigestCommand(commandForPatternMatching) ||
|
|
1529
|
+
isReadOnlyDiffCommand(commandForPatternMatching) ||
|
|
1515
1530
|
isReadOnlyFindCommand(normalized) ||
|
|
1516
1531
|
(!hasActiveShellExpansion(benignRedirectCommand) && isReadOnlyShellCondition(benignRedirectCommand))
|
|
1517
1532
|
) {
|