@monoes/monomindcli 1.10.47 → 1.10.55

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 (573) hide show
  1. package/.claude/agents/optimization/benchmark-suite.md +2 -0
  2. package/.claude/agents/optimization/load-balancer.md +2 -0
  3. package/.claude/agents/optimization/performance-monitor.md +2 -0
  4. package/.claude/agents/optimization/resource-allocator.md +3 -1
  5. package/.claude/agents/optimization/topology-optimizer.md +2 -0
  6. package/.claude/commands/mastermind/_repeat.md +21 -0
  7. package/.claude/commands/mastermind/_taskfile.md +235 -0
  8. package/.claude/commands/mastermind/adr.md +11 -0
  9. package/.claude/commands/mastermind/approve.md +94 -0
  10. package/.claude/commands/mastermind/autodev.md +32 -0
  11. package/.claude/commands/mastermind/budget.md +7 -0
  12. package/.claude/commands/mastermind/code-review.md +317 -0
  13. package/.claude/commands/mastermind/createorg.md +40 -1
  14. package/.claude/commands/mastermind/createtask.md +383 -0
  15. package/.claude/commands/mastermind/debug.md +22 -0
  16. package/.claude/commands/mastermind/design.md +20 -0
  17. package/.claude/commands/mastermind/do.md +526 -0
  18. package/.claude/commands/mastermind/execute.md +20 -0
  19. package/.claude/commands/mastermind/finish.md +20 -0
  20. package/.claude/commands/mastermind/graph-status.md +7 -0
  21. package/.claude/commands/mastermind/help.md +118 -0
  22. package/.claude/commands/mastermind/ideate.md +261 -0
  23. package/.claude/commands/mastermind/improve.md +345 -0
  24. package/.claude/commands/mastermind/loops.md +7 -0
  25. package/.claude/commands/mastermind/master.md +186 -6
  26. package/.claude/commands/mastermind/memory.md +230 -0
  27. package/.claude/commands/mastermind/plan.md +26 -0
  28. package/.claude/commands/mastermind/receive-review.md +20 -0
  29. package/.claude/commands/mastermind/repeat.md +257 -0
  30. package/.claude/commands/mastermind/runorg.md +3 -0
  31. package/.claude/commands/mastermind/skill-builder.md +20 -0
  32. package/.claude/commands/mastermind/specialagents.md +125 -0
  33. package/.claude/commands/mastermind/swarm.md +161 -0
  34. package/.claude/commands/mastermind/taskdev.md +26 -0
  35. package/.claude/commands/mastermind/tdd.md +22 -0
  36. package/.claude/commands/mastermind/techport.md +4 -0
  37. package/.claude/commands/mastermind/understand.md +139 -0
  38. package/.claude/commands/mastermind/verify.md +22 -0
  39. package/.claude/commands/mastermind/worktree.md +20 -0
  40. package/.claude/commands/monomind/do.md +52 -0
  41. package/.claude/commands/monomind/improve.md +2 -0
  42. package/.claude/helpers/handlers/graph-status-handler.cjs +2 -1
  43. package/.claude/helpers/handlers/route-handler.cjs +61 -11
  44. package/.claude/helpers/hook-handler.cjs +19 -0
  45. package/.claude/helpers/skill-registry.json +122 -51
  46. package/.claude/helpers/statusline.cjs +1 -1
  47. package/.claude/skills/agent-browser-testing/SKILL.md +522 -152
  48. package/.claude/skills/github-issue-triage/SKILL.md +354 -0
  49. package/.claude/skills/github-repo-recap/SKILL.md +207 -0
  50. package/.claude/skills/mastermind/_delegation.md +83 -0
  51. package/.claude/skills/mastermind/_protocol.md +14 -0
  52. package/.claude/skills/mastermind/approve.md +15 -7
  53. package/.claude/skills/mastermind/autodev.md +534 -0
  54. package/.claude/skills/mastermind/createorg.md +21 -5
  55. package/.claude/skills/mastermind/debug.md +232 -0
  56. package/.claude/skills/mastermind/design.md +187 -0
  57. package/.claude/skills/mastermind/execute.md +104 -0
  58. package/.claude/skills/mastermind/finish.md +251 -0
  59. package/.claude/skills/mastermind/plan.md +180 -0
  60. package/.claude/skills/mastermind/receive-review.md +213 -0
  61. package/.claude/skills/mastermind/runorg.md +23 -8
  62. package/.claude/skills/mastermind/skill-builder.md +274 -0
  63. package/.claude/skills/mastermind/taskdev.md +307 -0
  64. package/.claude/skills/mastermind/tdd.md +394 -0
  65. package/.claude/skills/mastermind/verify.md +196 -0
  66. package/.claude/skills/mastermind/worktree.md +160 -132
  67. package/README.md +320 -253
  68. package/dist/src/commands/analyze.d.ts.map +1 -1
  69. package/dist/src/commands/analyze.js +9 -2
  70. package/dist/src/commands/analyze.js.map +1 -1
  71. package/dist/src/commands/benchmark.js.map +1 -1
  72. package/dist/src/commands/completions.js +1 -1
  73. package/dist/src/commands/guidance.js +7 -7
  74. package/dist/src/commands/hooks.d.ts.map +1 -1
  75. package/dist/src/commands/hooks.js +16 -3
  76. package/dist/src/commands/hooks.js.map +1 -1
  77. package/dist/src/commands/index.d.ts +3 -2
  78. package/dist/src/commands/index.d.ts.map +1 -1
  79. package/dist/src/commands/index.js +7 -0
  80. package/dist/src/commands/index.js.map +1 -1
  81. package/dist/src/commands/init.d.ts.map +1 -1
  82. package/dist/src/commands/init.js +47 -13
  83. package/dist/src/commands/init.js.map +1 -1
  84. package/dist/src/commands/neural.d.ts.map +1 -1
  85. package/dist/src/commands/neural.js +100 -14
  86. package/dist/src/commands/neural.js.map +1 -1
  87. package/dist/src/commands/platforms.d.ts +11 -0
  88. package/dist/src/commands/platforms.d.ts.map +1 -0
  89. package/dist/src/commands/platforms.js +195 -0
  90. package/dist/src/commands/platforms.js.map +1 -0
  91. package/dist/src/commands/ruvector/backup.js.map +1 -1
  92. package/dist/src/commands/ruvector/benchmark.js.map +1 -1
  93. package/dist/src/commands/ruvector/init.js.map +1 -1
  94. package/dist/src/commands/ruvector/migrate.js.map +1 -1
  95. package/dist/src/commands/ruvector/optimize.js.map +1 -1
  96. package/dist/src/commands/ruvector/status.js.map +1 -1
  97. package/dist/src/commands/update.js +6 -6
  98. package/dist/src/init/executor.d.ts.map +1 -1
  99. package/dist/src/init/executor.js +28 -0
  100. package/dist/src/init/executor.js.map +1 -1
  101. package/dist/src/init/statusline-generator.js +1 -1
  102. package/dist/src/init/types.d.ts +1 -0
  103. package/dist/src/init/types.d.ts.map +1 -1
  104. package/dist/src/mcp-server.d.ts.map +1 -1
  105. package/dist/src/mcp-server.js +92 -0
  106. package/dist/src/mcp-server.js.map +1 -1
  107. package/dist/src/mcp-tools/hive-mind-tools.d.ts.map +1 -1
  108. package/dist/src/mcp-tools/hive-mind-tools.js +52 -0
  109. package/dist/src/mcp-tools/hive-mind-tools.js.map +1 -1
  110. package/dist/src/mcp-tools/hooks-tools.d.ts.map +1 -1
  111. package/dist/src/mcp-tools/hooks-tools.js +106 -5
  112. package/dist/src/mcp-tools/hooks-tools.js.map +1 -1
  113. package/dist/src/mcp-tools/index.d.ts +0 -5
  114. package/dist/src/mcp-tools/index.d.ts.map +1 -1
  115. package/dist/src/mcp-tools/index.js +0 -5
  116. package/dist/src/mcp-tools/index.js.map +1 -1
  117. package/dist/src/mcp-tools/monograph-tools.d.ts.map +1 -1
  118. package/dist/src/mcp-tools/monograph-tools.js +507 -5587
  119. package/dist/src/mcp-tools/monograph-tools.js.map +1 -1
  120. package/dist/src/mcp-tools/neural-tools.d.ts.map +1 -1
  121. package/dist/src/mcp-tools/neural-tools.js +64 -4
  122. package/dist/src/mcp-tools/neural-tools.js.map +1 -1
  123. package/dist/src/mcp-tools/security-tools.js +4 -4
  124. package/dist/src/memory/intelligence.d.ts +2 -2
  125. package/dist/src/memory/intelligence.d.ts.map +1 -1
  126. package/dist/src/memory/intelligence.js +108 -3
  127. package/dist/src/memory/intelligence.js.map +1 -1
  128. package/dist/src/memory/memory-bridge.js +1 -1
  129. package/dist/src/memory/memory-bridge.js.map +1 -1
  130. package/dist/src/memory/sona-optimizer.d.ts +1 -10
  131. package/dist/src/memory/sona-optimizer.d.ts.map +1 -1
  132. package/dist/src/memory/sona-optimizer.js +0 -46
  133. package/dist/src/memory/sona-optimizer.js.map +1 -1
  134. package/dist/src/runtime/headless.js +3 -3
  135. package/dist/src/ruvector/diff-classifier.d.ts +0 -2
  136. package/dist/src/ruvector/diff-classifier.d.ts.map +1 -1
  137. package/dist/src/ruvector/diff-classifier.js +2 -14
  138. package/dist/src/ruvector/diff-classifier.js.map +1 -1
  139. package/dist/src/ruvector/index.d.ts +26 -9
  140. package/dist/src/ruvector/index.d.ts.map +1 -1
  141. package/dist/src/ruvector/index.js +3 -21
  142. package/dist/src/ruvector/index.js.map +1 -1
  143. package/dist/src/ruvector/ruvllm-wasm.js +2 -2
  144. package/dist/src/ruvector/ruvllm-wasm.js.map +1 -1
  145. package/dist/src/types.d.ts +0 -15
  146. package/dist/src/types.d.ts.map +1 -1
  147. package/dist/src/types.js +0 -18
  148. package/dist/src/types.js.map +1 -1
  149. package/dist/src/ui/dashboard.html +8763 -9765
  150. package/dist/src/ui/data/agent-avatars.html +763 -0
  151. package/dist/src/ui/data/agent-avatars.json +966 -0
  152. package/dist/src/ui/data/avatars/account-strategist.svg +58 -0
  153. package/dist/src/ui/data/avatars/accounts-payable.svg +54 -0
  154. package/dist/src/ui/data/avatars/adaptive-coordinator.svg +55 -0
  155. package/dist/src/ui/data/avatars/adaptive-coordinator2.svg +54 -0
  156. package/dist/src/ui/data/avatars/ai-citation.svg +57 -0
  157. package/dist/src/ui/data/avatars/ai-engineer.svg +61 -0
  158. package/dist/src/ui/data/avatars/analytics-reporter.svg +53 -0
  159. package/dist/src/ui/data/avatars/api-tester.svg +53 -0
  160. package/dist/src/ui/data/avatars/architecture.svg +54 -0
  161. package/dist/src/ui/data/avatars/automation-governance.svg +55 -0
  162. package/dist/src/ui/data/avatars/backend-dev.svg +53 -0
  163. package/dist/src/ui/data/avatars/benchmarker.svg +54 -0
  164. package/dist/src/ui/data/avatars/blockchain-auditor.svg +53 -0
  165. package/dist/src/ui/data/avatars/byzantine-coord.svg +57 -0
  166. package/dist/src/ui/data/avatars/case-analyst.svg +57 -0
  167. package/dist/src/ui/data/avatars/cicd-engineer.svg +55 -0
  168. package/dist/src/ui/data/avatars/cloud-architect.svg +54 -0
  169. package/dist/src/ui/data/avatars/code-review-swarm.svg +57 -0
  170. package/dist/src/ui/data/avatars/coder-v119.svg +57 -0
  171. package/dist/src/ui/data/avatars/coder.svg +58 -0
  172. package/dist/src/ui/data/avatars/collective-coord.svg +54 -0
  173. package/dist/src/ui/data/avatars/compliance-auditor.svg +58 -0
  174. package/dist/src/ui/data/avatars/consensus-coordinator.svg +54 -0
  175. package/dist/src/ui/data/avatars/content-creator.svg +54 -0
  176. package/dist/src/ui/data/avatars/crdt-synchronizer.svg +53 -0
  177. package/dist/src/ui/data/avatars/cro-specialist.svg +58 -0
  178. package/dist/src/ui/data/avatars/data-consolidator.svg +54 -0
  179. package/dist/src/ui/data/avatars/data-engineer.svg +53 -0
  180. package/dist/src/ui/data/avatars/database-optimizer.svg +61 -0
  181. package/dist/src/ui/data/avatars/deal-strategist.svg +54 -0
  182. package/dist/src/ui/data/avatars/defender.svg +53 -0
  183. package/dist/src/ui/data/avatars/devops-automator.svg +56 -0
  184. package/dist/src/ui/data/avatars/discovery-coach.svg +54 -0
  185. package/dist/src/ui/data/avatars/email-marketing.svg +57 -0
  186. package/dist/src/ui/data/avatars/embedded-firmware.svg +61 -0
  187. package/dist/src/ui/data/avatars/evidence-collector.svg +57 -0
  188. package/dist/src/ui/data/avatars/experiment-tracker.svg +53 -0
  189. package/dist/src/ui/data/avatars/feedback-synthesizer.svg +54 -0
  190. package/dist/src/ui/data/avatars/finance-tracker.svg +54 -0
  191. package/dist/src/ui/data/avatars/frontend-developer.svg +54 -0
  192. package/dist/src/ui/data/avatars/game-audio-engineer.svg +59 -0
  193. package/dist/src/ui/data/avatars/game-designer.svg +54 -0
  194. package/dist/src/ui/data/avatars/gossip-coordinator.svg +54 -0
  195. package/dist/src/ui/data/avatars/hierarchical-coord.svg +54 -0
  196. package/dist/src/ui/data/avatars/incident-commander.svg +57 -0
  197. package/dist/src/ui/data/avatars/infrastructure.svg +54 -0
  198. package/dist/src/ui/data/avatars/input-validator.svg +53 -0
  199. package/dist/src/ui/data/avatars/ios-developer.svg +54 -0
  200. package/dist/src/ui/data/avatars/issue-tracker.svg +53 -0
  201. package/dist/src/ui/data/avatars/judge.svg +55 -0
  202. package/dist/src/ui/data/avatars/launch-strategist.svg +54 -0
  203. package/dist/src/ui/data/avatars/legal-compliance.svg +53 -0
  204. package/dist/src/ui/data/avatars/level-designer.svg +53 -0
  205. package/dist/src/ui/data/avatars/load-balancer.svg +57 -0
  206. package/dist/src/ui/data/avatars/mcp-builder.svg +53 -0
  207. package/dist/src/ui/data/avatars/memory-coordinator.svg +55 -0
  208. package/dist/src/ui/data/avatars/mesh-coordinator.svg +55 -0
  209. package/dist/src/ui/data/avatars/ml-developer.svg +58 -0
  210. package/dist/src/ui/data/avatars/mobile-app-builder.svg +53 -0
  211. package/dist/src/ui/data/avatars/mobile-dev.svg +54 -0
  212. package/dist/src/ui/data/avatars/model-qa.svg +58 -0
  213. package/dist/src/ui/data/avatars/narrative-designer.svg +58 -0
  214. package/dist/src/ui/data/avatars/outbound-strategist.svg +55 -0
  215. package/dist/src/ui/data/avatars/path-validator.svg +54 -0
  216. package/dist/src/ui/data/avatars/payment-agent.svg +53 -0
  217. package/dist/src/ui/data/avatars/perf-analyzer.svg +58 -0
  218. package/dist/src/ui/data/avatars/pipeline-analyst.svg +54 -0
  219. package/dist/src/ui/data/avatars/planner.svg +55 -0
  220. package/dist/src/ui/data/avatars/pr-manager.svg +54 -0
  221. package/dist/src/ui/data/avatars/pricing-strategist.svg +54 -0
  222. package/dist/src/ui/data/avatars/product-manager.svg +54 -0
  223. package/dist/src/ui/data/avatars/production-validator.svg +54 -0
  224. package/dist/src/ui/data/avatars/project-shepherd.svg +54 -0
  225. package/dist/src/ui/data/avatars/proposal-strategist.svg +54 -0
  226. package/dist/src/ui/data/avatars/prosecutor.svg +57 -0
  227. package/dist/src/ui/data/avatars/pseudocode.svg +53 -0
  228. package/dist/src/ui/data/avatars/queen-coordinator.svg +55 -0
  229. package/dist/src/ui/data/avatars/quorum-manager.svg +53 -0
  230. package/dist/src/ui/data/avatars/raft-manager.svg +53 -0
  231. package/dist/src/ui/data/avatars/reality-checker.svg +58 -0
  232. package/dist/src/ui/data/avatars/recruitment.svg +58 -0
  233. package/dist/src/ui/data/avatars/refinement.svg +53 -0
  234. package/dist/src/ui/data/avatars/release-manager.svg +54 -0
  235. package/dist/src/ui/data/avatars/repo-architect.svg +54 -0
  236. package/dist/src/ui/data/avatars/researcher.svg +58 -0
  237. package/dist/src/ui/data/avatars/resource-allocator.svg +53 -0
  238. package/dist/src/ui/data/avatars/reviewer.svg +53 -0
  239. package/dist/src/ui/data/avatars/safe-executor.svg +53 -0
  240. package/dist/src/ui/data/avatars/sales-coach.svg +53 -0
  241. package/dist/src/ui/data/avatars/sales-engineer.svg +58 -0
  242. package/dist/src/ui/data/avatars/scout-explorer.svg +58 -0
  243. package/dist/src/ui/data/avatars/security-architect.svg +54 -0
  244. package/dist/src/ui/data/avatars/security-auditor.svg +55 -0
  245. package/dist/src/ui/data/avatars/senior-developer.svg +58 -0
  246. package/dist/src/ui/data/avatars/senior-pm.svg +58 -0
  247. package/dist/src/ui/data/avatars/seo-specialist.svg +57 -0
  248. package/dist/src/ui/data/avatars/social-media.svg +54 -0
  249. package/dist/src/ui/data/avatars/solidity-engineer.svg +58 -0
  250. package/dist/src/ui/data/avatars/sparc-coder.svg +58 -0
  251. package/dist/src/ui/data/avatars/sparc-coord.svg +56 -0
  252. package/dist/src/ui/data/avatars/specification.svg +57 -0
  253. package/dist/src/ui/data/avatars/sprint-prioritizer.svg +53 -0
  254. package/dist/src/ui/data/avatars/sre.svg +54 -0
  255. package/dist/src/ui/data/avatars/studio-operations.svg +53 -0
  256. package/dist/src/ui/data/avatars/studio-producer.svg +55 -0
  257. package/dist/src/ui/data/avatars/support-responder.svg +56 -0
  258. package/dist/src/ui/data/avatars/system-architect.svg +54 -0
  259. package/dist/src/ui/data/avatars/task-orchestrator.svg +56 -0
  260. package/dist/src/ui/data/avatars/technical-artist.svg +53 -0
  261. package/dist/src/ui/data/avatars/technical-writer.svg +59 -0
  262. package/dist/src/ui/data/avatars/tester.svg +53 -0
  263. package/dist/src/ui/data/avatars/threat-detection.svg +61 -0
  264. package/dist/src/ui/data/avatars/trend-researcher.svg +54 -0
  265. package/dist/src/ui/data/avatars/trial-director.svg +55 -0
  266. package/dist/src/ui/data/avatars/unity-architect.svg +54 -0
  267. package/dist/src/ui/data/avatars/visionos-engineer.svg +57 -0
  268. package/dist/src/ui/data/avatars/worker-specialist.svg +55 -0
  269. package/dist/src/ui/data/avatars/workflow-architect.svg +57 -0
  270. package/dist/src/ui/data/avatars/workflow-automation.svg +54 -0
  271. package/dist/src/ui/data/avatars/zk-steward.svg +54 -0
  272. package/dist/src/ui/data/known-projects.json +1 -1
  273. package/dist/src/ui/data/mastermind-events.jsonl +28 -0
  274. package/dist/src/ui/orgs.html +1171 -0
  275. package/dist/src/ui/server.mjs +529 -43
  276. package/dist/src/update/index.js +1 -1
  277. package/dist/src/update/validator.js +8 -8
  278. package/dist/tsconfig.tsbuildinfo +1 -1
  279. package/package.json +2 -2
  280. package/.claude/agents/academic/academic-anthropologist.md +0 -126
  281. package/.claude/agents/academic/academic-geographer.md +0 -128
  282. package/.claude/agents/academic/academic-historian.md +0 -124
  283. package/.claude/agents/academic/academic-narratologist.md +0 -119
  284. package/.claude/agents/academic/academic-psychologist.md +0 -119
  285. package/.claude/agents/analysis/analyze-code-quality.md +0 -58
  286. package/.claude/agents/analysis/code-analyzer.md +0 -189
  287. package/.claude/agents/analysis/code-review/analyze-code-quality.md +0 -58
  288. package/.claude/agents/consensus/performance-benchmarker.md +0 -831
  289. package/.claude/agents/data/ml/data-ml-model.md +0 -76
  290. package/.claude/agents/development/dev-backend-api.md +0 -178
  291. package/.claude/agents/devops/ci-cd/ops-cicd-github.md +0 -52
  292. package/.claude/agents/documentation/api-docs/docs-api-openapi.md +0 -63
  293. package/.claude/agents/game-development/blender/blender-addon-engineer.md +0 -235
  294. package/.claude/agents/game-development/game-audio-engineer.md +0 -265
  295. package/.claude/agents/game-development/game-designer.md +0 -168
  296. package/.claude/agents/game-development/godot/godot-gameplay-scripter.md +0 -335
  297. package/.claude/agents/game-development/godot/godot-multiplayer-engineer.md +0 -298
  298. package/.claude/agents/game-development/godot/godot-shader-developer.md +0 -267
  299. package/.claude/agents/game-development/level-designer.md +0 -209
  300. package/.claude/agents/game-development/narrative-designer.md +0 -244
  301. package/.claude/agents/game-development/roblox-studio/roblox-avatar-creator.md +0 -298
  302. package/.claude/agents/game-development/roblox-studio/roblox-experience-designer.md +0 -306
  303. package/.claude/agents/game-development/roblox-studio/roblox-systems-scripter.md +0 -326
  304. package/.claude/agents/game-development/technical-artist.md +0 -230
  305. package/.claude/agents/game-development/unity/unity-architect.md +0 -272
  306. package/.claude/agents/game-development/unity/unity-editor-tool-developer.md +0 -311
  307. package/.claude/agents/game-development/unity/unity-multiplayer-engineer.md +0 -322
  308. package/.claude/agents/game-development/unity/unity-shader-graph-artist.md +0 -270
  309. package/.claude/agents/game-development/unreal-engine/unreal-multiplayer-architect.md +0 -314
  310. package/.claude/agents/game-development/unreal-engine/unreal-systems-engineer.md +0 -311
  311. package/.claude/agents/game-development/unreal-engine/unreal-technical-artist.md +0 -257
  312. package/.claude/agents/game-development/unreal-engine/unreal-world-builder.md +0 -274
  313. package/.claude/agents/github/release-swarm.md +0 -597
  314. package/.claude/agents/goal/agent.md +0 -804
  315. package/.claude/agents/goal/code-goal-planner.md +0 -445
  316. package/.claude/agents/marketing/marketing-ai-citation-strategist.md +0 -171
  317. package/.claude/agents/marketing/marketing-app-store-optimizer.md +0 -322
  318. package/.claude/agents/marketing/marketing-baidu-seo-specialist.md +0 -227
  319. package/.claude/agents/marketing/marketing-bilibili-content-strategist.md +0 -200
  320. package/.claude/agents/marketing/marketing-book-co-author.md +0 -111
  321. package/.claude/agents/marketing/marketing-carousel-growth-engine.md +0 -200
  322. package/.claude/agents/marketing/marketing-china-ecommerce-operator.md +0 -284
  323. package/.claude/agents/marketing/marketing-content-creator.md +0 -67
  324. package/.claude/agents/marketing/marketing-cross-border-ecommerce.md +0 -260
  325. package/.claude/agents/marketing/marketing-douyin-strategist.md +0 -150
  326. package/.claude/agents/marketing/marketing-growth-hacker.md +0 -54
  327. package/.claude/agents/marketing/marketing-instagram-curator.md +0 -114
  328. package/.claude/agents/marketing/marketing-kuaishou-strategist.md +0 -224
  329. package/.claude/agents/marketing/marketing-linkedin-content-creator.md +0 -215
  330. package/.claude/agents/marketing/marketing-livestream-commerce-coach.md +0 -306
  331. package/.claude/agents/marketing/marketing-podcast-strategist.md +0 -278
  332. package/.claude/agents/marketing/marketing-private-domain-operator.md +0 -309
  333. package/.claude/agents/marketing/marketing-reddit-community-builder.md +0 -124
  334. package/.claude/agents/marketing/marketing-seo-specialist.md +0 -279
  335. package/.claude/agents/marketing/marketing-short-video-editing-coach.md +0 -413
  336. package/.claude/agents/marketing/marketing-social-media-strategist.md +0 -125
  337. package/.claude/agents/marketing/marketing-tiktok-strategist.md +0 -126
  338. package/.claude/agents/marketing/marketing-twitter-engager.md +0 -127
  339. package/.claude/agents/marketing/marketing-wechat-official-account.md +0 -146
  340. package/.claude/agents/marketing/marketing-weibo-strategist.md +0 -241
  341. package/.claude/agents/marketing/marketing-xiaohongshu-specialist.md +0 -139
  342. package/.claude/agents/marketing/marketing-zhihu-strategist.md +0 -163
  343. package/.claude/agents/neural/safla-neural.md +0 -74
  344. package/.claude/agents/paid-media/paid-media-auditor.md +0 -71
  345. package/.claude/agents/paid-media/paid-media-creative-strategist.md +0 -71
  346. package/.claude/agents/paid-media/paid-media-paid-social-strategist.md +0 -71
  347. package/.claude/agents/paid-media/paid-media-ppc-strategist.md +0 -71
  348. package/.claude/agents/paid-media/paid-media-programmatic-buyer.md +0 -71
  349. package/.claude/agents/paid-media/paid-media-search-query-analyst.md +0 -71
  350. package/.claude/agents/paid-media/paid-media-tracking-specialist.md +0 -71
  351. package/.claude/agents/payments/agentic-payments.md +0 -126
  352. package/.claude/agents/product/product-behavioral-nudge-engine.md +0 -81
  353. package/.claude/agents/product/product-feedback-synthesizer.md +0 -119
  354. package/.claude/agents/product/product-manager.md +0 -469
  355. package/.claude/agents/product/product-sprint-prioritizer.md +0 -154
  356. package/.claude/agents/product/product-trend-researcher.md +0 -159
  357. package/.claude/agents/project-management/project-management-experiment-tracker.md +0 -199
  358. package/.claude/agents/project-management/project-management-jira-workflow-steward.md +0 -231
  359. package/.claude/agents/project-management/project-management-project-shepherd.md +0 -195
  360. package/.claude/agents/project-management/project-management-studio-operations.md +0 -201
  361. package/.claude/agents/project-management/project-management-studio-producer.md +0 -204
  362. package/.claude/agents/project-management/project-manager-senior.md +0 -136
  363. package/.claude/agents/reasoning/agent.md +0 -804
  364. package/.claude/agents/reasoning/goal-planner.md +0 -73
  365. package/.claude/agents/sales/sales-account-strategist.md +0 -228
  366. package/.claude/agents/sales/sales-coach.md +0 -272
  367. package/.claude/agents/sales/sales-deal-strategist.md +0 -181
  368. package/.claude/agents/sales/sales-discovery-coach.md +0 -226
  369. package/.claude/agents/sales/sales-engineer.md +0 -183
  370. package/.claude/agents/sales/sales-outbound-strategist.md +0 -202
  371. package/.claude/agents/sales/sales-pipeline-analyst.md +0 -268
  372. package/.claude/agents/sales/sales-proposal-strategist.md +0 -218
  373. package/.claude/agents/sona/sona-learning-optimizer.md +0 -65
  374. package/.claude/agents/spatial-computing/macos-spatial-metal-engineer.md +0 -338
  375. package/.claude/agents/spatial-computing/terminal-integration-specialist.md +0 -71
  376. package/.claude/agents/spatial-computing/visionos-spatial-engineer.md +0 -55
  377. package/.claude/agents/specialists/memory-specialist.md +0 -298
  378. package/.claude/agents/specialists/performance-engineer.md +0 -387
  379. package/.claude/agents/specialists/queen-coordinator.md +0 -67
  380. package/.claude/agents/specialists/security-architect.md +0 -154
  381. package/.claude/agents/specialized/accounts-payable-agent.md +0 -186
  382. package/.claude/agents/specialized/corporate-training-designer.md +0 -193
  383. package/.claude/agents/specialized/data-consolidation-agent.md +0 -61
  384. package/.claude/agents/specialized/government-digital-presales-consultant.md +0 -364
  385. package/.claude/agents/specialized/healthcare-marketing-compliance.md +0 -396
  386. package/.claude/agents/specialized/recruitment-specialist.md +0 -510
  387. package/.claude/agents/specialized/report-distribution-agent.md +0 -66
  388. package/.claude/agents/specialized/sales-data-extraction-agent.md +0 -68
  389. package/.claude/agents/specialized/specialized-french-consulting-market.md +0 -193
  390. package/.claude/agents/specialized/specialized-korean-business-navigator.md +0 -217
  391. package/.claude/agents/specialized/specialized-salesforce-architect.md +0 -181
  392. package/.claude/agents/specialized/study-abroad-advisor.md +0 -283
  393. package/.claude/agents/specialized/supply-chain-strategist.md +0 -583
  394. package/.claude/agents/sublinear/consensus-coordinator.md +0 -333
  395. package/.claude/agents/sublinear/matrix-optimizer.md +0 -180
  396. package/.claude/agents/sublinear/pagerank-analyzer.md +0 -295
  397. package/.claude/agents/sublinear/performance-optimizer.md +0 -363
  398. package/.claude/agents/sublinear/trading-predictor.md +0 -242
  399. package/.claude/agents/support/support-analytics-reporter.md +0 -366
  400. package/.claude/agents/support/support-executive-summary-generator.md +0 -213
  401. package/.claude/agents/support/support-finance-tracker.md +0 -443
  402. package/.claude/agents/support/support-infrastructure-maintainer.md +0 -619
  403. package/.claude/agents/support/support-legal-compliance-checker.md +0 -589
  404. package/.claude/agents/support/support-support-responder.md +0 -586
  405. package/.claude/agents/swarm/adaptive-coordinator.md +0 -364
  406. package/.claude/agents/swarm/hierarchical-coordinator.md +0 -318
  407. package/.claude/agents/templates/github-pr-manager.md +0 -155
  408. package/.claude/agents/templates/memory-coordinator.md +0 -163
  409. package/.claude/agents/templates/migration-plan.md +0 -724
  410. package/.claude/agents/templates/orchestrator-task.md +0 -120
  411. package/.claude/agents/templates/performance-analyzer.md +0 -179
  412. package/.claude/agents/templates/sparc-coordinator.md +0 -163
  413. package/.claude/agents/testing/testing-reality-checker.md +0 -237
  414. package/.claude/commands/analysis/token-efficiency.md +0 -42
  415. package/.claude/commands/optimization/README.md +0 -73
  416. package/.claude/commands/optimization/parallel-execution.md +0 -76
  417. package/.claude/commands/swarm/swarm-analysis.md +0 -62
  418. package/.claude/commands/swarm/swarm-background.md +0 -65
  419. package/.claude/commands/swarm/swarm-modes.md +0 -67
  420. package/.claude/commands/swarm/swarm-monitor.md +0 -54
  421. package/.claude/commands/swarm/swarm-status.md +0 -44
  422. package/.claude/commands/swarm/swarm-strategies.md +0 -76
  423. package/.claude/commands/training/model-update.md +0 -78
  424. package/.claude/commands/training/pattern-learn.md +0 -69
  425. package/.claude/commands/training/specialization.md +0 -92
  426. package/.claude/commands/verify/check.md +0 -106
  427. package/.claude/commands/verify/start.md +0 -105
  428. package/.claude/helpers/README.md +0 -105
  429. package/.claude/helpers/context-persistence-hook.mjs +0 -1988
  430. package/.claude/helpers/intelligence.cjs +0 -247
  431. package/.claude/helpers/learning-service.mjs +0 -1302
  432. package/.claude/helpers/memory-palace.cjs +0 -461
  433. package/.claude/helpers/memory.cjs +0 -84
  434. package/.claude/helpers/metrics-db.mjs +0 -488
  435. package/.claude/helpers/router.cjs +0 -559
  436. package/.claude/helpers/session.cjs +0 -126
  437. package/.claude/helpers/swarm-hooks.sh +0 -761
  438. package/.claude/helpers/toggle-statusline.cjs +0 -58
  439. package/.claude/helpers/token-tracker.cjs +0 -934
  440. package/.claude/skills/agentdb-advanced/SKILL.md +0 -549
  441. package/.claude/skills/agentdb-learning/SKILL.md +0 -544
  442. package/.claude/skills/agentdb-memory-patterns/SKILL.md +0 -337
  443. package/.claude/skills/agentdb-optimization/SKILL.md +0 -508
  444. package/.claude/skills/agentdb-vector-search/SKILL.md +0 -335
  445. package/.claude/skills/agentic-integration/SKILL.md +0 -265
  446. package/.claude/skills/cli-modernization/SKILL.md +0 -950
  447. package/.claude/skills/core-implementation/SKILL.md +0 -892
  448. package/.claude/skills/ddd-architecture/SKILL.md +0 -444
  449. package/.claude/skills/github-code-review/SKILL.md +0 -1147
  450. package/.claude/skills/github-multi-repo/SKILL.md +0 -912
  451. package/.claude/skills/github-project-management/SKILL.md +0 -1245
  452. package/.claude/skills/github-release-management/SKILL.md +0 -1118
  453. package/.claude/skills/github-workflow-automation/SKILL.md +0 -1107
  454. package/.claude/skills/mcp-optimization/SKILL.md +0 -837
  455. package/.claude/skills/memory-unification/SKILL.md +0 -196
  456. package/.claude/skills/performance-optimization/SKILL.md +0 -416
  457. package/.claude/skills/reasoningbank-agentdb/SKILL.md +0 -444
  458. package/.claude/skills/reasoningbank-intelligence/SKILL.md +0 -199
  459. package/.claude/skills/security-hardening/SKILL.md +0 -101
  460. package/.claude/skills/stream-chain/SKILL.md +0 -560
  461. package/.claude/skills/swarm-coordination/SKILL.md +0 -451
  462. package/bundled-graph/dist/src/analyze.d.ts +0 -32
  463. package/bundled-graph/dist/src/analyze.d.ts.map +0 -1
  464. package/bundled-graph/dist/src/analyze.js +0 -297
  465. package/bundled-graph/dist/src/analyze.js.map +0 -1
  466. package/bundled-graph/dist/src/build.d.ts +0 -8
  467. package/bundled-graph/dist/src/build.d.ts.map +0 -1
  468. package/bundled-graph/dist/src/build.js.map +0 -1
  469. package/bundled-graph/dist/src/cache.d.ts +0 -12
  470. package/bundled-graph/dist/src/cache.d.ts.map +0 -1
  471. package/bundled-graph/dist/src/cache.js +0 -43
  472. package/bundled-graph/dist/src/cache.js.map +0 -1
  473. package/bundled-graph/dist/src/cluster.d.ts +0 -5
  474. package/bundled-graph/dist/src/cluster.d.ts.map +0 -1
  475. package/bundled-graph/dist/src/cluster.js.map +0 -1
  476. package/bundled-graph/dist/src/detect.d.ts +0 -21
  477. package/bundled-graph/dist/src/detect.d.ts.map +0 -1
  478. package/bundled-graph/dist/src/detect.js +0 -195
  479. package/bundled-graph/dist/src/detect.js.map +0 -1
  480. package/bundled-graph/dist/src/export.d.ts +0 -21
  481. package/bundled-graph/dist/src/export.d.ts.map +0 -1
  482. package/bundled-graph/dist/src/export.js +0 -68
  483. package/bundled-graph/dist/src/export.js.map +0 -1
  484. package/bundled-graph/dist/src/extract/index.d.ts +0 -20
  485. package/bundled-graph/dist/src/extract/index.d.ts.map +0 -1
  486. package/bundled-graph/dist/src/extract/index.js +0 -158
  487. package/bundled-graph/dist/src/extract/index.js.map +0 -1
  488. package/bundled-graph/dist/src/extract/languages/c.d.ts +0 -3
  489. package/bundled-graph/dist/src/extract/languages/c.d.ts.map +0 -1
  490. package/bundled-graph/dist/src/extract/languages/c.js +0 -88
  491. package/bundled-graph/dist/src/extract/languages/c.js.map +0 -1
  492. package/bundled-graph/dist/src/extract/languages/cpp.d.ts +0 -3
  493. package/bundled-graph/dist/src/extract/languages/cpp.d.ts.map +0 -1
  494. package/bundled-graph/dist/src/extract/languages/cpp.js +0 -121
  495. package/bundled-graph/dist/src/extract/languages/cpp.js.map +0 -1
  496. package/bundled-graph/dist/src/extract/languages/csharp.d.ts +0 -3
  497. package/bundled-graph/dist/src/extract/languages/csharp.d.ts.map +0 -1
  498. package/bundled-graph/dist/src/extract/languages/csharp.js +0 -121
  499. package/bundled-graph/dist/src/extract/languages/csharp.js.map +0 -1
  500. package/bundled-graph/dist/src/extract/languages/go.d.ts +0 -3
  501. package/bundled-graph/dist/src/extract/languages/go.d.ts.map +0 -1
  502. package/bundled-graph/dist/src/extract/languages/go.js +0 -181
  503. package/bundled-graph/dist/src/extract/languages/go.js.map +0 -1
  504. package/bundled-graph/dist/src/extract/languages/java.d.ts +0 -3
  505. package/bundled-graph/dist/src/extract/languages/java.d.ts.map +0 -1
  506. package/bundled-graph/dist/src/extract/languages/java.js +0 -117
  507. package/bundled-graph/dist/src/extract/languages/java.js.map +0 -1
  508. package/bundled-graph/dist/src/extract/languages/kotlin.d.ts +0 -3
  509. package/bundled-graph/dist/src/extract/languages/kotlin.d.ts.map +0 -1
  510. package/bundled-graph/dist/src/extract/languages/kotlin.js +0 -112
  511. package/bundled-graph/dist/src/extract/languages/kotlin.js.map +0 -1
  512. package/bundled-graph/dist/src/extract/languages/php.d.ts +0 -3
  513. package/bundled-graph/dist/src/extract/languages/php.d.ts.map +0 -1
  514. package/bundled-graph/dist/src/extract/languages/php.js +0 -130
  515. package/bundled-graph/dist/src/extract/languages/php.js.map +0 -1
  516. package/bundled-graph/dist/src/extract/languages/python.d.ts +0 -3
  517. package/bundled-graph/dist/src/extract/languages/python.d.ts.map +0 -1
  518. package/bundled-graph/dist/src/extract/languages/python.js +0 -230
  519. package/bundled-graph/dist/src/extract/languages/python.js.map +0 -1
  520. package/bundled-graph/dist/src/extract/languages/ruby.d.ts +0 -3
  521. package/bundled-graph/dist/src/extract/languages/ruby.d.ts.map +0 -1
  522. package/bundled-graph/dist/src/extract/languages/ruby.js +0 -120
  523. package/bundled-graph/dist/src/extract/languages/ruby.js.map +0 -1
  524. package/bundled-graph/dist/src/extract/languages/rust.d.ts +0 -3
  525. package/bundled-graph/dist/src/extract/languages/rust.d.ts.map +0 -1
  526. package/bundled-graph/dist/src/extract/languages/rust.js +0 -195
  527. package/bundled-graph/dist/src/extract/languages/rust.js.map +0 -1
  528. package/bundled-graph/dist/src/extract/languages/scala.d.ts +0 -3
  529. package/bundled-graph/dist/src/extract/languages/scala.d.ts.map +0 -1
  530. package/bundled-graph/dist/src/extract/languages/scala.js +0 -110
  531. package/bundled-graph/dist/src/extract/languages/scala.js.map +0 -1
  532. package/bundled-graph/dist/src/extract/languages/swift.d.ts +0 -3
  533. package/bundled-graph/dist/src/extract/languages/swift.d.ts.map +0 -1
  534. package/bundled-graph/dist/src/extract/languages/swift.js +0 -122
  535. package/bundled-graph/dist/src/extract/languages/swift.js.map +0 -1
  536. package/bundled-graph/dist/src/extract/languages/typescript.d.ts +0 -3
  537. package/bundled-graph/dist/src/extract/languages/typescript.d.ts.map +0 -1
  538. package/bundled-graph/dist/src/extract/languages/typescript.js +0 -295
  539. package/bundled-graph/dist/src/extract/languages/typescript.js.map +0 -1
  540. package/bundled-graph/dist/src/extract/semantic.d.ts +0 -38
  541. package/bundled-graph/dist/src/extract/semantic.d.ts.map +0 -1
  542. package/bundled-graph/dist/src/extract/semantic.js +0 -242
  543. package/bundled-graph/dist/src/extract/semantic.js.map +0 -1
  544. package/bundled-graph/dist/src/extract/tree-sitter-runner.d.ts +0 -48
  545. package/bundled-graph/dist/src/extract/tree-sitter-runner.d.ts.map +0 -1
  546. package/bundled-graph/dist/src/extract/tree-sitter-runner.js +0 -137
  547. package/bundled-graph/dist/src/extract/tree-sitter-runner.js.map +0 -1
  548. package/bundled-graph/dist/src/extract/types.d.ts +0 -7
  549. package/bundled-graph/dist/src/extract/types.d.ts.map +0 -1
  550. package/bundled-graph/dist/src/extract/types.js +0 -2
  551. package/bundled-graph/dist/src/extract/types.js.map +0 -1
  552. package/bundled-graph/dist/src/index.d.ts +0 -28
  553. package/bundled-graph/dist/src/index.d.ts.map +0 -1
  554. package/bundled-graph/dist/src/index.js +0 -26
  555. package/bundled-graph/dist/src/index.js.map +0 -1
  556. package/bundled-graph/dist/src/pipeline.d.ts +0 -27
  557. package/bundled-graph/dist/src/pipeline.d.ts.map +0 -1
  558. package/bundled-graph/dist/src/pipeline.js +0 -269
  559. package/bundled-graph/dist/src/pipeline.js.map +0 -1
  560. package/bundled-graph/dist/src/report.d.ts +0 -26
  561. package/bundled-graph/dist/src/report.d.ts.map +0 -1
  562. package/bundled-graph/dist/src/report.js +0 -214
  563. package/bundled-graph/dist/src/report.js.map +0 -1
  564. package/bundled-graph/dist/src/types.d.ts +0 -124
  565. package/bundled-graph/dist/src/types.d.ts.map +0 -1
  566. package/bundled-graph/dist/src/types.js +0 -2
  567. package/bundled-graph/dist/src/types.js.map +0 -1
  568. package/bundled-graph/dist/src/visualize.d.ts +0 -4
  569. package/bundled-graph/dist/src/visualize.d.ts.map +0 -1
  570. package/bundled-graph/dist/src/visualize.js +0 -574
  571. package/bundled-graph/dist/src/visualize.js.map +0 -1
  572. package/bundled-graph/dist/tsconfig.tsbuildinfo +0 -1
  573. package/dist/src/ui/dashboard-v2.html +0 -4576
@@ -251,6 +251,48 @@ function bindServer(server, port) {
251
251
  * @param {boolean} [options.openBrowser=true] - Whether to open the dashboard in the default browser.
252
252
  * @returns {Promise<{port: number, url: string, server: http.Server}>}
253
253
  */
254
+ /**
255
+ * Resolve a Claude project slug back to the real filesystem path.
256
+ * Slugs are created by replacing all '/' with '-', so paths containing
257
+ * hyphens (like agent-f/agf-accounting) are ambiguous. This function
258
+ * uses a greedy BFS over the real filesystem to find the correct path.
259
+ * Falls back to cwd in session files, then to direct slug replacement.
260
+ */
261
+ function resolveSlugToPath(slug, projDir) {
262
+ // 1. Try filesystem BFS (most reliable)
263
+ const parts = slug.replace(/^-/, '').split('-');
264
+ function tryPaths(idx, current) {
265
+ if (idx === parts.length) return fs.existsSync(current) ? current : null;
266
+ // Option A: next part is a new path component
267
+ const asDir = path.join(current, parts[idx]);
268
+ const r1 = tryPaths(idx + 1, asDir);
269
+ if (r1) return r1;
270
+ // Option B: combine with hyphen into current basename
271
+ if (current !== '/') {
272
+ const combined = path.join(path.dirname(current), path.basename(current) + '-' + parts[idx]);
273
+ const r2 = tryPaths(idx + 1, combined);
274
+ if (r2) return r2;
275
+ }
276
+ return null;
277
+ }
278
+ const fsResolved = parts.length ? tryPaths(1, '/' + parts[0]) : null;
279
+ if (fsResolved) return fsResolved;
280
+
281
+ // 2. Try reading cwd from a session file
282
+ try {
283
+ const sfiles = fs.readdirSync(projDir).filter(f => f.endsWith('.jsonl'));
284
+ for (const sf of sfiles) {
285
+ try {
286
+ const line = fs.readFileSync(path.join(projDir, sf), 'utf-8').split('\n').find(l => l.includes('"cwd"'));
287
+ if (line) { const m = line.match(/"cwd"\s*:\s*"([^"]+)"/); if (m?.[1]) return m[1]; }
288
+ } catch {}
289
+ }
290
+ } catch {}
291
+
292
+ // 3. Dumb fallback (known-broken for hyphenated dirs, but last resort)
293
+ return slug.replace(/-/g, '/');
294
+ }
295
+
254
296
  export async function startServer({ port = 4242, projectDir, openBrowser = true } = {}) {
255
297
  const server = http.createServer(async (req, res) => {
256
298
  const url = req.url.split('?')[0];
@@ -269,17 +311,10 @@ export async function startServer({ port = 4242, projectDir, openBrowser = true
269
311
  return;
270
312
  }
271
313
 
272
- // ----------------------------------------------------------------- GET /v2
314
+ // ----------------------------------------------------------------- GET /v2 (alias → /)
273
315
  if (req.method === 'GET' && url === '/v2') {
274
- const htmlPath = path.join(__dirname, 'dashboard-v2.html');
275
- try {
276
- const html = fs.readFileSync(htmlPath, 'utf8');
277
- res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
278
- res.end(html);
279
- } catch (err) {
280
- res.writeHead(500, { 'Content-Type': 'text/plain' });
281
- res.end(`Failed to load dashboard-v2.html: ${err.message}`);
282
- }
316
+ res.writeHead(301, { 'Location': '/' });
317
+ res.end();
283
318
  return;
284
319
  }
285
320
 
@@ -601,7 +636,7 @@ export async function startServer({ port = 4242, projectDir, openBrowser = true
601
636
  const projectCosts = [];
602
637
  for (const slug of slugDirs) {
603
638
  const projDir = path.join(projectsBase, slug);
604
- const projPath = '/' + slug.replace(/^-/, '').replace(/-/g, '/');
639
+ const projPath = resolveSlugToPath(slug, projDir);
605
640
  let sessionFiles = [];
606
641
  try { sessionFiles = fs.readdirSync(projDir).filter(f => f.endsWith('.jsonl')).map(f => path.join(projDir, f)); } catch {}
607
642
  if (!sessionFiles.length) continue;
@@ -635,9 +670,8 @@ export async function startServer({ port = 4242, projectDir, openBrowser = true
635
670
  try { slugDirs = fs.readdirSync(projectsBase, { withFileTypes: true }).filter(e => e.isDirectory()).map(e => e.name); } catch {}
636
671
  const projects = slugDirs.map(slug => {
637
672
  const projDir = path.join(projectsBase, slug);
638
- // convert slug back to path: replace leading - and then each - that was /
639
- const projPath = slug.replace(/-/g, '/');
640
- const name = slug.split('-').filter(Boolean).pop() || slug;
673
+ const projPath = resolveSlugToPath(slug, projDir);
674
+ const name = projPath.split('/').filter(Boolean).pop() || slug.split('-').filter(Boolean).pop() || slug;
641
675
  let sessionCount = 0; let lastActivity = 0; let memoryCount = 0;
642
676
  try {
643
677
  const files = fs.readdirSync(projDir).filter(f => f.endsWith('.jsonl'));
@@ -850,6 +884,79 @@ export async function startServer({ port = 4242, projectDir, openBrowser = true
850
884
  return;
851
885
  }
852
886
 
887
+ // ------------------------------------------------- GET /api/routing-feedback
888
+ if (req.method === 'GET' && url === '/api/routing-feedback') {
889
+ try {
890
+ const qs = new URL(req.url, 'http://localhost').searchParams;
891
+ const d = path.resolve(qs.get('dir') || projectDir || process.cwd());
892
+ const feedbackPath = path.join(d, '.monomind', 'routing-feedback.jsonl');
893
+ let rows = [];
894
+ if (fs.existsSync(feedbackPath)) {
895
+ const raw = fs.readFileSync(feedbackPath, 'utf-8');
896
+ rows = raw.split('\n').filter(Boolean).map(l => { try { return JSON.parse(l); } catch { return null; } }).filter(Boolean);
897
+ }
898
+ res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
899
+ res.end(JSON.stringify(rows));
900
+ } catch (err) {
901
+ res.writeHead(500, { 'Content-Type': 'application/json' });
902
+ res.end(JSON.stringify({ error: err.message }));
903
+ }
904
+ return;
905
+ }
906
+
907
+ // ---------------------------------------------------- GET /api/memory/stats
908
+ if (req.method === 'GET' && url === '/api/memory/stats') {
909
+ try {
910
+ const qs = new URL(req.url, 'http://localhost').searchParams;
911
+ const d = path.resolve(qs.get('dir') || projectDir || process.cwd());
912
+ const slug = d.replace(/\//g, '-');
913
+ const memDir = path.join(os.homedir(), '.claude', 'projects', slug, 'memory');
914
+
915
+ let total = 0, namespaces = 0, size = 0, lastWrite = null;
916
+ const byType = {};
917
+ if (fs.existsSync(memDir)) {
918
+ const files = fs.readdirSync(memDir).filter(f => f.endsWith('.md'));
919
+ total = files.length;
920
+ namespaces = files.length; // each .md file is a memory namespace
921
+ files.forEach(f => {
922
+ const fp = path.join(memDir, f);
923
+ try {
924
+ const st = fs.statSync(fp);
925
+ size += st.size;
926
+ if (!lastWrite || st.mtimeMs > lastWrite) lastWrite = st.mtimeMs;
927
+ } catch {}
928
+ const type = f.replace('.md', '');
929
+ byType[type] = (byType[type] || 0) + 1;
930
+ });
931
+ }
932
+
933
+ // Check for AgentDB / HNSW / RVF backends
934
+ const dbPath = path.join(d, '.monomind', 'agentdb.db');
935
+ const hnswPath = path.join(d, '.monomind', 'hnsw.index');
936
+ const rvfPath = path.join(d, '.monomind', 'memory.rvf');
937
+
938
+ const stats = {
939
+ total,
940
+ count: total,
941
+ namespaces,
942
+ ns: Object.keys(byType).length,
943
+ size,
944
+ byType,
945
+ hnsw: fs.existsSync(hnswPath),
946
+ agentdb: fs.existsSync(dbPath),
947
+ rvf: fs.existsSync(rvfPath),
948
+ lastWrite,
949
+ memDir,
950
+ };
951
+ res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
952
+ res.end(JSON.stringify({ stats }));
953
+ } catch (err) {
954
+ res.writeHead(500, { 'Content-Type': 'application/json' });
955
+ res.end(JSON.stringify({ error: err.message }));
956
+ }
957
+ return;
958
+ }
959
+
853
960
  // ---------------------------------------------------------- GET /api/loops
854
961
  if (req.method === 'GET' && url === '/api/loops') {
855
962
  try {
@@ -1165,7 +1272,8 @@ export async function startServer({ port = 4242, projectDir, openBrowser = true
1165
1272
 
1166
1273
  // Generate HTML on-the-fly from SQLite DB using the improved toHtml export
1167
1274
  if (fs.existsSync(dbPath)) {
1168
- const { openDb, closeDb, toHtml } = await import('@monoes/monograph');
1275
+ const { openDb, closeDb } = await import('/Users/morteza/Desktop/tools/monomind/packages/@monomind/monograph/dist/src/storage/db.js');
1276
+ const { toHtml } = await import('/Users/morteza/Desktop/tools/monomind/packages/@monomind/monograph/dist/src/export/html.js');
1169
1277
  const db = openDb(dbPath);
1170
1278
  let html;
1171
1279
  try {
@@ -1225,7 +1333,7 @@ export async function startServer({ port = 4242, projectDir, openBrowser = true
1225
1333
  let report = null, exists = false, stats = null;
1226
1334
  if (fs.existsSync(dbPath)) {
1227
1335
  exists = true;
1228
- const { openDb, closeDb } = await import('@monoes/monograph');
1336
+ const { openDb, closeDb } = await import('/Users/morteza/Desktop/tools/monomind/packages/@monomind/monograph/dist/src/storage/db.js');
1229
1337
  const db = openDb(dbPath);
1230
1338
  try {
1231
1339
  const nodeCount = db.prepare('SELECT COUNT(*) AS c FROM nodes').get().c;
@@ -1268,7 +1376,7 @@ export async function startServer({ port = 4242, projectDir, openBrowser = true
1268
1376
  const dbPath = path.join(d, '.monomind', 'monograph.db');
1269
1377
  let nodes = [], edges = [];
1270
1378
  if (fs.existsSync(dbPath)) {
1271
- const { openDb, closeDb } = await import('@monoes/monograph');
1379
+ const { openDb, closeDb } = await import('/Users/morteza/Desktop/tools/monomind/packages/@monomind/monograph/dist/src/storage/db.js');
1272
1380
  const db = openDb(dbPath);
1273
1381
  try {
1274
1382
  const nodeLimit = Math.min(parseInt(qs.get('limit') || '500', 10), 5000);
@@ -1406,7 +1514,8 @@ export async function startServer({ port = 4242, projectDir, openBrowser = true
1406
1514
 
1407
1515
  // Run doc parsing in background
1408
1516
  (async () => {
1409
- const { openDb, closeDb, isFileCached, updateFileCache, hashFileContent } = await import('@monoes/monograph');
1517
+ const { openDb, closeDb } = await import('/Users/morteza/Desktop/tools/monomind/packages/@monomind/monograph/dist/src/storage/db.js');
1518
+ const { isFileCached, updateFileCache, hashFileContent } = await import('/Users/morteza/Desktop/tools/monomind/packages/@monomind/monograph/dist/src/storage/file-cache.js');
1410
1519
  const { readFileSync, readdirSync, statSync } = fs;
1411
1520
 
1412
1521
  const docExts = new Set(['.md', '.mdx', '.txt', '.rst']);
@@ -1569,7 +1678,7 @@ export async function startServer({ port = 4242, projectDir, openBrowser = true
1569
1678
  const dbPath = path.join(d, '.monomind', 'monograph.db');
1570
1679
  if (!id) { res.writeHead(400); res.end(JSON.stringify({ error: 'Missing ?id=' })); return; }
1571
1680
  if (!fs.existsSync(dbPath)) { res.writeHead(404); res.end(JSON.stringify({ error: 'Graph not built' })); return; }
1572
- const { openDb, closeDb } = await import('@monoes/monograph');
1681
+ const { openDb, closeDb } = await import('/Users/morteza/Desktop/tools/monomind/packages/@monomind/monograph/dist/src/storage/db.js');
1573
1682
  const db = openDb(dbPath);
1574
1683
  let content = '', filePath = '', startLine = 0, endLine = 0, language = '', name = '', type = '';
1575
1684
  try {
@@ -1619,7 +1728,8 @@ export async function startServer({ port = 4242, projectDir, openBrowser = true
1619
1728
  const dbPath = path.join(d, '.monomind', 'monograph.db');
1620
1729
  if (!q) { res.writeHead(400); res.end(JSON.stringify({ error: 'Missing ?q=' })); return; }
1621
1730
  if (!fs.existsSync(dbPath)) { res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' }); res.end(JSON.stringify({ nodes: [] })); return; }
1622
- const { openDb, closeDb, ftsSearch } = await import('@monoes/monograph');
1731
+ const { openDb, closeDb } = await import('/Users/morteza/Desktop/tools/monomind/packages/@monomind/monograph/dist/src/storage/db.js');
1732
+ const { ftsSearch } = await import('/Users/morteza/Desktop/tools/monomind/packages/@monomind/monograph/dist/src/storage/fts-store.js');
1623
1733
  const db = openDb(dbPath);
1624
1734
  let nodes = [];
1625
1735
  try {
@@ -1650,7 +1760,7 @@ export async function startServer({ port = 4242, projectDir, openBrowser = true
1650
1760
  const d = path.resolve(dir || process.cwd());
1651
1761
  const dbPath = path.join(d, '.monomind', 'monograph.db');
1652
1762
  if (!id || !fs.existsSync(dbPath)) { res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' }); res.end(JSON.stringify({ related: [] })); return; }
1653
- const { openDb, closeDb } = await import('@monoes/monograph');
1763
+ const { openDb, closeDb } = await import('/Users/morteza/Desktop/tools/monomind/packages/@monomind/monograph/dist/src/storage/db.js');
1654
1764
  const db = openDb(dbPath);
1655
1765
  const related = [];
1656
1766
  try {
@@ -1691,7 +1801,7 @@ export async function startServer({ port = 4242, projectDir, openBrowser = true
1691
1801
  const d = path.resolve(dir || process.cwd());
1692
1802
  const dbPath = path.join(d, '.monomind', 'monograph.db');
1693
1803
  if (!id || !fs.existsSync(dbPath)) { res.writeHead(404); res.end(JSON.stringify({ error: 'Not found' })); return; }
1694
- const { openDb, closeDb } = await import('@monoes/monograph');
1804
+ const { openDb, closeDb } = await import('/Users/morteza/Desktop/tools/monomind/packages/@monomind/monograph/dist/src/storage/db.js');
1695
1805
  const db = openDb(dbPath);
1696
1806
  let result = { node: null, content: '', neighbors: [], markdown: '' };
1697
1807
  try {
@@ -1751,7 +1861,8 @@ export async function startServer({ port = 4242, projectDir, openBrowser = true
1751
1861
  const dbPath = path.join(d, '.monomind', 'monograph.db');
1752
1862
  if (!q) { res.writeHead(400); res.end(JSON.stringify({ error: 'Missing ?q= parameter' })); return; }
1753
1863
  if (!fs.existsSync(dbPath)) { res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' }); res.end(JSON.stringify({ success: false, result: 'Graph not built yet. Run: monomind monograph build' })); return; }
1754
- const { openDb, closeDb, ftsSearch } = await import('@monoes/monograph');
1864
+ const { openDb, closeDb } = await import('/Users/morteza/Desktop/tools/monomind/packages/@monomind/monograph/dist/src/storage/db.js');
1865
+ const { ftsSearch } = await import('/Users/morteza/Desktop/tools/monomind/packages/@monomind/monograph/dist/src/storage/fts-store.js');
1755
1866
  const db = openDb(dbPath);
1756
1867
  let result = '';
1757
1868
  try {
@@ -1787,7 +1898,8 @@ export async function startServer({ port = 4242, projectDir, openBrowser = true
1787
1898
  const dbPath = path.join(d, '.monomind', 'monograph.db');
1788
1899
  if (!nodeQ) { res.writeHead(400); res.end(JSON.stringify({ error: 'Missing ?node= parameter' })); return; }
1789
1900
  if (!fs.existsSync(dbPath)) { res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' }); res.end(JSON.stringify({ success: false, explanation: 'Graph not built yet. Run: monomind monograph build' })); return; }
1790
- const { openDb, closeDb, ftsSearch } = await import('@monoes/monograph');
1901
+ const { openDb, closeDb } = await import('/Users/morteza/Desktop/tools/monomind/packages/@monomind/monograph/dist/src/storage/db.js');
1902
+ const { ftsSearch } = await import('/Users/morteza/Desktop/tools/monomind/packages/@monomind/monograph/dist/src/storage/fts-store.js');
1791
1903
  const db = openDb(dbPath);
1792
1904
  let explanation = '';
1793
1905
  try {
@@ -1829,7 +1941,33 @@ export async function startServer({ port = 4242, projectDir, openBrowser = true
1829
1941
  const dbPath = path.join(d, '.monomind', 'monograph.db');
1830
1942
  if (!from || !to) { res.writeHead(400); res.end(JSON.stringify({ error: 'Missing ?from= and ?to= parameters' })); return; }
1831
1943
  if (!fs.existsSync(dbPath)) { res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' }); res.end(JSON.stringify({ success: false, path: 'Graph not built yet.' })); return; }
1832
- const { openDb, closeDb, getShortestPath, ftsSearch } = await import('@monoes/monograph');
1944
+ // Import only graphology-free storage modules to avoid broken graphology dep
1945
+ const { openDb, closeDb } = await import('/Users/morteza/Desktop/tools/monomind/packages/@monomind/monograph/dist/src/storage/db.js');
1946
+ const { ftsSearch } = await import('/Users/morteza/Desktop/tools/monomind/packages/@monomind/monograph/dist/src/storage/fts-store.js');
1947
+ // SQL-based BFS for shortest path (avoids graphology)
1948
+ const getShortestPath = (db, fromId, toId, maxDepth = 6) => {
1949
+ if (fromId === toId) return [fromId];
1950
+ const visited = new Set([fromId]);
1951
+ let frontier = [[fromId]];
1952
+ for (let depth = 0; depth < maxDepth; depth++) {
1953
+ const next = [];
1954
+ for (const chain of frontier) {
1955
+ const cur = chain[chain.length - 1];
1956
+ const neighbors = db.prepare('SELECT target_id AS id FROM edges WHERE source_id=? UNION SELECT source_id AS id FROM edges WHERE target_id=?').all(cur, cur);
1957
+ for (const { id } of neighbors) {
1958
+ if (!visited.has(id)) {
1959
+ const newChain = [...chain, id];
1960
+ if (id === toId) return newChain;
1961
+ visited.add(id);
1962
+ next.push(newChain);
1963
+ }
1964
+ }
1965
+ }
1966
+ if (!next.length) break;
1967
+ frontier = next;
1968
+ }
1969
+ return null;
1970
+ };
1833
1971
  const db = openDb(dbPath);
1834
1972
  let pathResult = '';
1835
1973
  try {
@@ -1924,13 +2062,41 @@ export async function startServer({ port = 4242, projectDir, openBrowser = true
1924
2062
  const ok = (data) => { json(res); res.end(JSON.stringify({ content: [{ type: 'text', text: typeof data === 'string' ? data : JSON.stringify(data, null, 2) }] })); };
1925
2063
  const err = (msg) => { json(res); res.end(JSON.stringify({ error: msg })); };
1926
2064
  try {
1927
- const { tool, input = {} } = JSON.parse(body);
2065
+ const { tool, input = {}, args = {} } = JSON.parse(body);
1928
2066
  const qs2 = new URL(req.url, 'http://localhost').searchParams;
1929
- const dir2 = qs2.get('dir') || projectDir;
2067
+ // dir can come from: URL query string, body.args.dir, body.input.dir, or server default
2068
+ const dir2 = qs2.get('dir') || args.dir || input.dir || projectDir;
1930
2069
  const d2 = path.resolve(dir2 || process.cwd());
1931
2070
  const dbPath2 = path.join(d2, '.monomind', 'monograph.db');
1932
2071
  if (!fs.existsSync(dbPath2)) { err('monograph.db not found — run monograph build first'); return; }
1933
- const { openDb, closeDb, ftsSearch, getShortestPath, countNodes, countEdges } = await import('@monoes/monograph');
2072
+ // Import only graphology-free storage modules to avoid broken graphology dep
2073
+ const { openDb, closeDb } = await import('/Users/morteza/Desktop/tools/monomind/packages/@monomind/monograph/dist/src/storage/db.js');
2074
+ const { ftsSearch } = await import('/Users/morteza/Desktop/tools/monomind/packages/@monomind/monograph/dist/src/storage/fts-store.js');
2075
+ const { countNodes } = await import('/Users/morteza/Desktop/tools/monomind/packages/@monomind/monograph/dist/src/storage/node-store.js');
2076
+ const { countEdges } = await import('/Users/morteza/Desktop/tools/monomind/packages/@monomind/monograph/dist/src/storage/edge-store.js');
2077
+ const getShortestPath = (db, fromId, toId, maxDepth = 6) => {
2078
+ if (fromId === toId) return [fromId];
2079
+ const visited = new Set([fromId]);
2080
+ let frontier = [[fromId]];
2081
+ for (let depth = 0; depth < maxDepth; depth++) {
2082
+ const next = [];
2083
+ for (const chain of frontier) {
2084
+ const cur = chain[chain.length - 1];
2085
+ const neighbors = db.prepare('SELECT target_id AS id FROM edges WHERE source_id=? UNION SELECT source_id AS id FROM edges WHERE target_id=?').all(cur, cur);
2086
+ for (const { id } of neighbors) {
2087
+ if (!visited.has(id)) {
2088
+ const newChain = [...chain, id];
2089
+ if (id === toId) return newChain;
2090
+ visited.add(id);
2091
+ next.push(newChain);
2092
+ }
2093
+ }
2094
+ }
2095
+ if (!next.length) break;
2096
+ frontier = next;
2097
+ }
2098
+ return null;
2099
+ };
1934
2100
  const db2 = openDb(dbPath2);
1935
2101
  try {
1936
2102
  if (tool === 'monograph_stats') {
@@ -2181,6 +2347,145 @@ export async function startServer({ port = 4242, projectDir, openBrowser = true
2181
2347
  else { ok(`Author Analytics (by commit count):\n${'─'.repeat(50)}\n${log.trim().split('\n').map(l => { const m = l.trim().match(/^(\d+)\s+(.+)$/); return m ? ` ${m[2].padEnd(45)} ${m[1]} commits` : l; }).join('\n')}`); }
2182
2348
  } catch { ok('Author analytics requires git. Ensure this directory is a git repository.'); }
2183
2349
 
2350
+ } else if (tool === 'monograph_reachability') {
2351
+ // Files with no inbound edges (nothing imports them)
2352
+ const allNodes = db2.prepare(`SELECT id, name, file_path FROM nodes WHERE label IN ('File','Module') LIMIT 5000`).all();
2353
+ const inboundSet = new Set(db2.prepare(`SELECT DISTINCT target_id FROM edges`).all().map(r => r.target_id));
2354
+ const unreachable = allNodes.filter(n => !inboundSet.has(n.id)).slice(0, 40);
2355
+ const outdeg = db2.prepare(`SELECT source_id, COUNT(*) as c FROM edges GROUP BY source_id`);
2356
+ const degMap = {};
2357
+ for (const r of outdeg.all()) degMap[r.source_id] = r.c;
2358
+ if (!unreachable.length) { ok('All files have at least one inbound reference.'); }
2359
+ else ok(`Unreachable Files (${unreachable.length} of ${allNodes.length} total):\n${'─'.repeat(50)}\n${unreachable.slice(0,30).map(n => ` ${n.name || n.id.split('/').pop()} (imports ${degMap[n.id]||0} others)\n ${n.file_path||''}`).join('\n\n')}`);
2360
+
2361
+ } else if (tool === 'monograph_vital_signs_snapshot') {
2362
+ // Same as health_score — kept for backward compatibility
2363
+ const n = db2.prepare('SELECT COUNT(*) as c FROM nodes').get().c;
2364
+ const e = db2.prepare('SELECT COUNT(*) as c FROM edges').get().c;
2365
+ const dead = db2.prepare(`SELECT COUNT(*) as c FROM nodes n WHERE NOT EXISTS (SELECT 1 FROM edges WHERE source_id=n.id OR target_id=n.id)`).get().c;
2366
+ const hubs = db2.prepare(`SELECT COUNT(*) as c FROM (SELECT source_id FROM edges GROUP BY source_id HAVING COUNT(*)>20)`).get().c;
2367
+ const density = n > 1 ? (e / (n * (n-1))).toFixed(6) : '0';
2368
+ const score = Math.max(0, Math.min(100, Math.round(100 - (dead/Math.max(n,1)*30) - (hubs/Math.max(n,1)*500))));
2369
+ ok(`Vital Signs — ${new Date().toISOString()}\n${'─'.repeat(50)}\n Health Score: ${score}/100 ${score>=80?'✓ OK':score>=60?'⚠ Warning':'✗ Critical'}\n Nodes: ${n}\n Edges: ${e}\n Density: ${density}\n Dead symbols: ${dead} (${(dead/Math.max(n,1)*100).toFixed(1)}%)\n Hub nodes: ${hubs} nodes with >20 edges`);
2370
+
2371
+ } else if (tool === 'monograph_circular_deps') {
2372
+ // Find import cycles using iterative DFS
2373
+ const limit = Math.min(parseInt(input.limit||'10'), 20);
2374
+ const importEdges = db2.prepare(`SELECT source_id, target_id FROM edges WHERE relation IN ('IMPORTS','REQUIRES','USES','DEPENDS_ON') LIMIT 50000`).all();
2375
+ const adj = {};
2376
+ for (const e of importEdges) { (adj[e.source_id] = adj[e.source_id]||[]).push(e.target_id); }
2377
+ const cycles = [];
2378
+ const visited = new Set(), inStack = new Set();
2379
+ function dfs(node, path) {
2380
+ if (cycles.length >= limit) return;
2381
+ if (inStack.has(node)) {
2382
+ const cycleStart = path.indexOf(node);
2383
+ if (cycleStart >= 0) cycles.push(path.slice(cycleStart).concat(node));
2384
+ return;
2385
+ }
2386
+ if (visited.has(node)) return;
2387
+ visited.add(node); inStack.add(node); path.push(node);
2388
+ for (const nb of (adj[node]||[])) dfs(nb, path);
2389
+ path.pop(); inStack.delete(node);
2390
+ }
2391
+ for (const node of Object.keys(adj).slice(0, 2000)) dfs(node, []);
2392
+ const getName = id => id.split('/').slice(-2).join('/');
2393
+ if (!cycles.length) ok(`No circular dependencies found among ${Object.keys(adj).length} nodes with import edges.`);
2394
+ else ok(`Circular Dependencies (${cycles.length} found):\n${'─'.repeat(50)}\n${cycles.slice(0,limit).map((c,i) => ` ${i+1}. ${c.map(getName).join(' → ')}`).join('\n')}`);
2395
+
2396
+ } else if (tool === 'monograph_largest_files') {
2397
+ const limit2 = Math.min(parseInt(input.limit||'25'), 50);
2398
+ const rows = db2.prepare(`SELECT file_path, MAX(end_line) as lines, COUNT(*) as symbols FROM nodes WHERE file_path IS NOT NULL AND end_line IS NOT NULL AND end_line > 0 GROUP BY file_path ORDER BY lines DESC LIMIT ${limit2}`).all();
2399
+ if (!rows.length) ok('No line-count data available. Ensure the index was built with source parsing enabled.');
2400
+ else ok(`Largest Files by Line Count:\n${'─'.repeat(50)}\n${rows.map((r,i) => ` ${String(i+1).padStart(2)}. ${r.lines.toString().padStart(5)} lines ${r.symbols} symbols ${r.file_path.split('/').slice(-2).join('/')}`).join('\n')}`);
2401
+
2402
+ } else if (tool === 'monograph_coupling_balance') {
2403
+ // Fan-out (what this file uses) vs Fan-in (what uses this file)
2404
+ const limit3 = Math.min(parseInt(input.limit||'20'), 40);
2405
+ const fanOut = db2.prepare(`SELECT source_id, COUNT(*) as c FROM edges GROUP BY source_id`).all();
2406
+ const fanIn = db2.prepare(`SELECT target_id, COUNT(*) as c FROM edges GROUP BY target_id`).all();
2407
+ const outMap = {}, inMap = {};
2408
+ for (const r of fanOut) outMap[r.source_id] = r.c;
2409
+ for (const r of fanIn) inMap[r.target_id] = r.c;
2410
+ const allIds = new Set([...Object.keys(outMap), ...Object.keys(inMap)]);
2411
+ const nodes3 = db2.prepare(`SELECT id, name, file_path FROM nodes WHERE label='File' LIMIT 10000`).all();
2412
+ const fileSet = new Set(nodes3.map(n => n.id));
2413
+ const entries = [...allIds].filter(id => fileSet.has(id)).map(id => {
2414
+ const o = outMap[id]||0, i = inMap[id]||0;
2415
+ const n = nodes3.find(x=>x.id===id);
2416
+ return { name: n?.name || id.split('/').pop(), path: n?.file_path||'', out: o, inn: i, ratio: i > 0 ? (o/i).toFixed(1) : '∞' };
2417
+ }).filter(x => x.out > 0 || x.inn > 0).sort((a,b) => (b.out+b.inn) - (a.out+a.inn)).slice(0, limit3);
2418
+ ok(`Coupling Balance (Fan-out vs Fan-in, top ${limit3} by activity):\n${'─'.repeat(60)}\n ${'File'.padEnd(35)} Out In Ratio\n${'─'.repeat(60)}\n${entries.map(e => ` ${e.name.slice(0,35).padEnd(35)} ${String(e.out).padStart(3)} ${String(e.inn).padStart(2)} ${e.ratio}`).join('\n')}`);
2419
+
2420
+ } else if (tool === 'monograph_dead_exports') {
2421
+ // Exported symbols with zero inbound edges
2422
+ const exported = db2.prepare(`SELECT id, name, label, file_path FROM nodes WHERE is_exported=1 LIMIT 10000`).all();
2423
+ const inbound = new Set(db2.prepare(`SELECT DISTINCT target_id FROM edges`).all().map(r => r.target_id));
2424
+ const dead2 = exported.filter(n => !inbound.has(n.id));
2425
+ if (!dead2.length) ok('No dead exports found — all exported symbols have at least one inbound reference.');
2426
+ else ok(`Dead Exports — exported but never imported (${dead2.length} of ${exported.length} exported symbols):\n${'─'.repeat(50)}\n${dead2.slice(0,30).map(n => ` ${n.label.padEnd(12)} ${n.name} → ${(n.file_path||'').split('/').slice(-2).join('/')}`).join('\n')}`);
2427
+
2428
+ } else if (tool === 'monograph_language_breakdown') {
2429
+ const rows2 = db2.prepare(`SELECT language, COUNT(*) as c FROM nodes WHERE language IS NOT NULL AND language != '' GROUP BY language ORDER BY c DESC`).all();
2430
+ if (!rows2.length) ok('No language metadata available in this graph index.');
2431
+ else {
2432
+ const total2 = rows2.reduce((s,r) => s+r.c, 0);
2433
+ const maxC = rows2[0].c;
2434
+ ok(`Language Breakdown:\n${'─'.repeat(50)}\n${rows2.map(r => { const bar = '█'.repeat(Math.round(r.c/maxC*20)); const pct = (r.c/total2*100).toFixed(1); return ` ${r.language.padEnd(15)} ${bar.padEnd(20)} ${String(r.c).padStart(6)} (${pct}%)`; }).join('\n')}\n\n Total nodes: ${total2}`);
2435
+ }
2436
+
2437
+ } else if (tool === 'monograph_instability') {
2438
+ // Robert Martin's Instability = Ce / (Ca + Ce)
2439
+ // Ca = afferent coupling (in-degree), Ce = efferent coupling (out-degree)
2440
+ const limit4 = Math.min(parseInt(input.limit||'25'), 50);
2441
+ const outRows = db2.prepare(`SELECT source_id, COUNT(*) as c FROM edges GROUP BY source_id`).all();
2442
+ const inRows = db2.prepare(`SELECT target_id, COUNT(*) as c FROM edges GROUP BY target_id`).all();
2443
+ const Ce = {}, Ca = {};
2444
+ for (const r of outRows) Ce[r.source_id] = r.c;
2445
+ for (const r of inRows) Ca[r.target_id] = r.c;
2446
+ const fileNodes = db2.prepare(`SELECT id, name, file_path FROM nodes WHERE label='File' LIMIT 10000`).all();
2447
+ const entries4 = fileNodes.map(n => {
2448
+ const ca = Ca[n.id]||0, ce = Ce[n.id]||0;
2449
+ const total = ca + ce;
2450
+ const inst = total > 0 ? ce / total : 0;
2451
+ return { name: n.name||n.id.split('/').pop(), ca, ce, inst };
2452
+ }).filter(x => x.ca+x.ce > 0).sort((a,b) => b.inst - a.inst);
2453
+ const risky = entries4.filter(x => x.inst > 0.7 && x.ca > 3);
2454
+ const stable = entries4.filter(x => x.inst < 0.2 && x.ce > 3);
2455
+ ok(`Instability Index (Ce÷(Ca+Ce), 0=stable 1=unstable):\n${'─'.repeat(60)}\n\n ⚠ High instability + high dependents (blast radius risk):\n${risky.slice(0,10).map(x => ` ${x.name.slice(0,40).padEnd(40)} I=${x.inst.toFixed(2)} Ca=${x.ca} Ce=${x.ce}`).join('\n')||' none'}\n\n ✓ Stable (low instability, many dependents on them):\n${stable.slice(0,8).map(x => ` ${x.name.slice(0,40).padEnd(40)} I=${x.inst.toFixed(2)} Ca=${x.ca} Ce=${x.ce}`).join('\n')||' none'}\n\n Total files analyzed: ${entries4.length}`);
2456
+
2457
+ } else if (tool === 'monograph_churn_hotspots') {
2458
+ // Combines git churn frequency with structural complexity (out-degree)
2459
+ const limit5 = Math.min(parseInt(input.limit||'15'), 30);
2460
+ const { execSync: execS2 } = await import('child_process');
2461
+ let churnMap = {};
2462
+ try {
2463
+ const since = input.since || '6 months ago';
2464
+ const log2 = execS2(`git log --since="${since}" --name-only --format="" -- . 2>/dev/null | grep -v '^$' | sort | uniq -c | sort -rn | head -200`, { cwd: d2, encoding: 'utf-8', timeout: 8000 });
2465
+ for (const line of log2.trim().split('\n')) {
2466
+ const m = line.trim().match(/^(\d+)\s+(.+)$/);
2467
+ if (m) churnMap[m[2]] = parseInt(m[1]);
2468
+ }
2469
+ } catch {}
2470
+ if (!Object.keys(churnMap).length) { ok('No git history found — churn analysis requires a git repository.'); }
2471
+ else {
2472
+ const outDeg = db2.prepare(`SELECT source_id, COUNT(*) as c FROM edges GROUP BY source_id`).all();
2473
+ const degMap2 = {};
2474
+ for (const r of outDeg) degMap2[r.source_id] = r.c;
2475
+ const fileNodes2 = db2.prepare(`SELECT id, name, file_path FROM nodes WHERE label='File' LIMIT 10000`).all();
2476
+ const maxChurn = Math.max(...Object.values(churnMap), 1);
2477
+ const maxDeg2 = Math.max(...Object.values(degMap2), 1);
2478
+ const scored = fileNodes2.map(n => {
2479
+ const fp = n.file_path || '';
2480
+ const churn = churnMap[fp] || Object.entries(churnMap).find(([k]) => fp.endsWith(k))?.[1] || 0;
2481
+ const deg = degMap2[n.id] || 0;
2482
+ const score2 = (churn/maxChurn * 0.6) + (deg/maxDeg2 * 0.4);
2483
+ return { name: n.name||fp.split('/').pop(), fp, churn, deg, score: score2 };
2484
+ }).filter(x => x.churn > 0 || x.deg > 5).sort((a,b) => b.score - a.score).slice(0, limit5);
2485
+ if (!scored.length) ok('No files matched both churn and complexity criteria.');
2486
+ else ok(`Churn × Complexity Hotspots (60% churn weight + 40% coupling weight):\n${'─'.repeat(60)}\n ${'File'.padEnd(38)} Churn Deps Score\n${'─'.repeat(60)}\n${scored.map(x => ` ${x.name.slice(0,38).padEnd(38)} ${String(x.churn).padStart(5)} ${String(x.deg).padStart(4)} ${(x.score*100).toFixed(0)}%`).join('\n')}\n\n Analyzed: ${scored.length} hotspot candidates from last ${input.since||'6 months'}`);
2487
+ }
2488
+
2184
2489
  } else {
2185
2490
  ok(`Tool "${tool}" not implemented in control panel`);
2186
2491
  }
@@ -2590,14 +2895,15 @@ export async function startServer({ port = 4242, projectDir, openBrowser = true
2590
2895
  // GET /api/orgs — list all saved org configs
2591
2896
  if (req.method === 'GET' && url === '/api/orgs') {
2592
2897
  try {
2593
- const orgsDir = path.join(projectDir || process.cwd(), '.monomind', 'orgs');
2898
+ const _orgsQs = new URL(req.url, 'http://localhost').searchParams;
2899
+ const orgsDir = path.join(path.resolve(_orgsQs.get('dir') || projectDir || process.cwd()), '.monomind', 'orgs');
2594
2900
  let orgs = [];
2595
2901
  if (fs.existsSync(orgsDir)) {
2596
2902
  const files = fs.readdirSync(orgsDir).filter(f => f.endsWith('.json'));
2597
2903
  // Read events file once, outside the per-org loop
2598
2904
  let recentLines = [];
2599
2905
  try {
2600
- const evFile = path.join(projectDir || process.cwd(), 'data', 'mastermind-events.jsonl');
2906
+ const evFile = path.join(path.resolve(_orgsQs.get('dir') || projectDir || process.cwd()), 'data', 'mastermind-events.jsonl');
2601
2907
  if (fs.existsSync(evFile)) {
2602
2908
  // Read only the last 64 KB to bound cost on large files
2603
2909
  const stat = fs.statSync(evFile);
@@ -2651,7 +2957,8 @@ export async function startServer({ port = 4242, projectDir, openBrowser = true
2651
2957
  try {
2652
2958
  const orgName = decodeURIComponent(url.slice('/api/org/'.length));
2653
2959
  if (orgName.length > 64 || !/^[a-z0-9][a-z0-9_-]*$/i.test(orgName)) { res.writeHead(400); res.end('Invalid org name'); return; }
2654
- const d = projectDir || process.cwd();
2960
+ const _orgQs = new URL(req.url, 'http://localhost').searchParams;
2961
+ const d = path.resolve(_orgQs.get('dir') || projectDir || process.cwd());
2655
2962
  const orgsDir = path.join(d, '.monomind', 'orgs');
2656
2963
 
2657
2964
  const readJsonSafe = (f) => { try { return JSON.parse(fs.readFileSync(f, 'utf8')); } catch(_) { return null; } };
@@ -2684,14 +2991,14 @@ export async function startServer({ port = 4242, projectDir, openBrowser = true
2684
2991
  const parts = url.split('/');
2685
2992
  const orgName = decodeURIComponent(parts[3]);
2686
2993
  if (orgName.length > 64 || !/^[a-z0-9][a-z0-9_-]*$/i.test(orgName)) { res.writeHead(400); res.end('[]'); return; }
2687
- const d = projectDir || process.cwd();
2994
+ const _actQs = new URL(req.url, 'http://localhost').searchParams;
2995
+ const d = path.resolve(_actQs.get('dir') || projectDir || process.cwd());
2688
2996
  const eventsFile = path.join(d, 'data', 'mastermind-events.jsonl');
2689
2997
  let events = [];
2690
2998
  if (fs.existsSync(eventsFile)) {
2691
2999
  const lines = fs.readFileSync(eventsFile, 'utf8').split('\n').filter(Boolean);
2692
- events = lines.slice(-200).map(l => { try { return JSON.parse(l); } catch { return null; } }).filter(Boolean)
2693
- .filter(e => e.org === orgName || e.session && typeof e.org === 'undefined')
2694
- .filter(e => e.org === orgName)
3000
+ events = lines.slice(-500).map(l => { try { return JSON.parse(l); } catch { return null; } }).filter(Boolean)
3001
+ .filter(e => e.org === orgName || !e.org)
2695
3002
  .reverse().slice(0, 100);
2696
3003
  }
2697
3004
  res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
@@ -2922,7 +3229,8 @@ export async function startServer({ port = 4242, projectDir, openBrowser = true
2922
3229
  try {
2923
3230
  const orgName = decodeURIComponent(url.split('/')[3]);
2924
3231
  if (orgName.length > 64 || !/^[a-z0-9][a-z0-9_-]*$/i.test(orgName)) { res.writeHead(400); res.end('Invalid org name'); return; }
2925
- const base = path.join(projectDir || process.cwd(), '.monomind', 'orgs');
3232
+ const _healthQs = new URL(req.url, 'http://localhost').searchParams;
3233
+ const base = path.join(path.resolve(_healthQs.get('dir') || projectDir || process.cwd()), '.monomind', 'orgs');
2926
3234
 
2927
3235
  let agentsRunning = 0, agentsIdle = 0, openIssues = 0, inProgressIssues = 0;
2928
3236
  let budgetUsedTokens = 0, budgetMaxTokens = 0;
@@ -2935,7 +3243,7 @@ export async function startServer({ port = 4242, projectDir, openBrowser = true
2935
3243
  Object.values(agents).forEach(a => {
2936
3244
  if (a.status === 'running') agentsRunning++;
2937
3245
  else agentsIdle++;
2938
- budgetUsedTokens += (a.tokens_used || 0);
3246
+ budgetUsedTokens += (a.tokens_used || ((a.tokens_in || 0) + (a.tokens_out || 0)));
2939
3247
  });
2940
3248
  } catch(_) {}
2941
3249
 
@@ -2974,13 +3282,16 @@ export async function startServer({ port = 4242, projectDir, openBrowser = true
2974
3282
  res.end(JSON.stringify({
2975
3283
  agents_running: agentsRunning,
2976
3284
  agents_idle: agentsIdle,
3285
+ agents_active: agentsRunning,
2977
3286
  open_issues: openIssues,
2978
3287
  in_progress_issues: inProgressIssues,
3288
+ tasks_pending: openIssues + inProgressIssues,
2979
3289
  budget_used_tokens: budgetUsedTokens,
2980
3290
  budget_max_tokens: budgetMaxTokens,
2981
3291
  budget_used_pct: budgetUsedPct,
2982
3292
  run_success_rate_7d: successRate,
2983
3293
  total_runs_7d: totalRuns,
3294
+ errors: [],
2984
3295
  }));
2985
3296
  } catch(_) { res.writeHead(500); res.end('{}'); }
2986
3297
  return;
@@ -3171,18 +3482,25 @@ export async function startServer({ port = 4242, projectDir, openBrowser = true
3171
3482
  const readJsonSafe = (f) => { try { return JSON.parse(fs.readFileSync(f, 'utf8')); } catch(_) { return null; } };
3172
3483
  const data = readJsonSafe(path.join(base, `${orgName}-approvals.json`)) || { approvals: [] };
3173
3484
  const approvals = (data.approvals || [])
3174
- .sort((a, b) => new Date(b.createdAt || 0) - new Date(a.createdAt || 0))
3485
+ .sort((a, b) => new Date(b.createdAt || b.created_at || b.requested_at || 0) - new Date(a.createdAt || a.created_at || a.requested_at || 0))
3175
3486
  .map(a => ({
3176
3487
  id: a.id,
3177
3488
  title: a.title || a.action || null,
3489
+ action: a.action || a.title || null,
3490
+ description: a.description || a.action || a.title || null,
3178
3491
  status: a.status || 'pending',
3179
3492
  agentId: a.agentId || a.agent_id || null,
3180
3493
  agentTitle: a.agentTitle || null,
3494
+ requester: a.requester || a.agentTitle || a.agent_id || a.agentId || null,
3495
+ agent: a.agent || a.agent_id || a.agentId || null,
3181
3496
  payload: a.payload || null,
3182
- createdAt: a.createdAt || null,
3497
+ risk_level: a.risk_level || 'medium',
3498
+ created_at: a.created_at || a.createdAt || a.requested_at || null,
3499
+ createdAt: a.createdAt || a.created_at || a.requested_at || null,
3183
3500
  updatedAt: a.updatedAt || null,
3184
3501
  resolvedAt: a.resolvedAt || null,
3185
3502
  resolvedBy: a.resolvedBy || null,
3503
+ ts: a.ts || null,
3186
3504
  }));
3187
3505
  const pending = approvals.filter(a => a.status === 'pending' || a.status === 'revision_requested').length;
3188
3506
  res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
@@ -3191,6 +3509,49 @@ export async function startServer({ port = 4242, projectDir, openBrowser = true
3191
3509
  return;
3192
3510
  }
3193
3511
 
3512
+ // POST /api/org/:name/approvals/:id — approve or reject a pending approval request
3513
+ // Body: { action: "approve" | "reject" | "revision_requested" }
3514
+ if (req.method === 'POST' && url.match(/^\/api\/org\/[a-z0-9][a-z0-9_-]{0,63}\/approvals\/[^/]+$/i)) {
3515
+ let body = '';
3516
+ for await (const chunk of req) body += chunk;
3517
+ try {
3518
+ const parts = url.split('/');
3519
+ const orgName = decodeURIComponent(parts[3]);
3520
+ const approvalId = decodeURIComponent(parts[5]);
3521
+ if (orgName.length > 64 || !/^[a-z0-9][a-z0-9_-]*$/i.test(orgName)) { res.writeHead(400); res.end('Invalid org name'); return; }
3522
+ if (!approvalId) { res.writeHead(400); res.end('{"error":"approval id required"}'); return; }
3523
+ const parsed = JSON.parse(body);
3524
+ const action = parsed.action;
3525
+ if (!['approve', 'reject', 'revision_requested'].includes(action)) {
3526
+ res.writeHead(400); res.end('{"error":"action must be approve, reject, or revision_requested"}'); return;
3527
+ }
3528
+ const base = path.join(projectDir || process.cwd(), '.monomind', 'orgs');
3529
+ const approvalsFile = path.join(base, `${orgName}-approvals.json`);
3530
+ let data = { approvals: [] };
3531
+ try { data = JSON.parse(fs.readFileSync(approvalsFile, 'utf8')); } catch(_) {}
3532
+ const idx = (data.approvals || []).findIndex(a => a.id === approvalId);
3533
+ if (idx === -1) { res.writeHead(404); res.end('{"error":"approval not found"}'); return; }
3534
+ const status = action === 'approve' ? 'approved' : action === 'reject' ? 'rejected' : 'revision_requested';
3535
+ data.approvals[idx] = {
3536
+ ...data.approvals[idx],
3537
+ status,
3538
+ resolvedAt: new Date().toISOString(),
3539
+ resolvedBy: 'operator',
3540
+ };
3541
+ const tmp = `${approvalsFile}.tmp`;
3542
+ fs.writeFileSync(tmp, JSON.stringify(data, null, 2), 'utf-8');
3543
+ fs.renameSync(tmp, approvalsFile);
3544
+ // Emit org:approval:resolved event so boss agent unblocks
3545
+ const event = { type: 'org:approval:resolved', org: orgName, approval_id: approvalId, status, ts: Date.now() };
3546
+ try { fs.appendFileSync(path.join(projectDir || process.cwd(), 'data', 'mastermind-events.jsonl'), JSON.stringify(event) + '\n'); } catch(_) {}
3547
+ const msg = `data: ${JSON.stringify(event)}\n\n`;
3548
+ for (const c of mmSseClients) { try { c.write(msg); } catch(_) { mmSseClients.delete(c); } }
3549
+ res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
3550
+ res.end(JSON.stringify({ ok: true, status }));
3551
+ } catch(_) { res.writeHead(500); res.end('{}'); }
3552
+ return;
3553
+ }
3554
+
3194
3555
  // GET /api/org/:name/secrets — masked secrets list (NEVER exposes values)
3195
3556
  if (req.method === 'GET' && url.match(/^\/api\/org\/[a-z0-9][a-z0-9_-]{0,63}\/secrets$/i)) {
3196
3557
  try {
@@ -3226,13 +3587,25 @@ export async function startServer({ port = 4242, projectDir, openBrowser = true
3226
3587
  const base = path.join(projectDir || process.cwd(), '.monomind', 'orgs');
3227
3588
  let budgetData = { org_budget: {}, agent_budgets: {}, period: 'monthly', currency: 'USD' };
3228
3589
  try { budgetData = JSON.parse(fs.readFileSync(path.join(base, `${orgName}-budgets.json`), 'utf8')); } catch(_) {}
3229
- // Enrich with per-agent spend from state file
3590
+ // Enrich with per-agent spend from state file.
3591
+ // State file format: { agents: { "<role_id>": { tokens_in, tokens_out, ... } } }
3230
3592
  let agents = [];
3231
3593
  try {
3232
3594
  const state = JSON.parse(fs.readFileSync(path.join(base, `${orgName}-state.json`), 'utf8'));
3233
- agents = (state.roles || []).map(r => ({
3234
- id: r.id, title: r.title,
3235
- tokens_in: r.tokens_in || 0, tokens_out: r.tokens_out || 0, total_cost_usd: r.total_cost_usd || 0
3595
+ const agentMap = state.agents || {};
3596
+ // Also load role titles from org config for enrichment
3597
+ let roleMap = {};
3598
+ try {
3599
+ const cfg = JSON.parse(fs.readFileSync(path.join(base, `${orgName}.json`), 'utf8'));
3600
+ (cfg.roles || []).forEach(r => { roleMap[r.id] = r.title || r.id; });
3601
+ } catch(_) {}
3602
+ agents = Object.entries(agentMap).map(([id, s]) => ({
3603
+ id,
3604
+ title: roleMap[id] || s.title || id,
3605
+ tokens_in: s.tokens_in || 0,
3606
+ tokens_out: s.tokens_out || 0,
3607
+ tokens_used: s.tokens_used || (s.tokens_in || 0) + (s.tokens_out || 0),
3608
+ total_cost_usd: s.total_cost_usd || 0,
3236
3609
  }));
3237
3610
  } catch(_) {}
3238
3611
  // Also include roles from org config if state is empty
@@ -3295,6 +3668,105 @@ export async function startServer({ port = 4242, projectDir, openBrowser = true
3295
3668
  return;
3296
3669
  }
3297
3670
 
3671
+ // GET /api/org/:name/goals — read org goals
3672
+ if (req.method === 'GET' && url.match(/^\/api\/org\/[a-z0-9][a-z0-9_-]{0,63}\/goals$/i)) {
3673
+ try {
3674
+ const orgName = decodeURIComponent(url.split('/')[3]);
3675
+ if (orgName.length > 64 || !/^[a-z0-9][a-z0-9_-]*$/i.test(orgName)) { res.writeHead(400); res.end('Invalid org name'); return; }
3676
+ const goalsFile = path.join(projectDir || process.cwd(), '.monomind', 'orgs', `${orgName}-goals.json`);
3677
+ let data = { goals: [] };
3678
+ try { data = JSON.parse(fs.readFileSync(goalsFile, 'utf8')); } catch(_) {}
3679
+ res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
3680
+ res.end(JSON.stringify({ goals: data.goals || [] }));
3681
+ } catch(_) { res.writeHead(500); res.end('{"goals":[]}'); }
3682
+ return;
3683
+ }
3684
+
3685
+ // GET /api/org/:name/routines — read org routines
3686
+ if (req.method === 'GET' && url.match(/^\/api\/org\/[a-z0-9][a-z0-9_-]{0,63}\/routines$/i)) {
3687
+ try {
3688
+ const orgName = decodeURIComponent(url.split('/')[3]);
3689
+ if (orgName.length > 64 || !/^[a-z0-9][a-z0-9_-]*$/i.test(orgName)) { res.writeHead(400); res.end('Invalid org name'); return; }
3690
+ const routinesFile = path.join(projectDir || process.cwd(), '.monomind', 'orgs', `${orgName}-routines.json`);
3691
+ let data = { routines: [] };
3692
+ try { data = JSON.parse(fs.readFileSync(routinesFile, 'utf8')); } catch(_) {}
3693
+ res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
3694
+ res.end(JSON.stringify({ routines: data.routines || [] }));
3695
+ } catch(_) { res.writeHead(500); res.end('{"routines":[]}'); }
3696
+ return;
3697
+ }
3698
+
3699
+ // POST /api/org/:name/goals — upsert the org goals file
3700
+ // Body: { goals: [{id, title, description, status, priority, assignee_id, created_at}] }
3701
+ if (req.method === 'POST' && url.match(/^\/api\/org\/[a-z0-9][a-z0-9_-]{0,63}\/goals$/i)) {
3702
+ let body = '';
3703
+ for await (const chunk of req) body += chunk;
3704
+ try {
3705
+ const orgName = decodeURIComponent(url.split('/')[3]);
3706
+ if (orgName.length > 64 || !/^[a-z0-9][a-z0-9_-]*$/i.test(orgName)) { res.writeHead(400); res.end('Invalid org name'); return; }
3707
+ const parsed = JSON.parse(body);
3708
+ if (!parsed || !Array.isArray(parsed.goals)) { res.writeHead(400); res.end('{"error":"goals array required"}'); return; }
3709
+ const goalsFile = path.join(projectDir || process.cwd(), '.monomind', 'orgs', `${orgName}-goals.json`);
3710
+ const tmp = `${goalsFile}.tmp`;
3711
+ const payload = { org: orgName, updated_at: new Date().toISOString(), goals: parsed.goals };
3712
+ fs.writeFileSync(tmp, JSON.stringify(payload, null, 2), 'utf-8');
3713
+ fs.renameSync(tmp, goalsFile);
3714
+ res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
3715
+ res.end(JSON.stringify({ ok: true, count: parsed.goals.length }));
3716
+ } catch(_) { res.writeHead(500); res.end('{"error":"' + String(_).replace(/"/g, '\\"') + '"}'); }
3717
+ return;
3718
+ }
3719
+
3720
+ // POST /api/org/:name/routines — upsert the org routines file
3721
+ // Body: { routines: [{name, description, schedule, enabled, last_run, next_run}] }
3722
+ if (req.method === 'POST' && url.match(/^\/api\/org\/[a-z0-9][a-z0-9_-]{0,63}\/routines$/i)) {
3723
+ let body = '';
3724
+ for await (const chunk of req) body += chunk;
3725
+ try {
3726
+ const orgName = decodeURIComponent(url.split('/')[3]);
3727
+ if (orgName.length > 64 || !/^[a-z0-9][a-z0-9_-]*$/i.test(orgName)) { res.writeHead(400); res.end('Invalid org name'); return; }
3728
+ const parsed = JSON.parse(body);
3729
+ if (!parsed || !Array.isArray(parsed.routines)) { res.writeHead(400); res.end('{"error":"routines array required"}'); return; }
3730
+ const routinesFile = path.join(projectDir || process.cwd(), '.monomind', 'orgs', `${orgName}-routines.json`);
3731
+ const tmp = `${routinesFile}.tmp`;
3732
+ const payload = { org: orgName, updated_at: new Date().toISOString(), routines: parsed.routines };
3733
+ fs.writeFileSync(tmp, JSON.stringify(payload, null, 2), 'utf-8');
3734
+ fs.renameSync(tmp, routinesFile);
3735
+ res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
3736
+ res.end(JSON.stringify({ ok: true, count: parsed.routines.length }));
3737
+ } catch(_) { res.writeHead(500); res.end('{"error":"' + String(_).replace(/"/g, '\\"') + '"}'); }
3738
+ return;
3739
+ }
3740
+
3741
+ // DELETE /api/orgs/:name — delete an org config and all associated data files
3742
+ if (req.method === 'DELETE' && url.match(/^\/api\/orgs\/[a-z0-9][a-z0-9_-]{0,63}$/i)) {
3743
+ try {
3744
+ const orgName = decodeURIComponent(url.split('/')[3]);
3745
+ if (orgName.length > 64 || !/^[a-z0-9][a-z0-9_-]*$/i.test(orgName)) { res.writeHead(400); res.end('Invalid org name'); return; }
3746
+ const orgsDir = path.join(projectDir || process.cwd(), '.monomind', 'orgs');
3747
+ const configFile = path.join(orgsDir, `${orgName}.json`);
3748
+ if (!fs.existsSync(configFile)) { res.writeHead(404); res.end('{"error":"org not found"}'); return; }
3749
+ // Remove all org-associated files (config + state + data)
3750
+ const suffixes = ['', '-state', '-goals', '-routines', '-approvals', '-activity', '-issues', '-members', '-projects', '-workspaces', '-worktrees', '-environments', '-plugins', '-adapters'];
3751
+ for (const suf of suffixes) {
3752
+ const f = path.join(orgsDir, `${orgName}${suf}.json`);
3753
+ try { if (fs.existsSync(f)) fs.unlinkSync(f); } catch(_) {}
3754
+ const fjsonl = path.join(orgsDir, `${orgName}${suf}.jsonl`);
3755
+ try { if (fs.existsSync(fjsonl)) fs.unlinkSync(fjsonl); } catch(_) {}
3756
+ }
3757
+ // Remove stop file if present
3758
+ try { fs.unlinkSync(path.join(orgsDir, '.stops', `${orgName}.stop`)); } catch(_) {}
3759
+ // Emit org:delete event
3760
+ const deleteEvent = { type: 'org:delete', org: orgName, ts: Date.now() };
3761
+ try { fs.appendFileSync(path.join(projectDir || process.cwd(), 'data', 'mastermind-events.jsonl'), JSON.stringify(deleteEvent) + '\n'); } catch(_) {}
3762
+ const msg = `data: ${JSON.stringify(deleteEvent)}\n\n`;
3763
+ for (const c of mmSseClients) { try { c.write(msg); } catch(_) { mmSseClients.delete(c); } }
3764
+ res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
3765
+ res.end('{"ok":true}');
3766
+ } catch(_) { res.writeHead(500); res.end('{}'); }
3767
+ return;
3768
+ }
3769
+
3298
3770
  // POST /api/orgs/:name/stop — send stop signal to a running org
3299
3771
  if (req.method === 'POST' && url.match(/^\/api\/orgs\/[a-z0-9][a-z0-9_-]{0,63}\/stop$/i)) {
3300
3772
  try {
@@ -3506,6 +3978,20 @@ export async function startServer({ port = 4242, projectDir, openBrowser = true
3506
3978
  return;
3507
3979
  }
3508
3980
 
3981
+ // ----------------------------------------------------------- GET /orgs
3982
+ if (req.method === 'GET' && url === '/orgs') {
3983
+ try {
3984
+ const htmlPath = path.join(__dirname, 'orgs.html');
3985
+ const html = fs.readFileSync(htmlPath, 'utf8');
3986
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
3987
+ res.end(html);
3988
+ } catch (err) {
3989
+ res.writeHead(404);
3990
+ res.end(`orgs.html not found: ${err.message}`);
3991
+ }
3992
+ return;
3993
+ }
3994
+
3509
3995
  // GET /api/mastermind/loops — list all active loop state files
3510
3996
  if (req.method === 'GET' && url === '/api/mastermind/loops') {
3511
3997
  try {