@vibecontrols/agent 2026.601.30

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.
Files changed (108) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +558 -0
  3. package/dist/agent-config-85pskv43.js +2 -0
  4. package/dist/agent-ready-tracker-zp6p8e6f.js +2 -0
  5. package/dist/app-yvjadjmh.js +2 -0
  6. package/dist/bootstrap-workspace-zpm20zez.js +2 -0
  7. package/dist/bootstrap.service-pjmnpxha.js +2 -0
  8. package/dist/bridge-client-341r9rry.js +2 -0
  9. package/dist/cli.js +5 -0
  10. package/dist/daemon-profile-vas1vf2t.js +2 -0
  11. package/dist/esm-9fpye77x.js +2 -0
  12. package/dist/finalize-retry-handle-registry-vv241fsq.js +2 -0
  13. package/dist/finalize-retry-worker-xp1nhv3c.js +2 -0
  14. package/dist/gateway-client-43gzvj5s.js +2 -0
  15. package/dist/getMachineId-bsd-a56s0v8c.js +2 -0
  16. package/dist/getMachineId-darwin-w9k0yw9r.js +3 -0
  17. package/dist/getMachineId-linux-anh31jbf.js +2 -0
  18. package/dist/getMachineId-unsupported-5hv3pwca.js +2 -0
  19. package/dist/getMachineId-win-njb8tery.js +2 -0
  20. package/dist/highlights-8d9mgr01.js +2 -0
  21. package/dist/highlights-eq9cgrbb.scm +604 -0
  22. package/dist/highlights-ghv9g403.scm +205 -0
  23. package/dist/highlights-hk7bwhj4.scm +284 -0
  24. package/dist/highlights-jwvdxm9x.js +2 -0
  25. package/dist/highlights-qbx2vnme.js +2 -0
  26. package/dist/highlights-r3m83kn9.js +2 -0
  27. package/dist/highlights-r812a2qc.scm +150 -0
  28. package/dist/highlights-s7mqapt6.js +2 -0
  29. package/dist/highlights-x6tmsnaa.scm +115 -0
  30. package/dist/index-01qzsnwd.js +16 -0
  31. package/dist/index-0248afsn.js +3 -0
  32. package/dist/index-04n4qgvd.js +407 -0
  33. package/dist/index-0ckffygp.js +5 -0
  34. package/dist/index-0cn9bv8z.js +4 -0
  35. package/dist/index-1hnw0rhc.js +178 -0
  36. package/dist/index-1zw3kea7.js +10 -0
  37. package/dist/index-2gsarrbn.js +4 -0
  38. package/dist/index-2xs9cvjn.js +28 -0
  39. package/dist/index-3ys16efc.js +231 -0
  40. package/dist/index-4wgjx8bf.js +3 -0
  41. package/dist/index-52cp759f.js +3 -0
  42. package/dist/index-5mw3eshk.js +4 -0
  43. package/dist/index-678rwfc0.js +5 -0
  44. package/dist/index-6jq17k9s.js +7 -0
  45. package/dist/index-6jzsthh9.js +3 -0
  46. package/dist/index-6mprnf7p.js +9 -0
  47. package/dist/index-8kvc8ttn.js +15 -0
  48. package/dist/index-8sm0nkh8.js +3 -0
  49. package/dist/index-9bqd8veb.js +21 -0
  50. package/dist/index-b5dhmybd.js +4 -0
  51. package/dist/index-c58g96mb.js +26 -0
  52. package/dist/index-cs78wq6y.js +3 -0
  53. package/dist/index-d5ysy1yn.js +3 -0
  54. package/dist/index-dm6yjmgq.js +3 -0
  55. package/dist/index-e1bw1bwr.js +4 -0
  56. package/dist/index-ef95xr4z.js +9 -0
  57. package/dist/index-g2raeeh4.js +11 -0
  58. package/dist/index-g3ap3xpr.js +5 -0
  59. package/dist/index-g8zv1gta.js +17 -0
  60. package/dist/index-h8a8s8sn.js +3 -0
  61. package/dist/index-hrdamx5j.js +2 -0
  62. package/dist/index-jw1k4vbk.js +3 -0
  63. package/dist/index-mtm8cfyt.js +158 -0
  64. package/dist/index-mxc61yr1.js +3 -0
  65. package/dist/index-n7qyrdr1.js +3 -0
  66. package/dist/index-qfz9fy56.js +3 -0
  67. package/dist/index-rc79x8fw.js +3 -0
  68. package/dist/index-rdp5xq4r.js +15 -0
  69. package/dist/index-scsjyj4m.js +171 -0
  70. package/dist/index-ssjmzqcz.js +13 -0
  71. package/dist/index-tmrbs96r.js +11 -0
  72. package/dist/index-tp4y9jde.js +83 -0
  73. package/dist/index-v9fx5wab.js +83 -0
  74. package/dist/index-vdahdt49.js +2 -0
  75. package/dist/index-x1h8r7pr.js +3 -0
  76. package/dist/index-xjzmb1pn.js +3 -0
  77. package/dist/index-yrgm89r8.js +3 -0
  78. package/dist/index-yy1mm8zs.js +3 -0
  79. package/dist/index-z5a4yxzz.js +8 -0
  80. package/dist/index.js +5 -0
  81. package/dist/injections-73j83es3.scm +27 -0
  82. package/dist/injections-srewsjcz.js +2 -0
  83. package/dist/interactive-22ta89hc.js +2 -0
  84. package/dist/key.cmd-wgcq6kt8.js +2 -0
  85. package/dist/log-shipper-k24m8yw5.js +2 -0
  86. package/dist/path-utils-35re7qf9.js +2 -0
  87. package/dist/plugin-system-c916v9an.js +2 -0
  88. package/dist/postinstall-shim-fix.cjs +382 -0
  89. package/dist/prereqs-runner-ca4kt803.js +2 -0
  90. package/dist/preuninstall.cjs +254 -0
  91. package/dist/profile-mount-npcknw6v.js +2 -0
  92. package/dist/prune-stale-shims-nkx9vq5m.js +2 -0
  93. package/dist/register-core-qrawzyym.js +2 -0
  94. package/dist/secondary-profile-attach-db5cr3e1.js +2 -0
  95. package/dist/subprocess-g9sk1ep9.js +2 -0
  96. package/dist/telemetry-tnq47dcs.js +2 -0
  97. package/dist/tree-sitter-javascript-3h25c6bs.js +2 -0
  98. package/dist/tree-sitter-javascript-nd0q4pe9.wasm +0 -0
  99. package/dist/tree-sitter-markdown-3nemcjhe.js +2 -0
  100. package/dist/tree-sitter-markdown-411r6y9b.wasm +0 -0
  101. package/dist/tree-sitter-markdown_inline-16ftwa53.js +2 -0
  102. package/dist/tree-sitter-markdown_inline-j5349f42.wasm +0 -0
  103. package/dist/tree-sitter-typescript-f6mq6ze6.js +2 -0
  104. package/dist/tree-sitter-typescript-zxjzwt75.wasm +0 -0
  105. package/dist/tree-sitter-zig-e78zbjpm.wasm +0 -0
  106. package/dist/tree-sitter-zig-s2trkm2d.js +2 -0
  107. package/dist/tunnel-bootstrap-2kg79ng8.js +2 -0
  108. package/package.json +122 -0
@@ -0,0 +1,382 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * postinstall self-heal for @vibecontrols/agent.
4
+ *
5
+ * The `curl | bash` install path uses `bun add -g`, which symlinks
6
+ * ~/.bun/bin/vibe into bun's global node_modules. If that target is
7
+ * later wiped (manual rm, vibe nuke fallback, partial bun remove), the
8
+ * symlink dangles. Because ~/.bun/bin precedes nvm/npm bin in $PATH,
9
+ * `vibe` invocations hit ENOENT instead of falling through to a parallel
10
+ * `npm install -g` install.
11
+ *
12
+ * Worse: bash caches resolved binaries in its in-process hash table on
13
+ * first successful exec. Once cached, bash skips PATH lookup entirely
14
+ * for that name. So even after the dangling symlink is removed, every
15
+ * existing shell that previously ran `vibe` continues to try the dead
16
+ * path until the user runs `hash -r` or opens a new terminal.
17
+ *
18
+ * Strategy:
19
+ * - Walk ~/.bun/bin/ for symlinks whose readlink target points into
20
+ * ~/.bun/install/global/node_modules/@vibecontrols/.
21
+ * - If target is alive, leave it (a working bun-global install).
22
+ * - If target is dead AND the shim name matches one we ship (`vibe`),
23
+ * REBIND it to this package's dist/cli.js — that keeps cached bash
24
+ * hash entries pointed at the same path while making them work.
25
+ * - Other dead vibecontrols-scoped shims get unlinked.
26
+ *
27
+ * Scoped strictly to @vibecontrols/* targets — never touches unrelated
28
+ * tools' shims. Best-effort throughout: any error is swallowed so a
29
+ * cleanup hiccup never breaks `npm install -g`.
30
+ */
31
+
32
+ "use strict";
33
+
34
+ const fs = require("fs");
35
+ const os = require("os");
36
+ const path = require("path");
37
+ const { spawnSync } = require("child_process");
38
+
39
+ const OWNED_BIN_NAMES = new Set(["vibe"]);
40
+
41
+ // Cross-package-manager hygiene: a host can have prior `vibe` shims sitting
42
+ // in a node-version-manager bin (nvm/fnm/volta), in the npm global bin, or
43
+ // in /usr/local/bin from an older install. When the user reinstalls via a
44
+ // different package manager (e.g. curl|bash → bun), those older shims may
45
+ // outrank the new one in PATH and/or be cached in the shell's hash table,
46
+ // causing `vibe` to ENOENT against a stale path. We scan a fixed set of
47
+ // well-known bin directories and prune any *dangling* `vibe` shim. Live
48
+ // shims (real installs of the package) are never touched.
49
+ function candidateExternalBins() {
50
+ const home = os.homedir();
51
+ const bins = new Set();
52
+ const isWin = process.platform === "win32";
53
+ if (isWin) {
54
+ if (process.env.APPDATA) bins.add(path.join(process.env.APPDATA, "npm"));
55
+ if (process.env.USERPROFILE) {
56
+ bins.add(path.join(process.env.USERPROFILE, "AppData", "Roaming", "npm"));
57
+ bins.add(
58
+ path.join(process.env.USERPROFILE, "AppData", "Local", "Volta", "bin"),
59
+ );
60
+ }
61
+ if (process.env.ProgramFiles)
62
+ bins.add(path.join(process.env.ProgramFiles, "nodejs"));
63
+ } else {
64
+ bins.add(path.join(home, ".local", "bin"));
65
+ bins.add("/usr/local/bin");
66
+ bins.add("/opt/homebrew/bin");
67
+ bins.add(path.join(home, ".volta", "bin"));
68
+ // nvm + fnm — enumerate installed node versions.
69
+ const nvmRoot = path.join(home, ".nvm", "versions", "node");
70
+ try {
71
+ for (const v of fs.readdirSync(nvmRoot)) {
72
+ bins.add(path.join(nvmRoot, v, "bin"));
73
+ }
74
+ } catch {
75
+ /* no nvm */
76
+ }
77
+ const fnmRoot = path.join(home, ".fnm", "node-versions");
78
+ try {
79
+ for (const v of fs.readdirSync(fnmRoot)) {
80
+ bins.add(path.join(fnmRoot, v, "installation", "bin"));
81
+ }
82
+ } catch {
83
+ /* no fnm */
84
+ }
85
+ }
86
+ return [...bins];
87
+ }
88
+
89
+ function pruneStaleExternalShims() {
90
+ const names =
91
+ process.platform === "win32" ? ["vibe", "vibe.cmd", "vibe.ps1"] : ["vibe"];
92
+ for (const dir of candidateExternalBins()) {
93
+ if (!fs.existsSync(dir)) continue;
94
+ for (const name of names) {
95
+ const p = path.join(dir, name);
96
+ let st;
97
+ try {
98
+ st = fs.lstatSync(p);
99
+ } catch {
100
+ continue;
101
+ }
102
+ // Unix: only prune symlinks (real files might be valid wrappers from
103
+ // another live install). Dangling symlinks are unambiguous garbage.
104
+ if (st.isSymbolicLink()) {
105
+ let target;
106
+ try {
107
+ target = fs.readlinkSync(p);
108
+ } catch {
109
+ continue;
110
+ }
111
+ const abs = path.isAbsolute(target)
112
+ ? target
113
+ : path.resolve(dir, target);
114
+ try {
115
+ fs.statSync(abs);
116
+ continue; // live — leave it
117
+ } catch {
118
+ /* dangling */
119
+ }
120
+ try {
121
+ fs.unlinkSync(p);
122
+ console.log(`[@vibecontrols/agent] pruned stale shim: ${p}`);
123
+ } catch {
124
+ /* best-effort */
125
+ }
126
+ }
127
+ }
128
+ }
129
+ }
130
+
131
+ // Peer deps every vibe-plugin-* package marks `--external` at build time and
132
+ // expects to resolve from the host. Without these symlinks at the npm-global
133
+ // root, plugins installed at `<npm-global>/@vibecontrols/<plugin>/` fail to
134
+ // resolve `import 'elysia'` (etc.) because Node's walk-up-the-tree search
135
+ // can't see the agent's nested copy at
136
+ // `<npm-global>/@vibecontrols/agent/node_modules/elysia/`.
137
+ //
138
+ // Ones we link MUST be:
139
+ // - present in the agent's own node_modules after a successful npm-global
140
+ // install (we don't fabricate them; if missing, we skip),
141
+ // - widely-shared peer deps that change rarely (so a single shared copy
142
+ // doesn't trigger version-skew issues across plugins),
143
+ // - listed as peerDependencies in actual plugin packages.
144
+ //
145
+ // Restricting to this allowlist (rather than mirroring every dep of the
146
+ // agent) keeps the symlink set small and predictable. Add to it only when
147
+ // a new plugin's --external flag exposes a new gap.
148
+ const SHARED_PEER_DEPS = ["elysia", "commander"];
149
+
150
+ function main() {
151
+ const home = os.homedir();
152
+ const bunBin = path.join(home, ".bun", "bin");
153
+ const vibeGlobalRoot = path.join(
154
+ home,
155
+ ".bun",
156
+ "install",
157
+ "global",
158
+ "node_modules",
159
+ "@vibecontrols",
160
+ );
161
+
162
+ if (!fs.existsSync(bunBin)) return;
163
+
164
+ // process.cwd() during npm postinstall is the installed package root.
165
+ const agentRoot = process.cwd();
166
+ const ourCli = path.join(agentRoot, "dist", "cli.js");
167
+ const ourCliExists = fs.existsSync(ourCli);
168
+
169
+ // Step 0: expose the agent's nested peer deps at the npm-global root so
170
+ // sibling plugin packages can resolve their `import 'elysia'` etc.
171
+ // Walks two levels up from the agent's package dir to the root that
172
+ // contains all installed packages (npm-global) and symlinks the agent's
173
+ // own dependency copy. No-op if either source missing or target already
174
+ // present.
175
+ try {
176
+ const agentNodeModules = path.join(agentRoot, "node_modules");
177
+ const npmGlobalRoot = path.dirname(path.dirname(agentRoot));
178
+ if (
179
+ fs.existsSync(agentNodeModules) &&
180
+ fs.existsSync(npmGlobalRoot) &&
181
+ path.basename(path.dirname(agentRoot)) === "@vibecontrols"
182
+ ) {
183
+ for (const dep of SHARED_PEER_DEPS) {
184
+ const src = path.join(agentNodeModules, dep);
185
+ const dst = path.join(npmGlobalRoot, dep);
186
+ if (!fs.existsSync(src)) continue;
187
+ let dstStat = null;
188
+ try {
189
+ dstStat = fs.lstatSync(dst);
190
+ } catch {
191
+ /* missing — will create */
192
+ }
193
+ if (dstStat) {
194
+ // Already present (real install or our prior symlink). If it's our
195
+ // own stale symlink to a now-missing src, replace; otherwise leave.
196
+ if (dstStat.isSymbolicLink()) {
197
+ try {
198
+ const link = fs.readlinkSync(dst);
199
+ const linkAbs = path.isAbsolute(link)
200
+ ? link
201
+ : path.resolve(npmGlobalRoot, link);
202
+ if (linkAbs === src) continue; // already pointing at us
203
+ try {
204
+ fs.statSync(linkAbs);
205
+ continue; // points elsewhere but valid — don't clobber
206
+ } catch {
207
+ // dangling symlink — replace
208
+ fs.unlinkSync(dst);
209
+ }
210
+ } catch {
211
+ continue;
212
+ }
213
+ } else {
214
+ // Real install (or directory) — never clobber.
215
+ continue;
216
+ }
217
+ }
218
+ try {
219
+ fs.symlinkSync(src, dst);
220
+ console.log(
221
+ `[@vibecontrols/agent] linked shared peer dep ${dep} at ${dst}`,
222
+ );
223
+ } catch (err) {
224
+ // best-effort; symlink can fail on Windows without admin/dev mode,
225
+ // or on filesystems that disallow symlinks. Plugins that depend on
226
+ // these peer deps will still fail to load — surface the reason.
227
+ console.log(
228
+ `[@vibecontrols/agent] could not link ${dep}: ${err.message}`,
229
+ );
230
+ }
231
+ }
232
+ }
233
+ } catch {
234
+ /* never fail the install on a peer-dep linking hiccup */
235
+ }
236
+
237
+ let entries;
238
+ try {
239
+ entries = fs.readdirSync(bunBin);
240
+ } catch {
241
+ return;
242
+ }
243
+
244
+ for (const name of entries) {
245
+ const full = path.join(bunBin, name);
246
+ let st;
247
+ try {
248
+ st = fs.lstatSync(full);
249
+ } catch {
250
+ continue;
251
+ }
252
+ if (!st.isSymbolicLink()) continue;
253
+
254
+ let link;
255
+ try {
256
+ link = fs.readlinkSync(full);
257
+ } catch {
258
+ continue;
259
+ }
260
+ const target = path.isAbsolute(link) ? link : path.resolve(bunBin, link);
261
+ if (!target.startsWith(vibeGlobalRoot + path.sep)) continue;
262
+
263
+ let targetAlive = true;
264
+ try {
265
+ fs.statSync(target);
266
+ } catch {
267
+ targetAlive = false;
268
+ }
269
+ if (targetAlive) continue;
270
+
271
+ if (OWNED_BIN_NAMES.has(name) && ourCliExists) {
272
+ try {
273
+ fs.unlinkSync(full);
274
+ fs.symlinkSync(ourCli, full);
275
+ try {
276
+ fs.chmodSync(ourCli, 0o755);
277
+ } catch {
278
+ /* non-fatal */
279
+ }
280
+ console.log(
281
+ `[@vibecontrols/agent] rebound stale bun-shim ${full} -> ${ourCli}`,
282
+ );
283
+ continue;
284
+ } catch {
285
+ /* fall through to unlink */
286
+ }
287
+ }
288
+
289
+ try {
290
+ fs.unlinkSync(full);
291
+ console.log(`[@vibecontrols/agent] pruned dangling bun-shim: ${full}`);
292
+ } catch {
293
+ /* best-effort */
294
+ }
295
+ }
296
+ }
297
+
298
+ // Windows-only: when the agent is installed via `npm install -g`, npm derives
299
+ // the `vibe.ps1` / `vibe.cmd` shim's interpreter from the bin's
300
+ // `#!/usr/bin/env bun` shebang — emitting a bare `bun`. If Bun isn't on PATH at
301
+ // invocation time the shim dies with
302
+ // "The term 'bun.exe' is not recognized as a name of a cmdlet...". Bun is the
303
+ // agent's runtime and the installer guarantees it under ~/.bun, so rewrite the
304
+ // bare `bun` token in those shims to bun's absolute path. Best-effort and
305
+ // idempotent: only acts when Bun is NOT already resolvable on PATH (a working
306
+ // setup is left untouched) and a concrete bun.exe exists to point at.
307
+ function patchWindowsNpmBunShims() {
308
+ if (process.platform !== "win32") return;
309
+ const home = os.homedir();
310
+ const bunAbs = path.join(home, ".bun", "bin", "bun.exe");
311
+ if (!fs.existsSync(bunAbs)) return;
312
+
313
+ // If bun already resolves on PATH the npm shim works as-is — don't touch it.
314
+ try {
315
+ const w = spawnSync("where.exe", ["bun"], { stdio: "ignore" });
316
+ if (w && w.status === 0) return;
317
+ } catch {
318
+ /* where.exe missing/blocked — proceed to patch defensively */
319
+ }
320
+
321
+ const dirs = new Set();
322
+ if (process.env.APPDATA) dirs.add(path.join(process.env.APPDATA, "npm"));
323
+ if (process.env.USERPROFILE) {
324
+ dirs.add(path.join(process.env.USERPROFILE, "AppData", "Roaming", "npm"));
325
+ }
326
+
327
+ for (const dir of dirs) {
328
+ // PowerShell shim: `& "bun$exe" "$basedir/.../cli.js" $args`
329
+ const ps1 = path.join(dir, "vibe.ps1");
330
+ try {
331
+ if (fs.existsSync(ps1)) {
332
+ const c = fs.readFileSync(ps1, "utf8");
333
+ if (c.includes('"bun$exe"')) {
334
+ // String split/join avoids regex-escaping the backslashes in bunAbs.
335
+ fs.writeFileSync(ps1, c.split('"bun$exe"').join(`"${bunAbs}"`));
336
+ console.log(
337
+ `[@vibecontrols/agent] patched ${ps1} -> ${bunAbs} (bun was not on PATH)`,
338
+ );
339
+ }
340
+ }
341
+ } catch {
342
+ /* best-effort */
343
+ }
344
+ // cmd.exe shim: npm emits a bare (often quoted) `bun` as the program name.
345
+ const cmd = path.join(dir, "vibe.cmd");
346
+ try {
347
+ if (
348
+ fs.existsSync(cmd) &&
349
+ !fs.readFileSync(cmd, "utf8").includes(bunAbs)
350
+ ) {
351
+ const c = fs.readFileSync(cmd, "utf8");
352
+ const patched = c.replace(/"bun"/g, `"${bunAbs}"`);
353
+ if (patched !== c) {
354
+ fs.writeFileSync(cmd, patched);
355
+ console.log(
356
+ `[@vibecontrols/agent] patched ${cmd} -> ${bunAbs} (bun was not on PATH)`,
357
+ );
358
+ }
359
+ }
360
+ } catch {
361
+ /* best-effort */
362
+ }
363
+ }
364
+ }
365
+
366
+ try {
367
+ pruneStaleExternalShims();
368
+ } catch {
369
+ /* never fail the install on a cross-bin cleanup hiccup */
370
+ }
371
+
372
+ try {
373
+ patchWindowsNpmBunShims();
374
+ } catch {
375
+ /* never fail the install on a shim-patch hiccup */
376
+ }
377
+
378
+ try {
379
+ main();
380
+ } catch {
381
+ /* never fail the install on a cleanup hiccup */
382
+ }
@@ -0,0 +1,2 @@
1
+ // @bun
2
+ import{d as a,e as b}from"./index-0248afsn.js";import"./index-2gsarrbn.js";import"./index-d5ysy1yn.js";import"./index-9bqd8veb.js";import"./index-0cn9bv8z.js";import"./index-jw1k4vbk.js";import"./index-yy1mm8zs.js";export{a as runPluginPrereqs,b as readPrereqState};
@@ -0,0 +1,254 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * preuninstall hook for @vibecontrols/agent.
4
+ *
5
+ * Runs before npm physically removes the package on `npm uninstall -g
6
+ * @vibecontrols/agent`. Cleans up everything the agent left on the host
7
+ * so the user gets a true uninstall — not a half-state where files,
8
+ * tunnels, and autostart daemons keep running with no agent to manage
9
+ * them.
10
+ *
11
+ * What we remove:
12
+ * 1. Running agent daemons — best-effort SIGTERM by PID from the
13
+ * product-level agents.json registry.
14
+ * 2. Detached tunnel children — every PID recorded in any profile's
15
+ * tunnel.state.json (cloudflared/frpc
16
+ * survive `vibe stop` by design, so
17
+ * they survive uninstall too unless
18
+ * we kill them explicitly).
19
+ * 3. Autostart daemons — systemd user units, launchd plists,
20
+ * Windows Task Scheduler tasks. Best-
21
+ * effort across all profiles found in
22
+ * the registry.
23
+ * 4. Data directory — `~/.boff/vibecontrols/` recursive
24
+ * rm. SKIPPED when:
25
+ * - VIBECONTROLS_PRESERVE_DATA=true
26
+ * - npm_config_preserve_data=true
27
+ * (set via `npm uninstall -g
28
+ * @vibecontrols/agent --preserve-data`)
29
+ *
30
+ * Idempotent + safe: every step is wrapped in try/catch and logs to
31
+ * stderr. A cleanup hiccup never throws — we'd rather let the npm
32
+ * uninstall complete than leave the user stuck on a failed hook.
33
+ *
34
+ * CommonJS because npm invokes preuninstall hooks as plain Node scripts
35
+ * via `node`, not Bun. Mirror style of postinstall-shim-fix.cjs.
36
+ */
37
+
38
+ "use strict";
39
+
40
+ const fs = require("fs");
41
+ const os = require("os");
42
+ const path = require("path");
43
+ const { spawnSync } = require("child_process");
44
+
45
+ function log(msg) {
46
+ try {
47
+ process.stderr.write(`[@vibecontrols/agent preuninstall] ${msg}\n`);
48
+ } catch {
49
+ /* ignore */
50
+ }
51
+ }
52
+
53
+ function shouldPreserveData() {
54
+ if (process.env.VIBECONTROLS_PRESERVE_DATA === "true") return true;
55
+ // npm forwards --preserve-data as npm_config_preserve_data="true"
56
+ if (process.env.npm_config_preserve_data === "true") return true;
57
+ return false;
58
+ }
59
+
60
+ function getProductDir() {
61
+ if (process.env.VIBECONTROLS_HOME) return process.env.VIBECONTROLS_HOME;
62
+ return path.join(os.homedir(), ".boff", "vibecontrols");
63
+ }
64
+
65
+ function readJsonSafe(file) {
66
+ try {
67
+ if (!fs.existsSync(file)) return null;
68
+ return JSON.parse(fs.readFileSync(file, "utf8"));
69
+ } catch {
70
+ return null;
71
+ }
72
+ }
73
+
74
+ function killPid(pid, signal) {
75
+ if (!pid || typeof pid !== "number") return;
76
+ try {
77
+ process.kill(pid, signal || "SIGTERM");
78
+ } catch {
79
+ /* already dead — ignore */
80
+ }
81
+ }
82
+
83
+ // Step 1: stop running agent daemons (best-effort SIGTERM from registry).
84
+ function stopAgents(productDir) {
85
+ try {
86
+ const registry = readJsonSafe(path.join(productDir, "agents.json"));
87
+ if (!registry) return [];
88
+ const list = Array.isArray(registry)
89
+ ? registry
90
+ : Array.isArray(registry.instances)
91
+ ? registry.instances
92
+ : [];
93
+ const names = [];
94
+ for (const entry of list) {
95
+ if (entry && typeof entry.pid === "number") {
96
+ killPid(entry.pid, "SIGTERM");
97
+ log(`SIGTERM agent ${entry.name || "?"} pid=${entry.pid}`);
98
+ }
99
+ if (entry && typeof entry.name === "string") names.push(entry.name);
100
+ }
101
+ return names;
102
+ } catch (err) {
103
+ log(`stopAgents: ${err && err.message ? err.message : err}`);
104
+ return [];
105
+ }
106
+ }
107
+
108
+ // Step 2: kill detached tunnel children recorded in any profile's
109
+ // tunnel.state.json under <productDir>/agents/<profile>/tunnel.state.json.
110
+ function stopTunnels(productDir) {
111
+ try {
112
+ const agentsDir = path.join(productDir, "agents");
113
+ if (!fs.existsSync(agentsDir)) return;
114
+ const profiles = fs.readdirSync(agentsDir);
115
+ for (const profile of profiles) {
116
+ const stateFile = path.join(agentsDir, profile, "tunnel.state.json");
117
+ const state = readJsonSafe(stateFile);
118
+ if (state && typeof state.pid === "number") {
119
+ killPid(state.pid, "SIGTERM");
120
+ log(`SIGTERM tunnel pid=${state.pid} (profile=${profile})`);
121
+ }
122
+ }
123
+ } catch (err) {
124
+ log(`stopTunnels: ${err && err.message ? err.message : err}`);
125
+ }
126
+ }
127
+
128
+ // Step 3: remove autostart daemons across all known profiles.
129
+ //
130
+ // The registry's profile names tell us which autostart entries the agent
131
+ // has likely created. We attempt removal for each — if a name has no
132
+ // installed daemon, the underlying tools no-op silently.
133
+ function removeAutostart(productDir, profileNames) {
134
+ // Always include the canonical default so a clean uninstall on a host
135
+ // with no agents.json still strips a manually-installed default daemon.
136
+ const candidates = new Set(["default", ...profileNames]);
137
+ const platform = os.platform();
138
+ for (const name of candidates) {
139
+ try {
140
+ if (platform === "linux") {
141
+ const unit = `vibecontrols-agent-${name}.service`;
142
+ const unitPath = path.join(
143
+ os.homedir(),
144
+ ".config",
145
+ "systemd",
146
+ "user",
147
+ unit,
148
+ );
149
+ spawnSync("systemctl", ["--user", "stop", unit], { stdio: "ignore" });
150
+ spawnSync("systemctl", ["--user", "disable", unit], {
151
+ stdio: "ignore",
152
+ });
153
+ if (fs.existsSync(unitPath)) {
154
+ fs.unlinkSync(unitPath);
155
+ log(`removed systemd unit: ${unitPath}`);
156
+ }
157
+ spawnSync("systemctl", ["--user", "daemon-reload"], {
158
+ stdio: "ignore",
159
+ });
160
+ } else if (platform === "darwin") {
161
+ const label = `com.boff.vibecontrols.agent.${name}`;
162
+ const plistPath = path.join(
163
+ os.homedir(),
164
+ "Library",
165
+ "LaunchAgents",
166
+ `${label}.plist`,
167
+ );
168
+ spawnSync("launchctl", ["unload", plistPath], { stdio: "ignore" });
169
+ const uidProc = spawnSync("id", ["-u"], { encoding: "utf8" });
170
+ const uid = (uidProc.stdout || "").trim();
171
+ if (uid) {
172
+ spawnSync("launchctl", ["bootout", `gui/${uid}/${label}`], {
173
+ stdio: "ignore",
174
+ });
175
+ }
176
+ if (fs.existsSync(plistPath)) {
177
+ fs.unlinkSync(plistPath);
178
+ log(`removed launchd plist: ${plistPath}`);
179
+ }
180
+ } else if (platform === "win32") {
181
+ const taskName = `VibeControlsAgent_${name}`;
182
+ spawnSync("schtasks.exe", ["/End", "/TN", taskName], {
183
+ stdio: "ignore",
184
+ });
185
+ spawnSync("schtasks.exe", ["/Delete", "/TN", taskName, "/F"], {
186
+ stdio: "ignore",
187
+ });
188
+ // Best-effort cleanup of the generated XML registration file.
189
+ const xmlPath = path.join(productDir, `autostart-${name}.xml`);
190
+ if (fs.existsSync(xmlPath)) {
191
+ try {
192
+ fs.unlinkSync(xmlPath);
193
+ } catch {
194
+ /* ignore */
195
+ }
196
+ }
197
+ }
198
+ } catch (err) {
199
+ log(
200
+ `removeAutostart(${name}): ${err && err.message ? err.message : err}`,
201
+ );
202
+ }
203
+ }
204
+ }
205
+
206
+ // Step 4: remove the data directory (gated by --preserve-data / env var).
207
+ function removeDataDir(productDir) {
208
+ if (shouldPreserveData()) {
209
+ log(
210
+ `VIBECONTROLS_PRESERVE_DATA / --preserve-data set; keeping ${productDir}`,
211
+ );
212
+ return;
213
+ }
214
+ try {
215
+ if (fs.existsSync(productDir)) {
216
+ fs.rmSync(productDir, { recursive: true, force: true });
217
+ log(`removed data dir: ${productDir}`);
218
+ }
219
+ } catch (err) {
220
+ log(`removeDataDir: ${err && err.message ? err.message : err}`);
221
+ }
222
+ }
223
+
224
+ function main() {
225
+ const productDir = getProductDir();
226
+ // Order matters: stop agents first so they don't auto-respawn tunnels;
227
+ // kill tunnels before tearing down autostart units (which on Linux/mac
228
+ // would re-launch the agent + tunnel chain on the next reboot if left
229
+ // enabled); finally rm the data dir.
230
+ const names = stopAgents(productDir);
231
+ // Give agents a brief moment to flush their shutdown handlers before
232
+ // we kill detached tunnel children. 250 ms is enough for SIGTERM
233
+ // delivery without dragging out the npm uninstall noticeably.
234
+ try {
235
+ const end = Date.now() + 250;
236
+ while (Date.now() < end) {
237
+ // Busy-wait is fine here; this script runs once per uninstall and
238
+ // the alternative (setTimeout + Promise) would force the script
239
+ // into async land for very little benefit.
240
+ }
241
+ } catch {
242
+ /* ignore */
243
+ }
244
+ stopTunnels(productDir);
245
+ removeAutostart(productDir, names);
246
+ removeDataDir(productDir);
247
+ }
248
+
249
+ try {
250
+ main();
251
+ } catch (err) {
252
+ // Never fail the uninstall on a cleanup hiccup.
253
+ log(`unexpected: ${err && err.message ? err.message : err}`);
254
+ }
@@ -0,0 +1,2 @@
1
+ // @bun
2
+ import{nb as a,ob as b,pb as c,qb as d,rb as e,sb as f}from"./index-v9fx5wab.js";import"./index-01qzsnwd.js";import"./index-d5ysy1yn.js";import"./index-04n4qgvd.js";import"./index-g2raeeh4.js";import"./index-9bqd8veb.js";import"./index-0cn9bv8z.js";import"./index-jw1k4vbk.js";import"./index-yy1mm8zs.js";export{b as unmountProfileRoutes,a as mountProfileRoutes,c as dispatchProfileRequest,f as __setMountForTests,e as __resetProfileMountsForTests,d as __listMountedProfilesForTests};
@@ -0,0 +1,2 @@
1
+ // @bun
2
+ import{H as a}from"./index-mxc61yr1.js";import"./index-yy1mm8zs.js";export{a as pruneStaleBunBinShims};
@@ -0,0 +1,2 @@
1
+ // @bun
2
+ import{J as a}from"./index-3ys16efc.js";import"./index-2gsarrbn.js";import"./index-b5dhmybd.js";import"./index-e1bw1bwr.js";import"./index-g8zv1gta.js";import"./index-qfz9fy56.js";import"./index-ssjmzqcz.js";import"./index-4wgjx8bf.js";import"./index-g3ap3xpr.js";import"./index-0ckffygp.js";import"./index-rc79x8fw.js";import"./index-yrgm89r8.js";import"./index-52cp759f.js";import"./index-01qzsnwd.js";import"./index-d5ysy1yn.js";import"./index-04n4qgvd.js";import"./index-5mw3eshk.js";import"./index-z5a4yxzz.js";import"./index-ef95xr4z.js";import"./index-xjzmb1pn.js";import"./index-g2raeeh4.js";import"./index-9bqd8veb.js";import"./index-0cn9bv8z.js";import"./index-jw1k4vbk.js";import"./index-yy1mm8zs.js";export{a as registerCoreCommands};
@@ -0,0 +1,2 @@
1
+ // @bun
2
+ import{x as a}from"./index-1hnw0rhc.js";import"./index-tp4y9jde.js";import"./index-4wgjx8bf.js";import"./index-g3ap3xpr.js";import"./index-0ckffygp.js";import"./index-v9fx5wab.js";import"./index-01qzsnwd.js";import"./index-d5ysy1yn.js";import"./index-04n4qgvd.js";import"./index-g2raeeh4.js";import"./index-9bqd8veb.js";import"./index-0cn9bv8z.js";import"./index-jw1k4vbk.js";import"./index-yy1mm8zs.js";export{a as attachSecondaryProfile};
@@ -0,0 +1,2 @@
1
+ // @bun
2
+ import{o as a,p as b,q as c,r as d,s as e}from"./index-n7qyrdr1.js";import"./index-0ckffygp.js";import"./index-9bqd8veb.js";import"./index-0cn9bv8z.js";import"./index-jw1k4vbk.js";import"./index-yy1mm8zs.js";export{a as spawnTracked,c as listTrackedByOwner,b as listTracked,d as killTracked,e as killAllTracked};
@@ -0,0 +1,2 @@
1
+ // @bun
2
+ import{bb as a}from"./index-yrgm89r8.js";import"./index-52cp759f.js";import"./index-9bqd8veb.js";import"./index-0cn9bv8z.js";import"./index-jw1k4vbk.js";import"./index-yy1mm8zs.js";export{a as telemetryService};
@@ -0,0 +1,2 @@
1
+ // @bun
2
+ import"./index-yy1mm8zs.js";var l="./tree-sitter-javascript-nd0q4pe9.wasm";export{l as default};
@@ -0,0 +1,2 @@
1
+ // @bun
2
+ import"./index-yy1mm8zs.js";var F="./tree-sitter-markdown-411r6y9b.wasm";export{F as default};
@@ -0,0 +1,2 @@
1
+ // @bun
2
+ import"./index-yy1mm8zs.js";var E="./tree-sitter-markdown_inline-j5349f42.wasm";export{E as default};