@adia-ai/adia-ui-factory 0.2.4 → 0.8.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.
Files changed (144) hide show
  1. package/.claude-plugin/plugin.json +5 -7
  2. package/.mcp.json +1 -1
  3. package/CHANGELOG.md +27 -67
  4. package/README.md +32 -53
  5. package/agents/app-architect.md +28 -0
  6. package/agents/routing-corpus.json +202 -0
  7. package/agents/screen-composer.md +27 -0
  8. package/bin/adia-lint +17 -2
  9. package/commands/adia-genui.md +5 -8
  10. package/commands/adia-migrate.md +5 -6
  11. package/commands/adia-orient.md +5 -10
  12. package/commands/adia-scaffold.md +7 -13
  13. package/commands/adia-verify.md +5 -6
  14. package/package.json +5 -6
  15. package/references/a2ui-mcp-tools.md +11 -8
  16. package/references/authoring-components.md +25 -1
  17. package/references/component-model.md +52 -4
  18. package/references/contracts/a2ui-mcp-surface.md +35 -0
  19. package/references/contracts/migration-guide-format.md +34 -0
  20. package/references/data-and-hydration.md +8 -5
  21. package/references/genui-a2ui.md +12 -6
  22. package/references/llm.md +22 -39
  23. package/references/migration.md +110 -36
  24. package/references/project-shapes.md +11 -13
  25. package/references/shell-admin.md +5 -2
  26. package/references/shell-chat.md +5 -3
  27. package/references/shell-editor.md +1 -1
  28. package/references/shell-embed.md +40 -26
  29. package/references/shell-simple.md +5 -2
  30. package/references/spa-architecture.md +28 -73
  31. package/references/ssr-integration.md +1 -1
  32. package/references/verification.md +8 -12
  33. package/skills/adia-compose/SKILL.md +52 -0
  34. package/skills/{adia-ui-kit → adia-compose}/assets/figma-make/guidelines/Guidelines.md +3 -3
  35. package/skills/{adia-ui-kit → adia-compose}/assets/figma-make/guidelines/components.md +1 -1
  36. package/skills/{adia-ui-kit → adia-compose}/assets/figma-make/guidelines/styles.md +1 -1
  37. package/skills/{adia-ui-kit → adia-compose}/assets/figma-make/guidelines/tokens.md +3 -3
  38. package/skills/{adia-ui-kit → adia-compose}/assets/templates/FEEDBACK.template.md +7 -7
  39. package/skills/{adia-ui-kit → adia-compose}/assets/templates/RESPONSE.template.md +6 -7
  40. package/skills/adia-compose/references/composition-traps.md +58 -0
  41. package/skills/adia-compose/references/feedback-discipline.md +20 -0
  42. package/skills/adia-compose/references/spec-to-ui-reasoning.md +158 -0
  43. package/skills/adia-data/SKILL.md +78 -0
  44. package/skills/adia-genui/SKILL.md +83 -0
  45. package/skills/adia-host/SKILL.md +119 -0
  46. package/skills/adia-llm/SKILL.md +36 -0
  47. package/skills/adia-migrate/SKILL.md +76 -0
  48. package/skills/adia-orient/SKILL.md +123 -0
  49. package/skills/adia-project/SKILL.md +83 -0
  50. package/skills/adia-shells/SKILL.md +74 -0
  51. package/skills/adia-verify/SKILL.md +43 -0
  52. package/skills/adia-verify/references/verification.md +42 -0
  53. package/commands/adia-compose.md +0 -10
  54. package/commands/adia-wire.md +0 -13
  55. package/skills/adia-ui-compose/SKILL.md +0 -57
  56. package/skills/adia-ui-data/SKILL.md +0 -62
  57. package/skills/adia-ui-factory/SKILL.md +0 -113
  58. package/skills/adia-ui-genui/SKILL.md +0 -74
  59. package/skills/adia-ui-kit/CHANGELOG.md +0 -41
  60. package/skills/adia-ui-kit/SKILL.md +0 -442
  61. package/skills/adia-ui-kit/assets/team-scaffold/archive-README.md +0 -30
  62. package/skills/adia-ui-kit/assets/team-scaffold/drafts-README.md +0 -57
  63. package/skills/adia-ui-kit/assets/team-scaffold/inbox-README.md +0 -76
  64. package/skills/adia-ui-kit/assets/team-scaffold/outbox-README.md +0 -46
  65. package/skills/adia-ui-kit/assets/team-scaffold/team-root.README.md +0 -51
  66. package/skills/adia-ui-kit/assets/team-scaffold/tickets-README.md +0 -208
  67. package/skills/adia-ui-kit/assets/team-scaffold/tickets-REGISTRY.md +0 -81
  68. package/skills/adia-ui-kit/assets/templates/AGENTS.template.md +0 -128
  69. package/skills/adia-ui-kit/assets/templates/CLAUDE.template.md +0 -1
  70. package/skills/adia-ui-kit/assets/templates/figma-make-guidelines.md +0 -90
  71. package/skills/adia-ui-kit/evals/adversarial-content-trust.json +0 -83
  72. package/skills/adia-ui-kit/evals/evals.json +0 -55
  73. package/skills/adia-ui-kit/evals/routing-corpus.json +0 -121
  74. package/skills/adia-ui-kit/evals/teach-routing-cases.json +0 -92
  75. package/skills/adia-ui-kit/references/capabilities.md +0 -245
  76. package/skills/adia-ui-kit/references/catalog-lookup.md +0 -186
  77. package/skills/adia-ui-kit/references/changelog-archive/CHANGELOG-v1.md +0 -8
  78. package/skills/adia-ui-kit/references/changelog-archive/CHANGELOG-v2.md +0 -3585
  79. package/skills/adia-ui-kit/references/changelog-archive/CHANGELOG-v3.md +0 -1899
  80. package/skills/adia-ui-kit/references/common-gotchas-consumer.md +0 -522
  81. package/skills/adia-ui-kit/references/component-literacy.md +0 -291
  82. package/skills/adia-ui-kit/references/composition.md +0 -245
  83. package/skills/adia-ui-kit/references/correction-loop.md +0 -462
  84. package/skills/adia-ui-kit/references/css-policy.md +0 -343
  85. package/skills/adia-ui-kit/references/decision-model.md +0 -158
  86. package/skills/adia-ui-kit/references/diagnostic-output.md +0 -57
  87. package/skills/adia-ui-kit/references/docs-catalog.md +0 -239
  88. package/skills/adia-ui-kit/references/exclusions.md +0 -225
  89. package/skills/adia-ui-kit/references/feedback-authoring.md +0 -466
  90. package/skills/adia-ui-kit/references/figma-make.md +0 -244
  91. package/skills/adia-ui-kit/references/flows-auth.md +0 -307
  92. package/skills/adia-ui-kit/references/flows-content.md +0 -206
  93. package/skills/adia-ui-kit/references/flows-data.md +0 -348
  94. package/skills/adia-ui-kit/references/flows-interaction.md +0 -181
  95. package/skills/adia-ui-kit/references/flows-shells.md +0 -336
  96. package/skills/adia-ui-kit/references/gap-detection.md +0 -266
  97. package/skills/adia-ui-kit/references/harness.md +0 -284
  98. package/skills/adia-ui-kit/references/loading-protocol.md +0 -406
  99. package/skills/adia-ui-kit/references/local-link.md +0 -198
  100. package/skills/adia-ui-kit/references/mcp.md +0 -401
  101. package/skills/adia-ui-kit/references/migration.md +0 -116
  102. package/skills/adia-ui-kit/references/mission.md +0 -194
  103. package/skills/adia-ui-kit/references/mode-routing.md +0 -298
  104. package/skills/adia-ui-kit/references/patterns-agent.md +0 -223
  105. package/skills/adia-ui-kit/references/patterns-data.md +0 -1065
  106. package/skills/adia-ui-kit/references/patterns-forms.md +0 -223
  107. package/skills/adia-ui-kit/references/patterns-layout.md +0 -326
  108. package/skills/adia-ui-kit/references/patterns-recipes.md +0 -1416
  109. package/skills/adia-ui-kit/references/patterns-shells.md +0 -1097
  110. package/skills/adia-ui-kit/references/patterns-traits.md +0 -259
  111. package/skills/adia-ui-kit/references/patterns-wiring.md +0 -339
  112. package/skills/adia-ui-kit/references/pev-rationale.md +0 -137
  113. package/skills/adia-ui-kit/references/reasoning-gate.md +0 -146
  114. package/skills/adia-ui-kit/references/reasoning-methodologies.md +0 -112
  115. package/skills/adia-ui-kit/references/recon.md +0 -192
  116. package/skills/adia-ui-kit/references/rendering-model.md +0 -431
  117. package/skills/adia-ui-kit/references/response-authoring.md +0 -398
  118. package/skills/adia-ui-kit/references/session-log-schema.md +0 -203
  119. package/skills/adia-ui-kit/references/session-log-template.md +0 -118
  120. package/skills/adia-ui-kit/references/setup.md +0 -652
  121. package/skills/adia-ui-kit/references/skill-hygiene.md +0 -135
  122. package/skills/adia-ui-kit/references/spec-to-ui-reasoning.md +0 -394
  123. package/skills/adia-ui-kit/references/state.md +0 -229
  124. package/skills/adia-ui-kit/references/teach-protocol.md +0 -421
  125. package/skills/adia-ui-kit/references/theme.md +0 -142
  126. package/skills/adia-ui-kit/references/version-check.md +0 -69
  127. package/skills/adia-ui-kit/scripts/audit-decision-trace.mjs +0 -198
  128. package/skills/adia-ui-kit/scripts/audit-kit-roster.mjs +0 -366
  129. package/skills/adia-ui-kit/scripts/changelog-archive.mjs +0 -126
  130. package/skills/adia-ui-kit/scripts/check-adia-versions.py +0 -404
  131. package/skills/adia-ui-kit/scripts/run-skill-evals.mjs +0 -358
  132. package/skills/adia-ui-kit/scripts/validate-session-log.mjs +0 -242
  133. package/skills/adia-ui-kit/skill.json +0 -102
  134. package/skills/adia-ui-llm/SKILL.md +0 -51
  135. package/skills/adia-ui-migrate/SKILL.md +0 -64
  136. package/skills/adia-ui-migration/CHANGELOG.md +0 -47
  137. package/skills/adia-ui-migration/SKILL.md +0 -381
  138. package/skills/adia-ui-migration/skill.json +0 -29
  139. package/skills/adia-ui-project/SKILL.md +0 -77
  140. package/skills/adia-ui-shells/SKILL.md +0 -62
  141. package/skills/adia-ui-spa/SKILL.md +0 -52
  142. package/skills/adia-ui-ssr/SKILL.md +0 -52
  143. package/skills/adia-ui-verify/SKILL.md +0 -44
  144. /package/skills/{adia-ui-kit → adia-compose}/assets/templates/FEEDBACK-OMISSIONS-DEFENSE.template.md +0 -0
@@ -1,142 +0,0 @@
1
- ---
2
- name: theme
3
- load-when: When customizing theme — color schemes, density, brand colors, custom themes, toggle-scheme, Cmd+K command palette
4
- load-size-tokens: ~1,200
5
- required-for:
6
- - theme customization
7
- - brand integration
8
- ---
9
-
10
- # §Theme — Color scheme, density, custom themes
11
-
12
- AdiaUI ships a three-knob theming contract. All themes are CSS-only,
13
- no runtime JS required.
14
-
15
- ### Three knobs
16
-
17
- | Knob | What it controls | How to set |
18
- |---|---|---|
19
- | **Named theme** | Token palette (`[theme="ocean"]` swaps `--a-*` values) | `<html theme="ocean">` |
20
- | **Color scheme** | Light / dark within a theme | `<html style="color-scheme: light">` or use `<toggle-scheme-ui>` |
21
- | **Density / radius** | `--a-density` (0–1), `--a-radius-k` (multiplier) | inline `style` or `[data-density="cozy"]` |
22
-
23
- Eight named themes ship by default (`default`, `ocean`, `forest`, `sunset`,
24
- `graphite`, `paper`, `ink`, `neon`). Add `theme="<slug>"` to `<html>` or
25
- any ancestor element to apply.
26
-
27
- ### Add a scheme toggle (light/dark)
28
-
29
- ```html
30
- <!-- One-line scheme toggle, persists to localStorage -->
31
- <toggle-scheme-ui scheme="auto"></toggle-scheme-ui>
32
- ```
33
-
34
- > **Placement.** Put `<toggle-scheme-ui>` in the shell topbar's trailing
35
- > `slot="action"` cluster — inside `<admin-topbar slot="header">` of
36
- > `<admin-content>`. That is the persistent top-right home for app-wide
37
- > preference controls. Do **not** put it in the sidebar footer: a global
38
- > preference buried there reads as navigation and vanishes when the
39
- > sidebar collapses.
40
-
41
- The component:
42
- - Reads `prefers-color-scheme` for `auto`
43
- - Writes the resolved scheme to `<html style="color-scheme: ...">`
44
- - Persists to `localStorage` under the `adia-theme-` namespace
45
- - Swaps moon/sun icon automatically
46
-
47
- Attributes: `scheme="auto|light|dark"`, `target="<selector>"` (default `:root`).
48
-
49
- ```js
50
- // Listen for scheme changes
51
- document.querySelector('toggle-scheme-ui').addEventListener('scheme-change', e => {
52
- console.log('new scheme:', e.detail.scheme); // 'light' | 'dark'
53
- });
54
- ```
55
-
56
- ### Full theme panel (settings page)
57
-
58
- `<theme-panel>` exposes all three knobs in one composition. Drop into a
59
- settings section or popover.
60
-
61
- ```html
62
- <popover-ui>
63
- <button-ui slot="trigger" icon="palette" variant="ghost"></button-ui>
64
- <theme-panel slot="content"
65
- parametric
66
- presets
67
- scheme-toggle>
68
- </theme-panel>
69
- </popover-ui>
70
- ```
71
-
72
- Imports (not in barrel — composes 5 primitives):
73
-
74
- ```js
75
- import '@adia-ai/web-components/components/toggle-scheme/toggle-scheme.js';
76
- import '@adia-ai/web-modules/theme/theme-panel/theme-panel.js';
77
- ```
78
-
79
- ### Brand-color overrides
80
-
81
- To override the brand palette without a full custom theme, write a small
82
- CSS block that targets the semantic tokens:
83
-
84
- ```css
85
- /* main.css — after `@adia-ai/web-components/css` */
86
- :root {
87
- --a-primary-bg: #3b82f6; /* your brand blue */
88
- --a-primary-fg: white;
89
- --a-primary-strong: #1d4ed8;
90
- --a-accent-bg: #ec4899; /* your accent pink */
91
- --a-accent-fg: white;
92
- }
93
-
94
- /* Dark scheme override */
95
- :root[style*="color-scheme: dark"] {
96
- --a-primary-bg: #60a5fa;
97
- --a-primary-strong: #93c5fd;
98
- }
99
- ```
100
-
101
- Only override semantic tokens (`--a-*-bg`, `--a-*-fg`, `--a-*-strong`).
102
- Never override component-internal tokens (`--button-ui-padding`, etc.) —
103
- those are implementation details and will break with version bumps.
104
-
105
- ### Custom theme (`[theme="my-brand"]`)
106
-
107
- For a full custom palette across many tokens, define a theme block:
108
-
109
- ```css
110
- /* themes/my-brand.css */
111
- [theme="my-brand"] {
112
- /* Surface */
113
- --a-bg: hsl(220 20% 99%);
114
- --a-bg-muted: hsl(220 20% 96%);
115
- --a-bg-strong: hsl(220 20% 92%);
116
- --a-fg: hsl(220 30% 12%);
117
- --a-fg-subtle: hsl(220 15% 45%);
118
-
119
- /* Chrome / borders */
120
- --a-chrome-strong: hsl(220 15% 80%);
121
- --a-chrome-bg: hsl(220 15% 90%);
122
-
123
- /* Primary / accent / danger / success / warning / info */
124
- --a-primary-bg: hsl(252 100% 60%);
125
- --a-primary-fg: white;
126
- --a-accent-bg: hsl(340 80% 55%);
127
- /* ... */
128
- }
129
-
130
- [theme="my-brand"][style*="color-scheme: dark"] {
131
- --a-bg: hsl(220 30% 8%);
132
- /* ... */
133
- }
134
- ```
135
-
136
- Apply with `<html theme="my-brand">`.
137
-
138
- > **Token reference:** see `node_modules/@adia-ai/web-components/styles/tokens.css`
139
- > for the full semantic-token surface. Roughly 80 tokens across surfaces,
140
- > chrome, semantic colors, spacing, radius, and motion.
141
-
142
- ---
@@ -1,69 +0,0 @@
1
- ---
2
- name: version-check
3
- load-when: Before any authoring — verifies that the installed `@adia-ai/*` version matches the kit's targeted shape (current lockstep is v0.6.33)
4
- load-size-tokens: ~750
5
- required-for:
6
- - cold-start version sanity
7
- - pre-author bundle gate companion
8
- ---
9
-
10
- # §VersionCheck — Verify the install matches what the skill describes
11
-
12
- **Why this gate exists.** The 9 `@adia-ai/*` packages ship in lockstep,
13
- and skill guidance is version-sensitive. Before trusting a stale install,
14
- run:
15
-
16
- ```bash
17
- scripts/check-adia-versions.py
18
- ```
19
-
20
- (Path relative to the consumer project that has this skill installed.
21
- If running from another consumer, pass `--root /path/to/consumer`.)
22
-
23
- The script reports three sources side-by-side: **installed**
24
- (node_modules), **declared** (package.json), **latest** (npm registry).
25
- It classifies drift and exits non-zero when something needs attention.
26
-
27
- **Exit codes**
28
-
29
- - `0` — install is clean: lockstep aligned, declarations match installs,
30
- and installed ≥ latest published (or you used `--offline`).
31
- - `1` — drift detected. The text output names every package + suggests
32
- the fix (`npm install @adia-ai/X@latest`, `npm install`, or wipe +
33
- reinstall to repair split lockstep).
34
- - `2` — unrecoverable (no `package.json` or no `node_modules` at root).
35
-
36
- **Status legend**
37
-
38
- | Marker | Meaning | Fix |
39
- |---|---|---|
40
- | ✓ ok | installed == declared, matches latest | — |
41
- | ⚠ stale | installed < latest published | `npm install @adia-ai/<pkg>@latest` |
42
- | ⚠ split | lockstep broken — packages disagree on version | wipe `node_modules` + lockfile, reinstall |
43
- | ⚠ undeclared | user-facing package installed but not in package.json | add to `dependencies` |
44
- | ⚠ uninstalled | declared but missing from node_modules | `npm install` |
45
- | ⓘ ahead | installed > latest published (dev cut / local tarball) | informational, not an error |
46
-
47
- **Flags**
48
-
49
- - `--offline` — skip `npm view` (no network). Still verifies lockstep
50
- + declared vs. installed; just can't tell you about staleness.
51
- - `--json` — machine-readable for agent harnesses.
52
- - `--root <path>` — explicit consumer root (default: cwd).
53
-
54
- **When to run it**
55
-
56
- - Once at the start of any new project work (cold-start gate).
57
- - After any `npm install` or `npm update` involving `@adia-ai/*`.
58
- - Before filing a feedback ticket — version coherence is required
59
- evidence (see §FeedbackDiscipline principle 4 "verify before
60
- claiming").
61
- - When a piece of skill guidance contradicts your install (the script
62
- tells you which side is stale).
63
-
64
- **Monorepo-root behavior.** The script auto-detects the `@adia-ai/*`
65
- source monorepo via the `workspaces` field and suppresses "undeclared"
66
- warnings there. The "ⓘ ahead" status is expected in the monorepo when
67
- sources are bumped but not yet published.
68
-
69
- ---
@@ -1,198 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * audit-decision-trace.mjs (adia-ui-kit v3.1.0+)
4
- *
5
- * Walks a JSONL session log (per references/session-log-schema.md) and
6
- * audits component-trace coverage: every component_named event should
7
- * trace to ≥1 decision_made event whose possible_actions array contains
8
- * (or whose chosen_action equals) the named component.
9
- *
10
- * Per REFACTOR-SPEC P5(b). See references/decision-model.md for the
11
- * contract.
12
- *
13
- * Default mode: --advisory — prints findings + summary; exit 0 even if
14
- * orphans found (advisory rollout — collecting baseline for v3.2.0
15
- * promotion to hard-fail).
16
- *
17
- * Strict mode: --strict — exits 1 on any orphan finding.
18
- *
19
- * Usage:
20
- * node audit-decision-trace.mjs <session-log.jsonl>
21
- * node audit-decision-trace.mjs <session-log.jsonl> --strict
22
- * node audit-decision-trace.mjs <session-log.jsonl> --json
23
- * node audit-decision-trace.mjs <session-log.jsonl> --allowlist=path/to/.decision-trace-allowlist.json
24
- */
25
-
26
- import fs from 'node:fs';
27
- import path from 'node:path';
28
- import process from 'node:process';
29
- import { fileURLToPath } from 'node:url';
30
-
31
- const __filename = fileURLToPath(import.meta.url);
32
- const SCRIPT_DIR = path.dirname(__filename);
33
- const KIT_DIR = path.dirname(SCRIPT_DIR);
34
-
35
- function loadAllowlist(allowlistPath) {
36
- if (!allowlistPath) return new Set();
37
- if (!fs.existsSync(allowlistPath)) return new Set();
38
- try {
39
- const obj = JSON.parse(fs.readFileSync(allowlistPath, 'utf8'));
40
- return new Set((obj.allowed_orphans || []).map(e => e.tag));
41
- } catch (err) {
42
- console.error(`⚠ Could not parse allowlist ${allowlistPath}: ${err.message}`);
43
- return new Set();
44
- }
45
- }
46
-
47
- function readJsonlEvents(logPath) {
48
- const content = fs.readFileSync(logPath, 'utf8');
49
- const lines = content.split('\n').filter(l => l.trim().length > 0);
50
- const events = [];
51
- lines.forEach((line, idx) => {
52
- try {
53
- events.push({ ...JSON.parse(line), _line: idx + 1 });
54
- } catch {
55
- // skip malformed lines (validate-session-log surfaces them separately)
56
- }
57
- });
58
- return events;
59
- }
60
-
61
- function extractDecisionsAndComponents(events) {
62
- const decisions = events.filter(e => e.event_type === 'decision_made');
63
- const components = events.filter(e => e.event_type === 'component_named');
64
- return { decisions, components };
65
- }
66
-
67
- /**
68
- * Normalize an action string to a canonical component tag.
69
- * Examples:
70
- * "button-ui variant=primary [type=submit] [loading]" → "button-ui"
71
- * "input-ui type=email" → "input-ui"
72
- * "form-field with input-ui" → "form-field" (and also matches "input-ui")
73
- * "none (raw)" → "none" (sentinel)
74
- */
75
- function extractTagsFromAction(action) {
76
- if (!action || typeof action !== 'string') return [];
77
- // Match anything that looks like a component tag (lowercase-with-hyphens, ending in -ui or known suffix or containing -)
78
- const tagPattern = /\b([a-z][a-z0-9]*(?:-[a-z0-9]+)+)\b/g;
79
- const tags = new Set();
80
- let m;
81
- while ((m = tagPattern.exec(action)) !== null) {
82
- tags.add(m[1]);
83
- }
84
- return [...tags];
85
- }
86
-
87
- function auditTrace(events, allowlist) {
88
- const { decisions, components } = extractDecisionsAndComponents(events);
89
-
90
- // Build the universe of tags traced to any decision (possible_actions ∪ chosen_action)
91
- const tracedTags = new Set();
92
- for (const d of decisions) {
93
- const p = d.payload || {};
94
- const actions = Array.isArray(p.possible_actions) ? p.possible_actions : [];
95
- for (const action of actions) {
96
- for (const tag of extractTagsFromAction(action)) {
97
- tracedTags.add(tag);
98
- }
99
- }
100
- if (p.chosen_action) {
101
- for (const tag of extractTagsFromAction(p.chosen_action)) {
102
- tracedTags.add(tag);
103
- }
104
- }
105
- }
106
-
107
- // Walk component_named events; flag any tag not in tracedTags ∪ allowlist
108
- const findings = [];
109
- const allTagsObserved = new Set();
110
- for (const c of components) {
111
- const tag = c.payload?.tag;
112
- if (!tag) continue;
113
- allTagsObserved.add(tag);
114
- if (tracedTags.has(tag)) continue;
115
- if (allowlist.has(tag)) continue;
116
- findings.push({
117
- line: c._line,
118
- severity: 'orphan',
119
- tag,
120
- session_id: c.session_id,
121
- context: c.payload?.context || '(no context)',
122
- msg: `Component "${tag}" named at line ${c._line} but no decision_made event lists it in possible_actions or chosen_action, and it's not in the allowlist.`,
123
- });
124
- }
125
-
126
- return {
127
- decision_count: decisions.length,
128
- component_named_count: components.length,
129
- unique_tags_observed: [...allTagsObserved].sort(),
130
- unique_tags_traced: [...tracedTags].sort(),
131
- allowlist_size: allowlist.size,
132
- orphan_count: findings.length,
133
- findings,
134
- };
135
- }
136
-
137
- function main() {
138
- const args = process.argv.slice(2);
139
- const json = args.includes('--json');
140
- const strict = args.includes('--strict');
141
- // Default: advisory
142
- const advisory = args.includes('--advisory') || !strict;
143
- const allowlistArg = args.find(a => a.startsWith('--allowlist='));
144
- const logPath = args.find(a => !a.startsWith('--'));
145
-
146
- if (!logPath) {
147
- console.error('Usage: audit-decision-trace.mjs <session-log.jsonl> [--strict] [--json] [--allowlist=path]');
148
- process.exit(2);
149
- }
150
- if (!fs.existsSync(logPath)) {
151
- console.error(`✗ Session log not found: ${logPath}`);
152
- process.exit(2);
153
- }
154
-
155
- // Try kit-default allowlist if not specified
156
- const defaultAllowlist = path.join(KIT_DIR, '.decision-trace-allowlist.json');
157
- const allowlistPath = allowlistArg
158
- ? allowlistArg.slice('--allowlist='.length)
159
- : (fs.existsSync(defaultAllowlist) ? defaultAllowlist : null);
160
- const allowlist = loadAllowlist(allowlistPath);
161
-
162
- const events = readJsonlEvents(logPath);
163
- const result = auditTrace(events, allowlist);
164
-
165
- const mode = strict ? 'STRICT' : 'ADVISORY';
166
-
167
- if (json) {
168
- console.log(JSON.stringify({ mode, allowlist_path: allowlistPath, ...result }, null, 2));
169
- } else {
170
- console.log(`\n══ audit-decision-trace — ${logPath} ══`);
171
- console.log(`Mode: ${mode}${advisory && !strict ? ' (default: never fails; v3.2.0 may promote to hard-fail — see references/decision-model.md)' : ''}`);
172
- console.log(`Allowlist: ${allowlistPath || '(none)'} (${result.allowlist_size} entries)`);
173
- console.log(`Decisions: ${result.decision_count}`);
174
- console.log(`Components named: ${result.component_named_count}`);
175
- console.log(`Unique tags: ${result.unique_tags_observed.length} observed; ${result.unique_tags_traced.length} traced`);
176
- console.log(`Orphan findings: ${result.orphan_count}`);
177
-
178
- if (result.findings.length > 0) {
179
- console.log(`\nOrphan-component findings (named without traced decision):`);
180
- for (const f of result.findings) {
181
- console.log(` ⚠ line ${f.line}: tag="${f.tag}" context="${f.context}"`);
182
- }
183
- console.log(`\nResolution paths:`);
184
- console.log(` 1. Retroactively add a decision_made event with this tag in possible_actions.`);
185
- console.log(` 2. Add the tag to .decision-trace-allowlist.json with a rationale.`);
186
- console.log(` 3. Remove the orphan component from the composition.`);
187
- } else {
188
- console.log(`\n✓ No orphan-component findings.`);
189
- }
190
- }
191
-
192
- if (strict && result.orphan_count > 0) {
193
- process.exit(1);
194
- }
195
- process.exit(0);
196
- }
197
-
198
- main();