@lazyingart/agintiflow 0.20.237 → 0.20.238
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.
|
|
3
|
+
"version": "0.20.238",
|
|
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",
|
|
@@ -3,7 +3,9 @@ import assert from "node:assert/strict";
|
|
|
3
3
|
import {
|
|
4
4
|
evaluateCurrentStateText,
|
|
5
5
|
evaluateDocumentConsistency,
|
|
6
|
+
evaluateExtractedDocumentText,
|
|
6
7
|
evaluatePdfPageBalance,
|
|
8
|
+
evaluatePdfTextBounds,
|
|
7
9
|
extractSupersededLiterals,
|
|
8
10
|
} from "../src/document-artifact-quality.js";
|
|
9
11
|
|
|
@@ -122,4 +124,21 @@ const readableOnePage = evaluatePdfPageBalance(
|
|
|
122
124
|
);
|
|
123
125
|
assert.equal(readableOnePage.ok, true, "readable one-page typography was rejected");
|
|
124
126
|
|
|
127
|
+
const cleanExtractedText = evaluateExtractedDocumentText("Page one\n\fPage two\tvalue\r\n");
|
|
128
|
+
assert.equal(cleanExtractedText.ok, true, "normal whitespace and PDF form feeds were rejected");
|
|
129
|
+
|
|
130
|
+
const corruptExtractedText = evaluateExtractedDocumentText("Reference detector \u0016 complete \ufffd");
|
|
131
|
+
assert.equal(corruptExtractedText.ok, false, "control and replacement glyphs were accepted");
|
|
132
|
+
assert.deepEqual(corruptExtractedText.codePoints, [0x16, 0xfffd]);
|
|
133
|
+
assert.equal(corruptExtractedText.defects[0]?.code, "corrupt-extracted-text");
|
|
134
|
+
|
|
135
|
+
const boundedText = evaluatePdfTextBounds(`<doc>${page(20)}</doc>`);
|
|
136
|
+
assert.equal(boundedText.ok, true, "text inside readable margins was rejected");
|
|
137
|
+
|
|
138
|
+
const clippedText = evaluatePdfTextBounds(
|
|
139
|
+
'<doc><page width="595" height="842"><word xMin="8" yMin="60" xMax="90" yMax="70">clipped</word></page></doc>'
|
|
140
|
+
);
|
|
141
|
+
assert.equal(clippedText.ok, false, "text outside readable margins was accepted");
|
|
142
|
+
assert.equal(clippedText.defects[0]?.code, "pdf-text-outside-readable-margin");
|
|
143
|
+
|
|
125
144
|
console.log("document artifact quality smoke test passed");
|
|
@@ -29,7 +29,13 @@ import {
|
|
|
29
29
|
shouldActivateScs,
|
|
30
30
|
shouldRequestScsReplan,
|
|
31
31
|
} from "../src/scs-controller.js";
|
|
32
|
-
import {
|
|
32
|
+
import {
|
|
33
|
+
buildScsEvidenceLedger,
|
|
34
|
+
deriveScsTaskContract,
|
|
35
|
+
evaluateScsEvidence,
|
|
36
|
+
gitActionsSatisfyContract,
|
|
37
|
+
inferSuccessfulGitActionsFromCommandResult,
|
|
38
|
+
} from "../src/scs-evidence.js";
|
|
33
39
|
import { resolveRuntimeConfig } from "../src/config.js";
|
|
34
40
|
import { classifyGoalIntent, isDirectAnswerIntent } from "../src/goal-intent.js";
|
|
35
41
|
import { languageWriterDefaults } from "../src/writing-specialist.js";
|
|
@@ -922,6 +928,26 @@ assert(
|
|
|
922
928
|
!committedEvaluation.missing.some((item) => item.category === "git"),
|
|
923
929
|
"a successful git commit did not satisfy the explicit git requirement"
|
|
924
930
|
);
|
|
931
|
+
const recoveredCommitActions = inferSuccessfulGitActionsFromCommandResult({
|
|
932
|
+
ok: true,
|
|
933
|
+
exitCode: 0,
|
|
934
|
+
args: {
|
|
935
|
+
command:
|
|
936
|
+
'echo "seed author: $(git log -1 --format=\'%an <%ae>\')"; git config user.name "$(git log -1 --format=\'%an\')"; git commit -m "finish handoff" && git log -1 --oneline',
|
|
937
|
+
},
|
|
938
|
+
stdout: "[main abc1234] finish handoff\n 8 files changed, 499 insertions(+)",
|
|
939
|
+
});
|
|
940
|
+
assert(
|
|
941
|
+
recoveredCommitActions.length === 1 && recoveredCommitActions[0] === "commit",
|
|
942
|
+
"a canonical successful commit was lost because its command had a setup prefix or shell expansion"
|
|
943
|
+
);
|
|
944
|
+
assert(
|
|
945
|
+
gitActionsSatisfyContract(
|
|
946
|
+
{ requiredGitActions: ["add", "commit"] },
|
|
947
|
+
recoveredCommitActions
|
|
948
|
+
),
|
|
949
|
+
"a successful commit did not satisfy the implied staging step after a partially successful add/commit chain"
|
|
950
|
+
);
|
|
925
951
|
const explainCodeContract = deriveScsTaskContract({
|
|
926
952
|
goal: "Explain JavaScript closures at a high level.",
|
|
927
953
|
taskProfile: "code",
|
|
@@ -20,3 +20,16 @@ tools:
|
|
|
20
20
|
Prefer safe conversions through available tools such as `pandoc`, `libreoffice`, or Python libraries when installed. Preserve originals; write converted or edited outputs to a new file unless overwrite is explicit.
|
|
21
21
|
|
|
22
22
|
If binary `.docx` content cannot be inspected directly, explain the needed converter and create a project-local script or setup note.
|
|
23
|
+
|
|
24
|
+
For a repository handoff or generated document project:
|
|
25
|
+
|
|
26
|
+
- synthesize the authoritative current state instead of narrating superseded values unless history was requested;
|
|
27
|
+
- keep editable source plus the requested reader format, normally DOCX and a phone-readable PDF;
|
|
28
|
+
- provide and document a conventional project-local `build.sh` entry point, even when it delegates to a Python or TeX implementation;
|
|
29
|
+
- make a clean-checkout build provision or clearly verify its dependencies rather than relying silently on the current shell;
|
|
30
|
+
- preserve source inputs byte-for-byte and keep session data, visual-inspection renders, LaTeX intermediates, caches, and other transient evidence ignored; prefer ignore rules over deleting evidence, and never couple cleanup commands to the build or validation command;
|
|
31
|
+
- validate extracted DOCX/PDF text for current facts, stale or private values, encoding damage, and missing action/evidence content;
|
|
32
|
+
- render every PDF page and inspect it for clipping, overlap, orphaned headings, sparse spill pages, readable margins, and phone-scale readability;
|
|
33
|
+
- when the task is in a git repository and requests a finished handoff, commit only intentional project files and finish with a clean worktree unless the user says not to commit.
|
|
34
|
+
|
|
35
|
+
Visual polish does not establish content quality. Cross-check names, dates, totals, counts, statuses, decisions, actions, risks, evidence, and limitations against the source material before completion.
|
|
@@ -30,6 +30,7 @@ const INTENTIONAL_SPARSE_PAGE_PATTERN =
|
|
|
30
30
|
const HISTORICAL_TRANSITION_PATTERN =
|
|
31
31
|
/\b(?:formerly|no longer|previously|replac(?:ed|ing)|supersed(?:e|ed|es|ing)|used to be)\b/i;
|
|
32
32
|
const MIN_READABLE_MEDIAN_WORD_HEIGHT_PT = 8.8;
|
|
33
|
+
const MIN_READABLE_HORIZONTAL_MARGIN_PT = 18;
|
|
33
34
|
const COUNT_WORDS = new Map([
|
|
34
35
|
["zero", 0], ["one", 1], ["two", 2], ["three", 3], ["four", 4], ["five", 5],
|
|
35
36
|
["six", 6], ["seven", 7], ["eight", 8], ["nine", 9], ["ten", 10],
|
|
@@ -239,6 +240,49 @@ export function evaluatePdfPageBalance(bboxXml = "") {
|
|
|
239
240
|
};
|
|
240
241
|
}
|
|
241
242
|
|
|
243
|
+
export function evaluateExtractedDocumentText(text = "") {
|
|
244
|
+
const unexpected = [...String(text || "").matchAll(/[\u0000-\u0008\u000b\u000e-\u001f\u007f-\u009f\ufffd]/gu)]
|
|
245
|
+
.map((match) => match[0].codePointAt(0))
|
|
246
|
+
.filter(Number.isInteger);
|
|
247
|
+
const codePoints = [...new Set(unexpected)].sort((a, b) => a - b);
|
|
248
|
+
const defects = [];
|
|
249
|
+
if (codePoints.length) {
|
|
250
|
+
defects.push({
|
|
251
|
+
code: "corrupt-extracted-text",
|
|
252
|
+
message: `The independently extracted reader text contains unexpected control or replacement glyphs: ${codePoints
|
|
253
|
+
.map((value) => `U+${value.toString(16).toUpperCase().padStart(4, "0")}`)
|
|
254
|
+
.join(", ")}. Repair the document encoding or generator instead of stripping these bytes only during validation.`,
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
return { ok: defects.length === 0, defects, codePoints };
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
export function evaluatePdfTextBounds(bboxXml = "", minimumMargin = MIN_READABLE_HORIZONTAL_MARGIN_PT) {
|
|
261
|
+
const pages = parsePdfBboxPages(bboxXml);
|
|
262
|
+
const defects = [];
|
|
263
|
+
for (const [index, page] of pages.entries()) {
|
|
264
|
+
if (!Number.isFinite(page.width) || page.width <= 0) continue;
|
|
265
|
+
const outside = page.words.filter((word) =>
|
|
266
|
+
word.text && (
|
|
267
|
+
!Number.isFinite(word.xMin) ||
|
|
268
|
+
!Number.isFinite(word.xMax) ||
|
|
269
|
+
word.xMin < minimumMargin ||
|
|
270
|
+
word.xMax > page.width - minimumMargin
|
|
271
|
+
)
|
|
272
|
+
);
|
|
273
|
+
if (!outside.length) continue;
|
|
274
|
+
const sample = outside
|
|
275
|
+
.slice(0, 4)
|
|
276
|
+
.map((word) => `${JSON.stringify(word.text)} at ${Number(word.xMin).toFixed(1)}..${Number(word.xMax).toFixed(1)} pt`)
|
|
277
|
+
.join("; ");
|
|
278
|
+
defects.push({
|
|
279
|
+
code: "pdf-text-outside-readable-margin",
|
|
280
|
+
message: `PDF page ${index + 1} places ${outside.length} text item${outside.length === 1 ? "" : "s"} outside the ${minimumMargin} pt horizontal readability margin (${sample}). Reflow the text or table instead of accepting clipping.`,
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
return { ok: pages.length > 0 && defects.length === 0, checked: pages.length > 0, defects };
|
|
284
|
+
}
|
|
285
|
+
|
|
242
286
|
export function evaluateCurrentStateText({ sourceText = "", outputText = "", currentStateRequired = false } = {}) {
|
|
243
287
|
const supersededLiterals = extractSupersededLiterals(sourceText);
|
|
244
288
|
const presentSupersededLiterals = supersededLiterals.filter((literal) => containsLiteral(outputText, literal));
|
|
@@ -475,9 +519,11 @@ export async function validateWordDocumentArtifacts({
|
|
|
475
519
|
try {
|
|
476
520
|
if (artifact.extension === ".pdf") {
|
|
477
521
|
const extracted = await extractPdf(artifact);
|
|
522
|
+
const textQuality = evaluateExtractedDocumentText(extracted.text);
|
|
478
523
|
const semantic = evaluateCurrentStateText({ sourceText, outputText: extracted.text, currentStateRequired });
|
|
479
524
|
const consistency = evaluateDocumentConsistency(extracted.text);
|
|
480
525
|
const pageBalance = evaluatePdfPageBalance(extracted.bbox);
|
|
526
|
+
const textBounds = evaluatePdfTextBounds(extracted.bbox);
|
|
481
527
|
if (!String(extracted.text || "").trim()) {
|
|
482
528
|
defects.push({
|
|
483
529
|
code: "empty-pdf-text",
|
|
@@ -493,8 +539,10 @@ export async function validateWordDocumentArtifacts({
|
|
|
493
539
|
});
|
|
494
540
|
}
|
|
495
541
|
defects.push(...semantic.defects.map((item) => ({ ...item, path: artifact.path })));
|
|
542
|
+
defects.push(...textQuality.defects.map((item) => ({ ...item, path: artifact.path })));
|
|
496
543
|
defects.push(...consistency.defects.map((item) => ({ ...item, path: artifact.path })));
|
|
497
544
|
defects.push(...pageBalance.defects.map((item) => ({ ...item, path: artifact.path })));
|
|
545
|
+
defects.push(...textBounds.defects.map((item) => ({ ...item, path: artifact.path })));
|
|
498
546
|
artifactReports.push({
|
|
499
547
|
path: artifact.path,
|
|
500
548
|
extension: artifact.extension,
|
|
@@ -506,6 +554,7 @@ export async function validateWordDocumentArtifacts({
|
|
|
506
554
|
});
|
|
507
555
|
} else {
|
|
508
556
|
const text = await extractDocxText(artifact);
|
|
557
|
+
const textQuality = evaluateExtractedDocumentText(text);
|
|
509
558
|
const semantic = evaluateCurrentStateText({ sourceText, outputText: text, currentStateRequired });
|
|
510
559
|
const consistency = evaluateDocumentConsistency(text);
|
|
511
560
|
if (!String(text || "").trim()) {
|
|
@@ -516,6 +565,7 @@ export async function validateWordDocumentArtifacts({
|
|
|
516
565
|
});
|
|
517
566
|
}
|
|
518
567
|
defects.push(...semantic.defects.map((item) => ({ ...item, path: artifact.path })));
|
|
568
|
+
defects.push(...textQuality.defects.map((item) => ({ ...item, path: artifact.path })));
|
|
519
569
|
defects.push(...consistency.defects.map((item) => ({ ...item, path: artifact.path })));
|
|
520
570
|
artifactReports.push({
|
|
521
571
|
path: artifact.path,
|
package/src/scs-evidence.js
CHANGED
|
@@ -204,7 +204,20 @@ function missingRequiredGitActionSequence(required = [], observed = []) {
|
|
|
204
204
|
let cursor = 0;
|
|
205
205
|
for (let index = 0; index < expected.length; index += 1) {
|
|
206
206
|
const observedIndex = actual.indexOf(expected[index], cursor);
|
|
207
|
-
if (observedIndex < 0)
|
|
207
|
+
if (observedIndex < 0) {
|
|
208
|
+
// A successful commit proves that an index was staged, even when the
|
|
209
|
+
// preceding `git add` happened in an earlier partially successful shell
|
|
210
|
+
// chain or the commit used `-a`. Preserve the requested add -> commit
|
|
211
|
+
// order without forcing the model to repeat a completed commit.
|
|
212
|
+
if (expected[index] === "add" && expected[index + 1] === "commit") {
|
|
213
|
+
const commitIndex = actual.indexOf("commit", cursor);
|
|
214
|
+
if (commitIndex >= 0) {
|
|
215
|
+
cursor = commitIndex;
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return expected.slice(index);
|
|
220
|
+
}
|
|
208
221
|
cursor = observedIndex + 1;
|
|
209
222
|
}
|
|
210
223
|
if (expected.at(-1) === "push") {
|
|
@@ -1070,7 +1083,20 @@ export function inferSuccessfulGitActionsFromCommandResult(payload = {}) {
|
|
|
1070
1083
|
return inferGitActionsFromCommand(exitWrapper.command);
|
|
1071
1084
|
}
|
|
1072
1085
|
if (payload.ok === false || Number(payload.exitCode ?? 0) !== 0) return [];
|
|
1073
|
-
|
|
1086
|
+
const inferred = inferGitActionsFromCommand(command);
|
|
1087
|
+
if (inferred.length) return inferred;
|
|
1088
|
+
|
|
1089
|
+
// Shell expansion or a setup prefix can make the full command ambiguous to
|
|
1090
|
+
// the static parser. A canonical successful commit line plus an explicit
|
|
1091
|
+
// top-level `git commit` still provides concrete commit evidence.
|
|
1092
|
+
const output = String(payload.stdout || payload.result || "");
|
|
1093
|
+
if (
|
|
1094
|
+
/(?:^|[;&|]\s*)git\s+commit\b/i.test(command) &&
|
|
1095
|
+
/^\[[^\]\n]+\s+[0-9a-f]{7,}\]\s+\S+/mi.test(output)
|
|
1096
|
+
) {
|
|
1097
|
+
return ["commit"];
|
|
1098
|
+
}
|
|
1099
|
+
return [];
|
|
1074
1100
|
}
|
|
1075
1101
|
|
|
1076
1102
|
function observedProjectCommandSatisfies(requiredCommand = "", item = {}) {
|