dsh-connect-trae 2.2.0 → 2.3.1
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/CHANGELOG.md +116 -2
- package/README.en.md +66 -18
- package/README.md +66 -18
- package/icons/dsh-connect-trae-128.png +0 -0
- package/icons/dsh-connect-trae-64.png +0 -0
- package/lib/client.js +124 -37
- package/lib/index.d.ts +210 -34
- package/lib/index.js +280 -62
- package/package.json +29 -26
- package/scripts/verify-windows.mjs +311 -0
package/lib/index.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import z from "@deepseek-ai/schemastery";
|
|
2
|
-
import * as dshSettings from "@deepseek-ai/dsh-settings";
|
|
3
2
|
import { createProvider } from "@earendil-works/pi-ai";
|
|
4
3
|
import { openAICompletionsApi } from "@earendil-works/pi-ai/api/openai-completions.lazy";
|
|
5
4
|
import { resolveRetryPolicy } from "@deepseek-ai/dsh-llm";
|
|
@@ -14,6 +13,7 @@ import { createServer } from "node:http";
|
|
|
14
13
|
import { Readable } from "node:stream";
|
|
15
14
|
import { execFile } from "node:child_process";
|
|
16
15
|
import { promisify } from "node:util";
|
|
16
|
+
import { existsSync } from "node:fs";
|
|
17
17
|
//#region src/catalog.ts
|
|
18
18
|
/**
|
|
19
19
|
* Bootstrap catalog: identity only where current Trae metadata has not been
|
|
@@ -150,12 +150,19 @@ function displayKey(name) {
|
|
|
150
150
|
* skeleton: it supplies the display id, display name, context windows, credit
|
|
151
151
|
* multiplier, reasoning and multimodal flags. `wire` (from `get_detail_param`)
|
|
152
152
|
* supplies the real `llm_utils_chat` `config_name` — the only id the chat
|
|
153
|
-
* endpoint actually accepts
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
*
|
|
158
|
-
*
|
|
153
|
+
* endpoint actually accepts — plus the authoritative post-discount credit
|
|
154
|
+
* multiplier when `display_contact_config` carries one. A remote row is only
|
|
155
|
+
* callable when it maps to a wire `config_name`, so a remote row with no wire
|
|
156
|
+
* match is DROPPED (it would otherwise be sent as an invalid `config_name` and
|
|
157
|
+
* rejected with 4001 "param is invalid"). Verified 2026-08-30: the Remote
|
|
158
|
+
* directory advertises `Doubao-Seed-Code` and `glm-5.3`, neither of which is a
|
|
159
|
+
* current `config_name`; both fail every request, so they must not be exposed.
|
|
160
|
+
*
|
|
161
|
+
* Credit multiplier precedence: the wire's `display_contact_config` rate wins
|
|
162
|
+
* whenever present (it is the post-discount figure the Trae IDE renders — the
|
|
163
|
+
* Remote directory can report up to 10x the undiscounted value, see
|
|
164
|
+
* `wireCreditMultiplier` in solo.ts); the Remote `consumption_rate` is the
|
|
165
|
+
* fallback when the wire row carries none.
|
|
159
166
|
*
|
|
160
167
|
* Joining is two-tier, in priority order:
|
|
161
168
|
* 1. `wire.id` (the `config_name`) equals the remote id — the model's display
|
|
@@ -177,12 +184,13 @@ function mergeTraeModelSources(remote, wire) {
|
|
|
177
184
|
for (const model of remote) {
|
|
178
185
|
const wireModel = wireById.get(displayKey(model.id)) ?? wireByName.get(displayKey(model.name));
|
|
179
186
|
if (wireModel === void 0) continue;
|
|
187
|
+
const creditMultiplier = wireModel.creditMultiplier ?? model.creditMultiplier;
|
|
180
188
|
result.push({
|
|
181
189
|
id: model.id,
|
|
182
190
|
name: model.name,
|
|
183
191
|
...model.contextWindow === void 0 ? {} : { contextWindow: model.contextWindow },
|
|
184
192
|
...model.maxContextWindow === void 0 ? {} : { maxContextWindow: model.maxContextWindow },
|
|
185
|
-
...
|
|
193
|
+
...creditMultiplier === void 0 ? {} : { creditMultiplier },
|
|
186
194
|
input: ["text"],
|
|
187
195
|
reasoningSupported: model.reasoningSupported,
|
|
188
196
|
...model.reasoning === void 0 ? {} : {
|
|
@@ -793,6 +801,43 @@ const LINUX_APP_NAMES = {
|
|
|
793
801
|
solo: ["trae-solo-cn", "TRAE SOLO CN"],
|
|
794
802
|
"solo-sg": ["trae-solo", "TRAE SOLO"]
|
|
795
803
|
};
|
|
804
|
+
/**
|
|
805
|
+
* Windows desktop config directory names.
|
|
806
|
+
*
|
|
807
|
+
* Trae is a VS Code-family Electron app, and that family names its per-user
|
|
808
|
+
* data directory from the installer-registered product name — which on Windows
|
|
809
|
+
* is `product.json`'s `win32DirName`, NOT the macOS bundle spelling. Measured
|
|
810
|
+
* from the shipped bundles (2026-09-26):
|
|
811
|
+
*
|
|
812
|
+
* Trae CN -> win32DirName = "Trae CN" (applicationName trae-cn)
|
|
813
|
+
* TRAE SOLO CN -> win32DirName = "TRAE SOLO CN" (applicationName trae-solo-cn)
|
|
814
|
+
*
|
|
815
|
+
* So the macOS spellings happen to be right here, and `win32DirName` is the
|
|
816
|
+
* authority that says so. The lowercase `applicationName` spellings
|
|
817
|
+
* (`trae-cn`, `trae-solo-cn`) are probed as well because the same family uses
|
|
818
|
+
* them for the Linux config directory, and which of the two a given installer
|
|
819
|
+
* writes has never been confirmed on a real Windows host
|
|
820
|
+
* (docs/WINDOWS_TOKEN_PROBE.md). Windows file systems are case-insensitive, so
|
|
821
|
+
* listing `trae cn` beside `Trae CN` would be the same directory twice — only
|
|
822
|
+
* genuinely different spellings are listed.
|
|
823
|
+
*/
|
|
824
|
+
const WINDOWS_APP_NAMES = {
|
|
825
|
+
cn: ["Trae CN", "trae-cn"],
|
|
826
|
+
sg: ["Trae"],
|
|
827
|
+
solo: ["TRAE SOLO CN", "trae-solo-cn"],
|
|
828
|
+
"solo-sg": ["TRAE SOLO"]
|
|
829
|
+
};
|
|
830
|
+
/**
|
|
831
|
+
* One edition's plausible Windows directory spellings, in probe order.
|
|
832
|
+
*
|
|
833
|
+
* Exported so the identity reader and the credential scanner probe the SAME
|
|
834
|
+
* names: the two resolve different files (the install's `product.json` vs the
|
|
835
|
+
* per-user `storage.json`) but they describe one installation, and a spelling
|
|
836
|
+
* that works for one but not the other is a bug rather than a preference.
|
|
837
|
+
*/
|
|
838
|
+
function traeWindowsAppNames(edition) {
|
|
839
|
+
return WINDOWS_APP_NAMES[edition];
|
|
840
|
+
}
|
|
796
841
|
function traeStorageCandidates(platform = process.platform, home = homedir(), env = process.env) {
|
|
797
842
|
const result = [];
|
|
798
843
|
for (const edition of [
|
|
@@ -809,7 +854,7 @@ function traeStorageCandidates(platform = process.platform, home = homedir(), en
|
|
|
809
854
|
appNames = [app];
|
|
810
855
|
} else if (platform === "win32") {
|
|
811
856
|
roots = [env.APPDATA, join(home, "AppData", "Roaming")].filter((value, index, all) => typeof value === "string" && value !== "" && all.indexOf(value) === index);
|
|
812
|
-
appNames = [
|
|
857
|
+
appNames = WINDOWS_APP_NAMES[edition];
|
|
813
858
|
} else if (platform === "linux") {
|
|
814
859
|
roots = [env.XDG_CONFIG_HOME || join(home, ".config")];
|
|
815
860
|
appNames = LINUX_APP_NAMES[edition];
|
|
@@ -1395,7 +1440,7 @@ async function readTraeIdentity(candidate, options = {}) {
|
|
|
1395
1440
|
if (platform === "darwin") productPaths.push(join("/Applications", `${appName}.app`, "Contents", "Resources", "app", "product.json"));
|
|
1396
1441
|
else {
|
|
1397
1442
|
const localRoots = [env.LOCALAPPDATA, join(home, "AppData", "Local")].filter((value) => typeof value === "string" && value !== "").filter((value, index, all) => all.indexOf(value) === index);
|
|
1398
|
-
for (const root of localRoots) productPaths.push(join(root, "Programs",
|
|
1443
|
+
for (const root of localRoots) for (const spelling of traeWindowsAppNames(candidate.edition)) productPaths.push(join(root, "Programs", spelling, "resources", "app", "product.json"));
|
|
1399
1444
|
}
|
|
1400
1445
|
}
|
|
1401
1446
|
let product = {};
|
|
@@ -1934,6 +1979,39 @@ function prepareSoloBody(source, defaultModel = "glm-5.2", functionName) {
|
|
|
1934
1979
|
}
|
|
1935
1980
|
return JSON.stringify(body);
|
|
1936
1981
|
}
|
|
1982
|
+
/**
|
|
1983
|
+
* Read the effective credit multiplier from a `get_detail_param` row.
|
|
1984
|
+
*
|
|
1985
|
+
* The rate the Trae IDE renders lives in `display_contact_config` — a *string*
|
|
1986
|
+
* holding a second JSON document — and its `consumption_rate.data.rate` is
|
|
1987
|
+
* already the post-discount value (verified 2026-09-13, commit 1.4.2: the
|
|
1988
|
+
* Remote directory reports the undiscounted figure, e.g. `0.8`, while the IDE
|
|
1989
|
+
* and this field both say `0.08` under a 限时 1 折 promotion — up to a 10x
|
|
1990
|
+
* difference). The wire figure therefore wins over the Remote one during the
|
|
1991
|
+
* merge; this parser is what feeds it.
|
|
1992
|
+
*
|
|
1993
|
+
* The international (ai) gateway serves no `consumption_rate` anywhere (its
|
|
1994
|
+
* subscription models carry only `features.cost` tags), so rows without the
|
|
1995
|
+
* field keep their bare name — parsed-but-absent, never fabricated.
|
|
1996
|
+
*/
|
|
1997
|
+
function wireCreditMultiplier(config) {
|
|
1998
|
+
const raw = config["display_contact_config"];
|
|
1999
|
+
if (typeof raw !== "string" || raw === "") return void 0;
|
|
2000
|
+
let parsed;
|
|
2001
|
+
try {
|
|
2002
|
+
parsed = JSON.parse(raw);
|
|
2003
|
+
} catch {
|
|
2004
|
+
return;
|
|
2005
|
+
}
|
|
2006
|
+
if (typeof parsed !== "object" || parsed === null) return void 0;
|
|
2007
|
+
const consumption = parsed["consumption_rate"];
|
|
2008
|
+
if (typeof consumption !== "object" || consumption === null) return void 0;
|
|
2009
|
+
const entry = consumption;
|
|
2010
|
+
if (entry["enable"] !== true) return void 0;
|
|
2011
|
+
const data = entry["data"];
|
|
2012
|
+
if (typeof data !== "object" || data === null) return void 0;
|
|
2013
|
+
return finitePositive$1(data["rate"]);
|
|
2014
|
+
}
|
|
1937
2015
|
var TraeSoloUpstreamClient = class {
|
|
1938
2016
|
options;
|
|
1939
2017
|
fetchImpl;
|
|
@@ -2012,6 +2090,7 @@ var TraeSoloUpstreamClient = class {
|
|
|
2012
2090
|
...config,
|
|
2013
2091
|
...detail
|
|
2014
2092
|
});
|
|
2093
|
+
const creditMultiplier = wireCreditMultiplier(config);
|
|
2015
2094
|
if (byId.has(id)) continue;
|
|
2016
2095
|
byId.set(id, {
|
|
2017
2096
|
id,
|
|
@@ -2019,6 +2098,7 @@ var TraeSoloUpstreamClient = class {
|
|
|
2019
2098
|
...contextWindow === void 0 ? {} : { contextWindow },
|
|
2020
2099
|
...maxTokens === void 0 ? {} : { maxTokens },
|
|
2021
2100
|
...reasoning === void 0 ? {} : { reasoning },
|
|
2101
|
+
...creditMultiplier === void 0 ? {} : { creditMultiplier },
|
|
2022
2102
|
function: directoryFunction
|
|
2023
2103
|
});
|
|
2024
2104
|
}
|
|
@@ -2910,6 +2990,8 @@ function createTraeRawGateway(options) {
|
|
|
2910
2990
|
//#endregion
|
|
2911
2991
|
//#region src/model-cache.ts
|
|
2912
2992
|
const execFileAsync = promisify(execFile);
|
|
2993
|
+
/** Basename of the SQLite cache sitting beside the credential document. */
|
|
2994
|
+
const TRAE_STATE_DB_FILENAME = "state.vscdb";
|
|
2913
2995
|
function positive$1(value) {
|
|
2914
2996
|
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
|
|
2915
2997
|
}
|
|
@@ -2937,18 +3019,59 @@ function parseTraeCachedModel(value) {
|
|
|
2937
3019
|
};
|
|
2938
3020
|
}
|
|
2939
3021
|
/**
|
|
3022
|
+
* The cache paths to try, most-specific first.
|
|
3023
|
+
*
|
|
3024
|
+
* `state.vscdb` is a SIBLING of the credential document (both sit in
|
|
3025
|
+
* `globalStorage`), so a candidate's own path is the authority for its cache —
|
|
3026
|
+
* this is why the database is derived from {@link traeStorageCandidates} rather
|
|
3027
|
+
* than re-spelled here.
|
|
3028
|
+
*
|
|
3029
|
+
* It previously hardcoded the single macOS spelling `Trae CN`, which was wrong
|
|
3030
|
+
* in two ways on Windows: `paths.ts` probes `Trae CN` AND `trae-cn`, and the
|
|
3031
|
+
* edition actually installed is often SOLO (`TRAE SOLO CN`). This module would
|
|
3032
|
+
* then point at a directory that does not exist. That went unnoticed only
|
|
3033
|
+
* because the Windows `sqlite3` dependency is absent, so the lookup failed and
|
|
3034
|
+
* callers fell back — masking the wrong path behind a different error. Sharing
|
|
3035
|
+
* one path table means a spelling that works for sign-in also works for the
|
|
3036
|
+
* cache.
|
|
3037
|
+
*/
|
|
3038
|
+
function traeStateDatabaseCandidates(options = {}) {
|
|
3039
|
+
const platform = options.platform ?? process.platform;
|
|
3040
|
+
const home = options.home ?? homedir();
|
|
3041
|
+
const env = options.env ?? process.env;
|
|
3042
|
+
const paths = [];
|
|
3043
|
+
const push = (storagePath) => {
|
|
3044
|
+
const database = join(dirname(storagePath), TRAE_STATE_DB_FILENAME);
|
|
3045
|
+
if (!paths.some((existing) => existing.toLowerCase() === database.toLowerCase())) paths.push(database);
|
|
3046
|
+
};
|
|
3047
|
+
if (options.candidate !== void 0 && options.candidate.source === "desktop") push(options.candidate.path);
|
|
3048
|
+
for (const candidate of traeStorageCandidates(platform, home, env)) {
|
|
3049
|
+
if (candidate.source !== "desktop") continue;
|
|
3050
|
+
if (options.candidate !== void 0 && candidate.edition !== options.candidate.edition) continue;
|
|
3051
|
+
push(candidate.path);
|
|
3052
|
+
}
|
|
3053
|
+
return paths;
|
|
3054
|
+
}
|
|
3055
|
+
/**
|
|
2940
3056
|
* Read Trae's own current user's model map via sqlite3 without exposing
|
|
2941
3057
|
* secrets. The sqlite3 command line is a macOS prerequisite; on Windows it is
|
|
2942
3058
|
* typically absent, so the call fails and callers fall back gracefully.
|
|
3059
|
+
*
|
|
3060
|
+
* Every candidate database is tried in order and the first that EXISTS is
|
|
3061
|
+
* queried. Existence is checked before spawning because a missing file and a
|
|
3062
|
+
* missing `sqlite3` binary are different problems: choosing the wrong directory
|
|
3063
|
+
* would otherwise surface as a confusing `sqlite3` failure, hiding a path bug
|
|
3064
|
+
* behind a dependency error.
|
|
2943
3065
|
*/
|
|
2944
3066
|
async function readTraeCachedModel(functionName, modelName, userId, options = {}) {
|
|
2945
|
-
const
|
|
2946
|
-
const
|
|
2947
|
-
const
|
|
2948
|
-
|
|
3067
|
+
const exists = options.exists ?? existsSync;
|
|
3068
|
+
const databases = traeStateDatabaseCandidates(options);
|
|
3069
|
+
const fallback = databases[0];
|
|
3070
|
+
if (fallback === void 0) throw new Error("trae: no desktop storage candidate to locate the model cache from");
|
|
3071
|
+
const database = databases.find((candidate) => exists(candidate)) ?? fallback;
|
|
2949
3072
|
const key = `${userId}_AI.agent.model.model_list_map`;
|
|
2950
3073
|
const sql = `select value from ItemTable where key=${JSON.stringify(key)} limit 1;`;
|
|
2951
|
-
const { stdout } = await execFileAsync("sqlite3", [
|
|
3074
|
+
const { stdout } = await (options.runSqlite ?? ((db, statement) => execFileAsync("sqlite3", [db, statement], { maxBuffer: 8388608 })))(database, sql);
|
|
2952
3075
|
const document = JSON.parse(stdout);
|
|
2953
3076
|
return parseTraeCachedModel((Array.isArray(document[functionName]) ? document[functionName] : []).find((item) => typeof item === "object" && item !== null && item.name === modelName));
|
|
2954
3077
|
}
|
|
@@ -2960,7 +3083,7 @@ async function resolveTraeRawRuntime(store, modelName) {
|
|
|
2960
3083
|
const candidate = store.candidates().find((item) => item.edition === credential.edition);
|
|
2961
3084
|
if (candidate === void 0) throw new Error(`no Trae ${credential.edition} storage candidate for Raw Chat identity`);
|
|
2962
3085
|
const identity = await readTraeIdentity(candidate);
|
|
2963
|
-
const cached = credential.edition === "cn" ? await readTraeCachedModel("solo_agent", modelName, credential.userId).catch(() => void 0) : void 0;
|
|
3086
|
+
const cached = credential.edition === "cn" ? await readTraeCachedModel("solo_agent", modelName, credential.userId, { candidate }).catch(() => void 0) : void 0;
|
|
2964
3087
|
return {
|
|
2965
3088
|
identity,
|
|
2966
3089
|
runtime: buildTraeRawChatRuntimeConfig(modelName, cached, {
|
|
@@ -3160,6 +3283,12 @@ var TraeUsageClient = class {
|
|
|
3160
3283
|
/**
|
|
3161
3284
|
* Daily check-in status. Read-only, and answered with or without the device
|
|
3162
3285
|
* header — the claim is what needs it.
|
|
3286
|
+
*
|
|
3287
|
+
* The read DOES carry the header whenever this installation has one, and
|
|
3288
|
+
* that is deliberate rather than incidental: `did_checked_in` is answered
|
|
3289
|
+
* per device, so omitting the header would make a device that already claimed
|
|
3290
|
+
* today look identical to one that never has (measured 2026-09-26, see
|
|
3291
|
+
* {@link TraeCheckinStatus.didCheckedIn}).
|
|
3163
3292
|
*/
|
|
3164
3293
|
async checkinStatus(signal) {
|
|
3165
3294
|
await this.requireCnRegion("check-in status");
|
|
@@ -3381,6 +3510,16 @@ function nextRegionEnabled(value, region, enabled) {
|
|
|
3381
3510
|
}
|
|
3382
3511
|
//#endregion
|
|
3383
3512
|
//#region src/web-status.ts
|
|
3513
|
+
/**
|
|
3514
|
+
* The upstream's business code for "该设备今日已参与签到" — this DEVICE already
|
|
3515
|
+
* used today's check-in (measured 2026-09-26 on a CN account whose claim was
|
|
3516
|
+
* refused with exactly this code after an account switch on the same machine).
|
|
3517
|
+
*
|
|
3518
|
+
* It arrives as HTTP 200 with a non-zero `code`, which is why it has to be
|
|
3519
|
+
* matched on the code rather than on the HTTP status: read as a transport
|
|
3520
|
+
* failure it looks like the plugin is broken, when the day is simply spent.
|
|
3521
|
+
*/
|
|
3522
|
+
const CHECKIN_DEVICE_ALREADY_CLAIMED = 9095;
|
|
3384
3523
|
/** Redact token-like content before it crosses to the browser. */
|
|
3385
3524
|
function safeMessage(error) {
|
|
3386
3525
|
return (error instanceof Error ? error.message : String(error)).replace(/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/gu, "[redacted token]").replace(/(\b(?:code|token|refresh_token|access_token)=)[^&\s]+/giu, "$1[redacted]").slice(0, 500);
|
|
@@ -3577,11 +3716,22 @@ function registerTraeUsageRoute(ctx, deps) {
|
|
|
3577
3716
|
/**
|
|
3578
3717
|
* Daily check-in claim — the ONLY route in this plugin that mutates
|
|
3579
3718
|
* upstream account state, so it is guarded more tightly than its siblings:
|
|
3580
|
-
* POST only, loopback origin only, and the status read runs FIRST so
|
|
3581
|
-
* already
|
|
3582
|
-
*
|
|
3583
|
-
*
|
|
3584
|
-
*
|
|
3719
|
+
* POST only, loopback origin only, and the status read runs FIRST so a day
|
|
3720
|
+
* the ACCOUNT has already been paid for never reaches the upstream claim.
|
|
3721
|
+
*
|
|
3722
|
+
* `alreadyCheckedIn` and `deviceCheckedIn` are deliberately separate
|
|
3723
|
+
* answers, because the two flags mean different things (see
|
|
3724
|
+
* {@link TraeWebCheckin}): `checkedIn` is the account's reward for today
|
|
3725
|
+
* existing, `didCheckedIn` is this MACHINE having spent its check-in —
|
|
3726
|
+
* possibly for a different account. Treating the latter as "claimed today"
|
|
3727
|
+
* was a shipped bug: after switching accounts the card said "claimed
|
|
3728
|
+
* today" and disabled the button, which is the right call for the wrong
|
|
3729
|
+
* reason and hides that the new account was never rewarded.
|
|
3730
|
+
*
|
|
3731
|
+
* The upstream is idempotent per Beijing day (verified 2026-09-24: a
|
|
3732
|
+
* repeat claim answers `code: 0` with the entitlement total unchanged), but
|
|
3733
|
+
* relying on that for correctness would put the guard in someone else's
|
|
3734
|
+
* hands.
|
|
3585
3735
|
*/
|
|
3586
3736
|
const disposeCheckin = ctx.webServer.register({
|
|
3587
3737
|
kind: "exact",
|
|
@@ -3596,16 +3746,27 @@ function registerTraeUsageRoute(ctx, deps) {
|
|
|
3596
3746
|
const client = deps.client(region);
|
|
3597
3747
|
const current = await client.checkinStatus();
|
|
3598
3748
|
if (!current.enabled) return json(res, 409, { error: "check-in is not enabled for this account" });
|
|
3599
|
-
if (current.checkedIn
|
|
3749
|
+
if (current.checkedIn) return json(res, 200, {
|
|
3600
3750
|
claimed: false,
|
|
3601
3751
|
alreadyCheckedIn: true,
|
|
3752
|
+
deviceCheckedIn: current.didCheckedIn,
|
|
3753
|
+
checkin: toCheckin(current)
|
|
3754
|
+
});
|
|
3755
|
+
if (current.didCheckedIn) return json(res, 200, {
|
|
3756
|
+
claimed: false,
|
|
3757
|
+
alreadyCheckedIn: false,
|
|
3758
|
+
deviceCheckedIn: true,
|
|
3759
|
+
code: CHECKIN_DEVICE_ALREADY_CLAIMED,
|
|
3760
|
+
message: "this device already used today's check-in",
|
|
3602
3761
|
checkin: toCheckin(current)
|
|
3603
3762
|
});
|
|
3604
3763
|
const claim = await client.claimCheckin();
|
|
3605
3764
|
const checkin = await client.checkinStatus();
|
|
3765
|
+
const deviceClaimed = claim.code === CHECKIN_DEVICE_ALREADY_CLAIMED;
|
|
3606
3766
|
json(res, 200, {
|
|
3607
3767
|
claimed: claim.claimed,
|
|
3608
3768
|
alreadyCheckedIn: false,
|
|
3769
|
+
...deviceClaimed ? { deviceCheckedIn: true } : {},
|
|
3609
3770
|
code: claim.code,
|
|
3610
3771
|
message: claim.message,
|
|
3611
3772
|
checkin: toCheckin(checkin)
|
|
@@ -3722,6 +3883,64 @@ function buildTraeModelDetailRequest(configName = "", custom = false) {
|
|
|
3722
3883
|
};
|
|
3723
3884
|
}
|
|
3724
3885
|
//#endregion
|
|
3886
|
+
//#region src/redact.ts
|
|
3887
|
+
/**
|
|
3888
|
+
* Redaction helpers for diagnostics that a user may paste into a public issue.
|
|
3889
|
+
*
|
|
3890
|
+
* A verification report is only useful if it can be shared, and it is only safe
|
|
3891
|
+
* to share if it carries no personal identifiers. Paths are the hard case:
|
|
3892
|
+
* `C:\Users\<real name>\AppData\Roaming\Trae CN\...` contains both a real
|
|
3893
|
+
* account name AND the single most diagnostic token in the whole report (the
|
|
3894
|
+
* Trae data directory spelling). Redacting the whole path would make the report
|
|
3895
|
+
* worthless; printing it whole would leak the user's name. So the user segment
|
|
3896
|
+
* is replaced and the meaningful tail is preserved.
|
|
3897
|
+
*
|
|
3898
|
+
* @module dsh-connect-trae/redact
|
|
3899
|
+
*/
|
|
3900
|
+
/**
|
|
3901
|
+
* Replace the user segment of a path with `<user>`, keeping the rest intact.
|
|
3902
|
+
*
|
|
3903
|
+
* Handles the shapes a Trae install can produce:
|
|
3904
|
+
* - `C:\Users\<name>\...` and `C:\Documents and Settings\<name>\...` (Windows)
|
|
3905
|
+
* - `/Users/<name>/...` and `/home/<name>/...` (macOS / Linux)
|
|
3906
|
+
*
|
|
3907
|
+
* Anything after that segment — edition directory, `User\globalStorage`,
|
|
3908
|
+
* `storage.json` — is preserved verbatim, because that is what a report is
|
|
3909
|
+
* actually read for. Cross-platform on purpose: the function is called by
|
|
3910
|
+
* Windows-focused diagnostics, but the same helpers run in tests and on other
|
|
3911
|
+
* hosts, and a report from the wrong platform must not leak either.
|
|
3912
|
+
*/
|
|
3913
|
+
function maskUserPath(path) {
|
|
3914
|
+
return String(path).replace(/([A-Za-z]:\\Users\\)[^\\]+/i, "$1<user>").replace(/([A-Za-z]:\\Documents and Settings\\)[^\\]+/i, "$1<user>").replace(/^(\/(?:Users|home)\/)[^/]+/, "$1<user>");
|
|
3915
|
+
}
|
|
3916
|
+
/**
|
|
3917
|
+
* Describe a name by shape instead of by value: a character count, plus whether
|
|
3918
|
+
* it is purely numeric.
|
|
3919
|
+
*
|
|
3920
|
+
* This is the deliberate middle ground for account names. A Trae account name
|
|
3921
|
+
* is often a real name or a phone number, so it must never be printed; but the
|
|
3922
|
+
* report still needs to show that an account WAS resolved, and the shape
|
|
3923
|
+
* distinguishes a real nickname from a generated `用户<n>` id — which is the
|
|
3924
|
+
* only thing a reader needs to judge whether account discovery worked.
|
|
3925
|
+
*/
|
|
3926
|
+
function describeNameShape(name) {
|
|
3927
|
+
const text = String(name ?? "");
|
|
3928
|
+
return `${text.length} 字符${/^\d+$/.test(text) ? ",纯数字" : ""}`;
|
|
3929
|
+
}
|
|
3930
|
+
/**
|
|
3931
|
+
* Describe an identifier by shape instead of by value.
|
|
3932
|
+
*
|
|
3933
|
+
* A device id (`x-device-id`) is a stable installation identifier and is
|
|
3934
|
+
* directly tied to the upstream's per-device rules, so it is never printed.
|
|
3935
|
+
* Its shape still proves which resolution path ran: a real `icube-dc` id is
|
|
3936
|
+
* 15 digits, while the fallback is a 32-character hex hash.
|
|
3937
|
+
*/
|
|
3938
|
+
function describeIdShape(value) {
|
|
3939
|
+
const text = String(value ?? "");
|
|
3940
|
+
if (text === "") return "(空)";
|
|
3941
|
+
return `${text.length} 位${/^\d+$/.test(text) ? ",纯数字" : ",含非数字"}`;
|
|
3942
|
+
}
|
|
3943
|
+
//#endregion
|
|
3725
3944
|
//#region src/raw-envelope.ts
|
|
3726
3945
|
/** Stable JSON hash candidate used by the native DTO's arg/args_hash fields. */
|
|
3727
3946
|
function hashTraeRawChatArg(arg) {
|
|
@@ -3761,14 +3980,34 @@ const name = "dsh-connect-trae";
|
|
|
3761
3980
|
const inject = ["llm"];
|
|
3762
3981
|
/**
|
|
3763
3982
|
* Settings namespace, as a plain lowercase literal. DSH 0.1.2 removed the
|
|
3764
|
-
* `settingsNamespace` brand constructor from the npm package
|
|
3765
|
-
*
|
|
3766
|
-
*
|
|
3767
|
-
*
|
|
3768
|
-
*
|
|
3983
|
+
* `settingsNamespace` brand constructor from the npm package, and every
|
|
3984
|
+
* consumer of this constant takes it as a kebab string — so no branding is
|
|
3985
|
+
* needed. It is the FALLBACK namespace; the namespace the host actually serves
|
|
3986
|
+
* comes from {@link settingsNamespaceOf} (0.1.7 keys settings by the Loader
|
|
3987
|
+
* entry id, which a profile patch may mount as `dsh-connect-trae` or
|
|
3988
|
+
* `include:dsh-connect-trae`).
|
|
3769
3989
|
*/
|
|
3770
3990
|
const TRAE_SETTINGS_NS = "trae";
|
|
3771
3991
|
/**
|
|
3992
|
+
* The namespace the HOST actually serves this plugin under.
|
|
3993
|
+
*
|
|
3994
|
+
* On DSH 0.1.7 `SettingsForms.describe()` keys every namespace by the Loader
|
|
3995
|
+
* entry id, and the harness looks a provider's namespace up by EXACT match —
|
|
3996
|
+
* advertising `trae` while the host serves `include:dsh-connect-trae` made the
|
|
3997
|
+
* provider read as "not configured": its configure affordance and model
|
|
3998
|
+
* discovery both silently went dead.
|
|
3999
|
+
*
|
|
4000
|
+
* `ctx.fiber.entry` is added by the Loader, not by Cordis itself, so it is not
|
|
4001
|
+
* in Cordis's public types and is absent on hosts that mount a plugin without a
|
|
4002
|
+
* Loader entry (a test harness, or `ctx.plugin()` called directly). Hence the
|
|
4003
|
+
* probe plus the documented fallback, mirroring the first-party plugins:
|
|
4004
|
+
* `const settingsNs = ctx.fiber.entry?.options.id ?? NS`.
|
|
4005
|
+
*/
|
|
4006
|
+
function settingsNamespaceOf(ctx) {
|
|
4007
|
+
const id = ctx?.fiber?.entry?.options?.id;
|
|
4008
|
+
return typeof id === "string" && id !== "" ? id : TRAE_SETTINGS_NS;
|
|
4009
|
+
}
|
|
4010
|
+
/**
|
|
3772
4011
|
* One region's saved state. A config written before the region split has only
|
|
3773
4012
|
* the flat fields: those were always captured from the CN endpoint (the
|
|
3774
4013
|
* plugin had no international support), so they are read as the CN state and
|
|
@@ -3800,23 +4039,18 @@ function regionEnabled(config, region) {
|
|
|
3800
4039
|
return regionStateOf(config, region).enabled !== false;
|
|
3801
4040
|
}
|
|
3802
4041
|
/**
|
|
3803
|
-
* Mark a schema's field as volatile
|
|
4042
|
+
* Mark a schema's field as volatile.
|
|
3804
4043
|
*
|
|
3805
|
-
* `volatile()` exists from schemastery 3.18.3
|
|
3806
|
-
*
|
|
3807
|
-
*
|
|
3808
|
-
*
|
|
3809
|
-
* bypass schemastery's own `validateVolatileSchema`
|
|
3810
|
-
*
|
|
3811
|
-
* no-op.
|
|
4044
|
+
* `volatile()` exists from schemastery 3.18.3; since 2.3.0 the peer range
|
|
4045
|
+
* requires `>=3.18.4`, so it is always present on a supported host. The probe
|
|
4046
|
+
* is kept as a safety net for a consumer that resolves an older schemastery
|
|
4047
|
+
* anyway (where the helper must degrade to identity — hand-writing
|
|
4048
|
+
* `meta.volatile = true` would bypass schemastery's own `validateVolatileSchema`
|
|
4049
|
+
* checks) and to keep both arms deterministically testable.
|
|
3812
4050
|
*
|
|
3813
4051
|
* Without the marker, 0.1.7's settings write gate REJECTS every write with
|
|
3814
4052
|
* `Plugin entry "trae" has no volatile fields` while the scope's `set()` still
|
|
3815
4053
|
* resolves — so the card would look like it saved and silently revert.
|
|
3816
|
-
*
|
|
3817
|
-
* Exported so BOTH arms are testable on any machine: the capability is decided
|
|
3818
|
-
* by whichever schemastery the dependency tree resolves, so without a seam the
|
|
3819
|
-
* no-op arm would silently stop being exercised the moment the pin moved up.
|
|
3820
4054
|
*/
|
|
3821
4055
|
function asVolatile(schema) {
|
|
3822
4056
|
if (typeof schema.volatile === "function") return schema.volatile();
|
|
@@ -3863,6 +4097,7 @@ const Config = z.object({
|
|
|
3863
4097
|
/** Every region, in card tab order. */
|
|
3864
4098
|
const REGION_KEYS = ["cn", "ai"];
|
|
3865
4099
|
function apply(ctx, config) {
|
|
4100
|
+
const settingsNs = settingsNamespaceOf(ctx);
|
|
3866
4101
|
let current = () => config;
|
|
3867
4102
|
const enabledSet = (value, region) => new Set(regionStateOf(value, region).enabledModelIds ?? []);
|
|
3868
4103
|
const imageSet = (value, region) => new Set(regionStateOf(value, region).imageModelIds ?? []);
|
|
@@ -4100,7 +4335,7 @@ function apply(ctx, config) {
|
|
|
4100
4335
|
registration.cn.directory?.replace(REGION_KEYS.filter((region) => regionEnabled(value, region)).map((region) => ({
|
|
4101
4336
|
provider: TRAE_PROVIDERS[region],
|
|
4102
4337
|
displayName: TRAE_PROVIDER_DISPLAY_NAMES[region],
|
|
4103
|
-
settingsNs
|
|
4338
|
+
settingsNs,
|
|
4104
4339
|
settingsPath: [],
|
|
4105
4340
|
declared: false
|
|
4106
4341
|
})));
|
|
@@ -4115,14 +4350,6 @@ function apply(ctx, config) {
|
|
|
4115
4350
|
}
|
|
4116
4351
|
syncRegionRegistration(value);
|
|
4117
4352
|
};
|
|
4118
|
-
const sectionHooks = {
|
|
4119
|
-
setSource(source) {
|
|
4120
|
-
current = source;
|
|
4121
|
-
},
|
|
4122
|
-
onChange() {
|
|
4123
|
-
applySelection(current());
|
|
4124
|
-
}
|
|
4125
|
-
};
|
|
4126
4353
|
applySelection(config);
|
|
4127
4354
|
(async () => {
|
|
4128
4355
|
const id = current().accountId;
|
|
@@ -4135,18 +4362,9 @@ function apply(ctx, config) {
|
|
|
4135
4362
|
}
|
|
4136
4363
|
} catch {}
|
|
4137
4364
|
})();
|
|
4138
|
-
|
|
4139
|
-
if (typeof legacyInstallSettingsSection === "function") legacyInstallSettingsSection(ctx, TRAE_SETTINGS_NS, Config, config, sectionHooks);
|
|
4140
|
-
else ctx.inject(["settings"], (settingsCtx) => {
|
|
4365
|
+
ctx.inject(["settings"], (settingsCtx) => {
|
|
4141
4366
|
const settings = settingsCtx.settings;
|
|
4142
|
-
|
|
4143
|
-
settings.configure({ auto: true }, ctx.fiber);
|
|
4144
|
-
return;
|
|
4145
|
-
}
|
|
4146
|
-
if (typeof settings.installSection === "function") {
|
|
4147
|
-
const entry = unwrapVolatileDeep(config);
|
|
4148
|
-
settings.installSection(ctx, TRAE_SETTINGS_NS, Config, entry, sectionHooks);
|
|
4149
|
-
}
|
|
4367
|
+
ctx.effect(() => settings.configure({ auto: true }, ctx.fiber));
|
|
4150
4368
|
});
|
|
4151
4369
|
ctx.on("loader/volatile-update", () => {
|
|
4152
4370
|
applySelection(current());
|
|
@@ -4173,7 +4391,7 @@ function apply(ctx, config) {
|
|
|
4173
4391
|
};
|
|
4174
4392
|
registration[region].adapter = region === "cn" ? ctx.llm.registerAdapter([TRAE_PROVIDER], trae.adapter) : ctx.llm.registerAdapter([TRAE_AI_PROVIDER], trae.adapter);
|
|
4175
4393
|
}
|
|
4176
|
-
ctx.llm.registerModelDiscovery(
|
|
4394
|
+
ctx.llm.registerModelDiscovery(settingsNs, async (request, signal) => {
|
|
4177
4395
|
const region = regionOfTraeProvider(request.provider ?? "");
|
|
4178
4396
|
if (region === void 0) return [];
|
|
4179
4397
|
if (!regionEnabled(current(), region)) return [];
|
|
@@ -4189,7 +4407,7 @@ function apply(ctx, config) {
|
|
|
4189
4407
|
registration.cn.directory = ctx.llm.registerConfigurableProviders(REGION_KEYS.map((region) => ({
|
|
4190
4408
|
provider: TRAE_PROVIDERS[region],
|
|
4191
4409
|
displayName: TRAE_PROVIDER_DISPLAY_NAMES[region],
|
|
4192
|
-
settingsNs
|
|
4410
|
+
settingsNs,
|
|
4193
4411
|
settingsPath: [],
|
|
4194
4412
|
declared: false
|
|
4195
4413
|
})));
|
|
@@ -4232,4 +4450,4 @@ function apply(ctx, config) {
|
|
|
4232
4450
|
});
|
|
4233
4451
|
}
|
|
4234
4452
|
//#endregion
|
|
4235
|
-
export { Config, FALLBACK_TRAE_MODELS, FALLBACK_TRAE_MODELS_AI, REGION_GATEWAYS, SseDecoder, TRAE_AI_PROVIDER, TRAE_CHECKIN_PATH, TRAE_CN_AGENT_TASK_PATH, TRAE_CN_TITLE_PATH, TRAE_MODEL_DETAIL_FUNCTIONS, TRAE_MODEL_DETAIL_PATH, TRAE_PAY_BASE, TRAE_PROVIDER, TRAE_PROVIDERS, TRAE_PROVIDER_DISPLAY_NAMES, TRAE_RAW_CHAT_V1_PATH, TRAE_RAW_CHAT_V2_PATH, TRAE_REASONING_EFFORTS, TRAE_REGIONS, TRAE_REGION_PARAM, TRAE_SETTINGS_NS, TRAE_SOLO_CHAT_PATH, TRAE_SOLO_FUNCTION, TRAE_SOLO_MODELS_PATH, TRAE_SOLO_REMOTE_BASE, TRAE_STREAM_IDLE_TIMEOUT_MS, TRAE_USAGE_PATH, TRAE_VERSION_CODE_FALLBACK, TraeCatalog, TraeCredentialStore, TraeDelegatingUpstreamClient, TraeFallbackUpstreamClient, TraeGatedUpstreamClient, TraeRawCapabilityController, TraeRawCapabilityState, TraeRawChatUpstreamClient, TraeSoloBridge, TraeSoloRemoteCatalogClient, TraeSoloUpstreamClient, TraeUsageClient, UnconfiguredTraeUpstreamClient, apply, applyContextBudgets, applyImageSelection, applyReasoningEffort, asVolatile, bridgeTraeSoloStream, buildTraeAgentTaskBody, buildTraeCnHeaders, buildTraeFusionRawChatEnvelope, buildTraeModelDetailRequest, buildTraeRawChatDraft, buildTraeRawChatRuntimeConfig, classifyTraeRawChatFailure, createTraeAdapter, createTraeRawGateway, createTraeShim, decodeRawChatChunk, decodeTraeEvent, decryptTraeStorageValue, deriveCatalog, discoveredCatalog, fallbackModelsFor, hashTraeRawChatArg, identityHeaders, inject, legacyTraeOwnAuthPath, mergeTraeModelSources, name, nextRegionEnabled, nextRegionSlots, normalizeTraeCredential, normalizeTraeVersionCode, parseObservedModelConfig, parseReasoningCapability, parseTraeAuthValue, parseTraeCachedModel, parseTraeModelExtraConfigLogLine, parseTraeRawChatBehaviorConfig, parseTraeRemoteModel, parseTraeStorageDocument, pickTraeStorageIdentity, prepareSoloBody, probeTraeRawChatCapability, rawCapabilityDiagnostic, rawCapabilityFingerprint, readTraeCachedModel, readTraeCliIdentity, readTraeIdentity, refreshTraeCredential, regionEnabled, regionEnabledOf, regionOfCredential, regionOfEdition, regionOfHost, regionOfTraeProvider, regionOfTraeStatusUrl, regionOfUserRegion, regionStateOf, registerTraeUsageRoute, resolveTraeIdentity, resolveTraeRawRuntime, sanitizeCatalog, traeEndpoint, traeInputModalities, traeModelDisplayName, traeOwnAuthPath, traeRawChatExtraInfo, traeStorageCandidates, traeWebUsage, unwrapVolatile, unwrapVolatileDeep, withTraeRegion };
|
|
4453
|
+
export { Config, FALLBACK_TRAE_MODELS, FALLBACK_TRAE_MODELS_AI, REGION_GATEWAYS, SseDecoder, TRAE_AI_PROVIDER, TRAE_CHECKIN_PATH, TRAE_CN_AGENT_TASK_PATH, TRAE_CN_TITLE_PATH, TRAE_MODEL_DETAIL_FUNCTIONS, TRAE_MODEL_DETAIL_PATH, TRAE_PAY_BASE, TRAE_PROVIDER, TRAE_PROVIDERS, TRAE_PROVIDER_DISPLAY_NAMES, TRAE_RAW_CHAT_V1_PATH, TRAE_RAW_CHAT_V2_PATH, TRAE_REASONING_EFFORTS, TRAE_REGIONS, TRAE_REGION_PARAM, TRAE_SETTINGS_NS, TRAE_SOLO_CHAT_PATH, TRAE_SOLO_FUNCTION, TRAE_SOLO_MODELS_PATH, TRAE_SOLO_REMOTE_BASE, TRAE_STATE_DB_FILENAME, TRAE_STREAM_IDLE_TIMEOUT_MS, TRAE_USAGE_PATH, TRAE_VERSION_CODE_FALLBACK, TraeCatalog, TraeCredentialStore, TraeDelegatingUpstreamClient, TraeFallbackUpstreamClient, TraeGatedUpstreamClient, TraeRawCapabilityController, TraeRawCapabilityState, TraeRawChatUpstreamClient, TraeSoloBridge, TraeSoloRemoteCatalogClient, TraeSoloUpstreamClient, TraeUsageClient, UnconfiguredTraeUpstreamClient, apply, applyContextBudgets, applyImageSelection, applyReasoningEffort, asVolatile, bridgeTraeSoloStream, buildTraeAgentTaskBody, buildTraeCnHeaders, buildTraeFusionRawChatEnvelope, buildTraeModelDetailRequest, buildTraeRawChatDraft, buildTraeRawChatRuntimeConfig, classifyTraeRawChatFailure, createTraeAdapter, createTraeRawGateway, createTraeShim, decodeRawChatChunk, decodeTraeEvent, decryptTraeStorageValue, deriveCatalog, describeIdShape, describeNameShape, discoveredCatalog, fallbackModelsFor, hashTraeRawChatArg, identityHeaders, inject, legacyTraeOwnAuthPath, maskUserPath, mergeTraeModelSources, name, nextRegionEnabled, nextRegionSlots, normalizeTraeCredential, normalizeTraeVersionCode, parseObservedModelConfig, parseReasoningCapability, parseTraeAuthValue, parseTraeCachedModel, parseTraeModelExtraConfigLogLine, parseTraeRawChatBehaviorConfig, parseTraeRemoteModel, parseTraeStorageDocument, pickTraeStorageIdentity, prepareSoloBody, probeTraeRawChatCapability, rawCapabilityDiagnostic, rawCapabilityFingerprint, readTraeCachedModel, readTraeCliIdentity, readTraeIdentity, refreshTraeCredential, regionEnabled, regionEnabledOf, regionOfCredential, regionOfEdition, regionOfHost, regionOfTraeProvider, regionOfTraeStatusUrl, regionOfUserRegion, regionStateOf, registerTraeUsageRoute, resolveTraeIdentity, resolveTraeRawRuntime, sanitizeCatalog, settingsNamespaceOf, traeEndpoint, traeInputModalities, traeModelDisplayName, traeOwnAuthPath, traeRawChatExtraInfo, traeStateDatabaseCandidates, traeStorageCandidates, traeWebUsage, traeWindowsAppNames, unwrapVolatile, unwrapVolatileDeep, withTraeRegion };
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-connect-trae",
|
|
3
3
|
"displayName": "DSH Connect Trae",
|
|
4
|
-
"description": "
|
|
5
|
-
"version": "2.
|
|
4
|
+
"description": "把本机登录的 Trae 模型接入 DeepSeek Harness:国内版与国际版双供应商并行,提供用量/积分概览与每日签到领取。",
|
|
5
|
+
"version": "2.3.1",
|
|
6
6
|
"author": "dingminhua",
|
|
7
7
|
"copyright": "Copyright (c) 2026 LaoDing",
|
|
8
8
|
"license": "MIT",
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
},
|
|
21
21
|
"main": "lib/index.js",
|
|
22
22
|
"types": "lib/index.d.ts",
|
|
23
|
+
"icon": "icons/dsh-connect-trae-128.png",
|
|
23
24
|
"exports": {
|
|
24
25
|
".": {
|
|
25
26
|
"types": "./lib/index.d.ts",
|
|
@@ -31,7 +32,9 @@
|
|
|
31
32
|
},
|
|
32
33
|
"files": [
|
|
33
34
|
"lib",
|
|
35
|
+
"icons",
|
|
34
36
|
"docs/assets/dsh-connect-trae-usage-card.png",
|
|
37
|
+
"scripts/verify-windows.mjs",
|
|
35
38
|
"screenshots.json",
|
|
36
39
|
"cordis.patch.yml",
|
|
37
40
|
"README.md",
|
|
@@ -72,34 +75,34 @@
|
|
|
72
75
|
"url": "https://github.com/dingminhua/dsh-connect-trae/issues"
|
|
73
76
|
},
|
|
74
77
|
"peerDependencies": {
|
|
75
|
-
"@deepseek-ai/cordis": "
|
|
76
|
-
"@deepseek-ai/dsh-atomic-write": ">=0.1.
|
|
77
|
-
"@deepseek-ai/dsh-attachment": ">=0.1.
|
|
78
|
-
"@deepseek-ai/dsh-client-ui-primitives": ">=0.1.
|
|
79
|
-
"@deepseek-ai/dsh-home-paths": ">=0.1.
|
|
80
|
-
"@deepseek-ai/dsh-host-webserver": ">=0.1.
|
|
81
|
-
"@deepseek-ai/dsh-llm": ">=0.1.
|
|
82
|
-
"@deepseek-ai/dsh-llm-pi-ai": ">=0.1.
|
|
83
|
-
"@deepseek-ai/dsh-settings": ">=0.1.
|
|
84
|
-
"@deepseek-ai/schemastery": "
|
|
78
|
+
"@deepseek-ai/cordis": ">=4.0.4 <5.0.0",
|
|
79
|
+
"@deepseek-ai/dsh-atomic-write": ">=0.1.7-rc.1 <0.2.0-0",
|
|
80
|
+
"@deepseek-ai/dsh-attachment": ">=0.1.7-rc.1 <0.2.0-0",
|
|
81
|
+
"@deepseek-ai/dsh-client-ui-primitives": ">=0.1.7-rc.1 <0.2.0-0",
|
|
82
|
+
"@deepseek-ai/dsh-home-paths": ">=0.1.7-rc.1 <0.2.0-0",
|
|
83
|
+
"@deepseek-ai/dsh-host-webserver": ">=0.1.7-rc.1 <0.2.0-0",
|
|
84
|
+
"@deepseek-ai/dsh-llm": ">=0.1.7-rc.1 <0.2.0-0",
|
|
85
|
+
"@deepseek-ai/dsh-llm-pi-ai": ">=0.1.7-rc.1 <0.2.0-0",
|
|
86
|
+
"@deepseek-ai/dsh-settings": ">=0.1.7-rc.1 <0.2.0-0",
|
|
87
|
+
"@deepseek-ai/schemastery": ">=3.18.4 <4.0.0",
|
|
85
88
|
"@earendil-works/pi-ai": ">=0.85.1",
|
|
86
89
|
"react": "^18.2.0"
|
|
87
90
|
},
|
|
88
91
|
"devDependencies": {
|
|
89
|
-
"@deepseek-ai/cordis": "^4.0.
|
|
90
|
-
"@deepseek-ai/dsh-atomic-write": "0.1.
|
|
91
|
-
"@deepseek-ai/dsh-attachment": "0.1.
|
|
92
|
-
"@deepseek-ai/dsh-client-locale": "0.1.
|
|
93
|
-
"@deepseek-ai/dsh-client-ui-primitives": "0.1.
|
|
94
|
-
"@deepseek-ai/dsh-client-ui-renderer": "0.1.
|
|
95
|
-
"@deepseek-ai/dsh-client-ui-settings": "0.1.
|
|
96
|
-
"@deepseek-ai/dsh-client-ui-settings-plugins": "0.1.
|
|
97
|
-
"@deepseek-ai/dsh-client-ui-slots": "0.1.
|
|
98
|
-
"@deepseek-ai/dsh-home-paths": "0.1.
|
|
99
|
-
"@deepseek-ai/dsh-host-webserver": "0.1.
|
|
100
|
-
"@deepseek-ai/dsh-llm": "0.1.
|
|
101
|
-
"@deepseek-ai/dsh-llm-pi-ai": "0.1.
|
|
102
|
-
"@deepseek-ai/dsh-settings": "0.1.
|
|
92
|
+
"@deepseek-ai/cordis": "^4.0.4",
|
|
93
|
+
"@deepseek-ai/dsh-atomic-write": "0.1.7-rc.1",
|
|
94
|
+
"@deepseek-ai/dsh-attachment": "0.1.7-rc.1",
|
|
95
|
+
"@deepseek-ai/dsh-client-locale": "0.1.7-rc.1",
|
|
96
|
+
"@deepseek-ai/dsh-client-ui-primitives": "0.1.7-rc.1",
|
|
97
|
+
"@deepseek-ai/dsh-client-ui-renderer": "0.1.7-rc.1",
|
|
98
|
+
"@deepseek-ai/dsh-client-ui-settings": "0.1.7-rc.1",
|
|
99
|
+
"@deepseek-ai/dsh-client-ui-settings-plugins": "0.1.7-rc.1",
|
|
100
|
+
"@deepseek-ai/dsh-client-ui-slots": "0.1.7-rc.1",
|
|
101
|
+
"@deepseek-ai/dsh-home-paths": "0.1.7-rc.1",
|
|
102
|
+
"@deepseek-ai/dsh-host-webserver": "0.1.7-rc.1",
|
|
103
|
+
"@deepseek-ai/dsh-llm": "0.1.7-rc.1",
|
|
104
|
+
"@deepseek-ai/dsh-llm-pi-ai": "0.1.7-rc.1",
|
|
105
|
+
"@deepseek-ai/dsh-settings": "0.1.7-rc.1",
|
|
103
106
|
"@deepseek-ai/schemastery": "3.18.4",
|
|
104
107
|
"@earendil-works/pi-ai": "^0.85.1",
|
|
105
108
|
"@testing-library/dom": "^10.4.2",
|