@plexus-ms/lib 0.0.0-stage → 0.2.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.
@@ -0,0 +1,23 @@
1
+ import type { Context } from './context.ts';
2
+ export interface Module {
3
+ code: string;
4
+ kind: 'contract' | 'approach';
5
+ maturity: string;
6
+ binds: string;
7
+ /** The train in which the module's requirements last changed; standard modules only. */
8
+ changed?: string;
9
+ /** Codes on the same side of every seam that a declaration of this module has to accompany. */
10
+ depends: string[];
11
+ /** Contracts on the other side of a seam; never the declaring unit's to satisfy. */
12
+ consumes: string[];
13
+ }
14
+ export type Catalog = Map<string, Module>;
15
+ export declare const CATALOG_DIRS: {
16
+ readonly contracts: "contract";
17
+ readonly approaches: "approach";
18
+ };
19
+ /** The module a page declares, or undefined for a note. */
20
+ export declare function parseModule(text: string, kind: Module['kind']): Module | undefined;
21
+ /** Every module of a compendium checkout, by code. */
22
+ export declare function readCatalog(ctx: Context, compendium: string): Promise<Catalog>;
23
+ //# sourceMappingURL=catalog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAG5C,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,UAAU,GAAG,UAAU,CAAC;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,wFAAwF;IACxF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+FAA+F;IAC/F,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,oFAAoF;IACpF,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAE1C,eAAO,MAAM,YAAY;;;CAA6D,CAAC;AAEvF,2DAA2D;AAC3D,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,GAAG,MAAM,GAAG,SAAS,CAYlF;AAMD,sDAAsD;AACtD,wBAAsB,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAUpF"}
@@ -0,0 +1,38 @@
1
+ // The module catalogue: what the compendium's `contracts/` and `approaches/`
2
+ // pages declare in their frontmatter (§ 1.3 PLX). Only pages with a `code`
3
+ // are modules a marker can declare; notes have none and are skipped.
4
+ import { join } from 'node:path';
5
+ import { splitFrontmatter } from "./marker.js";
6
+ export const CATALOG_DIRS = { contracts: 'contract', approaches: 'approach' };
7
+ /** The module a page declares, or undefined for a note. */
8
+ export function parseModule(text, kind) {
9
+ const { data } = splitFrontmatter(text);
10
+ if (typeof data.code !== 'string')
11
+ return undefined;
12
+ return {
13
+ code: data.code,
14
+ kind,
15
+ maturity: String(data.maturity ?? ''),
16
+ binds: String(data.binds ?? ''),
17
+ changed: data.changed === undefined ? undefined : String(data.changed),
18
+ depends: codes(data.depends),
19
+ consumes: codes(data.consumes),
20
+ };
21
+ }
22
+ function codes(value) {
23
+ return Array.isArray(value) ? value.map(String) : [];
24
+ }
25
+ /** Every module of a compendium checkout, by code. */
26
+ export async function readCatalog(ctx, compendium) {
27
+ const catalog = new Map();
28
+ for (const [dir, kind] of Object.entries(CATALOG_DIRS)) {
29
+ const entries = await ctx.readDir(join(compendium, dir));
30
+ for (const e of entries.filter((e) => !e.directory && e.name.endsWith('.md') && e.name !== 'index.md').sort()) {
31
+ const module = parseModule(await ctx.readFile(join(compendium, dir, e.name)), kind);
32
+ if (module)
33
+ catalog.set(module.code, module);
34
+ }
35
+ }
36
+ return catalog;
37
+ }
38
+ //# sourceMappingURL=catalog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,2EAA2E;AAC3E,qEAAqE;AACrE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAiB/C,MAAM,CAAC,MAAM,YAAY,GAAG,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAW,CAAC;AAEvF,2DAA2D;AAC3D,MAAM,UAAU,WAAW,CAAC,IAAY,EAAE,IAAoB;IAC5D,MAAM,EAAE,IAAI,EAAE,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACxC,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IACpD,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,IAAI;QACJ,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC;QACrC,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;QAC/B,OAAO,EAAE,IAAI,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC;QACtE,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC;QAC5B,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC;KAC/B,CAAC;AACJ,CAAC;AAED,SAAS,KAAK,CAAC,KAAc;IAC3B,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACvD,CAAC;AAED,sDAAsD;AACtD,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,GAAY,EAAE,UAAkB;IAChE,MAAM,OAAO,GAAY,IAAI,GAAG,EAAE,CAAC;IACnC,KAAK,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;QACvD,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC,CAAC;QACzD,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;YAC9G,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;YACpF,IAAI,MAAM;gBAAE,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,41 @@
1
+ import { type DirEntry, type ExecOptions, type Io } from './io.ts';
2
+ import { type Plan } from './plan.ts';
3
+ export interface Options {
4
+ dryRun?: boolean;
5
+ /** 0: every effect; 1: reads and inputs too; 2: subprocess output too. */
6
+ verbose?: number;
7
+ quiet?: boolean;
8
+ yes?: boolean;
9
+ json?: boolean;
10
+ }
11
+ export declare class Context {
12
+ readonly dryRun: boolean;
13
+ readonly verbose: number;
14
+ readonly quiet: boolean;
15
+ readonly yes: boolean;
16
+ readonly json: boolean;
17
+ readonly io: Io;
18
+ constructor(options: Options, io?: Io);
19
+ /** One line, if the verbosity allows the level (0 normal, 1 verbose, 2 debug). */
20
+ say(line: string, level?: number): void;
21
+ /** A final outcome line, `✓ ...` or `✗ ...`; shown even under --quiet. */
22
+ done(line: string, ok?: boolean): void;
23
+ /**
24
+ * The command's product. `data` is what --json prints; `human` renders it
25
+ * otherwise (default: strings as they are, arrays one item per line).
26
+ */
27
+ result<T>(data: T, human?: (data: T) => string): void;
28
+ /** Run a command for its output. Changes nothing; narrated only when verbose. */
29
+ read(command: string, args?: string[], options?: Omit<ExecOptions, 'inherit'>): Promise<string>;
30
+ readFile(path: string): Promise<string>;
31
+ readDir(path: string): Promise<DirEntry[]>;
32
+ /**
33
+ * Ask before applying. `--yes` and `--dry-run` answer yes; off a terminal
34
+ * without `--yes` the answer is an error, never a hang.
35
+ */
36
+ confirm(question: string): Promise<boolean>;
37
+ /** Narrate and perform each step in order; the first failure stops the run. */
38
+ apply(plan: Plan): Promise<void>;
39
+ private perform;
40
+ }
41
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,WAAW,EAAE,KAAK,EAAE,EAAU,MAAM,SAAS,CAAC;AAC3E,OAAO,EAAkB,KAAK,IAAI,EAAa,MAAM,WAAW,CAAC;AAEjE,MAAM,WAAW,OAAO;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,0EAA0E;IAC1E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,qBAAa,OAAO;IAClB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC;gBAEJ,OAAO,EAAE,OAAO,EAAE,EAAE,GAAE,EAAa;IAW/C,kFAAkF;IAClF,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,SAAI,GAAG,IAAI;IAIlC,0EAA0E;IAC1E,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,UAAO,GAAG,IAAI;IAMnC;;;OAGG;IACH,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,GAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAoB,GAAG,IAAI;IAOlE,iFAAiF;IACjF,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,EAAO,EAAE,OAAO,GAAE,IAAI,CAAC,WAAW,EAAE,SAAS,CAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAKvG,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAKvC,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAO1C;;;OAGG;IACG,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IASjD,+EAA+E;IACzE,KAAK,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAStC,OAAO,CAAC,OAAO;CAWhB"}
@@ -0,0 +1,115 @@
1
+ // The Context is what a verb runs in: the options, the injected Io, and the
2
+ // three things a verb does with them.
3
+ //
4
+ // read look at the world; always performed, so a dry run sees real state
5
+ // apply perform a Plan (plan.ts); every step is narrated with its exact
6
+ // shell line, and performed unless --dry-run
7
+ // result print the command's product: human-readable, or JSON under --json
8
+ //
9
+ // Plan, then confirm, then apply: validation and every read happen while
10
+ // planning, so a failure there costs nothing, and by the time an effect runs
11
+ // the verb knows the whole of what it is about to do. Narration goes to
12
+ // stderr, results to stdout, so `plx <verb> | ...` composes like the script
13
+ // it replaces. Conventions: compendium/miscellaneous/cli-design.md.
14
+ import { realIo } from "./io.js";
15
+ import { body, describe } from "./plan.js";
16
+ export class Context {
17
+ dryRun;
18
+ verbose;
19
+ quiet;
20
+ yes;
21
+ json;
22
+ io;
23
+ constructor(options, io = realIo()) {
24
+ this.io = io;
25
+ this.dryRun = options.dryRun ?? false;
26
+ this.quiet = options.quiet ?? false;
27
+ this.verbose = this.quiet ? -1 : (options.verbose ?? 0);
28
+ this.yes = options.yes ?? false;
29
+ this.json = options.json ?? false;
30
+ }
31
+ // --- narration (stderr) ---------------------------------------------------
32
+ /** One line, if the verbosity allows the level (0 normal, 1 verbose, 2 debug). */
33
+ say(line, level = 0) {
34
+ if (this.verbose >= level)
35
+ this.io.stderr.write(`${line}\n`);
36
+ }
37
+ /** A final outcome line, `✓ ...` or `✗ ...`; shown even under --quiet. */
38
+ done(line, ok = true) {
39
+ this.io.stderr.write(`${ok ? '✓' : '✗'} ${line}\n`);
40
+ }
41
+ // --- results (stdout) -----------------------------------------------------
42
+ /**
43
+ * The command's product. `data` is what --json prints; `human` renders it
44
+ * otherwise (default: strings as they are, arrays one item per line).
45
+ */
46
+ result(data, human = renderHuman) {
47
+ const text = this.json ? JSON.stringify(data, null, 2) : human(data);
48
+ this.io.stdout.write(text.endsWith('\n') ? text : `${text}\n`);
49
+ }
50
+ // --- reads: always performed ---------------------------------------------
51
+ /** Run a command for its output. Changes nothing; narrated only when verbose. */
52
+ read(command, args = [], options = {}) {
53
+ this.say(`? ${describe({ kind: 'run', command, args, ...options })}`, 1);
54
+ return this.io.exec(command, args, options);
55
+ }
56
+ readFile(path) {
57
+ this.say(`? read ${path}`, 1);
58
+ return this.io.readFile(path);
59
+ }
60
+ readDir(path) {
61
+ this.say(`? list ${path}`, 2);
62
+ return this.io.readDir(path);
63
+ }
64
+ // --- effects: narrated always, performed unless --dry-run -----------------
65
+ /**
66
+ * Ask before applying. `--yes` and `--dry-run` answer yes; off a terminal
67
+ * without `--yes` the answer is an error, never a hang.
68
+ */
69
+ async confirm(question) {
70
+ if (this.yes || this.dryRun) {
71
+ this.say(`? ${question} yes (${this.yes ? '--yes' : '--dry-run'})`, 1);
72
+ return true;
73
+ }
74
+ if (!this.io.prompt)
75
+ throw new Error(`cannot ask "${question}" without a terminal; pass --yes`);
76
+ return this.io.prompt(question);
77
+ }
78
+ /** Narrate and perform each step in order; the first failure stops the run. */
79
+ async apply(plan) {
80
+ for (const step of plan) {
81
+ this.say(`${this.dryRun ? '[dry-run] ' : ''}${describe(step)}`);
82
+ const input = body(step);
83
+ if (input !== undefined)
84
+ this.say(indent(input), step.kind === 'write' ? 2 : 1);
85
+ if (!this.dryRun)
86
+ await this.perform(step);
87
+ }
88
+ }
89
+ perform(step) {
90
+ const inherit = this.verbose >= 2;
91
+ switch (step.kind) {
92
+ case 'run':
93
+ return this.io.exec(step.command, step.args, { cwd: step.cwd, input: step.input, inherit });
94
+ case 'ssh':
95
+ return this.io.exec('ssh', [step.host, 'bash', '-s'], { input: step.script, inherit });
96
+ case 'write':
97
+ return this.io.writeFile(step.path, step.content);
98
+ }
99
+ }
100
+ }
101
+ function renderHuman(data) {
102
+ if (typeof data === 'string')
103
+ return data;
104
+ if (Array.isArray(data))
105
+ return data.map(String).join('\n');
106
+ return JSON.stringify(data, null, 2);
107
+ }
108
+ function indent(text) {
109
+ return text
110
+ .trimEnd()
111
+ .split('\n')
112
+ .map((l) => ` ${l}`)
113
+ .join('\n');
114
+ }
115
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,sCAAsC;AACtC,EAAE;AACF,6EAA6E;AAC7E,2EAA2E;AAC3E,sDAAsD;AACtD,6EAA6E;AAC7E,EAAE;AACF,yEAAyE;AACzE,6EAA6E;AAC7E,wEAAwE;AACxE,4EAA4E;AAC5E,oEAAoE;AACpE,OAAO,EAA4C,MAAM,EAAE,MAAM,SAAS,CAAC;AAC3E,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAwB,MAAM,WAAW,CAAC;AAWjE,MAAM,OAAO,OAAO;IACT,MAAM,CAAU;IAChB,OAAO,CAAS;IAChB,KAAK,CAAU;IACf,GAAG,CAAU;IACb,IAAI,CAAU;IACd,EAAE,CAAK;IAEhB,YAAY,OAAgB,EAAE,KAAS,MAAM,EAAE;QAC7C,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,KAAK,CAAC;QACtC,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,KAAK,CAAC;QACpC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC;QACxD,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,KAAK,CAAC;QAChC,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,KAAK,CAAC;IACpC,CAAC;IAED,6EAA6E;IAE7E,kFAAkF;IAClF,GAAG,CAAC,IAAY,EAAE,KAAK,GAAG,CAAC;QACzB,IAAI,IAAI,CAAC,OAAO,IAAI,KAAK;YAAE,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC;IAC/D,CAAC;IAED,0EAA0E;IAC1E,IAAI,CAAC,IAAY,EAAE,EAAE,GAAG,IAAI;QAC1B,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,IAAI,CAAC,CAAC;IACtD,CAAC;IAED,6EAA6E;IAE7E;;;OAGG;IACH,MAAM,CAAI,IAAO,EAAE,QAA6B,WAAW;QACzD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACrE,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC;IACjE,CAAC;IAED,4EAA4E;IAE5E,iFAAiF;IACjF,IAAI,CAAC,OAAe,EAAE,OAAiB,EAAE,EAAE,UAAwC,EAAE;QACnF,IAAI,CAAC,GAAG,CAAC,KAAK,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;QACzE,OAAO,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IAC9C,CAAC;IAED,QAAQ,CAAC,IAAY;QACnB,IAAI,CAAC,GAAG,CAAC,UAAU,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;QAC9B,OAAO,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;IAED,OAAO,CAAC,IAAY;QAClB,IAAI,CAAC,GAAG,CAAC,UAAU,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;QAC9B,OAAO,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC;IAED,6EAA6E;IAE7E;;;OAGG;IACH,KAAK,CAAC,OAAO,CAAC,QAAgB;QAC5B,IAAI,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAC5B,IAAI,CAAC,GAAG,CAAC,KAAK,QAAQ,SAAS,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,GAAG,EAAE,CAAC,CAAC,CAAC;YACvE,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,eAAe,QAAQ,kCAAkC,CAAC,CAAC;QAChG,OAAO,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAClC,CAAC;IAED,+EAA+E;IAC/E,KAAK,CAAC,KAAK,CAAC,IAAU;QACpB,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC;YACxB,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAChE,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;YACzB,IAAI,KAAK,KAAK,SAAS;gBAAE,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAChF,IAAI,CAAC,IAAI,CAAC,MAAM;gBAAE,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC7C,CAAC;IACH,CAAC;IAEO,OAAO,CAAC,IAAU;QACxB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC;QAClC,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;YAClB,KAAK,KAAK;gBACR,OAAO,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;YAC9F,KAAK,KAAK;gBACR,OAAO,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;YACzF,KAAK,OAAO;gBACV,OAAO,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QACtD,CAAC;IACH,CAAC;CACF;AAED,SAAS,WAAW,CAAC,IAAa;IAChC,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC1C,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5D,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AACvC,CAAC;AAED,SAAS,MAAM,CAAC,IAAY;IAC1B,OAAO,IAAI;SACR,OAAO,EAAE;SACT,KAAK,CAAC,IAAI,CAAC;SACX,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;SACtB,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC"}
@@ -0,0 +1,12 @@
1
+ export declare const ANSWERS_FILE = ".copier-answers.yml";
2
+ export declare const TEMPLATE_FILES: string[];
3
+ export interface Answers {
4
+ /** The template's ref the project was last updated to, if recorded. */
5
+ commit?: string;
6
+ /** Where the template comes from, e.g. `gh:plexus-ms/preset-repo-web`. */
7
+ src?: string;
8
+ /** Every other answer, by question name. */
9
+ answers: Record<string, unknown>;
10
+ }
11
+ export declare function parseAnswers(text: string): Answers;
12
+ //# sourceMappingURL=copier.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copier.d.ts","sourceRoot":"","sources":["../src/copier.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,YAAY,wBAAwB,CAAC;AAClD,eAAO,MAAM,cAAc,UAAgC,CAAC;AAE5D,MAAM,WAAW,OAAO;IACtB,uEAAuE;IACvE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0EAA0E;IAC1E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,4CAA4C;IAC5C,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAUlD"}
package/dist/copier.js ADDED
@@ -0,0 +1,19 @@
1
+ // Copier's bookkeeping in a generated project (§ 3 PLX-Updates): the answers
2
+ // file records the template (`_src_path`) and the version it was last synced
3
+ // to (`_commit`), plus the answers given. A template is a directory carrying a
4
+ // `copier.yml`.
5
+ import { parse } from 'yaml';
6
+ export const ANSWERS_FILE = '.copier-answers.yml';
7
+ export const TEMPLATE_FILES = ['copier.yml', 'copier.yaml'];
8
+ export function parseAnswers(text) {
9
+ const data = parse(text);
10
+ if (data === null || typeof data !== 'object' || Array.isArray(data))
11
+ throw new Error('answers file is not a mapping');
12
+ const { _commit, _src_path, ...answers } = data;
13
+ return {
14
+ commit: _commit === undefined ? undefined : String(_commit),
15
+ src: _src_path === undefined ? undefined : String(_src_path),
16
+ answers,
17
+ };
18
+ }
19
+ //# sourceMappingURL=copier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copier.js","sourceRoot":"","sources":["../src/copier.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,6EAA6E;AAC7E,+EAA+E;AAC/E,gBAAgB;AAChB,OAAO,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC;AAE7B,MAAM,CAAC,MAAM,YAAY,GAAG,qBAAqB,CAAC;AAClD,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,YAAY,EAAE,aAAa,CAAC,CAAC;AAW5D,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,MAAM,IAAI,GAAY,KAAK,CAAC,IAAI,CAAC,CAAC;IAClC,IAAI,IAAI,KAAK,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QAClE,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;IACnD,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,OAAO,EAAE,GAAG,IAA+B,CAAC;IAC3E,OAAO;QACL,MAAM,EAAE,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;QAC3D,GAAG,EAAE,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC;QAC5D,OAAO;KACR,CAAC;AACJ,CAAC"}
@@ -0,0 +1,19 @@
1
+ import type { Catalog } from './catalog.ts';
2
+ import type { Directory } from './model.ts';
3
+ export interface Diagnosis {
4
+ /** The marker's directory, relative to the scanned root. */
5
+ path: string;
6
+ plexus?: string;
7
+ modules: string[];
8
+ findings: string[];
9
+ }
10
+ export interface Report {
11
+ declarations: Diagnosis[];
12
+ /** Declarations with at least one finding. */
13
+ stale: number;
14
+ }
15
+ /** A scanned tree against a catalogue: pure, so a test compares reports. */
16
+ export declare function diagnose(root: Directory, catalog: Catalog): Report;
17
+ /** Numeric comparison of two train versions; suffixes ignored. */
18
+ export declare function compareTrains(a: string, b: string): number;
19
+ //# sourceMappingURL=doctor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,MAAM,WAAW,SAAS;IACxB,4DAA4D;IAC5D,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,MAAM;IACrB,YAAY,EAAE,SAAS,EAAE,CAAC;IAC1B,8CAA8C;IAC9C,KAAK,EAAE,MAAM,CAAC;CACf;AAED,4EAA4E;AAC5E,wBAAgB,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,CAIlE;AA4DD,kEAAkE;AAClE,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAS1D"}
package/dist/doctor.js ADDED
@@ -0,0 +1,79 @@
1
+ // doctor: the staleness check (§ 13.4 PLX), a verb, not a system.
2
+ //
3
+ // Every PLEXUS.md marker under a directory is read, and for each module it
4
+ // declares the module's `changed` train is compared with the marker's
5
+ // `plexus`; every `depends` entry of a declared module has to be declared
6
+ // where § 1.4 says it is satisfied: by the unit itself, by an enclosing
7
+ // declaration (an app's repo, a repo's tenant) or by a contained one (a
8
+ // repo's apps, a tenant's repos). What a module `consumes` is the other side
9
+ // of a seam and never this unit's to declare. Findings are reported, never
10
+ // fixed. A tenant is a directory whose repos sit side by side; the repo whose
11
+ // marker declares PLX-Tenancy is the tenant's declaration.
12
+ //
13
+ // plx doctor # every marker, one line each
14
+ // plx doctor ~/dev --compendium ~/dev/plexus-ms/compendium
15
+ import { relative } from 'node:path';
16
+ /** A scanned tree against a catalogue: pure, so a test compares reports. */
17
+ export function diagnose(root, catalog) {
18
+ const units = collect(root, []);
19
+ const declarations = units.map((u) => diagnoseUnit(u, units, catalog, root.path));
20
+ return { declarations, stale: declarations.filter((d) => d.findings.length > 0).length };
21
+ }
22
+ function collect(dir, ancestors, parent) {
23
+ const here = dir.declaration || dir.problems?.some((p) => p.startsWith('PLEXUS.md')) ? [{ dir, ancestors, parent }] : [];
24
+ const below = dir.declaration ? [...ancestors, dir] : ancestors;
25
+ return [...here, ...dir.children.flatMap((c) => collect(c, below, dir))];
26
+ }
27
+ function diagnoseUnit(unit, units, catalog, root) {
28
+ const { dir } = unit;
29
+ const path = relative(root, dir.path) || '.';
30
+ const problem = dir.problems?.find((p) => p.startsWith('PLEXUS.md'));
31
+ if (!dir.declaration)
32
+ return { path, modules: [], findings: [problem?.replace(/^PLEXUS\.md: /, '') ?? 'unreadable marker'] };
33
+ const { plexus, modules } = dir.declaration;
34
+ const context = new Set(contextOf(unit, units).flatMap((d) => d.declaration?.modules ?? []));
35
+ const findings = [];
36
+ for (const code of modules) {
37
+ const module = catalog.get(code);
38
+ if (!module) {
39
+ findings.push(`declares ${code}, which no module carries`);
40
+ continue;
41
+ }
42
+ if (module.changed && compareTrains(module.changed, plexus) > 0)
43
+ findings.push(`${code} changed in ${module.changed}, declared at ${plexus}`);
44
+ for (const dep of module.depends)
45
+ if (!modules.includes(dep) && !context.has(dep))
46
+ findings.push(`${code} depends on ${dep}, declared neither here nor by an enclosing or contained declaration`);
47
+ }
48
+ return { path, plexus, modules, findings };
49
+ }
50
+ /** The declarations that may satisfy a unit's dependencies: enclosing and contained ones (§ 1.4 PLX). */
51
+ function contextOf(unit, units) {
52
+ const { dir, ancestors } = unit;
53
+ const context = [...ancestors, ...descendants(dir)];
54
+ // The tenant: the repo's siblings. A unit inside a repo belongs to that repo; a repo is its own.
55
+ const repo = ancestors[0] ?? dir;
56
+ const repoParent = units.find((u) => u.dir === repo)?.parent;
57
+ const siblings = repoParent?.children.filter((c) => c !== repo && c.declaration) ?? [];
58
+ const isTenancy = (d) => d.declaration?.modules.includes('PLX-Tenancy') ?? false;
59
+ context.push(...siblings.filter(isTenancy));
60
+ if (isTenancy(dir))
61
+ context.push(...siblings);
62
+ return context;
63
+ }
64
+ function descendants(dir) {
65
+ return dir.children.flatMap((c) => [...(c.declaration ? [c] : []), ...descendants(c)]);
66
+ }
67
+ /** Numeric comparison of two train versions; suffixes ignored. */
68
+ export function compareTrains(a, b) {
69
+ const nums = (v) => v
70
+ .split('.')
71
+ .slice(0, 3)
72
+ .map((p) => Number.parseInt(p, 10) || 0);
73
+ const [x, y] = [nums(a), nums(b)];
74
+ for (let i = 0; i < 3; i++)
75
+ if ((x[i] ?? 0) !== (y[i] ?? 0))
76
+ return (x[i] ?? 0) > (y[i] ?? 0) ? 1 : -1;
77
+ return 0;
78
+ }
79
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export { CATALOG_DIRS, type Catalog, type Module, parseModule, readCatalog } from './catalog.ts';
2
+ export { Context, type Options } from './context.ts';
3
+ export { ANSWERS_FILE, type Answers, parseAnswers, TEMPLATE_FILES } from './copier.ts';
4
+ export { compareTrains, type Diagnosis, diagnose, type Report } from './doctor.ts';
5
+ export { type DirEntry, ExecError, type ExecOptions, type Io, realIo, render } from './io.ts';
6
+ export { type Declaration, MARKER_FILE, parseMarker, splitFrontmatter } from './marker.ts';
7
+ export { type Directory, type GitFacet, isNotable, type Kind, kindOf, shortRemote, type TemplateFacet, } from './model.ts';
8
+ export { overview, PRUNED, type ScanOptions } from './overview.ts';
9
+ export { body, describe, type Plan, run, type Step, ssh, write } from './plan.ts';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,YAAY,EAAE,KAAK,OAAO,EAAE,KAAK,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACjG,OAAO,EAAE,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,KAAK,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACvF,OAAO,EAAE,aAAa,EAAE,KAAK,SAAS,EAAE,QAAQ,EAAE,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AACnF,OAAO,EAAE,KAAK,QAAQ,EAAE,SAAS,EAAE,KAAK,WAAW,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAC9F,OAAO,EAAE,KAAK,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC3F,OAAO,EACL,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,SAAS,EACT,KAAK,IAAI,EACT,MAAM,EACN,WAAW,EACX,KAAK,aAAa,GACnB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AACnE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,18 @@
1
+ // @plexus-ms/lib: the core layer of plx, usable without the CLI.
2
+ //
3
+ // A verb here is either a reader returning data, or a pure planner returning
4
+ // a Plan (plan.ts) from what was read. The Context (context.ts) reads through
5
+ // an injected Io (io.ts) and applies plans, narrating every step; the CLI
6
+ // package is an adapter that maps argv onto this. The parsers of Plexus's own
7
+ // file shapes (marker.ts, copier.ts) live here, once, for every verb.
8
+ // Conventions: compendium/miscellaneous/cli-design.md.
9
+ export { CATALOG_DIRS, parseModule, readCatalog } from "./catalog.js";
10
+ export { Context } from "./context.js";
11
+ export { ANSWERS_FILE, parseAnswers, TEMPLATE_FILES } from "./copier.js";
12
+ export { compareTrains, diagnose } from "./doctor.js";
13
+ export { ExecError, realIo, render } from "./io.js";
14
+ export { MARKER_FILE, parseMarker, splitFrontmatter } from "./marker.js";
15
+ export { isNotable, kindOf, shortRemote, } from "./model.js";
16
+ export { overview, PRUNED } from "./overview.js";
17
+ export { body, describe, run, ssh, write } from "./plan.js";
18
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,EAAE;AACF,6EAA6E;AAC7E,8EAA8E;AAC9E,0EAA0E;AAC1E,8EAA8E;AAC9E,sEAAsE;AACtE,uDAAuD;AACvD,OAAO,EAAE,YAAY,EAA6B,WAAW,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACjG,OAAO,EAAE,OAAO,EAAgB,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,YAAY,EAAgB,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACvF,OAAO,EAAE,aAAa,EAAkB,QAAQ,EAAe,MAAM,aAAa,CAAC;AACnF,OAAO,EAAiB,SAAS,EAA6B,MAAM,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAC9F,OAAO,EAAoB,WAAW,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC3F,OAAO,EAGL,SAAS,EAET,MAAM,EACN,WAAW,GAEZ,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAoB,MAAM,eAAe,CAAC;AACnE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAa,GAAG,EAAa,GAAG,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC"}
package/dist/io.d.ts ADDED
@@ -0,0 +1,40 @@
1
+ import type { Writable } from 'node:stream';
2
+ export interface ExecOptions {
3
+ cwd?: string;
4
+ env?: NodeJS.ProcessEnv;
5
+ /** Fed to the process's stdin, then closed. */
6
+ input?: string;
7
+ /** Pass the process's output through to the terminal instead of capturing it. */
8
+ inherit?: boolean;
9
+ }
10
+ export interface Io {
11
+ stdout: Writable;
12
+ stderr: Writable;
13
+ /**
14
+ * Ask a yes/no question of a human, or undefined when there is none: off a
15
+ * terminal, or in a program that brings no prompt (the CLI supplies one).
16
+ */
17
+ prompt?: (question: string) => Promise<boolean>;
18
+ /** Run a process to completion; resolves with its stdout, rejects with ExecError on nonzero exit. */
19
+ exec(command: string, args: string[], options?: ExecOptions): Promise<string>;
20
+ readFile(path: string): Promise<string>;
21
+ writeFile(path: string, content: string): Promise<void>;
22
+ /** The entries of a directory, in no particular order. */
23
+ readDir(path: string): Promise<DirEntry[]>;
24
+ }
25
+ export interface DirEntry {
26
+ name: string;
27
+ directory: boolean;
28
+ }
29
+ export declare class ExecError extends Error {
30
+ readonly command: string;
31
+ readonly code: number | null;
32
+ readonly stderr: string;
33
+ constructor(command: string, code: number | null, stderr: string);
34
+ }
35
+ /** True when a human is on both ends of the terminal. */
36
+ export declare const isInteractive: () => boolean;
37
+ export declare function realIo(prompt?: Io['prompt']): Io;
38
+ /** The command line as a shell would need it typed: args quoted when they must be. */
39
+ export declare function render(command: string, args: string[]): string;
40
+ //# sourceMappingURL=io.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"io.d.ts","sourceRoot":"","sources":["../src/io.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,WAAW,WAAW;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,+CAA+C;IAC/C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iFAAiF;IACjF,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,EAAE;IACjB,MAAM,EAAE,QAAQ,CAAC;IACjB,MAAM,EAAE,QAAQ,CAAC;IACjB;;;OAGG;IACH,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAChD,qGAAqG;IACrG,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9E,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACxC,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxD,0DAA0D;IAC1D,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;CAC5C;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,qBAAa,SAAU,SAAQ,KAAK;IAClC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAEZ,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM;CAMjE;AAED,yDAAyD;AACzD,eAAO,MAAM,aAAa,QAAO,OAAwE,CAAC;AAE1G,wBAAgB,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,EAAE,CAiChD;AAED,sFAAsF;AACtF,wBAAgB,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CAE9D"}
package/dist/io.js ADDED
@@ -0,0 +1,62 @@
1
+ // Everything a verb does to the world goes through an Io, injected into the
2
+ // Context (context.ts). The real one wraps node; a test hands in a fake and
3
+ // asserts what was asked of it, with no subprocess and no filesystem.
4
+ import { spawn } from 'node:child_process';
5
+ import { readdir, readFile, writeFile } from 'node:fs/promises';
6
+ export class ExecError extends Error {
7
+ command;
8
+ code;
9
+ stderr;
10
+ constructor(command, code, stderr) {
11
+ super(`${command} exited with ${code ?? 'signal'}${stderr ? `\n${stderr.trimEnd()}` : ''}`);
12
+ this.command = command;
13
+ this.code = code;
14
+ this.stderr = stderr;
15
+ }
16
+ }
17
+ /** True when a human is on both ends of the terminal. */
18
+ export const isInteractive = () => process.stdin.isTTY === true && process.stderr.isTTY === true;
19
+ export function realIo(prompt) {
20
+ return {
21
+ stdout: process.stdout,
22
+ stderr: process.stderr,
23
+ prompt: prompt && isInteractive() ? prompt : undefined,
24
+ exec: (command, args, options = {}) => new Promise((resolve, reject) => {
25
+ const child = spawn(command, args, {
26
+ cwd: options.cwd,
27
+ env: options.env,
28
+ stdio: [options.input === undefined ? 'ignore' : 'pipe', options.inherit ? 'inherit' : 'pipe', 'pipe'],
29
+ });
30
+ let stdout = '';
31
+ let stderr = '';
32
+ child.stdout?.on('data', (chunk) => {
33
+ stdout += chunk;
34
+ });
35
+ child.stderr?.on('data', (chunk) => {
36
+ stderr += chunk;
37
+ if (options.inherit)
38
+ process.stderr.write(chunk);
39
+ });
40
+ child.on('error', reject);
41
+ child.on('close', (code) => {
42
+ if (code === 0)
43
+ resolve(stdout);
44
+ else
45
+ reject(new ExecError(render(command, args), code, stderr));
46
+ });
47
+ if (options.input !== undefined)
48
+ child.stdin?.end(options.input);
49
+ }),
50
+ readFile: (path) => readFile(path, 'utf8'),
51
+ writeFile: (path, content) => writeFile(path, content),
52
+ readDir: async (path) => (await readdir(path, { withFileTypes: true })).map((e) => ({ name: e.name, directory: e.isDirectory() })),
53
+ };
54
+ }
55
+ /** The command line as a shell would need it typed: args quoted when they must be. */
56
+ export function render(command, args) {
57
+ return [command, ...args].map(quote).join(' ');
58
+ }
59
+ function quote(arg) {
60
+ return /^[\w./:@%+=,-]+$/.test(arg) ? arg : `'${arg.replaceAll("'", "'\\''")}'`;
61
+ }
62
+ //# sourceMappingURL=io.js.map
package/dist/io.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"io.js","sourceRoot":"","sources":["../src/io.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ export interface Declaration {
2
+ /** The Plexus version the unit was last brought up to, e.g. `0.62.0`. */
3
+ plexus: string;
4
+ /** The module codes it follows, e.g. `PLX-Repo`. */
5
+ modules: string[];
6
+ /** The prose after the frontmatter: what the unit is, and its owned deviations. */
7
+ body: string;
8
+ }
9
+ export declare const MARKER_FILE = "PLEXUS.md";
10
+ export declare function parseMarker(text: string): Declaration;
11
+ /** The YAML between the leading `---` lines, as a plain object, and the rest. */
12
+ export declare function splitFrontmatter(text: string): {
13
+ data: Record<string, unknown>;
14
+ body: string;
15
+ };
16
+ //# sourceMappingURL=marker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"marker.d.ts","sourceRoot":"","sources":["../src/marker.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,WAAW;IAC1B,yEAAyE;IACzE,MAAM,EAAE,MAAM,CAAC;IACf,oDAAoD;IACpD,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,mFAAmF;IACnF,IAAI,EAAE,MAAM,CAAC;CACd;AAED,eAAO,MAAM,WAAW,cAAc,CAAC;AAEvC,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAQrD;AAED,iFAAiF;AACjF,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAM9F"}
package/dist/marker.js ADDED
@@ -0,0 +1,26 @@
1
+ // The declaration marker, PLEXUS.md (§ 1.4 PLX): YAML frontmatter with the
2
+ // Plexus version and the declared modules, then free-form prose. This is the
3
+ // one reader of that shape; every verb that needs a marker parses it here.
4
+ import { parse } from 'yaml';
5
+ export const MARKER_FILE = 'PLEXUS.md';
6
+ export function parseMarker(text) {
7
+ const { data, body } = splitFrontmatter(text);
8
+ const plexus = data.plexus;
9
+ const modules = data.modules;
10
+ if (typeof plexus !== 'string' && typeof plexus !== 'number')
11
+ throw new Error('marker: `plexus` must be a version');
12
+ if (!Array.isArray(modules) || !modules.every((m) => typeof m === 'string'))
13
+ throw new Error('marker: `modules` must be a list of module codes');
14
+ return { plexus: String(plexus), modules, body };
15
+ }
16
+ /** The YAML between the leading `---` lines, as a plain object, and the rest. */
17
+ export function splitFrontmatter(text) {
18
+ const match = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)([\s\S]*)$/.exec(text);
19
+ if (!match)
20
+ throw new Error('no frontmatter: expected a `---` block at the top');
21
+ const data = parse(match[1] ?? '');
22
+ if (data === null || typeof data !== 'object' || Array.isArray(data))
23
+ throw new Error('frontmatter is not a mapping');
24
+ return { data: data, body: match[2] ?? '' };
25
+ }
26
+ //# sourceMappingURL=marker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"marker.js","sourceRoot":"","sources":["../src/marker.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,6EAA6E;AAC7E,2EAA2E;AAC3E,OAAO,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC;AAW7B,MAAM,CAAC,MAAM,WAAW,GAAG,WAAW,CAAC;AAEvC,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAC9C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;IAC3B,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;IAC7B,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;IACpH,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC;QACzE,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;IACtE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AACnD,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,MAAM,KAAK,GAAG,kDAAkD,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5E,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;IACjF,MAAM,IAAI,GAAY,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC5C,IAAI,IAAI,KAAK,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IACtH,OAAO,EAAE,IAAI,EAAE,IAA+B,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;AACzE,CAAC"}