@sparkelf/dsh-plus 0.1.0-rc.28 → 0.1.0-rc.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/bin.js CHANGED
@@ -6,6 +6,7 @@ import { createWriteStream, existsSync, mkdirSync, readFileSync, readdirSync, rm
6
6
  import { dirname, join, resolve } from "node:path";
7
7
  import { homedir } from "node:os";
8
8
  import semver from "semver";
9
+ import { fileURLToPath } from "node:url";
9
10
  import { createServer } from "node:net";
10
11
  //#region lib/types/registry-versions.js
11
12
  /**
@@ -247,9 +248,14 @@ function resolveDistributionDirectory(anchor) {
247
248
  } catch {
248
249
  throw new Error("@sparkelf/dsh-plus is not installed in " + dirname(anchor) + "; run this command from the directory that installed it");
249
250
  }
250
- const consumerRoot = resolve(dirname(anchor));
251
- if (!resolved.startsWith(consumerRoot + "/")) throw new Error("@sparkelf/dsh-plus resolved outside " + consumerRoot + " (found " + resolved + "); run this command from the directory that installed it");
252
- return resolved;
251
+ let current = resolve(dirname(anchor));
252
+ for (;;) {
253
+ if (resolved === current || resolved.startsWith(current + "/")) return resolved;
254
+ const parent = dirname(current);
255
+ if (parent === current) break;
256
+ current = parent;
257
+ }
258
+ throw new Error("@sparkelf/dsh-plus resolved outside " + resolve(dirname(anchor)) + " (found " + resolved + "); run this command from the directory that installed it");
253
259
  }
254
260
  /** The reviewed bundle order and pins the installed distribution declares. */
255
261
  function readDistributionProfile(distributionDirectory) {
@@ -425,6 +431,34 @@ function parseStartOptions(argv) {
425
431
  foreground
426
432
  };
427
433
  }
434
+ /**
435
+ * Where the installation that owns this command keeps its packages.
436
+ *
437
+ * A global install places the command in a shared prefix and a local install places
438
+ * it in a project; neither has anything to do with the directory the user happens to
439
+ * be in. The search therefore starts at this module own file and climbs to the tree
440
+ * npm laid out around it.
441
+ *
442
+ * The test is the launcher, not the distribution: inside a workspace the package
443
+ * resolves its own name, so looking for the distribution would stop at the package
444
+ * rather than at the tree that owns every dependency.
445
+ *
446
+ * @returns absolute path to the installation root.
447
+ */
448
+ function installationRoot() {
449
+ const here = dirname(fileURLToPath(import.meta.url));
450
+ let current = here;
451
+ for (;;) {
452
+ if (existsSync(join(current, "node_modules", "@deepseek-ai", "dsh"))) return current;
453
+ const parent = dirname(current);
454
+ if (parent === current) return here;
455
+ current = parent;
456
+ }
457
+ }
458
+ /** The package.json this installation resolves its dependencies from. */
459
+ function installationAnchor() {
460
+ return join(installationRoot(), "package.json");
461
+ }
428
462
  /** The launcher entry this installation must drive. */
429
463
  function launcherEntry(anchor) {
430
464
  return createRequire(anchor).resolve("@deepseek-ai/dsh/lib/bin.js");
@@ -445,9 +479,9 @@ function runForeground(entry, port, host, open) {
445
479
  }
446
480
  async function start(argv) {
447
481
  const options = parseStartOptions(argv);
448
- const anchor = join(process.cwd(), "package.json");
482
+ const anchor = installationAnchor();
449
483
  const paths = resolvePaths(anchor);
450
- const created = ensureProfile(paths, process.cwd());
484
+ const created = ensureProfile(paths, installationRoot());
451
485
  console.log(created ? "Created the plus profile at " + paths.profileDirectory : "Using the existing plus profile");
452
486
  const entry = launcherEntry(anchor);
453
487
  if (options.foreground) return runForeground(entry, options.port, options.host, options.open);
@@ -506,7 +540,7 @@ async function startDetached(home, entry, options) {
506
540
  return 0;
507
541
  }
508
542
  async function stop() {
509
- const { home } = resolvePaths(join(process.cwd(), "package.json"));
543
+ const { home } = resolvePaths(installationAnchor());
510
544
  const state = readState(home);
511
545
  if (state === void 0) {
512
546
  clearState(home);
@@ -527,7 +561,7 @@ async function stop() {
527
561
  return 0;
528
562
  }
529
563
  function status() {
530
- const state = readState(resolvePaths(join(process.cwd(), "package.json")).home);
564
+ const state = readState(resolvePaths(installationAnchor()).home);
531
565
  if (state === void 0) {
532
566
  console.log("Plus is not running.");
533
567
  console.log("Start it with: dsh-plus start");
@@ -548,7 +582,7 @@ function status() {
548
582
  async function update(argv) {
549
583
  const checkOnly = argv.includes("--check");
550
584
  const assumeYes = argv.includes("--yes");
551
- const paths = resolvePaths(join(process.cwd(), "package.json"));
585
+ const paths = resolvePaths(installationAnchor());
552
586
  const distribution = readDistributionProfile(paths.distributionDirectory);
553
587
  const installed = distribution.version;
554
588
  const newer = newerVersion(distribution.name, installed);
@@ -600,7 +634,7 @@ function confirm(question) {
600
634
  });
601
635
  }
602
636
  async function doctor() {
603
- const paths = resolvePaths(join(process.cwd(), "package.json"));
637
+ const paths = resolvePaths(installationAnchor());
604
638
  let failures = 0;
605
639
  const check = (ok, line) => {
606
640
  console.log((ok ? "ok " : "FAIL ") + line);
@@ -10,7 +10,8 @@
10
10
  import { spawnSync } from 'node:child_process';
11
11
  import { existsSync, readFileSync, writeFileSync } from 'node:fs';
12
12
  import { createRequire } from 'node:module';
13
- import { join } from 'node:path';
13
+ import { dirname, join } from 'node:path';
14
+ import { fileURLToPath } from 'node:url';
14
15
  import { newerVersion } from "./registry-versions.js";
15
16
  import { DEFAULT_PORT, STOP_GRACE_MILLISECONDS, choosePort, clearState, isRunning, portAvailable, readState, spawnServer, stateDirectory, waitForServer, writeState, } from "./standalone-server.js";
16
17
  import { STANDALONE_PROFILE, ensureProfile, readDistributionProfile, resolvePaths, } from "./standalone-profile.js";
@@ -51,6 +52,38 @@ function parseStartOptions(argv) {
51
52
  }
52
53
  return { port, host, open, foreground };
53
54
  }
55
+ /**
56
+ * Where the installation that owns this command keeps its packages.
57
+ *
58
+ * A global install places the command in a shared prefix and a local install places
59
+ * it in a project; neither has anything to do with the directory the user happens to
60
+ * be in. The search therefore starts at this module own file and climbs to the tree
61
+ * npm laid out around it.
62
+ *
63
+ * The test is the launcher, not the distribution: inside a workspace the package
64
+ * resolves its own name, so looking for the distribution would stop at the package
65
+ * rather than at the tree that owns every dependency.
66
+ *
67
+ * @returns absolute path to the installation root.
68
+ */
69
+ function installationRoot() {
70
+ const here = dirname(fileURLToPath(import.meta.url));
71
+ let current = here;
72
+ for (;;) {
73
+ if (existsSync(join(current, 'node_modules', '@deepseek-ai', 'dsh')))
74
+ return current;
75
+ const parent = dirname(current);
76
+ // A tree npm did not lay out has no such ancestor; the module own directory
77
+ // keeps the failure message pointing at the installation that was searched.
78
+ if (parent === current)
79
+ return here;
80
+ current = parent;
81
+ }
82
+ }
83
+ /** The package.json this installation resolves its dependencies from. */
84
+ function installationAnchor() {
85
+ return join(installationRoot(), 'package.json');
86
+ }
54
87
  /** The launcher entry this installation must drive. */
55
88
  function launcherEntry(anchor) {
56
89
  return createRequire(anchor).resolve('@deepseek-ai/dsh/lib/bin.js');
@@ -65,9 +98,9 @@ function runForeground(entry, port, host, open) {
65
98
  }
66
99
  async function start(argv) {
67
100
  const options = parseStartOptions(argv);
68
- const anchor = join(process.cwd(), 'package.json');
101
+ const anchor = installationAnchor();
69
102
  const paths = resolvePaths(anchor);
70
- const created = ensureProfile(paths, process.cwd());
103
+ const created = ensureProfile(paths, installationRoot());
71
104
  console.log(created
72
105
  ? 'Created the ' + STANDALONE_PROFILE + ' profile at ' + paths.profileDirectory
73
106
  : 'Using the existing ' + STANDALONE_PROFILE + ' profile');
@@ -111,7 +144,7 @@ async function startDetached(home, entry, options) {
111
144
  return 0;
112
145
  }
113
146
  async function stop() {
114
- const anchor = join(process.cwd(), 'package.json');
147
+ const anchor = installationAnchor();
115
148
  const { home } = resolvePaths(anchor);
116
149
  const state = readState(home);
117
150
  if (state === undefined) {
@@ -133,7 +166,7 @@ async function stop() {
133
166
  return 0;
134
167
  }
135
168
  function status() {
136
- const anchor = join(process.cwd(), 'package.json');
169
+ const anchor = installationAnchor();
137
170
  const paths = resolvePaths(anchor);
138
171
  const state = readState(paths.home);
139
172
  if (state === undefined) {
@@ -156,7 +189,7 @@ function status() {
156
189
  async function update(argv) {
157
190
  const checkOnly = argv.includes('--check');
158
191
  const assumeYes = argv.includes('--yes');
159
- const anchor = join(process.cwd(), 'package.json');
192
+ const anchor = installationAnchor();
160
193
  const paths = resolvePaths(anchor);
161
194
  const distribution = readDistributionProfile(paths.distributionDirectory);
162
195
  const installed = distribution.version;
@@ -210,7 +243,7 @@ function confirm(question) {
210
243
  });
211
244
  }
212
245
  async function doctor() {
213
- const anchor = join(process.cwd(), 'package.json');
246
+ const anchor = installationAnchor();
214
247
  const paths = resolvePaths(anchor);
215
248
  let failures = 0;
216
249
  const check = (ok, line) => {
@@ -49,11 +49,19 @@ export function resolveDistributionDirectory(anchor) {
49
49
  }
50
50
  // A resolution that leaves the consumer tree means the module answered from its own
51
51
  // installation, which reports health for a distribution the consumer never installed.
52
- const consumerRoot = resolve(dirname(anchor));
53
- if (!resolved.startsWith(consumerRoot + '/')) {
54
- throw new Error('@sparkelf/dsh-plus resolved outside ' + consumerRoot + ' (found ' + resolved + '); run this command from the directory that installed it');
52
+ // The comparison walks up from the anchor because the resolved package sits under the
53
+ // anchor's \`node_modules\`, not beside it: requiring \`<root>/package.json\` legitimately
54
+ // reports \`<root>/node_modules/@sparkelf/dsh-plus\`.
55
+ let current = resolve(dirname(anchor));
56
+ for (;;) {
57
+ if (resolved === current || resolved.startsWith(current + '/'))
58
+ return resolved;
59
+ const parent = dirname(current);
60
+ if (parent === current)
61
+ break;
62
+ current = parent;
55
63
  }
56
- return resolved;
64
+ throw new Error('@sparkelf/dsh-plus resolved outside ' + resolve(dirname(anchor)) + ' (found ' + resolved + '); run this command from the directory that installed it');
57
65
  }
58
66
  /** The reviewed bundle order and pins the installed distribution declares. */
59
67
  export function readDistributionProfile(distributionDirectory) {
package/package.json CHANGED
@@ -138,5 +138,5 @@
138
138
  },
139
139
  "type": "module",
140
140
  "types": "lib/types/index.d.ts",
141
- "version": "0.1.0-rc.28"
141
+ "version": "0.1.0-rc.30"
142
142
  }