@ipv9/tokentracker-cli 0.39.38 → 0.39.40
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 +43 -11
- package/dashboard/dist/assets/{Card-DD4s0V6T.js → Card-JS4gjUZf.js} +1 -1
- package/dashboard/dist/assets/DashboardPage-BoXhzJb1.js +60 -0
- package/dashboard/dist/assets/{FadeIn-CUSBK0jm.js → FadeIn-DvLfvwys.js} +1 -1
- package/dashboard/dist/assets/{IpCheckPage-PHF4lPax.js → IpCheckPage-Dcfc0Uts.js} +1 -1
- package/dashboard/dist/assets/LimitsPage-Vz-GVdi9.js +2 -0
- package/dashboard/dist/assets/{LocalOnlyNotice-DCmtS_j5.js → LocalOnlyNotice-8xF5couh.js} +1 -1
- package/dashboard/dist/assets/PopoverPopup-7HrUzeRx.js +1 -0
- package/dashboard/dist/assets/Select-9XDsaO_C.js +1 -0
- package/dashboard/dist/assets/SelectItemText-DE5Fs9p6.js +12 -0
- package/dashboard/dist/assets/SettingsPage-CMnfAptE.js +1 -0
- package/dashboard/dist/assets/SkillsPage-CbvLHN0L.js +1 -0
- package/dashboard/dist/assets/WidgetsPage-CeGQlyt7.js +1 -0
- package/dashboard/dist/assets/WrappedPage-Bux8qLUC.js +1 -0
- package/dashboard/dist/assets/{arrow-up-right-CjaBQnwI.js → arrow-up-right-B7rCoZdW.js} +1 -1
- package/dashboard/dist/assets/{download-DLBqkSwp.js → download-CtTYpbcx.js} +1 -1
- package/dashboard/dist/assets/format-BuQKK6kQ.js +1 -0
- package/dashboard/dist/assets/limitDisplay-WwuTdS_a.js +1 -0
- package/dashboard/dist/assets/main-Ck4SUH4m.js +696 -0
- package/dashboard/dist/assets/main-ZrWkoMlr.css +1 -0
- package/dashboard/dist/assets/mock-data-Bvbe8tYK.js +1 -0
- package/dashboard/dist/assets/use-limits-display-prefs-BKWYPgeA.js +1 -0
- package/dashboard/dist/assets/use-native-settings-D7Nj1dXR.js +1 -0
- package/dashboard/dist/assets/useCurrency-BX3pvyhh.js +1 -0
- package/dashboard/dist/index.html +15 -27
- package/dashboard/dist/llms.txt +0 -2
- package/dashboard/dist/sitemap.xml +0 -12
- package/package.json +7 -4
- package/src/cli.js +4 -13
- package/src/commands/doctor.js +1 -3
- package/src/commands/init.js +63 -53
- package/src/commands/serve.js +2 -50
- package/src/commands/status.js +1 -55
- package/src/commands/sync.js +134 -227
- package/src/lib/{browser-auth.js → browser-open.js} +3 -149
- package/src/lib/claude-categorizer.js +204 -32
- package/src/lib/codex-context-breakdown.js +83 -7
- package/src/lib/codex-rollout-parser.js +52 -10
- package/src/lib/diagnostics.js +1 -49
- package/src/lib/doctor.js +12 -87
- package/src/lib/file-identity.js +69 -0
- package/src/lib/init-flow.js +6 -3
- package/src/lib/local-api.js +6 -364
- package/src/lib/pricing/curated-overrides.json +1 -1
- package/src/lib/pricing/seed-snapshot.json +1 -1
- package/src/lib/rollout.js +392 -144
- package/src/lib/runtime-config.js +0 -32
- package/src/lib/sqlite-reader.js +83 -8
- package/dashboard/dist/assets/ActivityHeatmap-BrehqUIb.js +0 -42
- package/dashboard/dist/assets/DashboardPage-CyUShBRJ.js +0 -19
- package/dashboard/dist/assets/DevicePage-BA74Su1l.js +0 -1
- package/dashboard/dist/assets/DialogTitle-DoKsz5wi.js +0 -1
- package/dashboard/dist/assets/InsforgeUserHeaderControls-Bk_U2dHr.js +0 -1
- package/dashboard/dist/assets/LandingPage-Bbeu84Iu.js +0 -4356
- package/dashboard/dist/assets/LeaderboardAvatar-ByqeB6bM.js +0 -1
- package/dashboard/dist/assets/LeaderboardPage-BeWXF00S.js +0 -6
- package/dashboard/dist/assets/LeaderboardProfileModal-C4yvbZd_.js +0 -72
- package/dashboard/dist/assets/LeaderboardProfilePage-D3cbSh5o.js +0 -1
- package/dashboard/dist/assets/LimitsPage-dS9C9Vdt.js +0 -2
- package/dashboard/dist/assets/LoginPage-Ch3UQoWj.js +0 -1
- package/dashboard/dist/assets/PopoverPopup-DjG0gjlA.js +0 -1
- package/dashboard/dist/assets/Select-HzIjWJpE.js +0 -1
- package/dashboard/dist/assets/SelectItemText-f0tCwtvZ.js +0 -1
- package/dashboard/dist/assets/SettingsPage-DJOZAlZy.js +0 -1
- package/dashboard/dist/assets/SkillsPage-BQcyJIdx.js +0 -1
- package/dashboard/dist/assets/WidgetsPage-B_vxuV09.js +0 -1
- package/dashboard/dist/assets/WrappedPage-CZN9Y3Vz.js +0 -1
- package/dashboard/dist/assets/index-BeoRn2gJ.js +0 -2
- package/dashboard/dist/assets/info-BAIxlHIB.js +0 -1
- package/dashboard/dist/assets/main-DAcSUW2t.css +0 -1
- package/dashboard/dist/assets/main-pi07CfeC.js +0 -1004
- package/dashboard/dist/assets/use-limits-display-prefs-CMfASZsh.js +0 -1
- package/dashboard/dist/assets/use-native-settings-CfPik-Ao.js +0 -1
- package/dashboard/dist/assets/use-spring-wsmJQRqb.js +0 -1
- package/dashboard/dist/assets/use-usage-limits-Bt0Dp6kx.js +0 -1
- package/dashboard/dist/assets/useCurrency-CsaAMc3j.js +0 -1
- package/dashboard/dist/assets/useOpenInteractionType-CPzi5Z8M.js +0 -12
- package/dashboard/dist/share.html +0 -140
- package/src/commands/device-login.js +0 -161
- package/src/lib/upload-throttle.js +0 -148
package/src/commands/init.js
CHANGED
|
@@ -57,7 +57,6 @@ const {
|
|
|
57
57
|
resolvePiAgentDir,
|
|
58
58
|
piAgentDirCollidesWithOmp,
|
|
59
59
|
} = require("../lib/rollout");
|
|
60
|
-
const { resolveRuntimeConfig, DEFAULT_BASE_URL } = require("../lib/runtime-config");
|
|
61
60
|
const {
|
|
62
61
|
BOLD,
|
|
63
62
|
DIM,
|
|
@@ -86,7 +85,6 @@ const ASCII_LOGO = [
|
|
|
86
85
|
].join("\n");
|
|
87
86
|
|
|
88
87
|
const DIVIDER = "----------------------------------------------";
|
|
89
|
-
const DEFAULT_DASHBOARD_URL = "https://www.tokentracker.cc";
|
|
90
88
|
|
|
91
89
|
// Single source of truth for the welcome screen's provider count + sample list.
|
|
92
90
|
// Keep in sync with the supported-tools table in CLAUDE.md.
|
|
@@ -120,11 +118,6 @@ async function cmdInit(argv) {
|
|
|
120
118
|
const linkCodeStatePath = path.join(trackerDir, "link_code_state.json");
|
|
121
119
|
|
|
122
120
|
const existingConfig = await readJson(configPath);
|
|
123
|
-
const runtime = resolveRuntimeConfig({
|
|
124
|
-
cli: { baseUrl: opts.baseUrl, dashboardUrl: opts.dashboardUrl },
|
|
125
|
-
config: existingConfig || {},
|
|
126
|
-
env: process.env,
|
|
127
|
-
});
|
|
128
121
|
const notifyPath = path.join(binDir, "notify.cjs");
|
|
129
122
|
const appDir = path.join(trackerDir, "app");
|
|
130
123
|
const trackerBinPath = path.join(appDir, "bin", "tracker.js");
|
|
@@ -156,7 +149,6 @@ async function cmdInit(argv) {
|
|
|
156
149
|
home,
|
|
157
150
|
trackerDir,
|
|
158
151
|
notifyPath,
|
|
159
|
-
runtime,
|
|
160
152
|
});
|
|
161
153
|
renderLocalReport({ summary: preview.summary, isDryRun: true });
|
|
162
154
|
renderAccountNotLinked({ context: "dry-run" });
|
|
@@ -178,7 +170,6 @@ async function cmdInit(argv) {
|
|
|
178
170
|
notifyPath,
|
|
179
171
|
appDir,
|
|
180
172
|
trackerBinPath,
|
|
181
|
-
runtime,
|
|
182
173
|
existingConfig,
|
|
183
174
|
});
|
|
184
175
|
} catch (err) {
|
|
@@ -280,20 +271,10 @@ function renderAccountNotLinked({ context } = {}) {
|
|
|
280
271
|
renderLocalSuccess();
|
|
281
272
|
}
|
|
282
273
|
|
|
283
|
-
function
|
|
284
|
-
if (deviceToken) return false;
|
|
285
|
-
if (opts.noAuth) return false;
|
|
286
|
-
if (opts.linkCode) return false;
|
|
287
|
-
if (opts.email || opts.password) return false;
|
|
288
|
-
return true;
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
async function buildDryRunSummary({ opts, home, trackerDir, notifyPath, runtime }) {
|
|
292
|
-
const deviceToken = runtime?.deviceToken || null;
|
|
293
|
-
const pendingBrowserAuth = shouldUseBrowserAuth({ deviceToken, opts });
|
|
274
|
+
async function buildDryRunSummary({ opts, home, trackerDir, notifyPath }) {
|
|
294
275
|
const context = buildIntegrationTargets({ home, trackerDir, notifyPath });
|
|
295
276
|
const summary = await previewIntegrations({ context });
|
|
296
|
-
return { summary
|
|
277
|
+
return { summary };
|
|
297
278
|
}
|
|
298
279
|
|
|
299
280
|
async function runSetup({
|
|
@@ -307,15 +288,12 @@ async function runSetup({
|
|
|
307
288
|
notifyPath,
|
|
308
289
|
appDir,
|
|
309
290
|
trackerBinPath,
|
|
310
|
-
runtime,
|
|
311
291
|
existingConfig,
|
|
312
292
|
}) {
|
|
313
293
|
await ensureDir(trackerDir);
|
|
314
294
|
await ensureDir(binDir);
|
|
315
|
-
let deviceToken = runtime?.deviceToken || null;
|
|
316
295
|
let deviceId = existingConfig?.deviceId || null;
|
|
317
296
|
const installedAt = existingConfig?.installedAt || new Date().toISOString();
|
|
318
|
-
let pendingBrowserAuth = false;
|
|
319
297
|
|
|
320
298
|
await installLocalTrackerApp({ appDir });
|
|
321
299
|
|
|
@@ -323,13 +301,33 @@ async function runSetup({
|
|
|
323
301
|
existingConfig && typeof existingConfig === "object" && !Array.isArray(existingConfig)
|
|
324
302
|
? existingConfig
|
|
325
303
|
: {};
|
|
304
|
+
// Scrub cloud credentials and endpoints on upgrade. Spreading the previous
|
|
305
|
+
// config forward kept a live InsForge bearer token in config.json, and this
|
|
306
|
+
// branch also removed the `status` / `diagnostics` lines that used to reveal
|
|
307
|
+
// it — so the user is told "local-only, nothing is uploaded" while a valid
|
|
308
|
+
// credential sits on disk with nothing left to report or rotate it.
|
|
309
|
+
const {
|
|
310
|
+
deviceToken: _removedDeviceToken,
|
|
311
|
+
baseUrl: _removedBaseUrl,
|
|
312
|
+
dashboardUrl: _removedDashboardUrl,
|
|
313
|
+
...carriedConfig
|
|
314
|
+
} = existingPlainConfig;
|
|
326
315
|
const config = {
|
|
327
|
-
...
|
|
316
|
+
...carriedConfig,
|
|
328
317
|
installedAt,
|
|
329
|
-
baseUrl: opts.baseUrl || existingPlainConfig.baseUrl || DEFAULT_BASE_URL,
|
|
330
318
|
};
|
|
331
|
-
|
|
332
|
-
|
|
319
|
+
|
|
320
|
+
// Files written by the removed cloud paths. The only code that ever deleted
|
|
321
|
+
// relay-cookies.json was clearRelayCookies(), which went with the auth proxy,
|
|
322
|
+
// so an upgrading machine would otherwise keep a refresh token forever.
|
|
323
|
+
for (const stale of ["relay-cookies.json", "upload.throttle.json", "auto.retry.json"]) {
|
|
324
|
+
try {
|
|
325
|
+
await fs.unlink(path.join(trackerDir, stale));
|
|
326
|
+
} catch (error) {
|
|
327
|
+
if (error?.code !== "ENOENT") {
|
|
328
|
+
process.stderr.write(`[tokentracker] could not remove ${stale}: ${error.message}\n`);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
333
331
|
}
|
|
334
332
|
|
|
335
333
|
await writeJson(configPath, config);
|
|
@@ -350,8 +348,6 @@ async function runSetup({
|
|
|
350
348
|
|
|
351
349
|
return {
|
|
352
350
|
summary,
|
|
353
|
-
pendingBrowserAuth,
|
|
354
|
-
deviceToken,
|
|
355
351
|
deviceId,
|
|
356
352
|
installedAt,
|
|
357
353
|
};
|
|
@@ -803,8 +799,6 @@ function arraysEqual(a, b) {
|
|
|
803
799
|
|
|
804
800
|
function parseArgs(argv) {
|
|
805
801
|
const out = {
|
|
806
|
-
baseUrl: null,
|
|
807
|
-
dashboardUrl: null,
|
|
808
802
|
email: null,
|
|
809
803
|
password: null,
|
|
810
804
|
deviceName: null,
|
|
@@ -817,13 +811,33 @@ function parseArgs(argv) {
|
|
|
817
811
|
|
|
818
812
|
for (let i = 0; i < argv.length; i++) {
|
|
819
813
|
const a = argv[i];
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
814
|
+
// Cloud sign-in flags (--email/--password/--device-name/--link-code/
|
|
815
|
+
// --no-auth) are gone: there is no account to sign into. Accept and
|
|
816
|
+
// ignore --no-auth so existing scripts and hooks do not start failing
|
|
817
|
+
// with "Unknown option"; the others were only ever used with it.
|
|
818
|
+
if (a === "--no-auth") {
|
|
819
|
+
// Accepted and ignored: it was the "skip sign-in" opt-out, and there is
|
|
820
|
+
// no sign-in left to skip. Silently tolerated so existing hooks and
|
|
821
|
+
// scripts do not start failing with "Unknown option".
|
|
822
|
+
out.noAuth = true;
|
|
823
|
+
} else if (a === "--email" || a === "--password" || a === "--device-name") {
|
|
824
|
+
i += 1;
|
|
825
|
+
} else if (
|
|
826
|
+
a.startsWith("--email=") ||
|
|
827
|
+
a.startsWith("--password=") ||
|
|
828
|
+
a.startsWith("--device-name=")
|
|
829
|
+
) {
|
|
830
|
+
// Swallow the `=` form too. Falling through raised
|
|
831
|
+
// `Unknown option: --password=hunter2`, and bin/tracker.js prints the
|
|
832
|
+
// stack — putting the secret on stderr and into any captured log.
|
|
833
|
+
} else if (a === "--link-code" || a.startsWith("--link-code=")) {
|
|
834
|
+
// Fail loudly. Unlike the others this was documented standalone, so a
|
|
835
|
+
// user pairing a device would otherwise see "Setup complete!" and
|
|
836
|
+
// believe the code was honored.
|
|
837
|
+
throw new Error(
|
|
838
|
+
"--link-code is no longer supported: TokenTracker is local-only and has no device pairing.",
|
|
839
|
+
);
|
|
840
|
+
}
|
|
827
841
|
else if (a === "--no-open") out.noOpen = true;
|
|
828
842
|
else if (a === "--yes") out.yes = true;
|
|
829
843
|
else if (a === "--dry-run") out.dryRun = true;
|
|
@@ -883,7 +897,6 @@ const codexOriginalPath = ${JSON.stringify(originalPath)};
|
|
|
883
897
|
const codeOriginalPath = ${JSON.stringify(path.join(trackerDir, "code_notify_original.json"))};
|
|
884
898
|
const trackerBinPath = ${JSON.stringify(trackerBinPath)};
|
|
885
899
|
const depsMarkerPath = path.join(trackerDir, 'app', 'bin', 'tracker.js');
|
|
886
|
-
const configPath = path.join(trackerDir, 'config.json');
|
|
887
900
|
const fallbackPkg = ${JSON.stringify(fallbackPkg)};
|
|
888
901
|
const selfPath = path.resolve(__filename);
|
|
889
902
|
const home = os.homedir();
|
|
@@ -919,20 +932,17 @@ if (debugEnabled) {
|
|
|
919
932
|
}
|
|
920
933
|
|
|
921
934
|
// Throttle spawn: at most once per 20 seconds.
|
|
935
|
+
// Parsing local logs and uploading to the cloud are two separate decisions.
|
|
936
|
+
// This hook makes only the first one. It runs whether or not a device token
|
|
937
|
+
// exists, because a local-only install still needs its queue refreshed when a
|
|
938
|
+
// session ends. Upload stays gated on a device token inside sync itself, so
|
|
939
|
+
// no credential here means local parse happens and nothing is transmitted.
|
|
922
940
|
try {
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
if (cfg && typeof cfg.deviceToken === 'string') deviceToken = cfg.deviceToken;
|
|
929
|
-
} catch (_) {}
|
|
930
|
-
}
|
|
931
|
-
const canSync = Boolean(deviceToken && deviceToken.length > 0);
|
|
932
|
-
const now = Date.now();
|
|
933
|
-
let last = 0;
|
|
934
|
-
try { last = Number(fs.readFileSync(throttlePath, 'utf8')) || 0; } catch (_) {}
|
|
935
|
-
if (canSync && now - last > 20_000) {
|
|
941
|
+
const throttlePath = path.join(trackerDir, 'sync.throttle');
|
|
942
|
+
const now = Date.now();
|
|
943
|
+
let last = 0;
|
|
944
|
+
try { last = Number(fs.readFileSync(throttlePath, 'utf8')) || 0; } catch (_) {}
|
|
945
|
+
if (now - last > 20_000) {
|
|
936
946
|
try { fs.writeFileSync(throttlePath, String(now), 'utf8'); } catch (_) {}
|
|
937
947
|
const hasLocalRuntime = fs.existsSync(trackerBinPath);
|
|
938
948
|
const hasLocalDeps = fs.existsSync(depsMarkerPath);
|
package/src/commands/serve.js
CHANGED
|
@@ -2,7 +2,6 @@ const http = require("node:http");
|
|
|
2
2
|
const os = require("node:os");
|
|
3
3
|
const path = require("node:path");
|
|
4
4
|
const fssync = require("node:fs");
|
|
5
|
-
const cp = require("node:child_process");
|
|
6
5
|
|
|
7
6
|
const { resolveTrackerPaths } = require("../lib/tracker-paths");
|
|
8
7
|
const { createLocalApiHandler, resolveQueuePath } = require("../lib/local-api");
|
|
@@ -12,7 +11,7 @@ const {
|
|
|
12
11
|
} = require("../lib/local-data-preflight");
|
|
13
12
|
const { ensurePricingLoaded } = require("../lib/pricing");
|
|
14
13
|
const { serveStaticFile } = require("../lib/static-server");
|
|
15
|
-
const { openInBrowser } = require("../lib/browser-
|
|
14
|
+
const { openInBrowser } = require("../lib/browser-open");
|
|
16
15
|
|
|
17
16
|
const DEFAULT_PORT = 7680;
|
|
18
17
|
const DEFAULT_MAX_PORT_ATTEMPTS = 20;
|
|
@@ -20,7 +19,7 @@ const NPM_PACKAGE_NAME = "@ipv9/tokentracker-cli";
|
|
|
20
19
|
const LOCAL_BIND_HOST = "127.0.0.1";
|
|
21
20
|
|
|
22
21
|
function buildPortInUseHint(port) {
|
|
23
|
-
return `Port ${port} is
|
|
22
|
+
return `Port ${port} is unavailable. Try: npx ${NPM_PACKAGE_NAME} serve --port ${port + 1}\n`;
|
|
24
23
|
}
|
|
25
24
|
|
|
26
25
|
function isPortUnavailableError(error) {
|
|
@@ -155,7 +154,6 @@ async function cmdServe(argv) {
|
|
|
155
154
|
try {
|
|
156
155
|
port = await listenOnAvailablePort(server, opts.port, {
|
|
157
156
|
allowFallback: !opts.portExplicit,
|
|
158
|
-
ensurePortFreeFn: opts.portExplicit ? ensurePortFree : null,
|
|
159
157
|
onRetry: (failedPort) => {
|
|
160
158
|
process.stdout.write(`Port ${failedPort} unavailable, trying ${failedPort + 1}...\n`);
|
|
161
159
|
},
|
|
@@ -208,47 +206,6 @@ async function cmdServe(argv) {
|
|
|
208
206
|
await new Promise(() => {});
|
|
209
207
|
}
|
|
210
208
|
|
|
211
|
-
function findPidOnPort(port) {
|
|
212
|
-
try {
|
|
213
|
-
const out = cp.execFileSync("lsof", ["-ti", `tcp:${port}`], { encoding: "utf8", timeout: 5000 });
|
|
214
|
-
const pids = out.trim().split(/\s+/).map(Number).filter((n) => Number.isFinite(n) && n > 0);
|
|
215
|
-
return pids;
|
|
216
|
-
} catch (_e) {
|
|
217
|
-
return [];
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
async function ensurePortFree(port) {
|
|
222
|
-
const pids = findPidOnPort(port);
|
|
223
|
-
if (pids.length === 0) return;
|
|
224
|
-
|
|
225
|
-
// Don't kill ourselves
|
|
226
|
-
const self = process.pid;
|
|
227
|
-
const targets = pids.filter((p) => p !== self);
|
|
228
|
-
if (targets.length === 0) return;
|
|
229
|
-
|
|
230
|
-
process.stdout.write(`Stopping previous server on port ${port} (pid ${targets.join(", ")})...\n`);
|
|
231
|
-
for (const pid of targets) {
|
|
232
|
-
try {
|
|
233
|
-
process.kill(pid, "SIGTERM");
|
|
234
|
-
} catch (_e) {}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
// Wait briefly for port to free up
|
|
238
|
-
for (let i = 0; i < 10; i++) {
|
|
239
|
-
await new Promise((r) => setTimeout(r, 300));
|
|
240
|
-
if (findPidOnPort(port).length === 0) return;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
// Force kill if still alive
|
|
244
|
-
for (const pid of targets) {
|
|
245
|
-
try {
|
|
246
|
-
process.kill(pid, "SIGKILL");
|
|
247
|
-
} catch (_e) {}
|
|
248
|
-
}
|
|
249
|
-
await new Promise((r) => setTimeout(r, 500));
|
|
250
|
-
}
|
|
251
|
-
|
|
252
209
|
function listenOnce(server, port, host) {
|
|
253
210
|
return new Promise((resolve, reject) => {
|
|
254
211
|
let settled = false;
|
|
@@ -283,7 +240,6 @@ async function listenOnAvailablePort(
|
|
|
283
240
|
host = LOCAL_BIND_HOST,
|
|
284
241
|
allowFallback = false,
|
|
285
242
|
maxAttempts = DEFAULT_MAX_PORT_ATTEMPTS,
|
|
286
|
-
ensurePortFreeFn = null,
|
|
287
243
|
onRetry = null,
|
|
288
244
|
} = {},
|
|
289
245
|
) {
|
|
@@ -292,10 +248,6 @@ async function listenOnAvailablePort(
|
|
|
292
248
|
let lastError = null;
|
|
293
249
|
|
|
294
250
|
for (let i = 0; i < attempts && port < 65536; i++, port++) {
|
|
295
|
-
if (ensurePortFreeFn) {
|
|
296
|
-
await ensurePortFreeFn(port);
|
|
297
|
-
}
|
|
298
|
-
|
|
299
251
|
try {
|
|
300
252
|
await listenOnce(server, port, host);
|
|
301
253
|
return port;
|
package/src/commands/status.js
CHANGED
|
@@ -25,9 +25,6 @@ const {
|
|
|
25
25
|
describeCopilotOtelStatus,
|
|
26
26
|
readCopilotOauthToken,
|
|
27
27
|
} = require("../lib/usage-limits");
|
|
28
|
-
const {
|
|
29
|
-
normalizeState: normalizeUploadState,
|
|
30
|
-
} = require("../lib/upload-throttle");
|
|
31
28
|
const { collectTrackerDiagnostics } = require("../lib/diagnostics");
|
|
32
29
|
const { detectPassiveProviders, isPassiveModeActive } = require("../lib/passive-mode");
|
|
33
30
|
const { probeOpenclawHookState } = require("../lib/openclaw-hook");
|
|
@@ -68,15 +65,11 @@ async function cmdStatus(argv = []) {
|
|
|
68
65
|
|
|
69
66
|
const home = os.homedir();
|
|
70
67
|
const { trackerDir, binDir } = await resolveTrackerPaths({ home });
|
|
71
|
-
const configPath = path.join(trackerDir, "config.json");
|
|
72
68
|
const queuePath = path.join(trackerDir, "queue.jsonl");
|
|
73
|
-
const queueStatePath = path.join(trackerDir, "queue.state.json");
|
|
74
69
|
const cursorsPath = path.join(trackerDir, "cursors.json");
|
|
75
70
|
const notifySignalPath = path.join(trackerDir, "notify.signal");
|
|
76
71
|
const openclawSignalPath = path.join(trackerDir, "openclaw.signal");
|
|
77
72
|
const throttlePath = path.join(trackerDir, "sync.throttle");
|
|
78
|
-
const uploadThrottlePath = path.join(trackerDir, "upload.throttle.json");
|
|
79
|
-
const autoRetryPath = path.join(trackerDir, "auto.retry.json");
|
|
80
73
|
const codexHome = process.env.CODEX_HOME || path.join(home, ".codex");
|
|
81
74
|
const codexConfigPath = path.join(codexHome, "config.toml");
|
|
82
75
|
const codeHome = process.env.CODE_HOME || path.join(home, ".code");
|
|
@@ -99,16 +92,9 @@ async function cmdStatus(argv = []) {
|
|
|
99
92
|
const codebuddyHookCommand = buildHookCommand(notifyPath, "codebuddy");
|
|
100
93
|
const geminiHookCommand = buildGeminiHookCommand(notifyPath);
|
|
101
94
|
|
|
102
|
-
const config = await readJson(configPath);
|
|
103
95
|
const cursors = await readJson(cursorsPath);
|
|
104
|
-
const queueState = (await readJson(queueStatePath)) || { offset: 0 };
|
|
105
|
-
const uploadThrottle = normalizeUploadState(
|
|
106
|
-
await readJson(uploadThrottlePath),
|
|
107
|
-
);
|
|
108
|
-
const autoRetry = await readJson(autoRetryPath);
|
|
109
96
|
|
|
110
97
|
const queueSize = await safeStatSize(queuePath);
|
|
111
|
-
const pendingBytes = Math.max(0, queueSize - (queueState.offset || 0));
|
|
112
98
|
|
|
113
99
|
const lastNotify = (await safeReadText(notifySignalPath))?.trim() || null;
|
|
114
100
|
const lastOpenclawSync =
|
|
@@ -148,23 +134,6 @@ async function cmdStatus(argv = []) {
|
|
|
148
134
|
env: process.env,
|
|
149
135
|
});
|
|
150
136
|
|
|
151
|
-
const lastUpload = uploadThrottle.lastSuccessMs
|
|
152
|
-
? parseEpochMsToIso(uploadThrottle.lastSuccessMs)
|
|
153
|
-
: typeof queueState.updatedAt === "string"
|
|
154
|
-
? queueState.updatedAt
|
|
155
|
-
: null;
|
|
156
|
-
const nextUpload = parseEpochMsToIso(uploadThrottle.nextAllowedAtMs || null);
|
|
157
|
-
const backoffUntil = parseEpochMsToIso(uploadThrottle.backoffUntilMs || null);
|
|
158
|
-
const lastUploadError = uploadThrottle.lastError
|
|
159
|
-
? `${uploadThrottle.lastErrorAt || "unknown"} ${uploadThrottle.lastError}`
|
|
160
|
-
: null;
|
|
161
|
-
const autoRetryAt = parseEpochMsToIso(autoRetry?.retryAtMs || null);
|
|
162
|
-
const autoRetryLine = autoRetryAt
|
|
163
|
-
? `- Auto retry after: ${autoRetryAt} (${autoRetry?.reason || "scheduled"}, pending ${Number(
|
|
164
|
-
autoRetry?.pendingBytes || 0,
|
|
165
|
-
)} bytes)`
|
|
166
|
-
: null;
|
|
167
|
-
|
|
168
137
|
const subscriptions = await collectLocalSubscriptions({
|
|
169
138
|
home,
|
|
170
139
|
env: process.env,
|
|
@@ -277,22 +246,13 @@ async function cmdStatus(argv = []) {
|
|
|
277
246
|
if (opts.json || opts.light) {
|
|
278
247
|
const summary = {
|
|
279
248
|
generated_at: new Date().toISOString(),
|
|
280
|
-
base_url: config?.baseUrl || null,
|
|
281
|
-
device_token_set: Boolean(config?.deviceToken),
|
|
282
249
|
queue: {
|
|
283
|
-
pending_bytes: pendingBytes,
|
|
284
250
|
size_bytes: queueSize,
|
|
285
|
-
offset: queueState.offset || 0,
|
|
286
251
|
},
|
|
287
252
|
last_parse: cursors?.updatedAt || null,
|
|
288
253
|
last_notify: lastNotify || null,
|
|
289
254
|
last_openclaw_sync: lastOpenclawSync || null,
|
|
290
255
|
last_notify_spawn: lastNotifySpawn || null,
|
|
291
|
-
last_upload: lastUpload || null,
|
|
292
|
-
next_upload_after: nextUpload || null,
|
|
293
|
-
backoff_until: backoffUntil || null,
|
|
294
|
-
last_upload_error: lastUploadError || null,
|
|
295
|
-
auto_retry: autoRetry || null,
|
|
296
256
|
hooks: {
|
|
297
257
|
codex_notify: notifyConfigured,
|
|
298
258
|
every_code_notify: everyCodeConfigured,
|
|
@@ -371,18 +331,11 @@ async function cmdStatus(argv = []) {
|
|
|
371
331
|
process.stdout.write(
|
|
372
332
|
[
|
|
373
333
|
"Status:",
|
|
374
|
-
`-
|
|
375
|
-
`- Device token: ${config?.deviceToken ? "set" : "unset"}`,
|
|
376
|
-
`- Queue: ${pendingBytes} bytes pending`,
|
|
334
|
+
`- Queue: ${queueSize} bytes`,
|
|
377
335
|
`- Last parse: ${cursors?.updatedAt || "never"}`,
|
|
378
336
|
`- Last notify: ${lastNotify || "never"}`,
|
|
379
337
|
`- Last OpenClaw-triggered sync: ${lastOpenclawSync || "never"}`,
|
|
380
338
|
`- Last notify-triggered sync: ${lastNotifySpawn || "never"}`,
|
|
381
|
-
`- Last upload: ${lastUpload || "never"}`,
|
|
382
|
-
`- Next upload after: ${nextUpload || "never"}`,
|
|
383
|
-
`- Backoff until: ${backoffUntil || "never"}`,
|
|
384
|
-
lastUploadError ? `- Last upload error: ${lastUploadError}` : null,
|
|
385
|
-
autoRetryLine,
|
|
386
339
|
`- Codex notify: ${notifyConfigured ? JSON.stringify(codexNotify) : "unset"}`,
|
|
387
340
|
`- Every Code notify: ${everyCodeConfigured ? JSON.stringify(everyCodeNotify) : "unset"}`,
|
|
388
341
|
`- Claude hooks: ${claudeHookConfigured ? "set" : "unset"}`,
|
|
@@ -538,16 +491,9 @@ function renderLightTable(summary) {
|
|
|
538
491
|
const rows = [];
|
|
539
492
|
const push = (k, v) => rows.push([k, v == null || v === "" ? "—" : String(v)]);
|
|
540
493
|
|
|
541
|
-
push("Base URL", summary.base_url);
|
|
542
|
-
push("Device token", summary.device_token_set ? "set" : "unset");
|
|
543
|
-
push("Queue pending (bytes)", summary.queue.pending_bytes);
|
|
544
494
|
push("Queue size (bytes)", summary.queue.size_bytes);
|
|
545
495
|
push("Last parse", summary.last_parse);
|
|
546
496
|
push("Last notify", summary.last_notify);
|
|
547
|
-
push("Last upload", summary.last_upload);
|
|
548
|
-
push("Next upload after", summary.next_upload_after);
|
|
549
|
-
push("Backoff until", summary.backoff_until);
|
|
550
|
-
if (summary.last_upload_error) push("Last upload error", summary.last_upload_error);
|
|
551
497
|
|
|
552
498
|
for (const [name, state] of Object.entries(summary.hooks || {})) {
|
|
553
499
|
push(`Hook · ${name}`, state ? "set" : "unset");
|