@event4u/agent-config 7.0.2 → 7.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.
Files changed (140) hide show
  1. package/.claude-plugin/marketplace.json +9 -1
  2. package/CHANGELOG.md +117 -0
  3. package/README.md +4 -2
  4. package/dist/agent-src/commands/council/default.md +28 -20
  5. package/dist/agent-src/commands/evals/fix.json +5 -1
  6. package/dist/agent-src/commands/fix/comments.md +101 -0
  7. package/dist/agent-src/commands/fix.md +5 -2
  8. package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +65 -0
  9. package/dist/agent-src/contexts/execution/auto-orchestration-activation.md +68 -0
  10. package/dist/agent-src/contexts/execution/host-capability-manifest.md +68 -0
  11. package/dist/agent-src/contexts/execution/orchestration-benchmark-gate.md +62 -0
  12. package/dist/agent-src/contexts/execution/orchestration-telemetry.md +59 -0
  13. package/dist/agent-src/contexts/execution/roadmap-process-loop.md +8 -3
  14. package/dist/agent-src/contexts/execution/subagent-response-contract.md +56 -0
  15. package/dist/agent-src/contexts/execution/subagent-routing.md +57 -0
  16. package/dist/agent-src/contexts/execution/subagent-spawn-contract.md +54 -0
  17. package/dist/agent-src/contexts/execution/subagent-steering.md +71 -0
  18. package/dist/agent-src/contexts/execution/verify-budget.md +50 -0
  19. package/dist/agent-src/rules/brand-source-of-truth.md +10 -0
  20. package/dist/agent-src/rules/delegation-policy.md +85 -0
  21. package/dist/agent-src/rules/design-fidelity.md +98 -0
  22. package/dist/agent-src/rules/domain-safety-pii.md +22 -0
  23. package/dist/agent-src/rules/legal-safety-floor.md +182 -0
  24. package/dist/agent-src/rules/lethal-trifecta-guard.md +25 -22
  25. package/dist/agent-src/rules/output-discipline.md +85 -0
  26. package/dist/agent-src/rules/telegraph-speak.md +4 -1
  27. package/dist/agent-src/rules/token-budget-discipline.md +94 -0
  28. package/dist/agent-src/scripts/archive_completed_roadmaps.ts +102 -15
  29. package/dist/agent-src/scripts/update_roadmap_progress.ts +30 -3
  30. package/dist/agent-src/skills/accessibility-auditor/SKILL.md +20 -5
  31. package/dist/agent-src/skills/ai-council/SKILL.md +28 -1
  32. package/dist/agent-src/skills/blade-ui/SKILL.md +9 -0
  33. package/dist/agent-src/skills/contract-review/SKILL.md +125 -0
  34. package/dist/agent-src/skills/contract-review/evals/triggers.json +17 -0
  35. package/dist/agent-src/skills/dashboard-design/SKILL.md +21 -5
  36. package/dist/agent-src/skills/design-intelligence/SKILL.md +96 -0
  37. package/dist/agent-src/skills/design-review/SKILL.md +83 -0
  38. package/dist/agent-src/skills/design-system-capture/SKILL.md +234 -0
  39. package/dist/agent-src/skills/design-tokens/SKILL.md +1 -0
  40. package/dist/agent-src/skills/dpa-review/SKILL.md +130 -0
  41. package/dist/agent-src/skills/dpa-review/evals/triggers.json +17 -0
  42. package/dist/agent-src/skills/existing-ui-audit/SKILL.md +15 -4
  43. package/dist/agent-src/skills/fe-design/SKILL.md +98 -16
  44. package/dist/agent-src/skills/flux/SKILL.md +8 -0
  45. package/dist/agent-src/skills/iconography/SKILL.md +1 -0
  46. package/dist/agent-src/skills/laravel/SKILL.md +1 -0
  47. package/dist/agent-src/skills/legal-intake-triage/SKILL.md +128 -0
  48. package/dist/agent-src/skills/legal-intake-triage/evals/triggers.json +17 -0
  49. package/dist/agent-src/skills/legal-practice-profile/SKILL.md +101 -0
  50. package/dist/agent-src/skills/legal-practice-profile/evals/triggers.json +17 -0
  51. package/dist/agent-src/skills/livewire/SKILL.md +8 -0
  52. package/dist/agent-src/skills/nda-triage/SKILL.md +114 -0
  53. package/dist/agent-src/skills/nda-triage/evals/triggers.json +17 -0
  54. package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +21 -9
  55. package/dist/agent-src/skills/reasoning-orchestrator/SKILL.md +3 -1
  56. package/dist/agent-src/skills/recursive-verification/SKILL.md +186 -0
  57. package/dist/agent-src/skills/roadmap-management/SKILL.md +17 -0
  58. package/dist/agent-src/skills/skill-writing/SKILL.md +18 -0
  59. package/dist/agent-src/skills/subagent-orchestration/SKILL.md +11 -0
  60. package/dist/agent-src/skills/tailwind-engineer/SKILL.md +17 -7
  61. package/dist/agent-src/skills/typography-system/SKILL.md +14 -0
  62. package/dist/agent-src/skills/ui-component-architect/SKILL.md +9 -0
  63. package/dist/agent-src/templates/agent-settings.md +64 -19
  64. package/dist/discovery/deprecation-report.md +1 -1
  65. package/dist/discovery/discovery-manifest.json +362 -43
  66. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  67. package/dist/discovery/discovery-manifest.summary.md +13 -5
  68. package/dist/discovery/orphan-report.md +1 -1
  69. package/dist/discovery/packs.json +56 -11
  70. package/dist/discovery/trust-report.md +7 -5
  71. package/dist/discovery/workspaces.json +38 -7
  72. package/dist/mcp/registry-manifest.json +3 -3
  73. package/dist/router.json +1 -1
  74. package/dist/server/routes/wizard.js +4 -3
  75. package/dist/server/routes/wizard.js.map +1 -1
  76. package/dist/server/schemas/settings.js +23 -0
  77. package/dist/server/schemas/settings.js.map +1 -1
  78. package/dist/ui/assets/{index-CoQo90sz.js → index-UjcTG_9O.js} +2 -2
  79. package/dist/ui/assets/index-UjcTG_9O.js.map +1 -0
  80. package/dist/ui/index.html +1 -1
  81. package/docs/RELEASE_STORY_TEMPLATE.md +37 -0
  82. package/docs/architecture.md +4 -4
  83. package/docs/benchmark.md +46 -0
  84. package/docs/catalog.md +18 -6
  85. package/docs/command-flows.md +7 -1
  86. package/docs/contracts/ai-council-config.md +17 -10
  87. package/docs/contracts/audit-log-v1.md +7 -0
  88. package/docs/contracts/auto-orchestration-v1.md +70 -0
  89. package/docs/contracts/capability-boundary.md +64 -0
  90. package/docs/contracts/command-clusters.md +1 -1
  91. package/docs/contracts/discovery-manifest.schema.json +2 -2
  92. package/docs/contracts/package-self-orientation.md +3 -0
  93. package/docs/contracts/subagent-boundary.md +54 -0
  94. package/docs/decisions/ADR-013-discovery-frontmatter-contract.md +32 -0
  95. package/docs/decisions/ADR-020-global-only-consumer-scope.md +13 -6
  96. package/docs/decisions/ADR-049-configuration-trust-boundary.md +11 -1
  97. package/docs/decisions/ADR-093-ai-council-config-user-global.md +10 -4
  98. package/docs/decisions/ADR-104-ai-council-config-global-only.md +119 -0
  99. package/docs/decisions/ADR-105-automatic-subagent-orchestration.md +102 -0
  100. package/docs/decisions/ADR-106-recursive-verification-benchmark-gate.md +126 -0
  101. package/docs/decisions/ADR-107-legal-domain-pack-adoption.md +70 -0
  102. package/docs/decisions/ADR-108-open-source-forever-no-commercial-tier.md +46 -0
  103. package/docs/decisions/INDEX.md +5 -0
  104. package/docs/getting-started.md +2 -2
  105. package/docs/guidelines/agent-infra/domain-eval-anti-pattern.md +53 -0
  106. package/docs/guidelines/agent-infra/domain-pack-architecture.md +56 -0
  107. package/docs/guidelines/design-antipatterns-triggers.json +17 -0
  108. package/docs/guidelines/design-antipatterns.md +170 -0
  109. package/docs/guidelines/design-modes.md +97 -0
  110. package/package.json +1 -1
  111. package/src/config/agent-settings.template.yml +103 -3
  112. package/src/config/discovery/packs.yml +24 -0
  113. package/src/config/discovery/workspaces.yml +7 -0
  114. package/src/scripts/_lib/auto_dispatch.ts +95 -0
  115. package/src/scripts/_lib/host_capability.ts +59 -0
  116. package/src/scripts/_lib/orchestration_gate.ts +98 -0
  117. package/src/scripts/_lib/subagent_bundle.ts +154 -0
  118. package/src/scripts/_lib/subagent_response.ts +82 -0
  119. package/src/scripts/_lib/subagent_routing.ts +81 -0
  120. package/src/scripts/_lib/subagent_spawn.ts +97 -0
  121. package/src/scripts/_lib/subagent_steering.ts +64 -0
  122. package/src/scripts/_lib/verify_budget.ts +54 -0
  123. package/src/scripts/ai_council/advisors.ts +4 -2
  124. package/src/scripts/ai_council/clients.ts +7 -1
  125. package/src/scripts/ai_council/config.ts +22 -17
  126. package/src/scripts/bench_ab_v2_run.ts +127 -0
  127. package/src/scripts/bench_ab_v2_stats.ts +39 -0
  128. package/src/scripts/check_council_config_location.ts +6 -5
  129. package/src/scripts/check_trunk_drift.ts +67 -0
  130. package/src/scripts/lint_design_quality.ts +321 -0
  131. package/src/scripts/lint_discovery_vocabulary.ts +6 -0
  132. package/src/scripts/lint_framework_leakage_allowlist.json +21 -0
  133. package/src/scripts/lint_legal_pack.ts +197 -0
  134. package/src/scripts/lint_output_slop.ts +223 -0
  135. package/src/scripts/lint_pack_risk_class.ts +79 -0
  136. package/src/scripts/probe_projection_fidelity.ts +7 -1
  137. package/src/scripts/schemas/agent-settings.schema.json +23 -0
  138. package/src/scripts/schemas/skill.schema.json +5 -0
  139. package/src/scripts/skill_linter.ts +3 -0
  140. package/dist/ui/assets/index-CoQo90sz.js.map +0 -1
@@ -0,0 +1,223 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * lint_output_slop — detect banned placeholder-prose patterns in generated
4
+ * code and UI output. Six zero-false-positive rules; exit 2 on any finding.
5
+ *
6
+ * Scans: src/skills/**\/SKILL.md, src/rules/*.md, docs/guidelines/*.md
7
+ * (i.e., the package's own authored artifacts). Consumer projects should
8
+ * run this against their own src/ directories.
9
+ *
10
+ * Rules (all zero-false-positive in the package tree):
11
+ * P1 lorem-ipsum — Lorem ipsum / dolor sit amet filler text
12
+ * P2 bracket-placeholder — [Your ... here], <YourComponentName> patterns
13
+ * P3 impl-placeholder — // rest of component, // ... (unchanged), etc.
14
+ * P4 for-brevity — "for brevity" inside code content
15
+ * P5 ellipsis-trunc — … or ... as standalone code-continuation markers
16
+ * P6 todo-implement — // TODO.*implement (unimplemented stubs)
17
+ *
18
+ * Inline-ignore: add a comment on the same or previous line:
19
+ * lint-output-slop-disable-next-line <rule-id> [-- reason]
20
+ * lint-output-slop-disable-line <rule-id> [-- reason]
21
+ * lint-output-slop-disable-file <rule-id> [-- reason] (top of file)
22
+ *
23
+ * Exit codes: 0 = clean, 2 = findings present, 1 = internal error.
24
+ */
25
+ import fs from "node:fs";
26
+ import path from "node:path";
27
+ import { fileURLToPath } from "node:url";
28
+
29
+ const _HERE = path.dirname(fileURLToPath(import.meta.url));
30
+ const REPO_ROOT = path.resolve(_HERE, "..", "..");
31
+
32
+ interface Finding {
33
+ rule: string;
34
+ file: string;
35
+ line: number;
36
+ snippet: string;
37
+ }
38
+
39
+ // ---------------------------------------------------------------------------
40
+ // Rule definitions — each is (id, label, regex-on-a-line-of-content)
41
+ // We only scan INSIDE fenced code blocks in markdown, and in plain .ts/.tsx
42
+ // source files. This prevents false positives from inline-ignore comments,
43
+ // documentation paragraphs, or test descriptions.
44
+ // ---------------------------------------------------------------------------
45
+ const RULES: Array<{ id: string; label: string; pattern: RegExp }> = [
46
+ {
47
+ id: "lorem-ipsum",
48
+ label: "Filler text: Lorem ipsum / dolor sit amet",
49
+ pattern: /Lorem\s+ipsum|dolor\s+sit\s+amet/i,
50
+ },
51
+ {
52
+ id: "bracket-placeholder",
53
+ label: "Bracket placeholder: [Your ... here] or <YourComponentName>",
54
+ pattern: /\[Your\s+\w[\w\s]*here\]|<Your\w+Name>/,
55
+ },
56
+ {
57
+ id: "impl-placeholder",
58
+ label: "Implementation placeholder: // rest of component / // ... (unchanged)",
59
+ pattern:
60
+ /\/\/\s*(rest\s+of\s+(component|implementation|code)|\.{3}\s*\(unchanged\)|same\s+pattern\s+follows)/i,
61
+ },
62
+ {
63
+ id: "for-brevity",
64
+ label: "Truncation excuse: 'for brevity' inside code",
65
+ pattern: /\/\/.*for\s+brevity|\/\*.*for\s+brevity.*\*\//i,
66
+ },
67
+ {
68
+ id: "ellipsis-trunc",
69
+ label: "Ellipsis-as-truncation: standalone … (Unicode) as a continuation placeholder",
70
+ // Match lines that are ONLY a Unicode ellipsis character (not `// ...`
71
+ // which is a legitimate code-documentation shorthand in SKILL.md examples).
72
+ pattern: /^\s*…\s*$/,
73
+ },
74
+ {
75
+ id: "todo-implement",
76
+ label: "Unimplemented stub: // TODO.*implement",
77
+ pattern: /\/\/\s*TODO[:\s].*implement/i,
78
+ },
79
+ ];
80
+
81
+ // ---------------------------------------------------------------------------
82
+ // File discovery
83
+ // ---------------------------------------------------------------------------
84
+ function* walkDir(dir: string, ext: RegExp): Generator<string> {
85
+ if (!fs.existsSync(dir)) return;
86
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
87
+ const full = path.join(dir, entry.name);
88
+ if (entry.isDirectory()) {
89
+ yield* walkDir(full, ext);
90
+ } else if (ext.test(entry.name)) {
91
+ yield full;
92
+ }
93
+ }
94
+ }
95
+
96
+ function collectFiles(): string[] {
97
+ const files: string[] = [];
98
+ // Package-authored markdown (skills, rules, guidelines)
99
+ for (const f of walkDir(path.join(REPO_ROOT, "src", "skills"), /SKILL\.md$/)) files.push(f);
100
+ for (const f of walkDir(path.join(REPO_ROOT, "src", "rules"), /\.md$/)) files.push(f);
101
+ for (const f of walkDir(path.join(REPO_ROOT, "docs", "guidelines"), /\.md$/)) files.push(f);
102
+ return files;
103
+ }
104
+
105
+ // ---------------------------------------------------------------------------
106
+ // Inline-ignore parsing
107
+ // ---------------------------------------------------------------------------
108
+ type IgnoreScope = "file" | "line" | "next-line";
109
+ interface Ignore {
110
+ scope: IgnoreScope;
111
+ rules: string[]; // empty = all rules
112
+ lineNum?: number;
113
+ }
114
+
115
+ function parseIgnores(lines: string[]): Ignore[] {
116
+ const ignores: Ignore[] = [];
117
+ for (let i = 0; i < lines.length; i++) {
118
+ const line = lines[i] ?? "";
119
+ const fileMatch = /lint-output-slop-disable-file\s*([\w-]+(?:,\s*[\w-]+)*)?/i.exec(line);
120
+ if (fileMatch) {
121
+ const rules = fileMatch[1] ? fileMatch[1].split(",").map((r) => r.trim()) : [];
122
+ ignores.push({ scope: "file", rules });
123
+ }
124
+ const lineMatch = /lint-output-slop-disable-line\s*([\w-]+(?:,\s*[\w-]+)*)?/i.exec(line);
125
+ if (lineMatch) {
126
+ const rules = lineMatch[1] ? lineMatch[1].split(",").map((r) => r.trim()) : [];
127
+ ignores.push({ scope: "line", rules, lineNum: i + 1 });
128
+ }
129
+ const nextMatch = /lint-output-slop-disable-next-line\s*([\w-]+(?:,\s*[\w-]+)*)?/i.exec(line);
130
+ if (nextMatch) {
131
+ const rules = nextMatch[1] ? nextMatch[1].split(",").map((r) => r.trim()) : [];
132
+ ignores.push({ scope: "next-line", rules, lineNum: i + 2 }); // 1-indexed, next line
133
+ }
134
+ }
135
+ return ignores;
136
+ }
137
+
138
+ function isIgnored(ignores: Ignore[], ruleId: string, lineNum: number): boolean {
139
+ for (const ig of ignores) {
140
+ const ruleMatch = ig.rules.length === 0 || ig.rules.includes(ruleId);
141
+ if (!ruleMatch) continue;
142
+ if (ig.scope === "file") return true;
143
+ if (ig.scope === "line" && ig.lineNum === lineNum) return true;
144
+ if (ig.scope === "next-line" && ig.lineNum === lineNum) return true;
145
+ }
146
+ return false;
147
+ }
148
+
149
+ // ---------------------------------------------------------------------------
150
+ // Scanning — only within fenced code blocks in markdown
151
+ // ---------------------------------------------------------------------------
152
+ function scanFile(filePath: string): Finding[] {
153
+ const content = fs.readFileSync(filePath, "utf-8");
154
+ const lines = content.split("\n");
155
+ const ignores = parseIgnores(lines);
156
+ const findings: Finding[] = [];
157
+
158
+ let inCodeBlock = false;
159
+ for (let i = 0; i < lines.length; i++) {
160
+ const lineNum = i + 1;
161
+ const line = lines[i] ?? "";
162
+
163
+ // Toggle code-fence state
164
+ if (/^```/.test(line) || /^~~~/.test(line)) {
165
+ inCodeBlock = !inCodeBlock;
166
+ continue;
167
+ }
168
+
169
+ // Only scan inside code fences in markdown
170
+ if (!inCodeBlock) continue;
171
+
172
+ for (const rule of RULES) {
173
+ if (rule.pattern.test(line) && !isIgnored(ignores, rule.id, lineNum)) {
174
+ findings.push({
175
+ rule: rule.id,
176
+ file: path.relative(REPO_ROOT, filePath),
177
+ line: lineNum,
178
+ snippet: line.trim().slice(0, 120),
179
+ });
180
+ }
181
+ }
182
+ }
183
+ return findings;
184
+ }
185
+
186
+ // ---------------------------------------------------------------------------
187
+ // Main
188
+ // ---------------------------------------------------------------------------
189
+ function main(): void {
190
+ const jsonMode = process.argv.includes("--json");
191
+ const quiet = process.argv.includes("--quiet");
192
+
193
+ const files = collectFiles();
194
+ const allFindings: Finding[] = [];
195
+
196
+ for (const file of files) {
197
+ try {
198
+ allFindings.push(...scanFile(file));
199
+ } catch (err) {
200
+ if (!quiet) process.stderr.write(`[lint_output_slop] error reading ${file}: ${err}\n`);
201
+ }
202
+ }
203
+
204
+ if (jsonMode) {
205
+ process.stdout.write(JSON.stringify(allFindings, null, 2) + "\n");
206
+ process.exit(allFindings.length > 0 ? 2 : 0);
207
+ }
208
+
209
+ if (allFindings.length === 0) {
210
+ if (!quiet) process.stdout.write("✅ lint_output_slop: clean — no placeholder-prose patterns found.\n");
211
+ process.exit(0);
212
+ }
213
+
214
+ for (const f of allFindings) {
215
+ process.stdout.write(`❌ ${f.file}:${f.line} [${f.rule}] ${f.snippet}\n`);
216
+ }
217
+ process.stdout.write(
218
+ `\nlint_output_slop: ${allFindings.length} finding(s). Fix or use lint-output-slop-disable-next-line <rule> -- reason.\n`,
219
+ );
220
+ process.exit(2);
221
+ }
222
+
223
+ main();
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Lint the `risk_class` invariant on packs (road-to-capability-governance Phase 2).
3
+ *
4
+ * `risk_class: high` is the regulated-advice-adjacent tier. A high-risk pack MUST
5
+ * ship conservatively — off by default, consent-gated, lab-tier — or it is a
6
+ * governance hole. This linter makes that invariant a hard CI failure.
7
+ *
8
+ * high ⇒ default_install: false AND requires_explicit_consent: true AND surface_tier: lab
9
+ *
10
+ * `medium` / `low` carry no structural requirement here (their disclaimers live
11
+ * in the domain safety floors). Absent `risk_class` = `low`.
12
+ *
13
+ * Pure core (`riskClassViolations`) takes the packs.yml text so it is unit-testable
14
+ * without the filesystem. Exit 0 = clean, 1 = at least one violation.
15
+ */
16
+
17
+ import * as fs from 'node:fs';
18
+ import * as path from 'node:path';
19
+ import { fileURLToPath, pathToFileURL } from 'node:url';
20
+
21
+ const QUIET = process.argv.includes('--quiet');
22
+ const _HERE = fileURLToPath(import.meta.url);
23
+ const REPO = path.resolve(path.dirname(_HERE), '..', '..');
24
+ const PACKS_YML = path.join(REPO, 'src', 'config', 'discovery', 'packs.yml');
25
+
26
+ export interface RiskViolation {
27
+ pack: string;
28
+ msg: string;
29
+ }
30
+
31
+ function _field(block: string, key: string): string | undefined {
32
+ return new RegExp(`(^|\\n)\\s*${key}:\\s*([^\\n#]+)`).exec(block)?.[2]?.trim();
33
+ }
34
+
35
+ /** Pure invariant check over packs.yml text. */
36
+ export function riskClassViolations(packsYml: string): RiskViolation[] {
37
+ const out: RiskViolation[] = [];
38
+ // Split into per-pack blocks on top-level `- id:` entries.
39
+ const re = /(^|\n)- id:\s*([^\n#]+?)\s*\n([\s\S]*?)(?=\n- id:|\n*$)/g;
40
+ let m: RegExpExecArray | null;
41
+ while ((m = re.exec(packsYml)) !== null) {
42
+ const id = (m[2] ?? '').trim();
43
+ const block = m[3] ?? '';
44
+ const risk = _field(block, 'risk_class') ?? 'low';
45
+ if (risk !== 'high') continue;
46
+ const checks: Array<[string, string, string]> = [
47
+ ['default_install', 'false', `${id}: risk_class high requires default_install: false`],
48
+ ['requires_explicit_consent', 'true', `${id}: risk_class high requires requires_explicit_consent: true`],
49
+ ['surface_tier', 'lab', `${id}: risk_class high requires surface_tier: lab`],
50
+ ];
51
+ for (const [key, want, msg] of checks) {
52
+ if (_field(block, key) !== want) out.push({ pack: id, msg });
53
+ }
54
+ }
55
+ return out;
56
+ }
57
+
58
+ function _print(s: string): void {
59
+ if (!QUIET) process.stdout.write(`${s}\n`);
60
+ }
61
+
62
+ export function main(): number {
63
+ if (!fs.existsSync(PACKS_YML)) {
64
+ _print('⚠️ packs.yml not found — skipping risk_class lint');
65
+ return 0;
66
+ }
67
+ const violations = riskClassViolations(fs.readFileSync(PACKS_YML, 'utf-8'));
68
+ if (violations.length === 0) {
69
+ _print('✅ risk_class invariant OK — every high-risk pack is off-by-default + consent + lab');
70
+ return 0;
71
+ }
72
+ _print(`❌ risk_class invariant — ${violations.length} violation(s):`);
73
+ for (const v of violations) _print(` - ${v.msg}`);
74
+ return 1;
75
+ }
76
+
77
+ if (process.argv[1] !== undefined && import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href) {
78
+ process.exit(main());
79
+ }
@@ -154,7 +154,13 @@ function check_entry(entry: Record<string, unknown>): EntryResult {
154
154
  for (const [tool, spec] of Object.entries(checks)) {
155
155
  const result: CheckResult = { status: 'pass', details: [] };
156
156
  const expect_present = 'present' in spec ? Boolean(spec['present']) : true;
157
- const pathLocated = locate(tool, out.type, entry['source'] as string);
157
+ // Honor an explicit per-tool `location` from the fixture when present
158
+ // (e.g. a renamed command whose projection stem differs from its source
159
+ // stem); otherwise derive the path from the artefact source.
160
+ const explicitLoc = spec['location'] as string | undefined;
161
+ const pathLocated = typeof explicitLoc === 'string'
162
+ ? (fs.existsSync(path.join(ROOT, explicitLoc)) ? path.join(ROOT, explicitLoc) : null)
163
+ : locate(tool, out.type, entry['source'] as string);
158
164
 
159
165
  if (tool === 'windsurf' && spec['concatenated_in']) {
160
166
  const fp = path.join(ROOT, spec['concatenated_in'] as string);
@@ -72,6 +72,29 @@
72
72
  "enum": ["off", "on", "ask"]
73
73
  }
74
74
  }
75
+ },
76
+ "design": {
77
+ "type": "object",
78
+ "additionalProperties": true,
79
+ "properties": {
80
+ "fidelity_mode": {
81
+ "type": "string",
82
+ "enum": ["strict", "structural", "hard-floor"],
83
+ "description": "How strictly the agent must follow a user-provided prototype / mockup / design system. Consumed by the design-fidelity rule. strict = build 1:1, every visible deviation needs confirmation; structural = structure locked, silent gaps fillable with a stated assumption; hard-floor = any deviation is never autonomous."
84
+ }
85
+ }
86
+ },
87
+ "tokens": {
88
+ "type": "object",
89
+ "additionalProperties": true,
90
+ "description": "Token-spend governance for skills marked token_budget_class: rich. See token-budget-discipline rule.",
91
+ "properties": {
92
+ "rich_skills": {
93
+ "type": "string",
94
+ "enum": ["on", "ask", "off"],
95
+ "description": "Controls whether skills marked token_budget_class: rich may load in full (exempt from telegraph-speak and thin-projector trimming). on = allowed (default); off = fall back to standard condensed behavior; ask = surface an estimated token delta (tokens, not dollars) and ask the user once per session before loading."
96
+ }
97
+ }
75
98
  }
76
99
  }
77
100
  }
@@ -182,6 +182,11 @@
182
182
  "removable": {"type": "boolean", "default": false}
183
183
  },
184
184
  "description": "ADR-013 install hints (default-on at consumer install; user-removable)."
185
+ },
186
+ "token_budget_class": {
187
+ "type": "string",
188
+ "enum": ["lean", "standard", "rich"],
189
+ "description": "Token-cost class for this skill. `lean` (default): subject to telegraph-speak condensation and thin-projector trimming; optimize for <500 tokens. `standard`: balanced guidance, normal condensation. `rich`: exempt from telegraph-speak and thin-projector trimming; detailed examples preserved; eager-load eligible; ≤15% of skills in a suite may be `rich` (CI-enforced). A `rich` skill MUST carry a '## Why this skill is rich' section explaining the irreducible complexity that makes condensation harmful. Governed by `token-budget-discipline` rule + `tokens.rich_skills` consumer setting. See docs/guidelines/token-budget-governance.md."
185
190
  }
186
191
  }
187
192
  }
@@ -1407,6 +1407,7 @@ export function lint_skill(p: string, text: string): LintResult {
1407
1407
  const skillName = basename(p) === 'SKILL.md' ? parentName(p) : stem(p);
1408
1408
  if (skillName && !skillName.includes('-') && skillName.length >= 3) {
1409
1409
  const ALLOWED_BARE_NOUNS = new Set([
1410
+ 'brand',
1410
1411
  'database',
1411
1412
  'devcontainer',
1412
1413
  'docker',
@@ -1414,12 +1415,14 @@ export function lint_skill(p: string, text: string): LintResult {
1414
1415
  'flux',
1415
1416
  'forecasting',
1416
1417
  'grafana',
1418
+ 'iconography',
1417
1419
  'laravel',
1418
1420
  'livewire',
1419
1421
  'markitdown',
1420
1422
  'mcp',
1421
1423
  'openapi',
1422
1424
  'performance',
1425
+ 'premortem',
1423
1426
  'security',
1424
1427
  'terraform',
1425
1428
  'terragrunt',