@tokenbuddy/tokenbuddy 1.0.37 → 1.0.39
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 +1 -1
- package/dist/src/buyer-store.js +3 -3
- package/dist/src/cli.d.ts +1 -0
- package/dist/src/cli.js +66 -5
- package/dist/src/daemon.d.ts +23 -5
- package/dist/src/daemon.js +606 -9
- package/dist/src/provider-install.d.ts +3 -0
- package/dist/src/provider-install.js +506 -85
- package/dist/src/workdir.d.ts +10 -0
- package/dist/src/workdir.js +26 -0
- package/package.json +2 -2
- package/static/ui/assets/index-BAwWDK4H.js +271 -0
- package/static/ui/assets/index-DM9SnAfj.css +1 -0
- package/static/ui/index.html +2 -2
- package/static/ui/assets/index-Djfl9tw5.js +0 -271
- package/static/ui/assets/index-DkfztCkn.css +0 -1
|
@@ -251,7 +251,7 @@ export interface BuyerStoreOptions {
|
|
|
251
251
|
}
|
|
252
252
|
/**
|
|
253
253
|
* 解析 buyer store 的 DB 路径。
|
|
254
|
-
* 优先级:`dbPath` → `TOKENBUDDY_BUYER_STORE` env → `~/.tokenbuddy
|
|
254
|
+
* 优先级:`dbPath` → `TOKENBUDDY_BUYER_STORE` env → `TB_WORKDIR` env → `~/.config/tokenbuddy/buyer-store.db`。
|
|
255
255
|
*
|
|
256
256
|
* @param options 解析选项
|
|
257
257
|
* @returns DB 文件绝对路径
|
package/dist/src/buyer-store.js
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
import { DatabaseSync } from "node:sqlite";
|
|
3
3
|
import * as crypto from "crypto";
|
|
4
4
|
import * as fs from "fs";
|
|
5
|
-
import * as os from "os";
|
|
6
5
|
import * as path from "path";
|
|
7
6
|
import { createModuleLogger } from "@tokenbuddy/logging";
|
|
7
|
+
import { resolveTokenBuddyWorkdir } from "./workdir.js";
|
|
8
8
|
const logger = createModuleLogger("tb-proxyd");
|
|
9
9
|
function nowIso() {
|
|
10
10
|
return new Date().toISOString();
|
|
@@ -26,7 +26,7 @@ function ensureDirForFile(filePath) {
|
|
|
26
26
|
}
|
|
27
27
|
/**
|
|
28
28
|
* 解析 buyer store 的 DB 路径。
|
|
29
|
-
* 优先级:`dbPath` → `TOKENBUDDY_BUYER_STORE` env → `~/.tokenbuddy
|
|
29
|
+
* 优先级:`dbPath` → `TOKENBUDDY_BUYER_STORE` env → `TB_WORKDIR` env → `~/.config/tokenbuddy/buyer-store.db`。
|
|
30
30
|
*
|
|
31
31
|
* @param options 解析选项
|
|
32
32
|
* @returns DB 文件绝对路径
|
|
@@ -35,7 +35,7 @@ export function resolveBuyerStorePath(options = {}) {
|
|
|
35
35
|
if (options.dbPath) {
|
|
36
36
|
return options.dbPath;
|
|
37
37
|
}
|
|
38
|
-
const root = options.root || process.env.TOKENBUDDY_BUYER_STORE ||
|
|
38
|
+
const root = options.root || process.env.TOKENBUDDY_BUYER_STORE || resolveTokenBuddyWorkdir();
|
|
39
39
|
return path.join(root, "buyer-store.db");
|
|
40
40
|
}
|
|
41
41
|
/**
|
package/dist/src/cli.d.ts
CHANGED
package/dist/src/cli.js
CHANGED
|
@@ -19,6 +19,7 @@ import { DEFAULT_CLAWTIP_BOOTSTRAP_URL, fetchClawtipBootstrap, } from "./clawtip
|
|
|
19
19
|
import { displayTerminalImage } from "./terminal-image.js";
|
|
20
20
|
import { checkPackageUpdate, readInstalledPackageManifest, runPackageUpdate, } from "./package-update.js";
|
|
21
21
|
import { DEFAULT_SELLER_REGISTRY_URL } from "./registry-trust.js";
|
|
22
|
+
import { resolveTokenBuddyWorkdir, resolveTokenBuddyWorkdirPath, TB_WORKDIR_ENV } from "./workdir.js";
|
|
22
23
|
// @ts-ignore
|
|
23
24
|
import qrcode from "qrcode-terminal";
|
|
24
25
|
const CONTROL_PORT = 17820;
|
|
@@ -119,7 +120,7 @@ function launchControlUi(controlPort, pathname = "/") {
|
|
|
119
120
|
return url;
|
|
120
121
|
}
|
|
121
122
|
function defaultProxydLogPath(kind) {
|
|
122
|
-
const logDir =
|
|
123
|
+
const logDir = resolveTokenBuddyWorkdir();
|
|
123
124
|
fs.mkdirSync(logDir, { recursive: true });
|
|
124
125
|
return path.join(logDir, `tb-proxyd.${kind}.log`);
|
|
125
126
|
}
|
|
@@ -164,6 +165,9 @@ export function buildLaunchdPlistContent(options) {
|
|
|
164
165
|
if (options.clawtipProofCommand?.trim()) {
|
|
165
166
|
env.TB_PROXYD_CLAWTIP_PROOF_COMMAND = options.clawtipProofCommand.trim();
|
|
166
167
|
}
|
|
168
|
+
if (options.workdir?.trim()) {
|
|
169
|
+
env[TB_WORKDIR_ENV] = options.workdir.trim();
|
|
170
|
+
}
|
|
167
171
|
if (options.clawtipProofTimeoutMs !== undefined) {
|
|
168
172
|
env.TB_PROXYD_CLAWTIP_PROOF_TIMEOUT_MS = String(options.clawtipProofTimeoutMs);
|
|
169
173
|
}
|
|
@@ -383,8 +387,9 @@ export async function runWebInitLauncher(deps = {}) {
|
|
|
383
387
|
if (platform === "darwin") {
|
|
384
388
|
const plistDir = path.join(home, "Library", "LaunchAgents");
|
|
385
389
|
const plistPath = path.join(plistDir, `${TOKENBUDDY_LAUNCHD_LABEL}.plist`);
|
|
386
|
-
const
|
|
387
|
-
const
|
|
390
|
+
const workdir = resolveTokenBuddyWorkdir({ homeDir: home });
|
|
391
|
+
const stdoutPath = deps.stdoutPath ?? resolveTokenBuddyWorkdirPath("tb-proxyd.stdout.log", { homeDir: home });
|
|
392
|
+
const stderrPath = deps.stderrPath ?? resolveTokenBuddyWorkdirPath("tb-proxyd.stderr.log", { homeDir: home });
|
|
388
393
|
try {
|
|
389
394
|
(deps.mkdirSync ?? fs.mkdirSync)(plistDir, { recursive: true });
|
|
390
395
|
(deps.mkdirSync ?? fs.mkdirSync)(path.dirname(stdoutPath), { recursive: true });
|
|
@@ -394,6 +399,7 @@ export async function runWebInitLauncher(deps = {}) {
|
|
|
394
399
|
nodePath: deps.nodePath ?? process.execPath,
|
|
395
400
|
scriptPath: deps.scriptPath ?? tbProxydScriptPath(),
|
|
396
401
|
pathEnv: deps.pathEnv,
|
|
402
|
+
workdir,
|
|
397
403
|
stdoutPath,
|
|
398
404
|
stderrPath,
|
|
399
405
|
controlPort,
|
|
@@ -690,6 +696,33 @@ function stableModelChoices(models) {
|
|
|
690
696
|
};
|
|
691
697
|
});
|
|
692
698
|
}
|
|
699
|
+
const OPENCODE_SUPPORTED_PROTOCOLS = ["chat_completions", "responses", "messages"];
|
|
700
|
+
function uniqueModelIds(models) {
|
|
701
|
+
const seen = new Set();
|
|
702
|
+
const output = [];
|
|
703
|
+
for (const model of models) {
|
|
704
|
+
const trimmed = model.trim();
|
|
705
|
+
if (!trimmed || seen.has(trimmed)) {
|
|
706
|
+
continue;
|
|
707
|
+
}
|
|
708
|
+
seen.add(trimmed);
|
|
709
|
+
output.push(trimmed);
|
|
710
|
+
}
|
|
711
|
+
return output;
|
|
712
|
+
}
|
|
713
|
+
function availableModelsByProtocol(models, protocols) {
|
|
714
|
+
const result = {};
|
|
715
|
+
for (const protocol of protocols) {
|
|
716
|
+
const modelIds = uniqueModelIds(filterCatalogByProtocol(models, protocol).map((entry) => entry.id));
|
|
717
|
+
if (modelIds.length > 0) {
|
|
718
|
+
result[protocol] = modelIds;
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
return result;
|
|
722
|
+
}
|
|
723
|
+
function filterCatalogByAnyProtocol(models, protocols) {
|
|
724
|
+
return models.filter((entry) => protocols.some((protocol) => entry.supportedProtocols.includes(protocol)));
|
|
725
|
+
}
|
|
693
726
|
async function promptSellerRoutingPreference(catalog) {
|
|
694
727
|
const healthySellers = catalog.sellers.filter((seller) => seller.status === "ok");
|
|
695
728
|
const mode = await p.select({
|
|
@@ -854,6 +887,28 @@ async function promptSingleModelSelection(providerId, models) {
|
|
|
854
887
|
selectionKind: "single-model",
|
|
855
888
|
protocolPreference,
|
|
856
889
|
defaultModel: selectedModel,
|
|
890
|
+
...(protocolPreference ? {
|
|
891
|
+
availableModelsByProtocol: availableModelsByProtocol(models, [protocolPreference]),
|
|
892
|
+
} : {}),
|
|
893
|
+
};
|
|
894
|
+
}
|
|
895
|
+
async function promptOpenCodeModelSelection(models) {
|
|
896
|
+
const compatibleModels = filterCatalogByAnyProtocol(models, OPENCODE_SUPPORTED_PROTOCOLS);
|
|
897
|
+
const choices = stableModelChoices(compatibleModels);
|
|
898
|
+
if (choices.length === 0) {
|
|
899
|
+
throw new Error("no compatible models available for OpenCode");
|
|
900
|
+
}
|
|
901
|
+
const selectedModel = await p.select({
|
|
902
|
+
message: "Choose the default model for OpenCode:",
|
|
903
|
+
options: choices,
|
|
904
|
+
});
|
|
905
|
+
if (typeof selectedModel !== "string") {
|
|
906
|
+
throw new Error("default model selection was cancelled for OpenCode");
|
|
907
|
+
}
|
|
908
|
+
return {
|
|
909
|
+
selectionKind: "single-model",
|
|
910
|
+
defaultModel: selectedModel,
|
|
911
|
+
availableModelsByProtocol: availableModelsByProtocol(models, OPENCODE_SUPPORTED_PROTOCOLS),
|
|
857
912
|
};
|
|
858
913
|
}
|
|
859
914
|
function defaultClaudeDisplayName(modelId) {
|
|
@@ -952,6 +1007,10 @@ async function promptProviderSelections(providerIds, catalog, sellerRouting) {
|
|
|
952
1007
|
: catalog.models;
|
|
953
1008
|
const selections = {};
|
|
954
1009
|
for (const providerId of providerIds) {
|
|
1010
|
+
if (providerId === "opencode") {
|
|
1011
|
+
selections[providerId] = await promptOpenCodeModelSelection(baseModels);
|
|
1012
|
+
continue;
|
|
1013
|
+
}
|
|
955
1014
|
const selectionKind = getProviderModelSelectionKind(providerId);
|
|
956
1015
|
if (selectionKind === "claude-role-mapping") {
|
|
957
1016
|
selections[providerId] = await promptClaudeCodeModelSelection(baseModels);
|
|
@@ -1799,8 +1858,9 @@ export function buildCli() {
|
|
|
1799
1858
|
const sellerRegistryUrl = sellerRegistryUrlForInit();
|
|
1800
1859
|
const nodePath = process.execPath;
|
|
1801
1860
|
const scriptPath = tbProxydScriptPath();
|
|
1802
|
-
const
|
|
1803
|
-
const
|
|
1861
|
+
const workdir = resolveTokenBuddyWorkdir({ homeDir: home });
|
|
1862
|
+
const stdoutPath = resolveTokenBuddyWorkdirPath("tb-proxyd.stdout.log", { homeDir: home });
|
|
1863
|
+
const stderrPath = resolveTokenBuddyWorkdirPath("tb-proxyd.stderr.log", { homeDir: home });
|
|
1804
1864
|
fs.mkdirSync(path.dirname(stdoutPath), { recursive: true });
|
|
1805
1865
|
fs.mkdirSync(path.dirname(stderrPath), { recursive: true });
|
|
1806
1866
|
const plistContent = buildLaunchdPlistContent({
|
|
@@ -1813,6 +1873,7 @@ export function buildCli() {
|
|
|
1813
1873
|
proxyPort,
|
|
1814
1874
|
sellerRegistryUrl,
|
|
1815
1875
|
pathEnv: process.env.PATH,
|
|
1876
|
+
workdir,
|
|
1816
1877
|
clawtipProofCommand: defaultClawtipProofCommand(),
|
|
1817
1878
|
clawtipProofTimeoutMs: process.env.TB_PROXYD_CLAWTIP_PROOF_TIMEOUT_MS
|
|
1818
1879
|
? Number(process.env.TB_PROXYD_CLAWTIP_PROOF_TIMEOUT_MS)
|
package/dist/src/daemon.d.ts
CHANGED
|
@@ -24,11 +24,7 @@ export interface DaemonConfig {
|
|
|
24
24
|
/** test-only override for the existing tb init ClawTip activation runner. */
|
|
25
25
|
clawtipWalletBootstrapStarter?: (payment: ClawtipBootstrapPayment, options?: {
|
|
26
26
|
home?: string;
|
|
27
|
-
}) => Promise<
|
|
28
|
-
orderFile: string;
|
|
29
|
-
parsedOutput: ParsedClawtipOutput;
|
|
30
|
-
payCredential?: string;
|
|
31
|
-
}>;
|
|
27
|
+
}) => Promise<ClawtipActivationResult>;
|
|
32
28
|
/** test-only override for waiting on the existing tb init ClawTip registration loop. */
|
|
33
29
|
clawtipActivationWaiter?: (options?: WaitForClawtipActivationOptions) => Promise<boolean>;
|
|
34
30
|
/** test-only override for bundled ClawTip static assets; false disables bundled assets. */
|
|
@@ -93,6 +89,7 @@ export declare class TokenbuddyDaemon {
|
|
|
93
89
|
private ensureClawtipStaticAssets;
|
|
94
90
|
private copyClawtipQrToStatic;
|
|
95
91
|
private startClawtipActivationQr;
|
|
92
|
+
private startClawtipActivationWithRebindFallback;
|
|
96
93
|
private scheduleClawtipActivationWait;
|
|
97
94
|
private clawtipRechargeQr;
|
|
98
95
|
private lastRegistrySnapshot;
|
|
@@ -130,6 +127,21 @@ export declare class TokenbuddyDaemon {
|
|
|
130
127
|
private applyAutoProviderRoutingConfig;
|
|
131
128
|
private autoProviderCanRoute;
|
|
132
129
|
private providerModePayload;
|
|
130
|
+
private isReconnectProviderId;
|
|
131
|
+
private uniqueModelIds;
|
|
132
|
+
private reconnectProtocolForProvider;
|
|
133
|
+
private reconnectProtocolsForProvider;
|
|
134
|
+
private catalogModelSupportsProtocol;
|
|
135
|
+
private catalogModelsByProtocol;
|
|
136
|
+
private previousProviderDefaultModel;
|
|
137
|
+
private pickReconnectDefaultModel;
|
|
138
|
+
private reconnectProviderSelection;
|
|
139
|
+
private reconnectProviderSelections;
|
|
140
|
+
private manualProviderModelCatalog;
|
|
141
|
+
private discoverSellerModelCatalog;
|
|
142
|
+
private refreshEnabledManualProviderModels;
|
|
143
|
+
private filterAutoEffectiveCatalog;
|
|
144
|
+
private effectiveModelCatalog;
|
|
133
145
|
private clientToolsSummary;
|
|
134
146
|
private initRepairStatus;
|
|
135
147
|
private initStateSnapshot;
|
|
@@ -270,4 +282,10 @@ export declare class TokenbuddyDaemon {
|
|
|
270
282
|
*/
|
|
271
283
|
setLastRegistrySnapshotForTest(snapshot: SellerRegistryDocument | null): void;
|
|
272
284
|
}
|
|
285
|
+
interface ClawtipActivationResult {
|
|
286
|
+
orderFile: string;
|
|
287
|
+
parsedOutput: ParsedClawtipOutput;
|
|
288
|
+
payCredential?: string;
|
|
289
|
+
}
|
|
290
|
+
export {};
|
|
273
291
|
//# sourceMappingURL=daemon.d.ts.map
|