@lazyingart/agintiflow 0.20.258 → 0.20.259

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.258",
3
+ "version": "0.20.259",
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",
@@ -2618,6 +2618,38 @@ try {
2618
2618
  JSON.stringify(["npm test"]),
2619
2619
  "console output lines were mistaken for required shell commands"
2620
2620
  );
2621
+ const operatorGuideMarkdown = [
2622
+ "# Service",
2623
+ "",
2624
+ "The controller must provide start, status, restart, and stop.",
2625
+ "",
2626
+ "## Operator Guidance",
2627
+ "",
2628
+ "### Start the service",
2629
+ "",
2630
+ "```bash",
2631
+ "python3 service_ctl.py start --state-dir .runtime",
2632
+ "```",
2633
+ "",
2634
+ "### Check service status",
2635
+ "",
2636
+ "```bash",
2637
+ "python3 service_ctl.py status --state-dir .runtime",
2638
+ "```",
2639
+ "",
2640
+ "## Running Tests",
2641
+ "",
2642
+ "Run the visible regression suite with:",
2643
+ "",
2644
+ "```bash",
2645
+ "python3 -m unittest discover -s tests -v",
2646
+ "```",
2647
+ ].join("\n");
2648
+ assert(
2649
+ JSON.stringify(projectAcceptanceFromMarkdown(operatorGuideMarkdown, "README.md").requiredCommands) ===
2650
+ JSON.stringify(["python3 -m unittest discover -s tests -v"]),
2651
+ "ordinary operator examples became mandatory acceptance commands"
2652
+ );
2621
2653
  const operatorContinuedCommandMarkdown = [
2622
2654
  "# Task",
2623
2655
  "",
@@ -60,6 +60,14 @@ const coordinatedForbiddenOutputContract = deriveScsTaskContract({
60
60
  taskProfile: "devops",
61
61
  });
62
62
 
63
+ const recoveryInstructionContract = deriveScsTaskContract({
64
+ goal: [
65
+ "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.",
66
+ "Then run `python3 -m unittest discover -s tests -v`, followed by `PYTHONDONTWRITEBYTECODE=1 python3 /tmp/devops_sensor_gateway_contract.py`. Do not use LocalLLM or change provider.",
67
+ ].join("\n"),
68
+ taskProfile: "devops",
69
+ });
70
+
63
71
  const readOnlyReviewContract = deriveScsTaskContract({
64
72
  goal: [
65
73
  "Review focus: changed files only.",
@@ -136,6 +144,33 @@ assert.deepEqual(
136
144
  ["scratch.py", "temporary.py"],
137
145
  "a coordinated list did not retain each path governed by one exclusion"
138
146
  );
147
+ assert(
148
+ recoveryInstructionContract.excludedOutputPaths.includes("resume-after-git-baseline-recovery-dev-prompt.txt") &&
149
+ !recoveryInstructionContract.exactOutputPaths.includes("resume-after-git-baseline-recovery-dev-prompt.txt"),
150
+ "an explicit deletion target became a required output"
151
+ );
152
+ assert.deepEqual(
153
+ recoveryInstructionContract.requiredTextTerms,
154
+ [],
155
+ "verification commands became required document prose"
156
+ );
157
+ assert.deepEqual(
158
+ recoveryInstructionContract.requiredExecutableTerms,
159
+ [],
160
+ "an environment assignment inside a verification command became required production source"
161
+ );
162
+ assert(
163
+ !recoveryInstructionContract.exactInputPaths.some((item) => item.includes("PYTHONDONTWRITEBYTECODE")),
164
+ "a quoted verification command became an input path"
165
+ );
166
+ assert.deepEqual(
167
+ recoveryInstructionContract.requiredProjectCommands,
168
+ [
169
+ "python3 -m unittest discover -s tests -v",
170
+ "PYTHONDONTWRITEBYTECODE=1 python3 /tmp/devops_sensor_gateway_contract.py",
171
+ ],
172
+ "a verification command introduced by 'followed by' was not retained"
173
+ );
139
174
  assert.equal(
140
175
  readOnlyReviewContract.requiresWorkspaceMutation,
141
176
  false,
@@ -5281,20 +5281,59 @@ function canonicalRequiredFenceCommand(value = "") {
5281
5281
  );
5282
5282
  }
5283
5283
 
5284
+ function markdownFenceRequiresCommandExecution(content = "", fenceIndex = 0) {
5285
+ const lines = String(content || "")
5286
+ .slice(0, Math.max(0, Number(fenceIndex || 0)))
5287
+ .split(/\r?\n/);
5288
+ while (lines.length && !lines.at(-1).trim()) lines.pop();
5289
+ if (!lines.length) return false;
5290
+
5291
+ const nearest = String(lines.at(-1) || "").trim();
5292
+ const heading = nearest.match(/^#{1,6}\s+(.+?)\s*#*$/);
5293
+ if (heading) {
5294
+ return /\b(?:acceptance|tests?|validation|verification)\b|(?:验收|驗收|测试|測試|验证|驗證)|(?:受入|テスト|検証)/iu.test(
5295
+ heading[1]
5296
+ );
5297
+ }
5298
+
5299
+ const paragraph = [];
5300
+ while (lines.length && paragraph.length < 5) {
5301
+ const line = String(lines.pop() || "").trim();
5302
+ if (!line || /^#{1,6}\s+/.test(line) || /^```/.test(line)) break;
5303
+ paragraph.unshift(line);
5304
+ }
5305
+ const cue = paragraph.join(" ").trim();
5306
+ if (!cue) return false;
5307
+
5308
+ const execution = /\b(?:commands?|execute|invoke|launch|regenerate|run|tests?|validate|validation|verify|verification)\b/iu.test(
5309
+ cue
5310
+ );
5311
+ const obligation = /\b(?:before\s+completion|must|required|shall|should)\b/iu.test(cue);
5312
+ const directImperative = /^(?:please\s+)?(?:execute|invoke|launch|regenerate|run|validate|verify)\b/iu.test(cue);
5313
+ const validationLead = /^(?:to\s+(?:check|test|validate|verify)\b|(?:required|mandatory)\s+(?:checks?|commands?|tests?|validation|verification)\b)/iu.test(
5314
+ cue
5315
+ );
5316
+ const cjkExecution = /(?:运行|運行|执行|執行|验证|驗證|检查|檢查|测试|測試|验收|驗收|実行|検証|確認|テスト)/u.test(cue);
5317
+ const cjkObligation = /(?:必须|必須|需要|应当|應當|完成前|完了前)/u.test(cue);
5318
+ const cjkDirectImperative = /^(?:请|請)?(?:运行|運行|执行|執行|验证|驗證|检查|檢查|测试|測試|验收|驗收|実行|検証|確認|テスト)/u.test(
5319
+ cue
5320
+ );
5321
+ return (
5322
+ (execution && obligation) ||
5323
+ directImperative ||
5324
+ validationLead ||
5325
+ (cjkExecution && cjkObligation) ||
5326
+ cjkDirectImperative
5327
+ );
5328
+ }
5329
+
5284
5330
  function markdownRequiredCommands(content = "") {
5285
5331
  const text = String(content || "");
5286
5332
  const commands = [];
5287
5333
  for (const match of text.matchAll(/```([A-Za-z0-9_-]*)[ \t]*\n([\s\S]*?)```/gi)) {
5288
5334
  const language = String(match[1] || "").toLowerCase();
5289
5335
  if (language && !["bash", "sh", "shell", "console"].includes(language)) continue;
5290
- const before = text.slice(Math.max(0, Number(match.index || 0) - 420), Number(match.index || 0));
5291
- if (
5292
- !/(?:run|running|execute|command|verify|validation|regenerate)[^\n.]{0,180}(?:must|required|should|use|run|regenerate)|(?:必须|需要|应当|运行|执行|验证)[^。\n]{0,180}(?:命令|生成|输出|交付)/i.test(
5293
- before
5294
- )
5295
- ) {
5296
- continue;
5297
- }
5336
+ if (!markdownFenceRequiresCommandExecution(text, match.index)) continue;
5298
5337
  const body = String(match[2] || "");
5299
5338
  const fenceCommandStart = commands.length;
5300
5339
  const context = [];
@@ -326,6 +326,56 @@ function quotedTerms(text = "") {
326
326
  return terms;
327
327
  }
328
328
 
329
+ function looksLikeShellCommandLiteral(value = "") {
330
+ const text = String(value || "").trim();
331
+ if (!text || /[\r\n]/.test(text)) return false;
332
+ const command = text.replace(/^(?:[A-Za-z_][A-Za-z0-9_]*=[^\s]+\s+)+/, "");
333
+ const tokens = tokenizeShellWords(command);
334
+ if (!tokens.length) return false;
335
+ const executable = path.basename(String(tokens[0] || "")).toLowerCase();
336
+ return new Set([
337
+ "aginti",
338
+ "bash",
339
+ "bun",
340
+ "cargo",
341
+ "cmake",
342
+ "curl",
343
+ "dotnet",
344
+ "ffmpeg",
345
+ "git",
346
+ "gh",
347
+ "go",
348
+ "java",
349
+ "javac",
350
+ "latexmk",
351
+ "make",
352
+ "node",
353
+ "npm",
354
+ "npx",
355
+ "perl",
356
+ "php",
357
+ "pnpm",
358
+ "pytest",
359
+ "python",
360
+ "python3",
361
+ "ruby",
362
+ "sh",
363
+ "wget",
364
+ "xelatex",
365
+ "yarn",
366
+ "zsh",
367
+ ]).has(executable);
368
+ }
369
+
370
+ function indexFallsInsideInlineCommand(source = "", index = 0) {
371
+ for (const match of String(source || "").matchAll(/`([^`\r\n]+)`/g)) {
372
+ const start = Number(match.index || 0);
373
+ const end = start + String(match[0] || "").length;
374
+ if (index >= start && index < end && looksLikeShellCommandLiteral(match[1])) return true;
375
+ }
376
+ return false;
377
+ }
378
+
329
379
  function splitInlineTerms(text = "") {
330
380
  return String(text || "")
331
381
  .split(/[、,,;;]/)
@@ -515,6 +565,10 @@ export function inferExplicitlyExcludedOutputPaths(goal = "") {
515
565
  /(?:不要|不得|禁止|无需|不需要)[^。!?;\n]{0,140}(?:运行|执行|重跑|创建|建立|写入|生成|保存|输出|修改|编辑|提交|暂存)/u;
516
566
  const cjkNegativeActionAfter =
517
567
  /^(?:(?:不得|禁止|不要)(?:被)?(?:运行|执行|重跑|创建|建立|写入|生成|保存|输出|修改|编辑|提交|暂存)|(?:を)?(?:作成|生成|実行|再実行|保存|編集|変更|コミット)[^。!?;\n]{0,40}(?:しない|しなくてよい|してはいけない))/u;
568
+ const directRemovalBefore =
569
+ /\b(?:remove|delete|unlink|discard)\s+(?:(?:the|an?|this|that)\s+)?(?:(?:accidental|stale|temporary|untracked|generated|obsolete|old|private|empty)\s+)*(?:file\s+)?$/i;
570
+ const cjkDirectRemovalBefore =
571
+ /(?:删除|刪除|移除|清除)(?:(?:这个|這個|该|該|意外的|暂存的|暫存的|临时的|臨時的|未跟踪的|未追蹤的|旧的|舊的|私有的)\s*)*(?:文件)?\s*$/u;
518
572
  const excluded = [];
519
573
  for (const clause of source.split(/[;;\n]|(?<=[.!?。!?])\s+/u)) {
520
574
  pathPattern.lastIndex = 0;
@@ -545,7 +599,9 @@ export function inferExplicitlyExcludedOutputPaths(goal = "") {
545
599
  negativeActionAfter.test(after) ||
546
600
  keepAbsent.test(`${before}${after}`) ||
547
601
  cjkNegativeActionBefore.test(before) ||
548
- cjkNegativeActionAfter.test(after)
602
+ cjkNegativeActionAfter.test(after) ||
603
+ directRemovalBefore.test(before) ||
604
+ cjkDirectRemovalBefore.test(before)
549
605
  );
550
606
  previousExcluded = directExclusion || coordinatedWithExcludedPrevious;
551
607
  if (previousExcluded) {
@@ -655,7 +711,13 @@ function inferRequiredTextTerms(goal = "") {
655
711
  }
656
712
  // A quoted filename in "save as `report.md`" is an output location, not
657
713
  // required prose inside that report. Path existence is validated separately.
658
- return uniqueLimited(terms.filter((term) => !outputPathTerms.has(String(term).trim())), 24);
714
+ return uniqueLimited(
715
+ terms.filter((term) => {
716
+ const cleaned = String(term).trim();
717
+ return !outputPathTerms.has(cleaned) && !looksLikeShellCommandLiteral(cleaned);
718
+ }),
719
+ 24
720
+ );
659
721
  }
660
722
 
661
723
  const EXECUTABLE_SOURCE_EXTENSIONS = new Set([
@@ -701,6 +763,7 @@ export function inferRequiredExecutableTerms(goal = "") {
701
763
  for (const match of source.matchAll(assignmentPattern)) {
702
764
  const index = Number(match.index || 0);
703
765
  if (executableRequirementIsNegated(source, index)) continue;
766
+ if (indexFallsInsideInlineCommand(source, index)) continue;
704
767
  const window = source.slice(Math.max(0, index - 180), Math.min(source.length, index + match[0].length + 220));
705
768
  const implementationRequirement =
706
769
  /\b(?:actual|canonical|executable|implementation|source|code|call|argument|keyword|parameter|repair|fix|correct|replace|add|set|pass|use|must|required)\b/iu.test(window) ||
@@ -1316,9 +1379,9 @@ function prefixRequestsInlineCommandExecution(prefix = "") {
1316
1379
  while (preamble.test(clause)) clause = clause.replace(preamble, "").trim();
1317
1380
  clause = clause.replace(/(?:[::]|--?)\s*$/, "").trim();
1318
1381
  return (
1319
- /^(?:run|rerun|re-run|execute|invoke|launch|verify|validate|check|confirm)(?:\s+(?:(?:the|this|that)\s+)?(?:following\s+)?command(?:\s+named)?)?\s*$/i.test(
1382
+ /^(?:followed\s+by|run|rerun|re-run|execute|invoke|launch|verify|validate|check|confirm)(?:\s+(?:(?:the|this|that)\s+)?(?:following\s+)?command(?:\s+named)?)?\s*$/i.test(
1320
1383
  clause
1321
- ) || /^(?:运行|運行|执行|執行|调用|調用|验证|驗證|检查|檢查|确认|確認)\s*$/.test(clause)
1384
+ ) || /^(?:随后运行|隨後運行|接着运行|接著運行|运行|運行|执行|執行|调用|調用|验证|驗證|检查|檢查|确认|確認)\s*$/.test(clause)
1322
1385
  );
1323
1386
  }
1324
1387
 
@@ -1408,6 +1471,7 @@ function inferExplicitRequestedCommands(goal = "") {
1408
1471
 
1409
1472
  export function deriveScsTaskContract({ goal = "", taskProfile = "", acceptanceCriteria = [] } = {}) {
1410
1473
  const evidenceGoal = scopedChatopsEvidenceGoal(goal, taskProfile);
1474
+ const positiveEvidenceGoal = stripForbiddenLanguage(evidenceGoal);
1411
1475
  const artifactRoot = scopedArtifactRoot(goal);
1412
1476
  const requirementCategories = inferRequirementCategories(evidenceGoal, taskProfile, acceptanceCriteria);
1413
1477
  const requiredToolCalls = inferRequiredToolCalls(evidenceGoal);
@@ -1431,7 +1495,7 @@ export function deriveScsTaskContract({ goal = "", taskProfile = "", acceptanceC
1431
1495
  excludedOutputPaths
1432
1496
  );
1433
1497
  const exactInputPaths = filterExplicitlyExcludedOutputPaths(
1434
- inferExactInputPaths(evidenceGoal),
1498
+ inferExactInputPaths(positiveEvidenceGoal),
1435
1499
  excludedOutputPaths
1436
1500
  ).filter((item) => !inferredOutputPaths.includes(item) && !exactOutputPaths.includes(item));
1437
1501
  const declaredSourceRoots = inferDeclaredSourceRoots(evidenceGoal);
@@ -1455,8 +1519,8 @@ export function deriveScsTaskContract({ goal = "", taskProfile = "", acceptanceC
1455
1519
  requiresWorkspaceMutation: goalRequestsWorkspaceMutation(evidenceGoal, taskProfile),
1456
1520
  requiresFileMutation: goalRequestsFileMutation(evidenceGoal, taskProfile),
1457
1521
  requiresSourceGrounding: requiresSourceGrounding(evidenceGoal),
1458
- requiredTextTerms: inferRequiredTextTerms(evidenceGoal),
1459
- requiredExecutableTerms: inferRequiredExecutableTerms(evidenceGoal),
1522
+ requiredTextTerms: inferRequiredTextTerms(positiveEvidenceGoal),
1523
+ requiredExecutableTerms: inferRequiredExecutableTerms(positiveEvidenceGoal),
1460
1524
  forbiddenTextTerms: inferForbiddenTextTerms(evidenceGoal),
1461
1525
  successCriteria: unique(acceptanceCriteria).slice(0, 10),
1462
1526
  };