monomind 1.8.0 → 1.9.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 (566) hide show
  1. package/.claude/agents/design/design-monodesign.md +121 -0
  2. package/.claude/agents/github/issue-tracker.md +12 -12
  3. package/.claude/agents/github/pr-manager.md +10 -10
  4. package/.claude/agents/github/release-manager.md +49 -105
  5. package/.claude/agents/github/repo-architect.md +73 -92
  6. package/.claude/agents/github/sync-coordinator.md +55 -123
  7. package/.claude/agents/marketing/marketing-competitive-content.md +155 -0
  8. package/.claude/agents/marketing/marketing-content-creator.md +13 -0
  9. package/.claude/agents/marketing/marketing-cro-specialist.md +147 -0
  10. package/.claude/agents/marketing/marketing-email-specialist.md +90 -0
  11. package/.claude/agents/marketing/marketing-launch-strategist.md +129 -0
  12. package/.claude/agents/marketing/marketing-pricing-strategist.md +127 -0
  13. package/.claude/agents/specialists/integration-architect.md +94 -0
  14. package/.claude/commands/agents/README.md +4 -0
  15. package/.claude/commands/agents/agent-capabilities.md +6 -2
  16. package/.claude/commands/agents/agent-coordination.md +4 -0
  17. package/.claude/commands/agents/agent-spawning.md +4 -0
  18. package/.claude/commands/agents/agent-types.md +6 -2
  19. package/.claude/commands/analysis/README.md +14 -5
  20. package/.claude/commands/analysis/bottleneck-detect.md +30 -123
  21. package/.claude/commands/analysis/performance-bottlenecks.md +14 -14
  22. package/.claude/commands/analysis/performance-report.md +38 -11
  23. package/.claude/commands/analysis/token-efficiency.md +13 -16
  24. package/.claude/commands/analysis/token-usage.md +34 -12
  25. package/.claude/commands/automation/README.md +15 -5
  26. package/.claude/commands/automation/auto-agent.md +49 -85
  27. package/.claude/commands/automation/self-healing.md +20 -18
  28. package/.claude/commands/automation/session-memory.md +28 -29
  29. package/.claude/commands/automation/smart-agents.md +17 -9
  30. package/.claude/commands/automation/smart-spawn.md +52 -11
  31. package/.claude/commands/automation/workflow-select.md +46 -11
  32. package/.claude/commands/browse.md +5 -0
  33. package/.claude/commands/coordination/README.md +9 -5
  34. package/.claude/commands/coordination/agent-spawn.md +53 -9
  35. package/.claude/commands/coordination/swarm-init.md +39 -42
  36. package/.claude/commands/coordination/task-orchestrate.md +65 -11
  37. package/.claude/commands/github/README.md +21 -8
  38. package/.claude/commands/github/github-modes.md +9 -5
  39. package/.claude/commands/github/issue-tracker.md +34 -33
  40. package/.claude/commands/github/pr-manager.md +20 -17
  41. package/.claude/commands/github/release-manager.md +37 -49
  42. package/.claude/commands/github/repo-architect.md +39 -41
  43. package/.claude/commands/github/sync-coordinator.md +45 -49
  44. package/.claude/commands/hive-mind/README.md +42 -17
  45. package/.claude/commands/hive-mind/hive-mind-consensus.md +68 -4
  46. package/.claude/commands/hive-mind/hive-mind-init.md +55 -5
  47. package/.claude/commands/hive-mind/hive-mind-memory.md +69 -4
  48. package/.claude/commands/hive-mind/hive-mind-spawn.md +71 -10
  49. package/.claude/commands/hive-mind/hive-mind-status.md +52 -4
  50. package/.claude/commands/hive-mind/hive-mind-stop.md +51 -4
  51. package/.claude/commands/hive-mind/hive-mind.md +74 -14
  52. package/.claude/commands/hooks/README.md +62 -7
  53. package/.claude/commands/hooks/overview.md +94 -35
  54. package/.claude/commands/hooks/post-edit.md +48 -87
  55. package/.claude/commands/hooks/post-task.md +37 -87
  56. package/.claude/commands/hooks/pre-edit.md +52 -84
  57. package/.claude/commands/hooks/pre-task.md +46 -81
  58. package/.claude/commands/hooks/session-end.md +49 -85
  59. package/.claude/commands/hooks/setup.md +87 -58
  60. package/.claude/commands/mastermind/_repeat.md +308 -0
  61. package/.claude/commands/mastermind/architect.md +49 -0
  62. package/.claude/commands/mastermind/brain.md +98 -0
  63. package/.claude/commands/mastermind/build.md +22 -0
  64. package/.claude/commands/mastermind/content.md +22 -0
  65. package/.claude/commands/mastermind/createorg.md +94 -0
  66. package/.claude/commands/mastermind/finance.md +22 -0
  67. package/.claude/commands/mastermind/idea.md +22 -0
  68. package/.claude/commands/mastermind/marketing.md +22 -0
  69. package/.claude/commands/mastermind/master.md +379 -0
  70. package/.claude/commands/mastermind/ops.md +22 -0
  71. package/.claude/commands/mastermind/release.md +22 -0
  72. package/.claude/commands/mastermind/research.md +22 -0
  73. package/.claude/commands/mastermind/review.md +22 -0
  74. package/.claude/commands/mastermind/runorg.md +106 -0
  75. package/.claude/commands/mastermind/sales.md +22 -0
  76. package/.claude/commands/mastermind/techport.md +17 -0
  77. package/.claude/commands/memory/README.md +75 -5
  78. package/.claude/commands/memory/memory-search.md +63 -11
  79. package/.claude/commands/monitoring/README.md +64 -4
  80. package/.claude/commands/monitoring/agent-metrics.md +50 -10
  81. package/.claude/commands/monitoring/agents.md +59 -32
  82. package/.claude/commands/monitoring/status.md +96 -34
  83. package/.claude/commands/monograph/README.md +102 -0
  84. package/.claude/commands/monograph/monograph-build.md +79 -0
  85. package/.claude/commands/monograph/monograph-search.md +96 -0
  86. package/.claude/commands/monograph/monograph-stats.md +53 -0
  87. package/.claude/commands/monograph/monograph-watch.md +63 -0
  88. package/.claude/commands/monograph/monograph-wiki.md +91 -0
  89. package/.claude/commands/monomind/createtask.md +277 -0
  90. package/.claude/commands/{monomind-do.md → monomind/do.md} +21 -8
  91. package/.claude/commands/monomind/help.md +118 -0
  92. package/.claude/commands/{monomind-idea.md → monomind/idea.md} +22 -28
  93. package/.claude/commands/{monomind-improve.md → monomind/improve.md} +21 -27
  94. package/.claude/commands/monomind/memory.md +230 -0
  95. package/.claude/commands/monomind/repeat.md +201 -0
  96. package/.claude/commands/monomind/review.md +313 -0
  97. package/.claude/commands/monomind/specialagents.md +125 -0
  98. package/.claude/commands/monomind/swarm.md +161 -0
  99. package/.claude/commands/monomind/understand.md +148 -0
  100. package/.claude/commands/optimization/README.md +69 -5
  101. package/.claude/commands/optimization/auto-topology.md +66 -43
  102. package/.claude/commands/optimization/parallel-execution.md +65 -39
  103. package/.claude/commands/optimization/performance-optimize.md +79 -0
  104. package/.claude/commands/pair/README.md +48 -230
  105. package/.claude/commands/pair/examples.md +85 -441
  106. package/.claude/commands/pair/modes.md +77 -303
  107. package/.claude/commands/pair/session.md +76 -359
  108. package/.claude/commands/sparc/analyzer.md +9 -26
  109. package/.claude/commands/sparc/architect.md +8 -25
  110. package/.claude/commands/sparc/ask.md +27 -68
  111. package/.claude/commands/sparc/batch-executor.md +8 -25
  112. package/.claude/commands/sparc/code.md +12 -53
  113. package/.claude/commands/sparc/coder.md +8 -25
  114. package/.claude/commands/sparc/debug.md +12 -53
  115. package/.claude/commands/sparc/debugger.md +8 -25
  116. package/.claude/commands/sparc/designer.md +8 -25
  117. package/.claude/commands/sparc/devops.md +16 -57
  118. package/.claude/commands/sparc/docs-writer.md +12 -53
  119. package/.claude/commands/sparc/documenter.md +8 -25
  120. package/.claude/commands/sparc/innovator.md +8 -25
  121. package/.claude/commands/sparc/integration.md +12 -53
  122. package/.claude/commands/sparc/mcp.md +12 -53
  123. package/.claude/commands/sparc/memory-manager.md +28 -25
  124. package/.claude/commands/sparc/optimizer.md +8 -25
  125. package/.claude/commands/sparc/orchestrator.md +35 -97
  126. package/.claude/commands/sparc/post-deployment-monitoring-mode.md +13 -54
  127. package/.claude/commands/sparc/refinement-optimization-mode.md +13 -54
  128. package/.claude/commands/sparc/researcher.md +8 -25
  129. package/.claude/commands/sparc/reviewer.md +8 -25
  130. package/.claude/commands/sparc/security-review.md +13 -54
  131. package/.claude/commands/sparc/sparc-modes.md +97 -151
  132. package/.claude/commands/sparc/sparc.md +16 -56
  133. package/.claude/commands/sparc/spec-pseudocode.md +13 -54
  134. package/.claude/commands/sparc/supabase-admin.md +19 -66
  135. package/.claude/commands/sparc/swarm-coordinator.md +21 -25
  136. package/.claude/commands/sparc/tdd.md +8 -25
  137. package/.claude/commands/sparc/tester.md +8 -25
  138. package/.claude/commands/sparc/tutorial.md +12 -53
  139. package/.claude/commands/sparc/workflow-manager.md +8 -25
  140. package/.claude/commands/sparc.md +76 -130
  141. package/.claude/commands/stream-chain/pipeline.md +72 -77
  142. package/.claude/commands/stream-chain/run.md +133 -47
  143. package/.claude/commands/swarm/README.md +37 -12
  144. package/.claude/commands/swarm/analysis.md +47 -69
  145. package/.claude/commands/swarm/development.md +45 -69
  146. package/.claude/commands/swarm/examples.md +77 -142
  147. package/.claude/commands/swarm/maintenance.md +47 -74
  148. package/.claude/commands/swarm/optimization.md +54 -87
  149. package/.claude/commands/swarm/research.md +47 -107
  150. package/.claude/commands/swarm/swarm-analysis.md +58 -4
  151. package/.claude/commands/swarm/swarm-background.md +61 -4
  152. package/.claude/commands/swarm/swarm-modes.md +63 -4
  153. package/.claude/commands/swarm/swarm-monitor.md +50 -4
  154. package/.claude/commands/swarm/swarm-status.md +40 -4
  155. package/.claude/commands/swarm/swarm-strategies.md +73 -5
  156. package/.claude/commands/swarm/swarm.md +70 -18
  157. package/.claude/commands/swarm/testing.md +51 -102
  158. package/.claude/commands/tokens.md +6 -1
  159. package/.claude/commands/training/README.md +36 -6
  160. package/.claude/commands/training/model-update.md +68 -15
  161. package/.claude/commands/training/neural-patterns.md +54 -55
  162. package/.claude/commands/training/neural-train.md +70 -16
  163. package/.claude/commands/training/pattern-learn.md +60 -16
  164. package/.claude/commands/training/specialization.md +78 -49
  165. package/.claude/commands/truth/start.md +87 -109
  166. package/.claude/commands/ts.md +7 -2
  167. package/.claude/commands/verify/check.md +90 -34
  168. package/.claude/commands/verify/start.md +71 -94
  169. package/.claude/commands/workflows/README.md +62 -6
  170. package/.claude/commands/workflows/development.md +69 -61
  171. package/.claude/commands/workflows/research.md +73 -47
  172. package/.claude/commands/workflows/workflow-create.md +75 -16
  173. package/.claude/commands/workflows/workflow-execute.md +94 -16
  174. package/.claude/commands/workflows/workflow-export.md +81 -16
  175. package/.claude/helpers/control-start.cjs +91 -0
  176. package/.claude/helpers/extras-registry.json +4104 -1991
  177. package/.claude/helpers/graphify-freshen.cjs +44 -13
  178. package/.claude/helpers/hook-handler.cjs +256 -1
  179. package/.claude/helpers/learning-service.mjs +0 -0
  180. package/.claude/helpers/loop-tracker.cjs +107 -0
  181. package/.claude/helpers/metrics-db.mjs +0 -0
  182. package/.claude/helpers/router.cjs +48 -68
  183. package/.claude/helpers/skill-registry.json +89 -104
  184. package/.claude/helpers/statusline.cjs +33 -2
  185. package/.claude/helpers/swarm-hooks.sh +0 -0
  186. package/.claude/scheduled_tasks.lock +1 -0
  187. package/.claude/settings.json +15 -0
  188. package/.claude/skills/.monomind/data/ranked-context.json +5 -0
  189. package/.claude/skills/.monomind/sessions/current.json +13 -0
  190. package/.claude/skills/.monomind/sessions/session-1777829336455.json +15 -0
  191. package/.claude/skills/.monomind/sessions/session-1777831614725.json +15 -0
  192. package/.claude/skills/.monomind/sessions/session-1777832095857.json +15 -0
  193. package/.claude/skills/.monomind/sessions/session-1777839814183.json +15 -0
  194. package/.claude/skills/.monomind/sessions/session-1777841847131.json +15 -0
  195. package/.claude/skills/.monomind/sessions/session-1777843309463.json +15 -0
  196. package/.claude/skills/.monomind/sessions/session-1777880867159.json +15 -0
  197. package/.claude/skills/.monomind/sessions/session-1777881884593.json +15 -0
  198. package/.claude/skills/.monomind/sessions/session-1777884090471.json +15 -0
  199. package/.claude/skills/.monomind/sessions/session-1777884808221.json +15 -0
  200. package/.claude/skills/.monomind/sessions/session-1777885672155.json +15 -0
  201. package/.claude/skills/.monomind/sessions/session-1777886852818.json +15 -0
  202. package/.claude/skills/.monomind/sessions/session-1777896532690.json +15 -0
  203. package/.claude/skills/agentdb-advanced/SKILL.md +11 -12
  204. package/.claude/skills/agentdb-learning/SKILL.md +20 -21
  205. package/.claude/skills/agentdb-memory-patterns/SKILL.md +28 -30
  206. package/.claude/skills/agentdb-optimization/SKILL.md +11 -12
  207. package/.claude/skills/agentdb-vector-search/SKILL.md +37 -41
  208. package/.claude/skills/{v3-integration-deep → agentic-integration}/SKILL.md +20 -13
  209. package/.claude/skills/agentic-jujutsu/SKILL.md +22 -22
  210. package/.claude/skills/{v3-cli-modernization → cli-modernization}/SKILL.md +17 -8
  211. package/.claude/skills/{v3-core-implementation → core-implementation}/SKILL.md +33 -8
  212. package/.claude/skills/{v3-ddd-architecture → ddd-architecture}/SKILL.md +18 -25
  213. package/.claude/skills/github-code-review/SKILL.md +82 -83
  214. package/.claude/skills/github-multi-repo/SKILL.md +42 -46
  215. package/.claude/skills/github-project-management/SKILL.md +83 -88
  216. package/.claude/skills/github-release-management/SKILL.md +12 -18
  217. package/.claude/skills/github-workflow-automation/SKILL.md +70 -74
  218. package/.claude/skills/hooks-automation/SKILL.md +9 -13
  219. package/.claude/skills/mastermind/_intake.md +83 -0
  220. package/.claude/skills/mastermind/_protocol.md +275 -0
  221. package/.claude/skills/mastermind/architect.md +847 -0
  222. package/.claude/skills/mastermind/build.md +158 -0
  223. package/.claude/skills/mastermind/content.md +185 -0
  224. package/.claude/skills/mastermind/createorg.md +318 -0
  225. package/.claude/skills/mastermind/finance.md +154 -0
  226. package/.claude/skills/mastermind/idea.md +158 -0
  227. package/.claude/skills/mastermind/marketing.md +216 -0
  228. package/.claude/skills/mastermind/monotask.md +350 -0
  229. package/.claude/skills/mastermind/ops.md +156 -0
  230. package/.claude/skills/mastermind/references/copywriting-frameworks.md +181 -0
  231. package/.claude/skills/mastermind/references/persuasion-psychology.md +158 -0
  232. package/.claude/skills/mastermind/release.md +156 -0
  233. package/.claude/skills/mastermind/research.md +156 -0
  234. package/.claude/skills/mastermind/review.md +157 -0
  235. package/.claude/skills/mastermind/runorg.md +308 -0
  236. package/.claude/skills/mastermind/sales.md +158 -0
  237. package/.claude/skills/mastermind/techport.md +743 -0
  238. package/.claude/skills/{v3-mcp-optimization → mcp-optimization}/SKILL.md +35 -14
  239. package/.claude/skills/{v3-memory-unification → memory-unification}/SKILL.md +20 -4
  240. package/.claude/skills/monodesign/SKILL.md +302 -0
  241. package/.claude/skills/monodesign/reference/adapt.md +190 -0
  242. package/.claude/skills/monodesign/reference/animate.md +175 -0
  243. package/.claude/skills/monodesign/reference/antipatterns-catalog.md +187 -0
  244. package/.claude/skills/monodesign/reference/audit.md +133 -0
  245. package/.claude/skills/monodesign/reference/bolder.md +113 -0
  246. package/.claude/skills/monodesign/reference/brand-workflow.md +180 -0
  247. package/.claude/skills/monodesign/reference/brand.md +114 -0
  248. package/.claude/skills/monodesign/reference/clarify.md +174 -0
  249. package/.claude/skills/monodesign/reference/cognitive-load.md +106 -0
  250. package/.claude/skills/monodesign/reference/color-and-contrast.md +105 -0
  251. package/.claude/skills/monodesign/reference/colorize.md +154 -0
  252. package/.claude/skills/monodesign/reference/component-specs.md +260 -0
  253. package/.claude/skills/monodesign/reference/component-states.md +274 -0
  254. package/.claude/skills/monodesign/reference/component-system.md +358 -0
  255. package/.claude/skills/monodesign/reference/copy-formulas.md +160 -0
  256. package/.claude/skills/monodesign/reference/craft.md +193 -0
  257. package/.claude/skills/monodesign/reference/critique.md +213 -0
  258. package/.claude/skills/monodesign/reference/delight.md +302 -0
  259. package/.claude/skills/monodesign/reference/design-principles.md +246 -0
  260. package/.claude/skills/monodesign/reference/distill.md +111 -0
  261. package/.claude/skills/monodesign/reference/document.md +427 -0
  262. package/.claude/skills/monodesign/reference/extract.md +69 -0
  263. package/.claude/skills/monodesign/reference/harden.md +347 -0
  264. package/.claude/skills/monodesign/reference/heuristics-scoring.md +234 -0
  265. package/.claude/skills/monodesign/reference/image-prompts.md +118 -0
  266. package/.claude/skills/monodesign/reference/interaction-design.md +195 -0
  267. package/.claude/skills/monodesign/reference/layout.md +141 -0
  268. package/.claude/skills/monodesign/reference/live.md +622 -0
  269. package/.claude/skills/monodesign/reference/motion-design.md +109 -0
  270. package/.claude/skills/monodesign/reference/onboard.md +234 -0
  271. package/.claude/skills/monodesign/reference/optimize.md +258 -0
  272. package/.claude/skills/monodesign/reference/overdrive.md +130 -0
  273. package/.claude/skills/monodesign/reference/personas.md +179 -0
  274. package/.claude/skills/monodesign/reference/polish.md +233 -0
  275. package/.claude/skills/monodesign/reference/pre-delivery-checklist.md +108 -0
  276. package/.claude/skills/monodesign/reference/product.md +62 -0
  277. package/.claude/skills/monodesign/reference/quieter.md +99 -0
  278. package/.claude/skills/monodesign/reference/responsive-design.md +114 -0
  279. package/.claude/skills/monodesign/reference/shape.md +151 -0
  280. package/.claude/skills/monodesign/reference/spatial-design.md +100 -0
  281. package/.claude/skills/monodesign/reference/teach.md +156 -0
  282. package/.claude/skills/monodesign/reference/token-architecture.md +222 -0
  283. package/.claude/skills/monodesign/reference/typeset.md +124 -0
  284. package/.claude/skills/monodesign/reference/typography.md +159 -0
  285. package/.claude/skills/monodesign/reference/ux-research.md +143 -0
  286. package/.claude/skills/monodesign/reference/ux-rules.md +211 -0
  287. package/.claude/skills/monodesign/reference/ux-writing.md +107 -0
  288. package/.claude/skills/monomotion/SKILL.md +145 -0
  289. package/.claude/skills/monomotion/rules/api-control.md +139 -0
  290. package/.claude/skills/monomotion/rules/effects.md +109 -0
  291. package/.claude/skills/monomotion/rules/integration.md +140 -0
  292. package/.claude/skills/monomotion/rules/scroll.md +131 -0
  293. package/.claude/skills/monomotion/rules/sequencing.md +105 -0
  294. package/.claude/skills/monomotion/rules/svg.md +101 -0
  295. package/.claude/skills/monomotion/rules/text.md +119 -0
  296. package/.claude/skills/pair-programming/SKILL.md +1 -1
  297. package/.claude/skills/performance-analysis/SKILL.md +3 -3
  298. package/.claude/skills/{v3-performance-optimization → performance-optimization}/SKILL.md +16 -8
  299. package/.claude/skills/reasoningbank-agentdb/SKILL.md +17 -19
  300. package/.claude/skills/reasoningbank-intelligence/SKILL.md +4 -6
  301. package/.claude/skills/{v3-security-overhaul → security-hardening}/SKILL.md +13 -3
  302. package/.claude/skills/skill-builder/SKILL.md +19 -19
  303. package/.claude/skills/sparc-methodology/SKILL.md +55 -211
  304. package/.claude/skills/stop-slop/SKILL.md +67 -0
  305. package/.claude/skills/stop-slop/references/examples.md +61 -0
  306. package/.claude/skills/stop-slop/references/phrases.md +130 -0
  307. package/.claude/skills/stop-slop/references/structures.md +136 -0
  308. package/.claude/skills/swarm-advanced/SKILL.md +13 -43
  309. package/.claude/skills/{v3-swarm-coordination → swarm-coordination}/SKILL.md +39 -21
  310. package/.claude/skills/swarm-orchestration/SKILL.md +12 -12
  311. package/.claude/skills/verification-quality/SKILL.md +5 -5
  312. package/.claude/statusline-command.sh +0 -0
  313. package/.claude/statusline.sh +0 -0
  314. package/.claude-plugin/scripts/install.sh +0 -0
  315. package/.claude-plugin/scripts/uninstall.sh +0 -0
  316. package/.claude-plugin/scripts/verify.sh +0 -0
  317. package/README.md +5 -5
  318. package/package.json +17 -17
  319. package/packages/@monomind/cli/README.md +441 -0
  320. package/packages/@monomind/cli/bin/cli.js +78 -13
  321. package/packages/@monomind/cli/bin/mcp-server.js +0 -0
  322. package/packages/@monomind/cli/dist/src/agents/halt-signal.js +33 -7
  323. package/packages/@monomind/cli/dist/src/agents/managed-agent.js +5 -2
  324. package/packages/@monomind/cli/dist/src/agents/prompt-experiment.d.ts +3 -2
  325. package/packages/@monomind/cli/dist/src/agents/prompt-experiment.js +1 -1
  326. package/packages/@monomind/cli/dist/src/agents/prompt-version-manager.d.ts +5 -2
  327. package/packages/@monomind/cli/dist/src/agents/prompt-version-manager.js +26 -4
  328. package/packages/@monomind/cli/dist/src/agents/specialization-scorer.js +17 -9
  329. package/packages/@monomind/cli/dist/src/agents/trigger-scanner.d.ts +5 -3
  330. package/packages/@monomind/cli/dist/src/agents/trigger-scanner.js +58 -10
  331. package/packages/@monomind/cli/dist/src/agents/version-store.d.ts +0 -1
  332. package/packages/@monomind/cli/dist/src/agents/version-store.js +44 -21
  333. package/packages/@monomind/cli/dist/src/autopilot-state.js +79 -28
  334. package/packages/@monomind/cli/dist/src/benchmarks/benchmark-runner.d.ts +7 -2
  335. package/packages/@monomind/cli/dist/src/benchmarks/benchmark-runner.js +20 -8
  336. package/packages/@monomind/cli/dist/src/benchmarks/metric-evaluators.d.ts +2 -1
  337. package/packages/@monomind/cli/dist/src/benchmarks/metric-evaluators.js +25 -2
  338. package/packages/@monomind/cli/dist/src/commands/agent.js +6 -4
  339. package/packages/@monomind/cli/dist/src/commands/appliance-advanced.js +23 -0
  340. package/packages/@monomind/cli/dist/src/commands/autopilot.js +3 -3
  341. package/packages/@monomind/cli/dist/src/commands/benchmark.js +119 -8
  342. package/packages/@monomind/cli/dist/src/commands/claims.js +22 -14
  343. package/packages/@monomind/cli/dist/src/commands/config.js +32 -0
  344. package/packages/@monomind/cli/dist/src/commands/daemon.js +13 -11
  345. package/packages/@monomind/cli/dist/src/commands/deployment.js +21 -2
  346. package/packages/@monomind/cli/dist/src/commands/doctor.js +5 -4
  347. package/packages/@monomind/cli/dist/src/commands/embeddings.js +124 -48
  348. package/packages/@monomind/cli/dist/src/commands/hive-mind.js +15 -14
  349. package/packages/@monomind/cli/dist/src/commands/hooks.js +45 -41
  350. package/packages/@monomind/cli/dist/src/commands/index.d.ts +2 -0
  351. package/packages/@monomind/cli/dist/src/commands/index.js +20 -7
  352. package/packages/@monomind/cli/dist/src/commands/init.js +53 -19
  353. package/packages/@monomind/cli/dist/src/commands/mcp.js +31 -44
  354. package/packages/@monomind/cli/dist/src/commands/memory.js +47 -15
  355. package/packages/@monomind/cli/dist/src/commands/migrate.js +156 -108
  356. package/packages/@monomind/cli/dist/src/commands/monograph.d.ts +8 -0
  357. package/packages/@monomind/cli/dist/src/commands/monograph.js +526 -0
  358. package/packages/@monomind/cli/dist/src/commands/neural.js +96 -56
  359. package/packages/@monomind/cli/dist/src/commands/performance.js +30 -8
  360. package/packages/@monomind/cli/dist/src/commands/plugins.js +13 -37
  361. package/packages/@monomind/cli/dist/src/commands/process.js +25 -2
  362. package/packages/@monomind/cli/dist/src/commands/providers.js +37 -5
  363. package/packages/@monomind/cli/dist/src/commands/replay.js +4 -4
  364. package/packages/@monomind/cli/dist/src/commands/route.js +37 -5
  365. package/packages/@monomind/cli/dist/src/commands/ruvector/import.js +12 -2
  366. package/packages/@monomind/cli/dist/src/commands/ruvector/init.js +15 -0
  367. package/packages/@monomind/cli/dist/src/commands/ruvector/status.js +16 -3
  368. package/packages/@monomind/cli/dist/src/commands/security.js +342 -193
  369. package/packages/@monomind/cli/dist/src/commands/session.js +51 -8
  370. package/packages/@monomind/cli/dist/src/commands/start.js +18 -4
  371. package/packages/@monomind/cli/dist/src/commands/swarm.js +47 -36
  372. package/packages/@monomind/cli/dist/src/commands/tokens.js +11 -11
  373. package/packages/@monomind/cli/dist/src/commands/transfer-store.js +1 -1
  374. package/packages/@monomind/cli/dist/src/commands/workflow.js +31 -4
  375. package/packages/@monomind/cli/dist/src/config-adapter.d.ts +2 -1
  376. package/packages/@monomind/cli/dist/src/consensus/audit-writer.js +46 -13
  377. package/packages/@monomind/cli/dist/src/consensus/vote-signer.d.ts +0 -3
  378. package/packages/@monomind/cli/dist/src/consensus/vote-signer.js +9 -1
  379. package/packages/@monomind/cli/dist/src/dlq/dlq-reader.d.ts +4 -2
  380. package/packages/@monomind/cli/dist/src/dlq/dlq-reader.js +25 -8
  381. package/packages/@monomind/cli/dist/src/dlq/dlq-replayer.d.ts +10 -3
  382. package/packages/@monomind/cli/dist/src/dlq/dlq-replayer.js +50 -16
  383. package/packages/@monomind/cli/dist/src/dlq/dlq-writer.js +27 -5
  384. package/packages/@monomind/cli/dist/src/eval/dataset-manager.d.ts +2 -2
  385. package/packages/@monomind/cli/dist/src/eval/dataset-manager.js +26 -16
  386. package/packages/@monomind/cli/dist/src/eval/trace-collector.js +23 -3
  387. package/packages/@monomind/cli/dist/src/index.js +12 -10
  388. package/packages/@monomind/cli/dist/src/init/claudemd-generator.js +8 -8
  389. package/packages/@monomind/cli/dist/src/init/executor.js +153 -70
  390. package/packages/@monomind/cli/dist/src/init/helpers-generator.js +35 -22
  391. package/packages/@monomind/cli/dist/src/init/mcp-generator.js +3 -3
  392. package/packages/@monomind/cli/dist/src/init/settings-generator.js +10 -3
  393. package/packages/@monomind/cli/dist/src/init/shared-instructions-generator.js +18 -3
  394. package/packages/@monomind/cli/dist/src/init/statusline-generator.js +3 -1
  395. package/packages/@monomind/cli/dist/src/init/types.d.ts +35 -11
  396. package/packages/@monomind/cli/dist/src/init/types.js +5 -9
  397. package/packages/@monomind/cli/dist/src/interactive/interrupt.js +8 -3
  398. package/packages/@monomind/cli/dist/src/mcp/tool-registry.js +38 -4
  399. package/packages/@monomind/cli/dist/src/mcp-client.js +10 -4
  400. package/packages/@monomind/cli/dist/src/mcp-server.d.ts +9 -2
  401. package/packages/@monomind/cli/dist/src/mcp-server.js +182 -35
  402. package/packages/@monomind/cli/dist/src/mcp-tools/agent-tools.js +66 -34
  403. package/packages/@monomind/cli/dist/src/mcp-tools/agentdb-tools.js +34 -7
  404. package/packages/@monomind/cli/dist/src/mcp-tools/analyze-tools.js +25 -16
  405. package/packages/@monomind/cli/dist/src/mcp-tools/auto-install.js +4 -6
  406. package/packages/@monomind/cli/dist/src/mcp-tools/autopilot-tools.js +12 -2
  407. package/packages/@monomind/cli/dist/src/mcp-tools/browser-tools.js +199 -20
  408. package/packages/@monomind/cli/dist/src/mcp-tools/claims-tools.js +68 -18
  409. package/packages/@monomind/cli/dist/src/mcp-tools/config-tools.js +33 -5
  410. package/packages/@monomind/cli/dist/src/mcp-tools/coordination-tools.js +59 -4
  411. package/packages/@monomind/cli/dist/src/mcp-tools/daa-tools.js +46 -10
  412. package/packages/@monomind/cli/dist/src/mcp-tools/embeddings-tools.js +46 -5
  413. package/packages/@monomind/cli/dist/src/mcp-tools/github-tools.js +29 -16
  414. package/packages/@monomind/cli/dist/src/mcp-tools/guidance-tools.js +38 -10
  415. package/packages/@monomind/cli/dist/src/mcp-tools/hive-mind-tools.js +96 -33
  416. package/packages/@monomind/cli/dist/src/mcp-tools/hooks-tools.js +70 -37
  417. package/packages/@monomind/cli/dist/src/mcp-tools/memory-tools.js +29 -13
  418. package/packages/@monomind/cli/dist/src/mcp-tools/monograph-tools.js +5867 -56
  419. package/packages/@monomind/cli/dist/src/mcp-tools/neural-tools.js +121 -37
  420. package/packages/@monomind/cli/dist/src/mcp-tools/performance-tools.js +21 -8
  421. package/packages/@monomind/cli/dist/src/mcp-tools/progress-tools.js +10 -8
  422. package/packages/@monomind/cli/dist/src/mcp-tools/request-tracker.js +4 -1
  423. package/packages/@monomind/cli/dist/src/mcp-tools/ruvllm-tools.js +19 -8
  424. package/packages/@monomind/cli/dist/src/mcp-tools/session-tools.js +57 -17
  425. package/packages/@monomind/cli/dist/src/mcp-tools/swarm-tools.js +35 -17
  426. package/packages/@monomind/cli/dist/src/mcp-tools/system-tools.js +4 -3
  427. package/packages/@monomind/cli/dist/src/mcp-tools/task-tools.js +53 -13
  428. package/packages/@monomind/cli/dist/src/mcp-tools/terminal-tools.js +63 -14
  429. package/packages/@monomind/cli/dist/src/mcp-tools/transfer-tools.js +21 -16
  430. package/packages/@monomind/cli/dist/src/mcp-tools/workflow-tools.js +92 -23
  431. package/packages/@monomind/cli/dist/src/memory/ewc-consolidation.js +41 -10
  432. package/packages/@monomind/cli/dist/src/memory/intelligence.d.ts +2 -2
  433. package/packages/@monomind/cli/dist/src/memory/intelligence.js +39 -13
  434. package/packages/@monomind/cli/dist/src/memory/memory-bridge.d.ts +1 -0
  435. package/packages/@monomind/cli/dist/src/memory/memory-bridge.js +149 -56
  436. package/packages/@monomind/cli/dist/src/memory/memory-initializer.js +107 -45
  437. package/packages/@monomind/cli/dist/src/memory/sona-optimizer.d.ts +8 -1
  438. package/packages/@monomind/cli/dist/src/memory/sona-optimizer.js +25 -8
  439. package/packages/@monomind/cli/dist/src/observability/replay-reader.d.ts +40 -0
  440. package/packages/@monomind/cli/dist/src/observability/replay-reader.js +138 -0
  441. package/packages/@monomind/cli/dist/src/orchestration/routing-modes.js +35 -5
  442. package/packages/@monomind/cli/dist/src/parser.d.ts +8 -0
  443. package/packages/@monomind/cli/dist/src/parser.js +48 -14
  444. package/packages/@monomind/cli/dist/src/plugins/manager.js +112 -19
  445. package/packages/@monomind/cli/dist/src/plugins/store/discovery.d.ts +1 -1
  446. package/packages/@monomind/cli/dist/src/plugins/store/discovery.js +80 -62
  447. package/packages/@monomind/cli/dist/src/production/circuit-breaker.js +8 -1
  448. package/packages/@monomind/cli/dist/src/production/error-handler.d.ts +4 -2
  449. package/packages/@monomind/cli/dist/src/production/error-handler.js +27 -5
  450. package/packages/@monomind/cli/dist/src/production/monitoring.js +8 -4
  451. package/packages/@monomind/cli/dist/src/production/rate-limiter.js +30 -22
  452. package/packages/@monomind/cli/dist/src/ruvector/agent-wasm.js +2 -2
  453. package/packages/@monomind/cli/dist/src/ruvector/coverage-router.js +19 -9
  454. package/packages/@monomind/cli/dist/src/ruvector/diff-classifier.d.ts +1 -0
  455. package/packages/@monomind/cli/dist/src/ruvector/diff-classifier.js +26 -6
  456. package/packages/@monomind/cli/dist/src/ruvector/enhanced-model-router.js +24 -2
  457. package/packages/@monomind/cli/dist/src/ruvector/index.d.ts +1 -2
  458. package/packages/@monomind/cli/dist/src/ruvector/index.js +2 -2
  459. package/packages/@monomind/cli/dist/src/ruvector/model-router.d.ts +4 -2
  460. package/packages/@monomind/cli/dist/src/ruvector/model-router.js +30 -6
  461. package/packages/@monomind/cli/dist/src/ruvector/moe-router.d.ts +7 -0
  462. package/packages/@monomind/cli/dist/src/ruvector/moe-router.js +35 -12
  463. package/packages/@monomind/cli/dist/src/ruvector/q-learning-router.d.ts +7 -1
  464. package/packages/@monomind/cli/dist/src/ruvector/q-learning-router.js +40 -9
  465. package/packages/@monomind/cli/dist/src/services/claim-service.d.ts +3 -1
  466. package/packages/@monomind/cli/dist/src/services/claim-service.js +33 -2
  467. package/packages/@monomind/cli/dist/src/services/config-file-manager.d.ts +16 -2
  468. package/packages/@monomind/cli/dist/src/services/config-file-manager.js +105 -17
  469. package/packages/@monomind/cli/dist/src/services/container-worker-pool.js +51 -11
  470. package/packages/@monomind/cli/dist/src/services/headless-worker-executor.d.ts +7 -0
  471. package/packages/@monomind/cli/dist/src/services/headless-worker-executor.js +188 -45
  472. package/packages/@monomind/cli/dist/src/services/registry-api.js +62 -9
  473. package/packages/@monomind/cli/dist/src/services/ruvector-training.js +8 -0
  474. package/packages/@monomind/cli/dist/src/services/worker-daemon.d.ts +4 -1
  475. package/packages/@monomind/cli/dist/src/services/worker-daemon.js +112 -28
  476. package/packages/@monomind/cli/dist/src/services/worker-queue.d.ts +9 -2
  477. package/packages/@monomind/cli/dist/src/services/worker-queue.js +86 -5
  478. package/packages/@monomind/cli/dist/src/suggest.js +9 -0
  479. package/packages/@monomind/cli/dist/src/swarm/flow-enforcer.d.ts +5 -3
  480. package/packages/@monomind/cli/dist/src/swarm/flow-enforcer.js +17 -5
  481. package/packages/@monomind/cli/dist/src/swarm/flow-visualizer.d.ts +3 -0
  482. package/packages/@monomind/cli/dist/src/swarm/flow-visualizer.js +30 -6
  483. package/packages/@monomind/cli/dist/src/transfer/anonymization/index.js +5 -3
  484. package/packages/@monomind/cli/dist/src/transfer/export.js +5 -3
  485. package/packages/@monomind/cli/dist/src/transfer/ipfs/client.js +84 -7
  486. package/packages/@monomind/cli/dist/src/transfer/ipfs/upload.js +13 -4
  487. package/packages/@monomind/cli/dist/src/transfer/storage/gcs.js +19 -10
  488. package/packages/@monomind/cli/dist/src/transfer/store/discovery.d.ts +9 -2
  489. package/packages/@monomind/cli/dist/src/transfer/store/discovery.js +68 -13
  490. package/packages/@monomind/cli/dist/src/transfer/store/download.d.ts +15 -6
  491. package/packages/@monomind/cli/dist/src/transfer/store/download.js +113 -24
  492. package/packages/@monomind/cli/dist/src/transfer/store/publish.d.ts +1 -1
  493. package/packages/@monomind/cli/dist/src/transfer/store/publish.js +13 -14
  494. package/packages/@monomind/cli/dist/src/transfer/store/registry.d.ts +3 -3
  495. package/packages/@monomind/cli/dist/src/transfer/store/registry.js +32 -16
  496. package/packages/@monomind/cli/dist/src/update/checker.js +17 -4
  497. package/packages/@monomind/cli/dist/src/update/executor.js +25 -20
  498. package/packages/@monomind/cli/dist/src/update/rate-limiter.d.ts +11 -0
  499. package/packages/@monomind/cli/dist/src/update/rate-limiter.js +23 -3
  500. package/packages/@monomind/cli/dist/src/utils/parse-jsonl.d.ts +6 -0
  501. package/packages/@monomind/cli/dist/src/utils/parse-jsonl.js +22 -0
  502. package/packages/@monomind/cli/dist/src/workflow/condition-evaluator.js +37 -3
  503. package/packages/@monomind/cli/dist/src/workflow/dag-builder.js +27 -11
  504. package/packages/@monomind/cli/dist/src/workflow/dag-executor.js +51 -13
  505. package/packages/@monomind/cli/dist/src/workflow/dsl-schema.d.ts +3 -0
  506. package/packages/@monomind/cli/dist/src/workflow/dsl-schema.js +6 -2
  507. package/packages/@monomind/cli/dist/src/workflow/template-engine.js +7 -0
  508. package/packages/@monomind/cli/dist/src/workflow/workflow-executor.js +95 -14
  509. package/packages/@monomind/cli/package.json +5 -3
  510. package/packages/@monomind/guidance/README.md +1192 -0
  511. package/packages/@monomind/shared/README.md +322 -0
  512. package/packages/@monomind/shared/dist/types/consensus-audit.d.ts +3 -1
  513. package/packages/README.md +513 -0
  514. package/.claude/agents/design/design-brand-guardian.md +0 -323
  515. package/.claude/agents/design/design-image-prompt-engineer.md +0 -237
  516. package/.claude/agents/design/design-inclusive-visuals-specialist.md +0 -72
  517. package/.claude/agents/design/design-ui-designer.md +0 -384
  518. package/.claude/agents/design/design-ux-architect.md +0 -470
  519. package/.claude/agents/design/design-ux-researcher.md +0 -330
  520. package/.claude/agents/design/design-visual-storyteller.md +0 -150
  521. package/.claude/agents/design/design-whimsy-injector.md +0 -439
  522. package/.claude/agents/v3/integration-architect.md +0 -338
  523. package/.claude/commands/analysis/COMMAND_COMPLIANCE_REPORT.md +0 -54
  524. package/.claude/commands/coordination/init.md +0 -44
  525. package/.claude/commands/coordination/orchestrate.md +0 -43
  526. package/.claude/commands/coordination/spawn.md +0 -45
  527. package/.claude/commands/github/code-review-swarm.md +0 -550
  528. package/.claude/commands/github/code-review.md +0 -25
  529. package/.claude/commands/github/github-swarm.md +0 -121
  530. package/.claude/commands/github/issue-triage.md +0 -25
  531. package/.claude/commands/github/multi-repo-swarm.md +0 -519
  532. package/.claude/commands/github/pr-enhance.md +0 -26
  533. package/.claude/commands/github/project-board-sync.md +0 -471
  534. package/.claude/commands/github/release-swarm.md +0 -590
  535. package/.claude/commands/github/repo-analyze.md +0 -25
  536. package/.claude/commands/github/swarm-issue.md +0 -482
  537. package/.claude/commands/github/swarm-pr.md +0 -310
  538. package/.claude/commands/github/workflow-automation.md +0 -468
  539. package/.claude/commands/hive-mind/hive-mind-metrics.md +0 -8
  540. package/.claude/commands/hive-mind/hive-mind-resume.md +0 -8
  541. package/.claude/commands/hive-mind/hive-mind-sessions.md +0 -8
  542. package/.claude/commands/hive-mind/hive-mind-wizard.md +0 -8
  543. package/.claude/commands/list-agents.md +0 -17
  544. package/.claude/commands/memory/memory-persist.md +0 -25
  545. package/.claude/commands/memory/memory-usage.md +0 -25
  546. package/.claude/commands/memory/neural.md +0 -47
  547. package/.claude/commands/metrics.md +0 -11
  548. package/.claude/commands/monitoring/real-time-view.md +0 -25
  549. package/.claude/commands/monitoring/swarm-monitor.md +0 -25
  550. package/.claude/commands/monomind-createtask.md +0 -302
  551. package/.claude/commands/monomind-help.md +0 -103
  552. package/.claude/commands/monomind-memory.md +0 -107
  553. package/.claude/commands/monomind-repeat.md +0 -149
  554. package/.claude/commands/monomind-swarm.md +0 -205
  555. package/.claude/commands/optimization/cache-manage.md +0 -25
  556. package/.claude/commands/optimization/topology-optimize.md +0 -25
  557. package/.claude/commands/pair/commands.md +0 -546
  558. package/.claude/commands/pair/config.md +0 -510
  559. package/.claude/commands/pair/start.md +0 -209
  560. package/.claude/commands/use-agent.md +0 -67
  561. package/.claude/skills/monomind-createtask/SKILL.md +0 -269
  562. package/.claude/skills/monomind-task-engine/SKILL.md +0 -358
  563. /package/.claude/agents/{v3 → specialists}/memory-specialist.md +0 -0
  564. /package/.claude/agents/{v3 → specialists}/performance-engineer.md +0 -0
  565. /package/.claude/agents/{v3 → specialists}/queen-coordinator.md +0 -0
  566. /package/.claude/agents/{v3 → specialists}/security-architect.md +0 -0
@@ -16,11 +16,19 @@
16
16
  * - Network isolation per worker type
17
17
  */
18
18
  import { EventEmitter } from 'events';
19
- import { spawn, exec } from 'child_process';
19
+ import { spawn, exec, execFile } from 'child_process';
20
20
  import { promisify } from 'util';
21
21
  import { existsSync, mkdirSync } from 'fs';
22
22
  import { join } from 'path';
23
23
  const execAsync = promisify(exec);
24
+ const execFileAsync = promisify(execFile);
25
+ /** Allowlist: registry/name:tag with optional digest — no shell metacharacters */
26
+ const DOCKER_IMAGE_RE = /^[a-zA-Z0-9][a-zA-Z0-9.\-_/:@]*$/;
27
+ function validateDockerImage(image) {
28
+ if (!DOCKER_IMAGE_RE.test(image)) {
29
+ throw new Error(`Invalid Docker image name: "${image}"`);
30
+ }
31
+ }
24
32
  // ============================================
25
33
  // Constants
26
34
  // ============================================
@@ -134,6 +142,10 @@ export class ContainerWorkerPool extends EventEmitter {
134
142
  }
135
143
  }
136
144
  // Queue the task
145
+ const MAX_TASK_QUEUE = 500;
146
+ if (this.taskQueue.length >= MAX_TASK_QUEUE) {
147
+ return this.createErrorResult(options.workerType, 'Task queue is full');
148
+ }
137
149
  return new Promise((resolve, reject) => {
138
150
  this.taskQueue.push({
139
151
  options,
@@ -236,13 +248,14 @@ export class ContainerWorkerPool extends EventEmitter {
236
248
  */
237
249
  async ensureImage() {
238
250
  try {
239
- await execAsync(`docker image inspect ${this.config.image}`, { timeout: 10000 });
251
+ validateDockerImage(this.config.image);
252
+ await execFileAsync('docker', ['image', 'inspect', this.config.image], { timeout: 10000 });
240
253
  }
241
254
  catch {
242
255
  // Image not found, try to pull
243
256
  this.emit('imagePull', { image: this.config.image });
244
257
  try {
245
- await execAsync(`docker pull ${this.config.image}`, { timeout: 300000 });
258
+ await execFileAsync('docker', ['pull', this.config.image], { timeout: 300000 });
246
259
  }
247
260
  catch (error) {
248
261
  this.emit('warning', { message: `Failed to pull image: ${error}` });
@@ -267,23 +280,48 @@ export class ContainerWorkerPool extends EventEmitter {
267
280
  this.containers.set(id, containerInfo);
268
281
  this.emit('containerCreating', { id, name });
269
282
  try {
270
- // Build docker run command
283
+ // Build docker run command with hardening flags.
284
+ // Without these flags the container ran with default capabilities and
285
+ // privilege escalation enabled — combined with a writable host mount
286
+ // that is JSON-parsed by the daemon, this was a container-to-host RCE
287
+ // chain (claims.json/daemon-state.json could be rewritten from inside).
288
+ const stateMount = join(this.projectRoot, this.config.statePath);
271
289
  const args = [
272
290
  'run', '-d',
273
291
  '--name', name,
292
+ // Resource limits
274
293
  '--cpus', this.config.resources.cpus,
275
294
  '--memory', this.config.resources.memory,
295
+ '--pids-limit', '256',
296
+ // Privilege & capability hardening
297
+ '--security-opt', 'no-new-privileges:true',
298
+ '--cap-drop', 'ALL',
299
+ '--user', '1000:1000',
300
+ '--ipc', 'none',
301
+ // Mounts: workspace read-only, state read-only by default with a
302
+ // narrow rw output channel for the worker to write back results.
276
303
  '-v', `${this.projectRoot}:${this.config.workspacePath}:ro`,
277
- '-v', `${join(this.projectRoot, this.config.statePath)}:/root/.monomind`,
304
+ '-v', `${stateMount}:/root/.monomind:ro`,
305
+ '-v', `${join(stateMount, 'output')}:/output:rw`,
306
+ // tmpfs for /tmp without exec
307
+ '--tmpfs', '/tmp:rw,noexec,nosuid,size=64m',
278
308
  '-w', this.config.workspacePath,
279
309
  ];
280
- // Add environment variables
310
+ // Add environment variables.
311
+ // SECURITY: ANTHROPIC_API_KEY is intentionally NOT injected via -e here.
312
+ // Visible via `docker inspect` and process listings on the host, and
313
+ // exfiltrable by indirect prompt injection via process.env. Containers
314
+ // that need API access must use a host-side proxy. Set
315
+ // MONOMIND_CONTAINER_PASS_ANTHROPIC_KEY=1 to opt back in for trusted
316
+ // single-tenant deployments.
281
317
  const env = {
282
318
  ...this.config.env,
283
- ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY || '',
284
319
  CLAUDE_CODE_HEADLESS: 'true',
285
320
  CLAUDE_CODE_SANDBOX_MODE: this.config.defaultSandbox,
286
321
  };
322
+ if (process.env.MONOMIND_CONTAINER_PASS_ANTHROPIC_KEY === '1' && process.env.ANTHROPIC_API_KEY) {
323
+ env.ANTHROPIC_API_KEY = process.env.ANTHROPIC_API_KEY;
324
+ }
287
325
  for (const [key, value] of Object.entries(env)) {
288
326
  if (value) {
289
327
  args.push('-e', `${key}=${value}`);
@@ -296,7 +334,7 @@ export class ContainerWorkerPool extends EventEmitter {
296
334
  // Add image and entrypoint to keep container running
297
335
  args.push(this.config.image, 'tail', '-f', '/dev/null');
298
336
  // Create the container (async)
299
- const { stdout } = await execAsync(`docker ${args.join(' ')}`, { timeout: 60000 });
337
+ const { stdout } = await execFileAsync('docker', args, { timeout: 60000 });
300
338
  const containerId = stdout.trim();
301
339
  containerInfo.state = 'ready';
302
340
  this.emit('containerCreated', { id, name, containerId });
@@ -317,7 +355,7 @@ export class ContainerWorkerPool extends EventEmitter {
317
355
  return;
318
356
  container.state = 'terminated';
319
357
  try {
320
- await execAsync(`docker rm -f ${container.name}`, { timeout: 30000 });
358
+ await execFileAsync('docker', ['rm', '-f', container.name], { timeout: 30000 });
321
359
  }
322
360
  catch {
323
361
  // Ignore removal errors
@@ -410,11 +448,13 @@ export class ContainerWorkerPool extends EventEmitter {
410
448
  let stdout = '';
411
449
  let stderr = '';
412
450
  let timedOut = false;
451
+ let exited = false;
452
+ child.once('exit', () => { exited = true; });
413
453
  const timeout = setTimeout(() => {
414
454
  timedOut = true;
415
455
  child.kill('SIGTERM');
416
456
  setTimeout(() => {
417
- if (!child.killed) {
457
+ if (!exited) {
418
458
  child.kill('SIGKILL');
419
459
  }
420
460
  }, 5000);
@@ -492,7 +532,7 @@ export class ContainerWorkerPool extends EventEmitter {
492
532
  continue;
493
533
  try {
494
534
  // Check if container is running (async)
495
- const { stdout } = await execAsync(`docker inspect -f '{{.State.Running}}' ${container.name}`, { timeout: 10000 });
535
+ const { stdout } = await execFileAsync('docker', ['inspect', '-f', '{{.State.Running}}', container.name], { timeout: 10000 });
496
536
  const output = stdout.trim();
497
537
  if (output !== 'true') {
498
538
  container.healthCheckFailures++;
@@ -205,7 +205,9 @@ export declare class HeadlessWorkerExecutor extends EventEmitter {
205
205
  private pendingQueue;
206
206
  private contextCache;
207
207
  private claudeCodeAvailable;
208
+ private claudeCodeAvailableCheckedAt;
208
209
  private claudeCodeVersion;
210
+ private activeReservations;
209
211
  constructor(projectRoot: string, options?: HeadlessExecutorConfig);
210
212
  /**
211
213
  * Check if Claude Code CLI is available
@@ -231,6 +233,11 @@ export declare class HeadlessWorkerExecutor extends EventEmitter {
231
233
  * Cancel a running execution
232
234
  */
233
235
  cancel(executionId: string): boolean;
236
+ /**
237
+ * Cancel all running executions for a specific worker type.
238
+ * Used by the timeout handler in worker-daemon to avoid killing unrelated workers.
239
+ */
240
+ cancelByType(workerType: string): boolean;
234
241
  /**
235
242
  * Cancel all running executions
236
243
  */
@@ -20,7 +20,7 @@
20
20
  */
21
21
  import { spawn, execSync } from 'child_process';
22
22
  import { EventEmitter } from 'events';
23
- import { existsSync, readFileSync, readdirSync, mkdirSync, writeFileSync } from 'fs';
23
+ import { existsSync, readFileSync, readdirSync, mkdirSync, writeFileSync, renameSync } from 'fs';
24
24
  import { join } from 'path';
25
25
  // ============================================
26
26
  // Constants
@@ -91,7 +91,7 @@ Provide a JSON report with:
91
91
  sandbox: 'strict',
92
92
  model: 'haiku',
93
93
  outputFormat: 'json',
94
- contextPatterns: ['**/*.ts', '**/*.js', '**/.env*', '**/package.json'],
94
+ contextPatterns: ['**/*.ts', '**/*.js', '**/package.json'],
95
95
  timeoutMs: 5 * 60 * 1000,
96
96
  },
97
97
  },
@@ -366,7 +366,13 @@ export class HeadlessWorkerExecutor extends EventEmitter {
366
366
  pendingQueue = [];
367
367
  contextCache = new Map();
368
368
  claudeCodeAvailable = null;
369
+ claudeCodeAvailableCheckedAt = null;
369
370
  claudeCodeVersion = null;
371
+ // SECURITY: synchronous reservation counter so processQueue() does not
372
+ // drain the entire pendingQueue before async pool insertions catch up.
373
+ // Without this, a single processQueue() iteration could spawn hundreds of
374
+ // claude child processes simultaneously (DoS amplifier: 1 dequeue → 500 spawns).
375
+ activeReservations = 0;
370
376
  constructor(projectRoot, options) {
371
377
  super();
372
378
  this.projectRoot = projectRoot;
@@ -390,8 +396,14 @@ export class HeadlessWorkerExecutor extends EventEmitter {
390
396
  * Check if Claude Code CLI is available
391
397
  */
392
398
  async isAvailable() {
393
- if (this.claudeCodeAvailable !== null) {
394
- return this.claudeCodeAvailable;
399
+ const NEGATIVE_CACHE_TTL_MS = 60_000; // re-check after 1 min on negative result
400
+ if (this.claudeCodeAvailable === true) {
401
+ return true;
402
+ }
403
+ if (this.claudeCodeAvailable === false && this.claudeCodeAvailableCheckedAt !== null) {
404
+ if (Date.now() - this.claudeCodeAvailableCheckedAt < NEGATIVE_CACHE_TTL_MS) {
405
+ return false;
406
+ }
395
407
  }
396
408
  try {
397
409
  const output = execSync('claude --version', {
@@ -401,12 +413,14 @@ export class HeadlessWorkerExecutor extends EventEmitter {
401
413
  windowsHide: true, // Prevent phantom console windows on Windows
402
414
  });
403
415
  this.claudeCodeAvailable = true;
416
+ this.claudeCodeAvailableCheckedAt = Date.now();
404
417
  this.claudeCodeVersion = output.trim();
405
418
  this.emit('status', { available: true, version: this.claudeCodeVersion });
406
419
  return true;
407
420
  }
408
421
  catch {
409
422
  this.claudeCodeAvailable = false;
423
+ this.claudeCodeAvailableCheckedAt = Date.now();
410
424
  this.emit('status', { available: false });
411
425
  return false;
412
426
  }
@@ -433,9 +447,14 @@ export class HeadlessWorkerExecutor extends EventEmitter {
433
447
  this.emit('error', result);
434
448
  return result;
435
449
  }
436
- // Check concurrent limit
437
- if (this.processPool.size >= this.config.maxConcurrent) {
450
+ // Check concurrent limit using activeReservations (synchronous counter)
451
+ // rather than processPool.size (which is updated only after async setup).
452
+ if (this.activeReservations >= this.config.maxConcurrent) {
438
453
  // Queue the request
454
+ const MAX_PENDING = 500;
455
+ if (this.pendingQueue.length >= MAX_PENDING) {
456
+ return this.createErrorResult(workerType, 'Pending queue is full');
457
+ }
439
458
  return new Promise((resolve, reject) => {
440
459
  const entry = {
441
460
  workerType,
@@ -451,8 +470,16 @@ export class HeadlessWorkerExecutor extends EventEmitter {
451
470
  });
452
471
  });
453
472
  }
454
- // Execute immediately
455
- return this.executeInternal(workerType, configOverrides);
473
+ // Reserve the slot synchronously and release it (regardless of success
474
+ // or failure) so processQueue can pull the next pending item.
475
+ this.activeReservations++;
476
+ try {
477
+ return await this.executeInternal(workerType, configOverrides);
478
+ }
479
+ finally {
480
+ this.activeReservations--;
481
+ this.processQueue();
482
+ }
456
483
  }
457
484
  /**
458
485
  * Get pool status
@@ -491,13 +518,63 @@ export class HeadlessWorkerExecutor extends EventEmitter {
491
518
  return false;
492
519
  }
493
520
  clearTimeout(entry.timeout);
494
- entry.process.kill('SIGTERM');
521
+ let exited = false;
522
+ entry.process.once('exit', () => { exited = true; });
523
+ try {
524
+ entry.process.kill('SIGTERM');
525
+ }
526
+ catch { /* may already be dead */ }
527
+ const killTimer = setTimeout(() => {
528
+ if (!exited) {
529
+ try {
530
+ entry.process.kill('SIGKILL');
531
+ }
532
+ catch { /* ignore */ }
533
+ }
534
+ }, 5000);
535
+ killTimer.unref();
536
+ entry.process.once('exit', () => clearTimeout(killTimer));
495
537
  this.processPool.delete(executionId);
496
538
  this.emit('cancelled', { executionId });
497
539
  // Process next in queue
498
540
  this.processQueue();
499
541
  return true;
500
542
  }
543
+ /**
544
+ * Cancel all running executions for a specific worker type.
545
+ * Used by the timeout handler in worker-daemon to avoid killing unrelated workers.
546
+ */
547
+ cancelByType(workerType) {
548
+ let cancelled = false;
549
+ const entries = Array.from(this.processPool.entries());
550
+ for (const [executionId, entry] of entries) {
551
+ if (entry.workerType !== workerType)
552
+ continue;
553
+ clearTimeout(entry.timeout);
554
+ let exited = false;
555
+ entry.process.once('exit', () => { exited = true; });
556
+ try {
557
+ entry.process.kill('SIGTERM');
558
+ }
559
+ catch { /* may already be dead */ }
560
+ const killTimer = setTimeout(() => {
561
+ if (!exited) {
562
+ try {
563
+ entry.process.kill('SIGKILL');
564
+ }
565
+ catch { /* ignore */ }
566
+ }
567
+ }, 5000);
568
+ killTimer.unref();
569
+ entry.process.once('exit', () => clearTimeout(killTimer));
570
+ this.processPool.delete(executionId);
571
+ this.emit('cancelled', { executionId });
572
+ cancelled = true;
573
+ }
574
+ if (cancelled)
575
+ this.processQueue();
576
+ return cancelled;
577
+ }
501
578
  /**
502
579
  * Cancel all running executions
503
580
  */
@@ -507,15 +584,26 @@ export class HeadlessWorkerExecutor extends EventEmitter {
507
584
  const entries = Array.from(this.processPool.entries());
508
585
  for (const [executionId, entry] of entries) {
509
586
  clearTimeout(entry.timeout);
510
- entry.process.kill('SIGTERM');
511
- // SIGKILL fallback after 5s to prevent orphan processes (#1395 Bug 6)
512
- setTimeout(() => {
587
+ // Track exit so the SIGKILL fallback can't be sent to a recycled PID.
588
+ // entry.process.killed is set by Node when .kill() was called, NOT when
589
+ // the OS process actually exited — without an explicit 'exit' listener,
590
+ // a recycled PID can receive our SIGKILL.
591
+ let exited = false;
592
+ entry.process.once('exit', () => { exited = true; });
593
+ try {
594
+ entry.process.kill('SIGTERM');
595
+ }
596
+ catch { /* may already be dead */ }
597
+ const killTimer = setTimeout(() => {
598
+ if (exited)
599
+ return;
513
600
  try {
514
- if (!entry.process.killed)
515
- entry.process.kill('SIGKILL');
601
+ entry.process.kill('SIGKILL');
516
602
  }
517
603
  catch { /* already dead */ }
518
- }, 5000).unref();
604
+ }, 5000);
605
+ killTimer.unref();
606
+ entry.process.once('exit', () => clearTimeout(killTimer));
519
607
  this.emit('cancelled', { executionId });
520
608
  cancelled++;
521
609
  }
@@ -637,14 +725,21 @@ export class HeadlessWorkerExecutor extends EventEmitter {
637
725
  * Process the pending queue
638
726
  */
639
727
  processQueue() {
728
+ // Gate on activeReservations (synchronous counter) so we cannot
729
+ // accidentally drain the queue past maxConcurrent before async setup
730
+ // populates processPool.
640
731
  while (this.pendingQueue.length > 0 &&
641
- this.processPool.size < this.config.maxConcurrent) {
732
+ this.activeReservations < this.config.maxConcurrent) {
642
733
  const next = this.pendingQueue.shift();
643
734
  if (!next)
644
735
  break;
736
+ this.activeReservations++;
645
737
  this.executeInternal(next.workerType, next.config)
646
- .then(next.resolve)
647
- .catch(next.reject);
738
+ .then(next.resolve, next.reject)
739
+ .finally(() => {
740
+ this.activeReservations--;
741
+ this.processQueue();
742
+ });
648
743
  }
649
744
  }
650
745
  /**
@@ -670,13 +765,18 @@ export class HeadlessWorkerExecutor extends EventEmitter {
670
765
  // Deduplicate and limit
671
766
  const uniqueFiles = Array.from(new Set(files)).slice(0, this.config.maxContextFiles);
672
767
  // Build context
768
+ const { resolve: resolvePath, sep } = await import('path');
673
769
  const contextParts = [];
674
770
  for (const file of uniqueFiles) {
675
771
  try {
676
772
  const fullPath = join(this.projectRoot, file);
677
- if (!existsSync(fullPath))
773
+ const resolvedFull = resolvePath(fullPath);
774
+ const resolvedRoot = resolvePath(this.projectRoot);
775
+ if (!resolvedFull.startsWith(resolvedRoot + sep) && resolvedFull !== resolvedRoot)
776
+ continue;
777
+ if (!existsSync(resolvedFull))
678
778
  continue;
679
- const content = readFileSync(fullPath, 'utf-8');
779
+ const content = readFileSync(resolvedFull, 'utf-8');
680
780
  const truncated = content.slice(0, this.config.maxCharsPerFile);
681
781
  const wasTruncated = content.length > this.config.maxCharsPerFile;
682
782
  contextParts.push(`--- ${file}${wasTruncated ? ' (truncated)' : ''} ---\n${truncated}`);
@@ -686,8 +786,13 @@ export class HeadlessWorkerExecutor extends EventEmitter {
686
786
  }
687
787
  }
688
788
  const contextContent = contextParts.join('\n\n');
689
- // Cache the result
789
+ // Cache the result (evict oldest when at capacity)
690
790
  if (this.config.cacheContext) {
791
+ if (this.contextCache.size >= 50) {
792
+ const oldestKey = this.contextCache.keys().next().value;
793
+ if (oldestKey !== undefined)
794
+ this.contextCache.delete(oldestKey);
795
+ }
691
796
  this.contextCache.set(cacheKey, {
692
797
  content: contextContent,
693
798
  timestamp: Date.now(),
@@ -815,8 +920,45 @@ Analyze the above codebase context and provide your response following the forma
815
920
  */
816
921
  executeClaudeCode(prompt, options) {
817
922
  return new Promise((resolve) => {
923
+ // SECURITY: in strict sandbox mode, build a minimal env allowlist instead
924
+ // of forwarding the entire parent env. The previous spread also passed
925
+ // LD_PRELOAD, NODE_OPTIONS, DYLD_INSERT_LIBRARIES, PYTHONPATH, HTTP_PROXY,
926
+ // etc. — which means "strict" was a label, not a control. Now it actually
927
+ // strips dangerous loaders/proxies even when the parent has them set.
928
+ const STRICT_ENV_ALLOWLIST = new Set([
929
+ 'PATH', 'HOME', 'USER', 'LOGNAME', 'LANG', 'LC_ALL', 'TZ', 'TERM', 'SHELL',
930
+ 'TMPDIR', 'TMP', 'TEMP',
931
+ 'ANTHROPIC_API_KEY', 'ANTHROPIC_MODEL', 'ANTHROPIC_BASE_URL',
932
+ ]);
933
+ const FORBIDDEN_ENV = new Set([
934
+ 'LD_PRELOAD', 'LD_LIBRARY_PATH', 'LD_AUDIT',
935
+ 'DYLD_INSERT_LIBRARIES', 'DYLD_LIBRARY_PATH', 'DYLD_FALLBACK_LIBRARY_PATH',
936
+ 'NODE_OPTIONS', 'NODE_PATH',
937
+ 'PYTHONPATH', 'PYTHONHOME', 'PYTHONSTARTUP',
938
+ 'HTTP_PROXY', 'HTTPS_PROXY', 'NO_PROXY',
939
+ 'BASH_ENV', 'ENV', 'CDPATH',
940
+ 'PERL5OPT', 'RUBYOPT',
941
+ 'JAVA_TOOL_OPTIONS', '_JAVA_OPTIONS', 'JDK_JAVA_OPTIONS',
942
+ ]);
943
+ const baseEnv = {};
944
+ if (options.sandbox === 'strict') {
945
+ for (const k of STRICT_ENV_ALLOWLIST) {
946
+ const v = process.env[k];
947
+ if (typeof v === 'string')
948
+ baseEnv[k] = v;
949
+ }
950
+ }
951
+ else {
952
+ for (const [k, v] of Object.entries(process.env)) {
953
+ if (typeof v !== 'string')
954
+ continue;
955
+ if (FORBIDDEN_ENV.has(k))
956
+ continue; // always strip in any mode
957
+ baseEnv[k] = v;
958
+ }
959
+ }
818
960
  const env = {
819
- ...process.env,
961
+ ...baseEnv,
820
962
  CLAUDE_CODE_HEADLESS: 'true',
821
963
  CLAUDE_CODE_SANDBOX_MODE: options.sandbox,
822
964
  // Fix #1395 Bug 2: Workers fail inside active Claude Code session.
@@ -831,23 +973,36 @@ Analyze the above codebase context and provide your response following the forma
831
973
  // Set model
832
974
  // Resolve model: user env override > config override > default alias
833
975
  env.ANTHROPIC_MODEL = process.env.ANTHROPIC_MODEL || MODEL_IDS[options.model];
834
- // Spawn claude CLI process
835
- const child = spawn('claude', ['--print', prompt], {
976
+ // Spawn claude CLI process — `--` terminates option parsing so prompt can't smuggle flags
977
+ const child = spawn('claude', ['--print', '--', prompt], {
836
978
  cwd: this.projectRoot,
837
979
  env,
838
980
  stdio: ['ignore', 'pipe', 'pipe'], // 'ignore' closes stdin at spawn — fixes #1395 where claude --print blocks on EOF
839
981
  windowsHide: true, // Prevent phantom console windows on Windows
840
982
  });
841
- // Setup timeout
983
+ // Setup timeout — track real exit via 'exit' listener.
984
+ // child.killed is set by Node when .kill() is called (signal sent), NOT
985
+ // when the OS process exited. Without an explicit `exited` flag the
986
+ // SIGKILL fallback never fires for a process that ignores SIGTERM, and
987
+ // the slot leaks indefinitely.
988
+ let sigkillTimer;
989
+ let childExited = false;
990
+ child.once('exit', () => { childExited = true; });
842
991
  const timeoutHandle = setTimeout(() => {
843
992
  if (this.processPool.has(options.executionId)) {
844
- child.kill('SIGTERM');
845
- // Give it a moment to terminate gracefully
846
- setTimeout(() => {
847
- if (!child.killed) {
993
+ try {
994
+ child.kill('SIGTERM');
995
+ }
996
+ catch { /* may already be dead */ }
997
+ sigkillTimer = setTimeout(() => {
998
+ if (childExited)
999
+ return;
1000
+ try {
848
1001
  child.kill('SIGKILL');
849
1002
  }
1003
+ catch { /* already dead */ }
850
1004
  }, 5000);
1005
+ sigkillTimer.unref();
851
1006
  }
852
1007
  }, options.timeoutMs);
853
1008
  // Track in process pool
@@ -864,6 +1019,7 @@ Analyze the above codebase context and provide your response following the forma
864
1019
  let resolved = false;
865
1020
  const cleanup = () => {
866
1021
  clearTimeout(timeoutHandle);
1022
+ clearTimeout(sigkillTimer);
867
1023
  this.processPool.delete(options.executionId);
868
1024
  };
869
1025
  child.stdout?.on('data', (data) => {
@@ -906,21 +1062,6 @@ Analyze the above codebase context and provide your response following the forma
906
1062
  error: error.message,
907
1063
  });
908
1064
  });
909
- // Handle timeout
910
- setTimeout(() => {
911
- if (resolved)
912
- return;
913
- if (!this.processPool.has(options.executionId))
914
- return;
915
- resolved = true;
916
- child.kill('SIGTERM');
917
- cleanup();
918
- resolve({
919
- success: false,
920
- output: stdout || stderr,
921
- error: `Execution timed out after ${options.timeoutMs}ms`,
922
- });
923
- }, options.timeoutMs + 100); // Slightly after the kill timeout
924
1065
  });
925
1066
  }
926
1067
  /**
@@ -1012,7 +1153,9 @@ Analyze the above codebase context and provide your response following the forma
1012
1153
  const timestamp = new Date().toISOString();
1013
1154
  const logFile = join(this.config.logDir, `${executionId}_${type}.log`);
1014
1155
  const logContent = `[${timestamp}] ${type.toUpperCase()}\n${'='.repeat(60)}\n${content}\n`;
1015
- writeFileSync(logFile, logContent);
1156
+ const tmpLog = logFile + '.tmp';
1157
+ writeFileSync(tmpLog, logContent);
1158
+ renameSync(tmpLog, logFile);
1016
1159
  }
1017
1160
  catch {
1018
1161
  // Ignore log write errors
@@ -9,12 +9,65 @@
9
9
  * - Input validation
10
10
  */
11
11
  const REGISTRY_API_URL = 'https://us-central1-monomind.cloudfunctions.net/publish-registry';
12
+ /**
13
+ * Read a fetch response body with a hard byte cap. AbortSignal.timeout bounds
14
+ * time, NOT bytes — a hijacked endpoint or MITM (TLS without pinning) can
15
+ * stream a multi-GB body that the CLI buffers into memory and OOMs. Cap the
16
+ * read here so all downstream JSON.parse / .text() calls are bounded.
17
+ */
18
+ async function readBoundedText(response, maxBytes) {
19
+ const lenHdr = response.headers.get('content-length');
20
+ if (lenHdr) {
21
+ const declared = parseInt(lenHdr, 10);
22
+ if (Number.isFinite(declared) && declared > maxBytes) {
23
+ throw new Error(`Response too large: ${declared} bytes (max ${maxBytes})`);
24
+ }
25
+ }
26
+ if (!response.body)
27
+ return '';
28
+ const reader = response.body.getReader();
29
+ const chunks = [];
30
+ let total = 0;
31
+ while (true) {
32
+ const { done, value } = await reader.read();
33
+ if (done)
34
+ break;
35
+ if (value) {
36
+ total += value.byteLength;
37
+ if (total > maxBytes) {
38
+ await reader.cancel();
39
+ throw new Error(`Response too large: exceeded ${maxBytes} bytes`);
40
+ }
41
+ chunks.push(value);
42
+ }
43
+ }
44
+ const buf = new Uint8Array(total);
45
+ let off = 0;
46
+ for (const c of chunks) {
47
+ buf.set(c, off);
48
+ off += c.byteLength;
49
+ }
50
+ return new TextDecoder('utf-8').decode(buf);
51
+ }
52
+ async function readBoundedJson(response, maxBytes = 1_048_576) {
53
+ const text = await readBoundedText(response, maxBytes);
54
+ return JSON.parse(text);
55
+ }
56
+ /**
57
+ * Strip control chars and cap length on attacker-controlled error body before
58
+ * inlining into a thrown Error.message. Without this, a malicious or
59
+ * compromised endpoint can deliver multi-MB error bodies that flow into log
60
+ * aggregators via unhandled-rejection traces.
61
+ */
62
+ function safeErrText(s) {
63
+ return s.replace(/[\x00-\x1f\x7f]/g, '?').slice(0, 512);
64
+ }
12
65
  /**
13
66
  * Validate item ID to prevent injection
14
67
  */
15
68
  function validateItemId(itemId) {
16
- // Only allow alphanumeric, @, /, -, _
17
- return /^[@a-zA-Z0-9\/_-]+$/.test(itemId) && itemId.length < 100;
69
+ // Scoped packages (@scope/name) or plain identifiers — no other slashes allowed
70
+ return /^(@[a-zA-Z0-9][a-zA-Z0-9_-]*\/[a-zA-Z0-9][a-zA-Z0-9_-]*|[a-zA-Z0-9][a-zA-Z0-9_-]*)$/.test(itemId) && itemId.length < 100;
18
71
  }
19
72
  /**
20
73
  * Validate rating value
@@ -44,10 +97,10 @@ export async function rateItem(itemId, rating, itemType = 'plugin', userId) {
44
97
  signal: AbortSignal.timeout(10000),
45
98
  });
46
99
  if (!response.ok) {
47
- const error = await response.text();
48
- throw new Error(`Rating failed: ${error}`);
100
+ const error = await readBoundedText(response, 64 * 1024).catch(() => 'unreadable');
101
+ throw new Error(`Rating failed: ${safeErrText(error)}`);
49
102
  }
50
- return response.json();
103
+ return readBoundedJson(response);
51
104
  }
52
105
  /**
53
106
  * Get ratings for a single item
@@ -67,7 +120,7 @@ export async function getRating(itemId, itemType = 'plugin') {
67
120
  if (!response.ok) {
68
121
  throw new Error('Failed to get ratings');
69
122
  }
70
- return response.json();
123
+ return readBoundedJson(response);
71
124
  }
72
125
  /**
73
126
  * Get ratings for multiple items (batch)
@@ -93,7 +146,7 @@ export async function getBulkRatings(itemIds, itemType = 'plugin') {
93
146
  if (!response.ok) {
94
147
  throw new Error('Failed to get bulk ratings');
95
148
  }
96
- return response.json();
149
+ return readBoundedJson(response, 4 * 1024 * 1024);
97
150
  }
98
151
  /**
99
152
  * Get analytics data
@@ -105,7 +158,7 @@ export async function getAnalytics() {
105
158
  if (!response.ok) {
106
159
  throw new Error('Failed to get analytics');
107
160
  }
108
- return response.json();
161
+ return readBoundedJson(response);
109
162
  }
110
163
  /**
111
164
  * Track a download event
@@ -134,7 +187,7 @@ export async function checkHealth() {
134
187
  const response = await fetch(`${REGISTRY_API_URL}?action=status`, {
135
188
  signal: AbortSignal.timeout(5000),
136
189
  });
137
- return response.json();
190
+ return readBoundedJson(response, 64 * 1024);
138
191
  }
139
192
  catch (error) {
140
193
  return {