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,197 @@
|
|
|
1
|
+
import { existsSync, writeFileSync, mkdirSync, readFileSync } from "fs";
|
|
2
|
+
import { access, constants } from "fs/promises";
|
|
3
|
+
import { join, dirname } from "path";
|
|
4
|
+
import {
|
|
5
|
+
createStandardError,
|
|
6
|
+
TaskOMaticErrorCodes,
|
|
7
|
+
} from "./task-o-matic-error";
|
|
8
|
+
import { configManager } from "../lib/config";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Validates that a file exists at the given path (synchronous).
|
|
12
|
+
* Throws an error with a custom message if the file doesn't exist.
|
|
13
|
+
*
|
|
14
|
+
* @param filePath - Path to the file to validate
|
|
15
|
+
* @param customMessage - Optional custom error message
|
|
16
|
+
* @throws TaskOMaticError if file doesn't exist
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* validateFileExists("./config.json", "Configuration file not found");
|
|
21
|
+
* // Throws: TaskOMaticError with code INVALID_INPUT if file doesn't exist
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export function validateFileExists(
|
|
25
|
+
filePath: string,
|
|
26
|
+
customMessage?: string
|
|
27
|
+
): void {
|
|
28
|
+
if (!existsSync(filePath)) {
|
|
29
|
+
throw createStandardError(
|
|
30
|
+
TaskOMaticErrorCodes.INVALID_INPUT,
|
|
31
|
+
customMessage || `File not found: ${filePath}`,
|
|
32
|
+
{
|
|
33
|
+
suggestions: ["Verify the file path is correct."],
|
|
34
|
+
}
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Validates that a file exists at the given path (asynchronous).
|
|
41
|
+
* Throws an error with a custom message if the file doesn't exist.
|
|
42
|
+
*
|
|
43
|
+
* @param filePath - Path to the file to validate
|
|
44
|
+
* @param customMessage - Optional custom error message
|
|
45
|
+
* @throws TaskOMaticError if file doesn't exist
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```typescript
|
|
49
|
+
* await validateFileExistsAsync("./data.json");
|
|
50
|
+
* // Throws: TaskOMaticError with code INVALID_INPUT if file doesn't exist
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export async function validateFileExistsAsync(
|
|
54
|
+
filePath: string,
|
|
55
|
+
customMessage?: string
|
|
56
|
+
): Promise<void> {
|
|
57
|
+
try {
|
|
58
|
+
await access(filePath, constants.F_OK);
|
|
59
|
+
} catch {
|
|
60
|
+
throw createStandardError(
|
|
61
|
+
TaskOMaticErrorCodes.INVALID_INPUT,
|
|
62
|
+
customMessage || `File not found: ${filePath}`,
|
|
63
|
+
{
|
|
64
|
+
suggestions: ["Verify the file path is correct."],
|
|
65
|
+
}
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Checks if a file exists at the given path (synchronous).
|
|
72
|
+
* Returns true if file exists, false otherwise.
|
|
73
|
+
* Unlike validateFileExists, this doesn't throw an error.
|
|
74
|
+
*
|
|
75
|
+
* @param filePath - Path to check
|
|
76
|
+
* @returns true if file exists, false otherwise
|
|
77
|
+
*/
|
|
78
|
+
export function fileExists(filePath: string): boolean {
|
|
79
|
+
return existsSync(filePath);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Checks if a file exists at the given path (asynchronous).
|
|
84
|
+
* Returns true if file exists, false otherwise.
|
|
85
|
+
* Unlike validateFileExistsAsync, this doesn't throw an error.
|
|
86
|
+
*
|
|
87
|
+
* @param filePath - Path to check
|
|
88
|
+
* @returns Promise resolving to true if file exists, false otherwise
|
|
89
|
+
*/
|
|
90
|
+
export async function fileExistsAsync(filePath: string): Promise<boolean> {
|
|
91
|
+
try {
|
|
92
|
+
await access(filePath, constants.F_OK);
|
|
93
|
+
return true;
|
|
94
|
+
} catch {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Saves a file to the PRD directory, ensuring the directory exists.
|
|
101
|
+
* If no output directory is specified, uses `.task-o-matic/prd/` by default.
|
|
102
|
+
*
|
|
103
|
+
* @param content - Content to write to the file
|
|
104
|
+
* @param filename - Filename (defaults to "prd.md")
|
|
105
|
+
* @param outputDir - Optional output directory override
|
|
106
|
+
* @returns Full path to the saved file
|
|
107
|
+
* @throws TaskOMaticError if file saving fails
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```typescript
|
|
111
|
+
* // Save to default location (.task-o-matic/prd/prd.md)
|
|
112
|
+
* const path = savePRDFile("# My PRD\n...");
|
|
113
|
+
*
|
|
114
|
+
* // Save with custom filename
|
|
115
|
+
* const path = savePRDFile("# My PRD\n...", "custom-prd.md");
|
|
116
|
+
*
|
|
117
|
+
* // Save to custom directory
|
|
118
|
+
* const path = savePRDFile("# My PRD\n...", "prd.md", "./docs");
|
|
119
|
+
* ```
|
|
120
|
+
*/
|
|
121
|
+
export function savePRDFile(
|
|
122
|
+
content: string,
|
|
123
|
+
filename: string = "prd.md",
|
|
124
|
+
outputDir?: string
|
|
125
|
+
): string {
|
|
126
|
+
const taskOMaticDir = configManager.getTaskOMaticDir();
|
|
127
|
+
const prdDir = outputDir || join(taskOMaticDir, "prd");
|
|
128
|
+
|
|
129
|
+
if (!existsSync(prdDir)) {
|
|
130
|
+
mkdirSync(prdDir, { recursive: true });
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const path = join(prdDir, filename);
|
|
134
|
+
writeFileSync(path, content);
|
|
135
|
+
|
|
136
|
+
return path;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Saves a stack configuration to a JSON file.
|
|
141
|
+
* If no output path is specified, saves to `.task-o-matic/stack.json`.
|
|
142
|
+
*
|
|
143
|
+
* @param config - BTSConfig object to save
|
|
144
|
+
* @param outputPath - Optional custom output path
|
|
145
|
+
* @returns Full path to the saved file
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* ```typescript
|
|
149
|
+
* // Save to default location
|
|
150
|
+
* const path = saveStackFile(config);
|
|
151
|
+
*
|
|
152
|
+
* // Save to custom location
|
|
153
|
+
* const path = saveStackFile(config, "./my-project/stack.json");
|
|
154
|
+
* ```
|
|
155
|
+
*/
|
|
156
|
+
export function saveStackFile(config: object, outputPath?: string): string {
|
|
157
|
+
const taskOMaticDir = configManager.getTaskOMaticDir();
|
|
158
|
+
const stackPath = outputPath || join(taskOMaticDir, "stack.json");
|
|
159
|
+
|
|
160
|
+
const dir = dirname(stackPath);
|
|
161
|
+
if (!existsSync(dir)) {
|
|
162
|
+
mkdirSync(dir, { recursive: true });
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
writeFileSync(stackPath, JSON.stringify(config, null, 2));
|
|
166
|
+
return stackPath;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Loads a stack configuration from a JSON file.
|
|
171
|
+
* If no input path is specified, loads from `.task-o-matic/stack.json`.
|
|
172
|
+
*
|
|
173
|
+
* @param inputPath - Optional custom input path
|
|
174
|
+
* @returns The parsed BTSConfig object, or null if file doesn't exist
|
|
175
|
+
*
|
|
176
|
+
* @example
|
|
177
|
+
* ```typescript
|
|
178
|
+
* // Load from default location
|
|
179
|
+
* const config = loadStackFile();
|
|
180
|
+
*
|
|
181
|
+
* // Load from custom location
|
|
182
|
+
* const config = loadStackFile("./my-project/stack.json");
|
|
183
|
+
* ```
|
|
184
|
+
*/
|
|
185
|
+
export function loadStackFile<T = Record<string, unknown>>(
|
|
186
|
+
inputPath?: string
|
|
187
|
+
): T | null {
|
|
188
|
+
const taskOMaticDir = configManager.getTaskOMaticDir();
|
|
189
|
+
const stackPath = inputPath || join(taskOMaticDir, "stack.json");
|
|
190
|
+
|
|
191
|
+
if (!existsSync(stackPath)) {
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const content = readFileSync(stackPath, "utf-8");
|
|
196
|
+
return JSON.parse(content) as T;
|
|
197
|
+
}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { randomBytes } from "crypto";
|
|
2
|
+
import {
|
|
3
|
+
createStandardError,
|
|
4
|
+
TaskOMaticErrorCodes,
|
|
5
|
+
} from "./task-o-matic-error";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Generates unique task IDs with consistent format.
|
|
9
|
+
* Uses timestamp + random hex for uniqueness.
|
|
10
|
+
*/
|
|
11
|
+
export class TaskIDGenerator {
|
|
12
|
+
/**
|
|
13
|
+
* Generates a unique task ID with format: prefix-timestamp-random
|
|
14
|
+
*
|
|
15
|
+
* @param prefix - Prefix for the ID (default: "task")
|
|
16
|
+
* @returns Unique task ID
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* const id = TaskIDGenerator.generate();
|
|
21
|
+
* // Returns: "task-1733750400000-a1b2c3d4"
|
|
22
|
+
*
|
|
23
|
+
* const customId = TaskIDGenerator.generate("subtask");
|
|
24
|
+
* // Returns: "subtask-1733750400000-e5f6g7h8"
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
static generate(prefix: string = "task"): string {
|
|
28
|
+
const timestamp = Date.now();
|
|
29
|
+
const random = randomBytes(4).toString("hex");
|
|
30
|
+
return `${prefix}-${timestamp}-${random}`;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Validates a task ID format.
|
|
35
|
+
* Accepts three formats:
|
|
36
|
+
* - Timestamped: "task-1234567890-abcd1234"
|
|
37
|
+
* - Hierarchical: "1.2.3"
|
|
38
|
+
* - Numeric: "123"
|
|
39
|
+
*
|
|
40
|
+
* @param id - Task ID to validate
|
|
41
|
+
* @returns true if ID format is valid
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```typescript
|
|
45
|
+
* TaskIDGenerator.validate("task-1234-abcd"); // true
|
|
46
|
+
* TaskIDGenerator.validate("1.2.3"); // true
|
|
47
|
+
* TaskIDGenerator.validate("123"); // true
|
|
48
|
+
* TaskIDGenerator.validate("invalid!"); // false
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
static validate(id: string): boolean {
|
|
52
|
+
if (!id || typeof id !== "string") {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Format 1: Timestamped (task-timestamp-random)
|
|
57
|
+
const timestampedPattern = /^[a-z]+-\d+-[a-f0-9]{8}$/;
|
|
58
|
+
if (timestampedPattern.test(id)) {
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Format 2: Hierarchical (1.2.3)
|
|
63
|
+
const hierarchicalPattern = /^[\d.]+$/;
|
|
64
|
+
if (hierarchicalPattern.test(id)) {
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Format 3: Numeric (123)
|
|
69
|
+
const numericPattern = /^\d+$/;
|
|
70
|
+
if (numericPattern.test(id)) {
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Checks if an ID is unique within a set of existing IDs.
|
|
79
|
+
*
|
|
80
|
+
* @param id - ID to check
|
|
81
|
+
* @param existingIds - Set of existing IDs
|
|
82
|
+
* @returns true if ID is unique
|
|
83
|
+
*/
|
|
84
|
+
static isUnique(id: string, existingIds: Set<string>): boolean {
|
|
85
|
+
return !existingIds.has(id);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Generates a unique ID that doesn't exist in the provided set.
|
|
90
|
+
* Retries up to maxAttempts times if collisions occur.
|
|
91
|
+
*
|
|
92
|
+
* @param existingIds - Set of existing IDs to avoid
|
|
93
|
+
* @param prefix - Prefix for the ID
|
|
94
|
+
* @param maxAttempts - Maximum number of generation attempts
|
|
95
|
+
* @returns Unique task ID
|
|
96
|
+
* @throws TaskOMaticError if unable to generate unique ID after maxAttempts
|
|
97
|
+
*/
|
|
98
|
+
static generateUnique(
|
|
99
|
+
existingIds: Set<string>,
|
|
100
|
+
prefix: string = "task",
|
|
101
|
+
maxAttempts: number = 10
|
|
102
|
+
): string {
|
|
103
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
104
|
+
const id = this.generate(prefix);
|
|
105
|
+
if (this.isUnique(id, existingIds)) {
|
|
106
|
+
return id;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
throw createStandardError(
|
|
111
|
+
TaskOMaticErrorCodes.UNEXPECTED_ERROR,
|
|
112
|
+
`Failed to generate unique ID after ${maxAttempts} attempts`,
|
|
113
|
+
{
|
|
114
|
+
context: `Could not find a unique ID with prefix '${prefix}' after ${maxAttempts} attempts.`,
|
|
115
|
+
suggestions: [
|
|
116
|
+
"Increase maxAttempts if you have a very large number of tasks.",
|
|
117
|
+
],
|
|
118
|
+
}
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Generates a hierarchical child ID from a parent ID.
|
|
124
|
+
* If parent is "1.2", generates "1.2.1", "1.2.2", etc.
|
|
125
|
+
*
|
|
126
|
+
* @param parentId - Parent task ID
|
|
127
|
+
* @param childIndex - Index of the child (1-based)
|
|
128
|
+
* @returns Child task ID
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* ```typescript
|
|
132
|
+
* TaskIDGenerator.generateChildId("1", 1); // "1.1"
|
|
133
|
+
* TaskIDGenerator.generateChildId("1.2", 3); // "1.2.3"
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
136
|
+
static generateChildId(parentId: string, childIndex: number): string {
|
|
137
|
+
return `${parentId}.${childIndex}`;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Parses a hierarchical ID to extract parent ID and child index.
|
|
142
|
+
*
|
|
143
|
+
* @param id - Hierarchical task ID
|
|
144
|
+
* @returns Object with parentId and childIndex, or null if not hierarchical
|
|
145
|
+
*
|
|
146
|
+
* @example
|
|
147
|
+
* ```typescript
|
|
148
|
+
* TaskIDGenerator.parseHierarchicalId("1.2.3");
|
|
149
|
+
* // Returns: { parentId: "1.2", childIndex: 3 }
|
|
150
|
+
* ```
|
|
151
|
+
*/
|
|
152
|
+
static parseHierarchicalId(
|
|
153
|
+
id: string
|
|
154
|
+
): { parentId: string; childIndex: number } | null {
|
|
155
|
+
const parts = id.split(".");
|
|
156
|
+
if (parts.length < 2) {
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const childIndex = parseInt(parts[parts.length - 1], 10);
|
|
161
|
+
if (isNaN(childIndex)) {
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const parentId = parts.slice(0, -1).join(".");
|
|
166
|
+
return { parentId, childIndex };
|
|
167
|
+
}
|
|
168
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { AIConfig } from "../types";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Creates base AI metadata object with common fields.
|
|
5
|
+
* Caller can extend with operation-specific fields.
|
|
6
|
+
*
|
|
7
|
+
* @param taskId - The ID of the task
|
|
8
|
+
* @param aiConfig - AI configuration used for the operation
|
|
9
|
+
* @param promptOverride - Optional custom prompt override
|
|
10
|
+
* @param defaultPrompt - Default prompt if no override provided
|
|
11
|
+
* @param confidence - Confidence score (0-1) for the AI operation
|
|
12
|
+
* @returns Base metadata object
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* const baseMetadata = createBaseAIMetadata(
|
|
17
|
+
* "task-123",
|
|
18
|
+
* { provider: "anthropic", model: "claude-sonnet-4.5" },
|
|
19
|
+
* undefined,
|
|
20
|
+
* "Split task into subtasks",
|
|
21
|
+
* 0.9
|
|
22
|
+
* );
|
|
23
|
+
*
|
|
24
|
+
* // Extend with operation-specific fields
|
|
25
|
+
* const subtaskMetadata = {
|
|
26
|
+
* ...baseMetadata,
|
|
27
|
+
* parentTaskId: "parent-123",
|
|
28
|
+
* subtaskIndex: 1
|
|
29
|
+
* };
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export function createBaseAIMetadata(
|
|
33
|
+
taskId: string,
|
|
34
|
+
aiConfig: Partial<AIConfig>,
|
|
35
|
+
promptOverride?: string,
|
|
36
|
+
defaultPrompt: string = "AI-generated task",
|
|
37
|
+
confidence: number = 0.9
|
|
38
|
+
) {
|
|
39
|
+
return {
|
|
40
|
+
taskId,
|
|
41
|
+
aiGenerated: true,
|
|
42
|
+
aiPrompt: promptOverride || defaultPrompt,
|
|
43
|
+
confidence,
|
|
44
|
+
aiProvider: aiConfig.provider,
|
|
45
|
+
aiModel: aiConfig.model,
|
|
46
|
+
generatedAt: Date.now(),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { ExecutorTool, ModelAttemptConfig } from "../types";
|
|
2
|
+
import {
|
|
3
|
+
createStandardError,
|
|
4
|
+
TaskOMaticErrorCodes,
|
|
5
|
+
} from "./task-o-matic-error";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Valid executor tools
|
|
9
|
+
*/
|
|
10
|
+
export const VALID_EXECUTORS: ExecutorTool[] = [
|
|
11
|
+
"opencode",
|
|
12
|
+
"claude",
|
|
13
|
+
"gemini",
|
|
14
|
+
"codex",
|
|
15
|
+
"kilo",
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Parse --try-models option into ModelAttemptConfig array
|
|
20
|
+
* Supports formats:
|
|
21
|
+
* - "model1,model2,model3" - just models (uses default executor)
|
|
22
|
+
* - "opencode:gpt-4o,claude:sonnet-4" - executor:model format
|
|
23
|
+
* - Mixed: "gpt-4o,claude:sonnet-4,gemini:gemini-2.0"
|
|
24
|
+
*
|
|
25
|
+
* @param value - Comma-separated model/executor specifications
|
|
26
|
+
* @returns Array of model attempt configurations
|
|
27
|
+
* @throws TaskOMaticError if an invalid executor is specified
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* parseTryModels("gpt-4o-mini,gpt-4o"); // [{ model: "gpt-4o-mini" }, { model: "gpt-4o" }]
|
|
32
|
+
* parseTryModels("opencode:gpt-4o,claude:sonnet-4"); // [{ executor: "opencode", model: "gpt-4o" }, ...]
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export function parseTryModels(value: string): ModelAttemptConfig[] {
|
|
36
|
+
return value.split(",").map((item) => {
|
|
37
|
+
const trimmed = item.trim();
|
|
38
|
+
|
|
39
|
+
// Check if it includes executor specification (executor:model format)
|
|
40
|
+
if (trimmed.includes(":")) {
|
|
41
|
+
const [executor, model] = trimmed.split(":");
|
|
42
|
+
|
|
43
|
+
if (!VALID_EXECUTORS.includes(executor as ExecutorTool)) {
|
|
44
|
+
throw createStandardError(
|
|
45
|
+
TaskOMaticErrorCodes.INVALID_INPUT,
|
|
46
|
+
`Invalid executor "${executor}" in --try-models. Must be one of: ${VALID_EXECUTORS.join(
|
|
47
|
+
", "
|
|
48
|
+
)}`
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
executor: executor as ExecutorTool,
|
|
54
|
+
model: model.trim(),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Just a model name - use default executor
|
|
59
|
+
return {
|
|
60
|
+
model: trimmed,
|
|
61
|
+
};
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Validate that an executor name is valid
|
|
67
|
+
*
|
|
68
|
+
* @param executor - Executor name to validate
|
|
69
|
+
* @returns Type guard confirming executor is valid
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```typescript
|
|
73
|
+
* if (validateExecutor(options.tool)) {
|
|
74
|
+
* // TypeScript knows options.tool is ExecutorTool
|
|
75
|
+
* }
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
export function validateExecutor(executor: string): executor is ExecutorTool {
|
|
79
|
+
return VALID_EXECUTORS.includes(executor as ExecutorTool);
|
|
80
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { isValidAIProvider } from "../lib/validation";
|
|
2
|
+
|
|
3
|
+
// Helper to parse model string ([provider:]model[;reasoning[=budget]])
|
|
4
|
+
export function parseModelString(modelStr: string): {
|
|
5
|
+
provider?: string;
|
|
6
|
+
model: string;
|
|
7
|
+
reasoning?: string;
|
|
8
|
+
} {
|
|
9
|
+
let processingStr = modelStr;
|
|
10
|
+
let reasoning: string | undefined;
|
|
11
|
+
|
|
12
|
+
// 1. Extract reasoning
|
|
13
|
+
// Format: ;reasoning or ;reasoning=1000
|
|
14
|
+
const reasoningMatch = processingStr.match(/;reasoning(?:=(\d+))?$/);
|
|
15
|
+
if (reasoningMatch) {
|
|
16
|
+
// If specific budget provided (group 1), use it.
|
|
17
|
+
// Otherwise default to "2000" as requested.
|
|
18
|
+
reasoning = reasoningMatch[1] ? reasoningMatch[1] : "2000";
|
|
19
|
+
|
|
20
|
+
// Remove the reasoning suffix from the string
|
|
21
|
+
processingStr = processingStr.substring(0, reasoningMatch.index);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// 2. Extract provider and model
|
|
25
|
+
// We look for the first colon.
|
|
26
|
+
const firstColonIndex = processingStr.indexOf(":");
|
|
27
|
+
|
|
28
|
+
if (firstColonIndex === -1) {
|
|
29
|
+
// No colon -> It's just a model name (provider inferred from env/defaults later)
|
|
30
|
+
return {
|
|
31
|
+
provider: undefined,
|
|
32
|
+
model: processingStr,
|
|
33
|
+
reasoning,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Has colon. Check if the part before is a valid provider.
|
|
38
|
+
const potentialProvider = processingStr.substring(0, firstColonIndex);
|
|
39
|
+
const potentialModel = processingStr.substring(firstColonIndex + 1);
|
|
40
|
+
|
|
41
|
+
if (isValidAIProvider(potentialProvider)) {
|
|
42
|
+
// It is a known provider
|
|
43
|
+
return {
|
|
44
|
+
provider: potentialProvider,
|
|
45
|
+
model: potentialModel,
|
|
46
|
+
reasoning,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Not a known provider. Treat the whole thing as the model name.
|
|
51
|
+
// This handles cases like "google/gemini...:free" where "google/gemini..." isn't a provider key.
|
|
52
|
+
// Or just "model:with:colons".
|
|
53
|
+
return {
|
|
54
|
+
provider: undefined,
|
|
55
|
+
model: processingStr,
|
|
56
|
+
reasoning,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { BTSFrontend } from "../types/index.js";
|
|
2
|
+
|
|
3
|
+
export interface StackInfo {
|
|
4
|
+
frontend: BTSFrontend | BTSFrontend[];
|
|
5
|
+
backend: string;
|
|
6
|
+
database: string;
|
|
7
|
+
orm: string;
|
|
8
|
+
auth: string;
|
|
9
|
+
addons: string[];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function formatStackInfo(stack: StackInfo | null | undefined): string {
|
|
13
|
+
if (!stack) {
|
|
14
|
+
return "Not detected";
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const frontendStr = Array.isArray(stack.frontend)
|
|
18
|
+
? stack.frontend.join(", ")
|
|
19
|
+
: stack.frontend;
|
|
20
|
+
|
|
21
|
+
const parts = [
|
|
22
|
+
`Frontend: ${frontendStr}`,
|
|
23
|
+
`Backend: ${stack.backend}`
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
if (stack.database !== 'none') {
|
|
27
|
+
parts.push(`Database: ${stack.database}`);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (stack.orm !== 'none') {
|
|
31
|
+
parts.push(`ORM: ${stack.orm}`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
parts.push(`Auth: ${stack.auth}`);
|
|
35
|
+
|
|
36
|
+
if (stack.addons.length > 0) {
|
|
37
|
+
parts.push(`Addons: ${stack.addons.join(", ")}`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return parts.join(", ");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function formatStackForContext(stack: StackInfo | null | undefined): string {
|
|
44
|
+
if (!stack) {
|
|
45
|
+
return "";
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const frontendStr = Array.isArray(stack.frontend)
|
|
49
|
+
? stack.frontend.join(" + ")
|
|
50
|
+
: stack.frontend;
|
|
51
|
+
|
|
52
|
+
return `Technology Stack: ${frontendStr} + ${stack.backend} + ${stack.database}`;
|
|
53
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { Task } from "../types/index.js";
|
|
2
|
+
import {
|
|
3
|
+
createStandardError,
|
|
4
|
+
formatTaskNotFoundError,
|
|
5
|
+
TaskOMaticErrorCodes,
|
|
6
|
+
} from "./task-o-matic-error";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Ensures a task is not null, throwing an error if it is.
|
|
10
|
+
* Useful for enforcing null checks after storage operations.
|
|
11
|
+
*
|
|
12
|
+
* @param task - Task that may be null
|
|
13
|
+
* @param taskId - ID of the task for error message
|
|
14
|
+
* @returns The task if not null
|
|
15
|
+
* @throws TaskOMaticError if task is null
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* const task = await storage.getTask(taskId);
|
|
20
|
+
* const validTask = requireTask(task, taskId);
|
|
21
|
+
* console.log(validTask.title); // Safe - never null
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export function requireTask(task: Task | null, taskId: string): Task {
|
|
25
|
+
if (!task) {
|
|
26
|
+
throw formatTaskNotFoundError(taskId);
|
|
27
|
+
}
|
|
28
|
+
return task;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Ensures multiple tasks are not null, throwing an error if any is null.
|
|
33
|
+
*
|
|
34
|
+
* @param tasks - Array of tasks that may contain nulls
|
|
35
|
+
* @param context - Context for error message (e.g., "subtasks", "dependencies")
|
|
36
|
+
* @returns Array of tasks with nulls filtered out
|
|
37
|
+
* @throws TaskOMaticError if any task is null
|
|
38
|
+
*/
|
|
39
|
+
export function requireTasks(
|
|
40
|
+
tasks: (Task | null)[],
|
|
41
|
+
context: string = "tasks"
|
|
42
|
+
): Task[] {
|
|
43
|
+
const validTasks: Task[] = [];
|
|
44
|
+
const missingIds: string[] = [];
|
|
45
|
+
|
|
46
|
+
tasks.forEach((task, index) => {
|
|
47
|
+
if (!task) {
|
|
48
|
+
missingIds.push(`index ${index}`);
|
|
49
|
+
} else {
|
|
50
|
+
validTasks.push(task);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
if (missingIds.length > 0) {
|
|
55
|
+
throw createStandardError(
|
|
56
|
+
TaskOMaticErrorCodes.STORAGE_INTEGRITY_ERROR,
|
|
57
|
+
`Missing ${context}: ${missingIds.join(", ")}`
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return validTasks;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Filters out null tasks from an array, with type narrowing.
|
|
66
|
+
*
|
|
67
|
+
* @param tasks - Array of tasks that may contain nulls
|
|
68
|
+
* @returns Array of tasks with nulls removed
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```typescript
|
|
72
|
+
* const tasks = await Promise.all(ids.map(id => storage.getTask(id)));
|
|
73
|
+
* const validTasks = filterNullTasks(tasks);
|
|
74
|
+
* // validTasks has type Task[] (no null)
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
export function filterNullTasks(tasks: (Task | null)[]): Task[] {
|
|
78
|
+
return tasks.filter((task): task is Task => task !== null);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Validates that a task ID is a non-empty string.
|
|
83
|
+
*
|
|
84
|
+
* @param taskId - Task ID to validate
|
|
85
|
+
* @throws TaskOMaticError if task ID is invalid
|
|
86
|
+
*/
|
|
87
|
+
export function validateTaskId(taskId: string): void {
|
|
88
|
+
if (!taskId || typeof taskId !== "string" || !taskId.trim()) {
|
|
89
|
+
throw createStandardError(
|
|
90
|
+
TaskOMaticErrorCodes.INVALID_INPUT,
|
|
91
|
+
"Invalid task ID: must be a non-empty string"
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
}
|