@smoothbricks/cli 0.10.3 → 0.10.5

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 (115) hide show
  1. package/README.md +9 -13
  2. package/dist/bun/preload.d.ts +13 -0
  3. package/dist/bun/preload.d.ts.map +1 -0
  4. package/dist/bun/preload.js +12 -0
  5. package/dist/cli.js +13 -5
  6. package/dist/generate/index.d.ts.map +1 -1
  7. package/dist/generate/index.js +0 -6
  8. package/dist/github-ci/index.d.ts.map +1 -1
  9. package/dist/github-ci/index.js +52 -16
  10. package/dist/github-ci/outputs.d.ts.map +1 -1
  11. package/dist/github-ci/outputs.js +1 -2
  12. package/dist/lib/cli-package.js +2 -2
  13. package/dist/lib/json.d.ts +120 -11
  14. package/dist/lib/json.d.ts.map +1 -1
  15. package/dist/lib/json.js +319 -29
  16. package/dist/lib/workspace.d.ts +7 -14
  17. package/dist/lib/workspace.d.ts.map +1 -1
  18. package/dist/lib/workspace.js +76 -82
  19. package/dist/monorepo/ci-workflow.d.ts +2 -0
  20. package/dist/monorepo/ci-workflow.d.ts.map +1 -1
  21. package/dist/monorepo/ci-workflow.js +27 -1
  22. package/dist/monorepo/git-config.js +2 -2
  23. package/dist/monorepo/index.d.ts +4 -2
  24. package/dist/monorepo/index.d.ts.map +1 -1
  25. package/dist/monorepo/index.js +19 -3
  26. package/dist/monorepo/lockfile.d.ts +14 -1
  27. package/dist/monorepo/lockfile.d.ts.map +1 -1
  28. package/dist/monorepo/lockfile.js +33 -21
  29. package/dist/monorepo/managed-files.d.ts +11 -0
  30. package/dist/monorepo/managed-files.d.ts.map +1 -1
  31. package/dist/monorepo/managed-files.js +57 -32
  32. package/dist/monorepo/package-policy.d.ts.map +1 -1
  33. package/dist/monorepo/package-policy.js +52 -45
  34. package/dist/monorepo/packed-manifest.d.ts +5 -2
  35. package/dist/monorepo/packed-manifest.d.ts.map +1 -1
  36. package/dist/monorepo/packed-manifest.js +16 -47
  37. package/dist/monorepo/packed-package.d.ts.map +1 -1
  38. package/dist/monorepo/packed-package.js +28 -16
  39. package/dist/monorepo/packs/index.d.ts.map +1 -1
  40. package/dist/monorepo/packs/index.js +14 -5
  41. package/dist/monorepo/publish-workflow.js +3 -1
  42. package/dist/monorepo/runtime.d.ts +15 -0
  43. package/dist/monorepo/runtime.d.ts.map +1 -1
  44. package/dist/monorepo/runtime.js +66 -12
  45. package/dist/monorepo/tool-validation.d.ts +2 -2
  46. package/dist/monorepo/tool-validation.d.ts.map +1 -1
  47. package/dist/monorepo/tool-validation.js +141 -38
  48. package/dist/monorepo/wrangler.d.ts.map +1 -1
  49. package/dist/monorepo/wrangler.js +13 -13
  50. package/dist/nx/index.d.ts +9 -7
  51. package/dist/nx/index.d.ts.map +1 -1
  52. package/dist/nx/index.js +48 -31
  53. package/dist/pr/index.d.ts.map +1 -1
  54. package/dist/pr/index.js +28 -32
  55. package/dist/release/candidates.d.ts +3 -2
  56. package/dist/release/candidates.d.ts.map +1 -1
  57. package/dist/release/candidates.js +4 -5
  58. package/dist/release/index.d.ts +1 -0
  59. package/dist/release/index.d.ts.map +1 -1
  60. package/dist/release/index.js +88 -59
  61. package/dist/wrangler/prepare-env.d.ts +0 -1
  62. package/dist/wrangler/prepare-env.d.ts.map +1 -1
  63. package/dist/wrangler/prepare-env.js +100 -51
  64. package/dist/wrangler/scaffold.d.ts.map +1 -1
  65. package/dist/wrangler/scaffold.js +12 -12
  66. package/managed/raw/envrc +5 -3
  67. package/managed/raw/git-format-staged.yml +19 -1
  68. package/managed/raw/patches/ttsc@0.19.3.patch +67 -0
  69. package/managed/raw/tooling/direnv/github-actions-bootstrap.sh +2 -1
  70. package/managed/raw/tooling/direnv/merge-newer-pins.sh +3 -3
  71. package/managed/raw/tooling/direnv/setup-environment.ts +170 -19
  72. package/managed/raw/tooling/git-hooks/pre-commit.sh +0 -6
  73. package/managed/templates/github/actions/cache-node-modules/action.yml +5 -2
  74. package/managed/templates/github/actions/cache-ttsc-plugins/action.yml +19 -0
  75. package/managed/templates/github/actions/setup-devenv/action.yml +5 -0
  76. package/managed/templates/github/workflows/managed-files.yml +80 -0
  77. package/package.json +15 -4
  78. package/src/bun/preload.ts +12 -0
  79. package/src/cli.ts +20 -8
  80. package/src/generate/index.ts +0 -6
  81. package/src/github-ci/index.ts +49 -18
  82. package/src/github-ci/outputs.ts +1 -2
  83. package/src/lib/cli-package.ts +2 -2
  84. package/src/lib/json.ts +293 -32
  85. package/src/lib/workspace.ts +88 -100
  86. package/src/monorepo/__tests__/ci-workflow.test.ts +3 -3
  87. package/src/monorepo/ci-workflow.ts +27 -1
  88. package/src/monorepo/git-config.ts +2 -2
  89. package/src/monorepo/index.ts +19 -3
  90. package/src/monorepo/lockfile.test.ts +35 -36
  91. package/src/monorepo/lockfile.ts +49 -24
  92. package/src/monorepo/managed-files.test.ts +1 -0
  93. package/src/monorepo/managed-files.ts +62 -38
  94. package/src/monorepo/package-policy.test.ts +20 -50
  95. package/src/monorepo/package-policy.ts +76 -59
  96. package/src/monorepo/packed-manifest.ts +18 -52
  97. package/src/monorepo/packed-package.ts +43 -22
  98. package/src/monorepo/packs/index.ts +14 -5
  99. package/src/monorepo/publish-workflow.ts +3 -1
  100. package/src/monorepo/runtime.test.ts +42 -3
  101. package/src/monorepo/runtime.ts +90 -12
  102. package/src/monorepo/tool-validation.test.ts +38 -16
  103. package/src/monorepo/tool-validation.ts +149 -41
  104. package/src/monorepo/wrangler.test.ts +11 -15
  105. package/src/monorepo/wrangler.ts +15 -15
  106. package/src/nx/index.test.ts +9 -5
  107. package/src/nx/index.ts +69 -42
  108. package/src/pr/index.ts +42 -36
  109. package/src/release/__tests__/candidates.test.ts +5 -4
  110. package/src/release/__tests__/trust-publisher.test.ts +7 -0
  111. package/src/release/candidates.ts +10 -17
  112. package/src/release/index.ts +110 -73
  113. package/src/wrangler/prepare-env.ts +75 -54
  114. package/src/wrangler/scaffold.test.ts +9 -12
  115. package/src/wrangler/scaffold.ts +13 -13
@@ -4,7 +4,8 @@ import { dirname, join, relative } from 'node:path';
4
4
  import { fileURLToPath, pathToFileURL } from 'node:url';
5
5
  import { publint } from 'publint';
6
6
  import { formatMessage } from 'publint/utils';
7
- import { isRecord } from '../lib/json.js';
7
+ import typia from 'typia';
8
+ import { parsePackageJsonText } from '../lib/json.js';
8
9
  import { printCommandOutput, runResult } from '../lib/run.js';
9
10
  import { listPublicPackages } from '../lib/workspace.js';
10
11
  import { readPackedPackageJson, validatePackedWorkspaceDependencies } from './packed-manifest.js';
@@ -60,7 +61,7 @@ async function validatePublint(_root, pkg, packed) {
60
61
  async function validatePackedManifest(root, pkg, packed) {
61
62
  let failures = 0;
62
63
  const packedPackage = await readPackedPackageJson(root, packed.path, pkg.name);
63
- for (const message of validatePackedWorkspaceDependencies(root, pkg, packedPackage)) {
64
+ for (const message of validatePackedWorkspaceDependencies(root, pkg, packedPackage, { mode: 'install' })) {
64
65
  console.error(message);
65
66
  failures++;
66
67
  }
@@ -71,11 +72,10 @@ async function validateAttw(root, pkg, packed) {
71
72
  const analysis = await attw.checkPackage(await createAttwPackageFromTarball(attw, root, packed.path), {
72
73
  excludeEntrypoints: nonJsExportEntrypoints(pkg.json.exports),
73
74
  });
74
- if (!isRecord(analysis) || analysis.types === false) {
75
+ if (!isAttwAnalysis(analysis) || analysis.types === false) {
75
76
  return 0;
76
77
  }
77
- const rawProblems = Array.isArray(analysis.problems) ? analysis.problems : [];
78
- const problems = rawProblems.filter(isReportedAttwProblem);
78
+ const problems = (analysis.problems ?? []).filter(isReportedAttwProblem);
79
79
  if (problems.length === 0) {
80
80
  return 0;
81
81
  }
@@ -85,10 +85,22 @@ async function validateAttw(root, pkg, packed) {
85
85
  console.error(`${pkg.path}: are-the-types-wrong validation failed`);
86
86
  return 1;
87
87
  }
88
+ const isAttwAnalysis = (() => {
89
+ const _io0 = input => true && (undefined === input.problems || Array.isArray(input.problems));
90
+ return input => "object" === typeof input && null !== input && false === Array.isArray(input) && _io0(input);
91
+ })();
92
+ const isAttwProblem = (() => {
93
+ const _io0 = input => "string" === typeof input.kind && (undefined === input.resolutionKind || "string" === typeof input.resolutionKind) && (undefined === input.entrypoint || "string" === typeof input.entrypoint);
94
+ return input => "object" === typeof input && null !== input && _io0(input);
95
+ })();
96
+ const isAttwCoreExport = (() => {
97
+ const _io0 = input => true && true;
98
+ return input => "object" === typeof input && null !== input && false === Array.isArray(input) && _io0(input);
99
+ })();
88
100
  async function loadAttwCore() {
89
101
  const packageJson = fileURLToPath(import.meta.resolve('@arethetypeswrong/core/package.json'));
90
102
  const core = await import(pathToFileURL(join(dirname(packageJson), 'dist', 'index.js')).href);
91
- if (!isRecord(core)) {
103
+ if (!isAttwCoreExport(core)) {
92
104
  throw new Error('@arethetypeswrong/core does not expose the expected API');
93
105
  }
94
106
  const PackageConstructor = core.Package;
@@ -117,8 +129,8 @@ async function createAttwPackageFromTarball(attw, root, tarballPath) {
117
129
  }
118
130
  function createAttwPackageFromDirectory(attw, packageDir) {
119
131
  const packageJson = readJsonFile(join(packageDir, 'package.json'));
120
- const packageName = typeof packageJson.name === 'string' ? packageJson.name : null;
121
- const packageVersion = typeof packageJson.version === 'string' ? packageJson.version : null;
132
+ const packageName = packageJson.name;
133
+ const packageVersion = packageJson.version;
122
134
  if (!packageName || !packageVersion) {
123
135
  throw new Error('packed package.json must contain name and version');
124
136
  }
@@ -142,14 +154,14 @@ function collectAttwFiles(root, current, packageName, files) {
142
154
  }
143
155
  }
144
156
  function readJsonFile(path) {
145
- const parsed = JSON.parse(readFileSync(path, 'utf8'));
146
- if (!isRecord(parsed)) {
157
+ const parsed = parsePackageJsonText(readFileSync(path, 'utf8'));
158
+ if (!parsed) {
147
159
  throw new Error(`${path} is not a JSON object`);
148
160
  }
149
161
  return parsed;
150
162
  }
151
163
  function isReportedAttwProblem(problem) {
152
- if (!isRecord(problem) || typeof problem.kind !== 'string') {
164
+ if (!isAttwProblem(problem)) {
153
165
  return false;
154
166
  }
155
167
  const flag = attwProblemFlag(problem.kind);
@@ -189,9 +201,6 @@ function attwProblemFlag(kind) {
189
201
  }
190
202
  }
191
203
  function formatProblemLocation(problem) {
192
- if (!isRecord(problem)) {
193
- return '';
194
- }
195
204
  const entrypoint = typeof problem.entrypoint === 'string' ? ` ${problem.entrypoint}` : '';
196
205
  const resolution = typeof problem.resolutionKind === 'string' ? ` ${formatResolutionKind(problem.resolutionKind)}` : '';
197
206
  return `${entrypoint}${resolution}`;
@@ -206,7 +215,7 @@ function formatResolutionKind(kind) {
206
215
  return kind;
207
216
  }
208
217
  function nonJsExportEntrypoints(exports) {
209
- if (!isRecord(exports)) {
218
+ if (exports === null || exports === undefined || typeof exports === 'string') {
210
219
  return [];
211
220
  }
212
221
  return Object.entries(exports)
@@ -219,7 +228,10 @@ function exportPointsToNonJs(value) {
219
228
  // Existence of the target files is still validated by publint.
220
229
  return value.endsWith('.wasm') || value.endsWith('.css');
221
230
  }
222
- return isRecord(value) && Object.values(value).some(exportPointsToNonJs);
231
+ if (value === null || value === undefined) {
232
+ return false;
233
+ }
234
+ return Object.values(value).some(exportPointsToNonJs);
223
235
  }
224
236
  async function packPackage(root, pkg) {
225
237
  const packageDir = join(root, pkg.path);
@@ -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;AA4GD,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,CAaxG"}
@@ -3,12 +3,12 @@ import { join } from 'node:path';
3
3
  import { printCommandOutput, runResult, runStatus } from '../../lib/run.js';
4
4
  import { readProjectTargets } from '../../nx/index.js';
5
5
  import { syncBunLockfileVersions, validateBunLockfileVersions } from '../lockfile.js';
6
- import { validateManagedFiles } from '../managed-files.js';
6
+ import { warnOnManagedFileDrift } from '../managed-files.js';
7
7
  import { fixNxSync, validateNxSync } from '../nx-sync.js';
8
8
  import { fixPackageHygiene, validatePackageHygiene } from '../package-hygiene.js';
9
9
  import { applyFixableMonorepoDefaults, applyNxReleaseDefaults, applyPublicPackageDefaults, applyWorkspaceDependencyDefaults, validateNxProjectNames, validateNxReleaseConfig, validatePublicPackageMetadata, validatePublicTags, validateRootPackagePolicy, validateWorkspaceDependencies, } from '../package-policy.js';
10
10
  import { validatePackedPublicPackageManifest, validatePackedPublicPackagePublint, validatePackedPublicPackageTypes, } from '../packed-package.js';
11
- import { syncRootRuntimeVersions } from '../runtime.js';
11
+ import { syncRootRuntimeVersions, validateRootRuntimeVersions } from '../runtime.js';
12
12
  import { applyToolConfigDefaults, validateToolConfig } from '../tool-validation.js';
13
13
  import { applyWranglerDefaults, validateWrangler } from '../wrangler.js';
14
14
  const packs = [
@@ -27,14 +27,23 @@ const packs = [
27
27
  async fixPreBuild(ctx) {
28
28
  applyFixableMonorepoDefaults(ctx.root);
29
29
  await applyToolConfigDefaults(ctx.root);
30
- syncBunLockfileVersions(ctx.root);
30
+ // Install/CI alignment only — do not rewrite -next to stable tags here.
31
+ syncBunLockfileVersions(ctx.root, { mode: 'install' });
31
32
  await fixNxSync(ctx.root, ctx.verbose === true);
32
33
  applyWorkspaceDependencyDefaults(ctx.root, { resolvedTargetsByProject: await readResolvedTargetsByProject(ctx) });
33
34
  },
34
35
  async validatePreBuild(ctx) {
35
- return (validateManagedFiles(ctx.root) +
36
+ // Runtime pins validate against the live PATH runtimes (devenv shell),
37
+ // never a stored template — outside devenv the PATH is not authoritative,
38
+ // mirroring the init-time syncRuntime gate above.
39
+ const runtimeFailures = ctx.syncRuntime ? await validateRootRuntimeVersions(ctx.root) : 0;
40
+ // Managed-file drift is derived state (CLI template x pinned version) with
41
+ // its own remediation flow; it warns instead of failing so validation only
42
+ // blocks on actual package issues. See warnOnManagedFileDrift.
43
+ warnOnManagedFileDrift(ctx.root);
44
+ return (runtimeFailures +
36
45
  validateRootPackagePolicy(ctx.root) +
37
- validateToolConfig(ctx.root) +
46
+ (await validateToolConfig(ctx.root)) +
38
47
  validateNxProjectNames(ctx.root) +
39
48
  validateNxReleaseConfig(ctx.root) +
40
49
  validateBunLockfileVersions(ctx.root) +
@@ -326,7 +326,9 @@ function yamlLinesForStep(step, options) {
326
326
  ' "$GITHUB_OUTPUT"',
327
327
  ];
328
328
  case PublishWorkflowStepKind.CheckManagedMonorepoFiles:
329
- return conditionalRunStep(step, 'smoo monorepo check');
329
+ // Drift is derived state with its own remediation PR; publishing only
330
+ // blocks on actual package issues (smoo monorepo validate).
331
+ return conditionalRunStep(step, 'smoo monorepo check --warn');
330
332
  case PublishWorkflowStepKind.Build:
331
333
  return conditionalRunStep(step, `smoo github-ci nx-run-many --targets build --projects "${githubExpression('steps.version.outputs.projects')}"`);
332
334
  case PublishWorkflowStepKind.Lint:
@@ -1,4 +1,19 @@
1
+ import { type PackageJson } from '../lib/json.js';
2
+ export interface RuntimeVersions {
3
+ node: string;
4
+ bun: string;
5
+ }
6
+ /** Live runtime versions from the shell PATH — the single source sync AND validate derive from. */
7
+ export declare function runtimeVersionsFromPath(root: string): Promise<RuntimeVersions>;
1
8
  export declare function syncRootRuntimeVersions(root: string): Promise<void>;
9
+ /**
10
+ * Validate that package.json runtime pins agree with the LIVE PATH runtimes,
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.
14
+ */
15
+ export declare function validateRootRuntimeVersions(root: string): Promise<number>;
16
+ export declare function validateRuntimePins(packageJson: PackageJson, runtime: RuntimeVersions): number;
2
17
  type RuntimeTypesPinMode = 'major' | 'exact';
3
18
  export declare function runtimeTypesRangeForPublishedVersions(packageName: string, runtimeVersion: string, pinMode: RuntimeTypesPinMode, versions: readonly string[]): string;
4
19
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/monorepo/runtime.ts"],"names":[],"mappings":"AAKA,wBAAsB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAqCzE;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,CAsBR"}
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,26 +1,32 @@
1
1
  import { existsSync } from 'node:fs';
2
2
  import { join } from 'node:path';
3
3
  import { $ } from 'bun';
4
- import { getOrCreateRecord, readJsonObject, setStringProperty, writeJsonObject } from '../lib/json.js';
4
+ import { ensureDependencyMap, ensureEngines, parseStringArrayText, readJsonObject, setPackageStringField, setStringProperty, writeJsonObject, } from '../lib/json.js';
5
+ /** Live runtime versions from the shell PATH — the single source sync AND validate derive from. */
6
+ export async function runtimeVersionsFromPath(root) {
7
+ const node = runtimeCommand(root, 'node');
8
+ const bun = runtimeCommand(root, 'bun');
9
+ return {
10
+ node: (await $ `${node} --version`.cwd(root).text()).trim().replace(/^v/, ''),
11
+ bun: (await $ `${bun} --version`.cwd(root).text()).trim(),
12
+ };
13
+ }
5
14
  export async function syncRootRuntimeVersions(root) {
6
15
  const packageJsonPath = join(root, 'package.json');
7
16
  const packageJson = readJsonObject(packageJsonPath);
8
17
  if (!packageJson) {
9
18
  throw new Error('package.json not found or invalid');
10
19
  }
11
- const node = runtimeCommand(root, 'node');
12
- const bun = runtimeCommand(root, 'bun');
13
- const nodeVersion = (await $ `${node} --version`.cwd(root).text()).trim().replace(/^v/, '');
14
- const bunVersion = (await $ `${bun} --version`.cwd(root).text()).trim();
20
+ const { node: nodeVersion, bun: bunVersion } = await runtimeVersionsFromPath(root);
15
21
  const nodeMajor = nodeVersion.split('.', 1)[0];
16
22
  if (!nodeMajor) {
17
23
  throw new Error(`Unable to derive Node major version from ${nodeVersion}`);
18
24
  }
19
25
  let changed = false;
20
- const engines = getOrCreateRecord(packageJson, 'engines');
26
+ const engines = ensureEngines(packageJson);
21
27
  changed = setStringProperty(engines, 'node', `>=${nodeMajor}.0.0`) || changed;
22
- changed = setStringProperty(packageJson, 'packageManager', `bun@${bunVersion}`) || changed;
23
- const devDependencies = getOrCreateRecord(packageJson, 'devDependencies');
28
+ changed = setPackageStringField(packageJson, 'packageManager', `bun@${bunVersion}`) || changed;
29
+ const devDependencies = ensureDependencyMap(packageJson, 'devDependencies');
24
30
  changed =
25
31
  setStringProperty(devDependencies, '@types/node', await runtimeTypesRange(root, '@types/node', nodeVersion, 'major')) || changed;
26
32
  changed =
@@ -30,10 +36,53 @@ export async function syncRootRuntimeVersions(root) {
30
36
  console.log('updated package.json runtime versions');
31
37
  }
32
38
  }
39
+ /**
40
+ * Validate that package.json runtime pins agree with the LIVE PATH runtimes,
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.
44
+ */
45
+ export async function validateRootRuntimeVersions(root) {
46
+ const packageJson = readJsonObject(join(root, 'package.json'));
47
+ if (!packageJson) {
48
+ console.error('package.json not found or invalid');
49
+ return 1;
50
+ }
51
+ return validateRuntimePins(packageJson, await runtimeVersionsFromPath(root));
52
+ }
53
+ export function validateRuntimePins(packageJson, runtime) {
54
+ const nodeMajor = runtime.node.split('.', 1)[0];
55
+ if (!nodeMajor) {
56
+ throw new Error(`Unable to derive Node major version from ${runtime.node}`);
57
+ }
58
+ let failures = 0;
59
+ const repair = 'run `smoo monorepo init --runtime-only` inside the devenv shell';
60
+ const enginesNode = packageJson.engines?.node ?? null;
61
+ if (enginesNode !== `>=${nodeMajor}.0.0`) {
62
+ console.error(`package.json engines.node is ${enginesNode ?? 'missing'} but the PATH node is v${runtime.node} — expected >=${nodeMajor}.0.0; ${repair}`);
63
+ failures++;
64
+ }
65
+ const packageManager = packageJson.packageManager ?? null;
66
+ if (packageManager !== `bun@${runtime.bun}`) {
67
+ console.error(`package.json packageManager is ${packageManager ?? 'missing'} but the PATH bun is ${runtime.bun} — expected bun@${runtime.bun}; ${repair}`);
68
+ failures++;
69
+ }
70
+ const typesNode = packageJson.devDependencies?.['@types/node'] ?? null;
71
+ const typesNodeParts = typesNode ? /^~(\d+)\.(\d+)\.(\d+)$/.exec(typesNode) : null;
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`);
78
+ failures++;
79
+ }
80
+ return failures;
81
+ }
33
82
  async function runtimeTypesRange(root, packageName, runtimeVersion, pinMode) {
34
83
  const versionsText = await $ `bun pm view ${packageName} versions --json`.cwd(root).text();
35
- const versions = JSON.parse(versionsText);
36
- if (!Array.isArray(versions) || !versions.every((version) => typeof version === 'string')) {
84
+ const versions = parseStringArrayText(versionsText);
85
+ if (!versions) {
37
86
  throw new Error(`Unable to read published ${packageName} versions`);
38
87
  }
39
88
  return runtimeTypesRangeForPublishedVersions(packageName, runtimeVersion, pinMode, versions);
@@ -45,8 +94,13 @@ export function runtimeTypesRangeForPublishedVersions(packageName, runtimeVersio
45
94
  }
46
95
  if (pinMode === 'major') {
47
96
  const runtimeMajor = parsedRuntimeVersion[0].toString();
48
- if (latestVersion(versions.filter((version) => versionMajor(version) === runtimeMajor))) {
49
- return `~${runtimeMajor}.0.0`;
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.
101
+ const latestInMajor = latestVersion(versions.filter((version) => versionMajor(version) === runtimeMajor));
102
+ if (latestInMajor) {
103
+ return `~${latestInMajor}`;
50
104
  }
51
105
  }
52
106
  else if (versions.includes(runtimeVersion)) {
@@ -9,7 +9,7 @@ export interface ToolContext {
9
9
  policy: ToolPolicy;
10
10
  }
11
11
  export declare function applyToolConfigDefaults(root: string): Promise<void>;
12
- export declare function validateToolConfig(root: string): number;
12
+ export declare function validateToolConfig(root: string): Promise<number>;
13
13
  export declare function applyRootDevDependencyDefaults(root: string, context: ToolContext): Promise<void>;
14
14
  export declare function applyToolingPackageDefaults(root: string, policy: ToolPolicy): void;
15
15
  export declare function applyToolingWorkspaceDefault(root: string): void;
@@ -18,5 +18,5 @@ export declare function validateRootDevDependencies(policy: ToolPolicy, rootPack
18
18
  export declare function validateToolingPackage(root: string, policy: ToolPolicy): number;
19
19
  export declare function validateToolingWorkspace(rootPackage: PackageJson | null): number;
20
20
  export declare function validateDevenvPackages(root: string): number;
21
- export declare function readToolContext(root: string): ToolContext;
21
+ export declare function readToolContext(root: string): Promise<ToolContext>;
22
22
  //# sourceMappingURL=tool-validation.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tool-validation.d.ts","sourceRoot":"","sources":["../../src/monorepo/tool-validation.ts"],"names":[],"mappings":"AAIA,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;AAiCD,wBAAsB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKzE;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQvD;AAED,wBAAsB,8BAA8B,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAuBtG;AAoCD,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;AAED,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,CAmB3D;AA0DD,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAQzD"}
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"}