flex-md 3.5.0 → 4.0.0

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 (72) hide show
  1. package/README.md +423 -39
  2. package/dist/index.cjs +62 -3
  3. package/dist/index.d.ts +1 -0
  4. package/dist/index.js +2 -0
  5. package/dist/ofs/parser.js +31 -10
  6. package/dist/tokens/auto-fix.d.ts +10 -0
  7. package/dist/tokens/auto-fix.js +56 -0
  8. package/dist/tokens/cognitive-cost.d.ts +10 -0
  9. package/dist/tokens/cognitive-cost.js +205 -0
  10. package/dist/tokens/compliance.d.ts +10 -0
  11. package/dist/tokens/compliance.js +70 -0
  12. package/dist/tokens/confidence.d.ts +6 -0
  13. package/dist/tokens/confidence.js +332 -0
  14. package/dist/tokens/estimator.d.ts +12 -0
  15. package/dist/tokens/estimator.js +138 -0
  16. package/dist/tokens/improvements.d.ts +10 -0
  17. package/dist/tokens/improvements.js +697 -0
  18. package/dist/tokens/index.d.ts +24 -0
  19. package/dist/tokens/index.js +31 -0
  20. package/dist/tokens/parser.d.ts +3 -0
  21. package/dist/tokens/parser.js +97 -0
  22. package/dist/tokens/patterns.d.ts +9 -0
  23. package/dist/tokens/patterns.js +20 -0
  24. package/dist/tokens/smart-report.d.ts +10 -0
  25. package/dist/tokens/smart-report.js +187 -0
  26. package/dist/tokens/spec-estimator.d.ts +7 -0
  27. package/dist/tokens/spec-estimator.js +68 -0
  28. package/dist/tokens/types.d.ts +185 -0
  29. package/dist/tokens/validator.d.ts +16 -0
  30. package/dist/tokens/validator.js +59 -0
  31. package/docs/Recommended New Strategies for AI Request Builder.md +691 -0
  32. package/package.json +5 -4
  33. package/dist/detection/detector.d.ts +0 -6
  34. package/dist/detection/detector.js +0 -104
  35. package/dist/detection/extractor.d.ts +0 -10
  36. package/dist/detection/extractor.js +0 -54
  37. package/dist/issues/build.d.ts +0 -26
  38. package/dist/issues/build.js +0 -62
  39. package/dist/md/lists.d.ts +0 -14
  40. package/dist/md/lists.js +0 -33
  41. package/dist/md/tables.d.ts +0 -25
  42. package/dist/md/tables.js +0 -72
  43. package/dist/ofs/extractor.d.ts +0 -9
  44. package/dist/ofs/extractor.js +0 -75
  45. package/dist/ofs/issues.d.ts +0 -14
  46. package/dist/ofs/issues.js +0 -92
  47. package/dist/ofs/validator.d.ts +0 -10
  48. package/dist/ofs/validator.js +0 -91
  49. package/dist/outline/builder.d.ts +0 -10
  50. package/dist/outline/builder.js +0 -85
  51. package/dist/outline/renderer.d.ts +0 -6
  52. package/dist/outline/renderer.js +0 -23
  53. package/dist/parser.d.ts +0 -2
  54. package/dist/parser.js +0 -199
  55. package/dist/parsers/lists.d.ts +0 -6
  56. package/dist/parsers/lists.js +0 -36
  57. package/dist/parsers/tables.d.ts +0 -10
  58. package/dist/parsers/tables.js +0 -58
  59. package/dist/stringify.d.ts +0 -2
  60. package/dist/stringify.js +0 -110
  61. package/dist/test-pipeline.js +0 -53
  62. package/dist/test-runner.d.ts +0 -1
  63. package/dist/test-runner.js +0 -331
  64. package/dist/test-strictness.d.ts +0 -1
  65. package/dist/test-strictness.js +0 -213
  66. package/dist/util.d.ts +0 -5
  67. package/dist/util.js +0 -64
  68. package/dist/validate/policy.d.ts +0 -10
  69. package/dist/validate/policy.js +0 -17
  70. package/dist/validator.d.ts +0 -2
  71. package/dist/validator.js +0 -80
  72. /package/dist/{test-pipeline.d.ts → tokens/types.js} +0 -0
@@ -0,0 +1,332 @@
1
+ import { parseSystemPart } from './parser.js';
2
+ import { detectSystemPartLevel } from './compliance.js';
3
+ /**
4
+ * Calculate confidence in token estimation
5
+ */
6
+ export function calculateConfidence(spec) {
7
+ const bySection = [];
8
+ const factors = [];
9
+ let totalConfidence = 0;
10
+ let totalWeight = 0;
11
+ // Analyze each section
12
+ for (const section of spec.sections) {
13
+ const sectionConf = analyzeSectionConfidence(section);
14
+ bySection.push(sectionConf);
15
+ // Weight required sections more heavily
16
+ const weight = section.required !== false ? 2 : 1;
17
+ totalConfidence += sectionConf.confidence * weight;
18
+ totalWeight += weight;
19
+ }
20
+ // Calculate coverage factor
21
+ const coverageFactor = calculateCoverageFactor(spec);
22
+ factors.push(coverageFactor);
23
+ // Calculate specificity factor
24
+ const specificityFactor = calculateSpecificityFactor(bySection);
25
+ factors.push(specificityFactor);
26
+ // Calculate consistency factor
27
+ const consistencyFactor = calculateConsistencyFactor(bySection);
28
+ factors.push(consistencyFactor);
29
+ // Calculate required coverage factor
30
+ const requiredFactor = calculateRequiredCoverageFactor(spec, bySection);
31
+ factors.push(requiredFactor);
32
+ // Combine all factors
33
+ let overall = totalWeight > 0 ? totalConfidence / totalWeight : 0;
34
+ // Apply factor adjustments
35
+ for (const factor of factors) {
36
+ overall += factor.score;
37
+ }
38
+ overall = Math.max(0, Math.min(100, overall));
39
+ return {
40
+ overall,
41
+ grade: getConfidenceGrade(overall),
42
+ bySection,
43
+ factors,
44
+ recommendations: generateConfidenceRecommendations(overall, factors, bySection)
45
+ };
46
+ }
47
+ /**
48
+ * Analyze confidence for individual section
49
+ */
50
+ function analyzeSectionConfidence(section) {
51
+ const kind = section.kind || 'text';
52
+ const systemPart = parseSystemPart(section.instruction, kind);
53
+ const hasSystemPart = systemPart !== null;
54
+ const level = systemPart ? detectSystemPartLevel(systemPart, kind) : null;
55
+ let confidence = 0;
56
+ let quality = 'none';
57
+ if (systemPart && level !== null) {
58
+ // Base confidence from level
59
+ const levelConfidence = { 0: 0, 1: 60, 2: 80, 3: 90 };
60
+ confidence = levelConfidence[level] || 0;
61
+ // Adjust based on section characteristics
62
+ const adjustment = getConfidenceAdjustment(systemPart, section);
63
+ confidence += adjustment;
64
+ confidence = Math.max(0, Math.min(100, confidence));
65
+ // Determine quality
66
+ if (confidence >= 85)
67
+ quality = 'excellent';
68
+ else if (confidence >= 70)
69
+ quality = 'good';
70
+ else if (confidence >= 50)
71
+ quality = 'fair';
72
+ else
73
+ quality = 'poor';
74
+ }
75
+ return {
76
+ sectionName: section.name,
77
+ confidence,
78
+ hasSystemPart,
79
+ level,
80
+ estimateQuality: quality
81
+ };
82
+ }
83
+ function getConfidenceAdjustment(systemPart, _section) {
84
+ let adjustment = 0;
85
+ const { parsed } = systemPart;
86
+ switch (parsed.type) {
87
+ case 'length':
88
+ // Specific values are better than vague ones
89
+ if (['1 sentence', '1-2 sentences', '1 paragraph', '2-3 paragraphs'].includes(parsed.value)) {
90
+ adjustment += 10; // Concrete measurements
91
+ }
92
+ break;
93
+ case 'items':
94
+ // Exact numbers or tight ranges are better
95
+ if (parsed.max !== null) {
96
+ const range = parsed.max - parsed.min;
97
+ if (range <= 2)
98
+ adjustment += 10; // Tight range
99
+ else if (range <= 5)
100
+ adjustment += 5; // Reasonable range
101
+ }
102
+ else if (!parsed.atLeast) {
103
+ adjustment += 10; // Exact number
104
+ }
105
+ break;
106
+ case 'table':
107
+ // Both dimensions specified tightly
108
+ const rowsExact = parsed.rows.max === null && !parsed.rows.atLeast;
109
+ const colsExact = parsed.columns.max === null && !parsed.columns.atLeast;
110
+ if (rowsExact && colsExact) {
111
+ adjustment += 10; // Both exact
112
+ }
113
+ else if (rowsExact || colsExact) {
114
+ adjustment += 5; // One exact
115
+ }
116
+ break;
117
+ case 'lines':
118
+ // Non-approximate is better
119
+ if (!parsed.approximate) {
120
+ adjustment += 5;
121
+ }
122
+ if (parsed.max !== null) {
123
+ const range = parsed.max - parsed.min;
124
+ if (range <= 10)
125
+ adjustment += 5; // Tight range
126
+ }
127
+ break;
128
+ }
129
+ // Penalty for very vague patterns
130
+ if (parsed.type === 'items' && parsed.atLeast && parsed.min < 3) {
131
+ adjustment -= 10; // "at least 1" is very vague
132
+ }
133
+ return adjustment;
134
+ }
135
+ /**
136
+ * Calculate coverage factor (what % of sections have system parts)
137
+ */
138
+ function calculateCoverageFactor(spec) {
139
+ const total = spec.sections.length;
140
+ const withSystemParts = spec.sections.filter(s => parseSystemPart(s.instruction, s.kind || 'text') !== null).length;
141
+ const coverage = total > 0 ? (withSystemParts / total) * 100 : 0;
142
+ let score = 0;
143
+ let impact = 'neutral';
144
+ if (coverage >= 90) {
145
+ score = 10;
146
+ impact = 'positive';
147
+ }
148
+ else if (coverage >= 70) {
149
+ score = 5;
150
+ impact = 'positive';
151
+ }
152
+ else if (coverage < 50) {
153
+ score = -10;
154
+ impact = 'negative';
155
+ }
156
+ else {
157
+ score = -5;
158
+ impact = 'negative';
159
+ }
160
+ return {
161
+ factor: 'coverage',
162
+ impact,
163
+ score,
164
+ description: `${coverage.toFixed(0)}% of sections have system parts`
165
+ };
166
+ }
167
+ /**
168
+ * Calculate specificity factor (are system parts specific or vague?)
169
+ */
170
+ function calculateSpecificityFactor(sections) {
171
+ const withSystemParts = sections.filter(s => s.hasSystemPart);
172
+ if (withSystemParts.length === 0) {
173
+ return {
174
+ factor: 'specificity',
175
+ impact: 'negative',
176
+ score: -15,
177
+ description: 'No system parts to evaluate'
178
+ };
179
+ }
180
+ const avgLevel = withSystemParts.reduce((sum, s) => sum + (s.level || 0), 0) / withSystemParts.length;
181
+ let score = 0;
182
+ let impact = 'neutral';
183
+ if (avgLevel >= 2.5) {
184
+ score = 10;
185
+ impact = 'positive';
186
+ }
187
+ else if (avgLevel >= 2) {
188
+ score = 5;
189
+ impact = 'positive';
190
+ }
191
+ else if (avgLevel < 1.5) {
192
+ score = -5;
193
+ impact = 'negative';
194
+ }
195
+ return {
196
+ factor: 'specificity',
197
+ impact,
198
+ score,
199
+ description: `Average specificity level: L${avgLevel.toFixed(1)}`
200
+ };
201
+ }
202
+ /**
203
+ * Calculate consistency factor (are all sections at similar level?)
204
+ */
205
+ function calculateConsistencyFactor(sections) {
206
+ const levels = sections
207
+ .filter(s => s.level !== null)
208
+ .map(s => s.level);
209
+ if (levels.length === 0) {
210
+ return {
211
+ factor: 'consistency',
212
+ impact: 'neutral',
213
+ score: 0,
214
+ description: 'No levels to compare'
215
+ };
216
+ }
217
+ const min = Math.min(...levels);
218
+ const max = Math.max(...levels);
219
+ const variance = max - min;
220
+ let score = 0;
221
+ let impact = 'neutral';
222
+ if (variance === 0) {
223
+ score = 5;
224
+ impact = 'positive';
225
+ }
226
+ else if (variance >= 3) {
227
+ score = -5;
228
+ impact = 'negative';
229
+ }
230
+ return {
231
+ factor: 'consistency',
232
+ impact,
233
+ score,
234
+ description: variance === 0
235
+ ? 'All sections at same level (consistent)'
236
+ : `Level variance: ${variance} (${min} to ${max})`
237
+ };
238
+ }
239
+ /**
240
+ * Calculate required coverage (do all required sections have good system parts?)
241
+ */
242
+ function calculateRequiredCoverageFactor(spec, sections) {
243
+ const requiredSections = spec.sections.filter(s => s.required !== false);
244
+ if (requiredSections.length === 0) {
245
+ return {
246
+ factor: 'required_coverage',
247
+ impact: 'neutral',
248
+ score: 0,
249
+ description: 'No required sections'
250
+ };
251
+ }
252
+ const requiredWithSystemParts = sections.filter(s => {
253
+ const section = spec.sections.find(sec => sec.name === s.sectionName);
254
+ return section?.required !== false && s.hasSystemPart;
255
+ }).length;
256
+ const coverage = (requiredWithSystemParts / requiredSections.length) * 100;
257
+ let score = 0;
258
+ let impact = 'neutral';
259
+ if (coverage === 100) {
260
+ score = 15;
261
+ impact = 'positive';
262
+ }
263
+ else if (coverage >= 80) {
264
+ score = 5;
265
+ impact = 'positive';
266
+ }
267
+ else if (coverage < 50) {
268
+ score = -15;
269
+ impact = 'negative';
270
+ }
271
+ else {
272
+ score = -5;
273
+ impact = 'negative';
274
+ }
275
+ return {
276
+ factor: 'required_coverage',
277
+ impact,
278
+ score,
279
+ description: `${coverage.toFixed(0)}% of required sections have system parts`
280
+ };
281
+ }
282
+ function getConfidenceGrade(score) {
283
+ if (score >= 90)
284
+ return 'A';
285
+ if (score >= 80)
286
+ return 'B';
287
+ if (score >= 70)
288
+ return 'C';
289
+ if (score >= 60)
290
+ return 'D';
291
+ return 'F';
292
+ }
293
+ function generateConfidenceRecommendations(overall, factors, sections) {
294
+ const recommendations = [];
295
+ // Overall quality
296
+ if (overall < 70) {
297
+ recommendations.push('Overall confidence is low. Consider adding more specific system parts.');
298
+ }
299
+ // Check negative factors
300
+ for (const factor of factors) {
301
+ if (factor.impact === 'negative') {
302
+ switch (factor.factor) {
303
+ case 'coverage':
304
+ recommendations.push('Add system parts to more sections to improve coverage.');
305
+ break;
306
+ case 'specificity':
307
+ recommendations.push('Upgrade some L1 system parts to L2 for better precision.');
308
+ break;
309
+ case 'consistency':
310
+ recommendations.push('Consider standardizing compliance level across sections.');
311
+ break;
312
+ case 'required_coverage':
313
+ recommendations.push('Ensure all required sections have system parts.');
314
+ break;
315
+ }
316
+ }
317
+ }
318
+ // Check poor quality sections
319
+ const poorSections = sections.filter(s => s.estimateQuality === 'poor' || s.estimateQuality === 'none');
320
+ if (poorSections.length > 0) {
321
+ const names = poorSections.map(s => s.sectionName).join(', ');
322
+ recommendations.push(`Improve system parts for: ${names}`);
323
+ }
324
+ // Positive feedback
325
+ if (overall >= 90) {
326
+ recommendations.push('Excellent! Token estimation will be highly accurate.');
327
+ }
328
+ else if (overall >= 80) {
329
+ recommendations.push('Good confidence. Minor improvements possible.');
330
+ }
331
+ return recommendations;
332
+ }
@@ -0,0 +1,12 @@
1
+ import type { SystemPart, TokenEstimate, LengthValue } from './types.js';
2
+ import type { SectionKind } from '../types.js';
3
+ export declare const TOKEN_CONSTANTS: {
4
+ readonly lengths: Record<LengthValue, number>;
5
+ readonly perItem: 40;
6
+ readonly perTableCell: 20;
7
+ readonly perCodeLine: 5;
8
+ readonly headingOverhead: 10;
9
+ readonly baseOverhead: 50;
10
+ };
11
+ export declare function estimateTokens(systemPart: SystemPart): TokenEstimate;
12
+ export declare function getFallbackEstimate(kind: SectionKind, required: boolean): TokenEstimate;
@@ -0,0 +1,138 @@
1
+ // Calibrated token constants
2
+ export const TOKEN_CONSTANTS = {
3
+ // Text lengths (enumerated)
4
+ lengths: {
5
+ '1 sentence': 25,
6
+ '1-2 sentences': 40,
7
+ '1 paragraph': 100,
8
+ '2-3 paragraphs': 250,
9
+ 'brief': 75,
10
+ 'moderate': 150,
11
+ 'detailed': 300,
12
+ 'extensive': 500
13
+ },
14
+ // Per-unit estimates
15
+ perItem: 40,
16
+ perTableCell: 20,
17
+ perCodeLine: 5,
18
+ // Overhead
19
+ headingOverhead: 10,
20
+ baseOverhead: 50
21
+ };
22
+ export function estimateTokens(systemPart) {
23
+ const { parsed } = systemPart;
24
+ switch (parsed.type) {
25
+ case 'length':
26
+ return estimateTextLength(parsed.value);
27
+ case 'items':
28
+ return estimateItems(parsed);
29
+ case 'table':
30
+ return estimateTable(parsed);
31
+ case 'lines':
32
+ return estimateCodeLines(parsed);
33
+ }
34
+ }
35
+ function estimateTextLength(value) {
36
+ const estimated = TOKEN_CONSTANTS.lengths[value];
37
+ return {
38
+ estimated,
39
+ min: Math.floor(estimated * 0.7),
40
+ max: Math.ceil(estimated * 1.3),
41
+ confidence: 'high'
42
+ };
43
+ }
44
+ function estimateItems(parsed) {
45
+ const { min, max, atLeast } = parsed;
46
+ if (max !== null) {
47
+ // Range: "3-5" → use average
48
+ const avg = (min + max) / 2;
49
+ const estimated = Math.round(avg * TOKEN_CONSTANTS.perItem);
50
+ return {
51
+ estimated,
52
+ min: min * TOKEN_CONSTANTS.perItem,
53
+ max: max * TOKEN_CONSTANTS.perItem,
54
+ confidence: 'high'
55
+ };
56
+ }
57
+ if (atLeast) {
58
+ // "at least 3" → estimate at min + 50%
59
+ const estimated = Math.round(min * 1.5 * TOKEN_CONSTANTS.perItem);
60
+ return {
61
+ estimated,
62
+ min: min * TOKEN_CONSTANTS.perItem,
63
+ max: min * 3 * TOKEN_CONSTANTS.perItem,
64
+ confidence: 'medium'
65
+ };
66
+ }
67
+ // Exact: "3" → use exact value
68
+ const estimated = min * TOKEN_CONSTANTS.perItem;
69
+ return {
70
+ estimated,
71
+ min: Math.floor(estimated * 0.8),
72
+ max: Math.ceil(estimated * 1.2),
73
+ confidence: 'high'
74
+ };
75
+ }
76
+ function estimateTable(parsed) {
77
+ const rowAvg = parsed.rows.max
78
+ ? (parsed.rows.min + parsed.rows.max) / 2
79
+ : parsed.rows.atLeast
80
+ ? parsed.rows.min * 1.5
81
+ : parsed.rows.min;
82
+ const colAvg = parsed.columns.max
83
+ ? (parsed.columns.min + parsed.columns.max) / 2
84
+ : parsed.columns.atLeast
85
+ ? parsed.columns.min * 1.5
86
+ : parsed.columns.min;
87
+ const estimated = Math.round(rowAvg * colAvg * TOKEN_CONSTANTS.perTableCell);
88
+ const minCells = parsed.rows.min * parsed.columns.min;
89
+ const maxRows = parsed.rows.max || (parsed.rows.atLeast ? parsed.rows.min * 2 : parsed.rows.min);
90
+ const maxCols = parsed.columns.max || (parsed.columns.atLeast ? parsed.columns.min * 2 : parsed.columns.min);
91
+ const maxCells = maxRows * maxCols;
92
+ return {
93
+ estimated,
94
+ min: minCells * TOKEN_CONSTANTS.perTableCell,
95
+ max: maxCells * TOKEN_CONSTANTS.perTableCell,
96
+ confidence: (parsed.rows.max && parsed.columns.max) ? 'high' : 'medium'
97
+ };
98
+ }
99
+ function estimateCodeLines(parsed) {
100
+ const { min, max, approximate } = parsed;
101
+ if (max !== null) {
102
+ // Range: "10-20"
103
+ const avg = (min + max) / 2;
104
+ const estimated = Math.round(avg * TOKEN_CONSTANTS.perCodeLine);
105
+ return {
106
+ estimated,
107
+ min: min * TOKEN_CONSTANTS.perCodeLine,
108
+ max: max * TOKEN_CONSTANTS.perCodeLine,
109
+ confidence: 'high'
110
+ };
111
+ }
112
+ // Exact or approximate: "10" or "~10"
113
+ const estimated = min * TOKEN_CONSTANTS.perCodeLine;
114
+ const variance = approximate ? 0.3 : 0.15;
115
+ return {
116
+ estimated,
117
+ min: Math.floor(estimated * (1 - variance)),
118
+ max: Math.ceil(estimated * (1 + variance)),
119
+ confidence: approximate ? 'medium' : 'high'
120
+ };
121
+ }
122
+ // Fallback for sections without system parts
123
+ export function getFallbackEstimate(kind, required) {
124
+ const fallbacks = {
125
+ text: 150,
126
+ list: 200,
127
+ 'ordered-list': 200,
128
+ table: 300,
129
+ code: 400
130
+ };
131
+ const base = fallbacks[kind] || 150;
132
+ return {
133
+ estimated: base,
134
+ min: Math.floor(base * 0.5),
135
+ max: Math.ceil(base * 2),
136
+ confidence: 'low'
137
+ };
138
+ }
@@ -0,0 +1,10 @@
1
+ import type { ImprovementAnalysis, ComplianceLevel } from './types.js';
2
+ import type { OutputFormatSpec } from '../types.js';
3
+ /**
4
+ * Main improvement detector
5
+ */
6
+ export declare function detectImprovements(spec: OutputFormatSpec, targetLevel?: ComplianceLevel): ImprovementAnalysis;
7
+ /**
8
+ * Format improvement report
9
+ */
10
+ export declare function formatImprovementReport(analysis: ImprovementAnalysis): string;