mcoda 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/.editorconfig +9 -0
- package/.eslintrc.cjs +12 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +29 -0
- package/.github/ISSUE_TEMPLATE/config.yml +5 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +19 -0
- package/.github/workflows/ci.yml +37 -0
- package/.github/workflows/nightly.yml +38 -0
- package/.github/workflows/release-dry-run.yml +40 -0
- package/.github/workflows/release-please.yml +22 -0
- package/.github/workflows/release.yml +149 -0
- package/.prettierrc +5 -0
- package/.release-please-manifest.json +8 -0
- package/CHANGELOG.md +7 -0
- package/CLA.md +42 -0
- package/CONTRIBUTING.md +38 -0
- package/LICENSE +21 -0
- package/README.md +314 -0
- package/docs/oss_publishing_plan.md +41 -0
- package/docs/pdr/.gitkeep +0 -0
- package/docs/quality_gates.md +32 -0
- package/docs/rfp/.gitkeep +0 -0
- package/docs/sds/sds.md +11963 -0
- package/docs/usage.md +72 -0
- package/openapi/gen-openapi.ts +1 -0
- package/openapi/generated/clients/.gitkeep +0 -0
- package/openapi/generated/types/.gitkeep +0 -0
- package/openapi/generated/types/index.ts +118 -0
- package/openapi/mcoda.yaml +2063 -0
- package/pack-mcoda.sh +88 -0
- package/package.json +46 -0
- package/packages/agents/CHANGELOG.md +7 -0
- package/packages/agents/LICENSE +21 -0
- package/packages/agents/README.md +9 -0
- package/packages/agents/package.json +41 -0
- package/packages/agents/src/AgentService/.gitkeep +0 -0
- package/packages/agents/src/AgentService/AgentService.d.ts +21 -0
- package/packages/agents/src/AgentService/AgentService.d.ts.map +1 -0
- package/packages/agents/src/AgentService/AgentService.js +141 -0
- package/packages/agents/src/AgentService/AgentService.ts +308 -0
- package/packages/agents/src/__tests__/AgentService.test.ts +284 -0
- package/packages/agents/src/adapters/AdapterTypes.d.ts +29 -0
- package/packages/agents/src/adapters/AdapterTypes.d.ts.map +1 -0
- package/packages/agents/src/adapters/AdapterTypes.js +1 -0
- package/packages/agents/src/adapters/AdapterTypes.ts +32 -0
- package/packages/agents/src/adapters/codex/.gitkeep +0 -0
- package/packages/agents/src/adapters/codex/CodexAdapter.d.ts +11 -0
- package/packages/agents/src/adapters/codex/CodexAdapter.d.ts.map +1 -0
- package/packages/agents/src/adapters/codex/CodexAdapter.js +43 -0
- package/packages/agents/src/adapters/codex/CodexAdapter.ts +63 -0
- package/packages/agents/src/adapters/codex/CodexCliRunner.ts +154 -0
- package/packages/agents/src/adapters/gemini/.gitkeep +0 -0
- package/packages/agents/src/adapters/gemini/GeminiAdapter.d.ts +11 -0
- package/packages/agents/src/adapters/gemini/GeminiAdapter.d.ts.map +1 -0
- package/packages/agents/src/adapters/gemini/GeminiAdapter.js +42 -0
- package/packages/agents/src/adapters/gemini/GeminiAdapter.ts +58 -0
- package/packages/agents/src/adapters/gemini/GeminiCliRunner.ts +75 -0
- package/packages/agents/src/adapters/local/.gitkeep +0 -0
- package/packages/agents/src/adapters/local/LocalAdapter.d.ts +11 -0
- package/packages/agents/src/adapters/local/LocalAdapter.d.ts.map +1 -0
- package/packages/agents/src/adapters/local/LocalAdapter.js +38 -0
- package/packages/agents/src/adapters/local/LocalAdapter.ts +43 -0
- package/packages/agents/src/adapters/ollama/OllamaCliAdapter.ts +58 -0
- package/packages/agents/src/adapters/ollama/OllamaCliRunner.ts +70 -0
- package/packages/agents/src/adapters/ollama/OllamaRemoteAdapter.ts +205 -0
- package/packages/agents/src/adapters/openai/.gitkeep +0 -0
- package/packages/agents/src/adapters/openai/OpenAiAdapter.d.ts +11 -0
- package/packages/agents/src/adapters/openai/OpenAiAdapter.d.ts.map +1 -0
- package/packages/agents/src/adapters/openai/OpenAiAdapter.js +51 -0
- package/packages/agents/src/adapters/openai/OpenAiAdapter.ts +56 -0
- package/packages/agents/src/adapters/openai/OpenAiCliAdapter.ts +62 -0
- package/packages/agents/src/adapters/qa/.gitkeep +0 -0
- package/packages/agents/src/adapters/qa/QaAdapter.d.ts +11 -0
- package/packages/agents/src/adapters/qa/QaAdapter.d.ts.map +1 -0
- package/packages/agents/src/adapters/qa/QaAdapter.js +37 -0
- package/packages/agents/src/adapters/qa/QaAdapter.ts +42 -0
- package/packages/agents/src/adapters/zhipu/ZhipuApiAdapter.ts +273 -0
- package/packages/agents/src/index.d.ts +8 -0
- package/packages/agents/src/index.d.ts.map +1 -0
- package/packages/agents/src/index.js +7 -0
- package/packages/agents/src/index.ts +11 -0
- package/packages/agents/tsconfig.json +14 -0
- package/packages/cli/CHANGELOG.md +7 -0
- package/packages/cli/LICENSE +21 -0
- package/packages/cli/README.md +23 -0
- package/packages/cli/package.json +61 -0
- package/packages/cli/src/__tests__/AgentsCommands.test.ts +137 -0
- package/packages/cli/src/__tests__/BacklogCommands.test.ts +40 -0
- package/packages/cli/src/__tests__/CodeReviewCommand.test.ts +594 -0
- package/packages/cli/src/__tests__/CreateTasksCommand.test.ts +40 -0
- package/packages/cli/src/__tests__/DocsCommands.test.ts +41 -0
- package/packages/cli/src/__tests__/EstimateCommands.test.ts +54 -0
- package/packages/cli/src/__tests__/JobsCommands.behavior.test.ts +311 -0
- package/packages/cli/src/__tests__/JobsCommands.test.ts +49 -0
- package/packages/cli/src/__tests__/MigrateTasksCommand.test.ts +36 -0
- package/packages/cli/src/__tests__/OpenapiCommands.test.ts +34 -0
- package/packages/cli/src/__tests__/OrderTasksCommand.test.ts +150 -0
- package/packages/cli/src/__tests__/PlanningCommands.test.ts +9 -0
- package/packages/cli/src/__tests__/QaTasksCommand.test.ts +58 -0
- package/packages/cli/src/__tests__/RefineTasksCommand.test.ts +63 -0
- package/packages/cli/src/__tests__/RoutingCommands.test.ts +302 -0
- package/packages/cli/src/__tests__/SetWorkspaceCommand.test.ts +18 -0
- package/packages/cli/src/__tests__/TaskShowCommands.test.ts +130 -0
- package/packages/cli/src/__tests__/TelemetryCommands.test.ts +35 -0
- package/packages/cli/src/__tests__/TestAgentCommand.test.ts +41 -0
- package/packages/cli/src/__tests__/UpdateCommands.test.ts +292 -0
- package/packages/cli/src/__tests__/WorkOnTasksCommand.test.ts +42 -0
- package/packages/cli/src/bin/.gitkeep +0 -0
- package/packages/cli/src/bin/McodaEntrypoint.ts +180 -0
- package/packages/cli/src/commands/agents/.gitkeep +0 -0
- package/packages/cli/src/commands/agents/AgentsCommands.ts +374 -0
- package/packages/cli/src/commands/agents/GatewayAgentCommand.ts +621 -0
- package/packages/cli/src/commands/agents/TestAgentCommand.ts +63 -0
- package/packages/cli/src/commands/backlog/.gitkeep +0 -0
- package/packages/cli/src/commands/backlog/BacklogCommands.ts +286 -0
- package/packages/cli/src/commands/backlog/OrderTasksCommand.ts +237 -0
- package/packages/cli/src/commands/backlog/TaskShowCommands.ts +289 -0
- package/packages/cli/src/commands/docs/.gitkeep +0 -0
- package/packages/cli/src/commands/docs/DocsCommands.ts +413 -0
- package/packages/cli/src/commands/estimate/EstimateCommands.ts +290 -0
- package/packages/cli/src/commands/jobs/.gitkeep +0 -0
- package/packages/cli/src/commands/jobs/JobsCommands.ts +595 -0
- package/packages/cli/src/commands/openapi/OpenapiCommands.ts +167 -0
- package/packages/cli/src/commands/planning/.gitkeep +0 -0
- package/packages/cli/src/commands/planning/CreateTasksCommand.ts +149 -0
- package/packages/cli/src/commands/planning/MigrateTasksCommand.ts +105 -0
- package/packages/cli/src/commands/planning/PlanningCommands.ts +1 -0
- package/packages/cli/src/commands/planning/QaTasksCommand.ts +320 -0
- package/packages/cli/src/commands/planning/RefineTasksCommand.ts +408 -0
- package/packages/cli/src/commands/review/CodeReviewCommand.ts +262 -0
- package/packages/cli/src/commands/routing/.gitkeep +0 -0
- package/packages/cli/src/commands/routing/RoutingCommands.ts +554 -0
- package/packages/cli/src/commands/telemetry/.gitkeep +0 -0
- package/packages/cli/src/commands/telemetry/TelemetryCommands.ts +348 -0
- package/packages/cli/src/commands/update/.gitkeep +0 -0
- package/packages/cli/src/commands/update/UpdateCommands.ts +301 -0
- package/packages/cli/src/commands/work/WorkOnTasksCommand.ts +264 -0
- package/packages/cli/src/commands/workspace/SetWorkspaceCommand.ts +132 -0
- package/packages/cli/src/index.ts +18 -0
- package/packages/cli/test/packaging_guardrails.test.js +75 -0
- package/packages/cli/tsconfig.json +20 -0
- package/packages/core/CHANGELOG.md +7 -0
- package/packages/core/LICENSE +21 -0
- package/packages/core/README.md +9 -0
- package/packages/core/package.json +45 -0
- package/packages/core/src/__tests__/SmokeClasses.test.ts +32 -0
- package/packages/core/src/api/AgentsApi.ts +219 -0
- package/packages/core/src/api/QaTasksApi.ts +38 -0
- package/packages/core/src/api/TasksApi.ts +35 -0
- package/packages/core/src/api/__tests__/AgentsApi.test.ts +203 -0
- package/packages/core/src/api/__tests__/QaTasksApi.test.ts +51 -0
- package/packages/core/src/api/__tests__/TasksApi.test.ts +56 -0
- package/packages/core/src/config/.gitkeep +0 -0
- package/packages/core/src/config/ConfigService.ts +1 -0
- package/packages/core/src/domain/dependencies/.gitkeep +0 -0
- package/packages/core/src/domain/dependencies/Dependency.ts +1 -0
- package/packages/core/src/domain/epics/.gitkeep +0 -0
- package/packages/core/src/domain/epics/Epic.ts +1 -0
- package/packages/core/src/domain/projects/.gitkeep +0 -0
- package/packages/core/src/domain/projects/Project.ts +1 -0
- package/packages/core/src/domain/tasks/.gitkeep +0 -0
- package/packages/core/src/domain/tasks/Task.ts +1 -0
- package/packages/core/src/domain/userStories/.gitkeep +0 -0
- package/packages/core/src/domain/userStories/UserStory.ts +1 -0
- package/packages/core/src/index.ts +27 -0
- package/packages/core/src/prompts/.gitkeep +0 -0
- package/packages/core/src/prompts/PdrPrompts.ts +23 -0
- package/packages/core/src/prompts/PromptLoader.ts +1 -0
- package/packages/core/src/prompts/SdsPrompts.ts +47 -0
- package/packages/core/src/services/agents/.gitkeep +0 -0
- package/packages/core/src/services/agents/AgentManagementService.ts +1 -0
- package/packages/core/src/services/agents/GatewayAgentService.ts +956 -0
- package/packages/core/src/services/agents/RoutingService.ts +461 -0
- package/packages/core/src/services/agents/__tests__/GatewayAgentService.test.ts +72 -0
- package/packages/core/src/services/agents/__tests__/RoutingService.test.ts +267 -0
- package/packages/core/src/services/agents/generated/RoutingApiClient.ts +89 -0
- package/packages/core/src/services/backlog/.gitkeep +0 -0
- package/packages/core/src/services/backlog/BacklogService.ts +580 -0
- package/packages/core/src/services/backlog/TaskOrderingService.ts +868 -0
- package/packages/core/src/services/backlog/__tests__/BacklogService.test.ts +219 -0
- package/packages/core/src/services/backlog/__tests__/TaskOrderingService.test.ts +268 -0
- package/packages/core/src/services/docs/.gitkeep +0 -0
- package/packages/core/src/services/docs/DocsService.ts +1913 -0
- package/packages/core/src/services/docs/__tests__/DocsService.test.ts +350 -0
- package/packages/core/src/services/estimate/EstimateService.ts +111 -0
- package/packages/core/src/services/estimate/VelocityService.ts +272 -0
- package/packages/core/src/services/estimate/__tests__/VelocityAndEstimate.test.ts +209 -0
- package/packages/core/src/services/estimate/types.ts +41 -0
- package/packages/core/src/services/execution/.gitkeep +0 -0
- package/packages/core/src/services/execution/ExecutionService.ts +1 -0
- package/packages/core/src/services/execution/QaFollowupService.ts +289 -0
- package/packages/core/src/services/execution/QaProfileService.ts +160 -0
- package/packages/core/src/services/execution/QaTasksService.ts +1303 -0
- package/packages/core/src/services/execution/TaskSelectionService.ts +362 -0
- package/packages/core/src/services/execution/TaskStateService.ts +64 -0
- package/packages/core/src/services/execution/WorkOnTasksService.ts +2023 -0
- package/packages/core/src/services/execution/__tests__/QaFollowupService.test.ts +58 -0
- package/packages/core/src/services/execution/__tests__/QaProfileService.test.ts +49 -0
- package/packages/core/src/services/execution/__tests__/QaTasksService.test.ts +157 -0
- package/packages/core/src/services/execution/__tests__/TaskSelectionService.test.ts +179 -0
- package/packages/core/src/services/execution/__tests__/TaskStateService.test.ts +51 -0
- package/packages/core/src/services/execution/__tests__/WorkOnTasksService.test.ts +285 -0
- package/packages/core/src/services/jobs/.gitkeep +0 -0
- package/packages/core/src/services/jobs/JobInsightsService.ts +355 -0
- package/packages/core/src/services/jobs/JobResumeService.ts +119 -0
- package/packages/core/src/services/jobs/JobService.ts +648 -0
- package/packages/core/src/services/jobs/JobsApiClient.ts +113 -0
- package/packages/core/src/services/jobs/__tests__/JobInsightsService.test.ts +17 -0
- package/packages/core/src/services/jobs/__tests__/JobResumeService.test.ts +45 -0
- package/packages/core/src/services/jobs/__tests__/JobService.test.ts +44 -0
- package/packages/core/src/services/openapi/OpenApiService.ts +558 -0
- package/packages/core/src/services/openapi/__tests__/OpenApiService.test.ts +57 -0
- package/packages/core/src/services/planning/.gitkeep +0 -0
- package/packages/core/src/services/planning/CreateTasksService.ts +1280 -0
- package/packages/core/src/services/planning/KeyHelpers.ts +80 -0
- package/packages/core/src/services/planning/PlanningService.ts +1 -0
- package/packages/core/src/services/planning/RefineTasksService.ts +1552 -0
- package/packages/core/src/services/planning/__tests__/CreateTasksService.test.ts +288 -0
- package/packages/core/src/services/planning/__tests__/KeyHelpers.test.ts +16 -0
- package/packages/core/src/services/planning/__tests__/RefineTasksService.test.ts +172 -0
- package/packages/core/src/services/review/CodeReviewService.ts +1386 -0
- package/packages/core/src/services/review/__tests__/CodeReviewService.test.ts +89 -0
- package/packages/core/src/services/system/SystemUpdateService.ts +177 -0
- package/packages/core/src/services/system/__tests__/SystemUpdateService.test.ts +40 -0
- package/packages/core/src/services/tasks/TaskApiResolver.ts +37 -0
- package/packages/core/src/services/tasks/TaskDetailService.ts +494 -0
- package/packages/core/src/services/tasks/__tests__/TaskApiResolver.test.ts +41 -0
- package/packages/core/src/services/tasks/__tests__/TaskDetailService.test.ts +178 -0
- package/packages/core/src/services/telemetry/.gitkeep +0 -0
- package/packages/core/src/services/telemetry/TelemetryService.ts +515 -0
- package/packages/core/src/services/telemetry/__tests__/TelemetryService.test.ts +160 -0
- package/packages/core/src/workspace/.gitkeep +0 -0
- package/packages/core/src/workspace/WorkspaceManager.ts +234 -0
- package/packages/core/tsconfig.json +20 -0
- package/packages/db/CHANGELOG.md +7 -0
- package/packages/db/LICENSE +21 -0
- package/packages/db/README.md +9 -0
- package/packages/db/package.json +42 -0
- package/packages/db/src/__tests__/GlobalRepository.test.ts +109 -0
- package/packages/db/src/__tests__/SchemaAlignment.test.ts +80 -0
- package/packages/db/src/__tests__/WorkspaceRepository.test.ts +19 -0
- package/packages/db/src/index.d.ts +6 -0
- package/packages/db/src/index.d.ts.map +1 -0
- package/packages/db/src/index.js +5 -0
- package/packages/db/src/index.ts +6 -0
- package/packages/db/src/migrations/global/.gitkeep +0 -0
- package/packages/db/src/migrations/global/GlobalMigrations.d.ts +9 -0
- package/packages/db/src/migrations/global/GlobalMigrations.d.ts.map +1 -0
- package/packages/db/src/migrations/global/GlobalMigrations.js +68 -0
- package/packages/db/src/migrations/global/GlobalMigrations.ts +336 -0
- package/packages/db/src/migrations/workspace/.gitkeep +0 -0
- package/packages/db/src/migrations/workspace/WorkspaceMigrations.d.ts +9 -0
- package/packages/db/src/migrations/workspace/WorkspaceMigrations.d.ts.map +1 -0
- package/packages/db/src/migrations/workspace/WorkspaceMigrations.js +251 -0
- package/packages/db/src/migrations/workspace/WorkspaceMigrations.ts +248 -0
- package/packages/db/src/repositories/global/.gitkeep +0 -0
- package/packages/db/src/repositories/global/GlobalRepository.d.ts +30 -0
- package/packages/db/src/repositories/global/GlobalRepository.d.ts.map +1 -0
- package/packages/db/src/repositories/global/GlobalRepository.js +209 -0
- package/packages/db/src/repositories/global/GlobalRepository.ts +492 -0
- package/packages/db/src/repositories/workspace/.gitkeep +0 -0
- package/packages/db/src/repositories/workspace/WorkspaceRepository.d.ts +282 -0
- package/packages/db/src/repositories/workspace/WorkspaceRepository.d.ts.map +1 -0
- package/packages/db/src/repositories/workspace/WorkspaceRepository.js +773 -0
- package/packages/db/src/repositories/workspace/WorkspaceRepository.ts +1511 -0
- package/packages/db/src/sqlite/connection.d.ts +11 -0
- package/packages/db/src/sqlite/connection.d.ts.map +1 -0
- package/packages/db/src/sqlite/connection.js +31 -0
- package/packages/db/src/sqlite/connection.ts +35 -0
- package/packages/db/src/sqlite/pragmas.d.ts +5 -0
- package/packages/db/src/sqlite/pragmas.d.ts.map +1 -0
- package/packages/db/src/sqlite/pragmas.js +6 -0
- package/packages/db/src/sqlite/pragmas.ts +10 -0
- package/packages/db/tsconfig.json +13 -0
- package/packages/generators/package.json +21 -0
- package/packages/generators/src/__tests__/Generators.test.ts +19 -0
- package/packages/generators/src/index.ts +1 -0
- package/packages/generators/src/openapi/generateTypes.ts +1 -0
- package/packages/generators/src/openapi/validateSchema.ts +1 -0
- package/packages/generators/src/scaffolding/docs/.gitkeep +0 -0
- package/packages/generators/src/scaffolding/docs/DocsScaffolder.ts +1 -0
- package/packages/generators/src/scaffolding/global/.gitkeep +0 -0
- package/packages/generators/src/scaffolding/global/GlobalScaffolder.ts +1 -0
- package/packages/generators/src/scaffolding/workspace/.gitkeep +0 -0
- package/packages/generators/src/scaffolding/workspace/WorkspaceScaffolder.ts +1 -0
- package/packages/generators/tsconfig.json +10 -0
- package/packages/integrations/CHANGELOG.md +7 -0
- package/packages/integrations/LICENSE +21 -0
- package/packages/integrations/README.md +9 -0
- package/packages/integrations/package.json +47 -0
- package/packages/integrations/src/docdex/.gitkeep +0 -0
- package/packages/integrations/src/docdex/DocdexClient.d.ts +50 -0
- package/packages/integrations/src/docdex/DocdexClient.d.ts.map +1 -0
- package/packages/integrations/src/docdex/DocdexClient.js +216 -0
- package/packages/integrations/src/docdex/DocdexClient.ts +261 -0
- package/packages/integrations/src/docdex/__tests__/DocdexClient.test.ts +29 -0
- package/packages/integrations/src/index.d.ts +2 -0
- package/packages/integrations/src/index.d.ts.map +1 -0
- package/packages/integrations/src/index.js +4 -0
- package/packages/integrations/src/index.ts +5 -0
- package/packages/integrations/src/issues/.gitkeep +0 -0
- package/packages/integrations/src/issues/IssuesClient.ts +1 -0
- package/packages/integrations/src/issues/__tests__/IssuesClient.test.ts +10 -0
- package/packages/integrations/src/qa/.gitkeep +0 -0
- package/packages/integrations/src/qa/ChromiumQaAdapter.ts +89 -0
- package/packages/integrations/src/qa/CliQaAdapter.ts +95 -0
- package/packages/integrations/src/qa/MaestroQaAdapter.ts +91 -0
- package/packages/integrations/src/qa/QaAdapter.ts +7 -0
- package/packages/integrations/src/qa/QaClient.ts +1 -0
- package/packages/integrations/src/qa/QaTypes.ts +26 -0
- package/packages/integrations/src/qa/__tests__/ChromiumQaAdapter.test.ts +30 -0
- package/packages/integrations/src/qa/__tests__/CliQaAdapter.test.ts +33 -0
- package/packages/integrations/src/qa/__tests__/MaestroQaAdapter.test.ts +30 -0
- package/packages/integrations/src/qa/index.ts +5 -0
- package/packages/integrations/src/system/SystemClient.ts +50 -0
- package/packages/integrations/src/system/__tests__/SystemClient.test.ts +40 -0
- package/packages/integrations/src/telemetry/TelemetryClient.ts +139 -0
- package/packages/integrations/src/telemetry/__tests__/TelemetryClient.test.ts +41 -0
- package/packages/integrations/src/vcs/.gitkeep +0 -0
- package/packages/integrations/src/vcs/VcsClient.ts +211 -0
- package/packages/integrations/src/vcs/__tests__/VcsClient.test.ts +26 -0
- package/packages/integrations/tsconfig.json +14 -0
- package/packages/shared/CHANGELOG.md +7 -0
- package/packages/shared/LICENSE +21 -0
- package/packages/shared/README.md +9 -0
- package/packages/shared/package.json +40 -0
- package/packages/shared/src/__tests__/CommandMetadata.test.ts +15 -0
- package/packages/shared/src/__tests__/ServiceShells.test.ts +16 -0
- package/packages/shared/src/crypto/.gitkeep +0 -0
- package/packages/shared/src/crypto/CryptoHelper.d.ts +15 -0
- package/packages/shared/src/crypto/CryptoHelper.d.ts.map +1 -0
- package/packages/shared/src/crypto/CryptoHelper.js +54 -0
- package/packages/shared/src/crypto/CryptoHelper.ts +57 -0
- package/packages/shared/src/errors/.gitkeep +0 -0
- package/packages/shared/src/errors/ErrorFactory.ts +1 -0
- package/packages/shared/src/index.d.ts +6 -0
- package/packages/shared/src/index.d.ts.map +1 -0
- package/packages/shared/src/index.js +4 -0
- package/packages/shared/src/index.ts +35 -0
- package/packages/shared/src/logging/.gitkeep +0 -0
- package/packages/shared/src/logging/Logger.ts +1 -0
- package/packages/shared/src/metadata/CommandMetadata.ts +165 -0
- package/packages/shared/src/openapi/.gitkeep +0 -0
- package/packages/shared/src/openapi/OpenApiTypes.d.ts +216 -0
- package/packages/shared/src/openapi/OpenApiTypes.d.ts.map +1 -0
- package/packages/shared/src/openapi/OpenApiTypes.js +1 -0
- package/packages/shared/src/openapi/OpenApiTypes.ts +312 -0
- package/packages/shared/src/paths/.gitkeep +0 -0
- package/packages/shared/src/paths/PathHelper.d.ts +12 -0
- package/packages/shared/src/paths/PathHelper.d.ts.map +1 -0
- package/packages/shared/src/paths/PathHelper.js +24 -0
- package/packages/shared/src/paths/PathHelper.ts +29 -0
- package/packages/shared/src/qa/QaProfile.ts +14 -0
- package/packages/shared/src/utils/.gitkeep +0 -0
- package/packages/shared/src/utils/UtilityService.ts +1 -0
- package/packages/shared/tsconfig.json +10 -0
- package/packages/testing/package.json +26 -0
- package/packages/testing/src/__tests__/TestingFakes.test.ts +15 -0
- package/packages/testing/src/cli/e2e/.gitkeep +0 -0
- package/packages/testing/src/cli/e2e/E2eSuite.ts +1 -0
- package/packages/testing/src/fakes/agents/.gitkeep +0 -0
- package/packages/testing/src/fakes/agents/FakeAgents.ts +1 -0
- package/packages/testing/src/fakes/docdex/.gitkeep +0 -0
- package/packages/testing/src/fakes/docdex/FakeDocdexClient.ts +1 -0
- package/packages/testing/src/fakes/qa/.gitkeep +0 -0
- package/packages/testing/src/fakes/qa/FakeQaClient.ts +1 -0
- package/packages/testing/src/fakes/vcs/.gitkeep +0 -0
- package/packages/testing/src/fakes/vcs/FakeVcsClient.ts +1 -0
- package/packages/testing/src/fixtures/db/.gitkeep +0 -0
- package/packages/testing/src/fixtures/db/DbFixtures.ts +1 -0
- package/packages/testing/src/fixtures/workspaces/.gitkeep +0 -0
- package/packages/testing/src/fixtures/workspaces/WorkspaceFixtures.ts +1 -0
- package/packages/testing/src/index.ts +1 -0
- package/packages/testing/tsconfig.json +10 -0
- package/pnpm-workspace.yaml +2 -0
- package/prompts/README.md +5 -0
- package/prompts/code-reviewer.md +23 -0
- package/prompts/code-writer.md +35 -0
- package/prompts/gateway-agent.md +27 -0
- package/prompts/qa-agent.md +21 -0
- package/release-please-config.json +39 -0
- package/scripts/build-all.ts +1 -0
- package/scripts/dev.ts +1 -0
- package/scripts/install-local-cli.sh +28 -0
- package/scripts/pack-npm-tarballs.js +63 -0
- package/scripts/release.ts +1 -0
- package/scripts/run-node-tests.js +37 -0
- package/tests/all.js +127 -0
- package/tests/api/openapi_spec.test.js +21 -0
- package/tests/artifacts.md +31 -0
- package/tests/component/cli_version.test.js +38 -0
- package/tests/integration/workspace_resolver.test.js +44 -0
- package/tests/unit/crypto_helper.test.js +36 -0
- package/tests/unit/path_helper.test.js +20 -0
- package/tsconfig.base.json +32 -0
|
@@ -0,0 +1,594 @@
|
|
|
1
|
+
import { describe, it, beforeEach, afterEach } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import fs from "node:fs/promises";
|
|
6
|
+
import { CodeReviewService } from "@mcoda/core";
|
|
7
|
+
import { CodeReviewCommand } from "../commands/review/CodeReviewCommand.js";
|
|
8
|
+
import { parseCodeReviewArgs } from "../commands/review/CodeReviewCommand.js";
|
|
9
|
+
|
|
10
|
+
class FakeAgentService {
|
|
11
|
+
constructor(private decision: string = "approve") {}
|
|
12
|
+
async resolveAgent() {
|
|
13
|
+
return { id: "agent-1", defaultModel: "stub" } as any;
|
|
14
|
+
}
|
|
15
|
+
async getCapabilities() {
|
|
16
|
+
return ["code_review"];
|
|
17
|
+
}
|
|
18
|
+
async invoke(_agentId: string, _req: any) {
|
|
19
|
+
return {
|
|
20
|
+
output: JSON.stringify({
|
|
21
|
+
decision: this.decision,
|
|
22
|
+
summary: "Looks good",
|
|
23
|
+
findings: [
|
|
24
|
+
{
|
|
25
|
+
type: "style",
|
|
26
|
+
severity: "low",
|
|
27
|
+
file: "src/demo.ts",
|
|
28
|
+
line: 10,
|
|
29
|
+
message: "Minor nit",
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
}),
|
|
33
|
+
model: "stub-model",
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
async invokeStream() {
|
|
37
|
+
throw new Error("stream not supported in fake");
|
|
38
|
+
}
|
|
39
|
+
async getPrompts() {
|
|
40
|
+
return { jobPrompt: "review", characterPrompt: "be concise", commandPrompts: { "code-review": "follow checklist" } };
|
|
41
|
+
}
|
|
42
|
+
async close() {}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
class FakeDocdex {
|
|
46
|
+
async search() {
|
|
47
|
+
return [];
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
class FakeRoutingService {
|
|
52
|
+
async resolveAgentForCommand() {
|
|
53
|
+
const agent = {
|
|
54
|
+
id: "agent-1",
|
|
55
|
+
slug: "agent-1",
|
|
56
|
+
adapter: "local-model",
|
|
57
|
+
defaultModel: "stub-model",
|
|
58
|
+
createdAt: new Date().toISOString(),
|
|
59
|
+
updatedAt: new Date().toISOString(),
|
|
60
|
+
};
|
|
61
|
+
return {
|
|
62
|
+
agent,
|
|
63
|
+
agentId: agent.id,
|
|
64
|
+
agentSlug: agent.slug,
|
|
65
|
+
model: agent.defaultModel,
|
|
66
|
+
capabilities: ["code_review"],
|
|
67
|
+
healthStatus: "healthy",
|
|
68
|
+
source: "workspace_default",
|
|
69
|
+
routingPreview: { workspaceId: "ws", commandName: "code-review", resolvedAgent: agent },
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
class FakeSelectionService {
|
|
75
|
+
lastFilters?: any;
|
|
76
|
+
constructor(private task: any) {}
|
|
77
|
+
async selectTasks(filters: any) {
|
|
78
|
+
this.lastFilters = filters;
|
|
79
|
+
return {
|
|
80
|
+
project: undefined,
|
|
81
|
+
filters,
|
|
82
|
+
ordered: [
|
|
83
|
+
{
|
|
84
|
+
task: this.task,
|
|
85
|
+
dependencies: { ids: [], keys: [], blocking: [] },
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
blocked: [],
|
|
89
|
+
warnings: [],
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
async close() {}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
class FakeStateService {
|
|
96
|
+
readyToQaCalled = false;
|
|
97
|
+
inProgressCalled = false;
|
|
98
|
+
blockedCalled = false;
|
|
99
|
+
async markReadyToQa() {
|
|
100
|
+
this.readyToQaCalled = true;
|
|
101
|
+
}
|
|
102
|
+
async returnToInProgress() {
|
|
103
|
+
this.inProgressCalled = true;
|
|
104
|
+
}
|
|
105
|
+
async markBlocked() {
|
|
106
|
+
this.blockedCalled = true;
|
|
107
|
+
}
|
|
108
|
+
async recordReviewMetadata() {}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
class FakeJobService {
|
|
112
|
+
createdJob?: any;
|
|
113
|
+
commandRun?: any;
|
|
114
|
+
checkpoints: any[] = [];
|
|
115
|
+
tokenUsage: any[] = [];
|
|
116
|
+
jobStatuses: any[] = [];
|
|
117
|
+
resumeJob?: any;
|
|
118
|
+
constructor(resumeJob?: any) {
|
|
119
|
+
this.resumeJob = resumeJob;
|
|
120
|
+
}
|
|
121
|
+
async startCommandRun() {
|
|
122
|
+
this.commandRun = { id: "cmd-1" };
|
|
123
|
+
return { ...this.commandRun };
|
|
124
|
+
}
|
|
125
|
+
async startJob(type: string, commandRunId?: string, _projectKey?: string, options: any = {}) {
|
|
126
|
+
this.createdJob = { id: "job-1", type, commandRunId, ...options };
|
|
127
|
+
return { id: "job-1", type };
|
|
128
|
+
}
|
|
129
|
+
async updateJobStatus(id: string, state: any, meta?: any) {
|
|
130
|
+
this.jobStatuses.push({ id, state, meta });
|
|
131
|
+
}
|
|
132
|
+
async finishCommandRun() {}
|
|
133
|
+
async writeCheckpoint(_jobId: string, ckpt: any) {
|
|
134
|
+
this.checkpoints.push(ckpt);
|
|
135
|
+
}
|
|
136
|
+
async recordTokenUsage(entry: any) {
|
|
137
|
+
this.tokenUsage.push(entry);
|
|
138
|
+
}
|
|
139
|
+
async getJob(id: string) {
|
|
140
|
+
if (this.resumeJob && this.resumeJob.id === id) return this.resumeJob;
|
|
141
|
+
return undefined;
|
|
142
|
+
}
|
|
143
|
+
async close() {}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
class FakeWorkspaceRepo {
|
|
147
|
+
comments: any[] = [];
|
|
148
|
+
reviews: any[] = [];
|
|
149
|
+
taskRuns: any[] = [];
|
|
150
|
+
logs: any[] = [];
|
|
151
|
+
epics: any[] = [];
|
|
152
|
+
stories: any[] = [];
|
|
153
|
+
constructor(public tasks: any[]) {
|
|
154
|
+
if (tasks.length) {
|
|
155
|
+
this.epics.push({ id: tasks[0].epicId, projectId: tasks[0].projectId, key: tasks[0].epicKey ?? "E1", title: "Epic", description: "" });
|
|
156
|
+
this.stories.push({
|
|
157
|
+
id: tasks[0].userStoryId,
|
|
158
|
+
epicId: tasks[0].epicId,
|
|
159
|
+
projectId: tasks[0].projectId,
|
|
160
|
+
key: tasks[0].storyKey ?? "S1",
|
|
161
|
+
title: "Story",
|
|
162
|
+
description: "",
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
async getTasksWithRelations(ids: string[]) {
|
|
167
|
+
return this.tasks.filter((t: any) => ids.includes(t.id));
|
|
168
|
+
}
|
|
169
|
+
async listTaskComments() {
|
|
170
|
+
return [];
|
|
171
|
+
}
|
|
172
|
+
async getLatestTaskReview() {
|
|
173
|
+
return undefined;
|
|
174
|
+
}
|
|
175
|
+
async getEpicByKey(_projectId: string, key: string) {
|
|
176
|
+
return this.epics.find((e) => e.key === key);
|
|
177
|
+
}
|
|
178
|
+
async getStoryByKey(epicId: string, key: string) {
|
|
179
|
+
return this.stories.find((s) => s.epicId === epicId && s.key === key);
|
|
180
|
+
}
|
|
181
|
+
async insertEpics(epics: any[]) {
|
|
182
|
+
const created = epics.map((e, idx) => ({
|
|
183
|
+
...e,
|
|
184
|
+
id: e.id ?? `epic-${this.epics.length + idx + 1}`,
|
|
185
|
+
createdAt: new Date().toISOString(),
|
|
186
|
+
updatedAt: new Date().toISOString(),
|
|
187
|
+
}));
|
|
188
|
+
this.epics.push(...created);
|
|
189
|
+
return created;
|
|
190
|
+
}
|
|
191
|
+
async insertStories(stories: any[]) {
|
|
192
|
+
const created = stories.map((s, idx) => ({
|
|
193
|
+
...s,
|
|
194
|
+
id: s.id ?? `story-${this.stories.length + idx + 1}`,
|
|
195
|
+
createdAt: new Date().toISOString(),
|
|
196
|
+
updatedAt: new Date().toISOString(),
|
|
197
|
+
}));
|
|
198
|
+
this.stories.push(...created);
|
|
199
|
+
return created;
|
|
200
|
+
}
|
|
201
|
+
async listTaskKeys(userStoryId: string) {
|
|
202
|
+
return this.tasks.filter((t: any) => t.userStoryId === userStoryId).map((t: any) => t.key);
|
|
203
|
+
}
|
|
204
|
+
async insertTasks(taskInserts: any[]) {
|
|
205
|
+
const created = taskInserts.map((t, idx) => ({
|
|
206
|
+
...t,
|
|
207
|
+
id: t.id ?? `task-${this.tasks.length + idx + 1}`,
|
|
208
|
+
createdAt: new Date().toISOString(),
|
|
209
|
+
updatedAt: new Date().toISOString(),
|
|
210
|
+
}));
|
|
211
|
+
this.tasks.push(...created);
|
|
212
|
+
return created;
|
|
213
|
+
}
|
|
214
|
+
async insertTaskLog(entry: any) {
|
|
215
|
+
this.logs.push(entry);
|
|
216
|
+
}
|
|
217
|
+
async createTaskRun(record: any) {
|
|
218
|
+
const run = { id: `run-${this.taskRuns.length + 1}`, ...record };
|
|
219
|
+
this.taskRuns.push(run);
|
|
220
|
+
return run;
|
|
221
|
+
}
|
|
222
|
+
async updateTaskRun() {}
|
|
223
|
+
async createTaskComment(input: any) {
|
|
224
|
+
this.comments.push(input);
|
|
225
|
+
return { id: `c-${this.comments.length}`, ...input };
|
|
226
|
+
}
|
|
227
|
+
async createTaskReview(input: any) {
|
|
228
|
+
this.reviews.push(input);
|
|
229
|
+
return { id: `r-${this.reviews.length}`, ...input };
|
|
230
|
+
}
|
|
231
|
+
async updateTask() {}
|
|
232
|
+
async close() {}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
class FakeVcs {
|
|
236
|
+
async ensureRepo() {}
|
|
237
|
+
async diff() {
|
|
238
|
+
return "diff --git a/src/demo.ts b/src/demo.ts\n+console.log('hi');";
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
class FakeGlobalRepo {
|
|
243
|
+
async getWorkspaceDefaults() {
|
|
244
|
+
return [];
|
|
245
|
+
}
|
|
246
|
+
async close() {}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const makeWorkspace = async () => {
|
|
250
|
+
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "mcoda-review-"));
|
|
251
|
+
return {
|
|
252
|
+
workspaceRoot: dir,
|
|
253
|
+
workspaceId: dir,
|
|
254
|
+
mcodaDir: path.join(dir, ".mcoda"),
|
|
255
|
+
};
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
describe("code-review argument parsing", () => {
|
|
259
|
+
it("defaults status to ready_to_review and agent streaming on", () => {
|
|
260
|
+
const parsed = parseCodeReviewArgs([]);
|
|
261
|
+
assert.deepEqual(parsed.statusFilter, ["ready_to_review"]);
|
|
262
|
+
assert.equal(parsed.agentStream, true);
|
|
263
|
+
assert.equal(parsed.dryRun, false);
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
it("parses filters, resume and agent stream override", () => {
|
|
267
|
+
const parsed = parseCodeReviewArgs([
|
|
268
|
+
"--workspace-root",
|
|
269
|
+
"/tmp/demo",
|
|
270
|
+
"--project",
|
|
271
|
+
"P1",
|
|
272
|
+
"--epic",
|
|
273
|
+
"E1",
|
|
274
|
+
"--story",
|
|
275
|
+
"S1",
|
|
276
|
+
"--task=TASK-1",
|
|
277
|
+
"--status",
|
|
278
|
+
"blocked,ready_to_review",
|
|
279
|
+
"--base",
|
|
280
|
+
"main",
|
|
281
|
+
"--resume",
|
|
282
|
+
"job-1",
|
|
283
|
+
"--agent-stream=false",
|
|
284
|
+
"--json",
|
|
285
|
+
]);
|
|
286
|
+
assert.equal(parsed.workspaceRoot, path.resolve("/tmp/demo"));
|
|
287
|
+
assert.equal(parsed.projectKey, "P1");
|
|
288
|
+
assert.equal(parsed.epicKey, "E1");
|
|
289
|
+
assert.equal(parsed.storyKey, "S1");
|
|
290
|
+
assert.equal(parsed.resumeJobId, "job-1");
|
|
291
|
+
assert.equal(parsed.agentStream, false);
|
|
292
|
+
assert.equal(parsed.baseRef, "main");
|
|
293
|
+
assert.equal(parsed.json, true);
|
|
294
|
+
assert.deepEqual(parsed.taskKeys, ["TASK-1"]);
|
|
295
|
+
assert.deepEqual(parsed.statusFilter, ["blocked", "ready_to_review"]);
|
|
296
|
+
});
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
describe("code-review service flow", () => {
|
|
300
|
+
let workspace: any;
|
|
301
|
+
let task: any;
|
|
302
|
+
let fakeSelection: FakeSelectionService;
|
|
303
|
+
let fakeWorkspaceRepo: FakeWorkspaceRepo;
|
|
304
|
+
let fakeJobService: FakeJobService;
|
|
305
|
+
let fakeStateService: FakeStateService;
|
|
306
|
+
|
|
307
|
+
beforeEach(async () => {
|
|
308
|
+
workspace = await makeWorkspace();
|
|
309
|
+
task = {
|
|
310
|
+
id: "task-1",
|
|
311
|
+
projectId: "proj-1",
|
|
312
|
+
epicId: "epic-1",
|
|
313
|
+
userStoryId: "story-1",
|
|
314
|
+
key: "TASK-1",
|
|
315
|
+
title: "Review demo",
|
|
316
|
+
description: "",
|
|
317
|
+
type: "feature",
|
|
318
|
+
status: "ready_to_review",
|
|
319
|
+
storyPoints: 3,
|
|
320
|
+
priority: 1,
|
|
321
|
+
assignedAgentId: null,
|
|
322
|
+
assigneeHuman: null,
|
|
323
|
+
vcsBranch: "mcoda/task/TASK-1",
|
|
324
|
+
vcsBaseBranch: "mcoda-dev",
|
|
325
|
+
vcsLastCommitSha: null,
|
|
326
|
+
metadata: { files: ["src/demo.ts"] },
|
|
327
|
+
openapiVersionAtCreation: null,
|
|
328
|
+
createdAt: new Date().toISOString(),
|
|
329
|
+
updatedAt: new Date().toISOString(),
|
|
330
|
+
epicKey: "E1",
|
|
331
|
+
storyKey: "S1",
|
|
332
|
+
};
|
|
333
|
+
fakeSelection = new FakeSelectionService(task);
|
|
334
|
+
fakeWorkspaceRepo = new FakeWorkspaceRepo([task]);
|
|
335
|
+
fakeJobService = new FakeJobService();
|
|
336
|
+
fakeStateService = new FakeStateService();
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
afterEach(async () => {
|
|
340
|
+
if (workspace?.workspaceRoot) {
|
|
341
|
+
await fs.rm(workspace.workspaceRoot, { recursive: true, force: true });
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
it("creates a review job, writes comments/reviews, and records token usage", async () => {
|
|
346
|
+
const service = new CodeReviewService(workspace, {
|
|
347
|
+
agentService: new FakeAgentService() as any,
|
|
348
|
+
docdex: new FakeDocdex() as any,
|
|
349
|
+
jobService: fakeJobService as any,
|
|
350
|
+
workspaceRepo: fakeWorkspaceRepo as any,
|
|
351
|
+
selectionService: fakeSelection as any,
|
|
352
|
+
stateService: fakeStateService as any,
|
|
353
|
+
repo: new FakeGlobalRepo() as any,
|
|
354
|
+
vcsClient: new FakeVcs() as any,
|
|
355
|
+
routingService: new FakeRoutingService() as any,
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
const result = await service.reviewTasks({
|
|
359
|
+
workspace,
|
|
360
|
+
projectKey: "P1",
|
|
361
|
+
statusFilter: ["ready_to_review"],
|
|
362
|
+
taskKeys: ["TASK-1"],
|
|
363
|
+
agentStream: false,
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
assert.equal(result.jobId, "job-1");
|
|
367
|
+
assert.equal(fakeJobService.createdJob?.type, "review");
|
|
368
|
+
assert.equal(fakeWorkspaceRepo.comments.length, 2);
|
|
369
|
+
assert.equal(fakeWorkspaceRepo.reviews.length, 1);
|
|
370
|
+
assert.equal(fakeStateService.readyToQaCalled, true);
|
|
371
|
+
assert.equal(fakeJobService.tokenUsage.length, 1);
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
it("handles changes_requested decision without throwing", async () => {
|
|
375
|
+
const service = new CodeReviewService(workspace, {
|
|
376
|
+
agentService: new FakeAgentService("changes_requested") as any,
|
|
377
|
+
docdex: new FakeDocdex() as any,
|
|
378
|
+
jobService: fakeJobService as any,
|
|
379
|
+
workspaceRepo: fakeWorkspaceRepo as any,
|
|
380
|
+
selectionService: fakeSelection as any,
|
|
381
|
+
stateService: fakeStateService as any,
|
|
382
|
+
repo: new FakeGlobalRepo() as any,
|
|
383
|
+
vcsClient: new FakeVcs() as any,
|
|
384
|
+
routingService: new FakeRoutingService() as any,
|
|
385
|
+
});
|
|
386
|
+
const result = await service.reviewTasks({
|
|
387
|
+
workspace,
|
|
388
|
+
projectKey: "P1",
|
|
389
|
+
statusFilter: ["ready_to_review"],
|
|
390
|
+
taskKeys: ["TASK-1"],
|
|
391
|
+
});
|
|
392
|
+
assert.equal(result.tasks.length, 1);
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
it("creates follow-up tasks for actionable findings and uses generic containers when needed", async () => {
|
|
396
|
+
const agent = new FakeAgentService("changes_requested") as any;
|
|
397
|
+
agent.invoke = async () => ({
|
|
398
|
+
output: JSON.stringify({
|
|
399
|
+
decision: "changes_requested",
|
|
400
|
+
summary: "Needs fixes",
|
|
401
|
+
findings: [
|
|
402
|
+
{
|
|
403
|
+
type: "bug",
|
|
404
|
+
severity: "high",
|
|
405
|
+
message: "Fix this issue",
|
|
406
|
+
},
|
|
407
|
+
],
|
|
408
|
+
}),
|
|
409
|
+
model: "stub-model",
|
|
410
|
+
});
|
|
411
|
+
const service = new CodeReviewService(workspace, {
|
|
412
|
+
agentService: agent,
|
|
413
|
+
docdex: new FakeDocdex() as any,
|
|
414
|
+
jobService: fakeJobService as any,
|
|
415
|
+
workspaceRepo: fakeWorkspaceRepo as any,
|
|
416
|
+
selectionService: fakeSelection as any,
|
|
417
|
+
stateService: fakeStateService as any,
|
|
418
|
+
repo: new FakeGlobalRepo() as any,
|
|
419
|
+
vcsClient: new FakeVcs() as any,
|
|
420
|
+
routingService: new FakeRoutingService() as any,
|
|
421
|
+
});
|
|
422
|
+
const result = await service.reviewTasks({
|
|
423
|
+
workspace,
|
|
424
|
+
projectKey: "P1",
|
|
425
|
+
statusFilter: ["ready_to_review"],
|
|
426
|
+
taskKeys: ["TASK-1"],
|
|
427
|
+
agentStream: false,
|
|
428
|
+
});
|
|
429
|
+
const followups = result.tasks[0].followupTasks ?? [];
|
|
430
|
+
assert.ok(followups.length >= 1);
|
|
431
|
+
assert.ok(fakeWorkspaceRepo.tasks.length > 1);
|
|
432
|
+
assert.ok(fakeWorkspaceRepo.epics.find((e: any) => e.key === "epic-bugs" || e.key === "epic-issues"));
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
it("does not create follow-up tasks for approved low/info findings", async () => {
|
|
436
|
+
const agent = new FakeAgentService("approve") as any;
|
|
437
|
+
agent.invoke = async () => ({
|
|
438
|
+
output: JSON.stringify({
|
|
439
|
+
decision: "approve",
|
|
440
|
+
summary: "Fine",
|
|
441
|
+
findings: [
|
|
442
|
+
{
|
|
443
|
+
type: "style",
|
|
444
|
+
severity: "low",
|
|
445
|
+
message: "Nit only",
|
|
446
|
+
},
|
|
447
|
+
{
|
|
448
|
+
type: "docs",
|
|
449
|
+
severity: "info",
|
|
450
|
+
message: "Note",
|
|
451
|
+
},
|
|
452
|
+
],
|
|
453
|
+
}),
|
|
454
|
+
model: "stub-model",
|
|
455
|
+
});
|
|
456
|
+
const service = new CodeReviewService(workspace, {
|
|
457
|
+
agentService: agent,
|
|
458
|
+
docdex: new FakeDocdex() as any,
|
|
459
|
+
jobService: fakeJobService as any,
|
|
460
|
+
workspaceRepo: fakeWorkspaceRepo as any,
|
|
461
|
+
selectionService: fakeSelection as any,
|
|
462
|
+
stateService: fakeStateService as any,
|
|
463
|
+
repo: new FakeGlobalRepo() as any,
|
|
464
|
+
vcsClient: new FakeVcs() as any,
|
|
465
|
+
routingService: new FakeRoutingService() as any,
|
|
466
|
+
});
|
|
467
|
+
const beforeCount = fakeWorkspaceRepo.tasks.length;
|
|
468
|
+
const result = await service.reviewTasks({
|
|
469
|
+
workspace,
|
|
470
|
+
projectKey: "P1",
|
|
471
|
+
statusFilter: ["ready_to_review"],
|
|
472
|
+
taskKeys: ["TASK-1"],
|
|
473
|
+
agentStream: false,
|
|
474
|
+
});
|
|
475
|
+
const afterCount = fakeWorkspaceRepo.tasks.length;
|
|
476
|
+
assert.equal(afterCount, beforeCount);
|
|
477
|
+
assert.equal(result.tasks[0].followupTasks?.length ?? 0, 0);
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
it("respects limit and records job payload", async () => {
|
|
481
|
+
const service = new CodeReviewService(workspace, {
|
|
482
|
+
agentService: new FakeAgentService() as any,
|
|
483
|
+
docdex: new FakeDocdex() as any,
|
|
484
|
+
jobService: fakeJobService as any,
|
|
485
|
+
workspaceRepo: fakeWorkspaceRepo as any,
|
|
486
|
+
selectionService: fakeSelection as any,
|
|
487
|
+
stateService: fakeStateService as any,
|
|
488
|
+
repo: new FakeGlobalRepo() as any,
|
|
489
|
+
vcsClient: new FakeVcs() as any,
|
|
490
|
+
routingService: new FakeRoutingService() as any,
|
|
491
|
+
});
|
|
492
|
+
await service.reviewTasks({
|
|
493
|
+
workspace,
|
|
494
|
+
projectKey: "P1",
|
|
495
|
+
statusFilter: ["ready_to_review"],
|
|
496
|
+
taskKeys: ["TASK-1"],
|
|
497
|
+
limit: 1,
|
|
498
|
+
});
|
|
499
|
+
assert.equal(fakeJobService.createdJob?.payload?.selection.length, 1);
|
|
500
|
+
assert.equal(fakeSelection.lastFilters?.limit, 1);
|
|
501
|
+
assert.ok(fakeJobService.checkpoints.find((c) => c.stage === "tasks_selected"));
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
it("supports resume using persisted selection", async () => {
|
|
505
|
+
const resumeJob = { id: "job-1", commandName: "code-review", type: "review", payload: { selection: [task.id] }, totalItems: 1 };
|
|
506
|
+
fakeJobService = new FakeJobService(resumeJob);
|
|
507
|
+
fakeWorkspaceRepo = new FakeWorkspaceRepo([task]);
|
|
508
|
+
await fs.mkdir(path.join(workspace.workspaceRoot, ".mcoda", "jobs", "job-1", "review"), { recursive: true });
|
|
509
|
+
await fs.writeFile(
|
|
510
|
+
path.join(workspace.workspaceRoot, ".mcoda", "jobs", "job-1", "review", "state.json"),
|
|
511
|
+
JSON.stringify({ schema_version: 1, job_id: "job-1", selectedTaskIds: [task.id], contextBuilt: [], reviewed: [] }, null, 2),
|
|
512
|
+
"utf8",
|
|
513
|
+
);
|
|
514
|
+
const service = new CodeReviewService(workspace, {
|
|
515
|
+
agentService: new FakeAgentService() as any,
|
|
516
|
+
docdex: new FakeDocdex() as any,
|
|
517
|
+
jobService: fakeJobService as any,
|
|
518
|
+
workspaceRepo: fakeWorkspaceRepo as any,
|
|
519
|
+
selectionService: fakeSelection as any,
|
|
520
|
+
stateService: fakeStateService as any,
|
|
521
|
+
repo: new FakeGlobalRepo() as any,
|
|
522
|
+
vcsClient: new FakeVcs() as any,
|
|
523
|
+
routingService: new FakeRoutingService() as any,
|
|
524
|
+
});
|
|
525
|
+
const result = await service.reviewTasks({
|
|
526
|
+
workspace,
|
|
527
|
+
projectKey: "P1",
|
|
528
|
+
statusFilter: ["ready_to_review"],
|
|
529
|
+
resumeJobId: "job-1",
|
|
530
|
+
});
|
|
531
|
+
assert.equal(result.jobId, "job-1");
|
|
532
|
+
assert.equal(fakeJobService.jobStatuses.length > 0, true);
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
it("passes default status filter to selection service", async () => {
|
|
536
|
+
const service = new CodeReviewService(workspace, {
|
|
537
|
+
agentService: new FakeAgentService() as any,
|
|
538
|
+
docdex: new FakeDocdex() as any,
|
|
539
|
+
jobService: fakeJobService as any,
|
|
540
|
+
workspaceRepo: fakeWorkspaceRepo as any,
|
|
541
|
+
selectionService: fakeSelection as any,
|
|
542
|
+
stateService: fakeStateService as any,
|
|
543
|
+
repo: new FakeGlobalRepo() as any,
|
|
544
|
+
vcsClient: new FakeVcs() as any,
|
|
545
|
+
routingService: new FakeRoutingService() as any,
|
|
546
|
+
});
|
|
547
|
+
|
|
548
|
+
await service.reviewTasks({
|
|
549
|
+
workspace,
|
|
550
|
+
projectKey: "P1",
|
|
551
|
+
taskKeys: ["TASK-1"],
|
|
552
|
+
});
|
|
553
|
+
|
|
554
|
+
assert.ok(fakeSelection.lastFilters);
|
|
555
|
+
assert.deepEqual(fakeSelection.lastFilters.statusFilter, ["ready_to_review"]);
|
|
556
|
+
});
|
|
557
|
+
});
|
|
558
|
+
|
|
559
|
+
describe("code-review CLI output shape", () => {
|
|
560
|
+
it("emits structured JSON output", async () => {
|
|
561
|
+
const originalCreate = CodeReviewService.create;
|
|
562
|
+
const fakeResult = {
|
|
563
|
+
jobId: "job-123",
|
|
564
|
+
commandRunId: "cmd-123",
|
|
565
|
+
tasks: [
|
|
566
|
+
{
|
|
567
|
+
taskId: "t1",
|
|
568
|
+
taskKey: "TASK-1",
|
|
569
|
+
decision: "approve",
|
|
570
|
+
statusBefore: "ready_to_review",
|
|
571
|
+
statusAfter: "ready_to_qa",
|
|
572
|
+
findings: [],
|
|
573
|
+
},
|
|
574
|
+
],
|
|
575
|
+
warnings: [],
|
|
576
|
+
};
|
|
577
|
+
// @ts-expect-error override for test
|
|
578
|
+
CodeReviewService.create = async () => ({
|
|
579
|
+
reviewTasks: async () => fakeResult,
|
|
580
|
+
close: async () => {},
|
|
581
|
+
});
|
|
582
|
+
const logs: string[] = [];
|
|
583
|
+
const originalLog = console.log;
|
|
584
|
+
console.log = (msg?: any) => {
|
|
585
|
+
logs.push(String(msg));
|
|
586
|
+
};
|
|
587
|
+
await CodeReviewCommand.run(["--project", "P1", "--json"]);
|
|
588
|
+
console.log = originalLog;
|
|
589
|
+
CodeReviewService.create = originalCreate;
|
|
590
|
+
const parsed = JSON.parse(logs[0]);
|
|
591
|
+
assert.deepEqual(parsed.job, { id: "job-123", commandRunId: "cmd-123" });
|
|
592
|
+
assert.equal(parsed.tasks[0].taskKey, "TASK-1");
|
|
593
|
+
});
|
|
594
|
+
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { describe, it } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { parseCreateTasksArgs } from "../commands/planning/CreateTasksCommand.js";
|
|
5
|
+
|
|
6
|
+
describe("create-tasks argument parsing", () => {
|
|
7
|
+
it("defaults agent stream to true and captures inputs", () => {
|
|
8
|
+
const parsed = parseCreateTasksArgs(["Feature", "More", "--quiet"]);
|
|
9
|
+
assert.equal(parsed.agentStream, true);
|
|
10
|
+
assert.equal(parsed.quiet, true);
|
|
11
|
+
assert.deepEqual(parsed.inputs, ["Feature", "More"]);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("parses numeric limits and agent options", () => {
|
|
15
|
+
const root = path.resolve("/tmp/workspace");
|
|
16
|
+
const parsed = parseCreateTasksArgs([
|
|
17
|
+
"--workspace-root",
|
|
18
|
+
root,
|
|
19
|
+
"--project-key",
|
|
20
|
+
"proj",
|
|
21
|
+
"--agent",
|
|
22
|
+
"planner",
|
|
23
|
+
"--agent-stream",
|
|
24
|
+
"false",
|
|
25
|
+
"--max-epics",
|
|
26
|
+
"2",
|
|
27
|
+
"--max-stories-per-epic",
|
|
28
|
+
"3",
|
|
29
|
+
"--max-tasks-per-story",
|
|
30
|
+
"4",
|
|
31
|
+
]);
|
|
32
|
+
assert.equal(parsed.workspaceRoot, root);
|
|
33
|
+
assert.equal(parsed.projectKey, "proj");
|
|
34
|
+
assert.equal(parsed.agentName, "planner");
|
|
35
|
+
assert.equal(parsed.agentStream, false);
|
|
36
|
+
assert.equal(parsed.maxEpics, 2);
|
|
37
|
+
assert.equal(parsed.maxStoriesPerEpic, 3);
|
|
38
|
+
assert.equal(parsed.maxTasksPerStory, 4);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { describe, it } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { parsePdrArgs, parseSdsArgs } from "../commands/docs/DocsCommands.js";
|
|
5
|
+
|
|
6
|
+
describe("docs pdr argument parsing", () => {
|
|
7
|
+
it("defaults agentStream to true", () => {
|
|
8
|
+
const parsed = parsePdrArgs(["--rfp-path", "/tmp/rfp.md"]);
|
|
9
|
+
assert.equal(parsed.agentStream, true);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it("parses agentStream false", () => {
|
|
13
|
+
const parsed = parsePdrArgs(["--rfp-path", "/tmp/rfp.md", "--agent-stream", "false"]);
|
|
14
|
+
assert.equal(parsed.agentStream, false);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it("captures workspace root when provided", () => {
|
|
18
|
+
const root = path.resolve("/tmp/my-workspace");
|
|
19
|
+
const parsed = parsePdrArgs(["--rfp-path", "docs/rfp.md", "--workspace-root", root]);
|
|
20
|
+
assert.equal(parsed.workspaceRoot, root);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("parses json and dry-run flags", () => {
|
|
24
|
+
const parsed = parsePdrArgs(["--rfp-path", "/tmp/rfp.md", "--json", "--dry-run"]);
|
|
25
|
+
assert.equal(parsed.json, true);
|
|
26
|
+
assert.equal(parsed.dryRun, true);
|
|
27
|
+
assert.equal(parsed.debug, false);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("parses sds defaults and flags", () => {
|
|
31
|
+
const parsed = parseSdsArgs(["--project", "SDS", "--agent-stream", "false", "--force", "--resume", "job-1"]);
|
|
32
|
+
assert.equal(parsed.agentStream, false);
|
|
33
|
+
assert.equal(parsed.force, true);
|
|
34
|
+
assert.equal(parsed.resumeJobId, "job-1");
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("defaults sds agentStream to true", () => {
|
|
38
|
+
const parsed = parseSdsArgs(["--project", "SDS"]);
|
|
39
|
+
assert.equal(parsed.agentStream, true);
|
|
40
|
+
});
|
|
41
|
+
});
|