@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/dist/index.cjs CHANGED
@@ -160,6 +160,7 @@ __export(index_exports, {
160
160
  comprehensionLevel: () => comprehensionLevel,
161
161
  comprehensionReport: () => comprehensionReport,
162
162
  confidenceFromClassification: () => confidenceFromClassification,
163
+ conformToEvidence: () => conformToEvidence,
163
164
  contractHash: () => contractHash,
164
165
  contradictionsView: () => contradictionsView,
165
166
  correctionsFor: () => correctionsFor,
@@ -168,6 +169,7 @@ __export(index_exports, {
168
169
  detectFormat: () => detectFormat,
169
170
  diffGraphs: () => diffGraphs,
170
171
  draftIntent: () => draftIntent,
172
+ driftToEvidence: () => driftToEvidence,
171
173
  dropNodeField: () => dropNodeField,
172
174
  emptyApprovals: () => emptyApprovals,
173
175
  emptyEventLog: () => emptyEventLog,
@@ -288,12 +290,14 @@ __export(index_exports, {
288
290
  toCss: () => toCss,
289
291
  toDMN: () => toDMN,
290
292
  toDesignTokens: () => toDesignTokens,
293
+ toEvidenceEvents: () => toEvidenceEvents,
291
294
  toFinding: () => toFinding,
292
295
  toJSONSchema: () => toJSONSchema,
293
296
  toJava: () => toJava,
294
297
  toMermaid: () => toMermaid,
295
298
  toOpenAPI: () => toOpenAPI,
296
299
  toPlaywright: () => toPlaywright,
300
+ toPython: () => toPython,
297
301
  toSMV: () => toSMV,
298
302
  toSarif: () => toSarif,
299
303
  toTypeScript: () => toTypeScript,
@@ -308,6 +312,7 @@ __export(index_exports, {
308
312
  validateIR: () => validateIR,
309
313
  validateProof: () => validateProof,
310
314
  verifyDiff: () => verifyDiff,
315
+ verifyDiffToEvidence: () => verifyDiffToEvidence,
311
316
  verifyLedger: () => verifyLedger,
312
317
  violatesArchitecture: () => violatesArchitecture,
313
318
  whyBuilt: () => whyBuilt
@@ -327,8 +332,8 @@ function intentRefId(astOrName, { sourceHash } = {}) {
327
332
  const name = typeof astOrName === "string" ? astOrName : subjectName(astOrName);
328
333
  const base = `intent:${slug(name || "mission")}`;
329
334
  if (!sourceHash) return base;
330
- const short = String(sourceHash).replace(/^sha256:/, "").slice(0, 8);
331
- return short ? `${base}@${short}` : base;
335
+ const short2 = String(sourceHash).replace(/^sha256:/, "").slice(0, 8);
336
+ return short2 ? `${base}@${short2}` : base;
332
337
  }
333
338
  function skillRefId(name) {
334
339
  return `skill:${slug(name || "unknown")}`;
@@ -1224,6 +1229,103 @@ function parseIntent(source) {
1224
1229
  return ast;
1225
1230
  }
1226
1231
 
1232
+ // src/evidence.mjs
1233
+ var COUNTED_STATUSES = ["verified", "failed", "planned", "needs_verification"];
1234
+ var stripHash = (h) => String(h || "").replace(/^sha256:/, "");
1235
+ var short = (h, n = 16) => stripHash(h).slice(0, n);
1236
+ function envelope(eventType, evidenceId, ctx = {}, payload = {}) {
1237
+ return {
1238
+ schema: "evidence-event-v1",
1239
+ sourceProduct: "thunderlang",
1240
+ producer: { name: "thunderlang", version: ctx.compilerVersion || null },
1241
+ eventType,
1242
+ evidenceType: "tool_verified",
1243
+ evidenceId,
1244
+ occurredAt: ctx.occurredAt || null,
1245
+ visibility: ctx.visibility || "private",
1246
+ subject: { missionName: ctx.missionName || null, intentHash: ctx.intentHash || null },
1247
+ payload
1248
+ };
1249
+ }
1250
+ var safeClaim = (kind, c) => ({ id: c.id, kind, status: c.status, provenBy: c.provenBy || null });
1251
+ function countByStatus(claims) {
1252
+ const counts = Object.fromEntries(COUNTED_STATUSES.map((s) => [s, 0]));
1253
+ for (const c of claims) if (c && Object.prototype.hasOwnProperty.call(counts, c.status)) counts[c.status]++;
1254
+ return counts;
1255
+ }
1256
+ var safeFinding = (f) => ({ code: f.code, level: f.level, ...f.regression !== void 0 ? { regression: !!f.regression } : {}, ...f.line !== void 0 ? { line: f.line } : {} });
1257
+ function toEvidenceEvents(proof) {
1258
+ if (!proof || typeof proof !== "object") return [];
1259
+ const guarantees = Array.isArray(proof.guarantees) ? proof.guarantees : [];
1260
+ const neverRules = Array.isArray(proof.neverRules) ? proof.neverRules : [];
1261
+ const claims = [
1262
+ ...guarantees.map((c) => safeClaim("guarantee", c)),
1263
+ ...neverRules.map((c) => safeClaim("prohibition", c))
1264
+ ];
1265
+ const fr = proof.freshness || {};
1266
+ const intentHash2 = proof.freshness?.intentHash || proof.sourceHash || null;
1267
+ return [envelope("intent.proven", `tl-proof-${short(intentHash2)}`, {
1268
+ compilerVersion: proof.compilerVersion,
1269
+ occurredAt: proof.generatedAt,
1270
+ missionName: proof.missionName,
1271
+ intentHash: intentHash2
1272
+ }, {
1273
+ proofStatus: proof.proofStatus || null,
1274
+ total: claims.length,
1275
+ counts: countByStatus(claims),
1276
+ freshness: { implementation: fr.implementation || null, dependencies: fr.dependencies ? fr.dependencies.hash || null : null, environment: fr.environment || null },
1277
+ claims
1278
+ })];
1279
+ }
1280
+ function verifyDiffToEvidence(verdict2, ctx = {}) {
1281
+ if (!verdict2 || typeof verdict2 !== "object") return [];
1282
+ const findings2 = Array.isArray(verdict2.findings) ? verdict2.findings : [];
1283
+ const id = `tl-verifydiff-${short(ctx.intentHash)}${ctx.changeHash ? `-${short(ctx.changeHash, 8)}` : ""}`;
1284
+ return [envelope("change.gated", id, ctx, {
1285
+ verdict: verdict2.verdict || null,
1286
+ ok: !!verdict2.ok,
1287
+ blocking: verdict2.blocking || 0,
1288
+ regressions: verdict2.summary?.regressions ?? findings2.filter((f) => f.regression).length,
1289
+ findings: findings2.map(safeFinding)
1290
+ })];
1291
+ }
1292
+ function conformToEvidence(report, ctx = {}) {
1293
+ if (!report || typeof report !== "object") return [];
1294
+ const cases = Array.isArray(report.cases) ? report.cases : [];
1295
+ const columns = Array.isArray(report.columns) ? report.columns : [];
1296
+ const targets = {};
1297
+ for (const col of columns) {
1298
+ const t = { pass: 0, fail: 0, declared: 0 };
1299
+ for (const c of cases) {
1300
+ const s = c.targets?.[col]?.status;
1301
+ if (s === "pass") t.pass++;
1302
+ else if (s === "fail") t.fail++;
1303
+ else t.declared++;
1304
+ }
1305
+ targets[col] = t;
1306
+ }
1307
+ return [envelope("conformance.verified", `tl-conform-${short(ctx.intentHash)}`, ctx, {
1308
+ total: report.total || cases.length,
1309
+ columns,
1310
+ semanticFailures: report.semanticFailures || 0,
1311
+ graded: !!report.graded,
1312
+ targets,
1313
+ // failure locations by name only (case + target), never expected/actual values.
1314
+ failures: (Array.isArray(report.failures) ? report.failures : []).map((f) => ({ target: f.target, case: f.case }))
1315
+ })];
1316
+ }
1317
+ function driftToEvidence(report, ctx = {}) {
1318
+ if (!report || typeof report !== "object") return [];
1319
+ const findings2 = Array.isArray(report.findings) ? report.findings : [];
1320
+ const id = `tl-drift-${short(ctx.intentHash)}${ctx.codeHash ? `-${short(ctx.codeHash, 8)}` : ""}`;
1321
+ return [envelope("intent.drift", id, ctx, {
1322
+ status: report.status || null,
1323
+ total: findings2.length,
1324
+ blocking: report.summary?.blocking ?? 0,
1325
+ findings: findings2.map(safeFinding)
1326
+ })];
1327
+ }
1328
+
1227
1329
  // src/hash.mjs
1228
1330
  var K = new Uint32Array([
1229
1331
  1116352408,
@@ -2287,7 +2389,7 @@ function notesSummary(ast) {
2287
2389
  byLens
2288
2390
  };
2289
2391
  }
2290
- var COMPILER_VERSION = "0.3.0";
2392
+ var COMPILER_VERSION = "0.4.2";
2291
2393
  var PROOF_SCHEMA_VERSION = "0.1.0";
2292
2394
  var SOURCE_PRODUCT = "skillstech-compiler";
2293
2395
  function buildContractGraph(ast, generatedAt) {
@@ -4086,7 +4188,7 @@ function liftRepo(files, { language } = {}) {
4086
4188
  const base = slug(r.lifted.mission);
4087
4189
  const n = (usedNames.get(base) || 0) + 1;
4088
4190
  usedNames.set(base, n);
4089
- const outName = n === 1 ? `${base}.intent` : `${base}-${n}.intent`;
4191
+ const outName = n === 1 ? `${base}.thunder` : `${base}-${n}.thunder`;
4090
4192
  missions.push({
4091
4193
  mission: r.lifted.mission,
4092
4194
  sourceFile: file,
@@ -5147,7 +5249,9 @@ function toPlaywright(ast) {
5147
5249
  const exps = ast.experiences || [];
5148
5250
  const L = [];
5149
5251
  L.push("// Playwright test scaffold generated from experience intent by @skillstech/thunderlang.");
5150
- L.push("// SKELETON: fill in selectors and assertions. It is not a passing test until you do.");
5252
+ L.push("// SKELETON: fill in selectors and assertions. Every test starts with a test.fixme");
5253
+ L.push('// guard so an unimplemented scaffold reports "fixme" instead of passing vacuously;');
5254
+ L.push("// remove the guard from each test once its body is real.");
5151
5255
  L.push("import { test, expect } from '@playwright/test';");
5152
5256
  L.push("");
5153
5257
  if (!exps.length) {
@@ -5162,6 +5266,7 @@ function toPlaywright(ast) {
5162
5266
  }
5163
5267
  for (const j of exp.journeys || []) {
5164
5268
  L.push(` test(${jsStr(j.name || "journey")}, async ({ page }) => {`);
5269
+ L.push(` test.fixme(true, ${jsStr("scaffold: implement the steps, then remove this guard")});`);
5165
5270
  if (!(j.steps || []).length) L.push(" // TODO: no steps declared for this journey");
5166
5271
  for (const step of j.steps || []) {
5167
5272
  L.push(` await test.step(${jsStr(step)}, async () => {`);
@@ -5173,10 +5278,12 @@ function toPlaywright(ast) {
5173
5278
  for (const st of exp.states || []) {
5174
5279
  if (st.hasRecovery) {
5175
5280
  L.push(` test(${jsStr(`failure state "${st.name}" offers a recovery path`)}, async ({ page }) => {`);
5281
+ L.push(` test.fixme(true, ${jsStr("scaffold: implement this state check, then remove this guard")});`);
5176
5282
  L.push(` // TODO: drive the UI into "${st.name}", assert a recovery action is available`);
5177
5283
  L.push(" });");
5178
5284
  } else {
5179
5285
  L.push(` test(${jsStr(`reaches state: ${st.name}`)}, async ({ page }) => {`);
5286
+ L.push(` test.fixme(true, ${jsStr("scaffold: implement this state check, then remove this guard")});`);
5180
5287
  L.push(` // TODO: drive the UI to "${st.name}" and assert it is shown`);
5181
5288
  L.push(" });");
5182
5289
  }
@@ -6351,6 +6458,7 @@ function exprToCode(src, { inputs = [], dialect = "js" } = {}) {
6351
6458
  var exprToJs = (src, opts = {}) => exprToCode(src, { ...opts, dialect: "js" });
6352
6459
  var exprToCSharp = (src, opts = {}) => exprToCode(src, { ...opts, dialect: "csharp" });
6353
6460
  var exprToJava = (src, opts = {}) => exprToCode(src, { ...opts, dialect: "java" });
6461
+ var exprToPython = (src, opts = {}) => exprToCode(src, { ...opts, dialect: "python" });
6354
6462
 
6355
6463
  // src/runtime.mjs
6356
6464
  var RUNTIME_SCHEMA = "intent-runtime-v1";
@@ -7848,7 +7956,7 @@ function toCSharp(ast) {
7848
7956
  try {
7849
7957
  cond = exprToCSharp(r.when, { inputs });
7850
7958
  } catch {
7851
- cond = `false /* TODO: "${r.when}" */`;
7959
+ cond = `false /* TODO: could not translate "${r.when}" */`;
7852
7960
  }
7853
7961
  L.push(` if (${cond}) return ${JSON.stringify(r.result)}; // rule ${r.name}`);
7854
7962
  }
@@ -7857,6 +7965,7 @@ function toCSharp(ast) {
7857
7965
  const inName = (ast.inputs || []).length ? `${subject}Input` : null;
7858
7966
  const outName = (ast.outputs || []).length ? `${subject}Output` : "void";
7859
7967
  L.push(` public static ${outName} Run(${inName ? `${inName} input` : ""})`, " {");
7968
+ for (const r of ast.requires || []) L.push(` // precondition: ${r} , TODO: validate`);
7860
7969
  for (const n of ast.neverRules || []) L.push(` // NEVER: ${n.statement}`);
7861
7970
  for (const g of ast.guarantees || []) L.push(` // GUARANTEE: ${g.statement}`);
7862
7971
  L.push(' throw new NotImplementedException("TODO: implement , the intent above defines what this must do.");', " }");
@@ -7917,7 +8026,7 @@ function toJava(ast) {
7917
8026
  try {
7918
8027
  cond = exprToJava(r.when, { inputs });
7919
8028
  } catch {
7920
- cond = `false /* TODO: "${r.when}" */`;
8029
+ cond = `false /* TODO: could not translate "${r.when}" */`;
7921
8030
  }
7922
8031
  L.push(` if (${cond}) return ${JSON.stringify(r.result)}; // rule ${r.name}`);
7923
8032
  }
@@ -7926,18 +8035,98 @@ function toJava(ast) {
7926
8035
  const inName = (ast.inputs || []).length ? `${subject}Input` : null;
7927
8036
  const outName = (ast.outputs || []).length ? `${subject}Output` : "void";
7928
8037
  L.push(` public static ${outName} run(${inName ? `${inName} input` : ""}) {`);
8038
+ for (const r of ast.requires || []) L.push(` // precondition: ${r} , TODO: validate`);
7929
8039
  for (const n of ast.neverRules || []) L.push(` // NEVER: ${n.statement}`);
7930
8040
  for (const g of ast.guarantees || []) L.push(` // GUARANTEE: ${g.statement}`);
7931
8041
  L.push(' throw new UnsupportedOperationException("TODO: implement , the intent above defines what this must do.");', " }");
7932
8042
  L.push("}", "");
7933
8043
  return L.join("\n");
7934
8044
  }
8045
+ var PY_TYPES = {
8046
+ Email: "str",
8047
+ Url: "str",
8048
+ UserId: "str",
8049
+ AccountId: "str",
8050
+ OrderId: "str",
8051
+ InvoiceId: "str",
8052
+ CustomerId: "str",
8053
+ Secret: "str",
8054
+ Token: "str",
8055
+ Jwt: "str",
8056
+ IdempotencyKey: "str",
8057
+ Currency: "str",
8058
+ Date: "str",
8059
+ DateTime: "str",
8060
+ Money: "float",
8061
+ Percentage: "float",
8062
+ Count: "int",
8063
+ Duration: "int",
8064
+ Flag: "bool"
8065
+ };
8066
+ function pyType(type, domain) {
8067
+ if (!type) return "object";
8068
+ const list = /^List<(.+)>$/.exec(type);
8069
+ if (list) return `list[${pyType(list[1], domain)}]`;
8070
+ const base = type.replace(/\(.*\)/, "");
8071
+ if (PY_TYPES[base]) return PY_TYPES[base];
8072
+ domain.add(base);
8073
+ return base;
8074
+ }
8075
+ var snake = (s) => pascal2(s).replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase();
8076
+ function toPython(ast) {
8077
+ const subject = pascal2(subjectName(ast) || "Intent");
8078
+ const domain = /* @__PURE__ */ new Set();
8079
+ const L = [
8080
+ `# ${subject} , generated from ThunderLang (intent-codegen-v1). Deterministic, no AI.`,
8081
+ "# The dataclass contract and the decision logic are fully determined by the intent;",
8082
+ "# business logic marked TODO is yours, bound by the guarantees and never-rules below.",
8083
+ ""
8084
+ ];
8085
+ const hasData = (ast.inputs || []).length || (ast.outputs || []).length;
8086
+ if (hasData) L.push("from __future__ import annotations", "from dataclasses import dataclass", "");
8087
+ const cls = (name, fields) => fields.length ? ["@dataclass", `class ${name}:`, ...fields.map((f) => ` ${f.name}: ${pyType(f.type, domain)}`), ""] : [];
8088
+ if ((ast.inputs || []).length) L.push(...cls(`${subject}Input`, ast.inputs));
8089
+ if ((ast.outputs || []).length) L.push(...cls(`${subject}Output`, ast.outputs));
8090
+ for (const d of ast.decisions || []) {
8091
+ const inputs = d.inputs || [];
8092
+ L.push(`# decision ${d.name} , first matching rule wins.`);
8093
+ L.push(`def ${snake(d.name)}(${inputs.join(", ")}) -> str:`);
8094
+ for (const r of d.rules || []) {
8095
+ let cond, note = "";
8096
+ try {
8097
+ cond = exprToPython(r.when, { inputs });
8098
+ } catch {
8099
+ cond = "False";
8100
+ note = ` # TODO: could not translate "${r.when}"`;
8101
+ }
8102
+ L.push(` if ${cond}:${note}`);
8103
+ L.push(` return ${JSON.stringify(r.result)} # rule ${r.name}`);
8104
+ }
8105
+ L.push(` return ${JSON.stringify(d.default ?? "Undecided")} # default`, "");
8106
+ }
8107
+ const inName = (ast.inputs || []).length ? `${subject}Input` : null;
8108
+ const outName = (ast.outputs || []).length ? `${subject}Output` : "None";
8109
+ L.push(`def run(${inName ? `input: ${inName}` : ""}) -> ${outName}:`);
8110
+ for (const r of ast.requires || []) L.push(` # precondition: ${r} , TODO: validate`);
8111
+ for (const n of ast.neverRules || []) L.push(` # NEVER: ${n.statement}`);
8112
+ for (const g of ast.guarantees || []) L.push(` # GUARANTEE: ${g.statement}`);
8113
+ L.push(' raise NotImplementedError("TODO: implement , the intent above defines what this must do.")', "");
8114
+ const stubs = [...domain].filter((t) => !PY_TYPES[t] && /^[A-Z]/.test(t)).sort();
8115
+ if (stubs.length) {
8116
+ L.push("# Domain types referenced by the intent , complete these.");
8117
+ for (const t of stubs) L.push(`class ${t}: pass # TODO: fields`);
8118
+ L.push("");
8119
+ }
8120
+ return L.join("\n");
8121
+ }
7935
8122
  var GENERATORS = {
7936
8123
  typescript: toTypeScript,
7937
8124
  ts: toTypeScript,
7938
8125
  csharp: toCSharp,
7939
8126
  cs: toCSharp,
7940
- java: toJava
8127
+ java: toJava,
8128
+ python: toPython,
8129
+ py: toPython
7941
8130
  };
7942
8131
 
7943
8132
  // src/changes.mjs
@@ -8527,6 +8716,54 @@ function verifyDiff(intentText, { before = null, after, language = "typescript"
8527
8716
  };
8528
8717
  }
8529
8718
 
8719
+ // src/mcp.mjs
8720
+ var import_node_child_process = require("node:child_process");
8721
+ var import_node_fs = require("node:fs");
8722
+ var import_node_path = require("node:path");
8723
+
8724
+ // src/conformance.mjs
8725
+ function buildConformance(ast, { targets = [], results = null } = {}) {
8726
+ const sem = runTests(ast);
8727
+ const cases = (sem.results || []).map((r) => ({
8728
+ key: `${r.target} / ${r.case}`,
8729
+ test: r.target,
8730
+ case: r.case,
8731
+ inputs: r.inputs || {},
8732
+ expected: r.expected,
8733
+ semantic: r.actual,
8734
+ semanticPass: !!r.pass
8735
+ }));
8736
+ const columns = (targets.length ? targets : ast.targets || []).map((t) => String(t).toLowerCase());
8737
+ const rows = cases.map((c) => {
8738
+ const t = {};
8739
+ for (const col of columns) {
8740
+ const tr = results && results[col];
8741
+ if (!tr || !(c.key in tr)) {
8742
+ t[col] = { status: "declared" };
8743
+ continue;
8744
+ }
8745
+ const actual = tr[c.key];
8746
+ t[col] = { status: String(actual) === String(c.expected) ? "pass" : "fail", actual };
8747
+ }
8748
+ return { ...c, targets: t };
8749
+ });
8750
+ const failures = [];
8751
+ for (const row of rows) for (const col of columns) {
8752
+ const tr = row.targets[col];
8753
+ if (tr.status === "fail") failures.push({ target: col, case: row.key, expected: row.expected, actual: tr.actual });
8754
+ }
8755
+ return {
8756
+ schema: "thunder-conformance-v1",
8757
+ mission: ast.mission,
8758
+ total: cases.length,
8759
+ columns,
8760
+ semanticFailures: cases.filter((c) => !c.semanticPass).length,
8761
+ graded: !!results,
8762
+ failures,
8763
+ cases: rows
8764
+ };
8765
+ }
8766
+
8530
8767
  // src/draft.mjs
8531
8768
  var DRAFT_SCHEMA = "intent-draft-v1";
8532
8769
  var SECRET_TYPES2 = /* @__PURE__ */ new Set(["secret", "password", "passwd", "jwt", "token", "apikey", "api_key", "privatekey", "private_key", "credential", "cvv"]);
@@ -8618,6 +8855,75 @@ function draftIntent(brief = {}) {
8618
8855
  // src/mcp.mjs
8619
8856
  var PROTOCOL_VERSION = "2024-11-05";
8620
8857
  var str = { type: "string" };
8858
+ function resolveObligations(ast) {
8859
+ const t = runTests(ast);
8860
+ const testPass = /* @__PURE__ */ new Map();
8861
+ for (const res of t.results || []) {
8862
+ const cur = testPass.get(res.target);
8863
+ testPass.set(res.target, cur === void 0 ? !!res.pass : cur && !!res.pass);
8864
+ }
8865
+ const norm4 = (s) => String(s).toLowerCase().replace(/[^a-z0-9]/g, "");
8866
+ const matchTest = (verifyText) => {
8867
+ const v = norm4(verifyText);
8868
+ if (!v) return null;
8869
+ for (const [name, pass] of testPass) {
8870
+ const n = norm4(name);
8871
+ if (n && (n === v || n.includes(v) || v.includes(n))) return { name, pass };
8872
+ }
8873
+ return null;
8874
+ };
8875
+ const build = (kind, o) => {
8876
+ const verify = o.verify || [];
8877
+ let status = "unverified", provenBy = null;
8878
+ if (verify.length) {
8879
+ let m = null;
8880
+ for (const vt of verify) {
8881
+ const x = matchTest(vt);
8882
+ if (x) {
8883
+ m = x;
8884
+ if (!x.pass) break;
8885
+ }
8886
+ }
8887
+ if (m) {
8888
+ status = m.pass ? "verified" : "failed";
8889
+ provenBy = m.name;
8890
+ } else status = "declared";
8891
+ }
8892
+ return { kind, id: o.id, status, provenBy };
8893
+ };
8894
+ const obligations = [...ast.guarantees.map((g) => build("guarantee", g)), ...ast.neverRules.map((n) => build("prohibition", n))];
8895
+ return { obligations, tests: t, failed: obligations.filter((o) => o.status === "failed").length };
8896
+ }
8897
+ var LOCKFILES = ["pnpm-lock.yaml", "package-lock.json", "yarn.lock", "poetry.lock", "Pipfile.lock", "Cargo.lock", "go.sum", "Gemfile.lock", "composer.lock"];
8898
+ function proofFreshness(proof, environment) {
8899
+ let head = null;
8900
+ try {
8901
+ head = (0, import_node_child_process.execSync)("git rev-parse HEAD", { encoding: "utf8", stdio: ["pipe", "pipe", "ignore"] }).trim() || null;
8902
+ } catch {
8903
+ head = null;
8904
+ }
8905
+ let lock = null, dir = process.cwd();
8906
+ for (let i = 0; i < 6 && !lock; i++) {
8907
+ for (const lf of LOCKFILES) {
8908
+ const p = (0, import_node_path.join)(dir, lf);
8909
+ if ((0, import_node_fs.existsSync)(p)) {
8910
+ lock = p;
8911
+ break;
8912
+ }
8913
+ }
8914
+ const parent = (0, import_node_path.dirname)(dir);
8915
+ if (parent === dir) break;
8916
+ dir = parent;
8917
+ }
8918
+ return {
8919
+ intentHash: proof.sourceHash,
8920
+ compilerVersion: proof.compilerVersion,
8921
+ implementation: head,
8922
+ dependencies: lock ? { file: (0, import_node_path.basename)(lock), hash: sha256((0, import_node_fs.readFileSync)(lock, "utf8")) } : null,
8923
+ environment: environment || null,
8924
+ generatedAt: proof.generatedAt
8925
+ };
8926
+ }
8621
8927
  var TOOLS = [
8622
8928
  {
8623
8929
  name: "intent_check",
@@ -8643,6 +8949,75 @@ var TOOLS = [
8643
8949
  },
8644
8950
  run: ({ intent, after, before = null, language = "typescript" }) => verifyDiff(String(intent), { before: before == null ? null : String(before), after: String(after), language })
8645
8951
  },
8952
+ {
8953
+ name: "intent_prove",
8954
+ description: "Emit the durable intent-proof-v1 artifact for .intent source: per-claim verdicts (verified / failed / planned / needs_verification, each bound to the named test that proves it) plus the freshness tuple (intent hash, compiler version, commit, dependency lockfile) that lets `thunder verify` mark the proof STALE later. Mirrors `thunder prove`; an unverified claim never reads as passed. Call it after the gate passes to record WHAT was proven.",
8955
+ inputSchema: {
8956
+ type: "object",
8957
+ required: ["source"],
8958
+ properties: {
8959
+ source: { ...str, description: "the .intent source" },
8960
+ sourceFile: { ...str, description: "file name to record in the proof (default intent.thunder)" },
8961
+ environment: { ...str, description: "environment name to bind into the freshness tuple (optional)" }
8962
+ }
8963
+ },
8964
+ run: ({ source, sourceFile = "intent.thunder", environment }) => {
8965
+ const text = String(source);
8966
+ const ast = parseIntent(text);
8967
+ const diagnostics = semanticDiagnostics(ast);
8968
+ const resolved = resolveObligations(ast);
8969
+ const proof = buildProof(ast, {
8970
+ sourceFile: String(sourceFile),
8971
+ sourceHash: sha256(text),
8972
+ targetsRequested: ast.targets || [],
8973
+ targetsGenerated: [],
8974
+ diagnostics,
8975
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString()
8976
+ });
8977
+ const CLAIM_MAP = { verified: "verified", failed: "failed", declared: "planned", unverified: "needs_verification" };
8978
+ const byId = new Map(resolved.obligations.map((o) => [o.id, o]));
8979
+ const applyStatus = (claim) => {
8980
+ const o = byId.get(claim.id);
8981
+ return o ? { ...claim, status: CLAIM_MAP[o.status], provenBy: o.provenBy || null } : claim;
8982
+ };
8983
+ proof.guarantees = proof.guarantees.map(applyStatus);
8984
+ proof.neverRules = proof.neverRules.map(applyStatus);
8985
+ proof.freshness = proofFreshness(proof, environment);
8986
+ const ok = proof.verification.semanticPassed && resolved.tests.ok !== false && resolved.failed === 0;
8987
+ return { ok, proofId: `proof-${proof.sourceHash.replace("sha256:", "").slice(0, 6)}`, ...proof, tests: resolved.tests };
8988
+ }
8989
+ },
8990
+ {
8991
+ name: "intent_conform",
8992
+ description: 'Grade cross-target conformance (thunder-conformance-v1): the deterministic engine defines the canonical result every in-file test case must produce, and each target\'s outputs (passed via `results`) are graded against it. Same tests, every implementation , a diverging target case is a CONFORMANCE FAILURE. Mirrors `thunder conform`. Without `results`, targets honestly stay "declared", never "pass".',
8993
+ inputSchema: {
8994
+ type: "object",
8995
+ required: ["source"],
8996
+ properties: {
8997
+ source: { ...str, description: "the .intent source (with test blocks)" },
8998
+ targets: { type: "array", items: str, description: "target languages to grade (default: the targets the intent declares)" },
8999
+ results: { type: "object", description: 'per-target actual outputs to grade: {target: {"Test / case": result}}' }
9000
+ }
9001
+ },
9002
+ run: ({ source, targets = [], results = null }) => {
9003
+ const rep = buildConformance(parseIntent(String(source)), { targets: Array.isArray(targets) ? targets.map(String) : [], results });
9004
+ return { ok: rep.semanticFailures === 0 && rep.failures.length === 0, ...rep };
9005
+ }
9006
+ },
9007
+ {
9008
+ name: "intent_drift",
9009
+ description: "Check whether real code, as it exists TODAY, still satisfies its intent , the standing-guard complement to intent_verify_diff (no diff needed). Re-lifts the code and reports drift findings: guarantees with no matching evidence, never-rules with no guard, declared inputs missing from the signature, and new behavior the intent never declared. Mirrors `thunder drift`.",
9010
+ inputSchema: {
9011
+ type: "object",
9012
+ required: ["intent", "code"],
9013
+ properties: {
9014
+ intent: { ...str, description: "the approved .intent source (the contract)" },
9015
+ code: { ...str, description: "the implementation source as it exists now" },
9016
+ language: { ...str, description: `source language (default typescript). One of: ${SUPPORTED_LANGUAGES.join(", ")}` }
9017
+ }
9018
+ },
9019
+ run: ({ intent, code, language = "typescript" }) => checkDrift(String(intent), String(code), { language })
9020
+ },
8646
9021
  {
8647
9022
  name: "intent_draft",
8648
9023
  description: "Turn a STRUCTURED brief into a rigorous, canonically-formatted ThunderLang draft plus a review checklist of what a human must still fill in (unverified guarantees, unguarded secrets, missing goal). Use this after distilling a user request into structured fields; the draft is a proposal for human approval, never verified.",
@@ -9374,6 +9749,7 @@ function startLspServer({ readable = process.stdin, writable = process.stdout }
9374
9749
  comprehensionLevel,
9375
9750
  comprehensionReport,
9376
9751
  confidenceFromClassification,
9752
+ conformToEvidence,
9377
9753
  contractHash,
9378
9754
  contradictionsView,
9379
9755
  correctionsFor,
@@ -9382,6 +9758,7 @@ function startLspServer({ readable = process.stdin, writable = process.stdout }
9382
9758
  detectFormat,
9383
9759
  diffGraphs,
9384
9760
  draftIntent,
9761
+ driftToEvidence,
9385
9762
  dropNodeField,
9386
9763
  emptyApprovals,
9387
9764
  emptyEventLog,
@@ -9502,12 +9879,14 @@ function startLspServer({ readable = process.stdin, writable = process.stdout }
9502
9879
  toCss,
9503
9880
  toDMN,
9504
9881
  toDesignTokens,
9882
+ toEvidenceEvents,
9505
9883
  toFinding,
9506
9884
  toJSONSchema,
9507
9885
  toJava,
9508
9886
  toMermaid,
9509
9887
  toOpenAPI,
9510
9888
  toPlaywright,
9889
+ toPython,
9511
9890
  toSMV,
9512
9891
  toSarif,
9513
9892
  toTypeScript,
@@ -9522,6 +9901,7 @@ function startLspServer({ readable = process.stdin, writable = process.stdout }
9522
9901
  validateIR,
9523
9902
  validateProof,
9524
9903
  verifyDiff,
9904
+ verifyDiffToEvidence,
9525
9905
  verifyLedger,
9526
9906
  violatesArchitecture,
9527
9907
  whyBuilt
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skillstech/thunderlang",
3
- "version": "0.3.0",
3
+ "version": "0.4.2",
4
4
  "description": "Deterministic ThunderLang compiler, CLI, and Language Server. No AI required. Turns .thunder files into the canonical Intent Graph, docs, and a proof, and EXECUTES the intent: run decisions, simulate lifecycles, and check outcome contracts. Interops with DMN, BPMN, JSON Schema, and OpenAPI.",
5
5
  "type": "module",
6
6
  "main": "./src/index.mjs",
@@ -70,11 +70,11 @@
70
70
  "homepage": "https://thunderlang.dev",
71
71
  "repository": {
72
72
  "type": "git",
73
- "url": "git+https://github.com/SkillsTechTalk/intent-language.git",
73
+ "url": "git+https://github.com/SkillsTechTalk/thunderlang.git",
74
74
  "directory": "compiler"
75
75
  },
76
76
  "bugs": {
77
- "url": "https://github.com/SkillsTechTalk/intent-language/issues"
77
+ "url": "https://github.com/SkillsTechTalk/thunderlang/issues"
78
78
  },
79
79
  "author": "Skills Tech Talk, LLC",
80
80
  "license": "Apache-2.0",