@ebowwa/coder 0.2.1 → 0.7.64
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/README.md +31 -32
- package/dist/core/__tests__/permissions.test.d.ts +12 -0
- package/dist/core/__tests__/permissions.test.d.ts.map +1 -0
- package/dist/core/__tests__/permissions.test.js +851 -0
- package/dist/core/agent-loop/__tests__/compaction.test.d.ts +5 -0
- package/dist/core/agent-loop/__tests__/compaction.test.d.ts.map +1 -0
- package/dist/core/agent-loop/__tests__/compaction.test.js +209 -0
- package/dist/core/agent-loop/__tests__/formatters.test.d.ts +5 -0
- package/dist/core/agent-loop/__tests__/formatters.test.d.ts.map +1 -0
- package/dist/core/agent-loop/__tests__/formatters.test.js +195 -0
- package/dist/core/agent-loop/__tests__/index.test.d.ts +5 -0
- package/dist/core/agent-loop/__tests__/index.test.d.ts.map +1 -0
- package/dist/core/agent-loop/__tests__/index.test.js +121 -0
- package/dist/core/agent-loop/__tests__/loop-state.test.d.ts +5 -0
- package/dist/core/agent-loop/__tests__/loop-state.test.d.ts.map +1 -0
- package/dist/core/agent-loop/__tests__/loop-state.test.js +340 -0
- package/dist/core/agent-loop/__tests__/message-builder.test.d.ts +5 -0
- package/dist/core/agent-loop/__tests__/message-builder.test.d.ts.map +1 -0
- package/dist/core/agent-loop/__tests__/message-builder.test.js +178 -0
- package/dist/core/agent-loop/__tests__/tool-executor.test.d.ts +5 -0
- package/dist/core/agent-loop/__tests__/tool-executor.test.d.ts.map +1 -0
- package/dist/core/agent-loop/__tests__/tool-executor.test.js +331 -0
- package/dist/core/agent-loop/compaction.d.ts +39 -0
- package/dist/core/agent-loop/compaction.d.ts.map +1 -0
- package/dist/core/agent-loop/compaction.js +51 -0
- package/dist/core/agent-loop/formatters.d.ts +21 -0
- package/dist/core/agent-loop/formatters.d.ts.map +1 -0
- package/dist/core/agent-loop/formatters.js +42 -0
- package/dist/core/agent-loop/index.d.ts +25 -0
- package/dist/core/agent-loop/index.d.ts.map +1 -0
- package/dist/core/agent-loop/index.js +83 -0
- package/dist/core/agent-loop/loop-state.d.ts +74 -0
- package/dist/core/agent-loop/loop-state.d.ts.map +1 -0
- package/dist/core/agent-loop/loop-state.js +147 -0
- package/dist/core/agent-loop/message-builder.d.ts +13 -0
- package/dist/core/agent-loop/message-builder.d.ts.map +1 -0
- package/dist/core/agent-loop/message-builder.js +49 -0
- package/dist/core/agent-loop/tool-executor.d.ts +23 -0
- package/dist/core/agent-loop/tool-executor.d.ts.map +1 -0
- package/dist/core/agent-loop/tool-executor.js +152 -0
- package/dist/core/agent-loop/turn-executor.d.ts +57 -0
- package/dist/core/agent-loop/turn-executor.d.ts.map +1 -0
- package/dist/core/agent-loop/turn-executor.js +124 -0
- package/dist/core/agent-loop/types.d.ts +141 -0
- package/dist/core/agent-loop/types.d.ts.map +1 -0
- package/dist/core/agent-loop/types.js +4 -0
- package/dist/core/agent-loop.d.ts +17 -0
- package/dist/core/agent-loop.d.ts.map +1 -0
- package/dist/core/agent-loop.js +16 -0
- package/dist/core/api-client-impl.d.ts +62 -0
- package/dist/core/api-client-impl.d.ts.map +1 -0
- package/dist/core/api-client-impl.js +479 -0
- package/dist/core/api-client.d.ts +6 -0
- package/dist/core/api-client.d.ts.map +1 -0
- package/dist/core/api-client.js +5 -0
- package/dist/core/checkpoints.d.ts +128 -0
- package/dist/core/checkpoints.d.ts.map +1 -0
- package/dist/core/checkpoints.js +438 -0
- package/dist/core/claude-md.d.ts +71 -0
- package/dist/core/claude-md.d.ts.map +1 -0
- package/dist/core/claude-md.js +198 -0
- package/dist/core/cognitive-security/hooks.d.ts +138 -0
- package/dist/core/cognitive-security/hooks.d.ts.map +1 -0
- package/dist/core/cognitive-security/hooks.js +389 -0
- package/dist/core/cognitive-security/index.d.ts +751 -0
- package/dist/core/cognitive-security/index.d.ts.map +1 -0
- package/dist/core/cognitive-security/index.js +1123 -0
- package/dist/core/cognitive-security/middleware.d.ts +136 -0
- package/dist/core/cognitive-security/middleware.d.ts.map +1 -0
- package/dist/core/cognitive-security/middleware.js +376 -0
- package/dist/core/config-loader.d.ts +127 -0
- package/dist/core/config-loader.d.ts.map +1 -0
- package/dist/core/config-loader.js +219 -0
- package/dist/core/context-compaction.d.ts +87 -0
- package/dist/core/context-compaction.d.ts.map +1 -0
- package/dist/core/context-compaction.js +428 -0
- package/dist/core/git-status.d.ts +25 -0
- package/dist/core/git-status.d.ts.map +1 -0
- package/dist/core/git-status.js +204 -0
- package/dist/core/image.d.ts +69 -0
- package/dist/core/image.d.ts.map +1 -0
- package/dist/core/image.js +290 -0
- package/dist/core/image.test.d.ts +2 -0
- package/dist/core/image.test.d.ts.map +1 -0
- package/dist/core/image.test.js +149 -0
- package/dist/core/models.d.ts +123 -0
- package/dist/core/models.d.ts.map +1 -0
- package/dist/core/models.js +325 -0
- package/dist/core/permissions.d.ts +81 -0
- package/dist/core/permissions.d.ts.map +1 -0
- package/dist/core/permissions.js +327 -0
- package/dist/core/retry.d.ts +25 -0
- package/dist/core/retry.d.ts.map +1 -0
- package/dist/core/retry.js +121 -0
- package/dist/core/session-store.d.ts +9 -0
- package/dist/core/session-store.d.ts.map +1 -0
- package/dist/core/session-store.js +10 -0
- package/dist/core/sessions/export.d.ts +47 -0
- package/dist/core/sessions/export.d.ts.map +1 -0
- package/dist/core/sessions/export.js +256 -0
- package/dist/core/sessions/index.d.ts +132 -0
- package/dist/core/sessions/index.d.ts.map +1 -0
- package/dist/core/sessions/index.js +442 -0
- package/dist/core/sessions/metadata.d.ts +77 -0
- package/dist/core/sessions/metadata.d.ts.map +1 -0
- package/dist/core/sessions/metadata.js +233 -0
- package/dist/core/sessions/persistence.d.ts +72 -0
- package/dist/core/sessions/persistence.d.ts.map +1 -0
- package/dist/core/sessions/persistence.js +201 -0
- package/dist/core/sessions/types.d.ts +110 -0
- package/dist/core/sessions/types.d.ts.map +1 -0
- package/dist/core/sessions/types.js +4 -0
- package/dist/core/stream-highlighter.d.ts +18 -0
- package/dist/core/stream-highlighter.d.ts.map +1 -0
- package/dist/core/stream-highlighter.js +916 -0
- package/dist/core/system-reminders.d.ts +89 -0
- package/dist/core/system-reminders.d.ts.map +1 -0
- package/dist/core/system-reminders.js +285 -0
- package/dist/ecosystem/hooks/__tests__/index.test.d.ts +5 -0
- package/dist/ecosystem/hooks/__tests__/index.test.d.ts.map +1 -0
- package/dist/ecosystem/hooks/__tests__/index.test.js +458 -0
- package/dist/ecosystem/hooks/index.d.ts +59 -0
- package/dist/ecosystem/hooks/index.d.ts.map +1 -0
- package/dist/ecosystem/hooks/index.js +294 -0
- package/dist/ecosystem/hooks/prompt-evaluator.d.ts +32 -0
- package/dist/ecosystem/hooks/prompt-evaluator.d.ts.map +1 -0
- package/dist/ecosystem/hooks/prompt-evaluator.js +229 -0
- package/dist/ecosystem/skills/index.d.ts +55 -0
- package/dist/ecosystem/skills/index.d.ts.map +1 -0
- package/dist/ecosystem/skills/index.js +258 -0
- package/dist/ecosystem/tools/__tests__/index.test.d.ts +7 -0
- package/dist/ecosystem/tools/__tests__/index.test.d.ts.map +1 -0
- package/dist/ecosystem/tools/__tests__/index.test.js +856 -0
- package/dist/ecosystem/tools/index.d.ts +24 -0
- package/dist/ecosystem/tools/index.d.ts.map +1 -0
- package/dist/ecosystem/tools/index.js +1709 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -2
- package/dist/interfaces/mcp/client.d.ts +40 -0
- package/dist/interfaces/mcp/client.d.ts.map +1 -0
- package/dist/interfaces/mcp/client.js +309 -0
- package/dist/interfaces/ui/index.d.ts +36 -0
- package/dist/interfaces/ui/index.d.ts.map +1 -0
- package/dist/interfaces/ui/index.js +61 -0
- package/dist/interfaces/ui/spinner.d.ts +140 -0
- package/dist/interfaces/ui/spinner.d.ts.map +1 -0
- package/dist/interfaces/ui/spinner.js +342 -0
- package/dist/interfaces/ui/terminal/cli/index.d.ts +12 -0
- package/dist/interfaces/ui/terminal/cli/index.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/cli/index.js +167 -0
- package/dist/interfaces/ui/terminal/shared/args.d.ts +39 -0
- package/dist/interfaces/ui/terminal/shared/args.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/shared/args.js +176 -0
- package/dist/interfaces/ui/terminal/shared/index.d.ts +11 -0
- package/dist/interfaces/ui/terminal/shared/index.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/shared/index.js +16 -0
- package/dist/interfaces/ui/terminal/shared/loading-state.d.ts +124 -0
- package/dist/interfaces/ui/terminal/shared/loading-state.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/shared/loading-state.js +246 -0
- package/dist/interfaces/ui/terminal/shared/query.d.ts +22 -0
- package/dist/interfaces/ui/terminal/shared/query.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/shared/query.js +100 -0
- package/dist/interfaces/ui/terminal/shared/setup.d.ts +33 -0
- package/dist/interfaces/ui/terminal/shared/setup.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/shared/setup.js +226 -0
- package/dist/interfaces/ui/terminal/shared/status-line.d.ts +117 -0
- package/dist/interfaces/ui/terminal/shared/status-line.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/shared/status-line.js +267 -0
- package/dist/interfaces/ui/terminal/shared/system-prompt.d.ts +38 -0
- package/dist/interfaces/ui/terminal/shared/system-prompt.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/shared/system-prompt.js +102 -0
- package/dist/interfaces/ui/terminal/tui/HelpPanel.d.ts +39 -0
- package/dist/interfaces/ui/terminal/tui/HelpPanel.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/HelpPanel.js +215 -0
- package/dist/interfaces/ui/terminal/tui/InputContext.d.ts +91 -0
- package/dist/interfaces/ui/terminal/tui/InputContext.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/InputContext.js +154 -0
- package/dist/interfaces/ui/terminal/tui/InputField.d.ts +18 -0
- package/dist/interfaces/ui/terminal/tui/InputField.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/InputField.js +41 -0
- package/dist/interfaces/ui/terminal/tui/InteractiveTUI.d.ts +16 -0
- package/dist/interfaces/ui/terminal/tui/InteractiveTUI.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/InteractiveTUI.js +451 -0
- package/dist/interfaces/ui/terminal/tui/MessageArea.d.ts +10 -0
- package/dist/interfaces/ui/terminal/tui/MessageArea.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/MessageArea.js +91 -0
- package/dist/interfaces/ui/terminal/tui/MessageStore.d.ts +48 -0
- package/dist/interfaces/ui/terminal/tui/MessageStore.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/MessageStore.js +151 -0
- package/dist/interfaces/ui/terminal/tui/StatusBar.d.ts +9 -0
- package/dist/interfaces/ui/terminal/tui/StatusBar.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/StatusBar.js +36 -0
- package/dist/interfaces/ui/terminal/tui/commands.d.ts +21 -0
- package/dist/interfaces/ui/terminal/tui/commands.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/commands.js +359 -0
- package/dist/interfaces/ui/terminal/tui/components/InteractiveElements.d.ts +115 -0
- package/dist/interfaces/ui/terminal/tui/components/InteractiveElements.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/components/InteractiveElements.js +306 -0
- package/dist/interfaces/ui/terminal/tui/components/MultilineInput.d.ts +92 -0
- package/dist/interfaces/ui/terminal/tui/components/MultilineInput.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/components/MultilineInput.js +399 -0
- package/dist/interfaces/ui/terminal/tui/components/PaneManager.d.ts +59 -0
- package/dist/interfaces/ui/terminal/tui/components/PaneManager.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/components/PaneManager.js +139 -0
- package/dist/interfaces/ui/terminal/tui/components/Sidebar.d.ts +68 -0
- package/dist/interfaces/ui/terminal/tui/components/Sidebar.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/components/Sidebar.js +340 -0
- package/dist/interfaces/ui/terminal/tui/components/index.d.ts +23 -0
- package/dist/interfaces/ui/terminal/tui/components/index.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/components/index.js +51 -0
- package/dist/interfaces/ui/terminal/tui/console.d.ts +20 -0
- package/dist/interfaces/ui/terminal/tui/console.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/console.js +46 -0
- package/dist/interfaces/ui/terminal/tui/index.d.ts +20 -0
- package/dist/interfaces/ui/terminal/tui/index.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/index.js +28 -0
- package/dist/interfaces/ui/terminal/tui/run.d.ts +13 -0
- package/dist/interfaces/ui/terminal/tui/run.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/run.js +31 -0
- package/dist/interfaces/ui/terminal/tui/spinner.d.ts +44 -0
- package/dist/interfaces/ui/terminal/tui/spinner.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/spinner.js +59 -0
- package/dist/interfaces/ui/terminal/tui/tui-app.d.ts +39 -0
- package/dist/interfaces/ui/terminal/tui/tui-app.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/tui-app.js +198 -0
- package/dist/interfaces/ui/terminal/tui/tui-footer.d.ts +167 -0
- package/dist/interfaces/ui/terminal/tui/tui-footer.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/tui-footer.js +330 -0
- package/dist/interfaces/ui/terminal/tui/types.d.ts +165 -0
- package/dist/interfaces/ui/terminal/tui/types.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/types.js +5 -0
- package/dist/interfaces/ui/terminal/tui/useInputHandler.d.ts +23 -0
- package/dist/interfaces/ui/terminal/tui/useInputHandler.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/useInputHandler.js +72 -0
- package/dist/interfaces/ui/terminal/tui/useNativeInput.d.ts +90 -0
- package/dist/interfaces/ui/terminal/tui/useNativeInput.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/useNativeInput.js +188 -0
- package/dist/native/index.d.ts +480 -0
- package/dist/native/index.d.ts.map +1 -0
- package/dist/native/index.js +1625 -0
- package/dist/teammates/index.d.ts +161 -0
- package/dist/teammates/index.d.ts.map +1 -0
- package/dist/teammates/index.js +827 -0
- package/dist/types/index.d.ts +482 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +52 -0
- package/native/README.md +5 -5
- package/native/index.darwin-arm64.node +0 -0
- package/native/index.node +0 -0
- package/native/package.json +4 -4
- package/package.json +33 -16
- package/packages/src/core/__tests__/permissions.test.ts +1091 -0
- package/packages/src/core/agent-loop/__tests__/compaction.test.ts +280 -0
- package/packages/src/core/agent-loop/__tests__/formatters.test.ts +234 -0
- package/packages/src/core/agent-loop/__tests__/index.test.ts +162 -0
- package/packages/src/core/agent-loop/__tests__/loop-state.test.ts +413 -0
- package/packages/src/core/agent-loop/__tests__/message-builder.test.ts +229 -0
- package/packages/src/core/agent-loop/__tests__/tool-executor.test.ts +457 -0
- package/packages/src/core/agent-loop/compaction.ts +88 -0
- package/packages/src/core/agent-loop/formatters.ts +50 -0
- package/packages/src/core/agent-loop/index.ts +135 -0
- package/packages/src/core/agent-loop/loop-state.ts +187 -0
- package/packages/src/core/agent-loop/message-builder.ts +62 -0
- package/packages/src/core/agent-loop/tool-executor.ts +211 -0
- package/packages/src/core/agent-loop/turn-executor.ts +222 -0
- package/packages/src/core/agent-loop/types.ts +148 -0
- package/packages/src/core/agent-loop.ts +18 -0
- package/packages/src/core/api-client-impl.ts +619 -0
- package/packages/src/core/api-client.ts +6 -0
- package/packages/src/core/checkpoints.ts +606 -0
- package/packages/src/core/claude-md.ts +272 -0
- package/packages/src/core/cognitive-security/hooks.ts +590 -0
- package/packages/src/core/cognitive-security/index.ts +2041 -0
- package/packages/src/core/cognitive-security/middleware.ts +536 -0
- package/packages/src/core/config-loader.ts +324 -0
- package/packages/src/core/context-compaction.ts +578 -0
- package/packages/src/core/git-status.ts +262 -0
- package/packages/src/core/image.test.ts +180 -0
- package/packages/src/core/image.ts +350 -0
- package/packages/src/core/lmdb.db +0 -0
- package/packages/src/core/lmdb.db-lock +0 -0
- package/packages/src/core/models.ts +430 -0
- package/packages/src/core/normalizers/todo +4 -0
- package/packages/src/core/permissions.ts +431 -0
- package/packages/src/core/retry.ts +170 -0
- package/packages/src/core/session-store.ts +36 -0
- package/packages/src/core/sessions/export.ts +329 -0
- package/packages/src/core/sessions/index.ts +587 -0
- package/packages/src/core/sessions/metadata.ts +309 -0
- package/packages/src/core/sessions/persistence.ts +244 -0
- package/packages/src/core/sessions/types.ts +169 -0
- package/packages/src/core/stream-highlighter.ts +1123 -0
- package/packages/src/core/system-reminders.ts +402 -0
- package/packages/src/core/todo +8 -0
- package/packages/src/ecosystem/hooks/__tests__/index.test.ts +561 -0
- package/packages/src/ecosystem/hooks/index.ts +341 -0
- package/packages/src/ecosystem/hooks/prompt-evaluator.ts +300 -0
- package/packages/src/ecosystem/skills/index.ts +295 -0
- package/packages/src/ecosystem/tools/__tests__/index.test.ts +1335 -0
- package/packages/src/ecosystem/tools/index.ts +1877 -0
- package/packages/src/index.ts +120 -0
- package/packages/src/interfaces/mcp/client.ts +389 -0
- package/packages/src/interfaces/ui/Screenshot 2026-03-02 at 9.23.10/342/200/257PM.png +0 -0
- package/packages/src/interfaces/ui/Screenshot 2026-03-03 at 10.55.11/342/200/257AM.png +0 -0
- package/packages/src/interfaces/ui/index.ts +161 -0
- package/packages/src/interfaces/ui/lmdb.db +0 -0
- package/packages/src/interfaces/ui/lmdb.db-lock +0 -0
- package/packages/src/interfaces/ui/spinner.ts +451 -0
- package/packages/src/interfaces/ui/terminal/cli/index.ts +228 -0
- package/packages/src/interfaces/ui/terminal/lmdb.db +0 -0
- package/packages/src/interfaces/ui/terminal/lmdb.db-lock +0 -0
- package/packages/src/interfaces/ui/terminal/shared/args.ts +222 -0
- package/packages/src/interfaces/ui/terminal/shared/index.ts +71 -0
- package/packages/src/interfaces/ui/terminal/shared/loading-state.ts +322 -0
- package/packages/src/interfaces/ui/terminal/shared/query.ts +146 -0
- package/packages/src/interfaces/ui/terminal/shared/setup.ts +295 -0
- package/packages/src/interfaces/ui/terminal/shared/status-line.ts +358 -0
- package/packages/src/interfaces/ui/terminal/shared/system-prompt.ts +146 -0
- package/packages/src/interfaces/ui/terminal/tui/HelpPanel.tsx +262 -0
- package/packages/src/interfaces/ui/terminal/tui/InputContext.tsx +232 -0
- package/packages/src/interfaces/ui/terminal/tui/InputField.tsx +62 -0
- package/packages/src/interfaces/ui/terminal/tui/InteractiveTUI.tsx +537 -0
- package/packages/src/interfaces/ui/terminal/tui/MessageArea.tsx +107 -0
- package/packages/src/interfaces/ui/terminal/tui/MessageStore.tsx +240 -0
- package/packages/src/interfaces/ui/terminal/tui/StatusBar.tsx +54 -0
- package/packages/src/interfaces/ui/terminal/tui/commands.ts +438 -0
- package/packages/src/interfaces/ui/terminal/tui/components/InteractiveElements.tsx +584 -0
- package/packages/src/interfaces/ui/terminal/tui/components/MultilineInput.tsx +614 -0
- package/packages/src/interfaces/ui/terminal/tui/components/PaneManager.tsx +333 -0
- package/packages/src/interfaces/ui/terminal/tui/components/Sidebar.tsx +604 -0
- package/packages/src/interfaces/ui/terminal/tui/components/index.ts +118 -0
- package/packages/src/interfaces/ui/terminal/tui/console.ts +49 -0
- package/packages/src/interfaces/ui/terminal/tui/index.ts +90 -0
- package/packages/src/interfaces/ui/terminal/tui/run.tsx +42 -0
- package/packages/src/interfaces/ui/terminal/tui/spinner.ts +69 -0
- package/packages/src/interfaces/ui/terminal/tui/tui-app.tsx +390 -0
- package/packages/src/interfaces/ui/terminal/tui/tui-footer.ts +422 -0
- package/packages/src/interfaces/ui/terminal/tui/types.ts +186 -0
- package/packages/src/interfaces/ui/terminal/tui/useInputHandler.ts +104 -0
- package/packages/src/interfaces/ui/terminal/tui/useNativeInput.ts +239 -0
- package/packages/src/lmdb.db +0 -0
- package/packages/src/lmdb.db-lock +0 -0
- package/packages/src/native/index.ts +2345 -0
- package/packages/src/teammates/index.ts +982 -0
- package/packages/src/types/index.ts +722 -0
- package/dist/cli.js +0 -148
- package/dist/index-0pkak453.js +0 -136
- package/dist/index-0qd0x8b4.js +0 -110
- package/dist/index-0x3kprq6.js +0 -240
- package/dist/index-1eawy937.js +0 -308
- package/dist/index-24m2aygy.js +0 -240
- package/dist/index-29xcjnne.js +0 -280
- package/dist/index-2avyytn5.js +0 -349
- package/dist/index-4ms367ey.js +0 -136
- package/dist/index-4w2t3b0m.js +0 -240
- package/dist/index-4xfgd8nz.js +0 -261
- package/dist/index-5acjp9gc.js +0 -157
- package/dist/index-5s15hr56.js +0 -136
- package/dist/index-6e4wf341.js +0 -349
- package/dist/index-6fvnkedw.js +0 -240
- package/dist/index-6rqpmd4g.js +0 -128
- package/dist/index-77ckwnbm.js +0 -280
- package/dist/index-9knxy49k.js +0 -128
- package/dist/index-9zrnw4zx.js +0 -128
- package/dist/index-bk21w99v.js +0 -280
- package/dist/index-c41n76fv.js +0 -240
- package/dist/index-cb4ppjdt.js +0 -255
- package/dist/index-cfb2edt6.js +0 -240
- package/dist/index-cmfa38hh.js +0 -308
- package/dist/index-datjz8q1.js +0 -257
- package/dist/index-eadf4wvn.js +0 -240
- package/dist/index-em5k0m3z.js +0 -345
- package/dist/index-gh8r333a.js +0 -110
- package/dist/index-gkx6k2tr.js +0 -261
- package/dist/index-h5cabfks.js +0 -155
- package/dist/index-hcrpwyy3.js +0 -261
- package/dist/index-hk7fwwa8.js +0 -257
- package/dist/index-jb8cw7f8.js +0 -136
- package/dist/index-kbyw4th1.js +0 -347
- package/dist/index-kgj5gqnm.js +0 -345
- package/dist/index-mdf6xp1z.js +0 -255
- package/dist/index-mrhv8kvc.js +0 -280
- package/dist/index-mt4743dd.js +0 -161
- package/dist/index-qnwsg97q.js +0 -240
- package/dist/index-qwdy6x44.js +0 -261
- package/dist/index-rmj77261.js +0 -157
- package/dist/index-sbbw1a61.js +0 -349
- package/dist/index-svy5bcpn.js +0 -345
- package/dist/index-tvmy7tm9.js +0 -261
- package/dist/index-tzz4vzkj.js +0 -312
- package/dist/index-vz80zmhe.js +0 -110
- package/dist/index-wed2fk67.js +0 -240
- package/dist/index-wksgzz8e.js +0 -280
- package/dist/index-wn2m4wma.js +0 -240
- package/dist/index-xha05vjc.js +0 -257
- package/dist/index-yc6eh8p8.js +0 -136
- package/dist/index-ycjxx9ft.js +0 -240
- package/dist/index-z0gzd0fc.js +0 -110
- package/dist/index-z8cwtf8j.js +0 -240
- package/dist/index-zy5mtt00.js +0 -128
|
@@ -0,0 +1,827 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Teammate System - Multi-agent coordination
|
|
3
|
+
*
|
|
4
|
+
* Messaging Architecture:
|
|
5
|
+
* - File-based inbox system for cross-process communication
|
|
6
|
+
* - Messages stored as JSON files in ~/.claude/teams/{team}/inboxes/{teammateId}/
|
|
7
|
+
* - pending/ for unread messages, processed/ for read messages
|
|
8
|
+
*/
|
|
9
|
+
import { spawn } from "child_process";
|
|
10
|
+
import { mkdirSync, rmSync, existsSync, readFileSync, readdirSync, renameSync, writeFileSync, statSync } from "fs";
|
|
11
|
+
import { join, basename } from "path";
|
|
12
|
+
// ============================================
|
|
13
|
+
// TEAMMATE MANAGER
|
|
14
|
+
// ============================================
|
|
15
|
+
export class TeammateManager {
|
|
16
|
+
teams = new Map();
|
|
17
|
+
teammates = new Map();
|
|
18
|
+
storagePath;
|
|
19
|
+
constructor(storagePath = "~/.claude/teams") {
|
|
20
|
+
this.storagePath = storagePath.replace("~", process.env.HOME || "");
|
|
21
|
+
// Ensure storage directory exists
|
|
22
|
+
if (!existsSync(this.storagePath)) {
|
|
23
|
+
mkdirSync(this.storagePath, { recursive: true });
|
|
24
|
+
}
|
|
25
|
+
// Load existing teams from disk
|
|
26
|
+
this.loadTeams();
|
|
27
|
+
// Ensure inbox directories exist for all teammates
|
|
28
|
+
this.ensureInboxDirectories();
|
|
29
|
+
}
|
|
30
|
+
// ============================================
|
|
31
|
+
// INBOX PATH HELPERS
|
|
32
|
+
// ============================================
|
|
33
|
+
getInboxPath(teamName, teammateId) {
|
|
34
|
+
return join(this.storagePath, teamName, "inboxes", teammateId);
|
|
35
|
+
}
|
|
36
|
+
getPendingPath(teamName, teammateId) {
|
|
37
|
+
return join(this.getInboxPath(teamName, teammateId), "pending");
|
|
38
|
+
}
|
|
39
|
+
getProcessedPath(teamName, teammateId) {
|
|
40
|
+
return join(this.getInboxPath(teamName, teammateId), "processed");
|
|
41
|
+
}
|
|
42
|
+
ensureInboxDirectories() {
|
|
43
|
+
for (const team of this.teams.values()) {
|
|
44
|
+
for (const teammate of team.teammates) {
|
|
45
|
+
const pendingPath = this.getPendingPath(team.name, teammate.teammateId);
|
|
46
|
+
const processedPath = this.getProcessedPath(team.name, teammate.teammateId);
|
|
47
|
+
if (!existsSync(pendingPath)) {
|
|
48
|
+
mkdirSync(pendingPath, { recursive: true });
|
|
49
|
+
}
|
|
50
|
+
if (!existsSync(processedPath)) {
|
|
51
|
+
mkdirSync(processedPath, { recursive: true });
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
generateMessageId() {
|
|
57
|
+
return `msg_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
58
|
+
}
|
|
59
|
+
// ============================================
|
|
60
|
+
// TEAM MANAGEMENT
|
|
61
|
+
// ============================================
|
|
62
|
+
createTeam(config) {
|
|
63
|
+
const team = {
|
|
64
|
+
...config,
|
|
65
|
+
status: "active",
|
|
66
|
+
};
|
|
67
|
+
this.teams.set(config.name, team);
|
|
68
|
+
// Store teammates
|
|
69
|
+
for (const teammate of config.teammates) {
|
|
70
|
+
this.teammates.set(teammate.teammateId, teammate);
|
|
71
|
+
}
|
|
72
|
+
// Create inbox directories for all teammates
|
|
73
|
+
for (const teammate of config.teammates) {
|
|
74
|
+
const pendingPath = this.getPendingPath(config.name, teammate.teammateId);
|
|
75
|
+
const processedPath = this.getProcessedPath(config.name, teammate.teammateId);
|
|
76
|
+
if (!existsSync(pendingPath)) {
|
|
77
|
+
mkdirSync(pendingPath, { recursive: true });
|
|
78
|
+
}
|
|
79
|
+
if (!existsSync(processedPath)) {
|
|
80
|
+
mkdirSync(processedPath, { recursive: true });
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// Persist to disk (fire and forget)
|
|
84
|
+
this.persistTeam(team).catch((err) => {
|
|
85
|
+
console.error(`Failed to persist team ${config.name}:`, err);
|
|
86
|
+
});
|
|
87
|
+
return team;
|
|
88
|
+
}
|
|
89
|
+
getTeam(name) {
|
|
90
|
+
return this.teams.get(name);
|
|
91
|
+
}
|
|
92
|
+
listTeams() {
|
|
93
|
+
return Array.from(this.teams.values());
|
|
94
|
+
}
|
|
95
|
+
deleteTeam(name) {
|
|
96
|
+
const team = this.teams.get(name);
|
|
97
|
+
if (team) {
|
|
98
|
+
// Remove teammates and their message queues
|
|
99
|
+
for (const teammate of team.teammates) {
|
|
100
|
+
this.teammates.delete(teammate.teammateId);
|
|
101
|
+
}
|
|
102
|
+
this.teams.delete(name);
|
|
103
|
+
// Delete team directory from disk
|
|
104
|
+
const teamDir = join(this.storagePath, name);
|
|
105
|
+
try {
|
|
106
|
+
rmSync(teamDir, { recursive: true, force: true });
|
|
107
|
+
}
|
|
108
|
+
catch (err) {
|
|
109
|
+
console.error(`Failed to delete team directory ${teamDir}:`, err);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// ============================================
|
|
114
|
+
// TEAMMATE MANAGEMENT
|
|
115
|
+
// ============================================
|
|
116
|
+
getTeammate(id) {
|
|
117
|
+
return this.teammates.get(id);
|
|
118
|
+
}
|
|
119
|
+
updateTeammateStatus(id, status) {
|
|
120
|
+
const teammate = this.teammates.get(id);
|
|
121
|
+
if (teammate) {
|
|
122
|
+
teammate.status = status;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Add a new teammate to an existing team
|
|
127
|
+
*/
|
|
128
|
+
addTeammate(teamName, teammate) {
|
|
129
|
+
const team = this.teams.get(teamName);
|
|
130
|
+
if (!team)
|
|
131
|
+
return false;
|
|
132
|
+
// Add to team
|
|
133
|
+
team.teammates.push(teammate);
|
|
134
|
+
this.teammates.set(teammate.teammateId, teammate);
|
|
135
|
+
// Create inbox directories
|
|
136
|
+
const pendingPath = this.getPendingPath(teamName, teammate.teammateId);
|
|
137
|
+
const processedPath = this.getProcessedPath(teamName, teammate.teammateId);
|
|
138
|
+
if (!existsSync(pendingPath)) {
|
|
139
|
+
mkdirSync(pendingPath, { recursive: true });
|
|
140
|
+
}
|
|
141
|
+
if (!existsSync(processedPath)) {
|
|
142
|
+
mkdirSync(processedPath, { recursive: true });
|
|
143
|
+
}
|
|
144
|
+
// Persist updated team
|
|
145
|
+
this.persistTeam(team).catch((err) => {
|
|
146
|
+
console.error(`Failed to persist team ${teamName}:`, err);
|
|
147
|
+
});
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Remove a teammate from a team
|
|
152
|
+
*/
|
|
153
|
+
removeTeammate(teamName, teammateId) {
|
|
154
|
+
const team = this.teams.get(teamName);
|
|
155
|
+
if (!team)
|
|
156
|
+
return false;
|
|
157
|
+
// Remove from team
|
|
158
|
+
const index = team.teammates.findIndex(t => t.teammateId === teammateId);
|
|
159
|
+
if (index === -1)
|
|
160
|
+
return false;
|
|
161
|
+
team.teammates.splice(index, 1);
|
|
162
|
+
this.teammates.delete(teammateId);
|
|
163
|
+
// Keep inbox directory for history (don't delete)
|
|
164
|
+
// Persist updated team
|
|
165
|
+
this.persistTeam(team).catch((err) => {
|
|
166
|
+
console.error(`Failed to persist team ${teamName}:`, err);
|
|
167
|
+
});
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
// ============================================
|
|
171
|
+
// SPAWNING
|
|
172
|
+
// ============================================
|
|
173
|
+
async spawnTeammate(teammate, options = {}) {
|
|
174
|
+
const { session, workingDir = process.cwd() } = options;
|
|
175
|
+
// Check if inside tmux
|
|
176
|
+
const insideTmux = !!process.env.TMUX;
|
|
177
|
+
if (!insideTmux) {
|
|
178
|
+
// Spawn in new terminal
|
|
179
|
+
await this.spawnInTerminal(teammate, { session, workingDir });
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
// Spawn in tmux pane
|
|
183
|
+
await this.spawnInTmux(teammate, { session, workingDir });
|
|
184
|
+
}
|
|
185
|
+
this.updateTeammateStatus(teammate.teammateId, "in_progress");
|
|
186
|
+
}
|
|
187
|
+
async spawnInTerminal(teammate, options) {
|
|
188
|
+
// Build claude command
|
|
189
|
+
const args = [
|
|
190
|
+
"bun",
|
|
191
|
+
"run",
|
|
192
|
+
"src/interfaces/ui/terminal/cli/index.ts",
|
|
193
|
+
"--teammate-mode",
|
|
194
|
+
"--agent-id",
|
|
195
|
+
teammate.teammateId,
|
|
196
|
+
"--agent-name",
|
|
197
|
+
teammate.name,
|
|
198
|
+
"--team-name",
|
|
199
|
+
teammate.teamName,
|
|
200
|
+
"--agent-color",
|
|
201
|
+
teammate.color,
|
|
202
|
+
];
|
|
203
|
+
if (teammate.planModeRequired) {
|
|
204
|
+
args.push("--permission-mode", "plan");
|
|
205
|
+
}
|
|
206
|
+
// Use AppleScript on macOS to open new Terminal
|
|
207
|
+
if (process.platform === "darwin") {
|
|
208
|
+
const script = `
|
|
209
|
+
tell application "Terminal"
|
|
210
|
+
do script "cd ${options.workingDir} && ${args.join(" ")}"
|
|
211
|
+
activate
|
|
212
|
+
end tell
|
|
213
|
+
`;
|
|
214
|
+
spawn("osascript", ["-e", script]);
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
// Linux: use xterm or similar
|
|
218
|
+
spawn("xterm", ["-e", args.join(" ")]);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
async spawnInTmux(teammate, options) {
|
|
222
|
+
const sessionName = options.session || process.env.TMUX?.split(",")[0]?.split(":")[0] || "claude";
|
|
223
|
+
// Create new pane
|
|
224
|
+
await this.tmuxCommand(["split-window", "-t", sessionName, "-c", options.workingDir]);
|
|
225
|
+
// Get pane ID
|
|
226
|
+
const paneId = await this.tmuxCommand(["display-message", "-p", "#{pane_id}"]);
|
|
227
|
+
if (paneId) {
|
|
228
|
+
teammate.paneId = paneId.trim();
|
|
229
|
+
}
|
|
230
|
+
// Send claude command
|
|
231
|
+
const args = [
|
|
232
|
+
"bun",
|
|
233
|
+
"run",
|
|
234
|
+
"src/interfaces/ui/terminal/cli/index.ts",
|
|
235
|
+
"--teammate-mode",
|
|
236
|
+
"--agent-id",
|
|
237
|
+
teammate.teammateId,
|
|
238
|
+
"--agent-name",
|
|
239
|
+
teammate.name,
|
|
240
|
+
"--team-name",
|
|
241
|
+
teammate.teamName,
|
|
242
|
+
];
|
|
243
|
+
await this.tmuxCommand(["send-keys", "-t", teammate.paneId || "", args.join(" "), "Enter"]);
|
|
244
|
+
}
|
|
245
|
+
async tmuxCommand(args) {
|
|
246
|
+
return new Promise((resolve) => {
|
|
247
|
+
const proc = spawn("tmux", args);
|
|
248
|
+
let output = "";
|
|
249
|
+
proc.stdout?.on("data", (data) => {
|
|
250
|
+
output += data.toString();
|
|
251
|
+
});
|
|
252
|
+
proc.on("close", () => {
|
|
253
|
+
resolve(output);
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
// ============================================
|
|
258
|
+
// MESSAGING (FILE-BASED)
|
|
259
|
+
// ============================================
|
|
260
|
+
/**
|
|
261
|
+
* Get the team name for a teammate
|
|
262
|
+
*/
|
|
263
|
+
getTeamNameForTeammate(teammateId) {
|
|
264
|
+
const teammate = this.teammates.get(teammateId);
|
|
265
|
+
return teammate?.teamName;
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Write a message to a teammate's file-based inbox
|
|
269
|
+
*/
|
|
270
|
+
writeMessageToInbox(teamName, toId, msg) {
|
|
271
|
+
const pendingPath = this.getPendingPath(teamName, toId);
|
|
272
|
+
// Ensure inbox exists
|
|
273
|
+
if (!existsSync(pendingPath)) {
|
|
274
|
+
mkdirSync(pendingPath, { recursive: true });
|
|
275
|
+
}
|
|
276
|
+
// Write message as JSON file
|
|
277
|
+
const msgPath = join(pendingPath, `${msg.id}.json`);
|
|
278
|
+
writeFileSync(msgPath, JSON.stringify(msg, null, 2));
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Read all pending messages from a teammate's inbox
|
|
282
|
+
*/
|
|
283
|
+
readPendingMessages(teamName, teammateId) {
|
|
284
|
+
const pendingPath = this.getPendingPath(teamName, teammateId);
|
|
285
|
+
const messages = [];
|
|
286
|
+
if (!existsSync(pendingPath)) {
|
|
287
|
+
return messages;
|
|
288
|
+
}
|
|
289
|
+
try {
|
|
290
|
+
const files = readdirSync(pendingPath)
|
|
291
|
+
.filter(f => f.endsWith('.json'))
|
|
292
|
+
.sort(); // Oldest first (by filename timestamp)
|
|
293
|
+
for (const file of files) {
|
|
294
|
+
try {
|
|
295
|
+
const msgPath = join(pendingPath, file);
|
|
296
|
+
const content = readFileSync(msgPath, 'utf-8');
|
|
297
|
+
const msg = JSON.parse(content);
|
|
298
|
+
messages.push(msg);
|
|
299
|
+
}
|
|
300
|
+
catch {
|
|
301
|
+
// Skip malformed messages
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
catch {
|
|
306
|
+
// Directory read error
|
|
307
|
+
}
|
|
308
|
+
return messages;
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Move a message from pending to processed
|
|
312
|
+
*/
|
|
313
|
+
markMessageProcessed(teamName, teammateId, msgId) {
|
|
314
|
+
const pendingPath = this.getPendingPath(teamName, teammateId);
|
|
315
|
+
const processedPath = this.getProcessedPath(teamName, teammateId);
|
|
316
|
+
const pendingFile = join(pendingPath, `${msgId}.json`);
|
|
317
|
+
const processedFile = join(processedPath, `${msgId}.json`);
|
|
318
|
+
if (existsSync(pendingFile)) {
|
|
319
|
+
// Ensure processed directory exists
|
|
320
|
+
if (!existsSync(processedPath)) {
|
|
321
|
+
mkdirSync(processedPath, { recursive: true });
|
|
322
|
+
}
|
|
323
|
+
// Update message with readAt timestamp
|
|
324
|
+
try {
|
|
325
|
+
const content = readFileSync(pendingFile, 'utf-8');
|
|
326
|
+
const msg = JSON.parse(content);
|
|
327
|
+
msg.readAt = Date.now();
|
|
328
|
+
writeFileSync(processedFile, JSON.stringify(msg, null, 2));
|
|
329
|
+
rmSync(pendingFile);
|
|
330
|
+
}
|
|
331
|
+
catch {
|
|
332
|
+
// If update fails, just move the file
|
|
333
|
+
try {
|
|
334
|
+
renameSync(pendingFile, processedFile);
|
|
335
|
+
}
|
|
336
|
+
catch {
|
|
337
|
+
// Ignore move errors
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Broadcast a message to all teammates in a team
|
|
344
|
+
*/
|
|
345
|
+
broadcast(teamName, message, fromId) {
|
|
346
|
+
const team = this.teams.get(teamName);
|
|
347
|
+
if (!team)
|
|
348
|
+
return;
|
|
349
|
+
const baseMsg = {
|
|
350
|
+
type: "broadcast",
|
|
351
|
+
from: fromId || "system",
|
|
352
|
+
content: message,
|
|
353
|
+
timestamp: Date.now(),
|
|
354
|
+
};
|
|
355
|
+
// Write message to each teammate's inbox
|
|
356
|
+
for (const teammate of team.teammates) {
|
|
357
|
+
// Don't send to sender
|
|
358
|
+
if (fromId && teammate.teammateId === fromId)
|
|
359
|
+
continue;
|
|
360
|
+
const msg = {
|
|
361
|
+
...baseMsg,
|
|
362
|
+
id: this.generateMessageId(),
|
|
363
|
+
teamName,
|
|
364
|
+
createdAt: Date.now(),
|
|
365
|
+
to: teammate.teammateId,
|
|
366
|
+
};
|
|
367
|
+
this.writeMessageToInbox(teamName, teammate.teammateId, msg);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Send a direct message to a specific teammate
|
|
372
|
+
*/
|
|
373
|
+
sendDirect(toId, fromId, message) {
|
|
374
|
+
const teamName = this.getTeamNameForTeammate(toId);
|
|
375
|
+
if (!teamName)
|
|
376
|
+
return;
|
|
377
|
+
const msg = {
|
|
378
|
+
id: this.generateMessageId(),
|
|
379
|
+
type: "direct",
|
|
380
|
+
from: fromId,
|
|
381
|
+
to: toId,
|
|
382
|
+
content: message,
|
|
383
|
+
timestamp: Date.now(),
|
|
384
|
+
teamName,
|
|
385
|
+
createdAt: Date.now(),
|
|
386
|
+
};
|
|
387
|
+
this.writeMessageToInbox(teamName, toId, msg);
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Inject a message as if it came from the user (for teammate integration)
|
|
391
|
+
* This integrates messages into conversation flow
|
|
392
|
+
*/
|
|
393
|
+
injectUserMessageToTeammate(toId, message) {
|
|
394
|
+
const teamName = this.getTeamNameForTeammate(toId);
|
|
395
|
+
if (!teamName)
|
|
396
|
+
return;
|
|
397
|
+
const msg = {
|
|
398
|
+
id: this.generateMessageId(),
|
|
399
|
+
type: "notification", // Use notification type for injected messages
|
|
400
|
+
from: "user",
|
|
401
|
+
to: toId,
|
|
402
|
+
content: message,
|
|
403
|
+
timestamp: Date.now(),
|
|
404
|
+
teamName,
|
|
405
|
+
createdAt: Date.now(),
|
|
406
|
+
};
|
|
407
|
+
this.writeMessageToInbox(teamName, toId, msg);
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* Retrieve and mark all messages as processed for a teammate
|
|
411
|
+
* Returns messages in chronological order (oldest first)
|
|
412
|
+
*/
|
|
413
|
+
getMessages(teammateId) {
|
|
414
|
+
const teamName = this.getTeamNameForTeammate(teammateId);
|
|
415
|
+
if (!teamName)
|
|
416
|
+
return [];
|
|
417
|
+
const storedMsgs = this.readPendingMessages(teamName, teammateId);
|
|
418
|
+
// Mark all as processed
|
|
419
|
+
for (const msg of storedMsgs) {
|
|
420
|
+
this.markMessageProcessed(teamName, teammateId, msg.id);
|
|
421
|
+
}
|
|
422
|
+
// Convert to TeammateMessage format
|
|
423
|
+
return storedMsgs.map(msg => ({
|
|
424
|
+
type: msg.type,
|
|
425
|
+
from: msg.from,
|
|
426
|
+
to: msg.to,
|
|
427
|
+
content: msg.content,
|
|
428
|
+
timestamp: msg.timestamp,
|
|
429
|
+
}));
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* Check if a teammate has pending messages
|
|
433
|
+
*/
|
|
434
|
+
hasMessages(teammateId) {
|
|
435
|
+
const teamName = this.getTeamNameForTeammate(teammateId);
|
|
436
|
+
if (!teamName)
|
|
437
|
+
return false;
|
|
438
|
+
const pendingPath = this.getPendingPath(teamName, teammateId);
|
|
439
|
+
if (!existsSync(pendingPath))
|
|
440
|
+
return false;
|
|
441
|
+
try {
|
|
442
|
+
const files = readdirSync(pendingPath);
|
|
443
|
+
return files.some(f => f.endsWith('.json'));
|
|
444
|
+
}
|
|
445
|
+
catch {
|
|
446
|
+
return false;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
/**
|
|
450
|
+
* Peek at messages without marking them as processed
|
|
451
|
+
*/
|
|
452
|
+
peekMessages(teammateId) {
|
|
453
|
+
const teamName = this.getTeamNameForTeammate(teammateId);
|
|
454
|
+
if (!teamName)
|
|
455
|
+
return [];
|
|
456
|
+
const storedMsgs = this.readPendingMessages(teamName, teammateId);
|
|
457
|
+
return storedMsgs.map(msg => ({
|
|
458
|
+
type: msg.type,
|
|
459
|
+
from: msg.from,
|
|
460
|
+
to: msg.to,
|
|
461
|
+
content: msg.content,
|
|
462
|
+
timestamp: msg.timestamp,
|
|
463
|
+
}));
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* Clear all pending messages for a teammate (move to processed)
|
|
467
|
+
*/
|
|
468
|
+
clearMessages(teammateId) {
|
|
469
|
+
const teamName = this.getTeamNameForTeammate(teammateId);
|
|
470
|
+
if (!teamName)
|
|
471
|
+
return;
|
|
472
|
+
const pendingPath = this.getPendingPath(teamName, teammateId);
|
|
473
|
+
if (!existsSync(pendingPath))
|
|
474
|
+
return;
|
|
475
|
+
const storedMsgs = this.readPendingMessages(teamName, teammateId);
|
|
476
|
+
for (const msg of storedMsgs) {
|
|
477
|
+
this.markMessageProcessed(teamName, teammateId, msg.id);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* Get count of pending messages for a teammate
|
|
482
|
+
*/
|
|
483
|
+
getMessageCount(teammateId) {
|
|
484
|
+
const teamName = this.getTeamNameForTeammate(teammateId);
|
|
485
|
+
if (!teamName)
|
|
486
|
+
return 0;
|
|
487
|
+
const pendingPath = this.getPendingPath(teamName, teammateId);
|
|
488
|
+
if (!existsSync(pendingPath))
|
|
489
|
+
return 0;
|
|
490
|
+
try {
|
|
491
|
+
const files = readdirSync(pendingPath);
|
|
492
|
+
return files.filter(f => f.endsWith('.json')).length;
|
|
493
|
+
}
|
|
494
|
+
catch {
|
|
495
|
+
return 0;
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
/**
|
|
499
|
+
* Get processed messages (history) for a teammate
|
|
500
|
+
*/
|
|
501
|
+
getProcessedMessages(teammateId, limit = 100) {
|
|
502
|
+
const teamName = this.getTeamNameForTeammate(teammateId);
|
|
503
|
+
if (!teamName)
|
|
504
|
+
return [];
|
|
505
|
+
const processedPath = this.getProcessedPath(teamName, teammateId);
|
|
506
|
+
const messages = [];
|
|
507
|
+
if (!existsSync(processedPath)) {
|
|
508
|
+
return messages;
|
|
509
|
+
}
|
|
510
|
+
try {
|
|
511
|
+
const files = readdirSync(processedPath)
|
|
512
|
+
.filter(f => f.endsWith('.json'))
|
|
513
|
+
.sort()
|
|
514
|
+
.reverse() // Newest first
|
|
515
|
+
.slice(0, limit);
|
|
516
|
+
for (const file of files) {
|
|
517
|
+
try {
|
|
518
|
+
const msgPath = join(processedPath, file);
|
|
519
|
+
const content = readFileSync(msgPath, 'utf-8');
|
|
520
|
+
messages.push(JSON.parse(content));
|
|
521
|
+
}
|
|
522
|
+
catch {
|
|
523
|
+
// Skip malformed
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
catch {
|
|
528
|
+
// Directory read error
|
|
529
|
+
}
|
|
530
|
+
return messages;
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* Clean up old processed messages (older than maxAgeMs)
|
|
534
|
+
*/
|
|
535
|
+
cleanupProcessedMessages(teammateId, maxAgeMs = 7 * 24 * 60 * 60 * 1000) {
|
|
536
|
+
const teamName = this.getTeamNameForTeammate(teammateId);
|
|
537
|
+
if (!teamName)
|
|
538
|
+
return 0;
|
|
539
|
+
const processedPath = this.getProcessedPath(teamName, teammateId);
|
|
540
|
+
const cutoff = Date.now() - maxAgeMs;
|
|
541
|
+
let deleted = 0;
|
|
542
|
+
if (!existsSync(processedPath))
|
|
543
|
+
return 0;
|
|
544
|
+
try {
|
|
545
|
+
const files = readdirSync(processedPath).filter(f => f.endsWith('.json'));
|
|
546
|
+
for (const file of files) {
|
|
547
|
+
try {
|
|
548
|
+
const msgPath = join(processedPath, file);
|
|
549
|
+
const content = readFileSync(msgPath, 'utf-8');
|
|
550
|
+
const msg = JSON.parse(content);
|
|
551
|
+
if (msg.readAt && msg.readAt < cutoff) {
|
|
552
|
+
rmSync(msgPath);
|
|
553
|
+
deleted++;
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
catch {
|
|
557
|
+
// Skip errors
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
catch {
|
|
562
|
+
// Directory read error
|
|
563
|
+
}
|
|
564
|
+
return deleted;
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* Wait for all teammates in a team to become idle
|
|
568
|
+
* Returns when all teammates have status 'idle', 'completed', or 'failed'
|
|
569
|
+
*/
|
|
570
|
+
async waitForTeammatesToBecomeIdle(teamName, options = {}) {
|
|
571
|
+
const { timeout = 60000, pollInterval = 1000 } = options;
|
|
572
|
+
const startTime = Date.now();
|
|
573
|
+
const idleStatuses = ['idle', 'completed', 'failed'];
|
|
574
|
+
while (true) {
|
|
575
|
+
const team = this.teams.get(teamName);
|
|
576
|
+
if (!team) {
|
|
577
|
+
return { success: false, timedOut: false, statuses: {} };
|
|
578
|
+
}
|
|
579
|
+
const statuses = {};
|
|
580
|
+
let allIdle = true;
|
|
581
|
+
for (const teammate of team.teammates) {
|
|
582
|
+
statuses[teammate.teammateId] = teammate.status;
|
|
583
|
+
if (!idleStatuses.includes(teammate.status)) {
|
|
584
|
+
allIdle = false;
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
if (allIdle) {
|
|
588
|
+
return { success: true, timedOut: false, statuses };
|
|
589
|
+
}
|
|
590
|
+
// Check timeout
|
|
591
|
+
if (Date.now() - startTime > timeout) {
|
|
592
|
+
return { success: false, timedOut: true, statuses };
|
|
593
|
+
}
|
|
594
|
+
// Wait before polling again
|
|
595
|
+
await new Promise(resolve => setTimeout(resolve, pollInterval));
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
/**
|
|
599
|
+
* Get inbox statistics for a teammate
|
|
600
|
+
*/
|
|
601
|
+
getInboxStats(teammateId) {
|
|
602
|
+
const teamName = this.getTeamNameForTeammate(teammateId);
|
|
603
|
+
if (!teamName)
|
|
604
|
+
return { pending: 0, processed: 0 };
|
|
605
|
+
const pendingPath = this.getPendingPath(teamName, teammateId);
|
|
606
|
+
const processedPath = this.getProcessedPath(teamName, teammateId);
|
|
607
|
+
let pending = 0;
|
|
608
|
+
let processed = 0;
|
|
609
|
+
let oldestPending;
|
|
610
|
+
let newestPending;
|
|
611
|
+
// Count pending
|
|
612
|
+
if (existsSync(pendingPath)) {
|
|
613
|
+
try {
|
|
614
|
+
const files = readdirSync(pendingPath).filter(f => f.endsWith('.json'));
|
|
615
|
+
pending = files.length;
|
|
616
|
+
for (const file of files) {
|
|
617
|
+
try {
|
|
618
|
+
const msgPath = join(pendingPath, file);
|
|
619
|
+
const content = readFileSync(msgPath, 'utf-8');
|
|
620
|
+
const msg = JSON.parse(content);
|
|
621
|
+
if (!oldestPending || msg.createdAt < oldestPending) {
|
|
622
|
+
oldestPending = msg.createdAt;
|
|
623
|
+
}
|
|
624
|
+
if (!newestPending || msg.createdAt > newestPending) {
|
|
625
|
+
newestPending = msg.createdAt;
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
catch {
|
|
629
|
+
// Skip
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
catch {
|
|
634
|
+
// Skip
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
// Count processed
|
|
638
|
+
if (existsSync(processedPath)) {
|
|
639
|
+
try {
|
|
640
|
+
const files = readdirSync(processedPath).filter(f => f.endsWith('.json'));
|
|
641
|
+
processed = files.length;
|
|
642
|
+
}
|
|
643
|
+
catch {
|
|
644
|
+
// Skip
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
return { pending, processed, oldestPending, newestPending };
|
|
648
|
+
}
|
|
649
|
+
// ============================================
|
|
650
|
+
// PERSISTENCE
|
|
651
|
+
// ============================================
|
|
652
|
+
/**
|
|
653
|
+
* Persist a team configuration to disk
|
|
654
|
+
*/
|
|
655
|
+
async persistTeam(team) {
|
|
656
|
+
const teamDir = join(this.storagePath, team.name);
|
|
657
|
+
const configPath = join(teamDir, "config.json");
|
|
658
|
+
// Ensure directory exists
|
|
659
|
+
if (!existsSync(teamDir)) {
|
|
660
|
+
mkdirSync(teamDir, { recursive: true });
|
|
661
|
+
}
|
|
662
|
+
// Write .gitkeep to ensure directory is tracked
|
|
663
|
+
await Bun.write(join(teamDir, ".gitkeep"), "");
|
|
664
|
+
// Build config object
|
|
665
|
+
const config = {
|
|
666
|
+
name: team.name,
|
|
667
|
+
description: team.description,
|
|
668
|
+
teammates: team.teammates,
|
|
669
|
+
taskListId: team.taskListId,
|
|
670
|
+
status: team.status,
|
|
671
|
+
coordination: team.coordination,
|
|
672
|
+
updatedAt: Date.now(),
|
|
673
|
+
};
|
|
674
|
+
// Write config as formatted JSON
|
|
675
|
+
await Bun.write(configPath, JSON.stringify(config, null, 2));
|
|
676
|
+
}
|
|
677
|
+
/**
|
|
678
|
+
* Load all teams from disk at startup
|
|
679
|
+
* Uses synchronous operations for constructor compatibility
|
|
680
|
+
*/
|
|
681
|
+
loadTeams() {
|
|
682
|
+
// Use Bun's glob to find team configs
|
|
683
|
+
const glob = new Bun.Glob("**/config.json");
|
|
684
|
+
try {
|
|
685
|
+
const files = Array.from(glob.scanSync(this.storagePath));
|
|
686
|
+
for (const file of files) {
|
|
687
|
+
try {
|
|
688
|
+
const filePath = join(this.storagePath, file);
|
|
689
|
+
const content = Bun.file(filePath);
|
|
690
|
+
// Check if file exists and is readable (sync check via size)
|
|
691
|
+
const size = content.size;
|
|
692
|
+
if (size === 0) {
|
|
693
|
+
continue;
|
|
694
|
+
}
|
|
695
|
+
// Read file synchronously using readFileSync
|
|
696
|
+
// Bun.file().text() is async, so we use fs.readFileSync for sync operation
|
|
697
|
+
const text = readFileSync(filePath, "utf-8");
|
|
698
|
+
const config = JSON.parse(text);
|
|
699
|
+
// Validate required fields - skip if missing teammates or name
|
|
700
|
+
if (!config.name || !config.teammates || !Array.isArray(config.teammates)) {
|
|
701
|
+
// Skip configs that don't match our expected structure
|
|
702
|
+
continue;
|
|
703
|
+
}
|
|
704
|
+
const team = {
|
|
705
|
+
name: config.name,
|
|
706
|
+
description: config.description || "",
|
|
707
|
+
teammates: config.teammates,
|
|
708
|
+
taskListId: config.taskListId || "",
|
|
709
|
+
status: config.status || "active",
|
|
710
|
+
coordination: config.coordination || {
|
|
711
|
+
dependencyOrder: [],
|
|
712
|
+
communicationProtocol: "broadcast",
|
|
713
|
+
taskAssignmentStrategy: "manual",
|
|
714
|
+
},
|
|
715
|
+
};
|
|
716
|
+
this.teams.set(team.name, team);
|
|
717
|
+
// Index teammates
|
|
718
|
+
for (const teammate of team.teammates) {
|
|
719
|
+
this.teammates.set(teammate.teammateId, teammate);
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
catch (error) {
|
|
723
|
+
// Silently skip malformed configs
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
catch (error) {
|
|
728
|
+
// Storage path may not exist yet - that's okay
|
|
729
|
+
if (error.code !== "ENOENT") {
|
|
730
|
+
// Ignore permission errors too
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
/**
|
|
735
|
+
* Persist all teams to disk (useful for shutdown)
|
|
736
|
+
*/
|
|
737
|
+
async persistAllTeams() {
|
|
738
|
+
const promises = Array.from(this.teams.values()).map((team) => this.persistTeam(team));
|
|
739
|
+
await Promise.all(promises);
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
// ============================================
|
|
743
|
+
// TEAMMATE TEMPLATES
|
|
744
|
+
// ============================================
|
|
745
|
+
export const teammateTemplates = {
|
|
746
|
+
/**
|
|
747
|
+
* Architect - Plans and designs
|
|
748
|
+
*/
|
|
749
|
+
architect: (teamName) => ({
|
|
750
|
+
name: "architect",
|
|
751
|
+
teamName,
|
|
752
|
+
color: "blue",
|
|
753
|
+
prompt: `You are an architect on the ${teamName} team.
|
|
754
|
+
Your role is to design and plan the technical architecture.
|
|
755
|
+
Focus on:
|
|
756
|
+
- System design and component relationships
|
|
757
|
+
- API contracts and interfaces
|
|
758
|
+
- Data models and schemas
|
|
759
|
+
- Trade-offs and design decisions`,
|
|
760
|
+
planModeRequired: true,
|
|
761
|
+
status: "pending",
|
|
762
|
+
}),
|
|
763
|
+
/**
|
|
764
|
+
* Implementer - Writes code
|
|
765
|
+
*/
|
|
766
|
+
implementer: (teamName) => ({
|
|
767
|
+
name: "implementer",
|
|
768
|
+
teamName,
|
|
769
|
+
color: "green",
|
|
770
|
+
prompt: `You are an implementer on the ${teamName} team.
|
|
771
|
+
Your role is to write clean, working code based on the architecture.
|
|
772
|
+
Focus on:
|
|
773
|
+
- Implementing the designed architecture
|
|
774
|
+
- Writing tests
|
|
775
|
+
- Following coding standards
|
|
776
|
+
- Handling edge cases`,
|
|
777
|
+
planModeRequired: false,
|
|
778
|
+
status: "pending",
|
|
779
|
+
}),
|
|
780
|
+
/**
|
|
781
|
+
* Reviewer - Reviews code
|
|
782
|
+
*/
|
|
783
|
+
reviewer: (teamName) => ({
|
|
784
|
+
name: "reviewer",
|
|
785
|
+
teamName,
|
|
786
|
+
color: "yellow",
|
|
787
|
+
prompt: `You are a code reviewer on the ${teamName} team.
|
|
788
|
+
Your role is to review code changes and provide feedback.
|
|
789
|
+
Focus on:
|
|
790
|
+
- Code quality and readability
|
|
791
|
+
- Potential bugs and issues
|
|
792
|
+
- Performance considerations
|
|
793
|
+
- Test coverage`,
|
|
794
|
+
planModeRequired: false,
|
|
795
|
+
status: "pending",
|
|
796
|
+
}),
|
|
797
|
+
/**
|
|
798
|
+
* Tester - Tests features
|
|
799
|
+
*/
|
|
800
|
+
tester: (teamName) => ({
|
|
801
|
+
name: "tester",
|
|
802
|
+
teamName,
|
|
803
|
+
color: "orange",
|
|
804
|
+
prompt: `You are a tester on the ${teamName} team.
|
|
805
|
+
Your role is to ensure features work correctly.
|
|
806
|
+
Focus on:
|
|
807
|
+
- Writing comprehensive tests
|
|
808
|
+
- Finding edge cases
|
|
809
|
+
- Verifying requirements
|
|
810
|
+
- Reporting bugs`,
|
|
811
|
+
planModeRequired: false,
|
|
812
|
+
status: "pending",
|
|
813
|
+
}),
|
|
814
|
+
};
|
|
815
|
+
// ============================================
|
|
816
|
+
// HELPER FUNCTIONS
|
|
817
|
+
// ============================================
|
|
818
|
+
export function generateTeammateId() {
|
|
819
|
+
return `teammate_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
820
|
+
}
|
|
821
|
+
export function createTeammate(config) {
|
|
822
|
+
return {
|
|
823
|
+
...config,
|
|
824
|
+
teammateId: generateTeammateId(),
|
|
825
|
+
status: "pending",
|
|
826
|
+
};
|
|
827
|
+
}
|