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,542 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Uninstall Command
|
|
3
|
-
*
|
|
4
|
-
* Complete system removal of prjct-cli.
|
|
5
|
-
* Handles cleanup of all prjct files, configurations, and installations.
|
|
6
|
-
*
|
|
7
|
-
* @version 1.0.0
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { execSync } from 'node:child_process'
|
|
11
|
-
import fs from 'node:fs/promises'
|
|
12
|
-
import os from 'node:os'
|
|
13
|
-
import path from 'node:path'
|
|
14
|
-
import readline from 'node:readline'
|
|
15
|
-
import chalk from 'chalk'
|
|
16
|
-
import { getProviderPaths } from '../infrastructure/command-installer'
|
|
17
|
-
import pathManager from '../infrastructure/path-manager'
|
|
18
|
-
import type { CommandResult, UninstallOptions } from '../types'
|
|
19
|
-
import { getErrorMessage } from '../types/fs'
|
|
20
|
-
import { fileExists } from '../utils/fs-helpers'
|
|
21
|
-
import { PrjctCommandsBase } from './base'
|
|
22
|
-
|
|
23
|
-
// Markers for prjct section in CLAUDE.md
|
|
24
|
-
const PRJCT_START_MARKER = '<!-- prjct:start - DO NOT REMOVE THIS MARKER -->'
|
|
25
|
-
const PRJCT_END_MARKER = '<!-- prjct:end - DO NOT REMOVE THIS MARKER -->'
|
|
26
|
-
|
|
27
|
-
interface UninstallItem {
|
|
28
|
-
path: string
|
|
29
|
-
type: 'directory' | 'file' | 'section'
|
|
30
|
-
description: string
|
|
31
|
-
size?: number
|
|
32
|
-
count?: number
|
|
33
|
-
exists: boolean
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
interface InstallationInfo {
|
|
37
|
-
homebrew: boolean
|
|
38
|
-
npm: boolean
|
|
39
|
-
homebrewFormula?: string
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Get directory size recursively
|
|
44
|
-
*/
|
|
45
|
-
async function getDirectorySize(dirPath: string): Promise<number> {
|
|
46
|
-
let totalSize = 0
|
|
47
|
-
|
|
48
|
-
try {
|
|
49
|
-
const entries = await fs.readdir(dirPath, { withFileTypes: true })
|
|
50
|
-
|
|
51
|
-
for (const entry of entries) {
|
|
52
|
-
const entryPath = path.join(dirPath, entry.name)
|
|
53
|
-
|
|
54
|
-
if (entry.isDirectory()) {
|
|
55
|
-
totalSize += await getDirectorySize(entryPath)
|
|
56
|
-
} else {
|
|
57
|
-
try {
|
|
58
|
-
const stats = await fs.stat(entryPath)
|
|
59
|
-
totalSize += stats.size
|
|
60
|
-
} catch {
|
|
61
|
-
// Skip files we can't stat
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
} catch {
|
|
66
|
-
// Directory doesn't exist or can't be read
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
return totalSize
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Format bytes to human readable size
|
|
74
|
-
*/
|
|
75
|
-
function formatSize(bytes: number): string {
|
|
76
|
-
if (bytes === 0) return '0 B'
|
|
77
|
-
|
|
78
|
-
const units = ['B', 'KB', 'MB', 'GB']
|
|
79
|
-
const i = Math.floor(Math.log(bytes) / Math.log(1024))
|
|
80
|
-
const size = bytes / 1024 ** i
|
|
81
|
-
|
|
82
|
-
return `${size.toFixed(1)} ${units[i]}`
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Count items in a directory
|
|
87
|
-
*/
|
|
88
|
-
async function countDirectoryItems(dirPath: string): Promise<number> {
|
|
89
|
-
try {
|
|
90
|
-
const entries = await fs.readdir(dirPath, { withFileTypes: true })
|
|
91
|
-
return entries.filter((e) => e.isDirectory()).length
|
|
92
|
-
} catch {
|
|
93
|
-
return 0
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Detect installation method
|
|
99
|
-
*/
|
|
100
|
-
function detectInstallation(): InstallationInfo {
|
|
101
|
-
const info: InstallationInfo = {
|
|
102
|
-
homebrew: false,
|
|
103
|
-
npm: false,
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// Check Homebrew
|
|
107
|
-
try {
|
|
108
|
-
const result = execSync('brew list prjct-cli 2>/dev/null', { encoding: 'utf-8' })
|
|
109
|
-
if (result) {
|
|
110
|
-
info.homebrew = true
|
|
111
|
-
info.homebrewFormula = 'prjct-cli'
|
|
112
|
-
}
|
|
113
|
-
} catch {
|
|
114
|
-
// Not installed via Homebrew
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// Check npm global
|
|
118
|
-
try {
|
|
119
|
-
const result = execSync('npm list -g prjct-cli --depth=0 2>/dev/null', { encoding: 'utf-8' })
|
|
120
|
-
if (result.includes('prjct-cli')) {
|
|
121
|
-
info.npm = true
|
|
122
|
-
}
|
|
123
|
-
} catch {
|
|
124
|
-
// Not installed via npm
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
return info
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Gather all items to uninstall
|
|
132
|
-
*/
|
|
133
|
-
async function gatherUninstallItems(): Promise<UninstallItem[]> {
|
|
134
|
-
const items: UninstallItem[] = []
|
|
135
|
-
const providerPaths = getProviderPaths()
|
|
136
|
-
|
|
137
|
-
// 1. ~/.prjct-cli/ (main data directory)
|
|
138
|
-
const prjctCliPath = pathManager.getGlobalBasePath()
|
|
139
|
-
const prjctCliExists = await fileExists(prjctCliPath)
|
|
140
|
-
const projectCount = prjctCliExists
|
|
141
|
-
? await countDirectoryItems(path.join(prjctCliPath, 'projects'))
|
|
142
|
-
: 0
|
|
143
|
-
const prjctCliSize = prjctCliExists ? await getDirectorySize(prjctCliPath) : 0
|
|
144
|
-
|
|
145
|
-
items.push({
|
|
146
|
-
path: prjctCliPath,
|
|
147
|
-
type: 'directory',
|
|
148
|
-
description: `All project data${projectCount > 0 ? `, ${projectCount} project${projectCount > 1 ? 's' : ''}` : ''}`,
|
|
149
|
-
size: prjctCliSize,
|
|
150
|
-
count: projectCount,
|
|
151
|
-
exists: prjctCliExists,
|
|
152
|
-
})
|
|
153
|
-
|
|
154
|
-
// 2. ~/.claude/CLAUDE.md (prjct section only)
|
|
155
|
-
const claudeMdPath = path.join(providerPaths.claude.config, 'CLAUDE.md')
|
|
156
|
-
const claudeMdExists = await fileExists(claudeMdPath)
|
|
157
|
-
let hasPrjctSection = false
|
|
158
|
-
|
|
159
|
-
if (claudeMdExists) {
|
|
160
|
-
try {
|
|
161
|
-
const content = await fs.readFile(claudeMdPath, 'utf-8')
|
|
162
|
-
hasPrjctSection = content.includes(PRJCT_START_MARKER) && content.includes(PRJCT_END_MARKER)
|
|
163
|
-
} catch {
|
|
164
|
-
// Can't read file
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
items.push({
|
|
169
|
-
path: claudeMdPath,
|
|
170
|
-
type: 'section',
|
|
171
|
-
description: 'prjct section in CLAUDE.md',
|
|
172
|
-
exists: claudeMdExists && hasPrjctSection,
|
|
173
|
-
})
|
|
174
|
-
|
|
175
|
-
// 3. ~/.claude/commands/p/ (prjct commands)
|
|
176
|
-
const claudeCommandsPath = providerPaths.claude.commands
|
|
177
|
-
const claudeCommandsExists = await fileExists(claudeCommandsPath)
|
|
178
|
-
const claudeCommandsSize = claudeCommandsExists ? await getDirectorySize(claudeCommandsPath) : 0
|
|
179
|
-
|
|
180
|
-
items.push({
|
|
181
|
-
path: claudeCommandsPath,
|
|
182
|
-
type: 'directory',
|
|
183
|
-
description: 'Claude commands',
|
|
184
|
-
size: claudeCommandsSize,
|
|
185
|
-
exists: claudeCommandsExists,
|
|
186
|
-
})
|
|
187
|
-
|
|
188
|
-
// 4. ~/.claude/commands/p.md (router)
|
|
189
|
-
const claudeRouterPath = providerPaths.claude.router
|
|
190
|
-
const claudeRouterExists = await fileExists(claudeRouterPath)
|
|
191
|
-
|
|
192
|
-
items.push({
|
|
193
|
-
path: claudeRouterPath,
|
|
194
|
-
type: 'file',
|
|
195
|
-
description: 'Claude router',
|
|
196
|
-
exists: claudeRouterExists,
|
|
197
|
-
})
|
|
198
|
-
|
|
199
|
-
// 5. ~/.claude/prjct-statusline.sh (status line script)
|
|
200
|
-
const statusLinePath = path.join(providerPaths.claude.config, 'prjct-statusline.sh')
|
|
201
|
-
const statusLineExists = await fileExists(statusLinePath)
|
|
202
|
-
|
|
203
|
-
items.push({
|
|
204
|
-
path: statusLinePath,
|
|
205
|
-
type: 'file',
|
|
206
|
-
description: 'Status line script',
|
|
207
|
-
exists: statusLineExists,
|
|
208
|
-
})
|
|
209
|
-
|
|
210
|
-
// 6. ~/.gemini/commands/p.toml (Gemini router, if exists)
|
|
211
|
-
const geminiRouterPath = providerPaths.gemini.router
|
|
212
|
-
const geminiRouterExists = await fileExists(geminiRouterPath)
|
|
213
|
-
|
|
214
|
-
items.push({
|
|
215
|
-
path: geminiRouterPath,
|
|
216
|
-
type: 'file',
|
|
217
|
-
description: 'Gemini router',
|
|
218
|
-
exists: geminiRouterExists,
|
|
219
|
-
})
|
|
220
|
-
|
|
221
|
-
// 7. ~/.gemini/GEMINI.md (prjct section only, if exists)
|
|
222
|
-
const geminiMdPath = path.join(providerPaths.gemini.config, 'GEMINI.md')
|
|
223
|
-
const geminiMdExists = await fileExists(geminiMdPath)
|
|
224
|
-
let hasGeminiPrjctSection = false
|
|
225
|
-
|
|
226
|
-
if (geminiMdExists) {
|
|
227
|
-
try {
|
|
228
|
-
const content = await fs.readFile(geminiMdPath, 'utf-8')
|
|
229
|
-
hasGeminiPrjctSection =
|
|
230
|
-
content.includes(PRJCT_START_MARKER) && content.includes(PRJCT_END_MARKER)
|
|
231
|
-
} catch {
|
|
232
|
-
// Can't read file
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
if (geminiMdExists && hasGeminiPrjctSection) {
|
|
237
|
-
items.push({
|
|
238
|
-
path: geminiMdPath,
|
|
239
|
-
type: 'section',
|
|
240
|
-
description: 'prjct section in GEMINI.md',
|
|
241
|
-
exists: true,
|
|
242
|
-
})
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
return items
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
/**
|
|
249
|
-
* Remove prjct section from a markdown file
|
|
250
|
-
*/
|
|
251
|
-
async function removePrjctSection(filePath: string): Promise<boolean> {
|
|
252
|
-
try {
|
|
253
|
-
const content = await fs.readFile(filePath, 'utf-8')
|
|
254
|
-
|
|
255
|
-
if (!content.includes(PRJCT_START_MARKER) || !content.includes(PRJCT_END_MARKER)) {
|
|
256
|
-
return false
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
const startIndex = content.indexOf(PRJCT_START_MARKER)
|
|
260
|
-
const endIndex = content.indexOf(PRJCT_END_MARKER) + PRJCT_END_MARKER.length
|
|
261
|
-
|
|
262
|
-
// Remove the section and any trailing newlines
|
|
263
|
-
let newContent = content.substring(0, startIndex) + content.substring(endIndex)
|
|
264
|
-
newContent = newContent.replace(/\n{3,}/g, '\n\n').trim()
|
|
265
|
-
|
|
266
|
-
// If the file is now empty or just whitespace, delete it
|
|
267
|
-
if (!newContent || newContent.trim().length === 0) {
|
|
268
|
-
await fs.unlink(filePath)
|
|
269
|
-
} else {
|
|
270
|
-
await fs.writeFile(filePath, `${newContent}\n`, 'utf-8')
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
return true
|
|
274
|
-
} catch {
|
|
275
|
-
return false
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
/**
|
|
280
|
-
* Create backup of prjct data
|
|
281
|
-
*/
|
|
282
|
-
async function createBackup(): Promise<string | null> {
|
|
283
|
-
const homeDir = os.homedir()
|
|
284
|
-
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').substring(0, 19)
|
|
285
|
-
const backupDir = path.join(homeDir, `.prjct-backup-${timestamp}`)
|
|
286
|
-
|
|
287
|
-
try {
|
|
288
|
-
await fs.mkdir(backupDir, { recursive: true })
|
|
289
|
-
|
|
290
|
-
const prjctCliPath = pathManager.getGlobalBasePath()
|
|
291
|
-
|
|
292
|
-
if (await fileExists(prjctCliPath)) {
|
|
293
|
-
// Copy entire .prjct-cli directory
|
|
294
|
-
await copyDirectory(prjctCliPath, path.join(backupDir, '.prjct-cli'))
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
return backupDir
|
|
298
|
-
} catch {
|
|
299
|
-
return null
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
/**
|
|
304
|
-
* Recursively copy a directory
|
|
305
|
-
*/
|
|
306
|
-
async function copyDirectory(src: string, dest: string): Promise<void> {
|
|
307
|
-
await fs.mkdir(dest, { recursive: true })
|
|
308
|
-
const entries = await fs.readdir(src, { withFileTypes: true })
|
|
309
|
-
|
|
310
|
-
for (const entry of entries) {
|
|
311
|
-
const srcPath = path.join(src, entry.name)
|
|
312
|
-
const destPath = path.join(dest, entry.name)
|
|
313
|
-
|
|
314
|
-
if (entry.isDirectory()) {
|
|
315
|
-
await copyDirectory(srcPath, destPath)
|
|
316
|
-
} else {
|
|
317
|
-
await fs.copyFile(srcPath, destPath)
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
/**
|
|
323
|
-
* Perform the actual uninstallation
|
|
324
|
-
*/
|
|
325
|
-
async function performUninstall(
|
|
326
|
-
items: UninstallItem[],
|
|
327
|
-
installation: InstallationInfo,
|
|
328
|
-
options: UninstallOptions
|
|
329
|
-
): Promise<{ deleted: string[]; errors: string[] }> {
|
|
330
|
-
const deleted: string[] = []
|
|
331
|
-
const errors: string[] = []
|
|
332
|
-
|
|
333
|
-
for (const item of items) {
|
|
334
|
-
if (!item.exists) continue
|
|
335
|
-
|
|
336
|
-
try {
|
|
337
|
-
if (item.type === 'section') {
|
|
338
|
-
// Remove prjct section from file
|
|
339
|
-
const success = await removePrjctSection(item.path)
|
|
340
|
-
if (success) {
|
|
341
|
-
deleted.push(item.path)
|
|
342
|
-
}
|
|
343
|
-
} else if (item.type === 'directory') {
|
|
344
|
-
await fs.rm(item.path, { recursive: true, force: true })
|
|
345
|
-
deleted.push(item.path)
|
|
346
|
-
} else if (item.type === 'file') {
|
|
347
|
-
await fs.unlink(item.path)
|
|
348
|
-
deleted.push(item.path)
|
|
349
|
-
}
|
|
350
|
-
} catch (error) {
|
|
351
|
-
errors.push(`${item.path}: ${getErrorMessage(error)}`)
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
// Uninstall package managers
|
|
356
|
-
if (!options.keepPackage) {
|
|
357
|
-
if (installation.homebrew && installation.homebrewFormula) {
|
|
358
|
-
try {
|
|
359
|
-
if (!options.dryRun) {
|
|
360
|
-
execSync(`brew uninstall ${installation.homebrewFormula}`, { stdio: 'pipe' })
|
|
361
|
-
}
|
|
362
|
-
deleted.push('Homebrew: prjct-cli')
|
|
363
|
-
} catch (error) {
|
|
364
|
-
errors.push(`Homebrew: ${getErrorMessage(error)}`)
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
if (installation.npm) {
|
|
369
|
-
try {
|
|
370
|
-
if (!options.dryRun) {
|
|
371
|
-
execSync('npm uninstall -g prjct-cli', { stdio: 'pipe' })
|
|
372
|
-
}
|
|
373
|
-
deleted.push('npm: prjct-cli')
|
|
374
|
-
} catch (error) {
|
|
375
|
-
errors.push(`npm: ${getErrorMessage(error)}`)
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
return { deleted, errors }
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
/**
|
|
384
|
-
* Prompt user for confirmation
|
|
385
|
-
*/
|
|
386
|
-
async function promptConfirmation(message: string): Promise<boolean> {
|
|
387
|
-
const rl = readline.createInterface({
|
|
388
|
-
input: process.stdin,
|
|
389
|
-
output: process.stdout,
|
|
390
|
-
})
|
|
391
|
-
|
|
392
|
-
return new Promise((resolve) => {
|
|
393
|
-
rl.question(message, (answer) => {
|
|
394
|
-
rl.close()
|
|
395
|
-
resolve(answer.toLowerCase() === 'uninstall')
|
|
396
|
-
})
|
|
397
|
-
})
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
/**
|
|
401
|
-
* Main uninstall function
|
|
402
|
-
*/
|
|
403
|
-
export async function uninstall(
|
|
404
|
-
options: UninstallOptions = {},
|
|
405
|
-
_projectPath: string = process.cwd()
|
|
406
|
-
): Promise<CommandResult> {
|
|
407
|
-
const items = await gatherUninstallItems()
|
|
408
|
-
const installation = detectInstallation()
|
|
409
|
-
const existingItems = items.filter((i) => i.exists)
|
|
410
|
-
|
|
411
|
-
// Check if there's anything to uninstall
|
|
412
|
-
if (existingItems.length === 0 && !installation.homebrew && !installation.npm) {
|
|
413
|
-
console.log(chalk.yellow('\nNo prjct installation found.'))
|
|
414
|
-
return {
|
|
415
|
-
success: true,
|
|
416
|
-
message: 'Nothing to uninstall',
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
// Calculate total size
|
|
421
|
-
const totalSize = existingItems.reduce((sum, item) => sum + (item.size || 0), 0)
|
|
422
|
-
|
|
423
|
-
// Display warning and items
|
|
424
|
-
console.log('')
|
|
425
|
-
console.log(chalk.red.bold(' WARNING: This action is DANGEROUS and IRREVERSIBLE'))
|
|
426
|
-
console.log('')
|
|
427
|
-
console.log(chalk.white('The following will be permanently deleted:'))
|
|
428
|
-
console.log('')
|
|
429
|
-
|
|
430
|
-
for (const item of existingItems) {
|
|
431
|
-
const displayPath = pathManager.getDisplayPath(item.path)
|
|
432
|
-
let info = ''
|
|
433
|
-
|
|
434
|
-
if (item.type === 'section') {
|
|
435
|
-
info = chalk.dim('(section only)')
|
|
436
|
-
} else if (item.size) {
|
|
437
|
-
info = chalk.dim(`(${formatSize(item.size)})`)
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
console.log(` ${chalk.cyan(displayPath.padEnd(35))} ${info}`)
|
|
441
|
-
console.log(` ${chalk.dim(item.description)}`)
|
|
442
|
-
console.log('')
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
// Show package manager installations
|
|
446
|
-
if (installation.homebrew) {
|
|
447
|
-
console.log(` ${chalk.cyan('Homebrew'.padEnd(35))} ${chalk.dim('prjct-cli formula')}`)
|
|
448
|
-
console.log('')
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
if (installation.npm) {
|
|
452
|
-
console.log(` ${chalk.cyan('npm global'.padEnd(35))} ${chalk.dim('prjct-cli package')}`)
|
|
453
|
-
console.log('')
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
if (totalSize > 0) {
|
|
457
|
-
console.log(chalk.dim(` Total size: ${formatSize(totalSize)}`))
|
|
458
|
-
console.log('')
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
// Handle dry run
|
|
462
|
-
if (options.dryRun) {
|
|
463
|
-
console.log(chalk.yellow('Dry run - no changes made'))
|
|
464
|
-
return {
|
|
465
|
-
success: true,
|
|
466
|
-
message: 'Dry run complete',
|
|
467
|
-
itemsFound: existingItems.length,
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
// Handle backup
|
|
472
|
-
if (options.backup) {
|
|
473
|
-
console.log(chalk.blue('Creating backup...'))
|
|
474
|
-
const backupPath = await createBackup()
|
|
475
|
-
|
|
476
|
-
if (backupPath) {
|
|
477
|
-
console.log(chalk.green(`Backup created: ${pathManager.getDisplayPath(backupPath)}`))
|
|
478
|
-
console.log('')
|
|
479
|
-
} else {
|
|
480
|
-
console.log(chalk.yellow('Failed to create backup, continuing...'))
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
// Require confirmation unless --force
|
|
485
|
-
if (!options.force) {
|
|
486
|
-
console.log(chalk.yellow('Type "uninstall" to confirm:'))
|
|
487
|
-
const confirmed = await promptConfirmation('> ')
|
|
488
|
-
|
|
489
|
-
if (!confirmed) {
|
|
490
|
-
console.log(chalk.yellow('\nUninstall cancelled.'))
|
|
491
|
-
return {
|
|
492
|
-
success: false,
|
|
493
|
-
message: 'Uninstall cancelled by user',
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
// Perform uninstallation
|
|
499
|
-
console.log('')
|
|
500
|
-
console.log(chalk.blue('Removing prjct...'))
|
|
501
|
-
|
|
502
|
-
const { deleted, errors } = await performUninstall(items, installation, options)
|
|
503
|
-
|
|
504
|
-
// Report results
|
|
505
|
-
console.log('')
|
|
506
|
-
|
|
507
|
-
if (deleted.length > 0) {
|
|
508
|
-
console.log(chalk.green(`Removed ${deleted.length} items`))
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
if (errors.length > 0) {
|
|
512
|
-
console.log(chalk.yellow(`\n${errors.length} errors:`))
|
|
513
|
-
for (const error of errors) {
|
|
514
|
-
console.log(chalk.red(` - ${error}`))
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
console.log('')
|
|
519
|
-
console.log(chalk.green('prjct has been uninstalled.'))
|
|
520
|
-
console.log(chalk.dim('Thanks for using prjct! We hope to see you again.'))
|
|
521
|
-
console.log('')
|
|
522
|
-
|
|
523
|
-
return {
|
|
524
|
-
success: errors.length === 0,
|
|
525
|
-
message: `Removed ${deleted.length} items`,
|
|
526
|
-
deleted,
|
|
527
|
-
errors: errors.length > 0 ? errors : undefined,
|
|
528
|
-
}
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
/**
|
|
532
|
-
* UninstallCommands class for integration with command system
|
|
533
|
-
*/
|
|
534
|
-
export class UninstallCommands extends PrjctCommandsBase {
|
|
535
|
-
async uninstall(
|
|
536
|
-
options: UninstallOptions = {},
|
|
537
|
-
projectPath: string = process.cwd()
|
|
538
|
-
): Promise<CommandResult> {
|
|
539
|
-
// Uninstall doesn't require project init
|
|
540
|
-
return uninstall(options, projectPath)
|
|
541
|
-
}
|
|
542
|
-
}
|
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Velocity Commands: velocity
|
|
3
|
-
* Sprint-based velocity dashboard
|
|
4
|
-
*
|
|
5
|
-
* @see PRJ-296
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import chalk from 'chalk'
|
|
9
|
-
import { calculateVelocity, projectCompletion } from '../domain/velocity'
|
|
10
|
-
import outcomeRecorder from '../outcomes/recorder'
|
|
11
|
-
import type { VelocityConfig } from '../schemas/velocity'
|
|
12
|
-
import { DEFAULT_VELOCITY_CONFIG } from '../schemas/velocity'
|
|
13
|
-
import { velocityStorage } from '../storage/velocity-storage'
|
|
14
|
-
import type { CommandResult } from '../types'
|
|
15
|
-
import { getErrorMessage } from '../types/fs'
|
|
16
|
-
import { configManager, out, PrjctCommandsBase } from './base'
|
|
17
|
-
|
|
18
|
-
export class VelocityCommands extends PrjctCommandsBase {
|
|
19
|
-
/**
|
|
20
|
-
* prjct velocity - Velocity dashboard
|
|
21
|
-
*/
|
|
22
|
-
async velocity(
|
|
23
|
-
backlogPoints: string = '0',
|
|
24
|
-
projectPath: string = process.cwd()
|
|
25
|
-
): Promise<CommandResult> {
|
|
26
|
-
try {
|
|
27
|
-
const initResult = await this.ensureProjectInit(projectPath)
|
|
28
|
-
if (!initResult.success) return initResult
|
|
29
|
-
|
|
30
|
-
const projectId = await configManager.getProjectId(projectPath)
|
|
31
|
-
if (!projectId) {
|
|
32
|
-
out.failWithHint('NO_PROJECT_ID')
|
|
33
|
-
return { success: false, error: 'No project ID found' }
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// Load velocity config from project config (or defaults)
|
|
37
|
-
const config = await this.loadVelocityConfig(projectPath)
|
|
38
|
-
|
|
39
|
-
// Load all outcomes
|
|
40
|
-
const outcomes = await outcomeRecorder.getAll(projectId)
|
|
41
|
-
|
|
42
|
-
if (outcomes.length === 0) {
|
|
43
|
-
console.log(`\n${chalk.dim('No velocity data yet.')}`)
|
|
44
|
-
console.log(`${chalk.dim('Complete tasks with estimates to build velocity history.')}\n`)
|
|
45
|
-
return { success: true, message: 'No data' }
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Calculate velocity metrics
|
|
49
|
-
const metrics = calculateVelocity(outcomes, config)
|
|
50
|
-
|
|
51
|
-
// Save for context injection
|
|
52
|
-
await velocityStorage.saveMetrics(projectId, metrics)
|
|
53
|
-
|
|
54
|
-
// Render dashboard
|
|
55
|
-
console.log(
|
|
56
|
-
`\n${chalk.cyan('Sprint Velocity')} ${chalk.dim(`(last ${config.windowSize ?? 6} sprints)`)}`
|
|
57
|
-
)
|
|
58
|
-
console.log('═'.repeat(60))
|
|
59
|
-
|
|
60
|
-
// Sprint table
|
|
61
|
-
const recentSprints = metrics.sprints.slice(-(config.windowSize ?? 6))
|
|
62
|
-
for (const sprint of recentSprints) {
|
|
63
|
-
const accuracyColor =
|
|
64
|
-
sprint.estimationAccuracy >= 80
|
|
65
|
-
? chalk.green
|
|
66
|
-
: sprint.estimationAccuracy >= 60
|
|
67
|
-
? chalk.yellow
|
|
68
|
-
: chalk.red
|
|
69
|
-
console.log(
|
|
70
|
-
` Sprint ${String(sprint.sprintNumber).padStart(2)}: ${chalk.bold(`${sprint.pointsCompleted} pts`)} | ${sprint.tasksCompleted} tasks | accuracy: ${accuracyColor(`${sprint.estimationAccuracy}%`)}`
|
|
71
|
-
)
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
console.log('')
|
|
75
|
-
const trendIcon =
|
|
76
|
-
metrics.velocityTrend === 'improving'
|
|
77
|
-
? chalk.green('↑')
|
|
78
|
-
: metrics.velocityTrend === 'declining'
|
|
79
|
-
? chalk.red('↓')
|
|
80
|
-
: chalk.dim('→')
|
|
81
|
-
console.log(
|
|
82
|
-
` Average: ${chalk.bold(`${metrics.averageVelocity} pts/sprint`)} | Trend: ${trendIcon} ${metrics.velocityTrend}`
|
|
83
|
-
)
|
|
84
|
-
console.log(
|
|
85
|
-
` Estimation accuracy: ${chalk.bold(`${metrics.estimationAccuracy}%`)} ${chalk.dim(`(±${config.accuracyTolerance ?? 20}% tolerance)`)}`
|
|
86
|
-
)
|
|
87
|
-
|
|
88
|
-
// Patterns
|
|
89
|
-
if (metrics.underEstimated.length > 0 || metrics.overEstimated.length > 0) {
|
|
90
|
-
console.log(`\n ${chalk.dim('Patterns:')}`)
|
|
91
|
-
for (const p of metrics.underEstimated) {
|
|
92
|
-
console.log(
|
|
93
|
-
` ${chalk.yellow('⚠')} ${p.category} tasks underestimated by avg ${chalk.bold(`${p.avgVariance}%`)}`
|
|
94
|
-
)
|
|
95
|
-
}
|
|
96
|
-
for (const p of metrics.overEstimated) {
|
|
97
|
-
console.log(
|
|
98
|
-
` ${chalk.green('✓')} ${p.category} tasks estimated within ${chalk.bold(`${p.avgVariance}%`)}`
|
|
99
|
-
)
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// Projection (if backlog points provided)
|
|
104
|
-
const points = parseInt(backlogPoints, 10)
|
|
105
|
-
if (points > 0 && metrics.averageVelocity > 0) {
|
|
106
|
-
const projection = projectCompletion(points, metrics.averageVelocity, config)
|
|
107
|
-
const dateStr = projection.estimatedDate
|
|
108
|
-
? new Date(projection.estimatedDate).toLocaleDateString('en-US', {
|
|
109
|
-
month: 'short',
|
|
110
|
-
day: 'numeric',
|
|
111
|
-
year: 'numeric',
|
|
112
|
-
})
|
|
113
|
-
: 'unknown'
|
|
114
|
-
console.log(`\n ${chalk.dim('Projection:')}`)
|
|
115
|
-
console.log(` Backlog: ${chalk.bold(`${points} pts`)} remaining`)
|
|
116
|
-
console.log(
|
|
117
|
-
` At current velocity: ~${projection.sprints} sprints (${projection.sprints * (config.sprintLengthDays ?? 7)} days)`
|
|
118
|
-
)
|
|
119
|
-
console.log(` Estimated completion: ${chalk.bold(dateStr)}`)
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
console.log('═'.repeat(60))
|
|
123
|
-
console.log('')
|
|
124
|
-
|
|
125
|
-
return { success: true }
|
|
126
|
-
} catch (error) {
|
|
127
|
-
out.fail(getErrorMessage(error))
|
|
128
|
-
return { success: false, error: getErrorMessage(error) }
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Load velocity config from project or use defaults.
|
|
134
|
-
* Velocity config can be added to prjct.config.json as { velocity: { sprintLengthDays, ... } }
|
|
135
|
-
*/
|
|
136
|
-
private async loadVelocityConfig(projectPath: string): Promise<VelocityConfig> {
|
|
137
|
-
try {
|
|
138
|
-
const config = await configManager.readConfig(projectPath)
|
|
139
|
-
// Read velocity config from extended config (not typed in LocalConfig yet)
|
|
140
|
-
const raw = config as Record<string, unknown> | null
|
|
141
|
-
if (raw?.velocity && typeof raw.velocity === 'object') {
|
|
142
|
-
return { ...DEFAULT_VELOCITY_CONFIG, ...(raw.velocity as Partial<VelocityConfig>) }
|
|
143
|
-
}
|
|
144
|
-
} catch {
|
|
145
|
-
// Use defaults
|
|
146
|
-
}
|
|
147
|
-
return DEFAULT_VELOCITY_CONFIG
|
|
148
|
-
}
|
|
149
|
-
}
|