@lazyingart/agintiflow 0.20.258 → 0.20.260

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.260",
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,114 @@ 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
+ );
2653
+ const refreshedAcceptanceState = {
2654
+ commandCwd: workspace,
2655
+ meta: {
2656
+ projectVerification: {
2657
+ requiredOutputs: ["stale-output.txt"],
2658
+ requiredCommands: [
2659
+ "python3 service_ctl.py start --state-dir .runtime",
2660
+ "python3 service_ctl.py status --state-dir .runtime",
2661
+ ],
2662
+ acceptanceSource: "README.md",
2663
+ },
2664
+ },
2665
+ };
2666
+ recordProjectVerificationOutcome(
2667
+ refreshedAcceptanceState,
2668
+ {
2669
+ ok: true,
2670
+ toolName: "read_file",
2671
+ path: "README.md",
2672
+ content: operatorGuideMarkdown,
2673
+ },
2674
+ { commandCwd: workspace, taskProfile: "devops" }
2675
+ );
2676
+ assert(
2677
+ JSON.stringify(refreshedAcceptanceState.meta.projectVerification.requiredCommands) ===
2678
+ JSON.stringify(["python3 -m unittest discover -s tests -v"]) &&
2679
+ refreshedAcceptanceState.meta.projectVerification.requiredOutputs.length === 0,
2680
+ "rereading one authoritative source retained its stale acceptance requirements"
2681
+ );
2682
+ const resumedAcceptanceWorkspace = path.join(workspace, "resumed-acceptance");
2683
+ await fs.mkdir(resumedAcceptanceWorkspace, { recursive: true });
2684
+ await fs.writeFile(
2685
+ path.join(resumedAcceptanceWorkspace, "README.md"),
2686
+ operatorGuideMarkdown,
2687
+ "utf8"
2688
+ );
2689
+ const resumedAcceptanceState = {
2690
+ commandCwd: resumedAcceptanceWorkspace,
2691
+ goal: "Repair the service and run its tests.",
2692
+ meta: {
2693
+ goalContract: { revision: 4, currentRequest: "Repair the service and run its tests." },
2694
+ projectVerification: {
2695
+ requiredCommands: [
2696
+ "python3 service_ctl.py start --state-dir .runtime",
2697
+ "python3 service_ctl.py status --state-dir .runtime",
2698
+ ],
2699
+ acceptanceSource: "README.md",
2700
+ },
2701
+ },
2702
+ };
2703
+ resetSameTaskExecutionContract(resumedAcceptanceState, 4);
2704
+ assert(
2705
+ JSON.stringify(resumedAcceptanceState.meta.projectVerification.requiredCommands) ===
2706
+ JSON.stringify(["python3 -m unittest discover -s tests -v"]),
2707
+ "same-task resume retained stale requirements from an older README parser"
2708
+ );
2709
+ recordProjectVerificationOutcome(
2710
+ refreshedAcceptanceState,
2711
+ {
2712
+ ok: true,
2713
+ toolName: "read_file",
2714
+ path: "TASK.md",
2715
+ content: requiredCommandMarkdown,
2716
+ },
2717
+ { commandCwd: workspace, taskProfile: "devops" }
2718
+ );
2719
+ assert(
2720
+ JSON.stringify(refreshedAcceptanceState.meta.projectVerification.requiredCommands) ===
2721
+ JSON.stringify([
2722
+ "python3 -m unittest discover -s tests -v",
2723
+ "npm run check",
2724
+ "npm test",
2725
+ "python scripts/verify.py --strict",
2726
+ ]),
2727
+ "source-scoped acceptance refresh discarded a distinct authoritative source"
2728
+ );
2621
2729
  const operatorContinuedCommandMarkdown = [
2622
2730
  "# Task",
2623
2731
  "",
@@ -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,
@@ -3769,6 +3769,67 @@ export function resetGoalScopedRuntimeState(state = {}) {
3769
3769
  return removed;
3770
3770
  }
3771
3771
 
3772
+ function refreshPersistedProjectAcceptance(state = {}) {
3773
+ const verification = state.meta?.projectVerification;
3774
+ if (!verification || typeof verification !== "object") return false;
3775
+ const priorBySource =
3776
+ verification.acceptanceBySource &&
3777
+ typeof verification.acceptanceBySource === "object" &&
3778
+ !Array.isArray(verification.acceptanceBySource)
3779
+ ? verification.acceptanceBySource
3780
+ : {};
3781
+ const sources = [
3782
+ ...Object.keys(priorBySource),
3783
+ String(verification.acceptanceSource || "").trim(),
3784
+ ].filter(Boolean);
3785
+ if (!sources.length) return false;
3786
+
3787
+ const commandCwd = path.resolve(state.commandCwd || process.cwd());
3788
+ const refreshed = {};
3789
+ let inspected = 0;
3790
+ for (const source of [...new Set(sources)].slice(-16)) {
3791
+ const sourceKey = normalizedProjectAcceptancePath(source, commandCwd);
3792
+ if (!sourceKey || !projectAcceptanceSourceIsAuthoritative(sourceKey, {
3793
+ commandCwd,
3794
+ authoritativePaths: [sourceKey],
3795
+ })) {
3796
+ continue;
3797
+ }
3798
+ const absolutePath = path.resolve(commandCwd, sourceKey);
3799
+ if (absolutePath !== commandCwd && !absolutePath.startsWith(`${commandCwd}${path.sep}`)) continue;
3800
+ inspected += 1;
3801
+ if (!fsSync.existsSync(absolutePath)) continue;
3802
+ try {
3803
+ const acceptance = projectAcceptanceFromMarkdown(
3804
+ fsSync.readFileSync(absolutePath, "utf8"),
3805
+ sourceKey,
3806
+ { commandCwd, authoritativePaths: [sourceKey] }
3807
+ );
3808
+ refreshed[sourceKey] = {
3809
+ requiredOutputs: acceptance.requiredOutputs,
3810
+ requiredCommands: acceptance.requiredCommands,
3811
+ readAt: new Date().toISOString(),
3812
+ };
3813
+ } catch {
3814
+ inspected -= 1;
3815
+ }
3816
+ }
3817
+ if (!inspected) return false;
3818
+ verification.acceptanceBySource = refreshed;
3819
+ verification.requiredOutputs = [
3820
+ ...new Set(
3821
+ Object.values(refreshed).flatMap((item) => item.requiredOutputs || [])
3822
+ ),
3823
+ ].slice(0, 64);
3824
+ verification.requiredCommands = [
3825
+ ...new Set(
3826
+ Object.values(refreshed).flatMap((item) => item.requiredCommands || [])
3827
+ ),
3828
+ ].slice(0, 24);
3829
+ verification.acceptanceRefreshedAt = new Date().toISOString();
3830
+ return true;
3831
+ }
3832
+
3772
3833
  export function resetSameTaskExecutionContract(state = {}, revision = 0) {
3773
3834
  state.meta = state.meta || {};
3774
3835
  const keys = [
@@ -3786,6 +3847,7 @@ export function resetSameTaskExecutionContract(state = {}, revision = 0) {
3786
3847
  removed.push(key);
3787
3848
  }
3788
3849
  state.plan = "";
3850
+ refreshPersistedProjectAcceptance(state);
3789
3851
  const activeRevision = Math.max(0, Number(revision || state.meta?.goalContract?.revision || 0));
3790
3852
  const currentRequest = String(state.meta?.goalContract?.currentRequest || state.goal || "").trim();
3791
3853
  const currentTurnContract = deriveScsTaskContract({
@@ -5281,20 +5343,59 @@ function canonicalRequiredFenceCommand(value = "") {
5281
5343
  );
5282
5344
  }
5283
5345
 
5346
+ function markdownFenceRequiresCommandExecution(content = "", fenceIndex = 0) {
5347
+ const lines = String(content || "")
5348
+ .slice(0, Math.max(0, Number(fenceIndex || 0)))
5349
+ .split(/\r?\n/);
5350
+ while (lines.length && !lines.at(-1).trim()) lines.pop();
5351
+ if (!lines.length) return false;
5352
+
5353
+ const nearest = String(lines.at(-1) || "").trim();
5354
+ const heading = nearest.match(/^#{1,6}\s+(.+?)\s*#*$/);
5355
+ if (heading) {
5356
+ return /\b(?:acceptance|tests?|validation|verification)\b|(?:验收|驗收|测试|測試|验证|驗證)|(?:受入|テスト|検証)/iu.test(
5357
+ heading[1]
5358
+ );
5359
+ }
5360
+
5361
+ const paragraph = [];
5362
+ while (lines.length && paragraph.length < 5) {
5363
+ const line = String(lines.pop() || "").trim();
5364
+ if (!line || /^#{1,6}\s+/.test(line) || /^```/.test(line)) break;
5365
+ paragraph.unshift(line);
5366
+ }
5367
+ const cue = paragraph.join(" ").trim();
5368
+ if (!cue) return false;
5369
+
5370
+ const execution = /\b(?:commands?|execute|invoke|launch|regenerate|run|tests?|validate|validation|verify|verification)\b/iu.test(
5371
+ cue
5372
+ );
5373
+ const obligation = /\b(?:before\s+completion|must|required|shall|should)\b/iu.test(cue);
5374
+ const directImperative = /^(?:please\s+)?(?:execute|invoke|launch|regenerate|run|validate|verify)\b/iu.test(cue);
5375
+ const validationLead = /^(?:to\s+(?:check|test|validate|verify)\b|(?:required|mandatory)\s+(?:checks?|commands?|tests?|validation|verification)\b)/iu.test(
5376
+ cue
5377
+ );
5378
+ const cjkExecution = /(?:运行|運行|执行|執行|验证|驗證|检查|檢查|测试|測試|验收|驗收|実行|検証|確認|テスト)/u.test(cue);
5379
+ const cjkObligation = /(?:必须|必須|需要|应当|應當|完成前|完了前)/u.test(cue);
5380
+ const cjkDirectImperative = /^(?:请|請)?(?:运行|運行|执行|執行|验证|驗證|检查|檢查|测试|測試|验收|驗收|実行|検証|確認|テスト)/u.test(
5381
+ cue
5382
+ );
5383
+ return (
5384
+ (execution && obligation) ||
5385
+ directImperative ||
5386
+ validationLead ||
5387
+ (cjkExecution && cjkObligation) ||
5388
+ cjkDirectImperative
5389
+ );
5390
+ }
5391
+
5284
5392
  function markdownRequiredCommands(content = "") {
5285
5393
  const text = String(content || "");
5286
5394
  const commands = [];
5287
5395
  for (const match of text.matchAll(/```([A-Za-z0-9_-]*)[ \t]*\n([\s\S]*?)```/gi)) {
5288
5396
  const language = String(match[1] || "").toLowerCase();
5289
5397
  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
- }
5398
+ if (!markdownFenceRequiresCommandExecution(text, match.index)) continue;
5298
5399
  const body = String(match[2] || "");
5299
5400
  const fenceCommandStart = commands.length;
5300
5401
  const context = [];
@@ -5342,11 +5443,9 @@ function normalizedProjectAcceptancePath(sourcePath = "", commandCwd = "") {
5342
5443
  return raw.replace(/\\/g, "/").replace(/^\.\//, "");
5343
5444
  }
5344
5445
 
5345
- export function projectAcceptanceFromMarkdown(content = "", sourcePath = "", options = {}) {
5446
+ function projectAcceptanceSourceIsAuthoritative(sourcePath = "", options = {}) {
5346
5447
  const basename = path.basename(String(sourcePath || "")).toLowerCase();
5347
- if (!/^(?:readme|task|agents?|aginti)(?:\.[^.]+)?$/.test(basename)) {
5348
- return { requiredOutputs: [], requiredCommands: [] };
5349
- }
5448
+ if (!/^(?:readme|task|agents?|aginti)(?:\.[^.]+)?$/.test(basename)) return false;
5350
5449
  const normalizedSource = normalizedProjectAcceptancePath(
5351
5450
  sourcePath,
5352
5451
  options.commandCwd
@@ -5356,10 +5455,11 @@ export function projectAcceptanceFromMarkdown(content = "", sourcePath = "", opt
5356
5455
  .map((item) => normalizedProjectAcceptancePath(item, options.commandCwd))
5357
5456
  .filter(Boolean)
5358
5457
  );
5359
- if (
5360
- normalizedSource.includes("/") &&
5361
- !authoritativePaths.has(normalizedSource)
5362
- ) {
5458
+ return !normalizedSource.includes("/") || authoritativePaths.has(normalizedSource);
5459
+ }
5460
+
5461
+ export function projectAcceptanceFromMarkdown(content = "", sourcePath = "", options = {}) {
5462
+ if (!projectAcceptanceSourceIsAuthoritative(sourcePath, options)) {
5363
5463
  return { requiredOutputs: [], requiredCommands: [] };
5364
5464
  }
5365
5465
  return {
@@ -5739,29 +5839,72 @@ export function recordProjectVerificationOutcome(state = {}, toolResult = {}, co
5739
5839
  goal: completionContractGoal(config, state),
5740
5840
  taskProfile: config.taskProfile || state.meta?.taskProfile || "auto",
5741
5841
  });
5842
+ const sourcePath = String(toolResult.path || toolResult.args?.path || "");
5843
+ const acceptanceOptions = {
5844
+ commandCwd: config.commandCwd || state.commandCwd || process.cwd(),
5845
+ authoritativePaths: [
5846
+ ...(Array.isArray(currentTaskContract.exactInputPaths)
5847
+ ? currentTaskContract.exactInputPaths
5848
+ : []),
5849
+ ...(Array.isArray(currentTaskContract.exactOutputPaths)
5850
+ ? currentTaskContract.exactOutputPaths
5851
+ : []),
5852
+ ],
5853
+ };
5742
5854
  const acceptance = projectAcceptanceFromMarkdown(
5743
5855
  toolResult.content,
5744
- toolResult.path || toolResult.args?.path || "",
5745
- {
5746
- commandCwd: config.commandCwd || state.commandCwd || process.cwd(),
5747
- authoritativePaths: [
5748
- ...(Array.isArray(currentTaskContract.exactInputPaths)
5749
- ? currentTaskContract.exactInputPaths
5750
- : []),
5751
- ...(Array.isArray(currentTaskContract.exactOutputPaths)
5752
- ? currentTaskContract.exactOutputPaths
5753
- : []),
5754
- ],
5755
- }
5856
+ sourcePath,
5857
+ acceptanceOptions
5756
5858
  );
5757
- verification.requiredOutputs = [
5758
- ...new Set([...verification.requiredOutputs, ...acceptance.requiredOutputs]),
5759
- ].slice(0, 64);
5760
- verification.requiredCommands = [
5761
- ...new Set([...verification.requiredCommands, ...acceptance.requiredCommands]),
5762
- ].slice(0, 24);
5763
- if (acceptance.requiredOutputs.length || acceptance.requiredCommands.length) {
5764
- verification.acceptanceSource = String(toolResult.path || toolResult.args?.path || "");
5859
+ if (projectAcceptanceSourceIsAuthoritative(sourcePath, acceptanceOptions)) {
5860
+ const sourceKey = normalizedProjectAcceptancePath(
5861
+ sourcePath,
5862
+ acceptanceOptions.commandCwd
5863
+ );
5864
+ const acceptanceBySource =
5865
+ verification.acceptanceBySource &&
5866
+ typeof verification.acceptanceBySource === "object" &&
5867
+ !Array.isArray(verification.acceptanceBySource)
5868
+ ? { ...verification.acceptanceBySource }
5869
+ : {};
5870
+ const legacySourceKey = normalizedProjectAcceptancePath(
5871
+ verification.acceptanceSource || "",
5872
+ acceptanceOptions.commandCwd
5873
+ );
5874
+ if (
5875
+ !Object.keys(acceptanceBySource).length &&
5876
+ legacySourceKey &&
5877
+ legacySourceKey !== sourceKey
5878
+ ) {
5879
+ acceptanceBySource[legacySourceKey] = {
5880
+ requiredOutputs: [...verification.requiredOutputs],
5881
+ requiredCommands: [...verification.requiredCommands],
5882
+ readAt: verification.acceptanceReadAt || "",
5883
+ };
5884
+ }
5885
+ acceptanceBySource[sourceKey] = {
5886
+ requiredOutputs: acceptance.requiredOutputs,
5887
+ requiredCommands: acceptance.requiredCommands,
5888
+ readAt: now,
5889
+ };
5890
+ verification.acceptanceBySource = Object.fromEntries(
5891
+ Object.entries(acceptanceBySource).slice(-16)
5892
+ );
5893
+ verification.requiredOutputs = [
5894
+ ...new Set(
5895
+ Object.values(verification.acceptanceBySource).flatMap((item) =>
5896
+ Array.isArray(item?.requiredOutputs) ? item.requiredOutputs : []
5897
+ )
5898
+ ),
5899
+ ].slice(0, 64);
5900
+ verification.requiredCommands = [
5901
+ ...new Set(
5902
+ Object.values(verification.acceptanceBySource).flatMap((item) =>
5903
+ Array.isArray(item?.requiredCommands) ? item.requiredCommands : []
5904
+ )
5905
+ ),
5906
+ ].slice(0, 24);
5907
+ verification.acceptanceSource = sourcePath;
5765
5908
  verification.acceptanceReadAt = now;
5766
5909
  }
5767
5910
  }
@@ -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
  };