monomind 1.8.0 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +153 -70
- 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
|
@@ -3,6 +3,19 @@
|
|
|
3
3
|
*
|
|
4
4
|
* ASCII and DOT (Graphviz) renderers for communication flow edges.
|
|
5
5
|
*/
|
|
6
|
+
/** Escape a slug for safe DOT identifier interpolation. */
|
|
7
|
+
function dotEscape(s) {
|
|
8
|
+
return String(s ?? '').replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
9
|
+
}
|
|
10
|
+
/** Strip newlines/CR for safe ASCII line emission (log-injection defense). */
|
|
11
|
+
function asciiSafe(s) {
|
|
12
|
+
return String(s ?? '').replace(/[\r\n\x00-\x1f\x7f]/g, '?');
|
|
13
|
+
}
|
|
14
|
+
/** Restrict graph names to a safe DOT identifier — graph_name must be an ID. */
|
|
15
|
+
function safeGraphName(name) {
|
|
16
|
+
return /^[a-zA-Z_][a-zA-Z0-9_]{0,63}$/.test(name) ? name : 'swarm_flow';
|
|
17
|
+
}
|
|
18
|
+
const MAX_DISPLAY_EDGES = 500;
|
|
6
19
|
/**
|
|
7
20
|
* Render edges as human-readable ASCII art.
|
|
8
21
|
* Empty edges produce a single-line "unrestricted" notice.
|
|
@@ -10,23 +23,30 @@
|
|
|
10
23
|
export function toAscii(edges, title) {
|
|
11
24
|
const lines = [];
|
|
12
25
|
if (title) {
|
|
13
|
-
lines.push(`=== ${title} ===`);
|
|
26
|
+
lines.push(`=== ${asciiSafe(title)} ===`);
|
|
14
27
|
lines.push('');
|
|
15
28
|
}
|
|
16
29
|
if (edges.length === 0) {
|
|
17
30
|
lines.push('(unrestricted — all agents may communicate freely)');
|
|
18
31
|
return lines.join('\n');
|
|
19
32
|
}
|
|
20
|
-
|
|
21
|
-
|
|
33
|
+
const capped = edges.slice(0, MAX_DISPLAY_EDGES);
|
|
34
|
+
for (const [from, to] of capped) {
|
|
35
|
+
lines.push(` ${asciiSafe(from)} --> ${asciiSafe(to)}`);
|
|
36
|
+
}
|
|
37
|
+
if (edges.length > MAX_DISPLAY_EDGES) {
|
|
38
|
+
lines.push(` ... (${edges.length - MAX_DISPLAY_EDGES} more edges omitted)`);
|
|
22
39
|
}
|
|
23
40
|
return lines.join('\n');
|
|
24
41
|
}
|
|
25
42
|
/**
|
|
26
43
|
* Render edges as a DOT language digraph (Graphviz compatible).
|
|
44
|
+
* Slugs are escaped so a malicious slug cannot inject DOT attributes
|
|
45
|
+
* (e.g., URL="javascript:..." would be rendered as a clickable link
|
|
46
|
+
* by Graphviz's SVG output without escaping).
|
|
27
47
|
*/
|
|
28
48
|
export function toDOT(edges, graphName) {
|
|
29
|
-
const name = graphName ?? 'swarm_flow';
|
|
49
|
+
const name = safeGraphName(graphName ?? 'swarm_flow');
|
|
30
50
|
const lines = [];
|
|
31
51
|
lines.push(`digraph ${name} {`);
|
|
32
52
|
lines.push(' rankdir=LR;');
|
|
@@ -34,8 +54,12 @@ export function toDOT(edges, graphName) {
|
|
|
34
54
|
lines.push(' // unrestricted — no explicit edges');
|
|
35
55
|
}
|
|
36
56
|
else {
|
|
37
|
-
|
|
38
|
-
|
|
57
|
+
const capped = edges.slice(0, MAX_DISPLAY_EDGES);
|
|
58
|
+
for (const [from, to] of capped) {
|
|
59
|
+
lines.push(` "${dotEscape(from)}" -> "${dotEscape(to)}";`);
|
|
60
|
+
}
|
|
61
|
+
if (edges.length > MAX_DISPLAY_EDGES) {
|
|
62
|
+
lines.push(` // ... (${edges.length - MAX_DISPLAY_EDGES} more edges omitted)`);
|
|
39
63
|
}
|
|
40
64
|
}
|
|
41
65
|
lines.push('}');
|
|
@@ -113,10 +113,12 @@ export function anonymizeCFP(cfp, level) {
|
|
|
113
113
|
}
|
|
114
114
|
// Level: Standard
|
|
115
115
|
if (['standard', 'strict', 'paranoid'].includes(level)) {
|
|
116
|
-
// Redact PII from all string fields
|
|
117
|
-
const jsonStr = JSON.stringify(anonymized.patterns);
|
|
116
|
+
// Redact PII from all string fields including metadata
|
|
117
|
+
const jsonStr = JSON.stringify({ patterns: anonymized.patterns, metadata: anonymized.metadata });
|
|
118
118
|
const redacted = redactPII(jsonStr);
|
|
119
|
-
|
|
119
|
+
const redactedObj = JSON.parse(redacted);
|
|
120
|
+
anonymized.patterns = redactedObj.patterns;
|
|
121
|
+
anonymized.metadata = redactedObj.metadata;
|
|
120
122
|
transforms.push('pii-redacted');
|
|
121
123
|
// Generalize timestamps
|
|
122
124
|
anonymized.anonymization.timestampsGeneralized = true;
|
|
@@ -54,13 +54,15 @@ export async function exportPatterns(cfp, options = {}) {
|
|
|
54
54
|
if (!fs.existsSync(dir)) {
|
|
55
55
|
fs.mkdirSync(dir, { recursive: true });
|
|
56
56
|
}
|
|
57
|
-
// Write file
|
|
57
|
+
// Write file atomically
|
|
58
|
+
const tmp = outputPath + '.tmp';
|
|
58
59
|
if (typeof serialized === 'string') {
|
|
59
|
-
fs.writeFileSync(
|
|
60
|
+
fs.writeFileSync(tmp, serialized, 'utf-8');
|
|
60
61
|
}
|
|
61
62
|
else {
|
|
62
|
-
fs.writeFileSync(
|
|
63
|
+
fs.writeFileSync(tmp, serialized);
|
|
63
64
|
}
|
|
65
|
+
fs.renameSync(tmp, outputPath);
|
|
64
66
|
console.log(`Exported to: ${outputPath}`);
|
|
65
67
|
}
|
|
66
68
|
// Calculate pattern count
|
|
@@ -19,6 +19,68 @@ export const IPFS_GATEWAYS = [
|
|
|
19
19
|
'https://dweb.link',
|
|
20
20
|
'https://w3s.link', // web3.storage gateway
|
|
21
21
|
];
|
|
22
|
+
/** Maximum response size for IPFS fetches — prevents OOM on attacker-controlled response bodies */
|
|
23
|
+
const MAX_IPFS_RESPONSE_BYTES = 50 * 1024 * 1024; // 50 MB
|
|
24
|
+
/**
|
|
25
|
+
* Allowlist gateway hosts to prevent SSRF when user-supplied gateways are passed in.
|
|
26
|
+
* Any preferredGateway must match this allowlist.
|
|
27
|
+
*/
|
|
28
|
+
const ALLOWED_GATEWAY_HOSTS = new Set([
|
|
29
|
+
'gateway.pinata.cloud',
|
|
30
|
+
'cloudflare-ipfs.com',
|
|
31
|
+
'ipfs.io',
|
|
32
|
+
'dweb.link',
|
|
33
|
+
'w3s.link',
|
|
34
|
+
]);
|
|
35
|
+
function isAllowedGatewayUrl(url) {
|
|
36
|
+
try {
|
|
37
|
+
const parsed = new URL(url);
|
|
38
|
+
return parsed.protocol === 'https:' && ALLOWED_GATEWAY_HOSTS.has(parsed.hostname);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Fetch a response body with a hard byte cap. Aborts the stream if the limit is exceeded
|
|
46
|
+
* to prevent OOM from attacker-controlled response bodies.
|
|
47
|
+
*/
|
|
48
|
+
async function readBodyWithLimit(response, maxBytes) {
|
|
49
|
+
// Fast-path: trust Content-Length when present
|
|
50
|
+
const lengthHeader = response.headers.get('content-length');
|
|
51
|
+
if (lengthHeader) {
|
|
52
|
+
const declared = parseInt(lengthHeader, 10);
|
|
53
|
+
if (Number.isFinite(declared) && declared > maxBytes) {
|
|
54
|
+
throw new Error(`Response too large: ${declared} bytes (max ${maxBytes})`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
const reader = response.body?.getReader();
|
|
58
|
+
if (!reader)
|
|
59
|
+
return '';
|
|
60
|
+
const chunks = [];
|
|
61
|
+
let total = 0;
|
|
62
|
+
while (true) {
|
|
63
|
+
const { done, value } = await reader.read();
|
|
64
|
+
if (done)
|
|
65
|
+
break;
|
|
66
|
+
if (value) {
|
|
67
|
+
total += value.byteLength;
|
|
68
|
+
if (total > maxBytes) {
|
|
69
|
+
await reader.cancel();
|
|
70
|
+
throw new Error(`Response too large: exceeded ${maxBytes} bytes`);
|
|
71
|
+
}
|
|
72
|
+
chunks.push(value);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Concatenate and decode as UTF-8
|
|
76
|
+
const combined = new Uint8Array(total);
|
|
77
|
+
let offset = 0;
|
|
78
|
+
for (const c of chunks) {
|
|
79
|
+
combined.set(c, offset);
|
|
80
|
+
offset += c.byteLength;
|
|
81
|
+
}
|
|
82
|
+
return new TextDecoder('utf-8').decode(combined);
|
|
83
|
+
}
|
|
22
84
|
/**
|
|
23
85
|
* IPNS resolvers
|
|
24
86
|
*/
|
|
@@ -35,6 +97,10 @@ export const IPNS_RESOLVERS = [
|
|
|
35
97
|
* @returns CID string or null if resolution fails
|
|
36
98
|
*/
|
|
37
99
|
export async function resolveIPNS(ipnsName, preferredGateway) {
|
|
100
|
+
if (!isValidIPNS(ipnsName))
|
|
101
|
+
return null;
|
|
102
|
+
if (preferredGateway && !isAllowedGatewayUrl(preferredGateway))
|
|
103
|
+
return null;
|
|
38
104
|
const resolvers = preferredGateway
|
|
39
105
|
? [preferredGateway, ...IPNS_RESOLVERS.filter(r => r !== preferredGateway)]
|
|
40
106
|
: IPNS_RESOLVERS;
|
|
@@ -50,22 +116,24 @@ export async function resolveIPNS(ipnsName, preferredGateway) {
|
|
|
50
116
|
headers: { 'Accept': 'application/json' },
|
|
51
117
|
});
|
|
52
118
|
if (response.ok) {
|
|
53
|
-
const
|
|
119
|
+
const text = await readBodyWithLimit(response, 64 * 1024); // IPNS resolve is tiny
|
|
120
|
+
const data = JSON.parse(text);
|
|
54
121
|
cid = data.Path?.replace('/ipfs/', '') || null;
|
|
55
122
|
}
|
|
56
123
|
}
|
|
57
|
-
// Method 2: Direct IPNS key resolution via gateway redirect
|
|
124
|
+
// Method 2: Direct IPNS key resolution via gateway redirect.
|
|
125
|
+
// Final URL must still be on a trusted gateway host (SSRF / open-redirect defense)
|
|
126
|
+
// and the extracted CID must pass `isValidCID` to prevent injection.
|
|
58
127
|
if (!cid) {
|
|
59
128
|
const response = await fetch(`${gateway}/ipns/${ipnsName}`, {
|
|
60
129
|
method: 'HEAD',
|
|
61
130
|
signal: AbortSignal.timeout(10000),
|
|
62
131
|
redirect: 'follow',
|
|
63
132
|
});
|
|
64
|
-
if (response.ok) {
|
|
65
|
-
// Extract CID from the final URL after redirects
|
|
133
|
+
if (response.ok && isAllowedGatewayUrl(response.url)) {
|
|
66
134
|
const finalUrl = response.url;
|
|
67
135
|
const cidMatch = finalUrl.match(/\/ipfs\/([a-zA-Z0-9]+)/);
|
|
68
|
-
if (cidMatch) {
|
|
136
|
+
if (cidMatch && isValidCID(cidMatch[1])) {
|
|
69
137
|
cid = cidMatch[1];
|
|
70
138
|
}
|
|
71
139
|
}
|
|
@@ -95,6 +163,9 @@ export async function resolveIPNS(ipnsName, preferredGateway) {
|
|
|
95
163
|
export async function fetchFromIPFS(cid, preferredGateway) {
|
|
96
164
|
if (!isValidCID(cid))
|
|
97
165
|
return null;
|
|
166
|
+
// Reject preferred gateways outside the allowlist (SSRF defense)
|
|
167
|
+
if (preferredGateway && !isAllowedGatewayUrl(preferredGateway))
|
|
168
|
+
return null;
|
|
98
169
|
const gateways = preferredGateway
|
|
99
170
|
? [preferredGateway, ...IPFS_GATEWAYS.filter(g => g !== preferredGateway)]
|
|
100
171
|
: IPFS_GATEWAYS;
|
|
@@ -111,7 +182,8 @@ export async function fetchFromIPFS(cid, preferredGateway) {
|
|
|
111
182
|
},
|
|
112
183
|
});
|
|
113
184
|
if (response.ok) {
|
|
114
|
-
const
|
|
185
|
+
const text = await readBodyWithLimit(response, MAX_IPFS_RESPONSE_BYTES);
|
|
186
|
+
const data = JSON.parse(text);
|
|
115
187
|
const latency = Date.now() - startTime;
|
|
116
188
|
console.log(`[IPFS] Fetched ${cid} from ${gateway} (${latency}ms)`);
|
|
117
189
|
return data;
|
|
@@ -139,6 +211,8 @@ export async function fetchFromIPFS(cid, preferredGateway) {
|
|
|
139
211
|
export async function fetchFromIPFSWithMetadata(cid, preferredGateway) {
|
|
140
212
|
if (!isValidCID(cid))
|
|
141
213
|
return null;
|
|
214
|
+
if (preferredGateway && !isAllowedGatewayUrl(preferredGateway))
|
|
215
|
+
return null;
|
|
142
216
|
const gateways = preferredGateway
|
|
143
217
|
? [preferredGateway, ...IPFS_GATEWAYS.filter(g => g !== preferredGateway)]
|
|
144
218
|
: IPFS_GATEWAYS;
|
|
@@ -153,7 +227,8 @@ export async function fetchFromIPFSWithMetadata(cid, preferredGateway) {
|
|
|
153
227
|
},
|
|
154
228
|
});
|
|
155
229
|
if (response.ok) {
|
|
156
|
-
const
|
|
230
|
+
const text = await readBodyWithLimit(response, MAX_IPFS_RESPONSE_BYTES);
|
|
231
|
+
const data = JSON.parse(text);
|
|
157
232
|
const latencyMs = Date.now() - startTime;
|
|
158
233
|
const cached = response.headers.get('X-Cache')?.includes('HIT') ||
|
|
159
234
|
response.headers.get('CF-Cache-Status') === 'HIT';
|
|
@@ -178,6 +253,8 @@ export async function fetchFromIPFSWithMetadata(cid, preferredGateway) {
|
|
|
178
253
|
export async function isPinned(cid, gateway = 'https://ipfs.io') {
|
|
179
254
|
if (!isValidCID(cid))
|
|
180
255
|
return false;
|
|
256
|
+
if (!isAllowedGatewayUrl(gateway))
|
|
257
|
+
return false;
|
|
181
258
|
try {
|
|
182
259
|
const response = await fetch(`${gateway}/ipfs/${cid}`, {
|
|
183
260
|
method: 'HEAD',
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* IPFS Upload Module
|
|
3
3
|
* Real upload support via web3.storage, Pinata, or local IPFS
|
|
4
4
|
*
|
|
5
|
-
* @module @
|
|
5
|
+
* @module @monomind/cli/transfer/ipfs/upload
|
|
6
6
|
* @version 3.0.0
|
|
7
7
|
*/
|
|
8
8
|
import * as crypto from 'crypto';
|
|
@@ -65,7 +65,10 @@ async function uploadToWeb3Storage(content, options) {
|
|
|
65
65
|
const error = await response.text();
|
|
66
66
|
throw new Error(`Web3.storage upload failed: ${response.status} ${error}`);
|
|
67
67
|
}
|
|
68
|
-
const
|
|
68
|
+
const rawText = await response.arrayBuffer();
|
|
69
|
+
if (rawText.byteLength > 64 * 1024)
|
|
70
|
+
throw new Error('Web3.storage response too large');
|
|
71
|
+
const result = JSON.parse(new TextDecoder().decode(rawText));
|
|
69
72
|
const cid = result.cid;
|
|
70
73
|
const gateway = options.gateway || 'https://w3s.link';
|
|
71
74
|
console.log(`[IPFS] Upload complete!`);
|
|
@@ -115,7 +118,10 @@ async function uploadToPinata(content, options) {
|
|
|
115
118
|
const error = await response.text();
|
|
116
119
|
throw new Error(`Pinata upload failed: ${response.status} ${error}`);
|
|
117
120
|
}
|
|
118
|
-
const
|
|
121
|
+
const rawText2 = await response.arrayBuffer();
|
|
122
|
+
if (rawText2.byteLength > 64 * 1024)
|
|
123
|
+
throw new Error('Pinata response too large');
|
|
124
|
+
const result = JSON.parse(new TextDecoder().decode(rawText2));
|
|
119
125
|
const cid = result.IpfsHash;
|
|
120
126
|
const gateway = options.gateway || 'https://gateway.pinata.cloud';
|
|
121
127
|
console.log(`[IPFS] Upload complete!`);
|
|
@@ -330,7 +336,10 @@ async function uploadToLocalIPFS(content, options) {
|
|
|
330
336
|
const error = await response.text();
|
|
331
337
|
throw new Error(`Local IPFS upload failed: ${response.status} ${error}`);
|
|
332
338
|
}
|
|
333
|
-
const
|
|
339
|
+
const rawText3 = await response.arrayBuffer();
|
|
340
|
+
if (rawText3.byteLength > 64 * 1024)
|
|
341
|
+
throw new Error('Local IPFS response too large');
|
|
342
|
+
const result = JSON.parse(new TextDecoder().decode(rawText3));
|
|
334
343
|
const cid = result.Hash;
|
|
335
344
|
// Try to get external gateway URL if configured
|
|
336
345
|
const gatewayUrl = process.env.IPFS_GATEWAY_URL || options.gateway || 'https://ipfs.io';
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Google Cloud Storage Backend
|
|
3
3
|
* Real storage implementation using gcloud CLI or GCS APIs
|
|
4
4
|
*
|
|
5
|
-
* @module @
|
|
5
|
+
* @module @monomind/cli/transfer/storage/gcs
|
|
6
6
|
* @version 3.0.0
|
|
7
7
|
*/
|
|
8
8
|
import * as crypto from 'crypto';
|
|
@@ -93,15 +93,16 @@ export async function uploadToGCS(content, options = {}) {
|
|
|
93
93
|
console.log(`[GCS] Uploading to gs://${config.bucket}/${objectPath}...`);
|
|
94
94
|
// Write content to temp file
|
|
95
95
|
const tempDir = process.env.TMPDIR || '/tmp';
|
|
96
|
-
const tempFile = path.join(tempDir, `monomind-upload-${
|
|
97
|
-
|
|
96
|
+
const tempFile = path.join(tempDir, `monomind-upload-${crypto.randomUUID()}.json`);
|
|
97
|
+
// wx flag = O_CREAT | O_EXCL — fails if path exists (symlink-attack defense)
|
|
98
|
+
fs.writeFileSync(tempFile, content, { flag: 'wx', mode: 0o600 });
|
|
98
99
|
try {
|
|
99
100
|
// Build gcloud args (array form prevents shell injection)
|
|
100
101
|
const uploadArgs = ['storage', 'cp', tempFile, `gs://${config.bucket}/${objectPath}`];
|
|
101
102
|
if (config.projectId)
|
|
102
103
|
uploadArgs.push(`--project=${config.projectId}`);
|
|
103
104
|
uploadArgs.push(`--content-type=${options.contentType || 'application/json'}`);
|
|
104
|
-
execFileSync('gcloud', uploadArgs, { encoding: 'utf-8', stdio: 'pipe' });
|
|
105
|
+
execFileSync('gcloud', uploadArgs, { encoding: 'utf-8', stdio: 'pipe', timeout: 60000 });
|
|
105
106
|
// Set metadata if provided
|
|
106
107
|
if (options.metadata && Object.keys(options.metadata).length > 0) {
|
|
107
108
|
const metadataJson = JSON.stringify(options.metadata);
|
|
@@ -109,7 +110,7 @@ export async function uploadToGCS(content, options = {}) {
|
|
|
109
110
|
const metaArgs = ['storage', 'objects', 'update', `gs://${config.bucket}/${objectPath}`, `--custom-metadata=${metadataJson}`];
|
|
110
111
|
if (config.projectId)
|
|
111
112
|
metaArgs.push(`--project=${config.projectId}`);
|
|
112
|
-
execFileSync('gcloud', metaArgs, { encoding: 'utf-8', stdio: 'pipe' });
|
|
113
|
+
execFileSync('gcloud', metaArgs, { encoding: 'utf-8', stdio: 'pipe', timeout: 60000 });
|
|
113
114
|
}
|
|
114
115
|
catch {
|
|
115
116
|
// Metadata update failed, but upload succeeded
|
|
@@ -152,10 +153,14 @@ export async function downloadFromGCS(uri, config) {
|
|
|
152
153
|
console.log(`[GCS] Downloading from ${uri}...`);
|
|
153
154
|
// Write to temp file first
|
|
154
155
|
const tempDir = process.env.TMPDIR || '/tmp';
|
|
155
|
-
const tempFile = path.join(tempDir, `monomind-download-${
|
|
156
|
+
const tempFile = path.join(tempDir, `monomind-download-${crypto.randomUUID()}.json`);
|
|
157
|
+
if (!uri.startsWith('gs://')) {
|
|
158
|
+
console.error('[GCS] Invalid URI: must start with gs://');
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
156
161
|
try {
|
|
157
|
-
// Download using gcloud storage cp
|
|
158
|
-
const downloadArgs = ['storage', 'cp', uri, tempFile];
|
|
162
|
+
// Download using gcloud storage cp; '--' prevents URI from being parsed as a flag
|
|
163
|
+
const downloadArgs = ['storage', 'cp', '--', uri, tempFile];
|
|
159
164
|
if (cfg?.projectId)
|
|
160
165
|
downloadArgs.push(`--project=${cfg.projectId}`);
|
|
161
166
|
execFileSync('gcloud', downloadArgs, { encoding: 'utf-8', stdio: 'pipe' });
|
|
@@ -184,8 +189,10 @@ export async function downloadFromGCS(uri, config) {
|
|
|
184
189
|
*/
|
|
185
190
|
export async function existsInGCS(uri, config) {
|
|
186
191
|
const cfg = config || getGCSConfig();
|
|
192
|
+
if (!uri.startsWith('gs://'))
|
|
193
|
+
return false;
|
|
187
194
|
try {
|
|
188
|
-
const lsArgs = ['storage', 'ls', uri];
|
|
195
|
+
const lsArgs = ['storage', 'ls', '--', uri];
|
|
189
196
|
if (cfg?.projectId)
|
|
190
197
|
lsArgs.push(`--project=${cfg.projectId}`);
|
|
191
198
|
execFileSync('gcloud', lsArgs, { encoding: 'utf-8', stdio: 'pipe' });
|
|
@@ -225,8 +232,10 @@ export async function listGCSObjects(prefix, config) {
|
|
|
225
232
|
*/
|
|
226
233
|
export async function deleteFromGCS(uri, config) {
|
|
227
234
|
const cfg = config || getGCSConfig();
|
|
235
|
+
if (!uri.startsWith('gs://'))
|
|
236
|
+
return false;
|
|
228
237
|
try {
|
|
229
|
-
const rmArgs = ['storage', 'rm', uri];
|
|
238
|
+
const rmArgs = ['storage', 'rm', '--', uri];
|
|
230
239
|
if (cfg?.projectId)
|
|
231
240
|
rmArgs.push(`--project=${cfg.projectId}`);
|
|
232
241
|
execFileSync('gcloud', rmArgs, { encoding: 'utf-8', stdio: 'pipe' });
|
|
@@ -53,9 +53,14 @@ export declare class PatternDiscovery {
|
|
|
53
53
|
*/
|
|
54
54
|
private getGenesisRegistry;
|
|
55
55
|
/**
|
|
56
|
-
* Verify registry signature
|
|
56
|
+
* Verify registry signature.
|
|
57
|
+
*
|
|
58
|
+
* DEPRECATED: Do not use this method. It was a length-only stub. Real
|
|
59
|
+
* verification must use `verifyRegistrySignature` from registry.ts which
|
|
60
|
+
* performs Ed25519 verification. This stub is preserved only to avoid
|
|
61
|
+
* breaking callers that imported it; it now always returns false.
|
|
57
62
|
*/
|
|
58
|
-
verifyRegistry(
|
|
63
|
+
verifyRegistry(_registry: PatternRegistry, _expectedPublicKey: string): boolean;
|
|
59
64
|
/**
|
|
60
65
|
* Get cached registry
|
|
61
66
|
*/
|
|
@@ -63,6 +68,8 @@ export declare class PatternDiscovery {
|
|
|
63
68
|
/**
|
|
64
69
|
* Cache registry
|
|
65
70
|
*/
|
|
71
|
+
private static readonly MAX_REGISTRY_CACHE;
|
|
72
|
+
private static readonly MAX_IPNS_CACHE;
|
|
66
73
|
cacheRegistry(ipnsName: string, registry: PatternRegistry): void;
|
|
67
74
|
/**
|
|
68
75
|
* Clear cache
|
|
@@ -66,11 +66,41 @@ export class PatternDiscovery {
|
|
|
66
66
|
error: 'Failed to fetch registry from IPFS',
|
|
67
67
|
};
|
|
68
68
|
}
|
|
69
|
-
// Verify registry
|
|
70
|
-
|
|
71
|
-
|
|
69
|
+
// Verify registry — fail closed for trusted registries.
|
|
70
|
+
// Previously this only warn-and-continued, and the `&& registry.registrySignature`
|
|
71
|
+
// guard meant an attacker could simply omit the signature to bypass verification entirely.
|
|
72
|
+
if (knownRegistry.trusted) {
|
|
73
|
+
// Use the real Ed25519 verifier from registry.ts, not the stub length-check below
|
|
74
|
+
const { verifyRegistrySignature } = await import('./registry.js');
|
|
75
|
+
const expected = knownRegistry.publicKey;
|
|
76
|
+
if (!registry.registrySignature || !registry.registryPublicKey) {
|
|
77
|
+
return {
|
|
78
|
+
success: false,
|
|
79
|
+
source: knownRegistry.name,
|
|
80
|
+
fromCache: false,
|
|
81
|
+
cid: resolution.cid,
|
|
82
|
+
error: 'Trusted registry response is missing required signature/publicKey fields',
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
// Pin the public key to the known registry's expected key
|
|
86
|
+
if (registry.registryPublicKey !== expected) {
|
|
87
|
+
return {
|
|
88
|
+
success: false,
|
|
89
|
+
source: knownRegistry.name,
|
|
90
|
+
fromCache: false,
|
|
91
|
+
cid: resolution.cid,
|
|
92
|
+
error: 'Registry public key does not match pinned trusted key',
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
const verified = await verifyRegistrySignature(registry);
|
|
72
96
|
if (!verified) {
|
|
73
|
-
|
|
97
|
+
return {
|
|
98
|
+
success: false,
|
|
99
|
+
source: knownRegistry.name,
|
|
100
|
+
fromCache: false,
|
|
101
|
+
cid: resolution.cid,
|
|
102
|
+
error: 'Registry signature verification failed',
|
|
103
|
+
};
|
|
74
104
|
}
|
|
75
105
|
}
|
|
76
106
|
// Cache the result
|
|
@@ -115,6 +145,11 @@ export class PatternDiscovery {
|
|
|
115
145
|
resolvedAt: new Date().toISOString(),
|
|
116
146
|
expiresAt: new Date(Date.now() + 3600000).toISOString(), // 1 hour
|
|
117
147
|
};
|
|
148
|
+
if (this.ipnsCache.size >= PatternDiscovery.MAX_IPNS_CACHE && !this.ipnsCache.has(ipnsName)) {
|
|
149
|
+
const oldest = this.ipnsCache.keys().next().value;
|
|
150
|
+
if (oldest !== undefined)
|
|
151
|
+
this.ipnsCache.delete(oldest);
|
|
152
|
+
}
|
|
118
153
|
this.ipnsCache.set(ipnsName, resolution);
|
|
119
154
|
console.log(`[Discovery] Resolved IPNS to CID: ${cid}`);
|
|
120
155
|
return resolution;
|
|
@@ -138,6 +173,11 @@ export class PatternDiscovery {
|
|
|
138
173
|
resolvedAt: new Date().toISOString(),
|
|
139
174
|
expiresAt: new Date(Date.now() + 3600000).toISOString(),
|
|
140
175
|
};
|
|
176
|
+
if (this.ipnsCache.size >= PatternDiscovery.MAX_IPNS_CACHE && !this.ipnsCache.has(ipnsName)) {
|
|
177
|
+
const oldest = this.ipnsCache.keys().next().value;
|
|
178
|
+
if (oldest !== undefined)
|
|
179
|
+
this.ipnsCache.delete(oldest);
|
|
180
|
+
}
|
|
141
181
|
this.ipnsCache.set(ipnsName, resolution);
|
|
142
182
|
console.log(`[Discovery] Resolved IPNS via redirect to CID: ${cid}`);
|
|
143
183
|
return resolution;
|
|
@@ -313,20 +353,28 @@ export class PatternDiscovery {
|
|
|
313
353
|
featured: ['seraphine-genesis-v1'],
|
|
314
354
|
trending: ['seraphine-genesis-v1'],
|
|
315
355
|
newest: ['seraphine-genesis-v1'],
|
|
316
|
-
|
|
356
|
+
// No signature on the genesis fallback. Previously this slot used
|
|
357
|
+
// `crypto.randomBytes(32)` which is meaningless by construction — every
|
|
358
|
+
// call would produce a different "valid" signature that no real key
|
|
359
|
+
// signed. Trusted-registry callers must reject this fallback (the
|
|
360
|
+
// verification path requires `registrySignature` to be present and
|
|
361
|
+
// verified against a pinned public key).
|
|
317
362
|
registryPublicKey: 'ed25519:monomind-registry-key',
|
|
318
363
|
};
|
|
319
364
|
}
|
|
320
365
|
/**
|
|
321
|
-
* Verify registry signature
|
|
366
|
+
* Verify registry signature.
|
|
367
|
+
*
|
|
368
|
+
* DEPRECATED: Do not use this method. It was a length-only stub. Real
|
|
369
|
+
* verification must use `verifyRegistrySignature` from registry.ts which
|
|
370
|
+
* performs Ed25519 verification. This stub is preserved only to avoid
|
|
371
|
+
* breaking callers that imported it; it now always returns false.
|
|
322
372
|
*/
|
|
323
|
-
verifyRegistry(
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
// For demo: Check signature length
|
|
329
|
-
return registry.registrySignature.length === 64;
|
|
373
|
+
verifyRegistry(_registry, _expectedPublicKey) {
|
|
374
|
+
// Always return false — the call site at line 117 was already migrated to
|
|
375
|
+
// the real verifier. Any other caller using this stub is treated as a
|
|
376
|
+
// verification failure (fail-closed).
|
|
377
|
+
return false;
|
|
330
378
|
}
|
|
331
379
|
/**
|
|
332
380
|
* Get cached registry
|
|
@@ -341,7 +389,14 @@ export class PatternDiscovery {
|
|
|
341
389
|
/**
|
|
342
390
|
* Cache registry
|
|
343
391
|
*/
|
|
392
|
+
static MAX_REGISTRY_CACHE = 50;
|
|
393
|
+
static MAX_IPNS_CACHE = 200;
|
|
344
394
|
cacheRegistry(ipnsName, registry) {
|
|
395
|
+
if (this.cache.size >= PatternDiscovery.MAX_REGISTRY_CACHE && !this.cache.has(ipnsName)) {
|
|
396
|
+
const oldest = this.cache.keys().next().value;
|
|
397
|
+
if (oldest !== undefined)
|
|
398
|
+
this.cache.delete(oldest);
|
|
399
|
+
}
|
|
345
400
|
this.cache.set(ipnsName, {
|
|
346
401
|
registry,
|
|
347
402
|
expiresAt: Date.now() + this.config.cacheExpiry,
|
|
@@ -11,10 +11,6 @@ export type DownloadProgressCallback = (progress: {
|
|
|
11
11
|
totalBytes: number;
|
|
12
12
|
percentage: number;
|
|
13
13
|
}) => void;
|
|
14
|
-
/**
|
|
15
|
-
* Pattern Downloader
|
|
16
|
-
* Handles secure download and verification of patterns
|
|
17
|
-
*/
|
|
18
14
|
export declare class PatternDownloader {
|
|
19
15
|
private config;
|
|
20
16
|
private downloadCache;
|
|
@@ -36,11 +32,24 @@ export declare class PatternDownloader {
|
|
|
36
32
|
*/
|
|
37
33
|
private verifyChecksum;
|
|
38
34
|
/**
|
|
39
|
-
* Verify content signature using
|
|
35
|
+
* Verify content signature using real Ed25519.
|
|
36
|
+
*
|
|
37
|
+
* CRITICAL FIX: Previously this used HMAC-SHA256 keyed with the *public* key —
|
|
38
|
+
* which is a no-op for security since the key is, by definition, public.
|
|
39
|
+
* Anyone reading the registry could recompute a valid "signature".
|
|
40
|
+
* The fallback at the bottom returned true for length>20, which made the
|
|
41
|
+
* function effectively a length check rather than a signature check.
|
|
42
|
+
* Now uses @noble/ed25519 verifyAsync, the same library used in publish.ts,
|
|
43
|
+
* and fails closed on any error.
|
|
40
44
|
*/
|
|
41
45
|
private verifySignature;
|
|
42
46
|
/**
|
|
43
|
-
* Resolve output path for pattern
|
|
47
|
+
* Resolve output path for pattern.
|
|
48
|
+
*
|
|
49
|
+
* CRITICAL: pattern.name and pattern.version come from registry data fetched
|
|
50
|
+
* over the network. Without strict validation, an attacker who controls the
|
|
51
|
+
* registry response can write to arbitrary paths (e.g. ~/.claude/helpers/
|
|
52
|
+
* hook-handler.cjs) via traversal sequences in pattern.name.
|
|
44
53
|
*/
|
|
45
54
|
private resolveOutputPath;
|
|
46
55
|
/**
|