@raypx-kit/drizzle-kit 0.0.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/LICENSE +26 -0
- package/README.md +66 -0
- package/dist/bin.cjs +179087 -0
- package/dist/index.d.mts +340 -0
- package/dist/index.d.ts +340 -0
- package/dist/index.js +97 -0
- package/dist/index.mjs +96 -0
- package/dist/package.json +1 -0
- package/dist/schemaValidator-OgLXlvBV.d.mts +5 -0
- package/dist/schemaValidator-OgLXlvBV.d.ts +5 -0
- package/dist/skills/drizzle/SKILL.md +44 -0
- package/dist/skills/drizzle-generate/SKILL.md +107 -0
- package/dist/skills/drizzle-hints/SKILL.md +181 -0
- package/dist/skills/drizzle-migrations/SKILL.md +88 -0
- package/dist/skills/drizzle-output-modes/SKILL.md +51 -0
- package/dist/skills/drizzle-pull/SKILL.md +108 -0
- package/dist/skills/drizzle-push/SKILL.md +159 -0
- package/dist/skills/drizzle-responses-and-errors/SKILL.md +156 -0
- package/package.json +69 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: drizzle-output-modes
|
|
3
|
+
description: "Choose and interpret drizzle-kit `--output text` vs `--output json`, reason about interactivity in non-TTY contexts, and read the human-readable missing-decisions text report. Load when deciding which `--output` mode to pass, when a drizzle-kit run in a non-TTY context needs to stay non-interactive, or when parsing a `missing_hints: N unresolved decisions` text report."
|
|
4
|
+
metadata:
|
|
5
|
+
version: "1.0.0"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Drizzle output modes
|
|
9
|
+
|
|
10
|
+
If the `drizzle` skill has not been loaded yet this session, load it first — it carries the staleness check and the MCP-vs-CLI surface-selection rule that govern every drizzle-kit invocation.
|
|
11
|
+
|
|
12
|
+
Drizzle Kit `generate` / `push` / `check` render results in one of two output modes, selected with `--output`. Output format and interactivity are separate axes: the output mode controls *how* results are rendered; interactivity controls *whether* the CLI may prompt.
|
|
13
|
+
|
|
14
|
+
- `--output text` (the default) renders human-readable progress and results on stdout, with typed errors on stderr. When a command has unresolved decisions and cannot prompt, it writes the missing-decisions report (below) to stdout and exits with code 2.
|
|
15
|
+
- `--output json` emits a single machine-readable JSON envelope on stdout for every status (including errors), and is always non-interactive.
|
|
16
|
+
|
|
17
|
+
`check --output json` rides the same plumbing: it is a no-hint, non-interactive gate that emits an `ok` envelope when the migrations folder is valid and a `check_error` envelope for snapshot-integrity problems or unreported branch conflicts. It never reaches the missing-decisions path. The `drizzle-responses-and-errors` skill decodes the `check_error` envelope.
|
|
18
|
+
|
|
19
|
+
## Interactivity
|
|
20
|
+
|
|
21
|
+
A command is interactive only when it is rendering text **and** stdin is a TTY:
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
interactive = output === 'text' && !!process.stdin.isTTY
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
`--output json` is therefore always non-interactive, regardless of whether stdin is a TTY. Under `--output text`, interactivity is determined solely by whether stdin is a TTY (`!process.stdin.isTTY` means non-interactive).
|
|
28
|
+
|
|
29
|
+
When the CLI is non-interactive and reaches a decision it cannot resolve from your `--hints` / `--hints-file`, it does not prompt. Under `--output json` it returns a `missing_hints` envelope; under `--output text` it prints the missing-decisions report below. The `drizzle-hints` skill covers building the reply that resolves those decisions.
|
|
30
|
+
|
|
31
|
+
## Missing-decisions text report
|
|
32
|
+
|
|
33
|
+
Under `--output text`, when the CLI is non-interactive (stdin is not a TTY) and at least one decision is still unresolved, it prints a human-readable report to stdout and exits with code 2. `rename_or_create` decisions are listed first (discovery order), then `confirm_data_loss` decisions (discovery order), with a continuous 1-based index across both groups. Each item shows an `Add to --hints:` block with the snippet(s) to supply; `rename_or_create` items show both a `rename` and a `create` snippet joined by `OR`.
|
|
34
|
+
|
|
35
|
+
The `from` placeholders are intentionally invalid JSON — replace the angle-bracket segments with the real identifier of the entity being renamed before re-running. The report only suggests the inline `--hints '<json-array>'` form, never `--hints-file`. A two-item run renders like this:
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
missing_hints: 2 unresolved decisions
|
|
39
|
+
|
|
40
|
+
1. Rename or create — table public.users_v2
|
|
41
|
+
Add to --hints:
|
|
42
|
+
{ "type": "rename", "kind": "table", "from": ["<schema>", "<old_name>"], "to": ["public", "users_v2"] }
|
|
43
|
+
OR
|
|
44
|
+
{ "type": "create", "kind": "table", "entity": ["public", "users_v2"] }
|
|
45
|
+
|
|
46
|
+
2. Confirm data loss — table public.legacy_audit (reason: non_empty)
|
|
47
|
+
Add to --hints:
|
|
48
|
+
{ "type": "confirm_data_loss", "kind": "table", "entity": ["public", "legacy_audit"] }
|
|
49
|
+
|
|
50
|
+
Re-run with --hints '<json-array>'. Exit code 2.
|
|
51
|
+
```
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: drizzle-pull
|
|
3
|
+
description: Introspect an existing database into a Drizzle schema — the reverse of generate and push, which drive a database from a schema. Load whenever the task is to generate a Drizzle schema from a live database, reverse-engineer or import an existing database, or decode the result manifest or a connect/introspect failure from a pull.
|
|
4
|
+
metadata:
|
|
5
|
+
version: "1.0.0"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Drizzle pull
|
|
9
|
+
|
|
10
|
+
If the `drizzle` skill has not been loaded yet this session, load it first — it carries the staleness check and the MCP-vs-CLI surface-selection rule that govern every drizzle-kit invocation.
|
|
11
|
+
|
|
12
|
+
Pull introspects an existing database and writes a Drizzle schema from it: it connects, reads the live DDL, and emits `schema.ts`, a `relations.ts` (for the dialects that have one), and a snapshot under the configured `out` dir. It is the inverse of `generate` / `push` — those start from a schema and drive the database; pull starts from the database and writes the schema. The `drizzle-migrations` skill covers where pull sits in the overall workflow. Output format and interactivity are separate axes the same way they are for the other verbs — the `drizzle-output-modes` skill covers the text-vs-json choice — and `drizzle-responses-and-errors` decodes the envelope shapes below.
|
|
13
|
+
|
|
14
|
+
## CLI form
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
drizzle-kit pull --output json [--config drizzle.config.ts] [--dialect <d>] [--out <dir>] [--breakpoints] [--casing camel|preserve] [--init]
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Flag surface:
|
|
21
|
+
|
|
22
|
+
- `--config` — path to `drizzle.config.ts` (default: `drizzle.config.ts` at CWD). Pull reads `dbCredentials` from the config; there is no CLI flag for the credentials object as a whole.
|
|
23
|
+
- `--dialect`, `--out` — override the corresponding `defineConfig` fields. `--out` is where `schema.ts` / `relations.ts` / the snapshot are written.
|
|
24
|
+
- `--url` / `--host` / `--port` / `--user` / `--password` / `--database` / `--ssl` / `--auth-token` — direct connection overrides for the corresponding `dbCredentials` fields. Most projects set these in the config file instead.
|
|
25
|
+
- `--breakpoints` — emit statement-breakpoint markers in any generated migration SQL.
|
|
26
|
+
- `--casing camel|preserve` — how introspected identifiers are cased in the emitted schema (`camel` camel-cases columns; `preserve` keeps the database spelling).
|
|
27
|
+
- `--output json` — switches stdout to one JSON line carrying the envelope and is always non-interactive. Use it for agent / CI / scripted contexts. Under the default `--output text` pull prints human-readable progress and the result.
|
|
28
|
+
- `--init` — also run the initial migration against the live database. This is a destructive write (see the `--init` note below); it adds `migrationPath` to the ok manifest.
|
|
29
|
+
|
|
30
|
+
Minimal example — `drizzle.config.ts` carries the credentials, the CLI invocation is just the verb:
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
// drizzle.config.ts
|
|
34
|
+
import { defineConfig } from 'drizzle-kit';
|
|
35
|
+
|
|
36
|
+
export default defineConfig({
|
|
37
|
+
dialect: 'postgresql',
|
|
38
|
+
out: './drizzle',
|
|
39
|
+
dbCredentials: { url: process.env.DATABASE_URL! },
|
|
40
|
+
});
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
drizzle-kit pull --output json --config drizzle.config.ts
|
|
45
|
+
# → {"status":"ok","dialect":"postgresql","schemaPath":"drizzle/schema.ts","relationsPath":"drizzle/relations.ts","snapshotPath":"drizzle/meta/0000_snapshot.json"}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The process exits with the code that matches `status` (`0` for ok, `1` for error). Agents read both stdout (the envelope) and the exit code.
|
|
49
|
+
|
|
50
|
+
## SDK form
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
import { pull } from 'drizzle-kit';
|
|
54
|
+
|
|
55
|
+
const response = await pull({
|
|
56
|
+
dialect: 'postgresql',
|
|
57
|
+
out: './drizzle',
|
|
58
|
+
url: process.env.DATABASE_URL!,
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
if (response.status === 'ok') {
|
|
62
|
+
// introspection succeeded; the manifest names the written files:
|
|
63
|
+
// response.schemaPath — always present
|
|
64
|
+
// response.snapshotPath — always present
|
|
65
|
+
// response.relationsPath — present except mssql (no relations file)
|
|
66
|
+
// response.migrationPath — present only when called with init: true
|
|
67
|
+
} else {
|
|
68
|
+
// response.status === 'error'
|
|
69
|
+
// response.error.code identifies the failure, e.g. database_driver_error
|
|
70
|
+
// (connect/introspect/init failures are credential-redacted) — decode it
|
|
71
|
+
// with the drizzle-responses-and-errors skill
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
`pull` is a real root SDK function. It always runs in JSON mode internally — no `--output json` flag needed at the call site — and returns the same envelope the CLI prints. In SDK form the credential fields are passed flat on the call (`url`, or the broken-out `host` / `port` / `user` / `password` / `database` set); pass `init: true` to also run the initial migration. The status is `ok` or `error` only — there is no `no_changes` branch and no `missing_hints` branch (see Contract below).
|
|
76
|
+
|
|
77
|
+
## Response shape
|
|
78
|
+
|
|
79
|
+
The `'ok'` envelope is a paths-manifest — it names the files pull wrote, not the introspected DDL:
|
|
80
|
+
|
|
81
|
+
```jsonc
|
|
82
|
+
// postgres / mysql / sqlite / turso / cockroach / singlestore — relationsPath present
|
|
83
|
+
{ "status": "ok", "dialect": "postgresql", "schemaPath": "drizzle/schema.ts", "relationsPath": "drizzle/relations.ts", "snapshotPath": "drizzle/meta/0000_snapshot.json" }
|
|
84
|
+
|
|
85
|
+
// mssql — relationsPath omitted (no relations file is generated)
|
|
86
|
+
{ "status": "ok", "dialect": "mssql", "schemaPath": "drizzle/schema.ts", "snapshotPath": "drizzle/meta/0000_snapshot.json" }
|
|
87
|
+
|
|
88
|
+
// with init: true — an initial migration was also written, so migrationPath appears
|
|
89
|
+
{ "status": "ok", "dialect": "postgresql", "schemaPath": "drizzle/schema.ts", "relationsPath": "drizzle/relations.ts", "snapshotPath": "drizzle/meta/0000_snapshot.json", "migrationPath": "drizzle/0000_init/migration.sql" }
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
So the manifest is `{ schemaPath, snapshotPath, relationsPath?, migrationPath? }`: `schemaPath` and `snapshotPath` are always present; `relationsPath?` is optional and omitted for mssql; `migrationPath?` is optional and present only with `--init`. The envelope carries no inline DDL array.
|
|
93
|
+
|
|
94
|
+
The `'error'` envelope, when the driver cannot connect or introspection fails:
|
|
95
|
+
|
|
96
|
+
```json
|
|
97
|
+
{ "status": "error", "error": { "code": "database_driver_error", "database": "postgresql", "packages": ["pg", "postgres"], "note": "<optional connection hint>" } }
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
`database_driver_error` carries only `database`, `packages`, and an optional `note` — the connection string, sql, and params are deliberately kept out of the envelope, so no credential substring ever reaches stdout. The `drizzle-responses-and-errors` skill decodes this and the other error codes. Example payloads here use placeholder paths and dialects only — never a real connection string, url, or password.
|
|
101
|
+
|
|
102
|
+
## Contract
|
|
103
|
+
|
|
104
|
+
Pull is ok/error only. It never emits `missing_hints`: it introspects against an empty starting DDL, constructs no hints handler, and exposes no consent surface — there are no ambiguous renames or destructive-change prompts to resolve. The only outcomes are `ok` (the manifest is returned) or a thrown typed error surfaced as the `error` envelope.
|
|
105
|
+
|
|
106
|
+
## --init
|
|
107
|
+
|
|
108
|
+
`--init` (CLI) / `init: true` (SDK) runs the initial migration against the live database in addition to writing the schema. That is a destructive write — it executes DDL against the connected database, not just disk — and on success it adds `migrationPath` to the ok manifest. The MCP `pull` tool surfaces this `init` escalation as a per-call destructive signal on its result; the `drizzle-responses-and-errors` skill carries the canonical shape of that signal.
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: drizzle-push
|
|
3
|
+
description: Apply drizzle schema changes directly to a live database without writing a migration file. Load before running `drizzle-kit push` or calling the `push(...)` SDK, when syncing a Drizzle schema directly to a live DB (prototyping, dev resets, ephemeral test databases), or when the task is to push, sync, apply, or deploy a schema.
|
|
4
|
+
metadata:
|
|
5
|
+
version: "1.0.0"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Drizzle push
|
|
9
|
+
|
|
10
|
+
If the `drizzle` skill has not been loaded yet this session, load it first — it carries the staleness check and the MCP-vs-CLI surface-selection rule that govern every drizzle-kit invocation.
|
|
11
|
+
|
|
12
|
+
The CLI flag `--output json` and the SDK `push(...)` function emit the same discriminated-union envelope, and the envelope (not the stdout text) is what the agent decodes. Output format and interactivity are separate axes: `--output json` selects the machine-readable envelope and is always non-interactive, so pass it whenever an agent calls the CLI. Under the default `--output text` the CLI prompts only when stdin is a TTY; in a non-TTY it prints the missing-decisions report and exits 2 (it never hangs prompting). See the `drizzle-output-modes` skill for the two modes and the interactivity rule. The SDK runs in JSON mode internally with no flag needed at the call site. Push is the live-DB counterpart to `generate`: `generate` is offline and writes a migration SQL file to disk, `push` connects to the database and executes the diff against it. The `drizzle-generate` skill covers the offline path; the `drizzle-migrations` skill covers the day-to-day workflow that combines them.
|
|
13
|
+
|
|
14
|
+
## CLI form
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
drizzle-kit push --output json [--config drizzle.config.ts] [--dialect <d>] [--schema <path>] [--explain] [--hints '<json>' | --hints-file ./hints.json]
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Flag surface:
|
|
21
|
+
|
|
22
|
+
- `--config` — path to `drizzle.config.ts` (default: `drizzle.config.ts` at CWD). Push reads `dbCredentials` from the config; there is no CLI flag for the credentials object as a whole.
|
|
23
|
+
- `--dialect`, `--schema` — override the corresponding `defineConfig` fields.
|
|
24
|
+
- `--output json` — switches stdout to one JSON line carrying the envelope and is always non-interactive. Use it for agent / CI / scripted contexts. Under the default `--output text` the CLI prompts only on a TTY and otherwise prints the missing-decisions report (exit 2).
|
|
25
|
+
- `--explain` — dry-run mode. Returns planned SQL statements and computed hints instead of executing them against the database.
|
|
26
|
+
- `--hints` — inline JSON array of hint resolutions (see the `drizzle-hints` skill).
|
|
27
|
+
- `--hints-file` — same payload as `--hints`, read from a JSON file. Use for long hint sets.
|
|
28
|
+
- `--url` / `--host` / `--port` / `--user` / `--password` / `--database` / `--ssl` / `--auth-token` — direct connection-string overrides for the corresponding `dbCredentials` fields. Most projects set these in the config file instead.
|
|
29
|
+
|
|
30
|
+
Minimal example — `drizzle.config.ts` carries the credentials, the CLI invocation is just the verb:
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
// drizzle.config.ts
|
|
34
|
+
import { defineConfig } from 'drizzle-kit';
|
|
35
|
+
|
|
36
|
+
export default defineConfig({
|
|
37
|
+
dialect: 'postgresql',
|
|
38
|
+
schema: './src/db/schema.ts',
|
|
39
|
+
dbCredentials: { url: process.env.DATABASE_URL! },
|
|
40
|
+
});
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
drizzle-kit push --output json --config drizzle.config.ts
|
|
45
|
+
# → {"status":"ok","dialect":"postgresql"}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The process exits with the code that matches `status` (see Response envelope below). Agents read both stdout (the envelope) and the exit code.
|
|
49
|
+
|
|
50
|
+
## SDK form
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
import { push } from 'drizzle-kit';
|
|
54
|
+
|
|
55
|
+
const response = await push({
|
|
56
|
+
dialect: 'postgresql',
|
|
57
|
+
schema: './src/db/schema.ts',
|
|
58
|
+
url: process.env.DATABASE_URL!,
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
if (response.status === 'ok') {
|
|
62
|
+
// schema applied to the live database
|
|
63
|
+
} else if (response.status === 'no_changes') {
|
|
64
|
+
// live DB already matches the schema — nothing executed
|
|
65
|
+
} else if (response.status === 'missing_hints') {
|
|
66
|
+
// response.unresolved lists ambiguities or destructive ops — see the drizzle-hints skill
|
|
67
|
+
} else if (response.status === 'error') {
|
|
68
|
+
// response.error.code identifies the failure — see drizzle-responses-and-errors
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
The SDK is the public-surface entry point. It always runs in JSON mode internally — no `--output json` flag needed at the call site — and returns the same envelope the CLI prints. In SDK form the credential fields are passed flat on the call (`url`, or the broken-out `host`/`port`/`user`/`password`/`database` set) — there is no `dbCredentials` wrapper and no `drizzle.config.ts` file is required. Narrow on `response.status` to extract typed branches:
|
|
73
|
+
|
|
74
|
+
- `'ok'` → `response.dialect` (plus `response.statements`, `response.hints` in explain mode).
|
|
75
|
+
- `'no_changes'` → `response.dialect`.
|
|
76
|
+
- `'missing_hints'` → `response.unresolved` (array of items).
|
|
77
|
+
- `'error'` → `response.error.code` plus per-code metadata.
|
|
78
|
+
|
|
79
|
+
The SDK does not throw on user-level failures — every outcome flows through the envelope. Unexpected runtime exceptions are wrapped as `status: 'error'` with `code: 'internal_error'`.
|
|
80
|
+
|
|
81
|
+
## Response shape
|
|
82
|
+
|
|
83
|
+
Push's `'ok'` envelope is `{ status, dialect }` — no `migration_path`, since push executes the diff against the live DB rather than writing a file. `'ok'` (explain) carries `{ status, dialect, statements, hints }`. `'no_changes'`, `'missing_hints'`, and `'error'` are shared across operations. Full envelope shapes, exit-code mapping, and per-code error metadata live in the `drizzle-responses-and-errors` skill's response-envelope section.
|
|
84
|
+
|
|
85
|
+
`'missing_hints'` (exit 2) means the diff is ambiguous or unsafe — the resolution loop lives in the `drizzle-hints` skill. The most common error codes for `push` are `config_validation_error`, `config_connection_error`, `database_driver_error`, `query_error`, `unsupported_schema_change`, `invalid_hints`, `required_packages_error`, `internal_error`.
|
|
86
|
+
|
|
87
|
+
## Connection
|
|
88
|
+
|
|
89
|
+
Push requires a live database connection. In `drizzle.config.ts` (CLI form) the credentials nest under a `dbCredentials` object; in SDK form the same fields are passed flat on the `push(...)` call — no `dbCredentials` wrapper. The shape varies per dialect; common fields are `url` (preferred when the driver supports it) or the broken-out `host` / `port` / `user` / `password` / `database` set, plus `ssl` for TLS and `authToken` for turso/libsql. The per-dialect shapes below show the config (`dbCredentials`) form; in the SDK, drop the wrapper and pass these fields directly on the call.
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
// postgresql / cockroach
|
|
93
|
+
dbCredentials: { url: process.env.DATABASE_URL! }
|
|
94
|
+
// or: { host, port, user, password, database, ssl }
|
|
95
|
+
|
|
96
|
+
// mysql / singlestore
|
|
97
|
+
dbCredentials: { url: process.env.DATABASE_URL! }
|
|
98
|
+
// or: { host, port, user, password, database }
|
|
99
|
+
|
|
100
|
+
// sqlite
|
|
101
|
+
dbCredentials: { url: 'file:./local.db' }
|
|
102
|
+
|
|
103
|
+
// turso (libsql)
|
|
104
|
+
dbCredentials: { url: process.env.TURSO_URL!, authToken: process.env.TURSO_AUTH_TOKEN }
|
|
105
|
+
|
|
106
|
+
// mssql
|
|
107
|
+
dbCredentials: { url: process.env.MSSQL_URL! }
|
|
108
|
+
// or: { server, port, user, password, database }
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Secrets belong in environment variables (`process.env.DATABASE_URL`, etc.) — `drizzle.config.ts` typically ships with the repo, so hard-coded credentials leak through source control once committed. When credentials are absent or malformed, push returns `status: 'error'` with `code: 'config_connection_error'`; when the driver itself fails to connect (wrong host, bad TLS, server down), `code: 'database_driver_error'`. The `drizzle-responses-and-errors` skill decodes both.
|
|
112
|
+
|
|
113
|
+
## Destructive changes
|
|
114
|
+
|
|
115
|
+
When push would drop a non-empty table, column, schema, or view, drop a primary key, change a column's SQL type, or recreate a SQLite table to add a `NOT NULL` column (which wipes its rows), it does not execute. Instead it returns `status: 'missing_hints'` with `unresolved` items of `type: 'confirm_data_loss'`. The agent must approve each item with a matching `Hint` and re-invoke.
|
|
116
|
+
|
|
117
|
+
Adding `NOT NULL` or `UNIQUE` on the server dialects (postgresql, mysql, mssql, cockroach, singlestore) does not trigger a confirmation request — the `ALTER` runs and the database enforces the constraint, rejecting a genuine violation cleanly. Only SQLite's `add_not_null` is a `confirm_data_loss`, because SQLite has no in-place path to add the column and so recreates the table and deletes all rows (reason `table_recreate`).
|
|
118
|
+
|
|
119
|
+
The `confirm_data_loss` kinds that fire here: `table`, `column`, `schema`, `view`, `primary_key`, and (sqlite / turso only) `add_not_null`. The reasons (`non_empty`, `table_recreate`, `type_change`) and the kinds they apply to are catalogued in the `drizzle-hints` skill's reasons section. See the `drizzle-hints` skill for the full resolution loop (parse `unresolved` → build a `Hint` per item → pass `hints` back → re-invoke).
|
|
120
|
+
|
|
121
|
+
Every entity tuple leads with a namespace segment for uniform arity, but only postgresql, cockroach, and mssql have a real schema namespace (the `schema` entity kind is wired only for those three). On the schemaless dialects (mysql, sqlite, singlestore) that leading segment is a synthesized `'public'` placeholder, not a real schema — echo it verbatim; on a schemaless dialect it is filler, never build a separate `schema` rename or create from it.
|
|
122
|
+
|
|
123
|
+
## Dialect notes
|
|
124
|
+
|
|
125
|
+
Per-dialect quirks (postgresql, mysql, sqlite, mssql, cockroach, singlestore) — the same diff engine and dialect surface drives both `generate` and `push`, so the notes are shared. See the `drizzle-migrations` skill's dialect-notes section.
|
|
126
|
+
|
|
127
|
+
## Examples
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
# Happy path — diff applied against the live DB
|
|
131
|
+
drizzle-kit push --output json --config drizzle.config.ts
|
|
132
|
+
# → {"status":"ok","dialect":"postgresql"}
|
|
133
|
+
|
|
134
|
+
# Idempotent re-run — live DB already matches the schema
|
|
135
|
+
drizzle-kit push --output json --config drizzle.config.ts
|
|
136
|
+
# → {"status":"no_changes","dialect":"postgresql"}
|
|
137
|
+
|
|
138
|
+
# Destructive change — caller must supply confirm_data_loss hints and retry
|
|
139
|
+
drizzle-kit push --output json --config drizzle.config.ts
|
|
140
|
+
# → {"status":"missing_hints","unresolved":[{"type":"confirm_data_loss","kind":"column","entity":["public","users","legacy_id"],"reason":"non_empty"}]}
|
|
141
|
+
# (resolution loop: see the drizzle-hints skill)
|
|
142
|
+
|
|
143
|
+
# Hard error — wrong credential shape for the driver
|
|
144
|
+
drizzle-kit push --output json --config drizzle.config.ts
|
|
145
|
+
# → {"status":"error","error":{"code":"config_connection_error","driver":"pg","params":["url"]}}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
SDK equivalent of the happy path:
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
import { push } from 'drizzle-kit';
|
|
152
|
+
|
|
153
|
+
const r = await push({
|
|
154
|
+
dialect: 'postgresql',
|
|
155
|
+
schema: './src/db/schema.ts',
|
|
156
|
+
url: process.env.DATABASE_URL!,
|
|
157
|
+
});
|
|
158
|
+
if (r.status === 'ok') console.log('applied');
|
|
159
|
+
```
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: drizzle-responses-and-errors
|
|
3
|
+
description: Decode the drizzle-kit response JSON envelope, error codes, and exit codes — from the CLI `--output json` output or any drizzle-kit SDK return value. Load whenever drizzle-kit output contains a non-zero exit, an error code (`config_validation_error`, `database_driver_error`, `invalid_hints`, `unsupported_schema_change`, etc.), or any drizzle-kit JSON response needs parsing or inspection.
|
|
4
|
+
metadata:
|
|
5
|
+
version: "1.0.0"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Drizzle responses and errors
|
|
9
|
+
|
|
10
|
+
If the `drizzle` skill has not been loaded yet this session, load it first — it carries the staleness check and the MCP-vs-CLI surface-selection rule that govern every drizzle-kit invocation.
|
|
11
|
+
|
|
12
|
+
Both invocation surfaces share one envelope: the CLI prints it on stdout when `--output json` is passed, and the SDK functions `generate(...)` / `push(...)` / `check(...)` return the same object. The discriminator is always `status`. Decoding logic written for one surface works on the other. This skill does not invoke commands or author schemas — see `drizzle-generate` and `drizzle-push` for invocation, `drizzle-hints` for the `missing_hints` resolution loop.
|
|
13
|
+
|
|
14
|
+
## Response envelope
|
|
15
|
+
|
|
16
|
+
The discriminated union (identical for CLI stdout and SDK return value):
|
|
17
|
+
|
|
18
|
+
| status | exit code | shape |
|
|
19
|
+
| ----------------- | --------- | ------------------------------------------------------- |
|
|
20
|
+
| `'ok'` | 0 | `{ status, dialect, ... }` (per-operation extras below) |
|
|
21
|
+
| `'no_changes'` | 0 | `{ status, dialect }` |
|
|
22
|
+
| `'missing_hints'` | 2 | `{ status, unresolved: MissingHint[] }` |
|
|
23
|
+
| `'error'` | 1 | `{ status, error: { code, ...meta } }` |
|
|
24
|
+
|
|
25
|
+
Per-operation extras on `'ok'`:
|
|
26
|
+
|
|
27
|
+
- `generate` (write mode) — `{ status, dialect, migration_path }`
|
|
28
|
+
- `push` (write mode) — `{ status, dialect }`
|
|
29
|
+
- `pull` — `{ status, dialect, schemaPath, snapshotPath, relationsPath?, migrationPath? }` (`relationsPath?` omitted for mssql; `migrationPath?` only with `--init`). `pull` is ok-or-error only — never `missing_hints`, never `no_changes`.
|
|
30
|
+
- `export` — `{ status, dialect, statements, warnings }` (the individual SQL statements plus rendered warnings — there is no joined `sql` field).
|
|
31
|
+
- `up` — `{ status, dialect, upgraded }` (`upgraded` is the array of rewritten snapshot paths; `[]` means a no-op).
|
|
32
|
+
- `--explain` (either command, non-empty diff) — `{ status, dialect, statements, hints }`
|
|
33
|
+
|
|
34
|
+
`'missing_hints'` carries `unresolved`, an array of items the agent must resolve before retrying. Each item is `{ type: 'rename_or_create', kind, entity }` or `{ type: 'confirm_data_loss', kind, entity, reason, reason_details? }`. The resolution loop lives in the `drizzle-hints` skill.
|
|
35
|
+
|
|
36
|
+
The table above describes `--output json`. Under `--output text` + non-TTY the same `missing_hints` information renders as the human-readable missing-decisions report on stdout, still exiting with code 2 — see the `drizzle-output-modes` skill for the text-report shape.
|
|
37
|
+
|
|
38
|
+
`'error'` carries `error.code` plus `meta` keys (variable per code). The runtime serializer flattens `{ code, ...meta }` into the `error` object — `code` is always present; the remaining keys vary. The envelope is the only shape an agent observes; no other fields are surfaced.
|
|
39
|
+
|
|
40
|
+
Exit code is the canonical second signal — agents spawning the CLI can branch on either the envelope or the exit code; agents using the SDK only see the envelope.
|
|
41
|
+
|
|
42
|
+
## Error codes
|
|
43
|
+
|
|
44
|
+
The canonical subset surfacing from `generate` and `push`. `code` is the discriminator; `meta` keys are listed alongside.
|
|
45
|
+
|
|
46
|
+
| code | when | meta keys |
|
|
47
|
+
| ----------------------------------- | ----------------------------------------------------------------------------------- | --------------------------------------------------------------- |
|
|
48
|
+
| `invalid_hints` | hints payload could not be loaded, parsed, validated, or matched to the diff | `source: 'file'\|'inline'`, `path?`, `issues?`, `kind?`, `from?` |
|
|
49
|
+
| `unsupported_schema_change` | the diff would emit DDL the target dialect cannot execute (see variants below) | `kind`, plus per-variant keys |
|
|
50
|
+
| `check_error` | `check` found a snapshot-integrity problem or unreported branch conflicts (see below) | `kind: 'unsupported'\|'malformed'\|'non_latest'\|'conflicts'`, `snapshot?`, `conflicts?`, `details?` |
|
|
51
|
+
| `query_error` | runtime SQL against the live DB threw | `sql`, `params` |
|
|
52
|
+
| `internal_error` | uncaught exception escaped the run boundary — likely a bug to report | `message` |
|
|
53
|
+
| `config_validation_error` | `drizzle.config.ts` failed shape validation | `issues?` (zod-style records) |
|
|
54
|
+
| `config_file_not_found_error` | config path did not resolve to a file | `path` |
|
|
55
|
+
| `schema_files_not_found_error` | schema glob(s) matched zero files | `paths` |
|
|
56
|
+
| `missing_required_params_error` | a required CLI flag or config field was absent | `params` |
|
|
57
|
+
| `ambiguous_params_error` | a flag conflicts with a `defineConfig` field (or two flags collide) | `command`, `configOption` |
|
|
58
|
+
| `unsupported_command_dialect_error` | the requested command isn't valid for the chosen dialect | `command`, `dialect?` |
|
|
59
|
+
| `config_connection_error` | `dbCredentials` shape doesn't match the chosen driver | `driver`, `params`, `command?` |
|
|
60
|
+
| `database_driver_error` | driver-specific connect failure — usually a missing or version-mismatched package; also arises from `pull`'s connect/introspect span and its `--init` migrate span | `database`, `packages`, `note?` |
|
|
61
|
+
| `orm_version_error` | `drizzle-orm` is missing, too old, or `drizzle-kit` itself is outdated | `kind: 'orm_missing'\|'orm_too_old'\|'kit_outdated'` |
|
|
62
|
+
| `required_packages_error` | one or more dialect driver packages need installing | `packages` |
|
|
63
|
+
| `migrations_outdated_error` | migrations folder format is outdated and needs upgrading | `out` |
|
|
64
|
+
|
|
65
|
+
Ordering above is roughly most-likely-first from `generate` / `push`. Other codes can surface (see the live `drizzle-kit` source); the table covers the curated subset relevant to the day-to-day workflow.
|
|
66
|
+
|
|
67
|
+
## Unsupported schema changes
|
|
68
|
+
|
|
69
|
+
`unsupported_schema_change` is a discriminated meta union — `meta.kind` selects the variant.
|
|
70
|
+
|
|
71
|
+
| meta.kind | dialect(s) | meta keys |
|
|
72
|
+
| ------------------------------------ | ------------------ | --------------------------------------------------------------- |
|
|
73
|
+
| `drop_pk_dependency` | mysql, singlestore | `kind`, `table`, `columns`, `blocking_fks` |
|
|
74
|
+
| `fk_target_not_unique` | mysql, singlestore | `kind`, `table`, `columns`, `table_to`, `columns_to` |
|
|
75
|
+
| `rename_blocked_by_check_constraint` | mssql | `kind`, `schema`, `table`, `from`, `to` |
|
|
76
|
+
| `rename_schema_unsupported` | mssql | `kind`, `from`, `to`, `dialect: 'mssql'` |
|
|
77
|
+
|
|
78
|
+
When fired:
|
|
79
|
+
|
|
80
|
+
- `drop_pk_dependency` — `ALTER TABLE … DROP PRIMARY KEY` is rejected because a foreign key references the dropped columns and no covering UNIQUE index exists. Add a UNIQUE on those columns first, then drop.
|
|
81
|
+
- `fk_target_not_unique` — `CREATE FOREIGN KEY` is rejected because the referenced columns on `table_to` are neither UNIQUE nor a PRIMARY KEY. Add a UNIQUE on `columns_to` first.
|
|
82
|
+
- `rename_blocked_by_check_constraint` — `sp_rename` of `schema.table.from` is rejected because the column appears in a CHECK constraint. Drop the constraint, rename, recreate the constraint.
|
|
83
|
+
- `rename_schema_unsupported` — MSSQL does not support schema rename at all. Recreate the schema and move objects manually, or keep the old schema name.
|
|
84
|
+
|
|
85
|
+
## Check errors
|
|
86
|
+
|
|
87
|
+
`check_error` surfaces from the `check()` SDK export and `drizzle-kit check`, returning the envelope on integrity or conflict failures exactly as the CLI does. It also surfaces from `generate` / `migrate` when their pre-flight migrations-folder gate fails. It exits with code 1 and carries a `kind` discriminator.
|
|
88
|
+
|
|
89
|
+
| meta.kind | meta keys | when fired |
|
|
90
|
+
| ------------- | ------------------------ | ---------------------------------------------------------------------- |
|
|
91
|
+
| `unsupported` | `kind`, `snapshot` | a snapshot was written by a newer drizzle-kit and cannot be read |
|
|
92
|
+
| `malformed` | `kind`, `snapshot` | a snapshot could not be parsed |
|
|
93
|
+
| `non_latest` | `kind`, `snapshot` | a snapshot is not at the latest internal version and must be upgraded |
|
|
94
|
+
| `conflicts` | `kind`, `conflicts`, `details` | branches in the migrations folder do not commute (run without `--ignore-conflicts`) |
|
|
95
|
+
|
|
96
|
+
For the integrity kinds, `snapshot` names the offending file. For `conflicts`, `conflicts` is the count and `details` is an array of length `conflicts`; each entry is `{ parentId, parentPath?, branches }` where `branches` is always a two-element array of `{ leafId, leafPath, statementDescription }` describing the two diverging branches off the common parent. `leafId` / `leafPath` are `null` when a branch chain is empty.
|
|
97
|
+
|
|
98
|
+
## Decoding pattern (CLI + SDK)
|
|
99
|
+
|
|
100
|
+
Narrow on `status` and then on `error.code`:
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
import { generate } from 'drizzle-kit';
|
|
104
|
+
|
|
105
|
+
const response = await generate({ dialect: 'postgresql', schema: './src/db/schema.ts', out: './drizzle' });
|
|
106
|
+
|
|
107
|
+
switch (response.status) {
|
|
108
|
+
case 'ok':
|
|
109
|
+
// response.dialect is present; response.migration_path when not in explain mode
|
|
110
|
+
break;
|
|
111
|
+
case 'no_changes':
|
|
112
|
+
// response.dialect is present; nothing to do
|
|
113
|
+
break;
|
|
114
|
+
case 'missing_hints':
|
|
115
|
+
// response.unresolved holds the items to resolve (see drizzle-hints)
|
|
116
|
+
break;
|
|
117
|
+
case 'error':
|
|
118
|
+
switch (response.error.code) {
|
|
119
|
+
case 'config_file_not_found_error':
|
|
120
|
+
// response.error.path
|
|
121
|
+
break;
|
|
122
|
+
case 'invalid_hints':
|
|
123
|
+
// response.error.source, response.error.issues, etc.
|
|
124
|
+
break;
|
|
125
|
+
case 'check_error':
|
|
126
|
+
// migrations-folder pre-flight gate failed; response.error.kind, response.error.snapshot / conflicts / details
|
|
127
|
+
break;
|
|
128
|
+
// ...other codes from the table above
|
|
129
|
+
}
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
CLI equivalent — parse `stdout` as JSON, switch on `response.status` the same way. Exit codes map: `exit 0` for `ok` / `no_changes`, `exit 1` for `error`, `exit 2` for `missing_hints`.
|
|
135
|
+
|
|
136
|
+
## Troubleshooting
|
|
137
|
+
|
|
138
|
+
Common failure modes and their fixes — keyed by `error.code` / `meta.kind`:
|
|
139
|
+
|
|
140
|
+
- `config_file_not_found_error` — `meta.path` names the missing file. Pass `--config <path>` (CLI) or point the SDK call's `configPath` at the right location; the default lookup is `drizzle.config.ts` in CWD.
|
|
141
|
+
- `schema_files_not_found_error` — `meta.paths` lists the globs that resolved to nothing. Use a concrete `.ts` extension in the path, or expand the glob to cover the directory the schema lives in.
|
|
142
|
+
- `config_validation_error` — `meta.issues` carries a zod-style array (`path`, `message`). Fix the named fields in `drizzle.config.ts`; the most common cause is a missing `dialect` or a `dbCredentials` block whose shape doesn't match the dialect.
|
|
143
|
+
- `missing_required_params_error` — `meta.params` names the missing fields (e.g. `['dialect']`). Add them via config or CLI flag.
|
|
144
|
+
- `ambiguous_params_error` — a flag and a `defineConfig` field both set the same value. Pick one source of truth — `meta.command` plus `meta.configOption` name the conflict.
|
|
145
|
+
- `config_connection_error` — the `dbCredentials` keys don't match what `meta.driver` expects. `meta.params` lists the keys the driver needs. Reshape `dbCredentials` accordingly.
|
|
146
|
+
- `database_driver_error` — driver could not connect. `meta.packages` lists the npm packages required for the driver; install them. `meta.note` may carry a connection-specific hint (e.g. SSL). Beyond `push`, this also fires from `pull`'s connect/introspect span and the `--init` migrate span — the meta is always the redacted `{ database, packages, note? }`; the connection string, SQL, and params are never spread into the envelope.
|
|
147
|
+
- `orm_version_error` — `meta.kind` discriminates: `orm_missing` (install `drizzle-orm`), `orm_too_old` (bump `drizzle-orm`), `kit_outdated` (bump `drizzle-kit` itself).
|
|
148
|
+
- `required_packages_error` — `meta.packages` lists the npm packages to install. Common for dialect drivers (`pg`, `mysql2`, `better-sqlite3`, `@libsql/client`, `mssql`).
|
|
149
|
+
- `unsupported_command_dialect_error` — the command isn't supported for `meta.dialect`. Use a different command or switch dialects.
|
|
150
|
+
- `migrations_outdated_error` — the migrations folder under `meta.out` uses an older snapshot format. Run `drizzle-kit up` to migrate the folder forward.
|
|
151
|
+
- `invalid_hints` — discriminated by which keys are present in `meta`: `path` means a file read failed, `issues` means schema validation failed, `kind` + `from` together mean a `rename` hint's `from` tuple did not match any deleted entity. For schema-validation failures, fix the named issues; for a `from` mismatch, correct the tuple (the entity must be one the diff would otherwise delete).
|
|
152
|
+
- `unsupported_schema_change` — refer to the variant table above; each variant has a specific remediation path.
|
|
153
|
+
- `query_error` — the live DB threw on `meta.sql` with `meta.params`. Run the same query manually against the target DB to surface the underlying DBMS error; fix the schema or the data.
|
|
154
|
+
- `internal_error` — an unexpected exception escaped. `meta.message` carries the underlying error text. File an issue if reproducible; the SDK never throws for known failures, only for genuine bugs.
|
|
155
|
+
|
|
156
|
+
For `missing_hints` (status, not an error code) — see the `drizzle-hints` skill for the resolve-and-retry loop. For workflow context — when to use `generate` vs `push`, how migrations folders work — see `drizzle-migrations`.
|
package/package.json
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@raypx-kit/drizzle-kit",
|
|
3
|
+
"version": "0.0.0-alpha.0",
|
|
4
|
+
"description": "drizzle-kit's CLI and defineConfig without the unused prebuilt API and payload bundles.",
|
|
5
|
+
"homepage": "https://github.com/raypx/raypx-kit/tree/canary/packages/drizzle-kit",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": {
|
|
8
|
+
"name": "Zack",
|
|
9
|
+
"email": "heyloyep@gmail.com"
|
|
10
|
+
},
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/raypx/raypx-kit.git",
|
|
14
|
+
"directory": "packages/drizzle-kit"
|
|
15
|
+
},
|
|
16
|
+
"bin": {
|
|
17
|
+
"drizzle-kit": "./dist/bin.cjs"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist",
|
|
21
|
+
"LICENSE",
|
|
22
|
+
"README.md",
|
|
23
|
+
"CHANGELOG.md"
|
|
24
|
+
],
|
|
25
|
+
"type": "module",
|
|
26
|
+
"sideEffects": false,
|
|
27
|
+
"exports": {
|
|
28
|
+
".": {
|
|
29
|
+
"import": {
|
|
30
|
+
"types": "./dist/index.d.mts",
|
|
31
|
+
"default": "./dist/index.mjs"
|
|
32
|
+
},
|
|
33
|
+
"require": {
|
|
34
|
+
"types": "./dist/index.d.ts",
|
|
35
|
+
"default": "./dist/index.js"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"publishConfig": {
|
|
40
|
+
"access": "public"
|
|
41
|
+
},
|
|
42
|
+
"scripts": {
|
|
43
|
+
"check": "bun --check --tsconfig-override tsconfig.json",
|
|
44
|
+
"test": "bun --bun vp test --run",
|
|
45
|
+
"test:unit": "bun --bun vp test --run --passWithNoTests --exclude '**/component.test.{ts,tsx}' --exclude '**/*.component.test.{ts,tsx}' --exclude '**/*.integration.test.{ts,tsx}'",
|
|
46
|
+
"test:integration": "bun --bun vp test --run --passWithNoTests integration.test",
|
|
47
|
+
"test:component": "bun --bun vp test --run --passWithNoTests component.test",
|
|
48
|
+
"test:coverage": "bun --bun vp test --run --passWithNoTests --coverage --coverage.reporter=text --coverage.reporter=json --coverage.reporter=lcov",
|
|
49
|
+
"build": "bun src/extract.ts",
|
|
50
|
+
"pack:check": "bun pm pack --dry-run --ignore-scripts"
|
|
51
|
+
},
|
|
52
|
+
"dependencies": {
|
|
53
|
+
"@drizzle-team/brocli": "^0.12.0",
|
|
54
|
+
"@js-temporal/polyfill": "^0.5.1",
|
|
55
|
+
"esbuild": "^0.25.10",
|
|
56
|
+
"get-tsconfig": "^4.13.6",
|
|
57
|
+
"jiti": "^2.6.1"
|
|
58
|
+
},
|
|
59
|
+
"devDependencies": {
|
|
60
|
+
"@types/semver": "^7.8.0",
|
|
61
|
+
"@vitest/coverage-v8": "^5.0.5",
|
|
62
|
+
"drizzle-kit": ">=1.0.0-rc.5-5935859 <1.0.0-rc.5-z",
|
|
63
|
+
"drizzle-orm": ">=1.0.0-rc.5-5935859 <1.0.0-rc.5-z",
|
|
64
|
+
"semver": "^7.8.5"
|
|
65
|
+
},
|
|
66
|
+
"engines": {
|
|
67
|
+
"node": ">=22.14"
|
|
68
|
+
}
|
|
69
|
+
}
|