dsh-connect-trae 2.3.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/lib/index.d.ts CHANGED
@@ -46,6 +46,15 @@ interface TraeStorageCandidate {
46
46
  path: string;
47
47
  source: TraeCredentialSource;
48
48
  }
49
+ /**
50
+ * One edition's plausible Windows directory spellings, in probe order.
51
+ *
52
+ * Exported so the identity reader and the credential scanner probe the SAME
53
+ * names: the two resolve different files (the install's `product.json` vs the
54
+ * per-user `storage.json`) but they describe one installation, and a spelling
55
+ * that works for one but not the other is a bug rather than a preference.
56
+ */
57
+ declare function traeWindowsAppNames(edition: TraeEdition): readonly string[];
49
58
  declare function traeStorageCandidates(platform?: NodeJS.Platform, home?: string, env?: NodeJS.ProcessEnv): TraeStorageCandidate[];
50
59
  //#endregion
51
60
  //#region src/region.d.ts
@@ -576,6 +585,8 @@ interface TraeObservedModelConfig {
576
585
  declare function parseObservedModelConfig(line: string): TraeObservedModelConfig | undefined;
577
586
  //#endregion
578
587
  //#region src/model-cache.d.ts
588
+ /** Basename of the SQLite cache sitting beside the credential document. */
589
+ declare const TRAE_STATE_DB_FILENAME = "state.vscdb";
579
590
  interface TraeCachedModelConfig {
580
591
  name: string;
581
592
  customConfig?: Record<string, unknown>;
@@ -594,11 +605,54 @@ interface TraeCachedModelReadOptions {
594
605
  home?: string;
595
606
  /** Environment override for testing; defaults to process.env. */
596
607
  env?: NodeJS.ProcessEnv;
608
+ /**
609
+ * The credential candidate whose account is being read. Supplying it pins the
610
+ * lookup to the installation the credential actually came from, which is the
611
+ * only way to stay correct when several editions are installed: `storage.json`
612
+ * and `state.vscdb` live in the SAME `globalStorage` directory, so the cache
613
+ * belongs to whichever candidate yielded the sign-in.
614
+ */
615
+ candidate?: TraeStorageCandidate;
616
+ /** Injectable for tests; defaults to node:fs existsSync. */
617
+ exists?: (path: string) => boolean;
618
+ /**
619
+ * Injectable `sqlite3` runner for tests; defaults to promisified `execFile`.
620
+ * Mirrors the `fetchImpl` injection used elsewhere in this plugin, and exists
621
+ * so a test can assert the exact argv — in particular WHICH database path was
622
+ * chosen, which no assertion on the candidate list alone can prove.
623
+ */
624
+ runSqlite?: (database: string, sql: string) => Promise<{
625
+ stdout: string;
626
+ }>;
597
627
  }
628
+ /**
629
+ * The cache paths to try, most-specific first.
630
+ *
631
+ * `state.vscdb` is a SIBLING of the credential document (both sit in
632
+ * `globalStorage`), so a candidate's own path is the authority for its cache —
633
+ * this is why the database is derived from {@link traeStorageCandidates} rather
634
+ * than re-spelled here.
635
+ *
636
+ * It previously hardcoded the single macOS spelling `Trae CN`, which was wrong
637
+ * in two ways on Windows: `paths.ts` probes `Trae CN` AND `trae-cn`, and the
638
+ * edition actually installed is often SOLO (`TRAE SOLO CN`). This module would
639
+ * then point at a directory that does not exist. That went unnoticed only
640
+ * because the Windows `sqlite3` dependency is absent, so the lookup failed and
641
+ * callers fell back — masking the wrong path behind a different error. Sharing
642
+ * one path table means a spelling that works for sign-in also works for the
643
+ * cache.
644
+ */
645
+ declare function traeStateDatabaseCandidates(options?: TraeCachedModelReadOptions): string[];
598
646
  /**
599
647
  * Read Trae's own current user's model map via sqlite3 without exposing
600
648
  * secrets. The sqlite3 command line is a macOS prerequisite; on Windows it is
601
649
  * typically absent, so the call fails and callers fall back gracefully.
650
+ *
651
+ * Every candidate database is tried in order and the first that EXISTS is
652
+ * queried. Existence is checked before spawning because a missing file and a
653
+ * missing `sqlite3` binary are different problems: choosing the wrong directory
654
+ * would otherwise surface as a confusing `sqlite3` failure, hiding a path bug
655
+ * behind a dependency error.
602
656
  */
603
657
  declare function readTraeCachedModel(functionName: string, modelName: string, userId: string, options?: TraeCachedModelReadOptions): Promise<TraeCachedModelConfig | undefined>;
604
658
  //#endregion
@@ -634,6 +688,55 @@ interface TraeModelDetailRequest {
634
688
  /** Build the exact request shape observed in successful current Trae CN logs. */
635
689
  declare function buildTraeModelDetailRequest(configName?: string, custom?: boolean): TraeModelDetailRequest;
636
690
  //#endregion
691
+ //#region src/redact.d.ts
692
+ /**
693
+ * Redaction helpers for diagnostics that a user may paste into a public issue.
694
+ *
695
+ * A verification report is only useful if it can be shared, and it is only safe
696
+ * to share if it carries no personal identifiers. Paths are the hard case:
697
+ * `C:\Users\<real name>\AppData\Roaming\Trae CN\...` contains both a real
698
+ * account name AND the single most diagnostic token in the whole report (the
699
+ * Trae data directory spelling). Redacting the whole path would make the report
700
+ * worthless; printing it whole would leak the user's name. So the user segment
701
+ * is replaced and the meaningful tail is preserved.
702
+ *
703
+ * @module dsh-connect-trae/redact
704
+ */
705
+ /**
706
+ * Replace the user segment of a path with `<user>`, keeping the rest intact.
707
+ *
708
+ * Handles the shapes a Trae install can produce:
709
+ * - `C:\Users\<name>\...` and `C:\Documents and Settings\<name>\...` (Windows)
710
+ * - `/Users/<name>/...` and `/home/<name>/...` (macOS / Linux)
711
+ *
712
+ * Anything after that segment — edition directory, `User\globalStorage`,
713
+ * `storage.json` — is preserved verbatim, because that is what a report is
714
+ * actually read for. Cross-platform on purpose: the function is called by
715
+ * Windows-focused diagnostics, but the same helpers run in tests and on other
716
+ * hosts, and a report from the wrong platform must not leak either.
717
+ */
718
+ declare function maskUserPath(path: string): string;
719
+ /**
720
+ * Describe a name by shape instead of by value: a character count, plus whether
721
+ * it is purely numeric.
722
+ *
723
+ * This is the deliberate middle ground for account names. A Trae account name
724
+ * is often a real name or a phone number, so it must never be printed; but the
725
+ * report still needs to show that an account WAS resolved, and the shape
726
+ * distinguishes a real nickname from a generated `用户<n>` id — which is the
727
+ * only thing a reader needs to judge whether account discovery worked.
728
+ */
729
+ declare function describeNameShape(name: unknown): string;
730
+ /**
731
+ * Describe an identifier by shape instead of by value.
732
+ *
733
+ * A device id (`x-device-id`) is a stable installation identifier and is
734
+ * directly tied to the upstream's per-device rules, so it is never printed.
735
+ * Its shape still proves which resolution path ran: a real `icube-dc` id is
736
+ * 15 digits, while the fallback is a 32-character hex hash.
737
+ */
738
+ declare function describeIdShape(value: unknown): string;
739
+ //#endregion
637
740
  //#region src/protocol.d.ts
638
741
  declare const TRAE_CN_AGENT_TASK_PATH = "/api/agent/v3/create_agent_task";
639
742
  declare const TRAE_CN_TITLE_PATH = "/api/agent/v3/llm_utils_chat";
@@ -1239,15 +1342,32 @@ interface TraeUsageSnapshot {
1239
1342
  packs: TraeUsagePack[];
1240
1343
  }
1241
1344
  interface TraeCheckinStatus {
1345
+ /**
1346
+ * Whether the account's REWARD PACK for today already exists. This is the
1347
+ * account-wide answer and it is the one that decides whether there is
1348
+ * anything left to claim: a day with `checkedIn: true` has already been paid
1349
+ * out, whichever device produced it.
1350
+ */
1242
1351
  checkedIn: boolean;
1243
1352
  /** Reward for one check-in, as reported by the upstream (`credits`). */
1244
1353
  credits: number;
1245
1354
  enabled: boolean;
1246
1355
  /**
1247
- * Whether today's reward was claimed in a previous session. The upstream
1248
- * reports `did_checked_in` separately from `checked_in`: the app uses the
1249
- * former to keep the claim button disabled for the rest of the Beijing day
1250
- * even when the status read happens to report `checked_in: false`.
1356
+ * Whether THIS device's claim for today was already recorded. The upstream
1357
+ * keys this on the `x-device-id` the request carries — not on the account —
1358
+ * so it answers `true` for the device that claimed and `false` for the same
1359
+ * account and day read from any other device.
1360
+ *
1361
+ * Measured 2026-09-26 on a live CN account whose claim had succeeded minutes
1362
+ * earlier: `did_checked_in` was `true` with the claiming device id and
1363
+ * `false` with the header omitted, with a synthetic id, and with another
1364
+ * install's id. Repeating the read never flips it, so it is not "have I seen
1365
+ * you before" state either — only an actual claim sets it.
1366
+ *
1367
+ * It is therefore NOT a "today is done" signal on its own (claiming again
1368
+ * answers the upstream's own 9095 "该设备今日已参与签到" refusal); it is
1369
+ * evidence that this exact device is already accounted for, which is what
1370
+ * makes a claim safe to skip.
1251
1371
  */
1252
1372
  didCheckedIn: boolean;
1253
1373
  /** Bonus credit granted on top of the base reward, when the upstream reports one. */
@@ -1323,6 +1443,12 @@ declare class TraeUsageClient {
1323
1443
  /**
1324
1444
  * Daily check-in status. Read-only, and answered with or without the device
1325
1445
  * header — the claim is what needs it.
1446
+ *
1447
+ * The read DOES carry the header whenever this installation has one, and
1448
+ * that is deliberate rather than incidental: `did_checked_in` is answered
1449
+ * per device, so omitting the header would make a device that already claimed
1450
+ * today look identical to one that never has (measured 2026-09-26, see
1451
+ * {@link TraeCheckinStatus.didCheckedIn}).
1326
1452
  */
1327
1453
  checkinStatus(signal?: AbortSignal): Promise<TraeCheckinStatus>;
1328
1454
  /**
@@ -1402,11 +1528,22 @@ interface TraeWebModel {
1402
1528
  /**
1403
1529
  * Daily check-in state rendered below the credit stats.
1404
1530
  *
1405
- * `didCheckedIn` is not redundant with `checkedIn`: the upstream reports them
1406
- * separately, and the official client keeps the claim button disabled for the
1407
- * rest of the Beijing day off `did_checked_in` even when a status read comes
1408
- * back `checked_in: false`. The card mirrors that rule so a stale-looking
1409
- * status cannot invite a pointless second claim.
1531
+ * The two booleans answer DIFFERENT questions and must never be collapsed into
1532
+ * one "done" flag — doing that was a shipped bug (see CHANGELOG 2.3.1):
1533
+ *
1534
+ * - `checkedIn` is ACCOUNT-level: today's reward pack exists for this account,
1535
+ * so there is nothing left to claim and the balance already includes it.
1536
+ * - `didCheckedIn` is DEVICE-level: this MACHINE already spent its one
1537
+ * check-in for the day, whichever account spent it. The upstream keys it on
1538
+ * the `x-device-id` in the request and answers it per device, not per
1539
+ * account (measured 2026-09-26: the same account and Beijing day answered
1540
+ * `false` with the header omitted, with a synthetic id, and with another
1541
+ * install's id, and `true` for the device that actually claimed).
1542
+ *
1543
+ * So `didCheckedIn && !checkedIn` is the "switched account" case: the device's
1544
+ * daily check-in is used up, but THIS account was never rewarded. Claiming
1545
+ * again is refused upstream (business code 9095, "该设备今日已参与签到"), so
1546
+ * the card disables the button — but it must say that, not "claimed today".
1410
1547
  */
1411
1548
  interface TraeWebCheckin {
1412
1549
  checkedIn: boolean;
@@ -1419,8 +1556,19 @@ interface TraeWebCheckin {
1419
1556
  interface TraeWebCheckinClaim {
1420
1557
  /** False when the upstream answered a non-zero business code (e.g. 9004). */
1421
1558
  claimed: boolean;
1422
- /** True when today was already claimed, so nothing was sent upstream. */
1559
+ /**
1560
+ * True only when THIS ACCOUNT's reward for today already exists, so nothing
1561
+ * was sent upstream. Distinct from {@link TraeWebCheckinClaim.deviceCheckedIn}:
1562
+ * a device that already claimed for another account leaves this false.
1563
+ */
1423
1564
  alreadyCheckedIn: boolean;
1565
+ /**
1566
+ * True when today's check-in was already spent on this DEVICE (by this or
1567
+ * another account), so no claim was sent or the upstream refused it with
1568
+ * 9095. Not an error: it is the truthful answer to "can this account claim
1569
+ * here today?" — no, and the reason is the machine, not the account.
1570
+ */
1571
+ deviceCheckedIn?: boolean;
1424
1572
  code?: number;
1425
1573
  message?: string;
1426
1574
  /** The refreshed check-in state, present whenever the claim path ran. */
@@ -1731,4 +1879,4 @@ declare function asVolatile<S>(schema: S): S;
1731
1879
  declare const Config: z<Config>;
1732
1880
  declare function apply(ctx: Context, config: Config): void;
1733
1881
  //#endregion
1734
- export { Config, FALLBACK_TRAE_MODELS, FALLBACK_TRAE_MODELS_AI, REGION_GATEWAYS, type RawChatDelta, type RawChatMessage, type RawChatTool, SseDecoder, type SseEvent, 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, type TraeActivityRule, type TraeAdapter, type TraeCachedModelConfig, TraeCatalog, type TraeChatResult, type TraeCheckinClaim, type TraeCheckinStatus, type TraeContextBudget, type TraeCredential, TraeCredentialStore, TraeDelegatingUpstreamClient, type TraeDiscoveredModel, type TraeDiscoveredReasoning, type TraeEdition, TraeFallbackUpstreamClient, type TraeFallbackUpstreamOptions, type TraeFusionRawChatEnvelope, TraeGatedUpstreamClient, type TraeGatedUpstreamOptions, type TraeIdentity, type TraeInputModality, type TraeModelDetailRequest, type TraeModelInfo, type TraeObservedModelConfig, TraeRawCapabilityController, type TraeRawCapabilityControllerOptions, type TraeRawCapabilitySnapshot, TraeRawCapabilityState, type TraeRawChatBehaviorConfig, type TraeRawChatCapability, type TraeRawChatClientOptions, type TraeRawChatConfig, type TraeRawChatFailureReason, type TraeRawChatRuntimeConfig, TraeRawChatUpstreamClient, type TraeRawDiagnostic, type TraeRawDiagnosticState, type TraeRawGateway, type TraeRawGatewayOptions, type TraeRawResolverResult, type TraeReasoningCapability, type TraeReasoningEffort, type TraeRefreshDevice, type TraeRegion, type TraeRegionGateways, TraeRegionState, type TraeShim, TraeSoloBridge, type TraeSoloClientOptions, TraeSoloRemoteCatalogClient, type TraeSoloRemoteCatalogOptions, TraeSoloUpstreamClient, type TraeStorageCandidate, type TraeStreamEvent, type TraeUpstreamClient, TraeUsageClient, type TraeUsageOptions, type TraeUsagePack, type TraeUsageRouteOptions, type TraeUsageSnapshot, type TraeUsageSummary, type TraeUsageView, type TraeWebActivity, type TraeWebCheckin, type TraeWebCheckinClaim, type TraeWebCredits, type TraeWebUsage, type TraeWireModel, 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, settingsNamespaceOf, traeEndpoint, traeInputModalities, traeModelDisplayName, traeOwnAuthPath, traeRawChatExtraInfo, traeStorageCandidates, traeWebUsage, unwrapVolatile, unwrapVolatileDeep, withTraeRegion };
1882
+ export { Config, FALLBACK_TRAE_MODELS, FALLBACK_TRAE_MODELS_AI, REGION_GATEWAYS, type RawChatDelta, type RawChatMessage, type RawChatTool, SseDecoder, type SseEvent, 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, type TraeActivityRule, type TraeAdapter, type TraeCachedModelConfig, TraeCatalog, type TraeChatResult, type TraeCheckinClaim, type TraeCheckinStatus, type TraeContextBudget, type TraeCredential, TraeCredentialStore, TraeDelegatingUpstreamClient, type TraeDiscoveredModel, type TraeDiscoveredReasoning, type TraeEdition, TraeFallbackUpstreamClient, type TraeFallbackUpstreamOptions, type TraeFusionRawChatEnvelope, TraeGatedUpstreamClient, type TraeGatedUpstreamOptions, type TraeIdentity, type TraeInputModality, type TraeModelDetailRequest, type TraeModelInfo, type TraeObservedModelConfig, TraeRawCapabilityController, type TraeRawCapabilityControllerOptions, type TraeRawCapabilitySnapshot, TraeRawCapabilityState, type TraeRawChatBehaviorConfig, type TraeRawChatCapability, type TraeRawChatClientOptions, type TraeRawChatConfig, type TraeRawChatFailureReason, type TraeRawChatRuntimeConfig, TraeRawChatUpstreamClient, type TraeRawDiagnostic, type TraeRawDiagnosticState, type TraeRawGateway, type TraeRawGatewayOptions, type TraeRawResolverResult, type TraeReasoningCapability, type TraeReasoningEffort, type TraeRefreshDevice, type TraeRegion, type TraeRegionGateways, TraeRegionState, type TraeShim, TraeSoloBridge, type TraeSoloClientOptions, TraeSoloRemoteCatalogClient, type TraeSoloRemoteCatalogOptions, TraeSoloUpstreamClient, type TraeStorageCandidate, type TraeStreamEvent, type TraeUpstreamClient, TraeUsageClient, type TraeUsageOptions, type TraeUsagePack, type TraeUsageRouteOptions, type TraeUsageSnapshot, type TraeUsageSummary, type TraeUsageView, type TraeWebActivity, type TraeWebCheckin, type TraeWebCheckinClaim, type TraeWebCredits, type TraeWebUsage, type TraeWireModel, 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/lib/index.js CHANGED
@@ -13,6 +13,7 @@ import { createServer } from "node:http";
13
13
  import { Readable } from "node:stream";
14
14
  import { execFile } from "node:child_process";
15
15
  import { promisify } from "node:util";
16
+ import { existsSync } from "node:fs";
16
17
  //#region src/catalog.ts
17
18
  /**
18
19
  * Bootstrap catalog: identity only where current Trae metadata has not been
@@ -800,6 +801,43 @@ const LINUX_APP_NAMES = {
800
801
  solo: ["trae-solo-cn", "TRAE SOLO CN"],
801
802
  "solo-sg": ["trae-solo", "TRAE SOLO"]
802
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
+ }
803
841
  function traeStorageCandidates(platform = process.platform, home = homedir(), env = process.env) {
804
842
  const result = [];
805
843
  for (const edition of [
@@ -816,7 +854,7 @@ function traeStorageCandidates(platform = process.platform, home = homedir(), en
816
854
  appNames = [app];
817
855
  } else if (platform === "win32") {
818
856
  roots = [env.APPDATA, join(home, "AppData", "Roaming")].filter((value, index, all) => typeof value === "string" && value !== "" && all.indexOf(value) === index);
819
- appNames = [app];
857
+ appNames = WINDOWS_APP_NAMES[edition];
820
858
  } else if (platform === "linux") {
821
859
  roots = [env.XDG_CONFIG_HOME || join(home, ".config")];
822
860
  appNames = LINUX_APP_NAMES[edition];
@@ -1402,7 +1440,7 @@ async function readTraeIdentity(candidate, options = {}) {
1402
1440
  if (platform === "darwin") productPaths.push(join("/Applications", `${appName}.app`, "Contents", "Resources", "app", "product.json"));
1403
1441
  else {
1404
1442
  const localRoots = [env.LOCALAPPDATA, join(home, "AppData", "Local")].filter((value) => typeof value === "string" && value !== "").filter((value, index, all) => all.indexOf(value) === index);
1405
- for (const root of localRoots) productPaths.push(join(root, "Programs", appName, "resources", "app", "product.json"));
1443
+ for (const root of localRoots) for (const spelling of traeWindowsAppNames(candidate.edition)) productPaths.push(join(root, "Programs", spelling, "resources", "app", "product.json"));
1406
1444
  }
1407
1445
  }
1408
1446
  let product = {};
@@ -2952,6 +2990,8 @@ function createTraeRawGateway(options) {
2952
2990
  //#endregion
2953
2991
  //#region src/model-cache.ts
2954
2992
  const execFileAsync = promisify(execFile);
2993
+ /** Basename of the SQLite cache sitting beside the credential document. */
2994
+ const TRAE_STATE_DB_FILENAME = "state.vscdb";
2955
2995
  function positive$1(value) {
2956
2996
  return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
2957
2997
  }
@@ -2979,18 +3019,59 @@ function parseTraeCachedModel(value) {
2979
3019
  };
2980
3020
  }
2981
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
+ /**
2982
3056
  * Read Trae's own current user's model map via sqlite3 without exposing
2983
3057
  * secrets. The sqlite3 command line is a macOS prerequisite; on Windows it is
2984
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.
2985
3065
  */
2986
3066
  async function readTraeCachedModel(functionName, modelName, userId, options = {}) {
2987
- const platform = options.platform ?? process.platform;
2988
- const home = options.home ?? homedir();
2989
- const env = options.env ?? process.env;
2990
- const database = platform === "win32" ? join(env.APPDATA ?? join(home, "AppData", "Roaming"), "Trae CN", "User", "globalStorage", "state.vscdb") : join(home, "Library", "Application Support", "Trae CN", "User", "globalStorage", "state.vscdb");
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;
2991
3072
  const key = `${userId}_AI.agent.model.model_list_map`;
2992
3073
  const sql = `select value from ItemTable where key=${JSON.stringify(key)} limit 1;`;
2993
- const { stdout } = await execFileAsync("sqlite3", [database, sql], { maxBuffer: 8388608 });
3074
+ const { stdout } = await (options.runSqlite ?? ((db, statement) => execFileAsync("sqlite3", [db, statement], { maxBuffer: 8388608 })))(database, sql);
2994
3075
  const document = JSON.parse(stdout);
2995
3076
  return parseTraeCachedModel((Array.isArray(document[functionName]) ? document[functionName] : []).find((item) => typeof item === "object" && item !== null && item.name === modelName));
2996
3077
  }
@@ -3002,7 +3083,7 @@ async function resolveTraeRawRuntime(store, modelName) {
3002
3083
  const candidate = store.candidates().find((item) => item.edition === credential.edition);
3003
3084
  if (candidate === void 0) throw new Error(`no Trae ${credential.edition} storage candidate for Raw Chat identity`);
3004
3085
  const identity = await readTraeIdentity(candidate);
3005
- 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;
3006
3087
  return {
3007
3088
  identity,
3008
3089
  runtime: buildTraeRawChatRuntimeConfig(modelName, cached, {
@@ -3202,6 +3283,12 @@ var TraeUsageClient = class {
3202
3283
  /**
3203
3284
  * Daily check-in status. Read-only, and answered with or without the device
3204
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}).
3205
3292
  */
3206
3293
  async checkinStatus(signal) {
3207
3294
  await this.requireCnRegion("check-in status");
@@ -3423,6 +3510,16 @@ function nextRegionEnabled(value, region, enabled) {
3423
3510
  }
3424
3511
  //#endregion
3425
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;
3426
3523
  /** Redact token-like content before it crosses to the browser. */
3427
3524
  function safeMessage(error) {
3428
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);
@@ -3619,11 +3716,22 @@ function registerTraeUsageRoute(ctx, deps) {
3619
3716
  /**
3620
3717
  * Daily check-in claim — the ONLY route in this plugin that mutates
3621
3718
  * upstream account state, so it is guarded more tightly than its siblings:
3622
- * POST only, loopback origin only, and the status read runs FIRST so an
3623
- * already-claimed day never reaches the upstream claim at all. The upstream
3624
- * is idempotent per Beijing day anyway (verified 2026-09-24: a repeat claim
3625
- * answers `code: 0` with the entitlement total unchanged), but relying on
3626
- * that for correctness would put the guard in someone else's hands.
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.
3627
3735
  */
3628
3736
  const disposeCheckin = ctx.webServer.register({
3629
3737
  kind: "exact",
@@ -3638,16 +3746,27 @@ function registerTraeUsageRoute(ctx, deps) {
3638
3746
  const client = deps.client(region);
3639
3747
  const current = await client.checkinStatus();
3640
3748
  if (!current.enabled) return json(res, 409, { error: "check-in is not enabled for this account" });
3641
- if (current.checkedIn || current.didCheckedIn) return json(res, 200, {
3749
+ if (current.checkedIn) return json(res, 200, {
3642
3750
  claimed: false,
3643
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",
3644
3761
  checkin: toCheckin(current)
3645
3762
  });
3646
3763
  const claim = await client.claimCheckin();
3647
3764
  const checkin = await client.checkinStatus();
3765
+ const deviceClaimed = claim.code === CHECKIN_DEVICE_ALREADY_CLAIMED;
3648
3766
  json(res, 200, {
3649
3767
  claimed: claim.claimed,
3650
3768
  alreadyCheckedIn: false,
3769
+ ...deviceClaimed ? { deviceCheckedIn: true } : {},
3651
3770
  code: claim.code,
3652
3771
  message: claim.message,
3653
3772
  checkin: toCheckin(checkin)
@@ -3764,6 +3883,64 @@ function buildTraeModelDetailRequest(configName = "", custom = false) {
3764
3883
  };
3765
3884
  }
3766
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
3767
3944
  //#region src/raw-envelope.ts
3768
3945
  /** Stable JSON hash candidate used by the native DTO's arg/args_hash fields. */
3769
3946
  function hashTraeRawChatArg(arg) {
@@ -4273,4 +4450,4 @@ function apply(ctx, config) {
4273
4450
  });
4274
4451
  }
4275
4452
  //#endregion
4276
- 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, settingsNamespaceOf, 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": "Connect locally signed-in Trae models to DeepSeek Harness, with a usage/credits summary and daily check-in claiming.",
5
- "version": "2.3.0",
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",
@@ -34,6 +34,7 @@
34
34
  "lib",
35
35
  "icons",
36
36
  "docs/assets/dsh-connect-trae-usage-card.png",
37
+ "scripts/verify-windows.mjs",
37
38
  "screenshots.json",
38
39
  "cordis.patch.yml",
39
40
  "README.md",