@rehpic/vcli 0.1.0-beta.34.1 → 0.1.0-beta.35.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 CHANGED
@@ -1,6 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  var __defProp = Object.defineProperty;
3
3
  var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
5
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
6
+ }) : x)(function(x) {
7
+ if (typeof require !== "undefined") return require.apply(this, arguments);
8
+ throw Error('Dynamic require of "' + x + '" is not supported');
9
+ });
4
10
  var __esm = (fn, res) => function __init() {
5
11
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
6
12
  };
@@ -436,16 +442,16 @@ function detectArchBinary(binary) {
436
442
  }
437
443
  return archBinary;
438
444
  }
439
- function detectPlatformBinary({ [platform]: platformBinary }, { wsl } = {}) {
445
+ function detectPlatformBinary({ [platform2]: platformBinary }, { wsl } = {}) {
440
446
  if (wsl && is_wsl_default) {
441
447
  return detectArchBinary(wsl);
442
448
  }
443
449
  if (!platformBinary) {
444
- throw new Error(`${platform} is not supported`);
450
+ throw new Error(`${platform2} is not supported`);
445
451
  }
446
452
  return detectArchBinary(platformBinary);
447
453
  }
448
- var fallbackAttemptSymbol, __dirname, localXdgOpenPath, platform, arch, tryEachApp, baseOpen, open, openApp, apps, open_default;
454
+ var fallbackAttemptSymbol, __dirname2, localXdgOpenPath, platform2, arch, tryEachApp, baseOpen, open, openApp, apps, open_default;
449
455
  var init_open = __esm({
450
456
  "../../node_modules/.pnpm/open@11.0.0/node_modules/open/index.js"() {
451
457
  "use strict";
@@ -456,9 +462,9 @@ var init_open = __esm({
456
462
  init_is_inside_container();
457
463
  init_is_in_ssh();
458
464
  fallbackAttemptSymbol = Symbol("fallbackAttempt");
459
- __dirname = import.meta.url ? path2.dirname(fileURLToPath(import.meta.url)) : "";
460
- localXdgOpenPath = path2.join(__dirname, "xdg-open");
461
- ({ platform, arch } = process8);
465
+ __dirname2 = import.meta.url ? path2.dirname(fileURLToPath(import.meta.url)) : "";
466
+ localXdgOpenPath = path2.join(__dirname2, "xdg-open");
467
+ ({ platform: platform2, arch } = process8);
462
468
  tryEachApp = async (apps2, opener) => {
463
469
  if (apps2.length === 0) {
464
470
  return;
@@ -555,7 +561,7 @@ var init_open = __esm({
555
561
  if (is_wsl_default && !isInsideContainer() && !is_in_ssh_default && !app) {
556
562
  shouldUseWindowsInWsl = await canAccessPowerShell();
557
563
  }
558
- if (platform === "darwin") {
564
+ if (platform2 === "darwin") {
559
565
  command = "open";
560
566
  if (options.wait) {
561
567
  cliArguments.push("--wait-apps");
@@ -569,7 +575,7 @@ var init_open = __esm({
569
575
  if (app) {
570
576
  cliArguments.push("-a", app);
571
577
  }
572
- } else if (platform === "win32" || shouldUseWindowsInWsl) {
578
+ } else if (platform2 === "win32" || shouldUseWindowsInWsl) {
573
579
  command = await powerShellPath2();
574
580
  cliArguments.push(...executePowerShell.argumentsPrefix);
575
581
  if (!is_wsl_default) {
@@ -602,14 +608,14 @@ var init_open = __esm({
602
608
  if (app) {
603
609
  command = app;
604
610
  } else {
605
- const isBundled = !__dirname || __dirname === "/";
611
+ const isBundled = !__dirname2 || __dirname2 === "/";
606
612
  let exeLocalXdgOpen = false;
607
613
  try {
608
614
  await fs6.access(localXdgOpenPath, fsConstants3.X_OK);
609
615
  exeLocalXdgOpen = true;
610
616
  } catch {
611
617
  }
612
- const useSystemXdgOpen = process8.versions.electron ?? (platform === "android" || isBundled || !exeLocalXdgOpen);
618
+ const useSystemXdgOpen = process8.versions.electron ?? (platform2 === "android" || isBundled || !exeLocalXdgOpen);
613
619
  command = useSystemXdgOpen ? "xdg-open" : localXdgOpenPath;
614
620
  }
615
621
  if (appArguments.length > 0) {
@@ -620,7 +626,7 @@ var init_open = __esm({
620
626
  childProcessOptions.detached = true;
621
627
  }
622
628
  }
623
- if (platform === "darwin" && appArguments.length > 0) {
629
+ if (platform2 === "darwin" && appArguments.length > 0) {
624
630
  cliArguments.push("--args", ...appArguments);
625
631
  }
626
632
  if (options.target) {
@@ -736,9 +742,9 @@ var init_open = __esm({
736
742
  });
737
743
 
738
744
  // ../../src/cli/index.ts
739
- import { readFileSync } from "fs";
745
+ import { readFileSync as readFileSync2 } from "fs";
740
746
  import { readFile as readFile2 } from "fs/promises";
741
- import { dirname, extname, join } from "path";
747
+ import { dirname, extname, join as join2 } from "path";
742
748
  import { fileURLToPath as fileURLToPath2 } from "url";
743
749
  import { config as loadEnv } from "dotenv";
744
750
  import { Command } from "commander";
@@ -1094,7 +1100,413 @@ function createEmptySession() {
1094
1100
  };
1095
1101
  }
1096
1102
 
1103
+ // ../../src/cli/bridge-service.ts
1104
+ import { ConvexHttpClient as ConvexHttpClient2 } from "convex/browser";
1105
+ import { execSync } from "child_process";
1106
+ import {
1107
+ existsSync,
1108
+ mkdirSync,
1109
+ readFileSync,
1110
+ writeFileSync,
1111
+ unlinkSync
1112
+ } from "fs";
1113
+ import { homedir as homedir2, hostname, platform } from "os";
1114
+ import { join } from "path";
1115
+ import { randomUUID } from "crypto";
1116
+ var CONFIG_DIR = join(homedir2(), ".vector");
1117
+ var BRIDGE_CONFIG_FILE = join(CONFIG_DIR, "bridge.json");
1118
+ var PID_FILE = join(CONFIG_DIR, "bridge.pid");
1119
+ var LIVE_ACTIVITIES_CACHE = join(CONFIG_DIR, "live-activities.json");
1120
+ var LAUNCHAGENT_DIR = join(homedir2(), "Library", "LaunchAgents");
1121
+ var LAUNCHAGENT_PLIST = join(LAUNCHAGENT_DIR, "com.vector.bridge.plist");
1122
+ var LAUNCHAGENT_LABEL = "com.vector.bridge";
1123
+ var HEARTBEAT_INTERVAL_MS = 3e4;
1124
+ var COMMAND_POLL_INTERVAL_MS = 5e3;
1125
+ var PROCESS_DISCOVERY_INTERVAL_MS = 6e4;
1126
+ function loadBridgeConfig() {
1127
+ if (!existsSync(BRIDGE_CONFIG_FILE)) return null;
1128
+ try {
1129
+ return JSON.parse(readFileSync(BRIDGE_CONFIG_FILE, "utf-8"));
1130
+ } catch {
1131
+ return null;
1132
+ }
1133
+ }
1134
+ function saveBridgeConfig(config) {
1135
+ if (!existsSync(CONFIG_DIR)) mkdirSync(CONFIG_DIR, { recursive: true });
1136
+ writeFileSync(BRIDGE_CONFIG_FILE, JSON.stringify(config, null, 2));
1137
+ }
1138
+ function discoverLocalProcesses() {
1139
+ const processes = [];
1140
+ const patterns = [
1141
+ {
1142
+ grep: "[c]laude",
1143
+ provider: "claude_code",
1144
+ label: "Claude",
1145
+ prefix: "claude"
1146
+ },
1147
+ { grep: "[c]odex", provider: "codex", label: "Codex", prefix: "codex" }
1148
+ ];
1149
+ for (const { grep, provider, label, prefix } of patterns) {
1150
+ try {
1151
+ const ps = execSync(
1152
+ `ps aux | grep -E '${grep}' | grep -v vector-bridge | grep -v grep`,
1153
+ { encoding: "utf-8", timeout: 5e3 }
1154
+ );
1155
+ for (const line of ps.trim().split("\n").filter(Boolean)) {
1156
+ const pid = line.split(/\s+/)[1];
1157
+ if (!pid) continue;
1158
+ let cwd;
1159
+ try {
1160
+ cwd = execSync(
1161
+ `lsof -p ${pid} 2>/dev/null | grep cwd | awk '{print $NF}'`,
1162
+ { encoding: "utf-8", timeout: 3e3 }
1163
+ ).trim() || void 0;
1164
+ } catch {
1165
+ }
1166
+ const gitInfo = cwd ? getGitInfo(cwd) : {};
1167
+ processes.push({
1168
+ provider,
1169
+ providerLabel: label,
1170
+ localProcessId: pid,
1171
+ sessionKey: `${prefix}-${pid}`,
1172
+ cwd,
1173
+ ...gitInfo,
1174
+ mode: "observed",
1175
+ status: "observed",
1176
+ supportsInboundMessages: false
1177
+ });
1178
+ }
1179
+ } catch {
1180
+ }
1181
+ }
1182
+ return processes;
1183
+ }
1184
+ function getGitInfo(cwd) {
1185
+ try {
1186
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
1187
+ encoding: "utf-8",
1188
+ cwd,
1189
+ timeout: 3e3
1190
+ }).trim();
1191
+ const repoRoot = execSync("git rev-parse --show-toplevel", {
1192
+ encoding: "utf-8",
1193
+ cwd,
1194
+ timeout: 3e3
1195
+ }).trim();
1196
+ return { branch, repoRoot };
1197
+ } catch {
1198
+ return {};
1199
+ }
1200
+ }
1201
+ function generateReply(userMessage) {
1202
+ const lower = userMessage.toLowerCase().trim();
1203
+ if (["hey", "hi", "hello"].includes(lower)) {
1204
+ return "Hey! I'm running on your local machine via the Vector bridge. What would you like me to work on?";
1205
+ }
1206
+ if (lower.includes("status") || lower.includes("progress")) {
1207
+ return "I'm making good progress. Currently reviewing the changes and running tests.";
1208
+ }
1209
+ if (lower.includes("stop") || lower.includes("cancel")) {
1210
+ return "Understood \u2014 wrapping up the current step.";
1211
+ }
1212
+ return `Got it \u2014 "${userMessage}". I'll incorporate that into my current work.`;
1213
+ }
1214
+ var BridgeService = class {
1215
+ constructor(config) {
1216
+ this.timers = [];
1217
+ this.config = config;
1218
+ this.client = new ConvexHttpClient2(config.convexUrl);
1219
+ }
1220
+ async heartbeat() {
1221
+ await this.client.mutation(api.agentBridge.bridgePublic.heartbeat, {
1222
+ deviceId: this.config.deviceId,
1223
+ deviceSecret: this.config.deviceSecret
1224
+ });
1225
+ }
1226
+ async pollCommands() {
1227
+ const commands = await this.client.query(
1228
+ api.agentBridge.bridgePublic.getPendingCommands,
1229
+ {
1230
+ deviceId: this.config.deviceId,
1231
+ deviceSecret: this.config.deviceSecret
1232
+ }
1233
+ );
1234
+ if (commands.length > 0) {
1235
+ console.log(`[${ts()}] ${commands.length} pending command(s)`);
1236
+ }
1237
+ for (const cmd of commands) {
1238
+ await this.handleCommand(cmd);
1239
+ }
1240
+ }
1241
+ async handleCommand(cmd) {
1242
+ console.log(` ${cmd.kind}: ${cmd._id}`);
1243
+ if (cmd.kind === "message" && cmd.liveActivityId) {
1244
+ const payload = cmd.payload;
1245
+ const body = payload?.body ?? "";
1246
+ console.log(` > "${body}"`);
1247
+ const reply = generateReply(body);
1248
+ await this.client.mutation(
1249
+ api.agentBridge.bridgePublic.postAgentMessage,
1250
+ {
1251
+ deviceId: this.config.deviceId,
1252
+ deviceSecret: this.config.deviceSecret,
1253
+ liveActivityId: cmd.liveActivityId,
1254
+ role: "assistant",
1255
+ body: reply
1256
+ }
1257
+ );
1258
+ console.log(` < "${reply.slice(0, 60)}..."`);
1259
+ }
1260
+ await this.client.mutation(api.agentBridge.bridgePublic.completeCommand, {
1261
+ deviceId: this.config.deviceId,
1262
+ deviceSecret: this.config.deviceSecret,
1263
+ commandId: cmd._id,
1264
+ status: "delivered"
1265
+ });
1266
+ }
1267
+ async reportProcesses() {
1268
+ const processes = discoverLocalProcesses();
1269
+ for (const proc of processes) {
1270
+ try {
1271
+ await this.client.mutation(api.agentBridge.bridgePublic.reportProcess, {
1272
+ deviceId: this.config.deviceId,
1273
+ deviceSecret: this.config.deviceSecret,
1274
+ ...proc
1275
+ });
1276
+ } catch {
1277
+ }
1278
+ }
1279
+ if (processes.length > 0) {
1280
+ console.log(`[${ts()}] Discovered ${processes.length} local process(es)`);
1281
+ }
1282
+ }
1283
+ async refreshLiveActivities() {
1284
+ try {
1285
+ const activities = await this.client.query(
1286
+ api.agentBridge.bridgePublic.getDeviceLiveActivities,
1287
+ {
1288
+ deviceId: this.config.deviceId,
1289
+ deviceSecret: this.config.deviceSecret
1290
+ }
1291
+ );
1292
+ writeFileSync(LIVE_ACTIVITIES_CACHE, JSON.stringify(activities, null, 2));
1293
+ } catch {
1294
+ }
1295
+ }
1296
+ async run() {
1297
+ console.log("Vector Bridge Service");
1298
+ console.log(
1299
+ ` Device: ${this.config.displayName} (${this.config.deviceId})`
1300
+ );
1301
+ console.log(` Convex: ${this.config.convexUrl}`);
1302
+ console.log(` PID: ${process.pid}`);
1303
+ console.log("");
1304
+ if (!existsSync(CONFIG_DIR)) mkdirSync(CONFIG_DIR, { recursive: true });
1305
+ writeFileSync(PID_FILE, String(process.pid));
1306
+ await this.heartbeat();
1307
+ await this.reportProcesses();
1308
+ await this.refreshLiveActivities();
1309
+ console.log(`[${ts()}] Service running. Ctrl+C to stop.
1310
+ `);
1311
+ this.timers.push(
1312
+ setInterval(() => {
1313
+ this.heartbeat().catch(
1314
+ (e) => console.error(`[${ts()}] Heartbeat error:`, e.message)
1315
+ );
1316
+ this.refreshLiveActivities().catch(() => {
1317
+ });
1318
+ }, HEARTBEAT_INTERVAL_MS)
1319
+ );
1320
+ this.timers.push(
1321
+ setInterval(() => {
1322
+ this.pollCommands().catch(
1323
+ (e) => console.error(`[${ts()}] Command poll error:`, e.message)
1324
+ );
1325
+ }, COMMAND_POLL_INTERVAL_MS)
1326
+ );
1327
+ this.timers.push(
1328
+ setInterval(() => {
1329
+ this.reportProcesses().catch(
1330
+ (e) => console.error(`[${ts()}] Discovery error:`, e.message)
1331
+ );
1332
+ }, PROCESS_DISCOVERY_INTERVAL_MS)
1333
+ );
1334
+ const shutdown = () => {
1335
+ console.log(`
1336
+ [${ts()}] Shutting down...`);
1337
+ for (const t of this.timers) clearInterval(t);
1338
+ try {
1339
+ unlinkSync(PID_FILE);
1340
+ } catch {
1341
+ }
1342
+ process.exit(0);
1343
+ };
1344
+ process.on("SIGINT", shutdown);
1345
+ process.on("SIGTERM", shutdown);
1346
+ await new Promise(() => {
1347
+ });
1348
+ }
1349
+ };
1350
+ async function setupBridgeDevice(convexUrl, userId) {
1351
+ const client = new ConvexHttpClient2(convexUrl);
1352
+ const deviceKey = `${hostname()}-${randomUUID().slice(0, 8)}`;
1353
+ const deviceSecret = randomUUID();
1354
+ const displayName = `${process.env.USER ?? "user"}'s ${platform() === "darwin" ? "Mac" : "machine"}`;
1355
+ const result = await client.mutation(
1356
+ api.agentBridge.bridgePublic.setupDevice,
1357
+ {
1358
+ userId,
1359
+ deviceKey,
1360
+ deviceSecret,
1361
+ displayName,
1362
+ hostname: hostname(),
1363
+ platform: platform(),
1364
+ cliVersion: "0.1.0",
1365
+ capabilities: ["codex", "claude_code"]
1366
+ }
1367
+ );
1368
+ const config = {
1369
+ deviceId: result.deviceId,
1370
+ deviceKey,
1371
+ deviceSecret,
1372
+ userId,
1373
+ displayName,
1374
+ convexUrl,
1375
+ registeredAt: (/* @__PURE__ */ new Date()).toISOString()
1376
+ };
1377
+ saveBridgeConfig(config);
1378
+ return config;
1379
+ }
1380
+ function installLaunchAgent(vcliPath) {
1381
+ if (platform() !== "darwin") {
1382
+ console.error("LaunchAgent is macOS only. Use systemd on Linux.");
1383
+ return;
1384
+ }
1385
+ const plist = `<?xml version="1.0" encoding="UTF-8"?>
1386
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
1387
+ <plist version="1.0">
1388
+ <dict>
1389
+ <key>Label</key>
1390
+ <string>${LAUNCHAGENT_LABEL}</string>
1391
+ <key>ProgramArguments</key>
1392
+ <array>
1393
+ <string>${vcliPath}</string>
1394
+ <string>service</string>
1395
+ <string>start</string>
1396
+ </array>
1397
+ <key>RunAtLoad</key>
1398
+ <true/>
1399
+ <key>KeepAlive</key>
1400
+ <true/>
1401
+ <key>StandardOutPath</key>
1402
+ <string>${CONFIG_DIR}/bridge.log</string>
1403
+ <key>StandardErrorPath</key>
1404
+ <string>${CONFIG_DIR}/bridge.err.log</string>
1405
+ <key>EnvironmentVariables</key>
1406
+ <dict>
1407
+ <key>PATH</key>
1408
+ <string>/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin</string>
1409
+ </dict>
1410
+ </dict>
1411
+ </plist>`;
1412
+ const menuBarBinary = join(
1413
+ __dirname,
1414
+ "..",
1415
+ "..",
1416
+ "cli",
1417
+ "macos",
1418
+ "VectorMenuBar"
1419
+ );
1420
+ if (existsSync(menuBarBinary)) {
1421
+ const menuBarPlist = `<?xml version="1.0" encoding="UTF-8"?>
1422
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
1423
+ <plist version="1.0">
1424
+ <dict>
1425
+ <key>Label</key>
1426
+ <string>com.vector.menubar</string>
1427
+ <key>ProgramArguments</key>
1428
+ <array>
1429
+ <string>${menuBarBinary}</string>
1430
+ </array>
1431
+ <key>RunAtLoad</key>
1432
+ <true/>
1433
+ <key>KeepAlive</key>
1434
+ <false/>
1435
+ </dict>
1436
+ </plist>`;
1437
+ const menuBarPlistPath = join(LAUNCHAGENT_DIR, "com.vector.menubar.plist");
1438
+ writeFileSync(menuBarPlistPath, menuBarPlist);
1439
+ try {
1440
+ execSync(`launchctl load ${menuBarPlistPath}`, { stdio: "pipe" });
1441
+ console.log("Menu bar helper installed.");
1442
+ } catch {
1443
+ }
1444
+ }
1445
+ if (!existsSync(LAUNCHAGENT_DIR)) {
1446
+ mkdirSync(LAUNCHAGENT_DIR, { recursive: true });
1447
+ }
1448
+ writeFileSync(LAUNCHAGENT_PLIST, plist);
1449
+ console.log(`Installed LaunchAgent: ${LAUNCHAGENT_PLIST}`);
1450
+ }
1451
+ function loadLaunchAgent() {
1452
+ try {
1453
+ execSync(`launchctl load ${LAUNCHAGENT_PLIST}`, { stdio: "inherit" });
1454
+ console.log(
1455
+ "LaunchAgent loaded. Bridge will start automatically on login."
1456
+ );
1457
+ } catch {
1458
+ console.error("Failed to load LaunchAgent");
1459
+ }
1460
+ }
1461
+ function unloadLaunchAgent() {
1462
+ try {
1463
+ execSync(`launchctl unload ${LAUNCHAGENT_PLIST}`, { stdio: "inherit" });
1464
+ console.log("LaunchAgent unloaded.");
1465
+ } catch {
1466
+ console.error("Failed to unload LaunchAgent (may not be loaded)");
1467
+ }
1468
+ }
1469
+ function uninstallLaunchAgent() {
1470
+ unloadLaunchAgent();
1471
+ try {
1472
+ unlinkSync(LAUNCHAGENT_PLIST);
1473
+ console.log("LaunchAgent removed.");
1474
+ } catch {
1475
+ }
1476
+ }
1477
+ function getBridgeStatus() {
1478
+ const config = loadBridgeConfig();
1479
+ if (!config) return { configured: false, running: false };
1480
+ let running = false;
1481
+ let pid;
1482
+ if (existsSync(PID_FILE)) {
1483
+ const pidStr = readFileSync(PID_FILE, "utf-8").trim();
1484
+ pid = Number(pidStr);
1485
+ try {
1486
+ process.kill(pid, 0);
1487
+ running = true;
1488
+ } catch {
1489
+ running = false;
1490
+ }
1491
+ }
1492
+ return { configured: true, running, pid, config };
1493
+ }
1494
+ function stopBridge() {
1495
+ if (!existsSync(PID_FILE)) return false;
1496
+ const pid = Number(readFileSync(PID_FILE, "utf-8").trim());
1497
+ try {
1498
+ process.kill(pid, "SIGTERM");
1499
+ return true;
1500
+ } catch {
1501
+ return false;
1502
+ }
1503
+ }
1504
+ function ts() {
1505
+ return (/* @__PURE__ */ new Date()).toLocaleTimeString();
1506
+ }
1507
+
1097
1508
  // ../../src/cli/index.ts
1509
+ import { platform as osPlatform } from "os";
1098
1510
  loadEnv({ path: ".env.local", override: false });
1099
1511
  loadEnv({ path: ".env", override: false });
1100
1512
  var cliApi = {
@@ -1537,7 +1949,7 @@ var program = new Command();
1537
1949
  function readPackageVersionSync() {
1538
1950
  try {
1539
1951
  const dir = import.meta.dirname ?? dirname(fileURLToPath2(import.meta.url));
1540
- const raw = readFileSync(join(dir, "..", "package.json"), "utf8");
1952
+ const raw = readFileSync2(join2(dir, "..", "package.json"), "utf8");
1541
1953
  return JSON.parse(raw).version ?? "unknown";
1542
1954
  } catch {
1543
1955
  return "unknown";
@@ -1999,6 +2411,75 @@ permissionCommand.command("check-many <permissions>").option("--team <teamKey>")
1999
2411
  printOutput(result, runtime.json);
2000
2412
  });
2001
2413
  var activityCommand = program.command("activity").description("Activity feed");
2414
+ activityCommand.command("list").description(
2415
+ "List org-wide activity with optional filters by entity type, event type, and time range"
2416
+ ).option(
2417
+ "--entity-type <type>",
2418
+ "Filter by entity type: issue, project, team, document"
2419
+ ).option(
2420
+ "--event-type <type>",
2421
+ "Filter by event type (e.g. issue_created, issue_priority_changed)"
2422
+ ).option(
2423
+ "--since <datetime>",
2424
+ "Start of time range (ISO date or shorthand: today, yesterday, 7d, 30d)"
2425
+ ).option(
2426
+ "--until <datetime>",
2427
+ "End of time range (ISO date or shorthand: today, now)"
2428
+ ).option("--limit <n>").option("--cursor <cursor>").action(async (options, command) => {
2429
+ const { client, runtime } = await getClient(command);
2430
+ const orgSlug = requireOrg(runtime);
2431
+ function parseTimeArg(value, bound) {
2432
+ if (!value) return void 0;
2433
+ const now = /* @__PURE__ */ new Date();
2434
+ const startOfToday = new Date(
2435
+ now.getFullYear(),
2436
+ now.getMonth(),
2437
+ now.getDate()
2438
+ );
2439
+ const endOfToday = new Date(
2440
+ now.getFullYear(),
2441
+ now.getMonth(),
2442
+ now.getDate(),
2443
+ 23,
2444
+ 59,
2445
+ 59,
2446
+ 999
2447
+ );
2448
+ switch (value) {
2449
+ case "now":
2450
+ return now.getTime();
2451
+ case "today":
2452
+ return bound === "start" ? startOfToday.getTime() : endOfToday.getTime();
2453
+ case "yesterday":
2454
+ return bound === "start" ? startOfToday.getTime() - 864e5 : startOfToday.getTime() - 1;
2455
+ default: {
2456
+ const daysMatch = value.match(/^(\d+)d$/);
2457
+ if (daysMatch) {
2458
+ return now.getTime() - Number(daysMatch[1]) * 864e5;
2459
+ }
2460
+ const parsed = new Date(value).getTime();
2461
+ if (Number.isNaN(parsed)) {
2462
+ throw new Error(`Invalid time value: ${value}`);
2463
+ }
2464
+ return parsed;
2465
+ }
2466
+ }
2467
+ }
2468
+ const result = await runQuery(
2469
+ client,
2470
+ api.activities.queries.listOrgActivity,
2471
+ {
2472
+ orgSlug,
2473
+ entityType: options.entityType ?? void 0,
2474
+ eventType: options.eventType ?? void 0,
2475
+ since: parseTimeArg(options.since, "start"),
2476
+ until: parseTimeArg(options.until, "end"),
2477
+ limit: optionalNumber(options.limit, "limit") ?? void 0,
2478
+ cursor: options.cursor ?? void 0
2479
+ }
2480
+ );
2481
+ printOutput(result, runtime.json);
2482
+ });
2002
2483
  activityCommand.command("project <projectKey>").option("--limit <n>").option("--cursor <cursor>").action(async (projectKey, options, command) => {
2003
2484
  const { client, runtime } = await getClient(command);
2004
2485
  const orgSlug = requireOrg(runtime);
@@ -2664,13 +3145,14 @@ projectCommand.command("set-lead <projectKey> <member>").action(async (projectKe
2664
3145
  printOutput(result, runtime.json);
2665
3146
  });
2666
3147
  var issueCommand = program.command("issue").description("Issues");
2667
- issueCommand.command("list [slug]").option("--project <projectKey>").option("--team <teamKey>").option("--limit <n>").option("--created-after <date>", "Filter: created on or after date (ISO)").option("--created-before <date>", "Filter: created on or before date (ISO)").option("--sort <field>", "Sort by field (e.g. createdAt, title, key)").option("--order <direction>", "Sort order: asc or desc (default: asc)").action(async (slug, options, command) => {
3148
+ issueCommand.command("list [slug]").option("--project <projectKey>").option("--team <teamKey>").option("--assignee <name>", "Filter by assignee name or email").option("--limit <n>").option("--created-after <date>", "Filter: created on or after date (ISO)").option("--created-before <date>", "Filter: created on or before date (ISO)").option("--sort <field>", "Sort by field (e.g. createdAt, title, key)").option("--order <direction>", "Sort order: asc or desc (default: asc)").action(async (slug, options, command) => {
2668
3149
  const { client, runtime } = await getClient(command);
2669
3150
  const orgSlug = requireOrg(runtime, slug);
2670
3151
  const raw = await runAction(client, cliApi.listIssues, {
2671
3152
  orgSlug,
2672
3153
  projectKey: options.project,
2673
- teamKey: options.team
3154
+ teamKey: options.team,
3155
+ assigneeName: options.assignee
2674
3156
  });
2675
3157
  const filtered = applyListFilters(raw, options);
2676
3158
  const result = addEntityUrls(filtered, runtime.appUrl, orgSlug, "issues");
@@ -3014,6 +3496,129 @@ folderCommand.command("delete <folderId>").action(async (folderId, _options, com
3014
3496
  });
3015
3497
  printOutput(result, runtime.json);
3016
3498
  });
3499
+ var serviceCommand = program.command("service").description("Manage the local bridge service");
3500
+ serviceCommand.command("start").description("Run the bridge service in the foreground").action(async (_options, command) => {
3501
+ let config = loadBridgeConfig();
3502
+ if (!config) {
3503
+ const runtime = await getRuntime(command);
3504
+ const session = requireSession(runtime);
3505
+ const client = await createConvexClient(
3506
+ session,
3507
+ runtime.appUrl,
3508
+ runtime.convexUrl
3509
+ );
3510
+ const user = await runQuery(client, api.users.currentUser);
3511
+ if (!user) throw new Error("Not logged in. Run `vcli auth login` first.");
3512
+ config = await setupBridgeDevice(runtime.convexUrl, user._id);
3513
+ console.log(`Device registered: ${config.deviceId}`);
3514
+ }
3515
+ const bridge = new BridgeService(config);
3516
+ await bridge.run();
3517
+ });
3518
+ serviceCommand.command("stop").description("Stop the running bridge service").action(() => {
3519
+ if (stopBridge()) {
3520
+ console.log("Bridge stopped.");
3521
+ } else {
3522
+ console.log("Bridge is not running.");
3523
+ }
3524
+ });
3525
+ serviceCommand.command("status").description("Show bridge service status").action((_options, command) => {
3526
+ const status = getBridgeStatus();
3527
+ if (!status.configured) {
3528
+ console.log("Bridge not configured. Run: vcli service start");
3529
+ return;
3530
+ }
3531
+ console.log("Vector Bridge");
3532
+ console.log(
3533
+ ` Device: ${status.config.displayName} (${status.config.deviceId})`
3534
+ );
3535
+ console.log(` User: ${status.config.userId}`);
3536
+ console.log(
3537
+ ` Status: ${status.running ? `Running (PID ${status.pid})` : "Not running"}`
3538
+ );
3539
+ console.log(` Config: ~/.vector/bridge.json`);
3540
+ });
3541
+ serviceCommand.command("install").description("Install the bridge as a system service (macOS LaunchAgent)").action(async (_options, command) => {
3542
+ if (osPlatform() !== "darwin") {
3543
+ console.error("Service install is currently macOS only (LaunchAgent).");
3544
+ console.error("On Linux, use systemd --user manually for now.");
3545
+ return;
3546
+ }
3547
+ const vcliPath = process.argv[1] ?? "vcli";
3548
+ installLaunchAgent(vcliPath);
3549
+ loadLaunchAgent();
3550
+ });
3551
+ serviceCommand.command("uninstall").description("Uninstall the bridge system service").action(() => {
3552
+ uninstallLaunchAgent();
3553
+ });
3554
+ serviceCommand.command("logs").description("Show bridge service logs").action(() => {
3555
+ const { existsSync: exists, readFileSync: read } = __require("fs");
3556
+ const logPath = __require("path").join(
3557
+ __require("os").homedir(),
3558
+ ".vector",
3559
+ "bridge.log"
3560
+ );
3561
+ if (exists(logPath)) {
3562
+ const content = read(logPath, "utf-8");
3563
+ const lines = content.split("\n");
3564
+ console.log(lines.slice(-50).join("\n"));
3565
+ } else {
3566
+ console.log("No log file found at ~/.vector/bridge.log");
3567
+ }
3568
+ });
3569
+ var bridgeCommand = program.command("bridge").description("Start/stop the local agent bridge");
3570
+ bridgeCommand.command("start").description("Register device, install service, and start the bridge").action(async (_options, command) => {
3571
+ let config = loadBridgeConfig();
3572
+ if (!config) {
3573
+ const runtime = await getRuntime(command);
3574
+ const session = requireSession(runtime);
3575
+ const client = await createConvexClient(
3576
+ session,
3577
+ runtime.appUrl,
3578
+ runtime.convexUrl
3579
+ );
3580
+ const user = await runQuery(client, api.users.currentUser);
3581
+ if (!user) throw new Error("Not logged in. Run `vcli auth login` first.");
3582
+ config = await setupBridgeDevice(runtime.convexUrl, user._id);
3583
+ console.log(
3584
+ `Device registered: ${config.displayName} (${config.deviceId})`
3585
+ );
3586
+ }
3587
+ if (osPlatform() === "darwin") {
3588
+ const vcliPath = process.argv[1] ?? "vcli";
3589
+ installLaunchAgent(vcliPath);
3590
+ loadLaunchAgent();
3591
+ console.log("\nBridge installed and started as LaunchAgent.");
3592
+ console.log("It will restart automatically on login.");
3593
+ console.log("Run `vcli service status` to check.");
3594
+ } else {
3595
+ console.log("Starting bridge in foreground...");
3596
+ const bridge = new BridgeService(config);
3597
+ await bridge.run();
3598
+ }
3599
+ });
3600
+ bridgeCommand.command("stop").description("Stop the bridge service").action(() => {
3601
+ if (osPlatform() === "darwin") {
3602
+ uninstallLaunchAgent();
3603
+ }
3604
+ if (stopBridge()) {
3605
+ console.log("Bridge stopped.");
3606
+ } else {
3607
+ console.log("Bridge is not running.");
3608
+ }
3609
+ });
3610
+ bridgeCommand.command("status").description("Show bridge status").action(() => {
3611
+ const s = getBridgeStatus();
3612
+ if (!s.configured) {
3613
+ console.log("Bridge not configured. Run: vcli bridge start");
3614
+ return;
3615
+ }
3616
+ console.log("Vector Bridge");
3617
+ console.log(` Device: ${s.config.displayName} (${s.config.deviceId})`);
3618
+ console.log(
3619
+ ` Status: ${s.running ? `Running (PID ${s.pid})` : "Not running"}`
3620
+ );
3621
+ });
3017
3622
  async function main() {
3018
3623
  await program.parseAsync(process.argv);
3019
3624
  }