@monoes/monomindcli 2.9.21 → 2.9.23
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/consensus/quorum-manager.md +35 -54
- package/.claude/agents/core/coordinator.md +14 -18
- package/.claude/agents/core/researcher.md +1 -1
- package/.claude/agents/github/issue-tracker.md +3 -3
- package/.claude/agents/github/{code-review-swarm.md → monoswarm-code-review.md} +1 -1
- package/.claude/agents/github/{swarm-issue.md → monoswarm-issue.md} +1 -1
- package/.claude/agents/github/{multi-repo-swarm.md → monoswarm-multi-repo.md} +1 -1
- package/.claude/agents/github/{swarm-pr.md → monoswarm-pr.md} +1 -1
- package/.claude/agents/github/pr-manager.md +1 -1
- package/.claude/agents/github/release-manager.md +1 -1
- package/.claude/agents/github/repo-architect.md +1 -1
- package/.claude/agents/github/sync-coordinator.md +4 -4
- package/.claude/agents/{hive-mind → monoswarm}/collective-intelligence-coordinator.md +9 -16
- package/.claude/agents/{swarm → monoswarm}/mesh-coordinator.md +19 -24
- package/.claude/agents/{hive-mind/swarm-memory-manager.md → monoswarm/monoswarm-memory-manager.md} +1 -1
- package/.claude/agents/templates/{coordinator-swarm-init.md → coordinator-monoswarm-init.md} +1 -1
- package/.claude/agents/testing/{tdd-london-swarm.md → tdd-london-monoswarm.md} +2 -2
- package/.claude/commands/agents/agent-coordination.md +3 -3
- package/.claude/commands/agents/agent-types.md +1 -1
- package/.claude/commands/automation/self-healing.md +1 -1
- package/.claude/commands/automation/smart-spawn.md +1 -1
- package/.claude/commands/coordination/README.md +1 -1
- package/.claude/commands/coordination/{swarm-init.md → monoswarm-init.md} +2 -2
- package/.claude/commands/coordination/task-orchestrate.md +4 -4
- package/.claude/commands/github/README.md +1 -1
- package/.claude/commands/github/issue-tracker.md +2 -2
- package/.claude/commands/github/pr-manager.md +1 -1
- package/.claude/commands/github/release-manager.md +1 -1
- package/.claude/commands/github/repo-architect.md +1 -1
- package/.claude/commands/github/sync-coordinator.md +2 -2
- package/.claude/commands/hooks/README.md +1 -2
- package/.claude/commands/hooks/overview.md +1 -2
- package/.claude/commands/hooks/setup.md +0 -3
- package/.claude/commands/mastermind/createtask.md +2 -2
- package/.claude/commands/mastermind/do.md +3 -3
- package/.claude/commands/mastermind/help.md +2 -2
- package/.claude/commands/mastermind/ideate.md +1 -1
- package/.claude/commands/mastermind/improve.md +1 -1
- package/.claude/commands/mastermind/memory.md +2 -2
- package/.claude/commands/mastermind/{swarm.md → monoswarm.md} +13 -26
- package/.claude/commands/mastermind/topology.md +1 -1
- package/.claude/commands/memory/README.md +2 -2
- package/.claude/commands/memory/memory-search.md +1 -1
- package/.claude/commands/monoswarm/README.md +59 -0
- package/.claude/commands/monoswarm/consensus.md +61 -0
- package/.claude/commands/monoswarm/init.md +68 -0
- package/.claude/commands/monoswarm/memory.md +55 -0
- package/.claude/commands/monoswarm/monoswarm.md +139 -0
- package/.claude/commands/{swarm → monoswarm}/research.md +2 -2
- package/.claude/commands/monoswarm/spawn.md +49 -0
- package/.claude/commands/monoswarm/status.md +48 -0
- package/.claude/commands/monoswarm/stop.md +46 -0
- package/.claude/commands/optimization/auto-topology.md +9 -9
- package/.claude/commands/stream-chain/run.md +1 -1
- package/.claude/commands/workflows/development.md +1 -1
- package/.claude/commands/workflows/research.md +2 -2
- package/.claude/helpers/audit-log-writer.cjs +72 -0
- package/.claude/helpers/control-start.cjs +84 -26
- package/.claude/helpers/handlers/agent-start-handler.cjs +5 -5
- package/.claude/helpers/handlers/gates-handler.cjs +31 -10
- package/.claude/helpers/handlers/session-restore-handler.cjs +1 -1
- package/.claude/helpers/handlers/task-handler.cjs +4 -4
- package/.claude/helpers/skill-registry.json +4718 -3669
- package/.claude/helpers/statusline.cjs +21 -21
- package/.claude/helpers/token-tracker.cjs +0 -6
- package/.claude/settings.json +2 -3
- package/.claude/skills/hooks-automation/SKILL.md +5 -5
- package/.claude/skills/mastermind-createorg/SKILL.md +26 -3
- package/.claude/skills/mastermind-protocol/SKILL.md +3 -3
- package/.claude/skills/memory-toolkit/SKILL.md +2 -2
- package/.claude/skills/{swarm-orchestration → monoswarm}/SKILL.md +106 -42
- package/.claude/skills/specialagent/SKILL.md +1 -1
- package/README.md +31 -12
- package/dist/src/autopilot-state.d.ts +0 -16
- package/dist/src/autopilot-state.d.ts.map +1 -1
- package/dist/src/autopilot-state.js +0 -15
- package/dist/src/autopilot-state.js.map +1 -1
- package/dist/src/browser/dashboard/server.js +3 -3
- package/dist/src/browser/dashboard/server.js.map +1 -1
- package/dist/src/browser/dashboard/ui.html +2 -2
- package/dist/src/capabilities/cap-documents.d.ts.map +1 -1
- package/dist/src/capabilities/cap-documents.js +49 -38
- package/dist/src/capabilities/cap-documents.js.map +1 -1
- package/dist/src/commands/agent-lifecycle.d.ts.map +1 -1
- package/dist/src/commands/agent-lifecycle.js +4 -9
- package/dist/src/commands/agent-lifecycle.js.map +1 -1
- package/dist/src/commands/agent-ops.d.ts.map +1 -1
- package/dist/src/commands/agent-ops.js +37 -24
- package/dist/src/commands/agent-ops.js.map +1 -1
- package/dist/src/commands/analyze-ast.d.ts +1 -1
- package/dist/src/commands/analyze-ast.d.ts.map +1 -1
- package/dist/src/commands/analyze-ast.js +8 -27
- package/dist/src/commands/analyze-ast.js.map +1 -1
- package/dist/src/commands/analyze-imports.d.ts.map +1 -1
- package/dist/src/commands/analyze-imports.js +18 -17
- package/dist/src/commands/analyze-imports.js.map +1 -1
- package/dist/src/commands/analyze-symbols.d.ts.map +1 -1
- package/dist/src/commands/analyze-symbols.js +10 -24
- package/dist/src/commands/analyze-symbols.js.map +1 -1
- package/dist/src/commands/analyze.d.ts +19 -6
- package/dist/src/commands/analyze.d.ts.map +1 -1
- package/dist/src/commands/analyze.js +61 -15
- package/dist/src/commands/analyze.js.map +1 -1
- package/dist/src/commands/autopilot.d.ts.map +1 -1
- package/dist/src/commands/autopilot.js +4 -89
- package/dist/src/commands/autopilot.js.map +1 -1
- package/dist/src/commands/browse.d.ts +1 -1
- package/dist/src/commands/cleanup.d.ts.map +1 -1
- package/dist/src/commands/cleanup.js +4 -2
- package/dist/src/commands/cleanup.js.map +1 -1
- package/dist/src/commands/completions.d.ts.map +1 -1
- package/dist/src/commands/completions.js +0 -1
- package/dist/src/commands/completions.js.map +1 -1
- package/dist/src/commands/config.js +7 -7
- package/dist/src/commands/config.js.map +1 -1
- package/dist/src/commands/doctor-project-checks.d.ts +7 -0
- package/dist/src/commands/doctor-project-checks.d.ts.map +1 -1
- package/dist/src/commands/doctor-project-checks.js +37 -5
- package/dist/src/commands/doctor-project-checks.js.map +1 -1
- package/dist/src/commands/doctor.d.ts.map +1 -1
- package/dist/src/commands/doctor.js +9 -3
- package/dist/src/commands/doctor.js.map +1 -1
- package/dist/src/commands/events.d.ts +9 -0
- package/dist/src/commands/events.d.ts.map +1 -0
- package/dist/src/commands/events.js +89 -0
- package/dist/src/commands/events.js.map +1 -0
- package/dist/src/commands/hooks-routing-commands.d.ts +1 -2
- package/dist/src/commands/hooks-routing-commands.d.ts.map +1 -1
- package/dist/src/commands/hooks-routing-commands.js +1 -101
- package/dist/src/commands/hooks-routing-commands.js.map +1 -1
- package/dist/src/commands/hooks-workers.d.ts.map +1 -1
- package/dist/src/commands/hooks-workers.js +19 -71
- package/dist/src/commands/hooks-workers.js.map +1 -1
- package/dist/src/commands/hooks.d.ts +1 -1
- package/dist/src/commands/hooks.d.ts.map +1 -1
- package/dist/src/commands/hooks.js +4 -7
- package/dist/src/commands/hooks.js.map +1 -1
- package/dist/src/commands/index.d.ts +2 -2
- package/dist/src/commands/index.d.ts.map +1 -1
- package/dist/src/commands/index.js +4 -3
- package/dist/src/commands/index.js.map +1 -1
- package/dist/src/commands/init-subcommands.d.ts.map +1 -1
- package/dist/src/commands/init-subcommands.js +4 -0
- package/dist/src/commands/init-subcommands.js.map +1 -1
- package/dist/src/commands/init-wizard.d.ts.map +1 -1
- package/dist/src/commands/init-wizard.js +0 -8
- package/dist/src/commands/init-wizard.js.map +1 -1
- package/dist/src/commands/init.d.ts.map +1 -1
- package/dist/src/commands/init.js +53 -23
- package/dist/src/commands/init.js.map +1 -1
- package/dist/src/commands/mcp.d.ts +1 -0
- package/dist/src/commands/mcp.d.ts.map +1 -1
- package/dist/src/commands/mcp.js +111 -60
- package/dist/src/commands/mcp.js.map +1 -1
- package/dist/src/commands/memory-crud.d.ts.map +1 -1
- package/dist/src/commands/memory-crud.js +33 -20
- package/dist/src/commands/memory-crud.js.map +1 -1
- package/dist/src/commands/monoswarm.d.ts +8 -0
- package/dist/src/commands/monoswarm.d.ts.map +1 -0
- package/dist/src/commands/{swarm.js → monoswarm.js} +83 -297
- package/dist/src/commands/monoswarm.js.map +1 -0
- package/dist/src/commands/neural-core.d.ts.map +1 -1
- package/dist/src/commands/neural-core.js +9 -1
- package/dist/src/commands/neural-core.js.map +1 -1
- package/dist/src/commands/neural-optimize.d.ts.map +1 -1
- package/dist/src/commands/neural-optimize.js +30 -110
- package/dist/src/commands/neural-optimize.js.map +1 -1
- package/dist/src/commands/neural-registry.d.ts +1 -2
- package/dist/src/commands/neural-registry.d.ts.map +1 -1
- package/dist/src/commands/neural-registry.js +21 -168
- package/dist/src/commands/neural-registry.js.map +1 -1
- package/dist/src/commands/org-observe.d.ts +34 -3
- package/dist/src/commands/org-observe.d.ts.map +1 -1
- package/dist/src/commands/org-observe.js +213 -45
- package/dist/src/commands/org-observe.js.map +1 -1
- package/dist/src/commands/org.d.ts +14 -0
- package/dist/src/commands/org.d.ts.map +1 -1
- package/dist/src/commands/org.js +118 -20
- package/dist/src/commands/org.js.map +1 -1
- package/dist/src/commands/performance.d.ts.map +1 -1
- package/dist/src/commands/performance.js +38 -31
- package/dist/src/commands/performance.js.map +1 -1
- package/dist/src/commands/security-misc.d.ts.map +1 -1
- package/dist/src/commands/security-misc.js +220 -90
- package/dist/src/commands/security-misc.js.map +1 -1
- package/dist/src/commands/security-scan.d.ts +13 -0
- package/dist/src/commands/security-scan.d.ts.map +1 -1
- package/dist/src/commands/security-scan.js +96 -27
- package/dist/src/commands/security-scan.js.map +1 -1
- package/dist/src/commands/security.js +1 -1
- package/dist/src/commands/security.js.map +1 -1
- package/dist/src/commands/start.d.ts.map +1 -1
- package/dist/src/commands/start.js +17 -96
- package/dist/src/commands/start.js.map +1 -1
- package/dist/src/commands/status.d.ts.map +1 -1
- package/dist/src/commands/status.js +72 -64
- package/dist/src/commands/status.js.map +1 -1
- package/dist/src/commands/tokens.d.ts.map +1 -1
- package/dist/src/commands/tokens.js +4 -5
- package/dist/src/commands/tokens.js.map +1 -1
- package/dist/src/consensus/audit-writer.d.ts +2 -2
- package/dist/src/consensus/audit-writer.d.ts.map +1 -1
- package/dist/src/consensus/audit-writer.js +1 -1
- package/dist/src/index.d.ts +2 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +12 -10
- package/dist/src/index.js.map +1 -1
- package/dist/src/init/claudemd-generator.d.ts.map +1 -1
- package/dist/src/init/claudemd-generator.js +32 -31
- package/dist/src/init/claudemd-generator.js.map +1 -1
- package/dist/src/init/codex-generator.d.ts +10 -0
- package/dist/src/init/codex-generator.d.ts.map +1 -0
- package/dist/src/init/codex-generator.js +67 -0
- package/dist/src/init/codex-generator.js.map +1 -0
- package/dist/src/init/copy-assets.d.ts.map +1 -1
- package/dist/src/init/copy-assets.js +4 -8
- package/dist/src/init/copy-assets.js.map +1 -1
- package/dist/src/init/executor.d.ts.map +1 -1
- package/dist/src/init/executor.js +9 -2
- package/dist/src/init/executor.js.map +1 -1
- package/dist/src/init/helpers-generator.js +1 -1
- package/dist/src/init/index.d.ts +1 -0
- package/dist/src/init/index.d.ts.map +1 -1
- package/dist/src/init/index.js +1 -0
- package/dist/src/init/index.js.map +1 -1
- package/dist/src/init/opencode-generator.js +2 -2
- package/dist/src/init/opencode-generator.js.map +1 -1
- package/dist/src/init/settings-generator.d.ts.map +1 -1
- package/dist/src/init/settings-generator.js +1 -2
- package/dist/src/init/settings-generator.js.map +1 -1
- package/dist/src/init/shared.d.ts.map +1 -1
- package/dist/src/init/shared.js +3 -7
- package/dist/src/init/shared.js.map +1 -1
- package/dist/src/init/statusline-generator.js +19 -19
- package/dist/src/init/types.d.ts +9 -10
- package/dist/src/init/types.d.ts.map +1 -1
- package/dist/src/init/types.js +8 -6
- package/dist/src/init/types.js.map +1 -1
- package/dist/src/init/upgrade.js +5 -5
- package/dist/src/init/upgrade.js.map +1 -1
- package/dist/src/init/write-capabilities.d.ts.map +1 -1
- package/dist/src/init/write-capabilities.js +36 -49
- package/dist/src/init/write-capabilities.js.map +1 -1
- package/dist/src/init/write-claude.js +1 -1
- package/dist/src/init/write-claude.js.map +1 -1
- package/dist/src/init/write-codex.d.ts +4 -0
- package/dist/src/init/write-codex.d.ts.map +1 -0
- package/dist/src/init/write-codex.js +57 -0
- package/dist/src/init/write-codex.js.map +1 -0
- package/dist/src/init/write-runtime-config.d.ts.map +1 -1
- package/dist/src/init/write-runtime-config.js +4 -5
- package/dist/src/init/write-runtime-config.js.map +1 -1
- package/dist/src/knowledge/eval/golden-set.js +15 -15
- package/dist/src/knowledge/eval/golden-set.js.map +1 -1
- package/dist/src/mcp-client.d.ts.map +1 -1
- package/dist/src/mcp-client.js +1 -2
- package/dist/src/mcp-client.js.map +1 -1
- package/dist/src/mcp-server.js +1 -1
- package/dist/src/mcp-server.js.map +1 -1
- package/dist/src/mcp-tools/agent-tools.d.ts +1 -1
- package/dist/src/mcp-tools/agent-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/agent-tools.js +3 -3
- package/dist/src/mcp-tools/agent-tools.js.map +1 -1
- package/dist/src/mcp-tools/autopilot-tools.d.ts +1 -1
- package/dist/src/mcp-tools/autopilot-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/autopilot-tools.js +4 -62
- package/dist/src/mcp-tools/autopilot-tools.js.map +1 -1
- package/dist/src/mcp-tools/guidance-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/guidance-tools.js +21 -31
- package/dist/src/mcp-tools/guidance-tools.js.map +1 -1
- package/dist/src/mcp-tools/hooks-intelligence.d.ts +0 -1
- package/dist/src/mcp-tools/hooks-intelligence.d.ts.map +1 -1
- package/dist/src/mcp-tools/hooks-intelligence.js +56 -103
- package/dist/src/mcp-tools/hooks-intelligence.js.map +1 -1
- package/dist/src/mcp-tools/hooks-routing.d.ts +1 -2
- package/dist/src/mcp-tools/hooks-routing.d.ts.map +1 -1
- package/dist/src/mcp-tools/hooks-routing.js +78 -152
- package/dist/src/mcp-tools/hooks-routing.js.map +1 -1
- package/dist/src/mcp-tools/hooks-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/hooks-tools.js +2 -4
- package/dist/src/mcp-tools/hooks-tools.js.map +1 -1
- package/dist/src/mcp-tools/index.d.ts +1 -2
- package/dist/src/mcp-tools/index.d.ts.map +1 -1
- package/dist/src/mcp-tools/index.js +1 -2
- package/dist/src/mcp-tools/index.js.map +1 -1
- package/dist/src/mcp-tools/memory-tools.js +10 -10
- package/dist/src/mcp-tools/memory-tools.js.map +1 -1
- package/dist/src/mcp-tools/monograph/query-tools.js +9 -9
- package/dist/src/mcp-tools/monograph/query-tools.js.map +1 -1
- package/dist/src/mcp-tools/monoswarm-tools.d.ts +17 -0
- package/dist/src/mcp-tools/monoswarm-tools.d.ts.map +1 -0
- package/dist/src/mcp-tools/monoswarm-tools.js +1153 -0
- package/dist/src/mcp-tools/monoswarm-tools.js.map +1 -0
- package/dist/src/mcp-tools/performance-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/performance-tools.js +32 -25
- package/dist/src/mcp-tools/performance-tools.js.map +1 -1
- package/dist/src/mcp-tools/system-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/system-tools.js +30 -13
- package/dist/src/mcp-tools/system-tools.js.map +1 -1
- package/dist/src/mcp-tools/transfer-tools.d.ts +8 -12
- package/dist/src/mcp-tools/transfer-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/transfer-tools.js +9 -13
- package/dist/src/mcp-tools/transfer-tools.js.map +1 -1
- package/dist/src/memory/embedding-operations.d.ts.map +1 -1
- package/dist/src/memory/embedding-operations.js +0 -37
- package/dist/src/memory/embedding-operations.js.map +1 -1
- package/dist/src/memory/hnsw-operations.d.ts +14 -74
- package/dist/src/memory/hnsw-operations.d.ts.map +1 -1
- package/dist/src/memory/hnsw-operations.js +22 -262
- package/dist/src/memory/hnsw-operations.js.map +1 -1
- 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 +8 -7
- package/dist/src/memory/intelligence.js.map +1 -1
- package/dist/src/memory/memory-bridge.d.ts +24 -24
- package/dist/src/memory/memory-bridge.d.ts.map +1 -1
- package/dist/src/memory/memory-bridge.js +33 -34
- package/dist/src/memory/memory-bridge.js.map +1 -1
- package/dist/src/memory/memory-crud.d.ts.map +1 -1
- package/dist/src/memory/memory-crud.js +0 -20
- package/dist/src/memory/memory-crud.js.map +1 -1
- package/dist/src/memory/memory-initializer.d.ts +2 -3
- package/dist/src/memory/memory-initializer.d.ts.map +1 -1
- package/dist/src/memory/memory-initializer.js +2 -3
- package/dist/src/memory/memory-initializer.js.map +1 -1
- package/dist/src/memory/memory-read.d.ts.map +1 -1
- package/dist/src/memory/memory-read.js +5 -14
- package/dist/src/memory/memory-read.js.map +1 -1
- package/dist/src/memory/sona-optimizer.d.ts +1 -1
- package/dist/src/memory/sona-optimizer.js +1 -1
- package/dist/src/monovector/model-outcomes.d.ts +25 -0
- package/dist/src/monovector/model-outcomes.d.ts.map +1 -0
- package/dist/src/monovector/model-outcomes.js +113 -0
- package/dist/src/monovector/model-outcomes.js.map +1 -0
- package/dist/src/orgrt/agent-runner.d.ts +8 -2
- package/dist/src/orgrt/agent-runner.d.ts.map +1 -1
- package/dist/src/orgrt/agent-runner.js.map +1 -1
- package/dist/src/orgrt/antigravity-runner.d.ts +25 -2
- package/dist/src/orgrt/antigravity-runner.d.ts.map +1 -1
- package/dist/src/orgrt/antigravity-runner.js +265 -124
- package/dist/src/orgrt/antigravity-runner.js.map +1 -1
- package/dist/src/orgrt/approvals.d.ts +16 -1
- package/dist/src/orgrt/approvals.d.ts.map +1 -1
- package/dist/src/orgrt/approvals.js +47 -2
- package/dist/src/orgrt/approvals.js.map +1 -1
- package/dist/src/orgrt/checkpoint-ops.d.ts +10 -16
- package/dist/src/orgrt/checkpoint-ops.d.ts.map +1 -1
- package/dist/src/orgrt/checkpoint-ops.js +12 -18
- package/dist/src/orgrt/checkpoint-ops.js.map +1 -1
- package/dist/src/orgrt/checkpoint.d.ts +12 -1
- package/dist/src/orgrt/checkpoint.d.ts.map +1 -1
- package/dist/src/orgrt/checkpoint.js +19 -3
- package/dist/src/orgrt/checkpoint.js.map +1 -1
- package/dist/src/orgrt/codex-runner.d.ts +26 -2
- package/dist/src/orgrt/codex-runner.d.ts.map +1 -1
- package/dist/src/orgrt/codex-runner.js +359 -128
- package/dist/src/orgrt/codex-runner.js.map +1 -1
- package/dist/src/orgrt/copilot-runner.d.ts +14 -0
- package/dist/src/orgrt/copilot-runner.d.ts.map +1 -0
- package/dist/src/orgrt/copilot-runner.js +260 -0
- package/dist/src/orgrt/copilot-runner.js.map +1 -0
- package/dist/src/orgrt/cross-org.d.ts.map +1 -1
- package/dist/src/orgrt/cross-org.js +11 -0
- package/dist/src/orgrt/cross-org.js.map +1 -1
- package/dist/src/orgrt/crush-runner.d.ts +27 -0
- package/dist/src/orgrt/crush-runner.d.ts.map +1 -0
- package/dist/src/orgrt/crush-runner.js +263 -0
- package/dist/src/orgrt/crush-runner.js.map +1 -0
- package/dist/src/orgrt/daemon.d.ts +68 -16
- package/dist/src/orgrt/daemon.d.ts.map +1 -1
- package/dist/src/orgrt/daemon.js +212 -29
- package/dist/src/orgrt/daemon.js.map +1 -1
- package/dist/src/orgrt/decisions.d.ts +1 -0
- package/dist/src/orgrt/decisions.d.ts.map +1 -1
- package/dist/src/orgrt/decisions.js +20 -0
- package/dist/src/orgrt/decisions.js.map +1 -1
- package/dist/src/orgrt/grok-runner.d.ts +18 -0
- package/dist/src/orgrt/grok-runner.d.ts.map +1 -0
- package/dist/src/orgrt/grok-runner.js +348 -0
- package/dist/src/orgrt/grok-runner.js.map +1 -0
- package/dist/src/orgrt/kimicode-runner.d.ts +53 -7
- package/dist/src/orgrt/kimicode-runner.d.ts.map +1 -1
- package/dist/src/orgrt/kimicode-runner.js +246 -144
- package/dist/src/orgrt/kimicode-runner.js.map +1 -1
- package/dist/src/orgrt/mailbox.d.ts +26 -1
- package/dist/src/orgrt/mailbox.d.ts.map +1 -1
- package/dist/src/orgrt/mailbox.js +74 -2
- package/dist/src/orgrt/mailbox.js.map +1 -1
- package/dist/src/orgrt/pi-rpc-runner.d.ts +68 -0
- package/dist/src/orgrt/pi-rpc-runner.d.ts.map +1 -0
- package/dist/src/orgrt/pi-rpc-runner.js +385 -0
- package/dist/src/orgrt/pi-rpc-runner.js.map +1 -0
- package/dist/src/orgrt/pi-runner.d.ts +16 -0
- package/dist/src/orgrt/pi-runner.d.ts.map +1 -0
- package/dist/src/orgrt/pi-runner.js +264 -0
- package/dist/src/orgrt/pi-runner.js.map +1 -0
- package/dist/src/orgrt/policy.d.ts +11 -0
- package/dist/src/orgrt/policy.d.ts.map +1 -1
- package/dist/src/orgrt/policy.js +25 -2
- package/dist/src/orgrt/policy.js.map +1 -1
- package/dist/src/orgrt/provider.d.ts +29 -1
- package/dist/src/orgrt/provider.d.ts.map +1 -1
- package/dist/src/orgrt/provider.js +62 -2
- package/dist/src/orgrt/provider.js.map +1 -1
- package/dist/src/orgrt/qwen-rpc-runner.d.ts +56 -0
- package/dist/src/orgrt/qwen-rpc-runner.d.ts.map +1 -0
- package/dist/src/orgrt/qwen-rpc-runner.js +346 -0
- package/dist/src/orgrt/qwen-rpc-runner.js.map +1 -0
- package/dist/src/orgrt/qwen-runner.d.ts +18 -0
- package/dist/src/orgrt/qwen-runner.d.ts.map +1 -0
- package/dist/src/orgrt/qwen-runner.js +270 -0
- package/dist/src/orgrt/qwen-runner.js.map +1 -0
- package/dist/src/orgrt/scheduler-integration.d.ts.map +1 -1
- package/dist/src/orgrt/scheduler-integration.js +7 -0
- package/dist/src/orgrt/scheduler-integration.js.map +1 -1
- package/dist/src/orgrt/session.d.ts +29 -1
- package/dist/src/orgrt/session.d.ts.map +1 -1
- package/dist/src/orgrt/session.js +87 -18
- package/dist/src/orgrt/session.js.map +1 -1
- package/dist/src/orgrt/task-dag.d.ts +29 -1
- package/dist/src/orgrt/task-dag.d.ts.map +1 -1
- package/dist/src/orgrt/task-dag.js +54 -0
- package/dist/src/orgrt/task-dag.js.map +1 -1
- package/dist/src/orgrt/test-loop.d.ts.map +1 -1
- package/dist/src/orgrt/test-loop.js +86 -9
- package/dist/src/orgrt/test-loop.js.map +1 -1
- package/dist/src/orgrt/tool-fence.d.ts.map +1 -1
- package/dist/src/orgrt/tool-fence.js +15 -0
- package/dist/src/orgrt/tool-fence.js.map +1 -1
- package/dist/src/orgrt/types.d.ts +50 -1
- package/dist/src/orgrt/types.d.ts.map +1 -1
- package/dist/src/orgrt/types.js +47 -4
- package/dist/src/orgrt/types.js.map +1 -1
- package/dist/src/orgrt/usage-proxy.d.ts +32 -0
- package/dist/src/orgrt/usage-proxy.d.ts.map +1 -0
- package/dist/src/orgrt/usage-proxy.js +226 -0
- package/dist/src/orgrt/usage-proxy.js.map +1 -0
- package/dist/src/pricing/model-pricing.d.ts.map +1 -1
- package/dist/src/pricing/model-pricing.js +0 -4
- package/dist/src/pricing/model-pricing.js.map +1 -1
- package/dist/src/security/audit-log.d.ts +47 -0
- package/dist/src/security/audit-log.d.ts.map +1 -0
- package/dist/src/security/audit-log.js +84 -0
- package/dist/src/security/audit-log.js.map +1 -0
- package/dist/src/services/config-file-manager.d.ts +2 -2
- package/dist/src/services/config-file-manager.d.ts.map +1 -1
- package/dist/src/services/config-file-manager.js +6 -7
- package/dist/src/services/config-file-manager.js.map +1 -1
- package/dist/src/suggest.d.ts.map +1 -1
- package/dist/src/suggest.js +4 -5
- package/dist/src/suggest.js.map +1 -1
- package/dist/src/transfer/anonymization/index.d.ts +1 -1
- package/dist/src/transfer/anonymization/index.js +1 -1
- package/dist/src/types.d.ts +3 -3
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/ui/collector.mjs +9 -13
- package/dist/src/ui/dashboard.html +93 -10
- package/dist/src/ui/data/agent-avatars.html +0 -12
- package/dist/src/ui/data/agent-avatars.json +10 -26
- package/dist/src/ui/orgs.html +8 -1
- package/dist/src/ui/routes-org.mjs +85 -16
- package/dist/src/ui/server.mjs +50 -23
- package/dist/src/utils/json-file.d.ts +12 -0
- package/dist/src/utils/json-file.d.ts.map +1 -1
- package/dist/src/utils/json-file.js +11 -0
- package/dist/src/utils/json-file.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -5
- package/.claude/agents/consensus/crdt-synchronizer.md +0 -977
- package/.claude/commands/hive-mind/README.md +0 -42
- package/.claude/commands/hive-mind/hive-mind-consensus.md +0 -72
- package/.claude/commands/hive-mind/hive-mind-init.md +0 -68
- package/.claude/commands/hive-mind/hive-mind-memory.md +0 -73
- package/.claude/commands/hive-mind/hive-mind-spawn.md +0 -82
- package/.claude/commands/hive-mind/hive-mind-status.md +0 -56
- package/.claude/commands/hive-mind/hive-mind-stop.md +0 -55
- package/.claude/commands/hive-mind/hive-mind.md +0 -87
- package/.claude/commands/swarm/README.md +0 -40
- package/.claude/commands/swarm/swarm.md +0 -79
- package/.claude/skills/hive-mind-advanced/SKILL.md +0 -347
- package/.claude/skills/swarm-advanced/SKILL.md +0 -936
- package/dist/src/commands/swarm.d.ts +0 -8
- package/dist/src/commands/swarm.d.ts.map +0 -1
- package/dist/src/commands/swarm.js.map +0 -1
- package/dist/src/mcp-tools/hive-mind-tools.d.ts +0 -17
- package/dist/src/mcp-tools/hive-mind-tools.d.ts.map +0 -1
- package/dist/src/mcp-tools/hive-mind-tools.js +0 -1239
- package/dist/src/mcp-tools/hive-mind-tools.js.map +0 -1
- package/dist/src/mcp-tools/swarm-tools.d.ts +0 -9
- package/dist/src/mcp-tools/swarm-tools.d.ts.map +0 -1
- package/dist/src/mcp-tools/swarm-tools.js +0 -411
- package/dist/src/mcp-tools/swarm-tools.js.map +0 -1
- package/dist/src/ui/data/avatars/crdt-synchronizer.svg +0 -53
- package/dist/src/ui/data/avatars/gossip-coordinator.svg +0 -54
- package/scripts/deploy-ipfs-node.sh +0 -153
- package/scripts/setup-ipfs-registry.md +0 -365
- /package/.claude/agents/{hive-mind → monoswarm}/scout-explorer.md +0 -0
- /package/.claude/agents/{hive-mind → monoswarm}/worker-specialist.md +0 -0
- /package/.claude/commands/{swarm → monoswarm}/analysis.md +0 -0
- /package/.claude/commands/{swarm → monoswarm}/development.md +0 -0
- /package/.claude/commands/{swarm → monoswarm}/examples.md +0 -0
- /package/.claude/commands/{swarm → monoswarm}/maintenance.md +0 -0
- /package/.claude/commands/{swarm → monoswarm}/optimization.md +0 -0
- /package/.claude/commands/{swarm → monoswarm}/testing.md +0 -0
- /package/dist/src/ui/data/avatars/{code-review-swarm.svg → monoswarm-code-review.svg} +0 -0
|
@@ -0,0 +1,1153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Monoswarm MCP Tools for CLI
|
|
3
|
+
*
|
|
4
|
+
* Merged replacement for the former swarm-tools.ts + hive-mind-tools.ts.
|
|
5
|
+
* Every tool here does one of two things: read/write a single JSON state
|
|
6
|
+
* file (`.monomind/monoswarm/state.json`), or tally votes already recorded
|
|
7
|
+
* in that file against a threshold. Nothing here starts a process, thread,
|
|
8
|
+
* or network connection — real concurrent work happens only when the caller
|
|
9
|
+
* separately dispatches subagents with Claude Code's Task tool.
|
|
10
|
+
*
|
|
11
|
+
* This is a clean break, not a migration: the old `.monomind/swarm/` and
|
|
12
|
+
* `.monomind/hive-mind/` state files are abandoned in place (a later cleanup
|
|
13
|
+
* phase purges them) rather than imported here.
|
|
14
|
+
*/
|
|
15
|
+
import { existsSync, readFileSync, statSync, writeFileSync, renameSync, mkdirSync } from 'node:fs';
|
|
16
|
+
import { randomBytes } from 'node:crypto';
|
|
17
|
+
import { join } from 'node:path';
|
|
18
|
+
import { getProjectCwd, getMonomindDataRoot } from './types.js';
|
|
19
|
+
import { agentTools, loadAgentStore, loadAgentStoreOrNull } from './agent-tools.js';
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
// State persistence — single file under the git-safe data root.
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
const MONOSWARM_DIR = 'monoswarm';
|
|
24
|
+
const MONOSWARM_STATE_FILE = 'state.json';
|
|
25
|
+
function getMonoswarmDir() {
|
|
26
|
+
return join(getMonomindDataRoot(), MONOSWARM_DIR);
|
|
27
|
+
}
|
|
28
|
+
function getMonoswarmStatePath() {
|
|
29
|
+
return join(getMonoswarmDir(), MONOSWARM_STATE_FILE);
|
|
30
|
+
}
|
|
31
|
+
function ensureMonoswarmDir() {
|
|
32
|
+
const dir = getMonoswarmDir();
|
|
33
|
+
if (!existsSync(dir)) {
|
|
34
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const MAX_MONOSWARM_STATE_BYTES = 10 * 1024 * 1024; // 10 MB
|
|
38
|
+
function defaultState() {
|
|
39
|
+
const now = new Date().toISOString();
|
|
40
|
+
return {
|
|
41
|
+
monoswarmId: '',
|
|
42
|
+
initialized: false,
|
|
43
|
+
topology: 'mesh',
|
|
44
|
+
maxAgents: 8,
|
|
45
|
+
status: 'initializing',
|
|
46
|
+
agents: [],
|
|
47
|
+
tasks: [],
|
|
48
|
+
config: {},
|
|
49
|
+
votes: { pending: [], history: [] },
|
|
50
|
+
sharedMemory: {},
|
|
51
|
+
notices: [],
|
|
52
|
+
createdAt: now,
|
|
53
|
+
updatedAt: now,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function loadMonoswarmState() {
|
|
57
|
+
try {
|
|
58
|
+
const path = getMonoswarmStatePath();
|
|
59
|
+
if (existsSync(path)) {
|
|
60
|
+
if (statSync(path).size > MAX_MONOSWARM_STATE_BYTES)
|
|
61
|
+
return defaultState();
|
|
62
|
+
return JSON.parse(readFileSync(path, 'utf-8'));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch (e) {
|
|
66
|
+
if (process.env.DEBUG || process.env.MONOMIND_DEBUG)
|
|
67
|
+
console.error('[monoswarm-tools] failed to parse state.json — resetting to default state:', e);
|
|
68
|
+
}
|
|
69
|
+
return defaultState();
|
|
70
|
+
}
|
|
71
|
+
function saveMonoswarmState(state) {
|
|
72
|
+
ensureMonoswarmDir();
|
|
73
|
+
state.updatedAt = new Date().toISOString();
|
|
74
|
+
const dest = getMonoswarmStatePath();
|
|
75
|
+
const tmp = `${dest}.${process.pid}.${Date.now()}.tmp`;
|
|
76
|
+
writeFileSync(tmp, JSON.stringify(state, null, 2), 'utf-8');
|
|
77
|
+
renameSync(tmp, dest);
|
|
78
|
+
}
|
|
79
|
+
const AUDIT_KEY_FILE = 'audit-key';
|
|
80
|
+
/**
|
|
81
|
+
* Resolve the HMAC signing key used for vote/audit records. Falls back to a
|
|
82
|
+
* per-project key generated once and persisted alongside the monoswarm
|
|
83
|
+
* state (kept out of state.json and never returned by any tool).
|
|
84
|
+
* MONOMIND_SESSION_SECRET still takes precedence for callers that want to
|
|
85
|
+
* manage/rotate the key themselves.
|
|
86
|
+
*/
|
|
87
|
+
function getOrCreateAuditKey() {
|
|
88
|
+
const envKey = process.env.MONOMIND_SESSION_SECRET;
|
|
89
|
+
if (envKey)
|
|
90
|
+
return envKey;
|
|
91
|
+
const path = join(getMonoswarmDir(), AUDIT_KEY_FILE);
|
|
92
|
+
try {
|
|
93
|
+
if (existsSync(path)) {
|
|
94
|
+
const existing = readFileSync(path, 'utf-8').trim();
|
|
95
|
+
if (existing)
|
|
96
|
+
return existing;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
catch { /* fall through to regeneration */ }
|
|
100
|
+
try {
|
|
101
|
+
ensureMonoswarmDir();
|
|
102
|
+
const key = randomBytes(32).toString('hex');
|
|
103
|
+
const tmp = `${path}.${process.pid}.${Date.now()}.tmp`;
|
|
104
|
+
writeFileSync(tmp, key, 'utf-8');
|
|
105
|
+
renameSync(tmp, path);
|
|
106
|
+
return key;
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
// Filesystem unavailable — fall back to an ephemeral in-process key.
|
|
110
|
+
return randomBytes(32).toString('hex');
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
function saveAgentStore(store) {
|
|
114
|
+
const storeDir = join(getMonomindDataRoot(), 'agents');
|
|
115
|
+
if (!existsSync(storeDir)) {
|
|
116
|
+
mkdirSync(storeDir, { recursive: true });
|
|
117
|
+
}
|
|
118
|
+
const dest = join(storeDir, 'store.json');
|
|
119
|
+
const tmp = `${dest}.${process.pid}.${Date.now()}.tmp`;
|
|
120
|
+
writeFileSync(tmp, JSON.stringify(store, null, 2), 'utf-8');
|
|
121
|
+
renameSync(tmp, dest);
|
|
122
|
+
}
|
|
123
|
+
const RESERVED_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
|
|
124
|
+
const VALID_TOPOLOGIES = new Set([
|
|
125
|
+
'hierarchical', 'mesh', 'hierarchical-mesh', 'ring', 'star', 'hybrid', 'adaptive',
|
|
126
|
+
]);
|
|
127
|
+
// ---------------------------------------------------------------------------
|
|
128
|
+
// Vote-threshold math
|
|
129
|
+
// ---------------------------------------------------------------------------
|
|
130
|
+
/** Calculate required votes for a given strategy and total voter count. */
|
|
131
|
+
function calculateRequiredVotes(strategy, totalVoters, minVotes) {
|
|
132
|
+
if (totalVoters <= 0)
|
|
133
|
+
return 1;
|
|
134
|
+
switch (strategy) {
|
|
135
|
+
case 'supermajority':
|
|
136
|
+
return Math.floor((totalVoters * 2) / 3) + 1;
|
|
137
|
+
case 'unanimous':
|
|
138
|
+
return totalVoters;
|
|
139
|
+
case 'threshold':
|
|
140
|
+
return Math.min(Math.max(1, minVotes ?? Math.floor(totalVoters / 2) + 1), totalVoters);
|
|
141
|
+
case 'majority':
|
|
142
|
+
default:
|
|
143
|
+
return Math.floor(totalVoters / 2) + 1;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Detect a voter who cast conflicting votes across proposals of the same
|
|
148
|
+
* type — a double-vote check, not real Byzantine fault detection.
|
|
149
|
+
*/
|
|
150
|
+
function detectDuplicateVotes(pending, currentProposal, voterId, newVote) {
|
|
151
|
+
for (const p of pending) {
|
|
152
|
+
if (p.proposalId === currentProposal.proposalId)
|
|
153
|
+
continue;
|
|
154
|
+
if (p.type !== currentProposal.type)
|
|
155
|
+
continue;
|
|
156
|
+
if (voterId in p.votes && p.votes[voterId] !== newVote) {
|
|
157
|
+
return true; // Conflicting vote detected
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Try to resolve a proposal based on its strategy. Returns 'approved',
|
|
164
|
+
* 'rejected', or null if still pending.
|
|
165
|
+
*/
|
|
166
|
+
function tryResolveProposal(proposal, totalVoters) {
|
|
167
|
+
const votesFor = Object.values(proposal.votes).filter(v => v).length;
|
|
168
|
+
const votesAgainst = Object.values(proposal.votes).filter(v => !v).length;
|
|
169
|
+
const required = calculateRequiredVotes(proposal.strategy, totalVoters, proposal.minVotes);
|
|
170
|
+
if (votesFor >= required)
|
|
171
|
+
return 'approved';
|
|
172
|
+
if (votesAgainst >= required)
|
|
173
|
+
return 'rejected';
|
|
174
|
+
if (proposal.strategy === 'unanimous' && votesAgainst > 0) {
|
|
175
|
+
return 'rejected';
|
|
176
|
+
}
|
|
177
|
+
const totalVotes = Object.keys(proposal.votes).length;
|
|
178
|
+
const remaining = totalVoters - totalVotes;
|
|
179
|
+
if (votesFor + remaining < required && votesAgainst + remaining < required) {
|
|
180
|
+
return 'rejected'; // Deadlock: neither side can win
|
|
181
|
+
}
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
// ---------------------------------------------------------------------------
|
|
185
|
+
// Tools
|
|
186
|
+
// ---------------------------------------------------------------------------
|
|
187
|
+
export const monoswarmTools = [
|
|
188
|
+
{
|
|
189
|
+
name: 'monoswarm_init',
|
|
190
|
+
description: 'Record a coordination topology, agent roster, and vote strategy in a JSON state file. Starts no process — agents are dispatched separately via Claude Code\'s Task tool.',
|
|
191
|
+
category: 'monoswarm',
|
|
192
|
+
inputSchema: {
|
|
193
|
+
type: 'object',
|
|
194
|
+
properties: {
|
|
195
|
+
topology: { type: 'string', description: 'Topology label (hierarchical, mesh, hierarchical-mesh, ring, star, hybrid, adaptive)' },
|
|
196
|
+
maxAgents: { type: 'number', description: 'Maximum number of agents (1-50)' },
|
|
197
|
+
strategy: { type: 'string', description: 'Agent role strategy (specialized, balanced, adaptive)' },
|
|
198
|
+
coordinatorId: { type: 'string', description: 'Initial coordinator agent ID (formerly "queen")' },
|
|
199
|
+
voteStrategy: { type: 'string', enum: ['majority', 'supermajority', 'unanimous', 'threshold'], description: 'Default vote strategy for monoswarm_vote. Default: majority.' },
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
handler: async (input) => {
|
|
203
|
+
const topology = input.topology || 'hierarchical-mesh';
|
|
204
|
+
const maxAgents = Math.min(Math.max(input.maxAgents || 8, 1), 50);
|
|
205
|
+
const MAX_FIELD_LEN = 256;
|
|
206
|
+
const rawStrategy = input.strategy || 'specialized';
|
|
207
|
+
const strategy = typeof rawStrategy === 'string' && rawStrategy.length > MAX_FIELD_LEN
|
|
208
|
+
? rawStrategy.slice(0, MAX_FIELD_LEN) : rawStrategy;
|
|
209
|
+
if (!VALID_TOPOLOGIES.has(topology)) {
|
|
210
|
+
return {
|
|
211
|
+
success: false,
|
|
212
|
+
error: `Invalid topology: ${topology}. Valid: ${[...VALID_TOPOLOGIES].join(', ')}`,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
const VALID_VOTE_STRATEGIES = ['majority', 'supermajority', 'unanimous', 'threshold'];
|
|
216
|
+
const rawVoteStrategy = input.voteStrategy || 'majority';
|
|
217
|
+
const voteStrategy = VALID_VOTE_STRATEGIES.includes(rawVoteStrategy)
|
|
218
|
+
? rawVoteStrategy
|
|
219
|
+
: 'majority';
|
|
220
|
+
const rawCoordinatorId = input.coordinatorId || undefined;
|
|
221
|
+
const coordinatorId = typeof rawCoordinatorId === 'string' && rawCoordinatorId.length > MAX_FIELD_LEN
|
|
222
|
+
? rawCoordinatorId.slice(0, MAX_FIELD_LEN) : rawCoordinatorId;
|
|
223
|
+
const monoswarmId = `monoswarm-${Date.now()}-${randomBytes(6).toString('hex')}`;
|
|
224
|
+
const now = new Date().toISOString();
|
|
225
|
+
const state = {
|
|
226
|
+
monoswarmId,
|
|
227
|
+
initialized: true,
|
|
228
|
+
topology,
|
|
229
|
+
maxAgents,
|
|
230
|
+
status: 'running',
|
|
231
|
+
agents: [],
|
|
232
|
+
coordinator: coordinatorId ? { agentId: coordinatorId, electedAt: now, term: 1 } : undefined,
|
|
233
|
+
tasks: [],
|
|
234
|
+
config: { topology, maxAgents, strategy },
|
|
235
|
+
voteStrategy,
|
|
236
|
+
votes: { pending: [], history: [] },
|
|
237
|
+
sharedMemory: {},
|
|
238
|
+
notices: [],
|
|
239
|
+
createdAt: now,
|
|
240
|
+
updatedAt: now,
|
|
241
|
+
};
|
|
242
|
+
saveMonoswarmState(state);
|
|
243
|
+
return {
|
|
244
|
+
success: true,
|
|
245
|
+
monoswarmId,
|
|
246
|
+
topology,
|
|
247
|
+
strategy,
|
|
248
|
+
maxAgents,
|
|
249
|
+
voteStrategy,
|
|
250
|
+
coordinatorId,
|
|
251
|
+
initializedAt: now,
|
|
252
|
+
config: state.config,
|
|
253
|
+
persisted: true,
|
|
254
|
+
};
|
|
255
|
+
},
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
name: 'monoswarm_status',
|
|
259
|
+
description: 'Read the merged coordination + vote state from the JSON state file — agent roster, topology, pending/resolved votes, shared memory key count.',
|
|
260
|
+
category: 'monoswarm',
|
|
261
|
+
inputSchema: {
|
|
262
|
+
type: 'object',
|
|
263
|
+
properties: {
|
|
264
|
+
verbose: { type: 'boolean', description: 'Include worker details, vote history, and shared memory contents' },
|
|
265
|
+
},
|
|
266
|
+
},
|
|
267
|
+
handler: async (input) => {
|
|
268
|
+
const state = loadMonoswarmState();
|
|
269
|
+
if (!state.initialized) {
|
|
270
|
+
return {
|
|
271
|
+
status: 'not_initialized',
|
|
272
|
+
message: 'No monoswarm state recorded. Use monoswarm_init to create one.',
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
const agentStore = loadAgentStore();
|
|
276
|
+
const uptime = state.createdAt ? Date.now() - new Date(state.createdAt).getTime() : 0;
|
|
277
|
+
let stateBytes = 0;
|
|
278
|
+
try {
|
|
279
|
+
const path = getMonoswarmStatePath();
|
|
280
|
+
if (existsSync(path))
|
|
281
|
+
stateBytes = statSync(path).size;
|
|
282
|
+
}
|
|
283
|
+
catch { /* best-effort */ }
|
|
284
|
+
const summary = {
|
|
285
|
+
monoswarmId: state.monoswarmId,
|
|
286
|
+
status: state.status,
|
|
287
|
+
topology: state.topology,
|
|
288
|
+
maxAgents: state.maxAgents,
|
|
289
|
+
agentCount: state.agents.length,
|
|
290
|
+
taskCount: state.tasks.length,
|
|
291
|
+
voteStrategy: state.voteStrategy ?? 'majority',
|
|
292
|
+
coordinator: state.coordinator ? {
|
|
293
|
+
agentId: state.coordinator.agentId,
|
|
294
|
+
electedAt: state.coordinator.electedAt,
|
|
295
|
+
term: state.coordinator.term,
|
|
296
|
+
} : undefined,
|
|
297
|
+
agents: state.agents.map(id => {
|
|
298
|
+
const agent = agentStore.agents[id];
|
|
299
|
+
return {
|
|
300
|
+
id,
|
|
301
|
+
type: agent?.agentType || 'worker',
|
|
302
|
+
status: agent?.status || 'unknown',
|
|
303
|
+
tasksCompleted: agent?.taskCount || 0,
|
|
304
|
+
};
|
|
305
|
+
}),
|
|
306
|
+
pendingVotes: state.votes.pending.length,
|
|
307
|
+
voteHistoryCount: state.votes.history.length,
|
|
308
|
+
sharedMemoryKeys: Object.keys(state.sharedMemory).length,
|
|
309
|
+
stateSize: `${Math.round(stateBytes / 1024)} KB`,
|
|
310
|
+
config: state.config,
|
|
311
|
+
uptime,
|
|
312
|
+
createdAt: state.createdAt,
|
|
313
|
+
updatedAt: state.updatedAt,
|
|
314
|
+
};
|
|
315
|
+
if (input.verbose) {
|
|
316
|
+
return {
|
|
317
|
+
...summary,
|
|
318
|
+
voteHistory: state.votes.history.slice(-10),
|
|
319
|
+
sharedMemory: state.sharedMemory,
|
|
320
|
+
notices: state.notices.slice(-10),
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
return summary;
|
|
324
|
+
},
|
|
325
|
+
},
|
|
326
|
+
{
|
|
327
|
+
name: 'monoswarm_scale',
|
|
328
|
+
description: 'Adjust the number of agent records in the roster to a target count by writing/removing bookkeeping entries in the state file. No process is started or stopped.',
|
|
329
|
+
category: 'monoswarm',
|
|
330
|
+
inputSchema: {
|
|
331
|
+
type: 'object',
|
|
332
|
+
properties: {
|
|
333
|
+
targetAgents: { type: 'number', description: 'Target number of agents' },
|
|
334
|
+
agentType: { type: 'string', description: 'Agent type for newly spawned agent records (default: worker)' },
|
|
335
|
+
},
|
|
336
|
+
required: ['targetAgents'],
|
|
337
|
+
},
|
|
338
|
+
handler: async (input) => {
|
|
339
|
+
const targetAgents = input.targetAgents;
|
|
340
|
+
const agentType = input.agentType || 'worker';
|
|
341
|
+
if (!Number.isFinite(targetAgents) || targetAgents < 0 || !Number.isInteger(targetAgents)) {
|
|
342
|
+
return { success: false, error: 'targetAgents must be a non-negative integer' };
|
|
343
|
+
}
|
|
344
|
+
const state = loadMonoswarmState();
|
|
345
|
+
if (!state.initialized) {
|
|
346
|
+
return { success: false, error: 'Monoswarm not initialized. Use monoswarm_init first.' };
|
|
347
|
+
}
|
|
348
|
+
const currentCount = state.agents.length;
|
|
349
|
+
const delta = targetAgents - currentCount;
|
|
350
|
+
const spawnTool = agentTools.find(t => t.name === 'agent_spawn');
|
|
351
|
+
const terminateTool = agentTools.find(t => t.name === 'agent_terminate');
|
|
352
|
+
const spawned = [];
|
|
353
|
+
const terminated = [];
|
|
354
|
+
if (delta > 0) {
|
|
355
|
+
for (let i = 0; i < delta; i++) {
|
|
356
|
+
const result = await spawnTool.handler({ agentType });
|
|
357
|
+
if (result.success && result.agentId) {
|
|
358
|
+
state.agents.push(result.agentId);
|
|
359
|
+
spawned.push(result.agentId);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
else if (delta < 0) {
|
|
364
|
+
const toRemove = state.agents.slice(0, -delta);
|
|
365
|
+
for (const agentId of toRemove) {
|
|
366
|
+
const result = await terminateTool.handler({ agentId });
|
|
367
|
+
if (result.success) {
|
|
368
|
+
terminated.push(agentId);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
state.agents = state.agents.filter(id => !terminated.includes(id));
|
|
372
|
+
}
|
|
373
|
+
state.maxAgents = Math.max(state.maxAgents, state.agents.length);
|
|
374
|
+
saveMonoswarmState(state);
|
|
375
|
+
const targetReached = state.agents.length === targetAgents;
|
|
376
|
+
return {
|
|
377
|
+
success: targetReached,
|
|
378
|
+
error: targetReached
|
|
379
|
+
? undefined
|
|
380
|
+
: `Reached ${state.agents.length}/${targetAgents} agents — some spawn/terminate operations failed`,
|
|
381
|
+
monoswarmId: state.monoswarmId,
|
|
382
|
+
previousCount: currentCount,
|
|
383
|
+
currentCount: state.agents.length,
|
|
384
|
+
targetAgents,
|
|
385
|
+
spawned,
|
|
386
|
+
terminated,
|
|
387
|
+
};
|
|
388
|
+
},
|
|
389
|
+
},
|
|
390
|
+
{
|
|
391
|
+
name: 'monoswarm_health',
|
|
392
|
+
description: 'Inspect the state file and agent roster and report a derived healthy/degraded status — no live process is polled.',
|
|
393
|
+
category: 'monoswarm',
|
|
394
|
+
inputSchema: {
|
|
395
|
+
type: 'object',
|
|
396
|
+
properties: {},
|
|
397
|
+
},
|
|
398
|
+
handler: async () => {
|
|
399
|
+
const state = loadMonoswarmState();
|
|
400
|
+
if (!state.initialized) {
|
|
401
|
+
return {
|
|
402
|
+
status: 'not_initialized',
|
|
403
|
+
healthy: false,
|
|
404
|
+
checks: [
|
|
405
|
+
{ name: 'monoswarm_exists', status: 'fail', message: 'No monoswarm state recorded' },
|
|
406
|
+
],
|
|
407
|
+
checkedAt: new Date().toISOString(),
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
const isRunning = state.status === 'running';
|
|
411
|
+
const stateFileExists = existsSync(getMonoswarmStatePath());
|
|
412
|
+
const checks = [
|
|
413
|
+
{ name: 'monoswarm_exists', status: 'ok', message: `Monoswarm ${state.monoswarmId} recorded` },
|
|
414
|
+
{
|
|
415
|
+
name: 'coordinator',
|
|
416
|
+
status: isRunning ? 'ok' : 'warn',
|
|
417
|
+
message: isRunning ? 'Status: running' : `Status: ${state.status}`,
|
|
418
|
+
},
|
|
419
|
+
{
|
|
420
|
+
name: 'agents',
|
|
421
|
+
status: state.agents.length > 0 ? 'ok' : 'info',
|
|
422
|
+
message: `${state.agents.length} agents registered (max: ${state.maxAgents})`,
|
|
423
|
+
},
|
|
424
|
+
{
|
|
425
|
+
name: 'persistence',
|
|
426
|
+
status: stateFileExists ? 'ok' : 'warn',
|
|
427
|
+
message: stateFileExists ? 'State file persisted' : 'State file missing',
|
|
428
|
+
},
|
|
429
|
+
{
|
|
430
|
+
name: 'topology',
|
|
431
|
+
status: 'ok',
|
|
432
|
+
message: `Topology: ${state.topology}`,
|
|
433
|
+
},
|
|
434
|
+
];
|
|
435
|
+
const healthy = isRunning && stateFileExists;
|
|
436
|
+
return {
|
|
437
|
+
status: healthy ? 'healthy' : 'degraded',
|
|
438
|
+
healthy,
|
|
439
|
+
monoswarmId: state.monoswarmId,
|
|
440
|
+
topology: state.topology,
|
|
441
|
+
agentCount: state.agents.length,
|
|
442
|
+
checks,
|
|
443
|
+
checkedAt: new Date().toISOString(),
|
|
444
|
+
};
|
|
445
|
+
},
|
|
446
|
+
},
|
|
447
|
+
{
|
|
448
|
+
name: 'monoswarm_shutdown',
|
|
449
|
+
description: 'Mark the state file terminated and remove roster agents from the agent store. No process is stopped because none was started.',
|
|
450
|
+
category: 'monoswarm',
|
|
451
|
+
inputSchema: {
|
|
452
|
+
type: 'object',
|
|
453
|
+
properties: {
|
|
454
|
+
graceful: { type: 'boolean', description: 'Refuse to shut down while votes are pending unless force is set (default: true)' },
|
|
455
|
+
force: { type: 'boolean', description: 'Force immediate shutdown even with pending votes' },
|
|
456
|
+
},
|
|
457
|
+
},
|
|
458
|
+
handler: async (input) => {
|
|
459
|
+
const state = loadMonoswarmState();
|
|
460
|
+
if (!state.initialized) {
|
|
461
|
+
return { success: false, error: 'Monoswarm not initialized or already shut down' };
|
|
462
|
+
}
|
|
463
|
+
if (state.status === 'terminated') {
|
|
464
|
+
return { success: false, monoswarmId: state.monoswarmId, error: 'Monoswarm already terminated' };
|
|
465
|
+
}
|
|
466
|
+
const graceful = input.graceful !== false;
|
|
467
|
+
const force = input.force === true;
|
|
468
|
+
const pendingVotes = state.votes.pending.length;
|
|
469
|
+
if (graceful && pendingVotes > 0 && !force) {
|
|
470
|
+
return {
|
|
471
|
+
success: false,
|
|
472
|
+
error: `Cannot gracefully shut down with ${pendingVotes} pending vote(s). Use force: true to override.`,
|
|
473
|
+
pendingVotes,
|
|
474
|
+
agentCount: state.agents.length,
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
// Clear roster agents from the agent store. Must use the null-aware
|
|
478
|
+
// loader here (this handler mutates and saves) — loadAgentStore() on a
|
|
479
|
+
// corrupt/oversized store.json returns the empty default, and saving
|
|
480
|
+
// that back would wipe every real agent, not just this roster.
|
|
481
|
+
const agentStore = loadAgentStoreOrNull();
|
|
482
|
+
if (!agentStore) {
|
|
483
|
+
return { success: false, error: 'Agent store is unreadable/corrupt — refusing to shut down to avoid overwriting real agent data.', pendingVotes, agentCount: state.agents.length };
|
|
484
|
+
}
|
|
485
|
+
for (const agentId of state.agents) {
|
|
486
|
+
if (agentStore.agents[agentId])
|
|
487
|
+
delete agentStore.agents[agentId];
|
|
488
|
+
}
|
|
489
|
+
saveAgentStore(agentStore);
|
|
490
|
+
const shutdownTime = new Date().toISOString();
|
|
491
|
+
const agentsTerminated = state.agents.length;
|
|
492
|
+
const previousCoordinator = state.coordinator?.agentId;
|
|
493
|
+
state.status = 'terminated';
|
|
494
|
+
state.initialized = false;
|
|
495
|
+
state.coordinator = undefined;
|
|
496
|
+
state.agents = [];
|
|
497
|
+
state.votes.pending = [];
|
|
498
|
+
state.sharedMemory = {};
|
|
499
|
+
saveMonoswarmState(state);
|
|
500
|
+
return {
|
|
501
|
+
success: true,
|
|
502
|
+
monoswarmId: state.monoswarmId,
|
|
503
|
+
terminated: true,
|
|
504
|
+
graceful,
|
|
505
|
+
agentsTerminated,
|
|
506
|
+
previousCoordinator,
|
|
507
|
+
votesCleared: pendingVotes,
|
|
508
|
+
terminatedAt: shutdownTime,
|
|
509
|
+
};
|
|
510
|
+
},
|
|
511
|
+
},
|
|
512
|
+
{
|
|
513
|
+
name: 'monoswarm_agent_add',
|
|
514
|
+
description: 'Add an agent record (id, role) to the roster in the state file, and write a matching record into the agent store. Starts nothing.',
|
|
515
|
+
category: 'monoswarm',
|
|
516
|
+
inputSchema: {
|
|
517
|
+
type: 'object',
|
|
518
|
+
properties: {
|
|
519
|
+
count: { type: 'number', description: 'Number of agent records to add (default: 1)', default: 1 },
|
|
520
|
+
role: { type: 'string', enum: ['worker', 'specialist', 'scout'], description: 'Agent role', default: 'worker' },
|
|
521
|
+
agentType: { type: 'string', description: 'Agent type for added agents', default: 'worker' },
|
|
522
|
+
prefix: { type: 'string', description: 'Prefix for agent IDs', default: 'monoswarm-agent' },
|
|
523
|
+
},
|
|
524
|
+
},
|
|
525
|
+
handler: async (input) => {
|
|
526
|
+
const state = loadMonoswarmState();
|
|
527
|
+
if (!state.initialized) {
|
|
528
|
+
return { success: false, error: 'Monoswarm not initialized. Run monoswarm_init first.' };
|
|
529
|
+
}
|
|
530
|
+
const count = Math.min(Math.max(1, input.count || 1), 20);
|
|
531
|
+
const MAX_ROLE_LEN = 256;
|
|
532
|
+
const MAX_PREFIX_LEN = 128;
|
|
533
|
+
const rawRole = input.role || 'worker';
|
|
534
|
+
const role = typeof rawRole === 'string' && rawRole.length > MAX_ROLE_LEN
|
|
535
|
+
? rawRole.slice(0, MAX_ROLE_LEN) : rawRole;
|
|
536
|
+
const rawAgentType = input.agentType || 'worker';
|
|
537
|
+
const agentType = typeof rawAgentType === 'string' && rawAgentType.length > MAX_ROLE_LEN
|
|
538
|
+
? rawAgentType.slice(0, MAX_ROLE_LEN) : rawAgentType;
|
|
539
|
+
const rawPrefix = input.prefix || 'monoswarm-agent';
|
|
540
|
+
const prefix = typeof rawPrefix === 'string' && rawPrefix.length > MAX_PREFIX_LEN
|
|
541
|
+
? rawPrefix.slice(0, MAX_PREFIX_LEN) : rawPrefix;
|
|
542
|
+
const agentStore = loadAgentStoreOrNull();
|
|
543
|
+
if (!agentStore) {
|
|
544
|
+
return { success: false, error: 'Agent store is unreadable/corrupt — refusing to add agents to avoid overwriting real agent data.' };
|
|
545
|
+
}
|
|
546
|
+
const added = [];
|
|
547
|
+
for (let i = 0; i < count; i++) {
|
|
548
|
+
const agentId = `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
|
|
549
|
+
if (RESERVED_KEYS.has(agentId))
|
|
550
|
+
continue;
|
|
551
|
+
agentStore.agents[agentId] = {
|
|
552
|
+
agentId,
|
|
553
|
+
agentType,
|
|
554
|
+
status: 'idle',
|
|
555
|
+
health: 1.0,
|
|
556
|
+
taskCount: 0,
|
|
557
|
+
config: { role },
|
|
558
|
+
createdAt: new Date().toISOString(),
|
|
559
|
+
domain: 'monoswarm',
|
|
560
|
+
};
|
|
561
|
+
const MAX_AGENTS = 100;
|
|
562
|
+
if (!state.agents.includes(agentId)) {
|
|
563
|
+
if (state.agents.length >= MAX_AGENTS) {
|
|
564
|
+
return { success: false, error: `Monoswarm has reached max agent capacity (${MAX_AGENTS})` };
|
|
565
|
+
}
|
|
566
|
+
state.agents.push(agentId);
|
|
567
|
+
}
|
|
568
|
+
added.push({ agentId, role, joinedAt: new Date().toISOString() });
|
|
569
|
+
}
|
|
570
|
+
saveAgentStore(agentStore);
|
|
571
|
+
saveMonoswarmState(state);
|
|
572
|
+
return {
|
|
573
|
+
success: true,
|
|
574
|
+
added: count,
|
|
575
|
+
agents: added,
|
|
576
|
+
totalAgents: state.agents.length,
|
|
577
|
+
message: `Added ${count} agent record(s) to the roster`,
|
|
578
|
+
};
|
|
579
|
+
},
|
|
580
|
+
},
|
|
581
|
+
{
|
|
582
|
+
name: 'monoswarm_join',
|
|
583
|
+
description: 'Append an agent id to the roster array in the state file. No membership handshake occurs — this is a list append.',
|
|
584
|
+
category: 'monoswarm',
|
|
585
|
+
inputSchema: {
|
|
586
|
+
type: 'object',
|
|
587
|
+
properties: {
|
|
588
|
+
agentId: { type: 'string', description: 'Agent ID to add to the roster' },
|
|
589
|
+
role: { type: 'string', enum: ['worker', 'specialist', 'scout'], description: 'Agent role' },
|
|
590
|
+
},
|
|
591
|
+
required: ['agentId'],
|
|
592
|
+
},
|
|
593
|
+
handler: async (input) => {
|
|
594
|
+
const state = loadMonoswarmState();
|
|
595
|
+
const agentId = input.agentId;
|
|
596
|
+
if (typeof agentId !== 'string' || agentId.length === 0 || agentId.length > 128 ||
|
|
597
|
+
RESERVED_KEYS.has(agentId) || !/^[a-zA-Z0-9_-]+$/.test(agentId)) {
|
|
598
|
+
return { success: false, error: 'Invalid agentId' };
|
|
599
|
+
}
|
|
600
|
+
if (!state.initialized) {
|
|
601
|
+
return { success: false, error: 'Monoswarm not initialized' };
|
|
602
|
+
}
|
|
603
|
+
const MAX_AGENTS = 100;
|
|
604
|
+
if (!state.agents.includes(agentId)) {
|
|
605
|
+
if (state.agents.length >= MAX_AGENTS) {
|
|
606
|
+
return { success: false, error: `Monoswarm has reached max agent capacity (${MAX_AGENTS})` };
|
|
607
|
+
}
|
|
608
|
+
state.agents.push(agentId);
|
|
609
|
+
saveMonoswarmState(state);
|
|
610
|
+
}
|
|
611
|
+
return {
|
|
612
|
+
success: true,
|
|
613
|
+
agentId,
|
|
614
|
+
role: input.role || 'worker',
|
|
615
|
+
totalAgents: state.agents.length,
|
|
616
|
+
joinedAt: new Date().toISOString(),
|
|
617
|
+
};
|
|
618
|
+
},
|
|
619
|
+
},
|
|
620
|
+
{
|
|
621
|
+
name: 'monoswarm_leave',
|
|
622
|
+
description: 'Remove an agent id from the roster array in the state file.',
|
|
623
|
+
category: 'monoswarm',
|
|
624
|
+
inputSchema: {
|
|
625
|
+
type: 'object',
|
|
626
|
+
properties: {
|
|
627
|
+
agentId: { type: 'string', description: 'Agent ID to remove' },
|
|
628
|
+
},
|
|
629
|
+
required: ['agentId'],
|
|
630
|
+
},
|
|
631
|
+
handler: async (input) => {
|
|
632
|
+
const state = loadMonoswarmState();
|
|
633
|
+
const agentId = input.agentId;
|
|
634
|
+
if (typeof agentId !== 'string' || agentId.length === 0 || agentId.length > 128 ||
|
|
635
|
+
RESERVED_KEYS.has(agentId) || !/^[a-zA-Z0-9_-]+$/.test(agentId)) {
|
|
636
|
+
return { success: false, error: 'Invalid agentId' };
|
|
637
|
+
}
|
|
638
|
+
const index = state.agents.indexOf(agentId);
|
|
639
|
+
if (index > -1) {
|
|
640
|
+
state.agents.splice(index, 1);
|
|
641
|
+
saveMonoswarmState(state);
|
|
642
|
+
return {
|
|
643
|
+
success: true,
|
|
644
|
+
agentId,
|
|
645
|
+
leftAt: new Date().toISOString(),
|
|
646
|
+
remainingAgents: state.agents.length,
|
|
647
|
+
};
|
|
648
|
+
}
|
|
649
|
+
return { success: false, agentId, error: 'Agent not in roster' };
|
|
650
|
+
},
|
|
651
|
+
},
|
|
652
|
+
{
|
|
653
|
+
name: 'monoswarm_vote',
|
|
654
|
+
description: 'Create or vote on a proposal; passes when the vote count meets the chosen strategy\'s threshold (majority / supermajority / unanimous / a custom threshold) — single in-process tally, not a distributed consensus protocol.',
|
|
655
|
+
category: 'monoswarm',
|
|
656
|
+
inputSchema: {
|
|
657
|
+
type: 'object',
|
|
658
|
+
properties: {
|
|
659
|
+
action: { type: 'string', enum: ['propose', 'vote', 'status', 'list'], description: 'Vote action' },
|
|
660
|
+
proposalId: { type: 'string', description: 'Proposal ID (for vote/status)' },
|
|
661
|
+
type: { type: 'string', description: 'Proposal type (for propose)' },
|
|
662
|
+
value: { description: 'Proposal value (for propose)' },
|
|
663
|
+
vote: { type: 'boolean', description: 'Vote (true=for, false=against)' },
|
|
664
|
+
voterId: { type: 'string', description: 'Voter agent ID' },
|
|
665
|
+
strategy: { type: 'string', enum: ['majority', 'supermajority', 'unanimous', 'threshold'], description: 'Vote strategy (default: the strategy chosen at monoswarm_init, else majority)' },
|
|
666
|
+
minVotes: { type: 'number', description: 'Explicit vote count required (for threshold strategy)' },
|
|
667
|
+
minDivergenceRounds: { type: 'number', description: 'Anti-groupthink delay: minimum rounds with divergent votes required before resolution. Default: 0 (disabled).' },
|
|
668
|
+
},
|
|
669
|
+
required: ['action'],
|
|
670
|
+
},
|
|
671
|
+
handler: async (input) => {
|
|
672
|
+
const state = loadMonoswarmState();
|
|
673
|
+
const action = input.action;
|
|
674
|
+
const rawStrategy = input.strategy || state.voteStrategy || 'majority';
|
|
675
|
+
const VALID_STRATEGIES = ['majority', 'supermajority', 'unanimous', 'threshold'];
|
|
676
|
+
if (!VALID_STRATEGIES.includes(rawStrategy)) {
|
|
677
|
+
return {
|
|
678
|
+
action,
|
|
679
|
+
error: `Unknown strategy "${rawStrategy}". Available strategies: ${VALID_STRATEGIES.join(', ')}.`,
|
|
680
|
+
availableStrategies: VALID_STRATEGIES,
|
|
681
|
+
};
|
|
682
|
+
}
|
|
683
|
+
const strategy = rawStrategy;
|
|
684
|
+
const totalVoters = state.agents.length;
|
|
685
|
+
if (action === 'propose') {
|
|
686
|
+
const proposalId = `proposal-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
687
|
+
const minVotes = strategy === 'threshold' ? input.minVotes : undefined;
|
|
688
|
+
const required = calculateRequiredVotes(strategy, totalVoters, minVotes);
|
|
689
|
+
const minDivergenceRounds = typeof input.minDivergenceRounds === 'number'
|
|
690
|
+
? Math.max(0, input.minDivergenceRounds)
|
|
691
|
+
: 0;
|
|
692
|
+
const MAX_TYPE_LEN = 128;
|
|
693
|
+
const MAX_VOTER_ID_LEN = 256;
|
|
694
|
+
const MAX_VALUE_BYTES = 64 * 1024;
|
|
695
|
+
const rawType = input.type || 'general';
|
|
696
|
+
const proposalType = typeof rawType === 'string' && rawType.length > MAX_TYPE_LEN
|
|
697
|
+
? rawType.slice(0, MAX_TYPE_LEN) : rawType;
|
|
698
|
+
const rawVoterId = input.voterId || 'system';
|
|
699
|
+
const proposedBy = typeof rawVoterId === 'string' && rawVoterId.length > MAX_VOTER_ID_LEN
|
|
700
|
+
? rawVoterId.slice(0, MAX_VOTER_ID_LEN) : rawVoterId;
|
|
701
|
+
const rawValue = input.value;
|
|
702
|
+
const cappedValue = typeof rawValue === 'string' && rawValue.length > MAX_VALUE_BYTES
|
|
703
|
+
? rawValue.slice(0, MAX_VALUE_BYTES) : rawValue;
|
|
704
|
+
const proposal = {
|
|
705
|
+
proposalId,
|
|
706
|
+
type: proposalType,
|
|
707
|
+
value: cappedValue,
|
|
708
|
+
proposedBy,
|
|
709
|
+
proposedAt: new Date().toISOString(),
|
|
710
|
+
votes: {},
|
|
711
|
+
status: 'pending',
|
|
712
|
+
strategy,
|
|
713
|
+
minVotes: strategy === 'threshold' ? required : undefined,
|
|
714
|
+
duplicateVoters: undefined,
|
|
715
|
+
minDivergenceRounds: minDivergenceRounds > 0 ? minDivergenceRounds : undefined,
|
|
716
|
+
divergenceRoundsSeen: 0,
|
|
717
|
+
};
|
|
718
|
+
state.votes.pending.push(proposal);
|
|
719
|
+
saveMonoswarmState(state);
|
|
720
|
+
return {
|
|
721
|
+
action,
|
|
722
|
+
proposalId,
|
|
723
|
+
type: proposal.type,
|
|
724
|
+
strategy,
|
|
725
|
+
status: 'pending',
|
|
726
|
+
required,
|
|
727
|
+
totalVoters,
|
|
728
|
+
minVotes: proposal.minVotes,
|
|
729
|
+
minDivergenceRounds: proposal.minDivergenceRounds,
|
|
730
|
+
};
|
|
731
|
+
}
|
|
732
|
+
if (action === 'vote') {
|
|
733
|
+
const proposal = state.votes.pending.find(p => p.proposalId === input.proposalId);
|
|
734
|
+
if (!proposal) {
|
|
735
|
+
return { action, error: 'Proposal not found or already resolved' };
|
|
736
|
+
}
|
|
737
|
+
const voterId = input.voterId;
|
|
738
|
+
if (!voterId) {
|
|
739
|
+
return { action, error: 'voterId is required for voting' };
|
|
740
|
+
}
|
|
741
|
+
if (totalVoters === 0) {
|
|
742
|
+
return { action, error: 'No agents in roster — cannot vote' };
|
|
743
|
+
}
|
|
744
|
+
if (!state.agents.includes(voterId)) {
|
|
745
|
+
return { action, error: `Voter ${voterId} is not a member of this roster` };
|
|
746
|
+
}
|
|
747
|
+
const voteValue = input.vote;
|
|
748
|
+
const proposalStrategy = proposal.strategy || 'majority';
|
|
749
|
+
const required = calculateRequiredVotes(proposalStrategy, totalVoters, proposal.minVotes);
|
|
750
|
+
if (voterId in proposal.votes) {
|
|
751
|
+
const previousVote = proposal.votes[voterId];
|
|
752
|
+
if (previousVote === voteValue) {
|
|
753
|
+
return {
|
|
754
|
+
action,
|
|
755
|
+
error: `Voter ${voterId} has already cast the same vote on this proposal`,
|
|
756
|
+
proposalId: proposal.proposalId,
|
|
757
|
+
existingVote: previousVote,
|
|
758
|
+
};
|
|
759
|
+
}
|
|
760
|
+
// Conflicting vote from the same voter — flag it and drop the vote.
|
|
761
|
+
if (!proposal.duplicateVoters)
|
|
762
|
+
proposal.duplicateVoters = [];
|
|
763
|
+
if (!proposal.duplicateVoters.includes(voterId)) {
|
|
764
|
+
proposal.duplicateVoters.push(voterId);
|
|
765
|
+
}
|
|
766
|
+
delete proposal.votes[voterId];
|
|
767
|
+
saveMonoswarmState(state);
|
|
768
|
+
return {
|
|
769
|
+
action,
|
|
770
|
+
proposalId: proposal.proposalId,
|
|
771
|
+
voterId,
|
|
772
|
+
duplicateVoteDetected: true,
|
|
773
|
+
message: `Voter ${voterId} attempted a conflicting vote. Previous vote invalidated.`,
|
|
774
|
+
duplicateVoters: proposal.duplicateVoters,
|
|
775
|
+
status: proposal.status,
|
|
776
|
+
};
|
|
777
|
+
}
|
|
778
|
+
// Cross-proposal duplicate-vote check (same voter, same proposal type, conflicting votes).
|
|
779
|
+
const isDuplicate = detectDuplicateVotes(state.votes.pending, proposal, voterId, voteValue);
|
|
780
|
+
if (isDuplicate) {
|
|
781
|
+
if (!proposal.duplicateVoters)
|
|
782
|
+
proposal.duplicateVoters = [];
|
|
783
|
+
if (!proposal.duplicateVoters.includes(voterId)) {
|
|
784
|
+
proposal.duplicateVoters.push(voterId);
|
|
785
|
+
}
|
|
786
|
+
saveMonoswarmState(state);
|
|
787
|
+
return {
|
|
788
|
+
action,
|
|
789
|
+
proposalId: proposal.proposalId,
|
|
790
|
+
voterId,
|
|
791
|
+
duplicateVoteDetected: true,
|
|
792
|
+
message: `Voter ${voterId} cast conflicting votes across proposals of the same type. Vote rejected.`,
|
|
793
|
+
duplicateVoters: proposal.duplicateVoters,
|
|
794
|
+
status: proposal.status,
|
|
795
|
+
};
|
|
796
|
+
}
|
|
797
|
+
proposal.votes[voterId] = voteValue;
|
|
798
|
+
const votesFor = Object.values(proposal.votes).filter(v => v).length;
|
|
799
|
+
const votesAgainst = Object.values(proposal.votes).filter(v => !v).length;
|
|
800
|
+
const allVotes = Object.values(proposal.votes);
|
|
801
|
+
const isUnanimous = allVotes.every(v => v) || allVotes.every(v => !v);
|
|
802
|
+
if (!isUnanimous && allVotes.length >= 2) {
|
|
803
|
+
proposal.divergenceRoundsSeen = (proposal.divergenceRoundsSeen ?? 0) + 1;
|
|
804
|
+
}
|
|
805
|
+
const totalVotesCast = Object.keys(proposal.votes).length;
|
|
806
|
+
const electorateExhausted = totalVoters > 0 && totalVotesCast >= totalVoters;
|
|
807
|
+
const divergenceGateOpen = !proposal.minDivergenceRounds
|
|
808
|
+
|| (proposal.divergenceRoundsSeen ?? 0) >= proposal.minDivergenceRounds
|
|
809
|
+
|| electorateExhausted;
|
|
810
|
+
const resolution = divergenceGateOpen ? tryResolveProposal(proposal, totalVoters) : null;
|
|
811
|
+
let resolved = false;
|
|
812
|
+
if (resolution !== null) {
|
|
813
|
+
resolved = true;
|
|
814
|
+
proposal.status = resolution;
|
|
815
|
+
state.votes.history.push({
|
|
816
|
+
proposalId: proposal.proposalId,
|
|
817
|
+
type: proposal.type,
|
|
818
|
+
result: resolution,
|
|
819
|
+
votes: { for: votesFor, against: votesAgainst },
|
|
820
|
+
decidedAt: new Date().toISOString(),
|
|
821
|
+
strategy: proposalStrategy,
|
|
822
|
+
duplicateVotersDetected: proposal.duplicateVoters?.length ? proposal.duplicateVoters : undefined,
|
|
823
|
+
});
|
|
824
|
+
if (state.votes.history.length > 1000) {
|
|
825
|
+
state.votes.history = state.votes.history.slice(-1000);
|
|
826
|
+
}
|
|
827
|
+
state.votes.pending = state.votes.pending.filter(p => p.proposalId !== proposal.proposalId);
|
|
828
|
+
}
|
|
829
|
+
saveMonoswarmState(state);
|
|
830
|
+
if (resolved) {
|
|
831
|
+
try {
|
|
832
|
+
const bridge = await import('../memory/memory-bridge.js');
|
|
833
|
+
await bridge.bridgeStoreEntry({
|
|
834
|
+
key: `monoswarm-vote-${proposal.proposalId}`,
|
|
835
|
+
value: JSON.stringify({
|
|
836
|
+
proposalId: proposal.proposalId,
|
|
837
|
+
type: proposal.type,
|
|
838
|
+
strategy: proposalStrategy,
|
|
839
|
+
status: proposal.status,
|
|
840
|
+
votes: proposal.votes,
|
|
841
|
+
resolvedAt: new Date().toISOString(),
|
|
842
|
+
}),
|
|
843
|
+
namespace: 'monoswarm-votes',
|
|
844
|
+
tags: [proposal.type, proposalStrategy, proposal.status],
|
|
845
|
+
});
|
|
846
|
+
}
|
|
847
|
+
catch { /* SQLite memory backend not available — JSON store is primary */ }
|
|
848
|
+
const hk = getOrCreateAuditKey();
|
|
849
|
+
try {
|
|
850
|
+
const { AuditWriter } = await import('../consensus/audit-writer.js');
|
|
851
|
+
const auditDir = join(getProjectCwd(), '.monomind', 'consensus');
|
|
852
|
+
const writer = new AuditWriter(auditDir);
|
|
853
|
+
const now = new Date().toISOString();
|
|
854
|
+
const voteEntries = Object.entries(proposal.votes).map(([agentId, vote]) => ({
|
|
855
|
+
agentId,
|
|
856
|
+
agentSlug: agentId,
|
|
857
|
+
vote,
|
|
858
|
+
votedAt: now,
|
|
859
|
+
}));
|
|
860
|
+
writer.record({
|
|
861
|
+
decisionId: proposal.proposalId,
|
|
862
|
+
swarmId: state.monoswarmId,
|
|
863
|
+
protocol: proposalStrategy,
|
|
864
|
+
topic: proposal.type,
|
|
865
|
+
decision: resolution,
|
|
866
|
+
votes: voteEntries,
|
|
867
|
+
quorumRequired: required,
|
|
868
|
+
quorumThreshold: required / Math.max(totalVoters, 1),
|
|
869
|
+
round: (proposal.divergenceRoundsSeen ?? 0) + 1,
|
|
870
|
+
startedAt: proposal.proposedAt,
|
|
871
|
+
completedAt: now,
|
|
872
|
+
sessionSecret: hk,
|
|
873
|
+
});
|
|
874
|
+
}
|
|
875
|
+
catch (e) {
|
|
876
|
+
if (process.env.MONOMIND_LOG_LEVEL === 'debug') {
|
|
877
|
+
process.stderr.write(`[monoswarm-vote] Audit write failed: ${e.message}\n`);
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
return {
|
|
882
|
+
action,
|
|
883
|
+
proposalId: proposal.proposalId,
|
|
884
|
+
voterId,
|
|
885
|
+
vote: voteValue,
|
|
886
|
+
strategy: proposalStrategy,
|
|
887
|
+
votesFor,
|
|
888
|
+
votesAgainst,
|
|
889
|
+
required,
|
|
890
|
+
totalVoters,
|
|
891
|
+
resolved,
|
|
892
|
+
result: resolved ? resolution : undefined,
|
|
893
|
+
status: proposal.status,
|
|
894
|
+
duplicateVoters: proposal.duplicateVoters?.length ? proposal.duplicateVoters : undefined,
|
|
895
|
+
divergenceGateOpen,
|
|
896
|
+
divergenceRoundsSeen: proposal.divergenceRoundsSeen ?? 0,
|
|
897
|
+
minDivergenceRounds: proposal.minDivergenceRounds,
|
|
898
|
+
divergenceHint: !divergenceGateOpen
|
|
899
|
+
? `Anti-groupthink delay: ${proposal.divergenceRoundsSeen ?? 0}/${proposal.minDivergenceRounds} divergent rounds seen. Resolution deferred.`
|
|
900
|
+
: undefined,
|
|
901
|
+
};
|
|
902
|
+
}
|
|
903
|
+
if (action === 'status') {
|
|
904
|
+
const proposal = state.votes.pending.find(p => p.proposalId === input.proposalId);
|
|
905
|
+
if (!proposal) {
|
|
906
|
+
const historical = state.votes.history.find(h => h.proposalId === input.proposalId);
|
|
907
|
+
if (historical) {
|
|
908
|
+
return { action, ...historical, historical: true, resolved: true };
|
|
909
|
+
}
|
|
910
|
+
return { action, error: 'Proposal not found' };
|
|
911
|
+
}
|
|
912
|
+
const votesFor = Object.values(proposal.votes).filter(v => v).length;
|
|
913
|
+
const votesAgainst = Object.values(proposal.votes).filter(v => !v).length;
|
|
914
|
+
const proposalStrategy = proposal.strategy || 'majority';
|
|
915
|
+
const required = calculateRequiredVotes(proposalStrategy, totalVoters, proposal.minVotes);
|
|
916
|
+
return {
|
|
917
|
+
action,
|
|
918
|
+
proposalId: proposal.proposalId,
|
|
919
|
+
type: proposal.type,
|
|
920
|
+
strategy: proposalStrategy,
|
|
921
|
+
status: proposal.status,
|
|
922
|
+
votesFor,
|
|
923
|
+
votesAgainst,
|
|
924
|
+
totalVotes: Object.keys(proposal.votes).length,
|
|
925
|
+
required,
|
|
926
|
+
totalVoters,
|
|
927
|
+
resolved: false,
|
|
928
|
+
minVotes: proposal.minVotes,
|
|
929
|
+
duplicateVoters: proposal.duplicateVoters?.length ? proposal.duplicateVoters : undefined,
|
|
930
|
+
};
|
|
931
|
+
}
|
|
932
|
+
if (action === 'list') {
|
|
933
|
+
return {
|
|
934
|
+
action,
|
|
935
|
+
pending: state.votes.pending.map(p => ({
|
|
936
|
+
proposalId: p.proposalId,
|
|
937
|
+
type: p.type,
|
|
938
|
+
strategy: p.strategy || 'majority',
|
|
939
|
+
proposedAt: p.proposedAt,
|
|
940
|
+
totalVotes: Object.keys(p.votes).length,
|
|
941
|
+
required: calculateRequiredVotes(p.strategy || 'majority', totalVoters, p.minVotes),
|
|
942
|
+
status: p.status,
|
|
943
|
+
})),
|
|
944
|
+
recentHistory: state.votes.history.slice(-5),
|
|
945
|
+
};
|
|
946
|
+
}
|
|
947
|
+
return { action, error: 'Unknown action' };
|
|
948
|
+
},
|
|
949
|
+
},
|
|
950
|
+
{
|
|
951
|
+
name: 'monoswarm_notice',
|
|
952
|
+
description: 'Append a message to a shared array in the state file — a noticeboard, not message delivery; nothing subscribes to it.',
|
|
953
|
+
category: 'monoswarm',
|
|
954
|
+
inputSchema: {
|
|
955
|
+
type: 'object',
|
|
956
|
+
properties: {
|
|
957
|
+
message: { type: 'string', description: 'Notice text' },
|
|
958
|
+
priority: { type: 'string', enum: ['low', 'normal', 'high', 'critical'], description: 'Notice priority' },
|
|
959
|
+
fromId: { type: 'string', description: 'Sender agent ID' },
|
|
960
|
+
},
|
|
961
|
+
required: ['message'],
|
|
962
|
+
},
|
|
963
|
+
handler: async (input) => {
|
|
964
|
+
const state = loadMonoswarmState();
|
|
965
|
+
if (!state.initialized) {
|
|
966
|
+
return { success: false, error: 'Monoswarm not initialized' };
|
|
967
|
+
}
|
|
968
|
+
const MAX_MSG_LEN = 1024 * 1024; // 1 MB
|
|
969
|
+
const MAX_FROM_ID_LEN = 256;
|
|
970
|
+
const MAX_PRIORITY_LEN = 16;
|
|
971
|
+
const rawMessage = input.message;
|
|
972
|
+
const message = typeof rawMessage === 'string' && rawMessage.length > MAX_MSG_LEN
|
|
973
|
+
? rawMessage.slice(0, MAX_MSG_LEN) : rawMessage;
|
|
974
|
+
const rawFromId = input.fromId || 'system';
|
|
975
|
+
const fromId = typeof rawFromId === 'string' && rawFromId.length > MAX_FROM_ID_LEN
|
|
976
|
+
? rawFromId.slice(0, MAX_FROM_ID_LEN) : rawFromId;
|
|
977
|
+
const rawPriority = input.priority || 'normal';
|
|
978
|
+
const priority = typeof rawPriority === 'string' && rawPriority.length > MAX_PRIORITY_LEN
|
|
979
|
+
? rawPriority.slice(0, MAX_PRIORITY_LEN) : rawPriority;
|
|
980
|
+
const noticeId = `notice-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
981
|
+
state.notices.push({ noticeId, message, priority, fromId, timestamp: new Date().toISOString() });
|
|
982
|
+
state.notices = state.notices.slice(-100); // Keep only the last 100 notices
|
|
983
|
+
saveMonoswarmState(state);
|
|
984
|
+
return {
|
|
985
|
+
success: true,
|
|
986
|
+
noticeId,
|
|
987
|
+
recipients: state.agents.length,
|
|
988
|
+
priority,
|
|
989
|
+
postedAt: new Date().toISOString(),
|
|
990
|
+
};
|
|
991
|
+
},
|
|
992
|
+
},
|
|
993
|
+
{
|
|
994
|
+
name: 'monoswarm_memory',
|
|
995
|
+
description: 'Plain key/value bookkeeping in the state file — not a distributed or replicated store.',
|
|
996
|
+
category: 'monoswarm',
|
|
997
|
+
inputSchema: {
|
|
998
|
+
type: 'object',
|
|
999
|
+
properties: {
|
|
1000
|
+
action: { type: 'string', enum: ['get', 'set', 'delete', 'list'], description: 'Memory action' },
|
|
1001
|
+
key: { type: 'string', description: 'Memory key' },
|
|
1002
|
+
value: { description: 'Value to store (for set)' },
|
|
1003
|
+
},
|
|
1004
|
+
required: ['action'],
|
|
1005
|
+
},
|
|
1006
|
+
handler: async (input) => {
|
|
1007
|
+
const state = loadMonoswarmState();
|
|
1008
|
+
const action = input.action;
|
|
1009
|
+
const key = input.key;
|
|
1010
|
+
const MAX_KEY_LEN = 256;
|
|
1011
|
+
const MAX_VALUE_BYTES = 1024 * 1024; // 1 MB
|
|
1012
|
+
const MAX_KEYS = 1000;
|
|
1013
|
+
if (action === 'get') {
|
|
1014
|
+
if (!key)
|
|
1015
|
+
return { action, error: 'Key required' };
|
|
1016
|
+
if (typeof key !== 'string' || key.length > MAX_KEY_LEN || RESERVED_KEYS.has(key)) {
|
|
1017
|
+
return { action, error: 'Invalid key' };
|
|
1018
|
+
}
|
|
1019
|
+
return {
|
|
1020
|
+
action,
|
|
1021
|
+
key,
|
|
1022
|
+
value: Object.hasOwn(state.sharedMemory, key) ? state.sharedMemory[key] : undefined,
|
|
1023
|
+
exists: Object.hasOwn(state.sharedMemory, key),
|
|
1024
|
+
};
|
|
1025
|
+
}
|
|
1026
|
+
if (action === 'set') {
|
|
1027
|
+
if (!key)
|
|
1028
|
+
return { action, error: 'Key required' };
|
|
1029
|
+
if (typeof key !== 'string' || key.length > MAX_KEY_LEN || RESERVED_KEYS.has(key)) {
|
|
1030
|
+
return { action, error: 'Invalid key' };
|
|
1031
|
+
}
|
|
1032
|
+
const rawValue = input.value;
|
|
1033
|
+
const cappedValue = typeof rawValue === 'string' && rawValue.length > MAX_VALUE_BYTES
|
|
1034
|
+
? rawValue.slice(0, MAX_VALUE_BYTES) : rawValue;
|
|
1035
|
+
const keyCount = Object.keys(state.sharedMemory).length;
|
|
1036
|
+
if (!Object.hasOwn(state.sharedMemory, key) && keyCount >= MAX_KEYS) {
|
|
1037
|
+
return { action, error: `Shared memory full (max ${MAX_KEYS} keys)` };
|
|
1038
|
+
}
|
|
1039
|
+
state.sharedMemory[key] = cappedValue;
|
|
1040
|
+
saveMonoswarmState(state);
|
|
1041
|
+
try {
|
|
1042
|
+
const bridge = await import('../memory/memory-bridge.js');
|
|
1043
|
+
await bridge.bridgeStoreEntry({
|
|
1044
|
+
key: `monoswarm-memory-${key}`,
|
|
1045
|
+
value: JSON.stringify(input.value),
|
|
1046
|
+
namespace: 'monoswarm-memory',
|
|
1047
|
+
});
|
|
1048
|
+
}
|
|
1049
|
+
catch { /* SQLite memory backend not available */ }
|
|
1050
|
+
return { action, key, success: true, updatedAt: new Date().toISOString() };
|
|
1051
|
+
}
|
|
1052
|
+
if (action === 'delete') {
|
|
1053
|
+
if (!key)
|
|
1054
|
+
return { action, error: 'Key required' };
|
|
1055
|
+
if (typeof key !== 'string' || key.length > MAX_KEY_LEN || RESERVED_KEYS.has(key)) {
|
|
1056
|
+
return { action, error: 'Invalid key' };
|
|
1057
|
+
}
|
|
1058
|
+
const existed = Object.hasOwn(state.sharedMemory, key);
|
|
1059
|
+
delete state.sharedMemory[key];
|
|
1060
|
+
saveMonoswarmState(state);
|
|
1061
|
+
return { action, key, deleted: existed };
|
|
1062
|
+
}
|
|
1063
|
+
if (action === 'list') {
|
|
1064
|
+
return {
|
|
1065
|
+
action,
|
|
1066
|
+
keys: Object.keys(state.sharedMemory),
|
|
1067
|
+
count: Object.keys(state.sharedMemory).length,
|
|
1068
|
+
};
|
|
1069
|
+
}
|
|
1070
|
+
return { action, error: 'Unknown action' };
|
|
1071
|
+
},
|
|
1072
|
+
},
|
|
1073
|
+
{
|
|
1074
|
+
name: 'monoswarm_audit_list',
|
|
1075
|
+
description: 'List tamper-evident vote audit records (HMAC-signed JSONL trail) — local file, not a distributed ledger.',
|
|
1076
|
+
category: 'monoswarm',
|
|
1077
|
+
inputSchema: {
|
|
1078
|
+
type: 'object',
|
|
1079
|
+
properties: {
|
|
1080
|
+
swarmId: { type: 'string', description: 'Filter by monoswarm ID (optional)' },
|
|
1081
|
+
limit: { type: 'number', description: 'Max records to return (default: 50, max: 500)' },
|
|
1082
|
+
},
|
|
1083
|
+
},
|
|
1084
|
+
handler: async (input) => {
|
|
1085
|
+
try {
|
|
1086
|
+
const { AuditWriter } = await import('../consensus/audit-writer.js');
|
|
1087
|
+
const auditDir = join(getProjectCwd(), '.monomind', 'consensus');
|
|
1088
|
+
const writer = new AuditWriter(auditDir);
|
|
1089
|
+
const limit = Math.min(Math.max(1, input.limit || 50), 500);
|
|
1090
|
+
const swarmId = input.swarmId;
|
|
1091
|
+
const records = writer.listDecisions(swarmId, limit);
|
|
1092
|
+
return {
|
|
1093
|
+
success: true,
|
|
1094
|
+
count: records.length,
|
|
1095
|
+
records: records.map(r => ({
|
|
1096
|
+
decisionId: r.decisionId,
|
|
1097
|
+
swarmId: r.swarmId,
|
|
1098
|
+
protocol: r.protocol,
|
|
1099
|
+
topic: r.topic,
|
|
1100
|
+
decision: r.decision,
|
|
1101
|
+
voteCount: r.votes.length,
|
|
1102
|
+
quorumAchieved: r.quorumAchieved,
|
|
1103
|
+
round: r.round,
|
|
1104
|
+
durationMs: r.durationMs,
|
|
1105
|
+
completedAt: r.completedAt,
|
|
1106
|
+
signed: !!r.recordSignature,
|
|
1107
|
+
})),
|
|
1108
|
+
};
|
|
1109
|
+
}
|
|
1110
|
+
catch (e) {
|
|
1111
|
+
return { success: false, error: `Audit trail unavailable: ${e.message}` };
|
|
1112
|
+
}
|
|
1113
|
+
},
|
|
1114
|
+
},
|
|
1115
|
+
{
|
|
1116
|
+
name: 'monoswarm_audit_verify',
|
|
1117
|
+
description: 'Verify tamper-evidence of a vote decision (checks HMAC signatures on all votes and the record itself) — a local file check, not a distributed ledger.',
|
|
1118
|
+
category: 'monoswarm',
|
|
1119
|
+
inputSchema: {
|
|
1120
|
+
type: 'object',
|
|
1121
|
+
properties: {
|
|
1122
|
+
decisionId: { type: 'string', description: 'Decision/proposal ID to verify' },
|
|
1123
|
+
},
|
|
1124
|
+
required: ['decisionId'],
|
|
1125
|
+
},
|
|
1126
|
+
handler: async (input) => {
|
|
1127
|
+
const hk = getOrCreateAuditKey();
|
|
1128
|
+
const decisionId = input.decisionId;
|
|
1129
|
+
if (typeof decisionId !== 'string' || decisionId.length === 0 || decisionId.length > 256) {
|
|
1130
|
+
return { success: false, error: 'Invalid decisionId' };
|
|
1131
|
+
}
|
|
1132
|
+
try {
|
|
1133
|
+
const { AuditWriter } = await import('../consensus/audit-writer.js');
|
|
1134
|
+
const auditDir = join(getProjectCwd(), '.monomind', 'consensus');
|
|
1135
|
+
const writer = new AuditWriter(auditDir);
|
|
1136
|
+
const result = writer.verifyDecision(decisionId, hk);
|
|
1137
|
+
return {
|
|
1138
|
+
success: true,
|
|
1139
|
+
decisionId,
|
|
1140
|
+
valid: result.valid,
|
|
1141
|
+
invalidVotes: result.invalidVotes,
|
|
1142
|
+
message: result.valid
|
|
1143
|
+
? 'All vote signatures and record signature verified — no tampering detected.'
|
|
1144
|
+
: `Verification failed: ${result.invalidVotes.length} invalid vote(s) or record signature mismatch.`,
|
|
1145
|
+
};
|
|
1146
|
+
}
|
|
1147
|
+
catch (e) {
|
|
1148
|
+
return { success: false, error: `Audit verification failed: ${e.message}` };
|
|
1149
|
+
}
|
|
1150
|
+
},
|
|
1151
|
+
},
|
|
1152
|
+
];
|
|
1153
|
+
//# sourceMappingURL=monoswarm-tools.js.map
|