@navbook/cli 0.3.0 → 0.5.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 (78) hide show
  1. package/dist/args.d.ts +28 -0
  2. package/dist/args.js +48 -0
  3. package/dist/args.js.map +1 -0
  4. package/dist/commands/complete.d.ts +10 -0
  5. package/dist/commands/complete.js +59 -51
  6. package/dist/commands/complete.js.map +1 -1
  7. package/dist/commands/compose.d.ts +35 -0
  8. package/dist/commands/doctor.d.ts +15 -0
  9. package/dist/commands/entity.d.ts +73 -0
  10. package/dist/commands/entity.js +59 -44
  11. package/dist/commands/entity.js.map +1 -1
  12. package/dist/commands/init.d.ts +11 -0
  13. package/dist/commands/install.d.ts +17 -0
  14. package/dist/commands/install.js +6 -3
  15. package/dist/commands/install.js.map +1 -1
  16. package/dist/commands/issue.d.ts +35 -0
  17. package/dist/commands/issue.js +4 -5
  18. package/dist/commands/issue.js.map +1 -1
  19. package/dist/commands/plugin.d.ts +36 -0
  20. package/dist/commands/plugin.js +386 -0
  21. package/dist/commands/plugin.js.map +1 -0
  22. package/dist/commands/policy.d.ts +58 -0
  23. package/dist/commands/policy.js +28 -2
  24. package/dist/commands/policy.js.map +1 -1
  25. package/dist/commands/pr-elsewhere.d.ts +40 -0
  26. package/dist/commands/pr-elsewhere.js +209 -0
  27. package/dist/commands/pr-elsewhere.js.map +1 -0
  28. package/dist/commands/pr.d.ts +69 -0
  29. package/dist/commands/pr.js +132 -68
  30. package/dist/commands/pr.js.map +1 -1
  31. package/dist/context.d.ts +42 -0
  32. package/dist/context.js +2 -0
  33. package/dist/context.js.map +1 -1
  34. package/dist/editor.d.ts +23 -0
  35. package/dist/editor.js +4 -0
  36. package/dist/editor.js.map +1 -1
  37. package/dist/errors.d.ts +17 -0
  38. package/dist/install/completions.d.ts +19 -0
  39. package/dist/install/hook.d.ts +32 -0
  40. package/dist/install/hook.js +48 -4
  41. package/dist/install/hook.js.map +1 -1
  42. package/dist/main.d.ts +21 -0
  43. package/dist/main.js +112 -8
  44. package/dist/main.js.map +1 -1
  45. package/dist/plugins/commands.d.ts +69 -0
  46. package/dist/plugins/commands.js +148 -0
  47. package/dist/plugins/commands.js.map +1 -0
  48. package/dist/plugins/hint.d.ts +23 -0
  49. package/dist/plugins/hint.js +65 -0
  50. package/dist/plugins/hint.js.map +1 -0
  51. package/dist/plugins/host.d.ts +125 -0
  52. package/dist/plugins/host.js +18 -0
  53. package/dist/plugins/host.js.map +1 -0
  54. package/dist/plugins/loader.d.ts +54 -0
  55. package/dist/plugins/loader.js +165 -0
  56. package/dist/plugins/loader.js.map +1 -0
  57. package/dist/plugins/resolve.d.ts +50 -0
  58. package/dist/plugins/resolve.js +134 -0
  59. package/dist/plugins/resolve.js.map +1 -0
  60. package/dist/plugins/runtime.d.ts +69 -0
  61. package/dist/plugins/runtime.js +256 -0
  62. package/dist/plugins/runtime.js.map +1 -0
  63. package/dist/plugins/store.d.ts +96 -0
  64. package/dist/plugins/store.js +186 -0
  65. package/dist/plugins/store.js.map +1 -0
  66. package/dist/program.d.ts +49 -0
  67. package/dist/program.js +353 -114
  68. package/dist/program.js.map +1 -1
  69. package/dist/prompt.d.ts +31 -0
  70. package/dist/render/colors.d.ts +13 -0
  71. package/dist/render/detail.d.ts +22 -0
  72. package/dist/render/table.d.ts +32 -0
  73. package/dist/render/table.js +123 -13
  74. package/dist/render/table.js.map +1 -1
  75. package/dist/sort.d.ts +27 -0
  76. package/package.json +9 -2
  77. package/dist/commands/feature.js +0 -202
  78. package/dist/commands/feature.js.map +0 -1
@@ -0,0 +1,256 @@
1
+ /**
2
+ * The CLI's plugin runtime: what is installed, what it contributes, and when
3
+ * its code is actually loaded.
4
+ *
5
+ * One of these is built per invocation and threaded through the program. It
6
+ * holds the resolution (cheap, always done) and memoises the loading
7
+ * (expensive, done only when a declaration says it is needed).
8
+ *
9
+ * The division of labour with `program.ts` is worth stating: the program asks
10
+ * this for *declarations* while building the command tree, and for
11
+ * *implementations* inside an action. Nothing in the build phase can trigger a
12
+ * load, which is how spec 04 §4.3's rule is kept structurally rather than by
13
+ * remembering to.
14
+ */
15
+ import { commitReport } from "@navbook/core";
16
+ import { composeFile } from "../commands/compose.js";
17
+ import { openInEditor } from "../editor.js";
18
+ import { fail, failFormat } from "../errors.js";
19
+ import { askYesNo, confirmAndPerform } from "../prompt.js";
20
+ import { pad, renderTable, terminalWidth } from "../render/table.js";
21
+ import { collectCommands } from "./commands.js";
22
+ import { importEntry, loadCoreExtensions } from "./loader.js";
23
+ export class PluginRuntime {
24
+ resolved;
25
+ commands;
26
+ /** Everything worth saying on stderr once, collected while resolving. */
27
+ notices;
28
+ #ext = null;
29
+ #activated = new Map();
30
+ constructor(resolved, builtinNouns) {
31
+ this.resolved = resolved;
32
+ this.commands = collectCommands(resolved.active, builtinNouns);
33
+ this.notices = [...this.commands.problems];
34
+ }
35
+ /** True when no plugin is installed, which is the common case. */
36
+ get empty() {
37
+ return this.resolved.active.length === 0;
38
+ }
39
+ /**
40
+ * Whether this command line needs the format extensions loaded.
41
+ *
42
+ * Decided from the manifests and the words typed, before anything parses,
43
+ * because loading them means importing plugin code — and spec 04 §4.3 says
44
+ * no plugin code is loaded for a command whose declaration does not name it.
45
+ * `nav issue list` with five plugins installed answers false here and
46
+ * imports nothing.
47
+ *
48
+ * The four cases that answer true:
49
+ *
50
+ * - a plugin noun is the first word, and its declaration asks for core;
51
+ * - a plugin contributes to this exact `noun verb`;
52
+ * - a term on the line names a query key a plugin declared;
53
+ * - the command is `doctor`, which runs every registered check.
54
+ */
55
+ needsCoreFor(argv) {
56
+ if (this.empty)
57
+ return false;
58
+ // `--help` runs no command: Commander prints what the manifests already
59
+ // built and exits, so there is nothing for an extension to be needed by.
60
+ if (argv.some((word) => word === "--help" || word === "-h"))
61
+ return false;
62
+ const words = argv.filter((word) => !word.startsWith("-"));
63
+ // `__complete` is a stand-in for whatever is being typed, so the decision
64
+ // is made about *that*: completing `nav issue list` must load whatever
65
+ // completing `nav issue list` would.
66
+ //
67
+ // With one exception. A plugin noun on its own — `nav probe <TAB>` — is
68
+ // answered with its verb names, which come from the manifest, so it costs
69
+ // nothing. Only once a verb is on the line can completion reach an
70
+ // argument completer or a query term, and only then is the tree needed.
71
+ const completing = words[0] === "__complete";
72
+ if (completing) {
73
+ words.shift();
74
+ if (words.length <= 1)
75
+ return false;
76
+ }
77
+ const [noun, verb] = words;
78
+ if (noun === undefined)
79
+ return false;
80
+ if (noun === "doctor")
81
+ return true;
82
+ const declared = this.commands.nouns.get(noun);
83
+ if (declared !== undefined) {
84
+ // A noun's own commands default to needing core: nearly all of them read
85
+ // the tree, and a plugin that does not can say so.
86
+ const leaf = (declared.spec.commands ?? []).find((child) => child.name === verb);
87
+ return (leaf ?? declared.spec).needsCore !== false;
88
+ }
89
+ if (verb !== undefined && this.commands.contributions.has(`${noun} ${verb}`))
90
+ return true;
91
+ const keys = new Set(this.queryKeys().map((key) => `${key.key}:`));
92
+ return argv.some((word) => {
93
+ const colon = word.indexOf(":");
94
+ return colon > 0 && keys.has(word.slice(0, colon + 1));
95
+ });
96
+ }
97
+ /** Plugins whose commands are still usable after collision checking. */
98
+ get usable() {
99
+ return this.resolved.active.filter((plugin) => !this.commands.skipped.has(plugin.name));
100
+ }
101
+ /**
102
+ * The query terms usable plugins declared, for one noun or for either.
103
+ *
104
+ * From the manifests, so help and completion can offer them without loading
105
+ * a line of plugin code (spec 04 §4.3).
106
+ */
107
+ queryKeys(kind) {
108
+ return this.usable.flatMap((plugin) => (plugin.manifest.core?.queryKeys ?? []).filter((key) => kind === undefined || key.kinds.includes(kind)));
109
+ }
110
+ /**
111
+ * The registered format extensions, loading the `./core` entries once.
112
+ *
113
+ * Everything that reads or validates a tree needs these; nothing else does.
114
+ * The caller decides whether this invocation is one of those, which is where
115
+ * the startup budget is actually spent or saved.
116
+ */
117
+ async coreExtensions(ctx) {
118
+ if (this.#ext !== null)
119
+ return this.#ext;
120
+ const { ext, problems } = await loadCoreExtensions(this.usable);
121
+ for (const line of problems)
122
+ ctx.stderr.write(`${line}\n`);
123
+ this.#ext = ext;
124
+ return ext;
125
+ }
126
+ /** What a plugin registered for a verb, loading its `./cli` entry if needed. */
127
+ async handlersFor(ctx, verb) {
128
+ const declared = this.commands.contributions.get(verb) ?? [];
129
+ const out = [];
130
+ for (const { plugin } of declared) {
131
+ const activated = await this.#activate(ctx, plugin);
132
+ const handlers = activated?.handlers.get(verb);
133
+ if (handlers !== undefined)
134
+ out.push(handlers);
135
+ }
136
+ return out;
137
+ }
138
+ /** Run a plugin command, loading its `./cli` entry. */
139
+ async run(ctx, plugin, path, args, opts) {
140
+ const activated = await this.#activate(ctx, plugin);
141
+ // Why it did not load is already on stderr; saying it does not implement
142
+ // the command would blame the plugin for what may be a missing package.
143
+ if (activated === null)
144
+ fail(`cannot run '${path}': plugin ${plugin.name} did not load`);
145
+ const run = activated.commands.get(path);
146
+ if (run === undefined) {
147
+ fail(`plugin ${plugin.name} declares '${path}' but does not implement it`);
148
+ }
149
+ await run(args, opts);
150
+ }
151
+ /** Completion candidates a plugin offers for a declared completer. */
152
+ async completions(ctx, plugin, id, words) {
153
+ const activated = await this.#activate(ctx, plugin);
154
+ return activated?.completers.get(id)?.(words) ?? [];
155
+ }
156
+ /** Activate a plugin's CLI entry once per process. */
157
+ async #activate(ctx, plugin) {
158
+ const existing = this.#activated.get(plugin.name);
159
+ if (existing !== undefined)
160
+ return existing;
161
+ const entry = await importEntry(plugin, "cli").catch((error) => {
162
+ ctx.stderr.write(`nav: plugin ${plugin.name} could not be loaded: ${message(error)}\n`);
163
+ return null;
164
+ });
165
+ if (entry === null) {
166
+ ctx.stderr.write(`nav: plugin ${plugin.name} has no './cli' entry\n`);
167
+ return null;
168
+ }
169
+ if (typeof entry.activate !== "function") {
170
+ ctx.stderr.write(`nav: plugin ${plugin.name} exports no activate() from './cli'\n`);
171
+ return null;
172
+ }
173
+ const activated = {
174
+ commands: new Map(),
175
+ handlers: new Map(),
176
+ completers: new Map(),
177
+ };
178
+ const declaredPaths = declaredCommandPaths(plugin);
179
+ const declaredVerbs = new Set((plugin.manifest.cli?.contributions ?? []).map((contribution) => contribution.on));
180
+ const host = {
181
+ core: await coreModule(),
182
+ manifest: plugin.manifest,
183
+ settings: plugin.settings,
184
+ // The core registrations happen through `coreExtensions`; a CLI entry
185
+ // calling `register` is registering for nothing, so it is refused rather
186
+ // than silently ignored.
187
+ register: () => {
188
+ fail(`plugin ${plugin.name}: register() belongs in './core', not './cli'`);
189
+ },
190
+ ctx,
191
+ command: (path, run) => {
192
+ if (!declaredPaths.has(path)) {
193
+ ctx.stderr.write(`nav: plugin ${plugin.name} implements '${path}', which its manifest does not declare\n`);
194
+ return;
195
+ }
196
+ activated.commands.set(path, run);
197
+ },
198
+ contribute: (on, handlers) => {
199
+ if (!declaredVerbs.has(on)) {
200
+ ctx.stderr.write(`nav: plugin ${plugin.name} contributes to '${on}', which its manifest does not declare\n`);
201
+ return;
202
+ }
203
+ activated.handlers.set(on, handlers);
204
+ },
205
+ completer: (id, complete) => void activated.completers.set(id, complete),
206
+ ui: makeUi(ctx),
207
+ };
208
+ try {
209
+ await entry.activate(host);
210
+ }
211
+ catch (error) {
212
+ ctx.stderr.write(`nav: plugin ${plugin.name} failed to activate: ${message(error)}\n`);
213
+ return null;
214
+ }
215
+ this.#activated.set(plugin.name, activated);
216
+ return activated;
217
+ }
218
+ }
219
+ /** Every command path a plugin's manifest declares, `noun verb` style. */
220
+ function declaredCommandPaths(plugin) {
221
+ const paths = new Set();
222
+ const walk = (specs, prefix) => {
223
+ for (const spec of specs) {
224
+ const path = prefix === "" ? spec.name : `${prefix} ${spec.name}`;
225
+ const children = spec.commands;
226
+ if (children?.length)
227
+ walk(children, path);
228
+ else
229
+ paths.add(path);
230
+ }
231
+ };
232
+ walk(plugin.manifest.cli?.commands ?? [], "");
233
+ return paths;
234
+ }
235
+ /** The running core, imported once and shared with every plugin. */
236
+ async function coreModule() {
237
+ return await import("@navbook/core");
238
+ }
239
+ function makeUi(ctx) {
240
+ return {
241
+ fail: (message, details) => fail(message, details ?? []),
242
+ failFormat: (message, details) => failFormat(message, details ?? []),
243
+ askYesNo: (question) => askYesNo(ctx, question),
244
+ confirmAndPerform: (opts) => confirmAndPerform(ctx, opts),
245
+ composeFile: (opts) => composeFile(ctx, opts),
246
+ editFile: (path) => openInEditor(ctx, path),
247
+ renderTable: (columns, rows) => renderTable([...columns], rows, { colors: ctx.colors, width: terminalWidth(ctx.stdout) }),
248
+ pad,
249
+ commitReport,
250
+ collect: (value, previous = []) => [...previous, value],
251
+ };
252
+ }
253
+ function message(error) {
254
+ return error instanceof Error ? error.message : String(error);
255
+ }
256
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/plugins/runtime.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * The per-user plugin store — spec 04 §4.3.
3
+ *
4
+ * Plugins live in a directory `nav` owns rather than beside `nav` itself,
5
+ * because where `nav` itself lives is not knowable: it may have arrived by
6
+ * `npm -g`, by pnpm, through a version manager, or not be installed at all
7
+ * under `npx`. A directory of our own works the same way in every one of those.
8
+ *
9
+ * The store is an ordinary npm project — a `package.json` and a `node_modules`
10
+ * — so resolution, transitive dependencies and updates are npm's problem and
11
+ * not ours. What we add on top is `plugins.json`: an index of what is
12
+ * installed, with each plugin's manifest copied into it. That file is why
13
+ * startup costs one read. Scanning `node_modules` to find out what is there
14
+ * would cost a directory walk and a `package.json` parse per plugin on every
15
+ * single `nav` invocation, which is the cost spec 05 §5.2 says we cannot pay —
16
+ * and is exactly the mistake Prettier removed its plugin search for.
17
+ */
18
+ import { type PluginManifest } from "@navbook/core";
19
+ /** Where the store lives, honouring `$XDG_DATA_HOME` (spec 04 §4.3). */
20
+ export declare function storeDir(env: NodeJS.ProcessEnv): string;
21
+ /** One installed plugin, as the index records it. */
22
+ export interface IndexedPlugin {
23
+ name: string;
24
+ version: string;
25
+ /** Absolute path to the package directory inside the store. */
26
+ dir: string;
27
+ /** The `engines.navbook` range, or null when the plugin names none. */
28
+ engines: string | null;
29
+ /**
30
+ * The manifest, copied at install time.
31
+ *
32
+ * A copy rather than a reference to the package's own `package.json`,
33
+ * because reading that file is precisely the work the index exists to avoid.
34
+ * It goes stale only when the package is replaced, and replacing it goes
35
+ * through `nav plugin`, which rewrites the index.
36
+ */
37
+ manifest: PluginManifest;
38
+ }
39
+ export interface PluginIndex {
40
+ version: 1;
41
+ plugins: Record<string, IndexedPlugin>;
42
+ }
43
+ export declare function indexPath(env: NodeJS.ProcessEnv): string;
44
+ /**
45
+ * Read the index, or null when there is none.
46
+ *
47
+ * Null for every fault — no store, no file, unreadable, not JSON, a version
48
+ * from some future `nav`. A store this `nav` cannot read is a store with no
49
+ * plugins in it as far as this run is concerned, and refusing to list issues
50
+ * because of a file in the user's data directory would be absurd. The repair
51
+ * is `nav plugin install`, which rewrites it.
52
+ */
53
+ export declare function readIndex(env: NodeJS.ProcessEnv): PluginIndex | null;
54
+ export declare function writeIndex(env: NodeJS.ProcessEnv, index: PluginIndex): void;
55
+ /** Create the store's own `package.json` if it is not there yet. */
56
+ export declare function ensureStore(env: NodeJS.ProcessEnv): string;
57
+ export interface NpmResult {
58
+ ok: boolean;
59
+ /** Everything npm said, for a failure worth showing in full. */
60
+ output: string;
61
+ }
62
+ /**
63
+ * The npm command a given install would run, as a string to print.
64
+ *
65
+ * Printed before it runs (spec 04 §4.3), so that what the user agrees to is
66
+ * the command rather than a summary of it.
67
+ */
68
+ export declare function installCommand(specs: readonly string[]): string;
69
+ /** Run npm in the store. Its output is captured rather than streamed. */
70
+ export declare function npmInstall(env: NodeJS.ProcessEnv, specs: readonly string[]): NpmResult;
71
+ export declare function npmRemove(env: NodeJS.ProcessEnv, names: readonly string[]): NpmResult;
72
+ /**
73
+ * Read an installed package directory as a plugin.
74
+ *
75
+ * Used at install time to check what npm actually fetched, and by
76
+ * `NAVBOOK_PLUGIN_PATH` to read a plugin nobody installed. Faults come back as
77
+ * a message so the caller can name the directory alongside them.
78
+ */
79
+ export declare function readPluginAt(dir: string): IndexedPlugin | {
80
+ error: string;
81
+ };
82
+ /** Where npm put a package inside the store. */
83
+ export declare function packageDir(env: NodeJS.ProcessEnv, name: string): string;
84
+ /**
85
+ * The packages the store depends on, as npm recorded them: each real package
86
+ * name, and the specifier npm saved for it.
87
+ *
88
+ * What was *asked* for and what was *installed* are not the same string: a
89
+ * tarball path, a git URL and a short name all resolve to a package whose real
90
+ * name is inside it, and looking in `node_modules/<what-was-typed>` finds
91
+ * nothing. npm writes the real name into the store's own `package.json`, so
92
+ * reading it back — before an install and again after — is how an install
93
+ * learns what it actually got. The specifier is kept too, because a new
94
+ * version of a plugin already installed changes it without adding a name.
95
+ */
96
+ export declare function storeDependencies(env: NodeJS.ProcessEnv): Record<string, string>;
@@ -0,0 +1,186 @@
1
+ /**
2
+ * The per-user plugin store — spec 04 §4.3.
3
+ *
4
+ * Plugins live in a directory `nav` owns rather than beside `nav` itself,
5
+ * because where `nav` itself lives is not knowable: it may have arrived by
6
+ * `npm -g`, by pnpm, through a version manager, or not be installed at all
7
+ * under `npx`. A directory of our own works the same way in every one of those.
8
+ *
9
+ * The store is an ordinary npm project — a `package.json` and a `node_modules`
10
+ * — so resolution, transitive dependencies and updates are npm's problem and
11
+ * not ours. What we add on top is `plugins.json`: an index of what is
12
+ * installed, with each plugin's manifest copied into it. That file is why
13
+ * startup costs one read. Scanning `node_modules` to find out what is there
14
+ * would cost a directory walk and a `package.json` parse per plugin on every
15
+ * single `nav` invocation, which is the cost spec 05 §5.2 says we cannot pay —
16
+ * and is exactly the mistake Prettier removed its plugin search for.
17
+ */
18
+ import { spawnSync } from "node:child_process";
19
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
20
+ import { join } from "node:path";
21
+ import { parsePluginPackage } from "@navbook/core";
22
+ /** Where the store lives, honouring `$XDG_DATA_HOME` (spec 04 §4.3). */
23
+ export function storeDir(env) {
24
+ const xdg = env.XDG_DATA_HOME;
25
+ if (xdg !== undefined && xdg.trim() !== "")
26
+ return join(xdg, "navbook", "plugins");
27
+ const home = env.HOME ?? env.USERPROFILE ?? "";
28
+ return join(home, ".local", "share", "navbook", "plugins");
29
+ }
30
+ const INDEX_FILE = "plugins.json";
31
+ const STORE_PACKAGE = {
32
+ name: "navbook-plugins",
33
+ private: true,
34
+ description: "Plugins installed for the nav CLI. Managed by `nav plugin`.",
35
+ version: "1.0.0",
36
+ };
37
+ export function indexPath(env) {
38
+ return join(storeDir(env), INDEX_FILE);
39
+ }
40
+ /**
41
+ * Read the index, or null when there is none.
42
+ *
43
+ * Null for every fault — no store, no file, unreadable, not JSON, a version
44
+ * from some future `nav`. A store this `nav` cannot read is a store with no
45
+ * plugins in it as far as this run is concerned, and refusing to list issues
46
+ * because of a file in the user's data directory would be absurd. The repair
47
+ * is `nav plugin install`, which rewrites it.
48
+ */
49
+ export function readIndex(env) {
50
+ const path = indexPath(env);
51
+ if (!existsSync(path))
52
+ return null;
53
+ try {
54
+ const parsed = JSON.parse(readFileSync(path, "utf8"));
55
+ if (parsed.version !== 1 || typeof parsed.plugins !== "object" || parsed.plugins === null) {
56
+ return null;
57
+ }
58
+ return parsed;
59
+ }
60
+ catch {
61
+ return null;
62
+ }
63
+ }
64
+ export function writeIndex(env, index) {
65
+ const dir = storeDir(env);
66
+ mkdirSync(dir, { recursive: true });
67
+ writeFileSync(join(dir, INDEX_FILE), `${JSON.stringify(index, null, 2)}\n`);
68
+ }
69
+ /** Create the store's own `package.json` if it is not there yet. */
70
+ export function ensureStore(env) {
71
+ const dir = storeDir(env);
72
+ mkdirSync(dir, { recursive: true });
73
+ const manifest = join(dir, "package.json");
74
+ if (!existsSync(manifest)) {
75
+ writeFileSync(manifest, `${JSON.stringify(STORE_PACKAGE, null, 2)}\n`);
76
+ }
77
+ return dir;
78
+ }
79
+ /**
80
+ * The npm command a given install would run, as a string to print.
81
+ *
82
+ * Printed before it runs (spec 04 §4.3), so that what the user agrees to is
83
+ * the command rather than a summary of it.
84
+ */
85
+ export function installCommand(specs) {
86
+ return `npm ${installArgs(specs).join(" ")}`;
87
+ }
88
+ function installArgs(specs) {
89
+ return [
90
+ "install",
91
+ // A plugin is code somebody chose to install, but its *dependencies* are
92
+ // not, and a postinstall script is the classic way a package does
93
+ // something nobody asked for. npm runs none of them here.
94
+ "--ignore-scripts",
95
+ // The pair that keeps a second `@navbook/core` out of the store. A plugin
96
+ // declares core as a peer for its types; installing peers would give it a
97
+ // copy of its own, and then `instanceof WorkspaceError` would be false
98
+ // across the boundary and the YAML parser would be loaded twice.
99
+ // `--omit=peer` alone only leaves peers off the disk: npm still resolves
100
+ // them, from the registry, and refuses the install when a web half's
101
+ // optional framework peers do not reconcile. `--legacy-peer-deps` stops it
102
+ // resolving them at all — the host provides every one.
103
+ "--omit=peer",
104
+ "--legacy-peer-deps",
105
+ "--no-audit",
106
+ "--no-fund",
107
+ "--save-exact",
108
+ ...specs,
109
+ ];
110
+ }
111
+ /** Run npm in the store. Its output is captured rather than streamed. */
112
+ export function npmInstall(env, specs) {
113
+ return runNpm(env, installArgs(specs));
114
+ }
115
+ export function npmRemove(env, names) {
116
+ return runNpm(env, ["uninstall", "--no-audit", "--no-fund", ...names]);
117
+ }
118
+ function runNpm(env, args) {
119
+ const dir = ensureStore(env);
120
+ const result = spawnSync("npm", [...args], {
121
+ cwd: dir,
122
+ encoding: "utf8",
123
+ // npm is a shell script on Windows; everywhere Navbook supports it is not.
124
+ shell: false,
125
+ env: { ...env },
126
+ });
127
+ if (result.error)
128
+ return { ok: false, output: result.error.message };
129
+ return {
130
+ ok: result.status === 0,
131
+ output: `${result.stdout ?? ""}${result.stderr ?? ""}`.trim(),
132
+ };
133
+ }
134
+ /**
135
+ * Read an installed package directory as a plugin.
136
+ *
137
+ * Used at install time to check what npm actually fetched, and by
138
+ * `NAVBOOK_PLUGIN_PATH` to read a plugin nobody installed. Faults come back as
139
+ * a message so the caller can name the directory alongside them.
140
+ */
141
+ export function readPluginAt(dir) {
142
+ const manifestPath = join(dir, "package.json");
143
+ let raw;
144
+ try {
145
+ raw = JSON.parse(readFileSync(manifestPath, "utf8"));
146
+ }
147
+ catch (error) {
148
+ return { error: `${manifestPath}: ${error instanceof Error ? error.message : String(error)}` };
149
+ }
150
+ const read = parsePluginPackage(raw);
151
+ if (!read.ok)
152
+ return { error: read.error };
153
+ return {
154
+ name: read.plugin.name,
155
+ version: read.plugin.version,
156
+ dir,
157
+ engines: read.plugin.engines,
158
+ manifest: read.plugin.manifest,
159
+ };
160
+ }
161
+ /** Where npm put a package inside the store. */
162
+ export function packageDir(env, name) {
163
+ return join(storeDir(env), "node_modules", ...name.split("/"));
164
+ }
165
+ /**
166
+ * The packages the store depends on, as npm recorded them: each real package
167
+ * name, and the specifier npm saved for it.
168
+ *
169
+ * What was *asked* for and what was *installed* are not the same string: a
170
+ * tarball path, a git URL and a short name all resolve to a package whose real
171
+ * name is inside it, and looking in `node_modules/<what-was-typed>` finds
172
+ * nothing. npm writes the real name into the store's own `package.json`, so
173
+ * reading it back — before an install and again after — is how an install
174
+ * learns what it actually got. The specifier is kept too, because a new
175
+ * version of a plugin already installed changes it without adding a name.
176
+ */
177
+ export function storeDependencies(env) {
178
+ try {
179
+ const pkg = JSON.parse(readFileSync(join(storeDir(env), "package.json"), "utf8"));
180
+ return { ...(pkg.dependencies ?? {}) };
181
+ }
182
+ catch {
183
+ return {};
184
+ }
185
+ }
186
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/plugins/store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Command tree — spec 04 §4.3: noun-verb, with one verb vocabulary shared by
3
+ * both entity kinds, plus root-level utilities.
4
+ */
5
+ import { type EntityKind } from "@navbook/core";
6
+ import { Command, Option } from "commander";
7
+ import { type CloseOptions, type ExtraColumn } from "./commands/entity.ts";
8
+ import type { Ctx, GetCtx } from "./context.ts";
9
+ import type { PluginRuntime } from "./plugins/runtime.ts";
10
+ export declare const VERSION: string;
11
+ /**
12
+ * A plugin's declared `help` line as rows of the table above.
13
+ *
14
+ * The manifest writes it as the built-in rows read, syntax then a gap then
15
+ * the hint; it is re-aligned here so a plugin need not know the column this
16
+ * help happens to use. A line with no gap is all syntax, and a syntax too wide
17
+ * for its column puts the hint on the next line rather than against it.
18
+ */
19
+ export declare function pluginHelpRow(help: string): string[];
20
+ /**
21
+ * The nouns and utilities this CLI defines, which a plugin may not take.
22
+ *
23
+ * Kept as data because two things read it: the collision check that refuses a
24
+ * plugin claiming one of these (spec 04 §4.3), and completion, which offers
25
+ * them alongside whatever plugins added.
26
+ */
27
+ export declare const BUILTIN_NOUNS: readonly ["issue", "pr", "plugin", "init", "id", "doctor", "install", "uninstall"];
28
+ export declare function buildProgram(getCtx: GetCtx, plugins?: PluginRuntime): Command;
29
+ export interface SharedVerbOptions {
30
+ extraColumns: ExtraColumn[];
31
+ /** The plugin runtime, when this invocation has one. */
32
+ plugins?: PluginRuntime;
33
+ /** The noun these verbs hang off, for looking a contribution up by name. */
34
+ verbPrefix?: string;
35
+ /** Extra options the noun's `list` accepts, e.g. `--all-refs` for PRs. */
36
+ configureList?: (command: Command) => void;
37
+ /** Extra options the noun's `show` accepts, e.g. `--depth` for issues. */
38
+ configureShow?: (command: Command) => void;
39
+ /** Extra options the noun's `delete` accepts, e.g. `--recursive` for issues. */
40
+ configureDelete?: (command: Command) => void;
41
+ /** Listing implementation, when the noun needs more than the shared one. */
42
+ runList?: (ctx: Ctx, terms: string[], options: Record<string, unknown>) => void;
43
+ /** Close implementation, when the noun needs more than the shared one. */
44
+ runClose?: (ctx: Ctx, id: string, options: CloseOptions) => void;
45
+ }
46
+ /** Register the verbs both nouns share, so their behavior can never drift. */
47
+ export declare function addSharedVerbs(parent: Command, kind: EntityKind, getCtx: () => Ctx, shared: SharedVerbOptions): void;
48
+ export declare function collect(value: string, previous: string[]): string[];
49
+ export { Option };