@happyvertical/smrt-cli 0.40.69 → 0.40.70
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/AGENTS.md +110 -1
- package/README.md +2 -1
- package/dist/{commands-U7gYv14z.js → commands-Df9OZ6tG.js} +1036 -337
- package/dist/index.js +9 -9
- package/package.json +7 -7
package/AGENTS.md
CHANGED
|
@@ -7,12 +7,16 @@ Developer CLI with lazy-loaded commands, manifest discovery, and class introspec
|
|
|
7
7
|
```
|
|
8
8
|
smrt introspect # Discover SMRT objects in project
|
|
9
9
|
smrt doctor # Umbrella diagnostics; can verify a generation snapshot
|
|
10
|
+
smrt doctor --db # Add the live-schema parity section (see below)
|
|
10
11
|
smrt db:status # Pending schema changes + failed migration classification
|
|
12
|
+
smrt db:status --parity # Same, plus live-schema parity (see below)
|
|
11
13
|
smrt db:migrate # Apply migrations
|
|
14
|
+
smrt db:migrate --postgres-safe # PostgreSQL concurrent-index mode (see below)
|
|
12
15
|
smrt db:migrate --force-migration <exact-id> [--force-migration <exact-id>...] # Force exact generated migrations in one atomic batch
|
|
13
16
|
smrt db:migrate-uuid # Convert schema-declared UUID text columns after data remap
|
|
14
17
|
smrt db:diff # Show schema differences without generating migration files
|
|
15
|
-
smrt db:rollback #
|
|
18
|
+
smrt db:rollback # Roll back migrations by executing their recorded DOWN
|
|
19
|
+
smrt db:rollback --mark-only # Record-only flip; schema deliberately untouched
|
|
16
20
|
smrt docs:agents # Generate .agents/smrt-framework.md
|
|
17
21
|
smrt docs:claude # Deprecated alias writing .claude/smrt-framework.md
|
|
18
22
|
smrt dev:knowledge-* # Deterministic agent knowledge index/check/diff
|
|
@@ -34,6 +38,107 @@ migrations are manifest-driven through registered objects and project manifests.
|
|
|
34
38
|
|
|
35
39
|
`smrt test` is **deprecated** — use vitest plugin directly.
|
|
36
40
|
|
|
41
|
+
## `db:migrate` on PostgreSQL
|
|
42
|
+
|
|
43
|
+
`db:migrate` always bounds a PostgreSQL batch with `SET LOCAL lock_timeout` and
|
|
44
|
+
`SET LOCAL statement_timeout` inside its transaction, from
|
|
45
|
+
`migrations.postgres.lockTimeout` / `.statementTimeout` (defaults `30s` / `60s`;
|
|
46
|
+
accepts `ms`/`s`/`min`/`h` suffixes, and `0` disables as PostgreSQL defines it).
|
|
47
|
+
A migration queued behind a long-running writer therefore fails fast and rolls
|
|
48
|
+
back instead of holding the locks it already took against every writer.
|
|
49
|
+
|
|
50
|
+
`--postgres-safe` selects **concurrent-index mode**: non-index DDL still commits
|
|
51
|
+
in one transaction, then each index statement runs
|
|
52
|
+
`CREATE INDEX CONCURRENTLY` / `DROP INDEX CONCURRENTLY` on one pinned session
|
|
53
|
+
after that commit. This is the mode for large index rollouts.
|
|
54
|
+
|
|
55
|
+
- **Concurrent mode is not atomic.** Committed column/table changes survive a
|
|
56
|
+
later index failure; unfinished index migrations are recorded `failed`, and
|
|
57
|
+
`db:migrate` (which reconciles) retries them on the next run. The retry
|
|
58
|
+
resumes at the index build — their `error_message` carries a
|
|
59
|
+
`[smrt: concurrent-index phase 1 committed]` marker, so the non-index
|
|
60
|
+
statements that already committed are not re-run.
|
|
61
|
+
- INVALID indexes — the stump a cancelled or timed-out
|
|
62
|
+
`CREATE INDEX CONCURRENTLY` leaves, which `pg_indexes` still reports as
|
|
63
|
+
present — are detected via `pg_index.indisvalid` and dropped before the
|
|
64
|
+
rebuild.
|
|
65
|
+
- `migrations.postgres.useConcurrently: false` vetoes the flag; index DDL then
|
|
66
|
+
runs inside the atomic transaction (still bounded by the timeouts).
|
|
67
|
+
- Without the flag, a batch containing explicit `CONCURRENTLY` DDL is rejected
|
|
68
|
+
before the transaction opens — PostgreSQL cannot run it there.
|
|
69
|
+
|
|
70
|
+
## Live-schema parity (#2368)
|
|
71
|
+
|
|
72
|
+
`doctor --db` and `db:status --parity` share `src/commands/db-parity.ts`, which
|
|
73
|
+
runs core's `checkLiveSchemaParity()`. This answers a different question than
|
|
74
|
+
`db:status`/`db:diff`: those compare the live database to the **manifest**, i.e.
|
|
75
|
+
to the artifact that dropped the index in the first place, which is why a
|
|
76
|
+
database missing 164 tenant-column indexes reported "in sync" (#2356).
|
|
77
|
+
|
|
78
|
+
Expected shape comes from the manifest schemas, the hand-DDL `_smrt_*` system
|
|
79
|
+
tables (parsed by core's `system-table-shapes.ts` — they are in no manifest and
|
|
80
|
+
enter no diff), and an index policy that consults no manifest at all: every
|
|
81
|
+
foreign-key/cross-package-ref/tenant column leads an index, every registry
|
|
82
|
+
conflict target has a matching UNIQUE index, every `unique: true` column is
|
|
83
|
+
unique live. Conflict targets come from `ObjectRegistry.getConflictColumns()`,
|
|
84
|
+
not from the schema definition.
|
|
85
|
+
|
|
86
|
+
- Severity is the contract: `error` fails the command (missing table/column,
|
|
87
|
+
type drift, orphan NOT NULL, conflict target unindexed or non-unique,
|
|
88
|
+
PostgreSQL INVALID index), `warning` does not (index coverage), `info` is
|
|
89
|
+
hidden without `--verbose` (undeclared tables/columns/indexes).
|
|
90
|
+
- Both surfaces **fail closed**: an unreachable database, or an adapter with no
|
|
91
|
+
`getTableSchema`, is an error, never a silent pass. Where index metadata
|
|
92
|
+
cannot be read at all, index checks are skipped and the report says so
|
|
93
|
+
(`indexIntrospection: 'unavailable'`) rather than inventing missing indexes.
|
|
94
|
+
- The check is read-only and lives in a new core module; it does not share code
|
|
95
|
+
with `migrations/differ.ts`.
|
|
96
|
+
|
|
97
|
+
## `db:migrate` on SQLite: type changes rebuild the table
|
|
98
|
+
|
|
99
|
+
SQLite has no `ALTER COLUMN ... TYPE`, so a type-bucket change (the common one
|
|
100
|
+
being a numeric default edited `0` → `0.0`) is applied as the documented table
|
|
101
|
+
rebuild — stage, copy, drop, rename, replay indexes and triggers — planned by
|
|
102
|
+
`smrt-core`'s `migrations/sqlite-rebuild.ts` and executed inside the same
|
|
103
|
+
atomic batch as everything else. It is no longer a "manual intervention" that
|
|
104
|
+
makes `db:migrate` exit 1 on every run (#2370). All drifted columns of one
|
|
105
|
+
table are fixed by one rebuild; `--dry-run` prints the whole statement list.
|
|
106
|
+
|
|
107
|
+
The rebuild refuses — and the column stays manual drift — when another table
|
|
108
|
+
declares a foreign key onto the target while `PRAGMA foreign_keys` is ON,
|
|
109
|
+
because `DROP TABLE` would fire those children's `ON DELETE` actions. Fix that
|
|
110
|
+
one by hand (or against a connection with enforcement disabled).
|
|
111
|
+
|
|
112
|
+
## `db:rollback` is execute-or-refuse
|
|
113
|
+
|
|
114
|
+
Schema state is diff-driven: `db:migrate` derives every migration from the
|
|
115
|
+
manifest at run time and stores **no SQL** in `_smrt_schema_migrations`. So
|
|
116
|
+
`db:rollback` can only honour the one DOWN script that is reconstructible from
|
|
117
|
+
a tracking row — `create_table_<table>` → `DROP TABLE IF EXISTS "<table>"`,
|
|
118
|
+
the exact statement `db:migrate` records for `diff.added_tables`.
|
|
119
|
+
|
|
120
|
+
- Rows with a reconstructible DOWN are **executed** through
|
|
121
|
+
`MigrationTracker.rollback` (transactional), then marked `rolled_back`.
|
|
122
|
+
- Anything else is **refused**: non-zero exit, an error naming each migration
|
|
123
|
+
and why, and no row touched. Refusal is all-or-nothing across the selected
|
|
124
|
+
set — a partial revert would leave the chain in a state the remaining DOWN
|
|
125
|
+
scripts were not written against. This includes rows recorded
|
|
126
|
+
`is_reversible` under a caller-chosen name: reversible at apply time, but the
|
|
127
|
+
SQL was never persisted, so it cannot be replayed (#2378).
|
|
128
|
+
- `--mark-only` is the explicit opt-in for the record-only flip (for an
|
|
129
|
+
operator who already reverted the schema by hand). It says in its own output
|
|
130
|
+
that the schema was not changed, and it is the only path that moves a row
|
|
131
|
+
without running DDL.
|
|
132
|
+
- A failed DOWN stops the batch; the migrations behind it are reported
|
|
133
|
+
`Not attempted` and left `completed`.
|
|
134
|
+
- `--dry-run` previews the DOWN statements and still exits non-zero when the
|
|
135
|
+
real run would refuse. Both `--dry-run` and `--mark-only` are declared
|
|
136
|
+
kebab-cased, so handlers must read `options['dry-run']` / `options['mark-only']`
|
|
137
|
+
(`parseCliArgs` returns keys verbatim — the #1385 data-loss class).
|
|
138
|
+
|
|
139
|
+
Reverting a non-`create_table` change is a forward operation: update the
|
|
140
|
+
`@smrt` object definitions and run `db:migrate` again.
|
|
141
|
+
|
|
37
142
|
## Architecture
|
|
38
143
|
|
|
39
144
|
- **Lazy command loading**: commands loaded on-demand via dynamic import (~100ms overhead on first use)
|
|
@@ -64,3 +169,7 @@ migrations are manifest-driven through registered objects and project manifests.
|
|
|
64
169
|
global when it appears before or without a subcommand (#2279). `--help` is
|
|
65
170
|
deliberately untouched.
|
|
66
171
|
- **Schema history nuance**: `db:status` / `db:history` should distinguish active live drift from superseded failed generated schema repairs instead of treating all failed rows as current blockers
|
|
172
|
+
- **Decorator check follows the Vite major**: doctor requires `oxc.decorator` in
|
|
173
|
+
vite.config on Vite 8+ and accepts tsconfig `experimentalDecorators` only
|
|
174
|
+
below it. The old unconditional tsconfig check flagged correct Vite 8 projects
|
|
175
|
+
and passed broken ones (#2368)
|
package/README.md
CHANGED
|
@@ -48,7 +48,8 @@ The four snapshot options are atomic: supplying any one requires all four.
|
|
|
48
48
|
| `smrt db:migrate --force-migration <exact-id> [--force-migration <exact-id>...]` | Force one or more exact generated migrations in one atomic batch while preserving every other guard |
|
|
49
49
|
| `smrt db:migrate-uuid` | Convert schema-declared UUID text columns to native PostgreSQL uuid after data has been remapped |
|
|
50
50
|
| `smrt db:diff` | Show schema differences without generating migration files |
|
|
51
|
-
| `smrt db:rollback` |
|
|
51
|
+
| `smrt db:rollback` | Roll back the last migration by executing its recorded DOWN script; refuses when no DOWN script exists |
|
|
52
|
+
| `smrt db:rollback --mark-only` | Record-only: mark migrations rolled back without running any DOWN script (schema untouched) |
|
|
52
53
|
| `smrt db:history` | Show migration history with active-vs-superseded failure classification |
|
|
53
54
|
|
|
54
55
|
File-backed SQL/TypeScript migration generation is not supported. s-m-r-t schema
|