@downcity/city 1.1.39 → 1.1.47

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 (353) hide show
  1. package/README.md +4 -9
  2. package/bin/cli/Index.js +2 -0
  3. package/bin/cli/Index.js.map +1 -1
  4. package/bin/cli/agent/AgentChat.d.ts +2 -1
  5. package/bin/cli/agent/AgentChat.d.ts.map +1 -1
  6. package/bin/cli/agent/AgentChat.js +93 -214
  7. package/bin/cli/agent/AgentChat.js.map +1 -1
  8. package/bin/cli/agent/AgentChatTypes.d.ts +8 -12
  9. package/bin/cli/agent/AgentChatTypes.d.ts.map +1 -1
  10. package/bin/cli/agent/AgentHistory.js +2 -2
  11. package/bin/cli/agent/AgentHistory.js.map +1 -1
  12. package/bin/cli/agent/AgentManager.d.ts.map +1 -1
  13. package/bin/cli/agent/AgentManager.js +26 -27
  14. package/bin/cli/agent/AgentManager.js.map +1 -1
  15. package/bin/cli/agent/AgentManagerTypes.d.ts +2 -2
  16. package/bin/cli/agent/AgentManagerTypes.d.ts.map +1 -1
  17. package/bin/cli/agent/AgentReset.js +4 -4
  18. package/bin/cli/agent/AgentReset.js.map +1 -1
  19. package/bin/cli/agent/AgentSelection.js +6 -6
  20. package/bin/cli/agent/AgentSelection.js.map +1 -1
  21. package/bin/cli/agent/AgentSelectionTypes.d.ts +1 -1
  22. package/bin/cli/agent/AgentSelectionTypes.d.ts.map +1 -1
  23. package/bin/cli/agent/Init.js +10 -10
  24. package/bin/cli/agent/Init.js.map +1 -1
  25. package/bin/cli/agent/Restart.js +2 -2
  26. package/bin/cli/agent/Restart.js.map +1 -1
  27. package/bin/cli/agent/Run.d.ts +1 -1
  28. package/bin/cli/agent/Run.d.ts.map +1 -1
  29. package/bin/cli/agent/Run.js +37 -17
  30. package/bin/cli/agent/Run.js.map +1 -1
  31. package/bin/cli/agent/Start.js +2 -2
  32. package/bin/cli/agent/Start.js.map +1 -1
  33. package/bin/cli/agent/Stop.js +2 -2
  34. package/bin/cli/agent/Stop.js.map +1 -1
  35. package/bin/cli/control-plane/ControlPlaneProcess.js +5 -5
  36. package/bin/cli/control-plane/ControlPlaneProcess.js.map +1 -1
  37. package/bin/cli/model/ModelCreateCommand.js +1 -1
  38. package/bin/cli/model/ModelCreateCommand.js.map +1 -1
  39. package/bin/cli/model/ModelManageCommand.d.ts.map +1 -1
  40. package/bin/cli/model/ModelManageCommand.js +5 -3
  41. package/bin/cli/model/ModelManageCommand.js.map +1 -1
  42. package/bin/cli/model/ModelManager.js +3 -3
  43. package/bin/cli/model/ModelManager.js.map +1 -1
  44. package/bin/cli/model/ModelSupport.d.ts +0 -1
  45. package/bin/cli/model/ModelSupport.d.ts.map +1 -1
  46. package/bin/cli/model/ModelSupport.js +2 -11
  47. package/bin/cli/model/ModelSupport.js.map +1 -1
  48. package/bin/cli/shared/CliReporterTypes.d.ts +1 -1
  49. package/bin/cli/shared/Config.js +2 -2
  50. package/bin/cli/shared/Config.js.map +1 -1
  51. package/bin/cli/shared/Env.d.ts +1 -1
  52. package/bin/cli/shared/Env.d.ts.map +1 -1
  53. package/bin/cli/shared/Env.js +18 -149
  54. package/bin/cli/shared/Env.js.map +1 -1
  55. package/bin/cli/shared/IndexAgentCommand.d.ts.map +1 -1
  56. package/bin/cli/shared/IndexAgentCommand.js +3 -3
  57. package/bin/cli/shared/IndexAgentCommand.js.map +1 -1
  58. package/bin/cli/shared/IndexSupport.d.ts +3 -3
  59. package/bin/cli/shared/IndexSupport.d.ts.map +1 -1
  60. package/bin/cli/shared/IndexSupport.js +14 -8
  61. package/bin/cli/shared/IndexSupport.js.map +1 -1
  62. package/bin/cli/shared/ManagedPluginActionCommands.d.ts.map +1 -1
  63. package/bin/cli/shared/ManagedPluginActionCommands.js +5 -4
  64. package/bin/cli/shared/ManagedPluginActionCommands.js.map +1 -1
  65. package/bin/cli/shared/ManagedPluginRemote.d.ts.map +1 -1
  66. package/bin/cli/shared/ManagedPluginRemote.js +4 -4
  67. package/bin/cli/shared/ManagedPluginRemote.js.map +1 -1
  68. package/bin/cli/shared/PluginTargetSupport.d.ts +2 -2
  69. package/bin/cli/shared/PluginTargetSupport.d.ts.map +1 -1
  70. package/bin/cli/shared/PluginTargetSupport.js +19 -19
  71. package/bin/cli/shared/PluginTargetSupport.js.map +1 -1
  72. package/bin/cli/shared/Plugins.js +10 -10
  73. package/bin/cli/shared/Plugins.js.map +1 -1
  74. package/bin/cli/shared/PublicHostEnv.d.ts +1 -1
  75. package/bin/cli/shared/PublicHostEnv.js +2 -2
  76. package/bin/cli/shared/PublicHostEnv.js.map +1 -1
  77. package/bin/cli/shared/Terminal.d.ts +13 -0
  78. package/bin/cli/shared/Terminal.d.ts.map +1 -0
  79. package/bin/cli/shared/Terminal.js +22 -0
  80. package/bin/cli/shared/Terminal.js.map +1 -0
  81. package/bin/config/DowncitySchema.d.ts.map +1 -1
  82. package/bin/config/DowncitySchema.js +3 -111
  83. package/bin/config/DowncitySchema.js.map +1 -1
  84. package/bin/config/Paths.d.ts +0 -56
  85. package/bin/config/Paths.d.ts.map +1 -1
  86. package/bin/config/Paths.js +9 -51
  87. package/bin/config/Paths.js.map +1 -1
  88. package/bin/control/ControlGateway.js +1 -1
  89. package/bin/control/ControlGateway.js.map +1 -1
  90. package/bin/control/EnvApiRoutes.d.ts +1 -1
  91. package/bin/control/EnvApiRoutes.d.ts.map +1 -1
  92. package/bin/control/EnvApiRoutes.js +7 -79
  93. package/bin/control/EnvApiRoutes.js.map +1 -1
  94. package/bin/control/PlatformApiRoutes.d.ts +2 -2
  95. package/bin/control/PlatformApiRoutes.d.ts.map +1 -1
  96. package/bin/control/PlatformApiRoutes.js +2 -2
  97. package/bin/control/PlatformApiRoutes.js.map +1 -1
  98. package/bin/control/gateway/AgentActions.d.ts +2 -2
  99. package/bin/control/gateway/AgentActions.d.ts.map +1 -1
  100. package/bin/control/gateway/AgentActions.js +7 -7
  101. package/bin/control/gateway/AgentActions.js.map +1 -1
  102. package/bin/control/gateway/AgentCatalog.d.ts +3 -6
  103. package/bin/control/gateway/AgentCatalog.d.ts.map +1 -1
  104. package/bin/control/gateway/AgentCatalog.js +16 -18
  105. package/bin/control/gateway/AgentCatalog.js.map +1 -1
  106. package/bin/control/instant/InstantSessionRunner.d.ts.map +1 -1
  107. package/bin/control/instant/InstantSessionRunner.js +3 -1
  108. package/bin/control/instant/InstantSessionRunner.js.map +1 -1
  109. package/bin/env/ProcessEnv.d.ts +24 -0
  110. package/bin/env/ProcessEnv.d.ts.map +1 -0
  111. package/bin/env/ProcessEnv.js +41 -0
  112. package/bin/env/ProcessEnv.js.map +1 -0
  113. package/bin/http/auth/AuthEnv.d.ts +1 -1
  114. package/bin/http/auth/AuthEnv.js +1 -1
  115. package/bin/model/runtime/CreateRuntimeModel.d.ts +8 -0
  116. package/bin/model/runtime/CreateRuntimeModel.d.ts.map +1 -1
  117. package/bin/model/runtime/CreateRuntimeModel.js +43 -37
  118. package/bin/model/runtime/CreateRuntimeModel.js.map +1 -1
  119. package/bin/model/service/ModelPoolService.d.ts +1 -1
  120. package/bin/model/service/ModelPoolService.d.ts.map +1 -1
  121. package/bin/model/service/ModelPoolService.js +8 -6
  122. package/bin/model/service/ModelPoolService.js.map +1 -1
  123. package/bin/platform/store/StoreEnvRepository.d.ts +5 -49
  124. package/bin/platform/store/StoreEnvRepository.d.ts.map +1 -1
  125. package/bin/platform/store/StoreEnvRepository.js +31 -178
  126. package/bin/platform/store/StoreEnvRepository.js.map +1 -1
  127. package/bin/platform/store/StoreSchema.js +3 -44
  128. package/bin/platform/store/StoreSchema.js.map +1 -1
  129. package/bin/platform/store/index.d.ts +9 -45
  130. package/bin/platform/store/index.d.ts.map +1 -1
  131. package/bin/platform/store/index.js +12 -62
  132. package/bin/platform/store/index.js.map +1 -1
  133. package/bin/platform/store/schema.d.ts +2 -2
  134. package/bin/platform/store/schema.js +2 -2
  135. package/bin/process/daemon/Api.d.ts +1 -1
  136. package/bin/process/daemon/CliArgs.d.ts +1 -0
  137. package/bin/process/daemon/CliArgs.d.ts.map +1 -1
  138. package/bin/process/daemon/CliArgs.js +20 -1
  139. package/bin/process/daemon/CliArgs.js.map +1 -1
  140. package/bin/process/daemon/Client.d.ts +18 -2
  141. package/bin/process/daemon/Client.d.ts.map +1 -1
  142. package/bin/process/daemon/Client.js +70 -20
  143. package/bin/process/daemon/Client.js.map +1 -1
  144. package/bin/process/daemon/Manager.d.ts.map +1 -1
  145. package/bin/process/daemon/Manager.js +2 -1
  146. package/bin/process/daemon/Manager.js.map +1 -1
  147. package/bin/terminal/admin/auth-error.d.ts +34 -0
  148. package/bin/terminal/admin/auth-error.d.ts.map +1 -0
  149. package/bin/terminal/admin/auth-error.js +51 -0
  150. package/bin/terminal/admin/auth-error.js.map +1 -0
  151. package/bin/terminal/admin/commands/accounts.d.ts +6 -0
  152. package/bin/terminal/admin/commands/accounts.d.ts.map +1 -0
  153. package/bin/terminal/admin/commands/accounts.js +44 -0
  154. package/bin/terminal/admin/commands/accounts.js.map +1 -0
  155. package/bin/terminal/admin/commands/balance.d.ts +6 -0
  156. package/bin/terminal/admin/commands/balance.d.ts.map +1 -0
  157. package/bin/terminal/admin/commands/balance.js +153 -0
  158. package/bin/terminal/admin/commands/balance.js.map +1 -0
  159. package/bin/terminal/admin/commands/config.d.ts +10 -0
  160. package/bin/terminal/admin/commands/config.d.ts.map +1 -0
  161. package/bin/terminal/admin/commands/config.js +11 -0
  162. package/bin/terminal/admin/commands/config.js.map +1 -0
  163. package/bin/terminal/admin/commands/custom.d.ts +6 -0
  164. package/bin/terminal/admin/commands/custom.d.ts.map +1 -0
  165. package/bin/terminal/admin/commands/custom.js +47 -0
  166. package/bin/terminal/admin/commands/custom.js.map +1 -0
  167. package/bin/terminal/admin/commands/instruction.d.ts +9 -0
  168. package/bin/terminal/admin/commands/instruction.d.ts.map +1 -0
  169. package/bin/terminal/admin/commands/instruction.js +10 -0
  170. package/bin/terminal/admin/commands/instruction.js.map +1 -0
  171. package/bin/terminal/admin/commands/models.d.ts +14 -0
  172. package/bin/terminal/admin/commands/models.d.ts.map +1 -0
  173. package/bin/terminal/admin/commands/models.js +61 -0
  174. package/bin/terminal/admin/commands/models.js.map +1 -0
  175. package/bin/terminal/admin/commands/payment.d.ts +6 -0
  176. package/bin/terminal/admin/commands/payment.d.ts.map +1 -0
  177. package/bin/terminal/admin/commands/payment.js +59 -0
  178. package/bin/terminal/admin/commands/payment.js.map +1 -0
  179. package/bin/terminal/admin/commands/products.d.ts +6 -0
  180. package/bin/terminal/admin/commands/products.d.ts.map +1 -0
  181. package/bin/terminal/admin/commands/products.js +80 -0
  182. package/bin/terminal/admin/commands/products.js.map +1 -0
  183. package/bin/terminal/admin/commands/service-env.d.ts +11 -0
  184. package/bin/terminal/admin/commands/service-env.d.ts.map +1 -0
  185. package/bin/terminal/admin/commands/service-env.js +248 -0
  186. package/bin/terminal/admin/commands/service-env.js.map +1 -0
  187. package/bin/terminal/admin/commands/usage.d.ts +6 -0
  188. package/bin/terminal/admin/commands/usage.d.ts.map +1 -0
  189. package/bin/terminal/admin/commands/usage.js +44 -0
  190. package/bin/terminal/admin/commands/usage.js.map +1 -0
  191. package/bin/terminal/admin/loop.d.ts +6 -0
  192. package/bin/terminal/admin/loop.d.ts.map +1 -0
  193. package/bin/terminal/admin/loop.js +70 -0
  194. package/bin/terminal/admin/loop.js.map +1 -0
  195. package/bin/terminal/agent/pi-agent.d.ts +15 -0
  196. package/bin/terminal/agent/pi-agent.d.ts.map +1 -0
  197. package/bin/terminal/agent/pi-agent.js +136 -0
  198. package/bin/terminal/agent/pi-agent.js.map +1 -0
  199. package/bin/terminal/app.d.ts +13 -0
  200. package/bin/terminal/app.d.ts.map +1 -0
  201. package/bin/terminal/app.js +123 -0
  202. package/bin/terminal/app.js.map +1 -0
  203. package/bin/terminal/auth/admin.d.ts +8 -0
  204. package/bin/terminal/auth/admin.d.ts.map +1 -0
  205. package/bin/terminal/auth/admin.js +18 -0
  206. package/bin/terminal/auth/admin.js.map +1 -0
  207. package/bin/terminal/auth/mode-select.d.ts +11 -0
  208. package/bin/terminal/auth/mode-select.d.ts.map +1 -0
  209. package/bin/terminal/auth/mode-select.js +33 -0
  210. package/bin/terminal/auth/mode-select.js.map +1 -0
  211. package/bin/terminal/auth/server-switch.d.ts +22 -0
  212. package/bin/terminal/auth/server-switch.d.ts.map +1 -0
  213. package/bin/terminal/auth/server-switch.js +241 -0
  214. package/bin/terminal/auth/server-switch.js.map +1 -0
  215. package/bin/terminal/auth/user.d.ts +19 -0
  216. package/bin/terminal/auth/user.d.ts.map +1 -0
  217. package/bin/terminal/auth/user.js +261 -0
  218. package/bin/terminal/auth/user.js.map +1 -0
  219. package/bin/terminal/core/browser.d.ts +12 -0
  220. package/bin/terminal/core/browser.d.ts.map +1 -0
  221. package/bin/terminal/core/browser.js +29 -0
  222. package/bin/terminal/core/browser.js.map +1 -0
  223. package/bin/terminal/core/env.d.ts +15 -0
  224. package/bin/terminal/core/env.d.ts.map +1 -0
  225. package/bin/terminal/core/env.js +67 -0
  226. package/bin/terminal/core/env.js.map +1 -0
  227. package/bin/terminal/core/session.d.ts +97 -0
  228. package/bin/terminal/core/session.d.ts.map +1 -0
  229. package/bin/terminal/core/session.js +342 -0
  230. package/bin/terminal/core/session.js.map +1 -0
  231. package/bin/terminal/core/stripe.d.ts +26 -0
  232. package/bin/terminal/core/stripe.d.ts.map +1 -0
  233. package/bin/terminal/core/stripe.js +22 -0
  234. package/bin/terminal/core/stripe.js.map +1 -0
  235. package/bin/terminal/core/ui.d.ts +29 -0
  236. package/bin/terminal/core/ui.d.ts.map +1 -0
  237. package/bin/terminal/core/ui.js +60 -0
  238. package/bin/terminal/core/ui.js.map +1 -0
  239. package/bin/terminal/core/update.d.ts +20 -0
  240. package/bin/terminal/core/update.d.ts.map +1 -0
  241. package/bin/terminal/core/update.js +193 -0
  242. package/bin/terminal/core/update.js.map +1 -0
  243. package/bin/terminal/user/balance.d.ts +31 -0
  244. package/bin/terminal/user/balance.d.ts.map +1 -0
  245. package/bin/terminal/user/balance.js +131 -0
  246. package/bin/terminal/user/balance.js.map +1 -0
  247. package/bin/terminal/user/chat.d.ts +12 -0
  248. package/bin/terminal/user/chat.d.ts.map +1 -0
  249. package/bin/terminal/user/chat.js +70 -0
  250. package/bin/terminal/user/chat.js.map +1 -0
  251. package/bin/terminal/user/loop.d.ts +13 -0
  252. package/bin/terminal/user/loop.d.ts.map +1 -0
  253. package/bin/terminal/user/loop.js +93 -0
  254. package/bin/terminal/user/loop.js.map +1 -0
  255. package/bin/terminal/user/models.d.ts +10 -0
  256. package/bin/terminal/user/models.d.ts.map +1 -0
  257. package/bin/terminal/user/models.js +39 -0
  258. package/bin/terminal/user/models.js.map +1 -0
  259. package/bin/utils/storage.d.ts +0 -1
  260. package/bin/utils/storage.d.ts.map +1 -1
  261. package/bin/utils/storage.js +0 -6
  262. package/bin/utils/storage.js.map +1 -1
  263. package/package.json +7 -3
  264. package/public/app.js +3 -3
  265. package/src/cli/Index.ts +2 -0
  266. package/src/cli/agent/AgentChat.ts +113 -289
  267. package/src/cli/agent/AgentChatTypes.ts +8 -12
  268. package/src/cli/agent/AgentHistory.ts +2 -2
  269. package/src/cli/agent/AgentManager.ts +27 -28
  270. package/src/cli/agent/AgentManagerTypes.ts +2 -2
  271. package/src/cli/agent/AgentReset.ts +4 -4
  272. package/src/cli/agent/AgentSelection.ts +6 -6
  273. package/src/cli/agent/AgentSelectionTypes.ts +1 -1
  274. package/src/cli/agent/Init.ts +13 -13
  275. package/src/cli/agent/Restart.ts +2 -2
  276. package/src/cli/agent/Run.ts +38 -17
  277. package/src/cli/agent/Start.ts +2 -2
  278. package/src/cli/agent/Stop.ts +2 -2
  279. package/src/cli/control-plane/ControlPlaneProcess.ts +5 -5
  280. package/src/cli/model/ModelCreateCommand.ts +1 -1
  281. package/src/cli/model/ModelManageCommand.ts +5 -3
  282. package/src/cli/model/ModelManager.ts +3 -3
  283. package/src/cli/model/ModelSupport.ts +2 -10
  284. package/src/cli/shared/CliReporterTypes.ts +1 -1
  285. package/src/cli/shared/Config.ts +2 -2
  286. package/src/cli/shared/Env.ts +22 -230
  287. package/src/cli/shared/IndexAgentCommand.ts +3 -4
  288. package/src/cli/shared/IndexSupport.ts +16 -10
  289. package/src/cli/shared/ManagedPluginActionCommands.ts +4 -4
  290. package/src/cli/shared/ManagedPluginRemote.ts +4 -4
  291. package/src/cli/shared/PluginTargetSupport.ts +19 -19
  292. package/src/cli/shared/Plugins.ts +10 -10
  293. package/src/cli/shared/PublicHostEnv.ts +2 -2
  294. package/src/cli/shared/Terminal.ts +24 -0
  295. package/src/config/DowncitySchema.ts +3 -113
  296. package/src/config/Paths.ts +9 -90
  297. package/src/control/ControlGateway.ts +3 -3
  298. package/src/control/EnvApiRoutes.ts +7 -91
  299. package/src/control/PlatformApiRoutes.ts +6 -6
  300. package/src/control/gateway/AgentActions.ts +10 -10
  301. package/src/control/gateway/AgentCatalog.ts +17 -21
  302. package/src/control/instant/InstantSessionRunner.ts +3 -1
  303. package/src/env/ProcessEnv.ts +43 -0
  304. package/src/http/auth/AuthEnv.ts +1 -1
  305. package/src/model/runtime/CreateRuntimeModel.ts +54 -37
  306. package/src/model/service/ModelPoolService.ts +13 -11
  307. package/src/platform/store/StoreEnvRepository.ts +31 -234
  308. package/src/platform/store/StoreSchema.ts +3 -49
  309. package/src/platform/store/index.ts +11 -80
  310. package/src/platform/store/schema.ts +2 -2
  311. package/src/process/daemon/Api.ts +1 -1
  312. package/src/process/daemon/CliArgs.ts +24 -1
  313. package/src/process/daemon/Client.ts +90 -22
  314. package/src/process/daemon/Manager.ts +2 -1
  315. package/src/terminal/admin/auth-error.ts +62 -0
  316. package/src/terminal/admin/commands/accounts.ts +44 -0
  317. package/src/terminal/admin/commands/balance.ts +160 -0
  318. package/src/terminal/admin/commands/config.ts +13 -0
  319. package/src/terminal/admin/commands/custom.ts +46 -0
  320. package/src/terminal/admin/commands/instruction.ts +12 -0
  321. package/src/terminal/admin/commands/models.ts +64 -0
  322. package/src/terminal/admin/commands/payment.ts +94 -0
  323. package/src/terminal/admin/commands/products.ts +72 -0
  324. package/src/terminal/admin/commands/service-env.ts +256 -0
  325. package/src/terminal/admin/commands/usage.ts +44 -0
  326. package/src/terminal/admin/loop.ts +69 -0
  327. package/src/terminal/agent/pi-agent.ts +180 -0
  328. package/src/terminal/app.ts +120 -0
  329. package/src/terminal/auth/admin.ts +21 -0
  330. package/src/terminal/auth/mode-select.ts +38 -0
  331. package/src/terminal/auth/server-switch.ts +275 -0
  332. package/src/terminal/auth/user.ts +351 -0
  333. package/src/terminal/core/browser.ts +31 -0
  334. package/src/terminal/core/env.ts +71 -0
  335. package/src/terminal/core/session.ts +450 -0
  336. package/src/terminal/core/stripe.ts +37 -0
  337. package/src/terminal/core/ui.ts +84 -0
  338. package/src/terminal/core/update.ts +230 -0
  339. package/src/terminal/user/balance.ts +215 -0
  340. package/src/terminal/user/chat.ts +80 -0
  341. package/src/terminal/user/loop.ts +112 -0
  342. package/src/terminal/user/models.ts +43 -0
  343. package/src/utils/storage.ts +0 -7
  344. package/bin/process/rpc/Client.d.ts +0 -13
  345. package/bin/process/rpc/Client.d.ts.map +0 -1
  346. package/bin/process/rpc/Client.js +0 -98
  347. package/bin/process/rpc/Client.js.map +0 -1
  348. package/bin/process/rpc/Paths.d.ts +0 -14
  349. package/bin/process/rpc/Paths.d.ts.map +0 -1
  350. package/bin/process/rpc/Paths.js +0 -36
  351. package/bin/process/rpc/Paths.js.map +0 -1
  352. package/src/process/rpc/Client.ts +0 -113
  353. package/src/process/rpc/Paths.ts +0 -43
@@ -0,0 +1,180 @@
1
+ /**
2
+ * Pi SDK agent 封装模块。
3
+ *
4
+ * 关键说明(中文)
5
+ * - 封装 @mariozechner/pi-coding-agent 的会话创建与多轮对话。
6
+ * - pi-agent 通过 server 的 /chat/completions 端点调用 AI,
7
+ * client 只需要 server 地址 + user token,不需要 AI provider 的 API key。
8
+ */
9
+ import type { Model } from "@mariozechner/pi-ai";
10
+ import {
11
+ AuthStorage,
12
+ createAgentSession,
13
+ createExtensionRuntime,
14
+ ModelRegistry,
15
+ SessionManager,
16
+ SettingsManager,
17
+ type ResourceLoader,
18
+ } from "@mariozechner/pi-coding-agent";
19
+ import type { ModelHandle } from "@downcity/conduit";
20
+
21
+ // ============================================================
22
+ // 类型
23
+ // ============================================================
24
+
25
+ /** Pi-agent 会话 */
26
+ export type PiAgentSession = {
27
+ ask(prompt: string): Promise<string>;
28
+ };
29
+
30
+ // ============================================================
31
+ // 会话创建
32
+ // ============================================================
33
+
34
+ /** 创建 pi-agent 会话,通过 server 端点调用 AI */
35
+ export async function createPiAgentSession(options: {
36
+ /** 模型句柄(来自 server model catalog) */
37
+ model: ModelHandle;
38
+ tools?: string;
39
+ onText?: (text: string) => void;
40
+ onToolStart?: (toolName: string, args: unknown) => void;
41
+ onToolEnd?: (toolName: string, isError: boolean) => void;
42
+ }): Promise<PiAgentSession> {
43
+ const { model: handle, tools: toolsOpt, onText, onToolStart, onToolEnd } = options;
44
+
45
+ if (!handle.token) {
46
+ throw new Error("User token is required for agent. Please login first.");
47
+ }
48
+
49
+ const authStorage = AuthStorage.inMemory();
50
+ authStorage.setRuntimeApiKey("openai-compatible", handle.token);
51
+ const tools = resolveTools(toolsOpt);
52
+
53
+ const { session } = await createAgentSession({
54
+ cwd: process.cwd(),
55
+ model: createModel(handle),
56
+ thinkingLevel: "off",
57
+ authStorage,
58
+ modelRegistry: ModelRegistry.inMemory(authStorage),
59
+ resourceLoader: createMinimalResourceLoader(),
60
+ sessionManager: SessionManager.inMemory(process.cwd()),
61
+ settingsManager: SettingsManager.inMemory({
62
+ compaction: { enabled: false },
63
+ retry: { enabled: false },
64
+ }),
65
+ noTools: tools.length === 0 ? "all" : undefined,
66
+ tools: tools.length > 0 ? tools : undefined,
67
+ });
68
+
69
+ let activeTurn: { text: string; streamedText: boolean; assistantError?: string } | undefined;
70
+
71
+ session.subscribe((event) => {
72
+ if (!activeTurn) return;
73
+
74
+ if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") {
75
+ activeTurn.text += event.assistantMessageEvent.delta;
76
+ activeTurn.streamedText = true;
77
+ onText?.(event.assistantMessageEvent.delta);
78
+ return;
79
+ }
80
+
81
+ if (event.type === "message_end") {
82
+ activeTurn.assistantError = extractAssistantError(event.message) ?? activeTurn.assistantError;
83
+ const finalText = extractAssistantText(event.message);
84
+ if (finalText) {
85
+ activeTurn.text = finalText;
86
+ if (!activeTurn.streamedText) onText?.(finalText);
87
+ }
88
+ return;
89
+ }
90
+
91
+ if (event.type === "tool_execution_start") {
92
+ onToolStart?.(event.toolName, event.args);
93
+ return;
94
+ }
95
+
96
+ if (event.type === "tool_execution_end") {
97
+ onToolEnd?.(event.toolName, event.isError);
98
+ }
99
+ });
100
+
101
+ return {
102
+ ask: async (prompt: string) => {
103
+ activeTurn = { text: "", streamedText: false };
104
+ await session.prompt(prompt, { expandPromptTemplates: false });
105
+ const completedTurn = activeTurn;
106
+ activeTurn = undefined;
107
+ if (completedTurn?.assistantError) {
108
+ throw new Error(`Pi agent request failed: ${completedTurn.assistantError}`);
109
+ }
110
+ return completedTurn?.text.trim() ?? "";
111
+ },
112
+ };
113
+ }
114
+
115
+ // ============================================================
116
+ // 内部函数
117
+ // ============================================================
118
+
119
+ function createModel(handle: ModelHandle): Model<"openai-completions"> {
120
+ return {
121
+ id: handle.id,
122
+ name: handle.name,
123
+ api: "openai-completions" as const,
124
+ provider: "openai-compatible",
125
+ baseUrl: handle.endpoint,
126
+ reasoning: false,
127
+ input: ["text" as const],
128
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
129
+ contextWindow: 262144,
130
+ maxTokens: 4096,
131
+ compat: {
132
+ supportsStore: false,
133
+ supportsDeveloperRole: false,
134
+ supportsReasoningEffort: false,
135
+ supportsStrictMode: false,
136
+ maxTokensField: "max_tokens" as const,
137
+ },
138
+ };
139
+ }
140
+
141
+ function resolveTools(value: string | undefined): string[] {
142
+ const mode = value ?? "agent";
143
+ if (mode === "none") return [];
144
+ if (mode === "read-only") return ["read", "grep", "find", "ls"];
145
+ if (mode === "agent") return ["read", "grep", "find", "ls", "bash"];
146
+ if (mode === "coding") return ["read", "grep", "find", "ls", "bash", "edit", "write"];
147
+ return mode.split(",").map((t) => t.trim()).filter(Boolean);
148
+ }
149
+
150
+ function extractAssistantText(message: unknown): string {
151
+ if (!isRecord(message) || message.role !== "assistant" || !Array.isArray(message.content)) return "";
152
+ return message.content
153
+ .filter(isRecord)
154
+ .filter((c) => c.type === "text" && typeof c.text === "string")
155
+ .map((c) => String(c.text))
156
+ .join("");
157
+ }
158
+
159
+ function extractAssistantError(message: unknown): string | undefined {
160
+ if (!isRecord(message) || message.role !== "assistant" || message.stopReason !== "error") return undefined;
161
+ return typeof message.errorMessage === "string" ? message.errorMessage : "unknown error";
162
+ }
163
+
164
+ function createMinimalResourceLoader(): ResourceLoader {
165
+ return {
166
+ getExtensions: () => ({ extensions: [], errors: [], runtime: createExtensionRuntime() }),
167
+ getSkills: () => ({ skills: [], diagnostics: [] }),
168
+ getPrompts: () => ({ prompts: [], diagnostics: [] }),
169
+ getThemes: () => ({ themes: [], diagnostics: [] }),
170
+ getAgentsFiles: () => ({ agentsFiles: [] }),
171
+ getSystemPrompt: () => "You are a minimal test assistant. Answer the user directly.",
172
+ getAppendSystemPrompt: () => [],
173
+ extendResources: () => {},
174
+ reload: async () => {},
175
+ };
176
+ }
177
+
178
+ function isRecord(value: unknown): value is Record<string, unknown> {
179
+ return typeof value === "object" && value !== null;
180
+ }
@@ -0,0 +1,120 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Downcity Agent 入口与状态机调度。
5
+ *
6
+ * 状态流转:
7
+ * selectIdentity → Admin → adminLoop → selectIdentity (switch identity)
8
+ * selectIdentity → User → userLoop → selectIdentity (switch identity)
9
+ * selectIdentity → Manage Servers → selectIdentity
10
+ *
11
+ * 不再持有 config 快照,每次需要时从磁盘 readConfig()。
12
+ */
13
+
14
+ import { readFileSync } from "node:fs";
15
+ import { intro } from "./core/ui.js";
16
+ import { readActiveServer, readConfig, writeConfig } from "./core/session.js";
17
+ import { parseArgs } from "./core/env.js";
18
+ import { selectIdentity } from "./auth/mode-select.js";
19
+ import { adminAuth } from "./auth/admin.js";
20
+ import { userAuth } from "./auth/user.js";
21
+ import { ensureServerConfigured, manageServersMenu } from "./auth/server-switch.js";
22
+ import { userLoop } from "./user/loop.js";
23
+ import { adminLoop } from "./admin/loop.js";
24
+ import { show, showError, showSuccess } from "./core/ui.js";
25
+ import { updateCityCLI } from "./core/update.js";
26
+
27
+ export async function runTerminalApp(argv: string[] = []): Promise<void> {
28
+ const cli = parseArgs(argv);
29
+ if (cli.command === "update") {
30
+ await runSelfUpdate();
31
+ return;
32
+ }
33
+
34
+ intro(`Downcity Terminal v${readCityVersion()} (Esc to go back, Ctrl+C to exit)`);
35
+ if (!(await ensureServerConfigured())) {
36
+ return;
37
+ }
38
+
39
+ let identity = await selectIdentity();
40
+
41
+ while (identity !== "quit") {
42
+ if (identity === "update") {
43
+ await runSelfUpdate();
44
+ return;
45
+ }
46
+
47
+ if (identity === "servers") {
48
+ await manageServersMenu();
49
+ if (!(await ensureServerConfigured())) {
50
+ return;
51
+ }
52
+ identity = await selectIdentity();
53
+ continue;
54
+ }
55
+
56
+ // 每次从磁盘读取最新 config,不持快照
57
+ const cfg = readConfig();
58
+ const activeServer = readActiveServer();
59
+ if (!activeServer) {
60
+ if (!(await ensureServerConfigured())) {
61
+ return;
62
+ }
63
+ identity = await selectIdentity();
64
+ continue;
65
+ }
66
+ writeConfig({ ...cfg, last_identity: identity });
67
+
68
+ if (identity === "admin") {
69
+ const session = await adminAuth(activeServer);
70
+ if (!session) { identity = await selectIdentity(); continue; }
71
+ const result = await adminLoop(session);
72
+ if (result === "quit") break;
73
+ if (result === "switch_identity") { identity = await selectIdentity(); continue; }
74
+ identity = await selectIdentity();
75
+ continue;
76
+ }
77
+
78
+ // identity === "user"
79
+ const ctx = await userAuth(activeServer.base_url);
80
+ if (!ctx) { identity = await selectIdentity(); continue; }
81
+ const result = await userLoop(ctx);
82
+ if (result === "quit") break;
83
+ if (result === "switch_identity") { identity = await selectIdentity(); continue; }
84
+ identity = await selectIdentity();
85
+ }
86
+ }
87
+
88
+ /**
89
+ * 读取当前 city 包版本。
90
+ *
91
+ * 关键说明(中文)
92
+ * - 运行源码时从仓库 package.json 读取
93
+ * - 发布后的全局安装同样从包根目录 package.json 读取
94
+ * - 读取失败时回退到 unknown,避免 CLI 启动被版本展示阻断
95
+ */
96
+ function readCityVersion(): string {
97
+ try {
98
+ const packageJsonPath = new URL("../../package.json", import.meta.url);
99
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8")) as {
100
+ version?: string;
101
+ };
102
+ return String(packageJson.version ?? "unknown");
103
+ } catch {
104
+ return "unknown";
105
+ }
106
+ }
107
+
108
+ /**
109
+ * 执行 CLI 自更新,并提示用户重新启动。
110
+ */
111
+ async function runSelfUpdate(): Promise<void> {
112
+ try {
113
+ show("Updating downcity CLI...");
114
+ const result = await updateCityCLI();
115
+ showSuccess(`downcity updated via ${result.mode} mode -> v${result.version}`);
116
+ show("Please run `downcity` again to use the updated CLI.");
117
+ } catch (error) {
118
+ showError(error instanceof Error ? error.message : String(error));
119
+ }
120
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Admin 鉴权模块。
3
+ *
4
+ * 当前版本直接复用当前 active server 上保存的 admin_secret_key。
5
+ */
6
+
7
+ import { type AdminSession, type ServerProfile } from "../core/session.js";
8
+ import { showError } from "../core/ui.js";
9
+
10
+ export async function adminAuth(server: ServerProfile): Promise<AdminSession | undefined> {
11
+ const adminSecretKey = String(server.admin_secret_key ?? "").trim();
12
+ if (!adminSecretKey) {
13
+ showError("Current server is missing admin_secret_key. Use Manage Servers -> Edit Server.");
14
+ return undefined;
15
+ }
16
+
17
+ return {
18
+ base_url: server.base_url,
19
+ admin_token: adminSecretKey,
20
+ };
21
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * 身份选择模块。
3
+ *
4
+ * 始终显示菜单,围绕当前 active server 进入身份或 server 管理。
5
+ */
6
+
7
+ import { readActiveServer, readConfig, readUserSession } from "../core/session.js";
8
+ import { select, isCancel } from "@clack/prompts";
9
+
10
+ export type Identity = "admin" | "user" | "servers" | "update" | "quit";
11
+
12
+ /**
13
+ * 选择身份。始终显示菜单,已有 session 的身份标注 ★。
14
+ */
15
+ export async function selectIdentity(): Promise<Identity> {
16
+ const config = readConfig();
17
+ const activeServer = readActiveServer();
18
+
19
+ const hasAdmin = !!String(activeServer?.admin_secret_key ?? "").trim();
20
+ const hasUser = activeServer ? !!readUserSession(activeServer.base_url) : false;
21
+ const title = activeServer
22
+ ? `Identity [${activeServer.name}]`
23
+ : "Identity [No servers configured]";
24
+
25
+ const selected = await select({
26
+ message: title,
27
+ options: [
28
+ { label: hasAdmin ? "★ Admin" : " Admin", value: "admin", hint: hasAdmin ? activeServer?.base_url ?? "" : "Admin management" },
29
+ { label: hasUser ? "★ User" : " User", value: "user", hint: hasUser ? "session active" : "Login or register" },
30
+ { label: "Manage Servers", value: "servers", hint: `${config.servers.length} configured` },
31
+ { label: "Update CLI", value: "update", hint: "Refresh global downcity command" },
32
+ { label: "Quit", value: "quit" },
33
+ ],
34
+ });
35
+
36
+ if (!selected || isCancel(selected)) return "quit";
37
+ return selected as Identity;
38
+ }
@@ -0,0 +1,275 @@
1
+ /**
2
+ * Server 管理模块。
3
+ *
4
+ * 关键说明(中文)
5
+ * - 不再提供“切换当前 server”的临时入口
6
+ * - 所有 server 操作都统一收口到 Manage Servers
7
+ * - 没有 server 时,CLI 会先强制进入添加流程
8
+ */
9
+
10
+ import { AdminClient } from "@downcity/conduit";
11
+ import { isCancel, password, select, text } from "@clack/prompts";
12
+ import {
13
+ addServer,
14
+ readActiveServer,
15
+ readConfig,
16
+ readServer,
17
+ removeServer,
18
+ setActiveServer,
19
+ type ServerProfile,
20
+ updateServer,
21
+ } from "../core/session.js";
22
+ import { show, showError, showSuccess } from "../core/ui.js";
23
+
24
+ /**
25
+ * 确保至少存在一个 server。
26
+ */
27
+ export async function ensureServerConfigured(): Promise<boolean> {
28
+ if (readConfig().servers.length > 0) {
29
+ return true;
30
+ }
31
+
32
+ show("No servers configured. Add a server before continuing.");
33
+ const created = await promptAddServer();
34
+ if (!created) {
35
+ showError("No server configured. Exiting.");
36
+ return false;
37
+ }
38
+ return true;
39
+ }
40
+
41
+ /**
42
+ * 顶层 server 管理菜单。
43
+ */
44
+ export async function manageServersMenu(): Promise<void> {
45
+ while (true) {
46
+ const config = readConfig();
47
+ const active = readActiveServer();
48
+
49
+ const selected = await select({
50
+ message: active
51
+ ? `Manage Servers [current: ${active.name}]`
52
+ : "Manage Servers [no active server]",
53
+ options: [
54
+ { label: "List Servers", value: "list", hint: `${config.servers.length} configured` },
55
+ { label: "Add Server", value: "add", hint: "Create a new Infra server profile" },
56
+ { label: "Select Active Server", value: "select", hint: active ? active.base_url : "Choose current server" },
57
+ { label: "Edit Server", value: "edit", hint: "Update name, server URL, or admin key" },
58
+ { label: "Remove Server", value: "remove", hint: "Delete a server profile" },
59
+ { label: "Back", value: "back", hint: "Return to main menu" },
60
+ ],
61
+ });
62
+
63
+ if (!selected || isCancel(selected) || selected === "back") {
64
+ return;
65
+ }
66
+
67
+ if (selected === "list") {
68
+ printServers(config.servers, active?.base_url);
69
+ continue;
70
+ }
71
+
72
+ if (selected === "add") {
73
+ await promptAddServer();
74
+ continue;
75
+ }
76
+
77
+ if (selected === "select") {
78
+ await promptSelectActiveServer();
79
+ continue;
80
+ }
81
+
82
+ if (selected === "edit") {
83
+ await promptEditServer();
84
+ continue;
85
+ }
86
+
87
+ if (selected === "remove") {
88
+ await promptRemoveServer();
89
+ }
90
+ }
91
+ }
92
+
93
+ /**
94
+ * 添加 server。
95
+ */
96
+ export async function promptAddServer(): Promise<ServerProfile | undefined> {
97
+ const baseUrl = await text({
98
+ message: "Server URL",
99
+ placeholder: "https://downcity.wangenius.workers.dev",
100
+ });
101
+ if (!baseUrl || isCancel(baseUrl) || !String(baseUrl).trim()) {
102
+ return undefined;
103
+ }
104
+
105
+ const adminSecretKey = await password({ message: "admin_secret_key" });
106
+ if (!adminSecretKey || isCancel(adminSecretKey) || !String(adminSecretKey).trim()) {
107
+ return undefined;
108
+ }
109
+
110
+ const server = addServer({
111
+ base_url: String(baseUrl).trim(),
112
+ admin_secret_key: String(adminSecretKey).trim(),
113
+ });
114
+
115
+ const verified = await verifyServerAdminAccess(server);
116
+ if (verified) {
117
+ showSuccess(`Server added and activated: ${server.name}`);
118
+ } else {
119
+ showError(`Server saved, but admin verification failed: ${server.name}`);
120
+ }
121
+
122
+ return server;
123
+ }
124
+
125
+ async function promptSelectActiveServer(): Promise<void> {
126
+ const config = readConfig();
127
+ if (config.servers.length === 0) {
128
+ showError("No servers configured.");
129
+ return;
130
+ }
131
+
132
+ const selected = await select({
133
+ message: "Select active server",
134
+ options: config.servers.map((server) => ({
135
+ label: server.base_url === config.active_server_url ? `★ ${server.name}` : ` ${server.name}`,
136
+ value: server.base_url,
137
+ hint: server.base_url,
138
+ })),
139
+ });
140
+
141
+ if (!selected || isCancel(selected)) {
142
+ return;
143
+ }
144
+
145
+ setActiveServer(String(selected));
146
+ showSuccess(`Active server: ${String(selected)}`);
147
+ }
148
+
149
+ async function promptEditServer(): Promise<void> {
150
+ const config = readConfig();
151
+ if (config.servers.length === 0) {
152
+ showError("No servers configured.");
153
+ return;
154
+ }
155
+
156
+ const targetBaseUrl = await select({
157
+ message: "Edit server",
158
+ options: config.servers.map((server) => ({
159
+ label: server.base_url === config.active_server_url ? `★ ${server.name}` : ` ${server.name}`,
160
+ value: server.base_url,
161
+ hint: server.base_url,
162
+ })),
163
+ });
164
+ if (!targetBaseUrl || isCancel(targetBaseUrl)) {
165
+ return;
166
+ }
167
+
168
+ const current = readServer(String(targetBaseUrl));
169
+ if (!current) {
170
+ showError("Selected server no longer exists.");
171
+ return;
172
+ }
173
+
174
+ const field = await select({
175
+ message: `Edit ${current.name}`,
176
+ options: [
177
+ { label: "Name", value: "name", hint: current.name },
178
+ { label: "Server URL", value: "base_url", hint: current.base_url },
179
+ { label: "Admin secret key", value: "admin_secret_key", hint: maskSecret(current.admin_secret_key) },
180
+ { label: "Cancel", value: "cancel", hint: "Return without changes" },
181
+ ],
182
+ });
183
+ if (!field || isCancel(field) || field === "cancel") {
184
+ return;
185
+ }
186
+
187
+ const next = { ...current };
188
+
189
+ if (field === "name") {
190
+ const name = await text({ message: "Display name", initialValue: current.name });
191
+ if (!name || isCancel(name)) return;
192
+ next.name = String(name).trim() || current.name;
193
+ } else if (field === "base_url") {
194
+ const baseUrl = await text({ message: "Server URL", initialValue: current.base_url });
195
+ if (!baseUrl || isCancel(baseUrl)) return;
196
+ next.base_url = String(baseUrl).trim() || current.base_url;
197
+ } else if (field === "admin_secret_key") {
198
+ const adminSecretKey = await password({ message: "admin_secret_key" });
199
+ if (!adminSecretKey || isCancel(adminSecretKey)) return;
200
+ next.admin_secret_key = String(adminSecretKey).trim();
201
+ }
202
+
203
+ const updated = updateServer(current.base_url, next);
204
+ const verified = await verifyServerAdminAccess(updated);
205
+ if (verified) {
206
+ showSuccess(`Server updated: ${updated.name}`);
207
+ } else {
208
+ showError(`Server updated, but admin verification failed: ${updated.name}`);
209
+ }
210
+ }
211
+
212
+ async function promptRemoveServer(): Promise<void> {
213
+ const config = readConfig();
214
+ if (config.servers.length === 0) {
215
+ showError("No servers configured.");
216
+ return;
217
+ }
218
+
219
+ const selected = await select({
220
+ message: "Remove server",
221
+ options: [
222
+ ...config.servers.map((server) => ({
223
+ label: `${server.base_url === config.active_server_url ? "★ " : ""}${server.name}`,
224
+ value: server.base_url,
225
+ hint: server.base_url,
226
+ })),
227
+ { label: "Cancel", value: "cancel", hint: "Return without changes" },
228
+ ],
229
+ });
230
+ if (!selected || isCancel(selected) || selected === "cancel") {
231
+ return;
232
+ }
233
+
234
+ removeServer(String(selected));
235
+ const nextActive = readActiveServer();
236
+ showSuccess(
237
+ nextActive
238
+ ? `Server removed. Current server: ${nextActive.name}`
239
+ : "Server removed. No servers configured.",
240
+ );
241
+ }
242
+
243
+ async function verifyServerAdminAccess(server: ServerProfile): Promise<boolean> {
244
+ try {
245
+ const admin = new AdminClient({
246
+ base_url: server.base_url,
247
+ admin_secret_key: server.admin_secret_key,
248
+ });
249
+ await admin.listServices();
250
+ return true;
251
+ } catch {
252
+ return false;
253
+ }
254
+ }
255
+
256
+ function printServers(servers: ServerProfile[], activeBaseUrl: string | undefined): void {
257
+ if (servers.length === 0) {
258
+ show("No servers configured.");
259
+ return;
260
+ }
261
+
262
+ console.log(`\n${servers.length} servers:\n`);
263
+ for (const server of servers) {
264
+ const marker = server.base_url === activeBaseUrl ? "★" : " ";
265
+ console.log(` ${marker} ${server.name.padEnd(24)} ${server.base_url} admin=${maskSecret(server.admin_secret_key)}`);
266
+ }
267
+ console.log("");
268
+ }
269
+
270
+ function maskSecret(value: string): string {
271
+ const normalized = String(value ?? "").trim();
272
+ if (!normalized) return "(missing)";
273
+ if (normalized.length <= 8) return `${normalized.slice(0, 2)}***`;
274
+ return `${normalized.slice(0, 4)}***${normalized.slice(-2)}`;
275
+ }