prjct-cli 1.22.0 → 1.23.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/CHANGELOG.md +147 -0
- package/bin/prjct +30 -13
- package/dist/bin/prjct.mjs +917 -35845
- package/dist/bin/prjct.mjs.map +7 -0
- package/dist/cli/linear.mjs +16 -0
- package/dist/cli/linear.mjs.map +7 -0
- package/dist/templates.json +1 -0
- package/package.json +4 -5
- package/bin/prjct.ts +0 -342
- package/core/__tests__/agentic/analysis-injection.test.ts +0 -377
- package/core/__tests__/agentic/cache-eviction.test.ts +0 -294
- package/core/__tests__/agentic/command-context.test.ts +0 -281
- package/core/__tests__/agentic/command-executor.test.ts +0 -659
- package/core/__tests__/agentic/domain-classifier.test.ts +0 -330
- package/core/__tests__/agentic/injection-validator.test.ts +0 -255
- package/core/__tests__/agentic/memory-system.test.ts +0 -281
- package/core/__tests__/agentic/plan-mode.test.ts +0 -386
- package/core/__tests__/agentic/prompt-assembly.test.ts +0 -298
- package/core/__tests__/agentic/prompt-builder.test.ts +0 -243
- package/core/__tests__/agentic/response-validator.test.ts +0 -263
- package/core/__tests__/agentic/semantic-matching.test.ts +0 -131
- package/core/__tests__/agentic/smart-context.test.ts +0 -372
- package/core/__tests__/agentic/tech-normalizer.test.ts +0 -136
- package/core/__tests__/agentic/token-budget.test.ts +0 -294
- package/core/__tests__/ai-tools/formatters.test.ts +0 -476
- package/core/__tests__/domain/bm25.test.ts +0 -225
- package/core/__tests__/domain/change-propagator.test.ts +0 -100
- package/core/__tests__/domain/fibonacci.test.ts +0 -113
- package/core/__tests__/domain/file-hasher.test.ts +0 -146
- package/core/__tests__/domain/file-ranker.test.ts +0 -169
- package/core/__tests__/domain/git-cochange.test.ts +0 -121
- package/core/__tests__/domain/import-graph.test.ts +0 -156
- package/core/__tests__/domain/velocity.test.ts +0 -623
- package/core/__tests__/infrastructure/performance-tracker.test.ts +0 -328
- package/core/__tests__/schemas/model.test.ts +0 -272
- package/core/__tests__/services/dependency-validator.test.ts +0 -175
- package/core/__tests__/services/hierarchical-agent-resolver.test.ts +0 -359
- package/core/__tests__/services/nested-context-resolver.test.ts +0 -443
- package/core/__tests__/services/project-index.test.ts +0 -355
- package/core/__tests__/services/staleness-checker.test.ts +0 -204
- package/core/__tests__/storage/analysis-storage.test.ts +0 -641
- package/core/__tests__/storage/archive-storage.test.ts +0 -455
- package/core/__tests__/storage/safe-reader.test.ts +0 -262
- package/core/__tests__/storage/sqlite-migration.test.ts +0 -1016
- package/core/__tests__/storage/state-storage-feedback.test.ts +0 -463
- package/core/__tests__/storage/state-storage-history.test.ts +0 -469
- package/core/__tests__/storage/storage-manager.test.ts +0 -383
- package/core/__tests__/storage/subtask-handoff.test.ts +0 -237
- package/core/__tests__/types/fs.test.ts +0 -125
- package/core/__tests__/utils/date-helper.test.ts +0 -449
- package/core/__tests__/utils/output.test.ts +0 -278
- package/core/__tests__/utils/preserve-sections.test.ts +0 -216
- package/core/__tests__/utils/project-commands.test.ts +0 -71
- package/core/__tests__/utils/retry.test.ts +0 -381
- package/core/__tests__/workflow/state-machine.test.ts +0 -216
- package/core/agentic/agent-router.ts +0 -150
- package/core/agentic/anti-hallucination.ts +0 -141
- package/core/agentic/chain-of-thought.ts +0 -234
- package/core/agentic/command-classifier.ts +0 -141
- package/core/agentic/command-context.ts +0 -168
- package/core/agentic/command-executor.ts +0 -471
- package/core/agentic/context-builder.ts +0 -285
- package/core/agentic/domain-classifier.ts +0 -525
- package/core/agentic/environment-block.ts +0 -102
- package/core/agentic/ground-truth.ts +0 -706
- package/core/agentic/index.ts +0 -193
- package/core/agentic/injection-validator.ts +0 -208
- package/core/agentic/loop-detector.ts +0 -451
- package/core/agentic/memory-system.ts +0 -1547
- package/core/agentic/orchestrator-executor.ts +0 -579
- package/core/agentic/plan-mode.ts +0 -525
- package/core/agentic/prompt-builder.ts +0 -1069
- package/core/agentic/response-validator.ts +0 -98
- package/core/agentic/services.ts +0 -167
- package/core/agentic/skill-loader.ts +0 -106
- package/core/agentic/smart-context.ts +0 -393
- package/core/agentic/tech-normalizer.ts +0 -167
- package/core/agentic/template-executor.ts +0 -272
- package/core/agentic/template-loader.ts +0 -109
- package/core/agentic/token-budget.ts +0 -226
- package/core/agentic/tool-registry.ts +0 -146
- package/core/agents/index.ts +0 -28
- package/core/agents/performance.ts +0 -429
- package/core/ai-tools/formatters.ts +0 -341
- package/core/ai-tools/generator.ts +0 -144
- package/core/ai-tools/index.ts +0 -15
- package/core/ai-tools/registry.ts +0 -201
- package/core/bus/bus.ts +0 -314
- package/core/bus/index.ts +0 -8
- package/core/cli/linear.ts +0 -500
- package/core/cli/lint-meta-commentary.ts +0 -177
- package/core/cli/start.ts +0 -386
- package/core/commands/analysis.ts +0 -1274
- package/core/commands/analytics.ts +0 -342
- package/core/commands/base.ts +0 -118
- package/core/commands/cleanup.ts +0 -157
- package/core/commands/command-data.ts +0 -463
- package/core/commands/commands.ts +0 -306
- package/core/commands/context.ts +0 -238
- package/core/commands/design.ts +0 -77
- package/core/commands/index.ts +0 -19
- package/core/commands/maintenance.ts +0 -77
- package/core/commands/performance.ts +0 -114
- package/core/commands/planning.ts +0 -662
- package/core/commands/register.ts +0 -127
- package/core/commands/registry.ts +0 -444
- package/core/commands/setup.ts +0 -280
- package/core/commands/shipping.ts +0 -267
- package/core/commands/snapshots.ts +0 -297
- package/core/commands/uninstall.ts +0 -542
- package/core/commands/velocity.ts +0 -149
- package/core/commands/workflow.ts +0 -505
- package/core/config/command-context.config.json +0 -66
- package/core/constants/index.ts +0 -379
- package/core/context/generator.ts +0 -368
- package/core/context-tools/files-tool.ts +0 -577
- package/core/context-tools/imports-tool.ts +0 -400
- package/core/context-tools/index.ts +0 -434
- package/core/context-tools/recent-tool.ts +0 -301
- package/core/context-tools/signatures-tool.ts +0 -495
- package/core/context-tools/summary-tool.ts +0 -301
- package/core/context-tools/token-counter.ts +0 -273
- package/core/context-tools/types.ts +0 -253
- package/core/domain/agent-generator.ts +0 -186
- package/core/domain/agent-loader.ts +0 -419
- package/core/domain/analyzer.ts +0 -387
- package/core/domain/architecture-generator.ts +0 -108
- package/core/domain/bm25.ts +0 -525
- package/core/domain/change-propagator.ts +0 -162
- package/core/domain/context-estimator.ts +0 -175
- package/core/domain/fibonacci.ts +0 -128
- package/core/domain/file-hasher.ts +0 -296
- package/core/domain/file-ranker.ts +0 -151
- package/core/domain/git-cochange.ts +0 -250
- package/core/domain/import-graph.ts +0 -315
- package/core/domain/snapshot-manager.ts +0 -415
- package/core/domain/task-stack.ts +0 -578
- package/core/domain/velocity.ts +0 -470
- package/core/errors.ts +0 -335
- package/core/events/events.ts +0 -85
- package/core/events/index.ts +0 -8
- package/core/index.ts +0 -481
- package/core/infrastructure/agent-detector.ts +0 -135
- package/core/infrastructure/ai-provider.ts +0 -578
- package/core/infrastructure/author-detector.ts +0 -133
- package/core/infrastructure/capability-installer.ts +0 -76
- package/core/infrastructure/claude-agent.ts +0 -297
- package/core/infrastructure/command-installer.ts +0 -752
- package/core/infrastructure/config-manager.ts +0 -364
- package/core/infrastructure/editors-config.ts +0 -172
- package/core/infrastructure/path-manager.ts +0 -571
- package/core/infrastructure/performance-tracker.ts +0 -326
- package/core/infrastructure/permission-manager.ts +0 -289
- package/core/infrastructure/setup.ts +0 -1061
- package/core/infrastructure/update-checker.ts +0 -246
- package/core/integrations/issue-tracker/enricher.ts +0 -271
- package/core/integrations/issue-tracker/index.ts +0 -8
- package/core/integrations/issue-tracker/manager.ts +0 -286
- package/core/integrations/issue-tracker/types.ts +0 -310
- package/core/integrations/jira/cache.ts +0 -57
- package/core/integrations/jira/client.ts +0 -688
- package/core/integrations/jira/index.ts +0 -23
- package/core/integrations/jira/service.ts +0 -244
- package/core/integrations/linear/cache.ts +0 -68
- package/core/integrations/linear/client.ts +0 -436
- package/core/integrations/linear/index.ts +0 -20
- package/core/integrations/linear/service.ts +0 -260
- package/core/integrations/linear/sync.ts +0 -314
- package/core/outcomes/analyzer.ts +0 -286
- package/core/outcomes/index.ts +0 -34
- package/core/outcomes/recorder.ts +0 -195
- package/core/plugin/builtin/webhook.ts +0 -148
- package/core/plugin/hooks.ts +0 -315
- package/core/plugin/index.ts +0 -50
- package/core/plugin/loader.ts +0 -354
- package/core/plugin/registry.ts +0 -326
- package/core/schemas/agents.ts +0 -27
- package/core/schemas/analysis.ts +0 -530
- package/core/schemas/classification.ts +0 -91
- package/core/schemas/command-context.ts +0 -29
- package/core/schemas/enriched-task.ts +0 -291
- package/core/schemas/ideas.ts +0 -114
- package/core/schemas/index.ts +0 -53
- package/core/schemas/issues.ts +0 -159
- package/core/schemas/llm-output.ts +0 -170
- package/core/schemas/metrics.ts +0 -143
- package/core/schemas/model.ts +0 -153
- package/core/schemas/outcomes.ts +0 -487
- package/core/schemas/performance.ts +0 -128
- package/core/schemas/permissions.ts +0 -180
- package/core/schemas/prd.ts +0 -450
- package/core/schemas/project.ts +0 -57
- package/core/schemas/roadmap.ts +0 -322
- package/core/schemas/schemas.ts +0 -38
- package/core/schemas/shipped.ts +0 -109
- package/core/schemas/state.ts +0 -284
- package/core/schemas/velocity.ts +0 -103
- package/core/server/index.ts +0 -21
- package/core/server/routes-extended.ts +0 -566
- package/core/server/routes.ts +0 -176
- package/core/server/server.ts +0 -149
- package/core/server/sse.ts +0 -192
- package/core/services/agent-generator.ts +0 -385
- package/core/services/agent-service.ts +0 -168
- package/core/services/breakdown-service.ts +0 -124
- package/core/services/context-generator.ts +0 -445
- package/core/services/context-selector.ts +0 -429
- package/core/services/dependency-validator.ts +0 -318
- package/core/services/diff-generator.ts +0 -313
- package/core/services/doctor-service.ts +0 -423
- package/core/services/file-categorizer.ts +0 -448
- package/core/services/file-scorer.ts +0 -270
- package/core/services/git-analyzer.ts +0 -293
- package/core/services/hierarchical-agent-resolver.ts +0 -236
- package/core/services/hooks-service.ts +0 -685
- package/core/services/index.ts +0 -46
- package/core/services/local-state-generator.ts +0 -158
- package/core/services/memory-service.ts +0 -181
- package/core/services/nested-context-resolver.ts +0 -842
- package/core/services/project-index.ts +0 -911
- package/core/services/project-service.ts +0 -155
- package/core/services/session-tracker.ts +0 -287
- package/core/services/skill-installer.ts +0 -447
- package/core/services/skill-lock.ts +0 -132
- package/core/services/skill-service.ts +0 -306
- package/core/services/stack-detector.ts +0 -229
- package/core/services/staleness-checker.ts +0 -327
- package/core/services/sync-service.ts +0 -1515
- package/core/services/sync-verifier.ts +0 -253
- package/core/services/watch-service.ts +0 -312
- package/core/session/compaction.ts +0 -248
- package/core/session/index.ts +0 -35
- package/core/session/log-migration.ts +0 -88
- package/core/session/metrics.ts +0 -323
- package/core/session/session-log-manager.ts +0 -307
- package/core/session/task-session-manager.ts +0 -404
- package/core/session/utils.ts +0 -51
- package/core/storage/analysis-storage.ts +0 -373
- package/core/storage/archive-storage.ts +0 -205
- package/core/storage/database.ts +0 -575
- package/core/storage/ideas-storage.ts +0 -298
- package/core/storage/index-storage.ts +0 -523
- package/core/storage/index.ts +0 -79
- package/core/storage/metrics-storage.ts +0 -321
- package/core/storage/migrate-json.ts +0 -720
- package/core/storage/queue-storage.ts +0 -336
- package/core/storage/safe-reader.ts +0 -105
- package/core/storage/shipped-storage.ts +0 -253
- package/core/storage/state-storage.ts +0 -1035
- package/core/storage/storage-manager.ts +0 -205
- package/core/storage/storage.ts +0 -177
- package/core/storage/velocity-storage.ts +0 -149
- package/core/sync/auth-config.ts +0 -138
- package/core/sync/index.ts +0 -31
- package/core/sync/oauth-handler.ts +0 -143
- package/core/sync/sync-client.ts +0 -251
- package/core/sync/sync-manager.ts +0 -327
- package/core/tsconfig.json +0 -22
- package/core/types/agentic.ts +0 -760
- package/core/types/agents.ts +0 -150
- package/core/types/bus.ts +0 -193
- package/core/types/citations.ts +0 -22
- package/core/types/commands.ts +0 -399
- package/core/types/config.ts +0 -92
- package/core/types/core.ts +0 -96
- package/core/types/diff.ts +0 -41
- package/core/types/domain.ts +0 -71
- package/core/types/errors.ts +0 -111
- package/core/types/events.ts +0 -42
- package/core/types/fs.ts +0 -72
- package/core/types/index.ts +0 -510
- package/core/types/infrastructure.ts +0 -210
- package/core/types/integrations.ts +0 -31
- package/core/types/jira.ts +0 -51
- package/core/types/logger.ts +0 -17
- package/core/types/memory.ts +0 -313
- package/core/types/outcomes.ts +0 -190
- package/core/types/output.ts +0 -47
- package/core/types/plugin.ts +0 -25
- package/core/types/project-sync.ts +0 -129
- package/core/types/provider.ts +0 -163
- package/core/types/server.ts +0 -71
- package/core/types/services.ts +0 -84
- package/core/types/session.ts +0 -135
- package/core/types/stack.ts +0 -19
- package/core/types/storage.ts +0 -318
- package/core/types/sync-verifier.ts +0 -33
- package/core/types/sync.ts +0 -121
- package/core/types/task.ts +0 -72
- package/core/types/template.ts +0 -24
- package/core/types/utils.ts +0 -92
- package/core/types/workflow.ts +0 -23
- package/core/utils/agent-stream.ts +0 -140
- package/core/utils/animations.ts +0 -251
- package/core/utils/branding.ts +0 -88
- package/core/utils/cache.ts +0 -187
- package/core/utils/citations.ts +0 -39
- package/core/utils/collection-filters.ts +0 -209
- package/core/utils/date-helper.ts +0 -176
- package/core/utils/error-messages.ts +0 -38
- package/core/utils/file-helper.ts +0 -277
- package/core/utils/fs-helpers.ts +0 -14
- package/core/utils/help.ts +0 -314
- package/core/utils/jsonl-helper.ts +0 -290
- package/core/utils/keychain.ts +0 -127
- package/core/utils/logger.ts +0 -77
- package/core/utils/markdown-builder.ts +0 -280
- package/core/utils/next-steps.ts +0 -95
- package/core/utils/output.ts +0 -403
- package/core/utils/preserve-sections.ts +0 -218
- package/core/utils/project-commands.ts +0 -126
- package/core/utils/project-credentials.ts +0 -143
- package/core/utils/provider-cache.ts +0 -49
- package/core/utils/retry.ts +0 -318
- package/core/utils/runtime.ts +0 -108
- package/core/utils/session-helper.ts +0 -278
- package/core/utils/subtask-table.ts +0 -227
- package/core/utils/version.ts +0 -128
- package/core/wizard/index.ts +0 -13
- package/core/wizard/onboarding.ts +0 -633
- package/core/workflow/index.ts +0 -7
- package/core/workflow/state-machine.ts +0 -198
- package/core/workflow/workflow-preferences.ts +0 -294
- package/dist/core/infrastructure/command-installer.js +0 -1141
- package/dist/core/infrastructure/editors-config.js +0 -177
- package/dist/core/infrastructure/setup.js +0 -2244
- package/dist/core/utils/version.js +0 -141
- package/templates/agentic/agent-routing.md +0 -45
- package/templates/agentic/agents/uxui.md +0 -63
- package/templates/agentic/checklist-routing.md +0 -98
- package/templates/agentic/orchestrator.md +0 -68
- package/templates/agentic/task-fragmentation.md +0 -89
- package/templates/agents/AGENTS.md +0 -68
- package/templates/analysis/analyze.md +0 -84
- package/templates/analysis/patterns.md +0 -60
- package/templates/antigravity/SKILL.md +0 -39
- package/templates/architect/discovery.md +0 -67
- package/templates/architect/phases.md +0 -59
- package/templates/checklists/architecture.md +0 -28
- package/templates/checklists/code-quality.md +0 -28
- package/templates/checklists/data.md +0 -33
- package/templates/checklists/documentation.md +0 -33
- package/templates/checklists/infrastructure.md +0 -33
- package/templates/checklists/performance.md +0 -33
- package/templates/checklists/security.md +0 -33
- package/templates/checklists/testing.md +0 -33
- package/templates/checklists/ux-ui.md +0 -37
- package/templates/commands/analyze.md +0 -56
- package/templates/commands/auth.md +0 -234
- package/templates/commands/bug.md +0 -163
- package/templates/commands/cleanup.md +0 -19
- package/templates/commands/dash.md +0 -99
- package/templates/commands/design.md +0 -15
- package/templates/commands/done.md +0 -291
- package/templates/commands/enrich.md +0 -174
- package/templates/commands/git.md +0 -295
- package/templates/commands/history.md +0 -389
- package/templates/commands/idea.md +0 -88
- package/templates/commands/impact.md +0 -864
- package/templates/commands/init.md +0 -54
- package/templates/commands/jira.md +0 -278
- package/templates/commands/linear.md +0 -288
- package/templates/commands/merge.md +0 -206
- package/templates/commands/next.md +0 -80
- package/templates/commands/p.md +0 -67
- package/templates/commands/p.toml +0 -37
- package/templates/commands/pause.md +0 -136
- package/templates/commands/plan.md +0 -696
- package/templates/commands/prd.md +0 -356
- package/templates/commands/resume.md +0 -171
- package/templates/commands/review.md +0 -276
- package/templates/commands/serve.md +0 -118
- package/templates/commands/setup.md +0 -91
- package/templates/commands/ship.md +0 -475
- package/templates/commands/skill.md +0 -259
- package/templates/commands/spec.md +0 -218
- package/templates/commands/status.md +0 -207
- package/templates/commands/sync.md +0 -104
- package/templates/commands/task.md +0 -312
- package/templates/commands/test.md +0 -93
- package/templates/commands/update.md +0 -63
- package/templates/commands/verify.md +0 -204
- package/templates/commands/workflow.md +0 -150
- package/templates/config/skill-mappings.json +0 -82
- package/templates/context/dashboard.md +0 -256
- package/templates/context/roadmap.md +0 -221
- package/templates/cursor/commands/bug.md +0 -8
- package/templates/cursor/commands/done.md +0 -4
- package/templates/cursor/commands/pause.md +0 -6
- package/templates/cursor/commands/resume.md +0 -4
- package/templates/cursor/commands/ship.md +0 -8
- package/templates/cursor/commands/sync.md +0 -4
- package/templates/cursor/commands/task.md +0 -8
- package/templates/cursor/p.md +0 -29
- package/templates/cursor/router.mdc +0 -28
- package/templates/design/api.md +0 -95
- package/templates/design/architecture.md +0 -77
- package/templates/design/component.md +0 -89
- package/templates/design/database.md +0 -78
- package/templates/design/flow.md +0 -94
- package/templates/global/ANTIGRAVITY.md +0 -254
- package/templates/global/CLAUDE.md +0 -497
- package/templates/global/CURSOR.mdc +0 -266
- package/templates/global/GEMINI.md +0 -293
- package/templates/global/STORAGE-SPEC.md +0 -391
- package/templates/global/WINDSURF.md +0 -266
- package/templates/global/modules/CLAUDE-commands.md +0 -70
- package/templates/global/modules/CLAUDE-core.md +0 -105
- package/templates/global/modules/CLAUDE-git.md +0 -50
- package/templates/global/modules/CLAUDE-intelligence.md +0 -92
- package/templates/global/modules/CLAUDE-storage.md +0 -50
- package/templates/global/modules/module-config.json +0 -36
- package/templates/mcp-config.json +0 -19
- package/templates/permissions/default.jsonc +0 -60
- package/templates/permissions/permissive.jsonc +0 -49
- package/templates/permissions/strict.jsonc +0 -58
- package/templates/planning-methodology.md +0 -195
- package/templates/skills/code-review.md +0 -47
- package/templates/skills/debug.md +0 -61
- package/templates/skills/refactor.md +0 -47
- package/templates/subagents/agent-base.md +0 -20
- package/templates/subagents/domain/backend.md +0 -109
- package/templates/subagents/domain/database.md +0 -121
- package/templates/subagents/domain/devops.md +0 -152
- package/templates/subagents/domain/frontend.md +0 -103
- package/templates/subagents/domain/testing.md +0 -169
- package/templates/subagents/pm-expert.md +0 -366
- package/templates/subagents/workflow/chief-architect.md +0 -657
- package/templates/subagents/workflow/prjct-planner.md +0 -159
- package/templates/subagents/workflow/prjct-shipper.md +0 -188
- package/templates/subagents/workflow/prjct-workflow.md +0 -98
- package/templates/tools/bash.txt +0 -22
- package/templates/tools/edit.txt +0 -18
- package/templates/tools/glob.txt +0 -19
- package/templates/tools/grep.txt +0 -21
- package/templates/tools/read.txt +0 -14
- package/templates/tools/task.txt +0 -20
- package/templates/tools/webfetch.txt +0 -16
- package/templates/tools/websearch.txt +0 -18
- package/templates/tools/write.txt +0 -17
- package/templates/windsurf/router.md +0 -28
- package/templates/windsurf/workflows/bug.md +0 -8
- package/templates/windsurf/workflows/done.md +0 -4
- package/templates/windsurf/workflows/pause.md +0 -4
- package/templates/windsurf/workflows/resume.md +0 -4
- package/templates/windsurf/workflows/ship.md +0 -8
- package/templates/windsurf/workflows/sync.md +0 -4
- package/templates/windsurf/workflows/task.md +0 -8
|
@@ -1,383 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Storage Manager Tests
|
|
3
|
-
*
|
|
4
|
-
* Tests for the base StorageManager class:
|
|
5
|
-
* - Read/write JSON operations
|
|
6
|
-
* - Missing file handling
|
|
7
|
-
* - Directory creation
|
|
8
|
-
* - Cache behavior
|
|
9
|
-
* - State consistency
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import { afterEach, beforeEach, describe, expect, it } from 'bun:test'
|
|
13
|
-
import fs from 'node:fs/promises'
|
|
14
|
-
import os from 'node:os'
|
|
15
|
-
import path from 'node:path'
|
|
16
|
-
import pathManager from '../../infrastructure/path-manager'
|
|
17
|
-
import { prjctDb } from '../../storage/database'
|
|
18
|
-
import { StorageManager } from '../../storage/storage-manager'
|
|
19
|
-
|
|
20
|
-
// =============================================================================
|
|
21
|
-
// Test Implementation
|
|
22
|
-
// =============================================================================
|
|
23
|
-
|
|
24
|
-
interface TestData {
|
|
25
|
-
value: string
|
|
26
|
-
count: number
|
|
27
|
-
items: string[]
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Concrete implementation for testing the abstract StorageManager
|
|
32
|
-
*/
|
|
33
|
-
class TestStorageManager extends StorageManager<TestData> {
|
|
34
|
-
constructor() {
|
|
35
|
-
super('test-data.json')
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
protected getLayer(): string {
|
|
39
|
-
return 'context'
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
protected getDefault(): TestData {
|
|
43
|
-
return { value: '', count: 0, items: [] }
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
protected toMarkdown(data: TestData): string {
|
|
47
|
-
return `# Test Data\n\nValue: ${data.value}\nCount: ${data.count}\nItems: ${data.items.join(', ')}`
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
protected getMdFilename(): string {
|
|
51
|
-
return 'test-data.md'
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
protected getEventType(action: 'update' | 'create' | 'delete'): string {
|
|
55
|
-
return `test.${action}`
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// =============================================================================
|
|
60
|
-
// Test Setup
|
|
61
|
-
// =============================================================================
|
|
62
|
-
|
|
63
|
-
let tmpRoot: string | null = null
|
|
64
|
-
let testProjectId: string
|
|
65
|
-
let manager: TestStorageManager
|
|
66
|
-
|
|
67
|
-
// Mock pathManager to use temp directory
|
|
68
|
-
const originalGetGlobalProjectPath = pathManager.getGlobalProjectPath.bind(pathManager)
|
|
69
|
-
const originalGetStoragePath = pathManager.getStoragePath.bind(pathManager)
|
|
70
|
-
const originalGetFilePath = pathManager.getFilePath.bind(pathManager)
|
|
71
|
-
|
|
72
|
-
describe('StorageManager', () => {
|
|
73
|
-
beforeEach(async () => {
|
|
74
|
-
// Create temp directory for test isolation
|
|
75
|
-
tmpRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'prjct-storage-test-'))
|
|
76
|
-
testProjectId = 'test-project-123'
|
|
77
|
-
|
|
78
|
-
// Mock pathManager to use temp directory
|
|
79
|
-
pathManager.getGlobalProjectPath = (projectId: string) => {
|
|
80
|
-
return path.join(tmpRoot!, projectId)
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
pathManager.getStoragePath = (projectId: string, filename: string) => {
|
|
84
|
-
return path.join(tmpRoot!, projectId, 'storage', filename)
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
pathManager.getFilePath = (projectId: string, layer: string, filename: string) => {
|
|
88
|
-
return path.join(tmpRoot!, projectId, layer, filename)
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// Create fresh manager instance
|
|
92
|
-
manager = new TestStorageManager()
|
|
93
|
-
})
|
|
94
|
-
|
|
95
|
-
afterEach(async () => {
|
|
96
|
-
// Close SQLite connections before cleanup
|
|
97
|
-
prjctDb.close()
|
|
98
|
-
|
|
99
|
-
// Restore original pathManager methods
|
|
100
|
-
pathManager.getGlobalProjectPath = originalGetGlobalProjectPath
|
|
101
|
-
pathManager.getStoragePath = originalGetStoragePath
|
|
102
|
-
pathManager.getFilePath = originalGetFilePath
|
|
103
|
-
|
|
104
|
-
// Clean up temp directory
|
|
105
|
-
if (tmpRoot) {
|
|
106
|
-
await fs.rm(tmpRoot, { recursive: true, force: true })
|
|
107
|
-
tmpRoot = null
|
|
108
|
-
}
|
|
109
|
-
})
|
|
110
|
-
|
|
111
|
-
// ===========================================================================
|
|
112
|
-
// Read/Write Tests
|
|
113
|
-
// ===========================================================================
|
|
114
|
-
|
|
115
|
-
describe('read/write', () => {
|
|
116
|
-
it('should write and read JSON correctly', async () => {
|
|
117
|
-
const testData: TestData = {
|
|
118
|
-
value: 'hello',
|
|
119
|
-
count: 42,
|
|
120
|
-
items: ['a', 'b', 'c'],
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
await manager.write(testProjectId, testData)
|
|
124
|
-
const result = await manager.read(testProjectId)
|
|
125
|
-
|
|
126
|
-
expect(result).toEqual(testData)
|
|
127
|
-
})
|
|
128
|
-
|
|
129
|
-
it('should write to SQLite kv_store', async () => {
|
|
130
|
-
const testData: TestData = {
|
|
131
|
-
value: 'test',
|
|
132
|
-
count: 1,
|
|
133
|
-
items: ['item1'],
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
await manager.write(testProjectId, testData)
|
|
137
|
-
|
|
138
|
-
// Verify SQLite has the data
|
|
139
|
-
const doc = prjctDb.getDoc<TestData>(testProjectId, 'test-data')
|
|
140
|
-
expect(doc).toEqual(testData)
|
|
141
|
-
})
|
|
142
|
-
|
|
143
|
-
it('should not create JSON storage file', async () => {
|
|
144
|
-
const testData: TestData = {
|
|
145
|
-
value: 'test',
|
|
146
|
-
count: 1,
|
|
147
|
-
items: ['item1'],
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
await manager.write(testProjectId, testData)
|
|
151
|
-
|
|
152
|
-
// Verify JSON file does NOT exist
|
|
153
|
-
const storagePath = path.join(tmpRoot!, testProjectId, 'storage', 'test-data.json')
|
|
154
|
-
await expect(fs.access(storagePath)).rejects.toThrow()
|
|
155
|
-
})
|
|
156
|
-
|
|
157
|
-
it('should create context markdown file', async () => {
|
|
158
|
-
const testData: TestData = {
|
|
159
|
-
value: 'markdown-test',
|
|
160
|
-
count: 5,
|
|
161
|
-
items: ['x', 'y'],
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
await manager.write(testProjectId, testData)
|
|
165
|
-
|
|
166
|
-
// Verify markdown file exists
|
|
167
|
-
const contextPath = path.join(tmpRoot!, testProjectId, 'context', 'test-data.md')
|
|
168
|
-
const content = await fs.readFile(contextPath, 'utf-8')
|
|
169
|
-
|
|
170
|
-
expect(content).toContain('# Test Data')
|
|
171
|
-
expect(content).toContain('Value: markdown-test')
|
|
172
|
-
expect(content).toContain('Count: 5')
|
|
173
|
-
expect(content).toContain('Items: x, y')
|
|
174
|
-
})
|
|
175
|
-
|
|
176
|
-
it('should overwrite existing data', async () => {
|
|
177
|
-
const data1: TestData = { value: 'first', count: 1, items: [] }
|
|
178
|
-
const data2: TestData = { value: 'second', count: 2, items: ['new'] }
|
|
179
|
-
|
|
180
|
-
await manager.write(testProjectId, data1)
|
|
181
|
-
await manager.write(testProjectId, data2)
|
|
182
|
-
|
|
183
|
-
const result = await manager.read(testProjectId)
|
|
184
|
-
expect(result).toEqual(data2)
|
|
185
|
-
})
|
|
186
|
-
})
|
|
187
|
-
|
|
188
|
-
// ===========================================================================
|
|
189
|
-
// Missing File Handling
|
|
190
|
-
// ===========================================================================
|
|
191
|
-
|
|
192
|
-
describe('missing file handling', () => {
|
|
193
|
-
it('should return default when file does not exist', async () => {
|
|
194
|
-
const result = await manager.read('non-existent-project')
|
|
195
|
-
|
|
196
|
-
expect(result).toEqual({ value: '', count: 0, items: [] })
|
|
197
|
-
})
|
|
198
|
-
|
|
199
|
-
it('should report exists=false when no data', async () => {
|
|
200
|
-
const exists = await manager.exists('non-existent-project')
|
|
201
|
-
expect(exists).toBe(false)
|
|
202
|
-
})
|
|
203
|
-
|
|
204
|
-
it('should report exists=true after write', async () => {
|
|
205
|
-
await manager.write(testProjectId, { value: 'test', count: 1, items: [] })
|
|
206
|
-
|
|
207
|
-
const exists = await manager.exists(testProjectId)
|
|
208
|
-
expect(exists).toBe(true)
|
|
209
|
-
})
|
|
210
|
-
})
|
|
211
|
-
|
|
212
|
-
// ===========================================================================
|
|
213
|
-
// Directory Creation
|
|
214
|
-
// ===========================================================================
|
|
215
|
-
|
|
216
|
-
describe('directory creation', () => {
|
|
217
|
-
it('should create project directory for SQLite DB', async () => {
|
|
218
|
-
const testData: TestData = { value: 'dir-test', count: 1, items: [] }
|
|
219
|
-
|
|
220
|
-
// Project directory shouldn't exist yet
|
|
221
|
-
const projectDir = path.join(tmpRoot!, testProjectId)
|
|
222
|
-
await expect(fs.access(projectDir)).rejects.toThrow()
|
|
223
|
-
|
|
224
|
-
// Write should create it (SQLite DB creates its parent dir)
|
|
225
|
-
await manager.write(testProjectId, testData)
|
|
226
|
-
|
|
227
|
-
// Project dir should exist (created by SQLite)
|
|
228
|
-
const stat = await fs.stat(projectDir)
|
|
229
|
-
expect(stat.isDirectory()).toBe(true)
|
|
230
|
-
})
|
|
231
|
-
|
|
232
|
-
it('should create context directory if it does not exist', async () => {
|
|
233
|
-
const testData: TestData = { value: 'ctx-test', count: 1, items: [] }
|
|
234
|
-
|
|
235
|
-
// Directory shouldn't exist yet
|
|
236
|
-
const contextDir = path.join(tmpRoot!, testProjectId, 'context')
|
|
237
|
-
await expect(fs.access(contextDir)).rejects.toThrow()
|
|
238
|
-
|
|
239
|
-
// Write should create it
|
|
240
|
-
await manager.write(testProjectId, testData)
|
|
241
|
-
|
|
242
|
-
// Now it should exist
|
|
243
|
-
const stat = await fs.stat(contextDir)
|
|
244
|
-
expect(stat.isDirectory()).toBe(true)
|
|
245
|
-
})
|
|
246
|
-
|
|
247
|
-
it('should create nested directories', async () => {
|
|
248
|
-
const deepProjectId = 'deep/nested/project'
|
|
249
|
-
const testData: TestData = { value: 'nested', count: 1, items: [] }
|
|
250
|
-
|
|
251
|
-
await manager.write(deepProjectId, testData)
|
|
252
|
-
|
|
253
|
-
const result = await manager.read(deepProjectId)
|
|
254
|
-
expect(result).toEqual(testData)
|
|
255
|
-
})
|
|
256
|
-
})
|
|
257
|
-
|
|
258
|
-
// ===========================================================================
|
|
259
|
-
// Cache Behavior
|
|
260
|
-
// ===========================================================================
|
|
261
|
-
|
|
262
|
-
describe('cache behavior', () => {
|
|
263
|
-
it('should cache read results', async () => {
|
|
264
|
-
const testData: TestData = { value: 'cached', count: 1, items: [] }
|
|
265
|
-
await manager.write(testProjectId, testData)
|
|
266
|
-
|
|
267
|
-
// First read
|
|
268
|
-
const result1 = await manager.read(testProjectId)
|
|
269
|
-
|
|
270
|
-
// Modify SQLite directly (bypass manager)
|
|
271
|
-
prjctDb.setDoc(testProjectId, 'test-data', { value: 'modified', count: 2, items: [] })
|
|
272
|
-
|
|
273
|
-
// Second read should return cached value
|
|
274
|
-
const result2 = await manager.read(testProjectId)
|
|
275
|
-
expect(result2).toEqual(result1)
|
|
276
|
-
})
|
|
277
|
-
|
|
278
|
-
it('should clear cache for specific project', async () => {
|
|
279
|
-
const testData: TestData = { value: 'to-clear', count: 1, items: [] }
|
|
280
|
-
await manager.write(testProjectId, testData)
|
|
281
|
-
|
|
282
|
-
// Read to populate cache
|
|
283
|
-
await manager.read(testProjectId)
|
|
284
|
-
|
|
285
|
-
// Write new data through the manager (the proper API)
|
|
286
|
-
const newData: TestData = { value: 'updated', count: 99, items: ['new'] }
|
|
287
|
-
await manager.write(testProjectId, newData)
|
|
288
|
-
|
|
289
|
-
// Create a new manager instance (simulates fresh session without cache)
|
|
290
|
-
const freshManager = new TestStorageManager()
|
|
291
|
-
|
|
292
|
-
// Clear cache on original manager
|
|
293
|
-
manager.clearCache(testProjectId)
|
|
294
|
-
|
|
295
|
-
// Both should get the new data
|
|
296
|
-
const result = await manager.read(testProjectId)
|
|
297
|
-
expect(result).toEqual(newData)
|
|
298
|
-
|
|
299
|
-
const freshResult = await freshManager.read(testProjectId)
|
|
300
|
-
expect(freshResult).toEqual(newData)
|
|
301
|
-
})
|
|
302
|
-
|
|
303
|
-
it('should clear all cache', async () => {
|
|
304
|
-
// Write to multiple projects
|
|
305
|
-
await manager.write('project-a', { value: 'a', count: 1, items: [] })
|
|
306
|
-
await manager.write('project-b', { value: 'b', count: 2, items: [] })
|
|
307
|
-
|
|
308
|
-
// Read to populate cache
|
|
309
|
-
await manager.read('project-a')
|
|
310
|
-
await manager.read('project-b')
|
|
311
|
-
|
|
312
|
-
// Clear all cache
|
|
313
|
-
manager.clearCache()
|
|
314
|
-
|
|
315
|
-
// Verify cache stats
|
|
316
|
-
const stats = manager.getCacheStats()
|
|
317
|
-
expect(stats.size).toBe(0)
|
|
318
|
-
})
|
|
319
|
-
|
|
320
|
-
it('should return cache stats', async () => {
|
|
321
|
-
const stats = manager.getCacheStats()
|
|
322
|
-
|
|
323
|
-
expect(stats).toHaveProperty('size')
|
|
324
|
-
expect(stats).toHaveProperty('maxSize')
|
|
325
|
-
expect(stats).toHaveProperty('ttl')
|
|
326
|
-
expect(typeof stats.size).toBe('number')
|
|
327
|
-
expect(typeof stats.maxSize).toBe('number')
|
|
328
|
-
expect(typeof stats.ttl).toBe('number')
|
|
329
|
-
})
|
|
330
|
-
})
|
|
331
|
-
|
|
332
|
-
// ===========================================================================
|
|
333
|
-
// State Consistency (Update Operations)
|
|
334
|
-
// ===========================================================================
|
|
335
|
-
|
|
336
|
-
describe('state consistency', () => {
|
|
337
|
-
it('should update data atomically with updater function', async () => {
|
|
338
|
-
const initial: TestData = { value: 'initial', count: 0, items: [] }
|
|
339
|
-
await manager.write(testProjectId, initial)
|
|
340
|
-
|
|
341
|
-
const result = await manager.update(testProjectId, (current) => ({
|
|
342
|
-
...current,
|
|
343
|
-
count: current.count + 1,
|
|
344
|
-
items: [...current.items, 'new-item'],
|
|
345
|
-
}))
|
|
346
|
-
|
|
347
|
-
expect(result.count).toBe(1)
|
|
348
|
-
expect(result.items).toEqual(['new-item'])
|
|
349
|
-
|
|
350
|
-
// Verify persisted
|
|
351
|
-
manager.clearCache(testProjectId)
|
|
352
|
-
const persisted = await manager.read(testProjectId)
|
|
353
|
-
expect(persisted).toEqual(result)
|
|
354
|
-
})
|
|
355
|
-
|
|
356
|
-
it('should handle multiple sequential updates', async () => {
|
|
357
|
-
await manager.write(testProjectId, { value: 'start', count: 0, items: [] })
|
|
358
|
-
|
|
359
|
-
// Multiple updates
|
|
360
|
-
for (let i = 0; i < 5; i++) {
|
|
361
|
-
await manager.update(testProjectId, (current) => ({
|
|
362
|
-
...current,
|
|
363
|
-
count: current.count + 1,
|
|
364
|
-
}))
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
const result = await manager.read(testProjectId)
|
|
368
|
-
expect(result.count).toBe(5)
|
|
369
|
-
})
|
|
370
|
-
|
|
371
|
-
it('should maintain data integrity after failed read during update', async () => {
|
|
372
|
-
// Start with no file (will use default)
|
|
373
|
-
const result = await manager.update(testProjectId, (current) => ({
|
|
374
|
-
...current,
|
|
375
|
-
value: 'from-default',
|
|
376
|
-
count: 100,
|
|
377
|
-
}))
|
|
378
|
-
|
|
379
|
-
expect(result.value).toBe('from-default')
|
|
380
|
-
expect(result.count).toBe(100)
|
|
381
|
-
})
|
|
382
|
-
})
|
|
383
|
-
})
|
|
@@ -1,237 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Subtask Handoff Tests (PRJ-262)
|
|
3
|
-
*
|
|
4
|
-
* Tests for mandatory subtask output and handoff:
|
|
5
|
-
* - SubtaskCompletionDataSchema validation
|
|
6
|
-
* - SubtaskSummarySchema required fields
|
|
7
|
-
* - validateSubtaskCompletion helper
|
|
8
|
-
* - Backward compatibility with old state.json
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { describe, expect, it } from 'bun:test'
|
|
12
|
-
import {
|
|
13
|
-
SubtaskCompletionDataSchema,
|
|
14
|
-
SubtaskSchema,
|
|
15
|
-
SubtaskSummarySchema,
|
|
16
|
-
validateSubtaskCompletion,
|
|
17
|
-
} from '../../schemas/state'
|
|
18
|
-
|
|
19
|
-
// =============================================================================
|
|
20
|
-
// SubtaskSummarySchema — outputForNextAgent is now required
|
|
21
|
-
// =============================================================================
|
|
22
|
-
|
|
23
|
-
describe('SubtaskSummarySchema', () => {
|
|
24
|
-
const validSummary = {
|
|
25
|
-
title: 'Implement auth middleware',
|
|
26
|
-
description: 'Added JWT verification to all protected routes',
|
|
27
|
-
filesChanged: [
|
|
28
|
-
{ path: 'src/middleware/auth.ts', action: 'created' as const },
|
|
29
|
-
{ path: 'src/routes/api.ts', action: 'modified' as const },
|
|
30
|
-
],
|
|
31
|
-
whatWasDone: ['Created JWT middleware', 'Applied to API routes'],
|
|
32
|
-
outputForNextAgent:
|
|
33
|
-
'Auth middleware is in place. Next subtask should add role-based access control.',
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
it('should parse a valid summary with all required fields', () => {
|
|
37
|
-
const result = SubtaskSummarySchema.parse(validSummary)
|
|
38
|
-
expect(result.outputForNextAgent).toBe(validSummary.outputForNextAgent)
|
|
39
|
-
expect(result.whatWasDone).toHaveLength(2)
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
it('should reject missing outputForNextAgent', () => {
|
|
43
|
-
const { outputForNextAgent, ...withoutOutput } = validSummary
|
|
44
|
-
expect(() => SubtaskSummarySchema.parse(withoutOutput)).toThrow()
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
it('should reject empty outputForNextAgent', () => {
|
|
48
|
-
expect(() => SubtaskSummarySchema.parse({ ...validSummary, outputForNextAgent: '' })).toThrow()
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
it('should reject empty whatWasDone array', () => {
|
|
52
|
-
expect(() => SubtaskSummarySchema.parse({ ...validSummary, whatWasDone: [] })).toThrow()
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
it('should allow optional notes', () => {
|
|
56
|
-
const result = SubtaskSummarySchema.parse({ ...validSummary, notes: 'Watch for rate limits' })
|
|
57
|
-
expect(result.notes).toBe('Watch for rate limits')
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
it('should allow missing notes', () => {
|
|
61
|
-
const result = SubtaskSummarySchema.parse(validSummary)
|
|
62
|
-
expect(result.notes).toBeUndefined()
|
|
63
|
-
})
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
// =============================================================================
|
|
67
|
-
// SubtaskCompletionDataSchema — validates completion requirements
|
|
68
|
-
// =============================================================================
|
|
69
|
-
|
|
70
|
-
describe('SubtaskCompletionDataSchema', () => {
|
|
71
|
-
const validCompletion = {
|
|
72
|
-
output: 'Implemented auth middleware with JWT verification',
|
|
73
|
-
summary: {
|
|
74
|
-
title: 'Auth middleware',
|
|
75
|
-
description: 'JWT verification for protected routes',
|
|
76
|
-
filesChanged: [{ path: 'src/auth.ts', action: 'created' as const }],
|
|
77
|
-
whatWasDone: ['Created JWT middleware'],
|
|
78
|
-
outputForNextAgent: 'Middleware ready, add RBAC next.',
|
|
79
|
-
},
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
it('should parse valid completion data', () => {
|
|
83
|
-
const result = SubtaskCompletionDataSchema.parse(validCompletion)
|
|
84
|
-
expect(result.output).toBe(validCompletion.output)
|
|
85
|
-
expect(result.summary.outputForNextAgent).toBe('Middleware ready, add RBAC next.')
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
it('should reject missing output', () => {
|
|
89
|
-
const { output, ...withoutOutput } = validCompletion
|
|
90
|
-
expect(() => SubtaskCompletionDataSchema.parse(withoutOutput)).toThrow()
|
|
91
|
-
})
|
|
92
|
-
|
|
93
|
-
it('should reject empty output', () => {
|
|
94
|
-
expect(() => SubtaskCompletionDataSchema.parse({ ...validCompletion, output: '' })).toThrow()
|
|
95
|
-
})
|
|
96
|
-
|
|
97
|
-
it('should reject missing summary', () => {
|
|
98
|
-
expect(() => SubtaskCompletionDataSchema.parse({ output: 'some output' })).toThrow()
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
it('should reject summary without outputForNextAgent', () => {
|
|
102
|
-
const badSummary = { ...validCompletion.summary }
|
|
103
|
-
// @ts-expect-error - intentionally testing invalid data
|
|
104
|
-
delete badSummary.outputForNextAgent
|
|
105
|
-
expect(() => SubtaskCompletionDataSchema.parse({ output: 'ok', summary: badSummary })).toThrow()
|
|
106
|
-
})
|
|
107
|
-
})
|
|
108
|
-
|
|
109
|
-
// =============================================================================
|
|
110
|
-
// validateSubtaskCompletion helper
|
|
111
|
-
// =============================================================================
|
|
112
|
-
|
|
113
|
-
describe('validateSubtaskCompletion', () => {
|
|
114
|
-
const validData = {
|
|
115
|
-
output: 'Task done',
|
|
116
|
-
summary: {
|
|
117
|
-
title: 'Test',
|
|
118
|
-
description: 'Testing',
|
|
119
|
-
filesChanged: [],
|
|
120
|
-
whatWasDone: ['Did the thing'],
|
|
121
|
-
outputForNextAgent: 'Context for next.',
|
|
122
|
-
},
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
it('should return success for valid data', () => {
|
|
126
|
-
const result = validateSubtaskCompletion(validData)
|
|
127
|
-
expect(result.success).toBe(true)
|
|
128
|
-
if (result.success) {
|
|
129
|
-
expect(result.data.output).toBe('Task done')
|
|
130
|
-
}
|
|
131
|
-
})
|
|
132
|
-
|
|
133
|
-
it('should return errors for missing output', () => {
|
|
134
|
-
const result = validateSubtaskCompletion({ summary: validData.summary })
|
|
135
|
-
expect(result.success).toBe(false)
|
|
136
|
-
if (!result.success) {
|
|
137
|
-
expect(result.errors.length).toBeGreaterThan(0)
|
|
138
|
-
expect(result.errors.some((e) => e.includes('output'))).toBe(true)
|
|
139
|
-
}
|
|
140
|
-
})
|
|
141
|
-
|
|
142
|
-
it('should return errors for empty whatWasDone', () => {
|
|
143
|
-
const result = validateSubtaskCompletion({
|
|
144
|
-
output: 'ok',
|
|
145
|
-
summary: { ...validData.summary, whatWasDone: [] },
|
|
146
|
-
})
|
|
147
|
-
expect(result.success).toBe(false)
|
|
148
|
-
if (!result.success) {
|
|
149
|
-
expect(result.errors.some((e) => e.includes('whatWasDone'))).toBe(true)
|
|
150
|
-
}
|
|
151
|
-
})
|
|
152
|
-
|
|
153
|
-
it('should return errors for completely invalid data', () => {
|
|
154
|
-
const result = validateSubtaskCompletion({})
|
|
155
|
-
expect(result.success).toBe(false)
|
|
156
|
-
if (!result.success) {
|
|
157
|
-
expect(result.errors.length).toBeGreaterThan(0)
|
|
158
|
-
}
|
|
159
|
-
})
|
|
160
|
-
})
|
|
161
|
-
|
|
162
|
-
// =============================================================================
|
|
163
|
-
// Backward Compatibility
|
|
164
|
-
// =============================================================================
|
|
165
|
-
|
|
166
|
-
describe('backward compatibility', () => {
|
|
167
|
-
it('should parse old SubtaskSchema without summary or output', () => {
|
|
168
|
-
const oldSubtask = {
|
|
169
|
-
id: 'subtask-1',
|
|
170
|
-
description: 'Old subtask without handoff',
|
|
171
|
-
domain: 'backend',
|
|
172
|
-
agent: 'backend.md',
|
|
173
|
-
status: 'completed' as const,
|
|
174
|
-
dependsOn: [],
|
|
175
|
-
startedAt: '2026-01-01T00:00:00.000Z',
|
|
176
|
-
completedAt: '2026-01-01T01:00:00.000Z',
|
|
177
|
-
// No output, no summary — old format
|
|
178
|
-
}
|
|
179
|
-
const result = SubtaskSchema.parse(oldSubtask)
|
|
180
|
-
expect(result.output).toBeUndefined()
|
|
181
|
-
expect(result.summary).toBeUndefined()
|
|
182
|
-
expect(result.status).toBe('completed')
|
|
183
|
-
})
|
|
184
|
-
|
|
185
|
-
it('should parse pending subtask without completion fields', () => {
|
|
186
|
-
const pending = {
|
|
187
|
-
id: 'subtask-2',
|
|
188
|
-
description: 'Pending subtask',
|
|
189
|
-
domain: 'frontend',
|
|
190
|
-
agent: 'frontend.md',
|
|
191
|
-
status: 'pending' as const,
|
|
192
|
-
dependsOn: ['subtask-1'],
|
|
193
|
-
}
|
|
194
|
-
const result = SubtaskSchema.parse(pending)
|
|
195
|
-
expect(result.status).toBe('pending')
|
|
196
|
-
expect(result.output).toBeUndefined()
|
|
197
|
-
expect(result.summary).toBeUndefined()
|
|
198
|
-
})
|
|
199
|
-
|
|
200
|
-
it('should parse subtask with output but no summary (transition format)', () => {
|
|
201
|
-
const transitional = {
|
|
202
|
-
id: 'subtask-1',
|
|
203
|
-
description: 'Transitional format',
|
|
204
|
-
domain: 'backend',
|
|
205
|
-
agent: 'backend.md',
|
|
206
|
-
status: 'completed' as const,
|
|
207
|
-
dependsOn: [],
|
|
208
|
-
output: 'Done with basic output',
|
|
209
|
-
// No summary yet
|
|
210
|
-
}
|
|
211
|
-
const result = SubtaskSchema.parse(transitional)
|
|
212
|
-
expect(result.output).toBe('Done with basic output')
|
|
213
|
-
expect(result.summary).toBeUndefined()
|
|
214
|
-
})
|
|
215
|
-
|
|
216
|
-
it('should parse subtask with full handoff data', () => {
|
|
217
|
-
const withHandoff = {
|
|
218
|
-
id: 'subtask-1',
|
|
219
|
-
description: 'Full handoff format',
|
|
220
|
-
domain: 'backend',
|
|
221
|
-
agent: 'backend.md',
|
|
222
|
-
status: 'completed' as const,
|
|
223
|
-
dependsOn: [],
|
|
224
|
-
output: 'Implemented the feature',
|
|
225
|
-
summary: {
|
|
226
|
-
title: 'Backend API',
|
|
227
|
-
description: 'Created REST endpoints',
|
|
228
|
-
filesChanged: [{ path: 'src/api.ts', action: 'created' as const }],
|
|
229
|
-
whatWasDone: ['Created endpoints', 'Added validation'],
|
|
230
|
-
outputForNextAgent: 'API is ready at /api/v1. Add auth next.',
|
|
231
|
-
},
|
|
232
|
-
}
|
|
233
|
-
const result = SubtaskSchema.parse(withHandoff)
|
|
234
|
-
expect(result.summary?.outputForNextAgent).toBe('API is ready at /api/v1. Add auth next.')
|
|
235
|
-
expect(result.summary?.whatWasDone).toHaveLength(2)
|
|
236
|
-
})
|
|
237
|
-
})
|