tokentracker-cli 0.93.3 → 0.93.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/dashboard/dist/assets/{AchievementBadge-Bl3bWjZw.js → AchievementBadge-BcNvxrVM.js} +1 -1
- package/dashboard/dist/assets/{AchievementsPage-B6FrDjg8.js → AchievementsPage-DhipQygJ.js} +2 -2
- package/dashboard/dist/assets/{AchievementsSection-D5TJtcI5.js → AchievementsSection-BJyb_mIr.js} +1 -1
- package/dashboard/dist/assets/{BadgeDetailModal-BFlrt34z.js → BadgeDetailModal-CoZv7o6t.js} +1 -1
- package/dashboard/dist/assets/{BotAnimated-KONFZbQT.js → BotAnimated-eVBNtvcG.js} +1 -1
- package/dashboard/dist/assets/{Card-DDZHhXlQ.js → Card-BEfG2im9.js} +1 -1
- package/dashboard/dist/assets/{ClawdAnimated-DMw54QJ_.js → ClawdAnimated-C-30t4dC.js} +2 -2
- package/dashboard/dist/assets/{CommandPalette-CxVv0uo_.js → CommandPalette-DF-TGB1C.js} +1 -1
- package/dashboard/dist/assets/{CommunityStatsModal-CR2MuFo3.js → CommunityStatsModal-D-0eI3Pz.js} +1 -1
- package/dashboard/dist/assets/{ConfirmModal-B-jvLsxn.js → ConfirmModal-BQ7Aor1C.js} +1 -1
- package/dashboard/dist/assets/{Controls-DXA3Zxx0.js → Controls-COThRtMS.js} +1 -1
- package/dashboard/dist/assets/{DashboardPage-0jQPu59U.js → DashboardPage-Ci_Gb5I1.js} +1 -1
- package/dashboard/dist/assets/{DevicePage-CMR7jT8-.js → DevicePage-BmlmimUg.js} +1 -1
- package/dashboard/dist/assets/{DialogClose-B1j73B1g.js → DialogClose-BdALEZzc.js} +1 -1
- package/dashboard/dist/assets/DialogDescription-DAKoQCEv.js +1 -0
- package/dashboard/dist/assets/{DialogTitle-eIgptOU-.js → DialogTitle-F6W1aTiE.js} +1 -1
- package/dashboard/dist/assets/{FadeIn-B8aisUg4.js → FadeIn-S2d3D28d.js} +1 -1
- package/dashboard/dist/assets/{HeaderGithubStar-B7MEGODn.js → HeaderGithubStar-DBBwOwc_.js} +1 -1
- package/dashboard/dist/assets/{HoverTooltip-DfBzMfW7.js → HoverTooltip-rLWQC9Va.js} +1 -1
- package/dashboard/dist/assets/{IpCheckPage-BBvSL0Zz.js → IpCheckPage-BpPoAIry.js} +1 -1
- package/dashboard/dist/assets/{LandingPage-CcX03ndP.js → LandingPage-BUm_ZMew.js} +2 -2
- package/dashboard/dist/assets/{LeaderboardAvatar-Dk4UJx-j.js → LeaderboardAvatar-DQxbOYZb.js} +1 -1
- package/dashboard/dist/assets/{LeaderboardPage-CcIp7sjv.js → LeaderboardPage-DzLrFQm8.js} +2 -2
- package/dashboard/dist/assets/{LeaderboardProfileModal-DzXfmNhy.js → LeaderboardProfileModal-Cq4B8Les.js} +3 -3
- package/dashboard/dist/assets/{LeaderboardProfilePage-18ijOFN-.js → LeaderboardProfilePage-C-Xj65xf.js} +1 -1
- package/dashboard/dist/assets/{LimitsPage-ZeRD1J97.js → LimitsPage-Bjcmr0bd.js} +1 -1
- package/dashboard/dist/assets/{LocalOnlyNotice-DQ_wPyho.js → LocalOnlyNotice-9mWINkVj.js} +1 -1
- package/dashboard/dist/assets/{LoginCard-DX5-Bxhr.js → LoginCard-BlKleF8M.js} +1 -1
- package/dashboard/dist/assets/{LoginModal-_Rt3qUyK.js → LoginModal-BUYa13hj.js} +1 -1
- package/dashboard/dist/assets/{LoginPage-CvYcDpeR.js → LoginPage-DbQhApOd.js} +1 -1
- package/dashboard/dist/assets/{PetPage-D0D4mRwd.js → PetPage-DuAf3OOf.js} +1 -1
- package/dashboard/dist/assets/{PopoverPopup-Bz3yRvv6.js → PopoverPopup-CG76MkbK.js} +1 -1
- package/dashboard/dist/assets/{ProviderIcon-PauvxgNb.js → ProviderIcon-N7OTtgte.js} +1 -1
- package/dashboard/dist/assets/{ResetPasswordPage-BiC1Us4d.js → ResetPasswordPage-D48--1wC.js} +1 -1
- package/dashboard/dist/assets/{SegmentedControl-bW8MsUDI.js → SegmentedControl-zRvbFqyY.js} +1 -1
- package/dashboard/dist/assets/{Select-BSpIj6-K.js → Select-Bi3B21Fb.js} +1 -1
- package/dashboard/dist/assets/{SelectItemText-taYIkVIw.js → SelectItemText-Bg8I618N.js} +1 -1
- package/dashboard/dist/assets/{ServiceStatusPage-GMkqBtrt.js → ServiceStatusPage-CeeYx4XY.js} +1 -1
- package/dashboard/dist/assets/{SessionsPage-QydYL4yt.js → SessionsPage-CZF3qLEm.js} +1 -1
- package/dashboard/dist/assets/{SettingsPage-BFvCcos0.js → SettingsPage-D2wa8i5u.js} +2 -2
- package/dashboard/dist/assets/{SkillsPage-CKci6NM2.js → SkillsPage-OxW2w6up.js} +1 -1
- package/dashboard/dist/assets/{TokenGalaxy-DMof07_u.js → TokenGalaxy-DmtP_r86.js} +1 -1
- package/dashboard/dist/assets/{ToolbarRootContext-CAsiI0PJ.js → ToolbarRootContext-DC6BLLoO.js} +1 -1
- package/dashboard/dist/assets/{TrendMonitor-Dj2Uxs9x.js → TrendMonitor-OvvLCD3K.js} +1 -1
- package/dashboard/dist/assets/{WidgetsPage-DOr-nMn1.js → WidgetsPage-DhOC8rae.js} +1 -1
- package/dashboard/dist/assets/{WrappedPage-BZUv1rX5.js → WrappedPage-C0boSobK.js} +1 -1
- package/dashboard/dist/assets/{__vite-browser-external-WKiEWJ30.js → __vite-browser-external-D_dICEUB.js} +2 -2
- package/dashboard/dist/assets/{agent-logos-1FaE1SqE.js → agent-logos-Dzyq5cDh.js} +1 -1
- package/dashboard/dist/assets/{arrow-up-right-Bs5oicPH.js → arrow-up-right-DrLfm7Vy.js} +1 -1
- package/dashboard/dist/assets/{check-Be2PwUMS.js → check-DAsdH-MF.js} +1 -1
- package/dashboard/dist/assets/{chevron-right-DH93vlVo.js → chevron-right-CdSgby9-.js} +1 -1
- package/dashboard/dist/assets/{copy-xOLhiaQa.js → copy-TuVoW7qK.js} +1 -1
- package/dashboard/dist/assets/{download-qUjPQH7V.js → download-BZ61xuhi.js} +1 -1
- package/dashboard/dist/assets/{external-link-D0nLaYYu.js → external-link-DJrRSKF9.js} +1 -1
- package/dashboard/dist/assets/{flame-DFEEnwot.js → flame-9JS9yMju.js} +1 -1
- package/dashboard/dist/assets/{format-tokens-BPq1moPg.js → format-tokens-Blp6lI_n.js} +1 -1
- package/dashboard/dist/assets/{icons-DxM91e9c.js → icons-CbF0cL6i.js} +1 -1
- package/dashboard/dist/assets/{index-BEi52jGG.js → index-Bu3I2hmd.js} +1 -1
- package/dashboard/dist/assets/{index-CEl88_eC.js → index-FnWiMfqV.js} +1 -1
- package/dashboard/dist/assets/{index-C8Sb5l3M.js → index-I81NzV7H.js} +1 -1
- package/dashboard/dist/assets/{info-C43iVFmY.js → info-B_iryt84.js} +1 -1
- package/dashboard/dist/assets/{limits-providers-xNF55jgX.js → limits-providers-Cli4pkKC.js} +1 -1
- package/dashboard/dist/assets/{link-2-CfarpF4W.js → link-2-pB3-7Waa.js} +1 -1
- package/dashboard/dist/assets/{loader-circle-CIKyaEoN.js → loader-circle-DivA-LsF.js} +1 -1
- package/dashboard/dist/assets/{maximize-2-DlTJ_PyX.js → maximize-2-WNMF5NUU.js} +1 -1
- package/dashboard/dist/assets/{modifiers.esm-CXV6l89k.js → modifiers.esm-BaJJxzf2.js} +1 -1
- package/dashboard/dist/assets/{monitor-smartphone-6dCO7HCP.js → monitor-smartphone-pAR3IHow.js} +1 -1
- package/dashboard/dist/assets/{provider-display-DNEUispM.js → provider-display-CyYhYVar.js} +1 -1
- package/dashboard/dist/assets/{react-us685QUG.js → react-BldsIPA1.js} +1 -1
- package/dashboard/dist/assets/{search-NcbnjXYq.js → search-xIfdCEo0.js} +1 -1
- package/dashboard/dist/assets/{skills-api-CFSZ441M.js → skills-api-DZNsCHPo.js} +1 -1
- package/dashboard/dist/assets/{sortable.esm-DiFLdkJ7.js → sortable.esm-DMaj448G.js} +1 -1
- package/dashboard/dist/assets/{store-B-d1Nz34.js → store-VTEegajU.js} +1 -1
- package/dashboard/dist/assets/{terminal-D3L94ngT.js → terminal-Bj8SotRv.js} +1 -1
- package/dashboard/dist/assets/{trash-2-esrIc05L.js → trash-2-CWgY_FBc.js} +1 -1
- package/dashboard/dist/assets/{use-community-stats-C4nPlCzJ.js → use-community-stats-BOVvh_Gv.js} +1 -1
- package/dashboard/dist/assets/{use-limits-display-prefs-iXm2ziaO.js → use-limits-display-prefs-MtLsQ5kN.js} +1 -1
- package/dashboard/dist/assets/{use-ordered-list-DU8WcVsn.js → use-ordered-list-DjCZVinv.js} +1 -1
- package/dashboard/dist/assets/use-reduced-motion-DjWNXuSi.js +1 -0
- package/dashboard/dist/assets/{use-session-efficiency-pref-CpGicS2y.js → use-session-efficiency-pref-DASihY0W.js} +1 -1
- package/dashboard/dist/assets/{use-transform-WxJRtugr.js → use-transform-tHlm2id8.js} +1 -1
- package/dashboard/dist/assets/{use-usage-limits-55w4KAqE.js → use-usage-limits-BBEHNJKl.js} +1 -1
- package/dashboard/dist/assets/{useCurrency-C6HKlFA6.js → useCurrency-DgTCDMXb.js} +1 -1
- package/dashboard/dist/assets/{useScrollLock-CZ1Na38Y.js → useScrollLock-C3TFkbz0.js} +1 -1
- package/dashboard/dist/assets/{useTokenFormat-BR7kJQ6x.js → useTokenFormat-BtqPANfZ.js} +1 -1
- package/dashboard/dist/assets/{zap-BcwbN9j5.js → zap-CJNTZ87b.js} +1 -1
- package/dashboard/dist/index.html +1 -1
- package/dashboard/dist/ip-check.html +1 -1
- package/dashboard/dist/leaderboard.html +1 -1
- package/dashboard/dist/share.html +1 -1
- package/package.json +1 -1
- package/src/commands/status.js +3 -3
- package/src/lib/opencode-go-limits.js +74 -27
- package/src/lib/pricing/seed-snapshot.json +1 -1
- package/src/lib/rollout.js +187 -28
- package/src/lib/trae-cn-config.js +11 -2
- package/dashboard/dist/assets/DialogDescription-ZS29ikF4.js +0 -1
- package/dashboard/dist/assets/use-reduced-motion-DDhy4yg_.js +0 -1
package/src/lib/rollout.js
CHANGED
|
@@ -2698,7 +2698,8 @@ async function parseOpencodeMessageFile({
|
|
|
2698
2698
|
};
|
|
2699
2699
|
}
|
|
2700
2700
|
|
|
2701
|
-
const
|
|
2701
|
+
const { modelId: fileModelId } = normalizeOpencodeModelFields(msg);
|
|
2702
|
+
const model = fileModelId || DEFAULT_MODEL;
|
|
2702
2703
|
const bucket = getHourlyBucket(hourlyState, source, model, bucketStart);
|
|
2703
2704
|
addTotals(bucket.totals, delta);
|
|
2704
2705
|
touchedBuckets.add(bucketKey(source, model, bucketStart));
|
|
@@ -3289,8 +3290,11 @@ function deriveOpencodeMessageFingerprint({ msg, totals, source }) {
|
|
|
3289
3290
|
const created = coerceEpochMs(msg?.time?.created) || 0;
|
|
3290
3291
|
const completed = coerceEpochMs(msg?.time?.completed) || 0;
|
|
3291
3292
|
if (!created && !completed) return null;
|
|
3292
|
-
|
|
3293
|
-
|
|
3293
|
+
// v1 keeps flat modelID/providerID strings; v2 nests them in
|
|
3294
|
+
// `model: { id, providerID }` — normalize both (see normalizeOpencodeModelFields).
|
|
3295
|
+
const { modelId, providerId } = normalizeOpencodeModelFields(msg);
|
|
3296
|
+
const model = modelId || DEFAULT_MODEL;
|
|
3297
|
+
const provider = providerId;
|
|
3294
3298
|
const raw = [
|
|
3295
3299
|
normalizeSourceInput(source) || "opencode",
|
|
3296
3300
|
created,
|
|
@@ -3402,7 +3406,8 @@ function repairCountedOpencodeForkCopy({
|
|
|
3402
3406
|
if (!timestampMs) return false;
|
|
3403
3407
|
const bucketStart = toUtcHalfHourStart(new Date(timestampMs).toISOString());
|
|
3404
3408
|
if (!bucketStart) return false;
|
|
3405
|
-
const
|
|
3409
|
+
const { modelId: repairModelId } = normalizeOpencodeModelFields(msg);
|
|
3410
|
+
const model = repairModelId || DEFAULT_MODEL;
|
|
3406
3411
|
const counted = { ...totals, conversation_count: 1 };
|
|
3407
3412
|
const bucket = getHourlyBucket(hourlyState, source, model, bucketStart);
|
|
3408
3413
|
subtractTotals(bucket.totals, counted);
|
|
@@ -3635,6 +3640,33 @@ function normalizeModelInput(value) {
|
|
|
3635
3640
|
return trimmed.length > 0 ? trimmed : null;
|
|
3636
3641
|
}
|
|
3637
3642
|
|
|
3643
|
+
// OpenCode v1 stores the model as flat strings on every assistant message
|
|
3644
|
+
// (`modelID`, `providerID`), while OpenCode v2 (the `opencode2` beta, which
|
|
3645
|
+
// moved messages into the `session_message` table) nests them inside a single
|
|
3646
|
+
// object: `model: { id, providerID, variant }`. Some forks also wrote a plain
|
|
3647
|
+
// string into `model`. Resolve both shapes to { modelId, providerId } so
|
|
3648
|
+
// bucket keys and fork fingerprints stay identical across versions.
|
|
3649
|
+
function normalizeOpencodeModelFields(msg) {
|
|
3650
|
+
const directModel =
|
|
3651
|
+
normalizeModelInput(msg?.modelID) ||
|
|
3652
|
+
normalizeModelInput(typeof msg?.model === "string" ? msg.model : null) ||
|
|
3653
|
+
normalizeModelInput(msg?.modelId);
|
|
3654
|
+
if (directModel) {
|
|
3655
|
+
return {
|
|
3656
|
+
modelId: directModel,
|
|
3657
|
+
providerId: normalizeMessageKeyPart(msg?.providerID || msg?.provider || msg?.providerId),
|
|
3658
|
+
};
|
|
3659
|
+
}
|
|
3660
|
+
const nested = msg?.model;
|
|
3661
|
+
if (nested && typeof nested === "object") {
|
|
3662
|
+
return {
|
|
3663
|
+
modelId: normalizeModelInput(nested.id),
|
|
3664
|
+
providerId: normalizeMessageKeyPart(nested.providerID),
|
|
3665
|
+
};
|
|
3666
|
+
}
|
|
3667
|
+
return { modelId: null, providerId: "" };
|
|
3668
|
+
}
|
|
3669
|
+
|
|
3638
3670
|
async function resolveProjectMetaForPath(startDir, cache) {
|
|
3639
3671
|
if (!startDir || typeof startDir !== "string") return null;
|
|
3640
3672
|
if (cache && cache.has(startDir)) return cache.get(startDir);
|
|
@@ -4298,12 +4330,79 @@ async function walkOpencodeMessages(dir, out) {
|
|
|
4298
4330
|
}
|
|
4299
4331
|
|
|
4300
4332
|
// ---------------------------------------------------------------------------
|
|
4301
|
-
// OpenCode SQLite DB reader
|
|
4333
|
+
// OpenCode SQLite DB reader
|
|
4334
|
+
//
|
|
4335
|
+
// Four real database shapes exist in the wild (see PR #501 / opencode2):
|
|
4336
|
+
// A pure v1: `message`(data) + `session_message`(empty) [+ `session`]
|
|
4337
|
+
// B beta-17887: `session_message`(data) + `session_v2`
|
|
4338
|
+
// C upstream v2: `session_message`(data) + `session`
|
|
4339
|
+
// D transitional: `message`(old data) + `session_message`(new data)
|
|
4340
|
+
//
|
|
4341
|
+
// The reader must serve all four without firing a doomed SQL at type A (an
|
|
4342
|
+
// empty `session_message` table still EXISTS — querying it with a JOIN against
|
|
4343
|
+
// `session_v2` that does not exist throws "no such table" every sync, and the
|
|
4344
|
+
// old code silently swallowed that error). The combined probe below answers
|
|
4345
|
+
// both "is there v2 data?" and "which session table exists?" in one round-trip.
|
|
4302
4346
|
// ---------------------------------------------------------------------------
|
|
4303
4347
|
|
|
4348
|
+
const OPENCODE_DB_V1_MESSAGE_SQL =
|
|
4349
|
+
`SELECT id, session_id, time_updated, data FROM message ` +
|
|
4350
|
+
`WHERE json_extract(data, '$.role') = 'assistant' ORDER BY time_created ASC`;
|
|
4351
|
+
|
|
4352
|
+
// Build the v2 query. When a session table exists the LEFT JOIN restores the
|
|
4353
|
+
// project directory for downstream attribution; when it does not (type B
|
|
4354
|
+
// without session_v2, or an exotic fork) the join and directory column are
|
|
4355
|
+
// omitted and tokens are counted as-is.
|
|
4356
|
+
function buildV2Sql(sessionTable) {
|
|
4357
|
+
const joinClause = sessionTable
|
|
4358
|
+
? `LEFT JOIN ${sessionTable} s ON s.id = sm.session_id `
|
|
4359
|
+
: "";
|
|
4360
|
+
const directorySelect = sessionTable
|
|
4361
|
+
? `s.directory AS directory, `
|
|
4362
|
+
: "";
|
|
4363
|
+
return (
|
|
4364
|
+
`SELECT sm.id AS id, sm.session_id AS session_id, sm.time_updated AS time_updated, ` +
|
|
4365
|
+
`${directorySelect}sm.data AS data ` +
|
|
4366
|
+
`FROM session_message sm ${joinClause}` +
|
|
4367
|
+
`WHERE sm.type = 'assistant' ORDER BY sm.time_created ASC`
|
|
4368
|
+
);
|
|
4369
|
+
}
|
|
4370
|
+
|
|
4371
|
+
// One combined probe: hasRows (is there any data in session_message?) plus
|
|
4372
|
+
// sessionTable (which session table exists, session_v2 preferred over session
|
|
4373
|
+
// via DESC). Returns null when the probe itself fails — callers treat that as
|
|
4374
|
+
// v1-only, matching the pre-existing silent-degradation contract.
|
|
4375
|
+
function detectOpencodeMessageLayout(dbPath, sqliteOptions = {}) {
|
|
4376
|
+
let rows;
|
|
4377
|
+
try {
|
|
4378
|
+
rows = readSqliteJsonRows(
|
|
4379
|
+
dbPath,
|
|
4380
|
+
`SELECT (SELECT 1 FROM session_message LIMIT 1) AS hasRows,
|
|
4381
|
+
(SELECT name FROM sqlite_master WHERE name IN ('session','session_v2') ORDER BY name DESC LIMIT 1) AS sessionTable`,
|
|
4382
|
+
{ label: "OpenCode", timeout: 10_000, maxBuffer: 1024 * 1024, ...sqliteOptions },
|
|
4383
|
+
);
|
|
4384
|
+
} catch (_e) {
|
|
4385
|
+
return null;
|
|
4386
|
+
}
|
|
4387
|
+
if (!Array.isArray(rows) || rows.length === 0) return null;
|
|
4388
|
+
const row = rows[0];
|
|
4389
|
+
return {
|
|
4390
|
+
hasRows: Boolean(row?.hasRows),
|
|
4391
|
+
sessionTable: typeof row?.sessionTable === "string" && row.sessionTable.trim()
|
|
4392
|
+
? row.sessionTable.trim()
|
|
4393
|
+
: null,
|
|
4394
|
+
};
|
|
4395
|
+
}
|
|
4396
|
+
|
|
4397
|
+
// Shared provider resolver: v1 rows carry a top-level providerID, v2 rows nest
|
|
4398
|
+
// it under model.providerID. Used by the mimo/zcode discriminators so they work
|
|
4399
|
+
// against both generations without duplicating the resolution logic.
|
|
4400
|
+
function opencodeMessageProvider(data) {
|
|
4401
|
+
return data?.providerID || data?.model?.providerID || "";
|
|
4402
|
+
}
|
|
4403
|
+
|
|
4304
4404
|
function readOpencodeDbMessages(dbPath, sqliteOptions = {}) {
|
|
4305
4405
|
if (!dbPath || !fssync.existsSync(dbPath)) return [];
|
|
4306
|
-
const sql = `SELECT id, session_id, time_updated, data FROM message WHERE json_extract(data, '$.role') = 'assistant' ORDER BY time_created ASC`;
|
|
4307
4406
|
|
|
4308
4407
|
let snapshot = null;
|
|
4309
4408
|
let effectiveDbPath = dbPath;
|
|
@@ -4314,13 +4413,16 @@ function readOpencodeDbMessages(dbPath, sqliteOptions = {}) {
|
|
|
4314
4413
|
} catch (_e) { }
|
|
4315
4414
|
}
|
|
4316
4415
|
|
|
4317
|
-
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
|
|
4322
|
-
|
|
4323
|
-
|
|
4416
|
+
// Parse raw SQL rows into the shared { id, sessionID, timeUpdated, data }
|
|
4417
|
+
// shape; optionally restore v2's session-level project directory as the
|
|
4418
|
+
// per-message `path.cwd` the rest of the pipeline expects.
|
|
4419
|
+
//
|
|
4420
|
+
// D-state (transitional) union: both the legacy `message` table and the new
|
|
4421
|
+
// `session_message` table may carry rows. Cross-table duplicates are caught
|
|
4422
|
+
// by the existing cursor-key + #426 fingerprint dedup in
|
|
4423
|
+
// parseOpencodeDbIncremental, so unioning here is safe — the downstream
|
|
4424
|
+
// parser collapses identical sessionID|messageID pairs before bucketing.
|
|
4425
|
+
const collectRows = (rows, isV2) => {
|
|
4324
4426
|
const out = [];
|
|
4325
4427
|
for (const row of rows) {
|
|
4326
4428
|
if (!row || typeof row.data !== "string") continue;
|
|
@@ -4338,6 +4440,9 @@ function readOpencodeDbMessages(dbPath, sqliteOptions = {}) {
|
|
|
4338
4440
|
toNonNegativeInt(tokens.output) > 0 ||
|
|
4339
4441
|
toNonNegativeInt(tokens.reasoning) > 0;
|
|
4340
4442
|
if (!hasTokens) continue;
|
|
4443
|
+
if (isV2 && typeof row.directory === "string" && row.directory.trim()) {
|
|
4444
|
+
data.path = { ...(typeof data.path === "object" && data.path ? data.path : {}), cwd: row.directory };
|
|
4445
|
+
}
|
|
4341
4446
|
out.push({
|
|
4342
4447
|
id: row.id || data.id,
|
|
4343
4448
|
sessionID: row.session_id || data.sessionID,
|
|
@@ -4345,6 +4450,40 @@ function readOpencodeDbMessages(dbPath, sqliteOptions = {}) {
|
|
|
4345
4450
|
data,
|
|
4346
4451
|
});
|
|
4347
4452
|
}
|
|
4453
|
+
return out;
|
|
4454
|
+
};
|
|
4455
|
+
|
|
4456
|
+
const readGeneration = (sql) => {
|
|
4457
|
+
try {
|
|
4458
|
+
const rows = readSqliteJsonRows(effectiveDbPath, sql, {
|
|
4459
|
+
label: "OpenCode",
|
|
4460
|
+
maxBuffer: 50 * 1024 * 1024,
|
|
4461
|
+
timeout: 30_000,
|
|
4462
|
+
...sqliteOptions,
|
|
4463
|
+
throwOnReadFailure: true,
|
|
4464
|
+
});
|
|
4465
|
+
return Array.isArray(rows) ? rows : [];
|
|
4466
|
+
} catch (_e) {
|
|
4467
|
+
return null; // query-level failure (e.g. wrong generation's table)
|
|
4468
|
+
}
|
|
4469
|
+
};
|
|
4470
|
+
|
|
4471
|
+
try {
|
|
4472
|
+
// Combined probe drives the orchestration: v1 always runs (it is the
|
|
4473
|
+
// baseline every database carries or degrades to), v2 runs only when the
|
|
4474
|
+
// probe confirms session_message has rows — this avoids firing a JOIN
|
|
4475
|
+
// against a non-existent session table on type-A databases.
|
|
4476
|
+
const probe = detectOpencodeMessageLayout(effectiveDbPath, sqliteOptions);
|
|
4477
|
+
const out = [];
|
|
4478
|
+
|
|
4479
|
+
const rows1 = readGeneration(OPENCODE_DB_V1_MESSAGE_SQL);
|
|
4480
|
+
if (rows1) out.push(...collectRows(rows1, false));
|
|
4481
|
+
|
|
4482
|
+
if (probe?.hasRows) {
|
|
4483
|
+
const rows2 = readGeneration(buildV2Sql(probe.sessionTable));
|
|
4484
|
+
if (rows2) out.push(...collectRows(rows2, true));
|
|
4485
|
+
}
|
|
4486
|
+
|
|
4348
4487
|
return out;
|
|
4349
4488
|
} finally {
|
|
4350
4489
|
if (snapshot) snapshot.cleanup();
|
|
@@ -4369,7 +4508,7 @@ function readOpencodeDbMessages(dbPath, sqliteOptions = {}) {
|
|
|
4369
4508
|
// subsumes it.
|
|
4370
4509
|
function isMimoNativeMessage(data) {
|
|
4371
4510
|
if (!data) return false;
|
|
4372
|
-
const provider = String(data
|
|
4511
|
+
const provider = String(opencodeMessageProvider(data)).toLowerCase();
|
|
4373
4512
|
return provider === "mimo" || provider === "xiaomi";
|
|
4374
4513
|
}
|
|
4375
4514
|
|
|
@@ -4403,7 +4542,7 @@ function readMimoDbMessages(dbPath, sqliteOptions = {}) {
|
|
|
4403
4542
|
// re-count it. Mirrors the Mimo discipline.
|
|
4404
4543
|
function isZcodeNativeMessage(data) {
|
|
4405
4544
|
if (!data) return false;
|
|
4406
|
-
const provider = String(data
|
|
4545
|
+
const provider = String(opencodeMessageProvider(data)).toLowerCase();
|
|
4407
4546
|
if (!provider) return false;
|
|
4408
4547
|
return !(
|
|
4409
4548
|
provider.includes("anthropic") ||
|
|
@@ -4562,7 +4701,8 @@ async function parseOpencodeDbIncremental({
|
|
|
4562
4701
|
continue;
|
|
4563
4702
|
}
|
|
4564
4703
|
|
|
4565
|
-
const
|
|
4704
|
+
const { modelId: dbModelId } = normalizeOpencodeModelFields(msg);
|
|
4705
|
+
const model = dbModelId || DEFAULT_MODEL;
|
|
4566
4706
|
const bucket = getHourlyBucket(hourlyState, defaultSource, model, bucketStart);
|
|
4567
4707
|
addTotals(bucket.totals, delta);
|
|
4568
4708
|
touchedBuckets.add(bucketKey(defaultSource, model, bucketStart));
|
|
@@ -16614,36 +16754,55 @@ function isCjkCodePoint(code) {
|
|
|
16614
16754
|
// (session transcripts are SQLCipher-encrypted; memory summaries carry no
|
|
16615
16755
|
// token counts), so the token-count-only queue is intentionally never written
|
|
16616
16756
|
// for this provider — the cloud hourly table stays clean.
|
|
16617
|
-
|
|
16757
|
+
// Ordered candidate app-dir names. The CN IDE build installs as "Trae CN" on
|
|
16758
|
+
// Windows; the international build installs as "TRAE SOLO". Both expose the same
|
|
16759
|
+
// iCubeServerData entitlement key, so either is a valid Trae IDE install.
|
|
16760
|
+
function traeCandidateAppDirs(env = process.env) {
|
|
16618
16761
|
const override = env.TOKENTRACKER_TRAE_HOME;
|
|
16619
16762
|
if (typeof override === "string" && override.trim().length > 0) {
|
|
16620
|
-
return override.trim();
|
|
16763
|
+
return [override.trim()];
|
|
16621
16764
|
}
|
|
16622
16765
|
const home = require("node:os").homedir();
|
|
16623
16766
|
if (process.platform === "darwin") {
|
|
16624
|
-
return path.join(home, "Library", "Application Support", "TRAE SOLO");
|
|
16767
|
+
return [path.join(home, "Library", "Application Support", "TRAE SOLO")];
|
|
16625
16768
|
}
|
|
16626
16769
|
if (process.platform === "win32") {
|
|
16627
16770
|
// A Windows box with no APPDATA still keeps Trae under the standard
|
|
16628
16771
|
// roaming profile — falling through to the dot-dir below would point at
|
|
16629
16772
|
// a location Trae never writes.
|
|
16630
|
-
const appData =
|
|
16631
|
-
|
|
16632
|
-
|
|
16633
|
-
|
|
16773
|
+
const appData =
|
|
16774
|
+
typeof env.APPDATA === "string" && env.APPDATA.trim()
|
|
16775
|
+
? env.APPDATA.trim()
|
|
16776
|
+
: path.join(home, "AppData", "Roaming");
|
|
16777
|
+
return [
|
|
16778
|
+
path.join(appData, "TRAE SOLO"),
|
|
16779
|
+
path.join(appData, "Trae CN"),
|
|
16780
|
+
];
|
|
16634
16781
|
}
|
|
16635
16782
|
// Linux and friends: TRAE SOLO ships official builds for macOS/Windows
|
|
16636
16783
|
// only, so there is no verified app-data layout to default to. Fall back to
|
|
16637
16784
|
// a deterministic home-dir path (best-effort detection);
|
|
16638
16785
|
// TOKENTRACKER_TRAE_HOME always wins for unusual installs.
|
|
16639
|
-
return path.join(home, ".trae-solo");
|
|
16786
|
+
return [path.join(home, ".trae-solo")];
|
|
16787
|
+
}
|
|
16788
|
+
|
|
16789
|
+
// Best-effort: the first candidate that exists on disk (used for display/init
|
|
16790
|
+
// detection). When no install is present, returns the primary candidate so
|
|
16791
|
+
// callers still get a deterministic path to report.
|
|
16792
|
+
function resolveTraePath(env = process.env) {
|
|
16793
|
+
const candidates = traeCandidateAppDirs(env);
|
|
16794
|
+
for (const dir of candidates) {
|
|
16795
|
+
try { if (fssync.existsSync(dir)) return dir; } catch (_error) {}
|
|
16796
|
+
}
|
|
16797
|
+
return candidates.length ? candidates[0] : null;
|
|
16640
16798
|
}
|
|
16641
16799
|
|
|
16642
16800
|
function resolveTraeStoragePath(env = process.env) {
|
|
16643
|
-
const
|
|
16644
|
-
|
|
16645
|
-
|
|
16646
|
-
|
|
16801
|
+
for (const dir of traeCandidateAppDirs(env)) {
|
|
16802
|
+
const p = path.join(dir, "User", "globalStorage", "storage.json");
|
|
16803
|
+
try { if (fssync.existsSync(p)) return p; } catch (_error) {}
|
|
16804
|
+
}
|
|
16805
|
+
return null;
|
|
16647
16806
|
}
|
|
16648
16807
|
|
|
16649
16808
|
/**
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* TRAE Work CN (国内版) config + usage fetch. Phase A: macOS + test-injected
|
|
4
|
+
* TRAE Work CN (国内版) config + usage fetch. Phase A: macOS + Windows + test-injected
|
|
5
5
|
* paths only. Resolves the CN home, reads the `iCubeAuthInfo://icube.cloudide`
|
|
6
6
|
* blob from User/globalStorage/storage.json (plaintext JSON or Base64 tc v5),
|
|
7
7
|
* and talks to the TRAE CN usage API. JWTs / refresh tokens are never
|
|
@@ -85,7 +85,16 @@ function resolveTraeCnHome({ env = process.env, home = os.homedir(), platform =
|
|
|
85
85
|
if (platform === "darwin") {
|
|
86
86
|
return path.join(home, "Library", "Application Support", TRAE_CN_APP_DIR);
|
|
87
87
|
}
|
|
88
|
-
|
|
88
|
+
if (platform === "win32") {
|
|
89
|
+
// Windows keeps the CN Work app under the roaming profile, mirroring the
|
|
90
|
+
// macOS Application Support layout (APPDATA/TRAE SOLO CN/User/...).
|
|
91
|
+
const appData =
|
|
92
|
+
typeof env.APPDATA === "string" && env.APPDATA.trim()
|
|
93
|
+
? env.APPDATA.trim()
|
|
94
|
+
: path.join(home, "AppData", "Roaming");
|
|
95
|
+
return path.join(appData, TRAE_CN_APP_DIR);
|
|
96
|
+
}
|
|
97
|
+
// No verified CN Work app-data layout on other platforms yet.
|
|
89
98
|
return null;
|
|
90
99
|
}
|
|
91
100
|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{r as n,z as a}from"./__vite-browser-external-WKiEWJ30.js";import{u as p}from"./DialogTitle-eIgptOU-.js";import{u as c}from"./useScrollLock-CZ1Na38Y.js";const x=n.forwardRef(function(e,r){const{render:l,className:u,style:m,id:s,...t}=e,i=p(),o=c(s);return i.useSyncedValueWithCleanup("descriptionElementId",o),a("p",e,{ref:r,props:[{id:o},t]})});export{x as D};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{r as o}from"./__vite-browser-external-WKiEWJ30.js";import{h as r,i as t,p as s}from"./react-us685QUG.js";function i(){!r.current&&t();const[e]=o.useState(s.current);return e}export{i as u};
|