@orkestrel/scaffold 0.0.55 → 0.0.56
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -6
- package/dist/bin/main.js +2 -2
- package/dist/bin/main.js.map +1 -1
- package/dist/host/agents/orchestration.md +6 -3
- package/dist/host/agents/skills/orkestrel-publish/references/wave.md +28 -2
- package/dist/host/claude/agents/orkestrel.md +6 -2
- package/dist/host/claude/rules/quality.md +1 -0
- package/dist/host/guides/scaffold.md +187 -68
- package/dist/host/manifest.json +7 -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/policy.test.ts +71 -4
- package/dist/src/core/index.cjs +196 -40
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +113 -12
- package/dist/src/core/index.d.ts +113 -12
- package/dist/src/core/index.js +195 -41
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +140 -12
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.d.cts +108 -9
- package/dist/src/server/index.d.ts +108 -9
- package/dist/src/server/index.js +141 -15
- package/dist/src/server/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import { existsSync, readdirSync } from 'node:fs'
|
|
2
|
+
import { join } from 'node:path'
|
|
1
3
|
import { describe, expect, it } from 'vitest'
|
|
2
4
|
import {
|
|
3
5
|
BRIDGE_POLICY_CONTROLS,
|
|
4
6
|
createPolicyScratch,
|
|
7
|
+
createSkillMetadata,
|
|
5
8
|
FUNCTION_SOURCE_FILES,
|
|
6
9
|
GENERIC_POLICY_SOURCES,
|
|
7
10
|
inspectPolicyControl,
|
|
@@ -23,6 +26,8 @@ import {
|
|
|
23
26
|
readPolicyPaths,
|
|
24
27
|
readSkillFamily,
|
|
25
28
|
RULES_POLICY_CONTROLS,
|
|
29
|
+
SKILL_BRIDGE_ROOT,
|
|
30
|
+
SKILL_FAMILY_ROOT,
|
|
26
31
|
SKILL_POLICY_APOSTROPHE,
|
|
27
32
|
SKILL_POLICY_BACKTICKED,
|
|
28
33
|
SKILL_POLICY_CONTROLS,
|
|
@@ -30,6 +35,7 @@ import {
|
|
|
30
35
|
SKILL_POLICY_FENCED,
|
|
31
36
|
SKILL_POLICY_FOLDED,
|
|
32
37
|
SKILL_POLICY_PARAGRAPHS,
|
|
38
|
+
SKILL_POLICY_TEXT,
|
|
33
39
|
stemToPolicyCandidates,
|
|
34
40
|
testToPolicyStem,
|
|
35
41
|
} from './setupPolicy.js'
|
|
@@ -345,10 +351,29 @@ describe('instrument negative controls', () => {
|
|
|
345
351
|
})
|
|
346
352
|
|
|
347
353
|
describe('skill family policy', () => {
|
|
348
|
-
|
|
354
|
+
// The family is read from the workspace it runs in, so a membership literal would
|
|
355
|
+
// bind this file to one workspace. The relationship binds in every workspace: a
|
|
356
|
+
// direct `node:fs` read of the canonical root is a second mechanism that reports
|
|
357
|
+
// the same directories, and reports none where the root is absent.
|
|
358
|
+
//
|
|
359
|
+
// The root is spelled here as literal segments rather than read from
|
|
360
|
+
// `SKILL_FAMILY_ROOT`, and that literal is what makes this read a second
|
|
361
|
+
// mechanism. Both sides reading the constant would move together when it drifts,
|
|
362
|
+
// so the case would stay green for every value the constant ever holds. Against
|
|
363
|
+
// the literal, a drifted constant desyncs the sides and reddens this case in a
|
|
364
|
+
// workspace that has the tree, while a workspace without one still passes on
|
|
365
|
+
// both readings being empty.
|
|
366
|
+
it('discovers exactly the directories the canonical skill root holds', () => {
|
|
367
|
+
const root = join(process.cwd(), '.agents', 'skills')
|
|
368
|
+
const held = existsSync(root)
|
|
369
|
+
? readdirSync(root, { withFileTypes: true })
|
|
370
|
+
.filter((entry) => entry.isDirectory())
|
|
371
|
+
.map((entry) => entry.name)
|
|
372
|
+
.sort()
|
|
373
|
+
: []
|
|
349
374
|
const family = readSkillFamily(process.cwd())
|
|
350
|
-
expect(family.length).
|
|
351
|
-
expect(family).
|
|
375
|
+
expect(family.length > 0).toBe(held.length > 0)
|
|
376
|
+
expect([...family]).toEqual(held)
|
|
352
377
|
})
|
|
353
378
|
|
|
354
379
|
it('requires every discovered skill file, metadata token, and reference', () => {
|
|
@@ -490,10 +515,52 @@ describe('repository policy', () => {
|
|
|
490
515
|
expect(inspectPolicyWorkspace(process.cwd())).toEqual([])
|
|
491
516
|
})
|
|
492
517
|
|
|
518
|
+
// A target reads the canon from the installed package, so its tree carries the
|
|
519
|
+
// pointer pair and no `.agents/` directory, no rule map, and no skill bridges.
|
|
520
|
+
// This vendored suite runs there, and every inspector it routes through has to
|
|
521
|
+
// stay silent on that shape.
|
|
522
|
+
it('accepts a target holding the pointer pair and no canon tree', () => {
|
|
523
|
+
const scratch = createPolicyScratch({ prefix: 'orkestrel-policy-pointer-' })
|
|
524
|
+
try {
|
|
525
|
+
scratch.write(
|
|
526
|
+
'AGENTS.md',
|
|
527
|
+
'# AGENTS.md\n\nRead `node_modules/@orkestrel/scaffold/dist/host/AGENTS.md` for the canon.\n',
|
|
528
|
+
)
|
|
529
|
+
scratch.write(
|
|
530
|
+
'CLAUDE.md',
|
|
531
|
+
'# Claude Code bridge\n\nRead the `AGENTS.md` file beside this one first.\n',
|
|
532
|
+
)
|
|
533
|
+
scratch.write('.claude/settings.json', '{\n\t"permissions": {\n\t\t"allow": []\n\t}\n}\n')
|
|
534
|
+
scratch.write(
|
|
535
|
+
'.claude/agents/orkestrel.md',
|
|
536
|
+
'# Orkestrel\n\nThe agent carrying the package catalog.\n',
|
|
537
|
+
)
|
|
538
|
+
scratch.write(
|
|
539
|
+
'package.json',
|
|
540
|
+
'{\n\t"name": "target",\n\t"private": true,\n\t"scripts": {\n\t\t"test": "vitest run"\n\t}\n}\n',
|
|
541
|
+
)
|
|
542
|
+
expect(inspectPolicyWorkspace(scratch.path)).toEqual([])
|
|
543
|
+
// The control: the same workspace with one canonical skill planted and no
|
|
544
|
+
// bridge beside it reports the twin violation, so the empty result above is a
|
|
545
|
+
// sweep that ran rather than a sweep with nothing it could report.
|
|
546
|
+
scratch.write(`${SKILL_FAMILY_ROOT}/sample/SKILL.md`, SKILL_POLICY_TEXT)
|
|
547
|
+
scratch.write(`${SKILL_FAMILY_ROOT}/sample/agents/openai.yaml`, createSkillMetadata('sample'))
|
|
548
|
+
expect(inspectPolicyWorkspace(scratch.path)).toEqual([
|
|
549
|
+
{
|
|
550
|
+
rule: 'bridge',
|
|
551
|
+
path: `${SKILL_BRIDGE_ROOT}/sample`,
|
|
552
|
+
message: 'canonical skill has a matching provider bridge directory',
|
|
553
|
+
},
|
|
554
|
+
])
|
|
555
|
+
} finally {
|
|
556
|
+
scratch.destroy()
|
|
557
|
+
}
|
|
558
|
+
})
|
|
559
|
+
|
|
493
560
|
it('reaches every branch of the workspace-authored path population', () => {
|
|
494
561
|
const paths = readPolicyPaths(process.cwd())
|
|
495
562
|
expect(paths).toContain('tests/setupPolicy.ts')
|
|
496
|
-
expect(paths).toContain('.claude/
|
|
563
|
+
expect(paths).toContain('.claude/settings.json')
|
|
497
564
|
expect(paths).toContain('package.json')
|
|
498
565
|
expect(paths).toContain('.gitattributes')
|
|
499
566
|
})
|
package/dist/src/core/index.cjs
CHANGED
|
@@ -4,7 +4,7 @@ let _orkestrel_template = require("@orkestrel/template");
|
|
|
4
4
|
let _orkestrel_emitter = require("@orkestrel/emitter");
|
|
5
5
|
var package_default = {
|
|
6
6
|
name: "@orkestrel/scaffold",
|
|
7
|
-
version: "0.0.
|
|
7
|
+
version: "0.0.56",
|
|
8
8
|
description: "Scaffold workspaces with five commands: new, audit, repair, catalog, and overwrite.",
|
|
9
9
|
keywords: [
|
|
10
10
|
"audit",
|
|
@@ -206,36 +206,28 @@ var BIN_CONFIGS = Object.freeze(["configs/src/vite.bin.config.ts", "configs/src/
|
|
|
206
206
|
/** The executable entry whose presence makes a workspace `bin`. */
|
|
207
207
|
var BIN_ENTRY_PATH = "src/bin/main.ts";
|
|
208
208
|
/**
|
|
209
|
-
* The paths
|
|
209
|
+
* The paths a target receives from the vendored data root, frozen.
|
|
210
210
|
*
|
|
211
211
|
* @remarks
|
|
212
|
-
* These are the files the fleet shares verbatim
|
|
213
|
-
*
|
|
214
|
-
*
|
|
215
|
-
*
|
|
216
|
-
* guide mirrors a generated workspace starts from. A directory entry vendors
|
|
212
|
+
* These are the files the fleet shares verbatim and every target holds a copy
|
|
213
|
+
* of: the licence, the harness permission file, the session hook scripts, the
|
|
214
|
+
* shared policy register, the byte-identical root dotfiles, and the guide
|
|
215
|
+
* mirrors a generated workspace starts from. A directory entry vendors
|
|
217
216
|
* everything beneath it.
|
|
218
217
|
*
|
|
219
218
|
* A plan carries the subset its target selects, which is why the list is a
|
|
220
219
|
* candidate set rather than a plan: a workspace never mirrors its own guide.
|
|
220
|
+
*
|
|
221
|
+
* Neither the instruction canon nor the harness wiring is here. A target reads
|
|
222
|
+
* its rules, its skills, its agent roles, its bench configuration, and its MCP
|
|
223
|
+
* registrations from {@link CANON_PATHS} inside the installed package, so no
|
|
224
|
+
* file scaffold leaves in a target names a path the target does not hold.
|
|
225
|
+
* `nameToHostArtifacts` appends {@link CATALOG_AGENT_PATH} to what this list
|
|
226
|
+
* selects, which is what keeps the list itself disjoint from the canon.
|
|
221
227
|
*/
|
|
222
228
|
var HOST_PATHS = Object.freeze([
|
|
223
|
-
"AGENTS.md",
|
|
224
|
-
"CLAUDE.md",
|
|
225
229
|
"LICENSE",
|
|
226
|
-
".agents/orchestration.md",
|
|
227
|
-
".agents/skills",
|
|
228
|
-
".agents/templates",
|
|
229
|
-
".agents/transports",
|
|
230
|
-
".claude/agents",
|
|
231
|
-
".claude/rules",
|
|
232
|
-
".claude/skills",
|
|
233
230
|
".claude/settings.json",
|
|
234
|
-
".codex/agents",
|
|
235
|
-
".codex/config.toml",
|
|
236
|
-
".cursor/mcp.json",
|
|
237
|
-
".cursor/rules",
|
|
238
|
-
".mcp.json",
|
|
239
231
|
"scripts/deps.sh",
|
|
240
232
|
"scripts/cursor.sh",
|
|
241
233
|
"scripts/codex.sh",
|
|
@@ -255,6 +247,53 @@ var HOST_PATHS = Object.freeze([
|
|
|
255
247
|
"guides/guide.md",
|
|
256
248
|
"guides/scaffold.md"
|
|
257
249
|
]);
|
|
250
|
+
/**
|
|
251
|
+
* The instruction-canon paths staged for reading rather than for a target, frozen.
|
|
252
|
+
*
|
|
253
|
+
* @remarks
|
|
254
|
+
* The root instruction documents, the orchestration contract every harness
|
|
255
|
+
* bridge points at, the rule map's rules, the skills, the templates, the
|
|
256
|
+
* transport contracts, the agent roles each harness dispatches, the bench
|
|
257
|
+
* configuration, and the MCP registrations. A directory entry covers everything
|
|
258
|
+
* beneath it.
|
|
259
|
+
*
|
|
260
|
+
* Staging walks these beside {@link HOST_PATHS}, so a release ships them and a
|
|
261
|
+
* reader reaches them two ways: a scaffold checkout sitting beside the
|
|
262
|
+
* repository, or the `node_modules/@orkestrel/scaffold/dist/host/` root inside
|
|
263
|
+
* the installed package. The `AGENTS.md` and `CLAUDE.md` pointers scaffold plans
|
|
264
|
+
* are what name each location.
|
|
265
|
+
*
|
|
266
|
+
* The lists are disjoint by prefix in either direction: no member of either
|
|
267
|
+
* equals or sits beneath a member of the other. Staging depends on that, because
|
|
268
|
+
* the walk covers the union and a path it discovers twice claims one storage
|
|
269
|
+
* name twice, which refuses the stage.
|
|
270
|
+
*
|
|
271
|
+
* The plan claims paths inside the canon deliberately, and each has a reason.
|
|
272
|
+
* `blueprintToDocumentArtifacts` claims `AGENTS.md` and `CLAUDE.md` as this
|
|
273
|
+
* package's own template pointers. `nameToHostArtifacts` claims
|
|
274
|
+
* {@link CATALOG_AGENT_PATH}, because the catalog verb refuses a target that
|
|
275
|
+
* lacks the file and repair restores its absence.
|
|
276
|
+
*
|
|
277
|
+
* A target therefore holds a file at a canon path only where the plan claims it.
|
|
278
|
+
* That is the rule every verb obeys, and it is what makes a copy found anywhere
|
|
279
|
+
* else superseded.
|
|
280
|
+
*/
|
|
281
|
+
var CANON_PATHS = Object.freeze([
|
|
282
|
+
"AGENTS.md",
|
|
283
|
+
"CLAUDE.md",
|
|
284
|
+
".mcp.json",
|
|
285
|
+
".agents/orchestration.md",
|
|
286
|
+
".agents/skills",
|
|
287
|
+
".agents/templates",
|
|
288
|
+
".agents/transports",
|
|
289
|
+
".claude/agents",
|
|
290
|
+
".claude/rules",
|
|
291
|
+
".claude/skills",
|
|
292
|
+
".codex/agents",
|
|
293
|
+
".codex/config.toml",
|
|
294
|
+
".cursor/mcp.json",
|
|
295
|
+
".cursor/rules"
|
|
296
|
+
]);
|
|
258
297
|
/** The repository-relative path where the committed vendored-file inventory is served. */
|
|
259
298
|
var HOST_INVENTORY_PATH = "host.json";
|
|
260
299
|
/**
|
|
@@ -316,9 +355,15 @@ var ORCHESTRATION_PATH_NAMES = Object.freeze([".mcp.json"]);
|
|
|
316
355
|
* The agent file whose marker-bounded package table the catalog verb alone owns.
|
|
317
356
|
*
|
|
318
357
|
* @remarks
|
|
319
|
-
*
|
|
320
|
-
*
|
|
321
|
-
*
|
|
358
|
+
* A plan claims it at a canon path, because the catalog verb refuses a target
|
|
359
|
+
* that lacks the file. `nameToHostArtifacts` appends it to the vendored
|
|
360
|
+
* selection, and it reaches a release through the `.claude/agents` directory in
|
|
361
|
+
* {@link CANON_PATHS} rather than through {@link HOST_PATHS}, which is what
|
|
362
|
+
* keeps the two lists disjoint.
|
|
363
|
+
*
|
|
364
|
+
* It is claimed by presence rather than content, so a consumer's own edits to
|
|
365
|
+
* the file survive every verb and only the catalog verb rewrites the region
|
|
366
|
+
* inside the markers.
|
|
322
367
|
*/
|
|
323
368
|
var CATALOG_AGENT_PATH = ".claude/agents/orkestrel.md";
|
|
324
369
|
/** The provisioner skeleton a workspace with declared service vendors is given once. */
|
|
@@ -2508,7 +2553,8 @@ describe('workspace integration', () => {
|
|
|
2508
2553
|
})
|
|
2509
2554
|
`
|
|
2510
2555
|
}),
|
|
2511
|
-
docs: Object.freeze({
|
|
2556
|
+
docs: Object.freeze({
|
|
2557
|
+
readme: `# {{package}}
|
|
2512
2558
|
|
|
2513
2559
|
{{description}}
|
|
2514
2560
|
|
|
@@ -2518,7 +2564,44 @@ describe('workspace integration', () => {
|
|
|
2518
2564
|
npm install
|
|
2519
2565
|
npm test
|
|
2520
2566
|
\`\`\`
|
|
2521
|
-
|
|
2567
|
+
`,
|
|
2568
|
+
agents: `# AGENTS.md
|
|
2569
|
+
|
|
2570
|
+
The \`@orkestrel/scaffold\` package is this repository's coding and orchestration authority. This
|
|
2571
|
+
file points at it and states no law of its own.
|
|
2572
|
+
|
|
2573
|
+
Read these before working: the \`AGENTS.md\` coding contract, the \`.agents/orchestration.md\`
|
|
2574
|
+
agent-operation contract, every applicable rule the contract's rule map names under
|
|
2575
|
+
\`.claude/rules/\`, and the dispatch-named skill under \`.agents/skills/\` with the references it
|
|
2576
|
+
requires.
|
|
2577
|
+
|
|
2578
|
+
Resolve every one of those paths against scaffold, never against this repository:
|
|
2579
|
+
|
|
2580
|
+
- When a scaffold checkout sits beside this repository, read \`../scaffold/AGENTS.md\`, the
|
|
2581
|
+
\`../scaffold/.agents/orchestration.md\` file, the \`../scaffold/.claude/rules/\` directory, and
|
|
2582
|
+
the \`../scaffold/.agents/skills/\` directory.
|
|
2583
|
+
- Otherwise read the installed copy, whose paths drop the dot that opens each segment: the
|
|
2584
|
+
\`node_modules/@orkestrel/scaffold/dist/host/AGENTS.md\` file, the
|
|
2585
|
+
\`node_modules/@orkestrel/scaffold/dist/host/agents/orchestration.md\` file, the
|
|
2586
|
+
\`node_modules/@orkestrel/scaffold/dist/host/claude/rules/\` directory, and the
|
|
2587
|
+
\`node_modules/@orkestrel/scaffold/dist/host/agents/skills/\` directory.
|
|
2588
|
+
|
|
2589
|
+
Every path a scaffold-supplied file names resolves the same way. The files this repository carries
|
|
2590
|
+
— the \`.claude/agents/orkestrel.md\` catalog file, the \`.claude/settings.json\` permission file,
|
|
2591
|
+
and the bench scripts under \`scripts/\` — are this repository's own copies and resolve here.
|
|
2592
|
+
|
|
2593
|
+
Edit none of the scaffold-owned files here. The \`scaffold repair\` command restores them, so a
|
|
2594
|
+
change to one is a commit in the scaffold repository followed by a release.
|
|
2595
|
+
`,
|
|
2596
|
+
claude: `# CLAUDE.md
|
|
2597
|
+
|
|
2598
|
+
Read the \`AGENTS.md\` file in this repository first. It names the coding and orchestration
|
|
2599
|
+
authority and where to read each contract.
|
|
2600
|
+
|
|
2601
|
+
This file imports nothing. An \`@path\` import inlines the imported file into every context that
|
|
2602
|
+
loads it, which is the cost this pointer removes.
|
|
2603
|
+
`
|
|
2604
|
+
}),
|
|
2522
2605
|
guides: Object.freeze({ readme: `# Guides
|
|
2523
2606
|
|
|
2524
2607
|
## By concept
|
|
@@ -3375,6 +3458,35 @@ function isDeferredPath(path) {
|
|
|
3375
3458
|
return path === ".claude/agents/orkestrel.md" || path.startsWith("guides/") && path.endsWith(".md");
|
|
3376
3459
|
}
|
|
3377
3460
|
/**
|
|
3461
|
+
* Checks whether a path belongs to the instruction canon a target reads rather than holds.
|
|
3462
|
+
*
|
|
3463
|
+
* @param path - The target-relative path to test.
|
|
3464
|
+
* @returns `true` for a {@link CANON_PATHS} member and for any path beneath a
|
|
3465
|
+
* member that is a directory; `false` otherwise.
|
|
3466
|
+
*
|
|
3467
|
+
* @remarks
|
|
3468
|
+
* The one reading of canon membership, so the live overlay and the executable's
|
|
3469
|
+
* fetch list never disagree about what a path is. The match runs to a segment
|
|
3470
|
+
* boundary, so a sibling whose name opens with a member's name —
|
|
3471
|
+
* `.claude/rulesets` beside `.claude/rules` — stays outside.
|
|
3472
|
+
*
|
|
3473
|
+
* Membership answers where a path's bytes are staged, not whether a plan claims
|
|
3474
|
+
* it. A plan claims `AGENTS.md`, `CLAUDE.md`, and {@link CATALOG_AGENT_PATH} at
|
|
3475
|
+
* canon paths deliberately, so a consumer deciding whether to write, restore, or
|
|
3476
|
+
* remove a path reads the plan rather than this predicate.
|
|
3477
|
+
*
|
|
3478
|
+
* @example
|
|
3479
|
+
* ```ts
|
|
3480
|
+
* import { isCanonPath } from '@orkestrel/scaffold'
|
|
3481
|
+
*
|
|
3482
|
+
* isCanonPath('.claude/rules/names.md') // true
|
|
3483
|
+
* isCanonPath('.claude/settings.json') // false
|
|
3484
|
+
* ```
|
|
3485
|
+
*/
|
|
3486
|
+
function isCanonPath(path) {
|
|
3487
|
+
return CANON_PATHS.some((canon) => path === canon || path.startsWith(`${canon}/`));
|
|
3488
|
+
}
|
|
3489
|
+
/**
|
|
3378
3490
|
* Infer the {@link Group} a path belongs to.
|
|
3379
3491
|
*
|
|
3380
3492
|
* @param path - The target-relative path to classify.
|
|
@@ -5137,22 +5249,53 @@ function blueprintToGuideArtifacts(blueprint) {
|
|
|
5137
5249
|
* Compile the generated workspace's root documentation.
|
|
5138
5250
|
*
|
|
5139
5251
|
* @param blueprint - The workspace specification.
|
|
5140
|
-
* @returns
|
|
5252
|
+
* @returns The birth-owned package front page and the content-owned `AGENTS.md`
|
|
5253
|
+
* and `CLAUDE.md` pointers.
|
|
5254
|
+
*
|
|
5255
|
+
* @remarks
|
|
5256
|
+
* The front page is the workspace's own prose, so it is written once and left
|
|
5257
|
+
* alone from then on. The pointers are scaffold's, so they are content-owned and
|
|
5258
|
+
* restored whenever they drift.
|
|
5259
|
+
*
|
|
5260
|
+
* A pointer is planned here rather than vendored because `stageHost` refuses two
|
|
5261
|
+
* vendored paths at one storage name, and `AGENTS.md` and `CLAUDE.md` already
|
|
5262
|
+
* store the canon a release ships. Planning them as this package's own content
|
|
5263
|
+
* leaves each path with one claimant.
|
|
5264
|
+
*
|
|
5265
|
+
* Neither pointer carries a varying span, so neither is filled: a workspace's
|
|
5266
|
+
* name never reaches the text, and the paths a reader follows are the same in
|
|
5267
|
+
* every target.
|
|
5141
5268
|
*/
|
|
5142
5269
|
function blueprintToDocumentArtifacts(blueprint) {
|
|
5143
5270
|
const publishes = blueprint.src.length > 0;
|
|
5144
5271
|
const name = publishes ? `@orkestrel/${blueprint.name}` : blueprint.name;
|
|
5145
5272
|
const description = blueprint.description ?? (publishes ? `The ${name} package.` : `The ${name} application.`);
|
|
5146
|
-
return [
|
|
5147
|
-
|
|
5148
|
-
|
|
5149
|
-
|
|
5150
|
-
|
|
5151
|
-
|
|
5152
|
-
|
|
5153
|
-
|
|
5154
|
-
|
|
5155
|
-
|
|
5273
|
+
return [
|
|
5274
|
+
{
|
|
5275
|
+
path: "README.md",
|
|
5276
|
+
group: "docs",
|
|
5277
|
+
ownership: "birth",
|
|
5278
|
+
origin: "template",
|
|
5279
|
+
content: (0, _orkestrel_template.fillTemplate)(ARTIFACT_TEMPLATES.docs.readme, {
|
|
5280
|
+
package: name,
|
|
5281
|
+
description
|
|
5282
|
+
})
|
|
5283
|
+
},
|
|
5284
|
+
{
|
|
5285
|
+
path: "AGENTS.md",
|
|
5286
|
+
group: "docs",
|
|
5287
|
+
ownership: "content",
|
|
5288
|
+
origin: "template",
|
|
5289
|
+
content: ARTIFACT_TEMPLATES.docs.agents
|
|
5290
|
+
},
|
|
5291
|
+
{
|
|
5292
|
+
path: "CLAUDE.md",
|
|
5293
|
+
group: "docs",
|
|
5294
|
+
ownership: "content",
|
|
5295
|
+
origin: "template",
|
|
5296
|
+
content: ARTIFACT_TEMPLATES.docs.claude
|
|
5297
|
+
}
|
|
5298
|
+
];
|
|
5156
5299
|
}
|
|
5157
5300
|
/**
|
|
5158
5301
|
* Compile the blueprint-dependent orchestration artifacts.
|
|
@@ -5180,7 +5323,8 @@ function blueprintToOrchestrationArtifacts(blueprint) {
|
|
|
5180
5323
|
* Compile the vendored host artifacts a named workspace plans.
|
|
5181
5324
|
*
|
|
5182
5325
|
* @param name - The target workspace's own bare package name.
|
|
5183
|
-
* @returns One artifact per vendored path
|
|
5326
|
+
* @returns One artifact per vendored path in `HOST_PATHS` order, then the
|
|
5327
|
+
* catalog file.
|
|
5184
5328
|
*
|
|
5185
5329
|
* @remarks
|
|
5186
5330
|
* Every artifact is claimed by presence, which is the strongest claim a pure
|
|
@@ -5194,16 +5338,26 @@ function blueprintToOrchestrationArtifacts(blueprint) {
|
|
|
5194
5338
|
* are classified by one rule and a plan never disagrees with the audit beside
|
|
5195
5339
|
* it.
|
|
5196
5340
|
*
|
|
5341
|
+
* {@link CATALOG_AGENT_PATH} is appended rather than listed, and it is the canon
|
|
5342
|
+
* path this compiler claims. The catalog verb refuses a target that lacks the
|
|
5343
|
+
* file, so the plan has to carry it; repair restores its absence from the
|
|
5344
|
+
* staged bytes; and the `.claude/agents` directory in `CANON_PATHS` is what
|
|
5345
|
+
* stages those bytes, so listing the file in `HOST_PATHS` as well would claim one
|
|
5346
|
+
* storage name twice and refuse the stage. The rest of the canon a target reads
|
|
5347
|
+
* from the installed package, at the locations the `AGENTS.md` and `CLAUDE.md`
|
|
5348
|
+
* pointers {@link blueprintToDocumentArtifacts} emits name.
|
|
5349
|
+
*
|
|
5197
5350
|
* @example
|
|
5198
5351
|
* ```ts
|
|
5199
5352
|
* import { nameToHostArtifacts } from '@orkestrel/scaffold'
|
|
5200
5353
|
*
|
|
5201
|
-
* nameToHostArtifacts('router').some((artifact) => artifact.path === '
|
|
5354
|
+
* nameToHostArtifacts('router').some((artifact) => artifact.path === '.claude/settings.json') // true
|
|
5355
|
+
* nameToHostArtifacts('router').some((artifact) => artifact.path === '.claude/agents/orkestrel.md') // true
|
|
5202
5356
|
* nameToHostArtifacts('router').some((artifact) => artifact.path === 'guides/router.md') // false
|
|
5203
5357
|
* ```
|
|
5204
5358
|
*/
|
|
5205
5359
|
function nameToHostArtifacts(name) {
|
|
5206
|
-
return selectHostPaths(HOST_PATHS, name).map((path) => ({
|
|
5360
|
+
return [...selectHostPaths(HOST_PATHS, name), CATALOG_AGENT_PATH].map((path) => ({
|
|
5207
5361
|
path,
|
|
5208
5362
|
group: inferGroup(path),
|
|
5209
5363
|
ownership: "presence",
|
|
@@ -6535,6 +6689,7 @@ exports.ARTIFACT_TEMPLATES = ARTIFACT_TEMPLATES;
|
|
|
6535
6689
|
exports.BASE_DEV_DEPENDENCIES = BASE_DEV_DEPENDENCIES;
|
|
6536
6690
|
exports.BIN_CONFIGS = BIN_CONFIGS;
|
|
6537
6691
|
exports.BIN_ENTRY_PATH = BIN_ENTRY_PATH;
|
|
6692
|
+
exports.CANON_PATHS = CANON_PATHS;
|
|
6538
6693
|
exports.CATALOG_AGENT_PATH = CATALOG_AGENT_PATH;
|
|
6539
6694
|
exports.CONFIG_TEMPLATES = CONFIG_TEMPLATES;
|
|
6540
6695
|
exports.CONFORMANCE_TEST_PATH = CONFORMANCE_TEST_PATH;
|
|
@@ -6625,6 +6780,7 @@ exports.inferGroup = inferGroup;
|
|
|
6625
6780
|
exports.isArtifact = isArtifact;
|
|
6626
6781
|
exports.isAudit = isAudit;
|
|
6627
6782
|
exports.isBlueprint = isBlueprint;
|
|
6783
|
+
exports.isCanonPath = isCanonPath;
|
|
6628
6784
|
exports.isCatalogEntry = isCatalogEntry;
|
|
6629
6785
|
exports.isCollection = isCollection;
|
|
6630
6786
|
exports.isCompilerHooks = isCompilerHooks;
|