@westbayberry/dg 2.2.0 → 2.3.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.
Files changed (48) hide show
  1. package/dist/agents/claude-code.js +10 -0
  2. package/dist/agents/codex.js +1 -1
  3. package/dist/agents/cursor.js +6 -1
  4. package/dist/agents/gate-posture.js +21 -0
  5. package/dist/agents/persistence.js +68 -2
  6. package/dist/agents/registry.js +4 -3
  7. package/dist/agents/routing.js +118 -0
  8. package/dist/agents/windsurf.js +1 -1
  9. package/dist/audit/rules.js +6 -2
  10. package/dist/auth/store.js +9 -2
  11. package/dist/commands/agents.js +45 -1
  12. package/dist/commands/audit.js +6 -0
  13. package/dist/commands/setup.js +1 -2
  14. package/dist/commands/uninstall.js +2 -1
  15. package/dist/config/settings.js +35 -4
  16. package/dist/install-ui/LiveInstall.js +3 -2
  17. package/dist/install-ui/block-render.js +17 -13
  18. package/dist/launcher/agent-check.js +455 -25
  19. package/dist/launcher/agent-hook-exec.js +1 -1
  20. package/dist/launcher/agent-hook-io.js +12 -4
  21. package/dist/launcher/classify.js +27 -1
  22. package/dist/launcher/env.js +39 -7
  23. package/dist/launcher/install-preflight.js +15 -6
  24. package/dist/launcher/live-install.js +4 -3
  25. package/dist/launcher/manifest-screen.js +171 -0
  26. package/dist/launcher/output-redaction.js +4 -1
  27. package/dist/launcher/preflight-prompt.js +4 -3
  28. package/dist/launcher/run.js +90 -18
  29. package/dist/project/dgfile.js +2 -1
  30. package/dist/project/override-trust.js +0 -0
  31. package/dist/proxy/metadata-map.js +29 -13
  32. package/dist/proxy/server.js +130 -14
  33. package/dist/runtime/first-run.js +2 -1
  34. package/dist/sbom-ui/inventory.js +5 -1
  35. package/dist/scan/staged.js +31 -8
  36. package/dist/scan-ui/hooks/useScan.js +4 -1
  37. package/dist/security/sanitize.js +8 -4
  38. package/dist/service/state.js +1 -1
  39. package/dist/service/trust-store.js +5 -9
  40. package/dist/service/worker.js +3 -3
  41. package/dist/setup/plan.js +156 -12
  42. package/dist/setup/uninstall-standalone.js +25 -0
  43. package/dist/setup-ui/wizard.js +9 -1
  44. package/dist/standalone/uninstall.mjs +2123 -0
  45. package/dist/verify/local.js +2 -2
  46. package/dist/verify/package-check.js +3 -1
  47. package/npm-shrinkwrap.json +2 -2
  48. package/package.json +2 -1
@@ -0,0 +1,2123 @@
1
+ var __getOwnPropNames = Object.getOwnPropertyNames;
2
+ var __esm = (fn, res) => function __init() {
3
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
4
+ };
5
+
6
+ // dist.next/state/store.js
7
+ import { mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
8
+ import { dirname } from "node:path";
9
+ import { randomUUID } from "node:crypto";
10
+ async function readJsonFile(path, fallback) {
11
+ try {
12
+ const content = await readFile(path, "utf8");
13
+ return JSON.parse(content);
14
+ } catch (error) {
15
+ if (isNotFound(error)) {
16
+ return fallback;
17
+ }
18
+ if (error instanceof SyntaxError) {
19
+ throw new JsonStoreError(`Malformed JSON store at ${path}`, error);
20
+ }
21
+ throw error;
22
+ }
23
+ }
24
+ async function writeJsonFileAtomic(path, value) {
25
+ await mkdir(dirname(path), {
26
+ recursive: true,
27
+ mode: 448
28
+ });
29
+ const tempPath = `${path}.${process.pid}.${randomUUID()}.tmp`;
30
+ const payload = `${JSON.stringify(value, null, 2)}
31
+ `;
32
+ try {
33
+ await writeFile(tempPath, payload, {
34
+ encoding: "utf8",
35
+ flag: "wx",
36
+ mode: 384
37
+ });
38
+ await rename(tempPath, path);
39
+ } catch (error) {
40
+ await rm(tempPath, {
41
+ force: true
42
+ });
43
+ throw error;
44
+ }
45
+ }
46
+ function isNotFound(error) {
47
+ return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
48
+ }
49
+ var JsonStoreError;
50
+ var init_store = __esm({
51
+ "dist.next/state/store.js"() {
52
+ "use strict";
53
+ JsonStoreError = class extends Error {
54
+ cause;
55
+ constructor(message, cause) {
56
+ super(message);
57
+ this.cause = cause;
58
+ this.name = "JsonStoreError";
59
+ }
60
+ };
61
+ }
62
+ });
63
+
64
+ // dist.next/state/locks.js
65
+ import { closeSync, mkdirSync, openSync, readFileSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
66
+ import { mkdir as mkdir2, open, readFile as readFile2, rename as rename2, rm as rm2, stat } from "node:fs/promises";
67
+ import { join } from "node:path";
68
+ function isErrno(error, code) {
69
+ return typeof error === "object" && error !== null && "code" in error && error.code === code;
70
+ }
71
+ async function acquireLock(paths, name, options = {}) {
72
+ assertLockName(name);
73
+ await mkdir2(paths.locksDir, {
74
+ recursive: true,
75
+ mode: 448
76
+ });
77
+ const path = join(paths.locksDir, `${name}.lock`);
78
+ await removeStaleLock(path, options);
79
+ let handle;
80
+ try {
81
+ handle = await open(path, "wx", 384);
82
+ } catch (error) {
83
+ if (isErrno(error, "EEXIST")) {
84
+ throw new LockBusyError(path);
85
+ }
86
+ throw error;
87
+ }
88
+ const metadata = {
89
+ pid: process.pid,
90
+ acquiredAt: (options.now ?? /* @__PURE__ */ new Date()).toISOString()
91
+ };
92
+ try {
93
+ await handle.writeFile(`${JSON.stringify(metadata)}
94
+ `, "utf8");
95
+ } finally {
96
+ await handle.close();
97
+ }
98
+ return {
99
+ name,
100
+ path,
101
+ release: async () => {
102
+ await rm2(path, {
103
+ force: true
104
+ });
105
+ }
106
+ };
107
+ }
108
+ function acquireLockSync(paths, name, options = {}) {
109
+ assertLockName(name);
110
+ mkdirSync(paths.locksDir, {
111
+ recursive: true,
112
+ mode: 448
113
+ });
114
+ const path = join(paths.locksDir, `${name}.lock`);
115
+ removeStaleLockSync(path, options);
116
+ let fd;
117
+ try {
118
+ fd = openSync(path, "wx", 384);
119
+ } catch (error) {
120
+ if (isErrno(error, "EEXIST")) {
121
+ throw new LockBusyError(path);
122
+ }
123
+ throw error;
124
+ }
125
+ const metadata = {
126
+ pid: process.pid,
127
+ acquiredAt: (options.now ?? /* @__PURE__ */ new Date()).toISOString()
128
+ };
129
+ try {
130
+ writeFileSync(fd, `${JSON.stringify(metadata)}
131
+ `, "utf8");
132
+ } finally {
133
+ closeSync(fd);
134
+ }
135
+ return {
136
+ name,
137
+ path,
138
+ release: () => {
139
+ rmSync(path, {
140
+ force: true
141
+ });
142
+ }
143
+ };
144
+ }
145
+ function isProcessAlive(pid) {
146
+ try {
147
+ process.kill(pid, 0);
148
+ return true;
149
+ } catch (error) {
150
+ return !isErrno(error, "ESRCH");
151
+ }
152
+ }
153
+ function holderStateFromContent(content) {
154
+ let pid;
155
+ try {
156
+ pid = JSON.parse(content).pid;
157
+ } catch {
158
+ return "unknown";
159
+ }
160
+ if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0) {
161
+ return "unknown";
162
+ }
163
+ return isProcessAlive(pid) ? "alive" : "dead";
164
+ }
165
+ async function removeStaleLock(path, options) {
166
+ let content;
167
+ try {
168
+ content = await readFile2(path, "utf8");
169
+ } catch (error) {
170
+ if (isErrno(error, "ENOENT")) {
171
+ return;
172
+ }
173
+ content = null;
174
+ }
175
+ const holder = content === null ? "unknown" : holderStateFromContent(content);
176
+ if (holder === "alive") {
177
+ return;
178
+ }
179
+ if (holder === "dead") {
180
+ await takeoverLock(path);
181
+ return;
182
+ }
183
+ if (!options.staleMs) {
184
+ return;
185
+ }
186
+ const details = await stat(path).catch((error) => {
187
+ if (isErrno(error, "ENOENT")) {
188
+ return null;
189
+ }
190
+ throw error;
191
+ });
192
+ if (!details) {
193
+ return;
194
+ }
195
+ const now = options.now?.getTime() ?? Date.now();
196
+ if (now - details.mtimeMs < options.staleMs) {
197
+ return;
198
+ }
199
+ await takeoverLock(path);
200
+ }
201
+ function removeStaleLockSync(path, options) {
202
+ let content;
203
+ try {
204
+ content = readFileSync(path, "utf8");
205
+ } catch (error) {
206
+ if (isErrno(error, "ENOENT")) {
207
+ return;
208
+ }
209
+ content = null;
210
+ }
211
+ const holder = content === null ? "unknown" : holderStateFromContent(content);
212
+ if (holder === "alive") {
213
+ return;
214
+ }
215
+ if (holder === "dead") {
216
+ takeoverLockSync(path);
217
+ return;
218
+ }
219
+ if (!options.staleMs) {
220
+ return;
221
+ }
222
+ let details;
223
+ try {
224
+ details = statSync(path);
225
+ } catch (error) {
226
+ if (isErrno(error, "ENOENT")) {
227
+ return;
228
+ }
229
+ throw error;
230
+ }
231
+ const now = options.now?.getTime() ?? Date.now();
232
+ if (now - details.mtimeMs < options.staleMs) {
233
+ return;
234
+ }
235
+ takeoverLockSync(path);
236
+ }
237
+ async function takeoverLock(path) {
238
+ const takeoverPath = `${path}.stale-${process.pid}-${++takeoverCounter}`;
239
+ try {
240
+ await rename2(path, takeoverPath);
241
+ } catch (error) {
242
+ if (isErrno(error, "ENOENT")) {
243
+ return;
244
+ }
245
+ throw error;
246
+ }
247
+ await rm2(takeoverPath, {
248
+ force: true
249
+ });
250
+ }
251
+ function takeoverLockSync(path) {
252
+ const takeoverPath = `${path}.stale-${process.pid}-${++takeoverCounter}`;
253
+ try {
254
+ renameSync(path, takeoverPath);
255
+ } catch (error) {
256
+ if (isErrno(error, "ENOENT")) {
257
+ return;
258
+ }
259
+ throw error;
260
+ }
261
+ rmSync(takeoverPath, {
262
+ force: true
263
+ });
264
+ }
265
+ function assertLockName(name) {
266
+ if (!/^[a-z][a-z0-9-]{0,63}$/.test(name)) {
267
+ throw new Error(`Invalid dg lock name: ${name}`);
268
+ }
269
+ }
270
+ var CLEANUP_REGISTRY_LOCK, takeoverCounter, LockBusyError;
271
+ var init_locks = __esm({
272
+ "dist.next/state/locks.js"() {
273
+ "use strict";
274
+ CLEANUP_REGISTRY_LOCK = "cleanup-registry";
275
+ takeoverCounter = 0;
276
+ LockBusyError = class extends Error {
277
+ path;
278
+ constructor(path) {
279
+ super(`dg lock is already held: ${path}`);
280
+ this.path = path;
281
+ this.name = "LockBusyError";
282
+ }
283
+ };
284
+ }
285
+ });
286
+
287
+ // dist.next/state/cleanup-registry.js
288
+ import { renameSync as renameSync2 } from "node:fs";
289
+ import { rename as rename3 } from "node:fs/promises";
290
+ function emptyCleanupRegistry() {
291
+ return {
292
+ version: 1,
293
+ entries: []
294
+ };
295
+ }
296
+ async function loadCleanupRegistry(paths, options = {}) {
297
+ let parsed;
298
+ try {
299
+ parsed = await readJsonFile(paths.cleanupRegistryPath, emptyCleanupRegistry());
300
+ } catch (error) {
301
+ if (!(error instanceof JsonStoreError)) {
302
+ throw error;
303
+ }
304
+ parsed = void 0;
305
+ }
306
+ if (isCleanupRegistry(parsed)) {
307
+ return {
308
+ registry: parsed
309
+ };
310
+ }
311
+ const preserved = await preserveCorruptRegistry(paths, options);
312
+ return {
313
+ registry: emptyCleanupRegistry(),
314
+ ...preserved ? { corruptPreservedPath: preserved } : {}
315
+ };
316
+ }
317
+ async function readCleanupRegistry(paths) {
318
+ return (await loadCleanupRegistry(paths)).registry;
319
+ }
320
+ async function writeCleanupRegistry(paths, registry) {
321
+ await writeJsonFileAtomic(paths.cleanupRegistryPath, registry);
322
+ }
323
+ async function recordCleanupEntry(paths, entry) {
324
+ const lock = await acquireLock(paths, CLEANUP_REGISTRY_LOCK);
325
+ try {
326
+ const { registry } = await loadCleanupRegistry(paths);
327
+ const nextEntry = {
328
+ ...entry,
329
+ installedAt: entry.installedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
330
+ owner: "dg"
331
+ };
332
+ const entries = registry.entries.filter((candidate) => !sameRegistryTarget(candidate, nextEntry));
333
+ const next = {
334
+ version: 1,
335
+ entries: [...entries, nextEntry]
336
+ };
337
+ await writeCleanupRegistry(paths, next);
338
+ return next;
339
+ } finally {
340
+ await lock.release();
341
+ }
342
+ }
343
+ async function removeCleanupEntry(paths, target) {
344
+ const lock = await acquireLock(paths, CLEANUP_REGISTRY_LOCK);
345
+ try {
346
+ const { registry } = await loadCleanupRegistry(paths);
347
+ const next = {
348
+ version: 1,
349
+ entries: registry.entries.filter((candidate) => !sameRegistryTarget(candidate, target))
350
+ };
351
+ await writeCleanupRegistry(paths, next);
352
+ return next;
353
+ } finally {
354
+ await lock.release();
355
+ }
356
+ }
357
+ async function preserveCorruptRegistry(paths, options) {
358
+ const preservedPath = `${paths.cleanupRegistryPath}.corrupt-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`;
359
+ try {
360
+ await rename3(paths.cleanupRegistryPath, preservedPath);
361
+ } catch (error) {
362
+ if (isEnoent(error)) {
363
+ return void 0;
364
+ }
365
+ throw error;
366
+ }
367
+ const stderr = options.stderr ?? process.stderr;
368
+ stderr.write(`dg: cleanup registry at ${paths.cleanupRegistryPath} was unreadable; preserved it at ${preservedPath}. Previously registered entries may need 'dg doctor'.
369
+ `);
370
+ return preservedPath;
371
+ }
372
+ function preserveCorruptCleanupRegistrySync(paths, options = {}) {
373
+ const preservedPath = `${paths.cleanupRegistryPath}.corrupt-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`;
374
+ try {
375
+ renameSync2(paths.cleanupRegistryPath, preservedPath);
376
+ } catch {
377
+ return void 0;
378
+ }
379
+ const stderr = options.stderr ?? process.stderr;
380
+ stderr.write(`dg: cleanup registry at ${paths.cleanupRegistryPath} was unreadable; preserved it at ${preservedPath}. Previously registered entries may need 'dg doctor'.
381
+ `);
382
+ return preservedPath;
383
+ }
384
+ function isCleanupRegistry(value) {
385
+ return typeof value === "object" && value !== null && !Array.isArray(value) && value.version === 1 && Array.isArray(value.entries);
386
+ }
387
+ function isEnoent(error) {
388
+ return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
389
+ }
390
+ function sameRegistryTarget(left, right) {
391
+ return left.kind === right.kind && left.path === right.path && left.sentinel === right.sentinel;
392
+ }
393
+ var init_cleanup_registry = __esm({
394
+ "dist.next/state/cleanup-registry.js"() {
395
+ "use strict";
396
+ init_store();
397
+ init_locks();
398
+ }
399
+ });
400
+
401
+ // dist.next/util/json-file.js
402
+ var init_json_file = __esm({
403
+ "dist.next/util/json-file.js"() {
404
+ "use strict";
405
+ }
406
+ });
407
+
408
+ // dist.next/state/paths.js
409
+ import { homedir } from "node:os";
410
+ import { isAbsolute, join as join2 } from "node:path";
411
+ function resolveDgPaths(env = process.env) {
412
+ const homeDir = env.HOME && isAbsolute(env.HOME) ? env.HOME : homedir();
413
+ const fallbackRoot = join2(homeDir, ".dg");
414
+ const configDir = xdgPath(env.XDG_CONFIG_HOME, fallbackRoot);
415
+ const stateDir = xdgPath(env.XDG_STATE_HOME, join2(fallbackRoot, "state"));
416
+ const cacheDir = xdgPath(env.XDG_CACHE_HOME, join2(fallbackRoot, "cache"));
417
+ return {
418
+ homeDir,
419
+ configDir,
420
+ stateDir,
421
+ cacheDir,
422
+ sessionsDir: join2(stateDir, "sessions"),
423
+ cleanupRegistryPath: join2(stateDir, "cleanup-registry.json"),
424
+ locksDir: join2(stateDir, "locks")
425
+ };
426
+ }
427
+ function xdgPath(value, fallback) {
428
+ if (!value || !isAbsolute(value)) {
429
+ return fallback;
430
+ }
431
+ return join2(value, "dg");
432
+ }
433
+ var init_paths = __esm({
434
+ "dist.next/state/paths.js"() {
435
+ "use strict";
436
+ }
437
+ });
438
+
439
+ // dist.next/state/cooldown-held.js
440
+ var UNKNOWN_ELIGIBILITY_TTL_MS;
441
+ var init_cooldown_held = __esm({
442
+ "dist.next/state/cooldown-held.js"() {
443
+ "use strict";
444
+ init_json_file();
445
+ init_paths();
446
+ UNKNOWN_ELIGIBILITY_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
447
+ }
448
+ });
449
+
450
+ // dist.next/state/sessions.js
451
+ import { mkdirSync as mkdirSync2, readdirSync, readFileSync as readFileSync2, rmSync as rmSync2, statSync as statSync2 } from "node:fs";
452
+ import { join as join3 } from "node:path";
453
+ function findStaleSessionsSync(paths, options) {
454
+ const now = options.now?.getTime() ?? Date.now();
455
+ let entries;
456
+ try {
457
+ entries = readdirSync(paths.sessionsDir, {
458
+ withFileTypes: true
459
+ });
460
+ } catch (error) {
461
+ if (typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT") {
462
+ return {
463
+ stale: []
464
+ };
465
+ }
466
+ throw error;
467
+ }
468
+ const stale = [];
469
+ for (const entry of entries) {
470
+ if (!entry.isDirectory() || !isValidSessionId(entry.name)) {
471
+ continue;
472
+ }
473
+ const dir = join3(paths.sessionsDir, entry.name);
474
+ let details;
475
+ try {
476
+ details = statSync2(dir);
477
+ } catch (error) {
478
+ if (isEnoent2(error)) {
479
+ continue;
480
+ }
481
+ throw error;
482
+ }
483
+ if (now - details.mtimeMs >= options.olderThanMs) {
484
+ stale.push(entry.name);
485
+ }
486
+ }
487
+ return {
488
+ stale
489
+ };
490
+ }
491
+ function sweepStaleSessionsSync(paths, options) {
492
+ const report = findStaleSessionsSync(paths, options);
493
+ for (const id of report.stale) {
494
+ rmSync2(join3(paths.sessionsDir, id), {
495
+ force: true,
496
+ recursive: true
497
+ });
498
+ }
499
+ return {
500
+ removed: report.stale
501
+ };
502
+ }
503
+ function isValidSessionId(id) {
504
+ return /^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$/.test(id);
505
+ }
506
+ function isEnoent2(error) {
507
+ return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
508
+ }
509
+ var DEAD_SESSION_TTL_MS;
510
+ var init_sessions = __esm({
511
+ "dist.next/state/sessions.js"() {
512
+ "use strict";
513
+ init_locks();
514
+ init_store();
515
+ DEAD_SESSION_TTL_MS = 24 * 60 * 60 * 1e3;
516
+ }
517
+ });
518
+
519
+ // dist.next/state/index.js
520
+ var init_state = __esm({
521
+ "dist.next/state/index.js"() {
522
+ "use strict";
523
+ init_cleanup_registry();
524
+ init_cooldown_held();
525
+ init_locks();
526
+ init_paths();
527
+ init_sessions();
528
+ init_store();
529
+ }
530
+ });
531
+
532
+ // dist.next/config/settings.js
533
+ var CONFIG_KEYS, DEFAULT_CONFIG;
534
+ var init_settings = __esm({
535
+ "dist.next/config/settings.js"() {
536
+ "use strict";
537
+ init_json_file();
538
+ init_state();
539
+ CONFIG_KEYS = Object.freeze([
540
+ "api.baseUrl",
541
+ "org.id",
542
+ "policy.mode",
543
+ "policy.trustProjectAllowlists",
544
+ "policy.allowForceOverride",
545
+ "policy.scriptHardening",
546
+ "policy.shimFailClosed",
547
+ "policy.strictEgress",
548
+ "scriptGate.mode",
549
+ "scriptGate.observe",
550
+ "gitHook.onWarn",
551
+ "gitHook.onIncomplete",
552
+ "cooldown.age",
553
+ "cooldown.npm.age",
554
+ "cooldown.pypi.age",
555
+ "cooldown.cargo.age",
556
+ "cooldown.onUnknown",
557
+ "cooldown.exempt",
558
+ "audit.upload"
559
+ ]);
560
+ DEFAULT_CONFIG = Object.freeze({
561
+ version: 1,
562
+ api: {
563
+ baseUrl: "https://api.westbayberry.com"
564
+ },
565
+ org: {
566
+ id: ""
567
+ },
568
+ policy: {
569
+ mode: "block",
570
+ trustProjectAllowlists: false,
571
+ allowForceOverride: true,
572
+ scriptHardening: false,
573
+ shimFailClosed: false,
574
+ strictEgress: false
575
+ },
576
+ scriptGate: {
577
+ mode: "observe",
578
+ observe: false
579
+ },
580
+ gitHook: {
581
+ onWarn: "prompt",
582
+ onIncomplete: "allow"
583
+ },
584
+ cooldown: {
585
+ age: "24h",
586
+ npmAge: "",
587
+ pypiAge: "",
588
+ cargoAge: "",
589
+ onUnknown: "block",
590
+ exempt: ""
591
+ },
592
+ audit: {
593
+ upload: false
594
+ }
595
+ });
596
+ }
597
+ });
598
+
599
+ // dist.next/launcher/resolve-real-binary.js
600
+ var init_resolve_real_binary = __esm({
601
+ "dist.next/launcher/resolve-real-binary.js"() {
602
+ "use strict";
603
+ init_state();
604
+ }
605
+ });
606
+
607
+ // dist.next/launcher/spawn-invocation.js
608
+ var init_spawn_invocation = __esm({
609
+ "dist.next/launcher/spawn-invocation.js"() {
610
+ "use strict";
611
+ }
612
+ });
613
+
614
+ // dist.next/service/trust-store.js
615
+ var init_trust_store = __esm({
616
+ "dist.next/service/trust-store.js"() {
617
+ "use strict";
618
+ init_json_file();
619
+ }
620
+ });
621
+
622
+ // dist.next/service/trust-refresh.js
623
+ var init_trust_refresh = __esm({
624
+ "dist.next/service/trust-refresh.js"() {
625
+ "use strict";
626
+ init_trust_store();
627
+ }
628
+ });
629
+
630
+ // dist.next/service/state.js
631
+ var SERVICE_LOCK_STALE_MS;
632
+ var init_state2 = __esm({
633
+ "dist.next/service/state.js"() {
634
+ "use strict";
635
+ init_settings();
636
+ init_trust_store();
637
+ init_trust_refresh();
638
+ init_state();
639
+ SERVICE_LOCK_STALE_MS = 30 * 60 * 1e3;
640
+ }
641
+ });
642
+
643
+ // dist.next/setup/uninstall-standalone.js
644
+ import { rmSync as rmSync5 } from "node:fs";
645
+ import { join as join11 } from "node:path";
646
+
647
+ // dist.next/setup/plan.js
648
+ import { accessSync, constants, copyFileSync, existsSync as existsSync2, mkdirSync as mkdirSync4, readdirSync as readdirSync2, readFileSync as readFileSync4, realpathSync, renameSync as renameSync4, rmSync as rmSync4, statSync as statSync3, writeFileSync as writeFileSync3 } from "node:fs";
649
+ import { basename, delimiter, dirname as dirname3, join as join10, resolve, sep } from "node:path";
650
+ import { randomBytes as randomBytes2 } from "node:crypto";
651
+
652
+ // dist.next/agents/registry.js
653
+ init_state();
654
+
655
+ // dist.next/agents/claude-code.js
656
+ import { join as join4 } from "node:path";
657
+
658
+ // dist.next/auth/store.js
659
+ init_settings();
660
+ init_state();
661
+
662
+ // dist.next/api/analyze.js
663
+ init_settings();
664
+
665
+ // dist.next/security/sanitize.js
666
+ import { stripVTControlCharacters } from "node:util";
667
+ var CTRL_ALL = /[\x00-\x1F\x7F-\x9F]/g;
668
+ function sanitizeLine(s) {
669
+ return stripVTControlCharacters(s).replace(/[\r\n]+/g, " ").replace(CTRL_ALL, "");
670
+ }
671
+
672
+ // dist.next/api/analyze.js
673
+ init_state();
674
+ var BATCH_CONCURRENCY = Math.max(1, Number(process.env.DG_ANALYZE_CONCURRENCY) || 4);
675
+
676
+ // dist.next/setup/optional-support.js
677
+ var OPTIONAL_SUPPORT_GATES = Object.freeze([
678
+ {
679
+ id: "windows",
680
+ label: "Windows support",
681
+ kind: "platform",
682
+ status: "unclaimed",
683
+ message: "Windows support is gated in this release; use dg prefix mode from a supported POSIX shell or run 'dg --help' for supported commands"
684
+ },
685
+ {
686
+ id: "python-hook",
687
+ label: "Python .pth hook",
688
+ kind: "hook",
689
+ status: "unclaimed",
690
+ message: "Python .pth hook support is gated in this release; use 'dg pip ...', 'dg pipx ...', 'dg uv ...', or 'dg uvx ...' prefix mode instead"
691
+ },
692
+ {
693
+ id: "bun",
694
+ label: "Bun and bunx",
695
+ kind: "package-manager",
696
+ status: "unclaimed",
697
+ standaloneCommand: true,
698
+ message: "Bun support is gated in this release; use 'dg npm ...', 'dg pnpm ...', or 'dg yarn ...' for supported JavaScript installs"
699
+ },
700
+ {
701
+ id: "yarn-berry",
702
+ label: "Yarn Berry",
703
+ kind: "package-manager",
704
+ status: "unclaimed",
705
+ standaloneCommand: false,
706
+ message: "Yarn Berry support is gated in this release; use Yarn classic through 'dg yarn ...' or another supported prefix manager"
707
+ },
708
+ {
709
+ id: "conda",
710
+ label: "Conda",
711
+ kind: "package-manager",
712
+ status: "unclaimed",
713
+ standaloneCommand: true,
714
+ message: "Conda support is gated in this release; use 'dg pip ...' or 'dg uv ...' for supported Python package installs"
715
+ },
716
+ {
717
+ id: "mamba",
718
+ label: "Mamba",
719
+ kind: "package-manager",
720
+ status: "unclaimed",
721
+ standaloneCommand: true,
722
+ message: "Mamba support is gated in this release; use 'dg pip ...' or 'dg uv ...' for supported Python package installs"
723
+ }
724
+ ]);
725
+ function optionalPackageManagerNames() {
726
+ return OPTIONAL_SUPPORT_GATES.filter((gate) => gate.kind === "package-manager" && gate.standaloneCommand === true).map((gate) => gate.id);
727
+ }
728
+
729
+ // dist.next/launcher/classify.js
730
+ var gatedManagers = optionalPackageManagerNames();
731
+
732
+ // dist.next/verify/preflight.js
733
+ init_settings();
734
+
735
+ // dist.next/audit/events.js
736
+ init_state();
737
+
738
+ // dist.next/policy/evaluate.js
739
+ init_settings();
740
+
741
+ // dist.next/verify/preflight.js
742
+ var MAX_LOCKFILE_BYTES = 64 * 1024 * 1024;
743
+
744
+ // dist.next/policy/cooldown.js
745
+ init_settings();
746
+
747
+ // dist.next/util/external-tool.js
748
+ init_resolve_real_binary();
749
+ init_spawn_invocation();
750
+
751
+ // dist.next/util/git.js
752
+ var DEFAULT_MAX_BUFFER = 256 * 1024 * 1024;
753
+
754
+ // dist.next/project/dgfile.js
755
+ init_json_file();
756
+ init_state();
757
+
758
+ // dist.next/project/override-trust.js
759
+ init_state();
760
+
761
+ // dist.next/launcher/install-preflight.js
762
+ init_settings();
763
+
764
+ // dist.next/decisions/remember-prompt.js
765
+ init_settings();
766
+
767
+ // dist.next/launcher/install-preflight.js
768
+ init_spawn_invocation();
769
+
770
+ // dist.next/launcher/manifest-screen.js
771
+ var MAX_MANIFEST_BYTES = 4 * 1024 * 1024;
772
+
773
+ // dist.next/launcher/agent-check.js
774
+ function formatScreenedNote(screened) {
775
+ if (screened.length === 0) {
776
+ return "";
777
+ }
778
+ const items = screened.map((pkg) => `${pkg.name}@${pkg.version} (${pkg.ecosystem})`).join(", ");
779
+ const noun = screened.length === 1 ? "package" : "packages";
780
+ return sanitizeLine(`dg pre-screened the requested ${noun}: ${items} \u2014 no known issues (dependencies are screened at install time)`);
781
+ }
782
+
783
+ // dist.next/agents/persistence.js
784
+ init_state();
785
+ import { existsSync, lstatSync, mkdirSync as mkdirSync3, readFileSync as readFileSync3, renameSync as renameSync3, rmSync as rmSync3, writeFileSync as writeFileSync2 } from "node:fs";
786
+ import { spawnSync } from "node:child_process";
787
+ import { dirname as dirname2 } from "node:path";
788
+ import { randomBytes } from "node:crypto";
789
+ var LEGACY_AGENT_HOOK_SENTINEL = "dg-agent-hook-v1";
790
+ function agentHookSentinel(agent) {
791
+ return `${LEGACY_AGENT_HOOK_SENTINEL}:${agent}`;
792
+ }
793
+ var AgentHookError = class extends Error {
794
+ };
795
+ function dirExists(path) {
796
+ try {
797
+ return lstatSync(path).isDirectory();
798
+ } catch {
799
+ return false;
800
+ }
801
+ }
802
+ function assertSafeNode(path, role) {
803
+ let stats;
804
+ try {
805
+ stats = lstatSync(path);
806
+ } catch {
807
+ return;
808
+ }
809
+ if (stats.isSymbolicLink()) {
810
+ throw new AgentHookError(`${path} is a symlink; refusing to write through it. Edit the link target directly, then retry.`);
811
+ }
812
+ if (typeof process.getuid === "function" && stats.uid !== process.getuid()) {
813
+ throw new AgentHookError(`${path} (${role}) is owned by another user; refusing to write to it.`);
814
+ }
815
+ if ((stats.mode & 2) !== 0) {
816
+ throw new AgentHookError(`${path} (${role}) is world-writable; refusing to write to it. Tighten its permissions, then retry.`);
817
+ }
818
+ }
819
+ function assertSafeWriteTarget(path) {
820
+ assertSafeNode(dirname2(path), "directory");
821
+ assertSafeNode(path, "file");
822
+ }
823
+ function readSettings(path) {
824
+ if (!existsSync(path)) {
825
+ return { settings: {}, existed: false };
826
+ }
827
+ let parsed;
828
+ try {
829
+ parsed = JSON.parse(readFileSync3(path, "utf8"));
830
+ } catch {
831
+ throw new AgentHookError(`${path} is not valid JSON; refusing to modify it. Fix or remove it, then retry.`);
832
+ }
833
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
834
+ throw new AgentHookError(`${path} is not a JSON object; refusing to modify it.`);
835
+ }
836
+ return { settings: parsed, existed: true };
837
+ }
838
+ function writeSettingsAtomic(path, settings) {
839
+ mkdirSync3(dirname2(path), { recursive: true });
840
+ assertSafeWriteTarget(path);
841
+ const tmp = `${path}.dg-${randomBytes(6).toString("hex")}.tmp`;
842
+ writeFileSync2(tmp, `${JSON.stringify(settings, null, 2)}
843
+ `, { mode: 384, flag: "wx" });
844
+ try {
845
+ renameSync3(tmp, path);
846
+ } catch (error) {
847
+ rmSync3(tmp, { force: true });
848
+ throw error;
849
+ }
850
+ }
851
+ async function wasCreatedByDg(ctx) {
852
+ try {
853
+ const reg = await readCleanupRegistry(ctx.paths);
854
+ return reg.entries.some((e) => e.kind === "agent-hook" && e.path === ctx.settingsPath && e.original === "dg-created");
855
+ } catch {
856
+ return false;
857
+ }
858
+ }
859
+ async function recordHookEntry(ctx, legacySentinels, created) {
860
+ for (const sentinel of legacySentinels) {
861
+ await removeCleanupEntry(ctx.paths, { kind: "agent-hook", path: ctx.settingsPath, sentinel });
862
+ }
863
+ const dgCreated = created || await wasCreatedByDg(ctx);
864
+ await recordCleanupEntry(ctx.paths, {
865
+ kind: "agent-hook",
866
+ path: ctx.settingsPath,
867
+ mode: "mode1",
868
+ sentinel: agentHookSentinel(ctx.agent),
869
+ ...dgCreated ? { original: "dg-created" } : {}
870
+ });
871
+ }
872
+ async function removeHookEntries(ctx, legacySentinels) {
873
+ await removeCleanupEntry(ctx.paths, { kind: "agent-hook", path: ctx.settingsPath, sentinel: agentHookSentinel(ctx.agent) });
874
+ for (const sentinel of legacySentinels) {
875
+ await removeCleanupEntry(ctx.paths, { kind: "agent-hook", path: ctx.settingsPath, sentinel });
876
+ }
877
+ }
878
+ function findHookCommand(node, signature) {
879
+ if (typeof node === "string") {
880
+ return node.includes(signature) ? node : null;
881
+ }
882
+ if (Array.isArray(node)) {
883
+ for (const value of node) {
884
+ const found = findHookCommand(value, signature);
885
+ if (found) {
886
+ return found;
887
+ }
888
+ }
889
+ return null;
890
+ }
891
+ if (node && typeof node === "object") {
892
+ for (const value of Object.values(node)) {
893
+ const found = findHookCommand(value, signature);
894
+ if (found) {
895
+ return found;
896
+ }
897
+ }
898
+ return null;
899
+ }
900
+ return null;
901
+ }
902
+ function hookResolvesCheck(settings, agent) {
903
+ const command = findHookCommand(settings, `hook-exec ${agent}`);
904
+ if (!command) {
905
+ return null;
906
+ }
907
+ const head = command.split(/\s+hook-exec\s+/)[0] ?? command;
908
+ const broken = head.split(/\s+/).filter((token) => token.startsWith("/")).filter((token) => !existsSync(token));
909
+ return {
910
+ name: "hook command resolves",
911
+ ok: broken.length === 0,
912
+ detail: broken.length === 0 ? "dg path in the hook resolves" : `hook references a missing path (${broken.join(", ")}); re-run 'dg agents on ${agent}'`
913
+ };
914
+ }
915
+ function mergedJsonHook(config) {
916
+ const legacy = config.legacySentinels ?? [];
917
+ return {
918
+ isInstalledCheckName: config.checkName,
919
+ async apply(ctx) {
920
+ const { settings, existed } = readSettings(ctx.settingsPath);
921
+ writeSettingsAtomic(ctx.settingsPath, config.insert(settings, ctx.dgCommand));
922
+ await recordHookEntry(ctx, legacy, !existed);
923
+ return { created: !existed };
924
+ },
925
+ async remove(ctx) {
926
+ let removed = false;
927
+ if (existsSync(ctx.settingsPath)) {
928
+ let settings = null;
929
+ try {
930
+ settings = readSettings(ctx.settingsPath).settings;
931
+ } catch {
932
+ settings = null;
933
+ }
934
+ if (settings) {
935
+ const result = config.remove(settings);
936
+ if (result.changed) {
937
+ removed = true;
938
+ if (result.empty && await wasCreatedByDg(ctx)) {
939
+ rmSync3(ctx.settingsPath, { force: true });
940
+ } else {
941
+ writeSettingsAtomic(ctx.settingsPath, result.settings);
942
+ }
943
+ }
944
+ }
945
+ }
946
+ await removeHookEntries(ctx, legacy);
947
+ return { removed };
948
+ },
949
+ verify(ctx) {
950
+ const checks = [];
951
+ const present = existsSync(ctx.settingsPath);
952
+ checks.push({ name: "settings file", ok: present, detail: present ? ctx.settingsPath : `${ctx.settingsPath} (absent)` });
953
+ if (!present) {
954
+ return checks;
955
+ }
956
+ let settings = null;
957
+ let installed = false;
958
+ try {
959
+ settings = readSettings(ctx.settingsPath).settings;
960
+ installed = config.isInstalled(settings);
961
+ } catch {
962
+ installed = false;
963
+ }
964
+ checks.push({ name: config.checkName, ok: installed, detail: installed ? "installed" : "not installed" });
965
+ if (installed && settings) {
966
+ const resolves = hookResolvesCheck(settings, ctx.agent);
967
+ if (resolves) {
968
+ checks.push(resolves);
969
+ }
970
+ }
971
+ return checks;
972
+ },
973
+ reverseEntry(entry, removed, missing, warnings) {
974
+ if (!existsSync(entry.path)) {
975
+ missing.push(entry.path);
976
+ return;
977
+ }
978
+ let settings;
979
+ try {
980
+ const parsed = JSON.parse(readFileSync3(entry.path, "utf8"));
981
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
982
+ warnings.push(`${entry.path}: not a JSON object; left untouched`);
983
+ return;
984
+ }
985
+ settings = parsed;
986
+ } catch {
987
+ warnings.push(`${entry.path}: unreadable JSON; left untouched`);
988
+ return;
989
+ }
990
+ const result = config.remove(settings);
991
+ if (!result.changed) {
992
+ missing.push(entry.path);
993
+ return;
994
+ }
995
+ if (result.empty && entry.original === "dg-created") {
996
+ rmSync3(entry.path, { force: true });
997
+ } else {
998
+ try {
999
+ writeSettingsAtomic(entry.path, result.settings);
1000
+ } catch (error) {
1001
+ warnings.push(`${entry.path}: ${error instanceof Error ? error.message : "could not rewrite settings"}`);
1002
+ return;
1003
+ }
1004
+ }
1005
+ removed.push(entry.path);
1006
+ }
1007
+ };
1008
+ }
1009
+ function ownedJsonHook(config) {
1010
+ const sentinel = agentHookSentinel(config.agent);
1011
+ const ownsFile = (path) => {
1012
+ try {
1013
+ const parsed = JSON.parse(readFileSync3(path, "utf8"));
1014
+ return parsed?.dgSentinel === sentinel;
1015
+ } catch {
1016
+ return false;
1017
+ }
1018
+ };
1019
+ return {
1020
+ isInstalledCheckName: config.checkName,
1021
+ async apply(ctx) {
1022
+ const existed = existsSync(ctx.settingsPath);
1023
+ if (existed && !ownsFile(ctx.settingsPath)) {
1024
+ throw new AgentHookError(`${ctx.settingsPath} already exists and was not written by dg; refusing to overwrite it. Merge the output of 'dg agents --print ${ctx.agent}' yourself, or remove the file and retry.`);
1025
+ }
1026
+ writeSettingsAtomic(ctx.settingsPath, { dgSentinel: sentinel, ...config.render(ctx.dgCommand) });
1027
+ await recordHookEntry(ctx, [], !existed);
1028
+ return { created: !existed };
1029
+ },
1030
+ async remove(ctx) {
1031
+ let removed = false;
1032
+ if (existsSync(ctx.settingsPath) && ownsFile(ctx.settingsPath)) {
1033
+ rmSync3(ctx.settingsPath, { force: true });
1034
+ removed = true;
1035
+ }
1036
+ await removeHookEntries(ctx, []);
1037
+ return { removed };
1038
+ },
1039
+ verify(ctx) {
1040
+ const checks = [];
1041
+ const present = existsSync(ctx.settingsPath);
1042
+ checks.push({ name: "hook file", ok: present, detail: present ? ctx.settingsPath : `${ctx.settingsPath} (absent)` });
1043
+ if (!present) {
1044
+ return checks;
1045
+ }
1046
+ const installed = ownsFile(ctx.settingsPath);
1047
+ checks.push({ name: config.checkName, ok: installed, detail: installed ? "installed" : "present but not dg-owned" });
1048
+ if (installed) {
1049
+ try {
1050
+ const settings = JSON.parse(readFileSync3(ctx.settingsPath, "utf8"));
1051
+ const resolves = hookResolvesCheck(settings, ctx.agent);
1052
+ if (resolves) {
1053
+ checks.push(resolves);
1054
+ }
1055
+ } catch {
1056
+ }
1057
+ }
1058
+ return checks;
1059
+ },
1060
+ reverseEntry(entry, removed, missing, warnings) {
1061
+ if (!existsSync(entry.path)) {
1062
+ missing.push(entry.path);
1063
+ return;
1064
+ }
1065
+ if (!ownsFile(entry.path)) {
1066
+ warnings.push(`${entry.path}: not dg-owned; left untouched`);
1067
+ return;
1068
+ }
1069
+ rmSync3(entry.path, { force: true });
1070
+ removed.push(entry.path);
1071
+ }
1072
+ };
1073
+ }
1074
+ function defaultExecVersion(binary, args) {
1075
+ try {
1076
+ const result = spawnSync(binary, [...args], { encoding: "utf8", timeout: 1500 });
1077
+ if (result.status !== 0 || typeof result.stdout !== "string") {
1078
+ return null;
1079
+ }
1080
+ return result.stdout.trim() || null;
1081
+ } catch {
1082
+ return null;
1083
+ }
1084
+ }
1085
+ function parseSemver(text) {
1086
+ const match = /(\d+)\.(\d+)(?:\.(\d+))?/.exec(text);
1087
+ if (!match) {
1088
+ return null;
1089
+ }
1090
+ return [Number(match[1]), Number(match[2]), Number(match[3] ?? "0")];
1091
+ }
1092
+ function probeMinCliVersion(binary, minVersion, label, deps) {
1093
+ const execVersion = deps?.execVersion ?? defaultExecVersion;
1094
+ const output = execVersion(binary, ["--version"]);
1095
+ if (!output) {
1096
+ return { supported: false, detail: `cannot confirm ${label} >= ${minVersion} (the ${binary} CLI did not report a version)` };
1097
+ }
1098
+ const found = parseSemver(output);
1099
+ const wanted = parseSemver(minVersion);
1100
+ if (!found || !wanted) {
1101
+ return { supported: false, detail: `cannot confirm ${label} >= ${minVersion} (unrecognized version '${output}')` };
1102
+ }
1103
+ for (let index = 0; index < 3; index += 1) {
1104
+ if ((found[index] ?? 0) > (wanted[index] ?? 0)) {
1105
+ break;
1106
+ }
1107
+ if ((found[index] ?? 0) < (wanted[index] ?? 0)) {
1108
+ return { supported: false, detail: `${label} ${found.join(".")} is older than ${minVersion}, which added the hook dg needs` };
1109
+ }
1110
+ }
1111
+ return { supported: true, detail: `${label} ${found.join(".")}` };
1112
+ }
1113
+
1114
+ // dist.next/agents/claude-code.js
1115
+ var SIGNATURE = "hook-exec claude-code";
1116
+ function configPath(home) {
1117
+ return join4(home, ".claude", "settings.json");
1118
+ }
1119
+ function isDgGroup(group) {
1120
+ if (typeof group !== "object" || group === null) {
1121
+ return false;
1122
+ }
1123
+ const hooks = group.hooks;
1124
+ if (!Array.isArray(hooks)) {
1125
+ return false;
1126
+ }
1127
+ return hooks.some((h) => typeof h === "object" && h !== null && typeof h.command === "string" && h.command.includes(SIGNATURE));
1128
+ }
1129
+ function dgGroup(dgCommand) {
1130
+ return { matcher: "Bash", hooks: [{ type: "command", command: dgCommand, timeout: 60 }] };
1131
+ }
1132
+ function insertDgHook(settings, dgCommand) {
1133
+ const next = { ...settings };
1134
+ const hooks = typeof next.hooks === "object" && next.hooks !== null ? { ...next.hooks } : {};
1135
+ const pre = Array.isArray(hooks.PreToolUse) ? hooks.PreToolUse : [];
1136
+ hooks.PreToolUse = [...pre.filter((g) => !isDgGroup(g)), dgGroup(dgCommand)];
1137
+ next.hooks = hooks;
1138
+ return next;
1139
+ }
1140
+ function removeDgHook(settings) {
1141
+ const next = { ...settings };
1142
+ if (typeof next.hooks !== "object" || next.hooks === null) {
1143
+ return { settings: next, changed: false, empty: Object.keys(next).length === 0 };
1144
+ }
1145
+ const hooks = { ...next.hooks };
1146
+ const pre = Array.isArray(hooks.PreToolUse) ? hooks.PreToolUse : [];
1147
+ const withoutDg = pre.filter((g) => !isDgGroup(g));
1148
+ const changed = withoutDg.length !== pre.length;
1149
+ if (withoutDg.length > 0) {
1150
+ hooks.PreToolUse = withoutDg;
1151
+ } else {
1152
+ delete hooks.PreToolUse;
1153
+ }
1154
+ if (Object.keys(hooks).length > 0) {
1155
+ next.hooks = hooks;
1156
+ } else {
1157
+ delete next.hooks;
1158
+ }
1159
+ return { settings: next, changed, empty: Object.keys(next).length === 0 };
1160
+ }
1161
+ function hasDgHook(settings) {
1162
+ const hooks = settings.hooks?.PreToolUse;
1163
+ return Array.isArray(hooks) && hooks.some((g) => isDgGroup(g));
1164
+ }
1165
+ function parseInput(stdin) {
1166
+ try {
1167
+ const obj = JSON.parse(stdin);
1168
+ const command = obj.tool_input?.command;
1169
+ if (typeof command !== "string") {
1170
+ return null;
1171
+ }
1172
+ return typeof obj.cwd === "string" ? { command, cwd: obj.cwd } : { command };
1173
+ } catch {
1174
+ return null;
1175
+ }
1176
+ }
1177
+ function emitDecision(verdict) {
1178
+ if (verdict.decision === "allow") {
1179
+ const note = verdict.screened ? formatScreenedNote(verdict.screened) : "";
1180
+ if (note) {
1181
+ return {
1182
+ stdout: JSON.stringify({
1183
+ hookSpecificOutput: { hookEventName: "PreToolUse", additionalContext: note }
1184
+ }),
1185
+ exitCode: 0
1186
+ };
1187
+ }
1188
+ return { stdout: "{}", exitCode: 0 };
1189
+ }
1190
+ return {
1191
+ stdout: JSON.stringify({
1192
+ hookSpecificOutput: {
1193
+ hookEventName: "PreToolUse",
1194
+ permissionDecision: verdict.decision,
1195
+ ...verdict.reason ? { permissionDecisionReason: verdict.reason } : {}
1196
+ }
1197
+ }),
1198
+ exitCode: 0
1199
+ };
1200
+ }
1201
+ var claudeCodeIntegration = {
1202
+ id: "claude-code",
1203
+ label: "Claude Code",
1204
+ kind: "merged-json",
1205
+ maturity: "verified",
1206
+ minVersion: null,
1207
+ configPath,
1208
+ detect: (home) => dirExists(join4(home, ".claude")),
1209
+ probeHookSupport: (home) => ({
1210
+ supported: true,
1211
+ detail: dirExists(join4(home, ".claude")) ? "Claude Code settings directory found" : "settings hooks are supported by every Claude Code version; ~/.claude will be created"
1212
+ }),
1213
+ parseInput,
1214
+ emitDecision,
1215
+ ...mergedJsonHook({
1216
+ checkName: "dg PreToolUse hook",
1217
+ legacySentinels: [LEGACY_AGENT_HOOK_SENTINEL],
1218
+ insert: insertDgHook,
1219
+ remove: removeDgHook,
1220
+ isInstalled: hasDgHook
1221
+ })
1222
+ };
1223
+
1224
+ // dist.next/agents/codex.js
1225
+ import { join as join5 } from "node:path";
1226
+ function configPath2(home) {
1227
+ return join5(home, ".codex", "hooks.json");
1228
+ }
1229
+ function parseInput2(stdin) {
1230
+ try {
1231
+ const obj = JSON.parse(stdin);
1232
+ const command = obj.tool_input?.command;
1233
+ if (typeof command !== "string") {
1234
+ return null;
1235
+ }
1236
+ return typeof obj.cwd === "string" ? { command, cwd: obj.cwd } : { command };
1237
+ } catch {
1238
+ return null;
1239
+ }
1240
+ }
1241
+ function emitDecision2(verdict) {
1242
+ if (verdict.decision === "allow") {
1243
+ return { stdout: "", exitCode: 0 };
1244
+ }
1245
+ const reason = verdict.reason ?? "Dependency Guardian firewall";
1246
+ const suffix = verdict.decision === "ask" ? " (dg flagged this for human review \u2014 not auto-approved)" : "";
1247
+ return {
1248
+ stdout: JSON.stringify({ decision: "block", reason: `${reason}${suffix}` }),
1249
+ exitCode: 0
1250
+ };
1251
+ }
1252
+ function renderHookFile(dgCommand) {
1253
+ return {
1254
+ hooks: {
1255
+ PreToolUse: [
1256
+ {
1257
+ matcher: "Bash",
1258
+ hooks: [{ type: "command", command: dgCommand, timeout: 60, statusMessage: "Dependency Guardian install check" }]
1259
+ }
1260
+ ]
1261
+ }
1262
+ };
1263
+ }
1264
+ function probeHookSupport(home, deps) {
1265
+ if (!dirExists(join5(home, ".codex"))) {
1266
+ return { supported: false, detail: "~/.codex not found (is Codex CLI installed?)" };
1267
+ }
1268
+ return probeMinCliVersion("codex", "0.124.0", "Codex CLI", deps);
1269
+ }
1270
+ var codexIntegration = {
1271
+ id: "codex",
1272
+ label: "Codex CLI",
1273
+ kind: "owned-json",
1274
+ maturity: "verified",
1275
+ minVersion: "0.124.0",
1276
+ postInstallNote: "Codex asks to trust new hooks: approve the dg hook when Codex prompts on its next start.",
1277
+ configPath: configPath2,
1278
+ detect: (home) => dirExists(join5(home, ".codex")),
1279
+ probeHookSupport,
1280
+ parseInput: parseInput2,
1281
+ emitDecision: emitDecision2,
1282
+ ...ownedJsonHook({
1283
+ agent: "codex",
1284
+ checkName: "dg PreToolUse hook",
1285
+ render: renderHookFile
1286
+ })
1287
+ };
1288
+
1289
+ // dist.next/agents/copilot-cli.js
1290
+ import { join as join6 } from "node:path";
1291
+ var SIGNATURE2 = "hook-exec copilot-cli";
1292
+ function configPath3(home) {
1293
+ return join6(home, ".copilot", "settings.json");
1294
+ }
1295
+ function isDgEntry(entry) {
1296
+ return typeof entry === "object" && entry !== null && typeof entry.command === "string" && entry.command.includes(SIGNATURE2);
1297
+ }
1298
+ function dgEntry(dgCommand) {
1299
+ return { type: "command", matcher: "bash", command: dgCommand, timeoutSec: 60 };
1300
+ }
1301
+ function insertDgHook2(settings, dgCommand) {
1302
+ const next = { ...settings };
1303
+ const hooks = typeof next.hooks === "object" && next.hooks !== null ? { ...next.hooks } : {};
1304
+ const pre = Array.isArray(hooks.preToolUse) ? hooks.preToolUse : [];
1305
+ hooks.preToolUse = [...pre.filter((e) => !isDgEntry(e)), dgEntry(dgCommand)];
1306
+ next.hooks = hooks;
1307
+ return next;
1308
+ }
1309
+ function removeDgHook2(settings) {
1310
+ const next = { ...settings };
1311
+ if (typeof next.hooks !== "object" || next.hooks === null) {
1312
+ return { settings: next, changed: false, empty: Object.keys(next).length === 0 };
1313
+ }
1314
+ const hooks = { ...next.hooks };
1315
+ const pre = Array.isArray(hooks.preToolUse) ? hooks.preToolUse : [];
1316
+ const withoutDg = pre.filter((e) => !isDgEntry(e));
1317
+ const changed = withoutDg.length !== pre.length;
1318
+ if (withoutDg.length > 0) {
1319
+ hooks.preToolUse = withoutDg;
1320
+ } else {
1321
+ delete hooks.preToolUse;
1322
+ }
1323
+ if (Object.keys(hooks).length > 0) {
1324
+ next.hooks = hooks;
1325
+ } else {
1326
+ delete next.hooks;
1327
+ }
1328
+ return { settings: next, changed, empty: Object.keys(next).length === 0 };
1329
+ }
1330
+ function hasDgHook2(settings) {
1331
+ const hooks = settings.hooks?.preToolUse;
1332
+ return Array.isArray(hooks) && hooks.some((e) => isDgEntry(e));
1333
+ }
1334
+ function toolArgsObject(raw) {
1335
+ if (typeof raw === "string") {
1336
+ try {
1337
+ const parsed = JSON.parse(raw);
1338
+ return typeof parsed === "object" && parsed !== null ? parsed : null;
1339
+ } catch {
1340
+ return null;
1341
+ }
1342
+ }
1343
+ return typeof raw === "object" && raw !== null ? raw : null;
1344
+ }
1345
+ function parseInput3(stdin) {
1346
+ try {
1347
+ const obj = JSON.parse(stdin);
1348
+ const args = toolArgsObject(obj.toolArgs);
1349
+ const command = args?.command;
1350
+ if (typeof command !== "string") {
1351
+ return null;
1352
+ }
1353
+ return typeof obj.cwd === "string" ? { command, cwd: obj.cwd } : { command };
1354
+ } catch {
1355
+ return null;
1356
+ }
1357
+ }
1358
+ function emitDecision3(verdict) {
1359
+ if (verdict.decision === "allow") {
1360
+ return { stdout: "{}", exitCode: 0 };
1361
+ }
1362
+ return {
1363
+ stdout: JSON.stringify({
1364
+ permissionDecision: verdict.decision,
1365
+ ...verdict.reason ? { permissionDecisionReason: verdict.reason } : {}
1366
+ }),
1367
+ exitCode: 0
1368
+ };
1369
+ }
1370
+ function probeHookSupport2(home, deps) {
1371
+ if (!dirExists(join6(home, ".copilot"))) {
1372
+ return { supported: false, detail: "~/.copilot not found (is GitHub Copilot CLI installed?)" };
1373
+ }
1374
+ return probeMinCliVersion("copilot", "1.0.61", "GitHub Copilot CLI", deps);
1375
+ }
1376
+ var copilotCliIntegration = {
1377
+ id: "copilot-cli",
1378
+ label: "GitHub Copilot CLI",
1379
+ kind: "merged-json",
1380
+ maturity: "verified",
1381
+ minVersion: "1.0.61",
1382
+ configPath: configPath3,
1383
+ detect: (home) => dirExists(join6(home, ".copilot")),
1384
+ probeHookSupport: probeHookSupport2,
1385
+ parseInput: parseInput3,
1386
+ emitDecision: emitDecision3,
1387
+ ...mergedJsonHook({
1388
+ checkName: "dg preToolUse hook",
1389
+ insert: insertDgHook2,
1390
+ remove: removeDgHook2,
1391
+ isInstalled: hasDgHook2
1392
+ })
1393
+ };
1394
+
1395
+ // dist.next/agents/cursor.js
1396
+ import { join as join7 } from "node:path";
1397
+ var SIGNATURE3 = "hook-exec cursor";
1398
+ function configPath4(home) {
1399
+ return join7(home, ".cursor", "hooks.json");
1400
+ }
1401
+ function isDgEntry2(entry) {
1402
+ return typeof entry === "object" && entry !== null && typeof entry.command === "string" && entry.command.includes(SIGNATURE3);
1403
+ }
1404
+ function hookList(settings) {
1405
+ const hooks = settings.hooks;
1406
+ if (typeof hooks !== "object" || hooks === null) {
1407
+ return [];
1408
+ }
1409
+ const list = hooks.beforeShellExecution;
1410
+ return Array.isArray(list) ? list : [];
1411
+ }
1412
+ function insertHook(settings, dgCommand) {
1413
+ const next = { ...settings };
1414
+ const hooks = typeof next.hooks === "object" && next.hooks !== null ? { ...next.hooks } : {};
1415
+ const list = Array.isArray(hooks.beforeShellExecution) ? hooks.beforeShellExecution : [];
1416
+ hooks.beforeShellExecution = [...list.filter((entry) => !isDgEntry2(entry)), { command: dgCommand }];
1417
+ next.hooks = hooks;
1418
+ if (next.version === void 0) {
1419
+ next.version = 1;
1420
+ }
1421
+ return next;
1422
+ }
1423
+ function effectivelyEmpty(obj) {
1424
+ const keys = Object.keys(obj);
1425
+ return keys.length === 0 || keys.length === 1 && keys[0] === "version";
1426
+ }
1427
+ function removeHook(settings) {
1428
+ const next = { ...settings };
1429
+ if (typeof next.hooks !== "object" || next.hooks === null) {
1430
+ return { settings: next, changed: false, empty: effectivelyEmpty(next) };
1431
+ }
1432
+ const hooks = { ...next.hooks };
1433
+ const list = Array.isArray(hooks.beforeShellExecution) ? hooks.beforeShellExecution : [];
1434
+ const withoutDg = list.filter((entry) => !isDgEntry2(entry));
1435
+ const changed = withoutDg.length !== list.length;
1436
+ if (withoutDg.length > 0) {
1437
+ hooks.beforeShellExecution = withoutDg;
1438
+ } else {
1439
+ delete hooks.beforeShellExecution;
1440
+ }
1441
+ if (Object.keys(hooks).length > 0) {
1442
+ next.hooks = hooks;
1443
+ } else {
1444
+ delete next.hooks;
1445
+ }
1446
+ return { settings: next, changed, empty: effectivelyEmpty(next) };
1447
+ }
1448
+ function hasDgHook3(settings) {
1449
+ return hookList(settings).some((entry) => isDgEntry2(entry));
1450
+ }
1451
+ function parseInput4(stdin) {
1452
+ try {
1453
+ const obj = JSON.parse(stdin);
1454
+ if (typeof obj.command !== "string") {
1455
+ return null;
1456
+ }
1457
+ return typeof obj.cwd === "string" ? { command: obj.command, cwd: obj.cwd } : { command: obj.command };
1458
+ } catch {
1459
+ return null;
1460
+ }
1461
+ }
1462
+ function emitDecision4(verdict) {
1463
+ if (verdict.decision === "allow") {
1464
+ const note = verdict.screened ? formatScreenedNote(verdict.screened) : "";
1465
+ return {
1466
+ stdout: JSON.stringify(note ? { permission: "allow", agent_message: note } : { permission: "allow" }),
1467
+ exitCode: 0
1468
+ };
1469
+ }
1470
+ const reason = verdict.reason ?? "Dependency Guardian firewall";
1471
+ return {
1472
+ stdout: JSON.stringify({ permission: verdict.decision, user_message: reason, agent_message: reason }),
1473
+ exitCode: 0
1474
+ };
1475
+ }
1476
+ function probeHookSupport3(home) {
1477
+ if (!dirExists(join7(home, ".cursor"))) {
1478
+ return { supported: false, detail: "~/.cursor not found (is Cursor installed?)" };
1479
+ }
1480
+ try {
1481
+ readSettings(configPath4(home));
1482
+ } catch {
1483
+ return { supported: false, detail: `${configPath4(home)} exists but is not a JSON object dg can merge into` };
1484
+ }
1485
+ return { supported: true, detail: "requires Cursor 1.7+; dg cannot read your Cursor version from disk" };
1486
+ }
1487
+ var cursorIntegration = {
1488
+ id: "cursor",
1489
+ label: "Cursor",
1490
+ kind: "merged-json",
1491
+ maturity: "verified",
1492
+ minVersion: "1.7",
1493
+ configPath: configPath4,
1494
+ detect: (home) => dirExists(join7(home, ".cursor")),
1495
+ probeHookSupport: probeHookSupport3,
1496
+ parseInput: parseInput4,
1497
+ emitDecision: emitDecision4,
1498
+ ...mergedJsonHook({
1499
+ checkName: "dg beforeShellExecution hook",
1500
+ insert: insertHook,
1501
+ remove: removeHook,
1502
+ isInstalled: hasDgHook3
1503
+ })
1504
+ };
1505
+
1506
+ // dist.next/agents/gemini.js
1507
+ import { join as join8 } from "node:path";
1508
+ var SIGNATURE4 = "hook-exec gemini";
1509
+ function configPath5(home) {
1510
+ return join8(home, ".gemini", "settings.json");
1511
+ }
1512
+ function isDgGroup2(group) {
1513
+ if (typeof group !== "object" || group === null) {
1514
+ return false;
1515
+ }
1516
+ const hooks = group.hooks;
1517
+ if (!Array.isArray(hooks)) {
1518
+ return false;
1519
+ }
1520
+ return hooks.some((h) => typeof h === "object" && h !== null && typeof h.command === "string" && h.command.includes(SIGNATURE4));
1521
+ }
1522
+ function dgGroup2(dgCommand) {
1523
+ return { matcher: "run_shell_command", hooks: [{ type: "command", command: dgCommand }] };
1524
+ }
1525
+ function insertHook2(settings, dgCommand) {
1526
+ const next = { ...settings };
1527
+ const hooks = typeof next.hooks === "object" && next.hooks !== null ? { ...next.hooks } : {};
1528
+ const pre = Array.isArray(hooks.BeforeTool) ? hooks.BeforeTool : [];
1529
+ hooks.BeforeTool = [...pre.filter((g) => !isDgGroup2(g)), dgGroup2(dgCommand)];
1530
+ next.hooks = hooks;
1531
+ return next;
1532
+ }
1533
+ function removeHook2(settings) {
1534
+ const next = { ...settings };
1535
+ if (typeof next.hooks !== "object" || next.hooks === null) {
1536
+ return { settings: next, changed: false, empty: Object.keys(next).length === 0 };
1537
+ }
1538
+ const hooks = { ...next.hooks };
1539
+ const pre = Array.isArray(hooks.BeforeTool) ? hooks.BeforeTool : [];
1540
+ const withoutDg = pre.filter((g) => !isDgGroup2(g));
1541
+ const changed = withoutDg.length !== pre.length;
1542
+ if (withoutDg.length > 0) {
1543
+ hooks.BeforeTool = withoutDg;
1544
+ } else {
1545
+ delete hooks.BeforeTool;
1546
+ }
1547
+ if (Object.keys(hooks).length > 0) {
1548
+ next.hooks = hooks;
1549
+ } else {
1550
+ delete next.hooks;
1551
+ }
1552
+ return { settings: next, changed, empty: Object.keys(next).length === 0 };
1553
+ }
1554
+ function hasDgHook4(settings) {
1555
+ const hooks = settings.hooks?.BeforeTool;
1556
+ return Array.isArray(hooks) && hooks.some((g) => isDgGroup2(g));
1557
+ }
1558
+ function parseInput5(stdin) {
1559
+ try {
1560
+ const obj = JSON.parse(stdin);
1561
+ const command = obj.tool_args?.command ?? obj.tool_input?.command;
1562
+ if (typeof command !== "string") {
1563
+ return null;
1564
+ }
1565
+ return typeof obj.cwd === "string" ? { command, cwd: obj.cwd } : { command };
1566
+ } catch {
1567
+ return null;
1568
+ }
1569
+ }
1570
+ function emitDecision5(verdict) {
1571
+ if (verdict.decision === "allow") {
1572
+ return { stdout: "{}", exitCode: 0 };
1573
+ }
1574
+ const reason = verdict.reason ?? "Dependency Guardian firewall";
1575
+ return {
1576
+ stdout: JSON.stringify({ decision: "block", reason }),
1577
+ exitCode: 0
1578
+ };
1579
+ }
1580
+ function probeHookSupport4(home, deps) {
1581
+ if (!dirExists(join8(home, ".gemini"))) {
1582
+ return { supported: false, detail: "~/.gemini not found (is Gemini CLI installed?)" };
1583
+ }
1584
+ return probeMinCliVersion("gemini", "0.26.0", "Gemini CLI", deps);
1585
+ }
1586
+ var geminiIntegration = {
1587
+ id: "gemini",
1588
+ label: "Gemini CLI",
1589
+ kind: "merged-json",
1590
+ maturity: "verified",
1591
+ minVersion: "0.26.0",
1592
+ configPath: configPath5,
1593
+ detect: (home) => dirExists(join8(home, ".gemini")),
1594
+ probeHookSupport: probeHookSupport4,
1595
+ parseInput: parseInput5,
1596
+ emitDecision: emitDecision5,
1597
+ ...mergedJsonHook({
1598
+ checkName: "dg BeforeTool hook",
1599
+ insert: insertHook2,
1600
+ remove: removeHook2,
1601
+ isInstalled: hasDgHook4
1602
+ })
1603
+ };
1604
+
1605
+ // dist.next/agents/windsurf.js
1606
+ import { join as join9 } from "node:path";
1607
+ var SIGNATURE5 = "hook-exec windsurf";
1608
+ function configPath6(home) {
1609
+ return join9(home, ".codeium", "windsurf", "hooks.json");
1610
+ }
1611
+ function isDgEntry3(entry) {
1612
+ return typeof entry === "object" && entry !== null && typeof entry.command === "string" && entry.command.includes(SIGNATURE5);
1613
+ }
1614
+ function insertHook3(settings, dgCommand) {
1615
+ const next = { ...settings };
1616
+ const hooks = typeof next.hooks === "object" && next.hooks !== null ? { ...next.hooks } : {};
1617
+ const list = Array.isArray(hooks.pre_run_command) ? hooks.pre_run_command : [];
1618
+ hooks.pre_run_command = [...list.filter((entry) => !isDgEntry3(entry)), { command: dgCommand }];
1619
+ next.hooks = hooks;
1620
+ return next;
1621
+ }
1622
+ function removeHook3(settings) {
1623
+ const next = { ...settings };
1624
+ if (typeof next.hooks !== "object" || next.hooks === null) {
1625
+ return { settings: next, changed: false, empty: Object.keys(next).length === 0 };
1626
+ }
1627
+ const hooks = { ...next.hooks };
1628
+ const list = Array.isArray(hooks.pre_run_command) ? hooks.pre_run_command : [];
1629
+ const withoutDg = list.filter((entry) => !isDgEntry3(entry));
1630
+ const changed = withoutDg.length !== list.length;
1631
+ if (withoutDg.length > 0) {
1632
+ hooks.pre_run_command = withoutDg;
1633
+ } else {
1634
+ delete hooks.pre_run_command;
1635
+ }
1636
+ if (Object.keys(hooks).length > 0) {
1637
+ next.hooks = hooks;
1638
+ } else {
1639
+ delete next.hooks;
1640
+ }
1641
+ return { settings: next, changed, empty: Object.keys(next).length === 0 };
1642
+ }
1643
+ function hasDgHook5(settings) {
1644
+ const hooks = settings.hooks?.pre_run_command;
1645
+ return Array.isArray(hooks) && hooks.some((entry) => isDgEntry3(entry));
1646
+ }
1647
+ function parseInput6(stdin) {
1648
+ try {
1649
+ const obj = JSON.parse(stdin);
1650
+ const command = obj.tool_info?.command_line;
1651
+ if (typeof command !== "string") {
1652
+ return null;
1653
+ }
1654
+ const cwd = obj.tool_info?.cwd;
1655
+ return typeof cwd === "string" ? { command, cwd } : { command };
1656
+ } catch {
1657
+ return null;
1658
+ }
1659
+ }
1660
+ function emitDecision6(verdict) {
1661
+ if (verdict.decision === "allow") {
1662
+ return { stdout: "", exitCode: 0 };
1663
+ }
1664
+ const reason = verdict.reason ?? "Dependency Guardian firewall";
1665
+ const suffix = verdict.decision === "ask" ? " (dg flagged this for human review \u2014 not auto-approved)" : "";
1666
+ return { stdout: `${reason}${suffix}
1667
+ `, exitCode: 2 };
1668
+ }
1669
+ function probeHookSupport5(home) {
1670
+ if (!dirExists(join9(home, ".codeium", "windsurf"))) {
1671
+ return { supported: false, detail: "~/.codeium/windsurf not found (is Windsurf installed?)" };
1672
+ }
1673
+ return { supported: true, detail: "Windsurf config directory found; dg cannot read the app version from disk" };
1674
+ }
1675
+ var windsurfIntegration = {
1676
+ id: "windsurf",
1677
+ label: "Windsurf",
1678
+ kind: "merged-json",
1679
+ maturity: "unverified",
1680
+ minVersion: null,
1681
+ configPath: configPath6,
1682
+ detect: (home) => dirExists(join9(home, ".codeium", "windsurf")),
1683
+ probeHookSupport: probeHookSupport5,
1684
+ parseInput: parseInput6,
1685
+ emitDecision: emitDecision6,
1686
+ ...mergedJsonHook({
1687
+ checkName: "dg pre_run_command hook",
1688
+ insert: insertHook3,
1689
+ remove: removeHook3,
1690
+ isInstalled: hasDgHook5
1691
+ })
1692
+ };
1693
+
1694
+ // dist.next/agents/registry.js
1695
+ var AGENTS = {
1696
+ "claude-code": claudeCodeIntegration,
1697
+ codex: codexIntegration,
1698
+ cursor: cursorIntegration,
1699
+ "copilot-cli": copilotCliIntegration,
1700
+ gemini: geminiIntegration,
1701
+ windsurf: windsurfIntegration
1702
+ };
1703
+ var AGENT_IDS = Object.keys(AGENTS);
1704
+ function isAgentId(value) {
1705
+ return value in AGENTS;
1706
+ }
1707
+ function agentFromSentinel(sentinel) {
1708
+ if (!sentinel || sentinel === LEGACY_AGENT_HOOK_SENTINEL) {
1709
+ return "claude-code";
1710
+ }
1711
+ if (!sentinel.startsWith(`${LEGACY_AGENT_HOOK_SENTINEL}:`)) {
1712
+ return null;
1713
+ }
1714
+ const id = sentinel.slice(LEGACY_AGENT_HOOK_SENTINEL.length + 1);
1715
+ return isAgentId(id) ? id : null;
1716
+ }
1717
+ function reverseAgentHookEntry(entry, removed, missing, warnings) {
1718
+ const agent = agentFromSentinel(entry.sentinel);
1719
+ if (!agent) {
1720
+ warnings.push(`${entry.path}: unrecognized agent hook entry (${entry.sentinel ?? "no sentinel"}); left untouched`);
1721
+ return;
1722
+ }
1723
+ AGENTS[agent].reverseEntry(entry, removed, missing, warnings);
1724
+ }
1725
+
1726
+ // dist.next/agents/gate-posture.js
1727
+ init_state2();
1728
+
1729
+ // dist.next/setup/plan.js
1730
+ init_state();
1731
+
1732
+ // dist.next/runtime/node-version.js
1733
+ var MINIMUM_NODE = Object.freeze({
1734
+ major: 22,
1735
+ minor: 14,
1736
+ patch: 0
1737
+ });
1738
+
1739
+ // dist.next/setup/plan.js
1740
+ init_settings();
1741
+ init_resolve_real_binary();
1742
+ init_state2();
1743
+ var SHIM_COMMANDS = Object.freeze(["npm", "npx", "pnpm", "pnpx", "yarn", "pip", "pip3", "pipx", "uv", "uvx", "cargo"]);
1744
+ var SHIM_SENTINEL = "dg-shim-v1";
1745
+ var RC_SENTINEL = "dg-shell-rc-v1";
1746
+ var RC_SHIM_HELPER = "__dg_shim";
1747
+ var GUARD_HOOK_SENTINEL = "dg-git-hook-v1";
1748
+ var RC_BEGIN = "# >>> dg setup >>>";
1749
+ var RC_END = "# <<< dg setup <<<";
1750
+ var LEGACY_RC_MARKERS = [
1751
+ { begin: "# >>> dg-managed >>>", end: "# <<< dg-managed <<<" }
1752
+ ];
1753
+ var LEGACY_RC_CANDIDATES = [".zshrc", ".bashrc", ".bash_profile", ".profile", join10(".config", "fish", "config.fish")];
1754
+ var LEGACY_PYTHON_HOOK_PY = "dg_pip_hook.py";
1755
+ var LEGACY_PYTHON_HOOK_PTH = "dg_pip_hook.pth";
1756
+ var LEGACY_PYTHON_HOOK_MARKER = "Dependency Guardian pip-install interceptor";
1757
+ var LEGACY_PYTHON_HOOK_PTH_MARKER = "import dg_pip_hook";
1758
+ var SETUP_UNINSTALL_LOCK = "setup-uninstall";
1759
+ var SETUP_UNINSTALL_LOCK_STALE_MS = 30 * 60 * 1e3;
1760
+ var STALE_SESSION_OLDER_THAN_MS = 24 * 60 * 60 * 1e3;
1761
+ function uninstallSetup(options) {
1762
+ const paths = resolveDgPaths(options.env ?? process.env);
1763
+ const hadCacheDirBeforeLock = existsSync2(paths.cacheDir);
1764
+ const hadStateDirBeforeLock = existsSync2(paths.stateDir);
1765
+ const lock = acquireLockSync(paths, SETUP_UNINSTALL_LOCK, {
1766
+ staleMs: SETUP_UNINSTALL_LOCK_STALE_MS
1767
+ });
1768
+ try {
1769
+ const registryRead = readRegistry(paths);
1770
+ const removed = [];
1771
+ const missing = [];
1772
+ const warnings = [];
1773
+ const staleSessions = sweepStaleSessionsSync(paths, {
1774
+ olderThanMs: STALE_SESSION_OLDER_THAN_MS
1775
+ }).removed;
1776
+ if (registryRead.malformed) {
1777
+ warnings.push(registryRead.preservedPath ? `cleanup registry was malformed: ${paths.cleanupRegistryPath} (preserved at ${registryRead.preservedPath})` : `cleanup registry is malformed: ${paths.cleanupRegistryPath}`);
1778
+ }
1779
+ for (const entry of registryRead.registry.entries) {
1780
+ if (entry.owner !== "dg") {
1781
+ continue;
1782
+ }
1783
+ if (entry.kind === "shim") {
1784
+ removeShim(entry, removed, missing, warnings);
1785
+ } else if (entry.kind === "rc") {
1786
+ removeRcBlock(entry, removed, missing, warnings);
1787
+ } else if (entry.kind === "git-hook") {
1788
+ reverseGitHookEntry(entry, removed, missing, warnings);
1789
+ } else if (entry.kind === "agent-hook") {
1790
+ reverseAgentHookEntry(entry, removed, missing, warnings);
1791
+ }
1792
+ }
1793
+ sweepLegacyRcBlocks(paths.homeDir, removed, warnings);
1794
+ sweepLegacyPythonHooks(paths.homeDir, removed, warnings);
1795
+ if (!options.all && !registryRead.malformed && options.keepConfig) {
1796
+ writeRegistryWithLock(paths, {
1797
+ version: 1,
1798
+ entries: registryRead.registry.entries.filter((entry) => entry.owner !== "dg")
1799
+ });
1800
+ }
1801
+ if (!options.keepConfig && hadCacheDirBeforeLock) {
1802
+ removeDirectory(paths.cacheDir, removed, missing);
1803
+ }
1804
+ if (!options.keepConfig && hadStateDirBeforeLock) {
1805
+ removeDirectory(paths.stateDir, removed, missing);
1806
+ }
1807
+ if (options.all) {
1808
+ removeDirectory(paths.configDir, removed, missing);
1809
+ }
1810
+ return {
1811
+ removed,
1812
+ missing,
1813
+ warnings,
1814
+ staleSessions
1815
+ };
1816
+ } finally {
1817
+ lock.release();
1818
+ }
1819
+ }
1820
+ function writeRcFileAtomic(rcPath, content) {
1821
+ let target = rcPath;
1822
+ let mode = 420;
1823
+ try {
1824
+ target = realpathSync(rcPath);
1825
+ mode = statSync3(target).mode & 4095;
1826
+ } catch {
1827
+ }
1828
+ const tempPath = join10(dirname3(target), `.${basename(target)}.dg-${randomBytes2(6).toString("hex")}.tmp`);
1829
+ writeFileSync3(tempPath, content, { encoding: "utf8", mode, flag: "wx" });
1830
+ try {
1831
+ renameSync4(tempPath, target);
1832
+ } catch (error) {
1833
+ rmSync4(tempPath, { force: true });
1834
+ throw error;
1835
+ }
1836
+ }
1837
+ function stripRcBlockDetailed(existing) {
1838
+ let content = existing.replace(rcPairPattern(RC_BEGIN, RC_END), "");
1839
+ const repairedLines = [];
1840
+ for (; ; ) {
1841
+ const lines = content.split("\n");
1842
+ const begin = lines.indexOf(RC_BEGIN);
1843
+ if (begin === -1) {
1844
+ break;
1845
+ }
1846
+ let end = begin;
1847
+ while (end + 1 < lines.length && isDgWrittenRcLine(lines[end + 1] ?? "")) {
1848
+ end += 1;
1849
+ }
1850
+ repairedLines.push(begin === end ? `line ${begin + 1}` : `lines ${begin + 1}-${end + 1}`);
1851
+ lines.splice(begin, end - begin + 1);
1852
+ content = lines.join("\n");
1853
+ }
1854
+ return { content, repairedLines };
1855
+ }
1856
+ function rcPairPattern(begin, end) {
1857
+ return new RegExp(`${escapeRegex(begin)}\\n(?:(?!${escapeRegex(begin)})[\\s\\S])*?${escapeRegex(end)}\\n?`, "g");
1858
+ }
1859
+ function isDgWrittenRcLine(line) {
1860
+ return line === RC_END || line.startsWith("# dg-") || line.includes(RC_SHIM_HELPER) || line.includes(`${sep}.dg${sep}shims`);
1861
+ }
1862
+ function sweepLegacyRcBlocks(homeDir, removed, warnings) {
1863
+ for (const rel of LEGACY_RC_CANDIDATES) {
1864
+ const rcPath = join10(homeDir, rel);
1865
+ const existing = readText(rcPath);
1866
+ if (!existing) {
1867
+ continue;
1868
+ }
1869
+ let next = existing;
1870
+ for (const marker of LEGACY_RC_MARKERS) {
1871
+ if (!next.includes(marker.begin)) {
1872
+ continue;
1873
+ }
1874
+ if (!next.includes(marker.end)) {
1875
+ warnings.push(`legacy dg block in ${rcPath} is missing its end marker; left untouched`);
1876
+ continue;
1877
+ }
1878
+ next = next.replace(rcPairPattern(marker.begin, marker.end), "");
1879
+ }
1880
+ if (next === existing) {
1881
+ continue;
1882
+ }
1883
+ try {
1884
+ writeRcFileAtomic(rcPath, next);
1885
+ removed.push(`${rcPath} (legacy dg block)`);
1886
+ } catch (error) {
1887
+ warnings.push(`could not strip legacy dg block from ${rcPath}: ${error instanceof Error ? error.message : "write error"}`);
1888
+ }
1889
+ }
1890
+ }
1891
+ function isLegacyPthHook(pthPath) {
1892
+ const content = readText(pthPath);
1893
+ return content.includes(LEGACY_PYTHON_HOOK_PTH_MARKER) || content.includes(LEGACY_PYTHON_HOOK_MARKER);
1894
+ }
1895
+ function sweepLegacyPythonHooks(homeDir, removed, warnings) {
1896
+ for (const dir of candidateSitePackagesDirs(homeDir)) {
1897
+ const pyPath = join10(dir, LEGACY_PYTHON_HOOK_PY);
1898
+ const pthPath = join10(dir, LEGACY_PYTHON_HOOK_PTH);
1899
+ const pyIsHook = readText(pyPath).includes(LEGACY_PYTHON_HOOK_MARKER);
1900
+ const pthIsHook = isLegacyPthHook(pthPath);
1901
+ if (!pyIsHook && !pthIsHook) {
1902
+ continue;
1903
+ }
1904
+ if (pthIsHook) {
1905
+ removePythonHookFile(pthPath, removed, warnings);
1906
+ }
1907
+ if (pyIsHook) {
1908
+ removePythonHookFile(pyPath, removed, warnings);
1909
+ }
1910
+ }
1911
+ }
1912
+ function removePythonHookFile(path, removed, warnings) {
1913
+ try {
1914
+ rmSync4(path, { force: true });
1915
+ removed.push(`${path} (legacy dg pip hook)`);
1916
+ } catch (error) {
1917
+ warnings.push(`could not remove legacy dg pip hook ${path}: ${error instanceof Error ? error.message : "remove error"}`);
1918
+ }
1919
+ }
1920
+ function candidateSitePackagesDirs(homeDir) {
1921
+ const dirs = [];
1922
+ for (const version of safeReaddir(join10(homeDir, "Library", "Python"))) {
1923
+ dirs.push(join10(homeDir, "Library", "Python", version, "lib", "python", "site-packages"));
1924
+ }
1925
+ for (const entry of safeReaddir(join10(homeDir, ".local", "lib"))) {
1926
+ if (entry.startsWith("python")) {
1927
+ dirs.push(join10(homeDir, ".local", "lib", entry, "site-packages"));
1928
+ }
1929
+ }
1930
+ return dirs;
1931
+ }
1932
+ function safeReaddir(dir) {
1933
+ try {
1934
+ return readdirSync2(dir);
1935
+ } catch {
1936
+ return [];
1937
+ }
1938
+ }
1939
+ function readRegistry(paths) {
1940
+ try {
1941
+ if (!existsSync2(paths.cleanupRegistryPath)) {
1942
+ return {
1943
+ registry: {
1944
+ version: 1,
1945
+ entries: []
1946
+ },
1947
+ malformed: false
1948
+ };
1949
+ }
1950
+ const registry = JSON.parse(readFileSync4(paths.cleanupRegistryPath, "utf8"));
1951
+ if (registry.version !== 1 || !Array.isArray(registry.entries)) {
1952
+ throw new Error("unsupported cleanup registry");
1953
+ }
1954
+ return {
1955
+ registry,
1956
+ malformed: false
1957
+ };
1958
+ } catch {
1959
+ const preservedPath = preserveCorruptCleanupRegistrySync(paths);
1960
+ return {
1961
+ registry: {
1962
+ version: 1,
1963
+ entries: []
1964
+ },
1965
+ malformed: true,
1966
+ ...preservedPath ? { preservedPath } : {}
1967
+ };
1968
+ }
1969
+ }
1970
+ function writeRegistry(paths, registry) {
1971
+ mkdirSync4(dirname3(paths.cleanupRegistryPath), {
1972
+ recursive: true,
1973
+ mode: 448
1974
+ });
1975
+ const tempPath = `${paths.cleanupRegistryPath}.${randomBytes2(6).toString("hex")}.tmp`;
1976
+ writeFileSync3(tempPath, `${JSON.stringify(registry, null, 2)}
1977
+ `, {
1978
+ encoding: "utf8",
1979
+ mode: 384,
1980
+ flag: "wx"
1981
+ });
1982
+ try {
1983
+ renameSync4(tempPath, paths.cleanupRegistryPath);
1984
+ } catch (error) {
1985
+ rmSync4(tempPath, { force: true });
1986
+ throw error;
1987
+ }
1988
+ }
1989
+ function withRegistryLock(paths, action) {
1990
+ const lock = acquireLockSync(paths, CLEANUP_REGISTRY_LOCK, {
1991
+ staleMs: SETUP_UNINSTALL_LOCK_STALE_MS
1992
+ });
1993
+ try {
1994
+ return action();
1995
+ } finally {
1996
+ lock.release();
1997
+ }
1998
+ }
1999
+ function writeRegistryWithLock(paths, registry) {
2000
+ withRegistryLock(paths, () => writeRegistry(paths, registry));
2001
+ }
2002
+ function removeShim(entry, removed, missing, warnings) {
2003
+ if (!existsSync2(entry.path)) {
2004
+ missing.push(entry.path);
2005
+ return;
2006
+ }
2007
+ if (!validShim(entry.path, basename(entry.path))) {
2008
+ warnings.push(`refused to remove drifted shim: ${entry.path}`);
2009
+ return;
2010
+ }
2011
+ rmSync4(entry.path, {
2012
+ force: true
2013
+ });
2014
+ removed.push(entry.path);
2015
+ }
2016
+ function removeRcBlock(entry, removed, missing, warnings) {
2017
+ const existing = readText(entry.path);
2018
+ if (!existing) {
2019
+ missing.push(entry.path);
2020
+ return;
2021
+ }
2022
+ if (!existing.includes(RC_SENTINEL)) {
2023
+ warnings.push(`refused to edit shell rc without dg sentinel: ${entry.path}`);
2024
+ return;
2025
+ }
2026
+ const stripped = stripRcBlockDetailed(existing);
2027
+ try {
2028
+ writeRcFileAtomic(entry.path, stripped.content);
2029
+ } catch (error) {
2030
+ warnings.push(`could not rewrite shell rc ${entry.path}: ${error instanceof Error ? error.message : "write error"}`);
2031
+ return;
2032
+ }
2033
+ if (stripped.repairedLines.length > 0) {
2034
+ warnings.push(`repaired an unterminated dg block in ${entry.path}: removed only dg-written lines (${stripped.repairedLines.join(", ")})`);
2035
+ }
2036
+ removed.push(entry.path);
2037
+ }
2038
+ function reverseGitHookEntry(entry, removed, missing, warnings) {
2039
+ const sentinel = entry.sentinel ?? GUARD_HOOK_SENTINEL;
2040
+ let ownsTarget = false;
2041
+ if (!existsSync2(entry.path)) {
2042
+ missing.push(entry.path);
2043
+ ownsTarget = true;
2044
+ } else if (readText(entry.path).split("\n", 2)[1]?.includes(sentinel)) {
2045
+ rmSync4(entry.path, { force: true });
2046
+ removed.push(entry.path);
2047
+ ownsTarget = true;
2048
+ } else {
2049
+ warnings.push(`refused to remove git hook without dg sentinel: ${entry.path}`);
2050
+ }
2051
+ if (!ownsTarget) {
2052
+ return;
2053
+ }
2054
+ if (entry.original) {
2055
+ if (existsSync2(entry.original)) {
2056
+ try {
2057
+ renameSync4(entry.original, entry.path);
2058
+ removed.push(entry.original);
2059
+ } catch (error) {
2060
+ warnings.push(`could not restore chained hook ${entry.original}: ${error instanceof Error ? error.message : "unknown error"}`);
2061
+ }
2062
+ } else {
2063
+ missing.push(entry.original);
2064
+ }
2065
+ }
2066
+ }
2067
+ function removeDirectory(path, removed, missing) {
2068
+ if (!existsSync2(path)) {
2069
+ missing.push(path);
2070
+ return;
2071
+ }
2072
+ rmSync4(path, {
2073
+ force: true,
2074
+ recursive: true
2075
+ });
2076
+ removed.push(path);
2077
+ }
2078
+ function validShim(path, command) {
2079
+ if (!existsSync2(path)) {
2080
+ return false;
2081
+ }
2082
+ return isValidShimSource(readText(path), command);
2083
+ }
2084
+ function isValidShimSource(content, command) {
2085
+ if (!content.includes(SHIM_SENTINEL)) {
2086
+ return false;
2087
+ }
2088
+ return content.includes("DG_SHIM_ACTIVE=") && content.includes('exec "') && content.includes(`" ${command} "$@"`);
2089
+ }
2090
+ function readText(path) {
2091
+ try {
2092
+ return readFileSync4(path, "utf8");
2093
+ } catch {
2094
+ return "";
2095
+ }
2096
+ }
2097
+ function escapeRegex(value) {
2098
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2099
+ }
2100
+
2101
+ // dist.next/setup/uninstall-standalone.js
2102
+ init_state();
2103
+ function run() {
2104
+ const quiet = process.argv.includes("--quiet");
2105
+ try {
2106
+ const result = uninstallSetup({ keepConfig: false, all: true });
2107
+ if (!quiet) {
2108
+ process.stderr.write(`Dependency Guardian cleaned up ${result.removed.length} leftover item(s) after the package was removed.
2109
+ `);
2110
+ }
2111
+ } catch (error) {
2112
+ if (!quiet && !(error instanceof LockBusyError)) {
2113
+ process.stderr.write(`dg self-cleanup could not finish: ${error.message}
2114
+ `);
2115
+ }
2116
+ }
2117
+ try {
2118
+ rmSync5(join11(resolveDgPaths().homeDir, ".dg"), { recursive: true, force: true });
2119
+ } catch {
2120
+ return;
2121
+ }
2122
+ }
2123
+ run();