@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
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI 自更新模块。
|
|
3
|
+
*
|
|
4
|
+
* 关键说明(中文)
|
|
5
|
+
* - 在 downcity 仓库内执行时,优先走本地 workspace 刷新全局安装
|
|
6
|
+
* - 普通全局安装环境下,退化为 `npm install -g @downcity/city@latest`
|
|
7
|
+
* - 更新完成后建议重新运行 CLI,避免当前进程继续使用旧代码
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
11
|
+
import { chmod, cp, lstat, mkdir, readFile, rm, symlink } from "node:fs/promises";
|
|
12
|
+
import path from "node:path";
|
|
13
|
+
import { spawn } from "node:child_process";
|
|
14
|
+
import os from "node:os";
|
|
15
|
+
|
|
16
|
+
const CITY_PACKAGE_NAME = "@downcity/city";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* 执行 CLI 自更新。
|
|
20
|
+
*/
|
|
21
|
+
export async function updateCityCLI(cwd = process.cwd()): Promise<{
|
|
22
|
+
mode: "workspace" | "npm";
|
|
23
|
+
version: string;
|
|
24
|
+
}> {
|
|
25
|
+
const workspaceRoot = findDowncityWorkspaceRoot(cwd);
|
|
26
|
+
|
|
27
|
+
if (workspaceRoot) {
|
|
28
|
+
await run(commandOf("pnpm"), ["-C", "packages/city", "build"], workspaceRoot);
|
|
29
|
+
const deploy_dir = path.join(os.tmpdir(), `downcity-city-deploy-${Date.now()}`);
|
|
30
|
+
await run(commandOf("pnpm"), ["--filter", CITY_PACKAGE_NAME, "deploy", "--legacy", deploy_dir], workspaceRoot);
|
|
31
|
+
await installCityDeployGlobally(deploy_dir, workspaceRoot);
|
|
32
|
+
await rm(deploy_dir, { recursive: true, force: true });
|
|
33
|
+
return {
|
|
34
|
+
mode: "workspace",
|
|
35
|
+
version: await readInstalledCityVersion(),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
await run(commandOf("npm"), ["install", "-g", `${CITY_PACKAGE_NAME}@latest`], cwd);
|
|
40
|
+
return {
|
|
41
|
+
mode: "npm",
|
|
42
|
+
version: await readInstalledCityVersion(),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* 读取当前全局安装的 city 版本。
|
|
48
|
+
*/
|
|
49
|
+
export async function readInstalledCityVersion(): Promise<string> {
|
|
50
|
+
try {
|
|
51
|
+
const global_paths = await resolveGlobalCityPaths(process.cwd());
|
|
52
|
+
const package_json = JSON.parse(await readFile(path.join(global_paths.package_dir, "package.json"), "utf8")) as {
|
|
53
|
+
version?: string;
|
|
54
|
+
};
|
|
55
|
+
return String(package_json.version ?? "unknown");
|
|
56
|
+
} catch {
|
|
57
|
+
return "unknown";
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* 将 pnpm deploy 的 city 产物安装到全局 CLI 位置。
|
|
63
|
+
*/
|
|
64
|
+
async function installCityDeployGlobally(deploy_dir: string, cwd: string): Promise<void> {
|
|
65
|
+
const global_paths = await resolveGlobalCityPaths(cwd);
|
|
66
|
+
|
|
67
|
+
// 关键点(中文):绕开 npm install -g 本地目录,避免 npm 11 Arborist 对本地包的崩溃。
|
|
68
|
+
await mkdir(global_paths.package_scope_dir, { recursive: true });
|
|
69
|
+
await mkdir(global_paths.global_bin, { recursive: true });
|
|
70
|
+
await rm(global_paths.package_dir, { recursive: true, force: true });
|
|
71
|
+
await cp(deploy_dir, global_paths.package_dir, { recursive: true, force: true });
|
|
72
|
+
await chmod(global_paths.cli_entry, 0o755);
|
|
73
|
+
|
|
74
|
+
await recreateSymlink(global_paths.city_bin, "../lib/node_modules/@downcity/city/bin/cli/Index.js");
|
|
75
|
+
await recreateSymlink(global_paths.downcity_bin, "../lib/node_modules/@downcity/city/bin/cli/Index.js");
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* 解析 npm 全局目录下的 city 安装位置。
|
|
80
|
+
*/
|
|
81
|
+
async function resolveGlobalCityPaths(cwd: string): Promise<{
|
|
82
|
+
npm_prefix: string;
|
|
83
|
+
global_modules: string;
|
|
84
|
+
global_bin: string;
|
|
85
|
+
package_scope_dir: string;
|
|
86
|
+
package_dir: string;
|
|
87
|
+
cli_entry: string;
|
|
88
|
+
city_bin: string;
|
|
89
|
+
downcity_bin: string;
|
|
90
|
+
}> {
|
|
91
|
+
const npm_prefix = (await capture(commandOf("npm"), ["prefix", "-g"], cwd)).trim();
|
|
92
|
+
const global_modules = path.join(npm_prefix, "lib", "node_modules");
|
|
93
|
+
const global_bin = path.join(npm_prefix, "bin");
|
|
94
|
+
const package_scope_dir = path.join(global_modules, "@downcity");
|
|
95
|
+
const package_dir = path.join(package_scope_dir, "city");
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
npm_prefix,
|
|
99
|
+
global_modules,
|
|
100
|
+
global_bin,
|
|
101
|
+
package_scope_dir,
|
|
102
|
+
package_dir,
|
|
103
|
+
cli_entry: path.join(package_dir, "bin", "cli", "Index.js"),
|
|
104
|
+
city_bin: path.join(global_bin, "city"),
|
|
105
|
+
downcity_bin: path.join(global_bin, "downcity"),
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* 重新创建全局命令链接。
|
|
111
|
+
*/
|
|
112
|
+
async function recreateSymlink(link_path: string, target_path: string): Promise<void> {
|
|
113
|
+
try {
|
|
114
|
+
const stat = await lstat(link_path);
|
|
115
|
+
if (stat.isDirectory()) {
|
|
116
|
+
await rm(link_path, { recursive: true, force: true });
|
|
117
|
+
} else {
|
|
118
|
+
await rm(link_path, { force: true });
|
|
119
|
+
}
|
|
120
|
+
} catch {
|
|
121
|
+
// 链接不存在是正常路径。
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
await symlink(target_path, link_path);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* 查找 downcity 仓库根目录。
|
|
129
|
+
*/
|
|
130
|
+
function findDowncityWorkspaceRoot(startDir: string): string | undefined {
|
|
131
|
+
let current = path.resolve(startDir);
|
|
132
|
+
|
|
133
|
+
while (true) {
|
|
134
|
+
if (isDowncityWorkspaceRoot(current)) {
|
|
135
|
+
return current;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const parent = path.dirname(current);
|
|
139
|
+
if (parent === current) {
|
|
140
|
+
return undefined;
|
|
141
|
+
}
|
|
142
|
+
current = parent;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* 判断某个目录是否为 downcity monorepo 根目录。
|
|
148
|
+
*/
|
|
149
|
+
function isDowncityWorkspaceRoot(dir: string): boolean {
|
|
150
|
+
const packageJsonPath = path.join(dir, "package.json");
|
|
151
|
+
const workspacePath = path.join(dir, "pnpm-workspace.yaml");
|
|
152
|
+
const cityPackagePath = path.join(dir, "packages", "city", "package.json");
|
|
153
|
+
|
|
154
|
+
if (!existsSync(packageJsonPath) || !existsSync(workspacePath) || !existsSync(cityPackagePath)) {
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
try {
|
|
159
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8")) as {
|
|
160
|
+
name?: string;
|
|
161
|
+
};
|
|
162
|
+
return packageJson.name === "downcity";
|
|
163
|
+
} catch {
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* 运行命令并继承当前终端输出。
|
|
170
|
+
*/
|
|
171
|
+
function run(command: string, args: string[], cwd: string): Promise<void> {
|
|
172
|
+
return new Promise((resolve, reject) => {
|
|
173
|
+
const child = spawn(command, args, {
|
|
174
|
+
cwd,
|
|
175
|
+
stdio: "inherit",
|
|
176
|
+
shell: false,
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
child.on("error", reject);
|
|
180
|
+
child.on("exit", (code) => {
|
|
181
|
+
if (code === 0) {
|
|
182
|
+
resolve();
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
reject(new Error(`${command} ${args.join(" ")} exited with code ${code ?? "unknown"}`));
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* 运行命令并采集 stdout。
|
|
192
|
+
*/
|
|
193
|
+
function capture(command: string, args: string[], cwd: string): Promise<string> {
|
|
194
|
+
return new Promise((resolve, reject) => {
|
|
195
|
+
const child = spawn(command, args, {
|
|
196
|
+
cwd,
|
|
197
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
198
|
+
shell: false,
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
let stdout = "";
|
|
202
|
+
let stderr = "";
|
|
203
|
+
|
|
204
|
+
child.stdout.on("data", (chunk) => {
|
|
205
|
+
stdout += String(chunk);
|
|
206
|
+
});
|
|
207
|
+
child.stderr.on("data", (chunk) => {
|
|
208
|
+
stderr += String(chunk);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
child.on("error", reject);
|
|
212
|
+
child.on("exit", (code) => {
|
|
213
|
+
if (code === 0) {
|
|
214
|
+
resolve(stdout);
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
reject(new Error(stderr.trim() || `${command} ${args.join(" ")} exited with code ${code ?? "unknown"}`));
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* 根据平台选择可执行文件名。
|
|
224
|
+
*/
|
|
225
|
+
function commandOf(name: "npm" | "pnpm" | "node"): string {
|
|
226
|
+
if (process.platform === "win32" && name !== "node") {
|
|
227
|
+
return `${name}.cmd`;
|
|
228
|
+
}
|
|
229
|
+
return name;
|
|
230
|
+
}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User Balance 命令。
|
|
3
|
+
*
|
|
4
|
+
* 提供:
|
|
5
|
+
* - 查看当前余额
|
|
6
|
+
* - 查看个人流水
|
|
7
|
+
* - 查看个人充值单
|
|
8
|
+
* - 发起充值
|
|
9
|
+
* - 兑换 redeem_code
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type { UserClient } from "@downcity/conduit";
|
|
13
|
+
import { openBrowser } from "../core/browser.js";
|
|
14
|
+
import { buildStripeEndpoints } from "../core/stripe.js";
|
|
15
|
+
import { askText, show, showError, showSuccess } from "../core/ui.js";
|
|
16
|
+
|
|
17
|
+
interface BalanceAccount {
|
|
18
|
+
/** 用户 ID */
|
|
19
|
+
user_id: string;
|
|
20
|
+
/** 当前余额 */
|
|
21
|
+
balance: number;
|
|
22
|
+
/** 余额单位 */
|
|
23
|
+
unit: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
interface BalanceLedgerItem {
|
|
27
|
+
/** 流水类型 */
|
|
28
|
+
kind: string;
|
|
29
|
+
/** 流水金额 */
|
|
30
|
+
amount: number;
|
|
31
|
+
/** 余额快照 */
|
|
32
|
+
balance_after: number;
|
|
33
|
+
/** 流水说明 */
|
|
34
|
+
note: string;
|
|
35
|
+
/** 创建时间 */
|
|
36
|
+
created_at: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
interface BalanceTopupItem {
|
|
40
|
+
/** 充值单 ID */
|
|
41
|
+
topup_id: string;
|
|
42
|
+
/** 充值金额 */
|
|
43
|
+
amount: number;
|
|
44
|
+
/** 余额单位 */
|
|
45
|
+
unit: string;
|
|
46
|
+
/** 充值单状态 */
|
|
47
|
+
status: string;
|
|
48
|
+
/** 充值说明 */
|
|
49
|
+
note: string;
|
|
50
|
+
/** 创建时间 */
|
|
51
|
+
created_at: string;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
interface StripeCheckoutResult {
|
|
55
|
+
/** 支付记录 ID */
|
|
56
|
+
payment_id: string;
|
|
57
|
+
/** 对应的充值单 ID */
|
|
58
|
+
topup_id: string;
|
|
59
|
+
/** Stripe Checkout Session ID */
|
|
60
|
+
stripe_checkout_session_id: string;
|
|
61
|
+
/** 可直接跳转的支付地址 */
|
|
62
|
+
checkout_url: string;
|
|
63
|
+
/** 当前支付状态 */
|
|
64
|
+
status: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
interface BalanceRedeemCodeItem {
|
|
68
|
+
/** redeem_code ID */
|
|
69
|
+
redeem_code_id: string;
|
|
70
|
+
/** redeem_code 状态 */
|
|
71
|
+
status: string;
|
|
72
|
+
/** 脱敏兑换码 */
|
|
73
|
+
code_mask: string;
|
|
74
|
+
/** 兑换金额 */
|
|
75
|
+
amount: number;
|
|
76
|
+
/** 余额单位 */
|
|
77
|
+
unit: string;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
interface BalanceRedeemResult {
|
|
81
|
+
/** 兑换后的账户快照 */
|
|
82
|
+
account: BalanceAccount;
|
|
83
|
+
/** 被兑换的 redeem_code */
|
|
84
|
+
redeem_code: BalanceRedeemCodeItem;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** 展示当前余额 */
|
|
88
|
+
export async function showBalance(c: UserClient): Promise<void> {
|
|
89
|
+
const account = await c.service("balance").get<BalanceAccount>("me");
|
|
90
|
+
show([
|
|
91
|
+
`user_id: ${account.user_id}`,
|
|
92
|
+
`balance: ${account.balance} ${account.unit}`,
|
|
93
|
+
].join("\n"));
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** 展示个人流水 */
|
|
97
|
+
export async function showBalanceHistory(c: UserClient): Promise<void> {
|
|
98
|
+
const response = await c.service("balance").get<{ items: BalanceLedgerItem[] }>("history/me", { limit: 20 });
|
|
99
|
+
if (response.items.length === 0) {
|
|
100
|
+
show("No balance history yet.");
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
console.log(`\n${response.items.length} balance entries:\n`);
|
|
105
|
+
for (const item of response.items) {
|
|
106
|
+
console.log(` ${item.created_at.slice(0, 19)} ${item.kind.padEnd(8)} ${String(item.amount).padStart(6)} -> ${String(item.balance_after).padStart(6)} ${item.note}`);
|
|
107
|
+
}
|
|
108
|
+
console.log("");
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** 展示个人充值单 */
|
|
112
|
+
export async function showTopups(c: UserClient): Promise<void> {
|
|
113
|
+
const response = await c.service("balance").get<{ items: BalanceTopupItem[] }>("topups/me", { limit: 20 });
|
|
114
|
+
if (response.items.length === 0) {
|
|
115
|
+
show("No topup orders yet.");
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
console.log(`\n${response.items.length} topup orders:\n`);
|
|
120
|
+
for (const item of response.items) {
|
|
121
|
+
console.log(` ${item.topup_id.padEnd(24)} ${String(item.amount).padStart(6)} ${item.unit.padEnd(10)} [${item.status}] ${item.note}`);
|
|
122
|
+
}
|
|
123
|
+
console.log("");
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** 发起充值 */
|
|
127
|
+
export async function createTopup(c: UserClient): Promise<void> {
|
|
128
|
+
const result = await createTopupOrder(c);
|
|
129
|
+
if (!result) return;
|
|
130
|
+
showSuccess(`topup created: ${result.topup_id} (${result.amount} ${result.unit}, ${result.status})`);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* 发起 Stripe 充值。
|
|
135
|
+
*
|
|
136
|
+
* 关键说明(中文)
|
|
137
|
+
* - 先创建 pending topup
|
|
138
|
+
* - 再调用 payment.stripe 创建 Checkout
|
|
139
|
+
* - 成功后尽量自动打开浏览器
|
|
140
|
+
*/
|
|
141
|
+
export async function rechargeWithStripe(c: UserClient): Promise<void> {
|
|
142
|
+
const topup = await createTopupOrder(c);
|
|
143
|
+
if (!topup) return;
|
|
144
|
+
const endpoints = buildStripeEndpoints(c.serverUrl);
|
|
145
|
+
|
|
146
|
+
showSuccess(`topup created: ${topup.topup_id} (${topup.amount} ${topup.unit}, ${topup.status})`);
|
|
147
|
+
|
|
148
|
+
const successURL = await askText("success_url override (optional)");
|
|
149
|
+
const cancelURL = await askText("cancel_url override (optional)");
|
|
150
|
+
|
|
151
|
+
try {
|
|
152
|
+
const checkout = await c.service("payment.stripe").action("checkout/create").invoke<StripeCheckoutResult>({
|
|
153
|
+
topup_id: topup.topup_id,
|
|
154
|
+
success_url: successURL ?? "",
|
|
155
|
+
cancel_url: cancelURL ?? "",
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
const opened = openBrowser(checkout.checkout_url);
|
|
159
|
+
showSuccess(`checkout created: ${checkout.payment_id}`);
|
|
160
|
+
show([
|
|
161
|
+
`topup_id: ${checkout.topup_id}`,
|
|
162
|
+
`checkout_url: ${checkout.checkout_url}`,
|
|
163
|
+
`status: ${checkout.status}`,
|
|
164
|
+
`stripe webhook endpoint: ${endpoints.webhook_url}`,
|
|
165
|
+
].join("\n"));
|
|
166
|
+
|
|
167
|
+
if (opened) {
|
|
168
|
+
show("Browser opened for Stripe Checkout.");
|
|
169
|
+
} else {
|
|
170
|
+
showError(`Could not open browser. Please visit:\n ${checkout.checkout_url}`);
|
|
171
|
+
}
|
|
172
|
+
} catch (error) {
|
|
173
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
174
|
+
showError([
|
|
175
|
+
"Stripe checkout creation failed.",
|
|
176
|
+
`topup_id: ${topup.topup_id}`,
|
|
177
|
+
`error: ${message}`,
|
|
178
|
+
`stripe webhook endpoint: ${endpoints.webhook_url}`,
|
|
179
|
+
"You can keep this pending topup and retry checkout later.",
|
|
180
|
+
].join("\n"));
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* 创建充值单。
|
|
186
|
+
*/
|
|
187
|
+
async function createTopupOrder(c: UserClient): Promise<BalanceTopupItem | undefined> {
|
|
188
|
+
const rawAmount = await askText("topup amount");
|
|
189
|
+
if (!rawAmount) return undefined;
|
|
190
|
+
|
|
191
|
+
const amount = Number(rawAmount);
|
|
192
|
+
if (!Number.isInteger(amount) || amount <= 0) {
|
|
193
|
+
showError("topup amount must be a positive integer");
|
|
194
|
+
return undefined;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const note = await askText("topup note (optional)");
|
|
198
|
+
return await c.service("balance").action("topups/create").invoke<BalanceTopupItem>({
|
|
199
|
+
amount,
|
|
200
|
+
note: note ?? "",
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/** 兑换 redeem_code */
|
|
205
|
+
export async function redeemCode(c: UserClient): Promise<void> {
|
|
206
|
+
const code = await askText("redeem_code");
|
|
207
|
+
if (!code) return;
|
|
208
|
+
|
|
209
|
+
const result = await c.service("balance").action("redeem-codes/redeem").invoke<BalanceRedeemResult>({
|
|
210
|
+
code,
|
|
211
|
+
});
|
|
212
|
+
showSuccess(
|
|
213
|
+
`redeemed: ${result.redeem_code.code_mask} -> +${result.redeem_code.amount} ${result.redeem_code.unit} (balance: ${result.account.balance} ${result.account.unit})`,
|
|
214
|
+
);
|
|
215
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User Chat 命令 — Agent 连续对话。
|
|
3
|
+
*
|
|
4
|
+
* 使用 pi-agent 进行多轮对话(流式输出 + tools)。
|
|
5
|
+
* pi-agent 通过 server 的 /chat/completions 端点调用 AI,
|
|
6
|
+
* client 不做任何 provider 或 model 硬编码。
|
|
7
|
+
* 空输入或 Esc 返回上级菜单。
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { UserClient } from "@downcity/conduit";
|
|
11
|
+
import { type UserContext } from "../auth/user.js";
|
|
12
|
+
import { askText, show, showError } from "../core/ui.js";
|
|
13
|
+
import { createPiAgentSession, type PiAgentSession } from "../agent/pi-agent.js";
|
|
14
|
+
|
|
15
|
+
let activeAgentSession: PiAgentSession | undefined;
|
|
16
|
+
|
|
17
|
+
export async function doAgentChat(c: UserClient, ctx: UserContext): Promise<void> {
|
|
18
|
+
// 从 server 获取模型目录,构建 ModelHandle
|
|
19
|
+
let modelName: string;
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
const catalog = await c.ai.listModels();
|
|
23
|
+
const all = catalog.all();
|
|
24
|
+
if (all.length === 0) {
|
|
25
|
+
showError("No ready models available on server. Please configure provider env first.");
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const selected = ctx.config.model
|
|
30
|
+
? (catalog.get(ctx.config.model) ?? catalog.default())
|
|
31
|
+
: catalog.default();
|
|
32
|
+
|
|
33
|
+
if (!selected) {
|
|
34
|
+
showError("No ready default model found on server.");
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
modelName = selected.name;
|
|
39
|
+
|
|
40
|
+
const handle = c.ai.model(selected);
|
|
41
|
+
|
|
42
|
+
show(`Starting agent chat (model: ${modelName})`);
|
|
43
|
+
show("Type your message (empty or Esc to exit chat)");
|
|
44
|
+
|
|
45
|
+
activeAgentSession = await createPiAgentSession({
|
|
46
|
+
model: handle,
|
|
47
|
+
tools: "agent",
|
|
48
|
+
onText: (text) => process.stdout.write(text),
|
|
49
|
+
onToolStart: (toolName) => process.stdout.write(`\n[tool:${toolName}] `),
|
|
50
|
+
onToolEnd: (toolName, isError) => {
|
|
51
|
+
if (isError) process.stdout.write(`[tool:${toolName} failed]\n`);
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
} catch (e) {
|
|
55
|
+
showError(`Failed to start agent: ${e instanceof Error ? e.message : String(e)}`);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
while (true) {
|
|
60
|
+
process.stdout.write("\n");
|
|
61
|
+
const prompt = await askText("You");
|
|
62
|
+
if (!prompt || prompt.trim() === "") {
|
|
63
|
+
show("Exited chat");
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
process.stdout.write("assistant: ");
|
|
68
|
+
try {
|
|
69
|
+
const response = await activeAgentSession.ask(prompt);
|
|
70
|
+
if (response) process.stdout.write("\n");
|
|
71
|
+
} catch (e) {
|
|
72
|
+
process.stdout.write("\n");
|
|
73
|
+
showError(`Agent error: ${e instanceof Error ? e.message : String(e)}`);
|
|
74
|
+
show("Agent session ended. Please re-enter chat to start a new conversation.");
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
activeAgentSession = undefined;
|
|
80
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User 命令循环。返回 "logout" | "quit" | "switch_identity"。
|
|
3
|
+
*
|
|
4
|
+
* 关键说明(中文)
|
|
5
|
+
* - chat 直接使用 pi-agent 进行连续对话(流式输出),委托到 chat.ts。
|
|
6
|
+
* - models 合并了列表展示与选择切换,委托到 models.ts。
|
|
7
|
+
* - me / services / service 保持内联(逻辑简单)。
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { UserClient } from "@downcity/conduit";
|
|
11
|
+
import { type UserContext } from "../auth/user.js";
|
|
12
|
+
import { clearUserSession } from "../core/session.js";
|
|
13
|
+
import { askUserCommand, askText, show, showError, showSuccess } from "../core/ui.js";
|
|
14
|
+
import { createTopup, rechargeWithStripe, redeemCode, showBalance, showBalanceHistory, showTopups } from "./balance.js";
|
|
15
|
+
import { doAgentChat } from "./chat.js";
|
|
16
|
+
import { doModels } from "./models.js";
|
|
17
|
+
|
|
18
|
+
type Result = "logout" | "quit" | "switch_identity";
|
|
19
|
+
|
|
20
|
+
export async function userLoop(ctx: UserContext): Promise<Result> {
|
|
21
|
+
const client = new UserClient({
|
|
22
|
+
base_url: ctx.session.base_url,
|
|
23
|
+
product_id: ctx.session.product_id,
|
|
24
|
+
user_token: ctx.session.user_token,
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
while (true) {
|
|
28
|
+
const cmd = await askUserCommand();
|
|
29
|
+
if (!cmd) continue;
|
|
30
|
+
if (cmd === "switch") return "switch_identity";
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
const r = await execute(client, ctx, cmd);
|
|
34
|
+
if (r === "quit") return "quit";
|
|
35
|
+
if (r === "logout") return "logout";
|
|
36
|
+
} catch (e) {
|
|
37
|
+
showError(e instanceof Error ? e.message : String(e));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function execute(
|
|
43
|
+
c: UserClient,
|
|
44
|
+
ctx: UserContext,
|
|
45
|
+
cmd: string,
|
|
46
|
+
): Promise<"continue" | "logout" | "quit"> {
|
|
47
|
+
switch (cmd) {
|
|
48
|
+
case "chat":
|
|
49
|
+
await doAgentChat(c, ctx);
|
|
50
|
+
return "continue";
|
|
51
|
+
|
|
52
|
+
case "models":
|
|
53
|
+
await doModels(c, ctx);
|
|
54
|
+
return "continue";
|
|
55
|
+
|
|
56
|
+
case "balance":
|
|
57
|
+
await showBalance(c);
|
|
58
|
+
return "continue";
|
|
59
|
+
|
|
60
|
+
case "history":
|
|
61
|
+
await showBalanceHistory(c);
|
|
62
|
+
return "continue";
|
|
63
|
+
|
|
64
|
+
case "topups":
|
|
65
|
+
await showTopups(c);
|
|
66
|
+
return "continue";
|
|
67
|
+
|
|
68
|
+
case "recharge":
|
|
69
|
+
await rechargeWithStripe(c);
|
|
70
|
+
return "continue";
|
|
71
|
+
|
|
72
|
+
case "topup_create":
|
|
73
|
+
await createTopup(c);
|
|
74
|
+
return "continue";
|
|
75
|
+
|
|
76
|
+
case "redeem_code":
|
|
77
|
+
await redeemCode(c);
|
|
78
|
+
return "continue";
|
|
79
|
+
|
|
80
|
+
case "me": {
|
|
81
|
+
const b = await c.service("accounts").get<{ user?: { user_id: string; email: string } }>("me");
|
|
82
|
+
if (b.user) show(`user_id: ${b.user.user_id}\nemail: ${b.user.email}`);
|
|
83
|
+
return "continue";
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
case "services":
|
|
87
|
+
show(
|
|
88
|
+
(await c.listServices())
|
|
89
|
+
.map((service) => `${service.id} - ${service.name}`)
|
|
90
|
+
.join("\n"),
|
|
91
|
+
);
|
|
92
|
+
return "continue";
|
|
93
|
+
|
|
94
|
+
case "service": {
|
|
95
|
+
const n = await askText("service name");
|
|
96
|
+
if (n) show(JSON.stringify(await c.service(n).action("").invoke({}), null, 2));
|
|
97
|
+
return "continue";
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
case "logout":
|
|
101
|
+
clearUserSession(ctx.session.base_url);
|
|
102
|
+
showSuccess("logged out");
|
|
103
|
+
return "logout";
|
|
104
|
+
|
|
105
|
+
case "quit":
|
|
106
|
+
return "quit";
|
|
107
|
+
|
|
108
|
+
default:
|
|
109
|
+
showError(`unknown: ${cmd}`);
|
|
110
|
+
return "continue";
|
|
111
|
+
}
|
|
112
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User Models 命令 — 模型列表与选择。
|
|
3
|
+
*
|
|
4
|
+
* 从 server 获取模型目录,显示并允许用户切换。
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { UserClient, ModelCatalog } from "@downcity/conduit";
|
|
8
|
+
import { type UserContext } from "../auth/user.js";
|
|
9
|
+
import { askModel, type ModelOption, show, showError, showSuccess } from "../core/ui.js";
|
|
10
|
+
import { readConfig, writeConfig } from "../core/session.js";
|
|
11
|
+
|
|
12
|
+
/** 列出模型并选择切换 */
|
|
13
|
+
export async function doModels(c: UserClient, ctx: UserContext): Promise<void> {
|
|
14
|
+
let catalog: ModelCatalog;
|
|
15
|
+
try {
|
|
16
|
+
catalog = await c.ai.listModels();
|
|
17
|
+
} catch (e) {
|
|
18
|
+
showError(`Failed to fetch models: ${e instanceof Error ? e.message : String(e)}`);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const all = catalog.all();
|
|
23
|
+
if (all.length === 0) {
|
|
24
|
+
showError("No ready models available from server. Configure provider env first.");
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const currentModel = ctx.config.model || catalog.default()?.id || "";
|
|
29
|
+
show(`Current model: ${currentModel || "(none)"}`);
|
|
30
|
+
|
|
31
|
+
const options: ModelOption[] = all.map((m) => ({
|
|
32
|
+
id: m.id,
|
|
33
|
+
name: m.name,
|
|
34
|
+
hint: m.description || m.tags?.join(", ") || "",
|
|
35
|
+
}));
|
|
36
|
+
|
|
37
|
+
const selected = await askModel(options, currentModel);
|
|
38
|
+
if (selected) {
|
|
39
|
+
ctx.config.model = selected;
|
|
40
|
+
const cfg = readConfig(); cfg.model = selected; writeConfig(cfg);
|
|
41
|
+
showSuccess(`Model switched to: ${selected}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
package/src/utils/storage.ts
CHANGED
|
@@ -17,10 +17,3 @@ export async function ensureDir(dir: string): Promise<void> {
|
|
|
17
17
|
export async function saveJson(filePath: string, data: JsonValue | object): Promise<void> {
|
|
18
18
|
await fs.writeJson(filePath, data, { spaces: 2 });
|
|
19
19
|
}
|
|
20
|
-
|
|
21
|
-
export async function loadJson<T>(filePath: string): Promise<T | null> {
|
|
22
|
-
if (!fs.existsSync(filePath)) {
|
|
23
|
-
return null;
|
|
24
|
-
}
|
|
25
|
-
return fs.readJson(filePath) as Promise<T>;
|
|
26
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Local RPC 客户端。
|
|
3
|
-
*
|
|
4
|
-
* 关键点(中文)
|
|
5
|
-
* - 只用于本机受信任 IPC,不附加 HTTP Bearer 鉴权。
|
|
6
|
-
* - 返回结构与 HTTP `callServer()` 对齐,便于上层透明切换 transport。
|
|
7
|
-
*/
|
|
8
|
-
import type { DaemonJsonApiCallParams, DaemonJsonApiCallResult } from "../../process/daemon/Api.js";
|
|
9
|
-
/**
|
|
10
|
-
* 通过本地 IPC 调用 agent runtime。
|
|
11
|
-
*/
|
|
12
|
-
export declare function callLocalServer<T>(params: DaemonJsonApiCallParams): Promise<DaemonJsonApiCallResult<T>>;
|
|
13
|
-
//# sourceMappingURL=Client.d.ts.map
|