tokentracker-cli 0.79.8 → 0.80.0
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-Ctu3c_8t.js → AchievementBadge-D9jOMhlD.js} +1 -1
- package/dashboard/dist/assets/{AchievementsPage-B3kBTHDB.js → AchievementsPage-DuswZa4g.js} +2 -2
- package/dashboard/dist/assets/{AchievementsSection-CAnTXGpC.js → AchievementsSection-BJPeE1Uq.js} +1 -1
- package/dashboard/dist/assets/{BadgeDetailModal-oTUXEQk9.js → BadgeDetailModal-nNPIsy6i.js} +1 -1
- package/dashboard/dist/assets/{Card-BHt5f5cD.js → Card-VENq8eEp.js} +1 -1
- package/dashboard/dist/assets/{ClawdAnimated-ChxXY3l0.js → ClawdAnimated-Cq7TW0vv.js} +1 -1
- package/dashboard/dist/assets/{CommunityStatsModal-CVLlItP1.js → CommunityStatsModal-y2VftQuq.js} +1 -1
- package/dashboard/dist/assets/{ConfirmModal-ClrILpb3.js → ConfirmModal-CWgnJ4hm.js} +1 -1
- package/dashboard/dist/assets/{Controls-D_XBBpIh.js → Controls-BUQ_iZZq.js} +1 -1
- package/dashboard/dist/assets/DashboardPage-WkiygMmq.js +19 -0
- package/dashboard/dist/assets/{DevicePage-J7DW7yeX.js → DevicePage-Dh3XDtNx.js} +1 -1
- package/dashboard/dist/assets/{DialogClose-B1r9gzUF.js → DialogClose-KTFU_B3F.js} +1 -1
- package/dashboard/dist/assets/DialogDescription-DIra288n.js +1 -0
- package/dashboard/dist/assets/{DialogTitle-BL2puDA7.js → DialogTitle-bza2pIek.js} +1 -1
- package/dashboard/dist/assets/{FadeIn-Cd-YT4oT.js → FadeIn-Dm3FVNfr.js} +1 -1
- package/dashboard/dist/assets/{HeaderGithubStar-BAtl4a-K.js → HeaderGithubStar-CbSElzLt.js} +1 -1
- package/dashboard/dist/assets/{IpCheckPage-BXK_cYN2.js → IpCheckPage-BDON7VCU.js} +1 -1
- package/dashboard/dist/assets/{LandingPage-C_16AbpF.js → LandingPage-Ck3CwZrt.js} +1 -1
- package/dashboard/dist/assets/{LeaderboardAvatar-B0vUuCYU.js → LeaderboardAvatar-GVUy0Ynq.js} +1 -1
- package/dashboard/dist/assets/{LeaderboardPage-Duhdaq09.js → LeaderboardPage-C19Rkt44.js} +2 -2
- package/dashboard/dist/assets/{LeaderboardProfileModal-CFFyHRTB.js → LeaderboardProfileModal-QcEq_o6E.js} +3 -3
- package/dashboard/dist/assets/{LeaderboardProfilePage-CjTelV-4.js → LeaderboardProfilePage-pFhI6292.js} +1 -1
- package/dashboard/dist/assets/{LimitsPage-DIcXRgSv.js → LimitsPage-ChV3Qezd.js} +1 -1
- package/dashboard/dist/assets/{LocalOnlyNotice-DC7wXWds.js → LocalOnlyNotice-ALvpjznF.js} +1 -1
- package/dashboard/dist/assets/{LoginPage--8hYT3aq.js → LoginPage-CL-QrJxU.js} +1 -1
- package/dashboard/dist/assets/{PetPage-ByWUW7-V.js → PetPage-DSuvdGgd.js} +1 -1
- package/dashboard/dist/assets/{PopoverPopup-g_v1fmhH.js → PopoverPopup-jSDQ87Bi.js} +1 -1
- package/dashboard/dist/assets/{ResetPasswordPage-BfunstIi.js → ResetPasswordPage-Dk2IDAJq.js} +1 -1
- package/dashboard/dist/assets/{Select-C4ShPt1t.js → Select-Cz6WTj7D.js} +1 -1
- package/dashboard/dist/assets/{SelectItemText-gw_TdvY6.js → SelectItemText-BZyRjWCM.js} +1 -1
- package/dashboard/dist/assets/{SettingsPage-BFCFrDuA.js → SettingsPage-CANz8HMM.js} +1 -1
- package/dashboard/dist/assets/{SkillsPage-BNQDySeK.js → SkillsPage-WZkQG_83.js} +1 -1
- package/dashboard/dist/assets/{WidgetsPage-B3bHP3Vk.js → WidgetsPage-BEyJ62NV.js} +1 -1
- package/dashboard/dist/assets/{WrappedPage-6amxWnWT.js → WrappedPage-Ck_dOx_w.js} +1 -1
- package/dashboard/dist/assets/{agent-logos-DPIQzYms.js → agent-logos-DpjHiAbZ.js} +1 -1
- package/dashboard/dist/assets/{arrow-up-right-CKcE2mif.js → arrow-up-right-C4iYPBtK.js} +1 -1
- package/dashboard/dist/assets/check-BkPUxPZV.js +1 -0
- package/dashboard/dist/assets/{copy-vi-V2M_I.js → copy-CHJ-38K6.js} +1 -1
- package/dashboard/dist/assets/{download-BH0Spg15.js → download-BSeG8u17.js} +1 -1
- package/dashboard/dist/assets/{flame-C3jUAnqA.js → flame-DeHwKcE-.js} +1 -1
- package/dashboard/dist/assets/{format-tokens-tnfJT09G.js → format-tokens-B-MJYJyp.js} +1 -1
- package/dashboard/dist/assets/{info-CGCZ5JvP.js → info-DA_0xr_o.js} +1 -1
- package/dashboard/dist/assets/{link-2-CXULWwZY.js → link-2-noUH83Lc.js} +1 -1
- package/dashboard/dist/assets/{loader-circle-B324hSa3.js → loader-circle-wL7KZtm0.js} +1 -1
- package/dashboard/dist/assets/{main-vGUuyRq-.js → main-BHfJDFcu.js} +20 -20
- package/dashboard/dist/assets/{provider-display-CeoAhoCb.js → provider-display-DxIClOGM.js} +1 -1
- package/dashboard/dist/assets/{trash-2-L9vxbDeP.js → trash-2-B8TPUmxZ.js} +1 -1
- package/dashboard/dist/assets/{use-community-stats-DLE30Lh0.js → use-community-stats-CXD3MRRE.js} +1 -1
- package/dashboard/dist/assets/{use-limits-display-prefs-BxN--PEW.js → use-limits-display-prefs-C2pJVYTn.js} +1 -1
- package/dashboard/dist/assets/{use-native-settings-Dn5gWQkJ.js → use-native-settings-BeOBLEZa.js} +1 -1
- package/dashboard/dist/assets/{use-ordered-list-DYoz2NJ9.js → use-ordered-list-kAtW8pJm.js} +1 -1
- package/dashboard/dist/assets/{use-quality-per-dollar-pref-JXorBQsT.js → use-quality-per-dollar-pref-CFZUZM3S.js} +1 -1
- package/dashboard/dist/assets/{use-transform-BTTF5vPC.js → use-transform-B9YwpyKi.js} +1 -1
- package/dashboard/dist/assets/{use-usage-limits-BUemSWQ9.js → use-usage-limits-DSX5iKPE.js} +1 -1
- package/dashboard/dist/assets/{useCurrency-Cxv4RR3U.js → useCurrency-CKg5K4Nj.js} +1 -1
- package/dashboard/dist/assets/{useScrollLock-DTPnHKfF.js → useScrollLock-DyyY_Vyt.js} +1 -1
- package/dashboard/dist/assets/useTokenFormat-FfTjEH_m.js +1 -0
- package/dashboard/dist/assets/{zap-CG8zuY9S.js → zap-B69x9NCT.js} +1 -1
- package/dashboard/dist/index.html +1 -1
- package/dashboard/dist/share.html +1 -1
- package/package.json +1 -1
- package/src/commands/init.js +89 -12
- package/src/commands/serve.js +65 -4
- package/src/commands/status.js +2 -1
- package/src/commands/sync.js +170 -7
- package/src/commands/uninstall.js +10 -2
- package/src/lib/claude-config.js +69 -28
- package/src/lib/diagnostics.js +2 -2
- package/src/lib/local-api.js +19 -6
- package/src/lib/openclaw-session-plugin.js +13 -0
- package/src/lib/pricing/seed-snapshot.json +1 -1
- package/src/lib/rollout.js +63 -2
- package/src/lib/usage-limits.js +9 -5
- package/dashboard/dist/assets/DashboardPage-CizTJox2.js +0 -19
- package/dashboard/dist/assets/DialogDescription-Bd9-kaCS.js +0 -1
- package/dashboard/dist/assets/check-B5V4_ezt.js +0 -1
- package/dashboard/dist/assets/useTokenFormat-DMAb2ec3.js +0 -1
package/src/lib/claude-config.js
CHANGED
|
@@ -4,56 +4,74 @@ const path = require("node:path");
|
|
|
4
4
|
const { ensureDir, readJson, writeJson } = require("./fs");
|
|
5
5
|
|
|
6
6
|
const DEFAULT_EVENT = "SessionEnd";
|
|
7
|
+
const CLAUDE_USAGE_EVENTS = ["Stop", DEFAULT_EVENT];
|
|
7
8
|
|
|
8
9
|
async function upsertClaudeHook({ settingsPath, hookCommand, event = DEFAULT_EVENT }) {
|
|
10
|
+
return upsertClaudeHooks({ settingsPath, hookCommand, events: [event] });
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async function upsertClaudeUsageHooks({ settingsPath, hookCommand }) {
|
|
14
|
+
return upsertClaudeHooks({ settingsPath, hookCommand, events: CLAUDE_USAGE_EVENTS });
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async function upsertClaudeHooks({ settingsPath, hookCommand, events }) {
|
|
9
18
|
const existing = await readJson(settingsPath);
|
|
10
19
|
const settings = normalizeSettings(existing);
|
|
11
20
|
const hooks = normalizeHooks(settings.hooks);
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
const normalized = normalizeEntriesForCommand(entries, hookCommand);
|
|
15
|
-
if (normalized.changed) {
|
|
16
|
-
const nextHooks = { ...hooks, [event]: normalized.entries };
|
|
17
|
-
const nextSettings = { ...settings, hooks: nextHooks };
|
|
18
|
-
const backupPath = await writeClaudeSettings({ settingsPath, settings: nextSettings });
|
|
19
|
-
return { changed: true, backupPath };
|
|
20
|
-
}
|
|
21
|
+
const nextHooks = { ...hooks };
|
|
22
|
+
let changed = false;
|
|
21
23
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
+
for (const event of normalizeEventList(events)) {
|
|
25
|
+
const entries = normalizeEntries(hooks[event]);
|
|
26
|
+
const normalized = normalizeEntriesForCommand(entries, hookCommand);
|
|
27
|
+
let nextEntries = normalized.entries;
|
|
28
|
+
if (!hasHook(nextEntries, hookCommand)) {
|
|
29
|
+
nextEntries = nextEntries.concat([{ hooks: [{ type: "command", command: hookCommand }] }]);
|
|
30
|
+
changed = true;
|
|
31
|
+
}
|
|
32
|
+
if (normalized.changed) changed = true;
|
|
33
|
+
if (normalized.changed || nextEntries.length !== entries.length) {
|
|
34
|
+
nextHooks[event] = nextEntries;
|
|
35
|
+
}
|
|
24
36
|
}
|
|
25
37
|
|
|
26
|
-
|
|
27
|
-
const nextHooks = { ...hooks, [event]: nextEntries };
|
|
28
|
-
const nextSettings = { ...settings, hooks: nextHooks };
|
|
38
|
+
if (!changed) return { changed: false, backupPath: null };
|
|
29
39
|
|
|
40
|
+
const nextSettings = { ...settings, hooks: nextHooks };
|
|
30
41
|
const backupPath = await writeClaudeSettings({ settingsPath, settings: nextSettings });
|
|
31
42
|
return { changed: true, backupPath };
|
|
32
43
|
}
|
|
33
44
|
|
|
34
45
|
async function removeClaudeHook({ settingsPath, hookCommand, event = DEFAULT_EVENT }) {
|
|
46
|
+
return removeClaudeHooks({ settingsPath, hookCommand, events: [event] });
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function removeClaudeUsageHooks({ settingsPath, hookCommand }) {
|
|
50
|
+
return removeClaudeHooks({ settingsPath, hookCommand, events: CLAUDE_USAGE_EVENTS });
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function removeClaudeHooks({ settingsPath, hookCommand, events }) {
|
|
35
54
|
const existing = await readJson(settingsPath);
|
|
36
55
|
if (!existing) return { removed: false, skippedReason: "settings-missing" };
|
|
37
56
|
|
|
38
57
|
const settings = normalizeSettings(existing);
|
|
39
58
|
const hooks = normalizeHooks(settings.hooks);
|
|
40
|
-
const
|
|
41
|
-
if (entries.length === 0) return { removed: false, skippedReason: "hook-missing" };
|
|
42
|
-
|
|
59
|
+
const nextHooks = { ...hooks };
|
|
43
60
|
let removed = false;
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
61
|
+
for (const event of normalizeEventList(events)) {
|
|
62
|
+
const entries = normalizeEntries(hooks[event]);
|
|
63
|
+
const nextEntries = [];
|
|
64
|
+
for (const entry of entries) {
|
|
65
|
+
const res = stripHookFromEntry(entry, hookCommand);
|
|
66
|
+
if (res.removed) removed = true;
|
|
67
|
+
if (res.entry) nextEntries.push(res.entry);
|
|
68
|
+
}
|
|
69
|
+
if (nextEntries.length > 0) nextHooks[event] = nextEntries;
|
|
70
|
+
else delete nextHooks[event];
|
|
49
71
|
}
|
|
50
72
|
|
|
51
73
|
if (!removed) return { removed: false, skippedReason: "hook-missing" };
|
|
52
74
|
|
|
53
|
-
const nextHooks = { ...hooks };
|
|
54
|
-
if (nextEntries.length > 0) nextHooks[event] = nextEntries;
|
|
55
|
-
else delete nextHooks[event];
|
|
56
|
-
|
|
57
75
|
const nextSettings = { ...settings };
|
|
58
76
|
if (Object.keys(nextHooks).length > 0) nextSettings.hooks = nextHooks;
|
|
59
77
|
else delete nextSettings.hooks;
|
|
@@ -63,12 +81,26 @@ async function removeClaudeHook({ settingsPath, hookCommand, event = DEFAULT_EVE
|
|
|
63
81
|
}
|
|
64
82
|
|
|
65
83
|
async function isClaudeHookConfigured({ settingsPath, hookCommand, event = DEFAULT_EVENT }) {
|
|
84
|
+
return areClaudeHooksConfigured({ settingsPath, hookCommand, events: [event] });
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async function areClaudeUsageHooksConfigured({ settingsPath, hookCommand }) {
|
|
88
|
+
return areClaudeHooksConfigured({
|
|
89
|
+
settingsPath,
|
|
90
|
+
hookCommand,
|
|
91
|
+
events: CLAUDE_USAGE_EVENTS,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async function areClaudeHooksConfigured({ settingsPath, hookCommand, events }) {
|
|
66
96
|
const settings = await readJson(settingsPath);
|
|
67
97
|
if (!settings || typeof settings !== "object") return false;
|
|
68
98
|
const hooks = settings.hooks;
|
|
69
99
|
if (!hooks || typeof hooks !== "object") return false;
|
|
70
|
-
|
|
71
|
-
|
|
100
|
+
return normalizeEventList(events).every((event) => {
|
|
101
|
+
const entries = normalizeEntries(hooks[event]);
|
|
102
|
+
return hasHook(entries, hookCommand);
|
|
103
|
+
});
|
|
72
104
|
}
|
|
73
105
|
|
|
74
106
|
// Generic Session-hook command builder. CodeBuddy CLI is a Claude-Code fork
|
|
@@ -96,6 +128,11 @@ function normalizeEntries(raw) {
|
|
|
96
128
|
return Array.isArray(raw) ? raw.slice() : [];
|
|
97
129
|
}
|
|
98
130
|
|
|
131
|
+
function normalizeEventList(events) {
|
|
132
|
+
const values = Array.isArray(events) ? events : [];
|
|
133
|
+
return Array.from(new Set(values.filter((event) => typeof event === "string" && event)));
|
|
134
|
+
}
|
|
135
|
+
|
|
99
136
|
function normalizeCommand(cmd) {
|
|
100
137
|
if (Array.isArray(cmd)) return cmd.map((v) => String(v)).join("\u0000");
|
|
101
138
|
if (typeof cmd === "string") return cmd.trim();
|
|
@@ -193,9 +230,13 @@ async function writeClaudeSettings({ settingsPath, settings }) {
|
|
|
193
230
|
}
|
|
194
231
|
|
|
195
232
|
module.exports = {
|
|
233
|
+
CLAUDE_USAGE_EVENTS,
|
|
196
234
|
upsertClaudeHook,
|
|
235
|
+
upsertClaudeUsageHooks,
|
|
197
236
|
removeClaudeHook,
|
|
237
|
+
removeClaudeUsageHooks,
|
|
198
238
|
isClaudeHookConfigured,
|
|
239
|
+
areClaudeUsageHooksConfigured,
|
|
199
240
|
buildClaudeHookCommand,
|
|
200
241
|
buildHookCommand,
|
|
201
242
|
// Aliases for callers that want a name unbiased toward Claude (the schema
|
package/src/lib/diagnostics.js
CHANGED
|
@@ -4,7 +4,7 @@ const fs = require("node:fs/promises");
|
|
|
4
4
|
|
|
5
5
|
const { readJson } = require("./fs");
|
|
6
6
|
const { readCodexNotify, readEveryCodeNotify } = require("./codex-config");
|
|
7
|
-
const {
|
|
7
|
+
const { areClaudeUsageHooksConfigured, buildClaudeHookCommand } = require("./claude-config");
|
|
8
8
|
const {
|
|
9
9
|
resolveGeminiConfigDir,
|
|
10
10
|
resolveGeminiSettingsPath,
|
|
@@ -81,7 +81,7 @@ async function collectTrackerDiagnostics({
|
|
|
81
81
|
? everyCodeNotifyRaw.map((v) => redactValue(v, home))
|
|
82
82
|
: null;
|
|
83
83
|
const claudeHookCommand = buildClaudeHookCommand(path.join(binDir, "notify.cjs"));
|
|
84
|
-
const claudeHookConfigured = await
|
|
84
|
+
const claudeHookConfigured = await areClaudeUsageHooksConfigured({
|
|
85
85
|
settingsPath: claudeConfigPath,
|
|
86
86
|
hookCommand: claudeHookCommand,
|
|
87
87
|
});
|
package/src/lib/local-api.js
CHANGED
|
@@ -685,6 +685,7 @@ function runSyncCommand(extraEnv = {}, opts = {}) {
|
|
|
685
685
|
const args = [TRACKER_BIN, "sync"];
|
|
686
686
|
if (opts.auto === true) args.push("--auto");
|
|
687
687
|
if (opts.background === true) args.push("--background");
|
|
688
|
+
if (opts.allLocalSources === true) args.push("--all-local-sources");
|
|
688
689
|
if (opts.drain === true) args.push("--drain");
|
|
689
690
|
const child = spawn(process.execPath, args, {
|
|
690
691
|
env: { ...process.env, ...extraEnv },
|
|
@@ -1053,15 +1054,17 @@ function createLocalApiHandler({ queuePath }) {
|
|
|
1053
1054
|
// sync is on. Cloud sync is a dashboard (WebView) preference persisted in
|
|
1054
1055
|
// localStorage; the dashboard mirrors it here via POST
|
|
1055
1056
|
// /functions/tokentracker-cloud-sync-pref so the auth-unaware popover can key
|
|
1056
|
-
// off the same flag. Defaults
|
|
1057
|
+
// off the same flag. Defaults ON, exactly like the dashboard toggle — every
|
|
1058
|
+
// consumer additionally requires a relayed refresh token, so the default only
|
|
1059
|
+
// takes effect for signed-in users; an explicit {enabled:false} still wins.
|
|
1057
1060
|
const cloudSyncPrefPath = path.join(trackerDataDir, "cloud-sync-pref.json");
|
|
1058
1061
|
let cloudSyncPrefCache;
|
|
1059
1062
|
function getCloudSyncPref() {
|
|
1060
1063
|
if (cloudSyncPrefCache === undefined) {
|
|
1061
1064
|
try {
|
|
1062
|
-
cloudSyncPrefCache = JSON.parse(fs.readFileSync(cloudSyncPrefPath, "utf8"))?.enabled
|
|
1065
|
+
cloudSyncPrefCache = JSON.parse(fs.readFileSync(cloudSyncPrefPath, "utf8"))?.enabled !== false;
|
|
1063
1066
|
} catch {
|
|
1064
|
-
cloudSyncPrefCache =
|
|
1067
|
+
cloudSyncPrefCache = true;
|
|
1065
1068
|
}
|
|
1066
1069
|
}
|
|
1067
1070
|
return cloudSyncPrefCache;
|
|
@@ -1693,6 +1696,7 @@ function createLocalApiHandler({ queuePath }) {
|
|
|
1693
1696
|
const auto = body.auto === true && !drain;
|
|
1694
1697
|
const background =
|
|
1695
1698
|
auto && (body.background === true || body.lightweight === true);
|
|
1699
|
+
const allLocalSources = background && body.allLocalSources === true;
|
|
1696
1700
|
if (typeof body.deviceToken === "string" && body.deviceToken.trim()) {
|
|
1697
1701
|
extraEnv.TOKENTRACKER_DEVICE_TOKEN = body.deviceToken.trim();
|
|
1698
1702
|
}
|
|
@@ -1724,7 +1728,12 @@ function createLocalApiHandler({ queuePath }) {
|
|
|
1724
1728
|
extraEnv.TOKENTRACKER_DEVICE_TOKEN = issuedToken;
|
|
1725
1729
|
}
|
|
1726
1730
|
}
|
|
1727
|
-
const result = await runSyncCommand(extraEnv, {
|
|
1731
|
+
const result = await runSyncCommand(extraEnv, {
|
|
1732
|
+
drain,
|
|
1733
|
+
auto,
|
|
1734
|
+
background,
|
|
1735
|
+
allLocalSources,
|
|
1736
|
+
});
|
|
1728
1737
|
try {
|
|
1729
1738
|
const { resetUsageLimitsCache } = require("./usage-limits");
|
|
1730
1739
|
resetUsageLimitsCache();
|
|
@@ -2572,14 +2581,18 @@ function createLocalApiHandler({ queuePath }) {
|
|
|
2572
2581
|
if (p === "/functions/tokentracker-usage-limits") {
|
|
2573
2582
|
const { getUsageLimits, resetUsageLimitsCache } = require("./usage-limits");
|
|
2574
2583
|
try {
|
|
2575
|
-
const
|
|
2576
|
-
|
|
2584
|
+
const refreshParam = url.searchParams.get("refresh");
|
|
2585
|
+
const forceRefresh = refreshParam === "1" || refreshParam === "true";
|
|
2586
|
+
if (forceRefresh) {
|
|
2577
2587
|
resetUsageLimitsCache();
|
|
2578
2588
|
}
|
|
2579
2589
|
const data = await getUsageLimits({
|
|
2580
2590
|
home: os.homedir(),
|
|
2581
2591
|
env: process.env,
|
|
2582
2592
|
platform: process.platform,
|
|
2593
|
+
// Punches through the Claude disk fresh-cache (but not the 429
|
|
2594
|
+
// cooldown) — an explicit user refresh should hit upstream.
|
|
2595
|
+
forceRefresh,
|
|
2583
2596
|
});
|
|
2584
2597
|
json(res, data);
|
|
2585
2598
|
} catch (e) {
|
|
@@ -312,6 +312,19 @@ async function removeOpenclawSessionPluginConfig({
|
|
|
312
312
|
}
|
|
313
313
|
|
|
314
314
|
function runOpenclawCli(args, env = process.env) {
|
|
315
|
+
// Test-only escape hatch: skip spawning the real `openclaw` CLI. Behaves like
|
|
316
|
+
// the CLI being absent (which is the CI environment anyway), so callers take
|
|
317
|
+
// their graceful skip path. Avoids a ~2s `plugins install --link` per cmdInit
|
|
318
|
+
// on dev machines that happen to have openclaw installed.
|
|
319
|
+
if ((env && env.TOKENTRACKER_SKIP_OPENCLAW_CLI) === "1") {
|
|
320
|
+
return {
|
|
321
|
+
code: 1,
|
|
322
|
+
skippedReason: "openclaw-cli-missing",
|
|
323
|
+
error: "skipped via TOKENTRACKER_SKIP_OPENCLAW_CLI",
|
|
324
|
+
stdout: "",
|
|
325
|
+
stderr: "",
|
|
326
|
+
};
|
|
327
|
+
}
|
|
315
328
|
let res;
|
|
316
329
|
try {
|
|
317
330
|
res = cp.spawnSync("openclaw", args, {
|