monomind 1.8.0 → 1.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/agents/design/design-monodesign.md +121 -0
- package/.claude/agents/github/issue-tracker.md +12 -12
- package/.claude/agents/github/pr-manager.md +10 -10
- package/.claude/agents/github/release-manager.md +49 -105
- package/.claude/agents/github/repo-architect.md +73 -92
- package/.claude/agents/github/sync-coordinator.md +55 -123
- package/.claude/agents/marketing/marketing-competitive-content.md +155 -0
- package/.claude/agents/marketing/marketing-content-creator.md +13 -0
- package/.claude/agents/marketing/marketing-cro-specialist.md +147 -0
- package/.claude/agents/marketing/marketing-email-specialist.md +90 -0
- package/.claude/agents/marketing/marketing-launch-strategist.md +129 -0
- package/.claude/agents/marketing/marketing-pricing-strategist.md +127 -0
- package/.claude/agents/specialists/integration-architect.md +94 -0
- package/.claude/commands/agents/README.md +4 -0
- package/.claude/commands/agents/agent-capabilities.md +6 -2
- package/.claude/commands/agents/agent-coordination.md +4 -0
- package/.claude/commands/agents/agent-spawning.md +4 -0
- package/.claude/commands/agents/agent-types.md +6 -2
- package/.claude/commands/analysis/README.md +14 -5
- package/.claude/commands/analysis/bottleneck-detect.md +30 -123
- package/.claude/commands/analysis/performance-bottlenecks.md +14 -14
- package/.claude/commands/analysis/performance-report.md +38 -11
- package/.claude/commands/analysis/token-efficiency.md +13 -16
- package/.claude/commands/analysis/token-usage.md +34 -12
- package/.claude/commands/automation/README.md +15 -5
- package/.claude/commands/automation/auto-agent.md +49 -85
- package/.claude/commands/automation/self-healing.md +20 -18
- package/.claude/commands/automation/session-memory.md +28 -29
- package/.claude/commands/automation/smart-agents.md +17 -9
- package/.claude/commands/automation/smart-spawn.md +52 -11
- package/.claude/commands/automation/workflow-select.md +46 -11
- package/.claude/commands/browse.md +5 -0
- package/.claude/commands/coordination/README.md +9 -5
- package/.claude/commands/coordination/agent-spawn.md +53 -9
- package/.claude/commands/coordination/swarm-init.md +39 -42
- package/.claude/commands/coordination/task-orchestrate.md +65 -11
- package/.claude/commands/github/README.md +21 -8
- package/.claude/commands/github/github-modes.md +9 -5
- package/.claude/commands/github/issue-tracker.md +34 -33
- package/.claude/commands/github/pr-manager.md +20 -17
- package/.claude/commands/github/release-manager.md +37 -49
- package/.claude/commands/github/repo-architect.md +39 -41
- package/.claude/commands/github/sync-coordinator.md +45 -49
- package/.claude/commands/hive-mind/README.md +42 -17
- package/.claude/commands/hive-mind/hive-mind-consensus.md +68 -4
- package/.claude/commands/hive-mind/hive-mind-init.md +55 -5
- package/.claude/commands/hive-mind/hive-mind-memory.md +69 -4
- package/.claude/commands/hive-mind/hive-mind-spawn.md +71 -10
- package/.claude/commands/hive-mind/hive-mind-status.md +52 -4
- package/.claude/commands/hive-mind/hive-mind-stop.md +51 -4
- package/.claude/commands/hive-mind/hive-mind.md +74 -14
- package/.claude/commands/hooks/README.md +62 -7
- package/.claude/commands/hooks/overview.md +94 -35
- package/.claude/commands/hooks/post-edit.md +48 -87
- package/.claude/commands/hooks/post-task.md +37 -87
- package/.claude/commands/hooks/pre-edit.md +52 -84
- package/.claude/commands/hooks/pre-task.md +46 -81
- package/.claude/commands/hooks/session-end.md +49 -85
- package/.claude/commands/hooks/setup.md +87 -58
- package/.claude/commands/mastermind/_repeat.md +308 -0
- package/.claude/commands/mastermind/architect.md +49 -0
- package/.claude/commands/mastermind/brain.md +98 -0
- package/.claude/commands/mastermind/build.md +22 -0
- package/.claude/commands/mastermind/content.md +22 -0
- package/.claude/commands/mastermind/createorg.md +94 -0
- package/.claude/commands/mastermind/finance.md +22 -0
- package/.claude/commands/mastermind/idea.md +22 -0
- package/.claude/commands/mastermind/marketing.md +22 -0
- package/.claude/commands/mastermind/master.md +379 -0
- package/.claude/commands/mastermind/ops.md +22 -0
- package/.claude/commands/mastermind/release.md +22 -0
- package/.claude/commands/mastermind/research.md +22 -0
- package/.claude/commands/mastermind/review.md +22 -0
- package/.claude/commands/mastermind/runorg.md +106 -0
- package/.claude/commands/mastermind/sales.md +22 -0
- package/.claude/commands/mastermind/techport.md +17 -0
- package/.claude/commands/memory/README.md +75 -5
- package/.claude/commands/memory/memory-search.md +63 -11
- package/.claude/commands/monitoring/README.md +64 -4
- package/.claude/commands/monitoring/agent-metrics.md +50 -10
- package/.claude/commands/monitoring/agents.md +59 -32
- package/.claude/commands/monitoring/status.md +96 -34
- package/.claude/commands/monograph/README.md +102 -0
- package/.claude/commands/monograph/monograph-build.md +79 -0
- package/.claude/commands/monograph/monograph-search.md +96 -0
- package/.claude/commands/monograph/monograph-stats.md +53 -0
- package/.claude/commands/monograph/monograph-watch.md +63 -0
- package/.claude/commands/monograph/monograph-wiki.md +91 -0
- package/.claude/commands/monomind/createtask.md +277 -0
- package/.claude/commands/{monomind-do.md → monomind/do.md} +21 -8
- package/.claude/commands/monomind/help.md +118 -0
- package/.claude/commands/{monomind-idea.md → monomind/idea.md} +22 -28
- package/.claude/commands/{monomind-improve.md → monomind/improve.md} +21 -27
- package/.claude/commands/monomind/memory.md +230 -0
- package/.claude/commands/monomind/repeat.md +201 -0
- package/.claude/commands/monomind/review.md +313 -0
- package/.claude/commands/monomind/specialagents.md +125 -0
- package/.claude/commands/monomind/swarm.md +161 -0
- package/.claude/commands/monomind/understand.md +148 -0
- package/.claude/commands/optimization/README.md +69 -5
- package/.claude/commands/optimization/auto-topology.md +66 -43
- package/.claude/commands/optimization/parallel-execution.md +65 -39
- package/.claude/commands/optimization/performance-optimize.md +79 -0
- package/.claude/commands/pair/README.md +48 -230
- package/.claude/commands/pair/examples.md +85 -441
- package/.claude/commands/pair/modes.md +77 -303
- package/.claude/commands/pair/session.md +76 -359
- package/.claude/commands/sparc/analyzer.md +9 -26
- package/.claude/commands/sparc/architect.md +8 -25
- package/.claude/commands/sparc/ask.md +27 -68
- package/.claude/commands/sparc/batch-executor.md +8 -25
- package/.claude/commands/sparc/code.md +12 -53
- package/.claude/commands/sparc/coder.md +8 -25
- package/.claude/commands/sparc/debug.md +12 -53
- package/.claude/commands/sparc/debugger.md +8 -25
- package/.claude/commands/sparc/designer.md +8 -25
- package/.claude/commands/sparc/devops.md +16 -57
- package/.claude/commands/sparc/docs-writer.md +12 -53
- package/.claude/commands/sparc/documenter.md +8 -25
- package/.claude/commands/sparc/innovator.md +8 -25
- package/.claude/commands/sparc/integration.md +12 -53
- package/.claude/commands/sparc/mcp.md +12 -53
- package/.claude/commands/sparc/memory-manager.md +28 -25
- package/.claude/commands/sparc/optimizer.md +8 -25
- package/.claude/commands/sparc/orchestrator.md +35 -97
- package/.claude/commands/sparc/post-deployment-monitoring-mode.md +13 -54
- package/.claude/commands/sparc/refinement-optimization-mode.md +13 -54
- package/.claude/commands/sparc/researcher.md +8 -25
- package/.claude/commands/sparc/reviewer.md +8 -25
- package/.claude/commands/sparc/security-review.md +13 -54
- package/.claude/commands/sparc/sparc-modes.md +97 -151
- package/.claude/commands/sparc/sparc.md +16 -56
- package/.claude/commands/sparc/spec-pseudocode.md +13 -54
- package/.claude/commands/sparc/supabase-admin.md +19 -66
- package/.claude/commands/sparc/swarm-coordinator.md +21 -25
- package/.claude/commands/sparc/tdd.md +8 -25
- package/.claude/commands/sparc/tester.md +8 -25
- package/.claude/commands/sparc/tutorial.md +12 -53
- package/.claude/commands/sparc/workflow-manager.md +8 -25
- package/.claude/commands/sparc.md +76 -130
- package/.claude/commands/stream-chain/pipeline.md +72 -77
- package/.claude/commands/stream-chain/run.md +133 -47
- package/.claude/commands/swarm/README.md +37 -12
- package/.claude/commands/swarm/analysis.md +47 -69
- package/.claude/commands/swarm/development.md +45 -69
- package/.claude/commands/swarm/examples.md +77 -142
- package/.claude/commands/swarm/maintenance.md +47 -74
- package/.claude/commands/swarm/optimization.md +54 -87
- package/.claude/commands/swarm/research.md +47 -107
- package/.claude/commands/swarm/swarm-analysis.md +58 -4
- package/.claude/commands/swarm/swarm-background.md +61 -4
- package/.claude/commands/swarm/swarm-modes.md +63 -4
- package/.claude/commands/swarm/swarm-monitor.md +50 -4
- package/.claude/commands/swarm/swarm-status.md +40 -4
- package/.claude/commands/swarm/swarm-strategies.md +73 -5
- package/.claude/commands/swarm/swarm.md +70 -18
- package/.claude/commands/swarm/testing.md +51 -102
- package/.claude/commands/tokens.md +6 -1
- package/.claude/commands/training/README.md +36 -6
- package/.claude/commands/training/model-update.md +68 -15
- package/.claude/commands/training/neural-patterns.md +54 -55
- package/.claude/commands/training/neural-train.md +70 -16
- package/.claude/commands/training/pattern-learn.md +60 -16
- package/.claude/commands/training/specialization.md +78 -49
- package/.claude/commands/truth/start.md +87 -109
- package/.claude/commands/ts.md +7 -2
- package/.claude/commands/verify/check.md +90 -34
- package/.claude/commands/verify/start.md +71 -94
- package/.claude/commands/workflows/README.md +62 -6
- package/.claude/commands/workflows/development.md +69 -61
- package/.claude/commands/workflows/research.md +73 -47
- package/.claude/commands/workflows/workflow-create.md +75 -16
- package/.claude/commands/workflows/workflow-execute.md +94 -16
- package/.claude/commands/workflows/workflow-export.md +81 -16
- package/.claude/helpers/control-start.cjs +91 -0
- package/.claude/helpers/extras-registry.json +4104 -1991
- package/.claude/helpers/graphify-freshen.cjs +44 -13
- package/.claude/helpers/hook-handler.cjs +256 -1
- package/.claude/helpers/learning-service.mjs +0 -0
- package/.claude/helpers/loop-tracker.cjs +107 -0
- package/.claude/helpers/metrics-db.mjs +0 -0
- package/.claude/helpers/router.cjs +48 -68
- package/.claude/helpers/skill-registry.json +89 -104
- package/.claude/helpers/statusline.cjs +33 -2
- package/.claude/helpers/swarm-hooks.sh +0 -0
- package/.claude/scheduled_tasks.lock +1 -0
- package/.claude/settings.json +15 -0
- package/.claude/skills/.monomind/data/ranked-context.json +5 -0
- package/.claude/skills/.monomind/sessions/current.json +13 -0
- package/.claude/skills/.monomind/sessions/session-1777829336455.json +15 -0
- package/.claude/skills/.monomind/sessions/session-1777831614725.json +15 -0
- package/.claude/skills/.monomind/sessions/session-1777832095857.json +15 -0
- package/.claude/skills/.monomind/sessions/session-1777839814183.json +15 -0
- package/.claude/skills/.monomind/sessions/session-1777841847131.json +15 -0
- package/.claude/skills/.monomind/sessions/session-1777843309463.json +15 -0
- package/.claude/skills/.monomind/sessions/session-1777880867159.json +15 -0
- package/.claude/skills/.monomind/sessions/session-1777881884593.json +15 -0
- package/.claude/skills/.monomind/sessions/session-1777884090471.json +15 -0
- package/.claude/skills/.monomind/sessions/session-1777884808221.json +15 -0
- package/.claude/skills/.monomind/sessions/session-1777885672155.json +15 -0
- package/.claude/skills/.monomind/sessions/session-1777886852818.json +15 -0
- package/.claude/skills/.monomind/sessions/session-1777896532690.json +15 -0
- package/.claude/skills/agentdb-advanced/SKILL.md +11 -12
- package/.claude/skills/agentdb-learning/SKILL.md +20 -21
- package/.claude/skills/agentdb-memory-patterns/SKILL.md +28 -30
- package/.claude/skills/agentdb-optimization/SKILL.md +11 -12
- package/.claude/skills/agentdb-vector-search/SKILL.md +37 -41
- package/.claude/skills/{v3-integration-deep → agentic-integration}/SKILL.md +20 -13
- package/.claude/skills/agentic-jujutsu/SKILL.md +22 -22
- package/.claude/skills/{v3-cli-modernization → cli-modernization}/SKILL.md +17 -8
- package/.claude/skills/{v3-core-implementation → core-implementation}/SKILL.md +33 -8
- package/.claude/skills/{v3-ddd-architecture → ddd-architecture}/SKILL.md +18 -25
- package/.claude/skills/github-code-review/SKILL.md +82 -83
- package/.claude/skills/github-multi-repo/SKILL.md +42 -46
- package/.claude/skills/github-project-management/SKILL.md +83 -88
- package/.claude/skills/github-release-management/SKILL.md +12 -18
- package/.claude/skills/github-workflow-automation/SKILL.md +70 -74
- package/.claude/skills/hooks-automation/SKILL.md +9 -13
- package/.claude/skills/mastermind/_intake.md +83 -0
- package/.claude/skills/mastermind/_protocol.md +275 -0
- package/.claude/skills/mastermind/architect.md +847 -0
- package/.claude/skills/mastermind/build.md +158 -0
- package/.claude/skills/mastermind/content.md +185 -0
- package/.claude/skills/mastermind/createorg.md +318 -0
- package/.claude/skills/mastermind/finance.md +154 -0
- package/.claude/skills/mastermind/idea.md +158 -0
- package/.claude/skills/mastermind/marketing.md +216 -0
- package/.claude/skills/mastermind/monotask.md +350 -0
- package/.claude/skills/mastermind/ops.md +156 -0
- package/.claude/skills/mastermind/references/copywriting-frameworks.md +181 -0
- package/.claude/skills/mastermind/references/persuasion-psychology.md +158 -0
- package/.claude/skills/mastermind/release.md +156 -0
- package/.claude/skills/mastermind/research.md +156 -0
- package/.claude/skills/mastermind/review.md +157 -0
- package/.claude/skills/mastermind/runorg.md +308 -0
- package/.claude/skills/mastermind/sales.md +158 -0
- package/.claude/skills/mastermind/techport.md +743 -0
- package/.claude/skills/{v3-mcp-optimization → mcp-optimization}/SKILL.md +35 -14
- package/.claude/skills/{v3-memory-unification → memory-unification}/SKILL.md +20 -4
- package/.claude/skills/monodesign/SKILL.md +302 -0
- package/.claude/skills/monodesign/reference/adapt.md +190 -0
- package/.claude/skills/monodesign/reference/animate.md +175 -0
- package/.claude/skills/monodesign/reference/antipatterns-catalog.md +187 -0
- package/.claude/skills/monodesign/reference/audit.md +133 -0
- package/.claude/skills/monodesign/reference/bolder.md +113 -0
- package/.claude/skills/monodesign/reference/brand-workflow.md +180 -0
- package/.claude/skills/monodesign/reference/brand.md +114 -0
- package/.claude/skills/monodesign/reference/clarify.md +174 -0
- package/.claude/skills/monodesign/reference/cognitive-load.md +106 -0
- package/.claude/skills/monodesign/reference/color-and-contrast.md +105 -0
- package/.claude/skills/monodesign/reference/colorize.md +154 -0
- package/.claude/skills/monodesign/reference/component-specs.md +260 -0
- package/.claude/skills/monodesign/reference/component-states.md +274 -0
- package/.claude/skills/monodesign/reference/component-system.md +358 -0
- package/.claude/skills/monodesign/reference/copy-formulas.md +160 -0
- package/.claude/skills/monodesign/reference/craft.md +193 -0
- package/.claude/skills/monodesign/reference/critique.md +213 -0
- package/.claude/skills/monodesign/reference/delight.md +302 -0
- package/.claude/skills/monodesign/reference/design-principles.md +246 -0
- package/.claude/skills/monodesign/reference/distill.md +111 -0
- package/.claude/skills/monodesign/reference/document.md +427 -0
- package/.claude/skills/monodesign/reference/extract.md +69 -0
- package/.claude/skills/monodesign/reference/harden.md +347 -0
- package/.claude/skills/monodesign/reference/heuristics-scoring.md +234 -0
- package/.claude/skills/monodesign/reference/image-prompts.md +118 -0
- package/.claude/skills/monodesign/reference/interaction-design.md +195 -0
- package/.claude/skills/monodesign/reference/layout.md +141 -0
- package/.claude/skills/monodesign/reference/live.md +622 -0
- package/.claude/skills/monodesign/reference/motion-design.md +109 -0
- package/.claude/skills/monodesign/reference/onboard.md +234 -0
- package/.claude/skills/monodesign/reference/optimize.md +258 -0
- package/.claude/skills/monodesign/reference/overdrive.md +130 -0
- package/.claude/skills/monodesign/reference/personas.md +179 -0
- package/.claude/skills/monodesign/reference/polish.md +233 -0
- package/.claude/skills/monodesign/reference/pre-delivery-checklist.md +108 -0
- package/.claude/skills/monodesign/reference/product.md +62 -0
- package/.claude/skills/monodesign/reference/quieter.md +99 -0
- package/.claude/skills/monodesign/reference/responsive-design.md +114 -0
- package/.claude/skills/monodesign/reference/shape.md +151 -0
- package/.claude/skills/monodesign/reference/spatial-design.md +100 -0
- package/.claude/skills/monodesign/reference/teach.md +156 -0
- package/.claude/skills/monodesign/reference/token-architecture.md +222 -0
- package/.claude/skills/monodesign/reference/typeset.md +124 -0
- package/.claude/skills/monodesign/reference/typography.md +159 -0
- package/.claude/skills/monodesign/reference/ux-research.md +143 -0
- package/.claude/skills/monodesign/reference/ux-rules.md +211 -0
- package/.claude/skills/monodesign/reference/ux-writing.md +107 -0
- package/.claude/skills/monomotion/SKILL.md +145 -0
- package/.claude/skills/monomotion/rules/api-control.md +139 -0
- package/.claude/skills/monomotion/rules/effects.md +109 -0
- package/.claude/skills/monomotion/rules/integration.md +140 -0
- package/.claude/skills/monomotion/rules/scroll.md +131 -0
- package/.claude/skills/monomotion/rules/sequencing.md +105 -0
- package/.claude/skills/monomotion/rules/svg.md +101 -0
- package/.claude/skills/monomotion/rules/text.md +119 -0
- package/.claude/skills/pair-programming/SKILL.md +1 -1
- package/.claude/skills/performance-analysis/SKILL.md +3 -3
- package/.claude/skills/{v3-performance-optimization → performance-optimization}/SKILL.md +16 -8
- package/.claude/skills/reasoningbank-agentdb/SKILL.md +17 -19
- package/.claude/skills/reasoningbank-intelligence/SKILL.md +4 -6
- package/.claude/skills/{v3-security-overhaul → security-hardening}/SKILL.md +13 -3
- package/.claude/skills/skill-builder/SKILL.md +19 -19
- package/.claude/skills/sparc-methodology/SKILL.md +55 -211
- package/.claude/skills/stop-slop/SKILL.md +67 -0
- package/.claude/skills/stop-slop/references/examples.md +61 -0
- package/.claude/skills/stop-slop/references/phrases.md +130 -0
- package/.claude/skills/stop-slop/references/structures.md +136 -0
- package/.claude/skills/swarm-advanced/SKILL.md +13 -43
- package/.claude/skills/{v3-swarm-coordination → swarm-coordination}/SKILL.md +39 -21
- package/.claude/skills/swarm-orchestration/SKILL.md +12 -12
- package/.claude/skills/verification-quality/SKILL.md +5 -5
- package/.claude/statusline-command.sh +0 -0
- package/.claude/statusline.sh +0 -0
- package/.claude-plugin/scripts/install.sh +0 -0
- package/.claude-plugin/scripts/uninstall.sh +0 -0
- package/.claude-plugin/scripts/verify.sh +0 -0
- package/README.md +5 -5
- package/package.json +17 -17
- package/packages/@monomind/cli/README.md +441 -0
- package/packages/@monomind/cli/bin/cli.js +78 -13
- package/packages/@monomind/cli/bin/mcp-server.js +0 -0
- package/packages/@monomind/cli/dist/src/agents/halt-signal.js +33 -7
- package/packages/@monomind/cli/dist/src/agents/managed-agent.js +5 -2
- package/packages/@monomind/cli/dist/src/agents/prompt-experiment.d.ts +3 -2
- package/packages/@monomind/cli/dist/src/agents/prompt-experiment.js +1 -1
- package/packages/@monomind/cli/dist/src/agents/prompt-version-manager.d.ts +5 -2
- package/packages/@monomind/cli/dist/src/agents/prompt-version-manager.js +26 -4
- package/packages/@monomind/cli/dist/src/agents/specialization-scorer.js +17 -9
- package/packages/@monomind/cli/dist/src/agents/trigger-scanner.d.ts +5 -3
- package/packages/@monomind/cli/dist/src/agents/trigger-scanner.js +58 -10
- package/packages/@monomind/cli/dist/src/agents/version-store.d.ts +0 -1
- package/packages/@monomind/cli/dist/src/agents/version-store.js +44 -21
- package/packages/@monomind/cli/dist/src/autopilot-state.js +79 -28
- package/packages/@monomind/cli/dist/src/benchmarks/benchmark-runner.d.ts +7 -2
- package/packages/@monomind/cli/dist/src/benchmarks/benchmark-runner.js +20 -8
- package/packages/@monomind/cli/dist/src/benchmarks/metric-evaluators.d.ts +2 -1
- package/packages/@monomind/cli/dist/src/benchmarks/metric-evaluators.js +25 -2
- package/packages/@monomind/cli/dist/src/commands/agent.js +6 -4
- package/packages/@monomind/cli/dist/src/commands/appliance-advanced.js +23 -0
- package/packages/@monomind/cli/dist/src/commands/autopilot.js +3 -3
- package/packages/@monomind/cli/dist/src/commands/benchmark.js +119 -8
- package/packages/@monomind/cli/dist/src/commands/claims.js +22 -14
- package/packages/@monomind/cli/dist/src/commands/config.js +32 -0
- package/packages/@monomind/cli/dist/src/commands/daemon.js +13 -11
- package/packages/@monomind/cli/dist/src/commands/deployment.js +21 -2
- package/packages/@monomind/cli/dist/src/commands/doctor.js +5 -4
- package/packages/@monomind/cli/dist/src/commands/embeddings.js +124 -48
- package/packages/@monomind/cli/dist/src/commands/hive-mind.js +15 -14
- package/packages/@monomind/cli/dist/src/commands/hooks.js +45 -41
- package/packages/@monomind/cli/dist/src/commands/index.d.ts +2 -0
- package/packages/@monomind/cli/dist/src/commands/index.js +20 -7
- package/packages/@monomind/cli/dist/src/commands/init.js +53 -19
- package/packages/@monomind/cli/dist/src/commands/mcp.js +31 -44
- package/packages/@monomind/cli/dist/src/commands/memory.js +47 -15
- package/packages/@monomind/cli/dist/src/commands/migrate.js +156 -108
- package/packages/@monomind/cli/dist/src/commands/monograph.d.ts +8 -0
- package/packages/@monomind/cli/dist/src/commands/monograph.js +526 -0
- package/packages/@monomind/cli/dist/src/commands/neural.js +96 -56
- package/packages/@monomind/cli/dist/src/commands/performance.js +30 -8
- package/packages/@monomind/cli/dist/src/commands/plugins.js +13 -37
- package/packages/@monomind/cli/dist/src/commands/process.js +25 -2
- package/packages/@monomind/cli/dist/src/commands/providers.js +37 -5
- package/packages/@monomind/cli/dist/src/commands/replay.js +4 -4
- package/packages/@monomind/cli/dist/src/commands/route.js +37 -5
- package/packages/@monomind/cli/dist/src/commands/ruvector/import.js +12 -2
- package/packages/@monomind/cli/dist/src/commands/ruvector/init.js +15 -0
- package/packages/@monomind/cli/dist/src/commands/ruvector/status.js +16 -3
- package/packages/@monomind/cli/dist/src/commands/security.js +342 -193
- package/packages/@monomind/cli/dist/src/commands/session.js +51 -8
- package/packages/@monomind/cli/dist/src/commands/start.js +18 -4
- package/packages/@monomind/cli/dist/src/commands/swarm.js +47 -36
- package/packages/@monomind/cli/dist/src/commands/tokens.js +11 -11
- package/packages/@monomind/cli/dist/src/commands/transfer-store.js +1 -1
- package/packages/@monomind/cli/dist/src/commands/workflow.js +31 -4
- package/packages/@monomind/cli/dist/src/config-adapter.d.ts +2 -1
- package/packages/@monomind/cli/dist/src/consensus/audit-writer.js +46 -13
- package/packages/@monomind/cli/dist/src/consensus/vote-signer.d.ts +0 -3
- package/packages/@monomind/cli/dist/src/consensus/vote-signer.js +9 -1
- package/packages/@monomind/cli/dist/src/dlq/dlq-reader.d.ts +4 -2
- package/packages/@monomind/cli/dist/src/dlq/dlq-reader.js +25 -8
- package/packages/@monomind/cli/dist/src/dlq/dlq-replayer.d.ts +10 -3
- package/packages/@monomind/cli/dist/src/dlq/dlq-replayer.js +50 -16
- package/packages/@monomind/cli/dist/src/dlq/dlq-writer.js +27 -5
- package/packages/@monomind/cli/dist/src/eval/dataset-manager.d.ts +2 -2
- package/packages/@monomind/cli/dist/src/eval/dataset-manager.js +26 -16
- package/packages/@monomind/cli/dist/src/eval/trace-collector.js +23 -3
- package/packages/@monomind/cli/dist/src/index.js +12 -10
- package/packages/@monomind/cli/dist/src/init/claudemd-generator.js +8 -8
- package/packages/@monomind/cli/dist/src/init/executor.js +212 -102
- package/packages/@monomind/cli/dist/src/init/helpers-generator.js +35 -22
- package/packages/@monomind/cli/dist/src/init/mcp-generator.js +3 -3
- package/packages/@monomind/cli/dist/src/init/settings-generator.js +10 -3
- package/packages/@monomind/cli/dist/src/init/shared-instructions-generator.js +18 -3
- package/packages/@monomind/cli/dist/src/init/statusline-generator.js +3 -1
- package/packages/@monomind/cli/dist/src/init/types.d.ts +35 -11
- package/packages/@monomind/cli/dist/src/init/types.js +5 -9
- package/packages/@monomind/cli/dist/src/interactive/interrupt.js +8 -3
- package/packages/@monomind/cli/dist/src/mcp/tool-registry.js +38 -4
- package/packages/@monomind/cli/dist/src/mcp-client.js +10 -4
- package/packages/@monomind/cli/dist/src/mcp-server.d.ts +9 -2
- package/packages/@monomind/cli/dist/src/mcp-server.js +182 -35
- package/packages/@monomind/cli/dist/src/mcp-tools/agent-tools.js +66 -34
- package/packages/@monomind/cli/dist/src/mcp-tools/agentdb-tools.js +34 -7
- package/packages/@monomind/cli/dist/src/mcp-tools/analyze-tools.js +25 -16
- package/packages/@monomind/cli/dist/src/mcp-tools/auto-install.js +4 -6
- package/packages/@monomind/cli/dist/src/mcp-tools/autopilot-tools.js +12 -2
- package/packages/@monomind/cli/dist/src/mcp-tools/browser-tools.js +199 -20
- package/packages/@monomind/cli/dist/src/mcp-tools/claims-tools.js +68 -18
- package/packages/@monomind/cli/dist/src/mcp-tools/config-tools.js +33 -5
- package/packages/@monomind/cli/dist/src/mcp-tools/coordination-tools.js +59 -4
- package/packages/@monomind/cli/dist/src/mcp-tools/daa-tools.js +46 -10
- package/packages/@monomind/cli/dist/src/mcp-tools/embeddings-tools.js +46 -5
- package/packages/@monomind/cli/dist/src/mcp-tools/github-tools.js +29 -16
- package/packages/@monomind/cli/dist/src/mcp-tools/guidance-tools.js +38 -10
- package/packages/@monomind/cli/dist/src/mcp-tools/hive-mind-tools.js +96 -33
- package/packages/@monomind/cli/dist/src/mcp-tools/hooks-tools.js +70 -37
- package/packages/@monomind/cli/dist/src/mcp-tools/memory-tools.js +29 -13
- package/packages/@monomind/cli/dist/src/mcp-tools/monograph-tools.js +5867 -56
- package/packages/@monomind/cli/dist/src/mcp-tools/neural-tools.js +121 -37
- package/packages/@monomind/cli/dist/src/mcp-tools/performance-tools.js +21 -8
- package/packages/@monomind/cli/dist/src/mcp-tools/progress-tools.js +10 -8
- package/packages/@monomind/cli/dist/src/mcp-tools/request-tracker.js +4 -1
- package/packages/@monomind/cli/dist/src/mcp-tools/ruvllm-tools.js +19 -8
- package/packages/@monomind/cli/dist/src/mcp-tools/session-tools.js +57 -17
- package/packages/@monomind/cli/dist/src/mcp-tools/swarm-tools.js +35 -17
- package/packages/@monomind/cli/dist/src/mcp-tools/system-tools.js +4 -3
- package/packages/@monomind/cli/dist/src/mcp-tools/task-tools.js +53 -13
- package/packages/@monomind/cli/dist/src/mcp-tools/terminal-tools.js +63 -14
- package/packages/@monomind/cli/dist/src/mcp-tools/transfer-tools.js +21 -16
- package/packages/@monomind/cli/dist/src/mcp-tools/workflow-tools.js +92 -23
- package/packages/@monomind/cli/dist/src/memory/ewc-consolidation.js +41 -10
- package/packages/@monomind/cli/dist/src/memory/intelligence.d.ts +2 -2
- package/packages/@monomind/cli/dist/src/memory/intelligence.js +39 -13
- package/packages/@monomind/cli/dist/src/memory/memory-bridge.d.ts +1 -0
- package/packages/@monomind/cli/dist/src/memory/memory-bridge.js +149 -56
- package/packages/@monomind/cli/dist/src/memory/memory-initializer.js +107 -45
- package/packages/@monomind/cli/dist/src/memory/sona-optimizer.d.ts +8 -1
- package/packages/@monomind/cli/dist/src/memory/sona-optimizer.js +25 -8
- package/packages/@monomind/cli/dist/src/observability/replay-reader.d.ts +40 -0
- package/packages/@monomind/cli/dist/src/observability/replay-reader.js +138 -0
- package/packages/@monomind/cli/dist/src/orchestration/routing-modes.js +35 -5
- package/packages/@monomind/cli/dist/src/parser.d.ts +8 -0
- package/packages/@monomind/cli/dist/src/parser.js +48 -14
- package/packages/@monomind/cli/dist/src/plugins/manager.js +112 -19
- package/packages/@monomind/cli/dist/src/plugins/store/discovery.d.ts +1 -1
- package/packages/@monomind/cli/dist/src/plugins/store/discovery.js +80 -62
- package/packages/@monomind/cli/dist/src/production/circuit-breaker.js +8 -1
- package/packages/@monomind/cli/dist/src/production/error-handler.d.ts +4 -2
- package/packages/@monomind/cli/dist/src/production/error-handler.js +27 -5
- package/packages/@monomind/cli/dist/src/production/monitoring.js +8 -4
- package/packages/@monomind/cli/dist/src/production/rate-limiter.js +30 -22
- package/packages/@monomind/cli/dist/src/ruvector/agent-wasm.js +2 -2
- package/packages/@monomind/cli/dist/src/ruvector/coverage-router.js +19 -9
- package/packages/@monomind/cli/dist/src/ruvector/diff-classifier.d.ts +1 -0
- package/packages/@monomind/cli/dist/src/ruvector/diff-classifier.js +26 -6
- package/packages/@monomind/cli/dist/src/ruvector/enhanced-model-router.js +24 -2
- package/packages/@monomind/cli/dist/src/ruvector/index.d.ts +1 -2
- package/packages/@monomind/cli/dist/src/ruvector/index.js +2 -2
- package/packages/@monomind/cli/dist/src/ruvector/model-router.d.ts +4 -2
- package/packages/@monomind/cli/dist/src/ruvector/model-router.js +30 -6
- package/packages/@monomind/cli/dist/src/ruvector/moe-router.d.ts +7 -0
- package/packages/@monomind/cli/dist/src/ruvector/moe-router.js +35 -12
- package/packages/@monomind/cli/dist/src/ruvector/q-learning-router.d.ts +7 -1
- package/packages/@monomind/cli/dist/src/ruvector/q-learning-router.js +40 -9
- package/packages/@monomind/cli/dist/src/services/claim-service.d.ts +3 -1
- package/packages/@monomind/cli/dist/src/services/claim-service.js +33 -2
- package/packages/@monomind/cli/dist/src/services/config-file-manager.d.ts +16 -2
- package/packages/@monomind/cli/dist/src/services/config-file-manager.js +105 -17
- package/packages/@monomind/cli/dist/src/services/container-worker-pool.js +51 -11
- package/packages/@monomind/cli/dist/src/services/headless-worker-executor.d.ts +7 -0
- package/packages/@monomind/cli/dist/src/services/headless-worker-executor.js +188 -45
- package/packages/@monomind/cli/dist/src/services/registry-api.js +62 -9
- package/packages/@monomind/cli/dist/src/services/ruvector-training.js +8 -0
- package/packages/@monomind/cli/dist/src/services/worker-daemon.d.ts +4 -1
- package/packages/@monomind/cli/dist/src/services/worker-daemon.js +112 -28
- package/packages/@monomind/cli/dist/src/services/worker-queue.d.ts +9 -2
- package/packages/@monomind/cli/dist/src/services/worker-queue.js +86 -5
- package/packages/@monomind/cli/dist/src/suggest.js +9 -0
- package/packages/@monomind/cli/dist/src/swarm/flow-enforcer.d.ts +5 -3
- package/packages/@monomind/cli/dist/src/swarm/flow-enforcer.js +17 -5
- package/packages/@monomind/cli/dist/src/swarm/flow-visualizer.d.ts +3 -0
- package/packages/@monomind/cli/dist/src/swarm/flow-visualizer.js +30 -6
- package/packages/@monomind/cli/dist/src/transfer/anonymization/index.js +5 -3
- package/packages/@monomind/cli/dist/src/transfer/export.js +5 -3
- package/packages/@monomind/cli/dist/src/transfer/ipfs/client.js +84 -7
- package/packages/@monomind/cli/dist/src/transfer/ipfs/upload.js +13 -4
- package/packages/@monomind/cli/dist/src/transfer/storage/gcs.js +19 -10
- package/packages/@monomind/cli/dist/src/transfer/store/discovery.d.ts +9 -2
- package/packages/@monomind/cli/dist/src/transfer/store/discovery.js +68 -13
- package/packages/@monomind/cli/dist/src/transfer/store/download.d.ts +15 -6
- package/packages/@monomind/cli/dist/src/transfer/store/download.js +113 -24
- package/packages/@monomind/cli/dist/src/transfer/store/publish.d.ts +1 -1
- package/packages/@monomind/cli/dist/src/transfer/store/publish.js +13 -14
- package/packages/@monomind/cli/dist/src/transfer/store/registry.d.ts +3 -3
- package/packages/@monomind/cli/dist/src/transfer/store/registry.js +32 -16
- package/packages/@monomind/cli/dist/src/update/checker.js +17 -4
- package/packages/@monomind/cli/dist/src/update/executor.js +25 -20
- package/packages/@monomind/cli/dist/src/update/rate-limiter.d.ts +11 -0
- package/packages/@monomind/cli/dist/src/update/rate-limiter.js +23 -3
- package/packages/@monomind/cli/dist/src/utils/parse-jsonl.d.ts +6 -0
- package/packages/@monomind/cli/dist/src/utils/parse-jsonl.js +22 -0
- package/packages/@monomind/cli/dist/src/workflow/condition-evaluator.js +37 -3
- package/packages/@monomind/cli/dist/src/workflow/dag-builder.js +27 -11
- package/packages/@monomind/cli/dist/src/workflow/dag-executor.js +51 -13
- package/packages/@monomind/cli/dist/src/workflow/dsl-schema.d.ts +3 -0
- package/packages/@monomind/cli/dist/src/workflow/dsl-schema.js +6 -2
- package/packages/@monomind/cli/dist/src/workflow/template-engine.js +7 -0
- package/packages/@monomind/cli/dist/src/workflow/workflow-executor.js +95 -14
- package/packages/@monomind/cli/package.json +5 -3
- package/packages/@monomind/guidance/README.md +1192 -0
- package/packages/@monomind/shared/README.md +322 -0
- package/packages/@monomind/shared/dist/types/consensus-audit.d.ts +3 -1
- package/packages/README.md +513 -0
- package/.claude/agents/design/design-brand-guardian.md +0 -323
- package/.claude/agents/design/design-image-prompt-engineer.md +0 -237
- package/.claude/agents/design/design-inclusive-visuals-specialist.md +0 -72
- package/.claude/agents/design/design-ui-designer.md +0 -384
- package/.claude/agents/design/design-ux-architect.md +0 -470
- package/.claude/agents/design/design-ux-researcher.md +0 -330
- package/.claude/agents/design/design-visual-storyteller.md +0 -150
- package/.claude/agents/design/design-whimsy-injector.md +0 -439
- package/.claude/agents/v3/integration-architect.md +0 -338
- package/.claude/commands/analysis/COMMAND_COMPLIANCE_REPORT.md +0 -54
- package/.claude/commands/coordination/init.md +0 -44
- package/.claude/commands/coordination/orchestrate.md +0 -43
- package/.claude/commands/coordination/spawn.md +0 -45
- package/.claude/commands/github/code-review-swarm.md +0 -550
- package/.claude/commands/github/code-review.md +0 -25
- package/.claude/commands/github/github-swarm.md +0 -121
- package/.claude/commands/github/issue-triage.md +0 -25
- package/.claude/commands/github/multi-repo-swarm.md +0 -519
- package/.claude/commands/github/pr-enhance.md +0 -26
- package/.claude/commands/github/project-board-sync.md +0 -471
- package/.claude/commands/github/release-swarm.md +0 -590
- package/.claude/commands/github/repo-analyze.md +0 -25
- package/.claude/commands/github/swarm-issue.md +0 -482
- package/.claude/commands/github/swarm-pr.md +0 -310
- package/.claude/commands/github/workflow-automation.md +0 -468
- package/.claude/commands/hive-mind/hive-mind-metrics.md +0 -8
- package/.claude/commands/hive-mind/hive-mind-resume.md +0 -8
- package/.claude/commands/hive-mind/hive-mind-sessions.md +0 -8
- package/.claude/commands/hive-mind/hive-mind-wizard.md +0 -8
- package/.claude/commands/list-agents.md +0 -17
- package/.claude/commands/memory/memory-persist.md +0 -25
- package/.claude/commands/memory/memory-usage.md +0 -25
- package/.claude/commands/memory/neural.md +0 -47
- package/.claude/commands/metrics.md +0 -11
- package/.claude/commands/monitoring/real-time-view.md +0 -25
- package/.claude/commands/monitoring/swarm-monitor.md +0 -25
- package/.claude/commands/monomind-createtask.md +0 -302
- package/.claude/commands/monomind-help.md +0 -103
- package/.claude/commands/monomind-memory.md +0 -107
- package/.claude/commands/monomind-repeat.md +0 -149
- package/.claude/commands/monomind-swarm.md +0 -205
- package/.claude/commands/optimization/cache-manage.md +0 -25
- package/.claude/commands/optimization/topology-optimize.md +0 -25
- package/.claude/commands/pair/commands.md +0 -546
- package/.claude/commands/pair/config.md +0 -510
- package/.claude/commands/pair/start.md +0 -209
- package/.claude/commands/use-agent.md +0 -67
- package/.claude/skills/monomind-createtask/SKILL.md +0 -269
- package/.claude/skills/monomind-task-engine/SKILL.md +0 -358
- /package/.claude/agents/{v3 → specialists}/memory-specialist.md +0 -0
- /package/.claude/agents/{v3 → specialists}/performance-engineer.md +0 -0
- /package/.claude/agents/{v3 → specialists}/queen-coordinator.md +0 -0
- /package/.claude/agents/{v3 → specialists}/security-architect.md +0 -0
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
*
|
|
16
16
|
* @module moe-router
|
|
17
17
|
*/
|
|
18
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
|
19
|
-
import { dirname } from 'path';
|
|
18
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync, renameSync } from 'fs';
|
|
19
|
+
import { dirname, join } from 'path';
|
|
20
20
|
/**
|
|
21
21
|
* Expert names in order (index corresponds to expert slot)
|
|
22
22
|
*/
|
|
@@ -445,7 +445,7 @@ export class MoERouter {
|
|
|
445
445
|
* Load weights from persistence file
|
|
446
446
|
*/
|
|
447
447
|
async loadWeights(path) {
|
|
448
|
-
const weightsPath = path
|
|
448
|
+
const weightsPath = path ? path : join(process.cwd(), this.config.weightsPath);
|
|
449
449
|
try {
|
|
450
450
|
if (!existsSync(weightsPath)) {
|
|
451
451
|
return false;
|
|
@@ -457,11 +457,20 @@ export class MoERouter {
|
|
|
457
457
|
console.warn(`[MoE] Incompatible model version: ${model.version}`);
|
|
458
458
|
return false;
|
|
459
459
|
}
|
|
460
|
-
// Load weights
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
460
|
+
// Load weights with dimension validation
|
|
461
|
+
const w1 = new Float32Array(model.weights.W1.flat());
|
|
462
|
+
const b1 = new Float32Array(model.weights.b1);
|
|
463
|
+
const w2 = new Float32Array(model.weights.W2.flat());
|
|
464
|
+
const b2 = new Float32Array(model.weights.b2);
|
|
465
|
+
if (w1.length !== INPUT_DIM * HIDDEN_DIM || b1.length !== HIDDEN_DIM ||
|
|
466
|
+
w2.length !== HIDDEN_DIM * NUM_EXPERTS || b2.length !== NUM_EXPERTS) {
|
|
467
|
+
console.warn('[MoE] Weight dimensions mismatch — reinitializing');
|
|
468
|
+
return false;
|
|
469
|
+
}
|
|
470
|
+
this.W1 = w1;
|
|
471
|
+
this.b1 = b1;
|
|
472
|
+
this.W2 = w2;
|
|
473
|
+
this.b2 = b2;
|
|
465
474
|
// Load stats
|
|
466
475
|
this.updateCount = model.stats.updateCount || 0;
|
|
467
476
|
this.avgReward = model.stats.avgReward || 0;
|
|
@@ -478,7 +487,7 @@ export class MoERouter {
|
|
|
478
487
|
* Save weights to persistence file
|
|
479
488
|
*/
|
|
480
489
|
async saveWeights(path) {
|
|
481
|
-
const weightsPath = path
|
|
490
|
+
const weightsPath = path ? path : join(process.cwd(), this.config.weightsPath);
|
|
482
491
|
try {
|
|
483
492
|
// Ensure directory exists
|
|
484
493
|
const dir = dirname(weightsPath);
|
|
@@ -518,7 +527,9 @@ export class MoERouter {
|
|
|
518
527
|
expertNames: [...EXPERT_NAMES],
|
|
519
528
|
},
|
|
520
529
|
};
|
|
521
|
-
|
|
530
|
+
const tmp = weightsPath + '.tmp';
|
|
531
|
+
writeFileSync(tmp, JSON.stringify(model, null, 2));
|
|
532
|
+
renameSync(tmp, weightsPath);
|
|
522
533
|
return true;
|
|
523
534
|
}
|
|
524
535
|
catch (err) {
|
|
@@ -595,6 +606,7 @@ export class MoERouter {
|
|
|
595
606
|
// Singleton Instance
|
|
596
607
|
// ============================================================================
|
|
597
608
|
let moeRouterInstance = null;
|
|
609
|
+
let _moeInitPromise = null;
|
|
598
610
|
/**
|
|
599
611
|
* Get singleton MoE router instance
|
|
600
612
|
*
|
|
@@ -604,13 +616,24 @@ let moeRouterInstance = null;
|
|
|
604
616
|
export function getMoERouter(config) {
|
|
605
617
|
if (!moeRouterInstance) {
|
|
606
618
|
moeRouterInstance = new MoERouter(config);
|
|
607
|
-
|
|
608
|
-
moeRouterInstance.initialize().catch((err) => {
|
|
619
|
+
_moeInitPromise = moeRouterInstance.initialize().catch((err) => {
|
|
609
620
|
console.warn('[MoE] Failed to initialize router:', err);
|
|
610
621
|
});
|
|
611
622
|
}
|
|
612
623
|
return moeRouterInstance;
|
|
613
624
|
}
|
|
625
|
+
/**
|
|
626
|
+
* Get singleton MoE router instance, waiting for initialization to complete
|
|
627
|
+
*
|
|
628
|
+
* @param config - Optional configuration (only used on first call)
|
|
629
|
+
* @returns Promise resolving to fully initialized MoE router instance
|
|
630
|
+
*/
|
|
631
|
+
export async function getMoERouterReady(config) {
|
|
632
|
+
const router = getMoERouter(config);
|
|
633
|
+
if (_moeInitPromise)
|
|
634
|
+
await _moeInitPromise;
|
|
635
|
+
return router;
|
|
636
|
+
}
|
|
614
637
|
/**
|
|
615
638
|
* Reset singleton instance (for testing)
|
|
616
639
|
*/
|
|
@@ -169,7 +169,13 @@ export declare class QLearningRouter {
|
|
|
169
169
|
visits: number;
|
|
170
170
|
}>;
|
|
171
171
|
/**
|
|
172
|
-
* Import Q-table from persistence
|
|
172
|
+
* Import Q-table from persistence with strict validation.
|
|
173
|
+
* SECURITY: a poisoned `.swarm/q-table.json` (co-located process write,
|
|
174
|
+
* malicious test fixture) with `qValues: [Infinity, ...]` would otherwise
|
|
175
|
+
* propagate NaN/Infinity through every argmax + Q-update — the attacker
|
|
176
|
+
* deterministically chooses every routing decision. Mirror the
|
|
177
|
+
* ewc-consolidation.ts:loadFromDisk pattern: per-field shape + finite-numeric
|
|
178
|
+
* + dimension check, drop bad records silently.
|
|
173
179
|
*/
|
|
174
180
|
import(data: Record<string, {
|
|
175
181
|
qValues: number[];
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
*
|
|
14
14
|
* @module q-learning-router
|
|
15
15
|
*/
|
|
16
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
|
17
|
-
import { dirname } from 'path';
|
|
16
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync, renameSync, statSync } from 'fs';
|
|
17
|
+
import { dirname, join } from 'path';
|
|
18
18
|
/**
|
|
19
19
|
* Default configuration
|
|
20
20
|
*/
|
|
@@ -125,11 +125,15 @@ export class QLearningRouter {
|
|
|
125
125
|
* Load model from persistence file
|
|
126
126
|
*/
|
|
127
127
|
async loadModel(path) {
|
|
128
|
-
const modelPath = path
|
|
128
|
+
const modelPath = path ? path : join(process.cwd(), this.config.modelPath);
|
|
129
129
|
try {
|
|
130
130
|
if (!existsSync(modelPath)) {
|
|
131
131
|
return false;
|
|
132
132
|
}
|
|
133
|
+
const MAX_MODEL_SIZE = 20 * 1024 * 1024; // 20 MB
|
|
134
|
+
const st = statSync(modelPath, { throwIfNoEntry: false });
|
|
135
|
+
if (!st || st.size > MAX_MODEL_SIZE)
|
|
136
|
+
return false;
|
|
133
137
|
const data = readFileSync(modelPath, 'utf-8');
|
|
134
138
|
const model = JSON.parse(data);
|
|
135
139
|
// Validate version compatibility
|
|
@@ -156,7 +160,7 @@ export class QLearningRouter {
|
|
|
156
160
|
* Save model to persistence file
|
|
157
161
|
*/
|
|
158
162
|
async saveModel(path) {
|
|
159
|
-
const modelPath = path
|
|
163
|
+
const modelPath = path ? path : join(process.cwd(), this.config.modelPath);
|
|
160
164
|
try {
|
|
161
165
|
// Ensure directory exists
|
|
162
166
|
const dir = dirname(modelPath);
|
|
@@ -183,7 +187,9 @@ export class QLearningRouter {
|
|
|
183
187
|
totalExperiences: this.totalExperiences,
|
|
184
188
|
},
|
|
185
189
|
};
|
|
186
|
-
|
|
190
|
+
const tmp = modelPath + '.tmp';
|
|
191
|
+
writeFileSync(tmp, JSON.stringify(model, null, 2));
|
|
192
|
+
renameSync(tmp, modelPath);
|
|
187
193
|
return true;
|
|
188
194
|
}
|
|
189
195
|
catch (err) {
|
|
@@ -197,8 +203,10 @@ export class QLearningRouter {
|
|
|
197
203
|
*/
|
|
198
204
|
route(taskContext, explore = true) {
|
|
199
205
|
const stateKey = this.hashStateOptimized(taskContext);
|
|
206
|
+
// Check if we should explore using decayed epsilon
|
|
207
|
+
const shouldExplore = explore && Math.random() < this.epsilon;
|
|
200
208
|
// Check cache first (only for exploitation, not exploration)
|
|
201
|
-
if (!
|
|
209
|
+
if (!shouldExplore) {
|
|
202
210
|
const cached = this.getCachedRoute(stateKey);
|
|
203
211
|
if (cached) {
|
|
204
212
|
this.cacheHits++;
|
|
@@ -206,8 +214,6 @@ export class QLearningRouter {
|
|
|
206
214
|
}
|
|
207
215
|
this.cacheMisses++;
|
|
208
216
|
}
|
|
209
|
-
// Check if we should explore using decayed epsilon
|
|
210
|
-
const shouldExplore = explore && Math.random() < this.epsilon;
|
|
211
217
|
let actionIdx;
|
|
212
218
|
let qValues;
|
|
213
219
|
if (shouldExplore) {
|
|
@@ -398,6 +404,7 @@ export class QLearningRouter {
|
|
|
398
404
|
while (batch.length < batchSize && selected.size < this.replayBuffer.length) {
|
|
399
405
|
let threshold = Math.random() * totalPriority;
|
|
400
406
|
let cumSum = 0;
|
|
407
|
+
const prevLen = batch.length;
|
|
401
408
|
for (let i = 0; i < this.replayBuffer.length; i++) {
|
|
402
409
|
if (selected.has(i))
|
|
403
410
|
continue;
|
|
@@ -408,6 +415,8 @@ export class QLearningRouter {
|
|
|
408
415
|
break;
|
|
409
416
|
}
|
|
410
417
|
}
|
|
418
|
+
if (batch.length === prevLen)
|
|
419
|
+
break; // nothing was selectable, exit
|
|
411
420
|
}
|
|
412
421
|
return batch;
|
|
413
422
|
}
|
|
@@ -492,16 +501,38 @@ export class QLearningRouter {
|
|
|
492
501
|
return result;
|
|
493
502
|
}
|
|
494
503
|
/**
|
|
495
|
-
* Import Q-table from persistence
|
|
504
|
+
* Import Q-table from persistence with strict validation.
|
|
505
|
+
* SECURITY: a poisoned `.swarm/q-table.json` (co-located process write,
|
|
506
|
+
* malicious test fixture) with `qValues: [Infinity, ...]` would otherwise
|
|
507
|
+
* propagate NaN/Infinity through every argmax + Q-update — the attacker
|
|
508
|
+
* deterministically chooses every routing decision. Mirror the
|
|
509
|
+
* ewc-consolidation.ts:loadFromDisk pattern: per-field shape + finite-numeric
|
|
510
|
+
* + dimension check, drop bad records silently.
|
|
496
511
|
*/
|
|
497
512
|
import(data) {
|
|
498
513
|
this.qTable.clear();
|
|
514
|
+
if (!data || typeof data !== 'object')
|
|
515
|
+
return;
|
|
516
|
+
let imported = 0;
|
|
499
517
|
for (const [key, entry] of Object.entries(data)) {
|
|
518
|
+
if (imported >= this.config.maxStates)
|
|
519
|
+
break;
|
|
520
|
+
if (typeof key !== 'string' || key.length === 0 || key.length > 256)
|
|
521
|
+
continue;
|
|
522
|
+
if (!entry || typeof entry !== 'object' || !Array.isArray(entry.qValues))
|
|
523
|
+
continue;
|
|
524
|
+
if (entry.qValues.length !== this.config.numActions)
|
|
525
|
+
continue;
|
|
526
|
+
if (!entry.qValues.every(v => typeof v === 'number' && Number.isFinite(v)))
|
|
527
|
+
continue;
|
|
528
|
+
if (typeof entry.visits !== 'number' || !Number.isFinite(entry.visits) || entry.visits < 0)
|
|
529
|
+
continue;
|
|
500
530
|
this.qTable.set(key, {
|
|
501
531
|
qValues: new Float32Array(entry.qValues),
|
|
502
532
|
visits: entry.visits,
|
|
503
533
|
lastUpdate: Date.now(),
|
|
504
534
|
});
|
|
535
|
+
imported++;
|
|
505
536
|
}
|
|
506
537
|
}
|
|
507
538
|
// Private methods
|
|
@@ -139,7 +139,9 @@ export declare class ClaimService extends EventEmitter {
|
|
|
139
139
|
constructor(projectRoot: string, config?: Partial<WorkStealingConfig>);
|
|
140
140
|
initialize(): Promise<void>;
|
|
141
141
|
private loadClaims;
|
|
142
|
+
private _saveQueue;
|
|
142
143
|
private saveClaims;
|
|
144
|
+
private _doSaveClaims;
|
|
143
145
|
claim(issueId: string, claimant: Claimant): Promise<ClaimResult>;
|
|
144
146
|
release(issueId: string, claimant: Claimant): Promise<void>;
|
|
145
147
|
requestHandoff(issueId: string, from: Claimant, to: Claimant, reason: string): Promise<void>;
|
|
@@ -148,7 +150,7 @@ export declare class ClaimService extends EventEmitter {
|
|
|
148
150
|
updateStatus(issueId: string, status: ClaimStatus, note?: string): Promise<void>;
|
|
149
151
|
updateProgress(issueId: string, progress: number): Promise<void>;
|
|
150
152
|
requestReview(issueId: string, reviewers: Claimant[]): Promise<void>;
|
|
151
|
-
markStealable(issueId: string, info: StealableInfo): Promise<void>;
|
|
153
|
+
markStealable(issueId: string, info: StealableInfo, claimant?: Claimant): Promise<void>;
|
|
152
154
|
steal(issueId: string, stealer: Claimant): Promise<StealResult>;
|
|
153
155
|
getStealable(agentType?: string): Promise<IssueClaim[]>;
|
|
154
156
|
contestSteal(issueId: string, originalClaimant: Claimant, reason: string): Promise<void>;
|
|
@@ -75,13 +75,37 @@ export class ClaimService extends EventEmitter {
|
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
|
+
// Single-flight save lock: serializes concurrent saveClaims() calls so that
|
|
79
|
+
// two writers cannot collide on the .tmp file or interleave their renames.
|
|
80
|
+
// Combined with the unique tmp suffix below, this defends against in-process
|
|
81
|
+
// corruption of claims.json. Cross-process safety still requires fcntl/flock
|
|
82
|
+
// around the read-modify-write at higher level.
|
|
83
|
+
_saveQueue = Promise.resolve();
|
|
78
84
|
async saveClaims() {
|
|
85
|
+
// CRITICAL: do NOT let a single rejection (ENOSPC / EROFS / EACCES)
|
|
86
|
+
// poison the entire chain. Previously every subsequent saveClaims would
|
|
87
|
+
// inherit the rejection and silently skip _doSaveClaims, causing the
|
|
88
|
+
// in-memory Map to drift from disk indefinitely — a permanent
|
|
89
|
+
// authorization-state desync. Catch the chain link so the next link runs;
|
|
90
|
+
// re-expose the real rejection to the caller via a separate promise.
|
|
91
|
+
const next = this._saveQueue
|
|
92
|
+
.catch(() => undefined)
|
|
93
|
+
.then(() => this._doSaveClaims());
|
|
94
|
+
this._saveQueue = next.catch(() => undefined);
|
|
95
|
+
return next;
|
|
96
|
+
}
|
|
97
|
+
async _doSaveClaims() {
|
|
79
98
|
const claimsFile = path.join(this.storagePath, 'claims.json');
|
|
80
99
|
const data = {
|
|
81
100
|
claims: Array.from(this.claims.values()),
|
|
82
101
|
savedAt: new Date().toISOString(),
|
|
83
102
|
};
|
|
84
|
-
|
|
103
|
+
// Unique tmp filename so a previous in-flight write cannot be clobbered
|
|
104
|
+
// by a concurrent fs.writeFileSync truncating the same .tmp path.
|
|
105
|
+
const { randomBytes } = await import('crypto');
|
|
106
|
+
const tmp = `${claimsFile}.${process.pid}.${Date.now()}.${randomBytes(4).toString('hex')}.tmp`;
|
|
107
|
+
fs.writeFileSync(tmp, JSON.stringify(data, null, 2));
|
|
108
|
+
fs.renameSync(tmp, claimsFile);
|
|
85
109
|
}
|
|
86
110
|
// ==========================================================================
|
|
87
111
|
// Core Claiming
|
|
@@ -217,6 +241,10 @@ export class ClaimService extends EventEmitter {
|
|
|
217
241
|
}
|
|
218
242
|
if (status === 'completed') {
|
|
219
243
|
claim.progress = 100;
|
|
244
|
+
// Evict completed claims after saving to prevent unbounded Map growth
|
|
245
|
+
await this.saveClaims();
|
|
246
|
+
this.claims.delete(issueId);
|
|
247
|
+
return;
|
|
220
248
|
}
|
|
221
249
|
await this.saveClaims();
|
|
222
250
|
this.emitEvent({
|
|
@@ -253,11 +281,14 @@ export class ClaimService extends EventEmitter {
|
|
|
253
281
|
// ==========================================================================
|
|
254
282
|
// Work Stealing
|
|
255
283
|
// ==========================================================================
|
|
256
|
-
async markStealable(issueId, info) {
|
|
284
|
+
async markStealable(issueId, info, claimant) {
|
|
257
285
|
const claim = this.claims.get(issueId);
|
|
258
286
|
if (!claim) {
|
|
259
287
|
throw new Error(`Issue ${issueId} is not claimed`);
|
|
260
288
|
}
|
|
289
|
+
if (claimant !== undefined && !this.isSameClaimant(claim.claimant, claimant)) {
|
|
290
|
+
throw new Error(`Issue ${issueId} is not owned by ${this.formatClaimant(claimant)}`);
|
|
291
|
+
}
|
|
261
292
|
claim.status = 'stealable';
|
|
262
293
|
claim.statusChangedAt = new Date();
|
|
263
294
|
claim.context = info.context;
|
|
@@ -13,7 +13,16 @@ export declare class ConfigFileManager {
|
|
|
13
13
|
getConfig(cwd: string): Record<string, unknown>;
|
|
14
14
|
/** Get a nested config value by dot-separated key */
|
|
15
15
|
get(cwd: string, key: string): unknown;
|
|
16
|
-
/** Set a nested config value by dot-separated key
|
|
16
|
+
/** Set a nested config value by dot-separated key.
|
|
17
|
+
* Enforces top-level section allowlist (mirroring importFrom) and recursively
|
|
18
|
+
* sanitises the value to strip prototype-pollution keys before persistence.
|
|
19
|
+
*
|
|
20
|
+
* Re-reads the file from disk inside the write to guard against the
|
|
21
|
+
* read-modify-write credential-clobber race. Without the re-read, two
|
|
22
|
+
* concurrent `monomind providers configure` calls would each see the
|
|
23
|
+
* original config, mutate locally, and the second writer would silently
|
|
24
|
+
* drop the first writer's API key.
|
|
25
|
+
*/
|
|
17
26
|
set(cwd: string, key: string, value: unknown): void;
|
|
18
27
|
/** Create a new config file with defaults */
|
|
19
28
|
create(cwd: string, overrides?: Record<string, unknown>, force?: boolean): string;
|
|
@@ -27,7 +36,12 @@ export declare class ConfigFileManager {
|
|
|
27
36
|
getConfigPath(): string | null;
|
|
28
37
|
/** Get default config */
|
|
29
38
|
getDefaults(): Record<string, unknown>;
|
|
30
|
-
/** Atomic write
|
|
39
|
+
/** Atomic write with restrictive 0o600 mode.
|
|
40
|
+
* SECURITY: this config file may contain API keys (per `commands/providers.ts`).
|
|
41
|
+
* Without explicit mode the file inherits the umask (typically 0o644 →
|
|
42
|
+
* world-readable). Set 0o600 on tmp file BEFORE rename, then re-chmod after
|
|
43
|
+
* rename in case the rename target had a more permissive mode.
|
|
44
|
+
*/
|
|
31
45
|
private writeAtomic;
|
|
32
46
|
}
|
|
33
47
|
/** Parse a string value to the appropriate type */
|
|
@@ -64,10 +64,14 @@ export class ConfigFileManager {
|
|
|
64
64
|
return candidate;
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
|
-
// Check env var
|
|
67
|
+
// Check env var — must resolve within project root
|
|
68
68
|
const envPath = process.env.MONOMIND_CONFIG;
|
|
69
|
-
if (envPath
|
|
70
|
-
|
|
69
|
+
if (envPath) {
|
|
70
|
+
const resolved = path.resolve(envPath);
|
|
71
|
+
const projectRoot = path.resolve(cwd);
|
|
72
|
+
if ((resolved.startsWith(projectRoot + path.sep) || resolved === projectRoot) && fs.existsSync(resolved)) {
|
|
73
|
+
return resolved;
|
|
74
|
+
}
|
|
71
75
|
}
|
|
72
76
|
return null;
|
|
73
77
|
}
|
|
@@ -80,7 +84,8 @@ export class ConfigFileManager {
|
|
|
80
84
|
}
|
|
81
85
|
try {
|
|
82
86
|
const content = fs.readFileSync(this.configPath, 'utf-8');
|
|
83
|
-
|
|
87
|
+
const parsed = JSON.parse(content);
|
|
88
|
+
this.config = sanitizeConfigObject(parsed);
|
|
84
89
|
return this.config;
|
|
85
90
|
}
|
|
86
91
|
catch {
|
|
@@ -100,13 +105,40 @@ export class ConfigFileManager {
|
|
|
100
105
|
const config = this.getConfig(cwd);
|
|
101
106
|
return getNestedValue(config, key);
|
|
102
107
|
}
|
|
103
|
-
/** Set a nested config value by dot-separated key
|
|
108
|
+
/** Set a nested config value by dot-separated key.
|
|
109
|
+
* Enforces top-level section allowlist (mirroring importFrom) and recursively
|
|
110
|
+
* sanitises the value to strip prototype-pollution keys before persistence.
|
|
111
|
+
*
|
|
112
|
+
* Re-reads the file from disk inside the write to guard against the
|
|
113
|
+
* read-modify-write credential-clobber race. Without the re-read, two
|
|
114
|
+
* concurrent `monomind providers configure` calls would each see the
|
|
115
|
+
* original config, mutate locally, and the second writer would silently
|
|
116
|
+
* drop the first writer's API key.
|
|
117
|
+
*/
|
|
104
118
|
set(cwd, key, value) {
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
119
|
+
const KNOWN_SET_SECTIONS = new Set(['version', 'agents', 'swarm', 'memory', 'mcp', 'cli', 'hooks']);
|
|
120
|
+
const topSection = String(key).split('.')[0];
|
|
121
|
+
if (!KNOWN_SET_SECTIONS.has(topSection)) {
|
|
122
|
+
throw new Error(`Unknown config section: "${topSection}". Allowed: ${[...KNOWN_SET_SECTIONS].join(', ')}`);
|
|
123
|
+
}
|
|
124
|
+
const sanitisedValue = sanitizeConfigObject(value);
|
|
125
|
+
const targetPath = this.configPath ?? this.findConfig(cwd) ?? path.resolve(cwd, CONFIG_FILENAMES[0]);
|
|
126
|
+
// Re-read from disk inside the write window so we operate on the latest
|
|
127
|
+
// bytes, not on a possibly-stale this.config cache. This still isn't
|
|
128
|
+
// cross-process atomic without an OS-level flock, but combined with the
|
|
129
|
+
// O_EXCL atomic rename it prevents the most common credential-clobber
|
|
130
|
+
// window where two CLIs interleave their getConfig→set→write cycles.
|
|
131
|
+
let onDisk = { ...DEFAULT_CONFIG };
|
|
132
|
+
if (fs.existsSync(targetPath)) {
|
|
133
|
+
try {
|
|
134
|
+
const parsed = JSON.parse(fs.readFileSync(targetPath, 'utf-8'));
|
|
135
|
+
onDisk = sanitizeConfigObject(parsed);
|
|
136
|
+
}
|
|
137
|
+
catch { /* fall through to defaults */ }
|
|
138
|
+
}
|
|
139
|
+
setNestedValue(onDisk, key, sanitisedValue);
|
|
140
|
+
this.writeAtomic(targetPath, onDisk);
|
|
141
|
+
this.config = onDisk;
|
|
110
142
|
this.configPath = targetPath;
|
|
111
143
|
}
|
|
112
144
|
/** Create a new config file with defaults */
|
|
@@ -115,7 +147,7 @@ export class ConfigFileManager {
|
|
|
115
147
|
if (fs.existsSync(targetPath) && !force) {
|
|
116
148
|
throw new Error(`Config file already exists: ${targetPath}. Use --force to overwrite.`);
|
|
117
149
|
}
|
|
118
|
-
const config = { ...DEFAULT_CONFIG, ...overrides };
|
|
150
|
+
const config = { ...DEFAULT_CONFIG, ...(overrides ? sanitizeConfigObject(overrides) : {}) };
|
|
119
151
|
this.writeAtomic(targetPath, config);
|
|
120
152
|
this.config = config;
|
|
121
153
|
this.configPath = targetPath;
|
|
@@ -133,6 +165,10 @@ export class ConfigFileManager {
|
|
|
133
165
|
exportTo(cwd, exportPath) {
|
|
134
166
|
const config = this.getConfig(cwd);
|
|
135
167
|
const resolved = path.resolve(cwd, exportPath);
|
|
168
|
+
const projectRoot = path.resolve(cwd);
|
|
169
|
+
if (!resolved.startsWith(projectRoot + path.sep) && resolved !== projectRoot) {
|
|
170
|
+
throw new Error('Export path must be within the project directory');
|
|
171
|
+
}
|
|
136
172
|
this.writeAtomic(resolved, config);
|
|
137
173
|
}
|
|
138
174
|
/** Import config from a specific path */
|
|
@@ -142,16 +178,26 @@ export class ConfigFileManager {
|
|
|
142
178
|
throw new Error(`Import file not found: ${resolved}`);
|
|
143
179
|
}
|
|
144
180
|
const content = fs.readFileSync(resolved, 'utf-8');
|
|
145
|
-
let
|
|
181
|
+
let importedRaw;
|
|
146
182
|
try {
|
|
147
|
-
|
|
183
|
+
importedRaw = JSON.parse(content);
|
|
148
184
|
}
|
|
149
185
|
catch {
|
|
150
186
|
throw new Error(`Invalid JSON in import file: ${resolved}`);
|
|
151
187
|
}
|
|
152
|
-
if (typeof
|
|
188
|
+
if (typeof importedRaw !== 'object' || importedRaw === null || Array.isArray(importedRaw)) {
|
|
153
189
|
throw new Error('Import file must contain a JSON object');
|
|
154
190
|
}
|
|
191
|
+
// Recursively strip prototype-pollution keys at every nesting level —
|
|
192
|
+
// KNOWN_SECTIONS only validates top-level keys, leaving nested
|
|
193
|
+
// {agents:{providers:[{__proto__:{...}}]}} unsanitized.
|
|
194
|
+
const imported = sanitizeConfigObject(importedRaw);
|
|
195
|
+
const KNOWN_SECTIONS = new Set(['version', 'agents', 'swarm', 'memory', 'mcp', 'cli', 'hooks']);
|
|
196
|
+
for (const key of Object.keys(imported)) {
|
|
197
|
+
if (!KNOWN_SECTIONS.has(key)) {
|
|
198
|
+
throw new Error(`Unknown config section: "${key}"`);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
155
201
|
const targetPath = this.configPath ?? path.resolve(cwd, CONFIG_FILENAMES[0]);
|
|
156
202
|
this.writeAtomic(targetPath, imported);
|
|
157
203
|
this.config = imported;
|
|
@@ -165,20 +211,57 @@ export class ConfigFileManager {
|
|
|
165
211
|
getDefaults() {
|
|
166
212
|
return { ...DEFAULT_CONFIG };
|
|
167
213
|
}
|
|
168
|
-
/** Atomic write
|
|
214
|
+
/** Atomic write with restrictive 0o600 mode.
|
|
215
|
+
* SECURITY: this config file may contain API keys (per `commands/providers.ts`).
|
|
216
|
+
* Without explicit mode the file inherits the umask (typically 0o644 →
|
|
217
|
+
* world-readable). Set 0o600 on tmp file BEFORE rename, then re-chmod after
|
|
218
|
+
* rename in case the rename target had a more permissive mode.
|
|
219
|
+
*/
|
|
169
220
|
writeAtomic(filePath, data) {
|
|
170
221
|
const dir = path.dirname(filePath);
|
|
171
222
|
if (!fs.existsSync(dir)) {
|
|
172
223
|
fs.mkdirSync(dir, { recursive: true });
|
|
173
224
|
}
|
|
174
|
-
const tmpPath = filePath
|
|
175
|
-
fs.writeFileSync(tmpPath, JSON.stringify(data, null, 2) + '\n');
|
|
225
|
+
const tmpPath = `${filePath}.${process.pid}.tmp`;
|
|
226
|
+
fs.writeFileSync(tmpPath, JSON.stringify(data, null, 2) + '\n', { mode: 0o600 });
|
|
176
227
|
fs.renameSync(tmpPath, filePath);
|
|
228
|
+
try {
|
|
229
|
+
fs.chmodSync(filePath, 0o600);
|
|
230
|
+
}
|
|
231
|
+
catch { /* best effort */ }
|
|
177
232
|
}
|
|
178
233
|
}
|
|
234
|
+
const FORBIDDEN_KEY_SEGMENTS = new Set(['__proto__', 'constructor', 'prototype']);
|
|
235
|
+
/**
|
|
236
|
+
* Recursively strip prototype-pollution keys from a parsed JSON object before
|
|
237
|
+
* it lands in this.config or is persisted back to disk. JSON.parse alone does
|
|
238
|
+
* not pollute, but downstream consumers that shallow-merge config values
|
|
239
|
+
* (Object.assign, spread) would propagate poisoned keys; persisting them back
|
|
240
|
+
* to disk also makes the pollution survive restarts.
|
|
241
|
+
*/
|
|
242
|
+
function sanitizeConfigObject(value, depth = 0) {
|
|
243
|
+
if (depth > 32)
|
|
244
|
+
return null;
|
|
245
|
+
if (Array.isArray(value))
|
|
246
|
+
return value.map(v => sanitizeConfigObject(v, depth + 1));
|
|
247
|
+
if (value !== null && typeof value === 'object') {
|
|
248
|
+
const out = {};
|
|
249
|
+
for (const [k, v] of Object.entries(value)) {
|
|
250
|
+
if (FORBIDDEN_KEY_SEGMENTS.has(k))
|
|
251
|
+
continue;
|
|
252
|
+
out[k] = sanitizeConfigObject(v, depth + 1);
|
|
253
|
+
}
|
|
254
|
+
return out;
|
|
255
|
+
}
|
|
256
|
+
return value;
|
|
257
|
+
}
|
|
179
258
|
/** Get a nested value by dot-separated key */
|
|
180
259
|
function getNestedValue(obj, key) {
|
|
181
260
|
const parts = key.split('.');
|
|
261
|
+
for (const part of parts) {
|
|
262
|
+
if (FORBIDDEN_KEY_SEGMENTS.has(part))
|
|
263
|
+
return undefined;
|
|
264
|
+
}
|
|
182
265
|
let current = obj;
|
|
183
266
|
for (const part of parts) {
|
|
184
267
|
if (current === null || current === undefined || typeof current !== 'object') {
|
|
@@ -191,6 +274,11 @@ function getNestedValue(obj, key) {
|
|
|
191
274
|
/** Set a nested value by dot-separated key */
|
|
192
275
|
function setNestedValue(obj, key, value) {
|
|
193
276
|
const parts = key.split('.');
|
|
277
|
+
for (const part of parts) {
|
|
278
|
+
if (FORBIDDEN_KEY_SEGMENTS.has(part)) {
|
|
279
|
+
throw new Error(`Forbidden config key segment: "${part}"`);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
194
282
|
let current = obj;
|
|
195
283
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
196
284
|
const part = parts[i];
|