@lazyingart/agintiflow 0.20.318 → 0.20.320
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.320",
|
|
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,105 @@ 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
|
+
);
|
|
4618
|
+
const workspaceCdWrappedTestCommand =
|
|
4619
|
+
`cd ${workspace} && PYTHONPATH=src python -m pytest tests/test_wechat_document_reader.py -v; echo "EXIT=$?"`;
|
|
4620
|
+
assert(
|
|
4621
|
+
isSubstantiveTestCommand(workspaceCdWrappedTestCommand, {
|
|
4622
|
+
commandCwd: workspace,
|
|
4623
|
+
}),
|
|
4624
|
+
"a safe explicit-status test wrapper lost test identity behind a workspace cd"
|
|
4625
|
+
);
|
|
4626
|
+
const workspaceCdWrappedTestState = {
|
|
4627
|
+
meta: { goalContract: { revision: 1 } },
|
|
4628
|
+
};
|
|
4629
|
+
const workspaceCdWrappedTestResult = {
|
|
4630
|
+
toolName: "run_command",
|
|
4631
|
+
ok: true,
|
|
4632
|
+
exitCode: 0,
|
|
4633
|
+
args: { command: workspaceCdWrappedTestCommand },
|
|
4634
|
+
stdout: "7 passed in 0.06s\nEXIT=0\n",
|
|
4635
|
+
stderr: "",
|
|
4636
|
+
projectMutationPaths: [],
|
|
4637
|
+
commandPolicy: classifyCommand(workspaceCdWrappedTestCommand),
|
|
4638
|
+
};
|
|
4639
|
+
recordProjectVerificationOutcome(
|
|
4640
|
+
workspaceCdWrappedTestState,
|
|
4641
|
+
workspaceCdWrappedTestResult,
|
|
4642
|
+
{
|
|
4643
|
+
commandCwd: workspace,
|
|
4644
|
+
taskProfile: "qa",
|
|
4645
|
+
allowShellTool: true,
|
|
4646
|
+
sandboxMode: "host",
|
|
4647
|
+
}
|
|
4648
|
+
);
|
|
4649
|
+
assert(
|
|
4650
|
+
workspaceCdWrappedTestResult.projectTest?.passed === true &&
|
|
4651
|
+
workspaceCdWrappedTestState.meta.projectVerification?.testRuns?.length === 1,
|
|
4652
|
+
`a successful workspace-cd status wrapper did not produce one passing test run: ${JSON.stringify({
|
|
4653
|
+
projectTest: workspaceCdWrappedTestResult.projectTest,
|
|
4654
|
+
testRuns:
|
|
4655
|
+
workspaceCdWrappedTestState.meta.projectVerification?.testRuns,
|
|
4656
|
+
})}`
|
|
4657
|
+
);
|
|
4559
4658
|
const pipedUnittestCommand =
|
|
4560
4659
|
"python3 -m unittest discover -s tests -p 'test_wechat_document_reader.py' -v 2>&1 | tail -14; echo \"EXIT=${PIPESTATUS[0]}\"";
|
|
4561
4660
|
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) ||
|
|
@@ -5439,10 +5495,12 @@ export function isSubstantiveTestCommand(command = "", config = {}) {
|
|
|
5439
5495
|
if (isRetainedExactVerificationCommand(command, config)) return true;
|
|
5440
5496
|
const normalized = normalizeProjectCommand(normalizeCommandForPolicy(command, config));
|
|
5441
5497
|
if (projectTestCommandWrapper(normalized)) return true;
|
|
5442
|
-
const
|
|
5498
|
+
const wrappedTestCommand =
|
|
5499
|
+
projectExitStatusWrapper(normalized)?.command || normalized;
|
|
5500
|
+
const text = normalizeLeadingWorkspaceCd(wrappedTestCommand, config);
|
|
5443
5501
|
if (!text) return false;
|
|
5444
|
-
const classification =
|
|
5445
|
-
if (classification.substantiveTest !== true) return false;
|
|
5502
|
+
const classification = boundedTestCommandClassification(text);
|
|
5503
|
+
if (classification.policy.substantiveTest !== true) return false;
|
|
5446
5504
|
const sequence = parseTopLevelShellSequence(text);
|
|
5447
5505
|
if (sequence.commands.length <= 1) return true;
|
|
5448
5506
|
if (!sequence.separators.every((separator) => separator === "&&")) return false;
|
|
@@ -5450,9 +5508,17 @@ export function isSubstantiveTestCommand(command = "", config = {}) {
|
|
|
5450
5508
|
let lastTestIndex = -1;
|
|
5451
5509
|
let lastMutationIndex = -1;
|
|
5452
5510
|
sequence.commands.forEach((segment, index) => {
|
|
5453
|
-
const
|
|
5511
|
+
const segmentClassification = boundedTestCommandClassification(segment);
|
|
5512
|
+
const segmentPolicy = segmentClassification.policy;
|
|
5454
5513
|
if (segmentPolicy.substantiveTest === true) lastTestIndex = index;
|
|
5455
|
-
if (
|
|
5514
|
+
if (
|
|
5515
|
+
commandCanMutateProjectContent(
|
|
5516
|
+
segmentClassification.executableCommand,
|
|
5517
|
+
segmentPolicy
|
|
5518
|
+
)
|
|
5519
|
+
) {
|
|
5520
|
+
lastMutationIndex = index;
|
|
5521
|
+
}
|
|
5456
5522
|
});
|
|
5457
5523
|
return lastTestIndex >= 0 && lastTestIndex >= lastMutationIndex;
|
|
5458
5524
|
}
|
|
@@ -7248,6 +7314,10 @@ export function recordProjectVerificationOutcome(state = {}, toolResult = {}, co
|
|
|
7248
7314
|
commandMutationPaths.length === 0 &&
|
|
7249
7315
|
commandIsBoundedReadOnlyArtifactValidation(mutationCommand)
|
|
7250
7316
|
);
|
|
7317
|
+
const nonMutatingTestOutputPipeline = Boolean(
|
|
7318
|
+
commandMutationPaths.length === 0 &&
|
|
7319
|
+
commandIsNonMutatingTestOutputPipeline(mutationCommand)
|
|
7320
|
+
);
|
|
7251
7321
|
const projectContentMutation = Boolean(
|
|
7252
7322
|
command &&
|
|
7253
7323
|
toolResult.blocked !== true &&
|
|
@@ -7257,6 +7327,7 @@ export function recordProjectVerificationOutcome(state = {}, toolResult = {}, co
|
|
|
7257
7327
|
!disposableGeneratedVerificationSideEffects &&
|
|
7258
7328
|
!scopedTaskArtifactWrite &&
|
|
7259
7329
|
!readOnlyArtifactValidation &&
|
|
7330
|
+
!nonMutatingTestOutputPipeline &&
|
|
7260
7331
|
(commandSucceeded || commandMutationPaths.length > 0) &&
|
|
7261
7332
|
(
|
|
7262
7333
|
commandCanMutateProjectContent(mutationCommand, commandPolicy) ||
|
|
@@ -7277,6 +7348,9 @@ export function recordProjectVerificationOutcome(state = {}, toolResult = {}, co
|
|
|
7277
7348
|
if (readOnlyArtifactValidation) {
|
|
7278
7349
|
toolResult.readOnlyArtifactValidation = true;
|
|
7279
7350
|
}
|
|
7351
|
+
if (nonMutatingTestOutputPipeline) {
|
|
7352
|
+
toolResult.nonAuthoritativeTestOutputPipeline = true;
|
|
7353
|
+
}
|
|
7280
7354
|
if (testCommandWrapper?.semanticallyReadOnly === true) {
|
|
7281
7355
|
toolResult.boundedReadOnlyTestWrapper = true;
|
|
7282
7356
|
}
|
|
@@ -22632,6 +22706,9 @@ async function completionEvidenceDecision({ config, state, store, observers, ste
|
|
|
22632
22706
|
detail.suggestedTestCommands.length
|
|
22633
22707
|
? `Use the established test command now: ${detail.suggestedTestCommands.join("; ")}.`
|
|
22634
22708
|
: "",
|
|
22709
|
+
detail.missingEvidence.includes("test")
|
|
22710
|
+
? "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."
|
|
22711
|
+
: "",
|
|
22635
22712
|
detail.failedProjectTestSummary
|
|
22636
22713
|
? `The latest current test run failed: ${detail.failedProjectTestSummary}`
|
|
22637
22714
|
: "",
|