@smoothbricks/cli 0.10.5 โ†’ 0.10.7

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 (65) hide show
  1. package/dist/cli.js +3 -2
  2. package/dist/github-ci/index.d.ts +1 -0
  3. package/dist/github-ci/index.d.ts.map +1 -1
  4. package/dist/github-ci/index.js +28 -5
  5. package/dist/lib/json.d.ts +3 -1
  6. package/dist/lib/json.d.ts.map +1 -1
  7. package/dist/lib/json.js +5 -20
  8. package/dist/lib/workspace.d.ts.map +1 -1
  9. package/dist/lib/workspace.js +1 -0
  10. package/dist/monorepo/ci-workflow.d.ts +2 -0
  11. package/dist/monorepo/ci-workflow.d.ts.map +1 -1
  12. package/dist/monorepo/ci-workflow.js +10 -4
  13. package/dist/monorepo/github-runs-on.d.ts +14 -0
  14. package/dist/monorepo/github-runs-on.d.ts.map +1 -0
  15. package/dist/monorepo/github-runs-on.js +43 -0
  16. package/dist/monorepo/index.d.ts +2 -2
  17. package/dist/monorepo/index.d.ts.map +1 -1
  18. package/dist/monorepo/index.js +7 -7
  19. package/dist/monorepo/managed-files.d.ts +14 -3
  20. package/dist/monorepo/managed-files.d.ts.map +1 -1
  21. package/dist/monorepo/managed-files.js +54 -74
  22. package/dist/monorepo/package-policy.js +2 -2
  23. package/dist/monorepo/packs/index.d.ts.map +1 -1
  24. package/dist/monorepo/packs/index.js +3 -1
  25. package/dist/monorepo/publish-workflow.d.ts +3 -0
  26. package/dist/monorepo/publish-workflow.d.ts.map +1 -1
  27. package/dist/monorepo/publish-workflow.js +17 -14
  28. package/dist/monorepo/runtime.d.ts +2 -2
  29. package/dist/monorepo/runtime.d.ts.map +1 -1
  30. package/dist/monorepo/runtime.js +11 -16
  31. package/dist/monorepo/tool-validation.d.ts.map +1 -1
  32. package/dist/monorepo/tool-validation.js +20 -23
  33. package/dist/nx/index.d.ts +7 -4
  34. package/dist/nx/index.d.ts.map +1 -1
  35. package/dist/nx/index.js +117 -56
  36. package/managed/raw/tooling/devenv +71 -0
  37. package/managed/raw/tooling/direnv/github-actions-bootstrap.sh +24 -7
  38. package/managed/templates/github/actions/cache-nix-devenv/action.yml +13 -11
  39. package/managed/templates/github/actions/save-nix-devenv/action.yml +34 -3
  40. package/managed/templates/github/actions/setup-devenv/action.yml +44 -15
  41. package/managed/templates/github/workflows/managed-files.yml +64 -12
  42. package/package.json +4 -4
  43. package/src/cli.ts +10 -3
  44. package/src/github-ci/index.test.ts +53 -4
  45. package/src/github-ci/index.ts +37 -5
  46. package/src/lib/json.ts +3 -1
  47. package/src/lib/workspace.ts +1 -0
  48. package/src/monorepo/__tests__/ci-workflow.test.ts +37 -1
  49. package/src/monorepo/__tests__/publish-workflow.test.ts +39 -4
  50. package/src/monorepo/ci-workflow.ts +14 -4
  51. package/src/monorepo/github-runs-on.ts +45 -0
  52. package/src/monorepo/index.ts +7 -7
  53. package/src/monorepo/managed-files.test.ts +58 -0
  54. package/src/monorepo/managed-files.ts +59 -76
  55. package/src/monorepo/package-policy.test.ts +31 -0
  56. package/src/monorepo/package-policy.ts +2 -2
  57. package/src/monorepo/packs/index.ts +3 -1
  58. package/src/monorepo/publish-workflow.ts +28 -15
  59. package/src/monorepo/runtime.test.ts +23 -17
  60. package/src/monorepo/runtime.ts +12 -17
  61. package/src/monorepo/tool-validation.test.ts +15 -8
  62. package/src/monorepo/tool-validation.ts +20 -25
  63. package/src/nx/index.test.ts +45 -14
  64. package/src/nx/index.ts +133 -64
  65. package/managed/raw/patches/ttsc@0.19.3.patch +0 -67
@@ -1,10 +1,9 @@
1
- import { execFileSync } from 'node:child_process';
2
1
  import { appendFileSync, existsSync, lstatSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
3
2
  import { dirname, join, resolve } from 'node:path';
4
3
  import { fileURLToPath } from 'node:url';
5
4
  import { PLATFORM_TARGET_GLOBS } from '@smoothbricks/nx-plugin/workspace-config-policy';
6
- import { parseNxProjectJsonText, parseStringArrayText } from '../lib/json.js';
7
5
  import { listReleasePackages, readPackageJson } from '../lib/workspace.js';
6
+ import { loadNxProjects, targetNamesFromProjects } from '../nx/index.js';
8
7
  import { renderCiWorkflowYaml } from './ci-workflow.js';
9
8
  import { renderPublishWorkflowYaml } from './publish-workflow.js';
10
9
  /**
@@ -100,6 +99,12 @@ const managedFiles = [
100
99
  source: 'envrc',
101
100
  target: '.envrc',
102
101
  },
102
+ {
103
+ kind: 'raw',
104
+ source: 'tooling/devenv',
105
+ target: 'tooling/devenv',
106
+ executable: true,
107
+ },
103
108
  {
104
109
  kind: 'raw',
105
110
  source: 'tooling/direnv/repo-path',
@@ -146,11 +151,6 @@ const managedFiles = [
146
151
  target: 'tooling/direnv/merge-newer-pins.sh',
147
152
  executable: true,
148
153
  },
149
- {
150
- kind: 'raw',
151
- source: 'patches/ttsc@0.19.3.patch',
152
- target: 'patches/ttsc@0.19.3.patch',
153
- },
154
154
  {
155
155
  kind: 'generated',
156
156
  source: 'ci-workflow',
@@ -198,9 +198,10 @@ const managedFiles = [
198
198
  target: '.github/actions/cache-nx/action.yml',
199
199
  },
200
200
  ];
201
+ export const managedFileTargetsForTest = managedFiles.map(({ target, executable }) => ({ target, executable }));
201
202
  const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..', '..');
202
- export function applyManagedFiles(root, mode) {
203
- const context = getManagedFileContext(root);
203
+ export async function applyManagedFiles(root, mode) {
204
+ const context = await getManagedFileContext(root);
204
205
  return managedFiles.map((file) => applyManagedFile(root, file, mode, context));
205
206
  }
206
207
  function applyManagedFile(root, file, mode, context) {
@@ -244,6 +245,7 @@ function getManagedContent(file, context) {
244
245
  deploy: context.hasStagingDeployTargets,
245
246
  deployProvider: context.stagingDeployProvider,
246
247
  pushBranches: context.ciPushBranches,
248
+ runsOn: context.ciRunsOn,
247
249
  });
248
250
  }
249
251
  if (file.source === 'publish-workflow') {
@@ -252,6 +254,7 @@ function getManagedContent(file, context) {
252
254
  deployProvider: context.productionDeployProvider,
253
255
  repoName: context.repoName,
254
256
  platformTargetGlobs: context.platformTargetGlobs,
257
+ runsOn: context.ciRunsOn,
255
258
  });
256
259
  }
257
260
  throw new Error(`Unknown generated managed file source ${file.source}`);
@@ -264,13 +267,16 @@ function getManagedContent(file, context) {
264
267
  }
265
268
  return renderTemplate(context, content);
266
269
  }
267
- function getManagedFileContext(root) {
270
+ async function getManagedFileContext(root) {
268
271
  const packageJson = readPackageJson(join(root, 'package.json'));
269
272
  const repoName = packageJson?.name ?? 'monorepo';
270
273
  const ciPushBranches = getCiPushBranches(packageJson?.json);
271
- const stagingDeploy = getDeployTargetInfo(root, 'staging');
272
- const productionDeploy = getDeployTargetInfo(root, 'production');
273
- const platformTargetGlobs = platformTargetGlobsForTest(readResolvedNxTargetNames(root));
274
+ const ciRunsOn = getCiRunsOn(packageJson?.json);
275
+ // In-process Nx API โ†’ daemon socket (no second Node/`nx` CLI process).
276
+ const nxProjects = await loadNxProjects(root);
277
+ const stagingDeploy = deployTargetInfoFromProjects(nxProjects, 'staging');
278
+ const productionDeploy = deployTargetInfoFromProjects(nxProjects, 'production');
279
+ const platformTargetGlobs = platformTargetGlobsForTest(targetNamesFromProjects(nxProjects));
274
280
  const nodeModulesCacheKey = existsSync(join(root, 'bun.lock'))
275
281
  ? `$${"{{ hashFiles('bun.lock', 'package.json', 'packages/*/package.json') }}"}`
276
282
  : `$${"{{ hashFiles('bun.lockb', 'package.json', 'packages/*/package.json') }}"}`;
@@ -281,6 +287,7 @@ function getManagedFileContext(root) {
281
287
  stagingDeployProvider: stagingDeploy.provider,
282
288
  productionDeployProvider: productionDeploy.provider,
283
289
  ciPushBranches,
290
+ ciRunsOn,
284
291
  nodeModulesCacheKey,
285
292
  repoName,
286
293
  platformTargetGlobs,
@@ -293,77 +300,50 @@ export function platformTargetGlobsForTest(targetNames) {
293
300
  return names.some((name) => name.endsWith(suffix));
294
301
  });
295
302
  }
296
- function readResolvedNxTargetNames(root) {
297
- const output = execFileSync('nx', ['show', 'projects', '--json'], {
298
- cwd: root,
299
- encoding: 'utf8',
300
- stdio: ['ignore', 'pipe', 'inherit'],
301
- });
302
- const projects = parseStringArrayText(output);
303
- if (!projects) {
304
- return [];
305
- }
306
- const targetNames = new Set();
307
- for (const project of projects) {
308
- const projectOutput = execFileSync('nx', ['show', 'project', project, '--json'], {
309
- cwd: root,
310
- encoding: 'utf8',
311
- stdio: ['ignore', 'pipe', 'inherit'],
312
- });
313
- const projectJson = parseNxProjectJsonText(projectOutput);
314
- const targets = projectJson?.targets;
315
- if (targets) {
316
- for (const targetName of Object.keys(targets)) {
317
- targetNames.add(targetName);
318
- }
319
- }
320
- }
321
- return [...targetNames];
322
- }
323
- function renderTemplate(context, template) {
324
- return template
325
- .replaceAll('{{REPO_NAME}}', context.repoName)
326
- .replaceAll('__SMOO_CI_PUSH_BRANCHES__', renderYamlFlowList(context.ciPushBranches))
327
- .replaceAll('{{NODE_MODULES_CACHE_KEY}}', context.nodeModulesCacheKey);
328
- }
329
- function getDeployTargetInfo(root, configuration) {
330
- const output = execFileSync('nx', ['show', 'projects', '--withTarget', 'deploy', '--json'], {
331
- cwd: root,
332
- encoding: 'utf8',
333
- stdio: ['ignore', 'pipe', 'inherit'],
334
- });
335
- const projects = parseStringArrayText(output);
336
- if (!projects) {
337
- return { exists: false };
338
- }
303
+ /** Test seam: deploy configuration presence/provider from graph nodes. */
304
+ export function deployTargetInfoFromProjects(projects, configuration) {
339
305
  let exists = false;
340
306
  let provider;
341
- for (const project of projects) {
342
- const target = nxDeployTarget(root, project, configuration);
343
- if (!target.exists) {
307
+ for (const project of Object.values(projects)) {
308
+ const info = deployTargetInfoFromTargets(project.targets ?? {}, configuration);
309
+ if (!info.exists) {
344
310
  continue;
345
311
  }
346
312
  exists = true;
347
- provider ??= target.provider;
313
+ provider ??= info.provider;
348
314
  }
349
315
  return { exists, provider };
350
316
  }
351
- function nxDeployTarget(root, project, configuration) {
352
- const output = execFileSync('nx', ['show', 'project', project, '--json'], {
353
- cwd: root,
354
- encoding: 'utf8',
355
- stdio: ['ignore', 'pipe', 'inherit'],
356
- });
357
- const projectJson = parseNxProjectJsonText(output);
358
- const deploy = projectJson?.targets?.deploy;
359
- const config = deploy?.configurations?.[configuration];
317
+ function deployTargetInfoFromTargets(targets, configuration) {
318
+ const deploy = targets.deploy;
319
+ if (!deploy) {
320
+ return { exists: false };
321
+ }
322
+ const config = deploy.configurations?.[configuration];
360
323
  if (!config) {
361
324
  return { exists: false };
362
325
  }
363
- const commandValue = config.command ?? config.options?.command ?? deploy?.options?.command;
326
+ const commandValue = config.command ?? config.options?.command ?? deploy.options?.command ?? deploy.command;
364
327
  const command = typeof commandValue === 'string' ? commandValue : '';
365
328
  return { exists: true, provider: command.includes('wrangler ') ? 'cloudflare' : undefined };
366
329
  }
330
+ function renderTemplate(context, template) {
331
+ return template
332
+ .replaceAll('{{REPO_NAME}}', context.repoName)
333
+ .replaceAll('__SMOO_CI_PUSH_BRANCHES__', renderYamlFlowList(context.ciPushBranches))
334
+ .replaceAll('{{NODE_MODULES_CACHE_KEY}}', context.nodeModulesCacheKey);
335
+ }
336
+ function getCiRunsOn(packageJson) {
337
+ const configured = packageJson?.smoo?.github?.runsOn;
338
+ if (configured === undefined) {
339
+ return 'ubuntu-latest';
340
+ }
341
+ if (typeof configured === 'string') {
342
+ return configured.length > 0 ? configured : 'ubuntu-latest';
343
+ }
344
+ const labels = configured.filter((label) => label.length > 0);
345
+ return labels.length > 0 ? labels : 'ubuntu-latest';
346
+ }
367
347
  function getCiPushBranches(packageJson) {
368
348
  const configured = readCiPushBranches(packageJson);
369
349
  return configured.length > 0 ? configured : ['main'];
@@ -384,8 +364,8 @@ export function printResults(results) {
384
364
  console.log(`${result.action.padEnd(15)} ${result.target}`);
385
365
  }
386
366
  }
387
- export function validateManagedFiles(root) {
388
- const results = applyManagedFiles(root, 'check');
367
+ export async function validateManagedFiles(root) {
368
+ const results = await applyManagedFiles(root, 'check');
389
369
  printResults(results);
390
370
  const failures = results.filter((result) => result.action === 'drifted').length;
391
371
  if (failures > 0) {
@@ -403,8 +383,8 @@ export function validateManagedFiles(root) {
403
383
  * Under GitHub Actions the drifted-file count is published as the step output
404
384
  * `drifted`, so downstream steps gate declaratively instead of parsing logs.
405
385
  */
406
- export function warnOnManagedFileDrift(root) {
407
- const results = applyManagedFiles(root, 'check');
386
+ export async function warnOnManagedFileDrift(root) {
387
+ const results = await applyManagedFiles(root, 'check');
408
388
  printResults(results);
409
389
  const drifted = results.filter((result) => result.action === 'drifted');
410
390
  if (process.env.GITHUB_OUTPUT) {
@@ -113,7 +113,7 @@ export function applyWorkspaceDependencyDefaults(root, options = {}) {
113
113
  else {
114
114
  console.log('unchanged tsconfig.test.json policy');
115
115
  }
116
- if (applyWorkspaceBoundedTestTargetPolicy(root)) {
116
+ if (applyWorkspaceBoundedTestTargetPolicy(root, options)) {
117
117
  console.log('updated package test targets bounded execution policy');
118
118
  }
119
119
  else {
@@ -343,7 +343,7 @@ export function validateWorkspaceDependencies(root, options = {}) {
343
343
  console.error(`${issue.path}: ${issue.message}`);
344
344
  failures++;
345
345
  }
346
- for (const issue of checkWorkspaceBoundedTestTargetPolicy(root)) {
346
+ for (const issue of checkWorkspaceBoundedTestTargetPolicy(root, options)) {
347
347
  console.error(`${issue.path}: ${issue.message}`);
348
348
  failures++;
349
349
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/monorepo/packs/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,cAAc,EAAsB,MAAM,mBAAmB,CAAC;AAK5E,OAAO,EAKL,KAAK,sBAAsB,EAO5B,MAAM,sBAAsB,CAAC;AAU9B,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,OAAO,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAClD,WAAW,CAAC,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACzD,YAAY,CAAC,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC1D,gBAAgB,CAAC,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;IAClE,iBAAiB,CAAC,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;CACpE;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,CAAC,EAAE,SAAS,YAAY,EAAE,CAAC;IAChC,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE,mBAAmB,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;CAC9F;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;CACtB;AAqHD,wBAAsB,YAAY,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAItE;AAED,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,eAAe,EACpB,OAAO,GAAE,mBAAwB,EACjC,KAAK,GAAE,oBAAyB,GAC/B,OAAO,CAAC,kBAAkB,CAAC,CA0B7B;AAuMD,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,cAAc,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAaxG"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/monorepo/packs/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,cAAc,EAAsB,MAAM,mBAAmB,CAAC;AAK5E,OAAO,EAKL,KAAK,sBAAsB,EAO5B,MAAM,sBAAsB,CAAC;AAU9B,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,OAAO,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAClD,WAAW,CAAC,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACzD,YAAY,CAAC,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC1D,gBAAgB,CAAC,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;IAClE,iBAAiB,CAAC,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;CACpE;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,CAAC,EAAE,SAAS,YAAY,EAAE,CAAC;IAChC,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE,mBAAmB,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;CAC9F;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;CACtB;AAqHD,wBAAsB,YAAY,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAItE;AAED,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,eAAe,EACpB,OAAO,GAAE,mBAAwB,EACjC,KAAK,GAAE,oBAAyB,GAC/B,OAAO,CAAC,kBAAkB,CAAC,CA0B7B;AAuMD,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,cAAc,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAexG"}
@@ -40,7 +40,7 @@ const packs = [
40
40
  // Managed-file drift is derived state (CLI template x pinned version) with
41
41
  // its own remediation flow; it warns instead of failing so validation only
42
42
  // blocks on actual package issues. See warnOnManagedFileDrift.
43
- warnOnManagedFileDrift(ctx.root);
43
+ await warnOnManagedFileDrift(ctx.root);
44
44
  return (runtimeFailures +
45
45
  validateRootPackagePolicy(ctx.root) +
46
46
  (await validateToolConfig(ctx.root)) +
@@ -315,10 +315,12 @@ export function resolvedTargetsByProject(projects) {
315
315
  return new Map(projects.map((project) => [
316
316
  project.project,
317
317
  {
318
+ ...(project.root ? { root: project.root } : {}),
318
319
  targets: new Set(project.targets),
319
320
  ...(project.buildDependsOn ? { buildDependsOn: project.buildDependsOn } : {}),
320
321
  ...(project.targetDependencies ? { targetDependencies: project.targetDependencies } : {}),
321
322
  ...(project.targetExecutors ? { targetExecutors: project.targetExecutors } : {}),
323
+ ...(project.targetOptions ? { targetOptions: project.targetOptions } : {}),
322
324
  ...(project.targetScripts ? { targetScripts: project.targetScripts } : {}),
323
325
  },
324
326
  ]));
@@ -1,3 +1,4 @@
1
+ import { type WorkflowRunsOn } from './github-runs-on.js';
1
2
  export type PublishWorkflowBump = 'auto' | 'patch' | 'minor' | 'major' | 'prerelease';
2
3
  export type PublishWorkflowCondition = 'version-mode-not-none' | 'deploy-production' | 'failure' | 'always';
3
4
  export type PublishWorkflowNxTarget = 'build' | 'lint' | 'test';
@@ -35,6 +36,8 @@ export interface PublishWorkflowDefinitionOptions {
35
36
  deployProvider?: 'cloudflare';
36
37
  repoName?: string;
37
38
  platformTargetGlobs?: readonly string[];
39
+ /** Linux jobs only. Default ubuntu-latest. Same smoo.github.runsOn as CI. */
40
+ runsOn?: WorkflowRunsOn;
38
41
  }
39
42
  export interface PublishWorkflowInputs {
40
43
  bump: PublishWorkflowBump;
@@ -1 +1 @@
1
- {"version":3,"file":"publish-workflow.d.ts","sourceRoot":"","sources":["../../src/monorepo/publish-workflow.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"publish-workflow.d.ts","sourceRoot":"","sources":["../../src/monorepo/publish-workflow.ts"],"names":[],"mappings":"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"}
@@ -2,6 +2,7 @@
2
2
  import synchronizedPrettier from '@prettier/sync';
3
3
  import { LINUX_PLATFORM_TARGET_GLOBS, MACOS_PLATFORM_TARGET_GLOBS, } from '@smoothbricks/nx-plugin/workspace-config-policy';
4
4
  import { isSmoothBricksCodebasePackageName } from '../lib/cli-package.js';
5
+ import { renderRunsOnLine } from './github-runs-on.js';
5
6
  const PUBLISH_WORKFLOW_FORMAT_OPTIONS = Object.freeze({
6
7
  parser: 'yaml',
7
8
  printWidth: 120,
@@ -338,7 +339,8 @@ function yamlLinesForStep(step, options) {
338
339
  case PublishWorkflowStepKind.UploadTraceDbs:
339
340
  return [
340
341
  ` - name: ${step.name}`,
341
- ` if: ${githubExpression('failure()')}`,
342
+ ' # Default is success(); failure() uploads traces only when the job already failed.',
343
+ ' if: failure()',
342
344
  ' uses: actions/upload-artifact@v7.0.1',
343
345
  ' with:',
344
346
  ` name: trace-results-${githubExpression('github.run_id')}`,
@@ -362,7 +364,8 @@ function yamlLinesForStep(step, options) {
362
364
  case PublishWorkflowStepKind.SaveNixDevenv:
363
365
  return [
364
366
  ` - name: ${step.name}`,
365
- ` if: ${githubExpression('always()')}`,
367
+ ' # success() is default; always() still saves GH Nix cache after a red job.',
368
+ ' if: always()',
366
369
  ' uses: ./.github/actions/save-nix-devenv',
367
370
  ' with:',
368
371
  ` nix-cache-hit: ${githubExpression('steps.setup.outputs.nix-cache-hit')}`,
@@ -392,7 +395,7 @@ function deployEnvLines(options) {
392
395
  }
393
396
  function conditionalRunStep(step, run) {
394
397
  const condition = "steps.version.outputs.mode != 'none'";
395
- return [` - name: ${step.name}`, ` if: ${githubExpression(condition)}`, ` run: ${run}`];
398
+ return [` - name: ${step.name}`, ` if: ${condition}`, ` run: ${run}`];
396
399
  }
397
400
  function renderSingleJobPublishWorkflowSteps(steps, options) {
398
401
  const lines = [];
@@ -402,7 +405,7 @@ function renderSingleJobPublishWorkflowSteps(steps, options) {
402
405
  lines.push(...yamlLinesForStep(step, options));
403
406
  lines.push('');
404
407
  if (step.kind === PublishWorkflowStepKind.Build) {
405
- lines.push(' - name: ๐Ÿง Build supplemental Linux targets', ` if: ${githubExpression("steps.version.outputs.mode != 'none'")}`, ` run: smoo github-ci nx-run-many --targets "${LINUX_PLATFORM_TARGET_GLOBS.join(',')}" --projects "${githubExpression('steps.version.outputs.projects')}"`, '');
408
+ lines.push(' - name: ๐Ÿง Build supplemental Linux targets', " if: steps.version.outputs.mode != 'none'", ` run: smoo github-ci nx-run-many --targets "${LINUX_PLATFORM_TARGET_GLOBS.join(',')}" --projects "${githubExpression('steps.version.outputs.projects')}"`, '');
406
409
  }
407
410
  }
408
411
  return `${lines.join('\n').trimEnd()}\n`;
@@ -447,7 +450,7 @@ defaults:
447
450
 
448
451
  jobs:
449
452
  linux-release-candidate:
450
- runs-on: ubuntu-latest
453
+ ${renderRunsOnLine(options.runsOn)}
451
454
  permissions:
452
455
  contents: write
453
456
  id-token: none
@@ -508,7 +511,7 @@ function renderLinuxReleaseCandidateSteps(steps, options) {
508
511
  lines.push(` - name: ${step.name}`, ' uses: actions/checkout@v6.0.2', ' with:', ` ref: ${githubExpression('github.sha')}`, ' filter: blob:none', ' fetch-depth: 0');
509
512
  }
510
513
  else if (step.kind === PublishWorkflowStepKind.Build) {
511
- lines.push(` - name: ${step.name}`, ` if: ${githubExpression("steps.version.outputs.mode != 'none'")}`, ' run:', ` smoo github-ci nx-run-many --targets build --projects "${githubExpression('steps.version.outputs.projects')}" --collect-outputs "${githubExpression('runner.temp')}/release-build-outputs"`);
514
+ lines.push(` - name: ${step.name}`, " if: steps.version.outputs.mode != 'none'", ' run:', ` smoo github-ci nx-run-many --targets build --projects "${githubExpression('steps.version.outputs.projects')}" --collect-outputs "${githubExpression('runner.temp')}/release-build-outputs"`);
512
515
  }
513
516
  else {
514
517
  lines.push(...yamlLinesForStep(step, options));
@@ -519,16 +522,16 @@ function renderLinuxReleaseCandidateSteps(steps, options) {
519
522
  stepNumber += 1;
520
523
  }
521
524
  if (step.kind === PublishWorkflowStepKind.Build && hasLinuxPlatformTargets(options)) {
522
- lines.push('', ` # Step ${stepNumber}`, ' - name: ๐Ÿง Build supplemental Linux targets', ` if: ${githubExpression("steps.version.outputs.mode != 'none'")}`, ' run:', ` smoo github-ci nx-run-many --targets "${LINUX_PLATFORM_TARGET_GLOBS.join(',')}" --projects "${githubExpression('steps.version.outputs.projects')}" --collect-outputs "${githubExpression('runner.temp')}/linux-platform-outputs"`);
525
+ lines.push('', ` # Step ${stepNumber}`, ' - name: ๐Ÿง Build supplemental Linux targets', " if: steps.version.outputs.mode != 'none'", ' run:', ` smoo github-ci nx-run-many --targets "${LINUX_PLATFORM_TARGET_GLOBS.join(',')}" --projects "${githubExpression('steps.version.outputs.projects')}" --collect-outputs "${githubExpression('runner.temp')}/linux-platform-outputs"`);
523
526
  stepNumber += 1;
524
527
  }
525
528
  lines.push('');
526
529
  }
527
- lines.push(' # --- Candidate transfer --------------------------------------------------', '', ` # Step ${stepNumber++}`, ' - name: ๐Ÿ“ฆ Bundle validated release state', ' run:', ` mkdir -p "${githubExpression('runner.temp')}/publish-release-state" && git bundle create`, ` "${githubExpression('runner.temp')}/publish-release-state/release-state.bundle" HEAD --tags && git rev-parse HEAD >`, ` "${githubExpression('runner.temp')}/publish-release-state/release-head"`, '', ` # Step ${stepNumber++}`, ' - name: ๐Ÿ“ค Upload validated release state', ' uses: actions/upload-artifact@v7.0.1', ' with:', ` name: publish-release-state-${githubExpression('github.run_id')}`, ` path: ${githubExpression('runner.temp')}/publish-release-state`, ' if-no-files-found: error', ' retention-days: 1', '', ` # Step ${stepNumber++}`, ' - name: ๐Ÿ“ค Upload validated build outputs', ` if: ${githubExpression("steps.version.outputs.mode != 'none'")}`, ' uses: actions/upload-artifact@v7.0.1', ' with:', ` name: publish-release-outputs-${githubExpression('github.run_id')}`, ` path: ${githubExpression('runner.temp')}/release-build-outputs`, ' if-no-files-found: error', ' retention-days: 1', ' include-hidden-files: true');
530
+ lines.push(' # --- Candidate transfer --------------------------------------------------', '', ` # Step ${stepNumber++}`, ' - name: ๐Ÿ“ฆ Bundle validated release state', ' run:', ` mkdir -p "${githubExpression('runner.temp')}/publish-release-state" && git bundle create`, ` "${githubExpression('runner.temp')}/publish-release-state/release-state.bundle" HEAD --tags && git rev-parse HEAD >`, ` "${githubExpression('runner.temp')}/publish-release-state/release-head"`, '', ` # Step ${stepNumber++}`, ' - name: ๐Ÿ“ค Upload validated release state', ' uses: actions/upload-artifact@v7.0.1', ' with:', ` name: publish-release-state-${githubExpression('github.run_id')}`, ` path: ${githubExpression('runner.temp')}/publish-release-state`, ' if-no-files-found: error', ' retention-days: 1', '', ` # Step ${stepNumber++}`, ' - name: ๐Ÿ“ค Upload validated build outputs', " if: steps.version.outputs.mode != 'none'", ' uses: actions/upload-artifact@v7.0.1', ' with:', ` name: publish-release-outputs-${githubExpression('github.run_id')}`, ` path: ${githubExpression('runner.temp')}/release-build-outputs`, ' if-no-files-found: error', ' retention-days: 1', ' include-hidden-files: true');
528
531
  if (hasLinuxPlatformTargets(options)) {
529
- lines.push('', ` # Step ${stepNumber++}`, ' - name: ๐Ÿ“ค Upload supplemental Linux outputs', ` if: ${githubExpression("steps.version.outputs.mode != 'none'")}`, ' uses: actions/upload-artifact@v7.0.1', ' with:', ` name: publish-linux-outputs-${githubExpression('github.run_id')}`, ` path: ${githubExpression('runner.temp')}/linux-platform-outputs`, ' if-no-files-found: error', ' retention-days: 1', ' include-hidden-files: true');
532
+ lines.push('', ` # Step ${stepNumber++}`, ' - name: ๐Ÿ“ค Upload supplemental Linux outputs', " if: steps.version.outputs.mode != 'none'", ' uses: actions/upload-artifact@v7.0.1', ' with:', ` name: publish-linux-outputs-${githubExpression('github.run_id')}`, ` path: ${githubExpression('runner.temp')}/linux-platform-outputs`, ' if-no-files-found: error', ' retention-days: 1', ' include-hidden-files: true');
530
533
  }
531
- lines.push('', ' # --- Cleanup ------------------------------------------------------------', '', ` # Step ${stepNumber}`, ' - name: ๐Ÿงน Cleanup and cache Nix/devenv', ` if: ${githubExpression('always()')}`, ' uses: ./.github/actions/save-nix-devenv', ' with:', ` nix-cache-hit: ${githubExpression('steps.setup.outputs.nix-cache-hit')}`, ` devenv-cache-hit: ${githubExpression('steps.setup.outputs.devenv-cache-hit')}`);
534
+ lines.push('', ' # --- Cleanup ------------------------------------------------------------', '', ` # Step ${stepNumber}`, ' - name: ๐Ÿงน Cleanup and cache Nix/devenv', ' # success() is default; always() still saves GH Nix cache after a red job.', ' if: always()', ' uses: ./.github/actions/save-nix-devenv', ' with:', ` nix-cache-hit: ${githubExpression('steps.setup.outputs.nix-cache-hit')}`, ` devenv-cache-hit: ${githubExpression('steps.setup.outputs.devenv-cache-hit')}`);
532
535
  return lines.join('\n').trimEnd();
533
536
  }
534
537
  function renderMacosPlatformSteps(options) {
@@ -554,7 +557,7 @@ function renderMacosPlatformSteps(options) {
554
557
  if (isSmoothBricksCodebasePackageName(options.repoName)) {
555
558
  lines.push('', ` # Step ${stepNumber++}`, ' - name: ๐Ÿ—๏ธ Build self-hosted smoo', ' # SmoothBricks self-hosts smoo from source for release commands.', ' run: nx build cli');
556
559
  }
557
- lines.push('', ` # Step ${stepNumber++}`, ' - name: ๐ŸŽ Build selected macOS and iOS release outputs', ' run:', ` smoo release build-platform-outputs --bump "${githubExpression('inputs.bump')}" --ref "${githubExpression('github.sha')}" --targets "${MACOS_PLATFORM_TARGET_GLOBS.join(',')}" --output`, ` "${githubExpression('runner.temp')}/macos-platform-outputs"`, '', ` # Step ${stepNumber++}`, ' - name: ๐Ÿ“ค Upload macOS platform outputs', ' uses: actions/upload-artifact@v7.0.1', ' with:', ` name: publish-macos-outputs-${githubExpression('github.run_id')}`, ` path: ${githubExpression('runner.temp')}/macos-platform-outputs`, ' if-no-files-found: error', ' retention-days: 1', ' include-hidden-files: true', '', ' # --- Cleanup ------------------------------------------------------------', '', ` # Step ${stepNumber}`, ' - name: ๐Ÿงน Cleanup and cache Nix/devenv', ` if: ${githubExpression('always()')}`, ' uses: ./.github/actions/save-nix-devenv', ' with:', ` nix-cache-hit: ${githubExpression('steps.setup.outputs.nix-cache-hit')}`, ` devenv-cache-hit: ${githubExpression('steps.setup.outputs.devenv-cache-hit')}`);
560
+ lines.push('', ` # Step ${stepNumber++}`, ' - name: ๐ŸŽ Build selected macOS and iOS release outputs', ' run:', ` smoo release build-platform-outputs --bump "${githubExpression('inputs.bump')}" --ref "${githubExpression('github.sha')}" --targets "${MACOS_PLATFORM_TARGET_GLOBS.join(',')}" --output`, ` "${githubExpression('runner.temp')}/macos-platform-outputs"`, '', ` # Step ${stepNumber++}`, ' - name: ๐Ÿงช Unit test macOS and iOS packages', ' run:', ` smoo github-ci nx-run-many --targets test --projects-with-targets "${MACOS_PLATFORM_TARGET_GLOBS.join(',')}"`, '', ` # Step ${stepNumber++}`, ' - name: ๐Ÿ“ค Upload macOS platform outputs', ' uses: actions/upload-artifact@v7.0.1', ' with:', ` name: publish-macos-outputs-${githubExpression('github.run_id')}`, ` path: ${githubExpression('runner.temp')}/macos-platform-outputs`, ' if-no-files-found: error', ' retention-days: 1', ' include-hidden-files: true', '', ' # --- Cleanup ------------------------------------------------------------', '', ` # Step ${stepNumber}`, ' - name: ๐Ÿงน Cleanup and cache Nix/devenv', ' # success() is default; always() still saves GH Nix cache after a red job.', ' if: always()', ' uses: ./.github/actions/save-nix-devenv', ' with:', ` nix-cache-hit: ${githubExpression('steps.setup.outputs.nix-cache-hit')}`, ` devenv-cache-hit: ${githubExpression('steps.setup.outputs.devenv-cache-hit')}`);
558
561
  return lines.join('\n').trimEnd();
559
562
  }
560
563
  function renderFinalLinuxPublishSteps(options) {
@@ -597,15 +600,15 @@ function renderFinalLinuxPublishSteps(options) {
597
600
  lines.push('', ` # Step ${stepNumber++}`, ' - name: ๐Ÿ—๏ธ Build self-hosted smoo', ' # SmoothBricks self-hosts smoo from source for release commands.', ' run: nx build cli');
598
601
  }
599
602
  lines.push('', ' # --- Repair -------------------------------------------------------------', '', ` # Step ${stepNumber++}`, ' - name: ๐Ÿงฏ Repair pending releases', ' run:', ` smoo release repair-pending --ref "${githubExpression('github.sha')}" --platform-outputs "${githubExpression('runner.temp')}/publish-artifacts/publish-macos-outputs-${githubExpression('github.run_id')}/repairs" --dry-run`, ` "${githubExpression('inputs.dry_run')}"`, '', ` # Step ${stepNumber++}`, ' - name: โ™ป๏ธ Restore validated release state', ' run:', ` git fetch "${githubExpression('runner.temp')}/publish-artifacts/publish-release-state-${githubExpression('github.run_id')}/release-state.bundle" HEAD --tags && git reset`, ` --hard "$(cat "${githubExpression('runner.temp')}/publish-artifacts/publish-release-state-${githubExpression('github.run_id')}/release-head")"`);
600
- lines.push('', ' # --- Validation ---------------------------------------------------------', '', ` # Step ${stepNumber++}`, ' - name: ๐Ÿ“ฆ Apply verified Linux outputs', ` if: ${githubExpression(`${mode} != 'none'`)}`, ' run:', ` smoo github-ci apply-outputs --source-sha "${githubExpression('needs.linux-release-candidate.outputs.release-sha')}"`, ` "${githubExpression('runner.temp')}/publish-artifacts/publish-release-outputs-${githubExpression('github.run_id')}"`);
603
+ lines.push('', ' # --- Validation ---------------------------------------------------------', '', ` # Step ${stepNumber++}`, ' - name: ๐Ÿ“ฆ Apply verified Linux outputs', ` if: ${mode} != 'none'`, ' run:', ` smoo github-ci apply-outputs --source-sha "${githubExpression('needs.linux-release-candidate.outputs.release-sha')}"`, ` "${githubExpression('runner.temp')}/publish-artifacts/publish-release-outputs-${githubExpression('github.run_id')}"`);
601
604
  if (hasLinuxPlatformTargets(options)) {
602
605
  lines.push(` "${githubExpression('runner.temp')}/publish-artifacts/publish-linux-outputs-${githubExpression('github.run_id')}"`);
603
606
  }
604
- lines.push('', ` # Step ${stepNumber++}`, ' - name: ๐ŸŽ Apply verified macOS outputs', ` if: ${githubExpression(`${mode} != 'none'`)}`, ' run:', ` smoo github-ci apply-outputs --source-sha "${githubExpression('github.sha')}"`, ` "${githubExpression('runner.temp')}/publish-artifacts/publish-macos-outputs-${githubExpression('github.run_id')}/current"`, '', ` # Step ${stepNumber++}`, ` - name: โœ… Validate restored release (${githubExpression(mode)})`, ` if: ${githubExpression(`${mode} != 'none'`)}`, ' run: smoo monorepo validate', '', ' # --- Release ------------------------------------------------------------', '', ` # Step ${stepNumber++}`, ` - name: ๐Ÿ“ฆ Publish release (${githubExpression(mode)})`, ' # smoo packs with Bun, then publishes tarballs with npm. Existing', ' # packages must already exist on npm and use trusted publishing/OIDC.', ' # Missing package names are bootstrapped locally before trust setup.', ` run: smoo release publish --bump "${githubExpression('inputs.bump')}" --dry-run "${githubExpression('inputs.dry_run')}"`);
607
+ lines.push('', ` # Step ${stepNumber++}`, ' - name: ๐ŸŽ Apply verified macOS outputs', ` if: ${mode} != 'none'`, ' run:', ` smoo github-ci apply-outputs --source-sha "${githubExpression('github.sha')}"`, ` "${githubExpression('runner.temp')}/publish-artifacts/publish-macos-outputs-${githubExpression('github.run_id')}/current"`, '', ` # Step ${stepNumber++}`, ` - name: โœ… Validate restored release (${githubExpression(mode)})`, ` if: ${mode} != 'none'`, ' run: smoo monorepo validate', '', ' # --- Release ------------------------------------------------------------', '', ` # Step ${stepNumber++}`, ` - name: ๐Ÿ“ฆ Publish release (${githubExpression(mode)})`, ' # smoo packs with Bun, then publishes tarballs with npm. Existing', ' # packages must already exist on npm and use trusted publishing/OIDC.', ' # Missing package names are bootstrapped locally before trust setup.', ` run: smoo release publish --bump "${githubExpression('inputs.bump')}" --dry-run "${githubExpression('inputs.dry_run')}"`);
605
608
  if (options.deploy === true) {
606
609
  lines.push('', ` # Step ${stepNumber++}`, ' - name: ๐Ÿš€ Deploy production', ' if:', " ${{ needs.linux-release-candidate.outputs.mode != 'none' && inputs.deploy_environment == 'production' &&", " inputs.dry_run != 'true' }}", ...deployEnvLines(options), ' run: smoo github-ci nx-deploy --configuration production --mode run-many --verify --name "Deploy Production"');
607
610
  }
608
- lines.push('', ' # --- Cleanup ------------------------------------------------------------', '', ` # Step ${stepNumber}`, ' - name: ๐Ÿงน Cleanup and cache Nix/devenv', ` if: ${githubExpression('always()')}`, ' uses: ./.github/actions/save-nix-devenv', ' with:', ` nix-cache-hit: ${githubExpression('steps.setup.outputs.nix-cache-hit')}`, ` devenv-cache-hit: ${githubExpression('steps.setup.outputs.devenv-cache-hit')}`);
611
+ lines.push('', ' # --- Cleanup ------------------------------------------------------------', '', ` # Step ${stepNumber}`, ' - name: ๐Ÿงน Cleanup and cache Nix/devenv', ' # success() is default; always() still saves GH Nix cache after a red job.', ' if: always()', ' uses: ./.github/actions/save-nix-devenv', ' with:', ` nix-cache-hit: ${githubExpression('steps.setup.outputs.nix-cache-hit')}`, ` devenv-cache-hit: ${githubExpression('steps.setup.outputs.devenv-cache-hit')}`);
609
612
  return lines.join('\n').trimEnd();
610
613
  }
611
614
  function hasMacosPlatformTargets(options) {
@@ -9,8 +9,8 @@ export declare function syncRootRuntimeVersions(root: string): Promise<void>;
9
9
  /**
10
10
  * Validate that package.json runtime pins agree with the LIVE PATH runtimes,
11
11
  * never a stored template. Offline by design: structural alignment only
12
- * (majors, exact bun pin, no `~major.0.0` floor) โ€” the registry is not
13
- * consulted. Repair: `smoo monorepo init --runtime-only` inside the devenv shell.
12
+ * (Node types float within the runtime major; Bun types stay exact) โ€” the registry
13
+ * is not consulted. Repair: `smoo monorepo init --runtime-only` inside the devenv shell.
14
14
  */
15
15
  export declare function validateRootRuntimeVersions(root: string): Promise<number>;
16
16
  export declare function validateRuntimePins(packageJson: PackageJson, runtime: RuntimeVersions): number;
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/monorepo/runtime.ts"],"names":[],"mappings":"AAGA,OAAO,EAGL,KAAK,WAAW,EAMjB,MAAM,gBAAgB,CAAC;AAExB,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAED,mGAAmG;AACnG,wBAAsB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAOpF;AAED,wBAAsB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAkCzE;AAED;;;;;GAKG;AACH,wBAAsB,2BAA2B,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAO/E;AAED,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,eAAe,GAAG,MAAM,CAmC9F;AAED,KAAK,mBAAmB,GAAG,OAAO,GAAG,OAAO,CAAC;AAgB7C,wBAAgB,qCAAqC,CACnD,WAAW,EAAE,MAAM,EACnB,cAAc,EAAE,MAAM,EACtB,OAAO,EAAE,mBAAmB,EAC5B,QAAQ,EAAE,SAAS,MAAM,EAAE,GAC1B,MAAM,CA2BR"}
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/monorepo/runtime.ts"],"names":[],"mappings":"AAGA,OAAO,EAGL,KAAK,WAAW,EAMjB,MAAM,gBAAgB,CAAC;AAExB,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAED,mGAAmG;AACnG,wBAAsB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAOpF;AAED,wBAAsB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAkCzE;AAED;;;;;GAKG;AACH,wBAAsB,2BAA2B,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAO/E;AAED,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,eAAe,GAAG,MAAM,CA8B9F;AAED,KAAK,mBAAmB,GAAG,OAAO,GAAG,OAAO,CAAC;AAgB7C,wBAAgB,qCAAqC,CACnD,WAAW,EAAE,MAAM,EACnB,cAAc,EAAE,MAAM,EACtB,OAAO,EAAE,mBAAmB,EAC5B,QAAQ,EAAE,SAAS,MAAM,EAAE,GAC1B,MAAM,CA2BR"}
@@ -39,8 +39,8 @@ export async function syncRootRuntimeVersions(root) {
39
39
  /**
40
40
  * Validate that package.json runtime pins agree with the LIVE PATH runtimes,
41
41
  * never a stored template. Offline by design: structural alignment only
42
- * (majors, exact bun pin, no `~major.0.0` floor) โ€” the registry is not
43
- * consulted. Repair: `smoo monorepo init --runtime-only` inside the devenv shell.
42
+ * (Node types float within the runtime major; Bun types stay exact) โ€” the registry
43
+ * is not consulted. Repair: `smoo monorepo init --runtime-only` inside the devenv shell.
44
44
  */
45
45
  export async function validateRootRuntimeVersions(root) {
46
46
  const packageJson = readJsonObject(join(root, 'package.json'));
@@ -68,13 +68,9 @@ export function validateRuntimePins(packageJson, runtime) {
68
68
  failures++;
69
69
  }
70
70
  const typesNode = packageJson.devDependencies?.['@types/node'] ?? null;
71
- const typesNodeParts = typesNode ? /^~(\d+)\.(\d+)\.(\d+)$/.exec(typesNode) : null;
71
+ const typesNodeParts = typesNode ? /^\^(\d+)\.(\d+)\.(\d+)$/.exec(typesNode) : null;
72
72
  if (!typesNodeParts || typesNodeParts[1] !== nodeMajor) {
73
- console.error(`package.json @types/node is ${typesNode ?? 'missing'} but the PATH node is v${runtime.node} โ€” types track the runtime major (~${nodeMajor}.x.y, newest published minor); ${repair}`);
74
- failures++;
75
- }
76
- else if (typesNodeParts[2] === '0' && typesNodeParts[3] === '0') {
77
- console.error(`package.json @types/node is pinned to the ~${nodeMajor}.0.0 floor โ€” tilde locks the first patch line and strands the repo on early broken releases; ${repair} to repin to the newest published ${nodeMajor}.x`);
73
+ console.error(`package.json @types/node is ${typesNode ?? 'missing'} but the PATH node is v${runtime.node} โ€” expected a caret range within the runtime major (^${nodeMajor}.x.y); ${repair}`);
78
74
  failures++;
79
75
  }
80
76
  return failures;
@@ -94,16 +90,15 @@ export function runtimeTypesRangeForPublishedVersions(packageName, runtimeVersio
94
90
  }
95
91
  if (pinMode === 'major') {
96
92
  const runtimeMajor = parsedRuntimeVersion[0].toString();
97
- // Newest published types WITHIN the runtime major โ€” never the `~major.0.0`
98
- // floor: tilde locks the patch line, so the floor can strand consumers on a
99
- // broken early release (e.g. @types/node 24.0.x's URLPattern/DOM TS2403
100
- // conflict, fixed in 24.13) with no path to the repaired minors.
93
+ // Anchor the range at the newest published types in the runtime major. The caret
94
+ // admits later patches and minors without crossing into a different Node major.
101
95
  const latestInMajor = latestVersion(versions.filter((version) => versionMajor(version) === runtimeMajor));
102
- if (latestInMajor) {
103
- return `~${latestInMajor}`;
96
+ if (!latestInMajor) {
97
+ throw new Error(`Unable to find published ${packageName} versions for runtime major ${runtimeMajor}`);
104
98
  }
99
+ return `^${latestInMajor}`;
105
100
  }
106
- else if (versions.includes(runtimeVersion)) {
101
+ if (versions.includes(runtimeVersion)) {
107
102
  return runtimeVersion;
108
103
  }
109
104
  const latest = latestVersion(versions);
@@ -111,7 +106,7 @@ export function runtimeTypesRangeForPublishedVersions(packageName, runtimeVersio
111
106
  throw new Error(`Unable to find any published ${packageName} versions`);
112
107
  }
113
108
  console.warn(`${packageName} has no published types for runtime ${runtimeVersion}; using ${latest}`);
114
- return pinMode === 'major' ? `~${latest}` : latest;
109
+ return latest;
115
110
  }
116
111
  function latestVersion(versions) {
117
112
  let latest = null;
@@ -1 +1 @@
1
- {"version":3,"file":"tool-validation.d.ts","sourceRoot":"","sources":["../../src/monorepo/tool-validation.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,KAAK,WAAW,EAAyB,MAAM,qBAAqB,CAAC;AAU9E,MAAM,WAAW,UAAU;IACzB,sBAAsB,EAAE,OAAO,CAAC;IAChC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,WAAW,GAAG,IAAI,CAAC;IAChC,MAAM,EAAE,UAAU,CAAC;CACpB;AAkDD,wBAAsB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKzE;AAED,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAStE;AAED,wBAAsB,8BAA8B,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBtG;AA2CD,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CAkBlF;AAED,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAY/D;AAED,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CA0B7D;AAED,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,GAAG,IAAI,GAAG,MAAM,CAyBvG;AAsBD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM,CAoB/E;AAED,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI,GAAG,MAAM,CAWhF;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAqB3D;AAsED,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAQxE"}
1
+ {"version":3,"file":"tool-validation.d.ts","sourceRoot":"","sources":["../../src/monorepo/tool-validation.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,KAAK,WAAW,EAAyB,MAAM,qBAAqB,CAAC;AAU9E,MAAM,WAAW,UAAU;IACzB,sBAAsB,EAAE,OAAO,CAAC;IAChC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,WAAW,GAAG,IAAI,CAAC;IAChC,MAAM,EAAE,UAAU,CAAC;CACpB;AAgDD,wBAAsB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKzE;AAED,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAStE;AAED,wBAAsB,8BAA8B,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBtG;AAqCD,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CAkBlF;AAED,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAY/D;AAED,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CA0B7D;AAED,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,GAAG,IAAI,GAAG,MAAM,CAyBvG;AAyBD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM,CAoB/E;AAED,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI,GAAG,MAAM,CAWhF;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAqB3D;AAsED,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAQxE"}