fix(cli): convert to ESM to support @clack/prompts v1.x#206
Conversation
Switch the CLI package from CommonJS to ESM to resolve the ERR_REQUIRE_ESM error when importing @clack/prompts v1.x. This enables use of the latest version instead of being pinned to v0.11.0. Changes: - Add "type": "module" to package.json - Update tsconfig to use Node16 module resolution with rewriteRelativeImportExtensions - Update relative imports to use explicit .ts extensions (rewritten to .js at build time) Co-Authored-By: Claude Haiku 4.5 <[email protected]>
Greptile SummaryThis PR converts Key observations:
Confidence Score: 4/5
Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
subgraph CLI ["packages/cli (ESM — type: module)"]
A["agent.ts / provider.ts\nsetup-wizard.ts / team.ts\nupdate.ts"]
B["shared.ts\n(import rewritten to shared.js at build)"]
A -->|"import from './shared.ts'\n→ emits './shared.js'"| B
end
subgraph Core ["packages/core (CJS — no type: module)"]
C["dist/index.js\n(CommonJS output)"]
end
subgraph Clack ["@clack/prompts v1.x (ESM-only)"]
D["ESM-only package\n(requires ESM host)"]
end
B -->|"ESM → CJS interop\n(Node.js native)"| C
A -->|"ESM → CJS interop\n(Node.js native)"| C
A -->|"ESM import\n(now compatible)"| D
subgraph TS ["TypeScript 5.9.3 — module: Node16"]
E["rewriteRelativeImportExtensions: true\n.ts → .js in emitted output"]
end
CLI -.->|compiled by| TS
Last reviewed commit: 950984c |
| "name": "@tinyclaw/cli", | ||
| "version": "0.0.10", | ||
| "type": "module", | ||
| "main": "dist/shared.js", |
There was a problem hiding this comment.
main field is misleading for an ESM CLI package
The "main": "dist/shared.js" entry points to an internal utility module rather than a primary package entry. Now that the package is ESM ("type": "module"), any external require('@tinyclaw/cli') call will fail because ESM cannot be synchronously required. For a CLI-only package this is generally fine at runtime (since nothing imports it), but it would be cleaner to either:
- Remove
"main"entirely if the package is not meant to be imported programmatically, or - Add a proper
"exports"field mapping to communicate intent and support Node16 module resolution tooling properly.
Additionally, the absence of a "bin" field means the CLI scripts cannot be installed globally via npm — this was already the case before this PR, but converting to ESM is a good opportunity to revisit the package's public shape.
| "module": "Node16", | ||
| "moduleResolution": "Node16", | ||
| "rewriteRelativeImportExtensions": true |
There was a problem hiding this comment.
@tinyclaw/core lacks "exports" field required for clean Node16 resolution
With "moduleResolution": "Node16", TypeScript (and Node.js at runtime) prefer packages to declare a "exports" field so the module system knows exactly which format (CJS/ESM) is being published and which entry points are available. The referenced @tinyclaw/core package has no "exports" field — only a "main" field — while remaining a CommonJS package (no "type": "module").
TypeScript falls back to "main" in this case and the build will succeed, but strict Node16/NodeNext tooling (bundlers, tsc --build with declaration emit, newer Jest/Vitest configs) may warn or fail to resolve the package correctly. The safer approach is to add an "exports" field to packages/core/package.json:
"exports": {
".": {
"require": "./dist/index.js",
"types": "./dist/index.d.ts"
}
}This is not introduced by this PR per se, but the move to moduleResolution: "Node16" in the CLI makes the gap visible.
Description
Fixes #205 by converting the CLI package from CommonJS to ESM, allowing use of @clack/prompts v1.x instead of the legacy v0.11.0.
Changes
"type": "module"to packages/cli/package.jsonTesting
🤖 Generated with Claude Code