@orkestrel/scaffold 0.0.40 → 0.0.42
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 +8 -1
- package/dist/bin/main.js.map +1 -1
- package/dist/host/AGENTS.md +2 -2
- package/dist/host/agents/skills/enterprise-bootstrap/references/bootstrap-reference.md +16 -16
- package/dist/host/agents/skills/enterprise-bootstrap/references/components.md +3 -3
- package/dist/host/agents/skills/orkestrel-align-packages/references/integration.md +1 -1
- package/dist/host/agents/skills/orkestrel-build-application/SKILL.md +7 -2
- package/dist/host/claude/agents/builder.md +2 -2
- package/dist/host/claude/agents/orkestrel.md +48 -48
- package/dist/host/claude/rules/application.md +6 -4
- package/dist/host/claude/rules/architecture.md +2 -0
- package/dist/host/claude/rules/documentation.md +6 -0
- package/dist/host/claude/rules/tests.md +11 -1
- package/dist/host/claude/rules/typescript.md +15 -1
- package/dist/host/claude/rules/workspace.md +43 -13
- package/dist/host/claude/rules/writing.md +125 -0
- package/dist/host/claude/skills/enterprise-bootstrap/SKILL.md +10 -1
- package/dist/host/claude/skills/orkestrel-align-packages/SKILL.md +1 -1
- package/dist/host/claude/skills/orkestrel-build-application/SKILL.md +1 -1
- package/dist/host/claude/skills/orkestrel-harden-package/SKILL.md +1 -1
- package/dist/host/configs/policy.ts +185 -0
- package/dist/host/dotfiles/oxlintrc.json +13 -1
- package/dist/host/dotfiles/prettierignore +3 -0
- package/dist/host/guides/scaffold.md +23 -10
- package/dist/host/manifest.json +11 -7
- package/dist/host/scripts/codex.sh +0 -0
- package/dist/host/scripts/cursor.sh +0 -0
- package/dist/host/scripts/deps.sh +0 -0
- package/dist/host/scripts/ollama.sh +0 -0
- package/dist/host/tests/config.test.ts +217 -4
- package/dist/host/tests/policy.test.ts +82 -0
- package/dist/host/tests/setupPolicy.ts +863 -21
- package/dist/src/core/index.cjs +97 -22
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +45 -29
- package/dist/src/core/index.d.ts +45 -29
- package/dist/src/core/index.js +96 -22
- package/dist/src/core/index.js.map +1 -1
- package/package.json +7 -7
- package/dist/host/agents/skills/orkestrel-build-application/references/application.md +0 -129
package/dist/src/core/index.cjs
CHANGED
|
@@ -129,6 +129,7 @@ var HOST_PATHS = Object.freeze([
|
|
|
129
129
|
"tests/policy.test.ts",
|
|
130
130
|
"tests/config.test.ts",
|
|
131
131
|
"configs/helpers.ts",
|
|
132
|
+
"configs/policy.ts",
|
|
132
133
|
".editorconfig",
|
|
133
134
|
".gitattributes",
|
|
134
135
|
".gitignore",
|
|
@@ -234,16 +235,16 @@ var NAME_PATTERN = /^[a-z][a-z0-9-]*$/;
|
|
|
234
235
|
*/
|
|
235
236
|
var DEPENDENCY_NAME_PATTERN = /^@orkestrel\/[a-z][a-z0-9-]*$/;
|
|
236
237
|
/**
|
|
237
|
-
* The
|
|
238
|
+
* The package name syntax for a dependency this package does not publish.
|
|
238
239
|
*
|
|
239
240
|
* @remarks
|
|
240
|
-
*
|
|
241
|
-
*
|
|
242
|
-
*
|
|
243
|
-
*
|
|
244
|
-
*
|
|
241
|
+
* A foreign package is one this package does not publish, so its name reaches
|
|
242
|
+
* no path. It may carry any scope or no scope at all. Each name segment begins
|
|
243
|
+
* with an alphanumeric character after an optional leading `@`, and the name
|
|
244
|
+
* carries at most one `/`. No segment can therefore be `..`, and no backslash
|
|
245
|
+
* is admitted, so the shape cannot express a traversal.
|
|
245
246
|
*/
|
|
246
|
-
var
|
|
247
|
+
var FOREIGN_NAME_PATTERN = /^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/;
|
|
247
248
|
/** The exact three-component version syntax a blueprint declares. */
|
|
248
249
|
var VERSION_PATTERN = /^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)$/;
|
|
249
250
|
/**
|
|
@@ -258,6 +259,15 @@ var VERSION_PATTERN = /^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)$/;
|
|
|
258
259
|
var ORKESTREL_RANGE_PATTERN = /^\^0\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)$/;
|
|
259
260
|
/** The registry-only semver subset accepted for a development extra's range. */
|
|
260
261
|
var EXTRA_RANGE_PATTERN = /^(?:\^|~)?(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*))*)?$/;
|
|
262
|
+
/**
|
|
263
|
+
* The exact three-component floor accepted for a foreign peer's range.
|
|
264
|
+
*
|
|
265
|
+
* @remarks
|
|
266
|
+
* This is independent from {@link ENGINES_PATTERN}. An engine floors the Node
|
|
267
|
+
* runtime a workspace supports, while a peer floors a tool the consumer
|
|
268
|
+
* supplies. Either obligation may change without changing the other.
|
|
269
|
+
*/
|
|
270
|
+
var FLOOR_RANGE_PATTERN = /^>=(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)$/;
|
|
261
271
|
/** The minimum-Node engine syntax a blueprint declares. */
|
|
262
272
|
var ENGINES_PATTERN = /^>=(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)$/;
|
|
263
273
|
/** Exact lowercase hexadecimal bytes: two digits per byte, and empty content is valid. */
|
|
@@ -305,7 +315,7 @@ var DEFAULT_ENGINES = `>=${MINIMUM_NODE_VERSION}`;
|
|
|
305
315
|
/** The tooling versions scaffold and every generated workspace share. */
|
|
306
316
|
var BASE_DEV_DEPENDENCIES = Object.freeze({
|
|
307
317
|
"@orkestrel/guide": "^0.0.12",
|
|
308
|
-
"@orkestrel/scaffold": "^0.0.
|
|
318
|
+
"@orkestrel/scaffold": "^0.0.41",
|
|
309
319
|
"@orkestrel/test": "^0.0.6",
|
|
310
320
|
"@types/node": "^26.2.0",
|
|
311
321
|
oxfmt: "^0.62.0",
|
|
@@ -405,6 +415,7 @@ var CONFIG_TEMPLATES = Object.freeze({
|
|
|
405
415
|
`,
|
|
406
416
|
vite: `import type { {{viteTypes}} } from 'vite'
|
|
407
417
|
{{imports}}import { defineConfig, mergeConfig } from 'vitest/config'
|
|
418
|
+
import manifest from './package.json' with { type: 'json' }
|
|
408
419
|
import tsconfig from './tsconfig.json' with { type: 'json' }
|
|
409
420
|
{{helpers}}{{browsers}}import { fileURLToPath, URL } from 'node:url'
|
|
410
421
|
|
|
@@ -412,6 +423,18 @@ import tsconfig from './tsconfig.json' with { type: 'json' }
|
|
|
412
423
|
return fileURLToPath(new URL(relativePath, import.meta.url))
|
|
413
424
|
}
|
|
414
425
|
|
|
426
|
+
const peerDependencies = 'peerDependencies' in manifest ? manifest.peerDependencies : undefined
|
|
427
|
+
if (
|
|
428
|
+
peerDependencies !== undefined &&
|
|
429
|
+
(typeof peerDependencies !== 'object' ||
|
|
430
|
+
peerDependencies === null ||
|
|
431
|
+
Array.isArray(peerDependencies))
|
|
432
|
+
) {
|
|
433
|
+
throw new Error('package peerDependencies must be an object')
|
|
434
|
+
}
|
|
435
|
+
export const peers: readonly string[] =
|
|
436
|
+
peerDependencies === undefined ? [] : Object.keys(peerDependencies)
|
|
437
|
+
|
|
415
438
|
const resolve = {
|
|
416
439
|
alias: Object.entries(tsconfig.compilerOptions.paths).reduce((aliases, [key, values]) => {
|
|
417
440
|
const [path] = values
|
|
@@ -539,7 +562,13 @@ const resolve = {
|
|
|
539
562
|
},
|
|
540
563
|
outDir: 'dist/bin',
|
|
541
564
|
target: 'node22',
|
|
542
|
-
rolldownOptions: {
|
|
565
|
+
rolldownOptions: {
|
|
566
|
+
external: (id: string) =>
|
|
567
|
+
id.startsWith('node:') ||
|
|
568
|
+
id.startsWith('@orkestrel/') ||
|
|
569
|
+
id.startsWith('@src/') ||
|
|
570
|
+
peers.some((peer) => id === peer || id.startsWith(peer + '/')),
|
|
571
|
+
},
|
|
543
572
|
},
|
|
544
573
|
test: {
|
|
545
574
|
name: { label: 'src:bin', color: 'yellow' },
|
|
@@ -660,6 +689,24 @@ export function appBrowser(): UserConfig {
|
|
|
660
689
|
setupFiles: ['./tests/setup.ts'],
|
|
661
690
|
environment: 'node',
|
|
662
691
|
browser: { enabled: false },
|
|
692
|
+
// A config test validates every target wrapper and runs the real linter twice with
|
|
693
|
+
// 15-second child caps, so this budget clears both caps and reports their diagnostics.
|
|
694
|
+
testTimeout: 45_000,
|
|
695
|
+
},
|
|
696
|
+
},
|
|
697
|
+
options ?? {},
|
|
698
|
+
)
|
|
699
|
+
`,
|
|
700
|
+
setup: `export const setup = (options?: UserConfig): UserConfig =>
|
|
701
|
+
mergeConfig(
|
|
702
|
+
{
|
|
703
|
+
resolve,
|
|
704
|
+
test: {
|
|
705
|
+
name: { label: 'setup', color: 'white' },
|
|
706
|
+
include: ['tests/setup*.test.ts'],
|
|
707
|
+
setupFiles: ['./tests/setup.ts'],
|
|
708
|
+
environment: 'node',
|
|
709
|
+
browser: { enabled: false },
|
|
663
710
|
},
|
|
664
711
|
},
|
|
665
712
|
options ?? {},
|
|
@@ -895,7 +942,7 @@ export const probe = (options?: UserConfig): UserConfig =>
|
|
|
895
942
|
core: `import { defineConfig } from 'vite'
|
|
896
943
|
import dts from 'vite-plugin-dts'
|
|
897
944
|
import { environmentBoundary, outputBoundary } from '../helpers.js'
|
|
898
|
-
import { srcCore, resolveWorkspacePath } from '../../vite.config.ts'
|
|
945
|
+
import { peers, srcCore, resolveWorkspacePath } from '../../vite.config.ts'
|
|
899
946
|
|
|
900
947
|
export default defineConfig(
|
|
901
948
|
srcCore({
|
|
@@ -923,7 +970,12 @@ export default defineConfig(
|
|
|
923
970
|
fileName: (format) => (format === 'es' ? 'index.js' : 'index.cjs'),
|
|
924
971
|
},
|
|
925
972
|
outDir: 'dist/src/core',
|
|
926
|
-
rolldownOptions: {
|
|
973
|
+
rolldownOptions: {
|
|
974
|
+
external: (id: string) =>
|
|
975
|
+
id.startsWith('node:') ||
|
|
976
|
+
id.startsWith('@orkestrel/') ||
|
|
977
|
+
peers.some((peer) => id === peer || id.startsWith(peer + '/')),
|
|
978
|
+
},
|
|
927
979
|
},
|
|
928
980
|
}),
|
|
929
981
|
)
|
|
@@ -1716,6 +1768,7 @@ var isBlueprint = (0, _orkestrel_contract.recordOf)({
|
|
|
1716
1768
|
engines: _orkestrel_contract.isString,
|
|
1717
1769
|
overrides: (0, _orkestrel_contract.andOf)(isCollection, (0, _orkestrel_contract.arrayOf)(isOverride)),
|
|
1718
1770
|
bin: _orkestrel_contract.isBoolean,
|
|
1771
|
+
setup: _orkestrel_contract.isBoolean,
|
|
1719
1772
|
guides: _orkestrel_contract.isBoolean,
|
|
1720
1773
|
distribution: _orkestrel_contract.isBoolean,
|
|
1721
1774
|
integration: _orkestrel_contract.isBoolean,
|
|
@@ -2973,7 +3026,10 @@ function srcToExports(src) {
|
|
|
2973
3026
|
* each declared axis adds the set its host needs. A declared extra or peer is
|
|
2974
3027
|
* applied after those, so a workspace that pins a range for a package the
|
|
2975
3028
|
* conditional sets also name gets the range it declared. An extra that restates
|
|
2976
|
-
* a shared toolchain pin never reaches here, because the gate refuses it.
|
|
3029
|
+
* a shared toolchain pin never reaches here, because the gate refuses it. A peer
|
|
3030
|
+
* that names a development tool already selected keeps that tool's pin, because
|
|
3031
|
+
* the peer's floor states what consumers may supply rather than what this workspace
|
|
3032
|
+
* develops against.
|
|
2977
3033
|
*
|
|
2978
3034
|
* A peer is declared here as well as under `peerDependencies`, because a peer is
|
|
2979
3035
|
* not installed by the workspace that declares it and developing against one
|
|
@@ -3006,7 +3062,7 @@ function blueprintToDevDependencies(blueprint) {
|
|
|
3006
3062
|
...blueprint.app.includes("server") ? APP_SERVER_DEV_DEPENDENCIES : {}
|
|
3007
3063
|
};
|
|
3008
3064
|
for (const extra of blueprint.extras) merged[extra.name] = extra.range;
|
|
3009
|
-
for (const peer of blueprint.peers) merged[peer.name] = peer.range;
|
|
3065
|
+
for (const peer of blueprint.peers) if (!Object.hasOwn(merged, peer.name)) merged[peer.name] = peer.range;
|
|
3010
3066
|
const own = blueprint.src.length > 0 ? `@orkestrel/${blueprint.name}` : blueprint.name;
|
|
3011
3067
|
const runtime = new Set(blueprint.dependencies.map((dependency) => dependency.name));
|
|
3012
3068
|
return Object.fromEntries(Object.entries(merged).filter(([name]) => name !== own && !runtime.has(name)).sort(([left], [right]) => (0, _orkestrel_contract.compareValues)(left, right)));
|
|
@@ -3079,6 +3135,7 @@ function blueprintToScripts(blueprint) {
|
|
|
3079
3135
|
...blueprint.app.length > 0 ? ["npm run test:app"] : [],
|
|
3080
3136
|
"npm run test:policy",
|
|
3081
3137
|
"npm run test:config",
|
|
3138
|
+
...blueprint.setup ? ["npm run test:setup"] : [],
|
|
3082
3139
|
...blueprint.guides ? ["npm run test:guides"] : [],
|
|
3083
3140
|
...blueprint.conformance ? ["npm run test:conformance"] : [],
|
|
3084
3141
|
...integrates ? ["npm run test:integration"] : [],
|
|
@@ -3099,6 +3156,7 @@ function blueprintToScripts(blueprint) {
|
|
|
3099
3156
|
}
|
|
3100
3157
|
scripts["test:policy"] = `${vitest} --project policy`;
|
|
3101
3158
|
scripts["test:config"] = `${vitest} --project config`;
|
|
3159
|
+
if (blueprint.setup) scripts["test:setup"] = `${vitest} --project setup`;
|
|
3102
3160
|
if (blueprint.guides) scripts["test:guides"] = `${vitest} --project guides`;
|
|
3103
3161
|
if (blueprint.conformance) scripts["test:conformance"] = `${vitest} --project conformance`;
|
|
3104
3162
|
scripts["test:probe"] = "vitest run --config vite.config.ts --no-cache --reporter=verbose --project probe";
|
|
@@ -3322,7 +3380,12 @@ function blueprintToRootVite(blueprint) {
|
|
|
3322
3380
|
if (blueprint.src.includes("browser")) {
|
|
3323
3381
|
const core = blueprint.src.includes("core");
|
|
3324
3382
|
factories.push((0, _orkestrel_template.fillTemplate)(CONFIG_TEMPLATES.factories.src.browser, {
|
|
3325
|
-
external: core ?
|
|
3383
|
+
external: core ? `external: (id: string) =>
|
|
3384
|
+
id === '@src/core' ||
|
|
3385
|
+
id.startsWith('@orkestrel/') ||
|
|
3386
|
+
peers.some((peer) => id === peer || id.startsWith(peer + '/')),` : `external: (id: string) =>
|
|
3387
|
+
id.startsWith('@orkestrel/') ||
|
|
3388
|
+
peers.some((peer) => id === peer || id.startsWith(peer + '/')),`,
|
|
3326
3389
|
output: core ? " output: { paths: { '@src/core': '../core/index.js' } }," : " output: {},",
|
|
3327
3390
|
exclude: core ? " exclude: ['tests/src/core/**/*.test.ts'],\n" : "",
|
|
3328
3391
|
global: blueprint.global ? " globalSetup: ['./tests/setupGlobal.ts'],\n" : ""
|
|
@@ -3333,7 +3396,13 @@ function blueprintToRootVite(blueprint) {
|
|
|
3333
3396
|
const core = blueprint.src.includes("core");
|
|
3334
3397
|
factories.push((0, _orkestrel_template.fillTemplate)(CONFIG_TEMPLATES.factories.src.server, {
|
|
3335
3398
|
external: core ? `external: (id: string) =>
|
|
3336
|
-
id === '@src/core' ||
|
|
3399
|
+
id === '@src/core' ||
|
|
3400
|
+
id.startsWith('node:') ||
|
|
3401
|
+
id.startsWith('@orkestrel/') ||
|
|
3402
|
+
peers.some((peer) => id === peer || id.startsWith(peer + '/')),` : `external: (id: string) =>
|
|
3403
|
+
id.startsWith('node:') ||
|
|
3404
|
+
id.startsWith('@orkestrel/') ||
|
|
3405
|
+
peers.some((peer) => id === peer || id.startsWith(peer + '/')),`,
|
|
3337
3406
|
output: core ? `\t\t\t\t\toutput: [
|
|
3338
3407
|
{
|
|
3339
3408
|
format: 'es',
|
|
@@ -3420,6 +3489,10 @@ export function appShowcase(): UserConfig {
|
|
|
3420
3489
|
projects.push("policy");
|
|
3421
3490
|
factories.push(CONFIG_TEMPLATES.factories.config);
|
|
3422
3491
|
projects.push("config");
|
|
3492
|
+
if (blueprint.setup) {
|
|
3493
|
+
factories.push(CONFIG_TEMPLATES.factories.setup);
|
|
3494
|
+
projects.push("setup");
|
|
3495
|
+
}
|
|
3423
3496
|
if (blueprint.guides) {
|
|
3424
3497
|
factories.push(CONFIG_TEMPLATES.factories.guides);
|
|
3425
3498
|
projects.push("guides");
|
|
@@ -4078,11 +4151,11 @@ function planToFindings(plan, current) {
|
|
|
4078
4151
|
* range, in list order.
|
|
4079
4152
|
*
|
|
4080
4153
|
* @remarks
|
|
4081
|
-
* The
|
|
4082
|
-
* rules live here once and each caller supplies its own patterns.
|
|
4083
|
-
* dependency name reaches a path through its guide mirror and is
|
|
4084
|
-
* `@orkestrel` scope
|
|
4085
|
-
* valid npm name.
|
|
4154
|
+
* The declared lists and peer partitions differ only in the two syntaxes they
|
|
4155
|
+
* accept, so the rules live here once and each caller supplies its own patterns.
|
|
4156
|
+
* A runtime dependency name reaches a path through its guide mirror and is
|
|
4157
|
+
* fixed to the `@orkestrel` scope. A foreign peer or development extra reaches
|
|
4158
|
+
* no path and admits any valid npm name.
|
|
4086
4159
|
*
|
|
4087
4160
|
* Both patterns must be stateless. A global or sticky pattern carries a
|
|
4088
4161
|
* `lastIndex` between calls, so it would answer differently for the same input
|
|
@@ -4240,7 +4313,7 @@ function blueprintToQuestions(blueprint) {
|
|
|
4240
4313
|
message: "showcase projects a browser app, and this workspace declares none, so it emits nothing.",
|
|
4241
4314
|
blocking: false
|
|
4242
4315
|
});
|
|
4243
|
-
questions.push(...dependenciesToQuestions(blueprint.dependencies, "dependencies", DEPENDENCY_NAME_PATTERN, ORKESTREL_RANGE_PATTERN), ...dependenciesToQuestions(blueprint.peers, "peers", DEPENDENCY_NAME_PATTERN, ORKESTREL_RANGE_PATTERN), ...dependenciesToQuestions(blueprint.extras, "extras",
|
|
4316
|
+
questions.push(...dependenciesToQuestions(blueprint.dependencies, "dependencies", DEPENDENCY_NAME_PATTERN, ORKESTREL_RANGE_PATTERN), ...dependenciesToQuestions(blueprint.peers.filter((peer) => peer.name.startsWith("@orkestrel/")), "peers", DEPENDENCY_NAME_PATTERN, ORKESTREL_RANGE_PATTERN), ...dependenciesToQuestions(blueprint.peers.filter((peer) => !peer.name.startsWith("@orkestrel/")), "peers", FOREIGN_NAME_PATTERN, FLOOR_RANGE_PATTERN), ...dependenciesToQuestions(blueprint.extras, "extras", FOREIGN_NAME_PATTERN, EXTRA_RANGE_PATTERN));
|
|
4244
4317
|
const lists = [
|
|
4245
4318
|
["dependencies", blueprint.dependencies],
|
|
4246
4319
|
["peers", blueprint.peers],
|
|
@@ -4742,6 +4815,7 @@ function createBlueprint(name, input) {
|
|
|
4742
4815
|
engines: input?.engines ?? DEFAULT_ENGINES,
|
|
4743
4816
|
overrides: input?.overrides ?? [],
|
|
4744
4817
|
bin: input?.bin ?? false,
|
|
4818
|
+
setup: input?.setup ?? false,
|
|
4745
4819
|
guides: input?.guides ?? false,
|
|
4746
4820
|
distribution: input?.distribution ?? false,
|
|
4747
4821
|
integration: input?.integration ?? false,
|
|
@@ -4795,8 +4869,9 @@ exports.DISTRIBUTION_TEST_PATH = DISTRIBUTION_TEST_PATH;
|
|
|
4795
4869
|
exports.ENGINES_PATTERN = ENGINES_PATTERN;
|
|
4796
4870
|
exports.ENVIRONMENTS = ENVIRONMENTS;
|
|
4797
4871
|
exports.EXECUTABLE_PATHS = EXECUTABLE_PATHS;
|
|
4798
|
-
exports.EXTRA_NAME_PATTERN = EXTRA_NAME_PATTERN;
|
|
4799
4872
|
exports.EXTRA_RANGE_PATTERN = EXTRA_RANGE_PATTERN;
|
|
4873
|
+
exports.FLOOR_RANGE_PATTERN = FLOOR_RANGE_PATTERN;
|
|
4874
|
+
exports.FOREIGN_NAME_PATTERN = FOREIGN_NAME_PATTERN;
|
|
4800
4875
|
exports.GLOBAL_SETUP_PATH = GLOBAL_SETUP_PATH;
|
|
4801
4876
|
exports.GROUPS = GROUPS;
|
|
4802
4877
|
exports.GUIDES_TEST_PATH = GUIDES_TEST_PATH;
|