Skip to content

refactor(init): move init logic to action pattern#845

Closed
binoy14 wants to merge 3 commits intomainfrom
bundled-create
Closed

refactor(init): move init logic to action pattern#845
binoy14 wants to merge 3 commits intomainfrom
bundled-create

Conversation

@binoy14
Copy link
Copy Markdown
Contributor

@binoy14 binoy14 commented Mar 30, 2026

refactor(init): move init logic to action pattern (#748)

refactor(init): split init flows into separate functions (#753)

@claude
Copy link
Copy Markdown

claude Bot commented Mar 30, 2026

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


PR Review

  • Read CLAUDE.md for repo guidelines
  • Review changed files
  • Check for changeset
  • Post findings

Changeset

This PR is tagged as a refactor, but the latest commit (d82d20e) restores unattended mode behavior — a behavioral bug fix. Since this affects runtime behavior in packages/, a patch changeset is required but missing. Please add one describing the fix.


Issues

1. getOrCreateDataset skips dataset existence check in unattended mode
initAction.ts:497-498

if (dataset && opts.unattended) {
  return {datasetName: dataset, userAction: 'none'}
}

In unattended mode with --dataset, the function short-circuits before the existence check at lines 506–521. In interactive mode, if the specified dataset doesn't exist, it's automatically created. In unattended mode, it's silently trusted to exist — if it doesn't, downstream studio config will reference a non-existent dataset with no helpful error. Either replicate the check in unattended mode, or document this expectation explicitly.

Fix this →


2. Inconsistency in getOrCreateProject for unattended + projectId
initAction.ts:634 vs 646 vs 650-664

Three code paths for unattended + projectId behave inconsistently:

  • API fails → returns gracefully with displayName: 'Unknown project' (line 634)
  • API succeeds, 0 projects → throws "No projects found for current user" (line 646)
  • API succeeds, project not in list → returns gracefully with 'Unknown project' (line 660)

The middle case throws even when a specific projectId was provided. In CI environments where the caller knows the project ID, this produces a confusing error. The check at line 646 should be guarded with !projectId:

if (projects.length === 0 && unattended && !projectId) {
  throw new InitError('No projects found for current user', 1)
}

3. Missing test for the restored unattended behavior
initAction.test.ts

The commit d82d20e fixes unattended mode behavior specifically around project/dataset selection, but initAction.test.ts only tests auth-related unattended cases (throws InitError when not authenticated in unattended mode). The restored behavior for valid unattended project selection (the case actually fixed) has no test, making it easy to regress again.


Copy link
Copy Markdown
Contributor Author

binoy14 commented Mar 30, 2026

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 30, 2026

📦 Bundle Stats — @sanity/cli

Compared against main (e9022171) · v6.2.1 (npm)

@sanity/cli

Metric Value vs main (e902217) vs v6.2.1
Internal (raw) 2.1 KB - -
Internal (gzip) 799 B - -
Bundled (raw) 11.06 MB - +9.12 MB, +470.6%
Bundled (gzip) 2.07 MB - +1.60 MB, +335.8%
Import time 844ms +0ms, +0.0% +27ms, +3.3%

bin:sanity

Metric Value vs main (e902217) vs v6.2.1
Internal (raw) 975 B - -
Internal (gzip) 460 B - -
Bundled (raw) 9.83 MB - +9.12 MB, +1286.7%
Bundled (gzip) 1.77 MB - +1.60 MB, +940.0%
Import time NaNs - NaNs, NaN%

🗺️ 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 (e9022171) · v1.2.1 (npm)

Metric Value vs main (e902217) vs v1.2.1
Internal (raw) 92.2 KB - +3.9 KB, +4.4%
Internal (gzip) 21.6 KB - +1.1 KB, +5.5%
Bundled (raw) 21.64 MB - +9.08 MB, +72.3%
Bundled (gzip) 3.43 MB - +1.58 MB, +85.9%
Import time 790ms +3ms, +0.4% +39ms, +5.2%

🗺️ 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.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 30, 2026

Coverage Delta

File Statements
packages/@sanity/cli/src/actions/init/bootstrapTemplate.ts 0.0% (±0%)
packages/@sanity/cli/src/actions/init/initAction.ts 94.9% (new)
packages/@sanity/cli/src/actions/init/initApp.ts 96.0% (+ 0.5%)
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 86.7% (- 3.1%)
packages/@sanity/cli/src/actions/init/initStudio.ts 87.0% (+ 0.6%)
packages/@sanity/cli/src/actions/init/scaffoldTemplate.ts 88.0% (+ 9.4%)
packages/@sanity/cli/src/actions/init/types.ts 100.0% (new)
packages/@sanity/cli/src/commands/init.ts 100.0% (+ 4.6%)
packages/@sanity/cli/src/telemetry/init.telemetry.ts 100.0% (±0%)

Comparing 11 changed files against main @ 9f2025641ca8399ebd4c0f8913bd7a8907b3e9b9

Overall Coverage

Metric Coverage
Statements 83.0% (+ 0.0%)
Branches 73.0% (+ 0.0%)
Functions 82.9% (+ 0.0%)
Lines 83.5% (+ 0.0%)

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 1, 2026

📦 Bundle Stats — @sanity/cli

Compared against main (9a7e2044)

@sanity/cli

Metric Value vs main (9a7e204)
Internal (raw) 2.1 KB -
Internal (gzip) 799 B -
Bundled (raw) 10.94 MB -
Bundled (gzip) 2.05 MB -
Import time 837ms +5ms, +0.5%

bin:sanity

Metric Value vs main (9a7e204)
Internal (raw) 975 B -
Internal (gzip) 460 B -
Bundled (raw) 9.84 MB -
Bundled (gzip) 1.77 MB -
Import time 2.01s +20ms, +1.0%

🗺️ 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 (9a7e2044)

Metric Value vs main (9a7e204)
Internal (raw) 93.1 KB -
Internal (gzip) 21.9 KB -
Bundled (raw) 21.62 MB -
Bundled (gzip) 3.42 MB -
Import time 811ms +17ms, +2.2%

🗺️ 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 (9a7e2044)

Metric Value vs main (9a7e204)
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.

@binoy14 binoy14 changed the title refactor(init): move init logic to action pattern (#748) refactor(init): move init logic to action pattern Apr 1, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 1, 2026

Coverage Delta

File Statements
packages/@sanity/cli/src/actions/init/bootstrapTemplate.ts 0.0% (±0%)
packages/@sanity/cli/src/actions/init/initAction.ts 94.8% (new)
packages/@sanity/cli/src/actions/init/initApp.ts 96.0% (new)
packages/@sanity/cli/src/actions/init/initError.ts 100.0% (new)
packages/@sanity/cli/src/actions/init/initHelpers.ts 100.0% (new)
packages/@sanity/cli/src/actions/init/initNextJs.ts 86.7% (new)
packages/@sanity/cli/src/actions/init/initStudio.ts 87.0% (new)
packages/@sanity/cli/src/actions/init/scaffoldTemplate.ts 88.0% (new)
packages/@sanity/cli/src/actions/init/types.ts 100.0% (new)
packages/@sanity/cli/src/commands/init.ts 100.0% (+ 7.4%)
packages/@sanity/cli/src/telemetry/init.telemetry.ts 100.0% (±0%)

Comparing 11 changed files against main @ 7af1594d79003801d6daeadeeb20508d184adb25

Overall Coverage

Metric Coverage
Statements 83.1% (+ 0.0%)
Branches 72.9% (+ 0.0%)
Functions 83.4% (+ 0.1%)
Lines 83.6% (+ 0.0%)

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 1, 2026

Coverage Delta

File Statements
packages/@sanity/cli/src/actions/init/bootstrapTemplate.ts 0.0% (±0%)
packages/@sanity/cli/src/actions/init/initAction.ts 94.8% (new)
packages/@sanity/cli/src/actions/init/initApp.ts 96.0% (new)
packages/@sanity/cli/src/actions/init/initError.ts 100.0% (new)
packages/@sanity/cli/src/actions/init/initHelpers.ts 100.0% (new)
packages/@sanity/cli/src/actions/init/initNextJs.ts 86.7% (new)
packages/@sanity/cli/src/actions/init/initStudio.ts 87.0% (new)
packages/@sanity/cli/src/actions/init/scaffoldTemplate.ts 88.0% (new)
packages/@sanity/cli/src/actions/init/types.ts 100.0% (new)
packages/@sanity/cli/src/commands/init.ts 100.0% (+ 7.4%)
packages/@sanity/cli/src/telemetry/init.telemetry.ts 100.0% (±0%)

Comparing 11 changed files against main @ ef5ed4565d33b83d67cd66c6b3c335516e5b1132

Overall Coverage

Metric Coverage
Statements 83.1% (+ 0.0%)
Branches 72.9% (+ 0.0%)
Functions 83.4% (+ 0.1%)
Lines 83.6% (+ 0.0%)

rexxars and others added 3 commits April 16, 2026 15:32
Behavior present on main but lost when bundled-create was rebased
(commits predate these fixes):

- Pass --missing to dataset import
- Allow --bare mode without --output-path in unattended mode
- Default to "production" dataset in unattended mode without --dataset

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
mttdnt added a commit that referenced this pull request Apr 22, 2026
…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>
mttdnt added a commit that referenced this pull request Apr 23, 2026
…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>
mttdnt added a commit that referenced this pull request Apr 24, 2026
#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>
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>
@binoy14 binoy14 closed this Apr 24, 2026
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.

3 participants