mop-flow 0.1.8
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/.MOP/PROTOCOL.md +579 -0
- package/.MOP/STATE.json +668 -0
- package/.MOP/config/defaults.json +55 -0
- package/.MOP/config/team.json +8 -0
- package/.MOP/flow/ROADMAP.md +51 -0
- package/.MOP/flow/skill-manifest.json +645 -0
- package/.MOP/scripts/burhan-mop.mjs +291 -0
- package/.MOP/scripts/mop-auto-deploy.mjs +152 -0
- package/.MOP/scripts/mop-autosycn.mjs +790 -0
- package/.MOP/scripts/mop-core.mjs +1206 -0
- package/.MOP/scripts/mop-flow.mjs +396 -0
- package/.MOP/scripts/mop-smoke-test.mjs +76 -0
- package/.MOP/scripts/mop-workflow.mjs +348 -0
- package/.MOP/templates/artifacts/adversarial-review.md +33 -0
- package/.MOP/templates/artifacts/architecture.md +28 -0
- package/.MOP/templates/artifacts/decision-log.md +21 -0
- package/.MOP/templates/artifacts/handoff.md +21 -0
- package/.MOP/templates/artifacts/implementation-notes.md +21 -0
- package/.MOP/templates/artifacts/prd.md +29 -0
- package/.MOP/templates/artifacts/product-brief.md +30 -0
- package/.MOP/templates/artifacts/readiness-report.md +25 -0
- package/.MOP/templates/artifacts/release-notes.md +21 -0
- package/.MOP/templates/artifacts/review.md +21 -0
- package/.MOP/templates/artifacts/story.md +25 -0
- package/.MOP/templates/artifacts/ux-spec.md +32 -0
- package/.agents/AGENTS.md +85 -0
- package/.agents/skills/auto-deploy/SKILL.md +48 -0
- package/.agents/skills/autosycn/SKILL.md +75 -0
- package/.agents/skills/mop-flow/SKILL.md +53 -0
- package/.agents/skills/mop-help/SKILL.md +35 -0
- package/.agents/skills/ruflo-core/SKILL.md +36 -0
- package/.claude/agents/analysis/analyze-code-quality.md +179 -0
- package/.claude/agents/analysis/code-analyzer.md +210 -0
- package/.claude/agents/analysis/code-review/analyze-code-quality.md +179 -0
- package/.claude/agents/architecture/arch-system-design.md +157 -0
- package/.claude/agents/architecture/system-design/arch-system-design.md +155 -0
- package/.claude/agents/browser/browser-agent.yaml +182 -0
- package/.claude/agents/consensus/byzantine-coordinator.md +63 -0
- package/.claude/agents/consensus/crdt-synchronizer.md +997 -0
- package/.claude/agents/consensus/gossip-coordinator.md +63 -0
- package/.claude/agents/consensus/performance-benchmarker.md +851 -0
- package/.claude/agents/consensus/quorum-manager.md +823 -0
- package/.claude/agents/consensus/raft-manager.md +63 -0
- package/.claude/agents/consensus/security-manager.md +622 -0
- package/.claude/agents/core/planner.md +375 -0
- package/.claude/agents/custom/test-long-runner.md +44 -0
- package/.claude/agents/data/data-ml-model.md +445 -0
- package/.claude/agents/data/ml/data-ml-model.md +193 -0
- package/.claude/agents/development/backend/dev-backend-api.md +142 -0
- package/.claude/agents/development/dev-backend-api.md +345 -0
- package/.claude/agents/devops/ci-cd/ops-cicd-github.md +164 -0
- package/.claude/agents/devops/ops-cicd-github.md +165 -0
- package/.claude/agents/documentation/api-docs/docs-api-openapi.md +174 -0
- package/.claude/agents/documentation/docs-api-openapi.md +355 -0
- package/.claude/agents/flow-nexus/app-store.md +88 -0
- package/.claude/agents/flow-nexus/authentication.md +69 -0
- package/.claude/agents/flow-nexus/challenges.md +81 -0
- package/.claude/agents/flow-nexus/neural-network.md +88 -0
- package/.claude/agents/flow-nexus/payments.md +83 -0
- package/.claude/agents/flow-nexus/sandbox.md +76 -0
- package/.claude/agents/flow-nexus/swarm.md +76 -0
- package/.claude/agents/flow-nexus/user-tools.md +96 -0
- package/.claude/agents/flow-nexus/workflow.md +84 -0
- package/.claude/agents/github/code-review-swarm.md +377 -0
- package/.claude/agents/github/github-modes.md +173 -0
- package/.claude/agents/github/issue-tracker.md +576 -0
- package/.claude/agents/github/multi-repo-swarm.md +553 -0
- package/.claude/agents/github/pr-manager.md +438 -0
- package/.claude/agents/github/project-board-sync.md +509 -0
- package/.claude/agents/github/release-manager.md +605 -0
- package/.claude/agents/github/release-swarm.md +583 -0
- package/.claude/agents/github/repo-architect.md +398 -0
- package/.claude/agents/github/swarm-issue.md +573 -0
- package/.claude/agents/github/swarm-pr.md +428 -0
- package/.claude/agents/github/sync-coordinator.md +452 -0
- package/.claude/agents/github/workflow-automation.md +903 -0
- package/.claude/agents/goal/agent.md +816 -0
- package/.claude/agents/optimization/benchmark-suite.md +665 -0
- package/.claude/agents/optimization/load-balancer.md +431 -0
- package/.claude/agents/optimization/performance-monitor.md +672 -0
- package/.claude/agents/optimization/resource-allocator.md +674 -0
- package/.claude/agents/optimization/topology-optimizer.md +808 -0
- package/.claude/agents/payments/agentic-payments.md +126 -0
- package/.claude/agents/sona/sona-learning-optimizer.md +74 -0
- package/.claude/agents/sparc/architecture.md +699 -0
- package/.claude/agents/sparc/pseudocode.md +520 -0
- package/.claude/agents/sparc/refinement.md +802 -0
- package/.claude/agents/sparc/specification.md +478 -0
- package/.claude/agents/specialized/mobile/spec-mobile-react-native.md +225 -0
- package/.claude/agents/specialized/spec-mobile-react-native.md +227 -0
- package/.claude/agents/sublinear/consensus-coordinator.md +338 -0
- package/.claude/agents/sublinear/matrix-optimizer.md +185 -0
- package/.claude/agents/sublinear/pagerank-analyzer.md +299 -0
- package/.claude/agents/sublinear/performance-optimizer.md +368 -0
- package/.claude/agents/sublinear/trading-predictor.md +246 -0
- package/.claude/agents/swarm/adaptive-coordinator.md +1127 -0
- package/.claude/agents/swarm/hierarchical-coordinator.md +710 -0
- package/.claude/agents/swarm/mesh-coordinator.md +963 -0
- package/.claude/agents/templates/automation-smart-agent.md +205 -0
- package/.claude/agents/templates/base-template-generator.md +289 -0
- package/.claude/agents/templates/coordinator-swarm-init.md +90 -0
- package/.claude/agents/templates/github-pr-manager.md +177 -0
- package/.claude/agents/templates/implementer-sparc-coder.md +259 -0
- package/.claude/agents/templates/memory-coordinator.md +187 -0
- package/.claude/agents/templates/orchestrator-task.md +139 -0
- package/.claude/agents/templates/performance-analyzer.md +199 -0
- package/.claude/agents/templates/sparc-coordinator.md +514 -0
- package/.claude/agents/testing/production-validator.md +395 -0
- package/.claude/agents/testing/tdd-london-swarm.md +244 -0
- package/.claude/agents/v3/aidefence-guardian.md +282 -0
- package/.claude/agents/v3/claims-authorizer.md +208 -0
- package/.claude/agents/v3/collective-intelligence-coordinator.md +993 -0
- package/.claude/agents/v3/ddd-domain-expert.md +220 -0
- package/.claude/agents/v3/injection-analyst.md +236 -0
- package/.claude/agents/v3/performance-engineer.md +1233 -0
- package/.claude/agents/v3/pii-detector.md +151 -0
- package/.claude/agents/v3/reasoningbank-learner.md +213 -0
- package/.claude/agents/v3/security-architect-aidefence.md +410 -0
- package/.claude/agents/v3/security-architect.md +867 -0
- package/.claude/agents/v3/swarm-memory-manager.md +157 -0
- package/.claude/agents/v3/v3-integration-architect.md +205 -0
- package/.claude/commands/agents/README.md +50 -0
- package/.claude/commands/agents/agent-capabilities.md +140 -0
- package/.claude/commands/agents/agent-coordination.md +28 -0
- package/.claude/commands/agents/agent-spawning.md +28 -0
- package/.claude/commands/agents/agent-types.md +216 -0
- package/.claude/commands/agents/health.md +139 -0
- package/.claude/commands/agents/list.md +100 -0
- package/.claude/commands/agents/logs.md +130 -0
- package/.claude/commands/agents/metrics.md +122 -0
- package/.claude/commands/agents/pool.md +127 -0
- package/.claude/commands/agents/spawn.md +140 -0
- package/.claude/commands/agents/status.md +115 -0
- package/.claude/commands/agents/stop.md +102 -0
- package/.claude/commands/analysis/COMMAND_COMPLIANCE_REPORT.md +54 -0
- package/.claude/commands/analysis/README.md +9 -0
- package/.claude/commands/analysis/bottleneck-detect.md +162 -0
- package/.claude/commands/analysis/performance-bottlenecks.md +59 -0
- package/.claude/commands/analysis/performance-report.md +25 -0
- package/.claude/commands/analysis/token-efficiency.md +45 -0
- package/.claude/commands/analysis/token-usage.md +25 -0
- package/.claude/commands/automation/README.md +9 -0
- package/.claude/commands/automation/auto-agent.md +122 -0
- package/.claude/commands/automation/self-healing.md +106 -0
- package/.claude/commands/automation/session-memory.md +90 -0
- package/.claude/commands/automation/smart-agents.md +73 -0
- package/.claude/commands/automation/smart-spawn.md +25 -0
- package/.claude/commands/automation/workflow-select.md +25 -0
- package/.claude/commands/claude-flow-help.md +103 -0
- package/.claude/commands/claude-flow-memory.md +107 -0
- package/.claude/commands/claude-flow-swarm.md +205 -0
- package/.claude/commands/coordination/README.md +9 -0
- package/.claude/commands/coordination/agent-spawn.md +25 -0
- package/.claude/commands/coordination/init.md +44 -0
- package/.claude/commands/coordination/orchestrate.md +43 -0
- package/.claude/commands/coordination/spawn.md +45 -0
- package/.claude/commands/coordination/swarm-init.md +85 -0
- package/.claude/commands/coordination/task-orchestrate.md +25 -0
- package/.claude/commands/github/README.md +11 -0
- package/.claude/commands/github/code-review-swarm.md +514 -0
- package/.claude/commands/github/code-review.md +25 -0
- package/.claude/commands/github/github-modes.md +147 -0
- package/.claude/commands/github/github-swarm.md +121 -0
- package/.claude/commands/github/issue-tracker.md +292 -0
- package/.claude/commands/github/issue-triage.md +25 -0
- package/.claude/commands/github/multi-repo-swarm.md +519 -0
- package/.claude/commands/github/pr-enhance.md +26 -0
- package/.claude/commands/github/pr-manager.md +170 -0
- package/.claude/commands/github/project-board-sync.md +471 -0
- package/.claude/commands/github/release-manager.md +340 -0
- package/.claude/commands/github/release-swarm.md +544 -0
- package/.claude/commands/github/repo-analyze.md +25 -0
- package/.claude/commands/github/repo-architect.md +367 -0
- package/.claude/commands/github/swarm-issue.md +485 -0
- package/.claude/commands/github/swarm-pr.md +288 -0
- package/.claude/commands/github/sync-coordinator.md +303 -0
- package/.claude/commands/github/workflow-automation.md +442 -0
- package/.claude/commands/hive-mind/README.md +17 -0
- package/.claude/commands/hive-mind/hive-mind-consensus.md +8 -0
- package/.claude/commands/hive-mind/hive-mind-init.md +18 -0
- package/.claude/commands/hive-mind/hive-mind-memory.md +8 -0
- package/.claude/commands/hive-mind/hive-mind-metrics.md +8 -0
- package/.claude/commands/hive-mind/hive-mind-resume.md +8 -0
- package/.claude/commands/hive-mind/hive-mind-sessions.md +8 -0
- package/.claude/commands/hive-mind/hive-mind-spawn.md +21 -0
- package/.claude/commands/hive-mind/hive-mind-status.md +8 -0
- package/.claude/commands/hive-mind/hive-mind-stop.md +8 -0
- package/.claude/commands/hive-mind/hive-mind-wizard.md +8 -0
- package/.claude/commands/hive-mind/hive-mind.md +27 -0
- package/.claude/commands/hooks/README.md +11 -0
- package/.claude/commands/hooks/overview.md +58 -0
- package/.claude/commands/hooks/post-edit.md +117 -0
- package/.claude/commands/hooks/post-task.md +112 -0
- package/.claude/commands/hooks/pre-edit.md +113 -0
- package/.claude/commands/hooks/pre-task.md +111 -0
- package/.claude/commands/hooks/session-end.md +118 -0
- package/.claude/commands/hooks/setup.md +103 -0
- package/.claude/commands/memory/README.md +9 -0
- package/.claude/commands/memory/memory-persist.md +25 -0
- package/.claude/commands/memory/memory-search.md +25 -0
- package/.claude/commands/memory/memory-usage.md +25 -0
- package/.claude/commands/memory/neural.md +47 -0
- package/.claude/commands/monitoring/README.md +9 -0
- package/.claude/commands/monitoring/agent-metrics.md +25 -0
- package/.claude/commands/monitoring/agents.md +44 -0
- package/.claude/commands/monitoring/real-time-view.md +25 -0
- package/.claude/commands/monitoring/status.md +46 -0
- package/.claude/commands/monitoring/swarm-monitor.md +25 -0
- package/.claude/commands/optimization/README.md +9 -0
- package/.claude/commands/optimization/auto-topology.md +62 -0
- package/.claude/commands/optimization/cache-manage.md +25 -0
- package/.claude/commands/optimization/parallel-execute.md +25 -0
- package/.claude/commands/optimization/parallel-execution.md +50 -0
- package/.claude/commands/optimization/topology-optimize.md +25 -0
- package/.claude/commands/pair/README.md +261 -0
- package/.claude/commands/pair/commands.md +546 -0
- package/.claude/commands/pair/config.md +510 -0
- package/.claude/commands/pair/examples.md +512 -0
- package/.claude/commands/pair/modes.md +348 -0
- package/.claude/commands/pair/session.md +407 -0
- package/.claude/commands/pair/start.md +209 -0
- package/.claude/commands/sparc/analyzer.md +52 -0
- package/.claude/commands/sparc/architect.md +53 -0
- package/.claude/commands/sparc/ask.md +97 -0
- package/.claude/commands/sparc/batch-executor.md +54 -0
- package/.claude/commands/sparc/code.md +89 -0
- package/.claude/commands/sparc/coder.md +54 -0
- package/.claude/commands/sparc/debug.md +83 -0
- package/.claude/commands/sparc/debugger.md +54 -0
- package/.claude/commands/sparc/designer.md +53 -0
- package/.claude/commands/sparc/devops.md +109 -0
- package/.claude/commands/sparc/docs-writer.md +80 -0
- package/.claude/commands/sparc/documenter.md +54 -0
- package/.claude/commands/sparc/innovator.md +54 -0
- package/.claude/commands/sparc/integration.md +83 -0
- package/.claude/commands/sparc/mcp.md +117 -0
- package/.claude/commands/sparc/memory-manager.md +54 -0
- package/.claude/commands/sparc/optimizer.md +54 -0
- package/.claude/commands/sparc/orchestrator.md +132 -0
- package/.claude/commands/sparc/post-deployment-monitoring-mode.md +83 -0
- package/.claude/commands/sparc/refinement-optimization-mode.md +83 -0
- package/.claude/commands/sparc/researcher.md +54 -0
- package/.claude/commands/sparc/reviewer.md +54 -0
- package/.claude/commands/sparc/security-review.md +80 -0
- package/.claude/commands/sparc/sparc-modes.md +174 -0
- package/.claude/commands/sparc/sparc.md +111 -0
- package/.claude/commands/sparc/spec-pseudocode.md +80 -0
- package/.claude/commands/sparc/supabase-admin.md +348 -0
- package/.claude/commands/sparc/swarm-coordinator.md +54 -0
- package/.claude/commands/sparc/tdd.md +54 -0
- package/.claude/commands/sparc/tester.md +54 -0
- package/.claude/commands/sparc/tutorial.md +79 -0
- package/.claude/commands/sparc/workflow-manager.md +54 -0
- package/.claude/commands/stream-chain/pipeline.md +121 -0
- package/.claude/commands/stream-chain/run.md +70 -0
- package/.claude/commands/swarm/README.md +15 -0
- package/.claude/commands/swarm/analysis.md +95 -0
- package/.claude/commands/swarm/development.md +96 -0
- package/.claude/commands/swarm/examples.md +168 -0
- package/.claude/commands/swarm/maintenance.md +102 -0
- package/.claude/commands/swarm/optimization.md +117 -0
- package/.claude/commands/swarm/research.md +136 -0
- package/.claude/commands/swarm/swarm-analysis.md +8 -0
- package/.claude/commands/swarm/swarm-background.md +8 -0
- package/.claude/commands/swarm/swarm-init.md +19 -0
- package/.claude/commands/swarm/swarm-modes.md +8 -0
- package/.claude/commands/swarm/swarm-monitor.md +8 -0
- package/.claude/commands/swarm/swarm-spawn.md +19 -0
- package/.claude/commands/swarm/swarm-status.md +8 -0
- package/.claude/commands/swarm/swarm-strategies.md +8 -0
- package/.claude/commands/swarm/swarm.md +87 -0
- package/.claude/commands/swarm/testing.md +131 -0
- package/.claude/commands/training/README.md +9 -0
- package/.claude/commands/training/model-update.md +25 -0
- package/.claude/commands/training/neural-patterns.md +108 -0
- package/.claude/commands/training/neural-train.md +75 -0
- package/.claude/commands/training/pattern-learn.md +25 -0
- package/.claude/commands/training/specialization.md +63 -0
- package/.claude/commands/truth/start.md +143 -0
- package/.claude/commands/verify/check.md +50 -0
- package/.claude/commands/verify/start.md +128 -0
- package/.claude/commands/workflows/README.md +9 -0
- package/.claude/commands/workflows/development.md +78 -0
- package/.claude/commands/workflows/research.md +63 -0
- package/.claude/commands/workflows/workflow-create.md +25 -0
- package/.claude/commands/workflows/workflow-execute.md +25 -0
- package/.claude/commands/workflows/workflow-export.md +25 -0
- package/.claude/helpers/README.md +97 -0
- package/.claude/helpers/adr-compliance.sh +186 -0
- package/.claude/helpers/auto-commit.sh +178 -0
- package/.claude/helpers/auto-memory-hook.mjs +368 -0
- package/.claude/helpers/checkpoint-manager.sh +251 -0
- package/.claude/helpers/daemon-manager.sh +252 -0
- package/.claude/helpers/ddd-tracker.sh +144 -0
- package/.claude/helpers/github-safe.js +156 -0
- package/.claude/helpers/github-setup.sh +45 -0
- package/.claude/helpers/guidance-hook.sh +13 -0
- package/.claude/helpers/guidance-hooks.sh +102 -0
- package/.claude/helpers/health-monitor.sh +108 -0
- package/.claude/helpers/hook-handler.cjs +286 -0
- package/.claude/helpers/intelligence.cjs +1031 -0
- package/.claude/helpers/learning-hooks.sh +329 -0
- package/.claude/helpers/learning-optimizer.sh +127 -0
- package/.claude/helpers/learning-service.mjs +1144 -0
- package/.claude/helpers/memory.js +83 -0
- package/.claude/helpers/metrics-db.mjs +488 -0
- package/.claude/helpers/pattern-consolidator.sh +86 -0
- package/.claude/helpers/perf-worker.sh +160 -0
- package/.claude/helpers/post-commit +16 -0
- package/.claude/helpers/pre-commit +26 -0
- package/.claude/helpers/quick-start.sh +19 -0
- package/.claude/helpers/router.js +105 -0
- package/.claude/helpers/ruflo-hook.cjs +59 -0
- package/.claude/helpers/security-scanner.sh +127 -0
- package/.claude/helpers/session.js +157 -0
- package/.claude/helpers/setup-mcp.sh +18 -0
- package/.claude/helpers/standard-checkpoint-hooks.sh +189 -0
- package/.claude/helpers/statusline-hook.sh +21 -0
- package/.claude/helpers/statusline.cjs +693 -0
- package/.claude/helpers/statusline.js +352 -0
- package/.claude/helpers/swarm-comms.sh +353 -0
- package/.claude/helpers/swarm-hooks.sh +761 -0
- package/.claude/helpers/swarm-monitor.sh +211 -0
- package/.claude/helpers/sync-v3-metrics.sh +245 -0
- package/.claude/helpers/update-v3-progress.sh +166 -0
- package/.claude/helpers/v3-quick-status.sh +58 -0
- package/.claude/helpers/v3.sh +111 -0
- package/.claude/helpers/validate-v3-config.sh +216 -0
- package/.claude/helpers/worker-manager.sh +170 -0
- package/.claude/settings.json +305 -0
- package/.claude/skills/agentdb-advanced/SKILL.md +550 -0
- package/.claude/skills/agentdb-learning/SKILL.md +545 -0
- package/.claude/skills/agentdb-memory-patterns/SKILL.md +339 -0
- package/.claude/skills/agentdb-optimization/SKILL.md +509 -0
- package/.claude/skills/agentdb-vector-search/SKILL.md +339 -0
- package/.claude/skills/auto-deploy/SKILL.md +31 -0
- package/.claude/skills/autosycn/SKILL.md +30 -0
- package/.claude/skills/browser/SKILL.md +204 -0
- package/.claude/skills/dual-mode/README.md +71 -0
- package/.claude/skills/dual-mode/dual-collect.md +103 -0
- package/.claude/skills/dual-mode/dual-coordinate.md +85 -0
- package/.claude/skills/dual-mode/dual-spawn.md +81 -0
- package/.claude/skills/flow-nexus-neural/SKILL.md +727 -0
- package/.claude/skills/flow-nexus-platform/SKILL.md +1154 -0
- package/.claude/skills/flow-nexus-swarm/SKILL.md +604 -0
- package/.claude/skills/github-code-review/SKILL.md +1125 -0
- package/.claude/skills/github-multi-repo/SKILL.md +862 -0
- package/.claude/skills/github-project-management/SKILL.md +1262 -0
- package/.claude/skills/github-release-management/SKILL.md +1064 -0
- package/.claude/skills/github-workflow-automation/SKILL.md +1047 -0
- package/.claude/skills/hooks-automation/SKILL.md +1201 -0
- package/.claude/skills/mop-flow/SKILL.md +53 -0
- package/.claude/skills/mop-help/SKILL.md +35 -0
- package/.claude/skills/pair-programming/SKILL.md +1202 -0
- package/.claude/skills/reasoningbank-agentdb/SKILL.md +446 -0
- package/.claude/skills/reasoningbank-intelligence/SKILL.md +201 -0
- package/.claude/skills/skill-builder/SKILL.md +910 -0
- package/.claude/skills/sparc-methodology/SKILL.md +1106 -0
- package/.claude/skills/stream-chain/SKILL.md +560 -0
- package/.claude/skills/swarm-advanced/SKILL.md +970 -0
- package/.claude/skills/swarm-orchestration/SKILL.md +179 -0
- package/.claude/skills/v3-cli-modernization/SKILL.md +872 -0
- package/.claude/skills/v3-core-implementation/SKILL.md +797 -0
- package/.claude/skills/v3-ddd-architecture/SKILL.md +442 -0
- package/.claude/skills/v3-integration-deep/SKILL.md +241 -0
- package/.claude/skills/v3-mcp-optimization/SKILL.md +777 -0
- package/.claude/skills/v3-memory-unification/SKILL.md +174 -0
- package/.claude/skills/v3-performance-optimization/SKILL.md +390 -0
- package/.claude/skills/v3-security-overhaul/SKILL.md +82 -0
- package/.claude/skills/v3-swarm-coordination/SKILL.md +340 -0
- package/.claude/skills/verification-quality/SKILL.md +691 -0
- package/.claude-flow/CAPABILITIES.md +406 -0
- package/.claude-flow/config.yaml +45 -0
- package/.claude-flow/metrics/learning.json +17 -0
- package/.claude-flow/metrics/swarm-activity.json +18 -0
- package/.claude-flow/metrics/v3-progress.json +26 -0
- package/.claude-flow/security/audit-status.json +8 -0
- package/.codex/config.toml +42 -0
- package/.gemini/settings.json +51 -0
- package/.mcp.json +58 -0
- package/AGENTS.md +180 -0
- package/CLAUDE.md +277 -0
- package/GEMINI.md +48 -0
- package/README.bm.md +171 -0
- package/README.md +170 -0
- package/bin/burhan-mop.mjs +2 -0
- package/bin/mop-core.mjs +2 -0
- package/bin/mop-flow.mjs +2 -0
- package/bin/mop-workflow.mjs +2 -0
- package/package.json +72 -0
|
@@ -0,0 +1,1206 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { dirname, join, resolve } from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { randomBytes, scryptSync, timingSafeEqual } from 'node:crypto';
|
|
6
|
+
import { spawnSync } from 'node:child_process';
|
|
7
|
+
|
|
8
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
const coreDir = resolve(here, '..');
|
|
10
|
+
const rootDir = resolve(coreDir, '..');
|
|
11
|
+
const statePath = join(coreDir, 'STATE.json');
|
|
12
|
+
|
|
13
|
+
function now() {
|
|
14
|
+
return new Date().toISOString();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function readState() {
|
|
18
|
+
return JSON.parse(readFileSync(statePath, 'utf8'));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function writeState(state) {
|
|
22
|
+
mkdirSync(coreDir, { recursive: true });
|
|
23
|
+
const tmp = `${statePath}.tmp`;
|
|
24
|
+
writeFileSync(tmp, `${JSON.stringify(state, null, 2)}\n`, 'utf8');
|
|
25
|
+
renameSync(tmp, statePath);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function parseArgs(argv) {
|
|
29
|
+
const out = { _: [] };
|
|
30
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
31
|
+
const item = argv[i];
|
|
32
|
+
if (!item.startsWith('--')) {
|
|
33
|
+
out._.push(item);
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
const key = item.slice(2);
|
|
37
|
+
const next = argv[i + 1];
|
|
38
|
+
if (!next || next.startsWith('--')) {
|
|
39
|
+
out[key] = true;
|
|
40
|
+
} else {
|
|
41
|
+
out[key] = next;
|
|
42
|
+
i += 1;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return out;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function requireArg(args, key) {
|
|
49
|
+
const value = args[key];
|
|
50
|
+
if (!value || value === true) {
|
|
51
|
+
throw new Error(`Missing --${key}`);
|
|
52
|
+
}
|
|
53
|
+
return String(value);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function slug(value) {
|
|
57
|
+
return String(value)
|
|
58
|
+
.trim()
|
|
59
|
+
.toLowerCase()
|
|
60
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
61
|
+
.replace(/^-+|-+$/g, '');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function hashPassword(password, salt = randomBytes(16).toString('hex')) {
|
|
65
|
+
const passwordHash = scryptSync(password, salt, 64).toString('hex');
|
|
66
|
+
return { passwordHash, passwordSalt: salt };
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function verifyPassword(password, salt, expectedHex) {
|
|
70
|
+
const actual = scryptSync(password, salt, 64);
|
|
71
|
+
const expected = Buffer.from(expectedHex, 'hex');
|
|
72
|
+
return expected.length === actual.length && timingSafeEqual(actual, expected);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function currentGhUser() {
|
|
76
|
+
const result = spawnSync('gh', ['api', 'user', '--jq', '{login:.login,id:.id,email:.email}'], {
|
|
77
|
+
cwd: rootDir,
|
|
78
|
+
encoding: 'utf8'
|
|
79
|
+
});
|
|
80
|
+
if (result.status !== 0) return null;
|
|
81
|
+
try {
|
|
82
|
+
return JSON.parse(result.stdout || '{}');
|
|
83
|
+
} catch {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function githubNoreplyEmail(user) {
|
|
89
|
+
if (!user?.login || !user?.id) return '';
|
|
90
|
+
return `${user.id}+${user.login}@users.noreply.github.com`;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function resolveGitIdentityInput(state, actor, name, emailInput, githubUsernameInput) {
|
|
94
|
+
const policy = state.autosync?.githubIdentity || {};
|
|
95
|
+
const preferNoreply = policy.useNoreplyForMemberCommits !== false;
|
|
96
|
+
const gh = currentGhUser();
|
|
97
|
+
const githubUsername = githubUsernameInput || gh?.login || '';
|
|
98
|
+
if (gh?.login && githubUsername && policy.requireMatchedGhUser !== false && gh.login.toLowerCase() !== githubUsername.toLowerCase()) {
|
|
99
|
+
throw new Error(`GitHub CLI authenticated as ${gh.login}, expected ${githubUsername}. Run gh auth login as the real user.`);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
let email = String(emailInput || '').trim();
|
|
103
|
+
const wantsNoreply = !email || ['auto', 'github', 'github-noreply', 'noreply'].includes(email.toLowerCase());
|
|
104
|
+
if (preferNoreply && wantsNoreply) {
|
|
105
|
+
email = githubNoreplyEmail(gh);
|
|
106
|
+
if (!email) {
|
|
107
|
+
throw new Error('Cannot derive GitHub noreply email. Run gh auth login or provide --git-email "<github-verified-email>".');
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (!email && state.autosync?.requireUserGitEmail !== false) {
|
|
111
|
+
throw new Error('Git email is required. Use --git-email github-noreply after gh auth login, or provide a GitHub-verified email.');
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
name,
|
|
115
|
+
email,
|
|
116
|
+
githubUsername,
|
|
117
|
+
githubUserId: gh?.login?.toLowerCase() === githubUsername.toLowerCase() ? gh.id : undefined,
|
|
118
|
+
emailSource: wantsNoreply && email ? 'github-noreply' : 'manual'
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function activeAgentFor(state, actor) {
|
|
123
|
+
const activeId = state.activeAgents?.[actor];
|
|
124
|
+
if (!activeId) return null;
|
|
125
|
+
const agent = (state.agentRoster || []).find((item) => item.id === activeId || item.name === activeId);
|
|
126
|
+
if (!agent || !(agent.owners || []).includes(actor)) return null;
|
|
127
|
+
return agent;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function agentLedgerFields(agent) {
|
|
131
|
+
return agent ? {
|
|
132
|
+
agent: agent.name,
|
|
133
|
+
agentRole: agent.role,
|
|
134
|
+
agentId: agent.id
|
|
135
|
+
} : {};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function memoryPolicy(state) {
|
|
139
|
+
return state.memoryPolicy || {
|
|
140
|
+
enabled: true,
|
|
141
|
+
directory: '.MOP/memory',
|
|
142
|
+
sessionBrief: '.MOP/memory/SESSION_BRIEF.md',
|
|
143
|
+
monthlyPattern: 'YYYY-MM.jsonl',
|
|
144
|
+
recentLimit: 20
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function answerPolicy(state) {
|
|
149
|
+
return state.answerPolicy || {
|
|
150
|
+
requireVisibleAgent: true,
|
|
151
|
+
visibleAgentFormat: 'agent: <agent-name> (<agent-role>) to <user>',
|
|
152
|
+
requireMemoryRestore: true,
|
|
153
|
+
requireMemorySave: true
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function monthKey(date = new Date()) {
|
|
158
|
+
return date.toISOString().slice(0, 7);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function relativeFromRoot(path) {
|
|
162
|
+
return path.replace(rootDir, '').replace(/^[\\/]/, '').replaceAll('\\', '/');
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function memoryDirFor(state) {
|
|
166
|
+
return join(rootDir, memoryPolicy(state).directory || '.MOP/memory');
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function monthlyMemoryPath(state, month = monthKey()) {
|
|
170
|
+
const policy = memoryPolicy(state);
|
|
171
|
+
const filename = (policy.monthlyPattern || 'YYYY-MM.jsonl').replace('YYYY-MM', month);
|
|
172
|
+
return join(memoryDirFor(state), filename);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function sessionBriefPath(state) {
|
|
176
|
+
return join(rootDir, memoryPolicy(state).sessionBrief || '.MOP/memory/SESSION_BRIEF.md');
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function readJsonl(path) {
|
|
180
|
+
if (!existsSync(path)) return [];
|
|
181
|
+
return readFileSync(path, 'utf8')
|
|
182
|
+
.split(/\r?\n/)
|
|
183
|
+
.filter(Boolean)
|
|
184
|
+
.map((line) => {
|
|
185
|
+
try {
|
|
186
|
+
return JSON.parse(line);
|
|
187
|
+
} catch {
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
})
|
|
191
|
+
.filter(Boolean);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function memoryMonths(state) {
|
|
195
|
+
const dir = memoryDirFor(state);
|
|
196
|
+
if (!existsSync(dir)) return [];
|
|
197
|
+
return readdirSync(dir)
|
|
198
|
+
.filter((name) => /^\d{4}-\d{2}\.jsonl$/.test(name))
|
|
199
|
+
.map((name) => name.replace(/\.jsonl$/, ''))
|
|
200
|
+
.sort();
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function latestMemoryEntries(state, limit = memoryPolicy(state).recentLimit || 20) {
|
|
204
|
+
const months = memoryMonths(state);
|
|
205
|
+
const selected = months.length ? months.slice(-3) : [monthKey()];
|
|
206
|
+
return selected
|
|
207
|
+
.flatMap((month) => readJsonl(monthlyMemoryPath(state, month)))
|
|
208
|
+
.sort((a, b) => String(a.at || '').localeCompare(String(b.at || '')))
|
|
209
|
+
.slice(-limit);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function answerContractFor(state, actor, agent = activeAgentFor(state, actor)) {
|
|
213
|
+
const policy = answerPolicy(state);
|
|
214
|
+
const format = policy.visibleAgentFormat || 'agent: <agent-name> (<agent-role>) to <user>';
|
|
215
|
+
const firstLine = agent
|
|
216
|
+
? format
|
|
217
|
+
.replace('<agent-name>', agent.name)
|
|
218
|
+
.replace('<agent-role>', agent.role)
|
|
219
|
+
.replace('<agent-title>', agent.title || agent.role)
|
|
220
|
+
.replace('<user>', actor || 'user')
|
|
221
|
+
: '';
|
|
222
|
+
return {
|
|
223
|
+
required: policy.requireVisibleAgent !== false,
|
|
224
|
+
firstLine,
|
|
225
|
+
beforeAnswer: `node .MOP/scripts/mop-core.mjs memory brief --actor ${actor || '<codename>'}`,
|
|
226
|
+
afterAnswer: `node .MOP/scripts/mop-core.mjs memory add --actor ${actor || '<codename>'} --kind conversation --summary "<one-line outcome>"`,
|
|
227
|
+
rules: [
|
|
228
|
+
'Do not answer authenticated work without an active named agent.',
|
|
229
|
+
'Every user-facing answer must show the active agent line first.',
|
|
230
|
+
'Restore monthly memory before answering and save a one-line memory after meaningful work.'
|
|
231
|
+
]
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function browserPolicy(state) {
|
|
236
|
+
return state.browserPolicy || {
|
|
237
|
+
requirePreflightBeforeBrowserWork: true,
|
|
238
|
+
requireDefaultBrowserCheck: true,
|
|
239
|
+
directModeBrowsers: ['brave', 'edge', 'opera'],
|
|
240
|
+
builtinChromeBrowsers: ['chrome', 'chromium'],
|
|
241
|
+
supportedChoices: ['Chrome', 'Edge', 'Brave', 'Opera']
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function browserFamilyFromValue(raw) {
|
|
246
|
+
const value = String(raw || '').toLowerCase();
|
|
247
|
+
if (/(google-chrome|chromehtml|chrome)/.test(value) && !/chromium/.test(value)) return 'chrome';
|
|
248
|
+
if (/chromium/.test(value)) return 'chromium';
|
|
249
|
+
if (/brave/.test(value)) return 'brave';
|
|
250
|
+
if (/(microsoft-edge|mseedge|edge)/.test(value)) return 'edge';
|
|
251
|
+
if (/opera/.test(value)) return 'opera';
|
|
252
|
+
if (/firefox/.test(value)) return 'firefox';
|
|
253
|
+
return 'unknown';
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function detectWindowsDefaultBrowser() {
|
|
257
|
+
const script = [
|
|
258
|
+
'$ErrorActionPreference = "SilentlyContinue";',
|
|
259
|
+
'$keys = @(',
|
|
260
|
+
'"HKCU:\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\https\\UserChoice",',
|
|
261
|
+
'"HKCU:\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\http\\UserChoice"',
|
|
262
|
+
');',
|
|
263
|
+
'foreach ($key in $keys) {',
|
|
264
|
+
' $item = Get-ItemProperty -Path $key -Name ProgId;',
|
|
265
|
+
' if ($item.ProgId) { Write-Output $item.ProgId; break }',
|
|
266
|
+
'}'
|
|
267
|
+
].join('\n');
|
|
268
|
+
const result = spawnSync('powershell.exe', ['-NoProfile', '-NonInteractive', '-Command', script], {
|
|
269
|
+
cwd: rootDir,
|
|
270
|
+
encoding: 'utf8'
|
|
271
|
+
});
|
|
272
|
+
const raw = result.status === 0 ? (result.stdout || '').trim().split(/\r?\n/)[0] : '';
|
|
273
|
+
return raw ? { raw, source: 'windows-registry' } : null;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function detectDefaultBrowser() {
|
|
277
|
+
let detected = process.platform === 'win32' ? detectWindowsDefaultBrowser() : null;
|
|
278
|
+
if (!detected) {
|
|
279
|
+
const xdg = spawnSync('xdg-settings', ['get', 'default-web-browser'], {
|
|
280
|
+
cwd: rootDir,
|
|
281
|
+
encoding: 'utf8'
|
|
282
|
+
});
|
|
283
|
+
const raw = (xdg.status === 0 ? xdg.stdout : '').trim();
|
|
284
|
+
if (raw) detected = { raw, source: 'xdg-settings' };
|
|
285
|
+
}
|
|
286
|
+
if (!detected && process.env.BROWSER) {
|
|
287
|
+
detected = { raw: process.env.BROWSER, source: 'BROWSER' };
|
|
288
|
+
}
|
|
289
|
+
const raw = detected?.raw || '';
|
|
290
|
+
return {
|
|
291
|
+
raw: raw || null,
|
|
292
|
+
family: browserFamilyFromValue(raw),
|
|
293
|
+
source: detected?.source || 'not-detected'
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function browserPreflightFor(state) {
|
|
298
|
+
const policy = browserPolicy(state);
|
|
299
|
+
const detected = detectDefaultBrowser();
|
|
300
|
+
const direct = (policy.directModeBrowsers || []).includes(detected.family);
|
|
301
|
+
const builtin = (policy.builtinChromeBrowsers || []).includes(detected.family);
|
|
302
|
+
const supported = direct || builtin;
|
|
303
|
+
const mode = builtin ? 'chrome' : direct ? 'chrome-direct' : 'ask-user-browser';
|
|
304
|
+
const needsQuestion = !supported;
|
|
305
|
+
return {
|
|
306
|
+
required: policy.requirePreflightBeforeBrowserWork !== false,
|
|
307
|
+
defaultBrowser: detected,
|
|
308
|
+
mode,
|
|
309
|
+
ready: supported,
|
|
310
|
+
needsQuestion,
|
|
311
|
+
question: needsQuestion
|
|
312
|
+
? `Saya tak dapat kesan Chrome/Edge/Brave/Opera sebagai browser default. Awak guna browser apa? Pilih: ${(policy.supportedChoices || ['Chrome', 'Edge', 'Brave', 'Opera']).join(', ')}.`
|
|
313
|
+
: '',
|
|
314
|
+
instructions: direct
|
|
315
|
+
? [
|
|
316
|
+
`Use browser-act chrome-direct for ${detected.family}.`,
|
|
317
|
+
'Guide the user to start that browser with --remote-debugging-port before scraping or form automation.',
|
|
318
|
+
'Do not create a default chrome session first.'
|
|
319
|
+
]
|
|
320
|
+
: builtin
|
|
321
|
+
? ['Use normal Chrome-compatible browser automation.', 'Do not ask the user again unless automation fails.']
|
|
322
|
+
: ['Ask the user which browser they use before scraping or browser automation.']
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function requireActiveAgent(state, actor, role = 'core', title = 'Core Agent') {
|
|
327
|
+
const agent = activeAgentFor(state, actor);
|
|
328
|
+
if (agent) return agent;
|
|
329
|
+
throw new Error([
|
|
330
|
+
`Agent diperlukan sebelum sambung kerja untuk ${actor}.`,
|
|
331
|
+
`Task ini perlukan ${title}. Agent ini belum ada nama lagi atau belum dipilih.`,
|
|
332
|
+
`Jalankan: node .MOP/scripts/mop-core.mjs agent activate --actor ${actor} --role ${role} --title "${title}" --name "<agent-name>"`
|
|
333
|
+
].join(' '));
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
function appendLedger(state, actor, kind, summary, agent = activeAgentFor(state, actor)) {
|
|
337
|
+
state.ledger ||= [];
|
|
338
|
+
state.ledger.push({ at: now(), actor, ...agentLedgerFields(agent), kind, summary });
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
function appendMonthlyMemory(state, actor, kind, summary, agent = activeAgentFor(state, actor)) {
|
|
342
|
+
if (memoryPolicy(state).enabled === false) return null;
|
|
343
|
+
const entry = { at: now(), actor, ...agentLedgerFields(agent), kind, summary };
|
|
344
|
+
const monthlyPath = monthlyMemoryPath(state);
|
|
345
|
+
mkdirSync(dirname(monthlyPath), { recursive: true });
|
|
346
|
+
writeFileSync(monthlyPath, `${JSON.stringify(entry)}\n`, { encoding: 'utf8', flag: 'a' });
|
|
347
|
+
writeSessionBrief(state, actor);
|
|
348
|
+
return { entry, monthlyPath };
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
function writeSessionBrief(state, actor) {
|
|
352
|
+
const path = sessionBriefPath(state);
|
|
353
|
+
const agent = activeAgentFor(state, actor);
|
|
354
|
+
const entries = latestMemoryEntries(state, memoryPolicy(state).recentLimit || 20);
|
|
355
|
+
const contract = answerContractFor(state, actor, agent);
|
|
356
|
+
const lines = [
|
|
357
|
+
'# MOP Session Brief',
|
|
358
|
+
'',
|
|
359
|
+
`Updated: ${now()}`,
|
|
360
|
+
`Actor: ${actor || state.activeMember || 'unknown'}`,
|
|
361
|
+
`Active agent: ${agent ? `${agent.name} (${agent.role})` : 'none'}`,
|
|
362
|
+
`Current month: ${monthKey()}`,
|
|
363
|
+
'',
|
|
364
|
+
'## Required Session Flow',
|
|
365
|
+
'',
|
|
366
|
+
'1. Read `.MOP/STATE.json` and follow `.MOP/PROTOCOL.md`.',
|
|
367
|
+
'2. Authenticate if required.',
|
|
368
|
+
'3. Run `agent route` for the user task before answering.',
|
|
369
|
+
`4. Start every authenticated answer with: \`${contract.firstLine || 'agent: <name> (<role>) to <user>'}\``,
|
|
370
|
+
'5. Save a one-line memory after meaningful work.',
|
|
371
|
+
'',
|
|
372
|
+
'## Recent Memory',
|
|
373
|
+
'',
|
|
374
|
+
...entries.map((entry) => {
|
|
375
|
+
const who = entry.agent ? `${entry.agent} (${entry.agentRole || 'agent'})` : entry.actor;
|
|
376
|
+
return `- ${entry.at} - ${who}: ${entry.summary}`;
|
|
377
|
+
})
|
|
378
|
+
];
|
|
379
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
380
|
+
writeFileSync(path, `${lines.join('\n')}\n`, 'utf8');
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
const routeRules = [
|
|
384
|
+
{
|
|
385
|
+
role: 'memory',
|
|
386
|
+
support: ['researcher'],
|
|
387
|
+
keywords: ['memory', 'memori', 'ingat', 'recall', 'search', 'cari semula', 'journal', 'ledger', 'history', 'sejarah']
|
|
388
|
+
},
|
|
389
|
+
{
|
|
390
|
+
role: 'github',
|
|
391
|
+
support: ['reviewer'],
|
|
392
|
+
keywords: ['github', 'git', 'branch', 'merge', 'megre', 'commit', 'push', 'pull', 'pr', 'repo', 'repository', 'autosycn', 'autosync']
|
|
393
|
+
},
|
|
394
|
+
{
|
|
395
|
+
role: 'deploy',
|
|
396
|
+
support: ['devops', 'github'],
|
|
397
|
+
keywords: ['deploy', 'deployment', 'vercel', 'docker', 'github pages', 'github actions', 'hosting', 'release']
|
|
398
|
+
},
|
|
399
|
+
{
|
|
400
|
+
role: 'security',
|
|
401
|
+
support: ['architect', 'reviewer'],
|
|
402
|
+
keywords: ['security', 'secure', 'auth', 'login', 'password', 'token', 'secret', 'permission', 'role', 'akses', 'encrypt', 'api key']
|
|
403
|
+
},
|
|
404
|
+
{
|
|
405
|
+
role: 'performance',
|
|
406
|
+
support: ['architect', 'coder'],
|
|
407
|
+
keywords: ['performance', 'slow', 'lambat', 'speed', 'optimize', 'latency', 'memory leak', 'bundle', 'cache']
|
|
408
|
+
},
|
|
409
|
+
{
|
|
410
|
+
role: 'database',
|
|
411
|
+
support: ['backend', 'architect'],
|
|
412
|
+
keywords: ['database', 'db', 'schema', 'migration', 'sql', 'postgres', 'mysql', 'sqlite', 'prisma', 'query']
|
|
413
|
+
},
|
|
414
|
+
{
|
|
415
|
+
role: 'backend',
|
|
416
|
+
support: ['database', 'security', 'tester'],
|
|
417
|
+
keywords: ['backend', 'api', 'server', 'endpoint', 'route', 'auth api', 'middleware', 'webhook', 'integration']
|
|
418
|
+
},
|
|
419
|
+
{
|
|
420
|
+
role: 'frontend',
|
|
421
|
+
support: ['design', 'ux', 'tester'],
|
|
422
|
+
keywords: ['frontend', 'ui', 'react', 'next', 'vue', 'css', 'tailwind', 'component', 'page', 'browser', 'dashboard']
|
|
423
|
+
},
|
|
424
|
+
{
|
|
425
|
+
role: 'mobile',
|
|
426
|
+
support: ['ux', 'backend'],
|
|
427
|
+
keywords: ['mobile', 'android', 'ios', 'react native', 'flutter', 'pwa']
|
|
428
|
+
},
|
|
429
|
+
{
|
|
430
|
+
role: 'design',
|
|
431
|
+
support: ['ux', 'frontend'],
|
|
432
|
+
keywords: ['design', 'ui/ux', 'layout', 'figma', 'wireframe', 'visual', 'color', 'theme', 'responsive']
|
|
433
|
+
},
|
|
434
|
+
{
|
|
435
|
+
role: 'ux',
|
|
436
|
+
support: ['planner', 'design'],
|
|
437
|
+
keywords: ['ux', 'user flow', 'persona', 'journey', 'usability', 'pengguna', 'flow']
|
|
438
|
+
},
|
|
439
|
+
{
|
|
440
|
+
role: 'tester',
|
|
441
|
+
support: ['reviewer'],
|
|
442
|
+
keywords: ['test', 'testing', 'bug', 'error', 'fix', 'regression', 'playwright', 'vitest', 'jest', 'qa']
|
|
443
|
+
},
|
|
444
|
+
{
|
|
445
|
+
role: 'reviewer',
|
|
446
|
+
support: ['security', 'tester'],
|
|
447
|
+
keywords: ['review', 'semak', 'audit', 'check', 'validate', 'risk', 'risiko', 'quality']
|
|
448
|
+
},
|
|
449
|
+
{
|
|
450
|
+
role: 'docs',
|
|
451
|
+
support: ['prompt'],
|
|
452
|
+
keywords: ['docs', 'documentation', 'readme', 'guide', 'manual', 'changelog', 'spec', 'tulis']
|
|
453
|
+
},
|
|
454
|
+
{
|
|
455
|
+
role: 'prompt',
|
|
456
|
+
support: ['architect', 'docs'],
|
|
457
|
+
keywords: ['prompt', 'prompts', 'copy to prompts', 'ai prompt', 'system prompt', 'agent prompt', 'chatgpt', 'claude', 'gemini']
|
|
458
|
+
},
|
|
459
|
+
{
|
|
460
|
+
role: 'architect',
|
|
461
|
+
support: ['planner', 'researcher', 'coder', 'reviewer'],
|
|
462
|
+
keywords: ['system', 'architecture', 'architect', 'platform', 'workflow', 'engine', 'core', 'framework', 'template', 'buat sebuah system', 'bina system']
|
|
463
|
+
},
|
|
464
|
+
{
|
|
465
|
+
role: 'planner',
|
|
466
|
+
support: ['architect', 'researcher'],
|
|
467
|
+
keywords: ['plan', 'roadmap', 'scope', 'idea', 'konsep', 'feature', 'requirement', 'mvp', 'project']
|
|
468
|
+
},
|
|
469
|
+
{
|
|
470
|
+
role: 'coder',
|
|
471
|
+
support: ['tester', 'reviewer'],
|
|
472
|
+
keywords: ['code', 'coding', 'implement', 'buat file', 'ubah file', 'fix code', 'script', 'function']
|
|
473
|
+
},
|
|
474
|
+
{
|
|
475
|
+
role: 'browser',
|
|
476
|
+
support: ['researcher', 'tester'],
|
|
477
|
+
keywords: ['agent browser', 'browser agent', 'browser automation', 'browser', 'browse', 'scrape', 'scraping', 'web scraping', 'extract', 'click', 'login flow', 'fill form', 'captcha', 'bot detection', 'website', 'url', 'webpage']
|
|
478
|
+
},
|
|
479
|
+
{
|
|
480
|
+
role: 'researcher',
|
|
481
|
+
support: ['planner'],
|
|
482
|
+
keywords: ['research', 'kaji', 'compare', 'pilih', 'cari info', 'best practice']
|
|
483
|
+
}
|
|
484
|
+
];
|
|
485
|
+
|
|
486
|
+
function catalogForRole(state, role) {
|
|
487
|
+
return (state.agentCatalog || []).find((item) => item.role === role) || {
|
|
488
|
+
role,
|
|
489
|
+
title: role.split('-').map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(' ')
|
|
490
|
+
};
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
function ownedAgentForRole(state, actor, role) {
|
|
494
|
+
return (state.agentRoster || []).find((agent) => agent.role === role && (agent.owners || []).includes(actor)) || null;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
function routeScore(task, rule) {
|
|
498
|
+
return rule.keywords.reduce((score, keyword) => task.includes(keyword) ? score + Math.max(1, keyword.split(/\s+/).length) : score, 0);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
function hasBrowserWorkIntent(task) {
|
|
502
|
+
return /\b(agent browser|browser agent|browser automation|browse|scrape|scraping|web scraping|extract|click|login flow|fill form|captcha|bot detection|webpage|url)\b/.test(task);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
function uniqueValues(values) {
|
|
506
|
+
return [...new Set(values.filter(Boolean))];
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
function maybeLimit(values, limit) {
|
|
510
|
+
if (limit === null || limit === undefined || limit === '' || limit === 'unlimited') return values;
|
|
511
|
+
const numeric = Number(limit);
|
|
512
|
+
if (!Number.isFinite(numeric) || numeric < 1) return values;
|
|
513
|
+
return values.slice(0, numeric);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
function shouldActivatePartyMode(state, task, primaryRole, supportRoles, newSystemIntent) {
|
|
517
|
+
if (state.partyMode?.enabled === false || state.partyMode?.autoActivateWhenNeeded === false) return false;
|
|
518
|
+
const explicitPartyIntent = /\b(party mode|party|multi[- ]?agent|swarm|semua agent|banyak agent|agent.*bincang|bincang.*agent|agent.*discuss|discuss.*agent)\b/.test(task);
|
|
519
|
+
const multiDomainIntent = [
|
|
520
|
+
['ui', 'backend'],
|
|
521
|
+
['frontend', 'backend'],
|
|
522
|
+
['design', 'api'],
|
|
523
|
+
['database', 'api'],
|
|
524
|
+
['deploy', 'github'],
|
|
525
|
+
['security', 'auth'],
|
|
526
|
+
['prompt', 'system']
|
|
527
|
+
].some(([first, second]) => task.includes(first) && task.includes(second));
|
|
528
|
+
const browserRiskIntent = hasBrowserWorkIntent(task);
|
|
529
|
+
const connectiveIntent = /\b(connect|connected|integrate|integration|bersambung|sambung|hubung|flow|workflow)\b/.test(task);
|
|
530
|
+
const broadBuild = newSystemIntent && supportRoles.length >= 2;
|
|
531
|
+
const specialistStack = supportRoles.length >= 3 && ['architect', 'planner', 'core'].includes(primaryRole);
|
|
532
|
+
return explicitPartyIntent || multiDomainIntent || browserRiskIntent || connectiveIntent || broadBuild || specialistStack;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
function partyFormat(state) {
|
|
536
|
+
const format = state.partyMode?.format || {};
|
|
537
|
+
return {
|
|
538
|
+
banner: format.banner || state.partyMode?.banner || 'PARTY MODE',
|
|
539
|
+
agentToAgent: format.agentToAgent || 'agent: <from-name> (<from-role>) to agent: <to-name> (<to-role>)',
|
|
540
|
+
agentToUser: format.agentToUser || 'agent: <from-name> (<from-role>) to <user>',
|
|
541
|
+
explanation: format.explanation || 'agent: <from-name> (<from-role>)',
|
|
542
|
+
messageIndent: format.messageIndent || ' ',
|
|
543
|
+
blankLineBeforeMessage: format.blankLineBeforeMessage !== false
|
|
544
|
+
};
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
function partyParticipantsFor(state, primaryRole, supportRoles, scored, partyActive) {
|
|
548
|
+
if (!partyActive) return [];
|
|
549
|
+
const preferredMinimum = Number(state.partyMode?.preferredMinimumParticipants || 4);
|
|
550
|
+
const minimum = Number(state.partyMode?.minimumParticipants || 3);
|
|
551
|
+
const floor = Number.isFinite(preferredMinimum) ? Math.max(minimum, preferredMinimum) : minimum;
|
|
552
|
+
const fallbackRoles = ['planner', 'researcher', 'reviewer', 'coder', 'architect', 'prompt', 'tester'];
|
|
553
|
+
const relevant = uniqueValues([
|
|
554
|
+
primaryRole,
|
|
555
|
+
...supportRoles,
|
|
556
|
+
...scored.map((rule) => rule.role)
|
|
557
|
+
]);
|
|
558
|
+
const participants = relevant.length >= floor
|
|
559
|
+
? relevant
|
|
560
|
+
: uniqueValues([...relevant, ...fallbackRoles]).slice(0, floor);
|
|
561
|
+
const catalogRoles = new Set((state.agentCatalog || []).map((item) => item.role));
|
|
562
|
+
const filtered = participants.filter((role) => catalogRoles.has(role));
|
|
563
|
+
const enough = filtered.length >= floor ? filtered : participants;
|
|
564
|
+
return maybeLimit(enough, state.partyMode?.participantLimit);
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
function inferAgentRoute(state, taskText) {
|
|
568
|
+
const task = taskText.toLowerCase();
|
|
569
|
+
const words = task.split(/\s+/).filter(Boolean);
|
|
570
|
+
const scored = routeRules
|
|
571
|
+
.map((rule) => ({ ...rule, score: routeScore(task, rule) }))
|
|
572
|
+
.filter((rule) => rule.score > 0)
|
|
573
|
+
.sort((a, b) => b.score - a.score);
|
|
574
|
+
|
|
575
|
+
const newSystemIntent = /\b(system|sistem|app|tool|platform|website|dashboard|engine|core)\b/.test(task)
|
|
576
|
+
|| /buat sebuah|bina sebuah|create a|build a/.test(task);
|
|
577
|
+
const implementationIntent = /\b(code|coding|implement|fix|ubah file|buat file)\b/.test(task);
|
|
578
|
+
const browserWorkIntent = hasBrowserWorkIntent(task);
|
|
579
|
+
const top = scored[0];
|
|
580
|
+
let primaryRole = browserWorkIntent ? 'browser' : (top?.role || state.agentPolicy?.defaultRole || 'core');
|
|
581
|
+
|
|
582
|
+
if (newSystemIntent && !implementationIntent && !browserWorkIntent && state.agentRouter?.preferHighReasoningForNewSystems !== false) {
|
|
583
|
+
primaryRole = state.agentRouter?.defaultHighReasoningRole || 'architect';
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
const primary = catalogForRole(state, primaryRole);
|
|
587
|
+
const baseSupport = newSystemIntent && !browserWorkIntent
|
|
588
|
+
? ['planner', 'researcher', 'prompt', 'coder', 'reviewer']
|
|
589
|
+
: (top?.support || []);
|
|
590
|
+
const supportRoles = maybeLimit(uniqueValues([
|
|
591
|
+
...baseSupport,
|
|
592
|
+
...scored.slice(1).map((rule) => rule.role)
|
|
593
|
+
])
|
|
594
|
+
.filter((role) => role !== primaryRole), state.agentRouter?.supportAgentLimit);
|
|
595
|
+
const partyActive = shouldActivatePartyMode(state, task, primaryRole, supportRoles, newSystemIntent);
|
|
596
|
+
const partyParticipants = partyParticipantsFor(state, primaryRole, supportRoles, scored, partyActive);
|
|
597
|
+
|
|
598
|
+
const ambiguousNewSystem = newSystemIntent && !browserWorkIntent && words.length < 18;
|
|
599
|
+
const noClearMatch = scored.length === 0 && words.length > 3;
|
|
600
|
+
const needsClarification = state.agentRouter?.clarifyBeforeActionWhenAmbiguous !== false
|
|
601
|
+
&& (ambiguousNewSystem || noClearMatch || /\b(maybe|mungkin|lebih kurang|macam)\b/.test(task));
|
|
602
|
+
|
|
603
|
+
const questions = needsClarification ? [
|
|
604
|
+
'Apa tujuan utama system ini dan masalah apa yang dia selesaikan?',
|
|
605
|
+
'Siapa pengguna utama system ini?',
|
|
606
|
+
'Output wajib apa yang awak nak lihat dulu: plan, UI, repo/file, atau prompt template?'
|
|
607
|
+
] : [];
|
|
608
|
+
|
|
609
|
+
return {
|
|
610
|
+
task: taskText,
|
|
611
|
+
primaryRole,
|
|
612
|
+
primaryTitle: primary.title,
|
|
613
|
+
supportRoles,
|
|
614
|
+
partyMode: {
|
|
615
|
+
active: partyActive,
|
|
616
|
+
banner: partyActive && state.partyMode?.bannerRequired !== false ? (state.partyMode?.banner || 'PARTY MODE') : '',
|
|
617
|
+
participants: partyActive ? partyParticipants : [],
|
|
618
|
+
minimumParticipants: state.partyMode?.minimumParticipants || 3,
|
|
619
|
+
preferredMinimumParticipants: state.partyMode?.preferredMinimumParticipants || 4,
|
|
620
|
+
visibleToUser: state.partyMode?.showAgentDialogueToUser !== false,
|
|
621
|
+
format: partyFormat(state),
|
|
622
|
+
reason: partyActive
|
|
623
|
+
? 'Task needs several specialist agents to reason together before the primary agent answers the user.'
|
|
624
|
+
: 'Single-agent route is enough for this task.'
|
|
625
|
+
},
|
|
626
|
+
confidence: top ? Math.min(0.95, 0.45 + (top.score * 0.08)) : 0.35,
|
|
627
|
+
needsClarification,
|
|
628
|
+
questions,
|
|
629
|
+
reason: newSystemIntent && !browserWorkIntent
|
|
630
|
+
? `New or broad system task routed to ${primary.title} for high-reasoning planning before implementation.`
|
|
631
|
+
: top
|
|
632
|
+
? `Matched keywords for ${primary.title}: ${top.keywords.filter((keyword) => task.includes(keyword)).join(', ')}.`
|
|
633
|
+
: `No strong specialist match; using ${primary.title}.`
|
|
634
|
+
};
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
function setup(args) {
|
|
638
|
+
const state = readState();
|
|
639
|
+
if (state.initialized) {
|
|
640
|
+
throw new Error('MOP already initialized.');
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
const folderDefault = rootDir.split(/[\\/]/).filter(Boolean).pop() || 'MOP';
|
|
644
|
+
const projectName = String(args['project-name'] || folderDefault);
|
|
645
|
+
const displayName = requireArg(args, 'name');
|
|
646
|
+
const codename = slug(requireArg(args, 'codename'));
|
|
647
|
+
const password = requireArg(args, 'password');
|
|
648
|
+
const mode = requireArg(args, 'mode').toLowerCase();
|
|
649
|
+
const conversationLanguage = String(args['conversation-language'] || 'Melayu');
|
|
650
|
+
const codingLanguage = String(args['coding-language'] || 'English');
|
|
651
|
+
const githubUrl = String(args['github-url'] || '');
|
|
652
|
+
const gitName = String(args['git-name'] || displayName);
|
|
653
|
+
const gitEmail = String(args['git-email'] || 'github-noreply');
|
|
654
|
+
const githubUsername = String(args['github-username'] || '');
|
|
655
|
+
const joinMode = String(args['join-mode'] || 'owner-approved');
|
|
656
|
+
|
|
657
|
+
if (codename.length < 2) throw new Error('Codename too short.');
|
|
658
|
+
if (password.length < 8) throw new Error('Password must be at least 8 characters.');
|
|
659
|
+
if (!['solo', 'team'].includes(mode)) throw new Error('Mode must be solo or team.');
|
|
660
|
+
if (mode === 'team' && !githubUrl) throw new Error('Team mode requires --github-url.');
|
|
661
|
+
if (!['open', 'owner-approved', 'invite'].includes(joinMode)) {
|
|
662
|
+
throw new Error('Join mode must be open, owner-approved, or invite.');
|
|
663
|
+
}
|
|
664
|
+
const gitIdentity = resolveGitIdentityInput(state, codename, gitName, gitEmail, githubUsername);
|
|
665
|
+
|
|
666
|
+
const { passwordHash, passwordSalt } = hashPassword(password);
|
|
667
|
+
state.initialized = true;
|
|
668
|
+
state.projectName = projectName;
|
|
669
|
+
state.projectNameDefault = folderDefault;
|
|
670
|
+
state.ownerCodename = codename;
|
|
671
|
+
state.activeMember = codename;
|
|
672
|
+
state.activeAgents ||= {};
|
|
673
|
+
state.agentPolicy ||= {
|
|
674
|
+
requiredAfterAuth: true,
|
|
675
|
+
requireForEveryConversation: true,
|
|
676
|
+
defaultRole: 'core',
|
|
677
|
+
defaultTitle: 'Core Agent',
|
|
678
|
+
gateOrder: 'AUTH_GATE_THEN_AGENT_ROUTER_THEN_AGENT_GATE_THEN_ACTION'
|
|
679
|
+
};
|
|
680
|
+
state.mode = mode;
|
|
681
|
+
state.joinMode = mode === 'team' ? joinMode : 'owner-approved';
|
|
682
|
+
state.githubUrl = githubUrl;
|
|
683
|
+
state.members = {
|
|
684
|
+
[codename]: {
|
|
685
|
+
codename,
|
|
686
|
+
displayName,
|
|
687
|
+
role: 'owner',
|
|
688
|
+
passwordHash,
|
|
689
|
+
passwordSalt,
|
|
690
|
+
languagePreferences: {
|
|
691
|
+
conversation: conversationLanguage,
|
|
692
|
+
coding: codingLanguage
|
|
693
|
+
},
|
|
694
|
+
gitIdentity,
|
|
695
|
+
joinedAt: now()
|
|
696
|
+
}
|
|
697
|
+
};
|
|
698
|
+
appendLedger(state, codename, 'setup', `Initialized ${projectName} in ${mode} mode.`);
|
|
699
|
+
writeState(state);
|
|
700
|
+
console.log(`MOP initialized. Owner ${displayName} (${codename}) is active.`);
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
function login(args) {
|
|
704
|
+
const state = readState();
|
|
705
|
+
const codename = slug(requireArg(args, 'codename'));
|
|
706
|
+
const password = requireArg(args, 'password');
|
|
707
|
+
const member = state.members?.[codename];
|
|
708
|
+
if (!member || !verifyPassword(password, member.passwordSalt, member.passwordHash)) {
|
|
709
|
+
console.log('Credentials tidak sah.');
|
|
710
|
+
process.exitCode = 1;
|
|
711
|
+
return;
|
|
712
|
+
}
|
|
713
|
+
state.activeMember = codename;
|
|
714
|
+
appendLedger(state, codename, 'login', 'Member authenticated.');
|
|
715
|
+
writeState(state);
|
|
716
|
+
console.log(`Active member: ${codename}`);
|
|
717
|
+
if (!activeAgentFor(state, codename) && state.agentPolicy?.requiredAfterAuth !== false) {
|
|
718
|
+
console.log(`Agent diperlukan. Jalankan: node .MOP/scripts/mop-core.mjs agent activate --actor ${codename} --role ${state.agentPolicy?.defaultRole || 'core'} --title "${state.agentPolicy?.defaultTitle || 'Core Agent'}" --name "<agent-name>"`);
|
|
719
|
+
} else {
|
|
720
|
+
console.log(JSON.stringify({
|
|
721
|
+
next: 'restore-memory-and-route-task',
|
|
722
|
+
memoryRestore: `node .MOP/scripts/mop-core.mjs memory brief --actor ${codename}`,
|
|
723
|
+
answerContract: answerContractFor(state, codename)
|
|
724
|
+
}, null, 2));
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
function agentActivate(args) {
|
|
729
|
+
const state = readState();
|
|
730
|
+
if (!state.initialized) throw new Error('MOP is not initialized.');
|
|
731
|
+
const actor = slug(requireArg(args, 'actor'));
|
|
732
|
+
if (!state.members?.[actor]) throw new Error('Unknown actor.');
|
|
733
|
+
|
|
734
|
+
const role = slug(requireArg(args, 'role'));
|
|
735
|
+
const title = String(args.title || role);
|
|
736
|
+
const name = requireArg(args, 'name').trim();
|
|
737
|
+
const key = name.toLowerCase();
|
|
738
|
+
state.agentRoster ||= [];
|
|
739
|
+
state.activeAgents ||= {};
|
|
740
|
+
|
|
741
|
+
let agent = state.agentRoster.find((item) => item.name.toLowerCase() === key);
|
|
742
|
+
if (agent) {
|
|
743
|
+
agent.owners ||= [];
|
|
744
|
+
if (!agent.owners.includes(actor)) agent.owners.push(actor);
|
|
745
|
+
appendLedger(state, actor, 'agent-share', `${actor} joined agent ${agent.name}.`);
|
|
746
|
+
} else {
|
|
747
|
+
agent = {
|
|
748
|
+
id: `agent-${slug(name)}`,
|
|
749
|
+
role,
|
|
750
|
+
title,
|
|
751
|
+
name,
|
|
752
|
+
owners: [actor],
|
|
753
|
+
createdBy: actor,
|
|
754
|
+
createdAt: now()
|
|
755
|
+
};
|
|
756
|
+
state.agentRoster.push(agent);
|
|
757
|
+
appendLedger(state, actor, 'agent-activate', `Named ${title} as ${name}.`);
|
|
758
|
+
}
|
|
759
|
+
state.activeAgents[actor] = agent.id;
|
|
760
|
+
appendLedger(state, actor, 'agent-use', `Set active agent to ${agent.name}.`, agent);
|
|
761
|
+
writeState(state);
|
|
762
|
+
console.log(`Agent active: ${agent.name} (${agent.role}) owners=${agent.owners.join(',')}`);
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
function agentUse(args) {
|
|
766
|
+
const state = readState();
|
|
767
|
+
if (!state.initialized) throw new Error('MOP is not initialized.');
|
|
768
|
+
const actor = slug(requireArg(args, 'actor'));
|
|
769
|
+
if (!state.members?.[actor]) throw new Error('Unknown actor.');
|
|
770
|
+
const name = requireArg(args, 'name').trim();
|
|
771
|
+
const agent = (state.agentRoster || []).find((item) => item.name.toLowerCase() === name.toLowerCase());
|
|
772
|
+
if (!agent) throw new Error(`Unknown agent: ${name}`);
|
|
773
|
+
if (!(agent.owners || []).includes(actor)) throw new Error(`${actor} does not own agent ${agent.name}.`);
|
|
774
|
+
state.activeAgents ||= {};
|
|
775
|
+
state.activeAgents[actor] = agent.id;
|
|
776
|
+
appendLedger(state, actor, 'agent-use', `Set active agent to ${agent.name}.`, agent);
|
|
777
|
+
writeState(state);
|
|
778
|
+
console.log(`Active agent for ${actor}: ${agent.name} (${agent.role})`);
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
function agentCurrent(args) {
|
|
782
|
+
const state = readState();
|
|
783
|
+
const actor = slug(requireArg(args, 'actor'));
|
|
784
|
+
const agent = activeAgentFor(state, actor);
|
|
785
|
+
if (!agent) {
|
|
786
|
+
console.log(`No active agent for ${actor}.`);
|
|
787
|
+
process.exitCode = 2;
|
|
788
|
+
return;
|
|
789
|
+
}
|
|
790
|
+
console.log(JSON.stringify({
|
|
791
|
+
actor,
|
|
792
|
+
agent: agent.name,
|
|
793
|
+
role: agent.role,
|
|
794
|
+
title: agent.title,
|
|
795
|
+
id: agent.id
|
|
796
|
+
}, null, 2));
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
function agentRequire(args) {
|
|
800
|
+
const state = readState();
|
|
801
|
+
const actor = slug(requireArg(args, 'actor'));
|
|
802
|
+
const role = slug(String(args.role || state.agentPolicy?.defaultRole || 'core'));
|
|
803
|
+
const title = String(args.title || state.agentPolicy?.defaultTitle || 'Core Agent');
|
|
804
|
+
const agent = requireActiveAgent(state, actor, role, title);
|
|
805
|
+
console.log(JSON.stringify({
|
|
806
|
+
actor,
|
|
807
|
+
agent: agent.name,
|
|
808
|
+
role: agent.role,
|
|
809
|
+
title: agent.title,
|
|
810
|
+
id: agent.id
|
|
811
|
+
}, null, 2));
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
function agentRoute(args) {
|
|
815
|
+
const state = readState();
|
|
816
|
+
if (!state.initialized) throw new Error('MOP is not initialized.');
|
|
817
|
+
if (state.agentRouter?.enabled === false) throw new Error('Agent Router is disabled.');
|
|
818
|
+
const actor = slug(requireArg(args, 'actor'));
|
|
819
|
+
if (!state.members?.[actor]) throw new Error('Unknown actor.');
|
|
820
|
+
const task = String(args.task || args._?.join(' ') || '').trim();
|
|
821
|
+
if (!task) throw new Error('Missing --task');
|
|
822
|
+
|
|
823
|
+
const route = inferAgentRoute(state, task);
|
|
824
|
+
const agent = ownedAgentForRole(state, actor, route.primaryRole);
|
|
825
|
+
const partyAgents = route.partyMode.active ? route.partyMode.participants.map((role) => {
|
|
826
|
+
const catalog = catalogForRole(state, role);
|
|
827
|
+
const owned = ownedAgentForRole(state, actor, role);
|
|
828
|
+
return {
|
|
829
|
+
role,
|
|
830
|
+
title: catalog.title,
|
|
831
|
+
name: owned?.name || null,
|
|
832
|
+
id: owned?.id || null,
|
|
833
|
+
missing: !owned
|
|
834
|
+
};
|
|
835
|
+
}) : [];
|
|
836
|
+
const missingPartyAgents = partyAgents.filter((item) => item.missing);
|
|
837
|
+
const missingAgentCommands = missingPartyAgents.map((item) => (
|
|
838
|
+
`node .MOP/scripts/mop-core.mjs agent activate --actor ${actor} --role ${item.role} --title "${item.title}" --name "<agent-name>"`
|
|
839
|
+
));
|
|
840
|
+
const missingAgentQuestions = missingPartyAgents.map((item) => (
|
|
841
|
+
`Beri nama untuk ${item.title} (${item.role}) kamu:`
|
|
842
|
+
));
|
|
843
|
+
const browserPreflight = route.primaryRole === 'browser'
|
|
844
|
+
|| route.supportRoles.includes('browser')
|
|
845
|
+
|| route.partyMode?.participants?.includes('browser')
|
|
846
|
+
|| hasBrowserWorkIntent(route.task || '')
|
|
847
|
+
? browserPreflightFor(state)
|
|
848
|
+
: null;
|
|
849
|
+
const response = {
|
|
850
|
+
ok: Boolean(agent),
|
|
851
|
+
actor,
|
|
852
|
+
route,
|
|
853
|
+
partyAgents,
|
|
854
|
+
missingAgents: missingPartyAgents,
|
|
855
|
+
activeAgent: null,
|
|
856
|
+
answerContract: null,
|
|
857
|
+
browserPreflight,
|
|
858
|
+
monthlyMemory: {
|
|
859
|
+
restoreCommand: `node .MOP/scripts/mop-core.mjs memory brief --actor ${actor}`,
|
|
860
|
+
saveCommand: `node .MOP/scripts/mop-core.mjs memory add --actor ${actor} --kind conversation --summary "<one-line outcome>"`
|
|
861
|
+
},
|
|
862
|
+
nextAction: null
|
|
863
|
+
};
|
|
864
|
+
|
|
865
|
+
if (agent) {
|
|
866
|
+
state.activeAgents ||= {};
|
|
867
|
+
state.activeAgents[actor] = agent.id;
|
|
868
|
+
appendLedger(state, actor, 'agent-route', `Routed task to ${agent.name}: ${route.reason}`, agent);
|
|
869
|
+
writeState(state);
|
|
870
|
+
response.activeAgent = {
|
|
871
|
+
id: agent.id,
|
|
872
|
+
name: agent.name,
|
|
873
|
+
role: agent.role,
|
|
874
|
+
title: agent.title
|
|
875
|
+
};
|
|
876
|
+
response.answerContract = answerContractFor(state, actor, agent);
|
|
877
|
+
if (route.partyMode.active && missingPartyAgents.length) {
|
|
878
|
+
response.ok = false;
|
|
879
|
+
response.nextAction = 'name-required-party-agents';
|
|
880
|
+
response.message = `Party Mode perlukan ${missingPartyAgents.length} agent yang belum ada nama. Minta nama semua agent ini dahulu sebelum sambung kerja.`;
|
|
881
|
+
response.ask = `Kita ada ${missingPartyAgents.length} agent belum ada nama. ${missingAgentQuestions.join(' ')}`;
|
|
882
|
+
response.missingAgentQuestions = missingAgentQuestions;
|
|
883
|
+
response.missingAgentCommands = missingAgentCommands;
|
|
884
|
+
} else if (browserPreflight?.required && browserPreflight.needsQuestion) {
|
|
885
|
+
response.ok = false;
|
|
886
|
+
response.nextAction = 'ask-browser-before-browser-work';
|
|
887
|
+
response.message = 'Browser preflight belum ready. Tanya browser user dahulu sebelum scraping/browser automation.';
|
|
888
|
+
response.ask = browserPreflight.question;
|
|
889
|
+
} else {
|
|
890
|
+
response.nextAction = route.needsClarification ? 'ask-clarifying-questions' : 'proceed-with-agent';
|
|
891
|
+
}
|
|
892
|
+
} else {
|
|
893
|
+
response.nextAction = route.partyMode.active && missingPartyAgents.length
|
|
894
|
+
? 'name-required-party-agents'
|
|
895
|
+
: 'name-required-agent';
|
|
896
|
+
response.message = route.partyMode.active && missingPartyAgents.length
|
|
897
|
+
? `Party Mode perlukan ${missingPartyAgents.length} agent yang belum ada nama. Minta nama semua agent ini dahulu sebelum sambung kerja.`
|
|
898
|
+
: `Task ini perlukan ${route.primaryTitle}. Agent ini belum ada nama lagi atau belum dipilih.`;
|
|
899
|
+
response.ask = route.partyMode.active && missingPartyAgents.length
|
|
900
|
+
? `Kita ada ${missingPartyAgents.length} agent belum ada nama. ${missingAgentQuestions.join(' ')}`
|
|
901
|
+
: `Beri nama untuk ${route.primaryTitle} kamu:`;
|
|
902
|
+
response.command = `node .MOP/scripts/mop-core.mjs agent activate --actor ${actor} --role ${route.primaryRole} --title "${route.primaryTitle}" --name "<agent-name>"`;
|
|
903
|
+
if (route.partyMode.active && missingPartyAgents.length) {
|
|
904
|
+
response.missingAgentQuestions = missingAgentQuestions;
|
|
905
|
+
response.missingAgentCommands = missingAgentCommands;
|
|
906
|
+
}
|
|
907
|
+
if (route.needsClarification) response.afterNaming = route.questions;
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
console.log(JSON.stringify(response, null, 2));
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
function agentList() {
|
|
914
|
+
const state = readState();
|
|
915
|
+
console.log(JSON.stringify({
|
|
916
|
+
activeAgents: state.activeAgents || {},
|
|
917
|
+
agents: state.agentRoster || []
|
|
918
|
+
}, null, 2));
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
function browserPreflight() {
|
|
922
|
+
const state = readState();
|
|
923
|
+
console.log(JSON.stringify(browserPreflightFor(state), null, 2));
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
function memoryAdd(args) {
|
|
927
|
+
const state = readState();
|
|
928
|
+
if (!state.initialized) throw new Error('MOP is not initialized.');
|
|
929
|
+
const actor = slug(requireArg(args, 'actor'));
|
|
930
|
+
if (!state.members?.[actor]) throw new Error('Unknown actor.');
|
|
931
|
+
const agent = requireActiveAgent(state, actor);
|
|
932
|
+
const summary = String(args.summary || args._?.join(' ') || '').trim();
|
|
933
|
+
const kind = String(args.kind || 'conversation');
|
|
934
|
+
if (!summary) throw new Error('Missing --summary');
|
|
935
|
+
|
|
936
|
+
appendLedger(state, actor, 'memory', summary, agent);
|
|
937
|
+
const saved = appendMonthlyMemory(state, actor, kind, summary, agent);
|
|
938
|
+
writeState(state);
|
|
939
|
+
console.log(JSON.stringify({
|
|
940
|
+
ok: true,
|
|
941
|
+
actor,
|
|
942
|
+
agent: agent.name,
|
|
943
|
+
kind,
|
|
944
|
+
summary,
|
|
945
|
+
monthlyMemory: saved ? relativeFromRoot(saved.monthlyPath) : 'disabled',
|
|
946
|
+
sessionBrief: relativeFromRoot(sessionBriefPath(state)),
|
|
947
|
+
answerContract: answerContractFor(state, actor, agent)
|
|
948
|
+
}, null, 2));
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
function memoryBrief(args) {
|
|
952
|
+
const state = readState();
|
|
953
|
+
if (!state.initialized) {
|
|
954
|
+
console.log('MOP belum di-setup. Jalankan /mop-setup.');
|
|
955
|
+
return;
|
|
956
|
+
}
|
|
957
|
+
const actor = slug(String(args.actor || state.activeMember || ''));
|
|
958
|
+
if (!actor) throw new Error('Missing --actor');
|
|
959
|
+
if (!state.members?.[actor]) throw new Error('Unknown actor.');
|
|
960
|
+
const agent = activeAgentFor(state, actor);
|
|
961
|
+
const month = String(args.month || monthKey());
|
|
962
|
+
const limit = Number(args.limit || memoryPolicy(state).recentLimit || 20);
|
|
963
|
+
const currentEntries = readJsonl(monthlyMemoryPath(state, month)).slice(-limit);
|
|
964
|
+
const recentEntries = latestMemoryEntries(state, limit);
|
|
965
|
+
if (agent) writeSessionBrief(state, actor);
|
|
966
|
+
console.log(JSON.stringify({
|
|
967
|
+
ok: true,
|
|
968
|
+
actor,
|
|
969
|
+
activeAgent: agent ? {
|
|
970
|
+
id: agent.id,
|
|
971
|
+
name: agent.name,
|
|
972
|
+
role: agent.role,
|
|
973
|
+
title: agent.title
|
|
974
|
+
} : null,
|
|
975
|
+
answerContract: answerContractFor(state, actor, agent),
|
|
976
|
+
memory: {
|
|
977
|
+
month,
|
|
978
|
+
monthPath: relativeFromRoot(monthlyMemoryPath(state, month)),
|
|
979
|
+
sessionBrief: relativeFromRoot(sessionBriefPath(state)),
|
|
980
|
+
currentMonthEntries: currentEntries,
|
|
981
|
+
recentEntries
|
|
982
|
+
},
|
|
983
|
+
next: agent
|
|
984
|
+
? 'Use answerContract.firstLine before answering, then save memory after meaningful work.'
|
|
985
|
+
: `Agent diperlukan. Jalankan: node .MOP/scripts/mop-core.mjs agent activate --actor ${actor} --role ${state.agentPolicy?.defaultRole || 'core'} --title "${state.agentPolicy?.defaultTitle || 'Core Agent'}" --name "<agent-name>"`
|
|
986
|
+
}, null, 2));
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
function memoryRestore(args) {
|
|
990
|
+
return memoryBrief(args);
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
function memberGitIdentity(args) {
|
|
994
|
+
const state = readState();
|
|
995
|
+
if (!state.initialized) throw new Error('MOP is not initialized.');
|
|
996
|
+
const actor = slug(requireArg(args, 'actor'));
|
|
997
|
+
const member = state.members?.[actor];
|
|
998
|
+
if (!member) throw new Error('Unknown actor.');
|
|
999
|
+
const agent = requireActiveAgent(state, actor);
|
|
1000
|
+
const name = String(args.name || member.displayName || actor);
|
|
1001
|
+
const email = String(args.email || 'github-noreply');
|
|
1002
|
+
const githubUsername = String(args['github-username'] || member.gitIdentity?.githubUsername || '');
|
|
1003
|
+
member.gitIdentity = resolveGitIdentityInput(state, actor, name, email, githubUsername);
|
|
1004
|
+
appendLedger(state, actor, 'git-identity', `Updated git identity for ${actor}.`, agent);
|
|
1005
|
+
writeState(state);
|
|
1006
|
+
console.log(`Git identity set for ${actor}: ${member.gitIdentity.name} <${member.gitIdentity.email}>${member.gitIdentity.githubUsername ? ` github=${member.gitIdentity.githubUsername}` : ''}`);
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
function validate() {
|
|
1010
|
+
const state = readState();
|
|
1011
|
+
const errors = [];
|
|
1012
|
+
if (typeof state.initialized !== 'boolean') errors.push('initialized must be boolean');
|
|
1013
|
+
if (!state.projectName) errors.push('projectName is required');
|
|
1014
|
+
if (!Array.isArray(state.agentRoster)) errors.push('agentRoster must be array');
|
|
1015
|
+
if (!Array.isArray(state.agentCatalog)) errors.push('agentCatalog must be array');
|
|
1016
|
+
if (state.activeAgents && typeof state.activeAgents !== 'object') errors.push('activeAgents must be object');
|
|
1017
|
+
if (state.agentPolicy && typeof state.agentPolicy !== 'object') errors.push('agentPolicy must be object');
|
|
1018
|
+
if (state.answerPolicy && typeof state.answerPolicy !== 'object') errors.push('answerPolicy must be object');
|
|
1019
|
+
if (state.memoryPolicy && typeof state.memoryPolicy !== 'object') errors.push('memoryPolicy must be object');
|
|
1020
|
+
if (state.browserPolicy && typeof state.browserPolicy !== 'object') errors.push('browserPolicy must be object');
|
|
1021
|
+
if (state.agentRouter && typeof state.agentRouter !== 'object') errors.push('agentRouter must be object');
|
|
1022
|
+
if (state.partyMode && typeof state.partyMode !== 'object') errors.push('partyMode must be object');
|
|
1023
|
+
if (state.autosync?.githubIdentity && typeof state.autosync.githubIdentity !== 'object') {
|
|
1024
|
+
errors.push('autosync.githubIdentity must be object');
|
|
1025
|
+
}
|
|
1026
|
+
if (state.mopFlow && typeof state.mopFlow !== 'object') errors.push('mopFlow must be object');
|
|
1027
|
+
if (state.mopFlow?.enabled !== false) {
|
|
1028
|
+
if (state.mopFlow?.brand !== 'MOP Flow') errors.push('mopFlow.brand must be MOP Flow');
|
|
1029
|
+
if (state.mopFlow?.canonicalMcpServer !== 'mop-flow') errors.push('mopFlow.canonicalMcpServer must be mop-flow');
|
|
1030
|
+
if (state.mopFlow?.providerParity?.enabled === false) errors.push('mopFlow.providerParity must remain enabled');
|
|
1031
|
+
for (const path of [
|
|
1032
|
+
'.MOP/scripts/mop-flow.mjs',
|
|
1033
|
+
'.agents/skills/mop-flow/SKILL.md',
|
|
1034
|
+
'.claude/skills/mop-flow/SKILL.md'
|
|
1035
|
+
]) {
|
|
1036
|
+
if (!existsSync(join(rootDir, path))) errors.push(`mopFlow required file missing: ${path}`);
|
|
1037
|
+
}
|
|
1038
|
+
const mcpText = existsSync(join(rootDir, '.mcp.json')) ? readFileSync(join(rootDir, '.mcp.json'), 'utf8') : '';
|
|
1039
|
+
if (mcpText && !mcpText.includes('"mop-flow"')) errors.push('.mcp.json must register mop-flow');
|
|
1040
|
+
}
|
|
1041
|
+
if (state.projectRootPolicy && typeof state.projectRootPolicy !== 'object') errors.push('projectRootPolicy must be object');
|
|
1042
|
+
if (state.projectRootPolicy?.rules && !Array.isArray(state.projectRootPolicy.rules)) {
|
|
1043
|
+
errors.push('projectRootPolicy.rules must be array');
|
|
1044
|
+
}
|
|
1045
|
+
if (!Array.isArray(state.ledger)) errors.push('ledger must be array');
|
|
1046
|
+
const catalogRoles = new Set();
|
|
1047
|
+
for (const item of state.agentCatalog || []) {
|
|
1048
|
+
if (!item.role) errors.push('agentCatalog entry missing role');
|
|
1049
|
+
if (!item.title) errors.push(`agentCatalog ${item.role || '<unknown>'} missing title`);
|
|
1050
|
+
if (item.role && catalogRoles.has(item.role)) errors.push(`duplicate agentCatalog role: ${item.role}`);
|
|
1051
|
+
if (item.role) catalogRoles.add(item.role);
|
|
1052
|
+
}
|
|
1053
|
+
const routerRole = state.agentRouter?.defaultHighReasoningRole;
|
|
1054
|
+
if (routerRole && !catalogRoles.has(routerRole)) {
|
|
1055
|
+
errors.push(`agentRouter.defaultHighReasoningRole missing from agentCatalog: ${routerRole}`);
|
|
1056
|
+
}
|
|
1057
|
+
const defaultRole = state.agentPolicy?.defaultRole;
|
|
1058
|
+
if (defaultRole && !catalogRoles.has(defaultRole)) {
|
|
1059
|
+
errors.push(`agentPolicy.defaultRole missing from agentCatalog: ${defaultRole}`);
|
|
1060
|
+
}
|
|
1061
|
+
for (const phase of state.workflow?.phases || []) {
|
|
1062
|
+
if (!phase.id) errors.push('workflow phase missing id');
|
|
1063
|
+
if (phase.primaryRole && !catalogRoles.has(phase.primaryRole)) {
|
|
1064
|
+
errors.push(`workflow phase ${phase.id} primaryRole missing from agentCatalog: ${phase.primaryRole}`);
|
|
1065
|
+
}
|
|
1066
|
+
for (const role of phase.partyRoles || []) {
|
|
1067
|
+
if (!catalogRoles.has(role)) errors.push(`workflow phase ${phase.id} partyRole missing from agentCatalog: ${role}`);
|
|
1068
|
+
}
|
|
1069
|
+
if (phase.artifact && !(state.artifacts?.types || []).includes(phase.artifact)) {
|
|
1070
|
+
errors.push(`workflow phase ${phase.id} artifact missing from artifact types: ${phase.artifact}`);
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
for (const type of state.artifacts?.types || []) {
|
|
1074
|
+
const templatePath = join(rootDir, state.artifacts?.templateDirectory || '.MOP/templates/artifacts', `${type}.md`);
|
|
1075
|
+
if (!existsSync(templatePath)) errors.push(`artifact template missing: ${templatePath}`);
|
|
1076
|
+
const folder = state.artifacts?.folderByType?.[type];
|
|
1077
|
+
if (state.artifacts?.folderByType && (!folder || typeof folder !== 'string')) {
|
|
1078
|
+
errors.push(`artifact folder missing for type: ${type}`);
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
if (state.installer?.entrypoint && !existsSync(join(rootDir, state.installer.entrypoint))) {
|
|
1082
|
+
errors.push(`installer entrypoint missing: ${state.installer.entrypoint}`);
|
|
1083
|
+
}
|
|
1084
|
+
if (state.initialized) {
|
|
1085
|
+
if (!state.ownerCodename) errors.push('ownerCodename is required after setup');
|
|
1086
|
+
if (!state.members?.[state.ownerCodename]) errors.push('owner member missing');
|
|
1087
|
+
if (!['solo', 'team'].includes(state.mode)) errors.push('mode must be solo or team');
|
|
1088
|
+
if (state.mode === 'team' && !state.githubUrl) errors.push('team mode requires githubUrl');
|
|
1089
|
+
if (state.autosync?.requireUserGitEmail !== false) {
|
|
1090
|
+
for (const [codename, member] of Object.entries(state.members || {})) {
|
|
1091
|
+
if (!member.gitIdentity?.email && !member.github?.noreplyEmail) {
|
|
1092
|
+
errors.push(`member ${codename} is missing git identity email`);
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
for (const [codename, agentId] of Object.entries(state.activeAgents || {})) {
|
|
1097
|
+
const agent = (state.agentRoster || []).find((item) => item.id === agentId || item.name === agentId);
|
|
1098
|
+
if (!agent) errors.push(`active agent for ${codename} is missing from agentRoster`);
|
|
1099
|
+
if (agent && !(agent.owners || []).includes(codename)) errors.push(`active agent ${agent.name} does not include owner ${codename}`);
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
if (errors.length) {
|
|
1103
|
+
console.error(errors.join('\n'));
|
|
1104
|
+
process.exitCode = 1;
|
|
1105
|
+
return;
|
|
1106
|
+
}
|
|
1107
|
+
console.log('MOP state OK.');
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
function status() {
|
|
1111
|
+
const state = readState();
|
|
1112
|
+
console.log(JSON.stringify({
|
|
1113
|
+
initialized: state.initialized,
|
|
1114
|
+
projectName: state.projectName,
|
|
1115
|
+
activeMember: state.activeMember,
|
|
1116
|
+
activeAgents: Object.fromEntries(Object.entries(state.activeAgents || {}).map(([codename, agentId]) => {
|
|
1117
|
+
const agent = (state.agentRoster || []).find((item) => item.id === agentId || item.name === agentId);
|
|
1118
|
+
return [codename, agent ? { name: agent.name, role: agent.role, id: agent.id } : { id: agentId, missing: true }];
|
|
1119
|
+
})),
|
|
1120
|
+
agentPolicy: state.agentPolicy || {},
|
|
1121
|
+
answerPolicy: answerPolicy(state),
|
|
1122
|
+
memoryPolicy: memoryPolicy(state),
|
|
1123
|
+
browserPolicy: browserPolicy(state),
|
|
1124
|
+
agentRouter: state.agentRouter || {},
|
|
1125
|
+
partyMode: state.partyMode || {},
|
|
1126
|
+
workflow: {
|
|
1127
|
+
enabled: state.workflow?.enabled !== false,
|
|
1128
|
+
currentPhase: state.workflow?.currentPhase || null,
|
|
1129
|
+
phases: state.workflow?.phaseOrder || []
|
|
1130
|
+
},
|
|
1131
|
+
artifacts: state.artifacts || {},
|
|
1132
|
+
projectRootPolicy: state.projectRootPolicy || {},
|
|
1133
|
+
readinessGate: state.readinessGate || {},
|
|
1134
|
+
adversarialReview: state.adversarialReview || {},
|
|
1135
|
+
mopFlow: state.mopFlow || {},
|
|
1136
|
+
installer: state.installer || {},
|
|
1137
|
+
mode: state.mode,
|
|
1138
|
+
githubUrl: state.githubUrl,
|
|
1139
|
+
members: Object.keys(state.members || {}),
|
|
1140
|
+
agents: (state.agentRoster || []).map((agent) => ({
|
|
1141
|
+
name: agent.name,
|
|
1142
|
+
role: agent.role,
|
|
1143
|
+
owners: agent.owners
|
|
1144
|
+
})),
|
|
1145
|
+
autosync: {
|
|
1146
|
+
enabled: state.autosync?.enabled !== false,
|
|
1147
|
+
requireUserGitEmail: state.autosync?.requireUserGitEmail !== false
|
|
1148
|
+
},
|
|
1149
|
+
gitIdentities: Object.fromEntries(Object.entries(state.members || {}).map(([codename, member]) => [
|
|
1150
|
+
codename,
|
|
1151
|
+
{
|
|
1152
|
+
name: member.gitIdentity?.name || member.displayName || codename,
|
|
1153
|
+
email: member.gitIdentity?.email || member.github?.noreplyEmail || '',
|
|
1154
|
+
githubUsername: member.gitIdentity?.githubUsername || member.github?.username || ''
|
|
1155
|
+
}
|
|
1156
|
+
]))
|
|
1157
|
+
}, null, 2));
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
function main() {
|
|
1161
|
+
if (!existsSync(statePath)) {
|
|
1162
|
+
throw new Error(`Missing state file: ${statePath}`);
|
|
1163
|
+
}
|
|
1164
|
+
const [command, subcommand, ...rest] = process.argv.slice(2);
|
|
1165
|
+
const args = parseArgs(rest);
|
|
1166
|
+
|
|
1167
|
+
if (command === 'setup') return setup(parseArgs([subcommand, ...rest].filter(Boolean)));
|
|
1168
|
+
if (command === 'login') return login(parseArgs([subcommand, ...rest].filter(Boolean)));
|
|
1169
|
+
if (command === 'validate') return validate();
|
|
1170
|
+
if (command === 'status') return status();
|
|
1171
|
+
if (command === 'member' && subcommand === 'git-identity') return memberGitIdentity(args);
|
|
1172
|
+
if (command === 'agent' && subcommand === 'activate') return agentActivate(args);
|
|
1173
|
+
if (command === 'agent' && subcommand === 'use') return agentUse(args);
|
|
1174
|
+
if (command === 'agent' && subcommand === 'current') return agentCurrent(args);
|
|
1175
|
+
if (command === 'agent' && subcommand === 'require') return agentRequire(args);
|
|
1176
|
+
if (command === 'agent' && subcommand === 'route') return agentRoute(args);
|
|
1177
|
+
if (command === 'agent' && subcommand === 'list') return agentList();
|
|
1178
|
+
if (command === 'browser' && subcommand === 'preflight') return browserPreflight();
|
|
1179
|
+
if (command === 'memory' && subcommand === 'add') return memoryAdd(args);
|
|
1180
|
+
if (command === 'memory' && subcommand === 'brief') return memoryBrief(args);
|
|
1181
|
+
if (command === 'memory' && subcommand === 'restore') return memoryRestore(args);
|
|
1182
|
+
|
|
1183
|
+
console.log(`Usage:
|
|
1184
|
+
node .MOP/scripts/mop-core.mjs status
|
|
1185
|
+
node .MOP/scripts/mop-core.mjs validate
|
|
1186
|
+
node .MOP/scripts/mop-core.mjs setup --project-name NAME --name DISPLAY --codename CODE --password PASS --mode solo|team --conversation-language LANG --coding-language LANG [--git-email github-noreply|EMAIL] [--git-name NAME] [--github-username USER] [--github-url URL]
|
|
1187
|
+
node .MOP/scripts/mop-core.mjs login --codename CODE --password PASS
|
|
1188
|
+
node .MOP/scripts/mop-core.mjs member git-identity --actor CODE --name NAME [--email github-noreply|EMAIL] [--github-username USER]
|
|
1189
|
+
node .MOP/scripts/mop-core.mjs agent activate --actor CODE --role ROLE --title TITLE --name NAME
|
|
1190
|
+
node .MOP/scripts/mop-core.mjs agent use --actor CODE --name NAME
|
|
1191
|
+
node .MOP/scripts/mop-core.mjs agent current --actor CODE
|
|
1192
|
+
node .MOP/scripts/mop-core.mjs agent require --actor CODE [--role ROLE] [--title TITLE]
|
|
1193
|
+
node .MOP/scripts/mop-core.mjs agent route --actor CODE --task "task text"
|
|
1194
|
+
node .MOP/scripts/mop-core.mjs agent list
|
|
1195
|
+
node .MOP/scripts/mop-core.mjs browser preflight
|
|
1196
|
+
node .MOP/scripts/mop-core.mjs memory brief --actor CODE [--month YYYY-MM]
|
|
1197
|
+
node .MOP/scripts/mop-core.mjs memory add --actor CODE --kind conversation --summary "what happened"
|
|
1198
|
+
node .MOP/scripts/mop-core.mjs memory restore --actor CODE`);
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
try {
|
|
1202
|
+
main();
|
|
1203
|
+
} catch (error) {
|
|
1204
|
+
console.error(error.message);
|
|
1205
|
+
process.exitCode = 1;
|
|
1206
|
+
}
|