tokentracker-cli 1.5.12 → 1.5.14
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/dashboard/dist/assets/{AchievementBadge-DvcPjqX7.js → AchievementBadge-DqJWve1h.js} +1 -1
- package/dashboard/dist/assets/{AchievementsPage-C9AkvdHe.js → AchievementsPage-CnuBayj3.js} +2 -2
- package/dashboard/dist/assets/{AchievementsSection-g0JGNGfT.js → AchievementsSection-WRU5TxAB.js} +1 -1
- package/dashboard/dist/assets/{BadgeDetailModal-BHxQ8umD.js → BadgeDetailModal-B5ikEQik.js} +1 -1
- package/dashboard/dist/assets/{BotAnimated-C5Byp7Ml.js → BotAnimated-CaMG6j-6.js} +1 -1
- package/dashboard/dist/assets/{Card-BV1iTPCd.js → Card-BL3vxENk.js} +1 -1
- package/dashboard/dist/assets/{CloudCheckoutPage-DcAvPHXS.js → CloudCheckoutPage-CsUb8CJ7.js} +1 -1
- package/dashboard/dist/assets/{CloudPage-pw82pCP6.js → CloudPage-5ZiPFzeC.js} +2 -2
- package/dashboard/dist/assets/{CommandPalette-B88IfMHd.js → CommandPalette-CYd9nXW-.js} +1 -1
- package/dashboard/dist/assets/{CommunityStatsModal-DwtEZ96Z.js → CommunityStatsModal-BItox7Sz.js} +1 -1
- package/dashboard/dist/assets/{ConfirmModal-Cx1-1xUk.js → ConfirmModal-BE1ABR4z.js} +1 -1
- package/dashboard/dist/assets/{Controls-hHP6yz1h.js → Controls-BRqIsaHT.js} +1 -1
- package/dashboard/dist/assets/{DashboardPage-Cz98astU.js → DashboardPage-Cm0YuBlx.js} +1 -1
- package/dashboard/dist/assets/{DateRangePopover-BjsUociY.js → DateRangePopover-CRwEu66e.js} +1 -1
- package/dashboard/dist/assets/{DevicePage-C0ZyCHAD.js → DevicePage-DFUPsGb_.js} +1 -1
- package/dashboard/dist/assets/{DialogClose-eeerEmfs.js → DialogClose-DALl4GmP.js} +1 -1
- package/dashboard/dist/assets/DialogDescription-CO0hykis.js +1 -0
- package/dashboard/dist/assets/{DialogTitle-Bn14t_Xd.js → DialogTitle-BSR8ozyn.js} +1 -1
- package/dashboard/dist/assets/{ElectricLogo-OyoU_h0I.js → ElectricLogo-BtrycBUW.js} +1 -1
- package/dashboard/dist/assets/{FadeIn-BbC4-H2A.js → FadeIn-CfhgvLVd.js} +1 -1
- package/dashboard/dist/assets/{HeaderGithubStar-B2CCV29J.js → HeaderGithubStar-N8wqAdOf.js} +1 -1
- package/dashboard/dist/assets/{HoverTooltip-DiD_l4GJ.js → HoverTooltip-CwdMYIzZ.js} +1 -1
- package/dashboard/dist/assets/{IpCheckPage-1HwHzeVT.js → IpCheckPage-DCRor9cb.js} +1 -1
- package/dashboard/dist/assets/{LandingPage-Cx_xIavm.js → LandingPage-s9xvTHSp.js} +2 -2
- package/dashboard/dist/assets/{LeaderboardPage-BsP635cI.js → LeaderboardPage-CUj3WLMo.js} +2 -2
- package/dashboard/dist/assets/{LeaderboardProBadge-B7uhXYjD.js → LeaderboardProBadge-N4NOKZWj.js} +1 -1
- package/dashboard/dist/assets/{LeaderboardProfileModal-_QOUdhsi.js → LeaderboardProfileModal-09HiUyxm.js} +3 -3
- package/dashboard/dist/assets/{LeaderboardProfilePage-CSpx6Rw5.js → LeaderboardProfilePage-Cw9_rodG.js} +1 -1
- package/dashboard/dist/assets/{LimitsPage-DOj_2vh6.js → LimitsPage-F8b6kZa0.js} +1 -1
- package/dashboard/dist/assets/{LocalOnlyNotice-DnkG5DmI.js → LocalOnlyNotice-D1eEzDEv.js} +1 -1
- package/dashboard/dist/assets/{LoginCard-Ds9kOBpV.js → LoginCard-0sIovG_J.js} +1 -1
- package/dashboard/dist/assets/{LoginModal-B-7fS0gK.js → LoginModal-BT3oMVak.js} +1 -1
- package/dashboard/dist/assets/{LoginPage-B2K2tXvd.js → LoginPage-CDsXdaE5.js} +1 -1
- package/dashboard/dist/assets/{PetPage-DwsDJxX_.js → PetPage-BEnC1azp.js} +2 -2
- package/dashboard/dist/assets/{PopoverPopup-CqUafQx4.js → PopoverPopup-Dwzp-hyf.js} +1 -1
- package/dashboard/dist/assets/{ProviderIcon-BcE1tBpR.js → ProviderIcon-Cu_lcuuu.js} +1 -1
- package/dashboard/dist/assets/{ResetPasswordPage-CP17McXH.js → ResetPasswordPage-DrpEscm1.js} +1 -1
- package/dashboard/dist/assets/{Select-BcFrd0ex.js → Select-wIR4qvEI.js} +1 -1
- package/dashboard/dist/assets/{SelectItemText-C-FBw54p.js → SelectItemText-CNuJgYps.js} +1 -1
- package/dashboard/dist/assets/{SelfHostPage--4KcyhvD.js → SelfHostPage-CWNLygpL.js} +1 -1
- package/dashboard/dist/assets/{ServiceStatusPage-C4GQ-8Tm.js → ServiceStatusPage-BId9t16Q.js} +1 -1
- package/dashboard/dist/assets/{SessionsPage-DMW3U0i3.js → SessionsPage-C_klx7d8.js} +1 -1
- package/dashboard/dist/assets/{SettingsPage-sYLabRGu.js → SettingsPage-nC73JaZ4.js} +3 -3
- package/dashboard/dist/assets/{SkillsPage-CkjmvAds.js → SkillsPage-B2agou8Y.js} +1 -1
- package/dashboard/dist/assets/{TokenGalaxy-BfJtQKzg.js → TokenGalaxy-BNXUWRwa.js} +1 -1
- package/dashboard/dist/assets/{TooltipPopup-BxvShS92.js → TooltipPopup--X2kExQ0.js} +1 -1
- package/dashboard/dist/assets/{TrendMonitor-C9cHT4G_.js → TrendMonitor-BELHsTnz.js} +1 -1
- package/dashboard/dist/assets/{WidgetsPage-BqlH3M7h.js → WidgetsPage-DWp0SMXA.js} +1 -1
- package/dashboard/dist/assets/{WrappedPage-D2A1zcGs.js → WrappedPage-DgwczKHe.js} +1 -1
- package/dashboard/dist/assets/{__vite-browser-external-RPZeXrAv.js → __vite-browser-external-BHphZRSC.js} +2 -2
- package/dashboard/dist/assets/{agent-logos-CKAwJGNX.js → agent-logos-Cfx5WzU5.js} +1 -1
- package/dashboard/dist/assets/{arrow-left-sB5X7dRY.js → arrow-left-D83SdANw.js} +1 -1
- package/dashboard/dist/assets/{arrow-right-Cvwg139b.js → arrow-right-D7ye9bmJ.js} +1 -1
- package/dashboard/dist/assets/{arrow-up-right-H5sP370z.js → arrow-up-right-CLmwEwwC.js} +1 -1
- package/dashboard/dist/assets/{calendar-days-B6p2eInB.js → calendar-days-D1qLlvh4.js} +1 -1
- package/dashboard/dist/assets/{check-DgFRXvUP.js → check-BHJvi4ey.js} +1 -1
- package/dashboard/dist/assets/{chevron-down-D-ny8IBp.js → chevron-down-6RBPKNpt.js} +1 -1
- package/dashboard/dist/assets/{cloud-checkout-CT_OgBOA.js → cloud-checkout-DgWcF-at.js} +1 -1
- package/dashboard/dist/assets/{composite-BJuoijSA.js → composite-D-0pfyMY.js} +1 -1
- package/dashboard/dist/assets/{copy-JdswLd9u.js → copy-B6mJSQsD.js} +1 -1
- package/dashboard/dist/assets/{download-BI-n3YEd.js → download-D31Nn-bI.js} +1 -1
- package/dashboard/dist/assets/{external-link-CH7tksO4.js → external-link-C_lK9S3p.js} +1 -1
- package/dashboard/dist/assets/{flame-CP7hkBXq.js → flame-1ZxhHshT.js} +1 -1
- package/dashboard/dist/assets/{format-tokens-Biw6wloc.js → format-tokens-DJk25SkD.js} +1 -1
- package/dashboard/dist/assets/{gift-Dz9MeN8q.js → gift-BUZzFh-1.js} +1 -1
- package/dashboard/dist/assets/{icons-DP4Ni8VA.js → icons-BVPThCa4.js} +1 -1
- package/dashboard/dist/assets/{index-kQETJkOr.js → index-B-mxrdIz.js} +1 -1
- package/dashboard/dist/assets/{index-SXavLLcl.js → index-C0zFsOWh.js} +1 -1
- package/dashboard/dist/assets/{index-CIfh9hNs.js → index-CjPsyTl7.js} +1 -1
- package/dashboard/dist/assets/{index-BkeoJvCA.js → index-CzstoU6d.js} +1 -1
- package/dashboard/dist/assets/{info-Bba3RZJA.js → info-DmU-vlJ6.js} +1 -1
- package/dashboard/dist/assets/{link-2-B2C7-GOt.js → link-2-BlBM7uw7.js} +1 -1
- package/dashboard/dist/assets/{loader-circle-Dld8yUT7.js → loader-circle-Dhrb_Ocy.js} +1 -1
- package/dashboard/dist/assets/{local-usage-transfer-CAuRHyVW.js → local-usage-transfer-BudmMtkd.js} +1 -1
- package/dashboard/dist/assets/{modifiers.esm-CtFVyyHC.js → modifiers.esm-kmw1VM8W.js} +1 -1
- package/dashboard/dist/assets/{monitor-smartphone-iFNG6h_M.js → monitor-smartphone-DtjXNC_x.js} +1 -1
- package/dashboard/dist/assets/{play-C7GLNAdX.js → play-9w46lbjy.js} +1 -1
- package/dashboard/dist/assets/{plus-CSKQToSA.js → plus-DAf_WGKT.js} +1 -1
- package/dashboard/dist/assets/{provider-display-BwVQXnb2.js → provider-display-BZ0XlB2q.js} +1 -1
- package/dashboard/dist/assets/{react-Cy_Eczdb.js → react-B01ZJuZY.js} +1 -1
- package/dashboard/dist/assets/{safePolygon-DiPfgohh.js → safePolygon-B6_x12Gb.js} +1 -1
- package/dashboard/dist/assets/{search-DKyVdlXG.js → search-D3dW9GbV.js} +1 -1
- package/dashboard/dist/assets/{server-DaU0lAOr.js → server-C2XZBar7.js} +1 -1
- package/dashboard/dist/assets/{shield-check-DWiYKLWx.js → shield-check-4FX5vbS7.js} +1 -1
- package/dashboard/dist/assets/{skills-api-CXotXIRt.js → skills-api-BvW_MUyg.js} +1 -1
- package/dashboard/dist/assets/{sortable.esm-ON-92Wzk.js → sortable.esm-CAa_BJgh.js} +1 -1
- package/dashboard/dist/assets/{store-C91MN0gm.js → store-2AX2MNkz.js} +1 -1
- package/dashboard/dist/assets/{terminal-CZUta1FC.js → terminal-CON7n_ir.js} +1 -1
- package/dashboard/dist/assets/{trash-dOvHm24W.js → trash-C2f88jSi.js} +1 -1
- package/dashboard/dist/assets/{use-community-stats-BD3O7D_G.js → use-community-stats-CgQu43xV.js} +1 -1
- package/dashboard/dist/assets/{use-latest-request-guard-Geg2sygc.js → use-latest-request-guard-lShM46-3.js} +1 -1
- package/dashboard/dist/assets/{use-limits-display-prefs-Ck2CuPqb.js → use-limits-display-prefs-8o7pbEg0.js} +1 -1
- package/dashboard/dist/assets/{use-native-settings-3DH5xldB.js → use-native-settings-dN8shG3M.js} +1 -1
- package/dashboard/dist/assets/{use-ordered-list-BonkP7AB.js → use-ordered-list-beJy2IqQ.js} +1 -1
- package/dashboard/dist/assets/use-reduced-motion-S0bR_G1B.js +1 -0
- package/dashboard/dist/assets/{use-transform-C32HObUN.js → use-transform-cJpAQr2d.js} +1 -1
- package/dashboard/dist/assets/{use-usage-limits-6GFRuUdV.js → use-usage-limits-CuusZA6b.js} +1 -1
- package/dashboard/dist/assets/{useCurrency-BsGBVGb5.js → useCurrency-Cx9UsKJK.js} +1 -1
- package/dashboard/dist/assets/{usePositioner-DvFrrUs0.js → usePositioner-TEClK6mF.js} +1 -1
- package/dashboard/dist/assets/{useTokenFormat-Dryg74BA.js → useTokenFormat-BNwTLiac.js} +1 -1
- package/dashboard/dist/assets/{zap-BL_hxkkj.js → zap-CFgbVEhC.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/init.js +30 -16
- package/src/commands/serve.js +28 -25
- package/src/commands/sync.js +3 -3
- package/src/lib/cursor-store.js +5 -1
- package/src/lib/local-api.js +25 -11
- package/src/lib/pricing/seed-snapshot.json +1 -1
- package/src/lib/rollout.js +262 -59
- package/src/lib/runtime-copy.js +77 -0
- package/dashboard/dist/assets/DialogDescription-DG_4qSj0.js +0 -1
- package/dashboard/dist/assets/use-reduced-motion-uryC1l51.js +0 -1
package/src/commands/init.js
CHANGED
|
@@ -11,7 +11,9 @@ const {
|
|
|
11
11
|
readJson,
|
|
12
12
|
writeJson,
|
|
13
13
|
chmod600IfPossible,
|
|
14
|
+
openLock,
|
|
14
15
|
} = require("../lib/fs");
|
|
16
|
+
const { copyRuntimeTree, ensureRuntimeDirectory } = require("../lib/runtime-copy");
|
|
15
17
|
const { resolveMimoNativeDbPath } = require("../lib/install-resolver");
|
|
16
18
|
const { resolveDumateDbPaths } = require("../lib/dumate");
|
|
17
19
|
const { expandHome } = require("../lib/scan-roots");
|
|
@@ -2291,7 +2293,7 @@ async function installLocalTrackerApp({ appDir }) {
|
|
|
2291
2293
|
// Copy the current package's runtime (bin + src) into ~/.tokentracker so notify can run sync without npx.
|
|
2292
2294
|
const packageRoot = path.resolve(__dirname, "../..");
|
|
2293
2295
|
const srcFrom = path.join(packageRoot, "src");
|
|
2294
|
-
const binFrom = path.join(packageRoot, "bin"
|
|
2296
|
+
const binFrom = path.join(packageRoot, "bin");
|
|
2295
2297
|
const packageJsonFrom = path.join(packageRoot, "package.json");
|
|
2296
2298
|
const nodeModulesFrom = path.join(packageRoot, "node_modules");
|
|
2297
2299
|
const dashboardDistFrom = path.join(packageRoot, "dashboard", "dist");
|
|
@@ -2308,17 +2310,31 @@ async function installLocalTrackerApp({ appDir }) {
|
|
|
2308
2310
|
const nodeModulesTo = path.join(appDir, "node_modules");
|
|
2309
2311
|
const dashboardDistTo = path.join(appDir, "dashboard", "dist");
|
|
2310
2312
|
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
await
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
await
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2313
|
+
// Serialize installers: init and desktop startup can overlap. In particular,
|
|
2314
|
+
// one refresh must not prune another writer's atomic temporary files.
|
|
2315
|
+
await ensureDir(path.dirname(appDir));
|
|
2316
|
+
const deadline = Date.now() + 120_000;
|
|
2317
|
+
let lock;
|
|
2318
|
+
while (!(lock = await openLock(`${appDir}.install.lock`, { quietIfLocked: true }))) {
|
|
2319
|
+
if (Date.now() >= deadline) throw new Error("Timed out waiting for local runtime installation");
|
|
2320
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
2321
|
+
}
|
|
2322
|
+
try {
|
|
2323
|
+
await ensureRuntimeDirectory(appDir);
|
|
2324
|
+
await copyRuntimeTree(srcFrom, srcTo);
|
|
2325
|
+
await copyRuntimeTree(binFrom, binToDir);
|
|
2326
|
+
await fs.chmod(binTo, 0o755).catch(() => {});
|
|
2327
|
+
if (await isDir(dashboardDistFrom)) {
|
|
2328
|
+
await ensureRuntimeDirectory(path.dirname(dashboardDistTo));
|
|
2329
|
+
await copyRuntimeTree(dashboardDistFrom, dashboardDistTo);
|
|
2330
|
+
} else {
|
|
2331
|
+
await fs.rm(path.dirname(dashboardDistTo), { recursive: true, force: true });
|
|
2332
|
+
}
|
|
2333
|
+
await copyRuntimeDependencies({ from: nodeModulesFrom, to: nodeModulesTo });
|
|
2334
|
+
await copyRuntimeTree(packageJsonFrom, path.join(appDir, "package.json"));
|
|
2335
|
+
} finally {
|
|
2336
|
+
await lock.release();
|
|
2320
2337
|
}
|
|
2321
|
-
await copyRuntimeDependencies({ from: nodeModulesFrom, to: nodeModulesTo });
|
|
2322
2338
|
}
|
|
2323
2339
|
|
|
2324
2340
|
async function pathsPointToSameLocation(a, b) {
|
|
@@ -2427,15 +2443,13 @@ function readFirstSyncTotals(trackerDir) {
|
|
|
2427
2443
|
}
|
|
2428
2444
|
|
|
2429
2445
|
async function copyRuntimeDependencies({ from, to }) {
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
if (!st.isDirectory()) return;
|
|
2433
|
-
} catch (_e) {
|
|
2446
|
+
if (!(await isDir(from))) {
|
|
2447
|
+
await fs.rm(to, { recursive: true, force: true });
|
|
2434
2448
|
return;
|
|
2435
2449
|
}
|
|
2436
2450
|
|
|
2437
2451
|
try {
|
|
2438
|
-
await
|
|
2452
|
+
await copyRuntimeTree(from, to);
|
|
2439
2453
|
} catch (_e) {
|
|
2440
2454
|
// Best-effort: missing dependencies will fall back to npx at notify time.
|
|
2441
2455
|
}
|
package/src/commands/serve.js
CHANGED
|
@@ -83,32 +83,9 @@ async function cmdServe(argv) {
|
|
|
83
83
|
// the setup never commits cursors.json (#961).
|
|
84
84
|
const { trackerDir, binDir } = await resolveTrackerPaths();
|
|
85
85
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
await installLocalTrackerApp({ appDir: path.join(trackerDir, "app") });
|
|
89
|
-
const repairResult = await repairRuntimeIntegrations({ trackerDir, binDir, safeMode: true });
|
|
90
|
-
for (const warning of repairResult?.warnings || []) {
|
|
91
|
-
process.stdout.write(
|
|
92
|
-
`Runtime integration repair warning (${warning.integration}): ${warning.error}\n`,
|
|
93
|
-
);
|
|
94
|
-
}
|
|
95
|
-
} catch (e) {
|
|
96
|
-
process.stdout.write(`Runtime refresh warning: ${e?.message || e}\n`);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Optional sync for non-first-run launches. First-run init still owns its
|
|
100
|
-
// inline first sync below, after the listener is up.
|
|
86
|
+
// All runtime maintenance and initial sync run after listen. The dashboard
|
|
87
|
+
// is served from this package, not the hook runtime installed in trackerDir.
|
|
101
88
|
const needsFirstRunSetup = !fssync.existsSync(path.join(trackerDir, "cursors.json"));
|
|
102
|
-
if (opts.sync && !needsFirstRunSetup) {
|
|
103
|
-
process.stdout.write("Syncing local data...\n");
|
|
104
|
-
try {
|
|
105
|
-
const { cmdSync } = require("./sync");
|
|
106
|
-
await cmdSync(["--auto"]);
|
|
107
|
-
process.stdout.write("Sync done.\n");
|
|
108
|
-
} catch (e) {
|
|
109
|
-
process.stdout.write(`Sync warning: ${e?.message || e}\n`);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
89
|
|
|
113
90
|
// Resolve paths
|
|
114
91
|
const queuePath = resolveQueuePath();
|
|
@@ -240,6 +217,32 @@ async function cmdServe(argv) {
|
|
|
240
217
|
}
|
|
241
218
|
}
|
|
242
219
|
|
|
220
|
+
// A large Windows runtime copy can take tens of seconds. Health probes and
|
|
221
|
+
// the dashboard must already work while maintenance is in progress.
|
|
222
|
+
try {
|
|
223
|
+
const { installLocalTrackerApp, repairRuntimeIntegrations } = require("./init");
|
|
224
|
+
await installLocalTrackerApp({ appDir: path.join(trackerDir, "app") });
|
|
225
|
+
const repairResult = await repairRuntimeIntegrations({ trackerDir, binDir, safeMode: true });
|
|
226
|
+
for (const warning of repairResult?.warnings || []) {
|
|
227
|
+
process.stdout.write(
|
|
228
|
+
`Runtime integration repair warning (${warning.integration}): ${warning.error}\n`,
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
} catch (e) {
|
|
232
|
+
process.stdout.write(`Runtime refresh warning: ${e?.message || e}\n`);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (opts.sync && !needsFirstRunSetup) {
|
|
236
|
+
process.stdout.write("Syncing local data...\n");
|
|
237
|
+
try {
|
|
238
|
+
const { cmdSync } = require("./sync");
|
|
239
|
+
await cmdSync(["--auto"]);
|
|
240
|
+
process.stdout.write("Sync done.\n");
|
|
241
|
+
} catch (e) {
|
|
242
|
+
process.stdout.write(`Sync warning: ${e?.message || e}\n`);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
243
246
|
// First-time setup AFTER the listener is accepting health probes. Init still
|
|
244
247
|
// runs inline (including first sync) so the dashboard fills in, but native
|
|
245
248
|
// hosts can mark the server Running without racing that sync (#961).
|
package/src/commands/sync.js
CHANGED
|
@@ -315,7 +315,7 @@ const DROID_DUP_SESSION_REPAIR_KEY = "droidDupSessionInflationRepair_2026_06";
|
|
|
315
315
|
const CODEX_COLD_SCAN_AUDIT_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
316
316
|
const NOTIFY_LOCK_WAIT_MS = 130_000;
|
|
317
317
|
const NOTIFY_LOCK_POLL_MS = 5_000;
|
|
318
|
-
// Local API sync requests
|
|
318
|
+
// Local API sync requests answer within a 120-second wait window. Reserve at
|
|
319
319
|
// least 30 seconds for parsing, persistence, and the response after contention.
|
|
320
320
|
const PRIORITY_LOCK_WAIT_MS = 90_000;
|
|
321
321
|
const PRIORITY_LOCK_POLL_MS = 250;
|
|
@@ -1854,7 +1854,7 @@ async function cmdSync(argv, context = {}) {
|
|
|
1854
1854
|
if (sourceAllowed("dsh")) {
|
|
1855
1855
|
await migrateLegacyDeepseekHarnessSource({ cursors, queuePath, queueStatePath });
|
|
1856
1856
|
const dshSessionFiles = await resolveDshSessionFiles(process.env);
|
|
1857
|
-
if (dshSessionFiles.length > 0) {
|
|
1857
|
+
if (dshSessionFiles.length > 0 || cursors.dsh) {
|
|
1858
1858
|
if (progress?.enabled) {
|
|
1859
1859
|
progress.start(
|
|
1860
1860
|
`Parsing DeepSeek Harness ${renderBar(0)} 0/${formatNumber(
|
|
@@ -1873,7 +1873,7 @@ async function cmdSync(argv, context = {}) {
|
|
|
1873
1873
|
warnProviderParseFailure(
|
|
1874
1874
|
"DeepSeek Harness",
|
|
1875
1875
|
new Error(
|
|
1876
|
-
`${dshResult.deferredMigrations} artifact migration(s) deferred; inspect cursors.dsh.deferredMigrations
|
|
1876
|
+
`${dshResult.deferredMigrations} accounting repair/artifact migration(s) deferred; inspect cursors.dsh.deferredMigrations, restore unavailable history or complete the replacement, then retry`,
|
|
1877
1877
|
),
|
|
1878
1878
|
opts,
|
|
1879
1879
|
);
|
package/src/lib/cursor-store.js
CHANGED
|
@@ -1850,9 +1850,13 @@ async function fingerprintFile(filePath) {
|
|
|
1850
1850
|
}
|
|
1851
1851
|
}
|
|
1852
1852
|
|
|
1853
|
+
// Legacy cursors.json is re-imported only when its content may have changed.
|
|
1854
|
+
// ctime moves on metadata-only events (chmod, xattr, backup tools); comparing
|
|
1855
|
+
// it re-imported a stale snapshot over newer v2 state and forced a full
|
|
1856
|
+
// re-read of every session log.
|
|
1853
1857
|
function sameFingerprint(left, right) {
|
|
1854
1858
|
if (!left || !right) return left === right;
|
|
1855
|
-
return ["dev", "ino", "size", "mtimeNs"
|
|
1859
|
+
return ["dev", "ino", "size", "mtimeNs"]
|
|
1856
1860
|
.every((key) => String(left[key]) === String(right[key]));
|
|
1857
1861
|
}
|
|
1858
1862
|
|
package/src/lib/local-api.js
CHANGED
|
@@ -26,7 +26,9 @@ const { negotiateEncoding } = require("./accept-encoding");
|
|
|
26
26
|
const { createLocalUsageTransfer, MAX_BYTES: LOCAL_USAGE_MAX_BYTES } = require("./local-usage-transfer");
|
|
27
27
|
const { fetchProviderServiceStatus } = require("./provider-status");
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
// How long a local-sync request waits for its sync child before answering.
|
|
30
|
+
// Native clients give up at 130s (macOS) so the server must answer first.
|
|
31
|
+
const SYNC_RESPONSE_WAIT_MS = 120_000;
|
|
30
32
|
// A failed account-view request should not stall every dashboard refresh
|
|
31
33
|
// while an expired session or unreachable backend keeps timing out. The first
|
|
32
34
|
// request still falls back normally; subsequent fan-out requests reuse that
|
|
@@ -910,15 +912,9 @@ function runSyncCommand(extraEnv = {}, opts = {}) {
|
|
|
910
912
|
const finish = (fn, v) => {
|
|
911
913
|
if (settled) return;
|
|
912
914
|
settled = true;
|
|
913
|
-
clearTimeout(tid);
|
|
914
915
|
opts.signal?.removeEventListener("abort", cancel);
|
|
915
916
|
fn(v);
|
|
916
917
|
};
|
|
917
|
-
let timedOut = false;
|
|
918
|
-
const tid = setTimeout(() => {
|
|
919
|
-
timedOut = true;
|
|
920
|
-
child.kill("SIGTERM");
|
|
921
|
-
}, SYNC_TIMEOUT_MS);
|
|
922
918
|
child.stdout?.on("data", (c) => {
|
|
923
919
|
stdout += c;
|
|
924
920
|
});
|
|
@@ -929,7 +925,6 @@ function runSyncCommand(extraEnv = {}, opts = {}) {
|
|
|
929
925
|
finish(reject, Object.assign(e, { stdout: trimOutput(stdout), stderr: trimOutput(stderr) }));
|
|
930
926
|
});
|
|
931
927
|
child.on("close", (code) => {
|
|
932
|
-
if (timedOut) { finish(reject, Object.assign(new Error("Sync timed out"), { code: "SYNC_TIMEOUT", stdout: trimOutput(stdout), stderr: trimOutput(stderr) })); return; }
|
|
933
928
|
if (opts.signal?.aborted) { finish(reject, Object.assign(new Error("Account session changed"), { code: "auth_session_changed", status: 409 })); return; }
|
|
934
929
|
const r = { code: code ?? 1, stdout: trimOutput(stdout), stderr: trimOutput(stderr) };
|
|
935
930
|
if (code === 0) {
|
|
@@ -948,6 +943,23 @@ function runSyncCommand(extraEnv = {}, opts = {}) {
|
|
|
948
943
|
});
|
|
949
944
|
}
|
|
950
945
|
|
|
946
|
+
// The sync child owns its own lifetime: it holds the sync lock and commits its
|
|
947
|
+
// cursors only after the whole scan finishes. Killing it when the HTTP caller
|
|
948
|
+
// stops waiting discarded that progress, so a backlog longer than one wait
|
|
949
|
+
// window was rescanned and killed on every attempt and never landed. The
|
|
950
|
+
// caller gets an answer after `waitMs`; the child keeps running to completion
|
|
951
|
+
// and only an explicit abort (account session change) terminates it.
|
|
952
|
+
function waitForSyncResponse(syncPromise, waitMs = SYNC_RESPONSE_WAIT_MS) {
|
|
953
|
+
let tid;
|
|
954
|
+
const expired = new Promise((_, reject) => {
|
|
955
|
+
tid = setTimeout(() => reject(Object.assign(
|
|
956
|
+
new Error("Sync is still running in the background"),
|
|
957
|
+
{ code: "SYNC_RUNNING", status: 503 },
|
|
958
|
+
)), waitMs);
|
|
959
|
+
});
|
|
960
|
+
return Promise.race([syncPromise, expired]).finally(() => clearTimeout(tid));
|
|
961
|
+
}
|
|
962
|
+
|
|
951
963
|
// ---------------------------------------------------------------------------
|
|
952
964
|
// Project detection helpers
|
|
953
965
|
// ---------------------------------------------------------------------------
|
|
@@ -2577,13 +2589,15 @@ function createLocalApiHandler({ queuePath, serverVersion = null, trackerDataDir
|
|
|
2577
2589
|
waitForLock:
|
|
2578
2590
|
!drain && !background && Boolean(extraEnv.TOKENTRACKER_DEVICE_TOKEN),
|
|
2579
2591
|
});
|
|
2580
|
-
controller
|
|
2581
|
-
|
|
2592
|
+
// The controller tracks the child, not this request: an account switch
|
|
2593
|
+
// must still be able to stop a sync that outlived its HTTP wait.
|
|
2594
|
+
controller.done = syncPromise.catch(() => {}).finally(() => activeCloudSyncs.delete(controller));
|
|
2595
|
+
const result = await waitForSyncResponse(syncPromise).catch((error) => {
|
|
2582
2596
|
if (uploadGeneration !== localCloudGeneration) throw Object.assign(new Error("Account session changed"), { code: "auth_session_changed", status: 409 });
|
|
2583
2597
|
const failure = currentCloudUploadFailure(syncStartedAt, { backoff: auto && drain, deviceToken: extraEnv.TOKENTRACKER_DEVICE_TOKEN, attemptId: extraEnv.TOKENTRACKER_LOCAL_SYNC_ATTEMPT_ID });
|
|
2584
2598
|
if (failure) Object.assign(error, failure);
|
|
2585
2599
|
throw error;
|
|
2586
|
-
})
|
|
2600
|
+
});
|
|
2587
2601
|
if (extraEnv.TOKENTRACKER_DEVICE_TOKEN && uploadGeneration !== localCloudGeneration) throw Object.assign(new Error("Account session changed"), { code: "auth_session_changed", status: 409 });
|
|
2588
2602
|
const failure = currentCloudUploadFailure(syncStartedAt, { deviceToken: extraEnv.TOKENTRACKER_DEVICE_TOKEN, attemptId: extraEnv.TOKENTRACKER_LOCAL_SYNC_ATTEMPT_ID });
|
|
2589
2603
|
if (failure) throw Object.assign(new Error("Cloud upload failed"), failure);
|