tokentracker-cli 1.4.10 → 1.4.12

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.
Files changed (124) hide show
  1. package/README.de.md +6 -5
  2. package/README.ja.md +6 -5
  3. package/README.ko.md +6 -5
  4. package/README.md +6 -4
  5. package/README.zh-CN.md +6 -5
  6. package/dashboard/dist/assets/{AchievementBadge-BTqlXUP1.js → AchievementBadge-BwrL59nq.js} +1 -1
  7. package/dashboard/dist/assets/{AchievementsPage-DbKUhaY-.js → AchievementsPage-DG0dvG3d.js} +2 -2
  8. package/dashboard/dist/assets/{AchievementsSection-El1F-OC7.js → AchievementsSection-NrjlZjZK.js} +1 -1
  9. package/dashboard/dist/assets/{BadgeDetailModal--8PySLzP.js → BadgeDetailModal-BjgBAb-0.js} +1 -1
  10. package/dashboard/dist/assets/{BotAnimated-DBcOS4vh.js → BotAnimated-D7gMmkaM.js} +1 -1
  11. package/dashboard/dist/assets/{Card-CeGs8TaY.js → Card-CgvwIS5W.js} +1 -1
  12. package/dashboard/dist/assets/{CloudCheckoutPage-DCg3VVAi.js → CloudCheckoutPage-DKDpT0HI.js} +1 -1
  13. package/dashboard/dist/assets/{CloudPage-CmeFDrmk.js → CloudPage-BOfqPAAH.js} +2 -2
  14. package/dashboard/dist/assets/{CommandPalette-CrSNoZW9.js → CommandPalette-BfRKy_dn.js} +1 -1
  15. package/dashboard/dist/assets/{CommunityStatsModal-ynB4j0Qb.js → CommunityStatsModal-BcVSszit.js} +1 -1
  16. package/dashboard/dist/assets/{ConfirmModal-DDTUf-My.js → ConfirmModal-Be4EVpPT.js} +1 -1
  17. package/dashboard/dist/assets/{Controls-DXsJjEU1.js → Controls-vrG8LLBe.js} +1 -1
  18. package/dashboard/dist/assets/{DashboardPage-fr4sgbLB.js → DashboardPage-DvhF72XX.js} +1 -1
  19. package/dashboard/dist/assets/{DateRangePopover-gTiPISL_.js → DateRangePopover-CZVMdPEq.js} +1 -1
  20. package/dashboard/dist/assets/{DevicePage-DvHVjCCH.js → DevicePage-BeNIjTqa.js} +1 -1
  21. package/dashboard/dist/assets/{DialogClose-CXwouQe4.js → DialogClose-BaNPZ3Bu.js} +1 -1
  22. package/dashboard/dist/assets/DialogDescription-LHQ-SC4e.js +1 -0
  23. package/dashboard/dist/assets/{DialogTitle-Cd_k-Nyw.js → DialogTitle-B3IwNXro.js} +1 -1
  24. package/dashboard/dist/assets/{ElectricLogo-C4vUNTCI.js → ElectricLogo-DC-03HL_.js} +1 -1
  25. package/dashboard/dist/assets/{FadeIn-CGM5RBFy.js → FadeIn-DhUnSf2V.js} +1 -1
  26. package/dashboard/dist/assets/{HeaderGithubStar-el5-DhVb.js → HeaderGithubStar-BiWRLl7V.js} +1 -1
  27. package/dashboard/dist/assets/{HoverTooltip-C7YaWwJx.js → HoverTooltip-DLPiBqDu.js} +1 -1
  28. package/dashboard/dist/assets/{IpCheckPage-EKhbH9hJ.js → IpCheckPage-DKjg0V9L.js} +1 -1
  29. package/dashboard/dist/assets/{LandingPage-DJYOv1AM.js → LandingPage-XQuTnBMQ.js} +2 -2
  30. package/dashboard/dist/assets/{LeaderboardPage-CwzJxA8p.js → LeaderboardPage-xAbo5mzo.js} +2 -2
  31. package/dashboard/dist/assets/{LeaderboardProBadge-DYLp9pJY.js → LeaderboardProBadge-mMiEeaYS.js} +1 -1
  32. package/dashboard/dist/assets/{LeaderboardProfileModal-DqD2h9dD.js → LeaderboardProfileModal-B7q0Kk6B.js} +3 -3
  33. package/dashboard/dist/assets/{LeaderboardProfilePage-CarYvpYe.js → LeaderboardProfilePage-Bru_6wgX.js} +1 -1
  34. package/dashboard/dist/assets/{LimitsPage-4T0BpfYS.js → LimitsPage-DQH6ziz4.js} +1 -1
  35. package/dashboard/dist/assets/{LocalOnlyNotice-CAR-mqy0.js → LocalOnlyNotice-B-lxih4W.js} +1 -1
  36. package/dashboard/dist/assets/{LoginCard-Czq-UgAU.js → LoginCard-ChNsRYE2.js} +1 -1
  37. package/dashboard/dist/assets/{LoginModal-D4uxfzZb.js → LoginModal-CRw3PgMi.js} +1 -1
  38. package/dashboard/dist/assets/{LoginPage-Bg3BG0Wv.js → LoginPage-CVsbYn-h.js} +1 -1
  39. package/dashboard/dist/assets/{PetPage-BgwBxRyx.js → PetPage-BwEnQLLY.js} +2 -2
  40. package/dashboard/dist/assets/{PopoverPopup-k3o_Jp2b.js → PopoverPopup-CDOtxSL8.js} +1 -1
  41. package/dashboard/dist/assets/{ProviderIcon-Bbw6MUSf.js → ProviderIcon-Dsu1p6gG.js} +1 -1
  42. package/dashboard/dist/assets/{ResetPasswordPage-DIKPVu5K.js → ResetPasswordPage-BzpaSORs.js} +1 -1
  43. package/dashboard/dist/assets/{Select-kA0dV5Qw.js → Select-62UH-yLs.js} +1 -1
  44. package/dashboard/dist/assets/{SelectItemText-D4YCIn1x.js → SelectItemText-aTexKmQ0.js} +1 -1
  45. package/dashboard/dist/assets/{SelfHostPage-C3Y9qF3P.js → SelfHostPage-CmhV0dms.js} +1 -1
  46. package/dashboard/dist/assets/{ServiceStatusPage-o1G3SJhV.js → ServiceStatusPage-CLWO33w1.js} +1 -1
  47. package/dashboard/dist/assets/{SessionsPage-CA-efxhU.js → SessionsPage-BNCDKb58.js} +2 -2
  48. package/dashboard/dist/assets/{SettingsPage-Mr84vxQL.js → SettingsPage-DybHncPO.js} +3 -3
  49. package/dashboard/dist/assets/{SkillsPage-BtRhLSpz.js → SkillsPage-BV5R3VhT.js} +1 -1
  50. package/dashboard/dist/assets/{TokenGalaxy-CcFjCCuC.js → TokenGalaxy-mNNAo6Ai.js} +1 -1
  51. package/dashboard/dist/assets/{TooltipPopup-6aTx3jDf.js → TooltipPopup-D00SVpLP.js} +1 -1
  52. package/dashboard/dist/assets/{TrendMonitor-DoywXr8h.js → TrendMonitor-aNIpzAO-.js} +1 -1
  53. package/dashboard/dist/assets/{WidgetsPage-BuGSzvR0.js → WidgetsPage-COjZIMo8.js} +1 -1
  54. package/dashboard/dist/assets/{WrappedPage-Bm6X-SUZ.js → WrappedPage-af-bDIfB.js} +1 -1
  55. package/dashboard/dist/assets/{__vite-browser-external-ClVJNQu3.js → __vite-browser-external-KHpR2q-A.js} +2 -2
  56. package/dashboard/dist/assets/{agent-logos-Sc8Sejgx.js → agent-logos-D9Uq5b6y.js} +1 -1
  57. package/dashboard/dist/assets/{arrow-left-Cm1LG2i_.js → arrow-left-Pt53BsA4.js} +1 -1
  58. package/dashboard/dist/assets/{arrow-right-WP3kIwiy.js → arrow-right-stBCZPot.js} +1 -1
  59. package/dashboard/dist/assets/{arrow-up-right-CjyprVMj.js → arrow-up-right-ltUBOD-o.js} +1 -1
  60. package/dashboard/dist/assets/{calendar-days-Bm88-Gcb.js → calendar-days-BMEtkPFp.js} +1 -1
  61. package/dashboard/dist/assets/{check-CzIxFg0I.js → check-ax5wQf5Q.js} +1 -1
  62. package/dashboard/dist/assets/{chevron-down-bfGK8629.js → chevron-down-gS62rNQt.js} +1 -1
  63. package/dashboard/dist/assets/{cloud-checkout-C9DFQ7yM.js → cloud-checkout-DDtdbz7C.js} +1 -1
  64. package/dashboard/dist/assets/{composite-CdExmgTx.js → composite-DVm8byy8.js} +1 -1
  65. package/dashboard/dist/assets/{copy-CPPdujn2.js → copy-VbASSQO1.js} +1 -1
  66. package/dashboard/dist/assets/{download-Cl6_dKeK.js → download-D1g6OCRI.js} +1 -1
  67. package/dashboard/dist/assets/{external-link-B0r6Wo4e.js → external-link-CGUQrKDL.js} +1 -1
  68. package/dashboard/dist/assets/{flame-wEezvzXx.js → flame-Dlvc-qIH.js} +1 -1
  69. package/dashboard/dist/assets/{format-tokens-vWpBpKpM.js → format-tokens-CB1QfZsj.js} +1 -1
  70. package/dashboard/dist/assets/{gift-BFjblRqU.js → gift-DydflDeL.js} +1 -1
  71. package/dashboard/dist/assets/{icons-DX3dCNJP.js → icons-B_xYF8_-.js} +1 -1
  72. package/dashboard/dist/assets/{index-p8Gt3NFg.js → index-BRNltZbP.js} +1 -1
  73. package/dashboard/dist/assets/{index-DBF1bJlm.js → index-ByXXZlPn.js} +1 -1
  74. package/dashboard/dist/assets/{index-D1Zdrpom.js → index-CuLrp2D2.js} +1 -1
  75. package/dashboard/dist/assets/{index-D-TnqdBv.js → index-cidqWI7C.js} +1 -1
  76. package/dashboard/dist/assets/{info-Cqi971MA.js → info-D6-LIywq.js} +1 -1
  77. package/dashboard/dist/assets/{link-2-79sm__cT.js → link-2-BbuXAF5y.js} +1 -1
  78. package/dashboard/dist/assets/{loader-circle-CDoVfOUb.js → loader-circle-DAeCHAyj.js} +1 -1
  79. package/dashboard/dist/assets/{local-usage-transfer-EcXnuwCj.js → local-usage-transfer-BejRwzi4.js} +1 -1
  80. package/dashboard/dist/assets/{modifiers.esm-v5_BKSmY.js → modifiers.esm-CV2S03sv.js} +1 -1
  81. package/dashboard/dist/assets/{monitor-smartphone-CO67DffO.js → monitor-smartphone-Dj_u5s6h.js} +1 -1
  82. package/dashboard/dist/assets/{play-CbvuGtc3.js → play-DrcSicai.js} +1 -1
  83. package/dashboard/dist/assets/{plus-jc2gXlRM.js → plus-BwYQW7nf.js} +1 -1
  84. package/dashboard/dist/assets/{provider-display-BK3EbRLM.js → provider-display-Bgfy-2rn.js} +2 -2
  85. package/dashboard/dist/assets/{react-DMs4C4qS.js → react-BXby2gfP.js} +1 -1
  86. package/dashboard/dist/assets/{safePolygon-cY9H0GBN.js → safePolygon-B8DY85mD.js} +1 -1
  87. package/dashboard/dist/assets/{search-fqTJoYYA.js → search-SCMosATz.js} +1 -1
  88. package/dashboard/dist/assets/{server-jpBtvTvr.js → server-DoD96f86.js} +1 -1
  89. package/dashboard/dist/assets/{shield-check-DQiBlJbN.js → shield-check-CESJcEp7.js} +1 -1
  90. package/dashboard/dist/assets/{skills-api-CN2r_rmt.js → skills-api-DE71Ylhd.js} +1 -1
  91. package/dashboard/dist/assets/{sortable.esm-DrS52yOK.js → sortable.esm-EgVv2jPt.js} +1 -1
  92. package/dashboard/dist/assets/{store-K2Mk6aMn.js → store-mMQPBMoh.js} +1 -1
  93. package/dashboard/dist/assets/{terminal-Q4SruAlh.js → terminal-DxNM-IG2.js} +1 -1
  94. package/dashboard/dist/assets/{trash-C1Ob-g8E.js → trash-rywOpT2_.js} +1 -1
  95. package/dashboard/dist/assets/{use-community-stats-C-Gxpp9D.js → use-community-stats-BQw06Twe.js} +1 -1
  96. package/dashboard/dist/assets/{use-latest-request-guard-DK-A4bBp.js → use-latest-request-guard-BvouGm-c.js} +1 -1
  97. package/dashboard/dist/assets/{use-limits-display-prefs-ZauQzxE_.js → use-limits-display-prefs-C5_9TDSy.js} +1 -1
  98. package/dashboard/dist/assets/{use-native-settings-BZLEIUK8.js → use-native-settings-BxuddjkP.js} +1 -1
  99. package/dashboard/dist/assets/{use-ordered-list-De_Mcm_H.js → use-ordered-list-Cwqc5XA8.js} +1 -1
  100. package/dashboard/dist/assets/use-reduced-motion-DU3FvZwM.js +1 -0
  101. package/dashboard/dist/assets/{use-transform-XCDD5IrX.js → use-transform-Dl-SvALB.js} +1 -1
  102. package/dashboard/dist/assets/{use-usage-limits-BncGDhoF.js → use-usage-limits-BqmHYYc3.js} +1 -1
  103. package/dashboard/dist/assets/{useCurrency-DXPclxBT.js → useCurrency-B1XK_Z0N.js} +1 -1
  104. package/dashboard/dist/assets/{usePositioner-C-E1npCy.js → usePositioner-BvqDMGZo.js} +1 -1
  105. package/dashboard/dist/assets/{useTokenFormat-B70xhy9u.js → useTokenFormat-pPWJeWRe.js} +1 -1
  106. package/dashboard/dist/assets/{zap-D7gRgGCj.js → zap-DKYjQi1B.js} +1 -1
  107. package/dashboard/dist/index.html +13 -11
  108. package/dashboard/dist/ip-check.html +1 -1
  109. package/dashboard/dist/leaderboard.html +1 -1
  110. package/dashboard/dist/llms.txt +3 -2
  111. package/dashboard/dist/share.html +1 -1
  112. package/package.json +2 -2
  113. package/src/commands/init.js +1 -0
  114. package/src/commands/status.js +10 -0
  115. package/src/commands/sync.js +24 -0
  116. package/src/lib/omp-session.js +480 -0
  117. package/src/lib/pricing/curated-overrides.json +101 -0
  118. package/src/lib/pricing/matcher.js +44 -15
  119. package/src/lib/pricing/seed-snapshot.json +1 -1
  120. package/src/lib/rollout.js +277 -0
  121. package/src/lib/session-analytics.js +54 -8
  122. package/src/lib/trae-cn-config.js +36 -20
  123. package/dashboard/dist/assets/DialogDescription-BzbzETUC.js +0 -1
  124. package/dashboard/dist/assets/use-reduced-motion-DatTtp2N.js +0 -1
@@ -14107,6 +14107,279 @@ async function parseLmstudioIncremental({
14107
14107
  return { recordsProcessed, eventsAggregated, bucketsQueued };
14108
14108
  }
14109
14109
 
14110
+ // ─────────────────────────────────────────────────────────────────────────────
14111
+ // OpenSquilla
14112
+ //
14113
+ // Read only the finalized usage ledger's model rows. Transcript entries and
14114
+ // message content are not needed for token attribution and are never selected.
14115
+ // ─────────────────────────────────────────────────────────────────────────────
14116
+
14117
+ const OPENSQUILLA_SOURCE = "opensquilla";
14118
+
14119
+ function resolveOpenSquillaPath(value, home) {
14120
+ const raw = typeof value === "string" ? value.trim() : "";
14121
+ if (!raw) return null;
14122
+ if (raw === "~") return path.resolve(home);
14123
+ if (raw.startsWith("~/") || raw.startsWith("~\\")) {
14124
+ return path.resolve(home, raw.slice(2));
14125
+ }
14126
+ return path.resolve(raw);
14127
+ }
14128
+
14129
+ function resolveOpenSquillaDbPaths(env = process.env, deps = {}) {
14130
+ const home = deps.home || env.HOME || env.USERPROFILE || os.homedir();
14131
+ const platform = deps.platform || process.platform;
14132
+ const dbOverride = resolveOpenSquillaPath(env.TOKENTRACKER_OPENSQUILLA_DB, home);
14133
+ if (dbOverride) return [dbOverride];
14134
+
14135
+ const gatewayStateDir = resolveOpenSquillaPath(env.OPENSQUILLA_GATEWAY_STATE_DIR, home);
14136
+ if (gatewayStateDir) return [path.join(gatewayStateDir, "sessions.db")];
14137
+
14138
+ const stateHome = resolveOpenSquillaPath(env.OPENSQUILLA_STATE_DIR, home);
14139
+ if (stateHome) return [path.join(stateHome, "state", "sessions.db")];
14140
+
14141
+ const profileHomeOverride = typeof env.OPENSQUILLA_HOME === "string"
14142
+ ? env.OPENSQUILLA_HOME.trim()
14143
+ : "";
14144
+ const profileOverride = typeof env.OPENSQUILLA_PROFILE === "string"
14145
+ ? env.OPENSQUILLA_PROFILE.trim()
14146
+ : "";
14147
+ if (profileHomeOverride || profileOverride) {
14148
+ const profilesRoot = resolveOpenSquillaPath(
14149
+ profileHomeOverride || path.join(home, ".opensquilla", "profiles"),
14150
+ home,
14151
+ );
14152
+ const profile = profileOverride || "default";
14153
+ if (!/^[a-z0-9][a-z0-9_-]{0,63}$/i.test(profile)) return [];
14154
+ return [path.join(profilesRoot, profile, "state", "sessions.db")];
14155
+ }
14156
+
14157
+ const paths = [path.join(home, ".opensquilla", "state", "sessions.db")];
14158
+ let userDataRoot;
14159
+ if (platform === "win32") {
14160
+ userDataRoot = env.APPDATA || path.join(home, "AppData", "Roaming");
14161
+ } else if (platform === "darwin") {
14162
+ userDataRoot = path.join(home, "Library", "Application Support");
14163
+ } else {
14164
+ userDataRoot = env.XDG_CONFIG_HOME || path.join(home, ".config");
14165
+ }
14166
+ paths.unshift(path.join(
14167
+ userDataRoot,
14168
+ "@opensquilla",
14169
+ "desktop-electron",
14170
+ "opensquilla",
14171
+ "state",
14172
+ "sessions.db",
14173
+ ));
14174
+
14175
+ const seen = new Set();
14176
+ return paths.filter((dbPath) => {
14177
+ const resolved = path.resolve(dbPath);
14178
+ const key = platform === "win32" ? resolved.toLowerCase() : resolved;
14179
+ if (seen.has(key)) return false;
14180
+ seen.add(key);
14181
+ return true;
14182
+ });
14183
+ }
14184
+
14185
+ async function readOpenSquillaUsageRows(dbPath, sqliteOptions = {}) {
14186
+ if (!dbPath || !fssync.existsSync(dbPath)) return [];
14187
+ const options = {
14188
+ label: "OpenSquilla",
14189
+ maxBuffer: 32 * 1024 * 1024,
14190
+ timeout: 30_000,
14191
+ ...sqliteOptions,
14192
+ readOnly: true,
14193
+ throwOnReadFailure: true,
14194
+ };
14195
+ const tables = new Set(
14196
+ (await readSqliteJsonRowsAsync(
14197
+ dbPath,
14198
+ "SELECT name FROM sqlite_master WHERE type='table' AND name IN ('usage_events','usage_event_items')",
14199
+ options,
14200
+ )).map((row) => row?.name).filter(Boolean),
14201
+ );
14202
+ if (!tables.has("usage_events") || !tables.has("usage_event_items")) return [];
14203
+ const sql = [
14204
+ "SELECT e.event_id, e.completed_at_ms, i.ordinal,",
14205
+ "COALESCE(i.model, e.model) AS model, i.input_tokens, i.output_tokens,",
14206
+ "i.reasoning_tokens, i.cache_read_tokens, i.cache_write_tokens, i.total_tokens",
14207
+ "FROM usage_events AS e",
14208
+ "JOIN usage_event_items AS i ON i.event_id = e.event_id",
14209
+ "WHERE e.status = 'finalized' AND e.completed_at_ms IS NOT NULL",
14210
+ "ORDER BY e.completed_at_ms, e.event_id, i.ordinal",
14211
+ ].join(" ");
14212
+ return readSqliteJsonRowsAsync(dbPath, sql, options);
14213
+ }
14214
+
14215
+ function normalizeOpenSquillaUsageRow(row) {
14216
+ const eventId = typeof row?.event_id === "string" ? row.event_id.trim() : "";
14217
+ if (!eventId || row?.ordinal == null) return null;
14218
+
14219
+ // OpenSquilla stores input as a cache-inclusive total and reasoning as an
14220
+ // output subset; normalize both before writing TokenTracker queue rows.
14221
+ const totals = normalizeLocalStudioTokens({
14222
+ input_tokens: row.input_tokens,
14223
+ output_tokens: row.output_tokens,
14224
+ reasoning_tokens: row.reasoning_tokens,
14225
+ cached_tokens: row.cache_read_tokens,
14226
+ cache_creation_input_tokens: row.cache_write_tokens,
14227
+ total_tokens: row.total_tokens,
14228
+ });
14229
+ const timestampMs = coerceEpochMs(row.completed_at_ms);
14230
+ const bucketStart = timestampMs
14231
+ ? toUtcHalfHourStart(new Date(timestampMs).toISOString())
14232
+ : null;
14233
+ if (!totals || !bucketStart) return null;
14234
+
14235
+ return {
14236
+ key: "opensquilla:" + eventId + ":" + String(toNonNegativeInt(row.ordinal)),
14237
+ model: normalizeModelInput(row.model) || DEFAULT_MODEL,
14238
+ bucketStart,
14239
+ totals,
14240
+ };
14241
+ }
14242
+
14243
+ async function parseOpenSquillaIncremental({
14244
+ dbPaths,
14245
+ cursors,
14246
+ queuePath,
14247
+ onProgress,
14248
+ env,
14249
+ sqliteOptions,
14250
+ } = {}) {
14251
+ await ensureDir(path.dirname(queuePath));
14252
+ const priorState = cursors.opensquilla && typeof cursors.opensquilla === "object"
14253
+ ? cursors.opensquilla
14254
+ : {};
14255
+ // Copy before mutate so a failed queue append leaves committed cursors intact.
14256
+ const messages = priorState.messages && typeof priorState.messages === "object"
14257
+ ? { ...priorState.messages }
14258
+ : {};
14259
+ const fingerprints = priorState.fingerprints && typeof priorState.fingerprints === "object"
14260
+ ? { ...priorState.fingerprints }
14261
+ : {};
14262
+ const requestedPaths = Array.isArray(dbPaths) && dbPaths.length
14263
+ ? dbPaths
14264
+ : resolveOpenSquillaDbPaths(env || process.env);
14265
+ const seenPaths = new Set();
14266
+ const availablePaths = requestedPaths.filter((dbPath) => {
14267
+ if (typeof dbPath !== "string" || !dbPath.trim() || !fssync.existsSync(dbPath)) return false;
14268
+ const resolved = path.resolve(dbPath);
14269
+ const key = process.platform === "win32" ? resolved.toLowerCase() : resolved;
14270
+ if (seenPaths.has(key)) return false;
14271
+ seenPaths.add(key);
14272
+ return true;
14273
+ });
14274
+ // No currently readable DB is treated as temporary unavailability — keep
14275
+ // prior observations rather than wiping totals.
14276
+ if (availablePaths.length === 0) {
14277
+ cursors.opensquilla = { ...priorState, messages, fingerprints, updatedAt: new Date().toISOString() };
14278
+ return { recordsProcessed: 0, eventsAggregated: 0, bucketsQueued: 0 };
14279
+ }
14280
+
14281
+ const pathFingerprints = new Map();
14282
+ let databaseChanged = false;
14283
+ const currentPathKeys = new Set();
14284
+ for (const dbPath of availablePaths) {
14285
+ const key = path.resolve(dbPath);
14286
+ currentPathKeys.add(key);
14287
+ const fingerprint = sqliteSidecarFingerprint(dbPath);
14288
+ pathFingerprints.set(key, fingerprint);
14289
+ if (!fingerprints[key] || !sameSqliteFingerprint(fingerprint, fingerprints[key])) {
14290
+ databaseChanged = true;
14291
+ }
14292
+ }
14293
+ // A removed Desktop/CLI DB must also trigger reconciliation so orphaned
14294
+ // observations can be retracted (fingerprint-only checks would miss this).
14295
+ for (const key of Object.keys(fingerprints)) {
14296
+ if (!currentPathKeys.has(key)) {
14297
+ databaseChanged = true;
14298
+ break;
14299
+ }
14300
+ }
14301
+ if (!databaseChanged) {
14302
+ return { recordsProcessed: 0, eventsAggregated: 0, bucketsQueued: 0 };
14303
+ }
14304
+
14305
+ // The Desktop profile is first in the default path list. If a migrated CLI
14306
+ // profile retains the same event IDs, prefer the active Desktop copy and
14307
+ // count each model row only once.
14308
+ const rowsByEventItem = new Map();
14309
+ for (const dbPath of availablePaths) {
14310
+ const dbRows = await readOpenSquillaUsageRows(dbPath, sqliteOptions);
14311
+ for (const row of dbRows) {
14312
+ const eventId = typeof row?.event_id === "string" ? row.event_id.trim() : "";
14313
+ if (!eventId || row?.ordinal == null) continue;
14314
+ const key = eventId + ":" + String(toNonNegativeInt(row.ordinal));
14315
+ if (!rowsByEventItem.has(key)) rowsByEventItem.set(key, row);
14316
+ }
14317
+ }
14318
+ const rows = Array.from(rowsByEventItem.values());
14319
+ // structuredClone so a failed enqueueTouchedBuckets cannot leave mutated
14320
+ // totals committed while opensquilla.messages stays unchanged (retry would
14321
+ // subtract again). Same pattern as TRAE / session reconcilers.
14322
+ const hourlyState = structuredClone(normalizeHourlyState(cursors?.hourly));
14323
+ const touchedBuckets = new Set();
14324
+ const cb = typeof onProgress === "function" ? onProgress : null;
14325
+ let eventsAggregated = 0;
14326
+ const currentKeys = new Set();
14327
+ for (let index = 0; index < rows.length; index++) {
14328
+ const event = normalizeOpenSquillaUsageRow(rows[index]);
14329
+ if (event) currentKeys.add(event.key);
14330
+ if (event && reconcilePassiveUsageEvent({
14331
+ event,
14332
+ source: OPENSQUILLA_SOURCE,
14333
+ messages,
14334
+ hourlyState,
14335
+ touchedBuckets,
14336
+ })) eventsAggregated += 1;
14337
+ if (cb) {
14338
+ cb({
14339
+ index: index + 1,
14340
+ total: rows.length,
14341
+ recordsProcessed: index + 1,
14342
+ eventsAggregated,
14343
+ bucketsQueued: touchedBuckets.size,
14344
+ });
14345
+ }
14346
+ }
14347
+
14348
+ // Retract observations that disappeared with a removed database (or were
14349
+ // deleted from the remaining DB). Overlapping event IDs keep Desktop-first
14350
+ // totals via reconcilePassiveUsageEvent above.
14351
+ for (const key of Object.keys(messages)) {
14352
+ if (!key.startsWith("opensquilla:") || currentKeys.has(key)) continue;
14353
+ const previous = messages[key];
14354
+ if (previous?.model && previous?.bucketStart && previous?.totals) {
14355
+ const oldBucket = getHourlyBucket(
14356
+ hourlyState,
14357
+ OPENSQUILLA_SOURCE,
14358
+ previous.model,
14359
+ previous.bucketStart,
14360
+ );
14361
+ subtractTotals(oldBucket.totals, previous.totals);
14362
+ touchedBuckets.add(bucketKey(OPENSQUILLA_SOURCE, previous.model, previous.bucketStart));
14363
+ }
14364
+ delete messages[key];
14365
+ eventsAggregated += 1;
14366
+ }
14367
+
14368
+ const nextFingerprints = {};
14369
+ for (const dbPath of availablePaths) {
14370
+ const key = path.resolve(dbPath);
14371
+ const before = pathFingerprints.get(key);
14372
+ const after = sqliteSidecarFingerprint(dbPath);
14373
+ nextFingerprints[key] = sameSqliteFingerprint(before, after) ? after : before;
14374
+ }
14375
+ const bucketsQueued = await enqueueTouchedBuckets({ queuePath, hourlyState, touchedBuckets });
14376
+ const updatedAt = new Date().toISOString();
14377
+ hourlyState.updatedAt = updatedAt;
14378
+ cursors.hourly = hourlyState;
14379
+ cursors.opensquilla = { messages, fingerprints: nextFingerprints, updatedAt };
14380
+ return { recordsProcessed: rows.length, eventsAggregated, bucketsQueued };
14381
+ }
14382
+
14110
14383
  // ─────────────────────────────────────────────────────────────────────────────
14111
14384
  // Unsloth Studio
14112
14385
  //
@@ -25865,6 +26138,10 @@ module.exports = {
25865
26138
  normalizeLocalStudioTokens,
25866
26139
  readLmstudioFileRecords,
25867
26140
  parseLmstudioIncremental,
26141
+ resolveOpenSquillaDbPaths,
26142
+ readOpenSquillaUsageRows,
26143
+ normalizeOpenSquillaUsageRow,
26144
+ parseOpenSquillaIncremental,
25868
26145
  resolveUnslothDbPath,
25869
26146
  readUnslothUsageRows,
25870
26147
  normalizeUnslothUsageRow,
@@ -38,6 +38,7 @@ const { readCursorStateSummary } = require("./cursor-store");
38
38
  const { USD_TICKS_PER_USD, normalizeGrokUsage } = require("./grok-usage");
39
39
  const wsl = require("./wsl-probe");
40
40
  const { discoverKimiWireFiles, kimiSessionDependencies, readKimiSessions } = require("./kimi-session");
41
+ const { discoverOmpSessionFiles, ompSessionDependencies, readOmpSessions } = require("./omp-session");
41
42
  const {
42
43
  appendUniqueDirs,
43
44
  dedupeDirsByRealpath,
@@ -89,7 +90,8 @@ const {
89
90
  // v25 adds Kimi wire sessions, including official/legacy migration dedup.
90
91
  // v26 retains Codex Ultrafast (service_tier ultrafast) subset columns so
91
92
  // date-filtered session views and cached sidecars keep the 6x premium.
92
- const SIDECAR_VERSION = 26;
93
+ // v27 adds oh-my-pi (omp) sessions from ~/.omp/agent/sessions/**/*.jsonl.
94
+ const SIDECAR_VERSION = 27;
93
95
  const EDIT_TOOLS = new Set([
94
96
  "apply_patch",
95
97
  "edit",
@@ -1948,6 +1950,26 @@ async function scanKimiSessions(filePaths) {
1948
1950
  }));
1949
1951
  }
1950
1952
 
1953
+ async function scanOmpSessions(filePaths) {
1954
+ // Batch the whole OMP inventory so fork copies that reuse entry ids are
1955
+ // counted once across sessions (same contract as the hourly seenIds set).
1956
+ const rows = await readOmpSessions(Array.isArray(filePaths) ? filePaths : [filePaths]);
1957
+ return rows.map(({ identity, files, title, ...row }) => finalizeRecord({
1958
+ ...row,
1959
+ title: cleanSessionTitle(title),
1960
+ version: SIDECAR_VERSION,
1961
+ source: "omp",
1962
+ session_hash: sessionHash("omp", identity),
1963
+ project_key: projectKey(row.project_ref, files[0]),
1964
+ ...sessionStorageUsage(files),
1965
+ }));
1966
+ }
1967
+
1968
+ async function scanOmpSession(filePath) {
1969
+ const rows = await scanOmpSessions([filePath]);
1970
+ return rows[0] || null;
1971
+ }
1972
+
1951
1973
  async function discoverSessionFiles(home, env = process.env, deps = {}) {
1952
1974
  const grokHome = resolveGrokHome(home);
1953
1975
  // config.scanRoots (#657): read from the tracker config unless the caller
@@ -2040,7 +2062,12 @@ async function discoverSessionFiles(home, env = process.env, deps = {}) {
2040
2062
  return roots;
2041
2063
  });
2042
2064
  const kimi = discoverKimiWireFiles(dedupeDirsByRealpath(kimiRoots), incomplete);
2043
- return { claude, codex: groupCodexFiles([...codex, ...archived]), grok, zcode, opencode, kimi, incomplete };
2065
+ const usingMachineHome = path.resolve(home) === path.resolve((deps.homedir || os.homedir)());
2066
+ const ompEnv = usingMachineHome
2067
+ ? { ...env, HOME: home }
2068
+ : { HOME: home, OMP_HOME: path.join(home, ".omp") };
2069
+ const omp = discoverOmpSessionFiles(ompEnv, incomplete);
2070
+ return { claude, codex: groupCodexFiles([...codex, ...archived]), grok, zcode, opencode, kimi, omp, incomplete };
2044
2071
  }
2045
2072
 
2046
2073
  // Warn once per unreadable directory per process: the dashboard polls this
@@ -2144,6 +2171,9 @@ function analyticsEntryStatKey(source, filePath) {
2144
2171
  if (source === "kimi") {
2145
2172
  return `${sessionStat}|metadata:${filesSignature(kimiSessionDependencies(filePaths))}`;
2146
2173
  }
2174
+ if (source === "omp") {
2175
+ return `${sessionStat}|metadata:${filesSignature(ompSessionDependencies([filePaths].flat()))}`;
2176
+ }
2147
2177
  if (source === "grok") {
2148
2178
  const primary = filePaths[0];
2149
2179
  return `${sessionStat}|summary:${sessionFileStatKey(grokSummaryPathFor(primary)) || "missing"}|signals:${sessionFileStatKey(grokSignalsPathFor(primary)) || "missing"}`;
@@ -2185,13 +2215,15 @@ async function buildSessionAnalyticsInternal({ home = os.homedir(), force = fals
2185
2215
  const retryOpencodeScan = fs.existsSync(incompleteOpencodePath);
2186
2216
  const incompleteKimiPath = `${metaPath}.kimi-incomplete`;
2187
2217
  const retryKimiScan = fs.existsSync(incompleteKimiPath);
2218
+ const incompleteOmpPath = `${metaPath}.omp-incomplete`;
2219
+ const retryOmpScan = fs.existsSync(incompleteOmpPath);
2188
2220
  let previousMeta = null;
2189
2221
  if (!force) {
2190
2222
  try {
2191
2223
  previousMeta = JSON.parse(fs.readFileSync(metaPath, "utf8"));
2192
2224
  const checkedAt = Date.parse(previousMeta.checked_at || previousMeta.generated_at || "");
2193
2225
  if (
2194
- !retryZcodeScan && !retryOpencodeScan && !retryKimiScan && previousMeta.version === SIDECAR_VERSION &&
2226
+ !retryZcodeScan && !retryOpencodeScan && !retryKimiScan && !retryOmpScan && previousMeta.version === SIDECAR_VERSION &&
2195
2227
  Number.isFinite(checkedAt) &&
2196
2228
  Date.now() - checkedAt < Math.max(0, Number(cacheTtlMs) || 0)
2197
2229
  ) {
@@ -2223,13 +2255,15 @@ async function buildSessionAnalyticsInternal({ home = os.homedir(), force = fals
2223
2255
  ...discovered.codex.flat().map(codexTitleIndexPathFor).filter(Boolean),
2224
2256
  ...discovered.kimi,
2225
2257
  ...kimiSessionDependencies(discovered.kimi),
2258
+ ...discovered.omp,
2259
+ ...ompSessionDependencies(discovered.omp),
2226
2260
  ...discovered.grok,
2227
2261
  ...discovered.grok.map(grokSummaryPathFor),
2228
2262
  ...discovered.grok.map(grokSignalsPathFor),
2229
2263
  // db + its WAL sidecars: the trio is one logical file for change detection.
2230
2264
  ...[...(discovered.zcode || []), ...(discovered.opencode || [])].flatMap((dbPath) => [dbPath, `${dbPath}-wal`, `${dbPath}-shm`]),
2231
2265
  ]);
2232
- if (!force && !retryZcodeScan && !retryOpencodeScan && !retryKimiScan && previousMeta?.version === SIDECAR_VERSION && previousMeta.signature === signature) {
2266
+ if (!force && !retryZcodeScan && !retryOpencodeScan && !retryKimiScan && !retryOmpScan && previousMeta?.version === SIDECAR_VERSION && previousMeta.signature === signature) {
2233
2267
  await writeAtomic(metaPath, `${JSON.stringify({ ...previousMeta, checked_at: new Date().toISOString() })}\n`);
2234
2268
  return readSidecar(sidecarPath);
2235
2269
  }
@@ -2252,6 +2286,7 @@ async function buildSessionAnalyticsInternal({ home = os.homedir(), force = fals
2252
2286
  ...(discovered.zcode.length ? [{ source: "zcode", filePath: discovered.zcode, scan: scanZcodeSessions }] : []),
2253
2287
  ...(discovered.opencode.length ? [{ source: "opencode", filePath: discovered.opencode, scan: scanOpencodeSessions }] : []),
2254
2288
  ...(discovered.kimi.length ? [{ source: "kimi", filePath: discovered.kimi, scan: scanKimiSessions }] : []),
2289
+ ...(discovered.omp.length ? [{ source: "omp", filePath: discovered.omp, scan: scanOmpSessions }] : []),
2255
2290
  ];
2256
2291
  // Files we could not turn into a row (permission denied, half-written line,
2257
2292
  // vanished mid-scan). Swallowing these silently made sessions disappear with
@@ -2260,6 +2295,7 @@ async function buildSessionAnalyticsInternal({ home = os.homedir(), force = fals
2260
2295
  let incompleteZcodeScan = false;
2261
2296
  let incompleteOpencodeScan = false;
2262
2297
  let incompleteKimiScan = false;
2298
+ let incompleteOmpScan = false;
2263
2299
  for (const entry of entries) {
2264
2300
  const cacheKey = sessionFileCacheKey(entry.source, entry.filePath);
2265
2301
  const statKey = analyticsEntryStatKey(entry.source, entry.filePath);
@@ -2268,11 +2304,12 @@ async function buildSessionAnalyticsInternal({ home = os.homedir(), force = fals
2268
2304
  if (entry.source === "zcode") incompleteZcodeScan = true;
2269
2305
  if (entry.source === "opencode") incompleteOpencodeScan = true;
2270
2306
  if (entry.source === "kimi") incompleteKimiScan = true;
2307
+ if (entry.source === "omp") incompleteOmpScan = true;
2271
2308
  continue;
2272
2309
  }
2273
2310
  let rows = null;
2274
- if (!force && !(entry.source === "zcode" && retryZcodeScan) && !(entry.source === "opencode" && retryOpencodeScan) && !(entry.source === "kimi" && retryKimiScan) && previousFiles[cacheKey]?.stat_key === statKey) {
2275
- if (entry.source === "zcode" || entry.source === "opencode" || entry.source === "kimi") {
2311
+ if (!force && !(entry.source === "zcode" && retryZcodeScan) && !(entry.source === "opencode" && retryOpencodeScan) && !(entry.source === "kimi" && retryKimiScan) && !(entry.source === "omp" && retryOmpScan) && previousFiles[cacheKey]?.stat_key === statKey) {
2312
+ if (entry.source === "zcode" || entry.source === "opencode" || entry.source === "kimi" || entry.source === "omp") {
2276
2313
  // One db scans to many cached rows; recover them all from the previous
2277
2314
  // pass. An empty recovery means the sidecar lost its rows — rescan.
2278
2315
  const cached = previousRows.filter((row) => row?.source === entry.source);
@@ -2293,6 +2330,7 @@ async function buildSessionAnalyticsInternal({ home = os.homedir(), force = fals
2293
2330
  if (entry.source === "zcode") incompleteZcodeScan = true;
2294
2331
  if (entry.source === "opencode") incompleteOpencodeScan = true;
2295
2332
  if (entry.source === "kimi") incompleteKimiScan = true;
2333
+ if (entry.source === "omp") incompleteOmpScan = true;
2296
2334
  if (!process.env.NODE_TEST_CONTEXT) {
2297
2335
  console.warn(`[session-analytics] skipped ${entry.source} session file: ${error?.message || error}`);
2298
2336
  }
@@ -2306,7 +2344,7 @@ async function buildSessionAnalyticsInternal({ home = os.homedir(), force = fals
2306
2344
  // so key each by the db path plus its session id; a bare session id as a
2307
2345
  // separate path element would be path.resolve()d against the process cwd
2308
2346
  // and never match across runs.
2309
- row._cache_key = (entry.source === "zcode" || entry.source === "opencode" || entry.source === "kimi") && (row.session_id || row.session_hash)
2347
+ row._cache_key = (entry.source === "zcode" || entry.source === "opencode" || entry.source === "kimi" || entry.source === "omp") && (row.session_id || row.session_hash)
2310
2348
  ? `${cacheKey}#${sessionHash(entry.source, row.session_id || row.session_hash)}`
2311
2349
  : cacheKey;
2312
2350
  sessions.push(row);
@@ -2330,10 +2368,14 @@ async function buildSessionAnalyticsInternal({ home = os.homedir(), force = fals
2330
2368
  await writeAtomic(incompleteKimiPath, "1\n");
2331
2369
  sessions.push(...readSidecar(sidecarPath).filter((row) => row.source === "kimi" && row.version === SIDECAR_VERSION));
2332
2370
  }
2371
+ if (incompleteOmpScan) {
2372
+ await writeAtomic(incompleteOmpPath, "1\n");
2373
+ sessions.push(...readSidecar(sidecarPath).filter((row) => row.source === "omp" && row.version === SIDECAR_VERSION));
2374
+ }
2333
2375
  sessions.sort((a, b) => String(b.ended_at || "").localeCompare(String(a.ended_at || "")));
2334
2376
  // A failed database scan is an incomplete inventory. Keep the last complete
2335
2377
  // snapshot and signature so an unchanged database is retried next build.
2336
- if (incompleteDirs.length === 0 && !incompleteZcodeScan && !incompleteOpencodeScan && !incompleteKimiScan) {
2378
+ if (incompleteDirs.length === 0 && !incompleteZcodeScan && !incompleteOpencodeScan && !incompleteKimiScan && !incompleteOmpScan) {
2337
2379
  const content = sessions.map(serializeSessionRecord).join("\n") + (sessions.length ? "\n" : "");
2338
2380
  await writeAtomic(sidecarPath, content);
2339
2381
  const generatedAt = new Date().toISOString();
@@ -2347,6 +2389,7 @@ async function buildSessionAnalyticsInternal({ home = os.homedir(), force = fals
2347
2389
  await fsp.rm(incompleteZcodePath, { force: true });
2348
2390
  await fsp.rm(incompleteOpencodePath, { force: true });
2349
2391
  await fsp.rm(incompleteKimiPath, { force: true });
2392
+ await fsp.rm(incompleteOmpPath, { force: true });
2350
2393
  }
2351
2394
  // Non-enumerable so the array still behaves exactly like a plain row list
2352
2395
  // for every existing caller (map/filter/JSON of the rows is unaffected).
@@ -2632,6 +2675,7 @@ function resumeCommandFor(source, sessionId) {
2632
2675
  // Grok Build: `grok --resume <session-id>` (also accepts a title). The
2633
2676
  // command must still be run from the session's project_ref cwd.
2634
2677
  if (source === "grok") return `grok --resume ${id}`;
2678
+ if (source === "omp") return `omp --resume ${id}`;
2635
2679
  return null;
2636
2680
  }
2637
2681
 
@@ -2973,6 +3017,8 @@ module.exports = {
2973
3017
  scanZcodeSessions,
2974
3018
  scanOpencodeSessions,
2975
3019
  scanKimiSessions,
3020
+ scanOmpSessions,
3021
+ scanOmpSession,
2976
3022
  buildSessionAnalytics,
2977
3023
  summarizeSessions,
2978
3024
  listSessionsForBrowser,
@@ -2,7 +2,8 @@
2
2
 
3
3
  /**
4
4
  * TRAE Work CN (国内版) config + usage fetch. Phase A: macOS + Windows + test-injected
5
- * paths only. Resolves the CN home, reads the `iCubeAuthInfo://icube.cloudide`
5
+ * paths only. Resolves the CN app data directory (TRAE Work CN or the classic
6
+ * Trae CN client), reads the `iCubeAuthInfo://icube.cloudide`
6
7
  * blob from User/globalStorage/storage.json (plaintext JSON or Base64 tc v5),
7
8
  * and talks to the TRAE CN usage API. JWTs / refresh tokens are never
8
9
  * persisted, never logged, and never put into error messages; a
@@ -31,7 +32,7 @@ function isTraeCnUsageEnabled(env = process.env) {
31
32
  const normalized = typeof value === "string" ? value.trim().toLowerCase() : "";
32
33
  return normalized === "1" || normalized === "true";
33
34
  }
34
- const TRAE_CN_APP_DIR = "TRAE SOLO CN";
35
+ const TRAE_CN_APP_DIRS = ["TRAE SOLO CN", "Trae CN"];
35
36
  const TRAE_CN_AUTH_KEY = "iCubeAuthInfo://icube.cloudide";
36
37
 
37
38
  const TRAE_CN_USAGE_URL = "https://api.trae.cn/trae/api/v1/pay/query_user_usage_group_by_session";
@@ -77,30 +78,46 @@ const TRAE_CN_KG = Buffer.from([
77
78
  // Path resolution
78
79
  // ---------------------------------------------------------------------------
79
80
 
80
- function resolveTraeCnHome({ env = process.env, home = os.homedir(), platform = process.platform } = {}) {
81
- const override = env[TRAE_CN_HOME_ENV];
82
- if (typeof override === "string" && override.trim()) {
83
- return path.resolve(override.trim());
84
- }
81
+ function traeCnDataParent({ env = process.env, home = os.homedir(), platform = process.platform } = {}) {
85
82
  if (platform === "darwin") {
86
- return path.join(home, "Library", "Application Support", TRAE_CN_APP_DIR);
83
+ return path.join(home, "Library", "Application Support");
87
84
  }
88
85
  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);
86
+ // Windows keeps the CN app under the roaming profile, mirroring the
87
+ // macOS Application Support layout (<parent>/<app dir>/User/...).
88
+ return typeof env.APPDATA === "string" && env.APPDATA.trim()
89
+ ? env.APPDATA.trim()
90
+ : path.join(home, "AppData", "Roaming");
96
91
  }
97
- // No verified CN Work app-data layout on other platforms yet.
92
+ // No verified CN app-data layout on other platforms yet.
98
93
  return null;
99
94
  }
100
95
 
101
96
  function resolveTraeCnStoragePath(options = {}) {
102
- const home = resolveTraeCnHome(options);
103
- return home ? path.join(home, "User", "globalStorage", "storage.json") : null;
97
+ const env = options.env ?? process.env;
98
+ const override = env[TRAE_CN_HOME_ENV];
99
+ if (typeof override === "string" && override.trim()) {
100
+ return path.join(path.resolve(override.trim()), "User", "globalStorage", "storage.json");
101
+ }
102
+ const parent = traeCnDataParent({ env, home: options.home ?? os.homedir(), platform: options.platform ?? process.platform });
103
+ if (!parent) return null;
104
+ for (const dir of TRAE_CN_APP_DIRS) {
105
+ const candidate = path.join(parent, dir, "User", "globalStorage", "storage.json");
106
+ try {
107
+ // Any successful stat means this client dir is the discovery hit —
108
+ // including a non-file path (e.g. a directory named storage.json).
109
+ // Hand that to the reader so EISDIR surfaces as TRAE_CN_STORAGE_UNREADABLE
110
+ // instead of silently skipping to the next client or reporting absent.
111
+ fs.statSync(candidate);
112
+ return candidate;
113
+ } catch (err) {
114
+ // Permission failures must reach the reader's diagnostics, not
115
+ // masquerade as an absent installation and silently drop an entire
116
+ // usage history (same discovery policy as trae-db.js).
117
+ if (err.code !== "ENOENT" && err.code !== "ENOTDIR") return candidate;
118
+ }
119
+ }
120
+ return null;
104
121
  }
105
122
 
106
123
  // ---------------------------------------------------------------------------
@@ -524,7 +541,7 @@ module.exports = {
524
541
  TRAE_CN_HOME_ENV,
525
542
  TRAE_CN_USAGE_ENV,
526
543
  isTraeCnUsageEnabled,
527
- TRAE_CN_APP_DIR,
544
+ TRAE_CN_APP_DIRS,
528
545
  TRAE_CN_AUTH_KEY,
529
546
  TRAE_CN_USAGE_URL,
530
547
  TRAE_CN_USAGE_TYPE,
@@ -532,7 +549,6 @@ module.exports = {
532
549
  TRAE_CN_USAGE_MAX_PAGES,
533
550
  TRAE_CN_USAGE_DELAY_MS,
534
551
  TRAE_CN_MAGIC,
535
- resolveTraeCnHome,
536
552
  resolveTraeCnStoragePath,
537
553
  traeCnHardcodedKdfSecret,
538
554
  deriveTraeCnKeyIv,
@@ -1 +0,0 @@
1
- import{r as n,J as a}from"./__vite-browser-external-ClVJNQu3.js";import{u as p}from"./DialogTitle-Cd_k-Nyw.js";import{u as c}from"./composite-CdExmgTx.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-ClVJNQu3.js";import{h as r,i as t,p as s}from"./react-DMs4C4qS.js";function i(){!r.current&&t();const[e]=o.useState(s.current);return e}export{i as u};