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.
Files changed (372) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/content/plugins/accessibility/plugin.yaml +14 -0
  3. package/content/plugins/accessibility/skills/agileflow-accessibility/SKILL.md +392 -0
  4. package/content/plugins/accessibility/skills/agileflow-accessibility/references/aria-patterns.md +528 -0
  5. package/content/plugins/accessibility/skills/agileflow-accessibility/references/testing-checklist.md +457 -0
  6. package/content/plugins/accessibility/skills/agileflow-accessibility/references/wcag-guide.md +683 -0
  7. package/content/plugins/accessibility/skills/agileflow-accessibility/workflows/audit-page.md +310 -0
  8. package/content/plugins/accessibility/skills/agileflow-accessibility/workflows/implement-accessible-component.md +479 -0
  9. package/content/plugins/ads/agents/ads-audit-budget.md +185 -0
  10. package/content/plugins/ads/agents/ads-audit-compliance.md +171 -0
  11. package/content/plugins/ads/agents/ads-audit-creative.md +168 -0
  12. package/content/plugins/ads/agents/ads-audit-google.md +227 -0
  13. package/content/plugins/ads/agents/ads-audit-meta.md +184 -0
  14. package/content/plugins/ads/agents/ads-audit-tracking.md +205 -0
  15. package/content/plugins/ads/agents/ads-consensus.md +410 -0
  16. package/content/plugins/ads/agents/ads-generate.md +152 -0
  17. package/content/plugins/ads/agents/ads-performance-tracker.md +212 -0
  18. package/content/plugins/ads/plugin.yaml +23 -4
  19. package/content/plugins/ads/skills/agileflow-ads/SKILL.md +218 -0
  20. package/content/plugins/ads/skills/agileflow-ads/references/ad-copy-formula-guide.md +131 -0
  21. package/content/plugins/ads/skills/agileflow-ads/references/audience-targeting-guide.md +137 -0
  22. package/content/plugins/ads/skills/agileflow-ads/references/bid-strategy-guide.md +115 -0
  23. package/content/plugins/ads/skills/agileflow-ads/references/platform-benchmarks.md +100 -0
  24. package/content/plugins/ads/skills/agileflow-ads/workflows/audit.md +118 -0
  25. package/content/plugins/ads/skills/agileflow-ads/workflows/generate.md +84 -0
  26. package/content/plugins/audit/agents/a11y-analyzer-aria.md +173 -0
  27. package/content/plugins/audit/agents/a11y-analyzer-forms.md +173 -0
  28. package/content/plugins/audit/agents/a11y-analyzer-keyboard.md +183 -0
  29. package/content/plugins/audit/agents/a11y-analyzer-semantic.md +169 -0
  30. package/content/plugins/audit/agents/a11y-analyzer-visual.md +172 -0
  31. package/content/plugins/audit/agents/a11y-consensus.md +249 -0
  32. package/content/plugins/audit/agents/accessibility.md +558 -0
  33. package/content/plugins/audit/agents/api-quality-analyzer-conventions.md +156 -0
  34. package/content/plugins/audit/agents/api-quality-analyzer-docs.md +184 -0
  35. package/content/plugins/audit/agents/api-quality-analyzer-errors.md +191 -0
  36. package/content/plugins/audit/agents/api-quality-analyzer-pagination.md +179 -0
  37. package/content/plugins/audit/agents/api-quality-analyzer-versioning.md +150 -0
  38. package/content/plugins/audit/agents/api-quality-consensus.md +217 -0
  39. package/content/plugins/audit/agents/api-validator.md +191 -0
  40. package/content/plugins/audit/agents/arch-analyzer-circular.md +156 -0
  41. package/content/plugins/audit/agents/arch-analyzer-complexity.md +193 -0
  42. package/content/plugins/audit/agents/arch-analyzer-coupling.md +152 -0
  43. package/content/plugins/audit/agents/arch-analyzer-layering.md +160 -0
  44. package/content/plugins/audit/agents/arch-analyzer-patterns.md +210 -0
  45. package/content/plugins/audit/agents/arch-consensus.md +228 -0
  46. package/content/plugins/audit/agents/browser-qa.md +342 -0
  47. package/content/plugins/audit/agents/code-reviewer.md +298 -0
  48. package/content/plugins/audit/agents/completeness-analyzer-api.md +199 -0
  49. package/content/plugins/audit/agents/completeness-analyzer-conditional.md +211 -0
  50. package/content/plugins/audit/agents/completeness-analyzer-handlers.md +166 -0
  51. package/content/plugins/audit/agents/completeness-analyzer-imports.md +165 -0
  52. package/content/plugins/audit/agents/completeness-analyzer-routes.md +190 -0
  53. package/content/plugins/audit/agents/completeness-analyzer-state.md +196 -0
  54. package/content/plugins/audit/agents/completeness-analyzer-stubs.md +206 -0
  55. package/content/plugins/audit/agents/completeness-consensus.md +295 -0
  56. package/content/plugins/audit/agents/error-analyzer.md +213 -0
  57. package/content/plugins/audit/agents/flow-analyzer-authorization.md +182 -0
  58. package/content/plugins/audit/agents/flow-analyzer-discovery.md +174 -0
  59. package/content/plugins/audit/agents/flow-analyzer-errors.md +186 -0
  60. package/content/plugins/audit/agents/flow-analyzer-feedback.md +185 -0
  61. package/content/plugins/audit/agents/flow-analyzer-navigation.md +177 -0
  62. package/content/plugins/audit/agents/flow-analyzer-persistence.md +193 -0
  63. package/content/plugins/audit/agents/flow-analyzer-wiring.md +169 -0
  64. package/content/plugins/audit/agents/flow-consensus.md +237 -0
  65. package/content/plugins/audit/agents/legal-analyzer-a11y.md +114 -0
  66. package/content/plugins/audit/agents/legal-analyzer-ai.md +121 -0
  67. package/content/plugins/audit/agents/legal-analyzer-consumer.md +114 -0
  68. package/content/plugins/audit/agents/legal-analyzer-content.md +117 -0
  69. package/content/plugins/audit/agents/legal-analyzer-international.md +119 -0
  70. package/content/plugins/audit/agents/legal-analyzer-licensing.md +119 -0
  71. package/content/plugins/audit/agents/legal-analyzer-privacy.md +112 -0
  72. package/content/plugins/audit/agents/legal-analyzer-security.md +116 -0
  73. package/content/plugins/audit/agents/legal-analyzer-terms.md +115 -0
  74. package/content/plugins/audit/agents/legal-consensus.md +250 -0
  75. package/content/plugins/audit/agents/logic-analyzer-edge.md +179 -0
  76. package/content/plugins/audit/agents/logic-analyzer-flow.md +264 -0
  77. package/content/plugins/audit/agents/logic-analyzer-invariant.md +215 -0
  78. package/content/plugins/audit/agents/logic-analyzer-race.md +280 -0
  79. package/content/plugins/audit/agents/logic-analyzer-type.md +227 -0
  80. package/content/plugins/audit/agents/logic-consensus.md +259 -0
  81. package/content/plugins/audit/agents/perf-analyzer-assets.md +182 -0
  82. package/content/plugins/audit/agents/perf-analyzer-bundle.md +173 -0
  83. package/content/plugins/audit/agents/perf-analyzer-caching.md +170 -0
  84. package/content/plugins/audit/agents/perf-analyzer-compute.md +173 -0
  85. package/content/plugins/audit/agents/perf-analyzer-memory.md +193 -0
  86. package/content/plugins/audit/agents/perf-analyzer-network.md +165 -0
  87. package/content/plugins/audit/agents/perf-analyzer-queries.md +162 -0
  88. package/content/plugins/audit/agents/perf-analyzer-rendering.md +168 -0
  89. package/content/plugins/audit/agents/perf-consensus.md +287 -0
  90. package/content/plugins/audit/agents/qa.md +820 -0
  91. package/content/plugins/audit/agents/quality-analyzer-comments.md +159 -0
  92. package/content/plugins/audit/agents/quality-analyzer-duplication.md +184 -0
  93. package/content/plugins/audit/agents/quality-analyzer-naming.md +160 -0
  94. package/content/plugins/audit/agents/quality-consensus.md +241 -0
  95. package/content/plugins/audit/agents/schema-validator.md +473 -0
  96. package/content/plugins/audit/agents/security-analyzer-api.md +210 -0
  97. package/content/plugins/audit/agents/security-analyzer-auth.md +169 -0
  98. package/content/plugins/audit/agents/security-analyzer-authz.md +180 -0
  99. package/content/plugins/audit/agents/security-analyzer-deps.md +153 -0
  100. package/content/plugins/audit/agents/security-analyzer-infra.md +184 -0
  101. package/content/plugins/audit/agents/security-analyzer-injection.md +155 -0
  102. package/content/plugins/audit/agents/security-analyzer-input.md +201 -0
  103. package/content/plugins/audit/agents/security-analyzer-secrets.md +183 -0
  104. package/content/plugins/audit/agents/security-consensus.md +283 -0
  105. package/content/plugins/audit/agents/test-analyzer-assertions.md +188 -0
  106. package/content/plugins/audit/agents/test-analyzer-coverage.md +189 -0
  107. package/content/plugins/audit/agents/test-analyzer-fragility.md +193 -0
  108. package/content/plugins/audit/agents/test-analyzer-integration.md +161 -0
  109. package/content/plugins/audit/agents/test-analyzer-maintenance.md +180 -0
  110. package/content/plugins/audit/agents/test-analyzer-mocking.md +188 -0
  111. package/content/plugins/audit/agents/test-analyzer-patterns.md +196 -0
  112. package/content/plugins/audit/agents/test-analyzer-structure.md +184 -0
  113. package/content/plugins/audit/agents/test-consensus.md +301 -0
  114. package/content/plugins/audit/agents/testing.md +561 -0
  115. package/content/plugins/audit/agents/ui-validator.md +344 -0
  116. package/content/plugins/audit/plugin.yaml +186 -5
  117. package/content/plugins/audit/skills/agileflow-audit/SKILL.md +113 -0
  118. package/content/plugins/audit/skills/agileflow-audit/references/audit-depth-guide.md +151 -0
  119. package/content/plugins/audit/skills/agileflow-audit/references/dependency-risk-guide.md +139 -0
  120. package/content/plugins/audit/skills/agileflow-audit/references/owasp-top10.md +120 -0
  121. package/content/plugins/audit/skills/agileflow-audit/references/performance-budget-guide.md +143 -0
  122. package/content/plugins/audit/skills/agileflow-audit/references/wcag-criteria.md +117 -0
  123. package/content/plugins/audit/skills/agileflow-audit/workflows/run-audit.md +52 -0
  124. package/content/plugins/audit/skills/agileflow-audit/workflows/tdd.md +66 -0
  125. package/content/plugins/core/agents/adr-writer.md +521 -0
  126. package/content/plugins/core/agents/epic-planner.md +520 -0
  127. package/content/plugins/core/agents/mentor.md +709 -0
  128. package/content/plugins/core/agents/orchestrator.md +776 -0
  129. package/content/plugins/core/agents/team-coordinator.md +334 -0
  130. package/content/plugins/core/agents/team-lead.md +181 -0
  131. package/content/plugins/core/agents/workspace-orchestrator.md +146 -0
  132. package/content/plugins/core/hooks/context-loader.js +31 -4
  133. package/content/plugins/core/hooks/damage-control-bash.js +10 -2
  134. package/content/plugins/core/hooks/damage-control-edit.js +4 -1
  135. package/content/plugins/core/hooks/damage-control-patterns.yaml +1 -1
  136. package/content/plugins/core/hooks/damage-control-write.js +4 -1
  137. package/content/plugins/core/hooks/{pre-compact-state.js → post-compact-state.js} +25 -8
  138. package/content/plugins/core/hooks/preferences-injector.js +352 -0
  139. package/content/plugins/core/plugin.yaml +24 -28
  140. package/content/plugins/core/skills/agileflow-adr/SKILL.md +34 -8
  141. package/content/plugins/core/skills/agileflow-adr/references/madr-format-guide.md +86 -0
  142. package/content/plugins/core/skills/agileflow-adr/workflows/write-adr.md +57 -0
  143. package/content/plugins/core/skills/agileflow-babysit-mentor/SKILL.md +94 -27
  144. package/content/plugins/core/skills/agileflow-babysit-mentor/references/mentor-decision-guide.md +81 -0
  145. package/content/plugins/core/skills/agileflow-babysit-mentor/workflows/mentor-session.md +79 -0
  146. package/content/plugins/core/skills/agileflow-epic-planner/SKILL.md +37 -7
  147. package/content/plugins/core/skills/agileflow-epic-planner/references/epic-sizing-guide.md +81 -0
  148. package/content/plugins/core/skills/agileflow-epic-planner/workflows/plan-epic.md +55 -0
  149. package/content/plugins/core/skills/agileflow-status-updater/SKILL.md +36 -20
  150. package/content/plugins/core/skills/agileflow-status-updater/references/status-transitions.md +89 -0
  151. package/content/plugins/core/skills/agileflow-status-updater/workflows/update-status.md +56 -0
  152. package/content/plugins/core/skills/agileflow-story-writer/SKILL.md +39 -114
  153. package/content/plugins/core/skills/agileflow-story-writer/references/estimation-reference.md +36 -0
  154. package/content/plugins/core/skills/agileflow-story-writer/references/story-template.md +92 -0
  155. package/content/plugins/core/skills/agileflow-story-writer/workflows/write-story.md +138 -0
  156. package/content/plugins/council/agents/council-advocate.md +223 -0
  157. package/content/plugins/council/agents/council-analyst.md +278 -0
  158. package/content/plugins/council/agents/council-compounder.md +204 -0
  159. package/content/plugins/council/agents/council-contrarian.md +217 -0
  160. package/content/plugins/council/agents/council-moonshot.md +217 -0
  161. package/content/plugins/council/agents/council-optimist.md +185 -0
  162. package/content/plugins/council/agents/council-revenue.md +200 -0
  163. package/content/plugins/council/agents/council-technical.md +218 -0
  164. package/content/plugins/council/agents/multi-expert.md +334 -0
  165. package/content/plugins/council/plugin.yaml +23 -4
  166. package/content/plugins/council/skills/agileflow-council/SKILL.md +102 -0
  167. package/content/plugins/council/skills/agileflow-council/references/decision-log-template.md +109 -0
  168. package/content/plugins/council/skills/agileflow-council/references/perspective-guide.md +104 -0
  169. package/content/plugins/council/skills/agileflow-council/references/when-to-convene-guide.md +112 -0
  170. package/content/plugins/council/skills/agileflow-council/workflows/convene.md +73 -0
  171. package/content/plugins/council/skills/agileflow-council/workflows/multi-expert.md +75 -0
  172. package/content/plugins/database/plugin.yaml +14 -0
  173. package/content/plugins/database/skills/agileflow-database/SKILL.md +284 -0
  174. package/content/plugins/database/skills/agileflow-database/references/indexing-guide.md +313 -0
  175. package/content/plugins/database/skills/agileflow-database/references/migration-guide.md +328 -0
  176. package/content/plugins/database/skills/agileflow-database/references/schema-design-guide.md +467 -0
  177. package/content/plugins/database/skills/agileflow-database/workflows/design-schema.md +213 -0
  178. package/content/plugins/database/skills/agileflow-database/workflows/optimize-query.md +253 -0
  179. package/content/plugins/debugging/plugin.yaml +14 -0
  180. package/content/plugins/debugging/skills/agileflow-debug/SKILL.md +236 -0
  181. package/content/plugins/debugging/skills/agileflow-debug/references/common-patterns.md +350 -0
  182. package/content/plugins/debugging/skills/agileflow-debug/references/debugging-strategies.md +328 -0
  183. package/content/plugins/debugging/skills/agileflow-debug/workflows/debug-issue.md +187 -0
  184. package/content/plugins/debugging/skills/agileflow-debug/workflows/reproduce-bug.md +194 -0
  185. package/content/plugins/delivery/agents/ci.md +547 -0
  186. package/content/plugins/delivery/agents/devops.md +789 -0
  187. package/content/plugins/delivery/plugin.yaml +19 -0
  188. package/content/plugins/delivery/skills/agileflow-delivery/SKILL.md +111 -0
  189. package/content/plugins/delivery/skills/agileflow-delivery/references/changelog-format-guide.md +133 -0
  190. package/content/plugins/delivery/skills/agileflow-delivery/references/ci-pipeline-guide.md +158 -0
  191. package/content/plugins/delivery/skills/agileflow-delivery/references/pr-checklist-guide.md +133 -0
  192. package/content/plugins/delivery/skills/agileflow-delivery/references/release-checklist.md +142 -0
  193. package/content/plugins/delivery/skills/agileflow-delivery/workflows/changelog.md +72 -0
  194. package/content/plugins/delivery/skills/agileflow-delivery/workflows/deploy.md +74 -0
  195. package/content/plugins/delivery/skills/agileflow-delivery/workflows/pr.md +75 -0
  196. package/content/plugins/docs/agents/documentation.md +544 -0
  197. package/content/plugins/docs/agents/readme-updater.md +640 -0
  198. package/content/plugins/docs/plugin.yaml +19 -0
  199. package/content/plugins/docs/skills/agileflow-docs/SKILL.md +106 -0
  200. package/content/plugins/docs/skills/agileflow-docs/references/api-doc-template.md +167 -0
  201. package/content/plugins/docs/skills/agileflow-docs/references/doc-types-guide.md +141 -0
  202. package/content/plugins/docs/skills/agileflow-docs/references/readme-template.md +156 -0
  203. package/content/plugins/docs/skills/agileflow-docs/workflows/readme-sync.md +57 -0
  204. package/content/plugins/docs/skills/agileflow-docs/workflows/sync.md +64 -0
  205. package/content/plugins/engineering/agents/api.md +718 -0
  206. package/content/plugins/engineering/agents/codebase-query.md +285 -0
  207. package/content/plugins/engineering/agents/compliance.md +559 -0
  208. package/content/plugins/engineering/agents/database.md +644 -0
  209. package/content/plugins/engineering/agents/integrations.md +644 -0
  210. package/content/plugins/engineering/agents/mobile.md +552 -0
  211. package/content/plugins/engineering/agents/monitoring.md +585 -0
  212. package/content/plugins/engineering/agents/performance.md +529 -0
  213. package/content/plugins/engineering/agents/refactor.md +592 -0
  214. package/content/plugins/engineering/agents/security.md +524 -0
  215. package/content/plugins/engineering/agents/ui.md +1336 -0
  216. package/content/plugins/engineering/plugin.yaml +37 -0
  217. package/content/plugins/engineering/skills/agileflow-engineering/SKILL.md +127 -0
  218. package/content/plugins/engineering/skills/agileflow-engineering/references/code-review-guide.md +126 -0
  219. package/content/plugins/engineering/skills/agileflow-engineering/references/domain-routing-guide.md +89 -0
  220. package/content/plugins/engineering/skills/agileflow-engineering/references/refactoring-guide.md +136 -0
  221. package/content/plugins/engineering/skills/agileflow-engineering/workflows/diagnose.md +63 -0
  222. package/content/plugins/engineering/skills/agileflow-engineering/workflows/impact.md +60 -0
  223. package/content/plugins/ideation/agents/brainstorm-analyzer-features.md +179 -0
  224. package/content/plugins/ideation/agents/brainstorm-analyzer-growth.md +169 -0
  225. package/content/plugins/ideation/agents/brainstorm-analyzer-integration.md +181 -0
  226. package/content/plugins/ideation/agents/brainstorm-analyzer-market.md +150 -0
  227. package/content/plugins/ideation/agents/brainstorm-analyzer-ux.md +180 -0
  228. package/content/plugins/ideation/agents/brainstorm-consensus.md +245 -0
  229. package/content/plugins/ideation/agents/design.md +568 -0
  230. package/content/plugins/ideation/agents/product.md +582 -0
  231. package/content/plugins/ideation/plugin.yaml +31 -0
  232. package/content/plugins/ideation/skills/agileflow-ideation/SKILL.md +109 -0
  233. package/content/plugins/ideation/skills/agileflow-ideation/references/brainstorm-techniques.md +138 -0
  234. package/content/plugins/ideation/skills/agileflow-ideation/references/competitive-analysis-template.md +148 -0
  235. package/content/plugins/ideation/skills/agileflow-ideation/references/feature-prioritization-guide.md +147 -0
  236. package/content/plugins/ideation/skills/agileflow-ideation/references/user-story-patterns.md +152 -0
  237. package/content/plugins/ideation/skills/agileflow-ideation/workflows/features.md +65 -0
  238. package/content/plugins/ideation/skills/agileflow-ideation/workflows/ideate.md +54 -0
  239. package/content/plugins/migration/agents/datamigration.md +757 -0
  240. package/content/plugins/migration/plugin.yaml +17 -0
  241. package/content/plugins/migration/skills/agileflow-migration/SKILL.md +106 -0
  242. package/content/plugins/migration/skills/agileflow-migration/references/data-validation-checklist.md +154 -0
  243. package/content/plugins/migration/skills/agileflow-migration/references/migration-patterns.md +209 -0
  244. package/content/plugins/migration/skills/agileflow-migration/references/rollback-playbook.md +171 -0
  245. package/content/plugins/migration/skills/agileflow-migration/references/version-compatibility-matrix.md +155 -0
  246. package/content/plugins/migration/skills/agileflow-migration/workflows/plan.md +73 -0
  247. package/content/plugins/migration/skills/agileflow-migration/workflows/validate.md +71 -0
  248. package/content/plugins/performance/plugin.yaml +14 -0
  249. package/content/plugins/performance/skills/agileflow-performance/SKILL.md +224 -0
  250. package/content/plugins/performance/skills/agileflow-performance/references/optimization-patterns.md +554 -0
  251. package/content/plugins/performance/skills/agileflow-performance/references/profiling-guide.md +383 -0
  252. package/content/plugins/performance/skills/agileflow-performance/references/web-vitals-guide.md +360 -0
  253. package/content/plugins/performance/skills/agileflow-performance/workflows/improve-web-vitals.md +344 -0
  254. package/content/plugins/performance/skills/agileflow-performance/workflows/profile-and-fix.md +254 -0
  255. package/content/plugins/planning/agents/analytics.md +670 -0
  256. package/content/plugins/planning/agents/rlm-subcore.md +215 -0
  257. package/content/plugins/planning/plugin.yaml +19 -0
  258. package/content/plugins/planning/skills/agileflow-planning/SKILL.md +111 -0
  259. package/content/plugins/planning/skills/agileflow-planning/references/estimation-guide.md +114 -0
  260. package/content/plugins/planning/skills/agileflow-planning/references/rpi-workflow.md +119 -0
  261. package/content/plugins/planning/skills/agileflow-planning/references/sprint-planning-guide.md +145 -0
  262. package/content/plugins/planning/skills/agileflow-planning/workflows/impact.md +63 -0
  263. package/content/plugins/planning/skills/agileflow-planning/workflows/rpi.md +104 -0
  264. package/content/plugins/psychology/plugin.yaml +14 -0
  265. package/content/plugins/psychology/skills/agileflow-retention/SKILL.md +252 -0
  266. package/content/plugins/psychology/skills/agileflow-retention/references/competitor-analysis.md +240 -0
  267. package/content/plugins/psychology/skills/agileflow-retention/references/psychology-models.md +349 -0
  268. package/content/plugins/psychology/skills/agileflow-retention/references/retention-patterns.md +279 -0
  269. package/content/plugins/psychology/skills/agileflow-retention/workflows/design-retention-feature.md +287 -0
  270. package/content/plugins/psychology/skills/agileflow-retention/workflows/retention-audit.md +259 -0
  271. package/content/plugins/refactoring/plugin.yaml +14 -0
  272. package/content/plugins/refactoring/skills/agileflow-refactor/SKILL.md +235 -0
  273. package/content/plugins/refactoring/skills/agileflow-refactor/references/refactoring-patterns.md +405 -0
  274. package/content/plugins/refactoring/skills/agileflow-refactor/references/safety-checks.md +177 -0
  275. package/content/plugins/refactoring/skills/agileflow-refactor/workflows/extract-module.md +226 -0
  276. package/content/plugins/refactoring/skills/agileflow-refactor/workflows/safe-refactor.md +169 -0
  277. package/content/plugins/research/agents/research.md +503 -0
  278. package/content/plugins/research/plugin.yaml +17 -0
  279. package/content/plugins/research/skills/agileflow-research/SKILL.md +110 -0
  280. package/content/plugins/research/skills/agileflow-research/references/knowledge-decay-guide.md +121 -0
  281. package/content/plugins/research/skills/agileflow-research/references/research-prompt-guide.md +141 -0
  282. package/content/plugins/research/skills/agileflow-research/references/synthesis-template.md +154 -0
  283. package/content/plugins/research/skills/agileflow-research/workflows/analyze.md +60 -0
  284. package/content/plugins/research/skills/agileflow-research/workflows/ask.md +64 -0
  285. package/content/plugins/research/skills/agileflow-research/workflows/import.md +66 -0
  286. package/content/plugins/research/skills/agileflow-research/workflows/synthesize.md +66 -0
  287. package/content/plugins/reviews/plugin.yaml +14 -0
  288. package/content/plugins/reviews/skills/agileflow-pr-reviewer/SKILL.md +241 -0
  289. package/content/plugins/reviews/skills/agileflow-pr-reviewer/references/review-checklist.md +200 -0
  290. package/content/plugins/reviews/skills/agileflow-pr-reviewer/references/security-patterns.md +328 -0
  291. package/content/plugins/reviews/skills/agileflow-pr-reviewer/workflows/review-pr.md +153 -0
  292. package/content/plugins/reviews/skills/agileflow-pr-reviewer/workflows/security-review.md +177 -0
  293. package/content/plugins/seo/agents/seo-analyzer-content.md +169 -0
  294. package/content/plugins/seo/agents/seo-analyzer-images.md +198 -0
  295. package/content/plugins/seo/agents/seo-analyzer-performance.md +217 -0
  296. package/content/plugins/seo/agents/seo-analyzer-schema.md +184 -0
  297. package/content/plugins/seo/agents/seo-analyzer-sitemap.md +177 -0
  298. package/content/plugins/seo/agents/seo-analyzer-technical.md +151 -0
  299. package/content/plugins/seo/agents/seo-consensus.md +304 -0
  300. package/content/plugins/seo/plugin.yaml +19 -4
  301. package/content/plugins/seo/skills/agileflow-seo/SKILL.md +188 -0
  302. package/content/plugins/seo/skills/agileflow-seo/references/cwv-thresholds.md +110 -0
  303. package/content/plugins/seo/skills/agileflow-seo/references/eeat-framework.md +144 -0
  304. package/content/plugins/seo/skills/agileflow-seo/references/keyword-research-guide.md +125 -0
  305. package/content/plugins/seo/skills/agileflow-seo/references/schema-types.md +139 -0
  306. package/content/plugins/seo/skills/agileflow-seo/references/technical-seo-checklist.md +139 -0
  307. package/content/plugins/seo/skills/agileflow-seo/workflows/audit.md +98 -0
  308. package/content/plugins/seo/skills/agileflow-seo/workflows/page.md +118 -0
  309. package/content/plugins/testing/plugin.yaml +16 -0
  310. package/content/plugins/testing/skills/agileflow-test-writer/SKILL.md +260 -0
  311. package/content/plugins/testing/skills/agileflow-test-writer/references/coverage-targets.md +239 -0
  312. package/content/plugins/testing/skills/agileflow-test-writer/references/test-patterns.md +420 -0
  313. package/content/plugins/testing/skills/agileflow-test-writer/workflows/add-coverage.md +154 -0
  314. package/content/plugins/testing/skills/agileflow-test-writer/workflows/write-tests-from-ac.md +225 -0
  315. package/package.json +2 -2
  316. package/src/cli/commands/doctor.js +818 -30
  317. package/src/cli/commands/hook.js +17 -14
  318. package/src/cli/commands/launch.js +1454 -0
  319. package/src/cli/commands/learn.js +149 -0
  320. package/src/cli/commands/plugins.js +113 -0
  321. package/src/cli/commands/setup.js +455 -110
  322. package/src/cli/commands/skills.js +324 -0
  323. package/src/cli/commands/status.js +8 -10
  324. package/src/cli/commands/update.js +76 -15
  325. package/src/cli/index.js +90 -26
  326. package/src/cli/wizard/babysit-mode-picker.js +192 -0
  327. package/src/cli/wizard/behaviors-picker.js +208 -54
  328. package/src/cli/wizard/ide-picker.js +40 -28
  329. package/src/cli/wizard/install-scope-picker.js +57 -0
  330. package/src/cli/wizard/launch-alias-picker.js +50 -0
  331. package/src/cli/wizard/launch-cli-picker.js +129 -0
  332. package/src/cli/wizard/launch-tmux-picker.js +133 -0
  333. package/src/cli/wizard/learnings-picker.js +40 -0
  334. package/src/cli/wizard/plugin-picker.js +47 -16
  335. package/src/lib/brand.js +116 -0
  336. package/src/lib/errors.js +120 -0
  337. package/src/lib/path-check.js +39 -0
  338. package/src/runtime/config/defaults.js +22 -17
  339. package/src/runtime/config/loader.js +77 -8
  340. package/src/runtime/config/schema.json +43 -16
  341. package/src/runtime/config/writer.js +3 -1
  342. package/src/runtime/ide/babysit-skill.js +202 -0
  343. package/src/runtime/ide/capabilities.js +84 -29
  344. package/src/runtime/ide/claude-code-content.js +177 -0
  345. package/src/runtime/ide/claude-code-settings.js +67 -29
  346. package/src/runtime/ide/claude-code-skills.js +47 -32
  347. package/src/runtime/ide/codex-config.js +295 -0
  348. package/src/runtime/installer/install.js +252 -24
  349. package/src/runtime/launch/alias-installer.js +191 -0
  350. package/src/runtime/launch/cli-resume.js +244 -0
  351. package/src/runtime/launch/closed-windows.js +338 -0
  352. package/src/runtime/launch/defaults.js +66 -0
  353. package/src/runtime/launch/detect-clis.js +69 -0
  354. package/src/runtime/launch/doctor.js +464 -0
  355. package/src/runtime/launch/exec-wrapper.js +114 -0
  356. package/src/runtime/launch/parallel-session.js +247 -0
  357. package/src/runtime/launch/prefs.js +211 -0
  358. package/src/runtime/launch/project-prefs.js +234 -0
  359. package/src/runtime/launch/resolve-cli.js +56 -0
  360. package/src/runtime/launch/restore.js +152 -0
  361. package/src/runtime/launch/schema.json +75 -0
  362. package/src/runtime/launch/session-lifecycle.js +313 -0
  363. package/src/runtime/launch/session-registry.js +401 -0
  364. package/src/runtime/launch/spawn.js +103 -0
  365. package/src/runtime/launch/tabs.js +350 -0
  366. package/src/runtime/launch/tmux.js +764 -0
  367. package/src/runtime/launch/worktree.js +260 -0
  368. package/src/runtime/plugins/registry.js +16 -11
  369. package/src/runtime/plugins/validator.js +57 -43
  370. package/src/runtime/skills/learnings.js +308 -0
  371. package/content/plugins/core/hooks/babysit-mentor-injector.js +0 -55
  372. package/src/cli/wizard/personalization.js +0 -64
@@ -0,0 +1,244 @@
1
+ /**
2
+ * Per-CLI resume strategy table.
3
+ *
4
+ * Each entry tells the __exec wrapper:
5
+ * - `resumeArgs(uuid)` — argv to append for "resume this conversation"
6
+ * - `captureUuid(cwd, opts)` — after the CLI exits, return the UUID of the
7
+ * newest conversation associated with this cwd
8
+ * so we can store it back in the registry
9
+ *
10
+ * Strategies covered:
11
+ * - claude: UUID-based; conversations are jsonl files under
12
+ * `~/.claude/projects/<encoded-cwd>/`. Mirrors v3
13
+ * `claude-smart.sh`.
14
+ * - codex: `codex resume --last` resumes the most-recent
15
+ * session. Codex doesn't (yet) take a UUID positionally
16
+ * in a stable way per-cwd, so MVP uses `--last`. Better:
17
+ * parse jsonl files under ~/.codex/sessions/ and target by id (deferred).
18
+ * - cursor-agent: no published resume convention. Restart fresh.
19
+ * - aider: auto-restores from `.aider.chat.history.md` in cwd.
20
+ * No flag needed.
21
+ *
22
+ * All filesystem reads are injectable via `opts.fs` for tests.
23
+ */
24
+ const fs = require("fs");
25
+ const path = require("path");
26
+ const os = require("os");
27
+
28
+ /**
29
+ * Encode a cwd into Claude's project directory naming convention.
30
+ * Claude stores conversations under `~/.claude/projects/<encoded>/`
31
+ * where `<encoded>` is the absolute path with `/` replaced by `-`
32
+ * (and a leading `-` for the root).
33
+ *
34
+ * @param {string} cwd
35
+ * @returns {string}
36
+ */
37
+ function encodeClaudeProjectDir(cwd) {
38
+ // Normalize backslashes to forward slashes first so Windows paths
39
+ // (`C:\Users\me\app`) and POSIX paths (`/home/me/app`) hit the same
40
+ // encoding path. Then strip leading slashes and convert any remaining
41
+ // separator to `-`. Claude itself produces names like
42
+ // `-home-user-myproject` for `/home/user/myproject`.
43
+ const slashed = cwd.replace(/\\/g, "/");
44
+ const normalized = slashed.replace(/^\/+/, "");
45
+ return "-" + normalized.replace(/\//g, "-");
46
+ }
47
+
48
+ /**
49
+ * Find the newest non-agent .jsonl file in a Claude project directory
50
+ * and return its UUID (filename minus `.jsonl`). Returns null when no
51
+ * conversation has been recorded yet.
52
+ *
53
+ * @param {string} cwd
54
+ * @param {{
55
+ * home?: string,
56
+ * readdirSync?: typeof fs.readdirSync,
57
+ * statSync?: typeof fs.statSync,
58
+ * }} [opts]
59
+ * @returns {string | null}
60
+ */
61
+ function captureClaudeUuid(cwd, opts = {}) {
62
+ const home = opts.home || os.homedir();
63
+ const readdirSync = opts.readdirSync || fs.readdirSync;
64
+ const statSync = opts.statSync || fs.statSync;
65
+ const projectDir = path.join(
66
+ home,
67
+ ".claude",
68
+ "projects",
69
+ encodeClaudeProjectDir(cwd),
70
+ );
71
+ /** @type {string[]} */
72
+ let entries;
73
+ try {
74
+ entries = readdirSync(projectDir);
75
+ } catch {
76
+ return null;
77
+ }
78
+ let bestUuid = null;
79
+ let bestMtime = -Infinity;
80
+ for (const entry of entries) {
81
+ if (!entry.endsWith(".jsonl")) continue;
82
+ // Skip agent transcripts — those are sub-conversations spawned by
83
+ // a parent claude session, not the main conversation we want to
84
+ // resume. v3 used the same `agent-` prefix filter.
85
+ if (entry.startsWith("agent-")) continue;
86
+ const full = path.join(projectDir, entry);
87
+ let stat;
88
+ try {
89
+ stat = statSync(full);
90
+ } catch {
91
+ continue;
92
+ }
93
+ const mtime = stat.mtimeMs || 0;
94
+ if (mtime > bestMtime) {
95
+ bestMtime = mtime;
96
+ bestUuid = entry.slice(0, -".jsonl".length);
97
+ }
98
+ }
99
+ return bestUuid;
100
+ }
101
+
102
+ /**
103
+ * Find the newest codex session whose first-line `payload.cwd` matches
104
+ * the given working directory.
105
+ *
106
+ * Codex stores sessions under
107
+ * `~/.codex/sessions/<YYYY>/<MM>/<DD>/rollout-<timestamp>-<UUID>.jsonl`.
108
+ * The first JSONL line is a `session_meta` record containing
109
+ * `payload.cwd` and `payload.id`. Walking that tree once per launch
110
+ * isn't free, but it's still a few dozen files even for active users
111
+ * and only runs after a session exits — so the cost is amortized.
112
+ *
113
+ * @param {string} cwd
114
+ * @param {{
115
+ * home?: string,
116
+ * readdirSync?: typeof fs.readdirSync,
117
+ * statSync?: typeof fs.statSync,
118
+ * readFileSync?: typeof fs.readFileSync,
119
+ * }} [opts]
120
+ * @returns {string | null}
121
+ */
122
+ function captureCodexUuid(cwd, opts = {}) {
123
+ const home = opts.home || os.homedir();
124
+ const readdirSync = opts.readdirSync || fs.readdirSync;
125
+ const statSync = opts.statSync || fs.statSync;
126
+ const readFileSync = opts.readFileSync || fs.readFileSync;
127
+
128
+ const sessionsRoot = path.join(home, ".codex", "sessions");
129
+ /** @type {string[]} */
130
+ const jsonlFiles = [];
131
+
132
+ // Recurse year → month → day → files. Tree depth is fixed at 3.
133
+ /** @param {string} dir */
134
+ function collect(dir) {
135
+ let entries;
136
+ try {
137
+ entries = readdirSync(dir, { withFileTypes: true });
138
+ } catch {
139
+ return;
140
+ }
141
+ for (const ent of entries) {
142
+ const full = path.join(dir, ent.name);
143
+ if (ent.isDirectory()) {
144
+ collect(full);
145
+ } else if (ent.isFile() && ent.name.endsWith(".jsonl")) {
146
+ jsonlFiles.push(full);
147
+ }
148
+ }
149
+ }
150
+ collect(sessionsRoot);
151
+
152
+ let bestUuid = null;
153
+ let bestMtime = -Infinity;
154
+ for (const file of jsonlFiles) {
155
+ let stat;
156
+ try {
157
+ stat = statSync(file);
158
+ } catch {
159
+ continue;
160
+ }
161
+ const mtime = typeof stat.mtimeMs === "number" ? stat.mtimeMs : 0;
162
+ if (mtime <= bestMtime) continue;
163
+ // Cheap match: read just the first line.
164
+ let head;
165
+ try {
166
+ head = readFileSync(file, "utf8").split("\n", 1)[0];
167
+ } catch {
168
+ continue;
169
+ }
170
+ let parsed;
171
+ try {
172
+ parsed = JSON.parse(head);
173
+ } catch {
174
+ continue;
175
+ }
176
+ const payload = parsed && parsed.payload;
177
+ if (!payload || typeof payload !== "object") continue;
178
+ if (payload.cwd !== cwd) continue;
179
+ if (typeof payload.id !== "string" || !payload.id) continue;
180
+ bestUuid = payload.id;
181
+ bestMtime = mtime;
182
+ }
183
+ return bestUuid;
184
+ }
185
+
186
+ /**
187
+ * @typedef {Object} ResumeStrategy
188
+ * @property {(uuid: string | null) => string[]} resumeArgs
189
+ * @property {(cwd: string, opts?: any) => string | null} captureUuid
190
+ */
191
+
192
+ /** @type {Record<string, ResumeStrategy>} */
193
+ const RESUME_STRATEGIES = {
194
+ claude: {
195
+ resumeArgs: (uuid) => (uuid ? ["--resume", uuid] : []),
196
+ captureUuid: captureClaudeUuid,
197
+ },
198
+ codex: {
199
+ // With a stored UUID we resume that specific session, which is
200
+ // critical when the user has multiple parallel codex sessions
201
+ // across different cwds — `resume --last` would pick whichever
202
+ // they touched most recently, not the one tied to THIS session.
203
+ // Without a UUID (first launch in a cwd, or capture failed) we
204
+ // fall back to `--last`.
205
+ resumeArgs: (uuid) => {
206
+ if (uuid) return ["resume", uuid];
207
+ return ["resume", "--last"];
208
+ },
209
+ captureUuid: captureCodexUuid,
210
+ },
211
+ "cursor-agent": {
212
+ resumeArgs: () => [],
213
+ captureUuid: () => null,
214
+ },
215
+ aider: {
216
+ // aider auto-restores the cwd's chat history from
217
+ // `.aider.chat.history.md` on every invocation. No flag needed.
218
+ resumeArgs: () => [],
219
+ captureUuid: () => null,
220
+ },
221
+ };
222
+
223
+ /**
224
+ * Pick a strategy by CLI id; unknown CLIs get the "spawn fresh" no-op.
225
+ *
226
+ * @param {string} cli
227
+ * @returns {ResumeStrategy}
228
+ */
229
+ function getResumeStrategy(cli) {
230
+ return (
231
+ RESUME_STRATEGIES[cli] || {
232
+ resumeArgs: () => [],
233
+ captureUuid: () => null,
234
+ }
235
+ );
236
+ }
237
+
238
+ module.exports = {
239
+ RESUME_STRATEGIES,
240
+ getResumeStrategy,
241
+ captureClaudeUuid,
242
+ captureCodexUuid,
243
+ encodeClaudeProjectDir,
244
+ };
@@ -0,0 +1,338 @@
1
+ /**
2
+ * Closed-window FIFO log for `agileflow launch`.
3
+ *
4
+ * Backs the `Alt+T → reopen last closed tab` keybind. When the user
5
+ * closes a window via `Alt+w`, the `__close-window` subcommand
6
+ * captures `#W` (name) + `#{pane_current_path}` (cwd) and pushes them
7
+ * here BEFORE issuing `kill-window`. `__restore-window` pops the most
8
+ * recent entry and runs `new-window -c <cwd> -n <name>`.
9
+ *
10
+ * On-disk shape (`~/.agileflow/launch-closed-windows.json`):
11
+ * {
12
+ * "version": 1,
13
+ * "sessions": {
14
+ * "claude-myapp": [
15
+ * { "id": "ab12cd", "name": "src", "cwd": "/...", "closedAt": "..." }
16
+ * ]
17
+ * }
18
+ * }
19
+ *
20
+ * Per-session stacks are isolated so closing a tab in session A
21
+ * doesn't pollute session B's restore history. Each stack is capped
22
+ * at MAX_PER_SESSION entries (oldest evicted on push).
23
+ *
24
+ * Concurrency: same O_EXCL lock pattern as session-registry.js — two
25
+ * sessions running `__close-window` simultaneously won't lose each
26
+ * other's entries.
27
+ */
28
+ const fs = require("fs");
29
+ const os = require("os");
30
+ const path = require("path");
31
+ const crypto = require("crypto");
32
+
33
+ const FILENAME = "launch-closed-windows.json";
34
+ const LOCK_SUFFIX = ".lock";
35
+ const LOCK_STALE_MS = 5000;
36
+ const LOCK_MAX_ATTEMPTS = 100;
37
+ const LOCK_RETRY_MS = 10;
38
+ const MAX_PER_SESSION = 20;
39
+
40
+ /**
41
+ * @typedef {Object} ClosedEntry
42
+ * @property {string} id - short random id for log/debug, not used for lookup
43
+ * @property {string} name - tmux window name (#W) at close time
44
+ * @property {string} cwd - pane's working directory at close time
45
+ * @property {string} closedAt - ISO timestamp
46
+ *
47
+ * @typedef {Object} ClosedLogShape
48
+ * @property {1} version
49
+ * @property {Record<string, ClosedEntry[]>} sessions
50
+ */
51
+
52
+ /** @param {number} ms */
53
+ function busyWait(ms) {
54
+ const target = Date.now() + ms;
55
+ while (Date.now() < target) {
56
+ /* spin */
57
+ }
58
+ }
59
+
60
+ /**
61
+ * @param {string} [home]
62
+ * @returns {string}
63
+ */
64
+ function logPath(home) {
65
+ return path.join(home || os.homedir(), ".agileflow", FILENAME);
66
+ }
67
+
68
+ /** @returns {ClosedLogShape} */
69
+ function emptyLog() {
70
+ return { version: 1, sessions: {} };
71
+ }
72
+
73
+ /**
74
+ * O_EXCL lock around `fn`. Same retry / stale-takeover policy as
75
+ * session-registry's withRegistryLock. Lock file lives next to the
76
+ * log file with a `.lock` suffix so the two registries' locks don't
77
+ * collide.
78
+ *
79
+ * @template T
80
+ * @param {string | undefined} home
81
+ * @param {() => T} fn
82
+ * @returns {T}
83
+ */
84
+ function withLock(home, fn) {
85
+ const lockFile = logPath(home) + LOCK_SUFFIX;
86
+ fs.mkdirSync(path.dirname(lockFile), { recursive: true });
87
+ /** @type {number | null} */
88
+ let lockFd = null;
89
+ for (let attempt = 0; attempt < LOCK_MAX_ATTEMPTS; attempt++) {
90
+ try {
91
+ lockFd = fs.openSync(lockFile, "wx");
92
+ break;
93
+ } catch (err) {
94
+ if (!err || err.code !== "EEXIST") throw err;
95
+ try {
96
+ const stat = fs.statSync(lockFile);
97
+ if (Date.now() - (stat.mtimeMs || 0) > LOCK_STALE_MS) {
98
+ try {
99
+ fs.unlinkSync(lockFile);
100
+ } catch {
101
+ /* swallow */
102
+ }
103
+ continue;
104
+ }
105
+ } catch {
106
+ /* lockfile vanished between EEXIST and stat — loop */
107
+ }
108
+ busyWait(LOCK_RETRY_MS);
109
+ }
110
+ }
111
+ if (lockFd === null) {
112
+ throw new Error(
113
+ `could not acquire launch-closed-windows lock after ${LOCK_MAX_ATTEMPTS} attempts`,
114
+ );
115
+ }
116
+ try {
117
+ return fn();
118
+ } finally {
119
+ try {
120
+ fs.closeSync(lockFd);
121
+ } catch {
122
+ /* swallow */
123
+ }
124
+ try {
125
+ fs.unlinkSync(lockFile);
126
+ } catch {
127
+ /* swallow */
128
+ }
129
+ }
130
+ }
131
+
132
+ /**
133
+ * Read the log, forgiving on any I/O or JSON failure (same posture as
134
+ * session-registry). Malformed file = empty log; the user shouldn't be
135
+ * blocked from closing or restoring tabs because of corruption.
136
+ *
137
+ * @param {string} [home]
138
+ * @returns {ClosedLogShape}
139
+ */
140
+ function loadLog(home) {
141
+ const file = logPath(home);
142
+ let raw;
143
+ try {
144
+ raw = fs.readFileSync(file, "utf8");
145
+ } catch (err) {
146
+ if (err && err.code === "ENOENT") return emptyLog();
147
+ return emptyLog();
148
+ }
149
+ let parsed;
150
+ try {
151
+ parsed = JSON.parse(raw);
152
+ } catch {
153
+ return emptyLog();
154
+ }
155
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
156
+ return emptyLog();
157
+ }
158
+ const sessions =
159
+ parsed.sessions && typeof parsed.sessions === "object"
160
+ ? parsed.sessions
161
+ : {};
162
+ /** @type {Record<string, ClosedEntry[]>} */
163
+ const sane = {};
164
+ for (const [sessionName, list] of Object.entries(sessions)) {
165
+ if (!Array.isArray(list)) continue;
166
+ /** @type {ClosedEntry[]} */
167
+ const cleaned = [];
168
+ for (const e of list) {
169
+ if (!e || typeof e !== "object") continue;
170
+ if (typeof e.name !== "string") continue;
171
+ if (typeof e.cwd !== "string" || !e.cwd) continue;
172
+ cleaned.push({
173
+ id: typeof e.id === "string" ? e.id : shortId(),
174
+ name: e.name,
175
+ cwd: e.cwd,
176
+ closedAt: typeof e.closedAt === "string" ? e.closedAt : "",
177
+ });
178
+ }
179
+ if (cleaned.length > 0) sane[sessionName] = cleaned;
180
+ }
181
+ return { version: 1, sessions: sane };
182
+ }
183
+
184
+ /**
185
+ * Atomic write via tmp + rename. Mirrors session-registry's pattern.
186
+ *
187
+ * @param {ClosedLogShape} log
188
+ * @param {string} [home]
189
+ * @returns {string}
190
+ */
191
+ function writeLog(log, home) {
192
+ const file = logPath(home);
193
+ const dir = path.dirname(file);
194
+ const tmp = path.join(dir, `.${FILENAME}.tmp-${process.pid}`);
195
+ const content = JSON.stringify(log, null, 2) + "\n";
196
+ fs.mkdirSync(dir, { recursive: true });
197
+ try {
198
+ fs.writeFileSync(tmp, content, "utf8");
199
+ fs.renameSync(tmp, file);
200
+ } catch (err) {
201
+ try {
202
+ fs.unlinkSync(tmp);
203
+ } catch {
204
+ /* swallow */
205
+ }
206
+ throw err;
207
+ }
208
+ return file;
209
+ }
210
+
211
+ /** @returns {string} */
212
+ function shortId() {
213
+ return crypto.randomBytes(3).toString("hex");
214
+ }
215
+
216
+ /**
217
+ * Push a closed window onto the FIFO for `sessionName`. Returns the
218
+ * pushed entry (so callers can log/inspect it). Caps the per-session
219
+ * stack at MAX_PER_SESSION; the oldest entry is evicted when over.
220
+ *
221
+ * @param {{ sessionName: string, name: string, cwd: string }} args
222
+ * @param {string} [home]
223
+ * @returns {ClosedEntry}
224
+ */
225
+ function pushClosed(args, home) {
226
+ if (!args || typeof args !== "object") {
227
+ throw new TypeError("pushClosed: args required");
228
+ }
229
+ if (typeof args.sessionName !== "string" || !args.sessionName) {
230
+ throw new TypeError("pushClosed: sessionName must be a non-empty string");
231
+ }
232
+ if (typeof args.name !== "string") {
233
+ throw new TypeError("pushClosed: name must be a string");
234
+ }
235
+ if (typeof args.cwd !== "string" || !args.cwd) {
236
+ throw new TypeError("pushClosed: cwd must be a non-empty string");
237
+ }
238
+ /** @type {ClosedEntry} */
239
+ const entry = {
240
+ id: shortId(),
241
+ name: args.name,
242
+ cwd: args.cwd,
243
+ closedAt: new Date().toISOString(),
244
+ };
245
+ withLock(home, () => {
246
+ const log = loadLog(home);
247
+ const list = log.sessions[args.sessionName] || [];
248
+ list.push(entry);
249
+ while (list.length > MAX_PER_SESSION) list.shift();
250
+ log.sessions[args.sessionName] = list;
251
+ writeLog(log, home);
252
+ });
253
+ return entry;
254
+ }
255
+
256
+ /**
257
+ * Pop the most recent closed entry for `sessionName`. Returns null
258
+ * when the stack is empty (or the session never had any). Done under
259
+ * the lock so two concurrent `__restore-window` processes don't both
260
+ * resurrect the same entry.
261
+ *
262
+ * @param {string} sessionName
263
+ * @param {string} [home]
264
+ * @returns {ClosedEntry | null}
265
+ */
266
+ function popClosed(sessionName, home) {
267
+ if (typeof sessionName !== "string" || !sessionName) return null;
268
+ return withLock(home, () => {
269
+ const log = loadLog(home);
270
+ const list = log.sessions[sessionName];
271
+ if (!list || list.length === 0) return null;
272
+ const entry = list.pop();
273
+ if (list.length === 0) delete log.sessions[sessionName];
274
+ else log.sessions[sessionName] = list;
275
+ writeLog(log, home);
276
+ return entry || null;
277
+ });
278
+ }
279
+
280
+ /**
281
+ * Look at the most recent entry without removing it. Cheap read —
282
+ * no lock taken; readers tolerate a brief inconsistency window with
283
+ * concurrent writers.
284
+ *
285
+ * @param {string} sessionName
286
+ * @param {string} [home]
287
+ * @returns {ClosedEntry | null}
288
+ */
289
+ function peekClosed(sessionName, home) {
290
+ if (typeof sessionName !== "string" || !sessionName) return null;
291
+ const log = loadLog(home);
292
+ const list = log.sessions[sessionName];
293
+ if (!list || list.length === 0) return null;
294
+ return list[list.length - 1];
295
+ }
296
+
297
+ /**
298
+ * Sweep entries older than `maxAgeMs` across all sessions. Returns the
299
+ * number of entries removed. Intended for a future doctor/prune
300
+ * integration; safe to call from anywhere.
301
+ *
302
+ * @param {number} maxAgeMs
303
+ * @param {string} [home]
304
+ * @returns {number}
305
+ */
306
+ function clearOlderThan(maxAgeMs, home) {
307
+ if (typeof maxAgeMs !== "number" || maxAgeMs < 0) return 0;
308
+ return withLock(home, () => {
309
+ const log = loadLog(home);
310
+ const cutoff = Date.now() - maxAgeMs;
311
+ let removed = 0;
312
+ for (const [sessionName, list] of Object.entries(log.sessions)) {
313
+ const kept = list.filter((e) => {
314
+ const t = Date.parse(e.closedAt || "");
315
+ if (Number.isNaN(t)) return true; // keep entries with no parseable timestamp
316
+ return t >= cutoff;
317
+ });
318
+ removed += list.length - kept.length;
319
+ if (kept.length === 0) delete log.sessions[sessionName];
320
+ else log.sessions[sessionName] = kept;
321
+ }
322
+ if (removed > 0) writeLog(log, home);
323
+ return removed;
324
+ });
325
+ }
326
+
327
+ module.exports = {
328
+ FILENAME,
329
+ MAX_PER_SESSION,
330
+ logPath,
331
+ emptyLog,
332
+ loadLog,
333
+ writeLog,
334
+ pushClosed,
335
+ popClosed,
336
+ peekClosed,
337
+ clearOlderThan,
338
+ };
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Default preferences for `agileflow launch`.
3
+ *
4
+ * `launch-prefs.json` is the first user-level config in v4 (lives under
5
+ * `~/.agileflow/`). Returned when the file is absent and merged into a
6
+ * partial user file so missing keys take sensible values.
7
+ *
8
+ * @typedef {Object} LaunchCliPrefs
9
+ * @property {string} preferred - CLI to invoke by default
10
+ * @property {string[]} fallbackOrder - order to try if preferred is missing
11
+ *
12
+ * @typedef {Object} LaunchTmuxPrefs
13
+ * @property {boolean} enabled - false skips tmux entirely
14
+ * @property {'top' | 'bottom'} statusPosition - tmux status-position value
15
+ *
16
+ * @typedef {Object} LaunchKeybindPrefs
17
+ * @property {'default' | 'minimal' | 'none'} preset - keybind preset name
18
+ *
19
+ * @typedef {Object} LaunchAliasPref
20
+ * @property {boolean} enabled - install `af` symlink to ~/.local/bin/af
21
+ *
22
+ * @typedef {Object} LaunchAliasesPrefs
23
+ * @property {LaunchAliasPref} af
24
+ *
25
+ * @typedef {Object} LaunchPrefs
26
+ * @property {1} version
27
+ * @property {LaunchCliPrefs} cli
28
+ * @property {LaunchTmuxPrefs} tmux
29
+ * @property {LaunchKeybindPrefs} keybinds
30
+ * @property {LaunchAliasesPrefs} aliases
31
+ * @property {string[]} pinned - reserved for slice 3 (pinning UI)
32
+ * @property {string} [lastUpdated] - ISO timestamp stamped by writePrefs
33
+ */
34
+
35
+ const KNOWN_CLI_IDS = ["claude", "codex", "cursor-agent", "aider"];
36
+ const STATUS_POSITIONS = ["top", "bottom"];
37
+ const KEYBIND_PRESETS = ["default", "minimal", "none"];
38
+
39
+ /** @returns {LaunchPrefs} */
40
+ function defaultPrefs() {
41
+ return {
42
+ version: 1,
43
+ cli: {
44
+ preferred: "claude",
45
+ fallbackOrder: [...KNOWN_CLI_IDS],
46
+ },
47
+ tmux: {
48
+ enabled: true,
49
+ statusPosition: "bottom",
50
+ },
51
+ keybinds: {
52
+ preset: "default",
53
+ },
54
+ aliases: {
55
+ af: { enabled: false },
56
+ },
57
+ pinned: [],
58
+ };
59
+ }
60
+
61
+ module.exports = {
62
+ defaultPrefs,
63
+ KNOWN_CLI_IDS,
64
+ STATUS_POSITIONS,
65
+ KEYBIND_PRESETS,
66
+ };
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Detect which AI CLIs are installed on the user's PATH.
3
+ *
4
+ * `agileflow launch` wraps whichever CLI the user has chosen — but the
5
+ * onboarding picker should only offer options that actually resolve.
6
+ * This module owns the canonical list of known AI CLIs and the routine
7
+ * that filters it against the system.
8
+ *
9
+ * `commandExists` is injectable so tests don't shell out.
10
+ */
11
+ const { commandExists: realCommandExists } = require("../../lib/path-check.js");
12
+
13
+ /**
14
+ * @typedef {Object} CliDescriptor
15
+ * @property {string} id - stable id used in launch-prefs.json
16
+ * @property {string} bin - binary name on PATH
17
+ * @property {string} label - human-readable name for pickers
18
+ * @property {string} hint - one-line description shown in pickers
19
+ */
20
+
21
+ /** @type {CliDescriptor[]} */
22
+ const KNOWN_CLIS = [
23
+ {
24
+ id: "claude",
25
+ bin: "claude",
26
+ label: "Claude Code",
27
+ hint: "Anthropic's official terminal CLI",
28
+ },
29
+ {
30
+ id: "codex",
31
+ bin: "codex",
32
+ label: "OpenAI Codex CLI",
33
+ hint: "OpenAI's terminal coding agent",
34
+ },
35
+ {
36
+ id: "cursor-agent",
37
+ bin: "cursor-agent",
38
+ label: "Cursor Agent",
39
+ hint: "Cursor's standalone CLI agent",
40
+ },
41
+ {
42
+ id: "aider",
43
+ bin: "aider",
44
+ label: "Aider",
45
+ hint: "Open-source pair programming CLI",
46
+ },
47
+ ];
48
+
49
+ /**
50
+ * Return descriptors for CLIs whose binary resolves on PATH.
51
+ *
52
+ * @param {(name: string) => boolean} [exists] - injectable for tests
53
+ * @returns {CliDescriptor[]}
54
+ */
55
+ function availableClis(exists = realCommandExists) {
56
+ return KNOWN_CLIS.filter((c) => exists(c.bin));
57
+ }
58
+
59
+ /**
60
+ * Find a descriptor by id. Returns null if unknown.
61
+ *
62
+ * @param {string} id
63
+ * @returns {CliDescriptor | null}
64
+ */
65
+ function findCli(id) {
66
+ return KNOWN_CLIS.find((c) => c.id === id) || null;
67
+ }
68
+
69
+ module.exports = { KNOWN_CLIS, availableClis, findCli };