@ykdz/template 0.0.33 → 0.0.36

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 (98) hide show
  1. package/dist/application.d.ts +2 -1
  2. package/dist/application.js +64 -75
  3. package/dist/main.js +6 -2
  4. package/node_modules/@ykdz/template-builtin-presets/dist/src/foundation.d.ts +50 -36
  5. package/node_modules/@ykdz/template-builtin-presets/dist/src/foundation.js +970 -365
  6. package/node_modules/@ykdz/template-builtin-presets/dist/src/generation-record.d.ts +24 -0
  7. package/node_modules/@ykdz/template-builtin-presets/dist/src/generation-record.js +154 -0
  8. package/node_modules/@ykdz/template-builtin-presets/dist/src/index.d.ts +2 -2
  9. package/node_modules/@ykdz/template-builtin-presets/dist/src/index.js +1 -1
  10. package/node_modules/@ykdz/template-builtin-presets/dist/src/rust-bin/definition.d.ts +31 -2
  11. package/node_modules/@ykdz/template-builtin-presets/dist/src/rust-bin/definition.js +29 -33
  12. package/node_modules/@ykdz/template-builtin-presets/dist/src/shared/development-container.d.ts +1 -0
  13. package/node_modules/@ykdz/template-builtin-presets/dist/src/shared/development-container.js +17 -0
  14. package/node_modules/@ykdz/template-builtin-presets/dist/src/shared/typescript.d.ts +4 -3
  15. package/node_modules/@ykdz/template-builtin-presets/dist/src/shared/typescript.js +9 -5
  16. package/node_modules/@ykdz/template-builtin-presets/dist/src/shared/vue.d.ts +1 -1
  17. package/node_modules/@ykdz/template-builtin-presets/dist/src/shared/vue.js +1 -2
  18. package/node_modules/@ykdz/template-builtin-presets/dist/src/ts-cli/definition.d.ts +31 -2
  19. package/node_modules/@ykdz/template-builtin-presets/dist/src/ts-cli/definition.js +79 -58
  20. package/node_modules/@ykdz/template-builtin-presets/dist/src/ts-lib/definition.d.ts +31 -2
  21. package/node_modules/@ykdz/template-builtin-presets/dist/src/ts-lib/definition.js +31 -23
  22. package/node_modules/@ykdz/template-builtin-presets/dist/src/vike-app/definition.d.ts +22 -2
  23. package/node_modules/@ykdz/template-builtin-presets/dist/src/vike-app/definition.js +61 -35
  24. package/node_modules/@ykdz/template-builtin-presets/dist/src/vue-app/definition.d.ts +26 -2
  25. package/node_modules/@ykdz/template-builtin-presets/dist/src/vue-app/definition.js +19 -8
  26. package/node_modules/@ykdz/template-builtin-presets/dist/src/vue-hono-app/definition.d.ts +22 -2
  27. package/node_modules/@ykdz/template-builtin-presets/dist/src/vue-hono-app/definition.js +31 -21
  28. package/node_modules/@ykdz/template-builtin-presets/package.json +12 -11
  29. package/node_modules/@ykdz/template-builtin-presets/templates/foundation/.github/workflows/check-deployment-diagnostics.yml +1 -1
  30. package/node_modules/@ykdz/template-builtin-presets/templates/foundation/.github/workflows/check-deployment.yml +1 -1
  31. package/node_modules/@ykdz/template-builtin-presets/templates/foundation/.pnpmfile.mjs +19 -0
  32. package/node_modules/@ykdz/template-builtin-presets/templates/foundation/gitignore +1 -0
  33. package/node_modules/@ykdz/template-builtin-presets/templates/foundation/tsconfig.packing-hook.json +8 -0
  34. package/node_modules/@ykdz/template-builtin-presets/templates/shared/devcontainer/github-cli.Dockerfile +9 -0
  35. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/publication/CHANGELOG.md.template +17 -0
  36. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/publication/RELEASING.md +17 -0
  37. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/publication/artifact.ts +1271 -0
  38. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/publication/changelog.ts +283 -0
  39. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/publication/check-artifact.ts +99 -0
  40. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/publication/check-readiness.ts +66 -0
  41. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/publication/cli-command-identity.ts +4 -0
  42. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/publication/handoff.ts +450 -0
  43. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/publication/publish.ts +483 -0
  44. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/publication/readiness.ts +1125 -0
  45. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/publication/release.ts +819 -0
  46. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/publication/release.yml +119 -0
  47. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/publication/root-tsconfig.json +13 -0
  48. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/publication/tsconfig.json +4 -0
  49. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/publication/turbo.json +6 -0
  50. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/publication-setup/README.md +48 -0
  51. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/publication-setup/assets/CHANGELOG.md.template +17 -0
  52. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/publication-setup/assets/LICENSE-APACHE-2.0.txt +202 -0
  53. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/publication-setup/assets/LICENSE-MIT.txt +21 -0
  54. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/publication-setup/assets/README.md.template +5 -0
  55. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/publication-setup/bridge.ts +3336 -0
  56. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/publication-setup/setup.sh +221 -0
  57. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/src/cli-command-identity.ts +133 -0
  58. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/src/cli.ts +4 -3
  59. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/src/main.ts +5 -4
  60. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/test/integration/command.test.ts +14 -13
  61. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/test/unit/cli-command-identity.test.ts +76 -0
  62. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/tsconfig.build.json +2 -0
  63. package/node_modules/@ykdz/template-builtin-presets/templates/vike-app/db/src/readiness.ts +1 -1
  64. package/node_modules/@ykdz/template-builtin-presets/templates/vike-app/db/test/global-setup.ts +21 -0
  65. package/node_modules/@ykdz/template-builtin-presets/templates/vike-app/db/tsconfig.json +6 -1
  66. package/node_modules/@ykdz/template-builtin-presets/templates/vike-app/db/vitest.config.ts +7 -0
  67. package/node_modules/@ykdz/template-builtin-presets/templates/vike-app/db-migrations/drizzle.config.ts +5 -1
  68. package/node_modules/@ykdz/template-builtin-presets/templates/vike-app/web/playwright.config.ts +102 -22
  69. package/node_modules/@ykdz/template-builtin-presets/templates/vike-app/web/test/playwright-teardown.ts +12 -0
  70. package/node_modules/@ykdz/template-builtin-presets/templates/vike-app/web/vite.config.ts +39 -1
  71. package/node_modules/@ykdz/template-builtin-presets/templates/vue-app/playwright.config.ts +48 -7
  72. package/node_modules/@ykdz/template-builtin-presets/templates/vue-hono-app/web/playwright.config.ts +59 -8
  73. package/node_modules/@ykdz/template-core/dist/module-graph.d.ts +15 -53
  74. package/node_modules/@ykdz/template-core/dist/module-graph.js +134 -101
  75. package/node_modules/@ykdz/template-core/dist/package-contribution.d.ts +13 -1
  76. package/node_modules/@ykdz/template-core/dist/package-contribution.js +92 -0
  77. package/node_modules/@ykdz/template-core/dist/pnpm-workspace.yaml +14 -10
  78. package/node_modules/@ykdz/template-core/dist/preset-definition.d.ts +71 -13
  79. package/node_modules/@ykdz/template-core/dist/preset-definition.js +16 -1
  80. package/node_modules/@ykdz/template-core/dist/project-blueprint.d.ts +56 -0
  81. package/node_modules/@ykdz/template-core/dist/project-blueprint.js +271 -0
  82. package/node_modules/@ykdz/template-core/dist/project-linking-v2.d.ts +2 -2
  83. package/node_modules/@ykdz/template-core/dist/project-linking-v2.js +2 -2
  84. package/node_modules/@ykdz/template-core/dist/project-projection.d.ts +2 -1
  85. package/node_modules/@ykdz/template-core/dist/project-projection.js +107 -20
  86. package/node_modules/@ykdz/template-core/dist/renderer.d.ts +0 -2
  87. package/node_modules/@ykdz/template-core/dist/renderer.js +17 -38
  88. package/node_modules/@ykdz/template-core/dist/template-boundary-check.d.ts +2 -2
  89. package/node_modules/@ykdz/template-core/dist/template-boundary-check.js +6 -0
  90. package/node_modules/@ykdz/template-core/dist/toolchain-resolution.d.ts +2 -0
  91. package/node_modules/@ykdz/template-core/dist/toolchain-resolution.js +9 -3
  92. package/package.json +3 -3
  93. package/node_modules/@ykdz/template-builtin-presets/templates/vike-app/db-migrations/scripts/prepare-database.ts +0 -45
  94. package/node_modules/@ykdz/template-builtin-presets/templates/vike-app/web/scripts/run-playwright.ts +0 -151
  95. package/node_modules/@ykdz/template-builtin-presets/templates/vue-app/scripts/run-playwright.ts +0 -62
  96. package/node_modules/@ykdz/template-builtin-presets/templates/vue-hono-app/web/scripts/run-playwright.ts +0 -103
  97. package/node_modules/@ykdz/template-core/dist/project-blueprint-v2.d.ts +0 -33
  98. package/node_modules/@ykdz/template-core/dist/project-blueprint-v2.js +0 -182
@@ -1,74 +1,156 @@
1
- export function checkEnvironmentNeedFact(need) {
2
- switch (need.kind) {
3
- case "playwright-browser-assets":
4
- return { kind: need.kind, browser: need.browser, owner: need.owner };
1
+ function isRecord(value) {
2
+ return typeof value === "object" && value !== null && !Array.isArray(value);
3
+ }
4
+ function assertExactKeys(value, allowedKeys, context) {
5
+ for (const key of Object.keys(value)) {
6
+ if (!allowedKeys.includes(key)) {
7
+ throw new Error(`${context} contains unknown field: ${key}`);
8
+ }
9
+ }
10
+ }
11
+ function parseComponentOwner(value, context) {
12
+ if (!isRecord(value)) {
13
+ throw new Error(`${context} must be a Component Owner`);
14
+ }
15
+ assertExactKeys(value, ["kind", "path"], context);
16
+ if (value.kind === "workspace-orchestration" && value.path === ".") {
17
+ return { kind: value.kind, path: value.path };
18
+ }
19
+ if (value.kind === "package-boundary" &&
20
+ typeof value.path === "string" &&
21
+ value.path.length > 0) {
22
+ return { kind: value.kind, path: value.path };
23
+ }
24
+ throw new Error(`${context} is not a supported Component Owner`);
25
+ }
26
+ function parseCheckEnvironmentNeed(value, context) {
27
+ if (!isRecord(value)) {
28
+ throw new Error(`${context} must be a Check Environment Need`);
29
+ }
30
+ switch (value.kind) {
31
+ case "playwright-browser-assets": {
32
+ assertExactKeys(value, ["kind", "browser", "owner"], context);
33
+ if (value.browser !== "chromium") {
34
+ throw new Error(`${context}.browser must be chromium`);
35
+ }
36
+ return {
37
+ kind: value.kind,
38
+ browser: value.browser,
39
+ owner: parseComponentOwner(value.owner, `${context}.owner`),
40
+ };
41
+ }
5
42
  case "shellcheck-command":
6
- return { kind: need.kind, owner: need.owner };
7
- case "rust-toolchain":
43
+ assertExactKeys(value, ["kind", "owner"], context);
44
+ return {
45
+ kind: value.kind,
46
+ owner: parseComponentOwner(value.owner, `${context}.owner`),
47
+ };
48
+ case "rust-toolchain": {
49
+ assertExactKeys(value, ["kind", "owner", "toolchain"], context);
50
+ if (value.toolchain !== "stable") {
51
+ throw new Error(`${context}.toolchain must be stable`);
52
+ }
8
53
  return {
9
- kind: need.kind,
10
- owner: need.owner,
11
- toolchain: need.toolchain,
54
+ kind: value.kind,
55
+ owner: parseComponentOwner(value.owner, `${context}.owner`),
56
+ toolchain: value.toolchain,
12
57
  };
58
+ }
59
+ default:
60
+ throw new Error(`${context} has unsupported kind: ${String(value.kind)}`);
13
61
  }
14
62
  }
15
- export function checkEnvironmentNeedFromFact(fact) {
16
- switch (fact.kind) {
63
+ function parseDeploymentEnvironmentNeed(value, context) {
64
+ if (!isRecord(value)) {
65
+ throw new Error(`${context} must be a Deployment Environment Need`);
66
+ }
67
+ assertExactKeys(value, ["kind"], context);
68
+ if (value.kind !== "docker-engine") {
69
+ throw new Error(`${context} has unsupported kind: ${String(value.kind)}`);
70
+ }
71
+ return { kind: value.kind };
72
+ }
73
+ function componentOwnerIdentity(owner) {
74
+ return `${owner.kind}:${owner.path}`;
75
+ }
76
+ function checkEnvironmentNeedConflictKey(need) {
77
+ return `${need.kind}:${componentOwnerIdentity(need.owner)}`;
78
+ }
79
+ function checkEnvironmentNeedIdentity(need) {
80
+ switch (need.kind) {
17
81
  case "playwright-browser-assets":
18
- return playwrightBrowserAssetsEnvironmentNeed({
19
- browser: fact.browser,
20
- owner: fact.owner,
21
- });
82
+ return `${checkEnvironmentNeedConflictKey(need)}:browser=${need.browser}`;
22
83
  case "shellcheck-command":
23
- return shellCheckEnvironmentNeed(fact.owner);
84
+ return checkEnvironmentNeedConflictKey(need);
24
85
  case "rust-toolchain":
25
- return rustToolchainEnvironmentNeed(fact.owner);
86
+ return `${checkEnvironmentNeedConflictKey(need)}:toolchain=${need.toolchain}`;
87
+ }
88
+ }
89
+ function normalizeCheckEnvironmentNeeds(needs) {
90
+ const byIdentity = new Map();
91
+ const identityByConflictKey = new Map();
92
+ for (const [index, input] of needs.entries()) {
93
+ const need = parseCheckEnvironmentNeed(input, `check[${index}]`);
94
+ const identity = checkEnvironmentNeedIdentity(need);
95
+ const conflictKey = checkEnvironmentNeedConflictKey(need);
96
+ const previousIdentity = identityByConflictKey.get(conflictKey);
97
+ if (previousIdentity !== undefined && previousIdentity !== identity) {
98
+ throw new Error(`Check Environment Need ${conflictKey} has conflicting semantic parameters`);
99
+ }
100
+ identityByConflictKey.set(conflictKey, identity);
101
+ byIdentity.set(identity, need);
102
+ }
103
+ return [...byIdentity]
104
+ .toSorted(([left], [right]) => left.localeCompare(right))
105
+ .map(([, need]) => need);
106
+ }
107
+ function normalizeDeploymentEnvironmentNeeds(needs) {
108
+ const byIdentity = new Map();
109
+ for (const [index, input] of needs.entries()) {
110
+ const need = parseDeploymentEnvironmentNeed(input, `deployment[${index}]`);
111
+ byIdentity.set(need.kind, need);
26
112
  }
113
+ return [...byIdentity]
114
+ .toSorted(([left], [right]) => left.localeCompare(right))
115
+ .map(([, need]) => need);
27
116
  }
28
- export function deploymentEnvironmentNeedFact(need) {
29
- return { kind: need.kind };
117
+ /** Validates, deduplicates, and canonically orders durable Environment Needs. */
118
+ export function normalizeEnvironmentNeeds(options) {
119
+ return {
120
+ schemaVersion: 1,
121
+ check: normalizeCheckEnvironmentNeeds(options.check),
122
+ deployment: normalizeDeploymentEnvironmentNeeds(options.deployment),
123
+ };
30
124
  }
31
- export function deploymentEnvironmentNeedFromFact(fact) {
32
- if (fact.kind !== "docker-engine") {
33
- throw new Error("Unsupported Deployment Environment Need fact.");
125
+ /** Strict codec for Local Template Metadata consumed by Package Addition. */
126
+ export function parseEnvironmentNeedsMetadata(value) {
127
+ if (!isRecord(value)) {
128
+ throw new Error("Environment Need metadata must be an object");
129
+ }
130
+ assertExactKeys(value, ["schemaVersion", "check", "deployment"], "$");
131
+ if (value.schemaVersion !== 1) {
132
+ throw new Error(`Unsupported Environment Need metadata schema version ${String(value.schemaVersion)}; expected 1`);
133
+ }
134
+ if (!Array.isArray(value.check)) {
135
+ throw new Error("$.check must be an array");
136
+ }
137
+ if (!Array.isArray(value.deployment)) {
138
+ throw new Error("$.deployment must be an array");
34
139
  }
35
- return dockerEngineEnvironmentNeed();
140
+ return normalizeEnvironmentNeeds({
141
+ check: value.check,
142
+ deployment: value.deployment,
143
+ });
36
144
  }
37
145
  export function rustToolchainEnvironmentNeed(owner) {
38
146
  return {
39
147
  kind: "rust-toolchain",
40
148
  owner,
41
149
  toolchain: "stable",
42
- nextStep: {
43
- id: "install-rust-toolchain",
44
- label: "Install Rust toolchain",
45
- command: "rustup",
46
- args: [
47
- "toolchain",
48
- "install",
49
- "stable",
50
- "--component",
51
- "rustfmt",
52
- "--component",
53
- "clippy",
54
- ],
55
- display: "rustup toolchain install stable --component rustfmt --component clippy",
56
- machineVerifiable: false,
57
- },
58
150
  };
59
151
  }
60
152
  export function dockerEngineEnvironmentNeed() {
61
- return {
62
- kind: "docker-engine",
63
- preparation: {
64
- id: "verify-docker-engine",
65
- label: "Verify Docker engine",
66
- command: "docker",
67
- args: ["version", "--format", "{{.Server.Version}}"],
68
- display: "docker version --format {{.Server.Version}}",
69
- machineVerifiable: true,
70
- },
71
- };
153
+ return { kind: "docker-engine" };
72
154
  }
73
155
  export const qualityTaskVocabulary = [
74
156
  "boundaries",
@@ -92,8 +174,8 @@ export function renderTurboRunCommand(taskNames, args = [], options = {}) {
92
174
  ...(options.taskPrefix ? ["--log-prefix=task"] : []),
93
175
  ].join(" ");
94
176
  }
95
- export function renderRootCheckCommand() {
96
- return renderTurboRunCommand(qualityTaskVocabulary, [], {
177
+ export function renderRootCheckCommand(additionalTasks = []) {
178
+ return renderTurboRunCommand([...qualityTaskVocabulary, ...additionalTasks], [], {
97
179
  continueAfterFailure: true,
98
180
  taskPrefix: true,
99
181
  });
@@ -108,65 +190,16 @@ export function renderFixCommand() {
108
190
  taskPrefix: true,
109
191
  });
110
192
  }
111
- function playwrightBrowserInstallArgs(need, options = {}) {
112
- const installArgs = [
113
- "exec",
114
- "playwright",
115
- "install",
116
- ...(options.withDeps ? ["--with-deps"] : []),
117
- need.browser,
118
- ];
119
- if (need.owner.kind === "package-boundary" && need.owner.path !== ".") {
120
- return ["--filter", `./${need.owner.path}`, ...installArgs];
121
- }
122
- return installArgs;
123
- }
124
- export function renderPlaywrightBrowserInstallCommand(need, options = {}) {
125
- if (need.kind !== "playwright-browser-assets") {
126
- throw new Error("Playwright install requires browser assets.");
127
- }
128
- return ["pnpm", ...playwrightBrowserInstallArgs(need, options)].join(" ");
129
- }
130
- export function playwrightBrowserAssetsNextStepDescriptor(owner) {
131
- if (owner.kind === "package-boundary" && owner.path !== ".") {
132
- return {
133
- id: `install-${owner.path.replaceAll("/", "-")}-playwright-browsers`,
134
- label: `Install Playwright browser assets for ${owner.path} package`,
135
- };
136
- }
137
- return {
138
- id: "install-workspace-playwright-browsers",
139
- label: "Install Playwright browser assets for workspace",
140
- };
141
- }
142
193
  export function playwrightBrowserAssetsEnvironmentNeed(options) {
143
- const args = playwrightBrowserInstallArgs(options);
144
- const descriptor = playwrightBrowserAssetsNextStepDescriptor(options.owner);
145
194
  return {
146
195
  kind: "playwright-browser-assets",
147
196
  browser: options.browser,
148
197
  owner: options.owner,
149
- nextStep: {
150
- id: options.id ?? descriptor.id,
151
- label: options.label ?? descriptor.label,
152
- command: "pnpm",
153
- args,
154
- display: ["pnpm", ...args].join(" "),
155
- machineVerifiable: options.machineVerifiable ?? true,
156
- },
157
198
  };
158
199
  }
159
200
  export function shellCheckEnvironmentNeed(owner) {
160
201
  return {
161
202
  kind: "shellcheck-command",
162
203
  owner,
163
- nextStep: {
164
- id: "install-shellcheck",
165
- label: "Install ShellCheck",
166
- command: "sudo",
167
- args: ["sh", "-c", "apt-get update && apt-get install -y shellcheck"],
168
- display: "sudo apt-get update && sudo apt-get install -y shellcheck",
169
- machineVerifiable: false,
170
- },
171
204
  };
172
205
  }
@@ -2,10 +2,14 @@ import { type CiDiagnosticArtifactDeclaration } from "./ci-diagnostic-artifact.t
2
2
  import type { DevelopmentContainerToolLayer } from "./development-container-tool-layer.ts";
3
3
  import type { EditorCustomizationCapability } from "./editor-customization.ts";
4
4
  import type { CheckEnvironmentNeed, DeploymentEnvironmentNeed } from "./module-graph.ts";
5
- import type { PackageDefinition } from "./project-blueprint-v2.ts";
5
+ import type { PackageDefinition } from "./project-blueprint.ts";
6
6
  import type { DependencyMaintenancePolicy } from "./project-github.ts";
7
7
  import type { RenderOperation, TemplateSourceHandle } from "./renderer.ts";
8
8
  export type FoundationContribution = {
9
+ /** Closed publication capability consumed only by coordinated root policy. */
10
+ readonly npmPublication?: {
11
+ readonly kind: "public-cli-candidate";
12
+ };
9
13
  /** Toolchains the Foundation must install and project into coordinated root files. */
10
14
  readonly toolchains: {
11
15
  readonly rust?: {
@@ -17,6 +21,10 @@ export type FoundationContribution = {
17
21
  readonly editorCapabilities: readonly EditorCustomizationCapability[];
18
22
  /** Ecosystems and paths whose maintenance belongs in the coordinated root policy. */
19
23
  readonly dependencyMaintenance: DependencyMaintenancePolicy;
24
+ /** Explicit dependency on the Foundation-owned TypeScript policy Package. */
25
+ readonly typescriptConfigurationPackage?: {
26
+ readonly dependency: "required";
27
+ };
20
28
  /** Workspace membership patterns contributed by package boundaries. */
21
29
  readonly workspacePackageGlobs?: readonly string[];
22
30
  /** Dependency Catalog entries required by package-owned manifests. */
@@ -49,6 +57,10 @@ export type PackageContribution = {
49
57
  /** Requirements prepared only by a focused deployment entrypoint. */
50
58
  readonly deploymentEnvironmentNeeds?: readonly DeploymentEnvironmentNeed[];
51
59
  };
60
+ /** Validates the portable executable name promised by a CLI Package Boundary. */
61
+ export declare function validateCliCommandName(commandName: string, occupiedCommandNames?: readonly string[]): string;
62
+ /** Validates command portability and uniqueness across one complete plan. */
63
+ export declare function assertPackageContributionCommandNames(contributions: readonly PackageContribution[]): readonly PackageContribution[];
52
64
  export declare function assertPackageContribution(contribution: PackageContribution, provenance?: {
53
65
  readonly definitionName?: string;
54
66
  readonly planner?: string;
@@ -6,6 +6,98 @@ const operationPath = (operation) => {
6
6
  return operation.path;
7
7
  return "";
8
8
  };
9
+ const reservedSystemToolNames = new Set([
10
+ "aux",
11
+ "bash",
12
+ "bun",
13
+ "cmd",
14
+ "com1",
15
+ "com2",
16
+ "com3",
17
+ "com4",
18
+ "com5",
19
+ "com6",
20
+ "com7",
21
+ "com8",
22
+ "com9",
23
+ "con",
24
+ "corepack",
25
+ "deno",
26
+ "git",
27
+ "lpt1",
28
+ "lpt2",
29
+ "lpt3",
30
+ "lpt4",
31
+ "lpt5",
32
+ "lpt6",
33
+ "lpt7",
34
+ "lpt8",
35
+ "lpt9",
36
+ "node",
37
+ "nul",
38
+ "npm",
39
+ "npx",
40
+ "pnpm",
41
+ "powershell",
42
+ "prn",
43
+ "pwsh",
44
+ "sh",
45
+ "yarn",
46
+ "zsh",
47
+ ]);
48
+ /** Validates the portable executable name promised by a CLI Package Boundary. */
49
+ export function validateCliCommandName(commandName, occupiedCommandNames = []) {
50
+ if (/[/\\]/u.test(commandName)) {
51
+ throw new Error(`CLI command name must not be a path; received ${JSON.stringify(commandName)}`);
52
+ }
53
+ if (/\p{White_Space}/u.test(commandName)) {
54
+ throw new Error(`CLI command name must not contain whitespace; received ${JSON.stringify(commandName)}`);
55
+ }
56
+ if (/\p{Control}/u.test(commandName)) {
57
+ throw new Error(`CLI command name must not contain a control character; received ${JSON.stringify(commandName)}`);
58
+ }
59
+ if (commandName.startsWith("-")) {
60
+ throw new Error(`CLI command name must not have a leading hyphen; received ${JSON.stringify(commandName)}`);
61
+ }
62
+ if (!/^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/u.test(commandName)) {
63
+ throw new Error(`CLI command name must use lowercase ASCII letters, digits, and single hyphens; received ${JSON.stringify(commandName)}`);
64
+ }
65
+ if (reservedSystemToolNames.has(commandName)) {
66
+ throw new Error(`CLI command name is a reserved system tool; received ${JSON.stringify(commandName)}`);
67
+ }
68
+ if (occupiedCommandNames.includes(commandName)) {
69
+ throw new Error(`CLI command name is already used by another workspace package; received ${JSON.stringify(commandName)}`);
70
+ }
71
+ return commandName;
72
+ }
73
+ function manifestBinEntries(contribution) {
74
+ const bin = contribution.manifest.bin;
75
+ if (typeof bin !== "object" || bin === null || Array.isArray(bin)) {
76
+ return [];
77
+ }
78
+ return Object.entries(bin);
79
+ }
80
+ /** Validates command portability and uniqueness across one complete plan. */
81
+ export function assertPackageContributionCommandNames(contributions) {
82
+ const commandOwner = new Map();
83
+ for (const contribution of contributions) {
84
+ const entries = manifestBinEntries(contribution);
85
+ for (const [commandName] of entries) {
86
+ const existingOwner = commandOwner.get(commandName);
87
+ try {
88
+ validateCliCommandName(commandName, [...commandOwner.keys()]);
89
+ }
90
+ catch (error) {
91
+ if (existingOwner !== undefined) {
92
+ throw new Error(`CLI command name ${JSON.stringify(commandName)} from ${contribution.definition.name} is already used by ${existingOwner}`);
93
+ }
94
+ throw error;
95
+ }
96
+ commandOwner.set(commandName, contribution.definition.name);
97
+ }
98
+ }
99
+ return contributions;
100
+ }
9
101
  export function assertPackageContribution(contribution, provenance = {}) {
10
102
  if (contribution.definition.name !== contribution.manifest.name) {
11
103
  throw new Error("Package Contribution manifest name must match its Package Definition");
@@ -23,7 +23,7 @@ overrides:
23
23
  catalog:
24
24
  "@devcontainers/cli": 0.88.0
25
25
  "@hono/node-server": ^2.0.12
26
- "@playwright/test": ^1.61.1
26
+ "@playwright/test": ^1.62.1
27
27
  "@tailwindcss/vite": ^4.3.3
28
28
  "@types/node": ^24.13.3
29
29
  "@types/web-bluetooth": ^0.0.21
@@ -34,28 +34,32 @@ catalog:
34
34
  commander: ^15.0.0
35
35
  drizzle-kit: 1.0.0-rc.4
36
36
  drizzle-orm: 1.0.0-rc.4
37
- execa: ^10.0.0
38
- hono: ^4.12.31
37
+ execa: ^10.0.1
38
+ hono: ^4.13.3
39
39
  node-diff3: ^3.2.1
40
+ npm: 11.19.1
40
41
  oxfmt: ^0.58.0
41
- oxlint: ^1.73.0
42
+ oxlint: ^1.77.0
42
43
  oxlint-tsgolint: ^7.0.2001
43
44
  semver: ^7.8.5
44
45
  "@types/semver": ^7.7.1
46
+ spdx-expression-parse: ^5.0.0
47
+ "@types/spdx-expression-parse": ^4.0.0
45
48
  pinia: ^4.0.2
46
- srvx: ^0.12.1
47
- tailwindcss: ^4.3.2
49
+ srvx: ^0.12.5
50
+ tailwindcss: ^4.3.3
51
+ tar: ^7.5.22
48
52
  telefunc: ^0.2.22
49
- turbo: 2.10.5
53
+ turbo: 2.10.11
50
54
  typescript: npm:@typescript/typescript6@^6.0.2
51
55
  typescript-7: npm:typescript@^7.0.2
52
56
  valibot: ^1.4.2
53
- vite: ^8.1.5
57
+ vite: ^8.2.0
54
58
  vike: ^0.4.260
55
59
  vike-vue: ^0.9.12
56
60
  vitest: ^4.1.10
57
- vue: ^3.5.39
58
- vue-tsc: ^3.3.6
61
+ vue: ^3.5.40
62
+ vue-tsc: ^3.3.9
59
63
  yaml: ^2.9.0
60
64
 
61
65
  catalogs:
@@ -1,18 +1,65 @@
1
1
  import type { PackageContribution } from "./package-contribution.ts";
2
- import type { ProjectBlueprintV2 } from "./project-blueprint-v2.ts";
2
+ import type { PackageDefinition, PackageRole, ProjectBlueprintDraft } from "./project-blueprint.ts";
3
3
  import type { TemplateSourceHandle } from "./renderer.ts";
4
4
  /** Stable, preset-agnostic input supplied after toolchain resolution. */
5
5
  export type GenerationContext = {
6
6
  readonly targetDir: string;
7
- readonly projectName: string;
8
- readonly scope: string;
7
+ readonly repositoryName: string;
8
+ readonly defaultPackageScope: string;
9
+ readonly foundationPackages: {
10
+ readonly typescriptConfiguration: {
11
+ readonly name: string;
12
+ };
13
+ };
9
14
  readonly toolchain: {
10
15
  readonly nodeLtsMajor: string;
11
16
  readonly packageManagerPin: string;
12
17
  };
13
18
  };
14
- /** A side-effect-free Built-in Preset planner. */
15
- export type BuiltInPresetDefinition = {
19
+ /** An in-memory plan tagged with the stable adapter that can replay it. */
20
+ export type PlannedPackageContribution = PackageContribution & {
21
+ readonly planningIdentity: string;
22
+ };
23
+ /** Narrow access to initial sibling packages, keyed by stable adapter identity. */
24
+ export type InitialPackageDefinitionLookup = {
25
+ require(identity: string): PackageDefinition;
26
+ };
27
+ export type PackageContributionReplayAdapter = {
28
+ readonly identity: string;
29
+ identify(contribution: PackageContribution): PlannedPackageContribution;
30
+ replay(options: {
31
+ readonly context: GenerationContext;
32
+ readonly planningContribution: "foundationPlan" | "planInitialization" | "planPackageAddition";
33
+ readonly packageDefinition: PackageDefinition;
34
+ readonly packageLeafName: string;
35
+ readonly initialPackages: InitialPackageDefinitionLookup;
36
+ }): PackageContribution;
37
+ };
38
+ /**
39
+ * Declares one stable replay semantic. Persisted provenance selection and
40
+ * diagnostics stay with the Foundation instead of leaking into Presets.
41
+ */
42
+ export declare function definePackageContributionReplayAdapter(options: {
43
+ readonly identity: string;
44
+ readonly replay: PackageContributionReplayAdapter["replay"];
45
+ }): PackageContributionReplayAdapter;
46
+ export type ResolvedPrimaryPackageIdentity = {
47
+ readonly leafName: string;
48
+ readonly definition: PackageDefinition;
49
+ };
50
+ /** Optional behavior owned only by Presets with a configurable initial package. */
51
+ export type InitialPrimaryPackageCapability = {
52
+ readonly defaultLeafName: string;
53
+ readonly role: PackageRole;
54
+ defaultPackagePath(options: {
55
+ readonly packageLeafName: string;
56
+ }): string;
57
+ planInitialContribution(options: {
58
+ readonly context: GenerationContext;
59
+ readonly resolvedPackageIdentity: ResolvedPrimaryPackageIdentity;
60
+ }): PlannedPackageContribution;
61
+ };
62
+ type BuiltInPresetDefinitionBase = {
16
63
  readonly metadata: {
17
64
  readonly name: string;
18
65
  readonly title: string;
@@ -22,13 +69,8 @@ export type BuiltInPresetDefinition = {
22
69
  readonly source: TemplateSourceHandle;
23
70
  /** The owned planner source inspected by the Template Boundary Check. */
24
71
  readonly plannerSourceFile: string;
25
- blueprint(context: GenerationContext): ProjectBlueprintV2;
26
- planInitialization(context: GenerationContext): PackageContribution;
27
- /**
28
- * Multi-package Definitions expose their complete owned topology directly,
29
- * while single-package Definitions keep the compact tracer interface.
30
- */
31
- planInitializationContributions?(context: GenerationContext): readonly PackageContribution[];
72
+ /** Stable semantics used to replay persisted Package Definitions. */
73
+ readonly packageContributionReplayAdapters: readonly PackageContributionReplayAdapter[];
32
74
  /** Package layout is Preset-owned even when callers omit --path. */
33
75
  defaultPackagePath?(options: {
34
76
  readonly context: GenerationContext;
@@ -38,5 +80,21 @@ export type BuiltInPresetDefinition = {
38
80
  readonly context: GenerationContext;
39
81
  readonly packageLeafName: string;
40
82
  readonly packagePath: string;
41
- }): PackageContribution;
83
+ }): PlannedPackageContribution;
84
+ };
85
+ type ConfigurablePrimaryPackagePresetDefinition = BuiltInPresetDefinitionBase & {
86
+ readonly initialPrimaryPackage: InitialPrimaryPackageCapability;
87
+ readonly blueprint?: never;
88
+ readonly planInitialization?: never;
89
+ readonly planInitializationContributions?: never;
42
90
  };
91
+ type FixedTopologyPresetDefinition = BuiltInPresetDefinitionBase & {
92
+ readonly initialPrimaryPackage?: never;
93
+ blueprint(context: GenerationContext): ProjectBlueprintDraft;
94
+ planInitialization(context: GenerationContext): PlannedPackageContribution;
95
+ /** Multi-package Definitions expose their complete owned topology directly. */
96
+ planInitializationContributions?(context: GenerationContext): readonly PlannedPackageContribution[];
97
+ };
98
+ /** A side-effect-free Built-in Preset planner. */
99
+ export type BuiltInPresetDefinition = ConfigurablePrimaryPackagePresetDefinition | FixedTopologyPresetDefinition;
100
+ export {};
@@ -1 +1,16 @@
1
- export {};
1
+ /**
2
+ * Declares one stable replay semantic. Persisted provenance selection and
3
+ * diagnostics stay with the Foundation instead of leaking into Presets.
4
+ */
5
+ export function definePackageContributionReplayAdapter(options) {
6
+ if (options.identity.length === 0) {
7
+ throw new Error("Package Contribution replay adapter identity is required");
8
+ }
9
+ return {
10
+ identity: options.identity,
11
+ identify(contribution) {
12
+ return { ...contribution, planningIdentity: options.identity };
13
+ },
14
+ replay: options.replay,
15
+ };
16
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * The durable, preset-agnostic topology used by local template follow-up
3
+ * operations. Preset provenance deliberately belongs in Generation Record.
4
+ */
5
+ declare const packageRoles: readonly ["cli-tool", "runtime-service", "shared-library", "native-package"];
6
+ export type PackageRole = (typeof packageRoles)[number];
7
+ export type PackageDefinition = {
8
+ readonly name: string;
9
+ readonly path: string;
10
+ readonly role: PackageRole;
11
+ };
12
+ /** Opaque durable identity assigned once when a Package Definition is created. */
13
+ export type PackageDefinitionId = `package-${string}`;
14
+ export type PersistedPackageDefinition = PackageDefinition & {
15
+ readonly packageDefinitionId: PackageDefinitionId;
16
+ };
17
+ export type PackageLinkIntent = {
18
+ readonly consumerPackagePath: string;
19
+ readonly providerPackagePath: string;
20
+ };
21
+ export type ProjectBlueprint = {
22
+ readonly schemaVersion: 3;
23
+ readonly packages: readonly PersistedPackageDefinition[];
24
+ readonly packageLinkIntents?: readonly PackageLinkIntent[];
25
+ };
26
+ /** Preset-owned topology before Foundation assigns durable package identities. */
27
+ export type ProjectBlueprintDraft = {
28
+ readonly schemaVersion: 3;
29
+ readonly packages: readonly PackageDefinition[];
30
+ readonly packageLinkIntents?: readonly PackageLinkIntent[];
31
+ };
32
+ export type BlueprintValidationIssue = {
33
+ readonly path: string;
34
+ readonly message: string;
35
+ };
36
+ export type BlueprintValidationResult = {
37
+ readonly ok: true;
38
+ readonly value: ProjectBlueprint;
39
+ } | {
40
+ readonly ok: false;
41
+ readonly issues: readonly BlueprintValidationIssue[];
42
+ };
43
+ /** Canonical npm package-name predicate shared by Blueprint and input preparation. */
44
+ export declare function isValidNewNpmPackageName(value: string): boolean;
45
+ export type NewPackagePathValidation = {
46
+ readonly hasValidShape: boolean;
47
+ readonly reservedWorkspaceCollection?: string;
48
+ };
49
+ /** Canonical Package Path facts shared by Blueprint and input preparation. */
50
+ export declare function validateNewPackagePath(value: string): NewPackagePathValidation;
51
+ /** Validates persisted metadata before it is used to plan or render changes. */
52
+ export declare function validateProjectBlueprint(value: unknown): BlueprintValidationResult;
53
+ /** Validates preset-owned topology before any persisted identity is assigned. */
54
+ export declare function assertProjectBlueprintDraft(value: ProjectBlueprintDraft): ProjectBlueprintDraft;
55
+ export declare function assertProjectBlueprint(value: unknown): ProjectBlueprint;
56
+ export {};