@sparkelf/dsh-plus 0.1.0-rc.29 → 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 +43 -9
- package/lib/types/standalone-cli.js +40 -7
- package/lib/types/standalone-profile.js +12 -4
- package/package.json +1 -1
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
|
-
|
|
251
|
-
|
|
252
|
-
|
|
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 =
|
|
482
|
+
const anchor = installationAnchor();
|
|
449
483
|
const paths = resolvePaths(anchor);
|
|
450
|
-
const created = ensureProfile(paths,
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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 =
|
|
101
|
+
const anchor = installationAnchor();
|
|
69
102
|
const paths = resolvePaths(anchor);
|
|
70
|
-
const created = ensureProfile(paths,
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
-
|
|
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