task-o-matic-core 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/README.md +646 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +46 -0
- package/dist/lib/ai-service/ai-operations.d.ts +45 -0
- package/dist/lib/ai-service/ai-operations.d.ts.map +1 -0
- package/dist/lib/ai-service/ai-operations.js +60 -0
- package/dist/lib/ai-service/base-operations.d.ts +43 -0
- package/dist/lib/ai-service/base-operations.d.ts.map +1 -0
- package/dist/lib/ai-service/base-operations.js +119 -0
- package/dist/lib/ai-service/documentation-operations.d.ts +18 -0
- package/dist/lib/ai-service/documentation-operations.d.ts.map +1 -0
- package/dist/lib/ai-service/documentation-operations.js +308 -0
- package/dist/lib/ai-service/filesystem-tools.d.ts +69 -0
- package/dist/lib/ai-service/filesystem-tools.d.ts.map +1 -0
- package/dist/lib/ai-service/filesystem-tools.js +70 -0
- package/dist/lib/ai-service/json-parser.d.ts +34 -0
- package/dist/lib/ai-service/json-parser.d.ts.map +1 -0
- package/dist/lib/ai-service/json-parser.js +177 -0
- package/dist/lib/ai-service/mcp-client.d.ts +9 -0
- package/dist/lib/ai-service/mcp-client.d.ts.map +1 -0
- package/dist/lib/ai-service/mcp-client.js +48 -0
- package/dist/lib/ai-service/model-provider.d.ts +12 -0
- package/dist/lib/ai-service/model-provider.d.ts.map +1 -0
- package/dist/lib/ai-service/model-provider.js +146 -0
- package/dist/lib/ai-service/prd-operations.d.ts +25 -0
- package/dist/lib/ai-service/prd-operations.d.ts.map +1 -0
- package/dist/lib/ai-service/prd-operations.js +592 -0
- package/dist/lib/ai-service/research-tools.d.ts +4 -0
- package/dist/lib/ai-service/research-tools.d.ts.map +1 -0
- package/dist/lib/ai-service/research-tools.js +8 -0
- package/dist/lib/ai-service/retry-handler.d.ts +8 -0
- package/dist/lib/ai-service/retry-handler.d.ts.map +1 -0
- package/dist/lib/ai-service/retry-handler.js +63 -0
- package/dist/lib/ai-service/task-operations.d.ts +13 -0
- package/dist/lib/ai-service/task-operations.d.ts.map +1 -0
- package/dist/lib/ai-service/task-operations.js +220 -0
- package/dist/lib/benchmark/registry.d.ts +11 -0
- package/dist/lib/benchmark/registry.d.ts.map +1 -0
- package/dist/lib/benchmark/registry.js +212 -0
- package/dist/lib/benchmark/runner.d.ts +6 -0
- package/dist/lib/benchmark/runner.d.ts.map +1 -0
- package/dist/lib/benchmark/runner.js +150 -0
- package/dist/lib/benchmark/storage.d.ts +13 -0
- package/dist/lib/benchmark/storage.d.ts.map +1 -0
- package/dist/lib/benchmark/storage.js +100 -0
- package/dist/lib/benchmark/types.d.ts +104 -0
- package/dist/lib/benchmark/types.d.ts.map +1 -0
- package/dist/lib/benchmark/types.js +2 -0
- package/dist/lib/better-t-stack-cli.d.ts +50 -0
- package/dist/lib/better-t-stack-cli.d.ts.map +1 -0
- package/dist/lib/better-t-stack-cli.js +428 -0
- package/dist/lib/bootstrap/cli-bootstrap.d.ts +14 -0
- package/dist/lib/bootstrap/cli-bootstrap.d.ts.map +1 -0
- package/dist/lib/bootstrap/cli-bootstrap.js +322 -0
- package/dist/lib/bootstrap/index.d.ts +3 -0
- package/dist/lib/bootstrap/index.d.ts.map +1 -0
- package/dist/lib/bootstrap/index.js +18 -0
- package/dist/lib/bootstrap/medusa-bootstrap.d.ts +14 -0
- package/dist/lib/bootstrap/medusa-bootstrap.d.ts.map +1 -0
- package/dist/lib/bootstrap/medusa-bootstrap.js +215 -0
- package/dist/lib/config-validation.d.ts +215 -0
- package/dist/lib/config-validation.d.ts.map +1 -0
- package/dist/lib/config-validation.js +254 -0
- package/dist/lib/config.d.ts +55 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +351 -0
- package/dist/lib/context-builder.d.ts +66 -0
- package/dist/lib/context-builder.d.ts.map +1 -0
- package/dist/lib/context-builder.js +322 -0
- package/dist/lib/executors/claude-code-executor.d.ts +9 -0
- package/dist/lib/executors/claude-code-executor.d.ts.map +1 -0
- package/dist/lib/executors/claude-code-executor.js +69 -0
- package/dist/lib/executors/codex-executor.d.ts +9 -0
- package/dist/lib/executors/codex-executor.d.ts.map +1 -0
- package/dist/lib/executors/codex-executor.js +73 -0
- package/dist/lib/executors/executor-factory.d.ts +5 -0
- package/dist/lib/executors/executor-factory.d.ts.map +1 -0
- package/dist/lib/executors/executor-factory.js +27 -0
- package/dist/lib/executors/gemini-executor.d.ts +9 -0
- package/dist/lib/executors/gemini-executor.d.ts.map +1 -0
- package/dist/lib/executors/gemini-executor.js +67 -0
- package/dist/lib/executors/kilo-executor.d.ts +9 -0
- package/dist/lib/executors/kilo-executor.d.ts.map +1 -0
- package/dist/lib/executors/kilo-executor.js +69 -0
- package/dist/lib/executors/opencode-executor.d.ts +9 -0
- package/dist/lib/executors/opencode-executor.d.ts.map +1 -0
- package/dist/lib/executors/opencode-executor.js +67 -0
- package/dist/lib/git-utils.d.ts +88 -0
- package/dist/lib/git-utils.d.ts.map +1 -0
- package/dist/lib/git-utils.js +242 -0
- package/dist/lib/hooks.d.ts +73 -0
- package/dist/lib/hooks.d.ts.map +1 -0
- package/dist/lib/hooks.js +62 -0
- package/dist/lib/index.d.ts +100 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/index.js +143 -0
- package/dist/lib/logger.d.ts +20 -0
- package/dist/lib/logger.d.ts.map +1 -0
- package/dist/lib/logger.js +32 -0
- package/dist/lib/notifications.d.ts +7 -0
- package/dist/lib/notifications.d.ts.map +1 -0
- package/dist/lib/notifications.js +81 -0
- package/dist/lib/prompt-builder.d.ts +70 -0
- package/dist/lib/prompt-builder.d.ts.map +1 -0
- package/dist/lib/prompt-builder.js +344 -0
- package/dist/lib/prompt-registry.d.ts +22 -0
- package/dist/lib/prompt-registry.d.ts.map +1 -0
- package/dist/lib/prompt-registry.js +409 -0
- package/dist/lib/provider-defaults.json +32 -0
- package/dist/lib/storage/file-system.d.ts +57 -0
- package/dist/lib/storage/file-system.d.ts.map +1 -0
- package/dist/lib/storage/file-system.js +638 -0
- package/dist/lib/storage/storage-callbacks.d.ts +17 -0
- package/dist/lib/storage/storage-callbacks.d.ts.map +1 -0
- package/dist/lib/storage/storage-callbacks.js +94 -0
- package/dist/lib/storage/types.d.ts +43 -0
- package/dist/lib/storage/types.d.ts.map +1 -0
- package/dist/lib/storage/types.js +2 -0
- package/dist/lib/task-execution-core.d.ts +7 -0
- package/dist/lib/task-execution-core.d.ts.map +1 -0
- package/dist/lib/task-execution-core.js +381 -0
- package/dist/lib/task-execution.d.ts +7 -0
- package/dist/lib/task-execution.d.ts.map +1 -0
- package/dist/lib/task-execution.js +40 -0
- package/dist/lib/task-loop-execution.d.ts +7 -0
- package/dist/lib/task-loop-execution.d.ts.map +1 -0
- package/dist/lib/task-loop-execution.js +156 -0
- package/dist/lib/task-planning.d.ts +29 -0
- package/dist/lib/task-planning.d.ts.map +1 -0
- package/dist/lib/task-planning.js +103 -0
- package/dist/lib/task-review.d.ts +27 -0
- package/dist/lib/task-review.d.ts.map +1 -0
- package/dist/lib/task-review.js +103 -0
- package/dist/lib/validation.d.ts +26 -0
- package/dist/lib/validation.d.ts.map +1 -0
- package/dist/lib/validation.js +98 -0
- package/dist/prompts/documentation-detection.d.ts +2 -0
- package/dist/prompts/documentation-detection.d.ts.map +1 -0
- package/dist/prompts/documentation-detection.js +24 -0
- package/dist/prompts/documentation-recap.d.ts +3 -0
- package/dist/prompts/documentation-recap.d.ts.map +1 -0
- package/dist/prompts/documentation-recap.js +13 -0
- package/dist/prompts/index.d.ts +15 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +30 -0
- package/dist/prompts/prd-combination.d.ts +2 -0
- package/dist/prompts/prd-combination.d.ts.map +1 -0
- package/dist/prompts/prd-combination.js +35 -0
- package/dist/prompts/prd-generation.d.ts +2 -0
- package/dist/prompts/prd-generation.d.ts.map +1 -0
- package/dist/prompts/prd-generation.js +49 -0
- package/dist/prompts/prd-parsing.d.ts +3 -0
- package/dist/prompts/prd-parsing.d.ts.map +1 -0
- package/dist/prompts/prd-parsing.js +172 -0
- package/dist/prompts/prd-question-answer.d.ts +3 -0
- package/dist/prompts/prd-question-answer.d.ts.map +1 -0
- package/dist/prompts/prd-question-answer.js +27 -0
- package/dist/prompts/prd-question.d.ts +3 -0
- package/dist/prompts/prd-question.d.ts.map +1 -0
- package/dist/prompts/prd-question.js +40 -0
- package/dist/prompts/prd-rework.d.ts +3 -0
- package/dist/prompts/prd-rework.d.ts.map +1 -0
- package/dist/prompts/prd-rework.js +81 -0
- package/dist/prompts/prd-suggest-stack.d.ts +3 -0
- package/dist/prompts/prd-suggest-stack.d.ts.map +1 -0
- package/dist/prompts/prd-suggest-stack.js +99 -0
- package/dist/prompts/task-breakdown.d.ts +3 -0
- package/dist/prompts/task-breakdown.d.ts.map +1 -0
- package/dist/prompts/task-breakdown.js +151 -0
- package/dist/prompts/task-enhancement.d.ts +3 -0
- package/dist/prompts/task-enhancement.d.ts.map +1 -0
- package/dist/prompts/task-enhancement.js +140 -0
- package/dist/prompts/task-execution.d.ts +3 -0
- package/dist/prompts/task-execution.d.ts.map +1 -0
- package/dist/prompts/task-execution.js +24 -0
- package/dist/prompts/task-planning.d.ts +3 -0
- package/dist/prompts/task-planning.d.ts.map +1 -0
- package/dist/prompts/task-planning.js +66 -0
- package/dist/prompts/workflow-assistance.d.ts +32 -0
- package/dist/prompts/workflow-assistance.d.ts.map +1 -0
- package/dist/prompts/workflow-assistance.js +130 -0
- package/dist/prompts/workflow-prompts.d.ts +9 -0
- package/dist/prompts/workflow-prompts.d.ts.map +1 -0
- package/dist/prompts/workflow-prompts.js +93 -0
- package/dist/services/benchmark.d.ts +26 -0
- package/dist/services/benchmark.d.ts.map +1 -0
- package/dist/services/benchmark.js +343 -0
- package/dist/services/prd.d.ts +136 -0
- package/dist/services/prd.d.ts.map +1 -0
- package/dist/services/prd.js +550 -0
- package/dist/services/tasks.d.ts +388 -0
- package/dist/services/tasks.d.ts.map +1 -0
- package/dist/services/tasks.js +1150 -0
- package/dist/services/workflow-ai-assistant.d.ts +74 -0
- package/dist/services/workflow-ai-assistant.d.ts.map +1 -0
- package/dist/services/workflow-ai-assistant.js +175 -0
- package/dist/services/workflow-benchmark.d.ts +34 -0
- package/dist/services/workflow-benchmark.d.ts.map +1 -0
- package/dist/services/workflow-benchmark.js +318 -0
- package/dist/services/workflow.d.ts +107 -0
- package/dist/services/workflow.d.ts.map +1 -0
- package/dist/services/workflow.js +580 -0
- package/dist/test/hooks.test.d.ts +2 -0
- package/dist/test/hooks.test.d.ts.map +1 -0
- package/dist/test/hooks.test.js +67 -0
- package/dist/test/integration/callbacks.test.d.ts +2 -0
- package/dist/test/integration/callbacks.test.d.ts.map +1 -0
- package/dist/test/integration/callbacks.test.js +64 -0
- package/dist/test/lib/ai-service/task-operations.test.d.ts +2 -0
- package/dist/test/lib/ai-service/task-operations.test.d.ts.map +1 -0
- package/dist/test/lib/ai-service/task-operations.test.js +362 -0
- package/dist/test/lib/config.test.d.ts +2 -0
- package/dist/test/lib/config.test.d.ts.map +1 -0
- package/dist/test/lib/config.test.js +128 -0
- package/dist/test/lib/git-utils.test.d.ts +2 -0
- package/dist/test/lib/git-utils.test.d.ts.map +1 -0
- package/dist/test/lib/git-utils.test.js +168 -0
- package/dist/test/mocks/mock-ai-operations.d.ts +15 -0
- package/dist/test/mocks/mock-ai-operations.d.ts.map +1 -0
- package/dist/test/mocks/mock-ai-operations.js +107 -0
- package/dist/test/mocks/mock-context-builder.d.ts +10 -0
- package/dist/test/mocks/mock-context-builder.d.ts.map +1 -0
- package/dist/test/mocks/mock-context-builder.js +81 -0
- package/dist/test/mocks/mock-model-provider.d.ts +7 -0
- package/dist/test/mocks/mock-model-provider.d.ts.map +1 -0
- package/dist/test/mocks/mock-model-provider.js +21 -0
- package/dist/test/mocks/mock-service-factory.d.ts +11 -0
- package/dist/test/mocks/mock-service-factory.d.ts.map +1 -0
- package/dist/test/mocks/mock-service-factory.js +61 -0
- package/dist/test/mocks/mock-storage.d.ts +50 -0
- package/dist/test/mocks/mock-storage.d.ts.map +1 -0
- package/dist/test/mocks/mock-storage.js +145 -0
- package/dist/test/model-parsing.test.d.ts +2 -0
- package/dist/test/model-parsing.test.d.ts.map +1 -0
- package/dist/test/model-parsing.test.js +73 -0
- package/dist/test/services/task-service.test.d.ts +2 -0
- package/dist/test/services/task-service.test.d.ts.map +1 -0
- package/dist/test/services/task-service.test.js +459 -0
- package/dist/test/storage.test.d.ts +2 -0
- package/dist/test/storage.test.d.ts.map +1 -0
- package/dist/test/storage.test.js +207 -0
- package/dist/test/task-loop-git.test.d.ts +2 -0
- package/dist/test/task-loop-git.test.d.ts.map +1 -0
- package/dist/test/task-loop-git.test.js +95 -0
- package/dist/test/test-mock-setup.d.ts +26 -0
- package/dist/test/test-mock-setup.d.ts.map +1 -0
- package/dist/test/test-mock-setup.js +41 -0
- package/dist/test/test-setup.d.ts +9 -0
- package/dist/test/test-setup.d.ts.map +1 -0
- package/dist/test/test-setup.js +44 -0
- package/dist/test/test-utils.d.ts +22 -0
- package/dist/test/test-utils.d.ts.map +1 -0
- package/dist/test/test-utils.js +37 -0
- package/dist/test/utils/ai-operation-utility.test.d.ts +2 -0
- package/dist/test/utils/ai-operation-utility.test.d.ts.map +1 -0
- package/dist/test/utils/ai-operation-utility.test.js +290 -0
- package/dist/test/utils/error-handling.test.d.ts +2 -0
- package/dist/test/utils/error-handling.test.d.ts.map +1 -0
- package/dist/test/utils/error-handling.test.js +231 -0
- package/dist/test/utils/file-utils.test.d.ts +2 -0
- package/dist/test/utils/file-utils.test.d.ts.map +1 -0
- package/dist/test/utils/file-utils.test.js +76 -0
- package/dist/test/utils/id-generator.test.d.ts +2 -0
- package/dist/test/utils/id-generator.test.d.ts.map +1 -0
- package/dist/test/utils/id-generator.test.js +41 -0
- package/dist/test/utils/model-parser.test.d.ts +2 -0
- package/dist/test/utils/model-parser.test.d.ts.map +1 -0
- package/dist/test/utils/model-parser.test.js +65 -0
- package/dist/test/validation.test.d.ts +2 -0
- package/dist/test/validation.test.d.ts.map +1 -0
- package/dist/test/validation.test.js +22 -0
- package/dist/types/callbacks.d.ts +30 -0
- package/dist/types/callbacks.d.ts.map +1 -0
- package/dist/types/callbacks.js +2 -0
- package/dist/types/index.d.ts +435 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +30 -0
- package/dist/types/mcp.d.ts +3 -0
- package/dist/types/mcp.d.ts.map +1 -0
- package/dist/types/mcp.js +3 -0
- package/dist/types/options.d.ts +112 -0
- package/dist/types/options.d.ts.map +1 -0
- package/dist/types/options.js +2 -0
- package/dist/types/results.d.ts +200 -0
- package/dist/types/results.d.ts.map +1 -0
- package/dist/types/results.js +2 -0
- package/dist/types/workflow-options.d.ts +82 -0
- package/dist/types/workflow-options.d.ts.map +1 -0
- package/dist/types/workflow-options.js +2 -0
- package/dist/types/workflow-results.d.ts +82 -0
- package/dist/types/workflow-results.d.ts.map +1 -0
- package/dist/types/workflow-results.js +2 -0
- package/dist/utils/ai-config-builder.d.ts +14 -0
- package/dist/utils/ai-config-builder.d.ts.map +1 -0
- package/dist/utils/ai-config-builder.js +22 -0
- package/dist/utils/ai-operation-utility.d.ts +142 -0
- package/dist/utils/ai-operation-utility.d.ts.map +1 -0
- package/dist/utils/ai-operation-utility.js +303 -0
- package/dist/utils/ai-service-factory.d.ts +34 -0
- package/dist/utils/ai-service-factory.d.ts.map +1 -0
- package/dist/utils/ai-service-factory.js +99 -0
- package/dist/utils/error-utils.d.ts +70 -0
- package/dist/utils/error-utils.d.ts.map +1 -0
- package/dist/utils/error-utils.js +104 -0
- package/dist/utils/file-utils.d.ts +107 -0
- package/dist/utils/file-utils.d.ts.map +1 -0
- package/dist/utils/file-utils.js +171 -0
- package/dist/utils/id-generator.d.ts +92 -0
- package/dist/utils/id-generator.d.ts.map +1 -0
- package/dist/utils/id-generator.js +146 -0
- package/dist/utils/metadata-utils.d.ts +40 -0
- package/dist/utils/metadata-utils.d.ts.map +1 -0
- package/dist/utils/metadata-utils.js +43 -0
- package/dist/utils/model-executor-parser.d.ts +38 -0
- package/dist/utils/model-executor-parser.d.ts.map +1 -0
- package/dist/utils/model-executor-parser.js +69 -0
- package/dist/utils/model-parser.d.ts +6 -0
- package/dist/utils/model-parser.d.ts.map +1 -0
- package/dist/utils/model-parser.js +49 -0
- package/dist/utils/stack-formatter.d.ts +12 -0
- package/dist/utils/stack-formatter.d.ts.map +1 -0
- package/dist/utils/stack-formatter.js +36 -0
- package/dist/utils/storage-utils.d.ts +49 -0
- package/dist/utils/storage-utils.d.ts.map +1 -0
- package/dist/utils/storage-utils.js +80 -0
- package/dist/utils/streaming-utils.d.ts +38 -0
- package/dist/utils/streaming-utils.d.ts.map +1 -0
- package/dist/utils/streaming-utils.js +64 -0
- package/dist/utils/task-o-matic-error.d.ts +206 -0
- package/dist/utils/task-o-matic-error.d.ts.map +1 -0
- package/dist/utils/task-o-matic-error.js +304 -0
- package/package.json +40 -0
- package/src/index.ts +36 -0
- package/src/lib/ai-service/ai-operations.ts +310 -0
- package/src/lib/ai-service/base-operations.ts +139 -0
- package/src/lib/ai-service/documentation-operations.ts +438 -0
- package/src/lib/ai-service/filesystem-tools.ts +73 -0
- package/src/lib/ai-service/gemini-proxy.ts.bak +52 -0
- package/src/lib/ai-service/json-parser.ts +203 -0
- package/src/lib/ai-service/mcp-client.ts +54 -0
- package/src/lib/ai-service/model-provider.ts +192 -0
- package/src/lib/ai-service/prd-operations.ts +854 -0
- package/src/lib/ai-service/research-tools.ts +207 -0
- package/src/lib/ai-service/retry-handler.ts +89 -0
- package/src/lib/ai-service/task-operations.ts +342 -0
- package/src/lib/benchmark/registry.ts +307 -0
- package/src/lib/benchmark/runner.ts +190 -0
- package/src/lib/benchmark/storage.ts +140 -0
- package/src/lib/benchmark/types.ts +121 -0
- package/src/lib/better-t-stack-cli.ts +524 -0
- package/src/lib/bootstrap/cli-bootstrap.ts +397 -0
- package/src/lib/bootstrap/index.ts +2 -0
- package/src/lib/bootstrap/medusa-bootstrap.ts +261 -0
- package/src/lib/config-validation.ts +278 -0
- package/src/lib/config.ts +435 -0
- package/src/lib/context-builder.ts +383 -0
- package/src/lib/executors/claude-code-executor.ts +83 -0
- package/src/lib/executors/codex-executor.ts +85 -0
- package/src/lib/executors/executor-factory.ts +28 -0
- package/src/lib/executors/gemini-executor.ts +80 -0
- package/src/lib/executors/kilo-executor.ts +83 -0
- package/src/lib/executors/opencode-executor.ts +81 -0
- package/src/lib/git-utils.ts +334 -0
- package/src/lib/hooks.ts +121 -0
- package/src/lib/index.ts +166 -0
- package/src/lib/logger.ts +43 -0
- package/src/lib/notifications.ts +103 -0
- package/src/lib/prompt-builder.ts +471 -0
- package/src/lib/prompt-registry.ts +491 -0
- package/src/lib/provider-defaults.json +32 -0
- package/src/lib/storage/file-system.ts +864 -0
- package/src/lib/storage/storage-callbacks.ts +120 -0
- package/src/lib/storage/types.ts +58 -0
- package/src/lib/task-execution-core.ts +591 -0
- package/src/lib/task-execution.ts +59 -0
- package/src/lib/task-loop-execution.ts +214 -0
- package/src/lib/task-planning.ts +157 -0
- package/src/lib/task-review.ts +138 -0
- package/src/lib/validation.ts +140 -0
- package/src/prompts/documentation-detection.ts +21 -0
- package/src/prompts/documentation-recap.ts +11 -0
- package/src/prompts/index.ts +14 -0
- package/src/prompts/prd-combination.ts +32 -0
- package/src/prompts/prd-generation.ts +46 -0
- package/src/prompts/prd-parsing.ts +170 -0
- package/src/prompts/prd-question-answer.ts +25 -0
- package/src/prompts/prd-question.ts +38 -0
- package/src/prompts/prd-rework.ts +79 -0
- package/src/prompts/prd-suggest-stack.ts +97 -0
- package/src/prompts/task-breakdown.ts +149 -0
- package/src/prompts/task-enhancement.ts +138 -0
- package/src/prompts/task-execution.ts +22 -0
- package/src/prompts/task-planning.ts +64 -0
- package/src/prompts/workflow-assistance.ts +151 -0
- package/src/prompts/workflow-prompts.ts +97 -0
- package/src/services/benchmark.ts +433 -0
- package/src/services/prd.ts +845 -0
- package/src/services/tasks.ts +1515 -0
- package/src/services/workflow-ai-assistant.ts +298 -0
- package/src/services/workflow-benchmark.ts +339 -0
- package/src/services/workflow.ts +779 -0
- package/src/test/hooks.test.ts +77 -0
- package/src/test/integration/callbacks.test.ts +39 -0
- package/src/test/lib/ai-service/task-operations.test.ts +430 -0
- package/src/test/lib/config.test.ts +150 -0
- package/src/test/lib/git-utils.test.ts +198 -0
- package/src/test/mocks/mock-ai-operations.ts +205 -0
- package/src/test/mocks/mock-context-builder.ts +84 -0
- package/src/test/mocks/mock-model-provider.ts +21 -0
- package/src/test/mocks/mock-service-factory.ts +64 -0
- package/src/test/mocks/mock-storage.ts +204 -0
- package/src/test/model-parsing.test.ts +78 -0
- package/src/test/services/task-service.test.ts +551 -0
- package/src/test/storage.test.ts +206 -0
- package/src/test/task-loop-git.test.ts +142 -0
- package/src/test/test-mock-setup.ts +46 -0
- package/src/test/test-setup.ts +48 -0
- package/src/test/test-utils.ts +45 -0
- package/src/test/utils/ai-operation-utility.test.ts +306 -0
- package/src/test/utils/error-handling.test.ts +241 -0
- package/src/test/utils/file-utils.test.ts +80 -0
- package/src/test/utils/id-generator.test.ts +44 -0
- package/src/test/utils/model-parser.test.ts +67 -0
- package/src/test/validation.test.ts +19 -0
- package/src/types/callbacks.ts +14 -0
- package/src/types/index.ts +628 -0
- package/src/types/mcp.ts +5 -0
- package/src/types/options.ts +165 -0
- package/src/types/results.ts +216 -0
- package/src/types/workflow-options.ts +113 -0
- package/src/types/workflow-results.ts +87 -0
- package/src/utils/ai-config-builder.ts +33 -0
- package/src/utils/ai-operation-utility.ts +380 -0
- package/src/utils/ai-service-factory.ts +125 -0
- package/src/utils/error-utils.ts +124 -0
- package/src/utils/file-utils.ts +197 -0
- package/src/utils/id-generator.ts +168 -0
- package/src/utils/metadata-utils.ts +48 -0
- package/src/utils/model-executor-parser.ts +80 -0
- package/src/utils/model-parser.ts +58 -0
- package/src/utils/stack-formatter.ts +53 -0
- package/src/utils/storage-utils.ts +94 -0
- package/src/utils/streaming-utils.ts +91 -0
- package/src/utils/task-o-matic-error.ts +393 -0
- package/tsconfig.json +20 -0
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
import { join } from "path";
|
|
2
|
+
import { Task, TaskContext, BTSConfig, TaskDocumentation } from "../types";
|
|
3
|
+
import { TaskRepository } from "./storage/types";
|
|
4
|
+
import { configManager } from "./config";
|
|
5
|
+
import { readFileSync, existsSync, readdirSync, statSync } from "fs";
|
|
6
|
+
import { logger } from "./logger";
|
|
7
|
+
|
|
8
|
+
export interface FileStats {
|
|
9
|
+
mtime: number;
|
|
10
|
+
isDirectory: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface ContextCallbacks {
|
|
14
|
+
readFile: (path: string) => Promise<string | null>;
|
|
15
|
+
fileExists: (path: string) => Promise<boolean>;
|
|
16
|
+
listFiles: (dir: string) => Promise<string[]>;
|
|
17
|
+
stat: (path: string) => Promise<FileStats | null>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function createDefaultContextCallbacks(): ContextCallbacks {
|
|
21
|
+
return {
|
|
22
|
+
readFile: async (path: string) => {
|
|
23
|
+
if (existsSync(path)) {
|
|
24
|
+
return readFileSync(path, "utf-8");
|
|
25
|
+
}
|
|
26
|
+
return null;
|
|
27
|
+
},
|
|
28
|
+
fileExists: async (path: string) => {
|
|
29
|
+
return existsSync(path);
|
|
30
|
+
},
|
|
31
|
+
listFiles: async (dir: string) => {
|
|
32
|
+
if (existsSync(dir) && statSync(dir).isDirectory()) {
|
|
33
|
+
return readdirSync(dir);
|
|
34
|
+
}
|
|
35
|
+
return [];
|
|
36
|
+
},
|
|
37
|
+
stat: async (path: string) => {
|
|
38
|
+
if (existsSync(path)) {
|
|
39
|
+
const stats = statSync(path);
|
|
40
|
+
return {
|
|
41
|
+
mtime: stats.mtime.getTime(),
|
|
42
|
+
isDirectory: stats.isDirectory(),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return null;
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export class ContextBuilder {
|
|
51
|
+
private storage: TaskRepository;
|
|
52
|
+
private callbacks: ContextCallbacks;
|
|
53
|
+
private taskOMatic: string | null = null;
|
|
54
|
+
private initialized = false;
|
|
55
|
+
|
|
56
|
+
constructor(storage: TaskRepository, callbacks?: ContextCallbacks) {
|
|
57
|
+
this.storage = storage;
|
|
58
|
+
this.callbacks = callbacks || createDefaultContextCallbacks();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
private ensureInitialized(): void {
|
|
62
|
+
if (this.initialized) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
this.taskOMatic = configManager.getTaskOMaticDir();
|
|
67
|
+
this.initialized = true;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Build comprehensive context for AI operations
|
|
72
|
+
*/
|
|
73
|
+
async buildContext(taskId: string): Promise<TaskContext> {
|
|
74
|
+
this.ensureInitialized();
|
|
75
|
+
|
|
76
|
+
const task = await this.storage.getTask(taskId);
|
|
77
|
+
if (!task) {
|
|
78
|
+
throw new Error(`Task with ID ${taskId} not found`);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const stack = await this.getStackConfig();
|
|
82
|
+
const documentation = this.getTaskDocumentation(task);
|
|
83
|
+
const fullContent = await this.getTaskFullContent(task);
|
|
84
|
+
const prdContent = task.prdFile
|
|
85
|
+
? await this.getPRDContent(task.prdFile)
|
|
86
|
+
: await this.getRelevantPRDContent(task.title, task.description);
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
task: {
|
|
90
|
+
id: task.id,
|
|
91
|
+
title: task.title,
|
|
92
|
+
description: task.description ?? "",
|
|
93
|
+
fullContent,
|
|
94
|
+
},
|
|
95
|
+
stack,
|
|
96
|
+
documentation: documentation
|
|
97
|
+
? {
|
|
98
|
+
recap: documentation.recap,
|
|
99
|
+
files: documentation.files.map((file) => ({
|
|
100
|
+
path: file,
|
|
101
|
+
// Content loading is skipped as per original code comment
|
|
102
|
+
})),
|
|
103
|
+
}
|
|
104
|
+
: undefined,
|
|
105
|
+
existingContent: documentation?.recap,
|
|
106
|
+
prdContent,
|
|
107
|
+
existingResearch: documentation?.research || {},
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Build context for new tasks (without requiring existing task)
|
|
113
|
+
*/
|
|
114
|
+
async buildContextForNewTask(
|
|
115
|
+
title: string,
|
|
116
|
+
description?: string,
|
|
117
|
+
prdFile?: string
|
|
118
|
+
): Promise<TaskContext> {
|
|
119
|
+
this.ensureInitialized();
|
|
120
|
+
|
|
121
|
+
const stack = await this.getStackConfig();
|
|
122
|
+
const prdContent = prdFile
|
|
123
|
+
? await this.getPRDContent(prdFile)
|
|
124
|
+
: await this.getRelevantPRDContent(title, description);
|
|
125
|
+
|
|
126
|
+
return {
|
|
127
|
+
task: {
|
|
128
|
+
id: "new-task",
|
|
129
|
+
title,
|
|
130
|
+
description: description ?? "",
|
|
131
|
+
fullContent: undefined,
|
|
132
|
+
},
|
|
133
|
+
stack,
|
|
134
|
+
documentation: undefined, // New tasks don't have documentation yet
|
|
135
|
+
existingContent: undefined,
|
|
136
|
+
prdContent,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Get stack configuration from project (set by bootstrap)
|
|
142
|
+
*/
|
|
143
|
+
private async getStackConfig(): Promise<BTSConfig | undefined> {
|
|
144
|
+
if (!this.taskOMatic) {
|
|
145
|
+
return undefined;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Return sensible defaults for Better-T-Stack
|
|
149
|
+
const fallbackConfig: BTSConfig = {
|
|
150
|
+
projectName: "default",
|
|
151
|
+
frontend: "next",
|
|
152
|
+
backend: "convex",
|
|
153
|
+
database: "none", // Convex has its own database
|
|
154
|
+
auth: "better-auth",
|
|
155
|
+
runtime: "none",
|
|
156
|
+
api: "none",
|
|
157
|
+
payments: "none",
|
|
158
|
+
orm: "none", // Convex doesn't use ORM
|
|
159
|
+
dbSetup: "none",
|
|
160
|
+
packageManager: "npm",
|
|
161
|
+
git: true,
|
|
162
|
+
webDeploy: "none",
|
|
163
|
+
serverDeploy: "none",
|
|
164
|
+
install: true,
|
|
165
|
+
addons: ["turborepo"],
|
|
166
|
+
examples: [],
|
|
167
|
+
};
|
|
168
|
+
try {
|
|
169
|
+
const stackFile = join(this.taskOMatic, "stack.json");
|
|
170
|
+
const content = await this.callbacks.readFile(stackFile);
|
|
171
|
+
|
|
172
|
+
if (content) {
|
|
173
|
+
const config = JSON.parse(content) as BTSConfig;
|
|
174
|
+
config._source = "file"; // Track source
|
|
175
|
+
return config;
|
|
176
|
+
}
|
|
177
|
+
fallbackConfig._source = "fallback"; // Track source
|
|
178
|
+
return fallbackConfig;
|
|
179
|
+
} catch (error) {
|
|
180
|
+
logger.warn(
|
|
181
|
+
`Failed to load stack configuration, using defaults: ${error}`
|
|
182
|
+
);
|
|
183
|
+
fallbackConfig._source = "fallback"; // Track source
|
|
184
|
+
return fallbackConfig;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Get task documentation references
|
|
190
|
+
*/
|
|
191
|
+
private getTaskDocumentation(task: Task): TaskDocumentation | undefined {
|
|
192
|
+
return task.documentation;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Get full task content from MD file
|
|
197
|
+
*/
|
|
198
|
+
private async getTaskFullContent(task: Task): Promise<string | undefined> {
|
|
199
|
+
if (!task.contentFile || !this.taskOMatic) {
|
|
200
|
+
return undefined;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
try {
|
|
204
|
+
const contentPath = join(this.taskOMatic, task.contentFile);
|
|
205
|
+
return (await this.callbacks.readFile(contentPath)) || undefined;
|
|
206
|
+
} catch (error) {
|
|
207
|
+
logger.warn(
|
|
208
|
+
`Failed to read task content file ${task.contentFile}: ${error}`
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
return undefined;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Read documentation file content
|
|
216
|
+
*/
|
|
217
|
+
private async readDocumentationFile(filePath: string): Promise<string> {
|
|
218
|
+
if (!this.taskOMatic) {
|
|
219
|
+
return `# ContextBuilder Not Initialized\n\nFile: ${filePath}\n\nContextBuilder has not been properly initialized.`;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
try {
|
|
223
|
+
const fullPath = join(this.taskOMatic, filePath);
|
|
224
|
+
const content = await this.callbacks.readFile(fullPath);
|
|
225
|
+
if (content) {
|
|
226
|
+
return content;
|
|
227
|
+
}
|
|
228
|
+
return `# Documentation File Not Found\n\nFile: ${filePath}\n\nThis documentation file could not be found on disk.`;
|
|
229
|
+
} catch (error) {
|
|
230
|
+
return `# Error Reading Documentation\n\nFile: ${filePath}\n\nError: ${
|
|
231
|
+
error instanceof Error ? error.message : "Unknown error"
|
|
232
|
+
}`;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Check if documentation is fresh (less than 7 days old)
|
|
238
|
+
*/
|
|
239
|
+
isDocumentationFresh(documentation: TaskDocumentation): boolean {
|
|
240
|
+
const sevenDaysAgo = Date.now() - 7 * 24 * 60 * 60 * 1000;
|
|
241
|
+
return documentation.lastFetched > sevenDaysAgo;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Check if documentation is stale (more than 30 days old)
|
|
246
|
+
*/
|
|
247
|
+
isDocumentationStale(documentation: TaskDocumentation): boolean {
|
|
248
|
+
const thirtyDaysAgo = Date.now() - 30 * 24 * 60 * 60 * 1000;
|
|
249
|
+
return documentation.lastFetched < thirtyDaysAgo;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Get PRD content from file path
|
|
254
|
+
*/
|
|
255
|
+
private async getPRDContent(prdFile: string): Promise<string | undefined> {
|
|
256
|
+
if (!this.taskOMatic) {
|
|
257
|
+
return undefined;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
try {
|
|
261
|
+
// Handle relative paths from .task-o-matic directory
|
|
262
|
+
const fullPath = prdFile.startsWith("/")
|
|
263
|
+
? prdFile
|
|
264
|
+
: join(this.taskOMatic, prdFile);
|
|
265
|
+
|
|
266
|
+
return (await this.callbacks.readFile(fullPath)) || undefined;
|
|
267
|
+
} catch (error) {
|
|
268
|
+
logger.warn(`Failed to read PRD file ${prdFile}: ${error}`);
|
|
269
|
+
return undefined;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Get relevant PRD content based on task title/description
|
|
275
|
+
*/
|
|
276
|
+
private async getRelevantPRDContent(
|
|
277
|
+
taskTitle?: string,
|
|
278
|
+
taskDescription?: string
|
|
279
|
+
): Promise<string | undefined> {
|
|
280
|
+
if (!this.taskOMatic) return undefined;
|
|
281
|
+
|
|
282
|
+
// Look for PRD files in known locations
|
|
283
|
+
const prdPaths = [
|
|
284
|
+
join(this.taskOMatic, "prd"),
|
|
285
|
+
join(this.taskOMatic, "..", "docs"),
|
|
286
|
+
join(configManager.getWorkingDirectory(), ".task-o-matic", "prd"),
|
|
287
|
+
join(configManager.getWorkingDirectory(), "prd"),
|
|
288
|
+
join(configManager.getWorkingDirectory(), "docs"),
|
|
289
|
+
];
|
|
290
|
+
|
|
291
|
+
for (const prdPath of prdPaths) {
|
|
292
|
+
if (await this.callbacks.fileExists(prdPath)) {
|
|
293
|
+
try {
|
|
294
|
+
// Look for ANY text files in PRD directory
|
|
295
|
+
const files = await this.callbacks.listFiles(prdPath);
|
|
296
|
+
const prdFiles = files.filter(
|
|
297
|
+
(f) => f.endsWith(".md") || f.endsWith(".txt")
|
|
298
|
+
);
|
|
299
|
+
|
|
300
|
+
if (prdFiles.length > 0) {
|
|
301
|
+
// Get the MOST RECENT PRD file by modification time
|
|
302
|
+
const prdFilesWithStats = await Promise.all(
|
|
303
|
+
prdFiles.map(async (file) => {
|
|
304
|
+
const path = join(prdPath, file);
|
|
305
|
+
const stats = await this.callbacks.stat(path);
|
|
306
|
+
return {
|
|
307
|
+
file,
|
|
308
|
+
path,
|
|
309
|
+
mtime: stats ? stats.mtime : 0,
|
|
310
|
+
};
|
|
311
|
+
})
|
|
312
|
+
);
|
|
313
|
+
|
|
314
|
+
prdFilesWithStats.sort((a, b) => b.mtime - a.mtime); // Sort by newest first
|
|
315
|
+
const mostRecentPrd = prdFilesWithStats[0];
|
|
316
|
+
return (
|
|
317
|
+
(await this.callbacks.readFile(mostRecentPrd.path)) || undefined
|
|
318
|
+
);
|
|
319
|
+
}
|
|
320
|
+
} catch (error) {
|
|
321
|
+
logger.warn(`Failed to read PRD directory ${prdPath}: ${error}`);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
return undefined;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Format context for AI prompts
|
|
331
|
+
*/
|
|
332
|
+
formatContextForAI(context: TaskContext): string {
|
|
333
|
+
let formatted = `# Task Context\n\n`;
|
|
334
|
+
|
|
335
|
+
formatted += `## Task Information\n`;
|
|
336
|
+
formatted += `- **ID**: ${context.task.id}\n`;
|
|
337
|
+
formatted += `- **Title**: ${context.task.title}\n`;
|
|
338
|
+
formatted += `- **Description**: ${context.task.description}\n`;
|
|
339
|
+
|
|
340
|
+
if (context.task.fullContent) {
|
|
341
|
+
formatted += `- **Full Content**:\n${context.task.fullContent}\n\n`;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
if (context.prdContent) {
|
|
345
|
+
formatted += `## Product Requirements Document\n`;
|
|
346
|
+
formatted += `${context.prdContent}\n\n`;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
if (context.stack) {
|
|
350
|
+
formatted += `## Technology Stack\n`;
|
|
351
|
+
formatted += `- **Project**: ${context.stack.projectName}\n`;
|
|
352
|
+
formatted += `- **Frontend**: ${context.stack.frontend}\n`;
|
|
353
|
+
formatted += `- **Backend**: ${context.stack.backend}\n`;
|
|
354
|
+
if (context.stack.database !== "none") {
|
|
355
|
+
formatted += `- **Database**: ${context.stack.database}\n`;
|
|
356
|
+
}
|
|
357
|
+
if (context.stack.orm !== "none") {
|
|
358
|
+
formatted += `- **ORM**: ${context.stack.orm}\n`;
|
|
359
|
+
}
|
|
360
|
+
formatted += `- **Auth**: ${context.stack.auth}\n`;
|
|
361
|
+
if (context.stack.addons.length > 0) {
|
|
362
|
+
formatted += `- **Addons**: ${context.stack.addons.join(", ")}\n`;
|
|
363
|
+
}
|
|
364
|
+
formatted += `- **Package Manager**: ${context.stack.packageManager}\n`;
|
|
365
|
+
formatted += `\n`;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
if (context.documentation) {
|
|
369
|
+
formatted += `## Available Documentation\n`;
|
|
370
|
+
formatted += `**Recap**: ${context.documentation.recap}\n\n`;
|
|
371
|
+
|
|
372
|
+
if (context.documentation.files.length > 0) {
|
|
373
|
+
formatted += `### Documentation Files\n\n`;
|
|
374
|
+
context.documentation.files.forEach((file, index) => {
|
|
375
|
+
formatted += `#### ${index + 1}. ${file.path}\n`;
|
|
376
|
+
// formatted += `${file.content}\n\n`;
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
return formatted;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
|
|
3
|
+
import type { ExecutorConfig, ExternalExecutor } from "../../types";
|
|
4
|
+
import { logger } from "../logger";
|
|
5
|
+
|
|
6
|
+
export class ClaudeCodeExecutor implements ExternalExecutor {
|
|
7
|
+
name = "claude";
|
|
8
|
+
private config?: ExecutorConfig;
|
|
9
|
+
|
|
10
|
+
constructor(config?: ExecutorConfig) {
|
|
11
|
+
this.config = config;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
supportsSessionResumption(): boolean {
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async execute(
|
|
19
|
+
message: string,
|
|
20
|
+
dry: boolean = false,
|
|
21
|
+
config?: ExecutorConfig
|
|
22
|
+
): Promise<void> {
|
|
23
|
+
// Merge constructor config with execution config (execution takes precedence)
|
|
24
|
+
const finalConfig = { ...this.config, ...config };
|
|
25
|
+
|
|
26
|
+
// Build arguments array
|
|
27
|
+
const args: string[] = [];
|
|
28
|
+
|
|
29
|
+
// Add model if specified
|
|
30
|
+
if (finalConfig.model) {
|
|
31
|
+
args.push("--model", finalConfig.model);
|
|
32
|
+
logger.progress(`🤖 Using model: ${finalConfig.model}`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Add session resumption if specified
|
|
36
|
+
if (finalConfig.continueLastSession) {
|
|
37
|
+
args.push("-c");
|
|
38
|
+
logger.progress("🔄 Continuing last session");
|
|
39
|
+
} else if (finalConfig.sessionId) {
|
|
40
|
+
args.push("-r", finalConfig.sessionId);
|
|
41
|
+
logger.progress(`🔄 Resuming session: ${finalConfig.sessionId}`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Add --print for non-interactive mode (required for automation)
|
|
45
|
+
// args.push("-p");
|
|
46
|
+
|
|
47
|
+
// Auto-approve file edits for automation
|
|
48
|
+
args.push("--permission-mode", "acceptEdits");
|
|
49
|
+
|
|
50
|
+
// Add prompt as positional argument
|
|
51
|
+
args.push(message);
|
|
52
|
+
|
|
53
|
+
if (dry) {
|
|
54
|
+
logger.progress(`🔧 Using executor: ${this.name}`);
|
|
55
|
+
logger.progress(`claude ${args.join(" ")}`);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Launch claude and wait for it to complete
|
|
60
|
+
const child = spawn("claude", args, {
|
|
61
|
+
stdio: "inherit", // Give tool full terminal control
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Wait for completion (blocking)
|
|
65
|
+
await new Promise<void>((resolve, reject) => {
|
|
66
|
+
child.on("close", (code: number) => {
|
|
67
|
+
if (code === 0) {
|
|
68
|
+
logger.success("✅ Claude Code execution completed successfully");
|
|
69
|
+
resolve();
|
|
70
|
+
} else {
|
|
71
|
+
const error = new Error(`Claude Code exited with code ${code}`);
|
|
72
|
+
logger.error(`❌ ${error.message}`);
|
|
73
|
+
reject(error);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
child.on("error", (error: Error) => {
|
|
78
|
+
logger.error(`❌ Failed to launch Claude Code: ${error.message}`);
|
|
79
|
+
reject(error);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
|
|
3
|
+
import type { ExecutorConfig, ExternalExecutor } from "../../types";
|
|
4
|
+
import { logger } from "../logger";
|
|
5
|
+
|
|
6
|
+
export class CodexExecutor implements ExternalExecutor {
|
|
7
|
+
name = "codex";
|
|
8
|
+
private config?: ExecutorConfig;
|
|
9
|
+
|
|
10
|
+
constructor(config?: ExecutorConfig) {
|
|
11
|
+
this.config = config;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
supportsSessionResumption(): boolean {
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async execute(
|
|
19
|
+
message: string,
|
|
20
|
+
dry: boolean = false,
|
|
21
|
+
config?: ExecutorConfig
|
|
22
|
+
): Promise<void> {
|
|
23
|
+
// Merge constructor config with execution config (execution takes precedence)
|
|
24
|
+
const finalConfig = { ...this.config, ...config };
|
|
25
|
+
|
|
26
|
+
// Build arguments array - structure depends on session resumption
|
|
27
|
+
const args: string[] = [];
|
|
28
|
+
|
|
29
|
+
// Add model via config if specified (codex uses -c for config overrides)
|
|
30
|
+
if (finalConfig.model) {
|
|
31
|
+
args.push("-c", `model="${finalConfig.model}"`);
|
|
32
|
+
logger.progress(`🤖 Using model: ${finalConfig.model}`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Session resumption uses different subcommand
|
|
36
|
+
if (finalConfig.continueLastSession) {
|
|
37
|
+
// Use 'exec resume --last' subcommand
|
|
38
|
+
args.push("exec", "resume", "--last");
|
|
39
|
+
logger.progress("🔄 Continuing last session");
|
|
40
|
+
} else if (finalConfig.sessionId) {
|
|
41
|
+
// Use 'exec resume <session-id>' subcommand
|
|
42
|
+
args.push("exec", "resume", finalConfig.sessionId);
|
|
43
|
+
logger.progress(`🔄 Resuming session: ${finalConfig.sessionId}`);
|
|
44
|
+
} else {
|
|
45
|
+
// Normal execution
|
|
46
|
+
args.push("exec");
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Add full write access for automation
|
|
50
|
+
args.push("--sandbox", "workspace-write");
|
|
51
|
+
|
|
52
|
+
// Add prompt as positional argument
|
|
53
|
+
args.push(message);
|
|
54
|
+
|
|
55
|
+
if (dry) {
|
|
56
|
+
logger.progress(`🔧 Using executor: ${this.name}`);
|
|
57
|
+
logger.progress(`codex ${args.join(" ")}`);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Launch codex and wait for it to complete
|
|
62
|
+
const child = spawn("codex", args, {
|
|
63
|
+
stdio: "inherit", // Give tool full terminal control
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// Wait for completion (blocking)
|
|
67
|
+
await new Promise<void>((resolve, reject) => {
|
|
68
|
+
child.on("close", (code: number) => {
|
|
69
|
+
if (code === 0) {
|
|
70
|
+
logger.success("✅ Codex CLI execution completed successfully");
|
|
71
|
+
resolve();
|
|
72
|
+
} else {
|
|
73
|
+
const error = new Error(`Codex CLI exited with code ${code}`);
|
|
74
|
+
logger.error(`❌ ${error.message}`);
|
|
75
|
+
reject(error);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
child.on("error", (error: Error) => {
|
|
80
|
+
logger.error(`❌ Failed to launch Codex CLI: ${error.message}`);
|
|
81
|
+
reject(error);
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { ExternalExecutor, ExecutorTool, ExecutorConfig } from "../../types";
|
|
2
|
+
import { OpencodeExecutor } from "./opencode-executor";
|
|
3
|
+
import { ClaudeCodeExecutor } from "./claude-code-executor";
|
|
4
|
+
import { GeminiExecutor } from "./gemini-executor";
|
|
5
|
+
import { CodexExecutor } from "./codex-executor";
|
|
6
|
+
import { KiloExecutor } from "./kilo-executor";
|
|
7
|
+
|
|
8
|
+
export class ExecutorFactory {
|
|
9
|
+
static create(
|
|
10
|
+
tool: ExecutorTool = "opencode",
|
|
11
|
+
config?: ExecutorConfig
|
|
12
|
+
): ExternalExecutor {
|
|
13
|
+
switch (tool) {
|
|
14
|
+
case "opencode":
|
|
15
|
+
return new OpencodeExecutor(config);
|
|
16
|
+
case "claude":
|
|
17
|
+
return new ClaudeCodeExecutor(config);
|
|
18
|
+
case "gemini":
|
|
19
|
+
return new GeminiExecutor(config);
|
|
20
|
+
case "codex":
|
|
21
|
+
return new CodexExecutor(config);
|
|
22
|
+
case "kilo":
|
|
23
|
+
return new KiloExecutor(config);
|
|
24
|
+
default:
|
|
25
|
+
throw new Error(`Unknown executor tool: ${tool}`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
|
|
3
|
+
import type { ExecutorConfig, ExternalExecutor } from "../../types";
|
|
4
|
+
import { logger } from "../logger";
|
|
5
|
+
|
|
6
|
+
export class GeminiExecutor implements ExternalExecutor {
|
|
7
|
+
name = "gemini";
|
|
8
|
+
private config?: ExecutorConfig;
|
|
9
|
+
|
|
10
|
+
constructor(config?: ExecutorConfig) {
|
|
11
|
+
this.config = config;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
supportsSessionResumption(): boolean {
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async execute(
|
|
19
|
+
message: string,
|
|
20
|
+
dry: boolean = false,
|
|
21
|
+
config?: ExecutorConfig
|
|
22
|
+
): Promise<void> {
|
|
23
|
+
// Merge constructor config with execution config (execution takes precedence)
|
|
24
|
+
const finalConfig = { ...this.config, ...config };
|
|
25
|
+
|
|
26
|
+
// Build arguments array
|
|
27
|
+
const args: string[] = [];
|
|
28
|
+
|
|
29
|
+
// Add model if specified
|
|
30
|
+
if (finalConfig.model) {
|
|
31
|
+
args.push("-m", finalConfig.model);
|
|
32
|
+
logger.progress(`🤖 Using model: ${finalConfig.model}`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Add session resumption if specified
|
|
36
|
+
if (finalConfig.continueLastSession) {
|
|
37
|
+
args.push("-r", "latest");
|
|
38
|
+
logger.progress("🔄 Continuing last session");
|
|
39
|
+
} else if (finalConfig.sessionId) {
|
|
40
|
+
args.push("-r", finalConfig.sessionId);
|
|
41
|
+
logger.progress(`🔄 Resuming session: ${finalConfig.sessionId}`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Enable auto-approval of all tools (yolo mode) - required for file writes
|
|
45
|
+
args.push("--yolo");
|
|
46
|
+
|
|
47
|
+
// Add prompt as positional argument (the -p flag is deprecated)
|
|
48
|
+
args.push(message);
|
|
49
|
+
|
|
50
|
+
if (dry) {
|
|
51
|
+
logger.progress(`🔧 Using executor: ${this.name}`);
|
|
52
|
+
logger.progress(`gemini ${args.join(" ")}`);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Launch gemini and wait for it to complete
|
|
57
|
+
const child = spawn("gemini", args, {
|
|
58
|
+
stdio: "inherit", // Give tool full terminal control
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// Wait for completion (blocking)
|
|
62
|
+
await new Promise<void>((resolve, reject) => {
|
|
63
|
+
child.on("close", (code: number) => {
|
|
64
|
+
if (code === 0) {
|
|
65
|
+
logger.success("✅ Gemini CLI execution completed successfully");
|
|
66
|
+
resolve();
|
|
67
|
+
} else {
|
|
68
|
+
const error = new Error(`Gemini CLI exited with code ${code}`);
|
|
69
|
+
logger.error(`❌ ${error.message}`);
|
|
70
|
+
reject(error);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
child.on("error", (error: Error) => {
|
|
75
|
+
logger.error(`❌ Failed to launch Gemini CLI: ${error.message}`);
|
|
76
|
+
reject(error);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|