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.
Files changed (104) hide show
  1. package/README.md +1 -1
  2. package/dist/__tests__/diagnostics.test.js +45 -47
  3. package/dist/__tests__/ofs.test.js +28 -30
  4. package/dist/__tests__/structural.test.js +19 -21
  5. package/dist/__tests__/validate.test.js +27 -29
  6. package/dist/cli/index.js +13 -15
  7. package/dist/detect/json/detectIntent.js +1 -4
  8. package/dist/detect/json/detectMarkdown.js +29 -35
  9. package/dist/detect/json/detectPresence.js +2 -6
  10. package/dist/detect/json/index.js +10 -31
  11. package/dist/detect/json/types.js +1 -2
  12. package/dist/extract/extract.js +11 -14
  13. package/dist/extract/types.js +1 -2
  14. package/dist/index.js +22 -69
  15. package/dist/logger.js +3 -6
  16. package/dist/md/match.js +1 -4
  17. package/dist/md/normalize.js +1 -4
  18. package/dist/md/outline.js +4 -8
  19. package/dist/md/parse.js +11 -20
  20. package/dist/ofs/adapter.js +45 -49
  21. package/dist/ofs/enricher.js +3 -8
  22. package/dist/ofs/infer.js +4 -7
  23. package/dist/ofs/issuesEnvelope.js +5 -10
  24. package/dist/ofs/memory.js +6 -10
  25. package/dist/ofs/parser.js +7 -13
  26. package/dist/ofs/stringify.js +1 -4
  27. package/dist/pipeline/enforce.js +12 -15
  28. package/dist/pipeline/kind.js +3 -6
  29. package/dist/pipeline/repair.js +8 -11
  30. package/dist/strictness/container.js +1 -4
  31. package/dist/strictness/processor.js +7 -10
  32. package/dist/strictness/types.js +1 -4
  33. package/dist/tokens/auto-fix.js +1 -4
  34. package/dist/tokens/cognitive-cost.js +6 -10
  35. package/dist/tokens/compliance.js +4 -8
  36. package/dist/tokens/confidence.js +6 -9
  37. package/dist/tokens/estimator.js +20 -26
  38. package/dist/tokens/improvements.js +12 -16
  39. package/dist/tokens/index.js +22 -40
  40. package/dist/tokens/parser.js +4 -7
  41. package/dist/tokens/patterns.js +2 -5
  42. package/dist/tokens/runtime-estimator.js +9 -12
  43. package/dist/tokens/smart-report.js +10 -14
  44. package/dist/tokens/spec-estimator.js +10 -15
  45. package/dist/tokens/types.js +1 -2
  46. package/dist/tokens/validator.js +3 -6
  47. package/dist/types.js +1 -2
  48. package/dist/validate/compliance.js +4 -8
  49. package/dist/validate/connection.js +5 -8
  50. package/dist/validate/types.js +1 -2
  51. package/dist/validate/validate.js +16 -19
  52. package/dist-cjs/__tests__/diagnostics.test.cjs +61 -0
  53. package/dist-cjs/__tests__/ofs.test.cjs +53 -0
  54. package/dist-cjs/__tests__/structural.test.cjs +30 -0
  55. package/dist-cjs/__tests__/validate.test.cjs +110 -0
  56. package/dist-cjs/cli/index.cjs +110 -0
  57. package/dist-cjs/detect/json/detectIntent.cjs +82 -0
  58. package/dist-cjs/detect/json/detectMarkdown.cjs +304 -0
  59. package/dist-cjs/detect/json/detectPresence.cjs +195 -0
  60. package/dist-cjs/detect/json/index.cjs +34 -0
  61. package/dist-cjs/detect/json/types.cjs +2 -0
  62. package/dist-cjs/extract/extract.cjs +72 -0
  63. package/dist-cjs/extract/types.cjs +2 -0
  64. package/dist-cjs/flex-md-loader.cjs +102 -0
  65. package/dist-cjs/index.cjs +79 -0
  66. package/dist-cjs/logger.cjs +22 -0
  67. package/dist-cjs/md/match.cjs +47 -0
  68. package/dist-cjs/md/normalize.cjs +13 -0
  69. package/dist-cjs/md/outline.cjs +49 -0
  70. package/dist-cjs/md/parse.cjs +199 -0
  71. package/dist-cjs/ofs/adapter.cjs +195 -0
  72. package/dist-cjs/ofs/enricher.cjs +151 -0
  73. package/dist-cjs/ofs/infer.cjs +63 -0
  74. package/dist-cjs/ofs/issuesEnvelope.cjs +76 -0
  75. package/dist-cjs/ofs/memory.cjs +26 -0
  76. package/dist-cjs/ofs/parser.cjs +373 -0
  77. package/dist-cjs/ofs/stringify.cjs +45 -0
  78. package/dist-cjs/pipeline/enforce.cjs +49 -0
  79. package/dist-cjs/pipeline/kind.cjs +30 -0
  80. package/dist-cjs/pipeline/repair.cjs +115 -0
  81. package/dist-cjs/strictness/container.cjs +49 -0
  82. package/dist-cjs/strictness/processor.cjs +32 -0
  83. package/dist-cjs/strictness/types.cjs +109 -0
  84. package/dist-cjs/tokens/auto-fix.cjs +59 -0
  85. package/dist-cjs/tokens/cognitive-cost.cjs +209 -0
  86. package/dist-cjs/tokens/compliance.cjs +74 -0
  87. package/dist-cjs/tokens/confidence.cjs +335 -0
  88. package/dist-cjs/tokens/estimator.cjs +157 -0
  89. package/dist-cjs/tokens/improvements.cjs +701 -0
  90. package/dist-cjs/tokens/index.cjs +74 -0
  91. package/dist-cjs/tokens/parser.cjs +100 -0
  92. package/dist-cjs/tokens/patterns.cjs +23 -0
  93. package/dist-cjs/tokens/runtime-estimator.cjs +74 -0
  94. package/dist-cjs/tokens/smart-report.cjs +191 -0
  95. package/dist-cjs/tokens/spec-estimator.cjs +125 -0
  96. package/dist-cjs/tokens/types.cjs +2 -0
  97. package/dist-cjs/tokens/validator.cjs +62 -0
  98. package/dist-cjs/types.cjs +2 -0
  99. package/dist-cjs/validate/compliance.cjs +103 -0
  100. package/dist-cjs/validate/connection.cjs +47 -0
  101. package/dist-cjs/validate/types.cjs +2 -0
  102. package/dist-cjs/validate/validate.cjs +319 -0
  103. package/docs/consumption.md +1 -1
  104. package/package.json +14 -8
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.getMaxTokens = getMaxTokens;
18
+ exports.getMaxTokensFromInstructions = getMaxTokensFromInstructions;
19
+ const parser_js_1 = require("../ofs/parser.cjs");
20
+ const spec_estimator_js_1 = require("./spec-estimator.cjs");
21
+ __exportStar(require("./types.cjs"), exports);
22
+ __exportStar(require("./parser.cjs"), exports);
23
+ __exportStar(require("./estimator.cjs"), exports);
24
+ __exportStar(require("./spec-estimator.cjs"), exports);
25
+ __exportStar(require("./runtime-estimator.cjs"), exports);
26
+ __exportStar(require("./validator.cjs"), exports);
27
+ __exportStar(require("./compliance.cjs"), exports);
28
+ __exportStar(require("./cognitive-cost.cjs"), exports);
29
+ __exportStar(require("./confidence.cjs"), exports);
30
+ __exportStar(require("./smart-report.cjs"), exports);
31
+ __exportStar(require("./improvements.cjs"), exports);
32
+ __exportStar(require("./auto-fix.cjs"), exports);
33
+ /**
34
+ * Convenience function: estimate max_tokens from spec
35
+ *
36
+ * @param spec - OutputFormatSpec object, markdown string, or full instructions text
37
+ * @param options - Estimation options
38
+ * @returns Estimated max_tokens value
39
+ */
40
+ function getMaxTokens(spec, options) {
41
+ if (!spec)
42
+ return 0;
43
+ const extractFromInstructions = options?.extractFromInstructions ?? false;
44
+ // If extractFromInstructions is true and spec is a string, try to extract both formats
45
+ if (extractFromInstructions && typeof spec === 'string') {
46
+ const formatSpecs = (0, parser_js_1.parseFormatSpecs)(spec);
47
+ if (formatSpecs.input || formatSpecs.output) {
48
+ const estimate = (0, spec_estimator_js_1.estimateFormatSpecsTokens)(formatSpecs.input, formatSpecs.output, options);
49
+ return estimate.total.estimated;
50
+ }
51
+ // Fall through to output-only parsing if no formats found
52
+ }
53
+ // Original behavior: parse as output format spec
54
+ const parsedSpec = typeof spec === 'string'
55
+ ? (0, parser_js_1.parseOutputFormatSpec)(spec)
56
+ : spec;
57
+ if (!parsedSpec)
58
+ return 0;
59
+ const estimate = (0, spec_estimator_js_1.estimateSpecTokens)(parsedSpec, options);
60
+ return estimate.total.estimated;
61
+ }
62
+ /**
63
+ * Estimate max tokens from entire instructions text.
64
+ * Automatically extracts both input and output format specs if present.
65
+ *
66
+ * @param instructions - Full instructions text that may contain format specs
67
+ * @param options - Estimation options
68
+ * @returns Estimated max_tokens value based on both input and output formats
69
+ */
70
+ function getMaxTokensFromInstructions(instructions, options) {
71
+ const formatSpecs = (0, parser_js_1.parseFormatSpecs)(instructions);
72
+ const estimate = (0, spec_estimator_js_1.estimateFormatSpecsTokens)(formatSpecs.input, formatSpecs.output, options);
73
+ return estimate.total.estimated;
74
+ }
@@ -0,0 +1,100 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseSystemPart = parseSystemPart;
4
+ const patterns_js_1 = require("./patterns.cjs");
5
+ function parseSystemPart(instruction, kind // Allow 'code' as a special case if needed
6
+ ) {
7
+ if (!instruction)
8
+ return null;
9
+ const pattern = patterns_js_1.SYSTEM_PART_PATTERNS[kind];
10
+ if (!pattern)
11
+ return null;
12
+ const match = instruction.match(pattern);
13
+ if (!match)
14
+ return null;
15
+ // Split into system and guidance parts
16
+ const parts = instruction.split(patterns_js_1.INSTRUCTION_SPLIT);
17
+ const raw = parts[0];
18
+ const guidance = parts.slice(1).join('. ') || null;
19
+ const parsed = parseMatchByKind(kind, match);
20
+ if (!parsed)
21
+ return null;
22
+ return { raw, guidance, parsed };
23
+ }
24
+ function parseMatchByKind(kind, match) {
25
+ switch (kind) {
26
+ case 'text':
27
+ return parseTextMatch(match);
28
+ case 'list':
29
+ case 'ordered_list':
30
+ return parseItemsMatch(match);
31
+ case 'table':
32
+ case 'ordered_table':
33
+ return parseTableMatch(match);
34
+ case 'code':
35
+ return parseCodeMatch(match);
36
+ default:
37
+ return null;
38
+ }
39
+ }
40
+ function parseTextMatch(match) {
41
+ const raw = match[1].toLowerCase().replace(/\s+/g, ' ');
42
+ // Map to canonical LengthValue
43
+ const lengthMap = {
44
+ '1 sentence': '1 sentence',
45
+ '1-2 sentences': '1-2 sentences',
46
+ '1 paragraph': '1 paragraph',
47
+ '2-3 paragraphs': '2-3 paragraphs',
48
+ 'brief': 'brief',
49
+ 'moderate': 'moderate',
50
+ 'detailed': 'detailed',
51
+ 'extensive': 'extensive'
52
+ };
53
+ const value = lengthMap[raw] || 'moderate';
54
+ return { type: 'length', value };
55
+ }
56
+ function parseItemsMatch(match) {
57
+ // match[1] = "at least" (optional)
58
+ // match[2] = min number
59
+ // match[3] = max number (optional)
60
+ return {
61
+ type: 'items',
62
+ min: parseInt(match[2]),
63
+ max: match[3] ? parseInt(match[3]) : null,
64
+ atLeast: !!match[1]
65
+ };
66
+ }
67
+ function parseTableMatch(match) {
68
+ // match[1] = rows "at least" (optional)
69
+ // match[2] = rows min
70
+ // match[3] = rows max (optional)
71
+ // match[4] = columns "at least" (optional)
72
+ // match[5] = columns min
73
+ // match[6] = columns max (optional)
74
+ return {
75
+ type: 'table',
76
+ rows: {
77
+ min: parseInt(match[2]),
78
+ max: match[3] ? parseInt(match[3]) : null,
79
+ atLeast: !!match[1],
80
+ approximate: false
81
+ },
82
+ columns: {
83
+ min: parseInt(match[5]),
84
+ max: match[6] ? parseInt(match[6]) : null,
85
+ atLeast: !!match[4],
86
+ approximate: false
87
+ }
88
+ };
89
+ }
90
+ function parseCodeMatch(match) {
91
+ // match[1] = "~" (optional)
92
+ // match[2] = min number
93
+ // match[3] = max number (optional)
94
+ return {
95
+ type: 'lines',
96
+ min: parseInt(match[2]),
97
+ max: match[3] ? parseInt(match[3]) : null,
98
+ approximate: !!match[1]
99
+ };
100
+ }
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ // patterns.ts
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.INSTRUCTION_SPLIT = exports.SYSTEM_PART_PATTERNS = void 0;
5
+ exports.SYSTEM_PART_PATTERNS = {
6
+ // TEXT: Enumerated literal strings only
7
+ text: /^Length:\s*(1\s+sentence|1-2\s+sentences|1\s+paragraph|2-3\s+paragraphs|brief|moderate|detailed|extensive)/i,
8
+ // LIST/ORDERED-LIST: [optional "at least"] + number + [optional range]
9
+ // Matches: "3" | "3-5" | "at least 3"
10
+ list: /^Items:\s*(?:(at least)\s+)?(\d+)(?:-(\d+))?/i,
11
+ ordered_list: /^Items:\s*(?:(at least)\s+)?(\d+)(?:-(\d+))?/i,
12
+ // TABLE: Two numeric patterns (rows and columns)
13
+ // Matches: "Rows: 3, Columns: 5" | "Rows: 3-5, Columns: at least 2"
14
+ table: /^Rows:\s*(?:(at least)\s+)?(\d+)(?:-(\d+))?,\s*Columns:\s*(?:(at least)\s+)?(\d+)(?:-(\d+))?/i,
15
+ ordered_table: /^Rows:\s*(?:(at least)\s+)?(\d+)(?:-(\d+))?,\s*Columns:\s*(?:(at least)\s+)?(\d+)(?:-(\d+))?/i,
16
+ // CODE: [optional "~"] + number + [optional range]
17
+ // Matches: "10" | "10-20" | "~50"
18
+ // Note: SectionKind doesn't include 'code' currently, but we might handle it if it's added.
19
+ // For now, let's keep it but expect SectionKind to match.
20
+ code: /^Lines:\s*(~)?(\d+)(?:-(\d+))?/i
21
+ };
22
+ // Separator for splitting system part from guidance
23
+ exports.INSTRUCTION_SPLIT = /\.\s+/;
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runtimeEstimateTokens = runtimeEstimateTokens;
4
+ const parser_js_1 = require("../ofs/parser.cjs");
5
+ const spec_estimator_js_1 = require("./spec-estimator.cjs");
6
+ const estimator_js_1 = require("./estimator.cjs");
7
+ /**
8
+ * Estimate max_tokens for an LLM API call at runtime.
9
+ *
10
+ * This function estimates the total tokens needed by considering:
11
+ * - The prompt text (user input)
12
+ * - Context (previous messages, system messages, etc.)
13
+ * - Instructions (which may contain output format specs)
14
+ * - Expected output format (extracted from instructions)
15
+ *
16
+ * Note: Input format specs in instructions are ignored (they're for planning/design only).
17
+ * Only output format specs are used for runtime token estimation.
18
+ *
19
+ * @param params - Runtime estimation parameters
20
+ * @returns Token estimate with breakdown
21
+ */
22
+ function runtimeEstimateTokens(params) {
23
+ const { prompt = '', context = '', instructions = '' } = params;
24
+ const opts = {
25
+ includeOptional: params.options?.includeOptional ?? true,
26
+ safetyMultiplier: params.options?.safetyMultiplier ?? 1.2,
27
+ strategy: params.options?.strategy ?? 'average',
28
+ estimatePrompt: params.options?.estimatePrompt ?? true,
29
+ estimateContext: params.options?.estimateContext ?? true,
30
+ estimateInstructions: params.options?.estimateInstructions ?? true,
31
+ additionalOverhead: params.options?.additionalOverhead ?? 0
32
+ };
33
+ // Extract format specs from instructions (only output format is used at runtime)
34
+ const formatSpecs = (0, parser_js_1.parseFormatSpecs)(instructions);
35
+ // Estimate tokens for each component
36
+ const promptTokens = opts.estimatePrompt ? (0, estimator_js_1.estimateTextTokens)(prompt) : 0;
37
+ const contextTokens = opts.estimateContext ? (0, estimator_js_1.estimateTextTokens)(context) : 0;
38
+ const instructionsTokens = opts.estimateInstructions ? (0, estimator_js_1.estimateTextTokens)(instructions) : 0;
39
+ // Estimate output tokens from output format spec (input format is for planning only)
40
+ const outputEstimate = formatSpecs.output
41
+ ? (0, spec_estimator_js_1.estimateFormatSpecsTokens)(undefined, formatSpecs.output, {
42
+ includeOptional: opts.includeOptional,
43
+ safetyMultiplier: 1.0, // Don't apply safety multiplier here, apply at the end
44
+ strategy: opts.strategy
45
+ })
46
+ : {
47
+ total: { estimated: 0, min: 0, max: 0, confidence: 'low' },
48
+ bySectionName: {},
49
+ overhead: 0
50
+ };
51
+ // Calculate total input tokens (prompt + context + instructions)
52
+ const inputTokens = promptTokens + contextTokens + instructionsTokens;
53
+ // Calculate total output tokens (from format spec)
54
+ // Note: max_tokens parameter in LLM APIs refers to OUTPUT tokens only
55
+ const outputTokens = outputEstimate.total.estimated;
56
+ // Apply safety multiplier to output tokens only (this is what max_tokens represents)
57
+ const maxTokens = Math.ceil(outputTokens * opts.safetyMultiplier) + opts.additionalOverhead;
58
+ // Total tokens for budgeting/planning (input + output)
59
+ const totalTokens = inputTokens + outputTokens + opts.additionalOverhead;
60
+ // Determine confidence based on output spec confidence
61
+ const confidence = outputEstimate.total.confidence;
62
+ return {
63
+ maxTokens, // This is the value to use for max_tokens API parameter (output only)
64
+ breakdown: {
65
+ prompt: promptTokens,
66
+ context: contextTokens,
67
+ instructions: instructionsTokens,
68
+ output: outputEstimate,
69
+ additionalOverhead: opts.additionalOverhead,
70
+ total: totalTokens // Total for budgeting (input + output)
71
+ },
72
+ confidence
73
+ };
74
+ }
@@ -0,0 +1,191 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.analyzeSpec = analyzeSpec;
4
+ exports.formatSmartReport = formatSmartReport;
5
+ const compliance_js_1 = require("./compliance.cjs");
6
+ const cognitive_cost_js_1 = require("./cognitive-cost.cjs");
7
+ const confidence_js_1 = require("./confidence.cjs");
8
+ const spec_estimator_js_1 = require("./spec-estimator.cjs");
9
+ /**
10
+ * Comprehensive smart analysis of spec
11
+ */
12
+ function analyzeSpec(spec, targetLevel = 2) {
13
+ const compliance = (0, compliance_js_1.checkSpecCompliance)(spec, targetLevel);
14
+ const cognitiveCost = (0, cognitive_cost_js_1.calculateCognitiveCost)(spec);
15
+ const confidence = (0, confidence_js_1.calculateConfidence)(spec);
16
+ const tokenEstimate = (0, spec_estimator_js_1.estimateSpecTokens)(spec);
17
+ const recommendations = generateSmartRecommendations(compliance, cognitiveCost, confidence, tokenEstimate);
18
+ return {
19
+ spec,
20
+ compliance,
21
+ cognitiveCost,
22
+ confidence,
23
+ tokenEstimate,
24
+ recommendations
25
+ };
26
+ }
27
+ function generateSmartRecommendations(compliance, cost, confidence, estimate) {
28
+ const recs = [];
29
+ // High priority: Compliance issues
30
+ if (!compliance.compliant && compliance.violations.length > 0) {
31
+ recs.push({
32
+ priority: 'high',
33
+ category: 'quality',
34
+ message: `${compliance.violations.length} sections don't meet L${compliance.level} compliance`,
35
+ action: 'Add or upgrade system parts in flagged sections'
36
+ });
37
+ }
38
+ // High priority: Low confidence
39
+ if (confidence.overall < 70) {
40
+ recs.push({
41
+ priority: 'high',
42
+ category: 'confidence',
43
+ message: `Token estimation confidence is ${confidence.grade} (${confidence.overall.toFixed(0)}%)`,
44
+ action: confidence.recommendations[0]
45
+ });
46
+ }
47
+ // Medium priority: High cognitive cost
48
+ if (cost.totalCost > 60) {
49
+ recs.push({
50
+ priority: 'medium',
51
+ category: 'cost',
52
+ message: `Cognitive cost is high (${cost.totalCost.toFixed(0)}/100)`,
53
+ action: 'Consider reducing some sections to L2 or L1'
54
+ });
55
+ }
56
+ // Medium priority: Unreasonable token estimate
57
+ if (estimate.total.estimated > 4000) {
58
+ recs.push({
59
+ priority: 'medium',
60
+ category: 'quality',
61
+ message: `Estimated ${estimate.total.estimated} tokens - may be too large`,
62
+ action: 'Consider reducing scope or splitting into multiple prompts'
63
+ });
64
+ }
65
+ // Low priority: Optimization opportunities
66
+ if (confidence.overall >= 70 && confidence.overall < 90) {
67
+ recs.push({
68
+ priority: 'low',
69
+ category: 'confidence',
70
+ message: 'Good confidence, but can be improved',
71
+ action: 'Upgrade a few sections to L3 for better precision'
72
+ });
73
+ }
74
+ // Low priority: Cost optimization
75
+ if (cost.totalCost < 30 && confidence.overall > 80) {
76
+ recs.push({
77
+ priority: 'low',
78
+ category: 'cost',
79
+ message: 'Excellent balance of cost and confidence',
80
+ action: 'No changes needed'
81
+ });
82
+ }
83
+ return recs;
84
+ }
85
+ /**
86
+ * Format comprehensive smart report
87
+ */
88
+ function formatSmartReport(analysis) {
89
+ const lines = [];
90
+ lines.push('╔═══════════════════════════════════════════════════╗');
91
+ lines.push('║ FLEX-MD SMART ANALYSIS REPORT ║');
92
+ lines.push('╚═══════════════════════════════════════════════════╝');
93
+ lines.push('');
94
+ // Summary Dashboard
95
+ lines.push('📊 SUMMARY DASHBOARD');
96
+ lines.push('─'.repeat(50));
97
+ lines.push(`Compliance: ${analysis.compliance.compliant ? '✓' : '✗'} L${analysis.compliance.level} ${analysis.compliance.compliant ? 'PASS' : 'FAIL'}`);
98
+ lines.push(`Confidence: ${analysis.confidence.grade} (${analysis.confidence.overall.toFixed(0)}%)`);
99
+ lines.push(`Cognitive Cost: ${analysis.cognitiveCost.totalCost.toFixed(0)}/100`);
100
+ lines.push(`Token Estimate: ${analysis.tokenEstimate.total.estimated} tokens`);
101
+ lines.push('');
102
+ // Key Metrics
103
+ lines.push('📈 KEY METRICS');
104
+ lines.push('─'.repeat(50));
105
+ lines.push(`Total Sections: ${analysis.spec.sections.length}`);
106
+ lines.push(`With System Parts: ${analysis.compliance.summary.compliantSections}`);
107
+ lines.push(`Coverage: ${analysis.confidence.bySection.filter(s => s.hasSystemPart).length}/${analysis.spec.sections.length} (${((analysis.confidence.bySection.filter(s => s.hasSystemPart).length / (analysis.spec.sections.length || 1)) * 100).toFixed(0)}%)`);
108
+ lines.push(`Average Compliance Level: L${(analysis.compliance.summary.averageLevel || 0).toFixed(1)}`);
109
+ lines.push('');
110
+ // Recommendations
111
+ if (analysis.recommendations.length > 0) {
112
+ lines.push('💡 RECOMMENDATIONS');
113
+ lines.push('─'.repeat(50));
114
+ const highPriority = analysis.recommendations.filter(r => r.priority === 'high');
115
+ const mediumPriority = analysis.recommendations.filter(r => r.priority === 'medium');
116
+ const lowPriority = analysis.recommendations.filter(r => r.priority === 'low');
117
+ if (highPriority.length > 0) {
118
+ lines.push('🔴 High Priority:');
119
+ highPriority.forEach(r => {
120
+ lines.push(` • ${r.message}`);
121
+ if (r.action)
122
+ lines.push(` → ${r.action}`);
123
+ });
124
+ lines.push('');
125
+ }
126
+ if (mediumPriority.length > 0) {
127
+ lines.push('🟡 Medium Priority:');
128
+ mediumPriority.forEach(r => {
129
+ lines.push(` • ${r.message}`);
130
+ if (r.action)
131
+ lines.push(` → ${r.action}`);
132
+ });
133
+ lines.push('');
134
+ }
135
+ if (lowPriority.length > 0) {
136
+ lines.push('🟢 Low Priority:');
137
+ lowPriority.forEach(r => {
138
+ lines.push(` • ${r.message}`);
139
+ if (r.action)
140
+ lines.push(` → ${r.action}`);
141
+ });
142
+ lines.push('');
143
+ }
144
+ }
145
+ // Section Breakdown
146
+ lines.push('📋 SECTION BREAKDOWN');
147
+ lines.push('─'.repeat(50));
148
+ lines.push('Section Level Confidence Cost Tokens');
149
+ lines.push('─'.repeat(50));
150
+ analysis.confidence.bySection.forEach((conf, i) => {
151
+ const cost = analysis.cognitiveCost.perSection[i];
152
+ const tokens = analysis.tokenEstimate.bySectionName[conf.sectionName];
153
+ const level = conf.level !== null ? `L${conf.level}` : 'L0';
154
+ const confStr = `${conf.confidence.toFixed(0)}%`;
155
+ const costStr = cost ? `${cost.cost.toFixed(1)}` : '0.0';
156
+ const tokenStr = tokens ? `~${tokens.estimated}` : 'N/A';
157
+ const name = conf.sectionName.length > 24 ? conf.sectionName.slice(0, 21) + '...' : conf.sectionName.padEnd(24);
158
+ lines.push(`${name} ${level.padEnd(5)} ${confStr.padEnd(10)} ${costStr.padEnd(4)} ${tokenStr}`);
159
+ });
160
+ lines.push('');
161
+ // Confidence Factors
162
+ if (analysis.confidence.factors.length > 0) {
163
+ lines.push('🎯 CONFIDENCE FACTORS');
164
+ lines.push('─'.repeat(50));
165
+ analysis.confidence.factors.forEach(factor => {
166
+ const icon = factor.impact === 'positive' ? '✓' : factor.impact === 'negative' ? '✗' : '○';
167
+ const sign = factor.score >= 0 ? '+' : '';
168
+ lines.push(`${icon} ${factor.factor}: ${sign}${factor.score}`);
169
+ lines.push(` ${factor.description}`);
170
+ });
171
+ lines.push('');
172
+ }
173
+ // Cost Breakdown
174
+ lines.push('💰 COGNITIVE COST BREAKDOWN');
175
+ lines.push('─'.repeat(50));
176
+ lines.push(`Base Cost: ${analysis.cognitiveCost.breakdown.baseCost.toFixed(1)}`);
177
+ lines.push(`Complexity Cost: ${analysis.cognitiveCost.breakdown.complexityCost.toFixed(1)}`);
178
+ lines.push(`Decision Cost: ${analysis.cognitiveCost.breakdown.decisionCost.toFixed(1)}`);
179
+ lines.push(`Total Cost: ${analysis.cognitiveCost.totalCost.toFixed(1)}/100`);
180
+ lines.push(`Assessment: ${analysis.cognitiveCost.recommendation}`);
181
+ lines.push('');
182
+ // Token Estimate
183
+ lines.push('🔢 TOKEN ESTIMATE');
184
+ lines.push('─'.repeat(50));
185
+ lines.push(`Estimated: ${analysis.tokenEstimate.total.estimated} tokens`);
186
+ lines.push(`Range: ${analysis.tokenEstimate.total.min} - ${analysis.tokenEstimate.total.max} tokens`);
187
+ lines.push(`Overhead: ${analysis.tokenEstimate.overhead} tokens`);
188
+ lines.push(`Confidence: ${analysis.confidence.grade}`);
189
+ lines.push('');
190
+ return lines.join('\n');
191
+ }
@@ -0,0 +1,125 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.estimateSpecTokens = estimateSpecTokens;
4
+ exports.estimateInputSpecTokens = estimateInputSpecTokens;
5
+ exports.estimateFormatSpecsTokens = estimateFormatSpecsTokens;
6
+ const parser_js_1 = require("./parser.cjs");
7
+ const estimator_js_1 = require("./estimator.cjs");
8
+ function estimateSpecTokens(spec, options = {}) {
9
+ const { includeOptional = true, safetyMultiplier = 1.2, strategy = 'average' } = options;
10
+ const bySectionName = {};
11
+ let totalEstimated = 0;
12
+ let totalMin = 0;
13
+ let totalMax = 0;
14
+ for (const section of spec.sections) {
15
+ // Skip optional sections if requested
16
+ const isRequired = section.required !== false; // Default to required if not explicitly false
17
+ if (!includeOptional && !isRequired)
18
+ continue;
19
+ const kind = section.kind || 'text';
20
+ const systemPart = (0, parser_js_1.parseSystemPart)(section.instruction, kind);
21
+ let estimate;
22
+ if (systemPart) {
23
+ estimate = (0, estimator_js_1.estimateTokens)(systemPart);
24
+ }
25
+ else {
26
+ estimate = (0, estimator_js_1.getFallbackEstimate)(kind, isRequired);
27
+ }
28
+ // Apply optional section discount
29
+ if (!isRequired) {
30
+ estimate = {
31
+ estimated: Math.round(estimate.estimated * 0.6),
32
+ min: Math.round(estimate.min * 0.5),
33
+ max: Math.round(estimate.max * 0.7),
34
+ confidence: 'low'
35
+ };
36
+ }
37
+ bySectionName[section.name] = estimate;
38
+ totalEstimated += estimate.estimated;
39
+ totalMin += estimate.min;
40
+ totalMax += estimate.max;
41
+ }
42
+ // Add overhead
43
+ const overhead = estimator_js_1.TOKEN_CONSTANTS.baseOverhead +
44
+ (spec.sections.length * estimator_js_1.TOKEN_CONSTANTS.headingOverhead);
45
+ totalEstimated += overhead;
46
+ totalMin += overhead;
47
+ totalMax += overhead;
48
+ // Apply strategy
49
+ let finalEstimate;
50
+ switch (strategy) {
51
+ case 'conservative':
52
+ finalEstimate = totalMin;
53
+ break;
54
+ case 'generous':
55
+ finalEstimate = totalMax;
56
+ break;
57
+ case 'average':
58
+ default:
59
+ finalEstimate = totalEstimated;
60
+ }
61
+ // Apply safety multiplier
62
+ finalEstimate = Math.ceil(finalEstimate * safetyMultiplier);
63
+ return {
64
+ total: {
65
+ estimated: finalEstimate,
66
+ min: Math.ceil(totalMin * safetyMultiplier),
67
+ max: Math.ceil(totalMax * safetyMultiplier),
68
+ confidence: 'medium'
69
+ },
70
+ bySectionName,
71
+ overhead
72
+ };
73
+ }
74
+ /**
75
+ * Estimate tokens for an Input Format Spec.
76
+ * Uses the same logic as output format estimation.
77
+ */
78
+ function estimateInputSpecTokens(spec, options = {}) {
79
+ // Input format uses the same structure as output format, so reuse the same logic
80
+ const outputSpec = {
81
+ ...spec,
82
+ descriptorType: "output_format_spec"
83
+ };
84
+ return estimateSpecTokens(outputSpec, options);
85
+ }
86
+ /**
87
+ * Estimate tokens for both input and output format specs.
88
+ * Combines estimates from both if present.
89
+ */
90
+ function estimateFormatSpecsTokens(inputSpec, outputSpec, options = {}) {
91
+ const inputEstimate = inputSpec ? estimateInputSpecTokens(inputSpec, options) : null;
92
+ const outputEstimate = outputSpec ? estimateSpecTokens(outputSpec, options) : null;
93
+ // If only one is present, return it
94
+ if (!inputEstimate && outputEstimate)
95
+ return outputEstimate;
96
+ if (inputEstimate && !outputEstimate)
97
+ return inputEstimate;
98
+ if (!inputEstimate && !outputEstimate) {
99
+ // Return empty estimate
100
+ return {
101
+ total: { estimated: 0, min: 0, max: 0, confidence: 'low' },
102
+ bySectionName: {},
103
+ overhead: 0
104
+ };
105
+ }
106
+ // Combine both estimates
107
+ const combined = {
108
+ total: {
109
+ estimated: inputEstimate.total.estimated + outputEstimate.total.estimated,
110
+ min: inputEstimate.total.min + outputEstimate.total.min,
111
+ max: inputEstimate.total.max + outputEstimate.total.max,
112
+ confidence: inputEstimate.total.confidence === 'high' && outputEstimate.total.confidence === 'high'
113
+ ? 'high'
114
+ : inputEstimate.total.confidence === 'low' || outputEstimate.total.confidence === 'low'
115
+ ? 'low'
116
+ : 'medium'
117
+ },
118
+ bySectionName: {
119
+ ...Object.fromEntries(Object.entries(inputEstimate.bySectionName).map(([k, v]) => [`input:${k}`, v])),
120
+ ...Object.fromEntries(Object.entries(outputEstimate.bySectionName).map(([k, v]) => [`output:${k}`, v]))
121
+ },
122
+ overhead: inputEstimate.overhead + outputEstimate.overhead
123
+ };
124
+ return combined;
125
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateSystemParts = validateSystemParts;
4
+ const parser_js_1 = require("./parser.cjs");
5
+ function validateSystemParts(spec) {
6
+ const errors = [];
7
+ const warnings = [];
8
+ for (const section of spec.sections) {
9
+ const isRequired = section.required !== false;
10
+ const kind = section.kind || 'text';
11
+ if (!section.instruction) {
12
+ if (isRequired) {
13
+ warnings.push({
14
+ sectionName: section.name,
15
+ message: 'Required section has no instruction. Token estimation will use fallback.'
16
+ });
17
+ }
18
+ continue;
19
+ }
20
+ const systemPart = (0, parser_js_1.parseSystemPart)(section.instruction, kind);
21
+ if (!systemPart) {
22
+ warnings.push({
23
+ sectionName: section.name,
24
+ message: `No valid system part found. Expected pattern for '${kind}' kind.`
25
+ });
26
+ continue;
27
+ }
28
+ // Validate ranges
29
+ if (systemPart.parsed.type === 'items' || systemPart.parsed.type === 'lines') {
30
+ const { min, max } = systemPart.parsed;
31
+ if (max !== null && max < min) {
32
+ errors.push({
33
+ sectionName: section.name,
34
+ message: `Invalid range: max (${max}) is less than min (${min})`,
35
+ instruction: section.instruction
36
+ });
37
+ }
38
+ }
39
+ if (systemPart.parsed.type === 'table') {
40
+ const { rows, columns } = systemPart.parsed;
41
+ if (rows.max !== null && rows.max < rows.min) {
42
+ errors.push({
43
+ sectionName: section.name,
44
+ message: `Invalid rows range: max (${rows.max}) < min (${rows.min})`,
45
+ instruction: section.instruction
46
+ });
47
+ }
48
+ if (columns.max !== null && columns.max < columns.min) {
49
+ errors.push({
50
+ sectionName: section.name,
51
+ message: `Invalid columns range: max (${columns.max}) < min (${columns.min})`,
52
+ instruction: section.instruction
53
+ });
54
+ }
55
+ }
56
+ }
57
+ return {
58
+ valid: errors.length === 0,
59
+ errors,
60
+ warnings
61
+ };
62
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });