@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.
- package/README.md +4 -9
- package/bin/cli/Index.js +2 -0
- package/bin/cli/Index.js.map +1 -1
- package/bin/cli/agent/AgentChat.d.ts +2 -1
- package/bin/cli/agent/AgentChat.d.ts.map +1 -1
- package/bin/cli/agent/AgentChat.js +93 -214
- package/bin/cli/agent/AgentChat.js.map +1 -1
- package/bin/cli/agent/AgentChatTypes.d.ts +8 -12
- package/bin/cli/agent/AgentChatTypes.d.ts.map +1 -1
- package/bin/cli/agent/AgentHistory.js +2 -2
- package/bin/cli/agent/AgentHistory.js.map +1 -1
- package/bin/cli/agent/AgentManager.d.ts.map +1 -1
- package/bin/cli/agent/AgentManager.js +26 -27
- package/bin/cli/agent/AgentManager.js.map +1 -1
- package/bin/cli/agent/AgentManagerTypes.d.ts +2 -2
- package/bin/cli/agent/AgentManagerTypes.d.ts.map +1 -1
- package/bin/cli/agent/AgentReset.js +4 -4
- package/bin/cli/agent/AgentReset.js.map +1 -1
- package/bin/cli/agent/AgentSelection.js +6 -6
- package/bin/cli/agent/AgentSelection.js.map +1 -1
- package/bin/cli/agent/AgentSelectionTypes.d.ts +1 -1
- package/bin/cli/agent/AgentSelectionTypes.d.ts.map +1 -1
- package/bin/cli/agent/Init.js +10 -10
- package/bin/cli/agent/Init.js.map +1 -1
- package/bin/cli/agent/Restart.js +2 -2
- package/bin/cli/agent/Restart.js.map +1 -1
- package/bin/cli/agent/Run.d.ts +1 -1
- package/bin/cli/agent/Run.d.ts.map +1 -1
- package/bin/cli/agent/Run.js +37 -17
- package/bin/cli/agent/Run.js.map +1 -1
- package/bin/cli/agent/Start.js +2 -2
- package/bin/cli/agent/Start.js.map +1 -1
- package/bin/cli/agent/Stop.js +2 -2
- package/bin/cli/agent/Stop.js.map +1 -1
- package/bin/cli/control-plane/ControlPlaneProcess.js +5 -5
- package/bin/cli/control-plane/ControlPlaneProcess.js.map +1 -1
- package/bin/cli/model/ModelCreateCommand.js +1 -1
- package/bin/cli/model/ModelCreateCommand.js.map +1 -1
- package/bin/cli/model/ModelManageCommand.d.ts.map +1 -1
- package/bin/cli/model/ModelManageCommand.js +5 -3
- package/bin/cli/model/ModelManageCommand.js.map +1 -1
- package/bin/cli/model/ModelManager.js +3 -3
- package/bin/cli/model/ModelManager.js.map +1 -1
- package/bin/cli/model/ModelSupport.d.ts +0 -1
- package/bin/cli/model/ModelSupport.d.ts.map +1 -1
- package/bin/cli/model/ModelSupport.js +2 -11
- package/bin/cli/model/ModelSupport.js.map +1 -1
- package/bin/cli/shared/CliReporterTypes.d.ts +1 -1
- package/bin/cli/shared/Config.js +2 -2
- package/bin/cli/shared/Config.js.map +1 -1
- package/bin/cli/shared/Env.d.ts +1 -1
- package/bin/cli/shared/Env.d.ts.map +1 -1
- package/bin/cli/shared/Env.js +18 -149
- package/bin/cli/shared/Env.js.map +1 -1
- package/bin/cli/shared/IndexAgentCommand.d.ts.map +1 -1
- package/bin/cli/shared/IndexAgentCommand.js +3 -3
- package/bin/cli/shared/IndexAgentCommand.js.map +1 -1
- package/bin/cli/shared/IndexSupport.d.ts +3 -3
- package/bin/cli/shared/IndexSupport.d.ts.map +1 -1
- package/bin/cli/shared/IndexSupport.js +14 -8
- package/bin/cli/shared/IndexSupport.js.map +1 -1
- package/bin/cli/shared/ManagedPluginActionCommands.d.ts.map +1 -1
- package/bin/cli/shared/ManagedPluginActionCommands.js +5 -4
- package/bin/cli/shared/ManagedPluginActionCommands.js.map +1 -1
- package/bin/cli/shared/ManagedPluginRemote.d.ts.map +1 -1
- package/bin/cli/shared/ManagedPluginRemote.js +4 -4
- package/bin/cli/shared/ManagedPluginRemote.js.map +1 -1
- package/bin/cli/shared/PluginTargetSupport.d.ts +2 -2
- package/bin/cli/shared/PluginTargetSupport.d.ts.map +1 -1
- package/bin/cli/shared/PluginTargetSupport.js +19 -19
- package/bin/cli/shared/PluginTargetSupport.js.map +1 -1
- package/bin/cli/shared/Plugins.js +10 -10
- package/bin/cli/shared/Plugins.js.map +1 -1
- package/bin/cli/shared/PublicHostEnv.d.ts +1 -1
- package/bin/cli/shared/PublicHostEnv.js +2 -2
- package/bin/cli/shared/PublicHostEnv.js.map +1 -1
- package/bin/cli/shared/Terminal.d.ts +13 -0
- package/bin/cli/shared/Terminal.d.ts.map +1 -0
- package/bin/cli/shared/Terminal.js +22 -0
- package/bin/cli/shared/Terminal.js.map +1 -0
- package/bin/config/DowncitySchema.d.ts.map +1 -1
- package/bin/config/DowncitySchema.js +3 -111
- package/bin/config/DowncitySchema.js.map +1 -1
- package/bin/config/Paths.d.ts +0 -56
- package/bin/config/Paths.d.ts.map +1 -1
- package/bin/config/Paths.js +9 -51
- package/bin/config/Paths.js.map +1 -1
- package/bin/control/ControlGateway.js +1 -1
- package/bin/control/ControlGateway.js.map +1 -1
- package/bin/control/EnvApiRoutes.d.ts +1 -1
- package/bin/control/EnvApiRoutes.d.ts.map +1 -1
- package/bin/control/EnvApiRoutes.js +7 -79
- package/bin/control/EnvApiRoutes.js.map +1 -1
- package/bin/control/PlatformApiRoutes.d.ts +2 -2
- package/bin/control/PlatformApiRoutes.d.ts.map +1 -1
- package/bin/control/PlatformApiRoutes.js +2 -2
- package/bin/control/PlatformApiRoutes.js.map +1 -1
- package/bin/control/gateway/AgentActions.d.ts +2 -2
- package/bin/control/gateway/AgentActions.d.ts.map +1 -1
- package/bin/control/gateway/AgentActions.js +7 -7
- package/bin/control/gateway/AgentActions.js.map +1 -1
- package/bin/control/gateway/AgentCatalog.d.ts +3 -6
- package/bin/control/gateway/AgentCatalog.d.ts.map +1 -1
- package/bin/control/gateway/AgentCatalog.js +16 -18
- package/bin/control/gateway/AgentCatalog.js.map +1 -1
- package/bin/control/instant/InstantSessionRunner.d.ts.map +1 -1
- package/bin/control/instant/InstantSessionRunner.js +3 -1
- package/bin/control/instant/InstantSessionRunner.js.map +1 -1
- package/bin/env/ProcessEnv.d.ts +24 -0
- package/bin/env/ProcessEnv.d.ts.map +1 -0
- package/bin/env/ProcessEnv.js +41 -0
- package/bin/env/ProcessEnv.js.map +1 -0
- package/bin/http/auth/AuthEnv.d.ts +1 -1
- package/bin/http/auth/AuthEnv.js +1 -1
- package/bin/model/runtime/CreateRuntimeModel.d.ts +8 -0
- package/bin/model/runtime/CreateRuntimeModel.d.ts.map +1 -1
- package/bin/model/runtime/CreateRuntimeModel.js +43 -37
- package/bin/model/runtime/CreateRuntimeModel.js.map +1 -1
- package/bin/model/service/ModelPoolService.d.ts +1 -1
- package/bin/model/service/ModelPoolService.d.ts.map +1 -1
- package/bin/model/service/ModelPoolService.js +8 -6
- package/bin/model/service/ModelPoolService.js.map +1 -1
- package/bin/platform/store/StoreEnvRepository.d.ts +5 -49
- package/bin/platform/store/StoreEnvRepository.d.ts.map +1 -1
- package/bin/platform/store/StoreEnvRepository.js +31 -178
- package/bin/platform/store/StoreEnvRepository.js.map +1 -1
- package/bin/platform/store/StoreSchema.js +3 -44
- package/bin/platform/store/StoreSchema.js.map +1 -1
- package/bin/platform/store/index.d.ts +9 -45
- package/bin/platform/store/index.d.ts.map +1 -1
- package/bin/platform/store/index.js +12 -62
- package/bin/platform/store/index.js.map +1 -1
- package/bin/platform/store/schema.d.ts +2 -2
- package/bin/platform/store/schema.js +2 -2
- package/bin/process/daemon/Api.d.ts +1 -1
- package/bin/process/daemon/CliArgs.d.ts +1 -0
- package/bin/process/daemon/CliArgs.d.ts.map +1 -1
- package/bin/process/daemon/CliArgs.js +20 -1
- package/bin/process/daemon/CliArgs.js.map +1 -1
- package/bin/process/daemon/Client.d.ts +18 -2
- package/bin/process/daemon/Client.d.ts.map +1 -1
- package/bin/process/daemon/Client.js +70 -20
- package/bin/process/daemon/Client.js.map +1 -1
- package/bin/process/daemon/Manager.d.ts.map +1 -1
- package/bin/process/daemon/Manager.js +2 -1
- package/bin/process/daemon/Manager.js.map +1 -1
- package/bin/terminal/admin/auth-error.d.ts +34 -0
- package/bin/terminal/admin/auth-error.d.ts.map +1 -0
- package/bin/terminal/admin/auth-error.js +51 -0
- package/bin/terminal/admin/auth-error.js.map +1 -0
- package/bin/terminal/admin/commands/accounts.d.ts +6 -0
- package/bin/terminal/admin/commands/accounts.d.ts.map +1 -0
- package/bin/terminal/admin/commands/accounts.js +44 -0
- package/bin/terminal/admin/commands/accounts.js.map +1 -0
- package/bin/terminal/admin/commands/balance.d.ts +6 -0
- package/bin/terminal/admin/commands/balance.d.ts.map +1 -0
- package/bin/terminal/admin/commands/balance.js +153 -0
- package/bin/terminal/admin/commands/balance.js.map +1 -0
- package/bin/terminal/admin/commands/config.d.ts +10 -0
- package/bin/terminal/admin/commands/config.d.ts.map +1 -0
- package/bin/terminal/admin/commands/config.js +11 -0
- package/bin/terminal/admin/commands/config.js.map +1 -0
- package/bin/terminal/admin/commands/custom.d.ts +6 -0
- package/bin/terminal/admin/commands/custom.d.ts.map +1 -0
- package/bin/terminal/admin/commands/custom.js +47 -0
- package/bin/terminal/admin/commands/custom.js.map +1 -0
- package/bin/terminal/admin/commands/instruction.d.ts +9 -0
- package/bin/terminal/admin/commands/instruction.d.ts.map +1 -0
- package/bin/terminal/admin/commands/instruction.js +10 -0
- package/bin/terminal/admin/commands/instruction.js.map +1 -0
- package/bin/terminal/admin/commands/models.d.ts +14 -0
- package/bin/terminal/admin/commands/models.d.ts.map +1 -0
- package/bin/terminal/admin/commands/models.js +61 -0
- package/bin/terminal/admin/commands/models.js.map +1 -0
- package/bin/terminal/admin/commands/payment.d.ts +6 -0
- package/bin/terminal/admin/commands/payment.d.ts.map +1 -0
- package/bin/terminal/admin/commands/payment.js +59 -0
- package/bin/terminal/admin/commands/payment.js.map +1 -0
- package/bin/terminal/admin/commands/products.d.ts +6 -0
- package/bin/terminal/admin/commands/products.d.ts.map +1 -0
- package/bin/terminal/admin/commands/products.js +80 -0
- package/bin/terminal/admin/commands/products.js.map +1 -0
- package/bin/terminal/admin/commands/service-env.d.ts +11 -0
- package/bin/terminal/admin/commands/service-env.d.ts.map +1 -0
- package/bin/terminal/admin/commands/service-env.js +248 -0
- package/bin/terminal/admin/commands/service-env.js.map +1 -0
- package/bin/terminal/admin/commands/usage.d.ts +6 -0
- package/bin/terminal/admin/commands/usage.d.ts.map +1 -0
- package/bin/terminal/admin/commands/usage.js +44 -0
- package/bin/terminal/admin/commands/usage.js.map +1 -0
- package/bin/terminal/admin/loop.d.ts +6 -0
- package/bin/terminal/admin/loop.d.ts.map +1 -0
- package/bin/terminal/admin/loop.js +70 -0
- package/bin/terminal/admin/loop.js.map +1 -0
- package/bin/terminal/agent/pi-agent.d.ts +15 -0
- package/bin/terminal/agent/pi-agent.d.ts.map +1 -0
- package/bin/terminal/agent/pi-agent.js +136 -0
- package/bin/terminal/agent/pi-agent.js.map +1 -0
- package/bin/terminal/app.d.ts +13 -0
- package/bin/terminal/app.d.ts.map +1 -0
- package/bin/terminal/app.js +123 -0
- package/bin/terminal/app.js.map +1 -0
- package/bin/terminal/auth/admin.d.ts +8 -0
- package/bin/terminal/auth/admin.d.ts.map +1 -0
- package/bin/terminal/auth/admin.js +18 -0
- package/bin/terminal/auth/admin.js.map +1 -0
- package/bin/terminal/auth/mode-select.d.ts +11 -0
- package/bin/terminal/auth/mode-select.d.ts.map +1 -0
- package/bin/terminal/auth/mode-select.js +33 -0
- package/bin/terminal/auth/mode-select.js.map +1 -0
- package/bin/terminal/auth/server-switch.d.ts +22 -0
- package/bin/terminal/auth/server-switch.d.ts.map +1 -0
- package/bin/terminal/auth/server-switch.js +241 -0
- package/bin/terminal/auth/server-switch.js.map +1 -0
- package/bin/terminal/auth/user.d.ts +19 -0
- package/bin/terminal/auth/user.d.ts.map +1 -0
- package/bin/terminal/auth/user.js +261 -0
- package/bin/terminal/auth/user.js.map +1 -0
- package/bin/terminal/core/browser.d.ts +12 -0
- package/bin/terminal/core/browser.d.ts.map +1 -0
- package/bin/terminal/core/browser.js +29 -0
- package/bin/terminal/core/browser.js.map +1 -0
- package/bin/terminal/core/env.d.ts +15 -0
- package/bin/terminal/core/env.d.ts.map +1 -0
- package/bin/terminal/core/env.js +67 -0
- package/bin/terminal/core/env.js.map +1 -0
- package/bin/terminal/core/session.d.ts +97 -0
- package/bin/terminal/core/session.d.ts.map +1 -0
- package/bin/terminal/core/session.js +342 -0
- package/bin/terminal/core/session.js.map +1 -0
- package/bin/terminal/core/stripe.d.ts +26 -0
- package/bin/terminal/core/stripe.d.ts.map +1 -0
- package/bin/terminal/core/stripe.js +22 -0
- package/bin/terminal/core/stripe.js.map +1 -0
- package/bin/terminal/core/ui.d.ts +29 -0
- package/bin/terminal/core/ui.d.ts.map +1 -0
- package/bin/terminal/core/ui.js +60 -0
- package/bin/terminal/core/ui.js.map +1 -0
- package/bin/terminal/core/update.d.ts +20 -0
- package/bin/terminal/core/update.d.ts.map +1 -0
- package/bin/terminal/core/update.js +193 -0
- package/bin/terminal/core/update.js.map +1 -0
- package/bin/terminal/user/balance.d.ts +31 -0
- package/bin/terminal/user/balance.d.ts.map +1 -0
- package/bin/terminal/user/balance.js +131 -0
- package/bin/terminal/user/balance.js.map +1 -0
- package/bin/terminal/user/chat.d.ts +12 -0
- package/bin/terminal/user/chat.d.ts.map +1 -0
- package/bin/terminal/user/chat.js +70 -0
- package/bin/terminal/user/chat.js.map +1 -0
- package/bin/terminal/user/loop.d.ts +13 -0
- package/bin/terminal/user/loop.d.ts.map +1 -0
- package/bin/terminal/user/loop.js +93 -0
- package/bin/terminal/user/loop.js.map +1 -0
- package/bin/terminal/user/models.d.ts +10 -0
- package/bin/terminal/user/models.d.ts.map +1 -0
- package/bin/terminal/user/models.js +39 -0
- package/bin/terminal/user/models.js.map +1 -0
- package/bin/utils/storage.d.ts +0 -1
- package/bin/utils/storage.d.ts.map +1 -1
- package/bin/utils/storage.js +0 -6
- package/bin/utils/storage.js.map +1 -1
- package/package.json +7 -3
- package/public/app.js +3 -3
- package/src/cli/Index.ts +2 -0
- package/src/cli/agent/AgentChat.ts +113 -289
- package/src/cli/agent/AgentChatTypes.ts +8 -12
- package/src/cli/agent/AgentHistory.ts +2 -2
- package/src/cli/agent/AgentManager.ts +27 -28
- package/src/cli/agent/AgentManagerTypes.ts +2 -2
- package/src/cli/agent/AgentReset.ts +4 -4
- package/src/cli/agent/AgentSelection.ts +6 -6
- package/src/cli/agent/AgentSelectionTypes.ts +1 -1
- package/src/cli/agent/Init.ts +13 -13
- package/src/cli/agent/Restart.ts +2 -2
- package/src/cli/agent/Run.ts +38 -17
- package/src/cli/agent/Start.ts +2 -2
- package/src/cli/agent/Stop.ts +2 -2
- package/src/cli/control-plane/ControlPlaneProcess.ts +5 -5
- package/src/cli/model/ModelCreateCommand.ts +1 -1
- package/src/cli/model/ModelManageCommand.ts +5 -3
- package/src/cli/model/ModelManager.ts +3 -3
- package/src/cli/model/ModelSupport.ts +2 -10
- package/src/cli/shared/CliReporterTypes.ts +1 -1
- package/src/cli/shared/Config.ts +2 -2
- package/src/cli/shared/Env.ts +22 -230
- package/src/cli/shared/IndexAgentCommand.ts +3 -4
- package/src/cli/shared/IndexSupport.ts +16 -10
- package/src/cli/shared/ManagedPluginActionCommands.ts +4 -4
- package/src/cli/shared/ManagedPluginRemote.ts +4 -4
- package/src/cli/shared/PluginTargetSupport.ts +19 -19
- package/src/cli/shared/Plugins.ts +10 -10
- package/src/cli/shared/PublicHostEnv.ts +2 -2
- package/src/cli/shared/Terminal.ts +24 -0
- package/src/config/DowncitySchema.ts +3 -113
- package/src/config/Paths.ts +9 -90
- package/src/control/ControlGateway.ts +3 -3
- package/src/control/EnvApiRoutes.ts +7 -91
- package/src/control/PlatformApiRoutes.ts +6 -6
- package/src/control/gateway/AgentActions.ts +10 -10
- package/src/control/gateway/AgentCatalog.ts +17 -21
- package/src/control/instant/InstantSessionRunner.ts +3 -1
- package/src/env/ProcessEnv.ts +43 -0
- package/src/http/auth/AuthEnv.ts +1 -1
- package/src/model/runtime/CreateRuntimeModel.ts +54 -37
- package/src/model/service/ModelPoolService.ts +13 -11
- package/src/platform/store/StoreEnvRepository.ts +31 -234
- package/src/platform/store/StoreSchema.ts +3 -49
- package/src/platform/store/index.ts +11 -80
- package/src/platform/store/schema.ts +2 -2
- package/src/process/daemon/Api.ts +1 -1
- package/src/process/daemon/CliArgs.ts +24 -1
- package/src/process/daemon/Client.ts +90 -22
- package/src/process/daemon/Manager.ts +2 -1
- package/src/terminal/admin/auth-error.ts +62 -0
- package/src/terminal/admin/commands/accounts.ts +44 -0
- package/src/terminal/admin/commands/balance.ts +160 -0
- package/src/terminal/admin/commands/config.ts +13 -0
- package/src/terminal/admin/commands/custom.ts +46 -0
- package/src/terminal/admin/commands/instruction.ts +12 -0
- package/src/terminal/admin/commands/models.ts +64 -0
- package/src/terminal/admin/commands/payment.ts +94 -0
- package/src/terminal/admin/commands/products.ts +72 -0
- package/src/terminal/admin/commands/service-env.ts +256 -0
- package/src/terminal/admin/commands/usage.ts +44 -0
- package/src/terminal/admin/loop.ts +69 -0
- package/src/terminal/agent/pi-agent.ts +180 -0
- package/src/terminal/app.ts +120 -0
- package/src/terminal/auth/admin.ts +21 -0
- package/src/terminal/auth/mode-select.ts +38 -0
- package/src/terminal/auth/server-switch.ts +275 -0
- package/src/terminal/auth/user.ts +351 -0
- package/src/terminal/core/browser.ts +31 -0
- package/src/terminal/core/env.ts +71 -0
- package/src/terminal/core/session.ts +450 -0
- package/src/terminal/core/stripe.ts +37 -0
- package/src/terminal/core/ui.ts +84 -0
- package/src/terminal/core/update.ts +230 -0
- package/src/terminal/user/balance.ts +215 -0
- package/src/terminal/user/chat.ts +80 -0
- package/src/terminal/user/loop.ts +112 -0
- package/src/terminal/user/models.ts +43 -0
- package/src/utils/storage.ts +0 -7
- package/bin/process/rpc/Client.d.ts +0 -13
- package/bin/process/rpc/Client.d.ts.map +0 -1
- package/bin/process/rpc/Client.js +0 -98
- package/bin/process/rpc/Client.js.map +0 -1
- package/bin/process/rpc/Paths.d.ts +0 -14
- package/bin/process/rpc/Paths.d.ts.map +0 -1
- package/bin/process/rpc/Paths.js +0 -36
- package/bin/process/rpc/Paths.js.map +0 -1
- package/src/process/rpc/Client.ts +0 -113
- package/src/process/rpc/Paths.ts +0 -43
|
@@ -48,8 +48,8 @@ export const modelsTable = sqliteTable(
|
|
|
48
48
|
* 平台 Env 统一存储表。
|
|
49
49
|
*
|
|
50
50
|
* 关键点(中文)
|
|
51
|
-
* -
|
|
52
|
-
* - `
|
|
51
|
+
* - 当前只保留平台全局 env。
|
|
52
|
+
* - 仍使用 `scope + agent_id + key` 复合主键,其中运行时固定写入 `global + ''`。
|
|
53
53
|
* - value 采用密文存储,解密仅在运行时内存中进行。
|
|
54
54
|
*/
|
|
55
55
|
export const envEntriesTable = sqliteTable(
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* 关键点
|
|
5
5
|
* - daemon(来自 `agent start` / `agent restart`)会拉起一个前台 `agent start`
|
|
6
6
|
* 进程(显式 `--foreground true`),这里负责拼装其 argv。
|
|
7
|
+
* - city 托管的 HTTP gateway 与 agent 本机 RPC 使用不同端口,避免职责混用。
|
|
7
8
|
*/
|
|
8
9
|
|
|
9
10
|
import type { StartOptions } from "@downcity/agent";
|
|
@@ -26,13 +27,35 @@ export const buildRunArgsFromOptions = async (
|
|
|
26
27
|
// 关键点(中文):host 未指定时统一落到 0.0.0.0,保持历史监听行为。
|
|
27
28
|
const host = String(options.host || "0.0.0.0").trim() || "0.0.0.0";
|
|
28
29
|
|
|
29
|
-
//
|
|
30
|
+
// 关键点(中文):外层 HTTP gateway 端口统一由 city 分配。
|
|
30
31
|
const port = await allocateAvailablePort({ host });
|
|
31
32
|
if (!Number.isFinite(port) || Number.isNaN(port) || port <= 0 || port > 65535) {
|
|
32
33
|
throw new Error(`Invalid allocated port: ${String(port)}`);
|
|
33
34
|
}
|
|
34
35
|
|
|
36
|
+
// 关键点(中文):本机 RPC 端口独立分配到另一段端口区间,避免和 HTTP gateway 冲突。
|
|
37
|
+
const rpc_port =
|
|
38
|
+
typeof options.rpcPort === "number" && Number.isInteger(options.rpcPort)
|
|
39
|
+
? options.rpcPort
|
|
40
|
+
: await allocateAvailablePort({
|
|
41
|
+
host: "127.0.0.1",
|
|
42
|
+
start: 15314,
|
|
43
|
+
end: 16399,
|
|
44
|
+
});
|
|
45
|
+
if (
|
|
46
|
+
!Number.isFinite(rpc_port) ||
|
|
47
|
+
Number.isNaN(rpc_port) ||
|
|
48
|
+
rpc_port <= 0 ||
|
|
49
|
+
rpc_port > 65535
|
|
50
|
+
) {
|
|
51
|
+
throw new Error(`Invalid allocated rpc port: ${String(rpc_port)}`);
|
|
52
|
+
}
|
|
53
|
+
if (rpc_port === port) {
|
|
54
|
+
throw new Error(`HTTP port and RPC port must be different: ${port}`);
|
|
55
|
+
}
|
|
56
|
+
|
|
35
57
|
args.push("--port", String(port));
|
|
58
|
+
args.push("--rpc-port", String(rpc_port));
|
|
36
59
|
args.push("--host", host);
|
|
37
60
|
|
|
38
61
|
return args;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* 关键点(中文)
|
|
5
5
|
* - 业务模块统一通过 daemon API 与运行时通信。
|
|
6
|
-
* -
|
|
6
|
+
* - HTTP gateway 与本机 RPC 的地址解析分开,避免端口语义混淆。
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import fs from "fs-extra";
|
|
@@ -62,29 +62,27 @@ function pickArgValue(args: string[], key: string): string | undefined {
|
|
|
62
62
|
return next || undefined;
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
|
|
66
|
-
* 解析 daemon endpoint。
|
|
67
|
-
*
|
|
68
|
-
* 优先级(中文)
|
|
69
|
-
* 1) 显式入参 `host/port`
|
|
70
|
-
* 2) 环境变量 `DC_SERVER_*` / `DC_CTX_SERVER_*`
|
|
71
|
-
* 3) daemon meta args(`downcity.daemon.json`)
|
|
72
|
-
* 4) 默认 `127.0.0.1:5314`
|
|
73
|
-
*/
|
|
74
|
-
export function resolveDaemonEndpoint(params: {
|
|
65
|
+
type ResolveDaemonEndpointParams = {
|
|
75
66
|
projectRoot: string;
|
|
76
67
|
host?: string;
|
|
77
68
|
port?: number;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
function resolveDaemonEndpointFromSources(params: {
|
|
72
|
+
projectRoot: string;
|
|
73
|
+
explicit_host?: string;
|
|
74
|
+
explicit_port?: number;
|
|
75
|
+
env_host_name: string;
|
|
76
|
+
env_port_name: string;
|
|
77
|
+
arg_port_name: string;
|
|
78
|
+
default_host: string;
|
|
79
|
+
default_port: number;
|
|
78
80
|
}): DaemonEndpoint {
|
|
79
|
-
const explicitHost = normalizeHost(params.
|
|
80
|
-
const explicitPort = parsePortLike(params.
|
|
81
|
+
const explicitHost = normalizeHost(params.explicit_host);
|
|
82
|
+
const explicitPort = parsePortLike(params.explicit_port);
|
|
81
83
|
|
|
82
|
-
const envHost =
|
|
83
|
-
|
|
84
|
-
normalizeHost(process.env.DC_CTX_SERVER_HOST);
|
|
85
|
-
const envPort =
|
|
86
|
-
parsePortLike(process.env.DC_SERVER_PORT) ||
|
|
87
|
-
parsePortLike(process.env.DC_CTX_SERVER_PORT);
|
|
84
|
+
const envHost = normalizeHost(process.env[params.env_host_name]);
|
|
85
|
+
const envPort = parsePortLike(process.env[params.env_port_name]);
|
|
88
86
|
|
|
89
87
|
let daemonArgHost: string | undefined;
|
|
90
88
|
let daemonArgPort: number | undefined;
|
|
@@ -96,14 +94,14 @@ export function resolveDaemonEndpoint(params: {
|
|
|
96
94
|
? raw.args.map((item) => String(item))
|
|
97
95
|
: [];
|
|
98
96
|
daemonArgHost = normalizeHost(pickArgValue(args, "--host"));
|
|
99
|
-
daemonArgPort = parsePortLike(pickArgValue(args,
|
|
97
|
+
daemonArgPort = parsePortLike(pickArgValue(args, params.arg_port_name));
|
|
100
98
|
}
|
|
101
99
|
} catch {
|
|
102
100
|
// ignore daemon meta errors, fallback to other sources
|
|
103
101
|
}
|
|
104
102
|
|
|
105
|
-
const host = explicitHost || envHost || daemonArgHost ||
|
|
106
|
-
const port = explicitPort || envPort || daemonArgPort ||
|
|
103
|
+
const host = explicitHost || envHost || daemonArgHost || params.default_host;
|
|
104
|
+
const port = explicitPort || envPort || daemonArgPort || params.default_port;
|
|
107
105
|
|
|
108
106
|
return {
|
|
109
107
|
host,
|
|
@@ -112,6 +110,56 @@ export function resolveDaemonEndpoint(params: {
|
|
|
112
110
|
};
|
|
113
111
|
}
|
|
114
112
|
|
|
113
|
+
/**
|
|
114
|
+
* 解析 daemon endpoint。
|
|
115
|
+
*
|
|
116
|
+
* 优先级(中文)
|
|
117
|
+
* 1) 显式入参 `host/port`
|
|
118
|
+
* 2) 环境变量 `DC_CITY_HOST/DC_CITY_PORT`
|
|
119
|
+
* 3) daemon meta args(`downcity.daemon.json`)
|
|
120
|
+
* 4) 默认 `127.0.0.1:5314`
|
|
121
|
+
*/
|
|
122
|
+
export function resolveDaemonEndpoint(params: {
|
|
123
|
+
projectRoot: string;
|
|
124
|
+
host?: string;
|
|
125
|
+
port?: number;
|
|
126
|
+
}): DaemonEndpoint {
|
|
127
|
+
return resolveDaemonEndpointFromSources({
|
|
128
|
+
projectRoot: params.projectRoot,
|
|
129
|
+
explicit_host: params.host,
|
|
130
|
+
explicit_port: params.port,
|
|
131
|
+
env_host_name: "DC_CITY_HOST",
|
|
132
|
+
env_port_name: "DC_CITY_PORT",
|
|
133
|
+
arg_port_name: "--port",
|
|
134
|
+
default_host: "127.0.0.1",
|
|
135
|
+
default_port: 5314,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* 解析 daemon 本机 RPC endpoint。
|
|
141
|
+
*
|
|
142
|
+
* 优先级(中文)
|
|
143
|
+
* 1) 显式入参 `host/port`
|
|
144
|
+
* 2) 环境变量 `DC_AGENT_RPC_HOST/DC_AGENT_RPC_PORT`
|
|
145
|
+
* 3) daemon meta args(`downcity.daemon.json`)
|
|
146
|
+
* 4) 默认 `127.0.0.1:15314`
|
|
147
|
+
*/
|
|
148
|
+
export function resolveDaemonRpcEndpoint(
|
|
149
|
+
params: ResolveDaemonEndpointParams,
|
|
150
|
+
): DaemonEndpoint {
|
|
151
|
+
return resolveDaemonEndpointFromSources({
|
|
152
|
+
projectRoot: params.projectRoot,
|
|
153
|
+
explicit_host: params.host,
|
|
154
|
+
explicit_port: params.port,
|
|
155
|
+
env_host_name: "DC_AGENT_RPC_HOST",
|
|
156
|
+
env_port_name: "DC_AGENT_RPC_PORT",
|
|
157
|
+
arg_port_name: "--rpc-port",
|
|
158
|
+
default_host: "127.0.0.1",
|
|
159
|
+
default_port: 15314,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
115
163
|
/**
|
|
116
164
|
* 调用 daemon JSON API。
|
|
117
165
|
*
|
|
@@ -132,6 +180,12 @@ export async function callServer<T>(
|
|
|
132
180
|
const method = params.method || "GET";
|
|
133
181
|
const hasBody = params.body !== undefined && method !== "GET";
|
|
134
182
|
const headers: Record<string, string> = {};
|
|
183
|
+
const timeoutMs =
|
|
184
|
+
typeof params.timeoutMs === "number" &&
|
|
185
|
+
Number.isFinite(params.timeoutMs) &&
|
|
186
|
+
params.timeoutMs > 0
|
|
187
|
+
? Math.floor(params.timeoutMs)
|
|
188
|
+
: undefined;
|
|
135
189
|
const authHeaderValue = formatCliBearerHeaderValue(
|
|
136
190
|
resolveCliAuthToken({
|
|
137
191
|
explicitToken: params.authToken,
|
|
@@ -145,11 +199,19 @@ export async function callServer<T>(
|
|
|
145
199
|
}
|
|
146
200
|
|
|
147
201
|
try {
|
|
202
|
+
const abortController = timeoutMs ? new AbortController() : undefined;
|
|
203
|
+
const timeoutHandle = timeoutMs
|
|
204
|
+
? setTimeout(() => abortController?.abort(), timeoutMs)
|
|
205
|
+
: undefined;
|
|
148
206
|
const response = await fetch(url, {
|
|
149
207
|
method,
|
|
150
208
|
headers: Object.keys(headers).length > 0 ? headers : undefined,
|
|
151
209
|
body: hasBody ? JSON.stringify(params.body) : undefined,
|
|
210
|
+
signal: abortController?.signal,
|
|
152
211
|
});
|
|
212
|
+
if (timeoutHandle) {
|
|
213
|
+
clearTimeout(timeoutHandle);
|
|
214
|
+
}
|
|
153
215
|
|
|
154
216
|
let data: JsonValue | null = null;
|
|
155
217
|
try {
|
|
@@ -174,6 +236,12 @@ export async function callServer<T>(
|
|
|
174
236
|
data: data as T,
|
|
175
237
|
};
|
|
176
238
|
} catch (error) {
|
|
239
|
+
if (timeoutMs && error instanceof Error && error.name === "AbortError") {
|
|
240
|
+
return {
|
|
241
|
+
success: false,
|
|
242
|
+
error: `Failed to call ${url}: timeout after ${timeoutMs}ms`,
|
|
243
|
+
};
|
|
244
|
+
}
|
|
177
245
|
return {
|
|
178
246
|
success: false,
|
|
179
247
|
error: `Failed to call ${url}: ${String(error)}`,
|
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
upsertManagedAgentEntry,
|
|
29
29
|
} from "@/process/registry/CityRegistry.js";
|
|
30
30
|
import { signalDetachedProcess } from "@/process/registry/ProcessSweep.js";
|
|
31
|
+
import { mergeProcessEnvWithPlatformGlobalEnv } from "@/env/ProcessEnv.js";
|
|
31
32
|
|
|
32
33
|
/**
|
|
33
34
|
* 异步睡眠工具。
|
|
@@ -239,7 +240,7 @@ export const startDaemonProcess = async (params: {
|
|
|
239
240
|
const logFd = fs.openSync(logPath, "a");
|
|
240
241
|
|
|
241
242
|
const childEnv: NodeJS.ProcessEnv = {
|
|
242
|
-
...process.env,
|
|
243
|
+
...mergeProcessEnvWithPlatformGlobalEnv(process.env),
|
|
243
244
|
DOWNCITY_DAEMON: "1",
|
|
244
245
|
};
|
|
245
246
|
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin 鉴权错误工具。
|
|
3
|
+
*
|
|
4
|
+
* 关键说明(中文)
|
|
5
|
+
* - 当 admin key 不正确或已失效时,SDK 会把请求失败包装成带 `status` 的 Error。
|
|
6
|
+
* - 这里统一把 401 转成可识别的 AdminAuthError,方便外层清理缓存 session 并提示重新输入。
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* admin key 无效时给用户展示的统一提示。
|
|
11
|
+
*/
|
|
12
|
+
export const ADMIN_AUTH_INVALID_MESSAGE =
|
|
13
|
+
"Current server admin key is incorrect or expired. Please set it again.";
|
|
14
|
+
|
|
15
|
+
interface HttpClientError extends Error {
|
|
16
|
+
/** HTTP 状态码 */
|
|
17
|
+
status?: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* 判断服务端是否缺少新接口。
|
|
22
|
+
*/
|
|
23
|
+
export function isAdminNotFoundError(error: unknown): boolean {
|
|
24
|
+
return (error as HttpClientError | undefined)?.status === 404;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* admin 鉴权失效错误。
|
|
29
|
+
*/
|
|
30
|
+
export class AdminAuthError extends Error {
|
|
31
|
+
constructor(message = ADMIN_AUTH_INVALID_MESSAGE) {
|
|
32
|
+
super(message);
|
|
33
|
+
this.name = "AdminAuthError";
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* 判断当前错误是否是 admin 鉴权失效。
|
|
39
|
+
*/
|
|
40
|
+
export function isAdminAuthError(error: unknown): error is AdminAuthError {
|
|
41
|
+
return error instanceof AdminAuthError;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* 如果底层错误是 401,则提升为 AdminAuthError。
|
|
46
|
+
*/
|
|
47
|
+
export function rethrowAdminAuthError(error: unknown): void {
|
|
48
|
+
const status = (error as HttpClientError | undefined)?.status;
|
|
49
|
+
if (status === 401) {
|
|
50
|
+
throw new AdminAuthError();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* 提取可展示的错误文本。
|
|
56
|
+
*/
|
|
57
|
+
export function adminErrorMessage(error: unknown): string {
|
|
58
|
+
if (error instanceof Error) {
|
|
59
|
+
return error.message;
|
|
60
|
+
}
|
|
61
|
+
return String(error);
|
|
62
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin Accounts 管理命令。
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { AdminClient } from "@downcity/conduit";
|
|
6
|
+
import { select, isCancel } from "@clack/prompts";
|
|
7
|
+
import { showError } from "../../core/ui.js";
|
|
8
|
+
import { adminErrorMessage, rethrowAdminAuthError } from "../auth-error.js";
|
|
9
|
+
|
|
10
|
+
export async function manageAccounts(a: AdminClient): Promise<void> {
|
|
11
|
+
const svc = a.service("accounts");
|
|
12
|
+
while (true) {
|
|
13
|
+
const act = await select({
|
|
14
|
+
message: "Accounts",
|
|
15
|
+
options: [
|
|
16
|
+
{ label: "List users", value: "users" },
|
|
17
|
+
{ label: "List sessions", value: "sessions" },
|
|
18
|
+
{ label: "Back", value: "back" },
|
|
19
|
+
],
|
|
20
|
+
});
|
|
21
|
+
if (!act || isCancel(act) || act === "back") return;
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
if (act === "users") {
|
|
25
|
+
const b = await svc.get<{ items: { user_id: string; email: string; created_at: string }[] }>("users");
|
|
26
|
+
console.log(`\n${b.items.length} users:\n`);
|
|
27
|
+
for (const u of b.items) {
|
|
28
|
+
console.log(` ${u.user_id.padEnd(30)} ${u.email.padEnd(30)} ${u.created_at.slice(0, 10)}`);
|
|
29
|
+
}
|
|
30
|
+
console.log("");
|
|
31
|
+
} else {
|
|
32
|
+
const b = await svc.get<{ items: { session_id: string; user_id: string; status: string }[] }>("sessions");
|
|
33
|
+
console.log(`\n${b.items.length} sessions:\n`);
|
|
34
|
+
for (const s of b.items) {
|
|
35
|
+
console.log(` ${s.session_id.padEnd(36)} ${s.user_id.padEnd(30)} [${s.status}]`);
|
|
36
|
+
}
|
|
37
|
+
console.log("");
|
|
38
|
+
}
|
|
39
|
+
} catch (e) {
|
|
40
|
+
rethrowAdminAuthError(e);
|
|
41
|
+
showError(adminErrorMessage(e));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin Balance 管理命令。
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { AdminClient } from "@downcity/conduit";
|
|
6
|
+
import { isCancel, select } from "@clack/prompts";
|
|
7
|
+
import { askText, showError, showSuccess } from "../../core/ui.js";
|
|
8
|
+
import { adminErrorMessage, rethrowAdminAuthError } from "../auth-error.js";
|
|
9
|
+
|
|
10
|
+
export async function manageBalance(a: AdminClient): Promise<void> {
|
|
11
|
+
while (true) {
|
|
12
|
+
const act = await select({
|
|
13
|
+
message: "Balance",
|
|
14
|
+
options: [
|
|
15
|
+
{ label: "List users", value: "users" },
|
|
16
|
+
{ label: "History", value: "history" },
|
|
17
|
+
{ label: "Topups", value: "topups" },
|
|
18
|
+
{ label: "Redeem codes", value: "redeem_codes" },
|
|
19
|
+
{ label: "Add balance", value: "add" },
|
|
20
|
+
{ label: "Subtract balance", value: "sub" },
|
|
21
|
+
{ label: "Finish topup", value: "finish" },
|
|
22
|
+
{ label: "Cancel topup", value: "cancel" },
|
|
23
|
+
{ label: "Create redeem code", value: "create_redeem_code" },
|
|
24
|
+
{ label: "Disable redeem code", value: "disable_redeem_code" },
|
|
25
|
+
{ label: "Back", value: "back" },
|
|
26
|
+
],
|
|
27
|
+
});
|
|
28
|
+
if (!act || isCancel(act) || act === "back") return;
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
if (act === "users") {
|
|
32
|
+
const items = await a.balance.listUsers(30);
|
|
33
|
+
console.log(`\n${items.length} balance accounts:\n`);
|
|
34
|
+
for (const item of items) {
|
|
35
|
+
console.log(` ${item.user_id.padEnd(28)} ${String(item.balance).padStart(8)} ${item.unit.padEnd(10)} ${item.updated_at.slice(0, 19)}`);
|
|
36
|
+
}
|
|
37
|
+
console.log("");
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (act === "history") {
|
|
42
|
+
const userId = await askText("user_id (optional)");
|
|
43
|
+
const items = await a.balance.listHistory({
|
|
44
|
+
limit: 30,
|
|
45
|
+
user_id: userId ?? "",
|
|
46
|
+
});
|
|
47
|
+
console.log(`\n${items.length} balance history entries:\n`);
|
|
48
|
+
for (const item of items) {
|
|
49
|
+
console.log(` ${item.created_at.slice(0, 19)} ${item.user_id.padEnd(20)} ${item.kind.padEnd(8)} ${String(item.amount).padStart(6)} -> ${String(item.balance_after).padStart(6)} ${item.note}`);
|
|
50
|
+
}
|
|
51
|
+
console.log("");
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (act === "topups") {
|
|
56
|
+
const userId = await askText("user_id (optional)");
|
|
57
|
+
const items = await a.balance.listTopups({
|
|
58
|
+
limit: 30,
|
|
59
|
+
user_id: userId ?? "",
|
|
60
|
+
});
|
|
61
|
+
console.log(`\n${items.length} topup orders:\n`);
|
|
62
|
+
for (const item of items) {
|
|
63
|
+
console.log(` ${item.topup_id.padEnd(24)} ${item.user_id.padEnd(20)} ${String(item.amount).padStart(6)} ${item.unit.padEnd(10)} [${item.status}] ${item.note}`);
|
|
64
|
+
}
|
|
65
|
+
console.log("");
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (act === "redeem_codes") {
|
|
70
|
+
const status = await askText("status (optional: active/redeemed/disabled)");
|
|
71
|
+
const userId = await askText("redeemed_by_user_id (optional)");
|
|
72
|
+
const items = await a.balance.redeemCodes.list({
|
|
73
|
+
limit: 30,
|
|
74
|
+
status: normalizeRedeemCodeStatus(status),
|
|
75
|
+
user_id: userId ?? "",
|
|
76
|
+
});
|
|
77
|
+
console.log(`\n${items.length} redeem codes:\n`);
|
|
78
|
+
for (const item of items) {
|
|
79
|
+
const owner = item.redeemed_by_user_id || "-";
|
|
80
|
+
console.log(` ${item.redeem_code_id.padEnd(24)} ${item.code_mask.padEnd(22)} ${String(item.amount).padStart(6)} ${item.unit.padEnd(10)} [${item.status.padEnd(8)}] ${owner.padEnd(20)} ${item.note}`);
|
|
81
|
+
}
|
|
82
|
+
console.log("");
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (act === "add" || act === "sub") {
|
|
87
|
+
const userId = await askText("user_id");
|
|
88
|
+
if (!userId) continue;
|
|
89
|
+
const rawAmount = await askText("amount");
|
|
90
|
+
if (!rawAmount) continue;
|
|
91
|
+
|
|
92
|
+
const amount = Number(rawAmount);
|
|
93
|
+
if (!Number.isInteger(amount) || amount <= 0) {
|
|
94
|
+
showError("amount must be a positive integer");
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const note = await askText("note (optional)");
|
|
99
|
+
const account = act === "add"
|
|
100
|
+
? await a.balance.add({ user_id: userId, amount, note: note ?? "" })
|
|
101
|
+
: await a.balance.sub({ user_id: userId, amount, note: note ?? "" });
|
|
102
|
+
showSuccess(`balance updated: ${account.user_id} -> ${account.balance} ${account.unit}`);
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (act === "create_redeem_code") {
|
|
107
|
+
const rawAmount = await askText("amount");
|
|
108
|
+
if (!rawAmount) continue;
|
|
109
|
+
|
|
110
|
+
const amount = Number(rawAmount);
|
|
111
|
+
if (!Number.isInteger(amount) || amount <= 0) {
|
|
112
|
+
showError("amount must be a positive integer");
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const code = await askText("custom redeem_code (optional)");
|
|
117
|
+
const note = await askText("note (optional)");
|
|
118
|
+
const issued = await a.balance.redeemCodes.create({
|
|
119
|
+
amount,
|
|
120
|
+
code: code ?? "",
|
|
121
|
+
note: note ?? "",
|
|
122
|
+
});
|
|
123
|
+
showSuccess(`redeem_code created: ${issued.redeem_code_id} -> ${issued.code} (+${issued.amount} ${issued.unit})`);
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (act === "disable_redeem_code") {
|
|
128
|
+
const redeemCodeId = await askText("redeem_code_id");
|
|
129
|
+
if (!redeemCodeId) continue;
|
|
130
|
+
const note = await askText("note (optional)");
|
|
131
|
+
const item = await a.balance.redeemCodes.disable({
|
|
132
|
+
redeem_code_id: redeemCodeId,
|
|
133
|
+
note: note ?? "",
|
|
134
|
+
});
|
|
135
|
+
showSuccess(`redeem_code updated: ${item.redeem_code_id} -> ${item.status}`);
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const topupId = await askText("topup_id");
|
|
140
|
+
if (!topupId) continue;
|
|
141
|
+
const note = await askText("note (optional)");
|
|
142
|
+
const topup = act === "finish"
|
|
143
|
+
? await a.balance.finishTopup({ topup_id: topupId, note: note ?? "" })
|
|
144
|
+
: await a.balance.cancelTopup({ topup_id: topupId, note: note ?? "" });
|
|
145
|
+
showSuccess(`topup updated: ${topup.topup_id} -> ${topup.status}`);
|
|
146
|
+
} catch (e) {
|
|
147
|
+
rethrowAdminAuthError(e);
|
|
148
|
+
showError(adminErrorMessage(e));
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function normalizeRedeemCodeStatus(value: string | undefined): "active" | "redeemed" | "disabled" | undefined {
|
|
154
|
+
const normalized = String(value ?? "").trim();
|
|
155
|
+
if (!normalized) return undefined;
|
|
156
|
+
if (normalized === "active" || normalized === "redeemed" || normalized === "disabled") {
|
|
157
|
+
return normalized;
|
|
158
|
+
}
|
|
159
|
+
throw new TypeError("status must be active, redeemed, or disabled");
|
|
160
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 旧的 Admin Server URL 命令兼容壳。
|
|
3
|
+
*
|
|
4
|
+
* 关键说明(中文)
|
|
5
|
+
* - 新交互下,server 管理已经提升到顶层 Manage Servers
|
|
6
|
+
* - 这里保留空壳是为了避免历史导入直接报错
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { type AdminSession } from "../../core/session.js";
|
|
10
|
+
|
|
11
|
+
export async function changeServerUrl(_session: AdminSession): Promise<boolean> {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin Custom Service 命令。
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { AdminClient } from "@downcity/conduit";
|
|
6
|
+
import { select, isCancel } from "@clack/prompts";
|
|
7
|
+
import { askText, showError } from "../../core/ui.js";
|
|
8
|
+
import { adminErrorMessage, rethrowAdminAuthError } from "../auth-error.js";
|
|
9
|
+
|
|
10
|
+
export async function manageCustom(a: AdminClient): Promise<void> {
|
|
11
|
+
while (true) {
|
|
12
|
+
const name = await askText("service name (empty to go back)");
|
|
13
|
+
if (!name) return;
|
|
14
|
+
|
|
15
|
+
const act = await select({
|
|
16
|
+
message: name,
|
|
17
|
+
options: [
|
|
18
|
+
{ label: "GET", value: "get" },
|
|
19
|
+
{ label: "POST", value: "post" },
|
|
20
|
+
{ label: "Back", value: "back" },
|
|
21
|
+
],
|
|
22
|
+
});
|
|
23
|
+
if (!act || isCancel(act) || act === "back") return;
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
const svc = a.service(name);
|
|
27
|
+
if (act === "get") {
|
|
28
|
+
const path = await askText("path") ?? "";
|
|
29
|
+
console.log(JSON.stringify(await svc.get(path), null, 2));
|
|
30
|
+
} else {
|
|
31
|
+
const raw = await askText("body (JSON)") ?? "{}";
|
|
32
|
+
let body: Record<string, unknown>;
|
|
33
|
+
try {
|
|
34
|
+
body = JSON.parse(raw);
|
|
35
|
+
} catch {
|
|
36
|
+
showError("Invalid JSON body");
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
console.log(JSON.stringify(await svc.action("").invoke(body), null, 2));
|
|
40
|
+
}
|
|
41
|
+
} catch (e) {
|
|
42
|
+
rethrowAdminAuthError(e);
|
|
43
|
+
showError(adminErrorMessage(e));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin Infra 说明文档查看命令。
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { AdminClient } from "@downcity/conduit";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 展示当前 InfraRuntime 聚合后的说明文档。
|
|
9
|
+
*/
|
|
10
|
+
export async function manageInstruction(a: AdminClient): Promise<void> {
|
|
11
|
+
console.log(`\n${await a.instruction()}\n`);
|
|
12
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin Models 只读视图。
|
|
3
|
+
*
|
|
4
|
+
* 关键说明(中文)
|
|
5
|
+
* - 这里不提供模型新增、删除、启停。
|
|
6
|
+
* - 模型定义仍然来自代码注册;admin 只负责查看当前可用状态。
|
|
7
|
+
* - 如果模型缺少 provider key,会在这里直接显示缺失项。
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { AdminClient } from "@downcity/conduit";
|
|
11
|
+
import { show, showError } from "../../core/ui.js";
|
|
12
|
+
import { adminErrorMessage, isAdminNotFoundError, rethrowAdminAuthError } from "../auth-error.js";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* 展示全部代码注册模型及其运行状态。
|
|
16
|
+
*/
|
|
17
|
+
export async function manageModels(a: AdminClient): Promise<void> {
|
|
18
|
+
try {
|
|
19
|
+
const [modelResp, envCatalog] = await Promise.all([
|
|
20
|
+
a.listModels(),
|
|
21
|
+
a.env.catalog(),
|
|
22
|
+
]);
|
|
23
|
+
const items = modelResp ?? [];
|
|
24
|
+
const aiScope = envCatalog.find((item) => item.id === "ai-models");
|
|
25
|
+
const envMap = new Map(aiScope?.env.map((item) => [item.key, item.configured]) ?? []);
|
|
26
|
+
|
|
27
|
+
if (items.length === 0) {
|
|
28
|
+
show("No models registered on server.");
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
console.log(`\n${items.length} models:\n`);
|
|
33
|
+
for (const model of items) {
|
|
34
|
+
const requirements = model.env_requirements ?? [];
|
|
35
|
+
const missingEnv = requirements
|
|
36
|
+
.filter((item) => item.required && !envMap.get(item.key))
|
|
37
|
+
.map((item) => item.key);
|
|
38
|
+
const status = missingEnv.length === 0 ? "READY" : `MISSING ${missingEnv.join(", ")}`;
|
|
39
|
+
const defaults = (model.default_modes ?? []).length > 0
|
|
40
|
+
? `default: ${(model.default_modes ?? []).join(", ")}`
|
|
41
|
+
: "default: none";
|
|
42
|
+
const envText = requirements.length > 0
|
|
43
|
+
? requirements
|
|
44
|
+
.map((item) => `${item.key}${envMap.get(item.key) ? "✓" : "✗"}`)
|
|
45
|
+
.join(", ")
|
|
46
|
+
: "none";
|
|
47
|
+
|
|
48
|
+
console.log(` ${model.name} (${model.id})`);
|
|
49
|
+
console.log(` status: ${status}`);
|
|
50
|
+
console.log(` modalities: ${model.modalities.join(", ") || "none"}`);
|
|
51
|
+
console.log(` ${defaults}`);
|
|
52
|
+
console.log(` env: ${envText}`);
|
|
53
|
+
if (model.description) console.log(` desc: ${model.description}`);
|
|
54
|
+
console.log("");
|
|
55
|
+
}
|
|
56
|
+
} catch (e) {
|
|
57
|
+
rethrowAdminAuthError(e);
|
|
58
|
+
if (isAdminNotFoundError(e)) {
|
|
59
|
+
showError("Connected InfraRuntime is too old and does not expose /v1/env/catalog yet. Deploy the latest worker/server first.");
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
showError(adminErrorMessage(e));
|
|
63
|
+
}
|
|
64
|
+
}
|