feat(cli): add --introspect option for studio command for bootstrapping without schema - #2775

Merged
jiashengguo merged 10 commits into
devfrom
jiasheng-proxy
Aug 3, 2026
Merged

feat(cli): add --introspect option for studio command for bootstrapping without schema #2775
jiashengguo merged 10 commits into
devfrom
jiasheng-proxy

Conversation

@jiashengguo

@jiashengguojiashengguo commented Jul 29, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • New Features

    • Added an --introspect option to generate a schema from your database when no schema file is available.
  • Enhancements

    • Improved schema resolution flows for --introspect vs missing schema, including smarter DATABASE_URL handling for SQLite (relative file: rewriting).
    • Enhanced database pulls with explicit --provider and --database-url support (including improved SQLite path normalization).
    • Improved automatic driver/provider loading and clearer guidance when required drivers aren’t installed.
  • Bug Fixes

    • Corrected SQLite nullability handling for primary key columns during introspection.
  • Tests

    • Expanded coverage for schema resolution and driver/module loading behaviors.

@jiashengguo
jiashengguo requested a review from CopilotJuly 29, 2026 13:35
@coderabbitai

coderabbitaiBot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The CLI adds project-aware database driver loading and an optional --introspect proxy flow that generates a schema from a database URL. runPull accepts explicit datasource overrides, with tests covering provider detection, schema resolution, SQLite URL rewriting, and package loading.

Changes

CLI introspection flow

Layer / File(s)Summary
Package-aware driver loading
packages/cli/src/actions/action-utils.ts, packages/cli/src/actions/proxy.ts, packages/cli/src/actions/pull/provider/*
Adds package resolution fallbacks and uses them to load SQLite, PostgreSQL, and MySQL drivers, with explicit missing-driver errors.
Pull datasource overrides
packages/cli/src/actions/db.ts
Exports runPull and accepts provider and database URL overrides, including SQLite URL normalization.
Proxy schema introspection
packages/cli/src/actions/proxy.ts, packages/cli/src/index.ts
Adds --introspect, provider detection, driver installation, schema generation, SQLite URL adjustment, and schema resolution branching.
Introspection validation
packages/cli/test/action-utils.test.ts, packages/cli/test/proxy.test.ts
Tests package loading, provider URL mapping, schema-resolution errors, default schema handling, and relative SQLite URLs.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

  • zenstackhq/zenstack#2761: Both changes modify runPull relation and schema synchronization logic in packages/cli/src/actions/db.ts.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title accurately describes the main user-facing change: adding a --introspect option to bootstrap studio without an existing schema.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jiasheng-proxy

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

CopilotAI left a comment

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.

Pull request overview

This PR adds an --introspect option to the CLI’s Studio/proxy command flow to bootstrap a project when no ZModel schema file is present, including auto-installing the correct DB driver and generating a schema via the existing pull/introspection pipeline.

Changes:

  • Adds --introspect flag to the CLI command definition and routes schema resolution through a new resolveSchema helper.
  • Introduces shared optional-dependency helpers (isPackageInstalled, loadPackage) and uses them across DB introspection providers and proxy dialect creation.
  • Extends runPull to accept explicit provider/databaseUrl overrides to support schema generation from an introspected database.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
FileDescription
packages/cli/src/index.tsAdds the --introspect CLI option to the command.
packages/cli/src/actions/proxy.tsImplements --introspect schema resolution, driver installation, schema generation, and generation follow-up.
packages/cli/src/actions/db.tsExports runPull and allows provider/URL overrides for introspection-driven generation.
packages/cli/src/actions/action-utils.tsAdds isPackageInstalled and loadPackage helpers for optional dependency loading.
packages/cli/src/actions/pull/provider/sqlite.tsSwitches SQLite introspection to loadPackage and adds file URL handling.
packages/cli/src/actions/pull/provider/postgresql.tsSwitches PostgreSQL introspection to loadPackage.
packages/cli/src/actions/pull/provider/mysql.tsSwitches MySQL introspection to loadPackage.
packages/cli/test/proxy.test.tsAdds unit tests for getProviderFromUrl and resolveSchema behaviors.
packages/cli/test/action-utils.test.tsAdds tests for isPackageInstalled and loadPackage.
Comments suppressed due to low confidence (1)

packages/cli/test/proxy.test.ts:862

  • This assertion looks for zen studio --introspect, but resolveSchema emits npx @zenstackhq/cli studio --introspect .... Using studio --introspect as the substring match should make the test align with the actual message formatting.
 ).rejects.toThrow('zen studio --introspect');

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment threadpackages/cli/src/actions/pull/provider/postgresql.ts
Comment threadpackages/cli/src/actions/pull/provider/sqlite.ts Outdated
Comment threadpackages/cli/test/proxy.test.ts Outdated
Comment threadpackages/cli/src/actions/proxy.ts Outdated

@coderabbitaicoderabbitaiBot left a comment

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.

Actionable comments posted: 8

🧹 Nitpick comments (1)
packages/cli/src/actions/action-utils.ts (1)

386-415: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract shared createRequire(package.json) logic.

The same createRequire(path.resolve(process.cwd(), 'package.json')) pattern is repeated 3 times across isPackageInstalled and loadPackage. A small shared helper (getProjectRequire()) would reduce duplication and keep the two functions in sync if the resolution base ever changes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/cli/src/actions/action-utils.ts` around lines 386 - 415, Extract the
repeated createRequire(path.resolve(process.cwd(), 'package.json')) construction
into a shared getProjectRequire() helper. Update isPackageInstalled and both
fallback branches in loadPackage to reuse this helper, preserving their existing
resolution and error-handling behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/cli/src/actions/action-utils.ts`:
- Around line 396-415: Update loadPackage so it preserves and propagates the
underlying error when the package cannot be loaded, rather than returning null
after all import and require fallbacks fail. Track the original and fallback
failures through the nested dynamic import, projectRequire.resolve, and
projectRequire calls, then throw a diagnostic error that retains the relevant
cause for callers such as createDialect and the database providers.
In `@packages/cli/src/actions/db.ts`:
- Around line 38-39: Add a warning in the introspection flow when the resulting
tables and enums are both empty, regardless of provider or schema selection.
Update the logic around allSchemas and the PostgreSQL introspect result so the
warning clearly indicates that no database objects were found, while preserving
successful empty-result behavior.
In `@packages/cli/src/actions/proxy.ts`:
- Around line 517-530: Restrict the existing default-schema fallback around
getSchemaFile to cases where options.schema was not explicitly provided. When an
explicit --schema path fails, propagate the original CliError instead of
returning zenstack/schema.zmodel; preserve the fallback for missing schemas in
default locations.
- Around line 619-649: Update introspectAndGenerateSchema so the generated
datasource always references env("DATABASE_URL") instead of embedding
databaseUrl when urlFromEnv is false. Preserve the existing provider and runPull
behavior, and ensure the literal connection string is never written to
schema.zmodel.
- Around line 542-544: Update the runGenerate invocation in the introspection
flow to pass options.output as the code generation output path. Preserve the
existing schema, silent, and watch arguments so generated files and subsequent
imports use the same custom output directory resolved by resolveSchema().
In `@packages/cli/src/actions/pull/provider/sqlite.ts`:
- Around line 144-151: Align SQLite relative file URL resolution between the
introspection path and createDialect. Update the resolution logic surrounding
the SQLite constructor and createDialect’s SQLite branch to use the same base
directory, preserving identical database targeting for the --introspect
bootstrap flow; prefer the existing shared resolution behavior rather than
introducing divergent path handling.
In `@packages/cli/test/action-utils.test.ts`:
- Around line 60-62: Update the successful-load test around loadPackage to
assert that the returned module is not null, replacing the insufficient
toBeDefined assertion. Keep the test focused on rejecting loadPackage’s
documented null failure result.
In `@packages/cli/test/proxy.test.ts`:
- Around line 836-846: Update the expected error substrings in the tests around
resolveSchema to match its actual command text: assert the npx `@zenstackhq/cli`
studio prefix and the -d <databaseUrl> placeholder. Apply the same correction to
both affected assertions while preserving the existing test setup and
error-checking behavior.
---
Nitpick comments:
In `@packages/cli/src/actions/action-utils.ts`:
- Around line 386-415: Extract the repeated
createRequire(path.resolve(process.cwd(), 'package.json')) construction into a
shared getProjectRequire() helper. Update isPackageInstalled and both fallback
branches in loadPackage to reuse this helper, preserving their existing
resolution and error-handling behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 312bca78-7c2c-4751-8fea-9074176dca5b

📥 Commits

Reviewing files that changed from the base of the PR and between 78e741e and bd12232.

📒 Files selected for processing (9)
  • packages/cli/src/actions/action-utils.ts
  • packages/cli/src/actions/db.ts
  • packages/cli/src/actions/proxy.ts
  • packages/cli/src/actions/pull/provider/mysql.ts
  • packages/cli/src/actions/pull/provider/postgresql.ts
  • packages/cli/src/actions/pull/provider/sqlite.ts
  • packages/cli/src/index.ts
  • packages/cli/test/action-utils.test.ts
  • packages/cli/test/proxy.test.ts

Comment threadpackages/cli/src/actions/action-utils.ts
Comment threadpackages/cli/src/actions/db.ts
Comment threadpackages/cli/src/actions/proxy.ts Outdated
Comment threadpackages/cli/src/actions/proxy.ts
Comment threadpackages/cli/src/actions/proxy.ts
Comment threadpackages/cli/src/actions/pull/provider/sqlite.ts Outdated
Comment threadpackages/cli/test/action-utils.test.ts
Comment threadpackages/cli/test/proxy.test.ts Outdated

@coderabbitaicoderabbitaiBot left a comment

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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/cli/src/actions/pull/provider/sqlite.ts (1)

131-143: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

SQLite file:/sqlite: scheme stripping is now split across files and only partially implemented. The root cause: sqlite.ts's introspect() used to normalize file:-prefixed connection strings itself; that logic was removed and only partially reimplemented in db.ts's runPull, covering just the file: prefix and only the explicit --introspect override path.

  • packages/cli/src/actions/pull/provider/sqlite.ts#L131-L143: reinstate scheme stripping (file:/sqlite: → raw path) directly before new SQLite(connectionString, ...) as a defensive last line of normalization, since callers cannot be relied upon to always pre-resolve the URL.
  • packages/cli/src/actions/db.ts#L137-L149: extend the existing databaseUrl.startsWith('file:') branch to also cover sqlite:, and consider applying equivalent normalization in the non-override getDatasource(model) branch too, since the documented ZenStack SQLite format (url = 'file:./dev.db') needs the same treatment there.
  • packages/cli/src/actions/proxy.ts#L607-L631: either confirm sqlite: is a genuinely supported input format and ensure runPull/introspect() honor it end-to-end, or drop the sqlite: branch here if it's dead/speculative handling.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/cli/src/actions/pull/provider/sqlite.ts` around lines 131 - 143,
Normalize SQLite connection schemes consistently: in
packages/cli/src/actions/pull/provider/sqlite.ts lines 131-143, strip file: and
sqlite: immediately before new SQLite in introspect(); in
packages/cli/src/actions/db.ts lines 137-149, extend runPull’s normalization to
sqlite: and apply equivalent handling in the non-override getDatasource(model)
path; in packages/cli/src/actions/proxy.ts lines 607-631, verify sqlite: is
supported end-to-end and retain the branch only if runPull and introspect honor
it, otherwise remove it.
packages/cli/src/actions/proxy.ts (1)

209-230: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Use the schema directory as the SQLite URL base when the path is relative.

outputPath resolves to zenstack/ with getOutputPath(), so relative SQLite URLs like file:database.sqlite, file:./database.sqlite, or sqlite:database.sqlite are incorrectly resolved from the cwd (/app/database.sqlite) while the generated datasource.url preserves them as relative to zenstack/ (/app/database.sqlite from zenstack/schema.zmodel) or intentionally up one level. Resolve file:/sqlite: relative URLs against path.resolve('zenstack'), not by joining with outputPath.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/cli/src/actions/proxy.ts` around lines 209 - 230, Update
createDialect’s SQLite URL resolution to use path.resolve('zenstack') as the
base for relative file: and sqlite: URLs, preserving intentional relative paths
such as ./ and ../. Do not use outputPath as the URL base; retain absolute URL
handling and Windows normalization.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@packages/cli/src/actions/proxy.ts`:
- Around line 209-230: Update createDialect’s SQLite URL resolution to use
path.resolve('zenstack') as the base for relative file: and sqlite: URLs,
preserving intentional relative paths such as ./ and ../. Do not use outputPath
as the URL base; retain absolute URL handling and Windows normalization.
In `@packages/cli/src/actions/pull/provider/sqlite.ts`:
- Around line 131-143: Normalize SQLite connection schemes consistently: in
packages/cli/src/actions/pull/provider/sqlite.ts lines 131-143, strip file: and
sqlite: immediately before new SQLite in introspect(); in
packages/cli/src/actions/db.ts lines 137-149, extend runPull’s normalization to
sqlite: and apply equivalent handling in the non-override getDatasource(model)
path; in packages/cli/src/actions/proxy.ts lines 607-631, verify sqlite: is
supported end-to-end and retain the branch only if runPull and introspect honor
it, otherwise remove it.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 98c2175a-b357-4c8e-8bfe-ec5f3d6a9336

📥 Commits

Reviewing files that changed from the base of the PR and between 844e92c and 0a25e4b.

📒 Files selected for processing (5)
  • packages/cli/src/actions/action-utils.ts
  • packages/cli/src/actions/db.ts
  • packages/cli/src/actions/proxy.ts
  • packages/cli/src/actions/pull/provider/sqlite.ts
  • packages/cli/test/proxy.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/cli/src/actions/action-utils.ts

@coderabbitaicoderabbitaiBot left a comment

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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/cli/src/actions/pull/provider/sqlite.ts`:
- Line 361: Update the column nullability mapping around the `nullable` property
to preserve SQLite’s explicit `c.notnull` value instead of treating every
primary-key column as non-nullable. Only override nullability when the table
schema confirms SQLite enforces it, such as an `INTEGER PRIMARY KEY` rowid alias
or applicable `WITHOUT ROWID`/strict tables, and add regression coverage for
TEXT and composite primary keys.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: cf8d702a-03ad-4664-9471-f6e37904c166

📥 Commits

Reviewing files that changed from the base of the PR and between 0a25e4b and e7c4a29.

📒 Files selected for processing (1)
  • packages/cli/src/actions/pull/provider/sqlite.ts

Comment threadpackages/cli/src/actions/pull/provider/sqlite.ts Outdated
Comment threadpackages/cli/src/actions/proxy.ts Outdated
Comment threadpackages/cli/src/actions/action-utils.ts Outdated
@jiashengguo
jiashengguo merged commit 2d239cd into devAug 3, 2026
10 checks passed
@jiashengguo
jiashengguo deleted the jiasheng-proxy branch August 3, 2026 06:23
@coderabbitaicoderabbitaiBot mentioned this pull request Aug 3, 2026
Sign up for freeto 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

@jiashengguo@ymc9
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

feat(cli): add --introspect option for studio command for bootstrapping without schema - #2775

Merged
jiashengguo merged 10 commits into
devfrom
jiasheng-proxy
Aug 3, 2026
Merged

feat(cli): add --introspect option for studio command for bootstrapping without schema #2775
jiashengguo merged 10 commits into
devfrom
jiasheng-proxy

Conversation

@jiashengguo

@jiashengguojiashengguo commented Jul 29, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • New Features

    • Added an --introspect option to generate a schema from your database when no schema file is available.
  • Enhancements

    • Improved schema resolution flows for --introspect vs missing schema, including smarter DATABASE_URL handling for SQLite (relative file: rewriting).
    • Enhanced database pulls with explicit --provider and --database-url support (including improved SQLite path normalization).
    • Improved automatic driver/provider loading and clearer guidance when required drivers aren’t installed.
  • Bug Fixes

    • Corrected SQLite nullability handling for primary key columns during introspection.
  • Tests

    • Expanded coverage for schema resolution and driver/module loading behaviors.

@jiashengguo
jiashengguo requested a review from CopilotJuly 29, 2026 13:35
@coderabbitai

coderabbitaiBot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The CLI adds project-aware database driver loading and an optional --introspect proxy flow that generates a schema from a database URL. runPull accepts explicit datasource overrides, with tests covering provider detection, schema resolution, SQLite URL rewriting, and package loading.

Changes

CLI introspection flow

Layer / File(s)Summary
Package-aware driver loading
packages/cli/src/actions/action-utils.ts, packages/cli/src/actions/proxy.ts, packages/cli/src/actions/pull/provider/*
Adds package resolution fallbacks and uses them to load SQLite, PostgreSQL, and MySQL drivers, with explicit missing-driver errors.
Pull datasource overrides
packages/cli/src/actions/db.ts
Exports runPull and accepts provider and database URL overrides, including SQLite URL normalization.
Proxy schema introspection
packages/cli/src/actions/proxy.ts, packages/cli/src/index.ts
Adds --introspect, provider detection, driver installation, schema generation, SQLite URL adjustment, and schema resolution branching.
Introspection validation
packages/cli/test/action-utils.test.ts, packages/cli/test/proxy.test.ts
Tests package loading, provider URL mapping, schema-resolution errors, default schema handling, and relative SQLite URLs.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

  • zenstackhq/zenstack#2761: Both changes modify runPull relation and schema synchronization logic in packages/cli/src/actions/db.ts.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title accurately describes the main user-facing change: adding a --introspect option to bootstrap studio without an existing schema.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jiasheng-proxy

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

CopilotAI left a comment

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.

Pull request overview

This PR adds an --introspect option to the CLI’s Studio/proxy command flow to bootstrap a project when no ZModel schema file is present, including auto-installing the correct DB driver and generating a schema via the existing pull/introspection pipeline.

Changes:

  • Adds --introspect flag to the CLI command definition and routes schema resolution through a new resolveSchema helper.
  • Introduces shared optional-dependency helpers (isPackageInstalled, loadPackage) and uses them across DB introspection providers and proxy dialect creation.
  • Extends runPull to accept explicit provider/databaseUrl overrides to support schema generation from an introspected database.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
FileDescription
packages/cli/src/index.tsAdds the --introspect CLI option to the command.
packages/cli/src/actions/proxy.tsImplements --introspect schema resolution, driver installation, schema generation, and generation follow-up.
packages/cli/src/actions/db.tsExports runPull and allows provider/URL overrides for introspection-driven generation.
packages/cli/src/actions/action-utils.tsAdds isPackageInstalled and loadPackage helpers for optional dependency loading.
packages/cli/src/actions/pull/provider/sqlite.tsSwitches SQLite introspection to loadPackage and adds file URL handling.
packages/cli/src/actions/pull/provider/postgresql.tsSwitches PostgreSQL introspection to loadPackage.
packages/cli/src/actions/pull/provider/mysql.tsSwitches MySQL introspection to loadPackage.
packages/cli/test/proxy.test.tsAdds unit tests for getProviderFromUrl and resolveSchema behaviors.
packages/cli/test/action-utils.test.tsAdds tests for isPackageInstalled and loadPackage.
Comments suppressed due to low confidence (1)

packages/cli/test/proxy.test.ts:862

  • This assertion looks for zen studio --introspect, but resolveSchema emits npx @zenstackhq/cli studio --introspect .... Using studio --introspect as the substring match should make the test align with the actual message formatting.
 ).rejects.toThrow('zen studio --introspect');

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment threadpackages/cli/src/actions/pull/provider/postgresql.ts
Comment threadpackages/cli/src/actions/pull/provider/sqlite.ts Outdated
Comment threadpackages/cli/test/proxy.test.ts Outdated
Comment threadpackages/cli/src/actions/proxy.ts Outdated

@coderabbitaicoderabbitaiBot left a comment

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.

Actionable comments posted: 8

🧹 Nitpick comments (1)
packages/cli/src/actions/action-utils.ts (1)

386-415: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract shared createRequire(package.json) logic.

The same createRequire(path.resolve(process.cwd(), 'package.json')) pattern is repeated 3 times across isPackageInstalled and loadPackage. A small shared helper (getProjectRequire()) would reduce duplication and keep the two functions in sync if the resolution base ever changes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/cli/src/actions/action-utils.ts` around lines 386 - 415, Extract the
repeated createRequire(path.resolve(process.cwd(), 'package.json')) construction
into a shared getProjectRequire() helper. Update isPackageInstalled and both
fallback branches in loadPackage to reuse this helper, preserving their existing
resolution and error-handling behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/cli/src/actions/action-utils.ts`:
- Around line 396-415: Update loadPackage so it preserves and propagates the
underlying error when the package cannot be loaded, rather than returning null
after all import and require fallbacks fail. Track the original and fallback
failures through the nested dynamic import, projectRequire.resolve, and
projectRequire calls, then throw a diagnostic error that retains the relevant
cause for callers such as createDialect and the database providers.
In `@packages/cli/src/actions/db.ts`:
- Around line 38-39: Add a warning in the introspection flow when the resulting
tables and enums are both empty, regardless of provider or schema selection.
Update the logic around allSchemas and the PostgreSQL introspect result so the
warning clearly indicates that no database objects were found, while preserving
successful empty-result behavior.
In `@packages/cli/src/actions/proxy.ts`:
- Around line 517-530: Restrict the existing default-schema fallback around
getSchemaFile to cases where options.schema was not explicitly provided. When an
explicit --schema path fails, propagate the original CliError instead of
returning zenstack/schema.zmodel; preserve the fallback for missing schemas in
default locations.
- Around line 619-649: Update introspectAndGenerateSchema so the generated
datasource always references env("DATABASE_URL") instead of embedding
databaseUrl when urlFromEnv is false. Preserve the existing provider and runPull
behavior, and ensure the literal connection string is never written to
schema.zmodel.
- Around line 542-544: Update the runGenerate invocation in the introspection
flow to pass options.output as the code generation output path. Preserve the
existing schema, silent, and watch arguments so generated files and subsequent
imports use the same custom output directory resolved by resolveSchema().
In `@packages/cli/src/actions/pull/provider/sqlite.ts`:
- Around line 144-151: Align SQLite relative file URL resolution between the
introspection path and createDialect. Update the resolution logic surrounding
the SQLite constructor and createDialect’s SQLite branch to use the same base
directory, preserving identical database targeting for the --introspect
bootstrap flow; prefer the existing shared resolution behavior rather than
introducing divergent path handling.
In `@packages/cli/test/action-utils.test.ts`:
- Around line 60-62: Update the successful-load test around loadPackage to
assert that the returned module is not null, replacing the insufficient
toBeDefined assertion. Keep the test focused on rejecting loadPackage’s
documented null failure result.
In `@packages/cli/test/proxy.test.ts`:
- Around line 836-846: Update the expected error substrings in the tests around
resolveSchema to match its actual command text: assert the npx `@zenstackhq/cli`
studio prefix and the -d <databaseUrl> placeholder. Apply the same correction to
both affected assertions while preserving the existing test setup and
error-checking behavior.
---
Nitpick comments:
In `@packages/cli/src/actions/action-utils.ts`:
- Around line 386-415: Extract the repeated
createRequire(path.resolve(process.cwd(), 'package.json')) construction into a
shared getProjectRequire() helper. Update isPackageInstalled and both fallback
branches in loadPackage to reuse this helper, preserving their existing
resolution and error-handling behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 312bca78-7c2c-4751-8fea-9074176dca5b

📥 Commits

Reviewing files that changed from the base of the PR and between 78e741e and bd12232.

📒 Files selected for processing (9)
  • packages/cli/src/actions/action-utils.ts
  • packages/cli/src/actions/db.ts
  • packages/cli/src/actions/proxy.ts
  • packages/cli/src/actions/pull/provider/mysql.ts
  • packages/cli/src/actions/pull/provider/postgresql.ts
  • packages/cli/src/actions/pull/provider/sqlite.ts
  • packages/cli/src/index.ts
  • packages/cli/test/action-utils.test.ts
  • packages/cli/test/proxy.test.ts

Comment threadpackages/cli/src/actions/action-utils.ts
Comment threadpackages/cli/src/actions/db.ts
Comment threadpackages/cli/src/actions/proxy.ts Outdated
Comment threadpackages/cli/src/actions/proxy.ts
Comment threadpackages/cli/src/actions/proxy.ts
Comment threadpackages/cli/src/actions/pull/provider/sqlite.ts Outdated
Comment threadpackages/cli/test/action-utils.test.ts
Comment threadpackages/cli/test/proxy.test.ts Outdated

@coderabbitaicoderabbitaiBot left a comment

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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/cli/src/actions/pull/provider/sqlite.ts (1)

131-143: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

SQLite file:/sqlite: scheme stripping is now split across files and only partially implemented. The root cause: sqlite.ts's introspect() used to normalize file:-prefixed connection strings itself; that logic was removed and only partially reimplemented in db.ts's runPull, covering just the file: prefix and only the explicit --introspect override path.

  • packages/cli/src/actions/pull/provider/sqlite.ts#L131-L143: reinstate scheme stripping (file:/sqlite: → raw path) directly before new SQLite(connectionString, ...) as a defensive last line of normalization, since callers cannot be relied upon to always pre-resolve the URL.
  • packages/cli/src/actions/db.ts#L137-L149: extend the existing databaseUrl.startsWith('file:') branch to also cover sqlite:, and consider applying equivalent normalization in the non-override getDatasource(model) branch too, since the documented ZenStack SQLite format (url = 'file:./dev.db') needs the same treatment there.
  • packages/cli/src/actions/proxy.ts#L607-L631: either confirm sqlite: is a genuinely supported input format and ensure runPull/introspect() honor it end-to-end, or drop the sqlite: branch here if it's dead/speculative handling.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/cli/src/actions/pull/provider/sqlite.ts` around lines 131 - 143,
Normalize SQLite connection schemes consistently: in
packages/cli/src/actions/pull/provider/sqlite.ts lines 131-143, strip file: and
sqlite: immediately before new SQLite in introspect(); in
packages/cli/src/actions/db.ts lines 137-149, extend runPull’s normalization to
sqlite: and apply equivalent handling in the non-override getDatasource(model)
path; in packages/cli/src/actions/proxy.ts lines 607-631, verify sqlite: is
supported end-to-end and retain the branch only if runPull and introspect honor
it, otherwise remove it.
packages/cli/src/actions/proxy.ts (1)

209-230: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Use the schema directory as the SQLite URL base when the path is relative.

outputPath resolves to zenstack/ with getOutputPath(), so relative SQLite URLs like file:database.sqlite, file:./database.sqlite, or sqlite:database.sqlite are incorrectly resolved from the cwd (/app/database.sqlite) while the generated datasource.url preserves them as relative to zenstack/ (/app/database.sqlite from zenstack/schema.zmodel) or intentionally up one level. Resolve file:/sqlite: relative URLs against path.resolve('zenstack'), not by joining with outputPath.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/cli/src/actions/proxy.ts` around lines 209 - 230, Update
createDialect’s SQLite URL resolution to use path.resolve('zenstack') as the
base for relative file: and sqlite: URLs, preserving intentional relative paths
such as ./ and ../. Do not use outputPath as the URL base; retain absolute URL
handling and Windows normalization.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@packages/cli/src/actions/proxy.ts`:
- Around line 209-230: Update createDialect’s SQLite URL resolution to use
path.resolve('zenstack') as the base for relative file: and sqlite: URLs,
preserving intentional relative paths such as ./ and ../. Do not use outputPath
as the URL base; retain absolute URL handling and Windows normalization.
In `@packages/cli/src/actions/pull/provider/sqlite.ts`:
- Around line 131-143: Normalize SQLite connection schemes consistently: in
packages/cli/src/actions/pull/provider/sqlite.ts lines 131-143, strip file: and
sqlite: immediately before new SQLite in introspect(); in
packages/cli/src/actions/db.ts lines 137-149, extend runPull’s normalization to
sqlite: and apply equivalent handling in the non-override getDatasource(model)
path; in packages/cli/src/actions/proxy.ts lines 607-631, verify sqlite: is
supported end-to-end and retain the branch only if runPull and introspect honor
it, otherwise remove it.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 98c2175a-b357-4c8e-8bfe-ec5f3d6a9336

📥 Commits

Reviewing files that changed from the base of the PR and between 844e92c and 0a25e4b.

📒 Files selected for processing (5)
  • packages/cli/src/actions/action-utils.ts
  • packages/cli/src/actions/db.ts
  • packages/cli/src/actions/proxy.ts
  • packages/cli/src/actions/pull/provider/sqlite.ts
  • packages/cli/test/proxy.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/cli/src/actions/action-utils.ts

@coderabbitaicoderabbitaiBot left a comment

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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/cli/src/actions/pull/provider/sqlite.ts`:
- Line 361: Update the column nullability mapping around the `nullable` property
to preserve SQLite’s explicit `c.notnull` value instead of treating every
primary-key column as non-nullable. Only override nullability when the table
schema confirms SQLite enforces it, such as an `INTEGER PRIMARY KEY` rowid alias
or applicable `WITHOUT ROWID`/strict tables, and add regression coverage for
TEXT and composite primary keys.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: cf8d702a-03ad-4664-9471-f6e37904c166

📥 Commits

Reviewing files that changed from the base of the PR and between 0a25e4b and e7c4a29.

📒 Files selected for processing (1)
  • packages/cli/src/actions/pull/provider/sqlite.ts

Comment threadpackages/cli/src/actions/pull/provider/sqlite.ts Outdated
Comment threadpackages/cli/src/actions/proxy.ts Outdated
Comment threadpackages/cli/src/actions/action-utils.ts Outdated
@jiashengguo
jiashengguo merged commit 2d239cd into devAug 3, 2026
10 checks passed
@jiashengguo
jiashengguo deleted the jiasheng-proxy branch August 3, 2026 06:23
@coderabbitaicoderabbitaiBot mentioned this pull request Aug 3, 2026
Sign up for freeto 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

@jiashengguo@ymc9
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(cli): add --introspect option for studio command for bootstrapping without schema - #2775

Merged
jiashengguo merged 10 commits into
devfrom
jiasheng-proxy
Aug 3, 2026
Merged

feat(cli): add --introspect option for studio command for bootstrapping without schema #2775
jiashengguo merged 10 commits into
devfrom
jiasheng-proxy

Conversation

@jiashengguo

@jiashengguojiashengguo commented Jul 29, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • New Features

    • Added an --introspect option to generate a schema from your database when no schema file is available.
  • Enhancements

    • Improved schema resolution flows for --introspect vs missing schema, including smarter DATABASE_URL handling for SQLite (relative file: rewriting).
    • Enhanced database pulls with explicit --provider and --database-url support (including improved SQLite path normalization).
    • Improved automatic driver/provider loading and clearer guidance when required drivers aren’t installed.
  • Bug Fixes

    • Corrected SQLite nullability handling for primary key columns during introspection.
  • Tests

    • Expanded coverage for schema resolution and driver/module loading behaviors.

@jiashengguo
jiashengguo requested a review from CopilotJuly 29, 2026 13:35
@coderabbitai

coderabbitaiBot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The CLI adds project-aware database driver loading and an optional --introspect proxy flow that generates a schema from a database URL. runPull accepts explicit datasource overrides, with tests covering provider detection, schema resolution, SQLite URL rewriting, and package loading.

Changes

CLI introspection flow

Layer / File(s)Summary
Package-aware driver loading
packages/cli/src/actions/action-utils.ts, packages/cli/src/actions/proxy.ts, packages/cli/src/actions/pull/provider/*
Adds package resolution fallbacks and uses them to load SQLite, PostgreSQL, and MySQL drivers, with explicit missing-driver errors.
Pull datasource overrides
packages/cli/src/actions/db.ts
Exports runPull and accepts provider and database URL overrides, including SQLite URL normalization.
Proxy schema introspection
packages/cli/src/actions/proxy.ts, packages/cli/src/index.ts
Adds --introspect, provider detection, driver installation, schema generation, SQLite URL adjustment, and schema resolution branching.
Introspection validation
packages/cli/test/action-utils.test.ts, packages/cli/test/proxy.test.ts
Tests package loading, provider URL mapping, schema-resolution errors, default schema handling, and relative SQLite URLs.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

  • zenstackhq/zenstack#2761: Both changes modify runPull relation and schema synchronization logic in packages/cli/src/actions/db.ts.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title accurately describes the main user-facing change: adding a --introspect option to bootstrap studio without an existing schema.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jiasheng-proxy

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

CopilotAI left a comment

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.

Pull request overview

This PR adds an --introspect option to the CLI’s Studio/proxy command flow to bootstrap a project when no ZModel schema file is present, including auto-installing the correct DB driver and generating a schema via the existing pull/introspection pipeline.

Changes:

  • Adds --introspect flag to the CLI command definition and routes schema resolution through a new resolveSchema helper.
  • Introduces shared optional-dependency helpers (isPackageInstalled, loadPackage) and uses them across DB introspection providers and proxy dialect creation.
  • Extends runPull to accept explicit provider/databaseUrl overrides to support schema generation from an introspected database.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
FileDescription
packages/cli/src/index.tsAdds the --introspect CLI option to the command.
packages/cli/src/actions/proxy.tsImplements --introspect schema resolution, driver installation, schema generation, and generation follow-up.
packages/cli/src/actions/db.tsExports runPull and allows provider/URL overrides for introspection-driven generation.
packages/cli/src/actions/action-utils.tsAdds isPackageInstalled and loadPackage helpers for optional dependency loading.
packages/cli/src/actions/pull/provider/sqlite.tsSwitches SQLite introspection to loadPackage and adds file URL handling.
packages/cli/src/actions/pull/provider/postgresql.tsSwitches PostgreSQL introspection to loadPackage.
packages/cli/src/actions/pull/provider/mysql.tsSwitches MySQL introspection to loadPackage.
packages/cli/test/proxy.test.tsAdds unit tests for getProviderFromUrl and resolveSchema behaviors.
packages/cli/test/action-utils.test.tsAdds tests for isPackageInstalled and loadPackage.
Comments suppressed due to low confidence (1)

packages/cli/test/proxy.test.ts:862

  • This assertion looks for zen studio --introspect, but resolveSchema emits npx @zenstackhq/cli studio --introspect .... Using studio --introspect as the substring match should make the test align with the actual message formatting.
 ).rejects.toThrow('zen studio --introspect');

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment threadpackages/cli/src/actions/pull/provider/postgresql.ts
Comment threadpackages/cli/src/actions/pull/provider/sqlite.ts Outdated
Comment threadpackages/cli/test/proxy.test.ts Outdated
Comment threadpackages/cli/src/actions/proxy.ts Outdated

@coderabbitaicoderabbitaiBot left a comment

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.

Actionable comments posted: 8

🧹 Nitpick comments (1)
packages/cli/src/actions/action-utils.ts (1)

386-415: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract shared createRequire(package.json) logic.

The same createRequire(path.resolve(process.cwd(), 'package.json')) pattern is repeated 3 times across isPackageInstalled and loadPackage. A small shared helper (getProjectRequire()) would reduce duplication and keep the two functions in sync if the resolution base ever changes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/cli/src/actions/action-utils.ts` around lines 386 - 415, Extract the
repeated createRequire(path.resolve(process.cwd(), 'package.json')) construction
into a shared getProjectRequire() helper. Update isPackageInstalled and both
fallback branches in loadPackage to reuse this helper, preserving their existing
resolution and error-handling behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/cli/src/actions/action-utils.ts`:
- Around line 396-415: Update loadPackage so it preserves and propagates the
underlying error when the package cannot be loaded, rather than returning null
after all import and require fallbacks fail. Track the original and fallback
failures through the nested dynamic import, projectRequire.resolve, and
projectRequire calls, then throw a diagnostic error that retains the relevant
cause for callers such as createDialect and the database providers.
In `@packages/cli/src/actions/db.ts`:
- Around line 38-39: Add a warning in the introspection flow when the resulting
tables and enums are both empty, regardless of provider or schema selection.
Update the logic around allSchemas and the PostgreSQL introspect result so the
warning clearly indicates that no database objects were found, while preserving
successful empty-result behavior.
In `@packages/cli/src/actions/proxy.ts`:
- Around line 517-530: Restrict the existing default-schema fallback around
getSchemaFile to cases where options.schema was not explicitly provided. When an
explicit --schema path fails, propagate the original CliError instead of
returning zenstack/schema.zmodel; preserve the fallback for missing schemas in
default locations.
- Around line 619-649: Update introspectAndGenerateSchema so the generated
datasource always references env("DATABASE_URL") instead of embedding
databaseUrl when urlFromEnv is false. Preserve the existing provider and runPull
behavior, and ensure the literal connection string is never written to
schema.zmodel.
- Around line 542-544: Update the runGenerate invocation in the introspection
flow to pass options.output as the code generation output path. Preserve the
existing schema, silent, and watch arguments so generated files and subsequent
imports use the same custom output directory resolved by resolveSchema().
In `@packages/cli/src/actions/pull/provider/sqlite.ts`:
- Around line 144-151: Align SQLite relative file URL resolution between the
introspection path and createDialect. Update the resolution logic surrounding
the SQLite constructor and createDialect’s SQLite branch to use the same base
directory, preserving identical database targeting for the --introspect
bootstrap flow; prefer the existing shared resolution behavior rather than
introducing divergent path handling.
In `@packages/cli/test/action-utils.test.ts`:
- Around line 60-62: Update the successful-load test around loadPackage to
assert that the returned module is not null, replacing the insufficient
toBeDefined assertion. Keep the test focused on rejecting loadPackage’s
documented null failure result.
In `@packages/cli/test/proxy.test.ts`:
- Around line 836-846: Update the expected error substrings in the tests around
resolveSchema to match its actual command text: assert the npx `@zenstackhq/cli`
studio prefix and the -d <databaseUrl> placeholder. Apply the same correction to
both affected assertions while preserving the existing test setup and
error-checking behavior.
---
Nitpick comments:
In `@packages/cli/src/actions/action-utils.ts`:
- Around line 386-415: Extract the repeated
createRequire(path.resolve(process.cwd(), 'package.json')) construction into a
shared getProjectRequire() helper. Update isPackageInstalled and both fallback
branches in loadPackage to reuse this helper, preserving their existing
resolution and error-handling behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 312bca78-7c2c-4751-8fea-9074176dca5b

📥 Commits

Reviewing files that changed from the base of the PR and between 78e741e and bd12232.

📒 Files selected for processing (9)
  • packages/cli/src/actions/action-utils.ts
  • packages/cli/src/actions/db.ts
  • packages/cli/src/actions/proxy.ts
  • packages/cli/src/actions/pull/provider/mysql.ts
  • packages/cli/src/actions/pull/provider/postgresql.ts
  • packages/cli/src/actions/pull/provider/sqlite.ts
  • packages/cli/src/index.ts
  • packages/cli/test/action-utils.test.ts
  • packages/cli/test/proxy.test.ts

Comment threadpackages/cli/src/actions/action-utils.ts
Comment threadpackages/cli/src/actions/db.ts
Comment threadpackages/cli/src/actions/proxy.ts Outdated
Comment threadpackages/cli/src/actions/proxy.ts
Comment threadpackages/cli/src/actions/proxy.ts
Comment threadpackages/cli/src/actions/pull/provider/sqlite.ts Outdated
Comment threadpackages/cli/test/action-utils.test.ts
Comment threadpackages/cli/test/proxy.test.ts Outdated

@coderabbitaicoderabbitaiBot left a comment

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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/cli/src/actions/pull/provider/sqlite.ts (1)

131-143: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

SQLite file:/sqlite: scheme stripping is now split across files and only partially implemented. The root cause: sqlite.ts's introspect() used to normalize file:-prefixed connection strings itself; that logic was removed and only partially reimplemented in db.ts's runPull, covering just the file: prefix and only the explicit --introspect override path.

  • packages/cli/src/actions/pull/provider/sqlite.ts#L131-L143: reinstate scheme stripping (file:/sqlite: → raw path) directly before new SQLite(connectionString, ...) as a defensive last line of normalization, since callers cannot be relied upon to always pre-resolve the URL.
  • packages/cli/src/actions/db.ts#L137-L149: extend the existing databaseUrl.startsWith('file:') branch to also cover sqlite:, and consider applying equivalent normalization in the non-override getDatasource(model) branch too, since the documented ZenStack SQLite format (url = 'file:./dev.db') needs the same treatment there.
  • packages/cli/src/actions/proxy.ts#L607-L631: either confirm sqlite: is a genuinely supported input format and ensure runPull/introspect() honor it end-to-end, or drop the sqlite: branch here if it's dead/speculative handling.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/cli/src/actions/pull/provider/sqlite.ts` around lines 131 - 143,
Normalize SQLite connection schemes consistently: in
packages/cli/src/actions/pull/provider/sqlite.ts lines 131-143, strip file: and
sqlite: immediately before new SQLite in introspect(); in
packages/cli/src/actions/db.ts lines 137-149, extend runPull’s normalization to
sqlite: and apply equivalent handling in the non-override getDatasource(model)
path; in packages/cli/src/actions/proxy.ts lines 607-631, verify sqlite: is
supported end-to-end and retain the branch only if runPull and introspect honor
it, otherwise remove it.
packages/cli/src/actions/proxy.ts (1)

209-230: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Use the schema directory as the SQLite URL base when the path is relative.

outputPath resolves to zenstack/ with getOutputPath(), so relative SQLite URLs like file:database.sqlite, file:./database.sqlite, or sqlite:database.sqlite are incorrectly resolved from the cwd (/app/database.sqlite) while the generated datasource.url preserves them as relative to zenstack/ (/app/database.sqlite from zenstack/schema.zmodel) or intentionally up one level. Resolve file:/sqlite: relative URLs against path.resolve('zenstack'), not by joining with outputPath.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/cli/src/actions/proxy.ts` around lines 209 - 230, Update
createDialect’s SQLite URL resolution to use path.resolve('zenstack') as the
base for relative file: and sqlite: URLs, preserving intentional relative paths
such as ./ and ../. Do not use outputPath as the URL base; retain absolute URL
handling and Windows normalization.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@packages/cli/src/actions/proxy.ts`:
- Around line 209-230: Update createDialect’s SQLite URL resolution to use
path.resolve('zenstack') as the base for relative file: and sqlite: URLs,
preserving intentional relative paths such as ./ and ../. Do not use outputPath
as the URL base; retain absolute URL handling and Windows normalization.
In `@packages/cli/src/actions/pull/provider/sqlite.ts`:
- Around line 131-143: Normalize SQLite connection schemes consistently: in
packages/cli/src/actions/pull/provider/sqlite.ts lines 131-143, strip file: and
sqlite: immediately before new SQLite in introspect(); in
packages/cli/src/actions/db.ts lines 137-149, extend runPull’s normalization to
sqlite: and apply equivalent handling in the non-override getDatasource(model)
path; in packages/cli/src/actions/proxy.ts lines 607-631, verify sqlite: is
supported end-to-end and retain the branch only if runPull and introspect honor
it, otherwise remove it.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 98c2175a-b357-4c8e-8bfe-ec5f3d6a9336

📥 Commits

Reviewing files that changed from the base of the PR and between 844e92c and 0a25e4b.

📒 Files selected for processing (5)
  • packages/cli/src/actions/action-utils.ts
  • packages/cli/src/actions/db.ts
  • packages/cli/src/actions/proxy.ts
  • packages/cli/src/actions/pull/provider/sqlite.ts
  • packages/cli/test/proxy.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/cli/src/actions/action-utils.ts

@coderabbitaicoderabbitaiBot left a comment

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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/cli/src/actions/pull/provider/sqlite.ts`:
- Line 361: Update the column nullability mapping around the `nullable` property
to preserve SQLite’s explicit `c.notnull` value instead of treating every
primary-key column as non-nullable. Only override nullability when the table
schema confirms SQLite enforces it, such as an `INTEGER PRIMARY KEY` rowid alias
or applicable `WITHOUT ROWID`/strict tables, and add regression coverage for
TEXT and composite primary keys.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: cf8d702a-03ad-4664-9471-f6e37904c166

📥 Commits

Reviewing files that changed from the base of the PR and between 0a25e4b and e7c4a29.

📒 Files selected for processing (1)
  • packages/cli/src/actions/pull/provider/sqlite.ts

Comment threadpackages/cli/src/actions/pull/provider/sqlite.ts Outdated
Comment threadpackages/cli/src/actions/proxy.ts Outdated
Comment threadpackages/cli/src/actions/action-utils.ts Outdated
@jiashengguo
jiashengguo merged commit 2d239cd into devAug 3, 2026
10 checks passed
@jiashengguo
jiashengguo deleted the jiasheng-proxy branch August 3, 2026 06:23
@coderabbitaicoderabbitaiBot mentioned this pull request Aug 3, 2026
Sign up for freeto 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

@jiashengguo@ymc9
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(cli): add --introspect option for studio command for bootstrapping without schema - #2775

Merged
jiashengguo merged 10 commits into
devfrom
jiasheng-proxy
Aug 3, 2026
Merged

feat(cli): add --introspect option for studio command for bootstrapping without schema #2775
jiashengguo merged 10 commits into
devfrom
jiasheng-proxy

Conversation

@jiashengguo

@jiashengguojiashengguo commented Jul 29, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • New Features

    • Added an --introspect option to generate a schema from your database when no schema file is available.
  • Enhancements

    • Improved schema resolution flows for --introspect vs missing schema, including smarter DATABASE_URL handling for SQLite (relative file: rewriting).
    • Enhanced database pulls with explicit --provider and --database-url support (including improved SQLite path normalization).
    • Improved automatic driver/provider loading and clearer guidance when required drivers aren’t installed.
  • Bug Fixes

    • Corrected SQLite nullability handling for primary key columns during introspection.
  • Tests

    • Expanded coverage for schema resolution and driver/module loading behaviors.

@jiashengguo
jiashengguo requested a review from CopilotJuly 29, 2026 13:35
@coderabbitai

coderabbitaiBot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The CLI adds project-aware database driver loading and an optional --introspect proxy flow that generates a schema from a database URL. runPull accepts explicit datasource overrides, with tests covering provider detection, schema resolution, SQLite URL rewriting, and package loading.

Changes

CLI introspection flow

Layer / File(s)Summary
Package-aware driver loading
packages/cli/src/actions/action-utils.ts, packages/cli/src/actions/proxy.ts, packages/cli/src/actions/pull/provider/*
Adds package resolution fallbacks and uses them to load SQLite, PostgreSQL, and MySQL drivers, with explicit missing-driver errors.
Pull datasource overrides
packages/cli/src/actions/db.ts
Exports runPull and accepts provider and database URL overrides, including SQLite URL normalization.
Proxy schema introspection
packages/cli/src/actions/proxy.ts, packages/cli/src/index.ts
Adds --introspect, provider detection, driver installation, schema generation, SQLite URL adjustment, and schema resolution branching.
Introspection validation
packages/cli/test/action-utils.test.ts, packages/cli/test/proxy.test.ts
Tests package loading, provider URL mapping, schema-resolution errors, default schema handling, and relative SQLite URLs.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

  • zenstackhq/zenstack#2761: Both changes modify runPull relation and schema synchronization logic in packages/cli/src/actions/db.ts.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title accurately describes the main user-facing change: adding a --introspect option to bootstrap studio without an existing schema.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jiasheng-proxy

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

CopilotAI left a comment

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.

Pull request overview

This PR adds an --introspect option to the CLI’s Studio/proxy command flow to bootstrap a project when no ZModel schema file is present, including auto-installing the correct DB driver and generating a schema via the existing pull/introspection pipeline.

Changes:

  • Adds --introspect flag to the CLI command definition and routes schema resolution through a new resolveSchema helper.
  • Introduces shared optional-dependency helpers (isPackageInstalled, loadPackage) and uses them across DB introspection providers and proxy dialect creation.
  • Extends runPull to accept explicit provider/databaseUrl overrides to support schema generation from an introspected database.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
FileDescription
packages/cli/src/index.tsAdds the --introspect CLI option to the command.
packages/cli/src/actions/proxy.tsImplements --introspect schema resolution, driver installation, schema generation, and generation follow-up.
packages/cli/src/actions/db.tsExports runPull and allows provider/URL overrides for introspection-driven generation.
packages/cli/src/actions/action-utils.tsAdds isPackageInstalled and loadPackage helpers for optional dependency loading.
packages/cli/src/actions/pull/provider/sqlite.tsSwitches SQLite introspection to loadPackage and adds file URL handling.
packages/cli/src/actions/pull/provider/postgresql.tsSwitches PostgreSQL introspection to loadPackage.
packages/cli/src/actions/pull/provider/mysql.tsSwitches MySQL introspection to loadPackage.
packages/cli/test/proxy.test.tsAdds unit tests for getProviderFromUrl and resolveSchema behaviors.
packages/cli/test/action-utils.test.tsAdds tests for isPackageInstalled and loadPackage.
Comments suppressed due to low confidence (1)

packages/cli/test/proxy.test.ts:862

  • This assertion looks for zen studio --introspect, but resolveSchema emits npx @zenstackhq/cli studio --introspect .... Using studio --introspect as the substring match should make the test align with the actual message formatting.
 ).rejects.toThrow('zen studio --introspect');

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment threadpackages/cli/src/actions/pull/provider/postgresql.ts
Comment threadpackages/cli/src/actions/pull/provider/sqlite.ts Outdated
Comment threadpackages/cli/test/proxy.test.ts Outdated
Comment threadpackages/cli/src/actions/proxy.ts Outdated

@coderabbitaicoderabbitaiBot left a comment

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.

Actionable comments posted: 8

🧹 Nitpick comments (1)
packages/cli/src/actions/action-utils.ts (1)

386-415: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract shared createRequire(package.json) logic.

The same createRequire(path.resolve(process.cwd(), 'package.json')) pattern is repeated 3 times across isPackageInstalled and loadPackage. A small shared helper (getProjectRequire()) would reduce duplication and keep the two functions in sync if the resolution base ever changes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/cli/src/actions/action-utils.ts` around lines 386 - 415, Extract the
repeated createRequire(path.resolve(process.cwd(), 'package.json')) construction
into a shared getProjectRequire() helper. Update isPackageInstalled and both
fallback branches in loadPackage to reuse this helper, preserving their existing
resolution and error-handling behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/cli/src/actions/action-utils.ts`:
- Around line 396-415: Update loadPackage so it preserves and propagates the
underlying error when the package cannot be loaded, rather than returning null
after all import and require fallbacks fail. Track the original and fallback
failures through the nested dynamic import, projectRequire.resolve, and
projectRequire calls, then throw a diagnostic error that retains the relevant
cause for callers such as createDialect and the database providers.
In `@packages/cli/src/actions/db.ts`:
- Around line 38-39: Add a warning in the introspection flow when the resulting
tables and enums are both empty, regardless of provider or schema selection.
Update the logic around allSchemas and the PostgreSQL introspect result so the
warning clearly indicates that no database objects were found, while preserving
successful empty-result behavior.
In `@packages/cli/src/actions/proxy.ts`:
- Around line 517-530: Restrict the existing default-schema fallback around
getSchemaFile to cases where options.schema was not explicitly provided. When an
explicit --schema path fails, propagate the original CliError instead of
returning zenstack/schema.zmodel; preserve the fallback for missing schemas in
default locations.
- Around line 619-649: Update introspectAndGenerateSchema so the generated
datasource always references env("DATABASE_URL") instead of embedding
databaseUrl when urlFromEnv is false. Preserve the existing provider and runPull
behavior, and ensure the literal connection string is never written to
schema.zmodel.
- Around line 542-544: Update the runGenerate invocation in the introspection
flow to pass options.output as the code generation output path. Preserve the
existing schema, silent, and watch arguments so generated files and subsequent
imports use the same custom output directory resolved by resolveSchema().
In `@packages/cli/src/actions/pull/provider/sqlite.ts`:
- Around line 144-151: Align SQLite relative file URL resolution between the
introspection path and createDialect. Update the resolution logic surrounding
the SQLite constructor and createDialect’s SQLite branch to use the same base
directory, preserving identical database targeting for the --introspect
bootstrap flow; prefer the existing shared resolution behavior rather than
introducing divergent path handling.
In `@packages/cli/test/action-utils.test.ts`:
- Around line 60-62: Update the successful-load test around loadPackage to
assert that the returned module is not null, replacing the insufficient
toBeDefined assertion. Keep the test focused on rejecting loadPackage’s
documented null failure result.
In `@packages/cli/test/proxy.test.ts`:
- Around line 836-846: Update the expected error substrings in the tests around
resolveSchema to match its actual command text: assert the npx `@zenstackhq/cli`
studio prefix and the -d <databaseUrl> placeholder. Apply the same correction to
both affected assertions while preserving the existing test setup and
error-checking behavior.
---
Nitpick comments:
In `@packages/cli/src/actions/action-utils.ts`:
- Around line 386-415: Extract the repeated
createRequire(path.resolve(process.cwd(), 'package.json')) construction into a
shared getProjectRequire() helper. Update isPackageInstalled and both fallback
branches in loadPackage to reuse this helper, preserving their existing
resolution and error-handling behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 312bca78-7c2c-4751-8fea-9074176dca5b

📥 Commits

Reviewing files that changed from the base of the PR and between 78e741e and bd12232.

📒 Files selected for processing (9)
  • packages/cli/src/actions/action-utils.ts
  • packages/cli/src/actions/db.ts
  • packages/cli/src/actions/proxy.ts
  • packages/cli/src/actions/pull/provider/mysql.ts
  • packages/cli/src/actions/pull/provider/postgresql.ts
  • packages/cli/src/actions/pull/provider/sqlite.ts
  • packages/cli/src/index.ts
  • packages/cli/test/action-utils.test.ts
  • packages/cli/test/proxy.test.ts

Comment threadpackages/cli/src/actions/action-utils.ts
Comment threadpackages/cli/src/actions/db.ts
Comment threadpackages/cli/src/actions/proxy.ts Outdated
Comment threadpackages/cli/src/actions/proxy.ts
Comment threadpackages/cli/src/actions/proxy.ts
Comment threadpackages/cli/src/actions/pull/provider/sqlite.ts Outdated
Comment threadpackages/cli/test/action-utils.test.ts
Comment threadpackages/cli/test/proxy.test.ts Outdated

@coderabbitaicoderabbitaiBot left a comment

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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/cli/src/actions/pull/provider/sqlite.ts (1)

131-143: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

SQLite file:/sqlite: scheme stripping is now split across files and only partially implemented. The root cause: sqlite.ts's introspect() used to normalize file:-prefixed connection strings itself; that logic was removed and only partially reimplemented in db.ts's runPull, covering just the file: prefix and only the explicit --introspect override path.

  • packages/cli/src/actions/pull/provider/sqlite.ts#L131-L143: reinstate scheme stripping (file:/sqlite: → raw path) directly before new SQLite(connectionString, ...) as a defensive last line of normalization, since callers cannot be relied upon to always pre-resolve the URL.
  • packages/cli/src/actions/db.ts#L137-L149: extend the existing databaseUrl.startsWith('file:') branch to also cover sqlite:, and consider applying equivalent normalization in the non-override getDatasource(model) branch too, since the documented ZenStack SQLite format (url = 'file:./dev.db') needs the same treatment there.
  • packages/cli/src/actions/proxy.ts#L607-L631: either confirm sqlite: is a genuinely supported input format and ensure runPull/introspect() honor it end-to-end, or drop the sqlite: branch here if it's dead/speculative handling.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/cli/src/actions/pull/provider/sqlite.ts` around lines 131 - 143,
Normalize SQLite connection schemes consistently: in
packages/cli/src/actions/pull/provider/sqlite.ts lines 131-143, strip file: and
sqlite: immediately before new SQLite in introspect(); in
packages/cli/src/actions/db.ts lines 137-149, extend runPull’s normalization to
sqlite: and apply equivalent handling in the non-override getDatasource(model)
path; in packages/cli/src/actions/proxy.ts lines 607-631, verify sqlite: is
supported end-to-end and retain the branch only if runPull and introspect honor
it, otherwise remove it.
packages/cli/src/actions/proxy.ts (1)

209-230: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Use the schema directory as the SQLite URL base when the path is relative.

outputPath resolves to zenstack/ with getOutputPath(), so relative SQLite URLs like file:database.sqlite, file:./database.sqlite, or sqlite:database.sqlite are incorrectly resolved from the cwd (/app/database.sqlite) while the generated datasource.url preserves them as relative to zenstack/ (/app/database.sqlite from zenstack/schema.zmodel) or intentionally up one level. Resolve file:/sqlite: relative URLs against path.resolve('zenstack'), not by joining with outputPath.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/cli/src/actions/proxy.ts` around lines 209 - 230, Update
createDialect’s SQLite URL resolution to use path.resolve('zenstack') as the
base for relative file: and sqlite: URLs, preserving intentional relative paths
such as ./ and ../. Do not use outputPath as the URL base; retain absolute URL
handling and Windows normalization.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@packages/cli/src/actions/proxy.ts`:
- Around line 209-230: Update createDialect’s SQLite URL resolution to use
path.resolve('zenstack') as the base for relative file: and sqlite: URLs,
preserving intentional relative paths such as ./ and ../. Do not use outputPath
as the URL base; retain absolute URL handling and Windows normalization.
In `@packages/cli/src/actions/pull/provider/sqlite.ts`:
- Around line 131-143: Normalize SQLite connection schemes consistently: in
packages/cli/src/actions/pull/provider/sqlite.ts lines 131-143, strip file: and
sqlite: immediately before new SQLite in introspect(); in
packages/cli/src/actions/db.ts lines 137-149, extend runPull’s normalization to
sqlite: and apply equivalent handling in the non-override getDatasource(model)
path; in packages/cli/src/actions/proxy.ts lines 607-631, verify sqlite: is
supported end-to-end and retain the branch only if runPull and introspect honor
it, otherwise remove it.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 98c2175a-b357-4c8e-8bfe-ec5f3d6a9336

📥 Commits

Reviewing files that changed from the base of the PR and between 844e92c and 0a25e4b.

📒 Files selected for processing (5)
  • packages/cli/src/actions/action-utils.ts
  • packages/cli/src/actions/db.ts
  • packages/cli/src/actions/proxy.ts
  • packages/cli/src/actions/pull/provider/sqlite.ts
  • packages/cli/test/proxy.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/cli/src/actions/action-utils.ts

@coderabbitaicoderabbitaiBot left a comment

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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/cli/src/actions/pull/provider/sqlite.ts`:
- Line 361: Update the column nullability mapping around the `nullable` property
to preserve SQLite’s explicit `c.notnull` value instead of treating every
primary-key column as non-nullable. Only override nullability when the table
schema confirms SQLite enforces it, such as an `INTEGER PRIMARY KEY` rowid alias
or applicable `WITHOUT ROWID`/strict tables, and add regression coverage for
TEXT and composite primary keys.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: cf8d702a-03ad-4664-9471-f6e37904c166

📥 Commits

Reviewing files that changed from the base of the PR and between 0a25e4b and e7c4a29.

📒 Files selected for processing (1)
  • packages/cli/src/actions/pull/provider/sqlite.ts

Comment threadpackages/cli/src/actions/pull/provider/sqlite.ts Outdated
Comment threadpackages/cli/src/actions/proxy.ts Outdated
Comment threadpackages/cli/src/actions/action-utils.ts Outdated
@jiashengguo
jiashengguo merged commit 2d239cd into devAug 3, 2026
10 checks passed
@jiashengguo
jiashengguo deleted the jiasheng-proxy branch August 3, 2026 06:23
@coderabbitaicoderabbitaiBot mentioned this pull request Aug 3, 2026
Sign up for freeto 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

@jiashengguo@ymc9
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

feat(cli): add --introspect option for studio command for bootstrapping without schema - #2775

Merged
jiashengguo merged 10 commits into
devfrom
jiasheng-proxy
Aug 3, 2026
Merged

feat(cli): add --introspect option for studio command for bootstrapping without schema #2775
jiashengguo merged 10 commits into
devfrom
jiasheng-proxy

Conversation

@jiashengguo

@jiashengguojiashengguo commented Jul 29, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • New Features

    • Added an --introspect option to generate a schema from your database when no schema file is available.
  • Enhancements

    • Improved schema resolution flows for --introspect vs missing schema, including smarter DATABASE_URL handling for SQLite (relative file: rewriting).
    • Enhanced database pulls with explicit --provider and --database-url support (including improved SQLite path normalization).
    • Improved automatic driver/provider loading and clearer guidance when required drivers aren’t installed.
  • Bug Fixes

    • Corrected SQLite nullability handling for primary key columns during introspection.
  • Tests

    • Expanded coverage for schema resolution and driver/module loading behaviors.

@jiashengguo
jiashengguo requested a review from CopilotJuly 29, 2026 13:35
@coderabbitai

coderabbitaiBot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The CLI adds project-aware database driver loading and an optional --introspect proxy flow that generates a schema from a database URL. runPull accepts explicit datasource overrides, with tests covering provider detection, schema resolution, SQLite URL rewriting, and package loading.

Changes

CLI introspection flow

Layer / File(s)Summary
Package-aware driver loading
packages/cli/src/actions/action-utils.ts, packages/cli/src/actions/proxy.ts, packages/cli/src/actions/pull/provider/*
Adds package resolution fallbacks and uses them to load SQLite, PostgreSQL, and MySQL drivers, with explicit missing-driver errors.
Pull datasource overrides
packages/cli/src/actions/db.ts
Exports runPull and accepts provider and database URL overrides, including SQLite URL normalization.
Proxy schema introspection
packages/cli/src/actions/proxy.ts, packages/cli/src/index.ts
Adds --introspect, provider detection, driver installation, schema generation, SQLite URL adjustment, and schema resolution branching.
Introspection validation
packages/cli/test/action-utils.test.ts, packages/cli/test/proxy.test.ts
Tests package loading, provider URL mapping, schema-resolution errors, default schema handling, and relative SQLite URLs.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

  • zenstackhq/zenstack#2761: Both changes modify runPull relation and schema synchronization logic in packages/cli/src/actions/db.ts.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title accurately describes the main user-facing change: adding a --introspect option to bootstrap studio without an existing schema.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jiasheng-proxy

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

CopilotAI left a comment

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.

Pull request overview

This PR adds an --introspect option to the CLI’s Studio/proxy command flow to bootstrap a project when no ZModel schema file is present, including auto-installing the correct DB driver and generating a schema via the existing pull/introspection pipeline.

Changes:

  • Adds --introspect flag to the CLI command definition and routes schema resolution through a new resolveSchema helper.
  • Introduces shared optional-dependency helpers (isPackageInstalled, loadPackage) and uses them across DB introspection providers and proxy dialect creation.
  • Extends runPull to accept explicit provider/databaseUrl overrides to support schema generation from an introspected database.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
FileDescription
packages/cli/src/index.tsAdds the --introspect CLI option to the command.
packages/cli/src/actions/proxy.tsImplements --introspect schema resolution, driver installation, schema generation, and generation follow-up.
packages/cli/src/actions/db.tsExports runPull and allows provider/URL overrides for introspection-driven generation.
packages/cli/src/actions/action-utils.tsAdds isPackageInstalled and loadPackage helpers for optional dependency loading.
packages/cli/src/actions/pull/provider/sqlite.tsSwitches SQLite introspection to loadPackage and adds file URL handling.
packages/cli/src/actions/pull/provider/postgresql.tsSwitches PostgreSQL introspection to loadPackage.
packages/cli/src/actions/pull/provider/mysql.tsSwitches MySQL introspection to loadPackage.
packages/cli/test/proxy.test.tsAdds unit tests for getProviderFromUrl and resolveSchema behaviors.
packages/cli/test/action-utils.test.tsAdds tests for isPackageInstalled and loadPackage.
Comments suppressed due to low confidence (1)

packages/cli/test/proxy.test.ts:862

  • This assertion looks for zen studio --introspect, but resolveSchema emits npx @zenstackhq/cli studio --introspect .... Using studio --introspect as the substring match should make the test align with the actual message formatting.
 ).rejects.toThrow('zen studio --introspect');

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment threadpackages/cli/src/actions/pull/provider/postgresql.ts
Comment threadpackages/cli/src/actions/pull/provider/sqlite.ts Outdated
Comment threadpackages/cli/test/proxy.test.ts Outdated
Comment threadpackages/cli/src/actions/proxy.ts Outdated

@coderabbitaicoderabbitaiBot left a comment

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.

Actionable comments posted: 8

🧹 Nitpick comments (1)
packages/cli/src/actions/action-utils.ts (1)

386-415: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract shared createRequire(package.json) logic.

The same createRequire(path.resolve(process.cwd(), 'package.json')) pattern is repeated 3 times across isPackageInstalled and loadPackage. A small shared helper (getProjectRequire()) would reduce duplication and keep the two functions in sync if the resolution base ever changes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/cli/src/actions/action-utils.ts` around lines 386 - 415, Extract the
repeated createRequire(path.resolve(process.cwd(), 'package.json')) construction
into a shared getProjectRequire() helper. Update isPackageInstalled and both
fallback branches in loadPackage to reuse this helper, preserving their existing
resolution and error-handling behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/cli/src/actions/action-utils.ts`:
- Around line 396-415: Update loadPackage so it preserves and propagates the
underlying error when the package cannot be loaded, rather than returning null
after all import and require fallbacks fail. Track the original and fallback
failures through the nested dynamic import, projectRequire.resolve, and
projectRequire calls, then throw a diagnostic error that retains the relevant
cause for callers such as createDialect and the database providers.
In `@packages/cli/src/actions/db.ts`:
- Around line 38-39: Add a warning in the introspection flow when the resulting
tables and enums are both empty, regardless of provider or schema selection.
Update the logic around allSchemas and the PostgreSQL introspect result so the
warning clearly indicates that no database objects were found, while preserving
successful empty-result behavior.
In `@packages/cli/src/actions/proxy.ts`:
- Around line 517-530: Restrict the existing default-schema fallback around
getSchemaFile to cases where options.schema was not explicitly provided. When an
explicit --schema path fails, propagate the original CliError instead of
returning zenstack/schema.zmodel; preserve the fallback for missing schemas in
default locations.
- Around line 619-649: Update introspectAndGenerateSchema so the generated
datasource always references env("DATABASE_URL") instead of embedding
databaseUrl when urlFromEnv is false. Preserve the existing provider and runPull
behavior, and ensure the literal connection string is never written to
schema.zmodel.
- Around line 542-544: Update the runGenerate invocation in the introspection
flow to pass options.output as the code generation output path. Preserve the
existing schema, silent, and watch arguments so generated files and subsequent
imports use the same custom output directory resolved by resolveSchema().
In `@packages/cli/src/actions/pull/provider/sqlite.ts`:
- Around line 144-151: Align SQLite relative file URL resolution between the
introspection path and createDialect. Update the resolution logic surrounding
the SQLite constructor and createDialect’s SQLite branch to use the same base
directory, preserving identical database targeting for the --introspect
bootstrap flow; prefer the existing shared resolution behavior rather than
introducing divergent path handling.
In `@packages/cli/test/action-utils.test.ts`:
- Around line 60-62: Update the successful-load test around loadPackage to
assert that the returned module is not null, replacing the insufficient
toBeDefined assertion. Keep the test focused on rejecting loadPackage’s
documented null failure result.
In `@packages/cli/test/proxy.test.ts`:
- Around line 836-846: Update the expected error substrings in the tests around
resolveSchema to match its actual command text: assert the npx `@zenstackhq/cli`
studio prefix and the -d <databaseUrl> placeholder. Apply the same correction to
both affected assertions while preserving the existing test setup and
error-checking behavior.
---
Nitpick comments:
In `@packages/cli/src/actions/action-utils.ts`:
- Around line 386-415: Extract the repeated
createRequire(path.resolve(process.cwd(), 'package.json')) construction into a
shared getProjectRequire() helper. Update isPackageInstalled and both fallback
branches in loadPackage to reuse this helper, preserving their existing
resolution and error-handling behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 312bca78-7c2c-4751-8fea-9074176dca5b

📥 Commits

Reviewing files that changed from the base of the PR and between 78e741e and bd12232.

📒 Files selected for processing (9)
  • packages/cli/src/actions/action-utils.ts
  • packages/cli/src/actions/db.ts
  • packages/cli/src/actions/proxy.ts
  • packages/cli/src/actions/pull/provider/mysql.ts
  • packages/cli/src/actions/pull/provider/postgresql.ts
  • packages/cli/src/actions/pull/provider/sqlite.ts
  • packages/cli/src/index.ts
  • packages/cli/test/action-utils.test.ts
  • packages/cli/test/proxy.test.ts

Comment threadpackages/cli/src/actions/action-utils.ts
Comment threadpackages/cli/src/actions/db.ts
Comment threadpackages/cli/src/actions/proxy.ts Outdated
Comment threadpackages/cli/src/actions/proxy.ts
Comment threadpackages/cli/src/actions/proxy.ts
Comment threadpackages/cli/src/actions/pull/provider/sqlite.ts Outdated
Comment threadpackages/cli/test/action-utils.test.ts
Comment threadpackages/cli/test/proxy.test.ts Outdated

@coderabbitaicoderabbitaiBot left a comment

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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/cli/src/actions/pull/provider/sqlite.ts (1)

131-143: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

SQLite file:/sqlite: scheme stripping is now split across files and only partially implemented. The root cause: sqlite.ts's introspect() used to normalize file:-prefixed connection strings itself; that logic was removed and only partially reimplemented in db.ts's runPull, covering just the file: prefix and only the explicit --introspect override path.

  • packages/cli/src/actions/pull/provider/sqlite.ts#L131-L143: reinstate scheme stripping (file:/sqlite: → raw path) directly before new SQLite(connectionString, ...) as a defensive last line of normalization, since callers cannot be relied upon to always pre-resolve the URL.
  • packages/cli/src/actions/db.ts#L137-L149: extend the existing databaseUrl.startsWith('file:') branch to also cover sqlite:, and consider applying equivalent normalization in the non-override getDatasource(model) branch too, since the documented ZenStack SQLite format (url = 'file:./dev.db') needs the same treatment there.
  • packages/cli/src/actions/proxy.ts#L607-L631: either confirm sqlite: is a genuinely supported input format and ensure runPull/introspect() honor it end-to-end, or drop the sqlite: branch here if it's dead/speculative handling.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/cli/src/actions/pull/provider/sqlite.ts` around lines 131 - 143,
Normalize SQLite connection schemes consistently: in
packages/cli/src/actions/pull/provider/sqlite.ts lines 131-143, strip file: and
sqlite: immediately before new SQLite in introspect(); in
packages/cli/src/actions/db.ts lines 137-149, extend runPull’s normalization to
sqlite: and apply equivalent handling in the non-override getDatasource(model)
path; in packages/cli/src/actions/proxy.ts lines 607-631, verify sqlite: is
supported end-to-end and retain the branch only if runPull and introspect honor
it, otherwise remove it.
packages/cli/src/actions/proxy.ts (1)

209-230: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Use the schema directory as the SQLite URL base when the path is relative.

outputPath resolves to zenstack/ with getOutputPath(), so relative SQLite URLs like file:database.sqlite, file:./database.sqlite, or sqlite:database.sqlite are incorrectly resolved from the cwd (/app/database.sqlite) while the generated datasource.url preserves them as relative to zenstack/ (/app/database.sqlite from zenstack/schema.zmodel) or intentionally up one level. Resolve file:/sqlite: relative URLs against path.resolve('zenstack'), not by joining with outputPath.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/cli/src/actions/proxy.ts` around lines 209 - 230, Update
createDialect’s SQLite URL resolution to use path.resolve('zenstack') as the
base for relative file: and sqlite: URLs, preserving intentional relative paths
such as ./ and ../. Do not use outputPath as the URL base; retain absolute URL
handling and Windows normalization.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@packages/cli/src/actions/proxy.ts`:
- Around line 209-230: Update createDialect’s SQLite URL resolution to use
path.resolve('zenstack') as the base for relative file: and sqlite: URLs,
preserving intentional relative paths such as ./ and ../. Do not use outputPath
as the URL base; retain absolute URL handling and Windows normalization.
In `@packages/cli/src/actions/pull/provider/sqlite.ts`:
- Around line 131-143: Normalize SQLite connection schemes consistently: in
packages/cli/src/actions/pull/provider/sqlite.ts lines 131-143, strip file: and
sqlite: immediately before new SQLite in introspect(); in
packages/cli/src/actions/db.ts lines 137-149, extend runPull’s normalization to
sqlite: and apply equivalent handling in the non-override getDatasource(model)
path; in packages/cli/src/actions/proxy.ts lines 607-631, verify sqlite: is
supported end-to-end and retain the branch only if runPull and introspect honor
it, otherwise remove it.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 98c2175a-b357-4c8e-8bfe-ec5f3d6a9336

📥 Commits

Reviewing files that changed from the base of the PR and between 844e92c and 0a25e4b.

📒 Files selected for processing (5)
  • packages/cli/src/actions/action-utils.ts
  • packages/cli/src/actions/db.ts
  • packages/cli/src/actions/proxy.ts
  • packages/cli/src/actions/pull/provider/sqlite.ts
  • packages/cli/test/proxy.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/cli/src/actions/action-utils.ts

@coderabbitaicoderabbitaiBot left a comment

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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/cli/src/actions/pull/provider/sqlite.ts`:
- Line 361: Update the column nullability mapping around the `nullable` property
to preserve SQLite’s explicit `c.notnull` value instead of treating every
primary-key column as non-nullable. Only override nullability when the table
schema confirms SQLite enforces it, such as an `INTEGER PRIMARY KEY` rowid alias
or applicable `WITHOUT ROWID`/strict tables, and add regression coverage for
TEXT and composite primary keys.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: cf8d702a-03ad-4664-9471-f6e37904c166

📥 Commits

Reviewing files that changed from the base of the PR and between 0a25e4b and e7c4a29.

📒 Files selected for processing (1)
  • packages/cli/src/actions/pull/provider/sqlite.ts

Comment threadpackages/cli/src/actions/pull/provider/sqlite.ts Outdated
Comment threadpackages/cli/src/actions/proxy.ts Outdated
Comment threadpackages/cli/src/actions/action-utils.ts Outdated
@jiashengguo
jiashengguo merged commit 2d239cd into devAug 3, 2026
10 checks passed
@jiashengguo
jiashengguo deleted the jiasheng-proxy branch August 3, 2026 06:23
@coderabbitaicoderabbitaiBot mentioned this pull request Aug 3, 2026
Sign up for freeto 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

@jiashengguo@ymc9
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(cli): add --introspect option for studio command for bootstrapping without schema - #2775

Merged
jiashengguo merged 10 commits into
devfrom
jiasheng-proxy
Aug 3, 2026
Merged

feat(cli): add --introspect option for studio command for bootstrapping without schema #2775
jiashengguo merged 10 commits into
devfrom
jiasheng-proxy

Conversation

@jiashengguo

@jiashengguojiashengguo commented Jul 29, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • New Features

    • Added an --introspect option to generate a schema from your database when no schema file is available.
  • Enhancements

    • Improved schema resolution flows for --introspect vs missing schema, including smarter DATABASE_URL handling for SQLite (relative file: rewriting).
    • Enhanced database pulls with explicit --provider and --database-url support (including improved SQLite path normalization).
    • Improved automatic driver/provider loading and clearer guidance when required drivers aren’t installed.
  • Bug Fixes

    • Corrected SQLite nullability handling for primary key columns during introspection.
  • Tests

    • Expanded coverage for schema resolution and driver/module loading behaviors.

@jiashengguo
jiashengguo requested a review from CopilotJuly 29, 2026 13:35
@coderabbitai

coderabbitaiBot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The CLI adds project-aware database driver loading and an optional --introspect proxy flow that generates a schema from a database URL. runPull accepts explicit datasource overrides, with tests covering provider detection, schema resolution, SQLite URL rewriting, and package loading.

Changes

CLI introspection flow

Layer / File(s)Summary
Package-aware driver loading
packages/cli/src/actions/action-utils.ts, packages/cli/src/actions/proxy.ts, packages/cli/src/actions/pull/provider/*
Adds package resolution fallbacks and uses them to load SQLite, PostgreSQL, and MySQL drivers, with explicit missing-driver errors.
Pull datasource overrides
packages/cli/src/actions/db.ts
Exports runPull and accepts provider and database URL overrides, including SQLite URL normalization.
Proxy schema introspection
packages/cli/src/actions/proxy.ts, packages/cli/src/index.ts
Adds --introspect, provider detection, driver installation, schema generation, SQLite URL adjustment, and schema resolution branching.
Introspection validation
packages/cli/test/action-utils.test.ts, packages/cli/test/proxy.test.ts
Tests package loading, provider URL mapping, schema-resolution errors, default schema handling, and relative SQLite URLs.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

  • zenstackhq/zenstack#2761: Both changes modify runPull relation and schema synchronization logic in packages/cli/src/actions/db.ts.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title accurately describes the main user-facing change: adding a --introspect option to bootstrap studio without an existing schema.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jiasheng-proxy

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

CopilotAI left a comment

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.

Pull request overview

This PR adds an --introspect option to the CLI’s Studio/proxy command flow to bootstrap a project when no ZModel schema file is present, including auto-installing the correct DB driver and generating a schema via the existing pull/introspection pipeline.

Changes:

  • Adds --introspect flag to the CLI command definition and routes schema resolution through a new resolveSchema helper.
  • Introduces shared optional-dependency helpers (isPackageInstalled, loadPackage) and uses them across DB introspection providers and proxy dialect creation.
  • Extends runPull to accept explicit provider/databaseUrl overrides to support schema generation from an introspected database.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
FileDescription
packages/cli/src/index.tsAdds the --introspect CLI option to the command.
packages/cli/src/actions/proxy.tsImplements --introspect schema resolution, driver installation, schema generation, and generation follow-up.
packages/cli/src/actions/db.tsExports runPull and allows provider/URL overrides for introspection-driven generation.
packages/cli/src/actions/action-utils.tsAdds isPackageInstalled and loadPackage helpers for optional dependency loading.
packages/cli/src/actions/pull/provider/sqlite.tsSwitches SQLite introspection to loadPackage and adds file URL handling.
packages/cli/src/actions/pull/provider/postgresql.tsSwitches PostgreSQL introspection to loadPackage.
packages/cli/src/actions/pull/provider/mysql.tsSwitches MySQL introspection to loadPackage.
packages/cli/test/proxy.test.tsAdds unit tests for getProviderFromUrl and resolveSchema behaviors.
packages/cli/test/action-utils.test.tsAdds tests for isPackageInstalled and loadPackage.
Comments suppressed due to low confidence (1)

packages/cli/test/proxy.test.ts:862

  • This assertion looks for zen studio --introspect, but resolveSchema emits npx @zenstackhq/cli studio --introspect .... Using studio --introspect as the substring match should make the test align with the actual message formatting.
 ).rejects.toThrow('zen studio --introspect');

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment threadpackages/cli/src/actions/pull/provider/postgresql.ts
Comment threadpackages/cli/src/actions/pull/provider/sqlite.ts Outdated
Comment threadpackages/cli/test/proxy.test.ts Outdated
Comment threadpackages/cli/src/actions/proxy.ts Outdated

@coderabbitaicoderabbitaiBot left a comment

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.

Actionable comments posted: 8

🧹 Nitpick comments (1)
packages/cli/src/actions/action-utils.ts (1)

386-415: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract shared createRequire(package.json) logic.

The same createRequire(path.resolve(process.cwd(), 'package.json')) pattern is repeated 3 times across isPackageInstalled and loadPackage. A small shared helper (getProjectRequire()) would reduce duplication and keep the two functions in sync if the resolution base ever changes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/cli/src/actions/action-utils.ts` around lines 386 - 415, Extract the
repeated createRequire(path.resolve(process.cwd(), 'package.json')) construction
into a shared getProjectRequire() helper. Update isPackageInstalled and both
fallback branches in loadPackage to reuse this helper, preserving their existing
resolution and error-handling behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/cli/src/actions/action-utils.ts`:
- Around line 396-415: Update loadPackage so it preserves and propagates the
underlying error when the package cannot be loaded, rather than returning null
after all import and require fallbacks fail. Track the original and fallback
failures through the nested dynamic import, projectRequire.resolve, and
projectRequire calls, then throw a diagnostic error that retains the relevant
cause for callers such as createDialect and the database providers.
In `@packages/cli/src/actions/db.ts`:
- Around line 38-39: Add a warning in the introspection flow when the resulting
tables and enums are both empty, regardless of provider or schema selection.
Update the logic around allSchemas and the PostgreSQL introspect result so the
warning clearly indicates that no database objects were found, while preserving
successful empty-result behavior.
In `@packages/cli/src/actions/proxy.ts`:
- Around line 517-530: Restrict the existing default-schema fallback around
getSchemaFile to cases where options.schema was not explicitly provided. When an
explicit --schema path fails, propagate the original CliError instead of
returning zenstack/schema.zmodel; preserve the fallback for missing schemas in
default locations.
- Around line 619-649: Update introspectAndGenerateSchema so the generated
datasource always references env("DATABASE_URL") instead of embedding
databaseUrl when urlFromEnv is false. Preserve the existing provider and runPull
behavior, and ensure the literal connection string is never written to
schema.zmodel.
- Around line 542-544: Update the runGenerate invocation in the introspection
flow to pass options.output as the code generation output path. Preserve the
existing schema, silent, and watch arguments so generated files and subsequent
imports use the same custom output directory resolved by resolveSchema().
In `@packages/cli/src/actions/pull/provider/sqlite.ts`:
- Around line 144-151: Align SQLite relative file URL resolution between the
introspection path and createDialect. Update the resolution logic surrounding
the SQLite constructor and createDialect’s SQLite branch to use the same base
directory, preserving identical database targeting for the --introspect
bootstrap flow; prefer the existing shared resolution behavior rather than
introducing divergent path handling.
In `@packages/cli/test/action-utils.test.ts`:
- Around line 60-62: Update the successful-load test around loadPackage to
assert that the returned module is not null, replacing the insufficient
toBeDefined assertion. Keep the test focused on rejecting loadPackage’s
documented null failure result.
In `@packages/cli/test/proxy.test.ts`:
- Around line 836-846: Update the expected error substrings in the tests around
resolveSchema to match its actual command text: assert the npx `@zenstackhq/cli`
studio prefix and the -d <databaseUrl> placeholder. Apply the same correction to
both affected assertions while preserving the existing test setup and
error-checking behavior.
---
Nitpick comments:
In `@packages/cli/src/actions/action-utils.ts`:
- Around line 386-415: Extract the repeated
createRequire(path.resolve(process.cwd(), 'package.json')) construction into a
shared getProjectRequire() helper. Update isPackageInstalled and both fallback
branches in loadPackage to reuse this helper, preserving their existing
resolution and error-handling behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 312bca78-7c2c-4751-8fea-9074176dca5b

📥 Commits

Reviewing files that changed from the base of the PR and between 78e741e and bd12232.

📒 Files selected for processing (9)
  • packages/cli/src/actions/action-utils.ts
  • packages/cli/src/actions/db.ts
  • packages/cli/src/actions/proxy.ts
  • packages/cli/src/actions/pull/provider/mysql.ts
  • packages/cli/src/actions/pull/provider/postgresql.ts
  • packages/cli/src/actions/pull/provider/sqlite.ts
  • packages/cli/src/index.ts
  • packages/cli/test/action-utils.test.ts
  • packages/cli/test/proxy.test.ts

Comment threadpackages/cli/src/actions/action-utils.ts
Comment threadpackages/cli/src/actions/db.ts
Comment threadpackages/cli/src/actions/proxy.ts Outdated
Comment threadpackages/cli/src/actions/proxy.ts
Comment threadpackages/cli/src/actions/proxy.ts
Comment threadpackages/cli/src/actions/pull/provider/sqlite.ts Outdated
Comment threadpackages/cli/test/action-utils.test.ts
Comment threadpackages/cli/test/proxy.test.ts Outdated

@coderabbitaicoderabbitaiBot left a comment

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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/cli/src/actions/pull/provider/sqlite.ts (1)

131-143: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

SQLite file:/sqlite: scheme stripping is now split across files and only partially implemented. The root cause: sqlite.ts's introspect() used to normalize file:-prefixed connection strings itself; that logic was removed and only partially reimplemented in db.ts's runPull, covering just the file: prefix and only the explicit --introspect override path.

  • packages/cli/src/actions/pull/provider/sqlite.ts#L131-L143: reinstate scheme stripping (file:/sqlite: → raw path) directly before new SQLite(connectionString, ...) as a defensive last line of normalization, since callers cannot be relied upon to always pre-resolve the URL.
  • packages/cli/src/actions/db.ts#L137-L149: extend the existing databaseUrl.startsWith('file:') branch to also cover sqlite:, and consider applying equivalent normalization in the non-override getDatasource(model) branch too, since the documented ZenStack SQLite format (url = 'file:./dev.db') needs the same treatment there.
  • packages/cli/src/actions/proxy.ts#L607-L631: either confirm sqlite: is a genuinely supported input format and ensure runPull/introspect() honor it end-to-end, or drop the sqlite: branch here if it's dead/speculative handling.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/cli/src/actions/pull/provider/sqlite.ts` around lines 131 - 143,
Normalize SQLite connection schemes consistently: in
packages/cli/src/actions/pull/provider/sqlite.ts lines 131-143, strip file: and
sqlite: immediately before new SQLite in introspect(); in
packages/cli/src/actions/db.ts lines 137-149, extend runPull’s normalization to
sqlite: and apply equivalent handling in the non-override getDatasource(model)
path; in packages/cli/src/actions/proxy.ts lines 607-631, verify sqlite: is
supported end-to-end and retain the branch only if runPull and introspect honor
it, otherwise remove it.
packages/cli/src/actions/proxy.ts (1)

209-230: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Use the schema directory as the SQLite URL base when the path is relative.

outputPath resolves to zenstack/ with getOutputPath(), so relative SQLite URLs like file:database.sqlite, file:./database.sqlite, or sqlite:database.sqlite are incorrectly resolved from the cwd (/app/database.sqlite) while the generated datasource.url preserves them as relative to zenstack/ (/app/database.sqlite from zenstack/schema.zmodel) or intentionally up one level. Resolve file:/sqlite: relative URLs against path.resolve('zenstack'), not by joining with outputPath.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/cli/src/actions/proxy.ts` around lines 209 - 230, Update
createDialect’s SQLite URL resolution to use path.resolve('zenstack') as the
base for relative file: and sqlite: URLs, preserving intentional relative paths
such as ./ and ../. Do not use outputPath as the URL base; retain absolute URL
handling and Windows normalization.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@packages/cli/src/actions/proxy.ts`:
- Around line 209-230: Update createDialect’s SQLite URL resolution to use
path.resolve('zenstack') as the base for relative file: and sqlite: URLs,
preserving intentional relative paths such as ./ and ../. Do not use outputPath
as the URL base; retain absolute URL handling and Windows normalization.
In `@packages/cli/src/actions/pull/provider/sqlite.ts`:
- Around line 131-143: Normalize SQLite connection schemes consistently: in
packages/cli/src/actions/pull/provider/sqlite.ts lines 131-143, strip file: and
sqlite: immediately before new SQLite in introspect(); in
packages/cli/src/actions/db.ts lines 137-149, extend runPull’s normalization to
sqlite: and apply equivalent handling in the non-override getDatasource(model)
path; in packages/cli/src/actions/proxy.ts lines 607-631, verify sqlite: is
supported end-to-end and retain the branch only if runPull and introspect honor
it, otherwise remove it.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 98c2175a-b357-4c8e-8bfe-ec5f3d6a9336

📥 Commits

Reviewing files that changed from the base of the PR and between 844e92c and 0a25e4b.

📒 Files selected for processing (5)
  • packages/cli/src/actions/action-utils.ts
  • packages/cli/src/actions/db.ts
  • packages/cli/src/actions/proxy.ts
  • packages/cli/src/actions/pull/provider/sqlite.ts
  • packages/cli/test/proxy.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/cli/src/actions/action-utils.ts

@coderabbitaicoderabbitaiBot left a comment

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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/cli/src/actions/pull/provider/sqlite.ts`:
- Line 361: Update the column nullability mapping around the `nullable` property
to preserve SQLite’s explicit `c.notnull` value instead of treating every
primary-key column as non-nullable. Only override nullability when the table
schema confirms SQLite enforces it, such as an `INTEGER PRIMARY KEY` rowid alias
or applicable `WITHOUT ROWID`/strict tables, and add regression coverage for
TEXT and composite primary keys.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: cf8d702a-03ad-4664-9471-f6e37904c166

📥 Commits

Reviewing files that changed from the base of the PR and between 0a25e4b and e7c4a29.

📒 Files selected for processing (1)
  • packages/cli/src/actions/pull/provider/sqlite.ts

Comment threadpackages/cli/src/actions/pull/provider/sqlite.ts Outdated
Comment threadpackages/cli/src/actions/proxy.ts Outdated
Comment threadpackages/cli/src/actions/action-utils.ts Outdated
@jiashengguo
jiashengguo merged commit 2d239cd into devAug 3, 2026
10 checks passed
@jiashengguo
jiashengguo deleted the jiasheng-proxy branch August 3, 2026 06:23
@coderabbitaicoderabbitaiBot mentioned this pull request Aug 3, 2026
Sign up for freeto 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

@jiashengguo@ymc9
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(cli): add --introspect option for studio command for bootstrapping without schema - #2775

Merged
jiashengguo merged 10 commits into
devfrom
jiasheng-proxy
Aug 3, 2026
Merged

feat(cli): add --introspect option for studio command for bootstrapping without schema #2775
jiashengguo merged 10 commits into
devfrom
jiasheng-proxy

Conversation

@jiashengguo

@jiashengguojiashengguo commented Jul 29, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • New Features

    • Added an --introspect option to generate a schema from your database when no schema file is available.
  • Enhancements

    • Improved schema resolution flows for --introspect vs missing schema, including smarter DATABASE_URL handling for SQLite (relative file: rewriting).
    • Enhanced database pulls with explicit --provider and --database-url support (including improved SQLite path normalization).
    • Improved automatic driver/provider loading and clearer guidance when required drivers aren’t installed.
  • Bug Fixes

    • Corrected SQLite nullability handling for primary key columns during introspection.
  • Tests

    • Expanded coverage for schema resolution and driver/module loading behaviors.

@jiashengguo
jiashengguo requested a review from CopilotJuly 29, 2026 13:35
@coderabbitai

coderabbitaiBot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The CLI adds project-aware database driver loading and an optional --introspect proxy flow that generates a schema from a database URL. runPull accepts explicit datasource overrides, with tests covering provider detection, schema resolution, SQLite URL rewriting, and package loading.

Changes

CLI introspection flow

Layer / File(s)Summary
Package-aware driver loading
packages/cli/src/actions/action-utils.ts, packages/cli/src/actions/proxy.ts, packages/cli/src/actions/pull/provider/*
Adds package resolution fallbacks and uses them to load SQLite, PostgreSQL, and MySQL drivers, with explicit missing-driver errors.
Pull datasource overrides
packages/cli/src/actions/db.ts
Exports runPull and accepts provider and database URL overrides, including SQLite URL normalization.
Proxy schema introspection
packages/cli/src/actions/proxy.ts, packages/cli/src/index.ts
Adds --introspect, provider detection, driver installation, schema generation, SQLite URL adjustment, and schema resolution branching.
Introspection validation
packages/cli/test/action-utils.test.ts, packages/cli/test/proxy.test.ts
Tests package loading, provider URL mapping, schema-resolution errors, default schema handling, and relative SQLite URLs.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

  • zenstackhq/zenstack#2761: Both changes modify runPull relation and schema synchronization logic in packages/cli/src/actions/db.ts.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title accurately describes the main user-facing change: adding a --introspect option to bootstrap studio without an existing schema.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jiasheng-proxy

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

CopilotAI left a comment

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.

Pull request overview

This PR adds an --introspect option to the CLI’s Studio/proxy command flow to bootstrap a project when no ZModel schema file is present, including auto-installing the correct DB driver and generating a schema via the existing pull/introspection pipeline.

Changes:

  • Adds --introspect flag to the CLI command definition and routes schema resolution through a new resolveSchema helper.
  • Introduces shared optional-dependency helpers (isPackageInstalled, loadPackage) and uses them across DB introspection providers and proxy dialect creation.
  • Extends runPull to accept explicit provider/databaseUrl overrides to support schema generation from an introspected database.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
FileDescription
packages/cli/src/index.tsAdds the --introspect CLI option to the command.
packages/cli/src/actions/proxy.tsImplements --introspect schema resolution, driver installation, schema generation, and generation follow-up.
packages/cli/src/actions/db.tsExports runPull and allows provider/URL overrides for introspection-driven generation.
packages/cli/src/actions/action-utils.tsAdds isPackageInstalled and loadPackage helpers for optional dependency loading.
packages/cli/src/actions/pull/provider/sqlite.tsSwitches SQLite introspection to loadPackage and adds file URL handling.
packages/cli/src/actions/pull/provider/postgresql.tsSwitches PostgreSQL introspection to loadPackage.
packages/cli/src/actions/pull/provider/mysql.tsSwitches MySQL introspection to loadPackage.
packages/cli/test/proxy.test.tsAdds unit tests for getProviderFromUrl and resolveSchema behaviors.
packages/cli/test/action-utils.test.tsAdds tests for isPackageInstalled and loadPackage.
Comments suppressed due to low confidence (1)

packages/cli/test/proxy.test.ts:862

  • This assertion looks for zen studio --introspect, but resolveSchema emits npx @zenstackhq/cli studio --introspect .... Using studio --introspect as the substring match should make the test align with the actual message formatting.
 ).rejects.toThrow('zen studio --introspect');

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment threadpackages/cli/src/actions/pull/provider/postgresql.ts
Comment threadpackages/cli/src/actions/pull/provider/sqlite.ts Outdated
Comment threadpackages/cli/test/proxy.test.ts Outdated
Comment threadpackages/cli/src/actions/proxy.ts Outdated

@coderabbitaicoderabbitaiBot left a comment

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.

Actionable comments posted: 8

🧹 Nitpick comments (1)
packages/cli/src/actions/action-utils.ts (1)

386-415: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract shared createRequire(package.json) logic.

The same createRequire(path.resolve(process.cwd(), 'package.json')) pattern is repeated 3 times across isPackageInstalled and loadPackage. A small shared helper (getProjectRequire()) would reduce duplication and keep the two functions in sync if the resolution base ever changes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/cli/src/actions/action-utils.ts` around lines 386 - 415, Extract the
repeated createRequire(path.resolve(process.cwd(), 'package.json')) construction
into a shared getProjectRequire() helper. Update isPackageInstalled and both
fallback branches in loadPackage to reuse this helper, preserving their existing
resolution and error-handling behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/cli/src/actions/action-utils.ts`:
- Around line 396-415: Update loadPackage so it preserves and propagates the
underlying error when the package cannot be loaded, rather than returning null
after all import and require fallbacks fail. Track the original and fallback
failures through the nested dynamic import, projectRequire.resolve, and
projectRequire calls, then throw a diagnostic error that retains the relevant
cause for callers such as createDialect and the database providers.
In `@packages/cli/src/actions/db.ts`:
- Around line 38-39: Add a warning in the introspection flow when the resulting
tables and enums are both empty, regardless of provider or schema selection.
Update the logic around allSchemas and the PostgreSQL introspect result so the
warning clearly indicates that no database objects were found, while preserving
successful empty-result behavior.
In `@packages/cli/src/actions/proxy.ts`:
- Around line 517-530: Restrict the existing default-schema fallback around
getSchemaFile to cases where options.schema was not explicitly provided. When an
explicit --schema path fails, propagate the original CliError instead of
returning zenstack/schema.zmodel; preserve the fallback for missing schemas in
default locations.
- Around line 619-649: Update introspectAndGenerateSchema so the generated
datasource always references env("DATABASE_URL") instead of embedding
databaseUrl when urlFromEnv is false. Preserve the existing provider and runPull
behavior, and ensure the literal connection string is never written to
schema.zmodel.
- Around line 542-544: Update the runGenerate invocation in the introspection
flow to pass options.output as the code generation output path. Preserve the
existing schema, silent, and watch arguments so generated files and subsequent
imports use the same custom output directory resolved by resolveSchema().
In `@packages/cli/src/actions/pull/provider/sqlite.ts`:
- Around line 144-151: Align SQLite relative file URL resolution between the
introspection path and createDialect. Update the resolution logic surrounding
the SQLite constructor and createDialect’s SQLite branch to use the same base
directory, preserving identical database targeting for the --introspect
bootstrap flow; prefer the existing shared resolution behavior rather than
introducing divergent path handling.
In `@packages/cli/test/action-utils.test.ts`:
- Around line 60-62: Update the successful-load test around loadPackage to
assert that the returned module is not null, replacing the insufficient
toBeDefined assertion. Keep the test focused on rejecting loadPackage’s
documented null failure result.
In `@packages/cli/test/proxy.test.ts`:
- Around line 836-846: Update the expected error substrings in the tests around
resolveSchema to match its actual command text: assert the npx `@zenstackhq/cli`
studio prefix and the -d <databaseUrl> placeholder. Apply the same correction to
both affected assertions while preserving the existing test setup and
error-checking behavior.
---
Nitpick comments:
In `@packages/cli/src/actions/action-utils.ts`:
- Around line 386-415: Extract the repeated
createRequire(path.resolve(process.cwd(), 'package.json')) construction into a
shared getProjectRequire() helper. Update isPackageInstalled and both fallback
branches in loadPackage to reuse this helper, preserving their existing
resolution and error-handling behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 312bca78-7c2c-4751-8fea-9074176dca5b

📥 Commits

Reviewing files that changed from the base of the PR and between 78e741e and bd12232.

📒 Files selected for processing (9)
  • packages/cli/src/actions/action-utils.ts
  • packages/cli/src/actions/db.ts
  • packages/cli/src/actions/proxy.ts
  • packages/cli/src/actions/pull/provider/mysql.ts
  • packages/cli/src/actions/pull/provider/postgresql.ts
  • packages/cli/src/actions/pull/provider/sqlite.ts
  • packages/cli/src/index.ts
  • packages/cli/test/action-utils.test.ts
  • packages/cli/test/proxy.test.ts

Comment threadpackages/cli/src/actions/action-utils.ts
Comment threadpackages/cli/src/actions/db.ts
Comment threadpackages/cli/src/actions/proxy.ts Outdated
Comment threadpackages/cli/src/actions/proxy.ts
Comment threadpackages/cli/src/actions/proxy.ts
Comment threadpackages/cli/src/actions/pull/provider/sqlite.ts Outdated
Comment threadpackages/cli/test/action-utils.test.ts
Comment threadpackages/cli/test/proxy.test.ts Outdated

@coderabbitaicoderabbitaiBot left a comment

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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/cli/src/actions/pull/provider/sqlite.ts (1)

131-143: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

SQLite file:/sqlite: scheme stripping is now split across files and only partially implemented. The root cause: sqlite.ts's introspect() used to normalize file:-prefixed connection strings itself; that logic was removed and only partially reimplemented in db.ts's runPull, covering just the file: prefix and only the explicit --introspect override path.

  • packages/cli/src/actions/pull/provider/sqlite.ts#L131-L143: reinstate scheme stripping (file:/sqlite: → raw path) directly before new SQLite(connectionString, ...) as a defensive last line of normalization, since callers cannot be relied upon to always pre-resolve the URL.
  • packages/cli/src/actions/db.ts#L137-L149: extend the existing databaseUrl.startsWith('file:') branch to also cover sqlite:, and consider applying equivalent normalization in the non-override getDatasource(model) branch too, since the documented ZenStack SQLite format (url = 'file:./dev.db') needs the same treatment there.
  • packages/cli/src/actions/proxy.ts#L607-L631: either confirm sqlite: is a genuinely supported input format and ensure runPull/introspect() honor it end-to-end, or drop the sqlite: branch here if it's dead/speculative handling.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/cli/src/actions/pull/provider/sqlite.ts` around lines 131 - 143,
Normalize SQLite connection schemes consistently: in
packages/cli/src/actions/pull/provider/sqlite.ts lines 131-143, strip file: and
sqlite: immediately before new SQLite in introspect(); in
packages/cli/src/actions/db.ts lines 137-149, extend runPull’s normalization to
sqlite: and apply equivalent handling in the non-override getDatasource(model)
path; in packages/cli/src/actions/proxy.ts lines 607-631, verify sqlite: is
supported end-to-end and retain the branch only if runPull and introspect honor
it, otherwise remove it.
packages/cli/src/actions/proxy.ts (1)

209-230: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Use the schema directory as the SQLite URL base when the path is relative.

outputPath resolves to zenstack/ with getOutputPath(), so relative SQLite URLs like file:database.sqlite, file:./database.sqlite, or sqlite:database.sqlite are incorrectly resolved from the cwd (/app/database.sqlite) while the generated datasource.url preserves them as relative to zenstack/ (/app/database.sqlite from zenstack/schema.zmodel) or intentionally up one level. Resolve file:/sqlite: relative URLs against path.resolve('zenstack'), not by joining with outputPath.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/cli/src/actions/proxy.ts` around lines 209 - 230, Update
createDialect’s SQLite URL resolution to use path.resolve('zenstack') as the
base for relative file: and sqlite: URLs, preserving intentional relative paths
such as ./ and ../. Do not use outputPath as the URL base; retain absolute URL
handling and Windows normalization.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@packages/cli/src/actions/proxy.ts`:
- Around line 209-230: Update createDialect’s SQLite URL resolution to use
path.resolve('zenstack') as the base for relative file: and sqlite: URLs,
preserving intentional relative paths such as ./ and ../. Do not use outputPath
as the URL base; retain absolute URL handling and Windows normalization.
In `@packages/cli/src/actions/pull/provider/sqlite.ts`:
- Around line 131-143: Normalize SQLite connection schemes consistently: in
packages/cli/src/actions/pull/provider/sqlite.ts lines 131-143, strip file: and
sqlite: immediately before new SQLite in introspect(); in
packages/cli/src/actions/db.ts lines 137-149, extend runPull’s normalization to
sqlite: and apply equivalent handling in the non-override getDatasource(model)
path; in packages/cli/src/actions/proxy.ts lines 607-631, verify sqlite: is
supported end-to-end and retain the branch only if runPull and introspect honor
it, otherwise remove it.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 98c2175a-b357-4c8e-8bfe-ec5f3d6a9336

📥 Commits

Reviewing files that changed from the base of the PR and between 844e92c and 0a25e4b.

📒 Files selected for processing (5)
  • packages/cli/src/actions/action-utils.ts
  • packages/cli/src/actions/db.ts
  • packages/cli/src/actions/proxy.ts
  • packages/cli/src/actions/pull/provider/sqlite.ts
  • packages/cli/test/proxy.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/cli/src/actions/action-utils.ts

@coderabbitaicoderabbitaiBot left a comment

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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/cli/src/actions/pull/provider/sqlite.ts`:
- Line 361: Update the column nullability mapping around the `nullable` property
to preserve SQLite’s explicit `c.notnull` value instead of treating every
primary-key column as non-nullable. Only override nullability when the table
schema confirms SQLite enforces it, such as an `INTEGER PRIMARY KEY` rowid alias
or applicable `WITHOUT ROWID`/strict tables, and add regression coverage for
TEXT and composite primary keys.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: cf8d702a-03ad-4664-9471-f6e37904c166

📥 Commits

Reviewing files that changed from the base of the PR and between 0a25e4b and e7c4a29.

📒 Files selected for processing (1)
  • packages/cli/src/actions/pull/provider/sqlite.ts

Comment threadpackages/cli/src/actions/pull/provider/sqlite.ts Outdated
Comment threadpackages/cli/src/actions/proxy.ts Outdated
Comment threadpackages/cli/src/actions/action-utils.ts Outdated
@jiashengguo
jiashengguo merged commit 2d239cd into devAug 3, 2026
10 checks passed
@jiashengguo
jiashengguo deleted the jiasheng-proxy branch August 3, 2026 06:23
@coderabbitaicoderabbitaiBot mentioned this pull request Aug 3, 2026
Sign up for freeto 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

@jiashengguo@ymc9
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

feat(cli): add --introspect option for studio command for bootstrapping without schema - #2775

Merged
jiashengguo merged 10 commits into
devfrom
jiasheng-proxy
Aug 3, 2026
Merged

feat(cli): add --introspect option for studio command for bootstrapping without schema #2775
jiashengguo merged 10 commits into
devfrom
jiasheng-proxy

Conversation

@jiashengguo

@jiashengguojiashengguo commented Jul 29, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • New Features

    • Added an --introspect option to generate a schema from your database when no schema file is available.
  • Enhancements

    • Improved schema resolution flows for --introspect vs missing schema, including smarter DATABASE_URL handling for SQLite (relative file: rewriting).
    • Enhanced database pulls with explicit --provider and --database-url support (including improved SQLite path normalization).
    • Improved automatic driver/provider loading and clearer guidance when required drivers aren’t installed.
  • Bug Fixes

    • Corrected SQLite nullability handling for primary key columns during introspection.
  • Tests

    • Expanded coverage for schema resolution and driver/module loading behaviors.

@jiashengguo
jiashengguo requested a review from CopilotJuly 29, 2026 13:35
@coderabbitai

coderabbitaiBot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The CLI adds project-aware database driver loading and an optional --introspect proxy flow that generates a schema from a database URL. runPull accepts explicit datasource overrides, with tests covering provider detection, schema resolution, SQLite URL rewriting, and package loading.

Changes

CLI introspection flow

Layer / File(s)Summary
Package-aware driver loading
packages/cli/src/actions/action-utils.ts, packages/cli/src/actions/proxy.ts, packages/cli/src/actions/pull/provider/*
Adds package resolution fallbacks and uses them to load SQLite, PostgreSQL, and MySQL drivers, with explicit missing-driver errors.
Pull datasource overrides
packages/cli/src/actions/db.ts
Exports runPull and accepts provider and database URL overrides, including SQLite URL normalization.
Proxy schema introspection
packages/cli/src/actions/proxy.ts, packages/cli/src/index.ts
Adds --introspect, provider detection, driver installation, schema generation, SQLite URL adjustment, and schema resolution branching.
Introspection validation
packages/cli/test/action-utils.test.ts, packages/cli/test/proxy.test.ts
Tests package loading, provider URL mapping, schema-resolution errors, default schema handling, and relative SQLite URLs.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

  • zenstackhq/zenstack#2761: Both changes modify runPull relation and schema synchronization logic in packages/cli/src/actions/db.ts.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title accurately describes the main user-facing change: adding a --introspect option to bootstrap studio without an existing schema.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jiasheng-proxy

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

CopilotAI left a comment

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.

Pull request overview

This PR adds an --introspect option to the CLI’s Studio/proxy command flow to bootstrap a project when no ZModel schema file is present, including auto-installing the correct DB driver and generating a schema via the existing pull/introspection pipeline.

Changes:

  • Adds --introspect flag to the CLI command definition and routes schema resolution through a new resolveSchema helper.
  • Introduces shared optional-dependency helpers (isPackageInstalled, loadPackage) and uses them across DB introspection providers and proxy dialect creation.
  • Extends runPull to accept explicit provider/databaseUrl overrides to support schema generation from an introspected database.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
FileDescription
packages/cli/src/index.tsAdds the --introspect CLI option to the command.
packages/cli/src/actions/proxy.tsImplements --introspect schema resolution, driver installation, schema generation, and generation follow-up.
packages/cli/src/actions/db.tsExports runPull and allows provider/URL overrides for introspection-driven generation.
packages/cli/src/actions/action-utils.tsAdds isPackageInstalled and loadPackage helpers for optional dependency loading.
packages/cli/src/actions/pull/provider/sqlite.tsSwitches SQLite introspection to loadPackage and adds file URL handling.
packages/cli/src/actions/pull/provider/postgresql.tsSwitches PostgreSQL introspection to loadPackage.
packages/cli/src/actions/pull/provider/mysql.tsSwitches MySQL introspection to loadPackage.
packages/cli/test/proxy.test.tsAdds unit tests for getProviderFromUrl and resolveSchema behaviors.
packages/cli/test/action-utils.test.tsAdds tests for isPackageInstalled and loadPackage.
Comments suppressed due to low confidence (1)

packages/cli/test/proxy.test.ts:862

  • This assertion looks for zen studio --introspect, but resolveSchema emits npx @zenstackhq/cli studio --introspect .... Using studio --introspect as the substring match should make the test align with the actual message formatting.
 ).rejects.toThrow('zen studio --introspect');

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment threadpackages/cli/src/actions/pull/provider/postgresql.ts
Comment threadpackages/cli/src/actions/pull/provider/sqlite.ts Outdated
Comment threadpackages/cli/test/proxy.test.ts Outdated
Comment threadpackages/cli/src/actions/proxy.ts Outdated

@coderabbitaicoderabbitaiBot left a comment

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.

Actionable comments posted: 8

🧹 Nitpick comments (1)
packages/cli/src/actions/action-utils.ts (1)

386-415: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract shared createRequire(package.json) logic.

The same createRequire(path.resolve(process.cwd(), 'package.json')) pattern is repeated 3 times across isPackageInstalled and loadPackage. A small shared helper (getProjectRequire()) would reduce duplication and keep the two functions in sync if the resolution base ever changes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/cli/src/actions/action-utils.ts` around lines 386 - 415, Extract the
repeated createRequire(path.resolve(process.cwd(), 'package.json')) construction
into a shared getProjectRequire() helper. Update isPackageInstalled and both
fallback branches in loadPackage to reuse this helper, preserving their existing
resolution and error-handling behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/cli/src/actions/action-utils.ts`:
- Around line 396-415: Update loadPackage so it preserves and propagates the
underlying error when the package cannot be loaded, rather than returning null
after all import and require fallbacks fail. Track the original and fallback
failures through the nested dynamic import, projectRequire.resolve, and
projectRequire calls, then throw a diagnostic error that retains the relevant
cause for callers such as createDialect and the database providers.
In `@packages/cli/src/actions/db.ts`:
- Around line 38-39: Add a warning in the introspection flow when the resulting
tables and enums are both empty, regardless of provider or schema selection.
Update the logic around allSchemas and the PostgreSQL introspect result so the
warning clearly indicates that no database objects were found, while preserving
successful empty-result behavior.
In `@packages/cli/src/actions/proxy.ts`:
- Around line 517-530: Restrict the existing default-schema fallback around
getSchemaFile to cases where options.schema was not explicitly provided. When an
explicit --schema path fails, propagate the original CliError instead of
returning zenstack/schema.zmodel; preserve the fallback for missing schemas in
default locations.
- Around line 619-649: Update introspectAndGenerateSchema so the generated
datasource always references env("DATABASE_URL") instead of embedding
databaseUrl when urlFromEnv is false. Preserve the existing provider and runPull
behavior, and ensure the literal connection string is never written to
schema.zmodel.
- Around line 542-544: Update the runGenerate invocation in the introspection
flow to pass options.output as the code generation output path. Preserve the
existing schema, silent, and watch arguments so generated files and subsequent
imports use the same custom output directory resolved by resolveSchema().
In `@packages/cli/src/actions/pull/provider/sqlite.ts`:
- Around line 144-151: Align SQLite relative file URL resolution between the
introspection path and createDialect. Update the resolution logic surrounding
the SQLite constructor and createDialect’s SQLite branch to use the same base
directory, preserving identical database targeting for the --introspect
bootstrap flow; prefer the existing shared resolution behavior rather than
introducing divergent path handling.
In `@packages/cli/test/action-utils.test.ts`:
- Around line 60-62: Update the successful-load test around loadPackage to
assert that the returned module is not null, replacing the insufficient
toBeDefined assertion. Keep the test focused on rejecting loadPackage’s
documented null failure result.
In `@packages/cli/test/proxy.test.ts`:
- Around line 836-846: Update the expected error substrings in the tests around
resolveSchema to match its actual command text: assert the npx `@zenstackhq/cli`
studio prefix and the -d <databaseUrl> placeholder. Apply the same correction to
both affected assertions while preserving the existing test setup and
error-checking behavior.
---
Nitpick comments:
In `@packages/cli/src/actions/action-utils.ts`:
- Around line 386-415: Extract the repeated
createRequire(path.resolve(process.cwd(), 'package.json')) construction into a
shared getProjectRequire() helper. Update isPackageInstalled and both fallback
branches in loadPackage to reuse this helper, preserving their existing
resolution and error-handling behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 312bca78-7c2c-4751-8fea-9074176dca5b

📥 Commits

Reviewing files that changed from the base of the PR and between 78e741e and bd12232.

📒 Files selected for processing (9)
  • packages/cli/src/actions/action-utils.ts
  • packages/cli/src/actions/db.ts
  • packages/cli/src/actions/proxy.ts
  • packages/cli/src/actions/pull/provider/mysql.ts
  • packages/cli/src/actions/pull/provider/postgresql.ts
  • packages/cli/src/actions/pull/provider/sqlite.ts
  • packages/cli/src/index.ts
  • packages/cli/test/action-utils.test.ts
  • packages/cli/test/proxy.test.ts

Comment threadpackages/cli/src/actions/action-utils.ts
Comment threadpackages/cli/src/actions/db.ts
Comment threadpackages/cli/src/actions/proxy.ts Outdated
Comment threadpackages/cli/src/actions/proxy.ts
Comment threadpackages/cli/src/actions/proxy.ts
Comment threadpackages/cli/src/actions/pull/provider/sqlite.ts Outdated
Comment threadpackages/cli/test/action-utils.test.ts
Comment threadpackages/cli/test/proxy.test.ts Outdated

@coderabbitaicoderabbitaiBot left a comment

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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/cli/src/actions/pull/provider/sqlite.ts (1)

131-143: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

SQLite file:/sqlite: scheme stripping is now split across files and only partially implemented. The root cause: sqlite.ts's introspect() used to normalize file:-prefixed connection strings itself; that logic was removed and only partially reimplemented in db.ts's runPull, covering just the file: prefix and only the explicit --introspect override path.

  • packages/cli/src/actions/pull/provider/sqlite.ts#L131-L143: reinstate scheme stripping (file:/sqlite: → raw path) directly before new SQLite(connectionString, ...) as a defensive last line of normalization, since callers cannot be relied upon to always pre-resolve the URL.
  • packages/cli/src/actions/db.ts#L137-L149: extend the existing databaseUrl.startsWith('file:') branch to also cover sqlite:, and consider applying equivalent normalization in the non-override getDatasource(model) branch too, since the documented ZenStack SQLite format (url = 'file:./dev.db') needs the same treatment there.
  • packages/cli/src/actions/proxy.ts#L607-L631: either confirm sqlite: is a genuinely supported input format and ensure runPull/introspect() honor it end-to-end, or drop the sqlite: branch here if it's dead/speculative handling.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/cli/src/actions/pull/provider/sqlite.ts` around lines 131 - 143,
Normalize SQLite connection schemes consistently: in
packages/cli/src/actions/pull/provider/sqlite.ts lines 131-143, strip file: and
sqlite: immediately before new SQLite in introspect(); in
packages/cli/src/actions/db.ts lines 137-149, extend runPull’s normalization to
sqlite: and apply equivalent handling in the non-override getDatasource(model)
path; in packages/cli/src/actions/proxy.ts lines 607-631, verify sqlite: is
supported end-to-end and retain the branch only if runPull and introspect honor
it, otherwise remove it.
packages/cli/src/actions/proxy.ts (1)

209-230: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Use the schema directory as the SQLite URL base when the path is relative.

outputPath resolves to zenstack/ with getOutputPath(), so relative SQLite URLs like file:database.sqlite, file:./database.sqlite, or sqlite:database.sqlite are incorrectly resolved from the cwd (/app/database.sqlite) while the generated datasource.url preserves them as relative to zenstack/ (/app/database.sqlite from zenstack/schema.zmodel) or intentionally up one level. Resolve file:/sqlite: relative URLs against path.resolve('zenstack'), not by joining with outputPath.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/cli/src/actions/proxy.ts` around lines 209 - 230, Update
createDialect’s SQLite URL resolution to use path.resolve('zenstack') as the
base for relative file: and sqlite: URLs, preserving intentional relative paths
such as ./ and ../. Do not use outputPath as the URL base; retain absolute URL
handling and Windows normalization.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@packages/cli/src/actions/proxy.ts`:
- Around line 209-230: Update createDialect’s SQLite URL resolution to use
path.resolve('zenstack') as the base for relative file: and sqlite: URLs,
preserving intentional relative paths such as ./ and ../. Do not use outputPath
as the URL base; retain absolute URL handling and Windows normalization.
In `@packages/cli/src/actions/pull/provider/sqlite.ts`:
- Around line 131-143: Normalize SQLite connection schemes consistently: in
packages/cli/src/actions/pull/provider/sqlite.ts lines 131-143, strip file: and
sqlite: immediately before new SQLite in introspect(); in
packages/cli/src/actions/db.ts lines 137-149, extend runPull’s normalization to
sqlite: and apply equivalent handling in the non-override getDatasource(model)
path; in packages/cli/src/actions/proxy.ts lines 607-631, verify sqlite: is
supported end-to-end and retain the branch only if runPull and introspect honor
it, otherwise remove it.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 98c2175a-b357-4c8e-8bfe-ec5f3d6a9336

📥 Commits

Reviewing files that changed from the base of the PR and between 844e92c and 0a25e4b.

📒 Files selected for processing (5)
  • packages/cli/src/actions/action-utils.ts
  • packages/cli/src/actions/db.ts
  • packages/cli/src/actions/proxy.ts
  • packages/cli/src/actions/pull/provider/sqlite.ts
  • packages/cli/test/proxy.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/cli/src/actions/action-utils.ts

@coderabbitaicoderabbitaiBot left a comment

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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/cli/src/actions/pull/provider/sqlite.ts`:
- Line 361: Update the column nullability mapping around the `nullable` property
to preserve SQLite’s explicit `c.notnull` value instead of treating every
primary-key column as non-nullable. Only override nullability when the table
schema confirms SQLite enforces it, such as an `INTEGER PRIMARY KEY` rowid alias
or applicable `WITHOUT ROWID`/strict tables, and add regression coverage for
TEXT and composite primary keys.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: cf8d702a-03ad-4664-9471-f6e37904c166

📥 Commits

Reviewing files that changed from the base of the PR and between 0a25e4b and e7c4a29.

📒 Files selected for processing (1)
  • packages/cli/src/actions/pull/provider/sqlite.ts

Comment threadpackages/cli/src/actions/pull/provider/sqlite.ts Outdated
Comment threadpackages/cli/src/actions/proxy.ts Outdated
Comment threadpackages/cli/src/actions/action-utils.ts Outdated
@jiashengguo
jiashengguo merged commit 2d239cd into devAug 3, 2026
10 checks passed
@jiashengguo
jiashengguo deleted the jiasheng-proxy branch August 3, 2026 06:23
@coderabbitaicoderabbitaiBot mentioned this pull request Aug 3, 2026
Sign up for freeto 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

@jiashengguo@ymc9