@orkestrel/scaffold 0.0.96 → 0.0.98

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.
Files changed (40) hide show
  1. package/dist/agents/skills/orkestrel-dispatch/scripts/bench.js +1 -1
  2. package/dist/bin/main.js +4 -4
  3. package/dist/bin/main.js.map +1 -1
  4. package/dist/host/agents/orchestration.md +29 -26
  5. package/dist/host/agents/skills/orkestrel-dispatch/scripts/bench.ts +1 -1
  6. package/dist/host/agents/skills/orkestrel-publish/references/wave.md +1 -2
  7. package/dist/host/agents/transports/claude-cli.md +1 -1
  8. package/dist/host/agents/transports/cursor.md +4 -4
  9. package/dist/host/claude/AGENTS.md +10 -7
  10. package/dist/host/claude/agents/analyst.md +4 -4
  11. package/dist/host/claude/agents/astra.md +4 -4
  12. package/dist/host/claude/agents/builder.md +4 -4
  13. package/dist/host/claude/agents/checker.md +4 -4
  14. package/dist/host/claude/agents/distiller.md +4 -4
  15. package/dist/host/claude/agents/grok.md +4 -4
  16. package/dist/host/claude/agents/opus.md +1 -1
  17. package/dist/host/claude/agents/orkestrel.md +24 -24
  18. package/dist/host/claude/agents/planner.md +1 -1
  19. package/dist/host/claude/agents/researcher.md +4 -4
  20. package/dist/host/claude/agents/reviewer.md +1 -1
  21. package/dist/host/claude/agents/scout.md +4 -4
  22. package/dist/host/claude/agents/verifier.md +4 -4
  23. package/dist/host/claude/rules/styles.md +2 -1
  24. package/dist/host/claude/settings.json +5 -2
  25. package/dist/host/codex/agents/builder.toml +6 -6
  26. package/dist/host/guides/scaffold.md +9 -3
  27. package/dist/host/manifest.json +36 -24
  28. package/dist/host/scripts/browsers.sh +54 -0
  29. package/dist/host/scripts/codex.sh +0 -0
  30. package/dist/host/scripts/cursor.sh +0 -0
  31. package/dist/host/scripts/deps.sh +0 -0
  32. package/dist/host/scripts/npm.sh +111 -0
  33. package/dist/host/scripts/ollama.sh +0 -0
  34. package/dist/src/core/index.cjs +39 -11
  35. package/dist/src/core/index.cjs.map +1 -1
  36. package/dist/src/core/index.d.cts +20 -0
  37. package/dist/src/core/index.d.ts +20 -0
  38. package/dist/src/core/index.js +39 -12
  39. package/dist/src/core/index.js.map +1 -1
  40. package/package.json +4 -4
@@ -1,6 +1,9 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/claude-code-settings.json",
3
3
  "enableAllProjectMcpServers": true,
4
+ "env": {
5
+ "CLAUDE_CODE_SUBAGENT_MODEL": "sonnet"
6
+ },
4
7
  "permissions": {
5
8
  "defaultMode": "bypassPermissions",
6
9
  "allow": [
@@ -969,8 +972,8 @@
969
972
  "hooks": [
970
973
  {
971
974
  "type": "command",
972
- "command": "\"$CLAUDE_PROJECT_DIR\"/scripts/deps.sh",
973
- "timeout": 600
975
+ "command": "\"$CLAUDE_PROJECT_DIR\"/scripts/npm.sh && \"$CLAUDE_PROJECT_DIR\"/scripts/deps.sh && \"$CLAUDE_PROJECT_DIR\"/scripts/browsers.sh",
976
+ "timeout": 900
974
977
  },
975
978
  {
976
979
  "type": "command",
@@ -1,19 +1,19 @@
1
1
  name = "builder"
2
- description = "Sol executor for one small, fully specified, taste-free unit in src, app, tests, or configs; writes only owned files as the sole writer in its checkout and validates scoped to them."
2
+ description = "Sol executor for one bounded unit with a closed shape in src, app, tests, or configs; writes only owned files as the sole writer in its checkout and validates scoped to them."
3
3
  model = "gpt-6-sol"
4
4
  model_reasoning_effort = "low"
5
5
  sandbox_mode = "workspace-write"
6
6
  developer_instructions = """
7
- Implement one fully specified unit. The dispatch is the plan; do not re-plan.
7
+ Implement one bounded unit with a closed shape. The dispatch is the plan; do not re-plan.
8
8
 
9
9
  Read the brief, the .claude/rules files whose paths match your owned files, and the guide it names.
10
10
  Write only the owned files; return an exact patch for a shared file. Follow AGENTS.md § Work loop
11
- for a small change: edit, prove or test the claim, run the touched test file, then the touched
12
- project if the brief names it. Validate read-only and scoped: a non-fix lint on your paths, the
11
+ at the size the brief names: edit, prove or test the claim, run the touched test file, then the
12
+ touched project when the brief names it. Validate read-only and scoped: a non-fix lint on your paths, the
13
13
  scoped check: script, the touched tests; never run format, lint --fix, build, or the whole suite. Delete any probe you wrote before returning.
14
14
 
15
- A unit whose naming, API shape, or architecture is still open belongs to astra or opus: stop and
16
- say so. Never install, commit, push, read a secret, or run a destructive command. Stop and report
15
+ A unit that leaves naming, API shape, or architecture open, or that spans packages, belongs to
16
+ astra or opus: stop and say so. Never install, commit, push, read a secret, or run a destructive command. Stop and report
17
17
  per .agents/orchestration.md § Deviation protocol on any conflict with the brief.
18
18
 
19
19
  Return changed files with one line each, the scoped commands run and their results, shared-file
@@ -299,6 +299,7 @@ Exported from `@orkestrel/scaffold`, and reachable from
299
299
  | `blueprintToQuestions` | function | Measures a blueprint against every law its own fields decide. |
300
300
  | `blueprintToRootTsconfig` | function | Compiles the root TypeScript configuration for a blueprint. |
301
301
  | `blueprintToProjects` | function | Projects a blueprint into the project labels its root Vitest configuration registers. |
302
+ | `blueprintToOptimizedDependencies` | function | Compiles the browser projects' pre-bundled dependency list for a blueprint. |
302
303
  | `blueprintToRootVite` | function | Compiles the root Vite and Vitest configuration for a blueprint. |
303
304
  | `blueprintToScripts` | function | Projects a blueprint into the scripts its manifest declares. |
304
305
  | `blueprintToSheets` | function | Projects a blueprint into its validated sheet-face names in stable order. |
@@ -1859,8 +1860,11 @@ lists name.
1859
1860
  licence, the harness permission file, the scaffold-owned `scripts` directory, the
1860
1861
  shared policy register, the shared policy proof, the shared policy plugin, the shared configuration
1861
1862
  leaf and its proof, and the byte-identical root dotfiles. The session-start hooks inside `scripts`
1862
- split by job. The bench probe reports whether a bench CLI resolves, and the dependency hook installs
1863
- the lockfile's closure in a remote session.
1863
+ split by job. The bench probe reports whether a bench CLI resolves. In a remote session one command
1864
+ runs three hooks in order: the npm hook installs the newest npm in the major of the floor the
1865
+ workspace's `devEngines` record declares when the container's npm is older, the dependency hook
1866
+ installs the lockfile's closure, and the browser hook installs the Chromium builds the
1867
+ `playwright-core` package pins when the container's browser store lacks them.
1864
1868
  The Ollama hook invokes `scripts/ollama.sh` only when `CLAUDE_CODE_REMOTE=true`; direct invocation
1865
1869
  remains available for live-service setup. Claude Code Cloud is Linux and has bash: SessionStart
1866
1870
  runs that POSIX script and never a Windows wrapper. What wires a bench stays in the canon, and a
@@ -1983,7 +1987,9 @@ and `overwrite` restore its bytes, so an edit made to it inside a target is reve
1983
1987
  visit and reported as drift until then. Put an operator grant in `.claude/settings.local.json`
1984
1988
  instead. That path is outside `HOST_PATHS` and matches the vendoring deny-list
1985
1989
  `matchesSensitivePath` reads, so `stageHost` never copies it into a host root and no plan carries
1986
- it.
1990
+ it. The staged `.claude/settings.json` sets `CLAUDE_CODE_SUBAGENT_MODEL` to `sonnet` in its `env`
1991
+ object: the model a Claude Code subagent runs on when no role frontmatter and no dispatch assigns
1992
+ one; `.claude/AGENTS.md` § Models owns the rule.
1987
1993
 
1988
1994
  `stageHost` fills the root from a real checkout at build time:
1989
1995
 
@@ -16,7 +16,7 @@
16
16
  "storage": "agents/orchestration.md",
17
17
  "destination": ".agents/orchestration.md",
18
18
  "executable": false,
19
- "digest": "b31dfd8ec22606bf3d98ca2f32241c7f43d2537be49400c4b801028b4178bac0"
19
+ "digest": "a2bdb3a85e41d8f2761f646da0f09f2a8dce8f48aadd1d68a1fc53e06dd57ec4"
20
20
  },
21
21
  {
22
22
  "storage": "agents/skills/enterprise-bootstrap/SKILL.md",
@@ -172,7 +172,7 @@
172
172
  "storage": "agents/skills/orkestrel-dispatch/scripts/bench.ts",
173
173
  "destination": ".agents/skills/orkestrel-dispatch/scripts/bench.ts",
174
174
  "executable": false,
175
- "digest": "a9bfce5def80e3b6917c76070c63c3a54ca9c0d1df62d62973b74b0dcd6224a2"
175
+ "digest": "952b12697e01f722fa50246718142987d1682bf3845a90b38e1255fa0ee609c4"
176
176
  },
177
177
  {
178
178
  "storage": "agents/skills/orkestrel-dispatch/scripts/brief.ts",
@@ -370,7 +370,7 @@
370
370
  "storage": "agents/skills/orkestrel-publish/references/wave.md",
371
371
  "destination": ".agents/skills/orkestrel-publish/references/wave.md",
372
372
  "executable": false,
373
- "digest": "68f5df5747f2b5cbd950413ce3e4a070ef5be229a79811711192763cd70d73fa"
373
+ "digest": "7aa0046c335d1728a3a4656757c19f096570970369eb04ca0377dcaf250d0901"
374
374
  },
375
375
  {
376
376
  "storage": "agents/skills/orkestrel-publish/references/window.md",
@@ -430,7 +430,7 @@
430
430
  "storage": "agents/transports/claude-cli.md",
431
431
  "destination": ".agents/transports/claude-cli.md",
432
432
  "executable": false,
433
- "digest": "cef2e96c822c7fd076703204d8c3e6192cd9c575f6527e272dde29dc6e53df32"
433
+ "digest": "d3d1243353ab48bce96bf9199997e494f7314d28cf8217ab79b6631936891ba3"
434
434
  },
435
435
  {
436
436
  "storage": "agents/transports/codex.md",
@@ -442,91 +442,91 @@
442
442
  "storage": "agents/transports/cursor.md",
443
443
  "destination": ".agents/transports/cursor.md",
444
444
  "executable": false,
445
- "digest": "2c3063adbac28be4942398dad5c004a083d6018de95042bb2ae1f48ecd4a3f35"
445
+ "digest": "c87663ca4b7f4f51aa9facab0dccdc8ee9dff673c9e15cadb722bdf7e89e5222"
446
446
  },
447
447
  {
448
448
  "storage": "claude/AGENTS.md",
449
449
  "destination": ".claude/AGENTS.md",
450
450
  "executable": false,
451
- "digest": "9047a8df9cea1fdaae4b31a8ad14e54ba1ecf5de89eba8bf89939627553cead2"
451
+ "digest": "5c5aa380ad393c1b222d08adc3c465b4dc3ec3cdc55f4847c57de0fd323e815e"
452
452
  },
453
453
  {
454
454
  "storage": "claude/agents/analyst.md",
455
455
  "destination": ".claude/agents/analyst.md",
456
456
  "executable": false,
457
- "digest": "e1d7e4202b293ff7d8d934e95d1c499845f0f49729180077f417864dc179c84b"
457
+ "digest": "6ad7895912fbfbdca3821132067d6c2993ace0a09bcc34d9f0a87b53d82d999b"
458
458
  },
459
459
  {
460
460
  "storage": "claude/agents/astra.md",
461
461
  "destination": ".claude/agents/astra.md",
462
462
  "executable": false,
463
- "digest": "4edd588c849f7bb9a3405096e935e5ff3ac0cc3391646a07f0d0f32efb12c41c"
463
+ "digest": "475af39fe97fc76836d969c66cab9cfb79f15d078b8668925236ef267cdd1c0c"
464
464
  },
465
465
  {
466
466
  "storage": "claude/agents/builder.md",
467
467
  "destination": ".claude/agents/builder.md",
468
468
  "executable": false,
469
- "digest": "a437e3410c183e7df6a7c5c007b72746111fc29771bb8c7116ee0a6d1ffab479"
469
+ "digest": "36bd7f5c6f2f57eaefca60f1743315f725f0604e77af8a81f217c2f0253252bf"
470
470
  },
471
471
  {
472
472
  "storage": "claude/agents/checker.md",
473
473
  "destination": ".claude/agents/checker.md",
474
474
  "executable": false,
475
- "digest": "7c57d1a025a2a88531dc3faefd9bf3c766ef76d309eae7778d1eef6f6db550e4"
475
+ "digest": "0b9cb8ebb287e80c52d653226f3b46a5e5e4fec4233a666d5f20d8a6a27e8ddc"
476
476
  },
477
477
  {
478
478
  "storage": "claude/agents/distiller.md",
479
479
  "destination": ".claude/agents/distiller.md",
480
480
  "executable": false,
481
- "digest": "03a38c07e45f19d925457cc3477de15b65701fab0f71f015acec0add55d1d7d2"
481
+ "digest": "a54a0534be8684a31741a6a9d1e56e083897a08bda09019fa5682c143e2677c2"
482
482
  },
483
483
  {
484
484
  "storage": "claude/agents/grok.md",
485
485
  "destination": ".claude/agents/grok.md",
486
486
  "executable": false,
487
- "digest": "6798fabf3a71e9514d8f33d7c310b7f20647951a0b847b11eee96f4150fb3e83"
487
+ "digest": "2ebe0e4621c92abdd88d90d4ec5745f4db90cf61d796cf666dc91951e78138a9"
488
488
  },
489
489
  {
490
490
  "storage": "claude/agents/opus.md",
491
491
  "destination": ".claude/agents/opus.md",
492
492
  "executable": false,
493
- "digest": "fc7a53b4d387ffdc7df51d31e7252c222d1ec539caca31c7ceee672c39f18042"
493
+ "digest": "007d5c173f8a0c9431aa2717a8571dfcefb65ae86fd277a20eaf7781d70935af"
494
494
  },
495
495
  {
496
496
  "storage": "claude/agents/orkestrel.md",
497
497
  "destination": ".claude/agents/orkestrel.md",
498
498
  "executable": false,
499
- "digest": "9a127e46e981c2d7fa8347d5e01c0c96205be566279e91923e1967094cca6029"
499
+ "digest": "70f83a325d00ec5e8f72866c22a867c22747d9f8ac3ed2ad844a9af7cba6dd93"
500
500
  },
501
501
  {
502
502
  "storage": "claude/agents/planner.md",
503
503
  "destination": ".claude/agents/planner.md",
504
504
  "executable": false,
505
- "digest": "86cef178ce25c8c8e002ea69c2e1bf0e21494ac77417e2376c5584fa3ae0c8b7"
505
+ "digest": "b96f0c28057393dafff0727669009311b0a9277a94286df0e73706495ec810ed"
506
506
  },
507
507
  {
508
508
  "storage": "claude/agents/researcher.md",
509
509
  "destination": ".claude/agents/researcher.md",
510
510
  "executable": false,
511
- "digest": "e5f0686f6bb1825fbf6006933e034c1ef882501792a93f690ac4bb059132e926"
511
+ "digest": "3a65cc76ce7f19cc00d6ec36d1b79f8bacaba3319a7f7648cc4fdffacb07c5f8"
512
512
  },
513
513
  {
514
514
  "storage": "claude/agents/reviewer.md",
515
515
  "destination": ".claude/agents/reviewer.md",
516
516
  "executable": false,
517
- "digest": "5e0ebe2e95de2281780842ada840ec0bd11f88fee2877530eee5d6c86731d5b4"
517
+ "digest": "557daaa0786c117ddc457c5b8a0c11e5a5b6f5292aadb1349b189e6d44141b88"
518
518
  },
519
519
  {
520
520
  "storage": "claude/agents/scout.md",
521
521
  "destination": ".claude/agents/scout.md",
522
522
  "executable": false,
523
- "digest": "fa55e6ca6c89dae3bdf6f2faddf6beea0746b8714962a45a44999f7d8b5f7691"
523
+ "digest": "9a0d995068a8c0706b768677de09da77a2e5155cdebd8efd482837596e1a82e5"
524
524
  },
525
525
  {
526
526
  "storage": "claude/agents/verifier.md",
527
527
  "destination": ".claude/agents/verifier.md",
528
528
  "executable": false,
529
- "digest": "bc5191ce230e03799a4437430be329a0593da06a28bfe45caaf5f8d51c72152a"
529
+ "digest": "70a39011bafc32bd39ef4506daba4b6b4be019356c13dc2a03756eccd345833c"
530
530
  },
531
531
  {
532
532
  "storage": "claude/rules/application.md",
@@ -580,7 +580,7 @@
580
580
  "storage": "claude/rules/styles.md",
581
581
  "destination": ".claude/rules/styles.md",
582
582
  "executable": false,
583
- "digest": "156572b7c26740411e64726255f76e0f6e6e4e55e800a26262a923210866eb77"
583
+ "digest": "9f59e22a0ca422e6e65b5adb0e7f3d92069a19dbd8b48b4c7ff5edfe4a39aab5"
584
584
  },
585
585
  {
586
586
  "storage": "claude/rules/tests.md",
@@ -610,7 +610,7 @@
610
610
  "storage": "claude/settings.json",
611
611
  "destination": ".claude/settings.json",
612
612
  "executable": false,
613
- "digest": "614d2cde6b6a6c00e90a8b7f8aa2a5c7b97f52bc5f4b4466df181752057e3f66"
613
+ "digest": "ebe54b12ac933a12312f562d069012b7d6dfe4b5155943c1805c3e1e2874afbd"
614
614
  },
615
615
  {
616
616
  "storage": "claude/skills/enterprise-bootstrap/SKILL.md",
@@ -694,7 +694,7 @@
694
694
  "storage": "codex/agents/builder.toml",
695
695
  "destination": ".codex/agents/builder.toml",
696
696
  "executable": false,
697
- "digest": "578be6691f4ce4c6dac2d953f0285d85dfb6fe72e885966bf2861227e969b5e2"
697
+ "digest": "dbf512595d6d4308003170c55252d4d9461daeeaca9f19a7e93026e1516d4be4"
698
698
  },
699
699
  {
700
700
  "storage": "codex/agents/checker.toml",
@@ -1042,7 +1042,7 @@
1042
1042
  "storage": "guides/scaffold.md",
1043
1043
  "destination": "guides/scaffold.md",
1044
1044
  "executable": false,
1045
- "digest": "a5c97efa111d3fe4832380638c025b9cd4f536819b595753c463d7ef2f094889"
1045
+ "digest": "92391c5adfa7652ce6c4b34b4b78176f152d0c4398f28dc7da04797b64e2e973"
1046
1046
  },
1047
1047
  {
1048
1048
  "storage": "guides/sea.md",
@@ -1140,6 +1140,12 @@
1140
1140
  "executable": false,
1141
1141
  "digest": "1353da0a0340a8ec7d7c2c08a028d95361bb75b2b03a0e743865c66eee3d0a42"
1142
1142
  },
1143
+ {
1144
+ "storage": "scripts/browsers.sh",
1145
+ "destination": "scripts/browsers.sh",
1146
+ "executable": true,
1147
+ "digest": "1f38c4b95681fe2415bfa5b44641859d80df866551733cb3d3b0e30ce41ff093"
1148
+ },
1143
1149
  {
1144
1150
  "storage": "scripts/codex.sh",
1145
1151
  "destination": "scripts/codex.sh",
@@ -1158,6 +1164,12 @@
1158
1164
  "executable": true,
1159
1165
  "digest": "8f4ad360cd43ea3da202892bf2cdea546795c4081e435384754cbffbf73d773e"
1160
1166
  },
1167
+ {
1168
+ "storage": "scripts/npm.sh",
1169
+ "destination": "scripts/npm.sh",
1170
+ "executable": true,
1171
+ "digest": "5f9e12952eeddfd9c40d42710c0eabbbe5c9ee55d882f24e0015f419f0fba137"
1172
+ },
1161
1173
  {
1162
1174
  "storage": "scripts/ollama.sh",
1163
1175
  "destination": "scripts/ollama.sh",
@@ -2108,5 +2120,5 @@
2108
2120
  ]
2109
2121
  }
2110
2122
  ],
2111
- "digest": "fe0bc8e58df9b675840871884af8db3b3390a38024e12fe2ef342f160a62931c"
2123
+ "digest": "ce09377c0924a0c47243e4558f2afd3784c71a9a69ff20a481dfc87331921452"
2112
2124
  }
@@ -0,0 +1,54 @@
1
+ #!/bin/bash
2
+ # ============================================================================
3
+ # scripts/browsers.sh — SessionStart hook: Playwright browsers for the pinned playwright-core
4
+ # ----------------------------------------------------------------------------
5
+ # Runs only in Claude Code's remote environment. The container pre-installs one
6
+ # Chromium build under PLAYWRIGHT_BROWSERS_PATH; when the lockfile pins a
7
+ # playwright-core whose browsers.json names another build, every browser project
8
+ # fails at launch. Playwright's own installer resolves the store, skips a build
9
+ # whose completion marker exists, and downloads the rest, so this hook runs it
10
+ # and reports what it did. It runs after scripts/deps.sh in the same SessionStart
11
+ # command, because matching hooks run in parallel and the installer arrives with
12
+ # node_modules.
13
+ # ============================================================================
14
+
15
+ if [ "${CLAUDE_CODE_REMOTE:-}" != "true" ]; then
16
+ exit 0
17
+ fi
18
+
19
+ cd "$CLAUDE_PROJECT_DIR" || exit 0
20
+
21
+ CLI="node_modules/playwright/cli.js"
22
+ if [ ! -f "$CLI" ]; then
23
+ echo "browsers.sh: playwright is not installed — skipped."
24
+ exit 0
25
+ fi
26
+
27
+ if ! TEMPORARY="$(node -p 'require("node:os").tmpdir()')" || [ -z "$TEMPORARY" ]; then
28
+ echo "browsers.sh: could not read the temporary directory — skipped."
29
+ exit 0
30
+ fi
31
+
32
+ BROWSERS_LOG="$(mktemp -p "$TEMPORARY" orkestrel-browsers.XXXXXX)" || {
33
+ echo "browsers.sh: could not create a private install log — skipped."
34
+ exit 0
35
+ }
36
+ chmod 600 "$BROWSERS_LOG"
37
+
38
+ cleanup_browsers_log() {
39
+ rm -f -- "$BROWSERS_LOG"
40
+ }
41
+
42
+ trap cleanup_browsers_log EXIT
43
+
44
+ if node "$CLI" install chromium >"$BROWSERS_LOG" 2>&1; then
45
+ if grep -q 'downloaded to' "$BROWSERS_LOG"; then
46
+ echo "browsers.sh: installed the Chromium builds playwright-core pins."
47
+ else
48
+ echo "browsers.sh: Playwright browsers match playwright-core — skipped."
49
+ fi
50
+ else
51
+ echo "browsers.sh: playwright install failed; browser projects remain unlaunchable in this session."
52
+ fi
53
+
54
+ exit 0
File without changes
File without changes
File without changes
@@ -0,0 +1,111 @@
1
+ #!/bin/bash
2
+ # ============================================================================
3
+ # scripts/npm.sh — SessionStart hook: npm at the checkout's declared floor
4
+ # ----------------------------------------------------------------------------
5
+ # Runs only in Claude Code's remote environment. A generated workspace declares
6
+ # its npm floor in devEngines.packageManager with onFail error, and an older npm
7
+ # refuses every install there with EBADDEVENGINES. This hook reads that floor:
8
+ # packageManager is one entry or an array of entries, each naming its manager,
9
+ # and the entry named npm carries a ">=major.minor.patch" version, the form
10
+ # readNpmFloor in tests/setupServer.ts admits. The @orkestrel/scaffold checkout
11
+ # declares no devEngines, because its CI installs on a Node whose bundled npm is
12
+ # older, so there the hook reads the MINIMUM_NPM_VERSION src/core/constants.ts
13
+ # exports. When the session's npm is older than the floor or a prerelease, it
14
+ # installs the newest npm in the floor's major globally. It runs first in the
15
+ # SessionStart command, before scripts/deps.sh runs npm ci.
16
+ # ============================================================================
17
+
18
+ if [ "${CLAUDE_CODE_REMOTE:-}" != "true" ]; then
19
+ exit 0
20
+ fi
21
+
22
+ cd "$CLAUDE_PROJECT_DIR" || exit 0
23
+
24
+ if [ ! -f package.json ]; then
25
+ exit 0
26
+ fi
27
+
28
+ if ! TEMPORARY="$(node -p 'require("node:os").tmpdir()')" || [ -z "$TEMPORARY" ]; then
29
+ echo "npm.sh: could not read the temporary directory — skipped."
30
+ exit 0
31
+ fi
32
+
33
+ NPM_LOG="$(mktemp -p "$TEMPORARY" orkestrel-npm.XXXXXX)" || {
34
+ echo "npm.sh: could not create a private install log — skipped."
35
+ exit 0
36
+ }
37
+ chmod 600 "$NPM_LOG"
38
+
39
+ cleanup_npm_log() {
40
+ rm -f -- "$NPM_LOG"
41
+ }
42
+
43
+ trap cleanup_npm_log EXIT
44
+
45
+ meets_floor() {
46
+ [[ "$1" =~ ^[0-9]+\.[0-9]+\.[0-9]+(\+[0-9A-Za-z.-]+)?$ ]] &&
47
+ [ "$(printf '%s\n%s\n' "$FLOOR" "${1%%+*}" | sort -V | head -n 1)" = "$FLOOR" ]
48
+ }
49
+
50
+ if ! FLOOR="$(node --input-type=module -e '
51
+ import { readFileSync } from "node:fs"
52
+ import { resolve } from "node:path"
53
+ import { pathToFileURL } from "node:url"
54
+ const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value)
55
+ const manifest = JSON.parse(readFileSync("package.json", "utf8"))
56
+ if (!isRecord(manifest)) throw new Error("package.json is not a record")
57
+ if (manifest.devEngines !== undefined && !isRecord(manifest.devEngines)) throw new Error("devEngines is not a record")
58
+ const declared = manifest.devEngines?.packageManager
59
+ let floor
60
+ if (declared !== undefined) {
61
+ const entries = Array.isArray(declared) ? declared : [declared]
62
+ if (!entries.every((candidate) => isRecord(candidate) && typeof candidate.name === "string")) throw new Error("devEngines.packageManager holds an entry with no name")
63
+ const entry = entries.find((candidate) => candidate.name === "npm")
64
+ if (entry !== undefined) {
65
+ floor = typeof entry.version === "string" ? /^>=((?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*))$/u.exec(entry.version)?.[1] : undefined
66
+ if (floor === undefined) throw new Error("the npm entry declares no >=major.minor.patch floor")
67
+ }
68
+ } else if (manifest.name === "@orkestrel/scaffold") {
69
+ const constants = await import(pathToFileURL(resolve("src/core/constants.ts")).href)
70
+ floor = constants.MINIMUM_NPM_VERSION
71
+ if (typeof floor !== "string" || !/^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)$/u.test(floor)) throw new Error("MINIMUM_NPM_VERSION is not a major.minor.patch version")
72
+ }
73
+ process.stdout.write(floor ?? "")
74
+ ' 2>"$NPM_LOG")"; then
75
+ echo "npm.sh: could not read the npm floor — skipped."
76
+ exit 0
77
+ fi
78
+
79
+ if [ -z "$FLOOR" ]; then
80
+ echo "npm.sh: the checkout declares no npm floor — skipped."
81
+ exit 0
82
+ fi
83
+
84
+ CURRENT="$(npm --version 2>"$NPM_LOG")"
85
+ if [ -z "$CURRENT" ]; then
86
+ echo "npm.sh: npm is not installed — skipped."
87
+ exit 0
88
+ fi
89
+
90
+ if meets_floor "$CURRENT"; then
91
+ echo "npm.sh: npm $CURRENT meets the floor $FLOOR — skipped."
92
+ exit 0
93
+ fi
94
+
95
+ if npm install -g "npm@^$FLOOR" >"$NPM_LOG" 2>&1; then
96
+ INSTALLED="$(npm --version 2>"$NPM_LOG")"
97
+ if meets_floor "$INSTALLED"; then
98
+ echo "npm.sh: installed npm $INSTALLED over $CURRENT to meet the floor $FLOOR."
99
+ else
100
+ echo "npm.sh: npm install ran, and npm reads ${INSTALLED:-nothing}, which does not meet the floor $FLOOR; installs that declare it refuse."
101
+ fi
102
+ else
103
+ INSTALLED="$(npm --version 2>"$NPM_LOG")"
104
+ if meets_floor "$INSTALLED"; then
105
+ echo "npm.sh: npm install failed, and npm $INSTALLED meets the floor $FLOOR."
106
+ else
107
+ echo "npm.sh: npm install failed; npm reads ${INSTALLED:-nothing}, which does not meet the floor $FLOOR; installs that declare it refuse."
108
+ fi
109
+ fi
110
+
111
+ exit 0
File without changes
@@ -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.96",
7
+ version: "0.0.98",
8
8
  description: "Scaffold workspaces with commands: new, audit, repair, catalog, and overwrite.",
9
9
  keywords: [
10
10
  "audit",
@@ -104,10 +104,10 @@ var package_default = {
104
104
  },
105
105
  devDependencies: {
106
106
  "@microsoft/api-extractor": "^7.59.4",
107
- "@orkestrel/browser": "^0.0.27",
107
+ "@orkestrel/browser": "^0.0.28",
108
108
  "@orkestrel/guide": "^0.0.24",
109
109
  "@orkestrel/html": "^0.0.12",
110
- "@orkestrel/probe": "^0.0.22",
110
+ "@orkestrel/probe": "^0.0.23",
111
111
  "@orkestrel/test": "^0.0.25",
112
112
  "@types/node": "^26.6.4",
113
113
  "@vitest/browser-playwright": "^4.1.11",
@@ -115,7 +115,7 @@ var package_default = {
115
115
  "oxlint": "^1.87.0",
116
116
  "playwright": "^1.63.0",
117
117
  "typescript": "^6.0.3",
118
- "vite": "^8.3.3",
118
+ "vite": "^8.3.4",
119
119
  "vitest": "^4.1.11"
120
120
  },
121
121
  engines: { "node": ">=22.18.0" }
@@ -384,9 +384,11 @@ var WORKSPACE_OWNED_PATHS = Object.freeze([".gitignore"]);
384
384
  * that must run when a target invokes it belongs here the moment it is vendored.
385
385
  */
386
386
  var EXECUTABLE_PATHS = Object.freeze([
387
+ "scripts/browsers.sh",
387
388
  "scripts/codex.sh",
388
389
  "scripts/cursor.sh",
389
390
  "scripts/deps.sh",
391
+ "scripts/npm.sh",
390
392
  "scripts/ollama.sh"
391
393
  ]);
392
394
  /**
@@ -6245,6 +6247,37 @@ function blueprintToProjects(blueprint) {
6245
6247
  return projects;
6246
6248
  }
6247
6249
  /**
6250
+ * Compiles the browser projects' pre-bundled dependency list for a blueprint.
6251
+ *
6252
+ * @remarks
6253
+ * A browser-mode run that discovers a runtime package mid-collection reloads the page, so the
6254
+ * list names the test package, its browser entry, and every Orkestrel runtime package the
6255
+ * blueprint declares or peers with, inline when the line fits the print width and stacked
6256
+ * otherwise.
6257
+ *
6258
+ * @example
6259
+ * ```ts
6260
+ * import { blueprintToOptimizedDependencies, createBlueprint } from '@orkestrel/scaffold'
6261
+ *
6262
+ * const blueprint = createBlueprint('router', { src: ['core'] })
6263
+ *
6264
+ * blueprintToOptimizedDependencies(blueprint).includes("'@orkestrel/test/browser'") // true
6265
+ * ```
6266
+ */
6267
+ function blueprintToOptimizedDependencies(blueprint) {
6268
+ const names = [
6269
+ "@orkestrel/test",
6270
+ "@orkestrel/test/browser",
6271
+ ...[.../* @__PURE__ */ new Set([
6272
+ ...Object.hasOwn(blueprintToDevDependencies(blueprint), "@orkestrel/contract") ? ["@orkestrel/contract"] : [],
6273
+ ...blueprint.dependencies.map((dependency) => dependency.name),
6274
+ ...blueprint.peers.map((peer) => peer.name)
6275
+ ])].filter((name) => name.startsWith("@orkestrel/")).sort()
6276
+ ];
6277
+ const inline = `\tinclude: [${names.map((name) => `'${name}'`).join(", ")}],`;
6278
+ return matchesPrintWidth(inline) ? `const optimizeDeps = {\n${inline}\n}\n\n` : `const optimizeDeps = {\n\tinclude: [\n${names.map((name) => `\t\t'${name}',`).join("\n")}\n\t],\n}\n\n`;
6279
+ }
6280
+ /**
6248
6281
  * Compiles the root Vite and Vitest configuration for a blueprint.
6249
6282
  *
6250
6283
  * @param blueprint - The workspace specification.
@@ -6424,13 +6457,7 @@ ${projects.map((project) => `\t\t\t${project},`).join("\n")}
6424
6457
  imports: imports.length === 0 ? "" : `${imports.join("\n")}\n`,
6425
6458
  helpers: helpers.length === 0 ? "" : matchesPrintWidth(helperImport.trimEnd()) ? helperImport : `import {\n${helpers.map((helper) => `\t${helper},`).join("\n")}\n} from './configs/helpers.js'\n`,
6426
6459
  browsers: machinery.browser ? "import { resolveBrowser, resolvePinnedBrowser } from './configs/browsers.js'\n" : "",
6427
- options: (machinery.browser ? `const browserOptions = resolveBrowser(resolvePinnedBrowser(), process.platform, process.env)
6428
-
6429
- const optimizeDeps = {\n\tinclude: ${JSON.stringify([
6430
- "@orkestrel/test",
6431
- "@orkestrel/test/browser",
6432
- ...Object.hasOwn(blueprintToDevDependencies(blueprint), "@orkestrel/contract") || blueprint.dependencies.some((dependency) => dependency.name === "@orkestrel/contract") || blueprint.peers.some((peer) => peer.name === "@orkestrel/contract") ? ["@orkestrel/contract"] : []
6433
- ]).replaceAll("\"", "'").replaceAll(",", ", ")},\n}\n\n` : "") + (blueprint.journey && blueprint.app.includes("browser") ? "const capture = process.env.CAPTURE === '1'\n\n" : "") + ((blueprint.journey || blueprint.showcase) && blueprint.app.includes("browser") ? `const applications = {\n\tbrowser: appBrowser,\n${blueprintToFaces(blueprint).filter((extension) => extension.surface === "browser" && extension.axes.includes("app")).map((extension) => `\t${extension.name}: app${extension.name[0]?.toUpperCase()}${extension.name.slice(1)},\n`).join("")}}\n\n` : ""),
6460
+ options: (machinery.browser ? "const browserOptions = resolveBrowser(resolvePinnedBrowser(), process.platform, process.env)\n\n" + blueprintToOptimizedDependencies(blueprint) : "") + (blueprint.journey && blueprint.app.includes("browser") ? "const capture = process.env.CAPTURE === '1'\n\n" : "") + ((blueprint.journey || blueprint.showcase) && blueprint.app.includes("browser") ? `const applications = {\n\tbrowser: appBrowser,\n${blueprintToFaces(blueprint).filter((extension) => extension.surface === "browser" && extension.axes.includes("app")).map((extension) => `\t${extension.name}: app${extension.name[0]?.toUpperCase()}${extension.name.slice(1)},\n`).join("")}}\n\n` : ""),
6434
6461
  factories: body,
6435
6462
  projects: projectRows
6436
6463
  });
@@ -8779,6 +8806,7 @@ exports.blueprintToGuideArtifacts = blueprintToGuideArtifacts;
8779
8806
  exports.blueprintToHostArtifacts = blueprintToHostArtifacts;
8780
8807
  exports.blueprintToMachinery = blueprintToMachinery;
8781
8808
  exports.blueprintToManifest = blueprintToManifest;
8809
+ exports.blueprintToOptimizedDependencies = blueprintToOptimizedDependencies;
8782
8810
  exports.blueprintToOrchestrationArtifacts = blueprintToOrchestrationArtifacts;
8783
8811
  exports.blueprintToProjects = blueprintToProjects;
8784
8812
  exports.blueprintToQuestions = blueprintToQuestions;