@rehpic/vcli 0.1.0-beta.42.1 → 0.1.0-beta.45.1
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/dist/index.js +299 -118
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -9,6 +9,237 @@ var __export = (target, all) => {
|
|
|
9
9
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
+
// src/menubar.ts
|
|
13
|
+
var menubar_exports = {};
|
|
14
|
+
__export(menubar_exports, {
|
|
15
|
+
startMenuBar: () => startMenuBar
|
|
16
|
+
});
|
|
17
|
+
import SysTray from "systray2";
|
|
18
|
+
import { existsSync, readFileSync } from "fs";
|
|
19
|
+
import { homedir as homedir2 } from "os";
|
|
20
|
+
import { join } from "path";
|
|
21
|
+
import { execSync } from "child_process";
|
|
22
|
+
function loadIconBase64() {
|
|
23
|
+
const iconPath = join(CONFIG_DIR, "assets", "vector-menubar.png");
|
|
24
|
+
if (existsSync(iconPath)) {
|
|
25
|
+
return readFileSync(iconPath).toString("base64");
|
|
26
|
+
}
|
|
27
|
+
return "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==";
|
|
28
|
+
}
|
|
29
|
+
function loadConfig() {
|
|
30
|
+
try {
|
|
31
|
+
return JSON.parse(readFileSync(BRIDGE_CONFIG_FILE, "utf-8"));
|
|
32
|
+
} catch {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function loadActivities() {
|
|
37
|
+
try {
|
|
38
|
+
return JSON.parse(readFileSync(LIVE_ACTIVITIES_FILE, "utf-8"));
|
|
39
|
+
} catch {
|
|
40
|
+
return [];
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function isBridgeRunning() {
|
|
44
|
+
try {
|
|
45
|
+
const pid = Number(readFileSync(PID_FILE, "utf-8").trim());
|
|
46
|
+
process.kill(pid, 0);
|
|
47
|
+
return { running: true, pid };
|
|
48
|
+
} catch {
|
|
49
|
+
return { running: false };
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function getSessionInfo() {
|
|
53
|
+
try {
|
|
54
|
+
const session = JSON.parse(
|
|
55
|
+
readFileSync(join(CONFIG_DIR, "cli-default.json"), "utf-8")
|
|
56
|
+
);
|
|
57
|
+
return {
|
|
58
|
+
orgSlug: session.activeOrgSlug ?? "oss-lab",
|
|
59
|
+
appUrl: session.appUrl
|
|
60
|
+
};
|
|
61
|
+
} catch {
|
|
62
|
+
return { orgSlug: "oss-lab" };
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function getOrgSlug() {
|
|
66
|
+
try {
|
|
67
|
+
const session = JSON.parse(
|
|
68
|
+
readFileSync(join(CONFIG_DIR, "cli-default.json"), "utf-8")
|
|
69
|
+
);
|
|
70
|
+
return session.activeOrgSlug ?? "oss-lab";
|
|
71
|
+
} catch {
|
|
72
|
+
return "oss-lab";
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function providerLabel(provider) {
|
|
76
|
+
if (provider === "claude_code") return "Claude";
|
|
77
|
+
if (provider === "codex") return "Codex";
|
|
78
|
+
return provider;
|
|
79
|
+
}
|
|
80
|
+
function buildMenu() {
|
|
81
|
+
const config = loadConfig();
|
|
82
|
+
const { running, pid } = isBridgeRunning();
|
|
83
|
+
const activities = loadActivities();
|
|
84
|
+
const items = [];
|
|
85
|
+
const actions = /* @__PURE__ */ new Map();
|
|
86
|
+
let idx = 0;
|
|
87
|
+
if (running && config) {
|
|
88
|
+
items.push({
|
|
89
|
+
title: `Vector Bridge \u2014 Running (PID ${pid})`,
|
|
90
|
+
enabled: false
|
|
91
|
+
});
|
|
92
|
+
idx++;
|
|
93
|
+
items.push({ title: ` ${config.displayName}`, enabled: false });
|
|
94
|
+
idx++;
|
|
95
|
+
} else if (config) {
|
|
96
|
+
items.push({ title: "Vector Bridge \u2014 Offline", enabled: false });
|
|
97
|
+
idx++;
|
|
98
|
+
} else {
|
|
99
|
+
items.push({ title: "Vector Bridge \u2014 Not Configured", enabled: false });
|
|
100
|
+
idx++;
|
|
101
|
+
items.push({
|
|
102
|
+
title: " Run: vcli service start",
|
|
103
|
+
enabled: false
|
|
104
|
+
});
|
|
105
|
+
idx++;
|
|
106
|
+
}
|
|
107
|
+
items.push({ title: "---", enabled: false });
|
|
108
|
+
idx++;
|
|
109
|
+
if (activities.length > 0) {
|
|
110
|
+
items.push({ title: "Active Sessions", enabled: false });
|
|
111
|
+
idx++;
|
|
112
|
+
const orgSlug = getOrgSlug();
|
|
113
|
+
for (const a of activities) {
|
|
114
|
+
const label = `${a.issueKey} \u2014 ${a.title ?? a.issueTitle} (${providerLabel(a.provider)})`;
|
|
115
|
+
items.push({ title: label, tooltip: a.latestSummary });
|
|
116
|
+
const issueKey = a.issueKey;
|
|
117
|
+
actions.set(idx, () => {
|
|
118
|
+
const url = `http://localhost:3000/${orgSlug}/issues/${issueKey}`;
|
|
119
|
+
try {
|
|
120
|
+
execSync(`open "${url}"`, { stdio: "ignore" });
|
|
121
|
+
} catch {
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
idx++;
|
|
125
|
+
}
|
|
126
|
+
items.push({ title: "---", enabled: false });
|
|
127
|
+
idx++;
|
|
128
|
+
}
|
|
129
|
+
if (running) {
|
|
130
|
+
items.push({ title: "Stop Bridge" });
|
|
131
|
+
actions.set(idx, () => {
|
|
132
|
+
try {
|
|
133
|
+
if (pid) process.kill(pid, "SIGTERM");
|
|
134
|
+
} catch {
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
idx++;
|
|
138
|
+
items.push({ title: "Restart Bridge" });
|
|
139
|
+
actions.set(idx, () => {
|
|
140
|
+
try {
|
|
141
|
+
if (pid) process.kill(pid, "SIGTERM");
|
|
142
|
+
setTimeout(() => {
|
|
143
|
+
execSync("vcli service start", { stdio: "ignore" });
|
|
144
|
+
}, 2e3);
|
|
145
|
+
} catch {
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
idx++;
|
|
149
|
+
} else if (config) {
|
|
150
|
+
items.push({ title: "Start Bridge" });
|
|
151
|
+
actions.set(idx, () => {
|
|
152
|
+
try {
|
|
153
|
+
execSync("vcli service start", { stdio: "ignore" });
|
|
154
|
+
} catch {
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
idx++;
|
|
158
|
+
}
|
|
159
|
+
items.push({ title: "---", enabled: false });
|
|
160
|
+
idx++;
|
|
161
|
+
if (config) {
|
|
162
|
+
const { orgSlug, appUrl } = getSessionInfo();
|
|
163
|
+
items.push({
|
|
164
|
+
title: `Account: ${config.userId.slice(0, 12)}...`,
|
|
165
|
+
enabled: false
|
|
166
|
+
});
|
|
167
|
+
idx++;
|
|
168
|
+
if (orgSlug) {
|
|
169
|
+
items.push({ title: `Org: ${orgSlug}`, enabled: false });
|
|
170
|
+
idx++;
|
|
171
|
+
}
|
|
172
|
+
items.push({ title: "---", enabled: false });
|
|
173
|
+
idx++;
|
|
174
|
+
}
|
|
175
|
+
items.push({ title: "Open Vector" });
|
|
176
|
+
actions.set(idx, () => {
|
|
177
|
+
const { appUrl } = getSessionInfo();
|
|
178
|
+
const url = appUrl ?? "http://localhost:3000";
|
|
179
|
+
try {
|
|
180
|
+
execSync(`open "${url}"`, { stdio: "ignore" });
|
|
181
|
+
} catch {
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
idx++;
|
|
185
|
+
items.push({ title: "Quit Vector" });
|
|
186
|
+
actions.set(idx, () => {
|
|
187
|
+
try {
|
|
188
|
+
const { pid: bridgePid } = isBridgeRunning();
|
|
189
|
+
if (bridgePid) process.kill(bridgePid, "SIGTERM");
|
|
190
|
+
} catch {
|
|
191
|
+
}
|
|
192
|
+
process.exit(0);
|
|
193
|
+
});
|
|
194
|
+
idx++;
|
|
195
|
+
return { items, actions };
|
|
196
|
+
}
|
|
197
|
+
async function startMenuBar() {
|
|
198
|
+
const icon = loadIconBase64();
|
|
199
|
+
const { items, actions } = buildMenu();
|
|
200
|
+
const systray = new SysTray({
|
|
201
|
+
menu: {
|
|
202
|
+
icon,
|
|
203
|
+
title: "",
|
|
204
|
+
tooltip: "Vector Bridge",
|
|
205
|
+
items: items.map((item) => ({
|
|
206
|
+
title: item.title,
|
|
207
|
+
tooltip: item.tooltip ?? "",
|
|
208
|
+
checked: item.checked ?? false,
|
|
209
|
+
enabled: item.enabled ?? true,
|
|
210
|
+
hidden: false
|
|
211
|
+
}))
|
|
212
|
+
},
|
|
213
|
+
debug: false,
|
|
214
|
+
copyDir: false
|
|
215
|
+
});
|
|
216
|
+
void systray.onClick((action) => {
|
|
217
|
+
const handler = actions.get(action.seq_id);
|
|
218
|
+
if (handler) handler();
|
|
219
|
+
});
|
|
220
|
+
setInterval(() => {
|
|
221
|
+
const { items: newItems, actions: newActions } = buildMenu();
|
|
222
|
+
void newItems;
|
|
223
|
+
void newActions;
|
|
224
|
+
}, 15e3);
|
|
225
|
+
}
|
|
226
|
+
var CONFIG_DIR, BRIDGE_CONFIG_FILE, PID_FILE, LIVE_ACTIVITIES_FILE;
|
|
227
|
+
var init_menubar = __esm({
|
|
228
|
+
"src/menubar.ts"() {
|
|
229
|
+
"use strict";
|
|
230
|
+
CONFIG_DIR = join(homedir2(), ".vector");
|
|
231
|
+
BRIDGE_CONFIG_FILE = join(CONFIG_DIR, "bridge.json");
|
|
232
|
+
PID_FILE = join(CONFIG_DIR, "bridge.pid");
|
|
233
|
+
LIVE_ACTIVITIES_FILE = join(CONFIG_DIR, "live-activities.json");
|
|
234
|
+
if (process.argv[1]?.endsWith("menubar.ts") || process.argv[1]?.endsWith("menubar.js")) {
|
|
235
|
+
startMenuBar().catch((e) => {
|
|
236
|
+
console.error("Menu bar error:", e);
|
|
237
|
+
process.exit(1);
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
|
|
12
243
|
// ../../node_modules/.pnpm/is-docker@3.0.0/node_modules/is-docker/index.js
|
|
13
244
|
import fs from "fs";
|
|
14
245
|
function hasDockerEnv() {
|
|
@@ -735,10 +966,10 @@ var init_open = __esm({
|
|
|
735
966
|
}
|
|
736
967
|
});
|
|
737
968
|
|
|
738
|
-
//
|
|
739
|
-
import { readFileSync as
|
|
969
|
+
// src/index.ts
|
|
970
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
740
971
|
import { readFile as readFile2 } from "fs/promises";
|
|
741
|
-
import { dirname, extname, join as
|
|
972
|
+
import { dirname, extname, join as join3 } from "path";
|
|
742
973
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
743
974
|
import { config as loadEnv } from "dotenv";
|
|
744
975
|
import { Command } from "commander";
|
|
@@ -749,7 +980,7 @@ import { anyApi, componentsGeneric } from "convex/server";
|
|
|
749
980
|
var api = anyApi;
|
|
750
981
|
var components = componentsGeneric();
|
|
751
982
|
|
|
752
|
-
//
|
|
983
|
+
// src/auth.ts
|
|
753
984
|
import { isCancel, password as passwordPrompt, text } from "@clack/prompts";
|
|
754
985
|
function buildUrl(appUrl, pathname) {
|
|
755
986
|
return new URL(pathname, appUrl).toString();
|
|
@@ -989,7 +1220,7 @@ async function promptSecret(question) {
|
|
|
989
1220
|
return String(value);
|
|
990
1221
|
}
|
|
991
1222
|
|
|
992
|
-
//
|
|
1223
|
+
// src/convex.ts
|
|
993
1224
|
import { ConvexHttpClient } from "convex/browser";
|
|
994
1225
|
async function createConvexClient(session, appUrl, convexUrl) {
|
|
995
1226
|
const { token } = await fetchConvexToken(session, appUrl);
|
|
@@ -1007,7 +1238,7 @@ async function runAction(client, ref, ...args) {
|
|
|
1007
1238
|
return await client.action(ref, ...args);
|
|
1008
1239
|
}
|
|
1009
1240
|
|
|
1010
|
-
//
|
|
1241
|
+
// src/output.ts
|
|
1011
1242
|
function simplify(value) {
|
|
1012
1243
|
if (value === null || value === void 0) {
|
|
1013
1244
|
return value;
|
|
@@ -1054,7 +1285,7 @@ function printOutput(data, json = false) {
|
|
|
1054
1285
|
console.log(String(data));
|
|
1055
1286
|
}
|
|
1056
1287
|
|
|
1057
|
-
//
|
|
1288
|
+
// src/session.ts
|
|
1058
1289
|
import { mkdir, readFile, rm, writeFile } from "fs/promises";
|
|
1059
1290
|
import { homedir } from "os";
|
|
1060
1291
|
import path from "path";
|
|
@@ -1094,40 +1325,40 @@ function createEmptySession() {
|
|
|
1094
1325
|
};
|
|
1095
1326
|
}
|
|
1096
1327
|
|
|
1097
|
-
//
|
|
1328
|
+
// src/bridge-service.ts
|
|
1098
1329
|
import { ConvexHttpClient as ConvexHttpClient2 } from "convex/browser";
|
|
1099
|
-
import { execSync } from "child_process";
|
|
1330
|
+
import { execSync as execSync2 } from "child_process";
|
|
1100
1331
|
import {
|
|
1101
|
-
existsSync,
|
|
1332
|
+
existsSync as existsSync2,
|
|
1102
1333
|
mkdirSync,
|
|
1103
|
-
readFileSync,
|
|
1334
|
+
readFileSync as readFileSync2,
|
|
1104
1335
|
writeFileSync,
|
|
1105
1336
|
unlinkSync
|
|
1106
1337
|
} from "fs";
|
|
1107
|
-
import { homedir as
|
|
1108
|
-
import { join } from "path";
|
|
1338
|
+
import { homedir as homedir3, hostname, platform } from "os";
|
|
1339
|
+
import { join as join2 } from "path";
|
|
1109
1340
|
import { randomUUID } from "crypto";
|
|
1110
|
-
var
|
|
1111
|
-
var
|
|
1112
|
-
var
|
|
1113
|
-
var LIVE_ACTIVITIES_CACHE =
|
|
1114
|
-
var LAUNCHAGENT_DIR =
|
|
1115
|
-
var LAUNCHAGENT_PLIST =
|
|
1341
|
+
var CONFIG_DIR2 = join2(homedir3(), ".vector");
|
|
1342
|
+
var BRIDGE_CONFIG_FILE2 = join2(CONFIG_DIR2, "bridge.json");
|
|
1343
|
+
var PID_FILE2 = join2(CONFIG_DIR2, "bridge.pid");
|
|
1344
|
+
var LIVE_ACTIVITIES_CACHE = join2(CONFIG_DIR2, "live-activities.json");
|
|
1345
|
+
var LAUNCHAGENT_DIR = join2(homedir3(), "Library", "LaunchAgents");
|
|
1346
|
+
var LAUNCHAGENT_PLIST = join2(LAUNCHAGENT_DIR, "com.vector.bridge.plist");
|
|
1116
1347
|
var LAUNCHAGENT_LABEL = "com.vector.bridge";
|
|
1117
1348
|
var HEARTBEAT_INTERVAL_MS = 3e4;
|
|
1118
1349
|
var COMMAND_POLL_INTERVAL_MS = 5e3;
|
|
1119
1350
|
var PROCESS_DISCOVERY_INTERVAL_MS = 6e4;
|
|
1120
1351
|
function loadBridgeConfig() {
|
|
1121
|
-
if (!
|
|
1352
|
+
if (!existsSync2(BRIDGE_CONFIG_FILE2)) return null;
|
|
1122
1353
|
try {
|
|
1123
|
-
return JSON.parse(
|
|
1354
|
+
return JSON.parse(readFileSync2(BRIDGE_CONFIG_FILE2, "utf-8"));
|
|
1124
1355
|
} catch {
|
|
1125
1356
|
return null;
|
|
1126
1357
|
}
|
|
1127
1358
|
}
|
|
1128
1359
|
function saveBridgeConfig(config) {
|
|
1129
|
-
if (!
|
|
1130
|
-
writeFileSync(
|
|
1360
|
+
if (!existsSync2(CONFIG_DIR2)) mkdirSync(CONFIG_DIR2, { recursive: true });
|
|
1361
|
+
writeFileSync(BRIDGE_CONFIG_FILE2, JSON.stringify(config, null, 2));
|
|
1131
1362
|
}
|
|
1132
1363
|
function discoverLocalProcesses() {
|
|
1133
1364
|
const processes = [];
|
|
@@ -1142,7 +1373,7 @@ function discoverLocalProcesses() {
|
|
|
1142
1373
|
];
|
|
1143
1374
|
for (const { grep, provider, label, prefix } of patterns) {
|
|
1144
1375
|
try {
|
|
1145
|
-
const ps =
|
|
1376
|
+
const ps = execSync2(
|
|
1146
1377
|
`ps aux | grep -E '${grep}' | grep -v vector-bridge | grep -v grep`,
|
|
1147
1378
|
{ encoding: "utf-8", timeout: 5e3 }
|
|
1148
1379
|
);
|
|
@@ -1151,7 +1382,7 @@ function discoverLocalProcesses() {
|
|
|
1151
1382
|
if (!pid) continue;
|
|
1152
1383
|
let cwd;
|
|
1153
1384
|
try {
|
|
1154
|
-
cwd =
|
|
1385
|
+
cwd = execSync2(
|
|
1155
1386
|
`lsof -p ${pid} 2>/dev/null | grep cwd | awk '{print $NF}'`,
|
|
1156
1387
|
{ encoding: "utf-8", timeout: 3e3 }
|
|
1157
1388
|
).trim() || void 0;
|
|
@@ -1177,12 +1408,12 @@ function discoverLocalProcesses() {
|
|
|
1177
1408
|
}
|
|
1178
1409
|
function getGitInfo(cwd) {
|
|
1179
1410
|
try {
|
|
1180
|
-
const branch =
|
|
1411
|
+
const branch = execSync2("git rev-parse --abbrev-ref HEAD", {
|
|
1181
1412
|
encoding: "utf-8",
|
|
1182
1413
|
cwd,
|
|
1183
1414
|
timeout: 3e3
|
|
1184
1415
|
}).trim();
|
|
1185
|
-
const repoRoot =
|
|
1416
|
+
const repoRoot = execSync2("git rev-parse --show-toplevel", {
|
|
1186
1417
|
encoding: "utf-8",
|
|
1187
1418
|
cwd,
|
|
1188
1419
|
timeout: 3e3
|
|
@@ -1295,8 +1526,8 @@ var BridgeService = class {
|
|
|
1295
1526
|
console.log(` Convex: ${this.config.convexUrl}`);
|
|
1296
1527
|
console.log(` PID: ${process.pid}`);
|
|
1297
1528
|
console.log("");
|
|
1298
|
-
if (!
|
|
1299
|
-
writeFileSync(
|
|
1529
|
+
if (!existsSync2(CONFIG_DIR2)) mkdirSync(CONFIG_DIR2, { recursive: true });
|
|
1530
|
+
writeFileSync(PID_FILE2, String(process.pid));
|
|
1300
1531
|
await this.heartbeat();
|
|
1301
1532
|
await this.reportProcesses();
|
|
1302
1533
|
await this.refreshLiveActivities();
|
|
@@ -1330,7 +1561,7 @@ var BridgeService = class {
|
|
|
1330
1561
|
[${ts()}] Shutting down...`);
|
|
1331
1562
|
for (const t of this.timers) clearInterval(t);
|
|
1332
1563
|
try {
|
|
1333
|
-
unlinkSync(
|
|
1564
|
+
unlinkSync(PID_FILE2);
|
|
1334
1565
|
} catch {
|
|
1335
1566
|
}
|
|
1336
1567
|
process.exit(0);
|
|
@@ -1393,9 +1624,9 @@ function installLaunchAgent(vcliPath) {
|
|
|
1393
1624
|
<key>KeepAlive</key>
|
|
1394
1625
|
<true/>
|
|
1395
1626
|
<key>StandardOutPath</key>
|
|
1396
|
-
<string>${
|
|
1627
|
+
<string>${CONFIG_DIR2}/bridge.log</string>
|
|
1397
1628
|
<key>StandardErrorPath</key>
|
|
1398
|
-
<string>${
|
|
1629
|
+
<string>${CONFIG_DIR2}/bridge.err.log</string>
|
|
1399
1630
|
<key>EnvironmentVariables</key>
|
|
1400
1631
|
<dict>
|
|
1401
1632
|
<key>PATH</key>
|
|
@@ -1404,11 +1635,11 @@ function installLaunchAgent(vcliPath) {
|
|
|
1404
1635
|
</dict>
|
|
1405
1636
|
</plist>`;
|
|
1406
1637
|
const menuBarCandidates = [
|
|
1407
|
-
|
|
1638
|
+
join2(CONFIG_DIR2, "VectorMenuBar"),
|
|
1408
1639
|
"/usr/local/bin/VectorMenuBar",
|
|
1409
|
-
|
|
1640
|
+
join2(homedir3(), ".local", "bin", "VectorMenuBar")
|
|
1410
1641
|
];
|
|
1411
|
-
const menuBarBinary = menuBarCandidates.find((p) =>
|
|
1642
|
+
const menuBarBinary = menuBarCandidates.find((p) => existsSync2(p));
|
|
1412
1643
|
if (menuBarBinary) {
|
|
1413
1644
|
const menuBarPlist = `<?xml version="1.0" encoding="UTF-8"?>
|
|
1414
1645
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
@@ -1426,15 +1657,15 @@ function installLaunchAgent(vcliPath) {
|
|
|
1426
1657
|
<false/>
|
|
1427
1658
|
</dict>
|
|
1428
1659
|
</plist>`;
|
|
1429
|
-
const menuBarPlistPath =
|
|
1660
|
+
const menuBarPlistPath = join2(LAUNCHAGENT_DIR, "com.vector.menubar.plist");
|
|
1430
1661
|
writeFileSync(menuBarPlistPath, menuBarPlist);
|
|
1431
1662
|
try {
|
|
1432
|
-
|
|
1663
|
+
execSync2(`launchctl load ${menuBarPlistPath}`, { stdio: "pipe" });
|
|
1433
1664
|
console.log("Menu bar helper installed.");
|
|
1434
1665
|
} catch {
|
|
1435
1666
|
}
|
|
1436
1667
|
}
|
|
1437
|
-
if (!
|
|
1668
|
+
if (!existsSync2(LAUNCHAGENT_DIR)) {
|
|
1438
1669
|
mkdirSync(LAUNCHAGENT_DIR, { recursive: true });
|
|
1439
1670
|
}
|
|
1440
1671
|
writeFileSync(LAUNCHAGENT_PLIST, plist);
|
|
@@ -1442,7 +1673,7 @@ function installLaunchAgent(vcliPath) {
|
|
|
1442
1673
|
}
|
|
1443
1674
|
function loadLaunchAgent() {
|
|
1444
1675
|
try {
|
|
1445
|
-
|
|
1676
|
+
execSync2(`launchctl load ${LAUNCHAGENT_PLIST}`, { stdio: "inherit" });
|
|
1446
1677
|
console.log(
|
|
1447
1678
|
"LaunchAgent loaded. Bridge will start automatically on login."
|
|
1448
1679
|
);
|
|
@@ -1452,7 +1683,7 @@ function loadLaunchAgent() {
|
|
|
1452
1683
|
}
|
|
1453
1684
|
function unloadLaunchAgent() {
|
|
1454
1685
|
try {
|
|
1455
|
-
|
|
1686
|
+
execSync2(`launchctl unload ${LAUNCHAGENT_PLIST}`, { stdio: "inherit" });
|
|
1456
1687
|
console.log("LaunchAgent unloaded.");
|
|
1457
1688
|
} catch {
|
|
1458
1689
|
console.error("Failed to unload LaunchAgent (may not be loaded)");
|
|
@@ -1466,75 +1697,22 @@ function uninstallLaunchAgent() {
|
|
|
1466
1697
|
} catch {
|
|
1467
1698
|
}
|
|
1468
1699
|
}
|
|
1469
|
-
async function compileMenuBar() {
|
|
1470
|
-
if (platform() !== "darwin") return null;
|
|
1471
|
-
const binaryPath = join(CONFIG_DIR, "VectorMenuBar");
|
|
1472
|
-
if (existsSync(binaryPath)) return binaryPath;
|
|
1473
|
-
const sourceCandidates = [
|
|
1474
|
-
join(CONFIG_DIR, "VectorMenuBar.swift"),
|
|
1475
|
-
// In the repo checkout (dev mode)
|
|
1476
|
-
join(process.cwd(), "cli", "macos", "VectorMenuBar.swift")
|
|
1477
|
-
];
|
|
1478
|
-
const source = sourceCandidates.find((p) => existsSync(p));
|
|
1479
|
-
if (!source) return null;
|
|
1480
|
-
try {
|
|
1481
|
-
execSync("which swiftc", { stdio: "pipe" });
|
|
1482
|
-
} catch {
|
|
1483
|
-
return null;
|
|
1484
|
-
}
|
|
1485
|
-
try {
|
|
1486
|
-
console.log("Compiling menu bar app...");
|
|
1487
|
-
execSync(`swiftc -o "${binaryPath}" "${source}" -framework AppKit`, {
|
|
1488
|
-
stdio: "pipe",
|
|
1489
|
-
timeout: 3e4
|
|
1490
|
-
});
|
|
1491
|
-
const sourceDir = join(source, "..", "assets");
|
|
1492
|
-
const destDir = join(CONFIG_DIR, "assets");
|
|
1493
|
-
if (existsSync(sourceDir)) {
|
|
1494
|
-
mkdirSync(destDir, { recursive: true });
|
|
1495
|
-
for (const f of ["vector-menubar.png", "vector-menubar@2x.png"]) {
|
|
1496
|
-
const src = join(sourceDir, f);
|
|
1497
|
-
if (existsSync(src)) {
|
|
1498
|
-
writeFileSync(join(destDir, f), readFileSync(src));
|
|
1499
|
-
}
|
|
1500
|
-
}
|
|
1501
|
-
}
|
|
1502
|
-
console.log("Menu bar app compiled.");
|
|
1503
|
-
return binaryPath;
|
|
1504
|
-
} catch {
|
|
1505
|
-
console.error(
|
|
1506
|
-
"Failed to compile menu bar app (Xcode CLI tools may be needed)."
|
|
1507
|
-
);
|
|
1508
|
-
return null;
|
|
1509
|
-
}
|
|
1510
|
-
}
|
|
1511
1700
|
async function launchMenuBar() {
|
|
1512
|
-
if (platform() !== "darwin") return;
|
|
1513
|
-
const candidates = [
|
|
1514
|
-
join(CONFIG_DIR, "VectorMenuBar"),
|
|
1515
|
-
"/usr/local/bin/VectorMenuBar",
|
|
1516
|
-
join(homedir2(), ".local", "bin", "VectorMenuBar")
|
|
1517
|
-
];
|
|
1518
|
-
let binary = candidates.find((p) => existsSync(p));
|
|
1519
|
-
if (!binary) {
|
|
1520
|
-
binary = await compileMenuBar() ?? void 0;
|
|
1521
|
-
}
|
|
1522
|
-
if (!binary) return;
|
|
1523
1701
|
try {
|
|
1524
|
-
const {
|
|
1525
|
-
|
|
1526
|
-
child.unref();
|
|
1702
|
+
const { startMenuBar: startMenuBar2 } = await Promise.resolve().then(() => (init_menubar(), menubar_exports));
|
|
1703
|
+
void startMenuBar2();
|
|
1527
1704
|
console.log("Menu bar started.");
|
|
1528
1705
|
} catch {
|
|
1529
1706
|
}
|
|
1530
1707
|
}
|
|
1531
1708
|
function getBridgeStatus() {
|
|
1532
1709
|
const config = loadBridgeConfig();
|
|
1533
|
-
if (!config) return { configured: false, running: false };
|
|
1710
|
+
if (!config) return { configured: false, running: false, starting: false };
|
|
1534
1711
|
let running = false;
|
|
1712
|
+
let starting = false;
|
|
1535
1713
|
let pid;
|
|
1536
|
-
if (
|
|
1537
|
-
const pidStr =
|
|
1714
|
+
if (existsSync2(PID_FILE2)) {
|
|
1715
|
+
const pidStr = readFileSync2(PID_FILE2, "utf-8").trim();
|
|
1538
1716
|
pid = Number(pidStr);
|
|
1539
1717
|
try {
|
|
1540
1718
|
process.kill(pid, 0);
|
|
@@ -1543,11 +1721,23 @@ function getBridgeStatus() {
|
|
|
1543
1721
|
running = false;
|
|
1544
1722
|
}
|
|
1545
1723
|
}
|
|
1546
|
-
|
|
1724
|
+
if (!running && platform() === "darwin") {
|
|
1725
|
+
try {
|
|
1726
|
+
const result = execSync2(
|
|
1727
|
+
`launchctl list ${LAUNCHAGENT_LABEL} 2>/dev/null`,
|
|
1728
|
+
{ encoding: "utf-8", timeout: 3e3 }
|
|
1729
|
+
);
|
|
1730
|
+
if (result.includes(LAUNCHAGENT_LABEL)) {
|
|
1731
|
+
starting = true;
|
|
1732
|
+
}
|
|
1733
|
+
} catch {
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1736
|
+
return { configured: true, running, starting, pid, config };
|
|
1547
1737
|
}
|
|
1548
1738
|
function stopBridge() {
|
|
1549
|
-
if (!
|
|
1550
|
-
const pid = Number(
|
|
1739
|
+
if (!existsSync2(PID_FILE2)) return false;
|
|
1740
|
+
const pid = Number(readFileSync2(PID_FILE2, "utf-8").trim());
|
|
1551
1741
|
try {
|
|
1552
1742
|
process.kill(pid, "SIGTERM");
|
|
1553
1743
|
return true;
|
|
@@ -1559,7 +1749,7 @@ function ts() {
|
|
|
1559
1749
|
return (/* @__PURE__ */ new Date()).toLocaleTimeString();
|
|
1560
1750
|
}
|
|
1561
1751
|
|
|
1562
|
-
//
|
|
1752
|
+
// src/index.ts
|
|
1563
1753
|
import { platform as osPlatform } from "os";
|
|
1564
1754
|
loadEnv({ path: ".env.local", override: false });
|
|
1565
1755
|
loadEnv({ path: ".env", override: false });
|
|
@@ -2003,7 +2193,7 @@ var program = new Command();
|
|
|
2003
2193
|
function readPackageVersionSync() {
|
|
2004
2194
|
try {
|
|
2005
2195
|
const dir = import.meta.dirname ?? dirname(fileURLToPath2(import.meta.url));
|
|
2006
|
-
const raw =
|
|
2196
|
+
const raw = readFileSync3(join3(dir, "..", "package.json"), "utf8");
|
|
2007
2197
|
return JSON.parse(raw).version ?? "unknown";
|
|
2008
2198
|
} catch {
|
|
2009
2199
|
return "unknown";
|
|
@@ -3579,9 +3769,6 @@ serviceCommand.command("start").description("Start the bridge service via Launch
|
|
|
3579
3769
|
loadLaunchAgent();
|
|
3580
3770
|
await launchMenuBar();
|
|
3581
3771
|
console.log("Bridge service started.");
|
|
3582
|
-
console.log("");
|
|
3583
|
-
console.log("Run `vcli service status` to check.");
|
|
3584
|
-
console.log("Run `vcli service stop` to stop.");
|
|
3585
3772
|
} else {
|
|
3586
3773
|
console.log(
|
|
3587
3774
|
"Starting bridge in foreground (use systemd for background)..."
|
|
@@ -3628,9 +3815,8 @@ serviceCommand.command("status").description("Show bridge service status").actio
|
|
|
3628
3815
|
` Device: ${status.config.displayName} (${status.config.deviceId})`
|
|
3629
3816
|
);
|
|
3630
3817
|
console.log(` User: ${status.config.userId}`);
|
|
3631
|
-
|
|
3632
|
-
|
|
3633
|
-
);
|
|
3818
|
+
const statusLabel = status.running ? `Running (PID ${status.pid})` : status.starting ? "Starting..." : "Not running";
|
|
3819
|
+
console.log(` Status: ${statusLabel}`);
|
|
3634
3820
|
console.log(` Config: ~/.vector/bridge.json`);
|
|
3635
3821
|
});
|
|
3636
3822
|
serviceCommand.command("install").description("Install the bridge as a system service (macOS LaunchAgent)").action(async (_options, command) => {
|
|
@@ -3658,14 +3844,9 @@ serviceCommand.command("install").description("Install the bridge as a system se
|
|
|
3658
3844
|
const vcliPath = process.argv[1] ?? "vcli";
|
|
3659
3845
|
installLaunchAgent(vcliPath);
|
|
3660
3846
|
loadLaunchAgent();
|
|
3661
|
-
console.log(
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
console.log("To start the service manually:");
|
|
3665
|
-
console.log(" vcli service start");
|
|
3666
|
-
console.log("");
|
|
3667
|
-
console.log("To check status:");
|
|
3668
|
-
console.log(" vcli service status");
|
|
3847
|
+
console.log(
|
|
3848
|
+
"Bridge installed and running. Will start automatically on login."
|
|
3849
|
+
);
|
|
3669
3850
|
});
|
|
3670
3851
|
serviceCommand.command("uninstall").description("Uninstall the bridge system service").action(() => {
|
|
3671
3852
|
uninstallLaunchAgent();
|