@tokenbuddy/tokenbuddy 1.0.11 → 1.0.13
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/dist/src/buyer-store.d.ts +61 -0
- package/dist/src/buyer-store.d.ts.map +1 -1
- package/dist/src/buyer-store.js +12 -0
- package/dist/src/buyer-store.js.map +1 -1
- package/dist/src/cli.d.ts +47 -0
- package/dist/src/cli.d.ts.map +1 -1
- package/dist/src/cli.js +287 -63
- package/dist/src/cli.js.map +1 -1
- package/dist/src/credit-tracker.d.ts +26 -0
- package/dist/src/credit-tracker.d.ts.map +1 -1
- package/dist/src/credit-tracker.js +8 -0
- package/dist/src/credit-tracker.js.map +1 -1
- package/dist/src/daemon.d.ts +29 -3
- package/dist/src/daemon.d.ts.map +1 -1
- package/dist/src/daemon.js +292 -65
- package/dist/src/daemon.js.map +1 -1
- package/dist/src/doctor-clawtip-wallet.d.ts +25 -0
- package/dist/src/doctor-clawtip-wallet.d.ts.map +1 -1
- package/dist/src/doctor-clawtip-wallet.js +13 -0
- package/dist/src/doctor-clawtip-wallet.js.map +1 -1
- package/dist/src/doctor-diagnostics.d.ts +63 -0
- package/dist/src/doctor-diagnostics.d.ts.map +1 -1
- package/dist/src/doctor-diagnostics.js +39 -1
- package/dist/src/doctor-diagnostics.js.map +1 -1
- package/dist/src/index.d.ts +4 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +4 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/init-clawtip-activation.d.ts +103 -0
- package/dist/src/init-clawtip-activation.d.ts.map +1 -1
- package/dist/src/init-clawtip-activation.js +60 -0
- package/dist/src/init-clawtip-activation.js.map +1 -1
- package/dist/src/init-payment-options.d.ts +124 -0
- package/dist/src/init-payment-options.d.ts.map +1 -1
- package/dist/src/init-payment-options.js +68 -0
- package/dist/src/init-payment-options.js.map +1 -1
- package/dist/src/model-index.d.ts +9 -0
- package/dist/src/model-index.d.ts.map +1 -1
- package/dist/src/model-index.js.map +1 -1
- package/dist/src/prewarm-cache.d.ts +89 -0
- package/dist/src/prewarm-cache.d.ts.map +1 -1
- package/dist/src/prewarm-cache.js +14 -1
- package/dist/src/prewarm-cache.js.map +1 -1
- package/dist/src/prewarm-scheduler.d.ts +62 -3
- package/dist/src/prewarm-scheduler.d.ts.map +1 -1
- package/dist/src/prewarm-scheduler.js +39 -8
- package/dist/src/prewarm-scheduler.js.map +1 -1
- package/dist/src/provider-install.d.ts +89 -3
- package/dist/src/provider-install.d.ts.map +1 -1
- package/dist/src/provider-install.js +77 -17
- package/dist/src/provider-install.js.map +1 -1
- package/dist/src/route-failover.d.ts +48 -0
- package/dist/src/route-failover.d.ts.map +1 -1
- package/dist/src/route-failover.js.map +1 -1
- package/dist/src/seller-catalog.d.ts +158 -10
- package/dist/src/seller-catalog.d.ts.map +1 -1
- package/dist/src/seller-catalog.js +79 -5
- package/dist/src/seller-catalog.js.map +1 -1
- package/dist/src/seller-metadata-cache.d.ts +29 -0
- package/dist/src/seller-metadata-cache.d.ts.map +1 -0
- package/dist/src/seller-metadata-cache.js +71 -0
- package/dist/src/seller-metadata-cache.js.map +1 -0
- package/dist/src/seller-pool.d.ts +71 -0
- package/dist/src/seller-pool.d.ts.map +1 -1
- package/dist/src/seller-pool.js +6 -1
- package/dist/src/seller-pool.js.map +1 -1
- package/dist/src/seller-route-planner.d.ts +118 -0
- package/dist/src/seller-route-planner.d.ts.map +1 -0
- package/dist/src/seller-route-planner.js +160 -0
- package/dist/src/seller-route-planner.js.map +1 -0
- package/dist/src/seller-routing-config.d.ts +69 -0
- package/dist/src/seller-routing-config.d.ts.map +1 -0
- package/dist/src/seller-routing-config.js +164 -0
- package/dist/src/seller-routing-config.js.map +1 -0
- package/dist/src/seller-routing-strategy.d.ts +118 -0
- package/dist/src/seller-routing-strategy.d.ts.map +1 -0
- package/dist/src/seller-routing-strategy.js +183 -0
- package/dist/src/seller-routing-strategy.js.map +1 -0
- package/dist/src/stream-failover.d.ts +23 -0
- package/dist/src/stream-failover.d.ts.map +1 -1
- package/dist/src/stream-failover.js +4 -0
- package/dist/src/stream-failover.js.map +1 -1
- package/dist/src/tb-proxyd.js +7 -21
- package/dist/src/tb-proxyd.js.map +1 -1
- package/dist/src/terminal-detect.d.ts +51 -0
- package/dist/src/terminal-detect.d.ts.map +1 -1
- package/dist/src/terminal-detect.js +42 -0
- package/dist/src/terminal-detect.js.map +1 -1
- package/dist/src/terminal-image.d.ts +41 -0
- package/dist/src/terminal-image.d.ts.map +1 -1
- package/dist/src/terminal-image.js +15 -0
- package/dist/src/terminal-image.js.map +1 -1
- package/package.json +1 -1
- package/src/buyer-store.ts +61 -0
- package/src/cli.ts +330 -68
- package/src/credit-tracker.ts +26 -0
- package/src/daemon.ts +363 -72
- package/src/doctor-clawtip-wallet.ts +25 -0
- package/src/doctor-diagnostics.ts +63 -1
- package/src/index.ts +4 -0
- package/src/init-clawtip-activation.ts +103 -0
- package/src/init-payment-options.ts +124 -0
- package/src/model-index.ts +9 -0
- package/src/prewarm-cache.ts +99 -1
- package/src/prewarm-scheduler.ts +97 -12
- package/src/provider-install.ts +125 -25
- package/src/route-failover.ts +48 -0
- package/src/seller-catalog.ts +158 -12
- package/src/seller-metadata-cache.ts +91 -0
- package/src/seller-pool.ts +77 -1
- package/src/seller-route-planner.ts +323 -0
- package/src/seller-routing-config.ts +198 -0
- package/src/seller-routing-strategy.ts +316 -0
- package/src/stream-failover.ts +23 -0
- package/src/tb-proxyd.ts +7 -23
- package/src/terminal-detect.ts +51 -0
- package/src/terminal-image.ts +41 -0
- package/tests/cli-routing.test.ts +287 -0
- package/tests/daemon-classify.test.ts +431 -0
- package/tests/daemon-roles.test.ts +92 -0
- package/tests/seller-catalog-utilities.test.ts +70 -0
- package/tests/seller-metadata-cache.test.ts +89 -0
- package/tests/seller-route-planner.test.ts +150 -0
- package/tests/seller-routing-config.test.ts +111 -0
- package/tests/seller-routing-strategy.test.ts +166 -0
- package/tests/tokenbuddy.test.ts +447 -33
- /package/{src → tests}/credit-tracker.test.ts +0 -0
- /package/{src → tests}/model-index.test.ts +0 -0
- /package/{src → tests}/prewarm-cache.test.ts +0 -0
- /package/{src → tests}/prewarm-scheduler.test.ts +0 -0
- /package/{src → tests}/route-failover.test.ts +0 -0
- /package/{src → tests}/seller-catalog-413.test.ts +0 -0
- /package/{src → tests}/seller-pool.test.ts +0 -0
- /package/{src → tests}/stream-failover.test.ts +0 -0
- /package/{src → tests}/thousand-seller.test.ts +0 -0
|
@@ -4,14 +4,26 @@ import {
|
|
|
4
4
|
type ClawtipWalletStatus,
|
|
5
5
|
} from "./init-payment-options.js";
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* `tb doctor` 视角的 ClawTip 钱包就绪摘要:把 readiness 拍平成 boolean + 关键路径。
|
|
9
|
+
* `printDoctorClawtipWallet()` 负责渲染它。
|
|
10
|
+
*/
|
|
7
11
|
export interface DoctorClawtipWalletSummary {
|
|
12
|
+
/** 综合就绪状态(同 `inspectClawtipWalletReadiness().status`) */
|
|
8
13
|
status: ClawtipWalletStatus;
|
|
14
|
+
/** `status === "ready"` 的便利布尔,UI 据此选择图标 */
|
|
9
15
|
ready: boolean;
|
|
16
|
+
/** buyer-store 里是否保存了 ClawTip 支付 metadata */
|
|
10
17
|
paymentMetadataPresent: boolean;
|
|
18
|
+
/** `~/.openclaw/configs/config.json` 是否存在 */
|
|
11
19
|
walletConfigPresent: boolean;
|
|
20
|
+
/** `~/.openclaw/configs/` 目录是否存在 */
|
|
12
21
|
configsDirExists: boolean;
|
|
22
|
+
/** 期望的 wallet config 绝对路径 */
|
|
13
23
|
expectedPath: string;
|
|
24
|
+
/** 同目录里其它文件列表(按字典序) */
|
|
14
25
|
alternatePaths: string[];
|
|
26
|
+
/** 人类可读说明(来自 readiness.message) */
|
|
15
27
|
message: string;
|
|
16
28
|
}
|
|
17
29
|
|
|
@@ -28,6 +40,12 @@ function clawtipWalletStatusIcon(status: ClawtipWalletStatus): string {
|
|
|
28
40
|
return "🔘";
|
|
29
41
|
}
|
|
30
42
|
|
|
43
|
+
/**
|
|
44
|
+
* 从 `BuyerStore` 读取当前 ClawTip 支付 metadata,再叠加 wallet config 探查结果,
|
|
45
|
+
* 生成 `tb doctor` 面板用的就绪摘要。
|
|
46
|
+
*
|
|
47
|
+
* @returns doctor 面板用的就绪摘要
|
|
48
|
+
*/
|
|
31
49
|
export function readDoctorClawtipWallet(): DoctorClawtipWalletSummary {
|
|
32
50
|
const store = new BuyerStore();
|
|
33
51
|
try {
|
|
@@ -47,6 +65,13 @@ export function readDoctorClawtipWallet(): DoctorClawtipWalletSummary {
|
|
|
47
65
|
}
|
|
48
66
|
}
|
|
49
67
|
|
|
68
|
+
/**
|
|
69
|
+
* 把 doctor 摘要渲染成多行人类可读输出,包含状态图标、metadata/config 缺失标记、
|
|
70
|
+
* 期望路径、同目录其它文件,以及按状态分支的"接下来怎么做"提示。
|
|
71
|
+
*
|
|
72
|
+
* @param wallet `readDoctorClawtipWallet()` 的输出
|
|
73
|
+
* @param writeLine 注入的单行写入函数(默认 `console.log`)
|
|
74
|
+
*/
|
|
50
75
|
export function printDoctorClawtipWallet(
|
|
51
76
|
wallet: DoctorClawtipWalletSummary,
|
|
52
77
|
writeLine: (line: string) => void,
|
|
@@ -19,11 +19,21 @@ import {
|
|
|
19
19
|
type DoctorClawtipWalletSummary,
|
|
20
20
|
} from "./doctor-clawtip-wallet.js";
|
|
21
21
|
|
|
22
|
+
/**
|
|
23
|
+
* `tb doctor` 输出里 provider 行的形状。
|
|
24
|
+
* 在 `ProviderCandidate` 之上叠加 buyer 端持久化的 runtime config(如果存在)。
|
|
25
|
+
*/
|
|
22
26
|
export interface DoctorProviderView extends ProviderCandidate {
|
|
27
|
+
/** 持久化的 provider runtime config(opencode 的 `defaultModel` 等) */
|
|
23
28
|
runtimeConfig?: ProviderRuntimeConfig;
|
|
29
|
+
/** runtime config 的最近更新时间 */
|
|
24
30
|
runtimeConfigUpdatedAt?: string;
|
|
25
31
|
}
|
|
26
32
|
|
|
33
|
+
/**
|
|
34
|
+
* `tb doctor` 输出里 seller 行的形状。
|
|
35
|
+
* 字段命名与 `RegistrySeller` 对齐,但额外包含状态、错误信息、manifest sellerId 等。
|
|
36
|
+
*/
|
|
27
37
|
export interface DoctorSellerEntry {
|
|
28
38
|
id: string;
|
|
29
39
|
name?: string;
|
|
@@ -37,11 +47,19 @@ export interface DoctorSellerEntry {
|
|
|
37
47
|
errorMessage?: string;
|
|
38
48
|
}
|
|
39
49
|
|
|
50
|
+
/**
|
|
51
|
+
* `tb doctor` 完整诊断结果,由 `collectDoctorDiagnostics` 返回。
|
|
52
|
+
*/
|
|
40
53
|
export interface DoctorDiagnostics {
|
|
54
|
+
/** 控制面 / 代理端点可达性 */
|
|
41
55
|
access: DoctorAccessSummary;
|
|
56
|
+
/** Clawtip 钱包信息 */
|
|
42
57
|
clawtipWallet: DoctorClawtipWalletSummary;
|
|
58
|
+
/** 模型目录汇总 */
|
|
43
59
|
models: DoctorModelsSummary;
|
|
60
|
+
/** provider 安装 / 配置状态 */
|
|
44
61
|
providers: DoctorProviderView[];
|
|
62
|
+
/** seller 注册表 + 探测结果 */
|
|
45
63
|
sellers: DoctorSellersSummary;
|
|
46
64
|
}
|
|
47
65
|
|
|
@@ -90,6 +108,9 @@ interface DoctorModelsResponse {
|
|
|
90
108
|
sellers?: DoctorSellerEntry[];
|
|
91
109
|
}
|
|
92
110
|
|
|
111
|
+
/**
|
|
112
|
+
* `tb doctor` 模型表的单行:按 model id 聚合 seller 的折扣 / 价格区间。
|
|
113
|
+
*/
|
|
93
114
|
export interface DoctorModelSummaryEntry {
|
|
94
115
|
id: string;
|
|
95
116
|
sellerCount: number;
|
|
@@ -163,6 +184,9 @@ type DoctorSellersSummary = {
|
|
|
163
184
|
error?: string;
|
|
164
185
|
};
|
|
165
186
|
|
|
187
|
+
/**
|
|
188
|
+
* `tb doctor` 模型目录汇总:原始 `data` + 聚合后的 `grouped`(按 model id 分组)。
|
|
189
|
+
*/
|
|
166
190
|
export type DoctorModelsSummary = {
|
|
167
191
|
available: boolean;
|
|
168
192
|
count: number;
|
|
@@ -235,7 +259,6 @@ function providerRuntimeSummary(runtimeConfig?: ProviderRuntimeConfig): string |
|
|
|
235
259
|
return [
|
|
236
260
|
runtimeConfig.protocolPreference,
|
|
237
261
|
runtimeConfig.defaultModel,
|
|
238
|
-
runtimeConfig.sellerId ? `seller=${runtimeConfig.sellerId}` : undefined,
|
|
239
262
|
].filter(Boolean).join(" · ");
|
|
240
263
|
}
|
|
241
264
|
|
|
@@ -647,6 +670,12 @@ function printDoctorSellers(sellers: DoctorSellersSummary, writeLine: (line: str
|
|
|
647
670
|
}
|
|
648
671
|
}
|
|
649
672
|
|
|
673
|
+
/**
|
|
674
|
+
* 打印模型目录汇总(写到 `writeLine`,默认 stdout)。
|
|
675
|
+
*
|
|
676
|
+
* @param models 模型汇总
|
|
677
|
+
* @param writeLine 自定义输出函数(测试可注入)
|
|
678
|
+
*/
|
|
650
679
|
export function printDoctorModelsSummary(
|
|
651
680
|
models: DoctorModelsSummary,
|
|
652
681
|
writeLine: (line: string) => void = defaultWriter,
|
|
@@ -676,6 +705,11 @@ export function printDoctorModelsSummary(
|
|
|
676
705
|
writeLine(table.toString());
|
|
677
706
|
}
|
|
678
707
|
|
|
708
|
+
/**
|
|
709
|
+
* 读取 buyer 端已知的 provider 列表,把 runtime config(如果有)合并到 `DoctorProviderView`。
|
|
710
|
+
*
|
|
711
|
+
* @returns 每个 provider 的 view(数组)
|
|
712
|
+
*/
|
|
679
713
|
export function readDoctorProviders(): DoctorProviderView[] {
|
|
680
714
|
const store = new BuyerStore();
|
|
681
715
|
try {
|
|
@@ -703,6 +737,12 @@ export function readDoctorProviders(): DoctorProviderView[] {
|
|
|
703
737
|
}
|
|
704
738
|
}
|
|
705
739
|
|
|
740
|
+
/**
|
|
741
|
+
* 打印 provider 列表("Programming Terminals" 段)。
|
|
742
|
+
*
|
|
743
|
+
* @param providers provider view 列表
|
|
744
|
+
* @param writeLine 自定义输出函数
|
|
745
|
+
*/
|
|
706
746
|
export function printDoctorProviders(
|
|
707
747
|
providers: DoctorProviderView[],
|
|
708
748
|
writeLine: (line: string) => void = defaultWriter,
|
|
@@ -725,6 +765,15 @@ export function printDoctorProviders(
|
|
|
725
765
|
}
|
|
726
766
|
}
|
|
727
767
|
|
|
768
|
+
/**
|
|
769
|
+
* 收集 `tb doctor` 需要的全部诊断信息。
|
|
770
|
+
* 1. 并发拉取 daemon health / sellers / models / proxy models / registry 五个端点。
|
|
771
|
+
* 2. 合并 registry 配置 + 探测结果 + catalog 拉取结果。
|
|
772
|
+
* 3. 返回完整 `DoctorDiagnostics`(供 JSON 消费者或自定义渲染使用)。
|
|
773
|
+
*
|
|
774
|
+
* @param options 收集选项(端口 / daemon 状态 / registry URL / providers)
|
|
775
|
+
* @returns 完整诊断结果
|
|
776
|
+
*/
|
|
728
777
|
export async function collectDoctorDiagnostics(options: DoctorCollectOptions): Promise<DoctorDiagnostics> {
|
|
729
778
|
const fetches = startDoctorFetches(
|
|
730
779
|
options.controlPort,
|
|
@@ -762,6 +811,13 @@ export async function collectDoctorDiagnostics(options: DoctorCollectOptions): P
|
|
|
762
811
|
};
|
|
763
812
|
}
|
|
764
813
|
|
|
814
|
+
/**
|
|
815
|
+
* 单独收集 `tb models` 需要的模型汇总(不包含 providers)。
|
|
816
|
+
* daemon 拉到的数据缺价格时,回退用 `discoverSellerBackedModels` 重新拉 catalog。
|
|
817
|
+
*
|
|
818
|
+
* @param options 同 `collectDoctorDiagnostics`(去掉 providers)
|
|
819
|
+
* @returns 模型汇总
|
|
820
|
+
*/
|
|
765
821
|
export async function collectDoctorModelsSummary(options: Omit<DoctorCollectOptions, "providers">): Promise<DoctorModelsSummary> {
|
|
766
822
|
const diagnostics = await collectDoctorDiagnostics({
|
|
767
823
|
...options,
|
|
@@ -789,6 +845,12 @@ export async function collectDoctorModelsSummary(options: Omit<DoctorCollectOpti
|
|
|
789
845
|
|
|
790
846
|
}
|
|
791
847
|
|
|
848
|
+
/**
|
|
849
|
+
* 渐进式渲染 `tb doctor`:分阶段打印(clawtip → access → sellers → models),边等边输出,避免用户长时间看不到输出。
|
|
850
|
+
*
|
|
851
|
+
* @param options 渲染选项(含写入函数)
|
|
852
|
+
* @returns 完整 `DoctorDiagnostics`
|
|
853
|
+
*/
|
|
792
854
|
export async function renderDoctorDiagnosticsProgressively(options: DoctorRenderOptions): Promise<DoctorDiagnostics> {
|
|
793
855
|
const writeLine = options.writeLine || defaultWriter;
|
|
794
856
|
const clawtipWallet = readDoctorClawtipWallet();
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { buildCli } from "./cli.js";
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* CLI 入口:构造 commander program、解析 `process.argv`、异步执行。
|
|
5
|
+
* 异常通过 `process.exitCode = 1` 透传,避免在 daemon 未启动等情况下刷红 stderr(已通过 `code` 字段分类)。
|
|
6
|
+
*/
|
|
3
7
|
export function run() {
|
|
4
8
|
const program = buildCli();
|
|
5
9
|
program.parseAsync(process.argv).catch((error: unknown) => {
|
|
@@ -13,43 +13,86 @@ const SLEEP_SLICE_MS = 200;
|
|
|
13
13
|
const CLAWTIP_MIN_CLI_VERSION = "1.0.4";
|
|
14
14
|
const CLAWTIP_MIN_SKILL_VERSION = "1.0.12";
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* 一次 ClawTip 引导支付的输入参数(由上游 service / wallet-bootstrap 解析后传入)。
|
|
18
|
+
* 用来写本地 order 文件并触发 `npx @clawtip/clawtip-cli pay` 流程。
|
|
19
|
+
*/
|
|
16
20
|
export interface ClawtipBootstrapPayment {
|
|
21
|
+
/** 订单号(也是 order JSON 文件名) */
|
|
17
22
|
orderNo: string;
|
|
23
|
+
/** 金额(分) */
|
|
18
24
|
amountFen: number;
|
|
25
|
+
/** 收款方标识,可选 */
|
|
19
26
|
payTo?: string;
|
|
27
|
+
/** 上游加密负载,可选 */
|
|
20
28
|
encryptedData?: string;
|
|
29
|
+
/** 上游分配的 indicator(用于切到正确目录) */
|
|
21
30
|
indicator: string;
|
|
31
|
+
/** 上游 slug,可选 */
|
|
22
32
|
slug?: string;
|
|
33
|
+
/** skill ID(写入 order 的 `skill-id` 字段) */
|
|
23
34
|
skillId?: string;
|
|
35
|
+
/** 订单描述,可选 */
|
|
24
36
|
description?: string;
|
|
37
|
+
/** 资源 URL(写入 order 的 `resource_url` 字段) */
|
|
25
38
|
resourceUrl?: string;
|
|
26
39
|
}
|
|
27
40
|
|
|
41
|
+
/**
|
|
42
|
+
* `parseClawtipCliOutput()` 的输出:从 ClawTip CLI 文本输出中提取的结构化字段。
|
|
43
|
+
* 字段都为"尽力推断":缺失时为 undefined,由调用方决定如何处理。
|
|
44
|
+
*/
|
|
28
45
|
export interface ParsedClawtipOutput {
|
|
46
|
+
/** 鉴权 URL(可被扫码或浏览器打开) */
|
|
29
47
|
authUrl?: string;
|
|
48
|
+
/** 设备 ID(用于 check-register 轮询) */
|
|
30
49
|
clawtipId?: string;
|
|
50
|
+
/** QR 图片本地路径 */
|
|
31
51
|
mediaPath?: string;
|
|
52
|
+
/** 下游/上游的失败信息(已 sanitize 过的中文提示) */
|
|
32
53
|
failureMessage?: string;
|
|
54
|
+
/** 是否需要用户做钱包授权(含 QR、authUrl、扫码关键字等) */
|
|
33
55
|
requiresWalletAuth: boolean;
|
|
56
|
+
/** 钱包是否已就绪(register success / tokeninfo / config.json 等关键字) */
|
|
34
57
|
walletReady: boolean;
|
|
35
58
|
}
|
|
36
59
|
|
|
60
|
+
/**
|
|
61
|
+
* `waitForClawtipActivationConfirmation()` 的可注入依赖与可调参数。
|
|
62
|
+
* 默认实现使用 `@clack/prompts` 的 `cancel`、本机 `~/.openclaw/configs/` 探查和 npx `check-register`。
|
|
63
|
+
*/
|
|
37
64
|
export interface WaitForClawtipActivationOptions {
|
|
65
|
+
/** wallet config 探查函数(默认 `inspectOpenClawWalletConfig`) */
|
|
38
66
|
inspectWalletConfig?: () => OpenClawWalletConfigState;
|
|
67
|
+
/** 外部取消信号(与 SIGINT 监听器互不冲突) */
|
|
39
68
|
isCancelled?: () => boolean;
|
|
69
|
+
/** check-register 用的 ClawTip 设备 ID(必填才会触发轮询) */
|
|
40
70
|
clawtipId?: string;
|
|
71
|
+
/** check-register 命令执行函数(默认 `npx @clawtip/clawtip-cli check-register`) */
|
|
41
72
|
checkRegister?: (clawtipId: string) => Promise<void>;
|
|
73
|
+
/** 取消时的回调(默认 `@clack/prompts.cancel`) */
|
|
42
74
|
cancel?: (message?: string) => void;
|
|
75
|
+
/** 轮询间隔(毫秒),默认 2000 */
|
|
43
76
|
pollIntervalMs?: number;
|
|
77
|
+
/** sleep 实现(测试可注入) */
|
|
44
78
|
sleep?: (ms: number) => Promise<void>;
|
|
45
79
|
}
|
|
46
80
|
|
|
81
|
+
/**
|
|
82
|
+
* `startClawtipWalletBootstrap()` 的可注入依赖。
|
|
83
|
+
*/
|
|
47
84
|
export interface StartClawtipWalletBootstrapOptions {
|
|
85
|
+
/** 注入的 home 目录(默认 `process.env.HOME` / `os.homedir()`) */
|
|
48
86
|
home?: string;
|
|
87
|
+
/** 注入的 ClawTip CLI 执行函数(默认 `npx @clawtip/clawtip-cli`) */
|
|
49
88
|
runClawtipCommand?: (args: string[]) => Promise<string>;
|
|
50
89
|
}
|
|
51
90
|
|
|
91
|
+
/**
|
|
92
|
+
* `checkOpenClawRuntime()` 的可注入依赖。
|
|
93
|
+
*/
|
|
52
94
|
export interface CheckOpenClawRuntimeOptions {
|
|
95
|
+
/** 注入的 OpenClaw CLI 执行函数(默认 `openclaw --version`) */
|
|
53
96
|
runOpenClawCommand?: (args: string[]) => Promise<string>;
|
|
54
97
|
}
|
|
55
98
|
|
|
@@ -286,6 +329,13 @@ function extractClawtipIdFromUrl(value: string): string | undefined {
|
|
|
286
329
|
return undefined;
|
|
287
330
|
}
|
|
288
331
|
|
|
332
|
+
/**
|
|
333
|
+
* 从 ClawTip CLI 的 stdout/stderr 合并文本中提取关键信息。
|
|
334
|
+
* 同时识别 authUrl / clawtipId / mediaPath / 失败关键字 / 是否需要钱包授权 / 钱包是否就绪。
|
|
335
|
+
*
|
|
336
|
+
* @param output 合并后的 ClawTip CLI 输出
|
|
337
|
+
* @returns 结构化解析结果
|
|
338
|
+
*/
|
|
289
339
|
export function parseClawtipCliOutput(output: string): ParsedClawtipOutput {
|
|
290
340
|
const authUrl = findValueAfterKeys(output, ["authUrl", "auth_url", "auth url"]) || findUrlInOutput(output);
|
|
291
341
|
const mediaPath = findMediaPathInOutput(output);
|
|
@@ -314,6 +364,15 @@ export function parseClawtipCliOutput(output: string): ParsedClawtipOutput {
|
|
|
314
364
|
};
|
|
315
365
|
}
|
|
316
366
|
|
|
367
|
+
/**
|
|
368
|
+
* 取得 ClawTip 引导流程中要展示给用户的 QR 图片本地路径:
|
|
369
|
+
* 优先用 `parsedOutput.mediaPath`;缺省时抛错(因为首次绑定必须先走 wallet QR 流程)。
|
|
370
|
+
*
|
|
371
|
+
* @param parsedOutput `parseClawtipCliOutput()` 的结果
|
|
372
|
+
* @param orderFile 当前订单的 JSON 文件路径(用于错误消息)
|
|
373
|
+
* @returns QR 图片绝对路径
|
|
374
|
+
* @throws 当 `parsedOutput.mediaPath` 缺失时
|
|
375
|
+
*/
|
|
317
376
|
export function resolveClawtipQrMediaPath(parsedOutput: ParsedClawtipOutput, orderFile: string): string {
|
|
318
377
|
if (parsedOutput.mediaPath) {
|
|
319
378
|
return parsedOutput.mediaPath;
|
|
@@ -327,6 +386,13 @@ export function resolveClawtipQrMediaPath(parsedOutput: ParsedClawtipOutput, ord
|
|
|
327
386
|
);
|
|
328
387
|
}
|
|
329
388
|
|
|
389
|
+
/**
|
|
390
|
+
* 读 order JSON 里的 `payCredential`(snake/camel 兼容)。
|
|
391
|
+
* 用于在 `startClawtipWalletBootstrap()` 之后回传给上游 service。
|
|
392
|
+
*
|
|
393
|
+
* @param orderFile order JSON 的绝对路径
|
|
394
|
+
* @returns 非空 `payCredential` 字符串;文件不存在 / 字段缺失时返回 `undefined`
|
|
395
|
+
*/
|
|
330
396
|
export function readClawtipPayCredential(orderFile: string): string | undefined {
|
|
331
397
|
if (!fs.existsSync(orderFile)) {
|
|
332
398
|
return undefined;
|
|
@@ -336,6 +402,15 @@ export function readClawtipPayCredential(orderFile: string): string | undefined
|
|
|
336
402
|
return typeof credential === "string" && credential.trim() ? credential : undefined;
|
|
337
403
|
}
|
|
338
404
|
|
|
405
|
+
/**
|
|
406
|
+
* 把 ClawTip 引导支付所需的所有字段写成本地 order JSON:
|
|
407
|
+
* `~/.openclaw/skills/orders/<indicator>/<orderNo>.json`。
|
|
408
|
+
* 自动创建父目录。
|
|
409
|
+
*
|
|
410
|
+
* @param payment 引导支付参数
|
|
411
|
+
* @param home 用户 home 目录(默认 `process.env.HOME` / `os.homedir()`)
|
|
412
|
+
* @returns 写入的 order JSON 绝对路径
|
|
413
|
+
*/
|
|
339
414
|
export function writeClawtipOrderFile(
|
|
340
415
|
payment: ClawtipBootstrapPayment,
|
|
341
416
|
home: string = defaultHomeDir(),
|
|
@@ -357,6 +432,19 @@ export function writeClawtipOrderFile(
|
|
|
357
432
|
return orderFile;
|
|
358
433
|
}
|
|
359
434
|
|
|
435
|
+
/**
|
|
436
|
+
* 启动 ClawTip 钱包引导流程:
|
|
437
|
+
* 1. 写本地 order JSON
|
|
438
|
+
* 2. 调用 `npx @clawtip/clawtip-cli pay` 完成下单
|
|
439
|
+
* 3. 解析输出;若无 `mediaPath` 会在 `~/.openclaw/workspace/clawtip/qrcode/` 里
|
|
440
|
+
* 找最近生成的 QR 图作为兜底
|
|
441
|
+
* 4. 返回 order 文件路径 + 解析结果 + 回读到的 `payCredential`
|
|
442
|
+
*
|
|
443
|
+
* @param payment 引导支付参数
|
|
444
|
+
* @param options 可注入的 home / runClawtipCommand
|
|
445
|
+
* @returns 引导结果
|
|
446
|
+
* @throws 当 `parsedOutput.failureMessage` 非空时(即 ClawTip 下单失败)
|
|
447
|
+
*/
|
|
360
448
|
export async function startClawtipWalletBootstrap(
|
|
361
449
|
payment: ClawtipBootstrapPayment,
|
|
362
450
|
options: StartClawtipWalletBootstrapOptions = {},
|
|
@@ -394,6 +482,13 @@ export async function startClawtipWalletBootstrap(
|
|
|
394
482
|
};
|
|
395
483
|
}
|
|
396
484
|
|
|
485
|
+
/**
|
|
486
|
+
* 校验本机 `openclaw` CLI 可用:执行 `openclaw --version` 并返回去空白的版本字符串。
|
|
487
|
+
*
|
|
488
|
+
* @param options 可注入的 runOpenClawCommand
|
|
489
|
+
* @returns OpenClaw 版本字符串
|
|
490
|
+
* @throws 当 CLI 缺失或退出码非 0 时
|
|
491
|
+
*/
|
|
397
492
|
export async function checkOpenClawRuntime(
|
|
398
493
|
options: CheckOpenClawRuntimeOptions = {},
|
|
399
494
|
): Promise<string> {
|
|
@@ -439,6 +534,14 @@ async function sleepUntilNextPoll(
|
|
|
439
534
|
return !isCancelled();
|
|
440
535
|
}
|
|
441
536
|
|
|
537
|
+
/**
|
|
538
|
+
* 阻塞等待 ClawTip 钱包激活完成:轮询 `~/.openclaw/configs/config.json` 是否出现;
|
|
539
|
+
* 拿到 `clawtipId` 时还会调 `check-register` 主动推一次。
|
|
540
|
+
* 监听 `SIGINT` 与外部 `isCancelled` 触发取消。
|
|
541
|
+
*
|
|
542
|
+
* @param options 可注入的 inspect / checkRegister / cancel / sleep / pollInterval
|
|
543
|
+
* @returns 钱包就绪返回 `true`;被取消返回 `false`
|
|
544
|
+
*/
|
|
442
545
|
export async function waitForClawtipActivationConfirmation(
|
|
443
546
|
options: WaitForClawtipActivationOptions = {},
|
|
444
547
|
): Promise<boolean> {
|
|
@@ -5,63 +5,121 @@ import * as path from "path";
|
|
|
5
5
|
import type { PaymentConfig } from "./buyer-store.js";
|
|
6
6
|
import type { ProviderCandidate } from "./provider-install.js";
|
|
7
7
|
|
|
8
|
+
/** 当前 init 流程已支持的支付方式。当前仅 JD ClawTip 扫码支付。 */
|
|
8
9
|
export type InitPaymentMethod = "clawtip";
|
|
9
10
|
|
|
11
|
+
/**
|
|
12
|
+
* `INIT_PAYMENT_OPTIONS` 里的单条目,喂给 `@clack/prompts` 的 select 组件。
|
|
13
|
+
*/
|
|
10
14
|
export interface InitPaymentOption {
|
|
15
|
+
/** 选项值,对应 `InitPaymentMethod` */
|
|
11
16
|
value: InitPaymentMethod;
|
|
17
|
+
/** 展示给用户的标签 */
|
|
12
18
|
label: string;
|
|
19
|
+
/** 选段下方的小字提示,可选 */
|
|
13
20
|
hint?: string;
|
|
14
21
|
}
|
|
15
22
|
|
|
23
|
+
/**
|
|
24
|
+
* `INIT_COMING_SOON_PAYMENT_OPTIONS` 里的单条目:未上线的支付方式占位。
|
|
25
|
+
* 仅用于"更多支付方式"提示框展示,不可被选中。
|
|
26
|
+
*/
|
|
16
27
|
export interface ComingSoonPaymentOption {
|
|
28
|
+
/** 选项 ID(仅作展示和未来上线时引用) */
|
|
17
29
|
id: string;
|
|
30
|
+
/** 人类可读名称 */
|
|
18
31
|
label: string;
|
|
19
32
|
}
|
|
20
33
|
|
|
34
|
+
/**
|
|
35
|
+
* buyer-store 里 ClawTip 支付的已有绑定(持久化的关键字段)。
|
|
36
|
+
* `resourceUrl` / `orderNo` 至少存在一个才视为"可复用绑定"。
|
|
37
|
+
*/
|
|
21
38
|
export interface ExistingClawtipBinding {
|
|
39
|
+
/** 原始 config 对象(透传回 buyer-store 时用) */
|
|
22
40
|
config: Record<string, unknown>;
|
|
41
|
+
/** 资源 URL(可选) */
|
|
23
42
|
resourceUrl?: string;
|
|
43
|
+
/** 订单号(可选) */
|
|
24
44
|
orderNo?: string;
|
|
25
45
|
}
|
|
26
46
|
|
|
47
|
+
/**
|
|
48
|
+
* `buildInitTerminalSelectionState()` 的输出单条,喂给 `@clack/prompts` 的多选组件。
|
|
49
|
+
*/
|
|
27
50
|
export interface InitTerminalOption {
|
|
51
|
+
/** 选项值(通常是 `provider.id` 或 `"other"`) */
|
|
28
52
|
value: string;
|
|
53
|
+
/** 展示给用户的标签 */
|
|
29
54
|
label: string;
|
|
55
|
+
/** 选段下方的小字提示,可选 */
|
|
30
56
|
hint?: string;
|
|
31
57
|
}
|
|
32
58
|
|
|
59
|
+
/**
|
|
60
|
+
* `buildInitTerminalSelectionState()` 的输出:已配置 / 待配置 两个分组。
|
|
61
|
+
* `options` 末尾会追加 `OTHER_TERMINAL_OPTION`,给"我自己接"留口。
|
|
62
|
+
*/
|
|
33
63
|
export interface InitTerminalSelectionState {
|
|
64
|
+
/** 已配置完成的 provider(`status === "configured"`) */
|
|
34
65
|
installed: InitTerminalOption[];
|
|
66
|
+
/** 待配置的 provider,末尾追加 `OTHER_TERMINAL_OPTION` */
|
|
35
67
|
options: InitTerminalOption[];
|
|
36
68
|
}
|
|
37
69
|
|
|
70
|
+
/**
|
|
71
|
+
* `inspectOpenClawWalletConfig()` 的输出:本地 OpenClaw 钱包目录的探查结果。
|
|
72
|
+
* `alternatePaths` 是 `~/.openclaw/configs/` 里除 `config.json` 之外的文件,
|
|
73
|
+
* 用于在 missing 状态下提示用户"目录里其实有别的东西"。
|
|
74
|
+
*/
|
|
38
75
|
export interface OpenClawWalletConfigState {
|
|
76
|
+
/** `~/.openclaw/configs/config.json` 的预期路径 */
|
|
39
77
|
expectedPath: string;
|
|
78
|
+
/** `~/.openclaw/configs/` 目录是否存在 */
|
|
40
79
|
configsDirExists: boolean;
|
|
80
|
+
/** `expectedPath` 是否真实存在 */
|
|
41
81
|
exists: boolean;
|
|
82
|
+
/** 同目录里其它文件路径(按文件名字典序) */
|
|
42
83
|
alternatePaths: string[];
|
|
43
84
|
}
|
|
44
85
|
|
|
86
|
+
/**
|
|
87
|
+
* ClawTip 钱包就绪状态四象限:
|
|
88
|
+
* - `ready`:saved binding + 本地 wallet config 同时存在
|
|
89
|
+
* - `metadata_missing_wallet`:只 saved binding,wallet 缺
|
|
90
|
+
* - `wallet_missing_metadata`:只 wallet config,metadata 缺
|
|
91
|
+
* - `missing`:都缺
|
|
92
|
+
*/
|
|
45
93
|
export type ClawtipWalletStatus =
|
|
46
94
|
| "ready"
|
|
47
95
|
| "metadata_missing_wallet"
|
|
48
96
|
| "wallet_missing_metadata"
|
|
49
97
|
| "missing";
|
|
50
98
|
|
|
99
|
+
/**
|
|
100
|
+
* `inspectClawtipWalletReadiness()` 的输出:状态枚举 + 物证 + 给用户看的说明。
|
|
101
|
+
*/
|
|
51
102
|
export interface ClawtipWalletReadiness {
|
|
103
|
+
/** 综合状态 */
|
|
52
104
|
status: ClawtipWalletStatus;
|
|
105
|
+
/** 本地 OpenClaw wallet config 探查结果 */
|
|
53
106
|
walletConfig: OpenClawWalletConfigState;
|
|
107
|
+
/** buyer-store 里的 saved binding(如果有) */
|
|
54
108
|
savedBinding?: ExistingClawtipBinding;
|
|
109
|
+
/** 既 saved 又本地存在的可复用 binding(如果有) */
|
|
55
110
|
reusableBinding?: ExistingClawtipBinding;
|
|
111
|
+
/** 面向 init 面板 / doctor 的人类可读说明 */
|
|
56
112
|
message: string;
|
|
57
113
|
}
|
|
58
114
|
|
|
115
|
+
/** init 流程里"我自己接"的兜底选项 */
|
|
59
116
|
export const OTHER_TERMINAL_OPTION: InitTerminalOption = {
|
|
60
117
|
value: "other",
|
|
61
118
|
label: "Other",
|
|
62
119
|
hint: "I will configure my own terminal using the TokenBuddy proxy endpoints."
|
|
63
120
|
};
|
|
64
121
|
|
|
122
|
+
/** init 流程已支持的可选支付方式(喂给 `@clack/prompts` 的 select 组件) */
|
|
65
123
|
export const INIT_PAYMENT_OPTIONS: InitPaymentOption[] = [
|
|
66
124
|
{
|
|
67
125
|
value: "clawtip",
|
|
@@ -70,6 +128,7 @@ export const INIT_PAYMENT_OPTIONS: InitPaymentOption[] = [
|
|
|
70
128
|
}
|
|
71
129
|
];
|
|
72
130
|
|
|
131
|
+
/** init 流程"更多支付方式"占位列表(仅展示用,不可选) */
|
|
73
132
|
export const INIT_COMING_SOON_PAYMENT_OPTIONS = [
|
|
74
133
|
{
|
|
75
134
|
id: "wechat-pay",
|
|
@@ -85,6 +144,11 @@ export const INIT_COMING_SOON_PAYMENT_OPTIONS = [
|
|
|
85
144
|
}
|
|
86
145
|
] satisfies ReadonlyArray<ComingSoonPaymentOption>;
|
|
87
146
|
|
|
147
|
+
/**
|
|
148
|
+
* 在 init 流程的支付选择面板下追加"更多支付方式(接入中)"提示。
|
|
149
|
+
*
|
|
150
|
+
* @param note 注入的 note 函数(默认 `@clack/prompts.note`,测试可替换)
|
|
151
|
+
*/
|
|
88
152
|
export function noteInitComingSoonPayments(
|
|
89
153
|
note: (message?: string, title?: string) => void = p.note
|
|
90
154
|
): void {
|
|
@@ -94,6 +158,13 @@ export function noteInitComingSoonPayments(
|
|
|
94
158
|
);
|
|
95
159
|
}
|
|
96
160
|
|
|
161
|
+
/**
|
|
162
|
+
* 把 provider-install 阶段的探测结果转成 `InitTerminalSelectionState`:
|
|
163
|
+
* 已配置完成的归 `installed`;已检测到但未配置的归 `options`,末尾追加 `OTHER_TERMINAL_OPTION`。
|
|
164
|
+
*
|
|
165
|
+
* @param providers provider-install 的探测结果
|
|
166
|
+
* @returns init 流程的多选状态
|
|
167
|
+
*/
|
|
97
168
|
export function buildInitTerminalSelectionState(providers: ProviderCandidate[]): InitTerminalSelectionState {
|
|
98
169
|
const installed = providers
|
|
99
170
|
.filter((provider) => provider.detected && provider.status === "configured")
|
|
@@ -117,6 +188,12 @@ export function buildInitTerminalSelectionState(providers: ProviderCandidate[]):
|
|
|
117
188
|
};
|
|
118
189
|
}
|
|
119
190
|
|
|
191
|
+
/**
|
|
192
|
+
* 校验 init 多选面板的返回值:必须至少选一个 terminal 或选择 `Other`。
|
|
193
|
+
*
|
|
194
|
+
* @param selected `@clack/prompts` 多选返回值
|
|
195
|
+
* @returns 错误消息字符串;合法时返回 `undefined`
|
|
196
|
+
*/
|
|
120
197
|
export function validateInitTerminalSelection(selected: string[] | undefined): string | undefined {
|
|
121
198
|
if (!selected || selected.length === 0) {
|
|
122
199
|
return "Select at least one terminal or choose Other.";
|
|
@@ -124,6 +201,12 @@ export function validateInitTerminalSelection(selected: string[] | undefined): s
|
|
|
124
201
|
return undefined;
|
|
125
202
|
}
|
|
126
203
|
|
|
204
|
+
/**
|
|
205
|
+
* 把"已配置完成的 terminal"列表渲染成 init 面板顶部的摘要文案。
|
|
206
|
+
*
|
|
207
|
+
* @param installed 已配置完成的 terminal 列表
|
|
208
|
+
* @returns 多行 markdown 摘要;空列表时返回 `undefined`
|
|
209
|
+
*/
|
|
127
210
|
export function buildInstalledTerminalMessage(installed: InitTerminalOption[]): string | undefined {
|
|
128
211
|
if (installed.length === 0) {
|
|
129
212
|
return undefined;
|
|
@@ -137,6 +220,15 @@ function defaultHomeDir(): string {
|
|
|
137
220
|
return process.env.HOME || os.homedir();
|
|
138
221
|
}
|
|
139
222
|
|
|
223
|
+
/**
|
|
224
|
+
* 探查 `~/.openclaw/configs/` 目录及其默认 wallet 配置:
|
|
225
|
+
* - 是否存在 configs 目录
|
|
226
|
+
* - `config.json` 是否存在
|
|
227
|
+
* - 同目录里其它文件列表(用于 missing 状态下的提示)
|
|
228
|
+
*
|
|
229
|
+
* @param home 用户 home 目录(默认读 `process.env.HOME` 或 `os.homedir()`)
|
|
230
|
+
* @returns 探查结果
|
|
231
|
+
*/
|
|
140
232
|
export function inspectOpenClawWalletConfig(home: string = defaultHomeDir()): OpenClawWalletConfigState {
|
|
141
233
|
const configsDir = path.join(home, ".openclaw", "configs");
|
|
142
234
|
const expectedPath = path.join(configsDir, "config.json");
|
|
@@ -168,6 +260,13 @@ function stringField(value: unknown): string | undefined {
|
|
|
168
260
|
return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
|
|
169
261
|
}
|
|
170
262
|
|
|
263
|
+
/**
|
|
264
|
+
* 从 `PaymentConfig` 里识别 ClawTip 已保存的关键字段(`resourceUrl` / `orderNo`)。
|
|
265
|
+
* 两者都没有时返回 `undefined`。
|
|
266
|
+
*
|
|
267
|
+
* @param payment buyer-store 读到的 payment 配置
|
|
268
|
+
* @returns 识别出的 binding;无关键字段时返回 `undefined`
|
|
269
|
+
*/
|
|
171
270
|
export function detectExistingClawtipBinding(payment: PaymentConfig | undefined): ExistingClawtipBinding | undefined {
|
|
172
271
|
if (!payment || payment.method !== "clawtip" || !payment.config || typeof payment.config !== "object") {
|
|
173
272
|
return undefined;
|
|
@@ -185,6 +284,14 @@ export function detectExistingClawtipBinding(payment: PaymentConfig | undefined)
|
|
|
185
284
|
};
|
|
186
285
|
}
|
|
187
286
|
|
|
287
|
+
/**
|
|
288
|
+
* 判断已保存的 ClawTip binding 能否被本地 OpenClaw wallet config 复用:
|
|
289
|
+
* wallet config 必须存在并且 saved binding 至少有一个关键字段。
|
|
290
|
+
*
|
|
291
|
+
* @param payment buyer-store 读到的 payment 配置
|
|
292
|
+
* @param walletConfig `inspectOpenClawWalletConfig()` 的结果
|
|
293
|
+
* @returns 可复用 binding;不可复用时返回 `undefined`
|
|
294
|
+
*/
|
|
188
295
|
export function detectReusableClawtipBinding(
|
|
189
296
|
payment: PaymentConfig | undefined,
|
|
190
297
|
walletConfig: OpenClawWalletConfigState
|
|
@@ -195,6 +302,14 @@ export function detectReusableClawtipBinding(
|
|
|
195
302
|
return detectExistingClawtipBinding(payment);
|
|
196
303
|
}
|
|
197
304
|
|
|
305
|
+
/**
|
|
306
|
+
* 综合判断 ClawTip 钱包的就绪状态:把 saved binding、wallet config 和 reuse 关系
|
|
307
|
+
* 合并成 `ClawtipWalletReadiness`,供 init 面板、doctor 和激活流程共同消费。
|
|
308
|
+
*
|
|
309
|
+
* @param payment buyer-store 读到的 payment 配置
|
|
310
|
+
* @param walletConfig 本地 wallet 探查结果(默认 `inspectOpenClawWalletConfig()`)
|
|
311
|
+
* @returns 就绪状态 + 物证 + 人类可读说明
|
|
312
|
+
*/
|
|
198
313
|
export function inspectClawtipWalletReadiness(
|
|
199
314
|
payment: PaymentConfig | undefined,
|
|
200
315
|
walletConfig: OpenClawWalletConfigState = inspectOpenClawWalletConfig(),
|
|
@@ -236,6 +351,15 @@ export function inspectClawtipWalletReadiness(
|
|
|
236
351
|
};
|
|
237
352
|
}
|
|
238
353
|
|
|
354
|
+
/**
|
|
355
|
+
* 把 init 流程的若干条摘要拼成"成功"提示:
|
|
356
|
+
* - 顶部一行 emoji + 成功消息
|
|
357
|
+
* - 中间每条摘要 `- ` 开头
|
|
358
|
+
* - 末尾附 `tb doctor` 提示
|
|
359
|
+
*
|
|
360
|
+
* @param summaryLines 摘要行(会先 trim,空行会被跳过)
|
|
361
|
+
* @returns 多行 markdown 摘要
|
|
362
|
+
*/
|
|
239
363
|
export function buildInitSuccessMessage(summaryLines: string[] = []): string {
|
|
240
364
|
const lines = ["✅ TokenBuddy setup completed successfully."];
|
|
241
365
|
for (const line of summaryLines) {
|
package/src/model-index.ts
CHANGED
|
@@ -21,10 +21,19 @@ function normalizeModelId(modelId: string): string {
|
|
|
21
21
|
* - `sellers` is a snapshot array of the matching registry entries. Order
|
|
22
22
|
* follows the registry's `defaultSeller` preference then declaration order.
|
|
23
23
|
*/
|
|
24
|
+
/**
|
|
25
|
+
* `ModelIndex.resolve()` 的返回结果。
|
|
26
|
+
* - `empty` 等价于 `matched = false && sellers = []`,路由层应当视为"无可用 seller"。
|
|
27
|
+
* - `sellers` 是按 `defaultSeller` 优先 + 声明顺序排序后的快照数组。
|
|
28
|
+
*/
|
|
24
29
|
export interface ModelIndexResolution {
|
|
30
|
+
/** 原始请求的模型 ID(未归一化) */
|
|
25
31
|
modelId: string;
|
|
32
|
+
/** 索引里是否至少有一个 seller 命中(已归一化匹配) */
|
|
26
33
|
matched: boolean;
|
|
34
|
+
/** 命中的 seller 列表(已按 default + 声明顺序排序的快照) */
|
|
27
35
|
sellers: RegistrySeller[];
|
|
36
|
+
/** 当前索引里 `models` 字段缺失的 seller 数(用于诊断和告警) */
|
|
28
37
|
missingModelsFlag: number;
|
|
29
38
|
}
|
|
30
39
|
|