devflow-kit 1.8.3 → 2.0.1
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 +182 -7
- package/LICENSE +1 -1
- package/README.md +139 -219
- package/dist/cli/agents-view/index.js +9 -0
- package/dist/cli/agents-view/render.js +310 -0
- package/dist/cli/agents-view/state.js +423 -0
- package/dist/cli/agents-view/terminal.js +179 -0
- package/dist/cli/commands/agents.js +585 -0
- package/dist/cli/commands/ambient.js +231 -0
- package/dist/cli/commands/capture.js +133 -0
- package/dist/cli/commands/compliance-prompts.js +174 -0
- package/dist/cli/commands/compliance.js +337 -0
- package/dist/cli/commands/context.js +66 -0
- package/dist/cli/commands/debug.js +122 -0
- package/dist/cli/commands/flags.js +119 -0
- package/dist/cli/commands/hud.js +229 -0
- package/dist/cli/commands/init-seed.js +226 -0
- package/dist/cli/commands/init.js +1786 -0
- package/dist/cli/commands/knowledge/index.js +25 -0
- package/dist/cli/commands/knowledge/list.js +115 -0
- package/dist/cli/commands/knowledge/toggle.js +84 -0
- package/dist/cli/commands/learning.js +311 -0
- package/dist/cli/commands/legacy-hooks.js +40 -0
- package/dist/cli/commands/memory.js +349 -0
- package/dist/cli/commands/proxy.js +1435 -0
- package/dist/cli/commands/rules.js +334 -0
- package/dist/cli/commands/safe-delete.js +140 -0
- package/dist/cli/commands/security.js +179 -0
- package/dist/cli/commands/skills.js +140 -0
- package/dist/cli/commands/uninstall.js +1214 -0
- package/dist/cli.js +35 -10
- package/dist/commands/bug-analysis.md +400 -0
- package/dist/commands/code-review.md +403 -0
- package/dist/commands/debug.md +282 -0
- package/dist/commands/dynamic-build.md +972 -0
- package/dist/commands/dynamic-plan.md +383 -0
- package/dist/commands/dynamic-profile.md +206 -0
- package/dist/commands/dynamic-tickets.md +583 -0
- package/dist/commands/explore.md +208 -0
- package/dist/commands/implement.md +590 -0
- package/dist/commands/plan.md +570 -0
- package/dist/commands/release.md +206 -0
- package/dist/commands/research.md +212 -0
- package/dist/commands/resolve.md +731 -0
- package/dist/commands/self-review.md +251 -0
- package/dist/core/agent-frontmatter.js +209 -0
- package/dist/core/agent-models.js +556 -0
- package/dist/core/agent-state.js +44 -0
- package/dist/core/assets.js +39 -0
- package/dist/core/cache.js +205 -0
- package/dist/core/codex-auth-inspect.js +128 -0
- package/dist/core/compliance-compose.js +458 -0
- package/dist/core/compliance.js +165 -0
- package/dist/core/external-models.js +76 -0
- package/dist/core/feature-config.js +125 -0
- package/dist/core/flags.js +309 -0
- package/dist/core/fs-atomic.js +74 -0
- package/dist/core/git.js +61 -0
- package/dist/core/learning-queue-cleanup.js +92 -0
- package/dist/core/learning-tuning-config.js +78 -0
- package/dist/core/manifest.js +171 -0
- package/dist/core/migrations.js +330 -0
- package/dist/core/model-discovery.js +655 -0
- package/dist/core/observation-io.js +50 -0
- package/dist/core/observations.js +109 -0
- package/dist/core/orphan-sweep.js +92 -0
- package/dist/core/paths.js +48 -0
- package/dist/core/plugins.js +525 -0
- package/dist/core/project-paths.js +159 -0
- package/dist/core/proxy-log.js +165 -0
- package/dist/core/proxy-state.js +305 -0
- package/dist/core/safe-delete-install.js +191 -0
- package/dist/core/teammate-mode-cleanup.js +33 -0
- package/dist/hud/colors.js +13 -2
- package/dist/hud/components/config-counts.js +2 -2
- package/dist/hud/components/context-usage.js +2 -2
- package/dist/hud/components/learning-counts.js +92 -0
- package/dist/hud/components/session-cost.js +10 -2
- package/dist/hud/components/usage-quota.js +43 -8
- package/dist/hud/components/version-badge.js +14 -4
- package/dist/hud/config.js +4 -2
- package/dist/hud/cost-history.js +281 -0
- package/dist/hud/git.js +112 -71
- package/dist/hud/index.js +47 -4
- package/dist/hud/render.js +8 -20
- package/dist/hud/transcript.js +5 -6
- package/dist/targets/claude-code/claude-paths.js +106 -0
- package/dist/targets/claude-code/compliance-install.js +305 -0
- package/dist/targets/claude-code/hooks.js +9 -0
- package/dist/targets/claude-code/installer.js +458 -0
- package/dist/targets/claude-code/legacy.js +239 -0
- package/dist/targets/claude-code/post-install.js +971 -0
- package/package.json +23 -17
- package/src/assets/agents/code.md +244 -0
- package/src/assets/agents/design.md +113 -0
- package/src/assets/agents/diagnose.md +210 -0
- package/src/assets/agents/evaluate.md +117 -0
- package/src/assets/agents/git.md +938 -0
- package/src/assets/agents/knowledge.md +89 -0
- package/src/assets/agents/learning.md +203 -0
- package/src/assets/agents/research.md +134 -0
- package/src/assets/agents/review.md +220 -0
- package/src/assets/agents/scrutinize.md +95 -0
- package/src/assets/agents/simplify.md +108 -0
- package/src/assets/agents/skim.md +136 -0
- package/src/assets/agents/synthesize.md +402 -0
- package/src/assets/agents/test.md +155 -0
- package/src/assets/agents/triage.md +141 -0
- package/src/assets/agents/validate.md +103 -0
- package/src/assets/commands/_partials/_compliance.mds +5 -0
- package/src/assets/commands/_partials/_decisions.mds +20 -0
- package/src/assets/commands/_partials/_engine.mds +244 -0
- package/src/assets/commands/_partials/_factory.mds +216 -0
- package/src/assets/commands/_partials/_knowledge.mds +95 -0
- package/src/assets/commands/_partials/_plan_contract.mds +51 -0
- package/src/assets/commands/_partials/_preamble.mds +82 -0
- package/src/assets/commands/_partials/_publication.mds +7 -0
- package/src/assets/commands/_partials/_roster.mds +31 -0
- package/src/assets/commands/_partials/_ticket_template.mds +59 -0
- package/src/assets/commands/_partials/_wave.mds +123 -0
- package/src/assets/commands/bug-analysis.mds +353 -0
- package/src/assets/commands/code-review.mds +355 -0
- package/src/assets/commands/debug.mds +224 -0
- package/src/assets/commands/dynamic-build.mds +534 -0
- package/src/assets/commands/dynamic-plan.mds +244 -0
- package/src/assets/commands/dynamic-profile.mds +132 -0
- package/src/assets/commands/dynamic-tickets.mds +226 -0
- package/src/assets/commands/explore.mds +150 -0
- package/src/assets/commands/implement.mds +496 -0
- package/src/assets/commands/plan.mds +523 -0
- package/src/assets/commands/release.md +206 -0
- package/src/assets/commands/research.mds +164 -0
- package/src/assets/commands/resolve.mds +636 -0
- package/src/assets/commands/self-review.mds +156 -0
- package/src/assets/rules/accessibility.md +11 -0
- package/src/assets/rules/compliance.md +15 -0
- package/src/assets/rules/engineering.md +13 -0
- package/src/assets/rules/go.md +12 -0
- package/src/assets/rules/java.md +12 -0
- package/src/assets/rules/python.md +12 -0
- package/src/assets/rules/quality.md +14 -0
- package/src/assets/rules/react.md +11 -0
- package/src/assets/rules/reliability.md +12 -0
- package/src/assets/rules/rust.md +12 -0
- package/src/assets/rules/security.md +12 -0
- package/src/assets/rules/typescript.md +12 -0
- package/src/assets/rules/ui-design.md +11 -0
- package/src/assets/scripts/hooks/assets/orchestrator-charter.md +21 -0
- package/src/assets/scripts/hooks/background-memory-update +460 -0
- package/src/assets/scripts/hooks/capture-prompt +87 -0
- package/src/assets/scripts/hooks/capture-question +153 -0
- package/src/assets/scripts/hooks/capture-turn +105 -0
- package/src/assets/scripts/hooks/debug-trace +75 -0
- package/src/assets/scripts/hooks/decisions-usage-scan.cjs +131 -0
- package/src/assets/scripts/hooks/ensure-devflow-init +39 -0
- package/src/assets/scripts/hooks/ensure-proxy +294 -0
- package/src/assets/scripts/hooks/ensure-root-gitignore +116 -0
- package/src/assets/scripts/hooks/get-mtime +23 -0
- package/src/assets/scripts/hooks/git-marker +16 -0
- package/src/assets/scripts/hooks/hook-bootstrap +25 -0
- package/src/assets/scripts/hooks/hook-log-init +41 -0
- package/src/assets/scripts/hooks/json-helper.cjs +725 -0
- package/src/assets/scripts/hooks/json-parse +243 -0
- package/src/assets/scripts/hooks/learning-lock +44 -0
- package/src/assets/scripts/hooks/lib/decisions-format.cjs +301 -0
- package/src/assets/scripts/hooks/lib/mkdir-lock.cjs +106 -0
- package/src/assets/scripts/hooks/lib/project-paths.cjs +230 -0
- package/src/assets/scripts/hooks/lib/render-decisions.cjs +398 -0
- package/src/assets/scripts/hooks/lib/safe-path.cjs +29 -0
- package/src/assets/scripts/hooks/log-paths +24 -0
- package/src/assets/scripts/hooks/memory-worker +101 -0
- package/src/assets/scripts/hooks/pre-compact-memory +126 -0
- package/src/assets/scripts/hooks/preamble +77 -0
- package/src/assets/scripts/hooks/queue-append +120 -0
- package/src/assets/scripts/hooks/resolve-project-root +37 -0
- package/src/assets/scripts/hooks/run-hook +31 -0
- package/src/assets/scripts/hooks/session-start-context +180 -0
- package/src/assets/scripts/hooks/session-start-memory +318 -0
- package/src/assets/scripts/hooks/session-start-orchestrator +54 -0
- package/src/assets/scripts/hud.sh +5 -0
- package/src/assets/scripts/redact-secrets.cjs +410 -0
- package/src/assets/skills/accessibility/SKILL.md +145 -0
- package/src/assets/skills/accessibility/references/patterns.md +398 -0
- package/src/assets/skills/accessibility/references/sources.md +26 -0
- package/src/assets/skills/accessibility/references/violations.md +358 -0
- package/src/assets/skills/apply-decisions/SKILL.md +100 -0
- package/src/assets/skills/apply-feature-knowledge/SKILL.md +69 -0
- package/src/assets/skills/architecture/SKILL.md +138 -0
- package/src/assets/skills/architecture/references/patterns.md +378 -0
- package/src/assets/skills/architecture/references/sources.md +41 -0
- package/src/assets/skills/architecture/references/violations.md +314 -0
- package/src/assets/skills/boundary-validation/SKILL.md +119 -0
- package/src/assets/skills/boundary-validation/references/detection.md +283 -0
- package/src/assets/skills/boundary-validation/references/patterns.md +283 -0
- package/src/assets/skills/boundary-validation/references/sources.md +41 -0
- package/src/assets/skills/boundary-validation/references/violations.md +211 -0
- package/src/assets/skills/complexity/SKILL.md +150 -0
- package/src/assets/skills/compliance/SKILL.md +121 -0
- package/src/assets/skills/compliance/frameworks/gdpr/fragment.md +11 -0
- package/src/assets/skills/compliance/frameworks/gdpr/reference.md +50 -0
- package/src/assets/skills/compliance/frameworks/hipaa/fragment.md +11 -0
- package/src/assets/skills/compliance/frameworks/hipaa/reference.md +44 -0
- package/src/assets/skills/compliance/frameworks/iso-27001/fragment.md +10 -0
- package/src/assets/skills/compliance/frameworks/iso-27001/reference.md +45 -0
- package/src/assets/skills/compliance/frameworks/pci-dss/fragment.md +11 -0
- package/src/assets/skills/compliance/frameworks/pci-dss/reference.md +55 -0
- package/src/assets/skills/compliance/frameworks/soc2/fragment.md +10 -0
- package/src/assets/skills/compliance/frameworks/soc2/reference.md +53 -0
- package/src/assets/skills/compliance/frameworks/sox/fragment.md +10 -0
- package/src/assets/skills/compliance/frameworks/sox/reference.md +67 -0
- package/src/assets/skills/compliance/references/detection.md +108 -0
- package/src/assets/skills/compliance/references/sources.md +28 -0
- package/src/assets/skills/consistency/SKILL.md +140 -0
- package/src/assets/skills/database/SKILL.md +134 -0
- package/src/assets/skills/dependencies/SKILL.md +141 -0
- package/src/assets/skills/dependency-research/SKILL.md +133 -0
- package/src/assets/skills/dependency-research/references/evaluation-criteria.md +101 -0
- package/src/assets/skills/design-review/SKILL.md +155 -0
- package/src/assets/skills/design-review/references/anti-patterns.md +207 -0
- package/src/assets/skills/docs-framework/SKILL.md +190 -0
- package/src/assets/skills/docs-framework/references/patterns.md +381 -0
- package/src/assets/skills/docs-framework/references/violations.md +221 -0
- package/src/assets/skills/documentation/SKILL.md +126 -0
- package/src/assets/skills/feature-knowledge/SKILL.md +341 -0
- package/src/assets/skills/gap-analysis/SKILL.md +151 -0
- package/src/assets/skills/gap-analysis/references/check-layers.md +125 -0
- package/src/assets/skills/git/SKILL.md +287 -0
- package/src/assets/skills/git/references/github-api.md +666 -0
- package/src/assets/skills/git/references/patterns.md +324 -0
- package/src/assets/skills/git/references/sources.md +16 -0
- package/src/assets/skills/git/references/violations.md +128 -0
- package/src/assets/skills/go/SKILL.md +147 -0
- package/src/assets/skills/go/references/concurrency.md +335 -0
- package/src/assets/skills/go/references/patterns.md +278 -0
- package/src/assets/skills/go/references/sources.md +41 -0
- package/src/assets/skills/go/references/violations.md +262 -0
- package/src/assets/skills/java/SKILL.md +148 -0
- package/src/assets/skills/java/references/modern-java.md +335 -0
- package/src/assets/skills/java/references/patterns.md +311 -0
- package/src/assets/skills/java/references/sources.md +44 -0
- package/src/assets/skills/java/references/violations.md +257 -0
- package/src/assets/skills/patterns/SKILL.md +162 -0
- package/src/assets/skills/performance/SKILL.md +135 -0
- package/src/assets/skills/performance/references/patterns.md +516 -0
- package/src/assets/skills/performance/references/sources.md +41 -0
- package/src/assets/skills/performance/references/violations.md +417 -0
- package/src/assets/skills/python/SKILL.md +156 -0
- package/src/assets/skills/python/references/async.md +255 -0
- package/src/assets/skills/python/references/patterns.md +280 -0
- package/src/assets/skills/python/references/sources.md +41 -0
- package/src/assets/skills/python/references/violations.md +272 -0
- package/src/assets/skills/qa/SKILL.md +136 -0
- package/src/assets/skills/qa/references/browser-testing.md +97 -0
- package/src/assets/skills/qa/references/patterns.md +118 -0
- package/src/assets/skills/qa/references/scenario-templates.md +102 -0
- package/src/assets/skills/qa/references/sources.md +30 -0
- package/src/assets/skills/qa/references/violations.md +98 -0
- package/src/assets/skills/quality-gates/SKILL.md +152 -0
- package/src/assets/skills/quality-gates/references/stub-detection.md +135 -0
- package/src/assets/skills/react/SKILL.md +143 -0
- package/src/assets/skills/react/references/error-handling.md +179 -0
- package/src/assets/skills/react/references/forms.md +214 -0
- package/src/assets/skills/react/references/hooks.md +193 -0
- package/src/assets/skills/react/references/patterns.md +1336 -0
- package/src/assets/skills/react/references/sources.md +35 -0
- package/src/assets/skills/react/references/violations.md +570 -0
- package/src/assets/skills/regression/SKILL.md +146 -0
- package/src/assets/skills/reliability/SKILL.md +153 -0
- package/src/assets/skills/reliability/references/detection.md +66 -0
- package/src/assets/skills/reliability/references/patterns.md +151 -0
- package/src/assets/skills/reliability/references/sources.md +27 -0
- package/src/assets/skills/reliability/references/violations.md +125 -0
- package/src/assets/skills/research-codebase/SKILL.md +135 -0
- package/src/assets/skills/research-competitor/SKILL.md +145 -0
- package/src/assets/skills/research-external/SKILL.md +141 -0
- package/src/assets/skills/research-market/SKILL.md +145 -0
- package/src/assets/skills/research-technology/SKILL.md +180 -0
- package/src/assets/skills/review-methodology/SKILL.md +121 -0
- package/src/assets/skills/review-methodology/references/patterns.md +186 -0
- package/src/assets/skills/review-methodology/references/report-template.md +142 -0
- package/src/assets/skills/review-methodology/references/violations.md +125 -0
- package/src/assets/skills/rust/SKILL.md +148 -0
- package/src/assets/skills/rust/references/ownership.md +278 -0
- package/src/assets/skills/rust/references/patterns.md +247 -0
- package/src/assets/skills/rust/references/sources.md +46 -0
- package/src/assets/skills/rust/references/violations.md +252 -0
- package/src/assets/skills/security/SKILL.md +121 -0
- package/src/assets/skills/security/references/patterns.md +271 -0
- package/src/assets/skills/security/references/sources.md +41 -0
- package/src/assets/skills/security/references/violations.md +241 -0
- package/src/assets/skills/software-design/SKILL.md +143 -0
- package/src/assets/skills/software-design/references/checklist.md +259 -0
- package/src/assets/skills/software-design/references/code-smell-violations.md +189 -0
- package/src/assets/skills/software-design/references/patterns.md +359 -0
- package/src/assets/skills/software-design/references/sources.md +41 -0
- package/src/assets/skills/software-design/references/violations.md +341 -0
- package/src/assets/skills/test-driven-development/SKILL.md +197 -0
- package/src/assets/skills/testing/SKILL.md +139 -0
- package/src/assets/skills/testing/references/patterns.md +346 -0
- package/src/assets/skills/testing/references/sources.md +53 -0
- package/src/assets/skills/testing/references/violations.md +322 -0
- package/src/assets/skills/typescript/SKILL.md +150 -0
- package/src/assets/skills/typescript/references/async.md +333 -0
- package/src/assets/skills/typescript/references/patterns.md +440 -0
- package/src/assets/skills/typescript/references/sources.md +41 -0
- package/src/assets/skills/typescript/references/type-guards.md +333 -0
- package/src/assets/skills/typescript/references/utility-types.md +255 -0
- package/src/assets/skills/typescript/references/violations.md +285 -0
- package/src/assets/skills/ui-design/SKILL.md +144 -0
- package/src/assets/skills/ui-design/references/patterns.md +341 -0
- package/src/assets/skills/ui-design/references/sources.md +41 -0
- package/src/assets/skills/ui-design/references/violations.md +312 -0
- package/src/assets/skills/worktree-support/SKILL.md +92 -0
- package/src/targets/claude-code/templates/claudeignore.template +188 -0
- package/src/targets/claude-code/templates/settings.json +86 -0
- package/dist/cli.d.ts +0 -3
- package/dist/commands/ambient.d.ts +0 -18
- package/dist/commands/ambient.js +0 -137
- package/dist/commands/hud.d.ts +0 -22
- package/dist/commands/hud.js +0 -180
- package/dist/commands/init.d.ts +0 -16
- package/dist/commands/init.js +0 -738
- package/dist/commands/list.d.ts +0 -24
- package/dist/commands/list.js +0 -89
- package/dist/commands/memory.d.ts +0 -22
- package/dist/commands/memory.js +0 -175
- package/dist/commands/skills.d.ts +0 -11
- package/dist/commands/skills.js +0 -116
- package/dist/commands/uninstall.d.ts +0 -22
- package/dist/commands/uninstall.js +0 -558
- package/dist/hud/cache.d.ts +0 -14
- package/dist/hud/cache.js +0 -54
- package/dist/hud/colors.d.ts +0 -23
- package/dist/hud/components/config-counts.d.ts +0 -8
- package/dist/hud/components/context-usage.d.ts +0 -8
- package/dist/hud/components/diff-stats.d.ts +0 -3
- package/dist/hud/components/directory.d.ts +0 -3
- package/dist/hud/components/git-ahead-behind.d.ts +0 -3
- package/dist/hud/components/git-branch.d.ts +0 -3
- package/dist/hud/components/model.d.ts +0 -3
- package/dist/hud/components/release-info.d.ts +0 -3
- package/dist/hud/components/session-cost.d.ts +0 -3
- package/dist/hud/components/session-duration.d.ts +0 -3
- package/dist/hud/components/todo-progress.d.ts +0 -3
- package/dist/hud/components/usage-quota.d.ts +0 -3
- package/dist/hud/components/version-badge.d.ts +0 -3
- package/dist/hud/components/worktree-count.d.ts +0 -3
- package/dist/hud/config.d.ts +0 -10
- package/dist/hud/credentials.d.ts +0 -17
- package/dist/hud/credentials.js +0 -99
- package/dist/hud/git.d.ts +0 -7
- package/dist/hud/index.d.ts +0 -2
- package/dist/hud/render.d.ts +0 -7
- package/dist/hud/stdin.d.ts +0 -6
- package/dist/hud/transcript.d.ts +0 -7
- package/dist/hud/types.d.ts +0 -116
- package/dist/hud/usage-api.d.ts +0 -7
- package/dist/hud/usage-api.js +0 -84
- package/dist/plugins.d.ts +0 -46
- package/dist/plugins.js +0 -233
- package/dist/utils/cli.d.ts +0 -5
- package/dist/utils/cli.js +0 -14
- package/dist/utils/git.d.ts +0 -11
- package/dist/utils/git.js +0 -36
- package/dist/utils/installer.d.ts +0 -41
- package/dist/utils/installer.js +0 -195
- package/dist/utils/manifest.d.ts +0 -46
- package/dist/utils/manifest.js +0 -100
- package/dist/utils/paths.d.ts +0 -42
- package/dist/utils/paths.js +0 -106
- package/dist/utils/post-install.d.ts +0 -87
- package/dist/utils/post-install.js +0 -546
- package/dist/utils/safe-delete-install.d.ts +0 -29
- package/dist/utils/safe-delete-install.js +0 -191
- package/dist/utils/safe-delete.d.ts +0 -12
- package/plugins/devflow-accessibility/.claude-plugin/plugin.json +0 -21
- package/plugins/devflow-accessibility/skills/accessibility/SKILL.md +0 -229
- package/plugins/devflow-accessibility/skills/accessibility/references/patterns.md +0 -670
- package/plugins/devflow-accessibility/skills/accessibility/references/violations.md +0 -419
- package/plugins/devflow-ambient/.claude-plugin/plugin.json +0 -33
- package/plugins/devflow-ambient/README.md +0 -68
- package/plugins/devflow-ambient/agents/coder.md +0 -135
- package/plugins/devflow-ambient/agents/reviewer.md +0 -165
- package/plugins/devflow-ambient/agents/scrutinizer.md +0 -82
- package/plugins/devflow-ambient/agents/shepherd.md +0 -108
- package/plugins/devflow-ambient/agents/simplifier.md +0 -102
- package/plugins/devflow-ambient/agents/skimmer.md +0 -143
- package/plugins/devflow-ambient/agents/validator.md +0 -86
- package/plugins/devflow-ambient/skills/ambient-router/SKILL.md +0 -145
- package/plugins/devflow-ambient/skills/ambient-router/references/skill-catalog.md +0 -74
- package/plugins/devflow-ambient/skills/debug-orchestration/SKILL.md +0 -69
- package/plugins/devflow-ambient/skills/implementation-orchestration/SKILL.md +0 -92
- package/plugins/devflow-ambient/skills/plan-orchestration/SKILL.md +0 -71
- package/plugins/devflow-audit-claude/.claude-plugin/plugin.json +0 -19
- package/plugins/devflow-audit-claude/README.md +0 -46
- package/plugins/devflow-audit-claude/agents/claude-md-auditor.md +0 -134
- package/plugins/devflow-audit-claude/commands/audit-claude.md +0 -89
- package/plugins/devflow-code-review/.claude-plugin/plugin.json +0 -38
- package/plugins/devflow-code-review/README.md +0 -73
- package/plugins/devflow-code-review/agents/git.md +0 -277
- package/plugins/devflow-code-review/agents/reviewer.md +0 -165
- package/plugins/devflow-code-review/agents/synthesizer.md +0 -211
- package/plugins/devflow-code-review/commands/code-review-teams.md +0 -285
- package/plugins/devflow-code-review/commands/code-review.md +0 -163
- package/plugins/devflow-code-review/skills/agent-teams/SKILL.md +0 -124
- package/plugins/devflow-code-review/skills/agent-teams/references/cleanup.md +0 -104
- package/plugins/devflow-code-review/skills/agent-teams/references/communication.md +0 -122
- package/plugins/devflow-code-review/skills/agent-teams/references/team-patterns.md +0 -217
- package/plugins/devflow-code-review/skills/architecture-patterns/SKILL.md +0 -153
- package/plugins/devflow-code-review/skills/architecture-patterns/references/patterns.md +0 -873
- package/plugins/devflow-code-review/skills/architecture-patterns/references/violations.md +0 -575
- package/plugins/devflow-code-review/skills/complexity-patterns/SKILL.md +0 -143
- package/plugins/devflow-code-review/skills/consistency-patterns/SKILL.md +0 -140
- package/plugins/devflow-code-review/skills/database-patterns/SKILL.md +0 -134
- package/plugins/devflow-code-review/skills/dependencies-patterns/SKILL.md +0 -141
- package/plugins/devflow-code-review/skills/documentation-patterns/SKILL.md +0 -125
- package/plugins/devflow-code-review/skills/knowledge-persistence/SKILL.md +0 -128
- package/plugins/devflow-code-review/skills/knowledge-persistence/references/examples.md +0 -44
- package/plugins/devflow-code-review/skills/performance-patterns/SKILL.md +0 -154
- package/plugins/devflow-code-review/skills/performance-patterns/references/patterns.md +0 -503
- package/plugins/devflow-code-review/skills/performance-patterns/references/violations.md +0 -354
- package/plugins/devflow-code-review/skills/regression-patterns/SKILL.md +0 -146
- package/plugins/devflow-code-review/skills/review-methodology/SKILL.md +0 -119
- package/plugins/devflow-code-review/skills/review-methodology/references/patterns.md +0 -186
- package/plugins/devflow-code-review/skills/review-methodology/references/report-template.md +0 -142
- package/plugins/devflow-code-review/skills/review-methodology/references/violations.md +0 -125
- package/plugins/devflow-code-review/skills/security-patterns/SKILL.md +0 -156
- package/plugins/devflow-code-review/skills/security-patterns/references/patterns.md +0 -507
- package/plugins/devflow-code-review/skills/security-patterns/references/violations.md +0 -237
- package/plugins/devflow-code-review/skills/test-patterns/SKILL.md +0 -183
- package/plugins/devflow-code-review/skills/test-patterns/references/patterns.md +0 -220
- package/plugins/devflow-code-review/skills/test-patterns/references/violations.md +0 -221
- package/plugins/devflow-core-skills/.claude-plugin/plugin.json +0 -31
- package/plugins/devflow-core-skills/README.md +0 -50
- package/plugins/devflow-core-skills/skills/core-patterns/SKILL.md +0 -162
- package/plugins/devflow-core-skills/skills/core-patterns/references/checklist.md +0 -276
- package/plugins/devflow-core-skills/skills/core-patterns/references/code-smell-violations.md +0 -144
- package/plugins/devflow-core-skills/skills/core-patterns/references/patterns.md +0 -576
- package/plugins/devflow-core-skills/skills/core-patterns/references/violations.md +0 -369
- package/plugins/devflow-core-skills/skills/docs-framework/SKILL.md +0 -143
- package/plugins/devflow-core-skills/skills/docs-framework/references/patterns.md +0 -346
- package/plugins/devflow-core-skills/skills/docs-framework/references/violations.md +0 -221
- package/plugins/devflow-core-skills/skills/git-safety/SKILL.md +0 -122
- package/plugins/devflow-core-skills/skills/git-safety/references/patterns.md +0 -289
- package/plugins/devflow-core-skills/skills/git-safety/references/violations.md +0 -18
- package/plugins/devflow-core-skills/skills/git-workflow/SKILL.md +0 -158
- package/plugins/devflow-core-skills/skills/git-workflow/references/commit-patterns.md +0 -115
- package/plugins/devflow-core-skills/skills/git-workflow/references/commit-violations.md +0 -77
- package/plugins/devflow-core-skills/skills/git-workflow/references/pr-patterns.md +0 -127
- package/plugins/devflow-core-skills/skills/git-workflow/references/pr-violations.md +0 -96
- package/plugins/devflow-core-skills/skills/github-patterns/SKILL.md +0 -153
- package/plugins/devflow-core-skills/skills/github-patterns/references/patterns.md +0 -572
- package/plugins/devflow-core-skills/skills/github-patterns/references/violations.md +0 -298
- package/plugins/devflow-core-skills/skills/input-validation/SKILL.md +0 -148
- package/plugins/devflow-core-skills/skills/input-validation/references/detection.md +0 -283
- package/plugins/devflow-core-skills/skills/input-validation/references/patterns.md +0 -361
- package/plugins/devflow-core-skills/skills/input-validation/references/violations.md +0 -224
- package/plugins/devflow-core-skills/skills/search-first/SKILL.md +0 -133
- package/plugins/devflow-core-skills/skills/search-first/references/evaluation-criteria.md +0 -101
- package/plugins/devflow-core-skills/skills/test-driven-development/SKILL.md +0 -137
- package/plugins/devflow-core-skills/skills/test-patterns/SKILL.md +0 -183
- package/plugins/devflow-core-skills/skills/test-patterns/references/detection.md +0 -149
- package/plugins/devflow-core-skills/skills/test-patterns/references/patterns.md +0 -220
- package/plugins/devflow-core-skills/skills/test-patterns/references/report-template.md +0 -108
- package/plugins/devflow-core-skills/skills/test-patterns/references/violations.md +0 -221
- package/plugins/devflow-debug/.claude-plugin/plugin.json +0 -26
- package/plugins/devflow-debug/README.md +0 -65
- package/plugins/devflow-debug/agents/git.md +0 -277
- package/plugins/devflow-debug/agents/synthesizer.md +0 -211
- package/plugins/devflow-debug/commands/debug-teams.md +0 -245
- package/plugins/devflow-debug/commands/debug.md +0 -174
- package/plugins/devflow-debug/skills/agent-teams/SKILL.md +0 -124
- package/plugins/devflow-debug/skills/agent-teams/references/cleanup.md +0 -104
- package/plugins/devflow-debug/skills/agent-teams/references/communication.md +0 -122
- package/plugins/devflow-debug/skills/agent-teams/references/team-patterns.md +0 -217
- package/plugins/devflow-debug/skills/git-safety/SKILL.md +0 -122
- package/plugins/devflow-debug/skills/git-safety/references/detection.md +0 -290
- package/plugins/devflow-debug/skills/git-safety/references/patterns.md +0 -289
- package/plugins/devflow-debug/skills/git-safety/references/violations.md +0 -18
- package/plugins/devflow-debug/skills/knowledge-persistence/SKILL.md +0 -128
- package/plugins/devflow-debug/skills/knowledge-persistence/references/examples.md +0 -44
- package/plugins/devflow-frontend-design/.claude-plugin/plugin.json +0 -21
- package/plugins/devflow-frontend-design/skills/frontend-design/SKILL.md +0 -254
- package/plugins/devflow-frontend-design/skills/frontend-design/references/patterns.md +0 -511
- package/plugins/devflow-frontend-design/skills/frontend-design/references/violations.md +0 -453
- package/plugins/devflow-go/.claude-plugin/plugin.json +0 -21
- package/plugins/devflow-go/skills/go/SKILL.md +0 -187
- package/plugins/devflow-go/skills/go/references/concurrency.md +0 -312
- package/plugins/devflow-go/skills/go/references/patterns.md +0 -232
- package/plugins/devflow-go/skills/go/references/violations.md +0 -205
- package/plugins/devflow-implement/.claude-plugin/plugin.json +0 -35
- package/plugins/devflow-implement/README.md +0 -71
- package/plugins/devflow-implement/agents/coder.md +0 -135
- package/plugins/devflow-implement/agents/git.md +0 -277
- package/plugins/devflow-implement/agents/scrutinizer.md +0 -82
- package/plugins/devflow-implement/agents/shepherd.md +0 -108
- package/plugins/devflow-implement/agents/simplifier.md +0 -102
- package/plugins/devflow-implement/agents/skimmer.md +0 -143
- package/plugins/devflow-implement/agents/synthesizer.md +0 -211
- package/plugins/devflow-implement/agents/validator.md +0 -86
- package/plugins/devflow-implement/commands/implement-teams.md +0 -620
- package/plugins/devflow-implement/commands/implement.md +0 -430
- package/plugins/devflow-implement/skills/agent-teams/SKILL.md +0 -124
- package/plugins/devflow-implement/skills/agent-teams/references/cleanup.md +0 -104
- package/plugins/devflow-implement/skills/agent-teams/references/communication.md +0 -122
- package/plugins/devflow-implement/skills/agent-teams/references/team-patterns.md +0 -217
- package/plugins/devflow-implement/skills/implementation-patterns/SKILL.md +0 -162
- package/plugins/devflow-implement/skills/knowledge-persistence/SKILL.md +0 -128
- package/plugins/devflow-implement/skills/knowledge-persistence/references/examples.md +0 -44
- package/plugins/devflow-implement/skills/self-review/SKILL.md +0 -149
- package/plugins/devflow-implement/skills/self-review/references/stub-detection.md +0 -135
- package/plugins/devflow-java/.claude-plugin/plugin.json +0 -21
- package/plugins/devflow-java/skills/java/SKILL.md +0 -183
- package/plugins/devflow-java/skills/java/references/modern-java.md +0 -270
- package/plugins/devflow-java/skills/java/references/patterns.md +0 -235
- package/plugins/devflow-java/skills/java/references/violations.md +0 -213
- package/plugins/devflow-python/.claude-plugin/plugin.json +0 -21
- package/plugins/devflow-python/skills/python/SKILL.md +0 -188
- package/plugins/devflow-python/skills/python/references/async.md +0 -220
- package/plugins/devflow-python/skills/python/references/patterns.md +0 -226
- package/plugins/devflow-python/skills/python/references/violations.md +0 -204
- package/plugins/devflow-react/.claude-plugin/plugin.json +0 -21
- package/plugins/devflow-react/skills/react/SKILL.md +0 -276
- package/plugins/devflow-react/skills/react/references/patterns.md +0 -1331
- package/plugins/devflow-react/skills/react/references/violations.md +0 -565
- package/plugins/devflow-resolve/.claude-plugin/plugin.json +0 -29
- package/plugins/devflow-resolve/README.md +0 -65
- package/plugins/devflow-resolve/agents/git.md +0 -277
- package/plugins/devflow-resolve/agents/resolver.md +0 -131
- package/plugins/devflow-resolve/agents/simplifier.md +0 -102
- package/plugins/devflow-resolve/commands/resolve-teams.md +0 -307
- package/plugins/devflow-resolve/commands/resolve.md +0 -246
- package/plugins/devflow-resolve/skills/agent-teams/SKILL.md +0 -124
- package/plugins/devflow-resolve/skills/agent-teams/references/cleanup.md +0 -104
- package/plugins/devflow-resolve/skills/agent-teams/references/communication.md +0 -122
- package/plugins/devflow-resolve/skills/agent-teams/references/team-patterns.md +0 -217
- package/plugins/devflow-resolve/skills/implementation-patterns/SKILL.md +0 -162
- package/plugins/devflow-resolve/skills/implementation-patterns/references/patterns.md +0 -1063
- package/plugins/devflow-resolve/skills/implementation-patterns/references/violations.md +0 -483
- package/plugins/devflow-resolve/skills/knowledge-persistence/SKILL.md +0 -128
- package/plugins/devflow-resolve/skills/knowledge-persistence/references/examples.md +0 -44
- package/plugins/devflow-resolve/skills/security-patterns/SKILL.md +0 -156
- package/plugins/devflow-resolve/skills/security-patterns/references/detection.md +0 -287
- package/plugins/devflow-resolve/skills/security-patterns/references/patterns.md +0 -507
- package/plugins/devflow-resolve/skills/security-patterns/references/violations.md +0 -237
- package/plugins/devflow-rust/.claude-plugin/plugin.json +0 -21
- package/plugins/devflow-rust/skills/rust/SKILL.md +0 -193
- package/plugins/devflow-rust/skills/rust/references/ownership.md +0 -242
- package/plugins/devflow-rust/skills/rust/references/patterns.md +0 -210
- package/plugins/devflow-rust/skills/rust/references/violations.md +0 -191
- package/plugins/devflow-self-review/.claude-plugin/plugin.json +0 -26
- package/plugins/devflow-self-review/README.md +0 -38
- package/plugins/devflow-self-review/agents/scrutinizer.md +0 -82
- package/plugins/devflow-self-review/agents/simplifier.md +0 -102
- package/plugins/devflow-self-review/agents/validator.md +0 -86
- package/plugins/devflow-self-review/commands/self-review.md +0 -132
- package/plugins/devflow-self-review/skills/core-patterns/SKILL.md +0 -162
- package/plugins/devflow-self-review/skills/core-patterns/references/checklist.md +0 -276
- package/plugins/devflow-self-review/skills/core-patterns/references/code-smell-violations.md +0 -144
- package/plugins/devflow-self-review/skills/core-patterns/references/detection.md +0 -303
- package/plugins/devflow-self-review/skills/core-patterns/references/patterns.md +0 -576
- package/plugins/devflow-self-review/skills/core-patterns/references/violations.md +0 -369
- package/plugins/devflow-self-review/skills/self-review/SKILL.md +0 -149
- package/plugins/devflow-self-review/skills/self-review/references/patterns.md +0 -405
- package/plugins/devflow-self-review/skills/self-review/references/report-template.md +0 -253
- package/plugins/devflow-self-review/skills/self-review/references/stub-detection.md +0 -135
- package/plugins/devflow-self-review/skills/self-review/references/violations.md +0 -308
- package/plugins/devflow-specify/.claude-plugin/plugin.json +0 -25
- package/plugins/devflow-specify/README.md +0 -46
- package/plugins/devflow-specify/agents/skimmer.md +0 -143
- package/plugins/devflow-specify/agents/synthesizer.md +0 -211
- package/plugins/devflow-specify/commands/specify-teams.md +0 -321
- package/plugins/devflow-specify/commands/specify.md +0 -186
- package/plugins/devflow-specify/skills/agent-teams/SKILL.md +0 -124
- package/plugins/devflow-specify/skills/agent-teams/references/cleanup.md +0 -104
- package/plugins/devflow-specify/skills/agent-teams/references/communication.md +0 -122
- package/plugins/devflow-specify/skills/agent-teams/references/team-patterns.md +0 -217
- package/plugins/devflow-typescript/.claude-plugin/plugin.json +0 -21
- package/plugins/devflow-typescript/skills/typescript/SKILL.md +0 -176
- package/plugins/devflow-typescript/skills/typescript/references/patterns.md +0 -1105
- package/plugins/devflow-typescript/skills/typescript/references/violations.md +0 -433
- package/scripts/hooks/ambient-prompt +0 -50
- package/scripts/hooks/background-memory-update +0 -257
- package/scripts/hooks/ensure-memory-gitignore +0 -17
- package/scripts/hooks/pre-compact-memory +0 -87
- package/scripts/hooks/run-hook +0 -23
- package/scripts/hooks/session-start-memory +0 -165
- package/scripts/hooks/stop-update-memory +0 -85
- package/scripts/hud/cache.d.ts +0 -14
- package/scripts/hud/cache.d.ts.map +0 -1
- package/scripts/hud/cache.js +0 -54
- package/scripts/hud/cache.js.map +0 -1
- package/scripts/hud/colors.d.ts +0 -23
- package/scripts/hud/colors.d.ts.map +0 -1
- package/scripts/hud/colors.js +0 -62
- package/scripts/hud/colors.js.map +0 -1
- package/scripts/hud/components/config-counts.d.ts +0 -8
- package/scripts/hud/components/config-counts.d.ts.map +0 -1
- package/scripts/hud/components/config-counts.js +0 -91
- package/scripts/hud/components/config-counts.js.map +0 -1
- package/scripts/hud/components/context-usage.d.ts +0 -8
- package/scripts/hud/components/context-usage.d.ts.map +0 -1
- package/scripts/hud/components/context-usage.js +0 -49
- package/scripts/hud/components/context-usage.js.map +0 -1
- package/scripts/hud/components/diff-stats.d.ts +0 -3
- package/scripts/hud/components/diff-stats.d.ts.map +0 -1
- package/scripts/hud/components/diff-stats.js +0 -36
- package/scripts/hud/components/diff-stats.js.map +0 -1
- package/scripts/hud/components/directory.d.ts +0 -3
- package/scripts/hud/components/directory.d.ts.map +0 -1
- package/scripts/hud/components/directory.js +0 -10
- package/scripts/hud/components/directory.js.map +0 -1
- package/scripts/hud/components/git-ahead-behind.d.ts +0 -3
- package/scripts/hud/components/git-ahead-behind.d.ts.map +0 -1
- package/scripts/hud/components/git-ahead-behind.js +0 -16
- package/scripts/hud/components/git-ahead-behind.js.map +0 -1
- package/scripts/hud/components/git-branch.d.ts +0 -3
- package/scripts/hud/components/git-branch.d.ts.map +0 -1
- package/scripts/hud/components/git-branch.js +0 -14
- package/scripts/hud/components/git-branch.js.map +0 -1
- package/scripts/hud/components/model.d.ts +0 -3
- package/scripts/hud/components/model.d.ts.map +0 -1
- package/scripts/hud/components/model.js +0 -21
- package/scripts/hud/components/model.js.map +0 -1
- package/scripts/hud/components/release-info.d.ts +0 -3
- package/scripts/hud/components/release-info.d.ts.map +0 -1
- package/scripts/hud/components/release-info.js +0 -9
- package/scripts/hud/components/release-info.js.map +0 -1
- package/scripts/hud/components/session-cost.d.ts +0 -3
- package/scripts/hud/components/session-cost.d.ts.map +0 -1
- package/scripts/hud/components/session-cost.js +0 -9
- package/scripts/hud/components/session-cost.js.map +0 -1
- package/scripts/hud/components/session-duration.d.ts +0 -3
- package/scripts/hud/components/session-duration.d.ts.map +0 -1
- package/scripts/hud/components/session-duration.js +0 -18
- package/scripts/hud/components/session-duration.js.map +0 -1
- package/scripts/hud/components/todo-progress.d.ts +0 -3
- package/scripts/hud/components/todo-progress.d.ts.map +0 -1
- package/scripts/hud/components/todo-progress.js +0 -11
- package/scripts/hud/components/todo-progress.js.map +0 -1
- package/scripts/hud/components/usage-quota.d.ts +0 -3
- package/scripts/hud/components/usage-quota.d.ts.map +0 -1
- package/scripts/hud/components/usage-quota.js +0 -45
- package/scripts/hud/components/usage-quota.js.map +0 -1
- package/scripts/hud/components/version-badge.d.ts +0 -3
- package/scripts/hud/components/version-badge.d.ts.map +0 -1
- package/scripts/hud/components/version-badge.js +0 -80
- package/scripts/hud/components/version-badge.js.map +0 -1
- package/scripts/hud/components/worktree-count.d.ts +0 -3
- package/scripts/hud/components/worktree-count.d.ts.map +0 -1
- package/scripts/hud/components/worktree-count.js +0 -8
- package/scripts/hud/components/worktree-count.js.map +0 -1
- package/scripts/hud/config.d.ts +0 -10
- package/scripts/hud/config.d.ts.map +0 -1
- package/scripts/hud/config.js +0 -55
- package/scripts/hud/config.js.map +0 -1
- package/scripts/hud/credentials.d.ts +0 -17
- package/scripts/hud/credentials.d.ts.map +0 -1
- package/scripts/hud/credentials.js +0 -99
- package/scripts/hud/credentials.js.map +0 -1
- package/scripts/hud/git.d.ts +0 -7
- package/scripts/hud/git.d.ts.map +0 -1
- package/scripts/hud/git.js +0 -153
- package/scripts/hud/git.js.map +0 -1
- package/scripts/hud/index.d.ts +0 -2
- package/scripts/hud/index.d.ts.map +0 -1
- package/scripts/hud/index.js +0 -81
- package/scripts/hud/index.js.map +0 -1
- package/scripts/hud/render.d.ts +0 -7
- package/scripts/hud/render.d.ts.map +0 -1
- package/scripts/hud/render.js +0 -111
- package/scripts/hud/render.js.map +0 -1
- package/scripts/hud/stdin.d.ts +0 -6
- package/scripts/hud/stdin.d.ts.map +0 -1
- package/scripts/hud/stdin.js +0 -25
- package/scripts/hud/stdin.js.map +0 -1
- package/scripts/hud/transcript.d.ts +0 -7
- package/scripts/hud/transcript.d.ts.map +0 -1
- package/scripts/hud/transcript.js +0 -130
- package/scripts/hud/transcript.js.map +0 -1
- package/scripts/hud/types.d.ts +0 -116
- package/scripts/hud/types.d.ts.map +0 -1
- package/scripts/hud/types.js +0 -2
- package/scripts/hud/types.js.map +0 -1
- package/scripts/hud/usage-api.d.ts +0 -7
- package/scripts/hud/usage-api.d.ts.map +0 -1
- package/scripts/hud/usage-api.js +0 -84
- package/scripts/hud/usage-api.js.map +0 -1
- package/scripts/hud.sh +0 -5
- package/shared/agents/coder.md +0 -135
- package/shared/agents/git.md +0 -277
- package/shared/agents/resolver.md +0 -131
- package/shared/agents/reviewer.md +0 -165
- package/shared/agents/scrutinizer.md +0 -82
- package/shared/agents/shepherd.md +0 -108
- package/shared/agents/simplifier.md +0 -102
- package/shared/agents/skimmer.md +0 -143
- package/shared/agents/synthesizer.md +0 -211
- package/shared/agents/validator.md +0 -86
- package/shared/skills/accessibility/SKILL.md +0 -229
- package/shared/skills/accessibility/references/detection.md +0 -171
- package/shared/skills/accessibility/references/patterns.md +0 -670
- package/shared/skills/accessibility/references/violations.md +0 -419
- package/shared/skills/agent-teams/SKILL.md +0 -124
- package/shared/skills/agent-teams/references/cleanup.md +0 -104
- package/shared/skills/agent-teams/references/communication.md +0 -122
- package/shared/skills/agent-teams/references/team-patterns.md +0 -217
- package/shared/skills/ambient-router/SKILL.md +0 -145
- package/shared/skills/ambient-router/references/skill-catalog.md +0 -74
- package/shared/skills/architecture-patterns/SKILL.md +0 -153
- package/shared/skills/architecture-patterns/references/detection.md +0 -337
- package/shared/skills/architecture-patterns/references/patterns.md +0 -873
- package/shared/skills/architecture-patterns/references/violations.md +0 -575
- package/shared/skills/complexity-patterns/SKILL.md +0 -143
- package/shared/skills/complexity-patterns/references/detection.md +0 -264
- package/shared/skills/complexity-patterns/references/patterns.md +0 -487
- package/shared/skills/complexity-patterns/references/violations.md +0 -361
- package/shared/skills/consistency-patterns/SKILL.md +0 -140
- package/shared/skills/consistency-patterns/references/detection.md +0 -207
- package/shared/skills/consistency-patterns/references/patterns.md +0 -202
- package/shared/skills/consistency-patterns/references/violations.md +0 -213
- package/shared/skills/core-patterns/SKILL.md +0 -162
- package/shared/skills/core-patterns/references/checklist.md +0 -276
- package/shared/skills/core-patterns/references/code-smell-violations.md +0 -144
- package/shared/skills/core-patterns/references/detection.md +0 -303
- package/shared/skills/core-patterns/references/patterns.md +0 -576
- package/shared/skills/core-patterns/references/violations.md +0 -369
- package/shared/skills/database-patterns/SKILL.md +0 -134
- package/shared/skills/database-patterns/references/detection.md +0 -208
- package/shared/skills/database-patterns/references/patterns.md +0 -394
- package/shared/skills/database-patterns/references/violations.md +0 -332
- package/shared/skills/debug-orchestration/SKILL.md +0 -69
- package/shared/skills/dependencies-patterns/SKILL.md +0 -141
- package/shared/skills/dependencies-patterns/references/detection.md +0 -181
- package/shared/skills/dependencies-patterns/references/patterns.md +0 -225
- package/shared/skills/dependencies-patterns/references/violations.md +0 -247
- package/shared/skills/docs-framework/SKILL.md +0 -143
- package/shared/skills/docs-framework/references/patterns.md +0 -346
- package/shared/skills/docs-framework/references/violations.md +0 -221
- package/shared/skills/documentation-patterns/SKILL.md +0 -125
- package/shared/skills/documentation-patterns/references/detection.md +0 -190
- package/shared/skills/documentation-patterns/references/patterns.md +0 -189
- package/shared/skills/documentation-patterns/references/violations.md +0 -163
- package/shared/skills/frontend-design/SKILL.md +0 -254
- package/shared/skills/frontend-design/references/detection.md +0 -184
- package/shared/skills/frontend-design/references/patterns.md +0 -511
- package/shared/skills/frontend-design/references/violations.md +0 -453
- package/shared/skills/git-safety/SKILL.md +0 -122
- package/shared/skills/git-safety/references/detection.md +0 -290
- package/shared/skills/git-safety/references/patterns.md +0 -289
- package/shared/skills/git-safety/references/violations.md +0 -18
- package/shared/skills/git-workflow/SKILL.md +0 -158
- package/shared/skills/git-workflow/references/commit-patterns.md +0 -115
- package/shared/skills/git-workflow/references/commit-violations.md +0 -77
- package/shared/skills/git-workflow/references/pr-patterns.md +0 -127
- package/shared/skills/git-workflow/references/pr-violations.md +0 -96
- package/shared/skills/github-patterns/SKILL.md +0 -153
- package/shared/skills/github-patterns/references/patterns.md +0 -572
- package/shared/skills/github-patterns/references/violations.md +0 -298
- package/shared/skills/go/SKILL.md +0 -187
- package/shared/skills/go/references/concurrency.md +0 -312
- package/shared/skills/go/references/detection.md +0 -129
- package/shared/skills/go/references/patterns.md +0 -232
- package/shared/skills/go/references/violations.md +0 -205
- package/shared/skills/implementation-orchestration/SKILL.md +0 -92
- package/shared/skills/implementation-patterns/SKILL.md +0 -162
- package/shared/skills/implementation-patterns/references/patterns.md +0 -1063
- package/shared/skills/implementation-patterns/references/violations.md +0 -483
- package/shared/skills/input-validation/SKILL.md +0 -148
- package/shared/skills/input-validation/references/detection.md +0 -283
- package/shared/skills/input-validation/references/patterns.md +0 -361
- package/shared/skills/input-validation/references/violations.md +0 -224
- package/shared/skills/java/SKILL.md +0 -183
- package/shared/skills/java/references/detection.md +0 -120
- package/shared/skills/java/references/modern-java.md +0 -270
- package/shared/skills/java/references/patterns.md +0 -235
- package/shared/skills/java/references/violations.md +0 -213
- package/shared/skills/knowledge-persistence/SKILL.md +0 -128
- package/shared/skills/knowledge-persistence/references/examples.md +0 -44
- package/shared/skills/performance-patterns/SKILL.md +0 -154
- package/shared/skills/performance-patterns/references/detection.md +0 -351
- package/shared/skills/performance-patterns/references/patterns.md +0 -503
- package/shared/skills/performance-patterns/references/violations.md +0 -354
- package/shared/skills/plan-orchestration/SKILL.md +0 -71
- package/shared/skills/python/SKILL.md +0 -188
- package/shared/skills/python/references/async.md +0 -220
- package/shared/skills/python/references/detection.md +0 -128
- package/shared/skills/python/references/patterns.md +0 -226
- package/shared/skills/python/references/violations.md +0 -204
- package/shared/skills/react/SKILL.md +0 -276
- package/shared/skills/react/references/patterns.md +0 -1331
- package/shared/skills/react/references/violations.md +0 -565
- package/shared/skills/regression-patterns/SKILL.md +0 -146
- package/shared/skills/regression-patterns/references/detection.md +0 -237
- package/shared/skills/regression-patterns/references/patterns.md +0 -226
- package/shared/skills/regression-patterns/references/violations.md +0 -225
- package/shared/skills/review-methodology/SKILL.md +0 -119
- package/shared/skills/review-methodology/references/patterns.md +0 -186
- package/shared/skills/review-methodology/references/report-template.md +0 -142
- package/shared/skills/review-methodology/references/violations.md +0 -125
- package/shared/skills/rust/SKILL.md +0 -193
- package/shared/skills/rust/references/detection.md +0 -131
- package/shared/skills/rust/references/ownership.md +0 -242
- package/shared/skills/rust/references/patterns.md +0 -210
- package/shared/skills/rust/references/violations.md +0 -191
- package/shared/skills/search-first/SKILL.md +0 -133
- package/shared/skills/search-first/references/evaluation-criteria.md +0 -101
- package/shared/skills/security-patterns/SKILL.md +0 -156
- package/shared/skills/security-patterns/references/detection.md +0 -287
- package/shared/skills/security-patterns/references/patterns.md +0 -507
- package/shared/skills/security-patterns/references/violations.md +0 -237
- package/shared/skills/self-review/SKILL.md +0 -149
- package/shared/skills/self-review/references/patterns.md +0 -405
- package/shared/skills/self-review/references/report-template.md +0 -253
- package/shared/skills/self-review/references/stub-detection.md +0 -135
- package/shared/skills/self-review/references/violations.md +0 -308
- package/shared/skills/test-driven-development/SKILL.md +0 -137
- package/shared/skills/test-driven-development/references/rationalization-prevention.md +0 -111
- package/shared/skills/test-patterns/SKILL.md +0 -183
- package/shared/skills/test-patterns/references/detection.md +0 -149
- package/shared/skills/test-patterns/references/patterns.md +0 -220
- package/shared/skills/test-patterns/references/report-template.md +0 -108
- package/shared/skills/test-patterns/references/violations.md +0 -221
- package/shared/skills/typescript/SKILL.md +0 -176
- package/shared/skills/typescript/references/patterns.md +0 -1105
- package/shared/skills/typescript/references/violations.md +0 -433
- package/src/templates/claudeignore.template +0 -188
- package/src/templates/settings.json +0 -59
- /package/dist/{utils → core}/safe-delete.js +0 -0
- /package/{plugins/devflow-accessibility → src/assets}/skills/accessibility/references/detection.md +0 -0
- /package/{plugins/devflow-code-review/skills/architecture-patterns → src/assets/skills/architecture}/references/detection.md +0 -0
- /package/{plugins/devflow-code-review/skills/complexity-patterns → src/assets/skills/complexity}/references/detection.md +0 -0
- /package/{plugins/devflow-code-review/skills/complexity-patterns → src/assets/skills/complexity}/references/patterns.md +0 -0
- /package/{plugins/devflow-code-review/skills/complexity-patterns → src/assets/skills/complexity}/references/violations.md +0 -0
- /package/{plugins/devflow-code-review/skills/consistency-patterns → src/assets/skills/consistency}/references/detection.md +0 -0
- /package/{plugins/devflow-code-review/skills/consistency-patterns → src/assets/skills/consistency}/references/patterns.md +0 -0
- /package/{plugins/devflow-code-review/skills/consistency-patterns → src/assets/skills/consistency}/references/violations.md +0 -0
- /package/{plugins/devflow-code-review/skills/database-patterns → src/assets/skills/database}/references/detection.md +0 -0
- /package/{plugins/devflow-code-review/skills/database-patterns → src/assets/skills/database}/references/patterns.md +0 -0
- /package/{plugins/devflow-code-review/skills/database-patterns → src/assets/skills/database}/references/violations.md +0 -0
- /package/{plugins/devflow-code-review/skills/dependencies-patterns → src/assets/skills/dependencies}/references/detection.md +0 -0
- /package/{plugins/devflow-code-review/skills/dependencies-patterns → src/assets/skills/dependencies}/references/patterns.md +0 -0
- /package/{plugins/devflow-code-review/skills/dependencies-patterns → src/assets/skills/dependencies}/references/violations.md +0 -0
- /package/{plugins/devflow-code-review/skills/documentation-patterns → src/assets/skills/documentation}/references/detection.md +0 -0
- /package/{plugins/devflow-code-review/skills/documentation-patterns → src/assets/skills/documentation}/references/patterns.md +0 -0
- /package/{plugins/devflow-code-review/skills/documentation-patterns → src/assets/skills/documentation}/references/violations.md +0 -0
- /package/{plugins/devflow-core-skills/skills/git-safety → src/assets/skills/git}/references/detection.md +0 -0
- /package/{plugins/devflow-go → src/assets}/skills/go/references/detection.md +0 -0
- /package/{plugins/devflow-java → src/assets}/skills/java/references/detection.md +0 -0
- /package/{plugins/devflow-implement/skills/implementation-patterns → src/assets/skills/patterns}/references/patterns.md +0 -0
- /package/{plugins/devflow-implement/skills/implementation-patterns → src/assets/skills/patterns}/references/violations.md +0 -0
- /package/{plugins/devflow-code-review/skills/performance-patterns → src/assets/skills/performance}/references/detection.md +0 -0
- /package/{plugins/devflow-python → src/assets}/skills/python/references/detection.md +0 -0
- /package/{plugins/devflow-implement/skills/self-review → src/assets/skills/quality-gates}/references/patterns.md +0 -0
- /package/{plugins/devflow-implement/skills/self-review → src/assets/skills/quality-gates}/references/report-template.md +0 -0
- /package/{plugins/devflow-implement/skills/self-review → src/assets/skills/quality-gates}/references/violations.md +0 -0
- /package/{plugins/devflow-code-review/skills/regression-patterns → src/assets/skills/regression}/references/detection.md +0 -0
- /package/{plugins/devflow-code-review/skills/regression-patterns → src/assets/skills/regression}/references/patterns.md +0 -0
- /package/{plugins/devflow-code-review/skills/regression-patterns → src/assets/skills/regression}/references/violations.md +0 -0
- /package/{plugins/devflow-rust → src/assets}/skills/rust/references/detection.md +0 -0
- /package/{plugins/devflow-code-review/skills/security-patterns → src/assets/skills/security}/references/detection.md +0 -0
- /package/{plugins/devflow-core-skills/skills/core-patterns → src/assets/skills/software-design}/references/detection.md +0 -0
- /package/{plugins/devflow-core-skills → src/assets}/skills/test-driven-development/references/rationalization-prevention.md +0 -0
- /package/{plugins/devflow-code-review/skills/test-patterns → src/assets/skills/testing}/references/detection.md +0 -0
- /package/{plugins/devflow-code-review/skills/test-patterns → src/assets/skills/testing}/references/report-template.md +0 -0
- /package/{plugins/devflow-frontend-design/skills/frontend-design → src/assets/skills/ui-design}/references/detection.md +0 -0
- /package/src/{templates → targets/claude-code/templates}/managed-settings.json +0 -0
|
@@ -0,0 +1,1214 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { promises as fs } from 'fs';
|
|
3
|
+
import * as os from 'os';
|
|
4
|
+
import * as path from 'path';
|
|
5
|
+
import * as p from '@clack/prompts';
|
|
6
|
+
import color from 'picocolors';
|
|
7
|
+
import { getInstallationPaths, getClaudeDirectory, getManagedSettingsPath } from '../../targets/claude-code/claude-paths.js';
|
|
8
|
+
import { getGitRoot } from '../../core/git.js';
|
|
9
|
+
import { DEVFLOW_PLUGINS, SKILL_NAMESPACE, getAllSkillNames, getAllAgentNames, getAllCommandNames, parsePluginSelection, resolveFeatureRedirect, prefixSkillName, unprefixSkillName, FEATURE_OWNED_SKILLS } from '../../core/plugins.js';
|
|
10
|
+
import { sweepOrphanedAssets, mdFileName, mdEntryName } from '../../core/orphan-sweep.js';
|
|
11
|
+
import { LEGACY_SKILL_NAMES } from '../../targets/claude-code/legacy.js';
|
|
12
|
+
import { removeAmbientHook } from './ambient.js';
|
|
13
|
+
import { removeMemoryHooks } from './memory.js';
|
|
14
|
+
import { removeCaptureHooks } from './capture.js';
|
|
15
|
+
import { removeDreamHook } from './legacy-hooks.js';
|
|
16
|
+
import { removeHudStatusLine } from './hud.js';
|
|
17
|
+
import { removeContextHook } from './context.js';
|
|
18
|
+
import { applyDisableToSettings } from './proxy.js';
|
|
19
|
+
import { readProxyState, DEFAULT_PROXY_PORT } from '../../core/proxy-state.js';
|
|
20
|
+
import { hudCacheDir } from '../../core/cache.js';
|
|
21
|
+
import { revertExternalAgents } from '../../core/agent-models.js';
|
|
22
|
+
import { detectShell, getProfilePath } from '../../core/safe-delete.js';
|
|
23
|
+
import { isAlreadyInstalled, removeFromProfile } from '../../core/safe-delete-install.js';
|
|
24
|
+
import { removeManagedSettings, stripUserDenyList, detectDenyState, DEVFLOW_HISTORICAL_DENY } from '../../targets/claude-code/post-install.js';
|
|
25
|
+
import { writeFileAtomicExclusive } from '../../core/fs-atomic.js';
|
|
26
|
+
import { stripFlags, stripViewMode } from '../../core/flags.js';
|
|
27
|
+
import { stripDevflowTeammateModeFromJson } from '../../core/teammate-mode-cleanup.js';
|
|
28
|
+
import { getPackageRoot, isContainedIn } from '../../core/paths.js';
|
|
29
|
+
/**
|
|
30
|
+
* Compute which assets should be removed during selective plugin uninstall.
|
|
31
|
+
* Skills and agents shared by remaining plugins are retained.
|
|
32
|
+
* Rules shared by remaining plugins are also retained.
|
|
33
|
+
*/
|
|
34
|
+
export function computeAssetsToRemove(selectedPlugins, allPlugins) {
|
|
35
|
+
const selectedNames = new Set(selectedPlugins.map(p => p.name));
|
|
36
|
+
const remainingPlugins = allPlugins.filter(p => !selectedNames.has(p.name));
|
|
37
|
+
const retainedSkills = new Set();
|
|
38
|
+
const retainedAgents = new Set();
|
|
39
|
+
const retainedRules = new Set();
|
|
40
|
+
for (const rp of remainingPlugins) {
|
|
41
|
+
for (const s of rp.skills)
|
|
42
|
+
retainedSkills.add(s);
|
|
43
|
+
for (const a of rp.agents)
|
|
44
|
+
retainedAgents.add(a);
|
|
45
|
+
for (const r of rp.rules)
|
|
46
|
+
retainedRules.add(r);
|
|
47
|
+
}
|
|
48
|
+
const skills = [];
|
|
49
|
+
const agents = [];
|
|
50
|
+
const commands = [];
|
|
51
|
+
const rules = [];
|
|
52
|
+
for (const plugin of selectedPlugins) {
|
|
53
|
+
for (const skill of plugin.skills) {
|
|
54
|
+
if (!retainedSkills.has(skill))
|
|
55
|
+
skills.push(skill);
|
|
56
|
+
}
|
|
57
|
+
for (const agent of plugin.agents) {
|
|
58
|
+
if (!retainedAgents.has(agent))
|
|
59
|
+
agents.push(agent);
|
|
60
|
+
}
|
|
61
|
+
for (const rule of plugin.rules) {
|
|
62
|
+
if (!retainedRules.has(rule))
|
|
63
|
+
rules.push(rule);
|
|
64
|
+
}
|
|
65
|
+
commands.push(...plugin.commands);
|
|
66
|
+
}
|
|
67
|
+
return { skills, agents, commands, rules };
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Format a dry-run plan showing what would be removed.
|
|
71
|
+
* Pure function — no I/O, fully testable.
|
|
72
|
+
*/
|
|
73
|
+
export function formatDryRunPlan(assets) {
|
|
74
|
+
const skills = [...new Set(assets.skills)];
|
|
75
|
+
const agents = [...new Set(assets.agents)];
|
|
76
|
+
const commands = [...new Set(assets.commands)];
|
|
77
|
+
const rules = [...new Set(assets.rules ?? [])];
|
|
78
|
+
const hasAssets = skills.length > 0 || agents.length > 0 || commands.length > 0 || rules.length > 0;
|
|
79
|
+
if (!hasAssets) {
|
|
80
|
+
return 'Nothing to remove.';
|
|
81
|
+
}
|
|
82
|
+
const lines = [];
|
|
83
|
+
if (skills.length > 0)
|
|
84
|
+
lines.push(`Skills (${skills.length}): ${skills.join(', ')}`);
|
|
85
|
+
if (agents.length > 0)
|
|
86
|
+
lines.push(`Agents (${agents.length}): ${agents.join(', ')}`);
|
|
87
|
+
if (commands.length > 0)
|
|
88
|
+
lines.push(`Commands (${commands.length}): ${commands.join(', ')}`);
|
|
89
|
+
if (rules.length > 0)
|
|
90
|
+
lines.push(`Rules (${rules.length}): ${rules.join(', ')}`);
|
|
91
|
+
return lines.join('\n');
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Determine whether the security deny list should prompt for removal in an
|
|
95
|
+
* interactive session, and what the non-interactive default is.
|
|
96
|
+
*
|
|
97
|
+
* PURE — no I/O, fully testable.
|
|
98
|
+
*
|
|
99
|
+
* Safety invariant: non-interactive mode NEVER removes the deny list
|
|
100
|
+
* (protective-by-default). `keepDocs` suppresses the entire section.
|
|
101
|
+
*
|
|
102
|
+
* Returns:
|
|
103
|
+
* - "skip" — nothing present, or keepDocs is set; no action needed
|
|
104
|
+
* - "preserve" — non-interactive (isTTY=false); deny list preserved
|
|
105
|
+
* - "prompt" — interactive (isTTY=true); caller should ask the user
|
|
106
|
+
*
|
|
107
|
+
* @D1 Non-interactive-preserve invariant: when isTTY is false the result is
|
|
108
|
+
* always "preserve", never "prompt" — avoids PF-004 half-applied-state hazard.
|
|
109
|
+
*/
|
|
110
|
+
export function resolveSecurityRemovalDecision(opts) {
|
|
111
|
+
if (!opts.anySecurityPresent || opts.keepDocs)
|
|
112
|
+
return 'skip';
|
|
113
|
+
if (!opts.isTTY)
|
|
114
|
+
return 'preserve';
|
|
115
|
+
return 'prompt';
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Resolve the answer from a Clack confirm prompt for the .devflow/ project data
|
|
119
|
+
* removal question into a boolean removal decision.
|
|
120
|
+
*
|
|
121
|
+
* A cancel (user presses Ctrl-C on this prompt) is treated as decline: the
|
|
122
|
+
* .devflow/ directory is preserved and the uninstall continues with the remaining
|
|
123
|
+
* steps rather than aborting via process.exit() (applies PF-014, applies ADR-003).
|
|
124
|
+
*
|
|
125
|
+
* PURE — no I/O, fully testable.
|
|
126
|
+
*
|
|
127
|
+
* @param answer - The value returned by p.confirm(): boolean or a cancel symbol.
|
|
128
|
+
* @returns true only when the user explicitly confirmed removal.
|
|
129
|
+
*/
|
|
130
|
+
export function resolveProjectDataCleanup(answer) {
|
|
131
|
+
return answer === true;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Determine the appropriate cleanup action for the user-scope devflow directory on
|
|
135
|
+
* full uninstall. Mirrors the resolveSecurityRemovalDecision pattern.
|
|
136
|
+
*
|
|
137
|
+
* PURE — no I/O, no side effects, fully testable. All decision logic lives here;
|
|
138
|
+
* the .action() caller performs I/O and prompt rendering only.
|
|
139
|
+
*
|
|
140
|
+
* Safety invariants checked as preconditions (guard fires → 'artifacts-only'):
|
|
141
|
+
* 1. basename(devflowDir) must be '.devflow'
|
|
142
|
+
* 2. devflowDir must not equal homeDir
|
|
143
|
+
* 3. devflowDir must not be the filesystem root '/'
|
|
144
|
+
* 4. devflowDir must reside inside $HOME (guards DEVFLOW_DIR env overrides)
|
|
145
|
+
*
|
|
146
|
+
* Returns:
|
|
147
|
+
* - 'artifacts-only' — remove only manifest.json; leave the directory intact
|
|
148
|
+
* - 'prompt' — interactive session with user-authored content; caller should ask
|
|
149
|
+
*
|
|
150
|
+
* @D5 Precondition guard: any anomalous devflowDir falls back to 'artifacts-only' rather
|
|
151
|
+
* than throwing — business logic must not throw (engineering rule). The explicit guard
|
|
152
|
+
* makes the invariant present in production code, not only in tests (reliability rule).
|
|
153
|
+
* @D6 avoids PF-014: the caller must NOT process.exit() after a cancel/decline response;
|
|
154
|
+
* removeAllDevFlow has already run by the time the prompt fires, so removeDevFlowInstallArtifacts
|
|
155
|
+
* must execute on every non-confirm path to leave a clean end-state (applies ADR-003).
|
|
156
|
+
* @D7 keepDocs gate: when the caller passes --keep-docs, the entire ~/.devflow dir cleanup
|
|
157
|
+
* prompt is suppressed — artifacts-only regardless of isTTY or userContent. This prevents
|
|
158
|
+
* --keep-docs from triggering prompts about skill shadows or preference-profile.md.
|
|
159
|
+
*/
|
|
160
|
+
export function resolveDevflowDirCleanup(opts) {
|
|
161
|
+
// Local scope never removes project data — only install artifacts.
|
|
162
|
+
if (opts.scope !== 'user')
|
|
163
|
+
return 'artifacts-only';
|
|
164
|
+
// --keep-docs: suppress the full cleanup prompt entirely; artifacts-only.
|
|
165
|
+
if (opts.keepDocs)
|
|
166
|
+
return 'artifacts-only';
|
|
167
|
+
// Precondition guard: devflowDir must be a well-known, safe-to-rm path.
|
|
168
|
+
// Any anomalous value (DEVFLOW_DIR override, bare homedir, filesystem root)
|
|
169
|
+
// resolves to artifacts-only — never throw in business logic (engineering rule).
|
|
170
|
+
const isBasenameValid = path.basename(opts.devflowDir) === '.devflow';
|
|
171
|
+
const isNotHomeDir = opts.devflowDir !== opts.homeDir;
|
|
172
|
+
const isNotRoot = opts.devflowDir !== '/';
|
|
173
|
+
const isInsideHome = opts.devflowDir.startsWith(opts.homeDir + path.sep);
|
|
174
|
+
if (!isBasenameValid || !isNotHomeDir || !isNotRoot || !isInsideHome) {
|
|
175
|
+
return 'artifacts-only';
|
|
176
|
+
}
|
|
177
|
+
// Non-interactive: never prompt for or perform full-dir removal.
|
|
178
|
+
if (!opts.isTTY)
|
|
179
|
+
return 'artifacts-only';
|
|
180
|
+
// No user-authored content: nothing to warn about; artifacts-only without prompting.
|
|
181
|
+
if (opts.userContent.length === 0)
|
|
182
|
+
return 'artifacts-only';
|
|
183
|
+
return 'prompt';
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Enumerate user-authored content in devflowDir that would be deleted by a
|
|
187
|
+
* full cleanup of the directory.
|
|
188
|
+
*
|
|
189
|
+
* Checks for items that exist on disk and are worth backing up:
|
|
190
|
+
* devflowDir/skills/ — skill shadow overrides (user-maintained)
|
|
191
|
+
* devflowDir/rules/ — rule shadow overrides (user-maintained)
|
|
192
|
+
* devflowDir/preference-profile.md — dynamic-plan preference profile
|
|
193
|
+
* devflowDir/learning.json — global learning agent tuning config
|
|
194
|
+
* devflowDir/hud.json — HUD enable/disable preference and display config
|
|
195
|
+
*
|
|
196
|
+
* NOT listed here: agent-models.json — reclassified as an INSTALL ARTIFACT (AC-P1-F4).
|
|
197
|
+
* Stale per-agent model overrides silently re-apply to renamed/deleted agents on reinstall,
|
|
198
|
+
* so it must be cleaned up by removeDevFlowInstallArtifacts, not preserved behind a confirm gate.
|
|
199
|
+
*
|
|
200
|
+
* Returns labels for each item that actually exists. Empty array means nothing
|
|
201
|
+
* user-authored is present in the directory.
|
|
202
|
+
*
|
|
203
|
+
* Pure I/O — no side effects, no output, fully testable.
|
|
204
|
+
*
|
|
205
|
+
* @D4 Called BEFORE any removal so shadow state is captured from real disk.
|
|
206
|
+
* Avoids the anti-pattern of checking existence after files are removed.
|
|
207
|
+
*/
|
|
208
|
+
export async function enumerateUserDevFlowContent(devflowDir) {
|
|
209
|
+
const items = [];
|
|
210
|
+
// Skill shadow overrides (~/.devflow/skills/{name}/)
|
|
211
|
+
try {
|
|
212
|
+
const entries = await fs.readdir(path.join(devflowDir, 'skills'));
|
|
213
|
+
if (entries.length > 0) {
|
|
214
|
+
items.push(`skill shadows (${path.join(devflowDir, 'skills')})`);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
catch { /* dir absent or unreadable */ }
|
|
218
|
+
// Rule shadow overrides (~/.devflow/rules/{name}.md)
|
|
219
|
+
try {
|
|
220
|
+
const entries = await fs.readdir(path.join(devflowDir, 'rules'));
|
|
221
|
+
if (entries.length > 0) {
|
|
222
|
+
items.push(`rule shadows (${path.join(devflowDir, 'rules')})`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
catch { /* dir absent or unreadable */ }
|
|
226
|
+
// preference-profile.md — user-curated decision-preference profile
|
|
227
|
+
try {
|
|
228
|
+
await fs.access(path.join(devflowDir, 'preference-profile.md'));
|
|
229
|
+
items.push('preference-profile.md');
|
|
230
|
+
}
|
|
231
|
+
catch { /* absent */ }
|
|
232
|
+
// learning.json — global learning agent tuning config
|
|
233
|
+
try {
|
|
234
|
+
await fs.access(path.join(devflowDir, 'learning.json'));
|
|
235
|
+
items.push('learning.json');
|
|
236
|
+
}
|
|
237
|
+
catch { /* absent */ }
|
|
238
|
+
// hud.json — user HUD enable/disable preference and display config
|
|
239
|
+
try {
|
|
240
|
+
await fs.access(path.join(devflowDir, 'hud.json'));
|
|
241
|
+
items.push('hud.json (HUD configuration)');
|
|
242
|
+
}
|
|
243
|
+
catch { /* absent */ }
|
|
244
|
+
return items;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Single source of truth for Devflow-owned install artifacts under `devflowDir`.
|
|
248
|
+
*
|
|
249
|
+
* Returns the paths that the artifact-removal loop inside `removeDevFlowInstallArtifacts`
|
|
250
|
+
* removes. Note: manifest.json is removed by a separate step at the top of that
|
|
251
|
+
* function and is NOT in this list. Having this as a standalone pure function
|
|
252
|
+
* lets callers (dry-run display, tests) enumerate the artifact set without
|
|
253
|
+
* duplicating the list.
|
|
254
|
+
*
|
|
255
|
+
* @D8 Nothing returned here may overlap with the items enumerated by
|
|
256
|
+
* `enumerateUserDevFlowContent` — the disjointness invariant is tested by test 9f
|
|
257
|
+
* and enforced by keeping both lists in one place.
|
|
258
|
+
*
|
|
259
|
+
* @param devflowDir - Absolute path to ~/.devflow (used to resolve cache dir).
|
|
260
|
+
*/
|
|
261
|
+
export function installArtifactPaths(devflowDir) {
|
|
262
|
+
return [
|
|
263
|
+
// migration run-state — removed so migrations re-run cleanly on reinstall
|
|
264
|
+
{ relPath: 'migrations.json' },
|
|
265
|
+
// per-agent model overrides — removed so stale keys (keyed to renamed/deleted agents
|
|
266
|
+
// from the wave-4 agent roster rename) cannot silently re-apply on reinstall (AC-P1-F4)
|
|
267
|
+
{ relPath: 'agent-models.json' },
|
|
268
|
+
// cost history — auto-generated session telemetry, not user-authored.
|
|
269
|
+
// The whole costs/ tree is removed so sessions/ and archive.jsonl cannot
|
|
270
|
+
// drift from their write sites in src/hud/cost-history.ts (avoids PF-013).
|
|
271
|
+
{ relPath: 'costs', isDir: true },
|
|
272
|
+
// proxy artifacts
|
|
273
|
+
{ relPath: 'proxy.json' },
|
|
274
|
+
{ relPath: 'proxy-routing.json' },
|
|
275
|
+
{ relPath: 'proxy.pid' },
|
|
276
|
+
{ relPath: '.proxy-spawn.lock', isDir: true },
|
|
277
|
+
// per-project hook logs (logs/{project-slug}/) AND global logs — remove the
|
|
278
|
+
// whole logs/ tree; covers proxy.log, debug logs, and any project-slug dirs.
|
|
279
|
+
{ relPath: 'logs', isDir: true },
|
|
280
|
+
// Model-discovery + HUD component caches. hudCacheDir() is the authoritative
|
|
281
|
+
// accessor for the cache/ parent (modelCacheDir() resolves beneath it), so the
|
|
282
|
+
// removal site stays byte-locked to the write sites (avoids PF-013).
|
|
283
|
+
{ relPath: path.relative(devflowDir, hudCacheDir(devflowDir)), isDir: true },
|
|
284
|
+
];
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Remove Devflow install artifacts from devflowDir: manifest.json, migrations.json,
|
|
288
|
+
* proxy artifacts, logs/, costs/, and cache/.
|
|
289
|
+
* The scripts/ directory is already removed by removeAllDevFlow.
|
|
290
|
+
*
|
|
291
|
+
* Used for:
|
|
292
|
+
* - Local scope (always — never removes project data under .devflow/)
|
|
293
|
+
* - User scope when full-dir confirm is declined or session is non-interactive
|
|
294
|
+
*
|
|
295
|
+
* @D8 Nothing enumerated by enumerateUserDevFlowContent may appear in this list.
|
|
296
|
+
* This function runs on the decline, cancel, non-interactive AND --keep-docs paths,
|
|
297
|
+
* so an entry here is deleted even when the user answers "no" to the full wipe.
|
|
298
|
+
* User-authored state (skill/rule shadows, preference-profile.md, learning.json,
|
|
299
|
+
* hud.json) is removed only by the confirmed full-dir rm.
|
|
300
|
+
* agent-models.json is an INSTALL ARTIFACT (stale per-agent overrides silently
|
|
301
|
+
* re-apply to renamed/deleted agents on reinstall — AC-P1-F4) and therefore
|
|
302
|
+
* belongs in this list, not in enumerateUserDevFlowContent.
|
|
303
|
+
*/
|
|
304
|
+
export async function removeDevFlowInstallArtifacts(devflowDir, verbose) {
|
|
305
|
+
const manifestPath = path.join(devflowDir, 'manifest.json');
|
|
306
|
+
try {
|
|
307
|
+
await fs.rm(manifestPath, { force: true });
|
|
308
|
+
if (verbose) {
|
|
309
|
+
p.log.success('Removed manifest.json');
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
catch (error) {
|
|
313
|
+
p.log.warn(`Could not remove manifest.json: ${error}`);
|
|
314
|
+
}
|
|
315
|
+
// Proxy install artifacts — remove non-fatally (per-item failure isolation, avoids PF-009)
|
|
316
|
+
// Inform the user if a proxy relay process is still running (never kill — informational only).
|
|
317
|
+
try {
|
|
318
|
+
const pidContent = await fs.readFile(path.join(devflowDir, 'proxy.pid'), 'utf-8');
|
|
319
|
+
const pid = parseInt(pidContent.trim(), 10);
|
|
320
|
+
if (!isNaN(pid) && pid > 0) {
|
|
321
|
+
try {
|
|
322
|
+
process.kill(pid, 0); // existence check — throws if process is gone
|
|
323
|
+
p.log.warn(`Proxy relay process (PID ${pid}) is still running — it will exit when ` +
|
|
324
|
+
`Claude Code closes, or stop it manually: kill ${pid}`);
|
|
325
|
+
}
|
|
326
|
+
catch { /* process is gone — nothing to report */ }
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
catch { /* proxy.pid absent or unreadable — non-fatal */ }
|
|
330
|
+
// All install artifacts removed non-fatally (avoids PF-009).
|
|
331
|
+
for (const artifact of installArtifactPaths(devflowDir)) {
|
|
332
|
+
const fullPath = path.join(devflowDir, artifact.relPath);
|
|
333
|
+
// Containment invariant: every artifact must resolve to a path STRICTLY inside
|
|
334
|
+
// devflowDir. A derived relPath that ever collapsed to '' or '..' would turn the
|
|
335
|
+
// recursive rm below into a wipe of devflowDir itself (or an ancestor). Asserting
|
|
336
|
+
// it in production code — not only in tests — keeps the invariant load-bearing
|
|
337
|
+
// (reliability rule) and never throws (engineering rule).
|
|
338
|
+
if (!isContainedIn(devflowDir, artifact.relPath)) {
|
|
339
|
+
continue;
|
|
340
|
+
}
|
|
341
|
+
try {
|
|
342
|
+
await fs.rm(fullPath, { force: true, recursive: artifact.isDir === true });
|
|
343
|
+
if (verbose)
|
|
344
|
+
p.log.success(`Removed ${artifact.relPath}`);
|
|
345
|
+
}
|
|
346
|
+
catch { /* absent or unreadable — non-fatal */ }
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Check if Devflow is installed at the given claudeDir by detecting any
|
|
351
|
+
* owned namespace: commands/devflow/, agents/devflow/, or any skill dir
|
|
352
|
+
* whose name starts with the devflow: namespace prefix.
|
|
353
|
+
*
|
|
354
|
+
* Keying off commands/devflow/ alone misses installs where the user selected
|
|
355
|
+
* a commandless plugin set — agents and skills may still be present.
|
|
356
|
+
*/
|
|
357
|
+
export async function isDevFlowInstalled(claudeDir) {
|
|
358
|
+
// Check commands namespace
|
|
359
|
+
try {
|
|
360
|
+
await fs.access(path.join(claudeDir, 'commands', 'devflow'));
|
|
361
|
+
return true;
|
|
362
|
+
}
|
|
363
|
+
catch { /* not present */ }
|
|
364
|
+
// Check agents namespace
|
|
365
|
+
try {
|
|
366
|
+
await fs.access(path.join(claudeDir, 'agents', 'devflow'));
|
|
367
|
+
return true;
|
|
368
|
+
}
|
|
369
|
+
catch { /* not present */ }
|
|
370
|
+
// Check for any installed skill under the devflow: namespace
|
|
371
|
+
try {
|
|
372
|
+
const entries = await fs.readdir(path.join(claudeDir, 'skills'));
|
|
373
|
+
if (entries.some(e => e.startsWith(SKILL_NAMESPACE)))
|
|
374
|
+
return true;
|
|
375
|
+
}
|
|
376
|
+
catch { /* skills dir absent or unreadable */ }
|
|
377
|
+
return false;
|
|
378
|
+
}
|
|
379
|
+
// ---------------------------------------------------------------------------
|
|
380
|
+
// Phase runners — extracted from the action function for readability and
|
|
381
|
+
// independent testability. Each covers one logical stage of the uninstall.
|
|
382
|
+
// ---------------------------------------------------------------------------
|
|
383
|
+
/**
|
|
384
|
+
* Enumerate paths that would be removed by a full uninstall for the given
|
|
385
|
+
* scope directories, intersected with what actually exists on disk.
|
|
386
|
+
*
|
|
387
|
+
* Extracted from the dry-run loop body so the enumeration logic is
|
|
388
|
+
* independently testable (avoids PF-018: tests must exercise the production
|
|
389
|
+
* path, not only the pure helper functions).
|
|
390
|
+
*
|
|
391
|
+
* Coverage matches removeAllDevFlow exactly:
|
|
392
|
+
* 1. Whole Claude directories (commands/devflow, agents/devflow, rules/devflow)
|
|
393
|
+
* and the scripts directory inside devflowDir.
|
|
394
|
+
* 2. ALL skill removal candidates (existence-filtered):
|
|
395
|
+
* - Prefixed (devflow:name): live registry ∪ LEGACY_SKILL_NAMES.
|
|
396
|
+
* - Bare (name or devflow-name legacy): LEGACY_SKILL_NAMES ONLY.
|
|
397
|
+
* ~/.claude/skills/ is shared; bare dirs for live-registry skill names
|
|
398
|
+
* are by construction foreign to Devflow (avoids PF-012).
|
|
399
|
+
* 3. manifest.json (removed separately in removeDevFlowInstallArtifacts).
|
|
400
|
+
* 4. Every artifact path from installArtifactPaths(devflowDir) — the single
|
|
401
|
+
* source of truth shared with the real removal loop.
|
|
402
|
+
*
|
|
403
|
+
* @param claudeDir - Target Claude Code directory (e.g. ~/.claude)
|
|
404
|
+
* @param devflowDir - Devflow data directory (e.g. ~/.devflow)
|
|
405
|
+
*/
|
|
406
|
+
export async function enumerateDryRunExtras(claudeDir, devflowDir) {
|
|
407
|
+
const extras = [];
|
|
408
|
+
// 1. Whole directories removed by removeAllDevFlow
|
|
409
|
+
for (const dir of [
|
|
410
|
+
path.join(claudeDir, 'commands', 'devflow'),
|
|
411
|
+
path.join(claudeDir, 'agents', 'devflow'),
|
|
412
|
+
path.join(claudeDir, 'rules', 'devflow'),
|
|
413
|
+
path.join(devflowDir, 'scripts'),
|
|
414
|
+
]) {
|
|
415
|
+
try {
|
|
416
|
+
await fs.access(dir);
|
|
417
|
+
extras.push(dir);
|
|
418
|
+
}
|
|
419
|
+
catch { /* absent */ }
|
|
420
|
+
}
|
|
421
|
+
// 2. Skills: enumerate ALL removal candidates that exist on disk.
|
|
422
|
+
// Mirrors removeAllDevFlow's split-pass approach (avoids PF-012 + PF-018):
|
|
423
|
+
// Prefixed: live registry ∪ LEGACY_SKILL_NAMES ∪ FEATURE_OWNED_SKILLS
|
|
424
|
+
// Bare: LEGACY_SKILL_NAMES only — shared skills/ dir; live-registry bare
|
|
425
|
+
// dirs are by construction foreign to Devflow.
|
|
426
|
+
// FEATURE_OWNED_SKILLS (compliance) is included so full uninstall removes
|
|
427
|
+
// devflow:compliance even though it left the plugin registry (step 1.5).
|
|
428
|
+
const prefixedSkillNames = new Set([...getAllSkillNames(), ...LEGACY_SKILL_NAMES, ...FEATURE_OWNED_SKILLS]);
|
|
429
|
+
const skillsDir = path.join(claudeDir, 'skills');
|
|
430
|
+
for (const skillName of prefixedSkillNames) {
|
|
431
|
+
const prefixedPath = path.join(skillsDir, prefixSkillName(skillName));
|
|
432
|
+
try {
|
|
433
|
+
await fs.access(prefixedPath);
|
|
434
|
+
extras.push(prefixedPath);
|
|
435
|
+
}
|
|
436
|
+
catch { /* absent */ }
|
|
437
|
+
}
|
|
438
|
+
for (const skillName of LEGACY_SKILL_NAMES) {
|
|
439
|
+
const barePath = path.join(skillsDir, skillName);
|
|
440
|
+
try {
|
|
441
|
+
await fs.access(barePath);
|
|
442
|
+
extras.push(barePath);
|
|
443
|
+
}
|
|
444
|
+
catch { /* absent */ }
|
|
445
|
+
}
|
|
446
|
+
// 3. manifest.json — removed separately by removeDevFlowInstallArtifacts
|
|
447
|
+
// (NOT in installArtifactPaths). List it here so the preview is complete.
|
|
448
|
+
const manifestPath = path.join(devflowDir, 'manifest.json');
|
|
449
|
+
try {
|
|
450
|
+
await fs.access(manifestPath);
|
|
451
|
+
extras.push(manifestPath);
|
|
452
|
+
}
|
|
453
|
+
catch { /* absent */ }
|
|
454
|
+
// 4. All install artifacts — derived from the single source of truth shared
|
|
455
|
+
// with the real removal loop (removeDevFlowInstallArtifacts).
|
|
456
|
+
// Guard with fs.access so files that never existed don't pollute the preview.
|
|
457
|
+
// (F7: previously pushed unconditionally, inflating the dry-run list with
|
|
458
|
+
// paths that were never on disk.)
|
|
459
|
+
for (const artifact of installArtifactPaths(devflowDir)) {
|
|
460
|
+
const fullPath = path.join(devflowDir, artifact.relPath);
|
|
461
|
+
try {
|
|
462
|
+
await fs.access(fullPath);
|
|
463
|
+
extras.push(fullPath);
|
|
464
|
+
}
|
|
465
|
+
catch { /* absent — omit from dry-run preview */ }
|
|
466
|
+
}
|
|
467
|
+
return extras;
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* DRY-RUN PHASE: display what would be removed without making any changes.
|
|
471
|
+
*
|
|
472
|
+
* Selective: uses the pure registry-diff plan from formatDryRunPlan.
|
|
473
|
+
* Full: enumerates what is actually on disk for each detected scope so the
|
|
474
|
+
* output reflects legacy/orphaned assets that the registry cannot see.
|
|
475
|
+
*
|
|
476
|
+
* @param opts.scopesToUninstall - Scopes detected in the setup phase.
|
|
477
|
+
* @param opts.isSelectiveUninstall - true when --plugin was given.
|
|
478
|
+
* @param opts.selectedPlugins - The plugin subset for selective mode.
|
|
479
|
+
*/
|
|
480
|
+
export async function runDryRunPhase(opts) {
|
|
481
|
+
const { scopesToUninstall, isSelectiveUninstall, selectedPlugins } = opts;
|
|
482
|
+
p.log.info(`Scope(s): ${[...scopesToUninstall].join(', ')} (dry-run shows all detected scopes)`);
|
|
483
|
+
if (isSelectiveUninstall) {
|
|
484
|
+
// Selective: compute from registry — this accurately reflects what would be removed.
|
|
485
|
+
const assets = computeAssetsToRemove(selectedPlugins, DEVFLOW_PLUGINS);
|
|
486
|
+
const plan = formatDryRunPlan(assets);
|
|
487
|
+
for (const line of plan.split('\n')) {
|
|
488
|
+
p.log.info(line);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
else {
|
|
492
|
+
// Full uninstall: the real path does rm -rf on entire directories plus a
|
|
493
|
+
// skills sweep. Enumerate what is actually on disk for each detected scope
|
|
494
|
+
// rather than computing from the registry (which misses legacy/orphaned assets).
|
|
495
|
+
const extras = [];
|
|
496
|
+
for (const scope of [...scopesToUninstall]) {
|
|
497
|
+
try {
|
|
498
|
+
const paths = await getInstallationPaths(scope);
|
|
499
|
+
const { claudeDir: cd, devflowDir: dd } = paths;
|
|
500
|
+
const moreExtras = await enumerateDryRunExtras(cd, dd);
|
|
501
|
+
extras.push(...moreExtras);
|
|
502
|
+
}
|
|
503
|
+
catch { /* scope path resolution failed */ }
|
|
504
|
+
}
|
|
505
|
+
// Project .devflow/ data dir
|
|
506
|
+
const devflowDataDir = path.join(process.cwd(), '.devflow');
|
|
507
|
+
try {
|
|
508
|
+
await fs.access(devflowDataDir);
|
|
509
|
+
extras.push(`${devflowDataDir} (if confirmed)`);
|
|
510
|
+
}
|
|
511
|
+
catch { /* noop */ }
|
|
512
|
+
extras.push('hooks removed from settings.json');
|
|
513
|
+
for (const line of extras) {
|
|
514
|
+
p.log.info(` ${line}`);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
/**
|
|
519
|
+
* SELECTIVE PHASE (per scope): revert agent model overrides, remove the
|
|
520
|
+
* selected plugins' assets, and clean up the ambient hook if the ambient
|
|
521
|
+
* plugin is being removed.
|
|
522
|
+
*
|
|
523
|
+
* @param opts.claudeDir - Target Claude Code directory for this scope.
|
|
524
|
+
* @param opts.devflowDir - Devflow data directory for this scope.
|
|
525
|
+
* @param opts.selectedPlugins - Plugin subset to remove.
|
|
526
|
+
* @param opts.verbose - Whether to emit verbose log lines.
|
|
527
|
+
*/
|
|
528
|
+
export async function runSelectivePhaseForScope(opts) {
|
|
529
|
+
const { claudeDir, devflowDir, selectedPlugins, verbose } = opts;
|
|
530
|
+
// Revert GPT agent frontmatter BEFORE removing agent files — strips GPT model
|
|
531
|
+
// lines from installed agent frontmatter while the files are still present.
|
|
532
|
+
// Non-fatal: tolerate missing agents dir or revert errors.
|
|
533
|
+
{
|
|
534
|
+
const agentsInstallDir = path.join(claudeDir, 'agents', 'devflow');
|
|
535
|
+
try {
|
|
536
|
+
await fs.access(agentsInstallDir);
|
|
537
|
+
await revertExternalAgents({
|
|
538
|
+
installDir: agentsInstallDir,
|
|
539
|
+
devflowDir,
|
|
540
|
+
onWarning: (msg) => { if (verbose)
|
|
541
|
+
p.log.warn(msg); },
|
|
542
|
+
});
|
|
543
|
+
}
|
|
544
|
+
catch { /* agents dir absent or revert failed — non-fatal */ }
|
|
545
|
+
}
|
|
546
|
+
await removeSelectedPlugins(claudeDir, selectedPlugins, verbose);
|
|
547
|
+
// Clean up ambient hook if ambient plugin is being removed
|
|
548
|
+
if (selectedPlugins.some(sp => sp.name === 'devflow-ambient')) {
|
|
549
|
+
const settingsPath = path.join(claudeDir, 'settings.json');
|
|
550
|
+
try {
|
|
551
|
+
const settings = await fs.readFile(settingsPath, 'utf-8');
|
|
552
|
+
const updated = await removeAmbientHook(settings);
|
|
553
|
+
if (updated !== settings) {
|
|
554
|
+
await fs.writeFile(settingsPath, updated, 'utf-8');
|
|
555
|
+
if (verbose) {
|
|
556
|
+
p.log.success('Ambient mode hooks removed from settings.json');
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
catch { /* settings.json may not exist */ }
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
/**
|
|
564
|
+
* FULL PHASE (per scope): revert agent model overrides, remove all Devflow
|
|
565
|
+
* assets from the scope, then perform scope-appropriate devflowDir cleanup.
|
|
566
|
+
*
|
|
567
|
+
* Local scope: remove only install artifacts — project data (memory, learning,
|
|
568
|
+
* docs, features) is always preserved under the git root.
|
|
569
|
+
* User scope: interactive TTY with user-authored content → confirm before wiping
|
|
570
|
+
* ~/.devflow/; non-interactive or no user content → artifacts-only.
|
|
571
|
+
*
|
|
572
|
+
* @param opts.scope - 'user' or 'local'.
|
|
573
|
+
* @param opts.claudeDir - Target Claude Code directory for this scope.
|
|
574
|
+
* @param opts.devflowDir - Devflow data directory for this scope.
|
|
575
|
+
* @param opts.devflowScriptsDir - scripts/ sub-directory removed by removeAllDevFlow.
|
|
576
|
+
* @param opts.verbose - Whether to emit verbose log lines.
|
|
577
|
+
* @param opts.keepDocs - When true, suppresses the full-dir prompt (artifacts-only).
|
|
578
|
+
* @param opts.isTTY - Whether the session is interactive. Injected rather than
|
|
579
|
+
* read from process.stdin so the prompt gate is an explicit input (matching
|
|
580
|
+
* resolveDevflowDirCleanup) instead of an ambient global a test cannot control.
|
|
581
|
+
*/
|
|
582
|
+
export async function runFullPhaseForScope(opts) {
|
|
583
|
+
const { scope, claudeDir, devflowDir, devflowScriptsDir, verbose, keepDocs, isTTY } = opts;
|
|
584
|
+
// Revert GPT agent frontmatter before removing agents — ensures no orphaned
|
|
585
|
+
// GPT model lines remain if agents dir is preserved by a later partial flow.
|
|
586
|
+
// Non-fatal: tolerate missing agents dir or revert errors.
|
|
587
|
+
{
|
|
588
|
+
const agentsInstallDir = path.join(claudeDir, 'agents', 'devflow');
|
|
589
|
+
try {
|
|
590
|
+
await fs.access(agentsInstallDir);
|
|
591
|
+
await revertExternalAgents({
|
|
592
|
+
installDir: agentsInstallDir,
|
|
593
|
+
devflowDir,
|
|
594
|
+
onWarning: (msg) => { if (verbose)
|
|
595
|
+
p.log.warn(msg); },
|
|
596
|
+
});
|
|
597
|
+
}
|
|
598
|
+
catch { /* agents dir absent or revert failed — non-fatal */ }
|
|
599
|
+
}
|
|
600
|
+
// removeAllDevFlow removes Claude Code assets (commands, agents, rules, skills)
|
|
601
|
+
// and devflowDir/scripts/. Scope-aware cleanup handles the rest of devflowDir.
|
|
602
|
+
await removeAllDevFlow(claudeDir, devflowScriptsDir, verbose);
|
|
603
|
+
if (scope === 'local') {
|
|
604
|
+
// Local scope: devflowDir is gitRoot/.devflow/ which holds project data
|
|
605
|
+
// (memory, learning, features, docs, config.json). Never remove those —
|
|
606
|
+
// only remove install artifacts: scripts/ (done above) + manifest.json and
|
|
607
|
+
// the other Devflow-generated artifacts (see removeDevFlowInstallArtifacts).
|
|
608
|
+
await removeDevFlowInstallArtifacts(devflowDir, verbose);
|
|
609
|
+
p.log.info('Local project data (memory, learning, features, docs) preserved');
|
|
610
|
+
}
|
|
611
|
+
else {
|
|
612
|
+
// User scope (devflowDir = ~/.devflow/): offer full cleanup behind a confirm gate
|
|
613
|
+
// that enumerates user-authored content worth backing up before wiping the dir.
|
|
614
|
+
// Non-interactive, no user content, or precondition guard failure → artifacts-only.
|
|
615
|
+
const userContent = await enumerateUserDevFlowContent(devflowDir);
|
|
616
|
+
const cleanupDecision = resolveDevflowDirCleanup({
|
|
617
|
+
scope: 'user',
|
|
618
|
+
isTTY,
|
|
619
|
+
userContent,
|
|
620
|
+
devflowDir,
|
|
621
|
+
homeDir: os.homedir(),
|
|
622
|
+
keepDocs,
|
|
623
|
+
});
|
|
624
|
+
if (cleanupDecision === 'artifacts-only') {
|
|
625
|
+
await removeDevFlowInstallArtifacts(devflowDir, verbose);
|
|
626
|
+
if (!isTTY && userContent.length > 0) {
|
|
627
|
+
p.log.info(`${devflowDir} preserved (non-interactive mode — removing scripts and install artifacts only)`);
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
else {
|
|
631
|
+
// cleanupDecision === 'prompt': interactive session with user-authored content present.
|
|
632
|
+
p.log.info(`User-authored content in ${devflowDir}:`);
|
|
633
|
+
for (const item of userContent) {
|
|
634
|
+
p.log.info(` ${item}`);
|
|
635
|
+
}
|
|
636
|
+
const confirmFullCleanup = await p.confirm({
|
|
637
|
+
message: `Remove entire ${devflowDir}? (includes the items listed above, plus logs and install metadata)`,
|
|
638
|
+
initialValue: false,
|
|
639
|
+
});
|
|
640
|
+
if (p.isCancel(confirmFullCleanup)) {
|
|
641
|
+
// removeAllDevFlow already ran — clean up the manifest to leave a consistent
|
|
642
|
+
// state. avoids PF-014: process.exit() here would skip removeDevFlowInstallArtifacts,
|
|
643
|
+
// leaving a stale manifest.json that points to assets no longer on disk.
|
|
644
|
+
await removeDevFlowInstallArtifacts(devflowDir, verbose);
|
|
645
|
+
p.log.info(`${devflowDir} preserved (full removal cancelled; removing scripts and install artifacts only)`);
|
|
646
|
+
}
|
|
647
|
+
else if (confirmFullCleanup) {
|
|
648
|
+
await fs.rm(devflowDir, { recursive: true, force: true });
|
|
649
|
+
p.log.success(`${devflowDir} removed`);
|
|
650
|
+
}
|
|
651
|
+
else {
|
|
652
|
+
await removeDevFlowInstallArtifacts(devflowDir, verbose);
|
|
653
|
+
p.log.info(`${devflowDir} preserved (removing scripts and install artifacts only)`);
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
/**
|
|
659
|
+
* CLEANUP PHASE: post-loop extras run only on full uninstall.
|
|
660
|
+
*
|
|
661
|
+
* Steps (all non-fatal, every interactive path gated on opts.isTTY):
|
|
662
|
+
* 1. .devflow/ project data directory
|
|
663
|
+
* 2. .claudeignore
|
|
664
|
+
* 3. settings.json — remove all Devflow hooks and flags
|
|
665
|
+
* 4. Security deny list
|
|
666
|
+
* 5. Safe-delete shell function
|
|
667
|
+
*
|
|
668
|
+
* This phase touches machine-wide state outside `cwd` — the user's settings.json
|
|
669
|
+
* and shell profile — so both of its ambient inputs are injected: `cwd` (which now
|
|
670
|
+
* also seeds the git-root lookup) and `isTTY`. Reading process.stdin.isTTY directly
|
|
671
|
+
* would leave every destructive prompt gated on a global the caller cannot set,
|
|
672
|
+
* which under a TTY test runner points the prompts at the developer's real files.
|
|
673
|
+
*
|
|
674
|
+
* @param opts.scopesToUninstall - Scopes processed by the scope loop.
|
|
675
|
+
* @param opts.keepDocs - When true, .devflow/ and security prompts are suppressed.
|
|
676
|
+
* @param opts.verbose - Whether to emit verbose log lines.
|
|
677
|
+
* @param opts.cwd - Working directory for project-local path resolution
|
|
678
|
+
* (.devflow/, git root, .claudeignore fallback).
|
|
679
|
+
* @param opts.isTTY - Whether the session is interactive. Every confirm
|
|
680
|
+
* prompt in this phase is gated on it.
|
|
681
|
+
*/
|
|
682
|
+
export async function runCleanupPhase(opts) {
|
|
683
|
+
const { scopesToUninstall, keepDocs, verbose, cwd, isTTY } = opts;
|
|
684
|
+
// Resolve the git root from the injected cwd, not process.cwd(): otherwise
|
|
685
|
+
// .devflow/ resolves under `cwd` while .claudeignore resolves under the process
|
|
686
|
+
// directory, and the two halves of this phase act on different repositories.
|
|
687
|
+
const gitRoot = await getGitRoot(cwd);
|
|
688
|
+
// 1. .devflow/ project data directory (contains docs/, memory/, learning/, features/, etc.)
|
|
689
|
+
const devflowDataDir = path.join(cwd, '.devflow');
|
|
690
|
+
let devflowDataExists = false;
|
|
691
|
+
try {
|
|
692
|
+
await fs.access(devflowDataDir);
|
|
693
|
+
devflowDataExists = true;
|
|
694
|
+
}
|
|
695
|
+
catch { /* .devflow doesn't exist */ }
|
|
696
|
+
if (devflowDataExists) {
|
|
697
|
+
let shouldRemoveDevflow = false;
|
|
698
|
+
// Tracks whether a specific "preserved" log was already emitted (e.g. the
|
|
699
|
+
// cancel-path message below) to avoid printing the generic one twice. (F10)
|
|
700
|
+
let preservedLogged = false;
|
|
701
|
+
if (keepDocs) {
|
|
702
|
+
shouldRemoveDevflow = false;
|
|
703
|
+
}
|
|
704
|
+
else if (isTTY) {
|
|
705
|
+
const removeDevflow = await p.confirm({
|
|
706
|
+
message: '.devflow/ directory found. Remove project data (docs, memory, learning)?',
|
|
707
|
+
initialValue: false,
|
|
708
|
+
});
|
|
709
|
+
if (p.isCancel(removeDevflow)) {
|
|
710
|
+
// Treat cancel as decline: preserve .devflow/ and continue cleanup.
|
|
711
|
+
// avoids PF-014: process.exit() here would skip claudeignore, hooks,
|
|
712
|
+
// and safe-delete removal — removeAllDevFlow has already run.
|
|
713
|
+
// applies ADR-003: clean end-state on every path.
|
|
714
|
+
p.log.info('.devflow/ preserved (prompt cancelled — continuing cleanup)');
|
|
715
|
+
preservedLogged = true;
|
|
716
|
+
}
|
|
717
|
+
shouldRemoveDevflow = resolveProjectDataCleanup(removeDevflow);
|
|
718
|
+
}
|
|
719
|
+
if (shouldRemoveDevflow) {
|
|
720
|
+
await fs.rm(devflowDataDir, { recursive: true, force: true });
|
|
721
|
+
p.log.success('.devflow/ removed');
|
|
722
|
+
}
|
|
723
|
+
else if (!preservedLogged) {
|
|
724
|
+
p.log.info('.devflow/ preserved');
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
// 2. .claudeignore
|
|
728
|
+
const claudeignorePath = gitRoot
|
|
729
|
+
? path.join(gitRoot, '.claudeignore')
|
|
730
|
+
: path.join(cwd, '.claudeignore');
|
|
731
|
+
let claudeignoreExists = false;
|
|
732
|
+
try {
|
|
733
|
+
await fs.access(claudeignorePath);
|
|
734
|
+
claudeignoreExists = true;
|
|
735
|
+
}
|
|
736
|
+
catch { /* doesn't exist */ }
|
|
737
|
+
if (claudeignoreExists) {
|
|
738
|
+
if (isTTY) {
|
|
739
|
+
const removeClaudeignore = await p.confirm({
|
|
740
|
+
message: '.claudeignore found. Remove it? (may contain custom rules)',
|
|
741
|
+
initialValue: false,
|
|
742
|
+
});
|
|
743
|
+
if (!p.isCancel(removeClaudeignore) && removeClaudeignore) {
|
|
744
|
+
await fs.rm(claudeignorePath, { force: true });
|
|
745
|
+
p.log.success('.claudeignore removed');
|
|
746
|
+
}
|
|
747
|
+
else {
|
|
748
|
+
p.log.info('.claudeignore preserved');
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
else {
|
|
752
|
+
p.log.info('.claudeignore preserved (non-interactive mode)');
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
// 3. settings.json (Devflow hooks)
|
|
756
|
+
for (const scope of [...scopesToUninstall]) {
|
|
757
|
+
try {
|
|
758
|
+
const paths = await getInstallationPaths(scope);
|
|
759
|
+
const settingsPath = path.join(paths.claudeDir, 'settings.json');
|
|
760
|
+
const originalContent = await fs.readFile(settingsPath, 'utf-8');
|
|
761
|
+
// Remove all Devflow hooks and flags in one pass (idempotent)
|
|
762
|
+
let settingsContent = await removeAmbientHook(originalContent);
|
|
763
|
+
settingsContent = removeMemoryHooks(settingsContent);
|
|
764
|
+
settingsContent = removeCaptureHooks(settingsContent);
|
|
765
|
+
settingsContent = removeDreamHook(settingsContent);
|
|
766
|
+
settingsContent = removeHudStatusLine(settingsContent);
|
|
767
|
+
settingsContent = removeContextHook(settingsContent);
|
|
768
|
+
settingsContent = stripFlags(settingsContent);
|
|
769
|
+
settingsContent = stripViewMode(settingsContent);
|
|
770
|
+
settingsContent = stripDevflowTeammateModeFromJson(settingsContent);
|
|
771
|
+
// Remove proxy hooks and ANTHROPIC_BASE_URL env in a single parse-mutate-serialize pass.
|
|
772
|
+
// REG-1: scope the URL strip to the port Devflow manages — use the pre-captured port
|
|
773
|
+
// (from opts.managedProxyPorts) because proxy.json is already deleted by
|
|
774
|
+
// removeDevFlowInstallArtifacts before this phase runs. A user's own localhost
|
|
775
|
+
// gateway on any other port is left in settings untouched.
|
|
776
|
+
{
|
|
777
|
+
const managedPort = opts.managedProxyPorts?.get(scope) ?? DEFAULT_PROXY_PORT;
|
|
778
|
+
const parsedSettings = JSON.parse(settingsContent);
|
|
779
|
+
applyDisableToSettings(parsedSettings, managedPort);
|
|
780
|
+
settingsContent = JSON.stringify(parsedSettings, null, 2) + '\n';
|
|
781
|
+
}
|
|
782
|
+
if (settingsContent !== originalContent) {
|
|
783
|
+
await fs.writeFile(settingsPath, settingsContent, 'utf-8');
|
|
784
|
+
if (verbose) {
|
|
785
|
+
p.log.success(`Devflow hooks removed from settings.json (${scope})`);
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
// The Devflow strippers above (removeAmbientHook, removeMemoryHooks, etc.) surgically
|
|
789
|
+
// remove every Devflow-owned hook entry. When they complete, any remaining
|
|
790
|
+
// settings.hooks entries belong to THIRD-PARTY tools and must be preserved.
|
|
791
|
+
// (F5: a prior bulk-removal block here was incorrectly scoped — it only fired when
|
|
792
|
+
// foreign hooks were present, and would have removed them. It is gone now.)
|
|
793
|
+
}
|
|
794
|
+
catch {
|
|
795
|
+
// settings.json doesn't exist or can't be parsed — skip
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
// 4. Security deny list
|
|
799
|
+
// Detect what's installed
|
|
800
|
+
let userSettingsJsonForSecurity = null;
|
|
801
|
+
const userSettingsPathForSecurity = path.join(getClaudeDirectory(), 'settings.json');
|
|
802
|
+
try {
|
|
803
|
+
userSettingsJsonForSecurity = await fs.readFile(userSettingsPathForSecurity, 'utf-8');
|
|
804
|
+
}
|
|
805
|
+
catch { /* absent */ }
|
|
806
|
+
let managedExistsForSecurity = false;
|
|
807
|
+
let managedContentForSecurity = null;
|
|
808
|
+
try {
|
|
809
|
+
const managedPath = getManagedSettingsPath();
|
|
810
|
+
managedContentForSecurity = await fs.readFile(managedPath, 'utf-8');
|
|
811
|
+
managedExistsForSecurity = true;
|
|
812
|
+
}
|
|
813
|
+
catch { /* absent or unsupported platform */ }
|
|
814
|
+
const detectedSecurity = detectDenyState(userSettingsJsonForSecurity, managedExistsForSecurity, managedContentForSecurity);
|
|
815
|
+
const anySecurityPresent = detectedSecurity.user || detectedSecurity.managed;
|
|
816
|
+
if (anySecurityPresent) {
|
|
817
|
+
const bothLocations = detectedSecurity.user && detectedSecurity.managed;
|
|
818
|
+
const locationLabel = bothLocations ? 'user settings + managed settings'
|
|
819
|
+
: detectedSecurity.user ? 'user settings' : 'managed settings';
|
|
820
|
+
const securityDecision = resolveSecurityRemovalDecision({
|
|
821
|
+
anySecurityPresent,
|
|
822
|
+
keepDocs,
|
|
823
|
+
isTTY: isTTY,
|
|
824
|
+
});
|
|
825
|
+
let shouldRemoveSecurity = false;
|
|
826
|
+
if (securityDecision === 'prompt') {
|
|
827
|
+
const removeDenyConfirm = await p.confirm({
|
|
828
|
+
message: `Remove Devflow security deny list from ${locationLabel}?`,
|
|
829
|
+
initialValue: false,
|
|
830
|
+
});
|
|
831
|
+
if (!p.isCancel(removeDenyConfirm) && removeDenyConfirm) {
|
|
832
|
+
shouldRemoveSecurity = true;
|
|
833
|
+
}
|
|
834
|
+
else {
|
|
835
|
+
p.log.info(`Security deny list preserved (${locationLabel})`);
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
else if (securityDecision === 'preserve') {
|
|
839
|
+
p.log.info(`Security deny list preserved (${locationLabel}, non-interactive mode)`);
|
|
840
|
+
}
|
|
841
|
+
// securityDecision === 'skip' when keepDocs is set — no message, no action
|
|
842
|
+
if (shouldRemoveSecurity) {
|
|
843
|
+
// Strip from user settings (ENOENT-tolerant; atomic write via temp+rename).
|
|
844
|
+
// NOTE: unparseable user settings are detected as user=false by detectDenyState
|
|
845
|
+
// (JSON.parse failure sets unknown=true but not user=true), so this branch is
|
|
846
|
+
// only reached when the JSON is valid — stripUserDenyList will not throw.
|
|
847
|
+
// Unlike `devflow security --disable`, uninstall does NOT hard-fail on corrupt
|
|
848
|
+
// JSON; it silently skips the strip instead (user=false → guard below is false).
|
|
849
|
+
if (detectedSecurity.user && userSettingsJsonForSecurity !== null) {
|
|
850
|
+
const { json: stripped, removed } = stripUserDenyList(userSettingsJsonForSecurity, DEVFLOW_HISTORICAL_DENY);
|
|
851
|
+
if (removed.length > 0) {
|
|
852
|
+
await writeFileAtomicExclusive(userSettingsPathForSecurity, stripped);
|
|
853
|
+
p.log.success(`Security deny list removed from user settings (${removed.length} entries)`);
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
// Strip from managed settings (ENOENT-tolerant via removeManagedSettings)
|
|
857
|
+
if (managedExistsForSecurity) {
|
|
858
|
+
await removeManagedSettings(getPackageRoot(), verbose);
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
// 5. Safe-delete shell function
|
|
863
|
+
const shell = detectShell();
|
|
864
|
+
const profilePath = getProfilePath(shell);
|
|
865
|
+
if (profilePath && await isAlreadyInstalled(profilePath)) {
|
|
866
|
+
if (isTTY) {
|
|
867
|
+
const removeSafeDelete = await p.confirm({
|
|
868
|
+
message: `Remove safe-delete function from ${profilePath}?`,
|
|
869
|
+
initialValue: false,
|
|
870
|
+
});
|
|
871
|
+
if (!p.isCancel(removeSafeDelete) && removeSafeDelete) {
|
|
872
|
+
const removed = await removeFromProfile(profilePath);
|
|
873
|
+
if (removed) {
|
|
874
|
+
p.log.success(`Safe-delete removed from ${profilePath}`);
|
|
875
|
+
}
|
|
876
|
+
else {
|
|
877
|
+
p.log.warn(`Could not remove safe-delete from ${profilePath}`);
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
else {
|
|
881
|
+
p.log.info('Safe-delete preserved in shell profile');
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
else {
|
|
885
|
+
p.log.info(`Safe-delete function preserved in ${profilePath} (non-interactive mode)`);
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
export const uninstallCommand = new Command('uninstall')
|
|
890
|
+
.description('Uninstall Devflow from Claude Code')
|
|
891
|
+
.option('--keep-docs', 'Keep .devflow/ directory and project data')
|
|
892
|
+
.option('--scope <type>', 'Uninstall from specific scope only (default: auto-detect all)', /^(user|local)$/i)
|
|
893
|
+
.option('--plugin <names>', 'Uninstall specific plugin(s), comma-separated (e.g., implement,code-review)')
|
|
894
|
+
.option('--verbose', 'Show detailed uninstall output')
|
|
895
|
+
.option('--dry-run', 'Show what would be removed without actually removing anything')
|
|
896
|
+
.action(async (options) => {
|
|
897
|
+
const dryRun = options.dryRun ?? false;
|
|
898
|
+
p.intro(color.bgRed(color.white(dryRun ? ' Devflow Uninstall (dry run) ' : ' Uninstalling Devflow ')));
|
|
899
|
+
const verbose = options.verbose ?? false;
|
|
900
|
+
// Parse plugin selection
|
|
901
|
+
let selectedPluginNames = [];
|
|
902
|
+
if (options.plugin) {
|
|
903
|
+
// Friendly redirect for retired feature plugins (e.g. devflow-compliance → `devflow compliance`).
|
|
904
|
+
// Strip retired names, emit the notice, and continue with the remaining plugins so that a
|
|
905
|
+
// mixed list like `devflow-implement,devflow-compliance` still uninstalls devflow-implement.
|
|
906
|
+
// Exit 0 only when nothing non-retired remains (compliance-only invocation).
|
|
907
|
+
const rawNames = options.plugin.split(',').map((s) => s.trim());
|
|
908
|
+
const redirect = resolveFeatureRedirect(rawNames);
|
|
909
|
+
if (redirect.notice) {
|
|
910
|
+
p.log.info(redirect.notice);
|
|
911
|
+
}
|
|
912
|
+
if (redirect.remaining.length === 0) {
|
|
913
|
+
process.exit(0);
|
|
914
|
+
}
|
|
915
|
+
const { selected, invalid } = parsePluginSelection(redirect.remaining.join(','), DEVFLOW_PLUGINS);
|
|
916
|
+
selectedPluginNames = selected;
|
|
917
|
+
if (invalid.length > 0) {
|
|
918
|
+
p.log.error(`Unknown plugin(s): ${invalid.join(', ')}`);
|
|
919
|
+
p.log.info(`Valid plugins: ${DEVFLOW_PLUGINS.map(pl => pl.name).join(', ')}`);
|
|
920
|
+
process.exit(1);
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
const isSelectiveUninstall = selectedPluginNames.length > 0;
|
|
924
|
+
const selectedPlugins = isSelectiveUninstall
|
|
925
|
+
? DEVFLOW_PLUGINS.filter(p => selectedPluginNames.includes(p.name))
|
|
926
|
+
: [];
|
|
927
|
+
// Determine which scopes to uninstall
|
|
928
|
+
let scopesToUninstall = [];
|
|
929
|
+
if (options.scope) {
|
|
930
|
+
scopesToUninstall = [options.scope.toLowerCase()];
|
|
931
|
+
}
|
|
932
|
+
else {
|
|
933
|
+
const userClaudeDir = getClaudeDirectory();
|
|
934
|
+
const gitRoot = await getGitRoot();
|
|
935
|
+
if (await isDevFlowInstalled(userClaudeDir)) {
|
|
936
|
+
scopesToUninstall.push('user');
|
|
937
|
+
}
|
|
938
|
+
if (gitRoot) {
|
|
939
|
+
const localClaudeDir = path.join(gitRoot, '.claude');
|
|
940
|
+
if (await isDevFlowInstalled(localClaudeDir)) {
|
|
941
|
+
scopesToUninstall.push('local');
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
if (scopesToUninstall.length === 0) {
|
|
945
|
+
p.log.error('No Devflow installation found');
|
|
946
|
+
p.log.info('Checked user scope (~/.claude/) and local scope (git-root/.claude/)');
|
|
947
|
+
process.exit(1);
|
|
948
|
+
}
|
|
949
|
+
if (scopesToUninstall.length > 1 && !dryRun) {
|
|
950
|
+
if (process.stdin.isTTY) {
|
|
951
|
+
const scopeChoice = await p.select({
|
|
952
|
+
message: 'Found Devflow in multiple scopes. Uninstall from:',
|
|
953
|
+
options: [
|
|
954
|
+
{ value: 'both', label: 'Both', hint: 'user + local' },
|
|
955
|
+
{ value: 'user', label: 'User scope', hint: '~/.claude/' },
|
|
956
|
+
{ value: 'local', label: 'Local scope', hint: 'git-root/.claude/' },
|
|
957
|
+
],
|
|
958
|
+
});
|
|
959
|
+
if (p.isCancel(scopeChoice)) {
|
|
960
|
+
p.cancel('Uninstall cancelled.');
|
|
961
|
+
process.exit(0);
|
|
962
|
+
}
|
|
963
|
+
if (scopeChoice !== 'both') {
|
|
964
|
+
scopesToUninstall = [scopeChoice];
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
else {
|
|
968
|
+
p.log.info('Multiple scopes detected, uninstalling from both...');
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
// === DRY RUN: show plan and exit ===
|
|
973
|
+
if (dryRun) {
|
|
974
|
+
await runDryRunPhase({ scopesToUninstall, isSelectiveUninstall, selectedPlugins });
|
|
975
|
+
p.outro(color.dim('No changes made (dry run)'));
|
|
976
|
+
return;
|
|
977
|
+
}
|
|
978
|
+
// Pre-capture managed proxy ports for each scope BEFORE artifact removal.
|
|
979
|
+
// proxy.json is deleted by removeDevFlowInstallArtifacts (inside runFullPhaseForScope),
|
|
980
|
+
// so reading it after the full phase would always yield DEFAULT_PROXY_PORT. (F6)
|
|
981
|
+
const managedProxyPorts = new Map();
|
|
982
|
+
if (!isSelectiveUninstall) {
|
|
983
|
+
for (const scope of scopesToUninstall) {
|
|
984
|
+
try {
|
|
985
|
+
const paths = await getInstallationPaths(scope);
|
|
986
|
+
const proxyState = await readProxyState(paths.devflowDir);
|
|
987
|
+
if (proxyState.ok)
|
|
988
|
+
managedProxyPorts.set(scope, proxyState.value.port);
|
|
989
|
+
}
|
|
990
|
+
catch { /* non-fatal: if we can't read, we fall back to DEFAULT_PROXY_PORT */ }
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
// Uninstall from each scope
|
|
994
|
+
for (const scope of scopesToUninstall) {
|
|
995
|
+
let claudeDir;
|
|
996
|
+
let devflowScriptsDir;
|
|
997
|
+
let devflowDir;
|
|
998
|
+
try {
|
|
999
|
+
const paths = await getInstallationPaths(scope);
|
|
1000
|
+
claudeDir = paths.claudeDir;
|
|
1001
|
+
devflowDir = paths.devflowDir;
|
|
1002
|
+
devflowScriptsDir = path.join(paths.devflowDir, 'scripts');
|
|
1003
|
+
if (scope === 'user') {
|
|
1004
|
+
p.log.step('Uninstalling user scope (~/.claude/)');
|
|
1005
|
+
}
|
|
1006
|
+
else {
|
|
1007
|
+
p.log.step('Uninstalling local scope (git-root/.claude/)');
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
catch (error) {
|
|
1011
|
+
p.log.warn(`Cannot uninstall ${scope} scope: ${error instanceof Error ? error.message : error}`);
|
|
1012
|
+
continue;
|
|
1013
|
+
}
|
|
1014
|
+
if (isSelectiveUninstall) {
|
|
1015
|
+
await runSelectivePhaseForScope({ claudeDir, devflowDir, selectedPlugins, verbose });
|
|
1016
|
+
}
|
|
1017
|
+
else {
|
|
1018
|
+
await runFullPhaseForScope({ scope, claudeDir, devflowDir, devflowScriptsDir, verbose, keepDocs: !!options.keepDocs, isTTY: !!process.stdin.isTTY });
|
|
1019
|
+
}
|
|
1020
|
+
const pluginLabel = isSelectiveUninstall
|
|
1021
|
+
? ` (${selectedPluginNames.join(', ')})`
|
|
1022
|
+
: '';
|
|
1023
|
+
p.log.success(`Plugin removed${pluginLabel}`);
|
|
1024
|
+
}
|
|
1025
|
+
// === CLEANUP EXTRAS (only for full uninstall) ===
|
|
1026
|
+
if (!isSelectiveUninstall) {
|
|
1027
|
+
await runCleanupPhase({ scopesToUninstall, keepDocs: !!options.keepDocs, verbose, cwd: process.cwd(), isTTY: !!process.stdin.isTTY, managedProxyPorts });
|
|
1028
|
+
}
|
|
1029
|
+
const status = color.green('Devflow uninstalled successfully');
|
|
1030
|
+
p.outro(`${status}${color.dim(' Reinstall: npx devflow-kit init')}`);
|
|
1031
|
+
});
|
|
1032
|
+
/**
|
|
1033
|
+
* Remove all Devflow assets (full uninstall).
|
|
1034
|
+
*/
|
|
1035
|
+
export async function removeAllDevFlow(claudeDir, devflowScriptsDir, verbose) {
|
|
1036
|
+
const devflowDirectories = [
|
|
1037
|
+
{ path: path.join(claudeDir, 'commands', 'devflow'), name: 'commands' },
|
|
1038
|
+
{ path: path.join(claudeDir, 'agents', 'devflow'), name: 'agents' },
|
|
1039
|
+
{ path: path.join(claudeDir, 'rules', 'devflow'), name: 'rules' },
|
|
1040
|
+
{ path: devflowScriptsDir, name: 'scripts' }
|
|
1041
|
+
];
|
|
1042
|
+
for (const dir of devflowDirectories) {
|
|
1043
|
+
try {
|
|
1044
|
+
await fs.rm(dir.path, { recursive: true, force: true });
|
|
1045
|
+
if (verbose) {
|
|
1046
|
+
p.log.success(`Removed Devflow ${dir.name}`);
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
catch (error) {
|
|
1050
|
+
p.log.warn(`Could not remove ${dir.name}: ${error}`);
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
// Remove Devflow skill directories.
|
|
1054
|
+
// ~/.claude/skills/ is shared with other tools; the two passes use different
|
|
1055
|
+
// name sets to avoid deleting foreign dirs (avoids PF-012):
|
|
1056
|
+
//
|
|
1057
|
+
// Prefixed pass (devflow:name): live registry ∪ LEGACY_SKILL_NAMES ∪ FEATURE_OWNED_SKILLS.
|
|
1058
|
+
// prefixSkillName() is idempotent for already-prefixed legacy entries.
|
|
1059
|
+
// FEATURE_OWNED_SKILLS (compliance) is included so full uninstall removes
|
|
1060
|
+
// devflow:compliance even though it left the plugin registry (step 1.5).
|
|
1061
|
+
// Bare pass (name or devflow-name legacy): LEGACY_SKILL_NAMES ONLY.
|
|
1062
|
+
// A bare dir whose name matches a live-registry skill is by construction
|
|
1063
|
+
// foreign to Devflow (the devflow: namespace shipped in dcecda3, 2026-03-30).
|
|
1064
|
+
// A bare 'compliance/' dir is also foreign (not in LEGACY_SKILL_NAMES) — PF-012.
|
|
1065
|
+
const prefixedSkillNames = new Set([...getAllSkillNames(), ...LEGACY_SKILL_NAMES, ...FEATURE_OWNED_SKILLS]);
|
|
1066
|
+
const skillsDir = path.join(claudeDir, 'skills');
|
|
1067
|
+
let skillsRemoved = 0;
|
|
1068
|
+
for (const skillName of prefixedSkillNames) {
|
|
1069
|
+
// Remove prefixed variant (devflow:name) — current naming
|
|
1070
|
+
const prefixedPath = path.join(skillsDir, prefixSkillName(skillName));
|
|
1071
|
+
try {
|
|
1072
|
+
await fs.stat(prefixedPath);
|
|
1073
|
+
await fs.rm(prefixedPath, { recursive: true, force: true });
|
|
1074
|
+
skillsRemoved++;
|
|
1075
|
+
}
|
|
1076
|
+
catch { /* Skill doesn't exist */ }
|
|
1077
|
+
}
|
|
1078
|
+
for (const skillName of LEGACY_SKILL_NAMES) {
|
|
1079
|
+
// Remove bare variant — frozen legacy list only, never the live registry
|
|
1080
|
+
const barePath = path.join(skillsDir, skillName);
|
|
1081
|
+
try {
|
|
1082
|
+
await fs.stat(barePath);
|
|
1083
|
+
await fs.rm(barePath, { recursive: true, force: true });
|
|
1084
|
+
skillsRemoved++;
|
|
1085
|
+
}
|
|
1086
|
+
catch { /* Skill doesn't exist */ }
|
|
1087
|
+
}
|
|
1088
|
+
if (skillsRemoved > 0 && verbose) {
|
|
1089
|
+
p.log.success(`Removed ${skillsRemoved} Devflow skill directories`);
|
|
1090
|
+
}
|
|
1091
|
+
// Also remove old nested skills structure if it exists
|
|
1092
|
+
try {
|
|
1093
|
+
await fs.rm(path.join(claudeDir, 'skills', 'devflow'), { recursive: true, force: true });
|
|
1094
|
+
}
|
|
1095
|
+
catch {
|
|
1096
|
+
// Old structure doesn't exist
|
|
1097
|
+
}
|
|
1098
|
+
// Registry-diff sweep: catch any devflow:* skill dirs whose names left the
|
|
1099
|
+
// registry (retired, renamed, or deleted). The loop above walks the static
|
|
1100
|
+
// registry + LEGACY list; this sweep walks the actual directory, so orphaned
|
|
1101
|
+
// dirs from older versions are also cleaned up. (F9)
|
|
1102
|
+
await sweepDevflowNamespaces(claudeDir, verbose);
|
|
1103
|
+
}
|
|
1104
|
+
/**
|
|
1105
|
+
* Registry-diff sweep of all Devflow-owned namespaces in `claudeDir`:
|
|
1106
|
+
* - agents/devflow/ — entries absent from getAllAgentNames()
|
|
1107
|
+
* - commands/devflow/ — entries absent from getAllCommandNames()
|
|
1108
|
+
* - skills/ — devflow:* entries absent from getAllSkillNames()
|
|
1109
|
+
*
|
|
1110
|
+
* Called by removeSelectedPlugins after per-plugin removals so that retired
|
|
1111
|
+
* asset names (agents/commands renamed or deleted from the registry) are
|
|
1112
|
+
* cleaned up promptly rather than accumulating on disk.
|
|
1113
|
+
*
|
|
1114
|
+
* knownNames spans ALL plugins for each asset type so assets belonging to
|
|
1115
|
+
* plugins NOT being uninstalled are never swept (avoids PF-012).
|
|
1116
|
+
*
|
|
1117
|
+
* Removals are announced only under `verbose`, but removal FAILURES always warn:
|
|
1118
|
+
* a swept-but-not-actually-removed agent or command keeps loading in Claude Code,
|
|
1119
|
+
* and the user has no other signal that it is still there.
|
|
1120
|
+
*/
|
|
1121
|
+
export async function sweepDevflowNamespaces(claudeDir, verbose) {
|
|
1122
|
+
const agentsDir = path.join(claudeDir, 'agents', 'devflow');
|
|
1123
|
+
const commandsDir = path.join(claudeDir, 'commands', 'devflow');
|
|
1124
|
+
const skillsDir = path.join(claudeDir, 'skills');
|
|
1125
|
+
const agentsSweep = await sweepOrphanedAssets(agentsDir, new Set(getAllAgentNames()), mdEntryName);
|
|
1126
|
+
const commandsSweep = await sweepOrphanedAssets(commandsDir, new Set(getAllCommandNames()), mdEntryName);
|
|
1127
|
+
// FEATURE_OWNED_SKILLS (compliance) unioned into knownNames so a selective
|
|
1128
|
+
// uninstall of another plugin does not sweep devflow:compliance — nothing
|
|
1129
|
+
// converges after selective uninstall (only installViaFileCopy + convergeComplianceArtifacts
|
|
1130
|
+
// on full/partial init re-materialize it). D-FO-1 applies.
|
|
1131
|
+
const skillsSweep = await sweepOrphanedAssets(skillsDir, new Set([...getAllSkillNames(), ...FEATURE_OWNED_SKILLS]), (entry) => entry.startsWith(SKILL_NAMESPACE) ? unprefixSkillName(entry) : null);
|
|
1132
|
+
const byKind = [
|
|
1133
|
+
{ kind: 'agent', sweep: agentsSweep },
|
|
1134
|
+
{ kind: 'command', sweep: commandsSweep },
|
|
1135
|
+
{ kind: 'skill', sweep: skillsSweep },
|
|
1136
|
+
];
|
|
1137
|
+
for (const { kind, sweep } of byKind) {
|
|
1138
|
+
if (verbose) {
|
|
1139
|
+
for (const name of sweep.removed)
|
|
1140
|
+
p.log.success(`Swept orphaned ${kind} ${name}`);
|
|
1141
|
+
}
|
|
1142
|
+
for (const failure of sweep.failed) {
|
|
1143
|
+
const reason = failure.error instanceof Error ? failure.error.message : String(failure.error);
|
|
1144
|
+
p.log.warn(`Could not remove orphaned ${kind} "${failure.name}" (${reason}) — remove it manually`);
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
/**
|
|
1149
|
+
* Remove only specific plugin assets (selective uninstall).
|
|
1150
|
+
* For commands and agents: remove files belonging to selected plugins, then
|
|
1151
|
+
* sweep the install directory for any orphaned assets whose names left the
|
|
1152
|
+
* registry (retired agents/commands survive indefinitely without the sweep).
|
|
1153
|
+
* For skills: only remove skills that are NOT used by any remaining plugin.
|
|
1154
|
+
*/
|
|
1155
|
+
export async function removeSelectedPlugins(claudeDir, plugins, verbose) {
|
|
1156
|
+
const { skills, agents, commands, rules } = computeAssetsToRemove(plugins, DEVFLOW_PLUGINS);
|
|
1157
|
+
const commandsDir = path.join(claudeDir, 'commands', 'devflow');
|
|
1158
|
+
for (const cmd of commands) {
|
|
1159
|
+
const cmdFileName = mdFileName(cmd.replace(/^\//, ''));
|
|
1160
|
+
try {
|
|
1161
|
+
await fs.rm(path.join(commandsDir, cmdFileName), { force: true });
|
|
1162
|
+
if (verbose) {
|
|
1163
|
+
p.log.success(`Removed command ${cmd}`);
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
catch {
|
|
1167
|
+
// Command file might not exist
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
const agentsDir = path.join(claudeDir, 'agents', 'devflow');
|
|
1171
|
+
for (const agent of agents) {
|
|
1172
|
+
try {
|
|
1173
|
+
await fs.rm(path.join(agentsDir, mdFileName(agent)), { force: true });
|
|
1174
|
+
if (verbose) {
|
|
1175
|
+
p.log.success(`Removed agent ${agent}`);
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
catch {
|
|
1179
|
+
// Agent file might not exist
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
const skillsDir = path.join(claudeDir, 'skills');
|
|
1183
|
+
for (const skill of skills) {
|
|
1184
|
+
// Remove only the prefixed variant (devflow:name) — current naming.
|
|
1185
|
+
// Bare dirs (~/.claude/skills/{name}) and legacy devflow-* dirs are owned
|
|
1186
|
+
// exclusively by the frozen LEGACY_SKILL_NAMES pass in removeAllDevFlow and
|
|
1187
|
+
// in init.ts; live-registry skills never had bare installs (the devflow:
|
|
1188
|
+
// namespace shipped in dcecda3, 2026-03-30), so a bare dir for a current
|
|
1189
|
+
// registry name is by construction foreign (avoids PF-012).
|
|
1190
|
+
try {
|
|
1191
|
+
await fs.rm(path.join(skillsDir, prefixSkillName(skill)), { recursive: true, force: true });
|
|
1192
|
+
}
|
|
1193
|
+
catch { /* Skill might not exist */ }
|
|
1194
|
+
if (verbose) {
|
|
1195
|
+
p.log.success(`Removed skill ${skill}`);
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
const rulesDir = path.join(claudeDir, 'rules', 'devflow');
|
|
1199
|
+
for (const rule of rules) {
|
|
1200
|
+
try {
|
|
1201
|
+
await fs.rm(path.join(rulesDir, mdFileName(rule)), { force: true });
|
|
1202
|
+
if (verbose) {
|
|
1203
|
+
p.log.success(`Removed rule ${rule}`);
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
catch { /* Rule file might not exist */ }
|
|
1207
|
+
}
|
|
1208
|
+
// Registry-diff sweep: agents, commands, AND skills — named step (A6).
|
|
1209
|
+
// Removes any orphaned files whose names left the registry (retired, renamed,
|
|
1210
|
+
// or deleted from all plugins). Spans ALL plugins so assets belonging to
|
|
1211
|
+
// non-selected plugins are never swept (avoids PF-012).
|
|
1212
|
+
await sweepDevflowNamespaces(claudeDir, verbose);
|
|
1213
|
+
}
|
|
1214
|
+
//# sourceMappingURL=uninstall.js.map
|