@automagik/omni 2.260423.2 → 2.260423.4

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.
@@ -0,0 +1,45 @@
1
+ -- Issue #407: reconcile gupshup column drift.
2
+ --
3
+ -- Migration 0018_supreme_puma renamed three columns on "instances":
4
+ -- gupshup_api_key -> gupshup_callback_url
5
+ -- gupshup_app_name -> gupshup_auth_token
6
+ -- gupshup_source_phone -> gupshup_event_id
7
+ --
8
+ -- On at least one deployed DB the migration was marked applied in
9
+ -- drizzle.__drizzle_migrations but the rename never executed, leaving the
10
+ -- live table with the old column names. Because RENAME is not idempotent,
11
+ -- replaying 0018 would fail. This migration is safe to rerun: it adds the
12
+ -- new columns if missing, copies any surviving data from old columns, and
13
+ -- then drops the old columns if present.
14
+
15
+ ALTER TABLE "instances" ADD COLUMN IF NOT EXISTS "gupshup_callback_url" text;
16
+ ALTER TABLE "instances" ADD COLUMN IF NOT EXISTS "gupshup_auth_token" text;
17
+ ALTER TABLE "instances" ADD COLUMN IF NOT EXISTS "gupshup_event_id" varchar(255);
18
+
19
+ DO $$
20
+ BEGIN
21
+ IF EXISTS (
22
+ SELECT 1 FROM information_schema.columns
23
+ WHERE table_schema = 'public' AND table_name = 'instances' AND column_name = 'gupshup_api_key'
24
+ ) THEN
25
+ EXECUTE 'UPDATE "instances" SET "gupshup_callback_url" = "gupshup_api_key" WHERE "gupshup_callback_url" IS NULL AND "gupshup_api_key" IS NOT NULL';
26
+ END IF;
27
+
28
+ IF EXISTS (
29
+ SELECT 1 FROM information_schema.columns
30
+ WHERE table_schema = 'public' AND table_name = 'instances' AND column_name = 'gupshup_app_name'
31
+ ) THEN
32
+ EXECUTE 'UPDATE "instances" SET "gupshup_auth_token" = "gupshup_app_name" WHERE "gupshup_auth_token" IS NULL AND "gupshup_app_name" IS NOT NULL';
33
+ END IF;
34
+
35
+ IF EXISTS (
36
+ SELECT 1 FROM information_schema.columns
37
+ WHERE table_schema = 'public' AND table_name = 'instances' AND column_name = 'gupshup_source_phone'
38
+ ) THEN
39
+ EXECUTE 'UPDATE "instances" SET "gupshup_event_id" = "gupshup_source_phone" WHERE "gupshup_event_id" IS NULL AND "gupshup_source_phone" IS NOT NULL';
40
+ END IF;
41
+ END $$;
42
+
43
+ ALTER TABLE "instances" DROP COLUMN IF EXISTS "gupshup_api_key";
44
+ ALTER TABLE "instances" DROP COLUMN IF EXISTS "gupshup_app_name";
45
+ ALTER TABLE "instances" DROP COLUMN IF EXISTS "gupshup_source_phone";
@@ -218,6 +218,13 @@
218
218
  "when": 1777300000000,
219
219
  "tag": "0030_twilio_whatsapp_channel",
220
220
  "breakpoints": true
221
+ },
222
+ {
223
+ "idx": 31,
224
+ "version": "7",
225
+ "when": 1777400000000,
226
+ "tag": "0031_reconcile_gupshup_columns",
227
+ "breakpoints": true
221
228
  }
222
229
  ]
223
230
  }
@@ -15,6 +15,40 @@
15
15
  * omni providers test <id>
16
16
  * omni providers delete <id>
17
17
  */
18
+ import type { AgnoAgent, AgnoTeam, AgnoWorkflow } from '@omni/sdk';
18
19
  import { Command } from 'commander';
20
+ /**
21
+ * Map agno 2.5+ (`id`) and pre-2.5 (`agent_id`) agent shapes to the list row.
22
+ */
23
+ declare function mapAgnoAgentRow(a: AgnoAgent): {
24
+ id: string | undefined;
25
+ name: string;
26
+ model: string;
27
+ description: string;
28
+ };
29
+ /**
30
+ * Map agno 2.5+ (`id`) and pre-2.5 (`team_id`) team shapes to the list row.
31
+ */
32
+ declare function mapAgnoTeamRow(t: AgnoTeam): {
33
+ id: string | undefined;
34
+ name: string;
35
+ mode: string;
36
+ members: number;
37
+ description: string;
38
+ };
39
+ /**
40
+ * Map agno 2.5+ (`id`) and pre-2.5 (`workflow_id`) workflow shapes to the list row.
41
+ */
42
+ declare function mapAgnoWorkflowRow(w: AgnoWorkflow): {
43
+ id: string | undefined;
44
+ name: string;
45
+ description: string;
46
+ };
47
+ export declare const __testables: {
48
+ mapAgnoAgentRow: typeof mapAgnoAgentRow;
49
+ mapAgnoTeamRow: typeof mapAgnoTeamRow;
50
+ mapAgnoWorkflowRow: typeof mapAgnoWorkflowRow;
51
+ };
19
52
  export declare function createProvidersCommand(): Command;
53
+ export {};
20
54
  //# sourceMappingURL=providers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../../src/commands/providers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiUpC,wBAAgB,sBAAsB,IAAI,OAAO,CA6JhD"}
1
+ {"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../../src/commands/providers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACnE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC;;GAEG;AACH,iBAAS,eAAe,CAAC,CAAC,EAAE,SAAS,GAAG;IACtC,EAAE,EAAE,MAAM,GAAG,SAAS,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACrB,CAOA;AAED;;GAEG;AACH,iBAAS,cAAc,CAAC,CAAC,EAAE,QAAQ,GAAG;IACpC,EAAE,EAAE,MAAM,GAAG,SAAS,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;CACrB,CAQA;AAED;;GAEG;AACH,iBAAS,kBAAkB,CAAC,CAAC,EAAE,YAAY,GAAG;IAC5C,EAAE,EAAE,MAAM,GAAG,SAAS,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB,CAMA;AAED,eAAO,MAAM,WAAW;;;;CAIvB,CAAC;AA6TF,wBAAgB,sBAAsB,IAAI,OAAO,CA8IhD"}
package/dist/index.js CHANGED
@@ -62070,10 +62070,14 @@ var init_migrate = __esm(() => {
62070
62070
  if (false) {}
62071
62071
  });
62072
62072
 
62073
+ // ../db/src/verify-schema.ts
62074
+ var init_verify_schema = () => {};
62075
+
62073
62076
  // ../db/src/index.ts
62074
62077
  var init_src3 = __esm(() => {
62075
62078
  init_client3();
62076
62079
  init_migrate();
62080
+ init_verify_schema();
62077
62081
  init_schema2();
62078
62082
  });
62079
62083
 
@@ -113839,7 +113843,7 @@ import { fileURLToPath } from "url";
113839
113843
  // package.json
113840
113844
  var package_default = {
113841
113845
  name: "@automagik/omni",
113842
- version: "2.260423.2",
113846
+ version: "2.260423.4",
113843
113847
  description: "LLM-optimized CLI for Omni",
113844
113848
  type: "module",
113845
113849
  bin: {
@@ -123139,6 +123143,30 @@ function createSetupCommand() {
123139
123143
  }
123140
123144
 
123141
123145
  // src/commands/providers.ts
123146
+ function mapAgnoAgentRow(a2) {
123147
+ return {
123148
+ id: a2.id ?? a2.agent_id,
123149
+ name: a2.name,
123150
+ model: a2.model?.name ?? "-",
123151
+ description: a2.description?.slice(0, 50) ?? "-"
123152
+ };
123153
+ }
123154
+ function mapAgnoTeamRow(t) {
123155
+ return {
123156
+ id: t.id ?? t.team_id,
123157
+ name: t.name,
123158
+ mode: t.mode ?? "-",
123159
+ members: t.members?.length ?? 0,
123160
+ description: t.description?.slice(0, 50) ?? "-"
123161
+ };
123162
+ }
123163
+ function mapAgnoWorkflowRow(w) {
123164
+ return {
123165
+ id: w.id ?? w.workflow_id,
123166
+ name: w.name,
123167
+ description: w.description?.slice(0, 50) ?? "-"
123168
+ };
123169
+ }
123142
123170
  var VALID_SCHEMAS = PROVIDER_SCHEMAS;
123143
123171
  var WS_ONLY_SCHEMAS = ["openclaw"];
123144
123172
  function validateUrlScheme(schema3, baseUrl) {
@@ -123401,12 +123429,7 @@ function createProvidersCommand() {
123401
123429
  const client = getClient();
123402
123430
  try {
123403
123431
  const agents2 = await client.providers.listAgents(resolvedId);
123404
- const items = agents2.map((a2) => ({
123405
- id: a2.agent_id,
123406
- name: a2.name,
123407
- model: a2.model?.name ?? "-",
123408
- description: a2.description?.slice(0, 50) ?? "-"
123409
- }));
123432
+ const items = agents2.map(mapAgnoAgentRow);
123410
123433
  list(items, { emptyMessage: "No agents found." });
123411
123434
  } catch (err2) {
123412
123435
  const message2 = err2 instanceof Error ? err2.message : "Unknown error";
@@ -123418,13 +123441,7 @@ function createProvidersCommand() {
123418
123441
  const client = getClient();
123419
123442
  try {
123420
123443
  const teams = await client.providers.listTeams(resolvedId);
123421
- const items = teams.map((t) => ({
123422
- id: t.team_id,
123423
- name: t.name,
123424
- mode: t.mode ?? "-",
123425
- members: t.members?.length ?? 0,
123426
- description: t.description?.slice(0, 50) ?? "-"
123427
- }));
123444
+ const items = teams.map(mapAgnoTeamRow);
123428
123445
  list(items, { emptyMessage: "No teams found." });
123429
123446
  } catch (err2) {
123430
123447
  const message2 = err2 instanceof Error ? err2.message : "Unknown error";
@@ -123436,11 +123453,7 @@ function createProvidersCommand() {
123436
123453
  const client = getClient();
123437
123454
  try {
123438
123455
  const workflows = await client.providers.listWorkflows(resolvedId);
123439
- const items = workflows.map((w) => ({
123440
- id: w.workflow_id,
123441
- name: w.name,
123442
- description: w.description?.slice(0, 50) ?? "-"
123443
- }));
123456
+ const items = workflows.map(mapAgnoWorkflowRow);
123444
123457
  list(items, { emptyMessage: "No workflows found." });
123445
123458
  } catch (err2) {
123446
123459
  const message2 = err2 instanceof Error ? err2.message : "Unknown error";
@@ -224464,7 +224464,7 @@ var init_sentry_scrub = __esm(() => {
224464
224464
  var require_package8 = __commonJS((exports, module) => {
224465
224465
  module.exports = {
224466
224466
  name: "@omni/api",
224467
- version: "2.260423.2",
224467
+ version: "2.260423.4",
224468
224468
  type: "module",
224469
224469
  exports: {
224470
224470
  ".": {
@@ -233528,10 +233528,68 @@ var init_migrate = __esm(() => {
233528
233528
  if (false) {}
233529
233529
  });
233530
233530
 
233531
+ // ../db/src/verify-schema.ts
233532
+ async function verifyCriticalColumns(db2, expectations) {
233533
+ if (expectations.length === 0) {
233534
+ return { ok: true, drift: [] };
233535
+ }
233536
+ const tables = expectations.map((e) => e.table);
233537
+ const rows = await db2.execute(sql`
233538
+ SELECT table_name, column_name
233539
+ FROM information_schema.columns
233540
+ WHERE table_schema = 'public'
233541
+ AND table_name IN (${sql.join(tables.map((t) => sql`${t}`), sql`, `)})
233542
+ `);
233543
+ const liveColumns = new Map;
233544
+ for (const row of rows) {
233545
+ const set = liveColumns.get(row.table_name) ?? new Set;
233546
+ set.add(row.column_name);
233547
+ liveColumns.set(row.table_name, set);
233548
+ }
233549
+ const drift = [];
233550
+ for (const expectation of expectations) {
233551
+ const live = liveColumns.get(expectation.table) ?? new Set;
233552
+ const missing = expectation.columns.filter((col) => !live.has(col));
233553
+ if (missing.length > 0) {
233554
+ drift.push({ table: expectation.table, missing });
233555
+ }
233556
+ }
233557
+ return { ok: drift.length === 0, drift };
233558
+ }
233559
+ function formatDriftReport(report) {
233560
+ if (report.ok)
233561
+ return "Schema drift check passed.";
233562
+ const lines = [
233563
+ "Schema drift detected \u2014 live database is missing columns Drizzle expects.",
233564
+ "This usually means drizzle-kit push was used against a migrated database,",
233565
+ "or a migration was marked applied but its SQL did not execute.",
233566
+ ""
233567
+ ];
233568
+ for (const entry of report.drift) {
233569
+ lines.push(` table "${entry.table}" missing columns: ${entry.missing.join(", ")}`);
233570
+ }
233571
+ lines.push("");
233572
+ lines.push("Run `bun run db:verify-drift` locally against the same DATABASE_URL,");
233573
+ lines.push("then apply the reconcile migration (see issue #407).");
233574
+ return lines.join(`
233575
+ `);
233576
+ }
233577
+ var API_CRITICAL_COLUMNS;
233578
+ var init_verify_schema = __esm(() => {
233579
+ init_drizzle_orm();
233580
+ API_CRITICAL_COLUMNS = [
233581
+ {
233582
+ table: "instances",
233583
+ columns: ["gupshup_callback_url", "gupshup_auth_token", "gupshup_event_id"]
233584
+ }
233585
+ ];
233586
+ });
233587
+
233531
233588
  // ../db/src/index.ts
233532
233589
  var init_src5 = __esm(() => {
233533
233590
  init_client5();
233534
233591
  init_migrate();
233592
+ init_verify_schema();
233535
233593
  init_schema2();
233536
233594
  });
233537
233595
 
@@ -305428,6 +305486,20 @@ async function main() {
305428
305486
  throw error2;
305429
305487
  }
305430
305488
  log111.info("Database migrations complete", { durationMs: Date.now() - migrationStart });
305489
+ try {
305490
+ const driftReport = await verifyCriticalColumns(db3, API_CRITICAL_COLUMNS);
305491
+ if (!driftReport.ok) {
305492
+ log111.error(formatDriftReport(driftReport), { drift: driftReport.drift });
305493
+ await closeDb();
305494
+ await stopEmbeddedPgserve();
305495
+ process.exit(1);
305496
+ }
305497
+ } catch (error2) {
305498
+ log111.error("Schema drift check failed", { error: String(error2) });
305499
+ await closeDb();
305500
+ await stopEmbeddedPgserve();
305501
+ process.exit(1);
305502
+ }
305431
305503
  try {
305432
305504
  const [countRow] = await db3.select({ count: sql`count(*)::int` }).from(instances);
305433
305505
  const rowCount = countRow?.count ?? 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automagik/omni",
3
- "version": "2.260423.2",
3
+ "version": "2.260423.4",
4
4
  "description": "LLM-optimized CLI for Omni",
5
5
  "type": "module",
6
6
  "bin": {
@@ -39,15 +39,15 @@
39
39
  "qrcode-terminal": "^0.12.0"
40
40
  },
41
41
  "devDependencies": {
42
- "@omni/api": "2.260423.1",
43
- "@omni/channel-discord": "2.260423.1",
44
- "@omni/channel-gupshup": "2.260423.1",
45
- "@omni/channel-sdk": "2.260423.1",
46
- "@omni/channel-slack": "2.260423.1",
47
- "@omni/channel-telegram": "2.260423.1",
48
- "@omni/channel-whatsapp": "2.260423.1",
49
- "@omni/core": "2.260423.1",
50
- "@omni/sdk": "2.260423.1",
42
+ "@omni/api": "2.260423.3",
43
+ "@omni/channel-discord": "2.260423.3",
44
+ "@omni/channel-gupshup": "2.260423.3",
45
+ "@omni/channel-sdk": "2.260423.3",
46
+ "@omni/channel-slack": "2.260423.3",
47
+ "@omni/channel-telegram": "2.260423.3",
48
+ "@omni/channel-whatsapp": "2.260423.3",
49
+ "@omni/core": "2.260423.3",
50
+ "@omni/sdk": "2.260423.3",
51
51
  "@types/node": "^22.10.3",
52
52
  "@types/qrcode-terminal": "^0.12.2",
53
53
  "typescript": "^5.7.3"