flex-md 4.7.2 → 4.7.3
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/README.md +1 -1
- package/dist/__tests__/diagnostics.test.js +45 -47
- package/dist/__tests__/ofs.test.js +28 -30
- package/dist/__tests__/structural.test.js +19 -21
- package/dist/__tests__/validate.test.js +27 -29
- package/dist/cli/index.js +13 -15
- package/dist/detect/json/detectIntent.js +1 -4
- package/dist/detect/json/detectMarkdown.js +29 -35
- package/dist/detect/json/detectPresence.js +2 -6
- package/dist/detect/json/index.js +10 -31
- package/dist/detect/json/types.js +1 -2
- package/dist/extract/extract.js +11 -14
- package/dist/extract/types.js +1 -2
- package/dist/index.js +22 -69
- package/dist/logger.js +3 -6
- package/dist/md/match.js +1 -4
- package/dist/md/normalize.js +1 -4
- package/dist/md/outline.js +4 -8
- package/dist/md/parse.js +11 -20
- package/dist/ofs/adapter.js +45 -49
- package/dist/ofs/enricher.js +3 -8
- package/dist/ofs/infer.js +4 -7
- package/dist/ofs/issuesEnvelope.js +5 -10
- package/dist/ofs/memory.js +6 -10
- package/dist/ofs/parser.js +7 -13
- package/dist/ofs/stringify.js +1 -4
- package/dist/pipeline/enforce.js +12 -15
- package/dist/pipeline/kind.js +3 -6
- package/dist/pipeline/repair.js +8 -11
- package/dist/strictness/container.js +1 -4
- package/dist/strictness/processor.js +7 -10
- package/dist/strictness/types.js +1 -4
- package/dist/tokens/auto-fix.js +1 -4
- package/dist/tokens/cognitive-cost.js +6 -10
- package/dist/tokens/compliance.js +4 -8
- package/dist/tokens/confidence.js +6 -9
- package/dist/tokens/estimator.js +20 -26
- package/dist/tokens/improvements.js +12 -16
- package/dist/tokens/index.js +22 -40
- package/dist/tokens/parser.js +4 -7
- package/dist/tokens/patterns.js +2 -5
- package/dist/tokens/runtime-estimator.js +9 -12
- package/dist/tokens/smart-report.js +10 -14
- package/dist/tokens/spec-estimator.js +10 -15
- package/dist/tokens/types.js +1 -2
- package/dist/tokens/validator.js +3 -6
- package/dist/types.js +1 -2
- package/dist/validate/compliance.js +4 -8
- package/dist/validate/connection.js +5 -8
- package/dist/validate/types.js +1 -2
- package/dist/validate/validate.js +16 -19
- package/dist-cjs/__tests__/diagnostics.test.cjs +61 -0
- package/dist-cjs/__tests__/ofs.test.cjs +53 -0
- package/dist-cjs/__tests__/structural.test.cjs +30 -0
- package/dist-cjs/__tests__/validate.test.cjs +110 -0
- package/dist-cjs/cli/index.cjs +110 -0
- package/dist-cjs/detect/json/detectIntent.cjs +82 -0
- package/dist-cjs/detect/json/detectMarkdown.cjs +304 -0
- package/dist-cjs/detect/json/detectPresence.cjs +195 -0
- package/dist-cjs/detect/json/index.cjs +34 -0
- package/dist-cjs/detect/json/types.cjs +2 -0
- package/dist-cjs/extract/extract.cjs +72 -0
- package/dist-cjs/extract/types.cjs +2 -0
- package/dist-cjs/flex-md-loader.cjs +102 -0
- package/dist-cjs/index.cjs +79 -0
- package/dist-cjs/logger.cjs +22 -0
- package/dist-cjs/md/match.cjs +47 -0
- package/dist-cjs/md/normalize.cjs +13 -0
- package/dist-cjs/md/outline.cjs +49 -0
- package/dist-cjs/md/parse.cjs +199 -0
- package/dist-cjs/ofs/adapter.cjs +195 -0
- package/dist-cjs/ofs/enricher.cjs +151 -0
- package/dist-cjs/ofs/infer.cjs +63 -0
- package/dist-cjs/ofs/issuesEnvelope.cjs +76 -0
- package/dist-cjs/ofs/memory.cjs +26 -0
- package/dist-cjs/ofs/parser.cjs +373 -0
- package/dist-cjs/ofs/stringify.cjs +45 -0
- package/dist-cjs/pipeline/enforce.cjs +49 -0
- package/dist-cjs/pipeline/kind.cjs +30 -0
- package/dist-cjs/pipeline/repair.cjs +115 -0
- package/dist-cjs/strictness/container.cjs +49 -0
- package/dist-cjs/strictness/processor.cjs +32 -0
- package/dist-cjs/strictness/types.cjs +109 -0
- package/dist-cjs/tokens/auto-fix.cjs +59 -0
- package/dist-cjs/tokens/cognitive-cost.cjs +209 -0
- package/dist-cjs/tokens/compliance.cjs +74 -0
- package/dist-cjs/tokens/confidence.cjs +335 -0
- package/dist-cjs/tokens/estimator.cjs +157 -0
- package/dist-cjs/tokens/improvements.cjs +701 -0
- package/dist-cjs/tokens/index.cjs +74 -0
- package/dist-cjs/tokens/parser.cjs +100 -0
- package/dist-cjs/tokens/patterns.cjs +23 -0
- package/dist-cjs/tokens/runtime-estimator.cjs +74 -0
- package/dist-cjs/tokens/smart-report.cjs +191 -0
- package/dist-cjs/tokens/spec-estimator.cjs +125 -0
- package/dist-cjs/tokens/types.cjs +2 -0
- package/dist-cjs/tokens/validator.cjs +62 -0
- package/dist-cjs/types.cjs +2 -0
- package/dist-cjs/validate/compliance.cjs +103 -0
- package/dist-cjs/validate/connection.cjs +47 -0
- package/dist-cjs/validate/types.cjs +2 -0
- package/dist-cjs/validate/validate.cjs +319 -0
- package/docs/consumption.md +1 -1
- package/package.json +14 -8
package/dist/ofs/enricher.js
CHANGED
|
@@ -1,13 +1,8 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.buildMarkdownGuidance = buildMarkdownGuidance;
|
|
4
|
-
exports.enrichInstructions = enrichInstructions;
|
|
5
|
-
exports.enrichInstructionsWithFlexMd = enrichInstructionsWithFlexMd;
|
|
6
1
|
/**
|
|
7
2
|
* Generates Markdown guidance instructions for the LLM based on the OFS and contract level.
|
|
8
3
|
* Strictly avoids the word "flex-md" and remains "tax-aware" by only including relevant rules.
|
|
9
4
|
*/
|
|
10
|
-
function buildMarkdownGuidance(spec, strict, opts) {
|
|
5
|
+
export function buildMarkdownGuidance(spec, strict, opts) {
|
|
11
6
|
const level = strict.level ?? 0;
|
|
12
7
|
const fence = opts?.containerFence === "flexmd" ? "```flexmd" : "```markdown";
|
|
13
8
|
// L0 - Minimal Markdown
|
|
@@ -85,14 +80,14 @@ function buildMarkdownGuidance(spec, strict, opts) {
|
|
|
85
80
|
/**
|
|
86
81
|
* @deprecated Use buildMarkdownGuidance
|
|
87
82
|
*/
|
|
88
|
-
function enrichInstructions(spec, strict) {
|
|
83
|
+
export function enrichInstructions(spec, strict) {
|
|
89
84
|
return buildMarkdownGuidance(spec, strict);
|
|
90
85
|
}
|
|
91
86
|
/**
|
|
92
87
|
* Enrich instructions with flex-md compliance guidance.
|
|
93
88
|
* Returns detailed information about what was changed.
|
|
94
89
|
*/
|
|
95
|
-
async function enrichInstructionsWithFlexMd(instructions, strictnessLevel, spec // Optional spec, if provided will include section guidance
|
|
90
|
+
export async function enrichInstructionsWithFlexMd(instructions, strictnessLevel, spec // Optional spec, if provided will include section guidance
|
|
96
91
|
) {
|
|
97
92
|
const originalLength = instructions.length;
|
|
98
93
|
const level = parseInt(strictnessLevel.slice(1));
|
package/dist/ofs/infer.js
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.inferOfsFromMarkdown = inferOfsFromMarkdown;
|
|
4
|
-
const parse_js_1 = require("../md/parse.js");
|
|
1
|
+
import { parseHeadingsAndSections, extractBullets } from "../md/parse.js";
|
|
5
2
|
/**
|
|
6
3
|
* Infers an OutputFormatSpec from a Markdown string.
|
|
7
4
|
*/
|
|
8
|
-
function inferOfsFromMarkdown(md) {
|
|
5
|
+
export function inferOfsFromMarkdown(md) {
|
|
9
6
|
// Collect all bullet names that look like headers ("- Name")
|
|
10
7
|
const lines = md.split("\n");
|
|
11
8
|
const bulletNames = [];
|
|
@@ -16,13 +13,13 @@ function inferOfsFromMarkdown(md) {
|
|
|
16
13
|
bulletNames.push(m[1].trim());
|
|
17
14
|
}
|
|
18
15
|
}
|
|
19
|
-
const sections =
|
|
16
|
+
const sections = parseHeadingsAndSections(md, { bulletNames });
|
|
20
17
|
const specSections = [];
|
|
21
18
|
for (const sec of sections) {
|
|
22
19
|
const name = sec.heading.name;
|
|
23
20
|
const body = sec.body.trim();
|
|
24
21
|
// 1. Detect list
|
|
25
|
-
const bullets =
|
|
22
|
+
const bullets = extractBullets(body);
|
|
26
23
|
if (bullets.length > 0) {
|
|
27
24
|
specSections.push({
|
|
28
25
|
name,
|
|
@@ -1,13 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
exports.buildIssuesEnvelope = buildIssuesEnvelope;
|
|
5
|
-
exports.buildIssuesEnvelopeAuto = buildIssuesEnvelopeAuto;
|
|
6
|
-
const parse_js_1 = require("../md/parse.js");
|
|
7
|
-
function parseIssuesEnvelope(md) {
|
|
8
|
-
return (0, parse_js_1.isIssuesEnvelopeCheck)(md);
|
|
1
|
+
import { isIssuesEnvelopeCheck } from "../md/parse.js";
|
|
2
|
+
export function parseIssuesEnvelope(md) {
|
|
3
|
+
return isIssuesEnvelopeCheck(md);
|
|
9
4
|
}
|
|
10
|
-
function buildIssuesEnvelope(args) {
|
|
5
|
+
export function buildIssuesEnvelope(args) {
|
|
11
6
|
const issues = args.validation.issues
|
|
12
7
|
.filter(i => i.severity === "warn" || i.severity === "error")
|
|
13
8
|
.map(i => `- ${i.message}`);
|
|
@@ -32,7 +27,7 @@ function buildIssuesEnvelope(args) {
|
|
|
32
27
|
"",
|
|
33
28
|
].join("\n");
|
|
34
29
|
}
|
|
35
|
-
function buildIssuesEnvelopeAuto(args) {
|
|
30
|
+
export function buildIssuesEnvelopeAuto(args) {
|
|
36
31
|
const v = args.validation;
|
|
37
32
|
const expected = [];
|
|
38
33
|
const found = [];
|
package/dist/ofs/memory.js
CHANGED
|
@@ -1,26 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.remember = remember;
|
|
4
|
-
exports.recall = recall;
|
|
5
|
-
const parser_js_1 = require("./parser.js");
|
|
6
|
-
const node_crypto_1 = require("node:crypto");
|
|
1
|
+
import { parseOutputFormatSpec } from "./parser.js";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
7
3
|
const specMemory = new Map();
|
|
8
4
|
/**
|
|
9
5
|
* Parses Flex-MD instructions and "remembers" the Output Format Spec.
|
|
10
6
|
* Returns a unique recallId that can be used later.
|
|
11
7
|
*/
|
|
12
|
-
function remember(instructions) {
|
|
13
|
-
const spec =
|
|
8
|
+
export function remember(instructions) {
|
|
9
|
+
const spec = parseOutputFormatSpec(instructions);
|
|
14
10
|
if (!spec) {
|
|
15
11
|
throw new Error("No valid Output Format Spec found in instructions.");
|
|
16
12
|
}
|
|
17
|
-
const id =
|
|
13
|
+
const id = randomUUID();
|
|
18
14
|
specMemory.set(id, spec);
|
|
19
15
|
return id;
|
|
20
16
|
}
|
|
21
17
|
/**
|
|
22
18
|
* Recalls a previously remembered Output Format Spec.
|
|
23
19
|
*/
|
|
24
|
-
function recall(id) {
|
|
20
|
+
export function recall(id) {
|
|
25
21
|
return specMemory.get(id);
|
|
26
22
|
}
|
package/dist/ofs/parser.js
CHANGED
|
@@ -1,15 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.validateFormat = validateFormat;
|
|
4
|
-
exports.parseOutputFormatSpec = parseOutputFormatSpec;
|
|
5
|
-
exports.parseInputFormatSpec = parseInputFormatSpec;
|
|
6
|
-
exports.parseFormatSpecs = parseFormatSpecs;
|
|
7
|
-
const parse_js_1 = require("../md/parse.js");
|
|
1
|
+
import { normalizeName } from "../md/parse.js";
|
|
8
2
|
/**
|
|
9
3
|
* Validate a format specification.
|
|
10
4
|
* Returns detailed validation results.
|
|
11
5
|
*/
|
|
12
|
-
async function validateFormat(formatSpec, formatType = "flex-md") {
|
|
6
|
+
export async function validateFormat(formatSpec, formatType = "flex-md") {
|
|
13
7
|
const issues = [];
|
|
14
8
|
const suggestions = [];
|
|
15
9
|
if (formatType === "json-schema") {
|
|
@@ -75,7 +69,7 @@ async function validateFormat(formatSpec, formatType = "flex-md") {
|
|
|
75
69
|
}
|
|
76
70
|
};
|
|
77
71
|
}
|
|
78
|
-
function parseOutputFormatSpec(md, opts = {}) {
|
|
72
|
+
export function parseOutputFormatSpec(md, opts = {}) {
|
|
79
73
|
const headingRx = opts.headingRegex ?? /^##\s*Output format\b/i;
|
|
80
74
|
const lines = md.split("\n");
|
|
81
75
|
// find OFS start
|
|
@@ -150,7 +144,7 @@ function parseOutputFormatSpec(md, opts = {}) {
|
|
|
150
144
|
if (headingMatch) {
|
|
151
145
|
const name = headingMatch[1].trim();
|
|
152
146
|
// Don't re-parse "Output format" itself if it somehow gets in here
|
|
153
|
-
if (
|
|
147
|
+
if (normalizeName(name) !== "output format") {
|
|
154
148
|
const s = { name, kind: "text" };
|
|
155
149
|
sections.push(s);
|
|
156
150
|
currentSection = s;
|
|
@@ -252,7 +246,7 @@ function parseRequiredOptional(s) {
|
|
|
252
246
|
* Parse an Input Format Spec block from Markdown.
|
|
253
247
|
* Uses the same parsing logic as Output Format Spec.
|
|
254
248
|
*/
|
|
255
|
-
function parseInputFormatSpec(md, opts = {}) {
|
|
249
|
+
export function parseInputFormatSpec(md, opts = {}) {
|
|
256
250
|
const headingRx = opts.headingRegex ?? /^##\s*Input format\b/i;
|
|
257
251
|
const lines = md.split("\n");
|
|
258
252
|
// find Input Format Spec start
|
|
@@ -327,7 +321,7 @@ function parseInputFormatSpec(md, opts = {}) {
|
|
|
327
321
|
if (headingMatch) {
|
|
328
322
|
const name = headingMatch[1].trim();
|
|
329
323
|
// Don't re-parse "Input format" itself if it somehow gets in here
|
|
330
|
-
if (
|
|
324
|
+
if (normalizeName(name) !== "input format") {
|
|
331
325
|
const s = { name, kind: "text" };
|
|
332
326
|
sections.push(s);
|
|
333
327
|
currentSection = s;
|
|
@@ -363,7 +357,7 @@ function parseInputFormatSpec(md, opts = {}) {
|
|
|
363
357
|
* Extract both Input and Output Format Specs from instructions text.
|
|
364
358
|
* This function searches for both "## Input format" and "## Output format" sections.
|
|
365
359
|
*/
|
|
366
|
-
function parseFormatSpecs(instructions, opts = {}) {
|
|
360
|
+
export function parseFormatSpecs(instructions, opts = {}) {
|
|
367
361
|
const input = parseInputFormatSpec(instructions, opts);
|
|
368
362
|
const output = parseOutputFormatSpec(instructions, opts);
|
|
369
363
|
return {
|
package/dist/ofs/stringify.js
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.stringifyOutputFormatSpec = stringifyOutputFormatSpec;
|
|
4
1
|
/**
|
|
5
2
|
* Convert an OutputFormatSpec to a formal "Instructions Output Format Block".
|
|
6
3
|
*/
|
|
7
|
-
function stringifyOutputFormatSpec(spec) {
|
|
4
|
+
export function stringifyOutputFormatSpec(spec) {
|
|
8
5
|
const lines = [];
|
|
9
6
|
lines.push(`## Output format (Markdown)`);
|
|
10
7
|
if (spec.description) {
|
package/dist/pipeline/enforce.js
CHANGED
|
@@ -1,23 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const repair_js_1 = require("./repair.js");
|
|
7
|
-
const processor_js_1 = require("../strictness/processor.js");
|
|
8
|
-
const issuesEnvelope_js_1 = require("../ofs/issuesEnvelope.js");
|
|
1
|
+
import { strictnessDefaults } from "../strictness/types.js";
|
|
2
|
+
import { detectResponseKind } from "./kind.js";
|
|
3
|
+
import { repairToMarkdownLevel } from "./repair.js";
|
|
4
|
+
import { processResponseMarkdown } from "../strictness/processor.js";
|
|
5
|
+
import { buildIssuesEnvelopeAuto } from "../ofs/issuesEnvelope.js";
|
|
9
6
|
/**
|
|
10
7
|
* Main pipeline: detect, optionally repair, and enforce Markdown contract constraints.
|
|
11
8
|
*/
|
|
12
|
-
function enforceFlexMd(text, spec, strictInput = {}, options = {}) {
|
|
9
|
+
export function enforceFlexMd(text, spec, strictInput = {}, options = {}) {
|
|
13
10
|
const level = strictInput.level ?? 0;
|
|
14
|
-
const strict = { ...
|
|
11
|
+
const strict = { ...strictnessDefaults(level), ...strictInput };
|
|
15
12
|
const autoFix = options.autoFix ?? true;
|
|
16
13
|
// 1. Kind detection
|
|
17
|
-
const detected =
|
|
14
|
+
const detected = detectResponseKind(text, spec);
|
|
18
15
|
if (detected.kind === "issues") {
|
|
19
16
|
return {
|
|
20
|
-
...
|
|
17
|
+
...processResponseMarkdown(text, spec, strict),
|
|
21
18
|
kind: "issues",
|
|
22
19
|
outputText: text
|
|
23
20
|
};
|
|
@@ -26,15 +23,15 @@ function enforceFlexMd(text, spec, strictInput = {}, options = {}) {
|
|
|
26
23
|
let currentText = text;
|
|
27
24
|
let repairedInfo;
|
|
28
25
|
if (autoFix) {
|
|
29
|
-
repairedInfo =
|
|
26
|
+
repairedInfo = repairToMarkdownLevel(currentText, spec, level);
|
|
30
27
|
currentText = repairedInfo.output;
|
|
31
28
|
}
|
|
32
29
|
// 3. Enforce
|
|
33
|
-
const result =
|
|
30
|
+
const result = processResponseMarkdown(currentText, spec, strict);
|
|
34
31
|
// 4. Mode B Fallback
|
|
35
32
|
let outputText = currentText;
|
|
36
33
|
if (!result.ok && level >= 1) {
|
|
37
|
-
outputText =
|
|
34
|
+
outputText = buildIssuesEnvelopeAuto({
|
|
38
35
|
validation: result.validation,
|
|
39
36
|
level,
|
|
40
37
|
requiredSectionNames: spec.sections.filter(s => s.required !== false).map(s => s.name)
|
package/dist/pipeline/kind.js
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const parse_js_1 = require("../md/parse.js");
|
|
5
|
-
function detectResponseKind(text, spec) {
|
|
6
|
-
const issuesResult = (0, parse_js_1.isIssuesEnvelopeCheck)(text);
|
|
1
|
+
import { isIssuesEnvelopeCheck } from "../md/parse.js";
|
|
2
|
+
export function detectResponseKind(text, spec) {
|
|
3
|
+
const issuesResult = isIssuesEnvelopeCheck(text);
|
|
7
4
|
const hasIssues = issuesResult.isIssuesEnvelope;
|
|
8
5
|
// Use more robust detection: check for both #+ Name and ===Name
|
|
9
6
|
const hasSections = spec.sections.some(s => {
|
package/dist/pipeline/repair.js
CHANGED
|
@@ -1,22 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.repairToMarkdownLevel = repairToMarkdownLevel;
|
|
4
|
-
const parse_js_1 = require("../md/parse.js");
|
|
1
|
+
import { extractFencedBlocks, parseHeadingsAndSections, normalizeName, isIssuesEnvelopeCheck } from "../md/parse.js";
|
|
5
2
|
/**
|
|
6
3
|
* Deterministic 9-step repair plan to transform input into the required Markdown structure.
|
|
7
4
|
*/
|
|
8
|
-
function repairToMarkdownLevel(input, spec, level, opts) {
|
|
5
|
+
export function repairToMarkdownLevel(input, spec, level, opts) {
|
|
9
6
|
const applied = [];
|
|
10
7
|
const noneValue = opts?.noneValue ?? spec.emptySectionValue ?? "None";
|
|
11
8
|
const preferHeadingLevel = opts?.preferHeadingLevel ?? 2;
|
|
12
9
|
// Step 0 — If Issues envelope, return as-is
|
|
13
|
-
if (
|
|
10
|
+
if (isIssuesEnvelopeCheck(input).isIssuesEnvelope) {
|
|
14
11
|
return { output: input, applied: [] };
|
|
15
12
|
}
|
|
16
13
|
// Step 1 — Normalize container (L2+ only)
|
|
17
14
|
let workingMd = input;
|
|
18
15
|
if (level >= 2) {
|
|
19
|
-
const fences =
|
|
16
|
+
const fences = extractFencedBlocks(workingMd);
|
|
20
17
|
if (fences.length === 0) {
|
|
21
18
|
workingMd = `\`\`\`markdown\n${workingMd.trim()}\n\`\`\`\n`;
|
|
22
19
|
applied.push("CONTAINER_WRAPPED");
|
|
@@ -44,7 +41,7 @@ function repairToMarkdownLevel(input, spec, level, opts) {
|
|
|
44
41
|
let contentToRepair = workingMd;
|
|
45
42
|
let isWrapped = false;
|
|
46
43
|
if (level >= 2) {
|
|
47
|
-
const fences =
|
|
44
|
+
const fences = extractFencedBlocks(workingMd);
|
|
48
45
|
if (fences.length === 1) {
|
|
49
46
|
contentToRepair = fences[0].content;
|
|
50
47
|
isWrapped = true;
|
|
@@ -63,14 +60,14 @@ function repairToMarkdownLevel(input, spec, level, opts) {
|
|
|
63
60
|
catch (e) { }
|
|
64
61
|
}
|
|
65
62
|
// Step 4 — Ensure required section headings exist (L1+)
|
|
66
|
-
let sections =
|
|
63
|
+
let sections = parseHeadingsAndSections(contentToRepair);
|
|
67
64
|
const existingNorms = new Set(sections.map(s => s.heading.norm));
|
|
68
65
|
for (const sSpec of spec.sections) {
|
|
69
|
-
if (sSpec.required !== false && !existingNorms.has(
|
|
66
|
+
if (sSpec.required !== false && !existingNorms.has(normalizeName(sSpec.name))) {
|
|
70
67
|
const hashes = "#".repeat(preferHeadingLevel);
|
|
71
68
|
contentToRepair = contentToRepair.trim() + `\n\n${hashes} ${sSpec.name}\n${noneValue}\n`;
|
|
72
69
|
applied.push(`SECTION_ADDED:${sSpec.name}`);
|
|
73
|
-
existingNorms.add(
|
|
70
|
+
existingNorms.add(normalizeName(sSpec.name));
|
|
74
71
|
}
|
|
75
72
|
}
|
|
76
73
|
// Step 5 — Move stray content (L1+)
|
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.extractSingleFence = extractSingleFence;
|
|
4
1
|
/**
|
|
5
2
|
* Extracts content from exactly one fenced block of the specified language.
|
|
6
3
|
*/
|
|
7
|
-
function extractSingleFence(text, fenceLang) {
|
|
4
|
+
export function extractSingleFence(text, fenceLang) {
|
|
8
5
|
const issues = [];
|
|
9
6
|
// Find first occurrence of opening fence
|
|
10
7
|
const startMarker = "```" + fenceLang;
|
|
@@ -1,16 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const validate_js_1 = require("../validate/validate.js");
|
|
5
|
-
const extract_js_1 = require("../extract/extract.js");
|
|
6
|
-
const issuesEnvelope_js_1 = require("../ofs/issuesEnvelope.js");
|
|
1
|
+
import { validateMarkdownAgainstOfs } from "../validate/validate.js";
|
|
2
|
+
import { extractFromMarkdown } from "../extract/extract.js";
|
|
3
|
+
import { parseIssuesEnvelope } from "../ofs/issuesEnvelope.js";
|
|
7
4
|
/**
|
|
8
5
|
* Unified entry point for processing a response against an OFS.
|
|
9
6
|
*/
|
|
10
|
-
function processResponseMarkdown(text, spec, strict // StrictnessOptions
|
|
7
|
+
export function processResponseMarkdown(text, spec, strict // StrictnessOptions
|
|
11
8
|
) {
|
|
12
9
|
const level = strict.level ?? 0;
|
|
13
|
-
const validation =
|
|
10
|
+
const validation = validateMarkdownAgainstOfs(text, spec, level, strict.policy);
|
|
14
11
|
const result = {
|
|
15
12
|
ok: validation.ok,
|
|
16
13
|
strictness: strict,
|
|
@@ -20,10 +17,10 @@ function processResponseMarkdown(text, spec, strict // StrictnessOptions
|
|
|
20
17
|
issues: validation.issues,
|
|
21
18
|
};
|
|
22
19
|
if (validation.ok) {
|
|
23
|
-
result.extracted =
|
|
20
|
+
result.extracted = extractFromMarkdown(text, spec);
|
|
24
21
|
}
|
|
25
22
|
else {
|
|
26
|
-
const issuesEnv =
|
|
23
|
+
const issuesEnv = parseIssuesEnvelope(text);
|
|
27
24
|
if (issuesEnv.isIssuesEnvelope) {
|
|
28
25
|
result.issuesEnvelope = issuesEnv;
|
|
29
26
|
}
|
package/dist/strictness/types.js
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.strictnessDefaults = strictnessDefaults;
|
|
4
|
-
function strictnessDefaults(level) {
|
|
1
|
+
export function strictnessDefaults(level) {
|
|
5
2
|
const common = {
|
|
6
3
|
tablesGuidance: "auto",
|
|
7
4
|
listsGuidance: "auto",
|
package/dist/tokens/auto-fix.js
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.autoFix = autoFix;
|
|
4
1
|
/**
|
|
5
2
|
* Automatically apply fixable improvements
|
|
6
3
|
*/
|
|
7
|
-
function autoFix(spec, improvements, options = {}) {
|
|
4
|
+
export function autoFix(spec, improvements, options = {}) {
|
|
8
5
|
const { applyQuickWinsOnly = false, maxPriority = 'low', skipManual = true } = options;
|
|
9
6
|
const priorityOrder = { critical: 0, high: 1, medium: 2, low: 3 };
|
|
10
7
|
const maxPriorityLevel = priorityOrder[maxPriority] ?? 3;
|
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.calculateCognitiveCost = calculateCognitiveCost;
|
|
4
|
-
exports.compareLevelCosts = compareLevelCosts;
|
|
5
|
-
const parser_js_1 = require("./parser.js");
|
|
6
|
-
const compliance_js_1 = require("./compliance.js");
|
|
1
|
+
import { parseSystemPart } from './parser.js';
|
|
2
|
+
import { detectSystemPartLevel } from './compliance.js';
|
|
7
3
|
/**
|
|
8
4
|
* Calculate cognitive cost of creating/maintaining spec
|
|
9
5
|
*/
|
|
10
|
-
function calculateCognitiveCost(spec) {
|
|
6
|
+
export function calculateCognitiveCost(spec) {
|
|
11
7
|
const perSection = [];
|
|
12
8
|
let totalCost = 0;
|
|
13
9
|
let complexityCost = 0;
|
|
@@ -38,8 +34,8 @@ function calculateCognitiveCost(spec) {
|
|
|
38
34
|
*/
|
|
39
35
|
function calculateSectionCost(section) {
|
|
40
36
|
const kind = section.kind || 'text';
|
|
41
|
-
const systemPart =
|
|
42
|
-
const level = systemPart ?
|
|
37
|
+
const systemPart = parseSystemPart(section.instruction, kind);
|
|
38
|
+
const level = systemPart ? detectSystemPartLevel(systemPart, kind) : null;
|
|
43
39
|
const factors = [];
|
|
44
40
|
let cost = 0;
|
|
45
41
|
// Base cost by level
|
|
@@ -170,7 +166,7 @@ function generateCostRecommendation(totalCost, sectionCount) {
|
|
|
170
166
|
/**
|
|
171
167
|
* Compare cognitive cost across different compliance levels
|
|
172
168
|
*/
|
|
173
|
-
function compareLevelCosts(spec) {
|
|
169
|
+
export function compareLevelCosts(spec) {
|
|
174
170
|
const costs = { 0: 0, 1: 0, 2: 0, 3: 0 };
|
|
175
171
|
// Simulate cost at each level
|
|
176
172
|
for (let level = 0; level <= 3; level++) {
|
|
@@ -1,12 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.detectSystemPartLevel = detectSystemPartLevel;
|
|
4
|
-
exports.checkSpecCompliance = checkSpecCompliance;
|
|
5
|
-
const parser_js_1 = require("./parser.js");
|
|
1
|
+
import { parseSystemPart } from './parser.js';
|
|
6
2
|
/**
|
|
7
3
|
* Detect the compliance level of a system part
|
|
8
4
|
*/
|
|
9
|
-
function detectSystemPartLevel(systemPart, kind) {
|
|
5
|
+
export function detectSystemPartLevel(systemPart, kind) {
|
|
10
6
|
const { parsed } = systemPart;
|
|
11
7
|
switch (parsed.type) {
|
|
12
8
|
case 'length':
|
|
@@ -35,13 +31,13 @@ function detectSystemPartLevel(systemPart, kind) {
|
|
|
35
31
|
/**
|
|
36
32
|
* Check if a spec complies with a target level
|
|
37
33
|
*/
|
|
38
|
-
function checkSpecCompliance(spec, targetLevel = 2) {
|
|
34
|
+
export function checkSpecCompliance(spec, targetLevel = 2) {
|
|
39
35
|
const violations = [];
|
|
40
36
|
let totalLevel = 0;
|
|
41
37
|
let compliantCount = 0;
|
|
42
38
|
for (const section of spec.sections) {
|
|
43
39
|
const kind = section.kind || 'text';
|
|
44
|
-
const systemPart =
|
|
40
|
+
const systemPart = parseSystemPart(section.instruction, kind);
|
|
45
41
|
const level = systemPart ? detectSystemPartLevel(systemPart, kind) : 0;
|
|
46
42
|
totalLevel += level;
|
|
47
43
|
if (level >= targetLevel) {
|
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.calculateConfidence = calculateConfidence;
|
|
4
|
-
const parser_js_1 = require("./parser.js");
|
|
5
|
-
const compliance_js_1 = require("./compliance.js");
|
|
1
|
+
import { parseSystemPart } from './parser.js';
|
|
2
|
+
import { detectSystemPartLevel } from './compliance.js';
|
|
6
3
|
/**
|
|
7
4
|
* Calculate confidence in token estimation
|
|
8
5
|
*/
|
|
9
|
-
function calculateConfidence(spec) {
|
|
6
|
+
export function calculateConfidence(spec) {
|
|
10
7
|
const bySection = [];
|
|
11
8
|
const factors = [];
|
|
12
9
|
let totalConfidence = 0;
|
|
@@ -52,9 +49,9 @@ function calculateConfidence(spec) {
|
|
|
52
49
|
*/
|
|
53
50
|
function analyzeSectionConfidence(section) {
|
|
54
51
|
const kind = section.kind || 'text';
|
|
55
|
-
const systemPart =
|
|
52
|
+
const systemPart = parseSystemPart(section.instruction, kind);
|
|
56
53
|
const hasSystemPart = systemPart !== null;
|
|
57
|
-
const level = systemPart ?
|
|
54
|
+
const level = systemPart ? detectSystemPartLevel(systemPart, kind) : null;
|
|
58
55
|
let confidence = 0;
|
|
59
56
|
let quality = 'none';
|
|
60
57
|
if (systemPart && level !== null) {
|
|
@@ -140,7 +137,7 @@ function getConfidenceAdjustment(systemPart, _section) {
|
|
|
140
137
|
*/
|
|
141
138
|
function calculateCoverageFactor(spec) {
|
|
142
139
|
const total = spec.sections.length;
|
|
143
|
-
const withSystemParts = spec.sections.filter(s =>
|
|
140
|
+
const withSystemParts = spec.sections.filter(s => parseSystemPart(s.instruction, s.kind || 'text') !== null).length;
|
|
144
141
|
const coverage = total > 0 ? (withSystemParts / total) * 100 : 0;
|
|
145
142
|
let score = 0;
|
|
146
143
|
let impact = 'neutral';
|
package/dist/tokens/estimator.js
CHANGED
|
@@ -1,11 +1,5 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.TOKEN_CONSTANTS = void 0;
|
|
4
|
-
exports.estimateTokens = estimateTokens;
|
|
5
|
-
exports.getFallbackEstimate = getFallbackEstimate;
|
|
6
|
-
exports.estimateTextTokens = estimateTextTokens;
|
|
7
1
|
// Calibrated token constants
|
|
8
|
-
|
|
2
|
+
export const TOKEN_CONSTANTS = {
|
|
9
3
|
// Text lengths (enumerated)
|
|
10
4
|
lengths: {
|
|
11
5
|
'1 sentence': 25,
|
|
@@ -27,7 +21,7 @@ exports.TOKEN_CONSTANTS = {
|
|
|
27
21
|
// Text token estimation (rough approximation: 1 token ≈ 4 characters)
|
|
28
22
|
charsPerToken: 4
|
|
29
23
|
};
|
|
30
|
-
function estimateTokens(systemPart) {
|
|
24
|
+
export function estimateTokens(systemPart) {
|
|
31
25
|
const { parsed } = systemPart;
|
|
32
26
|
switch (parsed.type) {
|
|
33
27
|
case 'length':
|
|
@@ -41,7 +35,7 @@ function estimateTokens(systemPart) {
|
|
|
41
35
|
}
|
|
42
36
|
}
|
|
43
37
|
function estimateTextLength(value) {
|
|
44
|
-
const estimated =
|
|
38
|
+
const estimated = TOKEN_CONSTANTS.lengths[value];
|
|
45
39
|
return {
|
|
46
40
|
estimated,
|
|
47
41
|
min: Math.floor(estimated * 0.7),
|
|
@@ -54,26 +48,26 @@ function estimateItems(parsed) {
|
|
|
54
48
|
if (max !== null) {
|
|
55
49
|
// Range: "3-5" → use average
|
|
56
50
|
const avg = (min + max) / 2;
|
|
57
|
-
const estimated = Math.round(avg *
|
|
51
|
+
const estimated = Math.round(avg * TOKEN_CONSTANTS.perItem);
|
|
58
52
|
return {
|
|
59
53
|
estimated,
|
|
60
|
-
min: min *
|
|
61
|
-
max: max *
|
|
54
|
+
min: min * TOKEN_CONSTANTS.perItem,
|
|
55
|
+
max: max * TOKEN_CONSTANTS.perItem,
|
|
62
56
|
confidence: 'high'
|
|
63
57
|
};
|
|
64
58
|
}
|
|
65
59
|
if (atLeast) {
|
|
66
60
|
// "at least 3" → estimate at min + 50%
|
|
67
|
-
const estimated = Math.round(min * 1.5 *
|
|
61
|
+
const estimated = Math.round(min * 1.5 * TOKEN_CONSTANTS.perItem);
|
|
68
62
|
return {
|
|
69
63
|
estimated,
|
|
70
|
-
min: min *
|
|
71
|
-
max: min * 3 *
|
|
64
|
+
min: min * TOKEN_CONSTANTS.perItem,
|
|
65
|
+
max: min * 3 * TOKEN_CONSTANTS.perItem,
|
|
72
66
|
confidence: 'medium'
|
|
73
67
|
};
|
|
74
68
|
}
|
|
75
69
|
// Exact: "3" → use exact value
|
|
76
|
-
const estimated = min *
|
|
70
|
+
const estimated = min * TOKEN_CONSTANTS.perItem;
|
|
77
71
|
return {
|
|
78
72
|
estimated,
|
|
79
73
|
min: Math.floor(estimated * 0.8),
|
|
@@ -92,15 +86,15 @@ function estimateTable(parsed) {
|
|
|
92
86
|
: parsed.columns.atLeast
|
|
93
87
|
? parsed.columns.min * 1.5
|
|
94
88
|
: parsed.columns.min;
|
|
95
|
-
const estimated = Math.round(rowAvg * colAvg *
|
|
89
|
+
const estimated = Math.round(rowAvg * colAvg * TOKEN_CONSTANTS.perTableCell);
|
|
96
90
|
const minCells = parsed.rows.min * parsed.columns.min;
|
|
97
91
|
const maxRows = parsed.rows.max || (parsed.rows.atLeast ? parsed.rows.min * 2 : parsed.rows.min);
|
|
98
92
|
const maxCols = parsed.columns.max || (parsed.columns.atLeast ? parsed.columns.min * 2 : parsed.columns.min);
|
|
99
93
|
const maxCells = maxRows * maxCols;
|
|
100
94
|
return {
|
|
101
95
|
estimated,
|
|
102
|
-
min: minCells *
|
|
103
|
-
max: maxCells *
|
|
96
|
+
min: minCells * TOKEN_CONSTANTS.perTableCell,
|
|
97
|
+
max: maxCells * TOKEN_CONSTANTS.perTableCell,
|
|
104
98
|
confidence: (parsed.rows.max && parsed.columns.max) ? 'high' : 'medium'
|
|
105
99
|
};
|
|
106
100
|
}
|
|
@@ -109,16 +103,16 @@ function estimateCodeLines(parsed) {
|
|
|
109
103
|
if (max !== null) {
|
|
110
104
|
// Range: "10-20"
|
|
111
105
|
const avg = (min + max) / 2;
|
|
112
|
-
const estimated = Math.round(avg *
|
|
106
|
+
const estimated = Math.round(avg * TOKEN_CONSTANTS.perCodeLine);
|
|
113
107
|
return {
|
|
114
108
|
estimated,
|
|
115
|
-
min: min *
|
|
116
|
-
max: max *
|
|
109
|
+
min: min * TOKEN_CONSTANTS.perCodeLine,
|
|
110
|
+
max: max * TOKEN_CONSTANTS.perCodeLine,
|
|
117
111
|
confidence: 'high'
|
|
118
112
|
};
|
|
119
113
|
}
|
|
120
114
|
// Exact or approximate: "10" or "~10"
|
|
121
|
-
const estimated = min *
|
|
115
|
+
const estimated = min * TOKEN_CONSTANTS.perCodeLine;
|
|
122
116
|
const variance = approximate ? 0.3 : 0.15;
|
|
123
117
|
return {
|
|
124
118
|
estimated,
|
|
@@ -128,7 +122,7 @@ function estimateCodeLines(parsed) {
|
|
|
128
122
|
};
|
|
129
123
|
}
|
|
130
124
|
// Fallback for sections without system parts
|
|
131
|
-
function getFallbackEstimate(kind, required) {
|
|
125
|
+
export function getFallbackEstimate(kind, required) {
|
|
132
126
|
const fallbacks = {
|
|
133
127
|
text: 150,
|
|
134
128
|
list: 200,
|
|
@@ -148,10 +142,10 @@ function getFallbackEstimate(kind, required) {
|
|
|
148
142
|
* Estimate tokens from plain text using character-based approximation.
|
|
149
143
|
* Uses a rule of thumb: ~4 characters per token (varies by model, but good approximation).
|
|
150
144
|
*/
|
|
151
|
-
function estimateTextTokens(text) {
|
|
145
|
+
export function estimateTextTokens(text) {
|
|
152
146
|
if (!text || text.length === 0)
|
|
153
147
|
return 0;
|
|
154
148
|
// Rough approximation: 1 token ≈ 4 characters for English text
|
|
155
149
|
// This is a common rule of thumb and works reasonably well for most cases
|
|
156
|
-
return Math.ceil(text.length /
|
|
150
|
+
return Math.ceil(text.length / TOKEN_CONSTANTS.charsPerToken);
|
|
157
151
|
}
|