@lazyingart/agintiflow 0.20.271 → 0.20.272

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.271",
3
+ "version": "0.20.272",
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",
@@ -5485,6 +5485,65 @@ try {
5485
5485
  runtime: postProducerRuntime,
5486
5486
  })}`
5487
5487
  );
5488
+ const failedAfterProducerState = structuredClone(staleGeneratedDeckState);
5489
+ failedAfterProducerState.meta.goalContract.taskGoal = failedAfterProducerState.goal;
5490
+ failedAfterProducerState.meta.projectVerification.mutationHistory.splice(1, 0, {
5491
+ revision: 8,
5492
+ toolName: "apply_patch",
5493
+ paths: ["TASK.md"],
5494
+ });
5495
+ failedAfterProducerState.meta.projectVerification.testRuns.push({
5496
+ command: generatedDeckValidator,
5497
+ at: "2026-08-27T19:05:00.000Z",
5498
+ mutationRevision: 10,
5499
+ privateMutationRevision: 0,
5500
+ passed: false,
5501
+ failureEvidenceVersion: 2,
5502
+ failureSignature: "fresh-generated-deck-visible-text",
5503
+ failureSummary: "acceptance failed: deck omits source-grounded phrase: single reader",
5504
+ });
5505
+ await fs.writeFile(
5506
+ path.join(workspace, "TASK.md"),
5507
+ "Treat source_brief.md, measurements.csv, prompt.txt, and TASK.md as immutable.\n",
5508
+ "utf8"
5509
+ );
5510
+ const failedAfterProducerPacket = await buildFailedTestRecoveryPacket(
5511
+ {
5512
+ provider: "deepseek",
5513
+ taskProfile: "slides",
5514
+ commandCwd: workspace,
5515
+ goal: failedAfterProducerState.goal,
5516
+ },
5517
+ failedAfterProducerState
5518
+ );
5519
+ assert(
5520
+ JSON.stringify(failedAfterProducerPacket.repairPaths) ===
5521
+ JSON.stringify(["build_deck.py"]),
5522
+ "a fresh generated-artifact failure dropped its latest mutable producer or retained an explicitly immutable input"
5523
+ );
5524
+ failedAfterProducerState.meta.failedTestRecoveryPacket = {
5525
+ packetVersion: 15,
5526
+ content: failedAfterProducerPacket.content,
5527
+ paths: failedAfterProducerPacket.paths,
5528
+ repairPaths: failedAfterProducerPacket.repairPaths,
5529
+ mutationRevision: 10,
5530
+ failureSignature: "fresh-generated-deck-visible-text",
5531
+ generatedAt: "2026-08-27T19:05:01.000Z",
5532
+ };
5533
+ const failedAfterProducerRuntime = nextStepRuntimeConfig(
5534
+ {
5535
+ provider: "deepseek",
5536
+ taskProfile: "slides",
5537
+ commandCwd: workspace,
5538
+ goal: failedAfterProducerState.goal,
5539
+ },
5540
+ failedAfterProducerState
5541
+ );
5542
+ assert(
5543
+ JSON.stringify(failedAfterProducerRuntime.testFailureRepairContextPaths) ===
5544
+ JSON.stringify(["build_deck.py"]),
5545
+ "failed-test recovery forced immutable evidence reads instead of grounding the canonical producer"
5546
+ );
5488
5547
  const immutableOnlyRepairState = {
5489
5548
  goal: "Treat service_ctl.py as immutable read-only source evidence and finish from existing results.",
5490
5549
  meta: {
@@ -70,6 +70,24 @@ const wrappedImmutableSourceContract = deriveScsTaskContract({
70
70
  taskProfile: "slides",
71
71
  });
72
72
 
73
+ const actionWrappedImmutableSourceContract = deriveScsTaskContract({
74
+ goal: [
75
+ "Continue the exact task. Do not",
76
+ "modify source_brief.md, measurements.csv, prompt.txt, or TASK.md.",
77
+ "Repair build_deck.py and rebuild output/deck.pptx.",
78
+ ].join("\n"),
79
+ taskProfile: "slides",
80
+ });
81
+
82
+ const pathWrappedImmutableSourceContract = deriveScsTaskContract({
83
+ goal: [
84
+ "Continue the exact task. Do not modify",
85
+ "source_brief.md, measurements.csv, prompt.txt, or TASK.md.",
86
+ "Repair build_deck.py and rebuild output/deck.pptx.",
87
+ ].join("\n"),
88
+ taskProfile: "slides",
89
+ });
90
+
73
91
  const recoveryInstructionContract = deriveScsTaskContract({
74
92
  goal: [
75
93
  "Use the retained source and these two failures: the tests invoke ../service_ctl.py, while `python3 service_ctl.py start --state-dir .runtime` fails. Preserve the lifecycle assertions rather than replacing them, repair service_ctl.py, and remove the accidental untracked resume-after-git-baseline-recovery-dev-prompt.txt.",
@@ -173,6 +191,16 @@ assert(
173
191
  ),
174
192
  "an immutable source path leaked into exact output requirements"
175
193
  );
194
+ for (const contract of [
195
+ actionWrappedImmutableSourceContract,
196
+ pathWrappedImmutableSourceContract,
197
+ ]) {
198
+ assert.deepEqual(
199
+ contract.excludedOutputPaths.sort(),
200
+ ["TASK.md", "measurements.csv", "prompt.txt", "source_brief.md"].sort(),
201
+ "a negative action or its governed path list lost protection across a line wrap"
202
+ );
203
+ }
176
204
  assert(
177
205
  recoveryInstructionContract.excludedOutputPaths.includes("resume-after-git-baseline-recovery-dev-prompt.txt") &&
178
206
  !recoveryInstructionContract.exactOutputPaths.includes("resume-after-git-baseline-recovery-dev-prompt.txt"),
@@ -4085,6 +4085,7 @@ async function applyContinuationPrompt(state, config, observers) {
4085
4085
  packetVersion: FAILED_TEST_RECOVERY_PACKET_VERSION,
4086
4086
  content: retainedTestEvidence.content,
4087
4087
  paths: retainedTestEvidence.paths,
4088
+ repairPaths: retainedTestEvidence.repairPaths,
4088
4089
  mutationRevision: Number(currentFailure?.mutationRevision || 0),
4089
4090
  failureSignature: String(currentFailure?.failureSignature || ""),
4090
4091
  command: String(currentFailure?.command || ""),
@@ -6624,6 +6625,64 @@ function safeRecoveryEvidencePath(value = "") {
6624
6625
  return PLAIN_TEXT_FILE_EXTENSIONS.has(path.extname(candidate).toLowerCase()) ? candidate : "";
6625
6626
  }
6626
6627
 
6628
+ function failedTestMutationRepairPaths(
6629
+ config = {},
6630
+ state = {},
6631
+ testRun = {},
6632
+ excludedPaths = []
6633
+ ) {
6634
+ const verification = state.meta?.projectVerification || {};
6635
+ const history = Array.isArray(verification.mutationHistory)
6636
+ ? verification.mutationHistory
6637
+ : verification.lastMutation
6638
+ ? [verification.lastMutation]
6639
+ : [];
6640
+ const maximumRevision = Math.max(
6641
+ 0,
6642
+ Number(testRun?.mutationRevision ?? verification.mutationRevision ?? 0)
6643
+ );
6644
+ const taskGoal = String(
6645
+ state.meta?.goalContract?.taskGoal || state.goal || config.goal || ""
6646
+ ).trim();
6647
+ const activeTaskHash = taskGoal ? hashForLog(taskGoal) : "";
6648
+ const repairPaths = [];
6649
+ for (const mutation of [...history].reverse()) {
6650
+ if (
6651
+ Number(mutation?.revision || 0) > maximumRevision ||
6652
+ !["apply_patch", "write_file"].includes(String(mutation?.toolName || "")) ||
6653
+ (activeTaskHash && mutation?.taskHash && mutation.taskHash !== activeTaskHash)
6654
+ ) {
6655
+ continue;
6656
+ }
6657
+ for (const candidate of Array.isArray(mutation?.paths) ? mutation.paths : []) {
6658
+ const safePath = safeRecoveryEvidencePath(candidate);
6659
+ if (
6660
+ !safePath ||
6661
+ pathLooksLikeTestSource(safePath) ||
6662
+ isPrivateVerificationEvidencePath(safePath) ||
6663
+ filterExplicitlyExcludedOutputPaths([safePath], excludedPaths).length === 0 ||
6664
+ repairPaths.includes(safePath)
6665
+ ) {
6666
+ continue;
6667
+ }
6668
+ repairPaths.push(safePath);
6669
+ if (repairPaths.length >= 6) return repairPaths;
6670
+ }
6671
+ }
6672
+ return repairPaths;
6673
+ }
6674
+
6675
+ function failedTestCanonicalRepairPaths(state = {}) {
6676
+ const packet = state.meta?.failedTestRecoveryPacket || {};
6677
+ const preferred = Array.isArray(packet.repairPaths) && packet.repairPaths.length
6678
+ ? packet.repairPaths
6679
+ : packet.paths;
6680
+ return (Array.isArray(preferred) ? preferred : [])
6681
+ .map(safeRecoveryEvidencePath)
6682
+ .filter(Boolean)
6683
+ .filter((item, index, items) => items.indexOf(item) === index);
6684
+ }
6685
+
6627
6686
  function recoveryEvidenceDependencies(sourcePath = "", content = "") {
6628
6687
  const dependencies = [];
6629
6688
  const append = (candidate) => {
@@ -6984,8 +7043,17 @@ export async function buildFailedTestRecoveryPacket(config = {}, state = {}) {
6984
7043
  ]
6985
7044
  .map(safeRecoveryEvidencePath)
6986
7045
  .filter(Boolean);
7046
+ const mutationRepairPaths = failedTestMutationRepairPaths(
7047
+ config,
7048
+ state,
7049
+ testRun,
7050
+ taskContract.excludedOutputPaths || []
7051
+ );
6987
7052
  const mutationEvidencePaths = new Set(
6988
- (Array.isArray(verification.lastMutation?.paths) ? verification.lastMutation.paths : [])
7053
+ [
7054
+ ...mutationRepairPaths,
7055
+ ...(Array.isArray(verification.lastMutation?.paths) ? verification.lastMutation.paths : []),
7056
+ ]
6989
7057
  .map(safeRecoveryEvidencePath)
6990
7058
  .filter(Boolean)
6991
7059
  );
@@ -7476,8 +7544,33 @@ export async function buildFailedTestRecoveryPacket(config = {}, state = {}) {
7476
7544
  at: new Date().toISOString(),
7477
7545
  focuses: diagnosticFocuses,
7478
7546
  };
7547
+ const evidencePaths = [...seen].filter((item) =>
7548
+ excerpts.some((excerpt) => excerpt.startsWith(`### ${item}\n`))
7549
+ );
7550
+ const diagnosticRepairPaths = diagnosticFocuses
7551
+ .map((focus) => safeRecoveryEvidencePath(focus?.path))
7552
+ .filter(Boolean);
7553
+ const preferredRepairPaths = [
7554
+ ...diagnosticRepairPaths,
7555
+ ...mutationRepairPaths,
7556
+ ]
7557
+ .filter((item, index, items) => items.indexOf(item) === index)
7558
+ .filter((item) => evidencePaths.includes(item));
7559
+ const fallbackRepairPaths = evidencePaths
7560
+ .filter((item) => !pathLooksLikeTestSource(item))
7561
+ .filter(
7562
+ (item) =>
7563
+ filterExplicitlyExcludedOutputPaths(
7564
+ [item],
7565
+ taskContract.excludedOutputPaths || []
7566
+ ).length > 0
7567
+ );
7479
7568
  return {
7480
- paths: [...seen].filter((item) => excerpts.some((excerpt) => excerpt.startsWith(`### ${item}\n`))),
7569
+ paths: evidencePaths,
7570
+ repairPaths: (preferredRepairPaths.length
7571
+ ? preferredRepairPaths
7572
+ : fallbackRepairPaths
7573
+ ).slice(0, 6),
7481
7574
  content: [
7482
7575
  `Bounded failed-test evidence packet v${FAILED_TEST_RECOVERY_PACKET_VERSION}. These are exact current workspace excerpts selected from the discovered test and its local dependencies. Use them to calculate the producing transformation; do not restart broad discovery.`,
7483
7576
  testRun.command ? `Verification command: ${testRun.command}` : "",
@@ -11676,9 +11769,7 @@ export function nextStepRuntimeConfig(config = {}, state = {}) {
11676
11769
  );
11677
11770
  });
11678
11771
  const recoveryPacketPaths = currentRecoveryPacket
11679
- ? (Array.isArray(state.meta?.failedTestRecoveryPacket?.paths)
11680
- ? state.meta.failedTestRecoveryPacket.paths
11681
- : [])
11772
+ ? failedTestCanonicalRepairPaths(state)
11682
11773
  .map(safeRecoveryEvidencePath)
11683
11774
  .filter(Boolean)
11684
11775
  .filter((item, index, items) => items.indexOf(item) === index)
@@ -13420,9 +13511,7 @@ function requiredDeclarationIdentitiesForPatch(state = {}, targetPath = "") {
13420
13511
  }
13421
13512
 
13422
13513
  function requiredSymbolRepairPath(state = {}, owner = "") {
13423
- const sourcePaths = (state.meta?.failedTestRecoveryPacket?.paths || [])
13424
- .map((item) => safeRecoveryEvidencePath(item))
13425
- .filter(Boolean)
13514
+ const sourcePaths = failedTestCanonicalRepairPaths(state)
13426
13515
  .filter((item) => !/(?:^|\/)tests?(?:\/|$)/i.test(item));
13427
13516
  const ownerBasename = String(owner || "")
13428
13517
  .split(".")
@@ -16542,7 +16631,7 @@ async function recordToolContractViolation({
16542
16631
  const completedRequestedPaths = requestedCalls
16543
16632
  .map((call) => call.path)
16544
16633
  .filter((item) => item && completedArtifacts.has(item));
16545
- const repairPaths = (state.meta?.failedTestRecoveryPacket?.paths || [])
16634
+ const repairPaths = failedTestCanonicalRepairPaths(state)
16546
16635
  .map((item) => String(item || "").replace(/\\/g, "/"))
16547
16636
  .filter((item) => item && !/(?:^|\/)tests?(?:\/|$)/i.test(item))
16548
16637
  .slice(0, 6);
@@ -17423,9 +17512,7 @@ export function recoverUnavailableVerificationRerunAsCanonicalRead(
17423
17512
  ...(Array.isArray(config.testFailureRepairPatchTargets)
17424
17513
  ? config.testFailureRepairPatchTargets.map((target) => target?.path)
17425
17514
  : []),
17426
- ...(Array.isArray(state.meta?.failedTestRecoveryPacket?.paths)
17427
- ? state.meta.failedTestRecoveryPacket.paths
17428
- : []),
17515
+ ...failedTestCanonicalRepairPaths(state),
17429
17516
  ]
17430
17517
  .map(safeRecoveryEvidencePath)
17431
17518
  .filter(Boolean)
@@ -19210,6 +19297,7 @@ async function runAgentOnceUnlocked(config) {
19210
19297
  packetVersion: FAILED_TEST_RECOVERY_PACKET_VERSION,
19211
19298
  content: recoveryEvidence.content,
19212
19299
  paths: recoveryEvidence.paths,
19300
+ repairPaths: recoveryEvidence.repairPaths,
19213
19301
  mutationRevision: Number(currentFailure.mutationRevision || 0),
19214
19302
  failureSignature: String(currentFailure.failureSignature || ""),
19215
19303
  command: String(currentFailure.command || ""),
@@ -20488,6 +20576,7 @@ async function runAgentOnceUnlocked(config) {
20488
20576
  packetVersion: FAILED_TEST_RECOVERY_PACKET_VERSION,
20489
20577
  content: recoveryEvidence.content,
20490
20578
  paths: recoveryEvidence.paths,
20579
+ repairPaths: recoveryEvidence.repairPaths,
20491
20580
  mutationRevision: Number(currentFailure.mutationRevision || 0),
20492
20581
  failureSignature: String(currentFailure.failureSignature || ""),
20493
20582
  command: String(currentFailure.command || ""),
@@ -542,12 +542,26 @@ export function filterExplicitlyExcludedOutputPaths(paths = [], exclusions = [])
542
542
  }
543
543
 
544
544
  export function inferExplicitlyExcludedOutputPaths(goal = "") {
545
+ const extensionPattern = "md|txt|json|jsonl|ndjson|ya?ml|html|css|js|ts|tsx|jsx|py|sh|csv|tex|svg|png|jpe?g|webp|mp4|mov|pdf|docx";
545
546
  // Preserve coordinated path lists that wrap after a comma. Prompt and task
546
547
  // files commonly format "do not modify a, b,\nc, or d" across lines; splitting
547
548
  // that text first drops the governing negative action from the continuation.
548
- const source = String(goal || "").replace(/([,,、])\s*\r?\n\s*/gu, "$1 ");
549
+ const negativePrefix = "(?:do\\s+not|don't|dont|must\\s+not|should\\s+not|never)";
550
+ const negativeAction = "(?:run|rerun|re-run|execut(?:e|ed|ing)|creat(?:e|ed|ing)|recreat(?:e|ed|ing)|writ(?:e|ten|ing)|generat(?:e|ed|ing)|sav(?:e|ed|ing)|output|touch|modif(?:y|ied|ying)|edit(?:ed|ing)?|stage|commit)";
551
+ const wrappedNegativeAction = new RegExp(
552
+ `(\\b${negativePrefix}\\b)\\s*\\r?\\n\\s*(?=${negativeAction}\\b)`,
553
+ "giu"
554
+ );
555
+ const wrappedNegativePath = new RegExp(
556
+ `(\\b${negativePrefix}\\b[^.!?。!?;;\\n]{0,180}\\b${negativeAction}\\b)\\s*\\r?\\n\\s*` +
557
+ `(?=\\S{1,260}\\.(?:${extensionPattern})\\b)`,
558
+ "giu"
559
+ );
560
+ const source = String(goal || "")
561
+ .replace(/([,,、])\s*\r?\n\s*/gu, "$1 ")
562
+ .replace(wrappedNegativeAction, "$1 ")
563
+ .replace(wrappedNegativePath, "$1 ");
549
564
  if (!source.trim()) return [];
550
- const extensionPattern = "md|txt|json|jsonl|ndjson|ya?ml|html|css|js|ts|tsx|jsx|py|sh|csv|tex|svg|png|jpe?g|webp|mp4|mov|pdf|docx";
551
565
  const pathPattern = new RegExp(
552
566
  '((?:~|\\.{1,2}|/|[A-Za-z0-9_\\-\\u4e00-\\u9fff])[\\w./~\\-\\u4e00-\\u9fff]{0,260}\\.(?:' +
553
567
  extensionPattern +