prjct-cli 0.11.5 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (391) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/README.md +81 -25
  3. package/bin/dev.js +1 -1
  4. package/bin/generate-views.js +209 -0
  5. package/bin/migrate-to-json.js +742 -0
  6. package/bin/prjct +5 -5
  7. package/bin/serve.js +226 -50
  8. package/core/__tests__/agentic/{memory-system.test.js → memory-system.test.ts} +12 -23
  9. package/core/__tests__/agentic/{plan-mode.test.js → plan-mode.test.ts} +26 -24
  10. package/core/__tests__/agentic/{prompt-builder.test.js → prompt-builder.test.ts} +3 -8
  11. package/core/__tests__/utils/{date-helper.test.js → date-helper.test.ts} +19 -30
  12. package/core/__tests__/utils/{output.test.js → output.test.ts} +12 -24
  13. package/core/agentic/agent-router.ts +137 -0
  14. package/core/agentic/chain-of-thought.ts +228 -0
  15. package/core/agentic/command-executor/command-executor.ts +384 -0
  16. package/core/agentic/command-executor/index.ts +16 -0
  17. package/core/agentic/command-executor/status-signal.ts +38 -0
  18. package/core/agentic/command-executor/types.ts +79 -0
  19. package/core/agentic/command-executor.ts +8 -0
  20. package/core/agentic/{context-builder.js → context-builder.ts} +92 -81
  21. package/core/agentic/context-filter.ts +365 -0
  22. package/core/agentic/ground-truth/index.ts +76 -0
  23. package/core/agentic/ground-truth/types.ts +33 -0
  24. package/core/agentic/ground-truth/utils.ts +48 -0
  25. package/core/agentic/ground-truth/verifiers/analyze.ts +54 -0
  26. package/core/agentic/ground-truth/verifiers/done.ts +75 -0
  27. package/core/agentic/ground-truth/verifiers/feature.ts +70 -0
  28. package/core/agentic/ground-truth/verifiers/index.ts +37 -0
  29. package/core/agentic/ground-truth/verifiers/init.ts +52 -0
  30. package/core/agentic/ground-truth/verifiers/now.ts +57 -0
  31. package/core/agentic/ground-truth/verifiers/ship.ts +85 -0
  32. package/core/agentic/ground-truth/verifiers/spec.ts +45 -0
  33. package/core/agentic/ground-truth/verifiers/sync.ts +47 -0
  34. package/core/agentic/ground-truth/verifiers.ts +6 -0
  35. package/core/agentic/ground-truth.ts +8 -0
  36. package/core/agentic/loop-detector/error-analysis.ts +97 -0
  37. package/core/agentic/loop-detector/hallucination.ts +71 -0
  38. package/core/agentic/loop-detector/index.ts +41 -0
  39. package/core/agentic/loop-detector/loop-detector.ts +222 -0
  40. package/core/agentic/loop-detector/types.ts +66 -0
  41. package/core/agentic/loop-detector.ts +8 -0
  42. package/core/agentic/memory-system/history.ts +53 -0
  43. package/core/agentic/memory-system/index.ts +192 -0
  44. package/core/agentic/memory-system/patterns.ts +156 -0
  45. package/core/agentic/memory-system/semantic-memories.ts +277 -0
  46. package/core/agentic/memory-system/session.ts +21 -0
  47. package/core/agentic/memory-system/types.ts +159 -0
  48. package/core/agentic/memory-system.ts +8 -0
  49. package/core/agentic/parallel-tools.ts +165 -0
  50. package/core/agentic/plan-mode/approval.ts +57 -0
  51. package/core/agentic/plan-mode/constants.ts +44 -0
  52. package/core/agentic/plan-mode/index.ts +28 -0
  53. package/core/agentic/plan-mode/plan-mode.ts +406 -0
  54. package/core/agentic/plan-mode/types.ts +193 -0
  55. package/core/agentic/plan-mode.ts +8 -0
  56. package/core/agentic/prompt-builder.ts +566 -0
  57. package/core/agentic/response-templates.ts +164 -0
  58. package/core/agentic/semantic-compression.ts +273 -0
  59. package/core/agentic/services.ts +206 -0
  60. package/core/agentic/smart-context.ts +476 -0
  61. package/core/agentic/{template-loader.js → template-loader.ts} +27 -16
  62. package/core/agentic/think-blocks.ts +202 -0
  63. package/core/agentic/tool-registry.ts +119 -0
  64. package/core/agentic/validation-rules.ts +313 -0
  65. package/core/agents/index.ts +28 -0
  66. package/core/agents/performance.ts +444 -0
  67. package/core/agents/types.ts +126 -0
  68. package/core/bus/{index.js → index.ts} +57 -61
  69. package/core/command-registry/categories.ts +23 -0
  70. package/core/command-registry/commands.ts +15 -0
  71. package/core/command-registry/core-commands.ts +319 -0
  72. package/core/command-registry/index.ts +158 -0
  73. package/core/command-registry/optional-commands.ts +119 -0
  74. package/core/command-registry/setup-commands.ts +53 -0
  75. package/core/command-registry/types.ts +59 -0
  76. package/core/command-registry.ts +9 -0
  77. package/core/commands/analysis.ts +298 -0
  78. package/core/commands/analytics.ts +288 -0
  79. package/core/commands/base.ts +273 -0
  80. package/core/commands/index.ts +211 -0
  81. package/core/commands/maintenance.ts +226 -0
  82. package/core/commands/planning.ts +311 -0
  83. package/core/commands/setup.ts +309 -0
  84. package/core/commands/shipping.ts +188 -0
  85. package/core/commands/types.ts +183 -0
  86. package/core/commands/workflow.ts +226 -0
  87. package/core/commands.ts +11 -0
  88. package/core/constants/formats.ts +187 -0
  89. package/core/constants/index.ts +7 -0
  90. package/core/{context-sync.js → context-sync.ts} +59 -26
  91. package/core/data/agents-manager.ts +76 -0
  92. package/core/data/analysis-manager.ts +83 -0
  93. package/core/data/base-manager.ts +156 -0
  94. package/core/data/ideas-manager.ts +81 -0
  95. package/core/data/index.ts +32 -0
  96. package/core/data/outcomes-manager.ts +96 -0
  97. package/core/data/project-manager.ts +75 -0
  98. package/core/data/roadmap-manager.ts +118 -0
  99. package/core/data/shipped-manager.ts +65 -0
  100. package/core/data/state-manager.ts +214 -0
  101. package/core/domain/{agent-generator.js → agent-generator.ts} +77 -57
  102. package/core/domain/{agent-loader.js → agent-loader.ts} +65 -56
  103. package/core/domain/{agent-matcher.js → agent-matcher.ts} +51 -24
  104. package/core/domain/{agent-validator.js → agent-validator.ts} +70 -37
  105. package/core/domain/{analyzer.js → analyzer.ts} +91 -85
  106. package/core/domain/{architect-session.js → architect-session.ts} +49 -34
  107. package/core/domain/{architecture-generator.js → architecture-generator.ts} +25 -13
  108. package/core/domain/{context-estimator.js → context-estimator.ts} +57 -36
  109. package/core/domain/{product-standards.js → product-standards.ts} +40 -26
  110. package/core/domain/{smart-cache.js → smart-cache.ts} +39 -30
  111. package/core/domain/{snapshot-manager.js → snapshot-manager.ts} +103 -100
  112. package/core/domain/{task-analyzer.js → task-analyzer.ts} +82 -43
  113. package/core/domain/task-stack/index.ts +19 -0
  114. package/core/domain/task-stack/parser.ts +86 -0
  115. package/core/domain/task-stack/storage.ts +123 -0
  116. package/core/domain/task-stack/task-stack.ts +340 -0
  117. package/core/domain/task-stack/types.ts +51 -0
  118. package/core/domain/task-stack.ts +8 -0
  119. package/core/{index.js → index.ts} +61 -18
  120. package/core/infrastructure/{agent-detector.js → agent-detector.ts} +55 -19
  121. package/core/infrastructure/agents/{claude-agent.js → claude-agent.ts} +61 -21
  122. package/core/infrastructure/{author-detector.js → author-detector.ts} +42 -49
  123. package/core/infrastructure/{capability-installer.js → capability-installer.ts} +51 -27
  124. package/core/infrastructure/{command-installer.js → command-installer/command-installer.ts} +43 -144
  125. package/core/infrastructure/command-installer/global-config.ts +106 -0
  126. package/core/infrastructure/command-installer/index.ts +25 -0
  127. package/core/infrastructure/command-installer/types.ts +41 -0
  128. package/core/infrastructure/command-installer.ts +8 -0
  129. package/core/infrastructure/{config-manager.js → config-manager.ts} +60 -80
  130. package/core/infrastructure/{editors-config.js → editors-config.ts} +33 -31
  131. package/core/infrastructure/legacy-installer-detector/cleanup.ts +216 -0
  132. package/core/infrastructure/legacy-installer-detector/detection.ts +95 -0
  133. package/core/infrastructure/legacy-installer-detector/index.ts +171 -0
  134. package/core/infrastructure/legacy-installer-detector/migration.ts +87 -0
  135. package/core/infrastructure/legacy-installer-detector/types.ts +42 -0
  136. package/core/infrastructure/legacy-installer-detector.ts +7 -0
  137. package/core/infrastructure/migrator/file-operations.ts +125 -0
  138. package/core/infrastructure/migrator/index.ts +288 -0
  139. package/core/infrastructure/migrator/project-scanner.ts +89 -0
  140. package/core/infrastructure/migrator/reports.ts +117 -0
  141. package/core/infrastructure/migrator/types.ts +124 -0
  142. package/core/infrastructure/migrator/validation.ts +94 -0
  143. package/core/infrastructure/migrator/version-migration.ts +117 -0
  144. package/core/infrastructure/migrator.ts +10 -0
  145. package/core/infrastructure/{path-manager.js → path-manager.ts} +51 -91
  146. package/core/infrastructure/session-manager/index.ts +23 -0
  147. package/core/infrastructure/session-manager/migration.ts +88 -0
  148. package/core/infrastructure/session-manager/session-manager.ts +307 -0
  149. package/core/infrastructure/session-manager/types.ts +45 -0
  150. package/core/infrastructure/session-manager.ts +8 -0
  151. package/core/infrastructure/{setup.js → setup.ts} +29 -21
  152. package/core/infrastructure/{update-checker.js → update-checker.ts} +40 -18
  153. package/core/outcomes/analyzer.ts +333 -0
  154. package/core/outcomes/index.ts +34 -0
  155. package/core/outcomes/recorder.ts +194 -0
  156. package/core/outcomes/types.ts +145 -0
  157. package/core/plugin/{hooks.js → hooks.ts} +56 -58
  158. package/core/plugin/{index.js → index.ts} +19 -8
  159. package/core/plugin/{loader.js → loader.ts} +87 -69
  160. package/core/plugin/{registry.js → registry.ts} +49 -45
  161. package/core/plugins/{webhook.js → webhook.ts} +43 -27
  162. package/core/schemas/agents.ts +27 -0
  163. package/core/schemas/analysis.ts +41 -0
  164. package/core/schemas/ideas.ts +83 -0
  165. package/core/schemas/index.ts +73 -0
  166. package/core/schemas/outcomes.ts +22 -0
  167. package/core/schemas/project.ts +26 -0
  168. package/core/schemas/roadmap.ts +90 -0
  169. package/core/schemas/shipped.ts +82 -0
  170. package/core/schemas/state.ts +107 -0
  171. package/core/session/index.ts +17 -0
  172. package/core/session/{metrics.js → metrics.ts} +64 -46
  173. package/core/session/{index.js → session-manager.ts} +51 -117
  174. package/core/session/types.ts +29 -0
  175. package/core/session/utils.ts +57 -0
  176. package/core/state/index.ts +25 -0
  177. package/core/state/manager.ts +376 -0
  178. package/core/state/types.ts +185 -0
  179. package/core/tsconfig.json +22 -0
  180. package/core/types/index.ts +506 -0
  181. package/core/utils/{animations.js → animations.ts} +74 -28
  182. package/core/utils/{branding.js → branding.ts} +29 -4
  183. package/core/utils/{date-helper.js → date-helper.ts} +31 -74
  184. package/core/utils/file-helper.ts +262 -0
  185. package/core/utils/{jsonl-helper.js → jsonl-helper.ts} +71 -107
  186. package/core/utils/{logger.js → logger.ts} +24 -12
  187. package/core/utils/{output.js → output.ts} +25 -13
  188. package/core/utils/{project-capabilities.js → project-capabilities.ts} +31 -18
  189. package/core/utils/{session-helper.js → session-helper.ts} +79 -66
  190. package/core/utils/{version.js → version.ts} +23 -31
  191. package/core/view-generator.ts +536 -0
  192. package/package.json +23 -17
  193. package/packages/shared/.turbo/turbo-build.log +14 -0
  194. package/packages/shared/dist/index.d.ts +8 -613
  195. package/packages/shared/dist/index.d.ts.map +1 -0
  196. package/packages/shared/dist/index.js +4110 -118
  197. package/packages/shared/dist/schemas.d.ts +408 -0
  198. package/packages/shared/dist/schemas.d.ts.map +1 -0
  199. package/packages/shared/dist/types.d.ts +144 -0
  200. package/packages/shared/dist/types.d.ts.map +1 -0
  201. package/packages/shared/dist/unified.d.ts +139 -0
  202. package/packages/shared/dist/unified.d.ts.map +1 -0
  203. package/packages/shared/dist/utils.d.ts +60 -0
  204. package/packages/shared/dist/utils.d.ts.map +1 -0
  205. package/packages/shared/package.json +4 -4
  206. package/packages/shared/src/index.ts +1 -0
  207. package/packages/shared/src/unified.ts +174 -0
  208. package/packages/web/app/api/claude/sessions/route.ts +1 -1
  209. package/packages/web/app/api/claude/status/route.ts +1 -1
  210. package/packages/web/app/api/migrate/route.ts +46 -0
  211. package/packages/web/app/api/projects/[id]/route.ts +1 -1
  212. package/packages/web/app/api/projects/[id]/stats/route.ts +30 -2
  213. package/packages/web/app/api/projects/[id]/status/route.ts +1 -1
  214. package/packages/web/app/api/projects/route.ts +1 -1
  215. package/packages/web/app/api/settings/route.ts +97 -0
  216. package/packages/web/app/api/v2/projects/[id]/unified/route.ts +57 -0
  217. package/packages/web/app/globals.css +38 -0
  218. package/packages/web/app/layout.tsx +10 -2
  219. package/packages/web/app/page.tsx +9 -224
  220. package/packages/web/app/project/[id]/page.tsx +191 -63
  221. package/packages/web/app/project/[id]/stats/loading.tsx +43 -0
  222. package/packages/web/app/project/[id]/stats/page.tsx +204 -163
  223. package/packages/web/app/settings/page.tsx +222 -2
  224. package/packages/web/components/ActivityTimeline/ActivityTimeline.constants.ts +2 -0
  225. package/packages/web/components/ActivityTimeline/ActivityTimeline.tsx +50 -0
  226. package/packages/web/components/ActivityTimeline/ActivityTimeline.types.ts +8 -0
  227. package/packages/web/components/ActivityTimeline/hooks/index.ts +2 -0
  228. package/packages/web/components/ActivityTimeline/hooks/useExpandable.ts +9 -0
  229. package/packages/web/components/ActivityTimeline/hooks/useGroupedEvents.ts +23 -0
  230. package/packages/web/components/ActivityTimeline/index.ts +2 -0
  231. package/packages/web/components/AgentsCard/AgentsCard.tsx +63 -0
  232. package/packages/web/components/AgentsCard/AgentsCard.types.ts +13 -0
  233. package/packages/web/components/AgentsCard/index.ts +2 -0
  234. package/packages/web/components/AppSidebar/AppSidebar.tsx +134 -0
  235. package/packages/web/components/AppSidebar/index.ts +1 -0
  236. package/packages/web/components/BackLink/BackLink.tsx +18 -0
  237. package/packages/web/components/BackLink/BackLink.types.ts +5 -0
  238. package/packages/web/components/BackLink/index.ts +2 -0
  239. package/packages/web/components/BentoCard/BentoCard.constants.ts +16 -0
  240. package/packages/web/components/BentoCard/BentoCard.tsx +47 -0
  241. package/packages/web/components/BentoCard/BentoCard.types.ts +15 -0
  242. package/packages/web/components/BentoCard/index.ts +2 -0
  243. package/packages/web/components/BentoCardSkeleton/BentoCardSkeleton.constants.ts +9 -0
  244. package/packages/web/components/BentoCardSkeleton/BentoCardSkeleton.tsx +18 -0
  245. package/packages/web/components/BentoCardSkeleton/BentoCardSkeleton.types.ts +5 -0
  246. package/packages/web/components/BentoCardSkeleton/index.ts +2 -0
  247. package/packages/web/components/{stats → BentoGrid}/BentoGrid.tsx +4 -8
  248. package/packages/web/components/BentoGrid/BentoGrid.types.ts +4 -0
  249. package/packages/web/components/BentoGrid/index.ts +2 -0
  250. package/packages/web/components/CommandButton/index.ts +1 -0
  251. package/packages/web/components/ConnectionStatus/index.ts +1 -0
  252. package/packages/web/components/DashboardContent/DashboardContent.tsx +254 -0
  253. package/packages/web/components/DashboardContent/index.ts +1 -0
  254. package/packages/web/components/DateGroup/DateGroup.tsx +18 -0
  255. package/packages/web/components/DateGroup/DateGroup.types.ts +6 -0
  256. package/packages/web/components/DateGroup/DateGroup.utils.ts +11 -0
  257. package/packages/web/components/DateGroup/index.ts +2 -0
  258. package/packages/web/components/{stats → EmptyState}/EmptyState.tsx +1 -10
  259. package/packages/web/components/EmptyState/EmptyState.types.ts +10 -0
  260. package/packages/web/components/EmptyState/index.ts +2 -0
  261. package/packages/web/components/EventRow/EventRow.constants.ts +10 -0
  262. package/packages/web/components/EventRow/EventRow.tsx +49 -0
  263. package/packages/web/components/EventRow/EventRow.types.ts +7 -0
  264. package/packages/web/components/EventRow/EventRow.utils.ts +49 -0
  265. package/packages/web/components/EventRow/index.ts +2 -0
  266. package/packages/web/components/ExpandButton/ExpandButton.tsx +18 -0
  267. package/packages/web/components/ExpandButton/ExpandButton.types.ts +6 -0
  268. package/packages/web/components/ExpandButton/index.ts +2 -0
  269. package/packages/web/components/HealthGradientBackground/HealthGradientBackground.tsx +14 -0
  270. package/packages/web/components/HealthGradientBackground/HealthGradientBackground.types.ts +5 -0
  271. package/packages/web/components/HealthGradientBackground/HealthGradientBackground.utils.ts +13 -0
  272. package/packages/web/components/HealthGradientBackground/index.ts +2 -0
  273. package/packages/web/components/HeroSection/HeroSection.tsx +55 -0
  274. package/packages/web/components/HeroSection/HeroSection.types.ts +14 -0
  275. package/packages/web/components/HeroSection/HeroSection.utils.ts +7 -0
  276. package/packages/web/components/HeroSection/hooks/index.ts +2 -0
  277. package/packages/web/components/HeroSection/hooks/useCountUp.ts +45 -0
  278. package/packages/web/components/HeroSection/hooks/useWeeklyActivity.ts +18 -0
  279. package/packages/web/components/HeroSection/index.ts +2 -0
  280. package/packages/web/components/{stats → IdeasCard}/IdeasCard.tsx +3 -14
  281. package/packages/web/components/IdeasCard/IdeasCard.types.ts +9 -0
  282. package/packages/web/components/IdeasCard/index.ts +2 -0
  283. package/packages/web/components/InsightMessage/InsightMessage.tsx +9 -0
  284. package/packages/web/components/InsightMessage/InsightMessage.types.ts +3 -0
  285. package/packages/web/components/InsightMessage/index.ts +2 -0
  286. package/packages/web/components/Logo/index.ts +1 -0
  287. package/packages/web/components/MarkdownContent/index.ts +1 -0
  288. package/packages/web/components/NowCard/NowCard.tsx +93 -0
  289. package/packages/web/components/NowCard/NowCard.types.ts +15 -0
  290. package/packages/web/components/NowCard/index.ts +2 -0
  291. package/packages/web/components/ProgressRing/ProgressRing.constants.ts +20 -0
  292. package/packages/web/components/{stats → ProgressRing}/ProgressRing.tsx +4 -27
  293. package/packages/web/components/ProgressRing/ProgressRing.types.ts +11 -0
  294. package/packages/web/components/ProgressRing/index.ts +2 -0
  295. package/packages/web/components/ProjectAvatar/index.ts +1 -0
  296. package/packages/web/components/Providers/index.ts +1 -0
  297. package/packages/web/components/QueueCard/QueueCard.tsx +72 -0
  298. package/packages/web/components/QueueCard/QueueCard.types.ts +11 -0
  299. package/packages/web/components/QueueCard/QueueCard.utils.ts +12 -0
  300. package/packages/web/components/QueueCard/index.ts +2 -0
  301. package/packages/web/components/{stats → RoadmapCard}/RoadmapCard.tsx +3 -23
  302. package/packages/web/components/RoadmapCard/RoadmapCard.types.ts +15 -0
  303. package/packages/web/components/RoadmapCard/index.ts +2 -0
  304. package/packages/web/components/{stats → ShipsCard}/ShipsCard.tsx +4 -22
  305. package/packages/web/components/ShipsCard/ShipsCard.types.ts +12 -0
  306. package/packages/web/components/ShipsCard/ShipsCard.utils.ts +4 -0
  307. package/packages/web/components/ShipsCard/index.ts +2 -0
  308. package/packages/web/components/{stats → SparklineChart}/SparklineChart.tsx +1 -7
  309. package/packages/web/components/SparklineChart/SparklineChart.types.ts +6 -0
  310. package/packages/web/components/SparklineChart/index.ts +2 -0
  311. package/packages/web/components/StreakCard/StreakCard.constants.ts +2 -0
  312. package/packages/web/components/{stats → StreakCard}/StreakCard.tsx +5 -11
  313. package/packages/web/components/StreakCard/StreakCard.types.ts +4 -0
  314. package/packages/web/components/StreakCard/index.ts +2 -0
  315. package/packages/web/components/TasksCounter/TasksCounter.tsx +14 -0
  316. package/packages/web/components/TasksCounter/TasksCounter.types.ts +3 -0
  317. package/packages/web/components/TasksCounter/index.ts +2 -0
  318. package/packages/web/components/TechStackBadges/index.ts +1 -0
  319. package/packages/web/components/{TerminalTab.tsx → TerminalTabs/TerminalTab.tsx} +11 -0
  320. package/packages/web/components/{TerminalTabs.tsx → TerminalTabs/TerminalTabs.tsx} +29 -28
  321. package/packages/web/components/TerminalTabs/index.ts +1 -0
  322. package/packages/web/components/VelocityBadge/VelocityBadge.tsx +27 -0
  323. package/packages/web/components/VelocityBadge/VelocityBadge.types.ts +3 -0
  324. package/packages/web/components/VelocityBadge/index.ts +2 -0
  325. package/packages/web/components/VelocityCard/VelocityCard.tsx +71 -0
  326. package/packages/web/components/VelocityCard/VelocityCard.types.ts +7 -0
  327. package/packages/web/components/VelocityCard/index.ts +2 -0
  328. package/packages/web/components/WeeklySparkline/WeeklySparkline.tsx +13 -0
  329. package/packages/web/components/WeeklySparkline/WeeklySparkline.types.ts +3 -0
  330. package/packages/web/components/WeeklySparkline/index.ts +2 -0
  331. package/packages/web/components/ui/input.tsx +21 -0
  332. package/packages/web/context/TerminalTabsContext.tsx +46 -1
  333. package/packages/web/hooks/useClaudeTerminal.ts +71 -21
  334. package/packages/web/hooks/useProjectStats.ts +55 -0
  335. package/packages/web/hooks/useProjects.ts +6 -6
  336. package/packages/web/lib/actions/projects.ts +15 -0
  337. package/packages/web/lib/json-loader.ts +630 -0
  338. package/packages/web/lib/services/index.ts +9 -0
  339. package/packages/web/lib/services/migration.server.ts +598 -0
  340. package/packages/web/lib/services/projects.server.ts +52 -0
  341. package/packages/web/lib/services/stats.server.ts +264 -0
  342. package/packages/web/lib/unified-loader.ts +396 -0
  343. package/packages/web/package.json +10 -7
  344. package/packages/web/server.ts +36 -6
  345. package/templates/commands/done.md +76 -32
  346. package/templates/commands/feature.md +121 -47
  347. package/templates/commands/idea.md +81 -8
  348. package/templates/commands/now.md +41 -17
  349. package/templates/commands/ship.md +64 -25
  350. package/templates/commands/sync.md +28 -3
  351. package/core/agentic/agent-router.js +0 -140
  352. package/core/agentic/chain-of-thought.js +0 -578
  353. package/core/agentic/command-executor.js +0 -417
  354. package/core/agentic/context-filter.js +0 -354
  355. package/core/agentic/ground-truth.js +0 -591
  356. package/core/agentic/loop-detector.js +0 -406
  357. package/core/agentic/memory-system.js +0 -845
  358. package/core/agentic/parallel-tools.js +0 -366
  359. package/core/agentic/plan-mode.js +0 -572
  360. package/core/agentic/prompt-builder.js +0 -352
  361. package/core/agentic/response-templates.js +0 -290
  362. package/core/agentic/semantic-compression.js +0 -517
  363. package/core/agentic/think-blocks.js +0 -657
  364. package/core/agentic/tool-registry.js +0 -184
  365. package/core/agentic/validation-rules.js +0 -380
  366. package/core/command-registry.js +0 -698
  367. package/core/commands.js +0 -2237
  368. package/core/domain/task-stack.js +0 -497
  369. package/core/infrastructure/legacy-installer-detector.js +0 -546
  370. package/core/infrastructure/migrator.js +0 -796
  371. package/core/infrastructure/session-manager.js +0 -390
  372. package/core/utils/file-helper.js +0 -329
  373. package/packages/web/app/api/projects/[id]/delete/route.ts +0 -21
  374. package/packages/web/app/api/stats/route.ts +0 -38
  375. package/packages/web/components/AppSidebar.tsx +0 -113
  376. package/packages/web/components/stats/ActivityTimeline.tsx +0 -201
  377. package/packages/web/components/stats/AgentsCard.tsx +0 -56
  378. package/packages/web/components/stats/BentoCard.tsx +0 -88
  379. package/packages/web/components/stats/HeroSection.tsx +0 -172
  380. package/packages/web/components/stats/NowCard.tsx +0 -71
  381. package/packages/web/components/stats/QueueCard.tsx +0 -58
  382. package/packages/web/components/stats/VelocityCard.tsx +0 -60
  383. package/packages/web/components/stats/index.ts +0 -17
  384. package/packages/web/hooks/useStats.ts +0 -28
  385. /package/packages/web/components/{CommandButton.tsx → CommandButton/CommandButton.tsx} +0 -0
  386. /package/packages/web/components/{ConnectionStatus.tsx → ConnectionStatus/ConnectionStatus.tsx} +0 -0
  387. /package/packages/web/components/{Logo.tsx → Logo/Logo.tsx} +0 -0
  388. /package/packages/web/components/{MarkdownContent.tsx → MarkdownContent/MarkdownContent.tsx} +0 -0
  389. /package/packages/web/components/{ProjectAvatar.tsx → ProjectAvatar/ProjectAvatar.tsx} +0 -0
  390. /package/packages/web/components/{providers.tsx → Providers/Providers.tsx} +0 -0
  391. /package/packages/web/components/{TechStackBadges.tsx → TechStackBadges/TechStackBadges.tsx} +0 -0
@@ -1,7 +1,3 @@
1
- const fs = require('fs').promises
2
- const pathManager = require('./path-manager')
3
- const { VERSION } = require('../utils/version')
4
-
5
1
  /**
6
2
  * ConfigManager - Manages prjct.config.json files
7
3
  *
@@ -13,14 +9,43 @@ const { VERSION } = require('../utils/version')
13
9
  *
14
10
  * @version 0.2.1
15
11
  */
12
+
13
+ import fs from 'fs/promises'
14
+ import path from 'path'
15
+ import pathManager from './path-manager'
16
+ import { VERSION } from '../utils/version'
17
+
18
+ interface Author {
19
+ name: string
20
+ email: string
21
+ github: string
22
+ firstContribution?: string
23
+ lastActivity?: string
24
+ }
25
+
26
+ interface LocalConfig {
27
+ projectId: string
28
+ dataPath: string
29
+ authors?: Author[]
30
+ author?: Author
31
+ version?: string
32
+ created?: string
33
+ lastSync?: string
34
+ }
35
+
36
+ interface GlobalConfig {
37
+ projectId: string
38
+ authors: Author[]
39
+ version: string
40
+ created?: string
41
+ lastSync: string
42
+ }
43
+
16
44
  class ConfigManager {
17
45
  /**
18
46
  * Read the project configuration file
19
- *
20
- * @param {string} projectPath - Path to the project
21
- * @returns {Promise<Object|null>} - Configuration object or null if not found
22
47
  */
23
- async readConfig(projectPath) {
48
+ async readConfig(projectPath: string): Promise<LocalConfig | null> {
24
49
  try {
25
50
  const configPath = pathManager.getLocalConfigPath(projectPath)
26
51
  const content = await fs.readFile(configPath, 'utf-8')
@@ -32,12 +57,8 @@ class ConfigManager {
32
57
 
33
58
  /**
34
59
  * Write the project configuration file
35
- *
36
- * @param {string} projectPath - Path to the project
37
- * @param {Object} config - Configuration object
38
- * @returns {Promise<void>}
39
60
  */
40
- async writeConfig(projectPath, config) {
61
+ async writeConfig(projectPath: string, config: LocalConfig): Promise<void> {
41
62
  const configPath = pathManager.getLocalConfigPath(projectPath)
42
63
  const configDir = pathManager.getLegacyPrjctPath(projectPath)
43
64
 
@@ -50,11 +71,8 @@ class ConfigManager {
50
71
  /**
51
72
  * Read the global project configuration file
52
73
  * Contains authors array and other system data
53
- *
54
- * @param {string} projectId - Project identifier
55
- * @returns {Promise<Object|null>} - Configuration object or null if not found
56
74
  */
57
- async readGlobalConfig(projectId) {
75
+ async readGlobalConfig(projectId: string): Promise<GlobalConfig | null> {
58
76
  try {
59
77
  const configPath = pathManager.getGlobalProjectConfigPath(projectId)
60
78
  const content = await fs.readFile(configPath, 'utf-8')
@@ -66,12 +84,8 @@ class ConfigManager {
66
84
 
67
85
  /**
68
86
  * Write the global project configuration file
69
- *
70
- * @param {string} projectId - Project identifier
71
- * @param {Object} config - Configuration object
72
- * @returns {Promise<void>}
73
87
  */
74
- async writeGlobalConfig(projectId, config) {
88
+ async writeGlobalConfig(projectId: string, config: GlobalConfig): Promise<void> {
75
89
  const configPath = pathManager.getGlobalProjectConfigPath(projectId)
76
90
  const configDir = pathManager.getGlobalProjectPath(projectId)
77
91
 
@@ -83,11 +97,8 @@ class ConfigManager {
83
97
 
84
98
  /**
85
99
  * Ensure global config exists, create if not
86
- *
87
- * @param {string} projectId - Project identifier
88
- * @returns {Promise<Object>} - Global configuration
89
100
  */
90
- async ensureGlobalConfig(projectId) {
101
+ async ensureGlobalConfig(projectId: string): Promise<GlobalConfig> {
91
102
  let globalConfig = await this.readGlobalConfig(projectId)
92
103
 
93
104
  if (!globalConfig) {
@@ -106,25 +117,24 @@ class ConfigManager {
106
117
 
107
118
  /**
108
119
  * Create a new project configuration
109
- *
110
- * @param {string} projectPath - Path to the project
111
- * @param {Object} author - Author information {name, email, github}
112
- * @returns {Promise<Object>} - Created configuration
113
120
  */
114
- async createConfig(projectPath, author) {
121
+ async createConfig(
122
+ projectPath: string,
123
+ author: { name?: string; email?: string; github?: string }
124
+ ): Promise<LocalConfig> {
115
125
  const projectId = pathManager.generateProjectId(projectPath)
116
126
  const globalPath = pathManager.getGlobalProjectPath(projectId)
117
127
  const displayPath = pathManager.getDisplayPath(globalPath)
118
128
  const now = new Date().toISOString()
119
129
 
120
- const localConfig = {
130
+ const localConfig: LocalConfig = {
121
131
  projectId,
122
132
  dataPath: displayPath,
123
133
  }
124
134
 
125
135
  await this.writeConfig(projectPath, localConfig)
126
136
 
127
- const globalConfig = {
137
+ const globalConfig: GlobalConfig = {
128
138
  projectId,
129
139
  authors: [
130
140
  {
@@ -147,11 +157,8 @@ class ConfigManager {
147
157
 
148
158
  /**
149
159
  * Update the lastSync timestamp in global config
150
- *
151
- * @param {string} projectPath - Path to the project
152
- * @returns {Promise<void>}
153
160
  */
154
- async updateLastSync(projectPath) {
161
+ async updateLastSync(projectPath: string): Promise<void> {
155
162
  const projectId = await this.getProjectId(projectPath)
156
163
  const globalConfig = await this.readGlobalConfig(projectId)
157
164
  if (globalConfig) {
@@ -164,11 +171,8 @@ class ConfigManager {
164
171
  * Validate a local configuration object
165
172
  * Local config only contains project metadata (projectId, dataPath)
166
173
  * All system data (version, created, lastSync, authors) is in global config
167
- *
168
- * @param {Object} config - Configuration to validate
169
- * @returns {boolean} - True if valid
170
174
  */
171
- validateConfig(config) {
175
+ validateConfig(config: LocalConfig | null): boolean {
172
176
  if (!config) return false
173
177
  if (!config.projectId) return false
174
178
  if (!config.dataPath) return false
@@ -181,11 +185,8 @@ class ConfigManager {
181
185
  * Migration is needed if:
182
186
  * - Has legacy .prjct/ structure
183
187
  * - AND either no config exists OR files not yet in global location
184
- *
185
- * @param {string} projectPath - Path to the project
186
- * @returns {Promise<boolean>} - True if migration needed
187
188
  */
188
- async needsMigration(projectPath) {
189
+ async needsMigration(projectPath: string): Promise<boolean> {
189
190
  const hasLegacy = await pathManager.hasLegacyStructure(projectPath)
190
191
  if (!hasLegacy) return false
191
192
 
@@ -197,8 +198,6 @@ class ConfigManager {
197
198
  if (!config || !config.projectId) return true
198
199
 
199
200
  const globalPath = pathManager.getGlobalProjectPath(config.projectId)
200
- const fs = require('fs').promises
201
- const path = require('path')
202
201
 
203
202
  try {
204
203
  const coreFiles = await fs.readdir(path.join(globalPath, 'core'))
@@ -210,11 +209,8 @@ class ConfigManager {
210
209
 
211
210
  /**
212
211
  * Get the project ID from config, or generate it if config doesn't exist
213
- *
214
- * @param {string} projectPath - Path to the project
215
- * @returns {Promise<string>} - Project ID
216
212
  */
217
- async getProjectId(projectPath) {
213
+ async getProjectId(projectPath: string): Promise<string> {
218
214
  const config = await this.readConfig(projectPath)
219
215
  if (config && config.projectId) {
220
216
  return config.projectId
@@ -225,12 +221,8 @@ class ConfigManager {
225
221
  /**
226
222
  * Find an author in the authors array by github username
227
223
  * Reads from GLOBAL config
228
- *
229
- * @param {string} projectId - Project identifier
230
- * @param {string} githubUsername - GitHub username to search for
231
- * @returns {Promise<Object|null>} - Author object or null if not found
232
224
  */
233
- async findAuthor(projectId, githubUsername) {
225
+ async findAuthor(projectId: string, githubUsername: string): Promise<Author | null> {
234
226
  const globalConfig = await this.readGlobalConfig(projectId)
235
227
  if (!globalConfig || !globalConfig.authors) return null
236
228
 
@@ -240,12 +232,11 @@ class ConfigManager {
240
232
  /**
241
233
  * Add a new author to the authors array
242
234
  * Writes to GLOBAL config
243
- *
244
- * @param {string} projectId - Project identifier
245
- * @param {Object} author - Author information {name, email, github}
246
- * @returns {Promise<void>}
247
235
  */
248
- async addAuthor(projectId, author) {
236
+ async addAuthor(
237
+ projectId: string,
238
+ author: { name?: string; email?: string; github?: string }
239
+ ): Promise<void> {
249
240
  const globalConfig = await this.ensureGlobalConfig(projectId)
250
241
 
251
242
  const exists = globalConfig.authors.some((a) => a.github === author.github)
@@ -267,12 +258,8 @@ class ConfigManager {
267
258
  /**
268
259
  * Update author's last activity timestamp
269
260
  * Updates GLOBAL config
270
- *
271
- * @param {string} projectId - Project identifier
272
- * @param {string} githubUsername - GitHub username
273
- * @returns {Promise<void>}
274
261
  */
275
- async updateAuthorActivity(projectId, githubUsername) {
262
+ async updateAuthorActivity(projectId: string, githubUsername: string): Promise<void> {
276
263
  const globalConfig = await this.readGlobalConfig(projectId)
277
264
  if (!globalConfig || !globalConfig.authors) return
278
265
 
@@ -286,12 +273,10 @@ class ConfigManager {
286
273
 
287
274
  /**
288
275
  * Get current author for session (detect or get from global config)
289
- *
290
- * @param {string} projectPath - Path to the project
291
- * @returns {Promise<string>} - GitHub username of current author
292
276
  */
293
- async getCurrentAuthor(projectPath) {
294
- const authorDetector = require('./author-detector')
277
+ async getCurrentAuthor(projectPath: string): Promise<string> {
278
+ // Dynamic import to avoid circular dependency
279
+ const authorDetector = (await import('./author-detector')).default
295
280
  const author = await authorDetector.detect()
296
281
 
297
282
  const projectId = await this.getProjectId(projectPath)
@@ -302,11 +287,8 @@ class ConfigManager {
302
287
 
303
288
  /**
304
289
  * Check if config exists and is valid
305
- *
306
- * @param {string} projectPath - Path to the project
307
- * @returns {Promise<boolean>} - True if valid config exists
308
290
  */
309
- async isConfigured(projectPath) {
291
+ async isConfigured(projectPath: string): Promise<boolean> {
310
292
  const config = await this.readConfig(projectPath)
311
293
  return this.validateConfig(config)
312
294
  }
@@ -314,11 +296,8 @@ class ConfigManager {
314
296
  /**
315
297
  * Get configuration with defaults
316
298
  * Returns LOCAL config only (projectId, dataPath)
317
- *
318
- * @param {string} projectPath - Path to the project
319
- * @returns {Promise<Object>} - Configuration with defaults
320
299
  */
321
- async getConfigWithDefaults(projectPath) {
300
+ async getConfigWithDefaults(projectPath: string): Promise<LocalConfig> {
322
301
  const config = await this.readConfig(projectPath)
323
302
  if (config) {
324
303
  return config
@@ -332,4 +311,5 @@ class ConfigManager {
332
311
  }
333
312
  }
334
313
 
335
- module.exports = new ConfigManager()
314
+ const configManager = new ConfigManager()
315
+ export default configManager
@@ -1,7 +1,3 @@
1
- const fs = require('fs').promises
2
- const path = require('path')
3
- const os = require('os')
4
-
5
1
  /**
6
2
  * EditorsConfig - Manages Claude installation tracking
7
3
  *
@@ -12,7 +8,23 @@ const os = require('os')
12
8
  *
13
9
  * @version 0.5.0
14
10
  */
11
+
12
+ import fs from 'fs/promises'
13
+ import path from 'path'
14
+ import os from 'os'
15
+
16
+ interface EditorConfig {
17
+ version: string
18
+ editor: string
19
+ lastInstall: string
20
+ path: string
21
+ }
22
+
15
23
  class EditorsConfig {
24
+ homeDir: string
25
+ configDir: string
26
+ configFile: string
27
+
16
28
  constructor() {
17
29
  this.homeDir = os.homedir()
18
30
  this.configDir = path.join(this.homeDir, '.prjct-cli', 'config')
@@ -22,42 +34,38 @@ class EditorsConfig {
22
34
  /**
23
35
  * Ensure config directory exists
24
36
  */
25
- async ensureConfigDir() {
37
+ async ensureConfigDir(): Promise<void> {
26
38
  try {
27
39
  await fs.mkdir(this.configDir, { recursive: true })
28
40
  } catch (error) {
29
- console.error('[editors-config] Error creating config directory:', error.message)
41
+ console.error('[editors-config] Error creating config directory:', (error as Error).message)
30
42
  }
31
43
  }
32
44
 
33
45
  /**
34
46
  * Load installation configuration
35
- * @returns {Promise<Object|null>} Configuration object or null if not found
36
47
  */
37
- async loadConfig() {
48
+ async loadConfig(): Promise<EditorConfig | null> {
38
49
  try {
39
50
  const content = await fs.readFile(this.configFile, 'utf-8')
40
51
  return JSON.parse(content)
41
52
  } catch (error) {
42
- if (error.code === 'ENOENT') {
53
+ if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
43
54
  return null
44
55
  }
45
- console.error('[editors-config] Error loading config:', error.message)
56
+ console.error('[editors-config] Error loading config:', (error as Error).message)
46
57
  return null
47
58
  }
48
59
  }
49
60
 
50
61
  /**
51
62
  * Save installation configuration
52
- * @param {string} version - Current prjct-cli version
53
- * @param {string} claudePath - Path to Claude commands directory
54
- * @returns {Promise<boolean>} Success status
55
63
  */
56
- async saveConfig(version, claudePath) {
64
+ async saveConfig(version: string, claudePath: string): Promise<boolean> {
57
65
  try {
58
66
  await this.ensureConfigDir()
59
67
 
60
- const config = {
68
+ const config: EditorConfig = {
61
69
  version,
62
70
  editor: 'claude',
63
71
  lastInstall: new Date().toISOString(),
@@ -68,36 +76,31 @@ class EditorsConfig {
68
76
 
69
77
  return true
70
78
  } catch (error) {
71
- console.error('[editors-config] Error saving config:', error.message)
79
+ console.error('[editors-config] Error saving config:', (error as Error).message)
72
80
  return false
73
81
  }
74
82
  }
75
83
 
76
84
  /**
77
85
  * Get last installed version
78
- * @returns {Promise<string|null>} Version string or null
79
86
  */
80
- async getLastVersion() {
87
+ async getLastVersion(): Promise<string | null> {
81
88
  const config = await this.loadConfig()
82
89
  return config ? config.version : null
83
90
  }
84
91
 
85
92
  /**
86
93
  * Check if version has changed since last install
87
- * @param {string} currentVersion - Current version to compare
88
- * @returns {Promise<boolean>} True if version has changed
89
94
  */
90
- async hasVersionChanged(currentVersion) {
95
+ async hasVersionChanged(currentVersion: string): Promise<boolean> {
91
96
  const lastVersion = await this.getLastVersion()
92
97
  return lastVersion !== null && lastVersion !== currentVersion
93
98
  }
94
99
 
95
100
  /**
96
101
  * Update version in configuration
97
- * @param {string} version - New version to save
98
- * @returns {Promise<boolean>} Success status
99
102
  */
100
- async updateVersion(version) {
103
+ async updateVersion(version: string): Promise<boolean> {
101
104
  try {
102
105
  const config = await this.loadConfig()
103
106
  if (!config) {
@@ -111,16 +114,15 @@ class EditorsConfig {
111
114
 
112
115
  return true
113
116
  } catch (error) {
114
- console.error('[editors-config] Error updating version:', error.message)
117
+ console.error('[editors-config] Error updating version:', (error as Error).message)
115
118
  return false
116
119
  }
117
120
  }
118
121
 
119
122
  /**
120
123
  * Check if config file exists
121
- * @returns {Promise<boolean>} True if config exists
122
124
  */
123
- async configExists() {
125
+ async configExists(): Promise<boolean> {
124
126
  try {
125
127
  await fs.access(this.configFile)
126
128
  return true
@@ -132,9 +134,8 @@ class EditorsConfig {
132
134
  /**
133
135
  * Delete configuration file
134
136
  * Used during uninstallation to clean up tracking data
135
- * @returns {Promise<boolean>} Success status
136
137
  */
137
- async deleteConfig() {
138
+ async deleteConfig(): Promise<boolean> {
138
139
  try {
139
140
  const exists = await this.configExists()
140
141
  if (exists) {
@@ -142,10 +143,11 @@ class EditorsConfig {
142
143
  }
143
144
  return true
144
145
  } catch (error) {
145
- console.error('[editors-config] Error deleting config:', error.message)
146
+ console.error('[editors-config] Error deleting config:', (error as Error).message)
146
147
  return false
147
148
  }
148
149
  }
149
150
  }
150
151
 
151
- module.exports = new EditorsConfig()
152
+ const editorsConfig = new EditorsConfig()
153
+ export default editorsConfig
@@ -0,0 +1,216 @@
1
+ /**
2
+ * Cleanup - Legacy Installation Cleanup
3
+ */
4
+
5
+ import fs from 'fs/promises'
6
+ import path from 'path'
7
+ import os from 'os'
8
+ import { legacyInstallDir, isWindows } from './detection'
9
+ import type { CleanupResult } from './types'
10
+
11
+ /**
12
+ * Get platform-specific shell config files
13
+ */
14
+ export function getShellConfigFiles(): string[] {
15
+ if (isWindows) {
16
+ const profilePaths: string[] = []
17
+
18
+ if (process.env.USERPROFILE) {
19
+ profilePaths.push(
20
+ path.join(
21
+ process.env.USERPROFILE,
22
+ 'Documents',
23
+ 'PowerShell',
24
+ 'Microsoft.PowerShell_profile.ps1'
25
+ ),
26
+ path.join(
27
+ process.env.USERPROFILE,
28
+ 'Documents',
29
+ 'WindowsPowerShell',
30
+ 'Microsoft.PowerShell_profile.ps1'
31
+ )
32
+ )
33
+ }
34
+
35
+ return profilePaths
36
+ } else {
37
+ return [
38
+ path.join(os.homedir(), '.zshrc'),
39
+ path.join(os.homedir(), '.bashrc'),
40
+ path.join(os.homedir(), '.profile'),
41
+ path.join(os.homedir(), '.bash_profile'),
42
+ ]
43
+ }
44
+ }
45
+
46
+ /**
47
+ * Remove legacy installation files (keep projects data)
48
+ */
49
+ export async function cleanupLegacyInstallation(): Promise<CleanupResult> {
50
+ const result: CleanupResult = {
51
+ success: false,
52
+ message: '',
53
+ }
54
+
55
+ try {
56
+ const dirsToRemove = [
57
+ 'bin',
58
+ 'core',
59
+ 'templates',
60
+ 'scripts',
61
+ 'node_modules',
62
+ '.git',
63
+ '__tests__',
64
+ 'website',
65
+ 'docs',
66
+ '.github',
67
+ ]
68
+ const filesToRemove = [
69
+ 'package.json',
70
+ 'package-lock.json',
71
+ 'README.md',
72
+ 'LICENSE',
73
+ 'CHANGELOG.md',
74
+ 'CLAUDE.md',
75
+ 'CONTRIBUTING.md',
76
+ 'MIGRATION.md',
77
+ 'TESTING.md',
78
+ '.gitignore',
79
+ '.eslintrc.js',
80
+ '.prettierrc',
81
+ 'vitest.config.js',
82
+ 'vitest.workspace.js',
83
+ ]
84
+
85
+ let removedItems = 0
86
+
87
+ for (const dir of dirsToRemove) {
88
+ const dirPath = path.join(legacyInstallDir, dir)
89
+ try {
90
+ await fs.rm(dirPath, { recursive: true, force: true })
91
+ removedItems++
92
+ } catch {
93
+ // Directory doesn't exist
94
+ }
95
+ }
96
+
97
+ for (const file of filesToRemove) {
98
+ const filePath = path.join(legacyInstallDir, file)
99
+ try {
100
+ await fs.unlink(filePath)
101
+ removedItems++
102
+ } catch {
103
+ // File doesn't exist
104
+ }
105
+ }
106
+
107
+ result.success = true
108
+ result.message = `Removed ${removedItems} legacy installation items`
109
+ return result
110
+ } catch (error) {
111
+ result.message = `Cleanup failed: ${(error as Error).message}`
112
+ return result
113
+ }
114
+ }
115
+
116
+ /**
117
+ * Clean up legacy PATH entries from shell config files
118
+ */
119
+ export async function cleanupLegacyPATH(): Promise<CleanupResult> {
120
+ const result: CleanupResult = {
121
+ success: false,
122
+ message: '',
123
+ filesModified: 0,
124
+ }
125
+
126
+ try {
127
+ const shellConfigs = getShellConfigFiles()
128
+
129
+ for (const configFile of shellConfigs) {
130
+ try {
131
+ const content = await fs.readFile(configFile, 'utf8')
132
+
133
+ if (!content.includes('.prjct-cli/bin')) {
134
+ continue
135
+ }
136
+
137
+ const lines = content.split('\n')
138
+ const filteredLines = lines.filter((line) => {
139
+ return !line.includes('.prjct-cli/bin') && !line.includes('# prjct/cli')
140
+ })
141
+
142
+ const cleanedLines: string[] = []
143
+ for (let i = 0; i < filteredLines.length; i++) {
144
+ const line = filteredLines[i]
145
+ const prevLine = filteredLines[i - 1]
146
+
147
+ if (line.trim() === '' && prevLine && prevLine.trim() === '') {
148
+ continue
149
+ }
150
+
151
+ cleanedLines.push(line)
152
+ }
153
+
154
+ await fs.writeFile(configFile, cleanedLines.join('\n'), 'utf8')
155
+ result.filesModified!++
156
+ } catch {
157
+ // File doesn't exist or can't read
158
+ }
159
+ }
160
+
161
+ result.success = true
162
+ result.message =
163
+ result.filesModified! > 0
164
+ ? `Cleaned PATH from ${result.filesModified} shell config(s)`
165
+ : 'No legacy PATH entries found'
166
+
167
+ return result
168
+ } catch (error) {
169
+ result.message = `PATH cleanup failed: ${(error as Error).message}`
170
+ return result
171
+ }
172
+ }
173
+
174
+ /**
175
+ * Clean up legacy symlinks
176
+ */
177
+ export async function cleanupLegacySymlinks(): Promise<CleanupResult> {
178
+ const result: CleanupResult = {
179
+ success: false,
180
+ message: '',
181
+ }
182
+
183
+ if (isWindows) {
184
+ result.success = true
185
+ result.message = 'No symlinks on Windows'
186
+ return result
187
+ }
188
+
189
+ try {
190
+ const symlinkPath = path.join(os.homedir(), '.local', 'bin', 'prjct')
191
+
192
+ try {
193
+ const stat = await fs.lstat(symlinkPath)
194
+
195
+ if (stat.isSymbolicLink()) {
196
+ const target = await fs.readlink(symlinkPath)
197
+
198
+ if (target.includes('.prjct-cli')) {
199
+ await fs.unlink(symlinkPath)
200
+ result.success = true
201
+ result.message = 'Removed legacy symlink'
202
+ return result
203
+ }
204
+ }
205
+ } catch {
206
+ // Symlink doesn't exist
207
+ }
208
+
209
+ result.success = true
210
+ result.message = 'No legacy symlinks found'
211
+ return result
212
+ } catch (error) {
213
+ result.message = `Symlink cleanup failed: ${(error as Error).message}`
214
+ return result
215
+ }
216
+ }