@skillstech/thunderlang 0.1.6 → 0.2.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.
package/dist/core.cjs CHANGED
@@ -471,7 +471,7 @@ var IL_AUTHOR_RULE_ROWS = [
471
471
  { ruleId: "IL-SEC-002", area: "security", severity: "blocker", blocks: ["release"], summary: "API returns a secret with no auth requirement." },
472
472
  { ruleId: "IL-TYPE-001", area: "type", severity: "info", blocks: [], summary: "Field uses an unrecognized (likely mistyped) type." },
473
473
  // 12-Factor Agents conformance (twelve-factor-v1). Advisory: an intent's alignment with the
474
- // humanlayer/12-factor-agents principles. `intent twelve-factor` scores these.
474
+ // humanlayer/12-factor-agents principles. `thunder twelve-factor` scores these.
475
475
  { ruleId: "IL-12F-01", area: "twelve-factor", severity: "info", blocks: [], summary: "F1 Natural language to tool calls: model dispatch as a decision/command." },
476
476
  { ruleId: "IL-12F-02", area: "twelve-factor", severity: "info", blocks: [], summary: "F2 Own your prompts: behavior is an owned, guaranteed contract, not a black box." },
477
477
  { ruleId: "IL-12F-03", area: "twelve-factor", severity: "info", blocks: [], summary: "F3 Own your context window: declare a scope boundary." },
@@ -497,8 +497,8 @@ var IL_CORE_RULE_ROWS = [
497
497
  { ruleId: "unknown-block", area: "core", severity: "info", blocks: [], summary: "Unrecognized top-level block." },
498
498
  { ruleId: "INTENT-ARCH-001", area: "architecture", severity: "warning", blocks: [], summary: "Architecture rule not understood." },
499
499
  { ruleId: "INTENT-AI-010", area: "ai", severity: "warning", blocks: [], summary: "Unsupported implementation scope." },
500
- { ruleId: "INTENT_NOTE_UNKNOWN_LENS", area: "note", severity: "info", blocks: [], summary: "IntentLens note uses an unknown lens." },
501
- { ruleId: "INTENT_NOTE_EMPTY", area: "note", severity: "info", blocks: [], summary: "IntentLens note is empty." }
500
+ { ruleId: "INTENT_NOTE_UNKNOWN_LENS", area: "note", severity: "info", blocks: [], summary: "ThunderLens note uses an unknown lens." },
501
+ { ruleId: "INTENT_NOTE_EMPTY", area: "note", severity: "info", blocks: [], summary: "ThunderLens note is empty." }
502
502
  ];
503
503
  var RULE_PHASES = ["author", "verify"];
504
504
  var RULE_OWNERS = ["IL", "OT"];
@@ -572,7 +572,7 @@ function intentProofJsonSchema() {
572
572
  sourceProduct: { type: "string" },
573
573
  missionName: { type: ["string", "null"] },
574
574
  sourceFile: { type: "string" },
575
- // sha256:<hex> , the source fingerprint `intent verify` re-checks for drift/tampering.
575
+ // sha256:<hex> , the source fingerprint `thunder verify` re-checks for drift/tampering.
576
576
  sourceHash: { type: "string", pattern: "^sha256:[0-9a-f]{64}$" },
577
577
  compilerVersion: { type: "string" },
578
578
  generatedAt: { type: ["string", "null"] },
@@ -789,6 +789,60 @@ function parseDecision(name, node2) {
789
789
  }
790
790
  return dec;
791
791
  }
792
+ function parseProperty(name, node2) {
793
+ const prop = { name, vars: [], decide: null, expects: [], line: node2.line };
794
+ for (const c of node2.children.filter((x) => !isNote(x))) {
795
+ const k = firstWord(c.text);
796
+ const a = rest(c.text);
797
+ if (k === "forAll" || k === "forall") {
798
+ for (const v of c.children.filter((x) => !isNote(x))) {
799
+ const m = v.text.trim().match(/^([A-Za-z_]\w*)\s*:\s*(\w+)(?:\s+where\s+(.+))?$/);
800
+ if (!m) continue;
801
+ const whereChild = (v.children || []).find((x) => firstWord(x.text) === "where");
802
+ prop.vars.push({ name: m[1], type: m[2], where: m[3] || (whereChild ? rest(whereChild.text) : null) });
803
+ }
804
+ } else if (k === "decide") prop.decide = a || c.children[0] && c.children[0].text.trim() || null;
805
+ else if (k === "when") {
806
+ const dm = a.match(/(?:decide|execute)\s+(\w+)/);
807
+ if (dm) prop.decide = dm[1];
808
+ } else if (k === "expect") for (const e of c.children.filter((x) => !isNote(x))) prop.expects.push(e.text.trim());
809
+ }
810
+ return prop;
811
+ }
812
+ function parseEvaluation(name, node2) {
813
+ const ev = { name, dataset: null, requires: [], line: node2.line };
814
+ for (const c of node2.children.filter((x) => !isNote(x))) {
815
+ const k = firstWord(c.text);
816
+ const a = rest(c.text);
817
+ if (k === "dataset") ev.dataset = a || c.children[0] && c.children[0].text.trim() || null;
818
+ else if (k === "require") {
819
+ for (const r of c.children.filter((x) => !isNote(x))) {
820
+ const m = r.text.trim().match(/^([A-Za-z_][\w.]*)\s*(>=|<=|==|!=|>|<)\s*(-?[\d.]+)$/);
821
+ if (m) ev.requires.push({ metric: m[1], op: m[2], threshold: parseFloat(m[3]) });
822
+ }
823
+ }
824
+ }
825
+ return ev;
826
+ }
827
+ function parseScenario(name, node2) {
828
+ const sc = { name, given: [], when: [], then: [], never: [], eventually: [], line: node2.line };
829
+ const clausesOf = (c) => {
830
+ const items = leafItems(c);
831
+ return items.length ? items : rest(c.text) ? [rest(c.text)] : [];
832
+ };
833
+ for (const c of node2.children.filter((x) => !isNote(x))) {
834
+ const k = firstWord(c.text);
835
+ if (k === "given") sc.given.push(...clausesOf(c));
836
+ else if (k === "when") sc.when.push(...clausesOf(c));
837
+ else if (k === "then") sc.then.push(...clausesOf(c));
838
+ else if (k === "never") sc.never.push(...clausesOf(c));
839
+ else if (k === "eventually") {
840
+ const within = (rest(c.text).match(/within\s+(.+)/) || [])[1] || null;
841
+ sc.eventually.push({ within, clauses: leafItems(c) });
842
+ }
843
+ }
844
+ return sc;
845
+ }
792
846
  function parseLifecycle(name, node2) {
793
847
  const lc = { name, states: [], transitions: [], terminals: [], line: node2.line };
794
848
  for (const c of node2.children.filter((x) => !isNote(x))) {
@@ -821,7 +875,13 @@ function parseInvariant(name, node2) {
821
875
  for (const c of kids(node2)) {
822
876
  const k = firstWord(c.text);
823
877
  if (k === "verify") inv.verify.push(rest(c.text));
824
- else if (k === "because") inv.because = rest(c.text);
878
+ else if (k === "id") {
879
+ const v = rest(c.text);
880
+ if (v) {
881
+ inv.id = v;
882
+ inv.stableId = v;
883
+ }
884
+ } else if (k === "because") inv.because = rest(c.text);
825
885
  else if (k === "statement") inv.statement = rest(c.text) || leafItems(c).join(" ");
826
886
  else if (k === "scope") inv.scope = (rest(c.text) || leafItems(c).join(" ")).toLowerCase();
827
887
  else if (k === "severity") inv.severity = (rest(c.text) || leafItems(c).join(" ")).toLowerCase();
@@ -907,11 +967,12 @@ function parseHandler(trigger, node2) {
907
967
  actions
908
968
  };
909
969
  }
970
+ var VERIFY_KINDS = /* @__PURE__ */ new Set(["assertion", "static", "runtime", "evidence", "tool", "approval", "formal"]);
910
971
  function upsertRule(list, statement, line) {
911
972
  const id = slug(statement);
912
973
  let r = list.find((x) => x.id === id);
913
974
  if (!r) {
914
- r = { id, statement, because: null, verify: [], notes: [], line };
975
+ r = { id, statement, because: null, verify: [], verifications: [], notes: [], line };
915
976
  list.push(r);
916
977
  }
917
978
  return r;
@@ -920,8 +981,28 @@ function applyDetail(rule, node2) {
920
981
  for (const c of node2.children) {
921
982
  const kw = firstWord(c.text);
922
983
  if (kw === "because") rule.because = rest(c.text) || c.children[0] && c.children[0].text || null;
923
- else if (kw === "verify") rule.verify.push(rest(c.text) || c.children[0] && c.children[0].text || "");
924
- else if (isNote(c)) rule.notes.push(parseNoteNode(c));
984
+ else if (kw === "verify") {
985
+ const a = rest(c.text);
986
+ const m = a && a.match(/^by\s+(\w+)/i);
987
+ if (m) {
988
+ const kind = m[1].toLowerCase();
989
+ const details = (c.children || []).filter((x) => !isNote(x)).map((x) => x.text.trim()).filter(Boolean);
990
+ rule.verifications.push({ kind: VERIFY_KINDS.has(kind) ? kind : "unknown", declared: kind, details });
991
+ rule.verify.push(details.length ? `${kind}: ${details.join("; ")}` : `by ${kind}`);
992
+ } else {
993
+ const v = a || c.children[0] && c.children[0].text || "";
994
+ if (v) {
995
+ rule.verify.push(v);
996
+ rule.verifications.push({ kind: "unclassified", declared: null, details: [v] });
997
+ }
998
+ }
999
+ } else if (kw === "id") {
1000
+ const v = rest(c.text) || c.children[0] && c.children[0].text;
1001
+ if (v) {
1002
+ rule.id = v;
1003
+ rule.stableId = v;
1004
+ }
1005
+ } else if (isNote(c)) rule.notes.push(parseNoteNode(c));
925
1006
  }
926
1007
  rule.verify = rule.verify.filter(Boolean);
927
1008
  }
@@ -986,6 +1067,9 @@ function parseIntent(source) {
986
1067
  handlers: [],
987
1068
  // Decisions, rules, process (Gap 4)
988
1069
  decisions: [],
1070
+ properties: [],
1071
+ scenarios: [],
1072
+ evaluations: [],
989
1073
  // Governance: waivers , governed exceptions to blocking diagnostics (Gap 5)
990
1074
  waivers: [],
991
1075
  // Data purpose + privacy , governed data elements (Gap 6)
@@ -1214,6 +1298,15 @@ function parseIntent(source) {
1214
1298
  case "decision":
1215
1299
  ast.decisions.push(parseDecision(arg, node2));
1216
1300
  break;
1301
+ case "property":
1302
+ ast.properties.push(parseProperty(arg, node2));
1303
+ break;
1304
+ case "scenario":
1305
+ ast.scenarios.push(parseScenario(arg, node2));
1306
+ break;
1307
+ case "evaluation":
1308
+ ast.evaluations.push(parseEvaluation(arg, node2));
1309
+ break;
1217
1310
  // ── System profile ──
1218
1311
  case "capability": {
1219
1312
  const cap = { name: arg, description: null, implements: [], line: node2.line };
@@ -3198,21 +3291,23 @@ function compileExpr(src) {
3198
3291
  function evalExpr(src, inputs = {}) {
3199
3292
  return compileExpr(src)(inputs);
3200
3293
  }
3294
+ var C_LOGIC = { and: (a, b) => `(${a} && ${b})`, or: (a, b) => `(${a} || ${b})`, not: (a) => `!${a}`, bool: (v) => String(v) };
3201
3295
  var DIALECTS = {
3202
- js: { eq: (a, b) => `${a} === ${b}`, neq: (a, b) => `${a} !== ${b}`, inList: (list, x) => `[${list.join(", ")}].includes(${x})`, nil: "undefined" },
3203
- csharp: { eq: (a, b) => `${a} == ${b}`, neq: (a, b) => `${a} != ${b}`, inList: (list, x) => `new[]{${list.join(", ")}}.Contains(${x})`, nil: "null" },
3204
- java: { eq: (a, b) => `java.util.Objects.equals(${a}, ${b})`, neq: (a, b) => `!java.util.Objects.equals(${a}, ${b})`, inList: (list, x) => `java.util.List.of(${list.join(", ")}).contains(${x})`, nil: "null" }
3296
+ js: { ...C_LOGIC, eq: (a, b) => `${a} === ${b}`, neq: (a, b) => `${a} !== ${b}`, inList: (list, x) => `[${list.join(", ")}].includes(${x})`, nil: "undefined" },
3297
+ csharp: { ...C_LOGIC, eq: (a, b) => `${a} == ${b}`, neq: (a, b) => `${a} != ${b}`, inList: (list, x) => `new[]{${list.join(", ")}}.Contains(${x})`, nil: "null" },
3298
+ java: { ...C_LOGIC, eq: (a, b) => `java.util.Objects.equals(${a}, ${b})`, neq: (a, b) => `!java.util.Objects.equals(${a}, ${b})`, inList: (list, x) => `java.util.List.of(${list.join(", ")}).contains(${x})`, nil: "null" },
3299
+ python: { and: (a, b) => `(${a} and ${b})`, or: (a, b) => `(${a} or ${b})`, not: (a) => `(not ${a})`, bool: (v) => v ? "True" : "False", eq: (a, b) => `${a} == ${b}`, neq: (a, b) => `${a} != ${b}`, inList: (list, x) => `${x} in [${list.join(", ")}]`, nil: "None" }
3205
3300
  };
3206
3301
  function renderExpr(src, inputs, D) {
3207
3302
  const known = new Set(inputs);
3208
3303
  const r = (n) => {
3209
3304
  switch (n.k) {
3210
3305
  case "or":
3211
- return `(${r(n.a)} || ${r(n.b)})`;
3306
+ return D.or(r(n.a), r(n.b));
3212
3307
  case "and":
3213
- return `(${r(n.a)} && ${r(n.b)})`;
3308
+ return D.and(r(n.a), r(n.b));
3214
3309
  case "not":
3215
- return `!${r(n.a)}`;
3310
+ return D.not(r(n.a));
3216
3311
  case "neg":
3217
3312
  return `-${r(n.a)}`;
3218
3313
  case "arith":
@@ -3226,7 +3321,7 @@ function renderExpr(src, inputs, D) {
3226
3321
  case "list":
3227
3322
  return `[${n.items.map(r).join(", ")}]`;
3228
3323
  case "lit":
3229
- return typeof n.v === "string" ? JSON.stringify(n.v) : String(n.v);
3324
+ return typeof n.v === "string" ? JSON.stringify(n.v) : typeof n.v === "boolean" ? D.bool(n.v) : String(n.v);
3230
3325
  case "ref":
3231
3326
  return known.has(n.path) || known.has(n.path.split(".")[0]) ? n.path : JSON.stringify(n.path);
3232
3327
  default:
@@ -3359,14 +3454,14 @@ function buildGuard(ast, { denyResults, mask = "[redacted]" } = {}) {
3359
3454
  }
3360
3455
  function decide(name, inputs) {
3361
3456
  const d = decisions.get(name);
3362
- if (!d) throw new Error(`intent guard: no decision "${name}"`);
3457
+ if (!d) throw new Error(`thunder guard: no decision "${name}"`);
3363
3458
  const r = evaluateDecision(d, inputs || {});
3364
3459
  return { ...r, allowed: !isDenied(r.result) };
3365
3460
  }
3366
3461
  function assertAllowed(name, inputs) {
3367
3462
  const r = decide(name, inputs);
3368
3463
  if (!r.allowed) {
3369
- const e = new Error(`intent guard: decision "${name}" denied the action (result: ${r.result})`);
3464
+ const e = new Error(`thunder guard: decision "${name}" denied the action (result: ${r.result})`);
3370
3465
  e.code = "INTENT_GUARD_DENIED";
3371
3466
  e.decision = name;
3372
3467
  e.result = r.result;
@@ -3570,7 +3665,7 @@ var FACTORS = [
3570
3665
  const scoped = len(ast.scope?.include) + len(ast.scope?.exclude);
3571
3666
  if (scoped) return { verdict: "satisfied", evidence: `context boundary declared (scope: ${len(ast.scope.include)} include / ${len(ast.scope.exclude)} exclude)` };
3572
3667
  if (len(ast.requires)) return { verdict: "partial", evidence: "dependencies declared but no explicit scope boundary", fix: "Declare `scope include/exclude` so the context window is curated, not unbounded." };
3573
- return { verdict: "absent", evidence: "no scope declared", fix: "Add a `scope` block to bound what belongs in context (IntentLens/Focus narrows it further)." };
3668
+ return { verdict: "absent", evidence: "no scope declared", fix: "Add a `scope` block to bound what belongs in context (ThunderLens/Focus narrows it further)." };
3574
3669
  }
3575
3670
  },
3576
3671
  {
@@ -4035,7 +4130,7 @@ function toDesignTokens(ast) {
4035
4130
  });
4036
4131
  for (const t of si.tokens) {
4037
4132
  const leaf = { $value: coerceValue(t.value), $type: tokenType(t.path) };
4038
- if (!isKnownPath(t.path)) leaf.$extensions = { "dev.thunderlang": { canonical: false } };
4133
+ if (!isKnownPath(t.path)) leaf.$extensions = { "dev.intentlanguage": { canonical: false } };
4039
4134
  setPath(root, t.path, leaf);
4040
4135
  }
4041
4136
  }
@@ -4043,7 +4138,7 @@ function toDesignTokens(ast) {
4043
4138
  $description: `Design tokens for ${ast.title || ast.mission || "intent"} (generated from style_intent by @skillstech/thunderlang)`,
4044
4139
  ...root,
4045
4140
  $extensions: {
4046
- "dev.thunderlang": {
4141
+ "dev.intentlanguage": {
4047
4142
  schema: DESIGN_TOKENS_SCHEMA,
4048
4143
  format: "W3C Design Tokens (DTCG)",
4049
4144
  source: ast.mission || null,
@@ -4193,7 +4288,7 @@ function notesSummary(ast) {
4193
4288
  byLens
4194
4289
  };
4195
4290
  }
4196
- var COMPILER_VERSION = "0.1.0";
4291
+ var COMPILER_VERSION = "0.2.0";
4197
4292
  var PROOF_SCHEMA_VERSION = "0.1.0";
4198
4293
  var SOURCE_PRODUCT = "skillstech-compiler";
4199
4294
  function buildContractGraph(ast, generatedAt) {
@@ -4686,13 +4781,15 @@ function buildProof(ast, { sourceFile, sourceHash, targetsRequested, targetsGene
4686
4781
  id: g.id,
4687
4782
  text: g.statement,
4688
4783
  status: g.verify.length > 0 || verifiedText ? "planned" : "needs_verification",
4689
- evidence: g.verify
4784
+ evidence: g.verify,
4785
+ verifications: g.verifications || []
4690
4786
  })),
4691
4787
  neverRules: ast.neverRules.map((n) => ({
4692
4788
  id: n.id,
4693
4789
  text: n.statement,
4694
4790
  status: n.verify.length > 0 ? "planned" : "needs_verification",
4695
- evidence: n.verify
4791
+ evidence: n.verify,
4792
+ verifications: n.verifications || []
4696
4793
  })),
4697
4794
  errors: (ast.errors || []).map((e) => ({ name: e.name })),
4698
4795
  examples: (ast.examples || []).map((ex) => ({ given: ex.given, expect: ex.expect })),
@@ -5527,7 +5624,7 @@ var LANG_EXT = {
5527
5624
  ruby: "rb",
5528
5625
  perl: "pl"
5529
5626
  };
5530
- function liftSource(source, { language = "typescript", file = "", seeds } = {}) {
5627
+ function liftSource(source, { language = "typescript", file = "", seeds = void 0 } = {}) {
5531
5628
  const key = String(language).toLowerCase();
5532
5629
  const adapter = ADAPTERS[key];
5533
5630
  if (!adapter) {
@@ -5597,7 +5694,7 @@ function renderLensDoc(ast, lens) {
5597
5694
  const L = [];
5598
5695
  L.push(`# ${m} , for the ${lens} reader`, "");
5599
5696
  L.push(
5600
- `> IntentLens \`${lens}\` notes are woven in below. They explain meaning for this`,
5697
+ `> ThunderLens \`${lens}\` notes are woven in below. They explain meaning for this`,
5601
5698
  `> audience; they are documentation, not verification.`,
5602
5699
  ""
5603
5700
  );
@@ -6069,7 +6166,7 @@ function fingerprint(parts) {
6069
6166
  return `fp_${h.toString(16)}`;
6070
6167
  }
6071
6168
  function makeScope({ type = "custom", title = null, seeds = [], projectId = null, createdBy = null, createdAt = null, ...rest2 } = {}) {
6072
- if (!SCOPE_TYPES.includes(type)) throw new Error(`intent focus: unknown scope type "${type}"`);
6169
+ if (!SCOPE_TYPES.includes(type)) throw new Error(`thunder focus: unknown scope type "${type}"`);
6073
6170
  return {
6074
6171
  schema: FOCUS_SCHEMA,
6075
6172
  scopeId: `scope.${type}.${fingerprint([type, ...seeds].map(String))}`,
package/dist/index.cjs CHANGED
@@ -450,6 +450,60 @@ function parseDecision(name, node2) {
450
450
  }
451
451
  return dec;
452
452
  }
453
+ function parseProperty(name, node2) {
454
+ const prop = { name, vars: [], decide: null, expects: [], line: node2.line };
455
+ for (const c of node2.children.filter((x) => !isNote(x))) {
456
+ const k = firstWord(c.text);
457
+ const a = rest(c.text);
458
+ if (k === "forAll" || k === "forall") {
459
+ for (const v of c.children.filter((x) => !isNote(x))) {
460
+ const m = v.text.trim().match(/^([A-Za-z_]\w*)\s*:\s*(\w+)(?:\s+where\s+(.+))?$/);
461
+ if (!m) continue;
462
+ const whereChild = (v.children || []).find((x) => firstWord(x.text) === "where");
463
+ prop.vars.push({ name: m[1], type: m[2], where: m[3] || (whereChild ? rest(whereChild.text) : null) });
464
+ }
465
+ } else if (k === "decide") prop.decide = a || c.children[0] && c.children[0].text.trim() || null;
466
+ else if (k === "when") {
467
+ const dm = a.match(/(?:decide|execute)\s+(\w+)/);
468
+ if (dm) prop.decide = dm[1];
469
+ } else if (k === "expect") for (const e of c.children.filter((x) => !isNote(x))) prop.expects.push(e.text.trim());
470
+ }
471
+ return prop;
472
+ }
473
+ function parseEvaluation(name, node2) {
474
+ const ev = { name, dataset: null, requires: [], line: node2.line };
475
+ for (const c of node2.children.filter((x) => !isNote(x))) {
476
+ const k = firstWord(c.text);
477
+ const a = rest(c.text);
478
+ if (k === "dataset") ev.dataset = a || c.children[0] && c.children[0].text.trim() || null;
479
+ else if (k === "require") {
480
+ for (const r of c.children.filter((x) => !isNote(x))) {
481
+ const m = r.text.trim().match(/^([A-Za-z_][\w.]*)\s*(>=|<=|==|!=|>|<)\s*(-?[\d.]+)$/);
482
+ if (m) ev.requires.push({ metric: m[1], op: m[2], threshold: parseFloat(m[3]) });
483
+ }
484
+ }
485
+ }
486
+ return ev;
487
+ }
488
+ function parseScenario(name, node2) {
489
+ const sc = { name, given: [], when: [], then: [], never: [], eventually: [], line: node2.line };
490
+ const clausesOf = (c) => {
491
+ const items = leafItems(c);
492
+ return items.length ? items : rest(c.text) ? [rest(c.text)] : [];
493
+ };
494
+ for (const c of node2.children.filter((x) => !isNote(x))) {
495
+ const k = firstWord(c.text);
496
+ if (k === "given") sc.given.push(...clausesOf(c));
497
+ else if (k === "when") sc.when.push(...clausesOf(c));
498
+ else if (k === "then") sc.then.push(...clausesOf(c));
499
+ else if (k === "never") sc.never.push(...clausesOf(c));
500
+ else if (k === "eventually") {
501
+ const within = (rest(c.text).match(/within\s+(.+)/) || [])[1] || null;
502
+ sc.eventually.push({ within, clauses: leafItems(c) });
503
+ }
504
+ }
505
+ return sc;
506
+ }
453
507
  function parseLifecycle(name, node2) {
454
508
  const lc = { name, states: [], transitions: [], terminals: [], line: node2.line };
455
509
  for (const c of node2.children.filter((x) => !isNote(x))) {
@@ -482,7 +536,13 @@ function parseInvariant(name, node2) {
482
536
  for (const c of kids(node2)) {
483
537
  const k = firstWord(c.text);
484
538
  if (k === "verify") inv.verify.push(rest(c.text));
485
- else if (k === "because") inv.because = rest(c.text);
539
+ else if (k === "id") {
540
+ const v = rest(c.text);
541
+ if (v) {
542
+ inv.id = v;
543
+ inv.stableId = v;
544
+ }
545
+ } else if (k === "because") inv.because = rest(c.text);
486
546
  else if (k === "statement") inv.statement = rest(c.text) || leafItems(c).join(" ");
487
547
  else if (k === "scope") inv.scope = (rest(c.text) || leafItems(c).join(" ")).toLowerCase();
488
548
  else if (k === "severity") inv.severity = (rest(c.text) || leafItems(c).join(" ")).toLowerCase();
@@ -568,11 +628,12 @@ function parseHandler(trigger, node2) {
568
628
  actions
569
629
  };
570
630
  }
631
+ var VERIFY_KINDS = /* @__PURE__ */ new Set(["assertion", "static", "runtime", "evidence", "tool", "approval", "formal"]);
571
632
  function upsertRule(list, statement, line) {
572
633
  const id = slug(statement);
573
634
  let r = list.find((x) => x.id === id);
574
635
  if (!r) {
575
- r = { id, statement, because: null, verify: [], notes: [], line };
636
+ r = { id, statement, because: null, verify: [], verifications: [], notes: [], line };
576
637
  list.push(r);
577
638
  }
578
639
  return r;
@@ -581,8 +642,28 @@ function applyDetail(rule, node2) {
581
642
  for (const c of node2.children) {
582
643
  const kw = firstWord(c.text);
583
644
  if (kw === "because") rule.because = rest(c.text) || c.children[0] && c.children[0].text || null;
584
- else if (kw === "verify") rule.verify.push(rest(c.text) || c.children[0] && c.children[0].text || "");
585
- else if (isNote(c)) rule.notes.push(parseNoteNode(c));
645
+ else if (kw === "verify") {
646
+ const a = rest(c.text);
647
+ const m = a && a.match(/^by\s+(\w+)/i);
648
+ if (m) {
649
+ const kind = m[1].toLowerCase();
650
+ const details = (c.children || []).filter((x) => !isNote(x)).map((x) => x.text.trim()).filter(Boolean);
651
+ rule.verifications.push({ kind: VERIFY_KINDS.has(kind) ? kind : "unknown", declared: kind, details });
652
+ rule.verify.push(details.length ? `${kind}: ${details.join("; ")}` : `by ${kind}`);
653
+ } else {
654
+ const v = a || c.children[0] && c.children[0].text || "";
655
+ if (v) {
656
+ rule.verify.push(v);
657
+ rule.verifications.push({ kind: "unclassified", declared: null, details: [v] });
658
+ }
659
+ }
660
+ } else if (kw === "id") {
661
+ const v = rest(c.text) || c.children[0] && c.children[0].text;
662
+ if (v) {
663
+ rule.id = v;
664
+ rule.stableId = v;
665
+ }
666
+ } else if (isNote(c)) rule.notes.push(parseNoteNode(c));
586
667
  }
587
668
  rule.verify = rule.verify.filter(Boolean);
588
669
  }
@@ -647,6 +728,9 @@ function parseIntent(source) {
647
728
  handlers: [],
648
729
  // Decisions, rules, process (Gap 4)
649
730
  decisions: [],
731
+ properties: [],
732
+ scenarios: [],
733
+ evaluations: [],
650
734
  // Governance: waivers , governed exceptions to blocking diagnostics (Gap 5)
651
735
  waivers: [],
652
736
  // Data purpose + privacy , governed data elements (Gap 6)
@@ -875,6 +959,15 @@ function parseIntent(source) {
875
959
  case "decision":
876
960
  ast.decisions.push(parseDecision(arg, node2));
877
961
  break;
962
+ case "property":
963
+ ast.properties.push(parseProperty(arg, node2));
964
+ break;
965
+ case "scenario":
966
+ ast.scenarios.push(parseScenario(arg, node2));
967
+ break;
968
+ case "evaluation":
969
+ ast.evaluations.push(parseEvaluation(arg, node2));
970
+ break;
878
971
  // ── System profile ──
879
972
  case "capability": {
880
973
  const cap = { name: arg, description: null, implements: [], line: node2.line };
@@ -1309,7 +1402,7 @@ var FACTORS = [
1309
1402
  const scoped = len(ast.scope?.include) + len(ast.scope?.exclude);
1310
1403
  if (scoped) return { verdict: "satisfied", evidence: `context boundary declared (scope: ${len(ast.scope.include)} include / ${len(ast.scope.exclude)} exclude)` };
1311
1404
  if (len(ast.requires)) return { verdict: "partial", evidence: "dependencies declared but no explicit scope boundary", fix: "Declare `scope include/exclude` so the context window is curated, not unbounded." };
1312
- return { verdict: "absent", evidence: "no scope declared", fix: "Add a `scope` block to bound what belongs in context (IntentLens/Focus narrows it further)." };
1405
+ return { verdict: "absent", evidence: "no scope declared", fix: "Add a `scope` block to bound what belongs in context (ThunderLens/Focus narrows it further)." };
1313
1406
  }
1314
1407
  },
1315
1408
  {
@@ -1977,7 +2070,7 @@ function toDesignTokens(ast) {
1977
2070
  });
1978
2071
  for (const t of si.tokens) {
1979
2072
  const leaf = { $value: coerceValue(t.value), $type: tokenType(t.path) };
1980
- if (!isKnownPath(t.path)) leaf.$extensions = { "dev.thunderlang": { canonical: false } };
2073
+ if (!isKnownPath(t.path)) leaf.$extensions = { "dev.intentlanguage": { canonical: false } };
1981
2074
  setPath(root, t.path, leaf);
1982
2075
  }
1983
2076
  }
@@ -1985,7 +2078,7 @@ function toDesignTokens(ast) {
1985
2078
  $description: `Design tokens for ${ast.title || ast.mission || "intent"} (generated from style_intent by @skillstech/thunderlang)`,
1986
2079
  ...root,
1987
2080
  $extensions: {
1988
- "dev.thunderlang": {
2081
+ "dev.intentlanguage": {
1989
2082
  schema: DESIGN_TOKENS_SCHEMA,
1990
2083
  format: "W3C Design Tokens (DTCG)",
1991
2084
  source: ast.mission || null,
@@ -2194,7 +2287,7 @@ function notesSummary(ast) {
2194
2287
  byLens
2195
2288
  };
2196
2289
  }
2197
- var COMPILER_VERSION = "0.1.0";
2290
+ var COMPILER_VERSION = "0.2.0";
2198
2291
  var PROOF_SCHEMA_VERSION = "0.1.0";
2199
2292
  var SOURCE_PRODUCT = "skillstech-compiler";
2200
2293
  function buildContractGraph(ast, generatedAt) {
@@ -2687,13 +2780,15 @@ function buildProof(ast, { sourceFile, sourceHash, targetsRequested, targetsGene
2687
2780
  id: g.id,
2688
2781
  text: g.statement,
2689
2782
  status: g.verify.length > 0 || verifiedText ? "planned" : "needs_verification",
2690
- evidence: g.verify
2783
+ evidence: g.verify,
2784
+ verifications: g.verifications || []
2691
2785
  })),
2692
2786
  neverRules: ast.neverRules.map((n) => ({
2693
2787
  id: n.id,
2694
2788
  text: n.statement,
2695
2789
  status: n.verify.length > 0 ? "planned" : "needs_verification",
2696
- evidence: n.verify
2790
+ evidence: n.verify,
2791
+ verifications: n.verifications || []
2697
2792
  })),
2698
2793
  errors: (ast.errors || []).map((e) => ({ name: e.name })),
2699
2794
  examples: (ast.examples || []).map((ex) => ({ given: ex.given, expect: ex.expect })),
@@ -2750,7 +2845,7 @@ function intentProofJsonSchema() {
2750
2845
  sourceProduct: { type: "string" },
2751
2846
  missionName: { type: ["string", "null"] },
2752
2847
  sourceFile: { type: "string" },
2753
- // sha256:<hex> , the source fingerprint `intent verify` re-checks for drift/tampering.
2848
+ // sha256:<hex> , the source fingerprint `thunder verify` re-checks for drift/tampering.
2754
2849
  sourceHash: { type: "string", pattern: "^sha256:[0-9a-f]{64}$" },
2755
2850
  compilerVersion: { type: "string" },
2756
2851
  generatedAt: { type: ["string", "null"] },
@@ -2862,7 +2957,7 @@ function renderLensDoc(ast, lens) {
2862
2957
  const L = [];
2863
2958
  L.push(`# ${m} , for the ${lens} reader`, "");
2864
2959
  L.push(
2865
- `> IntentLens \`${lens}\` notes are woven in below. They explain meaning for this`,
2960
+ `> ThunderLens \`${lens}\` notes are woven in below. They explain meaning for this`,
2866
2961
  `> audience; they are documentation, not verification.`,
2867
2962
  ""
2868
2963
  );
@@ -3104,7 +3199,7 @@ function getHover(source, position = {}) {
3104
3199
  target: lens,
3105
3200
  kind: "note_lens",
3106
3201
  title: `note ${lens}`,
3107
- description: LENS_INFO[lens] || "An IntentLens reader lens.",
3202
+ description: LENS_INFO[lens] || "An ThunderLens reader lens.",
3108
3203
  examples: [],
3109
3204
  relatedSuggestions: []
3110
3205
  }
@@ -3904,7 +3999,7 @@ var LANG_EXT = {
3904
3999
  ruby: "rb",
3905
4000
  perl: "pl"
3906
4001
  };
3907
- function liftSource(source, { language = "typescript", file = "", seeds } = {}) {
4002
+ function liftSource(source, { language = "typescript", file = "", seeds = void 0 } = {}) {
3908
4003
  const key = String(language).toLowerCase();
3909
4004
  const adapter = ADAPTERS[key];
3910
4005
  if (!adapter) {
@@ -4051,7 +4146,7 @@ function checkDrift(intentText, codeSource, { language = "typescript" } = {}) {
4051
4146
  add("warning", "INTENT_DRIFT_STALE_PROOF", "The approved intent was edited after approval (hash mismatch). Re-approve it.");
4052
4147
  }
4053
4148
  } else {
4054
- add("info", "INTENT_DRIFT_NOT_APPROVED", "This intent has no approval block. Approve it first: intent approve <file>.");
4149
+ add("info", "INTENT_DRIFT_NOT_APPROVED", "This intent has no approval block. Approve it first: thunder approve <file>.");
4055
4150
  }
4056
4151
  const lift = liftSource(codeSource, { language });
4057
4152
  if (!lift.ok) {
@@ -5677,7 +5772,7 @@ var IL_AUTHOR_RULE_ROWS = [
5677
5772
  { ruleId: "IL-SEC-002", area: "security", severity: "blocker", blocks: ["release"], summary: "API returns a secret with no auth requirement." },
5678
5773
  { ruleId: "IL-TYPE-001", area: "type", severity: "info", blocks: [], summary: "Field uses an unrecognized (likely mistyped) type." },
5679
5774
  // 12-Factor Agents conformance (twelve-factor-v1). Advisory: an intent's alignment with the
5680
- // humanlayer/12-factor-agents principles. `intent twelve-factor` scores these.
5775
+ // humanlayer/12-factor-agents principles. `thunder twelve-factor` scores these.
5681
5776
  { ruleId: "IL-12F-01", area: "twelve-factor", severity: "info", blocks: [], summary: "F1 Natural language to tool calls: model dispatch as a decision/command." },
5682
5777
  { ruleId: "IL-12F-02", area: "twelve-factor", severity: "info", blocks: [], summary: "F2 Own your prompts: behavior is an owned, guaranteed contract, not a black box." },
5683
5778
  { ruleId: "IL-12F-03", area: "twelve-factor", severity: "info", blocks: [], summary: "F3 Own your context window: declare a scope boundary." },
@@ -5703,8 +5798,8 @@ var IL_CORE_RULE_ROWS = [
5703
5798
  { ruleId: "unknown-block", area: "core", severity: "info", blocks: [], summary: "Unrecognized top-level block." },
5704
5799
  { ruleId: "INTENT-ARCH-001", area: "architecture", severity: "warning", blocks: [], summary: "Architecture rule not understood." },
5705
5800
  { ruleId: "INTENT-AI-010", area: "ai", severity: "warning", blocks: [], summary: "Unsupported implementation scope." },
5706
- { ruleId: "INTENT_NOTE_UNKNOWN_LENS", area: "note", severity: "info", blocks: [], summary: "IntentLens note uses an unknown lens." },
5707
- { ruleId: "INTENT_NOTE_EMPTY", area: "note", severity: "info", blocks: [], summary: "IntentLens note is empty." }
5801
+ { ruleId: "INTENT_NOTE_UNKNOWN_LENS", area: "note", severity: "info", blocks: [], summary: "ThunderLens note uses an unknown lens." },
5802
+ { ruleId: "INTENT_NOTE_EMPTY", area: "note", severity: "info", blocks: [], summary: "ThunderLens note is empty." }
5708
5803
  ];
5709
5804
  var RULE_PHASES = ["author", "verify"];
5710
5805
  var RULE_OWNERS = ["IL", "OT"];
@@ -6088,21 +6183,23 @@ function compileExpr(src) {
6088
6183
  function evalExpr(src, inputs = {}) {
6089
6184
  return compileExpr(src)(inputs);
6090
6185
  }
6186
+ var C_LOGIC = { and: (a, b) => `(${a} && ${b})`, or: (a, b) => `(${a} || ${b})`, not: (a) => `!${a}`, bool: (v) => String(v) };
6091
6187
  var DIALECTS = {
6092
- js: { eq: (a, b) => `${a} === ${b}`, neq: (a, b) => `${a} !== ${b}`, inList: (list, x) => `[${list.join(", ")}].includes(${x})`, nil: "undefined" },
6093
- csharp: { eq: (a, b) => `${a} == ${b}`, neq: (a, b) => `${a} != ${b}`, inList: (list, x) => `new[]{${list.join(", ")}}.Contains(${x})`, nil: "null" },
6094
- java: { eq: (a, b) => `java.util.Objects.equals(${a}, ${b})`, neq: (a, b) => `!java.util.Objects.equals(${a}, ${b})`, inList: (list, x) => `java.util.List.of(${list.join(", ")}).contains(${x})`, nil: "null" }
6188
+ js: { ...C_LOGIC, eq: (a, b) => `${a} === ${b}`, neq: (a, b) => `${a} !== ${b}`, inList: (list, x) => `[${list.join(", ")}].includes(${x})`, nil: "undefined" },
6189
+ csharp: { ...C_LOGIC, eq: (a, b) => `${a} == ${b}`, neq: (a, b) => `${a} != ${b}`, inList: (list, x) => `new[]{${list.join(", ")}}.Contains(${x})`, nil: "null" },
6190
+ java: { ...C_LOGIC, eq: (a, b) => `java.util.Objects.equals(${a}, ${b})`, neq: (a, b) => `!java.util.Objects.equals(${a}, ${b})`, inList: (list, x) => `java.util.List.of(${list.join(", ")}).contains(${x})`, nil: "null" },
6191
+ python: { and: (a, b) => `(${a} and ${b})`, or: (a, b) => `(${a} or ${b})`, not: (a) => `(not ${a})`, bool: (v) => v ? "True" : "False", eq: (a, b) => `${a} == ${b}`, neq: (a, b) => `${a} != ${b}`, inList: (list, x) => `${x} in [${list.join(", ")}]`, nil: "None" }
6095
6192
  };
6096
6193
  function renderExpr(src, inputs, D) {
6097
6194
  const known = new Set(inputs);
6098
6195
  const r = (n) => {
6099
6196
  switch (n.k) {
6100
6197
  case "or":
6101
- return `(${r(n.a)} || ${r(n.b)})`;
6198
+ return D.or(r(n.a), r(n.b));
6102
6199
  case "and":
6103
- return `(${r(n.a)} && ${r(n.b)})`;
6200
+ return D.and(r(n.a), r(n.b));
6104
6201
  case "not":
6105
- return `!${r(n.a)}`;
6202
+ return D.not(r(n.a));
6106
6203
  case "neg":
6107
6204
  return `-${r(n.a)}`;
6108
6205
  case "arith":
@@ -6116,7 +6213,7 @@ function renderExpr(src, inputs, D) {
6116
6213
  case "list":
6117
6214
  return `[${n.items.map(r).join(", ")}]`;
6118
6215
  case "lit":
6119
- return typeof n.v === "string" ? JSON.stringify(n.v) : String(n.v);
6216
+ return typeof n.v === "string" ? JSON.stringify(n.v) : typeof n.v === "boolean" ? D.bool(n.v) : String(n.v);
6120
6217
  case "ref":
6121
6218
  return known.has(n.path) || known.has(n.path.split(".")[0]) ? n.path : JSON.stringify(n.path);
6122
6219
  default:
@@ -6237,7 +6334,7 @@ function runTests(ast) {
6237
6334
  const inputs = coerce(c.given);
6238
6335
  const run = evaluateDecision(dec, inputs);
6239
6336
  const pass = c.expect == null || String(run.result) === String(c.expect);
6240
- results.push({ ...label, kind: "decision", expected: c.expect, actual: run.result, pass, ...run.ok ? {} : { note: "a condition failed to evaluate" } });
6337
+ results.push({ ...label, kind: "decision", expected: c.expect, actual: run.result, matched: run.matched, pass, ...run.ok ? {} : { note: "a condition failed to evaluate" } });
6241
6338
  } else if (lc) {
6242
6339
  const sim = simulateLifecycle(lc, c.events || []);
6243
6340
  const passState = c.expect == null || sim.finalState === c.expect;
@@ -7246,7 +7343,7 @@ function fingerprint(parts) {
7246
7343
  return `fp_${h.toString(16)}`;
7247
7344
  }
7248
7345
  function makeScope({ type = "custom", title = null, seeds = [], projectId = null, createdBy = null, createdAt = null, ...rest2 } = {}) {
7249
- if (!SCOPE_TYPES.includes(type)) throw new Error(`intent focus: unknown scope type "${type}"`);
7346
+ if (!SCOPE_TYPES.includes(type)) throw new Error(`thunder focus: unknown scope type "${type}"`);
7250
7347
  return {
7251
7348
  schema: FOCUS_SCHEMA,
7252
7349
  scopeId: `scope.${type}.${fingerprint([type, ...seeds].map(String))}`,
@@ -8071,7 +8168,7 @@ function payloadOf(seq, entry, prev) {
8071
8168
  };
8072
8169
  }
8073
8170
  function record(ledger, entry) {
8074
- if (!entry || !ENTRY_TYPES.includes(entry.type)) throw new Error(`intent ledger: unknown entry type "${entry?.type}"`);
8171
+ if (!entry || !ENTRY_TYPES.includes(entry.type)) throw new Error(`thunder ledger: unknown entry type "${entry?.type}"`);
8075
8172
  const base = ledger && Array.isArray(ledger.entries) ? ledger : emptyLedger();
8076
8173
  const payload = payloadOf(base.entries.length, entry, base.head);
8077
8174
  const hash = sha256(JSON.stringify(payload));
@@ -8218,7 +8315,7 @@ function emptyEventLog() {
8218
8315
  }
8219
8316
  function recordEvent(log, event) {
8220
8317
  if (!event || !INTENT_AI_EVENTS.includes(event.type)) {
8221
- throw new Error(`intent ai events: unknown event type "${event?.type}"`);
8318
+ throw new Error(`thunder ai events: unknown event type "${event?.type}"`);
8222
8319
  }
8223
8320
  const base = log && Array.isArray(log.events) ? log : emptyEventLog();
8224
8321
  return { ...base, events: [...base.events, event] };
@@ -8582,14 +8679,14 @@ function buildGuard(ast, { denyResults, mask = "[redacted]" } = {}) {
8582
8679
  }
8583
8680
  function decide(name, inputs) {
8584
8681
  const d = decisions.get(name);
8585
- if (!d) throw new Error(`intent guard: no decision "${name}"`);
8682
+ if (!d) throw new Error(`thunder guard: no decision "${name}"`);
8586
8683
  const r = evaluateDecision(d, inputs || {});
8587
8684
  return { ...r, allowed: !isDenied(r.result) };
8588
8685
  }
8589
8686
  function assertAllowed(name, inputs) {
8590
8687
  const r = decide(name, inputs);
8591
8688
  if (!r.allowed) {
8592
- const e = new Error(`intent guard: decision "${name}" denied the action (result: ${r.result})`);
8689
+ const e = new Error(`thunder guard: decision "${name}" denied the action (result: ${r.result})`);
8593
8690
  e.code = "INTENT_GUARD_DENIED";
8594
8691
  e.decision = name;
8595
8692
  e.result = r.result;