claudecode-omc 4.4.5 → 4.4.7
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/.mcp.json +2 -6
- package/README.es.md +64 -8
- package/README.ja.md +64 -8
- package/README.ko.md +64 -8
- package/README.pt.md +29 -0
- package/README.vi.md +29 -0
- package/README.zh.md +64 -8
- package/agents/architect.md +17 -7
- package/agents/code-reviewer.md +6 -7
- package/agents/critic.md +14 -1
- package/agents/deep-executor.md +6 -7
- package/agents/designer.md +6 -8
- package/agents/executor.md +6 -7
- package/agents/planner.md +21 -0
- package/agents/quality-reviewer.md +6 -7
- package/agents/security-reviewer.md +6 -7
- package/agents/test-engineer.md +6 -7
- package/bridge/mcp-server.cjs +517 -202
- package/bridge/runtime-cli.cjs +1550 -0
- package/bridge/team-bridge.cjs +362 -103
- package/bridge/{gemini-server.cjs → team-mcp.cjs} +10914 -10240
- package/dist/__tests__/auto-update.test.js +1 -1
- package/dist/__tests__/auto-update.test.js.map +1 -1
- package/dist/__tests__/cli-win32-warning.test.d.ts +2 -0
- package/dist/__tests__/cli-win32-warning.test.d.ts.map +1 -0
- package/dist/__tests__/cli-win32-warning.test.js +46 -0
- package/dist/__tests__/cli-win32-warning.test.js.map +1 -0
- package/dist/__tests__/codex-callsite-normalization.test.js +112 -0
- package/dist/__tests__/consensus-execution-handoff.test.d.ts +2 -0
- package/dist/__tests__/consensus-execution-handoff.test.d.ts.map +1 -1
- package/dist/__tests__/consensus-execution-handoff.test.js +48 -0
- package/dist/__tests__/consensus-execution-handoff.test.js.map +1 -1
- package/dist/__tests__/context-safety.test.d.ts +2 -0
- package/dist/__tests__/context-safety.test.d.ts.map +1 -0
- package/dist/__tests__/context-safety.test.js +59 -0
- package/dist/__tests__/context-safety.test.js.map +1 -0
- package/dist/__tests__/hooks.test.js +15 -0
- package/dist/__tests__/hooks.test.js.map +1 -1
- package/dist/__tests__/hud/call-counts.test.js +0 -3
- package/dist/__tests__/hud/call-counts.test.js.map +1 -1
- package/dist/__tests__/hud/defaults.test.js +3 -5
- package/dist/__tests__/hud/defaults.test.js.map +1 -1
- package/dist/__tests__/hud/prompt-time.test.d.ts +2 -0
- package/dist/__tests__/hud/prompt-time.test.d.ts.map +1 -0
- package/dist/__tests__/hud/prompt-time.test.js +24 -0
- package/dist/__tests__/hud/prompt-time.test.js.map +1 -0
- package/dist/__tests__/hud/render.test.js +0 -1
- package/dist/__tests__/hud/render.test.js.map +1 -1
- package/dist/__tests__/hud/usage-api.test.js +5 -0
- package/dist/__tests__/hud/usage-api.test.js.map +1 -1
- package/dist/__tests__/hud/version-display.test.js +1 -0
- package/dist/__tests__/hud/version-display.test.js.map +1 -1
- package/dist/__tests__/hud/windows-platform.test.js +0 -4
- package/dist/__tests__/hud/windows-platform.test.js.map +1 -1
- package/dist/__tests__/hud-windows.test.js +5 -3
- package/dist/__tests__/hud-windows.test.js.map +1 -1
- package/dist/__tests__/installer-hud-skip.test.js +12 -2
- package/dist/__tests__/installer-hud-skip.test.js.map +1 -1
- package/dist/__tests__/installer.test.js +1 -1
- package/dist/__tests__/installer.test.js.map +1 -1
- package/dist/__tests__/job-management-sqlite.test.js +0 -15
- package/dist/__tests__/job-management-sqlite.test.js.map +1 -1
- package/dist/__tests__/job-management.test.js +0 -16
- package/dist/__tests__/job-management.test.js.map +1 -1
- package/dist/__tests__/load-agent-prompt.test.js +0 -23
- package/dist/__tests__/load-agent-prompt.test.js.map +1 -1
- package/dist/__tests__/model-routing.test.js +3 -2
- package/dist/__tests__/model-routing.test.js.map +1 -1
- package/dist/__tests__/omc-tools-server-interop.test.js +1 -1
- package/dist/__tests__/omc-tools-server-interop.test.js.map +1 -1
- package/dist/__tests__/pre-tool-enforcer.test.d.ts +2 -0
- package/dist/__tests__/pre-tool-enforcer.test.d.ts.map +1 -0
- package/dist/__tests__/pre-tool-enforcer.test.js +194 -0
- package/dist/__tests__/pre-tool-enforcer.test.js.map +1 -0
- package/dist/__tests__/prompt-injection.test.js +0 -26
- package/dist/__tests__/prompt-injection.test.js.map +1 -1
- package/dist/__tests__/purge-stale-cache.test.js +3 -2
- package/dist/__tests__/purge-stale-cache.test.js.map +1 -1
- package/dist/__tests__/run-cjs-graceful-fallback.test.d.ts +2 -0
- package/dist/__tests__/run-cjs-graceful-fallback.test.d.ts.map +1 -0
- package/dist/__tests__/run-cjs-graceful-fallback.test.js +167 -0
- package/dist/__tests__/run-cjs-graceful-fallback.test.js.map +1 -0
- package/dist/__tests__/session-start-cache-cleanup.test.d.ts +2 -0
- package/dist/__tests__/session-start-cache-cleanup.test.d.ts.map +1 -0
- package/dist/__tests__/session-start-cache-cleanup.test.js +150 -0
- package/dist/__tests__/session-start-cache-cleanup.test.js.map +1 -0
- package/dist/__tests__/skills.test.js +7 -10
- package/dist/__tests__/skills.test.js.map +1 -1
- package/dist/__tests__/team-server-validation.test.d.ts +2 -0
- package/dist/__tests__/team-server-validation.test.d.ts.map +1 -0
- package/dist/__tests__/team-server-validation.test.js +122 -0
- package/dist/__tests__/team-server-validation.test.js.map +1 -0
- package/dist/agents/index.d.ts +0 -1
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js +0 -2
- package/dist/agents/index.js.map +1 -1
- package/dist/agents/prompt-helpers.d.ts +74 -0
- package/dist/agents/prompt-helpers.d.ts.map +1 -0
- package/dist/agents/prompt-helpers.js +187 -0
- package/dist/agents/prompt-helpers.js.map +1 -0
- package/dist/agents/utils.d.ts +1 -5
- package/dist/agents/utils.d.ts.map +1 -1
- package/dist/agents/utils.js +1 -34
- package/dist/agents/utils.js.map +1 -1
- package/dist/cli/__tests__/launch.test.d.ts +1 -2
- package/dist/cli/__tests__/launch.test.d.ts.map +1 -1
- package/dist/cli/__tests__/launch.test.js +442 -48
- package/dist/cli/__tests__/launch.test.js.map +1 -1
- package/dist/cli/__tests__/teleport-help.test.d.ts +2 -0
- package/dist/cli/__tests__/teleport-help.test.d.ts.map +1 -0
- package/dist/cli/__tests__/teleport-help.test.js +17 -0
- package/dist/cli/__tests__/teleport-help.test.js.map +1 -0
- package/dist/cli/commands/teleport.d.ts +2 -1
- package/dist/cli/commands/teleport.d.ts.map +1 -1
- package/dist/cli/commands/teleport.js +6 -3
- package/dist/cli/commands/teleport.js.map +1 -1
- package/dist/cli/index.js +40 -290
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/launch.d.ts +83 -3
- package/dist/cli/launch.d.ts.map +1 -1
- package/dist/cli/launch.js +213 -48
- package/dist/cli/launch.js.map +1 -1
- package/dist/cli/win32-warning.d.ts +6 -0
- package/dist/cli/win32-warning.d.ts.map +1 -0
- package/dist/cli/win32-warning.js +15 -0
- package/dist/cli/win32-warning.js.map +1 -0
- package/dist/config/loader.d.ts +9 -1
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +29 -19
- package/dist/config/loader.js.map +1 -1
- package/dist/config/models.d.ts +33 -0
- package/dist/config/models.d.ts.map +1 -0
- package/dist/config/models.js +49 -0
- package/dist/config/models.js.map +1 -0
- package/dist/constants/names.d.ts +2 -0
- package/dist/constants/names.d.ts.map +1 -1
- package/dist/constants/names.js +2 -0
- package/dist/constants/names.js.map +1 -1
- package/dist/features/auto-update.d.ts.map +1 -1
- package/dist/features/auto-update.js +21 -11
- package/dist/features/auto-update.js.map +1 -1
- package/dist/features/background-agent/manager.d.ts.map +1 -1
- package/dist/features/background-agent/manager.js +1 -2
- package/dist/features/background-agent/manager.js.map +1 -1
- package/dist/features/boulder-state/storage.d.ts.map +1 -1
- package/dist/features/boulder-state/storage.js +9 -5
- package/dist/features/boulder-state/storage.js.map +1 -1
- package/dist/features/boulder-state/types.d.ts +4 -0
- package/dist/features/boulder-state/types.d.ts.map +1 -1
- package/dist/features/builtin-skills/skills.d.ts.map +1 -1
- package/dist/features/builtin-skills/skills.js +25 -78
- package/dist/features/builtin-skills/skills.js.map +1 -1
- package/dist/features/delegation-enforcer.d.ts.map +1 -1
- package/dist/features/delegation-enforcer.js +4 -1
- package/dist/features/delegation-enforcer.js.map +1 -1
- package/dist/features/delegation-routing/__tests__/resolver.test.js +47 -122
- package/dist/features/delegation-routing/__tests__/resolver.test.js.map +1 -1
- package/dist/features/delegation-routing/resolver.d.ts.map +1 -1
- package/dist/features/delegation-routing/resolver.js +24 -47
- package/dist/features/delegation-routing/resolver.js.map +1 -1
- package/dist/features/delegation-routing/types.d.ts.map +1 -1
- package/dist/features/delegation-routing/types.js +2 -0
- package/dist/features/delegation-routing/types.js.map +1 -1
- package/dist/features/model-routing/external-model-policy.d.ts.map +1 -1
- package/dist/features/model-routing/external-model-policy.js.map +1 -1
- package/dist/features/model-routing/router.d.ts.map +1 -1
- package/dist/features/model-routing/router.js +12 -2
- package/dist/features/model-routing/router.js.map +1 -1
- package/dist/features/model-routing/types.d.ts +5 -1
- package/dist/features/model-routing/types.d.ts.map +1 -1
- package/dist/features/model-routing/types.js +7 -6
- package/dist/features/model-routing/types.js.map +1 -1
- package/dist/features/rate-limit-wait/daemon.d.ts.map +1 -1
- package/dist/features/rate-limit-wait/daemon.js +40 -4
- package/dist/features/rate-limit-wait/daemon.js.map +1 -1
- package/dist/features/task-decomposer/index.js +14 -4
- package/dist/features/task-decomposer/index.js.map +1 -1
- package/dist/hooks/__tests__/bridge-openclaw.test.d.ts +2 -0
- package/dist/hooks/__tests__/bridge-openclaw.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/bridge-openclaw.test.js +124 -0
- package/dist/hooks/__tests__/bridge-openclaw.test.js.map +1 -0
- package/dist/hooks/__tests__/bridge-security.test.js +1 -1
- package/dist/hooks/__tests__/bridge-security.test.js.map +1 -1
- package/dist/hooks/auto-slash-command/executor.d.ts.map +1 -1
- package/dist/hooks/auto-slash-command/executor.js +38 -61
- package/dist/hooks/auto-slash-command/executor.js.map +1 -1
- package/dist/hooks/bridge.d.ts +11 -0
- package/dist/hooks/bridge.d.ts.map +1 -1
- package/dist/hooks/bridge.js +154 -82
- package/dist/hooks/bridge.js.map +1 -1
- package/dist/hooks/comment-checker/index.d.ts.map +1 -1
- package/dist/hooks/comment-checker/index.js +3 -1
- package/dist/hooks/comment-checker/index.js.map +1 -1
- package/dist/hooks/conductor/__tests__/state.test.js +4 -2
- package/dist/hooks/conductor/__tests__/state.test.js.map +1 -1
- package/dist/hooks/keyword-detector/__tests__/index.test.js +348 -1
- package/dist/hooks/keyword-detector/__tests__/index.test.js.map +1 -1
- package/dist/hooks/keyword-detector/index.d.ts +29 -0
- package/dist/hooks/keyword-detector/index.d.ts.map +1 -1
- package/dist/hooks/keyword-detector/index.js +123 -1
- package/dist/hooks/keyword-detector/index.js.map +1 -1
- package/dist/hooks/learner/bridge.d.ts.map +1 -1
- package/dist/hooks/learner/bridge.js +19 -4
- package/dist/hooks/learner/bridge.js.map +1 -1
- package/dist/hooks/learner/finder.d.ts.map +1 -1
- package/dist/hooks/learner/finder.js +19 -4
- package/dist/hooks/learner/finder.js.map +1 -1
- package/dist/hooks/mode-registry/__tests__/session-isolation.test.js +40 -0
- package/dist/hooks/mode-registry/__tests__/session-isolation.test.js.map +1 -1
- package/dist/hooks/mode-registry/index.d.ts.map +1 -1
- package/dist/hooks/mode-registry/index.js +135 -52
- package/dist/hooks/mode-registry/index.js.map +1 -1
- package/dist/hooks/notepad/index.d.ts.map +1 -1
- package/dist/hooks/notepad/index.js +5 -3
- package/dist/hooks/notepad/index.js.map +1 -1
- package/dist/hooks/persistent-mode/__tests__/cancel-race.test.d.ts +2 -0
- package/dist/hooks/persistent-mode/__tests__/cancel-race.test.d.ts.map +1 -0
- package/dist/hooks/persistent-mode/__tests__/cancel-race.test.js +73 -0
- package/dist/hooks/persistent-mode/__tests__/cancel-race.test.js.map +1 -0
- package/dist/hooks/persistent-mode/__tests__/idle-cooldown.test.js +89 -13
- package/dist/hooks/persistent-mode/__tests__/idle-cooldown.test.js.map +1 -1
- package/dist/hooks/persistent-mode/__tests__/skill-state-stop.test.d.ts +2 -0
- package/dist/hooks/persistent-mode/__tests__/skill-state-stop.test.d.ts.map +1 -0
- package/dist/hooks/persistent-mode/__tests__/skill-state-stop.test.js +156 -0
- package/dist/hooks/persistent-mode/__tests__/skill-state-stop.test.js.map +1 -0
- package/dist/hooks/persistent-mode/idle-cooldown.test.d.ts +2 -3
- package/dist/hooks/persistent-mode/idle-cooldown.test.d.ts.map +1 -1
- package/dist/hooks/persistent-mode/idle-cooldown.test.js +19 -4
- package/dist/hooks/persistent-mode/idle-cooldown.test.js.map +1 -1
- package/dist/hooks/persistent-mode/index.d.ts +2 -2
- package/dist/hooks/persistent-mode/index.d.ts.map +1 -1
- package/dist/hooks/persistent-mode/index.js +144 -26
- package/dist/hooks/persistent-mode/index.js.map +1 -1
- package/dist/hooks/plugin-patterns/index.d.ts.map +1 -1
- package/dist/hooks/plugin-patterns/index.js +22 -31
- package/dist/hooks/plugin-patterns/index.js.map +1 -1
- package/dist/hooks/pre-compact/index.js +1 -1
- package/dist/hooks/preemptive-compaction/index.d.ts.map +1 -1
- package/dist/hooks/preemptive-compaction/index.js +3 -1
- package/dist/hooks/preemptive-compaction/index.js.map +1 -1
- package/dist/hooks/project-memory/index.d.ts.map +1 -1
- package/dist/hooks/project-memory/index.js +9 -0
- package/dist/hooks/project-memory/index.js.map +1 -1
- package/dist/hooks/project-memory/learner.d.ts.map +1 -1
- package/dist/hooks/project-memory/learner.js +107 -85
- package/dist/hooks/project-memory/learner.js.map +1 -1
- package/dist/hooks/project-memory/storage.d.ts.map +1 -1
- package/dist/hooks/project-memory/storage.js +3 -2
- package/dist/hooks/project-memory/storage.js.map +1 -1
- package/dist/hooks/recovery/context-window.d.ts +4 -0
- package/dist/hooks/recovery/context-window.d.ts.map +1 -1
- package/dist/hooks/recovery/context-window.js +22 -1
- package/dist/hooks/recovery/context-window.js.map +1 -1
- package/dist/hooks/recovery/session-recovery.js +1 -1
- package/dist/hooks/recovery/session-recovery.js.map +1 -1
- package/dist/hooks/session-end/index.d.ts.map +1 -1
- package/dist/hooks/session-end/index.js +13 -22
- package/dist/hooks/session-end/index.js.map +1 -1
- package/dist/hooks/setup/__tests__/windows-patch.test.d.ts +2 -0
- package/dist/hooks/setup/__tests__/windows-patch.test.d.ts.map +1 -0
- package/dist/hooks/setup/__tests__/windows-patch.test.js +110 -0
- package/dist/hooks/setup/__tests__/windows-patch.test.js.map +1 -0
- package/dist/hooks/setup/index.d.ts +18 -0
- package/dist/hooks/setup/index.d.ts.map +1 -1
- package/dist/hooks/setup/index.js +59 -1
- package/dist/hooks/setup/index.js.map +1 -1
- package/dist/hooks/skill-bridge.cjs +17 -3
- package/dist/hooks/skill-state/__tests__/skill-state.test.d.ts +2 -0
- package/dist/hooks/skill-state/__tests__/skill-state.test.d.ts.map +1 -0
- package/dist/hooks/skill-state/__tests__/skill-state.test.js +301 -0
- package/dist/hooks/skill-state/__tests__/skill-state.test.js.map +1 -0
- package/dist/hooks/skill-state/index.d.ts +79 -0
- package/dist/hooks/skill-state/index.d.ts.map +1 -0
- package/dist/hooks/skill-state/index.js +245 -0
- package/dist/hooks/skill-state/index.js.map +1 -0
- package/dist/hooks/team-pipeline/state.d.ts.map +1 -1
- package/dist/hooks/team-pipeline/state.js +5 -0
- package/dist/hooks/team-pipeline/state.js.map +1 -1
- package/dist/hooks/todo-continuation/index.d.ts +17 -0
- package/dist/hooks/todo-continuation/index.d.ts.map +1 -1
- package/dist/hooks/todo-continuation/index.js +44 -2
- package/dist/hooks/todo-continuation/index.js.map +1 -1
- package/dist/hud/elements/call-counts.d.ts.map +1 -1
- package/dist/hud/elements/call-counts.js +6 -4
- package/dist/hud/elements/call-counts.js.map +1 -1
- package/dist/hud/elements/index.d.ts +1 -0
- package/dist/hud/elements/index.d.ts.map +1 -1
- package/dist/hud/elements/index.js +1 -0
- package/dist/hud/elements/index.js.map +1 -1
- package/dist/hud/elements/prompt-time.d.ts +13 -0
- package/dist/hud/elements/prompt-time.d.ts.map +1 -0
- package/dist/hud/elements/prompt-time.js +21 -0
- package/dist/hud/elements/prompt-time.js.map +1 -0
- package/dist/hud/index.d.ts +2 -1
- package/dist/hud/index.d.ts.map +1 -1
- package/dist/hud/index.js +40 -215
- package/dist/hud/index.js.map +1 -1
- package/dist/hud/render.d.ts.map +1 -1
- package/dist/hud/render.js +7 -108
- package/dist/hud/render.js.map +1 -1
- package/dist/hud/state.d.ts.map +1 -1
- package/dist/hud/state.js +4 -3
- package/dist/hud/state.js.map +1 -1
- package/dist/hud/stdin.d.ts +10 -0
- package/dist/hud/stdin.d.ts.map +1 -1
- package/dist/hud/stdin.js +43 -0
- package/dist/hud/stdin.js.map +1 -1
- package/dist/hud/types.d.ts +6 -18
- package/dist/hud/types.d.ts.map +1 -1
- package/dist/hud/types.js +6 -46
- package/dist/hud/types.js.map +1 -1
- package/dist/hud/usage-api.d.ts.map +1 -1
- package/dist/hud/usage-api.js +12 -0
- package/dist/hud/usage-api.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -11
- package/dist/index.js.map +1 -1
- package/dist/installer/hooks.d.ts +5 -0
- package/dist/installer/hooks.d.ts.map +1 -1
- package/dist/installer/hooks.js +8 -0
- package/dist/installer/hooks.js.map +1 -1
- package/dist/installer/index.d.ts.map +1 -1
- package/dist/installer/index.js +26 -11
- package/dist/installer/index.js.map +1 -1
- package/dist/interop/omx-team-state.d.ts.map +1 -1
- package/dist/interop/omx-team-state.js +38 -6
- package/dist/interop/omx-team-state.js.map +1 -1
- package/dist/interop/shared-state.d.ts.map +1 -1
- package/dist/interop/shared-state.js +58 -7
- package/dist/interop/shared-state.js.map +1 -1
- package/dist/lib/__tests__/worktree-paths.test.js +250 -1
- package/dist/lib/__tests__/worktree-paths.test.js.map +1 -1
- package/dist/lib/job-state-db.d.ts +150 -0
- package/dist/lib/job-state-db.d.ts.map +1 -0
- package/dist/lib/job-state-db.js +650 -0
- package/dist/lib/job-state-db.js.map +1 -0
- package/dist/lib/mode-names.d.ts +46 -0
- package/dist/lib/mode-names.d.ts.map +1 -0
- package/dist/lib/mode-names.js +73 -0
- package/dist/lib/mode-names.js.map +1 -0
- package/dist/lib/session-isolation.d.ts +32 -0
- package/dist/lib/session-isolation.d.ts.map +1 -0
- package/dist/lib/session-isolation.js +39 -0
- package/dist/lib/session-isolation.js.map +1 -0
- package/dist/lib/worktree-paths.d.ts +38 -8
- package/dist/lib/worktree-paths.d.ts.map +1 -1
- package/dist/lib/worktree-paths.js +124 -56
- package/dist/lib/worktree-paths.js.map +1 -1
- package/dist/mcp/__tests__/team-cleanup.test.d.ts +11 -0
- package/dist/mcp/__tests__/team-cleanup.test.d.ts.map +1 -0
- package/dist/mcp/__tests__/team-cleanup.test.js +228 -0
- package/dist/mcp/__tests__/team-cleanup.test.js.map +1 -0
- package/dist/mcp/cli-detection.d.ts +4 -8
- package/dist/mcp/cli-detection.d.ts.map +1 -1
- package/dist/mcp/cli-detection.js +5 -8
- package/dist/mcp/cli-detection.js.map +1 -1
- package/dist/mcp/codex-request-normalizer.js +59 -0
- package/dist/mcp/codex-server.js +16 -4
- package/dist/mcp/codex-standalone-server.js +13 -4
- package/dist/mcp/index.d.ts +2 -4
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +1 -5
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/job-management.d.ts.map +1 -1
- package/dist/mcp/job-management.js +11 -9
- package/dist/mcp/job-management.js.map +1 -1
- package/dist/mcp/job-state-db.d.ts +1 -149
- package/dist/mcp/job-state-db.d.ts.map +1 -1
- package/dist/mcp/job-state-db.js +2 -649
- package/dist/mcp/job-state-db.js.map +1 -1
- package/dist/mcp/mcp-config.d.ts +1 -1
- package/dist/mcp/mcp-config.js +1 -1
- package/dist/mcp/prompt-injection.d.ts +14 -76
- package/dist/mcp/prompt-injection.d.ts.map +1 -1
- package/dist/mcp/prompt-injection.js +34 -175
- package/dist/mcp/prompt-injection.js.map +1 -1
- package/dist/mcp/standalone-server.js +2 -0
- package/dist/mcp/standalone-server.js.map +1 -1
- package/dist/mcp/team-server.d.ts +16 -0
- package/dist/mcp/team-server.d.ts.map +1 -0
- package/dist/mcp/team-server.js +356 -0
- package/dist/mcp/team-server.js.map +1 -0
- package/dist/notifications/__tests__/formatter.test.js +62 -0
- package/dist/notifications/__tests__/formatter.test.js.map +1 -1
- package/dist/notifications/__tests__/hook-config.test.d.ts +14 -0
- package/dist/notifications/__tests__/hook-config.test.d.ts.map +1 -0
- package/dist/notifications/__tests__/hook-config.test.js +210 -0
- package/dist/notifications/__tests__/hook-config.test.js.map +1 -0
- package/dist/notifications/__tests__/platform-gating.test.d.ts +12 -0
- package/dist/notifications/__tests__/platform-gating.test.d.ts.map +1 -0
- package/dist/notifications/__tests__/platform-gating.test.js +140 -0
- package/dist/notifications/__tests__/platform-gating.test.js.map +1 -0
- package/dist/notifications/__tests__/template-engine.test.d.ts +13 -0
- package/dist/notifications/__tests__/template-engine.test.d.ts.map +1 -0
- package/dist/notifications/__tests__/template-engine.test.js +378 -0
- package/dist/notifications/__tests__/template-engine.test.js.map +1 -0
- package/dist/notifications/config.d.ts.map +1 -1
- package/dist/notifications/config.js +54 -18
- package/dist/notifications/config.js.map +1 -1
- package/dist/notifications/dispatcher.d.ts +2 -2
- package/dist/notifications/dispatcher.d.ts.map +1 -1
- package/dist/notifications/dispatcher.js +10 -6
- package/dist/notifications/dispatcher.js.map +1 -1
- package/dist/notifications/formatter.d.ts.map +1 -1
- package/dist/notifications/formatter.js +22 -0
- package/dist/notifications/formatter.js.map +1 -1
- package/dist/notifications/hook-config-types.d.ts +44 -0
- package/dist/notifications/hook-config-types.d.ts.map +1 -0
- package/dist/notifications/hook-config-types.js +8 -0
- package/dist/notifications/hook-config-types.js.map +1 -0
- package/dist/notifications/hook-config.d.ts +36 -0
- package/dist/notifications/hook-config.d.ts.map +1 -0
- package/dist/notifications/hook-config.js +95 -0
- package/dist/notifications/hook-config.js.map +1 -0
- package/dist/notifications/index.d.ts +3 -0
- package/dist/notifications/index.d.ts.map +1 -1
- package/dist/notifications/index.js +31 -3
- package/dist/notifications/index.js.map +1 -1
- package/dist/notifications/reply-listener.d.ts.map +1 -1
- package/dist/notifications/reply-listener.js +1 -0
- package/dist/notifications/reply-listener.js.map +1 -1
- package/dist/notifications/session-registry.d.ts.map +1 -1
- package/dist/notifications/session-registry.js +13 -5
- package/dist/notifications/session-registry.js.map +1 -1
- package/dist/notifications/template-engine.d.ts +34 -0
- package/dist/notifications/template-engine.d.ts.map +1 -0
- package/dist/notifications/template-engine.js +248 -0
- package/dist/notifications/template-engine.js.map +1 -0
- package/dist/notifications/types.d.ts +0 -2
- package/dist/notifications/types.d.ts.map +1 -1
- package/dist/openclaw/__tests__/config.test.d.ts +2 -0
- package/dist/openclaw/__tests__/config.test.d.ts.map +1 -0
- package/dist/openclaw/__tests__/config.test.js +200 -0
- package/dist/openclaw/__tests__/config.test.js.map +1 -0
- package/dist/openclaw/__tests__/dispatcher.test.d.ts +2 -0
- package/dist/openclaw/__tests__/dispatcher.test.d.ts.map +1 -0
- package/dist/openclaw/__tests__/dispatcher.test.js +348 -0
- package/dist/openclaw/__tests__/dispatcher.test.js.map +1 -0
- package/dist/openclaw/__tests__/index.test.d.ts +2 -0
- package/dist/openclaw/__tests__/index.test.d.ts.map +1 -0
- package/dist/openclaw/__tests__/index.test.js +235 -0
- package/dist/openclaw/__tests__/index.test.js.map +1 -0
- package/dist/openclaw/config.d.ts +33 -0
- package/dist/openclaw/config.d.ts.map +1 -0
- package/dist/openclaw/config.js +83 -0
- package/dist/openclaw/config.js.map +1 -0
- package/dist/openclaw/dispatcher.d.ts +47 -0
- package/dist/openclaw/dispatcher.d.ts.map +1 -0
- package/dist/openclaw/dispatcher.js +138 -0
- package/dist/openclaw/dispatcher.js.map +1 -0
- package/dist/openclaw/index.d.ts +25 -0
- package/dist/openclaw/index.d.ts.map +1 -0
- package/dist/openclaw/index.js +132 -0
- package/dist/openclaw/index.js.map +1 -0
- package/dist/openclaw/types.d.ts +102 -0
- package/dist/openclaw/types.d.ts.map +1 -0
- package/dist/openclaw/types.js +8 -0
- package/dist/openclaw/types.js.map +1 -0
- package/dist/platform/index.d.ts +5 -0
- package/dist/platform/index.d.ts.map +1 -1
- package/dist/platform/index.js +17 -0
- package/dist/platform/index.js.map +1 -1
- package/dist/platform/process-utils.d.ts.map +1 -1
- package/dist/platform/process-utils.js +55 -9
- package/dist/platform/process-utils.js.map +1 -1
- package/dist/shared/types.d.ts +7 -5
- package/dist/shared/types.d.ts.map +1 -1
- package/dist/team/__tests__/bridge-integration.test.js +10 -8
- package/dist/team/__tests__/bridge-integration.test.js.map +1 -1
- package/dist/team/__tests__/edge-cases.test.js +40 -29
- package/dist/team/__tests__/edge-cases.test.js.map +1 -1
- package/dist/team/__tests__/idle-nudge.test.d.ts +11 -0
- package/dist/team/__tests__/idle-nudge.test.d.ts.map +1 -0
- package/dist/team/__tests__/idle-nudge.test.js +282 -0
- package/dist/team/__tests__/idle-nudge.test.js.map +1 -0
- package/dist/team/__tests__/mcp-team-bridge.spawn-args.test.js +2 -2
- package/dist/team/__tests__/mcp-team-bridge.spawn-args.test.js.map +1 -1
- package/dist/team/__tests__/mcp-team-bridge.usage.test.d.ts +2 -0
- package/dist/team/__tests__/mcp-team-bridge.usage.test.d.ts.map +1 -0
- package/dist/team/__tests__/mcp-team-bridge.usage.test.js +49 -0
- package/dist/team/__tests__/mcp-team-bridge.usage.test.js.map +1 -0
- package/dist/team/__tests__/merge-coordinator.test.js +1 -1
- package/dist/team/__tests__/merge-coordinator.test.js.map +1 -1
- package/dist/team/__tests__/model-contract.test.d.ts +2 -0
- package/dist/team/__tests__/model-contract.test.d.ts.map +1 -0
- package/dist/team/__tests__/model-contract.test.js +121 -0
- package/dist/team/__tests__/model-contract.test.js.map +1 -0
- package/dist/team/__tests__/phase-controller.test.d.ts +2 -0
- package/dist/team/__tests__/phase-controller.test.d.ts.map +1 -0
- package/dist/team/__tests__/phase-controller.test.js +45 -0
- package/dist/team/__tests__/phase-controller.test.js.map +1 -0
- package/dist/team/__tests__/runtime-assign.test.d.ts +2 -0
- package/dist/team/__tests__/runtime-assign.test.d.ts.map +1 -0
- package/dist/team/__tests__/runtime-assign.test.js +43 -0
- package/dist/team/__tests__/runtime-assign.test.js.map +1 -0
- package/dist/team/__tests__/runtime-gemini-prompt.test.d.ts +2 -0
- package/dist/team/__tests__/runtime-gemini-prompt.test.d.ts.map +1 -0
- package/dist/team/__tests__/runtime-gemini-prompt.test.js +153 -0
- package/dist/team/__tests__/runtime-gemini-prompt.test.js.map +1 -0
- package/dist/team/__tests__/runtime-prompt-mode.test.d.ts +2 -0
- package/dist/team/__tests__/runtime-prompt-mode.test.d.ts.map +1 -0
- package/dist/team/__tests__/runtime-prompt-mode.test.js +162 -0
- package/dist/team/__tests__/runtime-prompt-mode.test.js.map +1 -0
- package/dist/team/__tests__/runtime.test.d.ts +2 -0
- package/dist/team/__tests__/runtime.test.d.ts.map +1 -0
- package/dist/team/__tests__/runtime.test.js +37 -0
- package/dist/team/__tests__/runtime.test.js.map +1 -0
- package/dist/team/__tests__/task-file-ops.test.js +63 -59
- package/dist/team/__tests__/task-file-ops.test.js.map +1 -1
- package/dist/team/__tests__/team-name.test.d.ts +2 -0
- package/dist/team/__tests__/team-name.test.d.ts.map +1 -0
- package/dist/team/__tests__/team-name.test.js +18 -0
- package/dist/team/__tests__/team-name.test.js.map +1 -0
- package/dist/team/__tests__/team-status.test.js +52 -6
- package/dist/team/__tests__/team-status.test.js.map +1 -1
- package/dist/team/__tests__/tmux-comm.test.d.ts +2 -0
- package/dist/team/__tests__/tmux-comm.test.d.ts.map +1 -0
- package/dist/team/__tests__/tmux-comm.test.js +26 -0
- package/dist/team/__tests__/tmux-comm.test.js.map +1 -0
- package/dist/team/__tests__/tmux-session.create-team.test.d.ts +2 -0
- package/dist/team/__tests__/tmux-session.create-team.test.d.ts.map +1 -0
- package/dist/team/__tests__/tmux-session.create-team.test.js +104 -0
- package/dist/team/__tests__/tmux-session.create-team.test.js.map +1 -0
- package/dist/team/__tests__/tmux-session.spawn.test.d.ts +2 -0
- package/dist/team/__tests__/tmux-session.spawn.test.d.ts.map +1 -0
- package/dist/team/__tests__/tmux-session.spawn.test.js +61 -0
- package/dist/team/__tests__/tmux-session.spawn.test.js.map +1 -0
- package/dist/team/__tests__/tmux-session.test.js +161 -2
- package/dist/team/__tests__/tmux-session.test.js.map +1 -1
- package/dist/team/__tests__/worker-bootstrap.test.d.ts +2 -0
- package/dist/team/__tests__/worker-bootstrap.test.d.ts.map +1 -0
- package/dist/team/__tests__/worker-bootstrap.test.js +58 -0
- package/dist/team/__tests__/worker-bootstrap.test.js.map +1 -0
- package/dist/team/bridge-entry.d.ts.map +1 -1
- package/dist/team/bridge-entry.js +4 -0
- package/dist/team/bridge-entry.js.map +1 -1
- package/dist/team/capabilities.d.ts.map +1 -1
- package/dist/team/capabilities.js +3 -0
- package/dist/team/capabilities.js.map +1 -1
- package/dist/team/cli-detection.d.ts +9 -0
- package/dist/team/cli-detection.d.ts.map +1 -0
- package/dist/team/cli-detection.js +29 -0
- package/dist/team/cli-detection.js.map +1 -0
- package/dist/team/fs-utils.d.ts.map +1 -1
- package/dist/team/fs-utils.js +25 -4
- package/dist/team/fs-utils.js.map +1 -1
- package/dist/team/idle-nudge.d.ts +53 -0
- package/dist/team/idle-nudge.d.ts.map +1 -0
- package/dist/team/idle-nudge.js +124 -0
- package/dist/team/idle-nudge.js.map +1 -0
- package/dist/team/inbox-outbox.d.ts.map +1 -1
- package/dist/team/inbox-outbox.js +7 -3
- package/dist/team/inbox-outbox.js.map +1 -1
- package/dist/team/index.d.ts +14 -1
- package/dist/team/index.d.ts.map +1 -1
- package/dist/team/index.js +12 -1
- package/dist/team/index.js.map +1 -1
- package/dist/team/mcp-team-bridge.d.ts +9 -0
- package/dist/team/mcp-team-bridge.d.ts.map +1 -1
- package/dist/team/mcp-team-bridge.js +82 -3
- package/dist/team/mcp-team-bridge.js.map +1 -1
- package/dist/team/model-contract.d.ts +37 -0
- package/dist/team/model-contract.d.ts.map +1 -0
- package/dist/team/model-contract.js +139 -0
- package/dist/team/model-contract.js.map +1 -0
- package/dist/team/phase-controller.d.ts +33 -0
- package/dist/team/phase-controller.d.ts.map +1 -0
- package/dist/team/phase-controller.js +79 -0
- package/dist/team/phase-controller.js.map +1 -0
- package/dist/team/runtime-cli.d.ts +9 -0
- package/dist/team/runtime-cli.d.ts.map +1 -0
- package/dist/team/runtime-cli.js +188 -0
- package/dist/team/runtime-cli.js.map +1 -0
- package/dist/team/runtime.d.ts +95 -0
- package/dist/team/runtime.d.ts.map +1 -0
- package/dist/team/runtime.js +692 -0
- package/dist/team/runtime.js.map +1 -0
- package/dist/team/state-paths.d.ts +72 -0
- package/dist/team/state-paths.d.ts.map +1 -0
- package/dist/team/state-paths.js +87 -0
- package/dist/team/state-paths.js.map +1 -0
- package/dist/team/task-file-ops.d.ts +27 -7
- package/dist/team/task-file-ops.d.ts.map +1 -1
- package/dist/team/task-file-ops.js +116 -55
- package/dist/team/task-file-ops.js.map +1 -1
- package/dist/team/team-name.d.ts +2 -0
- package/dist/team/team-name.d.ts.map +1 -0
- package/dist/team/team-name.js +8 -0
- package/dist/team/team-name.js.map +1 -0
- package/dist/team/team-registration.d.ts +1 -1
- package/dist/team/team-registration.d.ts.map +1 -1
- package/dist/team/team-registration.js.map +1 -1
- package/dist/team/team-status.d.ts +11 -1
- package/dist/team/team-status.d.ts.map +1 -1
- package/dist/team/team-status.js +32 -3
- package/dist/team/team-status.js.map +1 -1
- package/dist/team/tmux-comm.d.ts +36 -0
- package/dist/team/tmux-comm.d.ts.map +1 -0
- package/dist/team/tmux-comm.js +115 -0
- package/dist/team/tmux-comm.js.map +1 -0
- package/dist/team/tmux-session.d.ts +92 -0
- package/dist/team/tmux-session.d.ts.map +1 -1
- package/dist/team/tmux-session.js +533 -2
- package/dist/team/tmux-session.js.map +1 -1
- package/dist/team/types.d.ts +10 -3
- package/dist/team/types.d.ts.map +1 -1
- package/dist/team/unified-team.d.ts.map +1 -1
- package/dist/team/unified-team.js +13 -3
- package/dist/team/unified-team.js.map +1 -1
- package/dist/team/worker-bootstrap.d.ts +39 -0
- package/dist/team/worker-bootstrap.d.ts.map +1 -0
- package/dist/team/worker-bootstrap.js +117 -0
- package/dist/team/worker-bootstrap.js.map +1 -0
- package/dist/team/worker-health.d.ts.map +1 -1
- package/dist/team/worker-health.js +15 -3
- package/dist/team/worker-health.js.map +1 -1
- package/dist/tools/ast-tools.js +1 -1
- package/dist/tools/ast-tools.js.map +1 -1
- package/dist/tools/diagnostics/lsp-aggregator.d.ts.map +1 -1
- package/dist/tools/diagnostics/lsp-aggregator.js +4 -2
- package/dist/tools/diagnostics/lsp-aggregator.js.map +1 -1
- package/dist/tools/lsp/__tests__/client-handle-data.test.d.ts +2 -0
- package/dist/tools/lsp/__tests__/client-handle-data.test.d.ts.map +1 -0
- package/dist/tools/lsp/__tests__/client-handle-data.test.js +138 -0
- package/dist/tools/lsp/__tests__/client-handle-data.test.js.map +1 -0
- package/dist/tools/lsp/client.d.ts +13 -0
- package/dist/tools/lsp/client.d.ts.map +1 -1
- package/dist/tools/lsp/client.js +64 -8
- package/dist/tools/lsp/client.js.map +1 -1
- package/dist/tools/lsp/servers.d.ts.map +1 -1
- package/dist/tools/lsp/servers.js +4 -9
- package/dist/tools/lsp/servers.js.map +1 -1
- package/dist/tools/lsp-tools.d.ts.map +1 -1
- package/dist/tools/lsp-tools.js +4 -0
- package/dist/tools/lsp-tools.js.map +1 -1
- package/dist/tools/python-repl/bridge-manager.d.ts.map +1 -1
- package/dist/tools/python-repl/bridge-manager.js +15 -1
- package/dist/tools/python-repl/bridge-manager.js.map +1 -1
- package/dist/tools/python-repl/session-lock.d.ts.map +1 -1
- package/dist/tools/python-repl/session-lock.js +35 -15
- package/dist/tools/python-repl/session-lock.js.map +1 -1
- package/dist/tools/state-tools.d.ts.map +1 -1
- package/dist/tools/state-tools.js +10 -0
- package/dist/tools/state-tools.js.map +1 -1
- package/dist/utils/__tests__/frontmatter.test.d.ts +2 -0
- package/dist/utils/__tests__/frontmatter.test.d.ts.map +1 -0
- package/dist/utils/__tests__/frontmatter.test.js +147 -0
- package/dist/utils/__tests__/frontmatter.test.js.map +1 -0
- package/dist/utils/frontmatter.d.ts +24 -0
- package/dist/utils/frontmatter.d.ts.map +1 -0
- package/dist/utils/frontmatter.js +62 -0
- package/dist/utils/frontmatter.js.map +1 -0
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +4 -2
- package/dist/utils/paths.js.map +1 -1
- package/dist/utils/string-width.d.ts.map +1 -1
- package/dist/utils/string-width.js +15 -4
- package/dist/utils/string-width.js.map +1 -1
- package/dist/verification/tier-selector.js +1 -1
- package/dist/verification/tier-selector.js.map +1 -1
- package/docs/AGENTS.md +4 -2
- package/docs/CLAUDE.md +8 -48
- package/docs/MIGRATION.md +114 -0
- package/docs/REFERENCE.md +35 -102
- package/hooks/hooks.json +23 -23
- package/package.json +8 -8
- package/scripts/build-runtime-cli.mjs +24 -0
- package/scripts/build-team-server.mjs +28 -0
- package/scripts/cleanup-orphans.mjs +22 -5
- package/scripts/context-safety.mjs +5 -1
- package/scripts/demo-team.mjs +26 -0
- package/scripts/keyword-detector.mjs +6 -76
- package/scripts/openclaw-gateway-demo.mjs +168 -0
- package/scripts/persistent-mode.cjs +30 -4
- package/scripts/persistent-mode.mjs +48 -3
- package/scripts/plugin-setup.mjs +66 -3
- package/scripts/post-tool-use-failure.mjs +20 -2
- package/scripts/post-tool-verifier.mjs +57 -6
- package/scripts/pre-tool-enforcer.mjs +125 -5
- package/scripts/run.cjs +114 -0
- package/scripts/session-start.mjs +56 -7
- package/scripts/status.mjs +144 -0
- package/scripts/test-codex-gemini-team.mjs +78 -0
- package/skills/AGENTS.md +5 -2
- package/skills/analyze/SKILL.md +5 -11
- package/skills/autopilot/SKILL.md +5 -6
- package/skills/ccg/SKILL.md +88 -99
- package/skills/configure-notifications/SKILL.md +177 -0
- package/skills/configure-openclaw/SKILL.md +320 -0
- package/skills/external-context/SKILL.md +7 -83
- package/skills/hud/SKILL.md +68 -46
- package/skills/omc-setup/SKILL.md +58 -19
- package/skills/omc-teams/SKILL.md +178 -0
- package/skills/pipeline/SKILL.md +4 -4
- package/skills/plan/SKILL.md +28 -16
- package/skills/ralph/SKILL.md +3 -4
- package/skills/ralph-init/SKILL.md +3 -1
- package/skills/ralplan/SKILL.md +93 -8
- package/skills/security-review/SKILL.md +5 -6
- package/skills/tdd/SKILL.md +5 -6
- package/skills/team/SKILL.md +35 -34
- package/templates/hooks/keyword-detector.mjs +11 -82
- package/templates/hooks/persistent-mode.mjs +120 -3
- package/templates/hooks/post-tool-use-failure.mjs +20 -2
- package/templates/hooks/session-start.mjs +2 -16
- package/dist/__tests__/analytics/backfill-dedup.test.d.ts +0 -2
- package/dist/__tests__/analytics/backfill-dedup.test.d.ts.map +0 -1
- package/dist/__tests__/analytics/backfill-dedup.test.js +0 -179
- package/dist/__tests__/analytics/backfill-dedup.test.js.map +0 -1
- package/dist/__tests__/analytics/backfill-engine.test.d.ts +0 -2
- package/dist/__tests__/analytics/backfill-engine.test.d.ts.map +0 -1
- package/dist/__tests__/analytics/backfill-engine.test.js +0 -362
- package/dist/__tests__/analytics/backfill-engine.test.js.map +0 -1
- package/dist/__tests__/analytics/output-estimator.test.d.ts +0 -2
- package/dist/__tests__/analytics/output-estimator.test.d.ts.map +0 -1
- package/dist/__tests__/analytics/output-estimator.test.js +0 -124
- package/dist/__tests__/analytics/output-estimator.test.js.map +0 -1
- package/dist/__tests__/analytics/token-extractor.test.d.ts +0 -2
- package/dist/__tests__/analytics/token-extractor.test.d.ts.map +0 -1
- package/dist/__tests__/analytics/token-extractor.test.js +0 -165
- package/dist/__tests__/analytics/token-extractor.test.js.map +0 -1
- package/dist/__tests__/analytics/token-tracker.test.d.ts +0 -2
- package/dist/__tests__/analytics/token-tracker.test.d.ts.map +0 -1
- package/dist/__tests__/analytics/token-tracker.test.js +0 -189
- package/dist/__tests__/analytics/token-tracker.test.js.map +0 -1
- package/dist/__tests__/analytics/tokscale-adapter.test.d.ts +0 -2
- package/dist/__tests__/analytics/tokscale-adapter.test.d.ts.map +0 -1
- package/dist/__tests__/analytics/tokscale-adapter.test.js +0 -79
- package/dist/__tests__/analytics/tokscale-adapter.test.js.map +0 -1
- package/dist/__tests__/analytics/transcript-parser.test.d.ts +0 -2
- package/dist/__tests__/analytics/transcript-parser.test.d.ts.map +0 -1
- package/dist/__tests__/analytics/transcript-parser.test.js +0 -285
- package/dist/__tests__/analytics/transcript-parser.test.js.map +0 -1
- package/dist/__tests__/analytics/transcript-scanner.test.d.ts +0 -2
- package/dist/__tests__/analytics/transcript-scanner.test.d.ts.map +0 -1
- package/dist/__tests__/analytics/transcript-scanner.test.js +0 -443
- package/dist/__tests__/analytics/transcript-scanner.test.js.map +0 -1
- package/dist/__tests__/analytics/transcript-token-extractor.test.d.ts +0 -2
- package/dist/__tests__/analytics/transcript-token-extractor.test.d.ts.map +0 -1
- package/dist/__tests__/analytics/transcript-token-extractor.test.js +0 -177
- package/dist/__tests__/analytics/transcript-token-extractor.test.js.map +0 -1
- package/dist/analytics/analytics-summary.d.ts +0 -47
- package/dist/analytics/analytics-summary.d.ts.map +0 -1
- package/dist/analytics/analytics-summary.js +0 -171
- package/dist/analytics/analytics-summary.js.map +0 -1
- package/dist/analytics/backfill-dedup.d.ts +0 -49
- package/dist/analytics/backfill-dedup.d.ts.map +0 -1
- package/dist/analytics/backfill-dedup.js +0 -115
- package/dist/analytics/backfill-dedup.js.map +0 -1
- package/dist/analytics/backfill-engine.d.ts +0 -59
- package/dist/analytics/backfill-engine.d.ts.map +0 -1
- package/dist/analytics/backfill-engine.js +0 -172
- package/dist/analytics/backfill-engine.js.map +0 -1
- package/dist/analytics/cost-estimator.d.ts +0 -29
- package/dist/analytics/cost-estimator.d.ts.map +0 -1
- package/dist/analytics/cost-estimator.js +0 -135
- package/dist/analytics/cost-estimator.js.map +0 -1
- package/dist/analytics/export.d.ts +0 -7
- package/dist/analytics/export.d.ts.map +0 -1
- package/dist/analytics/export.js +0 -93
- package/dist/analytics/export.js.map +0 -1
- package/dist/analytics/index.d.ts +0 -24
- package/dist/analytics/index.d.ts.map +0 -1
- package/dist/analytics/index.js +0 -30
- package/dist/analytics/index.js.map +0 -1
- package/dist/analytics/metrics-collector.d.ts +0 -30
- package/dist/analytics/metrics-collector.d.ts.map +0 -1
- package/dist/analytics/metrics-collector.js +0 -96
- package/dist/analytics/metrics-collector.js.map +0 -1
- package/dist/analytics/output-estimator.d.ts +0 -26
- package/dist/analytics/output-estimator.d.ts.map +0 -1
- package/dist/analytics/output-estimator.js +0 -65
- package/dist/analytics/output-estimator.js.map +0 -1
- package/dist/analytics/query-engine.d.ts +0 -35
- package/dist/analytics/query-engine.d.ts.map +0 -1
- package/dist/analytics/query-engine.js +0 -239
- package/dist/analytics/query-engine.js.map +0 -1
- package/dist/analytics/session-catalog.d.ts +0 -45
- package/dist/analytics/session-catalog.d.ts.map +0 -1
- package/dist/analytics/session-catalog.js +0 -153
- package/dist/analytics/session-catalog.js.map +0 -1
- package/dist/analytics/session-manager.d.ts +0 -58
- package/dist/analytics/session-manager.d.ts.map +0 -1
- package/dist/analytics/session-manager.js +0 -396
- package/dist/analytics/session-manager.js.map +0 -1
- package/dist/analytics/session-types.d.ts +0 -37
- package/dist/analytics/session-types.d.ts.map +0 -1
- package/dist/analytics/session-types.js +0 -2
- package/dist/analytics/session-types.js.map +0 -1
- package/dist/analytics/token-extractor.d.ts +0 -31
- package/dist/analytics/token-extractor.d.ts.map +0 -1
- package/dist/analytics/token-extractor.js +0 -57
- package/dist/analytics/token-extractor.js.map +0 -1
- package/dist/analytics/token-tracker.d.ts +0 -33
- package/dist/analytics/token-tracker.d.ts.map +0 -1
- package/dist/analytics/token-tracker.js +0 -443
- package/dist/analytics/token-tracker.js.map +0 -1
- package/dist/analytics/tokscale-adapter.d.ts +0 -71
- package/dist/analytics/tokscale-adapter.d.ts.map +0 -1
- package/dist/analytics/tokscale-adapter.js +0 -223
- package/dist/analytics/tokscale-adapter.js.map +0 -1
- package/dist/analytics/transcript-parser.d.ts +0 -42
- package/dist/analytics/transcript-parser.d.ts.map +0 -1
- package/dist/analytics/transcript-parser.js +0 -90
- package/dist/analytics/transcript-parser.js.map +0 -1
- package/dist/analytics/transcript-scanner.d.ts +0 -51
- package/dist/analytics/transcript-scanner.d.ts.map +0 -1
- package/dist/analytics/transcript-scanner.js +0 -279
- package/dist/analytics/transcript-scanner.js.map +0 -1
- package/dist/analytics/transcript-token-extractor.d.ts +0 -35
- package/dist/analytics/transcript-token-extractor.d.ts.map +0 -1
- package/dist/analytics/transcript-token-extractor.js +0 -136
- package/dist/analytics/transcript-token-extractor.js.map +0 -1
- package/dist/analytics/types.d.ts +0 -119
- package/dist/analytics/types.d.ts.map +0 -1
- package/dist/analytics/types.js +0 -32
- package/dist/analytics/types.js.map +0 -1
- package/dist/cli/analytics.d.ts +0 -3
- package/dist/cli/analytics.d.ts.map +0 -1
- package/dist/cli/analytics.js +0 -105
- package/dist/cli/analytics.js.map +0 -1
- package/dist/cli/commands/agents.d.ts +0 -5
- package/dist/cli/commands/agents.d.ts.map +0 -1
- package/dist/cli/commands/agents.js +0 -31
- package/dist/cli/commands/agents.js.map +0 -1
- package/dist/cli/commands/backfill.d.ts +0 -15
- package/dist/cli/commands/backfill.d.ts.map +0 -1
- package/dist/cli/commands/backfill.js +0 -146
- package/dist/cli/commands/backfill.js.map +0 -1
- package/dist/cli/commands/cleanup.d.ts +0 -4
- package/dist/cli/commands/cleanup.d.ts.map +0 -1
- package/dist/cli/commands/cleanup.js +0 -31
- package/dist/cli/commands/cleanup.js.map +0 -1
- package/dist/cli/commands/cost.d.ts +0 -4
- package/dist/cli/commands/cost.d.ts.map +0 -1
- package/dist/cli/commands/cost.js +0 -53
- package/dist/cli/commands/cost.js.map +0 -1
- package/dist/cli/commands/export.d.ts +0 -5
- package/dist/cli/commands/export.d.ts.map +0 -1
- package/dist/cli/commands/export.js +0 -30
- package/dist/cli/commands/export.js.map +0 -1
- package/dist/cli/commands/sessions.d.ts +0 -5
- package/dist/cli/commands/sessions.d.ts.map +0 -1
- package/dist/cli/commands/sessions.js +0 -89
- package/dist/cli/commands/sessions.js.map +0 -1
- package/dist/cli/commands/stats.d.ts +0 -5
- package/dist/cli/commands/stats.d.ts.map +0 -1
- package/dist/cli/commands/stats.js +0 -84
- package/dist/cli/commands/stats.js.map +0 -1
- package/dist/cli/utils/tokscale-launcher.d.ts +0 -25
- package/dist/cli/utils/tokscale-launcher.d.ts.map +0 -1
- package/dist/cli/utils/tokscale-launcher.js +0 -70
- package/dist/cli/utils/tokscale-launcher.js.map +0 -1
- package/dist/hud/analytics-display.d.ts +0 -63
- package/dist/hud/analytics-display.d.ts.map +0 -1
- package/dist/hud/analytics-display.js +0 -190
- package/dist/hud/analytics-display.js.map +0 -1
- package/scripts/build-codex-server.mjs +0 -95
|
@@ -0,0 +1,1550 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
+
for (let key of __getOwnPropNames(from))
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
12
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
13
|
+
}
|
|
14
|
+
return to;
|
|
15
|
+
};
|
|
16
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
17
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
18
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
19
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
20
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
21
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
22
|
+
mod
|
|
23
|
+
));
|
|
24
|
+
|
|
25
|
+
// src/team/runtime-cli.ts
|
|
26
|
+
var import_fs7 = require("fs");
|
|
27
|
+
var import_promises4 = require("fs/promises");
|
|
28
|
+
var import_path10 = require("path");
|
|
29
|
+
|
|
30
|
+
// src/team/runtime.ts
|
|
31
|
+
var import_promises3 = require("fs/promises");
|
|
32
|
+
var import_path9 = require("path");
|
|
33
|
+
var import_fs6 = require("fs");
|
|
34
|
+
|
|
35
|
+
// src/team/model-contract.ts
|
|
36
|
+
var import_child_process = require("child_process");
|
|
37
|
+
|
|
38
|
+
// src/team/team-name.ts
|
|
39
|
+
var TEAM_NAME_PATTERN = /^[a-z0-9][a-z0-9-]{0,48}[a-z0-9]$/;
|
|
40
|
+
function validateTeamName(teamName) {
|
|
41
|
+
if (!TEAM_NAME_PATTERN.test(teamName)) {
|
|
42
|
+
throw new Error(
|
|
43
|
+
`Invalid team name: "${teamName}". Team name must match /^[a-z0-9][a-z0-9-]{0,48}[a-z0-9]$/.`
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
return teamName;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// src/team/model-contract.ts
|
|
50
|
+
var CONTRACTS = {
|
|
51
|
+
claude: {
|
|
52
|
+
agentType: "claude",
|
|
53
|
+
binary: "claude",
|
|
54
|
+
installInstructions: "Install Claude CLI: https://claude.ai/download",
|
|
55
|
+
buildLaunchArgs(model, extraFlags = []) {
|
|
56
|
+
const args = ["--dangerously-skip-permissions"];
|
|
57
|
+
if (model) args.push("--model", model);
|
|
58
|
+
return [...args, ...extraFlags];
|
|
59
|
+
},
|
|
60
|
+
parseOutput(rawOutput) {
|
|
61
|
+
return rawOutput.trim();
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
codex: {
|
|
65
|
+
agentType: "codex",
|
|
66
|
+
binary: "codex",
|
|
67
|
+
installInstructions: "Install Codex CLI: npm install -g @openai/codex",
|
|
68
|
+
supportsPromptMode: true,
|
|
69
|
+
// Codex accepts prompt as a positional argument (no flag needed):
|
|
70
|
+
// codex [OPTIONS] [PROMPT]
|
|
71
|
+
buildLaunchArgs(model, extraFlags = []) {
|
|
72
|
+
const args = ["--dangerously-bypass-approvals-and-sandbox"];
|
|
73
|
+
if (model) args.push("--model", model);
|
|
74
|
+
return [...args, ...extraFlags];
|
|
75
|
+
},
|
|
76
|
+
parseOutput(rawOutput) {
|
|
77
|
+
const lines = rawOutput.trim().split("\n").filter(Boolean);
|
|
78
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
79
|
+
try {
|
|
80
|
+
const parsed = JSON.parse(lines[i]);
|
|
81
|
+
if (parsed.type === "message" && parsed.role === "assistant") {
|
|
82
|
+
return parsed.content ?? rawOutput;
|
|
83
|
+
}
|
|
84
|
+
if (parsed.type === "result" || parsed.output) {
|
|
85
|
+
return parsed.output ?? parsed.result ?? rawOutput;
|
|
86
|
+
}
|
|
87
|
+
} catch {
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return rawOutput.trim();
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
gemini: {
|
|
94
|
+
agentType: "gemini",
|
|
95
|
+
binary: "gemini",
|
|
96
|
+
installInstructions: "Install Gemini CLI: npm install -g @google/gemini-cli",
|
|
97
|
+
supportsPromptMode: true,
|
|
98
|
+
promptModeFlag: "-p",
|
|
99
|
+
buildLaunchArgs(model, extraFlags = []) {
|
|
100
|
+
const args = ["--yolo"];
|
|
101
|
+
if (model) args.push("--model", model);
|
|
102
|
+
return [...args, ...extraFlags];
|
|
103
|
+
},
|
|
104
|
+
parseOutput(rawOutput) {
|
|
105
|
+
return rawOutput.trim();
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
function getContract(agentType) {
|
|
110
|
+
const contract = CONTRACTS[agentType];
|
|
111
|
+
if (!contract) {
|
|
112
|
+
throw new Error(`Unknown agent type: ${agentType}. Supported: ${Object.keys(CONTRACTS).join(", ")}`);
|
|
113
|
+
}
|
|
114
|
+
return contract;
|
|
115
|
+
}
|
|
116
|
+
function isCliAvailable(agentType) {
|
|
117
|
+
const contract = getContract(agentType);
|
|
118
|
+
try {
|
|
119
|
+
const result = (0, import_child_process.spawnSync)(contract.binary, ["--version"], { timeout: 5e3, shell: true });
|
|
120
|
+
return result.status === 0;
|
|
121
|
+
} catch {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
function validateCliAvailable(agentType) {
|
|
126
|
+
if (!isCliAvailable(agentType)) {
|
|
127
|
+
const contract = getContract(agentType);
|
|
128
|
+
throw new Error(
|
|
129
|
+
`CLI agent '${agentType}' not found. ${contract.installInstructions}`
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
function buildLaunchArgs(agentType, config) {
|
|
134
|
+
return getContract(agentType).buildLaunchArgs(config.model, config.extraFlags);
|
|
135
|
+
}
|
|
136
|
+
function buildWorkerArgv(agentType, config) {
|
|
137
|
+
validateTeamName(config.teamName);
|
|
138
|
+
const contract = getContract(agentType);
|
|
139
|
+
const args = buildLaunchArgs(agentType, config);
|
|
140
|
+
return [contract.binary, ...args];
|
|
141
|
+
}
|
|
142
|
+
function getWorkerEnv(teamName, workerName2, agentType) {
|
|
143
|
+
validateTeamName(teamName);
|
|
144
|
+
return {
|
|
145
|
+
OMC_TEAM_WORKER: `${teamName}/${workerName2}`,
|
|
146
|
+
OMC_TEAM_NAME: teamName,
|
|
147
|
+
OMC_WORKER_AGENT_TYPE: agentType
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
function isPromptModeAgent(agentType) {
|
|
151
|
+
const contract = getContract(agentType);
|
|
152
|
+
return !!contract.supportsPromptMode;
|
|
153
|
+
}
|
|
154
|
+
function getPromptModeArgs(agentType, instruction) {
|
|
155
|
+
const contract = getContract(agentType);
|
|
156
|
+
if (!contract.supportsPromptMode) {
|
|
157
|
+
return [];
|
|
158
|
+
}
|
|
159
|
+
if (contract.promptModeFlag) {
|
|
160
|
+
return [contract.promptModeFlag, instruction];
|
|
161
|
+
}
|
|
162
|
+
return [instruction];
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// src/team/tmux-session.ts
|
|
166
|
+
var import_child_process2 = require("child_process");
|
|
167
|
+
var import_path = require("path");
|
|
168
|
+
var import_util = require("util");
|
|
169
|
+
var import_promises = __toESM(require("fs/promises"), 1);
|
|
170
|
+
var promisifiedExec = (0, import_util.promisify)(import_child_process2.exec);
|
|
171
|
+
var promisifiedExecFile = (0, import_util.promisify)(import_child_process2.execFile);
|
|
172
|
+
function isUnixLikeOnWindows() {
|
|
173
|
+
return process.platform === "win32" && !!(process.env.MSYSTEM || process.env.MINGW_PREFIX);
|
|
174
|
+
}
|
|
175
|
+
async function tmuxAsync(args) {
|
|
176
|
+
if (args.some((a) => a.includes("#{"))) {
|
|
177
|
+
const escaped = args.map((a) => `"${a.replace(/"/g, '\\"')}"`).join(" ");
|
|
178
|
+
return promisifiedExec(`tmux ${escaped}`);
|
|
179
|
+
}
|
|
180
|
+
return promisifiedExecFile("tmux", args);
|
|
181
|
+
}
|
|
182
|
+
function getDefaultShell() {
|
|
183
|
+
if (process.platform === "win32" && !isUnixLikeOnWindows()) {
|
|
184
|
+
return process.env.COMSPEC || "cmd.exe";
|
|
185
|
+
}
|
|
186
|
+
return process.env.SHELL || "/bin/bash";
|
|
187
|
+
}
|
|
188
|
+
function escapeForCmdSet(value) {
|
|
189
|
+
return value.replace(/"/g, '""');
|
|
190
|
+
}
|
|
191
|
+
function shellNameFromPath(shellPath) {
|
|
192
|
+
const shellName = (0, import_path.basename)(shellPath.replace(/\\/g, "/"));
|
|
193
|
+
return shellName.replace(/\.(exe|cmd|bat)$/i, "");
|
|
194
|
+
}
|
|
195
|
+
function shellEscape(value) {
|
|
196
|
+
return `'${value.replace(/'/g, `'"'"'`)}'`;
|
|
197
|
+
}
|
|
198
|
+
function assertSafeEnvKey(key) {
|
|
199
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) {
|
|
200
|
+
throw new Error(`Invalid environment key: "${key}"`);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
function getLaunchWords(config) {
|
|
204
|
+
if (config.launchBinary) {
|
|
205
|
+
return [config.launchBinary, ...config.launchArgs ?? []];
|
|
206
|
+
}
|
|
207
|
+
if (config.launchCmd) {
|
|
208
|
+
return [config.launchCmd];
|
|
209
|
+
}
|
|
210
|
+
throw new Error("Missing worker launch command. Provide launchBinary or launchCmd.");
|
|
211
|
+
}
|
|
212
|
+
function buildWorkerStartCommand(config) {
|
|
213
|
+
const shell = getDefaultShell();
|
|
214
|
+
const launchWords = getLaunchWords(config);
|
|
215
|
+
if (process.platform === "win32" && !isUnixLikeOnWindows()) {
|
|
216
|
+
const envPrefix = Object.entries(config.envVars).map(([k, v]) => {
|
|
217
|
+
assertSafeEnvKey(k);
|
|
218
|
+
return `set "${k}=${escapeForCmdSet(v)}"`;
|
|
219
|
+
}).join(" && ");
|
|
220
|
+
const launch = config.launchBinary ? launchWords.map((part) => `"${escapeForCmdSet(part)}"`).join(" ") : launchWords[0];
|
|
221
|
+
const cmdBody = envPrefix ? `${envPrefix} && ${launch}` : launch;
|
|
222
|
+
return `${shell} /d /s /c "${cmdBody}"`;
|
|
223
|
+
}
|
|
224
|
+
if (config.launchBinary) {
|
|
225
|
+
const envAssignments = Object.entries(config.envVars).map(([key, value]) => {
|
|
226
|
+
assertSafeEnvKey(key);
|
|
227
|
+
return `${key}=${shellEscape(value)}`;
|
|
228
|
+
});
|
|
229
|
+
const shellName2 = shellNameFromPath(shell) || "bash";
|
|
230
|
+
const rcFile2 = process.env.HOME ? `${process.env.HOME}/.${shellName2}rc` : "";
|
|
231
|
+
const script = rcFile2 ? `[ -f ${shellEscape(rcFile2)} ] && . ${shellEscape(rcFile2)}; exec "$@"` : 'exec "$@"';
|
|
232
|
+
return [
|
|
233
|
+
"env",
|
|
234
|
+
...envAssignments,
|
|
235
|
+
shell,
|
|
236
|
+
"-lc",
|
|
237
|
+
script,
|
|
238
|
+
"--",
|
|
239
|
+
...launchWords
|
|
240
|
+
].map(shellEscape).join(" ");
|
|
241
|
+
}
|
|
242
|
+
const envString = Object.entries(config.envVars).map(([k, v]) => {
|
|
243
|
+
assertSafeEnvKey(k);
|
|
244
|
+
return `${k}=${shellEscape(v)}`;
|
|
245
|
+
}).join(" ");
|
|
246
|
+
const shellName = shellNameFromPath(shell) || "bash";
|
|
247
|
+
const rcFile = process.env.HOME ? `${process.env.HOME}/.${shellName}rc` : "";
|
|
248
|
+
const sourceCmd = rcFile ? `[ -f "${rcFile}" ] && source "${rcFile}"; ` : "";
|
|
249
|
+
return `env ${envString} ${shell} -c "${sourceCmd}exec ${launchWords[0]}"`;
|
|
250
|
+
}
|
|
251
|
+
function sanitizeName(name) {
|
|
252
|
+
const sanitized = name.replace(/[^a-zA-Z0-9-]/g, "");
|
|
253
|
+
if (sanitized.length === 0) {
|
|
254
|
+
throw new Error(`Invalid name: "${name}" contains no valid characters (alphanumeric or hyphen)`);
|
|
255
|
+
}
|
|
256
|
+
if (sanitized.length < 2) {
|
|
257
|
+
throw new Error(`Invalid name: "${name}" too short after sanitization (minimum 2 characters)`);
|
|
258
|
+
}
|
|
259
|
+
return sanitized.slice(0, 50);
|
|
260
|
+
}
|
|
261
|
+
async function createTeamSession(teamName, workerCount, cwd) {
|
|
262
|
+
const { execFile: execFile2 } = await import("child_process");
|
|
263
|
+
const { promisify: promisify2 } = await import("util");
|
|
264
|
+
const execFileAsync = promisify2(execFile2);
|
|
265
|
+
if (!process.env.TMUX) {
|
|
266
|
+
throw new Error("Team mode requires running inside tmux. Start one: tmux new-session");
|
|
267
|
+
}
|
|
268
|
+
const envPaneIdRaw = (process.env.TMUX_PANE ?? "").trim();
|
|
269
|
+
const envPaneId = /^%\d+$/.test(envPaneIdRaw) ? envPaneIdRaw : "";
|
|
270
|
+
let sessionAndWindow = "";
|
|
271
|
+
let leaderPaneId = envPaneId;
|
|
272
|
+
if (envPaneId) {
|
|
273
|
+
try {
|
|
274
|
+
const targetedContextResult = await execFileAsync("tmux", [
|
|
275
|
+
"display-message",
|
|
276
|
+
"-p",
|
|
277
|
+
"-t",
|
|
278
|
+
envPaneId,
|
|
279
|
+
"#S:#I"
|
|
280
|
+
]);
|
|
281
|
+
sessionAndWindow = targetedContextResult.stdout.trim();
|
|
282
|
+
} catch {
|
|
283
|
+
sessionAndWindow = "";
|
|
284
|
+
leaderPaneId = "";
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
if (!sessionAndWindow || !leaderPaneId) {
|
|
288
|
+
const contextResult = await tmuxAsync([
|
|
289
|
+
"display-message",
|
|
290
|
+
"-p",
|
|
291
|
+
"#S:#I #{pane_id}"
|
|
292
|
+
]);
|
|
293
|
+
const contextLine = contextResult.stdout.trim();
|
|
294
|
+
const contextMatch = contextLine.match(/^(\S+)\s+(%\d+)$/);
|
|
295
|
+
if (!contextMatch) {
|
|
296
|
+
throw new Error(`Failed to resolve tmux context: "${contextLine}"`);
|
|
297
|
+
}
|
|
298
|
+
sessionAndWindow = contextMatch[1];
|
|
299
|
+
leaderPaneId = contextMatch[2];
|
|
300
|
+
}
|
|
301
|
+
const teamTarget = sessionAndWindow;
|
|
302
|
+
const resolvedSessionName = teamTarget.split(":")[0];
|
|
303
|
+
const workerPaneIds = [];
|
|
304
|
+
if (workerCount <= 0) {
|
|
305
|
+
try {
|
|
306
|
+
await execFileAsync("tmux", ["set-option", "-t", resolvedSessionName, "mouse", "on"]);
|
|
307
|
+
} catch {
|
|
308
|
+
}
|
|
309
|
+
try {
|
|
310
|
+
await execFileAsync("tmux", ["select-pane", "-t", leaderPaneId]);
|
|
311
|
+
} catch {
|
|
312
|
+
}
|
|
313
|
+
await new Promise((r) => setTimeout(r, 300));
|
|
314
|
+
return { sessionName: teamTarget, leaderPaneId, workerPaneIds };
|
|
315
|
+
}
|
|
316
|
+
for (let i = 0; i < workerCount; i++) {
|
|
317
|
+
const splitTarget = i === 0 ? leaderPaneId : workerPaneIds[i - 1];
|
|
318
|
+
const splitType = i === 0 ? "-h" : "-v";
|
|
319
|
+
const splitResult = await tmuxAsync([
|
|
320
|
+
"split-window",
|
|
321
|
+
splitType,
|
|
322
|
+
"-t",
|
|
323
|
+
splitTarget,
|
|
324
|
+
"-d",
|
|
325
|
+
"-P",
|
|
326
|
+
"-F",
|
|
327
|
+
"#{pane_id}",
|
|
328
|
+
"-c",
|
|
329
|
+
cwd
|
|
330
|
+
]);
|
|
331
|
+
const paneId = splitResult.stdout.split("\n")[0]?.trim();
|
|
332
|
+
if (paneId) {
|
|
333
|
+
workerPaneIds.push(paneId);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
try {
|
|
337
|
+
await execFileAsync("tmux", ["select-layout", "-t", teamTarget, "main-vertical"]);
|
|
338
|
+
} catch {
|
|
339
|
+
}
|
|
340
|
+
try {
|
|
341
|
+
const widthResult = await tmuxAsync([
|
|
342
|
+
"display-message",
|
|
343
|
+
"-p",
|
|
344
|
+
"-t",
|
|
345
|
+
teamTarget,
|
|
346
|
+
"#{window_width}"
|
|
347
|
+
]);
|
|
348
|
+
const width = parseInt(widthResult.stdout.trim(), 10);
|
|
349
|
+
if (Number.isFinite(width) && width >= 40) {
|
|
350
|
+
const half = String(Math.floor(width / 2));
|
|
351
|
+
await execFileAsync("tmux", ["set-window-option", "-t", teamTarget, "main-pane-width", half]);
|
|
352
|
+
await execFileAsync("tmux", ["select-layout", "-t", teamTarget, "main-vertical"]);
|
|
353
|
+
}
|
|
354
|
+
} catch {
|
|
355
|
+
}
|
|
356
|
+
try {
|
|
357
|
+
await execFileAsync("tmux", ["set-option", "-t", resolvedSessionName, "mouse", "on"]);
|
|
358
|
+
} catch {
|
|
359
|
+
}
|
|
360
|
+
try {
|
|
361
|
+
await execFileAsync("tmux", ["select-pane", "-t", leaderPaneId]);
|
|
362
|
+
} catch {
|
|
363
|
+
}
|
|
364
|
+
await new Promise((r) => setTimeout(r, 300));
|
|
365
|
+
return { sessionName: teamTarget, leaderPaneId, workerPaneIds };
|
|
366
|
+
}
|
|
367
|
+
async function spawnWorkerInPane(sessionName, paneId, config) {
|
|
368
|
+
const { execFile: execFile2 } = await import("child_process");
|
|
369
|
+
const { promisify: promisify2 } = await import("util");
|
|
370
|
+
const execFileAsync = promisify2(execFile2);
|
|
371
|
+
validateTeamName(config.teamName);
|
|
372
|
+
const startCmd = buildWorkerStartCommand(config);
|
|
373
|
+
await execFileAsync("tmux", [
|
|
374
|
+
"send-keys",
|
|
375
|
+
"-t",
|
|
376
|
+
paneId,
|
|
377
|
+
"-l",
|
|
378
|
+
startCmd
|
|
379
|
+
]);
|
|
380
|
+
await execFileAsync("tmux", ["send-keys", "-t", paneId, "Enter"]);
|
|
381
|
+
}
|
|
382
|
+
function normalizeTmuxCapture(value) {
|
|
383
|
+
return value.replace(/\r/g, "").replace(/\s+/g, " ").trim();
|
|
384
|
+
}
|
|
385
|
+
async function capturePaneAsync(paneId, execFileAsync) {
|
|
386
|
+
try {
|
|
387
|
+
const result = await execFileAsync("tmux", ["capture-pane", "-t", paneId, "-p", "-S", "-80"]);
|
|
388
|
+
return result.stdout;
|
|
389
|
+
} catch {
|
|
390
|
+
return "";
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
function paneHasTrustPrompt(captured) {
|
|
394
|
+
const lines = captured.split("\n").map((l) => l.replace(/\r/g, "").trim()).filter((l) => l.length > 0);
|
|
395
|
+
const tail = lines.slice(-12);
|
|
396
|
+
const hasQuestion = tail.some((l) => /Do you trust the contents of this directory\?/i.test(l));
|
|
397
|
+
const hasChoices = tail.some((l) => /Yes,\s*continue|No,\s*quit|Press enter to continue/i.test(l));
|
|
398
|
+
return hasQuestion && hasChoices;
|
|
399
|
+
}
|
|
400
|
+
function paneHasActiveTask(captured) {
|
|
401
|
+
const lines = captured.split("\n").map((l) => l.replace(/\r/g, "").trim()).filter((l) => l.length > 0);
|
|
402
|
+
const tail = lines.slice(-40);
|
|
403
|
+
if (tail.some((l) => /esc to interrupt/i.test(l))) return true;
|
|
404
|
+
if (tail.some((l) => /\bbackground terminal running\b/i.test(l))) return true;
|
|
405
|
+
return false;
|
|
406
|
+
}
|
|
407
|
+
function paneLooksReady(captured) {
|
|
408
|
+
const lines = captured.split("\n").map((line) => line.replace(/\r/g, "").trim()).filter((line) => line.length > 0);
|
|
409
|
+
if (lines.length === 0) return false;
|
|
410
|
+
const tail = lines.slice(-20);
|
|
411
|
+
const hasPrompt = tail.some((line) => /^\s*[›>❯]\s*/u.test(line));
|
|
412
|
+
if (hasPrompt) return true;
|
|
413
|
+
const hasCodexHint = tail.some(
|
|
414
|
+
(line) => /\bgpt-[\w.-]+\b/i.test(line) || /\b\d+% left\b/i.test(line)
|
|
415
|
+
);
|
|
416
|
+
return hasCodexHint;
|
|
417
|
+
}
|
|
418
|
+
function paneTailContainsLiteralLine(captured, text) {
|
|
419
|
+
return normalizeTmuxCapture(captured).includes(normalizeTmuxCapture(text));
|
|
420
|
+
}
|
|
421
|
+
async function paneInCopyMode(paneId, execFileAsync) {
|
|
422
|
+
try {
|
|
423
|
+
const result = await tmuxAsync(["display-message", "-t", paneId, "-p", "#{pane_in_mode}"]);
|
|
424
|
+
return result.stdout.trim() === "1";
|
|
425
|
+
} catch {
|
|
426
|
+
return false;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
function shouldAttemptAdaptiveRetry(args) {
|
|
430
|
+
if (process.env.OMX_TEAM_AUTO_INTERRUPT_RETRY === "0") return false;
|
|
431
|
+
if (args.retriesAttempted >= 1) return false;
|
|
432
|
+
if (args.paneInCopyMode) return false;
|
|
433
|
+
if (!args.paneBusy) return false;
|
|
434
|
+
if (typeof args.latestCapture !== "string") return false;
|
|
435
|
+
if (!paneTailContainsLiteralLine(args.latestCapture, args.message)) return false;
|
|
436
|
+
if (paneHasActiveTask(args.latestCapture)) return false;
|
|
437
|
+
if (!paneLooksReady(args.latestCapture)) return false;
|
|
438
|
+
return true;
|
|
439
|
+
}
|
|
440
|
+
async function sendToWorker(_sessionName, paneId, message) {
|
|
441
|
+
if (message.length > 200) {
|
|
442
|
+
console.warn(`[tmux-session] sendToWorker: message truncated to 200 chars`);
|
|
443
|
+
message = message.slice(0, 200);
|
|
444
|
+
}
|
|
445
|
+
try {
|
|
446
|
+
const { execFile: execFile2 } = await import("child_process");
|
|
447
|
+
const { promisify: promisify2 } = await import("util");
|
|
448
|
+
const execFileAsync = promisify2(execFile2);
|
|
449
|
+
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
450
|
+
const sendKey = async (key) => {
|
|
451
|
+
await execFileAsync("tmux", ["send-keys", "-t", paneId, key]);
|
|
452
|
+
};
|
|
453
|
+
if (await paneInCopyMode(paneId, execFileAsync)) {
|
|
454
|
+
return false;
|
|
455
|
+
}
|
|
456
|
+
const initialCapture = await capturePaneAsync(paneId, execFileAsync);
|
|
457
|
+
const paneBusy = paneHasActiveTask(initialCapture);
|
|
458
|
+
if (paneHasTrustPrompt(initialCapture)) {
|
|
459
|
+
await sendKey("C-m");
|
|
460
|
+
await sleep(120);
|
|
461
|
+
await sendKey("C-m");
|
|
462
|
+
await sleep(200);
|
|
463
|
+
}
|
|
464
|
+
await execFileAsync("tmux", ["send-keys", "-t", paneId, "-l", "--", message]);
|
|
465
|
+
await sleep(150);
|
|
466
|
+
const submitRounds = 6;
|
|
467
|
+
for (let round = 0; round < submitRounds; round++) {
|
|
468
|
+
await sleep(100);
|
|
469
|
+
if (round === 0 && paneBusy) {
|
|
470
|
+
await sendKey("Tab");
|
|
471
|
+
await sleep(80);
|
|
472
|
+
await sendKey("C-m");
|
|
473
|
+
} else {
|
|
474
|
+
await sendKey("C-m");
|
|
475
|
+
await sleep(200);
|
|
476
|
+
await sendKey("C-m");
|
|
477
|
+
}
|
|
478
|
+
await sleep(140);
|
|
479
|
+
const checkCapture = await capturePaneAsync(paneId, execFileAsync);
|
|
480
|
+
if (!paneTailContainsLiteralLine(checkCapture, message)) return true;
|
|
481
|
+
await sleep(140);
|
|
482
|
+
}
|
|
483
|
+
if (await paneInCopyMode(paneId, execFileAsync)) {
|
|
484
|
+
return false;
|
|
485
|
+
}
|
|
486
|
+
const finalCapture = await capturePaneAsync(paneId, execFileAsync);
|
|
487
|
+
const paneModeBeforeAdaptiveRetry = await paneInCopyMode(paneId, execFileAsync);
|
|
488
|
+
if (shouldAttemptAdaptiveRetry({
|
|
489
|
+
paneBusy,
|
|
490
|
+
latestCapture: finalCapture,
|
|
491
|
+
message,
|
|
492
|
+
paneInCopyMode: paneModeBeforeAdaptiveRetry,
|
|
493
|
+
retriesAttempted: 0
|
|
494
|
+
})) {
|
|
495
|
+
if (await paneInCopyMode(paneId, execFileAsync)) {
|
|
496
|
+
return false;
|
|
497
|
+
}
|
|
498
|
+
await sendKey("C-u");
|
|
499
|
+
await sleep(80);
|
|
500
|
+
if (await paneInCopyMode(paneId, execFileAsync)) {
|
|
501
|
+
return false;
|
|
502
|
+
}
|
|
503
|
+
await execFileAsync("tmux", ["send-keys", "-t", paneId, "-l", "--", message]);
|
|
504
|
+
await sleep(120);
|
|
505
|
+
for (let round = 0; round < 4; round++) {
|
|
506
|
+
await sendKey("C-m");
|
|
507
|
+
await sleep(180);
|
|
508
|
+
await sendKey("C-m");
|
|
509
|
+
await sleep(140);
|
|
510
|
+
const retryCapture = await capturePaneAsync(paneId, execFileAsync);
|
|
511
|
+
if (!paneTailContainsLiteralLine(retryCapture, message)) return true;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
if (await paneInCopyMode(paneId, execFileAsync)) {
|
|
515
|
+
return false;
|
|
516
|
+
}
|
|
517
|
+
await sendKey("C-m");
|
|
518
|
+
await sleep(120);
|
|
519
|
+
await sendKey("C-m");
|
|
520
|
+
return true;
|
|
521
|
+
} catch {
|
|
522
|
+
return false;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
async function isWorkerAlive(paneId) {
|
|
526
|
+
try {
|
|
527
|
+
const { execFile: execFile2 } = await import("child_process");
|
|
528
|
+
const { promisify: promisify2 } = await import("util");
|
|
529
|
+
const execFileAsync = promisify2(execFile2);
|
|
530
|
+
const result = await tmuxAsync([
|
|
531
|
+
"display-message",
|
|
532
|
+
"-t",
|
|
533
|
+
paneId,
|
|
534
|
+
"-p",
|
|
535
|
+
"#{pane_dead}"
|
|
536
|
+
]);
|
|
537
|
+
return result.stdout.trim() === "0";
|
|
538
|
+
} catch {
|
|
539
|
+
return false;
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
async function killTeamSession(sessionName, workerPaneIds, leaderPaneId) {
|
|
543
|
+
const { execFile: execFile2 } = await import("child_process");
|
|
544
|
+
const { promisify: promisify2 } = await import("util");
|
|
545
|
+
const execFileAsync = promisify2(execFile2);
|
|
546
|
+
if (sessionName.includes(":")) {
|
|
547
|
+
if (!workerPaneIds?.length) return;
|
|
548
|
+
for (const id of workerPaneIds) {
|
|
549
|
+
if (id === leaderPaneId) continue;
|
|
550
|
+
try {
|
|
551
|
+
await execFileAsync("tmux", ["kill-pane", "-t", id]);
|
|
552
|
+
} catch {
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
557
|
+
try {
|
|
558
|
+
await execFileAsync("tmux", ["kill-session", "-t", sessionName]);
|
|
559
|
+
} catch {
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
// src/team/worker-bootstrap.ts
|
|
564
|
+
var import_promises2 = require("fs/promises");
|
|
565
|
+
var import_path4 = require("path");
|
|
566
|
+
|
|
567
|
+
// src/agents/prompt-helpers.ts
|
|
568
|
+
var import_fs2 = require("fs");
|
|
569
|
+
var import_path3 = require("path");
|
|
570
|
+
var import_url2 = require("url");
|
|
571
|
+
|
|
572
|
+
// src/agents/utils.ts
|
|
573
|
+
var import_fs = require("fs");
|
|
574
|
+
var import_path2 = require("path");
|
|
575
|
+
var import_url = require("url");
|
|
576
|
+
|
|
577
|
+
// src/agents/prompt-helpers.ts
|
|
578
|
+
var import_meta = {};
|
|
579
|
+
function getPackageDir() {
|
|
580
|
+
try {
|
|
581
|
+
if (import_meta?.url) {
|
|
582
|
+
const __filename = (0, import_url2.fileURLToPath)(import_meta.url);
|
|
583
|
+
const __dirname2 = (0, import_path3.dirname)(__filename);
|
|
584
|
+
return (0, import_path3.join)(__dirname2, "..", "..");
|
|
585
|
+
}
|
|
586
|
+
} catch {
|
|
587
|
+
}
|
|
588
|
+
if (typeof __dirname !== "undefined") {
|
|
589
|
+
return (0, import_path3.join)(__dirname, "..");
|
|
590
|
+
}
|
|
591
|
+
return process.cwd();
|
|
592
|
+
}
|
|
593
|
+
var _cachedRoles = null;
|
|
594
|
+
function getValidAgentRoles() {
|
|
595
|
+
if (_cachedRoles) return _cachedRoles;
|
|
596
|
+
try {
|
|
597
|
+
if (typeof __AGENT_ROLES__ !== "undefined" && Array.isArray(__AGENT_ROLES__) && __AGENT_ROLES__.length > 0) {
|
|
598
|
+
_cachedRoles = __AGENT_ROLES__;
|
|
599
|
+
return _cachedRoles;
|
|
600
|
+
}
|
|
601
|
+
} catch {
|
|
602
|
+
}
|
|
603
|
+
try {
|
|
604
|
+
const agentsDir = (0, import_path3.join)(getPackageDir(), "agents");
|
|
605
|
+
const files = (0, import_fs2.readdirSync)(agentsDir);
|
|
606
|
+
_cachedRoles = files.filter((f) => f.endsWith(".md")).map((f) => (0, import_path3.basename)(f, ".md")).sort();
|
|
607
|
+
} catch (err) {
|
|
608
|
+
console.error("[prompt-injection] CRITICAL: Could not scan agents/ directory for role discovery:", err);
|
|
609
|
+
_cachedRoles = [];
|
|
610
|
+
}
|
|
611
|
+
return _cachedRoles;
|
|
612
|
+
}
|
|
613
|
+
var VALID_AGENT_ROLES = getValidAgentRoles();
|
|
614
|
+
function sanitizePromptContent(content, maxLength = 4e3) {
|
|
615
|
+
if (!content) return "";
|
|
616
|
+
let sanitized = content.length > maxLength ? content.slice(0, maxLength) : content;
|
|
617
|
+
if (sanitized.length > 0) {
|
|
618
|
+
const lastCode = sanitized.charCodeAt(sanitized.length - 1);
|
|
619
|
+
if (lastCode >= 55296 && lastCode <= 56319) {
|
|
620
|
+
sanitized = sanitized.slice(0, -1);
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
sanitized = sanitized.replace(/<(\/?)(TASK_SUBJECT)[^>]*>/gi, "[$1$2]");
|
|
624
|
+
sanitized = sanitized.replace(/<(\/?)(TASK_DESCRIPTION)[^>]*>/gi, "[$1$2]");
|
|
625
|
+
sanitized = sanitized.replace(/<(\/?)(INBOX_MESSAGE)[^>]*>/gi, "[$1$2]");
|
|
626
|
+
sanitized = sanitized.replace(/<(\/?)(INSTRUCTIONS)[^>]*>/gi, "[$1$2]");
|
|
627
|
+
sanitized = sanitized.replace(/<(\/?)(SYSTEM)[^>]*>/gi, "[$1$2]");
|
|
628
|
+
return sanitized;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
// src/team/worker-bootstrap.ts
|
|
632
|
+
function generateWorkerOverlay(params) {
|
|
633
|
+
const { teamName, workerName: workerName2, agentType, tasks, bootstrapInstructions } = params;
|
|
634
|
+
const sanitizedTasks = tasks.map((t) => ({
|
|
635
|
+
id: t.id,
|
|
636
|
+
subject: sanitizePromptContent(t.subject),
|
|
637
|
+
description: sanitizePromptContent(t.description)
|
|
638
|
+
}));
|
|
639
|
+
const sentinelPath = `.omc/state/team/${teamName}/workers/${workerName2}/.ready`;
|
|
640
|
+
const heartbeatPath = `.omc/state/team/${teamName}/workers/${workerName2}/heartbeat.json`;
|
|
641
|
+
const inboxPath = `.omc/state/team/${teamName}/workers/${workerName2}/inbox.md`;
|
|
642
|
+
const taskDir = `.omc/state/team/${teamName}/tasks`;
|
|
643
|
+
const donePath = `.omc/state/team/${teamName}/workers/${workerName2}/done.json`;
|
|
644
|
+
const taskList = sanitizedTasks.length > 0 ? sanitizedTasks.map((t) => `- **Task ${t.id}**: ${t.subject}`).join("\n") : "- No tasks assigned yet. Check your inbox for assignments.";
|
|
645
|
+
return `# Team Worker Protocol
|
|
646
|
+
|
|
647
|
+
## FIRST ACTION REQUIRED
|
|
648
|
+
Before doing anything else, write your ready sentinel file:
|
|
649
|
+
\`\`\`bash
|
|
650
|
+
mkdir -p $(dirname ${sentinelPath}) && touch ${sentinelPath}
|
|
651
|
+
\`\`\`
|
|
652
|
+
|
|
653
|
+
## Identity
|
|
654
|
+
- **Team**: ${teamName}
|
|
655
|
+
- **Worker**: ${workerName2}
|
|
656
|
+
- **Agent Type**: ${agentType}
|
|
657
|
+
- **Environment**: OMC_TEAM_WORKER=${teamName}/${workerName2}
|
|
658
|
+
|
|
659
|
+
## Your Tasks
|
|
660
|
+
${taskList}
|
|
661
|
+
|
|
662
|
+
## Task Claiming Protocol
|
|
663
|
+
To claim a task, update the task file atomically:
|
|
664
|
+
1. Read task from: ${taskDir}/{taskId}.json
|
|
665
|
+
2. Update status to "in_progress", set owner to "${workerName2}"
|
|
666
|
+
3. Write back to task file
|
|
667
|
+
4. Do the work
|
|
668
|
+
5. Update status to "completed", write result to task file
|
|
669
|
+
|
|
670
|
+
## Communication Protocol
|
|
671
|
+
- **Inbox**: Read ${inboxPath} for new instructions
|
|
672
|
+
- **Heartbeat**: Update ${heartbeatPath} every few minutes:
|
|
673
|
+
\`\`\`json
|
|
674
|
+
{"workerName":"${workerName2}","status":"working","updatedAt":"<ISO timestamp>","currentTaskId":"<id or null>"}
|
|
675
|
+
\`\`\`
|
|
676
|
+
|
|
677
|
+
## Task Completion Protocol
|
|
678
|
+
When you finish a task (success or failure), write a done signal file:
|
|
679
|
+
- Path: ${donePath}
|
|
680
|
+
- Content (JSON, one line):
|
|
681
|
+
{"taskId":"<id>","status":"completed","summary":"<1-2 sentence summary>","completedAt":"<ISO timestamp>"}
|
|
682
|
+
- For failures, set status to "failed" and include the error in summary.
|
|
683
|
+
- Use "completed" or "failed" only for status.
|
|
684
|
+
|
|
685
|
+
## Shutdown Protocol
|
|
686
|
+
When you see a shutdown request (check .omc/state/team/${teamName}/shutdown.json):
|
|
687
|
+
1. Finish your current task if close to completion
|
|
688
|
+
2. Write an ACK file: .omc/state/team/${teamName}/workers/${workerName2}/shutdown-ack.json
|
|
689
|
+
3. Exit
|
|
690
|
+
|
|
691
|
+
${bootstrapInstructions ? `## Additional Instructions
|
|
692
|
+
${bootstrapInstructions}
|
|
693
|
+
` : ""}`;
|
|
694
|
+
}
|
|
695
|
+
async function composeInitialInbox(teamName, workerName2, content, cwd) {
|
|
696
|
+
const inboxPath = (0, import_path4.join)(cwd, `.omc/state/team/${teamName}/workers/${workerName2}/inbox.md`);
|
|
697
|
+
await (0, import_promises2.mkdir)((0, import_path4.dirname)(inboxPath), { recursive: true });
|
|
698
|
+
await (0, import_promises2.writeFile)(inboxPath, content, "utf-8");
|
|
699
|
+
}
|
|
700
|
+
async function ensureWorkerStateDir(teamName, workerName2, cwd) {
|
|
701
|
+
const workerDir = (0, import_path4.join)(cwd, `.omc/state/team/${teamName}/workers/${workerName2}`);
|
|
702
|
+
await (0, import_promises2.mkdir)(workerDir, { recursive: true });
|
|
703
|
+
const mailboxDir = (0, import_path4.join)(cwd, `.omc/state/team/${teamName}/mailbox`);
|
|
704
|
+
await (0, import_promises2.mkdir)(mailboxDir, { recursive: true });
|
|
705
|
+
const tasksDir = (0, import_path4.join)(cwd, `.omc/state/team/${teamName}/tasks`);
|
|
706
|
+
await (0, import_promises2.mkdir)(tasksDir, { recursive: true });
|
|
707
|
+
}
|
|
708
|
+
async function writeWorkerOverlay(params) {
|
|
709
|
+
const { teamName, workerName: workerName2, cwd } = params;
|
|
710
|
+
const overlay = generateWorkerOverlay(params);
|
|
711
|
+
const overlayPath = (0, import_path4.join)(cwd, `.omc/state/team/${teamName}/workers/${workerName2}/AGENTS.md`);
|
|
712
|
+
await (0, import_promises2.mkdir)((0, import_path4.dirname)(overlayPath), { recursive: true });
|
|
713
|
+
await (0, import_promises2.writeFile)(overlayPath, overlay, "utf-8");
|
|
714
|
+
return overlayPath;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
// src/team/task-file-ops.ts
|
|
718
|
+
var import_fs5 = require("fs");
|
|
719
|
+
var import_path8 = require("path");
|
|
720
|
+
|
|
721
|
+
// src/utils/paths.ts
|
|
722
|
+
var import_path5 = require("path");
|
|
723
|
+
var import_fs3 = require("fs");
|
|
724
|
+
var import_os = require("os");
|
|
725
|
+
var STALE_THRESHOLD_MS = 24 * 60 * 60 * 1e3;
|
|
726
|
+
|
|
727
|
+
// src/team/fs-utils.ts
|
|
728
|
+
var import_fs4 = require("fs");
|
|
729
|
+
var import_path6 = require("path");
|
|
730
|
+
function ensureDirWithMode(dirPath, mode = 448) {
|
|
731
|
+
if (!(0, import_fs4.existsSync)(dirPath)) (0, import_fs4.mkdirSync)(dirPath, { recursive: true, mode });
|
|
732
|
+
}
|
|
733
|
+
function canonicalizePath(p) {
|
|
734
|
+
const absInput = (0, import_path6.resolve)(p);
|
|
735
|
+
const tail = [];
|
|
736
|
+
let probe = absInput;
|
|
737
|
+
while (true) {
|
|
738
|
+
try {
|
|
739
|
+
const realBase = (0, import_fs4.realpathSync)(probe);
|
|
740
|
+
return tail.reduce((acc, seg) => (0, import_path6.resolve)(acc, seg), realBase);
|
|
741
|
+
} catch {
|
|
742
|
+
const parent = (0, import_path6.dirname)(probe);
|
|
743
|
+
if (parent === probe) return absInput;
|
|
744
|
+
tail.unshift((0, import_path6.basename)(probe));
|
|
745
|
+
probe = parent;
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
function validateResolvedPath(resolvedPath, expectedBase) {
|
|
750
|
+
const absResolved = canonicalizePath(resolvedPath);
|
|
751
|
+
const absBase = canonicalizePath(expectedBase);
|
|
752
|
+
const rel = (0, import_path6.relative)(absBase, absResolved);
|
|
753
|
+
if (rel !== "" && (rel.startsWith("..") || (0, import_path6.isAbsolute)(rel) || (0, import_path6.resolve)(absBase, rel) !== absResolved)) {
|
|
754
|
+
throw new Error(`Path traversal detected: "${resolvedPath}" escapes base "${expectedBase}"`);
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
// src/team/state-paths.ts
|
|
759
|
+
var import_path7 = require("path");
|
|
760
|
+
var TeamPaths = {
|
|
761
|
+
root: (teamName) => `.omc/state/team/${teamName}`,
|
|
762
|
+
config: (teamName) => `.omc/state/team/${teamName}/config.json`,
|
|
763
|
+
shutdown: (teamName) => `.omc/state/team/${teamName}/shutdown.json`,
|
|
764
|
+
tasks: (teamName) => `.omc/state/team/${teamName}/tasks`,
|
|
765
|
+
taskFile: (teamName, taskId) => `.omc/state/team/${teamName}/tasks/${taskId}.json`,
|
|
766
|
+
workers: (teamName) => `.omc/state/team/${teamName}/workers`,
|
|
767
|
+
workerDir: (teamName, workerName2) => `.omc/state/team/${teamName}/workers/${workerName2}`,
|
|
768
|
+
heartbeat: (teamName, workerName2) => `.omc/state/team/${teamName}/workers/${workerName2}/heartbeat.json`,
|
|
769
|
+
inbox: (teamName, workerName2) => `.omc/state/team/${teamName}/workers/${workerName2}/inbox.md`,
|
|
770
|
+
outbox: (teamName, workerName2) => `.omc/state/team/${teamName}/workers/${workerName2}/outbox.jsonl`,
|
|
771
|
+
ready: (teamName, workerName2) => `.omc/state/team/${teamName}/workers/${workerName2}/.ready`,
|
|
772
|
+
overlay: (teamName, workerName2) => `.omc/state/team/${teamName}/workers/${workerName2}/AGENTS.md`,
|
|
773
|
+
shutdownAck: (teamName, workerName2) => `.omc/state/team/${teamName}/workers/${workerName2}/shutdown-ack.json`,
|
|
774
|
+
done: (teamName, workerName2) => `.omc/state/team/${teamName}/workers/${workerName2}/done.json`,
|
|
775
|
+
mailbox: (teamName, workerName2) => `.omc/state/team/${teamName}/mailbox/${workerName2}.jsonl`
|
|
776
|
+
};
|
|
777
|
+
function getTaskStoragePath(cwd, teamName, taskId) {
|
|
778
|
+
if (taskId !== void 0) {
|
|
779
|
+
return (0, import_path7.join)(cwd, TeamPaths.taskFile(teamName, taskId));
|
|
780
|
+
}
|
|
781
|
+
return (0, import_path7.join)(cwd, TeamPaths.tasks(teamName));
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
// src/team/task-file-ops.ts
|
|
785
|
+
var DEFAULT_STALE_LOCK_MS = 3e4;
|
|
786
|
+
function isPidAlive(pid) {
|
|
787
|
+
if (pid <= 0 || !Number.isFinite(pid)) return false;
|
|
788
|
+
try {
|
|
789
|
+
process.kill(pid, 0);
|
|
790
|
+
return true;
|
|
791
|
+
} catch (e) {
|
|
792
|
+
if (e && typeof e === "object" && "code" in e && e.code === "EPERM") return true;
|
|
793
|
+
return false;
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
function acquireTaskLock(teamName, taskId, opts) {
|
|
797
|
+
const staleLockMs = opts?.staleLockMs ?? DEFAULT_STALE_LOCK_MS;
|
|
798
|
+
const dir = canonicalTasksDir(teamName, opts?.cwd);
|
|
799
|
+
ensureDirWithMode(dir);
|
|
800
|
+
const lockPath = (0, import_path8.join)(dir, `${sanitizeTaskId(taskId)}.lock`);
|
|
801
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
802
|
+
try {
|
|
803
|
+
const fd = (0, import_fs5.openSync)(lockPath, import_fs5.constants.O_CREAT | import_fs5.constants.O_EXCL | import_fs5.constants.O_WRONLY, 384);
|
|
804
|
+
const payload = JSON.stringify({
|
|
805
|
+
pid: process.pid,
|
|
806
|
+
workerName: opts?.workerName ?? "",
|
|
807
|
+
timestamp: Date.now()
|
|
808
|
+
});
|
|
809
|
+
(0, import_fs5.writeSync)(fd, payload, null, "utf-8");
|
|
810
|
+
return { fd, path: lockPath };
|
|
811
|
+
} catch (err) {
|
|
812
|
+
if (err && typeof err === "object" && "code" in err && err.code === "EEXIST") {
|
|
813
|
+
if (attempt === 0 && isLockStale(lockPath, staleLockMs)) {
|
|
814
|
+
try {
|
|
815
|
+
(0, import_fs5.unlinkSync)(lockPath);
|
|
816
|
+
} catch {
|
|
817
|
+
}
|
|
818
|
+
continue;
|
|
819
|
+
}
|
|
820
|
+
return null;
|
|
821
|
+
}
|
|
822
|
+
throw err;
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
return null;
|
|
826
|
+
}
|
|
827
|
+
function releaseTaskLock(handle) {
|
|
828
|
+
try {
|
|
829
|
+
(0, import_fs5.closeSync)(handle.fd);
|
|
830
|
+
} catch {
|
|
831
|
+
}
|
|
832
|
+
try {
|
|
833
|
+
(0, import_fs5.unlinkSync)(handle.path);
|
|
834
|
+
} catch {
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
async function withTaskLock(teamName, taskId, fn, opts) {
|
|
838
|
+
const handle = acquireTaskLock(teamName, taskId, opts);
|
|
839
|
+
if (!handle) return null;
|
|
840
|
+
try {
|
|
841
|
+
return await fn();
|
|
842
|
+
} finally {
|
|
843
|
+
releaseTaskLock(handle);
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
function isLockStale(lockPath, staleLockMs) {
|
|
847
|
+
try {
|
|
848
|
+
const stat = (0, import_fs5.statSync)(lockPath);
|
|
849
|
+
const ageMs = Date.now() - stat.mtimeMs;
|
|
850
|
+
if (ageMs < staleLockMs) return false;
|
|
851
|
+
try {
|
|
852
|
+
const raw = (0, import_fs5.readFileSync)(lockPath, "utf-8");
|
|
853
|
+
const payload = JSON.parse(raw);
|
|
854
|
+
if (payload.pid && isPidAlive(payload.pid)) return false;
|
|
855
|
+
} catch {
|
|
856
|
+
}
|
|
857
|
+
return true;
|
|
858
|
+
} catch {
|
|
859
|
+
return false;
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
function sanitizeTaskId(taskId) {
|
|
863
|
+
if (!/^[A-Za-z0-9._-]+$/.test(taskId)) {
|
|
864
|
+
throw new Error(`Invalid task ID: "${taskId}" contains unsafe characters`);
|
|
865
|
+
}
|
|
866
|
+
return taskId;
|
|
867
|
+
}
|
|
868
|
+
function canonicalTasksDir(teamName, cwd) {
|
|
869
|
+
const root = cwd ?? process.cwd();
|
|
870
|
+
const dir = getTaskStoragePath(root, sanitizeName(teamName));
|
|
871
|
+
validateResolvedPath(dir, (0, import_path8.join)(root, ".omc", "state", "team"));
|
|
872
|
+
return dir;
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
// src/team/runtime.ts
|
|
876
|
+
function workerName(index) {
|
|
877
|
+
return `worker-${index + 1}`;
|
|
878
|
+
}
|
|
879
|
+
function stateRoot(cwd, teamName) {
|
|
880
|
+
validateTeamName(teamName);
|
|
881
|
+
return (0, import_path9.join)(cwd, `.omc/state/team/${teamName}`);
|
|
882
|
+
}
|
|
883
|
+
async function writeJson(filePath, data) {
|
|
884
|
+
await (0, import_promises3.mkdir)((0, import_path9.join)(filePath, ".."), { recursive: true });
|
|
885
|
+
await (0, import_promises3.writeFile)(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
886
|
+
}
|
|
887
|
+
async function readJsonSafe(filePath) {
|
|
888
|
+
try {
|
|
889
|
+
const content = await (0, import_promises3.readFile)(filePath, "utf-8");
|
|
890
|
+
return JSON.parse(content);
|
|
891
|
+
} catch {
|
|
892
|
+
return null;
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
function parseWorkerIndex(workerNameValue) {
|
|
896
|
+
const match = workerNameValue.match(/^worker-(\d+)$/);
|
|
897
|
+
if (!match) return 0;
|
|
898
|
+
const parsed = Number.parseInt(match[1], 10) - 1;
|
|
899
|
+
return Number.isFinite(parsed) && parsed >= 0 ? parsed : 0;
|
|
900
|
+
}
|
|
901
|
+
function taskPath(root, taskId) {
|
|
902
|
+
return (0, import_path9.join)(root, "tasks", `${taskId}.json`);
|
|
903
|
+
}
|
|
904
|
+
async function writePanesTrackingFileIfPresent(runtime) {
|
|
905
|
+
const jobId = process.env.OMC_JOB_ID;
|
|
906
|
+
const omcJobsDir = process.env.OMC_JOBS_DIR;
|
|
907
|
+
if (!jobId || !omcJobsDir) return;
|
|
908
|
+
const panesPath = (0, import_path9.join)(omcJobsDir, `${jobId}-panes.json`);
|
|
909
|
+
const tempPath = `${panesPath}.tmp`;
|
|
910
|
+
await (0, import_promises3.writeFile)(
|
|
911
|
+
tempPath,
|
|
912
|
+
JSON.stringify({ paneIds: [...runtime.workerPaneIds], leaderPaneId: runtime.leaderPaneId }),
|
|
913
|
+
"utf-8"
|
|
914
|
+
);
|
|
915
|
+
await (0, import_promises3.rename)(tempPath, panesPath);
|
|
916
|
+
}
|
|
917
|
+
async function readTask(root, taskId) {
|
|
918
|
+
return readJsonSafe(taskPath(root, taskId));
|
|
919
|
+
}
|
|
920
|
+
async function writeTask(root, task) {
|
|
921
|
+
await writeJson(taskPath(root, task.id), task);
|
|
922
|
+
}
|
|
923
|
+
async function markTaskInProgress(root, taskId, owner, teamName, cwd) {
|
|
924
|
+
const result = await withTaskLock(teamName, taskId, async () => {
|
|
925
|
+
const task = await readTask(root, taskId);
|
|
926
|
+
if (!task || task.status !== "pending") return false;
|
|
927
|
+
task.status = "in_progress";
|
|
928
|
+
task.owner = owner;
|
|
929
|
+
task.assignedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
930
|
+
await writeTask(root, task);
|
|
931
|
+
return true;
|
|
932
|
+
}, { cwd });
|
|
933
|
+
return result ?? false;
|
|
934
|
+
}
|
|
935
|
+
async function resetTaskToPending(root, taskId) {
|
|
936
|
+
const task = await readTask(root, taskId);
|
|
937
|
+
if (!task) return;
|
|
938
|
+
task.status = "pending";
|
|
939
|
+
task.owner = null;
|
|
940
|
+
task.assignedAt = void 0;
|
|
941
|
+
await writeTask(root, task);
|
|
942
|
+
}
|
|
943
|
+
async function markTaskFromDone(root, taskId, status, summary) {
|
|
944
|
+
const task = await readTask(root, taskId);
|
|
945
|
+
if (!task) return;
|
|
946
|
+
task.status = status;
|
|
947
|
+
task.result = summary;
|
|
948
|
+
task.summary = summary;
|
|
949
|
+
if (status === "completed") {
|
|
950
|
+
task.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
951
|
+
} else {
|
|
952
|
+
task.failedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
953
|
+
}
|
|
954
|
+
await writeTask(root, task);
|
|
955
|
+
}
|
|
956
|
+
async function markTaskFailedDeadPane(root, taskId, workerNameValue) {
|
|
957
|
+
const task = await readTask(root, taskId);
|
|
958
|
+
if (!task) return;
|
|
959
|
+
task.status = "failed";
|
|
960
|
+
task.owner = workerNameValue;
|
|
961
|
+
task.summary = `Worker pane died before done.json was written (${workerNameValue})`;
|
|
962
|
+
task.result = task.summary;
|
|
963
|
+
task.failedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
964
|
+
await writeTask(root, task);
|
|
965
|
+
}
|
|
966
|
+
async function nextPendingTaskIndex(runtime) {
|
|
967
|
+
const root = stateRoot(runtime.cwd, runtime.teamName);
|
|
968
|
+
for (let i = 0; i < runtime.config.tasks.length; i++) {
|
|
969
|
+
const task = await readTask(root, String(i + 1));
|
|
970
|
+
if (task?.status === "pending") return i;
|
|
971
|
+
}
|
|
972
|
+
return null;
|
|
973
|
+
}
|
|
974
|
+
async function notifyPaneWithRetry(sessionName, paneId, message, maxAttempts = 6, retryDelayMs = 350) {
|
|
975
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
976
|
+
if (await sendToWorker(sessionName, paneId, message)) {
|
|
977
|
+
return true;
|
|
978
|
+
}
|
|
979
|
+
if (attempt < maxAttempts) {
|
|
980
|
+
await new Promise((r) => setTimeout(r, retryDelayMs));
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
return false;
|
|
984
|
+
}
|
|
985
|
+
async function allTasksTerminal(runtime) {
|
|
986
|
+
const root = stateRoot(runtime.cwd, runtime.teamName);
|
|
987
|
+
for (let i = 0; i < runtime.config.tasks.length; i++) {
|
|
988
|
+
const task = await readTask(root, String(i + 1));
|
|
989
|
+
if (!task) return false;
|
|
990
|
+
if (task.status !== "completed" && task.status !== "failed") return false;
|
|
991
|
+
}
|
|
992
|
+
return true;
|
|
993
|
+
}
|
|
994
|
+
function buildInitialTaskInstruction(teamName, workerName2, task, taskId) {
|
|
995
|
+
const donePath = `.omc/state/team/${teamName}/workers/${workerName2}/done.json`;
|
|
996
|
+
return [
|
|
997
|
+
`## Initial Task Assignment`,
|
|
998
|
+
`Task ID: ${taskId}`,
|
|
999
|
+
`Worker: ${workerName2}`,
|
|
1000
|
+
`Subject: ${task.subject}`,
|
|
1001
|
+
``,
|
|
1002
|
+
task.description,
|
|
1003
|
+
``,
|
|
1004
|
+
`When complete, write done signal to ${donePath}:`,
|
|
1005
|
+
`{"taskId":"${taskId}","status":"completed","summary":"<brief summary>","completedAt":"<ISO timestamp>"}`,
|
|
1006
|
+
``,
|
|
1007
|
+
`IMPORTANT: Execute ONLY the task assigned to you in this inbox. After writing done.json, exit immediately. Do not read from the task directory or claim other tasks.`
|
|
1008
|
+
].join("\n");
|
|
1009
|
+
}
|
|
1010
|
+
async function startTeam(config) {
|
|
1011
|
+
const { teamName, agentTypes, tasks, cwd } = config;
|
|
1012
|
+
validateTeamName(teamName);
|
|
1013
|
+
for (const agentType of [...new Set(agentTypes)]) {
|
|
1014
|
+
validateCliAvailable(agentType);
|
|
1015
|
+
}
|
|
1016
|
+
const root = stateRoot(cwd, teamName);
|
|
1017
|
+
await (0, import_promises3.mkdir)((0, import_path9.join)(root, "tasks"), { recursive: true });
|
|
1018
|
+
await (0, import_promises3.mkdir)((0, import_path9.join)(root, "mailbox"), { recursive: true });
|
|
1019
|
+
await writeJson((0, import_path9.join)(root, "config.json"), config);
|
|
1020
|
+
for (let i = 0; i < tasks.length; i++) {
|
|
1021
|
+
const taskId = String(i + 1);
|
|
1022
|
+
await writeJson((0, import_path9.join)(root, "tasks", `${taskId}.json`), {
|
|
1023
|
+
id: taskId,
|
|
1024
|
+
subject: tasks[i].subject,
|
|
1025
|
+
description: tasks[i].description,
|
|
1026
|
+
status: "pending",
|
|
1027
|
+
owner: null,
|
|
1028
|
+
result: null,
|
|
1029
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1030
|
+
});
|
|
1031
|
+
}
|
|
1032
|
+
const workerNames = [];
|
|
1033
|
+
for (let i = 0; i < tasks.length; i++) {
|
|
1034
|
+
const wName = workerName(i);
|
|
1035
|
+
workerNames.push(wName);
|
|
1036
|
+
const agentType = agentTypes[i % agentTypes.length] ?? agentTypes[0] ?? "claude";
|
|
1037
|
+
await ensureWorkerStateDir(teamName, wName, cwd);
|
|
1038
|
+
await writeWorkerOverlay({
|
|
1039
|
+
teamName,
|
|
1040
|
+
workerName: wName,
|
|
1041
|
+
agentType,
|
|
1042
|
+
tasks: tasks.map((t, idx) => ({ id: String(idx + 1), subject: t.subject, description: t.description })),
|
|
1043
|
+
cwd
|
|
1044
|
+
});
|
|
1045
|
+
}
|
|
1046
|
+
const session = await createTeamSession(teamName, 0, cwd);
|
|
1047
|
+
const runtime = {
|
|
1048
|
+
teamName,
|
|
1049
|
+
sessionName: session.sessionName,
|
|
1050
|
+
leaderPaneId: session.leaderPaneId,
|
|
1051
|
+
config,
|
|
1052
|
+
workerNames,
|
|
1053
|
+
workerPaneIds: session.workerPaneIds,
|
|
1054
|
+
// initially empty []
|
|
1055
|
+
activeWorkers: /* @__PURE__ */ new Map(),
|
|
1056
|
+
cwd
|
|
1057
|
+
};
|
|
1058
|
+
const maxConcurrentWorkers = agentTypes.length;
|
|
1059
|
+
for (let i = 0; i < maxConcurrentWorkers; i++) {
|
|
1060
|
+
const taskIndex = await nextPendingTaskIndex(runtime);
|
|
1061
|
+
if (taskIndex == null) break;
|
|
1062
|
+
await spawnWorkerForTask(runtime, workerName(i), taskIndex);
|
|
1063
|
+
}
|
|
1064
|
+
runtime.stopWatchdog = watchdogCliWorkers(runtime, 1e3);
|
|
1065
|
+
return runtime;
|
|
1066
|
+
}
|
|
1067
|
+
async function monitorTeam(teamName, cwd, workerPaneIds) {
|
|
1068
|
+
validateTeamName(teamName);
|
|
1069
|
+
const monitorStartedAt = Date.now();
|
|
1070
|
+
const root = stateRoot(cwd, teamName);
|
|
1071
|
+
const taskScanStartedAt = Date.now();
|
|
1072
|
+
const taskCounts = { pending: 0, inProgress: 0, completed: 0, failed: 0 };
|
|
1073
|
+
try {
|
|
1074
|
+
const { readdir } = await import("fs/promises");
|
|
1075
|
+
const taskFiles = await readdir((0, import_path9.join)(root, "tasks"));
|
|
1076
|
+
for (const f of taskFiles.filter((f2) => f2.endsWith(".json"))) {
|
|
1077
|
+
const task = await readJsonSafe((0, import_path9.join)(root, "tasks", f));
|
|
1078
|
+
if (task?.status === "pending") taskCounts.pending++;
|
|
1079
|
+
else if (task?.status === "in_progress") taskCounts.inProgress++;
|
|
1080
|
+
else if (task?.status === "completed") taskCounts.completed++;
|
|
1081
|
+
else if (task?.status === "failed") taskCounts.failed++;
|
|
1082
|
+
}
|
|
1083
|
+
} catch {
|
|
1084
|
+
}
|
|
1085
|
+
const listTasksMs = Date.now() - taskScanStartedAt;
|
|
1086
|
+
const workerScanStartedAt = Date.now();
|
|
1087
|
+
const workers = [];
|
|
1088
|
+
const deadWorkers = [];
|
|
1089
|
+
for (let i = 0; i < workerPaneIds.length; i++) {
|
|
1090
|
+
const wName = `worker-${i + 1}`;
|
|
1091
|
+
const paneId = workerPaneIds[i];
|
|
1092
|
+
const alive = await isWorkerAlive(paneId);
|
|
1093
|
+
const heartbeatPath = (0, import_path9.join)(root, "workers", wName, "heartbeat.json");
|
|
1094
|
+
const heartbeat = await readJsonSafe(heartbeatPath);
|
|
1095
|
+
let stalled = false;
|
|
1096
|
+
if (heartbeat?.updatedAt) {
|
|
1097
|
+
const age = Date.now() - new Date(heartbeat.updatedAt).getTime();
|
|
1098
|
+
stalled = age > 6e4;
|
|
1099
|
+
}
|
|
1100
|
+
const status = {
|
|
1101
|
+
workerName: wName,
|
|
1102
|
+
alive,
|
|
1103
|
+
paneId,
|
|
1104
|
+
currentTaskId: heartbeat?.currentTaskId,
|
|
1105
|
+
lastHeartbeat: heartbeat?.updatedAt,
|
|
1106
|
+
stalled
|
|
1107
|
+
};
|
|
1108
|
+
workers.push(status);
|
|
1109
|
+
if (!alive) deadWorkers.push(wName);
|
|
1110
|
+
}
|
|
1111
|
+
const workerScanMs = Date.now() - workerScanStartedAt;
|
|
1112
|
+
let phase = "executing";
|
|
1113
|
+
if (taskCounts.inProgress === 0 && taskCounts.pending > 0 && taskCounts.completed === 0) {
|
|
1114
|
+
phase = "planning";
|
|
1115
|
+
} else if (taskCounts.failed > 0 && taskCounts.pending === 0 && taskCounts.inProgress === 0) {
|
|
1116
|
+
phase = "fixing";
|
|
1117
|
+
} else if (taskCounts.completed > 0 && taskCounts.pending === 0 && taskCounts.inProgress === 0 && taskCounts.failed === 0) {
|
|
1118
|
+
phase = "completed";
|
|
1119
|
+
}
|
|
1120
|
+
return {
|
|
1121
|
+
teamName,
|
|
1122
|
+
phase,
|
|
1123
|
+
workers,
|
|
1124
|
+
taskCounts,
|
|
1125
|
+
deadWorkers,
|
|
1126
|
+
monitorPerformance: {
|
|
1127
|
+
listTasksMs,
|
|
1128
|
+
workerScanMs,
|
|
1129
|
+
totalMs: Date.now() - monitorStartedAt
|
|
1130
|
+
}
|
|
1131
|
+
};
|
|
1132
|
+
}
|
|
1133
|
+
function watchdogCliWorkers(runtime, intervalMs) {
|
|
1134
|
+
let tickInFlight = false;
|
|
1135
|
+
let consecutiveFailures = 0;
|
|
1136
|
+
const MAX_CONSECUTIVE_FAILURES = 3;
|
|
1137
|
+
const unresponsiveCounts = /* @__PURE__ */ new Map();
|
|
1138
|
+
const UNRESPONSIVE_KILL_THRESHOLD = 3;
|
|
1139
|
+
const tick = async () => {
|
|
1140
|
+
if (tickInFlight) return;
|
|
1141
|
+
tickInFlight = true;
|
|
1142
|
+
try {
|
|
1143
|
+
const workers = [...runtime.activeWorkers.entries()];
|
|
1144
|
+
if (workers.length === 0) return;
|
|
1145
|
+
const root = stateRoot(runtime.cwd, runtime.teamName);
|
|
1146
|
+
const [doneSignals, aliveResults] = await Promise.all([
|
|
1147
|
+
Promise.all(workers.map(([wName]) => {
|
|
1148
|
+
const donePath = (0, import_path9.join)(root, "workers", wName, "done.json");
|
|
1149
|
+
return readJsonSafe(donePath);
|
|
1150
|
+
})),
|
|
1151
|
+
Promise.all(workers.map(([, active]) => isWorkerAlive(active.paneId)))
|
|
1152
|
+
]);
|
|
1153
|
+
for (let i = 0; i < workers.length; i++) {
|
|
1154
|
+
const [wName, active] = workers[i];
|
|
1155
|
+
const donePath = (0, import_path9.join)(root, "workers", wName, "done.json");
|
|
1156
|
+
const signal = doneSignals[i];
|
|
1157
|
+
if (signal) {
|
|
1158
|
+
unresponsiveCounts.delete(wName);
|
|
1159
|
+
await markTaskFromDone(root, signal.taskId || active.taskId, signal.status, signal.summary);
|
|
1160
|
+
try {
|
|
1161
|
+
const { unlink } = await import("fs/promises");
|
|
1162
|
+
await unlink(donePath);
|
|
1163
|
+
} catch {
|
|
1164
|
+
}
|
|
1165
|
+
await killWorkerPane(runtime, wName, active.paneId);
|
|
1166
|
+
if (!await allTasksTerminal(runtime)) {
|
|
1167
|
+
const nextTaskIndexValue = await nextPendingTaskIndex(runtime);
|
|
1168
|
+
if (nextTaskIndexValue != null) {
|
|
1169
|
+
await spawnWorkerForTask(runtime, wName, nextTaskIndexValue);
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
continue;
|
|
1173
|
+
}
|
|
1174
|
+
const alive = aliveResults[i];
|
|
1175
|
+
if (!alive) {
|
|
1176
|
+
unresponsiveCounts.delete(wName);
|
|
1177
|
+
await markTaskFailedDeadPane(root, active.taskId, wName);
|
|
1178
|
+
await killWorkerPane(runtime, wName, active.paneId);
|
|
1179
|
+
if (!await allTasksTerminal(runtime)) {
|
|
1180
|
+
const nextTaskIndexValue = await nextPendingTaskIndex(runtime);
|
|
1181
|
+
if (nextTaskIndexValue != null) {
|
|
1182
|
+
await spawnWorkerForTask(runtime, wName, nextTaskIndexValue);
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
continue;
|
|
1186
|
+
}
|
|
1187
|
+
const heartbeatPath = (0, import_path9.join)(root, "workers", wName, "heartbeat.json");
|
|
1188
|
+
const heartbeat = await readJsonSafe(heartbeatPath);
|
|
1189
|
+
const isStalled = heartbeat?.updatedAt ? Date.now() - new Date(heartbeat.updatedAt).getTime() > 6e4 : false;
|
|
1190
|
+
if (isStalled) {
|
|
1191
|
+
const count = (unresponsiveCounts.get(wName) ?? 0) + 1;
|
|
1192
|
+
unresponsiveCounts.set(wName, count);
|
|
1193
|
+
if (count < UNRESPONSIVE_KILL_THRESHOLD) {
|
|
1194
|
+
console.warn(`[watchdog] worker ${wName} unresponsive (${count}/${UNRESPONSIVE_KILL_THRESHOLD}), task ${active.taskId}`);
|
|
1195
|
+
} else {
|
|
1196
|
+
console.warn(`[watchdog] worker ${wName} unresponsive ${count} consecutive ticks \u2014 killing and reassigning task ${active.taskId}`);
|
|
1197
|
+
unresponsiveCounts.delete(wName);
|
|
1198
|
+
await markTaskFailedDeadPane(root, active.taskId, wName);
|
|
1199
|
+
await killWorkerPane(runtime, wName, active.paneId);
|
|
1200
|
+
if (!await allTasksTerminal(runtime)) {
|
|
1201
|
+
const nextTaskIndexValue = await nextPendingTaskIndex(runtime);
|
|
1202
|
+
if (nextTaskIndexValue != null) {
|
|
1203
|
+
await spawnWorkerForTask(runtime, wName, nextTaskIndexValue);
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
} else {
|
|
1208
|
+
unresponsiveCounts.delete(wName);
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
consecutiveFailures = 0;
|
|
1212
|
+
} catch (err) {
|
|
1213
|
+
consecutiveFailures++;
|
|
1214
|
+
console.warn("[watchdog] tick error:", err);
|
|
1215
|
+
if (consecutiveFailures >= MAX_CONSECUTIVE_FAILURES) {
|
|
1216
|
+
console.warn(`[watchdog] ${consecutiveFailures} consecutive failures \u2014 marking team as failed`);
|
|
1217
|
+
try {
|
|
1218
|
+
const root = stateRoot(runtime.cwd, runtime.teamName);
|
|
1219
|
+
await writeJson((0, import_path9.join)(root, "watchdog-failed.json"), {
|
|
1220
|
+
failedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1221
|
+
consecutiveFailures,
|
|
1222
|
+
lastError: err instanceof Error ? err.message : String(err)
|
|
1223
|
+
});
|
|
1224
|
+
} catch {
|
|
1225
|
+
}
|
|
1226
|
+
clearInterval(intervalId);
|
|
1227
|
+
}
|
|
1228
|
+
} finally {
|
|
1229
|
+
tickInFlight = false;
|
|
1230
|
+
}
|
|
1231
|
+
};
|
|
1232
|
+
const intervalId = setInterval(() => {
|
|
1233
|
+
tick();
|
|
1234
|
+
}, intervalMs);
|
|
1235
|
+
return () => clearInterval(intervalId);
|
|
1236
|
+
}
|
|
1237
|
+
async function spawnWorkerForTask(runtime, workerNameValue, taskIndex) {
|
|
1238
|
+
const root = stateRoot(runtime.cwd, runtime.teamName);
|
|
1239
|
+
const taskId = String(taskIndex + 1);
|
|
1240
|
+
const task = runtime.config.tasks[taskIndex];
|
|
1241
|
+
if (!task) return "";
|
|
1242
|
+
const marked = await markTaskInProgress(root, taskId, workerNameValue, runtime.teamName, runtime.cwd);
|
|
1243
|
+
if (!marked) return "";
|
|
1244
|
+
const { execFile: execFile2 } = await import("child_process");
|
|
1245
|
+
const { promisify: promisify2 } = await import("util");
|
|
1246
|
+
const execFileAsync = promisify2(execFile2);
|
|
1247
|
+
const splitTarget = runtime.workerPaneIds.length === 0 ? runtime.leaderPaneId : runtime.workerPaneIds[runtime.workerPaneIds.length - 1];
|
|
1248
|
+
const splitType = runtime.workerPaneIds.length === 0 ? "-h" : "-v";
|
|
1249
|
+
const splitResult = await execFileAsync("tmux", [
|
|
1250
|
+
"split-window",
|
|
1251
|
+
splitType,
|
|
1252
|
+
"-t",
|
|
1253
|
+
splitTarget,
|
|
1254
|
+
"-d",
|
|
1255
|
+
"-P",
|
|
1256
|
+
"-F",
|
|
1257
|
+
"#{pane_id}",
|
|
1258
|
+
"-c",
|
|
1259
|
+
runtime.cwd
|
|
1260
|
+
]);
|
|
1261
|
+
const paneId = splitResult.stdout.split("\n")[0]?.trim();
|
|
1262
|
+
if (!paneId) return "";
|
|
1263
|
+
const workerIndex = parseWorkerIndex(workerNameValue);
|
|
1264
|
+
const agentType = runtime.config.agentTypes[workerIndex % runtime.config.agentTypes.length] ?? runtime.config.agentTypes[0] ?? "claude";
|
|
1265
|
+
const usePromptMode = isPromptModeAgent(agentType);
|
|
1266
|
+
const instruction = buildInitialTaskInstruction(runtime.teamName, workerNameValue, task, taskId);
|
|
1267
|
+
await composeInitialInbox(runtime.teamName, workerNameValue, instruction, runtime.cwd);
|
|
1268
|
+
const relInboxPath = `.omc/state/team/${runtime.teamName}/workers/${workerNameValue}/inbox.md`;
|
|
1269
|
+
const envVars = getWorkerEnv(runtime.teamName, workerNameValue, agentType);
|
|
1270
|
+
const [launchBinary, ...launchArgs] = buildWorkerArgv(agentType, {
|
|
1271
|
+
teamName: runtime.teamName,
|
|
1272
|
+
workerName: workerNameValue,
|
|
1273
|
+
cwd: runtime.cwd
|
|
1274
|
+
});
|
|
1275
|
+
if (usePromptMode) {
|
|
1276
|
+
const promptArgs = getPromptModeArgs(agentType, `Read and execute your task from: ${relInboxPath}`);
|
|
1277
|
+
launchArgs.push(...promptArgs);
|
|
1278
|
+
}
|
|
1279
|
+
const paneConfig = {
|
|
1280
|
+
teamName: runtime.teamName,
|
|
1281
|
+
workerName: workerNameValue,
|
|
1282
|
+
envVars,
|
|
1283
|
+
launchBinary,
|
|
1284
|
+
launchArgs,
|
|
1285
|
+
cwd: runtime.cwd
|
|
1286
|
+
};
|
|
1287
|
+
await spawnWorkerInPane(runtime.sessionName, paneId, paneConfig);
|
|
1288
|
+
runtime.workerPaneIds.push(paneId);
|
|
1289
|
+
runtime.activeWorkers.set(workerNameValue, { paneId, taskId, spawnedAt: Date.now() });
|
|
1290
|
+
try {
|
|
1291
|
+
await execFileAsync("tmux", ["select-layout", "-t", runtime.sessionName, "main-vertical"]);
|
|
1292
|
+
} catch {
|
|
1293
|
+
}
|
|
1294
|
+
try {
|
|
1295
|
+
await writePanesTrackingFileIfPresent(runtime);
|
|
1296
|
+
} catch {
|
|
1297
|
+
}
|
|
1298
|
+
if (!usePromptMode) {
|
|
1299
|
+
await new Promise((r) => setTimeout(r, 4e3));
|
|
1300
|
+
if (agentType === "gemini") {
|
|
1301
|
+
const confirmed = await notifyPaneWithRetry(runtime.sessionName, paneId, "1");
|
|
1302
|
+
if (!confirmed) {
|
|
1303
|
+
await killWorkerPane(runtime, workerNameValue, paneId);
|
|
1304
|
+
await resetTaskToPending(root, taskId);
|
|
1305
|
+
throw new Error(`worker_notify_failed:${workerNameValue}:trust-confirm`);
|
|
1306
|
+
}
|
|
1307
|
+
await new Promise((r) => setTimeout(r, 800));
|
|
1308
|
+
}
|
|
1309
|
+
const notified = await notifyPaneWithRetry(
|
|
1310
|
+
runtime.sessionName,
|
|
1311
|
+
paneId,
|
|
1312
|
+
`Read and execute your task from: ${relInboxPath}`
|
|
1313
|
+
);
|
|
1314
|
+
if (!notified) {
|
|
1315
|
+
await killWorkerPane(runtime, workerNameValue, paneId);
|
|
1316
|
+
await resetTaskToPending(root, taskId);
|
|
1317
|
+
throw new Error(`worker_notify_failed:${workerNameValue}:initial-inbox`);
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
return paneId;
|
|
1321
|
+
}
|
|
1322
|
+
async function killWorkerPane(runtime, workerNameValue, paneId) {
|
|
1323
|
+
try {
|
|
1324
|
+
const { execFile: execFile2 } = await import("child_process");
|
|
1325
|
+
const { promisify: promisify2 } = await import("util");
|
|
1326
|
+
const execFileAsync = promisify2(execFile2);
|
|
1327
|
+
await execFileAsync("tmux", ["kill-pane", "-t", paneId]);
|
|
1328
|
+
} catch {
|
|
1329
|
+
}
|
|
1330
|
+
const paneIndex = runtime.workerPaneIds.indexOf(paneId);
|
|
1331
|
+
if (paneIndex >= 0) {
|
|
1332
|
+
runtime.workerPaneIds.splice(paneIndex, 1);
|
|
1333
|
+
}
|
|
1334
|
+
runtime.activeWorkers.delete(workerNameValue);
|
|
1335
|
+
try {
|
|
1336
|
+
await writePanesTrackingFileIfPresent(runtime);
|
|
1337
|
+
} catch {
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
async function shutdownTeam(teamName, sessionName, cwd, timeoutMs = 3e4, workerPaneIds, leaderPaneId) {
|
|
1341
|
+
const root = stateRoot(cwd, teamName);
|
|
1342
|
+
await writeJson((0, import_path9.join)(root, "shutdown.json"), {
|
|
1343
|
+
requestedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1344
|
+
teamName
|
|
1345
|
+
});
|
|
1346
|
+
const configData = await readJsonSafe((0, import_path9.join)(root, "config.json"));
|
|
1347
|
+
const CLI_AGENT_TYPES = /* @__PURE__ */ new Set(["claude", "codex", "gemini"]);
|
|
1348
|
+
const agentTypes = configData?.agentTypes ?? [];
|
|
1349
|
+
const isCliWorkerTeam = agentTypes.length > 0 && agentTypes.every((t) => CLI_AGENT_TYPES.has(t));
|
|
1350
|
+
if (!isCliWorkerTeam) {
|
|
1351
|
+
const deadline = Date.now() + timeoutMs;
|
|
1352
|
+
const workerCount = configData?.workerCount ?? 0;
|
|
1353
|
+
const expectedAcks = Array.from({ length: workerCount }, (_, i) => `worker-${i + 1}`);
|
|
1354
|
+
while (Date.now() < deadline && expectedAcks.length > 0) {
|
|
1355
|
+
for (const wName of [...expectedAcks]) {
|
|
1356
|
+
const ackPath = (0, import_path9.join)(root, "workers", wName, "shutdown-ack.json");
|
|
1357
|
+
if ((0, import_fs6.existsSync)(ackPath)) {
|
|
1358
|
+
expectedAcks.splice(expectedAcks.indexOf(wName), 1);
|
|
1359
|
+
}
|
|
1360
|
+
}
|
|
1361
|
+
if (expectedAcks.length > 0) {
|
|
1362
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1366
|
+
await killTeamSession(sessionName, workerPaneIds, leaderPaneId);
|
|
1367
|
+
try {
|
|
1368
|
+
await (0, import_promises3.rm)(root, { recursive: true, force: true });
|
|
1369
|
+
} catch {
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1373
|
+
// src/team/runtime-cli.ts
|
|
1374
|
+
async function writePanesFile(jobId, paneIds, leaderPaneId) {
|
|
1375
|
+
const omcJobsDir = process.env.OMC_JOBS_DIR;
|
|
1376
|
+
if (!jobId || !omcJobsDir) return;
|
|
1377
|
+
const panesPath = (0, import_path10.join)(omcJobsDir, `${jobId}-panes.json`);
|
|
1378
|
+
await (0, import_promises4.writeFile)(
|
|
1379
|
+
panesPath + ".tmp",
|
|
1380
|
+
JSON.stringify({ paneIds: [...paneIds], leaderPaneId })
|
|
1381
|
+
);
|
|
1382
|
+
await (0, import_promises4.rename)(panesPath + ".tmp", panesPath);
|
|
1383
|
+
}
|
|
1384
|
+
function collectTaskResults(stateRoot2) {
|
|
1385
|
+
const tasksDir = (0, import_path10.join)(stateRoot2, "tasks");
|
|
1386
|
+
try {
|
|
1387
|
+
const files = (0, import_fs7.readdirSync)(tasksDir).filter((f) => f.endsWith(".json"));
|
|
1388
|
+
return files.map((f) => {
|
|
1389
|
+
try {
|
|
1390
|
+
const raw = (0, import_fs7.readFileSync)((0, import_path10.join)(tasksDir, f), "utf-8");
|
|
1391
|
+
const task = JSON.parse(raw);
|
|
1392
|
+
return {
|
|
1393
|
+
taskId: task.id ?? f.replace(".json", ""),
|
|
1394
|
+
status: task.status ?? "unknown",
|
|
1395
|
+
summary: task.result ?? task.summary ?? ""
|
|
1396
|
+
};
|
|
1397
|
+
} catch {
|
|
1398
|
+
return { taskId: f.replace(".json", ""), status: "unknown", summary: "" };
|
|
1399
|
+
}
|
|
1400
|
+
});
|
|
1401
|
+
} catch {
|
|
1402
|
+
return [];
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1405
|
+
async function main() {
|
|
1406
|
+
const startTime = Date.now();
|
|
1407
|
+
const chunks = [];
|
|
1408
|
+
for await (const chunk of process.stdin) {
|
|
1409
|
+
chunks.push(chunk);
|
|
1410
|
+
}
|
|
1411
|
+
const rawInput = Buffer.concat(chunks).toString("utf-8").trim();
|
|
1412
|
+
let input;
|
|
1413
|
+
try {
|
|
1414
|
+
input = JSON.parse(rawInput);
|
|
1415
|
+
} catch (err) {
|
|
1416
|
+
process.stderr.write(`[runtime-cli] Failed to parse stdin JSON: ${err}
|
|
1417
|
+
`);
|
|
1418
|
+
process.exit(1);
|
|
1419
|
+
}
|
|
1420
|
+
const missing = [];
|
|
1421
|
+
if (!input.teamName) missing.push("teamName");
|
|
1422
|
+
if (!input.agentTypes || !Array.isArray(input.agentTypes) || input.agentTypes.length === 0) missing.push("agentTypes");
|
|
1423
|
+
if (!input.tasks || !Array.isArray(input.tasks) || input.tasks.length === 0) missing.push("tasks");
|
|
1424
|
+
if (!input.cwd) missing.push("cwd");
|
|
1425
|
+
if (missing.length > 0) {
|
|
1426
|
+
process.stderr.write(`[runtime-cli] Missing required fields: ${missing.join(", ")}
|
|
1427
|
+
`);
|
|
1428
|
+
process.exit(1);
|
|
1429
|
+
}
|
|
1430
|
+
const {
|
|
1431
|
+
teamName,
|
|
1432
|
+
agentTypes,
|
|
1433
|
+
tasks,
|
|
1434
|
+
cwd,
|
|
1435
|
+
pollIntervalMs = 5e3
|
|
1436
|
+
} = input;
|
|
1437
|
+
const workerCount = input.workerCount ?? agentTypes.length;
|
|
1438
|
+
const stateRoot2 = (0, import_path10.join)(cwd, `.omc/state/team/${teamName}`);
|
|
1439
|
+
const config = {
|
|
1440
|
+
teamName,
|
|
1441
|
+
workerCount,
|
|
1442
|
+
agentTypes,
|
|
1443
|
+
tasks,
|
|
1444
|
+
cwd
|
|
1445
|
+
};
|
|
1446
|
+
let runtime = null;
|
|
1447
|
+
let finalStatus = "failed";
|
|
1448
|
+
let pollActive = true;
|
|
1449
|
+
function exitCodeFor(status) {
|
|
1450
|
+
return status === "completed" ? 0 : 1;
|
|
1451
|
+
}
|
|
1452
|
+
async function doShutdown(status) {
|
|
1453
|
+
pollActive = false;
|
|
1454
|
+
finalStatus = status;
|
|
1455
|
+
if (runtime?.stopWatchdog) {
|
|
1456
|
+
runtime.stopWatchdog();
|
|
1457
|
+
}
|
|
1458
|
+
const taskResults = collectTaskResults(stateRoot2);
|
|
1459
|
+
if (runtime) {
|
|
1460
|
+
try {
|
|
1461
|
+
await shutdownTeam(
|
|
1462
|
+
runtime.teamName,
|
|
1463
|
+
runtime.sessionName,
|
|
1464
|
+
runtime.cwd,
|
|
1465
|
+
2e3,
|
|
1466
|
+
runtime.workerPaneIds,
|
|
1467
|
+
runtime.leaderPaneId
|
|
1468
|
+
);
|
|
1469
|
+
} catch (err) {
|
|
1470
|
+
process.stderr.write(`[runtime-cli] shutdownTeam error: ${err}
|
|
1471
|
+
`);
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1474
|
+
const duration = (Date.now() - startTime) / 1e3;
|
|
1475
|
+
const output = {
|
|
1476
|
+
status: finalStatus,
|
|
1477
|
+
teamName,
|
|
1478
|
+
taskResults,
|
|
1479
|
+
duration,
|
|
1480
|
+
workerCount
|
|
1481
|
+
};
|
|
1482
|
+
process.stdout.write(JSON.stringify(output) + "\n");
|
|
1483
|
+
process.exit(exitCodeFor(status));
|
|
1484
|
+
}
|
|
1485
|
+
process.on("SIGINT", () => {
|
|
1486
|
+
process.stderr.write("[runtime-cli] Received SIGINT, shutting down...\n");
|
|
1487
|
+
doShutdown("failed").catch(() => process.exit(1));
|
|
1488
|
+
});
|
|
1489
|
+
process.on("SIGTERM", () => {
|
|
1490
|
+
process.stderr.write("[runtime-cli] Received SIGTERM, shutting down...\n");
|
|
1491
|
+
doShutdown("failed").catch(() => process.exit(1));
|
|
1492
|
+
});
|
|
1493
|
+
try {
|
|
1494
|
+
runtime = await startTeam(config);
|
|
1495
|
+
} catch (err) {
|
|
1496
|
+
process.stderr.write(`[runtime-cli] startTeam failed: ${err}
|
|
1497
|
+
`);
|
|
1498
|
+
process.exit(1);
|
|
1499
|
+
}
|
|
1500
|
+
const jobId = process.env.OMC_JOB_ID;
|
|
1501
|
+
try {
|
|
1502
|
+
await writePanesFile(jobId, runtime.workerPaneIds, runtime.leaderPaneId);
|
|
1503
|
+
} catch (err) {
|
|
1504
|
+
process.stderr.write(`[runtime-cli] Failed to persist pane IDs: ${err}
|
|
1505
|
+
`);
|
|
1506
|
+
}
|
|
1507
|
+
while (pollActive) {
|
|
1508
|
+
await new Promise((r) => setTimeout(r, pollIntervalMs));
|
|
1509
|
+
if (!pollActive) break;
|
|
1510
|
+
let snap;
|
|
1511
|
+
try {
|
|
1512
|
+
snap = await monitorTeam(teamName, cwd, runtime.workerPaneIds);
|
|
1513
|
+
} catch (err) {
|
|
1514
|
+
process.stderr.write(`[runtime-cli] monitorTeam error: ${err}
|
|
1515
|
+
`);
|
|
1516
|
+
continue;
|
|
1517
|
+
}
|
|
1518
|
+
try {
|
|
1519
|
+
await writePanesFile(jobId, runtime.workerPaneIds, runtime.leaderPaneId);
|
|
1520
|
+
} catch (err) {
|
|
1521
|
+
process.stderr.write(`[runtime-cli] Failed to persist pane IDs: ${err}
|
|
1522
|
+
`);
|
|
1523
|
+
}
|
|
1524
|
+
process.stderr.write(
|
|
1525
|
+
`[runtime-cli] phase=${snap.phase} pending=${snap.taskCounts.pending} inProgress=${snap.taskCounts.inProgress} completed=${snap.taskCounts.completed} failed=${snap.taskCounts.failed} dead=${snap.deadWorkers.length} monitorMs=${snap.monitorPerformance.totalMs} tasksMs=${snap.monitorPerformance.listTasksMs} workerMs=${snap.monitorPerformance.workerScanMs}
|
|
1526
|
+
`
|
|
1527
|
+
);
|
|
1528
|
+
if (snap.phase === "completed") {
|
|
1529
|
+
await doShutdown("completed");
|
|
1530
|
+
return;
|
|
1531
|
+
}
|
|
1532
|
+
const allWorkersDead = runtime.workerPaneIds.length > 0 && snap.deadWorkers.length === runtime.workerPaneIds.length;
|
|
1533
|
+
const hasOutstandingWork = snap.taskCounts.pending + snap.taskCounts.inProgress > 0;
|
|
1534
|
+
const deadWorkerFailure = allWorkersDead && hasOutstandingWork;
|
|
1535
|
+
const fixingWithNoWorkers = snap.phase === "fixing" && allWorkersDead;
|
|
1536
|
+
if (deadWorkerFailure || fixingWithNoWorkers) {
|
|
1537
|
+
process.stderr.write(`[runtime-cli] Failure detected: deadWorkerFailure=${deadWorkerFailure} fixingWithNoWorkers=${fixingWithNoWorkers}
|
|
1538
|
+
`);
|
|
1539
|
+
await doShutdown("failed");
|
|
1540
|
+
return;
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1544
|
+
if (require.main === module) {
|
|
1545
|
+
main().catch((err) => {
|
|
1546
|
+
process.stderr.write(`[runtime-cli] Fatal error: ${err}
|
|
1547
|
+
`);
|
|
1548
|
+
process.exit(1);
|
|
1549
|
+
});
|
|
1550
|
+
}
|