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
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.detectImprovements = detectImprovements;
|
|
4
|
-
exports.formatImprovementReport = formatImprovementReport;
|
|
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
|
* Main improvement detector
|
|
9
5
|
*/
|
|
10
|
-
function detectImprovements(spec, targetLevel = 2) {
|
|
6
|
+
export function detectImprovements(spec, targetLevel = 2) {
|
|
11
7
|
const improvements = [];
|
|
12
8
|
const antiPatterns = [];
|
|
13
9
|
const optimizations = [];
|
|
@@ -36,8 +32,8 @@ function detectImprovements(spec, targetLevel = 2) {
|
|
|
36
32
|
function detectSectionImprovements(section, targetLevel) {
|
|
37
33
|
const improvements = [];
|
|
38
34
|
const kind = (section.kind || 'text');
|
|
39
|
-
const systemPart =
|
|
40
|
-
const currentLevel = systemPart ?
|
|
35
|
+
const systemPart = parseSystemPart(section.instruction, kind);
|
|
36
|
+
const currentLevel = systemPart ? detectSystemPartLevel(systemPart, kind) : null;
|
|
41
37
|
// 1. Missing system part
|
|
42
38
|
if (!systemPart) {
|
|
43
39
|
improvements.push({
|
|
@@ -319,7 +315,7 @@ function detectUnreasonableValues(systemPart, section) {
|
|
|
319
315
|
function detectSectionAntiPatterns(section) {
|
|
320
316
|
const patterns = [];
|
|
321
317
|
const kind = (section.kind || 'text');
|
|
322
|
-
const systemPart =
|
|
318
|
+
const systemPart = parseSystemPart(section.instruction, kind);
|
|
323
319
|
const isRequired = section.required !== false;
|
|
324
320
|
// Anti-pattern: Required section with no instruction at all
|
|
325
321
|
if (isRequired && !section.instruction) {
|
|
@@ -348,7 +344,7 @@ function detectSectionAntiPatterns(section) {
|
|
|
348
344
|
}
|
|
349
345
|
// Anti-pattern: Optional section with higher compliance than required
|
|
350
346
|
if (!isRequired && systemPart) {
|
|
351
|
-
const level =
|
|
347
|
+
const level = detectSystemPartLevel(systemPart, kind);
|
|
352
348
|
if (level === 3) {
|
|
353
349
|
patterns.push({
|
|
354
350
|
sectionName: section.name,
|
|
@@ -398,9 +394,9 @@ function detectSpecOptimizations(spec) {
|
|
|
398
394
|
const firstKind = (spec.sections[0].kind || 'text');
|
|
399
395
|
// Optimization: All sections at L1, could upgrade key ones to L2
|
|
400
396
|
const levels = spec.sections
|
|
401
|
-
.map(s =>
|
|
397
|
+
.map(s => parseSystemPart(s.instruction, (s.kind || 'text')))
|
|
402
398
|
.filter(sp => sp !== null)
|
|
403
|
-
.map(sp =>
|
|
399
|
+
.map(sp => detectSystemPartLevel(sp, firstKind));
|
|
404
400
|
const allL1 = levels.length > 0 && levels.every(l => l === 1);
|
|
405
401
|
if (allL1 && levels.length >= 3) {
|
|
406
402
|
opts.push({
|
|
@@ -428,7 +424,7 @@ function detectSpecOptimizations(spec) {
|
|
|
428
424
|
});
|
|
429
425
|
}
|
|
430
426
|
// Optimization: Too many sections without system parts
|
|
431
|
-
const withoutSystemParts = spec.sections.filter(s =>
|
|
427
|
+
const withoutSystemParts = spec.sections.filter(s => parseSystemPart(s.instruction, (s.kind || 'text')) === null);
|
|
432
428
|
if (withoutSystemParts.length > spec.sections.length * 0.3) {
|
|
433
429
|
opts.push({
|
|
434
430
|
type: 'simplify',
|
|
@@ -453,7 +449,7 @@ function detectSpecOptimizations(spec) {
|
|
|
453
449
|
// Optimization: All text sections could benefit from more specific lengths
|
|
454
450
|
const textSections = spec.sections.filter(s => (s.kind || 'text') === 'text');
|
|
455
451
|
const vagueLengths = textSections.filter(s => {
|
|
456
|
-
const sp =
|
|
452
|
+
const sp = parseSystemPart(s.instruction, 'text');
|
|
457
453
|
return sp?.parsed.type === 'length' &&
|
|
458
454
|
['brief', 'moderate', 'detailed', 'extensive'].includes(sp.parsed.value);
|
|
459
455
|
});
|
|
@@ -609,7 +605,7 @@ function byImpact(a, b) {
|
|
|
609
605
|
/**
|
|
610
606
|
* Format improvement report
|
|
611
607
|
*/
|
|
612
|
-
function formatImprovementReport(analysis) {
|
|
608
|
+
export function formatImprovementReport(analysis) {
|
|
613
609
|
const lines = [];
|
|
614
610
|
lines.push('\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2551');
|
|
615
611
|
lines.push('\u2551 IMPROVEMENT DETECTION REPORT \u2551');
|
package/dist/tokens/index.js
CHANGED
|
@@ -1,35 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
};
|
|
16
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.getMaxTokens = getMaxTokens;
|
|
18
|
-
exports.getMaxTokensFromInstructions = getMaxTokensFromInstructions;
|
|
19
|
-
const parser_js_1 = require("../ofs/parser.js");
|
|
20
|
-
const spec_estimator_js_1 = require("./spec-estimator.js");
|
|
21
|
-
__exportStar(require("./types.js"), exports);
|
|
22
|
-
__exportStar(require("./parser.js"), exports);
|
|
23
|
-
__exportStar(require("./estimator.js"), exports);
|
|
24
|
-
__exportStar(require("./spec-estimator.js"), exports);
|
|
25
|
-
__exportStar(require("./runtime-estimator.js"), exports);
|
|
26
|
-
__exportStar(require("./validator.js"), exports);
|
|
27
|
-
__exportStar(require("./compliance.js"), exports);
|
|
28
|
-
__exportStar(require("./cognitive-cost.js"), exports);
|
|
29
|
-
__exportStar(require("./confidence.js"), exports);
|
|
30
|
-
__exportStar(require("./smart-report.js"), exports);
|
|
31
|
-
__exportStar(require("./improvements.js"), exports);
|
|
32
|
-
__exportStar(require("./auto-fix.js"), exports);
|
|
1
|
+
import { parseOutputFormatSpec, parseFormatSpecs } from '../ofs/parser.js';
|
|
2
|
+
import { estimateSpecTokens, estimateFormatSpecsTokens } from './spec-estimator.js';
|
|
3
|
+
export * from './types.js';
|
|
4
|
+
export * from './parser.js';
|
|
5
|
+
export * from './estimator.js';
|
|
6
|
+
export * from './spec-estimator.js';
|
|
7
|
+
export * from './runtime-estimator.js';
|
|
8
|
+
export * from './validator.js';
|
|
9
|
+
export * from './compliance.js';
|
|
10
|
+
export * from './cognitive-cost.js';
|
|
11
|
+
export * from './confidence.js';
|
|
12
|
+
export * from './smart-report.js';
|
|
13
|
+
export * from './improvements.js';
|
|
14
|
+
export * from './auto-fix.js';
|
|
33
15
|
/**
|
|
34
16
|
* Convenience function: estimate max_tokens from spec
|
|
35
17
|
*
|
|
@@ -37,26 +19,26 @@ __exportStar(require("./auto-fix.js"), exports);
|
|
|
37
19
|
* @param options - Estimation options
|
|
38
20
|
* @returns Estimated max_tokens value
|
|
39
21
|
*/
|
|
40
|
-
function getMaxTokens(spec, options) {
|
|
22
|
+
export function getMaxTokens(spec, options) {
|
|
41
23
|
if (!spec)
|
|
42
24
|
return 0;
|
|
43
25
|
const extractFromInstructions = options?.extractFromInstructions ?? false;
|
|
44
26
|
// If extractFromInstructions is true and spec is a string, try to extract both formats
|
|
45
27
|
if (extractFromInstructions && typeof spec === 'string') {
|
|
46
|
-
const formatSpecs =
|
|
28
|
+
const formatSpecs = parseFormatSpecs(spec);
|
|
47
29
|
if (formatSpecs.input || formatSpecs.output) {
|
|
48
|
-
const estimate =
|
|
30
|
+
const estimate = estimateFormatSpecsTokens(formatSpecs.input, formatSpecs.output, options);
|
|
49
31
|
return estimate.total.estimated;
|
|
50
32
|
}
|
|
51
33
|
// Fall through to output-only parsing if no formats found
|
|
52
34
|
}
|
|
53
35
|
// Original behavior: parse as output format spec
|
|
54
36
|
const parsedSpec = typeof spec === 'string'
|
|
55
|
-
?
|
|
37
|
+
? parseOutputFormatSpec(spec)
|
|
56
38
|
: spec;
|
|
57
39
|
if (!parsedSpec)
|
|
58
40
|
return 0;
|
|
59
|
-
const estimate =
|
|
41
|
+
const estimate = estimateSpecTokens(parsedSpec, options);
|
|
60
42
|
return estimate.total.estimated;
|
|
61
43
|
}
|
|
62
44
|
/**
|
|
@@ -67,8 +49,8 @@ function getMaxTokens(spec, options) {
|
|
|
67
49
|
* @param options - Estimation options
|
|
68
50
|
* @returns Estimated max_tokens value based on both input and output formats
|
|
69
51
|
*/
|
|
70
|
-
function getMaxTokensFromInstructions(instructions, options) {
|
|
71
|
-
const formatSpecs =
|
|
72
|
-
const estimate =
|
|
52
|
+
export function getMaxTokensFromInstructions(instructions, options) {
|
|
53
|
+
const formatSpecs = parseFormatSpecs(instructions);
|
|
54
|
+
const estimate = estimateFormatSpecsTokens(formatSpecs.input, formatSpecs.output, options);
|
|
73
55
|
return estimate.total.estimated;
|
|
74
56
|
}
|
package/dist/tokens/parser.js
CHANGED
|
@@ -1,19 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.parseSystemPart = parseSystemPart;
|
|
4
|
-
const patterns_js_1 = require("./patterns.js");
|
|
5
|
-
function parseSystemPart(instruction, kind // Allow 'code' as a special case if needed
|
|
1
|
+
import { SYSTEM_PART_PATTERNS, INSTRUCTION_SPLIT } from './patterns.js';
|
|
2
|
+
export function parseSystemPart(instruction, kind // Allow 'code' as a special case if needed
|
|
6
3
|
) {
|
|
7
4
|
if (!instruction)
|
|
8
5
|
return null;
|
|
9
|
-
const pattern =
|
|
6
|
+
const pattern = SYSTEM_PART_PATTERNS[kind];
|
|
10
7
|
if (!pattern)
|
|
11
8
|
return null;
|
|
12
9
|
const match = instruction.match(pattern);
|
|
13
10
|
if (!match)
|
|
14
11
|
return null;
|
|
15
12
|
// Split into system and guidance parts
|
|
16
|
-
const parts = instruction.split(
|
|
13
|
+
const parts = instruction.split(INSTRUCTION_SPLIT);
|
|
17
14
|
const raw = parts[0];
|
|
18
15
|
const guidance = parts.slice(1).join('. ') || null;
|
|
19
16
|
const parsed = parseMatchByKind(kind, match);
|
package/dist/tokens/patterns.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
// patterns.ts
|
|
3
|
-
|
|
4
|
-
exports.INSTRUCTION_SPLIT = exports.SYSTEM_PART_PATTERNS = void 0;
|
|
5
|
-
exports.SYSTEM_PART_PATTERNS = {
|
|
2
|
+
export const SYSTEM_PART_PATTERNS = {
|
|
6
3
|
// TEXT: Enumerated literal strings only
|
|
7
4
|
text: /^Length:\s*(1\s+sentence|1-2\s+sentences|1\s+paragraph|2-3\s+paragraphs|brief|moderate|detailed|extensive)/i,
|
|
8
5
|
// LIST/ORDERED-LIST: [optional "at least"] + number + [optional range]
|
|
@@ -20,4 +17,4 @@ exports.SYSTEM_PART_PATTERNS = {
|
|
|
20
17
|
code: /^Lines:\s*(~)?(\d+)(?:-(\d+))?/i
|
|
21
18
|
};
|
|
22
19
|
// Separator for splitting system part from guidance
|
|
23
|
-
|
|
20
|
+
export const INSTRUCTION_SPLIT = /\.\s+/;
|
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const parser_js_1 = require("../ofs/parser.js");
|
|
5
|
-
const spec_estimator_js_1 = require("./spec-estimator.js");
|
|
6
|
-
const estimator_js_1 = require("./estimator.js");
|
|
1
|
+
import { parseFormatSpecs } from '../ofs/parser.js';
|
|
2
|
+
import { estimateFormatSpecsTokens } from './spec-estimator.js';
|
|
3
|
+
import { estimateTextTokens } from './estimator.js';
|
|
7
4
|
/**
|
|
8
5
|
* Estimate max_tokens for an LLM API call at runtime.
|
|
9
6
|
*
|
|
@@ -19,7 +16,7 @@ const estimator_js_1 = require("./estimator.js");
|
|
|
19
16
|
* @param params - Runtime estimation parameters
|
|
20
17
|
* @returns Token estimate with breakdown
|
|
21
18
|
*/
|
|
22
|
-
function runtimeEstimateTokens(params) {
|
|
19
|
+
export function runtimeEstimateTokens(params) {
|
|
23
20
|
const { prompt = '', context = '', instructions = '' } = params;
|
|
24
21
|
const opts = {
|
|
25
22
|
includeOptional: params.options?.includeOptional ?? true,
|
|
@@ -31,14 +28,14 @@ function runtimeEstimateTokens(params) {
|
|
|
31
28
|
additionalOverhead: params.options?.additionalOverhead ?? 0
|
|
32
29
|
};
|
|
33
30
|
// Extract format specs from instructions (only output format is used at runtime)
|
|
34
|
-
const formatSpecs =
|
|
31
|
+
const formatSpecs = parseFormatSpecs(instructions);
|
|
35
32
|
// Estimate tokens for each component
|
|
36
|
-
const promptTokens = opts.estimatePrompt ?
|
|
37
|
-
const contextTokens = opts.estimateContext ?
|
|
38
|
-
const instructionsTokens = opts.estimateInstructions ?
|
|
33
|
+
const promptTokens = opts.estimatePrompt ? estimateTextTokens(prompt) : 0;
|
|
34
|
+
const contextTokens = opts.estimateContext ? estimateTextTokens(context) : 0;
|
|
35
|
+
const instructionsTokens = opts.estimateInstructions ? estimateTextTokens(instructions) : 0;
|
|
39
36
|
// Estimate output tokens from output format spec (input format is for planning only)
|
|
40
37
|
const outputEstimate = formatSpecs.output
|
|
41
|
-
?
|
|
38
|
+
? estimateFormatSpecsTokens(undefined, formatSpecs.output, {
|
|
42
39
|
includeOptional: opts.includeOptional,
|
|
43
40
|
safetyMultiplier: 1.0, // Don't apply safety multiplier here, apply at the end
|
|
44
41
|
strategy: opts.strategy
|
|
@@ -1,19 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const compliance_js_1 = require("./compliance.js");
|
|
6
|
-
const cognitive_cost_js_1 = require("./cognitive-cost.js");
|
|
7
|
-
const confidence_js_1 = require("./confidence.js");
|
|
8
|
-
const spec_estimator_js_1 = require("./spec-estimator.js");
|
|
1
|
+
import { checkSpecCompliance } from './compliance.js';
|
|
2
|
+
import { calculateCognitiveCost } from './cognitive-cost.js';
|
|
3
|
+
import { calculateConfidence } from './confidence.js';
|
|
4
|
+
import { estimateSpecTokens } from './spec-estimator.js';
|
|
9
5
|
/**
|
|
10
6
|
* Comprehensive smart analysis of spec
|
|
11
7
|
*/
|
|
12
|
-
function analyzeSpec(spec, targetLevel = 2) {
|
|
13
|
-
const compliance =
|
|
14
|
-
const cognitiveCost =
|
|
15
|
-
const confidence =
|
|
16
|
-
const tokenEstimate =
|
|
8
|
+
export function analyzeSpec(spec, targetLevel = 2) {
|
|
9
|
+
const compliance = checkSpecCompliance(spec, targetLevel);
|
|
10
|
+
const cognitiveCost = calculateCognitiveCost(spec);
|
|
11
|
+
const confidence = calculateConfidence(spec);
|
|
12
|
+
const tokenEstimate = estimateSpecTokens(spec);
|
|
17
13
|
const recommendations = generateSmartRecommendations(compliance, cognitiveCost, confidence, tokenEstimate);
|
|
18
14
|
return {
|
|
19
15
|
spec,
|
|
@@ -85,7 +81,7 @@ function generateSmartRecommendations(compliance, cost, confidence, estimate) {
|
|
|
85
81
|
/**
|
|
86
82
|
* Format comprehensive smart report
|
|
87
83
|
*/
|
|
88
|
-
function formatSmartReport(analysis) {
|
|
84
|
+
export function formatSmartReport(analysis) {
|
|
89
85
|
const lines = [];
|
|
90
86
|
lines.push('╔═══════════════════════════════════════════════════╗');
|
|
91
87
|
lines.push('║ FLEX-MD SMART ANALYSIS REPORT ║');
|
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
exports.estimateInputSpecTokens = estimateInputSpecTokens;
|
|
5
|
-
exports.estimateFormatSpecsTokens = estimateFormatSpecsTokens;
|
|
6
|
-
const parser_js_1 = require("./parser.js");
|
|
7
|
-
const estimator_js_1 = require("./estimator.js");
|
|
8
|
-
function estimateSpecTokens(spec, options = {}) {
|
|
1
|
+
import { parseSystemPart } from './parser.js';
|
|
2
|
+
import { estimateTokens, getFallbackEstimate, TOKEN_CONSTANTS } from './estimator.js';
|
|
3
|
+
export function estimateSpecTokens(spec, options = {}) {
|
|
9
4
|
const { includeOptional = true, safetyMultiplier = 1.2, strategy = 'average' } = options;
|
|
10
5
|
const bySectionName = {};
|
|
11
6
|
let totalEstimated = 0;
|
|
@@ -17,13 +12,13 @@ function estimateSpecTokens(spec, options = {}) {
|
|
|
17
12
|
if (!includeOptional && !isRequired)
|
|
18
13
|
continue;
|
|
19
14
|
const kind = section.kind || 'text';
|
|
20
|
-
const systemPart =
|
|
15
|
+
const systemPart = parseSystemPart(section.instruction, kind);
|
|
21
16
|
let estimate;
|
|
22
17
|
if (systemPart) {
|
|
23
|
-
estimate =
|
|
18
|
+
estimate = estimateTokens(systemPart);
|
|
24
19
|
}
|
|
25
20
|
else {
|
|
26
|
-
estimate =
|
|
21
|
+
estimate = getFallbackEstimate(kind, isRequired);
|
|
27
22
|
}
|
|
28
23
|
// Apply optional section discount
|
|
29
24
|
if (!isRequired) {
|
|
@@ -40,8 +35,8 @@ function estimateSpecTokens(spec, options = {}) {
|
|
|
40
35
|
totalMax += estimate.max;
|
|
41
36
|
}
|
|
42
37
|
// Add overhead
|
|
43
|
-
const overhead =
|
|
44
|
-
(spec.sections.length *
|
|
38
|
+
const overhead = TOKEN_CONSTANTS.baseOverhead +
|
|
39
|
+
(spec.sections.length * TOKEN_CONSTANTS.headingOverhead);
|
|
45
40
|
totalEstimated += overhead;
|
|
46
41
|
totalMin += overhead;
|
|
47
42
|
totalMax += overhead;
|
|
@@ -75,7 +70,7 @@ function estimateSpecTokens(spec, options = {}) {
|
|
|
75
70
|
* Estimate tokens for an Input Format Spec.
|
|
76
71
|
* Uses the same logic as output format estimation.
|
|
77
72
|
*/
|
|
78
|
-
function estimateInputSpecTokens(spec, options = {}) {
|
|
73
|
+
export function estimateInputSpecTokens(spec, options = {}) {
|
|
79
74
|
// Input format uses the same structure as output format, so reuse the same logic
|
|
80
75
|
const outputSpec = {
|
|
81
76
|
...spec,
|
|
@@ -87,7 +82,7 @@ function estimateInputSpecTokens(spec, options = {}) {
|
|
|
87
82
|
* Estimate tokens for both input and output format specs.
|
|
88
83
|
* Combines estimates from both if present.
|
|
89
84
|
*/
|
|
90
|
-
function estimateFormatSpecsTokens(inputSpec, outputSpec, options = {}) {
|
|
85
|
+
export function estimateFormatSpecsTokens(inputSpec, outputSpec, options = {}) {
|
|
91
86
|
const inputEstimate = inputSpec ? estimateInputSpecTokens(inputSpec, options) : null;
|
|
92
87
|
const outputEstimate = outputSpec ? estimateSpecTokens(outputSpec, options) : null;
|
|
93
88
|
// If only one is present, return it
|
package/dist/tokens/types.js
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1
|
+
export {};
|
package/dist/tokens/validator.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.validateSystemParts = validateSystemParts;
|
|
4
|
-
const parser_js_1 = require("./parser.js");
|
|
5
|
-
function validateSystemParts(spec) {
|
|
1
|
+
import { parseSystemPart } from './parser.js';
|
|
2
|
+
export function validateSystemParts(spec) {
|
|
6
3
|
const errors = [];
|
|
7
4
|
const warnings = [];
|
|
8
5
|
for (const section of spec.sections) {
|
|
@@ -17,7 +14,7 @@ function validateSystemParts(spec) {
|
|
|
17
14
|
}
|
|
18
15
|
continue;
|
|
19
16
|
}
|
|
20
|
-
const systemPart =
|
|
17
|
+
const systemPart = parseSystemPart(section.instruction, kind);
|
|
21
18
|
if (!systemPart) {
|
|
22
19
|
warnings.push({
|
|
23
20
|
sectionName: section.name,
|
package/dist/types.js
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1
|
+
export {};
|
|
@@ -1,19 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.checkCompliance = checkCompliance;
|
|
4
|
-
exports.hasFlexMdContract = hasFlexMdContract;
|
|
5
|
-
const parser_js_1 = require("../ofs/parser.js");
|
|
1
|
+
import { parseFormatSpecs } from "../ofs/parser.js";
|
|
6
2
|
/**
|
|
7
3
|
* Check if instructions meet the required flex-md compliance level.
|
|
8
4
|
* Returns detailed results including what's missing or wrong.
|
|
9
5
|
* Now also checks for Input Format Spec if present.
|
|
10
6
|
*/
|
|
11
|
-
async function checkCompliance(instructions, complianceLevel) {
|
|
7
|
+
export async function checkCompliance(instructions, complianceLevel) {
|
|
12
8
|
const issues = [];
|
|
13
9
|
const suggestions = [];
|
|
14
10
|
const lower = instructions.toLowerCase();
|
|
15
11
|
// Extract both input and output format specs
|
|
16
|
-
const formatSpecs =
|
|
12
|
+
const formatSpecs = parseFormatSpecs(instructions);
|
|
17
13
|
const hasInputFormat = !!formatSpecs.input;
|
|
18
14
|
const hasOutputFormat = !!formatSpecs.output;
|
|
19
15
|
const hasMarkdownMention = lower.includes("markdown");
|
|
@@ -97,7 +93,7 @@ async function checkCompliance(instructions, complianceLevel) {
|
|
|
97
93
|
* Check if instructions meet the required flex-md compliance level.
|
|
98
94
|
* @deprecated Use checkCompliance for detailed results.
|
|
99
95
|
*/
|
|
100
|
-
async function hasFlexMdContract(instructions, complianceLevel) {
|
|
96
|
+
export async function hasFlexMdContract(instructions, complianceLevel) {
|
|
101
97
|
const result = await checkCompliance(instructions, complianceLevel);
|
|
102
98
|
return result.meetsCompliance;
|
|
103
99
|
}
|
|
@@ -1,14 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.checkConnection = checkConnection;
|
|
4
|
-
const outline_js_1 = require("../md/outline.js");
|
|
5
|
-
const parse_js_1 = require("../md/parse.js");
|
|
1
|
+
import { buildOutline } from "../md/outline.js";
|
|
2
|
+
import { normalizeName } from "../md/parse.js";
|
|
6
3
|
/**
|
|
7
4
|
* Checks if a specific key (section) is "connected" in the given markdown.
|
|
8
5
|
*/
|
|
9
|
-
function checkConnection(md, key) {
|
|
10
|
-
const outline =
|
|
11
|
-
const normKey =
|
|
6
|
+
export function checkConnection(md, key) {
|
|
7
|
+
const outline = buildOutline(md);
|
|
8
|
+
const normKey = normalizeName(key);
|
|
12
9
|
const path = [];
|
|
13
10
|
// Breadth-first search for the key
|
|
14
11
|
const queue = outline.nodes.map(n => ({ node: n, currentPath: [n.title] }));
|
package/dist/validate/types.js
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1
|
+
export {};
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.validateMarkdownAgainstOfs = validateMarkdownAgainstOfs;
|
|
4
|
-
const parse_js_1 = require("../md/parse.js");
|
|
1
|
+
import { extractFencedBlocks, parseHeadingsAndSections, normalizeName, isIssuesEnvelopeCheck } from "../md/parse.js";
|
|
5
2
|
function enforcementToSeverity(e) {
|
|
6
3
|
if (e === "ignore")
|
|
7
4
|
return null;
|
|
@@ -35,19 +32,19 @@ function isRequiredSection(spec, level) {
|
|
|
35
32
|
function stripToWorkingMarkdown(input, level) {
|
|
36
33
|
if (level < 2)
|
|
37
34
|
return { working: input, container: null };
|
|
38
|
-
const fences =
|
|
35
|
+
const fences = extractFencedBlocks(input);
|
|
39
36
|
if (fences.length === 1) {
|
|
40
37
|
const f = fences[0];
|
|
41
38
|
return { working: f.content, container: { fence: f } };
|
|
42
39
|
}
|
|
43
40
|
return { working: input, container: null };
|
|
44
41
|
}
|
|
45
|
-
function validateMarkdownAgainstOfs(input, spec, level, policyOverride) {
|
|
42
|
+
export function validateMarkdownAgainstOfs(input, spec, level, policyOverride) {
|
|
46
43
|
const policy = { ...defaultPolicy(level), ...(policyOverride ?? {}) };
|
|
47
44
|
const issues = [];
|
|
48
|
-
const fencesAll =
|
|
45
|
+
const fencesAll = extractFencedBlocks(input);
|
|
49
46
|
if (level === 0) {
|
|
50
|
-
const env =
|
|
47
|
+
const env = isIssuesEnvelopeCheck(input);
|
|
51
48
|
return {
|
|
52
49
|
ok: true,
|
|
53
50
|
level,
|
|
@@ -61,7 +58,7 @@ function validateMarkdownAgainstOfs(input, spec, level, policyOverride) {
|
|
|
61
58
|
},
|
|
62
59
|
};
|
|
63
60
|
}
|
|
64
|
-
const env =
|
|
61
|
+
const env = isIssuesEnvelopeCheck(input);
|
|
65
62
|
if (env.isIssuesEnvelope) {
|
|
66
63
|
issues.push({
|
|
67
64
|
code: "ISSUES_ENVELOPE_PRESENT",
|
|
@@ -110,10 +107,10 @@ function validateMarkdownAgainstOfs(input, spec, level, policyOverride) {
|
|
|
110
107
|
}
|
|
111
108
|
}
|
|
112
109
|
const { working } = stripToWorkingMarkdown(input, level);
|
|
113
|
-
const parsed =
|
|
110
|
+
const parsed = parseHeadingsAndSections(working);
|
|
114
111
|
const specByNorm = new Map();
|
|
115
112
|
for (const s of spec.sections)
|
|
116
|
-
specByNorm.set(
|
|
113
|
+
specByNorm.set(normalizeName(s.name), s);
|
|
117
114
|
const occurrences = new Map();
|
|
118
115
|
const bodiesByNorm = {};
|
|
119
116
|
for (const sec of parsed) {
|
|
@@ -128,7 +125,7 @@ function validateMarkdownAgainstOfs(input, spec, level, policyOverride) {
|
|
|
128
125
|
const req = isRequiredSection(s, level);
|
|
129
126
|
if (!req)
|
|
130
127
|
continue;
|
|
131
|
-
const norm =
|
|
128
|
+
const norm = normalizeName(s.name);
|
|
132
129
|
const count = occurrences.get(norm) ?? 0;
|
|
133
130
|
if (count === 0) {
|
|
134
131
|
missingRequired.push(s.name);
|
|
@@ -144,12 +141,12 @@ function validateMarkdownAgainstOfs(input, spec, level, policyOverride) {
|
|
|
144
141
|
const req = isRequiredSection(s, level);
|
|
145
142
|
if (!req)
|
|
146
143
|
continue;
|
|
147
|
-
const norm =
|
|
144
|
+
const norm = normalizeName(s.name);
|
|
148
145
|
const bodies = bodiesByNorm[norm] ?? [];
|
|
149
146
|
if (!bodies.length)
|
|
150
147
|
continue;
|
|
151
148
|
const allEmpty = bodies.every(b => b.trim().length === 0);
|
|
152
|
-
const allNone = bodies.every(b =>
|
|
149
|
+
const allNone = bodies.every(b => normalizeName(b) === normalizeName(noneValue));
|
|
153
150
|
const emptyByPolicy = allEmpty || (!policy.noneIsAcceptableContent && allNone);
|
|
154
151
|
if (emptyByPolicy) {
|
|
155
152
|
addIssue(issues, policy.emptyRequiredSection, {
|
|
@@ -173,14 +170,14 @@ function validateMarkdownAgainstOfs(input, spec, level, policyOverride) {
|
|
|
173
170
|
}
|
|
174
171
|
if (level >= 3) {
|
|
175
172
|
for (const s of spec.sections) {
|
|
176
|
-
const norm =
|
|
173
|
+
const norm = normalizeName(s.name);
|
|
177
174
|
const bodies = bodiesByNorm[norm] ?? [];
|
|
178
175
|
if (!bodies.length)
|
|
179
176
|
continue;
|
|
180
177
|
const kind = s.kind ?? "text";
|
|
181
178
|
for (const body of bodies) {
|
|
182
179
|
const b = body.trim();
|
|
183
|
-
if (
|
|
180
|
+
if (normalizeName(b) === normalizeName(noneValue))
|
|
184
181
|
continue;
|
|
185
182
|
if (kind === "text")
|
|
186
183
|
continue;
|
|
@@ -214,9 +211,9 @@ function validateMarkdownAgainstOfs(input, spec, level, policyOverride) {
|
|
|
214
211
|
});
|
|
215
212
|
continue;
|
|
216
213
|
}
|
|
217
|
-
const cols = (s.columns ?? []).map(c =>
|
|
214
|
+
const cols = (s.columns ?? []).map(c => normalizeName(c));
|
|
218
215
|
if (cols.length) {
|
|
219
|
-
const headerNorm = table.header.map(c =>
|
|
216
|
+
const headerNorm = table.header.map(c => normalizeName(c));
|
|
220
217
|
const missingCols = cols.filter(c => !headerNorm.includes(c));
|
|
221
218
|
if (missingCols.length) {
|
|
222
219
|
addIssue(issues, policy.malformedTable, {
|
|
@@ -227,7 +224,7 @@ function validateMarkdownAgainstOfs(input, spec, level, policyOverride) {
|
|
|
227
224
|
}
|
|
228
225
|
}
|
|
229
226
|
if (kind === "ordered_table") {
|
|
230
|
-
const header0 =
|
|
227
|
+
const header0 = normalizeName(table.header[0] ?? "");
|
|
231
228
|
if (header0 !== "#") {
|
|
232
229
|
addIssue(issues, policy.malformedOrderedTable, {
|
|
233
230
|
code: "MALFORMED_ORDERED_TABLE",
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
const index_js_1 = require("../index.cjs");
|
|
5
|
+
(0, vitest_1.describe)("Diagnostics", () => {
|
|
6
|
+
(0, vitest_1.describe)("checkCompliance", () => {
|
|
7
|
+
(0, vitest_1.it)("should return meetsCompliance: true for L0 if Markdown is mentioned", async () => {
|
|
8
|
+
const res = await (0, index_js_1.checkCompliance)("Reply in Markdown.", "L0");
|
|
9
|
+
(0, vitest_1.expect)(res.meetsCompliance).toBe(true);
|
|
10
|
+
(0, vitest_1.expect)(res.issues).toHaveLength(0);
|
|
11
|
+
});
|
|
12
|
+
(0, vitest_1.it)("should return issues for L2 if container is missing", async () => {
|
|
13
|
+
const res = await (0, index_js_1.checkCompliance)("Reply in Markdown. Include headings.", "L2");
|
|
14
|
+
(0, vitest_1.expect)(res.meetsCompliance).toBe(false);
|
|
15
|
+
(0, vitest_1.expect)(res.issues.some(i => i.type === "missing-container")).toBe(true);
|
|
16
|
+
});
|
|
17
|
+
(0, vitest_1.it)("should return false for hasFlexMdContract if requirements not met", async () => {
|
|
18
|
+
const ok = await (0, index_js_1.hasFlexMdContract)("Hello", "L0");
|
|
19
|
+
(0, vitest_1.expect)(ok).toBe(false);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
(0, vitest_1.describe)("enrichInstructionsWithFlexMd", () => {
|
|
23
|
+
(0, vitest_1.it)("should append guidance to existing instructions", async () => {
|
|
24
|
+
const res = await (0, index_js_1.enrichInstructionsWithFlexMd)("Do a good job.", "L0");
|
|
25
|
+
(0, vitest_1.expect)(res.enriched).toContain("Do a good job.");
|
|
26
|
+
(0, vitest_1.expect)(res.enriched).toContain("Reply in Markdown.");
|
|
27
|
+
(0, vitest_1.expect)(res.changes).toHaveLength(1);
|
|
28
|
+
(0, vitest_1.expect)(res.metadata?.guidanceAdded).toBe(true);
|
|
29
|
+
});
|
|
30
|
+
(0, vitest_1.it)("should track container addition for L2", async () => {
|
|
31
|
+
const res = await (0, index_js_1.enrichInstructionsWithFlexMd)("Do a good job.", "L2");
|
|
32
|
+
(0, vitest_1.expect)(res.changes.some(c => c.type === "added-container")).toBe(true);
|
|
33
|
+
(0, vitest_1.expect)(res.metadata?.containerAdded).toBe(true);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
(0, vitest_1.describe)("validateFormat", () => {
|
|
37
|
+
(0, vitest_1.it)("should validate a correct flex-md OFS", async () => {
|
|
38
|
+
const ofs = `## Output format\n- Summary — prose\n- Actions — list`;
|
|
39
|
+
const res = await (0, index_js_1.validateFormat)(ofs);
|
|
40
|
+
(0, vitest_1.expect)(res.valid).toBe(true);
|
|
41
|
+
(0, vitest_1.expect)(res.metadata?.sectionCount).toBe(2);
|
|
42
|
+
});
|
|
43
|
+
(0, vitest_1.it)("should return errors for missing heading", async () => {
|
|
44
|
+
const ofs = `- Summary — prose`;
|
|
45
|
+
const res = await (0, index_js_1.validateFormat)(ofs);
|
|
46
|
+
(0, vitest_1.expect)(res.valid).toBe(false);
|
|
47
|
+
(0, vitest_1.expect)(res.issues.some(i => i.type === "missing-heading")).toBe(true);
|
|
48
|
+
});
|
|
49
|
+
(0, vitest_1.it)("should validate JSON schema", async () => {
|
|
50
|
+
const schema = `{"type": "object"}`;
|
|
51
|
+
const res = await (0, index_js_1.validateFormat)(schema, "json-schema");
|
|
52
|
+
(0, vitest_1.expect)(res.valid).toBe(true);
|
|
53
|
+
});
|
|
54
|
+
(0, vitest_1.it)("should fail on invalid JSON schema", async () => {
|
|
55
|
+
const schema = `{"type": "object"`;
|
|
56
|
+
const res = await (0, index_js_1.validateFormat)(schema, "json-schema");
|
|
57
|
+
(0, vitest_1.expect)(res.valid).toBe(false);
|
|
58
|
+
(0, vitest_1.expect)(res.issues[0].type).toBe("syntax-error");
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
});
|