@skillstech/thunderlang 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +375 -0
- package/LICENSE +21 -0
- package/README.md +165 -0
- package/dist/core.cjs +6768 -0
- package/dist/index.cjs +9308 -0
- package/intent-graph.schema.json +687 -0
- package/package.json +84 -0
- package/src/ai-core.mjs +67 -0
- package/src/ai-events.mjs +56 -0
- package/src/ai.mjs +324 -0
- package/src/arch.mjs +55 -0
- package/src/atlas.mjs +118 -0
- package/src/changes.mjs +74 -0
- package/src/classification.mjs +36 -0
- package/src/cli.mjs +1534 -0
- package/src/codegen.mjs +214 -0
- package/src/compile.mjs +142 -0
- package/src/comprehension.mjs +130 -0
- package/src/conflict.mjs +0 -0
- package/src/core.d.ts +99 -0
- package/src/core.mjs +92 -0
- package/src/data-schema.mjs +137 -0
- package/src/decision.mjs +38 -0
- package/src/distributed.mjs +48 -0
- package/src/draft.mjs +101 -0
- package/src/drift.mjs +177 -0
- package/src/emit.mjs +519 -0
- package/src/exporters.mjs +245 -0
- package/src/expr.mjs +245 -0
- package/src/fable.mjs +110 -0
- package/src/focus.mjs +151 -0
- package/src/format.mjs +55 -0
- package/src/governance.mjs +100 -0
- package/src/graph-source.mjs +292 -0
- package/src/guard.mjs +105 -0
- package/src/guardian.mjs +98 -0
- package/src/hash.mjs +89 -0
- package/src/importers.mjs +194 -0
- package/src/index.d.ts +725 -0
- package/src/index.mjs +185 -0
- package/src/intellisense.mjs +210 -0
- package/src/intent-atlas.mjs +77 -0
- package/src/intent-graph.mjs +346 -0
- package/src/intent-ir.mjs +144 -0
- package/src/intent-schema.mjs +215 -0
- package/src/ledger.mjs +109 -0
- package/src/lifecycle.mjs +56 -0
- package/src/lift.mjs +693 -0
- package/src/lsp.mjs +152 -0
- package/src/mcp.mjs +158 -0
- package/src/migrate.mjs +118 -0
- package/src/outcome.mjs +93 -0
- package/src/parse.mjs +733 -0
- package/src/patch.mjs +364 -0
- package/src/privacy.mjs +61 -0
- package/src/proof-schema.mjs +129 -0
- package/src/report.mjs +84 -0
- package/src/runtime.mjs +96 -0
- package/src/sarif.mjs +88 -0
- package/src/scan-queries.mjs +97 -0
- package/src/scan.mjs +87 -0
- package/src/security.mjs +73 -0
- package/src/select.mjs +80 -0
- package/src/semantic-diff.mjs +125 -0
- package/src/simulate.mjs +106 -0
- package/src/style.mjs +250 -0
- package/src/sync.mjs +103 -0
- package/src/testing.mjs +59 -0
- package/src/twelve-factor.mjs +173 -0
- package/src/verify-diff.mjs +105 -0
- package/src/xml.mjs +87 -0
- package/syntaxes/intent.tmLanguage.json +55 -0
package/src/codegen.mjs
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
// Code generation (intent-codegen-v1) , deterministic scaffolds from intent. NO AI: the same
|
|
2
|
+
// intent always produces the same code. It generates what the intent fully determines (typed
|
|
3
|
+
// interfaces, and the decision logic, which is already executable) and leaves honest TODO
|
|
4
|
+
// markers where a human must supply the business logic , never a fake implementation. This is
|
|
5
|
+
// the "see how it works, then change it" surface for the playground and `intent gen`.
|
|
6
|
+
//
|
|
7
|
+
// Pure and browser-safe so the playground can render it. TypeScript first; the same adapter
|
|
8
|
+
// shape (a type map + a body walk) extends to C# / Java.
|
|
9
|
+
|
|
10
|
+
import { exprToJs, exprToCSharp, exprToJava } from './expr.mjs';
|
|
11
|
+
import { subjectName } from './parse.mjs';
|
|
12
|
+
|
|
13
|
+
export const CODEGEN_SCHEMA = 'intent-codegen-v1';
|
|
14
|
+
|
|
15
|
+
// Semantic type -> TypeScript type. Unknown/domain types become a named type (interface stub).
|
|
16
|
+
const TS_TYPES = {
|
|
17
|
+
Email: 'string', Url: 'string', UserId: 'string', AccountId: 'string', OrderId: 'string',
|
|
18
|
+
InvoiceId: 'string', CustomerId: 'string', PaymentId: 'string', EventId: 'string',
|
|
19
|
+
Secret: 'string', Token: 'string', Jwt: 'string', Password: 'string', IdempotencyKey: 'string',
|
|
20
|
+
Money: 'number', Currency: 'string', Percentage: 'number', Count: 'number', Duration: 'number',
|
|
21
|
+
Date: 'string', DateTime: 'string', Flag: 'boolean', TraceId: 'string', CorrelationId: 'string',
|
|
22
|
+
Version: 'string', EnvironmentName: 'string',
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
function tsType(type, domain) {
|
|
26
|
+
if (!type) return 'unknown';
|
|
27
|
+
const list = /^List<(.+)>$/.exec(type);
|
|
28
|
+
if (list) { domain.add(list[1]); return `${tsType(list[1], domain)}[]`; }
|
|
29
|
+
const base = type.replace(/\(.*\)/, '');
|
|
30
|
+
if (TS_TYPES[base]) return TS_TYPES[base];
|
|
31
|
+
domain.add(base); // a domain/entity type -> emit an interface stub for it
|
|
32
|
+
return base;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const lower = (s) => (s ? s[0].toLowerCase() + s.slice(1) : s);
|
|
36
|
+
const pascal = (s) => (s ? s[0].toUpperCase() + s.slice(1) : s).replace(/[^A-Za-z0-9]/g, '');
|
|
37
|
+
const fieldsIface = (name, fields, domain) => [
|
|
38
|
+
`export interface ${name} {`,
|
|
39
|
+
...fields.map((f) => ` ${f.name}: ${tsType(f.type, domain)};`),
|
|
40
|
+
'}', '',
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
/** Generate a deterministic TypeScript scaffold from a parsed intent AST. Returns a string. */
|
|
44
|
+
export function toTypeScript(ast) {
|
|
45
|
+
const subject = pascal(subjectName(ast) || 'Intent');
|
|
46
|
+
const domain = new Set();
|
|
47
|
+
const L = [];
|
|
48
|
+
|
|
49
|
+
L.push(
|
|
50
|
+
`// ${subject} , generated from ThunderLang (intent-codegen-v1). Deterministic, no AI.`,
|
|
51
|
+
'// The typed contract and the decision logic below are fully determined by the intent.',
|
|
52
|
+
'// Business logic marked TODO is yours to complete; the guarantees and never-rules state',
|
|
53
|
+
'// what your implementation must uphold. Regenerate any time; edits to TODO bodies are lost.',
|
|
54
|
+
'',
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
// Input / output interfaces.
|
|
58
|
+
if ((ast.inputs || []).length) L.push(...fieldsIface(`${subject}Input`, ast.inputs, domain));
|
|
59
|
+
if ((ast.outputs || []).length) L.push(...fieldsIface(`${subject}Output`, ast.outputs, domain));
|
|
60
|
+
|
|
61
|
+
// Decisions , real, first-hit logic (the intent already executes these).
|
|
62
|
+
for (const d of ast.decisions || []) {
|
|
63
|
+
const inputs = d.inputs || [];
|
|
64
|
+
const params = inputs.map((i) => `${i}: unknown`).join(', ');
|
|
65
|
+
L.push(`// decision ${d.name} , first matching rule wins.`);
|
|
66
|
+
L.push(`export function ${lower(pascal(d.name))}(${params}): string {`);
|
|
67
|
+
for (const r of d.rules || []) {
|
|
68
|
+
let cond;
|
|
69
|
+
try { cond = exprToJs(r.when, { inputs }); }
|
|
70
|
+
catch { cond = `false /* TODO: could not translate "${r.when}" */`; }
|
|
71
|
+
L.push(` if (${cond}) return ${JSON.stringify(r.result)}; // rule ${r.name}`);
|
|
72
|
+
}
|
|
73
|
+
L.push(` return ${JSON.stringify(d.default ?? 'Undecided')}; // default`);
|
|
74
|
+
L.push('}', '');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// The mission function , signature is determined; body is a guarded stub.
|
|
78
|
+
const inName = (ast.inputs || []).length ? `${subject}Input` : 'void';
|
|
79
|
+
const outName = (ast.outputs || []).length ? `${subject}Output` : 'void';
|
|
80
|
+
const arg = inName === 'void' ? '' : `input: ${inName}`;
|
|
81
|
+
L.push(`export function ${lower(subject)}(${arg}): ${outName} {`);
|
|
82
|
+
for (const r of ast.requires || []) L.push(` // precondition: ${r} , TODO: validate`);
|
|
83
|
+
for (const n of ast.neverRules || []) L.push(` // NEVER: ${n.statement} , your code must not do this`);
|
|
84
|
+
for (const g of ast.guarantees || []) L.push(` // GUARANTEE: ${g.statement} , your code must uphold this${g.verify?.length ? ` (verify: ${g.verify.join(', ')})` : ''}`);
|
|
85
|
+
L.push(' throw new Error("TODO: implement , the intent above defines what this must do.");');
|
|
86
|
+
L.push('}', '');
|
|
87
|
+
|
|
88
|
+
// Domain type stubs for any referenced entity types.
|
|
89
|
+
const stubs = [...domain].filter((t) => !TS_TYPES[t] && /^[A-Z]/.test(t)).sort();
|
|
90
|
+
if (stubs.length) {
|
|
91
|
+
L.push('// Domain types referenced by the intent , complete these.');
|
|
92
|
+
for (const t of stubs) L.push(`export interface ${t} { /* TODO: fields */ }`);
|
|
93
|
+
L.push('');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return L.join('\n');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// ── C# ───────────────────────────────────────────────────────────────────────
|
|
100
|
+
const CS_TYPES = {
|
|
101
|
+
Email: 'string', Url: 'string', UserId: 'string', AccountId: 'string', OrderId: 'string',
|
|
102
|
+
InvoiceId: 'string', CustomerId: 'string', Secret: 'string', Token: 'string', Jwt: 'string',
|
|
103
|
+
IdempotencyKey: 'string', Currency: 'string', Date: 'DateTime', DateTime: 'DateTime',
|
|
104
|
+
Money: 'decimal', Percentage: 'decimal', Count: 'int', Duration: 'int', Flag: 'bool',
|
|
105
|
+
};
|
|
106
|
+
function csType(type, domain) {
|
|
107
|
+
if (!type) return 'object';
|
|
108
|
+
const list = /^List<(.+)>$/.exec(type);
|
|
109
|
+
if (list) return `List<${csType(list[1], domain)}>`;
|
|
110
|
+
const base = type.replace(/\(.*\)/, '');
|
|
111
|
+
if (CS_TYPES[base]) return CS_TYPES[base];
|
|
112
|
+
domain.add(base); return base;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** Generate a deterministic C# scaffold from an intent AST. */
|
|
116
|
+
export function toCSharp(ast) {
|
|
117
|
+
const subject = pascal(subjectName(ast) || 'Intent');
|
|
118
|
+
const domain = new Set();
|
|
119
|
+
const L = [
|
|
120
|
+
`// ${subject} , generated from ThunderLang (intent-codegen-v1). Deterministic, no AI.`,
|
|
121
|
+
'// The record contract and the decision logic are fully determined by the intent;',
|
|
122
|
+
'// business logic marked TODO is yours, bound by the guarantees and never-rules below.',
|
|
123
|
+
'',
|
|
124
|
+
'using System;',
|
|
125
|
+
'using System.Collections.Generic;',
|
|
126
|
+
'using System.Linq;',
|
|
127
|
+
'',
|
|
128
|
+
];
|
|
129
|
+
const rec = (name, fields) => fields.length
|
|
130
|
+
? [`public record ${name}(${fields.map((f) => `${csType(f.type, domain)} ${pascal(f.name)}`).join(', ')});`, '']
|
|
131
|
+
: [];
|
|
132
|
+
if ((ast.inputs || []).length) L.push(...rec(`${subject}Input`, ast.inputs));
|
|
133
|
+
if ((ast.outputs || []).length) L.push(...rec(`${subject}Output`, ast.outputs));
|
|
134
|
+
L.push(`public static class ${subject}`, '{');
|
|
135
|
+
for (const d of ast.decisions || []) {
|
|
136
|
+
const inputs = d.inputs || [];
|
|
137
|
+
L.push(` // decision ${d.name} , first matching rule wins.`);
|
|
138
|
+
L.push(` public static string ${pascal(d.name)}(${inputs.map((i) => `dynamic ${i}`).join(', ')})`);
|
|
139
|
+
L.push(' {');
|
|
140
|
+
for (const r of d.rules || []) {
|
|
141
|
+
let cond; try { cond = exprToCSharp(r.when, { inputs }); } catch { cond = `false /* TODO: "${r.when}" */`; }
|
|
142
|
+
L.push(` if (${cond}) return ${JSON.stringify(r.result)}; // rule ${r.name}`);
|
|
143
|
+
}
|
|
144
|
+
L.push(` return ${JSON.stringify(d.default ?? 'Undecided')}; // default`, ' }');
|
|
145
|
+
}
|
|
146
|
+
const inName = (ast.inputs || []).length ? `${subject}Input` : null;
|
|
147
|
+
const outName = (ast.outputs || []).length ? `${subject}Output` : 'void';
|
|
148
|
+
L.push(` public static ${outName} Run(${inName ? `${inName} input` : ''})`, ' {');
|
|
149
|
+
for (const n of ast.neverRules || []) L.push(` // NEVER: ${n.statement}`);
|
|
150
|
+
for (const g of ast.guarantees || []) L.push(` // GUARANTEE: ${g.statement}`);
|
|
151
|
+
L.push(' throw new NotImplementedException("TODO: implement , the intent above defines what this must do.");', ' }');
|
|
152
|
+
L.push('}', '');
|
|
153
|
+
return L.join('\n');
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// ── Java ─────────────────────────────────────────────────────────────────────
|
|
157
|
+
const JAVA_TYPES = {
|
|
158
|
+
Email: 'String', Url: 'String', UserId: 'String', AccountId: 'String', OrderId: 'String',
|
|
159
|
+
InvoiceId: 'String', CustomerId: 'String', Secret: 'String', Token: 'String', Jwt: 'String',
|
|
160
|
+
IdempotencyKey: 'String', Currency: 'String', Date: 'java.time.LocalDate', DateTime: 'java.time.Instant',
|
|
161
|
+
Money: 'java.math.BigDecimal', Percentage: 'double', Count: 'int', Duration: 'long', Flag: 'boolean',
|
|
162
|
+
};
|
|
163
|
+
function javaType(type, domain) {
|
|
164
|
+
if (!type) return 'Object';
|
|
165
|
+
const list = /^List<(.+)>$/.exec(type);
|
|
166
|
+
if (list) return `java.util.List<${javaType(list[1], domain)}>`;
|
|
167
|
+
const base = type.replace(/\(.*\)/, '');
|
|
168
|
+
if (JAVA_TYPES[base]) return JAVA_TYPES[base];
|
|
169
|
+
domain.add(base); return base;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/** Generate a deterministic Java scaffold from an intent AST. */
|
|
173
|
+
export function toJava(ast) {
|
|
174
|
+
const subject = pascal(subjectName(ast) || 'Intent');
|
|
175
|
+
const domain = new Set();
|
|
176
|
+
const L = [
|
|
177
|
+
`// ${subject} , generated from ThunderLang (intent-codegen-v1). Deterministic, no AI.`,
|
|
178
|
+
'// The record contract and the decision logic are fully determined by the intent;',
|
|
179
|
+
'// business logic marked TODO is yours, bound by the guarantees and never-rules below.',
|
|
180
|
+
'',
|
|
181
|
+
`public final class ${subject} {`,
|
|
182
|
+
` private ${subject}() {}`,
|
|
183
|
+
'',
|
|
184
|
+
];
|
|
185
|
+
const rec = (name, fields) => fields.length
|
|
186
|
+
? [` public record ${name}(${fields.map((f) => `${javaType(f.type, domain)} ${f.name}`).join(', ')}) {}`, '']
|
|
187
|
+
: [];
|
|
188
|
+
if ((ast.inputs || []).length) L.push(...rec(`${subject}Input`, ast.inputs));
|
|
189
|
+
if ((ast.outputs || []).length) L.push(...rec(`${subject}Output`, ast.outputs));
|
|
190
|
+
for (const d of ast.decisions || []) {
|
|
191
|
+
const inputs = d.inputs || [];
|
|
192
|
+
L.push(` // decision ${d.name} , first matching rule wins.`);
|
|
193
|
+
L.push(` public static String ${lower(pascal(d.name))}(${inputs.map((i) => `Object ${i}`).join(', ')}) {`);
|
|
194
|
+
for (const r of d.rules || []) {
|
|
195
|
+
let cond; try { cond = exprToJava(r.when, { inputs }); } catch { cond = `false /* TODO: "${r.when}" */`; }
|
|
196
|
+
L.push(` if (${cond}) return ${JSON.stringify(r.result)}; // rule ${r.name}`);
|
|
197
|
+
}
|
|
198
|
+
L.push(` return ${JSON.stringify(d.default ?? 'Undecided')}; // default`, ' }');
|
|
199
|
+
}
|
|
200
|
+
const inName = (ast.inputs || []).length ? `${subject}Input` : null;
|
|
201
|
+
const outName = (ast.outputs || []).length ? `${subject}Output` : 'void';
|
|
202
|
+
L.push(` public static ${outName} run(${inName ? `${inName} input` : ''}) {`);
|
|
203
|
+
for (const n of ast.neverRules || []) L.push(` // NEVER: ${n.statement}`);
|
|
204
|
+
for (const g of ast.guarantees || []) L.push(` // GUARANTEE: ${g.statement}`);
|
|
205
|
+
L.push(' throw new UnsupportedOperationException("TODO: implement , the intent above defines what this must do.");', ' }');
|
|
206
|
+
L.push('}', '');
|
|
207
|
+
return L.join('\n');
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export const GENERATORS = {
|
|
211
|
+
typescript: toTypeScript, ts: toTypeScript,
|
|
212
|
+
csharp: toCSharp, cs: toCSharp,
|
|
213
|
+
java: toJava,
|
|
214
|
+
};
|
package/src/compile.mjs
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
// Pure, in-memory compile entrypoint shared by the CLI (writes to disk) and the
|
|
2
|
+
// web playground (returns artifacts as strings). No filesystem, no AI.
|
|
3
|
+
// Deterministic given a fixed `generatedAt`.
|
|
4
|
+
|
|
5
|
+
import { parseIntent, slug, subjectName, intentRefId } from './parse.mjs';
|
|
6
|
+
import { twelveFactorSummary } from './twelve-factor.mjs';
|
|
7
|
+
import {
|
|
8
|
+
buildContractGraph, buildArchitectureGraph, buildImplementationPlan,
|
|
9
|
+
semanticDiagnostics, buildProof, sha256,
|
|
10
|
+
} from './emit.mjs';
|
|
11
|
+
|
|
12
|
+
export function renderMarkdown(ast) {
|
|
13
|
+
const L = [];
|
|
14
|
+
L.push(`# ${subjectName(ast) || 'Untitled intent'}`, '');
|
|
15
|
+
if (ast.goal) L.push(`**Goal.** ${ast.goal}`, '');
|
|
16
|
+
if (ast.why) L.push(`**Why.** ${ast.why}`, '');
|
|
17
|
+
if (ast.guarantees.length) {
|
|
18
|
+
L.push('## Guarantees', '');
|
|
19
|
+
for (const g of ast.guarantees) L.push(`- ${g.statement}${g.because ? ` (because ${g.because})` : ''}`);
|
|
20
|
+
L.push('');
|
|
21
|
+
}
|
|
22
|
+
if (ast.neverRules.length) {
|
|
23
|
+
L.push('## Never', '');
|
|
24
|
+
for (const n of ast.neverRules) L.push(`- ${n.statement}${n.because ? ` (because ${n.because})` : ''}`);
|
|
25
|
+
L.push('');
|
|
26
|
+
}
|
|
27
|
+
if (ast.verify.length) { L.push('## Verification', ''); for (const v of ast.verify) L.push(`- ${v}`); L.push(''); }
|
|
28
|
+
return L.join('\n');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Render a mission as Markdown documentation for ONE audience, weaving that lens's
|
|
33
|
+
* IntentLens notes inline next to the mission element they annotate. Notes explain
|
|
34
|
+
* meaning; they are never verification, and the doc says so. Pure and browser-safe.
|
|
35
|
+
*/
|
|
36
|
+
export function renderLensDoc(ast, lens) {
|
|
37
|
+
const m = ast.mission || 'mission';
|
|
38
|
+
const prefix = `mission.${m}`;
|
|
39
|
+
const flat = (t) => String(t).replace(/\s+/g, ' ').trim();
|
|
40
|
+
const notesFor = (path) => (ast.notes || []).filter((n) => n.lens === lens && n.targetPath === path);
|
|
41
|
+
const L = [];
|
|
42
|
+
L.push(`# ${m} , for the ${lens} reader`, '');
|
|
43
|
+
L.push(`> IntentLens \`${lens}\` notes are woven in below. They explain meaning for this`,
|
|
44
|
+
`> audience; they are documentation, not verification.`, '');
|
|
45
|
+
for (const nt of notesFor(prefix)) L.push(`_${flat(nt.text)}_`, '');
|
|
46
|
+
if (ast.goal) L.push(`**Goal.** ${ast.goal}`, '');
|
|
47
|
+
if (ast.why) L.push(`**Why.** ${ast.why}`, '');
|
|
48
|
+
const fieldSection = (title, fields, kind) => {
|
|
49
|
+
if (!fields.length) return;
|
|
50
|
+
L.push(`## ${title}`, '');
|
|
51
|
+
for (const f of fields) {
|
|
52
|
+
L.push(`- \`${f.name}: ${f.type}\``);
|
|
53
|
+
for (const nt of notesFor(`${prefix}.${kind}.${f.name}`)) L.push(` , ${flat(nt.text)}`);
|
|
54
|
+
}
|
|
55
|
+
L.push('');
|
|
56
|
+
};
|
|
57
|
+
fieldSection('Inputs', ast.inputs, 'input');
|
|
58
|
+
fieldSection('Outputs', ast.outputs, 'output');
|
|
59
|
+
const ruleSection = (title, rules, kind) => {
|
|
60
|
+
if (!rules.length) return;
|
|
61
|
+
L.push(`## ${title}`, '');
|
|
62
|
+
for (const r of rules) {
|
|
63
|
+
L.push(`- ${r.statement}${r.because ? ` (because ${r.because})` : ''}`);
|
|
64
|
+
for (const nt of notesFor(`${prefix}.${kind}.${r.id}`)) L.push(` , ${flat(nt.text)}`);
|
|
65
|
+
}
|
|
66
|
+
L.push('');
|
|
67
|
+
};
|
|
68
|
+
ruleSection('Guarantees', ast.guarantees, 'guarantee');
|
|
69
|
+
ruleSection('Never', ast.neverRules, 'never');
|
|
70
|
+
const count = (ast.notes || []).filter((n) => n.lens === lens).length;
|
|
71
|
+
L.push('---', `${count} \`${lens}\` note${count === 1 ? '' : 's'} in this mission.`);
|
|
72
|
+
return L.join('\n');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function renderMermaid(ast) {
|
|
76
|
+
const L = ['graph TD'];
|
|
77
|
+
const m = slug(ast.mission || 'mission');
|
|
78
|
+
L.push(` ${m}["${ast.mission}"]`);
|
|
79
|
+
ast.guarantees.forEach((g, i) => L.push(` ${m} --> g${i}["guarantee: ${g.statement}"]`));
|
|
80
|
+
ast.neverRules.forEach((n, i) => L.push(` ${m} --> n${i}["never: ${n.statement}"]`));
|
|
81
|
+
ast.events.forEach((e) => L.push(` ${m} --> ev_${e.id}(["event: ${e.name}"])`));
|
|
82
|
+
return L.join('\n') + '\n';
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function renderTestplan(ast) {
|
|
86
|
+
const L = [`# Test plan: ${ast.mission}`, ''];
|
|
87
|
+
for (const g of ast.guarantees) L.push(`- [ ] Guarantee holds: ${g.statement}${g.verify.length ? ` (via ${g.verify.join(', ')})` : ''}`);
|
|
88
|
+
for (const n of ast.neverRules) L.push(`- [ ] Never occurs: ${n.statement}${n.verify.length ? ` (via ${n.verify.join(', ')})` : ''}`);
|
|
89
|
+
for (const e of ast.errors || []) L.push(`- [ ] Failure mode handled: ${e.name}`);
|
|
90
|
+
for (const ex of ast.examples || []) L.push(`- [ ] Example: given ${ex.given}${ex.expect ? ` -> expect ${ex.expect}` : ''}`);
|
|
91
|
+
for (const v of ast.verify) L.push(`- [ ] ${v}`);
|
|
92
|
+
return L.join('\n') + '\n';
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Compile ThunderLang source in memory and return every artifact `intent build`
|
|
97
|
+
* would emit, without touching the filesystem.
|
|
98
|
+
*/
|
|
99
|
+
export function compileSource(source, { sourceFile = 'playground.intent', generatedAt, origin = 'authored' } = {}) {
|
|
100
|
+
const ast = parseIntent(source);
|
|
101
|
+
const at = generatedAt || new Date().toISOString();
|
|
102
|
+
const sourceHash = sha256(source);
|
|
103
|
+
const diagnostics = semanticDiagnostics(ast);
|
|
104
|
+
|
|
105
|
+
const contractGraph = buildContractGraph(ast, at);
|
|
106
|
+
const architectureGraph = buildArchitectureGraph(ast, at);
|
|
107
|
+
const implementationPlan = buildImplementationPlan(ast, at);
|
|
108
|
+
const markdown = renderMarkdown(ast);
|
|
109
|
+
const mermaid = renderMermaid(ast);
|
|
110
|
+
const testplan = renderTestplan(ast);
|
|
111
|
+
|
|
112
|
+
const mission = ast.mission || 'mission';
|
|
113
|
+
const targetsGenerated = [
|
|
114
|
+
'contract-graph.json', 'architecture-graph.json', 'implementation-plan.json',
|
|
115
|
+
`${slug(mission)}.md`, `${slug(mission)}.mmd`, `${slug(mission)}.testplan.md`,
|
|
116
|
+
];
|
|
117
|
+
const proof = buildProof(ast, {
|
|
118
|
+
sourceFile, sourceHash, generatedAt: at, origin,
|
|
119
|
+
targetsRequested: ast.targets, targetsGenerated, diagnostics,
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
return {
|
|
123
|
+
mission,
|
|
124
|
+
origin,
|
|
125
|
+
// Canonical cross-ecosystem intent reference ids , producers (OT/RM/STT/Certified) put these
|
|
126
|
+
// in evidence-event-v1 / proof-bundle-v1 `intentReferences[]` so evidence cites this exact intent.
|
|
127
|
+
intentRef: intentRefId(ast), // subject-level: intent:<slug>
|
|
128
|
+
intentRefPinned: intentRefId(ast, { sourceHash }), // version-pinned: intent:<slug>@<sha8>
|
|
129
|
+
// Ownership Graph seam: skills this intent requires (shared skill: ids) + required-understanding.
|
|
130
|
+
// Producers drop `skillsRequired` straight into evidence-event-v1 `skillIds[]`.
|
|
131
|
+
skillsRequired: (ast.skills || []).map((s) => s.id).filter(Boolean),
|
|
132
|
+
demonstrates: (ast.demonstrates || []).map((d) => d.statement),
|
|
133
|
+
// 12-Factor Agents conformance summary (score/grade/counts). Full per-factor report via twelveFactorReport.
|
|
134
|
+
twelveFactor: twelveFactorSummary(ast),
|
|
135
|
+
diagnostics,
|
|
136
|
+
notes: ast.notes || [],
|
|
137
|
+
artifacts: {
|
|
138
|
+
markdown, mermaid, testplan,
|
|
139
|
+
contractGraph, architectureGraph, implementationPlan, proof,
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
// Comprehension Contracts + the C0..C6 level (intent-comprehension-v1). The measurable backbone
|
|
2
|
+
// of the Software Understanding System: given a mission's Intended Truth (its intent), compute
|
|
3
|
+
// how well-understood it is, from C0 (Unknown) to C6 (Teachable). Deterministic, no AI, pure
|
|
4
|
+
// (browser-safe), so IL is the single evaluator and every product , Atlas overlays it, Fable
|
|
5
|
+
// reports it, Skills Tech Talk targets it, OpenThunder lifts it to C5 with runtime evidence ,
|
|
6
|
+
// reads ONE number, never a fork.
|
|
7
|
+
//
|
|
8
|
+
// Honesty boundary: IL computes the intent-side levels (C1..C4) deterministically. C5 (Observed)
|
|
9
|
+
// needs runtime evidence (OpenThunder / runtime) and C6 (Teachable) needs a learning path
|
|
10
|
+
// (Skills Tech Talk); IL reports what it can determine and names the sibling that owns each gap,
|
|
11
|
+
// never inflating a level on evidence it does not have.
|
|
12
|
+
|
|
13
|
+
export const COMPREHENSION_SCHEMA = 'intent-comprehension-v1';
|
|
14
|
+
|
|
15
|
+
export const LEVELS = [
|
|
16
|
+
{ level: 'C0', name: 'Unknown', means: 'Intent exists with no stated purpose.' },
|
|
17
|
+
{ level: 'C1', name: 'Described', means: 'Purpose and a summary exist.' },
|
|
18
|
+
{ level: 'C2', name: 'Structured', means: 'Guarantees, rules, states, failures, or constraints exist.' },
|
|
19
|
+
{ level: 'C3', name: 'Mapped', means: 'Intent links to implementation (targets, components, APIs, architecture).' },
|
|
20
|
+
{ level: 'C4', name: 'Verified', means: 'Every guarantee and never-rule carries a verification.' },
|
|
21
|
+
{ level: 'C5', name: 'Observed', means: 'Runtime evidence is connected and discrepancies are monitored.' },
|
|
22
|
+
{ level: 'C6', name: 'Teachable', means: 'A source-grounded explanation and learning path exist.' },
|
|
23
|
+
{ level: 'C7', name: 'Governed', means: 'Drift is monitored, ownership and risk are on the record, and the understanding stays true as the software evolves.' },
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
const nonEmpty = (a) => Array.isArray(a) && a.length > 0;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Evaluate a mission's comprehension level from its AST (its Intended Truth). Optional external
|
|
30
|
+
* signals let a sibling lift the joint level: `observed` (OpenThunder/runtime evidence present)
|
|
31
|
+
* for C5, `learningPath` (Skills Tech Talk) for C6. Pure and deterministic.
|
|
32
|
+
*/
|
|
33
|
+
export function comprehensionLevel(ast, { observed = false, learningPath = false, governed = false } = {}) {
|
|
34
|
+
const guarantees = ast?.guarantees || [];
|
|
35
|
+
const nevers = ast?.neverRules || [];
|
|
36
|
+
const claims = [...guarantees, ...nevers];
|
|
37
|
+
const allVerified = claims.length > 0 && claims.every((c) => nonEmpty(c.verify));
|
|
38
|
+
|
|
39
|
+
// Each signal: is it met, from what evidence, and (if not IL-determinable) who owns it.
|
|
40
|
+
const signals = {
|
|
41
|
+
purpose: {
|
|
42
|
+
// A purpose/summary in any form: a goal, a why, a product title, or the problem statement.
|
|
43
|
+
// (goal/why/title/problem are strings on the AST, not lists.)
|
|
44
|
+
met: Boolean(ast?.goal) || Boolean(ast?.why) || Boolean(ast?.title) || Boolean(ast?.problem),
|
|
45
|
+
evidence: [ast?.goal && 'goal', ast?.why && 'why', ast?.title && 'title', ast?.problem && 'problem'].filter(Boolean),
|
|
46
|
+
owner: 'ThunderLang',
|
|
47
|
+
},
|
|
48
|
+
structure: {
|
|
49
|
+
met: nonEmpty(guarantees) || nonEmpty(nevers) || nonEmpty(ast?.decisions)
|
|
50
|
+
|| nonEmpty(ast?.lifecycles) || nonEmpty(ast?.errors) || nonEmpty(ast?.constraints) || nonEmpty(ast?.invariants),
|
|
51
|
+
evidence: [
|
|
52
|
+
nonEmpty(guarantees) && 'guarantees', nonEmpty(nevers) && 'never', nonEmpty(ast?.decisions) && 'decisions',
|
|
53
|
+
nonEmpty(ast?.lifecycles) && 'lifecycles', nonEmpty(ast?.errors) && 'errors', nonEmpty(ast?.constraints) && 'constraints',
|
|
54
|
+
nonEmpty(ast?.invariants) && 'invariants',
|
|
55
|
+
].filter(Boolean),
|
|
56
|
+
owner: 'ThunderLang',
|
|
57
|
+
},
|
|
58
|
+
mapping: {
|
|
59
|
+
met: nonEmpty(ast?.targets) || nonEmpty(ast?.components) || nonEmpty(ast?.apis)
|
|
60
|
+
|| nonEmpty(ast?.services) || Boolean(ast?.implementation) || nonEmpty(ast?.architecture),
|
|
61
|
+
evidence: [
|
|
62
|
+
nonEmpty(ast?.targets) && 'target', nonEmpty(ast?.components) && 'components', nonEmpty(ast?.apis) && 'apis',
|
|
63
|
+
nonEmpty(ast?.services) && 'services', ast?.implementation && 'implementation', nonEmpty(ast?.architecture) && 'architecture',
|
|
64
|
+
].filter(Boolean),
|
|
65
|
+
owner: 'ThunderLang',
|
|
66
|
+
},
|
|
67
|
+
verification: {
|
|
68
|
+
met: allVerified,
|
|
69
|
+
evidence: allVerified ? [`${claims.length}/${claims.length} claims verified`] : (claims.length ? [`${claims.filter((c) => nonEmpty(c.verify)).length}/${claims.length} claims verified`] : []),
|
|
70
|
+
owner: 'ThunderLang + OpenThunder',
|
|
71
|
+
},
|
|
72
|
+
observation: {
|
|
73
|
+
met: Boolean(observed),
|
|
74
|
+
evidence: observed ? ['runtime evidence provided'] : [],
|
|
75
|
+
owner: 'OpenThunder / runtime', // IL cannot observe production; the level rises when OT attaches evidence
|
|
76
|
+
},
|
|
77
|
+
teachability: {
|
|
78
|
+
met: Boolean(learningPath) || nonEmpty(ast?.notes) || nonEmpty(ast?.examples),
|
|
79
|
+
evidence: [learningPath && 'learning path', nonEmpty(ast?.notes) && 'notes', nonEmpty(ast?.examples) && 'examples'].filter(Boolean),
|
|
80
|
+
owner: 'Skills Tech Talk (learning) + ThunderLang (notes/examples)',
|
|
81
|
+
},
|
|
82
|
+
governance: {
|
|
83
|
+
// Understanding that stays true as the software changes: drift monitored (Guardian) AND
|
|
84
|
+
// ownership + declared risk on the record. IL supplies the record; Guardian supplies drift.
|
|
85
|
+
met: Boolean(governed) && Boolean(ast?.owner) && (nonEmpty(ast?.unknowns) || nonEmpty(ast?.assumptions) || nonEmpty(ast?.conflicts) || nonEmpty(ast?.waivers)),
|
|
86
|
+
evidence: [governed && 'drift-monitored', ast?.owner && 'ownership', (nonEmpty(ast?.unknowns) || nonEmpty(ast?.assumptions) || nonEmpty(ast?.conflicts) || nonEmpty(ast?.waivers)) && 'risk on record'].filter(Boolean),
|
|
87
|
+
owner: 'Intent Guardian (drift) + Workspace/Ledger (risk + approvals)',
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// The ladder is cumulative: the level is the highest Cn where C1..Cn are all met.
|
|
92
|
+
const ladder = ['purpose', 'structure', 'mapping', 'verification', 'observation', 'teachability', 'governance'];
|
|
93
|
+
let n = 0;
|
|
94
|
+
for (const s of ladder) { if (signals[s].met) n += 1; else break; }
|
|
95
|
+
const level = LEVELS[n];
|
|
96
|
+
|
|
97
|
+
// The next unmet rungs become explicit gaps with the owner responsible for closing each.
|
|
98
|
+
const missing = [];
|
|
99
|
+
for (let i = n; i < ladder.length; i += 1) {
|
|
100
|
+
const lv = LEVELS[i + 1];
|
|
101
|
+
missing.push({ level: lv.level, name: lv.name, need: lv.means, owner: signals[ladder[i]].owner });
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
schema: COMPREHENSION_SCHEMA,
|
|
106
|
+
mission: ast?.mission || null,
|
|
107
|
+
level: level.level,
|
|
108
|
+
levelName: level.name,
|
|
109
|
+
means: level.means,
|
|
110
|
+
signals,
|
|
111
|
+
missing,
|
|
112
|
+
// The Comprehension Contract checklist , what a critical capability should declare (capability 14).
|
|
113
|
+
contract: {
|
|
114
|
+
why: signals.purpose.met, structure: signals.structure.met, mapping: signals.mapping.met,
|
|
115
|
+
verification: signals.verification.met, observation: signals.observation.met,
|
|
116
|
+
teachability: signals.teachability.met, governance: signals.governance.met,
|
|
117
|
+
ownership: Boolean(ast?.owner), nonGoals: nonEmpty(ast?.nonGoals),
|
|
118
|
+
unknownsDeclared: nonEmpty(ast?.unknowns) || nonEmpty(ast?.assumptions) || nonEmpty(ast?.conflicts),
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** Evaluate many missions and summarize the distribution across levels. */
|
|
124
|
+
export function comprehensionReport(asts, opts = {}) {
|
|
125
|
+
const missions = (asts || []).map((ast) => comprehensionLevel(ast, opts));
|
|
126
|
+
const byLevel = {};
|
|
127
|
+
for (const lv of LEVELS) byLevel[lv.level] = 0;
|
|
128
|
+
for (const m of missions) byLevel[m.level] += 1;
|
|
129
|
+
return { schema: COMPREHENSION_SCHEMA, count: missions.length, byLevel, missions };
|
|
130
|
+
}
|
package/src/conflict.mjs
ADDED
|
Binary file
|
package/src/core.d.ts
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
// Types for `@skillstech/thunderlang/core` , the universal (Node + browser + React Native)
|
|
2
|
+
// surface. This re-exports exactly the symbols core.mjs exports, using the declarations in
|
|
3
|
+
// index.d.ts as the single source of truth. It intentionally does NOT re-export the Node-only
|
|
4
|
+
// surface (CLI, LSP, filesystem lift/drift), so a consumer cannot type-import something that
|
|
5
|
+
// is not actually in the universal build.
|
|
6
|
+
|
|
7
|
+
// The canonical hash (byte-identical to node:crypto).
|
|
8
|
+
export { sha256, sha256hex } from './index';
|
|
9
|
+
|
|
10
|
+
// Parser + graph + in-memory compile.
|
|
11
|
+
export {
|
|
12
|
+
IntentAst, Diagnostic, parseIntent, slug, KNOWN_LENSES,
|
|
13
|
+
INTENT_GRAPH_SCHEMA, IntentGraph, IntentGraphNode, buildIntentGraph,
|
|
14
|
+
compileSource, renderMarkdown, renderMermaid, renderTestplan,
|
|
15
|
+
semanticDiagnostics, buildContractGraph, buildArchitectureGraph, buildImplementationPlan, buildProof,
|
|
16
|
+
} from './index';
|
|
17
|
+
|
|
18
|
+
// IntentLift: code -> inferred candidate intent (OT orchestrates this in-process).
|
|
19
|
+
export {
|
|
20
|
+
liftSource, liftAll, liftRepo, languageForFile, inferIntent, renderLiftedIntent, SUPPORTED_LANGUAGES,
|
|
21
|
+
IntentSeed, SEED_SCHEMA, normalizeSeeds,
|
|
22
|
+
} from './index';
|
|
23
|
+
|
|
24
|
+
// Intent Scanner + Fable.
|
|
25
|
+
export {
|
|
26
|
+
SCAN_SCHEMA, ScanResult, scanIntent, scanProject,
|
|
27
|
+
FABLE_SCHEMA, RISK_CATEGORIES, Finding, toFinding, fableRuleFor, universalPack,
|
|
28
|
+
} from './index';
|
|
29
|
+
|
|
30
|
+
// Focused scan query views.
|
|
31
|
+
export {
|
|
32
|
+
VIEW_SCHEMA, VIEWS, risksView, gapsView, unverifiedView, coverageView, unknownsView, contradictionsView,
|
|
33
|
+
} from './index';
|
|
34
|
+
|
|
35
|
+
// Intent Atlas + navigation.
|
|
36
|
+
export {
|
|
37
|
+
ATLAS_SCHEMA, IntentAtlas, buildAtlas, atlasNode, expandNode, searchAtlas,
|
|
38
|
+
} from './index';
|
|
39
|
+
|
|
40
|
+
// Intent Lens , Intent Scope + Focus Graph + Intent Brief.
|
|
41
|
+
export {
|
|
42
|
+
FOCUS_SCHEMA, SCOPE_TYPES, FOCUS_REASONS, IntentScope, FocusNode, FocusGraph, IntentBrief,
|
|
43
|
+
makeScope, buildFocusGraph, intentBrief,
|
|
44
|
+
} from './index';
|
|
45
|
+
|
|
46
|
+
// Comprehension Contract , the C0..C7 understanding level.
|
|
47
|
+
export {
|
|
48
|
+
COMPREHENSION_SCHEMA, COMPREHENSION_LEVELS, ComprehensionResult, ComprehensionSignal,
|
|
49
|
+
comprehensionLevel, comprehensionReport,
|
|
50
|
+
} from './index';
|
|
51
|
+
|
|
52
|
+
// Code generation , deterministic scaffolds from intent.
|
|
53
|
+
export { CODEGEN_SCHEMA, GENERATORS, toTypeScript, toCSharp, toJava, subjectName, intentRefId, skillRefId } from './index';
|
|
54
|
+
|
|
55
|
+
// 12-Factor Agents conformance lens (twelve-factor-v1).
|
|
56
|
+
export { TWELVE_FACTOR_SCHEMA, TwelveFactorResult, twelveFactorReport, twelveFactorSummary } from './index';
|
|
57
|
+
|
|
58
|
+
// Change Lens , what a branch/PR changed by meaning.
|
|
59
|
+
export { CHANGES_SCHEMA, ChangeReport, changeReport } from './index';
|
|
60
|
+
|
|
61
|
+
// Change Lens , semantic diff + 3-way merge + graph->source round-trip.
|
|
62
|
+
export {
|
|
63
|
+
IntentDiff, IntentMerge, diffGraphs, mergeGraphs,
|
|
64
|
+
GRAPH_SOURCE_SCHEMA, graphToSource,
|
|
65
|
+
} from './index';
|
|
66
|
+
|
|
67
|
+
// Shared Intent IR (intent-ir-v1) + classification model.
|
|
68
|
+
export {
|
|
69
|
+
IR_SCHEMA, IR_EMBEDS, IR_NODE_TYPES, IR_RELATIONSHIP_TYPES, PROVENANCE, FACTUAL_PROVENANCE,
|
|
70
|
+
isFactualProvenance, IR_CONFIDENCE, IR_CONFIDENCE_MEANING, confidenceFromClassification,
|
|
71
|
+
SENSITIVITY, RETENTION, REVIEW_STATUS, APPROVAL_STATUS, NODE_FIELDS,
|
|
72
|
+
IntentIR, IntentIRNode, validateIR, graphToIR,
|
|
73
|
+
CLASSIFICATIONS, CONFIDENCE, UNSETTLED, BLOCKABLE_PHASES,
|
|
74
|
+
} from './index';
|
|
75
|
+
|
|
76
|
+
// Canonical schema constants + proof envelope.
|
|
77
|
+
export {
|
|
78
|
+
SCHEMA_VERSION, NODE_TYPES, RELATIONSHIP_TYPES, intentGraphJsonSchema,
|
|
79
|
+
DIAGNOSTIC_RULES, CORE_DIAGNOSTICS, ALL_DIAGNOSTICS,
|
|
80
|
+
RULE_PHASES, RULE_OWNERS, RULE_NAMESPACES, VERIFICATION_RULES, ruleNamespace,
|
|
81
|
+
PROOF_SCHEMA, CLAIM_STATUSES, PROOF_STATUSES, intentProofJsonSchema, validateProof,
|
|
82
|
+
} from './index';
|
|
83
|
+
|
|
84
|
+
// The pure Intent Runtime + guard + prompt->intent draft + expression engine.
|
|
85
|
+
export {
|
|
86
|
+
evaluateDecision, simulateLifecycle, checkDecisionCases, RUNTIME_SCHEMA,
|
|
87
|
+
buildGuard, compileGuard, guardSummary, GUARD_SCHEMA,
|
|
88
|
+
draftIntent, DRAFT_SCHEMA,
|
|
89
|
+
} from './index';
|
|
90
|
+
|
|
91
|
+
// Human <-> Structured <-> ThunderLang sync + comment-preserving structural editing.
|
|
92
|
+
export {
|
|
93
|
+
parseToStructured, proposeIntent, SYNC_SCHEMA, applyEdits, PATCH_SCHEMA,
|
|
94
|
+
} from './index';
|
|
95
|
+
|
|
96
|
+
// Style intent , canonical token address space + accessibility vocabulary.
|
|
97
|
+
export {
|
|
98
|
+
analyzeStyle, styleDiagnostics, toDesignTokens, toCss, STYLE_SCHEMA, DESIGN_TOKENS_SCHEMA,
|
|
99
|
+
} from './index';
|