Skip to content

feat(cli): ratify ./console as a public subpath export — the out-of-repo consumer #13123 predicted - #13662

Merged
hotlong merged 1 commit into
mainfrom
feat/cli-console-subpath-export
Aug 31, 2026
Merged

feat(cli): ratify ./console as a public subpath export — the out-of-repo consumer #13123 predicted#13662
hotlong merged 1 commit into
mainfrom
feat/cli-console-subpath-export

Conversation

@hotlong

@hotlong hotlong commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

What

One deliberate door in the CLI's exports map: "./console"dist/utils/console.{js,d.ts} — the self-contained static-serve util (resolveConsolePath / hasConsoleDist / createConsoleStaticPlugin + drift-guard helpers; fs/path only, no oclif).

Why

#13123 sealed the CLI behind an exports map and its own body names this exact remedy for an out-of-repo consumer: ratify the subpath as public surface rather than read dist/ paths. That consumer exists — cloud's objectos-runtime node server mounts the Console SPA through this util, formerly via @objectstack/cli/dist/utils/console.js. Under the sealed map that specifier now fails at both layers:

  • types: tsup DTS refuses with TS2307 (measured on cloud's pin-bump build);
  • runtime: ERR_PACKAGE_PATH_NOT_EXPORTED, which the consumer's defensive catch turns into a silent API-only boot — a working deployment loses its console with nothing but a warn line.

Duplicating the util in cloud was rejected: it is 654 lines carrying the objectui-pin drift guards (#7752) and the mount-decision policy — a fork would drift by construction.

Scope

The surface grows by ONE named door, not back to "everything under dist/". check:published-files' GATED invariant stays green (the map names real entries); census floor untouched. Changeset: @objectstack/cli minor.

Gates at this head

Full 71-package build, full-repo lint, check:published-files, check-empty-changeset — all exit 0. Cloud-side consumer verified against a locally patched checkout of this exact map: runtime resolution returns all three functions, objectos-runtime DTS builds green, and cloud's five harness suites pass.

🤖 Generated with Claude Code

…-repo consumer #13123 predicted

#13123 sealed the CLI behind an `exports` map, and its own body names the
remedy for a consumer that was reading `dist/` paths: ratify the subpath as
public surface rather than keep the deep read. That consumer exists — cloud's
`objectos-runtime` node server mounts the Console SPA through the CLI's
self-contained static-serve util (`resolveConsolePath` / `hasConsoleDist` /
`createConsoleStaticPlugin`, fs/path only, no oclif) via what was
`@objectstack/cli/dist/utils/console.js`. Under the sealed map that specifier
throws ERR_PACKAGE_PATH_NOT_EXPORTED at BOTH layers: tsup's DTS build refuses
(TS2307), and at runtime the consumer's defensive catch silently degrades
every boot to API-only — a working deployment loses its console with nothing
but a warn line.

`./console` maps to exactly the module that was being consumed
(`dist/utils/console.{js,d.ts}`), so the surface grows by one deliberate
door, not back to "everything under dist/". check:published-files' GATED
invariant stays green (the map still names real entries), and the census
floor is untouched.

Gates run at this head: full 71-package build, full-repo lint,
check:published-files, check-empty-changeset — all exit 0.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@hotlong
hotlong enabled auto-merge August 31, 2026 05:38
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️ 1 changed file(s) yielded no anchor (packages/cli/package.json), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files. Nothing else in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 1 changed package(s)).

What this run could not see
  • 1 changed file(s) yielded no anchor (packages/cli/package.json) — pages documenting those are invisible to this run
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 23 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json c45d8e6b4ef915004f091e03134a9314587df13dpackageMentionDocs.

@github-actions github-actions Bot added dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation tooling labels Aug 31, 2026
@hotlong
hotlong added this pull request to the merge queue Aug 31, 2026
Merged via the queue into main with commit 8c82289 Aug 31, 2026
34 checks passed
@hotlong
hotlong deleted the feat/cli-console-subpath-export branch August 31, 2026 06:21
baozhoutao pushed a commit that referenced this pull request Sep 5, 2026
…e exports maps

An `exports` map is a PACKAGING contract, and inside this monorepo nothing is
sealed: every in-repo consumer reaches any file through a relative import, a
vitest alias or a `paths` entry. So the repo could not observe a sealing
regression at all, by construction — twice the seal 17.3.0 introduced (#13123)
was found after publish, by the consumer, during an upgrade (#13662, #15325).

`consumer-specifiers.ledger.json` imports that knowledge from outside: the bare
specifiers named out-of-repo consumers import, each with the consumer, a date
and the card that ratified it. The suite packs each ledgered package with
`pnpm pack`, unpacks it into a throwaway `node_modules` outside the workspace,
and resolves every specifier from there with Node's real resolver under both
the `require` and `import` conditions — failing with a message that names the
specifier AND the consumer it breaks.

Option A of #15589 only. Option B (a changeset-gated seal declaration in
`check:published-files`) is deliberately not here.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation size/xs tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant