@lazyingart/agintiflow 0.20.318 → 0.20.319
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.319",
|
|
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",
|
|
@@ -4556,6 +4556,65 @@ try {
|
|
|
4556
4556
|
failedSpacedExitProbeResult.projectTest?.explicitExitStatus === 1,
|
|
4557
4557
|
"a spaced nonzero test-status wrapper was recorded as successful generic evidence"
|
|
4558
4558
|
);
|
|
4559
|
+
const unsafePipedTestCommand =
|
|
4560
|
+
"cd . && PYTHONPATH=src python -m pytest tests/test_wechat_document_reader.py -q 2>&1 | tail -5 && echo '---artifacts---' && ls -la output/task";
|
|
4561
|
+
const unsafePipedTestState = { meta: { goalContract: { revision: 1 } } };
|
|
4562
|
+
const unsafePipedTestResult = {
|
|
4563
|
+
toolName: "run_command",
|
|
4564
|
+
ok: true,
|
|
4565
|
+
exitCode: 0,
|
|
4566
|
+
args: { command: unsafePipedTestCommand },
|
|
4567
|
+
stdout: "....... [100%]\n7 passed in 0.04s\n---artifacts---\n",
|
|
4568
|
+
stderr: "",
|
|
4569
|
+
projectMutationPaths: [],
|
|
4570
|
+
commandPolicy: classifyCommand(unsafePipedTestCommand),
|
|
4571
|
+
};
|
|
4572
|
+
recordProjectVerificationOutcome(
|
|
4573
|
+
unsafePipedTestState,
|
|
4574
|
+
unsafePipedTestResult,
|
|
4575
|
+
{ commandCwd: workspace, taskProfile: "qa", allowShellTool: true, sandboxMode: "host" }
|
|
4576
|
+
);
|
|
4577
|
+
assert(
|
|
4578
|
+
unsafePipedTestState.meta.projectVerification?.mutationRevision === 0 &&
|
|
4579
|
+
unsafePipedTestResult.nonAuthoritativeTestOutputPipeline === true &&
|
|
4580
|
+
unsafePipedTestResult.projectTest === undefined,
|
|
4581
|
+
`an exit-status-hiding test pipeline fabricated source mutation or passing test evidence: ${JSON.stringify({
|
|
4582
|
+
mutationRevision:
|
|
4583
|
+
unsafePipedTestState.meta.projectVerification?.mutationRevision,
|
|
4584
|
+
nonAuthoritativeTestOutputPipeline:
|
|
4585
|
+
unsafePipedTestResult.nonAuthoritativeTestOutputPipeline,
|
|
4586
|
+
projectTest: unsafePipedTestResult.projectTest,
|
|
4587
|
+
policy: unsafePipedTestResult.commandPolicy,
|
|
4588
|
+
})}`
|
|
4589
|
+
);
|
|
4590
|
+
const mutatingPipedTestCommand = `${unsafePipedTestCommand} && touch src/agent-runner.js`;
|
|
4591
|
+
const mutatingPipedTestState = { meta: { goalContract: { revision: 1 } } };
|
|
4592
|
+
const mutatingPipedTestResult = {
|
|
4593
|
+
toolName: "run_command",
|
|
4594
|
+
ok: true,
|
|
4595
|
+
exitCode: 0,
|
|
4596
|
+
args: { command: mutatingPipedTestCommand },
|
|
4597
|
+
stdout: "7 passed in 0.04s\n",
|
|
4598
|
+
stderr: "",
|
|
4599
|
+
projectMutationPaths: [],
|
|
4600
|
+
commandPolicy: classifyCommand(mutatingPipedTestCommand),
|
|
4601
|
+
};
|
|
4602
|
+
recordProjectVerificationOutcome(
|
|
4603
|
+
mutatingPipedTestState,
|
|
4604
|
+
mutatingPipedTestResult,
|
|
4605
|
+
{
|
|
4606
|
+
commandCwd: workspace,
|
|
4607
|
+
taskProfile: "qa",
|
|
4608
|
+
allowShellTool: true,
|
|
4609
|
+
allowDestructive: true,
|
|
4610
|
+
sandboxMode: "host",
|
|
4611
|
+
}
|
|
4612
|
+
);
|
|
4613
|
+
assert(
|
|
4614
|
+
mutatingPipedTestState.meta.projectVerification?.mutationRevision === 1 &&
|
|
4615
|
+
mutatingPipedTestResult.nonAuthoritativeTestOutputPipeline !== true,
|
|
4616
|
+
"a source mutation appended to an unsafe test pipeline escaped revision tracking"
|
|
4617
|
+
);
|
|
4559
4618
|
const pipedUnittestCommand =
|
|
4560
4619
|
"python3 -m unittest discover -s tests -p 'test_wechat_document_reader.py' -v 2>&1 | tail -14; echo \"EXIT=${PIPESTATUS[0]}\"";
|
|
4561
4620
|
assert(
|
package/src/agent-runner.js
CHANGED
|
@@ -5189,6 +5189,13 @@ function boundedReadOnlyTestPrefixCommand(value = "") {
|
|
|
5189
5189
|
const command = normalizeProjectCommand(value);
|
|
5190
5190
|
if (!command) return false;
|
|
5191
5191
|
const tokens = tokenizeShellWords(command);
|
|
5192
|
+
if (
|
|
5193
|
+
tokens[0] === "cd" &&
|
|
5194
|
+
tokens.length === 2 &&
|
|
5195
|
+
!/(?:`|\$\(|[|<>])/u.test(command)
|
|
5196
|
+
) {
|
|
5197
|
+
return true;
|
|
5198
|
+
}
|
|
5192
5199
|
if (
|
|
5193
5200
|
["date", "echo", "printf"].includes(String(tokens[0] || "")) &&
|
|
5194
5201
|
!/(?:`|\$\()/u.test(command)
|
|
@@ -5361,6 +5368,55 @@ function projectTestCommandWrapper(command = "") {
|
|
|
5361
5368
|
);
|
|
5362
5369
|
}
|
|
5363
5370
|
|
|
5371
|
+
function commandIsNonMutatingTestOutputPipeline(command = "") {
|
|
5372
|
+
const normalized = normalizeProjectCommand(command);
|
|
5373
|
+
if (!normalized || /\b(?:PIPESTATUS|pipefail)\b/u.test(normalized)) return false;
|
|
5374
|
+
const sequence = parseTopLevelShellSequence(normalized);
|
|
5375
|
+
if (
|
|
5376
|
+
sequence.openQuote ||
|
|
5377
|
+
sequence.trailingEscape ||
|
|
5378
|
+
sequence.trailingSeparator ||
|
|
5379
|
+
!sequence.commands.length
|
|
5380
|
+
) {
|
|
5381
|
+
return false;
|
|
5382
|
+
}
|
|
5383
|
+
let sawTestPipeline = false;
|
|
5384
|
+
for (let index = 0; index < sequence.commands.length;) {
|
|
5385
|
+
if (sequence.separators[index] === "|") {
|
|
5386
|
+
let pipelineEnd = index + 1;
|
|
5387
|
+
while (sequence.separators[pipelineEnd] === "|") pipelineEnd += 1;
|
|
5388
|
+
const test = boundedTestCommandClassification(sequence.commands[index]);
|
|
5389
|
+
if (test.policy.substantiveTest !== true) return false;
|
|
5390
|
+
const filtersAreReadOnly = sequence.commands
|
|
5391
|
+
.slice(index + 1, pipelineEnd + 1)
|
|
5392
|
+
.every((candidate) => {
|
|
5393
|
+
const tokens = tokenizeShellWords(candidate);
|
|
5394
|
+
if (
|
|
5395
|
+
!["cat", "grep", "head", "sed", "sort", "tail", "tr", "uniq", "wc"].includes(
|
|
5396
|
+
String(tokens[0] || "")
|
|
5397
|
+
) ||
|
|
5398
|
+
/(?:`|\$\(|[<>])/u.test(candidate)
|
|
5399
|
+
) {
|
|
5400
|
+
return false;
|
|
5401
|
+
}
|
|
5402
|
+
const policy = classifyCommand(candidate);
|
|
5403
|
+
return policy.writesWorkspace !== true && policy.mayMutateProject !== true;
|
|
5404
|
+
});
|
|
5405
|
+
if (!filtersAreReadOnly) return false;
|
|
5406
|
+
sawTestPipeline = true;
|
|
5407
|
+
index = pipelineEnd + 1;
|
|
5408
|
+
continue;
|
|
5409
|
+
}
|
|
5410
|
+
const candidate = String(sequence.commands[index] || "")
|
|
5411
|
+
.trim()
|
|
5412
|
+
.replace(/^(?:[A-Za-z_]\w*=(?:"[^"\n]*"|'[^'\n]*'|[^\s;&|]+)\s*)+/u, "")
|
|
5413
|
+
.trim();
|
|
5414
|
+
if (candidate && !boundedReadOnlyTestPrefixCommand(candidate)) return false;
|
|
5415
|
+
index += 1;
|
|
5416
|
+
}
|
|
5417
|
+
return sawTestPipeline;
|
|
5418
|
+
}
|
|
5419
|
+
|
|
5364
5420
|
function projectExitStatusWrapper(command = "") {
|
|
5365
5421
|
return (
|
|
5366
5422
|
parseNonMutatingExitStatusWrapper(command) ||
|
|
@@ -7248,6 +7304,10 @@ export function recordProjectVerificationOutcome(state = {}, toolResult = {}, co
|
|
|
7248
7304
|
commandMutationPaths.length === 0 &&
|
|
7249
7305
|
commandIsBoundedReadOnlyArtifactValidation(mutationCommand)
|
|
7250
7306
|
);
|
|
7307
|
+
const nonMutatingTestOutputPipeline = Boolean(
|
|
7308
|
+
commandMutationPaths.length === 0 &&
|
|
7309
|
+
commandIsNonMutatingTestOutputPipeline(mutationCommand)
|
|
7310
|
+
);
|
|
7251
7311
|
const projectContentMutation = Boolean(
|
|
7252
7312
|
command &&
|
|
7253
7313
|
toolResult.blocked !== true &&
|
|
@@ -7257,6 +7317,7 @@ export function recordProjectVerificationOutcome(state = {}, toolResult = {}, co
|
|
|
7257
7317
|
!disposableGeneratedVerificationSideEffects &&
|
|
7258
7318
|
!scopedTaskArtifactWrite &&
|
|
7259
7319
|
!readOnlyArtifactValidation &&
|
|
7320
|
+
!nonMutatingTestOutputPipeline &&
|
|
7260
7321
|
(commandSucceeded || commandMutationPaths.length > 0) &&
|
|
7261
7322
|
(
|
|
7262
7323
|
commandCanMutateProjectContent(mutationCommand, commandPolicy) ||
|
|
@@ -7277,6 +7338,9 @@ export function recordProjectVerificationOutcome(state = {}, toolResult = {}, co
|
|
|
7277
7338
|
if (readOnlyArtifactValidation) {
|
|
7278
7339
|
toolResult.readOnlyArtifactValidation = true;
|
|
7279
7340
|
}
|
|
7341
|
+
if (nonMutatingTestOutputPipeline) {
|
|
7342
|
+
toolResult.nonAuthoritativeTestOutputPipeline = true;
|
|
7343
|
+
}
|
|
7280
7344
|
if (testCommandWrapper?.semanticallyReadOnly === true) {
|
|
7281
7345
|
toolResult.boundedReadOnlyTestWrapper = true;
|
|
7282
7346
|
}
|
|
@@ -22632,6 +22696,9 @@ async function completionEvidenceDecision({ config, state, store, observers, ste
|
|
|
22632
22696
|
detail.suggestedTestCommands.length
|
|
22633
22697
|
? `Use the established test command now: ${detail.suggestedTestCommands.join("; ")}.`
|
|
22634
22698
|
: "",
|
|
22699
|
+
detail.missingEvidence.includes("test")
|
|
22700
|
+
? "Run the focused test directly without piping it through tail, head, tee, grep, or another output filter that can replace the test exit status. If bounded output is essential, enable shell pipefail or capture the test's PIPESTATUS immediately and emit one EXIT=<status> marker. Keep artifact inspection in a separate later command."
|
|
22701
|
+
: "",
|
|
22635
22702
|
detail.failedProjectTestSummary
|
|
22636
22703
|
? `The latest current test run failed: ${detail.failedProjectTestSummary}`
|
|
22637
22704
|
: "",
|