@orkestrel/scaffold 0.0.81 → 0.0.82
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/dist/bin/main.js +167 -13
- package/dist/bin/main.js.map +1 -1
- package/dist/host/AGENTS.md +5 -3
- package/dist/host/agents/skills/orkestrel-harden/references/centralization.md +2 -2
- package/dist/host/agents/skills/orkestrel-journey/SKILL.md +41 -38
- package/dist/host/agents/skills/orkestrel-journey/references/captures.md +3 -3
- package/dist/host/agents/skills/orkestrel-journey/references/decide.md +3 -3
- package/dist/host/agents/skills/orkestrel-journey/references/layer.md +5 -5
- package/dist/host/agents/skills/orkestrel-journey/references/statechart.md +3 -3
- package/dist/host/agents/skills/orkestrel-journey/references/styles.md +9 -9
- package/dist/host/claude/rules/application.md +20 -6
- package/dist/host/claude/rules/architecture.md +2 -2
- package/dist/host/claude/rules/browser.md +9 -0
- package/dist/host/claude/rules/documentation.md +2 -1
- package/dist/host/claude/rules/styles.md +35 -12
- package/dist/host/claude/rules/tests.md +15 -10
- package/dist/host/claude/rules/workspace.md +128 -98
- package/dist/host/claude/skills/orkestrel-journey/SKILL.md +1 -1
- package/dist/host/configs/helpers.ts +157 -9
- package/dist/host/configs/policy.ts +64 -61
- package/dist/host/dotfiles/oxlintrc.json +132 -16
- package/dist/host/dotfiles/prettierignore +1 -1
- package/dist/host/guides/README.md +9 -5
- package/dist/host/guides/scaffold.md +475 -115
- package/dist/host/manifest.json +26 -26
- package/dist/host/tests/config.test.ts +996 -39
- package/dist/host/tests/policy.test.ts +11 -0
- package/dist/host/tests/setupPolicy.ts +396 -22
- package/dist/src/core/index.cjs +1261 -159
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +297 -35
- package/dist/src/core/index.d.ts +297 -35
- package/dist/src/core/index.js +1241 -160
- package/dist/src/core/index.js.map +1 -1
- package/package.json +1 -1
package/dist/bin/main.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { align, renderTable, strip, stripControls, width } from "@orkestrel/console";
|
|
3
3
|
import { attempt, isArray, isError, isInstance, isRecord, isString, parseJSON } from "@orkestrel/contract";
|
|
4
|
-
import { BIN_ENTRY_PATH, CATALOG_AGENT_PATH, CONFORMANCE_TEST_PATH, Compiler, DEPENDENCY_NAME_PATTERN, ENVIRONMENTS, GLOBAL_SETUP_PATH, GROUPS, GUIDES_TEST_PATH, HOST_PATHS, INTEGRATION_TEST_PATH, JOURNEY_CONFIG_PATH, MAX_MANIFEST_BYTES, MAX_PATH_LENGTH, SERVICE_SETUP_PATH, SHOWCASE_CONFIG_PATH, SKILLS_CONFIG_PATH, ScaffoldError, blueprintToConfigArtifacts, blueprintToDevDependencies,
|
|
4
|
+
import { AXES, BIN_ENTRY_PATH, CATALOG_AGENT_PATH, CONFORMANCE_TEST_PATH, Compiler, DEPENDENCY_NAME_PATTERN, ENVIRONMENTS, FRAMEWORKS, GLOBAL_SETUP_PATH, GROUPS, GUIDES_TEST_PATH, HOST_PATHS, INTEGRATION_TEST_PATH, JOURNEY_CONFIG_PATH, MAX_MANIFEST_BYTES, MAX_PATH_LENGTH, RESERVED_SHEET_NAMES, SERVICE_SETUP_PATH, SHEET_ENTRY_NAME, SHOWCASE_CONFIG_PATH, SHOWCASE_PAGES_PATH, SKILLS_CONFIG_PATH, STYLES_ENTRY_PATH, ScaffoldError, THEMES_BARREL_PATH, THEMES_ENTRY_PATH, blueprintToConfigArtifacts, blueprintToDevDependencies, blueprintToFaces, blueprintToProjects, blueprintToScripts, blueprintToSheets, blueprintToTestArtifacts, blueprintToWritableScripts, compareVersions, createBlueprint, extractRangeMajor, extractVersion, isFloorPath, isScaffoldError, isSheetName, manifestToDependencies, manifestToName, nameToGuide, parseExtension, replaceManifestScripts, replacePlanRanges } from "../src/core/index.js";
|
|
5
5
|
import { MAX_INVENTORY_PATHS, Materializer, Upstream, filesToHost, isExactCaseFile, isPhysicalDirectory, isWorktree, listFiles, readFileText, readHostFloor, readHostManifest, readSnapshot, resolveContainedPath } from "../src/server/index.js";
|
|
6
6
|
import { createMarkdown, flattenText, isTableNode } from "@orkestrel/markdown";
|
|
7
7
|
import { createSession } from "@orkestrel/process/server";
|
|
8
|
+
import { readdirSync } from "node:fs";
|
|
9
|
+
import { normalize } from "node:path";
|
|
8
10
|
import { parseArgs } from "node:util";
|
|
9
11
|
//#region src/bin/constants.ts
|
|
10
12
|
/**
|
|
@@ -82,6 +84,13 @@ var COMMAND_OPTIONS = Object.freeze({
|
|
|
82
84
|
src: Object.freeze({ type: "string" }),
|
|
83
85
|
app: Object.freeze({ type: "string" }),
|
|
84
86
|
bin: Object.freeze({ type: "boolean" }),
|
|
87
|
+
styles: Object.freeze({ type: "boolean" }),
|
|
88
|
+
themes: Object.freeze({ type: "boolean" }),
|
|
89
|
+
showcase: Object.freeze({ type: "boolean" }),
|
|
90
|
+
extend: Object.freeze({
|
|
91
|
+
type: "string",
|
|
92
|
+
multiple: true
|
|
93
|
+
}),
|
|
85
94
|
deps: Object.freeze({ type: "string" }),
|
|
86
95
|
groups: Object.freeze({ type: "string" }),
|
|
87
96
|
all: Object.freeze({ type: "boolean" }),
|
|
@@ -106,6 +115,10 @@ var OPTION_SUMMARY = Object.freeze({
|
|
|
106
115
|
"--src <list>": "the published library environments to build: core, browser, server",
|
|
107
116
|
"--app <list>": "the private application environments to build: core, browser, server",
|
|
108
117
|
"--bin": "scaffold a command-line executable at src/bin/main.ts",
|
|
118
|
+
"--styles": "select the base styles surface",
|
|
119
|
+
"--themes": "select themes; requires --styles",
|
|
120
|
+
"--showcase": "select the showcase; requires --app browser",
|
|
121
|
+
"--extend <list>": "select surface:name extensions on the selected surfaces",
|
|
109
122
|
"--deps <list>": "the @orkestrel/* packages the workspace depends on",
|
|
110
123
|
"--groups <list>": "the artifact groups to cover; every group when absent",
|
|
111
124
|
"--all": "fetch a guide for every package the organization publishes, not the declared ones alone",
|
|
@@ -131,6 +144,10 @@ var VERB_OPTIONS = Object.freeze({
|
|
|
131
144
|
"--src <list>",
|
|
132
145
|
"--app <list>",
|
|
133
146
|
"--bin",
|
|
147
|
+
"--styles",
|
|
148
|
+
"--themes",
|
|
149
|
+
"--showcase",
|
|
150
|
+
"--extend <list>",
|
|
134
151
|
"--deps <list>",
|
|
135
152
|
"--offline",
|
|
136
153
|
"--from <path>",
|
|
@@ -383,6 +400,9 @@ function argvToCommand(argv) {
|
|
|
383
400
|
const target = isString(values.target) ? values.target : void 0;
|
|
384
401
|
const json = values.json === true;
|
|
385
402
|
const [from] = paths;
|
|
403
|
+
const extensions = isArray(values.extend) ? values.extend.filter(isString) : [];
|
|
404
|
+
if (extensions.length > 1) throw new UsageError("'new' takes --extend once; combine entries in one list.");
|
|
405
|
+
const [extension] = extensions;
|
|
386
406
|
const location = target === void 0 ? {} : { target };
|
|
387
407
|
const source = from === void 0 ? {} : { from };
|
|
388
408
|
const selection = isString(values.groups) ? { groups: values.groups } : {};
|
|
@@ -398,6 +418,10 @@ function argvToCommand(argv) {
|
|
|
398
418
|
...src === void 0 ? {} : { src },
|
|
399
419
|
...app === void 0 ? {} : { app },
|
|
400
420
|
...bin ? { bin } : {},
|
|
421
|
+
...values.styles === true ? { styles: true } : {},
|
|
422
|
+
...values.themes === true ? { themes: true } : {},
|
|
423
|
+
...values.showcase === true ? { showcase: true } : {},
|
|
424
|
+
...extension === void 0 ? {} : { extensions: extension },
|
|
401
425
|
...offline ? { offline } : {},
|
|
402
426
|
...dependencies === void 0 ? {} : { dependencies }
|
|
403
427
|
};
|
|
@@ -888,6 +912,7 @@ function releasesToPins(releases, declared) {
|
|
|
888
912
|
* Reads the literal Vitest projects, configuration paths, and npm run scripts a shell command names.
|
|
889
913
|
*
|
|
890
914
|
* @param script - The manifest script text to read.
|
|
915
|
+
* @param wrappers - Planned wrapper paths mapped to the face projects they run.
|
|
891
916
|
* @returns The named projects, configurations, and scripts, or `undefined` when the command
|
|
892
917
|
* cannot be read literally.
|
|
893
918
|
*
|
|
@@ -906,7 +931,7 @@ function releasesToPins(releases, declared) {
|
|
|
906
931
|
* // { projects: ['src:core'], configs: [], scripts: [] }
|
|
907
932
|
* ```
|
|
908
933
|
*/
|
|
909
|
-
function scriptToInvocations(script) {
|
|
934
|
+
function scriptToInvocations(script, wrappers = /* @__PURE__ */ new Map()) {
|
|
910
935
|
const tokens = [];
|
|
911
936
|
let value = "";
|
|
912
937
|
let resolved = true;
|
|
@@ -983,9 +1008,19 @@ function scriptToInvocations(script) {
|
|
|
983
1008
|
const projects = [];
|
|
984
1009
|
const configs = [];
|
|
985
1010
|
const scripts = [];
|
|
1011
|
+
const configurations = new Map([...wrappers].map(([path, project]) => [normalize(path), project]));
|
|
1012
|
+
let testing = false;
|
|
986
1013
|
for (let index = 0; index < tokens.length; index += 1) {
|
|
987
1014
|
const token = tokens[index];
|
|
988
1015
|
if (token === void 0) return void 0;
|
|
1016
|
+
if (index === 0 || [
|
|
1017
|
+
"&&",
|
|
1018
|
+
"||",
|
|
1019
|
+
";",
|
|
1020
|
+
"|",
|
|
1021
|
+
"&",
|
|
1022
|
+
"("
|
|
1023
|
+
].includes(tokens[index - 1]?.value ?? "")) testing = token.resolved && token.value === "vitest" && tokens[index + 1]?.value === "run";
|
|
989
1024
|
if (token.value === "npm" && tokens[index + 1]?.value === "run") {
|
|
990
1025
|
const name = tokens[index + 2];
|
|
991
1026
|
if (name === void 0 || !name.resolved || name.value.length === 0 || [
|
|
@@ -1012,14 +1047,20 @@ function scriptToInvocations(script) {
|
|
|
1012
1047
|
"(",
|
|
1013
1048
|
")"
|
|
1014
1049
|
].includes(project.value)) return void 0;
|
|
1015
|
-
|
|
1050
|
+
const names = token.value === "--project" ? projects : configs;
|
|
1051
|
+
names.push(project.value);
|
|
1052
|
+
const face = testing && names === configs ? configurations.get(normalize(project.value)) : void 0;
|
|
1053
|
+
if (face !== void 0) projects.push(face);
|
|
1016
1054
|
index += 1;
|
|
1017
1055
|
continue;
|
|
1018
1056
|
}
|
|
1019
1057
|
if (token.value.startsWith("--project=") || token.value.startsWith("--config=")) {
|
|
1020
1058
|
const project = token.value.slice(token.value.indexOf("=") + 1);
|
|
1021
1059
|
if (!token.resolved || project.length === 0) return void 0;
|
|
1022
|
-
|
|
1060
|
+
const names = token.value.startsWith("--project=") ? projects : configs;
|
|
1061
|
+
names.push(project);
|
|
1062
|
+
const face = testing && names === configs ? configurations.get(normalize(project)) : void 0;
|
|
1063
|
+
if (face !== void 0) projects.push(face);
|
|
1023
1064
|
continue;
|
|
1024
1065
|
}
|
|
1025
1066
|
if (!token.resolved && /--project|--config/.test(token.value)) return void 0;
|
|
@@ -1055,6 +1096,96 @@ function targetToEnvironments(target, axis) {
|
|
|
1055
1096
|
});
|
|
1056
1097
|
}
|
|
1057
1098
|
/**
|
|
1099
|
+
* Reads the styles, themes, and showcase markers a target physically holds.
|
|
1100
|
+
* @param target - The target directory.
|
|
1101
|
+
* @returns The independent structural facts, false when their markers are absent.
|
|
1102
|
+
*/
|
|
1103
|
+
function targetToFacts(target) {
|
|
1104
|
+
const styles = resolveContainedPath(target, STYLES_ENTRY_PATH);
|
|
1105
|
+
const themes = resolveContainedPath(target, THEMES_ENTRY_PATH);
|
|
1106
|
+
const barrel = resolveContainedPath(target, THEMES_BARREL_PATH);
|
|
1107
|
+
const wrapper = resolveContainedPath(target, SHOWCASE_CONFIG_PATH);
|
|
1108
|
+
const pages = resolveContainedPath(target, SHOWCASE_PAGES_PATH);
|
|
1109
|
+
return {
|
|
1110
|
+
styles: styles !== void 0 && isExactCaseFile(styles),
|
|
1111
|
+
themes: themes !== void 0 && isExactCaseFile(themes) && barrel !== void 0 && isExactCaseFile(barrel),
|
|
1112
|
+
showcase: wrapper !== void 0 && isExactCaseFile(wrapper) || pages !== void 0 && isPhysicalDirectory(pages)
|
|
1113
|
+
};
|
|
1114
|
+
}
|
|
1115
|
+
/**
|
|
1116
|
+
* Reads browser faces and named sheet marker pairs from a target.
|
|
1117
|
+
* @param target - The target directory.
|
|
1118
|
+
* @returns Browser extensions in framework order followed by sheets in code-unit order.
|
|
1119
|
+
* @throws `ScaffoldError` when sheet markers name an invalid or case-colliding face, or the directory cannot be read.
|
|
1120
|
+
*/
|
|
1121
|
+
function targetToExtensions(target) {
|
|
1122
|
+
const extensions = [];
|
|
1123
|
+
for (const name of FRAMEWORKS) {
|
|
1124
|
+
const axes = AXES.filter((axis) => {
|
|
1125
|
+
const path = resolveContainedPath(target, `${axis}/${name}`);
|
|
1126
|
+
return path !== void 0 && isPhysicalDirectory(path);
|
|
1127
|
+
});
|
|
1128
|
+
if (axes.length > 0) extensions.push({
|
|
1129
|
+
surface: "browser",
|
|
1130
|
+
name,
|
|
1131
|
+
axes
|
|
1132
|
+
});
|
|
1133
|
+
}
|
|
1134
|
+
const source = resolveContainedPath(target, "src");
|
|
1135
|
+
if (source === void 0 || !isPhysicalDirectory(source)) return extensions;
|
|
1136
|
+
const entries = readdirSync(source, { withFileTypes: true });
|
|
1137
|
+
if (entries.length > MAX_INVENTORY_PATHS) throw new ScaffoldError("TARGET", "The source directory exceeds the inventory limit.");
|
|
1138
|
+
const names = [];
|
|
1139
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1140
|
+
for (const entry of entries) {
|
|
1141
|
+
if (!entry.isDirectory() || RESERVED_SHEET_NAMES.includes(entry.name)) continue;
|
|
1142
|
+
const sheet = resolveContainedPath(target, `src/${entry.name}/index.scss`);
|
|
1143
|
+
const marker = resolveContainedPath(target, `src/${entry.name}/${SHEET_ENTRY_NAME}`);
|
|
1144
|
+
if (sheet === void 0 || marker === void 0 || !isExactCaseFile(sheet) || !isExactCaseFile(marker)) continue;
|
|
1145
|
+
const folded = entry.name.toLowerCase();
|
|
1146
|
+
if (seen.has(folded)) throw new ScaffoldError("TARGET", `Case-colliding sheet face '${entry.name}'.`);
|
|
1147
|
+
seen.add(folded);
|
|
1148
|
+
names.push(entry.name);
|
|
1149
|
+
}
|
|
1150
|
+
for (const name of names.sort()) {
|
|
1151
|
+
if (!isSheetName(name)) throw new ScaffoldError("TARGET", `Invalid sheet face '${name}'.`);
|
|
1152
|
+
extensions.push({
|
|
1153
|
+
surface: "styles",
|
|
1154
|
+
name
|
|
1155
|
+
});
|
|
1156
|
+
}
|
|
1157
|
+
return extensions;
|
|
1158
|
+
}
|
|
1159
|
+
/**
|
|
1160
|
+
* Reads a creation extension list and assigns its selected browser axes.
|
|
1161
|
+
* @param selection - The comma-separated `surface:name` entries, or no selection.
|
|
1162
|
+
* @param axes - The axes selecting a browser environment.
|
|
1163
|
+
* @param styles - If `true`, admits stylesheet extensions; if `false`, refuses them.
|
|
1164
|
+
* @returns The validated extensions in selection order.
|
|
1165
|
+
* @throws `UsageError` when an entry is malformed, repeated, unsupported, or lacks its surface.
|
|
1166
|
+
*/
|
|
1167
|
+
function selectionToExtensions(selection, axes, styles) {
|
|
1168
|
+
if (selection === void 0) return [];
|
|
1169
|
+
const extensions = [];
|
|
1170
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1171
|
+
for (const entry of selection.split(",")) {
|
|
1172
|
+
const extension = parseExtension(entry);
|
|
1173
|
+
if (extension === void 0 || seen.has(entry)) throw new UsageError(`'--extend' refuses '${entry}': use distinct supported surface:name entries.`);
|
|
1174
|
+
seen.add(entry);
|
|
1175
|
+
if (extension.surface === "browser") {
|
|
1176
|
+
if (axes.length === 0) throw new UsageError("A browser extension requires browser in --src or --app.");
|
|
1177
|
+
extensions.push({
|
|
1178
|
+
...extension,
|
|
1179
|
+
axes
|
|
1180
|
+
});
|
|
1181
|
+
} else {
|
|
1182
|
+
if (!styles) throw new UsageError("A styles extension requires --styles.");
|
|
1183
|
+
extensions.push(extension);
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
return extensions;
|
|
1187
|
+
}
|
|
1188
|
+
/**
|
|
1058
1189
|
* Reads the packages a target's catalog table listed before this run.
|
|
1059
1190
|
*
|
|
1060
1191
|
* @param target - The target or raw checkout directory, or a verified value host.
|
|
@@ -1396,9 +1527,17 @@ var CLI = class {
|
|
|
1396
1527
|
async #create(command) {
|
|
1397
1528
|
const target = command.target ?? command.name;
|
|
1398
1529
|
const app = selectionToEnvironments(command.app, "app");
|
|
1530
|
+
const src = selectionToEnvironments(command.src, "src");
|
|
1531
|
+
if (command.themes === true && command.styles !== true) throw new UsageError("--themes requires --styles.");
|
|
1532
|
+
if (command.showcase === true && !app.includes("browser")) throw new UsageError("--showcase requires --app browser.");
|
|
1533
|
+
const axes = AXES.filter((axis) => (axis === "src" ? src : app).includes("browser"));
|
|
1399
1534
|
const blueprint = createBlueprint(command.name, {
|
|
1400
|
-
src
|
|
1535
|
+
src,
|
|
1401
1536
|
app,
|
|
1537
|
+
extensions: selectionToExtensions(command.extensions, axes, command.styles === true),
|
|
1538
|
+
styles: command.styles === true,
|
|
1539
|
+
themes: command.themes === true,
|
|
1540
|
+
showcase: command.showcase === true,
|
|
1402
1541
|
journey: app.includes("browser"),
|
|
1403
1542
|
bin: command.bin === true,
|
|
1404
1543
|
setup: [],
|
|
@@ -1900,16 +2039,17 @@ var CLI = class {
|
|
|
1900
2039
|
const conformance = resolveContainedPath(target, CONFORMANCE_TEST_PATH);
|
|
1901
2040
|
const service = resolveContainedPath(target, SERVICE_SETUP_PATH);
|
|
1902
2041
|
const global = resolveContainedPath(target, GLOBAL_SETUP_PATH);
|
|
1903
|
-
const showcase = resolveContainedPath(target, SHOWCASE_CONFIG_PATH);
|
|
1904
2042
|
const journey = resolveContainedPath(target, JOURNEY_CONFIG_PATH);
|
|
1905
2043
|
const skills = resolveContainedPath(target, SKILLS_CONFIG_PATH);
|
|
1906
2044
|
const setup = /* @__PURE__ */ new Set();
|
|
1907
2045
|
if (tests !== void 0) for (const path of listFiles(tests)) {
|
|
1908
2046
|
if (path.includes("/") || !path.startsWith("setup") || !path.endsWith(".test.ts")) continue;
|
|
1909
2047
|
const proof = resolveContainedPath(tests, path);
|
|
1910
|
-
if (proof !== void 0 && isExactCaseFile(proof)) setup.add(path === "setupBrowser.test.ts" ? "browser" : "node");
|
|
2048
|
+
if (proof !== void 0 && isExactCaseFile(proof)) setup.add(path === "setupBrowser.test.ts" || path === "setupStyles.test.ts" ? "browser" : "node");
|
|
1911
2049
|
}
|
|
1912
2050
|
return createBlueprint(declared.slice(declared.lastIndexOf("/") + 1), {
|
|
2051
|
+
...targetToFacts(target),
|
|
2052
|
+
extensions: targetToExtensions(target),
|
|
1913
2053
|
src: targetToEnvironments(target, "src"),
|
|
1914
2054
|
app: targetToEnvironments(target, "app"),
|
|
1915
2055
|
dependencies: manifestToDependencies(manifest).runtime,
|
|
@@ -1920,7 +2060,6 @@ var CLI = class {
|
|
|
1920
2060
|
conformance: conformance !== void 0 && isExactCaseFile(conformance),
|
|
1921
2061
|
service: service !== void 0 && isExactCaseFile(service),
|
|
1922
2062
|
global: global !== void 0 && isExactCaseFile(global),
|
|
1923
|
-
showcase: showcase !== void 0 && isExactCaseFile(showcase),
|
|
1924
2063
|
journey: journey !== void 0 && isExactCaseFile(journey),
|
|
1925
2064
|
skills: skills !== void 0 && isExactCaseFile(skills)
|
|
1926
2065
|
});
|
|
@@ -1929,7 +2068,7 @@ var CLI = class {
|
|
|
1929
2068
|
const text = this.#manifest(target);
|
|
1930
2069
|
const writable = writing ? manifestToWritableScripts(text, blueprint) : blueprintToWritableScripts(blueprint);
|
|
1931
2070
|
const manifest = replaceManifestScripts(text, writable) ?? text;
|
|
1932
|
-
const planned =
|
|
2071
|
+
const planned = new Set(blueprintToProjects(blueprint));
|
|
1933
2072
|
const parsed = parseJSON(manifest);
|
|
1934
2073
|
const scripts = isRecord(parsed) && isRecord(parsed.scripts) ? parsed.scripts : {};
|
|
1935
2074
|
const gates = !isRecord(parsed) || parsed.private !== true ? ["test", "prepublishOnly"] : ["test"];
|
|
@@ -1943,7 +2082,7 @@ var CLI = class {
|
|
|
1943
2082
|
unresolved = true;
|
|
1944
2083
|
continue;
|
|
1945
2084
|
}
|
|
1946
|
-
for (const project of invoked.projects) if (!planned.
|
|
2085
|
+
for (const project of invoked.projects) if (!planned.has(project)) absent.add(project);
|
|
1947
2086
|
}
|
|
1948
2087
|
const projects = [...absent].sort();
|
|
1949
2088
|
if (unresolved) return {
|
|
@@ -1991,6 +2130,14 @@ var CLI = class {
|
|
|
1991
2130
|
if (command !== void 0) expectedLines.set(project, `"${direct}": ${JSON.stringify(command)},`);
|
|
1992
2131
|
}
|
|
1993
2132
|
}
|
|
2133
|
+
const faces = /* @__PURE__ */ new Set([...blueprintToSheets(blueprint).map((name) => `src:${name}`), ...blueprintToFaces(blueprint).flatMap(({ name, axes }) => axes.map((axis) => `${axis}:${name}`))]);
|
|
2134
|
+
const wrappers = /* @__PURE__ */ new Map();
|
|
2135
|
+
for (const artifact of blueprintToConfigArtifacts(blueprint)) {
|
|
2136
|
+
const match = /^configs\/(src|app)\/vite\.([^.]+)\.config\.ts$/u.exec(artifact.path);
|
|
2137
|
+
if (match === null) continue;
|
|
2138
|
+
const project = `${match[1]}:${match[2]}`;
|
|
2139
|
+
if (faces.has(project)) wrappers.set(artifact.path, project);
|
|
2140
|
+
}
|
|
1994
2141
|
const reachable = /* @__PURE__ */ new Set();
|
|
1995
2142
|
const chains = /* @__PURE__ */ new Map();
|
|
1996
2143
|
for (const gate of gates) {
|
|
@@ -2003,7 +2150,7 @@ var CLI = class {
|
|
|
2003
2150
|
visited.add(name);
|
|
2004
2151
|
const script = scripts[name];
|
|
2005
2152
|
if (!isString(script)) continue;
|
|
2006
|
-
const invoked = scriptToInvocations(script);
|
|
2153
|
+
const invoked = scriptToInvocations(script, wrappers);
|
|
2007
2154
|
if (invoked === void 0) {
|
|
2008
2155
|
unresolved = true;
|
|
2009
2156
|
continue;
|
|
@@ -2102,7 +2249,7 @@ var CLI = class {
|
|
|
2102
2249
|
if (proofs.has(`${path.slice(0, -3)}.test.ts`)) return false;
|
|
2103
2250
|
if (resolveContainedPath(tests, path) === void 0) return false;
|
|
2104
2251
|
const content = (readFileText(tests, path) ?? "").trim();
|
|
2105
|
-
return content
|
|
2252
|
+
return /^export /m.test(content) && content !== (seeds.get(`tests/${path}`) ?? "");
|
|
2106
2253
|
}).sort();
|
|
2107
2254
|
if (modules.length === 0) return void 0;
|
|
2108
2255
|
const single = modules.length === 1;
|
|
@@ -2118,6 +2265,13 @@ var CLI = class {
|
|
|
2118
2265
|
}
|
|
2119
2266
|
#targetQuestions(target, blueprint, groups, writing = false) {
|
|
2120
2267
|
const questions = [];
|
|
2268
|
+
const browser = resolveContainedPath(target, "app/browser");
|
|
2269
|
+
if (browser !== void 0 && listFiles(browser).some((path) => path.endsWith(".vue"))) questions.push({
|
|
2270
|
+
field: "extensions",
|
|
2271
|
+
message: "Move Vue components from app/browser to app/vue before regenerating this workspace.",
|
|
2272
|
+
blocking: writing,
|
|
2273
|
+
groups: []
|
|
2274
|
+
});
|
|
2121
2275
|
if (!writing) {
|
|
2122
2276
|
const script = this.#scriptQuestion(target, blueprint);
|
|
2123
2277
|
if (script !== void 0) questions.push(script);
|
|
@@ -2130,7 +2284,7 @@ var CLI = class {
|
|
|
2130
2284
|
const setup = this.#setupQuestion(target, blueprint);
|
|
2131
2285
|
if (setup !== void 0) questions.push(setup);
|
|
2132
2286
|
}
|
|
2133
|
-
return questions.filter((question) => groups === void 0 || question.groups.some((group) => groups.includes(group))).map(({ field, message, blocking, candidates }) => ({
|
|
2287
|
+
return questions.filter((question) => question.blocking || groups === void 0 || question.groups.some((group) => groups.includes(group))).map(({ field, message, blocking, candidates }) => ({
|
|
2134
2288
|
field,
|
|
2135
2289
|
message,
|
|
2136
2290
|
blocking,
|