@happyvertical/smrt-cli 0.41.0 → 0.42.1
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
CHANGED
|
@@ -14,6 +14,7 @@ smrt db:migrate # Apply migrations
|
|
|
14
14
|
smrt db:migrate --postgres-safe # PostgreSQL concurrent-index mode (see below)
|
|
15
15
|
smrt db:migrate --force-migration <exact-id> [--force-migration <exact-id>...] # Force exact generated migrations in one atomic batch
|
|
16
16
|
smrt db:migrate-uuid # Convert schema-declared UUID text columns after data remap
|
|
17
|
+
smrt db:migrate-int8 # Explicitly widen pre-#2373 int4 columns after preflight
|
|
17
18
|
smrt db:diff # Show schema differences without generating migration files
|
|
18
19
|
smrt db:rollback # Roll back migrations by executing their recorded DOWN
|
|
19
20
|
smrt db:rollback --mark-only # Record-only flip; schema deliberately untouched
|
|
@@ -95,6 +96,12 @@ not from the schema definition.
|
|
|
95
96
|
(`indexIntrospection: 'unavailable'`) rather than inventing missing indexes.
|
|
96
97
|
- The check is read-only and lives in a new core module; it does not share code
|
|
97
98
|
with `migrations/differ.ts`.
|
|
99
|
+
- PostgreSQL/DuckDB `int4` columns created before #2373 are advisory warnings,
|
|
100
|
+
not type drift: the differ intentionally treats int4/int8 as equivalent.
|
|
101
|
+
Run `smrt db:migrate-int8 --dry-run`, schedule the reported table rewrites,
|
|
102
|
+
then run `smrt db:migrate-int8`; SQLite is already 64-bit and is a no-op.
|
|
103
|
+
PostgreSQL uses the same bounded `migrations.postgres.lockTimeout` and
|
|
104
|
+
`statementTimeout` settings as ordinary schema migration.
|
|
98
105
|
|
|
99
106
|
## `db:migrate` on SQLite: type changes rebuild the table
|
|
100
107
|
|
|
@@ -20,6 +20,7 @@ import https from "node:https";
|
|
|
20
20
|
import { homedir, tmpdir } from "node:os";
|
|
21
21
|
import { extract } from "tar";
|
|
22
22
|
import { importWorkspaceModule } from "@happyvertical/smrt-core/utils/import-workspace-module";
|
|
23
|
+
import { buildIntegerWidthTableStatements, collectIntegerWidthTargets, parsePostgresTimeoutMs, preflightIntegerWidthWidening, widenIntegerColumnsToBigInt } from "@happyvertical/smrt-core/migrations";
|
|
23
24
|
import { buildArchitectureContext, buildKnowledgeIndex, buildReviewContext, checkKnowledgeFreshness, diffKnowledgeIndex, renderFreshnessResult, renderKnowledgeIndexMarkdown } from "@happyvertical/smrt-dev-mcp/knowledge";
|
|
24
25
|
//#region src/commands/db-command-utils.ts
|
|
25
26
|
var SENSITIVE_QUERY_PARAMS = /* @__PURE__ */ new Set([
|
|
@@ -6035,6 +6036,100 @@ var playgroundCommands = {
|
|
|
6035
6036
|
}
|
|
6036
6037
|
};
|
|
6037
6038
|
//#endregion
|
|
6039
|
+
//#region src/commands/db-migrate-int8.ts
|
|
6040
|
+
/**
|
|
6041
|
+
* db:migrate-int8 Command
|
|
6042
|
+
*
|
|
6043
|
+
* Explicitly widens legacy PostgreSQL/DuckDB int4 columns created before
|
|
6044
|
+
* #2373. This is deliberately separate from `db:migrate`: PostgreSQL rewrites
|
|
6045
|
+
* each table, so an operator must review the row-count preflight and schedule
|
|
6046
|
+
* a maintenance window before opting in.
|
|
6047
|
+
*/
|
|
6048
|
+
var BACKFILL_NAME = "@happyvertical/smrt-core:integer-width:v1";
|
|
6049
|
+
var DEFAULT_POSTGRES_LOCK_TIMEOUT_MS = 3e4;
|
|
6050
|
+
var DEFAULT_POSTGRES_STATEMENT_TIMEOUT_MS = 6e4;
|
|
6051
|
+
var dbMigrateInt8Command = {
|
|
6052
|
+
name: "db:migrate-int8",
|
|
6053
|
+
description: "Widen legacy SMRT int4 columns to BIGINT after reviewing the maintenance-window preflight. Run after db:migrate.",
|
|
6054
|
+
aliases: ["migrate-int8", "db-migrate-int8"],
|
|
6055
|
+
args: [],
|
|
6056
|
+
options: {
|
|
6057
|
+
"dry-run": {
|
|
6058
|
+
type: "boolean",
|
|
6059
|
+
description: "Print the preflight and ALTER statements without writing.",
|
|
6060
|
+
default: false
|
|
6061
|
+
},
|
|
6062
|
+
verbose: {
|
|
6063
|
+
type: "boolean",
|
|
6064
|
+
description: "Print the full per-table preflight report.",
|
|
6065
|
+
default: false,
|
|
6066
|
+
short: "v"
|
|
6067
|
+
}
|
|
6068
|
+
},
|
|
6069
|
+
handler: async (_args, options) => {
|
|
6070
|
+
let db;
|
|
6071
|
+
const dryRun = Boolean(options["dry-run"]);
|
|
6072
|
+
try {
|
|
6073
|
+
const { getPackageConfig } = await import("@happyvertical/smrt-config");
|
|
6074
|
+
const { DEFAULT_CLI_CONFIG } = await import("./config-BwrFRL8L.js");
|
|
6075
|
+
const config = getPackageConfig("cli", DEFAULT_CLI_CONFIG);
|
|
6076
|
+
if (!config.database?.url || config.database.url === ":memory:") throw new Error("Database configuration required for db:migrate-int8. Configure database.url in smrt.config.ts (or DATABASE_URL).");
|
|
6077
|
+
await autoDiscoverAndLoad();
|
|
6078
|
+
const schemas = ObjectRegistry.getAllSchemasAsDefinitions();
|
|
6079
|
+
if (Object.keys(schemas).length === 0) throw new Error("No SMRT application schemas were discovered. Run this command from the project root after generating manifests.");
|
|
6080
|
+
const dbType = config.database.type || "sqlite";
|
|
6081
|
+
const dbUrl = config.database.url;
|
|
6082
|
+
const { getDatabase } = await import("@happyvertical/sql");
|
|
6083
|
+
db = await getDatabase({
|
|
6084
|
+
type: dbType,
|
|
6085
|
+
url: dbUrl
|
|
6086
|
+
});
|
|
6087
|
+
console.log("\n↔️ Integer-width migration\n");
|
|
6088
|
+
console.log(`✓ Connected to ${formatDatabaseDisplayUrl(dbType, dbUrl)}\n`);
|
|
6089
|
+
const targets = collectIntegerWidthTargets(schemas, { includeSystemTables: true });
|
|
6090
|
+
const preflight = await preflightIntegerWidthWidening(db, targets, { engineHint: dbType });
|
|
6091
|
+
console.log(preflight.summary);
|
|
6092
|
+
if (options.verbose && preflight.supported) {
|
|
6093
|
+
console.log("\nFull preflight report:");
|
|
6094
|
+
for (const table of preflight.tables) {
|
|
6095
|
+
const columns = table.columns.map((column) => `${column.column}: ${column.declaredType ?? "missing"} (${column.state})`).join(", ");
|
|
6096
|
+
console.log(` ${table.table}: ${table.rowCount ?? "not counted"} row(s); ${columns}`);
|
|
6097
|
+
}
|
|
6098
|
+
}
|
|
6099
|
+
if (!preflight.supported) {
|
|
6100
|
+
console.log("\nNo widening is needed on this engine.\n");
|
|
6101
|
+
return;
|
|
6102
|
+
}
|
|
6103
|
+
if (preflight.unexpectedColumns > 0) throw new Error("Some schema-declared integer columns have unexpected live types. Resolve ordinary schema drift before this widening pass.");
|
|
6104
|
+
if (preflight.pendingColumns === 0) {
|
|
6105
|
+
console.log("\nNo legacy int4 columns remain.\n");
|
|
6106
|
+
return;
|
|
6107
|
+
}
|
|
6108
|
+
const statements = preflight.tables.flatMap((table) => buildIntegerWidthTableStatements(preflight.engine, table.table, table.columns.filter((column) => column.state === "pending").map((column) => column.column)));
|
|
6109
|
+
console.log(`\n${dryRun ? "DRY RUN — would execute" : "Applying"} ${statements.length} lossless ALTER statement(s):`);
|
|
6110
|
+
for (const statement of statements) console.log(` ${statement};`);
|
|
6111
|
+
if (dryRun) {
|
|
6112
|
+
console.log("\nDry run complete — no changes applied.\n");
|
|
6113
|
+
return;
|
|
6114
|
+
}
|
|
6115
|
+
const postgresMigrationConfig = config.migrations?.postgres;
|
|
6116
|
+
const result = await widenIntegerColumnsToBigInt(db, targets, {
|
|
6117
|
+
engineHint: dbType,
|
|
6118
|
+
backfillName: BACKFILL_NAME,
|
|
6119
|
+
packageName: "@happyvertical/smrt-core",
|
|
6120
|
+
lockTimeout: parsePostgresTimeoutMs(postgresMigrationConfig?.lockTimeout, DEFAULT_POSTGRES_LOCK_TIMEOUT_MS),
|
|
6121
|
+
statementTimeout: parsePostgresTimeoutMs(postgresMigrationConfig?.statementTimeout, DEFAULT_POSTGRES_STATEMENT_TIMEOUT_MS)
|
|
6122
|
+
});
|
|
6123
|
+
console.log(result.ran ? `\n✓ Widened ${result.widenedColumns.length} column(s) to BIGINT.\n` : "\nNo widening was applied; no legacy int4 columns remain.\n");
|
|
6124
|
+
} catch (error) {
|
|
6125
|
+
console.error(`\n❌ int8 migration failed: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
6126
|
+
process.exitCode = 1;
|
|
6127
|
+
} finally {
|
|
6128
|
+
await closeDatabaseConnection(db);
|
|
6129
|
+
}
|
|
6130
|
+
}
|
|
6131
|
+
};
|
|
6132
|
+
//#endregion
|
|
6038
6133
|
//#region src/commands/db-migrate-uuid.ts
|
|
6039
6134
|
/**
|
|
6040
6135
|
* db:migrate-uuid Command
|
|
@@ -8714,6 +8809,7 @@ export default testManifest;
|
|
|
8714
8809
|
"db:rollback": dbRollbackCommand,
|
|
8715
8810
|
"db:generate": dbGenerateCommand,
|
|
8716
8811
|
"db:migrate-uuid": dbMigrateUuidCommand,
|
|
8812
|
+
"db:migrate-int8": dbMigrateInt8Command,
|
|
8717
8813
|
"db:prune": dbPruneCommand,
|
|
8718
8814
|
"config:export": configExportCommand,
|
|
8719
8815
|
export: exportCommand
|
package/dist/index.js
CHANGED
|
@@ -49,63 +49,63 @@ var _playgroundCommands = null;
|
|
|
49
49
|
var _workbenchCommands = null;
|
|
50
50
|
async function getGnodeCommands() {
|
|
51
51
|
if (!_gnodeCommands) {
|
|
52
|
-
const { gnodeCommands } = await import("./commands-
|
|
52
|
+
const { gnodeCommands } = await import("./commands-BOw91sjd.js");
|
|
53
53
|
_gnodeCommands = gnodeCommands;
|
|
54
54
|
}
|
|
55
55
|
return _gnodeCommands;
|
|
56
56
|
}
|
|
57
57
|
async function getGitCommands() {
|
|
58
58
|
if (!_gitCommands) {
|
|
59
|
-
const { gitCommands } = await import("./commands-
|
|
59
|
+
const { gitCommands } = await import("./commands-BOw91sjd.js");
|
|
60
60
|
_gitCommands = gitCommands;
|
|
61
61
|
}
|
|
62
62
|
return _gitCommands;
|
|
63
63
|
}
|
|
64
64
|
async function getGenerateCommands() {
|
|
65
65
|
if (!_generateCommands) {
|
|
66
|
-
const { generateCommands } = await import("./commands-
|
|
66
|
+
const { generateCommands } = await import("./commands-BOw91sjd.js");
|
|
67
67
|
_generateCommands = generateCommands;
|
|
68
68
|
}
|
|
69
69
|
return _generateCommands;
|
|
70
70
|
}
|
|
71
71
|
async function getInitCommands() {
|
|
72
72
|
if (!_initCommands) {
|
|
73
|
-
const { initCommands } = await import("./commands-
|
|
73
|
+
const { initCommands } = await import("./commands-BOw91sjd.js");
|
|
74
74
|
_initCommands = initCommands;
|
|
75
75
|
}
|
|
76
76
|
return _initCommands;
|
|
77
77
|
}
|
|
78
78
|
async function getUtilityCommands() {
|
|
79
79
|
if (!_utilityCommands) {
|
|
80
|
-
const { utilityCommands } = await import("./commands-
|
|
80
|
+
const { utilityCommands } = await import("./commands-BOw91sjd.js");
|
|
81
81
|
_utilityCommands = utilityCommands;
|
|
82
82
|
}
|
|
83
83
|
return _utilityCommands;
|
|
84
84
|
}
|
|
85
85
|
async function getDispatchCommands() {
|
|
86
86
|
if (!_dispatchCommands) {
|
|
87
|
-
const { dispatchCommands } = await import("./commands-
|
|
87
|
+
const { dispatchCommands } = await import("./commands-BOw91sjd.js");
|
|
88
88
|
_dispatchCommands = dispatchCommands;
|
|
89
89
|
}
|
|
90
90
|
return _dispatchCommands;
|
|
91
91
|
}
|
|
92
92
|
async function getDocsCommands() {
|
|
93
93
|
if (!_docsCommands) {
|
|
94
|
-
const { docsCommands } = await import("./commands-
|
|
94
|
+
const { docsCommands } = await import("./commands-BOw91sjd.js");
|
|
95
95
|
_docsCommands = docsCommands;
|
|
96
96
|
}
|
|
97
97
|
return _docsCommands;
|
|
98
98
|
}
|
|
99
99
|
async function getPlaygroundCommands() {
|
|
100
100
|
if (!_playgroundCommands) {
|
|
101
|
-
const { playgroundCommands } = await import("./commands-
|
|
101
|
+
const { playgroundCommands } = await import("./commands-BOw91sjd.js");
|
|
102
102
|
_playgroundCommands = playgroundCommands;
|
|
103
103
|
}
|
|
104
104
|
return _playgroundCommands;
|
|
105
105
|
}
|
|
106
106
|
async function getWorkbenchCommands() {
|
|
107
107
|
if (!_workbenchCommands) {
|
|
108
|
-
const { workbenchCommands } = await import("./commands-
|
|
108
|
+
const { workbenchCommands } = await import("./commands-BOw91sjd.js");
|
|
109
109
|
_workbenchCommands = workbenchCommands;
|
|
110
110
|
}
|
|
111
111
|
return _workbenchCommands;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@happyvertical/smrt-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.42.1",
|
|
4
4
|
"description": "Developer CLI for SMRT framework - introspection, testing, and project management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -32,12 +32,12 @@
|
|
|
32
32
|
"acorn": "^8.17.0",
|
|
33
33
|
"fast-glob": "3.3.3",
|
|
34
34
|
"tar": "^7.5.19",
|
|
35
|
-
"@happyvertical/smrt-agents": "0.
|
|
36
|
-
"@happyvertical/smrt-
|
|
37
|
-
"@happyvertical/smrt-
|
|
38
|
-
"@happyvertical/smrt-
|
|
39
|
-
"@happyvertical/smrt-
|
|
40
|
-
"@happyvertical/smrt-playground": "0.
|
|
35
|
+
"@happyvertical/smrt-agents": "0.42.1",
|
|
36
|
+
"@happyvertical/smrt-core": "0.42.1",
|
|
37
|
+
"@happyvertical/smrt-config": "0.42.1",
|
|
38
|
+
"@happyvertical/smrt-types": "0.42.1",
|
|
39
|
+
"@happyvertical/smrt-dev-mcp": "0.42.1",
|
|
40
|
+
"@happyvertical/smrt-playground": "0.42.1"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/node": "24.13.2",
|