From 637702c0fef72ac3ebaab0728763771418107154 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 3 Jul 2026 10:24:15 +0000 Subject: [PATCH 1/2] Harden secrets, audit logging, agent-run recovery, CI, and token budgets Secrets: - Encrypt mcpServer.env/oauthState at rest (AES-256-GCM, same envelope as modelInstallation.apiKey/knowledgeBaseConfig.obsidianApiKey) via new encryptJsonNullable/decryptJsonNullable helpers in packages/db/src/crypto.ts. - Add toClientSafeMcpServer/toClientSafeKnowledgeBaseConfig mappers and wire them (plus the existing toClientSafeInstallation) into every router procedure that previously returned raw secrets to the browser. Audit log: - Centralize input/output redaction (apiKey/token/accessToken/refreshToken/ authorization/password/secret/cookie, case-insensitive, nested) and a serialized-size cap in apps/server/src/audit.ts's logAudit, ahead of every audit_log write. inputHash is unaffected (computed from the raw value before redaction). Agent run recovery: - Add workerId/heartbeatAt/leaseUntil/cancelRequestedAt to agent_run (both dialects). executeManagedTask claims a lease and renews it on a heartbeat interval; cancelAgentRun always sets cancelRequestedAt/status in the DB regardless of in-memory controller reachability. scheduler.ts's new checkStaleAgentRuns recovers runs whose lease expired (or never had one) on every tick and once at startup. CI/tests: - Delete 5 dead /tests files that imported nonexistent modules; add a root "test": "bun test" script and a CI job that runs it after lint/typecheck; add hermetic fetch-mocked tests for local model detection. Token budgets: - Make the knowledge-base prompt injection char caps env-configurable; add an aggregate output-byte cap to the builtin search/codebase/usages tool. Tests added for every behavior changed; typecheck/lint clean on all touched files (verified against the pre-existing baseline); both Postgres migrations verified against a live Postgres 16 instance, including that pre-existing legacy plaintext data survives the jsonb->text conversion. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_019tXH1XWxA1CsvoVr29pPHR --- .github/workflows/ci.yml | 12 + apps/server/src/agent-runtime.test.ts | 73 + apps/server/src/agent-runtime.ts | 72 +- apps/server/src/audit.test.ts | 90 + apps/server/src/audit.ts | 70 +- apps/server/src/knowledge-base.test.ts | 87 + apps/server/src/knowledge-base.ts | 29 +- apps/server/src/scheduler.test.ts | 125 + apps/server/src/scheduler.ts | 67 + apps/server/src/tools-builtin/search.test.ts | 70 + apps/server/src/tools-builtin/search.ts | 280 +- apps/server/src/trpc/router.test.ts | 94 +- apps/server/src/trpc/router.ts | 114 +- .../components/workspace-settings-panel.tsx | 45 +- apps/web/src/lib/trpc.ts | 31 +- package.json | 1 + .../db/drizzle/pg/0042_sad_emma_frost.sql | 2 + .../db/drizzle/pg/0043_cooing_starjammers.sql | 4 + .../db/drizzle/pg/meta/0042_snapshot.json | 4908 ++++++++++++++++ .../db/drizzle/pg/meta/0043_snapshot.json | 4932 +++++++++++++++++ packages/db/drizzle/pg/meta/_journal.json | 14 + .../drizzle/sqlite/0039_dazzling_gressill.sql | 4 + .../db/drizzle/sqlite/meta/0039_snapshot.json | 4792 ++++++++++++++++ packages/db/drizzle/sqlite/meta/_journal.json | 7 + packages/db/src/crypto.test.ts | 24 +- packages/db/src/crypto.ts | 16 + packages/db/src/repo/pg.repo.ts | 54 +- .../db/src/repo/secrets-encryption.test.ts | 145 + packages/db/src/repo/sqlite.repo.ts | 55 +- packages/db/src/repo/types.ts | 22 + packages/db/src/schema/pg/app.ts | 19 +- packages/db/src/schema/sqlite/app.ts | 19 +- packages/model-providers/src/detect.test.ts | 196 + tests/db_migration.test.ts | 18 - tests/kb_context_injector.test.ts | 19 - tests/skill_file_read.test.ts | 20 - tests/skill_http_fetch.test.ts | 20 - tests/skill_registry.test.ts | 20 - 38 files changed, 16218 insertions(+), 352 deletions(-) create mode 100644 apps/server/src/agent-runtime.test.ts create mode 100644 apps/server/src/audit.test.ts create mode 100644 apps/server/src/knowledge-base.test.ts create mode 100644 apps/server/src/scheduler.test.ts create mode 100644 apps/server/src/tools-builtin/search.test.ts create mode 100644 packages/db/drizzle/pg/0042_sad_emma_frost.sql create mode 100644 packages/db/drizzle/pg/0043_cooing_starjammers.sql create mode 100644 packages/db/drizzle/pg/meta/0042_snapshot.json create mode 100644 packages/db/drizzle/pg/meta/0043_snapshot.json create mode 100644 packages/db/drizzle/sqlite/0039_dazzling_gressill.sql create mode 100644 packages/db/drizzle/sqlite/meta/0039_snapshot.json create mode 100644 packages/db/src/repo/secrets-encryption.test.ts create mode 100644 packages/model-providers/src/detect.test.ts delete mode 100644 tests/db_migration.test.ts delete mode 100644 tests/kb_context_injector.test.ts delete mode 100644 tests/skill_file_read.test.ts delete mode 100644 tests/skill_http_fetch.test.ts delete mode 100644 tests/skill_registry.test.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index af93268..014f885 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -53,3 +53,15 @@ jobs: bun-version: 1.3.14 - run: bun install --frozen-lockfile - run: bun run build + + test: + name: Test + runs-on: ubuntu-latest + needs: [lint, typecheck] + steps: + - uses: actions/checkout@v7 + - uses: oven-sh/setup-bun@v2 + with: + bun-version: 1.3.14 + - run: bun install --frozen-lockfile + - run: bun run test diff --git a/apps/server/src/agent-runtime.test.ts b/apps/server/src/agent-runtime.test.ts new file mode 100644 index 0000000..62b78a9 --- /dev/null +++ b/apps/server/src/agent-runtime.test.ts @@ -0,0 +1,73 @@ +import { afterEach, beforeEach, describe, expect, it } from "bun:test"; +import type { DbRepository } from "@nyxel/db"; +import { getDb } from "@nyxel/db"; +import { createTestUser, installTestDb } from "@nyxel/db/test-utils"; +import { cancelAgentRun } from "./agent-runtime"; + +async function seedWorkspace(db: DbRepository, path: string) { + const user = createTestUser(path); + const workspace = await db.createWorkspace({ userId: user.id, name: "Test workspace" }); + return { user, workspace }; +} + +async function seedAgent(db: DbRepository, workspaceId: string) { + return db.createAgent({ + workspaceId, + name: "Worker", + modelId: "anthropic/claude-fake", + autonomyLevel: "autonomous", + }); +} + +let ctx: Awaited>; + +beforeEach(async () => { + ctx = await installTestDb(); +}); + +afterEach(async () => { + await ctx.cleanup(); +}); + +describe("cancelAgentRun", () => { + it("marks the run cancelled in the DB even with no in-memory AbortController for it", async () => { + const db = getDb(); + const { workspace } = await seedWorkspace(db, ctx.path); + const agent = await seedAgent(db, workspace.id); + const task = await db.createTask({ + workspaceId: workspace.id, + assignedAgentId: agent.id, + title: "Orphaned run's task", + instruction: "Do the thing.", + status: "running", + }); + // Simulates a run whose owning process died/restarted: this test never + // calls executeManagedTask, so there is no activeRunControllers entry + // for this run in this process — cancelAgentRun must still succeed. + const run = await db.createAgentRun({ + workspaceId: workspace.id, + taskId: task.id, + agentId: agent.id, + trigger: "task", + status: "running", + startedAt: new Date(), + workerId: "some-other-process", + }); + + const cancelled = await cancelAgentRun(run.id); + + expect(cancelled.status).toBe("cancelled"); + expect(cancelled.cancelRequestedAt).not.toBeNull(); + expect(cancelled.completedAt).not.toBeNull(); + + const persisted = await db.getAgentRun(run.id); + expect(persisted?.status).toBe("cancelled"); + + const cancelledTask = await db.getTask(task.id); + expect(cancelledTask?.status).toBe("cancelled"); + }); + + it("throws for an unknown run id", async () => { + await expect(cancelAgentRun("does-not-exist")).rejects.toThrow("Unknown agent run"); + }); +}); diff --git a/apps/server/src/agent-runtime.ts b/apps/server/src/agent-runtime.ts index bbe9f58..490aaf3 100644 --- a/apps/server/src/agent-runtime.ts +++ b/apps/server/src/agent-runtime.ts @@ -1,3 +1,4 @@ +import { randomUUID } from "node:crypto"; import type { AgentRecord, AgentRunRecord, TaskRecord } from "@nyxel/db"; import { getDb } from "@nyxel/db"; import { getModelCapabilities, streamChat } from "@nyxel/model-providers"; @@ -24,9 +25,24 @@ export interface ExecutionPlan { * aborted in-flight (cancelAgentRun still marks it cancelled in the DB). */ const activeRunControllers = new Map(); +/** Identifies this process as the owner of whatever runs it currently holds + * a lease on — written to agentRun.workerId, purely informational (nothing + * currently reads it back to route work), but gives a stale/orphaned run a + * breadcrumb of which process it was left running in. */ +const WORKER_ID = randomUUID(); + +/** How long a run's lease is valid without a renewed heartbeat before the + * stale-run sweep (see scheduler.ts's checkStaleAgentRuns) considers the + * owning process dead and recovers it. Must be comfortably longer than + * HEARTBEAT_INTERVAL_MS so a single missed tick doesn't cause a false + * positive. */ +const LEASE_DURATION_MS = 90_000; +const HEARTBEAT_INTERVAL_MS = 30_000; + /** Aborts the in-flight model call for a run (best-effort — a no-op on the * abort itself if the run isn't live in this process) and always marks the - * run/task cancelled in the DB so the UI reflects it immediately. */ + * run/task cancelled in the DB so the UI reflects it immediately, even if + * the run's owning process isn't this one (see AgentRunRecord.cancelRequestedAt). */ export async function cancelAgentRun(runId: string): Promise { activeRunControllers.get(runId)?.abort(); @@ -37,6 +53,7 @@ export async function cancelAgentRun(runId: string): Promise { const updated = await db.updateAgentRun(runId, { status: "cancelled", completedAt: new Date(), + cancelRequestedAt: new Date(), }); if (run.taskId) { const task = await db.getTask(run.taskId); @@ -336,6 +353,7 @@ export async function executeManagedTask(input: { const task = await db.getTask(input.taskId); if (!task) throw new Error(`Unknown task: ${input.taskId}`); + const startedAt = new Date(); const run = await db.createAgentRun({ workspaceId: task.workspaceId, taskId: task.id, @@ -345,7 +363,10 @@ export async function executeManagedTask(input: { trigger: input.trigger, modelId: effectiveModelId(input.agent, task), status: "running", - startedAt: new Date(), + startedAt, + workerId: WORKER_ID, + heartbeatAt: startedAt, + leaseUntil: new Date(startedAt.getTime() + LEASE_DURATION_MS), }); await emitNyxelEvent({ workspaceId: task.workspaceId, @@ -358,6 +379,30 @@ export async function executeManagedTask(input: { const controller = new AbortController(); activeRunControllers.set(run.id, controller); + // Renews the run's lease periodically so the stale-run sweep + // (scheduler.ts's checkStaleAgentRuns) doesn't mistake a genuinely + // in-progress run for one whose owning process died. Also the DB-visible + // fallback for cross-process cancellation: if this run were ever picked + // up by another process's cancelAgentRun call (cancelRequestedAt set + // without this process's activeRunControllers entry being reachable), + // the next heartbeat tick notices and aborts locally too. + const heartbeatTimer = setInterval(() => { + void (async () => { + const current = await db.getAgentRun(run.id).catch(() => null); + if (current?.cancelRequestedAt && !controller.signal.aborted) { + controller.abort(); + return; + } + await db + .updateAgentRun(run.id, { + heartbeatAt: new Date(), + leaseUntil: new Date(Date.now() + LEASE_DURATION_MS), + }) + .catch(() => {}); + })(); + }, HEARTBEAT_INTERVAL_MS); + if (typeof heartbeatTimer.unref === "function") heartbeatTimer.unref(); + // Autonomy Budgets v1 (see ./autonomy-budget.ts) — the tool-call-boundary // runtime check inside buildToolsForAgent only fires between tool calls, // so a run that never calls a tool (or sits inside one very long model @@ -381,9 +426,7 @@ export async function executeManagedTask(input: { completedAt: new Date(), }) .catch(() => {}); - await db - .updateTask(task.id, { status: "blocked", errorMessage: reason }) - .catch(() => {}); + await db.updateTask(task.id, { status: "blocked", errorMessage: reason }).catch(() => {}); await db .createTaskEvent({ taskId: task.id, @@ -428,6 +471,7 @@ export async function executeManagedTask(input: { throw err; } finally { if (budgetTimeout) clearTimeout(budgetTimeout); + clearInterval(heartbeatTimer); activeRunControllers.delete(run.id); } } @@ -607,18 +651,18 @@ async function runManagedTask( // Detected from the tracker's own state rather than string-matching the // model's final text (unlike the two checks above) — more robust, since // it doesn't depend on the model actually repeating the tool result back. - const pausedOnBudget = - !pausedOnQuestion && !pausedOnApproval && budgetBlockedReason !== null; + const pausedOnBudget = !pausedOnQuestion && !pausedOnApproval && budgetBlockedReason !== null; const isPaused = pausedOnQuestion || pausedOnApproval || pausedOnBudget; // AgentRunStatus has no "blocked" state (a question-pause is still an // agent run that's technically waiting on the human) — only TaskStatus // distinguishes "blocked" (question or budget) from "waiting_approval" // (tool approval). - const taskStatus = pausedOnQuestion || pausedOnBudget - ? ("blocked" as const) - : pausedOnApproval - ? ("waiting_approval" as const) - : ("completed" as const); + const taskStatus = + pausedOnQuestion || pausedOnBudget + ? ("blocked" as const) + : pausedOnApproval + ? ("waiting_approval" as const) + : ("completed" as const); run = await db.updateAgentRun(run.id, { status: isPaused ? "waiting_approval" : "completed", @@ -631,9 +675,7 @@ async function runManagedTask( status: taskStatus, resultSummary: output, completedAt: isPaused ? null : new Date(), - ...(pausedOnBudget - ? { errorMessage: `Autonomy budget exceeded: ${budgetBlockedReason}` } - : {}), + ...(pausedOnBudget ? { errorMessage: `Autonomy budget exceeded: ${budgetBlockedReason}` } : {}), }); await db.createTaskEvent({ taskId: task.id, diff --git a/apps/server/src/audit.test.ts b/apps/server/src/audit.test.ts new file mode 100644 index 0000000..036e715 --- /dev/null +++ b/apps/server/src/audit.test.ts @@ -0,0 +1,90 @@ +import { describe, expect, test } from "bun:test"; +import { sanitizeForAudit } from "./audit"; + +describe("sanitizeForAudit", () => { + test("passes through undefined/null unchanged", () => { + expect(sanitizeForAudit(undefined)).toBeUndefined(); + expect(sanitizeForAudit(null)).toBeNull(); + }); + + test("redacts top-level secret-shaped keys, case-insensitively", () => { + const sanitized = sanitizeForAudit({ + apiKey: "sk-live-abc", + ApiKey: "sk-live-def", + API_KEY: "sk-live-ghi", + token: "tok-live", + accessToken: "at-live", + refreshToken: "rt-live", + Authorization: "Bearer xyz", + password: "hunter2", + secret: "shh", + cookie: "session=abc", + label: "keep me", + }) as Record; + + expect(sanitized.apiKey).toBe("[REDACTED]"); + expect(sanitized.ApiKey).toBe("[REDACTED]"); + expect(sanitized.API_KEY).toBe("[REDACTED]"); + expect(sanitized.token).toBe("[REDACTED]"); + expect(sanitized.accessToken).toBe("[REDACTED]"); + expect(sanitized.refreshToken).toBe("[REDACTED]"); + expect(sanitized.Authorization).toBe("[REDACTED]"); + expect(sanitized.password).toBe("[REDACTED]"); + expect(sanitized.secret).toBe("[REDACTED]"); + expect(sanitized.cookie).toBe("[REDACTED]"); + expect(sanitized.label).toBe("keep me"); + }); + + test("redacts secret-shaped keys nested arbitrarily deep", () => { + const sanitized = sanitizeForAudit({ + request: { + headers: { authorization: "Bearer live-token" }, + body: { + nested: [{ config: { apiKey: "sk-live-nested" } }, { safe: "ok" }], + }, + }, + }) as { + request: { + headers: { authorization: string }; + body: { nested: [{ config: { apiKey: string } }, { safe: string }] }; + }; + }; + + expect(sanitized.request.headers.authorization).toBe("[REDACTED]"); + expect(sanitized.request.body.nested[0].config.apiKey).toBe("[REDACTED]"); + expect(sanitized.request.body.nested[1].safe).toBe("ok"); + }); + + test("does not redact non-secret keys or mutate primitives/arrays", () => { + const sanitized = sanitizeForAudit({ + count: 3, + items: ["a", "b", "c"], + nested: { ok: true }, + }); + expect(sanitized).toEqual({ count: 3, items: ["a", "b", "c"], nested: { ok: true } }); + }); + + test("caps serialized size and marks the result truncated", () => { + const huge = { blob: "x".repeat(50_000) }; + const sanitized = sanitizeForAudit(huge) as { + truncated: boolean; + originalChars: number; + preview: string; + }; + expect(sanitized.truncated).toBe(true); + expect(sanitized.originalChars).toBeGreaterThan(20_000); + expect(sanitized.preview.length).toBe(20_000); + }); + + test("leaves small values under the size cap untouched", () => { + const small = { blob: "x".repeat(100) }; + const sanitized = sanitizeForAudit(small); + expect(sanitized).toEqual(small); + }); + + test("redacts secrets even inside a value that also gets truncated", () => { + const huge = { apiKey: "sk-live-secret", blob: "x".repeat(50_000) }; + const sanitized = sanitizeForAudit(huge) as { preview: string }; + expect(sanitized.preview).not.toContain("sk-live-secret"); + }); +}); diff --git a/apps/server/src/audit.ts b/apps/server/src/audit.ts index 1beefe2..7b6633f 100644 --- a/apps/server/src/audit.ts +++ b/apps/server/src/audit.ts @@ -1,6 +1,67 @@ import type { AuditActor, AuditStatus } from "@nyxel/db"; import { getDb } from "@nyxel/db"; +const REDACTED = "[REDACTED]"; + +// Matched against a normalized (lowercased, non-alphanumeric stripped) key, +// so "API-Key", "apiKey", "access_token", "Authorization" all match despite +// different casing/separator conventions across tool schemas. +const SECRET_KEY_SUBSTRINGS = ["apikey", "token", "authorization", "password", "secret", "cookie"]; + +function isSecretKey(key: string): boolean { + const normalized = key.toLowerCase().replace(/[^a-z0-9]/g, ""); + return SECRET_KEY_SUBSTRINGS.some((needle) => normalized.includes(needle)); +} + +// Tool inputs/outputs are already JSON-serializable (they're literal +// arguments/results), so no cycle handling — just a depth cap against a +// pathologically nested value. +const MAX_REDACT_DEPTH = 12; + +function redactValue(value: unknown, depth: number): unknown { + if (depth > MAX_REDACT_DEPTH) return "[TRUNCATED: max nesting depth exceeded]"; + if (Array.isArray(value)) return value.map((entry) => redactValue(entry, depth + 1)); + if (value !== null && typeof value === "object") { + const result: Record = {}; + for (const [key, entry] of Object.entries(value as Record)) { + result[key] = isSecretKey(key) ? REDACTED : redactValue(entry, depth + 1); + } + return result; + } + return value; +} + +// Serialized-size cap for a single audit_log.input/output value — tool +// output can be arbitrarily large (whole file contents, full search +// results), and the audit trail only needs enough to reconstruct what +// happened, not a full replay. +const MAX_AUDIT_VALUE_CHARS = 20_000; + +/** + * Redacts secret-shaped keys (case/separator-insensitive) anywhere in a tool + * input/output value and caps its serialized size, before it's ever written + * to audit_log — a leaked or over-broadly-shared audit row should never + * itself hand over a live credential. `inputHash` (see permissions.ts's + * hashToolInput) is computed from the raw, pre-redaction value elsewhere and + * passed through logAudit unchanged, so redaction here doesn't affect it. + */ +export function sanitizeForAudit(value: unknown): unknown { + if (value === undefined || value === null) return value; + const redacted = redactValue(value, 0); + let serialized: string; + try { + serialized = JSON.stringify(redacted); + } catch { + return "[UNSERIALIZABLE]"; + } + if (serialized.length <= MAX_AUDIT_VALUE_CHARS) return redacted; + return { + truncated: true, + originalChars: serialized.length, + preview: serialized.slice(0, MAX_AUDIT_VALUE_CHARS), + }; +} + /** * Writes one row to the audit log (ARCHITECTURE.md section 5: "every action * by every agent is logged"). Logging failures are swallowed — a broken @@ -21,7 +82,14 @@ export async function logAudit(input: { permissionSnapshot?: Record | null; }): Promise { try { - await getDb().createAuditLog(input); + await getDb().createAuditLog({ + ...input, + input: sanitizeForAudit(input.input), + output: sanitizeForAudit(input.output), + permissionSnapshot: input.permissionSnapshot + ? (sanitizeForAudit(input.permissionSnapshot) as Record) + : input.permissionSnapshot, + }); } catch (err) { console.error("Failed to write audit log entry", err); } diff --git a/apps/server/src/knowledge-base.test.ts b/apps/server/src/knowledge-base.test.ts new file mode 100644 index 0000000..ebf7328 --- /dev/null +++ b/apps/server/src/knowledge-base.test.ts @@ -0,0 +1,87 @@ +import { afterEach, beforeEach, describe, expect, it } from "bun:test"; +import { mkdtemp, rm, writeFile } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { getDb } from "@nyxel/db"; +import { createTestUser, installTestDb } from "@nyxel/db/test-utils"; +import { getKnowledgeBaseContextForPrompt } from "./knowledge-base"; + +let ctx: Awaited>; +let vaultDir: string; + +beforeEach(async () => { + ctx = await installTestDb(); + vaultDir = await mkdtemp(join(tmpdir(), "nyxel-kb-test-")); +}); + +afterEach(async () => { + await ctx.cleanup(); + await rm(vaultDir, { recursive: true, force: true }); + delete process.env.NYXEL_KB_PROMPT_SECTION_MAX_CHARS; + delete process.env.NYXEL_KB_PROMPT_CONTEXT_MAX_CHARS; +}); + +async function seedWorkspaceWithVault(noteContent: string) { + const db = getDb(); + const user = createTestUser(ctx.path); + const workspace = await db.createWorkspace({ userId: user.id, name: "Test workspace" }); + await db.upsertKnowledgeBaseConfig({ + workspaceId: workspace.id, + vaultPath: vaultDir, + injectIntoPrompts: true, + }); + await writeFile(join(vaultDir, "00-Meta-overview.md"), noteContent, "utf8"); + return workspace; +} + +describe("getKnowledgeBaseContextForPrompt budget env vars", () => { + it("falls back to the existing hardcoded caps when env vars are unset", async () => { + const longNote = "x".repeat(3000); + const workspace = await seedWorkspaceWithVault(longNote); + + const block = await getKnowledgeBaseContextForPrompt(workspace.id); + + expect(block).not.toBeNull(); + // Default per-note cap (1500) truncates the 3000-char note. + expect(block).toContain("x".repeat(1500)); + expect(block).not.toContain("x".repeat(1501)); + // Whole block stays under the default context cap (6000), so no + // context-level truncation marker is appended. + expect(block?.endsWith("…(truncated)")).toBe(false); + }); + + it("truncates per-note content when NYXEL_KB_PROMPT_SECTION_MAX_CHARS is set", async () => { + process.env.NYXEL_KB_PROMPT_SECTION_MAX_CHARS = "50"; + const longNote = "y".repeat(3000); + const workspace = await seedWorkspaceWithVault(longNote); + + const block = await getKnowledgeBaseContextForPrompt(workspace.id); + + expect(block).not.toBeNull(); + expect(block).toContain("y".repeat(50)); + expect(block).not.toContain("y".repeat(51)); + }); + + it("truncates the whole assembled block when NYXEL_KB_PROMPT_CONTEXT_MAX_CHARS is set low", async () => { + process.env.NYXEL_KB_PROMPT_CONTEXT_MAX_CHARS = "200"; + const workspace = await seedWorkspaceWithVault("z".repeat(3000)); + + const block = await getKnowledgeBaseContextForPrompt(workspace.id); + + expect(block).not.toBeNull(); + expect(block?.endsWith("…(truncated)")).toBe(true); + expect(block?.length).toBeLessThanOrEqual(200 + "\n…(truncated)".length); + }); + + it("falls back silently to the default when an env var is invalid", async () => { + process.env.NYXEL_KB_PROMPT_SECTION_MAX_CHARS = "not-a-number"; + const longNote = "w".repeat(3000); + const workspace = await seedWorkspaceWithVault(longNote); + + const block = await getKnowledgeBaseContextForPrompt(workspace.id); + + expect(block).not.toBeNull(); + expect(block).toContain("w".repeat(1500)); + expect(block).not.toContain("w".repeat(1501)); + }); +}); diff --git a/apps/server/src/knowledge-base.ts b/apps/server/src/knowledge-base.ts index 416c1ec..5449bc0 100644 --- a/apps/server/src/knowledge-base.ts +++ b/apps/server/src/knowledge-base.ts @@ -205,11 +205,18 @@ function summarizeAuditEntry(entry: AuditLogRecord) { return `- ${entry.actor} · ${entry.toolLabel} · ${entry.status}${clipped ? ` · ${clipped}` : ""}`; } -const KNOWLEDGE_BASE_PROMPT_CONTEXT_MAX_CHARS = 6000; -const KNOWLEDGE_BASE_PROMPT_SECTION_MAX_CHARS = 1500; +const KNOWLEDGE_BASE_PROMPT_CONTEXT_MAX_CHARS_DEFAULT = 6000; +const KNOWLEDGE_BASE_PROMPT_SECTION_MAX_CHARS_DEFAULT = 1500; const ALWAYS_INCLUDE_GROUP = "00-Meta"; const RECENT_NOTES_TO_INCLUDE = 3; +function positiveIntEnv(name: string, fallback: number): number { + const raw = process.env[name]; + if (!raw) return fallback; + const parsed = Number.parseInt(raw, 10); + return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback; +} + /** * Builds the auto-injected knowledge-base block appended to every chat, * automation, and scheduled-agent system prompt (see ARCHITECTURE.md section @@ -227,6 +234,15 @@ const RECENT_NOTES_TO_INCLUDE = 3; export async function getKnowledgeBaseContextForPrompt( workspaceId: string, ): Promise { + const contextMaxChars = positiveIntEnv( + "NYXEL_KB_PROMPT_CONTEXT_MAX_CHARS", + KNOWLEDGE_BASE_PROMPT_CONTEXT_MAX_CHARS_DEFAULT, + ); + const sectionMaxChars = positiveIntEnv( + "NYXEL_KB_PROMPT_SECTION_MAX_CHARS", + KNOWLEDGE_BASE_PROMPT_SECTION_MAX_CHARS_DEFAULT, + ); + const db = getDb(); const config = await db.getKnowledgeBaseConfig(workspaceId); if (config && !config.injectIntoPrompts) return null; @@ -257,7 +273,7 @@ export async function getKnowledgeBaseContextForPrompt( const content = await fs .readFile(path.join(absoluteVaultPath, doc.path), "utf8") .catch(() => ""); - return `### ${doc.path}\n${content.slice(0, KNOWLEDGE_BASE_PROMPT_SECTION_MAX_CHARS)}`; + return `### ${doc.path}\n${content.slice(0, sectionMaxChars)}`; }), ); @@ -271,8 +287,8 @@ export async function getKnowledgeBaseContextForPrompt( ...sections, ].join("\n"); - return block.length > KNOWLEDGE_BASE_PROMPT_CONTEXT_MAX_CHARS - ? `${block.slice(0, KNOWLEDGE_BASE_PROMPT_CONTEXT_MAX_CHARS)}\n…(truncated)` + return block.length > contextMaxChars + ? `${block.slice(0, contextMaxChars)}\n…(truncated)` : block; } @@ -298,9 +314,10 @@ export async function getKnowledgeBaseOverview(workspaceId: string) { ? await pingObsidianRestApi(config.obsidianRestUrl, config.obsidianApiKey) : { reachable: false, error: "Not configured" }; + const { obsidianApiKey: _obsidianApiKey, ...configWithoutApiKey } = config; return { config: { - ...config, + ...configWithoutApiKey, obsidianApiKeySet: Boolean(config.obsidianApiKey), absoluteVaultPath, }, diff --git a/apps/server/src/scheduler.test.ts b/apps/server/src/scheduler.test.ts new file mode 100644 index 0000000..c3fddbd --- /dev/null +++ b/apps/server/src/scheduler.test.ts @@ -0,0 +1,125 @@ +import { afterEach, beforeEach, describe, expect, it } from "bun:test"; +import type { DbRepository } from "@nyxel/db"; +import { getDb } from "@nyxel/db"; +import { createTestUser, installTestDb } from "@nyxel/db/test-utils"; +import { checkStaleAgentRuns } from "./scheduler"; + +async function seedWorkspace(db: DbRepository, path: string) { + const user = createTestUser(path); + const workspace = await db.createWorkspace({ userId: user.id, name: "Test workspace" }); + return { user, workspace }; +} + +async function seedAgent(db: DbRepository, workspaceId: string) { + return db.createAgent({ + workspaceId, + name: "Worker", + modelId: "anthropic/claude-fake", + autonomyLevel: "autonomous", + }); +} + +let ctx: Awaited>; + +beforeEach(async () => { + ctx = await installTestDb(); +}); + +afterEach(async () => { + await ctx.cleanup(); +}); + +describe("checkStaleAgentRuns", () => { + it("marks a run failed once its lease has expired with no live process renewing it", async () => { + const db = getDb(); + const { workspace } = await seedWorkspace(db, ctx.path); + const agent = await seedAgent(db, workspace.id); + const task = await db.createTask({ + workspaceId: workspace.id, + assignedAgentId: agent.id, + title: "Stuck task", + instruction: "Do the thing.", + status: "running", + }); + const run = await db.createAgentRun({ + workspaceId: workspace.id, + taskId: task.id, + agentId: agent.id, + trigger: "task", + status: "running", + startedAt: new Date(), + workerId: "dead-process", + heartbeatAt: new Date(Date.now() - 10 * 60_000), + leaseUntil: new Date(Date.now() - 5 * 60_000), + }); + + await checkStaleAgentRuns(); + + const recoveredRun = await db.getAgentRun(run.id); + expect(recoveredRun?.status).toBe("failed"); + expect(recoveredRun?.errorMessage).toContain("stale-run sweep"); + + const recoveredTask = await db.getTask(task.id); + expect(recoveredTask?.status).toBe("failed"); + expect(recoveredTask?.errorMessage).toContain("stale-run sweep"); + }); + + it("recovers a run that never had a lease at all (pre-dates this feature)", async () => { + const db = getDb(); + const { workspace } = await seedWorkspace(db, ctx.path); + const agent = await seedAgent(db, workspace.id); + const run = await db.createAgentRun({ + workspaceId: workspace.id, + agentId: agent.id, + trigger: "chat", + status: "running", + startedAt: new Date(), + }); + + await checkStaleAgentRuns(); + + const recoveredRun = await db.getAgentRun(run.id); + expect(recoveredRun?.status).toBe("failed"); + }); + + it("leaves a run alone whose lease is still valid (owning process is alive)", async () => { + const db = getDb(); + const { workspace } = await seedWorkspace(db, ctx.path); + const agent = await seedAgent(db, workspace.id); + const run = await db.createAgentRun({ + workspaceId: workspace.id, + agentId: agent.id, + trigger: "chat", + status: "running", + startedAt: new Date(), + workerId: "alive-process", + heartbeatAt: new Date(), + leaseUntil: new Date(Date.now() + 60_000), + }); + + await checkStaleAgentRuns(); + + const untouchedRun = await db.getAgentRun(run.id); + expect(untouchedRun?.status).toBe("running"); + }); + + it("does not touch runs that already completed", async () => { + const db = getDb(); + const { workspace } = await seedWorkspace(db, ctx.path); + const agent = await seedAgent(db, workspace.id); + const run = await db.createAgentRun({ + workspaceId: workspace.id, + agentId: agent.id, + trigger: "chat", + status: "completed", + startedAt: new Date(), + completedAt: new Date(), + leaseUntil: new Date(Date.now() - 60_000), + }); + + await checkStaleAgentRuns(); + + const stillCompleted = await db.getAgentRun(run.id); + expect(stillCompleted?.status).toBe("completed"); + }); +}); diff --git a/apps/server/src/scheduler.ts b/apps/server/src/scheduler.ts index e20a5bd..023fb4c 100644 --- a/apps/server/src/scheduler.ts +++ b/apps/server/src/scheduler.ts @@ -346,6 +346,67 @@ async function checkDueSeoProjects(): Promise { } } +/** + * Recovers agent runs left stuck in "running" by a process that died or + * restarted before it could mark them cancelled/completed/failed itself — + * see apps/server/src/agent-runtime.ts's lease/heartbeat mechanism. A run + * qualifies once its lease has expired (or it never had one, e.g. it + * predates this feature) with no live process still renewing it. Marks the + * run failed and, if its task is still in a run-owned state, marks the task + * failed too so the Goal Orchestrator/task UI can react instead of the task + * looking permanently stuck. Runs on every scheduler tick and once at + * startup, so a crash is recovered within one tick rather than only once a + * human notices. + */ +export async function checkStaleAgentRuns(): Promise { + const db = getDb(); + let staleRuns: Awaited>; + try { + staleRuns = await db.listStaleRunningAgentRuns(new Date()); + } catch (err) { + console.error("Scheduler: failed to query stale agent runs:", err); + return; + } + for (const run of staleRuns) { + const reason = + "Run lease expired — recovered by the stale-run sweep (owning process likely died)."; + try { + await db.updateAgentRun(run.id, { + status: "failed", + errorMessage: reason, + completedAt: new Date(), + }); + if (run.taskId) { + const task = await db.getTask(run.taskId); + if (task && (task.status === "running" || task.status === "planning")) { + await db.updateTask(run.taskId, { + status: "failed", + errorMessage: reason, + completedAt: new Date(), + }); + await db.createTaskEvent({ + taskId: run.taskId, + workspaceId: run.workspaceId, + agentRunId: run.id, + agentId: run.agentId, + kind: "failed", + message: reason, + }); + } + } + await emitNyxelEvent({ + workspaceId: run.workspaceId, + type: NyxelEvent.AgentRunFailed, + entityType: "agent_run", + entityId: run.id, + payload: { taskId: run.taskId, agentId: run.agentId, error: reason }, + }); + } catch (err) { + console.error(`Scheduler: failed to recover stale agent run ${run.id}:`, err); + } + } +} + /** * Reviews every goal due for its periodic Goal Orchestrator check (ADR-0018) * — `orchestrationEnabled` goals whose `nextReviewAt` has passed. A separate @@ -372,6 +433,11 @@ async function checkGoalsForReview(): Promise { * the poll loop or block sibling automations from running. */ export function startScheduler(): () => void { + // Runs once immediately at startup (not just on the first 30s tick) so a + // run orphaned by a crash/restart is recovered as soon as the server comes + // back up, rather than sitting stuck for up to POLL_INTERVAL_MS. + void checkStaleAgentRuns(); + const timer = setInterval(async () => { let due: AutomationRecord[]; try { @@ -391,6 +457,7 @@ export function startScheduler(): () => void { await checkFileWatchAutomations(); await checkDueSeoProjects(); await checkGoalsForReview(); + await checkStaleAgentRuns(); }, POLL_INTERVAL_MS); // Timers otherwise keep the process alive forever — unref lets a clean diff --git a/apps/server/src/tools-builtin/search.test.ts b/apps/server/src/tools-builtin/search.test.ts new file mode 100644 index 0000000..b78f27f --- /dev/null +++ b/apps/server/src/tools-builtin/search.test.ts @@ -0,0 +1,70 @@ +import { afterEach, beforeEach, describe, expect, it } from "bun:test"; +import { mkdtemp, rm, writeFile } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import type { ToolRecord } from "@nyxel/db"; +import { createSkillContext } from "@nyxel/skills-sdk"; +import { buildTextSearchTool } from "./search"; + +function record(overrides: Partial = {}): ToolRecord { + return { + id: "tool-1", + workspaceId: "workspace-1", + name: "Text search", + description: "Search file contents.", + kind: "text_search", + config: {}, + sensitive: false, + enabled: true, + builtin: true, + createdAt: new Date(), + ...overrides, + }; +} + +let dir: string; + +beforeEach(async () => { + dir = await mkdtemp(join(tmpdir(), "nyxel-search-test-")); +}); + +afterEach(async () => { + await rm(dir, { recursive: true, force: true }); +}); + +describe("buildTextSearchTool aggregate output cap", () => { + it("returns every match untruncated when well under the output byte budget", async () => { + await writeFile(join(dir, "small.txt"), "needle appears once here\n", "utf8"); + const tool = buildTextSearchTool(record({ config: { allowedDirs: [dir] } })); + + const result = await tool.run( + { query: "needle", roots: [dir], maxResults: 100 }, + createSkillContext(tool.permissions), + ); + + expect(result.matches).toHaveLength(1); + expect(result.truncated).toBe(false); + }); + + it("stops adding matches and marks the result truncated once the aggregate byte budget is hit", async () => { + // Each matching line is ~300 chars (capped) plus JSON overhead, so a + // few hundred matches comfortably blow past the 50,000-byte budget. + const line = `needle ${"a".repeat(290)}`; + const content = Array.from({ length: 400 }, () => line).join("\n"); + await writeFile(join(dir, "big.txt"), content, "utf8"); + const tool = buildTextSearchTool(record({ config: { allowedDirs: [dir] } })); + + const result = await tool.run( + { query: "needle", roots: [dir], maxResults: 500 }, + createSkillContext(tool.permissions), + ); + + expect(result.truncated).toBe(true); + expect(result.matches.length).toBeLessThan(400); + const totalBytes = result.matches.reduce( + (sum: number, match: unknown) => sum + JSON.stringify(match).length, + 0, + ); + expect(totalBytes).toBeLessThanOrEqual(50_000); + }); +}); diff --git a/apps/server/src/tools-builtin/search.ts b/apps/server/src/tools-builtin/search.ts index d03f7c1..4c6ebe7 100644 --- a/apps/server/src/tools-builtin/search.ts +++ b/apps/server/src/tools-builtin/search.ts @@ -6,183 +6,179 @@ import { z } from "zod"; import { allowedDirsFromConfig, baseFields } from "./shared"; import { runCommandToCompletion } from "./terminal"; -const IGNORED_DIR_NAMES = new Set([ - "node_modules", - ".git", - "dist", - "build", - ".next", - ".turbo", -]); +const IGNORED_DIR_NAMES = new Set(["node_modules", ".git", "dist", "build", ".next", ".turbo"]); const MAX_FILE_BYTES = 1_000_000; const MAX_WALK_ENTRIES = 20_000; +const MAX_TOTAL_OUTPUT_BYTES = 50_000; /** Recursively walks `roots`, yielding file paths — skips the usual * dependency/build noise. Deliberately hand-rolled (no glob/ripgrep * dependency, see the plan) rather than pulling in fast-glob/ripgrep. */ async function* walkFiles(roots: string[]): AsyncGenerator { - let visited = 0; - async function* walk(dir: string): AsyncGenerator { - if (visited > MAX_WALK_ENTRIES) return; - let entries: import("node:fs").Dirent[]; - try { - entries = await readdir(dir, { withFileTypes: true }); - } catch { - return; - } - for (const entry of entries) { - if (visited > MAX_WALK_ENTRIES) return; - visited++; - if (entry.isDirectory()) { - if (IGNORED_DIR_NAMES.has(entry.name) || entry.name.startsWith(".")) continue; - yield* walk(path.join(dir, entry.name)); - } else if (entry.isFile()) { - yield path.join(dir, entry.name); - } - } - } - for (const root of roots) yield* walk(root); + let visited = 0; + async function* walk(dir: string): AsyncGenerator { + if (visited > MAX_WALK_ENTRIES) return; + let entries: import("node:fs").Dirent[]; + try { + entries = await readdir(dir, { withFileTypes: true }); + } catch { + return; + } + for (const entry of entries) { + if (visited > MAX_WALK_ENTRIES) return; + visited++; + if (entry.isDirectory()) { + if (IGNORED_DIR_NAMES.has(entry.name) || entry.name.startsWith(".")) continue; + yield* walk(path.join(dir, entry.name)); + } else if (entry.isFile()) { + yield path.join(dir, entry.name); + } + } + } + for (const root of roots) yield* walk(root); } function assertRootsAllowed(roots: string[], allowedDirs: string[]) { - for (const root of roots) { - const resolved = path.resolve(root); - const allowed = allowedDirs.some( - (dir) => resolved === dir || resolved.startsWith(`${dir}/`), - ); - if (!allowed) { - throw new Error(`"${resolved}" isn't in this tool's declared filesystem permissions.`); - } - } + for (const root of roots) { + const resolved = path.resolve(root); + const allowed = allowedDirs.some((dir) => resolved === dir || resolved.startsWith(`${dir}/`)); + if (!allowed) { + throw new Error(`"${resolved}" isn't in this tool's declared filesystem permissions.`); + } + } } function wildcardToRegExp(pattern: string): RegExp { - const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&"); - const withWildcards = escaped.replace(/\*/g, ".*").replace(/\?/g, "."); - return new RegExp(`^${withWildcards}$`, "i"); + const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&"); + const withWildcards = escaped.replace(/\*/g, ".*").replace(/\?/g, "."); + return new RegExp(`^${withWildcards}$`, "i"); } export function buildFileSearchTool(record: ToolRecord): SkillDefinition { - const allowedDirs = allowedDirsFromConfig(record.config ?? {}); - return { - ...baseFields(record), - inputSchema: z.object({ - pattern: z - .string() - .describe('Filename glob, e.g. "*.test.ts" — only "*" and "?" wildcards.'), - roots: z.array(z.string()).optional(), - maxResults: z.number().int().min(1).max(500).default(100), - }), - permissions: { network: [], filesystem: allowedDirs }, - async run({ pattern, roots, maxResults }) { - const searchRoots = roots ?? allowedDirs; - assertRootsAllowed(searchRoots, allowedDirs); - const regex = wildcardToRegExp(pattern); - const matches: string[] = []; - for await (const file of walkFiles(searchRoots)) { - if (regex.test(path.basename(file))) matches.push(file); - if (matches.length >= maxResults) break; - } - return { pattern, matches }; - }, - }; + const allowedDirs = allowedDirsFromConfig(record.config ?? {}); + return { + ...baseFields(record), + inputSchema: z.object({ + pattern: z.string().describe('Filename glob, e.g. "*.test.ts" — only "*" and "?" wildcards.'), + roots: z.array(z.string()).optional(), + maxResults: z.number().int().min(1).max(500).default(100), + }), + permissions: { network: [], filesystem: allowedDirs }, + async run({ pattern, roots, maxResults }) { + const searchRoots = roots ?? allowedDirs; + assertRootsAllowed(searchRoots, allowedDirs); + const regex = wildcardToRegExp(pattern); + const matches: string[] = []; + for await (const file of walkFiles(searchRoots)) { + if (regex.test(path.basename(file))) matches.push(file); + if (matches.length >= maxResults) break; + } + return { pattern, matches }; + }, + }; } async function grepFiles( - roots: string[], - needle: RegExp, - maxResults: number, -): Promise<{ path: string; line: number; text: string }[]> { - const results: { path: string; line: number; text: string }[] = []; - for await (const file of walkFiles(roots)) { - if (results.length >= maxResults) break; - let stats: Awaited>; - try { - stats = await stat(file); - } catch { - continue; - } - if (stats.size > MAX_FILE_BYTES) continue; - let content: string; - try { - content = await readFile(file, "utf-8"); - } catch { - continue; // binary/unreadable — skip rather than fail the whole search - } - const lines = content.split("\n"); - for (let i = 0; i < lines.length; i++) { - const line = lines[i]; - if (line !== undefined && needle.test(line)) { - results.push({ path: file, line: i + 1, text: line.trim().slice(0, 300) }); - if (results.length >= maxResults) break; - } - needle.lastIndex = 0; - } - } - return results; + roots: string[], + needle: RegExp, + maxResults: number, +): Promise<{ matches: { path: string; line: number; text: string }[]; truncated: boolean }> { + const results: { path: string; line: number; text: string }[] = []; + let outputBytes = 0; + let truncated = false; + files: for await (const file of walkFiles(roots)) { + if (results.length >= maxResults) break; + let stats: Awaited>; + try { + stats = await stat(file); + } catch { + continue; + } + if (stats.size > MAX_FILE_BYTES) continue; + let content: string; + try { + content = await readFile(file, "utf-8"); + } catch { + continue; // binary/unreadable — skip rather than fail the whole search + } + const lines = content.split("\n"); + for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + if (line !== undefined && needle.test(line)) { + const match = { path: file, line: i + 1, text: line.trim().slice(0, 300) }; + const matchBytes = JSON.stringify(match).length; + if (outputBytes + matchBytes > MAX_TOTAL_OUTPUT_BYTES) { + truncated = true; + break files; + } + outputBytes += matchBytes; + results.push(match); + if (results.length >= maxResults) break; + } + needle.lastIndex = 0; + } + } + return { matches: results, truncated }; } /** text_search, usages, and codebase_search all funnel through this — see * the plan's explicit callout that "usages"/"codebase_search" are heuristic * regex search over the allowed directory tree, not LSP-based symbol * resolution or embeddings-based semantic search. */ -function buildGrepTool( - record: ToolRecord, - toRegExp: (query: string) => RegExp, -): SkillDefinition { - const allowedDirs = allowedDirsFromConfig(record.config ?? {}); - return { - ...baseFields(record), - inputSchema: z.object({ - query: z.string().min(1), - roots: z.array(z.string()).optional(), - maxResults: z.number().int().min(1).max(500).default(100), - }), - permissions: { network: [], filesystem: allowedDirs }, - async run({ query, roots, maxResults }) { - const searchRoots = roots ?? allowedDirs; - assertRootsAllowed(searchRoots, allowedDirs); - const matches = await grepFiles(searchRoots, toRegExp(query), maxResults); - return { query, matches }; - }, - }; +function buildGrepTool(record: ToolRecord, toRegExp: (query: string) => RegExp): SkillDefinition { + const allowedDirs = allowedDirsFromConfig(record.config ?? {}); + return { + ...baseFields(record), + inputSchema: z.object({ + query: z.string().min(1), + roots: z.array(z.string()).optional(), + maxResults: z.number().int().min(1).max(500).default(100), + }), + permissions: { network: [], filesystem: allowedDirs }, + async run({ query, roots, maxResults }) { + const searchRoots = roots ?? allowedDirs; + assertRootsAllowed(searchRoots, allowedDirs); + const { matches, truncated } = await grepFiles(searchRoots, toRegExp(query), maxResults); + return { query, matches, truncated }; + }, + }; } export function buildTextSearchTool(record: ToolRecord): SkillDefinition { - return buildGrepTool(record, (query) => new RegExp(query, "gi")); + return buildGrepTool(record, (query) => new RegExp(query, "gi")); } export function buildUsagesTool(record: ToolRecord): SkillDefinition { - return buildGrepTool( - record, - (identifier) => new RegExp(`\\b${identifier.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\b`, "g"), - ); + return buildGrepTool( + record, + (identifier) => new RegExp(`\\b${identifier.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\b`, "g"), + ); } export function buildCodebaseSearchTool(record: ToolRecord): SkillDefinition { - return buildGrepTool(record, (query) => new RegExp(query, "gi")); + return buildGrepTool(record, (query) => new RegExp(query, "gi")); } export function buildChangesTool(record: ToolRecord): SkillDefinition { - const allowedDirs = allowedDirsFromConfig(record.config ?? {}); - const root = allowedDirs[0]; - return { - ...baseFields(record), - inputSchema: z.object({ staged: z.boolean().default(false) }), - permissions: { network: [], filesystem: allowedDirs }, - async run({ staged }) { - if (!root) throw new Error(`"${record.name}" has no configured directory.`); - const { output } = await runCommandToCompletion( - staged ? "git diff --cached" : "git diff", - root, - 10_000, - ); - const { output: statusOutput } = await runCommandToCompletion( - "git status --porcelain", - root, - 10_000, - ); - return { diff: output.slice(-8000), status: statusOutput.slice(-4000) }; - }, - }; + const allowedDirs = allowedDirsFromConfig(record.config ?? {}); + const root = allowedDirs[0]; + return { + ...baseFields(record), + inputSchema: z.object({ staged: z.boolean().default(false) }), + permissions: { network: [], filesystem: allowedDirs }, + async run({ staged }) { + if (!root) throw new Error(`"${record.name}" has no configured directory.`); + const { output } = await runCommandToCompletion( + staged ? "git diff --cached" : "git diff", + root, + 10_000, + ); + const { output: statusOutput } = await runCommandToCompletion( + "git status --porcelain", + root, + 10_000, + ); + return { diff: output.slice(-8000), status: statusOutput.slice(-4000) }; + }, + }; } diff --git a/apps/server/src/trpc/router.test.ts b/apps/server/src/trpc/router.test.ts index dc026ff..02a53b3 100644 --- a/apps/server/src/trpc/router.test.ts +++ b/apps/server/src/trpc/router.test.ts @@ -1,6 +1,14 @@ import { describe, expect, test } from "bun:test"; -import type { ModelInstallationRecord } from "@nyxel/db"; -import { toClientSafeInstallation } from "./router"; +import type { + KnowledgeBaseConfigRecord, + McpServerRecord, + ModelInstallationRecord, +} from "@nyxel/db"; +import { + toClientSafeInstallation, + toClientSafeKnowledgeBaseConfig, + toClientSafeMcpServer, +} from "./router"; function makeInstallation( overrides: Partial = {}, @@ -53,3 +61,85 @@ describe("toClientSafeInstallation (SECURITY_AUDIT.md SEC-02)", () => { expect(safe.modelIds).toEqual(installation.modelIds); }); }); + +function makeMcpServer(overrides: Partial = {}): McpServerRecord { + return { + id: "mcp-1", + workspaceId: "ws-1", + name: "GitHub", + transport: "http", + command: null, + args: null, + url: "https://api.githubcopilot.com/mcp", + env: { GITHUB_TOKEN: "ghp_live_secret" }, + oauthState: { accessToken: "at-live-secret", refreshToken: "rt-live-secret" }, + enabled: true, + createdAt: new Date(), + ...overrides, + }; +} + +describe("toClientSafeMcpServer (SECURITY_AUDIT.md SEC-01)", () => { + test("never includes the raw env or oauthState fields", () => { + const safe = toClientSafeMcpServer(makeMcpServer()); + expect("env" in safe).toBe(false); + expect("oauthState" in safe).toBe(false); + expect(JSON.stringify(safe)).not.toContain("secret"); + }); + + test("reports hasEnv/hasOAuthState: true when configured", () => { + const safe = toClientSafeMcpServer(makeMcpServer()); + expect(safe.hasEnv).toBe(true); + expect(safe.hasOAuthState).toBe(true); + }); + + test("reports hasEnv/hasOAuthState: false when null or empty", () => { + const safe = toClientSafeMcpServer(makeMcpServer({ env: null, oauthState: {} })); + expect(safe.hasEnv).toBe(false); + expect(safe.hasOAuthState).toBe(false); + }); + + test("preserves every other field unchanged", () => { + const server = makeMcpServer(); + const safe = toClientSafeMcpServer(server); + expect(safe.id).toBe(server.id); + expect(safe.name).toBe(server.name); + expect(safe.transport).toBe(server.transport); + expect(safe.enabled).toBe(server.enabled); + }); +}); + +function makeKnowledgeBaseConfig( + overrides: Partial = {}, +): KnowledgeBaseConfigRecord { + return { + workspaceId: "ws-1", + vaultPath: "knowledge-base", + obsidianRestUrl: "http://127.0.0.1:27124/", + obsidianApiKey: "obsidian-live-secret", + docsAgentEnabled: true, + injectIntoPrompts: true, + lastDocsSyncAt: null, + lastDocsSyncError: null, + updatedAt: new Date(), + ...overrides, + }; +} + +describe("toClientSafeKnowledgeBaseConfig (SECURITY_AUDIT.md SEC-01/SEC-02)", () => { + test("never includes the raw obsidianApiKey field", () => { + const safe = toClientSafeKnowledgeBaseConfig(makeKnowledgeBaseConfig()); + expect("obsidianApiKey" in safe).toBe(false); + expect(JSON.stringify(safe)).not.toContain("obsidian-live-secret"); + }); + + test("reports obsidianApiKeySet: true when a key is configured", () => { + const safe = toClientSafeKnowledgeBaseConfig(makeKnowledgeBaseConfig()); + expect(safe.obsidianApiKeySet).toBe(true); + }); + + test("reports obsidianApiKeySet: false when no key is configured", () => { + const safe = toClientSafeKnowledgeBaseConfig(makeKnowledgeBaseConfig({ obsidianApiKey: null })); + expect(safe.obsidianApiKeySet).toBe(false); + }); +}); diff --git a/apps/server/src/trpc/router.ts b/apps/server/src/trpc/router.ts index 3ac1a53..fd671d0 100644 --- a/apps/server/src/trpc/router.ts +++ b/apps/server/src/trpc/router.ts @@ -2,6 +2,8 @@ import { DEFAULT_CHAT_TOOL_POLICY, DEFAULT_CHAT_WORKING_DIRECTORY, getDb, + type KnowledgeBaseConfigRecord, + type McpServerRecord, type ModelInstallationRecord, } from "@nyxel/db"; import { McpAuthorizationRequiredError, McpInvalidConfigurationError } from "@nyxel/mcp-client"; @@ -416,6 +418,27 @@ export function toClientSafeInstallation(installation: ModelInstallationRecord) return { ...rest, hasApiKey: apiKey !== null && apiKey.length > 0 }; } +// Same rationale as toClientSafeInstallation above — env (may hold a stdio +// server's OAuth credential path or other secret env vars) and oauthState +// (access/refresh tokens, PKCE state) never need to leave the server; the +// client only needs to know whether either is configured. +export function toClientSafeMcpServer(server: McpServerRecord) { + const { env, oauthState, ...rest } = server; + return { + ...rest, + hasEnv: env !== null && Object.keys(env).length > 0, + hasOAuthState: oauthState !== null && Object.keys(oauthState).length > 0, + }; +} + +// Same rationale — obsidianApiKey never needs to leave the server; the UI +// only needs to know whether one's configured (mirrors getKnowledgeBaseOverview's +// obsidianApiKeySet field so both endpoints agree on shape). +export function toClientSafeKnowledgeBaseConfig(config: KnowledgeBaseConfigRecord) { + const { obsidianApiKey, ...rest } = config; + return { ...rest, obsidianApiKeySet: obsidianApiKey !== null && obsidianApiKey.length > 0 }; +} + export const appRouter = router({ health: publicProcedure.query(() => ({ ok: true, name: "nyxel-server" })), @@ -574,7 +597,7 @@ export const appRouter = router({ ? input.modelIds : detected.modelIds; - return getDb().createModelInstallation({ + const installation = await getDb().createModelInstallation({ workspaceId: input.workspaceId, label: input.label, providerKind: input.providerKind, @@ -583,6 +606,7 @@ export const appRouter = router({ modelIds, enabled: true, }); + return toClientSafeInstallation(installation); }), // OpenRouter's catalog is public, so this works with or without a key — // the settings panel calls it as the user types their key to preview @@ -613,7 +637,7 @@ export const appRouter = router({ ? input.modelIds : models.map((model) => model.id); - return getDb().createModelInstallation({ + const installation = await getDb().createModelInstallation({ workspaceId: input.workspaceId, label: input.label, providerKind: "openrouter", @@ -622,6 +646,7 @@ export const appRouter = router({ modelIds, enabled: true, }); + return toClientSafeInstallation(installation); }), deleteInstallation: protectedProcedure .input(z.object({ id: z.string() })) @@ -676,7 +701,9 @@ export const appRouter = router({ const disabledModelIds = input.enabled ? installation.disabledModelIds.filter((id) => id !== input.modelId) : Array.from(new Set([...installation.disabledModelIds, input.modelId])); - return db.updateModelInstallation({ id: input.id, disabledModelIds }); + return toClientSafeInstallation( + await db.updateModelInstallation({ id: input.id, disabledModelIds }), + ); }), // Catalog for the "add model" autocomplete/autofill on an already // installed provider — same live source addModelToInstallation @@ -708,7 +735,9 @@ export const appRouter = router({ () => db.getModelInstallation(input.id), "Model installation not found", ); - if (installation.modelIds.includes(input.modelId)) return installation; + if (installation.modelIds.includes(input.modelId)) { + return toClientSafeInstallation(installation); + } // Verify against the provider's real catalog when one is // reachable — `null` means unverifiable (no key, CLI provider, @@ -725,7 +754,9 @@ export const appRouter = router({ } const modelIds = [...installation.modelIds, input.modelId]; - return db.updateModelInstallation({ id: input.id, modelIds }); + return toClientSafeInstallation( + await db.updateModelInstallation({ id: input.id, modelIds }), + ); }), removeModelFromInstallation: protectedProcedure .input(z.object({ id: z.string(), modelId: z.string() })) @@ -744,7 +775,9 @@ export const appRouter = router({ await db.deleteModelInstallation(input.id); return null; } - return db.updateModelInstallation({ id: input.id, modelIds, disabledModelIds }); + return toClientSafeInstallation( + await db.updateModelInstallation({ id: input.id, modelIds, disabledModelIds }), + ); }), // Local CLI providers (claude_cli/codex_cli) — see // apps/server/src/cli-providers.ts. Auth state is host-wide, not @@ -796,10 +829,12 @@ export const appRouter = router({ ); if (existing) { const modelIds = Array.from(new Set([...existing.modelIds, ...input.modelIds])); - return db.updateModelInstallation({ id: existing.id, modelIds }); + return toClientSafeInstallation( + await db.updateModelInstallation({ id: existing.id, modelIds }), + ); } - return db.createModelInstallation({ + const installation = await db.createModelInstallation({ workspaceId: input.workspaceId, label: input.label, providerKind: input.providerKind, @@ -808,6 +843,7 @@ export const appRouter = router({ modelIds: input.modelIds, enabled: true, }); + return toClientSafeInstallation(installation); }), // TODO(ADR-0017): needs auth review — scans host-local paths for // importable provider configs (e.g. existing CLI credential files); @@ -818,7 +854,9 @@ export const appRouter = router({ scanImportSources: publicProcedure.query(() => listProviderImportSources()), importSource: workspaceProcedure .input(z.object({ workspaceId: z.string(), sourceId: z.string() })) - .mutation(({ input }) => importProviderSourceToWorkspace(input)), + .mutation(async ({ input }) => + toClientSafeInstallation(await importProviderSourceToWorkspace(input)), + ), }), skills: router({ @@ -2245,13 +2283,17 @@ export const appRouter = router({ catalog: publicProcedure.query(() => MCP_CONNECTOR_CATALOG), list: workspaceProcedure .input(z.object({ workspaceId: z.string() })) - .query(({ input }) => getDb().listMcpServersByWorkspace(input.workspaceId)), - create: workspaceProcedure.input(mcpServerCreateSchema).mutation(({ input }) => - getDb().createMcpServer({ - ...input, - command: input.command?.trim(), - url: input.url?.trim(), - }), + .query(async ({ input }) => + (await getDb().listMcpServersByWorkspace(input.workspaceId)).map(toClientSafeMcpServer), + ), + create: workspaceProcedure.input(mcpServerCreateSchema).mutation(async ({ input }) => + toClientSafeMcpServer( + await getDb().createMcpServer({ + ...input, + command: input.command?.trim(), + url: input.url?.trim(), + }), + ), ), // For catalog entries with configFields — writes any "secret-file" values // to a local file and builds the stdio server's env from the result, @@ -2265,7 +2307,7 @@ export const appRouter = router({ values: z.record(z.string(), z.string()), }), ) - .mutation(({ input }) => { + .mutation(async ({ input }) => { const entry = MCP_CONNECTOR_CATALOG.find((e) => e.key === input.key); if (!entry) throw new Error(`Unknown connector: ${input.key}`); if (entry.transport !== "stdio" || !entry.command) { @@ -2282,14 +2324,16 @@ export const appRouter = router({ ? writeMcpSecretFile(input.workspaceId, `${entry.key}-${field.key}`, value) : value; } - return getDb().createMcpServer({ - workspaceId: input.workspaceId, - name: entry.name, - transport: "stdio", - command: entry.command, - args: entry.args, - env, - }); + return toClientSafeMcpServer( + await getDb().createMcpServer({ + workspaceId: input.workspaceId, + name: entry.name, + transport: "stdio", + command: entry.command, + args: entry.args, + env, + }), + ); }), delete: protectedProcedure .input(z.object({ id: z.string() })) @@ -2855,15 +2899,17 @@ export const appRouter = router({ injectIntoPrompts: z.boolean().optional(), }), ) - .mutation(({ input }) => - getDb().upsertKnowledgeBaseConfig({ - workspaceId: input.workspaceId, - vaultPath: input.vaultPath, - obsidianRestUrl: input.obsidianRestUrl ?? null, - obsidianApiKey: input.obsidianApiKey ?? null, - docsAgentEnabled: input.docsAgentEnabled, - injectIntoPrompts: input.injectIntoPrompts, - }), + .mutation(async ({ input }) => + toClientSafeKnowledgeBaseConfig( + await getDb().upsertKnowledgeBaseConfig({ + workspaceId: input.workspaceId, + vaultPath: input.vaultPath, + obsidianRestUrl: input.obsidianRestUrl ?? null, + obsidianApiKey: input.obsidianApiKey ?? null, + docsAgentEnabled: input.docsAgentEnabled, + injectIntoPrompts: input.injectIntoPrompts, + }), + ), ), documents: workspaceProcedure .input(z.object({ workspaceId: z.string() })) diff --git a/apps/web/src/components/workspace-settings-panel.tsx b/apps/web/src/components/workspace-settings-panel.tsx index 87e9260..c033eaa 100644 --- a/apps/web/src/components/workspace-settings-panel.tsx +++ b/apps/web/src/components/workspace-settings-panel.tsx @@ -25,12 +25,12 @@ import { } from "lucide-react"; import Link from "next/link"; import { useEffect, useMemo, useState } from "react"; +import { ModelParametersDialog } from "@/components/model-parameters-dialog"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Checkbox } from "@/components/ui/checkbox"; import { Input } from "@/components/ui/input"; import { Switch } from "@/components/ui/switch"; -import { ModelParametersDialog } from "@/components/model-parameters-dialog"; import { Textarea } from "@/components/ui/textarea"; import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"; import { @@ -48,7 +48,6 @@ import { DEFAULT_CHAT_TOOL_POLICY, type ModelCapabilities, type ModelInstallationClientSummary, - type ModelInstallationSummary, type OpenRouterModel, type ProbedModelProvider, trpcClient, @@ -103,10 +102,7 @@ function CapabilityBadges({ capabilities }: { capabilities?: ModelCapabilities } @@ -334,8 +330,8 @@ function CliProviderCard({ {status === "not_installed" && (

- {kind === "claude_cli" ? "claude" : "codex"} isn't installed (or not on PATH) on - the server host. + {kind === "claude_cli" ? "claude" : "codex"} isn't installed (or not on PATH) on the + server host.

)} @@ -428,11 +424,15 @@ function InstalledProviderCard({ provider: ModelInstallationClientSummary; modelCapabilitiesByLabel: Map; setModelEnabled: UseMutationResult< - ModelInstallationSummary, + ModelInstallationClientSummary, Error, { id: string; modelId: string; enabled: boolean } >; - removeModel: UseMutationResult; + removeModel: UseMutationResult< + ModelInstallationClientSummary | null, + Error, + { id: string; modelId: string } + >; removeProvider: UseMutationResult; invalidateModelQueries: () => void; }) { @@ -581,7 +581,8 @@ function OpenRouterProviderCard({ const [selectedModelIds, setSelectedModelIds] = useState>(new Set()); const fetchModels = useMutation({ - mutationFn: () => trpcClient.models.listOpenRouterModels.query({ apiKey: apiKey.trim() || undefined }), + mutationFn: () => + trpcClient.models.listOpenRouterModels.query({ apiKey: apiKey.trim() || undefined }), onSuccess: (result) => { setModels(result); setSelectedModelIds(new Set(result.map((model) => model.id))); @@ -1280,9 +1281,7 @@ export function WorkspaceSettingsPanel({

Installed

{installedProvidersQuery.data?.length === 0 && ( -

- No custom providers installed yet. -

+

No custom providers installed yet.

)}
{installedProvidersQuery.data?.map((provider) => ( @@ -1388,9 +1387,7 @@ export function WorkspaceSettingsPanel({
{probeProvider.isError && ( -

- {(probeProvider.error as Error).message} -

+

{(probeProvider.error as Error).message}

)} {installProvider.isError && (

@@ -1437,9 +1434,9 @@ export function WorkspaceSettingsPanel({

Server URL

- Point this device at a different Nyxel server — a LAN IP at home, a Tailscale/ - ngrok tunnel, or a custom domain. Only affects this browser; other devices keep - their own setting. + Point this device at a different Nyxel server — a LAN IP at home, a Tailscale/ ngrok + tunnel, or a custom domain. Only affects this browser; other devices keep their own + setting.

Marketplace

- Optional NyxelOS features. Installing one adds it to the sidebar outside the - normal workspace navigation. + Optional NyxelOS features. Installing one adds it to the sidebar outside the normal + workspace navigation.

{extensionCatalogQuery.isLoading ? ( @@ -1521,9 +1518,7 @@ export function WorkspaceSettingsPanel({ ) : (
{(extensionCatalogQuery.data ?? []).map((entry) => { - const installed = installedExtensionsQuery.data?.find( - (e) => e.key === entry.key, - ); + const installed = installedExtensionsQuery.data?.find((e) => e.key === entry.key); return (
diff --git a/apps/web/src/lib/trpc.ts b/apps/web/src/lib/trpc.ts index e38a5d8..6d4c594 100644 --- a/apps/web/src/lib/trpc.ts +++ b/apps/web/src/lib/trpc.ts @@ -941,6 +941,11 @@ export type McpServerSummary = { url: string | null; enabled: boolean; createdAt: Date; + /** Neither the raw stdio env vars nor the OAuth session ever leave the + * server (SECURITY_AUDIT.md SEC-01) — these booleans are all the UI needs + * to show "configured"/"not configured". */ + hasEnv: boolean; + hasOAuthState: boolean; }; export type McpToolSummary = { @@ -1055,11 +1060,14 @@ export type SeoBlogPostSummary = { updatedAt: Date; }; +// The raw obsidianApiKey never leaves the server (SECURITY_AUDIT.md SEC-01) — +// both knowledgeBase.overview and knowledgeBase.updateConfig return +// `obsidianApiKeySet` instead; the UI only needs "configured"/"not configured". export type KnowledgeBaseConfigSummary = { workspaceId: string; vaultPath: string; obsidianRestUrl: string | null; - obsidianApiKey: string | null; + obsidianApiKeySet: boolean; docsAgentEnabled: boolean; injectIntoPrompts: boolean; lastDocsSyncAt: Date | null; @@ -1069,7 +1077,6 @@ export type KnowledgeBaseConfigSummary = { export type KnowledgeBaseOverview = { config: KnowledgeBaseConfigSummary & { - obsidianApiKeySet: boolean; absoluteVaultPath: string; }; stats: { @@ -1243,7 +1250,7 @@ type NyxelTrpcClient = { baseUrl: string; apiKey?: string; modelIds?: string[]; - }): Promise; + }): Promise; }; listOpenRouterModels: { query(input?: { apiKey?: string }): Promise; @@ -1254,7 +1261,7 @@ type NyxelTrpcClient = { label?: string; apiKey: string; modelIds?: string[]; - }): Promise; + }): Promise; }; deleteInstallation: { mutate(input: { id: string }): Promise; @@ -1264,13 +1271,16 @@ type NyxelTrpcClient = { id: string; modelId: string; enabled: boolean; - }): Promise; + }): Promise; }; removeModelFromInstallation: { - mutate(input: { id: string; modelId: string }): Promise; + mutate(input: { + id: string; + modelId: string; + }): Promise; }; addModelToInstallation: { - mutate(input: { id: string; modelId: string }): Promise; + mutate(input: { id: string; modelId: string }): Promise; }; listCatalogForInstallation: { query(input: { id: string }): Promise; @@ -1293,13 +1303,16 @@ type NyxelTrpcClient = { providerKind: CliProviderKind; label: string; modelIds: string[]; - }): Promise; + }): Promise; }; scanImportSources: { query(): Promise; }; importSource: { - mutate(input: { workspaceId: string; sourceId: string }): Promise; + mutate(input: { + workspaceId: string; + sourceId: string; + }): Promise; }; getParameters: { query(input: { workspaceId: string; modelId: string }): Promise; diff --git a/package.json b/package.json index bc93c63..90beb0f 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "dev": "turbo run dev", "build": "turbo run build", "typecheck": "turbo run typecheck", + "test": "bun test", "lint": "biome check .", "lint:fix": "biome check --write .", "format": "biome format --write .", diff --git a/packages/db/drizzle/pg/0042_sad_emma_frost.sql b/packages/db/drizzle/pg/0042_sad_emma_frost.sql new file mode 100644 index 0000000..ef2dc9a --- /dev/null +++ b/packages/db/drizzle/pg/0042_sad_emma_frost.sql @@ -0,0 +1,2 @@ +ALTER TABLE "mcp_server" ALTER COLUMN "env" SET DATA TYPE text USING "env"::text;--> statement-breakpoint +ALTER TABLE "mcp_server" ALTER COLUMN "oauth_state" SET DATA TYPE text USING "oauth_state"::text; \ No newline at end of file diff --git a/packages/db/drizzle/pg/0043_cooing_starjammers.sql b/packages/db/drizzle/pg/0043_cooing_starjammers.sql new file mode 100644 index 0000000..c564fab --- /dev/null +++ b/packages/db/drizzle/pg/0043_cooing_starjammers.sql @@ -0,0 +1,4 @@ +ALTER TABLE "agent_run" ADD COLUMN "worker_id" text;--> statement-breakpoint +ALTER TABLE "agent_run" ADD COLUMN "heartbeat_at" timestamp;--> statement-breakpoint +ALTER TABLE "agent_run" ADD COLUMN "lease_until" timestamp;--> statement-breakpoint +ALTER TABLE "agent_run" ADD COLUMN "cancel_requested_at" timestamp; \ No newline at end of file diff --git a/packages/db/drizzle/pg/meta/0042_snapshot.json b/packages/db/drizzle/pg/meta/0042_snapshot.json new file mode 100644 index 0000000..7b468ca --- /dev/null +++ b/packages/db/drizzle/pg/meta/0042_snapshot.json @@ -0,0 +1,4908 @@ +{ + "id": "e81a749d-19c7-4b31-86b6-00b7a46843f4", + "prevId": "2d1f0359-c2db-497c-80c5-502fa7720485", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.agent": { + "name": "agent", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "system_prompt": { + "name": "system_prompt", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "goal_template": { + "name": "goal_template", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "model_id": { + "name": "model_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "autonomy_level": { + "name": "autonomy_level", + "type": "agent_autonomy_level", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'chat'" + }, + "mcp_server_ids": { + "name": "mcp_server_ids", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "tool_ids": { + "name": "tool_ids", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "skill_ids": { + "name": "skill_ids", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "mcp_tool_filter": { + "name": "mcp_tool_filter", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "delegate_agent_ids": { + "name": "delegate_agent_ids", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "autonomy_budget": { + "name": "autonomy_budget", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "agent_workspace_id_workspace_id_fk": { + "name": "agent_workspace_id_workspace_id_fk", + "tableFrom": "agent", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.agent_run": { + "name": "agent_run", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "task_id": { + "name": "task_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "agent_id": { + "name": "agent_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "chat_id": { + "name": "chat_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "automation_id": { + "name": "automation_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "trigger": { + "name": "trigger", + "type": "agent_run_trigger", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "model_id": { + "name": "model_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "step_count": { + "name": "step_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "status": { + "name": "status", + "type": "agent_run_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "final_output": { + "name": "final_output", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "agent_run_workspace_id_workspace_id_fk": { + "name": "agent_run_workspace_id_workspace_id_fk", + "tableFrom": "agent_run", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "agent_run_task_id_task_id_fk": { + "name": "agent_run_task_id_task_id_fk", + "tableFrom": "agent_run", + "tableTo": "task", + "columnsFrom": [ + "task_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "agent_run_agent_id_agent_id_fk": { + "name": "agent_run_agent_id_agent_id_fk", + "tableFrom": "agent_run", + "tableTo": "agent", + "columnsFrom": [ + "agent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "agent_run_chat_id_chat_id_fk": { + "name": "agent_run_chat_id_chat_id_fk", + "tableFrom": "agent_run", + "tableTo": "chat", + "columnsFrom": [ + "chat_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "agent_run_automation_id_automation_id_fk": { + "name": "agent_run_automation_id_automation_id_fk", + "tableFrom": "agent_run", + "tableTo": "automation", + "columnsFrom": [ + "automation_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.approval_request": { + "name": "approval_request", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "agent_id": { + "name": "agent_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "chat_id": { + "name": "chat_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "automation_id": { + "name": "automation_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "task_id": { + "name": "task_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "agent_run_id": { + "name": "agent_run_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "kind": { + "name": "kind", + "type": "approval_kind", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "skill_id": { + "name": "skill_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tool_id": { + "name": "tool_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mcp_server_id": { + "name": "mcp_server_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mcp_tool_name": { + "name": "mcp_tool_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tool_label": { + "name": "tool_label", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "input": { + "name": "input", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "approval_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "result_output": { + "name": "result_output", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "resolved_at": { + "name": "resolved_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "risk_level": { + "name": "risk_level", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "affected_resources": { + "name": "affected_resources", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "diff_preview": { + "name": "diff_preview", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "approval_request_workspace_id_workspace_id_fk": { + "name": "approval_request_workspace_id_workspace_id_fk", + "tableFrom": "approval_request", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "approval_request_agent_id_agent_id_fk": { + "name": "approval_request_agent_id_agent_id_fk", + "tableFrom": "approval_request", + "tableTo": "agent", + "columnsFrom": [ + "agent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "approval_request_chat_id_chat_id_fk": { + "name": "approval_request_chat_id_chat_id_fk", + "tableFrom": "approval_request", + "tableTo": "chat", + "columnsFrom": [ + "chat_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "approval_request_automation_id_automation_id_fk": { + "name": "approval_request_automation_id_automation_id_fk", + "tableFrom": "approval_request", + "tableTo": "automation", + "columnsFrom": [ + "automation_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "approval_request_task_id_task_id_fk": { + "name": "approval_request_task_id_task_id_fk", + "tableFrom": "approval_request", + "tableTo": "task", + "columnsFrom": [ + "task_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "approval_request_agent_run_id_agent_run_id_fk": { + "name": "approval_request_agent_run_id_agent_run_id_fk", + "tableFrom": "approval_request", + "tableTo": "agent_run", + "columnsFrom": [ + "agent_run_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.artifact": { + "name": "artifact", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "artifact_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "task_id": { + "name": "task_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "agent_run_id": { + "name": "agent_run_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "agent_id": { + "name": "agent_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "artifact_workspace_id_workspace_id_fk": { + "name": "artifact_workspace_id_workspace_id_fk", + "tableFrom": "artifact", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "artifact_task_id_task_id_fk": { + "name": "artifact_task_id_task_id_fk", + "tableFrom": "artifact", + "tableTo": "task", + "columnsFrom": [ + "task_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "artifact_agent_run_id_agent_run_id_fk": { + "name": "artifact_agent_run_id_agent_run_id_fk", + "tableFrom": "artifact", + "tableTo": "agent_run", + "columnsFrom": [ + "agent_run_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "artifact_agent_id_agent_id_fk": { + "name": "artifact_agent_id_agent_id_fk", + "tableFrom": "artifact", + "tableTo": "agent", + "columnsFrom": [ + "agent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.audit_log": { + "name": "audit_log", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "agent_id": { + "name": "agent_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "chat_id": { + "name": "chat_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "automation_id": { + "name": "automation_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "actor": { + "name": "actor", + "type": "audit_actor", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "tool_label": { + "name": "tool_label", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "input": { + "name": "input", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "output": { + "name": "output", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "audit_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "input_hash": { + "name": "input_hash", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "permission_snapshot": { + "name": "permission_snapshot", + "type": "jsonb", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "audit_log_workspace_id_workspace_id_fk": { + "name": "audit_log_workspace_id_workspace_id_fk", + "tableFrom": "audit_log", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "audit_log_agent_id_agent_id_fk": { + "name": "audit_log_agent_id_agent_id_fk", + "tableFrom": "audit_log", + "tableTo": "agent", + "columnsFrom": [ + "agent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "audit_log_chat_id_chat_id_fk": { + "name": "audit_log_chat_id_chat_id_fk", + "tableFrom": "audit_log", + "tableTo": "chat", + "columnsFrom": [ + "chat_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "audit_log_automation_id_automation_id_fk": { + "name": "audit_log_automation_id_automation_id_fk", + "tableFrom": "audit_log", + "tableTo": "automation", + "columnsFrom": [ + "automation_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.automation": { + "name": "automation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "agent_id": { + "name": "agent_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "target_kind": { + "name": "target_kind", + "type": "automation_target_kind", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'agent'" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "trigger_type": { + "name": "trigger_type", + "type": "automation_trigger_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'cron'" + }, + "cron_expression": { + "name": "cron_expression", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "watch_path": { + "name": "watch_path", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "watch_glob": { + "name": "watch_glob", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_watch_check_at": { + "name": "last_watch_check_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "prompt": { + "name": "prompt", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "last_run_at": { + "name": "last_run_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "next_run_at": { + "name": "next_run_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_run_status": { + "name": "last_run_status", + "type": "automation_run_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "last_error_message": { + "name": "last_error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "automation_workspace_id_workspace_id_fk": { + "name": "automation_workspace_id_workspace_id_fk", + "tableFrom": "automation", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "automation_agent_id_agent_id_fk": { + "name": "automation_agent_id_agent_id_fk", + "tableFrom": "automation", + "tableTo": "agent", + "columnsFrom": [ + "agent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "automation_workflow_id_workflow_id_fk": { + "name": "automation_workflow_id_workflow_id_fk", + "tableFrom": "automation", + "tableTo": "workflow", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.chat": { + "name": "chat", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "working_directory": { + "name": "working_directory", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "agent_id": { + "name": "agent_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'New chat'" + }, + "model_id": { + "name": "model_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "archived_at": { + "name": "archived_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "pinned_at": { + "name": "pinned_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "share_id": { + "name": "share_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "shared_at": { + "name": "shared_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "tool_mode": { + "name": "tool_mode", + "type": "chat_tool_mode", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'default'" + }, + "tool_policy": { + "name": "tool_policy", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{\"mode\":\"default\",\"approveFileWrites\":true,\"approveFileDeletes\":true,\"approveCustomCode\":true,\"approveMcpTools\":true}'::jsonb" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "chat_workspace_id_workspace_id_fk": { + "name": "chat_workspace_id_workspace_id_fk", + "tableFrom": "chat", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "chat_agent_id_agent_id_fk": { + "name": "chat_agent_id_agent_id_fk", + "tableFrom": "chat", + "tableTo": "agent", + "columnsFrom": [ + "agent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "chat_project_id_project_id_fk": { + "name": "chat_project_id_project_id_fk", + "tableFrom": "chat", + "tableTo": "project", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "chat_share_id_unique": { + "name": "chat_share_id_unique", + "nullsNotDistinct": false, + "columns": [ + "share_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.extension": { + "name": "extension", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "config": { + "name": "config", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "installed_at": { + "name": "installed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "extension_workspace_id_workspace_id_fk": { + "name": "extension_workspace_id_workspace_id_fk", + "tableFrom": "extension", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.goal": { + "name": "goal", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "goal_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'active'" + }, + "priority": { + "name": "priority", + "type": "task_priority", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'normal'" + }, + "default_agent_id": { + "name": "default_agent_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "success_criteria": { + "name": "success_criteria", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "orchestration_enabled": { + "name": "orchestration_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "next_review_at": { + "name": "next_review_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_reviewed_at": { + "name": "last_reviewed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "blocked_reason": { + "name": "blocked_reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "plan_generated_at": { + "name": "plan_generated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "goal_workspace_id_workspace_id_fk": { + "name": "goal_workspace_id_workspace_id_fk", + "tableFrom": "goal", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "goal_default_agent_id_agent_id_fk": { + "name": "goal_default_agent_id_agent_id_fk", + "tableFrom": "goal", + "tableTo": "agent", + "columnsFrom": [ + "default_agent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.goal_milestone": { + "name": "goal_milestone", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "goal_id": { + "name": "goal_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "goal_milestone_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "goal_milestone_goal_id_goal_id_fk": { + "name": "goal_milestone_goal_id_goal_id_fk", + "tableFrom": "goal_milestone", + "tableTo": "goal", + "columnsFrom": [ + "goal_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "goal_milestone_workspace_id_workspace_id_fk": { + "name": "goal_milestone_workspace_id_workspace_id_fk", + "tableFrom": "goal_milestone", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.goal_progress_event": { + "name": "goal_progress_event", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "goal_id": { + "name": "goal_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "goal_event_kind", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "message": { + "name": "message", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "payload": { + "name": "payload", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "goal_progress_event_goal_id_goal_id_fk": { + "name": "goal_progress_event_goal_id_goal_id_fk", + "tableFrom": "goal_progress_event", + "tableTo": "goal", + "columnsFrom": [ + "goal_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "goal_progress_event_workspace_id_workspace_id_fk": { + "name": "goal_progress_event_workspace_id_workspace_id_fk", + "tableFrom": "goal_progress_event", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.installation": { + "name": "installation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "mode": { + "name": "mode", + "type": "installation_mode", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "owner_user_id": { + "name": "owner_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "primary_workspace_id": { + "name": "primary_workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "app_url": { + "name": "app_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "installation_owner_user_id_user_id_fk": { + "name": "installation_owner_user_id_user_id_fk", + "tableFrom": "installation", + "tableTo": "user", + "columnsFrom": [ + "owner_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.knowledge_base_config": { + "name": "knowledge_base_config", + "schema": "", + "columns": { + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "vault_path": { + "name": "vault_path", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'knowledge-base'" + }, + "obsidian_rest_url": { + "name": "obsidian_rest_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "obsidian_api_key": { + "name": "obsidian_api_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "docs_agent_enabled": { + "name": "docs_agent_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "inject_into_prompts": { + "name": "inject_into_prompts", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "last_docs_sync_at": { + "name": "last_docs_sync_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_docs_sync_error": { + "name": "last_docs_sync_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "knowledge_base_config_workspace_id_workspace_id_fk": { + "name": "knowledge_base_config_workspace_id_workspace_id_fk", + "tableFrom": "knowledge_base_config", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.library_file": { + "name": "library_file", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "folder_id": { + "name": "folder_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "mime_type": { + "name": "mime_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "size_bytes": { + "name": "size_bytes", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "library_item_kind", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'other'" + }, + "storage_key": { + "name": "storage_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "library_file_workspace_id_workspace_id_fk": { + "name": "library_file_workspace_id_workspace_id_fk", + "tableFrom": "library_file", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "library_file_folder_id_library_folder_id_fk": { + "name": "library_file_folder_id_library_folder_id_fk", + "tableFrom": "library_file", + "tableTo": "library_folder", + "columnsFrom": [ + "folder_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.library_folder": { + "name": "library_folder", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "parent_id": { + "name": "parent_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "library_folder_workspace_id_workspace_id_fk": { + "name": "library_folder_workspace_id_workspace_id_fk", + "tableFrom": "library_folder", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mcp_server": { + "name": "mcp_server", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "transport": { + "name": "transport", + "type": "mcp_transport", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "args": { + "name": "args", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "oauth_state": { + "name": "oauth_state", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "mcp_server_workspace_id_workspace_id_fk": { + "name": "mcp_server_workspace_id_workspace_id_fk", + "tableFrom": "mcp_server", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.memory_entry": { + "name": "memory_entry", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "memory_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "memory_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "confidence": { + "name": "confidence", + "type": "double precision", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "created_by_agent_id": { + "name": "created_by_agent_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "memory_entry_workspace_id_workspace_id_fk": { + "name": "memory_entry_workspace_id_workspace_id_fk", + "tableFrom": "memory_entry", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "memory_entry_created_by_agent_id_agent_id_fk": { + "name": "memory_entry_created_by_agent_id_agent_id_fk", + "tableFrom": "memory_entry", + "tableTo": "agent", + "columnsFrom": [ + "created_by_agent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.message": { + "name": "message", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "chat_id": { + "name": "chat_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "message_role", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "model_id": { + "name": "model_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "input_tokens": { + "name": "input_tokens", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "output_tokens": { + "name": "output_tokens", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "reasoning_tokens": { + "name": "reasoning_tokens", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "cache_read_tokens": { + "name": "cache_read_tokens", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "total_tokens": { + "name": "total_tokens", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "cost_micros": { + "name": "cost_micros", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "duration_ms": { + "name": "duration_ms", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "thinking_ms": { + "name": "thinking_ms", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "line_count": { + "name": "line_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "code_line_count": { + "name": "code_line_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "code_block_count": { + "name": "code_block_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "message_chat_id_chat_id_fk": { + "name": "message_chat_id_chat_id_fk", + "tableFrom": "message", + "tableTo": "chat", + "columnsFrom": [ + "chat_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.model_installation": { + "name": "model_installation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "label": { + "name": "label", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider_kind": { + "name": "provider_kind", + "type": "model_provider_kind", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "base_url": { + "name": "base_url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "api_key": { + "name": "api_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "model_ids": { + "name": "model_ids", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "disabled_model_ids": { + "name": "disabled_model_ids", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "model_installation_workspace_id_workspace_id_fk": { + "name": "model_installation_workspace_id_workspace_id_fk", + "tableFrom": "model_installation", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.model_parameter": { + "name": "model_parameter", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "model_id": { + "name": "model_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "custom_name": { + "name": "custom_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "custom_instructions": { + "name": "custom_instructions", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "max_output_tokens": { + "name": "max_output_tokens", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "temperature": { + "name": "temperature", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "top_p": { + "name": "top_p", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "frequency_penalty": { + "name": "frequency_penalty", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "presence_penalty": { + "name": "presence_penalty", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "stop_sequences": { + "name": "stop_sequences", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "reasoning_effort": { + "name": "reasoning_effort", + "type": "model_reasoning_effort", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "model_parameter_workspace_model_idx": { + "name": "model_parameter_workspace_model_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "model_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "model_parameter_workspace_id_workspace_id_fk": { + "name": "model_parameter_workspace_id_workspace_id_fk", + "tableFrom": "model_parameter", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.nyxel_event": { + "name": "nyxel_event", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "nyxel_event_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "entity_type": { + "name": "entity_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "entity_id": { + "name": "entity_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "payload": { + "name": "payload", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "nyxel_event_workspace_id_workspace_id_fk": { + "name": "nyxel_event_workspace_id_workspace_id_fk", + "tableFrom": "nyxel_event", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.plugin": { + "name": "plugin", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "version": { + "name": "version", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "author": { + "name": "author", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "homepage": { + "name": "homepage", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "repo_url": { + "name": "repo_url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "manifest": { + "name": "manifest", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "skill_slugs": { + "name": "skill_slugs", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "agent_defs": { + "name": "agent_defs", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "file_count": { + "name": "file_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "install_dir": { + "name": "install_dir", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "ref": { + "name": "ref", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "resolved_sha": { + "name": "resolved_sha", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ref_pinned": { + "name": "ref_pinned", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "risk_findings": { + "name": "risk_findings", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "plugin_workspace_id_workspace_id_fk": { + "name": "plugin_workspace_id_workspace_id_fk", + "tableFrom": "plugin", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project": { + "name": "project", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "color": { + "name": "color", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'gray'" + }, + "icon": { + "name": "icon", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'folder'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "project_workspace_id_workspace_id_fk": { + "name": "project_workspace_id_workspace_id_fk", + "tableFrom": "project", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.push_subscription": { + "name": "push_subscription", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "endpoint": { + "name": "endpoint", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "p256dh": { + "name": "p256dh", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "auth": { + "name": "auth", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "push_subscription_user_id_user_id_fk": { + "name": "push_subscription_user_id_user_id_fk", + "tableFrom": "push_subscription", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "push_subscription_endpoint_unique": { + "name": "push_subscription_endpoint_unique", + "nullsNotDistinct": false, + "columns": [ + "endpoint" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.seo_analysis_run": { + "name": "seo_analysis_run", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "seo_project_id": { + "name": "seo_project_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "seo_analysis_run_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'running'" + }, + "score": { + "name": "score", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "pages_scanned": { + "name": "pages_scanned", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "summary": { + "name": "summary", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "seo_analysis_run_seo_project_id_seo_project_id_fk": { + "name": "seo_analysis_run_seo_project_id_seo_project_id_fk", + "tableFrom": "seo_analysis_run", + "tableTo": "seo_project", + "columnsFrom": [ + "seo_project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "seo_analysis_run_workspace_id_workspace_id_fk": { + "name": "seo_analysis_run_workspace_id_workspace_id_fk", + "tableFrom": "seo_analysis_run", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.seo_blog_post": { + "name": "seo_blog_post", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "seo_project_id": { + "name": "seo_project_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "keyword": { + "name": "keyword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "file_path": { + "name": "file_path", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "seo_blog_post_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'suggested'" + }, + "task_id": { + "name": "task_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "seo_blog_post_seo_project_id_seo_project_id_fk": { + "name": "seo_blog_post_seo_project_id_seo_project_id_fk", + "tableFrom": "seo_blog_post", + "tableTo": "seo_project", + "columnsFrom": [ + "seo_project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "seo_blog_post_workspace_id_workspace_id_fk": { + "name": "seo_blog_post_workspace_id_workspace_id_fk", + "tableFrom": "seo_blog_post", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "seo_blog_post_task_id_task_id_fk": { + "name": "seo_blog_post_task_id_task_id_fk", + "tableFrom": "seo_blog_post", + "tableTo": "task", + "columnsFrom": [ + "task_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.seo_finding": { + "name": "seo_finding", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "run_id": { + "name": "run_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "seo_project_id": { + "name": "seo_project_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "category": { + "name": "category", + "type": "seo_finding_category", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "severity": { + "name": "severity", + "type": "seo_finding_severity", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "recommendation": { + "name": "recommendation", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "location": { + "name": "location", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "resolved": { + "name": "resolved", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "seo_finding_run_id_seo_analysis_run_id_fk": { + "name": "seo_finding_run_id_seo_analysis_run_id_fk", + "tableFrom": "seo_finding", + "tableTo": "seo_analysis_run", + "columnsFrom": [ + "run_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "seo_finding_seo_project_id_seo_project_id_fk": { + "name": "seo_finding_seo_project_id_seo_project_id_fk", + "tableFrom": "seo_finding", + "tableTo": "seo_project", + "columnsFrom": [ + "seo_project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.seo_project": { + "name": "seo_project", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "extension_id": { + "name": "extension_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "domain": { + "name": "domain", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "repo_path": { + "name": "repo_path", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "blog_config": { + "name": "blog_config", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "fixer_agent_id": { + "name": "fixer_agent_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "reanalyze_cron_expression": { + "name": "reanalyze_cron_expression", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "next_reanalyze_at": { + "name": "next_reanalyze_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_reanalyze_at": { + "name": "last_reanalyze_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "seo_project_workspace_id_workspace_id_fk": { + "name": "seo_project_workspace_id_workspace_id_fk", + "tableFrom": "seo_project", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "seo_project_extension_id_extension_id_fk": { + "name": "seo_project_extension_id_extension_id_fk", + "tableFrom": "seo_project", + "tableTo": "extension", + "columnsFrom": [ + "extension_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "seo_project_fixer_agent_id_agent_id_fk": { + "name": "seo_project_fixer_agent_id_agent_id_fk", + "tableFrom": "seo_project", + "tableTo": "agent", + "columnsFrom": [ + "fixer_agent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.task": { + "name": "task", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "parent_task_id": { + "name": "parent_task_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_chat_id": { + "name": "source_chat_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_by_agent_id": { + "name": "created_by_agent_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "assigned_agent_id": { + "name": "assigned_agent_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "goal_id": { + "name": "goal_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "goal_milestone_id": { + "name": "goal_milestone_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "instruction": { + "name": "instruction", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "model_id": { + "name": "model_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "task_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "priority": { + "name": "priority", + "type": "task_priority", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'normal'" + }, + "requires_approval": { + "name": "requires_approval", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "input": { + "name": "input", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "plan": { + "name": "plan", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "handoff": { + "name": "handoff", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "result_summary": { + "name": "result_summary", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "task_workspace_id_workspace_id_fk": { + "name": "task_workspace_id_workspace_id_fk", + "tableFrom": "task", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "task_source_chat_id_chat_id_fk": { + "name": "task_source_chat_id_chat_id_fk", + "tableFrom": "task", + "tableTo": "chat", + "columnsFrom": [ + "source_chat_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "task_created_by_agent_id_agent_id_fk": { + "name": "task_created_by_agent_id_agent_id_fk", + "tableFrom": "task", + "tableTo": "agent", + "columnsFrom": [ + "created_by_agent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "task_assigned_agent_id_agent_id_fk": { + "name": "task_assigned_agent_id_agent_id_fk", + "tableFrom": "task", + "tableTo": "agent", + "columnsFrom": [ + "assigned_agent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "task_goal_id_goal_id_fk": { + "name": "task_goal_id_goal_id_fk", + "tableFrom": "task", + "tableTo": "goal", + "columnsFrom": [ + "goal_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "task_goal_milestone_id_goal_milestone_id_fk": { + "name": "task_goal_milestone_id_goal_milestone_id_fk", + "tableFrom": "task", + "tableTo": "goal_milestone", + "columnsFrom": [ + "goal_milestone_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.task_event": { + "name": "task_event", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "task_id": { + "name": "task_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "agent_run_id": { + "name": "agent_run_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "agent_id": { + "name": "agent_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "kind": { + "name": "kind", + "type": "task_event_kind", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "message": { + "name": "message", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "payload": { + "name": "payload", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "task_event_task_id_task_id_fk": { + "name": "task_event_task_id_task_id_fk", + "tableFrom": "task_event", + "tableTo": "task", + "columnsFrom": [ + "task_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "task_event_workspace_id_workspace_id_fk": { + "name": "task_event_workspace_id_workspace_id_fk", + "tableFrom": "task_event", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "task_event_agent_run_id_agent_run_id_fk": { + "name": "task_event_agent_run_id_agent_run_id_fk", + "tableFrom": "task_event", + "tableTo": "agent_run", + "columnsFrom": [ + "agent_run_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "task_event_agent_id_agent_id_fk": { + "name": "task_event_agent_id_agent_id_fk", + "tableFrom": "task_event", + "tableTo": "agent", + "columnsFrom": [ + "agent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.tool": { + "name": "tool", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "config": { + "name": "config", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "sensitive": { + "name": "sensitive", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "builtin": { + "name": "builtin", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "tool_workspace_id_workspace_id_fk": { + "name": "tool_workspace_id_workspace_id_fk", + "tableFrom": "tool", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.video_generation_job": { + "name": "video_generation_job", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "chat_id": { + "name": "chat_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "prompt": { + "name": "prompt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "model": { + "name": "model", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "video_generation_job_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'queued'" + }, + "progress": { + "name": "progress", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "size": { + "name": "size", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "seconds": { + "name": "seconds", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "auto": { + "name": "auto", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "external_job_id": { + "name": "external_job_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "library_file_id": { + "name": "library_file_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "poster_library_file_id": { + "name": "poster_library_file_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "video_generation_job_workspace_id_workspace_id_fk": { + "name": "video_generation_job_workspace_id_workspace_id_fk", + "tableFrom": "video_generation_job", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "video_generation_job_library_file_id_library_file_id_fk": { + "name": "video_generation_job_library_file_id_library_file_id_fk", + "tableFrom": "video_generation_job", + "tableTo": "library_file", + "columnsFrom": [ + "library_file_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "video_generation_job_poster_library_file_id_library_file_id_fk": { + "name": "video_generation_job_poster_library_file_id_library_file_id_fk", + "tableFrom": "video_generation_job", + "tableTo": "library_file", + "columnsFrom": [ + "poster_library_file_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow": { + "name": "workflow", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "definition": { + "name": "definition", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_workspace_id_workspace_id_fk": { + "name": "workflow_workspace_id_workspace_id_fk", + "tableFrom": "workflow", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_run": { + "name": "workflow_run", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "workflow_run_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'queued'" + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_run_workflow_id_workflow_id_fk": { + "name": "workflow_run_workflow_id_workflow_id_fk", + "tableFrom": "workflow_run", + "tableTo": "workflow", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_run_workspace_id_workspace_id_fk": { + "name": "workflow_run_workspace_id_workspace_id_fk", + "tableFrom": "workflow_run", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_run_node": { + "name": "workflow_run_node", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "run_id": { + "name": "run_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "node_id": { + "name": "node_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "workflow_run_node_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'queued'" + }, + "progress": { + "name": "progress", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "library_file_id": { + "name": "library_file_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_run_node_run_id_workflow_run_id_fk": { + "name": "workflow_run_node_run_id_workflow_run_id_fk", + "tableFrom": "workflow_run_node", + "tableTo": "workflow_run", + "columnsFrom": [ + "run_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_run_node_library_file_id_library_file_id_fk": { + "name": "workflow_run_node_library_file_id_library_file_id_fk", + "tableFrom": "workflow_run_node", + "tableTo": "library_file", + "columnsFrom": [ + "library_file_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace": { + "name": "workspace", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "custom_instructions": { + "name": "custom_instructions", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "icon": { + "name": "icon", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "color": { + "name": "color", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "default_model_id": { + "name": "default_model_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "default_autonomy_level": { + "name": "default_autonomy_level", + "type": "agent_autonomy_level", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'assisted'" + }, + "default_tool_policy": { + "name": "default_tool_policy", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workspace_user_id_user_id_fk": { + "name": "workspace_user_id_user_id_fk", + "tableFrom": "workspace", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.account": { + "name": "account", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "account_id": { + "name": "account_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token_expires_at": { + "name": "access_token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "refresh_token_expires_at": { + "name": "refresh_token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "account_user_id_user_id_fk": { + "name": "account_user_id_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session": { + "name": "session", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "session_user_id_user_id_fk": { + "name": "session_user_id_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "session_token_unique": { + "name": "session_token_unique", + "nullsNotDistinct": false, + "columns": [ + "token" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email_verified": { + "name": "email_verified", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_email_unique": { + "name": "user_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.verification": { + "name": "verification", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": { + "public.agent_autonomy_level": { + "name": "agent_autonomy_level", + "schema": "public", + "values": [ + "chat", + "assisted", + "autonomous", + "super_agent" + ] + }, + "public.agent_run_status": { + "name": "agent_run_status", + "schema": "public", + "values": [ + "pending", + "running", + "waiting_approval", + "completed", + "failed", + "cancelled" + ] + }, + "public.agent_run_trigger": { + "name": "agent_run_trigger", + "schema": "public", + "values": [ + "chat", + "task", + "automation", + "delegate", + "extension" + ] + }, + "public.approval_kind": { + "name": "approval_kind", + "schema": "public", + "values": [ + "skill", + "tool", + "mcp" + ] + }, + "public.approval_status": { + "name": "approval_status", + "schema": "public", + "values": [ + "pending", + "approved", + "rejected" + ] + }, + "public.artifact_type": { + "name": "artifact_type", + "schema": "public", + "values": [ + "text", + "markdown", + "code_patch", + "diff", + "file", + "report", + "json", + "image_reference", + "task_result", + "command_output" + ] + }, + "public.audit_actor": { + "name": "audit_actor", + "schema": "public", + "values": [ + "chat", + "automation", + "approval", + "delegate", + "extension", + "goal_orchestrator" + ] + }, + "public.audit_status": { + "name": "audit_status", + "schema": "public", + "values": [ + "success", + "error", + "pending_approval", + "rejected" + ] + }, + "public.automation_run_status": { + "name": "automation_run_status", + "schema": "public", + "values": [ + "success", + "error", + "pending_approval" + ] + }, + "public.automation_target_kind": { + "name": "automation_target_kind", + "schema": "public", + "values": [ + "agent", + "workflow" + ] + }, + "public.automation_trigger_type": { + "name": "automation_trigger_type", + "schema": "public", + "values": [ + "cron", + "file_watch" + ] + }, + "public.chat_tool_mode": { + "name": "chat_tool_mode", + "schema": "public", + "values": [ + "default", + "automatic", + "auto" + ] + }, + "public.goal_event_kind": { + "name": "goal_event_kind", + "schema": "public", + "values": [ + "created", + "status_changed", + "milestone_added", + "milestone_status_changed", + "plan_created", + "task_created", + "task_status_changed", + "review" + ] + }, + "public.goal_milestone_status": { + "name": "goal_milestone_status", + "schema": "public", + "values": [ + "pending", + "completed" + ] + }, + "public.goal_status": { + "name": "goal_status", + "schema": "public", + "values": [ + "active", + "paused", + "blocked", + "completed", + "archived" + ] + }, + "public.installation_mode": { + "name": "installation_mode", + "schema": "public", + "values": [ + "pc", + "server" + ] + }, + "public.library_item_kind": { + "name": "library_item_kind", + "schema": "public", + "values": [ + "image", + "document", + "video", + "other" + ] + }, + "public.mcp_transport": { + "name": "mcp_transport", + "schema": "public", + "values": [ + "stdio", + "http" + ] + }, + "public.memory_source": { + "name": "memory_source", + "schema": "public", + "values": [ + "user", + "agent", + "automation", + "system" + ] + }, + "public.memory_type": { + "name": "memory_type", + "schema": "public", + "values": [ + "user_preference", + "workspace_fact", + "project_decision", + "agent_observation", + "task_summary", + "file_summary", + "repo_summary", + "long_term_note" + ] + }, + "public.message_role": { + "name": "message_role", + "schema": "public", + "values": [ + "user", + "assistant", + "system", + "tool" + ] + }, + "public.model_provider_kind": { + "name": "model_provider_kind", + "schema": "public", + "values": [ + "anthropic", + "openai", + "openrouter", + "openai_compatible", + "claude_cli", + "codex_cli" + ] + }, + "public.model_reasoning_effort": { + "name": "model_reasoning_effort", + "schema": "public", + "values": [ + "low", + "medium", + "high" + ] + }, + "public.nyxel_event_type": { + "name": "nyxel_event_type", + "schema": "public", + "values": [ + "agent.run.started", + "agent.run.completed", + "agent.run.failed", + "approval.created", + "approval.resolved", + "workflow.completed", + "task.failed", + "library.file.created", + "automation.triggered" + ] + }, + "public.seo_analysis_run_status": { + "name": "seo_analysis_run_status", + "schema": "public", + "values": [ + "running", + "completed", + "failed" + ] + }, + "public.seo_blog_post_status": { + "name": "seo_blog_post_status", + "schema": "public", + "values": [ + "suggested", + "generating", + "written", + "failed" + ] + }, + "public.seo_finding_category": { + "name": "seo_finding_category", + "schema": "public", + "values": [ + "seo", + "geo", + "aeo" + ] + }, + "public.seo_finding_severity": { + "name": "seo_finding_severity", + "schema": "public", + "values": [ + "info", + "warning", + "critical" + ] + }, + "public.task_event_kind": { + "name": "task_event_kind", + "schema": "public", + "values": [ + "created", + "planned", + "status_changed", + "assigned", + "delegated", + "tool_called", + "approval_waiting", + "approval_resolved", + "run_started", + "run_finished", + "comment", + "question", + "question_answered", + "completed", + "failed" + ] + }, + "public.task_priority": { + "name": "task_priority", + "schema": "public", + "values": [ + "low", + "normal", + "high", + "urgent" + ] + }, + "public.task_status": { + "name": "task_status", + "schema": "public", + "values": [ + "pending", + "planning", + "ready", + "running", + "blocked", + "waiting_approval", + "completed", + "failed", + "cancelled" + ] + }, + "public.video_generation_job_status": { + "name": "video_generation_job_status", + "schema": "public", + "values": [ + "queued", + "in_progress", + "completed", + "failed" + ] + }, + "public.workflow_run_node_status": { + "name": "workflow_run_node_status", + "schema": "public", + "values": [ + "queued", + "running", + "completed", + "failed", + "skipped" + ] + }, + "public.workflow_run_status": { + "name": "workflow_run_status", + "schema": "public", + "values": [ + "queued", + "running", + "completed", + "failed", + "partial" + ] + } + }, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/packages/db/drizzle/pg/meta/0043_snapshot.json b/packages/db/drizzle/pg/meta/0043_snapshot.json new file mode 100644 index 0000000..7fc3380 --- /dev/null +++ b/packages/db/drizzle/pg/meta/0043_snapshot.json @@ -0,0 +1,4932 @@ +{ + "id": "7530067a-9735-4651-9d58-5c6574be8dd8", + "prevId": "e81a749d-19c7-4b31-86b6-00b7a46843f4", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.agent": { + "name": "agent", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "system_prompt": { + "name": "system_prompt", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "goal_template": { + "name": "goal_template", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "model_id": { + "name": "model_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "autonomy_level": { + "name": "autonomy_level", + "type": "agent_autonomy_level", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'chat'" + }, + "mcp_server_ids": { + "name": "mcp_server_ids", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "tool_ids": { + "name": "tool_ids", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "skill_ids": { + "name": "skill_ids", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "mcp_tool_filter": { + "name": "mcp_tool_filter", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "delegate_agent_ids": { + "name": "delegate_agent_ids", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "autonomy_budget": { + "name": "autonomy_budget", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "agent_workspace_id_workspace_id_fk": { + "name": "agent_workspace_id_workspace_id_fk", + "tableFrom": "agent", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.agent_run": { + "name": "agent_run", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "task_id": { + "name": "task_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "agent_id": { + "name": "agent_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "chat_id": { + "name": "chat_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "automation_id": { + "name": "automation_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "trigger": { + "name": "trigger", + "type": "agent_run_trigger", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "model_id": { + "name": "model_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "step_count": { + "name": "step_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "status": { + "name": "status", + "type": "agent_run_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "final_output": { + "name": "final_output", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "worker_id": { + "name": "worker_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "heartbeat_at": { + "name": "heartbeat_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "lease_until": { + "name": "lease_until", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "cancel_requested_at": { + "name": "cancel_requested_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "agent_run_workspace_id_workspace_id_fk": { + "name": "agent_run_workspace_id_workspace_id_fk", + "tableFrom": "agent_run", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "agent_run_task_id_task_id_fk": { + "name": "agent_run_task_id_task_id_fk", + "tableFrom": "agent_run", + "tableTo": "task", + "columnsFrom": [ + "task_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "agent_run_agent_id_agent_id_fk": { + "name": "agent_run_agent_id_agent_id_fk", + "tableFrom": "agent_run", + "tableTo": "agent", + "columnsFrom": [ + "agent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "agent_run_chat_id_chat_id_fk": { + "name": "agent_run_chat_id_chat_id_fk", + "tableFrom": "agent_run", + "tableTo": "chat", + "columnsFrom": [ + "chat_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "agent_run_automation_id_automation_id_fk": { + "name": "agent_run_automation_id_automation_id_fk", + "tableFrom": "agent_run", + "tableTo": "automation", + "columnsFrom": [ + "automation_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.approval_request": { + "name": "approval_request", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "agent_id": { + "name": "agent_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "chat_id": { + "name": "chat_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "automation_id": { + "name": "automation_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "task_id": { + "name": "task_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "agent_run_id": { + "name": "agent_run_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "kind": { + "name": "kind", + "type": "approval_kind", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "skill_id": { + "name": "skill_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tool_id": { + "name": "tool_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mcp_server_id": { + "name": "mcp_server_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mcp_tool_name": { + "name": "mcp_tool_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tool_label": { + "name": "tool_label", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "input": { + "name": "input", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "approval_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "result_output": { + "name": "result_output", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "resolved_at": { + "name": "resolved_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "risk_level": { + "name": "risk_level", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "affected_resources": { + "name": "affected_resources", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "diff_preview": { + "name": "diff_preview", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "approval_request_workspace_id_workspace_id_fk": { + "name": "approval_request_workspace_id_workspace_id_fk", + "tableFrom": "approval_request", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "approval_request_agent_id_agent_id_fk": { + "name": "approval_request_agent_id_agent_id_fk", + "tableFrom": "approval_request", + "tableTo": "agent", + "columnsFrom": [ + "agent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "approval_request_chat_id_chat_id_fk": { + "name": "approval_request_chat_id_chat_id_fk", + "tableFrom": "approval_request", + "tableTo": "chat", + "columnsFrom": [ + "chat_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "approval_request_automation_id_automation_id_fk": { + "name": "approval_request_automation_id_automation_id_fk", + "tableFrom": "approval_request", + "tableTo": "automation", + "columnsFrom": [ + "automation_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "approval_request_task_id_task_id_fk": { + "name": "approval_request_task_id_task_id_fk", + "tableFrom": "approval_request", + "tableTo": "task", + "columnsFrom": [ + "task_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "approval_request_agent_run_id_agent_run_id_fk": { + "name": "approval_request_agent_run_id_agent_run_id_fk", + "tableFrom": "approval_request", + "tableTo": "agent_run", + "columnsFrom": [ + "agent_run_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.artifact": { + "name": "artifact", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "artifact_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "task_id": { + "name": "task_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "agent_run_id": { + "name": "agent_run_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "agent_id": { + "name": "agent_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "artifact_workspace_id_workspace_id_fk": { + "name": "artifact_workspace_id_workspace_id_fk", + "tableFrom": "artifact", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "artifact_task_id_task_id_fk": { + "name": "artifact_task_id_task_id_fk", + "tableFrom": "artifact", + "tableTo": "task", + "columnsFrom": [ + "task_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "artifact_agent_run_id_agent_run_id_fk": { + "name": "artifact_agent_run_id_agent_run_id_fk", + "tableFrom": "artifact", + "tableTo": "agent_run", + "columnsFrom": [ + "agent_run_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "artifact_agent_id_agent_id_fk": { + "name": "artifact_agent_id_agent_id_fk", + "tableFrom": "artifact", + "tableTo": "agent", + "columnsFrom": [ + "agent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.audit_log": { + "name": "audit_log", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "agent_id": { + "name": "agent_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "chat_id": { + "name": "chat_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "automation_id": { + "name": "automation_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "actor": { + "name": "actor", + "type": "audit_actor", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "tool_label": { + "name": "tool_label", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "input": { + "name": "input", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "output": { + "name": "output", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "audit_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "input_hash": { + "name": "input_hash", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "permission_snapshot": { + "name": "permission_snapshot", + "type": "jsonb", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "audit_log_workspace_id_workspace_id_fk": { + "name": "audit_log_workspace_id_workspace_id_fk", + "tableFrom": "audit_log", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "audit_log_agent_id_agent_id_fk": { + "name": "audit_log_agent_id_agent_id_fk", + "tableFrom": "audit_log", + "tableTo": "agent", + "columnsFrom": [ + "agent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "audit_log_chat_id_chat_id_fk": { + "name": "audit_log_chat_id_chat_id_fk", + "tableFrom": "audit_log", + "tableTo": "chat", + "columnsFrom": [ + "chat_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "audit_log_automation_id_automation_id_fk": { + "name": "audit_log_automation_id_automation_id_fk", + "tableFrom": "audit_log", + "tableTo": "automation", + "columnsFrom": [ + "automation_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.automation": { + "name": "automation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "agent_id": { + "name": "agent_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "target_kind": { + "name": "target_kind", + "type": "automation_target_kind", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'agent'" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "trigger_type": { + "name": "trigger_type", + "type": "automation_trigger_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'cron'" + }, + "cron_expression": { + "name": "cron_expression", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "watch_path": { + "name": "watch_path", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "watch_glob": { + "name": "watch_glob", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_watch_check_at": { + "name": "last_watch_check_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "prompt": { + "name": "prompt", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "last_run_at": { + "name": "last_run_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "next_run_at": { + "name": "next_run_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_run_status": { + "name": "last_run_status", + "type": "automation_run_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "last_error_message": { + "name": "last_error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "automation_workspace_id_workspace_id_fk": { + "name": "automation_workspace_id_workspace_id_fk", + "tableFrom": "automation", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "automation_agent_id_agent_id_fk": { + "name": "automation_agent_id_agent_id_fk", + "tableFrom": "automation", + "tableTo": "agent", + "columnsFrom": [ + "agent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "automation_workflow_id_workflow_id_fk": { + "name": "automation_workflow_id_workflow_id_fk", + "tableFrom": "automation", + "tableTo": "workflow", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.chat": { + "name": "chat", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "working_directory": { + "name": "working_directory", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "agent_id": { + "name": "agent_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'New chat'" + }, + "model_id": { + "name": "model_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "archived_at": { + "name": "archived_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "pinned_at": { + "name": "pinned_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "share_id": { + "name": "share_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "shared_at": { + "name": "shared_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "tool_mode": { + "name": "tool_mode", + "type": "chat_tool_mode", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'default'" + }, + "tool_policy": { + "name": "tool_policy", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{\"mode\":\"default\",\"approveFileWrites\":true,\"approveFileDeletes\":true,\"approveCustomCode\":true,\"approveMcpTools\":true}'::jsonb" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "chat_workspace_id_workspace_id_fk": { + "name": "chat_workspace_id_workspace_id_fk", + "tableFrom": "chat", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "chat_agent_id_agent_id_fk": { + "name": "chat_agent_id_agent_id_fk", + "tableFrom": "chat", + "tableTo": "agent", + "columnsFrom": [ + "agent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "chat_project_id_project_id_fk": { + "name": "chat_project_id_project_id_fk", + "tableFrom": "chat", + "tableTo": "project", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "chat_share_id_unique": { + "name": "chat_share_id_unique", + "nullsNotDistinct": false, + "columns": [ + "share_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.extension": { + "name": "extension", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "config": { + "name": "config", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "installed_at": { + "name": "installed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "extension_workspace_id_workspace_id_fk": { + "name": "extension_workspace_id_workspace_id_fk", + "tableFrom": "extension", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.goal": { + "name": "goal", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "goal_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'active'" + }, + "priority": { + "name": "priority", + "type": "task_priority", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'normal'" + }, + "default_agent_id": { + "name": "default_agent_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "success_criteria": { + "name": "success_criteria", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "orchestration_enabled": { + "name": "orchestration_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "next_review_at": { + "name": "next_review_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_reviewed_at": { + "name": "last_reviewed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "blocked_reason": { + "name": "blocked_reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "plan_generated_at": { + "name": "plan_generated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "goal_workspace_id_workspace_id_fk": { + "name": "goal_workspace_id_workspace_id_fk", + "tableFrom": "goal", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "goal_default_agent_id_agent_id_fk": { + "name": "goal_default_agent_id_agent_id_fk", + "tableFrom": "goal", + "tableTo": "agent", + "columnsFrom": [ + "default_agent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.goal_milestone": { + "name": "goal_milestone", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "goal_id": { + "name": "goal_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "goal_milestone_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "goal_milestone_goal_id_goal_id_fk": { + "name": "goal_milestone_goal_id_goal_id_fk", + "tableFrom": "goal_milestone", + "tableTo": "goal", + "columnsFrom": [ + "goal_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "goal_milestone_workspace_id_workspace_id_fk": { + "name": "goal_milestone_workspace_id_workspace_id_fk", + "tableFrom": "goal_milestone", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.goal_progress_event": { + "name": "goal_progress_event", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "goal_id": { + "name": "goal_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "goal_event_kind", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "message": { + "name": "message", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "payload": { + "name": "payload", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "goal_progress_event_goal_id_goal_id_fk": { + "name": "goal_progress_event_goal_id_goal_id_fk", + "tableFrom": "goal_progress_event", + "tableTo": "goal", + "columnsFrom": [ + "goal_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "goal_progress_event_workspace_id_workspace_id_fk": { + "name": "goal_progress_event_workspace_id_workspace_id_fk", + "tableFrom": "goal_progress_event", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.installation": { + "name": "installation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "mode": { + "name": "mode", + "type": "installation_mode", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "owner_user_id": { + "name": "owner_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "primary_workspace_id": { + "name": "primary_workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "app_url": { + "name": "app_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "installation_owner_user_id_user_id_fk": { + "name": "installation_owner_user_id_user_id_fk", + "tableFrom": "installation", + "tableTo": "user", + "columnsFrom": [ + "owner_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.knowledge_base_config": { + "name": "knowledge_base_config", + "schema": "", + "columns": { + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "vault_path": { + "name": "vault_path", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'knowledge-base'" + }, + "obsidian_rest_url": { + "name": "obsidian_rest_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "obsidian_api_key": { + "name": "obsidian_api_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "docs_agent_enabled": { + "name": "docs_agent_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "inject_into_prompts": { + "name": "inject_into_prompts", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "last_docs_sync_at": { + "name": "last_docs_sync_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_docs_sync_error": { + "name": "last_docs_sync_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "knowledge_base_config_workspace_id_workspace_id_fk": { + "name": "knowledge_base_config_workspace_id_workspace_id_fk", + "tableFrom": "knowledge_base_config", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.library_file": { + "name": "library_file", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "folder_id": { + "name": "folder_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "mime_type": { + "name": "mime_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "size_bytes": { + "name": "size_bytes", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "library_item_kind", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'other'" + }, + "storage_key": { + "name": "storage_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "library_file_workspace_id_workspace_id_fk": { + "name": "library_file_workspace_id_workspace_id_fk", + "tableFrom": "library_file", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "library_file_folder_id_library_folder_id_fk": { + "name": "library_file_folder_id_library_folder_id_fk", + "tableFrom": "library_file", + "tableTo": "library_folder", + "columnsFrom": [ + "folder_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.library_folder": { + "name": "library_folder", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "parent_id": { + "name": "parent_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "library_folder_workspace_id_workspace_id_fk": { + "name": "library_folder_workspace_id_workspace_id_fk", + "tableFrom": "library_folder", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mcp_server": { + "name": "mcp_server", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "transport": { + "name": "transport", + "type": "mcp_transport", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "args": { + "name": "args", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "oauth_state": { + "name": "oauth_state", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "mcp_server_workspace_id_workspace_id_fk": { + "name": "mcp_server_workspace_id_workspace_id_fk", + "tableFrom": "mcp_server", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.memory_entry": { + "name": "memory_entry", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "memory_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "memory_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "confidence": { + "name": "confidence", + "type": "double precision", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "created_by_agent_id": { + "name": "created_by_agent_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "memory_entry_workspace_id_workspace_id_fk": { + "name": "memory_entry_workspace_id_workspace_id_fk", + "tableFrom": "memory_entry", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "memory_entry_created_by_agent_id_agent_id_fk": { + "name": "memory_entry_created_by_agent_id_agent_id_fk", + "tableFrom": "memory_entry", + "tableTo": "agent", + "columnsFrom": [ + "created_by_agent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.message": { + "name": "message", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "chat_id": { + "name": "chat_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "message_role", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "model_id": { + "name": "model_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "input_tokens": { + "name": "input_tokens", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "output_tokens": { + "name": "output_tokens", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "reasoning_tokens": { + "name": "reasoning_tokens", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "cache_read_tokens": { + "name": "cache_read_tokens", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "total_tokens": { + "name": "total_tokens", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "cost_micros": { + "name": "cost_micros", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "duration_ms": { + "name": "duration_ms", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "thinking_ms": { + "name": "thinking_ms", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "line_count": { + "name": "line_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "code_line_count": { + "name": "code_line_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "code_block_count": { + "name": "code_block_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "message_chat_id_chat_id_fk": { + "name": "message_chat_id_chat_id_fk", + "tableFrom": "message", + "tableTo": "chat", + "columnsFrom": [ + "chat_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.model_installation": { + "name": "model_installation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "label": { + "name": "label", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider_kind": { + "name": "provider_kind", + "type": "model_provider_kind", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "base_url": { + "name": "base_url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "api_key": { + "name": "api_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "model_ids": { + "name": "model_ids", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "disabled_model_ids": { + "name": "disabled_model_ids", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "model_installation_workspace_id_workspace_id_fk": { + "name": "model_installation_workspace_id_workspace_id_fk", + "tableFrom": "model_installation", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.model_parameter": { + "name": "model_parameter", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "model_id": { + "name": "model_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "custom_name": { + "name": "custom_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "custom_instructions": { + "name": "custom_instructions", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "max_output_tokens": { + "name": "max_output_tokens", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "temperature": { + "name": "temperature", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "top_p": { + "name": "top_p", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "frequency_penalty": { + "name": "frequency_penalty", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "presence_penalty": { + "name": "presence_penalty", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "stop_sequences": { + "name": "stop_sequences", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "reasoning_effort": { + "name": "reasoning_effort", + "type": "model_reasoning_effort", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "model_parameter_workspace_model_idx": { + "name": "model_parameter_workspace_model_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "model_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "model_parameter_workspace_id_workspace_id_fk": { + "name": "model_parameter_workspace_id_workspace_id_fk", + "tableFrom": "model_parameter", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.nyxel_event": { + "name": "nyxel_event", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "nyxel_event_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "entity_type": { + "name": "entity_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "entity_id": { + "name": "entity_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "payload": { + "name": "payload", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "nyxel_event_workspace_id_workspace_id_fk": { + "name": "nyxel_event_workspace_id_workspace_id_fk", + "tableFrom": "nyxel_event", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.plugin": { + "name": "plugin", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "version": { + "name": "version", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "author": { + "name": "author", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "homepage": { + "name": "homepage", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "repo_url": { + "name": "repo_url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "manifest": { + "name": "manifest", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "skill_slugs": { + "name": "skill_slugs", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "agent_defs": { + "name": "agent_defs", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "file_count": { + "name": "file_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "install_dir": { + "name": "install_dir", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "ref": { + "name": "ref", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "resolved_sha": { + "name": "resolved_sha", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ref_pinned": { + "name": "ref_pinned", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "risk_findings": { + "name": "risk_findings", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "plugin_workspace_id_workspace_id_fk": { + "name": "plugin_workspace_id_workspace_id_fk", + "tableFrom": "plugin", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project": { + "name": "project", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "color": { + "name": "color", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'gray'" + }, + "icon": { + "name": "icon", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'folder'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "project_workspace_id_workspace_id_fk": { + "name": "project_workspace_id_workspace_id_fk", + "tableFrom": "project", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.push_subscription": { + "name": "push_subscription", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "endpoint": { + "name": "endpoint", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "p256dh": { + "name": "p256dh", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "auth": { + "name": "auth", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "push_subscription_user_id_user_id_fk": { + "name": "push_subscription_user_id_user_id_fk", + "tableFrom": "push_subscription", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "push_subscription_endpoint_unique": { + "name": "push_subscription_endpoint_unique", + "nullsNotDistinct": false, + "columns": [ + "endpoint" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.seo_analysis_run": { + "name": "seo_analysis_run", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "seo_project_id": { + "name": "seo_project_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "seo_analysis_run_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'running'" + }, + "score": { + "name": "score", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "pages_scanned": { + "name": "pages_scanned", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "summary": { + "name": "summary", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "seo_analysis_run_seo_project_id_seo_project_id_fk": { + "name": "seo_analysis_run_seo_project_id_seo_project_id_fk", + "tableFrom": "seo_analysis_run", + "tableTo": "seo_project", + "columnsFrom": [ + "seo_project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "seo_analysis_run_workspace_id_workspace_id_fk": { + "name": "seo_analysis_run_workspace_id_workspace_id_fk", + "tableFrom": "seo_analysis_run", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.seo_blog_post": { + "name": "seo_blog_post", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "seo_project_id": { + "name": "seo_project_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "keyword": { + "name": "keyword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "file_path": { + "name": "file_path", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "seo_blog_post_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'suggested'" + }, + "task_id": { + "name": "task_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "seo_blog_post_seo_project_id_seo_project_id_fk": { + "name": "seo_blog_post_seo_project_id_seo_project_id_fk", + "tableFrom": "seo_blog_post", + "tableTo": "seo_project", + "columnsFrom": [ + "seo_project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "seo_blog_post_workspace_id_workspace_id_fk": { + "name": "seo_blog_post_workspace_id_workspace_id_fk", + "tableFrom": "seo_blog_post", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "seo_blog_post_task_id_task_id_fk": { + "name": "seo_blog_post_task_id_task_id_fk", + "tableFrom": "seo_blog_post", + "tableTo": "task", + "columnsFrom": [ + "task_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.seo_finding": { + "name": "seo_finding", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "run_id": { + "name": "run_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "seo_project_id": { + "name": "seo_project_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "category": { + "name": "category", + "type": "seo_finding_category", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "severity": { + "name": "severity", + "type": "seo_finding_severity", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "recommendation": { + "name": "recommendation", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "location": { + "name": "location", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "resolved": { + "name": "resolved", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "seo_finding_run_id_seo_analysis_run_id_fk": { + "name": "seo_finding_run_id_seo_analysis_run_id_fk", + "tableFrom": "seo_finding", + "tableTo": "seo_analysis_run", + "columnsFrom": [ + "run_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "seo_finding_seo_project_id_seo_project_id_fk": { + "name": "seo_finding_seo_project_id_seo_project_id_fk", + "tableFrom": "seo_finding", + "tableTo": "seo_project", + "columnsFrom": [ + "seo_project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.seo_project": { + "name": "seo_project", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "extension_id": { + "name": "extension_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "domain": { + "name": "domain", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "repo_path": { + "name": "repo_path", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "blog_config": { + "name": "blog_config", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "fixer_agent_id": { + "name": "fixer_agent_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "reanalyze_cron_expression": { + "name": "reanalyze_cron_expression", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "next_reanalyze_at": { + "name": "next_reanalyze_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_reanalyze_at": { + "name": "last_reanalyze_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "seo_project_workspace_id_workspace_id_fk": { + "name": "seo_project_workspace_id_workspace_id_fk", + "tableFrom": "seo_project", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "seo_project_extension_id_extension_id_fk": { + "name": "seo_project_extension_id_extension_id_fk", + "tableFrom": "seo_project", + "tableTo": "extension", + "columnsFrom": [ + "extension_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "seo_project_fixer_agent_id_agent_id_fk": { + "name": "seo_project_fixer_agent_id_agent_id_fk", + "tableFrom": "seo_project", + "tableTo": "agent", + "columnsFrom": [ + "fixer_agent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.task": { + "name": "task", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "parent_task_id": { + "name": "parent_task_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_chat_id": { + "name": "source_chat_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_by_agent_id": { + "name": "created_by_agent_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "assigned_agent_id": { + "name": "assigned_agent_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "goal_id": { + "name": "goal_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "goal_milestone_id": { + "name": "goal_milestone_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "instruction": { + "name": "instruction", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "model_id": { + "name": "model_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "task_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "priority": { + "name": "priority", + "type": "task_priority", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'normal'" + }, + "requires_approval": { + "name": "requires_approval", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "input": { + "name": "input", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "plan": { + "name": "plan", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "handoff": { + "name": "handoff", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "result_summary": { + "name": "result_summary", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "task_workspace_id_workspace_id_fk": { + "name": "task_workspace_id_workspace_id_fk", + "tableFrom": "task", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "task_source_chat_id_chat_id_fk": { + "name": "task_source_chat_id_chat_id_fk", + "tableFrom": "task", + "tableTo": "chat", + "columnsFrom": [ + "source_chat_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "task_created_by_agent_id_agent_id_fk": { + "name": "task_created_by_agent_id_agent_id_fk", + "tableFrom": "task", + "tableTo": "agent", + "columnsFrom": [ + "created_by_agent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "task_assigned_agent_id_agent_id_fk": { + "name": "task_assigned_agent_id_agent_id_fk", + "tableFrom": "task", + "tableTo": "agent", + "columnsFrom": [ + "assigned_agent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "task_goal_id_goal_id_fk": { + "name": "task_goal_id_goal_id_fk", + "tableFrom": "task", + "tableTo": "goal", + "columnsFrom": [ + "goal_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "task_goal_milestone_id_goal_milestone_id_fk": { + "name": "task_goal_milestone_id_goal_milestone_id_fk", + "tableFrom": "task", + "tableTo": "goal_milestone", + "columnsFrom": [ + "goal_milestone_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.task_event": { + "name": "task_event", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "task_id": { + "name": "task_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "agent_run_id": { + "name": "agent_run_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "agent_id": { + "name": "agent_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "kind": { + "name": "kind", + "type": "task_event_kind", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "message": { + "name": "message", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "payload": { + "name": "payload", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "task_event_task_id_task_id_fk": { + "name": "task_event_task_id_task_id_fk", + "tableFrom": "task_event", + "tableTo": "task", + "columnsFrom": [ + "task_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "task_event_workspace_id_workspace_id_fk": { + "name": "task_event_workspace_id_workspace_id_fk", + "tableFrom": "task_event", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "task_event_agent_run_id_agent_run_id_fk": { + "name": "task_event_agent_run_id_agent_run_id_fk", + "tableFrom": "task_event", + "tableTo": "agent_run", + "columnsFrom": [ + "agent_run_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "task_event_agent_id_agent_id_fk": { + "name": "task_event_agent_id_agent_id_fk", + "tableFrom": "task_event", + "tableTo": "agent", + "columnsFrom": [ + "agent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.tool": { + "name": "tool", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "config": { + "name": "config", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "sensitive": { + "name": "sensitive", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "builtin": { + "name": "builtin", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "tool_workspace_id_workspace_id_fk": { + "name": "tool_workspace_id_workspace_id_fk", + "tableFrom": "tool", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.video_generation_job": { + "name": "video_generation_job", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "chat_id": { + "name": "chat_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "prompt": { + "name": "prompt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "model": { + "name": "model", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "video_generation_job_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'queued'" + }, + "progress": { + "name": "progress", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "size": { + "name": "size", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "seconds": { + "name": "seconds", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "auto": { + "name": "auto", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "external_job_id": { + "name": "external_job_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "library_file_id": { + "name": "library_file_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "poster_library_file_id": { + "name": "poster_library_file_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "video_generation_job_workspace_id_workspace_id_fk": { + "name": "video_generation_job_workspace_id_workspace_id_fk", + "tableFrom": "video_generation_job", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "video_generation_job_library_file_id_library_file_id_fk": { + "name": "video_generation_job_library_file_id_library_file_id_fk", + "tableFrom": "video_generation_job", + "tableTo": "library_file", + "columnsFrom": [ + "library_file_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "video_generation_job_poster_library_file_id_library_file_id_fk": { + "name": "video_generation_job_poster_library_file_id_library_file_id_fk", + "tableFrom": "video_generation_job", + "tableTo": "library_file", + "columnsFrom": [ + "poster_library_file_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow": { + "name": "workflow", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "definition": { + "name": "definition", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_workspace_id_workspace_id_fk": { + "name": "workflow_workspace_id_workspace_id_fk", + "tableFrom": "workflow", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_run": { + "name": "workflow_run", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "workflow_run_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'queued'" + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_run_workflow_id_workflow_id_fk": { + "name": "workflow_run_workflow_id_workflow_id_fk", + "tableFrom": "workflow_run", + "tableTo": "workflow", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_run_workspace_id_workspace_id_fk": { + "name": "workflow_run_workspace_id_workspace_id_fk", + "tableFrom": "workflow_run", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_run_node": { + "name": "workflow_run_node", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "run_id": { + "name": "run_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "node_id": { + "name": "node_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "workflow_run_node_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'queued'" + }, + "progress": { + "name": "progress", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "library_file_id": { + "name": "library_file_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_run_node_run_id_workflow_run_id_fk": { + "name": "workflow_run_node_run_id_workflow_run_id_fk", + "tableFrom": "workflow_run_node", + "tableTo": "workflow_run", + "columnsFrom": [ + "run_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_run_node_library_file_id_library_file_id_fk": { + "name": "workflow_run_node_library_file_id_library_file_id_fk", + "tableFrom": "workflow_run_node", + "tableTo": "library_file", + "columnsFrom": [ + "library_file_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace": { + "name": "workspace", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "custom_instructions": { + "name": "custom_instructions", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "icon": { + "name": "icon", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "color": { + "name": "color", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "default_model_id": { + "name": "default_model_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "default_autonomy_level": { + "name": "default_autonomy_level", + "type": "agent_autonomy_level", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'assisted'" + }, + "default_tool_policy": { + "name": "default_tool_policy", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workspace_user_id_user_id_fk": { + "name": "workspace_user_id_user_id_fk", + "tableFrom": "workspace", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.account": { + "name": "account", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "account_id": { + "name": "account_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token_expires_at": { + "name": "access_token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "refresh_token_expires_at": { + "name": "refresh_token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "account_user_id_user_id_fk": { + "name": "account_user_id_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session": { + "name": "session", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "session_user_id_user_id_fk": { + "name": "session_user_id_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "session_token_unique": { + "name": "session_token_unique", + "nullsNotDistinct": false, + "columns": [ + "token" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email_verified": { + "name": "email_verified", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_email_unique": { + "name": "user_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.verification": { + "name": "verification", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": { + "public.agent_autonomy_level": { + "name": "agent_autonomy_level", + "schema": "public", + "values": [ + "chat", + "assisted", + "autonomous", + "super_agent" + ] + }, + "public.agent_run_status": { + "name": "agent_run_status", + "schema": "public", + "values": [ + "pending", + "running", + "waiting_approval", + "completed", + "failed", + "cancelled" + ] + }, + "public.agent_run_trigger": { + "name": "agent_run_trigger", + "schema": "public", + "values": [ + "chat", + "task", + "automation", + "delegate", + "extension" + ] + }, + "public.approval_kind": { + "name": "approval_kind", + "schema": "public", + "values": [ + "skill", + "tool", + "mcp" + ] + }, + "public.approval_status": { + "name": "approval_status", + "schema": "public", + "values": [ + "pending", + "approved", + "rejected" + ] + }, + "public.artifact_type": { + "name": "artifact_type", + "schema": "public", + "values": [ + "text", + "markdown", + "code_patch", + "diff", + "file", + "report", + "json", + "image_reference", + "task_result", + "command_output" + ] + }, + "public.audit_actor": { + "name": "audit_actor", + "schema": "public", + "values": [ + "chat", + "automation", + "approval", + "delegate", + "extension", + "goal_orchestrator" + ] + }, + "public.audit_status": { + "name": "audit_status", + "schema": "public", + "values": [ + "success", + "error", + "pending_approval", + "rejected" + ] + }, + "public.automation_run_status": { + "name": "automation_run_status", + "schema": "public", + "values": [ + "success", + "error", + "pending_approval" + ] + }, + "public.automation_target_kind": { + "name": "automation_target_kind", + "schema": "public", + "values": [ + "agent", + "workflow" + ] + }, + "public.automation_trigger_type": { + "name": "automation_trigger_type", + "schema": "public", + "values": [ + "cron", + "file_watch" + ] + }, + "public.chat_tool_mode": { + "name": "chat_tool_mode", + "schema": "public", + "values": [ + "default", + "automatic", + "auto" + ] + }, + "public.goal_event_kind": { + "name": "goal_event_kind", + "schema": "public", + "values": [ + "created", + "status_changed", + "milestone_added", + "milestone_status_changed", + "plan_created", + "task_created", + "task_status_changed", + "review" + ] + }, + "public.goal_milestone_status": { + "name": "goal_milestone_status", + "schema": "public", + "values": [ + "pending", + "completed" + ] + }, + "public.goal_status": { + "name": "goal_status", + "schema": "public", + "values": [ + "active", + "paused", + "blocked", + "completed", + "archived" + ] + }, + "public.installation_mode": { + "name": "installation_mode", + "schema": "public", + "values": [ + "pc", + "server" + ] + }, + "public.library_item_kind": { + "name": "library_item_kind", + "schema": "public", + "values": [ + "image", + "document", + "video", + "other" + ] + }, + "public.mcp_transport": { + "name": "mcp_transport", + "schema": "public", + "values": [ + "stdio", + "http" + ] + }, + "public.memory_source": { + "name": "memory_source", + "schema": "public", + "values": [ + "user", + "agent", + "automation", + "system" + ] + }, + "public.memory_type": { + "name": "memory_type", + "schema": "public", + "values": [ + "user_preference", + "workspace_fact", + "project_decision", + "agent_observation", + "task_summary", + "file_summary", + "repo_summary", + "long_term_note" + ] + }, + "public.message_role": { + "name": "message_role", + "schema": "public", + "values": [ + "user", + "assistant", + "system", + "tool" + ] + }, + "public.model_provider_kind": { + "name": "model_provider_kind", + "schema": "public", + "values": [ + "anthropic", + "openai", + "openrouter", + "openai_compatible", + "claude_cli", + "codex_cli" + ] + }, + "public.model_reasoning_effort": { + "name": "model_reasoning_effort", + "schema": "public", + "values": [ + "low", + "medium", + "high" + ] + }, + "public.nyxel_event_type": { + "name": "nyxel_event_type", + "schema": "public", + "values": [ + "agent.run.started", + "agent.run.completed", + "agent.run.failed", + "approval.created", + "approval.resolved", + "workflow.completed", + "task.failed", + "library.file.created", + "automation.triggered" + ] + }, + "public.seo_analysis_run_status": { + "name": "seo_analysis_run_status", + "schema": "public", + "values": [ + "running", + "completed", + "failed" + ] + }, + "public.seo_blog_post_status": { + "name": "seo_blog_post_status", + "schema": "public", + "values": [ + "suggested", + "generating", + "written", + "failed" + ] + }, + "public.seo_finding_category": { + "name": "seo_finding_category", + "schema": "public", + "values": [ + "seo", + "geo", + "aeo" + ] + }, + "public.seo_finding_severity": { + "name": "seo_finding_severity", + "schema": "public", + "values": [ + "info", + "warning", + "critical" + ] + }, + "public.task_event_kind": { + "name": "task_event_kind", + "schema": "public", + "values": [ + "created", + "planned", + "status_changed", + "assigned", + "delegated", + "tool_called", + "approval_waiting", + "approval_resolved", + "run_started", + "run_finished", + "comment", + "question", + "question_answered", + "completed", + "failed" + ] + }, + "public.task_priority": { + "name": "task_priority", + "schema": "public", + "values": [ + "low", + "normal", + "high", + "urgent" + ] + }, + "public.task_status": { + "name": "task_status", + "schema": "public", + "values": [ + "pending", + "planning", + "ready", + "running", + "blocked", + "waiting_approval", + "completed", + "failed", + "cancelled" + ] + }, + "public.video_generation_job_status": { + "name": "video_generation_job_status", + "schema": "public", + "values": [ + "queued", + "in_progress", + "completed", + "failed" + ] + }, + "public.workflow_run_node_status": { + "name": "workflow_run_node_status", + "schema": "public", + "values": [ + "queued", + "running", + "completed", + "failed", + "skipped" + ] + }, + "public.workflow_run_status": { + "name": "workflow_run_status", + "schema": "public", + "values": [ + "queued", + "running", + "completed", + "failed", + "partial" + ] + } + }, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/packages/db/drizzle/pg/meta/_journal.json b/packages/db/drizzle/pg/meta/_journal.json index da3f1ec..a55e10e 100644 --- a/packages/db/drizzle/pg/meta/_journal.json +++ b/packages/db/drizzle/pg/meta/_journal.json @@ -295,6 +295,20 @@ "when": 1783067653683, "tag": "0041_medical_lizard", "breakpoints": true + }, + { + "idx": 42, + "version": "7", + "when": 1783072878737, + "tag": "0042_sad_emma_frost", + "breakpoints": true + }, + { + "idx": 43, + "version": "7", + "when": 1783073683795, + "tag": "0043_cooing_starjammers", + "breakpoints": true } ] } \ No newline at end of file diff --git a/packages/db/drizzle/sqlite/0039_dazzling_gressill.sql b/packages/db/drizzle/sqlite/0039_dazzling_gressill.sql new file mode 100644 index 0000000..6f67671 --- /dev/null +++ b/packages/db/drizzle/sqlite/0039_dazzling_gressill.sql @@ -0,0 +1,4 @@ +ALTER TABLE `agent_run` ADD `worker_id` text;--> statement-breakpoint +ALTER TABLE `agent_run` ADD `heartbeat_at` integer;--> statement-breakpoint +ALTER TABLE `agent_run` ADD `lease_until` integer;--> statement-breakpoint +ALTER TABLE `agent_run` ADD `cancel_requested_at` integer; \ No newline at end of file diff --git a/packages/db/drizzle/sqlite/meta/0039_snapshot.json b/packages/db/drizzle/sqlite/meta/0039_snapshot.json new file mode 100644 index 0000000..f7b2fa1 --- /dev/null +++ b/packages/db/drizzle/sqlite/meta/0039_snapshot.json @@ -0,0 +1,4792 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "55e682fb-66ea-4f72-8df7-ef0338fe1f6a", + "prevId": "ca21c508-587f-4853-a35c-3aacc12df8e0", + "tables": { + "agent": { + "name": "agent", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "system_prompt": { + "name": "system_prompt", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "goal_template": { + "name": "goal_template", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "model_id": { + "name": "model_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "autonomy_level": { + "name": "autonomy_level", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'chat'" + }, + "mcp_server_ids": { + "name": "mcp_server_ids", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'[]'" + }, + "tool_ids": { + "name": "tool_ids", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'[]'" + }, + "skill_ids": { + "name": "skill_ids", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'[]'" + }, + "mcp_tool_filter": { + "name": "mcp_tool_filter", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "delegate_agent_ids": { + "name": "delegate_agent_ids", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'[]'" + }, + "autonomy_budget": { + "name": "autonomy_budget", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "agent_workspace_id_workspace_id_fk": { + "name": "agent_workspace_id_workspace_id_fk", + "tableFrom": "agent", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "agent_run": { + "name": "agent_run", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "task_id": { + "name": "task_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "agent_id": { + "name": "agent_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "chat_id": { + "name": "chat_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "automation_id": { + "name": "automation_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "trigger": { + "name": "trigger", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "model_id": { + "name": "model_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "step_count": { + "name": "step_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'pending'" + }, + "final_output": { + "name": "final_output", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "started_at": { + "name": "started_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "completed_at": { + "name": "completed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "worker_id": { + "name": "worker_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "heartbeat_at": { + "name": "heartbeat_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "lease_until": { + "name": "lease_until", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "cancel_requested_at": { + "name": "cancel_requested_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "agent_run_workspace_id_workspace_id_fk": { + "name": "agent_run_workspace_id_workspace_id_fk", + "tableFrom": "agent_run", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "agent_run_task_id_task_id_fk": { + "name": "agent_run_task_id_task_id_fk", + "tableFrom": "agent_run", + "tableTo": "task", + "columnsFrom": [ + "task_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "agent_run_agent_id_agent_id_fk": { + "name": "agent_run_agent_id_agent_id_fk", + "tableFrom": "agent_run", + "tableTo": "agent", + "columnsFrom": [ + "agent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "agent_run_chat_id_chat_id_fk": { + "name": "agent_run_chat_id_chat_id_fk", + "tableFrom": "agent_run", + "tableTo": "chat", + "columnsFrom": [ + "chat_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "agent_run_automation_id_automation_id_fk": { + "name": "agent_run_automation_id_automation_id_fk", + "tableFrom": "agent_run", + "tableTo": "automation", + "columnsFrom": [ + "automation_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "approval_request": { + "name": "approval_request", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "agent_id": { + "name": "agent_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "chat_id": { + "name": "chat_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "automation_id": { + "name": "automation_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "task_id": { + "name": "task_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "agent_run_id": { + "name": "agent_run_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "skill_id": { + "name": "skill_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "tool_id": { + "name": "tool_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "mcp_server_id": { + "name": "mcp_server_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "mcp_tool_name": { + "name": "mcp_tool_name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "tool_label": { + "name": "tool_label", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "input": { + "name": "input", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'pending'" + }, + "result_output": { + "name": "result_output", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "resolved_at": { + "name": "resolved_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "risk_level": { + "name": "risk_level", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "affected_resources": { + "name": "affected_resources", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "diff_preview": { + "name": "diff_preview", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "approval_request_workspace_id_workspace_id_fk": { + "name": "approval_request_workspace_id_workspace_id_fk", + "tableFrom": "approval_request", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "approval_request_agent_id_agent_id_fk": { + "name": "approval_request_agent_id_agent_id_fk", + "tableFrom": "approval_request", + "tableTo": "agent", + "columnsFrom": [ + "agent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "approval_request_chat_id_chat_id_fk": { + "name": "approval_request_chat_id_chat_id_fk", + "tableFrom": "approval_request", + "tableTo": "chat", + "columnsFrom": [ + "chat_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "approval_request_automation_id_automation_id_fk": { + "name": "approval_request_automation_id_automation_id_fk", + "tableFrom": "approval_request", + "tableTo": "automation", + "columnsFrom": [ + "automation_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "approval_request_task_id_task_id_fk": { + "name": "approval_request_task_id_task_id_fk", + "tableFrom": "approval_request", + "tableTo": "task", + "columnsFrom": [ + "task_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "approval_request_agent_run_id_agent_run_id_fk": { + "name": "approval_request_agent_run_id_agent_run_id_fk", + "tableFrom": "approval_request", + "tableTo": "agent_run", + "columnsFrom": [ + "agent_run_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "artifact": { + "name": "artifact", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "task_id": { + "name": "task_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "agent_run_id": { + "name": "agent_run_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "agent_id": { + "name": "agent_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "artifact_workspace_id_workspace_id_fk": { + "name": "artifact_workspace_id_workspace_id_fk", + "tableFrom": "artifact", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "artifact_task_id_task_id_fk": { + "name": "artifact_task_id_task_id_fk", + "tableFrom": "artifact", + "tableTo": "task", + "columnsFrom": [ + "task_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "artifact_agent_run_id_agent_run_id_fk": { + "name": "artifact_agent_run_id_agent_run_id_fk", + "tableFrom": "artifact", + "tableTo": "agent_run", + "columnsFrom": [ + "agent_run_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "artifact_agent_id_agent_id_fk": { + "name": "artifact_agent_id_agent_id_fk", + "tableFrom": "artifact", + "tableTo": "agent", + "columnsFrom": [ + "agent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "audit_log": { + "name": "audit_log", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "agent_id": { + "name": "agent_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "chat_id": { + "name": "chat_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "automation_id": { + "name": "automation_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "actor": { + "name": "actor", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "tool_label": { + "name": "tool_label", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "input": { + "name": "input", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "output": { + "name": "output", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "input_hash": { + "name": "input_hash", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "permission_snapshot": { + "name": "permission_snapshot", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "audit_log_workspace_id_workspace_id_fk": { + "name": "audit_log_workspace_id_workspace_id_fk", + "tableFrom": "audit_log", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "audit_log_agent_id_agent_id_fk": { + "name": "audit_log_agent_id_agent_id_fk", + "tableFrom": "audit_log", + "tableTo": "agent", + "columnsFrom": [ + "agent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "audit_log_chat_id_chat_id_fk": { + "name": "audit_log_chat_id_chat_id_fk", + "tableFrom": "audit_log", + "tableTo": "chat", + "columnsFrom": [ + "chat_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "audit_log_automation_id_automation_id_fk": { + "name": "audit_log_automation_id_automation_id_fk", + "tableFrom": "audit_log", + "tableTo": "automation", + "columnsFrom": [ + "automation_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "automation": { + "name": "automation", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "agent_id": { + "name": "agent_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "target_kind": { + "name": "target_kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'agent'" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "trigger_type": { + "name": "trigger_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'cron'" + }, + "cron_expression": { + "name": "cron_expression", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "watch_path": { + "name": "watch_path", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "watch_glob": { + "name": "watch_glob", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_watch_check_at": { + "name": "last_watch_check_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "prompt": { + "name": "prompt", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "enabled": { + "name": "enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "last_run_at": { + "name": "last_run_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "next_run_at": { + "name": "next_run_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_run_status": { + "name": "last_run_status", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_error_message": { + "name": "last_error_message", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "automation_workspace_id_workspace_id_fk": { + "name": "automation_workspace_id_workspace_id_fk", + "tableFrom": "automation", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "automation_agent_id_agent_id_fk": { + "name": "automation_agent_id_agent_id_fk", + "tableFrom": "automation", + "tableTo": "agent", + "columnsFrom": [ + "agent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "automation_workflow_id_workflow_id_fk": { + "name": "automation_workflow_id_workflow_id_fk", + "tableFrom": "automation", + "tableTo": "workflow", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "chat": { + "name": "chat", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "working_directory": { + "name": "working_directory", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "agent_id": { + "name": "agent_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'New chat'" + }, + "model_id": { + "name": "model_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "archived_at": { + "name": "archived_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "pinned_at": { + "name": "pinned_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "share_id": { + "name": "share_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "shared_at": { + "name": "shared_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "tool_mode": { + "name": "tool_mode", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'default'" + }, + "tool_policy": { + "name": "tool_policy", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'{\"mode\":\"default\",\"approveFileWrites\":true,\"approveFileDeletes\":true,\"approveCustomCode\":true,\"approveMcpTools\":true}'" + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "chat_share_id_unique": { + "name": "chat_share_id_unique", + "columns": [ + "share_id" + ], + "isUnique": true + } + }, + "foreignKeys": { + "chat_workspace_id_workspace_id_fk": { + "name": "chat_workspace_id_workspace_id_fk", + "tableFrom": "chat", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "chat_agent_id_agent_id_fk": { + "name": "chat_agent_id_agent_id_fk", + "tableFrom": "chat", + "tableTo": "agent", + "columnsFrom": [ + "agent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "chat_project_id_project_id_fk": { + "name": "chat_project_id_project_id_fk", + "tableFrom": "chat", + "tableTo": "project", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "extension": { + "name": "extension", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "enabled": { + "name": "enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "config": { + "name": "config", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'{}'" + }, + "installed_at": { + "name": "installed_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "extension_workspace_id_workspace_id_fk": { + "name": "extension_workspace_id_workspace_id_fk", + "tableFrom": "extension", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "goal": { + "name": "goal", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'active'" + }, + "priority": { + "name": "priority", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'normal'" + }, + "default_agent_id": { + "name": "default_agent_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "success_criteria": { + "name": "success_criteria", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "orchestration_enabled": { + "name": "orchestration_enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "next_review_at": { + "name": "next_review_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_reviewed_at": { + "name": "last_reviewed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "blocked_reason": { + "name": "blocked_reason", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "plan_generated_at": { + "name": "plan_generated_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "goal_workspace_id_workspace_id_fk": { + "name": "goal_workspace_id_workspace_id_fk", + "tableFrom": "goal", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "goal_default_agent_id_agent_id_fk": { + "name": "goal_default_agent_id_agent_id_fk", + "tableFrom": "goal", + "tableTo": "agent", + "columnsFrom": [ + "default_agent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "goal_milestone": { + "name": "goal_milestone", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "goal_id": { + "name": "goal_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'pending'" + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "goal_milestone_goal_id_goal_id_fk": { + "name": "goal_milestone_goal_id_goal_id_fk", + "tableFrom": "goal_milestone", + "tableTo": "goal", + "columnsFrom": [ + "goal_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "goal_milestone_workspace_id_workspace_id_fk": { + "name": "goal_milestone_workspace_id_workspace_id_fk", + "tableFrom": "goal_milestone", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "goal_progress_event": { + "name": "goal_progress_event", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "goal_id": { + "name": "goal_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "message": { + "name": "message", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "payload": { + "name": "payload", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "goal_progress_event_goal_id_goal_id_fk": { + "name": "goal_progress_event_goal_id_goal_id_fk", + "tableFrom": "goal_progress_event", + "tableTo": "goal", + "columnsFrom": [ + "goal_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "goal_progress_event_workspace_id_workspace_id_fk": { + "name": "goal_progress_event_workspace_id_workspace_id_fk", + "tableFrom": "goal_progress_event", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "installation": { + "name": "installation", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "mode": { + "name": "mode", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "owner_user_id": { + "name": "owner_user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "primary_workspace_id": { + "name": "primary_workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "app_url": { + "name": "app_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "installation_owner_user_id_user_id_fk": { + "name": "installation_owner_user_id_user_id_fk", + "tableFrom": "installation", + "tableTo": "user", + "columnsFrom": [ + "owner_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "knowledge_base_config": { + "name": "knowledge_base_config", + "columns": { + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "vault_path": { + "name": "vault_path", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'knowledge-base'" + }, + "obsidian_rest_url": { + "name": "obsidian_rest_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "obsidian_api_key": { + "name": "obsidian_api_key", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "docs_agent_enabled": { + "name": "docs_agent_enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "inject_into_prompts": { + "name": "inject_into_prompts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "last_docs_sync_at": { + "name": "last_docs_sync_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_docs_sync_error": { + "name": "last_docs_sync_error", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "knowledge_base_config_workspace_id_workspace_id_fk": { + "name": "knowledge_base_config_workspace_id_workspace_id_fk", + "tableFrom": "knowledge_base_config", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "library_file": { + "name": "library_file", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "folder_id": { + "name": "folder_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "mime_type": { + "name": "mime_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "size_bytes": { + "name": "size_bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'other'" + }, + "storage_key": { + "name": "storage_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "library_file_workspace_id_workspace_id_fk": { + "name": "library_file_workspace_id_workspace_id_fk", + "tableFrom": "library_file", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "library_file_folder_id_library_folder_id_fk": { + "name": "library_file_folder_id_library_folder_id_fk", + "tableFrom": "library_file", + "tableTo": "library_folder", + "columnsFrom": [ + "folder_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "library_folder": { + "name": "library_folder", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "parent_id": { + "name": "parent_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "library_folder_workspace_id_workspace_id_fk": { + "name": "library_folder_workspace_id_workspace_id_fk", + "tableFrom": "library_folder", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "mcp_server": { + "name": "mcp_server", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "transport": { + "name": "transport", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "args": { + "name": "args", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "oauth_state": { + "name": "oauth_state", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "enabled": { + "name": "enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "mcp_server_workspace_id_workspace_id_fk": { + "name": "mcp_server_workspace_id_workspace_id_fk", + "tableFrom": "mcp_server", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "memory_entry": { + "name": "memory_entry", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "confidence": { + "name": "confidence", + "type": "real", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "created_by_agent_id": { + "name": "created_by_agent_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "memory_entry_workspace_id_workspace_id_fk": { + "name": "memory_entry_workspace_id_workspace_id_fk", + "tableFrom": "memory_entry", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "memory_entry_created_by_agent_id_agent_id_fk": { + "name": "memory_entry_created_by_agent_id_agent_id_fk", + "tableFrom": "memory_entry", + "tableTo": "agent", + "columnsFrom": [ + "created_by_agent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "message": { + "name": "message", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "chat_id": { + "name": "chat_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "model_id": { + "name": "model_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "input_tokens": { + "name": "input_tokens", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "output_tokens": { + "name": "output_tokens", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "reasoning_tokens": { + "name": "reasoning_tokens", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "cache_read_tokens": { + "name": "cache_read_tokens", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "total_tokens": { + "name": "total_tokens", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "cost_micros": { + "name": "cost_micros", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "duration_ms": { + "name": "duration_ms", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "thinking_ms": { + "name": "thinking_ms", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "line_count": { + "name": "line_count", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "code_line_count": { + "name": "code_line_count", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "code_block_count": { + "name": "code_block_count", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "message_chat_id_chat_id_fk": { + "name": "message_chat_id_chat_id_fk", + "tableFrom": "message", + "tableTo": "chat", + "columnsFrom": [ + "chat_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "model_installation": { + "name": "model_installation", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "label": { + "name": "label", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider_kind": { + "name": "provider_kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "base_url": { + "name": "base_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "api_key": { + "name": "api_key", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "model_ids": { + "name": "model_ids", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'[]'" + }, + "disabled_model_ids": { + "name": "disabled_model_ids", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'[]'" + }, + "enabled": { + "name": "enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "model_installation_workspace_id_workspace_id_fk": { + "name": "model_installation_workspace_id_workspace_id_fk", + "tableFrom": "model_installation", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "model_parameter": { + "name": "model_parameter", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "model_id": { + "name": "model_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "custom_name": { + "name": "custom_name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "custom_instructions": { + "name": "custom_instructions", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "max_output_tokens": { + "name": "max_output_tokens", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "temperature": { + "name": "temperature", + "type": "real", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "top_p": { + "name": "top_p", + "type": "real", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "frequency_penalty": { + "name": "frequency_penalty", + "type": "real", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "presence_penalty": { + "name": "presence_penalty", + "type": "real", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "stop_sequences": { + "name": "stop_sequences", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'[]'" + }, + "reasoning_effort": { + "name": "reasoning_effort", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "model_parameter_workspace_model_idx": { + "name": "model_parameter_workspace_model_idx", + "columns": [ + "workspace_id", + "model_id" + ], + "isUnique": true + } + }, + "foreignKeys": { + "model_parameter_workspace_id_workspace_id_fk": { + "name": "model_parameter_workspace_id_workspace_id_fk", + "tableFrom": "model_parameter", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "nyxel_event": { + "name": "nyxel_event", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "entity_type": { + "name": "entity_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "entity_id": { + "name": "entity_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "payload": { + "name": "payload", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "nyxel_event_workspace_id_workspace_id_fk": { + "name": "nyxel_event_workspace_id_workspace_id_fk", + "tableFrom": "nyxel_event", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "plugin": { + "name": "plugin", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "version": { + "name": "version", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "author": { + "name": "author", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "homepage": { + "name": "homepage", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "repo_url": { + "name": "repo_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "manifest": { + "name": "manifest", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'{}'" + }, + "skill_slugs": { + "name": "skill_slugs", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'[]'" + }, + "agent_defs": { + "name": "agent_defs", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'[]'" + }, + "file_count": { + "name": "file_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "install_dir": { + "name": "install_dir", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "enabled": { + "name": "enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "ref": { + "name": "ref", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "resolved_sha": { + "name": "resolved_sha", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ref_pinned": { + "name": "ref_pinned", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "risk_findings": { + "name": "risk_findings", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'[]'" + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "plugin_workspace_id_workspace_id_fk": { + "name": "plugin_workspace_id_workspace_id_fk", + "tableFrom": "plugin", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "project": { + "name": "project", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "color": { + "name": "color", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'gray'" + }, + "icon": { + "name": "icon", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'folder'" + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "project_workspace_id_workspace_id_fk": { + "name": "project_workspace_id_workspace_id_fk", + "tableFrom": "project", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "push_subscription": { + "name": "push_subscription", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "endpoint": { + "name": "endpoint", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "p256dh": { + "name": "p256dh", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "auth": { + "name": "auth", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "push_subscription_endpoint_unique": { + "name": "push_subscription_endpoint_unique", + "columns": [ + "endpoint" + ], + "isUnique": true + } + }, + "foreignKeys": { + "push_subscription_user_id_user_id_fk": { + "name": "push_subscription_user_id_user_id_fk", + "tableFrom": "push_subscription", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "seo_analysis_run": { + "name": "seo_analysis_run", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "seo_project_id": { + "name": "seo_project_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'running'" + }, + "score": { + "name": "score", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "pages_scanned": { + "name": "pages_scanned", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "summary": { + "name": "summary", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "started_at": { + "name": "started_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "completed_at": { + "name": "completed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "seo_analysis_run_seo_project_id_seo_project_id_fk": { + "name": "seo_analysis_run_seo_project_id_seo_project_id_fk", + "tableFrom": "seo_analysis_run", + "tableTo": "seo_project", + "columnsFrom": [ + "seo_project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "seo_analysis_run_workspace_id_workspace_id_fk": { + "name": "seo_analysis_run_workspace_id_workspace_id_fk", + "tableFrom": "seo_analysis_run", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "seo_blog_post": { + "name": "seo_blog_post", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "seo_project_id": { + "name": "seo_project_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "keyword": { + "name": "keyword", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "file_path": { + "name": "file_path", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'suggested'" + }, + "task_id": { + "name": "task_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "seo_blog_post_seo_project_id_seo_project_id_fk": { + "name": "seo_blog_post_seo_project_id_seo_project_id_fk", + "tableFrom": "seo_blog_post", + "tableTo": "seo_project", + "columnsFrom": [ + "seo_project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "seo_blog_post_workspace_id_workspace_id_fk": { + "name": "seo_blog_post_workspace_id_workspace_id_fk", + "tableFrom": "seo_blog_post", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "seo_blog_post_task_id_task_id_fk": { + "name": "seo_blog_post_task_id_task_id_fk", + "tableFrom": "seo_blog_post", + "tableTo": "task", + "columnsFrom": [ + "task_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "seo_finding": { + "name": "seo_finding", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "run_id": { + "name": "run_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "seo_project_id": { + "name": "seo_project_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "category": { + "name": "category", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "severity": { + "name": "severity", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "recommendation": { + "name": "recommendation", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "location": { + "name": "location", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "resolved": { + "name": "resolved", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "seo_finding_run_id_seo_analysis_run_id_fk": { + "name": "seo_finding_run_id_seo_analysis_run_id_fk", + "tableFrom": "seo_finding", + "tableTo": "seo_analysis_run", + "columnsFrom": [ + "run_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "seo_finding_seo_project_id_seo_project_id_fk": { + "name": "seo_finding_seo_project_id_seo_project_id_fk", + "tableFrom": "seo_finding", + "tableTo": "seo_project", + "columnsFrom": [ + "seo_project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "seo_project": { + "name": "seo_project", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "extension_id": { + "name": "extension_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "domain": { + "name": "domain", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "repo_path": { + "name": "repo_path", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "blog_config": { + "name": "blog_config", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "fixer_agent_id": { + "name": "fixer_agent_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "reanalyze_cron_expression": { + "name": "reanalyze_cron_expression", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "next_reanalyze_at": { + "name": "next_reanalyze_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_reanalyze_at": { + "name": "last_reanalyze_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "seo_project_workspace_id_workspace_id_fk": { + "name": "seo_project_workspace_id_workspace_id_fk", + "tableFrom": "seo_project", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "seo_project_extension_id_extension_id_fk": { + "name": "seo_project_extension_id_extension_id_fk", + "tableFrom": "seo_project", + "tableTo": "extension", + "columnsFrom": [ + "extension_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "seo_project_fixer_agent_id_agent_id_fk": { + "name": "seo_project_fixer_agent_id_agent_id_fk", + "tableFrom": "seo_project", + "tableTo": "agent", + "columnsFrom": [ + "fixer_agent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "task": { + "name": "task", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "parent_task_id": { + "name": "parent_task_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "source_chat_id": { + "name": "source_chat_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_by_agent_id": { + "name": "created_by_agent_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "assigned_agent_id": { + "name": "assigned_agent_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "goal_id": { + "name": "goal_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "goal_milestone_id": { + "name": "goal_milestone_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "instruction": { + "name": "instruction", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "model_id": { + "name": "model_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'pending'" + }, + "priority": { + "name": "priority", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'normal'" + }, + "requires_approval": { + "name": "requires_approval", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "input": { + "name": "input", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'{}'" + }, + "plan": { + "name": "plan", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "handoff": { + "name": "handoff", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "result_summary": { + "name": "result_summary", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "started_at": { + "name": "started_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "completed_at": { + "name": "completed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "task_workspace_id_workspace_id_fk": { + "name": "task_workspace_id_workspace_id_fk", + "tableFrom": "task", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "task_source_chat_id_chat_id_fk": { + "name": "task_source_chat_id_chat_id_fk", + "tableFrom": "task", + "tableTo": "chat", + "columnsFrom": [ + "source_chat_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "task_created_by_agent_id_agent_id_fk": { + "name": "task_created_by_agent_id_agent_id_fk", + "tableFrom": "task", + "tableTo": "agent", + "columnsFrom": [ + "created_by_agent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "task_assigned_agent_id_agent_id_fk": { + "name": "task_assigned_agent_id_agent_id_fk", + "tableFrom": "task", + "tableTo": "agent", + "columnsFrom": [ + "assigned_agent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "task_goal_id_goal_id_fk": { + "name": "task_goal_id_goal_id_fk", + "tableFrom": "task", + "tableTo": "goal", + "columnsFrom": [ + "goal_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "task_goal_milestone_id_goal_milestone_id_fk": { + "name": "task_goal_milestone_id_goal_milestone_id_fk", + "tableFrom": "task", + "tableTo": "goal_milestone", + "columnsFrom": [ + "goal_milestone_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "task_event": { + "name": "task_event", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "task_id": { + "name": "task_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "agent_run_id": { + "name": "agent_run_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "agent_id": { + "name": "agent_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "message": { + "name": "message", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "payload": { + "name": "payload", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "task_event_task_id_task_id_fk": { + "name": "task_event_task_id_task_id_fk", + "tableFrom": "task_event", + "tableTo": "task", + "columnsFrom": [ + "task_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "task_event_workspace_id_workspace_id_fk": { + "name": "task_event_workspace_id_workspace_id_fk", + "tableFrom": "task_event", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "task_event_agent_run_id_agent_run_id_fk": { + "name": "task_event_agent_run_id_agent_run_id_fk", + "tableFrom": "task_event", + "tableTo": "agent_run", + "columnsFrom": [ + "agent_run_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "task_event_agent_id_agent_id_fk": { + "name": "task_event_agent_id_agent_id_fk", + "tableFrom": "task_event", + "tableTo": "agent", + "columnsFrom": [ + "agent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "tool": { + "name": "tool", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "config": { + "name": "config", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'{}'" + }, + "sensitive": { + "name": "sensitive", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "enabled": { + "name": "enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "builtin": { + "name": "builtin", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "tool_workspace_id_workspace_id_fk": { + "name": "tool_workspace_id_workspace_id_fk", + "tableFrom": "tool", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "video_generation_job": { + "name": "video_generation_job", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "chat_id": { + "name": "chat_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "prompt": { + "name": "prompt", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "model": { + "name": "model", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'queued'" + }, + "progress": { + "name": "progress", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "size": { + "name": "size", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "seconds": { + "name": "seconds", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "auto": { + "name": "auto", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "external_job_id": { + "name": "external_job_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "library_file_id": { + "name": "library_file_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "poster_library_file_id": { + "name": "poster_library_file_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "video_generation_job_workspace_id_workspace_id_fk": { + "name": "video_generation_job_workspace_id_workspace_id_fk", + "tableFrom": "video_generation_job", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "video_generation_job_library_file_id_library_file_id_fk": { + "name": "video_generation_job_library_file_id_library_file_id_fk", + "tableFrom": "video_generation_job", + "tableTo": "library_file", + "columnsFrom": [ + "library_file_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "video_generation_job_poster_library_file_id_library_file_id_fk": { + "name": "video_generation_job_poster_library_file_id_library_file_id_fk", + "tableFrom": "video_generation_job", + "tableTo": "library_file", + "columnsFrom": [ + "poster_library_file_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "workflow": { + "name": "workflow", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "definition": { + "name": "definition", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_workspace_id_workspace_id_fk": { + "name": "workflow_workspace_id_workspace_id_fk", + "tableFrom": "workflow", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "workflow_run": { + "name": "workflow_run", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'queued'" + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "started_at": { + "name": "started_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "completed_at": { + "name": "completed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_run_workflow_id_workflow_id_fk": { + "name": "workflow_run_workflow_id_workflow_id_fk", + "tableFrom": "workflow_run", + "tableTo": "workflow", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_run_workspace_id_workspace_id_fk": { + "name": "workflow_run_workspace_id_workspace_id_fk", + "tableFrom": "workflow_run", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "workflow_run_node": { + "name": "workflow_run_node", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "run_id": { + "name": "run_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "node_id": { + "name": "node_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'queued'" + }, + "progress": { + "name": "progress", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "library_file_id": { + "name": "library_file_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "started_at": { + "name": "started_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "completed_at": { + "name": "completed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_run_node_run_id_workflow_run_id_fk": { + "name": "workflow_run_node_run_id_workflow_run_id_fk", + "tableFrom": "workflow_run_node", + "tableTo": "workflow_run", + "columnsFrom": [ + "run_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_run_node_library_file_id_library_file_id_fk": { + "name": "workflow_run_node_library_file_id_library_file_id_fk", + "tableFrom": "workflow_run_node", + "tableTo": "library_file", + "columnsFrom": [ + "library_file_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "workspace": { + "name": "workspace", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "custom_instructions": { + "name": "custom_instructions", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "icon": { + "name": "icon", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "color": { + "name": "color", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "default_model_id": { + "name": "default_model_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "default_autonomy_level": { + "name": "default_autonomy_level", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'assisted'" + }, + "default_tool_policy": { + "name": "default_tool_policy", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "workspace_user_id_user_id_fk": { + "name": "workspace_user_id_user_id_fk", + "tableFrom": "workspace", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "account": { + "name": "account", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "account_id": { + "name": "account_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "access_token_expires_at": { + "name": "access_token_expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "refresh_token_expires_at": { + "name": "refresh_token_expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "account_user_id_user_id_fk": { + "name": "account_user_id_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "session": { + "name": "session", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "session_token_unique": { + "name": "session_token_unique", + "columns": [ + "token" + ], + "isUnique": true + } + }, + "foreignKeys": { + "session_user_id_user_id_fk": { + "name": "session_user_id_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user": { + "name": "user", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email_verified": { + "name": "email_verified", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "user_email_unique": { + "name": "user_email_unique", + "columns": [ + "email" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "verification": { + "name": "verification", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} \ No newline at end of file diff --git a/packages/db/drizzle/sqlite/meta/_journal.json b/packages/db/drizzle/sqlite/meta/_journal.json index fd0f7cf..2343226 100644 --- a/packages/db/drizzle/sqlite/meta/_journal.json +++ b/packages/db/drizzle/sqlite/meta/_journal.json @@ -274,6 +274,13 @@ "when": 1783067654369, "tag": "0038_brown_silk_fever", "breakpoints": true + }, + { + "idx": 39, + "version": "6", + "when": 1783073684791, + "tag": "0039_dazzling_gressill", + "breakpoints": true } ] } \ No newline at end of file diff --git a/packages/db/src/crypto.test.ts b/packages/db/src/crypto.test.ts index 8775501..0fc1945 100644 --- a/packages/db/src/crypto.test.ts +++ b/packages/db/src/crypto.test.ts @@ -1,5 +1,12 @@ import { describe, expect, test } from "bun:test"; -import { decrypt, decryptNullable, encrypt, encryptNullable } from "./crypto"; +import { + decrypt, + decryptJsonNullable, + decryptNullable, + encrypt, + encryptJsonNullable, + encryptNullable, +} from "./crypto"; describe("crypto", () => { test("encrypt then decrypt round-trips the original plaintext", () => { @@ -44,4 +51,19 @@ describe("crypto", () => { expect(encrypted).not.toBeNull(); expect(decryptNullable(encrypted)).toBe("obsidian-key-abc"); }); + + test("encryptJsonNullable/decryptJsonNullable pass through null and undefined", () => { + expect(encryptJsonNullable(null)).toBeNull(); + expect(encryptJsonNullable(undefined)).toBeNull(); + expect(decryptJsonNullable(null)).toBeNull(); + expect(decryptJsonNullable(undefined)).toBeNull(); + }); + + test("encryptJsonNullable/decryptJsonNullable round-trip an object", () => { + const oauthState = { accessToken: "at-123", refreshToken: "rt-456", expiresAt: 1234567890 }; + const encrypted = encryptJsonNullable(oauthState); + expect(encrypted).not.toBeNull(); + expect(encrypted).not.toContain("at-123"); + expect(decryptJsonNullable(encrypted)).toEqual(oauthState); + }); }); diff --git a/packages/db/src/crypto.ts b/packages/db/src/crypto.ts index f97b30f..443f4e4 100644 --- a/packages/db/src/crypto.ts +++ b/packages/db/src/crypto.ts @@ -69,3 +69,19 @@ export function decryptNullable(value: string | null | undefined): string | null if (value === null || value === undefined) return null; return decrypt(value); } + +/** + * Same as `encryptNullable`/`decryptNullable` but for JSON-shaped secret + * columns (mcpServer.env, mcpServer.oauthState) — stringifies before + * encrypting, parses after decrypting, so the column stores an opaque + * encrypted string instead of a plaintext jsonb/json value. + */ +export function encryptJsonNullable(value: T | null | undefined): string | null { + if (value === null || value === undefined) return null; + return encrypt(JSON.stringify(value)); +} + +export function decryptJsonNullable(value: string | null | undefined): T | null { + if (value === null || value === undefined) return null; + return JSON.parse(decrypt(value)) as T; +} diff --git a/packages/db/src/repo/pg.repo.ts b/packages/db/src/repo/pg.repo.ts index 42a8715..d86ed4a 100644 --- a/packages/db/src/repo/pg.repo.ts +++ b/packages/db/src/repo/pg.repo.ts @@ -2,7 +2,12 @@ import { randomUUID } from "node:crypto"; import { and, asc, desc, eq, gte, inArray, isNotNull, isNull, lte, or } from "drizzle-orm"; import { drizzle } from "drizzle-orm/postgres-js"; import postgres from "postgres"; -import { decryptNullable, encryptNullable } from "../crypto"; +import { + decryptJsonNullable, + decryptNullable, + encryptJsonNullable, + encryptNullable, +} from "../crypto"; import * as schema from "../schema/pg"; import { normalizeChatWorkingDirectory } from "../working-directory"; import type { DbRepository } from "./types"; @@ -121,6 +126,14 @@ export function createPgRepository(connectionString: string): DbRepository { return row; } + function mapMcpServer(row: typeof schema.mcpServer.$inferSelect) { + return { + ...row, + env: decryptJsonNullable>(row.env), + oauthState: decryptJsonNullable>(row.oauthState), + }; + } + function mapAgentRun(row: typeof schema.agentRun.$inferSelect) { return row; } @@ -1184,6 +1197,9 @@ export function createPgRepository(connectionString: string): DbRepository { errorMessage, startedAt, completedAt, + workerId, + heartbeatAt, + leaseUntil, }) { const [row] = await db .insert(schema.agentRun) @@ -1203,6 +1219,9 @@ export function createPgRepository(connectionString: string): DbRepository { startedAt: startedAt ?? null, completedAt: completedAt ?? null, updatedAt: new Date(), + workerId: workerId ?? null, + heartbeatAt: heartbeatAt ?? null, + leaseUntil: leaseUntil ?? null, }) .returning(); if (!row) throw new Error("Failed to create agent run"); @@ -1259,6 +1278,19 @@ export function createPgRepository(connectionString: string): DbRepository { return rows.map(mapAgentRun); }, + async listStaleRunningAgentRuns(now) { + const rows = await db + .select() + .from(schema.agentRun) + .where( + and( + eq(schema.agentRun.status, "running"), + or(isNull(schema.agentRun.leaseUntil), lte(schema.agentRun.leaseUntil, now)), + ), + ); + return rows.map(mapAgentRun); + }, + async updateAgentRun(id, input) { const [row] = await db .update(schema.agentRun) @@ -1269,6 +1301,12 @@ export function createPgRepository(connectionString: string): DbRepository { ...(input.errorMessage !== undefined ? { errorMessage: input.errorMessage } : {}), ...(input.startedAt !== undefined ? { startedAt: input.startedAt } : {}), ...(input.completedAt !== undefined ? { completedAt: input.completedAt } : {}), + ...(input.workerId !== undefined ? { workerId: input.workerId } : {}), + ...(input.heartbeatAt !== undefined ? { heartbeatAt: input.heartbeatAt } : {}), + ...(input.leaseUntil !== undefined ? { leaseUntil: input.leaseUntil } : {}), + ...(input.cancelRequestedAt !== undefined + ? { cancelRequestedAt: input.cancelRequestedAt } + : {}), updatedAt: new Date(), }) .where(eq(schema.agentRun.id, id)) @@ -1288,25 +1326,26 @@ export function createPgRepository(connectionString: string): DbRepository { command: command ?? null, args: args ?? null, url: url ?? null, - env: env ?? null, + env: encryptJsonNullable(env), }) .returning(); if (!row) throw new Error("Failed to create MCP server"); - return row; + return mapMcpServer(row); }, async listMcpServersByWorkspace(workspaceId) { - return db + const rows = await db .select() .from(schema.mcpServer) .where(eq(schema.mcpServer.workspaceId, workspaceId)); + return rows.map(mapMcpServer); }, async getMcpServer(id) { const row = await db.query.mcpServer.findFirst({ where: eq(schema.mcpServer.id, id), }); - return row ?? null; + return row ? mapMcpServer(row) : null; }, async deleteMcpServer(id) { @@ -1314,7 +1353,10 @@ export function createPgRepository(connectionString: string): DbRepository { }, async updateMcpServerOAuthState(id, oauthState) { - await db.update(schema.mcpServer).set({ oauthState }).where(eq(schema.mcpServer.id, id)); + await db + .update(schema.mcpServer) + .set({ oauthState: encryptJsonNullable(oauthState) }) + .where(eq(schema.mcpServer.id, id)); }, async getKnowledgeBaseConfig(workspaceId) { diff --git a/packages/db/src/repo/secrets-encryption.test.ts b/packages/db/src/repo/secrets-encryption.test.ts new file mode 100644 index 0000000..3aaadaa --- /dev/null +++ b/packages/db/src/repo/secrets-encryption.test.ts @@ -0,0 +1,145 @@ +import { Database } from "bun:sqlite"; +import { afterEach, beforeEach, describe, expect, test } from "bun:test"; +import { createTestSqliteRepository, createTestUser } from "../test-utils"; +import type { DbRepository } from "./types"; + +let ctx: Awaited>; +let db: DbRepository; + +beforeEach(async () => { + ctx = await createTestSqliteRepository(); + db = ctx.db; +}); + +afterEach(async () => { + await ctx.cleanup(); +}); + +function readRawColumn( + path: string, + table: string, + column: string, + where: { column: string; value: string }, +): unknown { + const sqlite = new Database(path); + try { + const row = sqlite + .query(`SELECT ${column} FROM ${table} WHERE ${where.column} = ?`) + .get(where.value) as Record | undefined; + return row?.[column]; + } finally { + sqlite.close(); + } +} + +describe("secrets are encrypted at rest (SECURITY_AUDIT.md SEC-01)", () => { + test("modelInstallation.apiKey is stored encrypted, decrypted on read", async () => { + const user = createTestUser(ctx.path); + const workspace = await db.createWorkspace({ userId: user.id, name: "Test workspace" }); + const installation = await db.createModelInstallation({ + workspaceId: workspace.id, + label: "OpenAI", + providerKind: "openai", + baseUrl: "https://api.openai.com/v1", + apiKey: "sk-live-super-secret", + modelIds: ["gpt-5"], + }); + + const raw = readRawColumn(ctx.path, "model_installation", "api_key", { + column: "id", + value: installation.id, + }); + expect(raw).not.toBe("sk-live-super-secret"); + expect(String(raw)).toStartWith("v1:"); + + const fetched = await db.getModelInstallation(installation.id); + expect(fetched?.apiKey).toBe("sk-live-super-secret"); + }); + + test("knowledgeBaseConfig.obsidianApiKey is stored encrypted, decrypted on read", async () => { + const user = createTestUser(ctx.path); + const workspace = await db.createWorkspace({ userId: user.id, name: "Test workspace" }); + await db.upsertKnowledgeBaseConfig({ + workspaceId: workspace.id, + vaultPath: "knowledge-base", + obsidianApiKey: "obsidian-live-secret", + }); + + const raw = readRawColumn(ctx.path, "knowledge_base_config", "obsidian_api_key", { + column: "workspace_id", + value: workspace.id, + }); + expect(raw).not.toBe("obsidian-live-secret"); + expect(String(raw)).toStartWith("v1:"); + + const fetched = await db.getKnowledgeBaseConfig(workspace.id); + expect(fetched?.obsidianApiKey).toBe("obsidian-live-secret"); + }); + + test("mcpServer.env is stored encrypted, decrypted on read", async () => { + const user = createTestUser(ctx.path); + const workspace = await db.createWorkspace({ userId: user.id, name: "Test workspace" }); + const server = await db.createMcpServer({ + workspaceId: workspace.id, + name: "Local stdio server", + transport: "stdio", + command: "npx", + args: ["some-mcp-server"], + env: { API_TOKEN: "env-live-secret" }, + }); + + const raw = readRawColumn(ctx.path, "mcp_server", "env", { + column: "id", + value: server.id, + }); + expect(String(raw)).not.toContain("env-live-secret"); + expect(String(raw)).toStartWith("v1:"); + + const fetched = await db.getMcpServer(server.id); + expect(fetched?.env).toEqual({ API_TOKEN: "env-live-secret" }); + }); + + test("mcpServer.oauthState is stored encrypted, decrypted on read", async () => { + const user = createTestUser(ctx.path); + const workspace = await db.createWorkspace({ userId: user.id, name: "Test workspace" }); + const server = await db.createMcpServer({ + workspaceId: workspace.id, + name: "Remote http server", + transport: "http", + url: "https://example.test/mcp", + }); + await db.updateMcpServerOAuthState(server.id, { + accessToken: "at-live-secret", + refreshToken: "rt-live-secret", + }); + + const raw = readRawColumn(ctx.path, "mcp_server", "oauth_state", { + column: "id", + value: server.id, + }); + expect(String(raw)).not.toContain("at-live-secret"); + expect(String(raw)).not.toContain("rt-live-secret"); + expect(String(raw)).toStartWith("v1:"); + + const fetched = await db.getMcpServer(server.id); + expect(fetched?.oauthState).toEqual({ + accessToken: "at-live-secret", + refreshToken: "rt-live-secret", + }); + }); + + test("mcpServer.env round-trips null (stdio servers with no extra env)", async () => { + const user = createTestUser(ctx.path); + const workspace = await db.createWorkspace({ userId: user.id, name: "Test workspace" }); + const server = await db.createMcpServer({ + workspaceId: workspace.id, + name: "No-env server", + transport: "http", + url: "https://example.test/mcp", + }); + + const fetched = await db.getMcpServer(server.id); + expect(fetched?.env).toBeNull(); + expect(fetched?.oauthState).toBeNull(); + }); +}); diff --git a/packages/db/src/repo/sqlite.repo.ts b/packages/db/src/repo/sqlite.repo.ts index cd21dac..5f45dc0 100644 --- a/packages/db/src/repo/sqlite.repo.ts +++ b/packages/db/src/repo/sqlite.repo.ts @@ -2,7 +2,12 @@ import { Database } from "bun:sqlite"; import { randomUUID } from "node:crypto"; import { and, asc, desc, eq, gte, inArray, isNotNull, isNull, lte, or } from "drizzle-orm"; import { drizzle } from "drizzle-orm/bun-sqlite"; -import { decryptNullable, encryptNullable } from "../crypto"; +import { + decryptJsonNullable, + decryptNullable, + encryptJsonNullable, + encryptNullable, +} from "../crypto"; import * as schema from "../schema/sqlite"; import { normalizeChatWorkingDirectory } from "../working-directory"; import type { DbRepository } from "./types"; @@ -149,6 +154,14 @@ export function createSqliteRepository(filePath: string): DbRepository { return row; } + function mapMcpServer(row: typeof schema.mcpServer.$inferSelect) { + return { + ...row, + env: decryptJsonNullable>(row.env), + oauthState: decryptJsonNullable>(row.oauthState), + }; + } + function mapAgentRun(row: typeof schema.agentRun.$inferSelect) { return row; } @@ -1317,6 +1330,9 @@ export function createSqliteRepository(filePath: string): DbRepository { errorMessage, startedAt, completedAt, + workerId, + heartbeatAt, + leaseUntil, }) { const now = new Date(); const row = db @@ -1338,6 +1354,9 @@ export function createSqliteRepository(filePath: string): DbRepository { startedAt: startedAt ?? null, completedAt: completedAt ?? null, updatedAt: now, + workerId: workerId ?? null, + heartbeatAt: heartbeatAt ?? null, + leaseUntil: leaseUntil ?? null, }) .returning() .get(); @@ -1396,6 +1415,20 @@ export function createSqliteRepository(filePath: string): DbRepository { return rows.map(mapAgentRun); }, + async listStaleRunningAgentRuns(now) { + const rows = db + .select() + .from(schema.agentRun) + .where( + and( + eq(schema.agentRun.status, "running"), + or(isNull(schema.agentRun.leaseUntil), lte(schema.agentRun.leaseUntil, now)), + ), + ) + .all(); + return rows.map(mapAgentRun); + }, + async updateAgentRun(id, input) { const row = db .update(schema.agentRun) @@ -1406,6 +1439,12 @@ export function createSqliteRepository(filePath: string): DbRepository { ...(input.errorMessage !== undefined ? { errorMessage: input.errorMessage } : {}), ...(input.startedAt !== undefined ? { startedAt: input.startedAt } : {}), ...(input.completedAt !== undefined ? { completedAt: input.completedAt } : {}), + ...(input.workerId !== undefined ? { workerId: input.workerId } : {}), + ...(input.heartbeatAt !== undefined ? { heartbeatAt: input.heartbeatAt } : {}), + ...(input.leaseUntil !== undefined ? { leaseUntil: input.leaseUntil } : {}), + ...(input.cancelRequestedAt !== undefined + ? { cancelRequestedAt: input.cancelRequestedAt } + : {}), updatedAt: new Date(), }) .where(eq(schema.agentRun.id, id)) @@ -1426,25 +1465,26 @@ export function createSqliteRepository(filePath: string): DbRepository { command: command ?? null, args: args ?? null, url: url ?? null, - env: env ?? null, + env: encryptJsonNullable(env), createdAt: new Date(), }) .returning() .get(); - return row; + return mapMcpServer(row); }, async listMcpServersByWorkspace(workspaceId) { - return db + const rows = db .select() .from(schema.mcpServer) .where(eq(schema.mcpServer.workspaceId, workspaceId)) .all(); + return rows.map(mapMcpServer); }, async getMcpServer(id) { const row = db.select().from(schema.mcpServer).where(eq(schema.mcpServer.id, id)).get(); - return row ?? null; + return row ? mapMcpServer(row) : null; }, async deleteMcpServer(id) { @@ -1452,7 +1492,10 @@ export function createSqliteRepository(filePath: string): DbRepository { }, async updateMcpServerOAuthState(id, oauthState) { - db.update(schema.mcpServer).set({ oauthState }).where(eq(schema.mcpServer.id, id)).run(); + db.update(schema.mcpServer) + .set({ oauthState: encryptJsonNullable(oauthState) }) + .where(eq(schema.mcpServer.id, id)) + .run(); }, async getKnowledgeBaseConfig(workspaceId) { diff --git a/packages/db/src/repo/types.ts b/packages/db/src/repo/types.ts index 8804915..22e7161 100644 --- a/packages/db/src/repo/types.ts +++ b/packages/db/src/repo/types.ts @@ -397,6 +397,17 @@ export interface AgentRunRecord { startedAt: Date | null; completedAt: Date | null; updatedAt: Date; + /** Process id that currently owns this run — see agent-runtime.ts. */ + workerId: string | null; + /** Last time the owning process renewed its lease on this run. */ + heartbeatAt: Date | null; + /** Run is considered stale (owning process presumed dead) once this + * passes without a renewed heartbeat. */ + leaseUntil: Date | null; + /** Set by cancelAgentRun regardless of whether the owning process's + * in-memory AbortController was reachable — a DB-visible cancellation + * signal that survives a process restart. */ + cancelRequestedAt: Date | null; } export interface UserRecord { @@ -1188,6 +1199,9 @@ export interface DbRepository { errorMessage?: string | null; startedAt?: Date | null; completedAt?: Date | null; + workerId?: string | null; + heartbeatAt?: Date | null; + leaseUntil?: Date | null; }): Promise; getAgentRun(id: string): Promise; /** Every run in the workspace regardless of status, newest first — @@ -1203,6 +1217,10 @@ export interface DbRepository { /** Runs with status "pending" | "running" | "waiting_approval" — powers * the "currently running" indicator on the agents list page. */ listActiveAgentRunsByWorkspace(workspaceId: string): Promise; + /** Every run still "running" whose lease has expired (or was never + * granted a lease at all, e.g. pre-dates this feature) — the stale-run + * sweep's input, across every workspace, not scoped to one. */ + listStaleRunningAgentRuns(now: Date): Promise; updateAgentRun( id: string, input: { @@ -1212,6 +1230,10 @@ export interface DbRepository { errorMessage?: string | null; startedAt?: Date | null; completedAt?: Date | null; + workerId?: string | null; + heartbeatAt?: Date | null; + leaseUntil?: Date | null; + cancelRequestedAt?: Date | null; }, ): Promise; diff --git a/packages/db/src/schema/pg/app.ts b/packages/db/src/schema/pg/app.ts index f05d6b8..7936dc3 100644 --- a/packages/db/src/schema/pg/app.ts +++ b/packages/db/src/schema/pg/app.ts @@ -369,14 +369,17 @@ export const mcpServer = pgTable("mcp_server", { url: text("url"), /** Extra env vars for stdio servers only, e.g. a path to an OAuth * credentials file a local command needs to read. Never sent to http - * servers — those authenticate via OAuth, not process env. */ - env: jsonb("env").$type>(), + * servers — those authenticate via OAuth, not process env. Stored as + * AES-256-GCM-encrypted JSON (see packages/db/src/crypto.ts) since this + * can carry live credentials — encrypted/decrypted at the repo layer. */ + env: text("env"), /** Persisted OAuth session for http servers — dynamic client registration * result, access/refresh tokens, PKCE state. Without this, every server * restart drops the in-memory OAuth provider and forces re-authorization * for every previously-connected http connector. Opaque blob because the - * shape belongs to @modelcontextprotocol/sdk, not this schema. */ - oauthState: jsonb("oauth_state").$type>(), + * shape belongs to @modelcontextprotocol/sdk, not this schema. Stored as + * AES-256-GCM-encrypted JSON, same as `env` above. */ + oauthState: text("oauth_state"), enabled: boolean("enabled").notNull().default(true), createdAt: timestamp("created_at").notNull().defaultNow(), }); @@ -679,6 +682,14 @@ export const agentRun = pgTable("agent_run", { startedAt: timestamp("started_at"), completedAt: timestamp("completed_at"), updatedAt: timestamp("updated_at").notNull().defaultNow(), + // Durable run recovery (see apps/server/src/agent-runtime.ts): a + // process-identifying id, a periodically-renewed lease, and a + // cancellation flag that's visible in the DB even if the process that + // owns the run's in-memory AbortController has died or isn't this one. + workerId: text("worker_id"), + heartbeatAt: timestamp("heartbeat_at"), + leaseUntil: timestamp("lease_until"), + cancelRequestedAt: timestamp("cancel_requested_at"), }); export const taskEvent = pgTable("task_event", { diff --git a/packages/db/src/schema/sqlite/app.ts b/packages/db/src/schema/sqlite/app.ts index e8b9d48..a814c61 100644 --- a/packages/db/src/schema/sqlite/app.ts +++ b/packages/db/src/schema/sqlite/app.ts @@ -382,14 +382,17 @@ export const mcpServer = sqliteTable("mcp_server", { url: text("url"), /** Extra env vars for stdio servers only, e.g. a path to an OAuth * credentials file a local command needs to read. Never sent to http - * servers — those authenticate via OAuth, not process env. */ - env: text("env", { mode: "json" }).$type>(), + * servers — those authenticate via OAuth, not process env. Stored as + * AES-256-GCM-encrypted JSON (see packages/db/src/crypto.ts) since this + * can carry live credentials — encrypted/decrypted at the repo layer. */ + env: text("env"), /** Persisted OAuth session for http servers — dynamic client registration * result, access/refresh tokens, PKCE state. Without this, every server * restart drops the in-memory OAuth provider and forces re-authorization * for every previously-connected http connector. Opaque blob because the - * shape belongs to @modelcontextprotocol/sdk, not this schema. */ - oauthState: text("oauth_state", { mode: "json" }).$type>(), + * shape belongs to @modelcontextprotocol/sdk, not this schema. Stored as + * AES-256-GCM-encrypted JSON, same as `env` above. */ + oauthState: text("oauth_state"), enabled: integer("enabled", { mode: "boolean" }).notNull().default(true), createdAt: integer("created_at", { mode: "timestamp" }).notNull(), }); @@ -615,6 +618,14 @@ export const agentRun = sqliteTable("agent_run", { startedAt: integer("started_at", { mode: "timestamp" }), completedAt: integer("completed_at", { mode: "timestamp" }), updatedAt: integer("updated_at", { mode: "timestamp" }).notNull(), + // Durable run recovery (see apps/server/src/agent-runtime.ts): a + // process-identifying id, a periodically-renewed lease, and a + // cancellation flag that's visible in the DB even if the process that + // owns the run's in-memory AbortController has died or isn't this one. + workerId: text("worker_id"), + heartbeatAt: integer("heartbeat_at", { mode: "timestamp" }), + leaseUntil: integer("lease_until", { mode: "timestamp" }), + cancelRequestedAt: integer("cancel_requested_at", { mode: "timestamp" }), }); export const taskEvent = sqliteTable("task_event", { diff --git a/packages/model-providers/src/detect.test.ts b/packages/model-providers/src/detect.test.ts new file mode 100644 index 0000000..c686954 --- /dev/null +++ b/packages/model-providers/src/detect.test.ts @@ -0,0 +1,196 @@ +import { afterEach, describe, expect, it } from "bun:test"; +import { + detectLmStudioModels, + detectLocalModels, + detectOllamaModels, + detectOpenAiCompatibleModels, +} from "./detect"; + +/** All tests here stub `globalThis.fetch` so the local-runtime probes never + * hit a real port (Ollama :11434, LM Studio :1234, vLLM :8000, LocalAI :8080, + * llama.cpp :8081, text-generation-webui :5000, Jan :1337) — see the + * `safeFetchJson` helper in ./detect.ts that these functions funnel through. */ + +type FetchHandler = (url: string, init?: RequestInit) => Response | null; + +function installFetchMock(handler: FetchHandler): typeof fetch { + return (async (input: RequestInfo | URL, init?: RequestInit) => { + const url = typeof input === "string" ? input : input.toString(); + const response = handler(url, init); + if (!response) throw new TypeError(`fetch failed: connection refused (${url})`); + return response; + }) as typeof fetch; +} + +function json(body: unknown, status = 200): Response { + return new Response(JSON.stringify(body), { status }); +} + +const originalFetch = globalThis.fetch; +const originalLmStudioBaseUrl = process.env.LMSTUDIO_BASE_URL; + +afterEach(() => { + globalThis.fetch = originalFetch; + if (originalLmStudioBaseUrl === undefined) { + delete process.env.LMSTUDIO_BASE_URL; + } else { + process.env.LMSTUDIO_BASE_URL = originalLmStudioBaseUrl; + } +}); + +describe("detectOllamaModels", () => { + it("returns parsed models with capabilities on a successful probe", async () => { + globalThis.fetch = installFetchMock((url, init) => { + if (url === "http://localhost:11434/api/tags") { + return json({ models: [{ name: "llama3.1:8b" }] }); + } + if (url === "http://localhost:11434/api/show" && init?.method === "POST") { + return json({ capabilities: ["completion", "tools", "vision"] }); + } + return null; + }); + + const models = await detectOllamaModels(); + + expect(models).toEqual([ + { + id: "ollama/llama3.1:8b", + label: "llama3.1:8b", + provider: "ollama", + providerLabel: "Ollama", + baseUrl: "http://localhost:11434/v1", + capabilities: { + visionInput: true, + toolCalling: true, + reasoning: false, + imageOutput: false, + }, + }, + ]); + }); + + it("returns an empty array instead of throwing when Ollama isn't running", async () => { + globalThis.fetch = installFetchMock(() => null); + + const models = await detectOllamaModels(); + + expect(models).toEqual([]); + }); +}); + +describe("detectLmStudioModels", () => { + it("returns chat-capable models enriched from LM Studio's native endpoint", async () => { + process.env.LMSTUDIO_BASE_URL = "http://localhost:19234"; + globalThis.fetch = installFetchMock((url) => { + if (url === "http://localhost:19234/v1/models") { + return json({ data: [{ id: "llama-3-8b-instruct" }] }); + } + if (url === "http://localhost:19234/api/v0/models") { + return json({ + data: [ + { + id: "llama-3-8b-instruct", + type: "llm", + capabilities: { trained_for_tool_use: true }, + }, + ], + }); + } + return null; + }); + + const models = await detectLmStudioModels(); + + expect(models).toEqual([ + { + id: "lmstudio/llama-3-8b-instruct", + label: "llama-3-8b-instruct", + provider: "lmstudio", + providerLabel: "LM Studio", + baseUrl: "http://localhost:19234/v1", + capabilities: { + visionInput: false, + toolCalling: true, + reasoning: false, + imageOutput: false, + }, + }, + ]); + }); + + it("returns an empty array instead of throwing when LM Studio isn't running", async () => { + process.env.LMSTUDIO_BASE_URL = "http://localhost:19235"; + globalThis.fetch = installFetchMock(() => null); + + const models = await detectLmStudioModels(); + + expect(models).toEqual([]); + }); +}); + +describe("detectOpenAiCompatibleModels", () => { + it("detects a runtime on one of the known ports while the rest are unreachable", async () => { + globalThis.fetch = installFetchMock((url) => { + if (url === "http://localhost:8080/v1/models") { + return json({ data: [{ id: "mistral-7b-instruct" }] }); + } + // LocalAI has no native LM Studio-style or Ollama-style capability + // endpoint, so both enrichment probes against it are expected to + // fail — the function must still return the bare model list. + return null; + }); + + const models = await detectOpenAiCompatibleModels(); + + expect(models).toEqual([ + { + id: "localai/mistral-7b-instruct", + label: "mistral-7b-instruct", + provider: "localai", + providerLabel: "LocalAI", + baseUrl: "http://localhost:8080/v1", + capabilities: undefined, + }, + ]); + }); + + it("returns an empty array when none of the known local ports respond", async () => { + globalThis.fetch = installFetchMock(() => null); + + const models = await detectOpenAiCompatibleModels(); + + expect(models).toEqual([]); + }); +}); + +describe("detectLocalModels", () => { + it("merges Ollama and OpenAI-compatible detections", async () => { + globalThis.fetch = installFetchMock((url, init) => { + if (url === "http://localhost:11434/api/tags") { + return json({ models: [{ name: "llama3.1:8b" }] }); + } + if (url === "http://localhost:11434/api/show" && init?.method === "POST") { + return json({ capabilities: [] }); + } + if (url === "http://localhost:8080/v1/models") { + return json({ data: [{ id: "mistral-7b-instruct" }] }); + } + return null; + }); + + const models = await detectLocalModels(); + + expect(models.map((m) => m.id).sort()).toEqual([ + "localai/mistral-7b-instruct", + "ollama/llama3.1:8b", + ]); + }); + + it("returns an empty array when nothing is reachable", async () => { + globalThis.fetch = installFetchMock(() => null); + + const models = await detectLocalModels(); + + expect(models).toEqual([]); + }); +}); diff --git a/tests/db_migration.test.ts b/tests/db_migration.test.ts deleted file mode 100644 index 40d90c1..0000000 --- a/tests/db_migration.test.ts +++ /dev/null @@ -1,18 +0,0 @@ -// tests/db_migration.test.ts -import { initializeDatabase, applyMigrations } from '../services/db'; - -describe('Database Migrations', () => { - beforeAll(() => { - // Setup testing environment with an in-memory database instance - }); - - it('should apply the initial schema migration (0008) without conflict', async () => { - await applyMigrations(); - // Verify that required tables (e.g., 'skills', 'notes') exist and are populated correctly - // Check schema against the target state defined in migration file.sql - }); - - it('should handle idempotent migrations gracefully', async () => { - await applyMigrations(); // Run a second time to ensure no errors occur if already applied - }); -}); \ No newline at end of file diff --git a/tests/kb_context_injector.test.ts b/tests/kb_context_injector.test.ts deleted file mode 100644 index 610fe00..0000000 --- a/tests/kb_context_injector.test.ts +++ /dev/null @@ -1,19 +0,0 @@ -// tests/kb_context_injector.test.ts -import { KnowledgeBaseService } from '../services/knowledge-base'; - -describe('Knowledge Base Context Injection', () => { - const service = new KnowledgeBaseService(); - - it('should generate a bounded context chunk when exceeding the minimum note count', async () => { - // Mock recent notes data (simulating the 'note index' content) - const mockRecentNotes = [/* ... 3 notes ... */]; - const context = await service.getKnowledgeBaseContextForPrompt(mockRecentNotes); - - // Assert that the generated context block is present and correctly formatted for prompt injection. - expect(context).toContain("bounded context block"); - }); - - it('should correctly truncate content when nearing the maximum character cap (~6000 char)', async () => { - // Test case where input is massive but output must be capped. This ensures the bounding logic works. - }); -}); \ No newline at end of file diff --git a/tests/skill_file_read.test.ts b/tests/skill_file_read.test.ts deleted file mode 100644 index 9824b37..0000000 --- a/tests/skill_file_read.test.ts +++ /dev/null @@ -1,20 +0,0 @@ -// tests/skill_file_read.test.ts -import { SkillContext, TestData } from '../types'; -import { FileReadSkill } from './skills/FileReadSkill'; - -describe('File Read Skill', () => { - it('should successfully read content of an existing file path', async () => { - const mockData: TestData = { content: "Hello, NyxelOS!" }; - // Mock the underlying file system access function - const fsAccess = jest.fn(() => Promise.resolve(mockData)); - - const skillInstance = new FileReadSkill({ fsAccess }); - - const result = await skillInstance.execute('/path/to/local/file'); - expect(result).toEqual(mockData.content); - }); - - it('should handle File Not Found errors gracefully', async () => { - // Test case for non-existent paths - }); -}); \ No newline at end of file diff --git a/tests/skill_http_fetch.test.ts b/tests/skill_http_fetch.test.ts deleted file mode 100644 index a32db65..0000000 --- a/tests/skill_http_fetch.test.ts +++ /dev/null @@ -1,20 +0,0 @@ -// tests/skill_http_fetch.test.ts -import { SkillContext, TestData } from '../types'; -import { HttpFetchSkill } from './skills/HttpFetchSkill'; - -describe('HTTP Fetch Skill', () => { - it('should successfully fetch data from a valid endpoint and return status 200', async () => { - const mockResponse = '{"status": "success", "data": "fetched"}'; - // Mock the underlying network call - const networkLayer = jest.fn(() => Promise.resolve({ status: 200, body: mockResponse })); - - const skillInstance = new HttpFetchSkill({ networkLayer }); - - const result = await skillInstance.execute('https://api.example/data'); - expect(result).toContain('"status": "success"'); - }); - - it('should handle 4xx/5xx server errors gracefully', async () => { - // Test case for connection timeouts or bad status codes - }); -}); \ No newline at end of file diff --git a/tests/skill_registry.test.ts b/tests/skill_registry.test.ts deleted file mode 100644 index ce00b07..0000000 --- a/tests/skill_registry.test.ts +++ /dev/null @@ -1,20 +0,0 @@ -// tests/skill_registry.test.ts -import { SkillRegistry } from '../server/src/skills-registry'; - -describe('Skill Registry Merging', () => { - it('should merge dynamic skills into the hardcoded registry correctly', () => { - // Setup: Initialize with base registry (skills-registry.ts) - const registry = new SkillRegistry(); - - // Inject a dynamic skill from the database migration '0008' - const dynamicSkill = { kind: 'file_read', config: {}, sensitive: false }; - registry.addDynamicSkill(dynamicSkill); - - // Assert that both the hardcoded and dynamic skills are available for tool building. - expect(registry.isSkillAvailable('file_read')).toBe(true); - }); - - it('should prioritize permissions/sensitivity flags from the dynamic configuration', () => { - // Test scenario where a dynamically added skill might override or be constrained by existing flags. - }); -}); \ No newline at end of file From 24941e45bf3f76c955fe08d18972754792bf2b6f Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 3 Jul 2026 10:35:16 +0000 Subject: [PATCH 2/2] fix: unblock CI (create-nyxel types, Radix prop typing, stale lint findings) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three pre-existing, repo-wide CI blockers surfaced once this PR's files were touched (Typecheck/Build/Build-web/Lint all fail on origin/main today, independent of this change): - packages/create-nyxel/tsconfig.json: @types/node was a declared devDependency but never auto-included (this TypeScript version doesn't auto-discover @types/* the way earlier versions did) — add the explicit `types: ["node"]` the compiler itself suggests. - apps/web/src/components/ui/dropdown-menu.tsx: onOpenAutoFocus is read and forwarded by @radix-ui/react-menu's content impl at runtime but omitted from this version's public prop type — widen the local wrapper's type to match the real, working API instead of the narrower public one. - apps/web/src/components/workspace-settings-panel.tsx: associate the two preset/model checkbox labels with their inputs via htmlFor/id, and replace a dead `eslint-disable-next-line` (this project uses Biome, not ESLint) with a real biome-ignore for the intentional exhaustive-deps exclusion. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_019tXH1XWxA1CsvoVr29pPHR --- apps/web/src/components/ui/dropdown-menu.tsx | 7 ++- .../components/workspace-settings-panel.tsx | 63 +++++++++++-------- packages/create-nyxel/tsconfig.json | 1 + 3 files changed, 43 insertions(+), 28 deletions(-) diff --git a/apps/web/src/components/ui/dropdown-menu.tsx b/apps/web/src/components/ui/dropdown-menu.tsx index 283bf44..efeddf5 100644 --- a/apps/web/src/components/ui/dropdown-menu.tsx +++ b/apps/web/src/components/ui/dropdown-menu.tsx @@ -26,7 +26,12 @@ function DropdownMenuContent({ align = "start", sideOffset = 4, ...props -}: React.ComponentProps) { +}: React.ComponentProps & { + // Consumed at runtime by the underlying Menu content impl (composed into + // its focus-scope mount handler) but omitted from this Radix version's + // public prop type — see @radix-ui/react-menu's MenuContentImplPrivateProps. + onOpenAutoFocus?: (event: Event) => void; +}) { return ( (query.state.data?.status === "running" ? 1500 : false), }); + // biome-ignore lint/correctness/useExhaustiveDependencies: only re-run when the CLI login process's status changes, not on every statusQuery.refetch identity change (that would refire on every statusQuery re-render). useEffect(() => { if (loginOutputQuery.data?.status === "exited") statusQuery.refetch(); - // eslint-disable-next-line react-hooks/exhaustive-deps }, [loginOutputQuery.data?.status]); const startLogin = useMutation({ @@ -369,19 +369,23 @@ function CliProviderCard({ className="h-8" />
- {presets.map((preset) => ( - - ))} + {presets.map((preset) => { + const inputId = `${kind}-preset-${preset}`; + return ( + + ); + })}
0 && (
- {models.map((model) => ( - - ))} + {models.map((model) => { + const inputId = `openrouter-model-${model.id}`; + return ( + + ); + })}
)} diff --git a/packages/create-nyxel/tsconfig.json b/packages/create-nyxel/tsconfig.json index 7e0deff..267a064 100644 --- a/packages/create-nyxel/tsconfig.json +++ b/packages/create-nyxel/tsconfig.json @@ -3,6 +3,7 @@ "compilerOptions": { "target": "ES2022", "lib": ["ES2022"], + "types": ["node"], "module": "NodeNext", "moduleResolution": "NodeNext", "strict": true,