@lazyingart/agintiflow 0.20.265 → 0.20.267

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.265",
3
+ "version": "0.20.267",
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",
@@ -159,6 +159,12 @@ try {
159
159
  assert(defaultMaxStepsForProfile("pipeline") >= 44, "pipeline profile step budget is too low for repair/verify/resume loops");
160
160
  assert(!/misleading failing test/i.test(qaProfile.prompt), "QA profile still encourages misleading test fixtures");
161
161
  assert(/do not stage fake bugs/i.test(qaProfile.prompt), "QA profile does not discourage fake staged failures");
162
+ const slidesProfile = listTaskProfiles().find((profile) => profile.id === "slides");
163
+ assert(slidesProfile, "slides profile is missing");
164
+ assert(/source-grounded editable slide source/i.test(slidesProfile.prompt), "slides profile does not require grounded editable source");
165
+ assert(/render every slide/i.test(slidesProfile.prompt), "slides profile does not require full rendered inspection");
166
+ assert(/wrapped-title decoration overlap/i.test(slidesProfile.prompt), "slides profile does not guard wrapped-title collisions");
167
+ assert(/fresh git status --short/i.test(slidesProfile.prompt), "slides profile does not require fresh repository evidence");
162
168
  assert(
163
169
  capabilities.trustedDockerPolicy.some((check) => check.command.startsWith("apt-get install") && check.allowed),
164
170
  "trusted Docker policy did not allow apt-get install"
@@ -5306,6 +5306,153 @@ try {
5306
5306
  postMutationVerificationRuntime.testVerificationCommand === postMutationVerifier,
5307
5307
  "a material failed-test repair did not advance directly to its exact retained verifier"
5308
5308
  );
5309
+ const generatedDeckValidator =
5310
+ "python3 /tmp/presentation_deck_contract.py --root .";
5311
+ const staleGeneratedDeckState = {
5312
+ goal: [
5313
+ "Rebuild the canonical presentation output after repairing build_deck.py.",
5314
+ "Do not modify source_brief.md, measurements.csv,",
5315
+ "prompt.txt, or TASK.md.",
5316
+ `Run ${generatedDeckValidator} only after the generated deck is fresh.`,
5317
+ ].join("\n"),
5318
+ meta: {
5319
+ taskProfile: "slides",
5320
+ goalContract: {
5321
+ revision: 13,
5322
+ currentRequest: "Rebuild the canonical presentation output from build_deck.py.",
5323
+ },
5324
+ activeExecutionContract: {
5325
+ revision: 13,
5326
+ startedMutationRevision: 8,
5327
+ materialMutationRevision: 9,
5328
+ requiresFileMutation: true,
5329
+ requiresSourceGrounding: true,
5330
+ },
5331
+ projectVerification: {
5332
+ mutationRevision: 9,
5333
+ mutationHistory: [
5334
+ { revision: 8, toolName: "run_command", paths: [] },
5335
+ { revision: 9, toolName: "apply_patch", paths: ["build_deck.py"] },
5336
+ ],
5337
+ commandRuns: [{
5338
+ command:
5339
+ 'rm -rf dist && echo "removed dist" && python3 build_deck.py && ls -la output',
5340
+ at: "2026-08-27T18:18:14.726Z",
5341
+ ok: true,
5342
+ mutationRevision: 8,
5343
+ privateMutationRevision: 0,
5344
+ }],
5345
+ testRuns: [{
5346
+ command: generatedDeckValidator,
5347
+ at: "2026-08-27T18:24:28.347Z",
5348
+ mutationRevision: 9,
5349
+ privateMutationRevision: 0,
5350
+ passed: false,
5351
+ failureEvidenceVersion: 2,
5352
+ failureSignature: "stale-generated-deck",
5353
+ failureSummary: "acceptance failed: deck omits source-grounded phrase: single reader",
5354
+ }],
5355
+ },
5356
+ },
5357
+ };
5358
+ const staleGeneratedDeckRuntime = nextStepRuntimeConfig(
5359
+ {
5360
+ provider: "deepseek",
5361
+ taskProfile: "slides",
5362
+ commandCwd: workspace,
5363
+ goal: staleGeneratedDeckState.goal,
5364
+ },
5365
+ staleGeneratedDeckState
5366
+ );
5367
+ const staleGeneratedDeckPhase = buildKnownConstrainedPhasePlan(
5368
+ {
5369
+ provider: "deepseek",
5370
+ taskProfile: "slides",
5371
+ commandCwd: workspace,
5372
+ goal: staleGeneratedDeckState.goal,
5373
+ },
5374
+ staleGeneratedDeckState,
5375
+ staleGeneratedDeckRuntime
5376
+ );
5377
+ assert(
5378
+ staleGeneratedDeckRuntime.generatedArtifactProducerPending === true &&
5379
+ staleGeneratedDeckRuntime.generatedArtifactProducerCommand === "python3 build_deck.py" &&
5380
+ staleGeneratedDeckPhase?.mode === "generated-artifact-producer" &&
5381
+ staleGeneratedDeckPhase?.command === "python3 build_deck.py",
5382
+ `a stale generated artifact did not recover its exact safe producer before validation: ${JSON.stringify(
5383
+ staleGeneratedDeckRuntime
5384
+ )}`
5385
+ );
5386
+ recordProjectVerificationOutcome(
5387
+ staleGeneratedDeckState,
5388
+ {
5389
+ toolName: "run_command",
5390
+ ok: true,
5391
+ exitCode: 0,
5392
+ args: { command: "python3 build_deck.py" },
5393
+ stdout: "Wrote output/deck.pptx\n",
5394
+ stderr: "",
5395
+ },
5396
+ {
5397
+ provider: "deepseek",
5398
+ taskProfile: "slides",
5399
+ commandCwd: workspace,
5400
+ goal: staleGeneratedDeckState.goal,
5401
+ allowShellTool: true,
5402
+ sandboxMode: "host",
5403
+ }
5404
+ );
5405
+ const postProducerRuntime = nextStepRuntimeConfig(
5406
+ {
5407
+ provider: "deepseek",
5408
+ taskProfile: "slides",
5409
+ commandCwd: workspace,
5410
+ goal: staleGeneratedDeckState.goal,
5411
+ },
5412
+ staleGeneratedDeckState
5413
+ );
5414
+ assert(
5415
+ staleGeneratedDeckState.meta.projectVerification.mutationRevision === 10 &&
5416
+ postProducerRuntime.generatedArtifactProducerPending !== true &&
5417
+ postProducerRuntime.testVerificationPending === true &&
5418
+ postProducerRuntime.testVerificationCommand === generatedDeckValidator,
5419
+ `a successful producer replay did not advance exactly once to fresh validation: ${JSON.stringify({
5420
+ verification: staleGeneratedDeckState.meta.projectVerification,
5421
+ activeExecutionContract: staleGeneratedDeckState.meta.activeExecutionContract,
5422
+ runtime: postProducerRuntime,
5423
+ })}`
5424
+ );
5425
+ const immutableOnlyRepairState = {
5426
+ goal: "Treat service_ctl.py as immutable read-only source evidence and finish from existing results.",
5427
+ meta: {
5428
+ taskProfile: "devops",
5429
+ projectVerification: {
5430
+ mutationRevision: 0,
5431
+ mutationHistory: [],
5432
+ commandRuns: [],
5433
+ testRuns: [],
5434
+ },
5435
+ completionEvidenceRepair: {
5436
+ key: "protected-source-only",
5437
+ at: "2026-08-27T19:00:00.000Z",
5438
+ requiresFreshFileMutation: true,
5439
+ requiredFreshMutationRevision: 1,
5440
+ },
5441
+ toolLoop: { recent: [] },
5442
+ },
5443
+ };
5444
+ assert(
5445
+ nextStepRuntimeConfig(
5446
+ {
5447
+ provider: "deepseek",
5448
+ taskProfile: "devops",
5449
+ commandCwd: workspace,
5450
+ goal: immutableOnlyRepairState.goal,
5451
+ },
5452
+ immutableOnlyRepairState
5453
+ ).completionFreshMutationRequired !== true,
5454
+ "completion recovery forced a mutation when every concrete candidate was immutable"
5455
+ );
5309
5456
  const concreteGoalUpdate = applyContinuationContractTransition(
5310
5457
  concreteContinuationState,
5311
5458
  concreteContinuation,
@@ -1747,6 +1747,28 @@ sameNames(
1747
1747
  "failed-test repair did not receive the bounded diagnose-patch-retest tool surface"
1748
1748
  );
1749
1749
 
1750
+ const generatedArtifactProducerTools = selectProgressiveTools(allTools, {
1751
+ config: {
1752
+ provider: "localllm",
1753
+ testFailureRepairActive: true,
1754
+ testFailureRepairMutationRequired: true,
1755
+ generatedArtifactProducerPending: true,
1756
+ generatedArtifactProducerCommand: "python3 build_deck.py",
1757
+ },
1758
+ goal: "Rebuild the generated presentation before rerunning its validator.",
1759
+ profile: "slides",
1760
+ });
1761
+ sameNames(
1762
+ generatedArtifactProducerTools,
1763
+ ["run_command", "finish"],
1764
+ "a stale generated artifact did not expose only its retained producer command"
1765
+ );
1766
+ assertStrict.deepEqual(
1767
+ generatedArtifactProducerTools[0].function.parameters.properties.command.enum,
1768
+ ["python3 build_deck.py"],
1769
+ "the generated-artifact producer command was not schema-constrained"
1770
+ );
1771
+
1750
1772
  const mutationOnlyFailedTestRepairTools = selectProgressiveTools(allTools, {
1751
1773
  config: {
1752
1774
  provider: "localllm",
@@ -60,6 +60,16 @@ const coordinatedForbiddenOutputContract = deriveScsTaskContract({
60
60
  taskProfile: "devops",
61
61
  });
62
62
 
63
+ const wrappedImmutableSourceContract = deriveScsTaskContract({
64
+ goal: [
65
+ "Continue the exact task. Do not modify source_brief.md, measurements.csv,",
66
+ "prompt.txt, or TASK.md.",
67
+ "Treat source_brief.md, measurements.csv, prompt.txt, and TASK.md as immutable read-only source evidence.",
68
+ "Repair build_deck.py and rebuild output/deck.pptx.",
69
+ ].join("\n"),
70
+ taskProfile: "slides",
71
+ });
72
+
63
73
  const recoveryInstructionContract = deriveScsTaskContract({
64
74
  goal: [
65
75
  "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.",
@@ -152,6 +162,17 @@ assert.deepEqual(
152
162
  ["scratch.py", "temporary.py"],
153
163
  "a coordinated list did not retain each path governed by one exclusion"
154
164
  );
165
+ assert.deepEqual(
166
+ wrappedImmutableSourceContract.excludedOutputPaths.sort(),
167
+ ["TASK.md", "measurements.csv", "prompt.txt", "source_brief.md"].sort(),
168
+ "a wrapped immutable source list lost one or more protected paths"
169
+ );
170
+ assert(
171
+ !wrappedImmutableSourceContract.exactOutputPaths.some((item) =>
172
+ ["TASK.md", "measurements.csv", "prompt.txt", "source_brief.md"].includes(item)
173
+ ),
174
+ "an immutable source path leaked into exact output requirements"
175
+ );
155
176
  assert(
156
177
  recoveryInstructionContract.excludedOutputPaths.includes("resume-after-git-baseline-recovery-dev-prompt.txt") &&
157
178
  !recoveryInstructionContract.exactOutputPaths.includes("resume-after-git-baseline-recovery-dev-prompt.txt"),
@@ -115,6 +115,11 @@ assert(selectedIds("write SQL migrations for sqlite schema").includes("database"
115
115
  assert(selectedIds("debug Docker deployment logs and port config").includes("devops-deployment"), "devops prompt did not select devops-deployment");
116
116
  assert(selectedIds("review auth security and secrets handling").includes("security-review"), "security prompt did not select security-review");
117
117
  assert(selectedIds("make a PowerPoint pitch deck").includes("presentation-slides"), "slides prompt did not select presentation-slides");
118
+ const presentationSkill = skills.find((skill) => skill.id === "presentation-slides");
119
+ assert(presentationSkill?.body.includes("Render every slide"), "presentation skill does not require every slide to be rendered");
120
+ assert(presentationSkill?.body.includes("wrapped titles"), "presentation skill does not require wrapped-title inspection");
121
+ assert(presentationSkill?.body.includes("git status --short"), "presentation skill does not require final repository evidence");
122
+ assert(presentationSkill?.body.includes("Do not call the deck complete"), "presentation skill still permits build-only completion");
118
123
  assert(selectedIds("edit a markdown screenplay final draft").includes("writing-editing"), "writing prompt did not select writing-editing");
119
124
  assert(selectedIds("create a lesson with exercises and quiz").includes("education-tutorial"), "education prompt did not select education-tutorial");
120
125
  assert(selectedIds("review this PR architecture without editing").includes("code-review"), "review prompt did not select code-review");
@@ -20,7 +20,17 @@ tools:
20
20
  ---
21
21
  # Slides And Presentations
22
22
 
23
- Clarify audience, goal, length, and tone from context. Build a durable outline before slide text. Keep slides visually sparse: one message, one figure/table/story per slide when possible.
23
+ Infer audience, goal, length, and tone from the request and available project context. Ask only when a missing fact materially changes the deck. Build a durable outline before slide text. Keep slides visually sparse: one message and usually one figure, table, or story per slide.
24
24
 
25
- Use markdown, HTML, LaTeX beamer, PPTX tooling, or available local converters depending on the workspace. Save source plus exported artifacts when possible.
25
+ Use the workspace's established presentation tooling when it exists. Otherwise choose editable PPTX, HTML, Markdown, or LaTeX Beamer tooling that can be rebuilt locally. Keep essential titles, claims, labels, citations, and body text editable. Image generation may supply bounded visual assets, but never use one generated bitmap as a complete slide or slide background.
26
26
 
27
+ Ground claims and calculations in the supplied sources. Preserve a reproducible source or build script and speaker notes when they improve delivery. Produce only the requested artifacts, with descriptive stable filenames. If the user supplied an exact validator or acceptance command, run that exact command after the final rebuild.
28
+
29
+ Before completion:
30
+
31
+ 1. Rebuild the final deck and every requested export from the current source.
32
+ 2. Render every slide to a PNG or equivalent preview and inspect the actual images. Check especially wrapped titles, accent rules, clipping, collisions, overflow, unreadably small text, charts, tables, and consistent framing.
33
+ 3. Verify that the PPTX or source remains editable, exported files open, slide and PDF page counts agree, calculations match the source data, and no unsupported claims were introduced.
34
+ 4. In a Git repository, if the task requests a commit, stage intentional source and deliverables, narrowly ignore only transient build or perception evidence, commit the result, then run a fresh `git status --short`.
35
+
36
+ Do not call the deck complete from a successful build alone. Artifact paths, model-generated visual descriptions, or an earlier clean status are not substitutes for current rendered inspection and final external verification.
@@ -2157,7 +2157,13 @@ export function buildKnownConstrainedPhasePlan(
2157
2157
  runtimeConfig = nextStepRuntimeConfig(config, state)
2158
2158
  ) {
2159
2159
  const repositoryStateRepair = runtimeConfig.testFailureRepositoryStateRepair === true;
2160
- if (runtimeConfig.testFailureRepairActive === true && !repositoryStateRepair) return null;
2160
+ const generatedArtifactProducer =
2161
+ runtimeConfig.generatedArtifactProducerPending === true;
2162
+ if (
2163
+ runtimeConfig.testFailureRepairActive === true &&
2164
+ !repositoryStateRepair &&
2165
+ !generatedArtifactProducer
2166
+ ) return null;
2161
2167
 
2162
2168
  const freshSourceMutation = runtimeConfig.completionFreshMutationRequired === true;
2163
2169
  const verificationPending = runtimeConfig.testVerificationPending === true;
@@ -2181,6 +2187,7 @@ export function buildKnownConstrainedPhasePlan(
2181
2187
  if (
2182
2188
  !repositoryStateRepair &&
2183
2189
  !freshSourceMutation &&
2190
+ !generatedArtifactProducer &&
2184
2191
  !verificationPending &&
2185
2192
  !requiredProjectCommandPending &&
2186
2193
  !verifiedCompletion &&
@@ -2191,19 +2198,22 @@ export function buildKnownConstrainedPhasePlan(
2191
2198
  }
2192
2199
 
2193
2200
  const command = String(
2194
- requiredProjectCommandPending
2195
- ? runtimeConfig.requiredProjectCommand || ""
2196
- : verificationPending
2197
- ? runtimeConfig.testVerificationCommand || ""
2198
- : repositoryStateRepair
2199
- ? runtimeConfig.testFailureCommand || ""
2200
- : runtimeConfig.verifiedCompletionCommand || ""
2201
+ generatedArtifactProducer
2202
+ ? runtimeConfig.generatedArtifactProducerCommand || ""
2203
+ : requiredProjectCommandPending
2204
+ ? runtimeConfig.requiredProjectCommand || ""
2205
+ : verificationPending
2206
+ ? runtimeConfig.testVerificationCommand || ""
2207
+ : repositoryStateRepair
2208
+ ? runtimeConfig.testFailureCommand || ""
2209
+ : runtimeConfig.verifiedCompletionCommand || ""
2201
2210
  ).trim();
2202
2211
  if (
2203
2212
  !verifiedCompletion &&
2204
2213
  !artifactCommitPending &&
2205
2214
  !taskOwnedCommitPending &&
2206
2215
  !freshSourceMutation &&
2216
+ !generatedArtifactProducer &&
2207
2217
  !command
2208
2218
  ) return null;
2209
2219
 
@@ -2211,6 +2221,8 @@ export function buildKnownConstrainedPhasePlan(
2211
2221
  ? "repository-state-repair"
2212
2222
  : freshSourceMutation
2213
2223
  ? "fresh-source-mutation"
2224
+ : generatedArtifactProducer
2225
+ ? "generated-artifact-producer"
2214
2226
  : requiredProjectCommandPending
2215
2227
  ? "required-project-command"
2216
2228
  : verificationPending
@@ -2250,6 +2262,12 @@ export function buildKnownConstrainedPhasePlan(
2250
2262
  "2. Preserve unrelated current behavior and do not edit private verification evidence.",
2251
2263
  "3. After the mutation succeeds, rerun the retained validation and complete required Git actions.",
2252
2264
  ].join("\n")
2265
+ : generatedArtifactProducer
2266
+ ? [
2267
+ `1. Run the exact retained local producer command now: ${command}`,
2268
+ "2. Rebuild generated artifacts from the latest canonical source mutation; do not rerun the stale validator first or substitute another command.",
2269
+ "3. After the producer succeeds, run the exact retained validator and repair only from any fresh concrete failure.",
2270
+ ].join("\n")
2253
2271
  : artifactCommitPending || taskOwnedCommitPending
2254
2272
  ? [
2255
2273
  "1. Use the offered commit_project_changes tool once; its path scope comes from recorded task-owned mutations.",
@@ -2281,6 +2299,8 @@ export function buildKnownConstrainedPhasePlan(
2281
2299
  ? runtimeConfig.completionFreshMutationNeedsSourceRead === true
2282
2300
  ? "Completion was rejected because a fresh canonical source correction is still missing. Read one exact offered project file now; command, test, Git, and finish actions remain intentionally unavailable until the source is grounded and materially patched."
2283
2301
  : "Completion was rejected because a fresh canonical source correction is still missing. Use the offered path-bounded apply_patch tool now. Do not substitute another read-only inspection, test rerun, Git command, private verifier edit, or finish claim."
2302
+ : generatedArtifactProducer
2303
+ ? "A canonical producer source changed after the last successful build. Run only the exact retained local producer command now so validation observes fresh artifacts; do not rerun the stale validator or invent another source edit."
2284
2304
  : artifactCommitPending
2285
2305
  ? "The exact artifact and current source changes already passed deterministic checks. Only the required local commit is missing. Call commit_project_changes with a concise factual subject, then finish; do not restart discovery or validation."
2286
2306
  : taskOwnedCommitPending
@@ -6030,6 +6050,9 @@ export function recordProjectVerificationOutcome(state = {}, toolResult = {}, co
6030
6050
  toolResult.blocked !== true &&
6031
6051
  commandCanMutateProjectContent(mutationCommand, commandPolicy)
6032
6052
  );
6053
+ const generatedArtifactProducer = projectContentMutation
6054
+ ? safeProjectProducerSegment(command, config)
6055
+ : "";
6033
6056
  let requiredBatch = currentRequiredCommandBatch(verification, requiredCommands);
6034
6057
  const activeExecutionContract = state.meta?.activeExecutionContract;
6035
6058
  const activeTurnCommands =
@@ -6086,6 +6109,21 @@ export function recordProjectVerificationOutcome(state = {}, toolResult = {}, co
6086
6109
  paths: [],
6087
6110
  commandCategory: String(commandPolicy.category || "general-shell"),
6088
6111
  }, config);
6112
+ if (
6113
+ generatedArtifactProducer &&
6114
+ Number(activeExecutionContract?.revision || 0) ===
6115
+ Number(state.meta?.goalContract?.revision || 0)
6116
+ ) {
6117
+ activeExecutionContract.materialMutationRevision = verification.mutationRevision;
6118
+ activeExecutionContract.materialMutationCommands = [
6119
+ ...new Set([
6120
+ ...(Array.isArray(activeExecutionContract.materialMutationCommands)
6121
+ ? activeExecutionContract.materialMutationCommands
6122
+ : []),
6123
+ generatedArtifactProducer,
6124
+ ]),
6125
+ ].slice(0, 12);
6126
+ }
6089
6127
  }
6090
6128
  const run = {
6091
6129
  command,
@@ -6096,6 +6134,7 @@ export function recordProjectVerificationOutcome(state = {}, toolResult = {}, co
6096
6134
  ...(requiredBatch?.id ? { requiredCommandBatchId: requiredBatch.id } : {}),
6097
6135
  ...(requiredCommand ? { requiredProjectCommand: requiredCommand } : {}),
6098
6136
  ...(exitProbe.present ? { explicitExitStatus: exitProbe.status } : {}),
6137
+ ...(generatedArtifactProducer ? { generatedArtifactProducer } : {}),
6099
6138
  };
6100
6139
  if (requiredCommand && commandSucceeded) {
6101
6140
  if (!requiredBatch && requiredMutatingCommands.length === 0) {
@@ -10415,6 +10454,139 @@ function completionFreshMutationCandidatePaths(state = {}, config = {}) {
10415
10454
  return selected.slice(0, 16);
10416
10455
  }
10417
10456
 
10457
+ function commandSegmentHasProducerIntent(command = "") {
10458
+ const normalized = normalizeProjectCommand(command);
10459
+ const tokens = tokenizeShellWords(normalized);
10460
+ if (!tokens.length) return false;
10461
+ let index = 0;
10462
+ while (/^[A-Za-z_][A-Za-z0-9_]*=/.test(String(tokens[index] || ""))) {
10463
+ index += 1;
10464
+ }
10465
+ const executable = path.posix.basename(
10466
+ String(tokens[index] || "").replace(/\\/g, "/")
10467
+ ).toLocaleLowerCase("en-US");
10468
+ const args = tokens.slice(index + 1);
10469
+ const rejectedProducerName =
10470
+ /(?:^|[_-])(?:acceptance|audit|check|lint|smoke|spec|test|validat(?:e|or|ion)?|verif(?:y|ier|ication)?)(?:[_-]|$)/i;
10471
+ const producerName =
10472
+ /(?:^|[_-])(?:build|bundle|compile|deck|export|generat(?:e|or)|package|presentation|regen(?:erate)?|render|report|slides?)(?:[_-]|$)/i;
10473
+
10474
+ if (["python", "python3", "node", "ruby", "bash", "sh"].some((name) =>
10475
+ executable === name || executable.startsWith(`${name}.`)
10476
+ )) {
10477
+ const scriptIndex = args[0] === "-m" ? 1 : 0;
10478
+ const scriptName = path.posix.basename(
10479
+ String(args[scriptIndex] || "").replace(/\\/g, "/")
10480
+ ).replace(/\.[A-Za-z0-9]{1,8}$/u, "");
10481
+ return Boolean(
10482
+ scriptName &&
10483
+ producerName.test(scriptName) &&
10484
+ !rejectedProducerName.test(scriptName)
10485
+ );
10486
+ }
10487
+
10488
+ if (["npm", "pnpm", "yarn", "bun"].includes(executable)) {
10489
+ const script = String(
10490
+ args[0] === "run" ? args[1] : args[0]
10491
+ ).toLocaleLowerCase("en-US");
10492
+ return Boolean(
10493
+ script && producerName.test(script) && !rejectedProducerName.test(script)
10494
+ );
10495
+ }
10496
+ if (["make", "ninja", "latexmk", "pdflatex", "xelatex", "lualatex", "openscad"].includes(executable)) {
10497
+ return true;
10498
+ }
10499
+ if (executable === "pandoc") return args.some((arg) => ["-o", "--output"].includes(arg));
10500
+ if (executable === "typst") return args[0] === "compile";
10501
+ if (executable === "cmake") return args.includes("--build");
10502
+ if (executable === "meson") return ["compile", "install"].includes(args[0]);
10503
+ if (["cargo", "go", "dotnet"].includes(executable)) return args[0] === "build";
10504
+ return Boolean(
10505
+ executable &&
10506
+ producerName.test(executable.replace(/\.[A-Za-z0-9]{1,8}$/u, "")) &&
10507
+ !rejectedProducerName.test(executable)
10508
+ );
10509
+ }
10510
+
10511
+ function safeProjectProducerSegment(command = "", config = {}) {
10512
+ const normalized = normalizeProjectCommand(
10513
+ normalizeCommandForPolicy(command, config)
10514
+ );
10515
+ const unwrapped = parseNonMutatingExitStatusWrapper(normalized)?.command || normalized;
10516
+ const sequence = parseTopLevelShellSequence(unwrapped);
10517
+ if (
10518
+ !sequence.commands.length ||
10519
+ sequence.openQuote ||
10520
+ sequence.trailingEscape ||
10521
+ sequence.trailingSeparator
10522
+ ) {
10523
+ return "";
10524
+ }
10525
+ for (const rawSegment of sequence.commands) {
10526
+ const segment = normalizeProjectCommand(rawSegment);
10527
+ if (!segment || !commandSegmentHasProducerIntent(segment)) continue;
10528
+ const policy = classifyCommand(segment);
10529
+ if (
10530
+ policy.hardBlocked === true ||
10531
+ policy.needsNetwork === true ||
10532
+ ["blocked", "destructive", "external-write", "git-remote", "git-workflow", "package-install"].includes(
10533
+ String(policy.category || "")
10534
+ ) ||
10535
+ isSubstantiveTestCommand(segment, config) ||
10536
+ !commandCanMutateProjectContent(segment, policy)
10537
+ ) {
10538
+ continue;
10539
+ }
10540
+ return segment;
10541
+ }
10542
+ return "";
10543
+ }
10544
+
10545
+ function pendingGeneratedArtifactProducerCommand(
10546
+ state = {},
10547
+ config = {},
10548
+ verification = {},
10549
+ currentFailedTest = null
10550
+ ) {
10551
+ if (!currentFailedTest || currentFailedTest.passed === true) return "";
10552
+ if (failedTestRequiresCleanRepositoryState(currentFailedTest)) return "";
10553
+ const context = [
10554
+ completionContractGoal(config, state),
10555
+ state.meta?.taskProfile || config.taskProfile || "",
10556
+ currentFailedTest.failureSummary || "",
10557
+ ].join("\n");
10558
+ if (
10559
+ !/(?:\b(?:artifact|build|bundle|compile|deck|export|generat(?:e|ed|or)|output|package|presentation|rebuild|regenerate|render|report|slides?)\b|\.(?:pdf|pptx|docx|html|svg|png|jpe?g|webp|mp4|mov)\b)/i.test(
10560
+ context
10561
+ )
10562
+ ) {
10563
+ return "";
10564
+ }
10565
+ const mutationRevision = Math.max(0, Number(verification.mutationRevision || 0));
10566
+ const latestSourceMutation = [...(verification.mutationHistory || [])]
10567
+ .reverse()
10568
+ .find(
10569
+ (mutation) =>
10570
+ Number(mutation?.revision || 0) === mutationRevision &&
10571
+ ["apply_patch", "write_file"].includes(String(mutation?.toolName || "")) &&
10572
+ (Array.isArray(mutation?.paths) ? mutation.paths : []).some(
10573
+ (item) => !isPrivateVerificationEvidencePath(item)
10574
+ )
10575
+ );
10576
+ if (!latestSourceMutation) return "";
10577
+ for (const run of [...(verification.commandRuns || [])].reverse()) {
10578
+ if (
10579
+ run?.ok !== true ||
10580
+ Number(run?.mutationRevision || 0) >= mutationRevision
10581
+ ) {
10582
+ continue;
10583
+ }
10584
+ const producer = safeProjectProducerSegment(run?.command || "", config);
10585
+ if (producer) return producer;
10586
+ }
10587
+ return "";
10588
+ }
10589
+
10418
10590
  function exactOutputPathsForState(state = {}) {
10419
10591
  const scsOutputPaths = Array.isArray(state.meta?.scs?.taskContract?.exactOutputPaths)
10420
10592
  ? state.meta.scs.taskContract.exactOutputPaths.filter(Boolean)
@@ -11082,7 +11254,7 @@ export function nextStepRuntimeConfig(config = {}, state = {}) {
11082
11254
  const entryAt = Date.parse(String(entry?.at || ""));
11083
11255
  return !Number.isFinite(repairAt) || (Number.isFinite(entryAt) && entryAt > repairAt);
11084
11256
  });
11085
- if (candidatePaths.length > 0 || !currentTurnRequiresFreshMutation) {
11257
+ if (candidatePaths.length > 0) {
11086
11258
  runtimeConfig.completionFreshMutationRequired = true;
11087
11259
  runtimeConfig.completionFreshMutationRevision = currentTurnRequiresFreshMutation
11088
11260
  ? groundingMutationBaseline + 1
@@ -11099,6 +11271,15 @@ export function nextStepRuntimeConfig(config = {}, state = {}) {
11099
11271
  const latestRecordedTest = [...testRuns]
11100
11272
  .reverse()
11101
11273
  .find((run) => String(run?.command || "").trim());
11274
+ const freshGeneratedArtifactProducer = [...(verification.commandRuns || [])]
11275
+ .reverse()
11276
+ .some(
11277
+ (run) =>
11278
+ run?.ok === true &&
11279
+ String(run?.generatedArtifactProducer || "").trim() &&
11280
+ Number(run?.mutationRevision || 0) === mutationRevision &&
11281
+ Number(run?.privateMutationRevision || 0) === privateMutationRevision
11282
+ );
11102
11283
  const retainedRepairPacket = state.meta?.failedTestRecoveryPacket;
11103
11284
  const repairedRetainedFailure = Boolean(
11104
11285
  latestRecordedTest?.passed !== true &&
@@ -11112,6 +11293,16 @@ export function nextStepRuntimeConfig(config = {}, state = {}) {
11112
11293
  );
11113
11294
  const retainedFailedTest =
11114
11295
  latestCurrentTest && latestCurrentTest.passed !== true ? latestCurrentTest : null;
11296
+ const pendingArtifactProducerCommand = pendingGeneratedArtifactProducerCommand(
11297
+ state,
11298
+ config,
11299
+ verification,
11300
+ retainedFailedTest
11301
+ );
11302
+ if (pendingArtifactProducerCommand) {
11303
+ runtimeConfig.generatedArtifactProducerPending = true;
11304
+ runtimeConfig.generatedArtifactProducerCommand = pendingArtifactProducerCommand;
11305
+ }
11115
11306
  if (retainedFailedTest) {
11116
11307
  const repositoryStateRepairMarker = state.meta?.repositoryStateRepair;
11117
11308
  const retainedRepositoryStateRepair = Boolean(
@@ -11572,7 +11763,7 @@ export function nextStepRuntimeConfig(config = {}, state = {}) {
11572
11763
  runtimeConfig.testVerificationCommand = String(retainedFailedTest.command || "");
11573
11764
  }
11574
11765
  } else if (
11575
- (!implementationOpen || repairedRetainedFailure) &&
11766
+ (!implementationOpen || repairedRetainedFailure || freshGeneratedArtifactProducer) &&
11576
11767
  !latestCurrentTest &&
11577
11768
  latestRecordedTest &&
11578
11769
  !testRunMatchesVerificationRevision(latestRecordedTest, verification)
@@ -1937,6 +1937,16 @@ export function selectProgressiveTools(
1937
1937
  return artifactValidationToolNames(config).map((name) => available.get(name)).filter(Boolean);
1938
1938
  }
1939
1939
 
1940
+ if (config.generatedArtifactProducerPending === true) {
1941
+ const available = new Map(enabled.map(({ name, tool }) => [name, tool]));
1942
+ const producerCommand = constrainRunCommand(
1943
+ available.get("run_command"),
1944
+ config.generatedArtifactProducerCommand,
1945
+ "Run this exact previously successful local producer command once. Canonical source changed after its last run, so generated artifacts must be rebuilt before the retained validator can provide fresh evidence. Do not substitute another command or rerun the stale validator first."
1946
+ );
1947
+ return [producerCommand, finish].filter(Boolean);
1948
+ }
1949
+
1940
1950
  if (config.testFailureRepairActive === true) {
1941
1951
  const available = new Map(enabled.map(({ name, tool }) => [name, tool]));
1942
1952
  if (
@@ -542,7 +542,10 @@ export function filterExplicitlyExcludedOutputPaths(paths = [], exclusions = [])
542
542
  }
543
543
 
544
544
  export function inferExplicitlyExcludedOutputPaths(goal = "") {
545
- const source = String(goal || "");
545
+ // Preserve coordinated path lists that wrap after a comma. Prompt and task
546
+ // files commonly format "do not modify a, b,\nc, or d" across lines; splitting
547
+ // that text first drops the governing negative action from the continuation.
548
+ const source = String(goal || "").replace(/([,,、])\s*\r?\n\s*/gu, "$1 ");
546
549
  if (!source.trim()) return [];
547
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";
548
551
  const pathPattern = new RegExp(
@@ -573,6 +576,11 @@ export function inferExplicitlyExcludedOutputPaths(goal = "") {
573
576
  for (const clause of source.split(/[;;\n]|(?<=[.!?。!?])\s+/u)) {
574
577
  pathPattern.lastIndex = 0;
575
578
  const matches = [...clause.matchAll(pathPattern)];
579
+ const immutablePathClause = Boolean(
580
+ /\b(?:treat|consider|regard)\b[^!?。!?;;\n]{0,260}\b(?:as\s+)?(?:immutable|read[ -]?only)\b/i.test(
581
+ clause
582
+ )
583
+ );
576
584
  let previousExcluded = false;
577
585
  for (let matchIndex = 0; matchIndex < matches.length; matchIndex += 1) {
578
586
  const match = matches[matchIndex];
@@ -595,6 +603,7 @@ export function inferExplicitlyExcludedOutputPaths(goal = "") {
595
603
  )
596
604
  );
597
605
  const directExclusion = Boolean(
606
+ immutablePathClause ||
598
607
  negativeActionBefore.test(before) ||
599
608
  negativeActionAfter.test(after) ||
600
609
  keepAbsent.test(`${before}${after}`) ||
@@ -122,7 +122,7 @@ export const TASK_PROFILES = {
122
122
  id: "slides",
123
123
  label: "Slides and presentations",
124
124
  prompt:
125
- "Bias toward presentation, pitch deck, poster, lecture, and slide-style communication. Clarify audience and purpose from available context, create a durable outline and slide files or markdown deck, keep each slide visually focused, include speaker notes when useful, and export/preview when local tools support it.",
125
+ "Bias toward presentation, pitch deck, poster, lecture, and slide-style communication. Infer audience and purpose from available context, create a durable outline and source-grounded editable slide source, keep each slide visually focused, and include useful speaker notes. Preserve editable text, charts, tables, and shapes instead of flattening complete slides into images. Produce the requested deck/export formats and a reproducible build path when practical. Render every slide to a preview and inspect the actual pixels for clipping, collisions, wrapped-title decoration overlap, unreadable text, and inconsistent framing; rebuild after repairs. Verify source claims and calculations, artifact existence and package readability, slide/page counts across PPTX/PDF/previews, and any exact acceptance command supplied by the user. In a Git repository, when the task asks for a commit, commit intentional source and deliverables, narrowly ignore only transient build/perception evidence, and run a fresh git status --short before claiming completion.",
126
126
  tools: ["files", "shell", "canvas", "web_search"],
127
127
  },
128
128
  education: {