@orkestrel/scaffold 0.0.21 → 0.0.22
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/scaffold.js +371 -140
- package/dist/bin/scaffold.js.map +1 -1
- package/dist/host/AGENTS.md +61 -42
- package/dist/host/CLAUDE.md +39 -408
- package/dist/host/agents/orchestration.md +454 -0
- package/dist/host/agents/skills/enterprise-bootstrap/SKILL.md +25 -7
- package/dist/host/agents/skills/orkestrel-align-packages/SKILL.md +2 -2
- package/dist/host/agents/skills/orkestrel-build-application/SKILL.md +42 -31
- package/dist/host/agents/skills/orkestrel-build-application/references/application.md +129 -0
- package/dist/host/agents/skills/orkestrel-debrief/SKILL.md +3 -3
- package/dist/host/agents/skills/orkestrel-debrief/references/field-testing.md +2 -2
- package/dist/host/agents/skills/orkestrel-falsify/SKILL.md +167 -0
- package/dist/host/agents/skills/orkestrel-falsify/references/brief.md +98 -0
- package/dist/host/agents/skills/orkestrel-falsify/references/reconcile.md +148 -0
- package/dist/host/agents/skills/orkestrel-harden-package/SKILL.md +4 -2
- package/dist/host/agents/skills/orkestrel-harden-package/references/centralization.md +5 -5
- package/dist/host/agents/skills/orkestrel-harden-package/references/research.md +2 -0
- package/dist/host/agents/skills/orkestrel-polish-surface/SKILL.md +11 -6
- package/dist/host/claude/agents/analyst.md +59 -0
- package/dist/host/claude/agents/application.md +1 -1
- package/dist/host/claude/agents/builder.md +1 -1
- package/dist/host/claude/agents/checker.md +5 -1
- package/dist/host/claude/agents/codex.md +120 -94
- package/dist/host/claude/agents/grok.md +44 -32
- package/dist/host/claude/agents/implementer.md +1 -1
- package/dist/host/claude/agents/orkestrel.md +1 -1
- package/dist/host/claude/agents/planner.md +9 -3
- package/dist/host/claude/agents/researcher.md +6 -5
- package/dist/host/claude/agents/reviewer.md +12 -6
- package/dist/host/claude/agents/scout.md +7 -4
- package/dist/host/claude/agents/verifier.md +1 -1
- package/dist/host/claude/rules/application.md +17 -16
- package/dist/host/claude/rules/architecture.md +41 -22
- package/dist/host/claude/rules/documentation.md +2 -1
- package/dist/host/claude/rules/names.md +7 -6
- package/dist/host/claude/rules/quality.md +65 -18
- package/dist/host/claude/rules/styles.md +1 -1
- package/dist/host/claude/rules/tests.md +12 -6
- package/dist/host/claude/rules/typescript.md +1 -1
- package/dist/host/claude/rules/workspace.md +6 -3
- package/dist/host/claude/settings.json +2 -0
- package/dist/host/claude/skills/orkestrel-falsify/SKILL.md +10 -0
- package/dist/host/codex/agents/analyst.toml +13 -4
- package/dist/host/codex/agents/checker.toml +1 -1
- package/dist/host/codex/agents/grok.toml +2 -1
- package/dist/host/codex/agents/opus.toml +1 -1
- package/dist/host/codex/agents/planner.toml +1 -1
- package/dist/host/codex/agents/researcher.toml +2 -2
- package/dist/host/codex/agents/reviewer.toml +1 -1
- package/dist/host/codex/agents/scout.toml +2 -2
- package/dist/host/codex/config.toml +23 -70
- package/dist/host/cursor/rules/orchestration.mdc +33 -0
- package/dist/host/guides/src/scaffold.md +301 -123
- package/dist/host/manifest.json +47 -1
- package/dist/host/tests/setupPolicy.ts +83 -3
- package/dist/src/core/index.cjs +404 -63
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +119 -41
- package/dist/src/core/index.d.ts +119 -41
- package/dist/src/core/index.js +401 -64
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +83 -33
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.d.cts +32 -16
- package/dist/src/server/index.d.ts +32 -16
- package/dist/src/server/index.js +84 -35
- package/dist/src/server/index.js.map +1 -1
- package/package.json +4 -4
package/dist/src/core/index.js
CHANGED
|
@@ -102,20 +102,29 @@ var APP_MATRIX = Object.freeze({
|
|
|
102
102
|
* The byte-copied host artifact paths, frozen.
|
|
103
103
|
*
|
|
104
104
|
* @remarks
|
|
105
|
-
* The root docs (`AGENTS.md` / `CLAUDE.md`), `LICENSE`,
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
* (`guides/src/
|
|
112
|
-
*
|
|
113
|
-
*
|
|
105
|
+
* The root docs (`AGENTS.md` / `CLAUDE.md`), `LICENSE`, the canonical
|
|
106
|
+
* orchestration contract (`.agents/orchestration.md`) every harness bridge
|
|
107
|
+
* points at, `.agents`, `.claude`, `.codex`, `.cursor`, the four SessionStart
|
|
108
|
+
* hook scripts (`scripts/deps.sh` / `scripts/cursor.sh` / `scripts/codex.sh` /
|
|
109
|
+
* `scripts/ollama.sh`), the repository coding-law policy module, the line's
|
|
110
|
+
* seven byte-identical root dotfiles, and the two guides-grouped mirror
|
|
111
|
+
* candidates: the line-wide dev-tooling guide (`guides/src/guide.md`) and the
|
|
112
|
+
* scaffold bin's own self-guide (`guides/src/scaffold.md`). `stageHost` vendors
|
|
113
|
+
* both; each plan carries the subset selected by `selectHostPaths`, omitting the
|
|
114
|
+
* target blueprint's own guide.
|
|
115
|
+
*
|
|
116
|
+
* Three harness bridges point at `.agents/orchestration.md` and carry only their
|
|
117
|
+
* own harness's specifics: `CLAUDE.md`, `.codex/config.toml`, and
|
|
118
|
+
* `.cursor/rules`. They are meaningless without the contract they reference, but
|
|
119
|
+
* they do not share a `Group` — `hostGroup` keeps `CLAUDE.md` in `docs` with the
|
|
120
|
+
* other root documents, so a plan selecting `orchestration` carries two of the
|
|
121
|
+
* three and a plan selecting `docs` carries the third.
|
|
114
122
|
*/
|
|
115
123
|
var HOST_PATHS = Object.freeze([
|
|
116
124
|
"AGENTS.md",
|
|
117
125
|
"CLAUDE.md",
|
|
118
126
|
"LICENSE",
|
|
127
|
+
".agents/orchestration.md",
|
|
119
128
|
".agents/skills",
|
|
120
129
|
".claude/agents",
|
|
121
130
|
".claude/rules",
|
|
@@ -124,6 +133,7 @@ var HOST_PATHS = Object.freeze([
|
|
|
124
133
|
".codex/agents",
|
|
125
134
|
".codex/config.toml",
|
|
126
135
|
".cursor/mcp.json",
|
|
136
|
+
".cursor/rules",
|
|
127
137
|
".mcp.json",
|
|
128
138
|
"scripts/deps.sh",
|
|
129
139
|
"scripts/cursor.sh",
|
|
@@ -140,12 +150,48 @@ var HOST_PATHS = Object.freeze([
|
|
|
140
150
|
"guides/src/guide.md",
|
|
141
151
|
"guides/src/scaffold.md"
|
|
142
152
|
]);
|
|
143
|
-
/**
|
|
153
|
+
/**
|
|
154
|
+
* The path prefixes whose contents instruct or wire an agent, frozen.
|
|
155
|
+
*
|
|
156
|
+
* @remarks
|
|
157
|
+
* Group classification splits by what a path governs, not by where it sits:
|
|
158
|
+
* anything under these prefixes is `orchestration`, and everything else that is
|
|
159
|
+
* not source, tests, guides, docs, or a manifest is `configs`. Both classifiers
|
|
160
|
+
* — `inferGroup` for a foreign target path and `hostGroup` for a `HOST_PATHS`
|
|
161
|
+
* entry — read this one list, so a new harness directory is admitted once.
|
|
162
|
+
*/
|
|
163
|
+
var ORCHESTRATION_PATH_PREFIXES = Object.freeze([
|
|
164
|
+
".agents/",
|
|
165
|
+
".claude/",
|
|
166
|
+
".codex/",
|
|
167
|
+
".cursor/",
|
|
168
|
+
".github/",
|
|
169
|
+
"scripts/"
|
|
170
|
+
]);
|
|
171
|
+
/**
|
|
172
|
+
* The exact root filenames that wire an agent bench rather than the toolchain, frozen.
|
|
173
|
+
*
|
|
174
|
+
* @remarks
|
|
175
|
+
* `.mcp.json` registers MCP servers for the harness. It sits among the root
|
|
176
|
+
* dotfiles but governs agents, so it groups with the harness bridges.
|
|
177
|
+
*/
|
|
178
|
+
var ORCHESTRATION_PATH_NAMES = Object.freeze([".mcp.json"]);
|
|
179
|
+
/** The birth-only provisioner skeleton retained by workspaces with declared service vendors. */
|
|
144
180
|
var SERVICE_SCRIPT_PATH = "scripts/service.sh";
|
|
145
181
|
/** The consumer-owned Vitest global-setup module shared by its independently selected projects. */
|
|
146
182
|
var GLOBAL_SETUP_PATH = "tests/setupGlobal.ts";
|
|
147
183
|
/** The consumer-owned Vite wrapper whose physical presence enables the optional app showcase. */
|
|
148
184
|
var SHOWCASE_CONFIG_PATH = "configs/app/vite.showcase.config.ts";
|
|
185
|
+
/**
|
|
186
|
+
* The catalog agent file whose bounded marker region the catalog operation alone owns.
|
|
187
|
+
*
|
|
188
|
+
* @remarks
|
|
189
|
+
* Vendored like every other host artifact, but presence-owned after hydration:
|
|
190
|
+
* `diffPlan` compares this one path by presence, so a consumer restores it while
|
|
191
|
+
* absent and never replaces its bytes — not from an audit, not from a repair, and
|
|
192
|
+
* not under `replace`.
|
|
193
|
+
*/
|
|
194
|
+
var CATALOG_AGENT_PATH = ".claude/agents/orkestrel.md";
|
|
149
195
|
/** The package-name RegExp — lowercase alphanumeric-with-hyphens, letter-first. */
|
|
150
196
|
var NAME_PATTERN = /^[a-z][a-z0-9-]*$/;
|
|
151
197
|
/** Maximum bare workspace name length beneath the generated `@orkestrel/` scope. */
|
|
@@ -228,7 +274,7 @@ var DEFAULT_VERSION = "0.0.1";
|
|
|
228
274
|
/** The `engines.node` range the `blueprint` builder fills. */
|
|
229
275
|
var DEFAULT_ENGINES = `>=${MINIMUM_NODE_VERSION}`;
|
|
230
276
|
/** The devDependency range generated packages pin `@orkestrel/scaffold` at. */
|
|
231
|
-
var SCAFFOLD_RANGE = "^0.0.
|
|
277
|
+
var SCAFFOLD_RANGE = "^0.0.22";
|
|
232
278
|
/** Tooling versions shared by scaffold and every generated workspace. */
|
|
233
279
|
var BASE_DEV_DEPENDENCIES = Object.freeze({
|
|
234
280
|
"@microsoft/api-extractor": "^7.58.12",
|
|
@@ -437,8 +483,8 @@ function member(name, category, summary, environment = "core") {
|
|
|
437
483
|
* @remarks
|
|
438
484
|
* `version` / `engines` default `DEFAULT_VERSION` / `DEFAULT_ENGINES`,
|
|
439
485
|
* `src` defaults `['core']`, and `app` / `keywords` / `dependencies` /
|
|
440
|
-
* `peers` / `extras` / `overrides` default `[]`, and `bin` /
|
|
441
|
-
* `
|
|
486
|
+
* `peers` / `extras` / `overrides` / `services` default `[]`, and `bin` /
|
|
487
|
+
* `integration` / `global` / `showcase` default `false`. `description` is OMITTED entirely
|
|
442
488
|
* when absent, so the result round-trips the exact-record `Blueprint` guard.
|
|
443
489
|
* @returns A complete `Blueprint`.
|
|
444
490
|
*
|
|
@@ -463,7 +509,7 @@ function blueprint(name, options) {
|
|
|
463
509
|
overrides: options?.overrides ?? [],
|
|
464
510
|
bin: options?.bin ?? false,
|
|
465
511
|
integration: options?.integration ?? false,
|
|
466
|
-
|
|
512
|
+
services: [...options?.services ?? []].sort(),
|
|
467
513
|
global: options?.global ?? false,
|
|
468
514
|
showcase: options?.showcase ?? false
|
|
469
515
|
};
|
|
@@ -952,7 +998,7 @@ function syncToReview(report) {
|
|
|
952
998
|
}
|
|
953
999
|
/**
|
|
954
1000
|
* Project a fleet package catalog into a markdown table — the block
|
|
955
|
-
*
|
|
1001
|
+
* `CATALOG_AGENT_PATH`'s catalog markers wrap.
|
|
956
1002
|
*
|
|
957
1003
|
* @param entries - The catalog rows to render.
|
|
958
1004
|
* @remarks
|
|
@@ -984,10 +1030,12 @@ function catalogToBlock(entries) {
|
|
|
984
1030
|
*
|
|
985
1031
|
* @param path - The target-relative path to classify.
|
|
986
1032
|
* @remarks
|
|
987
|
-
* Ordered prefix match — `src/`, `tests/`, `guides/`, `docs/`, `configs/`,
|
|
988
|
-
*
|
|
989
|
-
* `
|
|
990
|
-
*
|
|
1033
|
+
* Ordered prefix match — `src/`, `tests/`, `guides/`, `docs/`, `configs/`, then
|
|
1034
|
+
* `matchesOrchestrationPath`, which owns the orchestration membership rule for
|
|
1035
|
+
* this function and for `hostGroup` alike, then the two manifest files by exact
|
|
1036
|
+
* name. Anything left falls through to `'configs'`. Read the rule at
|
|
1037
|
+
* `matchesOrchestrationPath` rather than here; one rule with two descriptions
|
|
1038
|
+
* drifts exactly as fast as one rule with two implementations.
|
|
991
1039
|
* @returns The inferred `Group` for `path`.
|
|
992
1040
|
*
|
|
993
1041
|
* @example
|
|
@@ -1005,23 +1053,43 @@ function inferGroup(path) {
|
|
|
1005
1053
|
if (path.startsWith("guides/")) return "guides";
|
|
1006
1054
|
if (path.startsWith("docs/")) return "docs";
|
|
1007
1055
|
if (path.startsWith("configs/")) return "configs";
|
|
1008
|
-
if (
|
|
1056
|
+
if (matchesOrchestrationPath(path)) return "orchestration";
|
|
1009
1057
|
if (path === "package.json" || path === "package-lock.json") return "manifest";
|
|
1010
1058
|
return "configs";
|
|
1011
1059
|
}
|
|
1012
1060
|
/**
|
|
1061
|
+
* Test whether a path instructs or wires an agent rather than the toolchain.
|
|
1062
|
+
*
|
|
1063
|
+
* @param path - The portable path to classify.
|
|
1064
|
+
* @returns `true` when the path is agent orchestration.
|
|
1065
|
+
*
|
|
1066
|
+
* @example
|
|
1067
|
+
* ```ts
|
|
1068
|
+
* import { matchesOrchestrationPath } from '@orkestrel/scaffold'
|
|
1069
|
+
*
|
|
1070
|
+
* matchesOrchestrationPath('.cursor/rules/orchestration.mdc') // true
|
|
1071
|
+
* matchesOrchestrationPath('.mcp.json') // true
|
|
1072
|
+
* matchesOrchestrationPath('.oxlintrc.json') // false
|
|
1073
|
+
* ```
|
|
1074
|
+
*/
|
|
1075
|
+
function matchesOrchestrationPath(path) {
|
|
1076
|
+
if (ORCHESTRATION_PATH_NAMES.includes(path)) return true;
|
|
1077
|
+
return ORCHESTRATION_PATH_PREFIXES.some((prefix) => path.startsWith(prefix));
|
|
1078
|
+
}
|
|
1079
|
+
/**
|
|
1013
1080
|
* Diff a plan's artifacts against a target's current content.
|
|
1014
1081
|
*
|
|
1015
1082
|
* @param plan - The plan whose artifacts are the source of truth.
|
|
1016
1083
|
* @param current - The target's current content, keyed by artifact-relative path.
|
|
1017
1084
|
* @remarks
|
|
1018
|
-
* Audit semantics are per-origin. A `host`-origin artifact
|
|
1019
|
-
*
|
|
1020
|
-
*
|
|
1021
|
-
*
|
|
1022
|
-
*
|
|
1023
|
-
*
|
|
1024
|
-
*
|
|
1085
|
+
* Audit semantics are per-origin. A `host`-origin artifact with canonical
|
|
1086
|
+
* `hex` is content-compared exactly like a `computed` artifact and CAN be
|
|
1087
|
+
* `stale`. A host artifact without canonical bytes is presence-owned:
|
|
1088
|
+
* present is `aligned`, absent is `missing`. `CATALOG_AGENT_PATH` remains
|
|
1089
|
+
* presence-owned after hydration because the catalog operation alone owns its
|
|
1090
|
+
* bounded marker region. `hydratePlan` expands directory-shaped host artifacts
|
|
1091
|
+
* into byte-aware file artifacts; only an intentional dependency-guide pointer
|
|
1092
|
+
* may remain without `hex`. A `computed` artifact is content-aware canon —
|
|
1025
1093
|
* `missing` / `aligned` / `stale` — and gates the audit like any drifted
|
|
1026
1094
|
* finding. A `template`-origin artifact is BIRTH-ONLY and AUDIT-EXEMPT: it is
|
|
1027
1095
|
* always reported `aligned`, regardless of whether the target has it at all
|
|
@@ -1061,7 +1129,7 @@ function diffPlan(plan, current) {
|
|
|
1061
1129
|
if (artifact.origin === "host") {
|
|
1062
1130
|
let drift;
|
|
1063
1131
|
if (seen === void 0) drift = "missing";
|
|
1064
|
-
else if (artifact.hex === void 0) drift = "aligned";
|
|
1132
|
+
else if (artifact.path === ".claude/agents/orkestrel.md" || artifact.hex === void 0) drift = "aligned";
|
|
1065
1133
|
else drift = seen === artifact.hex ? "aligned" : "stale";
|
|
1066
1134
|
findings.push({
|
|
1067
1135
|
path: artifact.path,
|
|
@@ -1418,6 +1486,35 @@ function validateBlueprint(spec) {
|
|
|
1418
1486
|
text: "Showcase requires the app browser environment",
|
|
1419
1487
|
blocking: true
|
|
1420
1488
|
});
|
|
1489
|
+
const seenServices = /* @__PURE__ */ new Set();
|
|
1490
|
+
const serviceProjects = /* @__PURE__ */ new Set();
|
|
1491
|
+
let previousService;
|
|
1492
|
+
for (const service of spec.services) {
|
|
1493
|
+
if (!NAME_PATTERN.test(service) || service.length > 203) questions.push({
|
|
1494
|
+
field: "services",
|
|
1495
|
+
text: `Service name "${service}" must be a bounded lowercase directory name matching ${NAME_PATTERN.source}`,
|
|
1496
|
+
blocking: true
|
|
1497
|
+
});
|
|
1498
|
+
if (seenServices.has(service)) questions.push({
|
|
1499
|
+
field: "services",
|
|
1500
|
+
text: `Service "${service}" is declared more than once`,
|
|
1501
|
+
blocking: true
|
|
1502
|
+
});
|
|
1503
|
+
if (previousService !== void 0 && previousService > service) questions.push({
|
|
1504
|
+
field: "services",
|
|
1505
|
+
text: "Services must be sorted by directory name",
|
|
1506
|
+
blocking: true
|
|
1507
|
+
});
|
|
1508
|
+
const project = pascalCase(service);
|
|
1509
|
+
if (serviceProjects.has(project)) questions.push({
|
|
1510
|
+
field: "services",
|
|
1511
|
+
text: `Service "${service}" collides with another generated project name`,
|
|
1512
|
+
blocking: true
|
|
1513
|
+
});
|
|
1514
|
+
seenServices.add(service);
|
|
1515
|
+
serviceProjects.add(project);
|
|
1516
|
+
previousService = service;
|
|
1517
|
+
}
|
|
1421
1518
|
if (spec.src.length > 0) {
|
|
1422
1519
|
for (const environment of spec.src) if (!ENVIRONMENTS.includes(environment)) questions.push({
|
|
1423
1520
|
field: "src",
|
|
@@ -1908,7 +2005,10 @@ function blueprintShape() {
|
|
|
1908
2005
|
overrides: arrayShape(overrideShape(), { max: MAX_COLLECTION_ITEMS }),
|
|
1909
2006
|
bin: booleanShape(),
|
|
1910
2007
|
integration: booleanShape(),
|
|
1911
|
-
|
|
2008
|
+
services: arrayShape(stringShape({
|
|
2009
|
+
min: 1,
|
|
2010
|
+
max: 203
|
|
2011
|
+
}), { max: MAX_COLLECTION_ITEMS }),
|
|
1912
2012
|
global: booleanShape(),
|
|
1913
2013
|
showcase: booleanShape()
|
|
1914
2014
|
});
|
|
@@ -4501,6 +4601,87 @@ describe('root Vite configuration', () => {
|
|
|
4501
4601
|
expect(environmentSourceError('app/browser', '@app/core')).toBeUndefined()
|
|
4502
4602
|
}){{cases}}
|
|
4503
4603
|
})
|
|
4604
|
+
`
|
|
4605
|
+
}),
|
|
4606
|
+
serviceConformance: Object.freeze({
|
|
4607
|
+
id: "serviceConformance",
|
|
4608
|
+
name: "serviceConformance",
|
|
4609
|
+
summary: "The generated service-vendor structure and configuration conformance test.",
|
|
4610
|
+
category: "tests",
|
|
4611
|
+
placeholders: Object.freeze([Object.freeze({
|
|
4612
|
+
name: "services",
|
|
4613
|
+
description: "The sorted service vendor directory names."
|
|
4614
|
+
})]),
|
|
4615
|
+
content: `import { existsSync, lstatSync, readFileSync, readdirSync } from 'node:fs'
|
|
4616
|
+
import { join } from 'node:path'
|
|
4617
|
+
import { isRecord, parseJSON } from '@orkestrel/contract'
|
|
4618
|
+
import { expect, it } from 'vitest'
|
|
4619
|
+
|
|
4620
|
+
it('keeps every service vendor structurally complete and exactly configured', () => {
|
|
4621
|
+
const declared = {{services}}
|
|
4622
|
+
const root = join(process.cwd(), 'tests', 'service')
|
|
4623
|
+
const directories = readdirSync(root, { withFileTypes: true })
|
|
4624
|
+
.filter((entry) => entry.isDirectory())
|
|
4625
|
+
.map((entry) => entry.name)
|
|
4626
|
+
.sort()
|
|
4627
|
+
const manifest = parseJSON(readFileSync(join(process.cwd(), 'package.json'), 'utf8'))
|
|
4628
|
+
const scripts = isRecord(manifest) && isRecord(manifest.scripts) ? manifest.scripts : {}
|
|
4629
|
+
const config = readFileSync(join(process.cwd(), 'vite.config.ts'), 'utf8')
|
|
4630
|
+
const provisioner = join(process.cwd(), 'scripts', 'service.sh')
|
|
4631
|
+
|
|
4632
|
+
expect(directories).toEqual(declared)
|
|
4633
|
+
if (!existsSync(provisioner) || !lstatSync(provisioner).isFile()) {
|
|
4634
|
+
throw new Error(
|
|
4635
|
+
'Service vendors require scripts/service.sh to provision every declared vendor idempotently or exit nonzero',
|
|
4636
|
+
)
|
|
4637
|
+
}
|
|
4638
|
+
for (const service of declared) {
|
|
4639
|
+
const setup = join(root, service, 'setup.ts')
|
|
4640
|
+
if (!existsSync(setup) || !lstatSync(setup).isFile()) {
|
|
4641
|
+
throw new Error(
|
|
4642
|
+
\`Service vendor "\${service}" is missing tests/service/\${service}/setup.ts; add a readiness module that probes and warms the vendor and throws when unavailable\`,
|
|
4643
|
+
)
|
|
4644
|
+
}
|
|
4645
|
+
const label = \`name: { label: 'service:\${service}', color: 'red' }\`
|
|
4646
|
+
const include = \`include: ['tests/service/\${service}/**/*.test.ts']\`
|
|
4647
|
+
const setupFiles = \`setupFiles: ['./tests/setup.ts', './tests/setupServer.ts', './tests/service/\${service}/setup.ts']\`
|
|
4648
|
+
if (!config.includes(label) || !config.includes(include) || !config.includes(setupFiles)) {
|
|
4649
|
+
throw new Error(\`Service vendor "\${service}" is missing its exact Vite project\`)
|
|
4650
|
+
}
|
|
4651
|
+
const command = \`vitest run --config vite.config.ts --no-cache --reporter=dot --project service:\${service}\`
|
|
4652
|
+
if (scripts[\`test:service:\${service}\`] !== command) {
|
|
4653
|
+
throw new Error(\`Service vendor "\${service}" is missing its exact npm script\`)
|
|
4654
|
+
}
|
|
4655
|
+
}
|
|
4656
|
+
const aggregate =
|
|
4657
|
+
'vitest run --config vite.config.ts --no-cache --reporter=dot ' +
|
|
4658
|
+
declared.map((service) => \`--project service:\${service}\`).join(' ')
|
|
4659
|
+
if (scripts['test:service'] !== aggregate) {
|
|
4660
|
+
throw new Error('test:service must name every declared service exactly once')
|
|
4661
|
+
}
|
|
4662
|
+
if (typeof scripts.test !== 'string' || scripts.test.includes('test:service')) {
|
|
4663
|
+
throw new Error('The default test script must omit live service proofs')
|
|
4664
|
+
}
|
|
4665
|
+
if (
|
|
4666
|
+
typeof scripts.prepublishOnly !== 'string' ||
|
|
4667
|
+
!scripts.prepublishOnly.endsWith(' && npm run test:service')
|
|
4668
|
+
) {
|
|
4669
|
+
throw new Error('prepublishOnly must end with the aggregate live service proof')
|
|
4670
|
+
}
|
|
4671
|
+
})
|
|
4672
|
+
`
|
|
4673
|
+
}),
|
|
4674
|
+
serviceProvisioner: Object.freeze({
|
|
4675
|
+
id: "serviceProvisioner",
|
|
4676
|
+
name: "serviceProvisioner",
|
|
4677
|
+
summary: "The birth-only workspace-owned service-vendor provisioner skeleton.",
|
|
4678
|
+
category: "orchestration",
|
|
4679
|
+
placeholders: Object.freeze([]),
|
|
4680
|
+
content: `#!/bin/sh
|
|
4681
|
+
set -eu
|
|
4682
|
+
|
|
4683
|
+
printf '%s\\n' 'Service provisioning is not configured. Implement scripts/service.sh to provision every declared vendor idempotently, then remove this failure.' >&2
|
|
4684
|
+
exit 1
|
|
4504
4685
|
`
|
|
4505
4686
|
}),
|
|
4506
4687
|
policyTest: Object.freeze({
|
|
@@ -4510,15 +4691,23 @@ describe('root Vite configuration', () => {
|
|
|
4510
4691
|
category: "tests",
|
|
4511
4692
|
placeholders: Object.freeze([Object.freeze({
|
|
4512
4693
|
name: "vuePolicyImport",
|
|
4513
|
-
description: "The
|
|
4694
|
+
description: "The Vue SFC parser import, when the workspace declares app/browser."
|
|
4514
4695
|
}), Object.freeze({
|
|
4515
4696
|
name: "workspacePolicyAssertion",
|
|
4516
|
-
description: "The
|
|
4697
|
+
description: "The workspace coding-law assertion, carrying a Vue script extractor when the workspace declares app/browser."
|
|
4517
4698
|
})]),
|
|
4518
4699
|
content: `import { globSync } from 'node:fs'
|
|
4519
4700
|
import { describe, expect, it } from 'vitest'
|
|
4520
4701
|
import { isBrowserVuePath } from './setup.js'
|
|
4521
|
-
import { inspectCodingWorkspace } from './setupPolicy.js'{{vuePolicyImport}}
|
|
4702
|
+
import { inspectCodingLaw, inspectCodingWorkspace, isFunctionDomainPath } from './setupPolicy.js'{{vuePolicyImport}}
|
|
4703
|
+
|
|
4704
|
+
${CONST_KEYWORD} FUNCTION_MODULE_PATH = 'app/browser/composables/useTheme.ts'
|
|
4705
|
+
${CONST_KEYWORD} FUNCTION_MODULE_VIOLATION =
|
|
4706
|
+
FUNCTION_MODULE_PATH + ' declarations do not form one matching exported function implementation'
|
|
4707
|
+
${CONST_KEYWORD} FUNCTION_DOMAIN_FILE_PATH = 'app/server/composables.ts'
|
|
4708
|
+
${CONST_KEYWORD} FUNCTION_DOMAIN_FILE_VIOLATION =
|
|
4709
|
+
FUNCTION_DOMAIN_FILE_PATH +
|
|
4710
|
+
' names a function domain, which belongs in a folder rather than a file'
|
|
4522
4711
|
|
|
4523
4712
|
describe('repository coding law', () => {
|
|
4524
4713
|
it('keeps Vue single-file components exclusively in browser environments', () => {
|
|
@@ -4530,6 +4719,125 @@ describe('repository coding law', () => {
|
|
|
4530
4719
|
it('enforces source placement, exports, readonly contracts, and syntax law', () => {
|
|
4531
4720
|
{{workspacePolicyAssertion}}
|
|
4532
4721
|
})
|
|
4722
|
+
|
|
4723
|
+
it('accepts one matching exported function in a registered domain', () => {
|
|
4724
|
+
expect(
|
|
4725
|
+
inspectCodingLaw(
|
|
4726
|
+
FUNCTION_MODULE_PATH,
|
|
4727
|
+
"import type { Ref } from 'vue'\\nexport function useTheme(): Ref<undefined> { throw new Error() }",
|
|
4728
|
+
),
|
|
4729
|
+
).toEqual([])
|
|
4730
|
+
})
|
|
4731
|
+
|
|
4732
|
+
it('accepts one matching exported generator in a registered domain', () => {
|
|
4733
|
+
expect(
|
|
4734
|
+
inspectCodingLaw(FUNCTION_MODULE_PATH, 'export function* useTheme(): Generator<void> {}'),
|
|
4735
|
+
).toEqual([])
|
|
4736
|
+
})
|
|
4737
|
+
|
|
4738
|
+
it('accepts overload signatures beside one matching implementation', () => {
|
|
4739
|
+
expect(
|
|
4740
|
+
inspectCodingLaw(
|
|
4741
|
+
FUNCTION_MODULE_PATH,
|
|
4742
|
+
'export function useTheme(): void\\nexport function useTheme(mode: string): void\\nexport function useTheme(_mode?: string): void {}',
|
|
4743
|
+
),
|
|
4744
|
+
).toEqual([])
|
|
4745
|
+
})
|
|
4746
|
+
|
|
4747
|
+
it('rejects a bodyless function-domain declaration', () => {
|
|
4748
|
+
expect(
|
|
4749
|
+
inspectCodingLaw(FUNCTION_MODULE_PATH, 'export declare function useTheme(): void'),
|
|
4750
|
+
).toEqual([FUNCTION_MODULE_VIOLATION])
|
|
4751
|
+
})
|
|
4752
|
+
|
|
4753
|
+
it('rejects a mismatched bodyless declaration beside one implementation', () => {
|
|
4754
|
+
expect(
|
|
4755
|
+
inspectCodingLaw(
|
|
4756
|
+
FUNCTION_MODULE_PATH,
|
|
4757
|
+
'declare function smuggled(secret: string): void\\nexport function useTheme(): void {}',
|
|
4758
|
+
),
|
|
4759
|
+
).toEqual([FUNCTION_MODULE_VIOLATION])
|
|
4760
|
+
})
|
|
4761
|
+
|
|
4762
|
+
it('rejects two exported functions in a function module', () => {
|
|
4763
|
+
expect(
|
|
4764
|
+
inspectCodingLaw(
|
|
4765
|
+
FUNCTION_MODULE_PATH,
|
|
4766
|
+
'export function useTheme(): void {}\\nexport function useMode(): void {}',
|
|
4767
|
+
),
|
|
4768
|
+
).toEqual([FUNCTION_MODULE_VIOLATION])
|
|
4769
|
+
})
|
|
4770
|
+
|
|
4771
|
+
it('rejects module data beside a function-domain export', () => {
|
|
4772
|
+
expect(
|
|
4773
|
+
inspectCodingLaw(
|
|
4774
|
+
FUNCTION_MODULE_PATH,
|
|
4775
|
+
"const THEME = 'dark'\\nexport function useTheme(): string { return THEME }",
|
|
4776
|
+
),
|
|
4777
|
+
).toEqual([FUNCTION_MODULE_VIOLATION])
|
|
4778
|
+
})
|
|
4779
|
+
|
|
4780
|
+
it('rejects a function whose name differs from its filename', () => {
|
|
4781
|
+
expect(inspectCodingLaw(FUNCTION_MODULE_PATH, 'export function useMode(): void {}')).toEqual([
|
|
4782
|
+
FUNCTION_MODULE_VIOLATION,
|
|
4783
|
+
])
|
|
4784
|
+
})
|
|
4785
|
+
|
|
4786
|
+
it('rejects a non-exported function-domain declaration', () => {
|
|
4787
|
+
expect(inspectCodingLaw(FUNCTION_MODULE_PATH, 'function useTheme(): void {}')).toEqual([
|
|
4788
|
+
FUNCTION_MODULE_VIOLATION,
|
|
4789
|
+
])
|
|
4790
|
+
})
|
|
4791
|
+
|
|
4792
|
+
it('rejects a default function-domain export', () => {
|
|
4793
|
+
expect(
|
|
4794
|
+
inspectCodingLaw(FUNCTION_MODULE_PATH, 'export default function useTheme(): void {}'),
|
|
4795
|
+
).toEqual([FUNCTION_MODULE_VIOLATION])
|
|
4796
|
+
})
|
|
4797
|
+
|
|
4798
|
+
it('keeps index modules outside the function-domain shape', () => {
|
|
4799
|
+
const path = 'app/browser/composables/index.ts'
|
|
4800
|
+
|
|
4801
|
+
expect(isFunctionDomainPath(path)).toBe(false)
|
|
4802
|
+
expect(inspectCodingLaw(path, 'export function index(): void {}')).toContain(
|
|
4803
|
+
path + ' places module functions in their centralized kind file',
|
|
4804
|
+
)
|
|
4805
|
+
})
|
|
4806
|
+
|
|
4807
|
+
it('keeps main modules outside the function-domain shape', () => {
|
|
4808
|
+
const path = 'app/browser/composables/main.ts'
|
|
4809
|
+
|
|
4810
|
+
expect(isFunctionDomainPath(path)).toBe(false)
|
|
4811
|
+
expect(inspectCodingLaw(path, 'export function main(): void {}')).toContain(
|
|
4812
|
+
path + ' places module functions in their centralized kind file',
|
|
4813
|
+
)
|
|
4814
|
+
})
|
|
4815
|
+
|
|
4816
|
+
it('rejects a file named for a registered function domain', () => {
|
|
4817
|
+
const content =
|
|
4818
|
+
"import { parentPort } from 'node:worker_threads'\\nexport function start(): void { parentPort?.close() }"
|
|
4819
|
+
|
|
4820
|
+
expect(inspectCodingLaw(FUNCTION_DOMAIN_FILE_PATH, content)).toEqual([
|
|
4821
|
+
FUNCTION_DOMAIN_FILE_VIOLATION,
|
|
4822
|
+
])
|
|
4823
|
+
})
|
|
4824
|
+
|
|
4825
|
+
it('keeps camelCase modules in unregistered domains under centralized placement', () => {
|
|
4826
|
+
const path = 'app/browser/services/normalizePath.ts'
|
|
4827
|
+
|
|
4828
|
+
expect(isFunctionDomainPath(path)).toBe(false)
|
|
4829
|
+
expect(inspectCodingLaw(path, 'export function normalizePath(): void {}')).toEqual([
|
|
4830
|
+
path + ' places module functions in their centralized kind file',
|
|
4831
|
+
])
|
|
4832
|
+
})
|
|
4833
|
+
|
|
4834
|
+
it('preserves the self-contained Node runtime exemption', () => {
|
|
4835
|
+
const path = 'app/server/worker.ts'
|
|
4836
|
+
const content =
|
|
4837
|
+
"import { parentPort } from 'node:worker_threads'\\nconst port = parentPort\\nexport function start(): void { port?.close() }"
|
|
4838
|
+
|
|
4839
|
+
expect(inspectCodingLaw(path, content)).toEqual([])
|
|
4840
|
+
})
|
|
4533
4841
|
})
|
|
4534
4842
|
`
|
|
4535
4843
|
}),
|
|
@@ -5676,14 +5984,30 @@ for (const entry of GUIDE_MANIFEST) {
|
|
|
5676
5984
|
* @example
|
|
5677
5985
|
* ```ts
|
|
5678
5986
|
* hostGroup('AGENTS.md') // 'docs'
|
|
5679
|
-
* hostGroup('.agents') // 'orchestration'
|
|
5680
|
-
* hostGroup('.claude') // 'orchestration'
|
|
5681
|
-
* hostGroup('.
|
|
5987
|
+
* hostGroup('.agents/orchestration.md') // 'orchestration'
|
|
5988
|
+
* hostGroup('.claude/rules') // 'orchestration'
|
|
5989
|
+
* hostGroup('.cursor/rules') // 'orchestration'
|
|
5990
|
+
* hostGroup('.mcp.json') // 'orchestration'
|
|
5991
|
+
* hostGroup('.oxlintrc.json') // 'configs'
|
|
5682
5992
|
* ```
|
|
5993
|
+
*
|
|
5994
|
+
* @remarks
|
|
5995
|
+
* Takes a `HOST_PATHS` entry, so every example above is one. A bare directory
|
|
5996
|
+
* name is not: `ORCHESTRATION_PATH_PREFIXES` entries carry a trailing slash, so
|
|
5997
|
+
* `hostGroup('.cursor')` is `configs`, and no vendored entry has that form.
|
|
5998
|
+
*
|
|
5999
|
+
* Below the `docs` branch the split is by what a path governs rather than where
|
|
6000
|
+
* it sits, which is why both MCP registrations — `.mcp.json` and
|
|
6001
|
+
* `.cursor/mcp.json` — group with the harness bridges instead of with the root
|
|
6002
|
+
* dotfiles beside them. The `docs` branch is checked first and is deliberately
|
|
6003
|
+
* positional: `AGENTS.md`, `CLAUDE.md`, and `LICENSE` are the root documents, and
|
|
6004
|
+
* `CLAUDE.md` stays there as a root document even though it is also a harness
|
|
6005
|
+
* bridge. A plan selecting `orchestration` therefore carries two of the three
|
|
6006
|
+
* bridges; a plan selecting `docs` carries the third.
|
|
5683
6007
|
*/
|
|
5684
6008
|
function hostGroup(path) {
|
|
5685
6009
|
if (path === "AGENTS.md" || path === "CLAUDE.md" || path === "LICENSE") return "docs";
|
|
5686
|
-
if (
|
|
6010
|
+
if (matchesOrchestrationPath(path)) return "orchestration";
|
|
5687
6011
|
if (path.startsWith("tests/")) return "tests";
|
|
5688
6012
|
if (path === "guides/src/guide.md" || path === "guides/src/scaffold.md") return "guides";
|
|
5689
6013
|
return "configs";
|
|
@@ -5949,7 +6273,10 @@ function packageManifest(spec) {
|
|
|
5949
6273
|
if (spec.bin) scripts["test:src:bin"] = "vitest run --config vite.config.ts --no-cache --reporter=dot --project src:bin";
|
|
5950
6274
|
if (spec.integration) scripts["test:integration"] = "vitest run --config vite.config.ts --no-cache --reporter=dot --project integration";
|
|
5951
6275
|
if (spec.bin && spec.integration) scripts["test:equivalence"] = "node -e \"const c=require('node:child_process'),p=process.env.npm_execpath;if(p===undefined)process.exit(1);const r=c.spawnSync(process.execPath,[p,'run','test:integration'],{stdio:'inherit',env:{...process.env,SCAFFOLD_BOUNDARY_EQUIVALENCE:'1'}});process.exit(r.status??1)\"";
|
|
5952
|
-
if (spec.
|
|
6276
|
+
if (spec.services.length > 0) {
|
|
6277
|
+
scripts["test:service"] = "vitest run --config vite.config.ts --no-cache --reporter=dot " + spec.services.map((service) => `--project service:${service}`).join(" ");
|
|
6278
|
+
for (const service of spec.services) scripts[`test:service:${service}`] = `vitest run --config vite.config.ts --no-cache --reporter=dot --project service:${service}`;
|
|
6279
|
+
}
|
|
5953
6280
|
if (spec.app.length > 0) {
|
|
5954
6281
|
scripts["test:app"] = "vitest run --config vite.config.ts --no-cache --reporter=dot " + spec.app.map((environment) => `--project ${APP_MATRIX[environment].project}`).join(" ");
|
|
5955
6282
|
for (const environment of spec.app) scripts[`test:app:${environment}`] = `vitest run --config vite.config.ts --no-cache --reporter=dot --project ${APP_MATRIX[environment].project}`;
|
|
@@ -5988,7 +6315,7 @@ function packageManifest(spec) {
|
|
|
5988
6315
|
scripts["build:src:bin"] = "vite build --config configs/src/vite.bin.config.ts";
|
|
5989
6316
|
scripts["build:host"] = "node -e \"import('./dist/src/server/index.js').then((m)=>{const n=m.stageHost(process.cwd(),'dist/host').length;console.log('build-host: staged '+n+' file(s) into dist/host')})\"";
|
|
5990
6317
|
}
|
|
5991
|
-
scripts.prepublishOnly = "npm run format:check && npm run lint:check && npm run check && npm run build && npm test" + (spec.integration ? " && npm run test:integration" : "");
|
|
6318
|
+
scripts.prepublishOnly = "npm run format:check && npm run lint:check && npm run check && npm run build && npm test" + (spec.integration ? " && npm run test:integration" : "") + (spec.services.length > 0 ? " && npm run test:service" : "");
|
|
5992
6319
|
const devDependencies = devDependenciesFor(spec);
|
|
5993
6320
|
const manifest = {
|
|
5994
6321
|
name: hasSource ? `@orkestrel/${spec.name}` : spec.name,
|
|
@@ -5996,13 +6323,15 @@ function packageManifest(spec) {
|
|
|
5996
6323
|
...hasSource ? {} : { private: true },
|
|
5997
6324
|
description: spec.description ?? (hasSource ? `The @orkestrel/${spec.name} package.` : `The ${spec.name} application.`),
|
|
5998
6325
|
keywords: [...spec.keywords].sort(),
|
|
5999
|
-
|
|
6000
|
-
|
|
6326
|
+
...hasSource ? {
|
|
6327
|
+
homepage: `https://github.com/orkestrel/${spec.name}#readme`,
|
|
6328
|
+
bugs: `https://github.com/orkestrel/${spec.name}/issues`
|
|
6329
|
+
} : {},
|
|
6001
6330
|
license: "MIT",
|
|
6002
|
-
repository: {
|
|
6331
|
+
...hasSource ? { repository: {
|
|
6003
6332
|
type: "git",
|
|
6004
6333
|
url: `git+https://github.com/orkestrel/${spec.name}.git`
|
|
6005
|
-
},
|
|
6334
|
+
} } : {},
|
|
6006
6335
|
...spec.bin ? { bin: { scaffold: "./dist/bin/scaffold.js" } } : {},
|
|
6007
6336
|
files: spec.bin ? [
|
|
6008
6337
|
"dist/src",
|
|
@@ -6152,7 +6481,7 @@ function viteProjectRegistrations(src, app = [], facts = {}) {
|
|
|
6152
6481
|
registrations.push({ project: "policy" }, { project: "config" }, { project: "guides" });
|
|
6153
6482
|
if (facts.bin === true) registrations.push({ project: "srcBin" });
|
|
6154
6483
|
if (facts.integration === true) registrations.push({ project: "integration" });
|
|
6155
|
-
|
|
6484
|
+
for (const service of facts.services ?? []) registrations.push({ project: `service${pascalCase(service)}` });
|
|
6156
6485
|
return registrations;
|
|
6157
6486
|
}
|
|
6158
6487
|
/**
|
|
@@ -6174,7 +6503,7 @@ function viteProjectDefinitions(facts = {}) {
|
|
|
6174
6503
|
];
|
|
6175
6504
|
if (facts.bin === true) definitions.push(binViteProject());
|
|
6176
6505
|
if (facts.integration === true) definitions.push(integrationViteProject(facts));
|
|
6177
|
-
|
|
6506
|
+
for (const service of facts.services ?? []) definitions.push(serviceViteProject(service));
|
|
6178
6507
|
return definitions.join("\n");
|
|
6179
6508
|
}
|
|
6180
6509
|
/**
|
|
@@ -8161,24 +8490,27 @@ ${facts.bin === true && facts.integration === true && facts.global === true ? `
|
|
|
8161
8490
|
`;
|
|
8162
8491
|
}
|
|
8163
8492
|
/**
|
|
8164
|
-
* Build
|
|
8493
|
+
* Build one standalone Node-only live-service vendor proof project.
|
|
8165
8494
|
*
|
|
8166
|
-
* @
|
|
8495
|
+
* @param name - The bounded vendor directory name.
|
|
8496
|
+
* @returns The emitted `service:<name>` project definition.
|
|
8167
8497
|
*
|
|
8168
8498
|
* @example
|
|
8169
8499
|
* ```ts
|
|
8170
|
-
* serviceViteProject().includes("label: 'service'") // true
|
|
8500
|
+
* serviceViteProject('claude').includes("label: 'service:claude'") // true
|
|
8171
8501
|
* ```
|
|
8172
8502
|
*/
|
|
8173
|
-
function serviceViteProject() {
|
|
8174
|
-
|
|
8503
|
+
function serviceViteProject(name) {
|
|
8504
|
+
if (!NAME_PATTERN.test(name) || name.length > 203) throw new Error("Service project name must be a bounded lowercase directory name");
|
|
8505
|
+
return `${EXPORT_KEYWORD} const ${`service${pascalCase(name)}`} = (options?: UserConfig): UserConfig =>
|
|
8175
8506
|
mergeConfig(
|
|
8176
8507
|
{
|
|
8177
8508
|
resolve,
|
|
8509
|
+
plugins: [environmentBoundary('app/server')],
|
|
8178
8510
|
test: {
|
|
8179
|
-
name: { label:
|
|
8180
|
-
include: [
|
|
8181
|
-
setupFiles: ['./tests/setup.ts', './tests/
|
|
8511
|
+
name: { label: ${serializeTypeScriptString(`service:${name}`)}, color: 'red' },
|
|
8512
|
+
include: [${serializeTypeScriptString(`tests/service/${name}/**/*.test.ts`)}],
|
|
8513
|
+
setupFiles: ['./tests/setup.ts', './tests/setupServer.ts', ${serializeTypeScriptString(`./tests/service/${name}/setup.ts`)}],
|
|
8182
8514
|
environment: 'node',
|
|
8183
8515
|
browser: { enabled: false },
|
|
8184
8516
|
testTimeout: 120_000,
|
|
@@ -8328,7 +8660,7 @@ ${renderedTest}
|
|
|
8328
8660
|
*
|
|
8329
8661
|
* @param src - The declared `Environment[]`.
|
|
8330
8662
|
* @param facts - Optional structural facts. `bin` appends the standalone executable
|
|
8331
|
-
* build-and-test project; `integration` and `
|
|
8663
|
+
* build-and-test project; `integration` and `services` append their standalone
|
|
8332
8664
|
* proof projects; `global` wires the shared global-setup module.
|
|
8333
8665
|
* @returns The root `vite.config.ts` file content, newline-terminated.
|
|
8334
8666
|
*
|
|
@@ -9108,7 +9440,7 @@ function ciWorkflow(spec) {
|
|
|
9108
9440
|
const tail = [];
|
|
9109
9441
|
if (spec.integration) tail.push(` - name: Run live consumer integration
|
|
9110
9442
|
run: npm run test:integration`);
|
|
9111
|
-
if (spec.
|
|
9443
|
+
if (spec.services.length > 0) {
|
|
9112
9444
|
tail.push(` - name: Provision live service
|
|
9113
9445
|
run: bash ${SERVICE_SCRIPT_PATH}`);
|
|
9114
9446
|
tail.push(` - name: Run live service tests
|
|
@@ -9591,7 +9923,8 @@ ${EXPORT_KEYWORD} ${FUNCTION_KEYWORD} waitForEvent<TMap extends EventMap, K exte
|
|
|
9591
9923
|
cases: configCases.join("")
|
|
9592
9924
|
})
|
|
9593
9925
|
];
|
|
9594
|
-
if (spec.src.includes("server") || spec.app.includes("server")) artifacts.push(fillArtifact("tests/setupServer.ts", "tests", "setupServer", {}, "server"));
|
|
9926
|
+
if (spec.src.includes("server") || spec.app.includes("server") || spec.services.length > 0) artifacts.push(fillArtifact("tests/setupServer.ts", "tests", "setupServer", {}, "server"));
|
|
9927
|
+
if (spec.services.length > 0) artifacts.push(fillArtifact("tests/config/services.test.ts", "tests", "serviceConformance", { services: renderStringArray(spec.services, " ", "const declared = ", "") }, "server"));
|
|
9595
9928
|
if (spec.src.includes("browser") || spec.app.includes("browser")) artifacts.push(fillArtifact("tests/setupBrowser.ts", "tests", "setupBrowser", {}, "browser"));
|
|
9596
9929
|
const hasBoundary = hasApplicationBoundary(spec);
|
|
9597
9930
|
const hasShowcase = hasApplicationShowcase(spec);
|
|
@@ -10194,12 +10527,15 @@ npm install @orkestrel/${blueprint.name}
|
|
|
10194
10527
|
\`\`\`` : "This is a private application workspace and is not published to npm.",
|
|
10195
10528
|
usage: guideUsage(blueprint, pascal)
|
|
10196
10529
|
}));
|
|
10197
|
-
if (selected.includes("orchestration"))
|
|
10198
|
-
|
|
10199
|
-
|
|
10200
|
-
|
|
10201
|
-
|
|
10202
|
-
|
|
10530
|
+
if (selected.includes("orchestration")) {
|
|
10531
|
+
artifacts.push({
|
|
10532
|
+
path: ".github/workflows/ci.yml",
|
|
10533
|
+
group: "orchestration",
|
|
10534
|
+
origin: "computed",
|
|
10535
|
+
content: ciWorkflow(blueprint)
|
|
10536
|
+
});
|
|
10537
|
+
if (blueprint.services.length > 0) artifacts.push(fillArtifact(SERVICE_SCRIPT_PATH, "orchestration", "serviceProvisioner", {}));
|
|
10538
|
+
}
|
|
10203
10539
|
for (const path of selectHostPaths(HOST_PATHS, blueprint.name)) {
|
|
10204
10540
|
const group = hostGroup(path);
|
|
10205
10541
|
if (!selected.includes(group)) continue;
|
|
@@ -10323,9 +10659,10 @@ var Compiler = class Compiler {
|
|
|
10323
10659
|
this.#emitter.emit("audit", result);
|
|
10324
10660
|
return result;
|
|
10325
10661
|
}
|
|
10662
|
+
const diff = diffPlan(scaffolding.plan, current);
|
|
10326
10663
|
const result = {
|
|
10327
|
-
...
|
|
10328
|
-
questions: scaffolding.questions
|
|
10664
|
+
...diff,
|
|
10665
|
+
questions: [...scaffolding.questions, ...diff.questions]
|
|
10329
10666
|
};
|
|
10330
10667
|
this.#emitter.emit("audit", result);
|
|
10331
10668
|
return result;
|
|
@@ -10721,6 +11058,6 @@ function createBlueprint(data) {
|
|
|
10721
11058
|
return candidate;
|
|
10722
11059
|
}
|
|
10723
11060
|
//#endregion
|
|
10724
|
-
export { APP_BROWSER_DEV_DEPENDENCIES, APP_DEV_DEPENDENCIES, APP_MATRIX, APP_SERVER_DEV_DEPENDENCIES, BASE_DEV_DEPENDENCIES, BIN_CONFIGS, CATEGORIES, CHECKOUT_ACTION_SHA, COMPILER_ID, COMPILE_STAGES, CONST_KEYWORD, CONTROL_CHARACTER_PATTERN, Compiler, DEFAULT_ENGINES, DEFAULT_VERSION, DEPENDENCY_NAME_PATTERN, ENGINES_PATTERN, ENVIRONMENTS, EXPORT_KEYWORD, EXTRA_NAME_PATTERN, EXTRA_RANGE_PATTERN, FRESHNESS, FUNCTION_KEYWORD, GLOBAL_SETUP_PATH, GROUPS, HEX_PATTERN, HOST_PATHS, IMPORT_KEYWORD, INVALID_PATH_CHARACTER_PATTERN, JSON_PRINT_WIDTH, JSON_TAB_WIDTH, MAX_ARTIFACT_BYTES, MAX_ARTIFACT_HEX_LENGTH, MAX_COLLECTION_ITEMS, MAX_DATA_GRAPH_KEYS, MAX_DATA_GRAPH_NODES, MAX_DEPENDENCY_NAME_LENGTH, MAX_MANIFEST_BYTES, MAX_NAME_LENGTH, MAX_PATH_LENGTH, MAX_RANGE_LENGTH, MAX_SERIALIZED_INPUT_BYTES, MAX_TOTAL_ARTIFACT_BYTES, MINIMUM_NODE_VERSION, NAME_PATTERN, ORIGINS, ORKESTREL_RANGE_PATTERN, PlanManager, SCAFFOLD_RANGE, SERVICE_SCRIPT_PATH, SETUP_NODE_ACTION_SHA, SHOWCASE_CONFIG_PATH, SOURCE_BROWSER_DEV_DEPENDENCIES, SRC_MATRIX, SYNC_BASELINE_PATTERN, ScaffoldError, TEMPLATES, TYPESCRIPT_EXTENSIONS, VERSION_PATTERN, alignTable, appTsconfig, appViteConfig, applicationArtifacts, applicationViteConfig, applyOverrides, artifactShape, auditToReview, binTsconfig, binViteConfig, binViteProject, blueprint, blueprintShape, blueprintToMembers, blueprintToPlan, bytesToHex, catalogNames, catalogToBlock, ciWorkflow, compareCodeUnit, computeColumnWidth, computeHash, configArtifacts, configViteProject, contentByteLength, contentCodePoint, contentToBytes, contentToHex, coreTsconfig, coreViteConfig, createBlueprint, createCompiler, createPlanManager, delimiterCell, dependency, dependencyShape, devDependenciesFor, diffPlan, dualCondition, entryFields, escapeHtmlText, exportsMap, fillArtifact, findFileConflict, findPathConflict, fitsPrintWidth, formatJson, guideArtifacts, guideMemberTable, guideMethods, guideTests, guideUsage, guidesViteProject, hasApplicationBoundary, hasApplicationShowcase, hasBlueprintEnvironment, hasOnlyDataProperties, hasValidArtifactBytes, hasValidArtifactHex, hasValidAuditBytes, hasValidBlueprintBytes, hasValidOverrideBytes, hasValidPlanBytes, hasValidPlanHex, hasValidSnapshotBytes, hasValidSyncReportBytes, hostGroup, inferGroup, integrationViteProject, isArtifact, isBehind, isBlueprint, isCompilerEventHooks, isDenseDataArray, isDependency, isEmitterErrorHandler, isMember, isOverride, isPlan, isPlanManagerEventHooks, isScaffoldError, isSyncReport, isWorkspaceName, manifestToDependencies, manifestToName, member, memberShape, override, overrideShape, ownDataValue, packageManifest, padCell, paritySpecifiers, parseBlueprint, parseBoundedJSON, parseCompilerOptions, parsePlan, parsePlanIds, parsePlanManagerOptions, parseSyncReport, pascalCase, pinPlan, planPayload, planShape, planToReview, planToSummary, policyViteProject, rangeToFreshness, renderArray, renderObject, renderStringArray, renderValue, renderViteTest, rootTsconfig, rootViteConfig, selectHostPaths, serializeTypeScriptString, serviceViteProject, singleSrcViteConfig, snapshotOf, snapshotPlan, sourceArtifacts, splitTableRow, srcTsconfig, srcVariant, srcViteConfig, stableStringify, syncReportShape, syncToReview, testArtifacts, validateBlueprint, validateDependencyArray, validatePlan, viteHeader, viteMachinery, viteProjectDefinitions, viteProjectRegistrations };
|
|
11061
|
+
export { APP_BROWSER_DEV_DEPENDENCIES, APP_DEV_DEPENDENCIES, APP_MATRIX, APP_SERVER_DEV_DEPENDENCIES, BASE_DEV_DEPENDENCIES, BIN_CONFIGS, CATALOG_AGENT_PATH, CATEGORIES, CHECKOUT_ACTION_SHA, COMPILER_ID, COMPILE_STAGES, CONST_KEYWORD, CONTROL_CHARACTER_PATTERN, Compiler, DEFAULT_ENGINES, DEFAULT_VERSION, DEPENDENCY_NAME_PATTERN, ENGINES_PATTERN, ENVIRONMENTS, EXPORT_KEYWORD, EXTRA_NAME_PATTERN, EXTRA_RANGE_PATTERN, FRESHNESS, FUNCTION_KEYWORD, GLOBAL_SETUP_PATH, GROUPS, HEX_PATTERN, HOST_PATHS, IMPORT_KEYWORD, INVALID_PATH_CHARACTER_PATTERN, JSON_PRINT_WIDTH, JSON_TAB_WIDTH, MAX_ARTIFACT_BYTES, MAX_ARTIFACT_HEX_LENGTH, MAX_COLLECTION_ITEMS, MAX_DATA_GRAPH_KEYS, MAX_DATA_GRAPH_NODES, MAX_DEPENDENCY_NAME_LENGTH, MAX_MANIFEST_BYTES, MAX_NAME_LENGTH, MAX_PATH_LENGTH, MAX_RANGE_LENGTH, MAX_SERIALIZED_INPUT_BYTES, MAX_TOTAL_ARTIFACT_BYTES, MINIMUM_NODE_VERSION, NAME_PATTERN, ORCHESTRATION_PATH_NAMES, ORCHESTRATION_PATH_PREFIXES, ORIGINS, ORKESTREL_RANGE_PATTERN, PlanManager, SCAFFOLD_RANGE, SERVICE_SCRIPT_PATH, SETUP_NODE_ACTION_SHA, SHOWCASE_CONFIG_PATH, SOURCE_BROWSER_DEV_DEPENDENCIES, SRC_MATRIX, SYNC_BASELINE_PATTERN, ScaffoldError, TEMPLATES, TYPESCRIPT_EXTENSIONS, VERSION_PATTERN, alignTable, appTsconfig, appViteConfig, applicationArtifacts, applicationViteConfig, applyOverrides, artifactShape, auditToReview, binTsconfig, binViteConfig, binViteProject, blueprint, blueprintShape, blueprintToMembers, blueprintToPlan, bytesToHex, catalogNames, catalogToBlock, ciWorkflow, compareCodeUnit, computeColumnWidth, computeHash, configArtifacts, configViteProject, contentByteLength, contentCodePoint, contentToBytes, contentToHex, coreTsconfig, coreViteConfig, createBlueprint, createCompiler, createPlanManager, delimiterCell, dependency, dependencyShape, devDependenciesFor, diffPlan, dualCondition, entryFields, escapeHtmlText, exportsMap, fillArtifact, findFileConflict, findPathConflict, fitsPrintWidth, formatJson, guideArtifacts, guideMemberTable, guideMethods, guideTests, guideUsage, guidesViteProject, hasApplicationBoundary, hasApplicationShowcase, hasBlueprintEnvironment, hasOnlyDataProperties, hasValidArtifactBytes, hasValidArtifactHex, hasValidAuditBytes, hasValidBlueprintBytes, hasValidOverrideBytes, hasValidPlanBytes, hasValidPlanHex, hasValidSnapshotBytes, hasValidSyncReportBytes, hostGroup, inferGroup, integrationViteProject, isArtifact, isBehind, isBlueprint, isCompilerEventHooks, isDenseDataArray, isDependency, isEmitterErrorHandler, isMember, isOverride, isPlan, isPlanManagerEventHooks, isScaffoldError, isSyncReport, isWorkspaceName, manifestToDependencies, manifestToName, matchesOrchestrationPath, member, memberShape, override, overrideShape, ownDataValue, packageManifest, padCell, paritySpecifiers, parseBlueprint, parseBoundedJSON, parseCompilerOptions, parsePlan, parsePlanIds, parsePlanManagerOptions, parseSyncReport, pascalCase, pinPlan, planPayload, planShape, planToReview, planToSummary, policyViteProject, rangeToFreshness, renderArray, renderObject, renderStringArray, renderValue, renderViteTest, rootTsconfig, rootViteConfig, selectHostPaths, serializeTypeScriptString, serviceViteProject, singleSrcViteConfig, snapshotOf, snapshotPlan, sourceArtifacts, splitTableRow, srcTsconfig, srcVariant, srcViteConfig, stableStringify, syncReportShape, syncToReview, testArtifacts, validateBlueprint, validateDependencyArray, validatePlan, viteHeader, viteMachinery, viteProjectDefinitions, viteProjectRegistrations };
|
|
10725
11062
|
|
|
10726
11063
|
//# sourceMappingURL=index.js.map
|