@codeledger/engine 0.7.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 (129) hide show
  1. package/dist/ccs/index.d.ts +11 -0
  2. package/dist/ccs/index.d.ts.map +1 -0
  3. package/dist/ccs/index.js +10 -0
  4. package/dist/ccs/index.js.map +1 -0
  5. package/dist/ccs/score.d.ts +61 -0
  6. package/dist/ccs/score.d.ts.map +1 -0
  7. package/dist/ccs/score.js +250 -0
  8. package/dist/ccs/score.js.map +1 -0
  9. package/dist/ecl/index.d.ts +9 -0
  10. package/dist/ecl/index.d.ts.map +1 -0
  11. package/dist/ecl/index.js +9 -0
  12. package/dist/ecl/index.js.map +1 -0
  13. package/dist/ecl/ledger.d.ts +84 -0
  14. package/dist/ecl/ledger.d.ts.map +1 -0
  15. package/dist/ecl/ledger.js +235 -0
  16. package/dist/ecl/ledger.js.map +1 -0
  17. package/dist/index.d.ts +54 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/index.js +56 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/iole/expansion-ladder.d.ts +51 -0
  22. package/dist/iole/expansion-ladder.d.ts.map +1 -0
  23. package/dist/iole/expansion-ladder.js +153 -0
  24. package/dist/iole/expansion-ladder.js.map +1 -0
  25. package/dist/iole/failure-vector.d.ts +21 -0
  26. package/dist/iole/failure-vector.d.ts.map +1 -0
  27. package/dist/iole/failure-vector.js +156 -0
  28. package/dist/iole/failure-vector.js.map +1 -0
  29. package/dist/iole/index.d.ts +19 -0
  30. package/dist/iole/index.d.ts.map +1 -0
  31. package/dist/iole/index.js +17 -0
  32. package/dist/iole/index.js.map +1 -0
  33. package/dist/iole/intent-decomposition.d.ts +33 -0
  34. package/dist/iole/intent-decomposition.d.ts.map +1 -0
  35. package/dist/iole/intent-decomposition.js +252 -0
  36. package/dist/iole/intent-decomposition.js.map +1 -0
  37. package/dist/iole/intent-signature.d.ts +37 -0
  38. package/dist/iole/intent-signature.d.ts.map +1 -0
  39. package/dist/iole/intent-signature.js +112 -0
  40. package/dist/iole/intent-signature.js.map +1 -0
  41. package/dist/iole/outcome-score.d.ts +25 -0
  42. package/dist/iole/outcome-score.d.ts.map +1 -0
  43. package/dist/iole/outcome-score.js +128 -0
  44. package/dist/iole/outcome-score.js.map +1 -0
  45. package/dist/isc/index.d.ts +8 -0
  46. package/dist/isc/index.d.ts.map +1 -0
  47. package/dist/isc/index.js +8 -0
  48. package/dist/isc/index.js.map +1 -0
  49. package/dist/isc/score.d.ts +27 -0
  50. package/dist/isc/score.d.ts.map +1 -0
  51. package/dist/isc/score.js +347 -0
  52. package/dist/isc/score.js.map +1 -0
  53. package/dist/license/index.d.ts +14 -0
  54. package/dist/license/index.d.ts.map +1 -0
  55. package/dist/license/index.js +11 -0
  56. package/dist/license/index.js.map +1 -0
  57. package/dist/license/parse.d.ts +42 -0
  58. package/dist/license/parse.d.ts.map +1 -0
  59. package/dist/license/parse.js +106 -0
  60. package/dist/license/parse.js.map +1 -0
  61. package/dist/license/publicKey.d.ts +37 -0
  62. package/dist/license/publicKey.d.ts.map +1 -0
  63. package/dist/license/publicKey.js +48 -0
  64. package/dist/license/publicKey.js.map +1 -0
  65. package/dist/license/verify.d.ts +33 -0
  66. package/dist/license/verify.d.ts.map +1 -0
  67. package/dist/license/verify.js +82 -0
  68. package/dist/license/verify.js.map +1 -0
  69. package/dist/orchestrator/index.d.ts +10 -0
  70. package/dist/orchestrator/index.d.ts.map +1 -0
  71. package/dist/orchestrator/index.js +10 -0
  72. package/dist/orchestrator/index.js.map +1 -0
  73. package/dist/orchestrator/orchestrator.d.ts +44 -0
  74. package/dist/orchestrator/orchestrator.d.ts.map +1 -0
  75. package/dist/orchestrator/orchestrator.js +182 -0
  76. package/dist/orchestrator/orchestrator.js.map +1 -0
  77. package/dist/policy-sim/index.d.ts +8 -0
  78. package/dist/policy-sim/index.d.ts.map +1 -0
  79. package/dist/policy-sim/index.js +8 -0
  80. package/dist/policy-sim/index.js.map +1 -0
  81. package/dist/policy-sim/simulate.d.ts +18 -0
  82. package/dist/policy-sim/simulate.d.ts.map +1 -0
  83. package/dist/policy-sim/simulate.js +61 -0
  84. package/dist/policy-sim/simulate.js.map +1 -0
  85. package/dist/provenance/graph.d.ts +42 -0
  86. package/dist/provenance/graph.d.ts.map +1 -0
  87. package/dist/provenance/graph.js +139 -0
  88. package/dist/provenance/graph.js.map +1 -0
  89. package/dist/provenance/index.d.ts +8 -0
  90. package/dist/provenance/index.d.ts.map +1 -0
  91. package/dist/provenance/index.js +8 -0
  92. package/dist/provenance/index.js.map +1 -0
  93. package/dist/sce/index.d.ts +15 -0
  94. package/dist/sce/index.d.ts.map +1 -0
  95. package/dist/sce/index.js +14 -0
  96. package/dist/sce/index.js.map +1 -0
  97. package/dist/sce/slice-builder.d.ts +35 -0
  98. package/dist/sce/slice-builder.d.ts.map +1 -0
  99. package/dist/sce/slice-builder.js +198 -0
  100. package/dist/sce/slice-builder.js.map +1 -0
  101. package/dist/sce/symbol-graph.d.ts +21 -0
  102. package/dist/sce/symbol-graph.d.ts.map +1 -0
  103. package/dist/sce/symbol-graph.js +187 -0
  104. package/dist/sce/symbol-graph.js.map +1 -0
  105. package/dist/team-ledger/index.d.ts +8 -0
  106. package/dist/team-ledger/index.d.ts.map +1 -0
  107. package/dist/team-ledger/index.js +8 -0
  108. package/dist/team-ledger/index.js.map +1 -0
  109. package/dist/team-ledger/ledger.d.ts +48 -0
  110. package/dist/team-ledger/ledger.d.ts.map +1 -0
  111. package/dist/team-ledger/ledger.js +208 -0
  112. package/dist/team-ledger/ledger.js.map +1 -0
  113. package/dist/team-metrics/index.d.ts +8 -0
  114. package/dist/team-metrics/index.d.ts.map +1 -0
  115. package/dist/team-metrics/index.js +8 -0
  116. package/dist/team-metrics/index.js.map +1 -0
  117. package/dist/team-metrics/metrics.d.ts +42 -0
  118. package/dist/team-metrics/metrics.d.ts.map +1 -0
  119. package/dist/team-metrics/metrics.js +156 -0
  120. package/dist/team-metrics/metrics.js.map +1 -0
  121. package/dist/team-policy/index.d.ts +8 -0
  122. package/dist/team-policy/index.d.ts.map +1 -0
  123. package/dist/team-policy/index.js +8 -0
  124. package/dist/team-policy/index.js.map +1 -0
  125. package/dist/team-policy/policy.d.ts +35 -0
  126. package/dist/team-policy/policy.d.ts.map +1 -0
  127. package/dist/team-policy/policy.js +100 -0
  128. package/dist/team-policy/policy.js.map +1 -0
  129. package/package.json +49 -0
@@ -0,0 +1,347 @@
1
+ /**
2
+ * ISC — Intent Sufficiency Check
3
+ *
4
+ * PRE-CONTEXT certification layer. Evaluates whether a task prompt carries
5
+ * enough structured intent to justify context construction.
6
+ *
7
+ * Design principles:
8
+ * - Deterministic: same input → same output (no ML, no external calls)
9
+ * - Local-first: pure string analysis
10
+ * - Additive scoring: five independent factors summed with fixed weights
11
+ *
12
+ * Decision thresholds:
13
+ * SUFFICIENT ≥ 0.75 → proceed normally
14
+ * WEAK 0.50–0.74 → proceed with -0.05 CCS penalty
15
+ * INSUFFICIENT < 0.50 → block context construction; surface recommendations
16
+ */
17
+ // ─── Weights ─────────────────────────────────────────────────────────────────
18
+ const W_TOKEN_SIGNAL = 0.20;
19
+ const W_OPERATION_CLARITY = 0.30;
20
+ const W_DOMAIN_CLARITY = 0.25;
21
+ const W_TARGET_SPECIFICITY = 0.15;
22
+ const W_CONSTRAINT_PRESENCE = 0.10;
23
+ // ─── Thresholds ───────────────────────────────────────────────────────────────
24
+ export const ISC_SUFFICIENT_THRESHOLD = 0.75;
25
+ export const ISC_WEAK_THRESHOLD = 0.50;
26
+ // ─── Keyword Tables ───────────────────────────────────────────────────────────
27
+ /**
28
+ * Operation clarity keywords — clear action verbs that signal a well-formed
29
+ * task. Grouped by verb family for readability.
30
+ */
31
+ const OPERATION_KEYWORDS = [
32
+ // Bug / fix
33
+ 'fix', 'fixes', 'fixing', 'fixed',
34
+ 'patch', 'patches', 'patching',
35
+ 'debug', 'debugs', 'debugging',
36
+ 'repair', 'repairs', 'repairing',
37
+ 'resolve', 'resolves', 'resolving',
38
+ // Feature / add
39
+ 'add', 'adds', 'adding',
40
+ 'implement', 'implements', 'implementing',
41
+ 'create', 'creates', 'creating',
42
+ 'build', 'builds', 'building',
43
+ 'introduce', 'introduces', 'introducing',
44
+ // Refactor / clean
45
+ 'refactor', 'refactors', 'refactoring',
46
+ 'rename', 'renames', 'renaming',
47
+ 'move', 'moves', 'moving',
48
+ 'extract', 'extracts', 'extracting',
49
+ 'clean', 'cleans', 'cleaning',
50
+ 'reorganize', 'reorganizes', 'reorganizing',
51
+ // Update / change
52
+ 'update', 'updates', 'updating',
53
+ 'upgrade', 'upgrades', 'upgrading',
54
+ 'change', 'changes', 'changing',
55
+ 'modify', 'modifies', 'modifying',
56
+ 'replace', 'replaces', 'replacing',
57
+ // Remove / delete
58
+ 'remove', 'removes', 'removing',
59
+ 'delete', 'deletes', 'deleting',
60
+ 'drop', 'drops', 'dropping',
61
+ // Test
62
+ 'test', 'tests', 'testing',
63
+ 'write test', 'add test', 'cover',
64
+ // Document / explain
65
+ 'document', 'documents', 'documenting',
66
+ 'explain', 'explains', 'explaining',
67
+ // Improve / optimize
68
+ 'improve', 'improves', 'improving',
69
+ 'optimize', 'optimizes', 'optimizing',
70
+ 'enhance', 'enhances', 'enhancing',
71
+ // Migrate / convert
72
+ 'migrate', 'migrates', 'migrating',
73
+ 'convert', 'converts', 'converting',
74
+ 'port', 'ports', 'porting',
75
+ ];
76
+ /**
77
+ * Domain clarity keywords — recognisable technical domains. A prompt
78
+ * containing any of these is scored as domain-clear.
79
+ */
80
+ const DOMAIN_KEYWORDS = [
81
+ // Auth / security
82
+ 'auth', 'authentication', 'authorization', 'login', 'logout', 'session',
83
+ 'oauth', 'jwt', 'token', 'password', 'credential', 'permission', 'role',
84
+ // API / routes
85
+ 'api', 'endpoint', 'route', 'routes', 'rest', 'graphql', 'grpc',
86
+ 'http', 'https', 'request', 'response', 'middleware',
87
+ // Database / storage
88
+ 'database', 'db', 'sql', 'query', 'migration', 'schema', 'table', 'index',
89
+ 'sqlite', 'postgres', 'mysql', 'mongo', 'redis', 'cache',
90
+ // UI / frontend
91
+ 'ui', 'frontend', 'component', 'react', 'vue', 'angular', 'css', 'style',
92
+ 'modal', 'button', 'form', 'input', 'render', 'view',
93
+ // Build / CI
94
+ 'build', 'ci', 'workflow', 'deploy', 'release', 'publish', 'bundle',
95
+ 'webpack', 'vite', 'rollup', 'tsconfig', 'eslint',
96
+ // Config / infra
97
+ 'config', 'configuration', 'settings', 'env', 'environment',
98
+ 'docker', 'kubernetes', 'infrastructure',
99
+ // Types / models
100
+ 'type', 'types', 'interface', 'model', 'schema', 'dto', 'entity',
101
+ // Tests
102
+ 'test', 'tests', 'spec', 'jest', 'vitest', 'mocha', 'coverage',
103
+ // Logging / observability
104
+ 'log', 'logs', 'logging', 'telemetry', 'metric', 'trace',
105
+ // CLI / commands
106
+ 'cli', 'command', 'flag', 'argument', 'subcommand',
107
+ // Core concepts in this repo
108
+ 'ledger', 'bundle', 'context', 'ccs', 'ecl', 'iole', 'sce', 'isc',
109
+ 'slice', 'selector', 'scanner', 'repo', 'graph', 'hotspot',
110
+ ];
111
+ /**
112
+ * Constraint keywords — words that introduce scope or quality limitations.
113
+ */
114
+ const CONSTRAINT_KEYWORDS = [
115
+ 'without', 'without breaking', 'must', 'should', 'ensure', 'only',
116
+ 'keep', 'maintain', 'preserve', 'backward compat', 'backwards compat',
117
+ 'no breaking', 'don\'t break', 'do not break', 'safe', 'safely',
118
+ 'not affect', 'except', 'but not', 'limited to', 'within',
119
+ 'in packages/', 'in src/', 'in tests/', 'only in',
120
+ ];
121
+ // ─── Public API ───────────────────────────────────────────────────────────────
122
+ /**
123
+ * Run the Intent Sufficiency Check on a task prompt.
124
+ *
125
+ * Returns a full IntentSufficiencyCheck with score, decision, per-factor
126
+ * breakdown, issues list, and actionable recommendations.
127
+ */
128
+ export function checkIntentSufficiency(task) {
129
+ const taskLower = task.toLowerCase().trim();
130
+ const tokens = tokenize(task);
131
+ // ── Factor 1: Token Signal (weight 0.20) ─────────────────────────────────
132
+ const tokenSignalScore = scoreTokenSignal(tokens);
133
+ // ── Factor 2: Operation Clarity (weight 0.30) ────────────────────────────
134
+ const { score: operationClarityScore, detected: detectedOperation } = scoreOperationClarity(taskLower, tokens);
135
+ // ── Factor 3: Domain Clarity (weight 0.25) ───────────────────────────────
136
+ const { score: domainClarityScore, detected: detectedDomain } = scoreDomainClarity(taskLower, tokens);
137
+ // ── Factor 4: Target Specificity (weight 0.15) ───────────────────────────
138
+ const { score: targetSpecificityScore, detected: detectedTargets } = scoreTargetSpecificity(task, taskLower, tokens);
139
+ // ── Factor 5: Constraint Presence (weight 0.10) ──────────────────────────
140
+ const constraintPresenceScore = scoreConstraintPresence(taskLower);
141
+ // ── Weighted composite ───────────────────────────────────────────────────
142
+ const factors = {
143
+ tokenSignalScore,
144
+ operationClarityScore,
145
+ domainClarityScore,
146
+ targetSpecificityScore,
147
+ constraintPresenceScore,
148
+ };
149
+ const score = tokenSignalScore * W_TOKEN_SIGNAL +
150
+ operationClarityScore * W_OPERATION_CLARITY +
151
+ domainClarityScore * W_DOMAIN_CLARITY +
152
+ targetSpecificityScore * W_TARGET_SPECIFICITY +
153
+ constraintPresenceScore * W_CONSTRAINT_PRESENCE;
154
+ const roundedScore = Math.round(score * 1000) / 1000;
155
+ // ── Decision ─────────────────────────────────────────────────────────────
156
+ const decision = roundedScore >= ISC_SUFFICIENT_THRESHOLD
157
+ ? 'SUFFICIENT'
158
+ : roundedScore >= ISC_WEAK_THRESHOLD
159
+ ? 'WEAK'
160
+ : 'INSUFFICIENT';
161
+ // ── Issues + Recommendations ─────────────────────────────────────────────
162
+ const { issues, recommendations } = buildDiagnostics(factors, tokens);
163
+ return {
164
+ score: roundedScore,
165
+ decision,
166
+ factors,
167
+ issues,
168
+ recommendations,
169
+ ...(detectedOperation ? { detectedOperation } : {}),
170
+ ...(detectedDomain ? { detectedDomain } : {}),
171
+ ...(detectedTargets.length > 0 ? { detectedTargets } : {}),
172
+ };
173
+ }
174
+ // ─── Factor Scorers ───────────────────────────────────────────────────────────
175
+ /**
176
+ * Factor 1: Token Signal
177
+ *
178
+ * Scoring table:
179
+ * < 2 tokens → 0.0
180
+ * 2 tokens → 0.3
181
+ * 3–4 tokens → 0.6
182
+ * 5–7 tokens → 0.8
183
+ * ≥ 8 tokens → 1.0
184
+ */
185
+ function scoreTokenSignal(tokens) {
186
+ const n = tokens.length;
187
+ if (n < 2)
188
+ return 0.0;
189
+ if (n === 2)
190
+ return 0.3;
191
+ if (n <= 4)
192
+ return 0.6;
193
+ if (n <= 7)
194
+ return 0.8;
195
+ return 1.0;
196
+ }
197
+ function scoreOperationClarity(taskLower, _tokens) {
198
+ for (const kw of OPERATION_KEYWORDS) {
199
+ // Match as a whole word or at start of a phrase
200
+ const escaped = kw.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
201
+ const regex = new RegExp(`\\b${escaped}\\b`);
202
+ if (regex.test(taskLower)) {
203
+ return { score: 1.0, detected: kw };
204
+ }
205
+ }
206
+ return { score: 0.0, detected: undefined };
207
+ }
208
+ function scoreDomainClarity(taskLower, _tokens) {
209
+ for (const kw of DOMAIN_KEYWORDS) {
210
+ const escaped = kw.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
211
+ const regex = new RegExp(`\\b${escaped}\\b`);
212
+ if (regex.test(taskLower)) {
213
+ return { score: 1.0, detected: kw };
214
+ }
215
+ }
216
+ return { score: 0.0, detected: undefined };
217
+ }
218
+ /**
219
+ * Factor 4: Target Specificity
220
+ *
221
+ * Rewards concrete targets:
222
+ * - File/directory path tokens (contain '/' or end in known extension)
223
+ * - camelCase or snake_case identifiers (internal caps or underscores)
224
+ * - Quoted identifiers: "something" or 'something'
225
+ * - PascalCase identifiers (likely type/class names)
226
+ * - Known extensions mentioned without full path (.ts, .json, etc.)
227
+ *
228
+ * Score:
229
+ * 0 targets → 0.0
230
+ * 1 target → 0.6
231
+ * 2 targets → 0.8
232
+ * ≥ 3 → 1.0
233
+ */
234
+ function scoreTargetSpecificity(taskOriginal, taskLower, tokens) {
235
+ const targets = new Set();
236
+ // File/directory paths (contain '/' or '\')
237
+ for (const token of tokens) {
238
+ if (/[/\\]/.test(token) && token.length > 1) {
239
+ targets.add(token);
240
+ }
241
+ }
242
+ // Tokens with known source extensions
243
+ const EXT_RE = /\.(ts|tsx|js|mjs|cjs|json|yaml|yml|md|sh|py|go|rs|java)$/i;
244
+ for (const token of tokens) {
245
+ if (EXT_RE.test(token)) {
246
+ targets.add(token);
247
+ }
248
+ }
249
+ // camelCase identifiers (at least one lowercase followed by uppercase)
250
+ const CAMEL_RE = /^[a-z][a-z0-9]*[A-Z][a-zA-Z0-9]*$/;
251
+ for (const token of tokens) {
252
+ if (CAMEL_RE.test(token)) {
253
+ targets.add(token);
254
+ }
255
+ }
256
+ // snake_case identifiers (at least one underscore between word chars)
257
+ const SNAKE_RE = /^[a-z][a-z0-9]*(_[a-z0-9]+)+$/;
258
+ for (const token of tokens) {
259
+ if (SNAKE_RE.test(token)) {
260
+ targets.add(token);
261
+ }
262
+ }
263
+ // PascalCase (starts with uppercase, has mixed case, length > 3)
264
+ const PASCAL_RE = /^[A-Z][a-z][a-zA-Z0-9]{2,}$/;
265
+ for (const token of tokens) {
266
+ if (PASCAL_RE.test(token)) {
267
+ targets.add(token);
268
+ }
269
+ }
270
+ // ALL_CAPS identifiers like README, API, CLI, UI, etc. (3+ chars)
271
+ const ALLCAPS_RE = /^[A-Z][A-Z0-9_]{2,}$/;
272
+ for (const token of tokens) {
273
+ const cleaned = token.replace(/[^A-Z0-9_]/g, '');
274
+ if (ALLCAPS_RE.test(cleaned)) {
275
+ targets.add(token);
276
+ }
277
+ }
278
+ // Quoted identifiers
279
+ const QUOTED_RE = /["'`]([^"'`]{2,40})["'`]/g;
280
+ let m;
281
+ while ((m = QUOTED_RE.exec(taskOriginal)) !== null) {
282
+ if (m[1] !== undefined)
283
+ targets.add(m[1]);
284
+ }
285
+ // CLI flags like --force, --json
286
+ const FLAG_RE = /--[a-z][-a-z0-9]+/g;
287
+ while ((m = FLAG_RE.exec(taskLower)) !== null) {
288
+ if (m[0] !== undefined)
289
+ targets.add(m[0]);
290
+ }
291
+ // Package scope tokens (e.g. @codeledger/engine, packages/engine)
292
+ const SCOPE_RE = /@[a-z][-a-z0-9]*\/[a-z][-a-z0-9]*/g;
293
+ while ((m = SCOPE_RE.exec(taskLower)) !== null) {
294
+ if (m[0] !== undefined)
295
+ targets.add(m[0]);
296
+ }
297
+ const detected = Array.from(targets).slice(0, 10);
298
+ const count = detected.length;
299
+ const score = count === 0 ? 0.0
300
+ : count === 1 ? 0.6
301
+ : count === 2 ? 0.8
302
+ : 1.0;
303
+ return { score, detected };
304
+ }
305
+ function scoreConstraintPresence(taskLower) {
306
+ for (const kw of CONSTRAINT_KEYWORDS) {
307
+ if (taskLower.includes(kw)) {
308
+ return 1.0;
309
+ }
310
+ }
311
+ return 0.0;
312
+ }
313
+ // ─── Diagnostics ─────────────────────────────────────────────────────────────
314
+ function buildDiagnostics(factors, tokens) {
315
+ const issues = [];
316
+ const recommendations = [];
317
+ if (factors.tokenSignalScore < 0.6) {
318
+ issues.push(`Prompt is too short (${tokens.length} token${tokens.length === 1 ? '' : 's'}); too little context for reliable file selection.`);
319
+ recommendations.push('Expand your prompt with more detail about what you want to change and where.');
320
+ }
321
+ if (factors.operationClarityScore === 0) {
322
+ issues.push('No clear action verb detected (e.g., fix, add, refactor, update, remove).');
323
+ recommendations.push('Start the prompt with a concrete action: "Fix …", "Add …", "Refactor …".');
324
+ }
325
+ if (factors.domainClarityScore === 0) {
326
+ issues.push('No recognisable technical domain detected (e.g., auth, api, database, cli, types).');
327
+ recommendations.push('Include the technical area this task belongs to (e.g., "in the auth middleware", "for the database layer").');
328
+ }
329
+ if (factors.targetSpecificityScore < 0.6) {
330
+ issues.push('No specific target identified (file path, function name, module name, or flag).');
331
+ recommendations.push('Name the specific file, function, or module being changed (e.g., "in packages/cli/src/commands/context.ts", "the buildSlice function").');
332
+ }
333
+ return { issues, recommendations };
334
+ }
335
+ // ─── Utilities ────────────────────────────────────────────────────────────────
336
+ /**
337
+ * Tokenize a task string into meaningful tokens.
338
+ * Splits on whitespace and common punctuation, preserving paths and identifiers.
339
+ */
340
+ function tokenize(task) {
341
+ // Split on whitespace, keeping compound tokens intact
342
+ return task
343
+ .split(/\s+/)
344
+ .map((t) => t.replace(/^[,;:()"'`]+|[,;:()"'`]+$/g, ''))
345
+ .filter((t) => t.length > 0);
346
+ }
347
+ //# sourceMappingURL=score.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"score.js","sourceRoot":"","sources":["../../src/isc/score.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,gFAAgF;AAEhF,MAAM,cAAc,GAAU,IAAI,CAAC;AACnC,MAAM,mBAAmB,GAAK,IAAI,CAAC;AACnC,MAAM,gBAAgB,GAAQ,IAAI,CAAC;AACnC,MAAM,oBAAoB,GAAI,IAAI,CAAC;AACnC,MAAM,qBAAqB,GAAG,IAAI,CAAC;AAEnC,iFAAiF;AAEjF,MAAM,CAAC,MAAM,wBAAwB,GAAK,IAAI,CAAC;AAC/C,MAAM,CAAC,MAAM,kBAAkB,GAAW,IAAI,CAAC;AAE/C,iFAAiF;AAEjF;;;GAGG;AACH,MAAM,kBAAkB,GAAsB;IAC5C,YAAY;IACZ,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO;IACjC,OAAO,EAAE,SAAS,EAAE,UAAU;IAC9B,OAAO,EAAE,QAAQ,EAAE,WAAW;IAC9B,QAAQ,EAAE,SAAS,EAAE,WAAW;IAChC,SAAS,EAAE,UAAU,EAAE,WAAW;IAClC,gBAAgB;IAChB,KAAK,EAAE,MAAM,EAAE,QAAQ;IACvB,WAAW,EAAE,YAAY,EAAE,cAAc;IACzC,QAAQ,EAAE,SAAS,EAAE,UAAU;IAC/B,OAAO,EAAE,QAAQ,EAAE,UAAU;IAC7B,WAAW,EAAE,YAAY,EAAE,aAAa;IACxC,mBAAmB;IACnB,UAAU,EAAE,WAAW,EAAE,aAAa;IACtC,QAAQ,EAAE,SAAS,EAAE,UAAU;IAC/B,MAAM,EAAE,OAAO,EAAE,QAAQ;IACzB,SAAS,EAAE,UAAU,EAAE,YAAY;IACnC,OAAO,EAAE,QAAQ,EAAE,UAAU;IAC7B,YAAY,EAAE,aAAa,EAAE,cAAc;IAC3C,kBAAkB;IAClB,QAAQ,EAAE,SAAS,EAAE,UAAU;IAC/B,SAAS,EAAE,UAAU,EAAE,WAAW;IAClC,QAAQ,EAAE,SAAS,EAAE,UAAU;IAC/B,QAAQ,EAAE,UAAU,EAAE,WAAW;IACjC,SAAS,EAAE,UAAU,EAAE,WAAW;IAClC,kBAAkB;IAClB,QAAQ,EAAE,SAAS,EAAE,UAAU;IAC/B,QAAQ,EAAE,SAAS,EAAE,UAAU;IAC/B,MAAM,EAAE,OAAO,EAAE,UAAU;IAC3B,OAAO;IACP,MAAM,EAAE,OAAO,EAAE,SAAS;IAC1B,YAAY,EAAE,UAAU,EAAE,OAAO;IACjC,qBAAqB;IACrB,UAAU,EAAE,WAAW,EAAE,aAAa;IACtC,SAAS,EAAE,UAAU,EAAE,YAAY;IACnC,qBAAqB;IACrB,SAAS,EAAE,UAAU,EAAE,WAAW;IAClC,UAAU,EAAE,WAAW,EAAE,YAAY;IACrC,SAAS,EAAE,UAAU,EAAE,WAAW;IAClC,oBAAoB;IACpB,SAAS,EAAE,UAAU,EAAE,WAAW;IAClC,SAAS,EAAE,UAAU,EAAE,YAAY;IACnC,MAAM,EAAE,OAAO,EAAE,SAAS;CAC3B,CAAC;AAEF;;;GAGG;AACH,MAAM,eAAe,GAAsB;IACzC,kBAAkB;IAClB,MAAM,EAAE,gBAAgB,EAAE,eAAe,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS;IACvE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM;IACvE,eAAe;IACf,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAC/D,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY;IACpD,qBAAqB;IACrB,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO;IACzE,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO;IACxD,gBAAgB;IAChB,IAAI,EAAE,UAAU,EAAE,WAAW,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO;IACxE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM;IACpD,aAAa;IACb,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ;IACnE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ;IACjD,iBAAiB;IACjB,QAAQ,EAAE,eAAe,EAAE,UAAU,EAAE,KAAK,EAAE,aAAa;IAC3D,QAAQ,EAAE,YAAY,EAAE,gBAAgB;IACxC,iBAAiB;IACjB,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ;IAChE,QAAQ;IACR,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU;IAC9D,0BAA0B;IAC1B,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,OAAO;IACxD,iBAAiB;IACjB,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,YAAY;IAClD,6BAA6B;IAC7B,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK;IACjE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS;CAC3D,CAAC;AAEF;;GAEG;AACH,MAAM,mBAAmB,GAAsB;IAC7C,SAAS,EAAE,kBAAkB,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM;IACjE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,iBAAiB,EAAE,kBAAkB;IACrE,aAAa,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,EAAE,QAAQ;IAC/D,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,YAAY,EAAE,QAAQ;IACzD,cAAc,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS;CAClD,CAAC;AAEF,iFAAiF;AAEjF;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CAAC,IAAY;IACjD,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;IAC5C,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAE9B,4EAA4E;IAC5E,MAAM,gBAAgB,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAElD,4EAA4E;IAC5E,MAAM,EAAE,KAAK,EAAE,qBAAqB,EAAE,QAAQ,EAAE,iBAAiB,EAAE,GACjE,qBAAqB,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAE3C,4EAA4E;IAC5E,MAAM,EAAE,KAAK,EAAE,kBAAkB,EAAE,QAAQ,EAAE,cAAc,EAAE,GAC3D,kBAAkB,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAExC,4EAA4E;IAC5E,MAAM,EAAE,KAAK,EAAE,sBAAsB,EAAE,QAAQ,EAAE,eAAe,EAAE,GAChE,sBAAsB,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;IAElD,4EAA4E;IAC5E,MAAM,uBAAuB,GAAG,uBAAuB,CAAC,SAAS,CAAC,CAAC;IAEnE,4EAA4E;IAC5E,MAAM,OAAO,GAA6B;QACxC,gBAAgB;QAChB,qBAAqB;QACrB,kBAAkB;QAClB,sBAAsB;QACtB,uBAAuB;KACxB,CAAC;IAEF,MAAM,KAAK,GACT,gBAAgB,GAAU,cAAc;QACxC,qBAAqB,GAAK,mBAAmB;QAC7C,kBAAkB,GAAQ,gBAAgB;QAC1C,sBAAsB,GAAI,oBAAoB;QAC9C,uBAAuB,GAAG,qBAAqB,CAAC;IAElD,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;IAErD,4EAA4E;IAC5E,MAAM,QAAQ,GAAG,YAAY,IAAI,wBAAwB;QACvD,CAAC,CAAC,YAAY;QACd,CAAC,CAAC,YAAY,IAAI,kBAAkB;YAClC,CAAC,CAAC,MAAM;YACR,CAAC,CAAC,cAAc,CAAC;IAErB,4EAA4E;IAC5E,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,GAAG,gBAAgB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAEtE,OAAO;QACL,KAAK,EAAE,YAAY;QACnB,QAAQ;QACR,OAAO;QACP,MAAM;QACN,eAAe;QACf,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,iBAAiB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACnD,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7C,GAAG,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC3D,CAAC;AACJ,CAAC;AAED,iFAAiF;AAEjF;;;;;;;;;GASG;AACH,SAAS,gBAAgB,CAAC,MAAgB;IACxC,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC;IACxB,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,GAAG,CAAC;IACtB,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,GAAG,CAAC;IACxB,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,GAAG,CAAC;IACvB,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,GAAG,CAAC;IACvB,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,qBAAqB,CAC5B,SAAiB,EACjB,OAAiB;IAEjB,KAAK,MAAM,EAAE,IAAI,kBAAkB,EAAE,CAAC;QACpC,gDAAgD;QAChD,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;QAC1D,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,MAAM,OAAO,KAAK,CAAC,CAAC;QAC7C,IAAI,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;YAC1B,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;QACtC,CAAC;IACH,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;AAC7C,CAAC;AAED,SAAS,kBAAkB,CACzB,SAAiB,EACjB,OAAiB;IAEjB,KAAK,MAAM,EAAE,IAAI,eAAe,EAAE,CAAC;QACjC,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;QAC1D,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,MAAM,OAAO,KAAK,CAAC,CAAC;QAC7C,IAAI,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;YAC1B,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;QACtC,CAAC;IACH,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;AAC7C,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,SAAS,sBAAsB,CAC7B,YAAoB,EACpB,SAAiB,EACjB,MAAgB;IAEhB,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAElC,4CAA4C;IAC5C,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;IAED,sCAAsC;IACtC,MAAM,MAAM,GAAG,2DAA2D,CAAC;IAC3E,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YACvB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;IAED,uEAAuE;IACvE,MAAM,QAAQ,GAAG,mCAAmC,CAAC;IACrD,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;IAED,sEAAsE;IACtE,MAAM,QAAQ,GAAG,+BAA+B,CAAC;IACjD,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;IAED,iEAAiE;IACjE,MAAM,SAAS,GAAG,6BAA6B,CAAC;IAChD,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;IAED,kEAAkE;IAClE,MAAM,UAAU,GAAG,sBAAsB,CAAC;IAC1C,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;QACjD,IAAI,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YAC7B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;IAED,qBAAqB;IACrB,MAAM,SAAS,GAAG,2BAA2B,CAAC;IAC9C,IAAI,CAAyB,CAAC;IAC9B,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACnD,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,SAAS;YAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5C,CAAC;IAED,iCAAiC;IACjC,MAAM,OAAO,GAAG,oBAAoB,CAAC;IACrC,OAAO,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAC9C,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,SAAS;YAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5C,CAAC;IAED,kEAAkE;IAClE,MAAM,QAAQ,GAAG,oCAAoC,CAAC;IACtD,OAAO,CAAC,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAC/C,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,SAAS;YAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5C,CAAC;IAED,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAClD,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC;IAE9B,MAAM,KAAK,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG;QAC7B,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG;YACnB,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG;gBACnB,CAAC,CAAC,GAAG,CAAC;IAER,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;AAC7B,CAAC;AAED,SAAS,uBAAuB,CAAC,SAAiB;IAChD,KAAK,MAAM,EAAE,IAAI,mBAAmB,EAAE,CAAC;QACrC,IAAI,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;YAC3B,OAAO,GAAG,CAAC;QACb,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,gFAAgF;AAEhF,SAAS,gBAAgB,CACvB,OAAiC,EACjC,MAAgB;IAEhB,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,eAAe,GAAa,EAAE,CAAC;IAErC,IAAI,OAAO,CAAC,gBAAgB,GAAG,GAAG,EAAE,CAAC;QACnC,MAAM,CAAC,IAAI,CAAC,wBAAwB,MAAM,CAAC,MAAM,SAAS,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,oDAAoD,CAAC,CAAC;QAC9I,eAAe,CAAC,IAAI,CAAC,8EAA8E,CAAC,CAAC;IACvG,CAAC;IAED,IAAI,OAAO,CAAC,qBAAqB,KAAK,CAAC,EAAE,CAAC;QACxC,MAAM,CAAC,IAAI,CAAC,2EAA2E,CAAC,CAAC;QACzF,eAAe,CAAC,IAAI,CAAC,0EAA0E,CAAC,CAAC;IACnG,CAAC;IAED,IAAI,OAAO,CAAC,kBAAkB,KAAK,CAAC,EAAE,CAAC;QACrC,MAAM,CAAC,IAAI,CAAC,oFAAoF,CAAC,CAAC;QAClG,eAAe,CAAC,IAAI,CAAC,6GAA6G,CAAC,CAAC;IACtI,CAAC;IAED,IAAI,OAAO,CAAC,sBAAsB,GAAG,GAAG,EAAE,CAAC;QACzC,MAAM,CAAC,IAAI,CAAC,iFAAiF,CAAC,CAAC;QAC/F,eAAe,CAAC,IAAI,CAAC,yIAAyI,CAAC,CAAC;IAClK,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC;AACrC,CAAC;AAED,iFAAiF;AAEjF;;;GAGG;AACH,SAAS,QAAQ,CAAC,IAAY;IAC5B,sDAAsD;IACtD,OAAO,IAAI;SACR,KAAK,CAAC,KAAK,CAAC;SACZ,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,4BAA4B,EAAE,EAAE,CAAC,CAAC;SACvD,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACjC,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @codeledger/engine/license — Signed license verification.
3
+ *
4
+ * Local-first, offline license verification using Ed25519 digital signatures.
5
+ * The private key lives in the license issuer service (separate private repo).
6
+ * Only the public key is embedded here.
7
+ */
8
+ export { parseLicenseKey, isSignedKey, base64urlToBuffer } from './parse.js';
9
+ export type { LicensePayload, ParsedSignedLicense, ParsedLegacyLicense, ParsedLicense, ParseResult, ParseError, } from './parse.js';
10
+ export { verifySignature, validateClaims, verifySignedLicense } from './verify.js';
11
+ export type { VerifyResult, VerifySuccess, VerifyFailure } from './verify.js';
12
+ export { KNOWN_PUBLIC_KEYS, getActivePublicKey, getPublicKeyById, } from './publicKey.js';
13
+ export type { PublicKeyEntry } from './publicKey.js';
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/license/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC7E,YAAY,EACV,cAAc,EACd,mBAAmB,EACnB,mBAAmB,EACnB,aAAa,EACb,WAAW,EACX,UAAU,GACX,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AACnF,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE9E,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @codeledger/engine/license — Signed license verification.
3
+ *
4
+ * Local-first, offline license verification using Ed25519 digital signatures.
5
+ * The private key lives in the license issuer service (separate private repo).
6
+ * Only the public key is embedded here.
7
+ */
8
+ export { parseLicenseKey, isSignedKey, base64urlToBuffer } from './parse.js';
9
+ export { verifySignature, validateClaims, verifySignedLicense } from './verify.js';
10
+ export { KNOWN_PUBLIC_KEYS, getActivePublicKey, getPublicKeyById, } from './publicKey.js';
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/license/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAU7E,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAGnF,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * License key parsing — split signed keys into components.
3
+ *
4
+ * Signed format: CL-PRO.<base64url-payload>.<base64url-signature>
5
+ * Legacy format: CL-PRO-XXXX-XXXX-XXXX
6
+ */
7
+ export interface LicensePayload {
8
+ plan: string;
9
+ features: string[];
10
+ issuedAt: string;
11
+ expiresAt: string | null;
12
+ issuedTo?: string;
13
+ licenseId: string;
14
+ }
15
+ export interface ParsedSignedLicense {
16
+ kind: 'signed';
17
+ prefix: string;
18
+ payloadRaw: string;
19
+ signatureRaw: string;
20
+ payload: LicensePayload;
21
+ }
22
+ export interface ParsedLegacyLicense {
23
+ kind: 'legacy';
24
+ rawKey: string;
25
+ }
26
+ export type ParsedLicense = ParsedSignedLicense | ParsedLegacyLicense;
27
+ export interface ParseError {
28
+ kind: 'error';
29
+ reason: string;
30
+ }
31
+ export type ParseResult = ParsedLicense | ParseError;
32
+ /** Convert base64url string to Buffer. Exported for use by verify.ts. */
33
+ export declare function base64urlToBuffer(input: string): Buffer;
34
+ /**
35
+ * Determine whether a key is signed (contains dots) or legacy format.
36
+ */
37
+ export declare function isSignedKey(key: string): boolean;
38
+ /**
39
+ * Parse a license key string into its components.
40
+ */
41
+ export declare function parseLicenseKey(rawKey: string): ParseResult;
42
+ //# sourceMappingURL=parse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../src/license/parse.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,cAAc,CAAC;CACzB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,aAAa,GAAG,mBAAmB,GAAG,mBAAmB,CAAC;AAEtE,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,WAAW,GAAG,aAAa,GAAG,UAAU,CAAC;AAIrD,yEAAyE;AACzE,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMvD;AAOD;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEhD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,CAyB3D"}
@@ -0,0 +1,106 @@
1
+ /**
2
+ * License key parsing — split signed keys into components.
3
+ *
4
+ * Signed format: CL-PRO.<base64url-payload>.<base64url-signature>
5
+ * Legacy format: CL-PRO-XXXX-XXXX-XXXX
6
+ */
7
+ // ── Base64url helpers ──────────────────────────────────────────────────────
8
+ /** Convert base64url string to Buffer. Exported for use by verify.ts. */
9
+ export function base64urlToBuffer(input) {
10
+ let base64 = input.replace(/-/g, '+').replace(/_/g, '/');
11
+ const pad = base64.length % 4;
12
+ if (pad === 2)
13
+ base64 += '==';
14
+ else if (pad === 3)
15
+ base64 += '=';
16
+ return Buffer.from(base64, 'base64');
17
+ }
18
+ // ── Parser ─────────────────────────────────────────────────────────────────
19
+ const SIGNED_PREFIX = 'CL-PRO';
20
+ const LEGACY_PATTERN = /^CL-PRO-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}$/;
21
+ /**
22
+ * Determine whether a key is signed (contains dots) or legacy format.
23
+ */
24
+ export function isSignedKey(key) {
25
+ return key.startsWith(SIGNED_PREFIX + '.') && key.split('.').length === 3;
26
+ }
27
+ /**
28
+ * Parse a license key string into its components.
29
+ */
30
+ export function parseLicenseKey(rawKey) {
31
+ if (!rawKey || typeof rawKey !== 'string') {
32
+ return { kind: 'error', reason: 'License key is empty.' };
33
+ }
34
+ const trimmed = rawKey.trim();
35
+ // Signed format: CL-PRO.<payload>.<signature>
36
+ if (isSignedKey(trimmed)) {
37
+ return parseSignedKey(trimmed);
38
+ }
39
+ // Legacy format: CL-PRO-XXXX-XXXX-XXXX
40
+ if (LEGACY_PATTERN.test(trimmed)) {
41
+ return { kind: 'legacy', rawKey: trimmed };
42
+ }
43
+ // Neither format matches
44
+ if (trimmed.startsWith('CL-PRO.')) {
45
+ return { kind: 'error', reason: 'Invalid signed license format. Expected: CL-PRO.<payload>.<signature>' };
46
+ }
47
+ if (trimmed.startsWith('CL-PRO-')) {
48
+ return { kind: 'error', reason: 'Invalid key format. Expected: CL-PRO-XXXX-XXXX-XXXX (uppercase alphanumeric).' };
49
+ }
50
+ return { kind: 'error', reason: 'Invalid license format.' };
51
+ }
52
+ function parseSignedKey(key) {
53
+ const parts = key.split('.');
54
+ if (parts.length !== 3) {
55
+ return { kind: 'error', reason: 'Invalid signed license format. Expected three dot-separated parts.' };
56
+ }
57
+ const [prefix, payloadRaw, signatureRaw] = parts;
58
+ if (prefix !== SIGNED_PREFIX) {
59
+ return { kind: 'error', reason: `Invalid license prefix. Expected "${SIGNED_PREFIX}".` };
60
+ }
61
+ if (!payloadRaw || !signatureRaw) {
62
+ return { kind: 'error', reason: 'License payload or signature is empty.' };
63
+ }
64
+ // Decode and parse payload
65
+ let decoded;
66
+ try {
67
+ const json = base64urlToBuffer(payloadRaw).toString('utf-8');
68
+ decoded = JSON.parse(json);
69
+ }
70
+ catch {
71
+ return { kind: 'error', reason: 'Failed to decode license payload.' };
72
+ }
73
+ if (typeof decoded !== 'object' || decoded === null) {
74
+ return { kind: 'error', reason: 'License payload is not a valid object.' };
75
+ }
76
+ const obj = decoded;
77
+ // Validate required fields
78
+ if (typeof obj['plan'] !== 'string') {
79
+ return { kind: 'error', reason: 'Missing required field: plan.' };
80
+ }
81
+ if (!Array.isArray(obj['features'])) {
82
+ return { kind: 'error', reason: 'Missing required field: features.' };
83
+ }
84
+ if (typeof obj['issuedAt'] !== 'string') {
85
+ return { kind: 'error', reason: 'Missing required field: issuedAt.' };
86
+ }
87
+ if (typeof obj['licenseId'] !== 'string') {
88
+ return { kind: 'error', reason: 'Missing required field: licenseId.' };
89
+ }
90
+ const payload = {
91
+ plan: obj['plan'],
92
+ features: obj['features'],
93
+ issuedAt: obj['issuedAt'],
94
+ expiresAt: typeof obj['expiresAt'] === 'string' ? obj['expiresAt'] : null,
95
+ issuedTo: typeof obj['issuedTo'] === 'string' ? obj['issuedTo'] : undefined,
96
+ licenseId: obj['licenseId'],
97
+ };
98
+ return {
99
+ kind: 'signed',
100
+ prefix,
101
+ payloadRaw,
102
+ signatureRaw,
103
+ payload,
104
+ };
105
+ }
106
+ //# sourceMappingURL=parse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.js","sourceRoot":"","sources":["../../src/license/parse.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Embedded public key for license verification.
3
+ *
4
+ * This is the Ed25519 public key corresponding to the private key held by
5
+ * the license issuer service. Only the public key lives in this repo.
6
+ *
7
+ * Key rotation: add new keys to KNOWN_PUBLIC_KEYS with a unique keyId.
8
+ * The active key is used for new verifications; older keys remain for
9
+ * backward compatibility with previously issued licenses.
10
+ */
11
+ export interface PublicKeyEntry {
12
+ keyId: string;
13
+ algorithm: 'Ed25519';
14
+ /** PEM-encoded public key */
15
+ pem: string;
16
+ /** When this key became active */
17
+ activeFrom: string;
18
+ /** If set, this key is no longer used for new issuance */
19
+ retiredAt?: string;
20
+ }
21
+ /**
22
+ * Known public keys for license verification.
23
+ * The issuer service signs with the corresponding private key.
24
+ *
25
+ * To rotate keys:
26
+ * 1. Generate a new Ed25519 keypair in the issuer service
27
+ * 2. Add the public key here with a new keyId
28
+ * 3. Set retiredAt on the old key
29
+ * 4. The issuer starts signing with the new key
30
+ * 5. Old licenses continue to verify against the old key
31
+ */
32
+ export declare const KNOWN_PUBLIC_KEYS: PublicKeyEntry[];
33
+ /** Get the currently active public key (most recent non-retired). */
34
+ export declare function getActivePublicKey(): PublicKeyEntry;
35
+ /** Find a public key by keyId (for verifying older licenses). */
36
+ export declare function getPublicKeyById(keyId: string): PublicKeyEntry | undefined;
37
+ //# sourceMappingURL=publicKey.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publicKey.d.ts","sourceRoot":"","sources":["../../src/license/publicKey.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,SAAS,CAAC;IACrB,6BAA6B;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,kCAAkC;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,0DAA0D;IAC1D,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iBAAiB,EAAE,cAAc,EAW7C,CAAC;AAEF,qEAAqE;AACrE,wBAAgB,kBAAkB,IAAI,cAAc,CAQnD;AAED,iEAAiE;AACjE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAE1E"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Embedded public key for license verification.
3
+ *
4
+ * This is the Ed25519 public key corresponding to the private key held by
5
+ * the license issuer service. Only the public key lives in this repo.
6
+ *
7
+ * Key rotation: add new keys to KNOWN_PUBLIC_KEYS with a unique keyId.
8
+ * The active key is used for new verifications; older keys remain for
9
+ * backward compatibility with previously issued licenses.
10
+ */
11
+ /**
12
+ * Known public keys for license verification.
13
+ * The issuer service signs with the corresponding private key.
14
+ *
15
+ * To rotate keys:
16
+ * 1. Generate a new Ed25519 keypair in the issuer service
17
+ * 2. Add the public key here with a new keyId
18
+ * 3. Set retiredAt on the old key
19
+ * 4. The issuer starts signing with the new key
20
+ * 5. Old licenses continue to verify against the old key
21
+ */
22
+ export const KNOWN_PUBLIC_KEYS = [
23
+ {
24
+ keyId: 'cl-v1',
25
+ algorithm: 'Ed25519',
26
+ pem: [
27
+ '-----BEGIN PUBLIC KEY-----',
28
+ 'MCowBQYDK2VwAyEADQoOMv3lKd7sfINa9Fr9cfRQn9QiE/pEO5XcOaFc0Ys=',
29
+ '-----END PUBLIC KEY-----',
30
+ ].join('\n'),
31
+ activeFrom: '2026-03-22T00:00:00Z',
32
+ },
33
+ ];
34
+ /** Get the currently active public key (most recent non-retired). */
35
+ export function getActivePublicKey() {
36
+ const active = KNOWN_PUBLIC_KEYS
37
+ .filter((k) => !k.retiredAt)
38
+ .sort((a, b) => b.activeFrom.localeCompare(a.activeFrom));
39
+ if (active.length === 0) {
40
+ throw new Error('No active public key configured.');
41
+ }
42
+ return active[0];
43
+ }
44
+ /** Find a public key by keyId (for verifying older licenses). */
45
+ export function getPublicKeyById(keyId) {
46
+ return KNOWN_PUBLIC_KEYS.find((k) => k.keyId === keyId);
47
+ }
48
+ //# sourceMappingURL=publicKey.js.map