vibeusage 0.2.21 → 0.2.23
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 +306 -173
- package/README.old.md +324 -0
- package/README.zh-CN.md +304 -188
- package/package.json +32 -32
- package/src/cli.js +37 -37
- package/src/commands/activate-if-needed.js +41 -0
- package/src/commands/diagnostics.js +8 -9
- package/src/commands/doctor.js +31 -26
- package/src/commands/init.js +285 -218
- package/src/commands/status.js +86 -83
- package/src/commands/sync.js +178 -130
- package/src/commands/uninstall.js +66 -62
- package/src/lib/activation-check.js +341 -0
- package/src/lib/browser-auth.js +52 -54
- package/src/lib/claude-config.js +25 -25
- package/src/lib/cli-ui.js +35 -35
- package/src/lib/codex-config.js +40 -36
- package/src/lib/debug-flags.js +2 -2
- package/src/lib/diagnostics.js +70 -57
- package/src/lib/doctor.js +139 -132
- package/src/lib/fs.js +17 -17
- package/src/lib/gemini-config.js +44 -40
- package/src/lib/init-flow.js +16 -22
- package/src/lib/insforge-client.js +10 -10
- package/src/lib/insforge.js +9 -3
- package/src/lib/openclaw-hook.js +89 -66
- package/src/lib/openclaw-session-plugin.js +116 -92
- package/src/lib/opencode-config.js +31 -32
- package/src/lib/opencode-usage-audit.js +34 -31
- package/src/lib/progress.js +12 -13
- package/src/lib/project-usage-purge.js +23 -17
- package/src/lib/prompt.js +8 -4
- package/src/lib/rollout.js +342 -241
- package/src/lib/runtime-config.js +34 -22
- package/src/lib/subscriptions.js +94 -92
- package/src/lib/tracker-paths.js +6 -6
- package/src/lib/upload-throttle.js +35 -16
- package/src/lib/uploader.js +33 -29
- package/src/lib/vibeusage-api.js +72 -56
- package/src/lib/vibeusage-public-repo.js +41 -24
package/src/commands/init.js
CHANGED
|
@@ -1,40 +1,54 @@
|
|
|
1
|
-
const os = require(
|
|
2
|
-
const path = require(
|
|
3
|
-
const fs = require(
|
|
4
|
-
const fssync = require(
|
|
5
|
-
const cp = require(
|
|
6
|
-
const crypto = require(
|
|
1
|
+
const os = require("node:os");
|
|
2
|
+
const path = require("node:path");
|
|
3
|
+
const fs = require("node:fs/promises");
|
|
4
|
+
const fssync = require("node:fs");
|
|
5
|
+
const cp = require("node:child_process");
|
|
6
|
+
const crypto = require("node:crypto");
|
|
7
7
|
|
|
8
|
-
const {
|
|
9
|
-
|
|
8
|
+
const {
|
|
9
|
+
ensureDir,
|
|
10
|
+
writeFileAtomic,
|
|
11
|
+
readJson,
|
|
12
|
+
writeJson,
|
|
13
|
+
chmod600IfPossible,
|
|
14
|
+
} = require("../lib/fs");
|
|
15
|
+
const { prompt, promptHidden } = require("../lib/prompt");
|
|
10
16
|
const {
|
|
11
17
|
upsertCodexNotify,
|
|
12
18
|
upsertEveryCodeNotify,
|
|
13
19
|
readCodexNotify,
|
|
14
|
-
readEveryCodeNotify
|
|
15
|
-
} = require(
|
|
16
|
-
const {
|
|
20
|
+
readEveryCodeNotify,
|
|
21
|
+
} = require("../lib/codex-config");
|
|
22
|
+
const {
|
|
23
|
+
upsertClaudeHook,
|
|
24
|
+
buildClaudeHookCommand,
|
|
25
|
+
isClaudeHookConfigured,
|
|
26
|
+
} = require("../lib/claude-config");
|
|
17
27
|
const {
|
|
18
28
|
resolveGeminiConfigDir,
|
|
19
29
|
resolveGeminiSettingsPath,
|
|
20
30
|
buildGeminiHookCommand,
|
|
21
31
|
upsertGeminiHook,
|
|
22
|
-
isGeminiHookConfigured
|
|
23
|
-
} = require(
|
|
24
|
-
const {
|
|
25
|
-
|
|
32
|
+
isGeminiHookConfigured,
|
|
33
|
+
} = require("../lib/gemini-config");
|
|
34
|
+
const {
|
|
35
|
+
resolveOpencodeConfigDir,
|
|
36
|
+
upsertOpencodePlugin,
|
|
37
|
+
isOpencodePluginInstalled,
|
|
38
|
+
} = require("../lib/opencode-config");
|
|
39
|
+
const { removeOpenclawHookConfig, probeOpenclawHookState } = require("../lib/openclaw-hook");
|
|
26
40
|
const {
|
|
27
41
|
installOpenclawSessionPlugin,
|
|
28
|
-
probeOpenclawSessionPluginState
|
|
29
|
-
} = require(
|
|
30
|
-
const { beginBrowserAuth, openInBrowser } = require(
|
|
42
|
+
probeOpenclawSessionPluginState,
|
|
43
|
+
} = require("../lib/openclaw-session-plugin");
|
|
44
|
+
const { beginBrowserAuth, openInBrowser } = require("../lib/browser-auth");
|
|
31
45
|
const {
|
|
32
46
|
issueDeviceTokenWithPassword,
|
|
33
47
|
issueDeviceTokenWithAccessToken,
|
|
34
|
-
issueDeviceTokenWithLinkCode
|
|
35
|
-
} = require(
|
|
36
|
-
const { resolveTrackerPaths } = require(
|
|
37
|
-
const { resolveRuntimeConfig } = require(
|
|
48
|
+
issueDeviceTokenWithLinkCode,
|
|
49
|
+
} = require("../lib/insforge");
|
|
50
|
+
const { resolveTrackerPaths } = require("../lib/tracker-paths");
|
|
51
|
+
const { resolveRuntimeConfig } = require("../lib/runtime-config");
|
|
38
52
|
const {
|
|
39
53
|
BOLD,
|
|
40
54
|
DIM,
|
|
@@ -43,21 +57,21 @@ const {
|
|
|
43
57
|
color,
|
|
44
58
|
isInteractive,
|
|
45
59
|
promptMenu,
|
|
46
|
-
createSpinner
|
|
47
|
-
} = require(
|
|
48
|
-
const { renderLocalReport, renderAuthTransition, renderSuccessBox } = require(
|
|
60
|
+
createSpinner,
|
|
61
|
+
} = require("../lib/cli-ui");
|
|
62
|
+
const { renderLocalReport, renderAuthTransition, renderSuccessBox } = require("../lib/init-flow");
|
|
49
63
|
|
|
50
64
|
const ASCII_LOGO = [
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
].join(
|
|
65
|
+
"██╗ ██╗██╗██████╗ ███████╗██╗ ██╗███████╗ █████╗ ██████╗ ███████╗",
|
|
66
|
+
"██║ ██║██║██╔══██╗██╔════╝██║ ██║██╔════╝██╔══██╗██╔════╝ ██╔════╝",
|
|
67
|
+
"██║ ██║██║██████╔╝█████╗ ██║ ██║███████╗███████║██║ ███╗█████╗",
|
|
68
|
+
"╚██╗ ██╔╝██║██╔══██╗██╔══╝ ██║ ██║╚════██║██╔══██║██║ ██║██╔══╝",
|
|
69
|
+
" ╚████╔╝ ██║██████╔╝███████╗╚██████╔╝███████║██║ ██║╚██████╔╝███████╗",
|
|
70
|
+
" ╚═══╝ ╚═╝╚═════╝ ╚══════╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚══════╝",
|
|
71
|
+
].join("\n");
|
|
58
72
|
|
|
59
|
-
const DIVIDER =
|
|
60
|
-
const DEFAULT_DASHBOARD_URL =
|
|
73
|
+
const DIVIDER = "----------------------------------------------";
|
|
74
|
+
const DEFAULT_DASHBOARD_URL = "https://www.vibeusage.cc";
|
|
61
75
|
|
|
62
76
|
async function cmdInit(argv) {
|
|
63
77
|
const opts = parseArgs(argv);
|
|
@@ -65,37 +79,39 @@ async function cmdInit(argv) {
|
|
|
65
79
|
|
|
66
80
|
const { rootDir, trackerDir, binDir } = await resolveTrackerPaths({ home });
|
|
67
81
|
|
|
68
|
-
const configPath = path.join(trackerDir,
|
|
69
|
-
const notifyOriginalPath = path.join(trackerDir,
|
|
70
|
-
const linkCodeStatePath = path.join(trackerDir,
|
|
82
|
+
const configPath = path.join(trackerDir, "config.json");
|
|
83
|
+
const notifyOriginalPath = path.join(trackerDir, "codex_notify_original.json");
|
|
84
|
+
const linkCodeStatePath = path.join(trackerDir, "link_code_state.json");
|
|
71
85
|
|
|
72
86
|
const existingConfig = await readJson(configPath);
|
|
73
87
|
const runtime = resolveRuntimeConfig({
|
|
74
88
|
cli: { baseUrl: opts.baseUrl, dashboardUrl: opts.dashboardUrl },
|
|
75
89
|
config: existingConfig || {},
|
|
76
|
-
env: process.env
|
|
90
|
+
env: process.env,
|
|
77
91
|
});
|
|
78
92
|
const baseUrl = runtime.baseUrl;
|
|
79
93
|
let dashboardUrl = runtime.dashboardUrl || DEFAULT_DASHBOARD_URL;
|
|
80
|
-
const notifyPath = path.join(binDir,
|
|
81
|
-
const appDir = path.join(trackerDir,
|
|
82
|
-
const trackerBinPath = path.join(appDir,
|
|
94
|
+
const notifyPath = path.join(binDir, "notify.cjs");
|
|
95
|
+
const appDir = path.join(trackerDir, "app");
|
|
96
|
+
const trackerBinPath = path.join(appDir, "bin", "tracker.js");
|
|
83
97
|
|
|
84
98
|
renderWelcome();
|
|
85
99
|
|
|
86
100
|
if (opts.dryRun) {
|
|
87
|
-
process.stdout.write(`${color(
|
|
101
|
+
process.stdout.write(`${color("Dry run: preview only (no changes applied).", DIM)}\n\n`);
|
|
88
102
|
}
|
|
89
103
|
|
|
90
104
|
if (isInteractive() && !opts.yes && !opts.dryRun) {
|
|
91
105
|
const choice = await promptMenu({
|
|
92
|
-
message:
|
|
93
|
-
options: [
|
|
94
|
-
defaultIndex: 0
|
|
106
|
+
message: "? Proceed with installation?",
|
|
107
|
+
options: ["Yes, configure my environment", "No, exit"],
|
|
108
|
+
defaultIndex: 0,
|
|
95
109
|
});
|
|
96
|
-
const normalizedChoice = String(choice ||
|
|
97
|
-
|
|
98
|
-
|
|
110
|
+
const normalizedChoice = String(choice || "")
|
|
111
|
+
.trim()
|
|
112
|
+
.toLowerCase();
|
|
113
|
+
if (normalizedChoice.startsWith("no") || normalizedChoice.includes("exit")) {
|
|
114
|
+
process.stdout.write("Setup cancelled.\n");
|
|
99
115
|
return;
|
|
100
116
|
}
|
|
101
117
|
}
|
|
@@ -106,18 +122,18 @@ async function cmdInit(argv) {
|
|
|
106
122
|
home,
|
|
107
123
|
trackerDir,
|
|
108
124
|
notifyPath,
|
|
109
|
-
runtime
|
|
125
|
+
runtime,
|
|
110
126
|
});
|
|
111
127
|
renderLocalReport({ summary: preview.summary, isDryRun: true });
|
|
112
128
|
if (preview.pendingBrowserAuth) {
|
|
113
|
-
process.stdout.write(
|
|
129
|
+
process.stdout.write("Account linking would be required for full setup.\n");
|
|
114
130
|
} else if (!preview.deviceToken) {
|
|
115
|
-
renderAccountNotLinked({ context:
|
|
131
|
+
renderAccountNotLinked({ context: "dry-run" });
|
|
116
132
|
}
|
|
117
133
|
return;
|
|
118
134
|
}
|
|
119
135
|
|
|
120
|
-
const spinner = createSpinner({ text:
|
|
136
|
+
const spinner = createSpinner({ text: "Analyzing and configuring local environment..." });
|
|
121
137
|
spinner.start();
|
|
122
138
|
let setup;
|
|
123
139
|
try {
|
|
@@ -134,7 +150,7 @@ async function cmdInit(argv) {
|
|
|
134
150
|
appDir,
|
|
135
151
|
trackerBinPath,
|
|
136
152
|
runtime,
|
|
137
|
-
existingConfig
|
|
153
|
+
existingConfig,
|
|
138
154
|
});
|
|
139
155
|
} catch (err) {
|
|
140
156
|
spinner.stop();
|
|
@@ -149,7 +165,12 @@ async function cmdInit(argv) {
|
|
|
149
165
|
|
|
150
166
|
if (setup.pendingBrowserAuth) {
|
|
151
167
|
const deviceName = opts.deviceName || os.hostname();
|
|
152
|
-
const flow = await beginBrowserAuth({
|
|
168
|
+
const flow = await beginBrowserAuth({
|
|
169
|
+
baseUrl,
|
|
170
|
+
dashboardUrl,
|
|
171
|
+
timeoutMs: 10 * 60_000,
|
|
172
|
+
open: false,
|
|
173
|
+
});
|
|
153
174
|
const canAutoOpen = !opts.noOpen;
|
|
154
175
|
renderAuthTransition({ authUrl: flow.authUrl, canAutoOpen });
|
|
155
176
|
if (canAutoOpen) {
|
|
@@ -157,7 +178,11 @@ async function cmdInit(argv) {
|
|
|
157
178
|
openInBrowser(flow.authUrl);
|
|
158
179
|
}
|
|
159
180
|
const callback = await flow.waitForCallback();
|
|
160
|
-
const issued = await issueDeviceTokenWithAccessToken({
|
|
181
|
+
const issued = await issueDeviceTokenWithAccessToken({
|
|
182
|
+
baseUrl,
|
|
183
|
+
accessToken: callback.accessToken,
|
|
184
|
+
deviceName,
|
|
185
|
+
});
|
|
161
186
|
deviceToken = issued.token;
|
|
162
187
|
deviceId = issued.deviceId;
|
|
163
188
|
await writeJson(configPath, { baseUrl, deviceToken, deviceId, installedAt: setup.installedAt });
|
|
@@ -172,9 +197,9 @@ async function cmdInit(argv) {
|
|
|
172
197
|
}
|
|
173
198
|
|
|
174
199
|
try {
|
|
175
|
-
spawnInitSync({ trackerBinPath, packageName:
|
|
200
|
+
spawnInitSync({ trackerBinPath, packageName: "vibeusage" });
|
|
176
201
|
} catch (err) {
|
|
177
|
-
const msg = err && err.message ? err.message :
|
|
202
|
+
const msg = err && err.message ? err.message : "unknown error";
|
|
178
203
|
process.stderr.write(`Initial sync spawn failed: ${msg}\n`);
|
|
179
204
|
}
|
|
180
205
|
}
|
|
@@ -183,29 +208,38 @@ function renderWelcome() {
|
|
|
183
208
|
process.stdout.write(
|
|
184
209
|
[
|
|
185
210
|
ASCII_LOGO,
|
|
186
|
-
|
|
211
|
+
"",
|
|
187
212
|
`${BOLD}Welcome to VibeScore CLI${RESET}`,
|
|
188
213
|
DIVIDER,
|
|
189
214
|
`${CYAN}Privacy First: Your content stays local. We only upload token counts and minimal metadata, never prompts or responses.${RESET}`,
|
|
190
215
|
DIVIDER,
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
].join(
|
|
216
|
+
"",
|
|
217
|
+
"This tool will:",
|
|
218
|
+
" - Analyze your local AI CLI configurations (Codex, Every Code, Claude, Gemini, Opencode, OpenClaw)",
|
|
219
|
+
" - Set up lightweight hooks to track your flow state",
|
|
220
|
+
" - Link your device to your VibeScore account",
|
|
221
|
+
"",
|
|
222
|
+
"(Nothing will be changed until you confirm below)",
|
|
223
|
+
"",
|
|
224
|
+
].join("\n"),
|
|
200
225
|
);
|
|
201
226
|
}
|
|
202
227
|
|
|
203
228
|
function renderAccountNotLinked({ context } = {}) {
|
|
204
|
-
if (context ===
|
|
205
|
-
process.stdout.write(
|
|
229
|
+
if (context === "dry-run") {
|
|
230
|
+
process.stdout.write(
|
|
231
|
+
[
|
|
232
|
+
"",
|
|
233
|
+
"Account not linked (dry run).",
|
|
234
|
+
"Run init without --dry-run to link your account.",
|
|
235
|
+
"",
|
|
236
|
+
].join("\n"),
|
|
237
|
+
);
|
|
206
238
|
return;
|
|
207
239
|
}
|
|
208
|
-
process.stdout.write(
|
|
240
|
+
process.stdout.write(
|
|
241
|
+
["", "Account not linked.", "Set VIBEUSAGE_DEVICE_TOKEN then re-run init.", ""].join("\n"),
|
|
242
|
+
);
|
|
209
243
|
}
|
|
210
244
|
|
|
211
245
|
function shouldUseBrowserAuth({ deviceToken, opts }) {
|
|
@@ -237,7 +271,7 @@ async function runSetup({
|
|
|
237
271
|
appDir,
|
|
238
272
|
trackerBinPath,
|
|
239
273
|
runtime,
|
|
240
|
-
existingConfig
|
|
274
|
+
existingConfig,
|
|
241
275
|
}) {
|
|
242
276
|
await ensureDir(trackerDir);
|
|
243
277
|
await ensureDir(binDir);
|
|
@@ -252,7 +286,7 @@ async function runSetup({
|
|
|
252
286
|
const deviceName = opts.deviceName || os.hostname();
|
|
253
287
|
const platform = normalizePlatform(process.platform);
|
|
254
288
|
const linkCode = String(opts.linkCode);
|
|
255
|
-
const linkCodeHash = crypto.createHash(
|
|
289
|
+
const linkCodeHash = crypto.createHash("sha256").update(linkCode).digest("hex");
|
|
256
290
|
const existingLinkState = await readJson(linkCodeStatePath);
|
|
257
291
|
let requestId =
|
|
258
292
|
existingLinkState?.linkCodeHash === linkCodeHash && existingLinkState?.requestId
|
|
@@ -263,7 +297,7 @@ async function runSetup({
|
|
|
263
297
|
await writeJson(linkCodeStatePath, {
|
|
264
298
|
linkCodeHash,
|
|
265
299
|
requestId,
|
|
266
|
-
createdAt: new Date().toISOString()
|
|
300
|
+
createdAt: new Date().toISOString(),
|
|
267
301
|
});
|
|
268
302
|
await chmod600IfPossible(linkCodeStatePath);
|
|
269
303
|
}
|
|
@@ -272,7 +306,7 @@ async function runSetup({
|
|
|
272
306
|
linkCode,
|
|
273
307
|
requestId,
|
|
274
308
|
deviceName,
|
|
275
|
-
platform
|
|
309
|
+
platform,
|
|
276
310
|
});
|
|
277
311
|
deviceToken = issued.token;
|
|
278
312
|
deviceId = issued.deviceId;
|
|
@@ -281,8 +315,8 @@ async function runSetup({
|
|
|
281
315
|
const deviceName = opts.deviceName || os.hostname();
|
|
282
316
|
|
|
283
317
|
if (opts.email || opts.password) {
|
|
284
|
-
const email = opts.email || (await prompt(
|
|
285
|
-
const password = opts.password || (await promptHidden(
|
|
318
|
+
const email = opts.email || (await prompt("Email: "));
|
|
319
|
+
const password = opts.password || (await promptHidden("Password: "));
|
|
286
320
|
const issued = await issueDeviceTokenWithPassword({ baseUrl, email, password, deviceName });
|
|
287
321
|
deviceToken = issued.token;
|
|
288
322
|
deviceId = issued.deviceId;
|
|
@@ -295,7 +329,7 @@ async function runSetup({
|
|
|
295
329
|
baseUrl,
|
|
296
330
|
deviceToken,
|
|
297
331
|
deviceId,
|
|
298
|
-
installedAt
|
|
332
|
+
installedAt,
|
|
299
333
|
};
|
|
300
334
|
|
|
301
335
|
await writeJson(configPath, config);
|
|
@@ -303,7 +337,7 @@ async function runSetup({
|
|
|
303
337
|
|
|
304
338
|
await writeFileAtomic(
|
|
305
339
|
notifyPath,
|
|
306
|
-
buildNotifyHandler({ trackerDir, trackerBinPath, packageName:
|
|
340
|
+
buildNotifyHandler({ trackerDir, trackerBinPath, packageName: "vibeusage" }),
|
|
307
341
|
);
|
|
308
342
|
await fs.chmod(notifyPath, 0o755).catch(() => {});
|
|
309
343
|
|
|
@@ -311,7 +345,7 @@ async function runSetup({
|
|
|
311
345
|
home,
|
|
312
346
|
trackerDir,
|
|
313
347
|
notifyPath,
|
|
314
|
-
notifyOriginalPath
|
|
348
|
+
notifyOriginalPath,
|
|
315
349
|
});
|
|
316
350
|
|
|
317
351
|
return {
|
|
@@ -319,21 +353,21 @@ async function runSetup({
|
|
|
319
353
|
pendingBrowserAuth,
|
|
320
354
|
deviceToken,
|
|
321
355
|
deviceId,
|
|
322
|
-
installedAt
|
|
356
|
+
installedAt,
|
|
323
357
|
};
|
|
324
358
|
}
|
|
325
359
|
|
|
326
360
|
function buildIntegrationTargets({ home, trackerDir, notifyPath }) {
|
|
327
|
-
const codexHome = process.env.CODEX_HOME || path.join(home,
|
|
328
|
-
const codexConfigPath = path.join(codexHome,
|
|
329
|
-
const codeHome = process.env.CODE_HOME || path.join(home,
|
|
330
|
-
const codeConfigPath = path.join(codeHome,
|
|
331
|
-
const notifyOriginalPath = path.join(trackerDir,
|
|
332
|
-
const codeNotifyOriginalPath = path.join(trackerDir,
|
|
333
|
-
const notifyCmd = [
|
|
334
|
-
const codeNotifyCmd = [
|
|
335
|
-
const claudeDir = path.join(home,
|
|
336
|
-
const claudeSettingsPath = path.join(claudeDir,
|
|
361
|
+
const codexHome = process.env.CODEX_HOME || path.join(home, ".codex");
|
|
362
|
+
const codexConfigPath = path.join(codexHome, "config.toml");
|
|
363
|
+
const codeHome = process.env.CODE_HOME || path.join(home, ".code");
|
|
364
|
+
const codeConfigPath = path.join(codeHome, "config.toml");
|
|
365
|
+
const notifyOriginalPath = path.join(trackerDir, "codex_notify_original.json");
|
|
366
|
+
const codeNotifyOriginalPath = path.join(trackerDir, "code_notify_original.json");
|
|
367
|
+
const notifyCmd = ["/usr/bin/env", "node", notifyPath];
|
|
368
|
+
const codeNotifyCmd = ["/usr/bin/env", "node", notifyPath, "--source=every-code"];
|
|
369
|
+
const claudeDir = path.join(home, ".claude");
|
|
370
|
+
const claudeSettingsPath = path.join(claudeDir, "settings.json");
|
|
337
371
|
const claudeHookCommand = buildClaudeHookCommand(notifyPath);
|
|
338
372
|
const geminiConfigDir = resolveGeminiConfigDir({ home, env: process.env });
|
|
339
373
|
const geminiSettingsPath = resolveGeminiSettingsPath({ configDir: geminiConfigDir });
|
|
@@ -354,7 +388,7 @@ function buildIntegrationTargets({ home, trackerDir, notifyPath }) {
|
|
|
354
388
|
geminiConfigDir,
|
|
355
389
|
geminiSettingsPath,
|
|
356
390
|
geminiHookCommand,
|
|
357
|
-
opencodeConfigDir
|
|
391
|
+
opencodeConfigDir,
|
|
358
392
|
};
|
|
359
393
|
}
|
|
360
394
|
|
|
@@ -369,89 +403,107 @@ async function applyIntegrationSetup({ home, trackerDir, notifyPath, notifyOrigi
|
|
|
369
403
|
const result = await upsertCodexNotify({
|
|
370
404
|
codexConfigPath: context.codexConfigPath,
|
|
371
405
|
notifyCmd: context.notifyCmd,
|
|
372
|
-
notifyOriginalPath: context.notifyOriginalPath
|
|
406
|
+
notifyOriginalPath: context.notifyOriginalPath,
|
|
373
407
|
});
|
|
374
408
|
summary.push({
|
|
375
|
-
label:
|
|
376
|
-
status: result.changed ?
|
|
377
|
-
detail: result.changed ?
|
|
409
|
+
label: "Codex CLI",
|
|
410
|
+
status: result.changed ? "updated" : "set",
|
|
411
|
+
detail: result.changed ? "Updated config" : "Config already set",
|
|
378
412
|
});
|
|
379
413
|
} else {
|
|
380
|
-
summary.push({ label:
|
|
414
|
+
summary.push({ label: "Codex CLI", status: "skipped", detail: renderSkipDetail(codexProbe) });
|
|
381
415
|
}
|
|
382
416
|
|
|
383
417
|
const claudeDirExists = await isDir(context.claudeDir);
|
|
384
418
|
if (claudeDirExists) {
|
|
385
419
|
await upsertClaudeHook({
|
|
386
420
|
settingsPath: context.claudeSettingsPath,
|
|
387
|
-
hookCommand: context.claudeHookCommand
|
|
421
|
+
hookCommand: context.claudeHookCommand,
|
|
388
422
|
});
|
|
389
|
-
summary.push({ label:
|
|
423
|
+
summary.push({ label: "Claude", status: "installed", detail: "Hooks installed" });
|
|
390
424
|
} else {
|
|
391
|
-
summary.push({ label:
|
|
425
|
+
summary.push({ label: "Claude", status: "skipped", detail: "Config not found" });
|
|
392
426
|
}
|
|
393
427
|
|
|
394
428
|
const geminiConfigExists = await isDir(context.geminiConfigDir);
|
|
395
429
|
if (geminiConfigExists) {
|
|
396
430
|
await upsertGeminiHook({
|
|
397
431
|
settingsPath: context.geminiSettingsPath,
|
|
398
|
-
hookCommand: context.geminiHookCommand
|
|
432
|
+
hookCommand: context.geminiHookCommand,
|
|
399
433
|
});
|
|
400
|
-
summary.push({ label:
|
|
434
|
+
summary.push({ label: "Gemini", status: "installed", detail: "Hooks installed" });
|
|
401
435
|
} else {
|
|
402
|
-
summary.push({ label:
|
|
436
|
+
summary.push({ label: "Gemini", status: "skipped", detail: "Config not found" });
|
|
403
437
|
}
|
|
404
438
|
|
|
405
439
|
const opencodeResult = await upsertOpencodePlugin({
|
|
406
440
|
configDir: context.opencodeConfigDir,
|
|
407
|
-
notifyPath
|
|
441
|
+
notifyPath,
|
|
408
442
|
});
|
|
409
|
-
if (opencodeResult?.skippedReason ===
|
|
410
|
-
summary.push({ label:
|
|
443
|
+
if (opencodeResult?.skippedReason === "config-missing") {
|
|
444
|
+
summary.push({ label: "Opencode Plugin", status: "skipped", detail: "Config not found" });
|
|
411
445
|
} else {
|
|
412
|
-
summary.push({
|
|
446
|
+
summary.push({
|
|
447
|
+
label: "Opencode Plugin",
|
|
448
|
+
status: opencodeResult?.changed ? "installed" : "set",
|
|
449
|
+
detail: "Plugin installed",
|
|
450
|
+
});
|
|
413
451
|
}
|
|
414
452
|
|
|
415
|
-
const openclawBefore = await probeOpenclawSessionPluginState({
|
|
453
|
+
const openclawBefore = await probeOpenclawSessionPluginState({
|
|
454
|
+
home,
|
|
455
|
+
trackerDir,
|
|
456
|
+
env: process.env,
|
|
457
|
+
});
|
|
416
458
|
const openclawInstall = await installOpenclawSessionPlugin({
|
|
417
459
|
home,
|
|
418
460
|
trackerDir,
|
|
419
|
-
packageName:
|
|
420
|
-
env: process.env
|
|
461
|
+
packageName: "vibeusage",
|
|
462
|
+
env: process.env,
|
|
421
463
|
});
|
|
422
|
-
if (openclawInstall?.skippedReason ===
|
|
423
|
-
summary.push({
|
|
424
|
-
|
|
464
|
+
if (openclawInstall?.skippedReason === "openclaw-cli-missing") {
|
|
465
|
+
summary.push({
|
|
466
|
+
label: "OpenClaw Session Plugin",
|
|
467
|
+
status: "skipped",
|
|
468
|
+
detail: "OpenClaw CLI not found",
|
|
469
|
+
});
|
|
470
|
+
} else if (openclawInstall?.skippedReason === "openclaw-plugins-install-failed") {
|
|
425
471
|
summary.push({
|
|
426
|
-
label:
|
|
427
|
-
status:
|
|
428
|
-
detail: `Install failed${openclawInstall.error ? `: ${openclawInstall.error}` :
|
|
472
|
+
label: "OpenClaw Session Plugin",
|
|
473
|
+
status: "skipped",
|
|
474
|
+
detail: `Install failed${openclawInstall.error ? `: ${openclawInstall.error}` : ""}`,
|
|
429
475
|
});
|
|
430
|
-
} else if (openclawInstall?.skippedReason ===
|
|
476
|
+
} else if (openclawInstall?.skippedReason === "openclaw-config-unreadable") {
|
|
431
477
|
summary.push({
|
|
432
|
-
label:
|
|
433
|
-
status:
|
|
434
|
-
detail: openclawInstall.error
|
|
478
|
+
label: "OpenClaw Session Plugin",
|
|
479
|
+
status: "skipped",
|
|
480
|
+
detail: openclawInstall.error
|
|
481
|
+
? `OpenClaw config unreadable: ${openclawInstall.error}`
|
|
482
|
+
: "OpenClaw config unreadable",
|
|
435
483
|
});
|
|
436
484
|
} else if (openclawInstall?.configured) {
|
|
437
485
|
summary.push({
|
|
438
|
-
label:
|
|
439
|
-
status: openclawBefore?.configured ?
|
|
486
|
+
label: "OpenClaw Session Plugin",
|
|
487
|
+
status: openclawBefore?.configured ? "set" : "installed",
|
|
440
488
|
detail: openclawBefore?.configured
|
|
441
|
-
?
|
|
442
|
-
:
|
|
489
|
+
? "Session plugin already linked"
|
|
490
|
+
: "Session plugin linked (restart OpenClaw gateway to activate)",
|
|
443
491
|
});
|
|
444
492
|
} else {
|
|
445
|
-
summary.push({
|
|
493
|
+
summary.push({
|
|
494
|
+
label: "OpenClaw Session Plugin",
|
|
495
|
+
status: "skipped",
|
|
496
|
+
detail: "OpenClaw session plugin unavailable",
|
|
497
|
+
});
|
|
446
498
|
}
|
|
447
499
|
|
|
448
500
|
const legacyHookState = await probeOpenclawHookState({ home, trackerDir, env: process.env });
|
|
449
501
|
if (legacyHookState?.configured || legacyHookState?.linked || legacyHookState?.enabled) {
|
|
450
502
|
await removeOpenclawHookConfig({ home, trackerDir, env: process.env });
|
|
451
503
|
summary.push({
|
|
452
|
-
label:
|
|
453
|
-
status:
|
|
454
|
-
detail:
|
|
504
|
+
label: "OpenClaw Hook (legacy)",
|
|
505
|
+
status: "updated",
|
|
506
|
+
detail: "Removed legacy command hook (migrated to session plugin)",
|
|
455
507
|
});
|
|
456
508
|
}
|
|
457
509
|
|
|
@@ -460,15 +512,15 @@ async function applyIntegrationSetup({ home, trackerDir, notifyPath, notifyOrigi
|
|
|
460
512
|
const result = await upsertEveryCodeNotify({
|
|
461
513
|
codeConfigPath: context.codeConfigPath,
|
|
462
514
|
notifyCmd: context.codeNotifyCmd,
|
|
463
|
-
notifyOriginalPath: context.codeNotifyOriginalPath
|
|
515
|
+
notifyOriginalPath: context.codeNotifyOriginalPath,
|
|
464
516
|
});
|
|
465
517
|
summary.push({
|
|
466
|
-
label:
|
|
467
|
-
status: result.changed ?
|
|
468
|
-
detail: result.changed ?
|
|
518
|
+
label: "Every Code",
|
|
519
|
+
status: result.changed ? "updated" : "set",
|
|
520
|
+
detail: result.changed ? "Updated config" : "Config already set",
|
|
469
521
|
});
|
|
470
522
|
} else {
|
|
471
|
-
summary.push({ label:
|
|
523
|
+
summary.push({ label: "Every Code", status: "skipped", detail: renderSkipDetail(codeProbe) });
|
|
472
524
|
}
|
|
473
525
|
|
|
474
526
|
return summary;
|
|
@@ -483,82 +535,96 @@ async function previewIntegrations({ context }) {
|
|
|
483
535
|
const existing = await readCodexNotify(context.codexConfigPath);
|
|
484
536
|
const matches = arraysEqual(existing, context.notifyCmd);
|
|
485
537
|
summary.push({
|
|
486
|
-
label:
|
|
487
|
-
status: matches ?
|
|
488
|
-
detail: matches ?
|
|
538
|
+
label: "Codex CLI",
|
|
539
|
+
status: matches ? "set" : "updated",
|
|
540
|
+
detail: matches ? "Already configured" : "Will update config",
|
|
489
541
|
});
|
|
490
542
|
} else {
|
|
491
|
-
summary.push({ label:
|
|
543
|
+
summary.push({ label: "Codex CLI", status: "skipped", detail: renderSkipDetail(codexProbe) });
|
|
492
544
|
}
|
|
493
545
|
|
|
494
546
|
const claudeDirExists = await isDir(context.claudeDir);
|
|
495
547
|
if (claudeDirExists) {
|
|
496
548
|
const configured = await isClaudeHookConfigured({
|
|
497
549
|
settingsPath: context.claudeSettingsPath,
|
|
498
|
-
hookCommand: context.claudeHookCommand
|
|
550
|
+
hookCommand: context.claudeHookCommand,
|
|
499
551
|
});
|
|
500
552
|
summary.push({
|
|
501
|
-
label:
|
|
502
|
-
status:
|
|
503
|
-
detail: configured ?
|
|
553
|
+
label: "Claude",
|
|
554
|
+
status: "installed",
|
|
555
|
+
detail: configured ? "Hooks already installed" : "Will install hooks",
|
|
504
556
|
});
|
|
505
557
|
} else {
|
|
506
|
-
summary.push({ label:
|
|
558
|
+
summary.push({ label: "Claude", status: "skipped", detail: "Config not found" });
|
|
507
559
|
}
|
|
508
560
|
|
|
509
561
|
const geminiConfigExists = await isDir(context.geminiConfigDir);
|
|
510
562
|
if (geminiConfigExists) {
|
|
511
563
|
const configured = await isGeminiHookConfigured({
|
|
512
564
|
settingsPath: context.geminiSettingsPath,
|
|
513
|
-
hookCommand: context.geminiHookCommand
|
|
565
|
+
hookCommand: context.geminiHookCommand,
|
|
514
566
|
});
|
|
515
567
|
summary.push({
|
|
516
|
-
label:
|
|
517
|
-
status:
|
|
518
|
-
detail: configured ?
|
|
568
|
+
label: "Gemini",
|
|
569
|
+
status: "installed",
|
|
570
|
+
detail: configured ? "Hooks already installed" : "Will install hooks",
|
|
519
571
|
});
|
|
520
572
|
} else {
|
|
521
|
-
summary.push({ label:
|
|
573
|
+
summary.push({ label: "Gemini", status: "skipped", detail: "Config not found" });
|
|
522
574
|
}
|
|
523
575
|
|
|
524
576
|
const opencodeDirExists = await isDir(context.opencodeConfigDir);
|
|
525
577
|
const installed = await isOpencodePluginInstalled({ configDir: context.opencodeConfigDir });
|
|
526
578
|
const opencodeDetail = installed
|
|
527
|
-
?
|
|
579
|
+
? "Plugin already installed"
|
|
528
580
|
: opencodeDirExists
|
|
529
|
-
?
|
|
530
|
-
:
|
|
581
|
+
? "Will install plugin"
|
|
582
|
+
: "Will create config and install plugin";
|
|
531
583
|
summary.push({
|
|
532
|
-
label:
|
|
533
|
-
status:
|
|
534
|
-
detail: opencodeDetail
|
|
584
|
+
label: "Opencode Plugin",
|
|
585
|
+
status: "installed",
|
|
586
|
+
detail: opencodeDetail,
|
|
535
587
|
});
|
|
536
588
|
|
|
537
|
-
const openclawState = await probeOpenclawSessionPluginState({
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
589
|
+
const openclawState = await probeOpenclawSessionPluginState({
|
|
590
|
+
home,
|
|
591
|
+
trackerDir: context.trackerDir,
|
|
592
|
+
env: process.env,
|
|
593
|
+
});
|
|
594
|
+
if (openclawState?.skippedReason === "openclaw-config-missing") {
|
|
541
595
|
summary.push({
|
|
542
|
-
label:
|
|
543
|
-
status:
|
|
544
|
-
detail:
|
|
596
|
+
label: "OpenClaw Session Plugin",
|
|
597
|
+
status: "skipped",
|
|
598
|
+
detail: "OpenClaw config not found",
|
|
599
|
+
});
|
|
600
|
+
} else if (openclawState?.skippedReason === "openclaw-config-unreadable") {
|
|
601
|
+
summary.push({
|
|
602
|
+
label: "OpenClaw Session Plugin",
|
|
603
|
+
status: "skipped",
|
|
604
|
+
detail: openclawState.error
|
|
605
|
+
? `OpenClaw config unreadable: ${openclawState.error}`
|
|
606
|
+
: "OpenClaw config unreadable",
|
|
545
607
|
});
|
|
546
608
|
} else {
|
|
547
609
|
summary.push({
|
|
548
|
-
label:
|
|
549
|
-
status: openclawState?.configured ?
|
|
610
|
+
label: "OpenClaw Session Plugin",
|
|
611
|
+
status: openclawState?.configured ? "set" : "installed",
|
|
550
612
|
detail: openclawState?.configured
|
|
551
|
-
?
|
|
552
|
-
:
|
|
613
|
+
? "Session plugin already linked"
|
|
614
|
+
: "Will link session plugin (restart OpenClaw gateway to activate)",
|
|
553
615
|
});
|
|
554
616
|
}
|
|
555
617
|
|
|
556
|
-
const legacyHookState = await probeOpenclawHookState({
|
|
618
|
+
const legacyHookState = await probeOpenclawHookState({
|
|
619
|
+
home,
|
|
620
|
+
trackerDir: context.trackerDir,
|
|
621
|
+
env: process.env,
|
|
622
|
+
});
|
|
557
623
|
if (legacyHookState?.configured || legacyHookState?.linked || legacyHookState?.enabled) {
|
|
558
624
|
summary.push({
|
|
559
|
-
label:
|
|
560
|
-
status:
|
|
561
|
-
detail:
|
|
625
|
+
label: "OpenClaw Hook (legacy)",
|
|
626
|
+
status: "updated",
|
|
627
|
+
detail: "Will remove legacy command hook during migration",
|
|
562
628
|
});
|
|
563
629
|
}
|
|
564
630
|
|
|
@@ -567,22 +633,22 @@ async function previewIntegrations({ context }) {
|
|
|
567
633
|
const existing = await readEveryCodeNotify(context.codeConfigPath);
|
|
568
634
|
const matches = arraysEqual(existing, context.codeNotifyCmd);
|
|
569
635
|
summary.push({
|
|
570
|
-
label:
|
|
571
|
-
status: matches ?
|
|
572
|
-
detail: matches ?
|
|
636
|
+
label: "Every Code",
|
|
637
|
+
status: matches ? "set" : "updated",
|
|
638
|
+
detail: matches ? "Already configured" : "Will update config",
|
|
573
639
|
});
|
|
574
640
|
} else {
|
|
575
|
-
summary.push({ label:
|
|
641
|
+
summary.push({ label: "Every Code", status: "skipped", detail: renderSkipDetail(codeProbe) });
|
|
576
642
|
}
|
|
577
643
|
|
|
578
644
|
return summary;
|
|
579
645
|
}
|
|
580
646
|
|
|
581
647
|
function renderSkipDetail(probe) {
|
|
582
|
-
if (!probe || probe.reason ===
|
|
583
|
-
if (probe.reason ===
|
|
584
|
-
if (probe.reason ===
|
|
585
|
-
return
|
|
648
|
+
if (!probe || probe.reason === "missing") return "Config not found";
|
|
649
|
+
if (probe.reason === "permission-denied") return "Permission denied";
|
|
650
|
+
if (probe.reason === "not-file") return "Invalid config";
|
|
651
|
+
return "Unavailable";
|
|
586
652
|
}
|
|
587
653
|
|
|
588
654
|
function arraysEqual(a, b) {
|
|
@@ -603,21 +669,21 @@ function parseArgs(argv) {
|
|
|
603
669
|
noAuth: false,
|
|
604
670
|
noOpen: false,
|
|
605
671
|
yes: false,
|
|
606
|
-
dryRun: false
|
|
672
|
+
dryRun: false,
|
|
607
673
|
};
|
|
608
674
|
|
|
609
675
|
for (let i = 0; i < argv.length; i++) {
|
|
610
676
|
const a = argv[i];
|
|
611
|
-
if (a ===
|
|
612
|
-
else if (a ===
|
|
613
|
-
else if (a ===
|
|
614
|
-
else if (a ===
|
|
615
|
-
else if (a ===
|
|
616
|
-
else if (a ===
|
|
617
|
-
else if (a ===
|
|
618
|
-
else if (a ===
|
|
619
|
-
else if (a ===
|
|
620
|
-
else if (a ===
|
|
677
|
+
if (a === "--base-url") out.baseUrl = argv[++i] || null;
|
|
678
|
+
else if (a === "--dashboard-url") out.dashboardUrl = argv[++i] || null;
|
|
679
|
+
else if (a === "--email") out.email = argv[++i] || null;
|
|
680
|
+
else if (a === "--password") out.password = argv[++i] || null;
|
|
681
|
+
else if (a === "--device-name") out.deviceName = argv[++i] || null;
|
|
682
|
+
else if (a === "--link-code") out.linkCode = argv[++i] || null;
|
|
683
|
+
else if (a === "--no-auth") out.noAuth = true;
|
|
684
|
+
else if (a === "--no-open") out.noOpen = true;
|
|
685
|
+
else if (a === "--yes") out.yes = true;
|
|
686
|
+
else if (a === "--dry-run") out.dryRun = true;
|
|
621
687
|
else throw new Error(`Unknown option: ${a}`);
|
|
622
688
|
}
|
|
623
689
|
return out;
|
|
@@ -629,19 +695,19 @@ function sleep(ms) {
|
|
|
629
695
|
}
|
|
630
696
|
|
|
631
697
|
function normalizePlatform(value) {
|
|
632
|
-
if (value ===
|
|
633
|
-
if (value ===
|
|
634
|
-
if (value ===
|
|
635
|
-
return
|
|
698
|
+
if (value === "darwin") return "macos";
|
|
699
|
+
if (value === "win32") return "windows";
|
|
700
|
+
if (value === "linux") return "linux";
|
|
701
|
+
return "unknown";
|
|
636
702
|
}
|
|
637
703
|
|
|
638
704
|
function buildNotifyHandler({ trackerDir, packageName }) {
|
|
639
705
|
// Keep this file dependency-free: Node built-ins only.
|
|
640
706
|
// It must never block Codex; it spawns sync in the background and exits 0.
|
|
641
|
-
const queueSignalPath = path.join(trackerDir,
|
|
642
|
-
const originalPath = path.join(trackerDir,
|
|
643
|
-
const fallbackPkg = packageName ||
|
|
644
|
-
const trackerBinPath = path.join(trackerDir,
|
|
707
|
+
const queueSignalPath = path.join(trackerDir, "notify.signal");
|
|
708
|
+
const originalPath = path.join(trackerDir, "codex_notify_original.json");
|
|
709
|
+
const fallbackPkg = packageName || "vibeusage";
|
|
710
|
+
const trackerBinPath = path.join(trackerDir, "app", "bin", "tracker.js");
|
|
645
711
|
|
|
646
712
|
return `#!/usr/bin/env node
|
|
647
713
|
'use strict';
|
|
@@ -671,7 +737,7 @@ for (let i = 0; i < rawArgs.length; i++) {
|
|
|
671
737
|
const trackerDir = ${JSON.stringify(trackerDir)};
|
|
672
738
|
const signalPath = ${JSON.stringify(queueSignalPath)};
|
|
673
739
|
const codexOriginalPath = ${JSON.stringify(originalPath)};
|
|
674
|
-
const codeOriginalPath = ${JSON.stringify(path.join(trackerDir,
|
|
740
|
+
const codeOriginalPath = ${JSON.stringify(path.join(trackerDir, "code_notify_original.json"))};
|
|
675
741
|
const trackerBinPath = ${JSON.stringify(trackerBinPath)};
|
|
676
742
|
const depsMarkerPath = path.join(trackerDir, 'app', 'node_modules', '@insforge', 'sdk', 'package.json');
|
|
677
743
|
const configPath = path.join(trackerDir, 'config.json');
|
|
@@ -791,11 +857,12 @@ async function probeFile(p) {
|
|
|
791
857
|
try {
|
|
792
858
|
const st = await fs.stat(p);
|
|
793
859
|
if (st.isFile()) return { exists: true, reason: null };
|
|
794
|
-
return { exists: false, reason:
|
|
860
|
+
return { exists: false, reason: "not-file" };
|
|
795
861
|
} catch (e) {
|
|
796
|
-
if (e?.code ===
|
|
797
|
-
if (e?.code ===
|
|
798
|
-
|
|
862
|
+
if (e?.code === "ENOENT" || e?.code === "ENOTDIR") return { exists: false, reason: "missing" };
|
|
863
|
+
if (e?.code === "EACCES" || e?.code === "EPERM")
|
|
864
|
+
return { exists: false, reason: "permission-denied" };
|
|
865
|
+
return { exists: false, reason: "error", code: e?.code || "unknown" };
|
|
799
866
|
}
|
|
800
867
|
}
|
|
801
868
|
|
|
@@ -810,10 +877,10 @@ async function isDir(p) {
|
|
|
810
877
|
|
|
811
878
|
async function installLocalTrackerApp({ appDir }) {
|
|
812
879
|
// Copy the current package's runtime (bin + src) into ~/.vibeusage so notify can run sync without npx.
|
|
813
|
-
const packageRoot = path.resolve(__dirname,
|
|
814
|
-
const srcFrom = path.join(packageRoot,
|
|
815
|
-
const binFrom = path.join(packageRoot,
|
|
816
|
-
const nodeModulesFrom = path.join(packageRoot,
|
|
880
|
+
const packageRoot = path.resolve(__dirname, "../..");
|
|
881
|
+
const srcFrom = path.join(packageRoot, "src");
|
|
882
|
+
const binFrom = path.join(packageRoot, "bin", "tracker.js");
|
|
883
|
+
const nodeModulesFrom = path.join(packageRoot, "node_modules");
|
|
817
884
|
|
|
818
885
|
// When running from the installed local runtime (or when appDir is symlinked to this package),
|
|
819
886
|
// source and destination resolve to the same place. Do not delete appDir in that case.
|
|
@@ -821,10 +888,10 @@ async function installLocalTrackerApp({ appDir }) {
|
|
|
821
888
|
return;
|
|
822
889
|
}
|
|
823
890
|
|
|
824
|
-
const srcTo = path.join(appDir,
|
|
825
|
-
const binToDir = path.join(appDir,
|
|
826
|
-
const binTo = path.join(binToDir,
|
|
827
|
-
const nodeModulesTo = path.join(appDir,
|
|
891
|
+
const srcTo = path.join(appDir, "src");
|
|
892
|
+
const binToDir = path.join(appDir, "bin");
|
|
893
|
+
const binTo = path.join(binToDir, "tracker.js");
|
|
894
|
+
const nodeModulesTo = path.join(appDir, "node_modules");
|
|
828
895
|
|
|
829
896
|
await fs.rm(appDir, { recursive: true, force: true }).catch(() => {});
|
|
830
897
|
await ensureDir(appDir);
|
|
@@ -851,22 +918,22 @@ async function safeRealpath(p) {
|
|
|
851
918
|
}
|
|
852
919
|
|
|
853
920
|
function spawnInitSync({ trackerBinPath, packageName }) {
|
|
854
|
-
const fallbackPkg = packageName ||
|
|
855
|
-
const argv = [
|
|
856
|
-
const hasLocalRuntime = typeof trackerBinPath ===
|
|
921
|
+
const fallbackPkg = packageName || "vibeusage";
|
|
922
|
+
const argv = ["sync", "--drain"];
|
|
923
|
+
const hasLocalRuntime = typeof trackerBinPath === "string" && fssync.existsSync(trackerBinPath);
|
|
857
924
|
const cmd = hasLocalRuntime
|
|
858
925
|
? [process.execPath, trackerBinPath, ...argv]
|
|
859
|
-
: [
|
|
926
|
+
: ["npx", "--yes", fallbackPkg, ...argv];
|
|
860
927
|
const child = cp.spawn(cmd[0], cmd.slice(1), {
|
|
861
928
|
detached: true,
|
|
862
|
-
stdio:
|
|
863
|
-
env: process.env
|
|
929
|
+
stdio: "ignore",
|
|
930
|
+
env: process.env,
|
|
864
931
|
});
|
|
865
|
-
child.on(
|
|
866
|
-
const msg = err && err.message ? err.message :
|
|
867
|
-
const detail = isDebugEnabled() ? ` (${msg})` :
|
|
932
|
+
child.on("error", (err) => {
|
|
933
|
+
const msg = err && err.message ? err.message : "unknown error";
|
|
934
|
+
const detail = isDebugEnabled() ? ` (${msg})` : "";
|
|
868
935
|
process.stderr.write(`Minor issue: Background sync could not start${detail}.\n`);
|
|
869
|
-
process.stderr.write(
|
|
936
|
+
process.stderr.write("Run: npx --yes vibeusage sync\n");
|
|
870
937
|
});
|
|
871
938
|
child.unref();
|
|
872
939
|
}
|
|
@@ -887,5 +954,5 @@ async function copyRuntimeDependencies({ from, to }) {
|
|
|
887
954
|
}
|
|
888
955
|
|
|
889
956
|
function isDebugEnabled() {
|
|
890
|
-
return process.env.VIBEUSAGE_DEBUG ===
|
|
957
|
+
return process.env.VIBEUSAGE_DEBUG === "1";
|
|
891
958
|
}
|