From e7950d968b873a87e899d61b41b7e553aaaffecd Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 1 Aug 2026 08:39:42 -0700 Subject: [PATCH] refactor(state): inline canonical database schemas at build (#117433) --- docs/refactor/database-first.md | 12 +- scripts/build-all.mjs | 1 + scripts/generate-kysely-types.mjs | 24 - src/commands/backup-sqlite.test.ts | 4 +- .../doctor-session-sqlite-recover-report.ts | 2 +- .../doctor-state-sqlite-compact.test.ts | 2 +- .../state-migrations.media-persistence.ts | 2 +- src/infra/tsdown-config.test.ts | 56 +- src/snapshot/local-repository.test.ts | 4 +- src/state/openclaw-agent-board-schema.ts | 2 +- src/state/openclaw-agent-db-maintenance.ts | 2 +- src/state/openclaw-agent-db-schema-helpers.ts | 2 +- src/state/openclaw-agent-db-schema.ts | 2 +- src/state/openclaw-agent-schema.generated.ts | 639 ----- src/state/openclaw-agent-schema.ts | 7 + ...claw-agent-standing-intents-schema.test.ts | 2 +- .../openclaw-agent-standing-intents-schema.ts | 2 +- .../openclaw-database-maintenance.test.ts | 4 +- src/state/openclaw-state-db-maintenance.ts | 2 +- ...ate-db-operator-approval-migration.test.ts | 2 +- ...aw-state-db-operator-approval-migration.ts | 2 +- src/state/openclaw-state-db.ts | 2 +- src/state/openclaw-state-schema.generated.ts | 2196 ----------------- src/state/openclaw-state-schema.ts | 7 + test/scripts/build-all.test.ts | 8 + tsdown.config.ts | 38 + 26 files changed, 141 insertions(+), 2885 deletions(-) delete mode 100644 src/state/openclaw-agent-schema.generated.ts create mode 100644 src/state/openclaw-agent-schema.ts delete mode 100644 src/state/openclaw-state-schema.generated.ts create mode 100644 src/state/openclaw-state-schema.ts diff --git a/docs/refactor/database-first.md b/docs/refactor/database-first.md index b1a8f46c3503..a6713569edde 100644 --- a/docs/refactor/database-first.md +++ b/docs/refactor/database-first.md @@ -183,7 +183,7 @@ without exceptions outside doctor/import/export/debug boundaries. - [x] Keep Kysely generated types aligned after any schema change. Files: `src/state/openclaw-state-schema.sql`, `src/state/openclaw-agent-schema.sql`, - `src/state/*generated*`. + `src/state/*-db.generated.d.ts`. Proof: no schema change in this pass; `pnpm db:kysely:check`; `pnpm lint:kysely`. - [x] Re-run focused tests for touched stores, commands, and scripts. @@ -296,12 +296,12 @@ The branch already has a real shared SQLite base: macOS runtime locator, CI, and public install docs all agree. - `src/state/openclaw-state-db.ts` opens `openclaw.sqlite`, sets WAL, `synchronous=NORMAL`, `busy_timeout=30000`, `foreign_keys=ON`, and applies - the generated schema module derived from + the build-inlined schema bytes derived from `src/state/openclaw-state-schema.sql`. -- Kysely table types and runtime schema modules are generated from disposable - SQLite databases created from the committed `.sql` files; runtime code no - longer keeps copy-pasted schema strings for global, per-agent, or proxy - capture databases. +- Kysely table types are generated from disposable SQLite databases created + from the committed `.sql` files. Source runs read those canonical files; + packaged builds inline the same bytes, so runtime code keeps no committed + copy-pasted schema strings or packaged SQL assets. - Runtime stores derive selected and inserted row types from those generated Kysely `DB` interfaces instead of shadowing SQLite row shapes by hand. Raw SQL remains limited to schema application, pragmas, and migration-only DDL. diff --git a/scripts/build-all.mjs b/scripts/build-all.mjs index 906aa05282c3..0234bd2a0471 100644 --- a/scripts/build-all.mjs +++ b/scripts/build-all.mjs @@ -31,6 +31,7 @@ const TSDOWN_SOURCE_EXTENSIONS = [ ".json5", ".mjs", ".mts", + ".sql", ".ts", ".tsx", ".yaml", diff --git a/scripts/generate-kysely-types.mjs b/scripts/generate-kysely-types.mjs index ceaefbcd5ef4..a2f0c0f5f3d4 100644 --- a/scripts/generate-kysely-types.mjs +++ b/scripts/generate-kysely-types.mjs @@ -10,15 +10,11 @@ const SCHEMAS = [ name: "openclaw-state", schema: "src/state/openclaw-state-schema.sql", outFile: "src/state/openclaw-state-db.generated.d.ts", - schemaOutFile: "src/state/openclaw-state-schema.generated.ts", - schemaExport: "OPENCLAW_STATE_SCHEMA_SQL", }, { name: "openclaw-agent", schema: "src/state/openclaw-agent-schema.sql", outFile: "src/state/openclaw-agent-db.generated.d.ts", - schemaOutFile: "src/state/openclaw-agent-schema.generated.ts", - schemaExport: "OPENCLAW_AGENT_SCHEMA_SQL", }, ]; @@ -118,39 +114,19 @@ function readUtf8(file) { return fs.readFileSync(file, "utf8"); } -function generatedSchemaModule(schema) { - const source = readUtf8(schema.schema).trimEnd(); - const literal = source.replaceAll("\\", "\\\\").replaceAll("`", "\\`").replaceAll("${", "\\${"); - return [ - "/**", - " * This file was generated from the SQLite schema source.", - " * Please do not edit it manually.", - " */", - "", - `export const ${schema.schemaExport} = \`${literal}\\n\`;`, - "", - ].join("\n"); -} - function generate(schema) { const db = new DatabaseSync(":memory:"); try { db.exec(readUtf8(schema.schema)); const typesSource = generateTypes(db); - const schemaSource = generatedSchemaModule(schema); if (verify) { if (typesSource !== readUtf8(schema.outFile)) { console.error(`${schema.outFile} is out of date. Run pnpm db:kysely:gen.`); process.exitCode = 1; } - if (schemaSource !== readUtf8(schema.schemaOutFile)) { - console.error(`${schema.schemaOutFile} is out of date. Run pnpm db:kysely:gen.`); - process.exitCode = 1; - } } else { fs.writeFileSync(schema.outFile, typesSource); - fs.writeFileSync(schema.schemaOutFile, schemaSource); } } finally { db.close(); diff --git a/src/commands/backup-sqlite.test.ts b/src/commands/backup-sqlite.test.ts index 0612a3715eab..0fcd32b36573 100644 --- a/src/commands/backup-sqlite.test.ts +++ b/src/commands/backup-sqlite.test.ts @@ -7,10 +7,10 @@ import type { RuntimeEnv } from "../runtime.js"; import { createLocalSqliteSnapshotProvider } from "../snapshot/local-repository.js"; import { OPENCLAW_AGENT_SCHEMA_VERSION } from "../state/openclaw-agent-db.js"; import { resolveOpenClawAgentSqlitePath } from "../state/openclaw-agent-db.paths.js"; -import { OPENCLAW_AGENT_SCHEMA_SQL } from "../state/openclaw-agent-schema.generated.js"; +import { OPENCLAW_AGENT_SCHEMA_SQL } from "../state/openclaw-agent-schema.js"; import { OPENCLAW_STATE_SCHEMA_VERSION } from "../state/openclaw-state-db.js"; import { resolveOpenClawStateSqlitePath } from "../state/openclaw-state-db.paths.js"; -import { OPENCLAW_STATE_SCHEMA_SQL } from "../state/openclaw-state-schema.generated.js"; +import { OPENCLAW_STATE_SCHEMA_SQL } from "../state/openclaw-state-schema.js"; import { backupSqliteCreateCommand, backupSqliteListCommand, diff --git a/src/commands/doctor-session-sqlite-recover-report.ts b/src/commands/doctor-session-sqlite-recover-report.ts index a40a9b7d7499..65e567b8f3a4 100644 --- a/src/commands/doctor-session-sqlite-recover-report.ts +++ b/src/commands/doctor-session-sqlite-recover-report.ts @@ -12,7 +12,7 @@ import { clearOpenClawAgentDatabaseOpenFailure, migrateOpenClawAgentDatabaseForMaintenance, } from "../state/openclaw-agent-db.js"; -import { OPENCLAW_AGENT_SCHEMA_SQL } from "../state/openclaw-agent-schema.generated.js"; +import { OPENCLAW_AGENT_SCHEMA_SQL } from "../state/openclaw-agent-schema.js"; import { OPENCLAW_SQLITE_BUSY_TIMEOUT_MS } from "../state/openclaw-state-db.js"; import { createSessionSqliteMigrationFailureIssue, diff --git a/src/commands/doctor-state-sqlite-compact.test.ts b/src/commands/doctor-state-sqlite-compact.test.ts index 811b8defd82e..5d6b36aa808c 100644 --- a/src/commands/doctor-state-sqlite-compact.test.ts +++ b/src/commands/doctor-state-sqlite-compact.test.ts @@ -14,7 +14,7 @@ import { OPENCLAW_STATE_SCHEMA_VERSION, } from "../state/openclaw-state-db.js"; import { resolveOpenClawStateSqlitePath } from "../state/openclaw-state-db.paths.js"; -import { OPENCLAW_STATE_SCHEMA_SQL } from "../state/openclaw-state-schema.generated.js"; +import { OPENCLAW_STATE_SCHEMA_SQL } from "../state/openclaw-state-schema.js"; import { runDoctorStateSqliteCompact } from "./doctor-state-sqlite-compact.js"; const tempDirs = useAutoCleanupTempDirTracker((cleanup) => { diff --git a/src/infra/state-migrations.media-persistence.ts b/src/infra/state-migrations.media-persistence.ts index fdd64ded670c..f138275c84ad 100644 --- a/src/infra/state-migrations.media-persistence.ts +++ b/src/infra/state-migrations.media-persistence.ts @@ -34,7 +34,7 @@ import { OPENCLAW_AGENT_SCHEMA_VERSION, type OpenClawAgentDatabase, } from "../state/openclaw-agent-db.js"; -import { OPENCLAW_AGENT_SCHEMA_SQL } from "../state/openclaw-agent-schema.generated.js"; +import { OPENCLAW_AGENT_SCHEMA_SQL } from "../state/openclaw-agent-schema.js"; import { OPENCLAW_SQLITE_BUSY_TIMEOUT_MS } from "../state/openclaw-state-db.js"; import { VERSION } from "../version.js"; import { repairGatewayAgentMediaMigrationStartupFailures } from "./gateway-boot-lifecycle.js"; diff --git a/src/infra/tsdown-config.test.ts b/src/infra/tsdown-config.test.ts index e5099f0ff659..bca176d32b01 100644 --- a/src/infra/tsdown-config.test.ts +++ b/src/infra/tsdown-config.test.ts @@ -1,8 +1,14 @@ // Covers bundling rules encoded in the root tsdown config. import { readFileSync } from "node:fs"; +import path from "node:path"; import { bundledPluginRoot } from "openclaw/plugin-sdk/test-fixtures"; import { describe, expect, it } from "vitest"; -import tsdownConfig from "../../tsdown.config.ts"; +import tsdownConfig, { + createStateSchemaInlinePlugin, + STATE_SCHEMA_INLINE_PLUGIN_NAME, +} from "../../tsdown.config.ts"; +import { OPENCLAW_AGENT_SCHEMA_SQL } from "../state/openclaw-agent-schema.js"; +import { OPENCLAW_STATE_SCHEMA_SQL } from "../state/openclaw-state-schema.js"; type TsdownConfigEntry = { deps?: { @@ -12,6 +18,7 @@ type TsdownConfigEntry = { entry?: Record | string[]; inputOptions?: TsdownInputOptions; outDir?: string; + plugins?: Array<{ name?: string }>; }; type TsdownLog = { @@ -87,6 +94,53 @@ function readAgentAuthDiscoverySource(): string { } describe("tsdown config", () => { + it.each([ + { + exportName: "OPENCLAW_STATE_SCHEMA_SQL", + modulePath: "src/state/openclaw-state-schema.ts", + schemaPath: "src/state/openclaw-state-schema.sql", + sourceValue: OPENCLAW_STATE_SCHEMA_SQL, + }, + { + exportName: "OPENCLAW_AGENT_SCHEMA_SQL", + modulePath: "src/state/openclaw-agent-schema.ts", + schemaPath: "src/state/openclaw-agent-schema.sql", + sourceValue: OPENCLAW_AGENT_SCHEMA_SQL, + }, + ])("inlines canonical schema bytes for $modulePath", (schema) => { + const rootDir = process.cwd(); + const watchedPaths: string[] = []; + const plugin = createStateSchemaInlinePlugin(rootDir); + const result = plugin.load.call( + { addWatchFile: (filePath: string) => watchedPaths.push(filePath) }, + path.resolve(rootDir, schema.modulePath), + ); + const schemaPath = path.resolve(rootDir, schema.schemaPath); + const canonicalSql = readFileSync(schemaPath, "utf8"); + + expect(result).not.toBeNull(); + const match = result?.code.match( + new RegExp(`^export const ${schema.exportName} = (.*);\\n$`, "su"), + ); + expect(match?.[1]).toBeDefined(); + expect(JSON.parse(match?.[1] ?? "null")).toBe(canonicalSql); + expect(schema.sourceValue).toBe(canonicalSql); + expect(watchedPaths).toEqual([schemaPath]); + }); + + it("installs schema inlining only on the unified runtime graph", () => { + const unifiedGraph = requireUnifiedDistGraph(); + const inlinePlugins = asConfigArray(tsdownConfig).flatMap( + (config) => + config.plugins?.filter((plugin) => plugin.name === STATE_SCHEMA_INLINE_PLUGIN_NAME) ?? [], + ); + + expect(unifiedGraph.plugins).toContainEqual( + expect.objectContaining({ name: STATE_SCHEMA_INLINE_PLUGIN_NAME }), + ); + expect(inlinePlugins).toHaveLength(1); + }); + it("keeps core, plugin runtime, plugin-sdk, bundled root plugins, and bundled hooks in one dist graph", () => { const distGraph = requireUnifiedDistGraph(); diff --git a/src/snapshot/local-repository.test.ts b/src/snapshot/local-repository.test.ts index 906c1a516d8d..e6799e1bbb69 100644 --- a/src/snapshot/local-repository.test.ts +++ b/src/snapshot/local-repository.test.ts @@ -8,9 +8,9 @@ import { requireNodeSqlite } from "../infra/node-sqlite.js"; import { createPrivateSqliteDirectory } from "../infra/sqlite-private-directory.js"; import { runExec } from "../process/exec.js"; import { OPENCLAW_AGENT_SCHEMA_VERSION } from "../state/openclaw-agent-db.js"; -import { OPENCLAW_AGENT_SCHEMA_SQL } from "../state/openclaw-agent-schema.generated.js"; +import { OPENCLAW_AGENT_SCHEMA_SQL } from "../state/openclaw-agent-schema.js"; import { OPENCLAW_STATE_SCHEMA_VERSION } from "../state/openclaw-state-db.js"; -import { OPENCLAW_STATE_SCHEMA_SQL } from "../state/openclaw-state-schema.generated.js"; +import { OPENCLAW_STATE_SCHEMA_SQL } from "../state/openclaw-state-schema.js"; import { hashSnapshotArtifact, readSnapshotManifest } from "./manifest.js"; import { SNAPSHOT_MANIFEST_FILENAME, diff --git a/src/state/openclaw-agent-board-schema.ts b/src/state/openclaw-agent-board-schema.ts index 0f9a758f8b20..ea931cdbf777 100644 --- a/src/state/openclaw-agent-board-schema.ts +++ b/src/state/openclaw-agent-board-schema.ts @@ -1,5 +1,5 @@ import type { DatabaseSync } from "node:sqlite"; -import { OPENCLAW_AGENT_SCHEMA_SQL } from "./openclaw-agent-schema.generated.js"; +import { OPENCLAW_AGENT_SCHEMA_SQL } from "./openclaw-agent-schema.js"; const BOARD_SCHEMA_START = "CREATE TABLE IF NOT EXISTS board_tabs ("; const BOARD_SCHEMA_END = "CREATE TABLE IF NOT EXISTS heartbeat_outcomes ("; diff --git a/src/state/openclaw-agent-db-maintenance.ts b/src/state/openclaw-agent-db-maintenance.ts index 2a045f90ffef..941bb92139fc 100644 --- a/src/state/openclaw-agent-db-maintenance.ts +++ b/src/state/openclaw-agent-db-maintenance.ts @@ -20,7 +20,7 @@ import { readExistingAgentSchemaMeta, } from "./openclaw-agent-db-schema-helpers.js"; import { ensureOpenClawAgentDatabaseSchema } from "./openclaw-agent-db-schema.js"; -import { OPENCLAW_AGENT_SCHEMA_SQL } from "./openclaw-agent-schema.generated.js"; +import { OPENCLAW_AGENT_SCHEMA_SQL } from "./openclaw-agent-schema.js"; import { OPENCLAW_SQLITE_BUSY_TIMEOUT_MS } from "./openclaw-state-db.js"; /** Require exact agent ownership without requiring the latest schema. */ diff --git a/src/state/openclaw-agent-db-schema-helpers.ts b/src/state/openclaw-agent-db-schema-helpers.ts index 589ce6e7cdf5..7f173915b9b4 100644 --- a/src/state/openclaw-agent-db-schema-helpers.ts +++ b/src/state/openclaw-agent-db-schema-helpers.ts @@ -23,7 +23,7 @@ import { } from "./openclaw-agent-board-schema.js"; import { OPENCLAW_AGENT_SCHEMA_VERSION } from "./openclaw-agent-db-contract.js"; import { OpenClawAgentDatabaseMediaMigrationRequiredError } from "./openclaw-agent-db-migration-required.js"; -import { OPENCLAW_AGENT_SCHEMA_SQL } from "./openclaw-agent-schema.generated.js"; +import { OPENCLAW_AGENT_SCHEMA_SQL } from "./openclaw-agent-schema.js"; import { AGENT_V14_ADDITIVE_SCHEMA_SQL, AGENT_V14_CORE_SCHEMA_SQL, diff --git a/src/state/openclaw-agent-db-schema.ts b/src/state/openclaw-agent-db-schema.ts index f83b6406ddd1..14995026437d 100644 --- a/src/state/openclaw-agent-db-schema.ts +++ b/src/state/openclaw-agent-db-schema.ts @@ -48,7 +48,7 @@ import { } from "./openclaw-agent-db-session-provenance.js"; import type { DB as OpenClawAgentKyselyDatabase } from "./openclaw-agent-db.generated.js"; import { resolveOpenClawAgentSqlitePath } from "./openclaw-agent-db.paths.js"; -import { OPENCLAW_AGENT_SCHEMA_SQL } from "./openclaw-agent-schema.generated.js"; +import { OPENCLAW_AGENT_SCHEMA_SQL } from "./openclaw-agent-schema.js"; import { OPENCLAW_SQLITE_BUSY_TIMEOUT_MS } from "./openclaw-state-db.js"; type OpenClawAgentMetadataDatabase = Pick; diff --git a/src/state/openclaw-agent-schema.generated.ts b/src/state/openclaw-agent-schema.generated.ts deleted file mode 100644 index 91bc8a7ae39b..000000000000 --- a/src/state/openclaw-agent-schema.generated.ts +++ /dev/null @@ -1,639 +0,0 @@ -/** - * This file was generated from the SQLite schema source. - * Please do not edit it manually. - */ - -export const OPENCLAW_AGENT_SCHEMA_SQL = `-- Session storage doctrine: session_nodes.entry_json is the canonical logical-session --- record. Promoted session_nodes columns are query indexes projected only by the --- session entry writer; session_windows and their children own transcript generations. - -CREATE TABLE IF NOT EXISTS schema_meta ( - meta_key TEXT NOT NULL PRIMARY KEY, - role TEXT NOT NULL, - schema_version INTEGER NOT NULL, - agent_id TEXT, - app_version TEXT, - created_at INTEGER NOT NULL, - updated_at INTEGER NOT NULL -) STRICT; - -CREATE TABLE IF NOT EXISTS state_leases ( - scope TEXT NOT NULL, - lease_key TEXT NOT NULL, - owner TEXT NOT NULL, - expires_at INTEGER, - heartbeat_at INTEGER, - payload_json TEXT, - created_at INTEGER NOT NULL, - updated_at INTEGER NOT NULL, - PRIMARY KEY (scope, lease_key) -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_agent_state_leases_expiry - ON state_leases(expires_at, scope, lease_key) - WHERE expires_at IS NOT NULL; - -CREATE INDEX IF NOT EXISTS idx_agent_state_leases_owner - ON state_leases(owner, updated_at DESC); - -CREATE TABLE IF NOT EXISTS session_nodes ( - session_key TEXT NOT NULL PRIMARY KEY, - current_session_id TEXT NOT NULL, - entry_json TEXT NOT NULL, - entry_valid INTEGER NOT NULL DEFAULT 0 CHECK (entry_valid IN (-1, 0, 1)), - updated_at INTEGER NOT NULL, - status TEXT CHECK (status IS NULL OR status IN ('running', 'done', 'failed', 'killed', 'timeout')), - created_at INTEGER, - created_via TEXT CHECK (created_via IS NULL OR created_via IN ('operator', 'spawn', 'channel', 'cron', 'talk', 'run', 'plugin', 'internal')), - created_actor_type TEXT CHECK (created_actor_type IS NULL OR created_actor_type IN ('human', 'agent', 'system')), - created_actor_id TEXT, - parent_session_key TEXT, - spawned_by TEXT, - fork_source_session_key TEXT, - fork_source_session_id TEXT, - fork_source_entry_id TEXT, - label TEXT, - display_name TEXT, - category TEXT, - icon TEXT, - pinned_at INTEGER, - archived_at INTEGER, - last_read_at INTEGER, - last_interaction_at INTEGER, - last_activity_at INTEGER -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_agent_session_nodes_updated_at - ON session_nodes(updated_at DESC, session_key); - -CREATE INDEX IF NOT EXISTS idx_agent_session_nodes_last_interaction_at - ON session_nodes(last_interaction_at DESC, session_key); - -CREATE INDEX IF NOT EXISTS idx_agent_session_nodes_parent_session_key - ON session_nodes(parent_session_key, session_key); - -CREATE INDEX IF NOT EXISTS idx_agent_session_nodes_spawned_by - ON session_nodes(spawned_by, session_key); - -CREATE INDEX IF NOT EXISTS idx_agent_session_nodes_status - ON session_nodes(status, session_key) - WHERE status IS NOT NULL; - -CREATE INDEX IF NOT EXISTS idx_agent_session_nodes_archived_at - ON session_nodes(archived_at, session_key) - WHERE archived_at IS NOT NULL; - -CREATE INDEX IF NOT EXISTS idx_agent_session_nodes_current_session_id - ON session_nodes(current_session_id); - -CREATE INDEX IF NOT EXISTS idx_agent_session_nodes_entry_valid_pending - ON session_nodes(session_key) - WHERE entry_valid = 0; - -CREATE TABLE IF NOT EXISTS session_key_contract ( - id INTEGER NOT NULL PRIMARY KEY CHECK (id = 1), - main_key TEXT NOT NULL, - updated_at INTEGER NOT NULL -) STRICT; - -INSERT OR IGNORE INTO session_key_contract (id, main_key, updated_at) VALUES (1, 'main', 0); - -CREATE TRIGGER IF NOT EXISTS session_nodes_entry_valid_after_insert -AFTER INSERT ON session_nodes -BEGIN - UPDATE session_nodes SET entry_valid = 0 WHERE session_key = NEW.session_key; -END; - -CREATE TRIGGER IF NOT EXISTS session_nodes_entry_valid_after_entry_update -AFTER UPDATE OF entry_json ON session_nodes -BEGIN - UPDATE session_nodes SET entry_valid = 0 WHERE session_key = NEW.session_key; -END; - -CREATE TRIGGER IF NOT EXISTS session_nodes_entry_valid_after_identity_update -AFTER UPDATE OF current_session_id, updated_at ON session_nodes -BEGIN - UPDATE session_nodes SET entry_valid = 0 WHERE session_key = NEW.session_key; -END; - -CREATE TABLE IF NOT EXISTS session_windows ( - session_id TEXT NOT NULL PRIMARY KEY, - session_key TEXT NOT NULL, - previous_session_id TEXT, - reason TEXT CHECK (reason IS NULL OR reason IN ('initial', 'reset', 'rollover', 'fork', 'rewind', 'switch', 'recovery', 'compaction')), - session_scope TEXT NOT NULL DEFAULT 'conversation' CHECK (session_scope IN ('conversation', 'shared-main', 'group', 'channel')), - created_at INTEGER NOT NULL, - updated_at INTEGER NOT NULL, - transcript_updated_at INTEGER DEFAULT NULL, - transcript_observed_at INTEGER DEFAULT NULL, - session_entry_provenance INTEGER NOT NULL DEFAULT 0 CHECK (session_entry_provenance IN (0, 1)), - acp_owned INTEGER NOT NULL DEFAULT 0 CHECK (acp_owned IN (0, 1)), - plugin_owner_id TEXT, - hook_external_content_source TEXT CHECK (hook_external_content_source IS NULL OR hook_external_content_source IN ('gmail', 'webhook')), - started_at INTEGER, - ended_at INTEGER, - status TEXT CHECK (status IS NULL OR status IN ('running', 'done', 'failed', 'killed', 'timeout')), - chat_type TEXT CHECK (chat_type IS NULL OR chat_type IN ('direct', 'group', 'channel')), - channel TEXT, - account_id TEXT, - primary_conversation_id TEXT, - model_provider TEXT, - model TEXT, - agent_harness_id TEXT, - parent_session_key TEXT, - spawned_by TEXT, - display_name TEXT, - FOREIGN KEY (session_key) REFERENCES session_nodes(session_key) ON DELETE CASCADE, - FOREIGN KEY (primary_conversation_id) REFERENCES conversations(conversation_id) ON DELETE SET NULL -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_agent_session_windows_updated_at - ON session_windows(updated_at DESC, session_id); - -CREATE INDEX IF NOT EXISTS idx_agent_session_windows_created_at - ON session_windows(created_at DESC, session_id); - -CREATE INDEX IF NOT EXISTS idx_agent_session_windows_conversation - ON session_windows(primary_conversation_id, updated_at DESC, session_id) - WHERE primary_conversation_id IS NOT NULL; - -CREATE TABLE IF NOT EXISTS conversations ( - conversation_id TEXT NOT NULL PRIMARY KEY, - channel TEXT NOT NULL, - account_id TEXT NOT NULL, - kind TEXT NOT NULL CHECK (kind IN ('direct', 'group', 'channel')), - peer_id TEXT NOT NULL, - delivery_target TEXT NOT NULL, - parent_conversation_id TEXT, - thread_id TEXT, - native_channel_id TEXT, - native_direct_user_id TEXT, - label TEXT, - metadata_json TEXT, - created_at INTEGER NOT NULL, - updated_at INTEGER NOT NULL -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_agent_conversations_lookup - ON conversations(channel, account_id, kind, peer_id, thread_id); - -CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_conversations_identity - ON conversations( - channel, - account_id, - kind, - peer_id, - IFNULL(parent_conversation_id, ''), - IFNULL(thread_id, '') - ); - -CREATE INDEX IF NOT EXISTS idx_agent_conversations_updated - ON conversations(updated_at DESC, conversation_id); - -CREATE TABLE IF NOT EXISTS conversation_deliveries ( - operation_id TEXT NOT NULL PRIMARY KEY, - operation_kind TEXT NOT NULL CHECK (operation_kind IN ('send', 'turn')), - conversation_id TEXT NOT NULL, - source_session_key TEXT, - message_hash TEXT NOT NULL, - status TEXT NOT NULL CHECK (status IN ('created', 'queued', 'sent', 'suppressed', 'rejected', 'unknown', 'replied')), - prepared_message_id TEXT, - platform_message_id TEXT, - queue_id TEXT, - rejection_error TEXT, - reply_message_id TEXT, - reply_to_id TEXT, - reply_thread_id TEXT, - reply_text TEXT, - reply_timestamp INTEGER, - created_at INTEGER NOT NULL, - updated_at INTEGER NOT NULL, - CHECK ( - (status = 'rejected' AND rejection_error IS NOT NULL) OR - (status != 'rejected' AND rejection_error IS NULL) - ), - FOREIGN KEY (conversation_id) REFERENCES conversations(conversation_id) ON DELETE CASCADE -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_agent_conversation_deliveries_reply - ON conversation_deliveries(conversation_id, platform_message_id, prepared_message_id) - WHERE status IN ('queued', 'sent', 'replied'); - -CREATE INDEX IF NOT EXISTS idx_agent_conversation_deliveries_updated - ON conversation_deliveries(updated_at DESC, operation_id); - -CREATE TABLE IF NOT EXISTS session_conversations ( - session_id TEXT NOT NULL, - conversation_id TEXT NOT NULL, - role TEXT NOT NULL DEFAULT 'primary' CHECK (role IN ('primary', 'participant', 'related')), - first_seen_at INTEGER NOT NULL, - last_seen_at INTEGER NOT NULL, - PRIMARY KEY (session_id, conversation_id, role), - FOREIGN KEY (session_id) REFERENCES "session_windows"(session_id) ON DELETE CASCADE, - FOREIGN KEY (conversation_id) REFERENCES conversations(conversation_id) ON DELETE CASCADE -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_agent_session_conversations_conversation - ON session_conversations(conversation_id, last_seen_at DESC, session_id); - -CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_session_conversations_primary - ON session_conversations(session_id) - WHERE role = 'primary'; - -CREATE TABLE IF NOT EXISTS session_members ( - session_key TEXT NOT NULL, - identity_id TEXT NOT NULL, - added_by TEXT NOT NULL, - added_at INTEGER NOT NULL, - PRIMARY KEY (session_key, identity_id), - FOREIGN KEY (session_key) REFERENCES session_nodes(session_key) ON DELETE CASCADE -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_agent_session_members_identity - ON session_members(identity_id, session_key); - -CREATE TABLE IF NOT EXISTS session_suggestions ( - id TEXT PRIMARY KEY, - session_key TEXT NOT NULL, - author_id TEXT NOT NULL, - author_label TEXT, - text TEXT NOT NULL, - created_at INTEGER NOT NULL, - state TEXT NOT NULL CHECK (state IN ('pending', 'accepted', 'dismissed')), - dispatch_token TEXT, - dispatch_started_at INTEGER, - dispatch_resolution TEXT CHECK (dispatch_resolution IN ('send', 'queue', 'edit', 'dismiss')), - CHECK ( - (dispatch_token IS NULL AND dispatch_started_at IS NULL AND dispatch_resolution IS NULL) - OR (dispatch_token IS NOT NULL AND dispatch_started_at IS NOT NULL AND dispatch_resolution IS NOT NULL) - ), - FOREIGN KEY (session_key) REFERENCES session_nodes(session_key) ON DELETE CASCADE -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_agent_session_suggestions_session_state_created - ON session_suggestions(session_key, state, created_at, id); - -CREATE INDEX IF NOT EXISTS idx_agent_session_suggestions_author_created - ON session_suggestions(author_id, created_at, id); - -CREATE TABLE IF NOT EXISTS board_tabs ( - session_key TEXT NOT NULL, - tab_id TEXT NOT NULL, - title TEXT NOT NULL, - position INTEGER NOT NULL CHECK (position >= 0), - chat_dock TEXT NOT NULL DEFAULT 'right' CHECK (chat_dock IN ('left', 'right', 'bottom', 'hidden')), - created_by TEXT NOT NULL CHECK (created_by IN ('user', 'agent')), - revision INTEGER NOT NULL CHECK (revision >= 0), - PRIMARY KEY (session_key, tab_id), - FOREIGN KEY (session_key) REFERENCES session_nodes(session_key) ON DELETE CASCADE -) STRICT; - -CREATE TABLE IF NOT EXISTS board_widgets ( - session_key TEXT NOT NULL, - name TEXT NOT NULL, - tab_id TEXT NOT NULL, - title TEXT, - content_kind TEXT NOT NULL CHECK (content_kind IN ('html', 'mcp-app', 'plugin')), - html BLOB, - descriptor_json TEXT, - sha256 TEXT NOT NULL, - view_generation TEXT, - revision INTEGER NOT NULL CHECK (revision >= 1), - size_w INTEGER NOT NULL CHECK (size_w BETWEEN 1 AND 12), - size_h INTEGER NOT NULL CHECK (size_h BETWEEN 1 AND 20), - position INTEGER NOT NULL CHECK (position >= 0), - manifest TEXT NOT NULL DEFAULT '{}', - grant_state TEXT NOT NULL DEFAULT 'none' CHECK (grant_state IN ('none', 'pending', 'granted', 'rejected')), - granted_sha TEXT, - created_by TEXT NOT NULL CHECK (created_by IN ('user', 'agent')), - created_at INTEGER NOT NULL, - updated_at INTEGER NOT NULL, - PRIMARY KEY (session_key, name), - FOREIGN KEY (session_key, tab_id) REFERENCES board_tabs(session_key, tab_id) ON DELETE CASCADE, - CHECK ( - (content_kind = 'html' AND html IS NOT NULL AND descriptor_json IS NULL AND view_generation IS NOT NULL) OR - (content_kind = 'mcp-app' AND html IS NULL AND descriptor_json IS NOT NULL AND view_generation IS NULL) OR - (content_kind = 'plugin' AND html IS NULL AND descriptor_json IS NOT NULL AND view_generation IS NULL) - ) -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_agent_board_widgets_tab_position - ON board_widgets(session_key, tab_id, position); - -CREATE TABLE IF NOT EXISTS heartbeat_outcomes ( - session_key TEXT NOT NULL PRIMARY KEY, - run_session_key TEXT NOT NULL, - outcome TEXT NOT NULL CHECK (outcome IN ('progress', 'done', 'blocked', 'needs_attention')), - summary TEXT NOT NULL, - response_reason TEXT, - priority TEXT CHECK (priority IS NULL OR priority IN ('low', 'normal', 'high')), - next_check TEXT, - task_names_json TEXT, - wake_source TEXT, - wake_reason TEXT, - occurred_at INTEGER NOT NULL, - context_run_id TEXT, - context_claimed_at INTEGER, - updated_at INTEGER NOT NULL, - FOREIGN KEY (session_key) REFERENCES session_nodes(session_key) ON DELETE CASCADE -) STRICT; - -CREATE TABLE IF NOT EXISTS transcript_events ( - session_id TEXT NOT NULL, - seq INTEGER NOT NULL, - event_json TEXT NOT NULL, - created_at INTEGER NOT NULL, - PRIMARY KEY (session_id, seq), - FOREIGN KEY (session_id) REFERENCES "session_windows"(session_id) ON DELETE CASCADE -) STRICT; - -CREATE TABLE IF NOT EXISTS transcript_rewrite_watermarks ( - session_id TEXT NOT NULL PRIMARY KEY, - generation TEXT NOT NULL, - updated_at INTEGER NOT NULL, - FOREIGN KEY (session_id) REFERENCES "session_windows"(session_id) ON DELETE CASCADE -) STRICT; - -CREATE TABLE IF NOT EXISTS trajectory_runtime_events ( - session_id TEXT NOT NULL, - seq INTEGER NOT NULL, - run_id TEXT, - event_json TEXT NOT NULL, - created_at INTEGER NOT NULL, - PRIMARY KEY (session_id, seq), - FOREIGN KEY (session_id) REFERENCES "session_windows"(session_id) ON DELETE CASCADE -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_agent_trajectory_runtime_run - ON trajectory_runtime_events(session_id, run_id, seq) - WHERE run_id IS NOT NULL; - -CREATE TABLE IF NOT EXISTS acp_parent_stream_events ( - session_id TEXT NOT NULL, - run_id TEXT NOT NULL, - seq INTEGER NOT NULL, - event_json TEXT NOT NULL, - created_at INTEGER NOT NULL, - PRIMARY KEY (session_id, run_id, seq), - FOREIGN KEY (session_id) REFERENCES "session_windows"(session_id) ON DELETE CASCADE -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_agent_acp_parent_stream_run - ON acp_parent_stream_events(run_id, seq); - -CREATE TABLE IF NOT EXISTS transcript_event_identities ( - session_id TEXT NOT NULL, - event_id TEXT NOT NULL, - seq INTEGER NOT NULL, - event_type TEXT, - parent_id TEXT, - message_idempotency_key TEXT, - created_at INTEGER NOT NULL, - PRIMARY KEY (session_id, event_id), - FOREIGN KEY (session_id, seq) REFERENCES transcript_events(session_id, seq) ON DELETE CASCADE -) STRICT; - -CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_transcript_message_idempotency - ON transcript_event_identities(session_id, message_idempotency_key) - WHERE message_idempotency_key IS NOT NULL; - -CREATE INDEX IF NOT EXISTS idx_agent_transcript_event_parent - ON transcript_event_identities(session_id, parent_id) - WHERE parent_id IS NOT NULL; - -CREATE INDEX IF NOT EXISTS idx_agent_transcript_event_sequence - ON transcript_event_identities(session_id, event_type, seq DESC); - -CREATE TABLE IF NOT EXISTS cache_entries ( - scope TEXT NOT NULL, - key TEXT NOT NULL, - value_json TEXT, - blob BLOB, - expires_at INTEGER, - updated_at INTEGER NOT NULL, - PRIMARY KEY (scope, key) -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_agent_cache_expiry - ON cache_entries(scope, expires_at, key) - WHERE expires_at IS NOT NULL; - -CREATE INDEX IF NOT EXISTS idx_agent_cache_updated - ON cache_entries(scope, updated_at DESC, key); - -CREATE TABLE IF NOT EXISTS auth_profile_store ( - store_key TEXT NOT NULL PRIMARY KEY, - store_json TEXT NOT NULL, - updated_at INTEGER NOT NULL -) STRICT; - -CREATE TABLE IF NOT EXISTS auth_profile_state ( - state_key TEXT NOT NULL PRIMARY KEY, - state_json TEXT NOT NULL, - updated_at INTEGER NOT NULL -) STRICT; - -CREATE TABLE IF NOT EXISTS memory_index_meta ( - key TEXT PRIMARY KEY, - value TEXT NOT NULL -) STRICT; - -CREATE TABLE IF NOT EXISTS memory_index_sources ( - id INTEGER PRIMARY KEY, - path TEXT NOT NULL, - source TEXT NOT NULL DEFAULT 'memory', - hash TEXT NOT NULL, - mtime REAL NOT NULL, - size INTEGER NOT NULL, - UNIQUE (path, source) -) STRICT; - -CREATE TABLE IF NOT EXISTS memory_index_chunks ( - id TEXT PRIMARY KEY, - path TEXT NOT NULL, - source TEXT NOT NULL DEFAULT 'memory', - start_line INTEGER NOT NULL, - end_line INTEGER NOT NULL, - hash TEXT NOT NULL, - model TEXT NOT NULL, - text TEXT NOT NULL, - embedding TEXT NOT NULL, - updated_at INTEGER NOT NULL -) STRICT; - -CREATE TABLE IF NOT EXISTS memory_index_chunk_recall_metadata ( - chunk_id TEXT PRIMARY KEY, - importance INTEGER CHECK (importance IS NULL OR importance BETWEEN 1 AND 10), - triggers TEXT, - project_key TEXT, - FOREIGN KEY (chunk_id) REFERENCES memory_index_chunks(id) ON DELETE CASCADE -) STRICT; - -CREATE TABLE IF NOT EXISTS memory_index_chunk_provenance ( - chunk_id TEXT PRIMARY KEY, - origin_class TEXT NOT NULL CHECK (origin_class IN ('owner', 'agent', 'untrusted', 'system')), - session_kind TEXT NOT NULL CHECK (session_kind IN ('interactive', 'cron', 'heartbeat', 'subagent', 'unknown')), - observed_at INTEGER NOT NULL, - supersedes_key TEXT, - FOREIGN KEY (chunk_id) REFERENCES memory_index_chunks(id) ON DELETE CASCADE -) STRICT; - -CREATE TABLE IF NOT EXISTS memory_embedding_cache ( - provider TEXT NOT NULL, - model TEXT NOT NULL, - provider_key TEXT NOT NULL, - hash TEXT NOT NULL, - embedding TEXT NOT NULL, - dims INTEGER, - updated_at INTEGER NOT NULL, - PRIMARY KEY (provider, model, provider_key, hash) -) STRICT; - -CREATE TABLE IF NOT EXISTS memory_index_state ( - id INTEGER PRIMARY KEY CHECK (id = 1), - revision INTEGER NOT NULL -) STRICT; - -CREATE TABLE IF NOT EXISTS standing_intents ( - intent_key INTEGER PRIMARY KEY, - id TEXT NOT NULL UNIQUE, - description TEXT NOT NULL, - trigger_keywords TEXT NOT NULL, - trigger_embedding TEXT, - channel_scope TEXT, - sender_scope TEXT, - creator_sender TEXT CHECK (creator_sender IS NULL OR length(trim(creator_sender)) > 0), - status TEXT NOT NULL CHECK (status IN ('pending', 'armed', 'fired', 'done', 'cancelled', 'expired')), - expires_at INTEGER NOT NULL, - max_fires INTEGER NOT NULL CHECK (max_fires > 0), - fire_count INTEGER NOT NULL DEFAULT 0 CHECK (fire_count >= 0), - cooldown_seconds INTEGER NOT NULL DEFAULT 86400 CHECK (cooldown_seconds >= 0), - last_fired_at INTEGER, - created_at INTEGER NOT NULL, - source_session_id TEXT -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_standing_intents_lifecycle - ON standing_intents(status, expires_at, last_fired_at); - -CREATE INDEX IF NOT EXISTS idx_standing_intents_scope - ON standing_intents(status, channel_scope, sender_scope); - -CREATE VIRTUAL TABLE IF NOT EXISTS standing_intents_fts USING fts5( - trigger_keywords, - content = 'standing_intents', - content_rowid = 'intent_key', - tokenize = 'unicode61 remove_diacritics 2' -); - -CREATE TRIGGER IF NOT EXISTS standing_intents_fts_after_insert -AFTER INSERT ON standing_intents -BEGIN - INSERT INTO standing_intents_fts(rowid, trigger_keywords) - VALUES (new.intent_key, new.trigger_keywords); -END; - -CREATE TRIGGER IF NOT EXISTS standing_intents_fts_after_delete -AFTER DELETE ON standing_intents -BEGIN - INSERT INTO standing_intents_fts(standing_intents_fts, rowid, trigger_keywords) - VALUES ('delete', old.intent_key, old.trigger_keywords); -END; - -CREATE TRIGGER IF NOT EXISTS standing_intents_fts_after_update -AFTER UPDATE OF trigger_keywords ON standing_intents -BEGIN - INSERT INTO standing_intents_fts(standing_intents_fts, rowid, trigger_keywords) - VALUES ('delete', old.intent_key, old.trigger_keywords); - INSERT INTO standing_intents_fts(rowid, trigger_keywords) - VALUES (new.intent_key, new.trigger_keywords); -END; - -CREATE TABLE IF NOT EXISTS session_transcript_index_state ( - session_id TEXT NOT NULL PRIMARY KEY, - indexed_seq INTEGER NOT NULL, - leaf_event_id TEXT, - needs_rebuild INTEGER NOT NULL DEFAULT 0, - active_event_count INTEGER NOT NULL DEFAULT 0, - active_message_count INTEGER NOT NULL DEFAULT 0, - updated_at INTEGER NOT NULL, - FOREIGN KEY (session_id) REFERENCES session_windows(session_id) ON DELETE CASCADE -) STRICT; - -CREATE TABLE IF NOT EXISTS session_transcript_active_events ( - session_id TEXT NOT NULL, - active_position INTEGER NOT NULL CHECK (active_position >= 0), - event_seq INTEGER NOT NULL, - message_position INTEGER CHECK (message_position IS NULL OR message_position >= 0), - PRIMARY KEY (session_id, active_position), - FOREIGN KEY (session_id, event_seq) REFERENCES transcript_events(session_id, seq) ON DELETE CASCADE -) STRICT; - -CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_transcript_active_event_seq - ON session_transcript_active_events(session_id, event_seq); - -CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_transcript_active_messages - ON session_transcript_active_events(session_id, message_position) - WHERE message_position IS NOT NULL; - -CREATE VIRTUAL TABLE IF NOT EXISTS session_transcript_fts USING fts5( - text, - session_id UNINDEXED, - message_id UNINDEXED, - role UNINDEXED, - timestamp UNINDEXED, - tokenize = 'unicode61 remove_diacritics 2' -); - -INSERT OR IGNORE INTO memory_index_state (id, revision) VALUES (1, 0); - -CREATE TRIGGER IF NOT EXISTS memory_index_sources_revision_after_insert -AFTER INSERT ON memory_index_sources -BEGIN - UPDATE memory_index_state SET revision = revision + 1 WHERE id = 1; -END; - -CREATE TRIGGER IF NOT EXISTS memory_index_sources_revision_after_update -AFTER UPDATE ON memory_index_sources -BEGIN - UPDATE memory_index_state SET revision = revision + 1 WHERE id = 1; -END; - -CREATE TRIGGER IF NOT EXISTS memory_index_sources_revision_after_delete -AFTER DELETE ON memory_index_sources -BEGIN - UPDATE memory_index_state SET revision = revision + 1 WHERE id = 1; -END; - -CREATE TRIGGER IF NOT EXISTS memory_index_chunks_revision_after_insert -AFTER INSERT ON memory_index_chunks -BEGIN - UPDATE memory_index_state SET revision = revision + 1 WHERE id = 1; -END; - -CREATE TRIGGER IF NOT EXISTS memory_index_chunks_revision_after_update -AFTER UPDATE ON memory_index_chunks -BEGIN - UPDATE memory_index_state SET revision = revision + 1 WHERE id = 1; -END; - -CREATE TRIGGER IF NOT EXISTS memory_index_chunks_revision_after_delete -AFTER DELETE ON memory_index_chunks -BEGIN - UPDATE memory_index_state SET revision = revision + 1 WHERE id = 1; -END; - -CREATE INDEX IF NOT EXISTS idx_memory_embedding_cache_updated_at - ON memory_embedding_cache(updated_at); - -CREATE INDEX IF NOT EXISTS idx_memory_index_sources_source - ON memory_index_sources(source); - -CREATE INDEX IF NOT EXISTS idx_memory_index_chunks_path_source - ON memory_index_chunks(path, source); - -CREATE INDEX IF NOT EXISTS idx_memory_index_chunks_path - ON memory_index_chunks(path); - -CREATE INDEX IF NOT EXISTS idx_memory_index_chunks_source - ON memory_index_chunks(source);\n`; diff --git a/src/state/openclaw-agent-schema.ts b/src/state/openclaw-agent-schema.ts new file mode 100644 index 000000000000..ef071324a3e7 --- /dev/null +++ b/src/state/openclaw-agent-schema.ts @@ -0,0 +1,7 @@ +import { fileURLToPath } from "node:url"; + +// Use the native builtin so unrelated node:fs mocks cannot replace this source input. +// Production builds replace this module so packaged database opens need no asset file. +export const OPENCLAW_AGENT_SCHEMA_SQL = process + .getBuiltinModule("node:fs") + .readFileSync(fileURLToPath(new URL("./openclaw-agent-schema.sql", import.meta.url)), "utf8"); diff --git a/src/state/openclaw-agent-standing-intents-schema.test.ts b/src/state/openclaw-agent-standing-intents-schema.test.ts index e322d33e5a35..77c4d9390c90 100644 --- a/src/state/openclaw-agent-standing-intents-schema.test.ts +++ b/src/state/openclaw-agent-standing-intents-schema.test.ts @@ -10,7 +10,7 @@ import { MEMORY_INDEX_CHUNK_RECALL_METADATA_TABLE } from "../../packages/memory- import { openNodeSqliteDatabase } from "../infra/node-sqlite.js"; import { OPENCLAW_AGENT_SCHEMA_VERSION } from "./openclaw-agent-db-contract.js"; import { ensureOpenClawAgentDatabaseSchema } from "./openclaw-agent-db-schema.js"; -import { OPENCLAW_AGENT_SCHEMA_SQL } from "./openclaw-agent-schema.generated.js"; +import { OPENCLAW_AGENT_SCHEMA_SQL } from "./openclaw-agent-schema.js"; import { ensureOpenClawAgentStandingIntentsSchema } from "./openclaw-agent-standing-intents-schema.js"; const STANDING_SCHEMA_START = "CREATE TABLE IF NOT EXISTS standing_intents ("; diff --git a/src/state/openclaw-agent-standing-intents-schema.ts b/src/state/openclaw-agent-standing-intents-schema.ts index 8cb6a5eb0566..1c508763d3e5 100644 --- a/src/state/openclaw-agent-standing-intents-schema.ts +++ b/src/state/openclaw-agent-standing-intents-schema.ts @@ -1,6 +1,6 @@ import type { DatabaseSync } from "node:sqlite"; import { runSqliteImmediateTransactionSync } from "../infra/sqlite-transaction.js"; -import { OPENCLAW_AGENT_SCHEMA_SQL } from "./openclaw-agent-schema.generated.js"; +import { OPENCLAW_AGENT_SCHEMA_SQL } from "./openclaw-agent-schema.js"; export const STANDING_INTENTS_TABLE = "standing_intents"; export const STANDING_INTENTS_FTS_TABLE = "standing_intents_fts"; diff --git a/src/state/openclaw-database-maintenance.test.ts b/src/state/openclaw-database-maintenance.test.ts index c091813f4bea..98dc311423b3 100644 --- a/src/state/openclaw-database-maintenance.test.ts +++ b/src/state/openclaw-database-maintenance.test.ts @@ -5,12 +5,12 @@ import { assertOpenClawAgentDatabaseForMaintenance, OPENCLAW_AGENT_SCHEMA_VERSION, } from "./openclaw-agent-db.js"; -import { OPENCLAW_AGENT_SCHEMA_SQL } from "./openclaw-agent-schema.generated.js"; +import { OPENCLAW_AGENT_SCHEMA_SQL } from "./openclaw-agent-schema.js"; import { assertOpenClawStateDatabaseForMaintenance, OPENCLAW_STATE_SCHEMA_VERSION, } from "./openclaw-state-db.js"; -import { OPENCLAW_STATE_SCHEMA_SQL } from "./openclaw-state-schema.generated.js"; +import { OPENCLAW_STATE_SCHEMA_SQL } from "./openclaw-state-schema.js"; describe("OpenClaw database maintenance schema validation", () => { it("accepts the current global and agent schemas", () => { diff --git a/src/state/openclaw-state-db-maintenance.ts b/src/state/openclaw-state-db-maintenance.ts index 8095ec3ddd07..5958890cc6d0 100644 --- a/src/state/openclaw-state-db-maintenance.ts +++ b/src/state/openclaw-state-db-maintenance.ts @@ -16,7 +16,7 @@ import { type OpenClawStateDatabaseOptions, } from "./openclaw-state-db-contract.js"; import { resolveOpenClawStateSqlitePath } from "./openclaw-state-db.paths.js"; -import { OPENCLAW_STATE_SCHEMA_SQL } from "./openclaw-state-schema.generated.js"; +import { OPENCLAW_STATE_SCHEMA_SQL } from "./openclaw-state-schema.js"; const OPENCLAW_STATE_MAINTENANCE_SCHEMA_COMPATIBILITY = { allowedMissingTables: LAZY_ADDITIVE_STATE_TABLES, diff --git a/src/state/openclaw-state-db-operator-approval-migration.test.ts b/src/state/openclaw-state-db-operator-approval-migration.test.ts index 5dfa78456375..35a326b16f20 100644 --- a/src/state/openclaw-state-db-operator-approval-migration.test.ts +++ b/src/state/openclaw-state-db-operator-approval-migration.test.ts @@ -5,7 +5,7 @@ import { assertCanonicalOperatorApprovalKinds, repairOperatorApprovalSchema, } from "./openclaw-state-db-operator-approval-migration.js"; -import { OPENCLAW_STATE_SCHEMA_SQL } from "./openclaw-state-schema.generated.js"; +import { OPENCLAW_STATE_SCHEMA_SQL } from "./openclaw-state-schema.js"; function canonicalOperatorApprovalCreateSql(): string { const marker = "CREATE TABLE IF NOT EXISTS operator_approvals ("; diff --git a/src/state/openclaw-state-db-operator-approval-migration.ts b/src/state/openclaw-state-db-operator-approval-migration.ts index 1a950e6e951e..a9ac9d9700d1 100644 --- a/src/state/openclaw-state-db-operator-approval-migration.ts +++ b/src/state/openclaw-state-db-operator-approval-migration.ts @@ -2,7 +2,7 @@ import type { DatabaseSync } from "node:sqlite"; import { runSqliteImmediateTransactionSync } from "../infra/sqlite-transaction.js"; import { tableExists } from "./openclaw-state-db-schema-helpers.js"; -import { OPENCLAW_STATE_SCHEMA_SQL } from "./openclaw-state-schema.generated.js"; +import { OPENCLAW_STATE_SCHEMA_SQL } from "./openclaw-state-schema.js"; const COLUMNS = [ "approval_id", diff --git a/src/state/openclaw-state-db.ts b/src/state/openclaw-state-db.ts index 4194810416eb..e1ef9cf3252d 100644 --- a/src/state/openclaw-state-db.ts +++ b/src/state/openclaw-state-db.ts @@ -74,7 +74,7 @@ import { } from "./openclaw-state-db-schema-repair.js"; import * as sessionWatchMigration from "./openclaw-state-db-session-watch-migration.js"; import type { DB as OpenClawStateKyselyDatabase } from "./openclaw-state-db.generated.js"; -import { OPENCLAW_STATE_SCHEMA_SQL } from "./openclaw-state-schema.generated.js"; +import { OPENCLAW_STATE_SCHEMA_SQL } from "./openclaw-state-schema.js"; export { OPENCLAW_DATABASE_SCHEMA_DOCS_URL, diff --git a/src/state/openclaw-state-schema.generated.ts b/src/state/openclaw-state-schema.generated.ts deleted file mode 100644 index b6b64d248b7f..000000000000 --- a/src/state/openclaw-state-schema.generated.ts +++ /dev/null @@ -1,2196 +0,0 @@ -/** - * This file was generated from the SQLite schema source. - * Please do not edit it manually. - */ - -export const OPENCLAW_STATE_SCHEMA_SQL = `CREATE TABLE IF NOT EXISTS auth_profile_stores ( - store_key TEXT NOT NULL PRIMARY KEY, - store_json TEXT NOT NULL, - updated_at INTEGER NOT NULL -) STRICT; - -CREATE TABLE IF NOT EXISTS auth_profile_state ( - store_key TEXT NOT NULL PRIMARY KEY, - state_json TEXT NOT NULL, - updated_at INTEGER NOT NULL -) STRICT; - -CREATE TABLE IF NOT EXISTS mcp_oauth_stores ( - store_key TEXT NOT NULL PRIMARY KEY, - format_version INTEGER NOT NULL CHECK (format_version = 1), - store_json TEXT NOT NULL, - updated_at INTEGER NOT NULL -) STRICT; - -CREATE TABLE IF NOT EXISTS diagnostic_events ( - scope TEXT NOT NULL, - event_key TEXT NOT NULL, - payload_json TEXT NOT NULL, - created_at INTEGER NOT NULL, - sequence INTEGER NOT NULL DEFAULT 0, - PRIMARY KEY (scope, event_key) -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_diagnostic_events_scope_sequence - ON diagnostic_events(scope, sequence, event_key); - -CREATE TABLE IF NOT EXISTS skill_usage ( - skill_file TEXT NOT NULL PRIMARY KEY, - skill_key TEXT NOT NULL, - skill_name TEXT NOT NULL, - skill_source TEXT NOT NULL, - first_used_at_ms INTEGER NOT NULL, - last_used_at_ms INTEGER NOT NULL, - use_count INTEGER NOT NULL, - last_agent_id TEXT -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_skill_usage_key - ON skill_usage(skill_key, skill_file); - -CREATE TABLE IF NOT EXISTS skill_lifecycle ( - skill_file TEXT NOT NULL PRIMARY KEY, - skill_key TEXT NOT NULL, - skill_name TEXT NOT NULL, - state TEXT NOT NULL CHECK (state IN ('active', 'stale', 'archived')), - pinned INTEGER NOT NULL DEFAULT 0, - state_changed_at_ms INTEGER NOT NULL, - created_at_ms INTEGER NOT NULL, - archived_reason TEXT -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_skill_lifecycle_key - ON skill_lifecycle(skill_key, skill_file); - -CREATE INDEX IF NOT EXISTS idx_skill_lifecycle_state - ON skill_lifecycle(state, skill_file); - -CREATE TABLE IF NOT EXISTS skill_curator_state ( - id INTEGER NOT NULL PRIMARY KEY CHECK (id = 1), - last_attempt_at_ms INTEGER NOT NULL, - last_success_at_ms INTEGER, - last_error TEXT, - last_result_json TEXT NOT NULL -) STRICT; - -CREATE TABLE IF NOT EXISTS skill_workshop_proposals ( - proposal_id TEXT NOT NULL PRIMARY KEY, - record_json TEXT NOT NULL, - owner_agent_id TEXT, - workspace_dir TEXT NOT NULL, - kind TEXT NOT NULL CHECK (kind IN ('create', 'update')), - status TEXT NOT NULL CHECK (status IN ('pending', 'applied', 'rejected', 'quarantined', 'stale')), - created_at TEXT NOT NULL, - updated_at TEXT NOT NULL, - draft_hash TEXT NOT NULL, - origin_agent_id TEXT, - origin_session_key TEXT, - origin_run_id TEXT, - origin_message_id TEXT, - applied_at TEXT, - rejected_at TEXT, - quarantined_at TEXT, - stale_at TEXT, - status_reason TEXT -) STRICT; - -CREATE TABLE IF NOT EXISTS skill_workshop_proposal_origin_runs ( - proposal_id TEXT NOT NULL, - run_id TEXT NOT NULL, - position INTEGER NOT NULL, - mutation_count INTEGER NOT NULL CHECK (mutation_count > 0), - PRIMARY KEY (proposal_id, run_id), - FOREIGN KEY (proposal_id) REFERENCES skill_workshop_proposals(proposal_id) ON DELETE CASCADE -) STRICT; - -CREATE TABLE IF NOT EXISTS skill_workshop_proposal_rollbacks ( - proposal_id TEXT NOT NULL PRIMARY KEY, - written_at TEXT NOT NULL, - target_skill_file TEXT NOT NULL, - action TEXT NOT NULL CHECK (action IN ('create', 'update')), - previous_content_hash TEXT, - previous_content TEXT, - support_files_json TEXT, - FOREIGN KEY (proposal_id) REFERENCES skill_workshop_proposals(proposal_id) ON DELETE CASCADE -) STRICT; - -CREATE TABLE IF NOT EXISTS skill_workshop_proposal_events ( - sequence INTEGER PRIMARY KEY AUTOINCREMENT, - event_id TEXT NOT NULL UNIQUE, - proposal_id TEXT NOT NULL, - proposed_version TEXT NOT NULL, - revision_hash TEXT NOT NULL, - event_type TEXT NOT NULL CHECK (event_type IN ( - 'created', - 'revised', - 'evaluation_completed', - 'applied', - 'rejected', - 'quarantined', - 'stale' - )), - occurred_at TEXT NOT NULL, - actor_json TEXT NOT NULL, - correlation_id TEXT, - payload_json TEXT, - FOREIGN KEY (proposal_id) REFERENCES skill_workshop_proposals(proposal_id) ON DELETE CASCADE -) STRICT; - -CREATE TABLE IF NOT EXISTS audit_events ( - sequence INTEGER PRIMARY KEY AUTOINCREMENT, - event_id TEXT NOT NULL UNIQUE, - source_id TEXT NOT NULL UNIQUE, - schema_version INTEGER NOT NULL DEFAULT 1, - source_sequence INTEGER NOT NULL, - occurred_at INTEGER NOT NULL, - kind TEXT NOT NULL, - action TEXT NOT NULL, - status TEXT NOT NULL, - error_code TEXT, - actor_type TEXT NOT NULL, - actor_id TEXT NOT NULL, - agent_id TEXT, - session_key TEXT, - session_id TEXT, - run_id TEXT, - tool_call_id TEXT, - tool_name TEXT, - direction TEXT, - channel TEXT, - conversation_kind TEXT, - message_outcome TEXT, - reason_code TEXT, - delivery_kind TEXT, - failure_stage TEXT, - duration_ms INTEGER, - result_count INTEGER, - account_ref TEXT, - conversation_ref TEXT, - message_ref TEXT, - target_ref TEXT -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_audit_events_time - ON audit_events(occurred_at DESC, sequence DESC); - -CREATE INDEX IF NOT EXISTS idx_audit_events_agent_sequence - ON audit_events(agent_id, sequence DESC); - -CREATE INDEX IF NOT EXISTS idx_audit_events_session_sequence - ON audit_events(session_key, sequence DESC); - -CREATE INDEX IF NOT EXISTS idx_audit_events_run_sequence - ON audit_events(run_id, sequence DESC); - -CREATE INDEX IF NOT EXISTS idx_audit_events_kind_sequence - ON audit_events(kind, sequence DESC); - -CREATE INDEX IF NOT EXISTS idx_audit_events_status_sequence - ON audit_events(status, sequence DESC); - -CREATE INDEX IF NOT EXISTS idx_audit_events_channel_sequence - ON audit_events(channel, sequence DESC); - -CREATE INDEX IF NOT EXISTS idx_audit_events_direction_sequence - ON audit_events(direction, sequence DESC); - -CREATE TABLE IF NOT EXISTS audit_identity_keys ( - id INTEGER NOT NULL PRIMARY KEY CHECK (id = 1), - key_id TEXT NOT NULL, - key BLOB NOT NULL, - created_at INTEGER NOT NULL -) STRICT; - -CREATE TABLE IF NOT EXISTS session_state_events ( - sequence INTEGER PRIMARY KEY AUTOINCREMENT, - dedupe_key TEXT UNIQUE, - session_key TEXT NOT NULL, - session_id TEXT, - agent_id TEXT NOT NULL, - kind TEXT NOT NULL, - actor_type TEXT NOT NULL, - actor_id TEXT, - run_id TEXT, - occurred_at INTEGER NOT NULL, - summary TEXT NOT NULL, - payload_json TEXT -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_session_state_events_session_sequence - ON session_state_events(session_key, sequence DESC); - -CREATE INDEX IF NOT EXISTS idx_session_state_events_time - ON session_state_events(occurred_at DESC, sequence DESC); - -CREATE TABLE IF NOT EXISTS session_state_heads ( - session_key TEXT NOT NULL, - agent_id TEXT NOT NULL, - last_sequence INTEGER NOT NULL, - pruned_max_sequence INTEGER NOT NULL DEFAULT 0, - updated_at INTEGER NOT NULL, - PRIMARY KEY (session_key, agent_id) -) STRICT; - --- Notifiable watcher identity is the bare session key, matching the process-local --- system-event queue it feeds. Provenance distinguishes explicit immediate-wake --- watches from ambient queue-only group watches. Other bare keys --- (session.scope="global") are ambiguous across agents and excluded until watcher --- identity is agent-scoped end-to-end. -CREATE TABLE IF NOT EXISTS session_watch_cursors ( - watcher_session_key TEXT NOT NULL, - target_session_key TEXT NOT NULL, - last_seen_sequence INTEGER NOT NULL DEFAULT 0, - notified_sequence INTEGER NOT NULL DEFAULT 0, - material_sequence INTEGER NOT NULL DEFAULT 0, - provenance TEXT NOT NULL DEFAULT 'explicit' CHECK (provenance IN ('explicit', 'ambient-group')), - updated_at INTEGER NOT NULL, - PRIMARY KEY (watcher_session_key, target_session_key) -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_session_watch_cursors_target - ON session_watch_cursors(target_session_key); - -CREATE TABLE IF NOT EXISTS session_upstream_links ( - session_key TEXT NOT NULL, - agent_id TEXT NOT NULL, - catalog_id TEXT NOT NULL, - host_id TEXT NOT NULL, - thread_id TEXT NOT NULL, - upstream_kind TEXT NOT NULL, - upstream_ref_json TEXT, - last_marker_json TEXT, - last_scanned_at INTEGER, - created_at INTEGER NOT NULL, - updated_at INTEGER NOT NULL, - -- (session_key, agent_id) composite identity: under session.scope="global" agents - -- share bare keys; a key-only row would let one agent overwrite another's upstream. - PRIMARY KEY (session_key, agent_id) -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_session_upstream_links_catalog_id - ON session_upstream_links(catalog_id); - -CREATE TABLE IF NOT EXISTS diagnostic_stability_bundles ( - bundle_key TEXT NOT NULL PRIMARY KEY, - reason TEXT NOT NULL, - generated_at TEXT NOT NULL, - bundle_json TEXT NOT NULL, - created_at INTEGER NOT NULL -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_diagnostic_stability_bundles_created - ON diagnostic_stability_bundles(created_at DESC, bundle_key); - -CREATE TABLE IF NOT EXISTS state_leases ( - scope TEXT NOT NULL, - lease_key TEXT NOT NULL, - owner TEXT NOT NULL, - expires_at INTEGER, - heartbeat_at INTEGER, - payload_json TEXT, - created_at INTEGER NOT NULL, - updated_at INTEGER NOT NULL, - PRIMARY KEY (scope, lease_key) -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_state_leases_expiry - ON state_leases(expires_at, scope, lease_key) - WHERE expires_at IS NOT NULL; - -CREATE INDEX IF NOT EXISTS idx_state_leases_owner - ON state_leases(owner, updated_at DESC); - -CREATE TABLE IF NOT EXISTS exec_approvals_config ( - config_key TEXT NOT NULL PRIMARY KEY, - raw_json TEXT NOT NULL, - socket_path TEXT, - has_socket_token INTEGER NOT NULL, - default_security TEXT, - default_ask TEXT, - default_ask_fallback TEXT, - auto_allow_skills INTEGER, - agent_count INTEGER NOT NULL, - allowlist_count INTEGER NOT NULL, - updated_at_ms INTEGER NOT NULL -) STRICT; - -CREATE TABLE IF NOT EXISTS operator_approvals ( - approval_id TEXT NOT NULL PRIMARY KEY CHECK ( - length(approval_id) > 0 AND approval_id NOT IN ('.', '..') - ), - resolution_ref TEXT NOT NULL CHECK ( - length(resolution_ref) = 43 AND resolution_ref NOT GLOB '*[^A-Za-z0-9_-]*' - ), - kind TEXT NOT NULL CHECK (kind IN ('exec', 'plugin', 'system-agent')), - status TEXT NOT NULL CHECK (status IN ('pending', 'allowed', 'denied', 'expired', 'cancelled')), - presentation_json TEXT NOT NULL, - requested_by_device_id TEXT, - requested_by_client_id TEXT, - requested_by_device_token_auth INTEGER NOT NULL DEFAULT 0, - reviewer_device_ids_json TEXT NOT NULL, - source_agent_id TEXT, - source_session_key TEXT, - source_session_id TEXT, - source_run_id TEXT, - source_tool_call_id TEXT, - source_tool_name TEXT, - audience_session_keys_json TEXT NOT NULL, - runtime_epoch TEXT NOT NULL, - created_at_ms INTEGER NOT NULL, - expires_at_ms INTEGER NOT NULL, - updated_at_ms INTEGER NOT NULL, - decision TEXT CHECK (decision IN ('allow-once', 'allow-always', 'deny')), - terminal_reason TEXT CHECK ( - terminal_reason IN ( - 'user', - 'timeout', - 'malformed-verdict', - 'no-route', - 'run-aborted', - 'gateway-restart', - 'storage-corrupt' - ) - ), - resolved_at_ms INTEGER, - resolver_kind TEXT CHECK (resolver_kind IN ('device', 'channel', 'runtime', 'system')), - resolver_id TEXT, - consumed_at_ms INTEGER, - consumed_by TEXT, - CHECK (expires_at_ms >= created_at_ms), - CHECK (updated_at_ms >= created_at_ms), - CHECK (resolved_at_ms IS NULL OR resolved_at_ms >= created_at_ms), - CHECK (resolved_at_ms IS NULL OR resolved_at_ms <= updated_at_ms), - CHECK (consumed_at_ms IS NULL OR consumed_at_ms >= resolved_at_ms), - CHECK (consumed_at_ms IS NULL OR consumed_at_ms <= updated_at_ms), - CHECK (requested_by_device_token_auth IN (0, 1)), - CHECK ( - ( - status = 'pending' - AND decision IS NULL - AND terminal_reason IS NULL - AND resolved_at_ms IS NULL - AND resolver_kind IS NULL - AND resolver_id IS NULL - AND consumed_at_ms IS NULL - AND consumed_by IS NULL - ) - OR ( - status = 'allowed' - AND decision IN ('allow-once', 'allow-always') - AND terminal_reason = 'user' - AND resolved_at_ms IS NOT NULL - AND resolver_kind IS NOT NULL - ) - OR ( - status = 'denied' - AND decision = 'deny' - AND terminal_reason IN ('user', 'malformed-verdict', 'no-route', 'storage-corrupt') - AND resolved_at_ms IS NOT NULL - AND resolver_kind IS NOT NULL - AND consumed_at_ms IS NULL - AND consumed_by IS NULL - ) - OR ( - status = 'expired' - AND decision = 'deny' - AND terminal_reason = 'timeout' - AND resolved_at_ms IS NOT NULL - AND resolver_kind IS NOT NULL - AND consumed_at_ms IS NULL - AND consumed_by IS NULL - ) - OR ( - status = 'cancelled' - AND decision = 'deny' - AND terminal_reason IN ('run-aborted', 'gateway-restart') - AND resolved_at_ms IS NOT NULL - AND resolver_kind IS NOT NULL - AND consumed_at_ms IS NULL - AND consumed_by IS NULL - ) - ), - CHECK ( - (consumed_at_ms IS NULL AND consumed_by IS NULL) - OR ( - status = 'allowed' - AND decision = 'allow-once' - AND consumed_at_ms IS NOT NULL - AND consumed_by IS NOT NULL - ) - ) -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_operator_approvals_status_expiry - ON operator_approvals(status, expires_at_ms, approval_id); - -CREATE UNIQUE INDEX IF NOT EXISTS idx_operator_approvals_resolution_ref - ON operator_approvals(resolution_ref); - -CREATE INDEX IF NOT EXISTS idx_operator_approvals_source_session_created - ON operator_approvals(source_session_key, created_at_ms DESC, approval_id); - -CREATE INDEX IF NOT EXISTS idx_operator_approvals_resolved - ON operator_approvals(resolved_at_ms, approval_id) - WHERE resolved_at_ms IS NOT NULL; - -CREATE INDEX IF NOT EXISTS idx_operator_approvals_runtime_pending - ON operator_approvals(runtime_epoch, approval_id) - WHERE status = 'pending'; - -CREATE TABLE IF NOT EXISTS schema_meta ( - meta_key TEXT NOT NULL PRIMARY KEY, - role TEXT NOT NULL, - schema_version INTEGER NOT NULL, - agent_id TEXT, - app_version TEXT, - created_at INTEGER NOT NULL, - updated_at INTEGER NOT NULL -) STRICT; - -CREATE TABLE IF NOT EXISTS config_machine_state ( - state_key TEXT NOT NULL PRIMARY KEY, - value_json TEXT NOT NULL, - updated_at_ms INTEGER NOT NULL -) STRICT; - -CREATE TABLE IF NOT EXISTS device_pairing_pending ( - request_id TEXT NOT NULL PRIMARY KEY, - device_id TEXT NOT NULL, - public_key TEXT NOT NULL, - display_name TEXT, - platform TEXT, - device_family TEXT, - client_id TEXT, - client_mode TEXT, - browser_origin TEXT, - role TEXT, - roles_json TEXT, - scopes_json TEXT, - remote_ip TEXT, - silent INTEGER, - is_repair INTEGER, - ts INTEGER NOT NULL, - refreshed_at_ms INTEGER -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_device_pairing_pending_device - ON device_pairing_pending(device_id, ts DESC); - -CREATE TABLE IF NOT EXISTS device_pairing_paired ( - device_id TEXT NOT NULL PRIMARY KEY, - public_key TEXT NOT NULL, - display_name TEXT, - operator_label TEXT, - platform TEXT, - device_family TEXT, - client_id TEXT, - client_mode TEXT, - browser_origin TEXT, - role TEXT, - roles_json TEXT, - scopes_json TEXT, - approved_scopes_json TEXT, - remote_ip TEXT, - tokens_json TEXT, - approved_via TEXT, - node_surface_json TEXT, - pending_node_surface_json TEXT, - created_at_ms INTEGER NOT NULL, - approved_at_ms INTEGER NOT NULL, - last_seen_at_ms INTEGER, - last_seen_reason TEXT -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_device_pairing_paired_approved - ON device_pairing_paired(approved_at_ms DESC, device_id); - -CREATE TABLE IF NOT EXISTS device_bootstrap_tokens ( - token_key TEXT NOT NULL PRIMARY KEY, - token TEXT NOT NULL, - ts INTEGER NOT NULL, - device_id TEXT, - public_key TEXT, - profile_json TEXT, - redeemed_profile_json TEXT, - pending_profile_json TEXT, - issued_at_ms INTEGER NOT NULL, - last_used_at_ms INTEGER -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_device_bootstrap_tokens_ts - ON device_bootstrap_tokens(ts); - -CREATE TABLE IF NOT EXISTS device_identities ( - identity_key TEXT NOT NULL PRIMARY KEY, - device_id TEXT NOT NULL, - public_key_pem TEXT NOT NULL, - private_key_pem TEXT NOT NULL, - created_at_ms INTEGER NOT NULL, - updated_at_ms INTEGER NOT NULL -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_device_identities_device - ON device_identities(device_id, updated_at_ms DESC); - -CREATE TABLE IF NOT EXISTS device_auth_tokens ( - device_id TEXT NOT NULL, - role TEXT NOT NULL, - token TEXT NOT NULL, - scopes_json TEXT NOT NULL, - updated_at_ms INTEGER NOT NULL, - PRIMARY KEY (device_id, role) -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_device_auth_tokens_updated - ON device_auth_tokens(updated_at_ms DESC, device_id, role); - -CREATE TABLE IF NOT EXISTS android_notification_recent_packages ( - package_name TEXT NOT NULL PRIMARY KEY, - sort_order INTEGER NOT NULL, - updated_at_ms INTEGER NOT NULL -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_android_notification_recent_packages_order - ON android_notification_recent_packages(sort_order, package_name); - -CREATE TABLE IF NOT EXISTS macos_port_guardian_records ( - pid INTEGER NOT NULL PRIMARY KEY, - port INTEGER NOT NULL, - command TEXT NOT NULL, - mode TEXT NOT NULL, - timestamp REAL NOT NULL -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_macos_port_guardian_records_port - ON macos_port_guardian_records(port, timestamp DESC); - -CREATE TABLE IF NOT EXISTS onboarding_recommendations ( - config_key TEXT NOT NULL PRIMARY KEY, - inventory_hash TEXT NOT NULL, - matches_json TEXT NOT NULL, - offered_at_ms INTEGER NOT NULL, - accepted_at_ms INTEGER, - updated_at_ms INTEGER NOT NULL -) STRICT; - -CREATE TABLE IF NOT EXISTS workspace_setup_state ( - workspace_key TEXT NOT NULL PRIMARY KEY, - workspace_path TEXT NOT NULL, - version INTEGER NOT NULL, - bootstrap_seeded_at TEXT, - setup_completed_at TEXT, - updated_at INTEGER NOT NULL -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_workspace_setup_state_path - ON workspace_setup_state(workspace_path); - -CREATE TABLE IF NOT EXISTS workspace_path_aliases ( - alias_key TEXT NOT NULL PRIMARY KEY, - alias_path TEXT NOT NULL, - workspace_key TEXT NOT NULL, - workspace_path TEXT NOT NULL, - updated_at_ms INTEGER NOT NULL -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_workspace_path_aliases_workspace - ON workspace_path_aliases(workspace_key); - -CREATE TABLE IF NOT EXISTS workspace_attestations ( - workspace_key TEXT NOT NULL PRIMARY KEY, - attested_at_ms INTEGER NOT NULL, - updated_at_ms INTEGER NOT NULL -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_workspace_attestations_attested - ON workspace_attestations(attested_at_ms DESC, workspace_key); - -CREATE TABLE IF NOT EXISTS workspace_generated_bootstrap_hashes ( - workspace_key TEXT NOT NULL, - filename TEXT NOT NULL, - sha256 TEXT NOT NULL, - PRIMARY KEY (workspace_key, filename), - FOREIGN KEY (workspace_key) REFERENCES workspace_attestations(workspace_key) ON DELETE CASCADE -) STRICT; - -CREATE TABLE IF NOT EXISTS native_hook_relay_bridges ( - relay_id TEXT NOT NULL PRIMARY KEY, - pid INTEGER NOT NULL, - hostname TEXT NOT NULL, - port INTEGER NOT NULL, - token TEXT NOT NULL, - expires_at_ms INTEGER NOT NULL, - updated_at_ms INTEGER NOT NULL -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_native_hook_relay_bridges_expires - ON native_hook_relay_bridges(expires_at_ms, relay_id); - -CREATE TABLE IF NOT EXISTS model_capability_cache ( - provider_id TEXT NOT NULL, - model_id TEXT NOT NULL, - name TEXT NOT NULL, - input_text INTEGER NOT NULL, - input_image INTEGER NOT NULL, - reasoning INTEGER NOT NULL, - supports_tools INTEGER, - context_window INTEGER NOT NULL, - max_tokens INTEGER NOT NULL, - cost_input REAL NOT NULL, - cost_output REAL NOT NULL, - cost_cache_read REAL NOT NULL, - cost_cache_write REAL NOT NULL, - updated_at_ms INTEGER NOT NULL, - PRIMARY KEY (provider_id, model_id) -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_model_capability_cache_provider_updated - ON model_capability_cache(provider_id, updated_at_ms DESC, model_id); - -CREATE TABLE IF NOT EXISTS agent_model_catalogs ( - catalog_key TEXT NOT NULL PRIMARY KEY, - agent_dir TEXT NOT NULL, - raw_json TEXT NOT NULL, - updated_at INTEGER NOT NULL -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_agent_model_catalogs_agent_dir - ON agent_model_catalogs(agent_dir, updated_at DESC); - -CREATE TABLE IF NOT EXISTS managed_outgoing_image_records ( - attachment_id TEXT NOT NULL PRIMARY KEY, - session_key TEXT NOT NULL, - agent_id TEXT, - message_id TEXT, - created_at TEXT NOT NULL, - updated_at TEXT, - retention_class TEXT, - alt TEXT NOT NULL, - original_media_root TEXT NOT NULL, - original_media_id TEXT NOT NULL, - original_media_subdir TEXT NOT NULL, - original_content_type TEXT NOT NULL, - original_width INTEGER, - original_height INTEGER, - original_size_bytes INTEGER, - original_filename TEXT, - record_json TEXT NOT NULL, - cleanup_pending INTEGER NOT NULL DEFAULT 0 CHECK (cleanup_pending IN (0, 1)) -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_managed_outgoing_images_session - ON managed_outgoing_image_records(session_key, created_at DESC, attachment_id); - -CREATE INDEX IF NOT EXISTS idx_managed_outgoing_images_message - ON managed_outgoing_image_records(session_key, message_id, attachment_id) - WHERE message_id IS NOT NULL; - -CREATE INDEX IF NOT EXISTS idx_managed_outgoing_images_agent_session - ON managed_outgoing_image_records(session_key, agent_id, created_at DESC, attachment_id); - -CREATE INDEX IF NOT EXISTS idx_managed_outgoing_images_agent_message - ON managed_outgoing_image_records(session_key, agent_id, message_id, attachment_id) - WHERE message_id IS NOT NULL; - -CREATE TABLE IF NOT EXISTS channel_pairing_requests ( - channel_key TEXT NOT NULL, - account_id TEXT NOT NULL, - request_id TEXT NOT NULL, - code TEXT NOT NULL, - created_at TEXT NOT NULL, - last_seen_at TEXT NOT NULL, - meta_json TEXT, - PRIMARY KEY (channel_key, account_id, request_id) -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_channel_pairing_requests_code - ON channel_pairing_requests(channel_key, code); - -CREATE INDEX IF NOT EXISTS idx_channel_pairing_requests_created - ON channel_pairing_requests(channel_key, created_at, request_id); - -CREATE TABLE IF NOT EXISTS channel_pairing_allow_entries ( - channel_key TEXT NOT NULL, - account_id TEXT NOT NULL, - entry TEXT NOT NULL, - sort_order INTEGER NOT NULL, - updated_at INTEGER NOT NULL, - PRIMARY KEY (channel_key, account_id, entry) -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_channel_pairing_allow_account - ON channel_pairing_allow_entries(channel_key, account_id, sort_order, entry); - -CREATE TABLE IF NOT EXISTS web_push_subscriptions ( - endpoint_hash TEXT NOT NULL PRIMARY KEY, - subscription_id TEXT NOT NULL UNIQUE, - endpoint TEXT NOT NULL, - p256dh TEXT NOT NULL, - auth TEXT NOT NULL, - created_at_ms INTEGER NOT NULL, - updated_at_ms INTEGER NOT NULL -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_web_push_subscriptions_updated - ON web_push_subscriptions(updated_at_ms DESC, subscription_id); - -CREATE TABLE IF NOT EXISTS web_push_vapid_keys ( - key_id TEXT NOT NULL PRIMARY KEY, - public_key TEXT NOT NULL, - private_key TEXT NOT NULL, - subject TEXT NOT NULL, - updated_at_ms INTEGER NOT NULL -) STRICT; - -CREATE TABLE IF NOT EXISTS apns_registrations ( - node_id TEXT NOT NULL PRIMARY KEY, - transport TEXT NOT NULL, - token TEXT, - relay_handle TEXT, - send_grant TEXT, - installation_id TEXT, - relay_origin TEXT, - topic TEXT NOT NULL, - environment TEXT NOT NULL, - distribution TEXT, - token_debug_suffix TEXT, - updated_at_ms INTEGER NOT NULL -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_apns_registrations_updated - ON apns_registrations(updated_at_ms DESC, node_id); - -CREATE TABLE IF NOT EXISTS apns_registration_tombstones ( - node_id TEXT NOT NULL PRIMARY KEY, - deleted_at_ms INTEGER NOT NULL -) STRICT; - -CREATE TABLE IF NOT EXISTS node_host_config ( - config_key TEXT NOT NULL PRIMARY KEY, - version INTEGER NOT NULL, - node_id TEXT NOT NULL, - token TEXT, - display_name TEXT, - gateway_host TEXT, - gateway_port INTEGER, - gateway_tls INTEGER, - gateway_tls_fingerprint TEXT, - gateway_context_path TEXT, - installed_apps_sharing INTEGER NOT NULL DEFAULT 0, - updated_at_ms INTEGER NOT NULL -) STRICT; - -CREATE TABLE IF NOT EXISTS voicewake_triggers ( - config_key TEXT NOT NULL, - position INTEGER NOT NULL, - trigger TEXT NOT NULL, - updated_at_ms INTEGER NOT NULL, - PRIMARY KEY (config_key, position) -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_voicewake_triggers_trigger - ON voicewake_triggers(config_key, trigger); - -CREATE TABLE IF NOT EXISTS voicewake_routing_config ( - config_key TEXT NOT NULL PRIMARY KEY, - version INTEGER NOT NULL, - default_target_mode TEXT NOT NULL, - default_target_agent_id TEXT, - default_target_session_key TEXT, - updated_at_ms INTEGER NOT NULL -) STRICT; - -CREATE TABLE IF NOT EXISTS voicewake_routing_routes ( - config_key TEXT NOT NULL, - position INTEGER NOT NULL, - trigger TEXT NOT NULL, - target_mode TEXT NOT NULL, - target_agent_id TEXT, - target_session_key TEXT, - updated_at_ms INTEGER NOT NULL, - PRIMARY KEY (config_key, position), - FOREIGN KEY (config_key) REFERENCES voicewake_routing_config(config_key) ON DELETE CASCADE -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_voicewake_routing_routes_trigger - ON voicewake_routing_routes(config_key, trigger); - -CREATE TABLE IF NOT EXISTS update_check_state ( - state_key TEXT NOT NULL PRIMARY KEY, - last_checked_at TEXT, - last_notified_version TEXT, - last_notified_tag TEXT, - last_available_version TEXT, - last_available_tag TEXT, - auto_install_id TEXT, - auto_first_seen_version TEXT, - auto_first_seen_tag TEXT, - auto_first_seen_at TEXT, - auto_last_attempt_version TEXT, - auto_last_attempt_at TEXT, - auto_last_success_version TEXT, - auto_last_success_at TEXT, - updated_at_ms INTEGER NOT NULL -) STRICT; - -CREATE TABLE IF NOT EXISTS config_health_entries ( - config_path TEXT NOT NULL PRIMARY KEY, - last_known_good_json TEXT, - last_promoted_good_json TEXT, - last_observed_suspicious_signature TEXT, - updated_at_ms INTEGER NOT NULL -) STRICT; - -CREATE TABLE IF NOT EXISTS clawhub_promotions_feed_state ( - state_key TEXT NOT NULL PRIMARY KEY, - etag TEXT, - payload_json TEXT, - feed_sequence INTEGER, - last_checked_at_ms INTEGER, - notified_slugs_json TEXT NOT NULL DEFAULT '[]', - updated_at_ms INTEGER NOT NULL -) STRICT; - -CREATE TABLE IF NOT EXISTS clawhub_promotion_claims ( - slug TEXT NOT NULL PRIMARY KEY, - provider TEXT, - model_keys_json TEXT NOT NULL, - ends_at_ms INTEGER NOT NULL, - claimed_at_ms INTEGER NOT NULL -) STRICT; - -CREATE TABLE IF NOT EXISTS installed_plugin_index ( - index_key TEXT NOT NULL PRIMARY KEY, - version INTEGER NOT NULL, - host_contract_version TEXT NOT NULL, - compat_registry_version TEXT NOT NULL, - migration_version INTEGER NOT NULL, - policy_hash TEXT NOT NULL, - generated_at_ms INTEGER NOT NULL, - refresh_reason TEXT, - install_records_json TEXT NOT NULL, - plugins_json TEXT NOT NULL, - diagnostics_json TEXT NOT NULL, - warning TEXT, - updated_at_ms INTEGER NOT NULL -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_installed_plugin_index_generated - ON installed_plugin_index(generated_at_ms DESC, index_key); - -CREATE TABLE IF NOT EXISTS official_external_plugin_catalog_snapshots ( - feed_url TEXT NOT NULL PRIMARY KEY, - body TEXT NOT NULL, - status INTEGER NOT NULL, - etag TEXT, - last_modified TEXT, - checksum TEXT NOT NULL, - saved_at TEXT NOT NULL, - trust_mode TEXT, - trust_key_id TEXT, - trust_signature_count INTEGER, - trust_threshold INTEGER, - trust_verified_at TEXT, - updated_at_ms INTEGER NOT NULL -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_official_external_plugin_catalog_snapshots_updated - ON official_external_plugin_catalog_snapshots(updated_at_ms DESC, feed_url); - -CREATE TABLE IF NOT EXISTS gateway_restart_sentinel ( - sentinel_key TEXT NOT NULL PRIMARY KEY, - version INTEGER NOT NULL, - kind TEXT NOT NULL, - status TEXT NOT NULL, - ts INTEGER NOT NULL, - session_key TEXT, - thread_id TEXT, - delivery_channel TEXT, - delivery_to TEXT, - delivery_account_id TEXT, - message TEXT, - continuation_json TEXT, - doctor_hint TEXT, - stats_json TEXT, - payload_json TEXT NOT NULL, - updated_at_ms INTEGER NOT NULL -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_gateway_restart_sentinel_ts - ON gateway_restart_sentinel(ts DESC, sentinel_key); - -CREATE TABLE IF NOT EXISTS gateway_restart_intent ( - intent_key TEXT NOT NULL PRIMARY KEY, - kind TEXT NOT NULL, - pid INTEGER NOT NULL, - created_at INTEGER NOT NULL, - reason TEXT, - force INTEGER, - wait_ms INTEGER, - updated_at_ms INTEGER NOT NULL -) STRICT; - -CREATE TABLE IF NOT EXISTS gateway_restart_handoff ( - handoff_key TEXT NOT NULL PRIMARY KEY, - kind TEXT NOT NULL, - version INTEGER NOT NULL, - intent_id TEXT NOT NULL, - pid INTEGER NOT NULL, - process_instance_id TEXT, - created_at INTEGER NOT NULL, - expires_at INTEGER NOT NULL, - reason TEXT, - restart_trace_started_at INTEGER, - restart_trace_last_at INTEGER, - source TEXT NOT NULL, - restart_kind TEXT NOT NULL, - supervisor_mode TEXT NOT NULL, - updated_at_ms INTEGER NOT NULL -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_gateway_restart_handoff_expiry - ON gateway_restart_handoff(expires_at, pid); - -CREATE TABLE IF NOT EXISTS gateway_boot_lifecycle ( - boot_id TEXT NOT NULL PRIMARY KEY, - pid INTEGER NOT NULL, - started_at_ms INTEGER NOT NULL, - completed_at_ms INTEGER, - outcome TEXT, - startup_reason TEXT, - reason TEXT -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_gateway_boot_lifecycle_started - ON gateway_boot_lifecycle(started_at_ms); - -CREATE TABLE IF NOT EXISTS acp_sessions ( - session_key TEXT NOT NULL PRIMARY KEY, - session_id TEXT, - backend TEXT NOT NULL, - agent TEXT NOT NULL, - runtime_session_name TEXT NOT NULL, - identity_json TEXT, - mode TEXT NOT NULL, - runtime_options_json TEXT, - cwd TEXT, - state TEXT NOT NULL, - last_activity_at INTEGER NOT NULL, - last_error TEXT, - updated_at INTEGER NOT NULL -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_acp_sessions_state_activity - ON acp_sessions(state, last_activity_at DESC, session_key); - -CREATE INDEX IF NOT EXISTS idx_acp_sessions_agent_activity - ON acp_sessions(agent, last_activity_at DESC, session_key); - -CREATE TABLE IF NOT EXISTS acp_replay_sessions ( - session_id TEXT NOT NULL PRIMARY KEY, - session_key TEXT NOT NULL, - cwd TEXT NOT NULL, - complete INTEGER NOT NULL, - created_at INTEGER NOT NULL, - updated_at INTEGER NOT NULL, - next_seq INTEGER NOT NULL, - -- Running estimate of this session's ledger footprint (row overhead plus - -- all event rows), maintained at insert/trim so budget checks never scan - -- acp_replay_events (#100622). - estimated_bytes INTEGER NOT NULL DEFAULT 0 -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_acp_replay_sessions_key_updated - ON acp_replay_sessions(session_key, complete, updated_at DESC, session_id); - -CREATE INDEX IF NOT EXISTS idx_acp_replay_sessions_updated - ON acp_replay_sessions(updated_at DESC, session_id); - -CREATE TABLE IF NOT EXISTS acp_replay_events ( - session_id TEXT NOT NULL, - seq INTEGER NOT NULL, - at INTEGER NOT NULL, - session_key TEXT NOT NULL, - run_id TEXT, - update_json TEXT NOT NULL, - estimated_bytes INTEGER NOT NULL DEFAULT 0, - PRIMARY KEY (session_id, seq), - FOREIGN KEY (session_id) REFERENCES acp_replay_sessions(session_id) ON DELETE CASCADE -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_acp_replay_events_session_seq - ON acp_replay_events(session_id, seq); - -CREATE TABLE IF NOT EXISTS agent_databases ( - agent_id TEXT NOT NULL, - path TEXT NOT NULL, - schema_version INTEGER NOT NULL, - last_seen_at INTEGER NOT NULL, - size_bytes INTEGER, - PRIMARY KEY (agent_id, path) -) STRICT; - -CREATE TABLE IF NOT EXISTS agent_deletion_journal ( - agent_id TEXT PRIMARY KEY, - operation_id TEXT NOT NULL DEFAULT '', - agent_dir TEXT NOT NULL, - workspace_dir TEXT NOT NULL, - sessions_dir TEXT NOT NULL, - database_paths_json TEXT NOT NULL DEFAULT '[]', - cleanup_paths_json TEXT NOT NULL DEFAULT '[]', - created_at INTEGER NOT NULL, - cleanup_completed INTEGER NOT NULL DEFAULT 0, - delete_files INTEGER NOT NULL DEFAULT 1 -) STRICT; - -CREATE TABLE IF NOT EXISTS agent_database_leases ( - lease_id TEXT PRIMARY KEY, - agent_id TEXT NOT NULL, - path TEXT NOT NULL, - owner_pid INTEGER NOT NULL, - owner_start_time INTEGER, - opened_at INTEGER NOT NULL -) STRICT; - -CREATE TABLE IF NOT EXISTS plugin_state_entries ( - plugin_id TEXT NOT NULL, - namespace TEXT NOT NULL, - entry_key TEXT NOT NULL, - value_json TEXT NOT NULL, - created_at INTEGER NOT NULL, - expires_at INTEGER, - PRIMARY KEY (plugin_id, namespace, entry_key) -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_plugin_state_expiry - ON plugin_state_entries(expires_at) - WHERE expires_at IS NOT NULL; - -CREATE INDEX IF NOT EXISTS idx_plugin_state_listing - ON plugin_state_entries(plugin_id, namespace, created_at, entry_key); - -CREATE TABLE IF NOT EXISTS channel_ingress_events ( - queue_name TEXT NOT NULL, - event_id TEXT NOT NULL, - channel_id TEXT NOT NULL, - account_id TEXT NOT NULL, - status TEXT NOT NULL, - lane_key TEXT, - payload_json TEXT NOT NULL, - metadata_json TEXT, - received_at INTEGER NOT NULL, - updated_at INTEGER NOT NULL, - claim_token TEXT, - claim_owner TEXT, - claimed_at INTEGER, - attempts INTEGER NOT NULL DEFAULT 0, - last_attempt_at INTEGER, - last_error TEXT, - failed_reason TEXT, - failed_at INTEGER, - completed_at INTEGER, - completed_metadata_json TEXT, - PRIMARY KEY (queue_name, event_id) -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_channel_ingress_pending - ON channel_ingress_events(queue_name, status, received_at, event_id); - -CREATE INDEX IF NOT EXISTS idx_channel_ingress_claims - ON channel_ingress_events(queue_name, status, claimed_at); - -CREATE INDEX IF NOT EXISTS idx_channel_ingress_lane - ON channel_ingress_events(queue_name, status, lane_key); - -CREATE TABLE IF NOT EXISTS plugin_blob_entries ( - plugin_id TEXT NOT NULL, - namespace TEXT NOT NULL, - entry_key TEXT NOT NULL, - metadata_json TEXT NOT NULL, - blob BLOB NOT NULL, - created_at INTEGER NOT NULL, - expires_at INTEGER, - PRIMARY KEY (plugin_id, namespace, entry_key) -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_plugin_blob_expiry - ON plugin_blob_entries(expires_at) - WHERE expires_at IS NOT NULL; - -CREATE INDEX IF NOT EXISTS idx_plugin_blob_listing - ON plugin_blob_entries(plugin_id, namespace, created_at, entry_key); - -CREATE TABLE IF NOT EXISTS media_blobs ( - subdir TEXT NOT NULL, - id TEXT NOT NULL, - content_type TEXT, - size_bytes INTEGER NOT NULL, - blob BLOB NOT NULL, - created_at INTEGER NOT NULL, - updated_at INTEGER NOT NULL, - PRIMARY KEY (subdir, id) -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_media_blobs_created - ON media_blobs(created_at); - -CREATE TABLE IF NOT EXISTS skill_uploads ( - upload_id TEXT NOT NULL PRIMARY KEY, - kind TEXT NOT NULL, - slug TEXT NOT NULL, - force INTEGER NOT NULL, - size_bytes INTEGER NOT NULL, - sha256 TEXT, - actual_sha256 TEXT, - received_bytes INTEGER NOT NULL, - archive_blob BLOB NOT NULL, - created_at INTEGER NOT NULL, - expires_at INTEGER NOT NULL, - committed INTEGER NOT NULL, - committed_at INTEGER, - idempotency_key_hash TEXT UNIQUE -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_skill_uploads_expiry - ON skill_uploads(expires_at); - -CREATE INDEX IF NOT EXISTS idx_skill_uploads_idempotency - ON skill_uploads(idempotency_key_hash) - WHERE idempotency_key_hash IS NOT NULL; - -CREATE TABLE IF NOT EXISTS skill_upload_chunks ( - upload_id TEXT NOT NULL, - byte_offset INTEGER NOT NULL CHECK (byte_offset >= 0), - size_bytes INTEGER NOT NULL CHECK (size_bytes > 0), - chunk_blob BLOB NOT NULL, - PRIMARY KEY (upload_id, byte_offset), - FOREIGN KEY (upload_id) REFERENCES skill_uploads(upload_id) ON DELETE CASCADE, - CHECK (length(chunk_blob) = size_bytes) -) STRICT; - -CREATE TABLE IF NOT EXISTS capture_sessions ( - id TEXT NOT NULL PRIMARY KEY, - started_at INTEGER NOT NULL, - ended_at INTEGER, - mode TEXT NOT NULL, - source_scope TEXT NOT NULL, - source_process TEXT NOT NULL, - proxy_url TEXT -) STRICT; - -CREATE TABLE IF NOT EXISTS capture_blobs ( - blob_id TEXT NOT NULL PRIMARY KEY, - content_type TEXT, - encoding TEXT NOT NULL, - size_bytes INTEGER NOT NULL, - sha256 TEXT NOT NULL, - data BLOB NOT NULL, - created_at INTEGER NOT NULL -) STRICT; - -CREATE TABLE IF NOT EXISTS capture_events ( - id INTEGER NOT NULL PRIMARY KEY, - session_id TEXT NOT NULL, - ts INTEGER NOT NULL, - source_scope TEXT NOT NULL, - source_process TEXT NOT NULL, - protocol TEXT NOT NULL, - direction TEXT NOT NULL, - kind TEXT NOT NULL, - flow_id TEXT NOT NULL, - method TEXT, - host TEXT, - path TEXT, - status INTEGER, - close_code INTEGER, - content_type TEXT, - headers_json TEXT, - data_text TEXT, - data_blob_id TEXT, - data_sha256 TEXT, - error_text TEXT, - meta_json TEXT, - FOREIGN KEY (session_id) REFERENCES capture_sessions(id) ON DELETE CASCADE, - FOREIGN KEY (data_blob_id) REFERENCES capture_blobs(blob_id) ON DELETE SET NULL -) STRICT; - -CREATE INDEX IF NOT EXISTS capture_events_session_ts_idx - ON capture_events(session_id, ts); - -CREATE INDEX IF NOT EXISTS capture_events_flow_idx - ON capture_events(flow_id, ts); - -CREATE TABLE IF NOT EXISTS sandbox_registry_entries ( - registry_kind TEXT NOT NULL, - container_name TEXT NOT NULL, - session_key TEXT, - backend_id TEXT, - runtime_label TEXT, - image TEXT, - created_at_ms INTEGER, - last_used_at_ms INTEGER, - config_label_kind TEXT, - config_hash TEXT, - cdp_port INTEGER, - no_vnc_port INTEGER, - entry_json TEXT NOT NULL, - updated_at INTEGER NOT NULL, - PRIMARY KEY (registry_kind, container_name) -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_sandbox_registry_updated - ON sandbox_registry_entries(registry_kind, updated_at DESC, container_name); - -CREATE INDEX IF NOT EXISTS idx_sandbox_registry_session - ON sandbox_registry_entries(registry_kind, session_key, last_used_at_ms DESC, container_name) - WHERE session_key IS NOT NULL; - -CREATE INDEX IF NOT EXISTS idx_sandbox_registry_last_used - ON sandbox_registry_entries(registry_kind, last_used_at_ms DESC, container_name) - WHERE last_used_at_ms IS NOT NULL; - -CREATE TABLE IF NOT EXISTS commitments ( - id TEXT NOT NULL PRIMARY KEY, - agent_id TEXT NOT NULL, - session_key TEXT NOT NULL, - channel TEXT NOT NULL, - account_id TEXT, - recipient_id TEXT, - thread_id TEXT, - sender_id TEXT, - kind TEXT NOT NULL, - sensitivity TEXT NOT NULL, - source TEXT NOT NULL, - status TEXT NOT NULL, - reason TEXT NOT NULL, - suggested_text TEXT NOT NULL, - dedupe_key TEXT NOT NULL, - confidence REAL NOT NULL, - due_earliest_ms INTEGER NOT NULL, - due_latest_ms INTEGER NOT NULL, - due_timezone TEXT NOT NULL, - source_message_id TEXT, - source_run_id TEXT, - created_at_ms INTEGER NOT NULL, - updated_at_ms INTEGER NOT NULL, - attempts INTEGER NOT NULL, - last_attempt_at_ms INTEGER, - sent_at_ms INTEGER, - dismissed_at_ms INTEGER, - snoozed_until_ms INTEGER, - expired_at_ms INTEGER, - record_json TEXT NOT NULL -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_commitments_scope_due - ON commitments(agent_id, session_key, status, due_earliest_ms, due_latest_ms); - -CREATE INDEX IF NOT EXISTS idx_commitments_status_due - ON commitments(status, due_earliest_ms, due_latest_ms); - -CREATE INDEX IF NOT EXISTS idx_commitments_scope_dedupe - ON commitments(agent_id, session_key, channel, dedupe_key, status); - -CREATE INDEX IF NOT EXISTS idx_commitments_agent_due - ON commitments(agent_id, status, due_earliest_ms, due_latest_ms, session_key); - -CREATE INDEX IF NOT EXISTS idx_commitments_agent_sent - ON commitments(agent_id, status, sent_at_ms, session_key); - -CREATE TABLE IF NOT EXISTS cron_jobs ( - store_key TEXT NOT NULL, - job_id TEXT NOT NULL, - declaration_key TEXT, - display_name TEXT, - owner_agent_id TEXT, - owner_session_key TEXT, - name TEXT NOT NULL, - description TEXT, - enabled INTEGER NOT NULL, - delete_after_run INTEGER, - created_at_ms INTEGER NOT NULL, - agent_id TEXT, - session_key TEXT, - schedule_kind TEXT NOT NULL, - schedule_expr TEXT, - schedule_tz TEXT, - every_ms INTEGER, - anchor_ms INTEGER, - at TEXT, - stagger_ms INTEGER, - session_target TEXT NOT NULL, - wake_mode TEXT NOT NULL, - trigger_script TEXT, - trigger_once INTEGER, - payload_kind TEXT NOT NULL, - payload_message TEXT, - payload_model TEXT, - payload_fallbacks_json TEXT, - payload_thinking TEXT, - payload_timeout_seconds INTEGER, - payload_allow_unsafe_external_content INTEGER, - payload_external_content_source_json TEXT, - payload_light_context INTEGER, - payload_tools_allow_json TEXT, - payload_tools_allow_is_default INTEGER, - delivery_mode TEXT, - delivery_channel TEXT, - delivery_to TEXT, - delivery_thread_id TEXT, - delivery_thread_id_type TEXT, - delivery_account_id TEXT, - delivery_best_effort INTEGER, - delivery_completion_mode TEXT, - delivery_completion_to TEXT, - failure_delivery_mode TEXT, - failure_delivery_channel TEXT, - failure_delivery_to TEXT, - failure_delivery_account_id TEXT, - failure_alert_disabled INTEGER, - failure_alert_after INTEGER, - failure_alert_channel TEXT, - failure_alert_to TEXT, - failure_alert_cooldown_ms INTEGER, - failure_alert_include_skipped INTEGER, - failure_alert_mode TEXT, - failure_alert_account_id TEXT, - next_run_at_ms INTEGER, - running_at_ms INTEGER, - last_run_at_ms INTEGER, - last_run_status TEXT, - last_error TEXT, - last_duration_ms INTEGER, - consecutive_errors INTEGER, - consecutive_skipped INTEGER, - schedule_error_count INTEGER, - last_delivery_status TEXT, - last_delivery_error TEXT, - last_delivered INTEGER, - last_failure_alert_at_ms INTEGER, - job_json TEXT NOT NULL, - state_json TEXT NOT NULL DEFAULT '{}', - runtime_updated_at_ms INTEGER, - schedule_identity TEXT, - sort_order INTEGER NOT NULL DEFAULT 0, - updated_at INTEGER NOT NULL, - PRIMARY KEY (store_key, job_id) -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_cron_jobs_store_updated - ON cron_jobs(store_key, sort_order ASC, updated_at DESC, job_id); - -CREATE INDEX IF NOT EXISTS idx_cron_jobs_store_order - ON cron_jobs(store_key, sort_order ASC, updated_at ASC, job_id); - -CREATE INDEX IF NOT EXISTS idx_cron_jobs_enabled_next_run - ON cron_jobs(store_key, enabled, next_run_at_ms, job_id) - WHERE next_run_at_ms IS NOT NULL; - -CREATE INDEX IF NOT EXISTS idx_cron_jobs_agent_session - ON cron_jobs(agent_id, session_key, updated_at DESC, job_id) - WHERE agent_id IS NOT NULL OR session_key IS NOT NULL; - --- Scratch is separate from cron_jobs so scheduler state writes and downgraded --- full-row replacement preserve it. New builds prune rows explicitly on job removal. --- content NULL is a tombstone: it keeps the revision lineage monotonic across --- unset/recreate so stale compare-and-swap writes cannot resurrect old content. -CREATE TABLE IF NOT EXISTS cron_job_scratch ( - store_key TEXT NOT NULL, - job_id TEXT NOT NULL, - content TEXT, - revision INTEGER NOT NULL, - source_sha256 TEXT, - updated_at_ms INTEGER NOT NULL, - PRIMARY KEY (store_key, job_id), - CHECK (revision >= 1), - CHECK (content IS NULL OR length(CAST(content AS BLOB)) <= 262144) -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_cron_job_scratch_store_updated - ON cron_job_scratch(store_key, updated_at_ms DESC, job_id); - -CREATE TABLE IF NOT EXISTS command_log_entries ( - id TEXT NOT NULL PRIMARY KEY, - timestamp_ms INTEGER NOT NULL, - action TEXT NOT NULL, - session_key TEXT NOT NULL, - sender_id TEXT NOT NULL, - source TEXT NOT NULL, - entry_json TEXT NOT NULL -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_command_log_entries_timestamp - ON command_log_entries(timestamp_ms DESC, id); - -CREATE INDEX IF NOT EXISTS idx_command_log_entries_session - ON command_log_entries(session_key, timestamp_ms DESC, id); - -CREATE TABLE IF NOT EXISTS delivery_queue_entries ( - queue_name TEXT NOT NULL, - id TEXT NOT NULL, - status TEXT NOT NULL, - entry_kind TEXT, - session_key TEXT, - channel TEXT, - target TEXT, - account_id TEXT, - retry_count INTEGER NOT NULL DEFAULT 0, - last_attempt_at INTEGER, - last_error TEXT, - recovery_state TEXT, - platform_send_started_at INTEGER, - entry_json TEXT NOT NULL, - enqueued_at INTEGER NOT NULL, - updated_at INTEGER NOT NULL, - failed_at INTEGER, - PRIMARY KEY (queue_name, id) -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_delivery_queue_pending - ON delivery_queue_entries(queue_name, status, enqueued_at, id); - -CREATE INDEX IF NOT EXISTS idx_delivery_queue_failed - ON delivery_queue_entries(queue_name, status, failed_at, id); - -CREATE INDEX IF NOT EXISTS idx_delivery_queue_session - ON delivery_queue_entries(queue_name, status, session_key, enqueued_at, id) - WHERE session_key IS NOT NULL; - -CREATE INDEX IF NOT EXISTS idx_delivery_queue_target - ON delivery_queue_entries(queue_name, status, channel, target, enqueued_at, id) - WHERE channel IS NOT NULL AND target IS NOT NULL; - -CREATE TABLE IF NOT EXISTS task_runs ( - task_id TEXT NOT NULL PRIMARY KEY, - runtime TEXT NOT NULL, - task_kind TEXT, - source_id TEXT, - requester_session_key TEXT, - owner_key TEXT NOT NULL, - scope_kind TEXT NOT NULL, - child_session_key TEXT, - parent_flow_id TEXT, - parent_task_id TEXT, - agent_id TEXT, - requester_agent_id TEXT, - run_id TEXT, - label TEXT, - task TEXT NOT NULL, - status TEXT NOT NULL, - delivery_status TEXT NOT NULL, - notify_policy TEXT NOT NULL, - created_at INTEGER NOT NULL, - started_at INTEGER, - ended_at INTEGER, - last_event_at INTEGER, - cleanup_after INTEGER, - tool_use_count INTEGER, - last_tool_name TEXT, - error TEXT, - progress_summary TEXT, - terminal_summary TEXT, - terminal_outcome TEXT, - detail_json TEXT -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_task_runs_run_id ON task_runs(run_id); -CREATE INDEX IF NOT EXISTS idx_task_runs_status ON task_runs(status); -CREATE INDEX IF NOT EXISTS idx_task_runs_runtime_status ON task_runs(runtime, status); -CREATE INDEX IF NOT EXISTS idx_task_runs_cleanup_after ON task_runs(cleanup_after); -CREATE INDEX IF NOT EXISTS idx_task_runs_last_event_at ON task_runs(last_event_at); -CREATE INDEX IF NOT EXISTS idx_task_runs_owner_key ON task_runs(owner_key); -CREATE INDEX IF NOT EXISTS idx_task_runs_parent_flow_id ON task_runs(parent_flow_id); -CREATE INDEX IF NOT EXISTS idx_task_runs_child_session_key ON task_runs(child_session_key); -CREATE INDEX IF NOT EXISTS idx_task_runs_runtime_source_ended - ON task_runs(runtime, source_id, ended_at, created_at, task_id); -CREATE INDEX IF NOT EXISTS idx_task_runs_runtime_ended - ON task_runs(runtime, ended_at, created_at, task_id); - -CREATE TABLE IF NOT EXISTS subagent_runs ( - run_id TEXT NOT NULL PRIMARY KEY, - child_session_key TEXT NOT NULL, - controller_session_key TEXT, - requester_session_key TEXT NOT NULL, - requester_display_key TEXT NOT NULL, - requester_origin_json TEXT, - task TEXT NOT NULL, - task_name TEXT, - cleanup TEXT NOT NULL, - label TEXT, - model TEXT, - agent_dir TEXT, - workspace_dir TEXT, - run_timeout_seconds INTEGER, - spawn_mode TEXT, - created_at INTEGER NOT NULL, - started_at INTEGER, - session_started_at INTEGER, - accumulated_runtime_ms INTEGER, - ended_at INTEGER, - outcome_json TEXT, - archive_at_ms INTEGER, - cleanup_completed_at INTEGER, - cleanup_handled INTEGER, - suppress_announce_reason TEXT, - expects_completion_message INTEGER, - announce_retry_count INTEGER, - last_announce_retry_at INTEGER, - last_announce_delivery_error TEXT, - ended_reason TEXT, - pause_reason TEXT, - wake_on_descendant_settle INTEGER, - requester_settle_wake_status TEXT, - requester_settle_wake_attempt_count INTEGER, - requester_settle_wake_replay_count INTEGER, - requester_settle_wake_next_attempt_at INTEGER, - requester_settle_wake_batch_run_ids_json TEXT, - requester_settle_wake_last_error TEXT, - requester_settle_wake_retire_after INTEGER, - frozen_result_text TEXT, - frozen_result_captured_at INTEGER, - fallback_frozen_result_text TEXT, - fallback_frozen_result_captured_at INTEGER, - ended_hook_emitted_at INTEGER, - pending_final_delivery INTEGER, - pending_final_delivery_created_at INTEGER, - pending_final_delivery_last_attempt_at INTEGER, - pending_final_delivery_attempt_count INTEGER, - pending_final_delivery_last_error TEXT, - pending_final_delivery_payload_json TEXT, - completion_announced_at INTEGER, - swarm_group_id TEXT, - swarm_collector INTEGER, - swarm_output_schema_json TEXT, - swarm_completion_status TEXT, - swarm_structured_json TEXT, - swarm_schema_error TEXT, - swarm_usage_json TEXT, - payload_json TEXT NOT NULL DEFAULT '{}' -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_subagent_runs_child_session_key - ON subagent_runs(child_session_key, created_at DESC, run_id); -CREATE INDEX IF NOT EXISTS idx_subagent_runs_requester_session_key - ON subagent_runs(requester_session_key, created_at DESC, run_id); -CREATE INDEX IF NOT EXISTS idx_subagent_runs_controller_session_key - ON subagent_runs(controller_session_key, created_at DESC, run_id); -CREATE INDEX IF NOT EXISTS idx_subagent_runs_archive_at - ON subagent_runs(archive_at_ms, cleanup_handled, run_id); -CREATE INDEX IF NOT EXISTS idx_subagent_runs_ended_cleanup - ON subagent_runs(ended_at, cleanup_handled, run_id); - -CREATE TABLE IF NOT EXISTS current_conversation_bindings ( - binding_key TEXT NOT NULL PRIMARY KEY, - binding_id TEXT NOT NULL, - target_agent_id TEXT NOT NULL, - target_session_id TEXT, - target_session_key TEXT NOT NULL, - channel TEXT NOT NULL, - account_id TEXT NOT NULL, - conversation_kind TEXT NOT NULL, - parent_conversation_id TEXT, - conversation_id TEXT NOT NULL, - target_kind TEXT NOT NULL, - status TEXT NOT NULL, - bound_at INTEGER NOT NULL, - expires_at INTEGER, - metadata_json TEXT, - record_json TEXT NOT NULL, - updated_at INTEGER NOT NULL -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_current_conversation_bindings_target - ON current_conversation_bindings(target_agent_id, target_session_key, updated_at DESC, binding_key); -CREATE INDEX IF NOT EXISTS idx_current_conversation_bindings_conversation - ON current_conversation_bindings(channel, account_id, conversation_kind, conversation_id); -CREATE INDEX IF NOT EXISTS idx_current_conversation_bindings_expires - ON current_conversation_bindings(expires_at, binding_key); - -CREATE TABLE IF NOT EXISTS plugin_binding_approvals ( - plugin_root TEXT NOT NULL, - channel TEXT NOT NULL, - account_id TEXT NOT NULL, - plugin_id TEXT NOT NULL, - plugin_name TEXT, - approved_at INTEGER NOT NULL, - PRIMARY KEY (plugin_root, channel, account_id) -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_plugin_binding_approvals_plugin - ON plugin_binding_approvals(plugin_id, approved_at DESC); - -CREATE TABLE IF NOT EXISTS tui_last_sessions ( - scope_key TEXT NOT NULL PRIMARY KEY, - session_key TEXT NOT NULL, - updated_at INTEGER NOT NULL -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_tui_last_sessions_session_key - ON tui_last_sessions(session_key, updated_at DESC, scope_key); - -CREATE TABLE IF NOT EXISTS task_delivery_state ( - task_id TEXT NOT NULL PRIMARY KEY, - requester_origin_json TEXT, - last_notified_event_at INTEGER, - FOREIGN KEY (task_id) REFERENCES task_runs(task_id) ON DELETE CASCADE -) STRICT; - -CREATE TABLE IF NOT EXISTS flow_runs ( - flow_id TEXT NOT NULL PRIMARY KEY, - shape TEXT, - sync_mode TEXT NOT NULL DEFAULT 'managed', - owner_key TEXT NOT NULL, - requester_origin_json TEXT, - controller_id TEXT, - revision INTEGER NOT NULL DEFAULT 0, - status TEXT NOT NULL, - notify_policy TEXT NOT NULL, - goal TEXT NOT NULL, - current_step TEXT, - blocked_task_id TEXT, - blocked_summary TEXT, - state_json TEXT, - wait_json TEXT, - cancel_requested_at INTEGER, - created_at INTEGER NOT NULL, - updated_at INTEGER NOT NULL, - ended_at INTEGER -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_flow_runs_status ON flow_runs(status); -CREATE INDEX IF NOT EXISTS idx_flow_runs_owner_key ON flow_runs(owner_key); -CREATE INDEX IF NOT EXISTS idx_flow_runs_updated_at ON flow_runs(updated_at); - --- Durable meeting-capture sessions are gateway-global rather than agent-session --- transcripts. JSON/JSONL files are doctor import inputs or explicit CLI exports. -CREATE TABLE IF NOT EXISTS meeting_transcript_sessions ( - session_id TEXT NOT NULL, - started_at TEXT NOT NULL, - selector TEXT NOT NULL UNIQUE, - export_key TEXT NOT NULL, - session_slug TEXT NOT NULL, - provider_id TEXT NOT NULL, - title TEXT, - source_json TEXT NOT NULL, - stopped_at TEXT, - metadata_json TEXT, - export_manifest_json TEXT NOT NULL DEFAULT '{}', - export_pending_json TEXT NOT NULL DEFAULT '[]', - next_utterance_seq INTEGER NOT NULL DEFAULT 0 CHECK (next_utterance_seq >= 0), - created_at_ms INTEGER NOT NULL CHECK (created_at_ms >= 0), - updated_at_ms INTEGER NOT NULL CHECK (updated_at_ms >= 0), - PRIMARY KEY (session_id, started_at) -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_meeting_transcript_sessions_started - ON meeting_transcript_sessions(started_at DESC, session_id); - -CREATE INDEX IF NOT EXISTS idx_meeting_transcript_sessions_id - ON meeting_transcript_sessions(session_id, started_at DESC); - -CREATE INDEX IF NOT EXISTS idx_meeting_transcript_sessions_slug - ON meeting_transcript_sessions(session_slug, started_at DESC); - -CREATE INDEX IF NOT EXISTS idx_meeting_transcript_sessions_export_key - ON meeting_transcript_sessions(export_key); - -CREATE TABLE IF NOT EXISTS meeting_transcript_utterances ( - session_id TEXT NOT NULL, - session_started_at TEXT NOT NULL, - sequence INTEGER NOT NULL CHECK (sequence >= 0), - utterance_id TEXT, - started_at TEXT, - ended_at TEXT, - speaker_id TEXT, - speaker_label TEXT, - text TEXT NOT NULL, - final INTEGER CHECK (final IN (0, 1)), - metadata_json TEXT, - PRIMARY KEY (session_id, session_started_at, sequence), - FOREIGN KEY (session_id, session_started_at) - REFERENCES meeting_transcript_sessions(session_id, started_at) - ON DELETE CASCADE -) STRICT; - -CREATE TABLE IF NOT EXISTS meeting_transcript_summaries ( - session_id TEXT NOT NULL, - session_started_at TEXT NOT NULL, - generated_at TEXT, - summary_json TEXT, - markdown TEXT, - utterance_count INTEGER NOT NULL CHECK (utterance_count >= 0), - PRIMARY KEY (session_id, session_started_at), - FOREIGN KEY (session_id, session_started_at) - REFERENCES meeting_transcript_sessions(session_id, started_at) - ON DELETE CASCADE, - CHECK (summary_json IS NOT NULL OR markdown IS NOT NULL) -) STRICT; - -CREATE TABLE IF NOT EXISTS migration_runs ( - id TEXT NOT NULL PRIMARY KEY, - started_at INTEGER NOT NULL, - finished_at INTEGER, - status TEXT NOT NULL, - report_json TEXT NOT NULL -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_migration_runs_started - ON migration_runs(started_at DESC, id); - -CREATE TABLE IF NOT EXISTS migration_sources ( - source_key TEXT NOT NULL PRIMARY KEY, - migration_kind TEXT NOT NULL, - source_path TEXT NOT NULL, - target_table TEXT NOT NULL, - source_sha256 TEXT, - source_size_bytes INTEGER, - source_record_count INTEGER, - last_run_id TEXT NOT NULL, - status TEXT NOT NULL, - imported_at INTEGER NOT NULL, - removed_source INTEGER NOT NULL DEFAULT 0, - report_json TEXT NOT NULL, - FOREIGN KEY (last_run_id) REFERENCES migration_runs(id) ON DELETE CASCADE -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_migration_sources_path - ON migration_sources(source_path, migration_kind, target_table); - -CREATE INDEX IF NOT EXISTS idx_migration_sources_run - ON migration_sources(last_run_id, source_path); - -CREATE TABLE IF NOT EXISTS backup_runs ( - id TEXT NOT NULL PRIMARY KEY, - created_at INTEGER NOT NULL, - archive_path TEXT NOT NULL, - status TEXT NOT NULL, - manifest_json TEXT NOT NULL -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_backup_runs_created - ON backup_runs(created_at DESC, id); - -CREATE TABLE IF NOT EXISTS worktrees ( - id TEXT NOT NULL PRIMARY KEY, - repo_fingerprint TEXT NOT NULL, - repo_root TEXT NOT NULL, - path TEXT NOT NULL, - branch TEXT NOT NULL, - base_ref TEXT NOT NULL, - owner_kind TEXT NOT NULL CHECK (owner_kind IN ('manual', 'workboard', 'session')), - owner_id TEXT, - snapshot_ref TEXT, - provisioned_paths_json TEXT, - created_at INTEGER NOT NULL, - last_active_at INTEGER NOT NULL, - removed_at INTEGER -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_worktrees_repo_fingerprint - ON worktrees(repo_fingerprint); - -CREATE INDEX IF NOT EXISTS idx_worktrees_removed_at - ON worktrees(removed_at); - -CREATE TABLE IF NOT EXISTS worktree_provisioned_file_chunks ( - worktree_id TEXT NOT NULL, - path TEXT NOT NULL, - chunk_index INTEGER NOT NULL CHECK (chunk_index >= 0), - data BLOB NOT NULL, - PRIMARY KEY (worktree_id, path, chunk_index) -) STRICT; - --- Gateway-owned custom session group catalog (names + display order). --- Membership stays on each session entry's category field; this table only --- owns which groups exist and how operator UIs order them. -CREATE TABLE IF NOT EXISTS session_groups ( - name TEXT NOT NULL PRIMARY KEY, - position INTEGER NOT NULL, - created_at INTEGER NOT NULL -) STRICT; - --- Gateway-owned sidebar section layout. IDs are ungrouped, groups, work, or --- category:; pinned sessions are ordered separately and never stored. -CREATE TABLE IF NOT EXISTS sidebar_sections ( - section_id TEXT NOT NULL PRIMARY KEY, - position INTEGER NOT NULL -) STRICT; - --- Gateway-owned durable cloud worker lifecycle. Provider-specific execution --- stays in plugins; this table records only core reconciliation facts. -CREATE TABLE IF NOT EXISTS worker_environments ( - environment_id TEXT NOT NULL PRIMARY KEY, - provider_id TEXT NOT NULL, - profile_id TEXT NOT NULL, - profile_snapshot_json TEXT NOT NULL, - provision_operation_id TEXT NOT NULL UNIQUE, - lease_id TEXT, - ssh_host TEXT, - ssh_port INTEGER CHECK (ssh_port IS NULL OR (ssh_port >= 1 AND ssh_port <= 65535)), - ssh_user TEXT, - ssh_host_key TEXT, - ssh_key_ref_json TEXT, - state TEXT NOT NULL CHECK ( - state IN ( - 'requested', - 'provisioning', - 'bootstrapping', - 'ready', - 'attached', - 'idle', - 'draining', - 'destroying', - 'destroyed', - 'failed', - 'orphaned' - ) - ), - bootstrap_bundle_hash TEXT, - bootstrap_openclaw_version TEXT, - bootstrap_protocol_features_json TEXT, - owner_epoch INTEGER NOT NULL DEFAULT 0 CHECK (owner_epoch >= 0), - teardown_terminal_state TEXT CHECK (teardown_terminal_state IN ('destroyed', 'failed')), - attached_session_ids_json TEXT NOT NULL DEFAULT '[]', - created_at_ms INTEGER NOT NULL, - updated_at_ms INTEGER NOT NULL, - state_changed_at_ms INTEGER NOT NULL, - idle_since_at_ms INTEGER, - destroy_requested_at_ms INTEGER, - last_error TEXT -) STRICT; - -CREATE UNIQUE INDEX IF NOT EXISTS idx_worker_environments_provider_lease - ON worker_environments(provider_id, lease_id) - WHERE lease_id IS NOT NULL; - --- Session placement lives in the shared state database so local admission, --- worker admission, and environment attachment use one durable authority. -CREATE TABLE IF NOT EXISTS worker_session_placements ( - session_id TEXT NOT NULL PRIMARY KEY, - agent_id TEXT NOT NULL, - session_key TEXT NOT NULL, - state TEXT NOT NULL CHECK ( - state IN ( - 'local', - 'requested', - 'provisioning', - 'syncing', - 'starting', - 'active', - 'draining', - 'reconciling', - 'reclaimed', - 'failed' - ) - ), - environment_id TEXT, - transition_generation INTEGER NOT NULL DEFAULT 0 CHECK (transition_generation >= 0), - active_owner_epoch INTEGER CHECK (active_owner_epoch IS NULL OR active_owner_epoch >= 1), - workspace_base_manifest_ref TEXT, - remote_workspace_dir TEXT, - worker_bundle_hash TEXT, - last_transcript_ack_cursor INTEGER CHECK ( - last_transcript_ack_cursor IS NULL OR last_transcript_ack_cursor >= 0 - ), - last_live_event_ack_cursor INTEGER CHECK ( - last_live_event_ack_cursor IS NULL OR last_live_event_ack_cursor >= 0 - ), - recovery_error TEXT, - turn_claim_owner TEXT CHECK (turn_claim_owner IN ('local', 'worker')), - turn_claim_id TEXT, - turn_claim_run_id TEXT, - turn_claim_generation INTEGER CHECK ( - turn_claim_generation IS NULL OR turn_claim_generation >= 0 - ), - turn_claim_owner_epoch INTEGER CHECK ( - turn_claim_owner_epoch IS NULL OR turn_claim_owner_epoch >= 1 - ), - created_at_ms INTEGER NOT NULL, - updated_at_ms INTEGER NOT NULL, - state_changed_at_ms INTEGER NOT NULL, - CHECK ( - (state IN ('local', 'requested') - AND environment_id IS NULL AND active_owner_epoch IS NULL - AND workspace_base_manifest_ref IS NULL AND remote_workspace_dir IS NULL - AND worker_bundle_hash IS NULL - AND last_transcript_ack_cursor IS NULL AND last_live_event_ack_cursor IS NULL - AND recovery_error IS NULL) - OR - (state IS 'provisioning' - AND active_owner_epoch IS NULL - AND workspace_base_manifest_ref IS NULL AND remote_workspace_dir IS NULL - AND worker_bundle_hash IS NULL - AND last_transcript_ack_cursor IS NULL AND last_live_event_ack_cursor IS NULL - AND recovery_error IS NULL) - OR - (state IS 'syncing' - AND environment_id IS NOT NULL AND active_owner_epoch IS NULL - AND workspace_base_manifest_ref IS NULL AND remote_workspace_dir IS NULL - AND worker_bundle_hash IS NOT NULL - AND last_transcript_ack_cursor IS NULL AND last_live_event_ack_cursor IS NULL - AND recovery_error IS NULL) - OR - (state IS 'starting' - AND environment_id IS NOT NULL AND active_owner_epoch IS NULL - AND workspace_base_manifest_ref IS NOT NULL AND remote_workspace_dir IS NOT NULL - AND worker_bundle_hash IS NOT NULL - AND last_transcript_ack_cursor IS NULL AND last_live_event_ack_cursor IS NULL - AND recovery_error IS NULL) - OR - (state IN ('active', 'draining', 'reconciling') - AND environment_id IS NOT NULL AND active_owner_epoch IS NOT NULL - AND workspace_base_manifest_ref IS NOT NULL AND remote_workspace_dir IS NOT NULL - AND worker_bundle_hash IS NOT NULL AND recovery_error IS NULL) - OR - (state IS 'reclaimed' - AND environment_id IS NOT NULL AND active_owner_epoch IS NOT NULL - AND workspace_base_manifest_ref IS NOT NULL AND remote_workspace_dir IS NOT NULL - AND worker_bundle_hash IS NOT NULL AND recovery_error IS NULL - AND turn_claim_owner IS NULL AND turn_claim_id IS NULL AND turn_claim_run_id IS NULL - AND turn_claim_generation IS NULL AND turn_claim_owner_epoch IS NULL) - OR - (state IS 'failed' AND recovery_error IS NOT NULL) - ), - CHECK ( - (turn_claim_owner IS NULL AND turn_claim_id IS NULL AND turn_claim_run_id IS NULL - AND turn_claim_generation IS NULL AND turn_claim_owner_epoch IS NULL) - OR - (turn_claim_owner IS 'local' AND turn_claim_id IS NOT NULL - AND turn_claim_run_id IS NOT NULL AND turn_claim_generation IS NOT NULL - AND turn_claim_owner_epoch IS NULL) - OR - (turn_claim_owner IS 'worker' AND turn_claim_id IS NOT NULL - AND turn_claim_run_id IS NOT NULL AND turn_claim_generation IS NOT NULL - AND turn_claim_owner_epoch IS NOT NULL) - ), - CHECK ( - turn_claim_owner IS NULL - OR - (turn_claim_owner IS 'local' AND state IN ('local', 'requested', 'failed')) - OR - (turn_claim_owner IS 'worker' AND state IN ('active', 'draining') - AND turn_claim_owner_epoch IS active_owner_epoch) - ) -) STRICT; - -CREATE INDEX IF NOT EXISTS idx_worker_session_placements_session_key - ON worker_session_placements(agent_id, session_key); - -CREATE INDEX IF NOT EXISTS idx_worker_session_placements_reconcile - ON worker_session_placements(updated_at_ms, session_id); - --- A reconciliation journal is written before managed-worktree mutation. The --- bounded Git base snapshot repairs any subset left by an interrupted apply. -CREATE TABLE IF NOT EXISTS worker_workspace_reconciliations ( - session_id TEXT NOT NULL PRIMARY KEY, - environment_id TEXT NOT NULL, - owner_epoch INTEGER NOT NULL CHECK (owner_epoch >= 1), - placement_generation INTEGER NOT NULL CHECK (placement_generation >= 0), - base_manifest_ref TEXT NOT NULL, - current_manifest_ref TEXT NOT NULL, - plan_json TEXT NOT NULL, - base_pack BLOB NOT NULL CHECK (length(base_pack) <= 268435456), - created_at_ms INTEGER NOT NULL, - FOREIGN KEY (session_id) REFERENCES worker_session_placements(session_id) ON DELETE CASCADE -) STRICT; - --- A completed remote turn is fenced from stale-claim teardown until its --- workspace result is durably reconciled into the managed worktree. -CREATE TABLE IF NOT EXISTS worker_workspace_pending_results ( - session_id TEXT NOT NULL PRIMARY KEY, - environment_id TEXT NOT NULL, - owner_epoch INTEGER NOT NULL CHECK (owner_epoch >= 1), - placement_generation INTEGER NOT NULL CHECK (placement_generation >= 0), - claim_id TEXT NOT NULL, - run_id TEXT NOT NULL, - gateway_instance_id TEXT NOT NULL, - recovery_requested_at_ms INTEGER, - workspace_accepted_at_ms INTEGER, - staged_result_ref TEXT, - created_at_ms INTEGER NOT NULL, - FOREIGN KEY (session_id) REFERENCES worker_session_placements(session_id) ON DELETE CASCADE -) STRICT; - --- One active, opaque admission credential per worker environment. Plaintext --- may be retried until delivery acknowledgement but never enters durable state. -CREATE TABLE IF NOT EXISTS worker_environment_credentials ( - environment_id TEXT NOT NULL PRIMARY KEY, - credential_hash TEXT NOT NULL UNIQUE, - bundle_hash TEXT NOT NULL, - session_id TEXT, - rpc_set_version INTEGER NOT NULL CHECK (rpc_set_version >= 1), - owner_epoch INTEGER NOT NULL CHECK (owner_epoch >= 0), - expires_at_ms INTEGER NOT NULL CHECK (expires_at_ms >= 0), - delivered_at_ms INTEGER CHECK (delivered_at_ms >= 0), - FOREIGN KEY (environment_id) REFERENCES worker_environments(environment_id) ON DELETE CASCADE -) STRICT; - --- One durable sequence cursor per attached session owner epoch. The environment --- binding prevents independent workers with coincident epochs from sharing replay state. -CREATE TABLE IF NOT EXISTS worker_transcript_commit_heads ( - session_id TEXT NOT NULL, - run_epoch INTEGER NOT NULL CHECK (run_epoch >= 0), - environment_id TEXT NOT NULL, - next_seq INTEGER NOT NULL CHECK (next_seq >= 1), - updated_at_ms INTEGER NOT NULL CHECK (updated_at_ms >= 0), - PRIMARY KEY (session_id, run_epoch) -) STRICT; - --- Pending rows preserve a claimed request across gateway restarts. Terminal rows --- cache the exact result returned for deterministic at-least-once replay. -CREATE TABLE IF NOT EXISTS worker_transcript_commits ( - session_id TEXT NOT NULL, - run_epoch INTEGER NOT NULL CHECK (run_epoch >= 0), - seq INTEGER NOT NULL CHECK (seq >= 1), - request_hash TEXT NOT NULL, - state TEXT NOT NULL CHECK (state IN ('pending', 'terminal')), - result_json TEXT, - created_at_ms INTEGER NOT NULL CHECK (created_at_ms >= 0), - updated_at_ms INTEGER NOT NULL CHECK (updated_at_ms >= 0), - PRIMARY KEY (session_id, run_epoch, seq), - FOREIGN KEY (session_id, run_epoch) - REFERENCES worker_transcript_commit_heads(session_id, run_epoch) - ON DELETE CASCADE, - CHECK ( - (state = 'pending' AND result_json IS NULL) OR - (state = 'terminal' AND result_json IS NOT NULL) - ) -) STRICT; - --- Pending rows preserve a claimed inference turn across gateway restarts. --- Terminal rows cache the exact outcome returned for deterministic replay. -CREATE TABLE IF NOT EXISTS worker_inference_turns ( - session_id TEXT NOT NULL, - run_epoch INTEGER NOT NULL CHECK (run_epoch >= 0), - run_id TEXT NOT NULL, - turn_id TEXT NOT NULL, - environment_id TEXT NOT NULL, - request_hash TEXT NOT NULL, - state TEXT NOT NULL CHECK (state IN ('pending', 'terminal')), - terminal_json TEXT, - created_at_ms INTEGER NOT NULL CHECK (created_at_ms >= 0), - updated_at_ms INTEGER NOT NULL CHECK (updated_at_ms >= 0), - PRIMARY KEY (session_id, run_epoch, run_id, turn_id), - FOREIGN KEY (environment_id) REFERENCES worker_environments(environment_id) ON DELETE CASCADE, - CHECK ( - (state = 'pending' AND terminal_json IS NULL) OR - (state = 'terminal' AND terminal_json IS NOT NULL) - ) -) STRICT; - -CREATE UNIQUE INDEX IF NOT EXISTS idx_worker_inference_turns_pending_run - ON worker_inference_turns(session_id, run_epoch, run_id) - WHERE state = 'pending'; - -CREATE TABLE IF NOT EXISTS fleet_cells ( - tenant_id TEXT NOT NULL PRIMARY KEY, - created_at_ms INTEGER NOT NULL, - image TEXT NOT NULL, - runtime TEXT NOT NULL, - host_port INTEGER NOT NULL, - container_name TEXT NOT NULL, - data_dir TEXT NOT NULL -) STRICT; - -CREATE TABLE IF NOT EXISTS claw_installs ( - agent_id TEXT NOT NULL PRIMARY KEY, - schema_version TEXT NOT NULL, - source_kind TEXT NOT NULL, - claw_name TEXT NOT NULL, - claw_version TEXT NOT NULL, - package_root TEXT NOT NULL, - manifest_path TEXT NOT NULL, - integrity_kind TEXT NOT NULL, - integrity TEXT NOT NULL, - source_byte_length INTEGER NOT NULL, - manifest_schema_version INTEGER NOT NULL, - plan_integrity TEXT NOT NULL, - workspace TEXT NOT NULL UNIQUE, - agent_config_digest TEXT NOT NULL, - agent_owned_paths_json TEXT NOT NULL, - status TEXT NOT NULL CHECK ( - status IN ('pending', 'workspace_ready', 'config_committed', 'complete', 'partial') - ), - added_at_ms INTEGER NOT NULL, - updated_at_ms INTEGER NOT NULL -) STRICT; - -CREATE TABLE IF NOT EXISTS claw_workspace_files ( - agent_id TEXT NOT NULL, - target_path TEXT NOT NULL, - schema_version TEXT NOT NULL, - workspace TEXT NOT NULL, - source_path TEXT NOT NULL, - content_digest TEXT NOT NULL, - status TEXT NOT NULL, - created_at_ms INTEGER NOT NULL, - updated_at_ms INTEGER NOT NULL, - PRIMARY KEY (agent_id, target_path) -) STRICT; - -CREATE TABLE IF NOT EXISTS claw_package_refs ( - agent_id TEXT NOT NULL, - package_kind TEXT NOT NULL, - package_source TEXT NOT NULL, - package_ref TEXT NOT NULL, - package_version TEXT NOT NULL, - package_integrity TEXT NOT NULL, - schema_version TEXT NOT NULL, - claw_name TEXT NOT NULL, - package_status TEXT NOT NULL, - relationship TEXT NOT NULL CHECK (relationship IN ('managed', 'referenced')), - origin TEXT NOT NULL CHECK (origin IN ('claw-introduced', 'pre-existing')), - independent_owner INTEGER NOT NULL CHECK (independent_owner IN (0, 1)), - installed_at_ms INTEGER NOT NULL, - updated_at_ms INTEGER NOT NULL, - PRIMARY KEY (agent_id, package_kind, package_source, package_ref, package_version) -) STRICT; - -CREATE TABLE IF NOT EXISTS claw_cron_refs ( - agent_id TEXT NOT NULL, - manifest_id TEXT NOT NULL, - schema_version TEXT NOT NULL, - declaration_key TEXT NOT NULL UNIQUE, - scheduler_job_id TEXT UNIQUE, - status TEXT NOT NULL, - job_json TEXT NOT NULL, - error TEXT, - created_at_ms INTEGER NOT NULL, - updated_at_ms INTEGER NOT NULL, - PRIMARY KEY (agent_id, manifest_id) -) STRICT; - -CREATE TABLE IF NOT EXISTS claw_mcp_server_refs ( - agent_id TEXT NOT NULL, - name TEXT NOT NULL, - schema_version TEXT NOT NULL, - config_digest TEXT NOT NULL, - relationship TEXT NOT NULL CHECK (relationship IN ('managed', 'referenced')), - origin TEXT NOT NULL CHECK (origin IN ('claw-introduced', 'pre-existing')), - independent_owner INTEGER NOT NULL DEFAULT 0 CHECK (independent_owner IN (0, 1)), - status TEXT NOT NULL, - error TEXT, - created_at_ms INTEGER NOT NULL, - updated_at_ms INTEGER NOT NULL, - PRIMARY KEY (agent_id, name) -) STRICT; - -CREATE TABLE IF NOT EXISTS outbound_media_provenance ( - realpath TEXT NOT NULL PRIMARY KEY, - kind TEXT NOT NULL, - version INTEGER NOT NULL, - sha256 TEXT NOT NULL, - size_bytes INTEGER NOT NULL, - created_at_ms INTEGER NOT NULL -) STRICT; - -CREATE TABLE IF NOT EXISTS model_catalog_remote ( - id INTEGER PRIMARY KEY CHECK (id = 1), - bundle_json TEXT NOT NULL, - generated_at INTEGER NOT NULL, - min_version TEXT, - source_url TEXT NOT NULL, - etag TEXT, - last_modified TEXT, - checked_at INTEGER NOT NULL -) STRICT;\n`; diff --git a/src/state/openclaw-state-schema.ts b/src/state/openclaw-state-schema.ts new file mode 100644 index 000000000000..b805edfccdc3 --- /dev/null +++ b/src/state/openclaw-state-schema.ts @@ -0,0 +1,7 @@ +import { fileURLToPath } from "node:url"; + +// Use the native builtin so unrelated node:fs mocks cannot replace this source input. +// Production builds replace this module so packaged database opens need no asset file. +export const OPENCLAW_STATE_SCHEMA_SQL = process + .getBuiltinModule("node:fs") + .readFileSync(fileURLToPath(new URL("./openclaw-state-schema.sql", import.meta.url)), "utf8"); diff --git a/test/scripts/build-all.test.ts b/test/scripts/build-all.test.ts index bf207ef71835..61d70ad06e44 100644 --- a/test/scripts/build-all.test.ts +++ b/test/scripts/build-all.test.ts @@ -387,6 +387,14 @@ describe("resolveBuildAllSteps", () => { ); } expect(unified.cache?.env).toContain("OPENCLAW_BUILD_PRIVATE_QA"); + expect(unified.cache?.inputs).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + path: "src", + extensions: expect.arrayContaining([".sql"]), + }), + ]), + ); expect(resolveBuildAllStepOnCacheHit(getBuildAllStep("copy-export-html-templates"))).toBeNull(); }); diff --git a/tsdown.config.ts b/tsdown.config.ts index 908c5d09aea1..1ca9275f7644 100644 --- a/tsdown.config.ts +++ b/tsdown.config.ts @@ -46,6 +46,43 @@ const env = { const OUTPUT_SOURCE_MAPS = process.env.OUTPUT_SOURCE_MAPS === "1"; const RUN_NODE_SKIP_DTS_BUILD = process.env.OPENCLAW_RUN_NODE_SKIP_DTS_BUILD === "1"; const TSDOWN_DECLARATIONS = !RUN_NODE_SKIP_DTS_BUILD; +export const STATE_SCHEMA_INLINE_PLUGIN_NAME = "openclaw:inline-state-schemas"; + +const STATE_SCHEMA_MODULES = [ + { + modulePath: "src/state/openclaw-state-schema.ts", + schemaPath: "src/state/openclaw-state-schema.sql", + exportName: "OPENCLAW_STATE_SCHEMA_SQL", + }, + { + modulePath: "src/state/openclaw-agent-schema.ts", + schemaPath: "src/state/openclaw-agent-schema.sql", + exportName: "OPENCLAW_AGENT_SCHEMA_SQL", + }, +] as const; + +/** Inline canonical schema bytes so packaged database opens need no SQL asset. */ +export function createStateSchemaInlinePlugin(rootDir: string = process.cwd()) { + const schemasByModulePath = new Map( + STATE_SCHEMA_MODULES.map((schema) => [path.resolve(rootDir, schema.modulePath), schema]), + ); + + return { + name: STATE_SCHEMA_INLINE_PLUGIN_NAME, + load(this: { addWatchFile(id: string): void }, id: string) { + const schema = schemasByModulePath.get(path.resolve(id)); + if (!schema) { + return null; + } + const schemaPath = path.resolve(rootDir, schema.schemaPath); + this.addWatchFile(schemaPath); + return { + code: `export const ${schema.exportName} = ${JSON.stringify(fs.readFileSync(schemaPath, "utf8"))};\n`, + moduleType: "js" as const, + }; + }, + }; +} const SUPPRESSED_EVAL_WARNING_PATHS = [ "@protobufjs/inquire/index.js", @@ -680,6 +717,7 @@ const configs = [ // and bundled hooks in one graph so runtime singletons are emitted once. entry: unifiedDistEntries, deps: unifiedDeps, + plugins: [createStateSchemaInlinePlugin()], }, false, ),