vexp-cli 2.1.0 → 2.1.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/autostart.js CHANGED
@@ -311,60 +311,6 @@ export function uninstallAutostart() {
311
311
  }
312
312
  catch { /* absent */ }
313
313
  }
314
- /**
315
- * Idempotent install guard used by `vexp` preAction / REPL / plugin activate.
316
- *
317
- * First invocation after an upgrade installs autostart + writes a marker.
318
- * Subsequent invocations (including `vexp setup`, any subcommand, multiple
319
- * VS Code windows) short-circuit on the marker → zero extra work, zero
320
- * process duplication.
321
- *
322
- * Respects `VEXP_NO_AUTOSTART_INSTALL=1` as opt-out.
323
- */
324
- export function installAutostartIfNeeded() {
325
- if (process.env.VEXP_NO_AUTOSTART_INSTALL === "1")
326
- return;
327
- // 2.0.12 shipped a broken Windows VBS template; rewrite any existing
328
- // file matching that signature regardless of marker state, so upgraded
329
- // users get fixed without manual autostart uninstall/install.
330
- if (process.platform === "win32") {
331
- try {
332
- const p = windowsStartupPath();
333
- if (fs.existsSync(p)) {
334
- const existing = fs.readFileSync(p, "utf-8");
335
- if (/sh\.Run\s+"cmd \/c "\s*&/.test(existing)) {
336
- installWindowsStartup();
337
- }
338
- }
339
- }
340
- catch { /* non-fatal */ }
341
- }
342
- const marker = installMarkerPath();
343
- if (fs.existsSync(marker))
344
- return;
345
- // Previous install by a different path (e.g. user ran older `vexp setup`
346
- // that called installAutostart directly). Record the marker so we don't
347
- // probe the filesystem again on every invocation.
348
- if (autostartStatus().installed) {
349
- try {
350
- fs.mkdirSync(path.dirname(marker), { recursive: true });
351
- fs.writeFileSync(marker, new Date().toISOString());
352
- }
353
- catch { /* non-fatal */ }
354
- return;
355
- }
356
- try {
357
- const r = installAutostart();
358
- if (r.installed) {
359
- try {
360
- fs.mkdirSync(path.dirname(marker), { recursive: true });
361
- fs.writeFileSync(marker, new Date().toISOString());
362
- }
363
- catch { /* non-fatal */ }
364
- }
365
- }
366
- catch { /* non-fatal — opt-in best effort */ }
367
- }
368
314
  const CLAUDE_UNPIN_MARKER_FILE = "claude-unpin-migrated";
369
315
  function claudeUnpinMarkerPath() {
370
316
  return path.join(homedir(), ".vexp", CLAUDE_UNPIN_MARKER_FILE);
package/dist/cli.js CHANGED
@@ -6,14 +6,14 @@ import { spawn, spawnSync, execFileSync } from "child_process";
6
6
  import * as path from "path";
7
7
  import * as fs from "fs";
8
8
  import * as net from "net";
9
- import { checkbox } from "@inquirer/prompts";
9
+ import { checkbox, confirm } from "@inquirer/prompts";
10
10
  import { getBinaryPath, getInstalledVersion, getMcpServerPath, binaryEnv } from "./binary.js";
11
11
  import { detectAgents, getAgentList, configureSelectedAgents } from "./agent-config.js";
12
12
  import { CLI_VERSION } from "./version.js";
13
13
  import { activateLicense, deactivateLicense, readLicenseLimits, readDeviceBlocked, } from "./license.js";
14
14
  import { checkForUpdate } from "./update-check.js";
15
15
  import { ensureMcpHttpServer, mcpHttpStatus } from "./mcp-supervisor.js";
16
- import { installAutostart, installAutostartIfNeeded, uninstallAutostart, autostartStatus, migrateClaudeUnpinIfNeeded } from "./autostart.js";
16
+ import { installAutostart, uninstallAutostart, autostartStatus, migrateClaudeUnpinIfNeeded } from "./autostart.js";
17
17
  import { runServe } from "./serve.js";
18
18
  import { runDoctor } from "./doctor.js";
19
19
  import { isTraceEnabled } from "./trace.js";
@@ -218,11 +218,17 @@ async function ensureDaemonRunning(workspaceRoot, binaryPath) {
218
218
  * REPL, setup) can never spawn duplicates:
219
219
  * - `ensureDaemonRunning` → socket probe, skips spawn if alive
220
220
  * - `ensureMcpHttpServer` → ~/.vexp/mcp.pid + port probe, no-op if live
221
- * - `installAutostartIfNeeded` → marker ~/.vexp/autostart-installed
222
221
  *
223
222
  * The point of this wrapper is to ensure users who upgraded via
224
223
  * `npm update` and then just typed `vexp` (never re-running `setup`) still
225
- * get: daemon up, MCP :7821 up, OS autostart installed for future reboots.
224
+ * get the daemon up and MCP :7821 up for this session. The daemon cold-starts
225
+ * lazily on the first invocation, so no OS-level login persistence is needed
226
+ * for interactive use.
227
+ *
228
+ * OS login autostart is NOT installed here — it is strictly opt-in via
229
+ * `vexp autostart install` or the setup wizard prompt, so vexp never writes
230
+ * LaunchAgent/systemd/Startup-folder persistence behind the user's back
231
+ * (which security tooling flags as a persistence anomaly).
226
232
  *
227
233
  * Honors VEXP_NO_AUTOSTART=1 as a global bypass.
228
234
  */
@@ -234,10 +240,6 @@ async function ensureBootstrap(workspaceRoot, binaryPath) {
234
240
  await ensureMcpHttpServer({ owner: "cli" });
235
241
  }
236
242
  catch { /* non-fatal */ }
237
- try {
238
- installAutostartIfNeeded();
239
- }
240
- catch { /* non-fatal */ }
241
243
  }
242
244
  /**
243
245
  * Start the vexp daemon and MCP HTTP server in the background.
@@ -625,20 +627,40 @@ program
625
627
  }
626
628
  }
627
629
  }
628
- // Step 5: Install login autostart (per-user, no admin required)
629
- if (process.env.VEXP_NO_AUTOSTART_INSTALL !== "1") {
630
- const spinnerAuto = ora("Installing login autostart...").start();
631
- try {
632
- const r = installAutostart();
633
- if (r.installed) {
634
- spinnerAuto.succeed(`Login autostart installed (${r.mechanism})`);
630
+ // Step 5: Optionally install login autostart (per-user, no admin required).
631
+ // Opt-in only — writing OS persistence (LaunchAgent / systemd / Startup
632
+ // folder) without asking is flagged as an anomaly by security tooling, and
633
+ // the daemon already cold-starts on the first `vexp` invocation, so this is
634
+ // purely a convenience for post-reboot warm-up. Skip entirely when the user
635
+ // opted out via env or when stdin is not a TTY (non-interactive install).
636
+ if (process.env.VEXP_NO_AUTOSTART_INSTALL === "1") {
637
+ // Explicit opt-out — do nothing.
638
+ }
639
+ else if (!process.stdin.isTTY) {
640
+ console.log(chalk.dim(" Skipping login autostart (non-interactive). Run 'vexp autostart install' to enable."));
641
+ }
642
+ else {
643
+ const wantAutostart = await confirm({
644
+ message: "Start the vexp daemon automatically at login? (optional — it also starts on demand)",
645
+ default: false,
646
+ });
647
+ if (wantAutostart) {
648
+ const spinnerAuto = ora("Installing login autostart...").start();
649
+ try {
650
+ const r = installAutostart();
651
+ if (r.installed) {
652
+ spinnerAuto.succeed(`Login autostart installed (${r.mechanism})`);
653
+ }
654
+ else {
655
+ spinnerAuto.warn("Autostart not installed on this platform");
656
+ }
635
657
  }
636
- else {
637
- spinnerAuto.warn("Autostart not installed on this platform");
658
+ catch (err) {
659
+ spinnerAuto.warn(`Autostart install failed: ${err instanceof Error ? err.message : err}`);
638
660
  }
639
661
  }
640
- catch (err) {
641
- spinnerAuto.warn(`Autostart install failed: ${err instanceof Error ? err.message : err}`);
662
+ else {
663
+ console.log(chalk.dim(" Login autostart skipped. Enable later with 'vexp autostart install'."));
642
664
  }
643
665
  }
644
666
  // Final summary
@@ -782,14 +804,30 @@ async function runSetupInteractive(rl) {
782
804
  }
783
805
  console.log(chalk.green(`\n ✓ Setup complete — ${result.agents.length} agent(s) configured\n`));
784
806
  }
785
- // Login autostart — opt-out via env
786
- if (process.env.VEXP_NO_AUTOSTART_INSTALL !== "1") {
787
- try {
788
- const r = installAutostart();
789
- if (r.installed)
790
- console.log(chalk.green(` ✓ Login autostart installed (${r.mechanism})`));
807
+ // Login autostart — opt-in only. The daemon already cold-starts on demand,
808
+ // so OS login persistence is a convenience the user must explicitly request;
809
+ // installing it silently is flagged as a persistence anomaly by security
810
+ // tooling. Env opt-out and non-TTY both skip the prompt without installing.
811
+ if (process.env.VEXP_NO_AUTOSTART_INSTALL === "1" || !process.stdin.isTTY) {
812
+ // Opted out or non-interactive — leave autostart uninstalled.
813
+ }
814
+ else {
815
+ rl.resume();
816
+ const answer = (await ask(rl, "\n Start the vexp daemon automatically at login? (optional — starts on demand too) [y/N]: ")).trim().toLowerCase();
817
+ rl.pause();
818
+ if (answer === "y" || answer === "yes") {
819
+ try {
820
+ const r = installAutostart();
821
+ if (r.installed)
822
+ console.log(chalk.green(` ✓ Login autostart installed (${r.mechanism})`));
823
+ else
824
+ console.log(chalk.yellow(" ⚠ Autostart not installed on this platform"));
825
+ }
826
+ catch { /* non-fatal */ }
827
+ }
828
+ else {
829
+ console.log(chalk.dim(" Login autostart skipped. Enable later with 'vexp autostart install'."));
791
830
  }
792
- catch { /* non-fatal */ }
793
831
  }
794
832
  }
795
833
  // ────────────────────────────────────────────────────
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vexp-cli",
3
- "version": "2.1.0",
3
+ "version": "2.1.1",
4
4
  "description": "Vexp — Context Engine for AI Coding Agents. Pre-indexes your codebase into a dependency graph and delivers ranked context to any MCP-compatible agent. 58% lower cost per task, 90% fewer tool calls (SWE-bench Verified). Works with Claude Code, Cursor, Copilot, Windsurf, Codex, Cline, Aider, and 12+ agents. Local-first. Your code never leaves your machine.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -100,10 +100,10 @@
100
100
  "node": ">=20.0.0"
101
101
  },
102
102
  "optionalDependencies": {
103
- "@vexp/core-linux-x64": "2.1.0",
104
- "@vexp/core-linux-arm64": "2.1.0",
105
- "@vexp/core-darwin-x64": "2.1.0",
106
- "@vexp/core-darwin-arm64": "2.1.0",
107
- "@vexp/core-win32-x64": "2.1.0"
103
+ "@vexp/core-linux-x64": "2.1.1",
104
+ "@vexp/core-linux-arm64": "2.1.1",
105
+ "@vexp/core-darwin-x64": "2.1.1",
106
+ "@vexp/core-darwin-arm64": "2.1.1",
107
+ "@vexp/core-win32-x64": "2.1.1"
108
108
  }
109
109
  }