prjct-cli 0.11.4 → 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 (385) hide show
  1. package/CHANGELOG.md +72 -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 +246 -54
  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.ts +405 -0
  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} +99 -89
  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} +35 -18
  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} +62 -23
  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 +203 -403
  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/BentoGrid/BentoGrid.tsx +18 -0
  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/EmptyState/EmptyState.tsx +58 -0
  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/IdeasCard/IdeasCard.tsx +48 -0
  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/ProgressRing/ProgressRing.tsx +51 -0
  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/RoadmapCard/RoadmapCard.tsx +77 -0
  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/ShipsCard/ShipsCard.tsx +52 -0
  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/SparklineChart/SparklineChart.tsx +38 -0
  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/StreakCard/StreakCard.tsx +53 -0
  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/components/ui/tooltip.tsx +2 -2
  333. package/packages/web/context/TerminalTabsContext.tsx +46 -1
  334. package/packages/web/hooks/useClaudeTerminal.ts +71 -21
  335. package/packages/web/hooks/useProjectStats.ts +55 -0
  336. package/packages/web/hooks/useProjects.ts +6 -6
  337. package/packages/web/lib/actions/projects.ts +15 -0
  338. package/packages/web/lib/json-loader.ts +630 -0
  339. package/packages/web/lib/services/index.ts +9 -0
  340. package/packages/web/lib/services/migration.server.ts +598 -0
  341. package/packages/web/lib/services/projects.server.ts +52 -0
  342. package/packages/web/lib/services/stats.server.ts +264 -0
  343. package/packages/web/lib/unified-loader.ts +396 -0
  344. package/packages/web/next-env.d.ts +1 -1
  345. package/packages/web/package.json +10 -6
  346. package/packages/web/server.ts +36 -6
  347. package/templates/commands/done.md +76 -32
  348. package/templates/commands/feature.md +121 -47
  349. package/templates/commands/idea.md +81 -8
  350. package/templates/commands/now.md +41 -17
  351. package/templates/commands/ship.md +64 -25
  352. package/templates/commands/sync.md +28 -3
  353. package/core/agentic/agent-router.js +0 -128
  354. package/core/agentic/chain-of-thought.js +0 -578
  355. package/core/agentic/command-executor.js +0 -421
  356. package/core/agentic/context-filter.js +0 -354
  357. package/core/agentic/ground-truth.js +0 -591
  358. package/core/agentic/loop-detector.js +0 -406
  359. package/core/agentic/memory-system.js +0 -850
  360. package/core/agentic/parallel-tools.js +0 -366
  361. package/core/agentic/plan-mode.js +0 -572
  362. package/core/agentic/prompt-builder.js +0 -338
  363. package/core/agentic/response-templates.js +0 -290
  364. package/core/agentic/semantic-compression.js +0 -517
  365. package/core/agentic/think-blocks.js +0 -657
  366. package/core/agentic/tool-registry.js +0 -184
  367. package/core/agentic/validation-rules.js +0 -380
  368. package/core/command-registry.js +0 -698
  369. package/core/commands.js +0 -2237
  370. package/core/domain/task-stack.js +0 -497
  371. package/core/infrastructure/legacy-installer-detector.js +0 -546
  372. package/core/infrastructure/migrator.js +0 -799
  373. package/core/infrastructure/session-manager.js +0 -390
  374. package/core/utils/file-helper.js +0 -329
  375. package/packages/web/app/api/projects/[id]/delete/route.ts +0 -21
  376. package/packages/web/app/api/stats/route.ts +0 -38
  377. package/packages/web/components/AppSidebar.tsx +0 -113
  378. package/packages/web/hooks/useStats.ts +0 -28
  379. /package/packages/web/components/{CommandButton.tsx → CommandButton/CommandButton.tsx} +0 -0
  380. /package/packages/web/components/{ConnectionStatus.tsx → ConnectionStatus/ConnectionStatus.tsx} +0 -0
  381. /package/packages/web/components/{Logo.tsx → Logo/Logo.tsx} +0 -0
  382. /package/packages/web/components/{MarkdownContent.tsx → MarkdownContent/MarkdownContent.tsx} +0 -0
  383. /package/packages/web/components/{ProjectAvatar.tsx → ProjectAvatar/ProjectAvatar.tsx} +0 -0
  384. /package/packages/web/components/{providers.tsx → Providers/Providers.tsx} +0 -0
  385. /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
  })
@@ -1,25 +1,66 @@
1
1
  /**
2
- * Agent Detection Module for prjct-cli
3
- *
4
- * 100% Claude-focused architecture
5
- * Detects Claude Code and Claude Desktop environments
2
+ * Agent Detector
3
+ * Detects Claude Code and Claude Desktop environments.
6
4
  *
5
+ * @module infrastructure/agent-detector
7
6
  * @version 0.5.0
8
7
  */
9
8
 
10
- const fs = require('fs')
11
- 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
+ }
12
21
 
13
- class AgentDetector {
14
- constructor() {
15
- this.detectedAgent = null
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
16
50
  }
51
+ }
52
+
53
+ /**
54
+ * Detects the current execution environment (Claude or Terminal).
55
+ * Provides appropriate capabilities and configuration for each environment.
56
+ */
57
+ class AgentDetector {
58
+ private detectedAgent: AgentInfo | null = null
17
59
 
18
60
  /**
19
61
  * Main detection method - Claude or CLI fallback
20
- * @returns {Object} Agent information
21
62
  */
22
- async detect() {
63
+ async detect(): Promise<AgentInfo> {
23
64
  if (this.detectedAgent) {
24
65
  return this.detectedAgent
25
66
  }
@@ -37,9 +78,8 @@ class AgentDetector {
37
78
 
38
79
  /**
39
80
  * Check if running in Claude environment
40
- * @returns {boolean} True if Claude detected
41
81
  */
42
- isClaudeEnvironment() {
82
+ isClaudeEnvironment(): boolean {
43
83
  // Environment variables
44
84
  if (process.env.CLAUDE_AGENT || process.env.ANTHROPIC_CLAUDE) {
45
85
  return true
@@ -75,7 +115,7 @@ class AgentDetector {
75
115
  * Get Claude agent configuration
76
116
  * Works for both Claude Code and Claude Desktop
77
117
  */
78
- getClaudeAgent() {
118
+ getClaudeAgent(): AgentInfo {
79
119
  return {
80
120
  type: 'claude',
81
121
  name: 'Claude (Code + Desktop)',
@@ -109,7 +149,7 @@ class AgentDetector {
109
149
  /**
110
150
  * Get terminal agent configuration (fallback)
111
151
  */
112
- getTerminalAgent() {
152
+ getTerminalAgent(): AgentInfo {
113
153
  return {
114
154
  type: 'terminal',
115
155
  name: 'Terminal/CLI',
@@ -143,7 +183,7 @@ class AgentDetector {
143
183
  /**
144
184
  * Force set agent type (for testing)
145
185
  */
146
- setAgent(type) {
186
+ setAgent(type: string): AgentInfo {
147
187
  switch (type) {
148
188
  case 'claude':
149
189
  this.detectedAgent = this.getClaudeAgent()
@@ -159,26 +199,25 @@ class AgentDetector {
159
199
  /**
160
200
  * Reset detection (clear cache)
161
201
  */
162
- reset() {
202
+ reset(): void {
163
203
  this.detectedAgent = null
164
204
  }
165
205
 
166
206
  /**
167
207
  * Check if current environment is Claude
168
- * @returns {boolean} True if Claude
169
208
  */
170
- isClaude() {
209
+ isClaude(): boolean {
171
210
  const agent = this.detectedAgent || this.isClaudeEnvironment()
172
- return agent === true || (agent && agent.type === 'claude')
211
+ return agent === true || (typeof agent === 'object' && agent?.type === 'claude')
173
212
  }
174
213
 
175
214
  /**
176
215
  * Check if current environment is Terminal/CLI
177
- * @returns {boolean} True if terminal
178
216
  */
179
- isTerminal() {
217
+ isTerminal(): boolean {
180
218
  return !this.isClaude()
181
219
  }
182
220
  }
183
221
 
184
- module.exports = new AgentDetector()
222
+ const agentDetector = new AgentDetector()
223
+ export default agentDetector