@claude-flow/cli 3.11.0 → 3.12.1

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 (192) hide show
  1. package/dist/src/commands/doctor.d.ts.map +1 -1
  2. package/dist/src/commands/doctor.js +175 -1
  3. package/dist/src/commands/doctor.js.map +1 -1
  4. package/dist/src/commands/eject.d.ts +33 -0
  5. package/dist/src/commands/eject.d.ts.map +1 -0
  6. package/dist/src/commands/eject.js +195 -0
  7. package/dist/src/commands/eject.js.map +1 -0
  8. package/dist/src/commands/hooks.d.ts.map +1 -1
  9. package/dist/src/commands/hooks.js +2 -1
  10. package/dist/src/commands/hooks.js.map +1 -1
  11. package/dist/src/commands/index.d.ts.map +1 -1
  12. package/dist/src/commands/index.js +4 -0
  13. package/dist/src/commands/index.js.map +1 -1
  14. package/dist/src/commands/init.d.ts.map +1 -1
  15. package/dist/src/commands/init.js +3 -0
  16. package/dist/src/commands/init.js.map +1 -1
  17. package/dist/src/commands/metaharness.d.ts +39 -0
  18. package/dist/src/commands/metaharness.d.ts.map +1 -0
  19. package/dist/src/commands/metaharness.js +194 -0
  20. package/dist/src/commands/metaharness.js.map +1 -0
  21. package/dist/src/mcp-client.d.ts.map +1 -1
  22. package/dist/src/mcp-client.js +4 -0
  23. package/dist/src/mcp-client.js.map +1 -1
  24. package/dist/src/mcp-tools/index.d.ts +1 -0
  25. package/dist/src/mcp-tools/index.d.ts.map +1 -1
  26. package/dist/src/mcp-tools/index.js +2 -0
  27. package/dist/src/mcp-tools/index.js.map +1 -1
  28. package/dist/src/mcp-tools/metaharness-tools.d.ts +31 -0
  29. package/dist/src/mcp-tools/metaharness-tools.d.ts.map +1 -0
  30. package/dist/src/mcp-tools/metaharness-tools.js +372 -0
  31. package/dist/src/mcp-tools/metaharness-tools.js.map +1 -0
  32. package/dist/src/plugins/store/discovery.d.ts.map +1 -1
  33. package/dist/src/plugins/store/discovery.js +3 -0
  34. package/dist/src/plugins/store/discovery.js.map +1 -1
  35. package/dist/src/plugins/store/types.d.ts +6 -1
  36. package/dist/src/plugins/store/types.d.ts.map +1 -1
  37. package/dist/src/ruvector/model-router.d.ts.map +1 -1
  38. package/dist/src/ruvector/model-router.js +37 -0
  39. package/dist/src/ruvector/model-router.js.map +1 -1
  40. package/dist/src/ruvector/router-parallel-recorder.d.ts +127 -0
  41. package/dist/src/ruvector/router-parallel-recorder.d.ts.map +1 -0
  42. package/dist/src/ruvector/router-parallel-recorder.js +183 -0
  43. package/dist/src/ruvector/router-parallel-recorder.js.map +1 -0
  44. package/dist/tsconfig.tsbuildinfo +1 -1
  45. package/package.json +13 -10
  46. package/plugins/ruflo-metaharness/.claude-flow/data/pending-insights.jsonl +1 -0
  47. package/plugins/ruflo-metaharness/.claude-flow/neural/stats.json +6 -0
  48. package/plugins/ruflo-metaharness/.claude-plugin/plugin.json +32 -0
  49. package/plugins/ruflo-metaharness/README.md +64 -0
  50. package/plugins/ruflo-metaharness/agents/metaharness-architect.md +58 -0
  51. package/plugins/ruflo-metaharness/commands/ruflo-metaharness.md +46 -0
  52. package/plugins/ruflo-metaharness/scripts/_harness.mjs +261 -0
  53. package/plugins/ruflo-metaharness/scripts/_similarity.mjs +161 -0
  54. package/plugins/ruflo-metaharness/scripts/_spike-similarity.mjs +223 -0
  55. package/plugins/ruflo-metaharness/scripts/audit-list.mjs +158 -0
  56. package/plugins/ruflo-metaharness/scripts/audit-trend.mjs +272 -0
  57. package/plugins/ruflo-metaharness/scripts/bench-parse-mcp-scan.mjs +146 -0
  58. package/plugins/ruflo-metaharness/scripts/bench-recordpair-overhead.mjs +186 -0
  59. package/plugins/ruflo-metaharness/scripts/bench-similarity.mjs +177 -0
  60. package/plugins/ruflo-metaharness/scripts/drift-from-history.mjs +363 -0
  61. package/plugins/ruflo-metaharness/scripts/genome.mjs +80 -0
  62. package/plugins/ruflo-metaharness/scripts/mcp-scan.mjs +111 -0
  63. package/plugins/ruflo-metaharness/scripts/mint.mjs +119 -0
  64. package/plugins/ruflo-metaharness/scripts/oia-audit.mjs +228 -0
  65. package/plugins/ruflo-metaharness/scripts/router-parallel-analyze.mjs +250 -0
  66. package/plugins/ruflo-metaharness/scripts/score.mjs +92 -0
  67. package/plugins/ruflo-metaharness/scripts/similarity.mjs +158 -0
  68. package/plugins/ruflo-metaharness/scripts/smoke.sh +2268 -0
  69. package/plugins/ruflo-metaharness/scripts/test-graceful-degradation.mjs +141 -0
  70. package/plugins/ruflo-metaharness/scripts/test-mcp-tools.mjs +437 -0
  71. package/plugins/ruflo-metaharness/scripts/test-parallel-pipeline.mjs +204 -0
  72. package/plugins/ruflo-metaharness/scripts/test-pipeline-roundtrip.mjs +586 -0
  73. package/plugins/ruflo-metaharness/scripts/test-similarity.mjs +334 -0
  74. package/plugins/ruflo-metaharness/scripts/test-with-openrouter.mjs +229 -0
  75. package/plugins/ruflo-metaharness/scripts/threat-model.mjs +59 -0
  76. package/plugins/ruflo-metaharness/skills/harness-drift-from-history/SKILL.md +65 -0
  77. package/plugins/ruflo-metaharness/skills/harness-genome/SKILL.md +54 -0
  78. package/plugins/ruflo-metaharness/skills/harness-mcp-scan/SKILL.md +47 -0
  79. package/plugins/ruflo-metaharness/skills/harness-mint/SKILL.md +72 -0
  80. package/plugins/ruflo-metaharness/skills/harness-oia-audit/SKILL.md +79 -0
  81. package/plugins/ruflo-metaharness/skills/harness-score/SKILL.md +66 -0
  82. package/plugins/ruflo-metaharness/skills/harness-similarity/SKILL.md +67 -0
  83. package/plugins/ruflo-metaharness/skills/harness-threat-model/SKILL.md +39 -0
  84. package/dist/src/benchmarks/capability-tasks.d.ts +0 -126
  85. package/dist/src/benchmarks/capability-tasks.d.ts.map +0 -1
  86. package/dist/src/benchmarks/capability-tasks.js +0 -147
  87. package/dist/src/benchmarks/capability-tasks.js.map +0 -1
  88. package/dist/src/benchmarks/gaia-agent-contrastive.d.ts +0 -53
  89. package/dist/src/benchmarks/gaia-agent-contrastive.d.ts.map +0 -1
  90. package/dist/src/benchmarks/gaia-agent-contrastive.js +0 -177
  91. package/dist/src/benchmarks/gaia-agent-contrastive.js.map +0 -1
  92. package/dist/src/benchmarks/gaia-agent-gemini.d.ts +0 -51
  93. package/dist/src/benchmarks/gaia-agent-gemini.d.ts.map +0 -1
  94. package/dist/src/benchmarks/gaia-agent-gemini.js +0 -352
  95. package/dist/src/benchmarks/gaia-agent-gemini.js.map +0 -1
  96. package/dist/src/benchmarks/gaia-claude-p.d.ts +0 -105
  97. package/dist/src/benchmarks/gaia-claude-p.d.ts.map +0 -1
  98. package/dist/src/benchmarks/gaia-claude-p.js +0 -269
  99. package/dist/src/benchmarks/gaia-claude-p.js.map +0 -1
  100. package/dist/src/benchmarks/gaia-claude-p.smoke.d.ts +0 -20
  101. package/dist/src/benchmarks/gaia-claude-p.smoke.d.ts.map +0 -1
  102. package/dist/src/benchmarks/gaia-claude-p.smoke.js +0 -168
  103. package/dist/src/benchmarks/gaia-claude-p.smoke.js.map +0 -1
  104. package/dist/src/benchmarks/gaia-codeagent-runner.py +0 -556
  105. package/dist/src/benchmarks/gaia-codeagent.d.ts +0 -129
  106. package/dist/src/benchmarks/gaia-codeagent.d.ts.map +0 -1
  107. package/dist/src/benchmarks/gaia-codeagent.js +0 -590
  108. package/dist/src/benchmarks/gaia-codeagent.js.map +0 -1
  109. package/dist/src/benchmarks/gaia-codeagent.smoke.d.ts +0 -33
  110. package/dist/src/benchmarks/gaia-codeagent.smoke.d.ts.map +0 -1
  111. package/dist/src/benchmarks/gaia-codeagent.smoke.js +0 -241
  112. package/dist/src/benchmarks/gaia-codeagent.smoke.js.map +0 -1
  113. package/dist/src/benchmarks/gaia-dag-pilot.d.ts +0 -22
  114. package/dist/src/benchmarks/gaia-dag-pilot.d.ts.map +0 -1
  115. package/dist/src/benchmarks/gaia-dag-pilot.js +0 -158
  116. package/dist/src/benchmarks/gaia-dag-pilot.js.map +0 -1
  117. package/dist/src/benchmarks/gaia-dag.d.ts +0 -110
  118. package/dist/src/benchmarks/gaia-dag.d.ts.map +0 -1
  119. package/dist/src/benchmarks/gaia-dag.js +0 -658
  120. package/dist/src/benchmarks/gaia-dag.js.map +0 -1
  121. package/dist/src/benchmarks/gaia-dag.smoke.d.ts +0 -21
  122. package/dist/src/benchmarks/gaia-dag.smoke.d.ts.map +0 -1
  123. package/dist/src/benchmarks/gaia-dag.smoke.js +0 -290
  124. package/dist/src/benchmarks/gaia-dag.smoke.js.map +0 -1
  125. package/dist/src/benchmarks/gaia-ensemble-pilot.d.ts +0 -17
  126. package/dist/src/benchmarks/gaia-ensemble-pilot.d.ts.map +0 -1
  127. package/dist/src/benchmarks/gaia-ensemble-pilot.js +0 -106
  128. package/dist/src/benchmarks/gaia-ensemble-pilot.js.map +0 -1
  129. package/dist/src/benchmarks/gaia-ensemble.d.ts +0 -103
  130. package/dist/src/benchmarks/gaia-ensemble.d.ts.map +0 -1
  131. package/dist/src/benchmarks/gaia-ensemble.js +0 -462
  132. package/dist/src/benchmarks/gaia-ensemble.js.map +0 -1
  133. package/dist/src/benchmarks/gaia-gemini-pilot.d.ts +0 -17
  134. package/dist/src/benchmarks/gaia-gemini-pilot.d.ts.map +0 -1
  135. package/dist/src/benchmarks/gaia-gemini-pilot.js +0 -168
  136. package/dist/src/benchmarks/gaia-gemini-pilot.js.map +0 -1
  137. package/dist/src/benchmarks/gaia-mode-router.d.ts +0 -67
  138. package/dist/src/benchmarks/gaia-mode-router.d.ts.map +0 -1
  139. package/dist/src/benchmarks/gaia-mode-router.js +0 -126
  140. package/dist/src/benchmarks/gaia-mode-router.js.map +0 -1
  141. package/dist/src/benchmarks/gaia-mode-router.smoke.d.ts +0 -15
  142. package/dist/src/benchmarks/gaia-mode-router.smoke.d.ts.map +0 -1
  143. package/dist/src/benchmarks/gaia-mode-router.smoke.js +0 -131
  144. package/dist/src/benchmarks/gaia-mode-router.smoke.js.map +0 -1
  145. package/dist/src/benchmarks/gaia-tools/grounded_query.smoke.d.ts +0 -24
  146. package/dist/src/benchmarks/gaia-tools/grounded_query.smoke.d.ts.map +0 -1
  147. package/dist/src/benchmarks/gaia-tools/grounded_query.smoke.js +0 -276
  148. package/dist/src/benchmarks/gaia-tools/grounded_query.smoke.js.map +0 -1
  149. package/dist/src/benchmarks/gaia-tools/image_describe.d.ts +0 -45
  150. package/dist/src/benchmarks/gaia-tools/image_describe.d.ts.map +0 -1
  151. package/dist/src/benchmarks/gaia-tools/image_describe.js +0 -222
  152. package/dist/src/benchmarks/gaia-tools/image_describe.js.map +0 -1
  153. package/dist/src/benchmarks/gaia-tools/image_describe.smoke.d.ts +0 -24
  154. package/dist/src/benchmarks/gaia-tools/image_describe.smoke.d.ts.map +0 -1
  155. package/dist/src/benchmarks/gaia-tools/image_describe.smoke.js +0 -169
  156. package/dist/src/benchmarks/gaia-tools/image_describe.smoke.js.map +0 -1
  157. package/dist/src/benchmarks/gaia-tools/pdf_read.d.ts +0 -27
  158. package/dist/src/benchmarks/gaia-tools/pdf_read.d.ts.map +0 -1
  159. package/dist/src/benchmarks/gaia-tools/pdf_read.js +0 -226
  160. package/dist/src/benchmarks/gaia-tools/pdf_read.js.map +0 -1
  161. package/dist/src/benchmarks/gaia-tools/python_exec.d.ts +0 -31
  162. package/dist/src/benchmarks/gaia-tools/python_exec.d.ts.map +0 -1
  163. package/dist/src/benchmarks/gaia-tools/python_exec.js +0 -94
  164. package/dist/src/benchmarks/gaia-tools/python_exec.js.map +0 -1
  165. package/dist/src/benchmarks/gaia-tools/python_exec.smoke.d.ts +0 -13
  166. package/dist/src/benchmarks/gaia-tools/python_exec.smoke.d.ts.map +0 -1
  167. package/dist/src/benchmarks/gaia-tools/python_exec.smoke.js +0 -98
  168. package/dist/src/benchmarks/gaia-tools/python_exec.smoke.js.map +0 -1
  169. package/dist/src/benchmarks/gaia-tools/visit_webpage.d.ts +0 -52
  170. package/dist/src/benchmarks/gaia-tools/visit_webpage.d.ts.map +0 -1
  171. package/dist/src/benchmarks/gaia-tools/visit_webpage.js +0 -304
  172. package/dist/src/benchmarks/gaia-tools/visit_webpage.js.map +0 -1
  173. package/dist/src/benchmarks/gaia-tools/web_browse.d.ts +0 -61
  174. package/dist/src/benchmarks/gaia-tools/web_browse.d.ts.map +0 -1
  175. package/dist/src/benchmarks/gaia-tools/web_browse.js +0 -217
  176. package/dist/src/benchmarks/gaia-tools/web_browse.js.map +0 -1
  177. package/dist/src/benchmarks/gaia-tools/web_browse.smoke.d.ts +0 -26
  178. package/dist/src/benchmarks/gaia-tools/web_browse.smoke.d.ts.map +0 -1
  179. package/dist/src/benchmarks/gaia-tools/web_browse.smoke.js +0 -152
  180. package/dist/src/benchmarks/gaia-tools/web_browse.smoke.js.map +0 -1
  181. package/dist/src/benchmarks/gaia-tools/web_search.smoke.d.ts +0 -24
  182. package/dist/src/benchmarks/gaia-tools/web_search.smoke.d.ts.map +0 -1
  183. package/dist/src/benchmarks/gaia-tools/web_search.smoke.js +0 -311
  184. package/dist/src/benchmarks/gaia-tools/web_search.smoke.js.map +0 -1
  185. package/dist/src/benchmarks/gaia-visit-webpage.smoke.d.ts +0 -25
  186. package/dist/src/benchmarks/gaia-visit-webpage.smoke.d.ts.map +0 -1
  187. package/dist/src/benchmarks/gaia-visit-webpage.smoke.js +0 -304
  188. package/dist/src/benchmarks/gaia-visit-webpage.smoke.js.map +0 -1
  189. package/dist/src/commands/performance-capability.d.ts +0 -30
  190. package/dist/src/commands/performance-capability.d.ts.map +0 -1
  191. package/dist/src/commands/performance-capability.js +0 -349
  192. package/dist/src/commands/performance-capability.js.map +0 -1
@@ -0,0 +1,161 @@
1
+ // _similarity.mjs — ADR-152 production similarity module.
2
+ //
3
+ // Graduated from `_spike-similarity.mjs` (iter 35) after both invariants
4
+ // passed on the LEGAL/SUPPORT/DEVOPS fixtures. The spike file STAYS as
5
+ // the regression-suite anchor; this file is what production callers
6
+ // (`similarity.mjs` skill, `metaharness_similarity` MCP tool) import.
7
+ //
8
+ // ADR-150 ARCHITECTURAL CONSTRAINTS PRESERVED
9
+ // Removable ✓ pure-TS — no `@metaharness/*` import path
10
+ // Optional ✓ no new dep on `@metaharness/*`
11
+ // Graceful ✓ malformed input → low-confidence output, never throws
12
+ // CI-gate ✓ standalone unit-importable; no `npx` needed
13
+ //
14
+ // CONTRACT (PUBLIC)
15
+ // projectToVec(input) → 9-dim numerical feature vector
16
+ // cosine(a, b) → [0,1]
17
+ // categoricalAgreement(a, b) → [0,1] over 4 enum fields
18
+ // jaccard(a, b) → [0,1] over agent_topology[]
19
+ // similarity(a, b, opts?) → { overall, components, perDimension? }
20
+ //
21
+ // WEIGHT DEFAULTS (from ADR-152 §Decision)
22
+ // overall = 0.60·cosine + 0.25·categorical + 0.15·jaccard
23
+ //
24
+ // ADR-152 reserves a future per-org weight override; for §3.1 the defaults
25
+ // are global. The opts.weights hook is here so consumers can experiment
26
+ // without forking the module — it is NOT a stable public API.
27
+
28
+ const DEFAULT_WEIGHTS = Object.freeze({ cosine: 0.6, categorical: 0.25, jaccard: 0.15 });
29
+
30
+ const CATEGORICAL_FIELDS = Object.freeze(['repo_type', 'archetype', 'template', 'recommendedMode']);
31
+
32
+ // ─────────────────────────────────────────────────────────────────────
33
+ // 9-dim feature vector. The mapping mirrors ADR-152 §Decision Table 1.
34
+ // Missing fields default to 0 — that's the graceful-degradation path.
35
+ // ─────────────────────────────────────────────────────────────────────
36
+
37
+ export function projectToVec(input) {
38
+ const s = input?.score ?? {};
39
+ const g = input?.genome ?? {};
40
+ return [
41
+ (s.harnessFit ?? 0) / 100,
42
+ (s.compileConfidence ?? 0) / 100,
43
+ (s.taskCoverage ?? 0) / 100,
44
+ (s.toolSafety ?? 0) / 100,
45
+ (s.memoryUsefulness ?? 0) / 100,
46
+ g.risk_score ?? 0,
47
+ g.test_confidence ?? 0,
48
+ g.publish_readiness ?? 0,
49
+ Math.max(0, Math.min(1, Math.log10((s.estCostPerRunUsd ?? 0) + 0.001) / Math.log10(10))),
50
+ ];
51
+ }
52
+
53
+ export function cosine(a, b) {
54
+ if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) return 0;
55
+ let dot = 0, na = 0, nb = 0;
56
+ for (let i = 0; i < a.length; i++) {
57
+ dot += a[i] * b[i];
58
+ na += a[i] * a[i];
59
+ nb += b[i] * b[i];
60
+ }
61
+ const denom = Math.sqrt(na) * Math.sqrt(nb);
62
+ if (denom === 0) return 0;
63
+ return Math.max(0, Math.min(1, dot / denom));
64
+ }
65
+
66
+ export function categoricalAgreement(a, b) {
67
+ let matches = 0;
68
+ for (const f of CATEGORICAL_FIELDS) {
69
+ const av = a?.genome?.[f] ?? a?.score?.[f];
70
+ const bv = b?.genome?.[f] ?? b?.score?.[f];
71
+ if (av && bv && av === bv) matches++;
72
+ }
73
+ return matches / CATEGORICAL_FIELDS.length;
74
+ }
75
+
76
+ export function jaccard(a, b) {
77
+ const A = new Set(a?.genome?.agent_topology ?? []);
78
+ const B = new Set(b?.genome?.agent_topology ?? []);
79
+ if (A.size === 0 && B.size === 0) return 1;
80
+ const intersection = [...A].filter((x) => B.has(x)).length;
81
+ const union = new Set([...A, ...B]).size;
82
+ return union === 0 ? 0 : intersection / union;
83
+ }
84
+
85
+ // ─────────────────────────────────────────────────────────────────────
86
+ // Composite similarity with optional per-dimension breakdown.
87
+ // Returns the ADR-152 §"return shape": overall + components + per-dim.
88
+ // ─────────────────────────────────────────────────────────────────────
89
+
90
+ export function similarity(a, b, opts = {}) {
91
+ const weights = { ...DEFAULT_WEIGHTS, ...(opts.weights ?? {}) };
92
+ const va = projectToVec(a);
93
+ const vb = projectToVec(b);
94
+ const cos = cosine(va, vb);
95
+ const cat = categoricalAgreement(a, b);
96
+ const jac = jaccard(a, b);
97
+
98
+ const overall = weights.cosine * cos + weights.categorical * cat + weights.jaccard * jac;
99
+
100
+ const result = {
101
+ overall: round4(overall),
102
+ components: {
103
+ cosine: round4(cos),
104
+ categorical: round4(cat),
105
+ jaccard: round4(jac),
106
+ },
107
+ weights,
108
+ };
109
+
110
+ if (opts.perDimension) {
111
+ result.perDimension = perDimensionBreakdown(a, b, va, vb, weights);
112
+ }
113
+ return result;
114
+ }
115
+
116
+ function round4(x) {
117
+ return Math.round(x * 10000) / 10000;
118
+ }
119
+
120
+ function perDimensionBreakdown(a, b, va, vb, weights) {
121
+ // Per-dimension contribution = squared-error-normalized cosine slice + categorical/jaccard direct.
122
+ // We surface raw a/b values + a contribution sign so callers can explain
123
+ // why two harnesses scored as they did (used by Recommendation Engine
124
+ // §3.2 confidence calc + Drift Detection §3.3 alert reason).
125
+ const out = {};
126
+
127
+ const numericKeys = [
128
+ ['harnessFit', 'score', 100], ['compileConfidence', 'score', 100],
129
+ ['taskCoverage', 'score', 100], ['toolSafety', 'score', 100],
130
+ ['memoryUsefulness', 'score', 100],
131
+ ['risk_score', 'genome', 1], ['test_confidence', 'genome', 1],
132
+ ['publish_readiness', 'genome', 1],
133
+ ['estCostPerRunUsd', 'score', 1],
134
+ ];
135
+ for (let i = 0; i < numericKeys.length; i++) {
136
+ const [k, src] = numericKeys[i];
137
+ const av = a?.[src]?.[k];
138
+ const bv = b?.[src]?.[k];
139
+ out[`numeric.${k}`] = {
140
+ a: av ?? null, b: bv ?? null,
141
+ contribution: round4(va[i] * vb[i] * weights.cosine / 9),
142
+ };
143
+ }
144
+ for (const f of CATEGORICAL_FIELDS) {
145
+ const av = a?.genome?.[f] ?? a?.score?.[f];
146
+ const bv = b?.genome?.[f] ?? b?.score?.[f];
147
+ out[`categorical.${f}`] = {
148
+ a: av ?? null, b: bv ?? null,
149
+ contribution: av && bv && av === bv ? round4(weights.categorical / 4) : 0,
150
+ };
151
+ }
152
+ const A = new Set(a?.genome?.agent_topology ?? []);
153
+ const B = new Set(b?.genome?.agent_topology ?? []);
154
+ const overlap = [...A].filter((x) => B.has(x));
155
+ const union = new Set([...A, ...B]);
156
+ out['set.agent_topology'] = {
157
+ a: [...A], b: [...B],
158
+ contribution: union.size === 0 ? 0 : round4((overlap.length / union.size) * weights.jaccard),
159
+ };
160
+ return out;
161
+ }
@@ -0,0 +1,223 @@
1
+ #!/usr/bin/env node
2
+ // _spike-similarity.mjs — ADR-152 §"Smallest demonstrable spike" gate.
3
+ //
4
+ // This file is the implementation gate for ADR-152 (Genome Similarity Search).
5
+ // Per ADR-151's scope-only constraint, ADR-152 cannot graduate to "Accepted"
6
+ // until the two invariants below are proven by running this script.
7
+ //
8
+ // THE TWO INVARIANTS (from ADR-152 §"Smallest demonstrable spike")
9
+ // 1. similarity(X, X) === 1 (self-match exact)
10
+ // 2. similarity(legal, devops) < similarity(legal, support)
11
+ // (vertical-affinity correct)
12
+ //
13
+ // USAGE
14
+ // node scripts/_spike-similarity.mjs (run + assert)
15
+ // node scripts/_spike-similarity.mjs --format json (CI-consumable)
16
+ //
17
+ // EXIT CODES
18
+ // 0 both invariants hold
19
+ // 1 at least one invariant fails (ADR-152 cannot graduate)
20
+ //
21
+ // LIFECYCLE
22
+ // Once ADR-152 is Accepted, the full similarity implementation lands in
23
+ // `_similarity.mjs` (production module). This file (`_spike-similarity.mjs`)
24
+ // remains as the regression-suite anchor for the two invariants.
25
+
26
+ const ARGS = (() => {
27
+ const a = { format: 'table' };
28
+ for (let i = 2; i < process.argv.length; i++) {
29
+ if (process.argv[i] === '--format') a.format = process.argv[++i];
30
+ }
31
+ return a;
32
+ })();
33
+
34
+ // ──────────────────────────────────────────────────────────────────────
35
+ // THE PROPOSED IMPLEMENTATION (ADR-152 §"Decision")
36
+ //
37
+ // Pure-TS. Takes two {genome, score} JSON shapes; emits {overall,
38
+ // components: {cosine, categorical, jaccard}}. The 9 numerical features +
39
+ // 4 categorical fields + 1 set field per ADR-152.
40
+ // ──────────────────────────────────────────────────────────────────────
41
+
42
+ function projectToVec(input) {
43
+ const s = input.score || {};
44
+ const g = input.genome || {};
45
+ return [
46
+ (s.harnessFit ?? 0) / 100,
47
+ (s.compileConfidence ?? 0) / 100,
48
+ (s.taskCoverage ?? 0) / 100,
49
+ (s.toolSafety ?? 0) / 100,
50
+ (s.memoryUsefulness ?? 0) / 100,
51
+ g.risk_score ?? 0,
52
+ g.test_confidence ?? 0,
53
+ g.publish_readiness ?? 0,
54
+ // estCostPerRunUsd: log10 transform, clamped to [0, 1]
55
+ Math.max(0, Math.min(1, Math.log10((s.estCostPerRunUsd ?? 0) + 0.001) / Math.log10(10))),
56
+ ];
57
+ }
58
+
59
+ function cosine(a, b) {
60
+ let dot = 0, na = 0, nb = 0;
61
+ for (let i = 0; i < a.length; i++) {
62
+ dot += a[i] * b[i];
63
+ na += a[i] * a[i];
64
+ nb += b[i] * b[i];
65
+ }
66
+ const denom = Math.sqrt(na) * Math.sqrt(nb);
67
+ if (denom === 0) return 0;
68
+ // Map cosine from [-1, 1] to [0, 1] for nonnegative vectors it's [0, 1] already
69
+ return Math.max(0, Math.min(1, dot / denom));
70
+ }
71
+
72
+ function categoricalAgreement(a, b) {
73
+ const fields = ['repo_type', 'archetype', 'template', 'recommendedMode'];
74
+ let matches = 0;
75
+ for (const f of fields) {
76
+ const av = a.genome?.[f] ?? a.score?.[f];
77
+ const bv = b.genome?.[f] ?? b.score?.[f];
78
+ if (av && bv && av === bv) matches++;
79
+ }
80
+ return matches / fields.length;
81
+ }
82
+
83
+ function jaccard(a, b) {
84
+ const A = new Set(a.genome?.agent_topology ?? []);
85
+ const B = new Set(b.genome?.agent_topology ?? []);
86
+ if (A.size === 0 && B.size === 0) return 1;
87
+ const intersection = [...A].filter((x) => B.has(x)).length;
88
+ const union = new Set([...A, ...B]).size;
89
+ return union === 0 ? 0 : intersection / union;
90
+ }
91
+
92
+ function similarity(a, b) {
93
+ const cos = cosine(projectToVec(a), projectToVec(b));
94
+ const cat = categoricalAgreement(a, b);
95
+ const jac = jaccard(a, b);
96
+ const overall = 0.6 * cos + 0.25 * cat + 0.15 * jac;
97
+ return {
98
+ overall: Math.round(overall * 10000) / 10000,
99
+ components: {
100
+ cosine: Math.round(cos * 10000) / 10000,
101
+ categorical: Math.round(cat * 10000) / 10000,
102
+ jaccard: Math.round(jac * 10000) / 10000,
103
+ },
104
+ };
105
+ }
106
+
107
+ // ──────────────────────────────────────────────────────────────────────
108
+ // THREE SYNTHETIC FIXTURES designed to exercise the invariants. These
109
+ // mirror the JSON shapes `harness genome` + `harness score` emit (verified
110
+ // against metaharness@0.1.14 via iter-26 test-with-openrouter.mjs).
111
+ // ──────────────────────────────────────────────────────────────────────
112
+
113
+ const LEGAL = {
114
+ score: {
115
+ harnessFit: 78, compileConfidence: 92, taskCoverage: 65,
116
+ toolSafety: 88, memoryUsefulness: 70, estCostPerRunUsd: 0.04,
117
+ recommendedMode: 'CLI + MCP', archetype: 'compliance-harness',
118
+ template: 'vertical:legal', scaffoldReady: true,
119
+ },
120
+ genome: {
121
+ repo_type: 'node_mcp_ci',
122
+ agent_topology: ['contract-analyst', 'redline-reviewer', 'risk-rater', 'compliance-officer'],
123
+ risk_score: 0.45,
124
+ mcp_surface: 'remote',
125
+ test_confidence: 0.7,
126
+ publish_readiness: 0.6,
127
+ },
128
+ };
129
+
130
+ const SUPPORT = {
131
+ score: {
132
+ harnessFit: 75, compileConfidence: 90, taskCoverage: 70,
133
+ toolSafety: 90, memoryUsefulness: 72, estCostPerRunUsd: 0.05,
134
+ recommendedMode: 'CLI + MCP', archetype: 'compliance-harness',
135
+ template: 'vertical:support', scaffoldReady: true,
136
+ },
137
+ genome: {
138
+ repo_type: 'node_mcp_ci',
139
+ agent_topology: ['triager', 'kb-searcher', 'responder', 'risk-rater', 'compliance-officer'],
140
+ risk_score: 0.40,
141
+ mcp_surface: 'remote',
142
+ test_confidence: 0.75,
143
+ publish_readiness: 0.65,
144
+ },
145
+ };
146
+
147
+ const DEVOPS = {
148
+ score: {
149
+ harnessFit: 88, compileConfidence: 95, taskCoverage: 85,
150
+ toolSafety: 70, memoryUsefulness: 55, estCostPerRunUsd: 0.08,
151
+ recommendedMode: 'CLI', archetype: 'cli-operator-harness',
152
+ template: 'vertical:devops', scaffoldReady: true,
153
+ },
154
+ genome: {
155
+ repo_type: 'python_ops',
156
+ agent_topology: ['incident-commander', 'deployer', 'rollback', 'oncall-pager'],
157
+ risk_score: 0.25,
158
+ mcp_surface: 'local',
159
+ test_confidence: 0.85,
160
+ publish_readiness: 0.9,
161
+ },
162
+ };
163
+
164
+ // ──────────────────────────────────────────────────────────────────────
165
+ // INVARIANT VERIFICATION (the gate)
166
+ // ──────────────────────────────────────────────────────────────────────
167
+
168
+ const self = similarity(LEGAL, LEGAL);
169
+ const legalVsSupport = similarity(LEGAL, SUPPORT);
170
+ const legalVsDevops = similarity(LEGAL, DEVOPS);
171
+
172
+ const inv1Pass = self.overall === 1;
173
+ const inv2Pass = legalVsDevops.overall < legalVsSupport.overall;
174
+
175
+ const payload = {
176
+ adr: 'ADR-152',
177
+ spike: '_spike-similarity.mjs',
178
+ invariants: {
179
+ selfMatch: { pass: inv1Pass, value: self.overall, expected: 1 },
180
+ verticalAffinity: {
181
+ pass: inv2Pass,
182
+ legalVsDevops: legalVsDevops.overall,
183
+ legalVsSupport: legalVsSupport.overall,
184
+ reason: inv2Pass
185
+ ? `legal:devops (${legalVsDevops.overall}) < legal:support (${legalVsSupport.overall}) — vertical affinity correct`
186
+ : `INVARIANT VIOLATED: legal:devops (${legalVsDevops.overall}) ≥ legal:support (${legalVsSupport.overall})`,
187
+ },
188
+ },
189
+ detail: {
190
+ 'similarity(LEGAL, LEGAL)': self,
191
+ 'similarity(LEGAL, SUPPORT)': legalVsSupport,
192
+ 'similarity(LEGAL, DEVOPS)': legalVsDevops,
193
+ },
194
+ graduates: inv1Pass && inv2Pass,
195
+ generatedAt: new Date().toISOString(),
196
+ };
197
+
198
+ if (ARGS.format === 'json') {
199
+ console.log(JSON.stringify(payload, null, 2));
200
+ } else {
201
+ console.log(`# ADR-152 §Spike — Genome Similarity Search\n`);
202
+ console.log(`Invariant 1 — selfMatch:`);
203
+ console.log(` similarity(LEGAL, LEGAL).overall = ${self.overall}`);
204
+ console.log(` expected: 1`);
205
+ console.log(` ${inv1Pass ? '✓ PASS' : '✗ FAIL'}`);
206
+ console.log('');
207
+ console.log(`Invariant 2 — verticalAffinity (legal closer to support than to devops):`);
208
+ console.log(` similarity(LEGAL, SUPPORT).overall = ${legalVsSupport.overall}`);
209
+ console.log(` similarity(LEGAL, DEVOPS).overall = ${legalVsDevops.overall}`);
210
+ console.log(` ${inv2Pass ? '✓ PASS' : '✗ FAIL'} — ${payload.invariants.verticalAffinity.reason}`);
211
+ console.log('');
212
+ console.log(`Per-component breakdown:`);
213
+ console.log(` LEGAL vs SUPPORT — cosine=${legalVsSupport.components.cosine} categorical=${legalVsSupport.components.categorical} jaccard=${legalVsSupport.components.jaccard}`);
214
+ console.log(` LEGAL vs DEVOPS — cosine=${legalVsDevops.components.cosine} categorical=${legalVsDevops.components.categorical} jaccard=${legalVsDevops.components.jaccard}`);
215
+ console.log('');
216
+ if (payload.graduates) {
217
+ console.log(`✓ Both invariants hold. ADR-152 may graduate Proposed → Accepted.`);
218
+ } else {
219
+ console.log(`✗ Invariant violation. ADR-152 stays Proposed.`);
220
+ }
221
+ }
222
+
223
+ if (!payload.graduates) process.exit(1);
@@ -0,0 +1,158 @@
1
+ #!/usr/bin/env node
2
+ // audit-list.mjs — list timestamped oia-audit records from the
3
+ // `metaharness-audit` memory namespace.
4
+ //
5
+ // The iter-7 oia-audit worker writes one record per run (keyed by ISO
6
+ // timestamp). This script enumerates them so operators can see audit
7
+ // cadence, spot gaps, and pick keys to feed into audit-trend.mjs.
8
+ //
9
+ // USAGE
10
+ // node scripts/audit-list.mjs # most recent 20
11
+ // node scripts/audit-list.mjs --limit 50
12
+ // node scripts/audit-list.mjs --format json
13
+ // node scripts/audit-list.mjs --since 30d # last N days
14
+ //
15
+ // EXIT CODES
16
+ // 0 ok
17
+ // 2 config error
18
+
19
+ import { spawnSync } from 'node:child_process';
20
+
21
+ const NS = process.env.AUDIT_LIST_NAMESPACE || 'metaharness-audit';
22
+ const CLI_PKG = process.env.CLI_CORE === '1'
23
+ ? '@claude-flow/cli-core@alpha'
24
+ : '@claude-flow/cli@latest';
25
+
26
+ const ARGS = (() => {
27
+ const a = { limit: 20, since: null, format: 'table' };
28
+ for (let i = 2; i < process.argv.length; i++) {
29
+ const v = process.argv[i];
30
+ if (v === '--limit') a.limit = parseInt(process.argv[++i], 10);
31
+ else if (v === '--since') a.since = process.argv[++i];
32
+ else if (v === '--format') a.format = process.argv[++i];
33
+ }
34
+ return a;
35
+ })();
36
+
37
+ function parseDurationMs(spec) {
38
+ const m = /^(\d+)([hdwm])$/.exec(spec);
39
+ if (!m) return null;
40
+ const n = parseInt(m[1], 10);
41
+ const unit = { h: 3600_000, d: 86400_000, w: 7 * 86400_000, m: 30 * 86400_000 }[m[2]];
42
+ return unit ? n * unit : null;
43
+ }
44
+
45
+ function memList() {
46
+ const r = spawnSync('npx', [
47
+ CLI_PKG, 'memory', 'list',
48
+ '--namespace', NS, '--format', 'json',
49
+ ], { stdio: ['ignore', 'pipe', 'pipe'], encoding: 'utf-8', shell: process.platform === 'win32' });
50
+ if (r.status !== 0) return [];
51
+ const m = /\[[\s\S]*\]/.exec(r.stdout || '');
52
+ if (!m) return [];
53
+ try { return JSON.parse(m[0]); } catch { return []; }
54
+ }
55
+
56
+ function memRetrieve(key) {
57
+ const r = spawnSync('npx', [
58
+ CLI_PKG, 'memory', 'retrieve',
59
+ '--namespace', NS, '--key', key,
60
+ ], { stdio: ['ignore', 'pipe', 'pipe'], encoding: 'utf-8', shell: process.platform === 'win32' });
61
+ if (r.status !== 0) return null;
62
+ const m = /\{[\s\S]*\}/.exec(r.stdout || '');
63
+ if (!m) return null;
64
+ try { return JSON.parse(m[0]); } catch { return null; }
65
+ }
66
+
67
+ function main() {
68
+ if (!Number.isInteger(ARGS.limit) || ARGS.limit < 1) {
69
+ console.error(`audit-list: --limit must be a positive integer`);
70
+ process.exit(2);
71
+ }
72
+ let cutoffMs = null;
73
+ if (ARGS.since) {
74
+ const ms = parseDurationMs(ARGS.since);
75
+ if (!ms) {
76
+ console.error(`audit-list: --since must be N(h|d|w|m); got ${ARGS.since}`);
77
+ process.exit(2);
78
+ }
79
+ cutoffMs = Date.now() - ms;
80
+ }
81
+
82
+ const entries = memList()
83
+ .map((e) => e.key)
84
+ .filter((k) => typeof k === 'string' && k.startsWith('audit-'))
85
+ .sort()
86
+ .reverse(); // newest first (ISO keys sort lexicographically by time)
87
+
88
+ // Apply --since by parsing the timestamp out of the key.
89
+ const filtered = entries.filter((k) => {
90
+ if (!cutoffMs) return true;
91
+ // key shape: audit-2026-06-16T15-30-00-000Z
92
+ const m = /^audit-(.+)$/.exec(k);
93
+ if (!m) return true;
94
+ const isoLike = m[1].replace(/-/g, ':').replace(/^(\d{4}):(\d{2}):(\d{2})/, '$1-$2-$3');
95
+ const ts = Date.parse(isoLike);
96
+ return Number.isFinite(ts) && ts >= cutoffMs;
97
+ });
98
+
99
+ const slice = filtered.slice(0, ARGS.limit);
100
+
101
+ // Pull just enough fields from each record to render a compact line.
102
+ const rows = [];
103
+ for (const key of slice) {
104
+ const rec = memRetrieve(key);
105
+ if (!rec) continue;
106
+ rows.push({
107
+ key,
108
+ startedAt: rec.startedAt || null,
109
+ finishedAt: rec.finishedAt || null,
110
+ worst: rec.composite?.worst || null,
111
+ tmWorst: rec.composite?.threatModelWorst || null,
112
+ mcpWorst: rec.composite?.mcpScanWorst || null,
113
+ degraded: !!(rec.components?.oiaManifest?.degraded
114
+ || rec.components?.threatModel?.degraded
115
+ || rec.components?.mcpScan?.degraded),
116
+ });
117
+ }
118
+
119
+ const payload = {
120
+ namespace: NS,
121
+ filters: { limit: ARGS.limit, since: ARGS.since },
122
+ totalInNamespace: entries.length,
123
+ matchedSinceFilter: filtered.length,
124
+ returned: rows.length,
125
+ records: rows,
126
+ generatedAt: new Date().toISOString(),
127
+ };
128
+
129
+ if (ARGS.format === 'json') {
130
+ console.log(JSON.stringify(payload, null, 2));
131
+ return;
132
+ }
133
+
134
+ console.log(`# audit-list`);
135
+ console.log('');
136
+ console.log(`| Field | Value |`);
137
+ console.log(`|---|---:|`);
138
+ console.log(`| Namespace | \`${NS}\` |`);
139
+ console.log(`| Total records | ${entries.length} |`);
140
+ console.log(`| Matched filter | ${filtered.length} |`);
141
+ console.log(`| Showing | ${rows.length} (newest first) |`);
142
+ console.log('');
143
+ if (rows.length === 0) {
144
+ console.log(`_No audit records found. Run \`harness oia-audit\` to create one._`);
145
+ return;
146
+ }
147
+ console.log(`| Key | Started | Composite worst | Threat | MCP | Degraded |`);
148
+ console.log(`|---|---|:---:|:---:|:---:|:---:|`);
149
+ for (const r of rows) {
150
+ const shortKey = r.key.slice(0, 32) + (r.key.length > 32 ? '…' : '');
151
+ const started = r.startedAt ? r.startedAt.slice(0, 19).replace('T', ' ') : '—';
152
+ console.log(`| \`${shortKey}\` | ${started} | ${r.worst || '—'} | ${r.tmWorst || '—'} | ${r.mcpWorst || '—'} | ${r.degraded ? '⚠' : '✓'} |`);
153
+ }
154
+ console.log('');
155
+ console.log(`_Use \`audit-trend --baseline-key <a> --current-key <b>\` to diff two records._`);
156
+ }
157
+
158
+ main();