@skillstech/thunderlang 0.1.6 → 0.1.7

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/src/codegen.mjs CHANGED
@@ -2,7 +2,7 @@
2
2
  // intent always produces the same code. It generates what the intent fully determines (typed
3
3
  // interfaces, and the decision logic, which is already executable) and leaves honest TODO
4
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`.
5
+ // the "see how it works, then change it" surface for the playground and `thunder gen`.
6
6
  //
7
7
  // Pure and browser-safe so the playground can render it. TypeScript first; the same adapter
8
8
  // shape (a type map + a body walk) extends to C# / Java.
package/src/compile.mjs CHANGED
@@ -30,7 +30,7 @@ export function renderMarkdown(ast) {
30
30
 
31
31
  /**
32
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
33
+ * ThunderLens notes inline next to the mission element they annotate. Notes explain
34
34
  * meaning; they are never verification, and the doc says so. Pure and browser-safe.
35
35
  */
36
36
  export function renderLensDoc(ast, lens) {
@@ -40,7 +40,7 @@ export function renderLensDoc(ast, lens) {
40
40
  const notesFor = (path) => (ast.notes || []).filter((n) => n.lens === lens && n.targetPath === path);
41
41
  const L = [];
42
42
  L.push(`# ${m} , for the ${lens} reader`, '');
43
- L.push(`> IntentLens \`${lens}\` notes are woven in below. They explain meaning for this`,
43
+ L.push(`> ThunderLens \`${lens}\` notes are woven in below. They explain meaning for this`,
44
44
  `> audience; they are documentation, not verification.`, '');
45
45
  for (const nt of notesFor(prefix)) L.push(`_${flat(nt.text)}_`, '');
46
46
  if (ast.goal) L.push(`**Goal.** ${ast.goal}`, '');
@@ -93,7 +93,7 @@ export function renderTestplan(ast) {
93
93
  }
94
94
 
95
95
  /**
96
- * Compile ThunderLang source in memory and return every artifact `intent build`
96
+ * Compile ThunderLang source in memory and return every artifact `thunder build`
97
97
  * would emit, without touching the filesystem.
98
98
  */
99
99
  export function compileSource(source, { sourceFile = 'playground.intent', generatedAt, origin = 'authored' } = {}) {
package/src/drift.mjs CHANGED
@@ -2,7 +2,7 @@
2
2
  // still matches the approved intent. Deterministic, no AI. This is the
3
3
  // compiler-side drift check; OpenThunder does the deeper repo-wide version later.
4
4
  //
5
- // lift code -> .intent draft -> intent approve -> (code changes) -> intent drift
5
+ // lift code -> .intent draft -> thunder approve -> (code changes) -> intent drift
6
6
 
7
7
  import { createHash } from 'node:crypto';
8
8
  import { parseIntent, slug } from './parse.mjs';
@@ -45,7 +45,7 @@ export function approveIntent(intentText, { approvedBy, approvedAt } = {}) {
45
45
  .replace(/^(\s*)reviewed\s+false\b/m, '$1reviewed true')
46
46
  .replace(/\s+$/, '');
47
47
  // Hash the exact content that gets written (post reviewed-flip), so a later
48
- // `intent drift` recomputes the same hash when nothing has changed.
48
+ // `thunder drift` recomputes the same hash when nothing has changed.
49
49
  const hash = sha256(base.trim());
50
50
  const lines = ['approval', ' reviewed true'];
51
51
  if (approvedBy) lines.push(` approved_by ${approvedBy}`);
@@ -137,7 +137,7 @@ export function checkDrift(intentText, codeSource, { language = 'typescript' } =
137
137
  add('warning', 'INTENT_DRIFT_STALE_PROOF', 'The approved intent was edited after approval (hash mismatch). Re-approve it.');
138
138
  }
139
139
  } else {
140
- add('info', 'INTENT_DRIFT_NOT_APPROVED', 'This intent has no approval block. Approve it first: intent approve <file>.');
140
+ add('info', 'INTENT_DRIFT_NOT_APPROVED', 'This intent has no approval block. Approve it first: thunder approve <file>.');
141
141
  }
142
142
 
143
143
  const lift = liftSource(codeSource, { language });
package/src/emit.mjs CHANGED
@@ -188,7 +188,7 @@ export function semanticDiagnostics(ast) {
188
188
  }
189
189
  }
190
190
 
191
- // ── IntentLens note checks (understanding, never verification) ──
191
+ // ── ThunderLens note checks (understanding, never verification) ──
192
192
  for (const note of ast.notes || []) {
193
193
  if (!KNOWN_LENSES.includes(note.lens)) {
194
194
  warn('INTENT_NOTE_UNKNOWN_LENS',
@@ -245,7 +245,7 @@ export function semanticDiagnostics(ast) {
245
245
  }
246
246
 
247
247
  // ── Product / intent-graph diagnostics (intent-graph-v1) ──
248
- // Role-aware. Kept at warning/info so `intent check` stays valid; `severity` +
248
+ // Role-aware. Kept at warning/info so `thunder check` stays valid; `severity` +
249
249
  // `blocks` drive phase gates (a valid spec can still be not-ready-to-proceed).
250
250
  for (const m of ast.metrics || []) {
251
251
  if (!m.window) d.push({
package/src/focus.mjs CHANGED
@@ -33,7 +33,7 @@ function fingerprint(parts) {
33
33
 
34
34
  /** Build a typed Intent Scope. `createdAt` is supplied by the caller (deterministic/testable). */
35
35
  export function makeScope({ type = 'custom', title = null, seeds = [], projectId = null, createdBy = null, createdAt = null, ...rest } = {}) {
36
- if (!SCOPE_TYPES.includes(type)) throw new Error(`intent focus: unknown scope type "${type}"`);
36
+ if (!SCOPE_TYPES.includes(type)) throw new Error(`thunder focus: unknown scope type "${type}"`);
37
37
  return {
38
38
  schema: FOCUS_SCHEMA,
39
39
  scopeId: `scope.${type}.${fingerprint([type, ...seeds].map(String))}`,
package/src/guard.mjs CHANGED
@@ -65,7 +65,7 @@ export function buildGuard(ast, { denyResults, mask = '[redacted]' } = {}) {
65
65
 
66
66
  function decide(name, inputs) {
67
67
  const d = decisions.get(name);
68
- if (!d) throw new Error(`intent guard: no decision "${name}"`);
68
+ if (!d) throw new Error(`thunder guard: no decision "${name}"`);
69
69
  const r = evaluateDecision(d, inputs || {});
70
70
  return { ...r, allowed: !isDenied(r.result) };
71
71
  }
@@ -73,7 +73,7 @@ export function buildGuard(ast, { denyResults, mask = '[redacted]' } = {}) {
73
73
  function assertAllowed(name, inputs) {
74
74
  const r = decide(name, inputs);
75
75
  if (!r.allowed) {
76
- const e = new Error(`intent guard: decision "${name}" denied the action (result: ${r.result})`);
76
+ const e = new Error(`thunder guard: decision "${name}" denied the action (result: ${r.result})`);
77
77
  e.code = 'INTENT_GUARD_DENIED';
78
78
  e.decision = name;
79
79
  e.result = r.result;
@@ -98,7 +98,7 @@ export function compileGuard(intentText, opts) {
98
98
  return buildGuard(parseIntent(String(intentText ?? '')), opts);
99
99
  }
100
100
 
101
- /** A JSON-able summary of what a guard would enforce (for `intent guard` / audits). */
101
+ /** A JSON-able summary of what a guard would enforce (for `thunder guard` / audits). */
102
102
  export function guardSummary(ast) {
103
103
  const g = buildGuard(ast);
104
104
  return { schema: GUARD_SCHEMA, redactsFields: g.secretFields, enforcesDecisions: g.decisions, neverRules: g.neverRules };
@@ -129,7 +129,7 @@ export function getHover(source, position = {}) {
129
129
  return {
130
130
  hover: {
131
131
  target: lens, kind: 'note_lens', title: `note ${lens}`,
132
- description: LENS_INFO[lens] || 'An IntentLens reader lens.',
132
+ description: LENS_INFO[lens] || 'An ThunderLens reader lens.',
133
133
  examples: [], relatedSuggestions: [],
134
134
  },
135
135
  };
@@ -3,7 +3,7 @@
3
3
  // enums / diagnostics (gap-closure program non-negotiable #1). Pure (no Node deps).
4
4
  //
5
5
  // IL owns + versions this. OT/RM/ST/STW import these enums + the JSON Schema instead
6
- // of maintaining their own copies. `intent schema` emits the JSON Schema.
6
+ // of maintaining their own copies. `thunder schema` emits the JSON Schema.
7
7
 
8
8
  import { CLASSIFICATIONS, CONFIDENCE } from './classification.mjs';
9
9
 
@@ -134,7 +134,7 @@ const IL_AUTHOR_RULE_ROWS = [
134
134
  { ruleId: 'IL-SEC-002', area: 'security', severity: 'blocker', blocks: ['release'], summary: 'API returns a secret with no auth requirement.' },
135
135
  { ruleId: 'IL-TYPE-001', area: 'type', severity: 'info', blocks: [], summary: 'Field uses an unrecognized (likely mistyped) type.' },
136
136
  // 12-Factor Agents conformance (twelve-factor-v1). Advisory: an intent's alignment with the
137
- // humanlayer/12-factor-agents principles. `intent twelve-factor` scores these.
137
+ // humanlayer/12-factor-agents principles. `thunder twelve-factor` scores these.
138
138
  { ruleId: 'IL-12F-01', area: 'twelve-factor', severity: 'info', blocks: [], summary: 'F1 Natural language to tool calls: model dispatch as a decision/command.' },
139
139
  { 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.' },
140
140
  { ruleId: 'IL-12F-03', area: 'twelve-factor', severity: 'info', blocks: [], summary: 'F3 Own your context window: declare a scope boundary.' },
@@ -165,8 +165,8 @@ const IL_CORE_RULE_ROWS = [
165
165
  { ruleId: 'unknown-block', area: 'core', severity: 'info', blocks: [], summary: 'Unrecognized top-level block.' },
166
166
  { ruleId: 'INTENT-ARCH-001', area: 'architecture', severity: 'warning', blocks: [], summary: 'Architecture rule not understood.' },
167
167
  { ruleId: 'INTENT-AI-010', area: 'ai', severity: 'warning', blocks: [], summary: 'Unsupported implementation scope.' },
168
- { ruleId: 'INTENT_NOTE_UNKNOWN_LENS', area: 'note', severity: 'info', blocks: [], summary: 'IntentLens note uses an unknown lens.' },
169
- { ruleId: 'INTENT_NOTE_EMPTY', area: 'note', severity: 'info', blocks: [], summary: 'IntentLens note is empty.' },
168
+ { ruleId: 'INTENT_NOTE_UNKNOWN_LENS', area: 'note', severity: 'info', blocks: [], summary: 'ThunderLens note uses an unknown lens.' },
169
+ { ruleId: 'INTENT_NOTE_EMPTY', area: 'note', severity: 'info', blocks: [], summary: 'ThunderLens note is empty.' },
170
170
  ];
171
171
 
172
172
  // ── Rule namespaces: ONE id space across two PHASES ──────────────────────────
package/src/ledger.mjs CHANGED
@@ -40,7 +40,7 @@ function payloadOf(seq, entry, prev) {
40
40
 
41
41
  /** Append an entry to the ledger, hash-chained over the previous head. Returns a NEW ledger. */
42
42
  export function record(ledger, entry) {
43
- if (!entry || !ENTRY_TYPES.includes(entry.type)) throw new Error(`intent ledger: unknown entry type "${entry?.type}"`);
43
+ if (!entry || !ENTRY_TYPES.includes(entry.type)) throw new Error(`thunder ledger: unknown entry type "${entry?.type}"`);
44
44
  const base = ledger && Array.isArray(ledger.entries) ? ledger : emptyLedger();
45
45
  const payload = payloadOf(base.entries.length, entry, base.head);
46
46
  const hash = sha256(JSON.stringify(payload));
package/src/lift.mjs CHANGED
@@ -546,7 +546,7 @@ function liftDiagnostics(lift, facts) {
546
546
  * Lift a set of source files (a repo) into inferred ThunderLang drafts, one per
547
547
  * file that yields a mission. `files` is [{ file, source }] (the CLI reads the
548
548
  * filesystem; this core function stays pure). Returns per-mission drafts + a
549
- * repo-level summary matching the `intent lift --from repo --json` contract.
549
+ * repo-level summary matching the `thunder lift --from repo --json` contract.
550
550
  */
551
551
  export function languageForFile(file) {
552
552
  if (/\.rs$/i.test(file)) return 'rust';
@@ -651,7 +651,7 @@ const LANG_EXT = {
651
651
  * EXACT node ids instead of lift's own function refs, so there is no divergent second reading.
652
652
  * Additive: with no seeds the output is byte-identical to before.
653
653
  */
654
- export function liftSource(source, { language = 'typescript', file = '', seeds } = {}) {
654
+ export function liftSource(source, { language = 'typescript', file = '', seeds = undefined } = {}) {
655
655
  const key = String(language).toLowerCase();
656
656
  const adapter = ADAPTERS[key];
657
657
  if (!adapter) {
package/src/lsp.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  // A minimal Language Server for ThunderLang (LSP over stdio). Wraps the compiler's existing
2
2
  // diagnostics + IntelliSense so ANY LSP-capable editor (VS Code, Neovim, Helix, ...) gets
3
3
  // live ThunderLang intelligence: diagnostics on open/change, keyword/type completions, and
4
- // hover docs for semantic types and note lenses. Deterministic; no AI. `intent lsp` starts it.
4
+ // hover docs for semantic types and note lenses. Deterministic; no AI. `thunder lsp` starts it.
5
5
 
6
6
  import { parseIntent } from './parse.mjs';
7
7
  import { semanticDiagnostics } from './emit.mjs';
package/src/mcp.mjs CHANGED
@@ -4,7 +4,7 @@
4
4
  // check its own output, and , the keystone , verify a proposed code change against the intent
5
5
  // before it ships. No AI runs here; every tool is the pure, deterministic compiler.
6
6
  //
7
- // Start it with `intent mcp`. Point an MCP client at that command.
7
+ // Start it with `thunder mcp`. Point an MCP client at that command.
8
8
 
9
9
  import { parseIntent } from './parse.mjs';
10
10
  import { semanticDiagnostics, COMPILER_VERSION } from './emit.mjs';
package/src/parse.mjs CHANGED
@@ -86,7 +86,7 @@ function buildTree(rows) {
86
86
  return root.children;
87
87
  }
88
88
 
89
- // Known IntentLens reader lenses. Unknown lenses warn (INTENT_NOTE_UNKNOWN_LENS).
89
+ // Known ThunderLens reader lenses. Unknown lenses warn (INTENT_NOTE_UNKNOWN_LENS).
90
90
  export const KNOWN_LENSES = [
91
91
  'pm', 'beginner', 'qa', 'risk', 'security', 'support', 'reviewer', 'ops', 'non_goal', 'term',
92
92
  ];
@@ -114,7 +114,7 @@ const kvChildren = (node) => {
114
114
  const childBlock = (node, kw) => node.children.find((c) => firstWord(c.text) === kw);
115
115
 
116
116
  function parseFields(node) {
117
- // "key: Type" lines. A field may carry indented modifiers and IntentLens notes.
117
+ // "key: Type" lines. A field may carry indented modifiers and ThunderLens notes.
118
118
  return node.children.map((c) => {
119
119
  const m = c.text.match(/^([A-Za-z_][\w]*)\s*:\s*(.+)$/);
120
120
  const modifiers = [];
@@ -712,7 +712,7 @@ export function parseIntent(source) {
712
712
  }
713
713
  }
714
714
 
715
- // ── Assemble IntentLens notes with stable ids, target kinds, paths, spans ──
715
+ // ── Assemble ThunderLens notes with stable ids, target kinds, paths, spans ──
716
716
  const mprefix = `mission.${ast.mission || 'unnamed'}`;
717
717
  const pushNote = (raw, targetKind, targetPath) => {
718
718
  if (!raw) return;
@@ -1,5 +1,5 @@
1
1
  // Canonical proof envelope schema (intent-proof-v1) , the shape of a `.intent-proof.json`
2
- // document. IL owns this: it is what the compiler emits (`buildProof`), what `intent verify`
2
+ // document. IL owns this: it is what the compiler emits (`buildProof`), what `thunder verify`
3
3
  // re-derives against, and the "shared envelope" siblings sign (STW) and re-verify (RM/OT)
4
4
  // rather than each re-describing the proof shape. Pure ESM, ZERO Node deps , browser-safe so
5
5
  // a signing service or a cert renderer can validate an envelope without a Node build.
@@ -41,7 +41,7 @@ export function intentProofJsonSchema() {
41
41
  sourceProduct: { type: 'string' },
42
42
  missionName: { type: ['string', 'null'] },
43
43
  sourceFile: { type: 'string' },
44
- // sha256:<hex> , the source fingerprint `intent verify` re-checks for drift/tampering.
44
+ // sha256:<hex> , the source fingerprint `thunder verify` re-checks for drift/tampering.
45
45
  sourceHash: { type: 'string', pattern: '^sha256:[0-9a-f]{64}$' },
46
46
  compilerVersion: { type: 'string' },
47
47
  generatedAt: { type: ['string', 'null'] },
package/src/report.mjs CHANGED
@@ -1,4 +1,4 @@
1
- // Repo-wide intent health report (intent-report-v1). `intent check` gates a build pass/fail;
1
+ // Repo-wide intent health report (intent-report-v1). `thunder check` gates a build pass/fail;
2
2
  // this AGGREGATES across every .intent file into a triage view a team adopting ThunderLang can
3
3
  // act on: how many missions, diagnostics by severity + area, the most common codes, and
4
4
  // coverage signals (are guarantees verified? do missions have tests? are outcomes contracted?).
package/src/sarif.mjs CHANGED
@@ -1,4 +1,4 @@
1
- // SARIF 2.1.0 output for `intent check` , so ThunderLang diagnostics show up natively in the
1
+ // SARIF 2.1.0 output for `thunder check` , so ThunderLang diagnostics show up natively in the
2
2
  // surfaces teams already use: GitHub / GitLab code scanning (inline PR annotations + the
3
3
  // Security tab) and any SARIF-aware IDE. Pure: reports in, one SARIF log object out.
4
4
  //
@@ -1,5 +1,5 @@
1
1
  // Scanner query views (intent-scan-view-v1) , the deterministic answers behind the Part 3
2
- // CLI verbs: `intent risks | gaps | unverified | coverage | unknowns | contradictions`.
2
+ // CLI verbs: `thunder risks | gaps | unverified | coverage | unknowns | contradictions`.
3
3
  // These are pure derivations over a scanProject() result (its Intent IR + Fable findings) ,
4
4
  // no new analysis, no AI. They exist so a person can ask one focused question ("what is
5
5
  // unverified?", "what contradicts?") instead of reading the whole scan report.
package/src/style.mjs CHANGED
@@ -85,7 +85,7 @@ function setPath(root, path, leaf) {
85
85
  /**
86
86
  * Deterministic diagnostics for every `style_intent` block. Returns an array of
87
87
  * { ruleId, severity, blocks, message, styleIntent, line } , the same shape the rest of
88
- * the compiler emits, so it composes into `intent check` with no special-casing.
88
+ * the compiler emits, so it composes into `thunder check` with no special-casing.
89
89
  */
90
90
  export function styleDiagnostics(ast) {
91
91
  const out = [];
@@ -199,7 +199,7 @@ export function toDesignTokens(ast) {
199
199
  });
200
200
  for (const t of si.tokens) {
201
201
  const leaf = { $value: coerceValue(t.value), $type: tokenType(t.path) };
202
- if (!isKnownPath(t.path)) leaf.$extensions = { 'dev.thunderlang': { canonical: false } };
202
+ if (!isKnownPath(t.path)) leaf.$extensions = { 'dev.intentlanguage': { canonical: false } };
203
203
  setPath(root, t.path, leaf);
204
204
  }
205
205
  }
@@ -207,7 +207,7 @@ export function toDesignTokens(ast) {
207
207
  $description: `Design tokens for ${ast.title || ast.mission || 'intent'} (generated from style_intent by @skillstech/thunderlang)`,
208
208
  ...root,
209
209
  $extensions: {
210
- 'dev.thunderlang': {
210
+ 'dev.intentlanguage': {
211
211
  schema: DESIGN_TOKENS_SCHEMA,
212
212
  format: 'W3C Design Tokens (DTCG)',
213
213
  source: ast.mission || null,
@@ -9,7 +9,7 @@
9
9
  //
10
10
  // Verdicts: 'satisfied' | 'partial' | 'absent'. Score = (satisfied + 0.5*partial) / 13.
11
11
  // Each factor cites the IL signal it inspects, the evidence found, and a concrete fix. The
12
- // finding ids (IL-12F-01..13) are in the canonical rule catalog for `intent explain`.
12
+ // finding ids (IL-12F-01..13) are in the canonical rule catalog for `thunder explain`.
13
13
 
14
14
  export const TWELVE_FACTOR_SCHEMA = 'twelve-factor-v1';
15
15
 
@@ -44,7 +44,7 @@ const FACTORS = [
44
44
  const scoped = len(ast.scope?.include) + len(ast.scope?.exclude);
45
45
  if (scoped) return { verdict: 'satisfied', evidence: `context boundary declared (scope: ${len(ast.scope.include)} include / ${len(ast.scope.exclude)} exclude)` };
46
46
  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.' };
47
- return { verdict: 'absent', evidence: 'no scope declared', fix: 'Add a `scope` block to bound what belongs in context (IntentLens/Focus narrows it further).' };
47
+ return { verdict: 'absent', evidence: 'no scope declared', fix: 'Add a `scope` block to bound what belongs in context (ThunderLens/Focus narrows it further).' };
48
48
  },
49
49
  },
50
50
  {