agileflow 4.0.0-alpha.2 → 4.0.0-alpha.21
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 +51 -0
- package/content/plugins/accessibility/plugin.yaml +14 -0
- package/content/plugins/accessibility/skills/agileflow-accessibility/SKILL.md +392 -0
- package/content/plugins/accessibility/skills/agileflow-accessibility/references/aria-patterns.md +528 -0
- package/content/plugins/accessibility/skills/agileflow-accessibility/references/testing-checklist.md +457 -0
- package/content/plugins/accessibility/skills/agileflow-accessibility/references/wcag-guide.md +683 -0
- package/content/plugins/accessibility/skills/agileflow-accessibility/workflows/audit-page.md +310 -0
- package/content/plugins/accessibility/skills/agileflow-accessibility/workflows/implement-accessible-component.md +479 -0
- package/content/plugins/ads/agents/ads-audit-budget.md +185 -0
- package/content/plugins/ads/agents/ads-audit-compliance.md +171 -0
- package/content/plugins/ads/agents/ads-audit-creative.md +168 -0
- package/content/plugins/ads/agents/ads-audit-google.md +227 -0
- package/content/plugins/ads/agents/ads-audit-meta.md +184 -0
- package/content/plugins/ads/agents/ads-audit-tracking.md +205 -0
- package/content/plugins/ads/agents/ads-consensus.md +410 -0
- package/content/plugins/ads/agents/ads-generate.md +152 -0
- package/content/plugins/ads/agents/ads-performance-tracker.md +212 -0
- package/content/plugins/ads/plugin.yaml +23 -4
- package/content/plugins/ads/skills/agileflow-ads/SKILL.md +218 -0
- package/content/plugins/ads/skills/agileflow-ads/references/ad-copy-formula-guide.md +131 -0
- package/content/plugins/ads/skills/agileflow-ads/references/audience-targeting-guide.md +137 -0
- package/content/plugins/ads/skills/agileflow-ads/references/bid-strategy-guide.md +115 -0
- package/content/plugins/ads/skills/agileflow-ads/references/platform-benchmarks.md +100 -0
- package/content/plugins/ads/skills/agileflow-ads/workflows/audit.md +118 -0
- package/content/plugins/ads/skills/agileflow-ads/workflows/generate.md +84 -0
- package/content/plugins/audit/agents/a11y-analyzer-aria.md +173 -0
- package/content/plugins/audit/agents/a11y-analyzer-forms.md +173 -0
- package/content/plugins/audit/agents/a11y-analyzer-keyboard.md +183 -0
- package/content/plugins/audit/agents/a11y-analyzer-semantic.md +169 -0
- package/content/plugins/audit/agents/a11y-analyzer-visual.md +172 -0
- package/content/plugins/audit/agents/a11y-consensus.md +249 -0
- package/content/plugins/audit/agents/accessibility.md +558 -0
- package/content/plugins/audit/agents/api-quality-analyzer-conventions.md +156 -0
- package/content/plugins/audit/agents/api-quality-analyzer-docs.md +184 -0
- package/content/plugins/audit/agents/api-quality-analyzer-errors.md +191 -0
- package/content/plugins/audit/agents/api-quality-analyzer-pagination.md +179 -0
- package/content/plugins/audit/agents/api-quality-analyzer-versioning.md +150 -0
- package/content/plugins/audit/agents/api-quality-consensus.md +217 -0
- package/content/plugins/audit/agents/api-validator.md +191 -0
- package/content/plugins/audit/agents/arch-analyzer-circular.md +156 -0
- package/content/plugins/audit/agents/arch-analyzer-complexity.md +193 -0
- package/content/plugins/audit/agents/arch-analyzer-coupling.md +152 -0
- package/content/plugins/audit/agents/arch-analyzer-layering.md +160 -0
- package/content/plugins/audit/agents/arch-analyzer-patterns.md +210 -0
- package/content/plugins/audit/agents/arch-consensus.md +228 -0
- package/content/plugins/audit/agents/browser-qa.md +342 -0
- package/content/plugins/audit/agents/code-reviewer.md +298 -0
- package/content/plugins/audit/agents/completeness-analyzer-api.md +199 -0
- package/content/plugins/audit/agents/completeness-analyzer-conditional.md +211 -0
- package/content/plugins/audit/agents/completeness-analyzer-handlers.md +166 -0
- package/content/plugins/audit/agents/completeness-analyzer-imports.md +165 -0
- package/content/plugins/audit/agents/completeness-analyzer-routes.md +190 -0
- package/content/plugins/audit/agents/completeness-analyzer-state.md +196 -0
- package/content/plugins/audit/agents/completeness-analyzer-stubs.md +206 -0
- package/content/plugins/audit/agents/completeness-consensus.md +295 -0
- package/content/plugins/audit/agents/error-analyzer.md +213 -0
- package/content/plugins/audit/agents/flow-analyzer-authorization.md +182 -0
- package/content/plugins/audit/agents/flow-analyzer-discovery.md +174 -0
- package/content/plugins/audit/agents/flow-analyzer-errors.md +186 -0
- package/content/plugins/audit/agents/flow-analyzer-feedback.md +185 -0
- package/content/plugins/audit/agents/flow-analyzer-navigation.md +177 -0
- package/content/plugins/audit/agents/flow-analyzer-persistence.md +193 -0
- package/content/plugins/audit/agents/flow-analyzer-wiring.md +169 -0
- package/content/plugins/audit/agents/flow-consensus.md +237 -0
- package/content/plugins/audit/agents/legal-analyzer-a11y.md +114 -0
- package/content/plugins/audit/agents/legal-analyzer-ai.md +121 -0
- package/content/plugins/audit/agents/legal-analyzer-consumer.md +114 -0
- package/content/plugins/audit/agents/legal-analyzer-content.md +117 -0
- package/content/plugins/audit/agents/legal-analyzer-international.md +119 -0
- package/content/plugins/audit/agents/legal-analyzer-licensing.md +119 -0
- package/content/plugins/audit/agents/legal-analyzer-privacy.md +112 -0
- package/content/plugins/audit/agents/legal-analyzer-security.md +116 -0
- package/content/plugins/audit/agents/legal-analyzer-terms.md +115 -0
- package/content/plugins/audit/agents/legal-consensus.md +250 -0
- package/content/plugins/audit/agents/logic-analyzer-edge.md +179 -0
- package/content/plugins/audit/agents/logic-analyzer-flow.md +264 -0
- package/content/plugins/audit/agents/logic-analyzer-invariant.md +215 -0
- package/content/plugins/audit/agents/logic-analyzer-race.md +280 -0
- package/content/plugins/audit/agents/logic-analyzer-type.md +227 -0
- package/content/plugins/audit/agents/logic-consensus.md +259 -0
- package/content/plugins/audit/agents/perf-analyzer-assets.md +182 -0
- package/content/plugins/audit/agents/perf-analyzer-bundle.md +173 -0
- package/content/plugins/audit/agents/perf-analyzer-caching.md +170 -0
- package/content/plugins/audit/agents/perf-analyzer-compute.md +173 -0
- package/content/plugins/audit/agents/perf-analyzer-memory.md +193 -0
- package/content/plugins/audit/agents/perf-analyzer-network.md +165 -0
- package/content/plugins/audit/agents/perf-analyzer-queries.md +162 -0
- package/content/plugins/audit/agents/perf-analyzer-rendering.md +168 -0
- package/content/plugins/audit/agents/perf-consensus.md +287 -0
- package/content/plugins/audit/agents/qa.md +820 -0
- package/content/plugins/audit/agents/quality-analyzer-comments.md +159 -0
- package/content/plugins/audit/agents/quality-analyzer-duplication.md +184 -0
- package/content/plugins/audit/agents/quality-analyzer-naming.md +160 -0
- package/content/plugins/audit/agents/quality-consensus.md +241 -0
- package/content/plugins/audit/agents/schema-validator.md +473 -0
- package/content/plugins/audit/agents/security-analyzer-api.md +210 -0
- package/content/plugins/audit/agents/security-analyzer-auth.md +169 -0
- package/content/plugins/audit/agents/security-analyzer-authz.md +180 -0
- package/content/plugins/audit/agents/security-analyzer-deps.md +153 -0
- package/content/plugins/audit/agents/security-analyzer-infra.md +184 -0
- package/content/plugins/audit/agents/security-analyzer-injection.md +155 -0
- package/content/plugins/audit/agents/security-analyzer-input.md +201 -0
- package/content/plugins/audit/agents/security-analyzer-secrets.md +183 -0
- package/content/plugins/audit/agents/security-consensus.md +283 -0
- package/content/plugins/audit/agents/test-analyzer-assertions.md +188 -0
- package/content/plugins/audit/agents/test-analyzer-coverage.md +189 -0
- package/content/plugins/audit/agents/test-analyzer-fragility.md +193 -0
- package/content/plugins/audit/agents/test-analyzer-integration.md +161 -0
- package/content/plugins/audit/agents/test-analyzer-maintenance.md +180 -0
- package/content/plugins/audit/agents/test-analyzer-mocking.md +188 -0
- package/content/plugins/audit/agents/test-analyzer-patterns.md +196 -0
- package/content/plugins/audit/agents/test-analyzer-structure.md +184 -0
- package/content/plugins/audit/agents/test-consensus.md +301 -0
- package/content/plugins/audit/agents/testing.md +561 -0
- package/content/plugins/audit/agents/ui-validator.md +344 -0
- package/content/plugins/audit/plugin.yaml +186 -5
- package/content/plugins/audit/skills/agileflow-audit/SKILL.md +113 -0
- package/content/plugins/audit/skills/agileflow-audit/references/audit-depth-guide.md +151 -0
- package/content/plugins/audit/skills/agileflow-audit/references/dependency-risk-guide.md +139 -0
- package/content/plugins/audit/skills/agileflow-audit/references/owasp-top10.md +120 -0
- package/content/plugins/audit/skills/agileflow-audit/references/performance-budget-guide.md +143 -0
- package/content/plugins/audit/skills/agileflow-audit/references/wcag-criteria.md +117 -0
- package/content/plugins/audit/skills/agileflow-audit/workflows/run-audit.md +52 -0
- package/content/plugins/audit/skills/agileflow-audit/workflows/tdd.md +66 -0
- package/content/plugins/core/agents/adr-writer.md +521 -0
- package/content/plugins/core/agents/epic-planner.md +520 -0
- package/content/plugins/core/agents/mentor.md +709 -0
- package/content/plugins/core/agents/orchestrator.md +776 -0
- package/content/plugins/core/agents/team-coordinator.md +334 -0
- package/content/plugins/core/agents/team-lead.md +181 -0
- package/content/plugins/core/agents/workspace-orchestrator.md +146 -0
- package/content/plugins/core/hooks/context-loader.js +31 -4
- package/content/plugins/core/hooks/damage-control-bash.js +10 -2
- package/content/plugins/core/hooks/damage-control-edit.js +4 -1
- package/content/plugins/core/hooks/damage-control-patterns.yaml +1 -1
- package/content/plugins/core/hooks/damage-control-write.js +4 -1
- package/content/plugins/core/hooks/{pre-compact-state.js → post-compact-state.js} +25 -8
- package/content/plugins/core/hooks/preferences-injector.js +352 -0
- package/content/plugins/core/plugin.yaml +24 -28
- package/content/plugins/core/skills/agileflow-adr/SKILL.md +34 -8
- package/content/plugins/core/skills/agileflow-adr/references/madr-format-guide.md +86 -0
- package/content/plugins/core/skills/agileflow-adr/workflows/write-adr.md +57 -0
- package/content/plugins/core/skills/agileflow-babysit-mentor/SKILL.md +94 -27
- package/content/plugins/core/skills/agileflow-babysit-mentor/references/mentor-decision-guide.md +81 -0
- package/content/plugins/core/skills/agileflow-babysit-mentor/workflows/mentor-session.md +79 -0
- package/content/plugins/core/skills/agileflow-epic-planner/SKILL.md +37 -7
- package/content/plugins/core/skills/agileflow-epic-planner/references/epic-sizing-guide.md +81 -0
- package/content/plugins/core/skills/agileflow-epic-planner/workflows/plan-epic.md +55 -0
- package/content/plugins/core/skills/agileflow-status-updater/SKILL.md +36 -20
- package/content/plugins/core/skills/agileflow-status-updater/references/status-transitions.md +89 -0
- package/content/plugins/core/skills/agileflow-status-updater/workflows/update-status.md +56 -0
- package/content/plugins/core/skills/agileflow-story-writer/SKILL.md +39 -114
- package/content/plugins/core/skills/agileflow-story-writer/references/estimation-reference.md +36 -0
- package/content/plugins/core/skills/agileflow-story-writer/references/story-template.md +92 -0
- package/content/plugins/core/skills/agileflow-story-writer/workflows/write-story.md +138 -0
- package/content/plugins/council/agents/council-advocate.md +223 -0
- package/content/plugins/council/agents/council-analyst.md +278 -0
- package/content/plugins/council/agents/council-compounder.md +204 -0
- package/content/plugins/council/agents/council-contrarian.md +217 -0
- package/content/plugins/council/agents/council-moonshot.md +217 -0
- package/content/plugins/council/agents/council-optimist.md +185 -0
- package/content/plugins/council/agents/council-revenue.md +200 -0
- package/content/plugins/council/agents/council-technical.md +218 -0
- package/content/plugins/council/agents/multi-expert.md +334 -0
- package/content/plugins/council/plugin.yaml +23 -4
- package/content/plugins/council/skills/agileflow-council/SKILL.md +102 -0
- package/content/plugins/council/skills/agileflow-council/references/decision-log-template.md +109 -0
- package/content/plugins/council/skills/agileflow-council/references/perspective-guide.md +104 -0
- package/content/plugins/council/skills/agileflow-council/references/when-to-convene-guide.md +112 -0
- package/content/plugins/council/skills/agileflow-council/workflows/convene.md +73 -0
- package/content/plugins/council/skills/agileflow-council/workflows/multi-expert.md +75 -0
- package/content/plugins/database/plugin.yaml +14 -0
- package/content/plugins/database/skills/agileflow-database/SKILL.md +284 -0
- package/content/plugins/database/skills/agileflow-database/references/indexing-guide.md +313 -0
- package/content/plugins/database/skills/agileflow-database/references/migration-guide.md +328 -0
- package/content/plugins/database/skills/agileflow-database/references/schema-design-guide.md +467 -0
- package/content/plugins/database/skills/agileflow-database/workflows/design-schema.md +213 -0
- package/content/plugins/database/skills/agileflow-database/workflows/optimize-query.md +253 -0
- package/content/plugins/debugging/plugin.yaml +14 -0
- package/content/plugins/debugging/skills/agileflow-debug/SKILL.md +236 -0
- package/content/plugins/debugging/skills/agileflow-debug/references/common-patterns.md +350 -0
- package/content/plugins/debugging/skills/agileflow-debug/references/debugging-strategies.md +328 -0
- package/content/plugins/debugging/skills/agileflow-debug/workflows/debug-issue.md +187 -0
- package/content/plugins/debugging/skills/agileflow-debug/workflows/reproduce-bug.md +194 -0
- package/content/plugins/delivery/agents/ci.md +547 -0
- package/content/plugins/delivery/agents/devops.md +789 -0
- package/content/plugins/delivery/plugin.yaml +19 -0
- package/content/plugins/delivery/skills/agileflow-delivery/SKILL.md +111 -0
- package/content/plugins/delivery/skills/agileflow-delivery/references/changelog-format-guide.md +133 -0
- package/content/plugins/delivery/skills/agileflow-delivery/references/ci-pipeline-guide.md +158 -0
- package/content/plugins/delivery/skills/agileflow-delivery/references/pr-checklist-guide.md +133 -0
- package/content/plugins/delivery/skills/agileflow-delivery/references/release-checklist.md +142 -0
- package/content/plugins/delivery/skills/agileflow-delivery/workflows/changelog.md +72 -0
- package/content/plugins/delivery/skills/agileflow-delivery/workflows/deploy.md +74 -0
- package/content/plugins/delivery/skills/agileflow-delivery/workflows/pr.md +75 -0
- package/content/plugins/docs/agents/documentation.md +544 -0
- package/content/plugins/docs/agents/readme-updater.md +640 -0
- package/content/plugins/docs/plugin.yaml +19 -0
- package/content/plugins/docs/skills/agileflow-docs/SKILL.md +106 -0
- package/content/plugins/docs/skills/agileflow-docs/references/api-doc-template.md +167 -0
- package/content/plugins/docs/skills/agileflow-docs/references/doc-types-guide.md +141 -0
- package/content/plugins/docs/skills/agileflow-docs/references/readme-template.md +156 -0
- package/content/plugins/docs/skills/agileflow-docs/workflows/readme-sync.md +57 -0
- package/content/plugins/docs/skills/agileflow-docs/workflows/sync.md +64 -0
- package/content/plugins/engineering/agents/api.md +718 -0
- package/content/plugins/engineering/agents/codebase-query.md +285 -0
- package/content/plugins/engineering/agents/compliance.md +559 -0
- package/content/plugins/engineering/agents/database.md +644 -0
- package/content/plugins/engineering/agents/integrations.md +644 -0
- package/content/plugins/engineering/agents/mobile.md +552 -0
- package/content/plugins/engineering/agents/monitoring.md +585 -0
- package/content/plugins/engineering/agents/performance.md +529 -0
- package/content/plugins/engineering/agents/refactor.md +592 -0
- package/content/plugins/engineering/agents/security.md +524 -0
- package/content/plugins/engineering/agents/ui.md +1336 -0
- package/content/plugins/engineering/plugin.yaml +37 -0
- package/content/plugins/engineering/skills/agileflow-engineering/SKILL.md +127 -0
- package/content/plugins/engineering/skills/agileflow-engineering/references/code-review-guide.md +126 -0
- package/content/plugins/engineering/skills/agileflow-engineering/references/domain-routing-guide.md +89 -0
- package/content/plugins/engineering/skills/agileflow-engineering/references/refactoring-guide.md +136 -0
- package/content/plugins/engineering/skills/agileflow-engineering/workflows/diagnose.md +63 -0
- package/content/plugins/engineering/skills/agileflow-engineering/workflows/impact.md +60 -0
- package/content/plugins/ideation/agents/brainstorm-analyzer-features.md +179 -0
- package/content/plugins/ideation/agents/brainstorm-analyzer-growth.md +169 -0
- package/content/plugins/ideation/agents/brainstorm-analyzer-integration.md +181 -0
- package/content/plugins/ideation/agents/brainstorm-analyzer-market.md +150 -0
- package/content/plugins/ideation/agents/brainstorm-analyzer-ux.md +180 -0
- package/content/plugins/ideation/agents/brainstorm-consensus.md +245 -0
- package/content/plugins/ideation/agents/design.md +568 -0
- package/content/plugins/ideation/agents/product.md +582 -0
- package/content/plugins/ideation/plugin.yaml +31 -0
- package/content/plugins/ideation/skills/agileflow-ideation/SKILL.md +109 -0
- package/content/plugins/ideation/skills/agileflow-ideation/references/brainstorm-techniques.md +138 -0
- package/content/plugins/ideation/skills/agileflow-ideation/references/competitive-analysis-template.md +148 -0
- package/content/plugins/ideation/skills/agileflow-ideation/references/feature-prioritization-guide.md +147 -0
- package/content/plugins/ideation/skills/agileflow-ideation/references/user-story-patterns.md +152 -0
- package/content/plugins/ideation/skills/agileflow-ideation/workflows/features.md +65 -0
- package/content/plugins/ideation/skills/agileflow-ideation/workflows/ideate.md +54 -0
- package/content/plugins/migration/agents/datamigration.md +757 -0
- package/content/plugins/migration/plugin.yaml +17 -0
- package/content/plugins/migration/skills/agileflow-migration/SKILL.md +106 -0
- package/content/plugins/migration/skills/agileflow-migration/references/data-validation-checklist.md +154 -0
- package/content/plugins/migration/skills/agileflow-migration/references/migration-patterns.md +209 -0
- package/content/plugins/migration/skills/agileflow-migration/references/rollback-playbook.md +171 -0
- package/content/plugins/migration/skills/agileflow-migration/references/version-compatibility-matrix.md +155 -0
- package/content/plugins/migration/skills/agileflow-migration/workflows/plan.md +73 -0
- package/content/plugins/migration/skills/agileflow-migration/workflows/validate.md +71 -0
- package/content/plugins/performance/plugin.yaml +14 -0
- package/content/plugins/performance/skills/agileflow-performance/SKILL.md +224 -0
- package/content/plugins/performance/skills/agileflow-performance/references/optimization-patterns.md +554 -0
- package/content/plugins/performance/skills/agileflow-performance/references/profiling-guide.md +383 -0
- package/content/plugins/performance/skills/agileflow-performance/references/web-vitals-guide.md +360 -0
- package/content/plugins/performance/skills/agileflow-performance/workflows/improve-web-vitals.md +344 -0
- package/content/plugins/performance/skills/agileflow-performance/workflows/profile-and-fix.md +254 -0
- package/content/plugins/planning/agents/analytics.md +670 -0
- package/content/plugins/planning/agents/rlm-subcore.md +215 -0
- package/content/plugins/planning/plugin.yaml +19 -0
- package/content/plugins/planning/skills/agileflow-planning/SKILL.md +111 -0
- package/content/plugins/planning/skills/agileflow-planning/references/estimation-guide.md +114 -0
- package/content/plugins/planning/skills/agileflow-planning/references/rpi-workflow.md +119 -0
- package/content/plugins/planning/skills/agileflow-planning/references/sprint-planning-guide.md +145 -0
- package/content/plugins/planning/skills/agileflow-planning/workflows/impact.md +63 -0
- package/content/plugins/planning/skills/agileflow-planning/workflows/rpi.md +104 -0
- package/content/plugins/psychology/plugin.yaml +14 -0
- package/content/plugins/psychology/skills/agileflow-retention/SKILL.md +252 -0
- package/content/plugins/psychology/skills/agileflow-retention/references/competitor-analysis.md +240 -0
- package/content/plugins/psychology/skills/agileflow-retention/references/psychology-models.md +349 -0
- package/content/plugins/psychology/skills/agileflow-retention/references/retention-patterns.md +279 -0
- package/content/plugins/psychology/skills/agileflow-retention/workflows/design-retention-feature.md +287 -0
- package/content/plugins/psychology/skills/agileflow-retention/workflows/retention-audit.md +259 -0
- package/content/plugins/refactoring/plugin.yaml +14 -0
- package/content/plugins/refactoring/skills/agileflow-refactor/SKILL.md +235 -0
- package/content/plugins/refactoring/skills/agileflow-refactor/references/refactoring-patterns.md +405 -0
- package/content/plugins/refactoring/skills/agileflow-refactor/references/safety-checks.md +177 -0
- package/content/plugins/refactoring/skills/agileflow-refactor/workflows/extract-module.md +226 -0
- package/content/plugins/refactoring/skills/agileflow-refactor/workflows/safe-refactor.md +169 -0
- package/content/plugins/research/agents/research.md +503 -0
- package/content/plugins/research/plugin.yaml +17 -0
- package/content/plugins/research/skills/agileflow-research/SKILL.md +110 -0
- package/content/plugins/research/skills/agileflow-research/references/knowledge-decay-guide.md +121 -0
- package/content/plugins/research/skills/agileflow-research/references/research-prompt-guide.md +141 -0
- package/content/plugins/research/skills/agileflow-research/references/synthesis-template.md +154 -0
- package/content/plugins/research/skills/agileflow-research/workflows/analyze.md +60 -0
- package/content/plugins/research/skills/agileflow-research/workflows/ask.md +64 -0
- package/content/plugins/research/skills/agileflow-research/workflows/import.md +66 -0
- package/content/plugins/research/skills/agileflow-research/workflows/synthesize.md +66 -0
- package/content/plugins/reviews/plugin.yaml +14 -0
- package/content/plugins/reviews/skills/agileflow-pr-reviewer/SKILL.md +241 -0
- package/content/plugins/reviews/skills/agileflow-pr-reviewer/references/review-checklist.md +200 -0
- package/content/plugins/reviews/skills/agileflow-pr-reviewer/references/security-patterns.md +328 -0
- package/content/plugins/reviews/skills/agileflow-pr-reviewer/workflows/review-pr.md +153 -0
- package/content/plugins/reviews/skills/agileflow-pr-reviewer/workflows/security-review.md +177 -0
- package/content/plugins/seo/agents/seo-analyzer-content.md +169 -0
- package/content/plugins/seo/agents/seo-analyzer-images.md +198 -0
- package/content/plugins/seo/agents/seo-analyzer-performance.md +217 -0
- package/content/plugins/seo/agents/seo-analyzer-schema.md +184 -0
- package/content/plugins/seo/agents/seo-analyzer-sitemap.md +177 -0
- package/content/plugins/seo/agents/seo-analyzer-technical.md +151 -0
- package/content/plugins/seo/agents/seo-consensus.md +304 -0
- package/content/plugins/seo/plugin.yaml +19 -4
- package/content/plugins/seo/skills/agileflow-seo/SKILL.md +188 -0
- package/content/plugins/seo/skills/agileflow-seo/references/cwv-thresholds.md +110 -0
- package/content/plugins/seo/skills/agileflow-seo/references/eeat-framework.md +144 -0
- package/content/plugins/seo/skills/agileflow-seo/references/keyword-research-guide.md +125 -0
- package/content/plugins/seo/skills/agileflow-seo/references/schema-types.md +139 -0
- package/content/plugins/seo/skills/agileflow-seo/references/technical-seo-checklist.md +139 -0
- package/content/plugins/seo/skills/agileflow-seo/workflows/audit.md +98 -0
- package/content/plugins/seo/skills/agileflow-seo/workflows/page.md +118 -0
- package/content/plugins/testing/plugin.yaml +16 -0
- package/content/plugins/testing/skills/agileflow-test-writer/SKILL.md +260 -0
- package/content/plugins/testing/skills/agileflow-test-writer/references/coverage-targets.md +239 -0
- package/content/plugins/testing/skills/agileflow-test-writer/references/test-patterns.md +420 -0
- package/content/plugins/testing/skills/agileflow-test-writer/workflows/add-coverage.md +154 -0
- package/content/plugins/testing/skills/agileflow-test-writer/workflows/write-tests-from-ac.md +225 -0
- package/package.json +2 -2
- package/src/cli/commands/doctor.js +818 -30
- package/src/cli/commands/hook.js +17 -14
- package/src/cli/commands/launch.js +1454 -0
- package/src/cli/commands/learn.js +149 -0
- package/src/cli/commands/plugins.js +113 -0
- package/src/cli/commands/setup.js +455 -110
- package/src/cli/commands/skills.js +324 -0
- package/src/cli/commands/status.js +8 -10
- package/src/cli/commands/update.js +76 -15
- package/src/cli/index.js +90 -26
- package/src/cli/wizard/babysit-mode-picker.js +192 -0
- package/src/cli/wizard/behaviors-picker.js +208 -54
- package/src/cli/wizard/ide-picker.js +40 -28
- package/src/cli/wizard/install-scope-picker.js +57 -0
- package/src/cli/wizard/launch-alias-picker.js +50 -0
- package/src/cli/wizard/launch-cli-picker.js +129 -0
- package/src/cli/wizard/launch-tmux-picker.js +133 -0
- package/src/cli/wizard/learnings-picker.js +40 -0
- package/src/cli/wizard/plugin-picker.js +47 -16
- package/src/lib/brand.js +116 -0
- package/src/lib/errors.js +120 -0
- package/src/lib/path-check.js +39 -0
- package/src/runtime/config/defaults.js +22 -17
- package/src/runtime/config/loader.js +77 -8
- package/src/runtime/config/schema.json +43 -16
- package/src/runtime/config/writer.js +3 -1
- package/src/runtime/ide/babysit-skill.js +202 -0
- package/src/runtime/ide/capabilities.js +84 -29
- package/src/runtime/ide/claude-code-content.js +177 -0
- package/src/runtime/ide/claude-code-settings.js +67 -29
- package/src/runtime/ide/claude-code-skills.js +47 -32
- package/src/runtime/ide/codex-config.js +295 -0
- package/src/runtime/installer/install.js +252 -24
- package/src/runtime/launch/alias-installer.js +191 -0
- package/src/runtime/launch/cli-resume.js +244 -0
- package/src/runtime/launch/closed-windows.js +338 -0
- package/src/runtime/launch/defaults.js +66 -0
- package/src/runtime/launch/detect-clis.js +69 -0
- package/src/runtime/launch/doctor.js +464 -0
- package/src/runtime/launch/exec-wrapper.js +114 -0
- package/src/runtime/launch/parallel-session.js +247 -0
- package/src/runtime/launch/prefs.js +211 -0
- package/src/runtime/launch/project-prefs.js +234 -0
- package/src/runtime/launch/resolve-cli.js +56 -0
- package/src/runtime/launch/restore.js +152 -0
- package/src/runtime/launch/schema.json +75 -0
- package/src/runtime/launch/session-lifecycle.js +313 -0
- package/src/runtime/launch/session-registry.js +401 -0
- package/src/runtime/launch/spawn.js +103 -0
- package/src/runtime/launch/tabs.js +350 -0
- package/src/runtime/launch/tmux.js +764 -0
- package/src/runtime/launch/worktree.js +260 -0
- package/src/runtime/plugins/registry.js +16 -11
- package/src/runtime/plugins/validator.js +57 -43
- package/src/runtime/skills/learnings.js +308 -0
- package/content/plugins/core/hooks/babysit-mentor-injector.js +0 -55
- package/src/cli/wizard/personalization.js +0 -64
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve the AI CLI to launch given a prefs object.
|
|
3
|
+
*
|
|
4
|
+
* Walks `[cli.preferred, ...cli.fallbackOrder]` (deduped, preferred first),
|
|
5
|
+
* looks up each id's descriptor in the known-CLI registry, and returns
|
|
6
|
+
* the first one whose binary actually resolves on PATH. Returns null if
|
|
7
|
+
* none of the user's configured CLIs are installed — the caller surfaces
|
|
8
|
+
* the actionable error.
|
|
9
|
+
*
|
|
10
|
+
* `exists` is injectable so tests don't shell out.
|
|
11
|
+
*/
|
|
12
|
+
const { commandExists: realCommandExists } = require("../../lib/path-check.js");
|
|
13
|
+
const { findCli } = require("./detect-clis.js");
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Build the dedup'd lookup order: preferred first, then any fallback ids
|
|
17
|
+
* that weren't the preferred. Skips ids the user has explicitly removed
|
|
18
|
+
* from fallback (i.e., empty fallbackOrder means "only try preferred").
|
|
19
|
+
*
|
|
20
|
+
* @param {{ preferred: string, fallbackOrder: string[] }} cli
|
|
21
|
+
* @returns {string[]}
|
|
22
|
+
*/
|
|
23
|
+
function buildLookupOrder(cli) {
|
|
24
|
+
const seen = new Set();
|
|
25
|
+
const order = [];
|
|
26
|
+
const push = (id) => {
|
|
27
|
+
if (typeof id !== "string" || !id) return;
|
|
28
|
+
if (seen.has(id)) return;
|
|
29
|
+
seen.add(id);
|
|
30
|
+
order.push(id);
|
|
31
|
+
};
|
|
32
|
+
push(cli.preferred);
|
|
33
|
+
for (const id of cli.fallbackOrder || []) push(id);
|
|
34
|
+
return order;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @param {{ cli: { preferred: string, fallbackOrder: string[] } }} prefs
|
|
39
|
+
* @param {(name: string) => boolean} [exists]
|
|
40
|
+
* @returns {{
|
|
41
|
+
* resolved: import('./detect-clis.js').CliDescriptor | null,
|
|
42
|
+
* tried: string[],
|
|
43
|
+
* }}
|
|
44
|
+
*/
|
|
45
|
+
function resolveCli(prefs, exists = realCommandExists) {
|
|
46
|
+
const tried = buildLookupOrder(prefs.cli);
|
|
47
|
+
for (const id of tried) {
|
|
48
|
+
const desc = findCli(id);
|
|
49
|
+
if (desc && exists(desc.bin)) {
|
|
50
|
+
return { resolved: desc, tried };
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return { resolved: null, tried };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
module.exports = { resolveCli, buildLookupOrder };
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bulk-restore tmux sessions from the registry after the tmux server
|
|
3
|
+
* died (typical cause: PC reboot). Walks every entry and re-creates
|
|
4
|
+
* the corresponding tmux session in the original cwd, wired to invoke
|
|
5
|
+
* `agileflow launch __exec <name>` so the per-CLI resume strategy
|
|
6
|
+
* fires automatically.
|
|
7
|
+
*
|
|
8
|
+
* Sessions that already exist on the running tmux server are skipped —
|
|
9
|
+
* restore is idempotent. Sessions whose original cwd no longer exists
|
|
10
|
+
* are skipped with a warning (e.g., user deleted the project dir).
|
|
11
|
+
*
|
|
12
|
+
* Returns counts so the caller can show a "restored N of M" summary.
|
|
13
|
+
*/
|
|
14
|
+
const fs = require("fs");
|
|
15
|
+
const path = require("path");
|
|
16
|
+
|
|
17
|
+
const {
|
|
18
|
+
defaultRunner,
|
|
19
|
+
sessionExists,
|
|
20
|
+
createSession,
|
|
21
|
+
applyKeybindPreset,
|
|
22
|
+
applyTabFormat,
|
|
23
|
+
detectTmuxVersion,
|
|
24
|
+
} = require("./tmux.js");
|
|
25
|
+
const { loadRegistry } = require("./session-registry.js");
|
|
26
|
+
const { resolveAgileflowBin } = require("./alias-installer.js");
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @typedef {Object} RestoreResult
|
|
30
|
+
* @property {number} restored
|
|
31
|
+
* @property {number} alreadyAlive
|
|
32
|
+
* @property {number} skipped - cwd missing or other unrecoverable state
|
|
33
|
+
* @property {number} failed
|
|
34
|
+
* @property {Array<{ name: string, reason: string }>} notes
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @param {{
|
|
39
|
+
* prefs: import("./defaults.js").LaunchPrefs,
|
|
40
|
+
* runner?: ReturnType<typeof defaultRunner>,
|
|
41
|
+
* home?: string,
|
|
42
|
+
* agileflowBin?: string,
|
|
43
|
+
* existsSync?: (p: string) => boolean,
|
|
44
|
+
* log?: (msg: string) => void,
|
|
45
|
+
* onlyName?: string,
|
|
46
|
+
* onlyNames?: string[],
|
|
47
|
+
* }} opts
|
|
48
|
+
* @returns {RestoreResult}
|
|
49
|
+
*/
|
|
50
|
+
function runRestore(opts) {
|
|
51
|
+
const runner = opts.runner || defaultRunner();
|
|
52
|
+
const existsSync = opts.existsSync || ((p) => fs.existsSync(p));
|
|
53
|
+
const log =
|
|
54
|
+
typeof opts.log === "function"
|
|
55
|
+
? opts.log
|
|
56
|
+
: (msg) => {
|
|
57
|
+
// eslint-disable-next-line no-console
|
|
58
|
+
console.error(msg);
|
|
59
|
+
};
|
|
60
|
+
const agileflowBin = opts.agileflowBin || resolveAgileflowBin();
|
|
61
|
+
|
|
62
|
+
const reg = loadRegistry(opts.home);
|
|
63
|
+
/** @type {RestoreResult} */
|
|
64
|
+
const result = {
|
|
65
|
+
restored: 0,
|
|
66
|
+
alreadyAlive: 0,
|
|
67
|
+
skipped: 0,
|
|
68
|
+
failed: 0,
|
|
69
|
+
notes: [],
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
/** @type {import("./session-registry.js").SessionEntry[]} */
|
|
73
|
+
let entries;
|
|
74
|
+
if (opts.onlyName) {
|
|
75
|
+
entries = reg.sessions.filter((s) => s.name === opts.onlyName);
|
|
76
|
+
} else if (Array.isArray(opts.onlyNames)) {
|
|
77
|
+
// Use a Set for O(1) lookup so a 100-entry registry restoring a
|
|
78
|
+
// 20-entry subset stays linear, not quadratic.
|
|
79
|
+
const wanted = new Set(opts.onlyNames);
|
|
80
|
+
entries = reg.sessions.filter((s) => wanted.has(s.name));
|
|
81
|
+
} else {
|
|
82
|
+
entries = reg.sessions.slice();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
for (const entry of entries) {
|
|
86
|
+
if (sessionExists(entry.name, runner)) {
|
|
87
|
+
result.alreadyAlive++;
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
if (!existsSync(entry.cwd)) {
|
|
91
|
+
result.skipped++;
|
|
92
|
+
result.notes.push({
|
|
93
|
+
name: entry.name,
|
|
94
|
+
reason: `cwd no longer exists: ${entry.cwd}`,
|
|
95
|
+
});
|
|
96
|
+
log(
|
|
97
|
+
`agileflow launch: skipping ${entry.name} — cwd missing (${entry.cwd})`,
|
|
98
|
+
);
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Tmux session command: invoke our own wrapper. tmux passes argv
|
|
103
|
+
// as separate words via the new-session args we hand it.
|
|
104
|
+
const wrapperArgs = [agileflowBin, "launch", "__exec", entry.name];
|
|
105
|
+
const create = createSession(
|
|
106
|
+
{
|
|
107
|
+
name: entry.name,
|
|
108
|
+
bin: wrapperArgs[0],
|
|
109
|
+
args: wrapperArgs.slice(1),
|
|
110
|
+
cwd: entry.cwd,
|
|
111
|
+
statusPosition: opts.prefs.tmux.statusPosition,
|
|
112
|
+
},
|
|
113
|
+
runner,
|
|
114
|
+
);
|
|
115
|
+
if (create.status !== 0) {
|
|
116
|
+
result.failed++;
|
|
117
|
+
const stderr = (create.stderr || "").trim() || "tmux new-session failed";
|
|
118
|
+
result.notes.push({ name: entry.name, reason: stderr });
|
|
119
|
+
log(`agileflow launch: failed to restore ${entry.name} — ${stderr}`);
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
// Apply the same per-session styling launchInTmux does for fresh
|
|
123
|
+
// sessions so the tab strip looks consistent on restore. Without
|
|
124
|
+
// this, restored sessions show tmux's default green status bar
|
|
125
|
+
// instead of the AgileFlow dark strip.
|
|
126
|
+
runner.runSync(["set-option", "-t", entry.name, "status", "1"]);
|
|
127
|
+
applyTabFormat(entry.name, runner, {
|
|
128
|
+
tmuxVersion: detectTmuxVersion(runner),
|
|
129
|
+
});
|
|
130
|
+
result.restored++;
|
|
131
|
+
log(`agileflow launch: restored session ${entry.name} (${entry.cwd})`);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Apply keybinds once after the bulk restore so the user's preset is
|
|
135
|
+
// active across all the new sessions (tmux bind-key is server-wide).
|
|
136
|
+
if (
|
|
137
|
+
result.restored > 0 &&
|
|
138
|
+
opts.prefs.keybinds &&
|
|
139
|
+
opts.prefs.keybinds.preset
|
|
140
|
+
) {
|
|
141
|
+
const kr = applyKeybindPreset(opts.prefs.keybinds.preset, runner, {
|
|
142
|
+
agileflowBin,
|
|
143
|
+
});
|
|
144
|
+
for (const f of kr.failures) {
|
|
145
|
+
log(`agileflow launch: keybind skipped during restore — ${f.hint}`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return result;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
module.exports = { runRestore };
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://agileflow.dev/schemas/launch-prefs.v1.json",
|
|
4
|
+
"title": "AgileFlow launch preferences",
|
|
5
|
+
"description": "User-level preferences for `agileflow launch` (multi-CLI tmux wrapper). Lives at ~/.agileflow/launch-prefs.json.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["version", "cli", "tmux", "keybinds", "aliases", "pinned"],
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"properties": {
|
|
10
|
+
"$schema": { "type": "string" },
|
|
11
|
+
"version": { "const": 1 },
|
|
12
|
+
"cli": {
|
|
13
|
+
"type": "object",
|
|
14
|
+
"required": ["preferred", "fallbackOrder"],
|
|
15
|
+
"additionalProperties": false,
|
|
16
|
+
"properties": {
|
|
17
|
+
"preferred": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"enum": ["claude", "codex", "cursor-agent", "aider"]
|
|
20
|
+
},
|
|
21
|
+
"fallbackOrder": {
|
|
22
|
+
"type": "array",
|
|
23
|
+
"items": {
|
|
24
|
+
"type": "string",
|
|
25
|
+
"enum": ["claude", "codex", "cursor-agent", "aider"]
|
|
26
|
+
},
|
|
27
|
+
"uniqueItems": true
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"tmux": {
|
|
32
|
+
"type": "object",
|
|
33
|
+
"required": ["enabled", "statusPosition"],
|
|
34
|
+
"additionalProperties": false,
|
|
35
|
+
"properties": {
|
|
36
|
+
"enabled": { "type": "boolean" },
|
|
37
|
+
"statusPosition": { "type": "string", "enum": ["top", "bottom"] }
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"keybinds": {
|
|
41
|
+
"type": "object",
|
|
42
|
+
"required": ["preset"],
|
|
43
|
+
"additionalProperties": false,
|
|
44
|
+
"properties": {
|
|
45
|
+
"preset": {
|
|
46
|
+
"type": "string",
|
|
47
|
+
"enum": ["default", "minimal", "none"]
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"aliases": {
|
|
52
|
+
"type": "object",
|
|
53
|
+
"required": ["af"],
|
|
54
|
+
"additionalProperties": false,
|
|
55
|
+
"properties": {
|
|
56
|
+
"af": {
|
|
57
|
+
"type": "object",
|
|
58
|
+
"required": ["enabled"],
|
|
59
|
+
"additionalProperties": false,
|
|
60
|
+
"properties": {
|
|
61
|
+
"enabled": { "type": "boolean" }
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"pinned": {
|
|
67
|
+
"type": "array",
|
|
68
|
+
"items": { "type": "string" }
|
|
69
|
+
},
|
|
70
|
+
"lastUpdated": {
|
|
71
|
+
"type": "string",
|
|
72
|
+
"format": "date-time"
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure helpers behind `agileflow launch ls / kill / attach / prune`.
|
|
3
|
+
*
|
|
4
|
+
* Composes already-built primitives:
|
|
5
|
+
* - registry: load / find / forget
|
|
6
|
+
* - tmux: sessionExists / killSession / attachSession
|
|
7
|
+
* - restore: runRestore({ onlyName }) for lazy re-creation
|
|
8
|
+
* - worktree: removeWorktree for paired cleanup
|
|
9
|
+
*
|
|
10
|
+
* Every helper accepts a `deps` bag with injectable callables so the unit
|
|
11
|
+
* tests don't have to spawn tmux or touch a real registry. The CLI
|
|
12
|
+
* wrappers in `commands/launch.js` are the only place that wires in the
|
|
13
|
+
* real implementations.
|
|
14
|
+
*/
|
|
15
|
+
const fs = require("fs");
|
|
16
|
+
|
|
17
|
+
const {
|
|
18
|
+
loadRegistry,
|
|
19
|
+
findSession,
|
|
20
|
+
forgetSession,
|
|
21
|
+
} = require("./session-registry.js");
|
|
22
|
+
const {
|
|
23
|
+
defaultRunner,
|
|
24
|
+
sessionExists: tmuxSessionExists,
|
|
25
|
+
killSession: tmuxKillSession,
|
|
26
|
+
attachSession: tmuxAttachSession,
|
|
27
|
+
} = require("./tmux.js");
|
|
28
|
+
const { removeWorktree } = require("./worktree.js");
|
|
29
|
+
const { runRestore } = require("./restore.js");
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @typedef {import("./session-registry.js").SessionEntry & {
|
|
33
|
+
* state: 'alive' | 'dormant' | 'missing-cwd',
|
|
34
|
+
* }} ClassifiedSession
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Return every registered session, each tagged with its current state:
|
|
39
|
+
* - alive → tmux has the session
|
|
40
|
+
* - dormant → registry has it, cwd still exists, tmux doesn't
|
|
41
|
+
* - missing-cwd → registry has it but the cwd has been deleted
|
|
42
|
+
*
|
|
43
|
+
* Read-only — never mutates the registry. Worktree-only orphan detection
|
|
44
|
+
* lives in doctor.js; this helper just exposes raw state.
|
|
45
|
+
*
|
|
46
|
+
* @param {{
|
|
47
|
+
* home?: string,
|
|
48
|
+
* runner?: import("./tmux.js").TmuxRunner,
|
|
49
|
+
* sessionExistsFn?: typeof tmuxSessionExists,
|
|
50
|
+
* existsSync?: (p: string) => boolean,
|
|
51
|
+
* }} [deps]
|
|
52
|
+
* @returns {ClassifiedSession[]}
|
|
53
|
+
*/
|
|
54
|
+
function listSessions(deps = {}) {
|
|
55
|
+
const runner = deps.runner || defaultRunner();
|
|
56
|
+
const sessionExistsFn = deps.sessionExistsFn || tmuxSessionExists;
|
|
57
|
+
const existsSync = deps.existsSync || ((p) => fs.existsSync(p));
|
|
58
|
+
const reg = loadRegistry(deps.home);
|
|
59
|
+
return reg.sessions.map((entry) => {
|
|
60
|
+
const alive = sessionExistsFn(entry.name, runner);
|
|
61
|
+
const cwdExists = existsSync(entry.cwd);
|
|
62
|
+
/** @type {'alive' | 'dormant' | 'missing-cwd'} */
|
|
63
|
+
const state = alive ? "alive" : cwdExists ? "dormant" : "missing-cwd";
|
|
64
|
+
return { ...entry, state };
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Kill a tmux session (if alive) and forget the registry entry. When
|
|
70
|
+
* `removeWorktree` is true and the entry has worktree metadata pointing
|
|
71
|
+
* at a directory that still exists, also remove the worktree + branch.
|
|
72
|
+
*
|
|
73
|
+
* The worktree removal is gated on caller intent rather than auto-applied
|
|
74
|
+
* so the CLI wrapper can prompt the user before destructive cleanup.
|
|
75
|
+
*
|
|
76
|
+
* Return shape lets the wrapper render a precise outcome without
|
|
77
|
+
* re-querying state:
|
|
78
|
+
* - ok: false + reason="not in registry" → unknown name
|
|
79
|
+
* - ok: true + wasAlive: boolean → kill attempted
|
|
80
|
+
* - ok: true + worktree: { removed, branchRemoved, stderr }
|
|
81
|
+
* → worktree cleanup attempted
|
|
82
|
+
*
|
|
83
|
+
* @param {{
|
|
84
|
+
* name: string,
|
|
85
|
+
* removeWorktree?: boolean,
|
|
86
|
+
* home?: string,
|
|
87
|
+
* runner?: import("./tmux.js").TmuxRunner,
|
|
88
|
+
* sessionExistsFn?: typeof tmuxSessionExists,
|
|
89
|
+
* killSessionFn?: typeof tmuxKillSession,
|
|
90
|
+
* removeWorktreeFn?: typeof removeWorktree,
|
|
91
|
+
* existsSync?: (p: string) => boolean,
|
|
92
|
+
* }} deps
|
|
93
|
+
* @returns {{
|
|
94
|
+
* ok: boolean,
|
|
95
|
+
* reason?: string,
|
|
96
|
+
* wasAlive?: boolean,
|
|
97
|
+
* worktree?: ReturnType<typeof removeWorktree> | null,
|
|
98
|
+
* }}
|
|
99
|
+
*/
|
|
100
|
+
function killBySessionName(deps) {
|
|
101
|
+
const runner = deps.runner || defaultRunner();
|
|
102
|
+
const sessionExistsFn = deps.sessionExistsFn || tmuxSessionExists;
|
|
103
|
+
const killFn = deps.killSessionFn || tmuxKillSession;
|
|
104
|
+
const removeWtFn = deps.removeWorktreeFn || removeWorktree;
|
|
105
|
+
const existsSync = deps.existsSync || ((p) => fs.existsSync(p));
|
|
106
|
+
|
|
107
|
+
const entry = findSession(deps.name, deps.home);
|
|
108
|
+
if (!entry) return { ok: false, reason: "not in registry" };
|
|
109
|
+
|
|
110
|
+
// Best-effort kill: ignore the return value because we proceed with
|
|
111
|
+
// forget regardless. A failed kill on an alive session leaves a tmux
|
|
112
|
+
// orphan, but the registry stays consistent.
|
|
113
|
+
const wasAlive = sessionExistsFn(entry.name, runner);
|
|
114
|
+
if (wasAlive) killFn(entry.name, runner);
|
|
115
|
+
|
|
116
|
+
// forgetSession can throw if the lockfile can't be acquired (registry
|
|
117
|
+
// contention from concurrent __exec processes). Surface that as a
|
|
118
|
+
// structured failure instead of letting the exception escape — callers
|
|
119
|
+
// expect this helper to honor the { ok, reason, ... } contract.
|
|
120
|
+
try {
|
|
121
|
+
forgetSession(deps.name, deps.home);
|
|
122
|
+
} catch (err) {
|
|
123
|
+
return {
|
|
124
|
+
ok: false,
|
|
125
|
+
reason: `could not update registry: ${err && err.message ? err.message : String(err)}`,
|
|
126
|
+
wasAlive,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/** @type {ReturnType<typeof removeWorktree> | null} */
|
|
131
|
+
let wt = null;
|
|
132
|
+
if (
|
|
133
|
+
deps.removeWorktree &&
|
|
134
|
+
entry.worktree &&
|
|
135
|
+
entry.worktree.path &&
|
|
136
|
+
existsSync(entry.worktree.path)
|
|
137
|
+
) {
|
|
138
|
+
wt = removeWtFn({
|
|
139
|
+
path: entry.worktree.path,
|
|
140
|
+
branch: entry.worktree.branch || undefined,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
return { ok: true, wasAlive, worktree: wt };
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Attach to a registered session, lazily restoring it from the registry
|
|
148
|
+
* if the tmux server doesn't currently have it. The lazy-restore step is
|
|
149
|
+
* what makes this useful after a reboot — `agileflow launch attach foo`
|
|
150
|
+
* Just Works whether or not foo is currently on the server.
|
|
151
|
+
*
|
|
152
|
+
* Failure cases (return { ok: false, reason }):
|
|
153
|
+
* - "not in registry" → unknown name
|
|
154
|
+
* - "cwd missing" → original directory deleted; can't restore
|
|
155
|
+
* - "could not restore" → tmux refused new-session (notes carries why)
|
|
156
|
+
*
|
|
157
|
+
* @param {{
|
|
158
|
+
* name: string,
|
|
159
|
+
* home?: string,
|
|
160
|
+
* prefs: import("./defaults.js").LaunchPrefs,
|
|
161
|
+
* agileflowBin?: string,
|
|
162
|
+
* runner?: import("./tmux.js").TmuxRunner,
|
|
163
|
+
* sessionExistsFn?: typeof tmuxSessionExists,
|
|
164
|
+
* attachSessionFn?: typeof tmuxAttachSession,
|
|
165
|
+
* runRestoreImpl?: typeof runRestore,
|
|
166
|
+
* existsSync?: (p: string) => boolean,
|
|
167
|
+
* }} deps
|
|
168
|
+
* @returns {Promise<{
|
|
169
|
+
* ok: boolean,
|
|
170
|
+
* reason?: string,
|
|
171
|
+
* restored?: boolean,
|
|
172
|
+
* attach?: Awaited<ReturnType<typeof tmuxAttachSession>>,
|
|
173
|
+
* notes?: Array<{ name: string, reason: string }>,
|
|
174
|
+
* }>}
|
|
175
|
+
*/
|
|
176
|
+
async function attachByName(deps) {
|
|
177
|
+
const runner = deps.runner || defaultRunner();
|
|
178
|
+
const sessionExistsFn = deps.sessionExistsFn || tmuxSessionExists;
|
|
179
|
+
const attachFn = deps.attachSessionFn || tmuxAttachSession;
|
|
180
|
+
const restoreFn = deps.runRestoreImpl || runRestore;
|
|
181
|
+
const existsSync = deps.existsSync || ((p) => fs.existsSync(p));
|
|
182
|
+
|
|
183
|
+
const entry = findSession(deps.name, deps.home);
|
|
184
|
+
if (!entry) return { ok: false, reason: "not in registry" };
|
|
185
|
+
if (!existsSync(entry.cwd)) return { ok: false, reason: "cwd missing" };
|
|
186
|
+
|
|
187
|
+
let restored = false;
|
|
188
|
+
if (!sessionExistsFn(entry.name, runner)) {
|
|
189
|
+
const r = restoreFn({
|
|
190
|
+
prefs: deps.prefs,
|
|
191
|
+
runner,
|
|
192
|
+
home: deps.home,
|
|
193
|
+
agileflowBin: deps.agileflowBin,
|
|
194
|
+
onlyName: deps.name,
|
|
195
|
+
});
|
|
196
|
+
if (r.restored === 0) {
|
|
197
|
+
return { ok: false, reason: "could not restore", notes: r.notes };
|
|
198
|
+
}
|
|
199
|
+
restored = true;
|
|
200
|
+
}
|
|
201
|
+
const attach = await attachFn(entry.name, runner);
|
|
202
|
+
return { ok: true, restored, attach };
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Return the registry entries that are safe to forget in bulk:
|
|
207
|
+
* - dormant + cwd missing (project deleted)
|
|
208
|
+
* - dormant + worktree dir missing (someone `git worktree remove`'d it)
|
|
209
|
+
*
|
|
210
|
+
* Alive sessions are NEVER candidates. Dormant entries with a live cwd
|
|
211
|
+
* stay too — the user likely just shut tmux down and intends to restore.
|
|
212
|
+
*
|
|
213
|
+
* Each candidate is annotated with `reason` so the CLI wrapper can show
|
|
214
|
+
* the user why it's offering the cleanup.
|
|
215
|
+
*
|
|
216
|
+
* @param {{
|
|
217
|
+
* home?: string,
|
|
218
|
+
* runner?: import("./tmux.js").TmuxRunner,
|
|
219
|
+
* sessionExistsFn?: typeof tmuxSessionExists,
|
|
220
|
+
* existsSync?: (p: string) => boolean,
|
|
221
|
+
* }} [deps]
|
|
222
|
+
* @returns {Array<ClassifiedSession & { reason: string }>}
|
|
223
|
+
*/
|
|
224
|
+
function pruneCandidates(deps = {}) {
|
|
225
|
+
const existsSync = deps.existsSync || ((p) => fs.existsSync(p));
|
|
226
|
+
const classified = listSessions(deps);
|
|
227
|
+
/** @type {Array<ClassifiedSession & { reason: string }>} */
|
|
228
|
+
const out = [];
|
|
229
|
+
for (const c of classified) {
|
|
230
|
+
if (c.state === "alive") continue;
|
|
231
|
+
// Pinned entries are explicit "always keep" — never surface them as
|
|
232
|
+
// prune candidates, even if their cwd disappeared. The user has to
|
|
233
|
+
// unpin first if they really want to forget.
|
|
234
|
+
if (c.pinned) continue;
|
|
235
|
+
if (c.state === "missing-cwd") {
|
|
236
|
+
out.push({ ...c, reason: `cwd missing: ${c.cwd}` });
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
if (c.worktree && c.worktree.path && !existsSync(c.worktree.path)) {
|
|
240
|
+
out.push({
|
|
241
|
+
...c,
|
|
242
|
+
reason: `worktree dir missing: ${c.worktree.path}`,
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return out;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Apply a prune selection: forget each named entry, optionally remove
|
|
251
|
+
* its worktree (only when the path still exists — pruneCandidates
|
|
252
|
+
* surfaces missing-dir cases, but we don't want to issue `git worktree
|
|
253
|
+
* remove` on something the user already cleaned up manually).
|
|
254
|
+
*
|
|
255
|
+
* Returns counts so the CLI wrapper can print a one-line summary.
|
|
256
|
+
*
|
|
257
|
+
* @param {{
|
|
258
|
+
* selections: Array<{ name: string }>,
|
|
259
|
+
* removeWorktrees?: boolean,
|
|
260
|
+
* home?: string,
|
|
261
|
+
* removeWorktreeFn?: typeof removeWorktree,
|
|
262
|
+
* existsSync?: (p: string) => boolean,
|
|
263
|
+
* }} deps
|
|
264
|
+
* @returns {{ forgotten: number, worktreesRemoved: number, errors: Array<{ name: string, error: string }> }}
|
|
265
|
+
*/
|
|
266
|
+
function applyPrune(deps) {
|
|
267
|
+
const removeWtFn = deps.removeWorktreeFn || removeWorktree;
|
|
268
|
+
const existsSync = deps.existsSync || ((p) => fs.existsSync(p));
|
|
269
|
+
let forgotten = 0;
|
|
270
|
+
let worktreesRemoved = 0;
|
|
271
|
+
/** @type {Array<{ name: string, error: string }>} */
|
|
272
|
+
const errors = [];
|
|
273
|
+
|
|
274
|
+
for (const sel of deps.selections || []) {
|
|
275
|
+
const entry = findSession(sel.name, deps.home);
|
|
276
|
+
if (!entry) {
|
|
277
|
+
// Concurrent prune from another process? Skip; nothing to do.
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
280
|
+
if (
|
|
281
|
+
deps.removeWorktrees &&
|
|
282
|
+
entry.worktree &&
|
|
283
|
+
entry.worktree.path &&
|
|
284
|
+
existsSync(entry.worktree.path)
|
|
285
|
+
) {
|
|
286
|
+
try {
|
|
287
|
+
const r = removeWtFn({
|
|
288
|
+
path: entry.worktree.path,
|
|
289
|
+
branch: entry.worktree.branch || undefined,
|
|
290
|
+
});
|
|
291
|
+
if (r.removed) worktreesRemoved++;
|
|
292
|
+
if (r.stderr) errors.push({ name: sel.name, error: r.stderr });
|
|
293
|
+
} catch (err) {
|
|
294
|
+
errors.push({ name: sel.name, error: err.message || String(err) });
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
try {
|
|
298
|
+
forgetSession(sel.name, deps.home);
|
|
299
|
+
forgotten++;
|
|
300
|
+
} catch (err) {
|
|
301
|
+
errors.push({ name: sel.name, error: err.message || String(err) });
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
return { forgotten, worktreesRemoved, errors };
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
module.exports = {
|
|
308
|
+
listSessions,
|
|
309
|
+
killBySessionName,
|
|
310
|
+
attachByName,
|
|
311
|
+
pruneCandidates,
|
|
312
|
+
applyPrune,
|
|
313
|
+
};
|