@orkestrel/scaffold 0.0.73 → 0.0.74
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 +75 -34
- package/dist/bin/main.js.map +1 -1
- package/dist/host/agents/skills/orkestrel-prove-journey/SKILL.md +175 -29
- package/dist/host/agents/skills/orkestrel-prove-journey/references/captures.md +42 -15
- package/dist/host/agents/skills/orkestrel-prove-journey/references/decide.md +34 -15
- package/dist/host/agents/skills/orkestrel-prove-journey/references/layer.md +248 -52
- package/dist/host/agents/skills/orkestrel-prove-journey/references/statechart.md +255 -49
- package/dist/host/agents/skills/orkestrel-prove-journey/references/styles.md +111 -23
- package/dist/host/agents/transports/codex.md +7 -0
- package/dist/host/claude/agents/orkestrel.md +2 -2
- package/dist/host/claude/rules/documentation.md +2 -0
- package/dist/host/claude/rules/tests.md +5 -3
- package/dist/host/claude/rules/workspace.md +26 -15
- package/dist/host/guides/README.md +5 -0
- package/dist/host/guides/scaffold.md +97 -13
- package/dist/host/guides/test.md +744 -184
- package/dist/host/manifest.json +18 -18
- package/dist/host/tests/config.test.ts +159 -64
- package/dist/host/tests/policy.test.ts +11 -1
- package/dist/host/tests/setupPolicy.ts +571 -7
- package/dist/src/core/index.cjs +109 -18
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +19 -6
- package/dist/src/core/index.d.ts +19 -6
- package/dist/src/core/index.js +109 -19
- package/dist/src/core/index.js.map +1 -1
- package/package.json +2 -2
package/dist/bin/main.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
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, MAX_MANIFEST_BYTES, MAX_PATH_LENGTH, SERVICE_SETUP_PATH, SHOWCASE_CONFIG_PATH, ScaffoldError, blueprintToDevDependencies, blueprintToRootVite, blueprintToScripts, blueprintToTestArtifacts, blueprintToWritableScripts, compareVersions, createBlueprint, extractRangeMajor, extractVersion, isFloorPath, isScaffoldError, manifestToDependencies, manifestToName, nameToGuide, replaceManifestScripts, replacePlanRanges } from "../src/core/index.js";
|
|
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, ScaffoldError, blueprintToConfigArtifacts, blueprintToDevDependencies, blueprintToRootVite, blueprintToScripts, blueprintToTestArtifacts, blueprintToWritableScripts, compareVersions, createBlueprint, extractRangeMajor, extractVersion, isFloorPath, isScaffoldError, manifestToDependencies, manifestToName, nameToGuide, 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";
|
|
@@ -836,16 +836,17 @@ function releasesToPins(releases, declared) {
|
|
|
836
836
|
};
|
|
837
837
|
}
|
|
838
838
|
/**
|
|
839
|
-
* Reads the literal Vitest projects and npm run scripts
|
|
839
|
+
* Reads the literal Vitest projects, configuration paths, and npm run scripts a shell command names.
|
|
840
840
|
*
|
|
841
841
|
* @param script - The manifest script text to read.
|
|
842
|
-
* @returns The
|
|
842
|
+
* @returns The named projects, configurations, and scripts, or `undefined` when the command
|
|
843
843
|
* cannot be read literally.
|
|
844
844
|
*
|
|
845
845
|
* @remarks
|
|
846
846
|
* Quotes group a token but do not hide the option, while shell expansions make
|
|
847
847
|
* its value unresolved and therefore refuse the write that asked the question.
|
|
848
|
-
*
|
|
848
|
+
* Configuration paths use `-c <path>`, `--config <path>`, or `--config=<path>`.
|
|
849
|
+
* An unterminated quote, a trailing escape, and an unresolved `--project`, `--config`, or `-c` value
|
|
849
850
|
* all answer `undefined` rather than a partial reading.
|
|
850
851
|
*
|
|
851
852
|
* @example
|
|
@@ -853,7 +854,7 @@ function releasesToPins(releases, declared) {
|
|
|
853
854
|
* import { scriptToInvocations } from './helpers.js'
|
|
854
855
|
*
|
|
855
856
|
* scriptToInvocations('vitest run --project src:core')
|
|
856
|
-
* // { projects: ['src:core'], scripts: [] }
|
|
857
|
+
* // { projects: ['src:core'], configs: [], scripts: [] }
|
|
857
858
|
* ```
|
|
858
859
|
*/
|
|
859
860
|
function scriptToInvocations(script) {
|
|
@@ -931,6 +932,7 @@ function scriptToInvocations(script) {
|
|
|
931
932
|
resolved
|
|
932
933
|
});
|
|
933
934
|
const projects = [];
|
|
935
|
+
const configs = [];
|
|
934
936
|
const scripts = [];
|
|
935
937
|
for (let index = 0; index < tokens.length; index += 1) {
|
|
936
938
|
const token = tokens[index];
|
|
@@ -950,7 +952,7 @@ function scriptToInvocations(script) {
|
|
|
950
952
|
index += 2;
|
|
951
953
|
continue;
|
|
952
954
|
}
|
|
953
|
-
if (token.value === "--project") {
|
|
955
|
+
if (token.value === "--project" || token.value === "--config" || token.value === "-c") {
|
|
954
956
|
const project = tokens[index + 1];
|
|
955
957
|
if (project === void 0 || !project.resolved || project.value.length === 0 || [
|
|
956
958
|
"&&",
|
|
@@ -961,20 +963,21 @@ function scriptToInvocations(script) {
|
|
|
961
963
|
"(",
|
|
962
964
|
")"
|
|
963
965
|
].includes(project.value)) return void 0;
|
|
964
|
-
projects.push(project.value);
|
|
966
|
+
(token.value === "--project" ? projects : configs).push(project.value);
|
|
965
967
|
index += 1;
|
|
966
968
|
continue;
|
|
967
969
|
}
|
|
968
|
-
if (token.value.startsWith("--project=")) {
|
|
969
|
-
const project = token.value.slice(
|
|
970
|
+
if (token.value.startsWith("--project=") || token.value.startsWith("--config=")) {
|
|
971
|
+
const project = token.value.slice(token.value.indexOf("=") + 1);
|
|
970
972
|
if (!token.resolved || project.length === 0) return void 0;
|
|
971
|
-
projects.push(project);
|
|
973
|
+
(token.value.startsWith("--project=") ? projects : configs).push(project);
|
|
972
974
|
continue;
|
|
973
975
|
}
|
|
974
|
-
if (!token.resolved && token.value
|
|
976
|
+
if (!token.resolved && /--project|--config/.test(token.value)) return void 0;
|
|
975
977
|
}
|
|
976
978
|
return {
|
|
977
979
|
projects,
|
|
980
|
+
configs,
|
|
978
981
|
scripts
|
|
979
982
|
};
|
|
980
983
|
}
|
|
@@ -1343,11 +1346,13 @@ var CLI = class {
|
|
|
1343
1346
|
}
|
|
1344
1347
|
async #create(command) {
|
|
1345
1348
|
const target = command.target ?? command.name;
|
|
1349
|
+
const app = selectionToEnvironments(command.app, "app");
|
|
1346
1350
|
const blueprint = createBlueprint(command.name, {
|
|
1347
1351
|
src: selectionToEnvironments(command.src, "src"),
|
|
1348
|
-
app
|
|
1352
|
+
app,
|
|
1353
|
+
journey: app.includes("browser"),
|
|
1349
1354
|
bin: command.bin === true,
|
|
1350
|
-
setup:
|
|
1355
|
+
setup: [],
|
|
1351
1356
|
dependencies: selectionToPackages(command.dependencies).map((name) => ({
|
|
1352
1357
|
name,
|
|
1353
1358
|
range: "^0.0.0"
|
|
@@ -1847,22 +1852,26 @@ var CLI = class {
|
|
|
1847
1852
|
const service = resolveContainedPath(target, SERVICE_SETUP_PATH);
|
|
1848
1853
|
const global = resolveContainedPath(target, GLOBAL_SETUP_PATH);
|
|
1849
1854
|
const showcase = resolveContainedPath(target, SHOWCASE_CONFIG_PATH);
|
|
1855
|
+
const journey = resolveContainedPath(target, JOURNEY_CONFIG_PATH);
|
|
1856
|
+
const setup = /* @__PURE__ */ new Set();
|
|
1857
|
+
if (tests !== void 0) for (const path of listFiles(tests)) {
|
|
1858
|
+
if (path.includes("/") || !path.startsWith("setup") || !path.endsWith(".test.ts")) continue;
|
|
1859
|
+
const proof = resolveContainedPath(tests, path);
|
|
1860
|
+
if (proof !== void 0 && isExactCaseFile(proof)) setup.add(path === "setupBrowser.test.ts" ? "browser" : "node");
|
|
1861
|
+
}
|
|
1850
1862
|
return createBlueprint(declared.slice(declared.lastIndexOf("/") + 1), {
|
|
1851
1863
|
src: targetToEnvironments(target, "src"),
|
|
1852
1864
|
app: targetToEnvironments(target, "app"),
|
|
1853
1865
|
dependencies: manifestToDependencies(manifest).runtime,
|
|
1854
1866
|
bin: bin !== void 0 && isExactCaseFile(bin),
|
|
1855
|
-
setup:
|
|
1856
|
-
if (path.includes("/") || !path.startsWith("setup") || !path.endsWith(".test.ts")) return false;
|
|
1857
|
-
const proof = resolveContainedPath(tests, path);
|
|
1858
|
-
return proof !== void 0 && isExactCaseFile(proof);
|
|
1859
|
-
}),
|
|
1867
|
+
setup: [...setup],
|
|
1860
1868
|
guides: guides !== void 0 && isExactCaseFile(guides),
|
|
1861
1869
|
integration: integration !== void 0 && isExactCaseFile(integration),
|
|
1862
1870
|
conformance: conformance !== void 0 && isExactCaseFile(conformance),
|
|
1863
1871
|
service: service !== void 0 && isExactCaseFile(service),
|
|
1864
1872
|
global: global !== void 0 && isExactCaseFile(global),
|
|
1865
|
-
showcase: showcase !== void 0 && isExactCaseFile(showcase)
|
|
1873
|
+
showcase: showcase !== void 0 && isExactCaseFile(showcase),
|
|
1874
|
+
journey: journey !== void 0 && isExactCaseFile(journey)
|
|
1866
1875
|
});
|
|
1867
1876
|
}
|
|
1868
1877
|
#projectQuestion(target, blueprint, writing = false) {
|
|
@@ -1897,6 +1906,26 @@ var CLI = class {
|
|
|
1897
1906
|
blocking: false,
|
|
1898
1907
|
groups: ["configs"]
|
|
1899
1908
|
};
|
|
1909
|
+
if (!writing) {
|
|
1910
|
+
const paths = new Set(blueprintToConfigArtifacts(blueprint).map((artifact) => resolveContainedPath(target, artifact.path)));
|
|
1911
|
+
const configurations = [];
|
|
1912
|
+
for (const [name, script] of Object.entries(scripts)) {
|
|
1913
|
+
if (!name.startsWith("test:") || !isString(script) || !script.includes("vitest")) continue;
|
|
1914
|
+
const invoked = scriptToInvocations(script);
|
|
1915
|
+
if (invoked === void 0) continue;
|
|
1916
|
+
for (const config of invoked.configs) {
|
|
1917
|
+
const path = resolveContainedPath(target, config);
|
|
1918
|
+
if (path !== void 0 && (paths.has(path) || isExactCaseFile(path))) continue;
|
|
1919
|
+
configurations.push(`${name} --config ${config}`);
|
|
1920
|
+
}
|
|
1921
|
+
}
|
|
1922
|
+
if (configurations.length > 0) return {
|
|
1923
|
+
field: "projects",
|
|
1924
|
+
message: `The manifest at ${target} names a Vitest configuration the plan does not emit and the target does not hold: ${configurations.join(", ")}. Add the configuration, or remove the script that names it and its invocation from the test chain.`,
|
|
1925
|
+
blocking: false,
|
|
1926
|
+
groups: ["configs"]
|
|
1927
|
+
};
|
|
1928
|
+
}
|
|
1900
1929
|
const expected = blueprintToScripts(blueprint);
|
|
1901
1930
|
const expectedLines = /* @__PURE__ */ new Map();
|
|
1902
1931
|
for (const [name, script] of Object.entries(expected)) {
|
|
@@ -1911,21 +1940,25 @@ var CLI = class {
|
|
|
1911
1940
|
}
|
|
1912
1941
|
}
|
|
1913
1942
|
const reachable = /* @__PURE__ */ new Set();
|
|
1914
|
-
const
|
|
1915
|
-
const
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1943
|
+
const chains = /* @__PURE__ */ new Map();
|
|
1944
|
+
for (const gate of gates) {
|
|
1945
|
+
const visited = /* @__PURE__ */ new Set();
|
|
1946
|
+
chains.set(gate, visited);
|
|
1947
|
+
const pending = [gate];
|
|
1948
|
+
while (pending.length > 0) {
|
|
1949
|
+
const name = pending.shift();
|
|
1950
|
+
if (name === void 0 || visited.has(name)) continue;
|
|
1951
|
+
visited.add(name);
|
|
1952
|
+
const script = scripts[name];
|
|
1953
|
+
if (!isString(script)) continue;
|
|
1954
|
+
const invoked = scriptToInvocations(script);
|
|
1955
|
+
if (invoked === void 0) {
|
|
1956
|
+
unresolved = true;
|
|
1957
|
+
continue;
|
|
1958
|
+
}
|
|
1959
|
+
for (const project of invoked.projects) reachable.add(project);
|
|
1960
|
+
for (const called of invoked.scripts) if (!visited.has(called)) pending.push(called);
|
|
1926
1961
|
}
|
|
1927
|
-
for (const project of invoked.projects) reachable.add(project);
|
|
1928
|
-
for (const called of invoked.scripts) if (!visited.has(called)) pending.push(called);
|
|
1929
1962
|
}
|
|
1930
1963
|
if (unresolved) return {
|
|
1931
1964
|
field: "projects",
|
|
@@ -1934,7 +1967,15 @@ var CLI = class {
|
|
|
1934
1967
|
groups: ["configs"]
|
|
1935
1968
|
};
|
|
1936
1969
|
const ungated = [...expectedLines].filter(([project]) => !reachable.has(project)).sort(([left], [right]) => left.localeCompare(right)).filter(([project]) => isString(scripts[`test:${project}`]));
|
|
1937
|
-
if (ungated.length === 0)
|
|
1970
|
+
if (ungated.length === 0) {
|
|
1971
|
+
if (!writing && expected["test:journey"] !== void 0 && !chains.get("test")?.has("test:journey")) return {
|
|
1972
|
+
field: "projects",
|
|
1973
|
+
message: `The manifest at ${target} does not invoke npm run test:journey from its test chain. Add npm run test:journey after npm run test:app.`,
|
|
1974
|
+
blocking: false,
|
|
1975
|
+
groups: ["configs"]
|
|
1976
|
+
};
|
|
1977
|
+
return;
|
|
1978
|
+
}
|
|
1938
1979
|
const names = ungated.map(([project]) => project);
|
|
1939
1980
|
const disk = parseJSON(text);
|
|
1940
1981
|
const written = isRecord(disk) && isRecord(disk.scripts) ? disk.scripts : {};
|