@lazyingart/agintiflow 0.20.282 → 0.20.283

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.282",
3
+ "version": "0.20.283",
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",
@@ -25,7 +25,11 @@ import { createToolContract, resolveDispatchableToolCallBatch } from "../src/too
25
25
  import { formatBehaviorContractForPrompt } from "../src/behavior-contract.js";
26
26
  import { resolveRuntimeConfig } from "../src/config.js";
27
27
  import { readCodebaseMap } from "../src/codebase-map.js";
28
- import { classifyCommand, evaluateCommandPolicy } from "../src/command-policy.js";
28
+ import {
29
+ classifyCommand,
30
+ evaluateCommandPolicy,
31
+ externalValidatorCommandContract,
32
+ } from "../src/command-policy.js";
29
33
  import { checkToolUse } from "../src/guardrails.js";
30
34
  import { shouldReviewToolResult } from "../src/scs-controller.js";
31
35
  import {
@@ -96,6 +100,52 @@ async function runMock(goal, sessionId, { resume = false } = {}) {
96
100
  }
97
101
 
98
102
  try {
103
+ const externalValidatorPath = path.join(
104
+ tempRoot,
105
+ "private-acceptance",
106
+ "spreadsheet_contract.py"
107
+ );
108
+ const externalValidatorCommand = `python3 ${externalValidatorPath}`;
109
+ assert(
110
+ externalValidatorCommandContract(externalValidatorCommand, {
111
+ commandCwd: workspace,
112
+ })?.path === externalValidatorPath,
113
+ "an exact external validator command did not produce an opaque contract"
114
+ );
115
+ assert(
116
+ externalValidatorCommandContract("python3 tests/local_contract.py", {
117
+ commandCwd: workspace,
118
+ }) === null,
119
+ "an in-workspace project test was incorrectly treated as an opaque external validator"
120
+ );
121
+ const opaqueValidatorPolicy = {
122
+ commandCwd: workspace,
123
+ allowShellTool: true,
124
+ sandboxMode: "host",
125
+ packageInstallPolicy: "block",
126
+ opaqueExternalValidatorPaths: [externalValidatorPath],
127
+ opaqueExternalValidatorCommands: [externalValidatorCommand],
128
+ };
129
+ assert(
130
+ evaluateCommandPolicy(externalValidatorCommand, opaqueValidatorPolicy).allowed === true,
131
+ "the exact declared external validator execution was blocked"
132
+ );
133
+ for (const inspectionCommand of [
134
+ `cat ${externalValidatorPath}`,
135
+ `sed -n '1,160p' ${externalValidatorPath}`,
136
+ `cat ${path.relative(workspace, externalValidatorPath)}`,
137
+ `V=${externalValidatorPath}; grep -n expected "$V"`,
138
+ `echo validator; cat ${externalValidatorPath}; git status --short`,
139
+ ]) {
140
+ const decision = evaluateCommandPolicy(inspectionCommand, opaqueValidatorPolicy);
141
+ assert(
142
+ decision.allowed === false &&
143
+ decision.category === "opaque-external-validator-inspection" &&
144
+ decision.recoverable === true,
145
+ `external validator source inspection escaped the opaque contract: ${inspectionCommand}`
146
+ );
147
+ }
148
+
99
149
  const genericArtifactBlock = await genericArtifactFilenameBlock(
100
150
  "write_file",
101
151
  { path: "report.md", content: "summary" },
@@ -8,6 +8,43 @@ import {
8
8
  evaluatePdfTextBounds,
9
9
  extractSupersededLiterals,
10
10
  } from "../src/document-artifact-quality.js";
11
+ import { evaluateSpreadsheetStructure } from "../src/spreadsheet-artifact-quality.js";
12
+
13
+ const workbookWithPlaceholder = evaluateSpreadsheetStructure({
14
+ sheets: [
15
+ { name: "Sheet", state: "visible", cellCount: 0, formulaCount: 0 },
16
+ { name: "Raw Inventory", state: "visible", cellCount: 30, formulaCount: 0 },
17
+ { name: "Reorder Plan", state: "visible", cellCount: 20, formulaCount: 8 },
18
+ ],
19
+ chartCount: 1,
20
+ externalLinkCount: 0,
21
+ hasMacros: false,
22
+ });
23
+ assert.equal(workbookWithPlaceholder.ok, false, "an empty default workbook sheet was accepted");
24
+ assert.equal(workbookWithPlaceholder.defects[0]?.code, "unused-default-worksheet");
25
+
26
+ const emptyWorkbook = evaluateSpreadsheetStructure({
27
+ sheets: [{ name: "Sheet", state: "visible", cellCount: 0, formulaCount: 0 }],
28
+ chartCount: 0,
29
+ externalLinkCount: 0,
30
+ hasMacros: false,
31
+ });
32
+ assert.equal(emptyWorkbook.ok, false, "a completely empty workbook was accepted");
33
+ assert.equal(emptyWorkbook.defects[0]?.code, "workbook-has-no-content");
34
+
35
+ const purposefulWorkbook = evaluateSpreadsheetStructure({
36
+ sheets: [
37
+ { name: "Raw Inventory", state: "visible", cellCount: 30, formulaCount: 0 },
38
+ { name: "Reorder Plan", state: "visible", cellCount: 20, formulaCount: 8 },
39
+ { name: "Dashboard", state: "visible", cellCount: 12, formulaCount: 3 },
40
+ ],
41
+ chartCount: 1,
42
+ externalLinkCount: 0,
43
+ hasMacros: false,
44
+ });
45
+ assert.equal(purposefulWorkbook.ok, true, "a workbook with only purposeful sheets was rejected");
46
+ assert.equal(purposefulWorkbook.formulaCount, 11);
47
+ assert.equal(purposefulWorkbook.chartCount, 1);
11
48
 
12
49
  const source = [
13
50
  "Initial plan: the demonstration date was September 12.",
@@ -5539,6 +5539,43 @@ try {
5539
5539
  );
5540
5540
  const generatedDeckValidator =
5541
5541
  `python3 ${generatedDeckValidatorPath} --root .`;
5542
+ const opaqueExternalValidatorState = {
5543
+ goal: [
5544
+ "Create the requested workbook from the local inputs.",
5545
+ `Run exactly: \`${generatedDeckValidator}\``,
5546
+ "Do not edit that external validator.",
5547
+ ].join("\n"),
5548
+ meta: {
5549
+ taskProfile: "data",
5550
+ goalContract: {
5551
+ revision: 1,
5552
+ currentRequest: "Create the requested workbook and run the exact validator.",
5553
+ },
5554
+ projectVerification: {
5555
+ mutationRevision: 0,
5556
+ mutationHistory: [],
5557
+ commandRuns: [],
5558
+ testRuns: [],
5559
+ },
5560
+ toolLoop: { recent: [] },
5561
+ },
5562
+ };
5563
+ const opaqueExternalValidatorRuntime = nextStepRuntimeConfig(
5564
+ {
5565
+ provider: "deepseek",
5566
+ taskProfile: "data",
5567
+ commandCwd: workspace,
5568
+ goal: opaqueExternalValidatorState.goal,
5569
+ },
5570
+ opaqueExternalValidatorState
5571
+ );
5572
+ assert(
5573
+ JSON.stringify(opaqueExternalValidatorRuntime.opaqueExternalValidatorPaths) ===
5574
+ JSON.stringify([generatedDeckValidatorPath]) &&
5575
+ JSON.stringify(opaqueExternalValidatorRuntime.opaqueExternalValidatorCommands) ===
5576
+ JSON.stringify([generatedDeckValidator]),
5577
+ "an exact external validator was not retained as an opaque execute-only contract before its first run"
5578
+ );
5542
5579
  await fs.writeFile(
5543
5580
  path.join(workspace, "build_deck.py"),
5544
5581
  "print('build canonical deck')\n",
@@ -38,6 +38,7 @@ import { normalizeWrapperName, runAgentWrapper, wrapperStatusText } from "./tool
38
38
  import {
39
39
  classifyCommand,
40
40
  evaluateCommandPolicy,
41
+ externalValidatorCommandContract,
41
42
  normalizeCommandForPolicy,
42
43
  } from "./command-policy.js";
43
44
  import {
@@ -59,6 +60,7 @@ import {
59
60
  import { normalizeCanvasPayload, persistCanvasPayloadFile } from "./artifact-tunnel.js";
60
61
  import { getTaskProfile } from "./task-profiles.js";
61
62
  import { validateWordDocumentArtifacts } from "./document-artifact-quality.js";
63
+ import { validateSpreadsheetArtifacts } from "./spreadsheet-artifact-quality.js";
62
64
  import { generateImage, listAuxiliarySkills } from "./auxiliary-tools.js";
63
65
  import {
64
66
  engineeringGuidanceForTask,
@@ -6756,11 +6758,13 @@ export function completionExternalBlockerCanClose({
6756
6758
  projectTestBlock = null,
6757
6759
  sourceQuality = { ok: true },
6758
6760
  documentQuality = null,
6761
+ spreadsheetQuality = null,
6759
6762
  } = {}) {
6760
6763
  return Boolean(
6761
6764
  !projectTestBlock &&
6762
6765
  sourceQuality?.ok !== false &&
6763
6766
  (!documentQuality || documentQuality.ok !== false) &&
6767
+ (!spreadsheetQuality || spreadsheetQuality.ok !== false) &&
6764
6768
  finishResultClaimsBlocker(candidateResult) &&
6765
6769
  hasScsBlockerEvidence(evidenceLedger)
6766
6770
  );
@@ -11613,6 +11617,25 @@ export function nextStepRuntimeConfig(config = {}, state = {}) {
11613
11617
  runtimeConfig.testFailureRequiredSymbolRepair = requiredSymbolRepair;
11614
11618
  }
11615
11619
  const verification = state.meta?.projectVerification || {};
11620
+ const externalValidatorContracts = effectiveRequiredProjectCommands(
11621
+ state,
11622
+ verification,
11623
+ config
11624
+ )
11625
+ .map((command) =>
11626
+ externalValidatorCommandContract(command, {
11627
+ commandCwd: config.commandCwd || state.commandCwd || process.cwd(),
11628
+ })
11629
+ )
11630
+ .filter(Boolean);
11631
+ if (externalValidatorContracts.length) {
11632
+ runtimeConfig.opaqueExternalValidatorPaths = [
11633
+ ...new Set(externalValidatorContracts.map((item) => item.path)),
11634
+ ];
11635
+ runtimeConfig.opaqueExternalValidatorCommands = [
11636
+ ...new Set(externalValidatorContracts.map((item) => item.command)),
11637
+ ];
11638
+ }
11616
11639
  const mutationRevision = Number(verification.mutationRevision || 0);
11617
11640
  const privateMutationRevision = verificationPrivateMutationRevision(verification);
11618
11641
  const implementationOpen = currentTurnImplementationOpen(state);
@@ -16544,6 +16567,8 @@ export function completionRepairMutationRequirement({
16544
16567
  contract = {},
16545
16568
  evaluation = {},
16546
16569
  sourceQuality = {},
16570
+ documentQuality = null,
16571
+ spreadsheetQuality = null,
16547
16572
  projectMutationRevision = 0,
16548
16573
  } = {}) {
16549
16574
  const sourceQualityRepairRequired = Boolean(
@@ -16559,15 +16584,28 @@ export function completionRepairMutationRequirement({
16559
16584
  (Array.isArray(evaluation?.missing) ? evaluation.missing : [])
16560
16585
  .some((item) => item?.category === "file")
16561
16586
  );
16587
+ const artifactQualityRepairRequired = [documentQuality, spreadsheetQuality]
16588
+ .some((quality) => Boolean(
16589
+ quality?.checked === true &&
16590
+ quality?.ok === false &&
16591
+ Array.isArray(quality?.defects) &&
16592
+ quality.defects.length > 0
16593
+ ));
16562
16594
  const revision = Math.max(0, Number(projectMutationRevision || 0));
16563
16595
  return {
16564
- requiresFreshFileMutation: sourceQualityRepairRequired || missingFileEvidence,
16596
+ requiresFreshFileMutation:
16597
+ sourceQualityRepairRequired ||
16598
+ missingFileEvidence ||
16599
+ artifactQualityRepairRequired,
16565
16600
  requiredFreshMutationRevision: Math.max(
16566
16601
  0,
16567
16602
  Number(contract?.requiredFreshMutationRevision || 0),
16568
- sourceQualityRepairRequired ? revision + 1 : 0
16603
+ sourceQualityRepairRequired || artifactQualityRepairRequired
16604
+ ? revision + 1
16605
+ : 0
16569
16606
  ),
16570
16607
  sourceQualityRepairRequired,
16608
+ artifactQualityRepairRequired,
16571
16609
  };
16572
16610
  }
16573
16611
 
@@ -16686,6 +16724,68 @@ async function completionEvidenceDecision({ config, state, store, observers, ste
16686
16724
  };
16687
16725
  }
16688
16726
  }
16727
+ let spreadsheetQuality = null;
16728
+ try {
16729
+ spreadsheetQuality = await validateSpreadsheetArtifacts({
16730
+ commandCwd: config.commandCwd || state.commandCwd || process.cwd(),
16731
+ candidateResult,
16732
+ goal: completionContractGoal(config, state),
16733
+ exactOutputPaths: [
16734
+ ...(assessment.contract?.exactOutputPaths || []),
16735
+ ...exactOutputPathsForState(state),
16736
+ ],
16737
+ });
16738
+ } catch (error) {
16739
+ spreadsheetQuality = {
16740
+ ok: false,
16741
+ checked: true,
16742
+ artifacts: [],
16743
+ defects: [{
16744
+ code: "spreadsheet-quality-check-failed",
16745
+ message: String(error?.message || error),
16746
+ }],
16747
+ reason: `Independent spreadsheet-quality validation failed: ${String(error?.message || error)}`,
16748
+ };
16749
+ }
16750
+ if (spreadsheetQuality.checked) {
16751
+ state.meta = state.meta || {};
16752
+ state.meta.spreadsheetArtifactQuality = spreadsheetQuality;
16753
+ const qualityEvent = {
16754
+ step,
16755
+ mode,
16756
+ ok: spreadsheetQuality.ok,
16757
+ reason: spreadsheetQuality.reason,
16758
+ artifacts: spreadsheetQuality.artifacts || [],
16759
+ defects: spreadsheetQuality.defects || [],
16760
+ };
16761
+ await store.appendEvent("spreadsheet.quality_assessed", qualityEvent);
16762
+ observers.event("spreadsheet.quality_assessed", qualityEvent);
16763
+ if (!spreadsheetQuality.ok) {
16764
+ const priorSemanticReason = assessment.semantic?.checked && !assessment.semantic?.ok
16765
+ ? String(assessment.semantic.reason || "")
16766
+ : "";
16767
+ const qualityReason = String(
16768
+ spreadsheetQuality.reason ||
16769
+ "The spreadsheet artifact failed independent structure checks."
16770
+ );
16771
+ assessment = {
16772
+ ...assessment,
16773
+ ok: false,
16774
+ spreadsheetQuality,
16775
+ evaluation: {
16776
+ ...assessment.evaluation,
16777
+ ok: false,
16778
+ reason: qualityReason,
16779
+ },
16780
+ semantic: {
16781
+ ...assessment.semantic,
16782
+ checked: true,
16783
+ ok: false,
16784
+ reason: [priorSemanticReason, qualityReason].filter(Boolean).join(" "),
16785
+ },
16786
+ };
16787
+ }
16788
+ }
16689
16789
  const sourceQuality = await validateMutatedPythonSourceQuality(config, state);
16690
16790
  state.meta = state.meta || {};
16691
16791
  state.meta.sourceCodeQuality = {
@@ -16735,6 +16835,7 @@ async function completionEvidenceDecision({ config, state, store, observers, ste
16735
16835
  projectTestBlock,
16736
16836
  sourceQuality,
16737
16837
  documentQuality,
16838
+ spreadsheetQuality,
16738
16839
  });
16739
16840
  if (assessment.ok && !claimsIncompleteWork) return { action: "accept", assessment };
16740
16841
  if (claimsIncompleteWork) {
@@ -16763,6 +16864,8 @@ async function completionEvidenceDecision({ config, state, store, observers, ste
16763
16864
  contract: assessment.contract,
16764
16865
  evaluation: assessment.evaluation,
16765
16866
  sourceQuality,
16867
+ documentQuality,
16868
+ spreadsheetQuality,
16766
16869
  projectMutationRevision: verificationDeficits.revision,
16767
16870
  });
16768
16871
  const baseDetail = {
@@ -16781,6 +16884,8 @@ async function completionEvidenceDecision({ config, state, store, observers, ste
16781
16884
  requiresFreshFileMutation: freshMutationRequirement.requiresFreshFileMutation,
16782
16885
  requiredFreshMutationRevision: freshMutationRequirement.requiredFreshMutationRevision,
16783
16886
  sourceQualityRepairRequired: freshMutationRequirement.sourceQualityRepairRequired,
16887
+ artifactQualityRepairRequired:
16888
+ freshMutationRequirement.artifactQualityRepairRequired,
16784
16889
  missingToolCalls: assessment.evaluation.missingToolCalls || [],
16785
16890
  pendingProjectCommands: verificationDeficits.pendingCommands,
16786
16891
  pendingProjectTests: verificationDeficits.testsCurrent ? [] : verificationDeficits.discoveredTests,
@@ -16801,6 +16906,13 @@ async function completionEvidenceDecision({ config, state, store, observers, ste
16801
16906
  defects: documentQuality.defects || [],
16802
16907
  }
16803
16908
  : null,
16909
+ spreadsheetQuality: spreadsheetQuality?.checked
16910
+ ? {
16911
+ ok: Boolean(spreadsheetQuality.ok),
16912
+ reason: spreadsheetQuality.reason || "",
16913
+ defects: spreadsheetQuality.defects || [],
16914
+ }
16915
+ : null,
16804
16916
  sourceQuality: sourceQuality.checked
16805
16917
  ? {
16806
16918
  ok: Boolean(sourceQuality.ok),
@@ -732,6 +732,115 @@ function structuredValidationCommand(command = "") {
732
732
  return null;
733
733
  }
734
734
 
735
+ const EXTERNAL_VALIDATOR_BASENAME_PATTERN =
736
+ /(?:^|[._-])(?:acceptance|audit|check|contract|spec|test|validat(?:e|ion)?|validator|verif(?:y|ication))(?:[._-]|$)/i;
737
+
738
+ function commandScriptOperand(tokens = []) {
739
+ const executable = path.basename(String(tokens[0] || "")).toLowerCase();
740
+ if (/^python(?:3(?:\.\d+)*)?$/.test(executable)) {
741
+ let index = 1;
742
+ while (index < tokens.length && String(tokens[index] || "").startsWith("-")) {
743
+ const option = String(tokens[index] || "");
744
+ if (/^-(?:B|E|I|O|OO|P|q|s|S|u|v|x)$/.test(option)) {
745
+ index += 1;
746
+ continue;
747
+ }
748
+ if (/^-(?:W|X)$/.test(option) && tokens[index + 1]) {
749
+ index += 2;
750
+ continue;
751
+ }
752
+ if (/^-(?:W|X).+/.test(option)) {
753
+ index += 1;
754
+ continue;
755
+ }
756
+ return "";
757
+ }
758
+ return String(tokens[index] || "");
759
+ }
760
+ if (["bash", "sh", "node"].includes(executable)) {
761
+ return String(tokens[1] || "");
762
+ }
763
+ return "";
764
+ }
765
+
766
+ export function externalValidatorCommandContract(command = "", config = {}) {
767
+ const normalized = String(command || "").trim();
768
+ const sequence = parseTopLevelShellSequence(normalized);
769
+ if (
770
+ !normalized ||
771
+ sequence.commands.length !== 1 ||
772
+ sequence.separators.length > 0 ||
773
+ sequence.trailingSeparator ||
774
+ sequence.openQuote ||
775
+ sequence.trailingEscape ||
776
+ hasActiveShellExpansion(normalized)
777
+ ) {
778
+ return null;
779
+ }
780
+ const tokens = tokenizeShellWords(normalized);
781
+ const operand = commandScriptOperand(tokens);
782
+ if (!operand || !/\.(?:c?js|mjs|py|sh)$/i.test(operand)) return null;
783
+ const basename = path.basename(operand, path.extname(operand));
784
+ if (!EXTERNAL_VALIDATOR_BASENAME_PATTERN.test(basename)) return null;
785
+
786
+ const commandCwd = path.resolve(config.commandCwd || process.cwd());
787
+ const absolutePath = path.resolve(commandCwd, operand);
788
+ const relativePath = path.relative(commandCwd, absolutePath);
789
+ if (
790
+ !relativePath ||
791
+ (!relativePath.startsWith("..") && !path.isAbsolute(relativePath))
792
+ ) {
793
+ return null;
794
+ }
795
+ return {
796
+ command: normalized,
797
+ path: absolutePath,
798
+ };
799
+ }
800
+
801
+ function commandReferencesOpaqueValidator(command = "", config = {}) {
802
+ const paths = (Array.isArray(config.opaqueExternalValidatorPaths)
803
+ ? config.opaqueExternalValidatorPaths
804
+ : [])
805
+ .map((item) => path.resolve(String(item || "")))
806
+ .filter(Boolean);
807
+ if (!paths.length) return "";
808
+ const normalized = String(command || "");
809
+ const commandCwd = path.resolve(config.commandCwd || process.cwd());
810
+ return paths.find((candidate) => {
811
+ if (normalized.includes(candidate)) return true;
812
+ const relative = path.relative(commandCwd, candidate);
813
+ return Boolean(relative && normalized.includes(relative));
814
+ }) || "";
815
+ }
816
+
817
+ function exactOpaqueValidatorExecution(command = "", config = {}) {
818
+ const requestedTokens = tokenizeShellWords(String(command || "").trim());
819
+ if (!requestedTokens.length) return false;
820
+ return (Array.isArray(config.opaqueExternalValidatorCommands)
821
+ ? config.opaqueExternalValidatorCommands
822
+ : []).some((candidate) => {
823
+ const candidateTokens = tokenizeShellWords(String(candidate || "").trim());
824
+ return candidateTokens.length > 0 &&
825
+ JSON.stringify(candidateTokens) === JSON.stringify(requestedTokens);
826
+ });
827
+ }
828
+
829
+ function opaqueExternalValidatorInspectionBlock(command = "", config = {}) {
830
+ const referencedPath = commandReferencesOpaqueValidator(command, config);
831
+ if (!referencedPath || exactOpaqueValidatorExecution(command, config)) return null;
832
+ return {
833
+ allowed: false,
834
+ category: "opaque-external-validator-inspection",
835
+ recoverable: true,
836
+ needsApproval: false,
837
+ writesWorkspace: false,
838
+ mayMutateProject: false,
839
+ reason:
840
+ "The exact external acceptance script is opaque verification evidence. Run its declared command unchanged before inspecting implementation details. If that run fails and its diagnostics are insufficient, the runtime will expose one bounded read-only source view.",
841
+ };
842
+ }
843
+
735
844
  function classifyBackgroundShell(normalized = "") {
736
845
  const sequence = parseTopLevelShellSequence(normalized);
737
846
  if (!sequence.separators.includes("&") && sequence.trailingSeparator !== "&") return null;
@@ -2694,6 +2803,19 @@ export function classifyCommand(command) {
2694
2803
 
2695
2804
  export function evaluateCommandPolicy(command, config = {}) {
2696
2805
  const normalizedForPolicy = normalizeCommandForPolicy(command, config);
2806
+ const opaqueValidatorBlock = opaqueExternalValidatorInspectionBlock(
2807
+ normalizedForPolicy,
2808
+ config
2809
+ );
2810
+ if (opaqueValidatorBlock) {
2811
+ return {
2812
+ ...opaqueValidatorBlock,
2813
+ sandboxMode: normalizeSandboxMode(config.sandboxMode),
2814
+ packageInstallPolicy: normalizePackageInstallPolicy(
2815
+ config.packageInstallPolicy
2816
+ ),
2817
+ };
2818
+ }
2697
2819
  const classification = classifyBackgroundShell(normalizedForPolicy) ||
2698
2820
  classifyReadOnlyRootCd(normalizedForPolicy, config) ||
2699
2821
  classifyReadOnlyRootSequence(normalizedForPolicy, config) ||
@@ -160,6 +160,7 @@ export function engineeringGuidanceForTask(goal = "", taskProfile = "auto") {
160
160
  "Never send sudo passwords or wait at interactive password prompts. If host-level permission is truly required, stop that path, explain the blocker, and provide a manual command instead of hanging.",
161
161
  "Shell commands already start in the configured workspace. Prefer workspace-relative commands such as python3 scripts/check.py or cd subdir && make; do not prefix commands with absolute host cd paths unless the tool explicitly requires it.",
162
162
  "When you create or fix scripts, reports, tables, generated files, or analysis outputs, inspect the actual output. If it contains obvious duplicates, noisy rows, stale names, broken markdown, or contradictions, patch the source/output and rerun the check rather than merely explaining the defect in the report.",
163
+ "Treat an exact external acceptance or validator command as opaque verification evidence. Implement from the user request and project-owned instructions, run that command unchanged, and use its diagnostics. Do not read, grep, cat, or reconstruct the external validator before its first failed run; if diagnostics are insufficient, use only the one bounded source view the runtime exposes.",
163
164
  "Before claiming a coding task is finished, run git status --short when git is available. Leave the worktree clean, or explicitly report and justify each remaining untracked/unstaged artifact.",
164
165
  "Do not claim there are no transient artifacts unless you checked recursively for the relevant stack, such as find . -type d -name __pycache__ -o -name '*.pyc' for Python. A clean git status means tracked work is clean; ignored caches such as __pycache__ may still exist and should be removed or described accurately if relevant.",
165
166
  "For generated screenshots, images, PDFs, reports, archives, and app packages, choose a descriptive non-conflicting workspace path when the user did not specify one. Verify the file still exists after cleanup before claiming it was saved.",
@@ -1616,7 +1616,8 @@ function inferBareRequestedVerifierCommands(goal = "") {
1616
1616
 
1617
1617
  function inferExplicitRequestedCommands(goal = "") {
1618
1618
  const source = stripForbiddenLanguage(goal);
1619
- const commands = inferBareRequestedVerifierCommands(source);
1619
+ const inferredBareCommands = inferBareRequestedVerifierCommands(source);
1620
+ const explicitCommands = [];
1620
1621
  const inlineCode = /(?<!`)`([^`\r\n]+)`(?!`)/g;
1621
1622
  for (const match of source.matchAll(inlineCode)) {
1622
1623
  const index = Number(match.index || 0);
@@ -1660,9 +1661,18 @@ function inferExplicitRequestedCommands(goal = "") {
1660
1661
  const tokens = tokenizeShellWords(segment);
1661
1662
  return Boolean(tokens.length && !String(tokens[0] || "").startsWith("-"));
1662
1663
  });
1663
- if (executableSegments) commands.push(command);
1664
- }
1665
- return unique(commands).slice(0, 8);
1664
+ if (executableSegments) explicitCommands.push(command);
1665
+ }
1666
+ const explicitTokenSets = explicitCommands.map((command) => tokenizeShellWords(command));
1667
+ const nonShadowedBareCommands = inferredBareCommands.filter((command) => {
1668
+ const bareTokens = tokenizeShellWords(command);
1669
+ return !explicitTokenSets.some(
1670
+ (tokens) =>
1671
+ tokens.length > bareTokens.length &&
1672
+ bareTokens.every((token, index) => tokens[index] === token)
1673
+ );
1674
+ });
1675
+ return unique([...nonShadowedBareCommands, ...explicitCommands]).slice(0, 8);
1666
1676
  }
1667
1677
 
1668
1678
  export function deriveScsTaskContract({ goal = "", taskProfile = "", acceptanceCriteria = [] } = {}) {
@@ -0,0 +1,228 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { execFile } from "node:child_process";
4
+ import { promisify } from "node:util";
5
+
6
+ const execFileAsync = promisify(execFile);
7
+ const DEFAULT_SHEET_NAME_PATTERN = /^Sheet\d*$/i;
8
+ const OUTPUT_DIRECTORY_NAMES = ["artifacts", "deliverables", "output", "outputs"];
9
+ const XLSX_INSPECTOR = String.raw`
10
+ import json, posixpath, sys, zipfile
11
+ import xml.etree.ElementTree as ET
12
+
13
+ MAIN = "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
14
+ DOC_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
15
+ PKG_REL = "http://schemas.openxmlformats.org/package/2006/relationships"
16
+
17
+ path = sys.argv[1]
18
+ with zipfile.ZipFile(path) as archive:
19
+ names = set(archive.namelist())
20
+ workbook = ET.fromstring(archive.read("xl/workbook.xml"))
21
+ relationships = ET.fromstring(archive.read("xl/_rels/workbook.xml.rels"))
22
+ targets = {
23
+ item.attrib.get("Id", ""): item.attrib.get("Target", "")
24
+ for item in relationships.findall(f"{{{PKG_REL}}}Relationship")
25
+ }
26
+ sheets = []
27
+ for item in workbook.findall(f".//{{{MAIN}}}sheet"):
28
+ relation_id = item.attrib.get(f"{{{DOC_REL}}}id", "")
29
+ target = targets.get(relation_id, "")
30
+ if target.startswith("/"):
31
+ worksheet_path = target.lstrip("/")
32
+ else:
33
+ worksheet_path = posixpath.normpath(posixpath.join("xl", target))
34
+ cells = []
35
+ formulas = []
36
+ rows = []
37
+ if worksheet_path in names:
38
+ worksheet = ET.fromstring(archive.read(worksheet_path))
39
+ cells = worksheet.findall(f".//{{{MAIN}}}c")
40
+ formulas = worksheet.findall(f".//{{{MAIN}}}f")
41
+ rows = worksheet.findall(f".//{{{MAIN}}}row")
42
+ sheets.append({
43
+ "name": item.attrib.get("name", ""),
44
+ "state": item.attrib.get("state", "visible"),
45
+ "path": worksheet_path,
46
+ "cellCount": len(cells),
47
+ "formulaCount": len(formulas),
48
+ "rowCount": len(rows),
49
+ })
50
+ print(json.dumps({
51
+ "sheets": sheets,
52
+ "chartCount": sum(1 for name in names if name.startswith("xl/charts/") and name.endswith(".xml")),
53
+ "externalLinkCount": sum(1 for name in names if name.startswith("xl/externalLinks/") and name.endswith(".xml")),
54
+ "hasMacros": "xl/vbaProject.bin" in names,
55
+ }, ensure_ascii=False))
56
+ `;
57
+
58
+ function portablePath(value = "") {
59
+ return String(value || "").replace(/\\/g, "/");
60
+ }
61
+
62
+ function isInsideRoot(root, candidate) {
63
+ const relative = path.relative(root, candidate);
64
+ return relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative));
65
+ }
66
+
67
+ function workbookPathsFromText(value = "") {
68
+ const paths = [];
69
+ const pattern = /(?:^|[\s`'"(])((?:[A-Za-z0-9_.-]+\/)*[A-Za-z0-9_.-]+\.xlsx)(?=$|[\s`'"),.;:])/gi;
70
+ for (const match of String(value || "").matchAll(pattern)) {
71
+ const candidate = portablePath(match[1]).replace(/^\.\//, "");
72
+ if (candidate && !paths.includes(candidate)) paths.push(candidate);
73
+ }
74
+ return paths;
75
+ }
76
+
77
+ async function shallowWorkbookCandidates(workspace) {
78
+ const results = [];
79
+ for (const relativeDirectory of ["", ...OUTPUT_DIRECTORY_NAMES]) {
80
+ const directory = path.join(workspace, relativeDirectory);
81
+ const entries = await fs.readdir(directory, { withFileTypes: true }).catch(() => []);
82
+ for (const entry of entries) {
83
+ if (!entry.isFile() || !entry.name.toLowerCase().endsWith(".xlsx")) continue;
84
+ results.push(portablePath(path.join(relativeDirectory, entry.name)));
85
+ }
86
+ }
87
+ return results;
88
+ }
89
+
90
+ async function inspectWorkbook(absolutePath) {
91
+ const result = await execFileAsync("python3", ["-c", XLSX_INSPECTOR, absolutePath], {
92
+ encoding: "utf8",
93
+ maxBuffer: 4 * 1024 * 1024,
94
+ timeout: 20_000,
95
+ });
96
+ return JSON.parse(String(result.stdout || "{}"));
97
+ }
98
+
99
+ export function evaluateSpreadsheetStructure(report = {}) {
100
+ const sheets = Array.isArray(report.sheets) ? report.sheets : [];
101
+ const defects = [];
102
+ if (!sheets.length) {
103
+ defects.push({
104
+ code: "workbook-has-no-worksheets",
105
+ message: "The workbook does not contain a readable worksheet.",
106
+ });
107
+ } else if (sheets.every((sheet) => Number(sheet?.cellCount || 0) === 0)) {
108
+ defects.push({
109
+ code: "workbook-has-no-content",
110
+ message: "The workbook contains no populated cells.",
111
+ });
112
+ }
113
+ if (sheets.length > 1) {
114
+ for (const sheet of sheets) {
115
+ if (
116
+ String(sheet?.state || "visible") === "visible" &&
117
+ DEFAULT_SHEET_NAME_PATTERN.test(String(sheet?.name || "")) &&
118
+ Number(sheet?.cellCount || 0) === 0
119
+ ) {
120
+ defects.push({
121
+ code: "unused-default-worksheet",
122
+ sheet: String(sheet.name || ""),
123
+ message: `The workbook retains an empty default worksheet named ${sheet.name}. Remove the placeholder in the canonical producer so every rebuild contains only purposeful sheets.`,
124
+ });
125
+ }
126
+ }
127
+ }
128
+ if (Number(report.externalLinkCount || 0) > 0) {
129
+ defects.push({
130
+ code: "external-workbook-links",
131
+ message: "The workbook contains external links, so its calculations are not self-contained and reproducible.",
132
+ });
133
+ }
134
+ if (report.hasMacros === true) {
135
+ defects.push({
136
+ code: "macro-payload-in-xlsx",
137
+ message: "The XLSX package unexpectedly contains a VBA macro payload.",
138
+ });
139
+ }
140
+ return {
141
+ ok: defects.length === 0,
142
+ checked: true,
143
+ sheets,
144
+ formulaCount: sheets.reduce((sum, sheet) => sum + Number(sheet?.formulaCount || 0), 0),
145
+ chartCount: Math.max(0, Number(report.chartCount || 0)),
146
+ defects,
147
+ };
148
+ }
149
+
150
+ export async function validateSpreadsheetArtifacts({
151
+ commandCwd = process.cwd(),
152
+ candidateResult = "",
153
+ goal = "",
154
+ exactOutputPaths = [],
155
+ } = {}) {
156
+ const workspace = path.resolve(commandCwd || process.cwd());
157
+ const declared = (Array.isArray(exactOutputPaths) ? exactOutputPaths : [])
158
+ .map(portablePath)
159
+ .filter((item) => item.toLowerCase().endsWith(".xlsx"));
160
+ const mentioned = workbookPathsFromText(candidateResult);
161
+ const discovered = declared.length || mentioned.length || !/\b(?:excel|spreadsheet|workbook|xlsx)\b/i.test(goal)
162
+ ? []
163
+ : await shallowWorkbookCandidates(workspace);
164
+ const candidates = [...new Set([...declared, ...mentioned, ...discovered])];
165
+ if (!candidates.length) {
166
+ return {
167
+ ok: true,
168
+ checked: false,
169
+ artifacts: [],
170
+ defects: [],
171
+ reason: "No current XLSX artifact required structural validation.",
172
+ };
173
+ }
174
+
175
+ const artifacts = [];
176
+ const defects = [];
177
+ for (const candidate of candidates) {
178
+ const absolutePath = path.resolve(workspace, candidate);
179
+ if (!isInsideRoot(workspace, absolutePath)) {
180
+ defects.push({
181
+ code: "spreadsheet-outside-workspace",
182
+ path: candidate,
183
+ message: `The workbook ${candidate} is outside the configured workspace.`,
184
+ });
185
+ continue;
186
+ }
187
+ const stat = await fs.stat(absolutePath).catch(() => null);
188
+ if (!stat?.isFile()) {
189
+ defects.push({
190
+ code: "missing-spreadsheet-artifact",
191
+ path: candidate,
192
+ message: `The workbook ${candidate} does not exist.`,
193
+ });
194
+ continue;
195
+ }
196
+ try {
197
+ const structure = evaluateSpreadsheetStructure(await inspectWorkbook(absolutePath));
198
+ artifacts.push({
199
+ path: portablePath(path.relative(workspace, absolutePath)),
200
+ sheets: structure.sheets,
201
+ formulaCount: structure.formulaCount,
202
+ chartCount: structure.chartCount,
203
+ });
204
+ defects.push(...structure.defects.map((item) => ({
205
+ ...item,
206
+ path: portablePath(path.relative(workspace, absolutePath)),
207
+ })));
208
+ } catch (error) {
209
+ defects.push({
210
+ code: "spreadsheet-extraction-failed",
211
+ path: candidate,
212
+ message: `Could not independently inspect ${candidate}: ${String(error?.message || error).slice(0, 300)}.`,
213
+ });
214
+ }
215
+ }
216
+
217
+ return {
218
+ ok: defects.length === 0 && artifacts.length > 0,
219
+ checked: true,
220
+ artifacts,
221
+ defects,
222
+ reason: defects.length
223
+ ? defects.map((item) => `${item.path ? `${item.path}: ` : ""}${item.message}`).join(" ")
224
+ : artifacts.length
225
+ ? `Independent spreadsheet structure checks passed for ${artifacts.map((item) => item.path).join(", ")}.`
226
+ : "No readable workbook artifact was available for structural validation.",
227
+ };
228
+ }
@@ -87,7 +87,7 @@ export const TASK_PROFILES = {
87
87
  id: "data",
88
88
  label: "Data analysis",
89
89
  prompt:
90
- "Bias toward reproducible data analysis, cleanup, ETL, visualization, and report generation while staying able to write scripts or docs. Before touching data, inspect the project and read its AGINTI/AGENTS/README instructions plus relevant existing analysis code, configuration, and tests. Local mutation and command tools intentionally remain unavailable until this bounded discovery is complete. Treat raw/source/input exports as immutable evidence unless the user explicitly authorizes an in-place source change; implement normalization in reproducible code and write generated results under the project's declared output paths. Inspect data shape, schema, units, missing values, duplicates, aliases, and audit requirements before drawing conclusions. Run the existing analyzer and focused tests, save plots/reports as durable artifacts, verify requested paths and statistics externally, and explain assumptions, limitations, and data quality issues.",
90
+ "Bias toward reproducible data analysis, cleanup, ETL, visualization, spreadsheets, and report generation while staying able to write scripts or docs. Before touching data, inspect the project and read its AGINTI/AGENTS/README instructions plus relevant existing analysis code, configuration, and tests. Local mutation and command tools intentionally remain unavailable until this bounded discovery is complete. Treat raw/source/input exports as immutable evidence unless the user explicitly authorizes an in-place source change; implement normalization in reproducible code and write generated results under the project's declared output paths. Inspect data shape, schema, units, missing values, duplicates, aliases, and audit requirements before drawing conclusions. For editable XLSX workbooks, preserve purposeful raw and calculated sheets, use formulas where the workbook is meant to remain live, remove empty default Sheet/Sheet1 placeholders, and inspect the actual sheet names, formulas, charts, and rendered user-facing views. Do not invent extra deliverables during a bounded correction. Run the existing analyzer and focused tests, save plots/reports as durable artifacts, verify requested paths and statistics externally, and explain assumptions, limitations, and data quality issues.",
91
91
  tools: ["inspect_project", "files", "shell", "canvas", "sandbox"],
92
92
  },
93
93
  qa: {