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,306 @@
|
|
|
1
|
+
import * as assert from "assert";
|
|
2
|
+
import { AIOperationUtility } from "../../utils/ai-operation-utility";
|
|
3
|
+
import { TaskOMaticError } from "../../utils/task-o-matic-error";
|
|
4
|
+
import { RetryHandler } from "../../lib/ai-service/retry-handler";
|
|
5
|
+
import { ModelProvider } from "../../lib/ai-service/model-provider";
|
|
6
|
+
import { Context7Client } from "../../lib/ai-service/mcp-client";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* ⚠️ CRITICAL: These tests use 100% MOCKS - ZERO real AI calls
|
|
10
|
+
* No API calls are made, no costs incurred, tests run fast
|
|
11
|
+
*/
|
|
12
|
+
describe("AIOperationUtility", () => {
|
|
13
|
+
let utility: AIOperationUtility;
|
|
14
|
+
let mockRetryHandler: any;
|
|
15
|
+
let mockModelProvider: any;
|
|
16
|
+
let mockContext7Client: any;
|
|
17
|
+
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
// Create utility instance
|
|
20
|
+
utility = new AIOperationUtility();
|
|
21
|
+
|
|
22
|
+
// Create mock retry handler - NO REAL RETRIES
|
|
23
|
+
mockRetryHandler = {
|
|
24
|
+
executeWithRetry: async (operation: () => Promise<any>) => {
|
|
25
|
+
// Execute immediately without real retry logic
|
|
26
|
+
return await operation();
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// Create mock model provider - NO REAL AI MODELS
|
|
31
|
+
mockModelProvider = {
|
|
32
|
+
getModel: () => ({
|
|
33
|
+
// Mock AI SDK v2 compliant model
|
|
34
|
+
specificationVersion: "v2",
|
|
35
|
+
provider: "mock",
|
|
36
|
+
modelId: "mock-model",
|
|
37
|
+
doGenerate: async () => ({
|
|
38
|
+
text: "Mock response",
|
|
39
|
+
finishReason: "stop",
|
|
40
|
+
usage: {
|
|
41
|
+
promptTokens: 10,
|
|
42
|
+
completionTokens: 5,
|
|
43
|
+
totalTokens: 15,
|
|
44
|
+
},
|
|
45
|
+
}),
|
|
46
|
+
doStream: async () => ({
|
|
47
|
+
stream: (async function* () {
|
|
48
|
+
yield { type: "text-delta", textDelta: "Mock" };
|
|
49
|
+
yield { type: "text-delta", textDelta: " response" };
|
|
50
|
+
})(),
|
|
51
|
+
}),
|
|
52
|
+
}),
|
|
53
|
+
getAIConfig: () => ({
|
|
54
|
+
provider: "mock",
|
|
55
|
+
model: "mock-model",
|
|
56
|
+
apiKey: "mock-key",
|
|
57
|
+
}),
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// Create mock Context7 client - NO REAL DOCUMENTATION FETCHES
|
|
61
|
+
mockContext7Client = {
|
|
62
|
+
saveContext7Documentation: () => {
|
|
63
|
+
// Mock save - no real file writes
|
|
64
|
+
},
|
|
65
|
+
getMCPTools: async () => ({}),
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// Inject mocks into utility
|
|
69
|
+
(utility as any).retryHandler = mockRetryHandler;
|
|
70
|
+
(utility as any).modelProvider = mockModelProvider;
|
|
71
|
+
(utility as any).context7Client = mockContext7Client;
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe("executeAIOperation", () => {
|
|
75
|
+
it("should execute operation successfully and return result with metrics", async () => {
|
|
76
|
+
// Mock operation that returns a simple result
|
|
77
|
+
const mockResult = { data: "test result" };
|
|
78
|
+
const operation = async () => mockResult;
|
|
79
|
+
|
|
80
|
+
const result = await utility.executeAIOperation(
|
|
81
|
+
"test operation",
|
|
82
|
+
operation
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
assert.deepStrictEqual(result.result, mockResult);
|
|
86
|
+
assert.ok("duration" in result.metrics);
|
|
87
|
+
assert.strictEqual(typeof result.metrics.duration, "number");
|
|
88
|
+
assert.ok(result.metrics.duration >= 0);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("should throw TaskOMaticError when operation fails", async () => {
|
|
92
|
+
// Mock operation that throws an error
|
|
93
|
+
const operation = async () => {
|
|
94
|
+
throw new Error("Mock AI failure");
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
await utility.executeAIOperation("test operation", operation);
|
|
99
|
+
assert.fail("Should have thrown TaskOMaticError");
|
|
100
|
+
} catch (error) {
|
|
101
|
+
assert.ok(error instanceof TaskOMaticError);
|
|
102
|
+
assert.strictEqual((error as TaskOMaticError).code, "AI_OPERATION_FAILED");
|
|
103
|
+
assert.ok((error as TaskOMaticError).message.includes("test operation"));
|
|
104
|
+
assert.ok(Array.isArray((error as TaskOMaticError).suggestions));
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it("should preserve error details in TaskOMaticError", async () => {
|
|
109
|
+
const originalError = new Error("Original error message");
|
|
110
|
+
const operation = async () => {
|
|
111
|
+
throw originalError;
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
await utility.executeAIOperation("test operation", operation);
|
|
116
|
+
assert.fail("Should have thrown");
|
|
117
|
+
} catch (error) {
|
|
118
|
+
assert.ok(error instanceof TaskOMaticError);
|
|
119
|
+
const taskError = error as TaskOMaticError;
|
|
120
|
+
assert.strictEqual(taskError.cause, originalError);
|
|
121
|
+
assert.ok(taskError.context?.includes("test operation"));
|
|
122
|
+
assert.ok("operationName" in (taskError.metadata || {}));
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it("should capture duration metrics correctly", async () => {
|
|
127
|
+
const operation = async () => {
|
|
128
|
+
// Simulate some work
|
|
129
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
130
|
+
return { data: "result" };
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
const result = await utility.executeAIOperation(
|
|
134
|
+
"slow operation",
|
|
135
|
+
operation
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
assert.ok(result.metrics.duration >= 50);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it("should respect maxRetries option", async () => {
|
|
142
|
+
let attemptCount = 0;
|
|
143
|
+
|
|
144
|
+
// Mock retry handler that counts attempts
|
|
145
|
+
(utility as any).retryHandler = {
|
|
146
|
+
executeWithRetry: async (
|
|
147
|
+
operation: () => Promise<any>,
|
|
148
|
+
config: any
|
|
149
|
+
) => {
|
|
150
|
+
attemptCount++;
|
|
151
|
+
assert.strictEqual(config.maxAttempts, 5);
|
|
152
|
+
return await operation();
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
const operation = async () => ({ data: "result" });
|
|
157
|
+
|
|
158
|
+
await utility.executeAIOperation("test", operation, { maxRetries: 5 });
|
|
159
|
+
assert.strictEqual(attemptCount, 1);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it("should extract token usage from result if available", async () => {
|
|
163
|
+
const mockResult = {
|
|
164
|
+
data: "test",
|
|
165
|
+
usage: {
|
|
166
|
+
prompt_tokens: 100,
|
|
167
|
+
completion_tokens: 50,
|
|
168
|
+
total_tokens: 150,
|
|
169
|
+
},
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
const operation = async () => mockResult;
|
|
173
|
+
|
|
174
|
+
const result = await utility.executeAIOperation("test", operation);
|
|
175
|
+
|
|
176
|
+
assert.deepStrictEqual(result.metrics.tokenUsage, {
|
|
177
|
+
prompt: 100,
|
|
178
|
+
completion: 50,
|
|
179
|
+
total: 150,
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it("should return undefined tokenUsage if not available in result", async () => {
|
|
184
|
+
const mockResult = { data: "test" };
|
|
185
|
+
const operation = async () => mockResult;
|
|
186
|
+
|
|
187
|
+
const result = await utility.executeAIOperation("test", operation);
|
|
188
|
+
|
|
189
|
+
assert.strictEqual(result.metrics.tokenUsage, undefined);
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
describe("streamTextWithTools", () => {
|
|
194
|
+
it("should verify method signature exists - NO REAL AI CALL", async () => {
|
|
195
|
+
// This test verifies the method exists and has the correct signature
|
|
196
|
+
// We don't actually call it to avoid real AI calls
|
|
197
|
+
assert.strictEqual(typeof utility.streamTextWithTools, "function");
|
|
198
|
+
|
|
199
|
+
// Verify the method is accessible
|
|
200
|
+
assert.ok("streamTextWithTools" in utility);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it("should pass tools to streamText when provided - NO REAL AI CALL", async () => {
|
|
204
|
+
// This test would verify tool passing in a real scenario
|
|
205
|
+
// For now, we just verify the method accepts tools parameter
|
|
206
|
+
const mockTools = {
|
|
207
|
+
readFile: {
|
|
208
|
+
description: "Read a file",
|
|
209
|
+
parameters: {},
|
|
210
|
+
execute: async () => ({}),
|
|
211
|
+
},
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
// The method should not throw
|
|
215
|
+
try {
|
|
216
|
+
// We can't fully test without real AI, but we verify the signature
|
|
217
|
+
assert.strictEqual(typeof utility.streamTextWithTools, "function");
|
|
218
|
+
} catch (error) {
|
|
219
|
+
assert.fail("Should not throw with valid parameters");
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
describe("Error Handling", () => {
|
|
225
|
+
it("should wrap string errors in Error objects", async () => {
|
|
226
|
+
const operation = async () => {
|
|
227
|
+
throw "String error";
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
try {
|
|
231
|
+
await utility.executeAIOperation("test", operation);
|
|
232
|
+
assert.fail("Should have thrown");
|
|
233
|
+
} catch (error) {
|
|
234
|
+
assert.ok(error instanceof TaskOMaticError);
|
|
235
|
+
assert.ok((error as TaskOMaticError).cause instanceof Error);
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
it("should include suggestions in thrown errors", async () => {
|
|
240
|
+
const operation = async () => {
|
|
241
|
+
throw new Error("Network timeout");
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
try {
|
|
245
|
+
await utility.executeAIOperation("test", operation);
|
|
246
|
+
assert.fail("Should have thrown");
|
|
247
|
+
} catch (error) {
|
|
248
|
+
const taskError = error as TaskOMaticError;
|
|
249
|
+
assert.ok(Array.isArray(taskError.suggestions));
|
|
250
|
+
assert.ok(taskError.suggestions!.length > 0);
|
|
251
|
+
assert.ok(taskError.suggestions?.includes("Check AI configuration"));
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
describe("Metrics Collection", () => {
|
|
257
|
+
it("should always include duration in metrics", async () => {
|
|
258
|
+
const operation = async () => ({ data: "result" });
|
|
259
|
+
|
|
260
|
+
const result = await utility.executeAIOperation("test", operation);
|
|
261
|
+
|
|
262
|
+
assert.ok("duration" in result.metrics);
|
|
263
|
+
assert.strictEqual(typeof result.metrics.duration, "number");
|
|
264
|
+
assert.ok(result.metrics.duration >= 0);
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
it("should capture metrics even on error", async () => {
|
|
268
|
+
const operation = async () => {
|
|
269
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
270
|
+
throw new Error("Failure");
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
try {
|
|
274
|
+
await utility.executeAIOperation("test", operation);
|
|
275
|
+
assert.fail("Should have thrown");
|
|
276
|
+
} catch (error) {
|
|
277
|
+
const taskError = error as TaskOMaticError;
|
|
278
|
+
assert.ok("duration" in (taskError.metadata || {}));
|
|
279
|
+
assert.ok((taskError.metadata?.duration as number) >= 10);
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
describe("Streaming Options", () => {
|
|
285
|
+
it("should wrap streaming options without modifying original", async () => {
|
|
286
|
+
let chunkCount = 0;
|
|
287
|
+
const originalOnChunk = (chunk: string) => {
|
|
288
|
+
chunkCount++;
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
const streamingOptions = {
|
|
292
|
+
onChunk: originalOnChunk,
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
// The wrapping happens internally, we just verify it doesn't throw
|
|
296
|
+
const operation = async () => ({ data: "result" });
|
|
297
|
+
|
|
298
|
+
await utility.executeAIOperation("test", operation, {
|
|
299
|
+
streamingOptions,
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
// Original callback should not be modified
|
|
303
|
+
assert.strictEqual(streamingOptions.onChunk, originalOnChunk);
|
|
304
|
+
});
|
|
305
|
+
});
|
|
306
|
+
});
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import * as assert from "assert";
|
|
2
|
+
import {
|
|
3
|
+
TaskOMaticError,
|
|
4
|
+
TaskOMaticErrorCodes,
|
|
5
|
+
createStandardError,
|
|
6
|
+
formatStandardError,
|
|
7
|
+
isTaskOMaticError,
|
|
8
|
+
formatTaskNotFoundError,
|
|
9
|
+
formatInvalidStatusTransitionError,
|
|
10
|
+
formatStorageError,
|
|
11
|
+
formatAIOperationError,
|
|
12
|
+
wrapErrorForBackwardCompatibility,
|
|
13
|
+
} from "../../utils/task-o-matic-error";
|
|
14
|
+
|
|
15
|
+
describe("TaskOMaticError", () => {
|
|
16
|
+
describe("TaskOMaticError class", () => {
|
|
17
|
+
it("should create a TaskOMaticError with all properties", () => {
|
|
18
|
+
const error = new TaskOMaticError("Test error", {
|
|
19
|
+
code: TaskOMaticErrorCodes.UNEXPECTED_ERROR,
|
|
20
|
+
context: "Test context",
|
|
21
|
+
suggestions: ["Suggestion 1", "Suggestion 2"],
|
|
22
|
+
metadata: { key: "value" },
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
assert.strictEqual(error.name, "TaskOMaticError");
|
|
26
|
+
assert.strictEqual(error.message, "Test error");
|
|
27
|
+
assert.strictEqual(error.code, TaskOMaticErrorCodes.UNEXPECTED_ERROR);
|
|
28
|
+
assert.strictEqual(error.context, "Test context");
|
|
29
|
+
assert.deepStrictEqual(error.suggestions, [
|
|
30
|
+
"Suggestion 1",
|
|
31
|
+
"Suggestion 2",
|
|
32
|
+
]);
|
|
33
|
+
assert.deepStrictEqual(error.metadata, { key: "value" });
|
|
34
|
+
assert.ok(error.timestamp);
|
|
35
|
+
assert.ok(error.stack);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("should create a TaskOMaticError with minimal properties", () => {
|
|
39
|
+
const error = new TaskOMaticError("Minimal error", {
|
|
40
|
+
code: TaskOMaticErrorCodes.UNEXPECTED_ERROR,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
assert.strictEqual(error.name, "TaskOMaticError");
|
|
44
|
+
assert.strictEqual(error.message, "Minimal error");
|
|
45
|
+
assert.strictEqual(error.code, TaskOMaticErrorCodes.UNEXPECTED_ERROR);
|
|
46
|
+
assert.ok(error.timestamp);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("should include cause error", () => {
|
|
50
|
+
const cause = new Error("Original error");
|
|
51
|
+
const error = new TaskOMaticError("Wrapped error", {
|
|
52
|
+
code: TaskOMaticErrorCodes.UNEXPECTED_ERROR,
|
|
53
|
+
cause,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
assert.strictEqual(error.cause, cause);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
describe("getDetails()", () => {
|
|
61
|
+
it("should return formatted error details", () => {
|
|
62
|
+
const error = new TaskOMaticError("Test error", {
|
|
63
|
+
code: TaskOMaticErrorCodes.UNEXPECTED_ERROR,
|
|
64
|
+
context: "Test context",
|
|
65
|
+
suggestions: ["Suggestion 1"],
|
|
66
|
+
metadata: { key: "value" },
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
const details = error.getDetails();
|
|
70
|
+
assert.ok(details.includes("[TASK_O_MATIC_001]"));
|
|
71
|
+
assert.ok(details.includes("Test error"));
|
|
72
|
+
assert.ok(details.includes("Context: Test context"));
|
|
73
|
+
assert.ok(details.includes("Suggestions:"));
|
|
74
|
+
assert.ok(details.includes("Suggestion 1"));
|
|
75
|
+
assert.ok(details.includes("Metadata:"));
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
describe("toJSON()", () => {
|
|
80
|
+
it("should return structured error data", () => {
|
|
81
|
+
const error = new TaskOMaticError("Test error", {
|
|
82
|
+
code: TaskOMaticErrorCodes.UNEXPECTED_ERROR,
|
|
83
|
+
context: "Test context",
|
|
84
|
+
suggestions: ["Suggestion 1"],
|
|
85
|
+
metadata: { key: "value" },
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const json = error.toJSON();
|
|
89
|
+
assert.strictEqual(json.name, "TaskOMaticError");
|
|
90
|
+
assert.strictEqual(json.code, TaskOMaticErrorCodes.UNEXPECTED_ERROR);
|
|
91
|
+
assert.strictEqual(json.message, "Test error");
|
|
92
|
+
assert.strictEqual(json.context, "Test context");
|
|
93
|
+
assert.deepStrictEqual(json.suggestions, ["Suggestion 1"]);
|
|
94
|
+
assert.deepStrictEqual(json.metadata, { key: "value" });
|
|
95
|
+
assert.ok(json.timestamp);
|
|
96
|
+
assert.ok(json.stack);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
describe("createStandardError()", () => {
|
|
101
|
+
it("should create a standardized error", () => {
|
|
102
|
+
const error = createStandardError(
|
|
103
|
+
TaskOMaticErrorCodes.TASK_NOT_FOUND,
|
|
104
|
+
"Task not found",
|
|
105
|
+
{
|
|
106
|
+
context: "Task search failed",
|
|
107
|
+
suggestions: ["Check task ID", "List all tasks"],
|
|
108
|
+
}
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
assert.ok(isTaskOMaticError(error));
|
|
112
|
+
assert.strictEqual(error.code, TaskOMaticErrorCodes.TASK_NOT_FOUND);
|
|
113
|
+
assert.strictEqual(error.message, "Task not found");
|
|
114
|
+
assert.strictEqual(error.context, "Task search failed");
|
|
115
|
+
assert.deepStrictEqual(error.suggestions, [
|
|
116
|
+
"Check task ID",
|
|
117
|
+
"List all tasks",
|
|
118
|
+
]);
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
describe("formatStandardError()", () => {
|
|
123
|
+
it("should format an error with context and suggestions", () => {
|
|
124
|
+
const originalError = new Error("Original error");
|
|
125
|
+
const error = formatStandardError(
|
|
126
|
+
originalError,
|
|
127
|
+
TaskOMaticErrorCodes.STORAGE_ERROR,
|
|
128
|
+
{
|
|
129
|
+
context: "Storage operation failed",
|
|
130
|
+
suggestions: ["Check permissions", "Retry operation"],
|
|
131
|
+
}
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
assert.ok(isTaskOMaticError(error));
|
|
135
|
+
assert.strictEqual(error.code, TaskOMaticErrorCodes.STORAGE_ERROR);
|
|
136
|
+
assert.strictEqual(error.message, "Original error");
|
|
137
|
+
assert.strictEqual(error.context, "Storage operation failed");
|
|
138
|
+
assert.deepStrictEqual(error.suggestions, [
|
|
139
|
+
"Check permissions",
|
|
140
|
+
"Retry operation",
|
|
141
|
+
]);
|
|
142
|
+
assert.strictEqual(error.cause, originalError);
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
describe("isTaskOMaticError()", () => {
|
|
147
|
+
it("should return true for TaskOMaticError instances", () => {
|
|
148
|
+
const error = new TaskOMaticError("Test", {
|
|
149
|
+
code: TaskOMaticErrorCodes.UNEXPECTED_ERROR,
|
|
150
|
+
});
|
|
151
|
+
assert.strictEqual(isTaskOMaticError(error), true);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it("should return false for regular Errors", () => {
|
|
155
|
+
const error = new Error("Regular error");
|
|
156
|
+
assert.strictEqual(isTaskOMaticError(error), false);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it("should return false for other values", () => {
|
|
160
|
+
assert.strictEqual(isTaskOMaticError("string error"), false);
|
|
161
|
+
assert.strictEqual(isTaskOMaticError(null), false);
|
|
162
|
+
assert.strictEqual(isTaskOMaticError(undefined), false);
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
describe("Standard error formatters", () => {
|
|
167
|
+
it("should format task not found error", () => {
|
|
168
|
+
const error = formatTaskNotFoundError("task-123");
|
|
169
|
+
assert.ok(isTaskOMaticError(error));
|
|
170
|
+
assert.strictEqual(error.code, TaskOMaticErrorCodes.TASK_NOT_FOUND);
|
|
171
|
+
assert.ok(error.message.includes("task-123"));
|
|
172
|
+
assert.ok(error.context);
|
|
173
|
+
assert.ok(error.suggestions);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it("should format invalid status transition error", () => {
|
|
177
|
+
const error = formatInvalidStatusTransitionError("todo", "invalid");
|
|
178
|
+
assert.ok(isTaskOMaticError(error));
|
|
179
|
+
assert.strictEqual(error.code, TaskOMaticErrorCodes.INVALID_TASK_STATUS);
|
|
180
|
+
assert.ok(error.message.includes("todo"));
|
|
181
|
+
assert.ok(error.message.includes("invalid"));
|
|
182
|
+
assert.ok(error.context);
|
|
183
|
+
assert.ok(error.suggestions);
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it("should format storage error", () => {
|
|
187
|
+
const cause = new Error("Storage failed");
|
|
188
|
+
const error = formatStorageError("save", cause);
|
|
189
|
+
assert.ok(isTaskOMaticError(error));
|
|
190
|
+
assert.strictEqual(error.code, TaskOMaticErrorCodes.STORAGE_ERROR);
|
|
191
|
+
assert.ok(error.message.includes("save"));
|
|
192
|
+
assert.strictEqual(error.cause, cause);
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it("should format AI operation error", () => {
|
|
196
|
+
const cause = new Error("AI failed");
|
|
197
|
+
const error = formatAIOperationError("generate", cause);
|
|
198
|
+
assert.ok(isTaskOMaticError(error));
|
|
199
|
+
assert.strictEqual(error.code, TaskOMaticErrorCodes.AI_OPERATION_FAILED);
|
|
200
|
+
assert.ok(error.message.includes("generate"));
|
|
201
|
+
assert.strictEqual(error.cause, cause);
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
describe("wrapErrorForBackwardCompatibility()", () => {
|
|
206
|
+
it("should return TaskOMaticError unchanged", () => {
|
|
207
|
+
const error = new TaskOMaticError("Test", {
|
|
208
|
+
code: TaskOMaticErrorCodes.UNEXPECTED_ERROR,
|
|
209
|
+
});
|
|
210
|
+
const wrapped = wrapErrorForBackwardCompatibility(error);
|
|
211
|
+
assert.strictEqual(wrapped, error);
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it("should return regular Error unchanged", () => {
|
|
215
|
+
const error = new Error("Regular error");
|
|
216
|
+
const wrapped = wrapErrorForBackwardCompatibility(error);
|
|
217
|
+
assert.strictEqual(wrapped, error);
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
it("should convert non-Error values to Error", () => {
|
|
221
|
+
const wrapped1 = wrapErrorForBackwardCompatibility("string error");
|
|
222
|
+
assert.ok(wrapped1 instanceof Error);
|
|
223
|
+
assert.ok(wrapped1.message.includes("string error"));
|
|
224
|
+
|
|
225
|
+
const wrapped2 = wrapErrorForBackwardCompatibility({
|
|
226
|
+
message: "object error",
|
|
227
|
+
});
|
|
228
|
+
assert.ok(wrapped2 instanceof Error);
|
|
229
|
+
assert.ok(wrapped2.message.includes("object error"));
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
describe("Error codes", () => {
|
|
234
|
+
it("should have defined error codes", () => {
|
|
235
|
+
assert.ok(TaskOMaticErrorCodes.UNEXPECTED_ERROR);
|
|
236
|
+
assert.ok(TaskOMaticErrorCodes.TASK_NOT_FOUND);
|
|
237
|
+
assert.ok(TaskOMaticErrorCodes.STORAGE_ERROR);
|
|
238
|
+
assert.ok(TaskOMaticErrorCodes.AI_OPERATION_FAILED);
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
});
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import assert from "assert";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
import { existsSync, mkdirSync, rmdirSync, writeFileSync } from "fs";
|
|
4
|
+
import { fileExists, validateFileExists, validateFileExistsAsync, fileExistsAsync, savePRDFile, saveStackFile, loadStackFile } from "../../utils/file-utils";
|
|
5
|
+
import { configManager } from "../../lib/config";
|
|
6
|
+
import { TaskOMaticErrorCodes } from "../../utils/task-o-matic-error";
|
|
7
|
+
|
|
8
|
+
describe("File Utilities", () => {
|
|
9
|
+
let testDir: string;
|
|
10
|
+
|
|
11
|
+
before(function () {
|
|
12
|
+
testDir = join(process.cwd(), "temp-test-file-utils");
|
|
13
|
+
if (!existsSync(testDir)) {
|
|
14
|
+
mkdirSync(testDir);
|
|
15
|
+
}
|
|
16
|
+
configManager.setWorkingDirectory(testDir);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
after(function () {
|
|
20
|
+
try {
|
|
21
|
+
if (existsSync(testDir)) {
|
|
22
|
+
rmdirSync(testDir, { recursive: true });
|
|
23
|
+
}
|
|
24
|
+
} catch (e) {
|
|
25
|
+
// Ignore cleanup errors
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
describe("Validation", () => {
|
|
30
|
+
it("validateFileExists should pass for existing file", () => {
|
|
31
|
+
const existingFile = join(testDir, "exist.txt");
|
|
32
|
+
writeFileSync(existingFile, "content");
|
|
33
|
+
assert.doesNotThrow(() => validateFileExists(existingFile));
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("validateFileExists should throw for missing file", () => {
|
|
37
|
+
const missingFile = join(testDir, "missing.txt");
|
|
38
|
+
assert.throws(() => validateFileExists(missingFile), (err: any) => {
|
|
39
|
+
return err.code === TaskOMaticErrorCodes.INVALID_INPUT;
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("validateFileExistsAsync should pass for existing file", async () => {
|
|
44
|
+
const existingFile = join(testDir, "exist-async.txt");
|
|
45
|
+
writeFileSync(existingFile, "content");
|
|
46
|
+
await validateFileExistsAsync(existingFile);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
describe("Existence Check", () => {
|
|
51
|
+
it("fileExists should return true for existing file", () => {
|
|
52
|
+
const existingFile = join(testDir, "exist-check.txt");
|
|
53
|
+
writeFileSync(existingFile, "content");
|
|
54
|
+
assert.strictEqual(fileExists(existingFile), true);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("fileExists should return false for missing file", () => {
|
|
58
|
+
const missingFile = join(testDir, "missing-check.txt");
|
|
59
|
+
assert.strictEqual(fileExists(missingFile), false);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
describe("PRD File", () => {
|
|
64
|
+
it("savePRDFile should save file to default location", () => {
|
|
65
|
+
const content = "# PRD Content";
|
|
66
|
+
const path = savePRDFile(content);
|
|
67
|
+
assert.ok(existsSync(path));
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
describe("Stack File", () => {
|
|
72
|
+
it("saveStackFile should save and load json", () => {
|
|
73
|
+
const data = { foo: "bar" };
|
|
74
|
+
const path = saveStackFile(data);
|
|
75
|
+
assert.ok(existsSync(path));
|
|
76
|
+
const loaded = loadStackFile<{ foo: string }>();
|
|
77
|
+
assert.deepStrictEqual(loaded, data);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import assert from "assert";
|
|
2
|
+
import { TaskIDGenerator } from "../../utils/id-generator";
|
|
3
|
+
import { TaskOMaticErrorCodes } from "../../utils/task-o-matic-error";
|
|
4
|
+
|
|
5
|
+
describe("TaskIDGenerator", () => {
|
|
6
|
+
describe("generate", () => {
|
|
7
|
+
it("should generate ID with default prefix", () => {
|
|
8
|
+
const id = TaskIDGenerator.generate();
|
|
9
|
+
assert.ok(id.startsWith("task-"));
|
|
10
|
+
assert.ok(TaskIDGenerator.validate(id));
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it("should generate ID with custom prefix", () => {
|
|
14
|
+
const id = TaskIDGenerator.generate("custom");
|
|
15
|
+
assert.ok(id.startsWith("custom-"));
|
|
16
|
+
assert.ok(TaskIDGenerator.validate(id));
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
describe("validate", () => {
|
|
21
|
+
it("should validate timestamped format", () => {
|
|
22
|
+
assert.strictEqual(TaskIDGenerator.validate("task-123456-abcdef12"), true);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("should validate hierarchical format", () => {
|
|
26
|
+
assert.strictEqual(TaskIDGenerator.validate("1.2.3"), true);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("should reject invalid format", () => {
|
|
30
|
+
assert.strictEqual(TaskIDGenerator.validate("invalid id"), false);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
describe("Hierarchical IDs", () => {
|
|
35
|
+
it("should generate child ID", () => {
|
|
36
|
+
assert.strictEqual(TaskIDGenerator.generateChildId("1", 1), "1.1");
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("should parse hierarchical ID", () => {
|
|
40
|
+
const result = TaskIDGenerator.parseHierarchicalId("1.2.3");
|
|
41
|
+
assert.deepStrictEqual(result, { parentId: "1.2", childIndex: 3 });
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
});
|