@event4u/agent-config 8.8.0 → 8.10.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 (215) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +139 -263
  3. package/README.md +5 -5
  4. package/dist/agent-src/commands/agent-handoff.md +39 -2
  5. package/dist/agent-src/commands/cost/report.md +13 -3
  6. package/dist/agent-src/commands/research/deep.md +8 -0
  7. package/dist/agent-src/commands/research/report.md +7 -0
  8. package/dist/agent-src/commands/roadmap/create.md +12 -0
  9. package/dist/agent-src/commands/roadmap/process-full.md +31 -5
  10. package/dist/agent-src/commands/tests/create.md +28 -6
  11. package/dist/agent-src/commands/work.md +33 -0
  12. package/dist/agent-src/commands/worktree/cleanup.md +78 -0
  13. package/dist/agent-src/commands/worktree/create.md +62 -0
  14. package/dist/agent-src/commands/worktree/status.md +63 -0
  15. package/dist/agent-src/commands/worktree/verify.md +70 -0
  16. package/dist/agent-src/commands/worktree.md +85 -0
  17. package/dist/agent-src/contexts/communication/rules-auto/think-before-action-mechanics.md +30 -1
  18. package/dist/agent-src/contexts/execution/orchestration-telemetry.md +60 -31
  19. package/dist/agent-src/contexts/execution/roadmap-process-loop.md +37 -0
  20. package/dist/agent-src/contexts/execution/subagent-topologies.md +34 -0
  21. package/dist/agent-src/contexts/execution/verification-mechanics.md +9 -9
  22. package/dist/agent-src/rules/agent-authority.md +1 -1
  23. package/dist/agent-src/rules/communication-through-line.md +1 -1
  24. package/dist/agent-src/rules/delegation-policy.md +5 -0
  25. package/dist/agent-src/rules/design-fidelity.md +40 -0
  26. package/dist/agent-src/rules/direct-answers.md +1 -1
  27. package/dist/agent-src/rules/downstream-changes.md +1 -0
  28. package/dist/agent-src/rules/external-code-graph-interop.md +65 -0
  29. package/dist/agent-src/rules/git-history-discipline.md +18 -0
  30. package/dist/agent-src/rules/lethal-trifecta-guard.md +6 -1
  31. package/dist/agent-src/rules/minimal-safe-diff.md +58 -10
  32. package/dist/agent-src/rules/non-destructive-by-default.md +3 -0
  33. package/dist/agent-src/rules/question-not-instruction.md +76 -0
  34. package/dist/agent-src/rules/senior-engineering-discipline.md +1 -1
  35. package/dist/agent-src/rules/spreadsheet-source-quality.md +61 -0
  36. package/dist/agent-src/rules/think-before-action.md +1 -0
  37. package/dist/agent-src/rules/tool-safety.md +8 -0
  38. package/dist/agent-src/rules/untrusted-input-defense.md +87 -22
  39. package/dist/agent-src/scripts/update_roadmap_progress.ts +2 -1
  40. package/dist/agent-src/skills/accessibility-auditor/SKILL.md +19 -0
  41. package/dist/agent-src/skills/accessibility-auditor/evals/evals.json +15 -0
  42. package/dist/agent-src/skills/ai-code-blindspots/SKILL.md +10 -3
  43. package/dist/agent-src/skills/analysis-skill-router/evals/evals.json +13 -0
  44. package/dist/agent-src/skills/api-testing/SKILL.md +15 -1
  45. package/dist/agent-src/skills/character-consistency/evals/evals.json +16 -0
  46. package/dist/agent-src/skills/code-review/SKILL.md +2 -0
  47. package/dist/agent-src/skills/command-routing/evals/evals.json +14 -0
  48. package/dist/agent-src/skills/command-writing/SKILL.md +53 -40
  49. package/dist/agent-src/skills/dashboard-design/evals/evals.json +16 -0
  50. package/dist/agent-src/skills/dcf-modeling/evals/domain-truth.json +29 -0
  51. package/dist/agent-src/skills/dcf-modeling/evals/evals.json +20 -0
  52. package/dist/agent-src/skills/decision-record/evals/evals.json +20 -0
  53. package/dist/agent-src/skills/deep-reading-analyst/SKILL.md +1 -0
  54. package/dist/agent-src/skills/design-intelligence/SKILL.md +49 -12
  55. package/dist/agent-src/skills/design-intelligence/evals/evals.json +14 -0
  56. package/dist/agent-src/skills/design-review/SKILL.md +35 -15
  57. package/dist/agent-src/skills/design-system-capture/SKILL.md +84 -24
  58. package/dist/agent-src/skills/design-system-capture/evals/evals.json +15 -0
  59. package/dist/agent-src/skills/developer-like-execution/evals/evals.json +16 -0
  60. package/dist/agent-src/skills/doc-coauthoring/SKILL.md +27 -0
  61. package/dist/agent-src/skills/doc-coauthoring/evals/evals.json +16 -0
  62. package/dist/agent-src/skills/editorial-calendar/evals/domain-truth.json +16 -0
  63. package/dist/agent-src/skills/editorial-calendar/evals/evals.json +16 -0
  64. package/dist/agent-src/skills/estimate-ticket/evals/evals.json +16 -0
  65. package/dist/agent-src/skills/existing-ui-audit/SKILL.md +30 -0
  66. package/dist/agent-src/skills/existing-ui-audit/evals/triggers.json +47 -0
  67. package/dist/agent-src/skills/fe-design/SKILL.md +36 -5
  68. package/dist/agent-src/skills/fe-design/evals/triggers.json +47 -0
  69. package/dist/agent-src/skills/forecasting/evals/domain-truth.json +29 -0
  70. package/dist/agent-src/skills/forecasting/evals/evals.json +20 -0
  71. package/dist/agent-src/skills/frontend-render-security/SKILL.md +2 -2
  72. package/dist/agent-src/skills/fundraising-narrative/evals/domain-truth.json +16 -0
  73. package/dist/agent-src/skills/fundraising-narrative/evals/evals.json +16 -0
  74. package/dist/agent-src/skills/html-deck/SKILL.md +27 -0
  75. package/dist/agent-src/skills/iconography/SKILL.md +24 -0
  76. package/dist/agent-src/skills/incident-commander/evals/domain-truth.json +16 -0
  77. package/dist/agent-src/skills/incident-commander/evals/evals.json +20 -0
  78. package/dist/agent-src/skills/launch-readiness/evals/evals.json +21 -0
  79. package/dist/agent-src/skills/logging-monitoring/evals/evals.json +16 -0
  80. package/dist/agent-src/skills/markitdown/SKILL.md +1 -0
  81. package/dist/agent-src/skills/mcp/SKILL.md +24 -0
  82. package/dist/agent-src/skills/mcp-builder/SKILL.md +9 -1
  83. package/dist/agent-src/skills/memory-consolidation/SKILL.md +55 -4
  84. package/dist/agent-src/skills/messaging-architecture/evals/domain-truth.json +16 -0
  85. package/dist/agent-src/skills/messaging-architecture/evals/evals.json +16 -0
  86. package/dist/agent-src/skills/perf-feedback-craft/evals/evals.json +16 -0
  87. package/dist/agent-src/skills/pest-testing/SKILL.md +1 -1
  88. package/dist/agent-src/skills/playwright-testing/SKILL.md +16 -0
  89. package/dist/agent-src/skills/prompt-engineering-patterns/evals/evals.json +16 -0
  90. package/dist/agent-src/skills/refine-prompt/evals/evals.json +16 -0
  91. package/dist/agent-src/skills/refine-ticket/evals/evals.json +16 -0
  92. package/dist/agent-src/skills/release-comms/evals/evals.json +16 -0
  93. package/dist/agent-src/skills/rice-prioritization/evals/evals.json +20 -0
  94. package/dist/agent-src/skills/roadmap-writing/SKILL.md +39 -5
  95. package/dist/agent-src/skills/runway-cognition/evals/domain-truth.json +29 -0
  96. package/dist/agent-src/skills/runway-cognition/evals/evals.json +20 -0
  97. package/dist/agent-src/skills/scenario-modeling/evals/domain-truth.json +29 -0
  98. package/dist/agent-src/skills/scenario-modeling/evals/evals.json +20 -0
  99. package/dist/agent-src/skills/secrets-management/SKILL.md +7 -0
  100. package/dist/agent-src/skills/skill-writing/SKILL.md +12 -3
  101. package/dist/agent-src/skills/spreadsheet-authoring/SKILL.md +98 -0
  102. package/dist/agent-src/skills/spreadsheet-authoring/evals/triggers.json +47 -0
  103. package/dist/agent-src/skills/subagent-orchestration/SKILL.md +27 -33
  104. package/dist/agent-src/skills/supply-chain-intake/SKILL.md +12 -0
  105. package/dist/agent-src/skills/systematic-debugging/evals/evals.json +20 -0
  106. package/dist/agent-src/skills/test-case-discovery/SKILL.md +118 -0
  107. package/dist/agent-src/skills/test-case-discovery/evals/triggers.json +52 -0
  108. package/dist/agent-src/skills/test-driven-development/SKILL.md +32 -6
  109. package/dist/agent-src/skills/test-driven-development/evals/evals.json +16 -0
  110. package/dist/agent-src/skills/testing-anti-patterns/SKILL.md +34 -4
  111. package/dist/agent-src/skills/threat-modeling/evals/evals.json +21 -0
  112. package/dist/agent-src/skills/typography-system/evals/evals.json +14 -0
  113. package/dist/agent-src/skills/ui-component-architect/SKILL.md +9 -0
  114. package/dist/agent-src/skills/unit-economics-modeling/evals/domain-truth.json +40 -0
  115. package/dist/agent-src/skills/unit-economics-modeling/evals/evals.json +24 -0
  116. package/dist/agent-src/skills/verify-completion-evidence/evals/evals.json +16 -0
  117. package/dist/agent-src/skills/vision-articulation/evals/evals.json +16 -0
  118. package/dist/agent-src/skills/voice-and-tone-design/evals/evals.json +16 -0
  119. package/dist/agent-src/skills/worktree-lifecycle/SKILL.md +180 -0
  120. package/dist/agent-src/skills/worktree-lifecycle/evals/triggers.json +52 -0
  121. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  122. package/dist/agent-src/templates/roadmaps.md +36 -0
  123. package/dist/cli/registry.js +3 -0
  124. package/dist/cli/registry.js.map +1 -1
  125. package/dist/discovery/deprecation-report.md +1 -1
  126. package/dist/discovery/discovery-manifest.json +326 -67
  127. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  128. package/dist/discovery/discovery-manifest.summary.md +6 -6
  129. package/dist/discovery/orphan-report.md +1 -1
  130. package/dist/discovery/packs.json +25 -14
  131. package/dist/discovery/trust-report.md +4 -4
  132. package/dist/discovery/workspaces.json +25 -12
  133. package/dist/install/install.mjs +136 -1
  134. package/dist/mcp/registry-manifest.json +3 -3
  135. package/dist/router.json +1 -1
  136. package/dist/scripts/_lib/claude_builtin_names.js +145 -0
  137. package/dist/scripts/_lib/claude_builtin_names.js.map +1 -0
  138. package/dist/scripts/condense.js +14 -0
  139. package/dist/scripts/condense.js.map +1 -1
  140. package/docs/CLAIMS.md +36 -8
  141. package/docs/architecture.md +4 -4
  142. package/docs/archive/CHANGELOG-pre-8.9.0.md +306 -0
  143. package/docs/benchmark.md +113 -0
  144. package/docs/catalog.md +32 -8
  145. package/docs/command-flows.md +6 -1
  146. package/docs/contracts/CHANGELOG-conventions.md +6 -0
  147. package/docs/contracts/command-clusters.md +18 -0
  148. package/docs/contracts/design-artifact-lifecycle.md +93 -0
  149. package/docs/contracts/design-artifact-verification.md +153 -0
  150. package/docs/contracts/injected-block-authenticity-model.md +66 -0
  151. package/docs/contracts/mcp-tool-inventory.md +28 -28
  152. package/docs/contracts/release-pr-gating.md +26 -0
  153. package/docs/contracts/release-sizing.md +85 -0
  154. package/docs/contracts/surface-agent-contracts.md +153 -0
  155. package/docs/decisions/ADR-061-corpus-grounding-layer.md +13 -0
  156. package/docs/decisions/ADR-115-command-cluster-consolidation-phase-4.md +1 -1
  157. package/docs/decisions/ADR-116-memory-tripwire-activation-path.md +9 -0
  158. package/docs/distribution/consumer-matrix.md +96 -0
  159. package/docs/featured-skills.md +2 -2
  160. package/docs/getting-started-by-role.md +1 -1
  161. package/docs/getting-started.md +2 -2
  162. package/docs/governance-advantage.md +1 -1
  163. package/docs/guidelines/agent-infra/asking-and-brevity-examples.md +27 -0
  164. package/docs/guidelines/agent-infra/emphasis-budget.md +45 -0
  165. package/docs/guidelines/agent-infra/simplicity-and-goal-demos.md +151 -0
  166. package/docs/guidelines/agent-infra/tool-description-as-policy.md +35 -0
  167. package/docs/guidelines/design-canon.md +1 -0
  168. package/docs/proof.md +38 -23
  169. package/docs/release-runbook.md +3 -0
  170. package/docs/second-brain-scope.md +69 -26
  171. package/docs/self-review-gate.md +51 -0
  172. package/package.json +1 -1
  173. package/src/agent-src/scripts/update_roadmap_progress.ts +2 -1
  174. package/src/scripts/_dispatch.bash +27 -0
  175. package/src/scripts/_lib/claude_builtin_names.ts +148 -0
  176. package/src/scripts/_lib/file_slicer.ts +117 -0
  177. package/src/scripts/_lib/lexical_index.ts +155 -0
  178. package/src/scripts/_lib/orchestration_record.ts +183 -0
  179. package/src/scripts/_lib/orchestration_savings.ts +114 -9
  180. package/src/scripts/_lib/retrieval_sanitize.ts +71 -0
  181. package/src/scripts/_lib/security_lint.ts +1 -0
  182. package/src/scripts/_lib/stat_index.ts +98 -0
  183. package/src/scripts/benchmark.ts +122 -0
  184. package/src/scripts/build_proof.ts +30 -17
  185. package/src/scripts/check_memory.ts +2 -0
  186. package/src/scripts/check_quality_regression.ts +51 -0
  187. package/src/scripts/check_release_adjacent_health.ts +121 -0
  188. package/src/scripts/check_roadmap_trackable.ts +3 -2
  189. package/src/scripts/check_rule_invariants.ts +275 -0
  190. package/src/scripts/condense.ts +14 -0
  191. package/src/scripts/consumer_matrix.ts +353 -0
  192. package/src/scripts/discovery_graph.ts +0 -0
  193. package/src/scripts/external_sources_denylist.json +4 -1
  194. package/src/scripts/generate_index.ts +6 -2
  195. package/src/scripts/install-hooks.sh +25 -0
  196. package/src/scripts/install.ts +35 -2
  197. package/src/scripts/learning_sidecar.ts +0 -0
  198. package/src/scripts/lint_agent_skill_names.ts +29 -0
  199. package/src/scripts/lint_changelog_rollback.ts +293 -0
  200. package/src/scripts/lint_knowledge_scale.ts +4 -3
  201. package/src/scripts/lint_roadmap_complexity.ts +124 -0
  202. package/src/scripts/lint_versioned_cache.ts +195 -0
  203. package/src/scripts/mcp_server/consumer_tool_catalog.json +2 -1
  204. package/src/scripts/mcp_server/tools.ts +24 -1
  205. package/src/scripts/measure_lexical_ranking.ts +173 -0
  206. package/src/scripts/memory_lookup.ts +0 -0
  207. package/src/scripts/orchestration_record.ts +156 -0
  208. package/src/scripts/orchestration_savings_report.ts +65 -8
  209. package/src/scripts/schemas/skill.schema.json +4 -0
  210. package/src/scripts/score_domain_truth.ts +192 -0
  211. package/src/scripts/second_brain_retrieval.ts +320 -0
  212. package/src/scripts/second_brain_run.ts +341 -0
  213. package/src/scripts/self_review_gate.test.ts +65 -0
  214. package/src/scripts/self_review_gate.ts +272 -0
  215. package/src/scripts/trigger_eval_grandfather.json +223 -224
@@ -0,0 +1,353 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * Consumer-proof release matrix — road-to-proof-under-real-conditions Phase 1.
4
+ *
5
+ * Exercises the PUBLISHED TARBALL the way a consumer does: pack → fresh
6
+ * global install (isolated prefix) → `init` into a fresh project → doctor →
7
+ * conformance → MCP stdio handshake → hook health → projection presence →
8
+ * uninstall. Optional upgrade leg: install the last published minor from the
9
+ * registry, then upgrade to the packed tarball and assert doctor stays green.
10
+ *
11
+ * Why this exists: the release-PR gate skips source-level matrices (soundly —
12
+ * a version-bump diff cannot regress source behaviour), but nothing between
13
+ * merge and tag exercised the tarball shape. Two published minors shipped
14
+ * without `src/install/` while published code imported from it; `tsx` was
15
+ * missing from the published package; each manifested only at publish time.
16
+ * Every leg here asserts exit code + an expected artifact, no LLM calls.
17
+ *
18
+ * Usage:
19
+ * npx tsx src/scripts/consumer_matrix.ts [--tarball <path>] [--only leg1,leg2]
20
+ * [--skip-registry] [--keep-tmp] [--json]
21
+ *
22
+ * Without --tarball the script runs `npm pack` itself (requires a built
23
+ * tree — `npm ci && npm run build` first; CI does this, local carve-out
24
+ * runs do it once).
25
+ *
26
+ * Exit codes: 0 all requested legs green · 1 leg failure · 2 usage/env.
27
+ */
28
+
29
+ import { spawnSync, spawn } from 'node:child_process';
30
+ import * as fs from 'node:fs';
31
+ import * as os from 'node:os';
32
+ import * as path from 'node:path';
33
+ import { fileURLToPath } from 'node:url';
34
+
35
+ const _HERE = fileURLToPath(import.meta.url);
36
+ const REPO_ROOT = path.resolve(path.dirname(_HERE), '..', '..');
37
+ const PKG_NAME = '@event4u/agent-config';
38
+
39
+ interface Ctx {
40
+ tmpRoot: string;
41
+ prefix: string; // isolated npm global prefix
42
+ projectDir: string; // fresh consumer project
43
+ tarball: string;
44
+ bin: string; // installed agent-config binary
45
+ keepTmp: boolean;
46
+ skipRegistry: boolean;
47
+ results: LegResult[];
48
+ }
49
+
50
+ interface LegResult {
51
+ leg: string;
52
+ ok: boolean;
53
+ detail: string;
54
+ durationMs: number;
55
+ }
56
+
57
+ function log(msg: string): void {
58
+ process.stderr.write(`${msg}\n`);
59
+ }
60
+
61
+ function run(
62
+ cmd: string,
63
+ args: string[],
64
+ opts: { cwd?: string; env?: NodeJS.ProcessEnv; timeoutMs?: number } = {},
65
+ ): { status: number; stdout: string; stderr: string } {
66
+ const r = spawnSync(cmd, args, {
67
+ cwd: opts.cwd ?? REPO_ROOT,
68
+ env: { ...process.env, ...opts.env },
69
+ encoding: 'utf8',
70
+ timeout: opts.timeoutMs ?? 600_000,
71
+ maxBuffer: 32 * 1024 * 1024,
72
+ });
73
+ return { status: r.status ?? 1, stdout: r.stdout ?? '', stderr: r.stderr ?? '' };
74
+ }
75
+
76
+ function fail(msg: string): never {
77
+ log(`❌ consumer-matrix: ${msg}`);
78
+ process.exit(1);
79
+ }
80
+
81
+ /**
82
+ * Env for running the installed binary against the isolated prefix.
83
+ * HOME is redirected into the tmp root so the simulation is a FRESH
84
+ * MACHINE even on a maintainer host: without this, an existing global
85
+ * install (~/.event4u, ~/.claude, …) trips the cross-scope drift guard
86
+ * inside `init` and the leg fails on developer machines while passing
87
+ * on clean CI runners — the opposite of what a consumer gate is for.
88
+ */
89
+ function binEnv(ctx: Ctx): NodeJS.ProcessEnv {
90
+ const home = path.join(ctx.tmpRoot, 'home');
91
+ fs.mkdirSync(home, { recursive: true });
92
+ return {
93
+ PATH: `${path.join(ctx.prefix, 'bin')}${path.delimiter}${process.env.PATH ?? ''}`,
94
+ npm_config_prefix: ctx.prefix,
95
+ npm_config_cache: path.join(ctx.tmpRoot, 'npm-cache'),
96
+ HOME: home,
97
+ // Never let a maintainer checkout leak into the consumer simulation.
98
+ AGENT_CONFIG_DEV_MODE: '',
99
+ };
100
+ }
101
+
102
+ // ── legs ────────────────────────────────────────────────────────────
103
+
104
+ function legPack(ctx: Ctx): string {
105
+ if (ctx.tarball) {
106
+ if (!fs.existsSync(ctx.tarball)) fail(`--tarball not found: ${ctx.tarball}`);
107
+ return `reused ${path.basename(ctx.tarball)}`;
108
+ }
109
+ const r = run('npm', ['pack', '--ignore-scripts', '--silent', '--pack-destination', ctx.tmpRoot]);
110
+ if (r.status !== 0) throw new Error(`npm pack failed: ${r.stderr.slice(-400)}`);
111
+ const name = r.stdout.trim().split('\n').pop() ?? '';
112
+ ctx.tarball = path.join(ctx.tmpRoot, name);
113
+ if (!fs.existsSync(ctx.tarball)) throw new Error(`packed tarball missing: ${ctx.tarball}`);
114
+ return path.basename(ctx.tarball);
115
+ }
116
+
117
+ function legFreshInstall(ctx: Ctx): string {
118
+ const r = run('npm', ['install', '-g', '--prefix', ctx.prefix, ctx.tarball], { timeoutMs: 900_000 });
119
+ if (r.status !== 0) throw new Error(`global install failed: ${r.stderr.slice(-600)}`);
120
+ ctx.bin = path.join(ctx.prefix, 'bin', 'agent-config');
121
+ if (!fs.existsSync(ctx.bin)) throw new Error(`installed binary missing at ${ctx.bin}`);
122
+ const v = run(ctx.bin, ['--version'], { env: binEnv(ctx) });
123
+ if (v.status !== 0) throw new Error(`--version failed (missing runtime dep in tarball?): ${v.stderr.slice(-400)}`);
124
+ return `bin ok, version ${v.stdout.trim()}`;
125
+ }
126
+
127
+ function legInit(ctx: Ctx): string {
128
+ fs.mkdirSync(ctx.projectDir, { recursive: true });
129
+ run('git', ['init', '-q', '.'], { cwd: ctx.projectDir });
130
+ // --scope=auto is the working headless consumer invocation. The bare
131
+ // default ('project default for backward compatibility') hard-fails on
132
+ // a fresh machine with '--scope=project is reserved for maintainers'
133
+ // (ADR-020) — a real trap this matrix documents; see
134
+ // docs/distribution/consumer-matrix.md § Headless default-scope trap.
135
+ const r = run(ctx.bin, ['init', '--tools=claude-code,cursor,windsurf', '--scope=auto', '--yes'], {
136
+ cwd: ctx.projectDir,
137
+ env: binEnv(ctx),
138
+ timeoutMs: 600_000,
139
+ });
140
+ if (r.status !== 0) throw new Error(`init failed: ${(r.stderr + r.stdout).slice(-600)}`);
141
+ // ADR-020: consumer installs are GLOBAL-only — assert the global trees.
142
+ const home = path.join(ctx.tmpRoot, 'home');
143
+ for (const p of ['.claude', '.cursor', '.codeium/windsurf', '.event4u']) {
144
+ if (!fs.existsSync(path.join(home, p))) throw new Error(`init did not write ~/${p}`);
145
+ }
146
+ return 'init --scope=auto wrote global ~/.claude, ~/.cursor, ~/.codeium/windsurf, ~/.event4u';
147
+ }
148
+
149
+ function legConformance(ctx: Ctx): string {
150
+ const r = run(ctx.bin, ['conformance'], { cwd: ctx.projectDir, env: binEnv(ctx) });
151
+ if (r.status !== 0) throw new Error(`conformance exit ${r.status}: ${(r.stdout + r.stderr).slice(-600)}`);
152
+ return 'conformance green (embeds doctor --ci + installed-and-firing checks)';
153
+ }
154
+
155
+ async function legMcpHandshake(ctx: Ctx): Promise<string> {
156
+ // Newline-delimited JSON-RPC per src/cli/mcp/stdio.ts.
157
+ return await new Promise<string>((resolve, reject) => {
158
+ const child = spawn(ctx.bin, ['mcp-server'], {
159
+ cwd: ctx.projectDir,
160
+ env: { ...process.env, ...binEnv(ctx) },
161
+ stdio: ['pipe', 'pipe', 'pipe'],
162
+ });
163
+ let out = '';
164
+ const timer = setTimeout(() => {
165
+ child.kill();
166
+ reject(new Error(`no initialize response within 20s; stdout so far: ${out.slice(0, 300)}`));
167
+ }, 20_000);
168
+ child.stdout.on('data', (d: Buffer) => {
169
+ out += d.toString();
170
+ const line = out.split('\n').find((l) => l.trim().startsWith('{'));
171
+ if (line) {
172
+ try {
173
+ const msg = JSON.parse(line) as { id?: number; result?: unknown; error?: unknown };
174
+ clearTimeout(timer);
175
+ child.kill();
176
+ if (msg.id === 1 && msg.result && !msg.error) {
177
+ resolve('initialize handshake ok');
178
+ } else {
179
+ reject(new Error(`unexpected first message: ${line.slice(0, 300)}`));
180
+ }
181
+ } catch {
182
+ /* partial line — keep buffering */
183
+ }
184
+ }
185
+ });
186
+ child.on('error', (e) => {
187
+ clearTimeout(timer);
188
+ reject(e);
189
+ });
190
+ child.on('exit', (code) => {
191
+ if (out === '') {
192
+ clearTimeout(timer);
193
+ reject(new Error(`mcp-server exited (${code}) before responding`));
194
+ }
195
+ });
196
+ child.stdin.write(
197
+ `${JSON.stringify({
198
+ jsonrpc: '2.0',
199
+ id: 1,
200
+ method: 'initialize',
201
+ params: {
202
+ protocolVersion: '2025-03-26',
203
+ capabilities: {},
204
+ clientInfo: { name: 'consumer-matrix', version: '0' },
205
+ },
206
+ })}\n`,
207
+ );
208
+ });
209
+ }
210
+
211
+ function legHooks(ctx: Ctx): string {
212
+ const r = run(ctx.bin, ['hooks:doctor'], { cwd: ctx.projectDir, env: binEnv(ctx) });
213
+ if (r.status !== 0) throw new Error(`hooks:doctor exit ${r.status}: ${(r.stdout + r.stderr).slice(-600)}`);
214
+ return 'hooks:doctor green';
215
+ }
216
+
217
+ function legProjections(ctx: Ctx): string {
218
+ const home = path.join(ctx.tmpRoot, 'home');
219
+ const missing = ['.cursor/rules', '.codeium/windsurf', '.claude/skills']
220
+ .filter((p) => !fs.existsSync(path.join(home, p)))
221
+ .join(', ');
222
+ if (missing) throw new Error(`global projection trees missing: ${missing}`);
223
+ return 'cursor + windsurf + claude projection trees present in global scope';
224
+ }
225
+
226
+ function legUninstall(ctx: Ctx): string {
227
+ const r = run(ctx.bin, ['uninstall', '--global', '--tools=claude-code,cursor,windsurf', '--force'], {
228
+ cwd: ctx.projectDir,
229
+ env: binEnv(ctx),
230
+ });
231
+ if (r.status !== 0) throw new Error(`uninstall exit ${r.status}: ${(r.stdout + r.stderr).slice(-600)}`);
232
+ const lock = path.join(ctx.tmpRoot, 'home', '.event4u', 'agent-config', 'installed.lock');
233
+ if (fs.existsSync(lock)) throw new Error(`global lockfile still present after uninstall: ${lock}`);
234
+ return 'uninstall --global green, lockfile removed';
235
+ }
236
+
237
+ function legUpgrade(ctx: Ctx): string {
238
+ if (ctx.skipRegistry) return 'skipped (--skip-registry)';
239
+ // Last published version from the registry (network).
240
+ const view = run('npm', ['view', PKG_NAME, 'version'], { timeoutMs: 120_000 });
241
+ if (view.status !== 0) throw new Error(`npm view failed: ${view.stderr.slice(-300)}`);
242
+ const published = view.stdout.trim();
243
+ const upPrefix = path.join(ctx.tmpRoot, 'prefix-upgrade');
244
+ const upProject = path.join(ctx.tmpRoot, 'project-upgrade');
245
+ fs.mkdirSync(upProject, { recursive: true });
246
+ const upHome = path.join(ctx.tmpRoot, 'home-upgrade');
247
+ fs.mkdirSync(upHome, { recursive: true });
248
+ const env = {
249
+ PATH: `${path.join(upPrefix, 'bin')}${path.delimiter}${process.env.PATH ?? ''}`,
250
+ npm_config_prefix: upPrefix,
251
+ npm_config_cache: path.join(ctx.tmpRoot, 'npm-cache'),
252
+ HOME: upHome,
253
+ AGENT_CONFIG_DEV_MODE: '',
254
+ };
255
+ let r = run('npm', ['install', '-g', '--prefix', upPrefix, `${PKG_NAME}@${published}`], { timeoutMs: 900_000 });
256
+ if (r.status !== 0) throw new Error(`registry install of ${published} failed: ${r.stderr.slice(-400)}`);
257
+ const bin = path.join(upPrefix, 'bin', 'agent-config');
258
+ r = run(bin, ['init', '--tools=claude-code', '--scope=auto', '--yes'], { cwd: upProject, env, timeoutMs: 600_000 });
259
+ if (r.status !== 0) throw new Error(`init on ${published} failed: ${(r.stderr + r.stdout).slice(-400)}`);
260
+ // Upgrade: overwrite the global install with the packed tarball.
261
+ r = run('npm', ['install', '-g', '--prefix', upPrefix, ctx.tarball], { timeoutMs: 900_000 });
262
+ if (r.status !== 0) throw new Error(`tarball upgrade failed: ${r.stderr.slice(-400)}`);
263
+ r = run(bin, ['conformance'], { cwd: upProject, env });
264
+ if (r.status !== 0) {
265
+ throw new Error(`conformance red after ${published} → tarball upgrade: ${(r.stdout + r.stderr).slice(-600)}`);
266
+ }
267
+ return `upgrade ${published} → packed tarball, conformance green`;
268
+ }
269
+
270
+ // ── main ────────────────────────────────────────────────────────────
271
+
272
+ const LEGS: Array<{ name: string; fn: (ctx: Ctx) => string | Promise<string> }> = [
273
+ { name: 'pack', fn: legPack },
274
+ { name: 'fresh-install', fn: legFreshInstall },
275
+ { name: 'init', fn: legInit },
276
+ { name: 'conformance', fn: legConformance },
277
+ { name: 'mcp-handshake', fn: legMcpHandshake },
278
+ { name: 'hooks', fn: legHooks },
279
+ { name: 'projections', fn: legProjections },
280
+ { name: 'uninstall', fn: legUninstall },
281
+ { name: 'upgrade', fn: legUpgrade },
282
+ ];
283
+
284
+ async function main(): Promise<number> {
285
+ const argv = process.argv.slice(2);
286
+ const getOpt = (flag: string): string | undefined => {
287
+ const i = argv.indexOf(flag);
288
+ return i >= 0 ? argv[i + 1] : undefined;
289
+ };
290
+ const only = getOpt('--only')?.split(',').map((s) => s.trim());
291
+ const unknownLeg = only?.find((l) => !LEGS.some((x) => x.name === l));
292
+ if (unknownLeg) {
293
+ log(`❌ unknown leg '${unknownLeg}'. Legs: ${LEGS.map((l) => l.name).join(', ')}`);
294
+ return 2;
295
+ }
296
+
297
+ const tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'consumer-matrix-'));
298
+ const ctx: Ctx = {
299
+ tmpRoot,
300
+ prefix: path.join(tmpRoot, 'prefix'),
301
+ projectDir: path.join(tmpRoot, 'project'),
302
+ tarball: getOpt('--tarball') ?? '',
303
+ bin: '',
304
+ keepTmp: argv.includes('--keep-tmp'),
305
+ skipRegistry: argv.includes('--skip-registry'),
306
+ results: [],
307
+ };
308
+ fs.mkdirSync(ctx.prefix, { recursive: true });
309
+ log(`consumer-matrix · tmp ${tmpRoot} · node ${process.version}`);
310
+
311
+ let failed = false;
312
+ for (const leg of LEGS) {
313
+ if (only && !only.includes(leg.name)) continue;
314
+ // Legs after a hard dependency failure cannot run meaningfully.
315
+ if (failed) {
316
+ ctx.results.push({ leg: leg.name, ok: false, detail: 'skipped (earlier leg failed)', durationMs: 0 });
317
+ continue;
318
+ }
319
+ const t0 = Date.now();
320
+ try {
321
+ const detail = await leg.fn(ctx);
322
+ ctx.results.push({ leg: leg.name, ok: true, detail, durationMs: Date.now() - t0 });
323
+ log(` ✅ ${leg.name} — ${detail}`);
324
+ } catch (err) {
325
+ ctx.results.push({
326
+ leg: leg.name,
327
+ ok: false,
328
+ detail: (err as Error).message,
329
+ durationMs: Date.now() - t0,
330
+ });
331
+ log(` ❌ ${leg.name} — ${(err as Error).message}`);
332
+ failed = true;
333
+ }
334
+ }
335
+
336
+ if (argv.includes('--json')) {
337
+ process.stdout.write(`${JSON.stringify({ ok: !failed, results: ctx.results }, null, 2)}\n`);
338
+ }
339
+ if (!ctx.keepTmp) {
340
+ fs.rmSync(tmpRoot, { recursive: true, force: true });
341
+ } else {
342
+ log(`kept tmp: ${tmpRoot}`);
343
+ }
344
+ return failed ? 1 : 0;
345
+ }
346
+
347
+ main().then(
348
+ (code) => process.exit(code),
349
+ (err) => {
350
+ log(`❌ consumer-matrix crashed: ${(err as Error).stack ?? err}`);
351
+ process.exit(2);
352
+ },
353
+ );
Binary file
@@ -54,7 +54,10 @@
54
54
  "gztchan",
55
55
  "amaancoderx",
56
56
  "npxskillui",
57
- "\\bskillui\\b"
57
+ "\\bskillui\\b",
58
+ "\\bgraphify\\b",
59
+ "graphify-labs",
60
+ "penpax"
58
61
  ],
59
62
  "skip_paths": [
60
63
  "src/scripts/check_no_external_sources.py",
@@ -24,6 +24,7 @@ import {
24
24
  iter_commands,
25
25
  strip_source_prefix,
26
26
  } from './_lib/agent_src.js';
27
+ import { computeStatus as domainSoundnessStatus } from './domain_soundness_status.js';
27
28
 
28
29
  const _HERE = fileURLToPath(import.meta.url);
29
30
 
@@ -398,6 +399,7 @@ export function _render_catalog(
398
399
  const publicRules = rules.filter((r) => !INTERNAL_RULES.has(r.name));
399
400
  const publicCommands = commands.filter((c) => c.kind === 'command');
400
401
  const total = skills.length + publicRules.length + publicCommands.length + guidelines.length;
402
+ const ds = domainSoundnessStatus();
401
403
  const parts = [
402
404
  '# agent-config — Public Catalog',
403
405
  '',
@@ -419,8 +421,10 @@ export function _render_catalog(
419
421
  '',
420
422
  '> **Non-coding domain correctness is scoped, not proven.** The',
421
423
  '> `finance` / `founder` / `ops` / `content` skills are forged on TS/PHP',
422
- '> codebases; their embedded domain heuristics are labeled `unvalidated`',
423
- '> until they pass a sourced `evals/domain-truth.json` fixture',
424
+ `> codebases; ${ds.validated} of ${ds.total} default-surface domain skills carry a sourced`,
425
+ '> `evals/domain-truth.json` fixture (deterministic targets with keys from',
426
+ '> cited formulas, or rubric targets matching a named external practice);',
427
+ '> the rest are labeled `unvalidated` until they pass one',
424
428
  '> (`./scripts-run src/scripts/domain_soundness_status`). A disclaimer',
425
429
  '> floor bounds liability, not correctness — see [the proof page](proof.md).',
426
430
  '',
@@ -42,6 +42,31 @@ if ! ./scripts-run src/scripts/check_no_conflict_markers --quiet; then
42
42
  fail=1
43
43
  fi
44
44
 
45
+ # Changed-files static pass (typecheck + lint) — the deterministic backstop to
46
+ # the behavioural verify-before-complete rule (#818). Catches the compile/lint
47
+ # errors that reach remote CI "Static Checks" (e.g. TS18048). Runs only when
48
+ # the push touches .ts, so docs-only pushes stay fast. Skip a genuine WIP push
49
+ # with AGENT_CONFIG_SKIP_PREPUSH_STATIC=1 (the agent cannot use --no-verify).
50
+ echo "🔍 Static check on changed TypeScript (typecheck + lint)..."
51
+ if [ "${AGENT_CONFIG_SKIP_PREPUSH_STATIC:-}" = "1" ]; then
52
+ echo "⏭️ skipped via AGENT_CONFIG_SKIP_PREPUSH_STATIC=1"
53
+ else
54
+ base="$(git merge-base HEAD origin/main 2>/dev/null || echo HEAD~1)"
55
+ changed_ts="$(git diff --name-only --diff-filter=d "$base"...HEAD -- '*.ts' 2>/dev/null || true)"
56
+ if [ -n "$changed_ts" ]; then
57
+ if ! npx eslint $changed_ts; then
58
+ echo "❌ ESLint failed on changed TypeScript. Fix before pushing (or AGENT_CONFIG_SKIP_PREPUSH_STATIC=1 for a WIP push)."
59
+ fail=1
60
+ fi
61
+ if ! npm run --silent typecheck; then
62
+ echo "❌ Typecheck (tsc) failed — this is the class of error remote CI 'Static Checks' catches (#818). Fix before pushing."
63
+ fail=1
64
+ fi
65
+ else
66
+ echo "⏭️ no changed .ts vs origin/main — skipping."
67
+ fi
68
+ fi
69
+
45
70
  if [ $fail -ne 0 ]; then
46
71
  echo ""
47
72
  echo " Push blocked — fix the failures above and re-push."
@@ -72,6 +72,7 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
72
72
  import type * as YamlModule from 'yaml';
73
73
 
74
74
  import { build_merge_entries } from './_lib/json_pointers.js';
75
+ import { is_claude_builtin_name } from './_lib/claude_builtin_names.js';
75
76
  import * as installed_lock from './_lib/installed_lock.js';
76
77
  import * as surface_tiers from './_lib/surface_tiers.js';
77
78
  import * as global_deploy_inventory from './_lib/global_deploy_inventory.js';
@@ -2847,15 +2848,40 @@ function _deploy_claude_desktop(
2847
2848
  * discovery (revert = one package release, no per-machine gating).
2848
2849
  * Tier-2/internal flat commands stay command files. A command whose name
2849
2850
  * collides with a real skill is skipped (the skill already owns `/name`).
2851
+ *
2852
+ * Reserved-name floor: a flat `/name` that equals a Claude Code BUILT-IN
2853
+ * command or bundled skill (see `_lib/claude_builtin_names.ts`) would shadow
2854
+ * the built-in — e.g. a `review` wrapper hides Claude Code's own `/review`.
2855
+ * Such slugs get NEITHER a skill wrapper NOR a flat command file on this
2856
+ * anchor (their nested `/cluster:sub` commands are untouched); the flat file
2857
+ * is removed so a future upstream flat-discovery fix cannot resurrect the
2858
+ * shadowing. The suite complements the host — it never overlays built-ins.
2850
2859
  */
2851
2860
  const _CLAUDE_FLAT_WRAPPER_EXTRA = new Set(['commit']); // essential; absent from the manifest
2852
2861
  export function _apply_claude_flat_command_wrappers(
2853
2862
  anchor: string,
2854
2863
  package_root: string,
2855
2864
  current_files: Set<string>,
2856
- ): { wrapped: string[]; collisions: string[] } {
2865
+ ): { wrapped: string[]; collisions: string[]; reserved: string[] } {
2857
2866
  const wrapped: string[] = [];
2858
2867
  const collisions: string[] = [];
2868
+ const reserved: string[] = [];
2869
+ // Reserved-name sweep over ALL flat command files (any tier): a name
2870
+ // shadowing a Claude Code built-in never ships on the claude-code anchor.
2871
+ const commands_dir = path.join(anchor, 'commands');
2872
+ let flat_entries: string[] = [];
2873
+ try {
2874
+ flat_entries = fs.readdirSync(commands_dir).filter((f) => f.endsWith('.md'));
2875
+ } catch {
2876
+ // No commands dir → nothing to sweep.
2877
+ }
2878
+ for (const fname of flat_entries.sort()) {
2879
+ const slug = fname.slice(0, -'.md'.length);
2880
+ if (!is_claude_builtin_name(slug)) continue;
2881
+ fs.rmSync(path.join(commands_dir, fname), { force: true });
2882
+ current_files.delete(`commands/${fname}`);
2883
+ reserved.push(slug);
2884
+ }
2859
2885
  // Tier-0/1 visible command slugs from the locked discovery manifest.
2860
2886
  const eligible = new Set<string>(_CLAUDE_FLAT_WRAPPER_EXTRA);
2861
2887
  try {
@@ -2892,7 +2918,7 @@ export function _apply_claude_flat_command_wrappers(
2892
2918
  current_files.add(`skills/${slug}/SKILL.md`);
2893
2919
  wrapped.push(slug);
2894
2920
  }
2895
- return { wrapped, collisions };
2921
+ return { wrapped, collisions, reserved };
2896
2922
  }
2897
2923
 
2898
2924
  function _deploy_global_content(
@@ -2949,6 +2975,13 @@ function _deploy_global_content(
2949
2975
  'skill wrappers (Claude Code flat-command discovery workaround)',
2950
2976
  );
2951
2977
  }
2978
+ if (res.reserved.length > 0 && !state.QUIET) {
2979
+ info(
2980
+ ` claude-code: ${res.reserved.length} flat command(s) withheld — name is a ` +
2981
+ `Claude Code built-in (${res.reserved.join(', ')}); nested /cluster:sub ` +
2982
+ 'commands remain available',
2983
+ );
2984
+ }
2952
2985
  }
2953
2986
 
2954
2987
  const missing_targets = _verify_deploy_targets(anchor, plan);
Binary file
@@ -14,6 +14,7 @@ import * as path from 'node:path';
14
14
  import { fileURLToPath, pathToFileURL } from 'node:url';
15
15
 
16
16
  import { command_slug } from './_lib/agent_src.js';
17
+ import { is_claude_builtin_name } from './_lib/claude_builtin_names.js';
17
18
 
18
19
  const SCRIPTS_DIR = path.dirname(fileURLToPath(import.meta.url));
19
20
  const ROOT = path.dirname(path.dirname(SCRIPTS_DIR));
@@ -97,6 +98,18 @@ function frontmatterNameFromFile(p: string): string | null {
97
98
  return _frontmatter_name(fs.readFileSync(p, 'utf-8'));
98
99
  }
99
100
 
101
+ const USER_INVOCABLE_FALSE_RE = /^user-invocable:\s*false\s*$/m;
102
+
103
+ /** True when the SKILL.md opts out of slash registration (`user-invocable: false`). */
104
+ export function _opts_out_of_slash(text: string): boolean {
105
+ if (!text.startsWith('---')) {
106
+ return false;
107
+ }
108
+ const end = text.indexOf('\n---', 3);
109
+ const block = end !== -1 ? text.slice(3, end) : text;
110
+ return USER_INVOCABLE_FALSE_RE.test(block);
111
+ }
112
+
100
113
  export function _spec_violation(name: string): string | null {
101
114
  if (name.length > MAX_NAME_LEN) {
102
115
  return `longer than ${MAX_NAME_LEN} chars`;
@@ -178,6 +191,22 @@ export function check_skills(): string[] {
178
191
  'requires the folder name to match the `name:` field',
179
192
  );
180
193
  }
194
+ // Reserved-name floor: a skill named after a Claude Code built-in
195
+ // command / bundled skill shadows the built-in when projected as
196
+ // `/name` (e.g. a `mcp` skill hides Claude Code's own /mcp dialog).
197
+ // Opting out of slash registration (`user-invocable: false`) keeps
198
+ // the skill model-loadable while the host retains the /name.
199
+ // Reserved set: src/scripts/_lib/claude_builtin_names.ts.
200
+ if (
201
+ is_claude_builtin_name(dirname) &&
202
+ !_opts_out_of_slash(fs.readFileSync(md, 'utf-8'))
203
+ ) {
204
+ violations.push(
205
+ `${rel}: \`${dirname}\` is a Claude Code built-in command name — ` +
206
+ 'add `user-invocable: false` (model-only invocation) or rename ' +
207
+ 'the skill; the suite must never shadow a host built-in',
208
+ );
209
+ }
181
210
  }
182
211
  return violations;
183
212
  }