@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.
- package/.claude/agents/optimization/benchmark-suite.md +2 -0
- package/.claude/agents/optimization/load-balancer.md +2 -0
- package/.claude/agents/optimization/performance-monitor.md +2 -0
- package/.claude/agents/optimization/resource-allocator.md +3 -1
- package/.claude/agents/optimization/topology-optimizer.md +2 -0
- package/.claude/commands/mastermind/_repeat.md +21 -0
- package/.claude/commands/mastermind/_taskfile.md +235 -0
- package/.claude/commands/mastermind/adr.md +11 -0
- package/.claude/commands/mastermind/approve.md +94 -0
- package/.claude/commands/mastermind/autodev.md +32 -0
- package/.claude/commands/mastermind/budget.md +7 -0
- package/.claude/commands/mastermind/code-review.md +317 -0
- package/.claude/commands/mastermind/createorg.md +40 -1
- package/.claude/commands/mastermind/createtask.md +383 -0
- package/.claude/commands/mastermind/debug.md +22 -0
- package/.claude/commands/mastermind/design.md +20 -0
- package/.claude/commands/mastermind/do.md +526 -0
- package/.claude/commands/mastermind/execute.md +20 -0
- package/.claude/commands/mastermind/finish.md +20 -0
- package/.claude/commands/mastermind/graph-status.md +7 -0
- package/.claude/commands/mastermind/help.md +118 -0
- package/.claude/commands/mastermind/ideate.md +261 -0
- package/.claude/commands/mastermind/improve.md +345 -0
- package/.claude/commands/mastermind/loops.md +7 -0
- package/.claude/commands/mastermind/master.md +186 -6
- package/.claude/commands/mastermind/memory.md +230 -0
- package/.claude/commands/mastermind/plan.md +26 -0
- package/.claude/commands/mastermind/receive-review.md +20 -0
- package/.claude/commands/mastermind/repeat.md +257 -0
- package/.claude/commands/mastermind/runorg.md +3 -0
- package/.claude/commands/mastermind/skill-builder.md +20 -0
- package/.claude/commands/mastermind/specialagents.md +125 -0
- package/.claude/commands/mastermind/swarm.md +161 -0
- package/.claude/commands/mastermind/taskdev.md +26 -0
- package/.claude/commands/mastermind/tdd.md +22 -0
- package/.claude/commands/mastermind/techport.md +4 -0
- package/.claude/commands/mastermind/understand.md +139 -0
- package/.claude/commands/mastermind/verify.md +22 -0
- package/.claude/commands/mastermind/worktree.md +20 -0
- package/.claude/commands/monomind/do.md +52 -0
- package/.claude/commands/monomind/improve.md +2 -0
- package/.claude/helpers/handlers/graph-status-handler.cjs +2 -1
- package/.claude/helpers/handlers/route-handler.cjs +61 -11
- package/.claude/helpers/hook-handler.cjs +19 -0
- package/.claude/helpers/skill-registry.json +122 -51
- package/.claude/helpers/statusline.cjs +1 -1
- package/.claude/skills/agent-browser-testing/SKILL.md +522 -152
- package/.claude/skills/github-issue-triage/SKILL.md +354 -0
- package/.claude/skills/github-repo-recap/SKILL.md +207 -0
- package/.claude/skills/mastermind/_delegation.md +83 -0
- package/.claude/skills/mastermind/_protocol.md +14 -0
- package/.claude/skills/mastermind/approve.md +15 -7
- package/.claude/skills/mastermind/autodev.md +534 -0
- package/.claude/skills/mastermind/createorg.md +21 -5
- package/.claude/skills/mastermind/debug.md +232 -0
- package/.claude/skills/mastermind/design.md +187 -0
- package/.claude/skills/mastermind/execute.md +104 -0
- package/.claude/skills/mastermind/finish.md +251 -0
- package/.claude/skills/mastermind/plan.md +180 -0
- package/.claude/skills/mastermind/receive-review.md +213 -0
- package/.claude/skills/mastermind/runorg.md +23 -8
- package/.claude/skills/mastermind/skill-builder.md +274 -0
- package/.claude/skills/mastermind/taskdev.md +307 -0
- package/.claude/skills/mastermind/tdd.md +394 -0
- package/.claude/skills/mastermind/verify.md +196 -0
- package/.claude/skills/mastermind/worktree.md +160 -132
- package/README.md +320 -253
- package/dist/src/commands/analyze.d.ts.map +1 -1
- package/dist/src/commands/analyze.js +9 -2
- package/dist/src/commands/analyze.js.map +1 -1
- package/dist/src/commands/benchmark.js.map +1 -1
- package/dist/src/commands/completions.js +1 -1
- package/dist/src/commands/guidance.js +7 -7
- package/dist/src/commands/hooks.d.ts.map +1 -1
- package/dist/src/commands/hooks.js +16 -3
- package/dist/src/commands/hooks.js.map +1 -1
- package/dist/src/commands/index.d.ts +3 -2
- package/dist/src/commands/index.d.ts.map +1 -1
- package/dist/src/commands/index.js +7 -0
- package/dist/src/commands/index.js.map +1 -1
- package/dist/src/commands/init.d.ts.map +1 -1
- package/dist/src/commands/init.js +47 -13
- package/dist/src/commands/init.js.map +1 -1
- package/dist/src/commands/neural.d.ts.map +1 -1
- package/dist/src/commands/neural.js +100 -14
- package/dist/src/commands/neural.js.map +1 -1
- package/dist/src/commands/platforms.d.ts +11 -0
- package/dist/src/commands/platforms.d.ts.map +1 -0
- package/dist/src/commands/platforms.js +195 -0
- package/dist/src/commands/platforms.js.map +1 -0
- package/dist/src/commands/ruvector/backup.js.map +1 -1
- package/dist/src/commands/ruvector/benchmark.js.map +1 -1
- package/dist/src/commands/ruvector/init.js.map +1 -1
- package/dist/src/commands/ruvector/migrate.js.map +1 -1
- package/dist/src/commands/ruvector/optimize.js.map +1 -1
- package/dist/src/commands/ruvector/status.js.map +1 -1
- package/dist/src/commands/update.js +6 -6
- package/dist/src/init/executor.d.ts.map +1 -1
- package/dist/src/init/executor.js +28 -0
- package/dist/src/init/executor.js.map +1 -1
- package/dist/src/init/statusline-generator.js +1 -1
- package/dist/src/init/types.d.ts +1 -0
- package/dist/src/init/types.d.ts.map +1 -1
- package/dist/src/mcp-server.d.ts.map +1 -1
- package/dist/src/mcp-server.js +92 -0
- package/dist/src/mcp-server.js.map +1 -1
- package/dist/src/mcp-tools/hive-mind-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/hive-mind-tools.js +52 -0
- package/dist/src/mcp-tools/hive-mind-tools.js.map +1 -1
- package/dist/src/mcp-tools/hooks-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/hooks-tools.js +106 -5
- package/dist/src/mcp-tools/hooks-tools.js.map +1 -1
- package/dist/src/mcp-tools/index.d.ts +0 -5
- package/dist/src/mcp-tools/index.d.ts.map +1 -1
- package/dist/src/mcp-tools/index.js +0 -5
- package/dist/src/mcp-tools/index.js.map +1 -1
- package/dist/src/mcp-tools/monograph-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/monograph-tools.js +507 -5587
- package/dist/src/mcp-tools/monograph-tools.js.map +1 -1
- package/dist/src/mcp-tools/neural-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/neural-tools.js +64 -4
- package/dist/src/mcp-tools/neural-tools.js.map +1 -1
- package/dist/src/mcp-tools/security-tools.js +4 -4
- package/dist/src/memory/intelligence.d.ts +2 -2
- package/dist/src/memory/intelligence.d.ts.map +1 -1
- package/dist/src/memory/intelligence.js +108 -3
- package/dist/src/memory/intelligence.js.map +1 -1
- package/dist/src/memory/memory-bridge.js +1 -1
- package/dist/src/memory/memory-bridge.js.map +1 -1
- package/dist/src/memory/sona-optimizer.d.ts +1 -10
- package/dist/src/memory/sona-optimizer.d.ts.map +1 -1
- package/dist/src/memory/sona-optimizer.js +0 -46
- package/dist/src/memory/sona-optimizer.js.map +1 -1
- package/dist/src/runtime/headless.js +3 -3
- package/dist/src/ruvector/diff-classifier.d.ts +0 -2
- package/dist/src/ruvector/diff-classifier.d.ts.map +1 -1
- package/dist/src/ruvector/diff-classifier.js +2 -14
- package/dist/src/ruvector/diff-classifier.js.map +1 -1
- package/dist/src/ruvector/index.d.ts +26 -9
- package/dist/src/ruvector/index.d.ts.map +1 -1
- package/dist/src/ruvector/index.js +3 -21
- package/dist/src/ruvector/index.js.map +1 -1
- package/dist/src/ruvector/ruvllm-wasm.js +2 -2
- package/dist/src/ruvector/ruvllm-wasm.js.map +1 -1
- package/dist/src/types.d.ts +0 -15
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.js +0 -18
- package/dist/src/types.js.map +1 -1
- package/dist/src/ui/dashboard.html +8763 -9765
- package/dist/src/ui/data/agent-avatars.html +763 -0
- package/dist/src/ui/data/agent-avatars.json +966 -0
- package/dist/src/ui/data/avatars/account-strategist.svg +58 -0
- package/dist/src/ui/data/avatars/accounts-payable.svg +54 -0
- package/dist/src/ui/data/avatars/adaptive-coordinator.svg +55 -0
- package/dist/src/ui/data/avatars/adaptive-coordinator2.svg +54 -0
- package/dist/src/ui/data/avatars/ai-citation.svg +57 -0
- package/dist/src/ui/data/avatars/ai-engineer.svg +61 -0
- package/dist/src/ui/data/avatars/analytics-reporter.svg +53 -0
- package/dist/src/ui/data/avatars/api-tester.svg +53 -0
- package/dist/src/ui/data/avatars/architecture.svg +54 -0
- package/dist/src/ui/data/avatars/automation-governance.svg +55 -0
- package/dist/src/ui/data/avatars/backend-dev.svg +53 -0
- package/dist/src/ui/data/avatars/benchmarker.svg +54 -0
- package/dist/src/ui/data/avatars/blockchain-auditor.svg +53 -0
- package/dist/src/ui/data/avatars/byzantine-coord.svg +57 -0
- package/dist/src/ui/data/avatars/case-analyst.svg +57 -0
- package/dist/src/ui/data/avatars/cicd-engineer.svg +55 -0
- package/dist/src/ui/data/avatars/cloud-architect.svg +54 -0
- package/dist/src/ui/data/avatars/code-review-swarm.svg +57 -0
- package/dist/src/ui/data/avatars/coder-v119.svg +57 -0
- package/dist/src/ui/data/avatars/coder.svg +58 -0
- package/dist/src/ui/data/avatars/collective-coord.svg +54 -0
- package/dist/src/ui/data/avatars/compliance-auditor.svg +58 -0
- package/dist/src/ui/data/avatars/consensus-coordinator.svg +54 -0
- package/dist/src/ui/data/avatars/content-creator.svg +54 -0
- package/dist/src/ui/data/avatars/crdt-synchronizer.svg +53 -0
- package/dist/src/ui/data/avatars/cro-specialist.svg +58 -0
- package/dist/src/ui/data/avatars/data-consolidator.svg +54 -0
- package/dist/src/ui/data/avatars/data-engineer.svg +53 -0
- package/dist/src/ui/data/avatars/database-optimizer.svg +61 -0
- package/dist/src/ui/data/avatars/deal-strategist.svg +54 -0
- package/dist/src/ui/data/avatars/defender.svg +53 -0
- package/dist/src/ui/data/avatars/devops-automator.svg +56 -0
- package/dist/src/ui/data/avatars/discovery-coach.svg +54 -0
- package/dist/src/ui/data/avatars/email-marketing.svg +57 -0
- package/dist/src/ui/data/avatars/embedded-firmware.svg +61 -0
- package/dist/src/ui/data/avatars/evidence-collector.svg +57 -0
- package/dist/src/ui/data/avatars/experiment-tracker.svg +53 -0
- package/dist/src/ui/data/avatars/feedback-synthesizer.svg +54 -0
- package/dist/src/ui/data/avatars/finance-tracker.svg +54 -0
- package/dist/src/ui/data/avatars/frontend-developer.svg +54 -0
- package/dist/src/ui/data/avatars/game-audio-engineer.svg +59 -0
- package/dist/src/ui/data/avatars/game-designer.svg +54 -0
- package/dist/src/ui/data/avatars/gossip-coordinator.svg +54 -0
- package/dist/src/ui/data/avatars/hierarchical-coord.svg +54 -0
- package/dist/src/ui/data/avatars/incident-commander.svg +57 -0
- package/dist/src/ui/data/avatars/infrastructure.svg +54 -0
- package/dist/src/ui/data/avatars/input-validator.svg +53 -0
- package/dist/src/ui/data/avatars/ios-developer.svg +54 -0
- package/dist/src/ui/data/avatars/issue-tracker.svg +53 -0
- package/dist/src/ui/data/avatars/judge.svg +55 -0
- package/dist/src/ui/data/avatars/launch-strategist.svg +54 -0
- package/dist/src/ui/data/avatars/legal-compliance.svg +53 -0
- package/dist/src/ui/data/avatars/level-designer.svg +53 -0
- package/dist/src/ui/data/avatars/load-balancer.svg +57 -0
- package/dist/src/ui/data/avatars/mcp-builder.svg +53 -0
- package/dist/src/ui/data/avatars/memory-coordinator.svg +55 -0
- package/dist/src/ui/data/avatars/mesh-coordinator.svg +55 -0
- package/dist/src/ui/data/avatars/ml-developer.svg +58 -0
- package/dist/src/ui/data/avatars/mobile-app-builder.svg +53 -0
- package/dist/src/ui/data/avatars/mobile-dev.svg +54 -0
- package/dist/src/ui/data/avatars/model-qa.svg +58 -0
- package/dist/src/ui/data/avatars/narrative-designer.svg +58 -0
- package/dist/src/ui/data/avatars/outbound-strategist.svg +55 -0
- package/dist/src/ui/data/avatars/path-validator.svg +54 -0
- package/dist/src/ui/data/avatars/payment-agent.svg +53 -0
- package/dist/src/ui/data/avatars/perf-analyzer.svg +58 -0
- package/dist/src/ui/data/avatars/pipeline-analyst.svg +54 -0
- package/dist/src/ui/data/avatars/planner.svg +55 -0
- package/dist/src/ui/data/avatars/pr-manager.svg +54 -0
- package/dist/src/ui/data/avatars/pricing-strategist.svg +54 -0
- package/dist/src/ui/data/avatars/product-manager.svg +54 -0
- package/dist/src/ui/data/avatars/production-validator.svg +54 -0
- package/dist/src/ui/data/avatars/project-shepherd.svg +54 -0
- package/dist/src/ui/data/avatars/proposal-strategist.svg +54 -0
- package/dist/src/ui/data/avatars/prosecutor.svg +57 -0
- package/dist/src/ui/data/avatars/pseudocode.svg +53 -0
- package/dist/src/ui/data/avatars/queen-coordinator.svg +55 -0
- package/dist/src/ui/data/avatars/quorum-manager.svg +53 -0
- package/dist/src/ui/data/avatars/raft-manager.svg +53 -0
- package/dist/src/ui/data/avatars/reality-checker.svg +58 -0
- package/dist/src/ui/data/avatars/recruitment.svg +58 -0
- package/dist/src/ui/data/avatars/refinement.svg +53 -0
- package/dist/src/ui/data/avatars/release-manager.svg +54 -0
- package/dist/src/ui/data/avatars/repo-architect.svg +54 -0
- package/dist/src/ui/data/avatars/researcher.svg +58 -0
- package/dist/src/ui/data/avatars/resource-allocator.svg +53 -0
- package/dist/src/ui/data/avatars/reviewer.svg +53 -0
- package/dist/src/ui/data/avatars/safe-executor.svg +53 -0
- package/dist/src/ui/data/avatars/sales-coach.svg +53 -0
- package/dist/src/ui/data/avatars/sales-engineer.svg +58 -0
- package/dist/src/ui/data/avatars/scout-explorer.svg +58 -0
- package/dist/src/ui/data/avatars/security-architect.svg +54 -0
- package/dist/src/ui/data/avatars/security-auditor.svg +55 -0
- package/dist/src/ui/data/avatars/senior-developer.svg +58 -0
- package/dist/src/ui/data/avatars/senior-pm.svg +58 -0
- package/dist/src/ui/data/avatars/seo-specialist.svg +57 -0
- package/dist/src/ui/data/avatars/social-media.svg +54 -0
- package/dist/src/ui/data/avatars/solidity-engineer.svg +58 -0
- package/dist/src/ui/data/avatars/sparc-coder.svg +58 -0
- package/dist/src/ui/data/avatars/sparc-coord.svg +56 -0
- package/dist/src/ui/data/avatars/specification.svg +57 -0
- package/dist/src/ui/data/avatars/sprint-prioritizer.svg +53 -0
- package/dist/src/ui/data/avatars/sre.svg +54 -0
- package/dist/src/ui/data/avatars/studio-operations.svg +53 -0
- package/dist/src/ui/data/avatars/studio-producer.svg +55 -0
- package/dist/src/ui/data/avatars/support-responder.svg +56 -0
- package/dist/src/ui/data/avatars/system-architect.svg +54 -0
- package/dist/src/ui/data/avatars/task-orchestrator.svg +56 -0
- package/dist/src/ui/data/avatars/technical-artist.svg +53 -0
- package/dist/src/ui/data/avatars/technical-writer.svg +59 -0
- package/dist/src/ui/data/avatars/tester.svg +53 -0
- package/dist/src/ui/data/avatars/threat-detection.svg +61 -0
- package/dist/src/ui/data/avatars/trend-researcher.svg +54 -0
- package/dist/src/ui/data/avatars/trial-director.svg +55 -0
- package/dist/src/ui/data/avatars/unity-architect.svg +54 -0
- package/dist/src/ui/data/avatars/visionos-engineer.svg +57 -0
- package/dist/src/ui/data/avatars/worker-specialist.svg +55 -0
- package/dist/src/ui/data/avatars/workflow-architect.svg +57 -0
- package/dist/src/ui/data/avatars/workflow-automation.svg +54 -0
- package/dist/src/ui/data/avatars/zk-steward.svg +54 -0
- package/dist/src/ui/data/known-projects.json +1 -1
- package/dist/src/ui/data/mastermind-events.jsonl +28 -0
- package/dist/src/ui/orgs.html +1171 -0
- package/dist/src/ui/server.mjs +529 -43
- package/dist/src/update/index.js +1 -1
- package/dist/src/update/validator.js +8 -8
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/.claude/agents/academic/academic-anthropologist.md +0 -126
- package/.claude/agents/academic/academic-geographer.md +0 -128
- package/.claude/agents/academic/academic-historian.md +0 -124
- package/.claude/agents/academic/academic-narratologist.md +0 -119
- package/.claude/agents/academic/academic-psychologist.md +0 -119
- package/.claude/agents/analysis/analyze-code-quality.md +0 -58
- package/.claude/agents/analysis/code-analyzer.md +0 -189
- package/.claude/agents/analysis/code-review/analyze-code-quality.md +0 -58
- package/.claude/agents/consensus/performance-benchmarker.md +0 -831
- package/.claude/agents/data/ml/data-ml-model.md +0 -76
- package/.claude/agents/development/dev-backend-api.md +0 -178
- package/.claude/agents/devops/ci-cd/ops-cicd-github.md +0 -52
- package/.claude/agents/documentation/api-docs/docs-api-openapi.md +0 -63
- package/.claude/agents/game-development/blender/blender-addon-engineer.md +0 -235
- package/.claude/agents/game-development/game-audio-engineer.md +0 -265
- package/.claude/agents/game-development/game-designer.md +0 -168
- package/.claude/agents/game-development/godot/godot-gameplay-scripter.md +0 -335
- package/.claude/agents/game-development/godot/godot-multiplayer-engineer.md +0 -298
- package/.claude/agents/game-development/godot/godot-shader-developer.md +0 -267
- package/.claude/agents/game-development/level-designer.md +0 -209
- package/.claude/agents/game-development/narrative-designer.md +0 -244
- package/.claude/agents/game-development/roblox-studio/roblox-avatar-creator.md +0 -298
- package/.claude/agents/game-development/roblox-studio/roblox-experience-designer.md +0 -306
- package/.claude/agents/game-development/roblox-studio/roblox-systems-scripter.md +0 -326
- package/.claude/agents/game-development/technical-artist.md +0 -230
- package/.claude/agents/game-development/unity/unity-architect.md +0 -272
- package/.claude/agents/game-development/unity/unity-editor-tool-developer.md +0 -311
- package/.claude/agents/game-development/unity/unity-multiplayer-engineer.md +0 -322
- package/.claude/agents/game-development/unity/unity-shader-graph-artist.md +0 -270
- package/.claude/agents/game-development/unreal-engine/unreal-multiplayer-architect.md +0 -314
- package/.claude/agents/game-development/unreal-engine/unreal-systems-engineer.md +0 -311
- package/.claude/agents/game-development/unreal-engine/unreal-technical-artist.md +0 -257
- package/.claude/agents/game-development/unreal-engine/unreal-world-builder.md +0 -274
- package/.claude/agents/github/release-swarm.md +0 -597
- package/.claude/agents/goal/agent.md +0 -804
- package/.claude/agents/goal/code-goal-planner.md +0 -445
- package/.claude/agents/marketing/marketing-ai-citation-strategist.md +0 -171
- package/.claude/agents/marketing/marketing-app-store-optimizer.md +0 -322
- package/.claude/agents/marketing/marketing-baidu-seo-specialist.md +0 -227
- package/.claude/agents/marketing/marketing-bilibili-content-strategist.md +0 -200
- package/.claude/agents/marketing/marketing-book-co-author.md +0 -111
- package/.claude/agents/marketing/marketing-carousel-growth-engine.md +0 -200
- package/.claude/agents/marketing/marketing-china-ecommerce-operator.md +0 -284
- package/.claude/agents/marketing/marketing-content-creator.md +0 -67
- package/.claude/agents/marketing/marketing-cross-border-ecommerce.md +0 -260
- package/.claude/agents/marketing/marketing-douyin-strategist.md +0 -150
- package/.claude/agents/marketing/marketing-growth-hacker.md +0 -54
- package/.claude/agents/marketing/marketing-instagram-curator.md +0 -114
- package/.claude/agents/marketing/marketing-kuaishou-strategist.md +0 -224
- package/.claude/agents/marketing/marketing-linkedin-content-creator.md +0 -215
- package/.claude/agents/marketing/marketing-livestream-commerce-coach.md +0 -306
- package/.claude/agents/marketing/marketing-podcast-strategist.md +0 -278
- package/.claude/agents/marketing/marketing-private-domain-operator.md +0 -309
- package/.claude/agents/marketing/marketing-reddit-community-builder.md +0 -124
- package/.claude/agents/marketing/marketing-seo-specialist.md +0 -279
- package/.claude/agents/marketing/marketing-short-video-editing-coach.md +0 -413
- package/.claude/agents/marketing/marketing-social-media-strategist.md +0 -125
- package/.claude/agents/marketing/marketing-tiktok-strategist.md +0 -126
- package/.claude/agents/marketing/marketing-twitter-engager.md +0 -127
- package/.claude/agents/marketing/marketing-wechat-official-account.md +0 -146
- package/.claude/agents/marketing/marketing-weibo-strategist.md +0 -241
- package/.claude/agents/marketing/marketing-xiaohongshu-specialist.md +0 -139
- package/.claude/agents/marketing/marketing-zhihu-strategist.md +0 -163
- package/.claude/agents/neural/safla-neural.md +0 -74
- package/.claude/agents/paid-media/paid-media-auditor.md +0 -71
- package/.claude/agents/paid-media/paid-media-creative-strategist.md +0 -71
- package/.claude/agents/paid-media/paid-media-paid-social-strategist.md +0 -71
- package/.claude/agents/paid-media/paid-media-ppc-strategist.md +0 -71
- package/.claude/agents/paid-media/paid-media-programmatic-buyer.md +0 -71
- package/.claude/agents/paid-media/paid-media-search-query-analyst.md +0 -71
- package/.claude/agents/paid-media/paid-media-tracking-specialist.md +0 -71
- package/.claude/agents/payments/agentic-payments.md +0 -126
- package/.claude/agents/product/product-behavioral-nudge-engine.md +0 -81
- package/.claude/agents/product/product-feedback-synthesizer.md +0 -119
- package/.claude/agents/product/product-manager.md +0 -469
- package/.claude/agents/product/product-sprint-prioritizer.md +0 -154
- package/.claude/agents/product/product-trend-researcher.md +0 -159
- package/.claude/agents/project-management/project-management-experiment-tracker.md +0 -199
- package/.claude/agents/project-management/project-management-jira-workflow-steward.md +0 -231
- package/.claude/agents/project-management/project-management-project-shepherd.md +0 -195
- package/.claude/agents/project-management/project-management-studio-operations.md +0 -201
- package/.claude/agents/project-management/project-management-studio-producer.md +0 -204
- package/.claude/agents/project-management/project-manager-senior.md +0 -136
- package/.claude/agents/reasoning/agent.md +0 -804
- package/.claude/agents/reasoning/goal-planner.md +0 -73
- package/.claude/agents/sales/sales-account-strategist.md +0 -228
- package/.claude/agents/sales/sales-coach.md +0 -272
- package/.claude/agents/sales/sales-deal-strategist.md +0 -181
- package/.claude/agents/sales/sales-discovery-coach.md +0 -226
- package/.claude/agents/sales/sales-engineer.md +0 -183
- package/.claude/agents/sales/sales-outbound-strategist.md +0 -202
- package/.claude/agents/sales/sales-pipeline-analyst.md +0 -268
- package/.claude/agents/sales/sales-proposal-strategist.md +0 -218
- package/.claude/agents/sona/sona-learning-optimizer.md +0 -65
- package/.claude/agents/spatial-computing/macos-spatial-metal-engineer.md +0 -338
- package/.claude/agents/spatial-computing/terminal-integration-specialist.md +0 -71
- package/.claude/agents/spatial-computing/visionos-spatial-engineer.md +0 -55
- package/.claude/agents/specialists/memory-specialist.md +0 -298
- package/.claude/agents/specialists/performance-engineer.md +0 -387
- package/.claude/agents/specialists/queen-coordinator.md +0 -67
- package/.claude/agents/specialists/security-architect.md +0 -154
- package/.claude/agents/specialized/accounts-payable-agent.md +0 -186
- package/.claude/agents/specialized/corporate-training-designer.md +0 -193
- package/.claude/agents/specialized/data-consolidation-agent.md +0 -61
- package/.claude/agents/specialized/government-digital-presales-consultant.md +0 -364
- package/.claude/agents/specialized/healthcare-marketing-compliance.md +0 -396
- package/.claude/agents/specialized/recruitment-specialist.md +0 -510
- package/.claude/agents/specialized/report-distribution-agent.md +0 -66
- package/.claude/agents/specialized/sales-data-extraction-agent.md +0 -68
- package/.claude/agents/specialized/specialized-french-consulting-market.md +0 -193
- package/.claude/agents/specialized/specialized-korean-business-navigator.md +0 -217
- package/.claude/agents/specialized/specialized-salesforce-architect.md +0 -181
- package/.claude/agents/specialized/study-abroad-advisor.md +0 -283
- package/.claude/agents/specialized/supply-chain-strategist.md +0 -583
- package/.claude/agents/sublinear/consensus-coordinator.md +0 -333
- package/.claude/agents/sublinear/matrix-optimizer.md +0 -180
- package/.claude/agents/sublinear/pagerank-analyzer.md +0 -295
- package/.claude/agents/sublinear/performance-optimizer.md +0 -363
- package/.claude/agents/sublinear/trading-predictor.md +0 -242
- package/.claude/agents/support/support-analytics-reporter.md +0 -366
- package/.claude/agents/support/support-executive-summary-generator.md +0 -213
- package/.claude/agents/support/support-finance-tracker.md +0 -443
- package/.claude/agents/support/support-infrastructure-maintainer.md +0 -619
- package/.claude/agents/support/support-legal-compliance-checker.md +0 -589
- package/.claude/agents/support/support-support-responder.md +0 -586
- package/.claude/agents/swarm/adaptive-coordinator.md +0 -364
- package/.claude/agents/swarm/hierarchical-coordinator.md +0 -318
- package/.claude/agents/templates/github-pr-manager.md +0 -155
- package/.claude/agents/templates/memory-coordinator.md +0 -163
- package/.claude/agents/templates/migration-plan.md +0 -724
- package/.claude/agents/templates/orchestrator-task.md +0 -120
- package/.claude/agents/templates/performance-analyzer.md +0 -179
- package/.claude/agents/templates/sparc-coordinator.md +0 -163
- package/.claude/agents/testing/testing-reality-checker.md +0 -237
- package/.claude/commands/analysis/token-efficiency.md +0 -42
- package/.claude/commands/optimization/README.md +0 -73
- package/.claude/commands/optimization/parallel-execution.md +0 -76
- package/.claude/commands/swarm/swarm-analysis.md +0 -62
- package/.claude/commands/swarm/swarm-background.md +0 -65
- package/.claude/commands/swarm/swarm-modes.md +0 -67
- package/.claude/commands/swarm/swarm-monitor.md +0 -54
- package/.claude/commands/swarm/swarm-status.md +0 -44
- package/.claude/commands/swarm/swarm-strategies.md +0 -76
- package/.claude/commands/training/model-update.md +0 -78
- package/.claude/commands/training/pattern-learn.md +0 -69
- package/.claude/commands/training/specialization.md +0 -92
- package/.claude/commands/verify/check.md +0 -106
- package/.claude/commands/verify/start.md +0 -105
- package/.claude/helpers/README.md +0 -105
- package/.claude/helpers/context-persistence-hook.mjs +0 -1988
- package/.claude/helpers/intelligence.cjs +0 -247
- package/.claude/helpers/learning-service.mjs +0 -1302
- package/.claude/helpers/memory-palace.cjs +0 -461
- package/.claude/helpers/memory.cjs +0 -84
- package/.claude/helpers/metrics-db.mjs +0 -488
- package/.claude/helpers/router.cjs +0 -559
- package/.claude/helpers/session.cjs +0 -126
- package/.claude/helpers/swarm-hooks.sh +0 -761
- package/.claude/helpers/toggle-statusline.cjs +0 -58
- package/.claude/helpers/token-tracker.cjs +0 -934
- package/.claude/skills/agentdb-advanced/SKILL.md +0 -549
- package/.claude/skills/agentdb-learning/SKILL.md +0 -544
- package/.claude/skills/agentdb-memory-patterns/SKILL.md +0 -337
- package/.claude/skills/agentdb-optimization/SKILL.md +0 -508
- package/.claude/skills/agentdb-vector-search/SKILL.md +0 -335
- package/.claude/skills/agentic-integration/SKILL.md +0 -265
- package/.claude/skills/cli-modernization/SKILL.md +0 -950
- package/.claude/skills/core-implementation/SKILL.md +0 -892
- package/.claude/skills/ddd-architecture/SKILL.md +0 -444
- package/.claude/skills/github-code-review/SKILL.md +0 -1147
- package/.claude/skills/github-multi-repo/SKILL.md +0 -912
- package/.claude/skills/github-project-management/SKILL.md +0 -1245
- package/.claude/skills/github-release-management/SKILL.md +0 -1118
- package/.claude/skills/github-workflow-automation/SKILL.md +0 -1107
- package/.claude/skills/mcp-optimization/SKILL.md +0 -837
- package/.claude/skills/memory-unification/SKILL.md +0 -196
- package/.claude/skills/performance-optimization/SKILL.md +0 -416
- package/.claude/skills/reasoningbank-agentdb/SKILL.md +0 -444
- package/.claude/skills/reasoningbank-intelligence/SKILL.md +0 -199
- package/.claude/skills/security-hardening/SKILL.md +0 -101
- package/.claude/skills/stream-chain/SKILL.md +0 -560
- package/.claude/skills/swarm-coordination/SKILL.md +0 -451
- package/bundled-graph/dist/src/analyze.d.ts +0 -32
- package/bundled-graph/dist/src/analyze.d.ts.map +0 -1
- package/bundled-graph/dist/src/analyze.js +0 -297
- package/bundled-graph/dist/src/analyze.js.map +0 -1
- package/bundled-graph/dist/src/build.d.ts +0 -8
- package/bundled-graph/dist/src/build.d.ts.map +0 -1
- package/bundled-graph/dist/src/build.js.map +0 -1
- package/bundled-graph/dist/src/cache.d.ts +0 -12
- package/bundled-graph/dist/src/cache.d.ts.map +0 -1
- package/bundled-graph/dist/src/cache.js +0 -43
- package/bundled-graph/dist/src/cache.js.map +0 -1
- package/bundled-graph/dist/src/cluster.d.ts +0 -5
- package/bundled-graph/dist/src/cluster.d.ts.map +0 -1
- package/bundled-graph/dist/src/cluster.js.map +0 -1
- package/bundled-graph/dist/src/detect.d.ts +0 -21
- package/bundled-graph/dist/src/detect.d.ts.map +0 -1
- package/bundled-graph/dist/src/detect.js +0 -195
- package/bundled-graph/dist/src/detect.js.map +0 -1
- package/bundled-graph/dist/src/export.d.ts +0 -21
- package/bundled-graph/dist/src/export.d.ts.map +0 -1
- package/bundled-graph/dist/src/export.js +0 -68
- package/bundled-graph/dist/src/export.js.map +0 -1
- package/bundled-graph/dist/src/extract/index.d.ts +0 -20
- package/bundled-graph/dist/src/extract/index.d.ts.map +0 -1
- package/bundled-graph/dist/src/extract/index.js +0 -158
- package/bundled-graph/dist/src/extract/index.js.map +0 -1
- package/bundled-graph/dist/src/extract/languages/c.d.ts +0 -3
- package/bundled-graph/dist/src/extract/languages/c.d.ts.map +0 -1
- package/bundled-graph/dist/src/extract/languages/c.js +0 -88
- package/bundled-graph/dist/src/extract/languages/c.js.map +0 -1
- package/bundled-graph/dist/src/extract/languages/cpp.d.ts +0 -3
- package/bundled-graph/dist/src/extract/languages/cpp.d.ts.map +0 -1
- package/bundled-graph/dist/src/extract/languages/cpp.js +0 -121
- package/bundled-graph/dist/src/extract/languages/cpp.js.map +0 -1
- package/bundled-graph/dist/src/extract/languages/csharp.d.ts +0 -3
- package/bundled-graph/dist/src/extract/languages/csharp.d.ts.map +0 -1
- package/bundled-graph/dist/src/extract/languages/csharp.js +0 -121
- package/bundled-graph/dist/src/extract/languages/csharp.js.map +0 -1
- package/bundled-graph/dist/src/extract/languages/go.d.ts +0 -3
- package/bundled-graph/dist/src/extract/languages/go.d.ts.map +0 -1
- package/bundled-graph/dist/src/extract/languages/go.js +0 -181
- package/bundled-graph/dist/src/extract/languages/go.js.map +0 -1
- package/bundled-graph/dist/src/extract/languages/java.d.ts +0 -3
- package/bundled-graph/dist/src/extract/languages/java.d.ts.map +0 -1
- package/bundled-graph/dist/src/extract/languages/java.js +0 -117
- package/bundled-graph/dist/src/extract/languages/java.js.map +0 -1
- package/bundled-graph/dist/src/extract/languages/kotlin.d.ts +0 -3
- package/bundled-graph/dist/src/extract/languages/kotlin.d.ts.map +0 -1
- package/bundled-graph/dist/src/extract/languages/kotlin.js +0 -112
- package/bundled-graph/dist/src/extract/languages/kotlin.js.map +0 -1
- package/bundled-graph/dist/src/extract/languages/php.d.ts +0 -3
- package/bundled-graph/dist/src/extract/languages/php.d.ts.map +0 -1
- package/bundled-graph/dist/src/extract/languages/php.js +0 -130
- package/bundled-graph/dist/src/extract/languages/php.js.map +0 -1
- package/bundled-graph/dist/src/extract/languages/python.d.ts +0 -3
- package/bundled-graph/dist/src/extract/languages/python.d.ts.map +0 -1
- package/bundled-graph/dist/src/extract/languages/python.js +0 -230
- package/bundled-graph/dist/src/extract/languages/python.js.map +0 -1
- package/bundled-graph/dist/src/extract/languages/ruby.d.ts +0 -3
- package/bundled-graph/dist/src/extract/languages/ruby.d.ts.map +0 -1
- package/bundled-graph/dist/src/extract/languages/ruby.js +0 -120
- package/bundled-graph/dist/src/extract/languages/ruby.js.map +0 -1
- package/bundled-graph/dist/src/extract/languages/rust.d.ts +0 -3
- package/bundled-graph/dist/src/extract/languages/rust.d.ts.map +0 -1
- package/bundled-graph/dist/src/extract/languages/rust.js +0 -195
- package/bundled-graph/dist/src/extract/languages/rust.js.map +0 -1
- package/bundled-graph/dist/src/extract/languages/scala.d.ts +0 -3
- package/bundled-graph/dist/src/extract/languages/scala.d.ts.map +0 -1
- package/bundled-graph/dist/src/extract/languages/scala.js +0 -110
- package/bundled-graph/dist/src/extract/languages/scala.js.map +0 -1
- package/bundled-graph/dist/src/extract/languages/swift.d.ts +0 -3
- package/bundled-graph/dist/src/extract/languages/swift.d.ts.map +0 -1
- package/bundled-graph/dist/src/extract/languages/swift.js +0 -122
- package/bundled-graph/dist/src/extract/languages/swift.js.map +0 -1
- package/bundled-graph/dist/src/extract/languages/typescript.d.ts +0 -3
- package/bundled-graph/dist/src/extract/languages/typescript.d.ts.map +0 -1
- package/bundled-graph/dist/src/extract/languages/typescript.js +0 -295
- package/bundled-graph/dist/src/extract/languages/typescript.js.map +0 -1
- package/bundled-graph/dist/src/extract/semantic.d.ts +0 -38
- package/bundled-graph/dist/src/extract/semantic.d.ts.map +0 -1
- package/bundled-graph/dist/src/extract/semantic.js +0 -242
- package/bundled-graph/dist/src/extract/semantic.js.map +0 -1
- package/bundled-graph/dist/src/extract/tree-sitter-runner.d.ts +0 -48
- package/bundled-graph/dist/src/extract/tree-sitter-runner.d.ts.map +0 -1
- package/bundled-graph/dist/src/extract/tree-sitter-runner.js +0 -137
- package/bundled-graph/dist/src/extract/tree-sitter-runner.js.map +0 -1
- package/bundled-graph/dist/src/extract/types.d.ts +0 -7
- package/bundled-graph/dist/src/extract/types.d.ts.map +0 -1
- package/bundled-graph/dist/src/extract/types.js +0 -2
- package/bundled-graph/dist/src/extract/types.js.map +0 -1
- package/bundled-graph/dist/src/index.d.ts +0 -28
- package/bundled-graph/dist/src/index.d.ts.map +0 -1
- package/bundled-graph/dist/src/index.js +0 -26
- package/bundled-graph/dist/src/index.js.map +0 -1
- package/bundled-graph/dist/src/pipeline.d.ts +0 -27
- package/bundled-graph/dist/src/pipeline.d.ts.map +0 -1
- package/bundled-graph/dist/src/pipeline.js +0 -269
- package/bundled-graph/dist/src/pipeline.js.map +0 -1
- package/bundled-graph/dist/src/report.d.ts +0 -26
- package/bundled-graph/dist/src/report.d.ts.map +0 -1
- package/bundled-graph/dist/src/report.js +0 -214
- package/bundled-graph/dist/src/report.js.map +0 -1
- package/bundled-graph/dist/src/types.d.ts +0 -124
- package/bundled-graph/dist/src/types.d.ts.map +0 -1
- package/bundled-graph/dist/src/types.js +0 -2
- package/bundled-graph/dist/src/types.js.map +0 -1
- package/bundled-graph/dist/src/visualize.d.ts +0 -4
- package/bundled-graph/dist/src/visualize.d.ts.map +0 -1
- package/bundled-graph/dist/src/visualize.js +0 -574
- package/bundled-graph/dist/src/visualize.js.map +0 -1
- package/bundled-graph/dist/tsconfig.tsbuildinfo +0 -1
- package/dist/src/ui/dashboard-v2.html +0 -4576
package/dist/src/ui/server.mjs
CHANGED
|
@@ -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
|
-
|
|
275
|
-
|
|
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 =
|
|
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
|
-
|
|
639
|
-
const
|
|
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
|
|
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('
|
|
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('
|
|
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
|
|
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('
|
|
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
|
|
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('
|
|
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('
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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(-
|
|
2693
|
-
.filter(e => e.org === orgName || e.
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
3234
|
-
|
|
3235
|
-
|
|
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 {
|