@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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@claude-flow/cli",
3
- "version": "3.11.0",
3
+ "version": "3.12.1",
4
4
  "type": "module",
5
5
  "description": "Ruflo CLI - Enterprise AI agent orchestration with 60+ specialized agents, swarm coordination, MCP server, self-learning hooks, and vector memory for Claude Code",
6
6
  "main": "dist/src/index.js",
@@ -78,6 +78,7 @@
78
78
  "bin",
79
79
  "scripts",
80
80
  ".claude",
81
+ "plugins",
81
82
  "README.md"
82
83
  ],
83
84
  "scripts": {
@@ -86,7 +87,7 @@
86
87
  "test:plugin-store": "npx tsx src/plugins/tests/standalone-test.ts",
87
88
  "test:pattern-store": "npx tsx src/transfer/store/tests/standalone-test.ts",
88
89
  "postinstall": "node ./scripts/postinstall.cjs",
89
- "prepublishOnly": "cp ../../../README.md ./README.md",
90
+ "prepublishOnly": "cp ../../../README.md ./README.md && rm -rf plugins && mkdir -p plugins && cp -r ../../../plugins/ruflo-metaharness plugins/",
90
91
  "release": "npm version prerelease --preid=alpha && npm run publish:all",
91
92
  "publish:all": "./scripts/publish.sh"
92
93
  },
@@ -95,13 +96,13 @@
95
96
  "vitest": "^4.0.16"
96
97
  },
97
98
  "dependencies": {
98
- "@claude-flow/cli-core": "^3.7.0-alpha.5",
99
- "@claude-flow/mcp": "^3.0.0-alpha.8",
100
- "@claude-flow/neural": "^3.0.0-alpha.9",
101
- "@claude-flow/shared": "^3.0.0-alpha.7",
102
- "@noble/ed25519": "^2.1.0",
103
- "@ruvector/rabitq-wasm": "^0.1.0",
104
- "semver": "^7.6.0",
99
+ "@claude-flow/cli-core": "3.7.0-alpha.5",
100
+ "@claude-flow/mcp": "3.0.0-alpha.8",
101
+ "@claude-flow/neural": "3.0.0-alpha.9",
102
+ "@claude-flow/shared": "3.0.0-alpha.7",
103
+ "@noble/ed25519": "2.3.0",
104
+ "@ruvector/rabitq-wasm": "0.1.0",
105
+ "semver": "7.7.3",
105
106
  "yaml": "^2.8.0"
106
107
  },
107
108
  "optionalDependencies": {
@@ -112,7 +113,9 @@
112
113
  "@claude-flow/memory": "^3.0.0-alpha.20",
113
114
  "@claude-flow/plugin-gastown-bridge": "^0.1.3",
114
115
  "@claude-flow/security": "^3.0.0-alpha.10",
115
- "@metaharness/router": "^0.3.2",
116
+ "@metaharness/kernel": "~0.1.0",
117
+ "@metaharness/router": "~0.3.2",
118
+ "metaharness": "~0.1.11",
116
119
  "@ruvector/attention": "^0.1.32",
117
120
  "@ruvector/attention-darwin-arm64": "0.1.32",
118
121
  "@ruvector/diskann": "^0.1.0",
@@ -0,0 +1 @@
1
+ {"type":"edit","file":"/Users/cohen/Projects/ruflo/plugins/ruflo-metaharness/scripts/test-mcp-tools.mjs","timestamp":1781649922735}
@@ -0,0 +1,6 @@
1
+ {
2
+ "trajectoriesRecorded": 22,
3
+ "patternsLearned": 22,
4
+ "signalsProcessed": 0,
5
+ "lastAdaptation": 1781650872839
6
+ }
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "ruflo-metaharness",
3
+ "description": "MetaHarness integration for ruflo — surfaces score/genome/mint/mcp-scan/threat-model via skills; pairs with @metaharness/router (ADR-148/149) for cost-optimal model routing; honors ADR-150's architectural constraint that MetaHarness remains an optional augmentation, never a required runtime dependency",
4
+ "version": "0.1.0",
5
+ "author": {
6
+ "name": "ruvnet",
7
+ "url": "https://github.com/ruvnet"
8
+ },
9
+ "homepage": "https://github.com/ruvnet/ruflo",
10
+ "license": "MIT",
11
+ "keywords": [
12
+ "ruflo",
13
+ "metaharness",
14
+ "harness",
15
+ "scaffolding",
16
+ "scorecard",
17
+ "genome",
18
+ "mcp-scan",
19
+ "threat-model",
20
+ "router",
21
+ "adr-150",
22
+ "adr-148",
23
+ "adr-149",
24
+ "optional-dependency",
25
+ "graceful-degradation",
26
+ "subprocess",
27
+ "namespace-routing",
28
+ "verified",
29
+ "ci",
30
+ "phase-1-mvp"
31
+ ]
32
+ }
@@ -0,0 +1,64 @@
1
+ # ruflo-metaharness
2
+
3
+ MetaHarness integration plugin for ruflo. Surfaces the upstream `metaharness` / `harness` CLIs through five ruflo skills, honoring [ADR-150](../../v3/docs/adr/ADR-150-metaharness-integration-surfaces.md)'s architectural constraint that MetaHarness must remain a removable augmentation — never a required runtime dependency.
4
+
5
+ ## ADR-150 architectural constraint (load-bearing)
6
+
7
+ **Ruflo remains operational if every MetaHarness package is removed.** Every code path in this plugin satisfies four rules:
8
+
9
+ 1. **Removable** — no static `import '@metaharness/*'` outside the optional-router path in `v3/@claude-flow/cli/src/ruvector/neural-router.ts`.
10
+ 2. **Optional in package.json** — `metaharness` is in `optionalDependencies`, never `dependencies`.
11
+ 3. **Graceful degradation** — every script catches `MODULE_NOT_FOUND`/network failure and emits `{ degraded: true, reason: 'metaharness-not-available' }` JSON, exits 0. The graceful path is the default behavior, not a special case.
12
+ 4. **CI gate** — `no-metaharness-smoke.yml` runs the plugin smoke with `npm install --no-optional` and asserts the contract still passes.
13
+
14
+ ## Skills
15
+
16
+ | Skill | Usage | Description |
17
+ |-------|-------|-------------|
18
+ | `harness-score` | `/harness-score [--path .] [--alert-on-fit-below 70]` | 5-dim readiness scorecard (harnessFit/compile/coverage/safety/memory + cost) |
19
+ | `harness-genome` | `/harness-genome [--path .] [--alert-on-risk-above 0.5]` | 7-section categorical report (repo_type/topology/risk/mcp/test/publish) |
20
+ | `harness-mcp-scan` | `/harness-mcp-scan [--path .] [--fail-on high]` | Static MCP security findings — pure-read, no dispatch |
21
+ | `harness-threat-model` | `/harness-threat-model [--path .] [--fail-on high]` | Enterprise-grade threat model (clean/low/medium/high + findings) |
22
+ | `harness-mint` | `/harness-mint --name <id> --template <id> [--confirm]` | Scaffold a custom harness; DRY-RUN by default; refuses project-root writes |
23
+
24
+ ## Phase-0 baseline (ruflo itself, 2026-06-16)
25
+
26
+ ```json
27
+ {
28
+ "harnessFit": 82,
29
+ "compileConfidence": 100,
30
+ "taskCoverage": 79,
31
+ "toolSafety": 100,
32
+ "memoryUsefulness": 40,
33
+ "estCostPerRunUsd": 0.048,
34
+ "recommendedMode": "CLI + MCP",
35
+ "archetype": "typescript-sdk-harness",
36
+ "template": "vertical:coding",
37
+ "scaffoldReady": true,
38
+ "risk_score": 0.27,
39
+ "publish_readiness": 0.9
40
+ }
41
+ ```
42
+
43
+ ## Architecture
44
+
45
+ All skills use subprocess invocation through the `_harness.mjs` shared helper:
46
+
47
+ ```
48
+ skills/X/SKILL.md → scripts/X.mjs → scripts/_harness.mjs → spawnSync('npx', ['metaharness', …])
49
+ ↘ on MODULE_NOT_FOUND → emit degraded JSON, exit 0
50
+ ```
51
+
52
+ This means:
53
+ - No library import overhead on ruflo's boot path
54
+ - 60s hard timeout per subprocess (bounded blast radius)
55
+ - `--json` flag forced for structured parsing
56
+ - Graceful degradation is a single helper used by every skill
57
+
58
+ ## Cross-links
59
+
60
+ - [ADR-150](../../v3/docs/adr/ADR-150-metaharness-integration-surfaces.md) — decision + architectural constraint
61
+ - [Issue #2399](https://github.com/ruvnet/ruflo/issues/2399) — phase rollout tracker
62
+ - [Research dossier](https://gist.github.com/ruvnet/19d166ff9acf368c9da4172d91ac9113) — full graded-evidence sourcing
63
+ - [Upstream](https://github.com/ruvnet/agent-harness-generator) — `metaharness` source
64
+ - ADR-148/149 — `@metaharness/router` cost-optimal routing (sibling integration)
@@ -0,0 +1,58 @@
1
+ ---
2
+ name: metaharness-architect
3
+ description: MetaHarness integration architect for ruflo. Surfaces score/genome/mint/mcp-scan/threat-model upstream capabilities via skills; enforces ADR-150 architectural constraint (MetaHarness as removable augmentation, never required runtime dep); coordinates Phase 1 MVP rollout
4
+ model: haiku
5
+ ---
6
+
7
+ You are the metaharness-architect for ruflo. Your job is to expose the
8
+ `@metaharness/*` ecosystem's capabilities through ruflo's UX while
9
+ keeping ruflo independently operational at all times.
10
+
11
+ ## ADR-150 invariants (load-bearing)
12
+
13
+ 1. **Removable** — `npm ls --without-deps @metaharness/*` must still
14
+ produce a working CLI.
15
+ 2. **Optional in package.json** — every `@metaharness/*` package goes in
16
+ `optionalDependencies` or `peerDependencies` (optional), NEVER
17
+ `dependencies`.
18
+ 3. **Graceful degradation** — every code path that imports a
19
+ `@metaharness/*` symbol catches `MODULE_NOT_FOUND` and falls back.
20
+ The `emitDegradedJsonAndExit()` helper in `scripts/_harness.mjs` is
21
+ the reference implementation.
22
+ 4. **CI gate** — at least one CI job runs ruflo with no MetaHarness
23
+ packages installed and asserts smoke still passes.
24
+
25
+ If a PR breaks any of these four rules, it is a breaking change and
26
+ needs its own ADR.
27
+
28
+ ## Skills (6 — what each does, when to invoke)
29
+
30
+ | Skill | Role | Invoke when |
31
+ |---|---|---|
32
+ | `harness-score` | 5-dim numeric scorecard | Pre-mint readiness check; CI regression gate |
33
+ | `harness-genome` | 7-section categorical report | Pre-mint architecture review; drift detection over time |
34
+ | `harness-mcp-scan` | Static MCP security findings | Every PR; enterprise security review |
35
+ | `harness-threat-model` | Categorized threat report | Pre-launch review; periodic OIA-audit cadence |
36
+ | `harness-oia-audit` | Composite weekly audit worker (iter 7) | Cron-scheduled; bundles oia+threat+mcp into one timestamped record in `metaharness-audit` namespace |
37
+ | `harness-mint` | Scaffold a custom harness | User wants to fork; ALWAYS dry-run first, never write to project root |
38
+
39
+ ## Tools (subprocess-only, no library imports)
40
+
41
+ - All skills shell out to `npx metaharness ...` or `npx -p metaharness@latest harness ...` via the `_harness.mjs` shared helper.
42
+ - 60s hard timeout per subprocess.
43
+ - Output captured + parsed; `--json` flag forced unless the script opts out.
44
+ - No `@metaharness/*` import statement appears outside the optional-router path in `v3/@claude-flow/cli/src/ruvector/neural-router.ts`.
45
+
46
+ ## Phase tracker
47
+
48
+ - ✅ Phase 0 — measurement spike (ruflo's own scorecard captured 2026-06-16: harnessFit 82, risk_score 0.27, publish_readiness 0.9)
49
+ - 🔄 Phase 1 — MVP plugin (this commit + CI gates + KRR retraining)
50
+ - ⏳ Phase 2 — Expansion (eject command, SelfEvolvingRouter parallel-log, harness registry, oia-audit worker)
51
+ - ⏳ Phase 3 — Harness Intelligence Layer (each item gets its own ADR)
52
+
53
+ ## Cross-links
54
+
55
+ - [ADR-150](../../../v3/docs/adr/ADR-150-metaharness-integration-surfaces.md) — decision
56
+ - [Issue #2399](https://github.com/ruvnet/ruflo/issues/2399) — phase tracker
57
+ - [Research dossier](https://gist.github.com/ruvnet/19d166ff9acf368c9da4172d91ac9113) — graded evidence
58
+ - [Upstream](https://github.com/ruvnet/agent-harness-generator) — `metaharness` source
@@ -0,0 +1,46 @@
1
+ ---
2
+ name: ruflo-metaharness
3
+ description: MetaHarness integration — score, genome, mint, mcp-scan, threat-model — via subprocess invocations honoring ADR-150 architectural constraint
4
+ ---
5
+
6
+ MetaHarness integration commands. All shell out to `npx metaharness ...`
7
+ or `npx -p metaharness@latest harness ...` via the `_harness.mjs`
8
+ shared helper; no library imports on ruflo's boot path.
9
+
10
+ **`harness score [--path .] [--alert-on-fit-below N] [--format table|json]`** -- 5-dimension readiness scorecard (harnessFit / compileConfidence / taskCoverage / toolSafety / memoryUsefulness + estCostPerRunUsd + scaffoldReady).
11
+ 1. Run `node plugins/ruflo-metaharness/scripts/score.mjs --path <dir>`
12
+ 2. Output JSON (default) with all dimensions + recommended template + archetype
13
+ 3. `--alert-on-fit-below N` exits 1 when harnessFit < N — CI regression gate
14
+ 4. Subprocess + 60s hard timeout; graceful degradation when metaharness unavailable
15
+
16
+ **`harness genome [--path .] [--alert-on-risk-above 0.5] [--format table|json]`** -- 7-section repo readiness report (repo_type / agent_topology / risk_score / mcp_surface / test_confidence / publish_readiness).
17
+ 1. Run `node plugins/ruflo-metaharness/scripts/genome.mjs --path <dir>`
18
+ 2. Pairs with harness-score for full readiness view — score is numeric, genome is categorical
19
+ 3. `--alert-on-risk-above N` exits 1 when risk_score > N
20
+ 4. Useful for drift detection: snapshot genome over time, diff to spot agent_topology drift
21
+
22
+ **`harness mcp-scan [--path .] [--fail-on low|medium|high] [--format table|json]`** -- Static security scan of `.mcp/servers.json` + `.harness/claims.json`. Reads only; no dispatch.
23
+ 1. Run `node plugins/ruflo-metaharness/scripts/mcp-scan.mjs --path <dir>`
24
+ 2. Severity-ranked findings (low/medium/high); default fail-on `high`
25
+ 3. CI integration: `mcp-scan --fail-on high` fails the build on any HIGH finding
26
+ 4. Pairs with harness-threat-model for enterprise-review-grade categorization
27
+
28
+ **`harness threat-model [--path .] [--fail-on clean|low|medium|high] [--format table|json]`** -- Enterprise-review threat model. Returns `worst` severity + categorized `findings[]`.
29
+ 1. Run `node plugins/ruflo-metaharness/scripts/threat-model.mjs --path <dir>`
30
+ 2. Default fail-on `high`; tightenable to `medium` for stricter gates
31
+ 3. Output suitable for sharing with security/infosec team
32
+ 4. Will be auto-fired by the Phase-2 oia-audit background worker on a schedule
33
+
34
+ **`harness oia-audit [--path .] [--dry-run] [--alert-on-worst clean|low|medium|high] [--format table|json]`** -- Phase-2 composite worker (ADR-150). Bundles oia-manifest + threat-model + mcp-scan into one timestamped audit record, stores in `metaharness-audit` memory namespace.
35
+ 1. Run `node plugins/ruflo-metaharness/scripts/oia-audit.mjs`
36
+ 2. Composite worst-severity = max(threatModel.worst, mcpScan.findings.severity)
37
+ 3. `--alert-on-worst high` exits 1 when composite ≥ high — CI weekly drift gate
38
+ 4. `--dry-run` skips memory persistence — useful for local checks
39
+ 5. Designed for cron schedule: weekly snapshot enables audit drift tracking via memory diff
40
+
41
+ **`harness mint --name <id> --template <vertical:coding|minimal|…> [--host claude-code|codex|…] [--target /abs/path] [--confirm] [--format table|json]`** -- Scaffold a custom AI agent harness. DRY-RUN by default; --confirm required to write.
42
+ 1. Run `node plugins/ruflo-metaharness/scripts/mint.mjs --name <id> --template <id> --host <id>`
43
+ 2. **Safety**: refuses to write to the calling repo root or any path inside it; defaults to `/tmp/ruflo-mint-<ts>-<name>/`
44
+ 3. Without `--confirm`: prints dry-run plan, exits 0 without touching disk
45
+ 4. With `--confirm`: shells `npx metaharness new ... --yes`
46
+ 5. Templates: minimal + 19 verticals (coding, devops, support, legal, …). Hosts: claude-code, codex, pi-dev, opencode, github-actions, +4 more.
@@ -0,0 +1,261 @@
1
+ // _harness.mjs — shared invocation helper for the metaharness/harness CLIs.
2
+ //
3
+ // All ruflo-metaharness skills shell out to the upstream CLI rather than
4
+ // linking the library — this honors ADR-150's architectural constraint
5
+ // (MetaHarness must remain a removable augmentation, never a required
6
+ // runtime dep) while still giving us "deep integration" through a single
7
+ // vetted bridge that every skill imports from.
8
+ //
9
+ // CONTRACT
10
+ // - `runMetaharness(args, opts)` — invoke `npx metaharness <args>`
11
+ // - `runHarness(args, opts)` — invoke `npx -p metaharness harness <args>`
12
+ // - both return `{ stdout, stderr, exitCode, json|null, durationMs }`
13
+ // - `--json` flag is appended automatically when `opts.json !== false`
14
+ // - subprocess hard timeout (default 60s) — captured in opts.timeoutMs
15
+ // - on MODULE_NOT_FOUND or "not installed", returns degraded result with
16
+ // `degraded: true, reason: 'metaharness-not-available'` — never throws
17
+ // (ADR-150 graceful-degradation rule #3)
18
+
19
+ import { spawnSync, spawn } from 'node:child_process';
20
+
21
+ const DEFAULT_TIMEOUT_MS = 60_000;
22
+
23
+ /**
24
+ * iter 56 — async variant of execCli. Used by oia-audit.mjs to parallelize
25
+ * its 5 subprocess calls, dropping worst-case wall-clock from 5×TIMEOUT
26
+ * (sequential) to 1×TIMEOUT (parallel). Identical return shape to the
27
+ * sync execCli so callers can swap without ceremony.
28
+ */
29
+ function execCliAsync(npxArgs, opts = {}) {
30
+ return new Promise((resolve) => {
31
+ const start = Date.now();
32
+ const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
33
+ const wantJson = opts.json !== false;
34
+ const argv = wantJson && !npxArgs.includes('--json') ? [...npxArgs, '--json'] : [...npxArgs];
35
+ const p = spawn('npx', argv, {
36
+ stdio: ['ignore', 'pipe', 'pipe'],
37
+ cwd: opts.cwd,
38
+ env: { ...process.env, ...(opts.env || {}) },
39
+ shell: process.platform === 'win32',
40
+ });
41
+ let stdout = '', stderr = '';
42
+ p.stdout?.on('data', (d) => { stdout += d.toString(); });
43
+ p.stderr?.on('data', (d) => { stderr += d.toString(); });
44
+ const timer = setTimeout(() => {
45
+ try { p.kill('SIGTERM'); } catch { /* ignore */ }
46
+ }, timeoutMs);
47
+ p.on('error', (e) => {
48
+ clearTimeout(timer);
49
+ resolve({
50
+ stdout, stderr: stderr + String(e?.message ?? e),
51
+ exitCode: 127, json: null, durationMs: Date.now() - start,
52
+ degraded: true, reason: 'metaharness-not-available',
53
+ });
54
+ });
55
+ p.on('close', (code) => {
56
+ clearTimeout(timer);
57
+ const durationMs = Date.now() - start;
58
+ if (code === null || /could not determine executable|404|not installed|MODULE_NOT_FOUND|ENOTFOUND|getaddrinfo|ECONNREFUSED|ETIMEDOUT/i.test(stderr)) {
59
+ resolve({
60
+ stdout, stderr,
61
+ exitCode: code ?? 127, json: null, durationMs,
62
+ degraded: true, reason: 'metaharness-not-available',
63
+ });
64
+ return;
65
+ }
66
+ let json = null;
67
+ if (wantJson) {
68
+ const m = /\{[\s\S]*\}/.exec(stdout);
69
+ if (m) { try { json = JSON.parse(m[0]); } catch { /* leave null */ } }
70
+ }
71
+ resolve({ stdout, stderr, exitCode: code ?? 0, json, durationMs, degraded: false });
72
+ });
73
+ });
74
+ }
75
+
76
+ export function runMetaharnessAsync(args, opts) {
77
+ return execCliAsync(['-y', 'metaharness@latest', ...args], opts);
78
+ }
79
+
80
+ export function runHarnessAsync(args, opts) {
81
+ return execCliAsync(['-y', '-p', 'metaharness@latest', 'harness', ...args], opts);
82
+ }
83
+
84
+ // ITER 27 — npx invocation hardening.
85
+ // The pre-iter-27 implementation passed `'-y metaharness@latest'` as a
86
+ // SINGLE argv element to npx (`spawnSync('npx', [bin, ...argv])` where
87
+ // bin contained two whitespace-separated tokens). spawnSync with
88
+ // shell:false does no word-splitting, so npx received a literal string
89
+ // with an embedded space and either failed silently or treated the
90
+ // whole thing as a package name. The graceful-degradation path then
91
+ // reported `degraded: true` for every skill — masking the bug. Every
92
+ // argv token must now be its own array element.
93
+ function execCli(npxArgs, opts = {}) {
94
+ const start = Date.now();
95
+ const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
96
+ const wantJson = opts.json !== false;
97
+ const argv = wantJson && !npxArgs.includes('--json') ? [...npxArgs, '--json'] : [...npxArgs];
98
+ const r = spawnSync('npx', argv, {
99
+ stdio: ['ignore', 'pipe', 'pipe'],
100
+ encoding: 'utf-8',
101
+ timeout: timeoutMs,
102
+ cwd: opts.cwd, // iter 27 — let callers redirect $CWD (mint.mjs needs this)
103
+ env: { ...process.env, ...(opts.env || {}) },
104
+ shell: process.platform === 'win32',
105
+ });
106
+ const durationMs = Date.now() - start;
107
+ const stdout = r.stdout || '';
108
+ const stderr = r.stderr || '';
109
+ // Graceful degradation — npx couldn't find the binary.
110
+ if (r.status === null || /could not determine executable|404|not installed|MODULE_NOT_FOUND|ENOTFOUND|getaddrinfo|ECONNREFUSED|ETIMEDOUT/i.test(stderr)) {
111
+ return {
112
+ stdout, stderr,
113
+ exitCode: r.status ?? 127,
114
+ json: null,
115
+ durationMs,
116
+ degraded: true,
117
+ reason: 'metaharness-not-available',
118
+ };
119
+ }
120
+ let json = null;
121
+ if (wantJson) {
122
+ const m = /\{[\s\S]*\}/.exec(stdout);
123
+ if (m) { try { json = JSON.parse(m[0]); } catch { /* leave null */ } }
124
+ }
125
+ return { stdout, stderr, exitCode: r.status ?? 0, json, durationMs, degraded: false };
126
+ }
127
+
128
+ export function runMetaharness(args, opts) {
129
+ // iter 27 — explicit argv tokens (was: '-y metaharness@latest' as one
130
+ // string, which silently degraded every skill).
131
+ return execCli(['-y', 'metaharness@latest', ...args], opts);
132
+ }
133
+
134
+ export function runHarness(args, opts) {
135
+ // The `harness` binary ships inside the `metaharness` package, so we
136
+ // need `npx -p metaharness@latest harness <args>`. spawnSync receives
137
+ // a single argv array, so encode the `-p` flag as its own argument.
138
+ const start = Date.now();
139
+ const timeoutMs = opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
140
+ const wantJson = opts?.json !== false;
141
+ const argv = wantJson && !args.includes('--json') ? [...args, '--json'] : [...args];
142
+ const r = spawnSync('npx', ['-y', '-p', 'metaharness@latest', 'harness', ...argv], {
143
+ stdio: ['ignore', 'pipe', 'pipe'],
144
+ encoding: 'utf-8',
145
+ timeout: timeoutMs,
146
+ cwd: opts?.cwd, // iter 27 — same cwd-redirect support as runMetaharness
147
+ env: { ...process.env, ...(opts?.env || {}) },
148
+ shell: process.platform === 'win32',
149
+ });
150
+ const durationMs = Date.now() - start;
151
+ const stdout = r.stdout || '';
152
+ const stderr = r.stderr || '';
153
+ if (r.status === null || /could not determine executable|404|not installed|MODULE_NOT_FOUND|ENOTFOUND|getaddrinfo|ECONNREFUSED|ETIMEDOUT/i.test(stderr)) {
154
+ return {
155
+ stdout, stderr,
156
+ exitCode: r.status ?? 127,
157
+ json: null,
158
+ durationMs,
159
+ degraded: true,
160
+ reason: 'metaharness-not-available',
161
+ };
162
+ }
163
+ let json = null;
164
+ if (wantJson) {
165
+ const m = /\{[\s\S]*\}/.exec(stdout);
166
+ if (m) { try { json = JSON.parse(m[0]); } catch { /* leave null */ } }
167
+ }
168
+ return { stdout, stderr, exitCode: r.status ?? 0, json, durationMs, degraded: false };
169
+ }
170
+
171
+ /**
172
+ * iter 63 — single source of truth for severity ranks across the
173
+ * metaharness plugin family. Pre-iter-63, three scripts (oia-audit,
174
+ * audit-trend, mcp-scan) maintained their own SEVERITY_RANK literal,
175
+ * each missing different keys, each producing different NaN-compare
176
+ * behavior on unknown severities. Iter 62 fixed oia-audit; iter 63
177
+ * propagates the fix and consolidates.
178
+ *
179
+ * Mapping rationale:
180
+ * clean / info → 0 (no harm)
181
+ * low → 1
182
+ * medium / warn → 2
183
+ * high / error → 3
184
+ * critical → 4 (explicit elevation above high)
185
+ *
186
+ * `rankSeverity(s)` is the safe accessor — returns 0 for any unknown
187
+ * string instead of `undefined`, eliminating the NaN-compare hazard
188
+ * (`undefined > 3` evaluates to false → unknown severities silently
189
+ * ignored in reduce expressions).
190
+ */
191
+ export const SEVERITY_RANK = Object.freeze({
192
+ clean: 0, info: 0,
193
+ low: 1,
194
+ medium: 2, warn: 2,
195
+ high: 3, error: 3,
196
+ critical: 4,
197
+ });
198
+
199
+ export function rankSeverity(s) {
200
+ if (s == null) return 0;
201
+ return SEVERITY_RANK[String(s).toLowerCase()] ?? 0;
202
+ }
203
+
204
+ /**
205
+ * iter 50 — parse `harness mcp-scan` text output into structured findings.
206
+ *
207
+ * Upstream `harness mcp-scan` emits plain text even with --json:
208
+ *
209
+ * harness mcp-scan — <path>
210
+ *
211
+ * [INFO] No MCP security issues found
212
+ * Policy is default-deny with safe capability grants and an audit log.
213
+ *
214
+ * Result: INFO (1 finding, 0 high)
215
+ *
216
+ * Closes the iter-49-flagged gap where audit-trend.mjs reads
217
+ * `json.findings` expecting an array, but mcp-scan's r.json was null.
218
+ * Used by BOTH mcp-scan.mjs (the wrapper) and oia-audit.mjs (composite
219
+ * audit) so the structured-findings invariant holds across the pipeline.
220
+ */
221
+ export function parseMcpScanText(stdout) {
222
+ const findings = [];
223
+ const lines = (stdout || '').split('\n');
224
+ let current = null;
225
+ for (const line of lines) {
226
+ const m = /^\s*\[([A-Z]+)\]\s+(.+?)\s*$/.exec(line);
227
+ if (m) {
228
+ if (current) findings.push(current);
229
+ current = { severity: m[1].toLowerCase(), message: m[2] };
230
+ } else if (current && /^\s{6,}\S/.test(line)) {
231
+ const cont = line.trim();
232
+ if (cont) current.message += ' ' + cont;
233
+ } else if (current && line.trim() === '') {
234
+ findings.push(current);
235
+ current = null;
236
+ }
237
+ }
238
+ if (current) findings.push(current);
239
+ const resultMatch = /Result:\s+([A-Z]+)\s+\((\d+)\s+finding/i.exec(stdout);
240
+ const summary = resultMatch ? {
241
+ overallSeverity: resultMatch[1].toLowerCase(),
242
+ totalCount: parseInt(resultMatch[2], 10),
243
+ } : null;
244
+ return { findings, summary };
245
+ }
246
+
247
+ // Convenience emitters for skill scripts — keep the boilerplate out of
248
+ // each skill so they focus on argument parsing + exit-code semantics.
249
+ export function emitDegradedJsonAndExit(reason) {
250
+ const payload = {
251
+ degraded: true,
252
+ reason,
253
+ hint: 'Install metaharness manually with `npm i -D metaharness` or run `npx metaharness@latest --version` to verify network access.',
254
+ generatedAt: new Date().toISOString(),
255
+ };
256
+ console.log(JSON.stringify(payload, null, 2));
257
+ // Exit 0 — ADR-150 architectural constraint says ruflo continues to
258
+ // function when MetaHarness is absent. Skills emit a structured
259
+ // degraded payload rather than failing.
260
+ process.exit(0);
261
+ }