prjct-cli 1.22.0 → 1.24.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 +230 -0
- package/bin/prjct +30 -13
- package/dist/bin/prjct-core.mjs +1748 -0
- package/dist/bin/prjct.mjs +17 -36672
- package/dist/cli/linear.mjs +14 -0
- package/dist/daemon/entry.mjs +1429 -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,281 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Memory System Tests
|
|
3
|
-
* P3.3: Semantic Memory Database
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from 'bun:test'
|
|
7
|
-
import fs from 'node:fs/promises'
|
|
8
|
-
import path from 'node:path'
|
|
9
|
-
import memorySystem from '../../agentic/memory-system'
|
|
10
|
-
import pathManager from '../../infrastructure/path-manager'
|
|
11
|
-
|
|
12
|
-
let testCounter = 0
|
|
13
|
-
const getTestProjectId = () => `test-memory-${Date.now()}-${++testCounter}`
|
|
14
|
-
|
|
15
|
-
describe('MemorySystem P3.3', () => {
|
|
16
|
-
let TEST_PROJECT_ID: string
|
|
17
|
-
const TEST_GLOBAL_BASE_DIR = path.join(process.cwd(), '.tmp', 'prjct-cli-tests')
|
|
18
|
-
|
|
19
|
-
beforeAll(async () => {
|
|
20
|
-
// Reason: In sandboxed test environments we can't write to "~/.prjct-cli".
|
|
21
|
-
pathManager.setGlobalBaseDir(TEST_GLOBAL_BASE_DIR)
|
|
22
|
-
await fs.mkdir(TEST_GLOBAL_BASE_DIR, { recursive: true })
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
beforeEach(() => {
|
|
26
|
-
TEST_PROJECT_ID = getTestProjectId()
|
|
27
|
-
memorySystem.resetState()
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
describe('createMemory', () => {
|
|
31
|
-
it('should create a memory with tags', async () => {
|
|
32
|
-
const memoryId = await memorySystem.createMemory(TEST_PROJECT_ID, {
|
|
33
|
-
title: 'Test Memory',
|
|
34
|
-
content: 'This is test content',
|
|
35
|
-
tags: ['code_style', 'naming_convention'],
|
|
36
|
-
userTriggered: true,
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
// UUID format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
|
40
|
-
expect(memoryId).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i)
|
|
41
|
-
|
|
42
|
-
const memories = await memorySystem.getAllMemories(TEST_PROJECT_ID)
|
|
43
|
-
expect(memories.length).toBe(1)
|
|
44
|
-
expect(memories[0].title).toBe('Test Memory')
|
|
45
|
-
expect(memories[0].tags).toContain('code_style')
|
|
46
|
-
expect(memories[0].userTriggered).toBe(true)
|
|
47
|
-
})
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
describe('updateMemory', () => {
|
|
51
|
-
it('should update memory content and tags', async () => {
|
|
52
|
-
const memoryId = await memorySystem.createMemory(TEST_PROJECT_ID, {
|
|
53
|
-
title: 'Original Title',
|
|
54
|
-
content: 'Original content',
|
|
55
|
-
tags: ['code_style'],
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
const updated = await memorySystem.updateMemory(TEST_PROJECT_ID, memoryId, {
|
|
59
|
-
title: 'Updated Title',
|
|
60
|
-
content: 'Updated content',
|
|
61
|
-
tags: ['naming_convention', 'architecture'],
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
expect(updated).toBe(true)
|
|
65
|
-
|
|
66
|
-
const memories = await memorySystem.getAllMemories(TEST_PROJECT_ID)
|
|
67
|
-
const memory = memories.find((m) => m.id === memoryId)
|
|
68
|
-
|
|
69
|
-
expect(memory!.title).toBe('Updated Title')
|
|
70
|
-
expect(memory!.content).toBe('Updated content')
|
|
71
|
-
expect(memory!.tags).toContain('architecture')
|
|
72
|
-
expect(memory!.tags).not.toContain('code_style')
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
it('should return false for non-existent memory', async () => {
|
|
76
|
-
const result = await memorySystem.updateMemory(TEST_PROJECT_ID, 'non_existent_id', {
|
|
77
|
-
title: 'New Title',
|
|
78
|
-
})
|
|
79
|
-
expect(result).toBe(false)
|
|
80
|
-
})
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
describe('deleteMemory', () => {
|
|
84
|
-
it('should delete a memory', async () => {
|
|
85
|
-
const memoryId = await memorySystem.createMemory(TEST_PROJECT_ID, {
|
|
86
|
-
title: 'To Delete',
|
|
87
|
-
content: 'Will be deleted',
|
|
88
|
-
tags: ['test'],
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
const deleted = await memorySystem.deleteMemory(TEST_PROJECT_ID, memoryId)
|
|
92
|
-
expect(deleted).toBe(true)
|
|
93
|
-
|
|
94
|
-
const memories = await memorySystem.getAllMemories(TEST_PROJECT_ID)
|
|
95
|
-
expect(memories.find((m) => m.id === memoryId)).toBeUndefined()
|
|
96
|
-
})
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
describe('findByTags', () => {
|
|
100
|
-
beforeEach(async () => {
|
|
101
|
-
await memorySystem.createMemory(TEST_PROJECT_ID, {
|
|
102
|
-
title: 'Memory 1',
|
|
103
|
-
content: 'Content 1',
|
|
104
|
-
tags: ['code_style', 'naming_convention'],
|
|
105
|
-
})
|
|
106
|
-
await memorySystem.createMemory(TEST_PROJECT_ID, {
|
|
107
|
-
title: 'Memory 2',
|
|
108
|
-
content: 'Content 2',
|
|
109
|
-
tags: ['architecture', 'naming_convention'],
|
|
110
|
-
})
|
|
111
|
-
await memorySystem.createMemory(TEST_PROJECT_ID, {
|
|
112
|
-
title: 'Memory 3',
|
|
113
|
-
content: 'Content 3',
|
|
114
|
-
tags: ['commit_style'],
|
|
115
|
-
})
|
|
116
|
-
})
|
|
117
|
-
|
|
118
|
-
it('should find memories with ANY tag (OR)', async () => {
|
|
119
|
-
const results = await memorySystem.findByTags(
|
|
120
|
-
TEST_PROJECT_ID,
|
|
121
|
-
['code_style', 'architecture'],
|
|
122
|
-
false
|
|
123
|
-
)
|
|
124
|
-
expect(results.length).toBe(2)
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
it('should find memories with ALL tags (AND)', async () => {
|
|
128
|
-
const results = await memorySystem.findByTags(
|
|
129
|
-
TEST_PROJECT_ID,
|
|
130
|
-
['naming_convention', 'architecture'],
|
|
131
|
-
true
|
|
132
|
-
)
|
|
133
|
-
expect(results.length).toBe(1)
|
|
134
|
-
expect(results[0].title).toBe('Memory 2')
|
|
135
|
-
})
|
|
136
|
-
})
|
|
137
|
-
|
|
138
|
-
describe('searchMemories', () => {
|
|
139
|
-
beforeEach(async () => {
|
|
140
|
-
await memorySystem.createMemory(TEST_PROJECT_ID, {
|
|
141
|
-
title: 'React Hooks Pattern',
|
|
142
|
-
content: 'Use custom hooks for reusable logic',
|
|
143
|
-
tags: ['code_style'],
|
|
144
|
-
})
|
|
145
|
-
await memorySystem.createMemory(TEST_PROJECT_ID, {
|
|
146
|
-
title: 'API Design',
|
|
147
|
-
content: 'REST endpoints follow /api/v1 pattern',
|
|
148
|
-
tags: ['architecture'],
|
|
149
|
-
})
|
|
150
|
-
})
|
|
151
|
-
|
|
152
|
-
it('should search by title', async () => {
|
|
153
|
-
const results = await memorySystem.searchMemories(TEST_PROJECT_ID, 'React')
|
|
154
|
-
expect(results.length).toBe(1)
|
|
155
|
-
expect(results[0].title).toContain('React')
|
|
156
|
-
})
|
|
157
|
-
|
|
158
|
-
it('should search by content', async () => {
|
|
159
|
-
const results = await memorySystem.searchMemories(TEST_PROJECT_ID, 'endpoints')
|
|
160
|
-
expect(results.length).toBe(1)
|
|
161
|
-
expect(results[0].content).toContain('endpoints')
|
|
162
|
-
})
|
|
163
|
-
|
|
164
|
-
it('should be case insensitive', async () => {
|
|
165
|
-
const results = await memorySystem.searchMemories(TEST_PROJECT_ID, 'HOOKS')
|
|
166
|
-
expect(results.length).toBe(1)
|
|
167
|
-
})
|
|
168
|
-
})
|
|
169
|
-
|
|
170
|
-
describe('getRelevantMemories', () => {
|
|
171
|
-
beforeEach(async () => {
|
|
172
|
-
await memorySystem.createMemory(TEST_PROJECT_ID, {
|
|
173
|
-
title: 'Commit Style',
|
|
174
|
-
content: 'Use conventional commits',
|
|
175
|
-
tags: ['commit_style', 'ship_workflow'],
|
|
176
|
-
userTriggered: true,
|
|
177
|
-
})
|
|
178
|
-
await memorySystem.createMemory(TEST_PROJECT_ID, {
|
|
179
|
-
title: 'Test Behavior',
|
|
180
|
-
content: 'Run tests before shipping',
|
|
181
|
-
tags: ['test_behavior', 'ship_workflow'],
|
|
182
|
-
})
|
|
183
|
-
await memorySystem.createMemory(TEST_PROJECT_ID, {
|
|
184
|
-
title: 'Code Style',
|
|
185
|
-
content: 'Use TypeScript strict mode',
|
|
186
|
-
tags: ['code_style'],
|
|
187
|
-
})
|
|
188
|
-
})
|
|
189
|
-
|
|
190
|
-
it('should return memories relevant to ship command', async () => {
|
|
191
|
-
const context = { commandName: 'ship', params: {} }
|
|
192
|
-
const results = await memorySystem.getRelevantMemories(TEST_PROJECT_ID, context, 5)
|
|
193
|
-
|
|
194
|
-
expect(results.length).toBeGreaterThan(0)
|
|
195
|
-
const hasRelevantTags = results.some(
|
|
196
|
-
(m) => m.tags.includes('commit_style') || m.tags.includes('ship_workflow')
|
|
197
|
-
)
|
|
198
|
-
expect(hasRelevantTags).toBe(true)
|
|
199
|
-
})
|
|
200
|
-
|
|
201
|
-
it('should prioritize user triggered memories', async () => {
|
|
202
|
-
const context = { commandName: 'ship', params: {} }
|
|
203
|
-
const results = await memorySystem.getRelevantMemories(TEST_PROJECT_ID, context, 5)
|
|
204
|
-
|
|
205
|
-
const userTriggeredIndex = results.findIndex((m) => m.userTriggered)
|
|
206
|
-
expect(userTriggeredIndex).toBeLessThanOrEqual(1)
|
|
207
|
-
})
|
|
208
|
-
|
|
209
|
-
it('should limit results', async () => {
|
|
210
|
-
const context = { commandName: 'ship', params: {} }
|
|
211
|
-
const results = await memorySystem.getRelevantMemories(TEST_PROJECT_ID, context, 1)
|
|
212
|
-
expect(results.length).toBeLessThanOrEqual(1)
|
|
213
|
-
})
|
|
214
|
-
})
|
|
215
|
-
|
|
216
|
-
describe('autoRemember', () => {
|
|
217
|
-
it('should create memory from user decision', async () => {
|
|
218
|
-
await memorySystem.autoRemember(
|
|
219
|
-
TEST_PROJECT_ID,
|
|
220
|
-
'commit_footer',
|
|
221
|
-
'prjct',
|
|
222
|
-
'User chose prjct footer'
|
|
223
|
-
)
|
|
224
|
-
|
|
225
|
-
const memories = await memorySystem.getAllMemories(TEST_PROJECT_ID)
|
|
226
|
-
expect(memories.length).toBe(1)
|
|
227
|
-
expect(memories[0].content).toContain('commit_footer: prjct')
|
|
228
|
-
expect(memories[0].tags).toContain('commit_style')
|
|
229
|
-
expect(memories[0].userTriggered).toBe(true)
|
|
230
|
-
})
|
|
231
|
-
|
|
232
|
-
it('should update existing memory instead of creating duplicate', async () => {
|
|
233
|
-
await memorySystem.autoRemember(TEST_PROJECT_ID, 'commit_footer', 'prjct', 'First choice')
|
|
234
|
-
await memorySystem.autoRemember(TEST_PROJECT_ID, 'commit_footer', 'claude', 'Changed mind')
|
|
235
|
-
|
|
236
|
-
const memories = await memorySystem.getAllMemories(TEST_PROJECT_ID)
|
|
237
|
-
expect(memories.length).toBe(1)
|
|
238
|
-
expect(memories[0].content).toContain('commit_footer: claude')
|
|
239
|
-
})
|
|
240
|
-
})
|
|
241
|
-
|
|
242
|
-
describe('getMemoryStats', () => {
|
|
243
|
-
it('should return memory statistics', async () => {
|
|
244
|
-
await memorySystem.createMemory(TEST_PROJECT_ID, {
|
|
245
|
-
title: 'Memory 1',
|
|
246
|
-
content: 'Content 1',
|
|
247
|
-
tags: ['code_style'],
|
|
248
|
-
userTriggered: true,
|
|
249
|
-
})
|
|
250
|
-
await memorySystem.createMemory(TEST_PROJECT_ID, {
|
|
251
|
-
title: 'Memory 2',
|
|
252
|
-
content: 'Content 2',
|
|
253
|
-
tags: ['code_style', 'architecture'],
|
|
254
|
-
})
|
|
255
|
-
|
|
256
|
-
const stats = await memorySystem.getMemoryStats(TEST_PROJECT_ID)
|
|
257
|
-
|
|
258
|
-
expect(stats.totalMemories).toBe(2)
|
|
259
|
-
expect(stats.userTriggered).toBe(1)
|
|
260
|
-
expect(stats.tagCounts.code_style).toBe(2)
|
|
261
|
-
expect(stats.tagCounts.architecture).toBe(1)
|
|
262
|
-
})
|
|
263
|
-
})
|
|
264
|
-
|
|
265
|
-
afterEach(async () => {
|
|
266
|
-
try {
|
|
267
|
-
const testPath = pathManager.getGlobalProjectPath(TEST_PROJECT_ID)
|
|
268
|
-
await fs.rm(testPath, { recursive: true, force: true })
|
|
269
|
-
} catch (_error) {
|
|
270
|
-
// Ignore cleanup errors
|
|
271
|
-
}
|
|
272
|
-
})
|
|
273
|
-
|
|
274
|
-
afterAll(async () => {
|
|
275
|
-
try {
|
|
276
|
-
await fs.rm(TEST_GLOBAL_BASE_DIR, { recursive: true, force: true })
|
|
277
|
-
} catch (_error) {
|
|
278
|
-
// Ignore cleanup errors
|
|
279
|
-
}
|
|
280
|
-
})
|
|
281
|
-
})
|
|
@@ -1,386 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Plan Mode Tests
|
|
3
|
-
* P3.4: Plan Mode + Approval Flow
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { beforeEach, describe, expect, it } from 'bun:test'
|
|
7
|
-
import planMode, { PLAN_STATUS } from '../../agentic/plan-mode'
|
|
8
|
-
import type { ApprovalContext, ProposedPlan } from '../../types'
|
|
9
|
-
|
|
10
|
-
// Helper to create complete ProposedPlan objects
|
|
11
|
-
const createPlan = (overrides: Partial<ProposedPlan> = {}): ProposedPlan => ({
|
|
12
|
-
summary: 'Test summary',
|
|
13
|
-
approach: 'Test approach',
|
|
14
|
-
steps: [],
|
|
15
|
-
affectedFiles: [],
|
|
16
|
-
...overrides,
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
// Helper to create complete ApprovalContext objects
|
|
20
|
-
const createApprovalContext = (overrides: Partial<ApprovalContext> = {}): ApprovalContext => ({
|
|
21
|
-
changedFiles: [],
|
|
22
|
-
filesToDelete: [],
|
|
23
|
-
operation: 'modify_files',
|
|
24
|
-
warnings: [],
|
|
25
|
-
...overrides,
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
describe('PlanMode P3.4', () => {
|
|
29
|
-
const TEST_PROJECT_ID = 'test-plan-mode'
|
|
30
|
-
|
|
31
|
-
beforeEach(() => {
|
|
32
|
-
planMode.activePlans.clear()
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
describe('requiresPlanning', () => {
|
|
36
|
-
it('should return true for feature command', () => {
|
|
37
|
-
expect(planMode.requiresPlanning('feature')).toBe(true)
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
it('should return true for spec command', () => {
|
|
41
|
-
expect(planMode.requiresPlanning('spec')).toBe(true)
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
it('should return false for now command', () => {
|
|
45
|
-
expect(planMode.requiresPlanning('now')).toBe(false)
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
it('should return false for done command', () => {
|
|
49
|
-
expect(planMode.requiresPlanning('done')).toBe(false)
|
|
50
|
-
})
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
describe('isDestructive', () => {
|
|
54
|
-
it('should return true for ship command', () => {
|
|
55
|
-
expect(planMode.isDestructive('ship')).toBe(true)
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
it('should return true for cleanup command', () => {
|
|
59
|
-
expect(planMode.isDestructive('cleanup')).toBe(true)
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
it('should return false for feature command', () => {
|
|
63
|
-
expect(planMode.isDestructive('feature')).toBe(false)
|
|
64
|
-
})
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
describe('isToolAllowedInPlanning', () => {
|
|
68
|
-
it('should allow Read in planning mode', () => {
|
|
69
|
-
expect(planMode.isToolAllowedInPlanning('Read')).toBe(true)
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
it('should allow Glob in planning mode', () => {
|
|
73
|
-
expect(planMode.isToolAllowedInPlanning('Glob')).toBe(true)
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
it('should not allow Write in planning mode', () => {
|
|
77
|
-
expect(planMode.isToolAllowedInPlanning('Write')).toBe(false)
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
it('should not allow Bash in planning mode', () => {
|
|
81
|
-
expect(planMode.isToolAllowedInPlanning('Bash')).toBe(false)
|
|
82
|
-
})
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
describe('getAllowedTools', () => {
|
|
86
|
-
it('should filter to read-only tools in planning mode', () => {
|
|
87
|
-
const templateTools = ['Read', 'Write', 'Glob', 'Bash', 'Grep']
|
|
88
|
-
const allowed = planMode.getAllowedTools(true, templateTools)
|
|
89
|
-
|
|
90
|
-
expect(allowed).toContain('Read')
|
|
91
|
-
expect(allowed).toContain('Glob')
|
|
92
|
-
expect(allowed).toContain('Grep')
|
|
93
|
-
expect(allowed).not.toContain('Write')
|
|
94
|
-
expect(allowed).not.toContain('Bash')
|
|
95
|
-
})
|
|
96
|
-
|
|
97
|
-
it('should return all template tools when not in planning mode', () => {
|
|
98
|
-
const templateTools = ['Read', 'Write', 'Glob', 'Bash']
|
|
99
|
-
const allowed = planMode.getAllowedTools(false, templateTools)
|
|
100
|
-
|
|
101
|
-
expect(allowed).toEqual(templateTools)
|
|
102
|
-
})
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
describe('startPlanning', () => {
|
|
106
|
-
it('should create a new plan with correct initial state', () => {
|
|
107
|
-
const plan = planMode.startPlanning(TEST_PROJECT_ID, 'feature', {
|
|
108
|
-
description: 'Add dark mode',
|
|
109
|
-
})
|
|
110
|
-
|
|
111
|
-
// UUID format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
|
112
|
-
expect(plan.id).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i)
|
|
113
|
-
expect(plan.projectId).toBe(TEST_PROJECT_ID)
|
|
114
|
-
expect(plan.command).toBe('feature')
|
|
115
|
-
expect(plan.status).toBe(PLAN_STATUS.GATHERING)
|
|
116
|
-
expect(plan.gatheredInfo).toEqual([])
|
|
117
|
-
})
|
|
118
|
-
|
|
119
|
-
it('should store plan in activePlans', () => {
|
|
120
|
-
planMode.startPlanning(TEST_PROJECT_ID, 'feature', {})
|
|
121
|
-
|
|
122
|
-
expect(planMode.getActivePlan(TEST_PROJECT_ID)).not.toBeNull()
|
|
123
|
-
})
|
|
124
|
-
})
|
|
125
|
-
|
|
126
|
-
describe('isInPlanningMode', () => {
|
|
127
|
-
it('should return true when gathering info', () => {
|
|
128
|
-
planMode.startPlanning(TEST_PROJECT_ID, 'feature', {})
|
|
129
|
-
|
|
130
|
-
expect(planMode.isInPlanningMode(TEST_PROJECT_ID)).toBe(true)
|
|
131
|
-
})
|
|
132
|
-
|
|
133
|
-
it('should return true when pending approval', () => {
|
|
134
|
-
planMode.startPlanning(TEST_PROJECT_ID, 'feature', {})
|
|
135
|
-
planMode.proposePlan(TEST_PROJECT_ID, createPlan())
|
|
136
|
-
|
|
137
|
-
expect(planMode.isInPlanningMode(TEST_PROJECT_ID)).toBe(true)
|
|
138
|
-
})
|
|
139
|
-
|
|
140
|
-
it('should return false when no active plan', () => {
|
|
141
|
-
expect(planMode.isInPlanningMode('non-existent-project')).toBe(false)
|
|
142
|
-
})
|
|
143
|
-
|
|
144
|
-
it('should return false when plan is executing', () => {
|
|
145
|
-
planMode.startPlanning(TEST_PROJECT_ID, 'feature', {})
|
|
146
|
-
planMode.proposePlan(TEST_PROJECT_ID, createPlan({ steps: [{ description: 'Step 1' }] }))
|
|
147
|
-
planMode.approvePlan(TEST_PROJECT_ID)
|
|
148
|
-
planMode.startExecution(TEST_PROJECT_ID)
|
|
149
|
-
|
|
150
|
-
expect(planMode.isInPlanningMode(TEST_PROJECT_ID)).toBe(false)
|
|
151
|
-
})
|
|
152
|
-
})
|
|
153
|
-
|
|
154
|
-
describe('recordGatheredInfo', () => {
|
|
155
|
-
it('should add info to gatheredInfo array', () => {
|
|
156
|
-
planMode.startPlanning(TEST_PROJECT_ID, 'feature', {})
|
|
157
|
-
planMode.recordGatheredInfo(TEST_PROJECT_ID, {
|
|
158
|
-
type: 'file_content',
|
|
159
|
-
source: 'src/index.js',
|
|
160
|
-
data: 'content',
|
|
161
|
-
gatheredAt: new Date().toISOString(),
|
|
162
|
-
})
|
|
163
|
-
|
|
164
|
-
const plan = planMode.getActivePlan(TEST_PROJECT_ID)
|
|
165
|
-
expect(plan!.gatheredInfo.length).toBe(1)
|
|
166
|
-
expect(plan!.gatheredInfo[0].type).toBe('file_content')
|
|
167
|
-
})
|
|
168
|
-
})
|
|
169
|
-
|
|
170
|
-
describe('proposePlan', () => {
|
|
171
|
-
it('should set status to pending approval', () => {
|
|
172
|
-
planMode.startPlanning(TEST_PROJECT_ID, 'feature', {})
|
|
173
|
-
planMode.proposePlan(
|
|
174
|
-
TEST_PROJECT_ID,
|
|
175
|
-
createPlan({
|
|
176
|
-
summary: 'Add dark mode feature',
|
|
177
|
-
approach: 'CSS variables with theme context',
|
|
178
|
-
steps: [{ description: 'Create theme context' }, { description: 'Add toggle' }],
|
|
179
|
-
})
|
|
180
|
-
)
|
|
181
|
-
|
|
182
|
-
const plan = planMode.getActivePlan(TEST_PROJECT_ID)
|
|
183
|
-
expect(plan!.status).toBe(PLAN_STATUS.PENDING_APPROVAL)
|
|
184
|
-
})
|
|
185
|
-
|
|
186
|
-
it('should return formatted plan for display', () => {
|
|
187
|
-
planMode.startPlanning(TEST_PROJECT_ID, 'feature', {})
|
|
188
|
-
const formatted = planMode.proposePlan(
|
|
189
|
-
TEST_PROJECT_ID,
|
|
190
|
-
createPlan({
|
|
191
|
-
summary: 'Test plan',
|
|
192
|
-
approach: 'Test approach',
|
|
193
|
-
steps: [{ description: 'Step 1' }],
|
|
194
|
-
})
|
|
195
|
-
)
|
|
196
|
-
|
|
197
|
-
expect(formatted!.summary).toBe('Test plan')
|
|
198
|
-
expect(formatted!.approach).toBe('Test approach')
|
|
199
|
-
expect(formatted!.requiresConfirmation).toBe(true)
|
|
200
|
-
})
|
|
201
|
-
})
|
|
202
|
-
|
|
203
|
-
describe('approvePlan', () => {
|
|
204
|
-
it('should change status to approved', () => {
|
|
205
|
-
planMode.startPlanning(TEST_PROJECT_ID, 'feature', {})
|
|
206
|
-
planMode.proposePlan(TEST_PROJECT_ID, createPlan({ steps: [{ description: 'Step 1' }] }))
|
|
207
|
-
const result = planMode.approvePlan(TEST_PROJECT_ID)
|
|
208
|
-
|
|
209
|
-
expect(result!.approved).toBe(true)
|
|
210
|
-
const plan = planMode.getActivePlan(TEST_PROJECT_ID)
|
|
211
|
-
expect(plan!.status).toBe(PLAN_STATUS.APPROVED)
|
|
212
|
-
})
|
|
213
|
-
|
|
214
|
-
it('should convert proposed steps to executable steps', () => {
|
|
215
|
-
planMode.startPlanning(TEST_PROJECT_ID, 'feature', {})
|
|
216
|
-
planMode.proposePlan(
|
|
217
|
-
TEST_PROJECT_ID,
|
|
218
|
-
createPlan({
|
|
219
|
-
steps: [{ description: 'Step 1' }, { description: 'Step 2' }],
|
|
220
|
-
})
|
|
221
|
-
)
|
|
222
|
-
const result = planMode.approvePlan(TEST_PROJECT_ID)
|
|
223
|
-
|
|
224
|
-
expect(result!.steps.length).toBe(2)
|
|
225
|
-
expect(result!.steps[0].status).toBe('pending')
|
|
226
|
-
})
|
|
227
|
-
|
|
228
|
-
it('should return null if not pending approval', () => {
|
|
229
|
-
planMode.startPlanning(TEST_PROJECT_ID, 'feature', {})
|
|
230
|
-
const result = planMode.approvePlan(TEST_PROJECT_ID)
|
|
231
|
-
|
|
232
|
-
expect(result).toBeNull()
|
|
233
|
-
})
|
|
234
|
-
})
|
|
235
|
-
|
|
236
|
-
describe('rejectPlan', () => {
|
|
237
|
-
it('should mark plan as rejected', () => {
|
|
238
|
-
planMode.startPlanning(TEST_PROJECT_ID, 'feature', {})
|
|
239
|
-
planMode.proposePlan(TEST_PROJECT_ID, createPlan())
|
|
240
|
-
const result = planMode.rejectPlan(TEST_PROJECT_ID, 'Not the right approach')
|
|
241
|
-
|
|
242
|
-
expect(result!.rejected).toBe(true)
|
|
243
|
-
expect(result!.reason).toBe('Not the right approach')
|
|
244
|
-
})
|
|
245
|
-
|
|
246
|
-
it('should clear active plan after rejection', () => {
|
|
247
|
-
planMode.startPlanning(TEST_PROJECT_ID, 'feature', {})
|
|
248
|
-
planMode.proposePlan(TEST_PROJECT_ID, createPlan())
|
|
249
|
-
planMode.rejectPlan(TEST_PROJECT_ID)
|
|
250
|
-
|
|
251
|
-
expect(planMode.getActivePlan(TEST_PROJECT_ID)).toBeNull()
|
|
252
|
-
})
|
|
253
|
-
})
|
|
254
|
-
|
|
255
|
-
describe('execution flow', () => {
|
|
256
|
-
beforeEach(() => {
|
|
257
|
-
planMode.startPlanning(TEST_PROJECT_ID, 'feature', {})
|
|
258
|
-
planMode.proposePlan(
|
|
259
|
-
TEST_PROJECT_ID,
|
|
260
|
-
createPlan({
|
|
261
|
-
steps: [
|
|
262
|
-
{ description: 'Step 1', tool: 'Write' },
|
|
263
|
-
{ description: 'Step 2', tool: 'Bash' },
|
|
264
|
-
],
|
|
265
|
-
})
|
|
266
|
-
)
|
|
267
|
-
planMode.approvePlan(TEST_PROJECT_ID)
|
|
268
|
-
})
|
|
269
|
-
|
|
270
|
-
it('should start execution and return first step', () => {
|
|
271
|
-
const step = planMode.startExecution(TEST_PROJECT_ID)
|
|
272
|
-
|
|
273
|
-
expect(step!.stepNumber).toBe(1)
|
|
274
|
-
expect(step!.totalSteps).toBe(2)
|
|
275
|
-
expect(step!.progress).toBe(0)
|
|
276
|
-
})
|
|
277
|
-
|
|
278
|
-
it('should advance to next step on completion', () => {
|
|
279
|
-
planMode.startExecution(TEST_PROJECT_ID)
|
|
280
|
-
const nextStep = planMode.completeStep(TEST_PROJECT_ID, { success: true })
|
|
281
|
-
|
|
282
|
-
expect(nextStep!.stepNumber).toBe(2)
|
|
283
|
-
expect(nextStep!.progress).toBe(50)
|
|
284
|
-
})
|
|
285
|
-
|
|
286
|
-
it('should complete plan when all steps done', () => {
|
|
287
|
-
planMode.startExecution(TEST_PROJECT_ID)
|
|
288
|
-
planMode.completeStep(TEST_PROJECT_ID)
|
|
289
|
-
const result = planMode.completeStep(TEST_PROJECT_ID)
|
|
290
|
-
|
|
291
|
-
expect(result).toBeNull()
|
|
292
|
-
expect(planMode.getActivePlan(TEST_PROJECT_ID)).toBeNull()
|
|
293
|
-
})
|
|
294
|
-
})
|
|
295
|
-
|
|
296
|
-
describe('abortPlan', () => {
|
|
297
|
-
it('should abort and clear active plan', () => {
|
|
298
|
-
planMode.startPlanning(TEST_PROJECT_ID, 'feature', {})
|
|
299
|
-
planMode.proposePlan(TEST_PROJECT_ID, createPlan({ steps: [{ description: 'Step 1' }] }))
|
|
300
|
-
planMode.approvePlan(TEST_PROJECT_ID)
|
|
301
|
-
planMode.startExecution(TEST_PROJECT_ID)
|
|
302
|
-
|
|
303
|
-
const result = planMode.abortPlan(TEST_PROJECT_ID, 'User cancelled')
|
|
304
|
-
|
|
305
|
-
expect(result!.aborted).toBe(true)
|
|
306
|
-
expect(result!.reason).toBe('User cancelled')
|
|
307
|
-
expect(planMode.getActivePlan(TEST_PROJECT_ID)).toBeNull()
|
|
308
|
-
})
|
|
309
|
-
})
|
|
310
|
-
|
|
311
|
-
describe('generateApprovalPrompt', () => {
|
|
312
|
-
it('should generate ship approval prompt', () => {
|
|
313
|
-
const prompt = planMode.generateApprovalPrompt(
|
|
314
|
-
'ship',
|
|
315
|
-
createApprovalContext({
|
|
316
|
-
branch: 'feature/dark-mode',
|
|
317
|
-
changedFiles: [
|
|
318
|
-
{ path: 'a.js', action: 'modify' },
|
|
319
|
-
{ path: 'b.js', action: 'modify' },
|
|
320
|
-
],
|
|
321
|
-
commitMessage: 'Add dark mode',
|
|
322
|
-
operation: 'git_push',
|
|
323
|
-
})
|
|
324
|
-
)
|
|
325
|
-
|
|
326
|
-
expect(prompt.title).toBe('Ship Confirmation')
|
|
327
|
-
expect(prompt.details).toContain('Branch: feature/dark-mode')
|
|
328
|
-
expect(prompt.options.length).toBe(3)
|
|
329
|
-
})
|
|
330
|
-
|
|
331
|
-
it('should generate cleanup approval prompt', () => {
|
|
332
|
-
const prompt = planMode.generateApprovalPrompt(
|
|
333
|
-
'cleanup',
|
|
334
|
-
createApprovalContext({
|
|
335
|
-
filesToDelete: ['temp.js'],
|
|
336
|
-
linesOfCode: 50,
|
|
337
|
-
operation: 'delete_files',
|
|
338
|
-
})
|
|
339
|
-
)
|
|
340
|
-
|
|
341
|
-
expect(prompt.title).toBe('Cleanup Confirmation')
|
|
342
|
-
expect(prompt.message).toContain('delete')
|
|
343
|
-
})
|
|
344
|
-
|
|
345
|
-
it('should generate default prompt for unknown commands', () => {
|
|
346
|
-
const prompt = planMode.generateApprovalPrompt('unknown', createApprovalContext())
|
|
347
|
-
|
|
348
|
-
expect(prompt.title).toBe('Confirmation Required')
|
|
349
|
-
expect(prompt.options.length).toBe(2)
|
|
350
|
-
})
|
|
351
|
-
})
|
|
352
|
-
|
|
353
|
-
describe('formatStatus', () => {
|
|
354
|
-
it('should format gathering status', () => {
|
|
355
|
-
planMode.startPlanning(TEST_PROJECT_ID, 'feature', {})
|
|
356
|
-
const status = planMode.formatStatus(TEST_PROJECT_ID)
|
|
357
|
-
|
|
358
|
-
expect(status).toContain('🔍')
|
|
359
|
-
expect(status).toContain('feature')
|
|
360
|
-
expect(status).toContain('gathering')
|
|
361
|
-
})
|
|
362
|
-
|
|
363
|
-
it('should show progress during execution', () => {
|
|
364
|
-
planMode.startPlanning(TEST_PROJECT_ID, 'feature', {})
|
|
365
|
-
planMode.proposePlan(
|
|
366
|
-
TEST_PROJECT_ID,
|
|
367
|
-
createPlan({
|
|
368
|
-
steps: [{ description: 'Step 1' }, { description: 'Step 2' }],
|
|
369
|
-
})
|
|
370
|
-
)
|
|
371
|
-
planMode.approvePlan(TEST_PROJECT_ID)
|
|
372
|
-
planMode.startExecution(TEST_PROJECT_ID)
|
|
373
|
-
|
|
374
|
-
const status = planMode.formatStatus(TEST_PROJECT_ID)
|
|
375
|
-
|
|
376
|
-
expect(status).toContain('⚡')
|
|
377
|
-
expect(status).toContain('Progress')
|
|
378
|
-
})
|
|
379
|
-
|
|
380
|
-
it('should return message for no active plan', () => {
|
|
381
|
-
const status = planMode.formatStatus('non-existent')
|
|
382
|
-
|
|
383
|
-
expect(status).toBe('No active plan')
|
|
384
|
-
})
|
|
385
|
-
})
|
|
386
|
-
})
|