@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.
- package/LICENSE +674 -0
- package/dist/catalog.d.ts +23 -0
- package/dist/catalog.d.ts.map +1 -0
- package/dist/catalog.js +38 -0
- package/dist/catalog.js.map +1 -0
- package/dist/context.d.ts +41 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +115 -0
- package/dist/context.js.map +1 -0
- package/dist/copier.d.ts +12 -0
- package/dist/copier.d.ts.map +1 -0
- package/dist/copier.js +19 -0
- package/dist/copier.js.map +1 -0
- package/dist/doctor.d.ts +19 -0
- package/dist/doctor.d.ts.map +1 -0
- package/dist/doctor.js +79 -0
- package/dist/doctor.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/io.d.ts +40 -0
- package/dist/io.d.ts.map +1 -0
- package/dist/io.js +62 -0
- package/dist/io.js.map +1 -0
- package/dist/marker.d.ts +16 -0
- package/dist/marker.d.ts.map +1 -0
- package/dist/marker.js +26 -0
- package/dist/marker.js.map +1 -0
- package/dist/model.d.ts +35 -0
- package/dist/model.d.ts.map +1 -0
- package/dist/model.js +22 -0
- package/dist/model.js.map +1 -0
- package/dist/overview.d.ts +10 -0
- package/dist/overview.d.ts.map +1 -0
- package/dist/overview.js +118 -0
- package/dist/overview.js.map +1 -0
- package/dist/plan.d.ts +28 -0
- package/dist/plan.d.ts.map +1 -0
- package/dist/plan.js +40 -0
- package/dist/plan.js.map +1 -0
- package/package.json +38 -3
- package/README.md +0 -3
package/dist/model.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { Answers } from './copier.ts';
|
|
2
|
+
import type { Declaration } from './marker.ts';
|
|
3
|
+
export interface Directory {
|
|
4
|
+
name: string;
|
|
5
|
+
path: string;
|
|
6
|
+
git?: GitFacet;
|
|
7
|
+
template?: TemplateFacet;
|
|
8
|
+
copier?: Answers;
|
|
9
|
+
declaration?: Declaration;
|
|
10
|
+
/** Marker files that could not be read; shown, never fatal. */
|
|
11
|
+
problems?: string[];
|
|
12
|
+
children: Directory[];
|
|
13
|
+
}
|
|
14
|
+
export interface GitFacet {
|
|
15
|
+
/** The checked-out branch, or the short commit when detached. */
|
|
16
|
+
branch: string;
|
|
17
|
+
/** Uncommitted tracked or untracked changes. */
|
|
18
|
+
dirty: boolean;
|
|
19
|
+
/** The most recent tag reachable from the default branch, if any. */
|
|
20
|
+
tag?: string;
|
|
21
|
+
/** The `origin` remote, shortened: `gh:org/repo` for GitHub. */
|
|
22
|
+
remote?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface TemplateFacet {
|
|
25
|
+
/** The template repo's most recent tag, if any. */
|
|
26
|
+
tag?: string;
|
|
27
|
+
}
|
|
28
|
+
export type Kind = 'app' | 'platform' | 'repo';
|
|
29
|
+
/** What a declaration makes a directory, by the modules it follows. */
|
|
30
|
+
export declare function kindOf(declaration: Declaration): Kind | undefined;
|
|
31
|
+
/** A git remote URL as a short handle: `gh:org/repo` for GitHub, the URL otherwise. */
|
|
32
|
+
export declare function shortRemote(url: string): string;
|
|
33
|
+
/** Whether a directory, or anything below it, carries a facet worth showing. */
|
|
34
|
+
export declare function isNotable(dir: Directory): boolean;
|
|
35
|
+
//# sourceMappingURL=model.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,QAAQ,CAAC;IACf,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,EAAE,SAAS,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,QAAQ;IACvB,iEAAiE;IACjE,MAAM,EAAE,MAAM,CAAC;IACf,gDAAgD;IAChD,KAAK,EAAE,OAAO,CAAC;IACf,qEAAqE;IACrE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,mDAAmD;IACnD,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,IAAI,GAAG,KAAK,GAAG,UAAU,GAAG,MAAM,CAAC;AAE/C,uEAAuE;AACvE,wBAAgB,MAAM,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,CAMjE;AAED,uFAAuF;AACvF,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAI/C;AAED,gFAAgF;AAChF,wBAAgB,SAAS,CAAC,GAAG,EAAE,SAAS,GAAG,OAAO,CAEjD"}
|
package/dist/model.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** What a declaration makes a directory, by the modules it follows. */
|
|
2
|
+
export function kindOf(declaration) {
|
|
3
|
+
const has = (code) => declaration.modules.includes(code);
|
|
4
|
+
if (has('PLX-App'))
|
|
5
|
+
return 'app';
|
|
6
|
+
if (has('PLX-Platform'))
|
|
7
|
+
return 'platform';
|
|
8
|
+
if (has('PLX-Repo'))
|
|
9
|
+
return 'repo';
|
|
10
|
+
return undefined;
|
|
11
|
+
}
|
|
12
|
+
/** A git remote URL as a short handle: `gh:org/repo` for GitHub, the URL otherwise. */
|
|
13
|
+
export function shortRemote(url) {
|
|
14
|
+
const bare = url.replace(/\.git$/, '').replace(/\/$/, '');
|
|
15
|
+
const m = /^(?:git@github\.com:|github\.com:|ssh:\/\/git@github\.com\/|https?:\/\/github\.com\/)(.+)$/.exec(bare);
|
|
16
|
+
return m ? `gh:${m[1]}` : bare;
|
|
17
|
+
}
|
|
18
|
+
/** Whether a directory, or anything below it, carries a facet worth showing. */
|
|
19
|
+
export function isNotable(dir) {
|
|
20
|
+
return Boolean(dir.git || dir.template || dir.copier || dir.declaration || dir.problems?.length);
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=model.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model.js","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAqCA,uEAAuE;AACvE,MAAM,UAAU,MAAM,CAAC,WAAwB;IAC7C,MAAM,GAAG,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,WAAW,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACjE,IAAI,GAAG,CAAC,SAAS,CAAC;QAAE,OAAO,KAAK,CAAC;IACjC,IAAI,GAAG,CAAC,cAAc,CAAC;QAAE,OAAO,UAAU,CAAC;IAC3C,IAAI,GAAG,CAAC,UAAU,CAAC;QAAE,OAAO,MAAM,CAAC;IACnC,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,uFAAuF;AACvF,MAAM,UAAU,WAAW,CAAC,GAAW;IACrC,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC1D,MAAM,CAAC,GAAG,4FAA4F,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClH,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AACjC,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,SAAS,CAAC,GAAc;IACtC,OAAO,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,WAAW,IAAI,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;AACnG,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Context } from './context.ts';
|
|
2
|
+
import { type Directory } from './model.ts';
|
|
3
|
+
/** Heavy or generated directories never descended into. `.git` is the repo marker and is handled apart. */
|
|
4
|
+
export declare const PRUNED: Set<string>;
|
|
5
|
+
export interface ScanOptions {
|
|
6
|
+
/** Read the git facets (four git calls per repo); off for verbs that only need markers. */
|
|
7
|
+
git?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare function overview(ctx: Context, root: string, options?: ScanOptions): Promise<Directory>;
|
|
10
|
+
//# sourceMappingURL=overview.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"overview.d.ts","sourceRoot":"","sources":["../src/overview.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAG5C,OAAO,EAAE,KAAK,SAAS,EAA6D,MAAM,YAAY,CAAC;AAEvG,2GAA2G;AAC3G,eAAO,MAAM,MAAM,aAsBjB,CAAC;AAEH,MAAM,WAAW,WAAW;IAC1B,2FAA2F;IAC3F,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,SAAS,CAAC,CAElG"}
|
package/dist/overview.js
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
// overview: the map of a folder of repos (the toolbox's overview.sh, moved).
|
|
2
|
+
//
|
|
3
|
+
// Walk a directory, note for every directory whether it is a git repo, a
|
|
4
|
+
// copier template, a copier-managed project, or a declared Plexus unit, and
|
|
5
|
+
// return the tree of directories that carry such a facet, with the ancestors
|
|
6
|
+
// needed to reach them. Reads only: there is nothing to plan or apply.
|
|
7
|
+
//
|
|
8
|
+
// plx overview # map the current directory
|
|
9
|
+
// plx overview ~/dev # map somewhere else
|
|
10
|
+
import { join } from 'node:path';
|
|
11
|
+
import { ANSWERS_FILE, parseAnswers, TEMPLATE_FILES } from "./copier.js";
|
|
12
|
+
import { MARKER_FILE, parseMarker } from "./marker.js";
|
|
13
|
+
import { isNotable, shortRemote } from "./model.js";
|
|
14
|
+
/** Heavy or generated directories never descended into. `.git` is the repo marker and is handled apart. */
|
|
15
|
+
export const PRUNED = new Set([
|
|
16
|
+
'node_modules',
|
|
17
|
+
'.hg',
|
|
18
|
+
'.svn',
|
|
19
|
+
'.next',
|
|
20
|
+
'.nuxt',
|
|
21
|
+
'.turbo',
|
|
22
|
+
'.svelte-kit',
|
|
23
|
+
'dist',
|
|
24
|
+
'build',
|
|
25
|
+
'out',
|
|
26
|
+
'.output',
|
|
27
|
+
'.venv',
|
|
28
|
+
'venv',
|
|
29
|
+
'__pycache__',
|
|
30
|
+
'target',
|
|
31
|
+
'.cache',
|
|
32
|
+
'.pnpm-store',
|
|
33
|
+
'coverage',
|
|
34
|
+
'vendor',
|
|
35
|
+
'.terraform',
|
|
36
|
+
'.gradle',
|
|
37
|
+
]);
|
|
38
|
+
export function overview(ctx, root, options = {}) {
|
|
39
|
+
return walk(ctx, root, root.replace(/\/+$/, '').split('/').pop() || root, { git: true, ...options });
|
|
40
|
+
}
|
|
41
|
+
async function walk(ctx, path, name, options) {
|
|
42
|
+
const entries = await ctx.readDir(path);
|
|
43
|
+
const files = new Set(entries.filter((e) => !e.directory).map((e) => e.name));
|
|
44
|
+
const names = new Set(entries.map((e) => e.name));
|
|
45
|
+
const dir = { name, path, children: [] };
|
|
46
|
+
// `.git` is a directory for a checkout and a file for a worktree or submodule.
|
|
47
|
+
if (names.has('.git') && options.git)
|
|
48
|
+
dir.git = await gitFacet(ctx, path);
|
|
49
|
+
if (TEMPLATE_FILES.some((f) => files.has(f)))
|
|
50
|
+
dir.template = options.git ? await templateFacet(ctx, path) : {};
|
|
51
|
+
if (files.has(ANSWERS_FILE)) {
|
|
52
|
+
await facet(ctx, dir, ANSWERS_FILE, (text) => {
|
|
53
|
+
dir.copier = parseAnswers(text);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
if (files.has(MARKER_FILE)) {
|
|
57
|
+
await facet(ctx, dir, MARKER_FILE, (text) => {
|
|
58
|
+
dir.declaration = parseMarker(text);
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
const subdirs = entries
|
|
62
|
+
.filter((e) => e.directory && e.name !== '.git' && !PRUNED.has(e.name))
|
|
63
|
+
.map((e) => e.name)
|
|
64
|
+
.sort();
|
|
65
|
+
for (const sub of subdirs) {
|
|
66
|
+
const child = await walk(ctx, join(path, sub), sub, options);
|
|
67
|
+
if (isNotable(child) || child.children.length > 0)
|
|
68
|
+
dir.children.push(child);
|
|
69
|
+
}
|
|
70
|
+
return dir;
|
|
71
|
+
}
|
|
72
|
+
async function facet(ctx, dir, file, read) {
|
|
73
|
+
try {
|
|
74
|
+
read(await ctx.readFile(join(dir.path, file)));
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
dir.problems ??= [];
|
|
78
|
+
dir.problems.push(`${file}: ${error instanceof Error ? error.message : String(error)}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/** A git read that may legitimately fail (no remote, no tag, detached): undefined then. */
|
|
82
|
+
async function git(ctx, cwd, args) {
|
|
83
|
+
try {
|
|
84
|
+
const out = (await ctx.read('git', args, { cwd })).trim();
|
|
85
|
+
return out === '' ? undefined : out;
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
async function gitFacet(ctx, cwd) {
|
|
92
|
+
const branch = (await git(ctx, cwd, ['symbolic-ref', '--short', '-q', 'HEAD'])) ??
|
|
93
|
+
(await git(ctx, cwd, ['rev-parse', '--short', 'HEAD'])) ??
|
|
94
|
+
'?';
|
|
95
|
+
const dirty = (await git(ctx, cwd, ['status', '--porcelain'])) !== undefined;
|
|
96
|
+
const remote = await git(ctx, cwd, ['remote', 'get-url', 'origin']);
|
|
97
|
+
// The most recent tag reachable from the default branch: origin/HEAD, else a local main or master.
|
|
98
|
+
let defaultRef = await git(ctx, cwd, ['symbolic-ref', '--short', '-q', 'refs/remotes/origin/HEAD']);
|
|
99
|
+
for (const b of ['main', 'master']) {
|
|
100
|
+
if (defaultRef)
|
|
101
|
+
break;
|
|
102
|
+
if (await git(ctx, cwd, ['rev-parse', '--verify', '-q', `refs/heads/${b}`]))
|
|
103
|
+
defaultRef = b;
|
|
104
|
+
}
|
|
105
|
+
const tag = defaultRef ? await git(ctx, cwd, ['describe', '--tags', '--abbrev=0', defaultRef]) : undefined;
|
|
106
|
+
const facet = { branch, dirty };
|
|
107
|
+
if (tag)
|
|
108
|
+
facet.tag = tag;
|
|
109
|
+
if (remote)
|
|
110
|
+
facet.remote = shortRemote(remote);
|
|
111
|
+
return facet;
|
|
112
|
+
}
|
|
113
|
+
async function templateFacet(ctx, cwd) {
|
|
114
|
+
const tag = (await git(ctx, cwd, ['describe', '--tags', '--abbrev=0'])) ??
|
|
115
|
+
(await git(ctx, cwd, ['tag', '--list', '--sort=-v:refname']))?.split('\n')[0];
|
|
116
|
+
return tag ? { tag } : {};
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=overview.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"overview.js","sourceRoot":"","sources":["../src/overview.ts"],"names":[],"mappings":"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"}
|
package/dist/plan.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export type Step = {
|
|
2
|
+
kind: 'run';
|
|
3
|
+
command: string;
|
|
4
|
+
args: string[];
|
|
5
|
+
cwd?: string;
|
|
6
|
+
input?: string;
|
|
7
|
+
} | {
|
|
8
|
+
kind: 'ssh';
|
|
9
|
+
host: string;
|
|
10
|
+
script: string;
|
|
11
|
+
} | {
|
|
12
|
+
kind: 'write';
|
|
13
|
+
path: string;
|
|
14
|
+
content: string;
|
|
15
|
+
};
|
|
16
|
+
export type Plan = Step[];
|
|
17
|
+
export declare const run: (command: string, args?: string[], options?: {
|
|
18
|
+
cwd?: string;
|
|
19
|
+
input?: string;
|
|
20
|
+
}) => Step;
|
|
21
|
+
/** Feed a bash script to a host: the remote half of a verb stays bash, carried verbatim. */
|
|
22
|
+
export declare const ssh: (host: string, script: string) => Step;
|
|
23
|
+
export declare const write: (path: string, content: string) => Step;
|
|
24
|
+
/** One line, the shell equivalent of the step. */
|
|
25
|
+
export declare function describe(step: Step): string;
|
|
26
|
+
/** What a step feeds in, shown at higher verbosity under its description. */
|
|
27
|
+
export declare function body(step: Step): string | undefined;
|
|
28
|
+
//# sourceMappingURL=plan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../src/plan.ts"],"names":[],"mappings":"AASA,MAAM,MAAM,IAAI,GACZ;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9E;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC7C;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAErD,MAAM,MAAM,IAAI,GAAG,IAAI,EAAE,CAAC;AAE1B,eAAO,MAAM,GAAG,GAAI,SAAS,MAAM,EAAE,OAAM,MAAM,EAAO,EAAE,UAAS;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,KAAG,IAKzG,CAAC;AAEH,4FAA4F;AAC5F,eAAO,MAAM,GAAG,GAAI,MAAM,MAAM,EAAE,QAAQ,MAAM,KAAG,IAAuC,CAAC;AAE3F,eAAO,MAAM,KAAK,GAAI,MAAM,MAAM,EAAE,SAAS,MAAM,KAAG,IAA0C,CAAC;AAEjG,kDAAkD;AAClD,wBAAgB,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAS3C;AAED,6EAA6E;AAC7E,wBAAgB,IAAI,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,SAAS,CASnD"}
|
package/dist/plan.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// A Plan is what a command decides to do, as data: the effects, in order.
|
|
2
|
+
//
|
|
3
|
+
// A command's core computes a Plan from what it read (pure, testable by
|
|
4
|
+
// comparing plans), the Context applies it (context.ts). Printing a plan is
|
|
5
|
+
// the dry run; applying it is the real run; both come from the one Plan, so
|
|
6
|
+
// they cannot drift. Describing a step gives the exact shell a stranded
|
|
7
|
+
// operator would type instead.
|
|
8
|
+
import { render } from "./io.js";
|
|
9
|
+
export const run = (command, args = [], options = {}) => ({
|
|
10
|
+
kind: 'run',
|
|
11
|
+
command,
|
|
12
|
+
args,
|
|
13
|
+
...options,
|
|
14
|
+
});
|
|
15
|
+
/** Feed a bash script to a host: the remote half of a verb stays bash, carried verbatim. */
|
|
16
|
+
export const ssh = (host, script) => ({ kind: 'ssh', host, script });
|
|
17
|
+
export const write = (path, content) => ({ kind: 'write', path, content });
|
|
18
|
+
/** One line, the shell equivalent of the step. */
|
|
19
|
+
export function describe(step) {
|
|
20
|
+
switch (step.kind) {
|
|
21
|
+
case 'run':
|
|
22
|
+
return `$ ${step.cwd ? `(cd ${step.cwd} && ` : ''}${render(step.command, step.args)}${step.cwd ? ')' : ''}`;
|
|
23
|
+
case 'ssh':
|
|
24
|
+
return `$ ${render('ssh', [step.host, 'bash', '-s'])} <<'EOF'`;
|
|
25
|
+
case 'write':
|
|
26
|
+
return `> ${step.path} (${Buffer.byteLength(step.content)} bytes)`;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/** What a step feeds in, shown at higher verbosity under its description. */
|
|
30
|
+
export function body(step) {
|
|
31
|
+
switch (step.kind) {
|
|
32
|
+
case 'run':
|
|
33
|
+
return step.input;
|
|
34
|
+
case 'ssh':
|
|
35
|
+
return `${step.script.trimEnd()}\nEOF`;
|
|
36
|
+
case 'write':
|
|
37
|
+
return step.content;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=plan.js.map
|
package/dist/plan.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan.js","sourceRoot":"","sources":["../src/plan.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,EAAE;AACF,wEAAwE;AACxE,4EAA4E;AAC5E,4EAA4E;AAC5E,wEAAwE;AACxE,+BAA+B;AAC/B,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AASjC,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,OAAe,EAAE,OAAiB,EAAE,EAAE,UAA4C,EAAE,EAAQ,EAAE,CAAC,CAAC;IAClH,IAAI,EAAE,KAAK;IACX,OAAO;IACP,IAAI;IACJ,GAAG,OAAO;CACX,CAAC,CAAC;AAEH,4FAA4F;AAC5F,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,IAAY,EAAE,MAAc,EAAQ,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;AAE3F,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,IAAY,EAAE,OAAe,EAAQ,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;AAEjG,kDAAkD;AAClD,MAAM,UAAU,QAAQ,CAAC,IAAU;IACjC,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;QAClB,KAAK,KAAK;YACR,OAAO,KAAK,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;QAC9G,KAAK,KAAK;YACR,OAAO,KAAK,MAAM,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,UAAU,CAAC;QACjE,KAAK,OAAO;YACV,OAAO,KAAK,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC;IACvE,CAAC;AACH,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,IAAI,CAAC,IAAU;IAC7B,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;QAClB,KAAK,KAAK;YACR,OAAO,IAAI,CAAC,KAAK,CAAC;QACpB,KAAK,KAAK;YACR,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC;QACzC,KAAK,OAAO;YACV,OAAO,IAAI,CAAC,OAAO,CAAC;IACxB,CAAC;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,41 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plexus-ms/lib",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "The Plexus verbs as a library: the plan-then-apply core behind plx, and the one parser of Plexus's own file shapes",
|
|
5
|
+
"license": "GPL-3.0-or-later",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/plexus-ms/packages.git",
|
|
20
|
+
"directory": "packages/lib"
|
|
21
|
+
},
|
|
22
|
+
"publishConfig": {
|
|
23
|
+
"registry": "https://registry.npmjs.org",
|
|
24
|
+
"access": "public"
|
|
25
|
+
},
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=24"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"yaml": "^2.9.1"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@types/node": "^26.1.2",
|
|
34
|
+
"typescript": "^6.0.3"
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "tsc",
|
|
38
|
+
"check": "tsc --noEmit",
|
|
39
|
+
"test": "node --test"
|
|
40
|
+
}
|
|
6
41
|
}
|
package/README.md
DELETED