feat(create-sanity): standalone bundled create-sanity package#761
feat(create-sanity): standalone bundled create-sanity package#761
Conversation
…rectly Replaces the spawn-wrapper approach with a TypeScript entry point that parses flags using @oclif/core/parser (reusing InitCommand.flags for exact parity) and calls initAction() directly. Uses no-op telemetry stub. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Switch from esbuild to Rollup for the create-sanity standalone bundle to enable better tree-shaking of barrel exports. Rollup resolves @sanity/cli-core source directly via alias plugin so it can tree-shake unused exports from the barrel. Plugins: alias, node-resolve, commonjs, json, esbuild (transpile only). Bundle size is ~13MB (same as esbuild - tree-shaking improvements will come in subsequent tasks with stub removal). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add lightweight error formatting utilities that match oclif's pretty-printed error output (bang prefix, word wrap, clean stacks, suggestions) without depending on @oclif/core. - CLIError: formatted error with oclif-compatible shape so oclif's error handler still recognizes it when thrown from commands - CLIWarning: same but with yellow bang prefix - error()/warn(): standalone functions for printing to stderr Update NonInteractiveError and ProjectRootNotFoundError to extend our CLIError instead of oclif's. Replace oclif ux imports in apiClient.ts and getCliTelemetry.ts with node:util styleText and our warn(). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace oclif ux.warn/ux.stdout with our own warn() from @sanity/cli-core/ux in setupMCP.ts. Replace console.log for stdout output. Replace CLIError with InitError in createOrAppendEnvVars.ts. Remove oclif import from promptForDefaultConfig.ts. These files are transitively bundled into create-sanity, so removing oclif imports here prevents the entire oclif runtime from being pulled into the standalone bundle. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extract flag definitions from InitCommand into plain objects in flags.ts with zero @oclif/core imports. These can be consumed by both the oclif command (via toOclifFlags adapter) and create-sanity's standalone entry point (via node:util parseArgs). - flags.ts: POJO flag/arg definitions shared across consumers - flagAdapter.ts: toOclifFlags/toOclifArgs converters - init.ts: uses adapter instead of direct oclif flag helpers - types.ts: env flag validation moved to flagsToInitOptions Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rewrite the standalone entry point to use parseArgs instead of @oclif/core/parser, consuming the shared POJO flag definitions directly. This eliminates @oclif/core from the bundle entirely. - Handles --no-<flag> negation via companion boolean flags - Adds --help with formatted flag listing - Validates flag types at runtime - Removes module stubs (no longer needed with Rollup tree-shaking) - Simplifies Rollup config (no typescript external needed) Bundle: 2.9 MB with zero oclif, zero typescript, zero stubs. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add stdout/stderr output helpers to @sanity/cli-core/ux to avoid bare console.log/console.error in lint-strict packages - Fix type errors: OclifChar narrowing, oclif overload disambiguation, FlagDef iteration, Output.warn/error signatures, noopTelemetry - Fix lint: eslint-disable for error output layer, perfectionist sorting - Use stdout() from cli-core/ux in setupMCP and promptForDefaultConfig - Add package manager detection for help text (npm/pnpm/yarn) - Handle ERR_PARSE_ARGS_UNKNOWN_OPTION with clean error message - Delete old create-sanity files: build.ts, index.js, test.js, vitest.config.mjs (replaced by rollup config and new test suite) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Tests run against the built dist/index.js bundle and cover: - --help output with flag listing - Package manager detection (npm/pnpm/yarn) in help text - Hidden flags not shown in help - -h shorthand - --help precedence over other flags - Invalid flag produces clean error (no stack trace) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove unused devDeps: @oclif/core, tsx - Add debug as devDep (used in rollup.config.ts alias) - Remove unused InitFlagName type export - Add knip ignore for @sanity/cli (imported via relative source paths) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace dynamic import of ImportDatasetCommand with spawning the project's own sanity binary via execa. The dynamic import pulled the entire oclif command tree into the create-sanity bundle because Rollup inlines all dynamic imports. The scaffolded project always has sanity as a dependency, so spawning its binary for dataset import works in both standalone and oclif contexts. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The function is 4 lines - no need for a separate package. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace custom detectPackageManager with the shared getRunningPackageManager from @sanity/cli-core/package-manager. Adds bun support for help text (`bun create sanity@latest`). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
create-sanity now handles --help itself via parseArgs, so it never delegates to `sanity init --help`. The --from-create flag, the SanityHelp.replaceInitWithCreateCommand rewriting, and the fromCreate option in InitOptions are all unused. Remove them. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
npm requires `--` to forward flags to the create script (e.g. `npm create sanity@latest -- --template moviedb`). Other package managers don't need it. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move flagsToInitOptions, InitCommandFlags, InitCommandArgs, and the narrowing helpers out of types.ts into flagsToInitOptions.ts. types.ts now only contains type definitions. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add fs.access check before spawning the sanity binary for dataset import. Gives a clear error message instead of a raw ENOENT if dependencies weren't installed correctly. Also fix misleading vitest config comment. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Use execa preferLocal instead of manual .bin path (Windows compat) - Fix exit:0 being silently discarded in CLIError (0 || undefined bug) - Remove duplicate --env validation from InitCommand (flagsToInitOptions is the canonical location, shared with create-sanity) - Remove unused overrides parameter from toOclifFlags Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… constraints parseArgs doesn't support oclif features like aliases, option validation, or exclusive constraints. Add post-parse handling: - Register flag aliases (e.g. --project-id) as separate parseArgs options, then resolve them back to canonical names - Validate string flags with `options` against allowed values (--package-manager, --visibility) - Check exclusive constraints and error if conflicting flags are passed Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move all parseArgs logic (option building, alias resolution, negation merging, option/exclusive validation, help printing) out of index.ts into a dedicated parseArgs.ts module. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace ImportDatasetCommand mock with execa mock - Update assertion to match new call signature (binary name, args, options) - Fix env validation exit code expectation (now InitError exit:1, not oclif exit:2) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Establish consistent exit code semantics: - 1: init action runtime failure (auth, missing deps, etc) - 2: flag parsing/validation error (unknown flag, invalid option value, exclusive constraint violation) - 3: domain-specific flag validation (e.g. --env must start with .env) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add pretest script so `pnpm test` builds the bundle before running - Wrap execa call in initStudio with try/catch so dataset import failures produce a clean InitError instead of dumping ExecaError - Add explicit default:false to bare, dataset-default, no-git flags so parseArgs always populates them, matching InitCommandFlags types Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Use helpLabel when defined (e.g. --[no-]git) - Show --[no-] prefix for allowNo boolean flags - Wrap long descriptions to terminal width - Show --help in the options list - Error when both a flag and its alias are passed (--project + --project-id) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Claude finished @rexxars's task in 5m 31s —— View job Code Review
Issues Found1. Exclusive constraint check fires on defaulted flags —
Concrete breakage: The existing tests don't catch this because they only assert 2. Dead code in const pm = getRunningPackageManager() ?? 'npm'
const sep = options?.withFlagSeparator && (pm === 'npm' || !pm) ? ' --' : ''
3. The 4.
5. Missing test for The test suite doesn't cover the happy path of |
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
Coverage Delta
Comparing 30 changed files against main @ Overall Coverage
|
Description
Note
This builds on top of #748 and #753, which are included in this branch.
This is the culmination of the
initrefactor series. The goal: shipcreate-sanityas a standalone, dependency-free bundled package so thatnpm create sanityis fast and lightweight, whilesanity initcontinues to work as before.What this does:
initAction) that takes a simple options objectnode:util parseArgsfor the standalone entry point - zero framework dependency@sanity/cli-coresource directly for better dead code eliminationCLIErrorandwarn()utilities to@sanity/cli-coreto replace oclif UX imports in the init code pathImportDatasetCommand(now uses execa to call the local sanity binary)Key changes by area:
@sanity/cli-core: NewCLIError/CLIWarningerror classes, reorganized exports, inlinedindent-stringdependency@sanity/cliinit action: Extracted from the 1700-lineinit.tscommand intoactions/init/with separate files for each flow (studio, nextjs, app, scaffolding, helpers)@sanity/cliinit command: Now a thin oclif wrapper that converts flags and delegates toinitAction()create-sanity: New standalone entry point (src/index.ts), Rollup bundling config, proper arg parsing with help output, testsflags.tsdefines flags as POJOs,flagAdapter.tsconverts them to oclif format,flagsToInitOptions.tsconverts parsed values toInitOptionsWhat to review
packages/create-sanity/rollup.config.ts)packages/create-sanity/src/index.ts,src/parseArgs.ts)packages/@sanity/cli/src/actions/init/flags.ts,src/util/flagAdapter.ts)initActionextraction and flow separation (packages/@sanity/cli/src/actions/init/)Notes
DEP-REPORT.mdanalysis has been prepared with a roadmap to get this under 1 MB.sanity initcommand continues to work exactly as before - this is purely additivenode:util parseArgsTest plan
pnpm testpassespnpm check:typespassespnpm check:lintpassespnpm build:clisucceedsnode packages/create-sanity/dist/index.js --helpshows correct help outputsanity initstill works end-to-endnpm create sanityworks end-to-end with the bundled package🤖 Generated with Claude Code