@skillstech/thunderlang 0.3.0 → 0.4.2
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 +41 -0
- package/README.md +25 -25
- package/dist/core.cjs +89 -5
- package/dist/index.cjs +388 -8
- package/package.json +3 -3
- package/src/cli.mjs +116 -67
- package/src/codegen.mjs +73 -4
- package/src/core.d.ts +1 -1
- package/src/core.mjs +1 -1
- package/src/emit.mjs +1 -1
- package/src/evidence.mjs +116 -0
- package/src/exporters.mjs +14 -5
- package/src/index.d.ts +1 -0
- package/src/index.mjs +2 -1
- package/src/lift.mjs +1 -1
- package/src/mcp.mjs +125 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,47 @@
|
|
|
3
3
|
All notable changes to `@skillstech/thunderlang`. Pre-1.0: the language and the
|
|
4
4
|
`intent-graph-v1` schema version independently and may still change.
|
|
5
5
|
|
|
6
|
+
## 0.4.2
|
|
7
|
+
|
|
8
|
+
The evidence-graph release. Additive; no breaking changes.
|
|
9
|
+
|
|
10
|
+
- **Evidence projections.** ThunderLang can now project its verification into `evidence-event-v1`
|
|
11
|
+
events (`evidenceType: tool_verified`) for the shared SkillsTech proof spine: `thunder evidence
|
|
12
|
+
<file>` emits `intent.proven`, and `--evidence` on `verify-diff` / `conform` / `drift` emits
|
|
13
|
+
`change.gated` / `conformance.verified` / `intent.drift`. The projections are pure, offline, and
|
|
14
|
+
safe-derived (ids, hashes, verdicts, diagnostic codes, and counts only , never source, secret
|
|
15
|
+
values, finding messages, or expected/actual values). The library exports `toEvidenceEvents`,
|
|
16
|
+
`verifyDiffToEvidence`, `conformToEvidence`, and `driftToEvidence`. The network push to the spine
|
|
17
|
+
is intentionally left to the org-layer/CI, so the compiler stays offline and deterministic.
|
|
18
|
+
- **Fix: `thunder lift` emits canonical `.thunder` drafts** instead of the legacy `.intent`
|
|
19
|
+
extension, on both single-file and repo lifts.
|
|
20
|
+
|
|
21
|
+
## 0.4.1
|
|
22
|
+
|
|
23
|
+
The coherence release. Additive; no breaking changes. Version chosen to align with OpenThunder
|
|
24
|
+
(TL and OT version in lockstep; OT is moving from 0.4.0 to match).
|
|
25
|
+
|
|
26
|
+
- **Python code generation.** `thunder gen <file> --target python` now emits a typed Python 3
|
|
27
|
+
scaffold, aligning the codegen axis with live execution. Also fixes a real gap: C# and Java `gen`
|
|
28
|
+
silently dropped `requires` preconditions that TypeScript emitted; they are now emitted as guided
|
|
29
|
+
TODOs.
|
|
30
|
+
- **Language support matrix.** New `docs/language-support-matrix.md` documents the three axes , lift
|
|
31
|
+
(14 languages), gen, and live target execution (4) , and makes them discoverable.
|
|
32
|
+
- **VS Code extension.** `editors/vscode/` ships a real extension: syntax highlighting and a Language
|
|
33
|
+
Server client that launches `thunder lsp`. Packageable with `vsce package`.
|
|
34
|
+
- **Grouped, scannable CLI help.** `thunder --help` is reorganized into nine labeled groups with a
|
|
35
|
+
one-line mental model. Command behavior is unchanged (help text only); a test guards that no
|
|
36
|
+
command was dropped.
|
|
37
|
+
- **Verify-real-code loop, productized.** New MCP tools `intent_prove`, `intent_conform`, and
|
|
38
|
+
`intent_drift` let AI agents drive the full loop. `docs/verifying-ai-changes.md` is rewritten as
|
|
39
|
+
the headline workflow (author intent, write code, prove conformance, gate the merge) with a CI
|
|
40
|
+
recipe.
|
|
41
|
+
- **Honest Playwright scaffolds.** The exported Playwright tests now open with `test.fixme` so an
|
|
42
|
+
unfilled scaffold cannot pass vacuously.
|
|
43
|
+
- **intent-graph-v1 stability policy.** New `docs/schema-stability.md` commits to additive-only type
|
|
44
|
+
sets within v1, an IR version that moves independently of the package, a deprecation policy, and a
|
|
45
|
+
road to 1.0, so consumers like OpenThunder can depend on the IR safely.
|
|
46
|
+
|
|
6
47
|
## 0.3.0
|
|
7
48
|
|
|
8
49
|
The 14-language lift release. Additive; no breaking changes. Restores the OpenThunder -> ThunderLang
|
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ Part of [ThunderLang](https://thunderlang.dev), the intent language for AI-era s
|
|
|
11
11
|
## Install
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
npm install -g @skillstech/thunderlang # then:
|
|
14
|
+
npm install -g @skillstech/thunderlang # then: thunder check path/to/Mission.intent
|
|
15
15
|
npx @skillstech/thunderlang help # or run without installing
|
|
16
16
|
```
|
|
17
17
|
|
|
@@ -19,36 +19,36 @@ npx @skillstech/thunderlang help # or run without installing
|
|
|
19
19
|
|
|
20
20
|
```bash
|
|
21
21
|
# Author & check
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
22
|
+
thunder init [Name] # scaffold a runnable starter mission
|
|
23
|
+
thunder check <file|dir> # semantic diagnostics (exit 1 on error); a dir gates the repo
|
|
24
|
+
thunder fmt <file|dir> -w # canonical formatting (whitespace only; comments preserved)
|
|
25
|
+
thunder build <file> # docs, contract graph, test plan, .intent-proof.json
|
|
26
|
+
thunder graph <file> # the canonical Intent Graph (intent-graph-v1)
|
|
27
|
+
thunder check . --format sarif # SARIF 2.1.0 for GitHub/GitLab code scanning
|
|
28
|
+
thunder schema # emit the graph schema + diagnostic catalog
|
|
29
|
+
thunder rules · thunder explain <CODE> # the full diagnostic catalog / one code
|
|
30
|
+
thunder proof --schema # the canonical proof envelope schema (intent-proof-v1)
|
|
31
31
|
|
|
32
32
|
# Execute (no AI, no generated code)
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
thunder run <file> --inputs '{"age":20}' # evaluate the decision(s) against inputs
|
|
34
|
+
thunder simulate <file> --events submit,approve # walk the lifecycle(s)
|
|
35
|
+
thunder test <file> # run in-file test blocks (case/scenario)
|
|
36
|
+
thunder outcomes <file> # evaluate outcome contracts vs results
|
|
37
|
+
thunder style <file> # resolve style intents vs the canonical token space
|
|
38
38
|
|
|
39
39
|
# Interop (9 export formats)
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
thunder export <file> --format dmn|bpmn|smv|jsonschema|openapi|tokens|css|mermaid|playwright
|
|
41
|
+
thunder import <file> [--format dmn|bpmn] [--json] # lift DMN/BPMN into intent
|
|
42
|
+
thunder source <file|graph.json> # regenerate .intent from a graph
|
|
43
|
+
thunder migrate <graph.json> [--to <ver>] # upgrade a persisted graph
|
|
44
|
+
thunder verify <proof.json> [src] # confirm a proof matches its source
|
|
45
45
|
|
|
46
46
|
# Navigate & compare
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
thunder atlas <dir> [--search q] thunder index <dir>
|
|
48
|
+
thunder diff <before> <after> thunder merge <base> <ours> <theirs>
|
|
49
49
|
|
|
50
50
|
# Code <-> intent
|
|
51
|
-
|
|
51
|
+
thunder lift <file> thunder approve <file> thunder drift <file>
|
|
52
52
|
```
|
|
53
53
|
|
|
54
54
|
Run `thunder help` for the full reference.
|
|
@@ -75,8 +75,8 @@ test Eligibility
|
|
|
75
75
|
```
|
|
76
76
|
|
|
77
77
|
```bash
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
thunder run mission.intent --inputs '{"age":20,"score":90}' # -> Eligible, with a trace
|
|
79
|
+
thunder test mission.intent # -> 1/1 passed
|
|
80
80
|
```
|
|
81
81
|
|
|
82
82
|
No AI, no generated code. The intent itself decides.
|
package/dist/core.cjs
CHANGED
|
@@ -161,6 +161,7 @@ __export(core_exports, {
|
|
|
161
161
|
toDesignTokens: () => toDesignTokens,
|
|
162
162
|
toFinding: () => toFinding,
|
|
163
163
|
toJava: () => toJava,
|
|
164
|
+
toPython: () => toPython,
|
|
164
165
|
toTypeScript: () => toTypeScript,
|
|
165
166
|
twelveFactorReport: () => twelveFactorReport,
|
|
166
167
|
twelveFactorSummary: () => twelveFactorSummary,
|
|
@@ -3336,6 +3337,7 @@ function exprToCode(src, { inputs = [], dialect = "js" } = {}) {
|
|
|
3336
3337
|
var exprToJs = (src, opts = {}) => exprToCode(src, { ...opts, dialect: "js" });
|
|
3337
3338
|
var exprToCSharp = (src, opts = {}) => exprToCode(src, { ...opts, dialect: "csharp" });
|
|
3338
3339
|
var exprToJava = (src, opts = {}) => exprToCode(src, { ...opts, dialect: "java" });
|
|
3340
|
+
var exprToPython = (src, opts = {}) => exprToCode(src, { ...opts, dialect: "python" });
|
|
3339
3341
|
|
|
3340
3342
|
// src/runtime.mjs
|
|
3341
3343
|
var RUNTIME_SCHEMA = "intent-runtime-v1";
|
|
@@ -4288,7 +4290,7 @@ function notesSummary(ast) {
|
|
|
4288
4290
|
byLens
|
|
4289
4291
|
};
|
|
4290
4292
|
}
|
|
4291
|
-
var COMPILER_VERSION = "0.
|
|
4293
|
+
var COMPILER_VERSION = "0.4.2";
|
|
4292
4294
|
var PROOF_SCHEMA_VERSION = "0.1.0";
|
|
4293
4295
|
var SOURCE_PRODUCT = "skillstech-compiler";
|
|
4294
4296
|
function buildContractGraph(ast, generatedAt) {
|
|
@@ -5711,7 +5713,7 @@ function liftRepo(files, { language } = {}) {
|
|
|
5711
5713
|
const base = slug(r.lifted.mission);
|
|
5712
5714
|
const n = (usedNames.get(base) || 0) + 1;
|
|
5713
5715
|
usedNames.set(base, n);
|
|
5714
|
-
const outName = n === 1 ? `${base}.
|
|
5716
|
+
const outName = n === 1 ? `${base}.thunder` : `${base}-${n}.thunder`;
|
|
5715
5717
|
missions.push({
|
|
5716
5718
|
mission: r.lifted.mission,
|
|
5717
5719
|
sourceFile: file,
|
|
@@ -6671,7 +6673,7 @@ function toCSharp(ast) {
|
|
|
6671
6673
|
try {
|
|
6672
6674
|
cond = exprToCSharp(r.when, { inputs });
|
|
6673
6675
|
} catch {
|
|
6674
|
-
cond = `false /* TODO: "${r.when}" */`;
|
|
6676
|
+
cond = `false /* TODO: could not translate "${r.when}" */`;
|
|
6675
6677
|
}
|
|
6676
6678
|
L.push(` if (${cond}) return ${JSON.stringify(r.result)}; // rule ${r.name}`);
|
|
6677
6679
|
}
|
|
@@ -6680,6 +6682,7 @@ function toCSharp(ast) {
|
|
|
6680
6682
|
const inName = (ast.inputs || []).length ? `${subject}Input` : null;
|
|
6681
6683
|
const outName = (ast.outputs || []).length ? `${subject}Output` : "void";
|
|
6682
6684
|
L.push(` public static ${outName} Run(${inName ? `${inName} input` : ""})`, " {");
|
|
6685
|
+
for (const r of ast.requires || []) L.push(` // precondition: ${r} , TODO: validate`);
|
|
6683
6686
|
for (const n of ast.neverRules || []) L.push(` // NEVER: ${n.statement}`);
|
|
6684
6687
|
for (const g of ast.guarantees || []) L.push(` // GUARANTEE: ${g.statement}`);
|
|
6685
6688
|
L.push(' throw new NotImplementedException("TODO: implement , the intent above defines what this must do.");', " }");
|
|
@@ -6740,7 +6743,7 @@ function toJava(ast) {
|
|
|
6740
6743
|
try {
|
|
6741
6744
|
cond = exprToJava(r.when, { inputs });
|
|
6742
6745
|
} catch {
|
|
6743
|
-
cond = `false /* TODO: "${r.when}" */`;
|
|
6746
|
+
cond = `false /* TODO: could not translate "${r.when}" */`;
|
|
6744
6747
|
}
|
|
6745
6748
|
L.push(` if (${cond}) return ${JSON.stringify(r.result)}; // rule ${r.name}`);
|
|
6746
6749
|
}
|
|
@@ -6749,18 +6752,98 @@ function toJava(ast) {
|
|
|
6749
6752
|
const inName = (ast.inputs || []).length ? `${subject}Input` : null;
|
|
6750
6753
|
const outName = (ast.outputs || []).length ? `${subject}Output` : "void";
|
|
6751
6754
|
L.push(` public static ${outName} run(${inName ? `${inName} input` : ""}) {`);
|
|
6755
|
+
for (const r of ast.requires || []) L.push(` // precondition: ${r} , TODO: validate`);
|
|
6752
6756
|
for (const n of ast.neverRules || []) L.push(` // NEVER: ${n.statement}`);
|
|
6753
6757
|
for (const g of ast.guarantees || []) L.push(` // GUARANTEE: ${g.statement}`);
|
|
6754
6758
|
L.push(' throw new UnsupportedOperationException("TODO: implement , the intent above defines what this must do.");', " }");
|
|
6755
6759
|
L.push("}", "");
|
|
6756
6760
|
return L.join("\n");
|
|
6757
6761
|
}
|
|
6762
|
+
var PY_TYPES = {
|
|
6763
|
+
Email: "str",
|
|
6764
|
+
Url: "str",
|
|
6765
|
+
UserId: "str",
|
|
6766
|
+
AccountId: "str",
|
|
6767
|
+
OrderId: "str",
|
|
6768
|
+
InvoiceId: "str",
|
|
6769
|
+
CustomerId: "str",
|
|
6770
|
+
Secret: "str",
|
|
6771
|
+
Token: "str",
|
|
6772
|
+
Jwt: "str",
|
|
6773
|
+
IdempotencyKey: "str",
|
|
6774
|
+
Currency: "str",
|
|
6775
|
+
Date: "str",
|
|
6776
|
+
DateTime: "str",
|
|
6777
|
+
Money: "float",
|
|
6778
|
+
Percentage: "float",
|
|
6779
|
+
Count: "int",
|
|
6780
|
+
Duration: "int",
|
|
6781
|
+
Flag: "bool"
|
|
6782
|
+
};
|
|
6783
|
+
function pyType(type, domain) {
|
|
6784
|
+
if (!type) return "object";
|
|
6785
|
+
const list = /^List<(.+)>$/.exec(type);
|
|
6786
|
+
if (list) return `list[${pyType(list[1], domain)}]`;
|
|
6787
|
+
const base = type.replace(/\(.*\)/, "");
|
|
6788
|
+
if (PY_TYPES[base]) return PY_TYPES[base];
|
|
6789
|
+
domain.add(base);
|
|
6790
|
+
return base;
|
|
6791
|
+
}
|
|
6792
|
+
var snake = (s) => pascal2(s).replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase();
|
|
6793
|
+
function toPython(ast) {
|
|
6794
|
+
const subject = pascal2(subjectName(ast) || "Intent");
|
|
6795
|
+
const domain = /* @__PURE__ */ new Set();
|
|
6796
|
+
const L = [
|
|
6797
|
+
`# ${subject} , generated from ThunderLang (intent-codegen-v1). Deterministic, no AI.`,
|
|
6798
|
+
"# The dataclass contract and the decision logic are fully determined by the intent;",
|
|
6799
|
+
"# business logic marked TODO is yours, bound by the guarantees and never-rules below.",
|
|
6800
|
+
""
|
|
6801
|
+
];
|
|
6802
|
+
const hasData = (ast.inputs || []).length || (ast.outputs || []).length;
|
|
6803
|
+
if (hasData) L.push("from __future__ import annotations", "from dataclasses import dataclass", "");
|
|
6804
|
+
const cls = (name, fields) => fields.length ? ["@dataclass", `class ${name}:`, ...fields.map((f) => ` ${f.name}: ${pyType(f.type, domain)}`), ""] : [];
|
|
6805
|
+
if ((ast.inputs || []).length) L.push(...cls(`${subject}Input`, ast.inputs));
|
|
6806
|
+
if ((ast.outputs || []).length) L.push(...cls(`${subject}Output`, ast.outputs));
|
|
6807
|
+
for (const d of ast.decisions || []) {
|
|
6808
|
+
const inputs = d.inputs || [];
|
|
6809
|
+
L.push(`# decision ${d.name} , first matching rule wins.`);
|
|
6810
|
+
L.push(`def ${snake(d.name)}(${inputs.join(", ")}) -> str:`);
|
|
6811
|
+
for (const r of d.rules || []) {
|
|
6812
|
+
let cond, note = "";
|
|
6813
|
+
try {
|
|
6814
|
+
cond = exprToPython(r.when, { inputs });
|
|
6815
|
+
} catch {
|
|
6816
|
+
cond = "False";
|
|
6817
|
+
note = ` # TODO: could not translate "${r.when}"`;
|
|
6818
|
+
}
|
|
6819
|
+
L.push(` if ${cond}:${note}`);
|
|
6820
|
+
L.push(` return ${JSON.stringify(r.result)} # rule ${r.name}`);
|
|
6821
|
+
}
|
|
6822
|
+
L.push(` return ${JSON.stringify(d.default ?? "Undecided")} # default`, "");
|
|
6823
|
+
}
|
|
6824
|
+
const inName = (ast.inputs || []).length ? `${subject}Input` : null;
|
|
6825
|
+
const outName = (ast.outputs || []).length ? `${subject}Output` : "None";
|
|
6826
|
+
L.push(`def run(${inName ? `input: ${inName}` : ""}) -> ${outName}:`);
|
|
6827
|
+
for (const r of ast.requires || []) L.push(` # precondition: ${r} , TODO: validate`);
|
|
6828
|
+
for (const n of ast.neverRules || []) L.push(` # NEVER: ${n.statement}`);
|
|
6829
|
+
for (const g of ast.guarantees || []) L.push(` # GUARANTEE: ${g.statement}`);
|
|
6830
|
+
L.push(' raise NotImplementedError("TODO: implement , the intent above defines what this must do.")', "");
|
|
6831
|
+
const stubs = [...domain].filter((t) => !PY_TYPES[t] && /^[A-Z]/.test(t)).sort();
|
|
6832
|
+
if (stubs.length) {
|
|
6833
|
+
L.push("# Domain types referenced by the intent , complete these.");
|
|
6834
|
+
for (const t of stubs) L.push(`class ${t}: pass # TODO: fields`);
|
|
6835
|
+
L.push("");
|
|
6836
|
+
}
|
|
6837
|
+
return L.join("\n");
|
|
6838
|
+
}
|
|
6758
6839
|
var GENERATORS = {
|
|
6759
6840
|
typescript: toTypeScript,
|
|
6760
6841
|
ts: toTypeScript,
|
|
6761
6842
|
csharp: toCSharp,
|
|
6762
6843
|
cs: toCSharp,
|
|
6763
|
-
java: toJava
|
|
6844
|
+
java: toJava,
|
|
6845
|
+
python: toPython,
|
|
6846
|
+
py: toPython
|
|
6764
6847
|
};
|
|
6765
6848
|
|
|
6766
6849
|
// src/changes.mjs
|
|
@@ -6977,6 +7060,7 @@ function changeReport(pairs) {
|
|
|
6977
7060
|
toDesignTokens,
|
|
6978
7061
|
toFinding,
|
|
6979
7062
|
toJava,
|
|
7063
|
+
toPython,
|
|
6980
7064
|
toTypeScript,
|
|
6981
7065
|
twelveFactorReport,
|
|
6982
7066
|
twelveFactorSummary,
|