prjct-cli 0.11.5 → 0.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 +190 -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 +600 -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 +58 -8
  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
@@ -0,0 +1,340 @@
1
+ /**
2
+ * Task Stack Manager - Core class
3
+ * Handles multiple concurrent tasks with pause/resume capability
4
+ */
5
+
6
+ import path from 'path'
7
+ import fs from 'fs/promises'
8
+ import { exec } from 'child_process'
9
+ import { promisify } from 'util'
10
+ import type { TaskEntry, MigrationResult, SwitchResult, StackSummary } from './types'
11
+ import { parseNowFile, formatDuration } from './parser'
12
+ import { ensureStackFile, appendToStack, readStack, writeStack, updateNowFile } from './storage'
13
+
14
+ const execAsync = promisify(exec)
15
+
16
+ export class TaskStack {
17
+ projectPath: string
18
+ stackPath: string
19
+ nowPath: string
20
+
21
+ constructor(projectPath: string) {
22
+ this.projectPath = projectPath
23
+ this.stackPath = path.join(projectPath, 'core', 'stack.jsonl')
24
+ this.nowPath = path.join(projectPath, 'core', 'now.md')
25
+ }
26
+
27
+ /**
28
+ * Initialize stack system - migrate from legacy now.md if needed
29
+ */
30
+ async initialize(): Promise<MigrationResult> {
31
+ try {
32
+ // Check if stack already exists
33
+ await fs.access(this.stackPath)
34
+ return { migrated: false }
35
+ } catch {
36
+ // Stack doesn't exist, check for legacy now.md
37
+ return await this.migrateFromLegacy()
38
+ }
39
+ }
40
+
41
+ /**
42
+ * Migrate from legacy now.md to stack system
43
+ */
44
+ async migrateFromLegacy(): Promise<MigrationResult> {
45
+ try {
46
+ const nowContent = await fs.readFile(this.nowPath, 'utf8')
47
+
48
+ if (!nowContent.trim() || nowContent.includes('No active task')) {
49
+ // Empty or no task, just create empty stack
50
+ await ensureStackFile(this.stackPath)
51
+ return { migrated: true, hadTask: false }
52
+ }
53
+
54
+ // Parse task from now.md
55
+ const task = parseNowFile(nowContent)
56
+
57
+ // Create initial stack entry
58
+ const entry: TaskEntry = {
59
+ id: `task-${Date.now()}`,
60
+ task: task.description || 'Migrated task',
61
+ agent: task.agent || 'unknown',
62
+ status: 'active',
63
+ started: task.started || new Date().toISOString(),
64
+ paused: null,
65
+ resumed: null,
66
+ completed: null,
67
+ duration: null,
68
+ complexity: task.complexity || 'moderate',
69
+ dev: task.dev || 'unknown',
70
+ }
71
+
72
+ // Write to stack
73
+ await appendToStack(this.stackPath, entry)
74
+
75
+ return { migrated: true, hadTask: true, task: entry }
76
+ } catch (error) {
77
+ // No now.md or error reading, just create empty stack
78
+ await ensureStackFile(this.stackPath)
79
+ return { migrated: true, hadTask: false, error: (error as Error).message }
80
+ }
81
+ }
82
+
83
+ // Re-expose parseNowFile for compatibility
84
+ parseNowFile(content: string) {
85
+ return parseNowFile(content)
86
+ }
87
+
88
+ // Re-expose formatDuration for compatibility
89
+ formatDuration(ms: number): string {
90
+ return formatDuration(ms)
91
+ }
92
+
93
+ /**
94
+ * Get active task
95
+ */
96
+ async getActiveTask(): Promise<TaskEntry | null> {
97
+ const stack = await readStack(this.stackPath)
98
+ return stack.find((task) => task.status === 'active') || null
99
+ }
100
+
101
+ /**
102
+ * Get paused tasks
103
+ */
104
+ async getPausedTasks(): Promise<TaskEntry[]> {
105
+ const stack = await readStack(this.stackPath)
106
+ return stack
107
+ .filter((task) => task.status === 'paused')
108
+ .sort((a, b) => new Date(b.paused!).getTime() - new Date(a.paused!).getTime())
109
+ }
110
+
111
+ /**
112
+ * Get all incomplete tasks
113
+ */
114
+ async getIncompleteTasks(): Promise<TaskEntry[]> {
115
+ const stack = await readStack(this.stackPath)
116
+ return stack.filter((task) => task.status !== 'completed')
117
+ }
118
+
119
+ /**
120
+ * Start a new task
121
+ */
122
+ async startTask(description: string, agent: string = 'general', complexity: string = 'moderate'): Promise<TaskEntry> {
123
+ // Check if there's already an active task
124
+ const active = await this.getActiveTask()
125
+ if (active) {
126
+ throw new Error(`Already working on: ${active.task}. Use /p:pause to pause it first.`)
127
+ }
128
+
129
+ const entry: TaskEntry = {
130
+ id: `task-${Date.now()}`,
131
+ task: description,
132
+ agent,
133
+ status: 'active',
134
+ started: new Date().toISOString(),
135
+ paused: null,
136
+ resumed: null,
137
+ completed: null,
138
+ duration: null,
139
+ complexity,
140
+ dev: await this.getCurrentDev(),
141
+ }
142
+
143
+ await appendToStack(this.stackPath, entry)
144
+ await updateNowFile(this.nowPath, entry, null, formatDuration)
145
+
146
+ return entry
147
+ }
148
+
149
+ /**
150
+ * Pause the active task
151
+ */
152
+ async pauseTask(reason: string = ''): Promise<TaskEntry> {
153
+ const active = await this.getActiveTask()
154
+ if (!active) {
155
+ throw new Error('No active task to pause')
156
+ }
157
+
158
+ // Update the task
159
+ active.status = 'paused'
160
+ active.paused = new Date().toISOString()
161
+ if (reason) {
162
+ active.pauseReason = reason
163
+ }
164
+
165
+ // Rewrite stack with updated task
166
+ await this.updateTask(active)
167
+
168
+ // Update now.md to show paused state
169
+ await updateNowFile(this.nowPath, null, `Paused: ${active.task}`, formatDuration)
170
+
171
+ return active
172
+ }
173
+
174
+ /**
175
+ * Resume a paused task
176
+ */
177
+ async resumeTask(taskId: string | null = null): Promise<TaskEntry> {
178
+ // Check if there's an active task
179
+ const active = await this.getActiveTask()
180
+ if (active) {
181
+ throw new Error(`Already working on: ${active.task}. Complete or pause it first.`)
182
+ }
183
+
184
+ const paused = await this.getPausedTasks()
185
+ if (paused.length === 0) {
186
+ throw new Error('No paused tasks to resume')
187
+ }
188
+
189
+ let taskToResume: TaskEntry | undefined
190
+ if (taskId) {
191
+ taskToResume = paused.find((t) => t.id === taskId)
192
+ if (!taskToResume) {
193
+ throw new Error(`Task ${taskId} not found or not paused`)
194
+ }
195
+ } else {
196
+ // Resume most recently paused
197
+ taskToResume = paused[0]
198
+ }
199
+
200
+ // Update the task
201
+ taskToResume.status = 'active'
202
+ taskToResume.resumed = new Date().toISOString()
203
+
204
+ // Calculate paused duration
205
+ if (taskToResume.paused) {
206
+ const pausedMs = Date.now() - new Date(taskToResume.paused).getTime()
207
+ taskToResume.pausedDuration = (taskToResume.pausedDuration || 0) + pausedMs
208
+ }
209
+
210
+ // Rewrite stack with updated task
211
+ await this.updateTask(taskToResume)
212
+
213
+ // Update now.md
214
+ await updateNowFile(this.nowPath, taskToResume, null, formatDuration)
215
+
216
+ return taskToResume
217
+ }
218
+
219
+ /**
220
+ * Complete the active task
221
+ */
222
+ async completeTask(): Promise<TaskEntry> {
223
+ const active = await this.getActiveTask()
224
+ if (!active) {
225
+ throw new Error('No active task to complete')
226
+ }
227
+
228
+ // Update the task
229
+ active.status = 'completed'
230
+ active.completed = new Date().toISOString()
231
+
232
+ // Calculate duration (excluding paused time)
233
+ const totalMs = Date.now() - new Date(active.started).getTime()
234
+ const pausedMs = active.pausedDuration || 0
235
+ active.duration = totalMs - pausedMs
236
+ active.durationFormatted = formatDuration(active.duration)
237
+
238
+ // Rewrite stack with updated task
239
+ await this.updateTask(active)
240
+
241
+ // Clear now.md
242
+ await updateNowFile(this.nowPath, null, '', formatDuration)
243
+
244
+ return active
245
+ }
246
+
247
+ /**
248
+ * Switch tasks (atomic pause + resume/start)
249
+ */
250
+ async switchTask(targetTaskOrDescription: string): Promise<SwitchResult> {
251
+ const active = await this.getActiveTask()
252
+ let pausedTask: TaskEntry | null = null
253
+
254
+ // Pause current if exists
255
+ if (active) {
256
+ pausedTask = await this.pauseTask('Switched to another task')
257
+ }
258
+
259
+ try {
260
+ // Check if target is a task ID or description
261
+ const paused = await this.getPausedTasks()
262
+ const existingTask = paused.find((t) => t.id === targetTaskOrDescription)
263
+
264
+ if (existingTask) {
265
+ // Resume existing task
266
+ return {
267
+ paused: pausedTask,
268
+ resumed: await this.resumeTask(targetTaskOrDescription),
269
+ type: 'resumed',
270
+ }
271
+ } else {
272
+ // Start new task
273
+ return {
274
+ paused: pausedTask,
275
+ started: await this.startTask(targetTaskOrDescription),
276
+ type: 'started',
277
+ }
278
+ }
279
+ } catch (error) {
280
+ // If switch fails, resume the original task
281
+ if (pausedTask) {
282
+ await this.resumeTask(pausedTask.id)
283
+ }
284
+ throw error
285
+ }
286
+ }
287
+
288
+ /**
289
+ * Update a task in the stack
290
+ */
291
+ async updateTask(updatedTask: TaskEntry): Promise<void> {
292
+ const stack = await readStack(this.stackPath)
293
+ const index = stack.findIndex((t) => t.id === updatedTask.id)
294
+
295
+ if (index === -1) {
296
+ throw new Error(`Task ${updatedTask.id} not found`)
297
+ }
298
+
299
+ stack[index] = updatedTask
300
+ await writeStack(this.stackPath, stack)
301
+ }
302
+
303
+ /**
304
+ * Update now.md to reflect current state
305
+ */
306
+ async updateNowFile(task: TaskEntry | null, customContent: string | null = null): Promise<void> {
307
+ await updateNowFile(this.nowPath, task, customContent, formatDuration)
308
+ }
309
+
310
+ /**
311
+ * Get current developer from git or system
312
+ */
313
+ async getCurrentDev(): Promise<string> {
314
+ try {
315
+ const { stdout } = await execAsync('git config user.name')
316
+ return stdout.trim()
317
+ } catch {
318
+ return 'unknown'
319
+ }
320
+ }
321
+
322
+ /**
323
+ * Get stack summary for display
324
+ */
325
+ async getStackSummary(): Promise<StackSummary> {
326
+ const active = await this.getActiveTask()
327
+ const paused = await this.getPausedTasks()
328
+ const stack = await readStack(this.stackPath)
329
+ const completed = stack.filter((t) => t.status === 'completed')
330
+
331
+ return {
332
+ active,
333
+ paused,
334
+ pausedCount: paused.length,
335
+ completed,
336
+ completedCount: completed.length,
337
+ totalTasks: stack.length,
338
+ }
339
+ }
340
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Task Stack Types
3
+ */
4
+
5
+ export interface TaskEntry {
6
+ id: string
7
+ task: string
8
+ agent: string
9
+ status: 'active' | 'paused' | 'completed'
10
+ started: string
11
+ paused: string | null
12
+ resumed: string | null
13
+ completed: string | null
14
+ duration: number | null
15
+ durationFormatted?: string
16
+ complexity: string
17
+ dev: string
18
+ pauseReason?: string
19
+ pausedDuration?: number
20
+ }
21
+
22
+ export interface ParsedNowFile {
23
+ description: string
24
+ started: string | null
25
+ agent: string | null
26
+ complexity: string | null
27
+ dev: string | null
28
+ }
29
+
30
+ export interface MigrationResult {
31
+ migrated: boolean
32
+ hadTask?: boolean
33
+ task?: TaskEntry
34
+ error?: string
35
+ }
36
+
37
+ export interface SwitchResult {
38
+ paused: TaskEntry | null
39
+ resumed?: TaskEntry
40
+ started?: TaskEntry
41
+ type: 'resumed' | 'started'
42
+ }
43
+
44
+ export interface StackSummary {
45
+ active: TaskEntry | null
46
+ paused: TaskEntry[]
47
+ pausedCount: number
48
+ completed: TaskEntry[]
49
+ completedCount: number
50
+ totalTasks: number
51
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Task Stack Manager
3
+ * Re-exports from task-stack/index.ts for backwards compatibility.
4
+ */
5
+
6
+ import TaskStack from './task-stack/index'
7
+ export * from './task-stack/index'
8
+ export default TaskStack
@@ -4,17 +4,37 @@
4
4
  * This file is required by bin/prjct after setup verification
5
5
  */
6
6
 
7
- const { PrjctCommands } = require('./commands')
8
- const registry = require('./command-registry')
9
- const out = require('./utils/output')
7
+ import { PrjctCommands } from './commands'
8
+ import registry from './command-registry'
9
+ import out from './utils/output'
10
+
11
+ interface Command {
12
+ name: string
13
+ description: string
14
+ category: string
15
+ params?: string
16
+ implemented: boolean
17
+ deprecated?: boolean
18
+ replacedBy?: string
19
+ }
20
+
21
+ interface ParsedCommandArgs {
22
+ parsedArgs: string[]
23
+ options: Record<string, string | boolean>
24
+ }
25
+
26
+ interface CommandResult {
27
+ success?: boolean
28
+ message?: string
29
+ }
10
30
 
11
- async function main() {
31
+ async function main(): Promise<void> {
12
32
  const [commandName, ...rawArgs] = process.argv.slice(2)
13
33
 
14
34
  // === SPECIAL COMMANDS (version, help) ===
15
35
 
16
36
  if (['-v', '--version', 'version'].includes(commandName)) {
17
- const packageJson = require('../package.json')
37
+ const packageJson = await import('../package.json')
18
38
  console.log(`prjct-cli v${packageJson.version}`)
19
39
  process.exit(0)
20
40
  }
@@ -66,7 +86,7 @@ async function main() {
66
86
  const commands = new PrjctCommands()
67
87
 
68
88
  // 6. Execute command
69
- let result
89
+ let result: CommandResult | undefined
70
90
 
71
91
  // Commands with special option handling
72
92
  if (commandName === 'design') {
@@ -87,9 +107,32 @@ async function main() {
87
107
  const taskOrNumber = parsedArgs.join(' ')
88
108
  result = await commands.build(taskOrNumber)
89
109
  } else {
90
- // Standard commands
110
+ // Standard commands - type-safe invocation
91
111
  const param = parsedArgs.join(' ') || null
92
- result = await commands[commandName](param)
112
+ const standardCommands: Record<string, (p: string | null) => Promise<CommandResult>> = {
113
+ now: (p) => commands.now(p),
114
+ done: () => commands.done(),
115
+ next: () => commands.next(),
116
+ init: (p) => commands.init(p),
117
+ feature: (p) => commands.feature(p || ''),
118
+ bug: (p) => commands.bug(p || ''),
119
+ architect: (p) => commands.architect(p || 'execute'),
120
+ ship: (p) => commands.ship(p),
121
+ context: () => commands.context(),
122
+ recap: () => commands.recap(),
123
+ stuck: (p) => commands.stuck(p || ''),
124
+ roadmap: () => commands.roadmap(),
125
+ status: () => commands.status(),
126
+ sync: () => commands.sync(),
127
+ start: () => commands.start(),
128
+ }
129
+
130
+ const handler = standardCommands[commandName]
131
+ if (handler) {
132
+ result = await handler(param)
133
+ } else {
134
+ throw new Error(`Command '${commandName}' has no handler`)
135
+ }
93
136
  }
94
137
 
95
138
  // 7. Display result
@@ -101,9 +144,9 @@ async function main() {
101
144
  out.end()
102
145
  process.exit(result && result.success ? 0 : 1)
103
146
  } catch (error) {
104
- console.error('Error:', error.message)
147
+ console.error('Error:', (error as Error).message)
105
148
  if (process.env.DEBUG) {
106
- console.error(error.stack)
149
+ console.error((error as Error).stack)
107
150
  }
108
151
  // Show branding footer even on error
109
152
  out.end()
@@ -114,9 +157,9 @@ async function main() {
114
157
  /**
115
158
  * Parse command arguments dynamically
116
159
  */
117
- function parseCommandArgs(cmd, rawArgs) {
118
- const parsedArgs = []
119
- const options = {}
160
+ function parseCommandArgs(cmd: Command, rawArgs: string[]): ParsedCommandArgs {
161
+ const parsedArgs: string[] = []
162
+ const options: Record<string, string | boolean> = {}
120
163
 
121
164
  for (let i = 0; i < rawArgs.length; i++) {
122
165
  const arg = rawArgs[i]
@@ -142,12 +185,12 @@ function parseCommandArgs(cmd, rawArgs) {
142
185
  /**
143
186
  * Display help using registry
144
187
  */
145
- function displayHelp() {
188
+ function displayHelp(): void {
146
189
  const categories = registry.getCategories()
147
- const categorizedCommands = {}
190
+ const categorizedCommands: Record<string, Command[]> = {}
148
191
 
149
192
  // Group commands by category (exclude deprecated)
150
- registry.getTerminalCommands().forEach((cmd) => {
193
+ registry.getTerminalCommands().forEach((cmd: Command) => {
151
194
  if (cmd.deprecated) return
152
195
 
153
196
  if (!categorizedCommands[cmd.category]) {
@@ -181,9 +224,9 @@ function displayHelp() {
181
224
 
182
225
  // Run CLI
183
226
  main().catch((error) => {
184
- console.error('Fatal error:', error.message)
227
+ console.error('Fatal error:', (error as Error).message)
185
228
  if (process.env.DEBUG) {
186
- console.error(error.stack)
229
+ console.error((error as Error).stack)
187
230
  }
188
231
  process.exit(1)
189
232
  })
@@ -6,23 +6,61 @@
6
6
  * @version 0.5.0
7
7
  */
8
8
 
9
- const fs = require('fs')
10
- const path = require('path')
9
+ import fs from 'fs'
10
+ import path from 'path'
11
+
12
+ interface AgentCapabilities {
13
+ mcp: boolean
14
+ filesystem: string
15
+ markdown: boolean
16
+ emojis: boolean
17
+ colors: boolean
18
+ interactive: boolean
19
+ agents: boolean
20
+ }
21
+
22
+ interface AgentConfig {
23
+ configFile: string | null
24
+ commandPrefix: string
25
+ responseStyle: string
26
+ dataDir: string
27
+ agentsDir: string | null
28
+ commandsDir: string | null
29
+ }
30
+
31
+ interface AgentEnvironment {
32
+ hasMCP: boolean
33
+ sandboxed: boolean
34
+ persistent: boolean
35
+ agentSystem: boolean
36
+ }
37
+
38
+ interface AgentInfo {
39
+ type: string
40
+ name: string
41
+ isSupported: boolean
42
+ capabilities: AgentCapabilities
43
+ config: AgentConfig
44
+ environment: AgentEnvironment
45
+ }
46
+
47
+ declare const global: typeof globalThis & {
48
+ mcp?: {
49
+ filesystem?: unknown
50
+ }
51
+ }
11
52
 
12
53
  /**
13
54
  * Detects the current execution environment (Claude or Terminal).
14
55
  * Provides appropriate capabilities and configuration for each environment.
15
56
  */
16
57
  class AgentDetector {
17
- constructor() {
18
- this.detectedAgent = null
19
- }
58
+ private detectedAgent: AgentInfo | null = null
20
59
 
21
60
  /**
22
61
  * Main detection method - Claude or CLI fallback
23
- * @returns {Object} Agent information
24
62
  */
25
- async detect() {
63
+ async detect(): Promise<AgentInfo> {
26
64
  if (this.detectedAgent) {
27
65
  return this.detectedAgent
28
66
  }
@@ -40,9 +78,8 @@ class AgentDetector {
40
78
 
41
79
  /**
42
80
  * Check if running in Claude environment
43
- * @returns {boolean} True if Claude detected
44
81
  */
45
- isClaudeEnvironment() {
82
+ isClaudeEnvironment(): boolean {
46
83
  // Environment variables
47
84
  if (process.env.CLAUDE_AGENT || process.env.ANTHROPIC_CLAUDE) {
48
85
  return true
@@ -78,7 +115,7 @@ class AgentDetector {
78
115
  * Get Claude agent configuration
79
116
  * Works for both Claude Code and Claude Desktop
80
117
  */
81
- getClaudeAgent() {
118
+ getClaudeAgent(): AgentInfo {
82
119
  return {
83
120
  type: 'claude',
84
121
  name: 'Claude (Code + Desktop)',
@@ -112,7 +149,7 @@ class AgentDetector {
112
149
  /**
113
150
  * Get terminal agent configuration (fallback)
114
151
  */
115
- getTerminalAgent() {
152
+ getTerminalAgent(): AgentInfo {
116
153
  return {
117
154
  type: 'terminal',
118
155
  name: 'Terminal/CLI',
@@ -146,7 +183,7 @@ class AgentDetector {
146
183
  /**
147
184
  * Force set agent type (for testing)
148
185
  */
149
- setAgent(type) {
186
+ setAgent(type: string): AgentInfo {
150
187
  switch (type) {
151
188
  case 'claude':
152
189
  this.detectedAgent = this.getClaudeAgent()
@@ -162,26 +199,25 @@ class AgentDetector {
162
199
  /**
163
200
  * Reset detection (clear cache)
164
201
  */
165
- reset() {
202
+ reset(): void {
166
203
  this.detectedAgent = null
167
204
  }
168
205
 
169
206
  /**
170
207
  * Check if current environment is Claude
171
- * @returns {boolean} True if Claude
172
208
  */
173
- isClaude() {
209
+ isClaude(): boolean {
174
210
  const agent = this.detectedAgent || this.isClaudeEnvironment()
175
- return agent === true || (agent && agent.type === 'claude')
211
+ return agent === true || (typeof agent === 'object' && agent?.type === 'claude')
176
212
  }
177
213
 
178
214
  /**
179
215
  * Check if current environment is Terminal/CLI
180
- * @returns {boolean} True if terminal
181
216
  */
182
- isTerminal() {
217
+ isTerminal(): boolean {
183
218
  return !this.isClaude()
184
219
  }
185
220
  }
186
221
 
187
- module.exports = new AgentDetector()
222
+ const agentDetector = new AgentDetector()
223
+ export default agentDetector