monomind 1.14.6 → 1.15.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/reengineer-squad/boss.md +113 -0
- package/.claude/agents/reengineer-squad/critic-architect.md +132 -0
- package/.claude/agents/reengineer-squad/git-manager.md +145 -0
- package/.claude/agents/reengineer-squad/idea-generator.md +95 -0
- package/.claude/agents/reengineer-squad/implementer.md +112 -0
- package/.claude/agents/reengineer-squad/integration-planner.md +112 -0
- package/.claude/agents/reengineer-squad/source-analyst.md +103 -0
- package/.claude/agents/reengineer-squad/target-analyst.md +118 -0
- package/.claude/agents/reengineer-squad/tester.md +105 -0
- package/.claude/commands/mastermind/master.md +35 -14
- package/.claude/helpers/handlers/capture-handler.cjs +155 -18
- package/.claude/helpers/monolean-activate.cjs +20 -0
- package/.claude/helpers/monolean-config.cjs +76 -0
- package/.claude/helpers/monolean-instructions.cjs +109 -0
- package/.claude/helpers/monolean-propagate.cjs +9 -0
- package/.claude/helpers/monolean-tracker.cjs +18 -0
- package/.claude/helpers/skill-registry.json +2 -2
- package/.claude/settings.json +34 -2
- package/.claude/skills/agent-browser-testing/SKILL.md +301 -18
- package/.claude/skills/mastermind/runorg.md +69 -23
- package/.claude/skills/monodesign/SKILL.md +32 -1
- package/.claude/skills/monodesign/adapt.md +53 -0
- package/.claude/skills/monodesign/agents/monodesign-asset-producer.md +100 -0
- package/.claude/skills/monodesign/animate.md +65 -0
- package/.claude/skills/monodesign/audit.md +89 -0
- package/.claude/skills/monodesign/bolder.md +50 -0
- package/.claude/skills/monodesign/clarify.md +64 -0
- package/.claude/skills/monodesign/colorize.md +68 -0
- package/.claude/skills/monodesign/craft.md +51 -0
- package/.claude/skills/monodesign/critique.md +66 -0
- package/.claude/skills/monodesign/delight.md +47 -0
- package/.claude/skills/monodesign/distill.md +56 -0
- package/.claude/skills/monodesign/document.md +80 -0
- package/.claude/skills/monodesign/extract.md +74 -0
- package/.claude/skills/monodesign/harden.md +65 -0
- package/.claude/skills/monodesign/live.md +59 -0
- package/.claude/skills/monodesign/onboard.md +50 -0
- package/.claude/skills/monodesign/optimize.md +64 -0
- package/.claude/skills/monodesign/overdrive.md +56 -0
- package/.claude/skills/monodesign/polish.md +68 -0
- package/.claude/skills/monodesign/quieter.md +57 -0
- package/.claude/skills/monodesign/reference/antipatterns-catalog.md +248 -76
- package/.claude/skills/monodesign/reference/codex.md +107 -0
- package/.claude/skills/monodesign/reference/craft.md +3 -0
- package/.claude/skills/monodesign/reference/hooks.md +99 -0
- package/.claude/skills/monodesign/reference/image-prompts.md +12 -0
- package/.claude/skills/monodesign/shape.md +71 -0
- package/.claude/skills/monodesign/teach.md +69 -0
- package/.claude/skills/monodesign/typeset.md +59 -0
- package/.claude/skills/monolean/SKILL.md +118 -0
- package/.claude/skills/monolean-audit/SKILL.md +41 -0
- package/.claude/skills/monolean-debt/SKILL.md +46 -0
- package/.claude/skills/monolean-help/SKILL.md +60 -0
- package/.claude/skills/monolean-review/SKILL.md +57 -0
- package/package.json +8 -2
- package/packages/@monomind/cli/bin/cli.js +3 -1
- package/packages/@monomind/cli/dist/dashboard/server.js +137 -0
- package/packages/@monomind/cli/dist/src/__tests__/browse-adapters.test.d.ts +2 -0
- package/packages/@monomind/cli/dist/src/__tests__/browse-adapters.test.js +51 -0
- package/packages/@monomind/cli/dist/src/__tests__/browse-analyzer.test.d.ts +2 -0
- package/packages/@monomind/cli/dist/src/__tests__/browse-analyzer.test.js +68 -0
- package/packages/@monomind/cli/dist/src/__tests__/browse-builtin-handlers.test.d.ts +2 -0
- package/packages/@monomind/cli/dist/src/__tests__/browse-builtin-handlers.test.js +139 -0
- package/packages/@monomind/cli/dist/src/__tests__/browse-cdp.test.d.ts +2 -0
- package/packages/@monomind/cli/dist/src/__tests__/browse-cdp.test.js +169 -0
- package/packages/@monomind/cli/dist/src/__tests__/browse-dashboard.test.d.ts +2 -0
- package/packages/@monomind/cli/dist/src/__tests__/browse-dashboard.test.js +179 -0
- package/packages/@monomind/cli/dist/src/__tests__/browse-engine.test.d.ts +2 -0
- package/packages/@monomind/cli/dist/src/__tests__/browse-engine.test.js +122 -0
- package/packages/@monomind/cli/dist/src/__tests__/browse-expression.test.d.ts +2 -0
- package/packages/@monomind/cli/dist/src/__tests__/browse-expression.test.js +54 -0
- package/packages/@monomind/cli/dist/src/__tests__/browse-store.test.d.ts +2 -0
- package/packages/@monomind/cli/dist/src/__tests__/browse-store.test.js +99 -0
- package/packages/@monomind/cli/dist/src/__tests__/browse-workflow-types.test.d.ts +2 -0
- package/packages/@monomind/cli/dist/src/__tests__/browse-workflow-types.test.js +33 -0
- package/packages/@monomind/cli/dist/src/browser/action-builder/analyzer.d.ts +11 -0
- package/packages/@monomind/cli/dist/src/browser/action-builder/analyzer.js +71 -0
- package/packages/@monomind/cli/dist/src/browser/action-builder/types.d.ts +47 -0
- package/packages/@monomind/cli/dist/src/browser/action-builder/types.js +2 -0
- package/packages/@monomind/cli/dist/src/browser/adapters/gemini.d.ts +3 -0
- package/packages/@monomind/cli/dist/src/browser/adapters/gemini.js +16 -0
- package/packages/@monomind/cli/dist/src/browser/adapters/google.d.ts +3 -0
- package/packages/@monomind/cli/dist/src/browser/adapters/google.js +17 -0
- package/packages/@monomind/cli/dist/src/browser/adapters/index.d.ts +19 -0
- package/packages/@monomind/cli/dist/src/browser/adapters/index.js +23 -0
- package/packages/@monomind/cli/dist/src/browser/adapters/instagram.d.ts +3 -0
- package/packages/@monomind/cli/dist/src/browser/adapters/instagram.js +17 -0
- package/packages/@monomind/cli/dist/src/browser/adapters/linkedin.d.ts +3 -0
- package/packages/@monomind/cli/dist/src/browser/adapters/linkedin.js +19 -0
- package/packages/@monomind/cli/dist/src/browser/adapters/microsoft.d.ts +3 -0
- package/packages/@monomind/cli/dist/src/browser/adapters/microsoft.js +16 -0
- package/packages/@monomind/cli/dist/src/browser/adapters/x.d.ts +3 -0
- package/packages/@monomind/cli/dist/src/browser/adapters/x.js +19 -0
- package/packages/@monomind/cli/dist/src/browser/dashboard/api-types.d.ts +50 -0
- package/packages/@monomind/cli/dist/src/browser/dashboard/api-types.js +14 -0
- package/packages/@monomind/cli/dist/src/browser/dashboard/server.d.ts +9 -0
- package/packages/@monomind/cli/dist/src/browser/dashboard/server.js +62 -0
- package/packages/@monomind/cli/dist/src/browser/dashboard/ui.html +1811 -0
- package/packages/@monomind/cli/dist/src/browser/workflow/builtin-handlers.d.ts +3 -0
- package/packages/@monomind/cli/dist/src/browser/workflow/builtin-handlers.js +343 -0
- package/packages/@monomind/cli/dist/src/browser/workflow/engine.d.ts +15 -0
- package/packages/@monomind/cli/dist/src/browser/workflow/engine.js +127 -0
- package/packages/@monomind/cli/dist/src/browser/workflow/expression.d.ts +4 -0
- package/packages/@monomind/cli/dist/src/browser/workflow/expression.js +64 -0
- package/packages/@monomind/cli/dist/src/browser/workflow/store.d.ts +24 -0
- package/packages/@monomind/cli/dist/src/browser/workflow/store.js +145 -0
- package/packages/@monomind/cli/dist/src/browser/workflow/types.d.ts +48 -0
- package/packages/@monomind/cli/dist/src/browser/workflow/types.js +2 -0
- package/packages/@monomind/cli/dist/src/commands/browse-action.d.ts +4 -0
- package/packages/@monomind/cli/dist/src/commands/browse-action.js +151 -0
- package/packages/@monomind/cli/dist/src/commands/browse-platform.d.ts +4 -0
- package/packages/@monomind/cli/dist/src/commands/browse-platform.js +117 -0
- package/packages/@monomind/cli/dist/src/commands/browse-workflow.d.ts +4 -0
- package/packages/@monomind/cli/dist/src/commands/browse-workflow.js +153 -0
- package/packages/@monomind/cli/dist/src/commands/browse.d.ts +10 -6
- package/packages/@monomind/cli/dist/src/commands/browse.js +11 -2154
- package/packages/@monomind/cli/dist/src/commands/design-detect.d.ts +21 -0
- package/packages/@monomind/cli/dist/src/commands/design-detect.js +127 -0
- package/packages/@monomind/cli/dist/src/commands/design-palette.d.ts +22 -0
- package/packages/@monomind/cli/dist/src/commands/design-palette.js +539 -0
- package/packages/@monomind/cli/dist/src/commands/hooks-core-commands.d.ts +10 -0
- package/packages/@monomind/cli/dist/src/commands/hooks-core-commands.js +377 -0
- package/packages/@monomind/cli/dist/src/commands/hooks-coverage-commands.d.ts +12 -0
- package/packages/@monomind/cli/dist/src/commands/hooks-coverage-commands.js +1217 -0
- package/packages/@monomind/cli/dist/src/commands/hooks-coverage-utils.d.ts +42 -0
- package/packages/@monomind/cli/dist/src/commands/hooks-coverage-utils.js +220 -0
- package/packages/@monomind/cli/dist/src/commands/hooks-extended-commands.d.ts +14 -0
- package/packages/@monomind/cli/dist/src/commands/hooks-extended-commands.js +579 -0
- package/packages/@monomind/cli/dist/src/commands/hooks-formatting.d.ts +13 -0
- package/packages/@monomind/cli/dist/src/commands/hooks-formatting.js +42 -0
- package/packages/@monomind/cli/dist/src/commands/hooks-routing-commands.d.ts +15 -0
- package/packages/@monomind/cli/dist/src/commands/hooks-routing-commands.js +723 -0
- package/packages/@monomind/cli/dist/src/commands/hooks-workers.d.ts +9 -0
- package/packages/@monomind/cli/dist/src/commands/hooks-workers.js +782 -0
- package/packages/@monomind/cli/dist/src/commands/hooks.d.ts +8 -0
- package/packages/@monomind/cli/dist/src/commands/hooks.js +179 -4103
- package/packages/@monomind/cli/dist/src/commands/index.d.ts +1 -0
- package/packages/@monomind/cli/dist/src/commands/index.js +6 -0
- package/packages/@monomind/cli/dist/src/commands/org.js +14 -15
- package/packages/@monomind/cli/dist/src/commands/tokens.js +77 -1
- package/packages/@monomind/cli/dist/src/graph/enrich.mjs +362 -0
- package/packages/@monomind/cli/dist/src/init/executor.js +18 -8
- package/packages/@monomind/cli/dist/src/init/settings-generator.js +39 -5
- package/packages/@monomind/cli/dist/src/init/statusline-generator.js +25 -5
- package/packages/@monomind/cli/dist/src/mcp-tools/browser-tools.d.ts +3 -5
- package/packages/@monomind/cli/dist/src/mcp-tools/browser-tools.js +619 -326
- package/packages/@monomind/cli/dist/src/mcp-tools/hooks-embedding.d.ts +161 -0
- package/packages/@monomind/cli/dist/src/mcp-tools/hooks-embedding.js +506 -0
- package/packages/@monomind/cli/dist/src/mcp-tools/hooks-intelligence.d.ts +26 -0
- package/packages/@monomind/cli/dist/src/mcp-tools/hooks-intelligence.js +1328 -0
- package/packages/@monomind/cli/dist/src/mcp-tools/hooks-routing.d.ts +27 -0
- package/packages/@monomind/cli/dist/src/mcp-tools/hooks-routing.js +1591 -0
- package/packages/@monomind/cli/dist/src/mcp-tools/hooks-tools.d.ts +3 -38
- package/packages/@monomind/cli/dist/src/mcp-tools/hooks-tools.js +5 -3393
- package/packages/@monomind/cli/dist/src/mcp-tools/monograph-tools.js +24 -14
- package/packages/@monomind/cli/dist/src/mcp-tools/workflow-tools.js +54 -1
- package/packages/@monomind/cli/dist/src/memory/embedding-operations.d.ts +58 -0
- package/packages/@monomind/cli/dist/src/memory/embedding-operations.js +299 -0
- package/packages/@monomind/cli/dist/src/memory/ewc-consolidation.js +37 -3
- package/packages/@monomind/cli/dist/src/memory/hnsw-operations.d.ts +130 -0
- package/packages/@monomind/cli/dist/src/memory/hnsw-operations.js +400 -0
- package/packages/@monomind/cli/dist/src/memory/intelligence.js +42 -23
- package/packages/@monomind/cli/dist/src/memory/memory-bridge.js +52 -8
- package/packages/@monomind/cli/dist/src/memory/memory-crud.d.ts +67 -0
- package/packages/@monomind/cli/dist/src/memory/memory-crud.js +415 -0
- package/packages/@monomind/cli/dist/src/memory/memory-initializer.d.ts +9 -322
- package/packages/@monomind/cli/dist/src/memory/memory-initializer.js +17 -1794
- package/packages/@monomind/cli/dist/src/memory/memory-migrations.d.ts +30 -0
- package/packages/@monomind/cli/dist/src/memory/memory-migrations.js +134 -0
- package/packages/@monomind/cli/dist/src/memory/memory-read.d.ts +78 -0
- package/packages/@monomind/cli/dist/src/memory/memory-read.js +331 -0
- package/packages/@monomind/cli/dist/src/memory/memory-schema.d.ts +13 -0
- package/packages/@monomind/cli/dist/src/memory/memory-schema.js +167 -0
- package/packages/@monomind/cli/dist/src/memory/sona-optimizer.js +37 -4
- package/packages/@monomind/cli/dist/src/monovector/route-outcomes.js +16 -6
- package/packages/@monomind/cli/dist/src/pricing/model-pricing.d.ts +41 -0
- package/packages/@monomind/cli/dist/src/pricing/model-pricing.js +61 -0
- package/packages/@monomind/cli/dist/src/ui/.monomind/capture/active-run.json +1 -0
- package/packages/@monomind/cli/dist/src/ui/collector.mjs +799 -0
- package/packages/@monomind/cli/dist/src/ui/dashboard.html +13986 -0
- package/packages/@monomind/cli/dist/src/ui/data/agent-avatars.html +763 -0
- package/packages/@monomind/cli/dist/src/ui/data/agent-avatars.json +966 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/account-strategist.svg +58 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/accounts-payable.svg +54 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/adaptive-coordinator.svg +55 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/adaptive-coordinator2.svg +54 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/ai-citation.svg +57 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/ai-engineer.svg +61 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/analytics-reporter.svg +53 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/api-tester.svg +53 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/architecture.svg +54 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/automation-governance.svg +55 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/backend-dev.svg +53 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/benchmarker.svg +54 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/blockchain-auditor.svg +53 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/byzantine-coord.svg +57 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/case-analyst.svg +57 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/cicd-engineer.svg +55 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/cloud-architect.svg +54 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/code-review-swarm.svg +57 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/coder-v119.svg +57 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/coder.svg +58 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/collective-coord.svg +54 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/compliance-auditor.svg +58 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/consensus-coordinator.svg +54 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/content-creator.svg +54 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/crdt-synchronizer.svg +53 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/cro-specialist.svg +58 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/data-consolidator.svg +54 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/data-engineer.svg +53 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/database-optimizer.svg +61 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/deal-strategist.svg +54 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/defender.svg +53 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/devops-automator.svg +56 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/discovery-coach.svg +54 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/email-marketing.svg +57 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/embedded-firmware.svg +61 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/evidence-collector.svg +57 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/experiment-tracker.svg +53 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/feedback-synthesizer.svg +54 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/finance-tracker.svg +54 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/frontend-developer.svg +54 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/game-audio-engineer.svg +59 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/game-designer.svg +54 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/gossip-coordinator.svg +54 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/hierarchical-coord.svg +54 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/incident-commander.svg +57 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/infrastructure.svg +54 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/input-validator.svg +53 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/ios-developer.svg +54 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/issue-tracker.svg +53 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/judge.svg +55 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/launch-strategist.svg +54 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/legal-compliance.svg +53 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/level-designer.svg +53 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/load-balancer.svg +57 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/mcp-builder.svg +53 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/memory-coordinator.svg +55 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/mesh-coordinator.svg +55 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/ml-developer.svg +58 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/mobile-app-builder.svg +53 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/mobile-dev.svg +54 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/model-qa.svg +58 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/narrative-designer.svg +58 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/outbound-strategist.svg +55 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/path-validator.svg +54 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/payment-agent.svg +53 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/perf-analyzer.svg +58 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/pipeline-analyst.svg +54 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/planner.svg +55 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/pr-manager.svg +54 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/pricing-strategist.svg +54 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/product-manager.svg +54 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/production-validator.svg +54 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/project-shepherd.svg +54 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/proposal-strategist.svg +54 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/prosecutor.svg +57 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/pseudocode.svg +53 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/queen-coordinator.svg +55 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/quorum-manager.svg +53 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/raft-manager.svg +53 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/reality-checker.svg +58 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/recruitment.svg +58 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/refinement.svg +53 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/release-manager.svg +54 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/repo-architect.svg +54 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/researcher.svg +58 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/resource-allocator.svg +53 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/reviewer.svg +53 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/safe-executor.svg +53 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/sales-coach.svg +53 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/sales-engineer.svg +58 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/scout-explorer.svg +58 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/security-architect.svg +54 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/security-auditor.svg +55 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/senior-developer.svg +58 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/senior-pm.svg +58 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/seo-specialist.svg +57 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/social-media.svg +54 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/solidity-engineer.svg +58 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/sparc-coder.svg +58 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/sparc-coord.svg +56 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/specification.svg +57 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/sprint-prioritizer.svg +53 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/sre.svg +54 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/studio-operations.svg +53 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/studio-producer.svg +55 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/support-responder.svg +56 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/system-architect.svg +54 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/task-orchestrator.svg +56 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/technical-artist.svg +53 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/technical-writer.svg +59 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/tester.svg +53 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/threat-detection.svg +61 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/trend-researcher.svg +54 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/trial-director.svg +55 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/unity-architect.svg +54 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/visionos-engineer.svg +57 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/worker-specialist.svg +55 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/workflow-architect.svg +57 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/workflow-automation.svg +54 -0
- package/packages/@monomind/cli/dist/src/ui/data/avatars/zk-steward.svg +54 -0
- package/packages/@monomind/cli/dist/src/ui/data/known-projects.json +1 -0
- package/packages/@monomind/cli/dist/src/ui/data/mastermind-sessions.json +1 -0
- package/packages/@monomind/cli/dist/src/ui/data/sessions/_index.json +1 -0
- package/packages/@monomind/cli/dist/src/ui/orgs.html +2215 -0
- package/packages/@monomind/cli/dist/src/ui/server.mjs +6175 -0
- package/packages/@monomind/cli/dist/src/ui/sse-manager.mjs +119 -0
- package/packages/@monomind/cli/dist/src/update/checker.js +1 -1
- package/packages/@monomind/cli/dist/workflow/builtin-handlers.js +321 -0
- package/packages/@monomind/cli/dist/workflow/engine.js +253 -0
- package/packages/@monomind/cli/dist/workflow/expression.js +98 -0
- package/packages/@monomind/cli/dist/workflow/types.js +2 -0
- package/packages/@monomind/cli/package.json +8 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "monomind",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.15.0",
|
|
4
4
|
"description": "Monomind - Enterprise AI agent orchestration for Claude Code. Deploy 60+ specialized agents in coordinated swarms with self-learning, fault-tolerant consensus, vector memory, and MCP integration",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -20,6 +20,10 @@
|
|
|
20
20
|
"bin/**",
|
|
21
21
|
"packages/@monomind/cli/bin/**",
|
|
22
22
|
"packages/@monomind/cli/dist/**/*.js",
|
|
23
|
+
"packages/@monomind/cli/dist/**/*.mjs",
|
|
24
|
+
"packages/@monomind/cli/dist/**/*.html",
|
|
25
|
+
"packages/@monomind/cli/dist/**/*.json",
|
|
26
|
+
"packages/@monomind/cli/dist/**/*.svg",
|
|
23
27
|
"packages/@monomind/cli/dist/**/*.d.ts",
|
|
24
28
|
"!packages/@monomind/cli/dist/**/*.map",
|
|
25
29
|
"packages/@monomind/cli/bundled-graph/**",
|
|
@@ -56,7 +60,9 @@
|
|
|
56
60
|
},
|
|
57
61
|
"dependencies": {
|
|
58
62
|
"semver": "^7.6.0",
|
|
59
|
-
"@monoes/monograph": "^1.1
|
|
63
|
+
"@monoes/monograph": "^1.2.1",
|
|
64
|
+
"@monoes/monobrowse": "^1.0.0",
|
|
65
|
+
"@monoes/monoplaybook": "^1.0.0"
|
|
60
66
|
},
|
|
61
67
|
"overrides": {
|
|
62
68
|
"hono": ">=4.12.21",
|
|
@@ -214,7 +214,9 @@ if (isMCPMode) {
|
|
|
214
214
|
|
|
215
215
|
const { CLI } = await import('../dist/src/index.js');
|
|
216
216
|
const cli = new CLI();
|
|
217
|
-
cli.run().
|
|
217
|
+
cli.run().then(() => {
|
|
218
|
+
process.exit(process.exitCode ?? 0);
|
|
219
|
+
}).catch((error) => {
|
|
218
220
|
console.error('Fatal error:', safeMsg(error && error.message));
|
|
219
221
|
process.exit(1);
|
|
220
222
|
});
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var _a;
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.startDashboard = startDashboard;
|
|
5
|
+
exports.getDashboard = getDashboard;
|
|
6
|
+
var node_http_1 = require("node:http");
|
|
7
|
+
var node_fs_1 = require("node:fs");
|
|
8
|
+
var node_path_1 = require("node:path");
|
|
9
|
+
var node_url_1 = require("node:url");
|
|
10
|
+
var node_module_1 = require("node:module");
|
|
11
|
+
var _require = (0, node_module_1.createRequire)(import.meta.url);
|
|
12
|
+
var __dirname = (0, node_path_1.dirname)((0, node_url_1.fileURLToPath)(import.meta.url));
|
|
13
|
+
var DEFAULT_PORT = parseInt((_a = process.env['MONOBROWSE_DASHBOARD_PORT']) !== null && _a !== void 0 ? _a : '4242', 10);
|
|
14
|
+
var MAX_RUN_HISTORY = 50;
|
|
15
|
+
var instance = null;
|
|
16
|
+
function startDashboard(port) {
|
|
17
|
+
var _a;
|
|
18
|
+
if (port === void 0) { port = DEFAULT_PORT; }
|
|
19
|
+
if (instance)
|
|
20
|
+
return instance;
|
|
21
|
+
var runHistory = [];
|
|
22
|
+
var stopRequests = new Set();
|
|
23
|
+
var clients = new Set(); // WebSocket or SSE response
|
|
24
|
+
// Try to load ws, fall back to SSE
|
|
25
|
+
var WebSocketServer = null;
|
|
26
|
+
try {
|
|
27
|
+
var wsModule = _require('ws');
|
|
28
|
+
WebSocketServer = (_a = wsModule.WebSocketServer) !== null && _a !== void 0 ? _a : wsModule.Server;
|
|
29
|
+
}
|
|
30
|
+
catch (_b) {
|
|
31
|
+
// ws not available — fall back to SSE
|
|
32
|
+
}
|
|
33
|
+
// ui.html must be copied to dist/ alongside server.js during build
|
|
34
|
+
var uiHtml;
|
|
35
|
+
try {
|
|
36
|
+
uiHtml = (0, node_fs_1.readFileSync)((0, node_path_1.join)(__dirname, 'ui.html'), 'utf-8');
|
|
37
|
+
}
|
|
38
|
+
catch (_c) {
|
|
39
|
+
uiHtml = "<!DOCTYPE html><html><head><title>monobrowse dashboard</title></head><body style=\"background:#0f0f1a;color:#ccc;font-family:system-ui;padding:20px\"><h1>monobrowse dashboard</h1><p>Dashboard UI not found. Run the build to include ui.html.</p><script>const es=new EventSource('/events');es.onmessage=e=>console.log(JSON.parse(e.data));</script></body></html>";
|
|
40
|
+
}
|
|
41
|
+
var server = (0, node_http_1.createServer)(function (req, res) {
|
|
42
|
+
var _a;
|
|
43
|
+
var url = (_a = req.url) !== null && _a !== void 0 ? _a : '/';
|
|
44
|
+
if (url === '/' && req.method === 'GET') {
|
|
45
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
46
|
+
res.end(uiHtml);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (url === '/runs' && req.method === 'GET') {
|
|
50
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
51
|
+
res.end(JSON.stringify(runHistory));
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (url.startsWith('/stop/') && req.method === 'POST') {
|
|
55
|
+
var runId = url.slice(6);
|
|
56
|
+
stopRequests.add(runId);
|
|
57
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
58
|
+
res.end(JSON.stringify({ ok: true, runId: runId }));
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
if (url === '/events' && (req.method === 'GET' || req.method === 'HEAD') && !WebSocketServer) {
|
|
62
|
+
// SSE endpoint (fallback when ws not available).
|
|
63
|
+
// No CORS header — the dashboard is served from 127.0.0.1:4242 and no cross-origin
|
|
64
|
+
// access is needed. A wildcard ACAO would let any web page subscribe to workflow events.
|
|
65
|
+
res.writeHead(200, {
|
|
66
|
+
'Content-Type': 'text/event-stream',
|
|
67
|
+
'Cache-Control': 'no-cache',
|
|
68
|
+
'Connection': 'keep-alive',
|
|
69
|
+
});
|
|
70
|
+
res.write("data: ".concat(JSON.stringify({ type: 'connected' }), "\n\n"));
|
|
71
|
+
clients.add(res);
|
|
72
|
+
req.on('close', function () { return clients.delete(res); });
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
res.writeHead(404);
|
|
76
|
+
res.end('Not found');
|
|
77
|
+
});
|
|
78
|
+
if (WebSocketServer) {
|
|
79
|
+
var wss = new WebSocketServer({ server: server });
|
|
80
|
+
wss.on('connection', function (ws) {
|
|
81
|
+
clients.add(ws);
|
|
82
|
+
ws.send(JSON.stringify({ type: 'history', runs: runHistory }));
|
|
83
|
+
ws.on('close', function () { return clients.delete(ws); });
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
server.on('error', function (err) {
|
|
87
|
+
if (err.code === 'EADDRINUSE') {
|
|
88
|
+
console.error("Dashboard port ".concat(port, " is already in use. Set MONOBROWSE_DASHBOARD_PORT to use a different port."));
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
console.error("Dashboard server error: ".concat(err.message));
|
|
92
|
+
}
|
|
93
|
+
instance = null;
|
|
94
|
+
process.exit(1);
|
|
95
|
+
});
|
|
96
|
+
server.listen(port, '127.0.0.1');
|
|
97
|
+
function broadcast(event) {
|
|
98
|
+
var msg = JSON.stringify(event);
|
|
99
|
+
for (var _i = 0, clients_1 = clients; _i < clients_1.length; _i++) {
|
|
100
|
+
var client = clients_1[_i];
|
|
101
|
+
try {
|
|
102
|
+
if (typeof client.send === 'function') {
|
|
103
|
+
client.send(msg); // WebSocket
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
client.write("data: ".concat(msg, "\n\n")); // SSE
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
catch (_a) {
|
|
110
|
+
clients.delete(client);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
function addRunRecord(record) {
|
|
115
|
+
var idx = runHistory.findIndex(function (r) { return r.id === record.id; });
|
|
116
|
+
if (idx >= 0) {
|
|
117
|
+
runHistory[idx] = record;
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
runHistory.unshift(record);
|
|
121
|
+
if (runHistory.length > MAX_RUN_HISTORY)
|
|
122
|
+
runHistory.pop();
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
function isStopRequested(runId) {
|
|
126
|
+
return stopRequests.has(runId);
|
|
127
|
+
}
|
|
128
|
+
function close() {
|
|
129
|
+
server.close();
|
|
130
|
+
instance = null;
|
|
131
|
+
}
|
|
132
|
+
instance = { broadcast: broadcast, addRunRecord: addRunRecord, isStopRequested: isStopRequested, close: close, port: port };
|
|
133
|
+
return instance;
|
|
134
|
+
}
|
|
135
|
+
function getDashboard() {
|
|
136
|
+
return instance;
|
|
137
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// src/__tests__/browse-adapters.test.ts
|
|
2
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
3
|
+
import { getAdapter, adapters } from '@monoes/monobrowse';
|
|
4
|
+
function mockPage(isLoggedIn, username = 'testuser') {
|
|
5
|
+
return {
|
|
6
|
+
evaluate: vi.fn().mockImplementation((expr) => {
|
|
7
|
+
if (expr.includes('querySelector'))
|
|
8
|
+
return Promise.resolve(isLoggedIn ? true : false);
|
|
9
|
+
return Promise.resolve(username);
|
|
10
|
+
}),
|
|
11
|
+
url: vi.fn().mockResolvedValue('https://example.com'),
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
describe('adapter registry', () => {
|
|
15
|
+
it('has all 6 platforms', () => {
|
|
16
|
+
expect(adapters.size).toBe(6);
|
|
17
|
+
for (const p of ['linkedin', 'instagram', 'x', 'gemini', 'google', 'microsoft']) {
|
|
18
|
+
expect(adapters.has(p)).toBe(true);
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
it('getAdapter throws for unknown platform', () => {
|
|
22
|
+
expect(() => getAdapter('myspace')).toThrow('Unknown platform');
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
describe('each adapter', () => {
|
|
26
|
+
const platforms = ['linkedin', 'instagram', 'x', 'gemini', 'google', 'microsoft'];
|
|
27
|
+
for (const platform of platforms) {
|
|
28
|
+
describe(platform, () => {
|
|
29
|
+
const adapter = getAdapter(platform);
|
|
30
|
+
it('has required fields', () => {
|
|
31
|
+
expect(typeof adapter.platform).toBe('string');
|
|
32
|
+
expect(adapter.baseURL).toMatch(/^https?:\/\//);
|
|
33
|
+
expect(Array.isArray(adapter.reservedPaths)).toBe(true);
|
|
34
|
+
expect(adapter.reservedPaths.length).toBeGreaterThan(0);
|
|
35
|
+
expect(typeof adapter.loginURL()).toBe('string');
|
|
36
|
+
});
|
|
37
|
+
it('isLoggedIn returns boolean', async () => {
|
|
38
|
+
const page = mockPage(true);
|
|
39
|
+
const result = await adapter.isLoggedIn(page);
|
|
40
|
+
expect(typeof result).toBe('boolean');
|
|
41
|
+
});
|
|
42
|
+
it('extractUsername returns string', async () => {
|
|
43
|
+
const page = mockPage(true);
|
|
44
|
+
page.evaluate = vi.fn().mockResolvedValue('johndoe');
|
|
45
|
+
const username = await adapter.extractUsername(page);
|
|
46
|
+
expect(typeof username).toBe('string');
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
//# sourceMappingURL=browse-adapters.test.js.map
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
// Shared mock instance so tests can override `create` per-test
|
|
3
|
+
const mockCreate = vi.fn().mockResolvedValue({
|
|
4
|
+
content: [{
|
|
5
|
+
type: 'text',
|
|
6
|
+
text: JSON.stringify({
|
|
7
|
+
id: 'linkedin:comment_post',
|
|
8
|
+
platform: 'linkedin',
|
|
9
|
+
name: 'Comment on Post',
|
|
10
|
+
params: ['post_url', 'text'],
|
|
11
|
+
steps: [
|
|
12
|
+
{ type: 'navigate', url: '{{params.post_url}}' },
|
|
13
|
+
{ type: 'find', selectors: ['.comment-box'], as: 'box' },
|
|
14
|
+
{ type: 'click', target: '{{box}}' },
|
|
15
|
+
{ type: 'type', target: '{{box}}', text: '{{params.text}}', humanDelay: true },
|
|
16
|
+
{ type: 'wait', condition: 'network_idle', timeout: 3000 },
|
|
17
|
+
],
|
|
18
|
+
}),
|
|
19
|
+
}],
|
|
20
|
+
});
|
|
21
|
+
// Mock Anthropic SDK before importing analyzer
|
|
22
|
+
vi.mock('@anthropic-ai/sdk', () => {
|
|
23
|
+
const MockAnthropic = vi.fn(function () {
|
|
24
|
+
this.messages = { create: mockCreate };
|
|
25
|
+
});
|
|
26
|
+
return { default: MockAnthropic };
|
|
27
|
+
});
|
|
28
|
+
function mockPage(url = 'https://linkedin.com/feed', title = 'LinkedIn') {
|
|
29
|
+
return {
|
|
30
|
+
url: vi.fn().mockResolvedValue(url),
|
|
31
|
+
evaluate: vi.fn().mockImplementation((expr) => {
|
|
32
|
+
if (expr === 'document.title')
|
|
33
|
+
return Promise.resolve(title);
|
|
34
|
+
return Promise.resolve('[]'); // empty elements for DOM capture
|
|
35
|
+
}),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
describe('analyzePageForAction', () => {
|
|
39
|
+
let analyzePageForAction;
|
|
40
|
+
beforeEach(async () => {
|
|
41
|
+
mockCreate.mockClear();
|
|
42
|
+
const mod = await import('@monoes/monobrowse');
|
|
43
|
+
analyzePageForAction = mod.analyzePageForAction;
|
|
44
|
+
});
|
|
45
|
+
it('returns a valid ActionDef from mocked Claude response', async () => {
|
|
46
|
+
const page = mockPage();
|
|
47
|
+
// Pass a dummy key via options (Anthropic SDK is mocked — no real call is made)
|
|
48
|
+
const result = await analyzePageForAction(page, 'comment on a LinkedIn post', { apiKey: 'sk-test' });
|
|
49
|
+
expect(result.id).toBe('linkedin:comment_post');
|
|
50
|
+
expect(result.steps).toHaveLength(5);
|
|
51
|
+
expect(result.params).toContain('text');
|
|
52
|
+
});
|
|
53
|
+
it('throws on invalid JSON from Claude', async () => {
|
|
54
|
+
mockCreate.mockResolvedValueOnce({
|
|
55
|
+
content: [{ type: 'text', text: 'not json at all' }],
|
|
56
|
+
});
|
|
57
|
+
const page = mockPage();
|
|
58
|
+
await expect(analyzePageForAction(page, 'test', { apiKey: 'sk-test' })).rejects.toThrow('invalid JSON');
|
|
59
|
+
});
|
|
60
|
+
it('throws when ActionDef is missing id', async () => {
|
|
61
|
+
mockCreate.mockResolvedValueOnce({
|
|
62
|
+
content: [{ type: 'text', text: JSON.stringify({ steps: [] }) }],
|
|
63
|
+
});
|
|
64
|
+
const page = mockPage();
|
|
65
|
+
await expect(analyzePageForAction(page, 'test', { apiKey: 'sk-test' })).rejects.toThrow('invalid ActionDef');
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
//# sourceMappingURL=browse-analyzer.test.js.map
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
// Mock fs/promises before importing the module under test
|
|
3
|
+
vi.mock('node:fs/promises', () => ({
|
|
4
|
+
writeFile: vi.fn().mockResolvedValue(undefined),
|
|
5
|
+
readFile: vi.fn().mockRejectedValue(new Error('no file')),
|
|
6
|
+
mkdir: vi.fn().mockResolvedValue(undefined),
|
|
7
|
+
chmod: vi.fn().mockResolvedValue(undefined),
|
|
8
|
+
}));
|
|
9
|
+
vi.mock('node:fs', () => ({
|
|
10
|
+
existsSync: vi.fn().mockReturnValue(false),
|
|
11
|
+
}));
|
|
12
|
+
// Mock the browser module so gemini_image CDP path returns null immediately
|
|
13
|
+
vi.mock('../browser/index.js', () => ({
|
|
14
|
+
connectToTarget: vi.fn().mockRejectedValue(new Error('no browser')),
|
|
15
|
+
setCookies: vi.fn(),
|
|
16
|
+
openUrl: vi.fn(),
|
|
17
|
+
findByRole: vi.fn(),
|
|
18
|
+
findBySelector: vi.fn(),
|
|
19
|
+
clickElement: vi.fn(),
|
|
20
|
+
fillElement: vi.fn(),
|
|
21
|
+
pressKey: vi.fn(),
|
|
22
|
+
evaluateJs: vi.fn(),
|
|
23
|
+
getCookies: vi.fn().mockResolvedValue([]),
|
|
24
|
+
getCurrentUrl: vi.fn().mockResolvedValue(''),
|
|
25
|
+
captureScreenshot: vi.fn().mockResolvedValue(null),
|
|
26
|
+
}));
|
|
27
|
+
import { createBuiltinHandlers } from '@monoes/monobrowse';
|
|
28
|
+
import * as fsMock from 'node:fs/promises';
|
|
29
|
+
function makeItem(data = {}) {
|
|
30
|
+
return { data };
|
|
31
|
+
}
|
|
32
|
+
describe('createBuiltinHandlers', () => {
|
|
33
|
+
it('returns a Map with the expected handler keys', () => {
|
|
34
|
+
const handlers = createBuiltinHandlers();
|
|
35
|
+
expect(handlers).toBeInstanceOf(Map);
|
|
36
|
+
expect(handlers.has('action.http')).toBe(true);
|
|
37
|
+
expect(handlers.has('action.save_file')).toBe(true);
|
|
38
|
+
expect(handlers.has('action.log')).toBe(true);
|
|
39
|
+
expect(handlers.has('action.gemini_image')).toBe(true);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
describe('action.save_file', () => {
|
|
43
|
+
let handlers;
|
|
44
|
+
beforeEach(() => {
|
|
45
|
+
vi.clearAllMocks();
|
|
46
|
+
// existsSync stays false — no sessions file
|
|
47
|
+
handlers = createBuiltinHandlers();
|
|
48
|
+
});
|
|
49
|
+
it('writes a file for a safe relative path', async () => {
|
|
50
|
+
const handler = handlers.get('action.save_file');
|
|
51
|
+
const items = [makeItem({ hello: 'world' })];
|
|
52
|
+
const result = await handler(items, { path: 'output.txt' });
|
|
53
|
+
expect(fsMock.writeFile).toHaveBeenCalled();
|
|
54
|
+
expect(result[0].data.savedPath).toMatch(/output\.txt$/);
|
|
55
|
+
});
|
|
56
|
+
it('throws "Path traversal blocked" for a path that escapes cwd', async () => {
|
|
57
|
+
const handler = handlers.get('action.save_file');
|
|
58
|
+
const items = [makeItem()];
|
|
59
|
+
await expect(handler(items, { path: '../../etc/passwd' })).rejects.toThrow('Path traversal blocked');
|
|
60
|
+
});
|
|
61
|
+
it('writes binary content when item.binaryBase64 is set', async () => {
|
|
62
|
+
const handler = handlers.get('action.save_file');
|
|
63
|
+
const binaryItem = { data: {}, binaryBase64: Buffer.from('abc').toString('base64') };
|
|
64
|
+
const result = await handler([binaryItem], { path: 'img.png' });
|
|
65
|
+
expect(fsMock.writeFile).toHaveBeenCalled();
|
|
66
|
+
const [, content] = vi.mocked(fsMock.writeFile).mock.calls[0];
|
|
67
|
+
expect(Buffer.isBuffer(content)).toBe(true);
|
|
68
|
+
expect(result[0].data.savedPath).toMatch(/img\.png$/);
|
|
69
|
+
});
|
|
70
|
+
it('uses config.content when no field is provided', async () => {
|
|
71
|
+
const handler = handlers.get('action.save_file');
|
|
72
|
+
const items = [makeItem()];
|
|
73
|
+
const result = await handler(items, { path: 'out.txt', content: 'hello content' });
|
|
74
|
+
const [, written] = vi.mocked(fsMock.writeFile).mock.calls[0];
|
|
75
|
+
expect(written).toBe('hello content');
|
|
76
|
+
expect(result[0].data.savedPath).toMatch(/out\.txt$/);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
describe('action.gemini_image', () => {
|
|
80
|
+
let handlers;
|
|
81
|
+
beforeEach(() => {
|
|
82
|
+
vi.clearAllMocks();
|
|
83
|
+
handlers = createBuiltinHandlers();
|
|
84
|
+
});
|
|
85
|
+
it('falls back to mock mode when browser and API key are unavailable', async () => {
|
|
86
|
+
const handler = handlers.get('action.gemini_image');
|
|
87
|
+
// No GEMINI_API_KEY set, browser import throws — mock mode
|
|
88
|
+
delete process.env['GEMINI_API_KEY'];
|
|
89
|
+
delete process.env['GOOGLE_API_KEY'];
|
|
90
|
+
const items = [makeItem({ prompt: 'a beautiful sunset' })];
|
|
91
|
+
const result = await handler(items, { prompt: 'a beautiful sunset', cdpPort: 19999 });
|
|
92
|
+
expect(result[0].data.mockMode).toBe(true);
|
|
93
|
+
expect(result[0].data.prompt).toBe('a beautiful sunset');
|
|
94
|
+
});
|
|
95
|
+
it('throws "Path traversal blocked" for outputPath outside cwd', async () => {
|
|
96
|
+
const handler = handlers.get('action.gemini_image');
|
|
97
|
+
delete process.env['GEMINI_API_KEY'];
|
|
98
|
+
delete process.env['GOOGLE_API_KEY'];
|
|
99
|
+
const items = [makeItem()];
|
|
100
|
+
await expect(handler(items, { prompt: 'test', outputPath: '../../evil.png', cdpPort: 19999 })).rejects.toThrow('Path traversal blocked');
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
describe('action.http', () => {
|
|
104
|
+
let handlers;
|
|
105
|
+
const originalFetch = globalThis.fetch;
|
|
106
|
+
beforeEach(() => {
|
|
107
|
+
handlers = createBuiltinHandlers();
|
|
108
|
+
});
|
|
109
|
+
afterEach(() => {
|
|
110
|
+
globalThis.fetch = originalFetch;
|
|
111
|
+
});
|
|
112
|
+
it('fetches a URL and stores response in item.data.response', async () => {
|
|
113
|
+
const mockFetch = vi.fn().mockResolvedValue({
|
|
114
|
+
ok: true,
|
|
115
|
+
status: 200,
|
|
116
|
+
text: async () => JSON.stringify({ success: true }),
|
|
117
|
+
});
|
|
118
|
+
globalThis.fetch = mockFetch;
|
|
119
|
+
const handler = handlers.get('action.http');
|
|
120
|
+
const items = [makeItem()];
|
|
121
|
+
const result = await handler(items, { url: 'https://example.com/api', method: 'GET' });
|
|
122
|
+
expect(mockFetch).toHaveBeenCalledWith('https://example.com/api', expect.objectContaining({ method: 'GET' }));
|
|
123
|
+
expect(result[0].data.response.statusCode).toBe(200);
|
|
124
|
+
expect(result[0].data.response.json).toEqual({ success: true });
|
|
125
|
+
});
|
|
126
|
+
it('uses a custom responseField when specified', async () => {
|
|
127
|
+
globalThis.fetch = vi.fn().mockResolvedValue({
|
|
128
|
+
ok: true,
|
|
129
|
+
status: 201,
|
|
130
|
+
text: async () => 'created',
|
|
131
|
+
});
|
|
132
|
+
const handler = handlers.get('action.http');
|
|
133
|
+
const items = [makeItem()];
|
|
134
|
+
const result = await handler(items, { url: 'https://example.com', responseField: 'myResult' });
|
|
135
|
+
expect(result[0].data.myResult).toBeDefined();
|
|
136
|
+
expect(result[0].data.myResult.statusCode).toBe(201);
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
//# sourceMappingURL=browse-builtin-handlers.test.js.map
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
// ---------------------------------------------------------------------------
|
|
3
|
+
// Fake WebSocket — mimics the Node.js EventEmitter-style API that 'ws' uses
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
class FakeWS {
|
|
6
|
+
readyState = 1; // OPEN
|
|
7
|
+
sent = [];
|
|
8
|
+
_handlers = {};
|
|
9
|
+
on(event, fn) {
|
|
10
|
+
if (!this._handlers[event])
|
|
11
|
+
this._handlers[event] = [];
|
|
12
|
+
this._handlers[event].push(fn);
|
|
13
|
+
return this;
|
|
14
|
+
}
|
|
15
|
+
send(data, cb) {
|
|
16
|
+
this.sent.push(data);
|
|
17
|
+
cb?.();
|
|
18
|
+
}
|
|
19
|
+
close() {
|
|
20
|
+
this.emit('close');
|
|
21
|
+
}
|
|
22
|
+
emit(event, ...args) {
|
|
23
|
+
for (const fn of this._handlers[event] ?? [])
|
|
24
|
+
fn(...args);
|
|
25
|
+
}
|
|
26
|
+
/** Simulate a message arriving from the browser */
|
|
27
|
+
simulateMessage(obj) {
|
|
28
|
+
this.emit('message', JSON.stringify(obj));
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
// Module-level reference so test helpers can access the last FakeWS instance
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
let fakeWsInstance = null;
|
|
35
|
+
// We need WebSocket to be constructable. Use vi.fn() and expose a class-like
|
|
36
|
+
// constructor that captures the instance.
|
|
37
|
+
function FakeWebSocket(_url) {
|
|
38
|
+
fakeWsInstance = new FakeWS();
|
|
39
|
+
Object.assign(this, fakeWsInstance);
|
|
40
|
+
// Proxy the FakeWS methods onto `this`
|
|
41
|
+
for (const key of Object.getOwnPropertyNames(FakeWS.prototype)) {
|
|
42
|
+
if (key !== 'constructor') {
|
|
43
|
+
this[key] = fakeWsInstance[key].bind(fakeWsInstance);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
// Also expose sent and emit directly on `this`
|
|
47
|
+
Object.defineProperty(this, 'sent', {
|
|
48
|
+
get: () => fakeWsInstance.sent,
|
|
49
|
+
configurable: true,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
vi.mock('ws', () => ({
|
|
53
|
+
WebSocket: FakeWebSocket,
|
|
54
|
+
}));
|
|
55
|
+
import { CdpClient } from '@monoes/monobrowse';
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
// Helpers
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
function openClient() {
|
|
60
|
+
const client = new CdpClient();
|
|
61
|
+
client.connect('ws://localhost:9222/devtools/page/abc');
|
|
62
|
+
const ws = fakeWsInstance;
|
|
63
|
+
ws.emit('open');
|
|
64
|
+
return { client, ws };
|
|
65
|
+
}
|
|
66
|
+
async function connectedClient() {
|
|
67
|
+
const { client, ws } = openClient();
|
|
68
|
+
await Promise.resolve();
|
|
69
|
+
return { client, ws };
|
|
70
|
+
}
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
// Tests
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
describe('CdpClient', () => {
|
|
75
|
+
beforeEach(() => {
|
|
76
|
+
fakeWsInstance = null;
|
|
77
|
+
vi.clearAllMocks();
|
|
78
|
+
});
|
|
79
|
+
it('connects and resolves when the WebSocket opens', async () => {
|
|
80
|
+
const client = new CdpClient();
|
|
81
|
+
const p = client.connect('ws://localhost:9222/devtools/page/abc');
|
|
82
|
+
fakeWsInstance.emit('open');
|
|
83
|
+
await expect(p).resolves.toBeUndefined();
|
|
84
|
+
expect(client.isConnected()).toBe(true);
|
|
85
|
+
});
|
|
86
|
+
it('rejects when the WebSocket emits an error before opening', async () => {
|
|
87
|
+
const client = new CdpClient();
|
|
88
|
+
const p = client.connect('ws://localhost:9222/devtools/page/abc');
|
|
89
|
+
const err = new Error('ECONNREFUSED');
|
|
90
|
+
fakeWsInstance.emit('error', err);
|
|
91
|
+
await expect(p).rejects.toThrow('ECONNREFUSED');
|
|
92
|
+
});
|
|
93
|
+
it('sends a command and resolves with the response result', async () => {
|
|
94
|
+
const { client, ws } = await connectedClient();
|
|
95
|
+
const sendPromise = client.send('Runtime.evaluate', { expression: '1+1' });
|
|
96
|
+
const sent = JSON.parse(ws.sent[0]);
|
|
97
|
+
expect(sent.method).toBe('Runtime.evaluate');
|
|
98
|
+
ws.simulateMessage({ id: sent.id, result: { value: 2 } });
|
|
99
|
+
const result = await sendPromise;
|
|
100
|
+
expect(result.value).toBe(2);
|
|
101
|
+
});
|
|
102
|
+
it('rejects a command when the response contains a CDP error', async () => {
|
|
103
|
+
const { client, ws } = await connectedClient();
|
|
104
|
+
const sendPromise = client.send('DOM.getDocument');
|
|
105
|
+
const sent = JSON.parse(ws.sent[0]);
|
|
106
|
+
ws.simulateMessage({ id: sent.id, error: { code: -32000, message: 'Not found' } });
|
|
107
|
+
await expect(sendPromise).rejects.toThrow('CDP error -32000: Not found');
|
|
108
|
+
});
|
|
109
|
+
it('rejects when not connected', async () => {
|
|
110
|
+
const client = new CdpClient();
|
|
111
|
+
await expect(client.send('Page.navigate')).rejects.toThrow('CDP not connected');
|
|
112
|
+
});
|
|
113
|
+
it('enforces 1000 in-flight command cap', async () => {
|
|
114
|
+
const { client, ws } = await connectedClient();
|
|
115
|
+
// Override send to avoid callbacks so commands stay pending
|
|
116
|
+
vi.spyOn(ws, 'send').mockImplementation((data) => {
|
|
117
|
+
ws.sent.push(data);
|
|
118
|
+
});
|
|
119
|
+
// Fill up to 1000 pending
|
|
120
|
+
for (let i = 0; i < 1000; i++) {
|
|
121
|
+
client.send('Page.dummy').catch(() => { });
|
|
122
|
+
}
|
|
123
|
+
// 1001st command should be rejected immediately
|
|
124
|
+
await expect(client.send('Page.overflow')).rejects.toThrow('queue full');
|
|
125
|
+
});
|
|
126
|
+
it('rejects all pending commands when the connection closes', async () => {
|
|
127
|
+
const { client, ws } = await connectedClient();
|
|
128
|
+
vi.spyOn(ws, 'send').mockImplementation((data) => {
|
|
129
|
+
ws.sent.push(data);
|
|
130
|
+
// no callback — keeps command in-flight
|
|
131
|
+
});
|
|
132
|
+
const pendingPromise = client.send('Page.navigate');
|
|
133
|
+
ws.emit('close');
|
|
134
|
+
await expect(pendingPromise).rejects.toThrow('CDP connection closed');
|
|
135
|
+
expect(client.isConnected()).toBe(false);
|
|
136
|
+
});
|
|
137
|
+
it('fires event listeners when a CDP event arrives', async () => {
|
|
138
|
+
const { client, ws } = await connectedClient();
|
|
139
|
+
const listener = vi.fn();
|
|
140
|
+
client.on('Page.loadEventFired', listener);
|
|
141
|
+
ws.simulateMessage({ method: 'Page.loadEventFired', params: { timestamp: 1.23 } });
|
|
142
|
+
expect(listener).toHaveBeenCalledWith({ timestamp: 1.23 }, undefined);
|
|
143
|
+
});
|
|
144
|
+
it('enforces 100 listener cap per event', async () => {
|
|
145
|
+
const { client } = await connectedClient();
|
|
146
|
+
for (let i = 0; i < 100; i++) {
|
|
147
|
+
client.on('Page.frameNavigated', vi.fn());
|
|
148
|
+
}
|
|
149
|
+
expect(() => client.on('Page.frameNavigated', vi.fn())).toThrow('CDP event listener limit reached');
|
|
150
|
+
});
|
|
151
|
+
it('close() rejects pending commands and disconnects', async () => {
|
|
152
|
+
const { client, ws } = await connectedClient();
|
|
153
|
+
vi.spyOn(ws, 'send').mockImplementation((data) => {
|
|
154
|
+
ws.sent.push(data);
|
|
155
|
+
});
|
|
156
|
+
const p = client.send('Network.enable');
|
|
157
|
+
client.close();
|
|
158
|
+
await expect(p).rejects.toThrow('CDP connection closed');
|
|
159
|
+
expect(client.isConnected()).toBe(false);
|
|
160
|
+
});
|
|
161
|
+
it('once() resolves on the first matching event', async () => {
|
|
162
|
+
const { client, ws } = await connectedClient();
|
|
163
|
+
const oncePromise = client.once('Page.loadEventFired');
|
|
164
|
+
ws.simulateMessage({ method: 'Page.loadEventFired', params: { timestamp: 99 } });
|
|
165
|
+
const params = await oncePromise;
|
|
166
|
+
expect(params).toEqual({ timestamp: 99 });
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
//# sourceMappingURL=browse-cdp.test.js.map
|