@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 +1 -1
- package/scripts/smoke-coding-tools.js +51 -1
- package/scripts/smoke-document-artifact-quality.js +37 -0
- package/scripts/smoke-dynamic-step-budget.js +37 -0
- package/src/agent-runner.js +114 -2
- package/src/command-policy.js +122 -0
- package/src/engineering-guidance.js +1 -0
- package/src/scs-evidence.js +14 -4
- package/src/spreadsheet-artifact-quality.js +228 -0
- package/src/task-profiles.js +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lazyingart/agintiflow",
|
|
3
|
-
"version": "0.20.
|
|
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 {
|
|
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",
|
package/src/agent-runner.js
CHANGED
|
@@ -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:
|
|
16596
|
+
requiresFreshFileMutation:
|
|
16597
|
+
sourceQualityRepairRequired ||
|
|
16598
|
+
missingFileEvidence ||
|
|
16599
|
+
artifactQualityRepairRequired,
|
|
16565
16600
|
requiredFreshMutationRevision: Math.max(
|
|
16566
16601
|
0,
|
|
16567
16602
|
Number(contract?.requiredFreshMutationRevision || 0),
|
|
16568
|
-
sourceQualityRepairRequired
|
|
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),
|
package/src/command-policy.js
CHANGED
|
@@ -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.",
|
package/src/scs-evidence.js
CHANGED
|
@@ -1616,7 +1616,8 @@ function inferBareRequestedVerifierCommands(goal = "") {
|
|
|
1616
1616
|
|
|
1617
1617
|
function inferExplicitRequestedCommands(goal = "") {
|
|
1618
1618
|
const source = stripForbiddenLanguage(goal);
|
|
1619
|
-
const
|
|
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)
|
|
1664
|
-
}
|
|
1665
|
-
|
|
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
|
+
}
|
package/src/task-profiles.js
CHANGED
|
@@ -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: {
|