hungry-ghost-hive 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +111 -0
- package/README.md +352 -0
- package/dist/agents/base-agent.d.ts +63 -0
- package/dist/agents/base-agent.d.ts.map +1 -0
- package/dist/agents/base-agent.js +189 -0
- package/dist/agents/base-agent.js.map +1 -0
- package/dist/agents/index.d.ts +7 -0
- package/dist/agents/index.d.ts.map +1 -0
- package/dist/agents/index.js +7 -0
- package/dist/agents/index.js.map +1 -0
- package/dist/agents/intermediate.d.ts +15 -0
- package/dist/agents/intermediate.d.ts.map +1 -0
- package/dist/agents/intermediate.js +142 -0
- package/dist/agents/intermediate.js.map +1 -0
- package/dist/agents/junior.d.ts +15 -0
- package/dist/agents/junior.d.ts.map +1 -0
- package/dist/agents/junior.js +147 -0
- package/dist/agents/junior.js.map +1 -0
- package/dist/agents/qa.d.ts +23 -0
- package/dist/agents/qa.d.ts.map +1 -0
- package/dist/agents/qa.js +238 -0
- package/dist/agents/qa.js.map +1 -0
- package/dist/agents/senior.d.ts +18 -0
- package/dist/agents/senior.d.ts.map +1 -0
- package/dist/agents/senior.js +267 -0
- package/dist/agents/senior.js.map +1 -0
- package/dist/agents/tech-lead.d.ts +17 -0
- package/dist/agents/tech-lead.d.ts.map +1 -0
- package/dist/agents/tech-lead.js +274 -0
- package/dist/agents/tech-lead.js.map +1 -0
- package/dist/cli/commands/add-repo.d.ts +3 -0
- package/dist/cli/commands/add-repo.d.ts.map +1 -0
- package/dist/cli/commands/add-repo.js +84 -0
- package/dist/cli/commands/add-repo.js.map +1 -0
- package/dist/cli/commands/agents.d.ts +3 -0
- package/dist/cli/commands/agents.d.ts.map +1 -0
- package/dist/cli/commands/agents.js +214 -0
- package/dist/cli/commands/agents.js.map +1 -0
- package/dist/cli/commands/assign.d.ts +3 -0
- package/dist/cli/commands/assign.d.ts.map +1 -0
- package/dist/cli/commands/assign.js +81 -0
- package/dist/cli/commands/assign.js.map +1 -0
- package/dist/cli/commands/config.d.ts +3 -0
- package/dist/cli/commands/config.d.ts.map +1 -0
- package/dist/cli/commands/config.js +118 -0
- package/dist/cli/commands/config.js.map +1 -0
- package/dist/cli/commands/escalations.d.ts +3 -0
- package/dist/cli/commands/escalations.d.ts.map +1 -0
- package/dist/cli/commands/escalations.js +157 -0
- package/dist/cli/commands/escalations.js.map +1 -0
- package/dist/cli/commands/index.d.ts +17 -0
- package/dist/cli/commands/index.d.ts.map +1 -0
- package/dist/cli/commands/index.js +17 -0
- package/dist/cli/commands/index.js.map +1 -0
- package/dist/cli/commands/init.d.ts +3 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +59 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/manager.d.ts +3 -0
- package/dist/cli/commands/manager.d.ts.map +1 -0
- package/dist/cli/commands/manager.js +775 -0
- package/dist/cli/commands/manager.js.map +1 -0
- package/dist/cli/commands/manager.test.d.ts +2 -0
- package/dist/cli/commands/manager.test.d.ts.map +1 -0
- package/dist/cli/commands/manager.test.js +45 -0
- package/dist/cli/commands/manager.test.js.map +1 -0
- package/dist/cli/commands/msg.d.ts +3 -0
- package/dist/cli/commands/msg.d.ts.map +1 -0
- package/dist/cli/commands/msg.js +190 -0
- package/dist/cli/commands/msg.js.map +1 -0
- package/dist/cli/commands/my-stories.d.ts +3 -0
- package/dist/cli/commands/my-stories.d.ts.map +1 -0
- package/dist/cli/commands/my-stories.js +174 -0
- package/dist/cli/commands/my-stories.js.map +1 -0
- package/dist/cli/commands/nuke.d.ts +3 -0
- package/dist/cli/commands/nuke.d.ts.map +1 -0
- package/dist/cli/commands/nuke.js +189 -0
- package/dist/cli/commands/nuke.js.map +1 -0
- package/dist/cli/commands/pr.d.ts +3 -0
- package/dist/cli/commands/pr.d.ts.map +1 -0
- package/dist/cli/commands/pr.js +488 -0
- package/dist/cli/commands/pr.js.map +1 -0
- package/dist/cli/commands/req.d.ts +3 -0
- package/dist/cli/commands/req.d.ts.map +1 -0
- package/dist/cli/commands/req.js +212 -0
- package/dist/cli/commands/req.js.map +1 -0
- package/dist/cli/commands/resume.d.ts +3 -0
- package/dist/cli/commands/resume.d.ts.map +1 -0
- package/dist/cli/commands/resume.js +114 -0
- package/dist/cli/commands/resume.js.map +1 -0
- package/dist/cli/commands/status.d.ts +3 -0
- package/dist/cli/commands/status.d.ts.map +1 -0
- package/dist/cli/commands/status.js +259 -0
- package/dist/cli/commands/status.js.map +1 -0
- package/dist/cli/commands/stories.d.ts +3 -0
- package/dist/cli/commands/stories.d.ts.map +1 -0
- package/dist/cli/commands/stories.js +111 -0
- package/dist/cli/commands/stories.js.map +1 -0
- package/dist/cli/commands/teams.d.ts +3 -0
- package/dist/cli/commands/teams.d.ts.map +1 -0
- package/dist/cli/commands/teams.js +137 -0
- package/dist/cli/commands/teams.js.map +1 -0
- package/dist/cli/dashboard/index.d.ts +5 -0
- package/dist/cli/dashboard/index.d.ts.map +1 -0
- package/dist/cli/dashboard/index.js +128 -0
- package/dist/cli/dashboard/index.js.map +1 -0
- package/dist/cli/dashboard/panels/activity.d.ts +5 -0
- package/dist/cli/dashboard/panels/activity.d.ts.map +1 -0
- package/dist/cli/dashboard/panels/activity.js +64 -0
- package/dist/cli/dashboard/panels/activity.js.map +1 -0
- package/dist/cli/dashboard/panels/agents.d.ts +5 -0
- package/dist/cli/dashboard/panels/agents.d.ts.map +1 -0
- package/dist/cli/dashboard/panels/agents.js +196 -0
- package/dist/cli/dashboard/panels/agents.js.map +1 -0
- package/dist/cli/dashboard/panels/escalations.d.ts +5 -0
- package/dist/cli/dashboard/panels/escalations.d.ts.map +1 -0
- package/dist/cli/dashboard/panels/escalations.js +93 -0
- package/dist/cli/dashboard/panels/escalations.js.map +1 -0
- package/dist/cli/dashboard/panels/merge-queue.d.ts +5 -0
- package/dist/cli/dashboard/panels/merge-queue.d.ts.map +1 -0
- package/dist/cli/dashboard/panels/merge-queue.js +57 -0
- package/dist/cli/dashboard/panels/merge-queue.js.map +1 -0
- package/dist/cli/dashboard/panels/pipeline.d.ts +5 -0
- package/dist/cli/dashboard/panels/pipeline.d.ts.map +1 -0
- package/dist/cli/dashboard/panels/pipeline.js +54 -0
- package/dist/cli/dashboard/panels/pipeline.js.map +1 -0
- package/dist/cli/dashboard/panels/stories.d.ts +5 -0
- package/dist/cli/dashboard/panels/stories.d.ts.map +1 -0
- package/dist/cli/dashboard/panels/stories.js +79 -0
- package/dist/cli/dashboard/panels/stories.js.map +1 -0
- package/dist/cli-runtimes/claude.d.ts +8 -0
- package/dist/cli-runtimes/claude.d.ts.map +1 -0
- package/dist/cli-runtimes/claude.js +27 -0
- package/dist/cli-runtimes/claude.js.map +1 -0
- package/dist/cli-runtimes/codex.d.ts +8 -0
- package/dist/cli-runtimes/codex.d.ts.map +1 -0
- package/dist/cli-runtimes/codex.js +27 -0
- package/dist/cli-runtimes/codex.js.map +1 -0
- package/dist/cli-runtimes/gemini.d.ts +8 -0
- package/dist/cli-runtimes/gemini.d.ts.map +1 -0
- package/dist/cli-runtimes/gemini.js +29 -0
- package/dist/cli-runtimes/gemini.js.map +1 -0
- package/dist/cli-runtimes/index.d.ts +25 -0
- package/dist/cli-runtimes/index.d.ts.map +1 -0
- package/dist/cli-runtimes/index.js +48 -0
- package/dist/cli-runtimes/index.js.map +1 -0
- package/dist/cli-runtimes/index.test.d.ts +2 -0
- package/dist/cli-runtimes/index.test.d.ts.map +1 -0
- package/dist/cli-runtimes/index.test.js +216 -0
- package/dist/cli-runtimes/index.test.js.map +1 -0
- package/dist/cli-runtimes/types.d.ts +27 -0
- package/dist/cli-runtimes/types.d.ts.map +1 -0
- package/dist/cli-runtimes/types.js +2 -0
- package/dist/cli-runtimes/types.js.map +1 -0
- package/dist/config/index.d.ts +3 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +3 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/loader.d.ts +11 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +72 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/schema.d.ts +660 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +217 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/config/schema.test.d.ts +2 -0
- package/dist/config/schema.test.d.ts.map +1 -0
- package/dist/config/schema.test.js +123 -0
- package/dist/config/schema.test.js.map +1 -0
- package/dist/context-files/generator.d.ts +32 -0
- package/dist/context-files/generator.d.ts.map +1 -0
- package/dist/context-files/generator.js +120 -0
- package/dist/context-files/generator.js.map +1 -0
- package/dist/context-files/index.d.ts +38 -0
- package/dist/context-files/index.d.ts.map +1 -0
- package/dist/context-files/index.js +76 -0
- package/dist/context-files/index.js.map +1 -0
- package/dist/context-files/index.test.d.ts +2 -0
- package/dist/context-files/index.test.d.ts.map +1 -0
- package/dist/context-files/index.test.js +265 -0
- package/dist/context-files/index.test.js.map +1 -0
- package/dist/context-files/templates.d.ts +19 -0
- package/dist/context-files/templates.d.ts.map +1 -0
- package/dist/context-files/templates.js +266 -0
- package/dist/context-files/templates.js.map +1 -0
- package/dist/db/client.d.ts +95 -0
- package/dist/db/client.d.ts.map +1 -0
- package/dist/db/client.js +343 -0
- package/dist/db/client.js.map +1 -0
- package/dist/db/lock.d.ts +25 -0
- package/dist/db/lock.d.ts.map +1 -0
- package/dist/db/lock.js +56 -0
- package/dist/db/lock.js.map +1 -0
- package/dist/db/lock.test.d.ts +2 -0
- package/dist/db/lock.test.d.ts.map +1 -0
- package/dist/db/lock.test.js +73 -0
- package/dist/db/lock.test.js.map +1 -0
- package/dist/db/queries/agents.d.ts +31 -0
- package/dist/db/queries/agents.d.ts.map +1 -0
- package/dist/db/queries/agents.js +76 -0
- package/dist/db/queries/agents.js.map +1 -0
- package/dist/db/queries/escalations.d.ts +29 -0
- package/dist/db/queries/escalations.d.ts.map +1 -0
- package/dist/db/queries/escalations.js +105 -0
- package/dist/db/queries/escalations.js.map +1 -0
- package/dist/db/queries/heartbeat.d.ts +20 -0
- package/dist/db/queries/heartbeat.d.ts.map +1 -0
- package/dist/db/queries/heartbeat.js +61 -0
- package/dist/db/queries/heartbeat.js.map +1 -0
- package/dist/db/queries/index.d.ts +8 -0
- package/dist/db/queries/index.d.ts.map +1 -0
- package/dist/db/queries/index.js +8 -0
- package/dist/db/queries/index.js.map +1 -0
- package/dist/db/queries/logs.d.ts +21 -0
- package/dist/db/queries/logs.d.ts.map +1 -0
- package/dist/db/queries/logs.js +72 -0
- package/dist/db/queries/logs.js.map +1 -0
- package/dist/db/queries/messages.d.ts +17 -0
- package/dist/db/queries/messages.d.ts.map +1 -0
- package/dist/db/queries/messages.js +22 -0
- package/dist/db/queries/messages.js.map +1 -0
- package/dist/db/queries/pull-requests.d.ts +33 -0
- package/dist/db/queries/pull-requests.d.ts.map +1 -0
- package/dist/db/queries/pull-requests.js +130 -0
- package/dist/db/queries/pull-requests.js.map +1 -0
- package/dist/db/queries/requirements.d.ts +22 -0
- package/dist/db/queries/requirements.d.ts.map +1 -0
- package/dist/db/queries/requirements.js +53 -0
- package/dist/db/queries/requirements.js.map +1 -0
- package/dist/db/queries/stories.d.ts +42 -0
- package/dist/db/queries/stories.d.ts.map +1 -0
- package/dist/db/queries/stories.js +163 -0
- package/dist/db/queries/stories.js.map +1 -0
- package/dist/db/queries/teams.d.ts +14 -0
- package/dist/db/queries/teams.d.ts.map +1 -0
- package/dist/db/queries/teams.js +24 -0
- package/dist/db/queries/teams.js.map +1 -0
- package/dist/git/branches.d.ts +52 -0
- package/dist/git/branches.d.ts.map +1 -0
- package/dist/git/branches.js +133 -0
- package/dist/git/branches.js.map +1 -0
- package/dist/git/github.d.ts +75 -0
- package/dist/git/github.d.ts.map +1 -0
- package/dist/git/github.js +162 -0
- package/dist/git/github.js.map +1 -0
- package/dist/git/index.d.ts +4 -0
- package/dist/git/index.d.ts.map +1 -0
- package/dist/git/index.js +4 -0
- package/dist/git/index.js.map +1 -0
- package/dist/git/submodules.d.ts +47 -0
- package/dist/git/submodules.d.ts.map +1 -0
- package/dist/git/submodules.js +115 -0
- package/dist/git/submodules.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +62 -0
- package/dist/index.js.map +1 -0
- package/dist/llm/anthropic.d.ts +18 -0
- package/dist/llm/anthropic.d.ts.map +1 -0
- package/dist/llm/anthropic.js +111 -0
- package/dist/llm/anthropic.js.map +1 -0
- package/dist/llm/index.d.ts +6 -0
- package/dist/llm/index.d.ts.map +1 -0
- package/dist/llm/index.js +24 -0
- package/dist/llm/index.js.map +1 -0
- package/dist/llm/openai.d.ts +18 -0
- package/dist/llm/openai.d.ts.map +1 -0
- package/dist/llm/openai.js +103 -0
- package/dist/llm/openai.js.map +1 -0
- package/dist/llm/provider.d.ts +38 -0
- package/dist/llm/provider.d.ts.map +1 -0
- package/dist/llm/provider.js +17 -0
- package/dist/llm/provider.js.map +1 -0
- package/dist/orchestrator/index.d.ts +4 -0
- package/dist/orchestrator/index.d.ts.map +1 -0
- package/dist/orchestrator/index.js +4 -0
- package/dist/orchestrator/index.js.map +1 -0
- package/dist/orchestrator/scaler.d.ts +42 -0
- package/dist/orchestrator/scaler.d.ts.map +1 -0
- package/dist/orchestrator/scaler.js +154 -0
- package/dist/orchestrator/scaler.js.map +1 -0
- package/dist/orchestrator/scheduler.d.ts +90 -0
- package/dist/orchestrator/scheduler.d.ts.map +1 -0
- package/dist/orchestrator/scheduler.js +1003 -0
- package/dist/orchestrator/scheduler.js.map +1 -0
- package/dist/orchestrator/scheduler.test.d.ts +2 -0
- package/dist/orchestrator/scheduler.test.d.ts.map +1 -0
- package/dist/orchestrator/scheduler.test.js +242 -0
- package/dist/orchestrator/scheduler.test.js.map +1 -0
- package/dist/orchestrator/workflow.d.ts +18 -0
- package/dist/orchestrator/workflow.d.ts.map +1 -0
- package/dist/orchestrator/workflow.js +106 -0
- package/dist/orchestrator/workflow.js.map +1 -0
- package/dist/state-detectors/claude.d.ts +33 -0
- package/dist/state-detectors/claude.d.ts.map +1 -0
- package/dist/state-detectors/claude.js +237 -0
- package/dist/state-detectors/claude.js.map +1 -0
- package/dist/state-detectors/claude.test.d.ts +2 -0
- package/dist/state-detectors/claude.test.d.ts.map +1 -0
- package/dist/state-detectors/claude.test.js +127 -0
- package/dist/state-detectors/claude.test.js.map +1 -0
- package/dist/state-detectors/codex.d.ts +34 -0
- package/dist/state-detectors/codex.d.ts.map +1 -0
- package/dist/state-detectors/codex.js +233 -0
- package/dist/state-detectors/codex.js.map +1 -0
- package/dist/state-detectors/codex.test.d.ts +2 -0
- package/dist/state-detectors/codex.test.d.ts.map +1 -0
- package/dist/state-detectors/codex.test.js +85 -0
- package/dist/state-detectors/codex.test.js.map +1 -0
- package/dist/state-detectors/factory.d.ts +22 -0
- package/dist/state-detectors/factory.d.ts.map +1 -0
- package/dist/state-detectors/factory.js +37 -0
- package/dist/state-detectors/factory.js.map +1 -0
- package/dist/state-detectors/factory.test.d.ts +2 -0
- package/dist/state-detectors/factory.test.d.ts.map +1 -0
- package/dist/state-detectors/factory.test.js +44 -0
- package/dist/state-detectors/factory.test.js.map +1 -0
- package/dist/state-detectors/gemini.d.ts +34 -0
- package/dist/state-detectors/gemini.d.ts.map +1 -0
- package/dist/state-detectors/gemini.js +236 -0
- package/dist/state-detectors/gemini.js.map +1 -0
- package/dist/state-detectors/gemini.test.d.ts +2 -0
- package/dist/state-detectors/gemini.test.d.ts.map +1 -0
- package/dist/state-detectors/gemini.test.js +93 -0
- package/dist/state-detectors/gemini.test.js.map +1 -0
- package/dist/state-detectors/index.d.ts +20 -0
- package/dist/state-detectors/index.d.ts.map +1 -0
- package/dist/state-detectors/index.js +21 -0
- package/dist/state-detectors/index.js.map +1 -0
- package/dist/state-detectors/types.d.ts +67 -0
- package/dist/state-detectors/types.d.ts.map +1 -0
- package/dist/state-detectors/types.js +28 -0
- package/dist/state-detectors/types.js.map +1 -0
- package/dist/tmux/index.d.ts +2 -0
- package/dist/tmux/index.d.ts.map +1 -0
- package/dist/tmux/index.js +2 -0
- package/dist/tmux/index.js.map +1 -0
- package/dist/tmux/manager.d.ts +45 -0
- package/dist/tmux/manager.d.ts.map +1 -0
- package/dist/tmux/manager.js +252 -0
- package/dist/tmux/manager.js.map +1 -0
- package/dist/utils/claude-code-state.d.ts +46 -0
- package/dist/utils/claude-code-state.d.ts.map +1 -0
- package/dist/utils/claude-code-state.js +252 -0
- package/dist/utils/claude-code-state.js.map +1 -0
- package/dist/utils/cli-builder.d.ts +19 -0
- package/dist/utils/cli-builder.d.ts.map +1 -0
- package/dist/utils/cli-builder.js +58 -0
- package/dist/utils/cli-builder.js.map +1 -0
- package/dist/utils/cli-commands.d.ts +27 -0
- package/dist/utils/cli-commands.d.ts.map +1 -0
- package/dist/utils/cli-commands.js +69 -0
- package/dist/utils/cli-commands.js.map +1 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +3 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/logger.d.ts +13 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +77 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/paths.d.ts +17 -0
- package/dist/utils/paths.d.ts.map +1 -0
- package/dist/utils/paths.js +33 -0
- package/dist/utils/paths.js.map +1 -0
- package/dist/utils/timeout.d.ts +25 -0
- package/dist/utils/timeout.d.ts.map +1 -0
- package/dist/utils/timeout.js +57 -0
- package/dist/utils/timeout.js.map +1 -0
- package/package.json +78 -0
- package/src/agents/base-agent.ts +255 -0
- package/src/agents/index.ts +6 -0
- package/src/agents/intermediate.ts +161 -0
- package/src/agents/junior.ts +166 -0
- package/src/agents/qa.ts +272 -0
- package/src/agents/senior.ts +307 -0
- package/src/agents/tech-lead.ts +324 -0
- package/src/cli/commands/add-repo.ts +89 -0
- package/src/cli/commands/agents.ts +247 -0
- package/src/cli/commands/assign.ts +86 -0
- package/src/cli/commands/config.ts +121 -0
- package/src/cli/commands/escalations.ts +179 -0
- package/src/cli/commands/index.ts +16 -0
- package/src/cli/commands/init.ts +66 -0
- package/src/cli/commands/manager.test.ts +52 -0
- package/src/cli/commands/manager.ts +916 -0
- package/src/cli/commands/msg.ts +232 -0
- package/src/cli/commands/my-stories.ts +198 -0
- package/src/cli/commands/nuke.ts +223 -0
- package/src/cli/commands/pr.ts +559 -0
- package/src/cli/commands/req.ts +231 -0
- package/src/cli/commands/resume.ts +129 -0
- package/src/cli/commands/status.ts +284 -0
- package/src/cli/commands/stories.ts +131 -0
- package/src/cli/commands/teams.ts +158 -0
- package/src/cli/dashboard/index.ts +141 -0
- package/src/cli/dashboard/panels/activity.ts +77 -0
- package/src/cli/dashboard/panels/agents.ts +244 -0
- package/src/cli/dashboard/panels/escalations.ts +109 -0
- package/src/cli/dashboard/panels/merge-queue.ts +65 -0
- package/src/cli/dashboard/panels/pipeline.ts +65 -0
- package/src/cli/dashboard/panels/stories.ts +87 -0
- package/src/cli-runtimes/claude.ts +31 -0
- package/src/cli-runtimes/codex.ts +31 -0
- package/src/cli-runtimes/gemini.ts +33 -0
- package/src/cli-runtimes/index.test.ts +261 -0
- package/src/cli-runtimes/index.ts +52 -0
- package/src/cli-runtimes/types.ts +30 -0
- package/src/config/index.ts +2 -0
- package/src/config/loader.ts +89 -0
- package/src/config/schema.test.ts +135 -0
- package/src/config/schema.ts +238 -0
- package/src/context-files/generator.ts +132 -0
- package/src/context-files/index.test.ts +323 -0
- package/src/context-files/index.ts +102 -0
- package/src/context-files/templates.ts +279 -0
- package/src/db/client.ts +475 -0
- package/src/db/lock.test.ts +93 -0
- package/src/db/lock.ts +74 -0
- package/src/db/migrations/001-initial.sql +121 -0
- package/src/db/migrations/005-add-agent-heartbeat.sql +4 -0
- package/src/db/queries/agents.ts +113 -0
- package/src/db/queries/escalations.ts +140 -0
- package/src/db/queries/heartbeat.ts +92 -0
- package/src/db/queries/index.ts +7 -0
- package/src/db/queries/logs.ts +136 -0
- package/src/db/queries/messages.ts +38 -0
- package/src/db/queries/pull-requests.ts +170 -0
- package/src/db/queries/requirements.ts +81 -0
- package/src/db/queries/stories.ts +223 -0
- package/src/db/queries/teams.ts +39 -0
- package/src/git/branches.ts +186 -0
- package/src/git/github.ts +247 -0
- package/src/git/index.ts +3 -0
- package/src/git/submodules.ts +141 -0
- package/src/index.ts +93 -0
- package/src/llm/anthropic.ts +134 -0
- package/src/llm/index.ts +26 -0
- package/src/llm/openai.ts +125 -0
- package/src/llm/provider.ts +60 -0
- package/src/orchestrator/index.ts +3 -0
- package/src/orchestrator/scaler.ts +201 -0
- package/src/orchestrator/scheduler.test.ts +288 -0
- package/src/orchestrator/scheduler.ts +1130 -0
- package/src/orchestrator/workflow.ts +137 -0
- package/src/state-detectors/claude.test.ts +149 -0
- package/src/state-detectors/claude.ts +256 -0
- package/src/state-detectors/codex.test.ts +100 -0
- package/src/state-detectors/codex.ts +252 -0
- package/src/state-detectors/factory.test.ts +51 -0
- package/src/state-detectors/factory.ts +40 -0
- package/src/state-detectors/gemini.test.ts +110 -0
- package/src/state-detectors/gemini.ts +255 -0
- package/src/state-detectors/index.ts +25 -0
- package/src/state-detectors/types.ts +80 -0
- package/src/tmux/index.ts +1 -0
- package/src/tmux/manager.ts +310 -0
- package/src/types/sql.js.d.ts +34 -0
- package/src/utils/claude-code-state.ts +281 -0
- package/src/utils/cli-builder.ts +78 -0
- package/src/utils/cli-commands.ts +84 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/logger.ts +93 -0
- package/src/utils/paths.ts +49 -0
- package/src/utils/timeout.ts +84 -0
- package/tsconfig.json +25 -0
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import type { Database } from 'sql.js';
|
|
2
|
+
import type { StoryStatus } from '../db/queries/stories.js';
|
|
3
|
+
import { queryAll, queryOne } from '../db/client.js';
|
|
4
|
+
|
|
5
|
+
// Valid story status transitions
|
|
6
|
+
const STORY_TRANSITIONS: Record<StoryStatus, StoryStatus[]> = {
|
|
7
|
+
draft: ['estimated'],
|
|
8
|
+
estimated: ['planned'],
|
|
9
|
+
planned: ['in_progress'],
|
|
10
|
+
in_progress: ['review', 'qa_failed'],
|
|
11
|
+
review: ['in_progress', 'qa'],
|
|
12
|
+
qa: ['qa_failed', 'pr_submitted'],
|
|
13
|
+
qa_failed: ['in_progress'],
|
|
14
|
+
pr_submitted: ['merged'],
|
|
15
|
+
merged: [],
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export function canTransitionStory(from: StoryStatus, to: StoryStatus): boolean {
|
|
19
|
+
return STORY_TRANSITIONS[from]?.includes(to) ?? false;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function getNextStatuses(status: StoryStatus): StoryStatus[] {
|
|
23
|
+
return STORY_TRANSITIONS[status] || [];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export type RequirementStatus = 'pending' | 'planning' | 'planned' | 'in_progress' | 'completed';
|
|
27
|
+
|
|
28
|
+
const REQUIREMENT_TRANSITIONS: Record<RequirementStatus, RequirementStatus[]> = {
|
|
29
|
+
pending: ['planning'],
|
|
30
|
+
planning: ['planned'],
|
|
31
|
+
planned: ['in_progress'],
|
|
32
|
+
in_progress: ['completed'],
|
|
33
|
+
completed: [],
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export function canTransitionRequirement(from: RequirementStatus, to: RequirementStatus): boolean {
|
|
37
|
+
return REQUIREMENT_TRANSITIONS[from]?.includes(to) ?? false;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Workflow phase tracking
|
|
41
|
+
export type WorkflowPhase =
|
|
42
|
+
| 'idle'
|
|
43
|
+
| 'requirement_intake'
|
|
44
|
+
| 'planning'
|
|
45
|
+
| 'estimation'
|
|
46
|
+
| 'development'
|
|
47
|
+
| 'review'
|
|
48
|
+
| 'qa'
|
|
49
|
+
| 'pr_submission'
|
|
50
|
+
| 'completed';
|
|
51
|
+
|
|
52
|
+
export interface WorkflowState {
|
|
53
|
+
phase: WorkflowPhase;
|
|
54
|
+
requirementId?: string;
|
|
55
|
+
activeStories: number;
|
|
56
|
+
completedStories: number;
|
|
57
|
+
blockedStories: number;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function getWorkflowState(db: Database, requirementId?: string): WorkflowState {
|
|
61
|
+
let whereClause = '';
|
|
62
|
+
const params: string[] = [];
|
|
63
|
+
|
|
64
|
+
if (requirementId) {
|
|
65
|
+
whereClause = 'WHERE requirement_id = ?';
|
|
66
|
+
params.push(requirementId);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const stories = queryAll<{ status: StoryStatus; count: number }>(db, `
|
|
70
|
+
SELECT status, COUNT(*) as count
|
|
71
|
+
FROM stories
|
|
72
|
+
${whereClause}
|
|
73
|
+
GROUP BY status
|
|
74
|
+
`, params);
|
|
75
|
+
|
|
76
|
+
const counts: Record<string, number> = {};
|
|
77
|
+
for (const row of stories) {
|
|
78
|
+
counts[row.status] = row.count;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const activeStories =
|
|
82
|
+
(counts.in_progress || 0) +
|
|
83
|
+
(counts.review || 0) +
|
|
84
|
+
(counts.qa || 0);
|
|
85
|
+
|
|
86
|
+
const completedStories =
|
|
87
|
+
(counts.pr_submitted || 0) +
|
|
88
|
+
(counts.merged || 0);
|
|
89
|
+
|
|
90
|
+
const blockedStories = counts.qa_failed || 0;
|
|
91
|
+
|
|
92
|
+
// Determine current phase
|
|
93
|
+
let phase: WorkflowPhase = 'idle';
|
|
94
|
+
|
|
95
|
+
if (counts.merged && completedStories === Object.values(counts).reduce((a, b) => a + b, 0)) {
|
|
96
|
+
phase = 'completed';
|
|
97
|
+
} else if (counts.pr_submitted) {
|
|
98
|
+
phase = 'pr_submission';
|
|
99
|
+
} else if (counts.qa) {
|
|
100
|
+
phase = 'qa';
|
|
101
|
+
} else if (counts.review) {
|
|
102
|
+
phase = 'review';
|
|
103
|
+
} else if (counts.in_progress) {
|
|
104
|
+
phase = 'development';
|
|
105
|
+
} else if (counts.planned) {
|
|
106
|
+
phase = 'development'; // Ready to start development
|
|
107
|
+
} else if (counts.estimated) {
|
|
108
|
+
phase = 'estimation';
|
|
109
|
+
} else if (counts.draft) {
|
|
110
|
+
phase = 'planning';
|
|
111
|
+
} else if (requirementId) {
|
|
112
|
+
// Check requirement status
|
|
113
|
+
const req = queryOne<{ status: string }>(db, 'SELECT status FROM requirements WHERE id = ?', [requirementId]);
|
|
114
|
+
if (req) {
|
|
115
|
+
if (req.status === 'planning') phase = 'planning';
|
|
116
|
+
else if (req.status === 'pending') phase = 'requirement_intake';
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return {
|
|
121
|
+
phase,
|
|
122
|
+
requirementId,
|
|
123
|
+
activeStories,
|
|
124
|
+
completedStories,
|
|
125
|
+
blockedStories,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function isWorkflowBlocked(state: WorkflowState): boolean {
|
|
130
|
+
return state.blockedStories > 0;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export function getWorkflowProgress(state: WorkflowState): number {
|
|
134
|
+
const total = state.activeStories + state.completedStories + state.blockedStories;
|
|
135
|
+
if (total === 0) return 0;
|
|
136
|
+
return Math.round((state.completedStories / total) * 100);
|
|
137
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { ClaudeStateDetector } from './claude.js';
|
|
3
|
+
import { AgentState } from './types.js';
|
|
4
|
+
|
|
5
|
+
describe('ClaudeStateDetector', () => {
|
|
6
|
+
const detector = new ClaudeStateDetector();
|
|
7
|
+
|
|
8
|
+
describe('detectState', () => {
|
|
9
|
+
it('should detect THINKING state', () => {
|
|
10
|
+
const result = detector.detectState('(thinking) about the problem');
|
|
11
|
+
expect(result.state).toBe(AgentState.THINKING);
|
|
12
|
+
expect(result.confidence).toBe(0.9);
|
|
13
|
+
expect(result.isWaiting).toBe(false);
|
|
14
|
+
expect(result.needsHuman).toBe(false);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('should detect THINKING state with action words', () => {
|
|
18
|
+
const result = detector.detectState('Analyzing the code structure...');
|
|
19
|
+
expect(result.state).toBe(AgentState.THINKING);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('should detect TOOL_RUNNING state', () => {
|
|
23
|
+
const result = detector.detectState('Running tests... (esc to interrupt)');
|
|
24
|
+
expect(result.state).toBe(AgentState.TOOL_RUNNING);
|
|
25
|
+
expect(result.isWaiting).toBe(false);
|
|
26
|
+
expect(result.needsHuman).toBe(false);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('should detect TOOL_RUNNING with progress bar', () => {
|
|
30
|
+
const result = detector.detectState('[=====> ] 50%');
|
|
31
|
+
expect(result.state).toBe(AgentState.TOOL_RUNNING);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should detect PROCESSING state', () => {
|
|
35
|
+
const result = detector.detectState('Processing your request...');
|
|
36
|
+
expect(result.state).toBe(AgentState.PROCESSING);
|
|
37
|
+
expect(result.isWaiting).toBe(false);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('should detect AWAITING_SELECTION state', () => {
|
|
41
|
+
const result = detector.detectState('Enter to select ↑/↓ to navigate');
|
|
42
|
+
expect(result.state).toBe(AgentState.AWAITING_SELECTION);
|
|
43
|
+
expect(result.isWaiting).toBe(true);
|
|
44
|
+
expect(result.needsHuman).toBe(true);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('should detect ASKING_QUESTION state', () => {
|
|
48
|
+
const result = detector.detectState('Would you like to continue?');
|
|
49
|
+
expect(result.state).toBe(AgentState.ASKING_QUESTION);
|
|
50
|
+
expect(result.needsHuman).toBe(true);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('should detect ASKING_QUESTION with question mark', () => {
|
|
54
|
+
const result = detector.detectState('Should I proceed with this change?');
|
|
55
|
+
expect(result.state).toBe(AgentState.ASKING_QUESTION);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('should detect PLAN_APPROVAL state', () => {
|
|
59
|
+
const result = detector.detectState('Please review the plan and approve');
|
|
60
|
+
expect(result.state).toBe(AgentState.PLAN_APPROVAL);
|
|
61
|
+
expect(result.needsHuman).toBe(true);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('should detect PERMISSION_REQUIRED state', () => {
|
|
65
|
+
const result = detector.detectState('Permission required: Allow access [y/n]');
|
|
66
|
+
expect(result.state).toBe(AgentState.PERMISSION_REQUIRED);
|
|
67
|
+
expect(result.needsHuman).toBe(true);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('should detect USER_DECLINED state', () => {
|
|
71
|
+
const result = detector.detectState('User declined the operation');
|
|
72
|
+
expect(result.state).toBe(AgentState.USER_DECLINED);
|
|
73
|
+
expect(result.needsHuman).toBe(true);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('should detect WORK_COMPLETE state', () => {
|
|
77
|
+
const result = detector.detectState('Task completed successfully');
|
|
78
|
+
expect(result.state).toBe(AgentState.WORK_COMPLETE);
|
|
79
|
+
expect(result.isWaiting).toBe(true);
|
|
80
|
+
expect(result.needsHuman).toBe(false);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('should detect IDLE_AT_PROMPT state', () => {
|
|
84
|
+
const result = detector.detectState('>\n');
|
|
85
|
+
expect(result.state).toBe(AgentState.IDLE_AT_PROMPT);
|
|
86
|
+
expect(result.isWaiting).toBe(true);
|
|
87
|
+
expect(result.needsHuman).toBe(false);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('should return UNKNOWN for unclear output', () => {
|
|
91
|
+
const result = detector.detectState('Some random text');
|
|
92
|
+
expect(result.state).toBe(AgentState.UNKNOWN);
|
|
93
|
+
expect(result.confidence).toBe(0.3);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('should prioritize higher priority patterns', () => {
|
|
97
|
+
// TOOL_RUNNING (priority 100) should win over PROCESSING (priority 90)
|
|
98
|
+
const result = detector.detectState('Executing and Processing');
|
|
99
|
+
expect(result.state).toBe(AgentState.TOOL_RUNNING);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
describe('getStateDescription', () => {
|
|
104
|
+
it('should return description for THINKING', () => {
|
|
105
|
+
const desc = detector.getStateDescription(AgentState.THINKING);
|
|
106
|
+
expect(desc).toBe('Claude is thinking');
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('should return description for PERMISSION_REQUIRED', () => {
|
|
110
|
+
const desc = detector.getStateDescription(AgentState.PERMISSION_REQUIRED);
|
|
111
|
+
expect(desc).toBe('Permission required');
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('should return description for UNKNOWN', () => {
|
|
115
|
+
const desc = detector.getStateDescription(AgentState.UNKNOWN);
|
|
116
|
+
expect(desc).toBe('Unknown state');
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
describe('isActiveState', () => {
|
|
121
|
+
it('should return true for active states', () => {
|
|
122
|
+
expect(detector.isActiveState(AgentState.THINKING)).toBe(true);
|
|
123
|
+
expect(detector.isActiveState(AgentState.TOOL_RUNNING)).toBe(true);
|
|
124
|
+
expect(detector.isActiveState(AgentState.PROCESSING)).toBe(true);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it('should return false for non-active states', () => {
|
|
128
|
+
expect(detector.isActiveState(AgentState.IDLE_AT_PROMPT)).toBe(false);
|
|
129
|
+
expect(detector.isActiveState(AgentState.ASKING_QUESTION)).toBe(false);
|
|
130
|
+
expect(detector.isActiveState(AgentState.UNKNOWN)).toBe(false);
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
describe('isBlockedState', () => {
|
|
135
|
+
it('should return true for blocked states', () => {
|
|
136
|
+
expect(detector.isBlockedState(AgentState.ASKING_QUESTION)).toBe(true);
|
|
137
|
+
expect(detector.isBlockedState(AgentState.AWAITING_SELECTION)).toBe(true);
|
|
138
|
+
expect(detector.isBlockedState(AgentState.PLAN_APPROVAL)).toBe(true);
|
|
139
|
+
expect(detector.isBlockedState(AgentState.PERMISSION_REQUIRED)).toBe(true);
|
|
140
|
+
expect(detector.isBlockedState(AgentState.USER_DECLINED)).toBe(true);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('should return false for non-blocked states', () => {
|
|
144
|
+
expect(detector.isBlockedState(AgentState.THINKING)).toBe(false);
|
|
145
|
+
expect(detector.isBlockedState(AgentState.IDLE_AT_PROMPT)).toBe(false);
|
|
146
|
+
expect(detector.isBlockedState(AgentState.WORK_COMPLETE)).toBe(false);
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
});
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code State Detector
|
|
3
|
+
*
|
|
4
|
+
* Detects the UI state of Claude Code CLI based on output patterns
|
|
5
|
+
* Refactored from src/utils/claude-code-state.ts
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { AgentState, StateDetectionResult, StateDetector } from './types.js';
|
|
9
|
+
|
|
10
|
+
interface StateIndicator {
|
|
11
|
+
state: AgentState;
|
|
12
|
+
patterns: RegExp[];
|
|
13
|
+
priority: number;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Priority-based state indicators for Claude Code
|
|
18
|
+
* Higher priority patterns are checked first to handle overlapping indicators
|
|
19
|
+
*/
|
|
20
|
+
const CLAUDE_STATE_INDICATORS: StateIndicator[] = [
|
|
21
|
+
// High priority: Active work states
|
|
22
|
+
{
|
|
23
|
+
state: AgentState.THINKING,
|
|
24
|
+
patterns: [
|
|
25
|
+
/\(thinking\)/i,
|
|
26
|
+
/Concocting|Twisting|Considering|Analyzing/i,
|
|
27
|
+
],
|
|
28
|
+
priority: 100,
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
state: AgentState.TOOL_RUNNING,
|
|
32
|
+
patterns: [
|
|
33
|
+
/esc to interrupt/i,
|
|
34
|
+
/Running|Executing/i,
|
|
35
|
+
/\[.*\]\s+\d+%/i, // Progress bars
|
|
36
|
+
],
|
|
37
|
+
priority: 100,
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
state: AgentState.PROCESSING,
|
|
41
|
+
patterns: [
|
|
42
|
+
/Processing|Analyzing|Generating/i,
|
|
43
|
+
/Please wait/i,
|
|
44
|
+
],
|
|
45
|
+
priority: 90,
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
// High priority: Blocked states requiring human intervention
|
|
49
|
+
{
|
|
50
|
+
state: AgentState.AWAITING_SELECTION,
|
|
51
|
+
patterns: [
|
|
52
|
+
/Enter to select.*↑\/↓/i,
|
|
53
|
+
/Use arrows to navigate/i,
|
|
54
|
+
/Select an option/i,
|
|
55
|
+
],
|
|
56
|
+
priority: 90,
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
state: AgentState.ASKING_QUESTION,
|
|
60
|
+
patterns: [
|
|
61
|
+
/\?\s*$/m, // Line ending with question mark
|
|
62
|
+
/Please (choose|select|confirm)/i,
|
|
63
|
+
/Would you like to/i,
|
|
64
|
+
/Do you want to/i,
|
|
65
|
+
],
|
|
66
|
+
priority: 85,
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
state: AgentState.PLAN_APPROVAL,
|
|
70
|
+
patterns: [
|
|
71
|
+
/approve.*plan/i,
|
|
72
|
+
/review.*plan/i,
|
|
73
|
+
/proceed.*plan/i,
|
|
74
|
+
/ExitPlanMode/i,
|
|
75
|
+
],
|
|
76
|
+
priority: 90,
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
state: AgentState.PERMISSION_REQUIRED,
|
|
80
|
+
patterns: [
|
|
81
|
+
/permission.*required/i,
|
|
82
|
+
/authorize/i,
|
|
83
|
+
/Allow.*\[y\/n\]/i,
|
|
84
|
+
/Approve.*\[y\/n\]/i,
|
|
85
|
+
],
|
|
86
|
+
priority: 90,
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
state: AgentState.USER_DECLINED,
|
|
90
|
+
patterns: [
|
|
91
|
+
/declined/i,
|
|
92
|
+
/permission denied/i,
|
|
93
|
+
/User chose not to/i,
|
|
94
|
+
],
|
|
95
|
+
priority: 85,
|
|
96
|
+
},
|
|
97
|
+
|
|
98
|
+
// Lower priority: Ready/idle states
|
|
99
|
+
{
|
|
100
|
+
state: AgentState.WORK_COMPLETE,
|
|
101
|
+
patterns: [
|
|
102
|
+
/done|complete|finished/i,
|
|
103
|
+
/successfully/i,
|
|
104
|
+
/All.*tests passed/i,
|
|
105
|
+
],
|
|
106
|
+
priority: 50,
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
state: AgentState.IDLE_AT_PROMPT,
|
|
110
|
+
patterns: [
|
|
111
|
+
/^>\s*$/m, // Prompt alone on line
|
|
112
|
+
/Ready for input/i,
|
|
113
|
+
/What would you like/i,
|
|
114
|
+
],
|
|
115
|
+
priority: 40,
|
|
116
|
+
},
|
|
117
|
+
];
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Claude Code State Detector Implementation
|
|
121
|
+
*/
|
|
122
|
+
export class ClaudeStateDetector implements StateDetector {
|
|
123
|
+
/**
|
|
124
|
+
* Detect the current Claude Code UI state from output text
|
|
125
|
+
*/
|
|
126
|
+
detectState(output: string): StateDetectionResult {
|
|
127
|
+
// Sort indicators by priority (highest first)
|
|
128
|
+
const sortedIndicators = [...CLAUDE_STATE_INDICATORS].sort((a, b) => b.priority - a.priority);
|
|
129
|
+
|
|
130
|
+
// Check each indicator in priority order
|
|
131
|
+
for (const indicator of sortedIndicators) {
|
|
132
|
+
for (const pattern of indicator.patterns) {
|
|
133
|
+
if (pattern.test(output)) {
|
|
134
|
+
const result = this.mapStateToWaitingStatus(indicator.state);
|
|
135
|
+
return {
|
|
136
|
+
...result,
|
|
137
|
+
confidence: 0.9,
|
|
138
|
+
reason: `Detected pattern for ${indicator.state}`,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// No clear state detected
|
|
145
|
+
return {
|
|
146
|
+
state: AgentState.UNKNOWN,
|
|
147
|
+
confidence: 0.3,
|
|
148
|
+
reason: 'No clear state indicators found',
|
|
149
|
+
isWaiting: false,
|
|
150
|
+
needsHuman: false,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Get a human-readable description of a state
|
|
156
|
+
*/
|
|
157
|
+
getStateDescription(state: AgentState): string {
|
|
158
|
+
switch (state) {
|
|
159
|
+
case AgentState.THINKING:
|
|
160
|
+
return 'Claude is thinking';
|
|
161
|
+
case AgentState.TOOL_RUNNING:
|
|
162
|
+
return 'A tool is running';
|
|
163
|
+
case AgentState.PROCESSING:
|
|
164
|
+
return 'Processing request';
|
|
165
|
+
case AgentState.IDLE_AT_PROMPT:
|
|
166
|
+
return 'Idle at prompt';
|
|
167
|
+
case AgentState.WORK_COMPLETE:
|
|
168
|
+
return 'Work completed';
|
|
169
|
+
case AgentState.ASKING_QUESTION:
|
|
170
|
+
return 'Asking a question - needs response';
|
|
171
|
+
case AgentState.AWAITING_SELECTION:
|
|
172
|
+
return 'Awaiting user selection';
|
|
173
|
+
case AgentState.PLAN_APPROVAL:
|
|
174
|
+
return 'Waiting for plan approval';
|
|
175
|
+
case AgentState.PERMISSION_REQUIRED:
|
|
176
|
+
return 'Permission required';
|
|
177
|
+
case AgentState.USER_DECLINED:
|
|
178
|
+
return 'User declined - blocked';
|
|
179
|
+
case AgentState.UNKNOWN:
|
|
180
|
+
return 'Unknown state';
|
|
181
|
+
default:
|
|
182
|
+
return 'Unknown';
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Check if a state represents active work (not waiting)
|
|
188
|
+
*/
|
|
189
|
+
isActiveState(state: AgentState): boolean {
|
|
190
|
+
return [
|
|
191
|
+
AgentState.THINKING,
|
|
192
|
+
AgentState.TOOL_RUNNING,
|
|
193
|
+
AgentState.PROCESSING,
|
|
194
|
+
].includes(state);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Check if a state requires human intervention
|
|
199
|
+
*/
|
|
200
|
+
isBlockedState(state: AgentState): boolean {
|
|
201
|
+
return [
|
|
202
|
+
AgentState.ASKING_QUESTION,
|
|
203
|
+
AgentState.AWAITING_SELECTION,
|
|
204
|
+
AgentState.PLAN_APPROVAL,
|
|
205
|
+
AgentState.PERMISSION_REQUIRED,
|
|
206
|
+
AgentState.USER_DECLINED,
|
|
207
|
+
].includes(state);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Map a state to waiting status flags
|
|
212
|
+
*/
|
|
213
|
+
private mapStateToWaitingStatus(state: AgentState): Omit<StateDetectionResult, 'confidence' | 'reason'> {
|
|
214
|
+
switch (state) {
|
|
215
|
+
// Active states - not waiting
|
|
216
|
+
case AgentState.THINKING:
|
|
217
|
+
case AgentState.TOOL_RUNNING:
|
|
218
|
+
case AgentState.PROCESSING:
|
|
219
|
+
return {
|
|
220
|
+
state,
|
|
221
|
+
isWaiting: false,
|
|
222
|
+
needsHuman: false,
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
// Idle states - waiting but not blocked
|
|
226
|
+
case AgentState.IDLE_AT_PROMPT:
|
|
227
|
+
case AgentState.WORK_COMPLETE:
|
|
228
|
+
return {
|
|
229
|
+
state,
|
|
230
|
+
isWaiting: true,
|
|
231
|
+
needsHuman: false,
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
// Blocked states - waiting and needs human
|
|
235
|
+
case AgentState.ASKING_QUESTION:
|
|
236
|
+
case AgentState.AWAITING_SELECTION:
|
|
237
|
+
case AgentState.PLAN_APPROVAL:
|
|
238
|
+
case AgentState.PERMISSION_REQUIRED:
|
|
239
|
+
case AgentState.USER_DECLINED:
|
|
240
|
+
return {
|
|
241
|
+
state,
|
|
242
|
+
isWaiting: true,
|
|
243
|
+
needsHuman: true,
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
// Unknown state - assume not waiting
|
|
247
|
+
case AgentState.UNKNOWN:
|
|
248
|
+
default:
|
|
249
|
+
return {
|
|
250
|
+
state,
|
|
251
|
+
isWaiting: false,
|
|
252
|
+
needsHuman: false,
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { CodexStateDetector } from './codex.js';
|
|
3
|
+
import { AgentState } from './types.js';
|
|
4
|
+
|
|
5
|
+
describe('CodexStateDetector', () => {
|
|
6
|
+
const detector = new CodexStateDetector();
|
|
7
|
+
|
|
8
|
+
describe('detectState', () => {
|
|
9
|
+
it('should detect THINKING state', () => {
|
|
10
|
+
const result = detector.detectState('thinking...');
|
|
11
|
+
expect(result.state).toBe(AgentState.THINKING);
|
|
12
|
+
expect(result.confidence).toBe(0.85);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('should detect TOOL_RUNNING state', () => {
|
|
16
|
+
const result = detector.detectState('Executing command...');
|
|
17
|
+
expect(result.state).toBe(AgentState.TOOL_RUNNING);
|
|
18
|
+
expect(result.isWaiting).toBe(false);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should detect TOOL_RUNNING with progress', () => {
|
|
22
|
+
const result = detector.detectState('50% complete');
|
|
23
|
+
expect(result.state).toBe(AgentState.TOOL_RUNNING);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('should detect PROCESSING state', () => {
|
|
27
|
+
const result = detector.detectState('Processing your request...');
|
|
28
|
+
expect(result.state).toBe(AgentState.PROCESSING);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('should detect AWAITING_SELECTION state', () => {
|
|
32
|
+
const result = detector.detectState('Select an option: [1] Option A [2] Option B');
|
|
33
|
+
expect(result.state).toBe(AgentState.AWAITING_SELECTION);
|
|
34
|
+
expect(result.needsHuman).toBe(true);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('should detect ASKING_QUESTION state', () => {
|
|
38
|
+
const result = detector.detectState('Do you want to continue?');
|
|
39
|
+
expect(result.state).toBe(AgentState.ASKING_QUESTION);
|
|
40
|
+
expect(result.needsHuman).toBe(true);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('should detect PERMISSION_REQUIRED state', () => {
|
|
44
|
+
const result = detector.detectState('Permission required [y/n]');
|
|
45
|
+
expect(result.state).toBe(AgentState.PERMISSION_REQUIRED);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should detect USER_DECLINED state', () => {
|
|
49
|
+
const result = detector.detectState('Operation cancelled by user');
|
|
50
|
+
expect(result.state).toBe(AgentState.USER_DECLINED);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('should detect WORK_COMPLETE state', () => {
|
|
54
|
+
const result = detector.detectState('Successfully completed the task');
|
|
55
|
+
expect(result.state).toBe(AgentState.WORK_COMPLETE);
|
|
56
|
+
expect(result.isWaiting).toBe(true);
|
|
57
|
+
expect(result.needsHuman).toBe(false);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('should detect IDLE_AT_PROMPT state', () => {
|
|
61
|
+
const result = detector.detectState('codex> ');
|
|
62
|
+
expect(result.state).toBe(AgentState.IDLE_AT_PROMPT);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('should return UNKNOWN for unclear output', () => {
|
|
66
|
+
const result = detector.detectState('Random output text');
|
|
67
|
+
expect(result.state).toBe(AgentState.UNKNOWN);
|
|
68
|
+
expect(result.confidence).toBe(0.3);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
describe('getStateDescription', () => {
|
|
73
|
+
it('should return Codex-specific description for THINKING', () => {
|
|
74
|
+
const desc = detector.getStateDescription(AgentState.THINKING);
|
|
75
|
+
expect(desc).toBe('Codex is thinking');
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('should return description for TOOL_RUNNING', () => {
|
|
79
|
+
const desc = detector.getStateDescription(AgentState.TOOL_RUNNING);
|
|
80
|
+
expect(desc).toBe('Running command');
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
describe('isActiveState', () => {
|
|
85
|
+
it('should identify active states correctly', () => {
|
|
86
|
+
expect(detector.isActiveState(AgentState.THINKING)).toBe(true);
|
|
87
|
+
expect(detector.isActiveState(AgentState.TOOL_RUNNING)).toBe(true);
|
|
88
|
+
expect(detector.isActiveState(AgentState.PROCESSING)).toBe(true);
|
|
89
|
+
expect(detector.isActiveState(AgentState.IDLE_AT_PROMPT)).toBe(false);
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
describe('isBlockedState', () => {
|
|
94
|
+
it('should identify blocked states correctly', () => {
|
|
95
|
+
expect(detector.isBlockedState(AgentState.ASKING_QUESTION)).toBe(true);
|
|
96
|
+
expect(detector.isBlockedState(AgentState.PERMISSION_REQUIRED)).toBe(true);
|
|
97
|
+
expect(detector.isBlockedState(AgentState.THINKING)).toBe(false);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
});
|