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,77 @@
|
|
|
1
|
+
import assert from "node:assert";
|
|
2
|
+
import { hooks } from "../lib/hooks";
|
|
3
|
+
import { Task } from "../types";
|
|
4
|
+
|
|
5
|
+
describe("HookRegistry", () => {
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
hooks.clear();
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it("should register and call a listener", async () => {
|
|
11
|
+
let called = false;
|
|
12
|
+
const task = { id: "1", title: "Test Task" } as Task;
|
|
13
|
+
|
|
14
|
+
hooks.on("task:created", (payload) => {
|
|
15
|
+
assert.strictEqual(payload.task, task);
|
|
16
|
+
called = true;
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
await hooks.emit("task:created", { task });
|
|
20
|
+
assert.strictEqual(called, true);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("should handle multiple listeners", async () => {
|
|
24
|
+
let count = 0;
|
|
25
|
+
const task = { id: "1", title: "Test Task" } as Task;
|
|
26
|
+
|
|
27
|
+
hooks.on("task:created", () => {
|
|
28
|
+
count++;
|
|
29
|
+
});
|
|
30
|
+
hooks.on("task:created", () => {
|
|
31
|
+
count++;
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
await hooks.emit("task:created", { task });
|
|
35
|
+
assert.strictEqual(count, 2);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("should remove a listener", async () => {
|
|
39
|
+
let count = 0;
|
|
40
|
+
const handler = () => {
|
|
41
|
+
count++;
|
|
42
|
+
};
|
|
43
|
+
const task = { id: "1", title: "Test Task" } as Task;
|
|
44
|
+
|
|
45
|
+
hooks.on("task:created", handler);
|
|
46
|
+
hooks.off("task:created", handler);
|
|
47
|
+
|
|
48
|
+
await hooks.emit("task:created", { task });
|
|
49
|
+
assert.strictEqual(count, 0);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("should not fail if a listener throws", async () => {
|
|
53
|
+
const task = { id: "1", title: "Test Task" } as Task;
|
|
54
|
+
|
|
55
|
+
// Suppress console.error for this test
|
|
56
|
+
const originalConsoleError = console.error;
|
|
57
|
+
console.error = () => {};
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
hooks.on("task:created", () => {
|
|
61
|
+
throw new Error("Oops");
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
let secondCalled = false;
|
|
65
|
+
hooks.on("task:created", () => {
|
|
66
|
+
secondCalled = true;
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// Should not throw
|
|
70
|
+
await hooks.emit("task:created", { task });
|
|
71
|
+
assert.strictEqual(secondCalled, true);
|
|
72
|
+
} finally {
|
|
73
|
+
// Restore console.error
|
|
74
|
+
console.error = originalConsoleError;
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { FileSystemStorage } from "../../lib/storage/file-system";
|
|
2
|
+
import { StorageCallbacks } from "../../lib/storage/storage-callbacks";
|
|
3
|
+
import * as assert from "assert";
|
|
4
|
+
|
|
5
|
+
describe("Callback Integration", () => {
|
|
6
|
+
it("should use custom storage callbacks", async () => {
|
|
7
|
+
const memoryStore = new Map<string, string>();
|
|
8
|
+
|
|
9
|
+
const callbacks: StorageCallbacks = {
|
|
10
|
+
read: async (key) => memoryStore.get(key) || null,
|
|
11
|
+
write: async (key, value) => {
|
|
12
|
+
memoryStore.set(key, value);
|
|
13
|
+
},
|
|
14
|
+
delete: async (key) => {
|
|
15
|
+
memoryStore.delete(key);
|
|
16
|
+
},
|
|
17
|
+
list: async (prefix) =>
|
|
18
|
+
Array.from(memoryStore.keys()).filter((k) =>
|
|
19
|
+
k.startsWith(prefix || "")
|
|
20
|
+
),
|
|
21
|
+
exists: async (key) => memoryStore.has(key),
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const storage = new FileSystemStorage(callbacks);
|
|
25
|
+
|
|
26
|
+
// Create task
|
|
27
|
+
const task = await storage.createTask({ title: "Test Task" });
|
|
28
|
+
|
|
29
|
+
// Verify it was written to memory store
|
|
30
|
+
assert.strictEqual(memoryStore.has("tasks.json"), true);
|
|
31
|
+
const data = JSON.parse(memoryStore.get("tasks.json")!);
|
|
32
|
+
assert.strictEqual(data.tasks.length, 1);
|
|
33
|
+
assert.strictEqual(data.tasks[0].title, "Test Task");
|
|
34
|
+
|
|
35
|
+
// Verify retrieval
|
|
36
|
+
const retrieved = await storage.getTask(task.id);
|
|
37
|
+
assert.strictEqual(retrieved?.id, task.id);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
import * as assert from "assert";
|
|
2
|
+
import { TaskOperations } from "../../../lib/ai-service/task-operations";
|
|
3
|
+
import { Task } from "../../../types";
|
|
4
|
+
import { TaskOMaticError } from "../../../utils/task-o-matic-error";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* ⚠️ CRITICAL: These integration tests use 100% MOCKS - ZERO real AI calls
|
|
8
|
+
* No API calls are made, no costs incurred, tests run fast
|
|
9
|
+
*
|
|
10
|
+
* These tests verify that TaskOperations properly integrates with AIOperationUtility
|
|
11
|
+
* and that errors propagate correctly through the stack.
|
|
12
|
+
*/
|
|
13
|
+
describe("TaskOperations Integration Tests", () => {
|
|
14
|
+
let taskOps: TaskOperations;
|
|
15
|
+
let mockAIOperationUtility: any;
|
|
16
|
+
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
taskOps = new TaskOperations();
|
|
19
|
+
|
|
20
|
+
// Create mock AIOperationUtility - NO REAL AI CALLS
|
|
21
|
+
mockAIOperationUtility = {
|
|
22
|
+
executeAIOperation: async (
|
|
23
|
+
operationName: string,
|
|
24
|
+
operation: () => Promise<any>,
|
|
25
|
+
options?: any
|
|
26
|
+
) => {
|
|
27
|
+
// Execute the operation and return mock metrics
|
|
28
|
+
const result = await operation();
|
|
29
|
+
return {
|
|
30
|
+
result,
|
|
31
|
+
metrics: {
|
|
32
|
+
duration: 100,
|
|
33
|
+
tokenUsage: {
|
|
34
|
+
prompt: 50,
|
|
35
|
+
completion: 25,
|
|
36
|
+
total: 75,
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
},
|
|
41
|
+
streamTextWithTools: async (
|
|
42
|
+
systemPrompt: string,
|
|
43
|
+
userMessage: string,
|
|
44
|
+
config?: any,
|
|
45
|
+
streamingOptions?: any,
|
|
46
|
+
tools?: any
|
|
47
|
+
) => {
|
|
48
|
+
// Return mock JSON response
|
|
49
|
+
return JSON.stringify({
|
|
50
|
+
subtasks: [
|
|
51
|
+
{
|
|
52
|
+
title: "Mock subtask 1",
|
|
53
|
+
description: "Mock description 1",
|
|
54
|
+
effort: "small",
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
title: "Mock subtask 2",
|
|
58
|
+
description: "Mock description 2",
|
|
59
|
+
effort: "medium",
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
});
|
|
63
|
+
},
|
|
64
|
+
streamText: async (
|
|
65
|
+
_prompt: string,
|
|
66
|
+
_config: any,
|
|
67
|
+
_systemPrompt: string,
|
|
68
|
+
_userMessage: string,
|
|
69
|
+
_streamingOptions?: any
|
|
70
|
+
) => {
|
|
71
|
+
return "Mock enhanced content";
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
// Inject mock into TaskOperations
|
|
76
|
+
(taskOps as any).aiOperationUtility = mockAIOperationUtility;
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
describe("breakdownTask Integration", () => {
|
|
80
|
+
it("should successfully break down a task using AIOperationUtility", async () => {
|
|
81
|
+
const mockTask: Task = {
|
|
82
|
+
id: "test-task-1",
|
|
83
|
+
title: "Test Task",
|
|
84
|
+
description: "A task to break down",
|
|
85
|
+
status: "todo",
|
|
86
|
+
createdAt: Date.now(),
|
|
87
|
+
updatedAt: Date.now(),
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const result = await taskOps.breakdownTask(mockTask);
|
|
91
|
+
|
|
92
|
+
// Verify result structure
|
|
93
|
+
assert.ok(Array.isArray(result));
|
|
94
|
+
assert.strictEqual(result.length, 2);
|
|
95
|
+
assert.strictEqual(result[0].title, "Mock subtask 1");
|
|
96
|
+
assert.strictEqual(result[0].content, "Mock description 1");
|
|
97
|
+
assert.strictEqual(result[0].estimatedEffort, "small");
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it("should handle filesystem tools when enabled", async () => {
|
|
101
|
+
let toolsPassed = false;
|
|
102
|
+
|
|
103
|
+
// Override streamTextWithTools to capture tools parameter
|
|
104
|
+
mockAIOperationUtility.streamTextWithTools = async (
|
|
105
|
+
_systemPrompt: string,
|
|
106
|
+
_userMessage: string,
|
|
107
|
+
_config: any,
|
|
108
|
+
_streamingOptions: any,
|
|
109
|
+
tools: any
|
|
110
|
+
) => {
|
|
111
|
+
if (tools && Object.keys(tools).length > 0) {
|
|
112
|
+
toolsPassed = true;
|
|
113
|
+
}
|
|
114
|
+
return JSON.stringify({
|
|
115
|
+
subtasks: [
|
|
116
|
+
{
|
|
117
|
+
title: "Subtask with tools",
|
|
118
|
+
description: "Used filesystem tools",
|
|
119
|
+
effort: "small",
|
|
120
|
+
},
|
|
121
|
+
],
|
|
122
|
+
});
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
const mockTask: Task = {
|
|
126
|
+
id: "test-task-2",
|
|
127
|
+
title: "Task with tools",
|
|
128
|
+
status: "todo",
|
|
129
|
+
createdAt: Date.now(),
|
|
130
|
+
updatedAt: Date.now(),
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
const result = await taskOps.breakdownTask(
|
|
134
|
+
mockTask,
|
|
135
|
+
undefined,
|
|
136
|
+
undefined,
|
|
137
|
+
undefined,
|
|
138
|
+
undefined,
|
|
139
|
+
undefined,
|
|
140
|
+
undefined,
|
|
141
|
+
undefined,
|
|
142
|
+
undefined,
|
|
143
|
+
true // enableFilesystemTools
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
assert.ok(toolsPassed, "Filesystem tools should be passed when enabled");
|
|
147
|
+
assert.strictEqual(result.length, 1);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it("should propagate TaskOMaticError from AIOperationUtility", async () => {
|
|
151
|
+
// Mock AIOperationUtility to throw error
|
|
152
|
+
(taskOps as any).aiOperationUtility.executeAIOperation = async () => {
|
|
153
|
+
throw new TaskOMaticError("AI operation failed: Task breakdown", {
|
|
154
|
+
code: "AI_OPERATION_FAILED",
|
|
155
|
+
context: "Mock error context",
|
|
156
|
+
suggestions: ["Check AI configuration"],
|
|
157
|
+
});
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
const mockTask: Task = {
|
|
161
|
+
id: "test-task-error",
|
|
162
|
+
title: "Task that will fail",
|
|
163
|
+
status: "todo",
|
|
164
|
+
createdAt: Date.now(),
|
|
165
|
+
updatedAt: Date.now(),
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
try {
|
|
169
|
+
await taskOps.breakdownTask(mockTask);
|
|
170
|
+
assert.fail("Should have thrown TaskOMaticError");
|
|
171
|
+
} catch (error) {
|
|
172
|
+
assert.ok(error instanceof TaskOMaticError);
|
|
173
|
+
assert.strictEqual(
|
|
174
|
+
(error as TaskOMaticError).code,
|
|
175
|
+
"AI_OPERATION_FAILED"
|
|
176
|
+
);
|
|
177
|
+
assert.ok(
|
|
178
|
+
(error as TaskOMaticError).message.includes("Task breakdown")
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
describe("enhanceTask Integration", () => {
|
|
185
|
+
it("should successfully enhance a task using AIOperationUtility", async () => {
|
|
186
|
+
const result = await taskOps.enhanceTask(
|
|
187
|
+
"Test Task",
|
|
188
|
+
"Basic description"
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
// Verify result
|
|
192
|
+
assert.strictEqual(typeof result, "string");
|
|
193
|
+
assert.strictEqual(result, "Mock enhanced content");
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
it("should propagate errors from AIOperationUtility", async () => {
|
|
197
|
+
// Mock AIOperationUtility to throw error
|
|
198
|
+
(taskOps as any).aiOperationUtility.executeAIOperation = async () => {
|
|
199
|
+
throw new TaskOMaticError("AI operation failed: Task enhancement", {
|
|
200
|
+
code: "AI_OPERATION_FAILED",
|
|
201
|
+
context: "Enhancement failed",
|
|
202
|
+
suggestions: ["Retry with different parameters"],
|
|
203
|
+
});
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
try {
|
|
207
|
+
await taskOps.enhanceTask("Test", "Description");
|
|
208
|
+
assert.fail("Should have thrown TaskOMaticError");
|
|
209
|
+
} catch (error) {
|
|
210
|
+
assert.ok(error instanceof TaskOMaticError);
|
|
211
|
+
assert.ok(
|
|
212
|
+
(error as TaskOMaticError).message.includes("Task enhancement")
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
describe("planTask Integration", () => {
|
|
219
|
+
it("should successfully plan a task using AIOperationUtility", async () => {
|
|
220
|
+
// Mock streamTextWithTools to return plan
|
|
221
|
+
mockAIOperationUtility.streamTextWithTools = async () => {
|
|
222
|
+
return "Mock implementation plan:\n1. Step 1\n2. Step 2\n3. Step 3";
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
const result = await taskOps.planTask("Project context", "Task details");
|
|
226
|
+
|
|
227
|
+
// Verify result
|
|
228
|
+
assert.strictEqual(typeof result, "string");
|
|
229
|
+
assert.ok(result.includes("Mock implementation plan"));
|
|
230
|
+
assert.ok(result.includes("Step 1"));
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
it("should handle MCP tools and filesystem tools", async () => {
|
|
234
|
+
let toolsReceived = false;
|
|
235
|
+
|
|
236
|
+
mockAIOperationUtility.streamTextWithTools = async (
|
|
237
|
+
_systemPrompt: string,
|
|
238
|
+
_userMessage: string,
|
|
239
|
+
_config: any,
|
|
240
|
+
_streamingOptions: any,
|
|
241
|
+
tools: any
|
|
242
|
+
) => {
|
|
243
|
+
if (tools && Object.keys(tools).length > 0) {
|
|
244
|
+
toolsReceived = true;
|
|
245
|
+
}
|
|
246
|
+
return "Plan with tools";
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
// Mock Context7Client to return MCP tools
|
|
250
|
+
const mockContext7Client = {
|
|
251
|
+
getMCPTools: async () => ({
|
|
252
|
+
mockTool: {
|
|
253
|
+
description: "Mock MCP tool",
|
|
254
|
+
parameters: {},
|
|
255
|
+
execute: async () => ({}),
|
|
256
|
+
},
|
|
257
|
+
}),
|
|
258
|
+
saveContext7Documentation: () => {},
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
(taskOps as any).context7Client = mockContext7Client;
|
|
262
|
+
|
|
263
|
+
const result = await taskOps.planTask("Context", "Details");
|
|
264
|
+
|
|
265
|
+
assert.ok(toolsReceived, "Tools should be passed to streamTextWithTools");
|
|
266
|
+
assert.strictEqual(result, "Plan with tools");
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
it("should propagate errors from AIOperationUtility", async () => {
|
|
270
|
+
// Mock AIOperationUtility to throw error
|
|
271
|
+
(taskOps as any).aiOperationUtility.executeAIOperation = async () => {
|
|
272
|
+
throw new TaskOMaticError("AI operation failed: Task planning", {
|
|
273
|
+
code: "AI_OPERATION_FAILED",
|
|
274
|
+
context: "Planning failed",
|
|
275
|
+
suggestions: ["Check task context"],
|
|
276
|
+
});
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
try {
|
|
280
|
+
await taskOps.planTask("Context", "Details");
|
|
281
|
+
assert.fail("Should have thrown TaskOMaticError");
|
|
282
|
+
} catch (error) {
|
|
283
|
+
assert.ok(error instanceof TaskOMaticError);
|
|
284
|
+
assert.ok((error as TaskOMaticError).message.includes("Task planning"));
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
describe("Metrics Flow", () => {
|
|
290
|
+
it("should return results from AIOperationUtility without exposing metrics", async () => {
|
|
291
|
+
// breakdownTask returns result.result directly, not the full AIOperationResult
|
|
292
|
+
const mockTask: Task = {
|
|
293
|
+
id: "metrics-test",
|
|
294
|
+
title: "Metrics test task",
|
|
295
|
+
status: "todo",
|
|
296
|
+
createdAt: Date.now(),
|
|
297
|
+
updatedAt: Date.now(),
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
const result = await taskOps.breakdownTask(mockTask);
|
|
301
|
+
|
|
302
|
+
// Verify we got the result, not the AIOperationResult wrapper
|
|
303
|
+
assert.ok(Array.isArray(result));
|
|
304
|
+
assert.ok(!("metrics" in result), "Should not expose metrics in result");
|
|
305
|
+
assert.ok(
|
|
306
|
+
!("result" in result),
|
|
307
|
+
"Should not expose AIOperationResult structure"
|
|
308
|
+
);
|
|
309
|
+
});
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
describe("Error Handling Integration", () => {
|
|
313
|
+
it("should wrap string errors in TaskOMaticError", async () => {
|
|
314
|
+
// Mock operation that throws string error
|
|
315
|
+
(taskOps as any).aiOperationUtility.executeAIOperation = async () => {
|
|
316
|
+
const error = new Error("String error was converted");
|
|
317
|
+
throw new TaskOMaticError("AI operation failed: Task breakdown", {
|
|
318
|
+
code: "AI_OPERATION_FAILED",
|
|
319
|
+
cause: error,
|
|
320
|
+
context: JSON.stringify({
|
|
321
|
+
operation: "Task breakdown",
|
|
322
|
+
error: "String error was converted",
|
|
323
|
+
}),
|
|
324
|
+
suggestions: ["Check AI configuration"],
|
|
325
|
+
});
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
const mockTask: Task = {
|
|
329
|
+
id: "string-error-test",
|
|
330
|
+
title: "Test",
|
|
331
|
+
status: "todo",
|
|
332
|
+
createdAt: Date.now(),
|
|
333
|
+
updatedAt: Date.now(),
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
try {
|
|
337
|
+
await taskOps.breakdownTask(mockTask);
|
|
338
|
+
assert.fail("Should have thrown");
|
|
339
|
+
} catch (error) {
|
|
340
|
+
assert.ok(error instanceof TaskOMaticError);
|
|
341
|
+
const taskError = error as TaskOMaticError;
|
|
342
|
+
assert.ok(taskError.cause instanceof Error);
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
it("should preserve error context and suggestions", async () => {
|
|
347
|
+
const mockError = new TaskOMaticError("Original error", {
|
|
348
|
+
code: "TEST_ERROR",
|
|
349
|
+
context: "Original context",
|
|
350
|
+
suggestions: ["Original suggestion 1", "Original suggestion 2"],
|
|
351
|
+
metadata: { testData: "test value" },
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
(taskOps as any).aiOperationUtility.executeAIOperation = async () => {
|
|
355
|
+
throw mockError;
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
const mockTask: Task = {
|
|
359
|
+
id: "context-test",
|
|
360
|
+
title: "Test",
|
|
361
|
+
status: "todo",
|
|
362
|
+
createdAt: Date.now(),
|
|
363
|
+
updatedAt: Date.now(),
|
|
364
|
+
};
|
|
365
|
+
|
|
366
|
+
try {
|
|
367
|
+
await taskOps.breakdownTask(mockTask);
|
|
368
|
+
assert.fail("Should have thrown");
|
|
369
|
+
} catch (error) {
|
|
370
|
+
assert.ok(error instanceof TaskOMaticError);
|
|
371
|
+
const taskError = error as TaskOMaticError;
|
|
372
|
+
assert.strictEqual(taskError.code, "TEST_ERROR");
|
|
373
|
+
assert.ok(taskError.context?.includes("Original context"));
|
|
374
|
+
assert.ok(Array.isArray(taskError.suggestions));
|
|
375
|
+
assert.ok(taskError.metadata?.testData === "test value");
|
|
376
|
+
}
|
|
377
|
+
});
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
describe("Streaming Options Integration", () => {
|
|
381
|
+
it("should pass streaming options through to AIOperationUtility", async () => {
|
|
382
|
+
let onChunkCalled = false;
|
|
383
|
+
let onFinishCalled = false;
|
|
384
|
+
|
|
385
|
+
const streamingOptions = {
|
|
386
|
+
onChunk: (chunk: string) => {
|
|
387
|
+
onChunkCalled = true;
|
|
388
|
+
},
|
|
389
|
+
onFinish: (result: any) => {
|
|
390
|
+
onFinishCalled = true;
|
|
391
|
+
},
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
// Mock to verify streaming options are passed
|
|
395
|
+
let receivedOptions: any;
|
|
396
|
+
(taskOps as any).aiOperationUtility.executeAIOperation = async (
|
|
397
|
+
_operationName: string,
|
|
398
|
+
operation: () => Promise<any>,
|
|
399
|
+
options: any
|
|
400
|
+
) => {
|
|
401
|
+
receivedOptions = options;
|
|
402
|
+
const result = await operation();
|
|
403
|
+
return {
|
|
404
|
+
result,
|
|
405
|
+
metrics: { duration: 100 },
|
|
406
|
+
};
|
|
407
|
+
};
|
|
408
|
+
|
|
409
|
+
const mockTask: Task = {
|
|
410
|
+
id: "streaming-test",
|
|
411
|
+
title: "Test",
|
|
412
|
+
status: "todo",
|
|
413
|
+
createdAt: Date.now(),
|
|
414
|
+
updatedAt: Date.now(),
|
|
415
|
+
};
|
|
416
|
+
|
|
417
|
+
await taskOps.breakdownTask(
|
|
418
|
+
mockTask,
|
|
419
|
+
undefined,
|
|
420
|
+
undefined,
|
|
421
|
+
undefined,
|
|
422
|
+
streamingOptions
|
|
423
|
+
);
|
|
424
|
+
|
|
425
|
+
// Verify streaming options were passed
|
|
426
|
+
assert.ok(receivedOptions);
|
|
427
|
+
assert.ok(receivedOptions.streamingOptions);
|
|
428
|
+
});
|
|
429
|
+
});
|
|
430
|
+
});
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import assert from "assert";
|
|
2
|
+
import { ConfigManager, Config, ConfigCallbacks } from "../../lib/config";
|
|
3
|
+
import { TaskOMaticErrorCodes } from "../../utils/task-o-matic-error";
|
|
4
|
+
|
|
5
|
+
describe("ConfigManager", () => {
|
|
6
|
+
let mockCallbacks: ConfigCallbacks;
|
|
7
|
+
let mockStorage: Record<string, string>;
|
|
8
|
+
let mockEnv: Record<string, string>;
|
|
9
|
+
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
mockStorage = {};
|
|
12
|
+
mockEnv = {};
|
|
13
|
+
mockCallbacks = {
|
|
14
|
+
read: async (key: string) => mockStorage[key] || null,
|
|
15
|
+
write: async (key: string, value: string) => {
|
|
16
|
+
mockStorage[key] = value;
|
|
17
|
+
},
|
|
18
|
+
getEnv: (key: string) => mockEnv[key],
|
|
19
|
+
};
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("should load default configuration when no config file exists", async () => {
|
|
23
|
+
const configManager = new ConfigManager(mockCallbacks);
|
|
24
|
+
const config = await configManager.load();
|
|
25
|
+
|
|
26
|
+
assert.strictEqual(config.ai.provider, "openrouter"); // Default
|
|
27
|
+
assert.strictEqual(config.ai.model, "z-ai/glm-4.6"); // Default
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("should load configuration from file", async () => {
|
|
31
|
+
const storedConfig: Config = {
|
|
32
|
+
ai: {
|
|
33
|
+
provider: "openai",
|
|
34
|
+
model: "gpt-4",
|
|
35
|
+
apiKey: "sk-test",
|
|
36
|
+
maxTokens: 1000,
|
|
37
|
+
temperature: 0.1,
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
mockStorage["config.json"] = JSON.stringify(storedConfig);
|
|
41
|
+
|
|
42
|
+
const configManager = new ConfigManager(mockCallbacks);
|
|
43
|
+
const config = await configManager.load();
|
|
44
|
+
|
|
45
|
+
assert.strictEqual(config.ai.provider, "openai");
|
|
46
|
+
assert.strictEqual(config.ai.model, "gpt-4");
|
|
47
|
+
assert.strictEqual(config.ai.apiKey, "sk-test");
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("should override config with environment variables", async () => {
|
|
51
|
+
const storedConfig: Config = {
|
|
52
|
+
ai: {
|
|
53
|
+
provider: "openai",
|
|
54
|
+
model: "gpt-4",
|
|
55
|
+
apiKey: "sk-test",
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
mockStorage["config.json"] = JSON.stringify(storedConfig);
|
|
59
|
+
mockEnv["AI_PROVIDER"] = "anthropic";
|
|
60
|
+
mockEnv["ANTHROPIC_API_KEY"] = "sk-ant-test";
|
|
61
|
+
|
|
62
|
+
// Note: ConfigManager loads defaults based on provider, but file config overrides defaults,
|
|
63
|
+
// and env config overrides file config?
|
|
64
|
+
// Let's check implementation:
|
|
65
|
+
// ... fileConfig ... envConfig
|
|
66
|
+
// ai: { ...defaultConfig.ai, ...fileConfig.ai, ...envConfig }
|
|
67
|
+
// So envConfig wins.
|
|
68
|
+
|
|
69
|
+
const configManager = new ConfigManager(mockCallbacks);
|
|
70
|
+
const config = await configManager.load();
|
|
71
|
+
|
|
72
|
+
assert.strictEqual(config.ai.provider, "anthropic");
|
|
73
|
+
assert.strictEqual(config.ai.apiKey, "sk-ant-test");
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("should validate configuration", async () => {
|
|
77
|
+
const configManager = new ConfigManager(mockCallbacks);
|
|
78
|
+
|
|
79
|
+
// Invalid provider
|
|
80
|
+
const result1 = configManager.validate({
|
|
81
|
+
ai: { provider: "invalid" as any, model: "test-model" },
|
|
82
|
+
});
|
|
83
|
+
assert.strictEqual(result1.valid, false);
|
|
84
|
+
assert.ok(result1.errors[0].includes("Invalid provider"));
|
|
85
|
+
|
|
86
|
+
// Valid provider
|
|
87
|
+
const result2 = configManager.validate({
|
|
88
|
+
ai: { provider: "openai", model: "gpt-5.2-mini" },
|
|
89
|
+
});
|
|
90
|
+
assert.strictEqual(result2.valid, true);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it("should save configuration", async () => {
|
|
94
|
+
const configManager = new ConfigManager(mockCallbacks);
|
|
95
|
+
await configManager.load(); // Load defaults
|
|
96
|
+
|
|
97
|
+
const newConfig: Config = {
|
|
98
|
+
ai: {
|
|
99
|
+
provider: "custom",
|
|
100
|
+
model: "my-model",
|
|
101
|
+
apiKey: "secret",
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
configManager.setConfig(newConfig);
|
|
105
|
+
await configManager.save();
|
|
106
|
+
|
|
107
|
+
const saved = JSON.parse(mockStorage["config.json"]);
|
|
108
|
+
assert.strictEqual(saved.ai.provider, "custom");
|
|
109
|
+
assert.strictEqual(saved.ai.model, "my-model");
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it("should throw error when accessing config before load", () => {
|
|
113
|
+
const configManager = new ConfigManager(mockCallbacks);
|
|
114
|
+
assert.throws(
|
|
115
|
+
() => {
|
|
116
|
+
configManager.getConfig();
|
|
117
|
+
},
|
|
118
|
+
(err: any) => {
|
|
119
|
+
return err.code === TaskOMaticErrorCodes.CONFIGURATION_ERROR;
|
|
120
|
+
}
|
|
121
|
+
);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it("should set AI config partially and save", async () => {
|
|
125
|
+
const configManager = new ConfigManager(mockCallbacks);
|
|
126
|
+
await configManager.load();
|
|
127
|
+
|
|
128
|
+
await configManager.setAIConfig({
|
|
129
|
+
temperature: 0.9,
|
|
130
|
+
maxTokens: 500,
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
const saved = JSON.parse(mockStorage["config.json"]);
|
|
134
|
+
assert.strictEqual(saved.ai.temperature, 0.9);
|
|
135
|
+
assert.strictEqual(saved.ai.maxTokens, 500);
|
|
136
|
+
// Should preserve other defaults
|
|
137
|
+
assert.strictEqual(saved.ai.provider, "openrouter");
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it("should update callbacks when changing working directory", () => {
|
|
141
|
+
const configManager = new ConfigManager();
|
|
142
|
+
const initialDir = configManager.getWorkingDirectory();
|
|
143
|
+
|
|
144
|
+
configManager.setWorkingDirectory("/new/path");
|
|
145
|
+
assert.notStrictEqual(configManager.getWorkingDirectory(), initialDir);
|
|
146
|
+
|
|
147
|
+
// Should reset config
|
|
148
|
+
assert.throws(() => configManager.getConfig());
|
|
149
|
+
});
|
|
150
|
+
});
|