@open-mercato/ai-assistant 0.6.6-develop.5509.1.006f4d4f24 → 0.6.6-develop.5531.1.ab1959dfae

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/AGENTS.md +12 -0
  3. package/dist/modules/ai_assistant/cli.js +14 -6
  4. package/dist/modules/ai_assistant/cli.js.map +2 -2
  5. package/dist/modules/ai_assistant/data/entities.js +4 -0
  6. package/dist/modules/ai_assistant/data/entities.js.map +2 -2
  7. package/dist/modules/ai_assistant/lib/client-factory.js +0 -8
  8. package/dist/modules/ai_assistant/lib/client-factory.js.map +2 -2
  9. package/dist/modules/ai_assistant/lib/mcp-client.js +2 -4
  10. package/dist/modules/ai_assistant/lib/mcp-client.js.map +2 -2
  11. package/dist/modules/ai_assistant/lib/mcp-dev-key-resolution.js +71 -0
  12. package/dist/modules/ai_assistant/lib/mcp-dev-key-resolution.js.map +7 -0
  13. package/dist/modules/ai_assistant/lib/mcp-dev-server.js +1 -30
  14. package/dist/modules/ai_assistant/lib/mcp-dev-server.js.map +2 -2
  15. package/dist/modules/ai_assistant/lib/mcp-server.js +29 -23
  16. package/dist/modules/ai_assistant/lib/mcp-server.js.map +2 -2
  17. package/package.json +6 -6
  18. package/src/modules/ai_assistant/__tests__/cli-mcp-serve-key.test.ts +63 -0
  19. package/src/modules/ai_assistant/cli.ts +18 -5
  20. package/src/modules/ai_assistant/data/__tests__/schema-unique-indexes.test.ts +39 -0
  21. package/src/modules/ai_assistant/data/entities.ts +5 -0
  22. package/src/modules/ai_assistant/lib/__tests__/client-factory.test.ts +42 -0
  23. package/src/modules/ai_assistant/lib/__tests__/mcp-client.test.ts +20 -1
  24. package/src/modules/ai_assistant/lib/__tests__/mcp-dev-key-resolution.test.ts +92 -0
  25. package/src/modules/ai_assistant/lib/__tests__/mcp-server-auth-fail-closed.test.ts +133 -0
  26. package/src/modules/ai_assistant/lib/client-factory.ts +3 -9
  27. package/src/modules/ai_assistant/lib/mcp-client.ts +9 -5
  28. package/src/modules/ai_assistant/lib/mcp-dev-key-resolution.ts +107 -0
  29. package/src/modules/ai_assistant/lib/mcp-dev-server.ts +1 -36
  30. package/src/modules/ai_assistant/lib/mcp-server.ts +47 -33
  31. package/src/modules/ai_assistant/lib/types.ts +7 -0
@@ -1,2 +1,2 @@
1
- [build:ai-assistant] found 214 entry points
1
+ [build:ai-assistant] found 215 entry points
2
2
  [build:ai-assistant] built successfully
package/AGENTS.md CHANGED
@@ -1464,6 +1464,18 @@ Agents that need multi-step tool loops configure the `loop` block on `AiAgentDef
1464
1464
 
1465
1465
  ## Changelog
1466
1466
 
1467
+ ### 2026-06-11 - MCP stdio server fails closed without auth (#2673)
1468
+
1469
+ **What changed**:
1470
+ - `createMcpServer` / `runMcpServer` (`lib/mcp-server.ts`) no longer silently grant `isSuperAdmin = true` when no auth is supplied. The two fail-open branches (a `context` without a `userId`, and neither `apiKeySecret` nor `context`) now **throw** instead of escalating to an unscoped superadmin.
1471
+ - `apiKeySecret` is normalized — an empty / whitespace-only string is treated as missing instead of falling through to the unauthenticated branch.
1472
+ - Added an explicit, loud opt-in `McpServerOptions.allowUnauthenticatedSuperadmin` (default off) for local dev/testing. When enabled the server runs as superadmin with a startup `WARNING` log; when off and unauthenticated it refuses to start.
1473
+ - `mcp:serve` CLI: `--user` is now effectively required alongside `--tenant`; the legacy "no user → superadmin" behavior is preserved only behind the new `--allow-unauthenticated-superadmin` flag (documented in `--help`).
1474
+
1475
+ **Files modified**: `lib/mcp-server.ts`, `lib/types.ts`, `cli.ts`. Regression test: `lib/__tests__/mcp-server-auth-fail-closed.test.ts`.
1476
+
1477
+ **Backward compatibility**: `allowUnauthenticatedSuperadmin` is an additive optional field. The only behavior change is that a previously fail-open misconfiguration now fails closed — callers that relied on auth-less superadmin must pass the explicit opt-in.
1478
+
1467
1479
  ### 2026-05-13 - Remove dead `indexApiEndpoints` from MCP boot (#1876)
1468
1480
 
1469
1481
  **What changed**:
@@ -34,28 +34,35 @@ const mcpServe = {
34
34
  command: "mcp:serve",
35
35
  async run(rest) {
36
36
  const args = parseArgs(rest);
37
- const apiKey = String(args["api-key"] ?? args.apiKey ?? "") || null;
37
+ const apiKey = String(args["api-key"] ?? args.apiKey ?? "") || process.env.OPEN_MERCATO_API_KEY || null;
38
38
  const tenantId = String(args.tenant ?? args.tenantId ?? "") || null;
39
39
  const organizationId = String(args.org ?? args.organizationId ?? "") || null;
40
40
  const userId = String(args.user ?? args.userId ?? "") || null;
41
41
  const debug = args.debug === true || args.debug === "true";
42
+ const allowUnauthenticatedSuperadmin = args["allow-unauthenticated-superadmin"] === true || args["allow-unauthenticated-superadmin"] === "true";
42
43
  if (!apiKey && !tenantId) {
43
44
  console.error("Usage: mercato ai_assistant mcp:serve [options]");
44
45
  console.error("");
45
46
  console.error("Authentication (choose one):");
46
- console.error(" --api-key <secret> API key secret for authentication (recommended)");
47
- console.error(" --tenant <id> Tenant ID (for manual context)");
47
+ console.error(" OPEN_MERCATO_API_KEY env API key secret (recommended \u2014 keeps the secret off argv)");
48
+ console.error(" --api-key <secret> API key secret for authentication (visible in process listings)");
49
+ console.error(" --tenant <id> Tenant ID (for manual context)");
48
50
  console.error("");
49
51
  console.error("Options (with --tenant):");
50
52
  console.error(" --org <id> Organization ID (optional)");
51
- console.error(" --user <id> User ID for ACL (optional, uses superadmin if not set)");
53
+ console.error(" --user <id> User ID for ACL (required unless --allow-unauthenticated-superadmin is set)");
52
54
  console.error("");
53
55
  console.error("Common options:");
54
56
  console.error(" --debug Enable debug logging");
57
+ console.error(" --allow-unauthenticated-superadmin");
58
+ console.error(" DEV/TEST ONLY: run as superadmin with no per-user ACL when");
59
+ console.error(" no --user (and no --api-key) is supplied. Never use in production.");
55
60
  console.error("");
56
61
  console.error("Examples:");
62
+ console.error(" OPEN_MERCATO_API_KEY=omk_xxxx.yyyy... mercato ai_assistant mcp:serve");
57
63
  console.error(" mercato ai_assistant mcp:serve --api-key omk_xxxx.yyyy...");
58
- console.error(" mercato ai_assistant mcp:serve --tenant 123e4567-e89b-12d3-a456-426614174000");
64
+ console.error(" mercato ai_assistant mcp:serve --tenant 123e4567-e89b-12d3-a456-426614174000 --user <user-id>");
65
+ console.error(" mercato ai_assistant mcp:serve --tenant 123e4567-e89b-12d3-a456-426614174000 --allow-unauthenticated-superadmin");
59
66
  return;
60
67
  }
61
68
  await ensureBootstrap();
@@ -83,7 +90,8 @@ const mcpServe = {
83
90
  tenantId,
84
91
  organizationId,
85
92
  userId
86
- }
93
+ },
94
+ allowUnauthenticatedSuperadmin
87
95
  });
88
96
  }
89
97
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/modules/ai_assistant/cli.ts"],
4
- "sourcesContent": ["import type { ModuleCli } from '@open-mercato/shared/modules/registry'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\n/**\n * Ensure app bootstrap is called before creating DI container.\n * Uses the shared generated-bootstrap loader so the command works both from\n * the monorepo app and from standalone apps installed through npm packages.\n */\nasync function ensureBootstrap(): Promise<void> {\n // First check if DI is already available\n try {\n const { getDiRegistrars } = await import('@open-mercato/shared/lib/di/container')\n getDiRegistrars()\n return // DI already available\n } catch {\n // DI not available, need to bootstrap\n }\n\n try {\n const { bootstrapFromAppRoot } = await import('@open-mercato/shared/lib/bootstrap/dynamicLoader')\n await bootstrapFromAppRoot()\n } catch (error) {\n console.error('[MCP] Bootstrap failed:', error instanceof Error ? error.message : error)\n // Continue - some contexts may not have bootstrap available\n }\n}\n\nfunction parseArgs(rest: string[]): Record<string, string | boolean> {\n const args: Record<string, string | boolean> = {}\n for (let i = 0; i < rest.length; i++) {\n const arg = rest[i]\n if (!arg?.startsWith('--')) continue\n\n const [key, value] = arg.replace(/^--/, '').split('=')\n if (value !== undefined) {\n args[key] = value\n } else if (rest[i + 1] && !rest[i + 1]!.startsWith('--')) {\n args[key] = rest[i + 1]!\n i++\n } else {\n args[key] = true\n }\n }\n return args\n}\n\nconst mcpServe: ModuleCli = {\n command: 'mcp:serve',\n async run(rest) {\n const args = parseArgs(rest)\n const apiKey = String(args['api-key'] ?? args.apiKey ?? '') || null\n const tenantId = String(args.tenant ?? args.tenantId ?? '') || null\n const organizationId = String(args.org ?? args.organizationId ?? '') || null\n const userId = String(args.user ?? args.userId ?? '') || null\n const debug = args.debug === true || args.debug === 'true'\n\n // Either API key or tenant is required\n if (!apiKey && !tenantId) {\n console.error('Usage: mercato ai_assistant mcp:serve [options]')\n console.error('')\n console.error('Authentication (choose one):')\n console.error(' --api-key <secret> API key secret for authentication (recommended)')\n console.error(' --tenant <id> Tenant ID (for manual context)')\n console.error('')\n console.error('Options (with --tenant):')\n console.error(' --org <id> Organization ID (optional)')\n console.error(' --user <id> User ID for ACL (optional, uses superadmin if not set)')\n console.error('')\n console.error('Common options:')\n console.error(' --debug Enable debug logging')\n console.error('')\n console.error('Examples:')\n console.error(' mercato ai_assistant mcp:serve --api-key omk_xxxx.yyyy...')\n console.error(' mercato ai_assistant mcp:serve --tenant 123e4567-e89b-12d3-a456-426614174000')\n return\n }\n\n await ensureBootstrap()\n const container = await createRequestContainer()\n\n const { runMcpServer } = await import('./lib/mcp-server')\n\n if (apiKey) {\n await runMcpServer({\n config: {\n name: 'open-mercato-mcp',\n version: '0.1.0',\n debug,\n },\n container,\n apiKeySecret: apiKey,\n })\n } else {\n await runMcpServer({\n config: {\n name: 'open-mercato-mcp',\n version: '0.1.0',\n debug,\n },\n container,\n context: {\n tenantId,\n organizationId,\n userId,\n },\n })\n }\n },\n}\n\nconst MCP_DEFAULT_PORT = 3001\n\nconst mcpServeHttp: ModuleCli = {\n command: 'mcp:serve-http',\n async run(rest) {\n const args = parseArgs(rest)\n const portArg = parseInt(String(args.port ?? ''), 10)\n const port = !portArg || isNaN(portArg) ? MCP_DEFAULT_PORT : portArg\n const debug = args.debug === true || args.debug === 'true'\n\n await ensureBootstrap()\n const container = await createRequestContainer()\n\n const { runMcpHttpServer } = await import('./lib/http-server')\n\n await runMcpHttpServer({\n config: {\n name: 'open-mercato-mcp',\n version: '0.1.0',\n debug,\n },\n container,\n port,\n })\n },\n}\n\nconst mcpDev: ModuleCli = {\n command: 'mcp:dev',\n async run() {\n await ensureBootstrap()\n const { runMcpDevServer } = await import('./lib/mcp-dev-server')\n await runMcpDevServer()\n },\n}\n\nconst listTools: ModuleCli = {\n command: 'mcp:list-tools',\n async run(rest) {\n const args = parseArgs(rest)\n const verbose = args.verbose === true || args.verbose === 'true'\n\n // Ensure bootstrap runs so modules are registered for API discovery\n await ensureBootstrap()\n\n const { loadAllModuleTools } = await import('./lib/tool-loader')\n await loadAllModuleTools()\n\n const { getToolRegistry } = await import('./lib/tool-registry')\n const registry = getToolRegistry()\n const toolNames = registry.listToolNames()\n\n if (toolNames.length === 0) {\n console.log('\\nNo MCP tools registered.')\n console.log('Tools can be registered by modules using registerMcpTool().\\n')\n return\n }\n\n console.log(`\\nRegistered MCP Tools (${toolNames.length}):\\n`)\n\n // Group tools by module\n const byModule = new Map<string, string[]>()\n for (const name of toolNames) {\n const [module] = name.split('.')\n const list = byModule.get(module) ?? []\n list.push(name)\n byModule.set(module, list)\n }\n\n // Sort modules alphabetically\n const sortedModules = Array.from(byModule.keys()).sort()\n\n for (const module of sortedModules) {\n const tools = byModule.get(module)!\n console.log(`${module} (${tools.length} tools):`)\n\n for (const name of tools.sort()) {\n const tool = registry.getTool(name)\n if (!tool) continue\n\n if (verbose) {\n console.log(` ${name}`)\n console.log(` ${tool.description}`)\n if (tool.requiredFeatures?.length) {\n console.log(` Requires: ${tool.requiredFeatures.join(', ')}`)\n }\n } else {\n console.log(` - ${name}`)\n }\n }\n console.log('')\n }\n },\n}\n\nconst entityGraph: ModuleCli = {\n command: 'entity-graph',\n async run(rest) {\n const args = parseArgs(rest)\n const format = String(args.format ?? 'triples') as 'json' | 'triples'\n const entity = args.entity ? String(args.entity) : undefined\n const module = args.module ? String(args.module) : undefined\n\n await ensureBootstrap()\n\n const { getOrm } = await import('@open-mercato/shared/lib/db/mikro')\n const { extractEntityGraph, formatGraphAsTriples, filterGraphByEntity, filterGraphByModule } = await import(\n './lib/entity-graph'\n )\n\n console.log('[Entity Graph] Extracting from MikroORM metadata...')\n\n const orm = await getOrm()\n const graph = await extractEntityGraph(orm)\n\n // Apply filters\n let edges = graph.edges\n\n if (entity) {\n edges = filterGraphByEntity(graph, entity)\n console.log(`[Entity Graph] Filtered by entity: ${entity}`)\n }\n\n if (module) {\n const filteredGraph = { ...graph, edges }\n edges = filterGraphByModule(filteredGraph, module)\n console.log(`[Entity Graph] Filtered by module: ${module}`)\n }\n\n const filteredGraph = { ...graph, edges }\n\n if (format === 'json') {\n console.log(JSON.stringify(filteredGraph, null, 2))\n } else {\n const triples = formatGraphAsTriples(filteredGraph)\n console.log('')\n for (const triple of triples) {\n console.log(triple)\n }\n }\n\n console.log(`\\n[Entity Graph] ${graph.nodes.length} entities, ${edges.length} relationships`)\n },\n}\n\nconst runPendingActionCleanup: ModuleCli = {\n command: 'run-pending-action-cleanup',\n async run() {\n await ensureBootstrap()\n const container = await createRequestContainer()\n\n const { runPendingActionCleanup: runCleanup } = await import(\n './workers/ai-pending-action-cleanup'\n )\n\n const em = container.resolve<import('@mikro-orm/postgresql').EntityManager>('em')\n const summary = await runCleanup({ em })\n\n console.log('[ai-pending-action-cleanup] Sweep complete:', summary)\n },\n}\n\nconst testTools: ModuleCli = {\n command: 'test-tools',\n async run(rest) {\n const args = parseArgs(rest)\n const json = args.json === true || args.json === 'true'\n const moduleFilter =\n typeof args.module === 'string' && args.module.length > 0 ? args.module : null\n const includeMutations = args['no-mutations'] !== true && args['no-mutations'] !== 'true'\n const tenantId =\n typeof args.tenant === 'string' && args.tenant.length > 0 ? args.tenant : null\n const organizationId =\n typeof args.org === 'string' && args.org.length > 0 ? args.org : null\n\n await ensureBootstrap()\n const { runToolTests } = await import('./lib/tool-test-runner')\n const report = await runToolTests({\n tenantId,\n organizationId,\n moduleFilter,\n includeMutations,\n })\n\n if (json) {\n // Wrap in markers so a Playwright spec (or any caller) can extract the\n // JSON payload without being thrown off by bootstrap log lines emitted\n // to stdout by other modules during DI container creation.\n console.log('---TOOL_TEST_REPORT_BEGIN---')\n console.log(JSON.stringify(report))\n console.log('---TOOL_TEST_REPORT_END---')\n } else {\n console.log('')\n console.log(\n `AI tool test report \u2014 tenant=${report.tenantId ?? '<none>'} org=${\n report.organizationId ?? '<none>'\n }`,\n )\n console.log(\n `total=${report.total} pass=${report.passed} fail=${report.failed} skip=${report.skipped}`,\n )\n const byModule = new Map<string, typeof report.records>()\n for (const record of report.records) {\n const list = byModule.get(record.module) ?? []\n list.push(record)\n byModule.set(record.module, list)\n }\n const sortedModules = Array.from(byModule.keys()).sort()\n for (const moduleId of sortedModules) {\n const list = byModule.get(moduleId)!\n console.log('')\n console.log(`${moduleId} (${list.length}):`)\n for (const record of list) {\n const marker =\n record.status === 'pass' ? '\u2713' : record.status === 'fail' ? '\u2717' : '\u00B7'\n const reason = record.reason ? ` \u2014 ${record.reason}` : ''\n const mutation = record.isMutation ? ' [mutation]' : ''\n console.log(\n ` ${marker} ${record.tool}${mutation} (${record.durationMs}ms)${reason}`,\n )\n }\n }\n console.log('')\n }\n\n if (report.failed > 0) {\n process.exitCode = 1\n }\n },\n}\n\nconst runTokenUsagePrune: ModuleCli = {\n command: 'run-token-usage-prune',\n async run() {\n await ensureBootstrap()\n const container = await createRequestContainer()\n\n const { runTokenUsagePrune: runPrune } = await import(\n './workers/ai-token-usage-prune'\n )\n\n const em = container.resolve<import('@mikro-orm/postgresql').EntityManager>('em')\n const summary = await runPrune({ em })\n\n console.log('[ai-token-usage-prune] Prune complete:', summary)\n },\n}\n\nexport default [\n mcpServe,\n mcpServeHttp,\n mcpDev,\n listTools,\n entityGraph,\n runPendingActionCleanup,\n runTokenUsagePrune,\n testTools,\n]\n"],
5
- "mappings": "AACA,SAAS,8BAA8B;AAMvC,eAAe,kBAAiC;AAE9C,MAAI;AACF,UAAM,EAAE,gBAAgB,IAAI,MAAM,OAAO,uCAAuC;AAChF,oBAAgB;AAChB;AAAA,EACF,QAAQ;AAAA,EAER;AAEA,MAAI;AACF,UAAM,EAAE,qBAAqB,IAAI,MAAM,OAAO,kDAAkD;AAChG,UAAM,qBAAqB;AAAA,EAC7B,SAAS,OAAO;AACd,YAAQ,MAAM,2BAA2B,iBAAiB,QAAQ,MAAM,UAAU,KAAK;AAAA,EAEzF;AACF;AAEA,SAAS,UAAU,MAAkD;AACnE,QAAM,OAAyC,CAAC;AAChD,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAM,MAAM,KAAK,CAAC;AAClB,QAAI,CAAC,KAAK,WAAW,IAAI,EAAG;AAE5B,UAAM,CAAC,KAAK,KAAK,IAAI,IAAI,QAAQ,OAAO,EAAE,EAAE,MAAM,GAAG;AACrD,QAAI,UAAU,QAAW;AACvB,WAAK,GAAG,IAAI;AAAA,IACd,WAAW,KAAK,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,EAAG,WAAW,IAAI,GAAG;AACxD,WAAK,GAAG,IAAI,KAAK,IAAI,CAAC;AACtB;AAAA,IACF,OAAO;AACL,WAAK,GAAG,IAAI;AAAA,IACd;AAAA,EACF;AACA,SAAO;AACT;AAEA,MAAM,WAAsB;AAAA,EAC1B,SAAS;AAAA,EACT,MAAM,IAAI,MAAM;AACd,UAAM,OAAO,UAAU,IAAI;AAC3B,UAAM,SAAS,OAAO,KAAK,SAAS,KAAK,KAAK,UAAU,EAAE,KAAK;AAC/D,UAAM,WAAW,OAAO,KAAK,UAAU,KAAK,YAAY,EAAE,KAAK;AAC/D,UAAM,iBAAiB,OAAO,KAAK,OAAO,KAAK,kBAAkB,EAAE,KAAK;AACxE,UAAM,SAAS,OAAO,KAAK,QAAQ,KAAK,UAAU,EAAE,KAAK;AACzD,UAAM,QAAQ,KAAK,UAAU,QAAQ,KAAK,UAAU;AAGpD,QAAI,CAAC,UAAU,CAAC,UAAU;AACxB,cAAQ,MAAM,iDAAiD;AAC/D,cAAQ,MAAM,EAAE;AAChB,cAAQ,MAAM,8BAA8B;AAC5C,cAAQ,MAAM,wEAAwE;AACtF,cAAQ,MAAM,uDAAuD;AACrE,cAAQ,MAAM,EAAE;AAChB,cAAQ,MAAM,0BAA0B;AACxC,cAAQ,MAAM,mDAAmD;AACjE,cAAQ,MAAM,+EAA+E;AAC7F,cAAQ,MAAM,EAAE;AAChB,cAAQ,MAAM,iBAAiB;AAC/B,cAAQ,MAAM,6CAA6C;AAC3D,cAAQ,MAAM,EAAE;AAChB,cAAQ,MAAM,WAAW;AACzB,cAAQ,MAAM,6DAA6D;AAC3E,cAAQ,MAAM,gFAAgF;AAC9F;AAAA,IACF;AAEA,UAAM,gBAAgB;AACtB,UAAM,YAAY,MAAM,uBAAuB;AAE/C,UAAM,EAAE,aAAa,IAAI,MAAM,OAAO,kBAAkB;AAExD,QAAI,QAAQ;AACV,YAAM,aAAa;AAAA,QACjB,QAAQ;AAAA,UACN,MAAM;AAAA,UACN,SAAS;AAAA,UACT;AAAA,QACF;AAAA,QACA;AAAA,QACA,cAAc;AAAA,MAChB,CAAC;AAAA,IACH,OAAO;AACL,YAAM,aAAa;AAAA,QACjB,QAAQ;AAAA,UACN,MAAM;AAAA,UACN,SAAS;AAAA,UACT;AAAA,QACF;AAAA,QACA;AAAA,QACA,SAAS;AAAA,UACP;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEA,MAAM,mBAAmB;AAEzB,MAAM,eAA0B;AAAA,EAC9B,SAAS;AAAA,EACT,MAAM,IAAI,MAAM;AACd,UAAM,OAAO,UAAU,IAAI;AAC3B,UAAM,UAAU,SAAS,OAAO,KAAK,QAAQ,EAAE,GAAG,EAAE;AACpD,UAAM,OAAO,CAAC,WAAW,MAAM,OAAO,IAAI,mBAAmB;AAC7D,UAAM,QAAQ,KAAK,UAAU,QAAQ,KAAK,UAAU;AAEpD,UAAM,gBAAgB;AACtB,UAAM,YAAY,MAAM,uBAAuB;AAE/C,UAAM,EAAE,iBAAiB,IAAI,MAAM,OAAO,mBAAmB;AAE7D,UAAM,iBAAiB;AAAA,MACrB,QAAQ;AAAA,QACN,MAAM;AAAA,QACN,SAAS;AAAA,QACT;AAAA,MACF;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AACF;AAEA,MAAM,SAAoB;AAAA,EACxB,SAAS;AAAA,EACT,MAAM,MAAM;AACV,UAAM,gBAAgB;AACtB,UAAM,EAAE,gBAAgB,IAAI,MAAM,OAAO,sBAAsB;AAC/D,UAAM,gBAAgB;AAAA,EACxB;AACF;AAEA,MAAM,YAAuB;AAAA,EAC3B,SAAS;AAAA,EACT,MAAM,IAAI,MAAM;AACd,UAAM,OAAO,UAAU,IAAI;AAC3B,UAAM,UAAU,KAAK,YAAY,QAAQ,KAAK,YAAY;AAG1D,UAAM,gBAAgB;AAEtB,UAAM,EAAE,mBAAmB,IAAI,MAAM,OAAO,mBAAmB;AAC/D,UAAM,mBAAmB;AAEzB,UAAM,EAAE,gBAAgB,IAAI,MAAM,OAAO,qBAAqB;AAC9D,UAAM,WAAW,gBAAgB;AACjC,UAAM,YAAY,SAAS,cAAc;AAEzC,QAAI,UAAU,WAAW,GAAG;AAC1B,cAAQ,IAAI,4BAA4B;AACxC,cAAQ,IAAI,+DAA+D;AAC3E;AAAA,IACF;AAEA,YAAQ,IAAI;AAAA,wBAA2B,UAAU,MAAM;AAAA,CAAM;AAG7D,UAAM,WAAW,oBAAI,IAAsB;AAC3C,eAAW,QAAQ,WAAW;AAC5B,YAAM,CAAC,MAAM,IAAI,KAAK,MAAM,GAAG;AAC/B,YAAM,OAAO,SAAS,IAAI,MAAM,KAAK,CAAC;AACtC,WAAK,KAAK,IAAI;AACd,eAAS,IAAI,QAAQ,IAAI;AAAA,IAC3B;AAGA,UAAM,gBAAgB,MAAM,KAAK,SAAS,KAAK,CAAC,EAAE,KAAK;AAEvD,eAAW,UAAU,eAAe;AAClC,YAAM,QAAQ,SAAS,IAAI,MAAM;AACjC,cAAQ,IAAI,GAAG,MAAM,KAAK,MAAM,MAAM,UAAU;AAEhD,iBAAW,QAAQ,MAAM,KAAK,GAAG;AAC/B,cAAM,OAAO,SAAS,QAAQ,IAAI;AAClC,YAAI,CAAC,KAAM;AAEX,YAAI,SAAS;AACX,kBAAQ,IAAI,KAAK,IAAI,EAAE;AACvB,kBAAQ,IAAI,OAAO,KAAK,WAAW,EAAE;AACrC,cAAI,KAAK,kBAAkB,QAAQ;AACjC,oBAAQ,IAAI,iBAAiB,KAAK,iBAAiB,KAAK,IAAI,CAAC,EAAE;AAAA,UACjE;AAAA,QACF,OAAO;AACL,kBAAQ,IAAI,OAAO,IAAI,EAAE;AAAA,QAC3B;AAAA,MACF;AACA,cAAQ,IAAI,EAAE;AAAA,IAChB;AAAA,EACF;AACF;AAEA,MAAM,cAAyB;AAAA,EAC7B,SAAS;AAAA,EACT,MAAM,IAAI,MAAM;AACd,UAAM,OAAO,UAAU,IAAI;AAC3B,UAAM,SAAS,OAAO,KAAK,UAAU,SAAS;AAC9C,UAAM,SAAS,KAAK,SAAS,OAAO,KAAK,MAAM,IAAI;AACnD,UAAM,SAAS,KAAK,SAAS,OAAO,KAAK,MAAM,IAAI;AAEnD,UAAM,gBAAgB;AAEtB,UAAM,EAAE,OAAO,IAAI,MAAM,OAAO,mCAAmC;AACnE,UAAM,EAAE,oBAAoB,sBAAsB,qBAAqB,oBAAoB,IAAI,MAAM,OACnG,oBACF;AAEA,YAAQ,IAAI,qDAAqD;AAEjE,UAAM,MAAM,MAAM,OAAO;AACzB,UAAM,QAAQ,MAAM,mBAAmB,GAAG;AAG1C,QAAI,QAAQ,MAAM;AAElB,QAAI,QAAQ;AACV,cAAQ,oBAAoB,OAAO,MAAM;AACzC,cAAQ,IAAI,sCAAsC,MAAM,EAAE;AAAA,IAC5D;AAEA,QAAI,QAAQ;AACV,YAAMA,iBAAgB,EAAE,GAAG,OAAO,MAAM;AACxC,cAAQ,oBAAoBA,gBAAe,MAAM;AACjD,cAAQ,IAAI,sCAAsC,MAAM,EAAE;AAAA,IAC5D;AAEA,UAAM,gBAAgB,EAAE,GAAG,OAAO,MAAM;AAExC,QAAI,WAAW,QAAQ;AACrB,cAAQ,IAAI,KAAK,UAAU,eAAe,MAAM,CAAC,CAAC;AAAA,IACpD,OAAO;AACL,YAAM,UAAU,qBAAqB,aAAa;AAClD,cAAQ,IAAI,EAAE;AACd,iBAAW,UAAU,SAAS;AAC5B,gBAAQ,IAAI,MAAM;AAAA,MACpB;AAAA,IACF;AAEA,YAAQ,IAAI;AAAA,iBAAoB,MAAM,MAAM,MAAM,cAAc,MAAM,MAAM,gBAAgB;AAAA,EAC9F;AACF;AAEA,MAAM,0BAAqC;AAAA,EACzC,SAAS;AAAA,EACT,MAAM,MAAM;AACV,UAAM,gBAAgB;AACtB,UAAM,YAAY,MAAM,uBAAuB;AAE/C,UAAM,EAAE,yBAAyB,WAAW,IAAI,MAAM,OACpD,qCACF;AAEA,UAAM,KAAK,UAAU,QAAuD,IAAI;AAChF,UAAM,UAAU,MAAM,WAAW,EAAE,GAAG,CAAC;AAEvC,YAAQ,IAAI,+CAA+C,OAAO;AAAA,EACpE;AACF;AAEA,MAAM,YAAuB;AAAA,EAC3B,SAAS;AAAA,EACT,MAAM,IAAI,MAAM;AACd,UAAM,OAAO,UAAU,IAAI;AAC3B,UAAM,OAAO,KAAK,SAAS,QAAQ,KAAK,SAAS;AACjD,UAAM,eACJ,OAAO,KAAK,WAAW,YAAY,KAAK,OAAO,SAAS,IAAI,KAAK,SAAS;AAC5E,UAAM,mBAAmB,KAAK,cAAc,MAAM,QAAQ,KAAK,cAAc,MAAM;AACnF,UAAM,WACJ,OAAO,KAAK,WAAW,YAAY,KAAK,OAAO,SAAS,IAAI,KAAK,SAAS;AAC5E,UAAM,iBACJ,OAAO,KAAK,QAAQ,YAAY,KAAK,IAAI,SAAS,IAAI,KAAK,MAAM;AAEnE,UAAM,gBAAgB;AACtB,UAAM,EAAE,aAAa,IAAI,MAAM,OAAO,wBAAwB;AAC9D,UAAM,SAAS,MAAM,aAAa;AAAA,MAChC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED,QAAI,MAAM;AAIR,cAAQ,IAAI,8BAA8B;AAC1C,cAAQ,IAAI,KAAK,UAAU,MAAM,CAAC;AAClC,cAAQ,IAAI,4BAA4B;AAAA,IAC1C,OAAO;AACL,cAAQ,IAAI,EAAE;AACd,cAAQ;AAAA,QACN,qCAAgC,OAAO,YAAY,QAAQ,QACzD,OAAO,kBAAkB,QAC3B;AAAA,MACF;AACA,cAAQ;AAAA,QACN,SAAS,OAAO,KAAK,SAAS,OAAO,MAAM,SAAS,OAAO,MAAM,SAAS,OAAO,OAAO;AAAA,MAC1F;AACA,YAAM,WAAW,oBAAI,IAAmC;AACxD,iBAAW,UAAU,OAAO,SAAS;AACnC,cAAM,OAAO,SAAS,IAAI,OAAO,MAAM,KAAK,CAAC;AAC7C,aAAK,KAAK,MAAM;AAChB,iBAAS,IAAI,OAAO,QAAQ,IAAI;AAAA,MAClC;AACA,YAAM,gBAAgB,MAAM,KAAK,SAAS,KAAK,CAAC,EAAE,KAAK;AACvD,iBAAW,YAAY,eAAe;AACpC,cAAM,OAAO,SAAS,IAAI,QAAQ;AAClC,gBAAQ,IAAI,EAAE;AACd,gBAAQ,IAAI,GAAG,QAAQ,KAAK,KAAK,MAAM,IAAI;AAC3C,mBAAW,UAAU,MAAM;AACzB,gBAAM,SACJ,OAAO,WAAW,SAAS,WAAM,OAAO,WAAW,SAAS,WAAM;AACpE,gBAAM,SAAS,OAAO,SAAS,WAAM,OAAO,MAAM,KAAK;AACvD,gBAAM,WAAW,OAAO,aAAa,gBAAgB;AACrD,kBAAQ;AAAA,YACN,KAAK,MAAM,IAAI,OAAO,IAAI,GAAG,QAAQ,KAAK,OAAO,UAAU,MAAM,MAAM;AAAA,UACzE;AAAA,QACF;AAAA,MACF;AACA,cAAQ,IAAI,EAAE;AAAA,IAChB;AAEA,QAAI,OAAO,SAAS,GAAG;AACrB,cAAQ,WAAW;AAAA,IACrB;AAAA,EACF;AACF;AAEA,MAAM,qBAAgC;AAAA,EACpC,SAAS;AAAA,EACT,MAAM,MAAM;AACV,UAAM,gBAAgB;AACtB,UAAM,YAAY,MAAM,uBAAuB;AAE/C,UAAM,EAAE,oBAAoB,SAAS,IAAI,MAAM,OAC7C,gCACF;AAEA,UAAM,KAAK,UAAU,QAAuD,IAAI;AAChF,UAAM,UAAU,MAAM,SAAS,EAAE,GAAG,CAAC;AAErC,YAAQ,IAAI,0CAA0C,OAAO;AAAA,EAC/D;AACF;AAEA,IAAO,cAAQ;AAAA,EACb;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;",
4
+ "sourcesContent": ["import type { ModuleCli } from '@open-mercato/shared/modules/registry'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\n/**\n * Ensure app bootstrap is called before creating DI container.\n * Uses the shared generated-bootstrap loader so the command works both from\n * the monorepo app and from standalone apps installed through npm packages.\n */\nasync function ensureBootstrap(): Promise<void> {\n // First check if DI is already available\n try {\n const { getDiRegistrars } = await import('@open-mercato/shared/lib/di/container')\n getDiRegistrars()\n return // DI already available\n } catch {\n // DI not available, need to bootstrap\n }\n\n try {\n const { bootstrapFromAppRoot } = await import('@open-mercato/shared/lib/bootstrap/dynamicLoader')\n await bootstrapFromAppRoot()\n } catch (error) {\n console.error('[MCP] Bootstrap failed:', error instanceof Error ? error.message : error)\n // Continue - some contexts may not have bootstrap available\n }\n}\n\nfunction parseArgs(rest: string[]): Record<string, string | boolean> {\n const args: Record<string, string | boolean> = {}\n for (let i = 0; i < rest.length; i++) {\n const arg = rest[i]\n if (!arg?.startsWith('--')) continue\n\n const [key, value] = arg.replace(/^--/, '').split('=')\n if (value !== undefined) {\n args[key] = value\n } else if (rest[i + 1] && !rest[i + 1]!.startsWith('--')) {\n args[key] = rest[i + 1]!\n i++\n } else {\n args[key] = true\n }\n }\n return args\n}\n\nconst mcpServe: ModuleCli = {\n command: 'mcp:serve',\n async run(rest) {\n const args = parseArgs(rest)\n // Prefer the OPEN_MERCATO_API_KEY env var so the secret never has to be\n // placed on the command line (argv is world-readable via ps / /proc).\n // The --api-key flag stays supported for backward compatibility.\n const apiKey = String(args['api-key'] ?? args.apiKey ?? '') || process.env.OPEN_MERCATO_API_KEY || null\n const tenantId = String(args.tenant ?? args.tenantId ?? '') || null\n const organizationId = String(args.org ?? args.organizationId ?? '') || null\n const userId = String(args.user ?? args.userId ?? '') || null\n const debug = args.debug === true || args.debug === 'true'\n const allowUnauthenticatedSuperadmin =\n args['allow-unauthenticated-superadmin'] === true ||\n args['allow-unauthenticated-superadmin'] === 'true'\n\n // Either API key or tenant is required\n if (!apiKey && !tenantId) {\n console.error('Usage: mercato ai_assistant mcp:serve [options]')\n console.error('')\n console.error('Authentication (choose one):')\n console.error(' OPEN_MERCATO_API_KEY env API key secret (recommended \u2014 keeps the secret off argv)')\n console.error(' --api-key <secret> API key secret for authentication (visible in process listings)')\n console.error(' --tenant <id> Tenant ID (for manual context)')\n console.error('')\n console.error('Options (with --tenant):')\n console.error(' --org <id> Organization ID (optional)')\n console.error(' --user <id> User ID for ACL (required unless --allow-unauthenticated-superadmin is set)')\n console.error('')\n console.error('Common options:')\n console.error(' --debug Enable debug logging')\n console.error(' --allow-unauthenticated-superadmin')\n console.error(' DEV/TEST ONLY: run as superadmin with no per-user ACL when')\n console.error(' no --user (and no --api-key) is supplied. Never use in production.')\n console.error('')\n console.error('Examples:')\n console.error(' OPEN_MERCATO_API_KEY=omk_xxxx.yyyy... mercato ai_assistant mcp:serve')\n console.error(' mercato ai_assistant mcp:serve --api-key omk_xxxx.yyyy...')\n console.error(' mercato ai_assistant mcp:serve --tenant 123e4567-e89b-12d3-a456-426614174000 --user <user-id>')\n console.error(' mercato ai_assistant mcp:serve --tenant 123e4567-e89b-12d3-a456-426614174000 --allow-unauthenticated-superadmin')\n return\n }\n\n await ensureBootstrap()\n const container = await createRequestContainer()\n\n const { runMcpServer } = await import('./lib/mcp-server')\n\n if (apiKey) {\n await runMcpServer({\n config: {\n name: 'open-mercato-mcp',\n version: '0.1.0',\n debug,\n },\n container,\n apiKeySecret: apiKey,\n })\n } else {\n await runMcpServer({\n config: {\n name: 'open-mercato-mcp',\n version: '0.1.0',\n debug,\n },\n container,\n context: {\n tenantId,\n organizationId,\n userId,\n },\n allowUnauthenticatedSuperadmin,\n })\n }\n },\n}\n\nconst MCP_DEFAULT_PORT = 3001\n\nconst mcpServeHttp: ModuleCli = {\n command: 'mcp:serve-http',\n async run(rest) {\n const args = parseArgs(rest)\n const portArg = parseInt(String(args.port ?? ''), 10)\n const port = !portArg || isNaN(portArg) ? MCP_DEFAULT_PORT : portArg\n const debug = args.debug === true || args.debug === 'true'\n\n await ensureBootstrap()\n const container = await createRequestContainer()\n\n const { runMcpHttpServer } = await import('./lib/http-server')\n\n await runMcpHttpServer({\n config: {\n name: 'open-mercato-mcp',\n version: '0.1.0',\n debug,\n },\n container,\n port,\n })\n },\n}\n\nconst mcpDev: ModuleCli = {\n command: 'mcp:dev',\n async run() {\n await ensureBootstrap()\n const { runMcpDevServer } = await import('./lib/mcp-dev-server')\n await runMcpDevServer()\n },\n}\n\nconst listTools: ModuleCli = {\n command: 'mcp:list-tools',\n async run(rest) {\n const args = parseArgs(rest)\n const verbose = args.verbose === true || args.verbose === 'true'\n\n // Ensure bootstrap runs so modules are registered for API discovery\n await ensureBootstrap()\n\n const { loadAllModuleTools } = await import('./lib/tool-loader')\n await loadAllModuleTools()\n\n const { getToolRegistry } = await import('./lib/tool-registry')\n const registry = getToolRegistry()\n const toolNames = registry.listToolNames()\n\n if (toolNames.length === 0) {\n console.log('\\nNo MCP tools registered.')\n console.log('Tools can be registered by modules using registerMcpTool().\\n')\n return\n }\n\n console.log(`\\nRegistered MCP Tools (${toolNames.length}):\\n`)\n\n // Group tools by module\n const byModule = new Map<string, string[]>()\n for (const name of toolNames) {\n const [module] = name.split('.')\n const list = byModule.get(module) ?? []\n list.push(name)\n byModule.set(module, list)\n }\n\n // Sort modules alphabetically\n const sortedModules = Array.from(byModule.keys()).sort()\n\n for (const module of sortedModules) {\n const tools = byModule.get(module)!\n console.log(`${module} (${tools.length} tools):`)\n\n for (const name of tools.sort()) {\n const tool = registry.getTool(name)\n if (!tool) continue\n\n if (verbose) {\n console.log(` ${name}`)\n console.log(` ${tool.description}`)\n if (tool.requiredFeatures?.length) {\n console.log(` Requires: ${tool.requiredFeatures.join(', ')}`)\n }\n } else {\n console.log(` - ${name}`)\n }\n }\n console.log('')\n }\n },\n}\n\nconst entityGraph: ModuleCli = {\n command: 'entity-graph',\n async run(rest) {\n const args = parseArgs(rest)\n const format = String(args.format ?? 'triples') as 'json' | 'triples'\n const entity = args.entity ? String(args.entity) : undefined\n const module = args.module ? String(args.module) : undefined\n\n await ensureBootstrap()\n\n const { getOrm } = await import('@open-mercato/shared/lib/db/mikro')\n const { extractEntityGraph, formatGraphAsTriples, filterGraphByEntity, filterGraphByModule } = await import(\n './lib/entity-graph'\n )\n\n console.log('[Entity Graph] Extracting from MikroORM metadata...')\n\n const orm = await getOrm()\n const graph = await extractEntityGraph(orm)\n\n // Apply filters\n let edges = graph.edges\n\n if (entity) {\n edges = filterGraphByEntity(graph, entity)\n console.log(`[Entity Graph] Filtered by entity: ${entity}`)\n }\n\n if (module) {\n const filteredGraph = { ...graph, edges }\n edges = filterGraphByModule(filteredGraph, module)\n console.log(`[Entity Graph] Filtered by module: ${module}`)\n }\n\n const filteredGraph = { ...graph, edges }\n\n if (format === 'json') {\n console.log(JSON.stringify(filteredGraph, null, 2))\n } else {\n const triples = formatGraphAsTriples(filteredGraph)\n console.log('')\n for (const triple of triples) {\n console.log(triple)\n }\n }\n\n console.log(`\\n[Entity Graph] ${graph.nodes.length} entities, ${edges.length} relationships`)\n },\n}\n\nconst runPendingActionCleanup: ModuleCli = {\n command: 'run-pending-action-cleanup',\n async run() {\n await ensureBootstrap()\n const container = await createRequestContainer()\n\n const { runPendingActionCleanup: runCleanup } = await import(\n './workers/ai-pending-action-cleanup'\n )\n\n const em = container.resolve<import('@mikro-orm/postgresql').EntityManager>('em')\n const summary = await runCleanup({ em })\n\n console.log('[ai-pending-action-cleanup] Sweep complete:', summary)\n },\n}\n\nconst testTools: ModuleCli = {\n command: 'test-tools',\n async run(rest) {\n const args = parseArgs(rest)\n const json = args.json === true || args.json === 'true'\n const moduleFilter =\n typeof args.module === 'string' && args.module.length > 0 ? args.module : null\n const includeMutations = args['no-mutations'] !== true && args['no-mutations'] !== 'true'\n const tenantId =\n typeof args.tenant === 'string' && args.tenant.length > 0 ? args.tenant : null\n const organizationId =\n typeof args.org === 'string' && args.org.length > 0 ? args.org : null\n\n await ensureBootstrap()\n const { runToolTests } = await import('./lib/tool-test-runner')\n const report = await runToolTests({\n tenantId,\n organizationId,\n moduleFilter,\n includeMutations,\n })\n\n if (json) {\n // Wrap in markers so a Playwright spec (or any caller) can extract the\n // JSON payload without being thrown off by bootstrap log lines emitted\n // to stdout by other modules during DI container creation.\n console.log('---TOOL_TEST_REPORT_BEGIN---')\n console.log(JSON.stringify(report))\n console.log('---TOOL_TEST_REPORT_END---')\n } else {\n console.log('')\n console.log(\n `AI tool test report \u2014 tenant=${report.tenantId ?? '<none>'} org=${\n report.organizationId ?? '<none>'\n }`,\n )\n console.log(\n `total=${report.total} pass=${report.passed} fail=${report.failed} skip=${report.skipped}`,\n )\n const byModule = new Map<string, typeof report.records>()\n for (const record of report.records) {\n const list = byModule.get(record.module) ?? []\n list.push(record)\n byModule.set(record.module, list)\n }\n const sortedModules = Array.from(byModule.keys()).sort()\n for (const moduleId of sortedModules) {\n const list = byModule.get(moduleId)!\n console.log('')\n console.log(`${moduleId} (${list.length}):`)\n for (const record of list) {\n const marker =\n record.status === 'pass' ? '\u2713' : record.status === 'fail' ? '\u2717' : '\u00B7'\n const reason = record.reason ? ` \u2014 ${record.reason}` : ''\n const mutation = record.isMutation ? ' [mutation]' : ''\n console.log(\n ` ${marker} ${record.tool}${mutation} (${record.durationMs}ms)${reason}`,\n )\n }\n }\n console.log('')\n }\n\n if (report.failed > 0) {\n process.exitCode = 1\n }\n },\n}\n\nconst runTokenUsagePrune: ModuleCli = {\n command: 'run-token-usage-prune',\n async run() {\n await ensureBootstrap()\n const container = await createRequestContainer()\n\n const { runTokenUsagePrune: runPrune } = await import(\n './workers/ai-token-usage-prune'\n )\n\n const em = container.resolve<import('@mikro-orm/postgresql').EntityManager>('em')\n const summary = await runPrune({ em })\n\n console.log('[ai-token-usage-prune] Prune complete:', summary)\n },\n}\n\nexport default [\n mcpServe,\n mcpServeHttp,\n mcpDev,\n listTools,\n entityGraph,\n runPendingActionCleanup,\n runTokenUsagePrune,\n testTools,\n]\n"],
5
+ "mappings": "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",
6
6
  "names": ["filteredGraph"]
7
7
  }
@@ -635,6 +635,10 @@ AiChatConversationParticipant = __decorateClass([
635
635
  name: "ai_chat_conv_participants_tenant_conv_user_null_org_uq",
636
636
  expression: 'create unique index "ai_chat_conv_participants_tenant_conv_user_null_org_uq" on "ai_chat_conversation_participants" ("tenant_id", "conversation_id", "user_id") where "organization_id" is null'
637
637
  }),
638
+ Index({
639
+ name: "ai_chat_conv_participants_active_conv_user_idx",
640
+ expression: 'create index "ai_chat_conv_participants_active_conv_user_idx" on "ai_chat_conversation_participants" ("tenant_id", "organization_id", "conversation_id", "user_id") where "deleted_at" is null'
641
+ }),
638
642
  Index({
639
643
  name: "ai_chat_conv_participants_tenant_org_user_conv_idx",
640
644
  properties: ["tenantId", "organizationId", "userId", "conversationId"]
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/ai_assistant/data/entities.ts"],
4
- "sourcesContent": ["import { OptionalProps } from '@mikro-orm/core'\nimport {\n Entity,\n Index,\n PrimaryKey,\n Property,\n} from '@mikro-orm/decorators/legacy'\nimport type {\n AiPendingActionExecutionResult,\n AiPendingActionFailedRecord,\n AiPendingActionFieldDiff,\n AiPendingActionQueueMode,\n AiPendingActionRecordDiff,\n AiPendingActionStatus,\n} from '../lib/pending-action-types'\n\n/**\n * Versioned additive prompt-override for a registered AI agent (Step 5.3).\n *\n * Each write creates a new row with `version = latest + 1`. Rows are never\n * updated in place \u2014 history is preserved so operators can roll back by\n * reading an earlier `version`. Column set is tenant/org-scoped per the\n * standard Open Mercato RBAC contract.\n *\n * `sections` holds additive text keyed by prompt section id. The runtime\n * composes the final `systemPrompt` via `composeSystemPromptWithOverride`\n * (see `lib/prompt-override-merge.ts`), which NEVER replaces a built-in\n * section \u2014 overrides are append-only by contract.\n */\n@Entity({ tableName: 'ai_agent_prompt_overrides' })\n@Index({\n name: 'ai_agent_prompt_overrides_tenant_org_agent_version_uq',\n expression:\n 'create unique index \"ai_agent_prompt_overrides_tenant_org_agent_version_uq\" on \"ai_agent_prompt_overrides\" (\"tenant_id\", \"organization_id\", \"agent_id\", \"version\") where \"organization_id\" is not null',\n})\n@Index({\n name: 'ai_agent_prompt_overrides_tenant_agent_version_null_org_uq',\n expression:\n 'create unique index \"ai_agent_prompt_overrides_tenant_agent_version_null_org_uq\" on \"ai_agent_prompt_overrides\" (\"tenant_id\", \"agent_id\", \"version\") where \"organization_id\" is null',\n})\n@Index({\n name: 'ai_agent_prompt_overrides_tenant_agent_idx',\n properties: ['tenantId', 'agentId'],\n})\n@Index({\n name: 'ai_agent_prompt_overrides_tenant_org_agent_version_idx',\n expression:\n 'create index \"ai_agent_prompt_overrides_tenant_org_agent_version_idx\" on \"ai_agent_prompt_overrides\" (\"tenant_id\", \"organization_id\", \"agent_id\", \"version\" desc)',\n})\nexport class AiAgentPromptOverride {\n [OptionalProps]?: 'createdAt' | 'updatedAt' | 'organizationId' | 'createdByUserId' | 'notes'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'agent_id', type: 'text' })\n agentId!: string\n\n @Property({ name: 'version', type: 'int' })\n version!: number\n\n @Property({ name: 'sections', type: 'jsonb' })\n sections!: Record<string, string>\n\n @Property({ name: 'notes', type: 'text', nullable: true })\n notes?: string | null\n\n @Property({ name: 'created_by_user_id', type: 'uuid', nullable: true })\n createdByUserId?: string | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n}\n\n/**\n * Persistent mutation-approval gate row backing the Phase 3 WS-C contract\n * (spec \u00A78 `AiPendingAction` + \u00A79 confirm/cancel flow, Step 5.5).\n *\n * One row is created by `prepareMutation` (Step 5.6) whenever the runtime\n * intercepts an `isMutation: true` tool call from a non-read-only agent.\n * The row stores the normalized tool input, a precomputed `fieldDiff` (or\n * per-record batch diff in `records[]`), the target record version, an\n * `idempotencyKey` that dedupes double-submits within the TTL, and a\n * `status` that walks the state machine defined in\n * {@link AI_PENDING_ACTION_ALLOWED_TRANSITIONS}.\n *\n * The cleanup worker (Step 5.12) sweeps `status='pending' AND expiresAt < now`\n * rows and transitions them to `expired`. The confirm route (Step 5.8)\n * walks `pending \u2192 confirmed \u2192 executing \u2192 (failed | terminal success)`.\n * Reads always flow through `findOneWithDecryption` /\n * `findWithDecryption`, even though no column is GDPR-flagged today, so\n * future encrypted columns (e.g. `normalizedInput`) are handled.\n */\n@Entity({ tableName: 'ai_pending_actions' })\n@Index({\n name: 'ai_pending_actions_tenant_org_idempotency_uq',\n expression:\n 'create unique index \"ai_pending_actions_tenant_org_idempotency_uq\" on \"ai_pending_actions\" (\"tenant_id\", \"organization_id\", \"idempotency_key\") where \"organization_id\" is not null',\n})\n@Index({\n name: 'ai_pending_actions_tenant_idem_null_org_uq',\n expression:\n 'create unique index \"ai_pending_actions_tenant_idem_null_org_uq\" on \"ai_pending_actions\" (\"tenant_id\", \"idempotency_key\") where \"organization_id\" is null',\n})\n@Index({\n name: 'ai_pending_actions_tenant_org_status_expires_idx',\n properties: ['tenantId', 'organizationId', 'status', 'expiresAt'],\n})\n@Index({\n name: 'ai_pending_actions_tenant_org_agent_status_idx',\n properties: ['tenantId', 'organizationId', 'agentId', 'status'],\n})\nexport class AiPendingAction {\n [OptionalProps]?:\n | 'createdAt'\n | 'organizationId'\n | 'conversationId'\n | 'targetEntityType'\n | 'targetRecordId'\n | 'fieldDiff'\n | 'records'\n | 'failedRecords'\n | 'sideEffectsSummary'\n | 'recordVersion'\n | 'attachmentIds'\n | 'executionResult'\n | 'resolvedAt'\n | 'resolvedByUserId'\n | 'queueMode'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'agent_id', type: 'text' })\n agentId!: string\n\n @Property({ name: 'tool_name', type: 'text' })\n toolName!: string\n\n @Property({ name: 'conversation_id', type: 'text', nullable: true })\n conversationId?: string | null\n\n @Property({ name: 'target_entity_type', type: 'text', nullable: true })\n targetEntityType?: string | null\n\n @Property({ name: 'target_record_id', type: 'text', nullable: true })\n targetRecordId?: string | null\n\n @Property({ name: 'normalized_input', type: 'jsonb' })\n normalizedInput!: Record<string, unknown>\n\n @Property({ name: 'field_diff', type: 'jsonb', default: [] })\n fieldDiff: AiPendingActionFieldDiff[] = []\n\n @Property({ name: 'records', type: 'jsonb', nullable: true })\n records?: AiPendingActionRecordDiff[] | null\n\n @Property({ name: 'failed_records', type: 'jsonb', nullable: true })\n failedRecords?: AiPendingActionFailedRecord[] | null\n\n @Property({ name: 'side_effects_summary', type: 'text', nullable: true })\n sideEffectsSummary?: string | null\n\n @Property({ name: 'record_version', type: 'text', nullable: true })\n recordVersion?: string | null\n\n @Property({ name: 'attachment_ids', type: 'jsonb', default: [] })\n attachmentIds: string[] = []\n\n @Property({ name: 'idempotency_key', type: 'text' })\n idempotencyKey!: string\n\n @Property({ name: 'created_by_user_id', type: 'uuid' })\n createdByUserId!: string\n\n @Property({ name: 'status', type: 'text' })\n status!: AiPendingActionStatus\n\n @Property({ name: 'queue_mode', type: 'text', default: 'inline' })\n queueMode: AiPendingActionQueueMode = 'inline'\n\n @Property({ name: 'execution_result', type: 'jsonb', nullable: true })\n executionResult?: AiPendingActionExecutionResult | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'expires_at', type: Date })\n expiresAt!: Date\n\n @Property({ name: 'resolved_at', type: Date, nullable: true })\n resolvedAt?: Date | null\n\n @Property({ name: 'resolved_by_user_id', type: 'uuid', nullable: true })\n resolvedByUserId?: string | null\n}\n\n/**\n * Per-tenant runtime override row that controls which provider, model, and\n * base URL the AI runtime uses for a given agent (or all agents when\n * `agent_id` is null).\n *\n * Resolution at query time: a non-null `agent_id` row takes precedence over\n * a null `agent_id` (tenant-wide) row for the same `(tenant_id,\n * organization_id)` scope. All value columns are nullable \u2014 an admin can\n * override just the provider, just the model, or any subset. A null value\n * means \"inherit from the next source in the factory resolution chain.\"\n *\n * Soft-delete via `deleted_at` so the unique partial index and audit trail\n * remain intact across upsert operations.\n *\n * Phase 4a of spec `2026-04-27-ai-agents-provider-model-baseurl-overrides`.\n */\n@Entity({ tableName: 'ai_agent_runtime_overrides' })\n@Index({\n name: 'ai_agent_runtime_overrides_tenant_org_agent_uq',\n expression:\n 'create unique index \"ai_agent_runtime_overrides_tenant_org_agent_uq\" on \"ai_agent_runtime_overrides\" (\"tenant_id\", \"organization_id\", \"agent_id\") where \"deleted_at\" is null and \"organization_id\" is not null and \"agent_id\" is not null',\n})\n@Index({\n name: 'ai_agent_runtime_overrides_tenant_agent_null_org_uq',\n expression:\n 'create unique index \"ai_agent_runtime_overrides_tenant_agent_null_org_uq\" on \"ai_agent_runtime_overrides\" (\"tenant_id\", \"agent_id\") where \"deleted_at\" is null and \"organization_id\" is null and \"agent_id\" is not null',\n})\n@Index({\n name: 'ai_agent_runtime_overrides_tenant_null_agent_null_org_uq',\n expression:\n 'create unique index \"ai_agent_runtime_overrides_tenant_null_agent_null_org_uq\" on \"ai_agent_runtime_overrides\" (\"tenant_id\") where \"deleted_at\" is null and \"organization_id\" is null and \"agent_id\" is null',\n})\n@Index({\n name: 'ai_agent_runtime_overrides_tenant_org_null_agent_uq',\n expression:\n 'create unique index \"ai_agent_runtime_overrides_tenant_org_null_agent_uq\" on \"ai_agent_runtime_overrides\" (\"tenant_id\", \"organization_id\") where \"deleted_at\" is null and \"organization_id\" is not null and \"agent_id\" is null',\n})\n@Index({\n name: 'ai_agent_runtime_overrides_tenant_idx',\n properties: ['tenantId'],\n})\nexport class AiAgentRuntimeOverride {\n [OptionalProps]?:\n | 'createdAt'\n | 'updatedAt'\n | 'organizationId'\n | 'agentId'\n | 'providerId'\n | 'modelId'\n | 'baseUrl'\n | 'allowedOverrideProviders'\n | 'allowedOverrideModelsByProvider'\n | 'updatedByUserId'\n | 'deletedAt'\n | 'loopDisabled'\n | 'loopMaxSteps'\n | 'loopMaxToolCalls'\n | 'loopMaxWallClockMs'\n | 'loopMaxTokens'\n | 'loopStopWhenJson'\n | 'loopActiveToolsJson'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'agent_id', type: 'string', columnType: 'varchar(128)', nullable: true })\n agentId?: string | null\n\n @Property({ name: 'provider_id', type: 'string', columnType: 'varchar(64)', nullable: true })\n providerId?: string | null\n\n @Property({ name: 'model_id', type: 'string', columnType: 'varchar(256)', nullable: true })\n modelId?: string | null\n\n @Property({ name: 'base_url', type: 'string', columnType: 'varchar(2048)', nullable: true })\n baseUrl?: string | null\n\n @Property({ name: 'allowed_override_providers', type: 'jsonb', nullable: true })\n allowedOverrideProviders?: string[] | null\n\n @Property({ name: 'allowed_override_models_by_provider', type: 'jsonb', default: '{}' })\n allowedOverrideModelsByProvider: Record<string, string[]> = {}\n\n @Property({ name: 'updated_by_user_id', type: 'uuid', nullable: true })\n updatedByUserId?: string | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n\n /**\n * Kill switch \u2014 when `true`, runtime forces `stopWhen: stepCountIs(1)` and\n * ignores all other loop config. Phase 3 of spec\n * `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n @Property({ name: 'loop_disabled', type: 'boolean', nullable: true })\n loopDisabled?: boolean | null\n\n /**\n * Override `loop.maxSteps`. Phase 3 of spec\n * `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n @Property({ name: 'loop_max_steps', type: 'int', nullable: true })\n loopMaxSteps?: number | null\n\n /**\n * Override `loop.budget.maxToolCalls`. Phase 3 of spec\n * `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n @Property({ name: 'loop_max_tool_calls', type: 'int', nullable: true })\n loopMaxToolCalls?: number | null\n\n /**\n * Override `loop.budget.maxWallClockMs`. Phase 3 of spec\n * `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n @Property({ name: 'loop_max_wall_clock_ms', type: 'int', nullable: true })\n loopMaxWallClockMs?: number | null\n\n /**\n * Override `loop.budget.maxTokens`. Phase 3 of spec\n * `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n @Property({ name: 'loop_max_tokens', type: 'int', nullable: true })\n loopMaxTokens?: number | null\n\n /**\n * Override `loop.stopWhen`. JSON-safe variants only (`stepCount`,\n * `hasToolCall`); validator rejects `kind: 'custom'`. Phase 3 of spec\n * `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n @Property({ name: 'loop_stop_when_json', type: 'jsonb', nullable: true })\n loopStopWhenJson?: unknown | null\n\n /**\n * Override `loop.activeTools` (must be subset of `agent.allowedTools`).\n * Phase 3 of spec `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n @Property({ name: 'loop_active_tools_json', type: 'jsonb', nullable: true })\n loopActiveToolsJson?: unknown | null\n}\n\n/**\n * Append-only event log for token usage per step (chat) or per turn (object).\n *\n * One row is created by `recordTokenUsage` (Phase 6.3) for every completed\n * AI SDK step. Indexed for the three read patterns: daily rollup, per-agent\n * report, and session drill-down.\n *\n * Retention: rows older than `AI_TOKEN_USAGE_EVENTS_RETENTION_DAYS` (default\n * 90) are swept by the `ai-token-usage-prune` worker (Phase 6.4).\n *\n * Phase 6.0 of spec `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n@Entity({ tableName: 'ai_token_usage_events' })\n@Index({\n name: 'ai_token_usage_events_tenant_created_idx',\n properties: ['tenantId', 'createdAt'],\n})\n@Index({\n name: 'ai_token_usage_events_tenant_agent_created_idx',\n properties: ['tenantId', 'agentId', 'createdAt'],\n})\n@Index({\n name: 'ai_token_usage_events_tenant_model_created_idx',\n properties: ['tenantId', 'modelId', 'createdAt'],\n})\n@Index({\n name: 'ai_token_usage_events_tenant_session_turn_step_idx',\n properties: ['tenantId', 'sessionId', 'turnId', 'stepIndex'],\n})\nexport class AiTokenUsageEvent {\n [OptionalProps]?:\n | 'createdAt'\n | 'updatedAt'\n | 'organizationId'\n | 'cachedInputTokens'\n | 'reasoningTokens'\n | 'finishReason'\n | 'loopAbortReason'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'user_id', type: 'uuid' })\n userId!: string\n\n @Property({ name: 'agent_id', type: 'text' })\n agentId!: string\n\n @Property({ name: 'module_id', type: 'text' })\n moduleId!: string\n\n @Property({ name: 'session_id', type: 'uuid' })\n sessionId!: string\n\n @Property({ name: 'turn_id', type: 'uuid' })\n turnId!: string\n\n @Property({ name: 'step_index', type: 'int' })\n stepIndex!: number\n\n @Property({ name: 'provider_id', type: 'text' })\n providerId!: string\n\n @Property({ name: 'model_id', type: 'text' })\n modelId!: string\n\n @Property({ name: 'input_tokens', type: 'int' })\n inputTokens!: number\n\n @Property({ name: 'output_tokens', type: 'int' })\n outputTokens!: number\n\n @Property({ name: 'cached_input_tokens', type: 'int', nullable: true })\n cachedInputTokens?: number | null\n\n @Property({ name: 'reasoning_tokens', type: 'int', nullable: true })\n reasoningTokens?: number | null\n\n @Property({ name: 'finish_reason', type: 'text', nullable: true })\n finishReason?: string | null\n\n @Property({ name: 'loop_abort_reason', type: 'text', nullable: true })\n loopAbortReason?: string | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n}\n\n/**\n * Materialized daily rollup of token usage per `(tenant, day, agent, model)`.\n *\n * Updated incrementally by UPSERT on every `recordTokenUsage` call so the\n * rollup is always current even when the prune worker is behind. A daily\n * reconciliation worker (Phase 6.4) recomputes `session_count` from the events\n * table to correct any drift caused by event delivery delays or outages.\n *\n * `session_count` is maintained via a per-row LATERAL exists check at write\n * time (first event in a `(tenant, day, agent, model, session)` window\n * increments the counter). This counter may drift if events arrive out of\n * order; the daily worker corrects it.\n *\n * Phase 6.1 of spec `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n@Entity({ tableName: 'ai_token_usage_daily' })\n@Index({\n name: 'ai_token_usage_daily_tenant_day_agent_model_org_uq',\n expression:\n 'create unique index \"ai_token_usage_daily_tenant_day_agent_model_org_uq\" on \"ai_token_usage_daily\" (\"tenant_id\", \"day\", \"agent_id\", \"model_id\", \"organization_id\") where \"organization_id\" is not null',\n})\n@Index({\n name: 'ai_token_usage_daily_tenant_day_agent_model_null_org_uq',\n expression:\n 'create unique index \"ai_token_usage_daily_tenant_day_agent_model_null_org_uq\" on \"ai_token_usage_daily\" (\"tenant_id\", \"day\", \"agent_id\", \"model_id\") where \"organization_id\" is null',\n})\n@Index({\n name: 'ai_token_usage_daily_tenant_day_idx',\n properties: ['tenantId', 'day'],\n})\nexport class AiTokenUsageDaily {\n [OptionalProps]?: 'createdAt' | 'updatedAt' | 'organizationId'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'day', type: 'string', columnType: 'date' })\n day!: string\n\n @Property({ name: 'agent_id', type: 'text' })\n agentId!: string\n\n @Property({ name: 'model_id', type: 'text' })\n modelId!: string\n\n @Property({ name: 'provider_id', type: 'text' })\n providerId!: string\n\n @Property({ name: 'input_tokens', type: 'string', columnType: 'bigint' })\n inputTokens!: string\n\n @Property({ name: 'output_tokens', type: 'string', columnType: 'bigint' })\n outputTokens!: string\n\n @Property({ name: 'cached_input_tokens', type: 'string', columnType: 'bigint' })\n cachedInputTokens!: string\n\n @Property({ name: 'reasoning_tokens', type: 'string', columnType: 'bigint' })\n reasoningTokens!: string\n\n @Property({ name: 'step_count', type: 'string', columnType: 'bigint' })\n stepCount!: string\n\n @Property({ name: 'turn_count', type: 'string', columnType: 'bigint' })\n turnCount!: string\n\n @Property({ name: 'session_count', type: 'string', columnType: 'bigint' })\n sessionCount!: string\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n}\n\n/**\n * Tenant-scoped override of an agent's declared `mutationPolicy` (Step 5.4).\n *\n * Unlike {@link AiAgentPromptOverride}, this surface is NOT versioned \u2014 it is\n * a single-value policy switch per `(tenantId, organizationId, agentId)`. The\n * runtime enforces the override as a DOWNGRADE only: the effective policy\n * equals the MOST RESTRICTIVE of `{ code-declared, override }`. Escalation is\n * a code-level change and is rejected at the route layer.\n *\n * Hierarchy (most restrictive \u2192 least): `read-only` < `destructive-confirm-required`\n * < `confirm-required`. The route never allows an override to widen the\n * code-declared policy.\n */\n/**\n * Tenant-scoped allowlist clipping which providers and models the runtime is\n * permitted to use within the env-driven allowlist (Phase 1780-6 of spec\n * `2026-04-27-ai-agents-provider-model-baseurl-overrides`).\n *\n * Effective constraint chain (outer \u2192 inner): `OM_AI_AVAILABLE_*` env vars \u2192\n * this tenant allowlist \u2192 per-tenant runtime overrides \u2192 per-request overrides.\n * The tenant allowlist may NEVER widen the env allowlist; the runtime\n * intersects the two and surfaces the intersection through the settings GET\n * response so the UI never offers a value the runtime would refuse.\n *\n * `allowedProviders === null` means \"inherit env\" (no tenant-level restriction\n * beyond what the env imposes). `allowedModelsByProvider` keys are provider\n * ids; a missing key means \"inherit env\" for that provider; an empty array\n * means \"no models permitted for this provider\" (effectively disabling it).\n */\n@Entity({ tableName: 'ai_tenant_model_allowlists' })\n@Index({\n name: 'ai_tenant_model_allowlists_tenant_org_uq',\n expression:\n 'create unique index \"ai_tenant_model_allowlists_tenant_org_uq\" on \"ai_tenant_model_allowlists\" (\"tenant_id\", \"organization_id\") where \"deleted_at\" is null and \"organization_id\" is not null',\n})\n@Index({\n name: 'ai_tenant_model_allowlists_tenant_null_org_uq',\n expression:\n 'create unique index \"ai_tenant_model_allowlists_tenant_null_org_uq\" on \"ai_tenant_model_allowlists\" (\"tenant_id\") where \"deleted_at\" is null and \"organization_id\" is null',\n})\n@Index({\n name: 'ai_tenant_model_allowlists_tenant_idx',\n properties: ['tenantId'],\n})\nexport class AiTenantModelAllowlist {\n [OptionalProps]?:\n | 'createdAt'\n | 'updatedAt'\n | 'organizationId'\n | 'allowedProviders'\n | 'allowedModelsByProvider'\n | 'updatedByUserId'\n | 'deletedAt'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'allowed_providers', type: 'jsonb', nullable: true })\n allowedProviders?: string[] | null\n\n @Property({ name: 'allowed_models_by_provider', type: 'jsonb', default: '{}' })\n allowedModelsByProvider: Record<string, string[]> = {}\n\n @Property({ name: 'updated_by_user_id', type: 'uuid', nullable: true })\n updatedByUserId?: string | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n\n@Entity({ tableName: 'ai_agent_mutation_policy_overrides' })\n@Index({\n name: 'ai_agent_mutation_policy_overrides_tenant_org_agent_uq',\n expression:\n 'create unique index \"ai_agent_mutation_policy_overrides_tenant_org_agent_uq\" on \"ai_agent_mutation_policy_overrides\" (\"tenant_id\", \"organization_id\", \"agent_id\") where \"organization_id\" is not null',\n})\n@Index({\n name: 'ai_agent_mutation_policy_overrides_tenant_agent_null_org_uq',\n expression:\n 'create unique index \"ai_agent_mutation_policy_overrides_tenant_agent_null_org_uq\" on \"ai_agent_mutation_policy_overrides\" (\"tenant_id\", \"agent_id\") where \"organization_id\" is null',\n})\n@Index({\n name: 'ai_agent_mutation_policy_overrides_tenant_agent_idx',\n properties: ['tenantId', 'agentId'],\n})\nexport class AiAgentMutationPolicyOverride {\n [OptionalProps]?: 'createdAt' | 'updatedAt' | 'organizationId' | 'createdByUserId' | 'notes'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'agent_id', type: 'text' })\n agentId!: string\n\n @Property({ name: 'mutation_policy', type: 'text' })\n mutationPolicy!: string\n\n @Property({ name: 'notes', type: 'text', nullable: true })\n notes?: string | null\n\n @Property({ name: 'created_by_user_id', type: 'uuid', nullable: true })\n createdByUserId?: string | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n}\n\n/**\n * Tenant-scoped durable record of a typed AI chat session.\n *\n * Owner-only MVP per spec `2026-05-05-ai-chat-server-side-conversation-storage`.\n * The `participants` table prepares for future sharing without a schema\n * rewrite \u2014 the owner row is always written in the same transaction as the\n * conversation row (see `AiChatConversationRepository.createOrGet`).\n *\n * `conversationId` is the stable, client-visible identifier. It is unique\n * within `(tenant_id, organization_id)` so an idempotent `createOrGet` can\n * accept a client-generated UUID. Pending mutation approvals already store\n * the same id in `AiPendingAction.conversationId` \u2014 the chat-history schema\n * deliberately matches that contract so a future foreign key can be added\n * without churn.\n *\n * `imported_from_local_at` flags conversations that the UI lazily migrated\n * from `localStorage`. The flag is informational only; once a row exists it\n * is always the source of truth for that conversation.\n */\n@Entity({ tableName: 'ai_chat_conversations' })\n@Index({\n name: 'ai_chat_conversations_tenant_org_conv_uq',\n expression:\n 'create unique index \"ai_chat_conversations_tenant_org_conv_uq\" on \"ai_chat_conversations\" (\"tenant_id\", \"organization_id\", \"conversation_id\") where \"organization_id\" is not null and \"deleted_at\" is null',\n})\n@Index({\n name: 'ai_chat_conversations_tenant_conv_null_org_uq',\n expression:\n 'create unique index \"ai_chat_conversations_tenant_conv_null_org_uq\" on \"ai_chat_conversations\" (\"tenant_id\", \"conversation_id\") where \"organization_id\" is null and \"deleted_at\" is null',\n})\n@Index({\n name: 'ai_chat_conversations_tenant_org_owner_agent_idx',\n properties: ['tenantId', 'organizationId', 'ownerUserId', 'agentId', 'status', 'lastMessageAt'],\n})\n@Index({\n name: 'ai_chat_conversations_tenant_org_deleted_idx',\n properties: ['tenantId', 'organizationId', 'deletedAt'],\n})\nexport class AiChatConversation {\n [OptionalProps]?:\n | 'createdAt'\n | 'updatedAt'\n | 'organizationId'\n | 'title'\n | 'status'\n | 'visibility'\n | 'pageContext'\n | 'lastMessageAt'\n | 'importedFromLocalAt'\n | 'deletedAt'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'conversation_id', type: 'text' })\n conversationId!: string\n\n @Property({ name: 'agent_id', type: 'text' })\n agentId!: string\n\n @Property({ name: 'owner_user_id', type: 'uuid' })\n ownerUserId!: string\n\n @Property({ name: 'title', type: 'text', nullable: true })\n title?: string | null\n\n @Property({ name: 'status', type: 'text', default: 'open' })\n status: 'open' | 'closed' = 'open'\n\n @Property({ name: 'visibility', type: 'text', default: 'private' })\n visibility: 'private' | 'shared' | 'organization' = 'private'\n\n @Property({ name: 'page_context', type: 'jsonb', nullable: true })\n pageContext?: Record<string, unknown> | null\n\n @Property({ name: 'last_message_at', type: Date, nullable: true })\n lastMessageAt?: Date | null\n\n @Property({ name: 'imported_from_local_at', type: Date, nullable: true })\n importedFromLocalAt?: Date | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n\n/**\n * Membership row for an `AiChatConversation`.\n *\n * MVP always writes exactly one row per conversation with `role = 'owner'`,\n * written transactionally alongside the conversation. Sharing extensions\n * append additional rows with `role IN ('viewer', 'commenter', ...)`. The\n * access predicate is \"is the caller an undeleted participant\" \u2014 see\n * `AiChatConversationRepository.assertAccessible`.\n *\n * `last_read_at` is reserved for future unread/share UX and is unused in MVP.\n */\n@Entity({ tableName: 'ai_chat_conversation_participants' })\n@Index({\n name: 'ai_chat_conv_participants_tenant_org_conv_user_uq',\n expression:\n 'create unique index \"ai_chat_conv_participants_tenant_org_conv_user_uq\" on \"ai_chat_conversation_participants\" (\"tenant_id\", \"organization_id\", \"conversation_id\", \"user_id\") where \"organization_id\" is not null',\n})\n@Index({\n name: 'ai_chat_conv_participants_tenant_conv_user_null_org_uq',\n expression:\n 'create unique index \"ai_chat_conv_participants_tenant_conv_user_null_org_uq\" on \"ai_chat_conversation_participants\" (\"tenant_id\", \"conversation_id\", \"user_id\") where \"organization_id\" is null',\n})\n@Index({\n name: 'ai_chat_conv_participants_tenant_org_user_conv_idx',\n properties: ['tenantId', 'organizationId', 'userId', 'conversationId'],\n})\nexport class AiChatConversationParticipant {\n [OptionalProps]?:\n | 'createdAt'\n | 'updatedAt'\n | 'organizationId'\n | 'role'\n | 'lastReadAt'\n | 'deletedAt'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'conversation_id', type: 'text' })\n conversationId!: string\n\n @Property({ name: 'user_id', type: 'uuid' })\n userId!: string\n\n @Property({ name: 'role', type: 'text', default: 'owner' })\n role: 'owner' | 'viewer' | 'commenter' = 'owner'\n\n @Property({ name: 'last_read_at', type: Date, nullable: true })\n lastReadAt?: Date | null\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n}\n\n/**\n * Append-only message row for an `AiChatConversation`.\n *\n * `client_message_id` is the idempotency key for retries and lazy imports\n * from `localStorage`. The partial unique index allows a non-null\n * `clientMessageId` to dedupe within the conversation while leaving\n * server-only rows (assistant turns persisted from the streaming dispatcher)\n * free of the constraint.\n *\n * `ui_parts` stores the serializable subset of `AiChatMessageUiPart[]` so the\n * chat surface can re-render record cards, mutation-preview cards, etc.\n * across reloads. Attachment previews (`data:` URLs and transient blob\n * URLs) MUST NOT be persisted here \u2014 the UI strips them before upload.\n */\n@Entity({ tableName: 'ai_chat_messages' })\n@Index({\n name: 'ai_chat_messages_tenant_org_conv_client_id_uq',\n expression:\n 'create unique index \"ai_chat_messages_tenant_org_conv_client_id_uq\" on \"ai_chat_messages\" (\"tenant_id\", \"organization_id\", \"conversation_id\", \"client_message_id\") where \"organization_id\" is not null and \"client_message_id\" is not null and \"deleted_at\" is null',\n})\n@Index({\n name: 'ai_chat_messages_tenant_conv_client_id_null_org_uq',\n expression:\n 'create unique index \"ai_chat_messages_tenant_conv_client_id_null_org_uq\" on \"ai_chat_messages\" (\"tenant_id\", \"conversation_id\", \"client_message_id\") where \"organization_id\" is null and \"client_message_id\" is not null and \"deleted_at\" is null',\n})\n@Index({\n name: 'ai_chat_messages_tenant_org_conv_created_idx',\n properties: ['tenantId', 'organizationId', 'conversationId', 'createdAt'],\n})\n@Index({\n name: 'ai_chat_messages_tenant_org_deleted_idx',\n properties: ['tenantId', 'organizationId', 'deletedAt'],\n})\nexport class AiChatMessage {\n [OptionalProps]?:\n | 'createdAt'\n | 'updatedAt'\n | 'organizationId'\n | 'clientMessageId'\n | 'uiParts'\n | 'attachmentIds'\n | 'filesMetadata'\n | 'model'\n | 'metadata'\n | 'createdByUserId'\n | 'deletedAt'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'conversation_id', type: 'text' })\n conversationId!: string\n\n @Property({ name: 'client_message_id', type: 'text', nullable: true })\n clientMessageId?: string | null\n\n @Property({ name: 'role', type: 'text' })\n role!: 'user' | 'assistant' | 'system'\n\n @Property({ name: 'content', type: 'text' })\n content!: string\n\n @Property({ name: 'ui_parts', type: 'jsonb', nullable: true })\n uiParts?: unknown[] | null\n\n @Property({ name: 'attachment_ids', type: 'jsonb', nullable: true })\n attachmentIds?: string[] | null\n\n @Property({ name: 'files_metadata', type: 'jsonb', nullable: true })\n filesMetadata?: Array<Record<string, unknown>> | null\n\n @Property({ name: 'model', type: 'text', nullable: true })\n model?: string | null\n\n @Property({ name: 'metadata', type: 'jsonb', nullable: true })\n metadata?: Record<string, unknown> | null\n\n @Property({ name: 'created_by_user_id', type: 'uuid', nullable: true })\n createdByUserId?: string | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { OptionalProps } from '@mikro-orm/core'\nimport {\n Entity,\n Index,\n PrimaryKey,\n Property,\n} from '@mikro-orm/decorators/legacy'\nimport type {\n AiPendingActionExecutionResult,\n AiPendingActionFailedRecord,\n AiPendingActionFieldDiff,\n AiPendingActionQueueMode,\n AiPendingActionRecordDiff,\n AiPendingActionStatus,\n} from '../lib/pending-action-types'\n\n/**\n * Versioned additive prompt-override for a registered AI agent (Step 5.3).\n *\n * Each write creates a new row with `version = latest + 1`. Rows are never\n * updated in place \u2014 history is preserved so operators can roll back by\n * reading an earlier `version`. Column set is tenant/org-scoped per the\n * standard Open Mercato RBAC contract.\n *\n * `sections` holds additive text keyed by prompt section id. The runtime\n * composes the final `systemPrompt` via `composeSystemPromptWithOverride`\n * (see `lib/prompt-override-merge.ts`), which NEVER replaces a built-in\n * section \u2014 overrides are append-only by contract.\n */\n@Entity({ tableName: 'ai_agent_prompt_overrides' })\n@Index({\n name: 'ai_agent_prompt_overrides_tenant_org_agent_version_uq',\n expression:\n 'create unique index \"ai_agent_prompt_overrides_tenant_org_agent_version_uq\" on \"ai_agent_prompt_overrides\" (\"tenant_id\", \"organization_id\", \"agent_id\", \"version\") where \"organization_id\" is not null',\n})\n@Index({\n name: 'ai_agent_prompt_overrides_tenant_agent_version_null_org_uq',\n expression:\n 'create unique index \"ai_agent_prompt_overrides_tenant_agent_version_null_org_uq\" on \"ai_agent_prompt_overrides\" (\"tenant_id\", \"agent_id\", \"version\") where \"organization_id\" is null',\n})\n@Index({\n name: 'ai_agent_prompt_overrides_tenant_agent_idx',\n properties: ['tenantId', 'agentId'],\n})\n@Index({\n name: 'ai_agent_prompt_overrides_tenant_org_agent_version_idx',\n expression:\n 'create index \"ai_agent_prompt_overrides_tenant_org_agent_version_idx\" on \"ai_agent_prompt_overrides\" (\"tenant_id\", \"organization_id\", \"agent_id\", \"version\" desc)',\n})\nexport class AiAgentPromptOverride {\n [OptionalProps]?: 'createdAt' | 'updatedAt' | 'organizationId' | 'createdByUserId' | 'notes'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'agent_id', type: 'text' })\n agentId!: string\n\n @Property({ name: 'version', type: 'int' })\n version!: number\n\n @Property({ name: 'sections', type: 'jsonb' })\n sections!: Record<string, string>\n\n @Property({ name: 'notes', type: 'text', nullable: true })\n notes?: string | null\n\n @Property({ name: 'created_by_user_id', type: 'uuid', nullable: true })\n createdByUserId?: string | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n}\n\n/**\n * Persistent mutation-approval gate row backing the Phase 3 WS-C contract\n * (spec \u00A78 `AiPendingAction` + \u00A79 confirm/cancel flow, Step 5.5).\n *\n * One row is created by `prepareMutation` (Step 5.6) whenever the runtime\n * intercepts an `isMutation: true` tool call from a non-read-only agent.\n * The row stores the normalized tool input, a precomputed `fieldDiff` (or\n * per-record batch diff in `records[]`), the target record version, an\n * `idempotencyKey` that dedupes double-submits within the TTL, and a\n * `status` that walks the state machine defined in\n * {@link AI_PENDING_ACTION_ALLOWED_TRANSITIONS}.\n *\n * The cleanup worker (Step 5.12) sweeps `status='pending' AND expiresAt < now`\n * rows and transitions them to `expired`. The confirm route (Step 5.8)\n * walks `pending \u2192 confirmed \u2192 executing \u2192 (failed | terminal success)`.\n * Reads always flow through `findOneWithDecryption` /\n * `findWithDecryption`, even though no column is GDPR-flagged today, so\n * future encrypted columns (e.g. `normalizedInput`) are handled.\n */\n@Entity({ tableName: 'ai_pending_actions' })\n@Index({\n name: 'ai_pending_actions_tenant_org_idempotency_uq',\n expression:\n 'create unique index \"ai_pending_actions_tenant_org_idempotency_uq\" on \"ai_pending_actions\" (\"tenant_id\", \"organization_id\", \"idempotency_key\") where \"organization_id\" is not null',\n})\n@Index({\n name: 'ai_pending_actions_tenant_idem_null_org_uq',\n expression:\n 'create unique index \"ai_pending_actions_tenant_idem_null_org_uq\" on \"ai_pending_actions\" (\"tenant_id\", \"idempotency_key\") where \"organization_id\" is null',\n})\n@Index({\n name: 'ai_pending_actions_tenant_org_status_expires_idx',\n properties: ['tenantId', 'organizationId', 'status', 'expiresAt'],\n})\n@Index({\n name: 'ai_pending_actions_tenant_org_agent_status_idx',\n properties: ['tenantId', 'organizationId', 'agentId', 'status'],\n})\nexport class AiPendingAction {\n [OptionalProps]?:\n | 'createdAt'\n | 'organizationId'\n | 'conversationId'\n | 'targetEntityType'\n | 'targetRecordId'\n | 'fieldDiff'\n | 'records'\n | 'failedRecords'\n | 'sideEffectsSummary'\n | 'recordVersion'\n | 'attachmentIds'\n | 'executionResult'\n | 'resolvedAt'\n | 'resolvedByUserId'\n | 'queueMode'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'agent_id', type: 'text' })\n agentId!: string\n\n @Property({ name: 'tool_name', type: 'text' })\n toolName!: string\n\n @Property({ name: 'conversation_id', type: 'text', nullable: true })\n conversationId?: string | null\n\n @Property({ name: 'target_entity_type', type: 'text', nullable: true })\n targetEntityType?: string | null\n\n @Property({ name: 'target_record_id', type: 'text', nullable: true })\n targetRecordId?: string | null\n\n @Property({ name: 'normalized_input', type: 'jsonb' })\n normalizedInput!: Record<string, unknown>\n\n @Property({ name: 'field_diff', type: 'jsonb', default: [] })\n fieldDiff: AiPendingActionFieldDiff[] = []\n\n @Property({ name: 'records', type: 'jsonb', nullable: true })\n records?: AiPendingActionRecordDiff[] | null\n\n @Property({ name: 'failed_records', type: 'jsonb', nullable: true })\n failedRecords?: AiPendingActionFailedRecord[] | null\n\n @Property({ name: 'side_effects_summary', type: 'text', nullable: true })\n sideEffectsSummary?: string | null\n\n @Property({ name: 'record_version', type: 'text', nullable: true })\n recordVersion?: string | null\n\n @Property({ name: 'attachment_ids', type: 'jsonb', default: [] })\n attachmentIds: string[] = []\n\n @Property({ name: 'idempotency_key', type: 'text' })\n idempotencyKey!: string\n\n @Property({ name: 'created_by_user_id', type: 'uuid' })\n createdByUserId!: string\n\n @Property({ name: 'status', type: 'text' })\n status!: AiPendingActionStatus\n\n @Property({ name: 'queue_mode', type: 'text', default: 'inline' })\n queueMode: AiPendingActionQueueMode = 'inline'\n\n @Property({ name: 'execution_result', type: 'jsonb', nullable: true })\n executionResult?: AiPendingActionExecutionResult | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'expires_at', type: Date })\n expiresAt!: Date\n\n @Property({ name: 'resolved_at', type: Date, nullable: true })\n resolvedAt?: Date | null\n\n @Property({ name: 'resolved_by_user_id', type: 'uuid', nullable: true })\n resolvedByUserId?: string | null\n}\n\n/**\n * Per-tenant runtime override row that controls which provider, model, and\n * base URL the AI runtime uses for a given agent (or all agents when\n * `agent_id` is null).\n *\n * Resolution at query time: a non-null `agent_id` row takes precedence over\n * a null `agent_id` (tenant-wide) row for the same `(tenant_id,\n * organization_id)` scope. All value columns are nullable \u2014 an admin can\n * override just the provider, just the model, or any subset. A null value\n * means \"inherit from the next source in the factory resolution chain.\"\n *\n * Soft-delete via `deleted_at` so the unique partial index and audit trail\n * remain intact across upsert operations.\n *\n * Phase 4a of spec `2026-04-27-ai-agents-provider-model-baseurl-overrides`.\n */\n@Entity({ tableName: 'ai_agent_runtime_overrides' })\n@Index({\n name: 'ai_agent_runtime_overrides_tenant_org_agent_uq',\n expression:\n 'create unique index \"ai_agent_runtime_overrides_tenant_org_agent_uq\" on \"ai_agent_runtime_overrides\" (\"tenant_id\", \"organization_id\", \"agent_id\") where \"deleted_at\" is null and \"organization_id\" is not null and \"agent_id\" is not null',\n})\n@Index({\n name: 'ai_agent_runtime_overrides_tenant_agent_null_org_uq',\n expression:\n 'create unique index \"ai_agent_runtime_overrides_tenant_agent_null_org_uq\" on \"ai_agent_runtime_overrides\" (\"tenant_id\", \"agent_id\") where \"deleted_at\" is null and \"organization_id\" is null and \"agent_id\" is not null',\n})\n@Index({\n name: 'ai_agent_runtime_overrides_tenant_null_agent_null_org_uq',\n expression:\n 'create unique index \"ai_agent_runtime_overrides_tenant_null_agent_null_org_uq\" on \"ai_agent_runtime_overrides\" (\"tenant_id\") where \"deleted_at\" is null and \"organization_id\" is null and \"agent_id\" is null',\n})\n@Index({\n name: 'ai_agent_runtime_overrides_tenant_org_null_agent_uq',\n expression:\n 'create unique index \"ai_agent_runtime_overrides_tenant_org_null_agent_uq\" on \"ai_agent_runtime_overrides\" (\"tenant_id\", \"organization_id\") where \"deleted_at\" is null and \"organization_id\" is not null and \"agent_id\" is null',\n})\n@Index({\n name: 'ai_agent_runtime_overrides_tenant_idx',\n properties: ['tenantId'],\n})\nexport class AiAgentRuntimeOverride {\n [OptionalProps]?:\n | 'createdAt'\n | 'updatedAt'\n | 'organizationId'\n | 'agentId'\n | 'providerId'\n | 'modelId'\n | 'baseUrl'\n | 'allowedOverrideProviders'\n | 'allowedOverrideModelsByProvider'\n | 'updatedByUserId'\n | 'deletedAt'\n | 'loopDisabled'\n | 'loopMaxSteps'\n | 'loopMaxToolCalls'\n | 'loopMaxWallClockMs'\n | 'loopMaxTokens'\n | 'loopStopWhenJson'\n | 'loopActiveToolsJson'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'agent_id', type: 'string', columnType: 'varchar(128)', nullable: true })\n agentId?: string | null\n\n @Property({ name: 'provider_id', type: 'string', columnType: 'varchar(64)', nullable: true })\n providerId?: string | null\n\n @Property({ name: 'model_id', type: 'string', columnType: 'varchar(256)', nullable: true })\n modelId?: string | null\n\n @Property({ name: 'base_url', type: 'string', columnType: 'varchar(2048)', nullable: true })\n baseUrl?: string | null\n\n @Property({ name: 'allowed_override_providers', type: 'jsonb', nullable: true })\n allowedOverrideProviders?: string[] | null\n\n @Property({ name: 'allowed_override_models_by_provider', type: 'jsonb', default: '{}' })\n allowedOverrideModelsByProvider: Record<string, string[]> = {}\n\n @Property({ name: 'updated_by_user_id', type: 'uuid', nullable: true })\n updatedByUserId?: string | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n\n /**\n * Kill switch \u2014 when `true`, runtime forces `stopWhen: stepCountIs(1)` and\n * ignores all other loop config. Phase 3 of spec\n * `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n @Property({ name: 'loop_disabled', type: 'boolean', nullable: true })\n loopDisabled?: boolean | null\n\n /**\n * Override `loop.maxSteps`. Phase 3 of spec\n * `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n @Property({ name: 'loop_max_steps', type: 'int', nullable: true })\n loopMaxSteps?: number | null\n\n /**\n * Override `loop.budget.maxToolCalls`. Phase 3 of spec\n * `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n @Property({ name: 'loop_max_tool_calls', type: 'int', nullable: true })\n loopMaxToolCalls?: number | null\n\n /**\n * Override `loop.budget.maxWallClockMs`. Phase 3 of spec\n * `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n @Property({ name: 'loop_max_wall_clock_ms', type: 'int', nullable: true })\n loopMaxWallClockMs?: number | null\n\n /**\n * Override `loop.budget.maxTokens`. Phase 3 of spec\n * `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n @Property({ name: 'loop_max_tokens', type: 'int', nullable: true })\n loopMaxTokens?: number | null\n\n /**\n * Override `loop.stopWhen`. JSON-safe variants only (`stepCount`,\n * `hasToolCall`); validator rejects `kind: 'custom'`. Phase 3 of spec\n * `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n @Property({ name: 'loop_stop_when_json', type: 'jsonb', nullable: true })\n loopStopWhenJson?: unknown | null\n\n /**\n * Override `loop.activeTools` (must be subset of `agent.allowedTools`).\n * Phase 3 of spec `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n @Property({ name: 'loop_active_tools_json', type: 'jsonb', nullable: true })\n loopActiveToolsJson?: unknown | null\n}\n\n/**\n * Append-only event log for token usage per step (chat) or per turn (object).\n *\n * One row is created by `recordTokenUsage` (Phase 6.3) for every completed\n * AI SDK step. Indexed for the three read patterns: daily rollup, per-agent\n * report, and session drill-down.\n *\n * Retention: rows older than `AI_TOKEN_USAGE_EVENTS_RETENTION_DAYS` (default\n * 90) are swept by the `ai-token-usage-prune` worker (Phase 6.4).\n *\n * Phase 6.0 of spec `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n@Entity({ tableName: 'ai_token_usage_events' })\n@Index({\n name: 'ai_token_usage_events_tenant_created_idx',\n properties: ['tenantId', 'createdAt'],\n})\n@Index({\n name: 'ai_token_usage_events_tenant_agent_created_idx',\n properties: ['tenantId', 'agentId', 'createdAt'],\n})\n@Index({\n name: 'ai_token_usage_events_tenant_model_created_idx',\n properties: ['tenantId', 'modelId', 'createdAt'],\n})\n@Index({\n name: 'ai_token_usage_events_tenant_session_turn_step_idx',\n properties: ['tenantId', 'sessionId', 'turnId', 'stepIndex'],\n})\nexport class AiTokenUsageEvent {\n [OptionalProps]?:\n | 'createdAt'\n | 'updatedAt'\n | 'organizationId'\n | 'cachedInputTokens'\n | 'reasoningTokens'\n | 'finishReason'\n | 'loopAbortReason'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'user_id', type: 'uuid' })\n userId!: string\n\n @Property({ name: 'agent_id', type: 'text' })\n agentId!: string\n\n @Property({ name: 'module_id', type: 'text' })\n moduleId!: string\n\n @Property({ name: 'session_id', type: 'uuid' })\n sessionId!: string\n\n @Property({ name: 'turn_id', type: 'uuid' })\n turnId!: string\n\n @Property({ name: 'step_index', type: 'int' })\n stepIndex!: number\n\n @Property({ name: 'provider_id', type: 'text' })\n providerId!: string\n\n @Property({ name: 'model_id', type: 'text' })\n modelId!: string\n\n @Property({ name: 'input_tokens', type: 'int' })\n inputTokens!: number\n\n @Property({ name: 'output_tokens', type: 'int' })\n outputTokens!: number\n\n @Property({ name: 'cached_input_tokens', type: 'int', nullable: true })\n cachedInputTokens?: number | null\n\n @Property({ name: 'reasoning_tokens', type: 'int', nullable: true })\n reasoningTokens?: number | null\n\n @Property({ name: 'finish_reason', type: 'text', nullable: true })\n finishReason?: string | null\n\n @Property({ name: 'loop_abort_reason', type: 'text', nullable: true })\n loopAbortReason?: string | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n}\n\n/**\n * Materialized daily rollup of token usage per `(tenant, day, agent, model)`.\n *\n * Updated incrementally by UPSERT on every `recordTokenUsage` call so the\n * rollup is always current even when the prune worker is behind. A daily\n * reconciliation worker (Phase 6.4) recomputes `session_count` from the events\n * table to correct any drift caused by event delivery delays or outages.\n *\n * `session_count` is maintained via a per-row LATERAL exists check at write\n * time (first event in a `(tenant, day, agent, model, session)` window\n * increments the counter). This counter may drift if events arrive out of\n * order; the daily worker corrects it.\n *\n * Phase 6.1 of spec `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n@Entity({ tableName: 'ai_token_usage_daily' })\n@Index({\n name: 'ai_token_usage_daily_tenant_day_agent_model_org_uq',\n expression:\n 'create unique index \"ai_token_usage_daily_tenant_day_agent_model_org_uq\" on \"ai_token_usage_daily\" (\"tenant_id\", \"day\", \"agent_id\", \"model_id\", \"organization_id\") where \"organization_id\" is not null',\n})\n@Index({\n name: 'ai_token_usage_daily_tenant_day_agent_model_null_org_uq',\n expression:\n 'create unique index \"ai_token_usage_daily_tenant_day_agent_model_null_org_uq\" on \"ai_token_usage_daily\" (\"tenant_id\", \"day\", \"agent_id\", \"model_id\") where \"organization_id\" is null',\n})\n@Index({\n name: 'ai_token_usage_daily_tenant_day_idx',\n properties: ['tenantId', 'day'],\n})\nexport class AiTokenUsageDaily {\n [OptionalProps]?: 'createdAt' | 'updatedAt' | 'organizationId'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'day', type: 'string', columnType: 'date' })\n day!: string\n\n @Property({ name: 'agent_id', type: 'text' })\n agentId!: string\n\n @Property({ name: 'model_id', type: 'text' })\n modelId!: string\n\n @Property({ name: 'provider_id', type: 'text' })\n providerId!: string\n\n @Property({ name: 'input_tokens', type: 'string', columnType: 'bigint' })\n inputTokens!: string\n\n @Property({ name: 'output_tokens', type: 'string', columnType: 'bigint' })\n outputTokens!: string\n\n @Property({ name: 'cached_input_tokens', type: 'string', columnType: 'bigint' })\n cachedInputTokens!: string\n\n @Property({ name: 'reasoning_tokens', type: 'string', columnType: 'bigint' })\n reasoningTokens!: string\n\n @Property({ name: 'step_count', type: 'string', columnType: 'bigint' })\n stepCount!: string\n\n @Property({ name: 'turn_count', type: 'string', columnType: 'bigint' })\n turnCount!: string\n\n @Property({ name: 'session_count', type: 'string', columnType: 'bigint' })\n sessionCount!: string\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n}\n\n/**\n * Tenant-scoped override of an agent's declared `mutationPolicy` (Step 5.4).\n *\n * Unlike {@link AiAgentPromptOverride}, this surface is NOT versioned \u2014 it is\n * a single-value policy switch per `(tenantId, organizationId, agentId)`. The\n * runtime enforces the override as a DOWNGRADE only: the effective policy\n * equals the MOST RESTRICTIVE of `{ code-declared, override }`. Escalation is\n * a code-level change and is rejected at the route layer.\n *\n * Hierarchy (most restrictive \u2192 least): `read-only` < `destructive-confirm-required`\n * < `confirm-required`. The route never allows an override to widen the\n * code-declared policy.\n */\n/**\n * Tenant-scoped allowlist clipping which providers and models the runtime is\n * permitted to use within the env-driven allowlist (Phase 1780-6 of spec\n * `2026-04-27-ai-agents-provider-model-baseurl-overrides`).\n *\n * Effective constraint chain (outer \u2192 inner): `OM_AI_AVAILABLE_*` env vars \u2192\n * this tenant allowlist \u2192 per-tenant runtime overrides \u2192 per-request overrides.\n * The tenant allowlist may NEVER widen the env allowlist; the runtime\n * intersects the two and surfaces the intersection through the settings GET\n * response so the UI never offers a value the runtime would refuse.\n *\n * `allowedProviders === null` means \"inherit env\" (no tenant-level restriction\n * beyond what the env imposes). `allowedModelsByProvider` keys are provider\n * ids; a missing key means \"inherit env\" for that provider; an empty array\n * means \"no models permitted for this provider\" (effectively disabling it).\n */\n@Entity({ tableName: 'ai_tenant_model_allowlists' })\n@Index({\n name: 'ai_tenant_model_allowlists_tenant_org_uq',\n expression:\n 'create unique index \"ai_tenant_model_allowlists_tenant_org_uq\" on \"ai_tenant_model_allowlists\" (\"tenant_id\", \"organization_id\") where \"deleted_at\" is null and \"organization_id\" is not null',\n})\n@Index({\n name: 'ai_tenant_model_allowlists_tenant_null_org_uq',\n expression:\n 'create unique index \"ai_tenant_model_allowlists_tenant_null_org_uq\" on \"ai_tenant_model_allowlists\" (\"tenant_id\") where \"deleted_at\" is null and \"organization_id\" is null',\n})\n@Index({\n name: 'ai_tenant_model_allowlists_tenant_idx',\n properties: ['tenantId'],\n})\nexport class AiTenantModelAllowlist {\n [OptionalProps]?:\n | 'createdAt'\n | 'updatedAt'\n | 'organizationId'\n | 'allowedProviders'\n | 'allowedModelsByProvider'\n | 'updatedByUserId'\n | 'deletedAt'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'allowed_providers', type: 'jsonb', nullable: true })\n allowedProviders?: string[] | null\n\n @Property({ name: 'allowed_models_by_provider', type: 'jsonb', default: '{}' })\n allowedModelsByProvider: Record<string, string[]> = {}\n\n @Property({ name: 'updated_by_user_id', type: 'uuid', nullable: true })\n updatedByUserId?: string | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n\n@Entity({ tableName: 'ai_agent_mutation_policy_overrides' })\n@Index({\n name: 'ai_agent_mutation_policy_overrides_tenant_org_agent_uq',\n expression:\n 'create unique index \"ai_agent_mutation_policy_overrides_tenant_org_agent_uq\" on \"ai_agent_mutation_policy_overrides\" (\"tenant_id\", \"organization_id\", \"agent_id\") where \"organization_id\" is not null',\n})\n@Index({\n name: 'ai_agent_mutation_policy_overrides_tenant_agent_null_org_uq',\n expression:\n 'create unique index \"ai_agent_mutation_policy_overrides_tenant_agent_null_org_uq\" on \"ai_agent_mutation_policy_overrides\" (\"tenant_id\", \"agent_id\") where \"organization_id\" is null',\n})\n@Index({\n name: 'ai_agent_mutation_policy_overrides_tenant_agent_idx',\n properties: ['tenantId', 'agentId'],\n})\nexport class AiAgentMutationPolicyOverride {\n [OptionalProps]?: 'createdAt' | 'updatedAt' | 'organizationId' | 'createdByUserId' | 'notes'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'agent_id', type: 'text' })\n agentId!: string\n\n @Property({ name: 'mutation_policy', type: 'text' })\n mutationPolicy!: string\n\n @Property({ name: 'notes', type: 'text', nullable: true })\n notes?: string | null\n\n @Property({ name: 'created_by_user_id', type: 'uuid', nullable: true })\n createdByUserId?: string | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n}\n\n/**\n * Tenant-scoped durable record of a typed AI chat session.\n *\n * Owner-only MVP per spec `2026-05-05-ai-chat-server-side-conversation-storage`.\n * The `participants` table prepares for future sharing without a schema\n * rewrite \u2014 the owner row is always written in the same transaction as the\n * conversation row (see `AiChatConversationRepository.createOrGet`).\n *\n * `conversationId` is the stable, client-visible identifier. It is unique\n * within `(tenant_id, organization_id)` so an idempotent `createOrGet` can\n * accept a client-generated UUID. Pending mutation approvals already store\n * the same id in `AiPendingAction.conversationId` \u2014 the chat-history schema\n * deliberately matches that contract so a future foreign key can be added\n * without churn.\n *\n * `imported_from_local_at` flags conversations that the UI lazily migrated\n * from `localStorage`. The flag is informational only; once a row exists it\n * is always the source of truth for that conversation.\n */\n@Entity({ tableName: 'ai_chat_conversations' })\n@Index({\n name: 'ai_chat_conversations_tenant_org_conv_uq',\n expression:\n 'create unique index \"ai_chat_conversations_tenant_org_conv_uq\" on \"ai_chat_conversations\" (\"tenant_id\", \"organization_id\", \"conversation_id\") where \"organization_id\" is not null and \"deleted_at\" is null',\n})\n@Index({\n name: 'ai_chat_conversations_tenant_conv_null_org_uq',\n expression:\n 'create unique index \"ai_chat_conversations_tenant_conv_null_org_uq\" on \"ai_chat_conversations\" (\"tenant_id\", \"conversation_id\") where \"organization_id\" is null and \"deleted_at\" is null',\n})\n@Index({\n name: 'ai_chat_conversations_tenant_org_owner_agent_idx',\n properties: ['tenantId', 'organizationId', 'ownerUserId', 'agentId', 'status', 'lastMessageAt'],\n})\n@Index({\n name: 'ai_chat_conversations_tenant_org_deleted_idx',\n properties: ['tenantId', 'organizationId', 'deletedAt'],\n})\nexport class AiChatConversation {\n [OptionalProps]?:\n | 'createdAt'\n | 'updatedAt'\n | 'organizationId'\n | 'title'\n | 'status'\n | 'visibility'\n | 'pageContext'\n | 'lastMessageAt'\n | 'importedFromLocalAt'\n | 'deletedAt'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'conversation_id', type: 'text' })\n conversationId!: string\n\n @Property({ name: 'agent_id', type: 'text' })\n agentId!: string\n\n @Property({ name: 'owner_user_id', type: 'uuid' })\n ownerUserId!: string\n\n @Property({ name: 'title', type: 'text', nullable: true })\n title?: string | null\n\n @Property({ name: 'status', type: 'text', default: 'open' })\n status: 'open' | 'closed' = 'open'\n\n @Property({ name: 'visibility', type: 'text', default: 'private' })\n visibility: 'private' | 'shared' | 'organization' = 'private'\n\n @Property({ name: 'page_context', type: 'jsonb', nullable: true })\n pageContext?: Record<string, unknown> | null\n\n @Property({ name: 'last_message_at', type: Date, nullable: true })\n lastMessageAt?: Date | null\n\n @Property({ name: 'imported_from_local_at', type: Date, nullable: true })\n importedFromLocalAt?: Date | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n\n/**\n * Membership row for an `AiChatConversation`.\n *\n * MVP always writes exactly one row per conversation with `role = 'owner'`,\n * written transactionally alongside the conversation. Sharing extensions\n * append additional rows with `role IN ('viewer', 'commenter', ...)`. The\n * access predicate is \"is the caller an undeleted participant\" \u2014 see\n * `AiChatConversationRepository.assertAccessible`.\n *\n * `last_read_at` is reserved for future unread/share UX and is unused in MVP.\n */\n@Entity({ tableName: 'ai_chat_conversation_participants' })\n@Index({\n name: 'ai_chat_conv_participants_tenant_org_conv_user_uq',\n expression:\n 'create unique index \"ai_chat_conv_participants_tenant_org_conv_user_uq\" on \"ai_chat_conversation_participants\" (\"tenant_id\", \"organization_id\", \"conversation_id\", \"user_id\") where \"organization_id\" is not null',\n})\n@Index({\n name: 'ai_chat_conv_participants_tenant_conv_user_null_org_uq',\n expression:\n 'create unique index \"ai_chat_conv_participants_tenant_conv_user_null_org_uq\" on \"ai_chat_conversation_participants\" (\"tenant_id\", \"conversation_id\", \"user_id\") where \"organization_id\" is null',\n})\n@Index({\n name: 'ai_chat_conv_participants_active_conv_user_idx',\n expression:\n 'create index \"ai_chat_conv_participants_active_conv_user_idx\" on \"ai_chat_conversation_participants\" (\"tenant_id\", \"organization_id\", \"conversation_id\", \"user_id\") where \"deleted_at\" is null',\n})\n@Index({\n name: 'ai_chat_conv_participants_tenant_org_user_conv_idx',\n properties: ['tenantId', 'organizationId', 'userId', 'conversationId'],\n})\nexport class AiChatConversationParticipant {\n [OptionalProps]?:\n | 'createdAt'\n | 'updatedAt'\n | 'organizationId'\n | 'role'\n | 'lastReadAt'\n | 'deletedAt'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'conversation_id', type: 'text' })\n conversationId!: string\n\n @Property({ name: 'user_id', type: 'uuid' })\n userId!: string\n\n @Property({ name: 'role', type: 'text', default: 'owner' })\n role: 'owner' | 'viewer' | 'commenter' = 'owner'\n\n @Property({ name: 'last_read_at', type: Date, nullable: true })\n lastReadAt?: Date | null\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n}\n\n/**\n * Append-only message row for an `AiChatConversation`.\n *\n * `client_message_id` is the idempotency key for retries and lazy imports\n * from `localStorage`. The partial unique index allows a non-null\n * `clientMessageId` to dedupe within the conversation while leaving\n * server-only rows (assistant turns persisted from the streaming dispatcher)\n * free of the constraint.\n *\n * `ui_parts` stores the serializable subset of `AiChatMessageUiPart[]` so the\n * chat surface can re-render record cards, mutation-preview cards, etc.\n * across reloads. Attachment previews (`data:` URLs and transient blob\n * URLs) MUST NOT be persisted here \u2014 the UI strips them before upload.\n */\n@Entity({ tableName: 'ai_chat_messages' })\n@Index({\n name: 'ai_chat_messages_tenant_org_conv_client_id_uq',\n expression:\n 'create unique index \"ai_chat_messages_tenant_org_conv_client_id_uq\" on \"ai_chat_messages\" (\"tenant_id\", \"organization_id\", \"conversation_id\", \"client_message_id\") where \"organization_id\" is not null and \"client_message_id\" is not null and \"deleted_at\" is null',\n})\n@Index({\n name: 'ai_chat_messages_tenant_conv_client_id_null_org_uq',\n expression:\n 'create unique index \"ai_chat_messages_tenant_conv_client_id_null_org_uq\" on \"ai_chat_messages\" (\"tenant_id\", \"conversation_id\", \"client_message_id\") where \"organization_id\" is null and \"client_message_id\" is not null and \"deleted_at\" is null',\n})\n@Index({\n name: 'ai_chat_messages_tenant_org_conv_created_idx',\n properties: ['tenantId', 'organizationId', 'conversationId', 'createdAt'],\n})\n@Index({\n name: 'ai_chat_messages_tenant_org_deleted_idx',\n properties: ['tenantId', 'organizationId', 'deletedAt'],\n})\nexport class AiChatMessage {\n [OptionalProps]?:\n | 'createdAt'\n | 'updatedAt'\n | 'organizationId'\n | 'clientMessageId'\n | 'uiParts'\n | 'attachmentIds'\n | 'filesMetadata'\n | 'model'\n | 'metadata'\n | 'createdByUserId'\n | 'deletedAt'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'conversation_id', type: 'text' })\n conversationId!: string\n\n @Property({ name: 'client_message_id', type: 'text', nullable: true })\n clientMessageId?: string | null\n\n @Property({ name: 'role', type: 'text' })\n role!: 'user' | 'assistant' | 'system'\n\n @Property({ name: 'content', type: 'text' })\n content!: string\n\n @Property({ name: 'ui_parts', type: 'jsonb', nullable: true })\n uiParts?: unknown[] | null\n\n @Property({ name: 'attachment_ids', type: 'jsonb', nullable: true })\n attachmentIds?: string[] | null\n\n @Property({ name: 'files_metadata', type: 'jsonb', nullable: true })\n filesMetadata?: Array<Record<string, unknown>> | null\n\n @Property({ name: 'model', type: 'text', nullable: true })\n model?: string | null\n\n @Property({ name: 'metadata', type: 'jsonb', nullable: true })\n metadata?: Record<string, unknown> | null\n\n @Property({ name: 'created_by_user_id', type: 'uuid', nullable: true })\n createdByUserId?: string | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -25,14 +25,6 @@ async function createMcpClient(options) {
25
25
  }
26
26
  if (options.stdioArgs) {
27
27
  stdioOptions.args = options.stdioArgs;
28
- } else {
29
- stdioOptions.args = [
30
- "mercato",
31
- "ai_assistant",
32
- "mcp:serve",
33
- "--api-key",
34
- apiKeySecret
35
- ];
36
28
  }
37
29
  if (options.cwd) {
38
30
  stdioOptions.cwd = options.cwd;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/ai_assistant/lib/client-factory.ts"],
4
- "sourcesContent": ["import type { AwilixContainer } from 'awilix'\nimport type { McpClientInterface } from './types'\n\n/**\n * Client connection mode.\n */\nexport type ClientMode = 'in-process' | 'stdio' | 'http'\n\n/**\n * Options for creating an MCP client.\n */\nexport type CreateClientOptions = {\n /** Connection mode */\n mode: ClientMode\n /** API key secret for authentication */\n apiKeySecret: string\n /** DI container (required for in-process mode) */\n container?: AwilixContainer\n /** HTTP server URL (required for http mode) */\n httpUrl?: string\n /** Custom command for stdio mode (default: 'yarn') */\n stdioCommand?: string\n /** Custom args for stdio mode (default: mercato mcp:serve) */\n stdioArgs?: string[]\n /** Working directory for stdio mode */\n cwd?: string\n}\n\n/**\n * Create an MCP client with the specified connection mode.\n *\n * All modes authenticate via API key, ensuring consistent ACL enforcement.\n *\n * @example\n * ```typescript\n * // In-process mode (fastest, same process)\n * const client = await createMcpClient({\n * mode: 'in-process',\n * apiKeySecret: 'omk_xxx.yyy',\n * container: diContainer,\n * })\n *\n * // Stdio mode (subprocess)\n * const client = await createMcpClient({\n * mode: 'stdio',\n * apiKeySecret: 'omk_xxx.yyy',\n * })\n *\n * // HTTP mode (network)\n * const client = await createMcpClient({\n * mode: 'http',\n * apiKeySecret: 'omk_xxx.yyy',\n * httpUrl: 'http://localhost:3001/mcp',\n * })\n *\n * // Use client (same interface for all modes)\n * const tools = await client.listTools()\n * const result = await client.callTool('search.query', { query: 'test' })\n * await client.close()\n * ```\n */\nexport async function createMcpClient(options: CreateClientOptions): Promise<McpClientInterface> {\n const { mode, apiKeySecret } = options\n\n if (!apiKeySecret) {\n throw new Error('API key secret is required')\n }\n\n switch (mode) {\n case 'in-process': {\n if (!options.container) {\n throw new Error('DI container is required for in-process mode')\n }\n\n const { InProcessMcpClient } = await import('./in-process-client')\n return InProcessMcpClient.create({\n apiKeySecret,\n container: options.container,\n })\n }\n\n case 'stdio': {\n const { McpClient } = await import('./mcp-client')\n\n const stdioOptions: any = {\n transport: 'stdio' as const,\n apiKeySecret,\n }\n\n if (options.stdioCommand) {\n stdioOptions.command = options.stdioCommand\n }\n\n if (options.stdioArgs) {\n stdioOptions.args = options.stdioArgs\n } else {\n // Default args include the API key\n stdioOptions.args = [\n 'mercato',\n 'ai_assistant',\n 'mcp:serve',\n '--api-key',\n apiKeySecret,\n ]\n }\n\n if (options.cwd) {\n stdioOptions.cwd = options.cwd\n }\n\n return McpClient.connect(stdioOptions)\n }\n\n case 'http': {\n if (!options.httpUrl) {\n throw new Error('HTTP URL is required for http mode')\n }\n\n const { McpClient } = await import('./mcp-client')\n return McpClient.connect({\n transport: 'http',\n apiKeySecret,\n url: options.httpUrl,\n })\n }\n\n default:\n throw new Error(`Unknown client mode: ${mode}`)\n }\n}\n"],
5
- "mappings": "AA6DA,eAAsB,gBAAgB,SAA2D;AAC/F,QAAM,EAAE,MAAM,aAAa,IAAI;AAE/B,MAAI,CAAC,cAAc;AACjB,UAAM,IAAI,MAAM,4BAA4B;AAAA,EAC9C;AAEA,UAAQ,MAAM;AAAA,IACZ,KAAK,cAAc;AACjB,UAAI,CAAC,QAAQ,WAAW;AACtB,cAAM,IAAI,MAAM,8CAA8C;AAAA,MAChE;AAEA,YAAM,EAAE,mBAAmB,IAAI,MAAM,OAAO,qBAAqB;AACjE,aAAO,mBAAmB,OAAO;AAAA,QAC/B;AAAA,QACA,WAAW,QAAQ;AAAA,MACrB,CAAC;AAAA,IACH;AAAA,IAEA,KAAK,SAAS;AACZ,YAAM,EAAE,UAAU,IAAI,MAAM,OAAO,cAAc;AAEjD,YAAM,eAAoB;AAAA,QACxB,WAAW;AAAA,QACX;AAAA,MACF;AAEA,UAAI,QAAQ,cAAc;AACxB,qBAAa,UAAU,QAAQ;AAAA,MACjC;AAEA,UAAI,QAAQ,WAAW;AACrB,qBAAa,OAAO,QAAQ;AAAA,MAC9B,OAAO;AAEL,qBAAa,OAAO;AAAA,UAClB;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAEA,UAAI,QAAQ,KAAK;AACf,qBAAa,MAAM,QAAQ;AAAA,MAC7B;AAEA,aAAO,UAAU,QAAQ,YAAY;AAAA,IACvC;AAAA,IAEA,KAAK,QAAQ;AACX,UAAI,CAAC,QAAQ,SAAS;AACpB,cAAM,IAAI,MAAM,oCAAoC;AAAA,MACtD;AAEA,YAAM,EAAE,UAAU,IAAI,MAAM,OAAO,cAAc;AACjD,aAAO,UAAU,QAAQ;AAAA,QACvB,WAAW;AAAA,QACX;AAAA,QACA,KAAK,QAAQ;AAAA,MACf,CAAC;AAAA,IACH;AAAA,IAEA;AACE,YAAM,IAAI,MAAM,wBAAwB,IAAI,EAAE;AAAA,EAClD;AACF;",
4
+ "sourcesContent": ["import type { AwilixContainer } from 'awilix'\nimport type { McpClientInterface } from './types'\n\n/**\n * Client connection mode.\n */\nexport type ClientMode = 'in-process' | 'stdio' | 'http'\n\n/**\n * Options for creating an MCP client.\n */\nexport type CreateClientOptions = {\n /** Connection mode */\n mode: ClientMode\n /** API key secret for authentication */\n apiKeySecret: string\n /** DI container (required for in-process mode) */\n container?: AwilixContainer\n /** HTTP server URL (required for http mode) */\n httpUrl?: string\n /** Custom command for stdio mode (default: 'yarn') */\n stdioCommand?: string\n /** Custom args for stdio mode (default: mercato mcp:serve) */\n stdioArgs?: string[]\n /** Working directory for stdio mode */\n cwd?: string\n}\n\n/**\n * Create an MCP client with the specified connection mode.\n *\n * All modes authenticate via API key, ensuring consistent ACL enforcement.\n *\n * @example\n * ```typescript\n * // In-process mode (fastest, same process)\n * const client = await createMcpClient({\n * mode: 'in-process',\n * apiKeySecret: 'omk_xxx.yyy',\n * container: diContainer,\n * })\n *\n * // Stdio mode (subprocess)\n * const client = await createMcpClient({\n * mode: 'stdio',\n * apiKeySecret: 'omk_xxx.yyy',\n * })\n *\n * // HTTP mode (network)\n * const client = await createMcpClient({\n * mode: 'http',\n * apiKeySecret: 'omk_xxx.yyy',\n * httpUrl: 'http://localhost:3001/mcp',\n * })\n *\n * // Use client (same interface for all modes)\n * const tools = await client.listTools()\n * const result = await client.callTool('search.query', { query: 'test' })\n * await client.close()\n * ```\n */\nexport async function createMcpClient(options: CreateClientOptions): Promise<McpClientInterface> {\n const { mode, apiKeySecret } = options\n\n if (!apiKeySecret) {\n throw new Error('API key secret is required')\n }\n\n switch (mode) {\n case 'in-process': {\n if (!options.container) {\n throw new Error('DI container is required for in-process mode')\n }\n\n const { InProcessMcpClient } = await import('./in-process-client')\n return InProcessMcpClient.create({\n apiKeySecret,\n container: options.container,\n })\n }\n\n case 'stdio': {\n const { McpClient } = await import('./mcp-client')\n\n const stdioOptions: any = {\n transport: 'stdio' as const,\n apiKeySecret,\n }\n\n if (options.stdioCommand) {\n stdioOptions.command = options.stdioCommand\n }\n\n if (options.stdioArgs) {\n stdioOptions.args = options.stdioArgs\n }\n // Otherwise let McpClient.connectStdio apply its default args. The API key\n // is delivered to the child via the OPEN_MERCATO_API_KEY env var, never on\n // argv \u2014 command-line arguments are world-readable (ps / /proc/<pid>/cmdline).\n\n if (options.cwd) {\n stdioOptions.cwd = options.cwd\n }\n\n return McpClient.connect(stdioOptions)\n }\n\n case 'http': {\n if (!options.httpUrl) {\n throw new Error('HTTP URL is required for http mode')\n }\n\n const { McpClient } = await import('./mcp-client')\n return McpClient.connect({\n transport: 'http',\n apiKeySecret,\n url: options.httpUrl,\n })\n }\n\n default:\n throw new Error(`Unknown client mode: ${mode}`)\n }\n}\n"],
5
+ "mappings": "AA6DA,eAAsB,gBAAgB,SAA2D;AAC/F,QAAM,EAAE,MAAM,aAAa,IAAI;AAE/B,MAAI,CAAC,cAAc;AACjB,UAAM,IAAI,MAAM,4BAA4B;AAAA,EAC9C;AAEA,UAAQ,MAAM;AAAA,IACZ,KAAK,cAAc;AACjB,UAAI,CAAC,QAAQ,WAAW;AACtB,cAAM,IAAI,MAAM,8CAA8C;AAAA,MAChE;AAEA,YAAM,EAAE,mBAAmB,IAAI,MAAM,OAAO,qBAAqB;AACjE,aAAO,mBAAmB,OAAO;AAAA,QAC/B;AAAA,QACA,WAAW,QAAQ;AAAA,MACrB,CAAC;AAAA,IACH;AAAA,IAEA,KAAK,SAAS;AACZ,YAAM,EAAE,UAAU,IAAI,MAAM,OAAO,cAAc;AAEjD,YAAM,eAAoB;AAAA,QACxB,WAAW;AAAA,QACX;AAAA,MACF;AAEA,UAAI,QAAQ,cAAc;AACxB,qBAAa,UAAU,QAAQ;AAAA,MACjC;AAEA,UAAI,QAAQ,WAAW;AACrB,qBAAa,OAAO,QAAQ;AAAA,MAC9B;AAKA,UAAI,QAAQ,KAAK;AACf,qBAAa,MAAM,QAAQ;AAAA,MAC7B;AAEA,aAAO,UAAU,QAAQ,YAAY;AAAA,IACvC;AAAA,IAEA,KAAK,QAAQ;AACX,UAAI,CAAC,QAAQ,SAAS;AACpB,cAAM,IAAI,MAAM,oCAAoC;AAAA,MACtD;AAEA,YAAM,EAAE,UAAU,IAAI,MAAM,OAAO,cAAc;AACjD,aAAO,UAAU,QAAQ;AAAA,QACvB,WAAW;AAAA,QACX;AAAA,QACA,KAAK,QAAQ;AAAA,MACf,CAAC;AAAA,IACH;AAAA,IAEA;AACE,YAAM,IAAI,MAAM,wBAAwB,IAAI,EAAE;AAAA,EAClD;AACF;",
6
6
  "names": []
7
7
  }
@@ -25,16 +25,14 @@ class McpClient {
25
25
  const args = options.args ?? [
26
26
  "mercato",
27
27
  "ai_assistant",
28
- "mcp:serve",
29
- "--api-key",
30
- options.apiKeySecret
28
+ "mcp:serve"
31
29
  ];
32
30
  const cwd = options.cwd ?? process.cwd();
33
31
  const transport = new StdioClientTransport({
34
32
  command,
35
33
  args,
36
34
  cwd,
37
- env: process.env,
35
+ env: { ...process.env, OPEN_MERCATO_API_KEY: options.apiKeySecret },
38
36
  stderr: "pipe"
39
37
  });
40
38
  transport.stderr?.on("data", (data) => {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/ai_assistant/lib/mcp-client.ts"],
4
- "sourcesContent": ["import { Client } from '@modelcontextprotocol/sdk/client/index.js'\nimport { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js'\nimport { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'\nimport type { McpClientInterface, ToolInfo, ToolResult } from './types'\n\n/**\n * Options for stdio transport.\n */\nexport type StdioClientOptions = {\n transport: 'stdio'\n /** API key secret (passed to server via --api-key) */\n apiKeySecret: string\n /** Command to run (default: 'yarn') */\n command?: string\n /** Arguments for the command (default: mercato mcp:serve with api-key) */\n args?: string[]\n /** Working directory (default: process.cwd()) */\n cwd?: string\n}\n\n/**\n * Options for HTTP transport.\n */\nexport type HttpClientOptions = {\n transport: 'http'\n /** API key secret (sent via x-api-key header) */\n apiKeySecret: string\n /** MCP server URL (e.g., 'http://localhost:3001/mcp') */\n url: string\n}\n\n/**\n * Combined options for McpClient.\n */\nexport type McpClientOptions = StdioClientOptions | HttpClientOptions\n\n/**\n * MCP protocol client for connecting to MCP servers.\n *\n * Supports two transport modes:\n * - stdio: Spawns server as subprocess\n * - http: Connects to HTTP server\n */\nexport class McpClient implements McpClientInterface {\n private client: Client\n private transport: StdioClientTransport | StreamableHTTPClientTransport\n private apiKeySecret: string\n\n private constructor(\n client: Client,\n transport: StdioClientTransport | StreamableHTTPClientTransport,\n apiKeySecret: string\n ) {\n this.client = client\n this.transport = transport\n this.apiKeySecret = apiKeySecret\n }\n\n /**\n * Connect to an MCP server via the specified transport.\n */\n static async connect(options: McpClientOptions): Promise<McpClient> {\n if (options.transport === 'stdio') {\n return McpClient.connectStdio(options)\n } else {\n return McpClient.connectHttp(options)\n }\n }\n\n /**\n * Connect via stdio transport (spawn subprocess).\n */\n private static async connectStdio(options: StdioClientOptions): Promise<McpClient> {\n const command = options.command ?? 'yarn'\n const args = options.args ?? [\n 'mercato',\n 'ai_assistant',\n 'mcp:serve',\n '--api-key',\n options.apiKeySecret,\n ]\n const cwd = options.cwd ?? process.cwd()\n\n const transport = new StdioClientTransport({\n command,\n args,\n cwd,\n env: process.env as Record<string, string>,\n stderr: 'pipe',\n })\n transport.stderr?.on('data', (data) => {\n const message = data.toString().trim()\n if (message) {\n console.error(`[MCP Client] ${message}`)\n }\n })\n\n const client = new Client(\n { name: 'open-mercato-client', version: '0.1.0' },\n { capabilities: {} }\n )\n\n await client.connect(transport)\n\n return new McpClient(client, transport, options.apiKeySecret)\n }\n\n /**\n * Connect via HTTP transport.\n */\n private static async connectHttp(options: HttpClientOptions): Promise<McpClient> {\n const transport = new StreamableHTTPClientTransport(\n new URL(options.url),\n {\n requestInit: {\n headers: {\n 'x-api-key': options.apiKeySecret,\n },\n },\n }\n )\n\n const client = new Client(\n { name: 'open-mercato-client', version: '0.1.0' },\n { capabilities: {} }\n )\n\n await client.connect(transport)\n\n return new McpClient(client, transport, options.apiKeySecret)\n }\n\n /**\n * List available tools from the server.\n */\n async listTools(): Promise<ToolInfo[]> {\n const response = await this.client.listTools()\n\n return response.tools.map((tool) => ({\n name: tool.name,\n description: tool.description ?? '',\n inputSchema: (tool.inputSchema ?? {}) as Record<string, unknown>,\n }))\n }\n\n /**\n * Call a tool on the server.\n */\n async callTool(name: string, args: unknown): Promise<ToolResult> {\n try {\n const response = await this.client.callTool({\n name,\n arguments: args as Record<string, unknown>,\n })\n\n // Parse content from response\n const content = response.content\n if (!Array.isArray(content) || content.length === 0) {\n return { success: true, result: null }\n }\n\n const firstContent = content[0]\n if (firstContent.type === 'text') {\n try {\n const parsed = JSON.parse(firstContent.text)\n\n // Check if it's an error response\n if (response.isError || parsed.error) {\n return {\n success: false,\n error: parsed.error ?? 'Unknown error',\n }\n }\n\n return { success: true, result: parsed }\n } catch {\n // Not JSON, return as-is\n return { success: true, result: firstContent.text }\n }\n }\n\n return { success: true, result: content }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n return { success: false, error: message }\n }\n }\n\n /**\n * Close the client and release resources.\n */\n async close(): Promise<void> {\n try {\n await this.client.close()\n } catch {\n // Ignore close errors\n }\n\n try {\n await this.transport.close()\n } catch {\n // Ignore close errors\n }\n\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { Client } from '@modelcontextprotocol/sdk/client/index.js'\nimport { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js'\nimport { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'\nimport type { McpClientInterface, ToolInfo, ToolResult } from './types'\n\n/**\n * Options for stdio transport.\n */\nexport type StdioClientOptions = {\n transport: 'stdio'\n /**\n * API key secret. Delivered to the spawned server via the\n * `OPEN_MERCATO_API_KEY` environment variable, never as a command-line\n * argument (argv is world-readable via `ps`/`/proc/<pid>/cmdline`).\n */\n apiKeySecret: string\n /** Command to run (default: 'yarn') */\n command?: string\n /** Arguments for the command (default: mercato ai_assistant mcp:serve, no secret on argv) */\n args?: string[]\n /** Working directory (default: process.cwd()) */\n cwd?: string\n}\n\n/**\n * Options for HTTP transport.\n */\nexport type HttpClientOptions = {\n transport: 'http'\n /** API key secret (sent via x-api-key header) */\n apiKeySecret: string\n /** MCP server URL (e.g., 'http://localhost:3001/mcp') */\n url: string\n}\n\n/**\n * Combined options for McpClient.\n */\nexport type McpClientOptions = StdioClientOptions | HttpClientOptions\n\n/**\n * MCP protocol client for connecting to MCP servers.\n *\n * Supports two transport modes:\n * - stdio: Spawns server as subprocess\n * - http: Connects to HTTP server\n */\nexport class McpClient implements McpClientInterface {\n private client: Client\n private transport: StdioClientTransport | StreamableHTTPClientTransport\n private apiKeySecret: string\n\n private constructor(\n client: Client,\n transport: StdioClientTransport | StreamableHTTPClientTransport,\n apiKeySecret: string\n ) {\n this.client = client\n this.transport = transport\n this.apiKeySecret = apiKeySecret\n }\n\n /**\n * Connect to an MCP server via the specified transport.\n */\n static async connect(options: McpClientOptions): Promise<McpClient> {\n if (options.transport === 'stdio') {\n return McpClient.connectStdio(options)\n } else {\n return McpClient.connectHttp(options)\n }\n }\n\n /**\n * Connect via stdio transport (spawn subprocess).\n */\n private static async connectStdio(options: StdioClientOptions): Promise<McpClient> {\n const command = options.command ?? 'yarn'\n // The API key is passed via OPEN_MERCATO_API_KEY in the child env (below),\n // never on argv \u2014 command-line arguments are readable by any local user.\n const args = options.args ?? [\n 'mercato',\n 'ai_assistant',\n 'mcp:serve',\n ]\n const cwd = options.cwd ?? process.cwd()\n\n const transport = new StdioClientTransport({\n command,\n args,\n cwd,\n env: { ...process.env, OPEN_MERCATO_API_KEY: options.apiKeySecret } as Record<string, string>,\n stderr: 'pipe',\n })\n transport.stderr?.on('data', (data) => {\n const message = data.toString().trim()\n if (message) {\n console.error(`[MCP Client] ${message}`)\n }\n })\n\n const client = new Client(\n { name: 'open-mercato-client', version: '0.1.0' },\n { capabilities: {} }\n )\n\n await client.connect(transport)\n\n return new McpClient(client, transport, options.apiKeySecret)\n }\n\n /**\n * Connect via HTTP transport.\n */\n private static async connectHttp(options: HttpClientOptions): Promise<McpClient> {\n const transport = new StreamableHTTPClientTransport(\n new URL(options.url),\n {\n requestInit: {\n headers: {\n 'x-api-key': options.apiKeySecret,\n },\n },\n }\n )\n\n const client = new Client(\n { name: 'open-mercato-client', version: '0.1.0' },\n { capabilities: {} }\n )\n\n await client.connect(transport)\n\n return new McpClient(client, transport, options.apiKeySecret)\n }\n\n /**\n * List available tools from the server.\n */\n async listTools(): Promise<ToolInfo[]> {\n const response = await this.client.listTools()\n\n return response.tools.map((tool) => ({\n name: tool.name,\n description: tool.description ?? '',\n inputSchema: (tool.inputSchema ?? {}) as Record<string, unknown>,\n }))\n }\n\n /**\n * Call a tool on the server.\n */\n async callTool(name: string, args: unknown): Promise<ToolResult> {\n try {\n const response = await this.client.callTool({\n name,\n arguments: args as Record<string, unknown>,\n })\n\n // Parse content from response\n const content = response.content\n if (!Array.isArray(content) || content.length === 0) {\n return { success: true, result: null }\n }\n\n const firstContent = content[0]\n if (firstContent.type === 'text') {\n try {\n const parsed = JSON.parse(firstContent.text)\n\n // Check if it's an error response\n if (response.isError || parsed.error) {\n return {\n success: false,\n error: parsed.error ?? 'Unknown error',\n }\n }\n\n return { success: true, result: parsed }\n } catch {\n // Not JSON, return as-is\n return { success: true, result: firstContent.text }\n }\n }\n\n return { success: true, result: content }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n return { success: false, error: message }\n }\n }\n\n /**\n * Close the client and release resources.\n */\n async close(): Promise<void> {\n try {\n await this.client.close()\n } catch {\n // Ignore close errors\n }\n\n try {\n await this.transport.close()\n } catch {\n // Ignore close errors\n }\n\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }