@downcity/city 1.1.32 → 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 (395) hide show
  1. package/README.md +4 -9
  2. package/bin/cli/Index.js +10 -3
  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.d.ts.map +1 -1
  24. package/bin/cli/agent/Init.js +17 -17
  25. package/bin/cli/agent/Init.js.map +1 -1
  26. package/bin/cli/agent/Restart.js +2 -2
  27. package/bin/cli/agent/Restart.js.map +1 -1
  28. package/bin/cli/agent/Run.d.ts +1 -1
  29. package/bin/cli/agent/Run.d.ts.map +1 -1
  30. package/bin/cli/agent/Run.js +44 -30
  31. package/bin/cli/agent/Run.js.map +1 -1
  32. package/bin/cli/agent/Start.js +2 -2
  33. package/bin/cli/agent/Start.js.map +1 -1
  34. package/bin/cli/agent/Stop.js +2 -2
  35. package/bin/cli/agent/Stop.js.map +1 -1
  36. package/bin/cli/control-plane/ControlPlaneProcess.d.ts.map +1 -1
  37. package/bin/cli/control-plane/ControlPlaneProcess.js +7 -8
  38. package/bin/cli/control-plane/ControlPlaneProcess.js.map +1 -1
  39. package/bin/cli/model/ModelCreateCommand.js +1 -1
  40. package/bin/cli/model/ModelCreateCommand.js.map +1 -1
  41. package/bin/cli/model/ModelManageCommand.d.ts.map +1 -1
  42. package/bin/cli/model/ModelManageCommand.js +5 -3
  43. package/bin/cli/model/ModelManageCommand.js.map +1 -1
  44. package/bin/cli/model/ModelManager.js +3 -3
  45. package/bin/cli/model/ModelManager.js.map +1 -1
  46. package/bin/cli/model/ModelSupport.d.ts +0 -1
  47. package/bin/cli/model/ModelSupport.d.ts.map +1 -1
  48. package/bin/cli/model/ModelSupport.js +2 -11
  49. package/bin/cli/model/ModelSupport.js.map +1 -1
  50. package/bin/cli/shared/ChatAuth.d.ts.map +1 -1
  51. package/bin/cli/shared/ChatAuth.js +5 -7
  52. package/bin/cli/shared/ChatAuth.js.map +1 -1
  53. package/bin/cli/shared/ChatManager.d.ts.map +1 -1
  54. package/bin/cli/shared/ChatManager.js +2 -3
  55. package/bin/cli/shared/ChatManager.js.map +1 -1
  56. package/bin/cli/shared/CliReporterTypes.d.ts +1 -1
  57. package/bin/cli/shared/Config.js +2 -2
  58. package/bin/cli/shared/Config.js.map +1 -1
  59. package/bin/cli/shared/Env.d.ts +1 -1
  60. package/bin/cli/shared/Env.d.ts.map +1 -1
  61. package/bin/cli/shared/Env.js +18 -149
  62. package/bin/cli/shared/Env.js.map +1 -1
  63. package/bin/cli/shared/IndexAgentCommand.d.ts.map +1 -1
  64. package/bin/cli/shared/IndexAgentCommand.js +3 -3
  65. package/bin/cli/shared/IndexAgentCommand.js.map +1 -1
  66. package/bin/cli/shared/IndexSupport.d.ts +3 -3
  67. package/bin/cli/shared/IndexSupport.d.ts.map +1 -1
  68. package/bin/cli/shared/IndexSupport.js +14 -8
  69. package/bin/cli/shared/IndexSupport.js.map +1 -1
  70. package/bin/cli/shared/ManagedPluginActionCommands.d.ts +2 -1
  71. package/bin/cli/shared/ManagedPluginActionCommands.d.ts.map +1 -1
  72. package/bin/cli/shared/ManagedPluginActionCommands.js +9 -7
  73. package/bin/cli/shared/ManagedPluginActionCommands.js.map +1 -1
  74. package/bin/cli/shared/ManagedPluginRemote.d.ts.map +1 -1
  75. package/bin/cli/shared/ManagedPluginRemote.js +4 -4
  76. package/bin/cli/shared/ManagedPluginRemote.js.map +1 -1
  77. package/bin/cli/shared/PluginScheduleCommand.d.ts +3 -2
  78. package/bin/cli/shared/PluginScheduleCommand.d.ts.map +1 -1
  79. package/bin/cli/shared/PluginScheduleCommand.js +11 -10
  80. package/bin/cli/shared/PluginScheduleCommand.js.map +1 -1
  81. package/bin/cli/shared/PluginTargetSupport.d.ts +6 -6
  82. package/bin/cli/shared/PluginTargetSupport.d.ts.map +1 -1
  83. package/bin/cli/shared/PluginTargetSupport.js +23 -24
  84. package/bin/cli/shared/PluginTargetSupport.js.map +1 -1
  85. package/bin/cli/shared/Plugins.d.ts.map +1 -1
  86. package/bin/cli/shared/Plugins.js +22 -16
  87. package/bin/cli/shared/Plugins.js.map +1 -1
  88. package/bin/cli/shared/PublicHostEnv.d.ts +1 -1
  89. package/bin/cli/shared/PublicHostEnv.js +2 -2
  90. package/bin/cli/shared/PublicHostEnv.js.map +1 -1
  91. package/bin/cli/shared/Terminal.d.ts +13 -0
  92. package/bin/cli/shared/Terminal.d.ts.map +1 -0
  93. package/bin/cli/shared/Terminal.js +22 -0
  94. package/bin/cli/shared/Terminal.js.map +1 -0
  95. package/bin/config/DowncitySchema.d.ts.map +1 -1
  96. package/bin/config/DowncitySchema.js +3 -111
  97. package/bin/config/DowncitySchema.js.map +1 -1
  98. package/bin/config/Paths.d.ts +0 -56
  99. package/bin/config/Paths.d.ts.map +1 -1
  100. package/bin/config/Paths.js +9 -51
  101. package/bin/config/Paths.js.map +1 -1
  102. package/bin/control/ChannelAccountApiRoutes.d.ts.map +1 -1
  103. package/bin/control/ChannelAccountApiRoutes.js +2 -3
  104. package/bin/control/ChannelAccountApiRoutes.js.map +1 -1
  105. package/bin/control/ControlGateway.d.ts.map +1 -1
  106. package/bin/control/ControlGateway.js +4 -3
  107. package/bin/control/ControlGateway.js.map +1 -1
  108. package/bin/control/EnvApiRoutes.d.ts +1 -1
  109. package/bin/control/EnvApiRoutes.d.ts.map +1 -1
  110. package/bin/control/EnvApiRoutes.js +7 -79
  111. package/bin/control/EnvApiRoutes.js.map +1 -1
  112. package/bin/control/PlatformApiRoutes.d.ts +2 -2
  113. package/bin/control/PlatformApiRoutes.d.ts.map +1 -1
  114. package/bin/control/PlatformApiRoutes.js +2 -2
  115. package/bin/control/PlatformApiRoutes.js.map +1 -1
  116. package/bin/control/PluginApiRoutes.d.ts.map +1 -1
  117. package/bin/control/PluginApiRoutes.js +33 -25
  118. package/bin/control/PluginApiRoutes.js.map +1 -1
  119. package/bin/control/gateway/AgentActions.d.ts +2 -2
  120. package/bin/control/gateway/AgentActions.d.ts.map +1 -1
  121. package/bin/control/gateway/AgentActions.js +23 -18
  122. package/bin/control/gateway/AgentActions.js.map +1 -1
  123. package/bin/control/gateway/AgentCatalog.d.ts +3 -6
  124. package/bin/control/gateway/AgentCatalog.d.ts.map +1 -1
  125. package/bin/control/gateway/AgentCatalog.js +16 -18
  126. package/bin/control/gateway/AgentCatalog.js.map +1 -1
  127. package/bin/control/instant/InstantSessionRunner.d.ts.map +1 -1
  128. package/bin/control/instant/InstantSessionRunner.js +3 -1
  129. package/bin/control/instant/InstantSessionRunner.js.map +1 -1
  130. package/bin/env/ProcessEnv.d.ts +24 -0
  131. package/bin/env/ProcessEnv.d.ts.map +1 -0
  132. package/bin/env/ProcessEnv.js +41 -0
  133. package/bin/env/ProcessEnv.js.map +1 -0
  134. package/bin/http/auth/AuthEnv.d.ts +1 -1
  135. package/bin/http/auth/AuthEnv.js +1 -1
  136. package/bin/model/runtime/CreateRuntimeModel.d.ts +6 -6
  137. package/bin/model/runtime/CreateRuntimeModel.d.ts.map +1 -1
  138. package/bin/model/runtime/CreateRuntimeModel.js +44 -53
  139. package/bin/model/runtime/CreateRuntimeModel.js.map +1 -1
  140. package/bin/model/runtime/ExecutionModelBinding.d.ts +46 -0
  141. package/bin/model/runtime/ExecutionModelBinding.d.ts.map +1 -0
  142. package/bin/model/runtime/ExecutionModelBinding.js +96 -0
  143. package/bin/model/runtime/ExecutionModelBinding.js.map +1 -0
  144. package/bin/model/service/ModelPoolService.d.ts +1 -1
  145. package/bin/model/service/ModelPoolService.d.ts.map +1 -1
  146. package/bin/model/service/ModelPoolService.js +8 -6
  147. package/bin/model/service/ModelPoolService.js.map +1 -1
  148. package/bin/platform/store/StoreEnvRepository.d.ts +5 -49
  149. package/bin/platform/store/StoreEnvRepository.d.ts.map +1 -1
  150. package/bin/platform/store/StoreEnvRepository.js +31 -178
  151. package/bin/platform/store/StoreEnvRepository.js.map +1 -1
  152. package/bin/platform/store/StoreSchema.js +3 -44
  153. package/bin/platform/store/StoreSchema.js.map +1 -1
  154. package/bin/platform/store/index.d.ts +9 -45
  155. package/bin/platform/store/index.d.ts.map +1 -1
  156. package/bin/platform/store/index.js +12 -62
  157. package/bin/platform/store/index.js.map +1 -1
  158. package/bin/platform/store/schema.d.ts +2 -2
  159. package/bin/platform/store/schema.js +2 -2
  160. package/bin/process/daemon/Api.d.ts +1 -1
  161. package/bin/process/daemon/CliArgs.d.ts +1 -0
  162. package/bin/process/daemon/CliArgs.d.ts.map +1 -1
  163. package/bin/process/daemon/CliArgs.js +20 -1
  164. package/bin/process/daemon/CliArgs.js.map +1 -1
  165. package/bin/process/daemon/Client.d.ts +18 -2
  166. package/bin/process/daemon/Client.d.ts.map +1 -1
  167. package/bin/process/daemon/Client.js +70 -20
  168. package/bin/process/daemon/Client.js.map +1 -1
  169. package/bin/process/daemon/Manager.d.ts.map +1 -1
  170. package/bin/process/daemon/Manager.js +2 -1
  171. package/bin/process/daemon/Manager.js.map +1 -1
  172. package/bin/process/registry/AgentHostRuntime.d.ts +1 -9
  173. package/bin/process/registry/AgentHostRuntime.d.ts.map +1 -1
  174. package/bin/process/registry/AgentHostRuntime.js +1 -155
  175. package/bin/process/registry/AgentHostRuntime.js.map +1 -1
  176. package/bin/terminal/admin/auth-error.d.ts +34 -0
  177. package/bin/terminal/admin/auth-error.d.ts.map +1 -0
  178. package/bin/terminal/admin/auth-error.js +51 -0
  179. package/bin/terminal/admin/auth-error.js.map +1 -0
  180. package/bin/terminal/admin/commands/accounts.d.ts +6 -0
  181. package/bin/terminal/admin/commands/accounts.d.ts.map +1 -0
  182. package/bin/terminal/admin/commands/accounts.js +44 -0
  183. package/bin/terminal/admin/commands/accounts.js.map +1 -0
  184. package/bin/terminal/admin/commands/balance.d.ts +6 -0
  185. package/bin/terminal/admin/commands/balance.d.ts.map +1 -0
  186. package/bin/terminal/admin/commands/balance.js +153 -0
  187. package/bin/terminal/admin/commands/balance.js.map +1 -0
  188. package/bin/terminal/admin/commands/config.d.ts +10 -0
  189. package/bin/terminal/admin/commands/config.d.ts.map +1 -0
  190. package/bin/terminal/admin/commands/config.js +11 -0
  191. package/bin/terminal/admin/commands/config.js.map +1 -0
  192. package/bin/terminal/admin/commands/custom.d.ts +6 -0
  193. package/bin/terminal/admin/commands/custom.d.ts.map +1 -0
  194. package/bin/terminal/admin/commands/custom.js +47 -0
  195. package/bin/terminal/admin/commands/custom.js.map +1 -0
  196. package/bin/terminal/admin/commands/instruction.d.ts +9 -0
  197. package/bin/terminal/admin/commands/instruction.d.ts.map +1 -0
  198. package/bin/terminal/admin/commands/instruction.js +10 -0
  199. package/bin/terminal/admin/commands/instruction.js.map +1 -0
  200. package/bin/terminal/admin/commands/models.d.ts +14 -0
  201. package/bin/terminal/admin/commands/models.d.ts.map +1 -0
  202. package/bin/terminal/admin/commands/models.js +61 -0
  203. package/bin/terminal/admin/commands/models.js.map +1 -0
  204. package/bin/terminal/admin/commands/payment.d.ts +6 -0
  205. package/bin/terminal/admin/commands/payment.d.ts.map +1 -0
  206. package/bin/terminal/admin/commands/payment.js +59 -0
  207. package/bin/terminal/admin/commands/payment.js.map +1 -0
  208. package/bin/terminal/admin/commands/products.d.ts +6 -0
  209. package/bin/terminal/admin/commands/products.d.ts.map +1 -0
  210. package/bin/terminal/admin/commands/products.js +80 -0
  211. package/bin/terminal/admin/commands/products.js.map +1 -0
  212. package/bin/terminal/admin/commands/service-env.d.ts +11 -0
  213. package/bin/terminal/admin/commands/service-env.d.ts.map +1 -0
  214. package/bin/terminal/admin/commands/service-env.js +248 -0
  215. package/bin/terminal/admin/commands/service-env.js.map +1 -0
  216. package/bin/terminal/admin/commands/usage.d.ts +6 -0
  217. package/bin/terminal/admin/commands/usage.d.ts.map +1 -0
  218. package/bin/terminal/admin/commands/usage.js +44 -0
  219. package/bin/terminal/admin/commands/usage.js.map +1 -0
  220. package/bin/terminal/admin/loop.d.ts +6 -0
  221. package/bin/terminal/admin/loop.d.ts.map +1 -0
  222. package/bin/terminal/admin/loop.js +70 -0
  223. package/bin/terminal/admin/loop.js.map +1 -0
  224. package/bin/terminal/agent/pi-agent.d.ts +15 -0
  225. package/bin/terminal/agent/pi-agent.d.ts.map +1 -0
  226. package/bin/terminal/agent/pi-agent.js +136 -0
  227. package/bin/terminal/agent/pi-agent.js.map +1 -0
  228. package/bin/terminal/app.d.ts +13 -0
  229. package/bin/terminal/app.d.ts.map +1 -0
  230. package/bin/terminal/app.js +123 -0
  231. package/bin/terminal/app.js.map +1 -0
  232. package/bin/terminal/auth/admin.d.ts +8 -0
  233. package/bin/terminal/auth/admin.d.ts.map +1 -0
  234. package/bin/terminal/auth/admin.js +18 -0
  235. package/bin/terminal/auth/admin.js.map +1 -0
  236. package/bin/terminal/auth/mode-select.d.ts +11 -0
  237. package/bin/terminal/auth/mode-select.d.ts.map +1 -0
  238. package/bin/terminal/auth/mode-select.js +33 -0
  239. package/bin/terminal/auth/mode-select.js.map +1 -0
  240. package/bin/terminal/auth/server-switch.d.ts +22 -0
  241. package/bin/terminal/auth/server-switch.d.ts.map +1 -0
  242. package/bin/terminal/auth/server-switch.js +241 -0
  243. package/bin/terminal/auth/server-switch.js.map +1 -0
  244. package/bin/terminal/auth/user.d.ts +19 -0
  245. package/bin/terminal/auth/user.d.ts.map +1 -0
  246. package/bin/terminal/auth/user.js +261 -0
  247. package/bin/terminal/auth/user.js.map +1 -0
  248. package/bin/terminal/core/browser.d.ts +12 -0
  249. package/bin/terminal/core/browser.d.ts.map +1 -0
  250. package/bin/terminal/core/browser.js +29 -0
  251. package/bin/terminal/core/browser.js.map +1 -0
  252. package/bin/terminal/core/env.d.ts +15 -0
  253. package/bin/terminal/core/env.d.ts.map +1 -0
  254. package/bin/terminal/core/env.js +67 -0
  255. package/bin/terminal/core/env.js.map +1 -0
  256. package/bin/terminal/core/session.d.ts +97 -0
  257. package/bin/terminal/core/session.d.ts.map +1 -0
  258. package/bin/terminal/core/session.js +342 -0
  259. package/bin/terminal/core/session.js.map +1 -0
  260. package/bin/terminal/core/stripe.d.ts +26 -0
  261. package/bin/terminal/core/stripe.d.ts.map +1 -0
  262. package/bin/terminal/core/stripe.js +22 -0
  263. package/bin/terminal/core/stripe.js.map +1 -0
  264. package/bin/terminal/core/ui.d.ts +29 -0
  265. package/bin/terminal/core/ui.d.ts.map +1 -0
  266. package/bin/terminal/core/ui.js +60 -0
  267. package/bin/terminal/core/ui.js.map +1 -0
  268. package/bin/terminal/core/update.d.ts +20 -0
  269. package/bin/terminal/core/update.d.ts.map +1 -0
  270. package/bin/terminal/core/update.js +193 -0
  271. package/bin/terminal/core/update.js.map +1 -0
  272. package/bin/terminal/user/balance.d.ts +31 -0
  273. package/bin/terminal/user/balance.d.ts.map +1 -0
  274. package/bin/terminal/user/balance.js +131 -0
  275. package/bin/terminal/user/balance.js.map +1 -0
  276. package/bin/terminal/user/chat.d.ts +12 -0
  277. package/bin/terminal/user/chat.d.ts.map +1 -0
  278. package/bin/terminal/user/chat.js +70 -0
  279. package/bin/terminal/user/chat.js.map +1 -0
  280. package/bin/terminal/user/loop.d.ts +13 -0
  281. package/bin/terminal/user/loop.d.ts.map +1 -0
  282. package/bin/terminal/user/loop.js +93 -0
  283. package/bin/terminal/user/loop.js.map +1 -0
  284. package/bin/terminal/user/models.d.ts +10 -0
  285. package/bin/terminal/user/models.d.ts.map +1 -0
  286. package/bin/terminal/user/models.js +39 -0
  287. package/bin/terminal/user/models.js.map +1 -0
  288. package/bin/utils/storage.d.ts +0 -1
  289. package/bin/utils/storage.d.ts.map +1 -1
  290. package/bin/utils/storage.js +0 -6
  291. package/bin/utils/storage.js.map +1 -1
  292. package/package.json +7 -2
  293. package/public/app.js +3 -3
  294. package/src/cli/Index.ts +13 -3
  295. package/src/cli/agent/AgentChat.ts +113 -289
  296. package/src/cli/agent/AgentChatTypes.ts +8 -12
  297. package/src/cli/agent/AgentHistory.ts +2 -2
  298. package/src/cli/agent/AgentManager.ts +27 -28
  299. package/src/cli/agent/AgentManagerTypes.ts +2 -2
  300. package/src/cli/agent/AgentReset.ts +4 -4
  301. package/src/cli/agent/AgentSelection.ts +6 -6
  302. package/src/cli/agent/AgentSelectionTypes.ts +1 -1
  303. package/src/cli/agent/Init.ts +22 -21
  304. package/src/cli/agent/Restart.ts +2 -2
  305. package/src/cli/agent/Run.ts +46 -30
  306. package/src/cli/agent/Start.ts +2 -2
  307. package/src/cli/agent/Stop.ts +2 -2
  308. package/src/cli/control-plane/ControlPlaneProcess.ts +7 -8
  309. package/src/cli/model/ModelCreateCommand.ts +1 -1
  310. package/src/cli/model/ModelManageCommand.ts +5 -3
  311. package/src/cli/model/ModelManager.ts +3 -3
  312. package/src/cli/model/ModelSupport.ts +2 -10
  313. package/src/cli/shared/ChatAuth.ts +10 -11
  314. package/src/cli/shared/ChatManager.ts +2 -3
  315. package/src/cli/shared/CliReporterTypes.ts +1 -1
  316. package/src/cli/shared/Config.ts +2 -2
  317. package/src/cli/shared/Env.ts +22 -230
  318. package/src/cli/shared/IndexAgentCommand.ts +3 -4
  319. package/src/cli/shared/IndexSupport.ts +16 -10
  320. package/src/cli/shared/ManagedPluginActionCommands.ts +15 -12
  321. package/src/cli/shared/ManagedPluginRemote.ts +4 -4
  322. package/src/cli/shared/PluginScheduleCommand.ts +11 -10
  323. package/src/cli/shared/PluginTargetSupport.ts +25 -26
  324. package/src/cli/shared/Plugins.ts +26 -20
  325. package/src/cli/shared/PublicHostEnv.ts +2 -2
  326. package/src/cli/shared/Terminal.ts +24 -0
  327. package/src/config/DowncitySchema.ts +3 -113
  328. package/src/config/Paths.ts +9 -90
  329. package/src/control/ChannelAccountApiRoutes.ts +2 -3
  330. package/src/control/ControlGateway.ts +6 -5
  331. package/src/control/EnvApiRoutes.ts +7 -91
  332. package/src/control/PlatformApiRoutes.ts +6 -6
  333. package/src/control/PluginApiRoutes.ts +37 -27
  334. package/src/control/gateway/AgentActions.ts +26 -21
  335. package/src/control/gateway/AgentCatalog.ts +17 -21
  336. package/src/control/instant/InstantSessionRunner.ts +3 -1
  337. package/src/env/ProcessEnv.ts +43 -0
  338. package/src/http/auth/AuthEnv.ts +1 -1
  339. package/src/model/runtime/CreateRuntimeModel.ts +51 -59
  340. package/src/model/runtime/ExecutionModelBinding.ts +120 -0
  341. package/src/model/service/ModelPoolService.ts +13 -11
  342. package/src/platform/store/StoreEnvRepository.ts +31 -234
  343. package/src/platform/store/StoreSchema.ts +3 -49
  344. package/src/platform/store/index.ts +11 -80
  345. package/src/platform/store/schema.ts +2 -2
  346. package/src/process/daemon/Api.ts +1 -1
  347. package/src/process/daemon/CliArgs.ts +24 -1
  348. package/src/process/daemon/Client.ts +90 -22
  349. package/src/process/daemon/Manager.ts +2 -1
  350. package/src/process/registry/AgentHostRuntime.ts +1 -163
  351. package/src/terminal/admin/auth-error.ts +62 -0
  352. package/src/terminal/admin/commands/accounts.ts +44 -0
  353. package/src/terminal/admin/commands/balance.ts +160 -0
  354. package/src/terminal/admin/commands/config.ts +13 -0
  355. package/src/terminal/admin/commands/custom.ts +46 -0
  356. package/src/terminal/admin/commands/instruction.ts +12 -0
  357. package/src/terminal/admin/commands/models.ts +64 -0
  358. package/src/terminal/admin/commands/payment.ts +94 -0
  359. package/src/terminal/admin/commands/products.ts +72 -0
  360. package/src/terminal/admin/commands/service-env.ts +256 -0
  361. package/src/terminal/admin/commands/usage.ts +44 -0
  362. package/src/terminal/admin/loop.ts +69 -0
  363. package/src/terminal/agent/pi-agent.ts +180 -0
  364. package/src/terminal/app.ts +120 -0
  365. package/src/terminal/auth/admin.ts +21 -0
  366. package/src/terminal/auth/mode-select.ts +38 -0
  367. package/src/terminal/auth/server-switch.ts +275 -0
  368. package/src/terminal/auth/user.ts +351 -0
  369. package/src/terminal/core/browser.ts +31 -0
  370. package/src/terminal/core/env.ts +71 -0
  371. package/src/terminal/core/session.ts +450 -0
  372. package/src/terminal/core/stripe.ts +37 -0
  373. package/src/terminal/core/ui.ts +84 -0
  374. package/src/terminal/core/update.ts +230 -0
  375. package/src/terminal/user/balance.ts +215 -0
  376. package/src/terminal/user/chat.ts +80 -0
  377. package/src/terminal/user/loop.ts +112 -0
  378. package/src/terminal/user/models.ts +43 -0
  379. package/src/utils/storage.ts +0 -7
  380. package/tsconfig.json +2 -1
  381. package/bin/platform/chatAuthorization/Store.d.ts +0 -31
  382. package/bin/platform/chatAuthorization/Store.d.ts.map +0 -1
  383. package/bin/platform/chatAuthorization/Store.js +0 -145
  384. package/bin/platform/chatAuthorization/Store.js.map +0 -1
  385. package/bin/process/rpc/Client.d.ts +0 -13
  386. package/bin/process/rpc/Client.d.ts.map +0 -1
  387. package/bin/process/rpc/Client.js +0 -98
  388. package/bin/process/rpc/Client.js.map +0 -1
  389. package/bin/process/rpc/Paths.d.ts +0 -14
  390. package/bin/process/rpc/Paths.d.ts.map +0 -1
  391. package/bin/process/rpc/Paths.js +0 -36
  392. package/bin/process/rpc/Paths.js.map +0 -1
  393. package/src/platform/chatAuthorization/Store.ts +0 -181
  394. package/src/process/rpc/Client.ts +0 -113
  395. package/src/process/rpc/Paths.ts +0 -43
@@ -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
+ }
@@ -0,0 +1,351 @@
1
+ /**
2
+ * User 鉴权模块。
3
+ *
4
+ * 登录方式不在 CLI 里写死,而是先读取 InfraRuntime 返回的 providers:
5
+ * 1. Email Login — 邮箱 + 密码直接登录
6
+ * 2. Email Register — 邮箱 + 密码注册 → 验证码 → 完成
7
+ * 3. 任意 OAuth Provider — 浏览器授权(完全以服务端 providers 返回为准)
8
+ *
9
+ * 已有有效 session 直接返回,不重复鉴权。
10
+ */
11
+
12
+ import { UserClient } from "@downcity/conduit";
13
+ import { select, isCancel } from "@clack/prompts";
14
+ import { normalizeBaseUrl } from "../core/env.js";
15
+ import { openBrowser } from "../core/browser.js";
16
+ import { readUserSession, writeUserSession, readConfig, type UserSession } from "../core/session.js";
17
+ import { askText, askSecret, showError, showSuccess, show } from "../core/ui.js";
18
+
19
+ export interface UserContext {
20
+ session: UserSession;
21
+ config: { model: string };
22
+ }
23
+
24
+ type AuthMethod = "login" | "register" | `oauth:${string}`;
25
+
26
+ /**
27
+ * 服务端返回的单个登录方式描述。
28
+ */
29
+ interface AccountsProviderItem {
30
+ /**
31
+ * 登录方式标识。
32
+ */
33
+ id?: string;
34
+
35
+ /**
36
+ * 登录方式类别。
37
+ */
38
+ type?: string;
39
+
40
+ /**
41
+ * 当前 InfraRuntime 是否真的启用了该登录方式。
42
+ */
43
+ enabled?: boolean;
44
+
45
+ /**
46
+ * 邮箱登录是否开放。
47
+ */
48
+ login_enabled?: boolean;
49
+
50
+ /**
51
+ * 邮箱注册是否开放。
52
+ */
53
+ register_enabled?: boolean;
54
+
55
+ /**
56
+ * 当登录方式不可用时的原因码。
57
+ */
58
+ reason?: string;
59
+ }
60
+
61
+ /**
62
+ * 登录菜单项。
63
+ */
64
+ interface AuthOption {
65
+ /**
66
+ * 菜单展示文案。
67
+ */
68
+ label: string;
69
+
70
+ /**
71
+ * 选择后进入的鉴权方式。
72
+ */
73
+ value: AuthMethod;
74
+
75
+ /**
76
+ * 菜单辅助提示。
77
+ */
78
+ hint: string;
79
+ }
80
+
81
+ // ===========================================================================
82
+ // 入口
83
+ // ===========================================================================
84
+
85
+ export async function userAuth(baseUrl: string): Promise<UserContext | undefined> {
86
+ const existing = readUserSession(normalizeBaseUrl(baseUrl));
87
+ if (existing) return { session: existing, config: readConfig() };
88
+
89
+ while (true) {
90
+ const method = await selectAuthMethod(baseUrl);
91
+ if (!method) return undefined;
92
+
93
+ const ctx = await doAuth(baseUrl, method);
94
+ if (ctx) return ctx;
95
+ }
96
+ }
97
+
98
+ async function selectAuthMethod(baseUrl: string): Promise<AuthMethod | undefined> {
99
+ const options = await loadAuthOptions(baseUrl);
100
+ if (options.length === 0) {
101
+ showError("No sign-in methods enabled on server.");
102
+ return undefined;
103
+ }
104
+
105
+ const selected = await select({
106
+ message: "Sign in",
107
+ options,
108
+ });
109
+ if (!selected || isCancel(selected)) return undefined;
110
+ return selected as AuthMethod;
111
+ }
112
+
113
+ async function loadAuthOptions(baseUrl: string): Promise<AuthOption[]> {
114
+ const client = new UserClient({ base_url: normalizeBaseUrl(baseUrl) });
115
+ const accounts = client.service("accounts");
116
+
117
+ try {
118
+ const result = await accounts.get<{ items?: AccountsProviderItem[] }>("providers");
119
+ return mapProvidersToOptions(result.items ?? []);
120
+ } catch (e) {
121
+ showError(`Failed to load sign-in methods: ${e instanceof Error ? e.message : String(e)}`);
122
+ return [];
123
+ }
124
+ }
125
+
126
+ function mapProvidersToOptions(items: AccountsProviderItem[]): AuthOption[] {
127
+ const options: AuthOption[] = [];
128
+
129
+ for (const item of items) {
130
+ if (!item.enabled) continue;
131
+
132
+ if (item.id === "email" && item.type === "password") {
133
+ if (item.login_enabled !== false) {
134
+ options.push({ label: "Email Login", value: "login", hint: "Sign in with email + password" });
135
+ }
136
+ if (item.register_enabled !== false) {
137
+ options.push({ label: "Email Register", value: "register", hint: "Create a new account" });
138
+ }
139
+ continue;
140
+ }
141
+
142
+ if (item.type === "oauth" && typeof item.id === "string" && item.id.trim()) {
143
+ const provider = item.id.trim();
144
+ options.push({
145
+ label: formatOAuthProviderLabel(provider),
146
+ value: `oauth:${provider}`,
147
+ hint: `Sign in with ${formatOAuthProviderLabel(provider)} OAuth`,
148
+ });
149
+ }
150
+ }
151
+
152
+ return options;
153
+ }
154
+
155
+ // ===========================================================================
156
+ // 鉴权分发
157
+ // ===========================================================================
158
+
159
+ async function doAuth(baseUrl: string, method: AuthMethod): Promise<UserContext | undefined> {
160
+ if (method.startsWith("oauth:")) {
161
+ return oauthAuth(baseUrl, method.slice("oauth:".length));
162
+ }
163
+
164
+ switch (method) {
165
+ case "login": return emailLogin(baseUrl);
166
+ case "register": return emailRegister(baseUrl);
167
+ }
168
+ }
169
+
170
+ // ===========================================================================
171
+ // 邮箱登录
172
+ // ===========================================================================
173
+
174
+ interface LoginResult {
175
+ user_token?: string;
176
+ user_id?: string;
177
+ email?: string;
178
+ error?: string;
179
+ }
180
+
181
+ async function emailLogin(baseUrl: string): Promise<UserContext | undefined> {
182
+ const email = await askText("email");
183
+ if (!email || !email.includes("@")) { showError("invalid email"); return undefined; }
184
+
185
+ const password = await askSecret("password");
186
+ if (!password) return undefined;
187
+
188
+ const client = new UserClient({ base_url: normalizeBaseUrl(baseUrl) });
189
+ const accounts = client.service("accounts");
190
+
191
+ try {
192
+ const result = await accounts.action("login").invoke<LoginResult>({ email, password });
193
+ if (result.error) { showError(result.error); return undefined; }
194
+ if (!result.user_token) { showError("login failed: no token"); return undefined; }
195
+
196
+ return saveSession(baseUrl, email, result as { user_token: string; user_id?: string });
197
+ } catch (e) {
198
+ showError(e instanceof Error ? e.message : String(e));
199
+ return undefined;
200
+ }
201
+ }
202
+
203
+ // ===========================================================================
204
+ // 邮箱注册 + 验证
205
+ // ===========================================================================
206
+
207
+ interface RegisterResult {
208
+ success?: boolean;
209
+ message?: string;
210
+ verification_token?: string;
211
+ user_id?: string;
212
+ error?: string;
213
+ }
214
+
215
+ interface VerifyResult {
216
+ user_token?: string;
217
+ user_id?: string;
218
+ error?: string;
219
+ }
220
+
221
+ async function emailRegister(baseUrl: string): Promise<UserContext | undefined> {
222
+ const email = await askText("email");
223
+ if (!email || !email.includes("@")) { showError("invalid email"); return undefined; }
224
+
225
+ const password = await askSecret("password (min 8 characters)");
226
+ if (!password || password.length < 8) { showError("password must be at least 8 characters"); return undefined; }
227
+
228
+ const client = new UserClient({ base_url: normalizeBaseUrl(baseUrl) });
229
+ const accounts = client.service("accounts");
230
+
231
+ let reg: RegisterResult;
232
+ try {
233
+ reg = await accounts.action("register").invoke<RegisterResult>({ email, password });
234
+ } catch (e) {
235
+ showError(e instanceof Error ? e.message : String(e));
236
+ return undefined;
237
+ }
238
+
239
+ if (reg.error) { showError(reg.error); return undefined; }
240
+ if (!reg.success) { showError("registration failed"); return undefined; }
241
+
242
+ showSuccess("Verification code sent to your email");
243
+ show("If email delivery is unavailable, check server logs for the verification code.");
244
+
245
+ const token = await askText("verification token");
246
+ if (!token) return undefined;
247
+
248
+ try {
249
+ const verify = await accounts.action("verify-email").invoke<VerifyResult>({ token: token.trim() });
250
+ if (verify.error) { showError(verify.error); return undefined; }
251
+ if (!verify.user_token) { showError("verification failed: no token"); return undefined; }
252
+
253
+ return saveSession(baseUrl, email, verify as { user_token: string; user_id?: string });
254
+ } catch (e) {
255
+ showError(e instanceof Error ? e.message : String(e));
256
+ return undefined;
257
+ }
258
+ }
259
+
260
+ // ===========================================================================
261
+ // OAuth 登录 (GitHub / Google)
262
+ // ===========================================================================
263
+
264
+ interface OAuthStartResult {
265
+ url?: string;
266
+ state?: string;
267
+ error?: string;
268
+ }
269
+
270
+ interface OAuthPollResult {
271
+ status?: string;
272
+ user_token?: string;
273
+ error?: string;
274
+ }
275
+
276
+ async function oauthAuth(baseUrl: string, provider: string): Promise<UserContext | undefined> {
277
+ const client = new UserClient({ base_url: normalizeBaseUrl(baseUrl) });
278
+ const accounts = client.service("accounts");
279
+
280
+ let start: OAuthStartResult;
281
+ try {
282
+ start = await accounts.action("oauth/start").invoke<OAuthStartResult>({ provider });
283
+ } catch (e) {
284
+ showError(e instanceof Error ? e.message : String(e));
285
+ return undefined;
286
+ }
287
+
288
+ if (start.error) { showError(start.error); return undefined; }
289
+ if (!start.url || !start.state) { showError("failed to start OAuth"); return undefined; }
290
+
291
+ show(`Opening browser for ${provider} authorization...`);
292
+ const opened = openBrowser(start.url);
293
+ if (!opened) showError(`Could not open browser. Please visit:\n ${start.url}`);
294
+
295
+ show("Waiting for authorization...");
296
+ const result = await pollOAuth(client, start.state);
297
+
298
+ if (!result || result.error) { showError(result?.error ?? "OAuth failed"); return undefined; }
299
+ if (!result.user_token) { showError("OAuth failed: no token"); return undefined; }
300
+
301
+ showSuccess(`${provider} login successful`);
302
+ return saveSession(baseUrl, `${provider}:`, result as { user_token: string; user_id?: string });
303
+ }
304
+
305
+ /** 轮询 OAuth 结果(最多 3 分钟) */
306
+ async function pollOAuth(client: UserClient, state: string): Promise<OAuthPollResult | undefined> {
307
+ const accounts = client.service("accounts");
308
+ for (let i = 0; i < 180; i++) {
309
+ try {
310
+ const result = await accounts.get<OAuthPollResult>("oauth/result", { state });
311
+ if (result.error) return result;
312
+ if (result.status === "done") return result;
313
+ } catch { /* continue polling */ }
314
+ await sleep(1000);
315
+ }
316
+ return { error: "OAuth timed out" };
317
+ }
318
+
319
+ // ===========================================================================
320
+ // 工具函数
321
+ // ===========================================================================
322
+
323
+ function saveSession(baseUrl: string, email: string, result: { user_token: string; user_id?: string }): UserContext {
324
+ const session: UserSession = {
325
+ base_url: normalizeBaseUrl(baseUrl),
326
+ email,
327
+ user_id: result.user_id ?? "",
328
+ product_id: "prod_downcity",
329
+ user_token: result.user_token,
330
+ };
331
+ writeUserSession(session);
332
+ showSuccess(`signed in: ${email}`);
333
+ return { session, config: readConfig() };
334
+ }
335
+
336
+ function sleep(ms: number): Promise<void> {
337
+ return new Promise((resolve) => setTimeout(resolve, ms));
338
+ }
339
+
340
+ function formatOAuthProviderLabel(provider: string): string {
341
+ const normalized = provider.trim().toLowerCase();
342
+ if (!normalized) return "OAuth";
343
+ if (normalized === "github") return "GitHub";
344
+ if (normalized === "google") return "Google";
345
+ if (normalized === "wechat") return "WeChat";
346
+ return normalized
347
+ .split(/[_-]+/)
348
+ .filter(Boolean)
349
+ .map((part) => part.slice(0, 1).toUpperCase() + part.slice(1))
350
+ .join(" ");
351
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * 浏览器工具模块。
3
+ *
4
+ * 关键说明(中文)
5
+ * - 统一封装跨平台打开默认浏览器
6
+ * - Stripe Checkout、OAuth 登录都复用这里,避免重复实现
7
+ */
8
+
9
+ import { execFileSync } from "node:child_process";
10
+
11
+ /**
12
+ * 打开系统默认浏览器。
13
+ */
14
+ export function openBrowser(url: string): boolean {
15
+ try {
16
+ if (process.platform === "darwin") {
17
+ execFileSync("open", [url], { stdio: "ignore" });
18
+ return true;
19
+ }
20
+
21
+ if (process.platform === "win32") {
22
+ execFileSync("cmd", ["/c", "start", "", url], { stdio: "ignore" });
23
+ return true;
24
+ }
25
+
26
+ execFileSync("xdg-open", [url], { stdio: "ignore" });
27
+ return true;
28
+ } catch {
29
+ return false;
30
+ }
31
+ }