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,170 @@
|
|
|
1
|
+
import type { Database } from 'sql.js';
|
|
2
|
+
import { nanoid } from 'nanoid';
|
|
3
|
+
import { queryAll, queryOne, run, type PullRequestRow } from '../client.js';
|
|
4
|
+
|
|
5
|
+
export type { PullRequestRow };
|
|
6
|
+
|
|
7
|
+
export type PullRequestStatus = 'queued' | 'reviewing' | 'approved' | 'merged' | 'rejected' | 'closed';
|
|
8
|
+
|
|
9
|
+
export interface CreatePullRequestInput {
|
|
10
|
+
storyId?: string | null;
|
|
11
|
+
teamId?: string | null;
|
|
12
|
+
branchName: string;
|
|
13
|
+
githubPrNumber?: number | null;
|
|
14
|
+
githubPrUrl?: string | null;
|
|
15
|
+
submittedBy?: string | null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface UpdatePullRequestInput {
|
|
19
|
+
status?: PullRequestStatus;
|
|
20
|
+
reviewedBy?: string | null;
|
|
21
|
+
reviewNotes?: string | null;
|
|
22
|
+
githubPrNumber?: number | null;
|
|
23
|
+
githubPrUrl?: string | null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function createPullRequest(db: Database, input: CreatePullRequestInput): PullRequestRow {
|
|
27
|
+
const id = `pr-${nanoid(8)}`;
|
|
28
|
+
const now = new Date().toISOString();
|
|
29
|
+
|
|
30
|
+
run(db, `
|
|
31
|
+
INSERT INTO pull_requests (id, story_id, team_id, branch_name, github_pr_number, github_pr_url, submitted_by, status, created_at, updated_at)
|
|
32
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, 'queued', ?, ?)
|
|
33
|
+
`, [
|
|
34
|
+
id,
|
|
35
|
+
input.storyId || null,
|
|
36
|
+
input.teamId || null,
|
|
37
|
+
input.branchName,
|
|
38
|
+
input.githubPrNumber || null,
|
|
39
|
+
input.githubPrUrl || null,
|
|
40
|
+
input.submittedBy || null,
|
|
41
|
+
now,
|
|
42
|
+
now,
|
|
43
|
+
]);
|
|
44
|
+
|
|
45
|
+
return getPullRequestById(db, id)!;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function getPullRequestById(db: Database, id: string): PullRequestRow | undefined {
|
|
49
|
+
return queryOne<PullRequestRow>(db, 'SELECT * FROM pull_requests WHERE id = ?', [id]);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function getPullRequestByStory(db: Database, storyId: string): PullRequestRow | undefined {
|
|
53
|
+
return queryOne<PullRequestRow>(db, 'SELECT * FROM pull_requests WHERE story_id = ?', [storyId]);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function getPullRequestByGithubNumber(db: Database, prNumber: number): PullRequestRow | undefined {
|
|
57
|
+
return queryOne<PullRequestRow>(db, 'SELECT * FROM pull_requests WHERE github_pr_number = ?', [prNumber]);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Merge Queue functions
|
|
61
|
+
|
|
62
|
+
export function getMergeQueue(db: Database, teamId?: string): PullRequestRow[] {
|
|
63
|
+
if (teamId) {
|
|
64
|
+
return queryAll<PullRequestRow>(db, `
|
|
65
|
+
SELECT * FROM pull_requests
|
|
66
|
+
WHERE team_id = ? AND status IN ('queued', 'reviewing')
|
|
67
|
+
ORDER BY created_at ASC
|
|
68
|
+
`, [teamId]);
|
|
69
|
+
}
|
|
70
|
+
return queryAll<PullRequestRow>(db, `
|
|
71
|
+
SELECT * FROM pull_requests
|
|
72
|
+
WHERE status IN ('queued', 'reviewing')
|
|
73
|
+
ORDER BY created_at ASC
|
|
74
|
+
`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function getNextInQueue(db: Database, teamId?: string): PullRequestRow | undefined {
|
|
78
|
+
if (teamId) {
|
|
79
|
+
return queryOne<PullRequestRow>(db, `
|
|
80
|
+
SELECT * FROM pull_requests
|
|
81
|
+
WHERE team_id = ? AND status = 'queued'
|
|
82
|
+
ORDER BY created_at ASC
|
|
83
|
+
LIMIT 1
|
|
84
|
+
`, [teamId]);
|
|
85
|
+
}
|
|
86
|
+
return queryOne<PullRequestRow>(db, `
|
|
87
|
+
SELECT * FROM pull_requests
|
|
88
|
+
WHERE status = 'queued'
|
|
89
|
+
ORDER BY created_at ASC
|
|
90
|
+
LIMIT 1
|
|
91
|
+
`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function getQueuePosition(db: Database, prId: string): number {
|
|
95
|
+
const pr = getPullRequestById(db, prId);
|
|
96
|
+
if (!pr || !['queued', 'reviewing'].includes(pr.status)) return -1;
|
|
97
|
+
|
|
98
|
+
const queue = getMergeQueue(db, pr.team_id || undefined);
|
|
99
|
+
return queue.findIndex(p => p.id === prId) + 1;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function getPullRequestsByStatus(db: Database, status: PullRequestStatus): PullRequestRow[] {
|
|
103
|
+
return queryAll<PullRequestRow>(db, `
|
|
104
|
+
SELECT * FROM pull_requests
|
|
105
|
+
WHERE status = ?
|
|
106
|
+
ORDER BY created_at DESC
|
|
107
|
+
`, [status]);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function getApprovedPullRequests(db: Database): PullRequestRow[] {
|
|
111
|
+
return queryAll<PullRequestRow>(db, `
|
|
112
|
+
SELECT * FROM pull_requests
|
|
113
|
+
WHERE status = 'approved'
|
|
114
|
+
ORDER BY created_at ASC
|
|
115
|
+
`);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function getAllPullRequests(db: Database): PullRequestRow[] {
|
|
119
|
+
return queryAll<PullRequestRow>(db, 'SELECT * FROM pull_requests ORDER BY created_at DESC');
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export function getPullRequestsByTeam(db: Database, teamId: string): PullRequestRow[] {
|
|
123
|
+
return queryAll<PullRequestRow>(db, `
|
|
124
|
+
SELECT * FROM pull_requests
|
|
125
|
+
WHERE team_id = ?
|
|
126
|
+
ORDER BY created_at DESC
|
|
127
|
+
`, [teamId]);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function updatePullRequest(db: Database, id: string, input: UpdatePullRequestInput): PullRequestRow | undefined {
|
|
131
|
+
const updates: string[] = ['updated_at = ?'];
|
|
132
|
+
const values: (string | number | null)[] = [new Date().toISOString()];
|
|
133
|
+
|
|
134
|
+
if (input.status !== undefined) {
|
|
135
|
+
updates.push('status = ?');
|
|
136
|
+
values.push(input.status);
|
|
137
|
+
if (['reviewing', 'approved', 'rejected', 'merged'].includes(input.status)) {
|
|
138
|
+
updates.push('reviewed_at = ?');
|
|
139
|
+
values.push(new Date().toISOString());
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
if (input.reviewedBy !== undefined) {
|
|
143
|
+
updates.push('reviewed_by = ?');
|
|
144
|
+
values.push(input.reviewedBy);
|
|
145
|
+
}
|
|
146
|
+
if (input.reviewNotes !== undefined) {
|
|
147
|
+
updates.push('review_notes = ?');
|
|
148
|
+
values.push(input.reviewNotes);
|
|
149
|
+
}
|
|
150
|
+
if (input.githubPrNumber !== undefined) {
|
|
151
|
+
updates.push('github_pr_number = ?');
|
|
152
|
+
values.push(input.githubPrNumber);
|
|
153
|
+
}
|
|
154
|
+
if (input.githubPrUrl !== undefined) {
|
|
155
|
+
updates.push('github_pr_url = ?');
|
|
156
|
+
values.push(input.githubPrUrl);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (updates.length === 1) {
|
|
160
|
+
return getPullRequestById(db, id);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
values.push(id);
|
|
164
|
+
run(db, `UPDATE pull_requests SET ${updates.join(', ')} WHERE id = ?`, values);
|
|
165
|
+
return getPullRequestById(db, id);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export function deletePullRequest(db: Database, id: string): void {
|
|
169
|
+
run(db, 'DELETE FROM pull_requests WHERE id = ?', [id]);
|
|
170
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { Database } from 'sql.js';
|
|
2
|
+
import { nanoid } from 'nanoid';
|
|
3
|
+
import { queryAll, queryOne, run, type RequirementRow } from '../client.js';
|
|
4
|
+
|
|
5
|
+
export type { RequirementRow };
|
|
6
|
+
|
|
7
|
+
export type RequirementStatus = 'pending' | 'planning' | 'planned' | 'in_progress' | 'completed';
|
|
8
|
+
|
|
9
|
+
export interface CreateRequirementInput {
|
|
10
|
+
title: string;
|
|
11
|
+
description: string;
|
|
12
|
+
submittedBy?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface UpdateRequirementInput {
|
|
16
|
+
title?: string;
|
|
17
|
+
description?: string;
|
|
18
|
+
status?: RequirementStatus;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function createRequirement(db: Database, input: CreateRequirementInput): RequirementRow {
|
|
22
|
+
const id = `REQ-${nanoid(8).toUpperCase()}`;
|
|
23
|
+
const now = new Date().toISOString();
|
|
24
|
+
|
|
25
|
+
run(db, `
|
|
26
|
+
INSERT INTO requirements (id, title, description, submitted_by, created_at)
|
|
27
|
+
VALUES (?, ?, ?, ?, ?)
|
|
28
|
+
`, [id, input.title, input.description, input.submittedBy || 'human', now]);
|
|
29
|
+
|
|
30
|
+
return getRequirementById(db, id)!;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function getRequirementById(db: Database, id: string): RequirementRow | undefined {
|
|
34
|
+
return queryOne<RequirementRow>(db, 'SELECT * FROM requirements WHERE id = ?', [id]);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function getAllRequirements(db: Database): RequirementRow[] {
|
|
38
|
+
return queryAll<RequirementRow>(db, 'SELECT * FROM requirements ORDER BY created_at DESC');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function getRequirementsByStatus(db: Database, status: RequirementStatus): RequirementRow[] {
|
|
42
|
+
return queryAll<RequirementRow>(db, 'SELECT * FROM requirements WHERE status = ? ORDER BY created_at DESC', [status]);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function getPendingRequirements(db: Database): RequirementRow[] {
|
|
46
|
+
return queryAll<RequirementRow>(db, `
|
|
47
|
+
SELECT * FROM requirements
|
|
48
|
+
WHERE status IN ('pending', 'planning', 'in_progress')
|
|
49
|
+
ORDER BY created_at
|
|
50
|
+
`);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function updateRequirement(db: Database, id: string, input: UpdateRequirementInput): RequirementRow | undefined {
|
|
54
|
+
const updates: string[] = [];
|
|
55
|
+
const values: string[] = [];
|
|
56
|
+
|
|
57
|
+
if (input.title !== undefined) {
|
|
58
|
+
updates.push('title = ?');
|
|
59
|
+
values.push(input.title);
|
|
60
|
+
}
|
|
61
|
+
if (input.description !== undefined) {
|
|
62
|
+
updates.push('description = ?');
|
|
63
|
+
values.push(input.description);
|
|
64
|
+
}
|
|
65
|
+
if (input.status !== undefined) {
|
|
66
|
+
updates.push('status = ?');
|
|
67
|
+
values.push(input.status);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (updates.length === 0) {
|
|
71
|
+
return getRequirementById(db, id);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
values.push(id);
|
|
75
|
+
run(db, `UPDATE requirements SET ${updates.join(', ')} WHERE id = ?`, values);
|
|
76
|
+
return getRequirementById(db, id);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function deleteRequirement(db: Database, id: string): void {
|
|
80
|
+
run(db, 'DELETE FROM requirements WHERE id = ?', [id]);
|
|
81
|
+
}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import type { Database } from 'sql.js';
|
|
2
|
+
import { nanoid } from 'nanoid';
|
|
3
|
+
import { queryAll, queryOne, run, type StoryRow } from '../client.js';
|
|
4
|
+
|
|
5
|
+
export type { StoryRow };
|
|
6
|
+
|
|
7
|
+
export type StoryStatus =
|
|
8
|
+
| 'draft'
|
|
9
|
+
| 'estimated'
|
|
10
|
+
| 'planned'
|
|
11
|
+
| 'in_progress'
|
|
12
|
+
| 'review'
|
|
13
|
+
| 'qa'
|
|
14
|
+
| 'qa_failed'
|
|
15
|
+
| 'pr_submitted'
|
|
16
|
+
| 'merged';
|
|
17
|
+
|
|
18
|
+
export interface CreateStoryInput {
|
|
19
|
+
requirementId?: string | null;
|
|
20
|
+
teamId?: string | null;
|
|
21
|
+
title: string;
|
|
22
|
+
description: string;
|
|
23
|
+
acceptanceCriteria?: string[] | null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface UpdateStoryInput {
|
|
27
|
+
teamId?: string | null;
|
|
28
|
+
title?: string;
|
|
29
|
+
description?: string;
|
|
30
|
+
acceptanceCriteria?: string[] | null;
|
|
31
|
+
complexityScore?: number | null;
|
|
32
|
+
storyPoints?: number | null;
|
|
33
|
+
status?: StoryStatus;
|
|
34
|
+
assignedAgentId?: string | null;
|
|
35
|
+
branchName?: string | null;
|
|
36
|
+
prUrl?: string | null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function createStory(db: Database, input: CreateStoryInput): StoryRow {
|
|
40
|
+
const id = `STORY-${nanoid(6).toUpperCase()}`;
|
|
41
|
+
const acceptanceCriteria = input.acceptanceCriteria
|
|
42
|
+
? JSON.stringify(input.acceptanceCriteria)
|
|
43
|
+
: null;
|
|
44
|
+
const now = new Date().toISOString();
|
|
45
|
+
|
|
46
|
+
run(db, `
|
|
47
|
+
INSERT INTO stories (id, requirement_id, team_id, title, description, acceptance_criteria, created_at, updated_at)
|
|
48
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
49
|
+
`, [id, input.requirementId || null, input.teamId || null, input.title, input.description, acceptanceCriteria, now, now]);
|
|
50
|
+
|
|
51
|
+
return getStoryById(db, id)!;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function getStoryById(db: Database, id: string): StoryRow | undefined {
|
|
55
|
+
return queryOne<StoryRow>(db, 'SELECT * FROM stories WHERE id = ?', [id]);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function getStoriesByRequirement(db: Database, requirementId: string): StoryRow[] {
|
|
59
|
+
return queryAll<StoryRow>(db, 'SELECT * FROM stories WHERE requirement_id = ? ORDER BY created_at', [requirementId]);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function getStoriesByTeam(db: Database, teamId: string): StoryRow[] {
|
|
63
|
+
return queryAll<StoryRow>(db, 'SELECT * FROM stories WHERE team_id = ? ORDER BY created_at', [teamId]);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function getStoriesByStatus(db: Database, status: StoryStatus): StoryRow[] {
|
|
67
|
+
return queryAll<StoryRow>(db, 'SELECT * FROM stories WHERE status = ? ORDER BY created_at', [status]);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function getStoriesByAgent(db: Database, agentId: string): StoryRow[] {
|
|
71
|
+
return queryAll<StoryRow>(db, 'SELECT * FROM stories WHERE assigned_agent_id = ? ORDER BY created_at', [agentId]);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function getActiveStoriesByAgent(db: Database, agentId: string): StoryRow[] {
|
|
75
|
+
return queryAll<StoryRow>(db, `
|
|
76
|
+
SELECT * FROM stories
|
|
77
|
+
WHERE assigned_agent_id = ?
|
|
78
|
+
AND status IN ('planned', 'in_progress', 'review', 'qa', 'qa_failed', 'pr_submitted')
|
|
79
|
+
ORDER BY created_at
|
|
80
|
+
`, [agentId]);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function getAllStories(db: Database): StoryRow[] {
|
|
84
|
+
return queryAll<StoryRow>(db, 'SELECT * FROM stories ORDER BY created_at DESC');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function getPlannedStories(db: Database): StoryRow[] {
|
|
88
|
+
return queryAll<StoryRow>(db, `
|
|
89
|
+
SELECT * FROM stories
|
|
90
|
+
WHERE status = 'planned'
|
|
91
|
+
ORDER BY story_points DESC, created_at
|
|
92
|
+
`);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function getInProgressStories(db: Database): StoryRow[] {
|
|
96
|
+
return queryAll<StoryRow>(db, `
|
|
97
|
+
SELECT * FROM stories
|
|
98
|
+
WHERE status IN ('in_progress', 'review', 'qa', 'qa_failed')
|
|
99
|
+
ORDER BY created_at
|
|
100
|
+
`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function getStoryPointsByTeam(db: Database, teamId: string): number {
|
|
104
|
+
const result = queryOne<{ total: number }>(db, `
|
|
105
|
+
SELECT COALESCE(SUM(story_points), 0) as total
|
|
106
|
+
FROM stories
|
|
107
|
+
WHERE team_id = ? AND status IN ('planned', 'in_progress', 'review', 'qa')
|
|
108
|
+
`, [teamId]);
|
|
109
|
+
return result?.total || 0;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function updateStory(db: Database, id: string, input: UpdateStoryInput): StoryRow | undefined {
|
|
113
|
+
const updates: string[] = ['updated_at = ?'];
|
|
114
|
+
const values: (string | number | null)[] = [new Date().toISOString()];
|
|
115
|
+
|
|
116
|
+
if (input.teamId !== undefined) {
|
|
117
|
+
updates.push('team_id = ?');
|
|
118
|
+
values.push(input.teamId);
|
|
119
|
+
}
|
|
120
|
+
if (input.title !== undefined) {
|
|
121
|
+
updates.push('title = ?');
|
|
122
|
+
values.push(input.title);
|
|
123
|
+
}
|
|
124
|
+
if (input.description !== undefined) {
|
|
125
|
+
updates.push('description = ?');
|
|
126
|
+
values.push(input.description);
|
|
127
|
+
}
|
|
128
|
+
if (input.acceptanceCriteria !== undefined) {
|
|
129
|
+
updates.push('acceptance_criteria = ?');
|
|
130
|
+
values.push(input.acceptanceCriteria ? JSON.stringify(input.acceptanceCriteria) : null);
|
|
131
|
+
}
|
|
132
|
+
if (input.complexityScore !== undefined) {
|
|
133
|
+
updates.push('complexity_score = ?');
|
|
134
|
+
values.push(input.complexityScore);
|
|
135
|
+
}
|
|
136
|
+
if (input.storyPoints !== undefined) {
|
|
137
|
+
updates.push('story_points = ?');
|
|
138
|
+
values.push(input.storyPoints);
|
|
139
|
+
}
|
|
140
|
+
if (input.status !== undefined) {
|
|
141
|
+
updates.push('status = ?');
|
|
142
|
+
values.push(input.status);
|
|
143
|
+
}
|
|
144
|
+
if (input.assignedAgentId !== undefined) {
|
|
145
|
+
updates.push('assigned_agent_id = ?');
|
|
146
|
+
values.push(input.assignedAgentId);
|
|
147
|
+
}
|
|
148
|
+
if (input.branchName !== undefined) {
|
|
149
|
+
updates.push('branch_name = ?');
|
|
150
|
+
values.push(input.branchName);
|
|
151
|
+
}
|
|
152
|
+
if (input.prUrl !== undefined) {
|
|
153
|
+
updates.push('pr_url = ?');
|
|
154
|
+
values.push(input.prUrl);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (updates.length === 1) {
|
|
158
|
+
return getStoryById(db, id);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
values.push(id);
|
|
162
|
+
run(db, `UPDATE stories SET ${updates.join(', ')} WHERE id = ?`, values);
|
|
163
|
+
return getStoryById(db, id);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export function deleteStory(db: Database, id: string): void {
|
|
167
|
+
run(db, 'DELETE FROM story_dependencies WHERE story_id = ? OR depends_on_story_id = ?', [id, id]);
|
|
168
|
+
run(db, 'DELETE FROM stories WHERE id = ?', [id]);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Story dependencies
|
|
172
|
+
export function addStoryDependency(db: Database, storyId: string, dependsOnStoryId: string): void {
|
|
173
|
+
run(db, `
|
|
174
|
+
INSERT OR IGNORE INTO story_dependencies (story_id, depends_on_story_id)
|
|
175
|
+
VALUES (?, ?)
|
|
176
|
+
`, [storyId, dependsOnStoryId]);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export function removeStoryDependency(db: Database, storyId: string, dependsOnStoryId: string): void {
|
|
180
|
+
run(db, 'DELETE FROM story_dependencies WHERE story_id = ? AND depends_on_story_id = ?', [storyId, dependsOnStoryId]);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export function getStoryDependencies(db: Database, storyId: string): StoryRow[] {
|
|
184
|
+
return queryAll<StoryRow>(db, `
|
|
185
|
+
SELECT s.* FROM stories s
|
|
186
|
+
JOIN story_dependencies sd ON s.id = sd.depends_on_story_id
|
|
187
|
+
WHERE sd.story_id = ?
|
|
188
|
+
`, [storyId]);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export function getStoriesDependingOn(db: Database, storyId: string): StoryRow[] {
|
|
192
|
+
return queryAll<StoryRow>(db, `
|
|
193
|
+
SELECT s.* FROM stories s
|
|
194
|
+
JOIN story_dependencies sd ON s.id = sd.story_id
|
|
195
|
+
WHERE sd.depends_on_story_id = ?
|
|
196
|
+
`, [storyId]);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export function getStoryCounts(db: Database): Record<StoryStatus, number> {
|
|
200
|
+
const rows = queryAll<{ status: StoryStatus; count: number }>(db, `
|
|
201
|
+
SELECT status, COUNT(*) as count
|
|
202
|
+
FROM stories
|
|
203
|
+
GROUP BY status
|
|
204
|
+
`);
|
|
205
|
+
|
|
206
|
+
const counts: Record<StoryStatus, number> = {
|
|
207
|
+
draft: 0,
|
|
208
|
+
estimated: 0,
|
|
209
|
+
planned: 0,
|
|
210
|
+
in_progress: 0,
|
|
211
|
+
review: 0,
|
|
212
|
+
qa: 0,
|
|
213
|
+
qa_failed: 0,
|
|
214
|
+
pr_submitted: 0,
|
|
215
|
+
merged: 0,
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
for (const row of rows) {
|
|
219
|
+
counts[row.status] = row.count;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return counts;
|
|
223
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Database } from 'sql.js';
|
|
2
|
+
import { nanoid } from 'nanoid';
|
|
3
|
+
import { queryAll, queryOne, run, type TeamRow } from '../client.js';
|
|
4
|
+
|
|
5
|
+
export type { TeamRow };
|
|
6
|
+
|
|
7
|
+
export interface CreateTeamInput {
|
|
8
|
+
repoUrl: string;
|
|
9
|
+
repoPath: string;
|
|
10
|
+
name: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function createTeam(db: Database, input: CreateTeamInput): TeamRow {
|
|
14
|
+
const id = `team-${nanoid(10)}`;
|
|
15
|
+
const now = new Date().toISOString();
|
|
16
|
+
|
|
17
|
+
run(db, `
|
|
18
|
+
INSERT INTO teams (id, repo_url, repo_path, name, created_at)
|
|
19
|
+
VALUES (?, ?, ?, ?, ?)
|
|
20
|
+
`, [id, input.repoUrl, input.repoPath, input.name, now]);
|
|
21
|
+
|
|
22
|
+
return getTeamById(db, id)!;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function getTeamById(db: Database, id: string): TeamRow | undefined {
|
|
26
|
+
return queryOne<TeamRow>(db, 'SELECT * FROM teams WHERE id = ?', [id]);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function getTeamByName(db: Database, name: string): TeamRow | undefined {
|
|
30
|
+
return queryOne<TeamRow>(db, 'SELECT * FROM teams WHERE name = ?', [name]);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function getAllTeams(db: Database): TeamRow[] {
|
|
34
|
+
return queryAll<TeamRow>(db, 'SELECT * FROM teams ORDER BY created_at');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function deleteTeam(db: Database, id: string): void {
|
|
38
|
+
run(db, 'DELETE FROM teams WHERE id = ?', [id]);
|
|
39
|
+
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { execa } from 'execa';
|
|
2
|
+
|
|
3
|
+
export interface BranchInfo {
|
|
4
|
+
name: string;
|
|
5
|
+
current: boolean;
|
|
6
|
+
remote?: string;
|
|
7
|
+
upstream?: string;
|
|
8
|
+
lastCommit: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Get current branch name
|
|
13
|
+
*/
|
|
14
|
+
export async function getCurrentBranch(workDir: string): Promise<string> {
|
|
15
|
+
const { stdout } = await execa('git', ['branch', '--show-current'], {
|
|
16
|
+
cwd: workDir,
|
|
17
|
+
});
|
|
18
|
+
return stdout.trim();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* List all local branches
|
|
23
|
+
*/
|
|
24
|
+
export async function listBranches(workDir: string): Promise<BranchInfo[]> {
|
|
25
|
+
const { stdout } = await execa('git', [
|
|
26
|
+
'branch', '-v', '--format=%(refname:short)|%(objectname:short)|%(HEAD)',
|
|
27
|
+
], { cwd: workDir });
|
|
28
|
+
|
|
29
|
+
return stdout.split('\n').filter(Boolean).map(line => {
|
|
30
|
+
const [name, lastCommit, head] = line.split('|');
|
|
31
|
+
return {
|
|
32
|
+
name,
|
|
33
|
+
current: head === '*',
|
|
34
|
+
lastCommit,
|
|
35
|
+
};
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Create a new branch
|
|
41
|
+
*/
|
|
42
|
+
export async function createBranch(
|
|
43
|
+
workDir: string,
|
|
44
|
+
name: string,
|
|
45
|
+
startPoint?: string
|
|
46
|
+
): Promise<void> {
|
|
47
|
+
const args = ['branch', name];
|
|
48
|
+
if (startPoint) {
|
|
49
|
+
args.push(startPoint);
|
|
50
|
+
}
|
|
51
|
+
await execa('git', args, { cwd: workDir });
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Checkout a branch
|
|
56
|
+
*/
|
|
57
|
+
export async function checkoutBranch(
|
|
58
|
+
workDir: string,
|
|
59
|
+
name: string,
|
|
60
|
+
create: boolean = false
|
|
61
|
+
): Promise<void> {
|
|
62
|
+
const args = ['checkout'];
|
|
63
|
+
if (create) {
|
|
64
|
+
args.push('-b');
|
|
65
|
+
}
|
|
66
|
+
args.push(name);
|
|
67
|
+
await execa('git', args, { cwd: workDir });
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Delete a branch
|
|
72
|
+
*/
|
|
73
|
+
export async function deleteBranch(
|
|
74
|
+
workDir: string,
|
|
75
|
+
name: string,
|
|
76
|
+
force: boolean = false
|
|
77
|
+
): Promise<void> {
|
|
78
|
+
const args = ['branch', force ? '-D' : '-d', name];
|
|
79
|
+
await execa('git', args, { cwd: workDir });
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Check if branch exists
|
|
84
|
+
*/
|
|
85
|
+
export async function branchExists(workDir: string, name: string): Promise<boolean> {
|
|
86
|
+
try {
|
|
87
|
+
await execa('git', ['rev-parse', '--verify', name], { cwd: workDir });
|
|
88
|
+
return true;
|
|
89
|
+
} catch {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Get branch tracking info
|
|
96
|
+
*/
|
|
97
|
+
export async function getBranchTracking(workDir: string, branch: string): Promise<{
|
|
98
|
+
upstream: string | null;
|
|
99
|
+
ahead: number;
|
|
100
|
+
behind: number;
|
|
101
|
+
}> {
|
|
102
|
+
try {
|
|
103
|
+
const { stdout: upstream } = await execa('git', [
|
|
104
|
+
'rev-parse', '--abbrev-ref', `${branch}@{upstream}`,
|
|
105
|
+
], { cwd: workDir });
|
|
106
|
+
|
|
107
|
+
const { stdout: counts } = await execa('git', [
|
|
108
|
+
'rev-list', '--left-right', '--count', `${upstream.trim()}...${branch}`,
|
|
109
|
+
], { cwd: workDir });
|
|
110
|
+
|
|
111
|
+
const [behind, ahead] = counts.trim().split('\t').map(Number);
|
|
112
|
+
|
|
113
|
+
return {
|
|
114
|
+
upstream: upstream.trim(),
|
|
115
|
+
ahead,
|
|
116
|
+
behind,
|
|
117
|
+
};
|
|
118
|
+
} catch {
|
|
119
|
+
return { upstream: null, ahead: 0, behind: 0 };
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Push branch to remote
|
|
125
|
+
*/
|
|
126
|
+
export async function pushBranch(
|
|
127
|
+
workDir: string,
|
|
128
|
+
branch: string,
|
|
129
|
+
remote: string = 'origin',
|
|
130
|
+
setUpstream: boolean = false
|
|
131
|
+
): Promise<void> {
|
|
132
|
+
const args = ['push', remote, branch];
|
|
133
|
+
if (setUpstream) {
|
|
134
|
+
args.splice(1, 0, '-u');
|
|
135
|
+
}
|
|
136
|
+
await execa('git', args, { cwd: workDir });
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Create and checkout a feature branch
|
|
141
|
+
*/
|
|
142
|
+
export async function createFeatureBranch(
|
|
143
|
+
workDir: string,
|
|
144
|
+
storyId: string,
|
|
145
|
+
description: string,
|
|
146
|
+
baseBranch: string = 'main'
|
|
147
|
+
): Promise<string> {
|
|
148
|
+
// Normalize the description for branch name
|
|
149
|
+
const slug = description
|
|
150
|
+
.toLowerCase()
|
|
151
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
152
|
+
.replace(/^-|-$/g, '')
|
|
153
|
+
.substring(0, 30);
|
|
154
|
+
|
|
155
|
+
const branchName = `feature/${storyId.toLowerCase()}-${slug}`;
|
|
156
|
+
|
|
157
|
+
// Make sure we're on the base branch and up to date
|
|
158
|
+
await checkoutBranch(workDir, baseBranch);
|
|
159
|
+
|
|
160
|
+
try {
|
|
161
|
+
await execa('git', ['pull', 'origin', baseBranch], { cwd: workDir });
|
|
162
|
+
} catch {
|
|
163
|
+
// Pull might fail if no remote tracking, continue anyway
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Create and checkout the feature branch
|
|
167
|
+
await checkoutBranch(workDir, branchName, true);
|
|
168
|
+
|
|
169
|
+
return branchName;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Merge a branch
|
|
174
|
+
*/
|
|
175
|
+
export async function mergeBranch(
|
|
176
|
+
workDir: string,
|
|
177
|
+
branch: string,
|
|
178
|
+
noFf: boolean = true
|
|
179
|
+
): Promise<void> {
|
|
180
|
+
const args = ['merge'];
|
|
181
|
+
if (noFf) {
|
|
182
|
+
args.push('--no-ff');
|
|
183
|
+
}
|
|
184
|
+
args.push(branch);
|
|
185
|
+
await execa('git', args, { cwd: workDir });
|
|
186
|
+
}
|