@ultimat3/cli 8.0.0 → 10.0.0

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 (64) hide show
  1. package/CLAUDE.md +9 -3
  2. package/package.json +26 -25
  3. package/src/affected.ts +0 -3
  4. package/src/app-boundaries.ts +4 -5
  5. package/src/app-env.ts +7 -2
  6. package/src/app-load.ts +7 -0
  7. package/src/browser-launcher.ts +0 -2
  8. package/src/budgets.ts +4 -3
  9. package/src/cmd-build.ts +2 -2
  10. package/src/cmd-db-branch.ts +2 -2
  11. package/src/cmd-deploy.ts +20 -6
  12. package/src/cmd-docs.ts +2 -1
  13. package/src/cmd-doctor.ts +3 -5
  14. package/src/cmd-env.ts +2 -2
  15. package/src/cmd-fix.ts +2 -4
  16. package/src/cmd-new.ts +2 -2
  17. package/src/cmd-shot.ts +22 -2
  18. package/src/db-finding.ts +2 -2
  19. package/src/db-seed.ts +0 -3
  20. package/src/dev-assets.ts +4 -7
  21. package/src/dev-cache.ts +140 -36
  22. package/src/dev-lock.ts +8 -7
  23. package/src/dev-purge.ts +120 -0
  24. package/src/dev-queue.ts +31 -6
  25. package/src/dev-render.ts +11 -14
  26. package/src/dev-runtime.ts +62 -15
  27. package/src/dev-storage.ts +8 -2
  28. package/src/dev-sync.ts +37 -2
  29. package/src/document-styles.ts +4 -2
  30. package/src/drift.ts +3 -2
  31. package/src/error-codes.ts +9 -2
  32. package/src/error-contract.ts +5 -5
  33. package/src/errors.ts +1 -29
  34. package/src/flag-reads.ts +2 -2
  35. package/src/generate-write.ts +3 -2
  36. package/src/guards.ts +4 -4
  37. package/src/index.ts +2 -6
  38. package/src/island-bundle.ts +34 -10
  39. package/src/island-routes.ts +7 -1
  40. package/src/island-styles.ts +1 -1
  41. package/src/mcp-errors.ts +2 -2
  42. package/src/metrics-endpoint.ts +0 -2
  43. package/src/output.ts +2 -2
  44. package/src/prerender.ts +34 -20
  45. package/src/runtime-overrides.ts +1 -1
  46. package/src/serve.ts +1 -1
  47. package/src/solid-loader.ts +1 -1
  48. package/src/static-report.ts +41 -3
  49. package/src/style-csp.ts +2 -1
  50. package/src/templates/scaffold-container.ts +12 -0
  51. package/src/templates/scaffold-docs.ts +11 -4
  52. package/src/templates/scaffold-domain-package.ts +3 -1
  53. package/src/templates/scaffold-repo.ts +19 -9
  54. package/src/templates/slice-foundation.ts +3 -5
  55. package/src/test-shards.ts +2 -2
  56. package/src/tsconfig-references.ts +2 -2
  57. package/src/verify-checks.ts +3 -2
  58. package/src/verify-floor.ts +8 -6
  59. package/src/verify-run.ts +2 -2
  60. package/src/verify-step.ts +2 -1
  61. package/src/verify-test-run.ts +2 -2
  62. package/src/workspace-checks.ts +10 -12
  63. package/src/workspace-graph.ts +3 -2
  64. package/src/write-line.ts +7 -1
@@ -7,7 +7,7 @@
7
7
  // all, and `join` builds the host-separator path to it.
8
8
  import { existsSync } from 'node:fs';
9
9
  import { join } from 'node:path';
10
- import { docsFor } from './error-codes';
10
+ import { ERROR_DOCS_URL, renderThrowable } from '@ultimat3/core';
11
11
  import type { Finding } from './output';
12
12
  import { VERIFY_STEP_NAMES } from './verify-step';
13
13
 
@@ -43,8 +43,10 @@ export function parseVerifyFloor(
43
43
  try {
44
44
  payload = JSON.parse(text);
45
45
  } catch (error) {
46
- const reason = error instanceof Error ? error.message : String(error);
47
- return { steps: [], problems: [`it does not parse as JSON (${reason})`] };
46
+ // `renderThrowable`, never `error instanceof Error ? error.message : String(error)`: both halves
47
+ // run on a value this process did not build, and either can throw one line before the guard that
48
+ // was meant to make the path safe (`metrics-endpoint.ts` states the same rule over `stringField`).
49
+ return { steps: [], problems: [`it does not parse as JSON (${renderThrowable(error)})`] };
48
50
  }
49
51
  const steps = asRecord(payload)?.['steps'];
50
52
  if (!Array.isArray(steps)) {
@@ -92,7 +94,7 @@ export const vanishedSuiteFinding = (step: string): Finding => ({
92
94
  code: 'X_VERIFY_SUITE_VANISHED',
93
95
  cause: `${VERIFY_FLOOR_FILE} requires the ${step} step and this run found nothing for it to check`,
94
96
  fix: `x verify --json # restore the ${step} suite, or drop "${step}" from ${VERIFY_FLOOR_FILE} in the commit that says why`,
95
- docs: docsFor('X_VERIFY_SUITE_VANISHED'),
97
+ docs: ERROR_DOCS_URL,
96
98
  at: VERIFY_FLOOR_FILE,
97
99
  });
98
100
 
@@ -111,7 +113,7 @@ export const skippedSuiteFinding = (step: string, skipped: number): Finding => (
111
113
  code: 'X_VERIFY_SUITE_VANISHED',
112
114
  cause: `${VERIFY_FLOOR_FILE} requires the ${step} step and all ${skipped} test(s) it found skipped themselves, so nothing ran`,
113
115
  fix: `x test ${step} --json # then set what the suite skips without, or drop "${step}" from ${VERIFY_FLOOR_FILE} in the commit that says why`,
114
- docs: docsFor('X_VERIFY_SUITE_VANISHED'),
116
+ docs: ERROR_DOCS_URL,
115
117
  at: VERIFY_FLOOR_FILE,
116
118
  });
117
119
 
@@ -128,6 +130,6 @@ export const floorProblemFindings = (floor: VerifyFloor | undefined): readonly F
128
130
  code: 'X_CONFIG_INVALID',
129
131
  cause: `${VERIFY_FLOOR_FILE} is not a suite floor: ${problem}`,
130
132
  fix: `x verify --json # then write ${VERIFY_FLOOR_FILE} as {"steps":["unit","contract"]}, naming only steps it ran`,
131
- docs: docsFor('X_CONFIG_INVALID'),
133
+ docs: ERROR_DOCS_URL,
132
134
  at: VERIFY_FLOOR_FILE,
133
135
  }));
package/src/verify-run.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  // `cmd-verify.ts` because `x build` and the MCP host run the gate without going through the
3
3
  // command: what a run means — never bail early, count what actually ran — belongs to neither.
4
4
 
5
- import { renderThrowable } from '@ultimat3/core';
5
+ import { ERROR_DOCS_URL, renderThrowable } from '@ultimat3/core';
6
6
  import { msg } from './messages';
7
7
  import type { CommandResult, Finding, StepResult } from './output';
8
8
  import {
@@ -139,6 +139,6 @@ function findingOf(error: unknown, step: string): Finding {
139
139
  code: 'X_VERIFY_FAILED',
140
140
  cause: `step "${step}" threw: ${cause}`,
141
141
  fix: 'x verify --json',
142
- docs: 'https://ultimate.dev/errors/X_VERIFY_FAILED',
142
+ docs: ERROR_DOCS_URL,
143
143
  };
144
144
  }
@@ -2,6 +2,7 @@
2
2
  // repo feeds it findings it could not produce on its own. Split from the step list so a step
3
3
  // implementation can live beside the code it checks without importing the list.
4
4
 
5
+ import { ERROR_DOCS_URL } from '@ultimat3/core';
5
6
  import type { ExecResult, Runner } from './exec';
6
7
  import { execOutput } from './exec';
7
8
  import type { Finding } from './output';
@@ -106,7 +107,7 @@ export function fromExec(result: ExecResult, finding: Omit<Finding, 'docs'>): St
106
107
  if (result.ok) return { ok: true, findings: [], output: execOutput(result) };
107
108
  return {
108
109
  ok: false,
109
- findings: [{ ...finding, docs: `https://ultimate.dev/errors/${finding.code}` }],
110
+ findings: [{ ...finding, docs: ERROR_DOCS_URL }],
110
111
  output: execOutput(result),
111
112
  };
112
113
  }
@@ -3,7 +3,7 @@
3
3
  // happens to them once selected — a wrong file list is never a race, and a race is never a
4
4
  // selection bug.
5
5
 
6
- import { docsFor } from './error-codes';
6
+ import { ERROR_DOCS_URL } from '@ultimat3/core';
7
7
  import type { Runner } from './exec';
8
8
  import { execOutput } from './exec';
9
9
  import type { Finding } from './output';
@@ -51,7 +51,7 @@ export async function runParallel(options: ParallelRunOptions): Promise<StepOutc
51
51
  // The reproduction has to name every input to the split, or it reruns a different file set:
52
52
  // `reproduceFor` is the one place that rule lives, shared with `x test`.
53
53
  fix: reproduceFor(shard, { workers: shards.length, type: options.type }),
54
- docs: docsFor('X_TEST_SHARD_FAILED'),
54
+ docs: ERROR_DOCS_URL,
55
55
  });
56
56
  }
57
57
  // Only the failing shards' output: a green 8-way split would otherwise print eight summaries,
@@ -5,7 +5,7 @@
5
5
 
6
6
  import { existsSync } from 'node:fs';
7
7
  import { join } from 'node:path';
8
- import { renderCauseValue } from '@ultimat3/core';
8
+ import { ERROR_DOCS_URL, renderCauseValue } from '@ultimat3/core';
9
9
  import type { Finding } from './output';
10
10
  import { eachSourceFile, isGenerated } from './source-files';
11
11
  import { checkRootReferences } from './tsconfig-references';
@@ -14,13 +14,11 @@ export const LINE_CEILING = 500;
14
14
 
15
15
  export const PACKAGE_FILES = ['README.md', 'CLAUDE.md', 'tsconfig.json', 'src/index.ts'] as const;
16
16
 
17
- const docs = (code: string): string => `https://ultimate.dev/errors/${code}`;
18
-
19
17
  export const tooLongFinding = (path: string, lines: number): Finding => ({
20
18
  code: 'X_FILE_TOO_LONG',
21
19
  cause: `${path} is ${lines} lines, over the ${LINE_CEILING} line ceiling`,
22
20
  fix: `split ${path}: one file, one responsibility`,
23
- docs: docs('X_FILE_TOO_LONG'),
21
+ docs: ERROR_DOCS_URL,
24
22
  at: path,
25
23
  });
26
24
 
@@ -49,7 +47,7 @@ export const missingFileFinding = (dir: string, file: string, scaffolder: boolea
49
47
  fix: scaffolder
50
48
  ? `bun run scripts/new-package.ts ${dir} --only ${file}`
51
49
  : `add packages/${dir}/${file}, shaped like the one in a sibling package`,
52
- docs: docs('X_PACKAGE_SHAPE'),
50
+ docs: ERROR_DOCS_URL,
53
51
  at: `packages/${dir}/${file}`,
54
52
  });
55
53
 
@@ -68,7 +66,7 @@ export const badVersionFinding = (dir: string, found: unknown): Finding => ({
68
66
  // this finding with a TypeError from inside the gate.
69
67
  cause: `packages/${dir}/package.json has no semver "version" (found ${renderCauseValue(found)})`,
70
68
  fix: `set a semver "version" in packages/${dir}/package.json, then: bun run verify`,
71
- docs: docs('X_PACKAGE_SHAPE'),
69
+ docs: ERROR_DOCS_URL,
72
70
  at: `packages/${dir}/package.json`,
73
71
  });
74
72
 
@@ -103,7 +101,7 @@ export const versionSkewFinding = (dir: string, found: string, expected: string)
103
101
  code: 'X_RELEASE_VERSION_SKEW',
104
102
  cause: `packages/${dir} is at ${found}, not the lockstep version ${expected}`,
105
103
  fix: `bun run scripts/release.ts --version ${expected}`,
106
- docs: docs('X_RELEASE_VERSION_SKEW'),
104
+ docs: ERROR_DOCS_URL,
107
105
  at: `packages/${dir}/package.json`,
108
106
  });
109
107
 
@@ -116,7 +114,7 @@ export const pinSkewFinding = (
116
114
  code: 'X_RELEASE_VERSION_SKEW',
117
115
  cause: `packages/${dir} pins ${dep} at ${range}, not the lockstep version ${expected}`,
118
116
  fix: `bun run scripts/release.ts --version ${expected}`,
119
- docs: docs('X_RELEASE_VERSION_SKEW'),
117
+ docs: ERROR_DOCS_URL,
120
118
  at: `packages/${dir}/package.json`,
121
119
  });
122
120
 
@@ -167,7 +165,7 @@ export const missingPublishedFileFinding = (dir: string, entry: string): Finding
167
165
  code: 'X_PACKAGE_SHAPE',
168
166
  cause: `packages/${dir}/package.json ships "${entry}" in "files", but packages/${dir}/${entry} does not exist`,
169
167
  fix: `add packages/${dir}/${entry}, or drop "${entry}" from "files" in packages/${dir}/package.json`,
170
- docs: docs('X_PACKAGE_SHAPE'),
168
+ docs: ERROR_DOCS_URL,
171
169
  at: `packages/${dir}/package.json`,
172
170
  });
173
171
 
@@ -175,7 +173,7 @@ export const publishesTestsFinding = (dir: string): Finding => ({
175
173
  code: 'X_PACKAGE_SHAPE',
176
174
  cause: `packages/${dir}/package.json does not exclude ${TEST_EXCLUSION} from "files"`,
177
175
  fix: `add "${TEST_EXCLUSION}" to "files" in packages/${dir}/package.json, after "src"`,
178
- docs: docs('X_PACKAGE_SHAPE'),
176
+ docs: ERROR_DOCS_URL,
179
177
  at: `packages/${dir}/package.json`,
180
178
  });
181
179
 
@@ -196,7 +194,7 @@ export const buildArtifactsFinding = (dir: string, count: number): Finding => ({
196
194
  code: 'X_PACKAGE_SHAPE',
197
195
  cause: `packages/${dir}/src/ contains ${count} build artifacts (.d.ts, .js, .map files)`,
198
196
  fix: `find packages/${dir}/src ${SWEEP_PREDICATE} -delete`,
199
- docs: docs('X_PACKAGE_SHAPE'),
197
+ docs: ERROR_DOCS_URL,
200
198
  at: `packages/${dir}/src/`,
201
199
  });
202
200
 
@@ -209,7 +207,7 @@ export const noFilesAllowlistFinding = (dir: string): Finding => ({
209
207
  code: 'X_PACKAGE_SHAPE',
210
208
  cause: `packages/${dir}/package.json publishes with no "files" allowlist, so the tarball carries whatever is in the directory`,
211
209
  fix: `add "files": ["src", "${TEST_EXCLUSION}", "README.md", "LICENSE"] to packages/${dir}/package.json`,
212
- docs: docs('X_PACKAGE_SHAPE'),
210
+ docs: ERROR_DOCS_URL,
213
211
  at: `packages/${dir}/package.json`,
214
212
  });
215
213
 
@@ -4,6 +4,7 @@
4
4
  // for `tsc` and is invisible to bun, to `--filter` ordering and to any change-detection tool.
5
5
 
6
6
  import { join } from 'node:path';
7
+ import { ERROR_DOCS_URL } from '@ultimat3/core';
7
8
  import type { Finding } from './output';
8
9
  import { eachSourceFile, isGenerated, isTest, isVendored } from './source-files';
9
10
  import { maskLiterals } from './ts-scan';
@@ -184,7 +185,7 @@ export const unreadableWorkspaceFinding = (path: string): Finding => ({
184
185
  code: 'X_APP_PACKAGE_INVALID',
185
186
  cause: `${path} is claimed by the root "workspaces" globs and supplies no readable "name"`,
186
187
  fix: `repair the JSON and the "name" in ${path}, or drop its directory from "workspaces" in package.json`,
187
- docs: 'https://ultimate.dev/errors/X_APP_PACKAGE_INVALID',
188
+ docs: ERROR_DOCS_URL,
188
189
  at: path,
189
190
  });
190
191
 
@@ -198,7 +199,7 @@ export const undeclaredWorkspaceDepFinding = (
198
199
  // The exact line to paste, at the version the target really carries: a `workspace:*` range would
199
200
  // resolve and then fail `checkLockstep`, which compares a sibling pin against the version.
200
201
  fix: `add "${to.name}": "${to.version ?? '0.0.0'}" to "dependencies" in ${from.dir}/package.json`,
201
- docs: 'https://ultimate.dev/errors/X_WORKSPACE_DEP_UNDECLARED',
202
+ docs: ERROR_DOCS_URL,
202
203
  at: `${from.dir}/package.json`,
203
204
  });
204
205
 
package/src/write-line.ts CHANGED
@@ -5,6 +5,9 @@
5
5
 
6
6
  // `node:fs`, and unavoidable: Bun has no synchronous stdout write of its own.
7
7
  import { writeSync } from 'node:fs';
8
+ // The one import beyond `node:fs`, and it costs nothing here: `create-ultimate` reaches this
9
+ // module through `@ultimat3/cli`'s barrel, which has already evaluated core.
10
+ import { stringField } from '@ultimat3/core';
8
11
 
9
12
  /**
10
13
  * Write to stdout and be certain it arrived, even if the next statement exits the process.
@@ -29,7 +32,10 @@ function writeTo(fd: 1 | 2, line: string): void {
29
32
  try {
30
33
  written += writeSync(fd, buffer, written, buffer.length - written);
31
34
  } catch (cause) {
32
- if ((cause as NodeJS.ErrnoException).code !== 'EAGAIN') throw cause;
35
+ // `stringField`, never a cast plus a property read — the rule `metrics-endpoint.ts` states
36
+ // and `caught-value-reads.test.ts` enforces. Here it is also the difference between
37
+ // rethrowing and an infinite loop: a `code` that cannot be read must not read as `EAGAIN`.
38
+ if (stringField(cause, 'code') !== 'EAGAIN') throw cause;
33
39
  }
34
40
  }
35
41
  }