@procedures/mark 0.45.0 → 0.47.1
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/CHANGELOG.md +65 -0
- package/README.md +7 -1
- package/dist/.tsbuildinfo +1 -1
- package/dist/bin.d.ts +3 -0
- package/dist/bin.d.ts.map +1 -1
- package/dist/bin.js +6 -1
- package/dist/bin.js.map +1 -1
- package/dist/cli.d.ts +8 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +44 -4
- package/dist/cli.js.map +1 -1
- package/dist/compile-cache.d.ts +31 -0
- package/dist/compile-cache.d.ts.map +1 -0
- package/dist/compile-cache.js +45 -0
- package/dist/compile-cache.js.map +1 -0
- package/dist/ecosystem.d.ts +26 -2
- package/dist/ecosystem.d.ts.map +1 -1
- package/dist/ecosystem.js +106 -8
- package/dist/ecosystem.js.map +1 -1
- package/dist/manifest-build.js +3 -2
- package/dist/manifest-build.js.map +1 -1
- package/dist/manifest.d.ts +17 -6
- package/dist/manifest.d.ts.map +1 -1
- package/dist/manifest.js +15 -8
- package/dist/manifest.js.map +1 -1
- package/dist/manifest.json +1054 -120
- package/dist/print.d.ts.map +1 -1
- package/dist/print.js +9 -1
- package/dist/print.js.map +1 -1
- package/package.json +52 -52
- package/src/bin.ts +7 -1
- package/src/cli.ts +44 -4
- package/src/compile-cache.ts +51 -0
- package/src/ecosystem.ts +115 -8
- package/src/manifest-build.ts +3 -2
- package/src/manifest.ts +27 -8
- package/src/print.ts +11 -1
package/dist/print.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"print.d.ts","sourceRoot":"","sources":["../src/print.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"print.d.ts","sourceRoot":"","sources":["../src/print.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAa1B;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,OAAO,EAAE,CAAC,OAAO,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,IAAI,EAAE,CAAC,OAAO,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,eAAO,MAAM,KAAK;IAEhB,IAAI,QAAQ,MAAM,KAAG,IAAI;IAIzB,OAAO,QAAQ,MAAM,KAAG,IAAI;IAI5B,KAAK,QAAQ,MAAM,KAAG,IAAI;IAI1B,OAAO,QAAQ,MAAM,KAAG,IAAI;IAI5B,KAAK,QAAQ,MAAM,KAAG,IAAI;IAI1B,SAAS,QAAQ,MAAM,KAAG,IAAI;IAK9B,IAAI,QAAQ,MAAM,KAAG,OAAO;IAgB5B,KAAK,SAAS,MAAM,EAAE,EAAE,aAAa;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,KAAG,IAAI;IAuB/D,OAAO,QAAM,IAAI;IAKjB,OAAO,QAAM,IAAI;CAGlB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC;AAEjC;;GAEG;AACH,OAAO,EAAE,KAAK,EAAE,CAAC"}
|
package/dist/print.js
CHANGED
|
@@ -6,7 +6,14 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import chalk from "chalk";
|
|
8
8
|
import ora from "ora";
|
|
9
|
-
import
|
|
9
|
+
import { createRequire } from "node:module";
|
|
10
|
+
/**
|
|
11
|
+
* This function gives the table class of `cli-table3`. The first table loads the package, not the
|
|
12
|
+
* start of `mark`: a call that prints no table does not load it (roadmap O93).
|
|
13
|
+
*/
|
|
14
|
+
function tableClass() {
|
|
15
|
+
return createRequire(import.meta.url)("cli-table3");
|
|
16
|
+
}
|
|
10
17
|
/**
|
|
11
18
|
* Print utilities
|
|
12
19
|
*/
|
|
@@ -52,6 +59,7 @@ export const print = {
|
|
|
52
59
|
const [headers, ...rows] = data;
|
|
53
60
|
if (!headers)
|
|
54
61
|
return;
|
|
62
|
+
const Table = tableClass();
|
|
55
63
|
const table = new Table({
|
|
56
64
|
head: headers.map((h) => chalk.bold(h)),
|
|
57
65
|
style: {
|
package/dist/print.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"print.js","sourceRoot":"","sources":["../src/print.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,
|
|
1
|
+
{"version":3,"file":"print.js","sourceRoot":"","sources":["../src/print.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package",
|
|
3
3
|
"name": "@procedures/mark",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.47.1",
|
|
5
5
|
"description": "mark: one CLI for every procedure package. It finds the procedures, parses flags by their Zod types, runs local or through a fast warm server, and asks for missing arguments.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"cli",
|
|
@@ -52,18 +52,18 @@
|
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
54
|
"@mark1russell7/service": "^0.6.0",
|
|
55
|
-
"@procedures/cli-kit": "0.
|
|
56
|
-
"@procedures/cli-run": "0.
|
|
57
|
-
"@procedures/client": "0.
|
|
58
|
-
"@procedures/fs": "0.
|
|
59
|
-
"@procedures/lib": "0.
|
|
60
|
-
"@procedures/mcp-dev-tools": "0.
|
|
61
|
-
"@procedures/peer": "0.
|
|
62
|
-
"@procedures/pnpm": "0.
|
|
63
|
-
"@procedures/procedure": "0.
|
|
64
|
-
"@procedures/server": "0.
|
|
65
|
-
"@procedures/shell": "0.
|
|
66
|
-
"@procedures/vitest": "0.
|
|
55
|
+
"@procedures/cli-kit": "0.47.1",
|
|
56
|
+
"@procedures/cli-run": "0.47.1",
|
|
57
|
+
"@procedures/client": "0.47.1",
|
|
58
|
+
"@procedures/fs": "0.47.1",
|
|
59
|
+
"@procedures/lib": "0.47.1",
|
|
60
|
+
"@procedures/mcp-dev-tools": "0.47.1",
|
|
61
|
+
"@procedures/peer": "0.47.1",
|
|
62
|
+
"@procedures/pnpm": "0.47.1",
|
|
63
|
+
"@procedures/procedure": "0.47.1",
|
|
64
|
+
"@procedures/server": "0.47.1",
|
|
65
|
+
"@procedures/shell": "0.47.1",
|
|
66
|
+
"@procedures/vitest": "0.47.1",
|
|
67
67
|
"chalk": "^5.3.0",
|
|
68
68
|
"cli-table3": "^0.6.5",
|
|
69
69
|
"ora": "^8.0.0",
|
|
@@ -71,44 +71,44 @@
|
|
|
71
71
|
"zod": "^4.6.5"
|
|
72
72
|
},
|
|
73
73
|
"devDependencies": {
|
|
74
|
-
"@mark1russell7/cue": "^1.
|
|
75
|
-
"@procedures/archive": "0.
|
|
76
|
-
"@procedures/bundle-assistant": "0.
|
|
77
|
-
"@procedures/bundle-dev": "0.
|
|
78
|
-
"@procedures/bundle-mcp": "0.
|
|
79
|
-
"@procedures/claude-cli": "0.
|
|
80
|
-
"@procedures/compiler": "0.
|
|
81
|
-
"@procedures/cue": "0.
|
|
82
|
-
"@procedures/dag": "0.
|
|
83
|
-
"@procedures/docker": "0.
|
|
84
|
-
"@procedures/env": "0.
|
|
85
|
-
"@procedures/exif": "0.
|
|
86
|
-
"@procedures/geo": "0.
|
|
87
|
-
"@procedures/gh": "0.
|
|
88
|
-
"@procedures/git": "0.
|
|
89
|
-
"@procedures/http": "0.
|
|
90
|
-
"@procedures/ics": "0.
|
|
91
|
-
"@procedures/ios-backup": "0.
|
|
92
|
-
"@procedures/json": "0.
|
|
93
|
-
"@procedures/llm": "0.
|
|
94
|
-
"@procedures/mail": "0.
|
|
95
|
-
"@procedures/mongo": "0.
|
|
96
|
-
"@procedures/node": "0.
|
|
97
|
-
"@procedures/notify": "0.
|
|
98
|
-
"@procedures/npm": "0.
|
|
99
|
-
"@procedures/pdf": "0.
|
|
100
|
-
"@procedures/privacy-scan": "0.
|
|
101
|
-
"@procedures/restic": "0.
|
|
102
|
-
"@procedures/s3": "0.
|
|
103
|
-
"@procedures/schedule": "0.
|
|
104
|
-
"@procedures/snapshot": "0.
|
|
105
|
-
"@procedures/splay": "0.
|
|
106
|
-
"@procedures/sqlite": "0.
|
|
107
|
-
"@procedures/store": "0.
|
|
108
|
-
"@procedures/systems": "0.
|
|
109
|
-
"@procedures/tailscale": "0.
|
|
110
|
-
"@procedures/vite": "0.
|
|
111
|
-
"@procedures/weather": "0.
|
|
74
|
+
"@mark1russell7/cue": "^1.1.0",
|
|
75
|
+
"@procedures/archive": "0.47.1",
|
|
76
|
+
"@procedures/bundle-assistant": "0.47.1",
|
|
77
|
+
"@procedures/bundle-dev": "0.47.1",
|
|
78
|
+
"@procedures/bundle-mcp": "0.47.1",
|
|
79
|
+
"@procedures/claude-cli": "0.47.1",
|
|
80
|
+
"@procedures/compiler": "0.47.1",
|
|
81
|
+
"@procedures/cue": "0.47.1",
|
|
82
|
+
"@procedures/dag": "0.47.1",
|
|
83
|
+
"@procedures/docker": "0.47.1",
|
|
84
|
+
"@procedures/env": "0.47.1",
|
|
85
|
+
"@procedures/exif": "0.47.1",
|
|
86
|
+
"@procedures/geo": "0.47.1",
|
|
87
|
+
"@procedures/gh": "0.47.1",
|
|
88
|
+
"@procedures/git": "0.47.1",
|
|
89
|
+
"@procedures/http": "0.47.1",
|
|
90
|
+
"@procedures/ics": "0.47.1",
|
|
91
|
+
"@procedures/ios-backup": "0.47.1",
|
|
92
|
+
"@procedures/json": "0.47.1",
|
|
93
|
+
"@procedures/llm": "0.47.1",
|
|
94
|
+
"@procedures/mail": "0.47.1",
|
|
95
|
+
"@procedures/mongo": "0.47.1",
|
|
96
|
+
"@procedures/node": "0.47.1",
|
|
97
|
+
"@procedures/notify": "0.47.1",
|
|
98
|
+
"@procedures/npm": "0.47.1",
|
|
99
|
+
"@procedures/pdf": "0.47.1",
|
|
100
|
+
"@procedures/privacy-scan": "0.47.1",
|
|
101
|
+
"@procedures/restic": "0.47.1",
|
|
102
|
+
"@procedures/s3": "0.47.1",
|
|
103
|
+
"@procedures/schedule": "0.47.1",
|
|
104
|
+
"@procedures/snapshot": "0.47.1",
|
|
105
|
+
"@procedures/splay": "0.47.1",
|
|
106
|
+
"@procedures/sqlite": "0.47.1",
|
|
107
|
+
"@procedures/store": "0.47.1",
|
|
108
|
+
"@procedures/systems": "0.47.1",
|
|
109
|
+
"@procedures/tailscale": "0.47.1",
|
|
110
|
+
"@procedures/vite": "0.47.1",
|
|
111
|
+
"@procedures/weather": "0.47.1",
|
|
112
112
|
"@types/node": "^22.0.0",
|
|
113
113
|
"fast-check": "^4.10.2",
|
|
114
114
|
"typescript": "^7.0.2",
|
|
@@ -116,7 +116,7 @@
|
|
|
116
116
|
},
|
|
117
117
|
"scripts": {
|
|
118
118
|
"build": "tsc -b && node dist/manifest-build.js",
|
|
119
|
-
"typecheck": "tsc --noEmit",
|
|
119
|
+
"typecheck": "tsc --noEmit && tsc -p tsconfig.test.json",
|
|
120
120
|
"clean": "rm -rf dist .tsbuildinfo",
|
|
121
121
|
"test": "vitest run",
|
|
122
122
|
"test:watch": "vitest",
|
package/src/bin.ts
CHANGED
|
@@ -7,8 +7,14 @@
|
|
|
7
7
|
*
|
|
8
8
|
* The bin owns its process: the runner of each command owns the signals, and it ends the process
|
|
9
9
|
* with the exit code of the command (CLI-26).
|
|
10
|
+
*
|
|
11
|
+
* This file enables the compile cache first (roadmap O90). Node.js loads each static import before
|
|
12
|
+
* the first statement, so the CLI loads with a dynamic import after the cache starts.
|
|
10
13
|
*/
|
|
11
14
|
|
|
12
|
-
import {
|
|
15
|
+
import { enableCompileCache } from "./compile-cache.js";
|
|
16
|
+
|
|
17
|
+
enableCompileCache();
|
|
13
18
|
|
|
19
|
+
const { main } = await import("./cli.js");
|
|
14
20
|
await main(process.argv.slice(2), { ownsProcess: true });
|
package/src/cli.ts
CHANGED
|
@@ -16,7 +16,7 @@ import { fieldsOf, generateHelp, resultFieldsOf, type CLIMeta, type CommandLike
|
|
|
16
16
|
import { readFreshManifest, writeManifest, type ManifestCommand } from "./manifest.js";
|
|
17
17
|
import { askMissing, canAsk, missingFields, processTerminal, terminalAsker, type Asker, type Terminal } from "./ask.js";
|
|
18
18
|
import { formatOutput, type OutputFormat, type Print } from "./format.js";
|
|
19
|
-
import { loadEcosystemRegistry } from "./ecosystem.js";
|
|
19
|
+
import { createLazyEcosystemRegistry, indexOfCommands, loadEcosystemRegistry, packageIndexOf } from "./ecosystem.js";
|
|
20
20
|
import { startServerMode, parsePort, parseTransport } from "./server-mode.js";
|
|
21
21
|
import { connectCliServer } from "./client-mode.js";
|
|
22
22
|
import type { ColdCommand, CommandRun } from "./command.js";
|
|
@@ -202,6 +202,37 @@ export async function initCli(verbose = false, fsRoot?: string): Promise<CliCont
|
|
|
202
202
|
return { client, procedures, registry, verbose, ...(ecosystem.fsRoot !== undefined ? { fsRoot: ecosystem.fsRoot } : {}) };
|
|
203
203
|
}
|
|
204
204
|
|
|
205
|
+
/**
|
|
206
|
+
* This function makes the context of a run from a fresh manifest (roadmap O93). Its registry is
|
|
207
|
+
* lazy: it has the core procedures at once, and a call loads only the packages that the manifest
|
|
208
|
+
* names for its path. A list, the help of the registry and `procedure.list` load each package
|
|
209
|
+
* first (`loadAll()`). `procedures` gives the procedures that have loaded at the time of the read.
|
|
210
|
+
* A root of the files (`--fs-root`) needs each procedure, so `run()` then uses `initCli()`.
|
|
211
|
+
*/
|
|
212
|
+
export async function initLazyCli(verbose: boolean, commands: readonly ManifestCommand[]): Promise<CliContext> {
|
|
213
|
+
const { Client, LocalTransport } = await import("@procedures/client");
|
|
214
|
+
const registry = createLazyEcosystemRegistry(indexOfCommands(commands), verbose, true);
|
|
215
|
+
const transport = new LocalTransport({ registry });
|
|
216
|
+
const client = new Client({ transport }).useRegistry(registry);
|
|
217
|
+
return {
|
|
218
|
+
client,
|
|
219
|
+
get procedures(): AnyProcedure[] {
|
|
220
|
+
return registry.getAll();
|
|
221
|
+
},
|
|
222
|
+
registry,
|
|
223
|
+
verbose,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* The procedure of a command in the context of a run. A lazy registry loads the packages of the
|
|
229
|
+
* path first (roadmap O93).
|
|
230
|
+
*/
|
|
231
|
+
async function procedureOfCommand(runtime: CliContext, path: readonly string[]): Promise<AnyProcedure | undefined> {
|
|
232
|
+
if (runtime.registry?.lazy) return runtime.registry.resolve([...path]);
|
|
233
|
+
return findProcedure(runtime.procedures, path);
|
|
234
|
+
}
|
|
235
|
+
|
|
205
236
|
/**
|
|
206
237
|
* Execute a single command given argv tokens.
|
|
207
238
|
* Reusable by both CLI entry point and REPL.
|
|
@@ -434,7 +465,14 @@ export async function executeArgs(
|
|
|
434
465
|
fail(`Error: ${messageOf(error)}`);
|
|
435
466
|
return;
|
|
436
467
|
}
|
|
437
|
-
|
|
468
|
+
let target: AnyProcedure | undefined;
|
|
469
|
+
try {
|
|
470
|
+
target = await procedureOfCommand(runtime, path);
|
|
471
|
+
} catch (error) {
|
|
472
|
+
// A package of the path did not load: the error has the load error
|
|
473
|
+
fail(`Error: ${messageOf(error)}`);
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
438
476
|
if (!target) {
|
|
439
477
|
fail(`Unknown command: mark ${path.join(" ")}`, "Run 'mark --help' for available commands.");
|
|
440
478
|
return;
|
|
@@ -755,7 +793,9 @@ async function run(argv: string[], options: RunCliOptions = {}): Promise<void> {
|
|
|
755
793
|
// server do not load them (roadmap 1.3)
|
|
756
794
|
const manifest = readFreshManifest();
|
|
757
795
|
if (manifest) {
|
|
758
|
-
|
|
796
|
+
// A call loads only the packages of its path (roadmap O93). A root of the files needs each procedure.
|
|
797
|
+
const load = fsRoot === undefined ? () => initLazyCli(verbose, manifest.commands) : () => initCli(verbose, fsRoot);
|
|
798
|
+
await executeArgs(argv, { commands: manifest.commands, verbose, fsRoot, load }, execute);
|
|
759
799
|
return;
|
|
760
800
|
}
|
|
761
801
|
|
|
@@ -763,7 +803,7 @@ async function run(argv: string[], options: RunCliOptions = {}): Promise<void> {
|
|
|
763
803
|
// write the manifest for the next run. A failure to write costs only time.
|
|
764
804
|
const ctx = await initCli(verbose, fsRoot);
|
|
765
805
|
try {
|
|
766
|
-
await writeManifest(ctx.procedures);
|
|
806
|
+
await writeManifest(ctx.procedures, packageIndexOf(ctx.registry));
|
|
767
807
|
} catch (error) {
|
|
768
808
|
if (verbose) {
|
|
769
809
|
print.warning(`mark: the manifest was not written: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The compile cache of Node.js for the `mark` executable (roadmap O90).
|
|
3
|
+
*
|
|
4
|
+
* With the cache, a run of `mark` reads the compiled code of its modules from a folder and does not
|
|
5
|
+
* compile them again. In CI, one `mark` call took 1019 ms with no cache and 754 ms with a warm cache.
|
|
6
|
+
* The first run after an install or a change of a file writes the cache, and costs 174 ms more.
|
|
7
|
+
*
|
|
8
|
+
* The folder is in the cache folder of the user, so a reboot keeps it and other users do not share it.
|
|
9
|
+
* `NODE_COMPILE_CACHE` replaces the folder, and `NODE_DISABLE_COMPILE_CACHE=1` turns the cache off.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import module from "node:module";
|
|
13
|
+
import { homedir } from "node:os";
|
|
14
|
+
import * as path from "node:path";
|
|
15
|
+
|
|
16
|
+
/** The part of `node:module` that this module uses. A test gives its own. */
|
|
17
|
+
export interface CompileCacheApi {
|
|
18
|
+
readonly enableCompileCache?: ((dir?: string) => { status: number; message?: string; directory?: string }) | undefined;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* This function gives the folder of the compile cache of `mark` for a platform: the cache folder of
|
|
23
|
+
* the user, then `mark/compile-cache`. Linux uses `XDG_CACHE_HOME` or `~/.cache`, macOS uses
|
|
24
|
+
* `~/Library/Caches`, and Windows uses `LOCALAPPDATA`.
|
|
25
|
+
*/
|
|
26
|
+
export function compileCacheDir(platform: NodeJS.Platform = process.platform, env: NodeJS.ProcessEnv = process.env, home: string = homedir()): string {
|
|
27
|
+
const join = platform === "win32" ? path.win32.join : path.posix.join;
|
|
28
|
+
const base =
|
|
29
|
+
platform === "win32"
|
|
30
|
+
? (env["LOCALAPPDATA"] ?? path.win32.join(home, "AppData", "Local"))
|
|
31
|
+
: platform === "darwin"
|
|
32
|
+
? path.posix.join(home, "Library", "Caches")
|
|
33
|
+
: env["XDG_CACHE_HOME"] !== undefined && path.posix.isAbsolute(env["XDG_CACHE_HOME"])
|
|
34
|
+
? env["XDG_CACHE_HOME"]
|
|
35
|
+
: path.posix.join(home, ".cache");
|
|
36
|
+
return join(base, "mark", "compile-cache");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* This function enables the compile cache in the folder of `compileCacheDir()`. It gives the result
|
|
41
|
+
* of Node.js, or `undefined` when this Node.js has no compile cache (before 22.1). It never throws:
|
|
42
|
+
* a folder that cannot be written gives the status `FAILED`, and `mark` runs with no cache.
|
|
43
|
+
*/
|
|
44
|
+
export function enableCompileCache(api: CompileCacheApi = module, dir: () => string = compileCacheDir): ReturnType<NonNullable<CompileCacheApi["enableCompileCache"]>> | undefined {
|
|
45
|
+
if (typeof api.enableCompileCache !== "function") return undefined;
|
|
46
|
+
try {
|
|
47
|
+
return api.enableCompileCache(dir());
|
|
48
|
+
} catch {
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
}
|
package/src/ecosystem.ts
CHANGED
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
PROCEDURE_REGISTRY,
|
|
20
20
|
allCoreProcedures,
|
|
21
21
|
clientModule,
|
|
22
|
+
createLazyRegistry,
|
|
22
23
|
createRegistry,
|
|
23
24
|
defineModule,
|
|
24
25
|
pathToKey,
|
|
@@ -40,7 +41,8 @@ interface PackageJson {
|
|
|
40
41
|
exports?: Record<string, unknown>;
|
|
41
42
|
}
|
|
42
43
|
|
|
43
|
-
|
|
44
|
+
/** A workspace package that declares `client.procedures`. */
|
|
45
|
+
export interface DiscoveredPackage {
|
|
44
46
|
name: string;
|
|
45
47
|
path: string;
|
|
46
48
|
proceduresPath: string;
|
|
@@ -205,10 +207,18 @@ export function listEcosystemProcedurePackages(): Array<{ name: string; path: st
|
|
|
205
207
|
/** The core procedures that `mark` serves: all of them, also the ones that the core import does not register. */
|
|
206
208
|
const allCoreModule: ProcedureModule = defineModule("@procedures/client (all core procedures)", allCoreProcedures);
|
|
207
209
|
|
|
210
|
+
/**
|
|
211
|
+
* The index of the packages of a registry (roadmap O93): the key of each path and the names of
|
|
212
|
+
* the packages that give it, in the order of the eager load. A core procedure has no package.
|
|
213
|
+
*/
|
|
214
|
+
export type PackageIndex = Record<string, string[]>;
|
|
215
|
+
|
|
208
216
|
/** The registry of `mark` and the names of the packages that it holds. */
|
|
209
217
|
export interface EcosystemRegistry {
|
|
210
218
|
registry: ProcedureRegistry;
|
|
211
219
|
loaded: string[];
|
|
220
|
+
/** The packages of each path that a package gives. */
|
|
221
|
+
index: PackageIndex;
|
|
212
222
|
/** The absolute path of the root of the files (`--fs-root`), or undefined. */
|
|
213
223
|
fsRoot?: string | undefined;
|
|
214
224
|
/** The keys of the procedures that the root refuses, or undefined without a root. */
|
|
@@ -248,6 +258,12 @@ async function confineRoot(
|
|
|
248
258
|
return { root: folder, refused };
|
|
249
259
|
}
|
|
250
260
|
|
|
261
|
+
/**
|
|
262
|
+
* The end of the last diff of the global registry. The lazy registry can load two packages at
|
|
263
|
+
* the same time: the diffs of the packages of the old kind go one after the other.
|
|
264
|
+
*/
|
|
265
|
+
let globalDiffs: Promise<unknown> = Promise.resolve();
|
|
266
|
+
|
|
251
267
|
/**
|
|
252
268
|
* The module of a package: its `./module` entry (it registers nothing), or else the procedures
|
|
253
269
|
* that importing its procedures file adds to the global registry (a package of the old kind).
|
|
@@ -262,10 +278,90 @@ async function moduleOfPackage(pkg: DiscoveredPackage): Promise<ProcedureModule
|
|
|
262
278
|
}
|
|
263
279
|
const proceduresFile = path.join(pkg.path, pkg.proceduresPath);
|
|
264
280
|
if (!fs.existsSync(proceduresFile)) return undefined;
|
|
265
|
-
const
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
281
|
+
const diff = globalDiffs.then(async (): Promise<ProcedureModule> => {
|
|
282
|
+
const before = new Set(PROCEDURE_REGISTRY.getAll().map((procedure) => pathToKey(procedure.path)));
|
|
283
|
+
await import(pathToFileURL(proceduresFile).href);
|
|
284
|
+
const added: AnyProcedure[] = PROCEDURE_REGISTRY.getAll().filter((procedure) => !before.has(pathToKey(procedure.path)));
|
|
285
|
+
return { name: pkg.name, procedures: added };
|
|
286
|
+
});
|
|
287
|
+
globalDiffs = diff.catch(() => undefined);
|
|
288
|
+
return diff;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/** The keys of the procedures of a registry. */
|
|
292
|
+
function keysOf(registry: ProcedureRegistry): Set<string> {
|
|
293
|
+
return new Set(registry.getAll().map((procedure) => pathToKey(procedure.path)));
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* This function adds the paths of a package to the index. The paths of its own procedures name it.
|
|
298
|
+
* A path that only a module that it requires gives names the first package that registered it.
|
|
299
|
+
*/
|
|
300
|
+
function indexPackage(index: PackageIndex, fallback: Map<string, string>, name: string, module: ProcedureModule, before: ReadonlySet<string>, after: ReadonlySet<string>): void {
|
|
301
|
+
for (const procedure of module.procedures) {
|
|
302
|
+
const key = pathToKey(procedure.path);
|
|
303
|
+
// A procedure that did not register (a conflict stopped the package) is not in the index
|
|
304
|
+
if (!after.has(key)) continue;
|
|
305
|
+
const names = (index[key] ??= []);
|
|
306
|
+
if (!names.includes(name)) names.push(name);
|
|
307
|
+
}
|
|
308
|
+
for (const key of after) if (!before.has(key) && !fallback.has(key)) fallback.set(key, name);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/** The index of a registry that `loadEcosystemRegistry()` made, by registry. */
|
|
312
|
+
const INDEXES = new WeakMap<ProcedureRegistry, PackageIndex>();
|
|
313
|
+
|
|
314
|
+
/** This function gives the index of the packages of an eager registry of `mark`, or undefined. */
|
|
315
|
+
export function packageIndexOf(registry: ProcedureRegistry | undefined): PackageIndex | undefined {
|
|
316
|
+
return registry === undefined ? undefined : INDEXES.get(registry);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* This function gives the index of the commands of a manifest: the key of each path that a
|
|
321
|
+
* package gives, and the names of the packages.
|
|
322
|
+
*/
|
|
323
|
+
export function indexOfCommands(commands: ReadonlyArray<{ path: readonly string[]; packages?: readonly string[] | undefined }>): PackageIndex {
|
|
324
|
+
const index: PackageIndex = {};
|
|
325
|
+
for (const command of commands) {
|
|
326
|
+
if (command.packages !== undefined && command.packages.length > 0) index[pathToKey(command.path)] = [...command.packages];
|
|
327
|
+
}
|
|
328
|
+
return index;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* The lazy registry of `mark` (roadmap O93). It has all the core procedures at once. A call of a
|
|
333
|
+
* path loads only the packages that the index names for it. `loadAll()` loads each package in the
|
|
334
|
+
* order of `discoverFromEcosystem()`, as `loadEcosystemRegistry()` does. A package that fails to
|
|
335
|
+
* load gives the warning of the eager load.
|
|
336
|
+
*/
|
|
337
|
+
export function createLazyEcosystemRegistry(
|
|
338
|
+
index: Readonly<Record<string, readonly string[]>>,
|
|
339
|
+
verbose = false,
|
|
340
|
+
warn = true,
|
|
341
|
+
discovered: readonly DiscoveredPackage[] = discoverFromEcosystem(),
|
|
342
|
+
): ProcedureRegistry {
|
|
343
|
+
const byName = new Map(discovered.map((pkg) => [pkg.name, pkg]));
|
|
344
|
+
return createLazyRegistry({
|
|
345
|
+
modules: [allCoreModule],
|
|
346
|
+
index,
|
|
347
|
+
packages: discovered.map((pkg) => pkg.name),
|
|
348
|
+
load: async (name) => {
|
|
349
|
+
const pkg = byName.get(name);
|
|
350
|
+
if (!pkg) return undefined;
|
|
351
|
+
try {
|
|
352
|
+
const module = await moduleOfPackage(pkg);
|
|
353
|
+
if (!module && verbose) console.warn(`Procedures file not found (build the package): ${path.join(pkg.path, pkg.proceduresPath)}`);
|
|
354
|
+
if (module && verbose) console.log(`Loaded procedures from: ${pkg.name}`);
|
|
355
|
+
return module;
|
|
356
|
+
} catch (error) {
|
|
357
|
+
if (verbose && error instanceof Error && error.stack) console.warn(error.stack);
|
|
358
|
+
throw error;
|
|
359
|
+
}
|
|
360
|
+
},
|
|
361
|
+
warn: (message) => {
|
|
362
|
+
if (warn) console.warn(`mark: ${message}`);
|
|
363
|
+
},
|
|
364
|
+
});
|
|
269
365
|
}
|
|
270
366
|
|
|
271
367
|
/**
|
|
@@ -278,6 +374,8 @@ async function moduleOfPackage(pkg: DiscoveredPackage): Promise<ProcedureModule
|
|
|
278
374
|
export async function loadEcosystemRegistry(verbose = false, warn = true, options: EcosystemOptions = {}): Promise<EcosystemRegistry> {
|
|
279
375
|
const registry = createRegistry(allCoreModule);
|
|
280
376
|
const loaded: string[] = [];
|
|
377
|
+
const index: PackageIndex = {};
|
|
378
|
+
const fallback = new Map<string, string>();
|
|
281
379
|
const discovered = discoverFromEcosystem();
|
|
282
380
|
for (const pkg of discovered) {
|
|
283
381
|
try {
|
|
@@ -286,7 +384,13 @@ export async function loadEcosystemRegistry(verbose = false, warn = true, option
|
|
|
286
384
|
if (verbose) console.warn(`Procedures file not found (build the package): ${path.join(pkg.path, pkg.proceduresPath)}`);
|
|
287
385
|
continue;
|
|
288
386
|
}
|
|
289
|
-
|
|
387
|
+
const before = keysOf(registry);
|
|
388
|
+
try {
|
|
389
|
+
registerModules(registry, [module]);
|
|
390
|
+
} finally {
|
|
391
|
+
// The paths that the package registered before an error count too: the lazy load registers them
|
|
392
|
+
indexPackage(index, fallback, pkg.name, module, before, keysOf(registry));
|
|
393
|
+
}
|
|
290
394
|
loaded.push(pkg.name);
|
|
291
395
|
if (verbose) console.log(`Loaded procedures from: ${pkg.name}`);
|
|
292
396
|
} catch (error) {
|
|
@@ -295,8 +399,11 @@ export async function loadEcosystemRegistry(verbose = false, warn = true, option
|
|
|
295
399
|
if (verbose && error instanceof Error && error.stack) console.warn(error.stack);
|
|
296
400
|
}
|
|
297
401
|
}
|
|
298
|
-
|
|
402
|
+
// A path that only a required module gives names the first package that registered it
|
|
403
|
+
for (const [key, name] of fallback) index[key] ??= [name];
|
|
404
|
+
INDEXES.set(registry, index);
|
|
405
|
+
if (options.fsRoot === undefined) return { registry, loaded, index };
|
|
299
406
|
// After the last package: each procedure of the registry gets the rules of the root
|
|
300
407
|
const { root: fsRoot, refused } = await confineRoot(registry, options.fsRoot, discovered);
|
|
301
|
-
return { registry, loaded, fsRoot, refusedUnderRoot: refused };
|
|
408
|
+
return { registry, loaded, index, fsRoot, refusedUnderRoot: refused };
|
|
302
409
|
}
|
package/src/manifest-build.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import { loadEcosystemRegistry } from "./ecosystem.js";
|
|
8
8
|
import { manifestPath, writeManifest } from "./manifest.js";
|
|
9
9
|
|
|
10
|
-
const { registry, loaded } = await loadEcosystemRegistry(false, false);
|
|
11
|
-
|
|
10
|
+
const { registry, loaded, index } = await loadEcosystemRegistry(false, false);
|
|
11
|
+
// Each command records the packages of its path: the lazy registry of a run loads only those (roadmap O93)
|
|
12
|
+
const manifest = await writeManifest(registry.getAll(), index);
|
|
12
13
|
console.log(`mark: ${manifestPath()} has ${manifest.commands.length} commands from ${loaded.length} packages`);
|
package/src/manifest.ts
CHANGED
|
@@ -17,16 +17,16 @@ import { createHash } from "node:crypto";
|
|
|
17
17
|
import * as fs from "node:fs";
|
|
18
18
|
import * as path from "node:path";
|
|
19
19
|
import { fileURLToPath } from "node:url";
|
|
20
|
-
import { describeProcedureEntry, jsonSchemaOf, type AnyProcedure, type ProcedureEntry } from "@procedures/client";
|
|
20
|
+
import { describeProcedureEntry, jsonSchemaOf, pathToKey, type AnyProcedure, type ProcedureEntry } from "@procedures/client";
|
|
21
21
|
import { writeFileAtomicSync } from "@procedures/fs/files";
|
|
22
22
|
import { discoverFromEcosystem, findWorkspaceRoot } from "./ecosystem.js";
|
|
23
23
|
import { extractSchemaFields, resultFieldsOfSchema, type CLIMeta, type SchemaFieldInfo } from "./parse.js";
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
26
|
* The format of the manifest. A change of the format makes old manifests stale.
|
|
27
|
-
* Version 2 adds `resultFields`.
|
|
27
|
+
* Version 2 adds `resultFields`. Version 3 adds `packages` (roadmap O93).
|
|
28
28
|
*/
|
|
29
|
-
export const MANIFEST_VERSION =
|
|
29
|
+
export const MANIFEST_VERSION = 3;
|
|
30
30
|
|
|
31
31
|
/** One command of the manifest */
|
|
32
32
|
export interface ManifestCommand {
|
|
@@ -39,6 +39,11 @@ export interface ManifestCommand {
|
|
|
39
39
|
inputSchema: unknown;
|
|
40
40
|
/** The fields of the result, for the help (none when the result is not an object) */
|
|
41
41
|
resultFields: SchemaFieldInfo[];
|
|
42
|
+
/**
|
|
43
|
+
* The packages that give the procedure, in the order of the eager load (roadmap O93). A core
|
|
44
|
+
* procedure has none. The lazy registry loads only these packages for a call of the path.
|
|
45
|
+
*/
|
|
46
|
+
packages: string[];
|
|
42
47
|
}
|
|
43
48
|
|
|
44
49
|
export interface Manifest {
|
|
@@ -111,8 +116,14 @@ function cliMetadata(entry: ProcedureEntry): CLIMeta {
|
|
|
111
116
|
return result;
|
|
112
117
|
}
|
|
113
118
|
|
|
114
|
-
/**
|
|
115
|
-
|
|
119
|
+
/**
|
|
120
|
+
* The commands of the manifest, from the procedures of the registry. The index gives the packages
|
|
121
|
+
* of each path (`packageIndexOf()`). Without it, each command has no package.
|
|
122
|
+
*/
|
|
123
|
+
export async function commandsOf(
|
|
124
|
+
procedures: readonly AnyProcedure[],
|
|
125
|
+
index: Readonly<Record<string, readonly string[]>> = {},
|
|
126
|
+
): Promise<ManifestCommand[]> {
|
|
116
127
|
return procedures.map((procedure) => {
|
|
117
128
|
// One JSON Schema for each command: the fields come from it too (roadmap 2.1). The schema and
|
|
118
129
|
// the CLI metadata come from the one manifest type of the core (roadmap R17).
|
|
@@ -124,6 +135,7 @@ export async function commandsOf(procedures: readonly AnyProcedure[]): Promise<M
|
|
|
124
135
|
fields: extractSchemaFields(inputSchema),
|
|
125
136
|
inputSchema,
|
|
126
137
|
resultFields: resultFieldsOfSchema(procedure.output),
|
|
138
|
+
packages: [...(index[pathToKey(procedure.path)] ?? [])],
|
|
127
139
|
};
|
|
128
140
|
});
|
|
129
141
|
}
|
|
@@ -133,13 +145,20 @@ function toJson(manifest: Manifest): string {
|
|
|
133
145
|
return JSON.stringify(manifest, (_key, value: unknown) => (typeof value === "bigint" ? value.toString() : value), 1);
|
|
134
146
|
}
|
|
135
147
|
|
|
136
|
-
/**
|
|
137
|
-
|
|
148
|
+
/**
|
|
149
|
+
* Write the manifest of these procedures for the current fingerprint (a temporary file, then a
|
|
150
|
+
* rename). The index gives the packages of each path.
|
|
151
|
+
*/
|
|
152
|
+
export async function writeManifest(
|
|
153
|
+
procedures: readonly AnyProcedure[],
|
|
154
|
+
index: Readonly<Record<string, readonly string[]>> = {},
|
|
155
|
+
file: string = manifestPath(),
|
|
156
|
+
): Promise<Manifest> {
|
|
138
157
|
const manifest: Manifest = {
|
|
139
158
|
version: MANIFEST_VERSION,
|
|
140
159
|
fingerprint: computeFingerprint(),
|
|
141
160
|
generatedAt: new Date().toISOString(),
|
|
142
|
-
commands: await commandsOf(procedures),
|
|
161
|
+
commands: await commandsOf(procedures, index),
|
|
143
162
|
};
|
|
144
163
|
// writeFileAtomicSync flushes the file, tries the rename again on Windows and removes the temporary file after a failure
|
|
145
164
|
writeFileAtomicSync(file, toJson(manifest));
|
package/src/print.ts
CHANGED
|
@@ -7,7 +7,16 @@
|
|
|
7
7
|
|
|
8
8
|
import chalk from "chalk";
|
|
9
9
|
import ora from "ora";
|
|
10
|
-
import
|
|
10
|
+
import { createRequire } from "node:module";
|
|
11
|
+
import type TableClass from "cli-table3";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* This function gives the table class of `cli-table3`. The first table loads the package, not the
|
|
15
|
+
* start of `mark`: a call that prints no table does not load it (roadmap O93).
|
|
16
|
+
*/
|
|
17
|
+
function tableClass(): typeof TableClass {
|
|
18
|
+
return createRequire(import.meta.url)("cli-table3") as typeof TableClass;
|
|
19
|
+
}
|
|
11
20
|
|
|
12
21
|
/**
|
|
13
22
|
* Spinner interface (compatible with existing code)
|
|
@@ -71,6 +80,7 @@ export const print = {
|
|
|
71
80
|
const [headers, ...rows] = data;
|
|
72
81
|
if (!headers) return;
|
|
73
82
|
|
|
83
|
+
const Table = tableClass();
|
|
74
84
|
const table = new Table({
|
|
75
85
|
head: headers.map((h) => chalk.bold(h)),
|
|
76
86
|
style: {
|