@stoneforge/smithy 0.1.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 +13 -0
- package/README.md +114 -0
- package/dist/api/index.d.ts +7 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +7 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/orchestrator-api.d.ts +153 -0
- package/dist/api/orchestrator-api.d.ts.map +1 -0
- package/dist/api/orchestrator-api.js +374 -0
- package/dist/api/orchestrator-api.js.map +1 -0
- package/dist/bin/sf.d.ts +3 -0
- package/dist/bin/sf.d.ts.map +1 -0
- package/dist/bin/sf.js +10 -0
- package/dist/bin/sf.js.map +1 -0
- package/dist/cli/commands/agent.d.ts +20 -0
- package/dist/cli/commands/agent.d.ts.map +1 -0
- package/dist/cli/commands/agent.js +861 -0
- package/dist/cli/commands/agent.js.map +1 -0
- package/dist/cli/commands/daemon.d.ts +14 -0
- package/dist/cli/commands/daemon.d.ts.map +1 -0
- package/dist/cli/commands/daemon.js +272 -0
- package/dist/cli/commands/daemon.js.map +1 -0
- package/dist/cli/commands/dispatch.d.ts +9 -0
- package/dist/cli/commands/dispatch.d.ts.map +1 -0
- package/dist/cli/commands/dispatch.js +128 -0
- package/dist/cli/commands/dispatch.js.map +1 -0
- package/dist/cli/commands/merge.d.ts +11 -0
- package/dist/cli/commands/merge.d.ts.map +1 -0
- package/dist/cli/commands/merge.js +246 -0
- package/dist/cli/commands/merge.js.map +1 -0
- package/dist/cli/commands/pool.d.ts +21 -0
- package/dist/cli/commands/pool.d.ts.map +1 -0
- package/dist/cli/commands/pool.js +762 -0
- package/dist/cli/commands/pool.js.map +1 -0
- package/dist/cli/commands/serve.d.ts +54 -0
- package/dist/cli/commands/serve.d.ts.map +1 -0
- package/dist/cli/commands/serve.js +57 -0
- package/dist/cli/commands/serve.js.map +1 -0
- package/dist/cli/commands/task.d.ts +36 -0
- package/dist/cli/commands/task.d.ts.map +1 -0
- package/dist/cli/commands/task.js +889 -0
- package/dist/cli/commands/task.js.map +1 -0
- package/dist/cli/commands/test-orchestration.d.ts +32 -0
- package/dist/cli/commands/test-orchestration.d.ts.map +1 -0
- package/dist/cli/commands/test-orchestration.js +392 -0
- package/dist/cli/commands/test-orchestration.js.map +1 -0
- package/dist/cli/index.d.ts +13 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +15 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/plugin.d.ts +23 -0
- package/dist/cli/plugin.d.ts.map +1 -0
- package/dist/cli/plugin.js +36 -0
- package/dist/cli/plugin.js.map +1 -0
- package/dist/git/index.d.ts +10 -0
- package/dist/git/index.d.ts.map +1 -0
- package/dist/git/index.js +12 -0
- package/dist/git/index.js.map +1 -0
- package/dist/git/merge.d.ts +79 -0
- package/dist/git/merge.d.ts.map +1 -0
- package/dist/git/merge.js +254 -0
- package/dist/git/merge.js.map +1 -0
- package/dist/git/worktree-manager.d.ts +299 -0
- package/dist/git/worktree-manager.d.ts.map +1 -0
- package/dist/git/worktree-manager.js +744 -0
- package/dist/git/worktree-manager.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/dist/prompts/director.md +272 -0
- package/dist/prompts/index.d.ts +100 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +294 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/prompts/message-triage.md +50 -0
- package/dist/prompts/persistent-worker.md +240 -0
- package/dist/prompts/steward-base.md +64 -0
- package/dist/prompts/steward-docs.md +118 -0
- package/dist/prompts/steward-health.md +39 -0
- package/dist/prompts/steward-merge.md +168 -0
- package/dist/prompts/steward-ops.md +28 -0
- package/dist/prompts/steward-reminder.md +26 -0
- package/dist/prompts/worker.md +282 -0
- package/dist/providers/claude/headless.d.ts +18 -0
- package/dist/providers/claude/headless.d.ts.map +1 -0
- package/dist/providers/claude/headless.js +307 -0
- package/dist/providers/claude/headless.js.map +1 -0
- package/dist/providers/claude/index.d.ts +24 -0
- package/dist/providers/claude/index.d.ts.map +1 -0
- package/dist/providers/claude/index.js +80 -0
- package/dist/providers/claude/index.js.map +1 -0
- package/dist/providers/claude/interactive.d.ts +21 -0
- package/dist/providers/claude/interactive.d.ts.map +1 -0
- package/dist/providers/claude/interactive.js +142 -0
- package/dist/providers/claude/interactive.js.map +1 -0
- package/dist/providers/codex/event-mapper.d.ts +91 -0
- package/dist/providers/codex/event-mapper.d.ts.map +1 -0
- package/dist/providers/codex/event-mapper.js +299 -0
- package/dist/providers/codex/event-mapper.js.map +1 -0
- package/dist/providers/codex/headless.d.ts +20 -0
- package/dist/providers/codex/headless.d.ts.map +1 -0
- package/dist/providers/codex/headless.js +174 -0
- package/dist/providers/codex/headless.js.map +1 -0
- package/dist/providers/codex/index.d.ts +30 -0
- package/dist/providers/codex/index.d.ts.map +1 -0
- package/dist/providers/codex/index.js +55 -0
- package/dist/providers/codex/index.js.map +1 -0
- package/dist/providers/codex/interactive.d.ts +21 -0
- package/dist/providers/codex/interactive.d.ts.map +1 -0
- package/dist/providers/codex/interactive.js +141 -0
- package/dist/providers/codex/interactive.js.map +1 -0
- package/dist/providers/codex/jsonrpc-client.d.ts +52 -0
- package/dist/providers/codex/jsonrpc-client.d.ts.map +1 -0
- package/dist/providers/codex/jsonrpc-client.js +141 -0
- package/dist/providers/codex/jsonrpc-client.js.map +1 -0
- package/dist/providers/codex/server-manager.d.ts +100 -0
- package/dist/providers/codex/server-manager.d.ts.map +1 -0
- package/dist/providers/codex/server-manager.js +153 -0
- package/dist/providers/codex/server-manager.js.map +1 -0
- package/dist/providers/index.d.ts +15 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +19 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/opencode/async-queue.d.ts +21 -0
- package/dist/providers/opencode/async-queue.d.ts.map +1 -0
- package/dist/providers/opencode/async-queue.js +51 -0
- package/dist/providers/opencode/async-queue.js.map +1 -0
- package/dist/providers/opencode/event-mapper.d.ts +132 -0
- package/dist/providers/opencode/event-mapper.d.ts.map +1 -0
- package/dist/providers/opencode/event-mapper.js +204 -0
- package/dist/providers/opencode/event-mapper.js.map +1 -0
- package/dist/providers/opencode/headless.d.ts +25 -0
- package/dist/providers/opencode/headless.d.ts.map +1 -0
- package/dist/providers/opencode/headless.js +190 -0
- package/dist/providers/opencode/headless.js.map +1 -0
- package/dist/providers/opencode/index.d.ts +33 -0
- package/dist/providers/opencode/index.d.ts.map +1 -0
- package/dist/providers/opencode/index.js +42 -0
- package/dist/providers/opencode/index.js.map +1 -0
- package/dist/providers/opencode/interactive.d.ts +21 -0
- package/dist/providers/opencode/interactive.d.ts.map +1 -0
- package/dist/providers/opencode/interactive.js +135 -0
- package/dist/providers/opencode/interactive.js.map +1 -0
- package/dist/providers/opencode/server-manager.d.ts +145 -0
- package/dist/providers/opencode/server-manager.d.ts.map +1 -0
- package/dist/providers/opencode/server-manager.js +163 -0
- package/dist/providers/opencode/server-manager.js.map +1 -0
- package/dist/providers/registry.d.ts +38 -0
- package/dist/providers/registry.d.ts.map +1 -0
- package/dist/providers/registry.js +82 -0
- package/dist/providers/registry.js.map +1 -0
- package/dist/providers/types.d.ts +144 -0
- package/dist/providers/types.d.ts.map +1 -0
- package/dist/providers/types.js +25 -0
- package/dist/providers/types.js.map +1 -0
- package/dist/runtime/event-utils.d.ts +8 -0
- package/dist/runtime/event-utils.d.ts.map +1 -0
- package/dist/runtime/event-utils.js +23 -0
- package/dist/runtime/event-utils.js.map +1 -0
- package/dist/runtime/handoff.d.ts +195 -0
- package/dist/runtime/handoff.d.ts.map +1 -0
- package/dist/runtime/handoff.js +332 -0
- package/dist/runtime/handoff.js.map +1 -0
- package/dist/runtime/index.d.ts +17 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +60 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/message-mapper.d.ts +99 -0
- package/dist/runtime/message-mapper.d.ts.map +1 -0
- package/dist/runtime/message-mapper.js +202 -0
- package/dist/runtime/message-mapper.js.map +1 -0
- package/dist/runtime/predecessor-query.d.ts +212 -0
- package/dist/runtime/predecessor-query.d.ts.map +1 -0
- package/dist/runtime/predecessor-query.js +283 -0
- package/dist/runtime/predecessor-query.js.map +1 -0
- package/dist/runtime/session-manager.d.ts +466 -0
- package/dist/runtime/session-manager.d.ts.map +1 -0
- package/dist/runtime/session-manager.js +986 -0
- package/dist/runtime/session-manager.js.map +1 -0
- package/dist/runtime/spawner.d.ts +407 -0
- package/dist/runtime/spawner.d.ts.map +1 -0
- package/dist/runtime/spawner.js +781 -0
- package/dist/runtime/spawner.js.map +1 -0
- package/dist/server/config.d.ts +22 -0
- package/dist/server/config.d.ts.map +1 -0
- package/dist/server/config.js +59 -0
- package/dist/server/config.js.map +1 -0
- package/dist/server/daemon-state.d.ts +50 -0
- package/dist/server/daemon-state.d.ts.map +1 -0
- package/dist/server/daemon-state.js +100 -0
- package/dist/server/daemon-state.js.map +1 -0
- package/dist/server/events-websocket.d.ts +32 -0
- package/dist/server/events-websocket.d.ts.map +1 -0
- package/dist/server/events-websocket.js +96 -0
- package/dist/server/events-websocket.js.map +1 -0
- package/dist/server/formatters.d.ts +94 -0
- package/dist/server/formatters.d.ts.map +1 -0
- package/dist/server/formatters.js +142 -0
- package/dist/server/formatters.js.map +1 -0
- package/dist/server/index.d.ts +17 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +153 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/lsp-websocket.d.ts +33 -0
- package/dist/server/lsp-websocket.d.ts.map +1 -0
- package/dist/server/lsp-websocket.js +161 -0
- package/dist/server/lsp-websocket.js.map +1 -0
- package/dist/server/routes/agents.d.ts +9 -0
- package/dist/server/routes/agents.d.ts.map +1 -0
- package/dist/server/routes/agents.js +369 -0
- package/dist/server/routes/agents.js.map +1 -0
- package/dist/server/routes/daemon.d.ts +13 -0
- package/dist/server/routes/daemon.d.ts.map +1 -0
- package/dist/server/routes/daemon.js +187 -0
- package/dist/server/routes/daemon.js.map +1 -0
- package/dist/server/routes/events.d.ts +23 -0
- package/dist/server/routes/events.d.ts.map +1 -0
- package/dist/server/routes/events.js +282 -0
- package/dist/server/routes/events.js.map +1 -0
- package/dist/server/routes/extensions.d.ts +9 -0
- package/dist/server/routes/extensions.d.ts.map +1 -0
- package/dist/server/routes/extensions.js +202 -0
- package/dist/server/routes/extensions.js.map +1 -0
- package/dist/server/routes/health.d.ts +7 -0
- package/dist/server/routes/health.d.ts.map +1 -0
- package/dist/server/routes/health.js +33 -0
- package/dist/server/routes/health.js.map +1 -0
- package/dist/server/routes/index.d.ts +21 -0
- package/dist/server/routes/index.d.ts.map +1 -0
- package/dist/server/routes/index.js +21 -0
- package/dist/server/routes/index.js.map +1 -0
- package/dist/server/routes/lsp.d.ts +9 -0
- package/dist/server/routes/lsp.d.ts.map +1 -0
- package/dist/server/routes/lsp.js +50 -0
- package/dist/server/routes/lsp.js.map +1 -0
- package/dist/server/routes/plugins.d.ts +9 -0
- package/dist/server/routes/plugins.d.ts.map +1 -0
- package/dist/server/routes/plugins.js +109 -0
- package/dist/server/routes/plugins.js.map +1 -0
- package/dist/server/routes/pools.d.ts +9 -0
- package/dist/server/routes/pools.d.ts.map +1 -0
- package/dist/server/routes/pools.js +189 -0
- package/dist/server/routes/pools.js.map +1 -0
- package/dist/server/routes/scheduler.d.ts +9 -0
- package/dist/server/routes/scheduler.d.ts.map +1 -0
- package/dist/server/routes/scheduler.js +162 -0
- package/dist/server/routes/scheduler.js.map +1 -0
- package/dist/server/routes/sessions.d.ts +27 -0
- package/dist/server/routes/sessions.d.ts.map +1 -0
- package/dist/server/routes/sessions.js +773 -0
- package/dist/server/routes/sessions.js.map +1 -0
- package/dist/server/routes/tasks.d.ts +9 -0
- package/dist/server/routes/tasks.d.ts.map +1 -0
- package/dist/server/routes/tasks.js +954 -0
- package/dist/server/routes/tasks.js.map +1 -0
- package/dist/server/routes/upload.d.ts +8 -0
- package/dist/server/routes/upload.d.ts.map +1 -0
- package/dist/server/routes/upload.js +40 -0
- package/dist/server/routes/upload.js.map +1 -0
- package/dist/server/routes/workflows.d.ts +9 -0
- package/dist/server/routes/workflows.d.ts.map +1 -0
- package/dist/server/routes/workflows.js +532 -0
- package/dist/server/routes/workflows.js.map +1 -0
- package/dist/server/routes/workspace-files.d.ts +12 -0
- package/dist/server/routes/workspace-files.d.ts.map +1 -0
- package/dist/server/routes/workspace-files.js +520 -0
- package/dist/server/routes/workspace-files.js.map +1 -0
- package/dist/server/routes/worktrees.d.ts +9 -0
- package/dist/server/routes/worktrees.d.ts.map +1 -0
- package/dist/server/routes/worktrees.js +94 -0
- package/dist/server/routes/worktrees.js.map +1 -0
- package/dist/server/server.d.ts +14 -0
- package/dist/server/server.d.ts.map +1 -0
- package/dist/server/server.js +258 -0
- package/dist/server/server.js.map +1 -0
- package/dist/server/services/lsp-manager.d.ts +93 -0
- package/dist/server/services/lsp-manager.d.ts.map +1 -0
- package/dist/server/services/lsp-manager.js +291 -0
- package/dist/server/services/lsp-manager.js.map +1 -0
- package/dist/server/services/session-messages.d.ts +61 -0
- package/dist/server/services/session-messages.d.ts.map +1 -0
- package/dist/server/services/session-messages.js +101 -0
- package/dist/server/services/session-messages.js.map +1 -0
- package/dist/server/services.d.ts +35 -0
- package/dist/server/services.d.ts.map +1 -0
- package/dist/server/services.js +159 -0
- package/dist/server/services.js.map +1 -0
- package/dist/server/static.d.ts +18 -0
- package/dist/server/static.d.ts.map +1 -0
- package/dist/server/static.js +71 -0
- package/dist/server/static.js.map +1 -0
- package/dist/server/types.d.ts +20 -0
- package/dist/server/types.d.ts.map +1 -0
- package/dist/server/types.js +7 -0
- package/dist/server/types.js.map +1 -0
- package/dist/server/websocket.d.ts +16 -0
- package/dist/server/websocket.d.ts.map +1 -0
- package/dist/server/websocket.js +143 -0
- package/dist/server/websocket.js.map +1 -0
- package/dist/services/agent-pool-service.d.ts +181 -0
- package/dist/services/agent-pool-service.d.ts.map +1 -0
- package/dist/services/agent-pool-service.js +590 -0
- package/dist/services/agent-pool-service.js.map +1 -0
- package/dist/services/agent-registry.d.ts +185 -0
- package/dist/services/agent-registry.d.ts.map +1 -0
- package/dist/services/agent-registry.js +432 -0
- package/dist/services/agent-registry.js.map +1 -0
- package/dist/services/dispatch-daemon.d.ts +429 -0
- package/dist/services/dispatch-daemon.d.ts.map +1 -0
- package/dist/services/dispatch-daemon.js +1833 -0
- package/dist/services/dispatch-daemon.js.map +1 -0
- package/dist/services/dispatch-service.d.ts +148 -0
- package/dist/services/dispatch-service.d.ts.map +1 -0
- package/dist/services/dispatch-service.js +170 -0
- package/dist/services/dispatch-service.js.map +1 -0
- package/dist/services/docs-steward-service.d.ts +199 -0
- package/dist/services/docs-steward-service.d.ts.map +1 -0
- package/dist/services/docs-steward-service.js +599 -0
- package/dist/services/docs-steward-service.js.map +1 -0
- package/dist/services/health-steward-service.d.ts +446 -0
- package/dist/services/health-steward-service.d.ts.map +1 -0
- package/dist/services/health-steward-service.js +866 -0
- package/dist/services/health-steward-service.js.map +1 -0
- package/dist/services/index.d.ts +26 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +111 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/merge-request-provider.d.ts +59 -0
- package/dist/services/merge-request-provider.d.ts.map +1 -0
- package/dist/services/merge-request-provider.js +89 -0
- package/dist/services/merge-request-provider.js.map +1 -0
- package/dist/services/merge-steward-service.d.ts +268 -0
- package/dist/services/merge-steward-service.d.ts.map +1 -0
- package/dist/services/merge-steward-service.js +568 -0
- package/dist/services/merge-steward-service.js.map +1 -0
- package/dist/services/plugin-executor.d.ts +247 -0
- package/dist/services/plugin-executor.d.ts.map +1 -0
- package/dist/services/plugin-executor.js +451 -0
- package/dist/services/plugin-executor.js.map +1 -0
- package/dist/services/role-definition-service.d.ts +117 -0
- package/dist/services/role-definition-service.d.ts.map +1 -0
- package/dist/services/role-definition-service.js +289 -0
- package/dist/services/role-definition-service.js.map +1 -0
- package/dist/services/steward-scheduler.d.ts +336 -0
- package/dist/services/steward-scheduler.d.ts.map +1 -0
- package/dist/services/steward-scheduler.js +732 -0
- package/dist/services/steward-scheduler.js.map +1 -0
- package/dist/services/task-assignment-service.d.ts +291 -0
- package/dist/services/task-assignment-service.d.ts.map +1 -0
- package/dist/services/task-assignment-service.js +454 -0
- package/dist/services/task-assignment-service.js.map +1 -0
- package/dist/services/worker-task-service.d.ts +202 -0
- package/dist/services/worker-task-service.d.ts.map +1 -0
- package/dist/services/worker-task-service.js +228 -0
- package/dist/services/worker-task-service.js.map +1 -0
- package/dist/testing/index.d.ts +13 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +17 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/orchestration-tests.d.ts +62 -0
- package/dist/testing/orchestration-tests.d.ts.map +1 -0
- package/dist/testing/orchestration-tests.js +1115 -0
- package/dist/testing/orchestration-tests.js.map +1 -0
- package/dist/testing/test-context.d.ts +171 -0
- package/dist/testing/test-context.d.ts.map +1 -0
- package/dist/testing/test-context.js +665 -0
- package/dist/testing/test-context.js.map +1 -0
- package/dist/testing/test-prompts.d.ts +46 -0
- package/dist/testing/test-prompts.d.ts.map +1 -0
- package/dist/testing/test-prompts.js +140 -0
- package/dist/testing/test-prompts.js.map +1 -0
- package/dist/testing/test-utils.d.ts +200 -0
- package/dist/testing/test-utils.d.ts.map +1 -0
- package/dist/testing/test-utils.js +378 -0
- package/dist/testing/test-utils.js.map +1 -0
- package/dist/types/agent-pool.d.ts +215 -0
- package/dist/types/agent-pool.d.ts.map +1 -0
- package/dist/types/agent-pool.js +143 -0
- package/dist/types/agent-pool.js.map +1 -0
- package/dist/types/agent.d.ts +265 -0
- package/dist/types/agent.d.ts.map +1 -0
- package/dist/types/agent.js +127 -0
- package/dist/types/agent.js.map +1 -0
- package/dist/types/index.d.ts +11 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +40 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/message-types.d.ts +294 -0
- package/dist/types/message-types.d.ts.map +1 -0
- package/dist/types/message-types.js +354 -0
- package/dist/types/message-types.js.map +1 -0
- package/dist/types/role-definition.d.ts +272 -0
- package/dist/types/role-definition.d.ts.map +1 -0
- package/dist/types/role-definition.js +144 -0
- package/dist/types/role-definition.js.map +1 -0
- package/dist/types/task-meta.d.ts +248 -0
- package/dist/types/task-meta.d.ts.map +1 -0
- package/dist/types/task-meta.js +213 -0
- package/dist/types/task-meta.js.map +1 -0
- package/package.json +120 -0
- package/web/assets/abap-BrgZPUOV.js +6 -0
- package/web/assets/apex-DyP6w7ZV.js +6 -0
- package/web/assets/azcli-BaLxmfj-.js +6 -0
- package/web/assets/bat-CFOPXBzS.js +6 -0
- package/web/assets/bicep-BfEKNvv3.js +7 -0
- package/web/assets/cameligo-BFG1Mk7z.js +6 -0
- package/web/assets/clojure-DTECt2xU.js +6 -0
- package/web/assets/codicon-DCmgc-ay.ttf +0 -0
- package/web/assets/coffee-CDGzqUPQ.js +6 -0
- package/web/assets/cpp-CLLBncYj.js +6 -0
- package/web/assets/csharp-dUCx_-0o.js +6 -0
- package/web/assets/csp-5Rap-vPy.js +6 -0
- package/web/assets/css-D3h14YRZ.js +8 -0
- package/web/assets/cssMode-DMo-5YLA.js +9 -0
- package/web/assets/cypher-DrQuvNYM.js +6 -0
- package/web/assets/dart-CFKIUWau.js +6 -0
- package/web/assets/dockerfile-Zznr-cwX.js +6 -0
- package/web/assets/ecl-Ce3n6wWz.js +6 -0
- package/web/assets/elixir-deUWdS0T.js +6 -0
- package/web/assets/flow9-i9-g7ZhI.js +6 -0
- package/web/assets/freemarker2-D4qgkQzN.js +8 -0
- package/web/assets/fsharp-CzKuDChf.js +6 -0
- package/web/assets/go-Cphgjts3.js +6 -0
- package/web/assets/graphql-Cg7bfA9N.js +6 -0
- package/web/assets/handlebars-CXFvNjQC.js +6 -0
- package/web/assets/hcl-0cvrggvQ.js +6 -0
- package/web/assets/html-oyuB_D-B.js +6 -0
- package/web/assets/htmlMode-iWuZ24-r.js +9 -0
- package/web/assets/index-DqP-_E4F.css +32 -0
- package/web/assets/index-R1cylSgw.js +1665 -0
- package/web/assets/ini-Drc7WvVn.js +6 -0
- package/web/assets/java-B_fMsGYe.js +6 -0
- package/web/assets/javascript-CRIkN2Pg.js +6 -0
- package/web/assets/jsonMode-DVDkDgex.js +15 -0
- package/web/assets/julia-Bqgm2twL.js +6 -0
- package/web/assets/kotlin-BSkB5QuD.js +6 -0
- package/web/assets/less-BsTHnhdd.js +7 -0
- package/web/assets/lexon-YWi4-JPR.js +6 -0
- package/web/assets/liquid-CSfldbB5.js +6 -0
- package/web/assets/lua-nf6ki56Z.js +6 -0
- package/web/assets/m3-Cpb6xl2v.js +6 -0
- package/web/assets/markdown-DSZPf7rp.js +6 -0
- package/web/assets/mdx-Dd58iymR.js +6 -0
- package/web/assets/mips-B_c3zf-v.js +6 -0
- package/web/assets/monaco-editor-B4lwqA13.js +751 -0
- package/web/assets/monaco-editor-CQpyCxOA.css +1 -0
- package/web/assets/msdax-rUNN04Wq.js +6 -0
- package/web/assets/mysql-DDwshQtU.js +6 -0
- package/web/assets/objective-c-B5zXfXm9.js +6 -0
- package/web/assets/pascal-CXOwvkN_.js +6 -0
- package/web/assets/pascaligo-Bc-ZgV77.js +6 -0
- package/web/assets/perl-CwNk8-XU.js +6 -0
- package/web/assets/pgsql-tGk8EFnU.js +6 -0
- package/web/assets/php-CpIb_Oan.js +6 -0
- package/web/assets/pla-B03wrqEc.js +6 -0
- package/web/assets/postiats-BKlk5iyT.js +6 -0
- package/web/assets/powerquery-Bhzvs7bI.js +6 -0
- package/web/assets/powershell-Dd3NCNK9.js +6 -0
- package/web/assets/protobuf-COyEY5Pt.js +7 -0
- package/web/assets/pug-BaJupSGV.js +6 -0
- package/web/assets/python-XWrMqdhO.js +6 -0
- package/web/assets/qsharp-DXyYeYxl.js +6 -0
- package/web/assets/r-CdQndTaG.js +6 -0
- package/web/assets/razor-DPlhCpIs.js +6 -0
- package/web/assets/redis-CVwtpugi.js +6 -0
- package/web/assets/redshift-25W9uPmb.js +6 -0
- package/web/assets/restructuredtext-DfzH4Xui.js +6 -0
- package/web/assets/router-vendor-DHlGizSU.js +41 -0
- package/web/assets/ruby-Cp1zYvxS.js +6 -0
- package/web/assets/rust-D5C2fndG.js +6 -0
- package/web/assets/sb-CDntyWJ8.js +6 -0
- package/web/assets/scala-BoFRg7Ot.js +6 -0
- package/web/assets/scheme-Bio4gycK.js +6 -0
- package/web/assets/scss-4Ik7cdeQ.js +8 -0
- package/web/assets/shell-CX-rkNHf.js +6 -0
- package/web/assets/solidity-Tw7wswEv.js +6 -0
- package/web/assets/sophia-C5WLch3f.js +6 -0
- package/web/assets/sparql-DHaeiCBh.js +6 -0
- package/web/assets/sql-CCSDG5nI.js +6 -0
- package/web/assets/st-pnP8ivHi.js +6 -0
- package/web/assets/swift-DwJ7jVG9.js +8 -0
- package/web/assets/systemverilog-B9Xyijhd.js +6 -0
- package/web/assets/tcl-DnHyzjbg.js +6 -0
- package/web/assets/tsMode-BbA1Jbf3.js +16 -0
- package/web/assets/twig-CPajHgWi.js +6 -0
- package/web/assets/typescript-DcLHYzvH.js +6 -0
- package/web/assets/typespec-D-MeaMDU.js +6 -0
- package/web/assets/ui-vendor-BSco96uv.js +51 -0
- package/web/assets/utils-vendor-DaJ2Dubl.js +911 -0
- package/web/assets/vb-DgyLZaXg.js +6 -0
- package/web/assets/wgsl-DYQUnd45.js +303 -0
- package/web/assets/xml-xKYS3dO6.js +6 -0
- package/web/assets/yaml-CNmlXqzH.js +6 -0
- package/web/favicon.ico +0 -0
- package/web/index.html +22 -0
- package/web/logo.png +0 -0
|
@@ -0,0 +1,889 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task Commands - CLI operations for orchestrator task management
|
|
3
|
+
*
|
|
4
|
+
* Provides commands for task management:
|
|
5
|
+
* - task handoff <task-id>: Hand off a task to another agent
|
|
6
|
+
* - task complete <task-id>: Complete a task and optionally create a PR
|
|
7
|
+
* - task merge <task-id>: Mark a task as merged and close it
|
|
8
|
+
* - task reject <task-id>: Mark a task merge as failed and reopen it
|
|
9
|
+
* - task sync <task-id>: Sync a task branch with the main branch
|
|
10
|
+
*/
|
|
11
|
+
import { success, failure, ExitCode, getOutputMode } from '@stoneforge/quarry/cli';
|
|
12
|
+
import { TaskStatus, createTimestamp } from '@stoneforge/core';
|
|
13
|
+
// ============================================================================
|
|
14
|
+
// Shared Helpers
|
|
15
|
+
// ============================================================================
|
|
16
|
+
/**
|
|
17
|
+
* Creates task assignment service
|
|
18
|
+
*/
|
|
19
|
+
async function createTaskAssignmentService(options) {
|
|
20
|
+
try {
|
|
21
|
+
const { createStorage, initializeSchema, findStoneforgeDir } = await import('@stoneforge/quarry');
|
|
22
|
+
const { createTaskAssignmentService: createService } = await import('../../services/task-assignment-service.js');
|
|
23
|
+
const { createLocalMergeProvider } = await import('../../services/merge-request-provider.js');
|
|
24
|
+
const { QuarryAPIImpl } = await import('@stoneforge/quarry');
|
|
25
|
+
const stoneforgeDir = findStoneforgeDir(process.cwd());
|
|
26
|
+
if (!stoneforgeDir) {
|
|
27
|
+
return {
|
|
28
|
+
service: null,
|
|
29
|
+
error: 'No .stoneforge directory found. Run "sf init" first.',
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
const dbPath = options.db ?? `${stoneforgeDir}/stoneforge.db`;
|
|
33
|
+
const backend = createStorage({ path: dbPath, create: true });
|
|
34
|
+
initializeSchema(backend);
|
|
35
|
+
const api = new QuarryAPIImpl(backend);
|
|
36
|
+
const mergeProvider = createLocalMergeProvider();
|
|
37
|
+
const service = createService(api, mergeProvider);
|
|
38
|
+
return { service };
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
42
|
+
return { service: null, error: `Failed to initialize service: ${message}` };
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Creates an OrchestratorAPI instance for merge/reject operations
|
|
47
|
+
*/
|
|
48
|
+
async function createOrchestratorApi(options) {
|
|
49
|
+
try {
|
|
50
|
+
const { createStorage, initializeSchema, findStoneforgeDir } = await import('@stoneforge/quarry');
|
|
51
|
+
const { createOrchestratorAPI } = await import('../../api/orchestrator-api.js');
|
|
52
|
+
const stoneforgeDir = findStoneforgeDir(process.cwd());
|
|
53
|
+
if (!stoneforgeDir) {
|
|
54
|
+
return {
|
|
55
|
+
api: null,
|
|
56
|
+
error: 'No .stoneforge directory found. Run "sf init" first.',
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
const dbPath = options.db ?? `${stoneforgeDir}/stoneforge.db`;
|
|
60
|
+
const backend = createStorage({ path: dbPath, create: true });
|
|
61
|
+
initializeSchema(backend);
|
|
62
|
+
const api = createOrchestratorAPI(backend);
|
|
63
|
+
return { api };
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
67
|
+
return { api: null, error: `Failed to initialize API: ${message}` };
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Gets the current session ID from environment or generates a placeholder
|
|
72
|
+
*/
|
|
73
|
+
function getCurrentSessionId() {
|
|
74
|
+
// Check for session ID in environment (set by spawner or agent)
|
|
75
|
+
return process.env.STONEFORGE_SESSION_ID || `cli-${Date.now()}`;
|
|
76
|
+
}
|
|
77
|
+
const taskHandoffOptions = [
|
|
78
|
+
{
|
|
79
|
+
name: 'message',
|
|
80
|
+
short: 'm',
|
|
81
|
+
description: 'Handoff message explaining context and reason',
|
|
82
|
+
hasValue: true,
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
name: 'branch',
|
|
86
|
+
short: 'b',
|
|
87
|
+
description: 'Override the branch to preserve (defaults to task branch)',
|
|
88
|
+
hasValue: true,
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
name: 'worktree',
|
|
92
|
+
short: 'w',
|
|
93
|
+
description: 'Override the worktree path to preserve (defaults to task worktree)',
|
|
94
|
+
hasValue: true,
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
name: 'sessionId',
|
|
98
|
+
short: 's',
|
|
99
|
+
description: 'Session ID of the agent handing off (defaults to current session)',
|
|
100
|
+
hasValue: true,
|
|
101
|
+
},
|
|
102
|
+
];
|
|
103
|
+
async function taskHandoffHandler(args, options) {
|
|
104
|
+
const [taskId] = args;
|
|
105
|
+
if (!taskId) {
|
|
106
|
+
return failure('Usage: sf task handoff <task-id> [options]\nExample: sf task handoff el-abc123 --message "Need help with frontend"', ExitCode.INVALID_ARGUMENTS);
|
|
107
|
+
}
|
|
108
|
+
const { service, error } = await createTaskAssignmentService(options);
|
|
109
|
+
if (error || !service) {
|
|
110
|
+
return failure(error ?? 'Failed to create service', ExitCode.GENERAL_ERROR);
|
|
111
|
+
}
|
|
112
|
+
try {
|
|
113
|
+
const sessionId = options.sessionId || getCurrentSessionId();
|
|
114
|
+
const task = await service.handoffTask(taskId, {
|
|
115
|
+
sessionId,
|
|
116
|
+
message: options.message,
|
|
117
|
+
branch: options.branch,
|
|
118
|
+
worktree: options.worktree,
|
|
119
|
+
});
|
|
120
|
+
const mode = getOutputMode(options);
|
|
121
|
+
if (mode === 'json') {
|
|
122
|
+
return success({
|
|
123
|
+
taskId: task.id,
|
|
124
|
+
sessionId,
|
|
125
|
+
message: options.message,
|
|
126
|
+
branch: options.branch,
|
|
127
|
+
worktree: options.worktree,
|
|
128
|
+
handedOff: true,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
if (mode === 'quiet') {
|
|
132
|
+
return success(task.id);
|
|
133
|
+
}
|
|
134
|
+
const lines = [
|
|
135
|
+
`Handed off task ${taskId}`,
|
|
136
|
+
` Session: ${sessionId}`,
|
|
137
|
+
];
|
|
138
|
+
if (options.message) {
|
|
139
|
+
lines.push(` Message: ${options.message.slice(0, 50)}${options.message.length > 50 ? '...' : ''}`);
|
|
140
|
+
}
|
|
141
|
+
if (options.branch) {
|
|
142
|
+
lines.push(` Branch: ${options.branch}`);
|
|
143
|
+
}
|
|
144
|
+
if (options.worktree) {
|
|
145
|
+
lines.push(` Worktree: ${options.worktree}`);
|
|
146
|
+
}
|
|
147
|
+
lines.push('');
|
|
148
|
+
lines.push('Task has been unassigned and is available for pickup by another agent.');
|
|
149
|
+
return success(task, lines.join('\n'));
|
|
150
|
+
}
|
|
151
|
+
catch (err) {
|
|
152
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
153
|
+
return failure(`Failed to hand off task: ${message}`, ExitCode.GENERAL_ERROR);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
export const taskHandoffCommand = {
|
|
157
|
+
name: 'handoff',
|
|
158
|
+
description: 'Hand off a task to another agent',
|
|
159
|
+
usage: 'sf task handoff <task-id> [options]',
|
|
160
|
+
help: `Hand off a task to be picked up by another agent.
|
|
161
|
+
|
|
162
|
+
This command:
|
|
163
|
+
1. Preserves the branch and worktree references in task metadata
|
|
164
|
+
2. Appends a handoff note with context to the task description
|
|
165
|
+
3. Unassigns the task so it returns to the available pool
|
|
166
|
+
|
|
167
|
+
The next agent that picks up this task can continue from the
|
|
168
|
+
existing code state in the preserved branch/worktree.
|
|
169
|
+
|
|
170
|
+
Arguments:
|
|
171
|
+
task-id Task identifier to hand off
|
|
172
|
+
|
|
173
|
+
Options:
|
|
174
|
+
-m, --message <text> Handoff message with context and reason
|
|
175
|
+
-b, --branch <name> Override branch to preserve
|
|
176
|
+
-w, --worktree <path> Override worktree path to preserve
|
|
177
|
+
-s, --sessionId <id> Session ID (defaults to current session)
|
|
178
|
+
|
|
179
|
+
Examples:
|
|
180
|
+
sf task handoff el-abc123
|
|
181
|
+
sf task handoff el-abc123 --message "Completed API, need help with frontend"
|
|
182
|
+
sf task handoff el-abc123 -m "Blocked on database access" -b feature/my-branch`,
|
|
183
|
+
options: taskHandoffOptions,
|
|
184
|
+
handler: taskHandoffHandler,
|
|
185
|
+
};
|
|
186
|
+
const taskCompleteOptions = [
|
|
187
|
+
{
|
|
188
|
+
name: 'summary',
|
|
189
|
+
short: 's',
|
|
190
|
+
description: 'Summary of what was accomplished',
|
|
191
|
+
hasValue: true,
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
name: 'commitHash',
|
|
195
|
+
short: 'c',
|
|
196
|
+
description: 'Commit hash for the final commit',
|
|
197
|
+
hasValue: true,
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
name: 'no-mr',
|
|
201
|
+
description: 'Skip merge request creation',
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
name: 'mr-title',
|
|
205
|
+
description: 'Custom title for the merge request',
|
|
206
|
+
hasValue: true,
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
name: 'mr-body',
|
|
210
|
+
description: 'Custom body for the merge request',
|
|
211
|
+
hasValue: true,
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
name: 'baseBranch',
|
|
215
|
+
short: 'b',
|
|
216
|
+
description: 'Base branch for the merge request (default: main)',
|
|
217
|
+
hasValue: true,
|
|
218
|
+
},
|
|
219
|
+
];
|
|
220
|
+
async function taskCompleteHandler(args, options) {
|
|
221
|
+
const [taskId] = args;
|
|
222
|
+
if (!taskId) {
|
|
223
|
+
return failure('Usage: sf task complete <task-id> [options]\nExample: sf task complete el-abc123 --summary "Implemented feature"', ExitCode.INVALID_ARGUMENTS);
|
|
224
|
+
}
|
|
225
|
+
const { service, error } = await createTaskAssignmentService(options);
|
|
226
|
+
if (error || !service) {
|
|
227
|
+
return failure(error ?? 'Failed to create service', ExitCode.GENERAL_ERROR);
|
|
228
|
+
}
|
|
229
|
+
try {
|
|
230
|
+
const result = await service.completeTask(taskId, {
|
|
231
|
+
summary: options.summary,
|
|
232
|
+
commitHash: options.commitHash,
|
|
233
|
+
createMergeRequest: options['no-mr'] !== true,
|
|
234
|
+
mergeRequestTitle: options['mr-title'],
|
|
235
|
+
mergeRequestBody: options['mr-body'],
|
|
236
|
+
baseBranch: options.baseBranch,
|
|
237
|
+
});
|
|
238
|
+
const mode = getOutputMode(options);
|
|
239
|
+
if (mode === 'json') {
|
|
240
|
+
return success({
|
|
241
|
+
taskId: result.task.id,
|
|
242
|
+
status: result.task.status,
|
|
243
|
+
mergeRequestUrl: result.mergeRequestUrl,
|
|
244
|
+
mergeRequestId: result.mergeRequestId,
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
if (mode === 'quiet') {
|
|
248
|
+
return success(result.task.id);
|
|
249
|
+
}
|
|
250
|
+
const lines = [
|
|
251
|
+
`Completed task ${taskId}`,
|
|
252
|
+
` Status: ${result.task.status}`,
|
|
253
|
+
];
|
|
254
|
+
if (options.summary) {
|
|
255
|
+
lines.push(` Summary: ${options.summary.slice(0, 50)}${options.summary.length > 50 ? '...' : ''}`);
|
|
256
|
+
}
|
|
257
|
+
if (result.mergeRequestUrl) {
|
|
258
|
+
lines.push(` MR: ${result.mergeRequestUrl}`);
|
|
259
|
+
}
|
|
260
|
+
return success(result, lines.join('\n'));
|
|
261
|
+
}
|
|
262
|
+
catch (err) {
|
|
263
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
264
|
+
return failure(`Failed to complete task: ${message}`, ExitCode.GENERAL_ERROR);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
export const taskCompleteCommand = {
|
|
268
|
+
name: 'complete',
|
|
269
|
+
description: 'Complete a task and optionally create a merge request',
|
|
270
|
+
usage: 'sf task complete <task-id> [options]',
|
|
271
|
+
help: `Complete a task and optionally create a merge request.
|
|
272
|
+
|
|
273
|
+
This command:
|
|
274
|
+
1. Sets the task status to 'review' (awaiting merge)
|
|
275
|
+
2. Clears the task assignee
|
|
276
|
+
3. Records completion time and optional summary
|
|
277
|
+
4. Creates a merge request for the task branch (if a provider is configured)
|
|
278
|
+
|
|
279
|
+
Arguments:
|
|
280
|
+
task-id Task identifier to complete
|
|
281
|
+
|
|
282
|
+
Options:
|
|
283
|
+
-s, --summary <text> Summary of what was accomplished
|
|
284
|
+
-c, --commitHash <hash> Commit hash for the final commit
|
|
285
|
+
--no-mr Skip merge request creation
|
|
286
|
+
--mr-title <title> Custom MR title (defaults to task title)
|
|
287
|
+
--mr-body <body> Custom MR body
|
|
288
|
+
-b, --baseBranch <name> Base branch for MR (default: main)
|
|
289
|
+
|
|
290
|
+
Examples:
|
|
291
|
+
sf task complete el-abc123
|
|
292
|
+
sf task complete el-abc123 --summary "Implemented login feature"
|
|
293
|
+
sf task complete el-abc123 --no-mr
|
|
294
|
+
sf task complete el-abc123 --baseBranch develop`,
|
|
295
|
+
options: taskCompleteOptions,
|
|
296
|
+
handler: taskCompleteHandler,
|
|
297
|
+
};
|
|
298
|
+
const taskMergeOptions = [
|
|
299
|
+
{
|
|
300
|
+
name: 'summary',
|
|
301
|
+
short: 's',
|
|
302
|
+
description: 'Summary of the merge',
|
|
303
|
+
hasValue: true,
|
|
304
|
+
},
|
|
305
|
+
];
|
|
306
|
+
async function taskMergeHandler(args, options) {
|
|
307
|
+
const [taskId] = args;
|
|
308
|
+
if (!taskId) {
|
|
309
|
+
return failure('Usage: sf task merge <task-id> [options]\nExample: sf task merge el-abc123', ExitCode.INVALID_ARGUMENTS);
|
|
310
|
+
}
|
|
311
|
+
const { api, error } = await createOrchestratorApi(options);
|
|
312
|
+
if (error || !api) {
|
|
313
|
+
return failure(error ?? 'Failed to create API', ExitCode.GENERAL_ERROR);
|
|
314
|
+
}
|
|
315
|
+
try {
|
|
316
|
+
// 1. Get task and validate
|
|
317
|
+
const task = await api.get(taskId);
|
|
318
|
+
if (!task) {
|
|
319
|
+
return failure(`Task not found: ${taskId}`, ExitCode.GENERAL_ERROR);
|
|
320
|
+
}
|
|
321
|
+
if (task.status !== TaskStatus.REVIEW) {
|
|
322
|
+
return failure(`Task ${taskId} is in '${task.status}' status. Only REVIEW tasks can be merged.`, ExitCode.GENERAL_ERROR);
|
|
323
|
+
}
|
|
324
|
+
const { getOrchestratorTaskMeta, updateOrchestratorTaskMeta } = await import('../../types/task-meta.js');
|
|
325
|
+
const orchestratorMeta = getOrchestratorTaskMeta(task.metadata);
|
|
326
|
+
const sourceBranch = orchestratorMeta?.branch;
|
|
327
|
+
if (!sourceBranch) {
|
|
328
|
+
return failure(`Task ${taskId} has no branch in orchestrator metadata.`, ExitCode.GENERAL_ERROR);
|
|
329
|
+
}
|
|
330
|
+
// 2. Derive workspace root from .stoneforge dir
|
|
331
|
+
const { findStoneforgeDir } = await import('@stoneforge/quarry');
|
|
332
|
+
const stoneforgeDir = findStoneforgeDir(process.cwd());
|
|
333
|
+
if (!stoneforgeDir) {
|
|
334
|
+
return failure('No .stoneforge directory found. Run "sf init" first.', ExitCode.GENERAL_ERROR);
|
|
335
|
+
}
|
|
336
|
+
const { default: path } = await import('node:path');
|
|
337
|
+
const workspaceRoot = path.dirname(stoneforgeDir);
|
|
338
|
+
// 3. Call mergeBranch() with syncLocal disabled (we'll do it after bookkeeping)
|
|
339
|
+
const { mergeBranch, syncLocalBranch } = await import('../../git/merge.js');
|
|
340
|
+
const { detectTargetBranch } = await import('../../git/merge.js');
|
|
341
|
+
const commitMessage = `${task.title} (${taskId})`;
|
|
342
|
+
const mergeResult = await mergeBranch({
|
|
343
|
+
workspaceRoot,
|
|
344
|
+
sourceBranch,
|
|
345
|
+
commitMessage,
|
|
346
|
+
syncLocal: false,
|
|
347
|
+
});
|
|
348
|
+
if (!mergeResult.success) {
|
|
349
|
+
const lines = [`Failed to merge task ${taskId}: ${mergeResult.error}`];
|
|
350
|
+
if (mergeResult.conflictFiles?.length) {
|
|
351
|
+
lines.push('Conflict files:');
|
|
352
|
+
for (const f of mergeResult.conflictFiles) {
|
|
353
|
+
lines.push(` - ${f}`);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
return failure(lines.join('\n'), ExitCode.GENERAL_ERROR);
|
|
357
|
+
}
|
|
358
|
+
// 4. Atomic status update: set mergeStatus + close in one call
|
|
359
|
+
const now = createTimestamp();
|
|
360
|
+
const newMeta = updateOrchestratorTaskMeta(task.metadata, {
|
|
361
|
+
mergeStatus: 'merged',
|
|
362
|
+
completedAt: now,
|
|
363
|
+
...(options.summary ? { completionSummary: options.summary } : {}),
|
|
364
|
+
});
|
|
365
|
+
await api.update(taskId, {
|
|
366
|
+
status: TaskStatus.CLOSED,
|
|
367
|
+
assignee: undefined,
|
|
368
|
+
closedAt: now,
|
|
369
|
+
metadata: newMeta,
|
|
370
|
+
});
|
|
371
|
+
// 5. Clean up: delete source branch and remove task worktree (best-effort)
|
|
372
|
+
const { exec } = await import('node:child_process');
|
|
373
|
+
const { promisify } = await import('node:util');
|
|
374
|
+
const execAsync = promisify(exec);
|
|
375
|
+
try {
|
|
376
|
+
await execAsync(`git branch -D ${sourceBranch}`, { cwd: workspaceRoot });
|
|
377
|
+
}
|
|
378
|
+
catch { /* branch may not exist locally */ }
|
|
379
|
+
try {
|
|
380
|
+
await execAsync(`git push origin --delete ${sourceBranch}`, { cwd: workspaceRoot });
|
|
381
|
+
}
|
|
382
|
+
catch { /* branch may not exist on remote */ }
|
|
383
|
+
const worktreePath = orchestratorMeta?.worktree;
|
|
384
|
+
if (worktreePath) {
|
|
385
|
+
try {
|
|
386
|
+
await execAsync(`git worktree remove --force "${worktreePath}"`, { cwd: workspaceRoot });
|
|
387
|
+
}
|
|
388
|
+
catch { /* worktree may already be gone */ }
|
|
389
|
+
}
|
|
390
|
+
// 6. Sync local target branch (best-effort, after all bookkeeping is done)
|
|
391
|
+
const targetBranch = await detectTargetBranch(workspaceRoot);
|
|
392
|
+
try {
|
|
393
|
+
await execAsync('git fetch origin', { cwd: workspaceRoot, encoding: 'utf8' });
|
|
394
|
+
}
|
|
395
|
+
catch { /* best-effort */ }
|
|
396
|
+
await syncLocalBranch(workspaceRoot, targetBranch);
|
|
397
|
+
// 7. Output result
|
|
398
|
+
const mode = getOutputMode(options);
|
|
399
|
+
if (mode === 'json') {
|
|
400
|
+
return success({
|
|
401
|
+
taskId,
|
|
402
|
+
mergeStatus: 'merged',
|
|
403
|
+
commitHash: mergeResult.commitHash,
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
if (mode === 'quiet') {
|
|
407
|
+
return success(taskId);
|
|
408
|
+
}
|
|
409
|
+
const lines = [
|
|
410
|
+
`Merged task ${taskId}`,
|
|
411
|
+
` Commit: ${mergeResult.commitHash}`,
|
|
412
|
+
' Merge Status: merged',
|
|
413
|
+
' Task Status: CLOSED',
|
|
414
|
+
];
|
|
415
|
+
if (options.summary) {
|
|
416
|
+
lines.push(` Summary: ${options.summary.slice(0, 50)}${options.summary.length > 50 ? '...' : ''}`);
|
|
417
|
+
}
|
|
418
|
+
return success({ taskId, mergeStatus: 'merged', commitHash: mergeResult.commitHash }, lines.join('\n'));
|
|
419
|
+
}
|
|
420
|
+
catch (err) {
|
|
421
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
422
|
+
return failure(`Failed to merge task: ${message}`, ExitCode.GENERAL_ERROR);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
export const taskMergeCommand = {
|
|
426
|
+
name: 'merge',
|
|
427
|
+
description: 'Squash-merge a task branch and close the task',
|
|
428
|
+
usage: 'sf task merge <task-id> [options]',
|
|
429
|
+
help: `Squash-merge a task's branch into the target branch and close it.
|
|
430
|
+
|
|
431
|
+
This command:
|
|
432
|
+
1. Validates the task is in REVIEW status with an associated branch
|
|
433
|
+
2. Squash-merges the branch into the target branch (auto-detected)
|
|
434
|
+
3. Pushes to remote
|
|
435
|
+
4. Atomically sets merge status to "merged" and closes the task
|
|
436
|
+
5. Cleans up the source branch (local + remote) and worktree
|
|
437
|
+
|
|
438
|
+
Arguments:
|
|
439
|
+
task-id Task identifier to merge
|
|
440
|
+
|
|
441
|
+
Options:
|
|
442
|
+
-s, --summary <text> Summary of the merge
|
|
443
|
+
|
|
444
|
+
Examples:
|
|
445
|
+
sf task merge el-abc123
|
|
446
|
+
sf task merge el-abc123 --summary "All tests passing, merged to main"`,
|
|
447
|
+
options: taskMergeOptions,
|
|
448
|
+
handler: taskMergeHandler,
|
|
449
|
+
};
|
|
450
|
+
const taskRejectOptions = [
|
|
451
|
+
{
|
|
452
|
+
name: 'reason',
|
|
453
|
+
short: 'r',
|
|
454
|
+
description: 'Reason for rejection (required)',
|
|
455
|
+
hasValue: true,
|
|
456
|
+
},
|
|
457
|
+
{
|
|
458
|
+
name: 'message',
|
|
459
|
+
short: 'm',
|
|
460
|
+
description: 'Handoff message for the next worker',
|
|
461
|
+
hasValue: true,
|
|
462
|
+
},
|
|
463
|
+
];
|
|
464
|
+
async function taskRejectHandler(args, options) {
|
|
465
|
+
const [taskId] = args;
|
|
466
|
+
if (!taskId) {
|
|
467
|
+
return failure('Usage: sf task reject <task-id> --reason "..." [options]\nExample: sf task reject el-abc123 --reason "Tests failed"', ExitCode.INVALID_ARGUMENTS);
|
|
468
|
+
}
|
|
469
|
+
if (!options.reason) {
|
|
470
|
+
return failure('--reason is required. Usage: sf task reject <task-id> --reason "..."\nExample: sf task reject el-abc123 --reason "Tests failed"', ExitCode.INVALID_ARGUMENTS);
|
|
471
|
+
}
|
|
472
|
+
const { api, error } = await createOrchestratorApi(options);
|
|
473
|
+
if (error || !api) {
|
|
474
|
+
return failure(error ?? 'Failed to create API', ExitCode.GENERAL_ERROR);
|
|
475
|
+
}
|
|
476
|
+
try {
|
|
477
|
+
await api.updateTaskOrchestratorMeta(taskId, {
|
|
478
|
+
mergeStatus: 'test_failed',
|
|
479
|
+
mergeFailureReason: options.reason,
|
|
480
|
+
...(options.message ? { handoffHistory: [{ sessionId: 'cli', message: options.message, handoffAt: new Date().toISOString() }] } : {}),
|
|
481
|
+
});
|
|
482
|
+
await api.update(taskId, {
|
|
483
|
+
status: TaskStatus.OPEN,
|
|
484
|
+
assignee: undefined,
|
|
485
|
+
});
|
|
486
|
+
const mode = getOutputMode(options);
|
|
487
|
+
if (mode === 'json') {
|
|
488
|
+
return success({
|
|
489
|
+
taskId,
|
|
490
|
+
mergeStatus: 'test_failed',
|
|
491
|
+
reason: options.reason,
|
|
492
|
+
message: options.message,
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
if (mode === 'quiet') {
|
|
496
|
+
return success(taskId);
|
|
497
|
+
}
|
|
498
|
+
const lines = [
|
|
499
|
+
`Rejected task ${taskId}`,
|
|
500
|
+
' Merge Status: test_failed',
|
|
501
|
+
` Reason: ${options.reason.slice(0, 50)}${options.reason.length > 50 ? '...' : ''}`,
|
|
502
|
+
];
|
|
503
|
+
if (options.message) {
|
|
504
|
+
lines.push(` Handoff: ${options.message.slice(0, 50)}${options.message.length > 50 ? '...' : ''}`);
|
|
505
|
+
}
|
|
506
|
+
lines.push('');
|
|
507
|
+
lines.push('Task has been reopened and unassigned for pickup by another agent.');
|
|
508
|
+
return success({ taskId, mergeStatus: 'test_failed' }, lines.join('\n'));
|
|
509
|
+
}
|
|
510
|
+
catch (err) {
|
|
511
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
512
|
+
return failure(`Failed to reject task: ${message}`, ExitCode.GENERAL_ERROR);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
export const taskRejectCommand = {
|
|
516
|
+
name: 'reject',
|
|
517
|
+
description: 'Mark a task merge as failed and reopen it',
|
|
518
|
+
usage: 'sf task reject <task-id> --reason "..." [options]',
|
|
519
|
+
help: `Mark a task merge as failed and reopen it.
|
|
520
|
+
|
|
521
|
+
This command:
|
|
522
|
+
1. Sets the task's merge status to "test_failed"
|
|
523
|
+
2. Records the failure reason
|
|
524
|
+
3. Reopens the task and unassigns it
|
|
525
|
+
|
|
526
|
+
Arguments:
|
|
527
|
+
task-id Task identifier to reject
|
|
528
|
+
|
|
529
|
+
Options:
|
|
530
|
+
-r, --reason <text> Reason for rejection (required)
|
|
531
|
+
-m, --message <text> Handoff message for the next worker
|
|
532
|
+
|
|
533
|
+
Examples:
|
|
534
|
+
sf task reject el-abc123 --reason "Tests failed"
|
|
535
|
+
sf task reject el-abc123 --reason "Tests failed" --message "Fix flaky test in auth.test.ts"`,
|
|
536
|
+
options: taskRejectOptions,
|
|
537
|
+
handler: taskRejectHandler,
|
|
538
|
+
};
|
|
539
|
+
async function taskSyncHandler(args, options) {
|
|
540
|
+
const [taskId] = args;
|
|
541
|
+
if (!taskId) {
|
|
542
|
+
return failure('Usage: sf task sync <task-id>\nExample: sf task sync el-abc123', ExitCode.INVALID_ARGUMENTS);
|
|
543
|
+
}
|
|
544
|
+
const { api, error } = await createOrchestratorApi(options);
|
|
545
|
+
if (error || !api) {
|
|
546
|
+
return failure(error ?? 'Failed to create API', ExitCode.GENERAL_ERROR);
|
|
547
|
+
}
|
|
548
|
+
try {
|
|
549
|
+
// 1. Get task and its metadata
|
|
550
|
+
const task = await api.get(taskId);
|
|
551
|
+
if (!task) {
|
|
552
|
+
return failure(`Task not found: ${taskId}`, ExitCode.GENERAL_ERROR);
|
|
553
|
+
}
|
|
554
|
+
// 2. Extract worktree and branch from task metadata
|
|
555
|
+
const taskMeta = task.metadata;
|
|
556
|
+
const orchestratorMeta = taskMeta?.orchestrator;
|
|
557
|
+
const worktreePath = orchestratorMeta?.worktree;
|
|
558
|
+
const branch = orchestratorMeta?.branch;
|
|
559
|
+
if (!worktreePath) {
|
|
560
|
+
const syncResult = {
|
|
561
|
+
success: false,
|
|
562
|
+
error: 'No worktree path found in task metadata',
|
|
563
|
+
message: 'Task has no worktree path - cannot sync',
|
|
564
|
+
};
|
|
565
|
+
const mode = getOutputMode(options);
|
|
566
|
+
if (mode === 'json') {
|
|
567
|
+
return success(syncResult);
|
|
568
|
+
}
|
|
569
|
+
return failure(syncResult.message, ExitCode.GENERAL_ERROR);
|
|
570
|
+
}
|
|
571
|
+
// 3. Check if worktree exists
|
|
572
|
+
const { findStoneforgeDir } = await import('@stoneforge/quarry');
|
|
573
|
+
const { createWorktreeManager } = await import('../../git/worktree-manager.js');
|
|
574
|
+
const stoneforgeDir = findStoneforgeDir(process.cwd());
|
|
575
|
+
if (!stoneforgeDir) {
|
|
576
|
+
return failure('No .stoneforge directory found. Run "sf init" first.', ExitCode.GENERAL_ERROR);
|
|
577
|
+
}
|
|
578
|
+
// Get workspace root (parent of .stoneforge)
|
|
579
|
+
const path = await import('node:path');
|
|
580
|
+
const workspaceRoot = path.dirname(stoneforgeDir);
|
|
581
|
+
const worktreeManager = createWorktreeManager({ workspaceRoot });
|
|
582
|
+
await worktreeManager.initWorkspace();
|
|
583
|
+
const worktreeExists = await worktreeManager.worktreeExists(worktreePath);
|
|
584
|
+
if (!worktreeExists) {
|
|
585
|
+
const syncResult = {
|
|
586
|
+
success: false,
|
|
587
|
+
error: `Worktree does not exist: ${worktreePath}`,
|
|
588
|
+
message: `Worktree not found at ${worktreePath}`,
|
|
589
|
+
worktreePath,
|
|
590
|
+
branch,
|
|
591
|
+
};
|
|
592
|
+
const mode = getOutputMode(options);
|
|
593
|
+
if (mode === 'json') {
|
|
594
|
+
return success(syncResult);
|
|
595
|
+
}
|
|
596
|
+
return failure(syncResult.message, ExitCode.GENERAL_ERROR);
|
|
597
|
+
}
|
|
598
|
+
// 4. Run git fetch and merge in the worktree
|
|
599
|
+
const { execFile } = await import('node:child_process');
|
|
600
|
+
const { promisify } = await import('node:util');
|
|
601
|
+
const execFileAsync = promisify(execFile);
|
|
602
|
+
// Resolve full worktree path
|
|
603
|
+
const fullWorktreePath = path.isAbsolute(worktreePath)
|
|
604
|
+
? worktreePath
|
|
605
|
+
: path.join(workspaceRoot, worktreePath);
|
|
606
|
+
// Fetch from origin
|
|
607
|
+
try {
|
|
608
|
+
await execFileAsync('git', ['fetch', 'origin'], {
|
|
609
|
+
cwd: fullWorktreePath,
|
|
610
|
+
encoding: 'utf8',
|
|
611
|
+
timeout: 60_000,
|
|
612
|
+
});
|
|
613
|
+
}
|
|
614
|
+
catch (fetchError) {
|
|
615
|
+
const syncResult = {
|
|
616
|
+
success: false,
|
|
617
|
+
error: `Failed to fetch from origin: ${fetchError.message}`,
|
|
618
|
+
message: 'Git fetch failed',
|
|
619
|
+
worktreePath,
|
|
620
|
+
branch,
|
|
621
|
+
};
|
|
622
|
+
const mode = getOutputMode(options);
|
|
623
|
+
if (mode === 'json') {
|
|
624
|
+
return success(syncResult);
|
|
625
|
+
}
|
|
626
|
+
return failure(syncResult.message, ExitCode.GENERAL_ERROR);
|
|
627
|
+
}
|
|
628
|
+
// Detect the default branch (main or master)
|
|
629
|
+
const defaultBranch = await worktreeManager.getDefaultBranch();
|
|
630
|
+
const remoteBranch = `origin/${defaultBranch}`;
|
|
631
|
+
// Attempt to merge
|
|
632
|
+
try {
|
|
633
|
+
await execFileAsync('git', ['merge', remoteBranch, '--no-edit'], {
|
|
634
|
+
cwd: fullWorktreePath,
|
|
635
|
+
encoding: 'utf8',
|
|
636
|
+
timeout: 120_000,
|
|
637
|
+
});
|
|
638
|
+
// Merge succeeded
|
|
639
|
+
const syncResult = {
|
|
640
|
+
success: true,
|
|
641
|
+
message: `Branch synced with ${remoteBranch}`,
|
|
642
|
+
worktreePath,
|
|
643
|
+
branch,
|
|
644
|
+
};
|
|
645
|
+
const mode = getOutputMode(options);
|
|
646
|
+
if (mode === 'json') {
|
|
647
|
+
return success(syncResult);
|
|
648
|
+
}
|
|
649
|
+
if (mode === 'quiet') {
|
|
650
|
+
return success('synced');
|
|
651
|
+
}
|
|
652
|
+
return success(syncResult, `✓ Branch synced with ${remoteBranch}`);
|
|
653
|
+
}
|
|
654
|
+
catch (mergeError) {
|
|
655
|
+
// Check for merge conflicts
|
|
656
|
+
try {
|
|
657
|
+
const { stdout: statusOutput } = await execFileAsync('git', ['status', '--porcelain'], {
|
|
658
|
+
cwd: fullWorktreePath,
|
|
659
|
+
encoding: 'utf8',
|
|
660
|
+
});
|
|
661
|
+
// Parse conflicted files (lines starting with UU, AA, DD, AU, UA, DU, UD)
|
|
662
|
+
const conflictPatterns = /^(UU|AA|DD|AU|UA|DU|UD)\s+(.+)$/gm;
|
|
663
|
+
const conflicts = [];
|
|
664
|
+
let match;
|
|
665
|
+
while ((match = conflictPatterns.exec(statusOutput)) !== null) {
|
|
666
|
+
conflicts.push(match[2]);
|
|
667
|
+
}
|
|
668
|
+
if (conflicts.length > 0) {
|
|
669
|
+
const syncResult = {
|
|
670
|
+
success: false,
|
|
671
|
+
conflicts,
|
|
672
|
+
message: `Merge conflicts detected in ${conflicts.length} file(s)`,
|
|
673
|
+
worktreePath,
|
|
674
|
+
branch,
|
|
675
|
+
};
|
|
676
|
+
const mode = getOutputMode(options);
|
|
677
|
+
if (mode === 'json') {
|
|
678
|
+
return success(syncResult);
|
|
679
|
+
}
|
|
680
|
+
if (mode === 'quiet') {
|
|
681
|
+
return success(conflicts.join('\n'));
|
|
682
|
+
}
|
|
683
|
+
const lines = [
|
|
684
|
+
`⚠ Merge conflicts detected in ${conflicts.length} file(s):`,
|
|
685
|
+
...conflicts.map(f => ` - ${f}`),
|
|
686
|
+
'',
|
|
687
|
+
'Resolve conflicts, then commit the resolution.',
|
|
688
|
+
];
|
|
689
|
+
return success(syncResult, lines.join('\n'));
|
|
690
|
+
}
|
|
691
|
+
// Some other merge error (not conflicts)
|
|
692
|
+
const syncResult = {
|
|
693
|
+
success: false,
|
|
694
|
+
error: mergeError.message,
|
|
695
|
+
message: 'Merge failed (not due to conflicts)',
|
|
696
|
+
worktreePath,
|
|
697
|
+
branch,
|
|
698
|
+
};
|
|
699
|
+
const mode = getOutputMode(options);
|
|
700
|
+
if (mode === 'json') {
|
|
701
|
+
return success(syncResult);
|
|
702
|
+
}
|
|
703
|
+
return failure(syncResult.message, ExitCode.GENERAL_ERROR);
|
|
704
|
+
}
|
|
705
|
+
catch {
|
|
706
|
+
// Failed to check status
|
|
707
|
+
const syncResult = {
|
|
708
|
+
success: false,
|
|
709
|
+
error: mergeError.message,
|
|
710
|
+
message: 'Merge failed',
|
|
711
|
+
worktreePath,
|
|
712
|
+
branch,
|
|
713
|
+
};
|
|
714
|
+
const mode = getOutputMode(options);
|
|
715
|
+
if (mode === 'json') {
|
|
716
|
+
return success(syncResult);
|
|
717
|
+
}
|
|
718
|
+
return failure(syncResult.message, ExitCode.GENERAL_ERROR);
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
catch (err) {
|
|
723
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
724
|
+
return failure(`Failed to sync task branch: ${message}`, ExitCode.GENERAL_ERROR);
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
export const taskSyncCommand = {
|
|
728
|
+
name: 'sync',
|
|
729
|
+
description: 'Sync a task branch with the main branch',
|
|
730
|
+
usage: 'sf task sync <task-id>',
|
|
731
|
+
help: `Sync a task's branch with the main branch (master/main).
|
|
732
|
+
|
|
733
|
+
This command:
|
|
734
|
+
1. Looks up the task's worktree path and branch from metadata
|
|
735
|
+
2. Runs \`git fetch origin\` in the worktree
|
|
736
|
+
3. Attempts \`git merge origin/main\` (or origin/master)
|
|
737
|
+
4. Reports success, conflicts, or errors
|
|
738
|
+
|
|
739
|
+
This is typically run by the dispatch daemon before spawning a merge steward,
|
|
740
|
+
or by the steward during review if master advances.
|
|
741
|
+
|
|
742
|
+
Arguments:
|
|
743
|
+
task-id Task identifier to sync
|
|
744
|
+
|
|
745
|
+
Output (JSON mode):
|
|
746
|
+
{
|
|
747
|
+
"success": true/false,
|
|
748
|
+
"conflicts": ["file1.ts", "file2.ts"], // if conflicts
|
|
749
|
+
"error": "message", // if error
|
|
750
|
+
"message": "human-readable status",
|
|
751
|
+
"worktreePath": "/path/to/worktree",
|
|
752
|
+
"branch": "agent/bob/el-123-feature"
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
Examples:
|
|
756
|
+
sf task sync el-abc123
|
|
757
|
+
sf task sync el-abc123 --json`,
|
|
758
|
+
options: [],
|
|
759
|
+
handler: taskSyncHandler,
|
|
760
|
+
};
|
|
761
|
+
// ============================================================================
|
|
762
|
+
// Task Merge-Status Command
|
|
763
|
+
// ============================================================================
|
|
764
|
+
import { MergeStatusValues, isMergeStatus } from '../../types/task-meta.js';
|
|
765
|
+
async function taskMergeStatusHandler(args, options) {
|
|
766
|
+
const [taskId, statusArg] = args;
|
|
767
|
+
if (!taskId || !statusArg) {
|
|
768
|
+
return failure(`Usage: sf task merge-status <task-id> <status>\nExample: sf task merge-status el-abc123 merged\n\nValid statuses: ${MergeStatusValues.join(', ')}`, ExitCode.INVALID_ARGUMENTS);
|
|
769
|
+
}
|
|
770
|
+
// Validate that the provided status is a valid MergeStatus
|
|
771
|
+
if (!isMergeStatus(statusArg)) {
|
|
772
|
+
return failure(`Invalid merge status: "${statusArg}"\nValid statuses: ${MergeStatusValues.join(', ')}`, ExitCode.INVALID_ARGUMENTS);
|
|
773
|
+
}
|
|
774
|
+
const status = statusArg;
|
|
775
|
+
const { api, error } = await createOrchestratorApi(options);
|
|
776
|
+
if (error || !api) {
|
|
777
|
+
return failure(error ?? 'Failed to create API', ExitCode.GENERAL_ERROR);
|
|
778
|
+
}
|
|
779
|
+
try {
|
|
780
|
+
// Terminal statuses (merged, not_applicable) also close the task atomically
|
|
781
|
+
if (status === 'merged' || status === 'not_applicable') {
|
|
782
|
+
const task = await api.get(taskId);
|
|
783
|
+
if (!task) {
|
|
784
|
+
return failure(`Task not found: ${taskId}`, ExitCode.GENERAL_ERROR);
|
|
785
|
+
}
|
|
786
|
+
const { updateOrchestratorTaskMeta } = await import('../../types/task-meta.js');
|
|
787
|
+
const now = createTimestamp();
|
|
788
|
+
const newMeta = updateOrchestratorTaskMeta(task.metadata, { mergeStatus: status });
|
|
789
|
+
await api.update(taskId, {
|
|
790
|
+
status: TaskStatus.CLOSED,
|
|
791
|
+
closedAt: now,
|
|
792
|
+
metadata: newMeta,
|
|
793
|
+
});
|
|
794
|
+
}
|
|
795
|
+
else {
|
|
796
|
+
await api.updateTaskOrchestratorMeta(taskId, {
|
|
797
|
+
mergeStatus: status,
|
|
798
|
+
});
|
|
799
|
+
}
|
|
800
|
+
const mode = getOutputMode(options);
|
|
801
|
+
if (mode === 'json') {
|
|
802
|
+
return success({
|
|
803
|
+
taskId,
|
|
804
|
+
mergeStatus: status,
|
|
805
|
+
});
|
|
806
|
+
}
|
|
807
|
+
if (mode === 'quiet') {
|
|
808
|
+
return success(taskId);
|
|
809
|
+
}
|
|
810
|
+
const statusLine = (status === 'merged' || status === 'not_applicable')
|
|
811
|
+
? `Updated task ${taskId}\n Merge Status: ${status}\n Task Status: CLOSED`
|
|
812
|
+
: `Updated task ${taskId}\n Merge Status: ${status}`;
|
|
813
|
+
return success({ taskId, mergeStatus: status }, statusLine);
|
|
814
|
+
}
|
|
815
|
+
catch (err) {
|
|
816
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
817
|
+
if (message.includes('not found') || message.includes('Task not found')) {
|
|
818
|
+
return failure(`Task not found: ${taskId}`, ExitCode.GENERAL_ERROR);
|
|
819
|
+
}
|
|
820
|
+
return failure(`Failed to update merge status: ${message}`, ExitCode.GENERAL_ERROR);
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
export const taskMergeStatusCommand = {
|
|
824
|
+
name: 'merge-status',
|
|
825
|
+
description: 'Update the merge status of a task',
|
|
826
|
+
usage: 'sf task merge-status <task-id> <status>',
|
|
827
|
+
help: `Update the merge status of a task.
|
|
828
|
+
|
|
829
|
+
This command allows you to manually update the merge status of a task,
|
|
830
|
+
which is useful when the merge steward gets stuck or when a branch is
|
|
831
|
+
manually merged outside of the normal workflow.
|
|
832
|
+
|
|
833
|
+
Arguments:
|
|
834
|
+
task-id Task identifier to update
|
|
835
|
+
status New merge status value
|
|
836
|
+
|
|
837
|
+
Valid status values:
|
|
838
|
+
pending Task completed, awaiting merge
|
|
839
|
+
testing Steward is running tests on the branch
|
|
840
|
+
merging Tests passed, merge in progress
|
|
841
|
+
merged Successfully merged
|
|
842
|
+
conflict Merge conflict detected
|
|
843
|
+
test_failed Tests failed, needs attention
|
|
844
|
+
failed Merge failed for other reason
|
|
845
|
+
not_applicable No merge needed (issue already fixed on master)
|
|
846
|
+
|
|
847
|
+
Examples:
|
|
848
|
+
sf task merge-status el-abc123 merged
|
|
849
|
+
sf task merge-status el-abc123 pending
|
|
850
|
+
sf task merge-status el-abc123 test_failed`,
|
|
851
|
+
options: [],
|
|
852
|
+
handler: taskMergeStatusHandler,
|
|
853
|
+
};
|
|
854
|
+
// ============================================================================
|
|
855
|
+
// Main Task Command
|
|
856
|
+
// ============================================================================
|
|
857
|
+
export const taskCommand = {
|
|
858
|
+
name: 'task',
|
|
859
|
+
description: 'Orchestrator task management',
|
|
860
|
+
usage: 'sf task <subcommand> [options]',
|
|
861
|
+
help: `Orchestrator task management commands.
|
|
862
|
+
|
|
863
|
+
Subcommands:
|
|
864
|
+
handoff Hand off a task to another agent
|
|
865
|
+
complete Complete a task and optionally create a merge request
|
|
866
|
+
merge Mark a task as merged and close it
|
|
867
|
+
reject Mark a task merge as failed and reopen it
|
|
868
|
+
sync Sync a task branch with the main branch
|
|
869
|
+
merge-status Update the merge status of a task
|
|
870
|
+
|
|
871
|
+
Examples:
|
|
872
|
+
sf task handoff el-abc123 --message "Need help with frontend"
|
|
873
|
+
sf task complete el-abc123 --summary "Implemented feature"
|
|
874
|
+
sf task merge el-abc123
|
|
875
|
+
sf task reject el-abc123 --reason "Tests failed"
|
|
876
|
+
sf task sync el-abc123
|
|
877
|
+
sf task merge-status el-abc123 merged`,
|
|
878
|
+
subcommands: {
|
|
879
|
+
handoff: taskHandoffCommand,
|
|
880
|
+
complete: taskCompleteCommand,
|
|
881
|
+
merge: taskMergeCommand,
|
|
882
|
+
reject: taskRejectCommand,
|
|
883
|
+
sync: taskSyncCommand,
|
|
884
|
+
'merge-status': taskMergeStatusCommand,
|
|
885
|
+
},
|
|
886
|
+
handler: taskHandoffCommand.handler, // Default to handoff
|
|
887
|
+
options: [],
|
|
888
|
+
};
|
|
889
|
+
//# sourceMappingURL=task.js.map
|