better-dsh 0.2.5-e → 0.3.0

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 (42) hide show
  1. package/README.md +27 -3
  2. package/cordis.patch.yml +44 -0
  3. package/docs/50_test-reports/2026-10-06-authentication-only-web-admission-4999.md +63 -0
  4. package/docs/50_test-reports/2026-10-07-better-dsh-welcome-self-contained-4999.md +52 -0
  5. package/docs/specs/welcome-self-contained/spec.md +13 -0
  6. package/lib/LaunchOptions-B874eBu2.js +4 -0
  7. package/lib/{LaunchOptions-DXdeJis3.js → LaunchOptions-kGXcZOe0.js} +1 -1
  8. package/lib/{bidi-CwtLGgcA.js → bidi-BalpKaJc.js} +1 -1
  9. package/lib/bundle-delivery.d.ts +20 -0
  10. package/lib/bundle-delivery.js +209 -0
  11. package/lib/client/index.js +2 -2
  12. package/lib/failover/index.js +1 -1
  13. package/lib/fs-aware/sandbox-plugin.js +4 -4
  14. package/lib/hmr.d.ts +32 -0
  15. package/lib/hmr.js +49 -0
  16. package/lib/{index-browser-Bp3vxHC3.js → index-browser-CysrjMyM.js} +4 -4
  17. package/lib/index.js +5 -5
  18. package/lib/{kernel-env-BLPZE-I3.js → kernel-env-D8UOWeji.js} +2 -2
  19. package/lib/kernel-env.js +1 -1
  20. package/lib/{lsp-server-registry-BcdkHROD.js → lsp-server-registry-BXvUTBY7.js} +1 -1
  21. package/lib/{lsp-server-registry-D4VLs1Sm.js → lsp-server-registry-CH9WNFFt.js} +1 -1
  22. package/lib/{main-BXwPLuYr.js → main-BQeFrBM1.js} +1 -1
  23. package/lib/{main-CKFNYpqT.js → main-CupOhMp5.js} +4 -4
  24. package/lib/mobile/plugin.d.ts +1 -1
  25. package/lib/mobile/plugin.js +1 -1
  26. package/lib/{puppeteer-core-Bliv_vNf.js → puppeteer-core-CSk2PtSm.js} +8 -8
  27. package/lib/remote/plugin.js +3 -3
  28. package/lib/url-schemes/index.d.ts +11 -11
  29. package/lib/url-schemes/index.js +14 -14
  30. package/lib/web-password.d.ts +7 -7
  31. package/lib/{web-trust-jR0o70JS.js → web-trust-D6gJpUMf.js} +5 -5
  32. package/lib/{web-trust-D9jFaQbH.d.ts → web-trust-Dej_RI2B.d.ts} +15 -15
  33. package/lib/web-trust.d.ts +2 -1
  34. package/lib/web-trust.js +1 -1
  35. package/lib/webserver.d.ts +10 -0
  36. package/lib/webserver.js +19 -0
  37. package/lib/welcome-notice.d.ts +18 -0
  38. package/lib/welcome-notice.js +59 -0
  39. package/lib/{wrap-kTohEeis.js → wrap-T4I0nfPM.js} +116 -116
  40. package/package.json +47 -5
  41. package/scripts/register-bundle.mjs +80 -0
  42. package/lib/LaunchOptions-3peHoOAx.js +0 -4
@@ -1,6 +1,6 @@
1
- import { promises, statSync } from "node:fs";
2
1
  import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
3
2
  import { fileURLToPath } from "node:url";
3
+ import { promises, statSync } from "node:fs";
4
4
 
5
5
  //#region src/url-schemes/catalog.ts
6
6
  /**
@@ -242,120 +242,6 @@ function stringifyNode(node) {
242
242
  }
243
243
  }
244
244
 
245
- //#endregion
246
- //#region src/url-schemes/handlers/dvc.ts
247
- /** Module-level device registry: insertion-ordered, shared by every handler instance. */
248
- const devices = /* @__PURE__ */ new Map();
249
- /** Register (or replace) the device mounted under `name`. */
250
- function registerDvcDevice(name, device) {
251
- devices.set(name, device);
252
- }
253
- /** Read-only view of the registered devices, in registration order. */
254
- function listDvcDevices() {
255
- return devices;
256
- }
257
- /**
258
- * The first path segment is the device name (`dvc://name`, `dvc://name/sub`).
259
- * A leading `dvc://` is tolerated so callers may pass either the parsed path
260
- * (the write tool's contract) or the full URL.
261
- */
262
- /** Subpath after the device name (`status`, `diagnostics?file=…`), or undefined. */
263
- function subpathOf(path$1) {
264
- const trimmed = (path$1.startsWith("dvc://") ? path$1.slice(6) : path$1).replace(/^\/+/, "");
265
- const slash = trimmed.indexOf("/");
266
- if (slash === -1) return void 0;
267
- const sub = trimmed.slice(slash + 1);
268
- return sub === "" ? void 0 : sub;
269
- }
270
- function deviceNameFromPath(path$1) {
271
- const trimmed = (path$1.startsWith("dvc://") ? path$1.slice(6) : path$1).replace(/^\/+/, "");
272
- const slash = trimmed.indexOf("/");
273
- return slash === -1 ? trimmed : trimmed.slice(0, slash);
274
- }
275
- /** Uniform `unknown`-error rendering for structured error messages. */
276
- function messageOf(error) {
277
- return error instanceof Error ? error.message : String(error);
278
- }
279
- /**
280
- * Build the `dvc://` scheme handler over the module-level device registry.
281
- * Bare `dvc://` yields the roster (`no devices mounted` while empty); a
282
- * registered `<device>` yields its summary plus a usage hint; an unregistered
283
- * name keeps the `unknown device` placeholder text.
284
- */
285
- function createDvcHandler(_deps = {}) {
286
- return {
287
- selectorAware: true,
288
- async resolve(_env, path$1, selector) {
289
- const name = deviceNameFromPath(path$1);
290
- if (name === "") {
291
- if (devices.size === 0) return "no devices mounted";
292
- return applySelector([...devices].map(([n, device$1]) => `${n}\t${device$1.summary}`).join("\n"), selector ?? null);
293
- }
294
- const device = devices.get(name);
295
- if (device === void 0) return `unknown device: ${name}`;
296
- const subpath = subpathOf(path$1);
297
- if (subpath !== void 0 && device.read !== void 0) {
298
- const query = selector?.kind === "query" ? `?${selector.q}` : "";
299
- let text;
300
- try {
301
- text = await device.read(`${subpath}${query}`, _env.agent?.id);
302
- } catch (error) {
303
- return `Error: ${error instanceof Error ? error.message : String(error)}`;
304
- }
305
- return selector !== void 0 && selector !== null && selector.kind !== "query" ? applySelector(text, selector) : text;
306
- }
307
- if (subpath !== void 0) return `unknown read path dvc://${name}/${subpath} (device serves doc only)`;
308
- return applySelector(`${device.summary}\nusage: write dvc://${name} with a JSON args object to execute this device`, selector ?? null);
309
- }
310
- };
311
- }
312
- /**
313
- * Write dispatch for `dvc://` URLs — called by the write tool's URL branch.
314
- * `path` addresses the device (parsed path or full `dvc://` URL); `content`
315
- * must be the JSON args payload.
316
- *
317
- * Routing and args failures (`DVC_NO_DEVICE`, `DVC_UNKNOWN_DEVICE`,
318
- * `DVC_BAD_ARGS`) throw synchronously — the placeholder wave's observable
319
- * contract — while a device-reported failure rejects the returned promise as
320
- * `DVC_DEVICE_ERROR` carrying the device name.
321
- */
322
- function dispatchDvcWrite(path$1, content, session, cwd) {
323
- if (devices.size === 0) throw new UrlSchemesError("DVC_NO_DEVICE", "dvc:// write dispatch: no devices mounted to route the write to");
324
- const name = deviceNameFromPath(path$1);
325
- const device = devices.get(name);
326
- if (device === void 0) throw new UrlSchemesError("DVC_UNKNOWN_DEVICE", `dvc:// write dispatch: no device named "${name}" (registered: ${[...devices.keys()].sort().join(", ")})`);
327
- let args;
328
- try {
329
- args = JSON.parse(content);
330
- } catch (error) {
331
- throw new UrlSchemesError("DVC_BAD_ARGS", `dvc:// write dispatch: device "${name}" requires a JSON args payload (${messageOf(error)})`);
332
- }
333
- if (session !== void 0 && args !== null && typeof args === "object" && !Array.isArray(args)) args = { ...args };
334
- return Promise.resolve().then(() => device.execute(args, {
335
- session,
336
- ...cwd === void 0 ? {} : { cwd }
337
- })).catch((error) => {
338
- throw new UrlSchemesError("DVC_DEVICE_ERROR", `dvc:// device "${name}" execute failed: ${messageOf(error)}`);
339
- });
340
- }
341
-
342
- //#endregion
343
- //#region src/url-schemes/docs-dir.ts
344
- function resolveDocsDir() {
345
- let dir = dirname(fileURLToPath(import.meta.url));
346
- for (;;) {
347
- for (const name of ["dsh-docs", "docs"]) {
348
- const candidate = join(dir, name);
349
- try {
350
- if (statSync(candidate).isDirectory()) return candidate;
351
- } catch {}
352
- }
353
- const parent = dirname(dir);
354
- if (parent === dir) return void 0;
355
- dir = parent;
356
- }
357
- }
358
-
359
245
  //#endregion
360
246
  //#region src/url-schemes/resolver.ts
361
247
  /** Scheme→handler registry that resolves `scheme://` URLs end-to-end. */
@@ -541,6 +427,103 @@ function createDshHandler(deps) {
541
427
  };
542
428
  }
543
429
 
430
+ //#endregion
431
+ //#region src/url-schemes/handlers/dvc.ts
432
+ /** Module-level device registry: insertion-ordered, shared by every handler instance. */
433
+ const devices = /* @__PURE__ */ new Map();
434
+ /** Register (or replace) the device mounted under `name`. */
435
+ function registerDvcDevice(name, device) {
436
+ devices.set(name, device);
437
+ }
438
+ /** Read-only view of the registered devices, in registration order. */
439
+ function listDvcDevices() {
440
+ return devices;
441
+ }
442
+ /**
443
+ * The first path segment is the device name (`dvc://name`, `dvc://name/sub`).
444
+ * A leading `dvc://` is tolerated so callers may pass either the parsed path
445
+ * (the write tool's contract) or the full URL.
446
+ */
447
+ /** Subpath after the device name (`status`, `diagnostics?file=…`), or undefined. */
448
+ function subpathOf(path$1) {
449
+ const trimmed = (path$1.startsWith("dvc://") ? path$1.slice(6) : path$1).replace(/^\/+/, "");
450
+ const slash = trimmed.indexOf("/");
451
+ if (slash === -1) return void 0;
452
+ const sub = trimmed.slice(slash + 1);
453
+ return sub === "" ? void 0 : sub;
454
+ }
455
+ function deviceNameFromPath(path$1) {
456
+ const trimmed = (path$1.startsWith("dvc://") ? path$1.slice(6) : path$1).replace(/^\/+/, "");
457
+ const slash = trimmed.indexOf("/");
458
+ return slash === -1 ? trimmed : trimmed.slice(0, slash);
459
+ }
460
+ /** Uniform `unknown`-error rendering for structured error messages. */
461
+ function messageOf(error) {
462
+ return error instanceof Error ? error.message : String(error);
463
+ }
464
+ /**
465
+ * Build the `dvc://` scheme handler over the module-level device registry.
466
+ * Bare `dvc://` yields the roster (`no devices mounted` while empty); a
467
+ * registered `<device>` yields its summary plus a usage hint; an unregistered
468
+ * name keeps the `unknown device` placeholder text.
469
+ */
470
+ function createDvcHandler(_deps = {}) {
471
+ return {
472
+ selectorAware: true,
473
+ async resolve(_env, path$1, selector) {
474
+ const name = deviceNameFromPath(path$1);
475
+ if (name === "") {
476
+ if (devices.size === 0) return "no devices mounted";
477
+ return applySelector([...devices].map(([n, device$1]) => `${n}\t${device$1.summary}`).join("\n"), selector ?? null);
478
+ }
479
+ const device = devices.get(name);
480
+ if (device === void 0) return `unknown device: ${name}`;
481
+ const subpath = subpathOf(path$1);
482
+ if (subpath !== void 0 && device.read !== void 0) {
483
+ const query = selector?.kind === "query" ? `?${selector.q}` : "";
484
+ let text;
485
+ try {
486
+ text = await device.read(`${subpath}${query}`, _env.agent?.id);
487
+ } catch (error) {
488
+ return `Error: ${error instanceof Error ? error.message : String(error)}`;
489
+ }
490
+ return selector !== void 0 && selector !== null && selector.kind !== "query" ? applySelector(text, selector) : text;
491
+ }
492
+ if (subpath !== void 0) return `unknown read path dvc://${name}/${subpath} (device serves doc only)`;
493
+ return applySelector(`${device.summary}\nusage: write dvc://${name} with a JSON args object to execute this device`, selector ?? null);
494
+ }
495
+ };
496
+ }
497
+ /**
498
+ * Write dispatch for `dvc://` URLs — called by the write tool's URL branch.
499
+ * `path` addresses the device (parsed path or full `dvc://` URL); `content`
500
+ * must be the JSON args payload.
501
+ *
502
+ * Routing and args failures (`DVC_NO_DEVICE`, `DVC_UNKNOWN_DEVICE`,
503
+ * `DVC_BAD_ARGS`) throw synchronously — the placeholder wave's observable
504
+ * contract — while a device-reported failure rejects the returned promise as
505
+ * `DVC_DEVICE_ERROR` carrying the device name.
506
+ */
507
+ function dispatchDvcWrite(path$1, content, session, cwd) {
508
+ if (devices.size === 0) throw new UrlSchemesError("DVC_NO_DEVICE", "dvc:// write dispatch: no devices mounted to route the write to");
509
+ const name = deviceNameFromPath(path$1);
510
+ const device = devices.get(name);
511
+ if (device === void 0) throw new UrlSchemesError("DVC_UNKNOWN_DEVICE", `dvc:// write dispatch: no device named "${name}" (registered: ${[...devices.keys()].sort().join(", ")})`);
512
+ let args;
513
+ try {
514
+ args = JSON.parse(content);
515
+ } catch (error) {
516
+ throw new UrlSchemesError("DVC_BAD_ARGS", `dvc:// write dispatch: device "${name}" requires a JSON args payload (${messageOf(error)})`);
517
+ }
518
+ if (session !== void 0 && args !== null && typeof args === "object" && !Array.isArray(args)) args = { ...args };
519
+ return Promise.resolve().then(() => device.execute(args, {
520
+ session,
521
+ ...cwd === void 0 ? {} : { cwd }
522
+ })).catch((error) => {
523
+ throw new UrlSchemesError("DVC_DEVICE_ERROR", `dvc:// device "${name}" execute failed: ${messageOf(error)}`);
524
+ });
525
+ }
526
+
544
527
  //#endregion
545
528
  //#region src/url-schemes/handlers/http.ts
546
529
  /** The schemes one handler instance serves; register it under each of these. */
@@ -660,6 +643,23 @@ function createHttpHandler() {
660
643
  } };
661
644
  }
662
645
 
646
+ //#endregion
647
+ //#region src/url-schemes/docs-dir.ts
648
+ function resolveDocsDir() {
649
+ let dir = dirname(fileURLToPath(import.meta.url));
650
+ for (;;) {
651
+ for (const name of ["dsh-docs", "docs"]) {
652
+ const candidate = join(dir, name);
653
+ try {
654
+ if (statSync(candidate).isDirectory()) return candidate;
655
+ } catch {}
656
+ }
657
+ const parent = dirname(dir);
658
+ if (parent === dir) return void 0;
659
+ dir = parent;
660
+ }
661
+ }
662
+
663
663
  //#endregion
664
664
  //#region src/fs-aware/wrap.ts
665
665
  const WRAPPED = Symbol("dsh-url-schemes.fs-wrap");
@@ -747,4 +747,4 @@ function wrapFsWithSchemes(fs$1, services) {
747
747
  }
748
748
 
749
749
  //#endregion
750
- export { createDshHandler as a, createDvcHandler as c, registerDvcDevice as d, UrlSchemesError as f, SCHEME_NAMES as h, createHttpHandler as i, dispatchDvcWrite as l, parseUrl as m, wrapFsWithSchemes as n, UrlResolver as o, applySelector as p, HTTP_SCHEMES as r, resolveDocsDir as s, buildFsLayerResolver as t, listDvcDevices as u };
750
+ export { createHttpHandler as a, listDvcDevices as c, UrlResolver as d, UrlSchemesError as f, SCHEME_NAMES as h, HTTP_SCHEMES as i, registerDvcDevice as l, parseUrl as m, wrapFsWithSchemes as n, createDvcHandler as o, applySelector as p, resolveDocsDir as r, dispatchDvcWrite as s, buildFsLayerResolver as t, createDshHandler as u };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "better-dsh",
3
- "version": "0.2.5-e",
3
+ "version": "0.3.0",
4
4
  "description": "Make your dsh ready for serious coding tasks. (Tools x Schemas)^REPL. `skill://`, `ctx://`, `agent://`, `dvc://`, `dsh://`, IPython REPL, Context as Variables, cross compactions recallable, full context revive. `hash-edit`, `dvc://browser`, subagent as function, workflow as function.",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -51,6 +51,22 @@
51
51
  "./client": {
52
52
  "types": "./lib/client/index.d.ts",
53
53
  "default": "./lib/client/index.js"
54
+ },
55
+ "./welcome-notice": {
56
+ "types": "./lib/welcome-notice.d.ts",
57
+ "default": "./lib/welcome-notice.js"
58
+ },
59
+ "./webserver": {
60
+ "types": "./lib/webserver.d.ts",
61
+ "default": "./lib/webserver.js"
62
+ },
63
+ "./bundle-delivery": {
64
+ "types": "./lib/bundle-delivery.d.ts",
65
+ "default": "./lib/bundle-delivery.js"
66
+ },
67
+ "./hmr": {
68
+ "types": "./lib/hmr.d.ts",
69
+ "default": "./lib/hmr.js"
54
70
  }
55
71
  },
56
72
  "imports": {
@@ -67,7 +83,8 @@
67
83
  "cordis.patch.yml",
68
84
  "eval-description.md",
69
85
  "url-schemes-instruction.md",
70
- "scripts/kernel-provision.mjs"
86
+ "scripts/kernel-provision.mjs",
87
+ "scripts/register-bundle.mjs"
71
88
  ],
72
89
  "scripts": {
73
90
  "prebuild": "node scripts/copy-docs.mjs",
@@ -158,7 +175,12 @@
158
175
  "@deepseek-ai/dsh-user-approval": ">=0.1.5-0 <0.3.0-0",
159
176
  "@deepseek-ai/dsh-web-app": ">=0.1.5-0 <0.3.0-0",
160
177
  "@deepseek-ai/dsh-workflow-worker-thread": ">=0.1.5-0 <0.3.0-0",
161
- "react": "^18.2.0"
178
+ "react": "^18.2.0",
179
+ "@deepseek-ai/dsh-app-boot": ">=0.1.5-0 <0.3.0-0",
180
+ "@deepseek-ai/dsh-atomic-write": ">=0.1.5-0 <0.3.0-0",
181
+ "@deepseek-ai/dsh-cmdline": ">=0.1.5-0 <0.3.0-0",
182
+ "@deepseek-ai/dsh-plugin-manager": ">=0.1.5-0 <0.3.0-0",
183
+ "@deepseek-ai/dsh-hmr": ">=0.1.5-0 <0.3.0-0"
162
184
  },
163
185
  "peerDependenciesMeta": {
164
186
  "@deepseek-ai/cordis": {
@@ -337,6 +359,21 @@
337
359
  },
338
360
  "react": {
339
361
  "optional": true
362
+ },
363
+ "@deepseek-ai/dsh-app-boot": {
364
+ "optional": true
365
+ },
366
+ "@deepseek-ai/dsh-atomic-write": {
367
+ "optional": true
368
+ },
369
+ "@deepseek-ai/dsh-cmdline": {
370
+ "optional": true
371
+ },
372
+ "@deepseek-ai/dsh-plugin-manager": {
373
+ "optional": true
374
+ },
375
+ "@deepseek-ai/dsh-hmr": {
376
+ "optional": true
340
377
  }
341
378
  },
342
379
  "devDependencies": {
@@ -373,7 +410,8 @@
373
410
  },
374
411
  "repository": {
375
412
  "type": "git",
376
- "url": "git+https://github.com/pgmi-builds/better-dsh.git"
413
+ "url": "git+https://github.com/pgmi-builds/super-dsh.git",
414
+ "directory": "better-dsh"
377
415
  },
378
416
  "keywords": [
379
417
  "dsh",
@@ -384,5 +422,9 @@
384
422
  "kernel",
385
423
  "agent",
386
424
  "plugin"
387
- ]
425
+ ],
426
+ "homepage": "https://github.com/pgmi-builds/super-dsh/tree/master/better-dsh",
427
+ "bugs": {
428
+ "url": "https://github.com/pgmi-builds/super-dsh/issues"
429
+ }
388
430
  }
@@ -0,0 +1,80 @@
1
+ // Separate-process entry for the SAME native package operations used by dsh plugin.
2
+ // No shell interpolation, package scripts, upstream edits, or companion registry lookup.
3
+ import { createRequire } from 'node:module'
4
+ import { createHash } from 'node:crypto'
5
+ import { readFile, realpath } from 'node:fs/promises'
6
+ import { dirname, join, relative, resolve, isAbsolute, sep } from 'node:path'
7
+ import { pathToFileURL } from 'node:url'
8
+ let input = ''
9
+ for await (const bytes of process.stdin) input += bytes
10
+ const {profile,archive,expected} = JSON.parse(input)
11
+ const require = createRequire(profile.installAnchor)
12
+ const {runProfilePnpm} = await import(pathToFileURL(require.resolve('@deepseek-ai/dsh-plugin-manager/operations')).href)
13
+ const {withFileLock} = await import(pathToFileURL(require.resolve('@deepseek-ai/dsh-atomic-write')).href)
14
+ const abort = new AbortController()
15
+ process.once('SIGTERM', () => abort.abort())
16
+ const json = async path => JSON.parse(await readFile(path, 'utf8'))
17
+ const hash = bytes => createHash('sha256').update(bytes).digest('hex')
18
+ async function contained(root, path) {
19
+ if (typeof path !== 'string' || isAbsolute(path)) throw new Error('Pack delivery path must be relative')
20
+ const base = await realpath(root), file = await realpath(resolve(base, path)), rel = relative(base, file)
21
+ if (rel === '..' || rel.startsWith('..' + sep) || isAbsolute(rel)) throw new Error('Pack delivery path escapes its owner')
22
+ return file
23
+ }
24
+ const skipped = disposition => ({ exitCode: 0, disposition })
25
+ // Complete each native acquisition/release before observing cancellation;
26
+ // exiting during its async lock-file write can strand incomplete lock metadata.
27
+ async function withCancellableProfileLock(operation) {
28
+ const path = join(profile.dir, 'package.json'), deadline = Date.now() + 120000
29
+ for (;;) {
30
+ abort.signal.throwIfAborted()
31
+ let acquired = false
32
+ try {
33
+ return await withFileLock(path, async () => {
34
+ acquired = true
35
+ abort.signal.throwIfAborted()
36
+ return operation()
37
+ }, { waitMs: Math.min(250, Math.max(0, deadline - Date.now())) })
38
+ } catch (error) {
39
+ abort.signal.throwIfAborted()
40
+ if (acquired || Date.now() >= deadline
41
+ || error.message !== `atomic-write: timed out waiting for the writer lock at ${path}.lock`) throw error
42
+ }
43
+ }
44
+ }
45
+ const result = await withCancellableProfileLock(async () => {
46
+ abort.signal.throwIfAborted()
47
+ const current = await json(join(profile.dir, 'package.json'))
48
+ if (typeof expected.ownerSpec !== 'string' || current.dependencies?.[expected.owner] !== expected.ownerSpec) return skipped('owner-changed')
49
+ const ownerDir = join(profile.dir, 'node_modules', expected.owner)
50
+ let owner, descriptorPath, descriptor
51
+ try {
52
+ owner = await json(join(ownerDir, 'package.json'))
53
+ if (owner.dependencies?.[expected.companion.name] !== expected.companion.version || owner.superd?.delivery === undefined) return skipped('owner-changed')
54
+ descriptorPath = await contained(ownerDir, owner.superd.delivery)
55
+ descriptor = await json(descriptorPath)
56
+ } catch (error) {
57
+ if (error.code === 'ENOENT') return skipped('owner-changed')
58
+ throw error
59
+ }
60
+ const item = descriptor.companions?.find(item => item.name === expected.companion.name)
61
+ if (item?.version !== expected.companion.version || item.sha256 !== expected.companion.sha256
62
+ || hash(await readFile(await contained(dirname(descriptorPath), item.tarball))) !== expected.companion.sha256) return skipped('owner-changed')
63
+ const prior = current.dependencies?.[item.name]
64
+ if (prior !== expected.priorSpec) return skipped(prior === undefined && expected.priorSpec !== undefined ? 'companion-removed' : 'companion-changed')
65
+ if (hash(await readFile(archive)) !== item.sha256) throw new Error('Cached companion SHA256 mismatch')
66
+ abort.signal.throwIfAborted()
67
+ // Same public operation and writer lock used by the native Plugin Manager;
68
+ // intent is checked after acquisition, before a queued install can undo removal.
69
+ const operation = await runProfilePnpm({profile:profile.name,dir:profile.dir,installAnchor:profile.installAnchor,cwd:profile.dir,home:profile.home}, ['add','file:'+archive,'--ignore-scripts'], {
70
+ ...profile.packageManager, execution:'service', signal:abort.signal, outputBytes:16384,
71
+ lookupTimeoutMs:120000, idleTimeoutMs:120000,
72
+ })
73
+ if (operation.exitCode === 0) {
74
+ const installed = await json(join(profile.dir, 'node_modules', item.name, 'package.json'))
75
+ const after = await json(join(profile.dir, 'package.json'))
76
+ if (installed.name !== item.name || installed.version !== item.version || after.dependencies?.[item.name] !== 'file:' + archive) throw new Error('Native companion registration did not install the exact local artifact')
77
+ }
78
+ return { exitCode: operation.exitCode, logPath: operation.logPath, disposition: 'installed' }
79
+ })
80
+ process.stdout.write(JSON.stringify(result)+'\n')
@@ -1,4 +0,0 @@
1
- import "./main-CKFNYpqT.js";
2
- import { t as convertPuppeteerChannelToBrowsersChannel } from "./LaunchOptions-DXdeJis3.js";
3
-
4
- export { convertPuppeteerChannelToBrowsersChannel };