@dyyz1993/create-agent 1.9.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 (358) hide show
  1. package/package.json +25 -0
  2. package/src/__tests__/cli.test.ts +85 -0
  3. package/src/__tests__/copy.test.ts +168 -0
  4. package/src/__tests__/templates.test.ts +87 -0
  5. package/src/cli.ts +65 -0
  6. package/src/commands/create.ts +49 -0
  7. package/src/commands/list.ts +12 -0
  8. package/src/commands/status.ts +85 -0
  9. package/src/commands/workspace.ts +129 -0
  10. package/src/lib/copy.ts +285 -0
  11. package/src/lib/templates.ts +57 -0
  12. package/src/lib/types.ts +6 -0
  13. package/templates/agent/.env.example +7 -0
  14. package/templates/agent/LICENSE +21 -0
  15. package/templates/agent/README.md +87 -0
  16. package/templates/agent/bun.lock +1279 -0
  17. package/templates/agent/electrobun.config.ts +27 -0
  18. package/templates/agent/eslint.config.mjs +63 -0
  19. package/templates/agent/llms.txt +24 -0
  20. package/templates/agent/package-lock.json +3670 -0
  21. package/templates/agent/package.json +59 -0
  22. package/templates/agent/postcss.config.js +6 -0
  23. package/templates/agent/scripts/dev.ts +138 -0
  24. package/templates/agent/src/__tests__/server-config.test.ts +59 -0
  25. package/templates/agent/src/bun/index.ts +73 -0
  26. package/templates/agent/src/gateway/__tests__/ws-handler.test.ts +48 -0
  27. package/templates/agent/src/gateway/http-routes.ts +1 -0
  28. package/templates/agent/src/gateway/ipc-transport.ts +68 -0
  29. package/templates/agent/src/gateway/ws-handler.ts +86 -0
  30. package/templates/agent/src/mainview/App.tsx +41 -0
  31. package/templates/agent/src/mainview/__tests__/components/ChatPanel.test.tsx +114 -0
  32. package/templates/agent/src/mainview/__tests__/components/ExplorerSidebar.test.tsx +141 -0
  33. package/templates/agent/src/mainview/__tests__/components/MessageBubble.test.tsx +72 -0
  34. package/templates/agent/src/mainview/__tests__/hooks/use-input-history.test.ts +125 -0
  35. package/templates/agent/src/mainview/__tests__/hooks/use-rpc-init.test.ts +217 -0
  36. package/templates/agent/src/mainview/__tests__/hooks/use-sidebar-resize.test.ts +127 -0
  37. package/templates/agent/src/mainview/__tests__/i18n/i18n.test.ts +48 -0
  38. package/templates/agent/src/mainview/__tests__/setup.ts +37 -0
  39. package/templates/agent/src/mainview/__tests__/stores/use-chat-store.test.ts +83 -0
  40. package/templates/agent/src/mainview/__tests__/stores/use-sidebar-store.test.ts +85 -0
  41. package/templates/agent/src/mainview/components/activity-bar/ActivityBar.tsx +36 -0
  42. package/templates/agent/src/mainview/components/activity-bar/MobileTabBar.tsx +36 -0
  43. package/templates/agent/src/mainview/components/activity-bar/__tests__/ActivityBar.test.tsx +44 -0
  44. package/templates/agent/src/mainview/components/activity-bar/__tests__/MobileTabBar.test.tsx +44 -0
  45. package/templates/agent/src/mainview/components/bash/BashPanel.tsx +206 -0
  46. package/templates/agent/src/mainview/components/bash/__tests__/BashPanel.test.tsx +103 -0
  47. package/templates/agent/src/mainview/components/chat/ChatPanel.tsx +102 -0
  48. package/templates/agent/src/mainview/components/chat/MessageBubble.tsx +86 -0
  49. package/templates/agent/src/mainview/components/common/ErrorBoundary.tsx +58 -0
  50. package/templates/agent/src/mainview/components/common/LanguageSwitcher.tsx +14 -0
  51. package/templates/agent/src/mainview/components/common/ThemeToggle.tsx +24 -0
  52. package/templates/agent/src/mainview/components/common/__tests__/ErrorBoundary.test.tsx +74 -0
  53. package/templates/agent/src/mainview/components/common/__tests__/LanguageSwitcher.test.tsx +44 -0
  54. package/templates/agent/src/mainview/components/common/__tests__/ThemeToggle.test.tsx +41 -0
  55. package/templates/agent/src/mainview/components/debug/DebugPanel.tsx +120 -0
  56. package/templates/agent/src/mainview/components/debug/__tests__/DebugPanel.test.tsx +102 -0
  57. package/templates/agent/src/mainview/components/diff/DiffViewerPanel.tsx +106 -0
  58. package/templates/agent/src/mainview/components/diff/__tests__/DiffViewerPanel.test.tsx +73 -0
  59. package/templates/agent/src/mainview/components/explorer/ConfirmDialog.tsx +53 -0
  60. package/templates/agent/src/mainview/components/explorer/ContextMenu.tsx +82 -0
  61. package/templates/agent/src/mainview/components/explorer/ExplorerSidebar.tsx +221 -0
  62. package/templates/agent/src/mainview/components/explorer/InlineInput.tsx +55 -0
  63. package/templates/agent/src/mainview/components/explorer/TreeNodeItem.tsx +121 -0
  64. package/templates/agent/src/mainview/components/explorer/__tests__/ConfirmDialog.test.tsx +37 -0
  65. package/templates/agent/src/mainview/components/explorer/__tests__/ContextMenu.test.tsx +49 -0
  66. package/templates/agent/src/mainview/components/explorer/__tests__/InlineInput.test.tsx +48 -0
  67. package/templates/agent/src/mainview/components/explorer/__tests__/TreeNodeItem.test.tsx +146 -0
  68. package/templates/agent/src/mainview/components/feed/FeedPanel.tsx +239 -0
  69. package/templates/agent/src/mainview/components/feed/__tests__/FeedPanel.test.tsx +108 -0
  70. package/templates/agent/src/mainview/components/file-preview/FilePreviewOverlay.tsx +56 -0
  71. package/templates/agent/src/mainview/components/file-preview/VirtualizedCodeView.tsx +99 -0
  72. package/templates/agent/src/mainview/components/file-preview/__tests__/FilePreviewOverlay.test.tsx +96 -0
  73. package/templates/agent/src/mainview/components/file-preview/__tests__/VirtualizedCodeView.test.tsx +58 -0
  74. package/templates/agent/src/mainview/components/git/GitBranchSelector.tsx +98 -0
  75. package/templates/agent/src/mainview/components/git/GitCommitInput.tsx +60 -0
  76. package/templates/agent/src/mainview/components/git/GitPanel.tsx +528 -0
  77. package/templates/agent/src/mainview/components/git/__tests__/GitBranchSelector.test.tsx +76 -0
  78. package/templates/agent/src/mainview/components/git/__tests__/GitCommitInput.test.tsx +91 -0
  79. package/templates/agent/src/mainview/components/git/__tests__/GitPanel.test.tsx +174 -0
  80. package/templates/agent/src/mainview/components/layout/AppLayout.tsx +170 -0
  81. package/templates/agent/src/mainview/components/layout/__tests__/AppLayout.test.tsx +163 -0
  82. package/templates/agent/src/mainview/components/rules/RulesPanel.tsx +117 -0
  83. package/templates/agent/src/mainview/components/rules/__tests__/RulesPanel.test.tsx +91 -0
  84. package/templates/agent/src/mainview/components/search/SearchPanel.tsx +404 -0
  85. package/templates/agent/src/mainview/components/search/__tests__/SearchPanel.test.tsx +50 -0
  86. package/templates/agent/src/mainview/components/sidebar/PinButton.tsx +20 -0
  87. package/templates/agent/src/mainview/components/sidebar/__tests__/PinButton.test.tsx +48 -0
  88. package/templates/agent/src/mainview/components/todo/TodoPanel.tsx +141 -0
  89. package/templates/agent/src/mainview/components/todo/__tests__/TodoPanel.test.tsx +91 -0
  90. package/templates/agent/src/mainview/global.d.ts +13 -0
  91. package/templates/agent/src/mainview/hooks/__tests__/use-breakpoint.test.ts +147 -0
  92. package/templates/agent/src/mainview/hooks/use-breakpoint.ts +34 -0
  93. package/templates/agent/src/mainview/hooks/use-input-history.ts +84 -0
  94. package/templates/agent/src/mainview/hooks/use-rpc-init.ts +61 -0
  95. package/templates/agent/src/mainview/hooks/use-sidebar-resize.ts +40 -0
  96. package/templates/agent/src/mainview/index.css +61 -0
  97. package/templates/agent/src/mainview/index.html +12 -0
  98. package/templates/agent/src/mainview/lib/api-client.ts +192 -0
  99. package/templates/agent/src/mainview/lib/i18n/index.ts +30 -0
  100. package/templates/agent/src/mainview/lib/i18n/locales/en.json +157 -0
  101. package/templates/agent/src/mainview/lib/i18n/locales/zh.json +157 -0
  102. package/templates/agent/src/mainview/lib/rpc-cache.ts +94 -0
  103. package/templates/agent/src/mainview/main.tsx +24 -0
  104. package/templates/agent/src/mainview/stores/__tests__/use-app-store.test.ts +86 -0
  105. package/templates/agent/src/mainview/stores/__tests__/use-bash-store.test.ts +99 -0
  106. package/templates/agent/src/mainview/stores/__tests__/use-connection-store.test.ts +26 -0
  107. package/templates/agent/src/mainview/stores/__tests__/use-explorer-store.test.ts +130 -0
  108. package/templates/agent/src/mainview/stores/__tests__/use-feed-store.test.ts +132 -0
  109. package/templates/agent/src/mainview/stores/__tests__/use-git-store.test.ts +161 -0
  110. package/templates/agent/src/mainview/stores/__tests__/use-locale-store.test.ts +32 -0
  111. package/templates/agent/src/mainview/stores/__tests__/use-log-store.test.ts +28 -0
  112. package/templates/agent/src/mainview/stores/__tests__/use-notification-store.test.ts +102 -0
  113. package/templates/agent/src/mainview/stores/__tests__/use-rules-store.test.ts +75 -0
  114. package/templates/agent/src/mainview/stores/__tests__/use-theme-store.test.ts +59 -0
  115. package/templates/agent/src/mainview/stores/__tests__/use-todo-store.test.ts +75 -0
  116. package/templates/agent/src/mainview/stores/message-batcher.ts +25 -0
  117. package/templates/agent/src/mainview/stores/use-app-store.ts +99 -0
  118. package/templates/agent/src/mainview/stores/use-bash-store.ts +93 -0
  119. package/templates/agent/src/mainview/stores/use-chat-store.ts +37 -0
  120. package/templates/agent/src/mainview/stores/use-connection-store.ts +42 -0
  121. package/templates/agent/src/mainview/stores/use-explorer-store.ts +320 -0
  122. package/templates/agent/src/mainview/stores/use-feed-store.ts +129 -0
  123. package/templates/agent/src/mainview/stores/use-git-store.ts +291 -0
  124. package/templates/agent/src/mainview/stores/use-locale-store.ts +27 -0
  125. package/templates/agent/src/mainview/stores/use-log-store.ts +16 -0
  126. package/templates/agent/src/mainview/stores/use-notification-store.ts +82 -0
  127. package/templates/agent/src/mainview/stores/use-rules-store.ts +54 -0
  128. package/templates/agent/src/mainview/stores/use-sidebar-store.ts +99 -0
  129. package/templates/agent/src/mainview/stores/use-theme-store.ts +46 -0
  130. package/templates/agent/src/mainview/stores/use-todo-store.ts +54 -0
  131. package/templates/agent/src/mainview/types/index.ts +33 -0
  132. package/templates/agent/src/mainview/utils/constants.ts +1 -0
  133. package/templates/agent/src/mainview/utils/drop-handler.ts +150 -0
  134. package/templates/agent/src/mainview/utils/file-icon.tsx +24 -0
  135. package/templates/agent/src/mainview/utils/file-utils.ts +35 -0
  136. package/templates/agent/src/server-config.ts +43 -0
  137. package/templates/agent/src/server.ts +89 -0
  138. package/templates/agent/src/shared/handlers/__tests__/bash-handler.test.ts +135 -0
  139. package/templates/agent/src/shared/handlers/__tests__/chat-handler.test.ts +77 -0
  140. package/templates/agent/src/shared/handlers/__tests__/feed-handler.test.ts +108 -0
  141. package/templates/agent/src/shared/handlers/__tests__/file-handler.test.ts +100 -0
  142. package/templates/agent/src/shared/handlers/__tests__/system-handler.test.ts +55 -0
  143. package/templates/agent/src/shared/handlers/__tests__/timer-handler.test.ts +77 -0
  144. package/templates/agent/src/shared/handlers/bash.ts +89 -0
  145. package/templates/agent/src/shared/handlers/chat.ts +179 -0
  146. package/templates/agent/src/shared/handlers/feed.ts +53 -0
  147. package/templates/agent/src/shared/handlers/file.ts +99 -0
  148. package/templates/agent/src/shared/handlers/git.ts +263 -0
  149. package/templates/agent/src/shared/handlers/index.ts +10 -0
  150. package/templates/agent/src/shared/handlers/rules.ts +45 -0
  151. package/templates/agent/src/shared/handlers/system.ts +27 -0
  152. package/templates/agent/src/shared/handlers/timer.ts +34 -0
  153. package/templates/agent/src/shared/handlers/todo.ts +45 -0
  154. package/templates/agent/src/shared/lib/__tests__/bash-security.test.ts +125 -0
  155. package/templates/agent/src/shared/lib/__tests__/logger.test.ts +92 -0
  156. package/templates/agent/src/shared/lib/__tests__/path-security.test.ts +77 -0
  157. package/templates/agent/src/shared/lib/bash-security.ts +64 -0
  158. package/templates/agent/src/shared/lib/logger.ts +130 -0
  159. package/templates/agent/src/shared/lib/path-security.ts +38 -0
  160. package/templates/agent/src/shared/lib/port-registry.ts +103 -0
  161. package/templates/agent/src/shared/modules/bash.ts +19 -0
  162. package/templates/agent/src/shared/modules/chat.ts +20 -0
  163. package/templates/agent/src/shared/modules/feed.ts +30 -0
  164. package/templates/agent/src/shared/modules/file.ts +40 -0
  165. package/templates/agent/src/shared/modules/git.ts +81 -0
  166. package/templates/agent/src/shared/modules/rules.ts +25 -0
  167. package/templates/agent/src/shared/modules/system.ts +8 -0
  168. package/templates/agent/src/shared/modules/timer.ts +11 -0
  169. package/templates/agent/src/shared/modules/todo.ts +27 -0
  170. package/templates/agent/src/shared/register-all-handlers.ts +36 -0
  171. package/templates/agent/src/shared/rpc-schema.ts +35 -0
  172. package/templates/agent/tailwind.config.js +15 -0
  173. package/templates/agent/tsconfig.json +26 -0
  174. package/templates/agent/vite.config.ts +3 -0
  175. package/templates/agent/vitest.config.ts +3 -0
  176. package/templates/chat/.env.example +6 -0
  177. package/templates/chat/LICENSE +21 -0
  178. package/templates/chat/README.md +56 -0
  179. package/templates/chat/bun.lock +1203 -0
  180. package/templates/chat/electrobun.config.ts +27 -0
  181. package/templates/chat/eslint.config.mjs +56 -0
  182. package/templates/chat/llms.txt +24 -0
  183. package/templates/chat/package-lock.json +3670 -0
  184. package/templates/chat/package.json +58 -0
  185. package/templates/chat/postcss.config.js +6 -0
  186. package/templates/chat/scripts/dev.ts +138 -0
  187. package/templates/chat/src/__tests__/server-config.test.ts +59 -0
  188. package/templates/chat/src/bun/index.ts +72 -0
  189. package/templates/chat/src/gateway/__tests__/ws-handler.test.ts +48 -0
  190. package/templates/chat/src/gateway/http-routes.ts +1 -0
  191. package/templates/chat/src/gateway/ipc-transport.ts +68 -0
  192. package/templates/chat/src/gateway/ws-handler.ts +86 -0
  193. package/templates/chat/src/mainview/App.tsx +108 -0
  194. package/templates/chat/src/mainview/__tests__/components/ChatPanel.test.tsx +76 -0
  195. package/templates/chat/src/mainview/__tests__/components/MessageBubble.test.tsx +48 -0
  196. package/templates/chat/src/mainview/__tests__/i18n/i18n.test.ts +48 -0
  197. package/templates/chat/src/mainview/__tests__/setup-verify.test.ts +8 -0
  198. package/templates/chat/src/mainview/__tests__/setup.ts +37 -0
  199. package/templates/chat/src/mainview/__tests__/stores/use-app-store.test.ts +46 -0
  200. package/templates/chat/src/mainview/__tests__/stores/use-chat-store.test.ts +104 -0
  201. package/templates/chat/src/mainview/__tests__/stores/use-connection-store.test.ts +35 -0
  202. package/templates/chat/src/mainview/__tests__/stores/use-log-store.test.ts +45 -0
  203. package/templates/chat/src/mainview/__tests__/stores/use-notification-store.test.ts +102 -0
  204. package/templates/chat/src/mainview/__tests__/stores/use-sidebar-store.test.ts +89 -0
  205. package/templates/chat/src/mainview/components/activity-bar/ActivityBar.tsx +26 -0
  206. package/templates/chat/src/mainview/components/activity-bar/MobileTabBar.tsx +20 -0
  207. package/templates/chat/src/mainview/components/chat/ChatPanel.tsx +66 -0
  208. package/templates/chat/src/mainview/components/chat/MessageBubble.tsx +85 -0
  209. package/templates/chat/src/mainview/components/common/LanguageSwitcher.tsx +15 -0
  210. package/templates/chat/src/mainview/components/common/ThemeToggle.tsx +24 -0
  211. package/templates/chat/src/mainview/components/sidebar/PinButton.tsx +20 -0
  212. package/templates/chat/src/mainview/global.d.ts +13 -0
  213. package/templates/chat/src/mainview/hooks/use-breakpoint.ts +34 -0
  214. package/templates/chat/src/mainview/hooks/use-input-history.ts +84 -0
  215. package/templates/chat/src/mainview/index.css +61 -0
  216. package/templates/chat/src/mainview/index.html +12 -0
  217. package/templates/chat/src/mainview/lib/api-client.ts +175 -0
  218. package/templates/chat/src/mainview/lib/i18n/index.ts +30 -0
  219. package/templates/chat/src/mainview/lib/i18n/locales/en.json +157 -0
  220. package/templates/chat/src/mainview/lib/i18n/locales/zh.json +157 -0
  221. package/templates/chat/src/mainview/main.tsx +20 -0
  222. package/templates/chat/src/mainview/stores/__tests__/use-locale-store.test.ts +32 -0
  223. package/templates/chat/src/mainview/stores/__tests__/use-theme-store.test.ts +59 -0
  224. package/templates/chat/src/mainview/stores/message-batcher.ts +25 -0
  225. package/templates/chat/src/mainview/stores/use-app-store.ts +50 -0
  226. package/templates/chat/src/mainview/stores/use-chat-store.ts +37 -0
  227. package/templates/chat/src/mainview/stores/use-connection-store.ts +42 -0
  228. package/templates/chat/src/mainview/stores/use-locale-store.ts +27 -0
  229. package/templates/chat/src/mainview/stores/use-log-store.ts +16 -0
  230. package/templates/chat/src/mainview/stores/use-notification-store.ts +82 -0
  231. package/templates/chat/src/mainview/stores/use-sidebar-store.ts +98 -0
  232. package/templates/chat/src/mainview/stores/use-theme-store.ts +46 -0
  233. package/templates/chat/src/mainview/types/index.ts +8 -0
  234. package/templates/chat/src/mainview/utils/constants.ts +1 -0
  235. package/templates/chat/src/server-config.ts +42 -0
  236. package/templates/chat/src/server.ts +89 -0
  237. package/templates/chat/src/shared/__tests__/chat-handler.test.ts +71 -0
  238. package/templates/chat/src/shared/__tests__/system-handler.test.ts +70 -0
  239. package/templates/chat/src/shared/handlers/chat.ts +186 -0
  240. package/templates/chat/src/shared/handlers/index.ts +2 -0
  241. package/templates/chat/src/shared/handlers/system.ts +27 -0
  242. package/templates/chat/src/shared/lib/logger.ts +130 -0
  243. package/templates/chat/src/shared/lib/path-security.ts +38 -0
  244. package/templates/chat/src/shared/lib/port-registry.ts +103 -0
  245. package/templates/chat/src/shared/modules/chat.ts +20 -0
  246. package/templates/chat/src/shared/modules/system.ts +8 -0
  247. package/templates/chat/src/shared/register-all-handlers.ts +36 -0
  248. package/templates/chat/src/shared/rpc-schema.ts +11 -0
  249. package/templates/chat/tailwind.config.js +15 -0
  250. package/templates/chat/tsconfig.json +26 -0
  251. package/templates/chat/vite.config.ts +3 -0
  252. package/templates/chat/vitest.config.ts +3 -0
  253. package/templates/general/.env.example +7 -0
  254. package/templates/general/LICENSE +21 -0
  255. package/templates/general/README.md +113 -0
  256. package/templates/general/bun.lock +1266 -0
  257. package/templates/general/electrobun.config.ts +27 -0
  258. package/templates/general/eslint.config.mjs +56 -0
  259. package/templates/general/llms.txt +24 -0
  260. package/templates/general/package-lock.json +3670 -0
  261. package/templates/general/package.json +59 -0
  262. package/templates/general/postcss.config.js +6 -0
  263. package/templates/general/scripts/dev.ts +138 -0
  264. package/templates/general/src/__tests__/server-config.test.ts +59 -0
  265. package/templates/general/src/bun/index.ts +72 -0
  266. package/templates/general/src/gateway/http-routes.ts +1 -0
  267. package/templates/general/src/gateway/ipc-transport.ts +68 -0
  268. package/templates/general/src/gateway/ws-handler.ts +86 -0
  269. package/templates/general/src/mainview/App.tsx +40 -0
  270. package/templates/general/src/mainview/__tests__/components/ChatPanel.test.tsx +82 -0
  271. package/templates/general/src/mainview/__tests__/components/FeedPanel.test.tsx +109 -0
  272. package/templates/general/src/mainview/__tests__/components/GitPanel.test.tsx +151 -0
  273. package/templates/general/src/mainview/__tests__/i18n/i18n.test.ts +48 -0
  274. package/templates/general/src/mainview/__tests__/setup-verify.test.ts +8 -0
  275. package/templates/general/src/mainview/__tests__/setup.ts +37 -0
  276. package/templates/general/src/mainview/components/activity-bar/ActivityBar.tsx +40 -0
  277. package/templates/general/src/mainview/components/activity-bar/MobileTabBar.tsx +29 -0
  278. package/templates/general/src/mainview/components/chat/ChatPanel.tsx +66 -0
  279. package/templates/general/src/mainview/components/chat/MessageBubble.tsx +85 -0
  280. package/templates/general/src/mainview/components/common/LanguageSwitcher.tsx +15 -0
  281. package/templates/general/src/mainview/components/common/ThemeToggle.tsx +24 -0
  282. package/templates/general/src/mainview/components/debug/DebugPanel.tsx +176 -0
  283. package/templates/general/src/mainview/components/diff/DiffViewerPanel.tsx +108 -0
  284. package/templates/general/src/mainview/components/explorer/ConfirmDialog.tsx +52 -0
  285. package/templates/general/src/mainview/components/explorer/ContextMenu.tsx +82 -0
  286. package/templates/general/src/mainview/components/explorer/ExplorerSidebar.tsx +225 -0
  287. package/templates/general/src/mainview/components/explorer/InlineInput.tsx +55 -0
  288. package/templates/general/src/mainview/components/explorer/TreeNodeItem.tsx +121 -0
  289. package/templates/general/src/mainview/components/feed/FeedPanel.tsx +248 -0
  290. package/templates/general/src/mainview/components/file-preview/FilePreviewOverlay.tsx +55 -0
  291. package/templates/general/src/mainview/components/file-preview/VirtualizedCodeView.tsx +99 -0
  292. package/templates/general/src/mainview/components/git/GitBranchSelector.tsx +93 -0
  293. package/templates/general/src/mainview/components/git/GitCommitInput.tsx +60 -0
  294. package/templates/general/src/mainview/components/git/GitPanel.tsx +533 -0
  295. package/templates/general/src/mainview/components/layout/AppLayout.tsx +146 -0
  296. package/templates/general/src/mainview/components/search/SearchPanel.tsx +405 -0
  297. package/templates/general/src/mainview/components/sidebar/PinButton.tsx +20 -0
  298. package/templates/general/src/mainview/global.d.ts +13 -0
  299. package/templates/general/src/mainview/hooks/use-breakpoint.ts +34 -0
  300. package/templates/general/src/mainview/hooks/use-input-history.ts +84 -0
  301. package/templates/general/src/mainview/hooks/use-rpc-init.ts +61 -0
  302. package/templates/general/src/mainview/hooks/use-sidebar-resize.ts +40 -0
  303. package/templates/general/src/mainview/index.css +61 -0
  304. package/templates/general/src/mainview/index.html +12 -0
  305. package/templates/general/src/mainview/lib/api-client.ts +175 -0
  306. package/templates/general/src/mainview/lib/i18n/index.ts +30 -0
  307. package/templates/general/src/mainview/lib/i18n/locales/en.json +157 -0
  308. package/templates/general/src/mainview/lib/i18n/locales/zh.json +157 -0
  309. package/templates/general/src/mainview/main.tsx +20 -0
  310. package/templates/general/src/mainview/stores/__tests__/use-chat-store.test.ts +104 -0
  311. package/templates/general/src/mainview/stores/__tests__/use-connection-store.test.ts +35 -0
  312. package/templates/general/src/mainview/stores/__tests__/use-locale-store.test.ts +32 -0
  313. package/templates/general/src/mainview/stores/__tests__/use-log-store.test.ts +45 -0
  314. package/templates/general/src/mainview/stores/__tests__/use-theme-store.test.ts +59 -0
  315. package/templates/general/src/mainview/stores/message-batcher.ts +25 -0
  316. package/templates/general/src/mainview/stores/use-app-store.ts +104 -0
  317. package/templates/general/src/mainview/stores/use-chat-store.ts +37 -0
  318. package/templates/general/src/mainview/stores/use-connection-store.ts +42 -0
  319. package/templates/general/src/mainview/stores/use-explorer-store.ts +315 -0
  320. package/templates/general/src/mainview/stores/use-feed-store.ts +129 -0
  321. package/templates/general/src/mainview/stores/use-git-store.ts +284 -0
  322. package/templates/general/src/mainview/stores/use-locale-store.ts +27 -0
  323. package/templates/general/src/mainview/stores/use-log-store.ts +16 -0
  324. package/templates/general/src/mainview/stores/use-notification-store.ts +82 -0
  325. package/templates/general/src/mainview/stores/use-sidebar-store.ts +99 -0
  326. package/templates/general/src/mainview/stores/use-theme-store.ts +46 -0
  327. package/templates/general/src/mainview/types/index.ts +33 -0
  328. package/templates/general/src/mainview/utils/constants.ts +1 -0
  329. package/templates/general/src/mainview/utils/drop-handler.ts +150 -0
  330. package/templates/general/src/mainview/utils/file-icon.tsx +24 -0
  331. package/templates/general/src/mainview/utils/file-utils.ts +35 -0
  332. package/templates/general/src/server-config.ts +42 -0
  333. package/templates/general/src/server.ts +89 -0
  334. package/templates/general/src/shared/handlers/__tests__/chat.test.ts +183 -0
  335. package/templates/general/src/shared/handlers/__tests__/system.test.ts +94 -0
  336. package/templates/general/src/shared/handlers/__tests__/timer.test.ts +113 -0
  337. package/templates/general/src/shared/handlers/chat.ts +179 -0
  338. package/templates/general/src/shared/handlers/feed.ts +53 -0
  339. package/templates/general/src/shared/handlers/file.ts +99 -0
  340. package/templates/general/src/shared/handlers/git.ts +263 -0
  341. package/templates/general/src/shared/handlers/index.ts +7 -0
  342. package/templates/general/src/shared/handlers/system.ts +27 -0
  343. package/templates/general/src/shared/handlers/timer.ts +34 -0
  344. package/templates/general/src/shared/lib/logger.ts +130 -0
  345. package/templates/general/src/shared/lib/path-security.ts +38 -0
  346. package/templates/general/src/shared/lib/port-registry.ts +103 -0
  347. package/templates/general/src/shared/modules/chat.ts +20 -0
  348. package/templates/general/src/shared/modules/feed.ts +30 -0
  349. package/templates/general/src/shared/modules/file.ts +40 -0
  350. package/templates/general/src/shared/modules/git.ts +81 -0
  351. package/templates/general/src/shared/modules/system.ts +8 -0
  352. package/templates/general/src/shared/modules/timer.ts +11 -0
  353. package/templates/general/src/shared/register-all-handlers.ts +36 -0
  354. package/templates/general/src/shared/rpc-schema.ts +31 -0
  355. package/templates/general/tailwind.config.js +15 -0
  356. package/templates/general/tsconfig.json +26 -0
  357. package/templates/general/vite.config.ts +3 -0
  358. package/templates/general/vitest.config.ts +3 -0
package/package.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "@dyyz1993/create-agent",
3
+ "version": "1.9.0",
4
+ "description": "Create Agent project scaffolding CLI",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/dyyz1993/pi-agent-template"
8
+ },
9
+ "bin": {
10
+ "create-agent": "./src/cli.ts"
11
+ },
12
+ "files": [
13
+ "src/",
14
+ "templates/"
15
+ ],
16
+ "scripts": {
17
+ "sync-templates": "rm -rf templates/general templates/chat templates/agent && rsync -a --exclude='node_modules' --exclude='dist' --exclude='build' --exclude='.server-port' --exclude='logs' --exclude='bun.lock' ../../templates/general/ templates/general/ && rsync -a --exclude='node_modules' --exclude='dist' --exclude='build' --exclude='.server-port' --exclude='logs' --exclude='bun.lock' ../../templates/chat/ templates/chat/ && rsync -a --exclude='node_modules' --exclude='dist' --exclude='build' --exclude='.server-port' --exclude='logs' --exclude='bun.lock' ../../templates/agent/ templates/agent/ && rsync -a ../../packages/eslint-plugin-rpc/ templates/agent/eslint-plugin-rpc/ && rsync -a ../../packages/eslint-plugin-rpc/ templates/chat/eslint-plugin-rpc/ && rsync -a ../../packages/eslint-plugin-rpc/ templates/general/eslint-plugin-rpc/ && node scripts/post-sync-templates.mjs",
18
+ "test": "bun test src/__tests__/",
19
+ "prepublishOnly": "test -d templates/general/src && test -d templates/chat/src && test -d templates/agent/src"
20
+ },
21
+ "engines": {
22
+ "bun": ">=1.0.0"
23
+ },
24
+ "license": "MIT"
25
+ }
@@ -0,0 +1,85 @@
1
+ import { describe, test, expect, spyOn } from 'bun:test';
2
+ import { runCreate } from '../commands/create';
3
+ import { runList } from '../commands/list';
4
+
5
+ describe('CLI argument parsing (create)', () => {
6
+ test('runCreate exits without project name', async () => {
7
+ const mockExit = spyOn(process, 'exit').mockImplementation(() => {
8
+ throw new Error('process.exit');
9
+ });
10
+ const mockLog = spyOn(console, 'log').mockImplementation(() => {});
11
+
12
+ try {
13
+ await runCreate([]);
14
+ } catch (e: unknown) {
15
+ expect((e as Error).message).toBe('process.exit');
16
+ }
17
+
18
+ expect(mockExit).toHaveBeenCalledWith(1);
19
+ mockExit.mockRestore();
20
+ mockLog.mockRestore();
21
+ });
22
+
23
+ test('runCreate throws for invalid --type', async () => {
24
+ expect(runCreate(['my-app', '--type', 'nonexistent'])).rejects.toThrow(
25
+ 'Unknown template type',
26
+ );
27
+ });
28
+
29
+ test('runCreate shows usage in help output', async () => {
30
+ const mockExit = spyOn(process, 'exit').mockImplementation(() => {
31
+ throw new Error('process.exit');
32
+ });
33
+ const logs: string[] = [];
34
+ const mockLog = spyOn(console, 'log').mockImplementation((...args: unknown[]) => {
35
+ logs.push(args.join(' '));
36
+ });
37
+
38
+ try {
39
+ await runCreate([]);
40
+ } catch {
41
+ // expected
42
+ }
43
+
44
+ const output = logs.join('\n');
45
+ expect(output).toContain('create-agent create');
46
+ expect(output).toContain('--type');
47
+ expect(output).toContain('--dir');
48
+
49
+ mockExit.mockRestore();
50
+ mockLog.mockRestore();
51
+ });
52
+ });
53
+
54
+ describe('CLI argument parsing (list)', () => {
55
+ test('runList outputs all template types', async () => {
56
+ const logs: string[] = [];
57
+ const mockLog = spyOn(console, 'log').mockImplementation((...args: unknown[]) => {
58
+ logs.push(args.join(' '));
59
+ });
60
+
61
+ await runList();
62
+
63
+ const output = logs.join('\n');
64
+ expect(output).toContain('general');
65
+ expect(output).toContain('chat');
66
+ expect(output).toContain('agent');
67
+ expect(output).toContain('Available templates');
68
+
69
+ mockLog.mockRestore();
70
+ });
71
+ });
72
+
73
+ describe('CLI command registry', () => {
74
+ test('all 4 commands are importable', async () => {
75
+ const { runCreate } = await import('../commands/create');
76
+ const { runList } = await import('../commands/list');
77
+ const { runStatus } = await import('../commands/status');
78
+ const { runWorkspace } = await import('../commands/workspace');
79
+
80
+ expect(typeof runCreate).toBe('function');
81
+ expect(typeof runList).toBe('function');
82
+ expect(typeof runStatus).toBe('function');
83
+ expect(typeof runWorkspace).toBe('function');
84
+ });
85
+ });
@@ -0,0 +1,168 @@
1
+ import { describe, test, expect, afterAll } from 'bun:test';
2
+ import { mkdtempSync, mkdirSync, writeFileSync, existsSync, readFileSync, rmSync } from 'fs';
3
+ import { join } from 'path';
4
+ import { tmpdir } from 'os';
5
+ import { copyAndReplace, deriveNames } from '../lib/copy';
6
+
7
+ const TMP_DIRS: string[] = [];
8
+
9
+ afterAll(() => {
10
+ for (const d of TMP_DIRS) {
11
+ if (existsSync(d)) rmSync(d, { recursive: true, force: true });
12
+ }
13
+ });
14
+
15
+ function makeTmp(prefix = 'pi-cli-test-'): string {
16
+ const d = mkdtempSync(join(tmpdir(), prefix));
17
+ TMP_DIRS.push(d);
18
+ return d;
19
+ }
20
+
21
+ describe('deriveNames', () => {
22
+ test('simple name', () => {
23
+ const names = deriveNames('my-app');
24
+ expect(names.pascalName).toBe('MyApp');
25
+ expect(names.identifier).toBe('com.myapp.app');
26
+ expect(names.shortId).toBe('com.myapp');
27
+ });
28
+
29
+ test('single word', () => {
30
+ const names = deriveNames('hello');
31
+ expect(names.pascalName).toBe('Hello');
32
+ expect(names.identifier).toBe('com.hello.app');
33
+ expect(names.shortId).toBe('com.hello');
34
+ });
35
+
36
+ test('multi-segment name', () => {
37
+ const names = deriveNames('my-cool-project');
38
+ expect(names.pascalName).toBe('MyCoolProject');
39
+ expect(names.identifier).toBe('com.mycoolproject.app');
40
+ expect(names.shortId).toBe('com.mycoolproject');
41
+ });
42
+ });
43
+
44
+ describe('copyAndReplace', () => {
45
+ test('copies files from src to dest', () => {
46
+ const srcDir = makeTmp('pi-src-');
47
+ const destDir = makeTmp('pi-dest-');
48
+
49
+ writeFileSync(join(srcDir, 'hello.txt'), 'hello world');
50
+
51
+ copyAndReplace(srcDir, destDir, 'test-project');
52
+
53
+ expect(existsSync(join(destDir, 'hello.txt'))).toBe(true);
54
+ expect(readFileSync(join(destDir, 'hello.txt'), 'utf-8')).toBe('hello world');
55
+ });
56
+
57
+ test('replaces pi-agent-template with project name', () => {
58
+ const srcDir = makeTmp('pi-src-');
59
+ const destDir = makeTmp('pi-dest-');
60
+
61
+ writeFileSync(join(srcDir, 'config.json'), '{"name": "pi-agent-template"}');
62
+
63
+ copyAndReplace(srcDir, destDir, 'my-app');
64
+
65
+ const content = readFileSync(join(destDir, 'config.json'), 'utf-8');
66
+ expect(content).toBe('{"name": "my-app"}');
67
+ });
68
+
69
+ test('replaces Pi Agent Template with pascal name', () => {
70
+ const srcDir = makeTmp('pi-src-');
71
+ const destDir = makeTmp('pi-dest-');
72
+
73
+ writeFileSync(join(srcDir, 'readme.md'), '# Pi Agent Template');
74
+
75
+ copyAndReplace(srcDir, destDir, 'my-app');
76
+
77
+ const content = readFileSync(join(destDir, 'readme.md'), 'utf-8');
78
+ expect(content).toBe('# MyApp');
79
+ });
80
+
81
+ test('replaces Pi Agent with pascal name', () => {
82
+ const srcDir = makeTmp('pi-src-');
83
+ const destDir = makeTmp('pi-dest-');
84
+
85
+ writeFileSync(join(srcDir, 'app.ts'), 'export const Pi Agent = true');
86
+
87
+ copyAndReplace(srcDir, destDir, 'cool-project');
88
+
89
+ const content = readFileSync(join(destDir, 'app.ts'), 'utf-8');
90
+ expect(content).toBe('export const CoolProject = true');
91
+ });
92
+
93
+ test('replaces com.piagent.template with identifier', () => {
94
+ const srcDir = makeTmp('pi-src-');
95
+ const destDir = makeTmp('pi-dest-');
96
+
97
+ writeFileSync(join(srcDir, 'plist.xml'), '<string>com.piagent.template</string>');
98
+
99
+ copyAndReplace(srcDir, destDir, 'my-app');
100
+
101
+ const content = readFileSync(join(destDir, 'plist.xml'), 'utf-8');
102
+ expect(content).toBe('<string>com.myapp.app</string>');
103
+ });
104
+
105
+ test('replaces com.piagent with shortId', () => {
106
+ const srcDir = makeTmp('pi-src-');
107
+ const destDir = makeTmp('pi-dest-');
108
+
109
+ writeFileSync(join(srcDir, 'config.xml'), '<id>com.piagent.something</id>');
110
+
111
+ copyAndReplace(srcDir, destDir, 'my-app');
112
+
113
+ const content = readFileSync(join(destDir, 'config.xml'), 'utf-8');
114
+ expect(content).toBe('<id>com.myapp.something</id>');
115
+ });
116
+
117
+ test('replaces @pi-agent/ scope', () => {
118
+ const srcDir = makeTmp('pi-src-');
119
+ const destDir = makeTmp('pi-dest-');
120
+
121
+ writeFileSync(join(srcDir, 'pkg.json'), '"@pi-agent/rpc-core"');
122
+
123
+ copyAndReplace(srcDir, destDir, 'my-app');
124
+
125
+ const content = readFileSync(join(destDir, 'pkg.json'), 'utf-8');
126
+ expect(content).toBe('"@my-app/rpc-core"');
127
+ });
128
+
129
+ test('skips node_modules directory', () => {
130
+ const srcDir = makeTmp('pi-src-');
131
+ const destDir = makeTmp('pi-dest-');
132
+
133
+ mkdirSync(join(srcDir, 'node_modules', 'pkg'), { recursive: true });
134
+ writeFileSync(join(srcDir, 'node_modules', 'pkg', 'index.js'), 'module.exports = 1;');
135
+ writeFileSync(join(srcDir, 'root.txt'), 'root');
136
+
137
+ copyAndReplace(srcDir, destDir, 'test');
138
+
139
+ expect(existsSync(join(destDir, 'root.txt'))).toBe(true);
140
+ expect(existsSync(join(destDir, 'node_modules'))).toBe(false);
141
+ });
142
+
143
+ test('skips bun.lock file', () => {
144
+ const srcDir = makeTmp('pi-src-');
145
+ const destDir = makeTmp('pi-dest-');
146
+
147
+ writeFileSync(join(srcDir, 'bun.lock'), 'lockfile content');
148
+ writeFileSync(join(srcDir, 'package.json'), '{}');
149
+
150
+ copyAndReplace(srcDir, destDir, 'test');
151
+
152
+ expect(existsSync(join(destDir, 'package.json'))).toBe(true);
153
+ expect(existsSync(join(destDir, 'bun.lock'))).toBe(false);
154
+ });
155
+
156
+ test('copies nested directories recursively', () => {
157
+ const srcDir = makeTmp('pi-src-');
158
+ const destDir = makeTmp('pi-dest-');
159
+
160
+ mkdirSync(join(srcDir, 'src', 'lib'), { recursive: true });
161
+ writeFileSync(join(srcDir, 'src', 'lib', 'util.ts'), '// pi-agent-template util');
162
+
163
+ copyAndReplace(srcDir, destDir, 'my-proj');
164
+
165
+ const content = readFileSync(join(destDir, 'src', 'lib', 'util.ts'), 'utf-8');
166
+ expect(content).toBe('// my-proj util');
167
+ });
168
+ });
@@ -0,0 +1,87 @@
1
+ import { describe, test, expect } from 'bun:test';
2
+ import { getAllTemplates, getTemplateInfo, resolveTemplateDir } from '../lib/templates';
3
+
4
+ describe('getAllTemplates', () => {
5
+ test('returns 3 templates', () => {
6
+ const templates = getAllTemplates();
7
+ expect(templates).toHaveLength(3);
8
+ });
9
+
10
+ test('includes general, chat, agent types', () => {
11
+ const templates = getAllTemplates();
12
+ const types = templates.map((t) => t.type);
13
+ expect(types).toContain('general');
14
+ expect(types).toContain('chat');
15
+ expect(types).toContain('agent');
16
+ });
17
+
18
+ test('all templates are available', () => {
19
+ const templates = getAllTemplates();
20
+ for (const t of templates) {
21
+ expect(t.available).toBe(true);
22
+ }
23
+ });
24
+
25
+ test('each template has required fields', () => {
26
+ const templates = getAllTemplates();
27
+ for (const t of templates) {
28
+ expect(t.type).toBeTruthy();
29
+ expect(t.description).toBeTruthy();
30
+ expect(t.dir).toBeTruthy();
31
+ expect(typeof t.available).toBe('boolean');
32
+ }
33
+ });
34
+ });
35
+
36
+ describe('getTemplateInfo', () => {
37
+ test('returns info for "general"', () => {
38
+ const info = getTemplateInfo('general');
39
+ expect(info).toBeDefined();
40
+ expect(info!.type).toBe('general');
41
+ expect(info!.dir).toBe('templates/general');
42
+ });
43
+
44
+ test('returns info for "chat"', () => {
45
+ const info = getTemplateInfo('chat');
46
+ expect(info).toBeDefined();
47
+ expect(info!.type).toBe('chat');
48
+ });
49
+
50
+ test('returns info for "agent"', () => {
51
+ const info = getTemplateInfo('agent');
52
+ expect(info).toBeDefined();
53
+ expect(info!.type).toBe('agent');
54
+ });
55
+
56
+ test('returns undefined for unknown type', () => {
57
+ expect(getTemplateInfo('nonexistent')).toBeUndefined();
58
+ expect(getTemplateInfo('')).toBeUndefined();
59
+ });
60
+ });
61
+
62
+ describe('resolveTemplateDir', () => {
63
+ test('resolves general template path', () => {
64
+ const dir = resolveTemplateDir('/fake/root', 'general');
65
+ expect(dir).toBe('/fake/root/templates/general');
66
+ });
67
+
68
+ test('resolves chat template path', () => {
69
+ const dir = resolveTemplateDir('/fake/root', 'chat');
70
+ expect(dir).toBe('/fake/root/templates/chat');
71
+ });
72
+
73
+ test('resolves agent template path', () => {
74
+ const dir = resolveTemplateDir('/fake/root', 'agent');
75
+ expect(dir).toBe('/fake/root/templates/agent');
76
+ });
77
+
78
+ test('throws for invalid template type', () => {
79
+ expect(() => resolveTemplateDir('/root', 'invalid')).toThrow(
80
+ 'Unknown template type: "invalid"',
81
+ );
82
+ });
83
+
84
+ test('throws with empty string', () => {
85
+ expect(() => resolveTemplateDir('/root', '')).toThrow('Unknown template type');
86
+ });
87
+ });
package/src/cli.ts ADDED
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env bun
2
+
3
+ import { runCreate } from './commands/create.js';
4
+ import { runList } from './commands/list.js';
5
+ import { runStatus } from './commands/status.js';
6
+ import { runWorkspace } from './commands/workspace.js';
7
+
8
+ const COMMANDS = new Map<string, (args: string[]) => Promise<void>>([
9
+ ['create', runCreate],
10
+ ['list', runList],
11
+ ['status', runStatus],
12
+ ['workspace', runWorkspace],
13
+ ]);
14
+
15
+ function printHelp(): void {
16
+ console.log(`
17
+ Create Agent CLI — project scaffolding tool
18
+
19
+ Usage:
20
+ create-agent <command> [options]
21
+
22
+ Commands:
23
+ create <name> Create a new project from template
24
+ list Show available template types
25
+ status Show active pi-agent instances
26
+ workspace add <name> Create isolated workspace for parallel development
27
+ update Update project to latest template (coming soon)
28
+
29
+ Options:
30
+ -h, --help Show this help message
31
+
32
+ Run "create-agent create --help" for create-specific options.
33
+ `);
34
+ }
35
+
36
+ async function main(): Promise<void> {
37
+ const args = process.argv.slice(2);
38
+
39
+ const command = args[0];
40
+ const rest = args.slice(1);
41
+
42
+ if (!command || command === '-h' || command === '--help') {
43
+ printHelp();
44
+ process.exit(0);
45
+ }
46
+
47
+ if (command === 'update') {
48
+ console.log('Update feature coming soon');
49
+ return;
50
+ }
51
+
52
+ const handler = COMMANDS.get(command);
53
+ if (!handler) {
54
+ console.error(`Unknown command: "${command}"\n`);
55
+ printHelp();
56
+ process.exit(1);
57
+ }
58
+
59
+ await handler(rest);
60
+ }
61
+
62
+ main().catch((err) => {
63
+ console.error(`Error: ${err.message}`);
64
+ process.exit(1);
65
+ });
@@ -0,0 +1,49 @@
1
+ import { resolve } from 'path';
2
+ import { resolveTemplateDir, getRootDir } from '../lib/templates.js';
3
+ import { copyTemplate } from '../lib/copy.js';
4
+
5
+ export async function runCreate(args: string[]): Promise<void> {
6
+ let templateType = 'general';
7
+ let customDir: string | undefined;
8
+
9
+ const positional: string[] = [];
10
+ for (let i = 0; i < args.length; i++) {
11
+ const arg = args[i];
12
+ if (arg === '--type' && args[i + 1]) {
13
+ templateType = args[++i];
14
+ } else if (arg === '--dir' && args[i + 1]) {
15
+ customDir = args[++i];
16
+ } else if (!arg.startsWith('--')) {
17
+ positional.push(arg);
18
+ }
19
+ }
20
+
21
+ const projectName = positional[0];
22
+ const targetArg = customDir || positional[1];
23
+ if (!projectName) {
24
+ console.log(`
25
+ Usage: create-agent create <name> [--type <type>] [--dir <path>]
26
+
27
+ Options:
28
+ --type <type> Template type (default: general)
29
+ --dir <path> Target directory (default: ./<name>)
30
+
31
+ Examples:
32
+ create-agent create my-app
33
+ create-agent create my-app --type chat
34
+ create-agent create my-app --dir ~/projects/my-app
35
+ `);
36
+ process.exit(1);
37
+ }
38
+
39
+ const sanitized = projectName.replace(/[^a-zA-Z0-9-_]/g, '-');
40
+ const targetDir = targetArg ? resolve(targetArg) : resolve(process.cwd(), sanitized);
41
+ const rootDir = getRootDir();
42
+ const templateDir = resolveTemplateDir(rootDir, templateType);
43
+
44
+ await copyTemplate({
45
+ projectName: sanitized,
46
+ templateDir,
47
+ targetDir,
48
+ });
49
+ }
@@ -0,0 +1,12 @@
1
+ import { getAllTemplates } from '../lib/templates.js';
2
+
3
+ export async function runList(): Promise<void> {
4
+ const templates = getAllTemplates();
5
+
6
+ console.log('Available templates:\n');
7
+ for (const t of templates) {
8
+ const suffix = t.available ? '' : ' (coming soon)';
9
+ console.log(` ${t.type.padEnd(10)} ${t.description}${suffix}`);
10
+ }
11
+ console.log('');
12
+ }
@@ -0,0 +1,85 @@
1
+ import { readFileSync, existsSync, writeFileSync } from 'fs';
2
+ import { resolve } from 'path';
3
+ import type { PortEntry } from '../lib/types.js';
4
+
5
+ function isPidAlive(pid: number): boolean {
6
+ try {
7
+ process.kill(pid, 0);
8
+ return true;
9
+ } catch {
10
+ return false;
11
+ }
12
+ }
13
+
14
+ function getUptime(startedAt: string): string {
15
+ const start = new Date(startedAt).getTime();
16
+ if (isNaN(start)) return 'unknown';
17
+ const diff = Date.now() - start;
18
+ const minutes = Math.floor(diff / 60000);
19
+ if (minutes < 1) return '<1m';
20
+ if (minutes < 60) return `${minutes}m`;
21
+ const hours = Math.floor(minutes / 60);
22
+ const remMinutes = minutes % 60;
23
+ if (hours < 24) return `${hours}h ${remMinutes}m`;
24
+ const days = Math.floor(hours / 24);
25
+ const remHours = hours % 24;
26
+ return `${days}d ${remHours}h`;
27
+ }
28
+
29
+ export async function runStatus(): Promise<void> {
30
+ const registryPath = resolve(process.env.HOME || '~', '.pi-agent', 'ports.json');
31
+
32
+ if (!existsSync(registryPath)) {
33
+ console.log('No active instances.\n');
34
+ return;
35
+ }
36
+
37
+ let registry: Record<string, PortEntry>;
38
+ try {
39
+ const raw = readFileSync(registryPath, 'utf-8');
40
+ const parsed = JSON.parse(raw);
41
+ if (Array.isArray(parsed)) {
42
+ registry = {};
43
+ for (const entry of parsed) {
44
+ const key = entry.dir || entry.name || String(entry.port);
45
+ registry[key] = entry;
46
+ }
47
+ } else {
48
+ registry = parsed;
49
+ }
50
+ } catch {
51
+ console.log('No active instances.\n');
52
+ return;
53
+ }
54
+
55
+ const allEntries = Object.entries(registry);
56
+ if (allEntries.length === 0) {
57
+ console.log('No active instances.\n');
58
+ return;
59
+ }
60
+
61
+ const aliveEntries = allEntries.filter(([, e]) => isPidAlive(e.pid));
62
+ const cleaned = aliveEntries.length < allEntries.length;
63
+
64
+ if (cleaned) {
65
+ const cleanedRegistry: Record<string, PortEntry> = {};
66
+ for (const [key, entry] of aliveEntries) {
67
+ cleanedRegistry[key] = entry;
68
+ }
69
+ writeFileSync(registryPath, JSON.stringify(cleanedRegistry, null, 2) + '\n');
70
+ }
71
+
72
+ if (aliveEntries.length === 0) {
73
+ console.log('No active instances.\n');
74
+ return;
75
+ }
76
+
77
+ console.log('Active pi-agent instances:\n');
78
+ for (const [dir, entry] of aliveEntries) {
79
+ const uptime = getUptime(entry.startedAt);
80
+ console.log(` ${entry.name.padEnd(16)} → http://localhost:${entry.port} (PID ${entry.pid}, up ${uptime})`);
81
+ console.log(` ${dir}`);
82
+ console.log('');
83
+ }
84
+ console.log(`Registry: ${registryPath}\n`);
85
+ }