@orkestrel/scaffold 0.0.16 → 0.0.17
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/README.md +13 -3
- package/dist/bin/scaffold.js +67 -31
- package/dist/bin/scaffold.js.map +1 -1
- package/dist/host/claude/agents/orkestrel.md +14 -14
- package/dist/host/guides/src/scaffold.md +55 -18
- package/dist/src/core/index.cjs +170 -32
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +3 -3
- package/dist/src/core/index.d.ts +3 -3
- package/dist/src/core/index.js +170 -32
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +49 -31
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.d.cts +10 -6
- package/dist/src/server/index.d.ts +10 -6
- package/dist/src/server/index.js +49 -31
- package/dist/src/server/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# @orkestrel/scaffold
|
|
2
2
|
|
|
3
|
-
Blueprint-to-plan package scaffolding, auditing, dependency guide/version
|
|
4
|
-
|
|
3
|
+
Blueprint-to-plan package scaffolding, auditing, dependency guide/version pulling,
|
|
4
|
+
complete guide mirroring, and fleet-wide shared-file upkeep for the `@orkestrel` line.
|
|
5
5
|
|
|
6
6
|
## Install
|
|
7
7
|
|
|
@@ -27,6 +27,12 @@ flag from the guided flow works standalone:
|
|
|
27
27
|
|
|
28
28
|
```sh
|
|
29
29
|
npx scaffold new mypackage --src core --app core,browser,server --apply
|
|
30
|
+
|
|
31
|
+
# refresh every published Orkestrel package guide in the current target
|
|
32
|
+
npx scaffold mirror --apply --yes
|
|
33
|
+
|
|
34
|
+
# the same command from this checkout, after npm run build
|
|
35
|
+
node ./dist/bin/scaffold.js mirror --apply --yes
|
|
30
36
|
```
|
|
31
37
|
|
|
32
38
|
In scripts, every verb is dry-run by default and fully non-interactive —
|
|
@@ -48,6 +54,7 @@ Node's default roots. `NODE_EXTRA_CA_CERTS` adds custom PEMs in either case.
|
|
|
48
54
|
```sh
|
|
49
55
|
scaffold new [name] [--src <list>] [--app <list>] [--deps <list>] [--apply] [--yes] [--json]
|
|
50
56
|
scaffold pull [--apply] [--yes] [--json]
|
|
57
|
+
scaffold mirror [--apply] [--yes] [--json]
|
|
51
58
|
scaffold audit [--live] [--json]
|
|
52
59
|
scaffold repair [--prune] [--apply] [--yes] [--json]
|
|
53
60
|
scaffold fleet [--apply] [--yes] [--json]
|
|
@@ -70,6 +77,9 @@ error.
|
|
|
70
77
|
its plan from your `package.json` and stays clean over the addition.
|
|
71
78
|
- **`pull`** — fetches the latest vendored dependency guides and registry versions
|
|
72
79
|
for an existing package and reports drift.
|
|
80
|
+
- **`mirror`** — discovers the exact published `@orkestrel/*` package set from npm and refreshes
|
|
81
|
+
every package's GitHub guide in deterministic name order. It never fetches registry versions or
|
|
82
|
+
overwrites the target package's own guide, and it applies nothing when any guide fetch fails.
|
|
73
83
|
- **`audit`** — a conformance report over the artifacts the plan actually gates: the
|
|
74
84
|
shared host-origin files (presence, or exact bytes once hydrated) AND the generated
|
|
75
85
|
configs/manifest (exact UTF-8 bytes); reports drift as data, findings and all; exits nonzero
|
|
@@ -114,7 +124,7 @@ compiler.destroy()
|
|
|
114
124
|
|
|
115
125
|
`@orkestrel/scaffold/server` carries the impure API — `createMaterializer`
|
|
116
126
|
(writes a `Plan` to disk) and `createSync` (the only part of the system that
|
|
117
|
-
touches the network, fetching dependency guides and registry versions).
|
|
127
|
+
touches the network, fetching dependency guides, fleet guide mirrors, and registry versions).
|
|
118
128
|
|
|
119
129
|
The built host uses an exact `{ entries, roots }` manifest. Staging preflights
|
|
120
130
|
containment and portable file-tree collisions, builds in a temporary sibling,
|
package/dist/bin/scaffold.js
CHANGED
|
@@ -15,6 +15,7 @@ import { parseArgs } from "node:util";
|
|
|
15
15
|
var KNOWN_VERBS = Object.freeze([
|
|
16
16
|
"new",
|
|
17
17
|
"pull",
|
|
18
|
+
"mirror",
|
|
18
19
|
"audit",
|
|
19
20
|
"repair",
|
|
20
21
|
"fleet",
|
|
@@ -92,6 +93,7 @@ var EXIT_CODES = Object.freeze([
|
|
|
92
93
|
var VERB_SUMMARY = Object.freeze({
|
|
93
94
|
new: "scaffold a workspace into ./<name>",
|
|
94
95
|
pull: "refresh vendored guides/versions, report drift",
|
|
96
|
+
mirror: "refresh every published Orkestrel package guide",
|
|
95
97
|
audit: "whole-plan conformance report",
|
|
96
98
|
repair: "restore host-owned files, plus generated canon with --generated",
|
|
97
99
|
fleet: "audit/repair every workspace under the cwd's immediate children",
|
|
@@ -101,6 +103,7 @@ var VERB_SUMMARY = Object.freeze({
|
|
|
101
103
|
var VERB_FLAGS = Object.freeze({
|
|
102
104
|
new: "--src a,b --app a,b --deps x,y --apply --yes --target <path> --from <path>",
|
|
103
105
|
pull: "--target . --deps x,y --apply --yes --strict",
|
|
106
|
+
mirror: "--target . --apply --yes --strict",
|
|
104
107
|
audit: "--target . --live --generated --from <path> --groups a,b",
|
|
105
108
|
repair: "--target . --generated --apply --yes --prune --from <path>",
|
|
106
109
|
fleet: "--generated --apply --yes --prune --from <path>",
|
|
@@ -124,6 +127,12 @@ var VERB_FLAG_HELP = Object.freeze({
|
|
|
124
127
|
["--yes", "skip the confirmation question"],
|
|
125
128
|
["--strict", "fail (exit 1) on any drift, even non-fatal"]
|
|
126
129
|
],
|
|
130
|
+
mirror: [
|
|
131
|
+
["--target .", "directory whose guide mirror is refreshed (default: current directory)"],
|
|
132
|
+
["--apply", "write the refreshed guides (default is a dry run)"],
|
|
133
|
+
["--yes", "skip the confirmation question"],
|
|
134
|
+
["--strict", "fail immediately when an upstream guide cannot be fetched"]
|
|
135
|
+
],
|
|
127
136
|
audit: [
|
|
128
137
|
["--target .", "directory to audit (default: current directory)"],
|
|
129
138
|
["--live", "also check upstream freshness over the network"],
|
|
@@ -158,6 +167,7 @@ var VERB_FLAG_HELP = Object.freeze({
|
|
|
158
167
|
var VERB_DRY_RUN_NOTE = Object.freeze({
|
|
159
168
|
new: "dry run by default — add --apply to write the files, --yes to skip the question",
|
|
160
169
|
pull: "dry run by default — add --apply to write the refreshed files, --yes to skip the question",
|
|
170
|
+
mirror: "dry run by default — add --apply to write every published package guide, --yes to skip the question",
|
|
161
171
|
audit: "read-only — audit never writes; pass --live to also check upstream freshness",
|
|
162
172
|
repair: "dry run by default — add --apply to write, --yes to skip the question",
|
|
163
173
|
fleet: "dry run by default — add --apply to write across every package, --yes to skip the question",
|
|
@@ -167,6 +177,7 @@ var VERB_DRY_RUN_NOTE = Object.freeze({
|
|
|
167
177
|
var VERB_EXAMPLE = Object.freeze({
|
|
168
178
|
new: "example: scaffold new widget --src core,server --app core,browser --apply",
|
|
169
179
|
pull: "example: scaffold pull --apply",
|
|
180
|
+
mirror: "example: scaffold mirror --apply --yes",
|
|
170
181
|
audit: "example: scaffold audit --live",
|
|
171
182
|
repair: "example: scaffold repair --apply",
|
|
172
183
|
fleet: "example: scaffold fleet --apply --yes",
|
|
@@ -355,8 +366,8 @@ function repairSuccess(result, removed) {
|
|
|
355
366
|
const written = result.written.length + result.copied.length;
|
|
356
367
|
return `${ACTION_LABEL.written} ${written}, ${ACTION_LABEL.skipped} ${result.skipped.length}, ${ACTION_LABEL.removed} ${removed.length}`;
|
|
357
368
|
}
|
|
358
|
-
/** Render
|
|
359
|
-
function
|
|
369
|
+
/** Render synchronization freshness as table rows. */
|
|
370
|
+
function syncRows(report) {
|
|
360
371
|
const guides = report.guides.map((guide) => [
|
|
361
372
|
guide.name,
|
|
362
373
|
"guide",
|
|
@@ -369,27 +380,28 @@ function pullRows(report) {
|
|
|
369
380
|
]);
|
|
370
381
|
return [...guides, ...versions];
|
|
371
382
|
}
|
|
372
|
-
/** Create
|
|
373
|
-
function
|
|
383
|
+
/** Create a synchronization terminal table. */
|
|
384
|
+
function syncTable(report) {
|
|
374
385
|
return {
|
|
375
386
|
columns: [
|
|
376
387
|
{ label: "Name" },
|
|
377
388
|
{ label: "Kind" },
|
|
378
389
|
{ label: "Freshness" }
|
|
379
390
|
],
|
|
380
|
-
rows:
|
|
391
|
+
rows: syncRows(report)
|
|
381
392
|
};
|
|
382
393
|
}
|
|
383
|
-
/** Render cause notes from non-current
|
|
384
|
-
function
|
|
394
|
+
/** Render cause notes from non-current synchronization entries. */
|
|
395
|
+
function syncCauseNotes(report) {
|
|
385
396
|
return [...report.guides, ...report.versions].filter((entry) => entry.note !== void 0).map((entry) => ` ${entry.name}: ${FRESHNESS_LABEL[entry.freshness] ?? entry.freshness} — ${entry.note}`);
|
|
386
397
|
}
|
|
387
|
-
/** Render
|
|
388
|
-
function
|
|
389
|
-
|
|
398
|
+
/** Render a command-specific synchronization tally. */
|
|
399
|
+
function syncVerdict(report, action) {
|
|
400
|
+
const count = report.guides.length + report.versions.length;
|
|
401
|
+
return `${action}: ${String(count)} ${count === 1 ? "entry" : "entries"} — ${String(report.failed)} failed`;
|
|
390
402
|
}
|
|
391
|
-
/** Render
|
|
392
|
-
function
|
|
403
|
+
/** Render a synchronization success tally. */
|
|
404
|
+
function syncSuccess(count) {
|
|
393
405
|
return `wrote ${countPart(count, "guide")}`;
|
|
394
406
|
}
|
|
395
407
|
/** Render one fleet repository outcome. */
|
|
@@ -1117,30 +1129,52 @@ var CLI = class {
|
|
|
1117
1129
|
} catch (error) {
|
|
1118
1130
|
this.#error(error, json);
|
|
1119
1131
|
}
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1132
|
+
await this.#refresh(sync, report, target, values, json, "pull", true);
|
|
1133
|
+
} finally {
|
|
1134
|
+
sync.destroy();
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
/** `scaffold mirror` — refresh every published Orkestrel package guide. */
|
|
1138
|
+
async #mirror(values, json) {
|
|
1139
|
+
const target = this.#contain(values.target ?? ".", json);
|
|
1140
|
+
const sync = createSync(values.strict === void 0 ? this.#sync : {
|
|
1141
|
+
...this.#sync,
|
|
1142
|
+
strict: values.strict
|
|
1143
|
+
});
|
|
1144
|
+
try {
|
|
1145
|
+
let report;
|
|
1146
|
+
try {
|
|
1147
|
+
report = await sync.mirror(target);
|
|
1148
|
+
} catch (error) {
|
|
1149
|
+
this.#error(error, json);
|
|
1124
1150
|
}
|
|
1125
|
-
|
|
1126
|
-
const terminal = createTerminal();
|
|
1127
|
-
const proceed = toWrite > 0 ? await this.#apply(terminal, applyConfirmMessage(toWrite), values, json) : false;
|
|
1128
|
-
if (proceed) {
|
|
1129
|
-
const spinner = this.#spinner("writing mirrors", json);
|
|
1130
|
-
spinner?.start();
|
|
1131
|
-
try {
|
|
1132
|
-
const written = await sync.write(report, target);
|
|
1133
|
-
if (json) this.#write(report);
|
|
1134
|
-
else this.#succeed(spinner, json, pullSuccess(written.length));
|
|
1135
|
-
} catch (error) {
|
|
1136
|
-
this.#reject(spinner, json, error);
|
|
1137
|
-
}
|
|
1138
|
-
} else if (json) this.#write(report);
|
|
1139
|
-
process.exitCode = report.clean ? 0 : proceed ? 0 : 1;
|
|
1151
|
+
await this.#refresh(sync, report, target, values, json, "mirror", report.failed === 0);
|
|
1140
1152
|
} finally {
|
|
1141
1153
|
sync.destroy();
|
|
1142
1154
|
}
|
|
1143
1155
|
}
|
|
1156
|
+
async #refresh(sync, report, target, values, json, action, writable) {
|
|
1157
|
+
if (!json) {
|
|
1158
|
+
this.#reporter.table(syncTable(report));
|
|
1159
|
+
for (const line of syncCauseNotes(report)) this.#reporter.line(line);
|
|
1160
|
+
this.#reporter.line(syncVerdict(report, action));
|
|
1161
|
+
}
|
|
1162
|
+
const toWrite = [...report.guides, ...report.versions].filter((entry) => entry.freshness !== "current").length;
|
|
1163
|
+
const terminal = createTerminal();
|
|
1164
|
+
const proceed = writable && toWrite > 0 ? await this.#apply(terminal, applyConfirmMessage(toWrite), values, json) : false;
|
|
1165
|
+
if (proceed) {
|
|
1166
|
+
const spinner = this.#spinner("writing mirrors", json);
|
|
1167
|
+
spinner?.start();
|
|
1168
|
+
try {
|
|
1169
|
+
const written = await sync.write(report, target);
|
|
1170
|
+
if (json) this.#write(report);
|
|
1171
|
+
else this.#succeed(spinner, json, syncSuccess(written.length));
|
|
1172
|
+
} catch (error) {
|
|
1173
|
+
this.#reject(spinner, json, error);
|
|
1174
|
+
}
|
|
1175
|
+
} else if (json) this.#write(report);
|
|
1176
|
+
process.exitCode = report.clean ? 0 : proceed ? 0 : 1;
|
|
1177
|
+
}
|
|
1144
1178
|
/** `scaffold audit` — whole-plan conformance report; offers a repair handoff on drift. */
|
|
1145
1179
|
async #audit(values, json) {
|
|
1146
1180
|
const target = this.#contain(values.target ?? ".", json);
|
|
@@ -1602,6 +1636,7 @@ var CLI = class {
|
|
|
1602
1636
|
}
|
|
1603
1637
|
if (!isVerb(command)) this.#usage(didYouMean(command), json);
|
|
1604
1638
|
if (command !== "catalog" && values.from !== void 0 && values.from.length > 1) this.#usage(`--from may be provided only once for '${command}'`, json);
|
|
1639
|
+
if (command === "mirror" && values.deps !== void 0) this.#usage("--deps is not supported for 'mirror'; use 'pull --deps'", json);
|
|
1605
1640
|
if (values.help) {
|
|
1606
1641
|
process.stdout.write(`${verbHelp(command)}\n`);
|
|
1607
1642
|
process.exitCode = 0;
|
|
@@ -1609,6 +1644,7 @@ var CLI = class {
|
|
|
1609
1644
|
}
|
|
1610
1645
|
if (command === "new") return this.#new(values, argument, json);
|
|
1611
1646
|
if (command === "pull") return this.#pull(values, json);
|
|
1647
|
+
if (command === "mirror") return this.#mirror(values, json);
|
|
1612
1648
|
if (command === "audit") return this.#audit(values, json);
|
|
1613
1649
|
if (command === "repair") return this.#repair(values, json);
|
|
1614
1650
|
if (command === "fleet") return this.#fleet(values, json);
|