@deepseek-insight/dsi 0.6.9 → 0.6.10
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/.agents/skills/dsi-plugin-rack/rack.d.mts +35 -0
- package/.agents/skills/dsi-plugin-rack/rack.mjs +168 -26
- package/build/client/_app/immutable/assets/{2.BGqV97Jd.css → 2.BuaCdYrs.css} +1 -1
- package/build/client/_app/immutable/chunks/B7sQH3rV.js +1 -0
- package/build/client/_app/immutable/chunks/{UkmEG9Ws.js → Dg3LIDOQ.js} +1 -1
- package/build/client/_app/immutable/chunks/XOquLDe4.js +2 -0
- package/build/client/_app/immutable/chunks/ivdzpE2c.js +1 -0
- package/build/client/_app/immutable/entry/{app.e7xoYywe.js → app.BTSQLfJD.js} +2 -2
- package/build/client/_app/immutable/entry/start.DMTgnn1w.js +1 -0
- package/build/client/_app/immutable/nodes/{1.E4wiL8sP.js → 1.Bj5dhQm8.js} +1 -1
- package/build/client/_app/immutable/nodes/{2.BBV-AGuB.js → 2.D2grr0LI.js} +195 -195
- package/build/client/_app/version.json +1 -1
- package/build/handler.js +4 -4
- package/build/index.js +4 -4
- package/build/server/chunks/chunks/{engine.js-CrdWRSwf.js → engine.js-1gYqtdBP.js} +17 -2
- package/build/server/chunks/chunks/{internal.js-BnJXHc1S.js → internal.js-CiymEM9G.js} +2 -2
- package/build/server/chunks/chunks/{state.js-CAjHzrRZ.js → state.js-Dve2UFKe.js} +2 -2
- package/build/server/chunks/entries/endpoints/api/plugins/apply/{_server.ts.js-CpO--Jwf.js → _server.ts.js-BNEUWbaf.js} +2 -2
- package/build/server/chunks/entries/endpoints/api/plugins/reload/{_server.ts.js-BACFXWMj.js → _server.ts.js-Ct28d7_t.js} +2 -2
- package/build/server/chunks/entries/endpoints/api/plugins/snapshot/{_server.ts.js-BJg0hLlC.js → _server.ts.js-DswGIO4S.js} +2 -2
- package/build/server/chunks/entries/pages/{_error.svelte.js-BXeIuPj-.js → _error.svelte.js-DUc94aLg.js} +3 -3
- package/build/server/chunks/entries/pages/{_page.svelte.js-CW-EdJ00.js → _page.svelte.js-CGKKJjvq.js} +154 -6
- package/build/server/chunks/{handler-DimUSmTW.js → handler-DndMFIB-.js} +3 -3
- package/build/server/chunks/{index.js-BQUp4Xgn.js → index.js-XCtYQ9iw.js} +2 -2
- package/build/server/chunks/{manifest.js-BWy6zgHL.js → manifest.js-B6QH7eda.js} +7 -7
- package/build/server/chunks/nodes/1.js-DgkiAL8m.js +9 -0
- package/build/server/chunks/nodes/{2.js-CzgP_zp4.js → 2.js-DiZQ86Is.js} +4 -4
- package/package.json +1 -1
- package/skills/dsi-add-plugin/SKILL.md +53 -0
- package/skills/dsi-add-plugin/references/allowbuilds-template.md +55 -0
- package/skills/dsi-add-plugin/references/checklist.md +98 -0
- package/skills/dsi-add-plugin/references/verification.md +67 -0
- package/template/.dsi/resources/plugins-reff.md +4 -2
- package/build/client/_app/immutable/chunks/C1F3aCiz.js +0 -2
- package/build/client/_app/immutable/chunks/CmnxnK6v.js +0 -1
- package/build/client/_app/immutable/chunks/jugX_o5s.js +0 -1
- package/build/client/_app/immutable/entry/start.CnkkMjJa.js +0 -1
- package/build/server/chunks/nodes/1.js-DJ3dsgdq.js +0 -9
- package/template/dsh-app-dev-preset/README.md +0 -69
- package/template/dsh-app-dev-preset/cordis.patch.yml +0 -219
- package/template/dsh-app-dev-preset/package.json +0 -7
- package/template/dsh-research-preset/README.md +0 -57
- package/template/dsh-research-preset/cordis.patch.yml +0 -118
- package/template/dsh-research-preset/package.json +0 -7
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/** Type surface of the rack engine (rack.mjs) for test files. */
|
|
2
|
+
declare const CACHE_VERSION: 2;
|
|
3
|
+
export interface RackRow {
|
|
4
|
+
n: string;
|
|
5
|
+
id: string;
|
|
6
|
+
group?: 'owned' | 'external';
|
|
7
|
+
repo: string;
|
|
8
|
+
author?: string | null;
|
|
9
|
+
authorUrl?: string | null;
|
|
10
|
+
version?: string | null;
|
|
11
|
+
description?: string | null;
|
|
12
|
+
order?: number;
|
|
13
|
+
installSpec?: string;
|
|
14
|
+
installed: boolean;
|
|
15
|
+
pkg: string | null;
|
|
16
|
+
bundle: string | null;
|
|
17
|
+
}
|
|
18
|
+
export interface GardenRow {
|
|
19
|
+
id: string;
|
|
20
|
+
group: 'owned';
|
|
21
|
+
version: string | null;
|
|
22
|
+
description: string | null;
|
|
23
|
+
order: number;
|
|
24
|
+
installSpec: string;
|
|
25
|
+
repo: string;
|
|
26
|
+
}
|
|
27
|
+
export function scanGarden(gardenPath: string | undefined | null): GardenRow[];
|
|
28
|
+
export function parseReff(text: string): { plugins: { id: string; repo: string; author: string | null; authorUrl: string | null }[]; warnings: { code: string; detail: string }[] };
|
|
29
|
+
export function findDepKey(manifest: { deps: Record<string, string> }, id: string, repo?: string): string | null;
|
|
30
|
+
export function readManifest(path: string): { deps: Record<string, string>; bundles: string[]; missing: boolean };
|
|
31
|
+
export function isInstalled(manifest: { deps: Record<string, string> }, id: string, repo?: string): boolean;
|
|
32
|
+
export function buildSnapshot(args: { reffPath?: string; manifestPath?: string; gardenPath?: string; profile?: string }): { snapshot: { v: number; generatedAt: string; profile: string; plugins: RackRow[] }; warnings: { code: string; detail: string }[] };
|
|
33
|
+
export function toInstallSpec(repo: string): string;
|
|
34
|
+
export function installOwned(manifestPath: string, row: { id: string; installSpec: string }): string;
|
|
35
|
+
export function restoreClobberedBundles(manifestPath: string, preOwnedRows: { id: string; installSpec?: string; pkg?: string | null }[]): boolean;
|
|
@@ -14,12 +14,12 @@
|
|
|
14
14
|
* dependencies[id] AND dsh.profile.bundles includes id. Gates surface, they
|
|
15
15
|
* never auto-clear (D6).
|
|
16
16
|
*/
|
|
17
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
17
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
18
18
|
import { homedir } from 'node:os';
|
|
19
19
|
import { dirname, join, resolve } from 'node:path';
|
|
20
20
|
import { spawnSync } from 'node:child_process';
|
|
21
21
|
|
|
22
|
-
const CACHE_VERSION =
|
|
22
|
+
export const CACHE_VERSION = 2;
|
|
23
23
|
|
|
24
24
|
function parseArgs(argv) {
|
|
25
25
|
const out = { command: argv[0], reload: false, reff: null, cache: null, manifest: null, profile: process.env.DSH_PROFILE ?? 'web', dshCmd: null, targets: [] };
|
|
@@ -30,6 +30,8 @@ function parseArgs(argv) {
|
|
|
30
30
|
else if (a === '--cache') out.cache = argv[++i];
|
|
31
31
|
else if (a === '--manifest') out.manifest = argv[++i];
|
|
32
32
|
else if (a === '--profile') out.profile = argv[++i];
|
|
33
|
+
else if (a === '--garden') out.garden = argv[++i];
|
|
34
|
+
else if (a === '--garden-repo') out.gardenRepo = argv[++i];
|
|
33
35
|
else if (a === '--dsh-cmd') out.dshCmd = argv[++i];
|
|
34
36
|
else out.targets.push(a);
|
|
35
37
|
}
|
|
@@ -54,6 +56,58 @@ export function parseReff(text) {
|
|
|
54
56
|
return { plugins, warnings };
|
|
55
57
|
}
|
|
56
58
|
|
|
59
|
+
|
|
60
|
+
/** Owned-species enumeration (ADR "The Plugin Garden" 2026-10-07, D1/D2):
|
|
61
|
+
* every direct child of the garden dir with a package.json wiring
|
|
62
|
+
* dsh.bundle.patch is one owned rack row, identified by its OWN package
|
|
63
|
+
* name. Rows carry version/description from the same file and an optional
|
|
64
|
+
* dsh.rack.order for display sort. Returns [] for a missing garden. */
|
|
65
|
+
export function scanGarden(gardenPath) {
|
|
66
|
+
if (!gardenPath || !existsSync(gardenPath)) return [];
|
|
67
|
+
const rows = [];
|
|
68
|
+
for (const child of readdirSync(gardenPath, { withFileTypes: true })) {
|
|
69
|
+
if (!child.isDirectory()) continue;
|
|
70
|
+
const pkgPath = join(gardenPath, child.name, 'package.json');
|
|
71
|
+
if (!existsSync(pkgPath)) continue;
|
|
72
|
+
let pkg;
|
|
73
|
+
try { pkg = JSON.parse(readFileSync(pkgPath, 'utf8')); } catch { continue; }
|
|
74
|
+
const patch = pkg && pkg.dsh && pkg.dsh.bundle && pkg.dsh.bundle.patch;
|
|
75
|
+
if (!patch) continue;
|
|
76
|
+
const order = (pkg.dsh && pkg.dsh.rack && pkg.dsh.rack.order) ?? Number.POSITIVE_INFINITY;
|
|
77
|
+
rows.push({
|
|
78
|
+
id: pkg.name,
|
|
79
|
+
group: 'owned',
|
|
80
|
+
version: pkg.version ?? null,
|
|
81
|
+
description: pkg.description ?? null,
|
|
82
|
+
order,
|
|
83
|
+
installSpec: 'link:' + join(gardenPath, child.name),
|
|
84
|
+
repo: 'link:' + join(gardenPath, child.name)
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
return rows.sort((a, b) => (a.order - b.order) || a.id.localeCompare(b.id));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** Repository identity (ADR-0016 D1): a catalog entry identifies a
|
|
91
|
+
* REPOSITORY, not a URL string. Strip protocol, .git suffix, trailing
|
|
92
|
+
* slashes and any /tree/<ref>(/...)? browse subtree, then keep the
|
|
93
|
+
* owner/repo tail. Two URLs with the same identity are one rack group. */
|
|
94
|
+
export function repoIdentity(url) {
|
|
95
|
+
const s = String(url || '')
|
|
96
|
+
.replace(/^[a-z+]+:(\/\/)?/i, '') // protocol (https://, git+, github:)
|
|
97
|
+
.split('/tree/')[0] // a github /tree/<ref>/... browse URL is a view INSIDE a repo
|
|
98
|
+
.replace(/\/+$/, '')
|
|
99
|
+
.replace(/\.git$/i, '')
|
|
100
|
+
.replace(/\/+$/, '');
|
|
101
|
+
return s.split('/').slice(-2).join('/');
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** Shared tail helper: last two path segments. findDepKey keeps a residual
|
|
105
|
+
* subtree (deps may point at subfolders); repoIdentity cuts it entirely. */
|
|
106
|
+
function repoTail(url) {
|
|
107
|
+
const s = String(url || '').replace(/\.git$/i, '').replace(/\/+$/, '');
|
|
108
|
+
return s.split('/').slice(-2).join('/');
|
|
109
|
+
}
|
|
110
|
+
|
|
57
111
|
/** D4 (amended 2026-09-27): the manifest's DEPENDENCIES are the install
|
|
58
112
|
* authority. pnpm records a git plugin under the package's REAL name from
|
|
59
113
|
* its own package.json (e.g. '@temoa/dsh-rules-paths'), not the reff id -
|
|
@@ -64,8 +118,11 @@ export function parseReff(text) {
|
|
|
64
118
|
* install gate. Returns the recorded dep key (the remove target) or null. */
|
|
65
119
|
export function findDepKey(manifest, id, repo) {
|
|
66
120
|
if (manifest.deps[id] !== undefined) return id;
|
|
67
|
-
|
|
68
|
-
|
|
121
|
+
// A github /tree/<ref>/ browse URL is the same repo, not a distinct plugin
|
|
122
|
+
// (identity rule: repoIdentity, ADR-0016 D1); a residual subtree segment is
|
|
123
|
+
// kept here because deps may legitimately point at subfolders.
|
|
124
|
+
const tail = repoTail(String(repo || '').replace(/\/tree\/[^/]+(\/|$)/, '/'));
|
|
125
|
+
if (!tail || tail === '/') return null;
|
|
69
126
|
for (const [key, value] of Object.entries(manifest.deps)) {
|
|
70
127
|
if (typeof value === 'string' && value.includes(tail)) return key;
|
|
71
128
|
}
|
|
@@ -89,39 +146,71 @@ export function isInstalled(manifest, id, repo) {
|
|
|
89
146
|
return findDepKey(manifest, id, repo) !== null;
|
|
90
147
|
}
|
|
91
148
|
|
|
92
|
-
export function buildSnapshot({ reffPath, manifestPath, profile }) {
|
|
149
|
+
export function buildSnapshot({ reffPath, manifestPath, gardenPath, gardenRepo, profile }) {
|
|
93
150
|
const warnings = [];
|
|
94
|
-
if (!existsSync(reffPath)) warnings.push({ code: 'reff-missing', detail: reffPath });
|
|
95
|
-
const parsed = existsSync(reffPath) ? parseReff(readFileSync(reffPath, 'utf8')) : { plugins: [], warnings: [] };
|
|
96
|
-
warnings.push(...parsed.warnings);
|
|
97
151
|
const manifest = readManifest(manifestPath);
|
|
98
152
|
if (manifest.missing) warnings.push({ code: 'manifest-missing', detail: manifestPath });
|
|
153
|
+
const reconcile = (row) => {
|
|
154
|
+
const depKey = findDepKey(manifest, row.id, row.repo);
|
|
155
|
+
return { ...row, installed: depKey !== null, pkg: depKey, bundle: (depKey !== null && manifest.bundles.includes(depKey)) || null };
|
|
156
|
+
};
|
|
157
|
+
// Owned species first (garden scan), then external (reff) - flat rows,
|
|
158
|
+
// renumbered once; sources[] groups them by repo (shelf grammar).
|
|
159
|
+
const owned = scanGarden(gardenPath).map((row) => reconcile({ ...row, repo: gardenRepo ?? row.repo }));
|
|
160
|
+
const parsed = existsSync(reffPath) ? parseReff(readFileSync(reffPath, 'utf8')) : { plugins: [], warnings: [] };
|
|
161
|
+
warnings.push(...parsed.warnings);
|
|
162
|
+
// ADR-0016 D2/D3: an external reff row whose repository the garden already
|
|
163
|
+
// enumerates is SHADOWED — dropped here with a warning; the reff file itself
|
|
164
|
+
// is never rewritten and parseReff output is untouched.
|
|
165
|
+
const ownedIdents = new Set(owned.map((row) => repoIdentity(row.repo)));
|
|
166
|
+
const external = [];
|
|
167
|
+
for (const p of parsed.plugins) {
|
|
168
|
+
if (ownedIdents.has(repoIdentity(p.repo))) {
|
|
169
|
+
warnings.push({ code: 'reff-shadowed-by-garden', detail: p.id });
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
external.push(reconcile({
|
|
173
|
+
n: null,
|
|
174
|
+
id: p.id,
|
|
175
|
+
group: 'external',
|
|
176
|
+
repo: p.repo,
|
|
177
|
+
version: null,
|
|
178
|
+
description: null,
|
|
179
|
+
author: p.author,
|
|
180
|
+
...(p.authorUrl ? { authorUrl: p.authorUrl } : {})
|
|
181
|
+
}));
|
|
182
|
+
}
|
|
183
|
+
const plugins = [...owned, ...external].map((row, i) => ({ ...row, n: String(i + 1) }));
|
|
184
|
+
// sources[]: one collapsible group per REPOSITORY (Shelf Chrome grammar),
|
|
185
|
+
// keyed by repoIdentity (ADR-0016 D2) so /tree browse URLs never split a repo.
|
|
186
|
+
const sources = [];
|
|
187
|
+
const byRepo = new Map();
|
|
188
|
+
for (const row of plugins) {
|
|
189
|
+
const key = repoIdentity(row.repo);
|
|
190
|
+
if (!byRepo.has(key)) {
|
|
191
|
+
sources.push({
|
|
192
|
+
id: key,
|
|
193
|
+
name: key.split('/').pop(),
|
|
194
|
+
author: row.author ?? null,
|
|
195
|
+
repo: row.repo,
|
|
196
|
+
plugins: []
|
|
197
|
+
});
|
|
198
|
+
byRepo.set(key, sources[sources.length - 1]);
|
|
199
|
+
}
|
|
200
|
+
byRepo.get(key).plugins.push(row);
|
|
201
|
+
}
|
|
99
202
|
return {
|
|
100
203
|
snapshot: {
|
|
101
204
|
v: CACHE_VERSION,
|
|
102
205
|
generatedAt: new Date().toISOString(),
|
|
103
206
|
profile,
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
return {
|
|
107
|
-
n: String(i + 1),
|
|
108
|
-
id: p.id,
|
|
109
|
-
repo: p.repo,
|
|
110
|
-
author: p.author,
|
|
111
|
-
...(p.authorUrl ? { authorUrl: p.authorUrl } : {}),
|
|
112
|
-
installed: depKey !== null,
|
|
113
|
-
// The recorded dependency name (pnpm's truth) - the remove target.
|
|
114
|
-
pkg: depKey,
|
|
115
|
-
bundle: (depKey !== null && manifest.bundles.includes(depKey)) || null
|
|
116
|
-
};
|
|
117
|
-
})
|
|
207
|
+
sources,
|
|
208
|
+
plugins
|
|
118
209
|
},
|
|
119
210
|
warnings
|
|
120
211
|
};
|
|
121
212
|
}
|
|
122
213
|
|
|
123
|
-
/** D3: the reff URL becomes the dsh add spec: git+<url>.git (append .git
|
|
124
|
-
* only when absent — the operator's line stays the single source). */
|
|
125
214
|
export function toInstallSpec(repo) {
|
|
126
215
|
return 'git+' + repo + (repo.endsWith('.git') ? '' : '.git');
|
|
127
216
|
}
|
|
@@ -132,6 +221,47 @@ function resolveDshCommand(flags) {
|
|
|
132
221
|
return 'npx --yes @deepseek-ai/dsh@latest';
|
|
133
222
|
}
|
|
134
223
|
|
|
224
|
+
|
|
225
|
+
/** Owned-species install (Plugin Garden ADR, D3): write the link dependency,
|
|
226
|
+
* APPEND (never rewrite) the bundle entry, idempotent on re-run. The only
|
|
227
|
+
* manifest write the rack performs itself - scoped to @local link species;
|
|
228
|
+
* git/npm species keep the dsh add delegation (D3). Returns the dep key. */
|
|
229
|
+
export function installOwned(manifestPath, row) {
|
|
230
|
+
const doc = JSON.parse(readFileSync(manifestPath, 'utf8'));
|
|
231
|
+
doc.dependencies = doc.dependencies ?? {};
|
|
232
|
+
doc.dependencies[row.id] = row.installSpec;
|
|
233
|
+
const bundles = doc.dsh && doc.dsh.profile && Array.isArray(doc.dsh.profile.bundles) ? doc.dsh.profile.bundles : [];
|
|
234
|
+
if (!bundles.includes(row.id)) bundles.push(row.id);
|
|
235
|
+
if (doc.dsh && doc.dsh.profile) doc.dsh.profile.bundles = bundles;
|
|
236
|
+
writeFileSync(manifestPath, JSON.stringify(doc, null, 2));
|
|
237
|
+
return row.id;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/** Clobber guard (Plugin Garden ADR, 2026-10-07): a dsh plugin add rewrites
|
|
241
|
+
* the bundles array to just the new plugin and may drop earlier deps.
|
|
242
|
+
* Re-append every still-installed owned row's bundle entry and dep entry.
|
|
243
|
+
* Rows already recorded pass through untouched. */
|
|
244
|
+
export function restoreClobberedBundles(manifestPath, preOwnedRows) {
|
|
245
|
+
const doc = JSON.parse(readFileSync(manifestPath, 'utf8'));
|
|
246
|
+
let changed = false;
|
|
247
|
+
doc.dependencies = doc.dependencies ?? {};
|
|
248
|
+
const bundles = doc.dsh && doc.dsh.profile && Array.isArray(doc.dsh.profile.bundles) ? doc.dsh.profile.bundles : [];
|
|
249
|
+
for (const row of preOwnedRows) {
|
|
250
|
+
if (!row.pkg && !row.installSpec) continue;
|
|
251
|
+
if (doc.dependencies[row.id] === undefined) {
|
|
252
|
+
doc.dependencies[row.id] = row.installSpec;
|
|
253
|
+
changed = true;
|
|
254
|
+
}
|
|
255
|
+
if (!bundles.includes(row.id)) {
|
|
256
|
+
bundles.push(row.id);
|
|
257
|
+
changed = true;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
if (doc.dsh && doc.dsh.profile) doc.dsh.profile.bundles = bundles;
|
|
261
|
+
if (changed) writeFileSync(manifestPath, JSON.stringify(doc, null, 2));
|
|
262
|
+
return changed;
|
|
263
|
+
}
|
|
264
|
+
|
|
135
265
|
/** D3/D6: run dsh, relay its own diagnostics verbatim on failure. */
|
|
136
266
|
export function runDsh(flags, action, spec) {
|
|
137
267
|
const cmd = resolveDshCommand(flags) + ' plugin --profile ' + flags.profile + ' ' + action + ' ' + spec;
|
|
@@ -166,7 +296,7 @@ function main() {
|
|
|
166
296
|
console.log(JSON.stringify({ v: CACHE_VERSION, ok: true, reused: true, snapshot: loadSnapshot(cachePath) }));
|
|
167
297
|
return;
|
|
168
298
|
}
|
|
169
|
-
const { snapshot, warnings } = buildSnapshot({ reffPath, manifestPath, profile: args.profile });
|
|
299
|
+
const { snapshot, warnings } = buildSnapshot({ reffPath, manifestPath, gardenPath: args.garden, gardenRepo: args.gardenRepo, profile: args.profile });
|
|
170
300
|
mkdirSync(dirname(cachePath), { recursive: true });
|
|
171
301
|
writeFileSync(cachePath, JSON.stringify(snapshot, null, 2));
|
|
172
302
|
console.log(JSON.stringify({ v: CACHE_VERSION, ok: true, snapshot, ...(warnings.length ? { errors: warnings.map((w) => w.code + ': ' + w.detail) } : {}) }));
|
|
@@ -186,6 +316,17 @@ function main() {
|
|
|
186
316
|
if (!plugin) { results.push({ n: t, ok: false, error: 'not on the rack: ' + t }); continue; }
|
|
187
317
|
if (action === 'install') {
|
|
188
318
|
if (plugin.installed) { results.push({ n: plugin.n, id: plugin.id, ok: true, already: true }); continue; }
|
|
319
|
+
if (plugin.group === 'owned') {
|
|
320
|
+
// Owned species (Plugin Garden ADR, D3-scoped): link dep + bundles append + pnpm install.
|
|
321
|
+
const res = installOwned(manifestPath, plugin);
|
|
322
|
+
const inst = spawnSync('pnpm', ['install'], { cwd: dirname(manifestPath), encoding: 'utf8', timeout: 300000 });
|
|
323
|
+
if (inst.status !== 0) { results.push({ n: plugin.n, id: plugin.id, ok: false, error: 'pnpm install failed (exit ' + (inst.status ?? 1) + '): ' + String(inst.stderr ?? '').slice(-400) }); continue; }
|
|
324
|
+
plugin.installed = true;
|
|
325
|
+
plugin.pkg = res;
|
|
326
|
+
plugin.bundle = true;
|
|
327
|
+
results.push({ n: plugin.n, id: plugin.id, pkg: res, ok: true });
|
|
328
|
+
continue;
|
|
329
|
+
}
|
|
189
330
|
const r = runDsh(args, 'add', toInstallSpec(plugin.repo));
|
|
190
331
|
if (!r.ok) { results.push({ n: plugin.n, id: plugin.id, ok: false, error: r.error }); continue; }
|
|
191
332
|
const manifest = readManifest(manifestPath);
|
|
@@ -234,4 +375,5 @@ function fail(errors) {
|
|
|
234
375
|
process.exit(1);
|
|
235
376
|
}
|
|
236
377
|
|
|
237
|
-
|
|
378
|
+
// Run only when executed directly (not when imported by tests/other tools).
|
|
379
|
+
if (process.argv[1] && import.meta.url === new URL('file://' + process.argv[1].replace(/\\/g, '/')).href) main();
|