Skip to content

refactor(cli): extract init command into framework-agnostic initAction#999

Merged
mttdnt merged 8 commits intomainfrom
refactor/move-init-to-action
Apr 24, 2026
Merged

refactor(cli): extract init command into framework-agnostic initAction#999
mttdnt merged 8 commits intomainfrom
refactor/move-init-to-action

Conversation

@mttdnt
Copy link
Copy Markdown
Contributor

@mttdnt mttdnt commented Apr 22, 2026

Description

Extracts ~1100 lines of logic from the oclif InitCommand (commands/init.ts) into a framework-agnostic actions/init/initAction.ts. This is the structural refactor from PR #929 / #845, using main's current logic (no regressions).

Key changes:

  • commands/init.ts is now a thin oclif wrapper: static declarations + run() that maps flags → InitOptions, calls initAction(), and catches InitError
  • New InitOptions / InitContext types in types.ts with flagsToInitOptions() converter
  • New InitError class replaces oclif's this.error() for non-zero exits
  • Flow files (initApp, initStudio, initNextJs, scaffoldTemplate) accept options: InitOptions instead of individual flag params
  • Flow files throw InitError directly instead of receiving an error callback
  • bootstrapTemplate.ts unchanged (only receives computed values)

What this enables:

  • Init logic can be called without oclif (e.g. from create-sanity, programmatic use)
  • Cleaner separation between CLI framework concerns and business logic

What to review

  • Verify the extraction is purely mechanical — no logic, control flow, or behavior changes
  • initAction.ts is the main new file (~1166 lines) containing all extracted functions
  • types.ts has the new InitOptions, InitContext, and flagsToInitOptions
  • Each flow file's signature change: individual flag params → options: InitOptions destructuring
  • errorFn adapter removed from initAction.ts since flow files now throw InitError directly

Testing

All 14 existing init test files pass with zero assertion changes, confirming behavior is identical:

  • init.authentication.test.ts
  • init.bootstrap-app.test.ts
  • init.create-new-project.test.ts
  • init.get-project-details.test.ts
  • init.nextjs.test.ts
  • init.plan.test.ts
  • init.setup.test.ts
  • init.staging-env.test.ts
  • Plus 6 unit test files for bootstrap/template/etc.

Typecheck, lint, and build all pass cleanly.


Note

Medium Risk
Large refactor of sanity init control flow and error handling (moving from oclif this.error() to thrown InitError), which could subtly change CLI exit/early-return behavior despite intent to be mechanical.

Overview
Refactors sanity init by extracting the ~1k lines of init orchestration out of commands/init.ts into a new framework-agnostic initAction() with a typed InitOptions/InitContext interface and a flagsToInitOptions() converter.

Reworks init subflows (initStudio, initApp, initNextJs, scaffoldTemplate, plan/project/dataset helpers) to accept a single options object and to throw InitError for controlled failures; InitCommand is now a thin wrapper that resolves mcpMode, calls initAction, and translates InitError to an oclif exit code.

Adds targeted unit tests for flagsToInitOptions, InitError, and direct initAction behavior, and updates existing init command tests to align with the new error/exit semantics (including optional visibility in init telemetry).

Reviewed by Cursor Bugbot for commit abac9ba. Bugbot is set up for automated code reviews on this repo. Configure here.

@claude
Copy link
Copy Markdown

claude Bot commented Apr 22, 2026

Claude finished @mttdnt's task in 3m 20s —— View job


Review

  • Gather context and read changed files
  • Check for changeset
  • Review key files for bugs and issues
  • Post findings

Changeset: No changeset — correctly absent for a pure refactor with no public API change.


1. organizations: [] hardcoded in promptForProjectCreation call

packages/@sanity/cli/src/actions/init/project/promptForAppTemplateSetup.ts lines 102–109:

await promptForProjectCreation({
  coupon,
  isUsersFirstProject: projects.length === 0,
  organizationId,
  organizations: [],   // ← always empty
  planId,
  user,
})

promptForProjectCreation forwards organizations to promptUserForOrganization when organizationId is falsy:

const org = organizationId || (await promptUserForOrganization({organizations, user}))

promptUserForOrganization then sees organizations.length === 0 and calls promptUserForNewOrganization — forcing the user to create a new org rather than choose from existing ones.

organizationId here is typed string | undefined. The caller getProjectDetails sets it via promptUserForOrganization, which has a return chosenOrg || undefined code path that can legitimately return undefined. If that happens, this produces the wrong behaviour silently.

Fix: either assert non-nullability at the callsite, or fetch and pass the real organizations list (the same list already fetched in getProjectDetails). Fix this →


2. promptForProjectCreation.ts test coverage at 44.4%

The coverage report shows promptForProjectCreation.ts at 44.4% (new file). The uncovered paths include the promptUserForOrganization fallback in the new-project creation flow. Given this is on the critical sanity init path, consider adding tests for the case where organizationId is undefined and the function falls through to the org prompt.


Note: The datasetDefault regression flagged in the previous Cursor Bugbot review has already been addressed in commit abac9badefaultConfig: datasetDefault || undefined is correctly passed in both the unattended and interactive paths of promptForAppTemplateSetup.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 22, 2026

📦 Bundle Stats — @sanity/cli

Compared against main (26f0fb57)

@sanity/cli

Metric Value vs main (26f0fb5)
Internal (raw) 2.1 KB -
Internal (gzip) 799 B -
Bundled (raw) 10.94 MB -
Bundled (gzip) 2.05 MB -
Import time 746ms +1ms, +0.1%

bin:sanity

Metric Value vs main (26f0fb5)
Internal (raw) 975 B -
Internal (gzip) 460 B -
Bundled (raw) 9.84 MB -
Bundled (gzip) 1.77 MB -
Import time 1.80s +16ms, +0.9%

🗺️ View treemap · Artifacts

Details
  • Import time regressions over 10% are flagged with ⚠️
  • Sizes shown as raw / gzip 🗜️. Internal bytes = own code only. Total bytes = with all dependencies. Import time = Node.js cold-start median.

📦 Bundle Stats — @sanity/cli-core

Compared against main (26f0fb57)

Metric Value vs main (26f0fb5)
Internal (raw) 93.1 KB -
Internal (gzip) 21.9 KB -
Bundled (raw) 21.62 MB -
Bundled (gzip) 3.42 MB -
Import time 703ms -1ms, -0.1%

🗺️ View treemap · Artifacts

Details
  • Import time regressions over 10% are flagged with ⚠️
  • Sizes shown as raw / gzip 🗜️. Internal bytes = own code only. Total bytes = with all dependencies. Import time = Node.js cold-start median.

📦 Bundle Stats — create-sanity

Compared against main (26f0fb57)

Metric Value vs main (26f0fb5)
Internal (raw) 976 B -
Internal (gzip) 507 B -
Bundled (raw) 50.7 KB -
Bundled (gzip) 12.6 KB -
Import time ❌ ChildProcess denied: node -
Details
  • Import time regressions over 10% are flagged with ⚠️
  • Sizes shown as raw / gzip 🗜️. Internal bytes = own code only. Total bytes = with all dependencies. Import time = Node.js cold-start median.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 22, 2026

Coverage Delta

File Statements
packages/@sanity/cli/src/actions/init/bootstrapTemplate.ts 0.0% (±0%)
packages/@sanity/cli/src/actions/init/initAction.ts 97.1% (new)
packages/@sanity/cli/src/actions/init/initApp.ts 96.0% (±0%)
packages/@sanity/cli/src/actions/init/initError.ts 100.0% (new)
packages/@sanity/cli/src/actions/init/initHelpers.ts 100.0% (±0%)
packages/@sanity/cli/src/actions/init/initNextJs.ts 88.8% (- 1.0%)
packages/@sanity/cli/src/actions/init/initStudio.ts 87.0% (+ 0.6%)
packages/@sanity/cli/src/actions/init/plan/getPlan.ts 100.0% (new)
packages/@sanity/cli/src/actions/init/plan/verifyCoupon.ts 100.0% (new)
packages/@sanity/cli/src/actions/init/plan/verifyPlan.ts 100.0% (new)
packages/@sanity/cli/src/actions/init/project/createProjectFromName.ts 100.0% (new)
packages/@sanity/cli/src/actions/init/project/getOrCreateDataset.ts 97.7% (new)
packages/@sanity/cli/src/actions/init/project/getOrCreateProject.ts 95.3% (new)
packages/@sanity/cli/src/actions/init/project/getProjectDetails.ts 89.5% (new)
packages/@sanity/cli/src/actions/init/project/getProjectOutputPath.ts 60.0% (new)
packages/@sanity/cli/src/actions/init/project/promptForAppTemplateSetup.ts 95.2% (new)
packages/@sanity/cli/src/actions/init/project/promptForProjectCreation.ts 44.4% (new)
packages/@sanity/cli/src/actions/init/project/promptUserForNewOrganization.ts 100.0% (new)
packages/@sanity/cli/src/actions/init/project/promptUserForOrganization.ts 100.0% (new)
packages/@sanity/cli/src/actions/init/scaffoldTemplate.ts 100.0% (+ 10.7%)
packages/@sanity/cli/src/actions/init/types.ts 100.0% (new)
packages/@sanity/cli/src/commands/init.ts 100.0% (+ 4.9%)
packages/@sanity/cli/src/telemetry/init.telemetry.ts 100.0% (±0%)

Comparing 23 changed files against main @ 26f0fb5774c142df2722ec3b4cd299e7419abf46

Overall Coverage

Metric Coverage
Statements 84.1% (+ 0.1%)
Branches 74.0% (+ 0.1%)
Functions 84.0% (+ 0.0%)
Lines 84.5% (+ 0.1%)

@mttdnt mttdnt marked this pull request as ready for review April 23, 2026 14:28
@mttdnt mttdnt requested a review from a team as a code owner April 23, 2026 14:28
@mttdnt mttdnt requested review from binoy14 and cngonzalez and removed request for a team April 23, 2026 14:28
Copy link
Copy Markdown
Contributor

@binoy14 binoy14 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good overall, smaller comments

}
})

describe('InitCommand.run() mcpMode computation', () => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this naming style is weird for the describe block

})

test('translates InitError to oclif error', async () => {
const {InitError} = await import('../../../actions/init/initError.js')
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can this just be a static import?

packageName,
templateName,
useTypeScript,
useTypeScript: useTypeScript ?? false,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 if useTypescript is boolean is the conditional needed?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For better readability does it make sense to split this files by functions aka move some functions out of here so it's not 1k lines

mttdnt and others added 5 commits April 23, 2026 14:17
…Action

Moves ~1100 lines of logic out of the oclif InitCommand into
actions/init/initAction.ts, leaving init.ts as a thin wrapper that
maps oclif flags → InitOptions and catches InitError.

Flow files (initApp, initStudio, initNextJs, scaffoldTemplate) now
accept `options: InitOptions` instead of individual flag params,
and throw InitError directly instead of receiving an `error` callback.

Zero test assertion changes — all 14 init test files pass as-is.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Make `visibility` optional in `CreateOrSelectDatasetStep` (can be
  undefined in unattended mode)
- Remove dead `ConfigureAppProjectStep` interface (no trace.log call
  exists for it)
- Remove unnecessary `as 'private' | 'public'` cast now that the
  type accepts undefined

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…d tests

- Restore configureAppProject trace calls dropped during extraction
  (thread `trace` param into promptForAppTemplateSetup)
- Replace `throw new InitError('', 0)` with plain `return` on --env path
  (it's a normal success path, not an error)
- Remove exitCode===0 special-case from command wrapper
- Add ConfigureAppProjectStep to telemetry union type
- Port 4 new test files from #845: flagsToInitOptions, initAction,
  initError, init.command
- Update 2 existing tests: --env path no longer throws

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- bootstrapTemplate: make overwriteFiles/useTypeScript optional
- initHelpers: use InitContext['output'] instead of Output
- initNextJs: throw InitError instead of output.error(), pass options directly
- initStudio: dynamic import for ImportDatasetCommand, use workDir over process.cwd()
- initApp: use workDir over process.cwd()
- scaffoldTemplate: remove as boolean casts and unnecessary try/catch

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… tighten useTypeScript type

- Rename describe blocks to simpler names (mcpMode resolution, error handling)
- Use static import for InitError instead of dynamic import
- Make useTypeScript a required boolean since flagOrDefault always returns boolean

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@mttdnt mttdnt force-pushed the refactor/move-init-to-action branch from 6ee3bb0 to 6ffc884 Compare April 23, 2026 18:23
Comment thread packages/@sanity/cli/src/actions/init/initAction.ts Outdated
mttdnt and others added 2 commits April 23, 2026 14:37
Tests from #1004 used the old flat-argument signature; wrap in options
object to match the current selectTemplate interface.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract helper functions from the 1175-line initAction.ts into
one-function-per-file modules under plan/ and project/ subdirectories.
initAction.ts now contains only the main orchestrator, flag validation,
and auth — down to ~300 lines.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 401d4a8. Configure here.

The refactor from class methods to standalone functions dropped
the implicit this.flags['dataset-default'] read that getOrCreateDataset
relied on. Thread datasetDefault through getProjectDetails →
promptForAppTemplateSetup → getOrCreateDataset so --dataset-default
applies to app templates again.

Adds a regression test exercising the app template + --dataset-default
code path.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@mttdnt mttdnt requested a review from binoy14 April 23, 2026 20:19
@mttdnt mttdnt merged commit bc0f1d3 into main Apr 24, 2026
52 checks passed
@mttdnt mttdnt deleted the refactor/move-init-to-action branch April 24, 2026 00:38
gu-stav added a commit that referenced this pull request Apr 24, 2026
Resolves conflicts from the init refactor on main (#999) by integrating
feat/workbench's federation flag and prompt flow into the new initAction
pipeline and its flagsToInitOptions helper.

Conflicted files:
- packages/@sanity/cli/src/commands/init.ts
- packages/@sanity/cli/src/actions/init/{initApp,initStudio,scaffoldTemplate}.ts
- packages/@sanity/cli/src/actions/dev/startStudioDevServer.ts
- pnpm-lock.yaml

Also applied federation changes to newly-added files from main that
weren't seen by the 3-way merge:
- packages/@sanity/cli/src/actions/init/initAction.ts
- packages/@sanity/cli/src/actions/init/types.ts

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
gu-stav added a commit that referenced this pull request Apr 24, 2026
* fix(cli): replace preferred-pm with local implementation (#984)

* fix(cli): replace preferred-pm with local implementation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): address review feedback for preferredPm

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): detect pnpm-workspace.yaml in parent directory walk-up

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): normalize path separators for workspace glob matching on windows

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): continue workspace walk-up when inner workspace globs don't match

When a nested package.json has a workspaces field whose globs don't
match the target path, continue traversing parent directories instead
of returning null. Also simplify error handling in detectFromNodeModules
to swallow all read errors for best-effort detection.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): remove continue that caused infinite loop in workspace walk-up

The continue statement skipped dir = path.dirname(dir) at the bottom
of the while loop, causing an infinite loop when a workspace's globs
didn't match the target path. Removing it lets the code fall through
to the directory advancement naturally.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): skip chmod-based permission test on Windows

chmod doesn't enforce read permissions on Windows, so the file remains
readable and the test returns 'pnpm' instead of falling through to 'npm'.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): remove circular import and add malformed package.json test

Address PR review feedback: inline DetectablePackageManager type to
break circular dependency between preferredPm and packageManagerChoice,
and add test covering malformed package.json handling in workspace
walk-up.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* ci: split e2e workflow into PR and scheduled runs (#995)

Move registry-mode e2e tests and Slack failure notifications into a
dedicated hourly scheduled workflow. The PR/push workflow now only runs
in pack mode. Post-release dispatch in release.yml updated to target
the new scheduled workflow with `latest` instead of a specific version.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor(cli): replace default namespace imports with named imports (#993)

Use named imports for semver, nock, and typescript to resolve 167
import-x/no-named-as-default-member lint warnings. Also replace one
`as any` with a proper type cast.

CJS modules (json5, dotenv, tar-fs, tar-stream) are left unchanged
since they don't support named ESM imports at runtime.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): default to TypeScript in unattended mode for sanity init (#1004)

* fix(cli): default to TypeScript in unattended mode for sanity init

When running sanity init in unattended mode (non-interactive terminal or
--yes flag), the CLI now defaults to TypeScript when --typescript or
--no-typescript is not explicitly provided, matching the interactive
prompt default.

Uses the existing flagOrDefault/shouldPrompt helpers already used by
initNextJs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: update auto-generated changeset for PR #1004

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com>

* refactor(cli): extract init command into framework-agnostic initAction (#999)

* refactor(cli): extract init command body into framework-agnostic initAction

Moves ~1100 lines of logic out of the oclif InitCommand into
actions/init/initAction.ts, leaving init.ts as a thin wrapper that
maps oclif flags → InitOptions and catches InitError.

Flow files (initApp, initStudio, initNextJs, scaffoldTemplate) now
accept `options: InitOptions` instead of individual flag params,
and throw InitError directly instead of receiving an `error` callback.

Zero test assertion changes — all 14 init test files pass as-is.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor(cli): clean up init telemetry types

- Make `visibility` optional in `CreateOrSelectDatasetStep` (can be
  undefined in unattended mode)
- Remove dead `ConfigureAppProjectStep` interface (no trace.log call
  exists for it)
- Remove unnecessary `as 'private' | 'public'` cast now that the
  type accepts undefined

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: address PR review feedback — restore telemetry, fix env path, add tests

- Restore configureAppProject trace calls dropped during extraction
  (thread `trace` param into promptForAppTemplateSetup)
- Replace `throw new InitError('', 0)` with plain `return` on --env path
  (it's a normal success path, not an error)
- Remove exitCode===0 special-case from command wrapper
- Add ConfigureAppProjectStep to telemetry union type
- Port 4 new test files from #845: flagsToInitOptions, initAction,
  initError, init.command
- Update 2 existing tests: --env path no longer throws

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor(cli): close remaining oclif decoupling gaps in init flow files

- bootstrapTemplate: make overwriteFiles/useTypeScript optional
- initHelpers: use InitContext['output'] instead of Output
- initNextJs: throw InitError instead of output.error(), pass options directly
- initStudio: dynamic import for ImportDatasetCommand, use workDir over process.cwd()
- initApp: use workDir over process.cwd()
- scaffoldTemplate: remove as boolean casts and unnecessary try/catch

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: address PR review feedback — clean up test names, static import, tighten useTypeScript type

- Rename describe blocks to simpler names (mcpMode resolution, error handling)
- Use static import for InitError instead of dynamic import
- Make useTypeScript a required boolean since flagOrDefault always returns boolean

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: update selectTemplate tests for refactored options signature

Tests from #1004 used the old flat-argument signature; wrap in options
object to match the current selectTemplate interface.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor(cli): split initAction.ts into plan/ and project/ modules

Extract helper functions from the 1175-line initAction.ts into
one-function-per-file modules under plan/ and project/ subdirectories.
initAction.ts now contains only the main orchestrator, flag validation,
and auth — down to ~300 lines.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: forward datasetDefault to app template dataset creation

The refactor from class methods to standalone functions dropped
the implicit this.flags['dataset-default'] read that getOrCreateDataset
relied on. Thread datasetDefault through getProjectDetails →
promptForAppTemplateSetup → getOrCreateDataset so --dataset-default
applies to app templates again.

Adds a regression test exercising the app template + --dataset-default
code path.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Binoy Patel <me@binoy.io>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com>
Co-authored-by: Matthew Dent <mttdnt@gmail.com>
gu-stav added a commit that referenced this pull request Apr 24, 2026
* fix(cli): replace preferred-pm with local implementation (#984)

* fix(cli): replace preferred-pm with local implementation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): address review feedback for preferredPm

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): detect pnpm-workspace.yaml in parent directory walk-up

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): normalize path separators for workspace glob matching on windows

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): continue workspace walk-up when inner workspace globs don't match

When a nested package.json has a workspaces field whose globs don't
match the target path, continue traversing parent directories instead
of returning null. Also simplify error handling in detectFromNodeModules
to swallow all read errors for best-effort detection.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): remove continue that caused infinite loop in workspace walk-up

The continue statement skipped dir = path.dirname(dir) at the bottom
of the while loop, causing an infinite loop when a workspace's globs
didn't match the target path. Removing it lets the code fall through
to the directory advancement naturally.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): skip chmod-based permission test on Windows

chmod doesn't enforce read permissions on Windows, so the file remains
readable and the test returns 'pnpm' instead of falling through to 'npm'.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): remove circular import and add malformed package.json test

Address PR review feedback: inline DetectablePackageManager type to
break circular dependency between preferredPm and packageManagerChoice,
and add test covering malformed package.json handling in workspace
walk-up.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* ci: split e2e workflow into PR and scheduled runs (#995)

Move registry-mode e2e tests and Slack failure notifications into a
dedicated hourly scheduled workflow. The PR/push workflow now only runs
in pack mode. Post-release dispatch in release.yml updated to target
the new scheduled workflow with `latest` instead of a specific version.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor(cli): replace default namespace imports with named imports (#993)

Use named imports for semver, nock, and typescript to resolve 167
import-x/no-named-as-default-member lint warnings. Also replace one
`as any` with a proper type cast.

CJS modules (json5, dotenv, tar-fs, tar-stream) are left unchanged
since they don't support named ESM imports at runtime.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): default to TypeScript in unattended mode for sanity init (#1004)

* fix(cli): default to TypeScript in unattended mode for sanity init

When running sanity init in unattended mode (non-interactive terminal or
--yes flag), the CLI now defaults to TypeScript when --typescript or
--no-typescript is not explicitly provided, matching the interactive
prompt default.

Uses the existing flagOrDefault/shouldPrompt helpers already used by
initNextJs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: update auto-generated changeset for PR #1004

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com>

* refactor(cli): extract init command into framework-agnostic initAction (#999)

* refactor(cli): extract init command body into framework-agnostic initAction

Moves ~1100 lines of logic out of the oclif InitCommand into
actions/init/initAction.ts, leaving init.ts as a thin wrapper that
maps oclif flags → InitOptions and catches InitError.

Flow files (initApp, initStudio, initNextJs, scaffoldTemplate) now
accept `options: InitOptions` instead of individual flag params,
and throw InitError directly instead of receiving an `error` callback.

Zero test assertion changes — all 14 init test files pass as-is.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor(cli): clean up init telemetry types

- Make `visibility` optional in `CreateOrSelectDatasetStep` (can be
  undefined in unattended mode)
- Remove dead `ConfigureAppProjectStep` interface (no trace.log call
  exists for it)
- Remove unnecessary `as 'private' | 'public'` cast now that the
  type accepts undefined

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: address PR review feedback — restore telemetry, fix env path, add tests

- Restore configureAppProject trace calls dropped during extraction
  (thread `trace` param into promptForAppTemplateSetup)
- Replace `throw new InitError('', 0)` with plain `return` on --env path
  (it's a normal success path, not an error)
- Remove exitCode===0 special-case from command wrapper
- Add ConfigureAppProjectStep to telemetry union type
- Port 4 new test files from #845: flagsToInitOptions, initAction,
  initError, init.command
- Update 2 existing tests: --env path no longer throws

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor(cli): close remaining oclif decoupling gaps in init flow files

- bootstrapTemplate: make overwriteFiles/useTypeScript optional
- initHelpers: use InitContext['output'] instead of Output
- initNextJs: throw InitError instead of output.error(), pass options directly
- initStudio: dynamic import for ImportDatasetCommand, use workDir over process.cwd()
- initApp: use workDir over process.cwd()
- scaffoldTemplate: remove as boolean casts and unnecessary try/catch

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: address PR review feedback — clean up test names, static import, tighten useTypeScript type

- Rename describe blocks to simpler names (mcpMode resolution, error handling)
- Use static import for InitError instead of dynamic import
- Make useTypeScript a required boolean since flagOrDefault always returns boolean

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: update selectTemplate tests for refactored options signature

Tests from #1004 used the old flat-argument signature; wrap in options
object to match the current selectTemplate interface.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor(cli): split initAction.ts into plan/ and project/ modules

Extract helper functions from the 1175-line initAction.ts into
one-function-per-file modules under plan/ and project/ subdirectories.
initAction.ts now contains only the main orchestrator, flag validation,
and auth — down to ~300 lines.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: forward datasetDefault to app template dataset creation

The refactor from class methods to standalone functions dropped
the implicit this.flags['dataset-default'] read that getOrCreateDataset
relied on. Thread datasetDefault through getProjectDetails →
promptForAppTemplateSetup → getOrCreateDataset so --dataset-default
applies to app templates again.

Adds a regression test exercising the app template + --dataset-default
code path.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Binoy Patel <me@binoy.io>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com>
Co-authored-by: Matthew Dent <mttdnt@gmail.com>
gu-stav added a commit that referenced this pull request May 5, 2026
Squashed merge of workbench commits up through 8535ccd (PR #1014) onto
current main (737ab0b). Resolves conflicts between main's init refactor
(#999), TypeScript default (#1004), preferred-pm replacement (#984),
named-import refactor (#993), e2e workflow split (#995), post-release
trigger removal (#1021), Slack action SHA bump (#1023), CSS bundle
loader (#893), and init flag fix (#1015) on the main side, against the
federation prompt, workbench dev server, and federation vite plugin
work on the workbench side.

This is the third-branch resolution; feat/workbench is untouched.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants