@orkestrel/scaffold 0.0.50 → 0.0.52

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 (66) hide show
  1. package/dist/bin/main.js +46 -17
  2. package/dist/bin/main.js.map +1 -1
  3. package/dist/host/AGENTS.md +2 -2
  4. package/dist/host/CLAUDE.md +3 -1
  5. package/dist/host/agents/orchestration.md +109 -274
  6. package/dist/host/agents/skills/enterprise-bootstrap/SKILL.md +12 -8
  7. package/dist/host/agents/skills/orkestrel-align-packages/SKILL.md +2 -2
  8. package/dist/host/agents/skills/orkestrel-debrief/SKILL.md +15 -11
  9. package/dist/host/agents/skills/orkestrel-debrief/references/instruction-audit.md +38 -12
  10. package/dist/host/agents/skills/orkestrel-debrief/references/retention.md +107 -0
  11. package/dist/host/agents/skills/{orkestrel-human-journey → orkestrel-prove-journey}/SKILL.md +1 -1
  12. package/dist/host/agents/skills/{orkestrel-human-journey → orkestrel-prove-journey}/agents/openai.yaml +1 -1
  13. package/dist/host/agents/skills/orkestrel-publish/SKILL.md +77 -0
  14. package/dist/host/agents/skills/orkestrel-publish/agents/openai.yaml +4 -0
  15. package/dist/host/agents/skills/orkestrel-publish/references/wave.md +97 -0
  16. package/dist/host/agents/skills/orkestrel-publish/references/window.md +95 -0
  17. package/dist/host/agents/templates/brief.md +157 -0
  18. package/dist/host/{codex/agents/claude.toml → agents/transports/claude.md} +16 -10
  19. package/dist/host/{claude/agents → agents/transports}/codex.md +13 -12
  20. package/dist/host/claude/agents/analyst.md +11 -10
  21. package/dist/host/claude/agents/application.md +6 -3
  22. package/dist/host/claude/agents/builder.md +11 -10
  23. package/dist/host/claude/agents/checker.md +20 -10
  24. package/dist/host/claude/agents/grok.md +8 -7
  25. package/dist/host/claude/agents/implementer.md +7 -4
  26. package/dist/host/claude/agents/orkestrel.md +27 -21
  27. package/dist/host/claude/agents/planner.md +13 -5
  28. package/dist/host/claude/agents/researcher.md +8 -7
  29. package/dist/host/claude/agents/reviewer.md +6 -4
  30. package/dist/host/claude/agents/scout.md +6 -7
  31. package/dist/host/claude/agents/sol.md +9 -8
  32. package/dist/host/claude/agents/verifier.md +6 -3
  33. package/dist/host/claude/rules/architecture.md +6 -6
  34. package/dist/host/claude/rules/documentation.md +2 -0
  35. package/dist/host/claude/rules/tests.md +4 -2
  36. package/dist/host/claude/rules/workspace.md +1 -1
  37. package/dist/host/claude/skills/enterprise-bootstrap/SKILL.md +12 -8
  38. package/dist/host/claude/skills/orkestrel-debrief/SKILL.md +1 -1
  39. package/dist/host/claude/skills/{orkestrel-human-journey → orkestrel-prove-journey}/SKILL.md +2 -2
  40. package/dist/host/claude/skills/orkestrel-publish/SKILL.md +12 -0
  41. package/dist/host/codex/agents/analyst.toml +3 -0
  42. package/dist/host/codex/agents/application.toml +3 -0
  43. package/dist/host/codex/agents/builder.toml +10 -7
  44. package/dist/host/codex/agents/checker.toml +14 -3
  45. package/dist/host/codex/agents/grok.toml +5 -2
  46. package/dist/host/codex/agents/implementer.toml +3 -2
  47. package/dist/host/codex/agents/opus.toml +4 -3
  48. package/dist/host/codex/agents/orkestrel.toml +14 -9
  49. package/dist/host/codex/agents/planner.toml +7 -5
  50. package/dist/host/codex/agents/researcher.toml +6 -4
  51. package/dist/host/codex/agents/reviewer.toml +4 -3
  52. package/dist/host/codex/agents/scout.toml +4 -1
  53. package/dist/host/codex/agents/verifier.toml +3 -2
  54. package/dist/host/codex/config.toml +1 -1
  55. package/dist/host/guides/scaffold.md +48 -44
  56. package/dist/host/manifest.json +132 -84
  57. package/dist/host/tests/config.test.ts +57 -0
  58. package/dist/src/core/index.cjs +455 -406
  59. package/dist/src/core/index.cjs.map +1 -1
  60. package/dist/src/core/index.d.cts +51 -48
  61. package/dist/src/core/index.d.ts +51 -48
  62. package/dist/src/core/index.js +455 -406
  63. package/dist/src/core/index.js.map +1 -1
  64. package/package.json +2 -2
  65. /package/dist/host/agents/skills/{orkestrel-human-journey → orkestrel-prove-journey}/references/captures.md +0 -0
  66. /package/dist/host/agents/skills/{orkestrel-human-journey → orkestrel-prove-journey}/references/layer.md +0 -0
@@ -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.50",
7
+ version: "0.0.52",
8
8
  description: "Scaffold workspaces with five commands: new, audit, repair, catalog, and overwrite.",
9
9
  keywords: [
10
10
  "audit",
@@ -100,7 +100,7 @@ var package_default = {
100
100
  "@microsoft/api-extractor": "^7.59.0",
101
101
  "@orkestrel/guide": "^0.0.13",
102
102
  "@orkestrel/html": "^0.0.5",
103
- "@orkestrel/probe": "^0.0.3",
103
+ "@orkestrel/probe": "^0.0.4",
104
104
  "@orkestrel/test": "^0.0.11",
105
105
  "@types/node": "^26.2.0",
106
106
  "@vitest/browser-playwright": "^4.1.11",
@@ -225,6 +225,8 @@ var HOST_PATHS = Object.freeze([
225
225
  "LICENSE",
226
226
  ".agents/orchestration.md",
227
227
  ".agents/skills",
228
+ ".agents/templates",
229
+ ".agents/transports",
228
230
  ".claude/agents",
229
231
  ".claude/rules",
230
232
  ".claude/skills",
@@ -561,7 +563,7 @@ var CONFIG_TEMPLATES = Object.freeze({
561
563
  }
562
564
  `,
563
565
  vite: `import type { {{viteTypes}} } from 'vite'
564
- {{imports}}import { defineConfig, mergeConfig } from 'vitest/config'
566
+ {{imports}}import { defineConfig } from 'vitest/config'
565
567
  import manifest from './package.json' with { type: 'json' }
566
568
  import tsconfig from './tsconfig.json' with { type: 'json' }
567
569
  {{helpers}}{{browsers}}import { fileURLToPath, URL } from 'node:url'
@@ -600,160 +602,140 @@ const resolve = {
600
602
  }),
601
603
  factories: Object.freeze({
602
604
  src: Object.freeze({
603
- core: `export const srcCore = (options?: UserConfig): UserConfig =>
604
- mergeConfig(
605
- {
606
- resolve,
607
- publicDir: false,
608
- build: {
609
- emptyOutDir: true,
610
- sourcemap: true,
611
- minify: false,
612
- rolldownOptions: { onLog: enforceBuildLog },
613
- },
614
- test: {
615
- name: { label: 'src:core', color: 'magenta' },
616
- include: ['tests/src/core/**/*.test.ts'],
617
- setupFiles: ['./tests/setup.ts'],
618
- environment: 'node',
619
- browser: { enabled: false },
620
- },
621
- },
622
- options ?? {},
623
- )
605
+ core: `export const srcCore = (): UserConfig => ({
606
+ resolve,
607
+ publicDir: false,
608
+ build: {
609
+ emptyOutDir: true,
610
+ sourcemap: true,
611
+ minify: false,
612
+ rolldownOptions: { onLog: enforceBuildLog },
613
+ },
614
+ test: {
615
+ name: { label: 'src:core', color: 'magenta' },
616
+ include: ['tests/src/core/**/*.test.ts'],
617
+ setupFiles: ['./tests/setup.ts'],
618
+ environment: 'node',
619
+ browser: { enabled: false },
620
+ },
621
+ })
624
622
  `,
625
- browser: `export const srcBrowser = (options?: UserConfig): UserConfig =>
626
- mergeConfig(
627
- {
628
- resolve,
629
- publicDir: false,
630
- plugins: [outputBoundary('dist/src/browser'), environmentBoundary('src/browser')],
631
- build: {
632
- emptyOutDir: true,
633
- sourcemap: true,
634
- minify: false,
635
- lib: {
636
- entry: resolveWorkspacePath('src/browser/index.ts'),
637
- formats: ['es'],
638
- fileName: () => 'index.js',
639
- },
640
- outDir: 'dist/src/browser',
641
- rolldownOptions: {
642
- onLog: enforceBuildLog,
643
- {{external}}
623
+ browser: `export const srcBrowser = (): UserConfig => ({
624
+ resolve,
625
+ publicDir: false,
626
+ plugins: [outputBoundary('dist/src/browser'), environmentBoundary('src/browser')],
627
+ build: {
628
+ emptyOutDir: true,
629
+ sourcemap: true,
630
+ minify: false,
631
+ lib: {
632
+ entry: resolveWorkspacePath('src/browser/index.ts'),
633
+ formats: ['es'],
634
+ fileName: () => 'index.js',
635
+ },
636
+ outDir: 'dist/src/browser',
637
+ rolldownOptions: {
638
+ onLog: enforceBuildLog,
639
+ {{external}}
644
640
  {{output}}
645
- },
646
- },
647
- test: {
648
- name: { label: 'src:browser', color: 'yellow' },
649
- include: ['tests/src/browser/**/*.test.ts'],
650
- {{exclude}} setupFiles: ['./tests/setup.ts', './tests/setupBrowser.ts'],
641
+ },
642
+ },
643
+ test: {
644
+ name: { label: 'src:browser', color: 'yellow' },
645
+ include: ['tests/src/browser/**/*.test.ts'],
646
+ {{exclude}} setupFiles: ['./tests/setup.ts', './tests/setupBrowser.ts'],
651
647
  {{global}}
652
- browser: {
653
- enabled: true,
654
- provider: playwright(browserOptions),
655
- instances: [{ browser: 'chromium', headless: true }],
656
- },
657
- fileParallelism: false,
658
- },
648
+ browser: {
649
+ enabled: true,
650
+ provider: playwright(browserOptions),
651
+ instances: [{ browser: 'chromium', headless: true }],
659
652
  },
660
- options ?? {},
661
- )
653
+ fileParallelism: false,
654
+ },
655
+ })
662
656
  `,
663
- server: `export const srcServer = (options?: UserConfig): UserConfig =>
664
- mergeConfig(
665
- {
666
- resolve,
667
- publicDir: false,
668
- plugins: [outputBoundary('dist/src/server'), environmentBoundary('src/server')],
669
- build: {
670
- emptyOutDir: true,
671
- sourcemap: true,
672
- minify: false,
673
- lib: {
674
- entry: resolveWorkspacePath('src/server/index.ts'),
675
- formats: ['es', 'cjs'],
676
- fileName: (format: string) => (format === 'es' ? 'index.js' : 'index.cjs'),
677
- },
678
- outDir: 'dist/src/server',
679
- target: 'node22',
680
- rolldownOptions: {
681
- onLog: enforceBuildLog,
682
- platform: 'node',
683
- {{external}}
657
+ server: `export const srcServer = (): UserConfig => ({
658
+ resolve,
659
+ publicDir: false,
660
+ plugins: [outputBoundary('dist/src/server'), environmentBoundary('src/server')],
661
+ build: {
662
+ emptyOutDir: true,
663
+ sourcemap: true,
664
+ minify: false,
665
+ lib: {
666
+ entry: resolveWorkspacePath('src/server/index.ts'),
667
+ formats: ['es', 'cjs'],
668
+ fileName: (format: string) => (format === 'es' ? 'index.js' : 'index.cjs'),
669
+ },
670
+ outDir: 'dist/src/server',
671
+ target: 'node22',
672
+ rolldownOptions: {
673
+ onLog: enforceBuildLog,
674
+ platform: 'node',
675
+ {{external}}
684
676
  {{output}}
685
- },
686
- },
687
- test: {
688
- name: { label: 'src:server', color: 'red' },
689
- include: ['tests/src/server/**/*.test.ts'],
690
- {{exclude}} setupFiles: ['./tests/setup.ts', './tests/setupServer.ts'],
691
- environment: 'node',
692
- browser: { enabled: false },
693
- },
694
677
  },
695
- options ?? {},
696
- )
678
+ },
679
+ test: {
680
+ name: { label: 'src:server', color: 'red' },
681
+ include: ['tests/src/server/**/*.test.ts'],
682
+ {{exclude}} setupFiles: ['./tests/setup.ts', './tests/setupServer.ts'],
683
+ environment: 'node',
684
+ browser: { enabled: false },
685
+ },
686
+ })
697
687
  `,
698
- bin: `export const srcBin = (options?: UserConfig): UserConfig =>
699
- mergeConfig(
700
- {
701
- resolve,
702
- publicDir: false,
703
- plugins: [outputBoundary('dist/bin')],
704
- build: {
705
- emptyOutDir: true,
706
- sourcemap: true,
707
- minify: false,
708
- lib: {
709
- entry: resolveWorkspacePath('${BIN_ENTRY_PATH}'),
710
- formats: ['es'],
711
- fileName: () => 'main.js',
712
- },
713
- outDir: 'dist/bin',
714
- target: 'node22',
715
- rolldownOptions: {
716
- onLog: enforceBuildLog,
717
- external: (id: string) =>
718
- id.startsWith('node:') ||
719
- id.startsWith('@orkestrel/') ||
720
- id.startsWith('@src/') ||
721
- peers.some((peer) => id === peer || id.startsWith(peer + '/')),
722
- },
723
- },
724
- test: {
725
- name: { label: 'src:bin', color: 'yellow' },
726
- include: ['tests/src/bin/**/*.test.ts'],
727
- setupFiles: ['./tests/setup.ts', './tests/setupServer.ts'],
728
- environment: 'node',
729
- browser: { enabled: false },
730
- // A bin test drives the real executable over a real temporary repository, so it
731
- // spends seconds in process startup and filesystem work rather than milliseconds.
732
- // Vitest's five-second default clears one alone and times out under a full suite.
733
- testTimeout: 15_000,
734
- },
688
+ bin: `export const srcBin = (): UserConfig => ({
689
+ resolve,
690
+ publicDir: false,
691
+ plugins: [outputBoundary('dist/bin')],
692
+ build: {
693
+ emptyOutDir: true,
694
+ sourcemap: true,
695
+ minify: false,
696
+ lib: {
697
+ entry: resolveWorkspacePath('${BIN_ENTRY_PATH}'),
698
+ formats: ['es'],
699
+ fileName: () => 'main.js',
735
700
  },
736
- options ?? {},
737
- )
701
+ outDir: 'dist/bin',
702
+ target: 'node22',
703
+ rolldownOptions: {
704
+ onLog: enforceBuildLog,
705
+ external: (id: string) =>
706
+ id.startsWith('node:') ||
707
+ id.startsWith('@orkestrel/') ||
708
+ id.startsWith('@src/') ||
709
+ peers.some((peer) => id === peer || id.startsWith(peer + '/')),
710
+ },
711
+ },
712
+ test: {
713
+ name: { label: 'src:bin', color: 'yellow' },
714
+ include: ['tests/src/bin/**/*.test.ts'],
715
+ setupFiles: ['./tests/setup.ts', './tests/setupServer.ts'],
716
+ environment: 'node',
717
+ browser: { enabled: false },
718
+ // A bin test drives the real executable over a real temporary repository, so it
719
+ // spends seconds in process startup and filesystem work rather than milliseconds.
720
+ // Vitest's five-second default clears one alone and times out under a full suite.
721
+ testTimeout: 15_000,
722
+ },
723
+ })
738
724
  `
739
725
  }),
740
726
  app: Object.freeze({
741
- core: `export const appCore = (options?: UserConfig): UserConfig =>
742
- mergeConfig(
743
- {
744
- resolve,
745
- publicDir: false,
746
- plugins: [environmentBoundary('app/core')],
747
- test: {
748
- name: { label: 'app:core', color: 'cyan' },
749
- include: ['tests/app/core/**/*.test.ts'],
750
- setupFiles: ['./tests/setup.ts'],
751
- environment: 'node',
752
- browser: { enabled: false },
753
- },
754
- },
755
- options ?? {},
756
- )
727
+ core: `export const appCore = (): UserConfig => ({
728
+ resolve,
729
+ publicDir: false,
730
+ plugins: [environmentBoundary('app/core')],
731
+ test: {
732
+ name: { label: 'app:core', color: 'cyan' },
733
+ include: ['tests/app/core/**/*.test.ts'],
734
+ setupFiles: ['./tests/setup.ts'],
735
+ environment: 'node',
736
+ browser: { enabled: false },
737
+ },
738
+ })
757
739
  `,
758
740
  browser: `function applicationBrowser(showcase: boolean): UserConfig {
759
741
  const output = showcase ? 'dist/showcase' : 'dist/app/browser'
@@ -785,197 +767,157 @@ const resolve = {
785
767
  }
786
768
  }
787
769
 
788
- export function appBrowser(options?: UserConfig): UserConfig {
789
- return mergeConfig(applicationBrowser(false), options ?? {})
770
+ export function appBrowser(): UserConfig {
771
+ return applicationBrowser(false)
790
772
  }
791
773
  {{showcaseFactory}}`,
792
- server: `export const appServer = (options?: UserConfig): UserConfig =>
793
- mergeConfig(
794
- {
795
- resolve,
796
- publicDir: false,
797
- plugins: [outputBoundary('dist/app/server'), environmentBoundary('app/server')],
798
- build: {
799
- emptyOutDir: true,
800
- lib: {
801
- entry: resolveWorkspacePath('app/server/main.ts'),
802
- formats: ['cjs'],
803
- fileName: () => 'main.cjs',
804
- },
805
- outDir: resolveWorkspacePath('dist/app/server'),
806
- target: 'node22',
807
- rolldownOptions: {
808
- onLog: enforceBuildLog,
809
- external: (id: string) => id.startsWith('node:'),
810
- },
811
- },
812
- test: {
813
- name: { label: 'app:server', color: 'green' },
814
- include: ['tests/app/server/**/*.test.ts'],
815
- setupFiles: ['./tests/setup.ts', './tests/setupServer.ts'],
816
- environment: 'node',
817
- browser: { enabled: false },
818
- },
774
+ server: `export const appServer = (): UserConfig => ({
775
+ resolve,
776
+ publicDir: false,
777
+ plugins: [outputBoundary('dist/app/server'), environmentBoundary('app/server')],
778
+ build: {
779
+ emptyOutDir: true,
780
+ lib: {
781
+ entry: resolveWorkspacePath('app/server/main.ts'),
782
+ formats: ['cjs'],
783
+ fileName: () => 'main.cjs',
819
784
  },
820
- options ?? {},
821
- )
785
+ outDir: resolveWorkspacePath('dist/app/server'),
786
+ target: 'node22',
787
+ rolldownOptions: {
788
+ onLog: enforceBuildLog,
789
+ external: (id: string) => id.startsWith('node:'),
790
+ },
791
+ },
792
+ test: {
793
+ name: { label: 'app:server', color: 'green' },
794
+ include: ['tests/app/server/**/*.test.ts'],
795
+ setupFiles: ['./tests/setup.ts', './tests/setupServer.ts'],
796
+ environment: 'node',
797
+ browser: { enabled: false },
798
+ },
799
+ })
822
800
  `
823
801
  }),
824
- policy: `export const policy = (options?: UserConfig): UserConfig =>
825
- mergeConfig(
826
- {
827
- resolve,
828
- test: {
829
- name: { label: 'policy', color: 'white' },
830
- include: ['tests/policy.test.ts'],
831
- setupFiles: ['./tests/setup.ts'],
832
- environment: 'node',
833
- browser: { enabled: false },
834
- },
835
- },
836
- options ?? {},
837
- )
802
+ policy: `export const policy = (): UserConfig => ({
803
+ resolve,
804
+ test: {
805
+ name: { label: 'policy', color: 'white' },
806
+ include: ['tests/policy.test.ts'],
807
+ setupFiles: ['./tests/setup.ts'],
808
+ environment: 'node',
809
+ browser: { enabled: false },
810
+ },
811
+ })
838
812
  `,
839
- config: `export const config = (options?: UserConfig): UserConfig =>
840
- mergeConfig(
841
- {
842
- resolve,
843
- test: {
844
- name: { label: 'config', color: 'yellow' },
845
- include: ['tests/config.test.ts'],
846
- setupFiles: ['./tests/setup.ts'],
847
- environment: 'node',
848
- browser: { enabled: false },
849
- // A config test validates every target wrapper and runs the real linter twice with
850
- // 15-second child caps, so this budget clears both caps and reports their diagnostics.
851
- testTimeout: 45_000,
852
- },
853
- },
854
- options ?? {},
855
- )
813
+ config: `export const config = (): UserConfig => ({
814
+ resolve,
815
+ test: {
816
+ name: { label: 'config', color: 'yellow' },
817
+ include: ['tests/config.test.ts'],
818
+ setupFiles: ['./tests/setup.ts'],
819
+ environment: 'node',
820
+ browser: { enabled: false },
821
+ // A config test validates every target wrapper and runs the real linter twice with
822
+ // 15-second child caps, so this budget clears both caps and reports their diagnostics.
823
+ testTimeout: 45_000,
824
+ },
825
+ })
856
826
  `,
857
- setup: `export const setup = (options?: UserConfig): UserConfig =>
858
- mergeConfig(
859
- {
860
- resolve,
861
- test: {
862
- name: { label: 'setup', color: 'white' },
863
- include: ['tests/setup*.test.ts'],
864
- setupFiles: ['./tests/setup.ts'],
865
- environment: 'node',
866
- browser: { enabled: false },
867
- },
868
- },
869
- options ?? {},
870
- )
827
+ setup: `export const setup = (): UserConfig => ({
828
+ resolve,
829
+ test: {
830
+ name: { label: 'setup', color: 'white' },
831
+ include: ['tests/setup*.test.ts'],
832
+ setupFiles: ['./tests/setup.ts'],
833
+ environment: 'node',
834
+ browser: { enabled: false },
835
+ },
836
+ })
871
837
  `,
872
- guides: `export const guides = (options?: UserConfig): UserConfig =>
873
- mergeConfig(
874
- {
875
- resolve,
876
- test: {
877
- name: { label: 'guides', color: 'green' },
878
- include: ['${GUIDES_TEST_PATH}'],
879
- exclude: ['tests/src/**/*.test.ts', 'tests/app/**/*.test.ts', 'tests/setup.test.ts'],
880
- setupFiles: ['./tests/setup.ts'],
881
- environment: 'node',
882
- browser: { enabled: false },
883
- },
884
- },
885
- options ?? {},
886
- )
838
+ guides: `export const guides = (): UserConfig => ({
839
+ resolve,
840
+ test: {
841
+ name: { label: 'guides', color: 'green' },
842
+ include: ['${GUIDES_TEST_PATH}'],
843
+ exclude: ['tests/src/**/*.test.ts', 'tests/app/**/*.test.ts', 'tests/setup.test.ts'],
844
+ setupFiles: ['./tests/setup.ts'],
845
+ environment: 'node',
846
+ browser: { enabled: false },
847
+ },
848
+ })
887
849
  `,
888
850
  conformance: `// Where this package drifts from the official tooling it stays compatible with.
889
851
  // The subject is this package, so the proof is hermetic and stays in \`npm test\`.
890
- export const conformance = (options?: UserConfig): UserConfig =>
891
- mergeConfig(
892
- {
893
- resolve,
894
- test: {
895
- name: { label: 'conformance', color: 'magenta' },
896
- include: ['${CONFORMANCE_TEST_PATH}'],
897
- setupFiles: ['./tests/setup.ts'],
898
- environment: 'node',
899
- browser: { enabled: false },
900
- },
901
- },
902
- options ?? {},
903
- )
852
+ export const conformance = (): UserConfig => ({
853
+ resolve,
854
+ test: {
855
+ name: { label: 'conformance', color: 'magenta' },
856
+ include: ['${CONFORMANCE_TEST_PATH}'],
857
+ setupFiles: ['./tests/setup.ts'],
858
+ environment: 'node',
859
+ browser: { enabled: false },
860
+ },
861
+ })
904
862
  `,
905
863
  service: `// The live external services this package drives. It starts nothing itself:
906
864
  // \`scripts/service.sh\` provisions, \`tests/setupService.ts\` proves readiness, and
907
865
  // the project stays out of \`npm test\` because a real service answers it.
908
- export const service = (options?: UserConfig): UserConfig =>
909
- mergeConfig(
910
- {
911
- resolve,
912
- test: {
913
- name: { label: 'service', color: 'red' },
914
- include: ['${SERVICE_TEST_INCLUDE}'],
915
- setupFiles: ['./tests/setup.ts', './tests/setupService.ts'],
916
- environment: 'node',
917
- browser: { enabled: false },
918
- testTimeout: 120_000,
919
- hookTimeout: 120_000,
920
- fileParallelism: false,
921
- },
922
- },
923
- options ?? {},
924
- )
866
+ export const service = (): UserConfig => ({
867
+ resolve,
868
+ test: {
869
+ name: { label: 'service', color: 'red' },
870
+ include: ['${SERVICE_TEST_INCLUDE}'],
871
+ setupFiles: ['./tests/setup.ts', './tests/setupService.ts'],
872
+ environment: 'node',
873
+ browser: { enabled: false },
874
+ testTimeout: 120_000,
875
+ hookTimeout: 120_000,
876
+ fileParallelism: false,
877
+ },
878
+ })
925
879
  `,
926
- distribution: `export const distribution = (options?: UserConfig): UserConfig =>
927
- mergeConfig(
928
- {
929
- resolve,
930
- test: {
931
- name: { label: 'distribution', color: 'cyan' },
932
- include: ['${DISTRIBUTION_TEST_PATH}'],
933
- setupFiles: ['./tests/setup.ts'],
934
- environment: 'node',
935
- testTimeout: 120_000,
936
- hookTimeout: 120_000,
937
- fileParallelism: false,
938
- },
939
- },
940
- options ?? {},
941
- )
880
+ distribution: `export const distribution = (): UserConfig => ({
881
+ resolve,
882
+ test: {
883
+ name: { label: 'distribution', color: 'cyan' },
884
+ include: ['${DISTRIBUTION_TEST_PATH}'],
885
+ setupFiles: ['./tests/setup.ts'],
886
+ environment: 'node',
887
+ testTimeout: 120_000,
888
+ hookTimeout: 120_000,
889
+ fileParallelism: false,
890
+ },
891
+ })
942
892
  `,
943
893
  probe: `// A workbench, not a proof. No gate selects this project. Run in test mode by the
944
894
  // \`test:probe\` script, it collects \`tmp/probe/**/*.test.ts\`. Run in benchmark mode by the
945
895
  // \`test:bench\` script, the same workbench also collects \`tests/**/*.test.ts\` for a \`bench\` block,
946
896
  // so a suite may carry a bench beside its ordinary tests without a second project. The mode
947
897
  // guard around each \`bench\` call keeps it out of test mode, so it never executes there.
948
- export const probe = (options?: UserConfig): UserConfig =>
949
- mergeConfig(
950
- {
951
- resolve,
952
- test: {
953
- name: { label: 'probe', color: 'gray' },
954
- include: ['tmp/probe/**/*.test.ts'],
955
- setupFiles: ['./tests/setup.ts'],
956
- environment: 'node',
957
- browser: { enabled: false },
958
- fileParallelism: false,
959
- pool: 'threads',
960
- benchmark: { include: ['tmp/probe/**/*.test.ts', 'tests/**/*.test.ts'] },
961
- },
962
- },
963
- options ?? {},
964
- )
898
+ export const probe = (): UserConfig => ({
899
+ resolve,
900
+ test: {
901
+ name: { label: 'probe', color: 'black' },
902
+ include: ['tmp/probe/**/*.test.ts'],
903
+ setupFiles: ['./tests/setup.ts'],
904
+ environment: 'node',
905
+ browser: { enabled: false },
906
+ fileParallelism: false,
907
+ pool: 'threads',
908
+ benchmark: { include: ['tmp/probe/**/*.test.ts', 'tests/**/*.test.ts'] },
909
+ },
910
+ })
965
911
  `,
966
- integration: `export const integration = (options?: UserConfig): UserConfig =>
967
- mergeConfig(
968
- {
969
- resolve,
970
- test: {
971
- name: { label: 'integration', color: 'blue' },
972
- include: ['${INTEGRATION_TEST_PATH}'],
973
- setupFiles: ['./tests/setup.ts'],
974
- {{global}} environment: 'node',
975
- },
976
- },
977
- options ?? {},
978
- )
912
+ integration: `export const integration = (): UserConfig => ({
913
+ resolve,
914
+ test: {
915
+ name: { label: 'integration', color: 'blue' },
916
+ include: ['${INTEGRATION_TEST_PATH}'],
917
+ setupFiles: ['./tests/setup.ts'],
918
+ {{global}} environment: 'node',
919
+ },
920
+ })
979
921
  `
980
922
  }),
981
923
  tsconfigs: Object.freeze({
@@ -1103,13 +1045,13 @@ export const probe = (options?: UserConfig): UserConfig =>
1103
1045
  }),
1104
1046
  vites: Object.freeze({
1105
1047
  src: Object.freeze({
1106
- core: `import { defineConfig } from 'vite'
1048
+ core: `import { defineConfig, mergeConfig } from 'vite'
1107
1049
  import dts from 'vite-plugin-dts'
1108
1050
  import { environmentBoundary, outputBoundary } from '../helpers.js'
1109
1051
  import { peers, srcCore, resolveWorkspacePath } from '../../vite.config.ts'
1110
1052
 
1111
1053
  export default defineConfig(
1112
- srcCore({
1054
+ mergeConfig(srcCore(), {
1113
1055
  publicDir: false,
1114
1056
  plugins: [
1115
1057
  outputBoundary('dist/src/core'),
@@ -1131,7 +1073,7 @@ export default defineConfig(
1131
1073
  lib: {
1132
1074
  entry: resolveWorkspacePath('src/core/index.ts'),
1133
1075
  formats: ['es', 'cjs'],
1134
- fileName: (format) => (format === 'es' ? 'index.js' : 'index.cjs'),
1076
+ fileName: (format: string) => (format === 'es' ? 'index.js' : 'index.cjs'),
1135
1077
  },
1136
1078
  outDir: 'dist/src/core',
1137
1079
  rolldownOptions: {
@@ -1144,17 +1086,17 @@ export default defineConfig(
1144
1086
  }),
1145
1087
  )
1146
1088
  `,
1147
- browser: `import { defineConfig } from 'vite'
1089
+ browser: `import { defineConfig, mergeConfig } from 'vite'
1148
1090
  import dts from 'vite-plugin-dts'
1149
1091
  import { srcBrowser, resolveWorkspacePath } from '../../vite.config.ts'
1150
1092
 
1151
1093
  // vite-plugin-dts rolls this face into one declaration, and the roll-up reaches
1152
1094
  // src/core through a relative source path the tarball does not carry. The path
1153
1095
  // keeps each source module's own depth, so a module in a browser subfolder emits
1154
- // one that leaves dist/src entirely. The rewrite below externalizes core through
1155
- // the package's own published root export, on the final roll-up only.
1096
+ // one that leaves dist/src entirely. The following rewrite externalizes core
1097
+ // through the package's own published root export, on the final roll-up only.
1156
1098
  export default defineConfig(
1157
- srcBrowser({
1099
+ mergeConfig(srcBrowser(), {
1158
1100
  plugins: [
1159
1101
  dts({
1160
1102
  tsconfigPath: resolveWorkspacePath('configs/src/tsconfig.browser.json'),
@@ -1169,16 +1111,16 @@ export default defineConfig(
1169
1111
  }),
1170
1112
  )
1171
1113
  `,
1172
- server: `import { defineConfig } from 'vite'
1114
+ server: `import { defineConfig, mergeConfig } from 'vite'
1173
1115
  import dts from 'vite-plugin-dts'
1174
1116
  import { srcServer, resolveWorkspacePath } from '../../vite.config.ts'
1175
1117
 
1176
1118
  // vite-plugin-dts rolls this face into one declaration, and the roll-up reaches
1177
- // src/core through a relative source path the tarball does not carry. The rewrite
1178
- // below externalizes core through the package's own published root export, on the
1179
- // final roll-up only.
1119
+ // src/core through a relative source path the tarball does not carry. The
1120
+ // following rewrite externalizes core through the package's own published root
1121
+ // export, on the final roll-up only.
1180
1122
  export default defineConfig(
1181
- srcServer({
1123
+ mergeConfig(srcServer(), {
1182
1124
  plugins: [
1183
1125
  dts({
1184
1126
  tsconfigPath: resolveWorkspacePath('configs/src/tsconfig.server.json'),
@@ -1194,7 +1136,7 @@ export default defineConfig(
1194
1136
  )
1195
1137
  `
1196
1138
  }),
1197
- bin: `import { defineConfig } from 'vite'
1139
+ bin: `import { defineConfig, mergeConfig } from 'vite'
1198
1140
  import { srcBin } from '../../vite.config.ts'
1199
1141
 
1200
1142
  // The \`scaffold\` executable build — a single ESM lib file, no declarations (an
@@ -1203,7 +1145,7 @@ import { srcBin } from '../../vite.config.ts'
1203
1145
  // \`output.paths\` rewriting the externalized \`@src/*\` specifiers to the built sibling
1204
1146
  // src environments (relative to \`dist/bin/\`), so the emitted bin resolves at runtime.
1205
1147
  export default defineConfig(
1206
- srcBin({
1148
+ mergeConfig(srcBin(), {
1207
1149
  build: {
1208
1150
  rolldownOptions: {
1209
1151
  output: {
@@ -1641,8 +1583,8 @@ const SHELL = process.platform === 'win32'
1641
1583
  // Release is the publish gate, so evidence it cannot obtain fails there and skips
1642
1584
  // everywhere else: a gate that passes on missing evidence proves nothing.
1643
1585
  const RELEASE = import.meta.env.MODE === 'release'
1644
- // The built output directory a browser face is published from. Every selection here
1645
- // reads this prefix off the export TARGET and never off the subpath name. A
1586
+ // The built output directory convention a browser face may publish from. Every
1587
+ // selection reads this prefix off the export target and never off the subpath name. A
1646
1588
  // workspace whose only published face is the browser one publishes that face at the
1647
1589
  // root subpath, so a rule keyed on the subpath name drives a browser bundle through
1648
1590
  // Node and the miss is silent.
@@ -1930,11 +1872,33 @@ function readPackageType(installed: string, target: string): unknown {
1930
1872
  }
1931
1873
  }
1932
1874
 
1933
- // Whether the declaration selected by a typed CommonJS consumer admits that entry
1934
- // to its compile probe. A \`.d.cts\` declaration admits and a \`.d.mts\`
1935
- // declaration refuses. A \`.d.ts\` declaration takes its own nearest package scope.
1936
- // Runtime target format remains the runtime drive's separate question.
1875
+ function resolvesBrowser(entry: unknown): boolean {
1876
+ const module = resolveTarget(entry, RUNTIME_CONDITIONS.browser)
1877
+ if (module !== undefined && module.startsWith(BROWSER_OUTPUT)) return true
1878
+ if (module === undefined) return false
1879
+ const imported = resolveTarget(entry, RUNTIME_CONDITIONS.module)
1880
+ const required = resolveTarget(entry, RUNTIME_CONDITIONS.commonjs)
1881
+ return module !== imported && module !== required
1882
+ }
1883
+
1884
+ // Whether the target selected by Node's CommonJS conditions is a module require can
1885
+ // load. A JavaScript target takes its own nearest package scope. Native addons and
1886
+ // extensionless targets have their own CommonJS handlers.
1937
1887
  function resolvesCommonJS(entry: unknown, installed: string): boolean {
1888
+ const target = resolveTarget(entry, RUNTIME_CONDITIONS.commonjs)
1889
+ if (target === undefined) return false
1890
+ const name = target.slice(target.lastIndexOf('/') + 1)
1891
+ if (name.endsWith('.cjs')) return true
1892
+ if (name.endsWith('.mjs')) return false
1893
+ if (name.endsWith('.node')) return true
1894
+ if (!name.includes('.')) return true
1895
+ return name.endsWith('.js') && readPackageType(installed, target) !== 'module'
1896
+ }
1897
+
1898
+ // Whether the declaration selected by a typed CommonJS consumer admits that entry.
1899
+ // A \`.d.cts\` declaration admits and a \`.d.mts\` declaration refuses. A \`.d.ts\`
1900
+ // declaration takes its own nearest package scope.
1901
+ function declaresCommonJS(entry: unknown, installed: string): boolean {
1938
1902
  const declaration = resolveDeclaration(entry, DECLARATION_CONDITIONS.commonjs, installed)
1939
1903
  if (declaration === undefined) return false
1940
1904
  if (declaration.endsWith('.d.cts')) return true
@@ -1997,13 +1961,13 @@ function selectEntries(entries: readonly Entry[], conditions: readonly string[])
1997
1961
  // Require-loadable entries that declare CommonJS support but a typed CommonJS
1998
1962
  // consumer cannot compile against. A default branch resolving under the require
1999
1963
  // condition set makes no CommonJS claim.
2000
- function selectUntypable(entries: readonly Entry[]): readonly Entry[] {
1964
+ function selectUntypable(entries: readonly Entry[], installed: string): readonly Entry[] {
2001
1965
  return entries.filter(
2002
1966
  (entry) =>
2003
1967
  entry.required &&
2004
1968
  isRecord(entry.mapping) &&
2005
1969
  Object.hasOwn(entry.mapping, 'require') &&
2006
- !entry.commonjs,
1970
+ !declaresCommonJS(entry.mapping, installed),
2007
1971
  )
2008
1972
  }
2009
1973
 
@@ -2136,9 +2100,11 @@ function buildStage(): Stage {
2136
2100
  continue
2137
2101
  }
2138
2102
  const imported = resolveTarget(entry, RUNTIME_CONDITIONS.module)
2139
- const commonjs = resolvesCommonJS(entry, installed)
2140
- const required = resolveTarget(entry, RUNTIME_CONDITIONS.commonjs) !== undefined
2141
- const module = resolveTarget(entry, RUNTIME_CONDITIONS.browser)
2103
+ const requiredTarget = resolveTarget(entry, RUNTIME_CONDITIONS.commonjs)
2104
+ const browserTarget = resolveTarget(entry, RUNTIME_CONDITIONS.browser)
2105
+ const browser = resolvesBrowser(entry)
2106
+ const required = requiredTarget !== undefined && !(browser && requiredTarget === browserTarget)
2107
+ const commonjs = required && resolvesCommonJS(entry, installed)
2142
2108
  entries.push({
2143
2109
  subpath,
2144
2110
  specifier: subpath === '.' ? name : \`\${name}\${subpath.slice(1)}\`,
@@ -2150,8 +2116,8 @@ function buildStage(): Stage {
2150
2116
  browser:
2151
2117
  declaration.browser === undefined ? undefined : join(installed, declaration.browser),
2152
2118
  },
2153
- browser: module !== undefined && module.startsWith(BROWSER_OUTPUT),
2154
- module: imported !== undefined,
2119
+ browser,
2120
+ module: imported !== undefined && !(browser && imported === browserTarget),
2155
2121
  commonjs,
2156
2122
  required,
2157
2123
  })
@@ -2192,6 +2158,74 @@ function openStage(): Stage | undefined {
2192
2158
  const STAGE = openStage()
2193
2159
  const STAGED = STAGE !== undefined
2194
2160
 
2161
+ describe('distribution classifiers', () => {
2162
+ it('classifies synthetic export mappings without a registry stage', () => {
2163
+ const root = join(SCRATCH, 'classifiers')
2164
+ writeFile(
2165
+ join(root, 'package.json'),
2166
+ JSON.stringify({
2167
+ type: 'commonjs',
2168
+ exports: {
2169
+ condition: { browser: './b.js', default: './n.js' },
2170
+ convention: { default: './dist/src/browser/index.js' },
2171
+ universal: { default: './shared.js' },
2172
+ 'import-shared': {
2173
+ browser: './shared.mjs',
2174
+ import: './shared.mjs',
2175
+ default: './node.js',
2176
+ },
2177
+ 'require-shared': {
2178
+ browser: './shared.cjs',
2179
+ require: './shared.cjs',
2180
+ default: './node.js',
2181
+ },
2182
+ node: { node: './node.js', default: './node.js' },
2183
+ silent: { 'module-sync': './x.cjs', import: './x.mjs' },
2184
+ module: { require: './x.mjs' },
2185
+ 'nested-module': { require: './module/x.js' },
2186
+ 'nested-commonjs': { require: './commonjs/x.js' },
2187
+ esm: { import: './x.mjs' },
2188
+ },
2189
+ }),
2190
+ )
2191
+ writeFile(join(root, 'module/package.json'), '{ "type": "module" }\\n')
2192
+ writeFile(join(root, 'commonjs/package.json'), '{ "type": "commonjs" }\\n')
2193
+ const manifest = readJson(join(root, 'package.json'))
2194
+ if (!isRecord(manifest) || !isRecord(manifest.exports)) {
2195
+ throw new Error('The classifier fixture declares no exports map')
2196
+ }
2197
+ const mappings = manifest.exports
2198
+ expect({
2199
+ condition: resolvesBrowser(mappings.condition),
2200
+ convention: resolvesBrowser(mappings.convention),
2201
+ universal: resolvesBrowser(mappings.universal),
2202
+ import: resolvesBrowser(mappings['import-shared']),
2203
+ require: resolvesBrowser(mappings['require-shared']),
2204
+ node: resolvesBrowser(mappings.node),
2205
+ }).toStrictEqual({
2206
+ condition: true,
2207
+ convention: true,
2208
+ universal: false,
2209
+ import: false,
2210
+ require: false,
2211
+ node: false,
2212
+ })
2213
+ expect({
2214
+ silent: resolvesCommonJS(mappings.silent, root),
2215
+ module: resolvesCommonJS(mappings.module, root),
2216
+ nestedModule: resolvesCommonJS(mappings['nested-module'], root),
2217
+ nestedCommonJS: resolvesCommonJS(mappings['nested-commonjs'], root),
2218
+ esm: resolvesCommonJS(mappings.esm, root),
2219
+ }).toStrictEqual({
2220
+ silent: true,
2221
+ module: false,
2222
+ nestedModule: false,
2223
+ nestedCommonJS: true,
2224
+ esm: false,
2225
+ })
2226
+ })
2227
+ })
2228
+
2195
2229
  // The staged consumer, or a skip naming what the run could not reach. \`it.skipIf\`
2196
2230
  // carries no reason, so the gate sits here where the test context can state one.
2197
2231
  function requireStage(context: TestContext): Stage {
@@ -2239,7 +2273,7 @@ describe('installed package consumer', () => {
2239
2273
  (entry) => !entry.module && !entry.required && !entry.browser,
2240
2274
  )
2241
2275
  expect(unreachable.map((entry) => entry.subpath)).toStrictEqual([])
2242
- const untypable = selectUntypable(stage.entries)
2276
+ const untypable = selectUntypable(stage.entries, stage.installed)
2243
2277
  expect(untypable.map((entry) => entry.subpath)).toStrictEqual([])
2244
2278
  })
2245
2279
 
@@ -2284,7 +2318,7 @@ describe('installed package consumer', () => {
2284
2318
 
2285
2319
  for (const entry of STAGE?.entries ?? []) {
2286
2320
  describe(\`installed entry \${entry.subpath}\`, () => {
2287
- it.runIf(entry.module && !entry.browser)(
2321
+ it.runIf(entry.module)(
2288
2322
  'publishes what it declares to a Node import, and no more',
2289
2323
  (context) => {
2290
2324
  const declaration = entry.declaration.module
@@ -2296,7 +2330,7 @@ for (const entry of STAGE?.entries ?? []) {
2296
2330
  },
2297
2331
  )
2298
2332
 
2299
- it.runIf(!entry.browser && entry.required)(
2333
+ it.runIf(entry.required)(
2300
2334
  'publishes what it declares to a Node require, and no more',
2301
2335
  (context) => {
2302
2336
  const declaration = entry.declaration.commonjs
@@ -4318,7 +4352,7 @@ function blueprintToScripts(blueprint) {
4318
4352
  scripts["serve:build"] = "npm run build:app:server && npm run serve";
4319
4353
  }
4320
4354
  if (publishes) {
4321
- scripts.prepack = scripts.build;
4355
+ scripts.prepack = "npm run build";
4322
4356
  scripts.prepublishOnly = [
4323
4357
  "npm run format:check && npm run lint:check && npm run check && npm run build && npm test",
4324
4358
  RELEASE_PROOF_COMMAND,
@@ -4331,19 +4365,21 @@ function blueprintToScripts(blueprint) {
4331
4365
  * Project a blueprint into the manifest scripts a region write may replace.
4332
4366
  *
4333
4367
  * @param blueprint - The workspace specification.
4334
- * @returns One entry per writable script, or none when the workspace publishes
4335
- * nothing and therefore declares neither script.
4368
+ * @returns One entry per writable script.
4336
4369
  *
4337
4370
  * @remarks
4338
- * Publishing is what selects these scripts, so a private workspace answers an
4339
- * empty region and the write leaves its manifest alone.
4340
- *
4341
- * `accepted` carries the predecessor a target can hold before this package
4342
- * generated the packed-package proof: the same gate chain without
4371
+ * Every direct `test:<project>` script is writable, together with the probe and
4372
+ * benchmark workbench scripts. Publishing adds the pack and publication
4373
+ * lifecycle scripts. Aggregate test scripts and maintainer-owned gate chains
4374
+ * stay outside the region.
4375
+ *
4376
+ * `accepted` carries each generated predecessor the region can replace. The
4377
+ * pack hook accepts the build chain emitted before it delegated to `build`. The
4378
+ * publication hook accepts the same gate chain without
4343
4379
  * {@link RELEASE_PROOF_COMMAND}. The value being written is always writable, so
4344
- * it is not repeated there. Any other value is a chain the workspace author
4345
- * customized, and {@link replaceManifestScripts} refuses the whole region
4346
- * rather than taking it.
4380
+ * it is not repeated there. Any other value is a script the workspace author
4381
+ * customized, and {@link replaceManifestScripts} retains it while writing the
4382
+ * other named scripts independently.
4347
4383
  *
4348
4384
  * @example
4349
4385
  * ```ts
@@ -4351,23 +4387,36 @@ function blueprintToScripts(blueprint) {
4351
4387
  *
4352
4388
  * const blueprint = createBlueprint('router', { src: ['core'] })
4353
4389
  *
4354
- * blueprintToWritableScripts(blueprint)[0]?.name // 'test:distribution'
4390
+ * blueprintToWritableScripts(blueprint)[0]?.name // 'test:src:core'
4355
4391
  * ```
4356
4392
  */
4357
4393
  function blueprintToWritableScripts(blueprint) {
4358
4394
  const scripts = blueprintToScripts(blueprint);
4359
- const distribution = scripts["test:distribution"];
4395
+ const writable = [];
4396
+ for (const [name, command] of Object.entries(scripts)) {
4397
+ if (!name.startsWith("test:") || name === "test:src" || name === "test:app") continue;
4398
+ writable.push({
4399
+ name,
4400
+ command,
4401
+ accepted: []
4402
+ });
4403
+ }
4404
+ const prepack = scripts.prepack;
4405
+ if (prepack !== void 0) {
4406
+ const predecessor = scripts.build;
4407
+ writable.push({
4408
+ name: "prepack",
4409
+ command: prepack,
4410
+ accepted: predecessor === void 0 ? [] : [predecessor]
4411
+ });
4412
+ }
4360
4413
  const prepublish = scripts.prepublishOnly;
4361
- if (distribution === void 0 || prepublish === void 0) return [];
4362
- return [{
4363
- name: "test:distribution",
4364
- command: distribution,
4365
- accepted: []
4366
- }, {
4414
+ if (prepublish !== void 0) writable.push({
4367
4415
  name: "prepublishOnly",
4368
4416
  command: prepublish,
4369
4417
  accepted: [prepublish.replace(` && ${RELEASE_PROOF_COMMAND}`, "")]
4370
- }];
4418
+ });
4419
+ return writable;
4371
4420
  }
4372
4421
  /**
4373
4422
  * Compile a blueprint into its `package.json` content.
@@ -4550,14 +4599,14 @@ function blueprintToRootVite(blueprint) {
4550
4599
  const core = blueprint.src.includes("core");
4551
4600
  factories.push((0, _orkestrel_template.fillTemplate)(CONFIG_TEMPLATES.factories.src.browser, {
4552
4601
  external: core ? `external: (id: string) =>
4553
- id === '@src/core' ||
4554
- id.startsWith('@orkestrel/') ||
4555
- peers.some((peer) => id === peer || id.startsWith(peer + '/')),` : `external: (id: string) =>
4556
- id.startsWith('@orkestrel/') ||
4557
- peers.some((peer) => id === peer || id.startsWith(peer + '/')),`,
4558
- output: core ? " output: { paths: { '@src/core': '../core/index.js' } }," : " output: {},",
4559
- exclude: core ? " exclude: ['tests/src/core/**/*.test.ts'],\n" : "",
4560
- global: blueprint.global ? " globalSetup: ['./tests/setupGlobal.ts'],\n" : ""
4602
+ id === '@src/core' ||
4603
+ id.startsWith('@orkestrel/') ||
4604
+ peers.some((peer) => id === peer || id.startsWith(peer + '/')),` : `external: (id: string) =>
4605
+ id.startsWith('@orkestrel/') ||
4606
+ peers.some((peer) => id === peer || id.startsWith(peer + '/')),`,
4607
+ output: core ? " output: { paths: { '@src/core': '../core/index.js' } }," : " output: {},",
4608
+ exclude: core ? " exclude: ['tests/src/core/**/*.test.ts'],\n" : "",
4609
+ global: blueprint.global ? " globalSetup: ['./tests/setupGlobal.ts'],\n" : ""
4561
4610
  }));
4562
4611
  projects.push("srcBrowser");
4563
4612
  }
@@ -4565,26 +4614,26 @@ function blueprintToRootVite(blueprint) {
4565
4614
  const core = blueprint.src.includes("core");
4566
4615
  factories.push((0, _orkestrel_template.fillTemplate)(CONFIG_TEMPLATES.factories.src.server, {
4567
4616
  external: core ? `external: (id: string) =>
4568
- id === '@src/core' ||
4569
- id.startsWith('node:') ||
4570
- id.startsWith('@orkestrel/') ||
4571
- peers.some((peer) => id === peer || id.startsWith(peer + '/')),` : `external: (id: string) =>
4572
- id.startsWith('node:') ||
4573
- id.startsWith('@orkestrel/') ||
4574
- peers.some((peer) => id === peer || id.startsWith(peer + '/')),`,
4575
- output: core ? `\t\t\t\t\toutput: [
4576
- {
4577
- format: 'es',
4578
- entryFileNames: 'index.js',
4579
- paths: { '@src/core': '../core/index.js' },
4580
- },
4581
- {
4582
- format: 'cjs',
4583
- entryFileNames: 'index.cjs',
4584
- paths: { '@src/core': '../core/index.cjs' },
4585
- },
4586
- ],` : " output: {},",
4587
- exclude: core ? " exclude: ['tests/src/core/**/*.test.ts'],\n" : ""
4617
+ id === '@src/core' ||
4618
+ id.startsWith('node:') ||
4619
+ id.startsWith('@orkestrel/') ||
4620
+ peers.some((peer) => id === peer || id.startsWith(peer + '/')),` : `external: (id: string) =>
4621
+ id.startsWith('node:') ||
4622
+ id.startsWith('@orkestrel/') ||
4623
+ peers.some((peer) => id === peer || id.startsWith(peer + '/')),`,
4624
+ output: core ? `\t\t\toutput: [
4625
+ {
4626
+ format: 'es',
4627
+ entryFileNames: 'index.js',
4628
+ paths: { '@src/core': '../core/index.js' },
4629
+ },
4630
+ {
4631
+ format: 'cjs',
4632
+ entryFileNames: 'index.cjs',
4633
+ paths: { '@src/core': '../core/index.cjs' },
4634
+ },
4635
+ ],` : " output: {},",
4636
+ exclude: core ? " exclude: ['tests/src/core/**/*.test.ts'],\n" : ""
4588
4637
  }));
4589
4638
  projects.push("srcServer");
4590
4639
  }
@@ -4679,7 +4728,7 @@ export function appShowcase(): UserConfig {
4679
4728
  projects.push("distribution");
4680
4729
  }
4681
4730
  if (blueprint.integration) {
4682
- factories.push((0, _orkestrel_template.fillTemplate)(CONFIG_TEMPLATES.factories.integration, { global: blueprint.global ? " globalSetup: ['./tests/setupGlobal.ts'],\n" : "" }));
4731
+ factories.push((0, _orkestrel_template.fillTemplate)(CONFIG_TEMPLATES.factories.integration, { global: blueprint.global ? " globalSetup: ['./tests/setupGlobal.ts'],\n" : "" }));
4683
4732
  projects.push("integration");
4684
4733
  }
4685
4734
  factories.push(CONFIG_TEMPLATES.factories.probe);
@@ -5382,24 +5431,23 @@ function replaceManifestRanges(manifest, pins) {
5382
5431
  *
5383
5432
  * @param manifest - The manifest text to compile.
5384
5433
  * @param scripts - The scripts to write, each with the predecessors it accepts.
5385
- * @returns The manifest carrying every named script, or `undefined` when a
5386
- * named script holds a value outside what it accepts, or when the text carries
5387
- * no readable `scripts` object to write into.
5434
+ * @returns The manifest carrying every absent or accepted named script and
5435
+ * retaining every differing string value, or `undefined` when a planned key
5436
+ * holds a non-string value or the text carries no readable `scripts` object to
5437
+ * write into.
5388
5438
  *
5389
5439
  * @remarks
5390
5440
  * The compiler replaces values in place instead of serializing the manifest, so
5391
5441
  * description, keywords, dependencies, key order, indentation, and every byte
5392
5442
  * outside the replaced ranges survive. A named script the manifest already
5393
- * declares is overwritten only when its value is the one being written or one
5394
- * of its {@link ManifestScript.accepted} predecessors; anything else is a chain
5395
- * the workspace author customized, and the whole region is refused without a
5396
- * byte moving. A named script the manifest does not declare is appended after
5397
- * the last declared script, copying that section's indentation. A region
5398
- * declaring nothing takes every named script as its first entries, indented
5399
- * from the line its own opening brace sits on.
5400
- *
5401
- * The refusal is whole rather than per script, so a manifest never ends up
5402
- * holding one written script beside one refused one.
5443
+ * declares is overwritten only when its value is one of its
5444
+ * {@link ManifestScript.accepted} predecessors. The planned value stands. Any
5445
+ * other string is a chain the workspace author customized, so it stays
5446
+ * byte-identical while the other named scripts are written independently. A
5447
+ * named script the manifest does not declare is appended after the last
5448
+ * declared script, copying that section's indentation. A region declaring
5449
+ * nothing takes every named script as its first entries, indented from the line
5450
+ * its own opening brace sits on.
5403
5451
  *
5404
5452
  * @example
5405
5453
  * ```ts
@@ -5421,7 +5469,6 @@ function replaceManifestScripts(manifest, scripts) {
5421
5469
  if (!Object.hasOwn(declared, script.name)) continue;
5422
5470
  const value = declared[script.name];
5423
5471
  if (!(0, _orkestrel_contract.isString)(value)) return void 0;
5424
- if (value !== script.command && !script.accepted.includes(value)) return void 0;
5425
5472
  }
5426
5473
  let depth = 0;
5427
5474
  let cursor = 0;
@@ -5549,6 +5596,8 @@ function replaceManifestScripts(manifest, scripts) {
5549
5596
  const script = scripts.find((entry) => entry.name === key);
5550
5597
  if (script === void 0) continue;
5551
5598
  written.add(script.name);
5599
+ const value = declared[script.name];
5600
+ if (value === script.command || !(0, _orkestrel_contract.isString)(value) || !script.accepted.includes(value)) continue;
5552
5601
  edits.push({
5553
5602
  start: valueStart,
5554
5603
  end: valueEnd + 1,