@askexenow/exe-os 0.9.269 → 0.9.270

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 (51) hide show
  1. package/deploy/compose/.env.customer.example +2 -0
  2. package/deploy/compose/.env.default +1 -0
  3. package/deploy/compose/.env.example +2 -0
  4. package/deploy/compose/docker-compose.yml +1 -0
  5. package/deploy/compose/generate-env.ts +5 -0
  6. package/deploy/compose/init-db.sql +236 -56
  7. package/dist/bin/cli.js +1 -1
  8. package/dist/bin/exe-forget.js +1 -1
  9. package/dist/bin/exe-new-employee.js +1 -1
  10. package/dist/bin/exe-search.js +1 -1
  11. package/dist/bin/exe-start.sh +28 -1
  12. package/dist/bin/install.js +1 -1
  13. package/dist/bin/setup.js +1 -1
  14. package/dist/bin/stack-update.js +2 -2
  15. package/dist/bin/vps-health-gate.js +1 -1
  16. package/dist/catchup-brief-7G3HIQT3.js +151 -0
  17. package/dist/catchup-brief-IA2K5RYM.js +151 -0
  18. package/dist/catchup-brief-KABFKY7U.js +151 -0
  19. package/dist/chunk-4GJHWD4H.js +1148 -0
  20. package/dist/chunk-6H7PZOYD.js +58 -0
  21. package/dist/chunk-AQU2CVD4.js +1148 -0
  22. package/dist/chunk-AX6EKVRZ.js +13696 -0
  23. package/dist/chunk-DFI2IZXM.js +1395 -0
  24. package/dist/chunk-EM4EYF3P.js +149 -0
  25. package/dist/chunk-F7RM3Z4R.js +230 -0
  26. package/dist/chunk-LMYSCMSQ.js +1148 -0
  27. package/dist/chunk-RJVFHGFD.js +13696 -0
  28. package/dist/chunk-U2O2UXVQ.js +13696 -0
  29. package/dist/chunk-X56OLWQS.js +58 -0
  30. package/dist/chunk-YYO5RQRT.js +1021 -0
  31. package/dist/chunk-ZFHXFDWX.js +58 -0
  32. package/dist/hooks/error-recall.js +1 -1
  33. package/dist/hooks/manifest.json +4 -4
  34. package/dist/hooks/prompt-submit.js +1 -1
  35. package/dist/hooks/session-start.js +1 -1
  36. package/dist/lib/exe-daemon.js +49 -3
  37. package/dist/lib/hybrid-search.js +1 -1
  38. package/dist/lib/session-wrappers.js +1 -1
  39. package/dist/mcp/register-tools.js +3 -3
  40. package/dist/mcp/server.js +3 -3
  41. package/dist/reranker-7GCUQ6LC.js +19 -0
  42. package/dist/reranker-NLH3VBTN.js +19 -0
  43. package/dist/reranker-RUOD4YHZ.js +19 -0
  44. package/dist/setup-wizard-M7A7MXH4.js +12 -0
  45. package/dist/stack-update-MYPMZQEI.js +52 -0
  46. package/dist/task-enforcement-CJKWU43B.js +364 -0
  47. package/dist/task-enforcement-FYDLTS3R.js +391 -0
  48. package/dist/task-enforcement-YXKZYS5L.js +369 -0
  49. package/package.json +1 -1
  50. package/release-notes.json +33 -14
  51. package/stack.release.json +48 -48
@@ -72,6 +72,8 @@ API_ROUTER_KEY=exe_rk_CHANGEME_API_ROUTER_KEY
72
72
  # ANTHROPIC_API_KEY=CHANGEME_ANTHROPIC_API_KEY
73
73
  GATEWAY_HTTP_HOST_PORT=3100
74
74
  GATEWAY_WS_HOST_PORT=3101
75
+ # CRM bridge: exe-gateway reaches exe-crm through Docker service DNS.
76
+ CRM_GRAPHQL_URL=http://exe-crm:3000/graphql
75
77
 
76
78
  # --- Monitoring hub (PocketBase — local per-customer instance) ---
77
79
  MONITOR_HUB_IMAGE_TAG=update.askexe.com/askexe/exe-monitor-hub:v0.9.4
@@ -69,5 +69,6 @@ EXE_GATEWAY_WHATSAPP_VERIFY_TOKEN=CHANGEME_EXE_GATEWAY_WHATSAPP_VERIFY_TOKEN
69
69
  WHATSAPP_ACCESS_TOKEN=
70
70
  API_ROUTER_URL=https://gateway.askexe.com
71
71
  API_ROUTER_KEY=exe_rk_CHANGEME_API_ROUTER_KEY
72
+ CRM_GRAPHQL_URL=http://exe-crm:3000/graphql
72
73
  GATEWAY_HTTP_HOST_PORT=3100
73
74
  GATEWAY_WS_HOST_PORT=3101
@@ -66,6 +66,8 @@ GATEWAY_HTTP_HOST_PORT=3100
66
66
  GATEWAY_WS_HOST_PORT=3101
67
67
  # GoTrue SSO — enable for unified auth across all services
68
68
  GATEWAY_GOTRUE_URL=http://gotrue:9999
69
+ # CRM bridge: exe-gateway reaches exe-crm through Docker service DNS.
70
+ CRM_GRAPHQL_URL=http://exe-crm:3000/graphql
69
71
  # Error forwarding to exe-monitor-hub (strongly recommended for production)
70
72
  ERROR_REPORTING_ENABLED=true
71
73
  MONITOR_ERROR_URL=http://exe-monitor-hub:8090/api/exe-monitor/errors
@@ -418,6 +418,7 @@ services:
418
418
  API_ROUTER_KEY: ${API_ROUTER_KEY:-}
419
419
  EXED_MCP_URL: http://exe-os:48739/mcp
420
420
  EXED_MCP_TOKEN: ${EXED_MCP_TOKEN:?EXED_MCP_TOKEN is required}
421
+ CRM_GRAPHQL_URL: ${CRM_GRAPHQL_URL:-http://exe-crm:3000/graphql}
421
422
  ERROR_REPORTING_ENABLED: "true"
422
423
  MONITOR_ERROR_URL: http://exe-monitor-hub:8090/api/exe-monitor/errors
423
424
  EXE_DAEMON_TOKEN: ${EXED_MCP_TOKEN:?EXED_MCP_TOKEN is required}
@@ -35,6 +35,7 @@ const LICENSE_KEY_COMMENT = "# injected by deploy_client";
35
35
  const MANUAL_VALUE_COMMENT = "# SET_MANUALLY";
36
36
  const EXAMPLE_LICENSE_KEY = "CHANGEME_EXE_LICENSE_KEY";
37
37
  const DEFAULT_API_ROUTER_URL = "https://gateway.askexe.com";
38
+ const DEFAULT_CRM_GRAPHQL_URL = "http://exe-crm:3000/graphql";
38
39
  const DEFAULT_MONITOR_HUB_URL = "http://exe-monitor-hub:8090";
39
40
  const DEFAULT_MONITOR_AGENT_LISTEN = ":45876";
40
41
  const DEFAULT_EXE_MCP_HOST_BIND = "127.0.0.1";
@@ -115,6 +116,8 @@ export function generateEnv(options: GenerateEnvOptions): string {
115
116
  `GATEWAY_WS_HOST_PORT=${GATEWAY_WS_HOST_PORT}`,
116
117
  "# GoTrue SSO — enable for unified auth across all services",
117
118
  "GATEWAY_GOTRUE_URL=http://gotrue:9999",
119
+ "# CRM bridge: exe-gateway reaches exe-crm through Docker service DNS.",
120
+ `CRM_GRAPHQL_URL=${DEFAULT_CRM_GRAPHQL_URL}`,
118
121
  "# Error forwarding to exe-monitor-hub (strongly recommended for production)",
119
122
  "ERROR_REPORTING_ENABLED=true",
120
123
  "MONITOR_ERROR_URL=http://exe-monitor-hub:8090/api/exe-monitor/errors",
@@ -234,6 +237,8 @@ export function generateExampleEnv(): string {
234
237
  `GATEWAY_WS_HOST_PORT=${GATEWAY_WS_HOST_PORT}`,
235
238
  "# GoTrue SSO — enable for unified auth across all services",
236
239
  "GATEWAY_GOTRUE_URL=http://gotrue:9999",
240
+ "# CRM bridge: exe-gateway reaches exe-crm through Docker service DNS.",
241
+ `CRM_GRAPHQL_URL=${DEFAULT_CRM_GRAPHQL_URL}`,
237
242
  "# Error forwarding to exe-monitor-hub (strongly recommended for production)",
238
243
  "ERROR_REPORTING_ENABLED=true",
239
244
  "MONITOR_ERROR_URL=http://exe-monitor-hub:8090/api/exe-monitor/errors",
@@ -49,6 +49,75 @@ CREATE SCHEMA IF NOT EXISTS auth;
49
49
  CREATE SCHEMA IF NOT EXISTS billing;
50
50
  CREATE SCHEMA IF NOT EXISTS erp;
51
51
 
52
+ -- Helpers for upgrading existing customer volumes. CREATE TABLE IF NOT EXISTS
53
+ -- does not add columns to tables created by older init-db.sql versions, and
54
+ -- CREATE INDEX IF NOT EXISTS still fails if the target column is missing.
55
+ CREATE OR REPLACE FUNCTION pg_temp.exe_add_column_if_missing(
56
+ p_schema_name TEXT,
57
+ p_table_name TEXT,
58
+ p_column_name TEXT,
59
+ p_column_sql TEXT
60
+ ) RETURNS VOID LANGUAGE plpgsql AS $$
61
+ BEGIN
62
+ IF to_regclass(format('%I.%I', p_schema_name, p_table_name)) IS NULL THEN
63
+ RETURN;
64
+ END IF;
65
+
66
+ IF NOT EXISTS (
67
+ SELECT 1
68
+ FROM information_schema.columns
69
+ WHERE table_schema = p_schema_name
70
+ AND table_name = p_table_name
71
+ AND column_name = p_column_name
72
+ ) THEN
73
+ EXECUTE format('ALTER TABLE %I.%I ADD COLUMN %s', p_schema_name, p_table_name, p_column_sql);
74
+ END IF;
75
+ END $$;
76
+
77
+ CREATE OR REPLACE FUNCTION pg_temp.exe_create_index_if_columns_exist(
78
+ p_index_name TEXT,
79
+ p_schema_name TEXT,
80
+ p_table_name TEXT,
81
+ p_column_names TEXT[],
82
+ p_create_sql TEXT
83
+ ) RETURNS VOID LANGUAGE plpgsql AS $$
84
+ DECLARE
85
+ missing_column TEXT;
86
+ BEGIN
87
+ IF to_regclass(format('%I.%I', p_schema_name, p_table_name)) IS NULL THEN
88
+ RETURN;
89
+ END IF;
90
+
91
+ SELECT c INTO missing_column
92
+ FROM unnest(p_column_names) AS c
93
+ WHERE NOT EXISTS (
94
+ SELECT 1
95
+ FROM information_schema.columns
96
+ WHERE table_schema = p_schema_name
97
+ AND table_name = p_table_name
98
+ AND column_name = c
99
+ )
100
+ LIMIT 1;
101
+
102
+ IF missing_column IS NOT NULL THEN
103
+ RAISE NOTICE 'Skipping index %.% because %.% is missing column %',
104
+ p_schema_name, p_index_name, p_schema_name, p_table_name, missing_column;
105
+ RETURN;
106
+ END IF;
107
+
108
+ IF to_regclass(format('%I.%I', p_schema_name, p_index_name)) IS NOT NULL THEN
109
+ RETURN;
110
+ END IF;
111
+
112
+ BEGIN
113
+ EXECUTE p_create_sql;
114
+ EXCEPTION
115
+ WHEN unique_violation THEN
116
+ RAISE NOTICE 'Skipping unique index %.% because existing rows are not unique',
117
+ p_schema_name, p_index_name;
118
+ END;
119
+ END $$;
120
+
52
121
  -- Grant exe full access to all schemas
53
122
  DO $$ DECLARE s text; BEGIN
54
123
  FOR s IN SELECT schema_name FROM information_schema.schemata
@@ -79,9 +148,9 @@ CREATE TABLE IF NOT EXISTS raw.raw_events (
79
148
  projections JSONB DEFAULT '{}'::jsonb
80
149
  );
81
150
 
82
- CREATE INDEX IF NOT EXISTS idx_raw_events_unprocessed ON raw.raw_events (created_at) WHERE processed_at IS NULL;
83
- CREATE INDEX IF NOT EXISTS idx_raw_events_retryable ON raw.raw_events (failed_at) WHERE processed_at IS NULL AND failed_at IS NOT NULL AND retry_count < 5;
84
- CREATE UNIQUE INDEX IF NOT EXISTS uq_raw_events_dedup ON raw.raw_events (source, source_id, event_type);
151
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_raw_events_unprocessed', 'raw', 'raw_events', ARRAY['created_at', 'processed_at'], 'CREATE INDEX IF NOT EXISTS idx_raw_events_unprocessed ON raw.raw_events (created_at) WHERE processed_at IS NULL');
152
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_raw_events_retryable', 'raw', 'raw_events', ARRAY['failed_at', 'processed_at', 'retry_count'], 'CREATE INDEX IF NOT EXISTS idx_raw_events_retryable ON raw.raw_events (failed_at) WHERE processed_at IS NULL AND failed_at IS NOT NULL AND retry_count < 5');
153
+ SELECT pg_temp.exe_create_index_if_columns_exist('uq_raw_events_dedup', 'raw', 'raw_events', ARRAY['source', 'source_id', 'event_type'], 'CREATE UNIQUE INDEX IF NOT EXISTS uq_raw_events_dedup ON raw.raw_events (source, source_id, event_type)');
85
154
 
86
155
  -- ---------------------------------------------------------------------------
87
156
  -- Graph schema — Company Brain memory + GraphRAG projection targets.
@@ -114,10 +183,33 @@ CREATE TABLE IF NOT EXISTS graph.memory_records (
114
183
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
115
184
  updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
116
185
  );
117
- CREATE INDEX IF NOT EXISTS idx_graph_memory_records_agent ON graph.memory_records(agent_id);
118
- CREATE INDEX IF NOT EXISTS idx_graph_memory_records_project_time ON graph.memory_records(project_name, timestamp DESC);
119
- CREATE INDEX IF NOT EXISTS idx_graph_memory_records_status ON graph.memory_records(status);
120
- CREATE INDEX IF NOT EXISTS idx_graph_memory_records_source_type ON graph.memory_records(source_type);
186
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'memory_records', 'id', 'id UUID DEFAULT gen_random_uuid()');
187
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'memory_records', 'agent_id', 'agent_id TEXT NOT NULL DEFAULT ''system''');
188
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'memory_records', 'agent_role', 'agent_role TEXT NOT NULL DEFAULT ''ingest''');
189
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'memory_records', 'session_id', 'session_id TEXT NOT NULL DEFAULT ''projection-worker''');
190
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'memory_records', 'timestamp', 'timestamp TIMESTAMPTZ NOT NULL DEFAULT now()');
191
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'memory_records', 'tool_name', 'tool_name TEXT NOT NULL DEFAULT ''projection_worker''');
192
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'memory_records', 'project_name', 'project_name TEXT NOT NULL DEFAULT ''exe-os''');
193
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'memory_records', 'has_error', 'has_error BOOLEAN NOT NULL DEFAULT false');
194
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'memory_records', 'raw_text', 'raw_text TEXT NOT NULL DEFAULT ''''');
195
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'memory_records', 'vector', 'vector vector(1024)');
196
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'memory_records', 'version', 'version INTEGER NOT NULL DEFAULT 0');
197
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'memory_records', 'task_id', 'task_id TEXT');
198
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'memory_records', 'intent', 'intent TEXT');
199
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'memory_records', 'outcome', 'outcome TEXT');
200
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'memory_records', 'domain', 'domain TEXT');
201
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'memory_records', 'trajectory', 'trajectory TEXT');
202
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'memory_records', 'memory_type', 'memory_type TEXT NOT NULL DEFAULT ''raw''');
203
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'memory_records', 'source_type', 'source_type TEXT NOT NULL DEFAULT ''unknown''');
204
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'memory_records', 'importance', 'importance INTEGER NOT NULL DEFAULT 5');
205
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'memory_records', 'status', 'status TEXT NOT NULL DEFAULT ''active''');
206
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'memory_records', 'metadata', 'metadata JSONB NOT NULL DEFAULT ''{}''::jsonb');
207
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'memory_records', 'created_at', 'created_at TIMESTAMPTZ NOT NULL DEFAULT now()');
208
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'memory_records', 'updated_at', 'updated_at TIMESTAMPTZ NOT NULL DEFAULT now()');
209
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_graph_memory_records_agent', 'graph', 'memory_records', ARRAY['agent_id'], 'CREATE INDEX IF NOT EXISTS idx_graph_memory_records_agent ON graph.memory_records(agent_id)');
210
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_graph_memory_records_project_time', 'graph', 'memory_records', ARRAY['project_name', 'timestamp'], 'CREATE INDEX IF NOT EXISTS idx_graph_memory_records_project_time ON graph.memory_records(project_name, timestamp DESC)');
211
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_graph_memory_records_status', 'graph', 'memory_records', ARRAY['status'], 'CREATE INDEX IF NOT EXISTS idx_graph_memory_records_status ON graph.memory_records(status)');
212
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_graph_memory_records_source_type', 'graph', 'memory_records', ARRAY['source_type'], 'CREATE INDEX IF NOT EXISTS idx_graph_memory_records_source_type ON graph.memory_records(source_type)');
121
213
 
122
214
  CREATE TABLE IF NOT EXISTS graph.entities (
123
215
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
@@ -128,8 +220,14 @@ CREATE TABLE IF NOT EXISTS graph.entities (
128
220
  properties JSONB NOT NULL DEFAULT '{}'::jsonb,
129
221
  UNIQUE(name, type)
130
222
  );
131
- CREATE INDEX IF NOT EXISTS idx_graph_entities_type ON graph.entities(type);
132
- CREATE INDEX IF NOT EXISTS idx_graph_entities_last_seen ON graph.entities(last_seen DESC);
223
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'entities', 'id', 'id UUID DEFAULT gen_random_uuid()');
224
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'entities', 'name', 'name TEXT NOT NULL DEFAULT ''''');
225
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'entities', 'type', 'type TEXT NOT NULL DEFAULT ''unknown''');
226
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'entities', 'first_seen', 'first_seen TIMESTAMPTZ NOT NULL DEFAULT now()');
227
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'entities', 'last_seen', 'last_seen TIMESTAMPTZ NOT NULL DEFAULT now()');
228
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'entities', 'properties', 'properties JSONB NOT NULL DEFAULT ''{}''::jsonb');
229
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_graph_entities_type', 'graph', 'entities', ARRAY['type'], 'CREATE INDEX IF NOT EXISTS idx_graph_entities_type ON graph.entities(type)');
230
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_graph_entities_last_seen', 'graph', 'entities', ARRAY['last_seen'], 'CREATE INDEX IF NOT EXISTS idx_graph_entities_last_seen ON graph.entities(last_seen DESC)');
133
231
 
134
232
  CREATE TABLE IF NOT EXISTS graph.relationships (
135
233
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
@@ -143,16 +241,26 @@ CREATE TABLE IF NOT EXISTS graph.relationships (
143
241
  properties JSONB NOT NULL DEFAULT '{}'::jsonb,
144
242
  UNIQUE(source_entity_id, target_entity_id, type)
145
243
  );
146
- CREATE INDEX IF NOT EXISTS idx_graph_relationships_source ON graph.relationships(source_entity_id);
147
- CREATE INDEX IF NOT EXISTS idx_graph_relationships_target ON graph.relationships(target_entity_id);
148
- CREATE INDEX IF NOT EXISTS idx_graph_relationships_type ON graph.relationships(type);
244
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'relationships', 'source_entity_id', 'source_entity_id UUID');
245
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'relationships', 'target_entity_id', 'target_entity_id UUID');
246
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'relationships', 'type', 'type TEXT NOT NULL DEFAULT ''related_to''');
247
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'relationships', 'weight', 'weight DOUBLE PRECISION NOT NULL DEFAULT 1.0');
248
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'relationships', 'confidence', 'confidence DOUBLE PRECISION NOT NULL DEFAULT 0.8');
249
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'relationships', 'confidence_label', 'confidence_label TEXT');
250
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'relationships', 'timestamp', 'timestamp TIMESTAMPTZ NOT NULL DEFAULT now()');
251
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'relationships', 'properties', 'properties JSONB NOT NULL DEFAULT ''{}''::jsonb');
252
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_graph_relationships_source', 'graph', 'relationships', ARRAY['source_entity_id'], 'CREATE INDEX IF NOT EXISTS idx_graph_relationships_source ON graph.relationships(source_entity_id)');
253
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_graph_relationships_target', 'graph', 'relationships', ARRAY['target_entity_id'], 'CREATE INDEX IF NOT EXISTS idx_graph_relationships_target ON graph.relationships(target_entity_id)');
254
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_graph_relationships_type', 'graph', 'relationships', ARRAY['type'], 'CREATE INDEX IF NOT EXISTS idx_graph_relationships_type ON graph.relationships(type)');
149
255
 
150
256
  CREATE TABLE IF NOT EXISTS graph.entity_memories (
151
257
  entity_id UUID NOT NULL REFERENCES graph.entities(id) ON DELETE CASCADE,
152
258
  memory_id UUID NOT NULL REFERENCES graph.memory_records(id) ON DELETE CASCADE,
153
259
  PRIMARY KEY(entity_id, memory_id)
154
260
  );
155
- CREATE INDEX IF NOT EXISTS idx_graph_entity_memories_memory ON graph.entity_memories(memory_id);
261
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'entity_memories', 'entity_id', 'entity_id UUID');
262
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'entity_memories', 'memory_id', 'memory_id UUID');
263
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_graph_entity_memories_memory', 'graph', 'entity_memories', ARRAY['memory_id'], 'CREATE INDEX IF NOT EXISTS idx_graph_entity_memories_memory ON graph.entity_memories(memory_id)');
156
264
 
157
265
  CREATE TABLE IF NOT EXISTS graph.agent_sessions (
158
266
  id TEXT PRIMARY KEY,
@@ -163,7 +271,13 @@ CREATE TABLE IF NOT EXISTS graph.agent_sessions (
163
271
  event_count INTEGER NOT NULL DEFAULT 0,
164
272
  properties JSONB NOT NULL DEFAULT '{}'::jsonb
165
273
  );
166
- CREATE INDEX IF NOT EXISTS idx_agent_sessions_agent_time ON graph.agent_sessions(agent_id, started_at);
274
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_sessions', 'agent_id', 'agent_id TEXT NOT NULL DEFAULT ''system''');
275
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_sessions', 'project_name', 'project_name TEXT');
276
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_sessions', 'started_at', 'started_at TIMESTAMP(3) NOT NULL DEFAULT now()');
277
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_sessions', 'last_event_at', 'last_event_at TIMESTAMP(3) NOT NULL DEFAULT now()');
278
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_sessions', 'event_count', 'event_count INTEGER NOT NULL DEFAULT 0');
279
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_sessions', 'properties', 'properties JSONB NOT NULL DEFAULT ''{}''::jsonb');
280
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_agent_sessions_agent_time', 'graph', 'agent_sessions', ARRAY['agent_id', 'started_at'], 'CREATE INDEX IF NOT EXISTS idx_agent_sessions_agent_time ON graph.agent_sessions(agent_id, started_at)');
167
281
 
168
282
  CREATE TABLE IF NOT EXISTS graph.agent_goals (
169
283
  id TEXT PRIMARY KEY,
@@ -181,7 +295,20 @@ CREATE TABLE IF NOT EXISTS graph.agent_goals (
181
295
  updated_at TIMESTAMP(3) NOT NULL,
182
296
  source_memory_id TEXT
183
297
  );
184
- CREATE INDEX IF NOT EXISTS idx_agent_goals_project_status ON graph.agent_goals(project_name, status, priority);
298
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_goals', 'statement', 'statement TEXT NOT NULL DEFAULT ''''');
299
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_goals', 'owner_agent_id', 'owner_agent_id TEXT');
300
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_goals', 'project_name', 'project_name TEXT');
301
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_goals', 'status', 'status TEXT NOT NULL DEFAULT ''open''');
302
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_goals', 'priority', 'priority INTEGER NOT NULL DEFAULT 5');
303
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_goals', 'success_criteria', 'success_criteria TEXT');
304
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_goals', 'parent_goal_id', 'parent_goal_id TEXT');
305
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_goals', 'due_at', 'due_at TIMESTAMP(3)');
306
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_goals', 'achieved_at', 'achieved_at TIMESTAMP(3)');
307
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_goals', 'supersedes_id', 'supersedes_id TEXT');
308
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_goals', 'created_at', 'created_at TIMESTAMP(3) NOT NULL DEFAULT now()');
309
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_goals', 'updated_at', 'updated_at TIMESTAMP(3) NOT NULL DEFAULT now()');
310
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_goals', 'source_memory_id', 'source_memory_id TEXT');
311
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_agent_goals_project_status', 'graph', 'agent_goals', ARRAY['project_name', 'status', 'priority'], 'CREATE INDEX IF NOT EXISTS idx_agent_goals_project_status ON graph.agent_goals(project_name, status, priority)');
185
312
 
186
313
  CREATE TABLE IF NOT EXISTS graph.agent_events (
187
314
  id TEXT PRIMARY KEY,
@@ -202,10 +329,26 @@ CREATE TABLE IF NOT EXISTS graph.agent_events (
202
329
  payload JSONB NOT NULL DEFAULT '{}'::jsonb,
203
330
  created_at TIMESTAMP(3) NOT NULL
204
331
  );
205
- CREATE INDEX IF NOT EXISTS idx_agent_events_time ON graph.agent_events(occurred_at, sequence_index);
206
- CREATE INDEX IF NOT EXISTS idx_agent_events_session_seq ON graph.agent_events(session_id, sequence_index);
207
- CREATE INDEX IF NOT EXISTS idx_agent_events_goal_time ON graph.agent_events(goal_id, occurred_at);
208
- CREATE INDEX IF NOT EXISTS idx_agent_events_memory ON graph.agent_events(evidence_memory_id);
332
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_events', 'event_type', 'event_type TEXT NOT NULL DEFAULT ''event''');
333
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_events', 'occurred_at', 'occurred_at TIMESTAMP(3) NOT NULL DEFAULT now()');
334
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_events', 'sequence_index', 'sequence_index INTEGER NOT NULL DEFAULT 0');
335
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_events', 'actor_agent_id', 'actor_agent_id TEXT');
336
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_events', 'agent_role', 'agent_role TEXT');
337
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_events', 'project_name', 'project_name TEXT');
338
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_events', 'session_id', 'session_id TEXT');
339
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_events', 'task_id', 'task_id TEXT');
340
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_events', 'goal_id', 'goal_id TEXT');
341
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_events', 'parent_event_id', 'parent_event_id TEXT');
342
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_events', 'intention', 'intention TEXT');
343
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_events', 'outcome', 'outcome TEXT');
344
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_events', 'evidence_memory_id', 'evidence_memory_id TEXT');
345
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_events', 'impact', 'impact TEXT');
346
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_events', 'payload', 'payload JSONB NOT NULL DEFAULT ''{}''::jsonb');
347
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_events', 'created_at', 'created_at TIMESTAMP(3) NOT NULL DEFAULT now()');
348
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_agent_events_time', 'graph', 'agent_events', ARRAY['occurred_at', 'sequence_index'], 'CREATE INDEX IF NOT EXISTS idx_agent_events_time ON graph.agent_events(occurred_at, sequence_index)');
349
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_agent_events_session_seq', 'graph', 'agent_events', ARRAY['session_id', 'sequence_index'], 'CREATE INDEX IF NOT EXISTS idx_agent_events_session_seq ON graph.agent_events(session_id, sequence_index)');
350
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_agent_events_goal_time', 'graph', 'agent_events', ARRAY['goal_id', 'occurred_at'], 'CREATE INDEX IF NOT EXISTS idx_agent_events_goal_time ON graph.agent_events(goal_id, occurred_at)');
351
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_agent_events_memory', 'graph', 'agent_events', ARRAY['evidence_memory_id'], 'CREATE INDEX IF NOT EXISTS idx_agent_events_memory ON graph.agent_events(evidence_memory_id)');
209
352
 
210
353
  CREATE TABLE IF NOT EXISTS graph.agent_goal_links (
211
354
  id TEXT PRIMARY KEY,
@@ -215,7 +358,12 @@ CREATE TABLE IF NOT EXISTS graph.agent_goal_links (
215
358
  target_type TEXT NOT NULL,
216
359
  created_at TIMESTAMP(3) NOT NULL
217
360
  );
218
- CREATE INDEX IF NOT EXISTS idx_agent_goal_links_goal ON graph.agent_goal_links(goal_id, target_type);
361
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_goal_links', 'goal_id', 'goal_id TEXT NOT NULL DEFAULT ''''');
362
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_goal_links', 'link_type', 'link_type TEXT NOT NULL DEFAULT ''related''');
363
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_goal_links', 'target_id', 'target_id TEXT NOT NULL DEFAULT ''''');
364
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_goal_links', 'target_type', 'target_type TEXT NOT NULL DEFAULT ''unknown''');
365
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_goal_links', 'created_at', 'created_at TIMESTAMP(3) NOT NULL DEFAULT now()');
366
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_agent_goal_links_goal', 'graph', 'agent_goal_links', ARRAY['goal_id', 'target_type'], 'CREATE INDEX IF NOT EXISTS idx_agent_goal_links_goal ON graph.agent_goal_links(goal_id, target_type)');
219
367
 
220
368
  CREATE TABLE IF NOT EXISTS graph.agent_semantic_labels (
221
369
  id TEXT PRIMARY KEY,
@@ -228,8 +376,16 @@ CREATE TABLE IF NOT EXISTS graph.agent_semantic_labels (
228
376
  created_at TIMESTAMP(3) NOT NULL,
229
377
  updated_at TIMESTAMP(3) NOT NULL
230
378
  );
231
- CREATE INDEX IF NOT EXISTS idx_agent_semantic_labels_memory ON graph.agent_semantic_labels(source_memory_id, labeler);
232
- CREATE INDEX IF NOT EXISTS idx_agent_semantic_labels_event ON graph.agent_semantic_labels(event_id);
379
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_semantic_labels', 'source_memory_id', 'source_memory_id TEXT NOT NULL DEFAULT ''''');
380
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_semantic_labels', 'event_id', 'event_id TEXT');
381
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_semantic_labels', 'labeler', 'labeler TEXT NOT NULL DEFAULT ''system''');
382
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_semantic_labels', 'schema_version', 'schema_version INTEGER NOT NULL DEFAULT 1');
383
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_semantic_labels', 'confidence', 'confidence DOUBLE PRECISION NOT NULL DEFAULT 0');
384
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_semantic_labels', 'labels', 'labels JSONB NOT NULL DEFAULT ''[]''::jsonb');
385
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_semantic_labels', 'created_at', 'created_at TIMESTAMP(3) NOT NULL DEFAULT now()');
386
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_semantic_labels', 'updated_at', 'updated_at TIMESTAMP(3) NOT NULL DEFAULT now()');
387
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_agent_semantic_labels_memory', 'graph', 'agent_semantic_labels', ARRAY['source_memory_id', 'labeler'], 'CREATE INDEX IF NOT EXISTS idx_agent_semantic_labels_memory ON graph.agent_semantic_labels(source_memory_id, labeler)');
388
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_agent_semantic_labels_event', 'graph', 'agent_semantic_labels', ARRAY['event_id'], 'CREATE INDEX IF NOT EXISTS idx_agent_semantic_labels_event ON graph.agent_semantic_labels(event_id)');
233
389
 
234
390
  CREATE TABLE IF NOT EXISTS graph.agent_reflection_checkpoints (
235
391
  id TEXT PRIMARY KEY,
@@ -249,8 +405,23 @@ CREATE TABLE IF NOT EXISTS graph.agent_reflection_checkpoints (
249
405
  confidence DOUBLE PRECISION NOT NULL DEFAULT 0,
250
406
  created_at TIMESTAMP(3) NOT NULL
251
407
  );
252
- CREATE INDEX IF NOT EXISTS idx_agent_reflection_project_time ON graph.agent_reflection_checkpoints(project_name, window_end_at);
253
- CREATE INDEX IF NOT EXISTS idx_agent_reflection_session_time ON graph.agent_reflection_checkpoints(session_id, window_end_at);
408
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_reflection_checkpoints', 'project_name', 'project_name TEXT');
409
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_reflection_checkpoints', 'session_id', 'session_id TEXT');
410
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_reflection_checkpoints', 'window_start_at', 'window_start_at TIMESTAMP(3) NOT NULL DEFAULT now()');
411
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_reflection_checkpoints', 'window_end_at', 'window_end_at TIMESTAMP(3) NOT NULL DEFAULT now()');
412
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_reflection_checkpoints', 'event_count', 'event_count INTEGER NOT NULL DEFAULT 0');
413
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_reflection_checkpoints', 'goal_count', 'goal_count INTEGER NOT NULL DEFAULT 0');
414
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_reflection_checkpoints', 'success_count', 'success_count INTEGER NOT NULL DEFAULT 0');
415
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_reflection_checkpoints', 'failure_count', 'failure_count INTEGER NOT NULL DEFAULT 0');
416
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_reflection_checkpoints', 'risk_count', 'risk_count INTEGER NOT NULL DEFAULT 0');
417
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_reflection_checkpoints', 'summary', 'summary TEXT NOT NULL DEFAULT ''''');
418
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_reflection_checkpoints', 'learnings', 'learnings JSONB NOT NULL DEFAULT ''[]''::jsonb');
419
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_reflection_checkpoints', 'next_actions', 'next_actions JSONB NOT NULL DEFAULT ''[]''::jsonb');
420
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_reflection_checkpoints', 'evidence_event_ids', 'evidence_event_ids JSONB NOT NULL DEFAULT ''[]''::jsonb');
421
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_reflection_checkpoints', 'confidence', 'confidence DOUBLE PRECISION NOT NULL DEFAULT 0');
422
+ SELECT pg_temp.exe_add_column_if_missing('graph', 'agent_reflection_checkpoints', 'created_at', 'created_at TIMESTAMP(3) NOT NULL DEFAULT now()');
423
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_agent_reflection_project_time', 'graph', 'agent_reflection_checkpoints', ARRAY['project_name', 'window_end_at'], 'CREATE INDEX IF NOT EXISTS idx_agent_reflection_project_time ON graph.agent_reflection_checkpoints(project_name, window_end_at)');
424
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_agent_reflection_session_time', 'graph', 'agent_reflection_checkpoints', ARRAY['session_id', 'window_end_at'], 'CREATE INDEX IF NOT EXISTS idx_agent_reflection_session_time ON graph.agent_reflection_checkpoints(session_id, window_end_at)');
254
425
 
255
426
  -- Minimal wiki projection tables used by projection-worker.ts before the
256
427
  -- full exe-wiki service has accepted API-ingested documents.
@@ -262,6 +433,7 @@ CREATE TABLE IF NOT EXISTS wiki.workspaces (
262
433
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
263
434
  updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
264
435
  );
436
+ SELECT pg_temp.exe_add_column_if_missing('wiki', 'workspaces', 'id', 'id INTEGER GENERATED BY DEFAULT AS IDENTITY');
265
437
 
266
438
  CREATE TABLE IF NOT EXISTS wiki.workspace_documents (
267
439
  id BIGSERIAL PRIMARY KEY,
@@ -274,8 +446,10 @@ CREATE TABLE IF NOT EXISTS wiki.workspace_documents (
274
446
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
275
447
  updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
276
448
  );
277
- CREATE INDEX IF NOT EXISTS idx_wiki_workspace_documents_workspace ON wiki.workspace_documents(workspace_id);
278
- CREATE INDEX IF NOT EXISTS idx_wiki_workspace_documents_docpath ON wiki.workspace_documents(docpath);
449
+ SELECT pg_temp.exe_add_column_if_missing('wiki', 'workspace_documents', 'workspace_id', 'workspace_id INTEGER');
450
+ SELECT pg_temp.exe_add_column_if_missing('wiki', 'workspace_documents', 'docpath', 'docpath TEXT NOT NULL DEFAULT ''''');
451
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_wiki_workspace_documents_workspace', 'wiki', 'workspace_documents', ARRAY['workspace_id'], 'CREATE INDEX IF NOT EXISTS idx_wiki_workspace_documents_workspace ON wiki.workspace_documents(workspace_id)');
452
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_wiki_workspace_documents_docpath', 'wiki', 'workspace_documents', ARRAY['docpath'], 'CREATE INDEX IF NOT EXISTS idx_wiki_workspace_documents_docpath ON wiki.workspace_documents(docpath)');
279
453
 
280
454
  -- Filtered schema — curated, deduplicated, entity-resolved data.
281
455
  -- Projected from raw.raw_events by daemon workers.
@@ -295,9 +469,10 @@ CREATE TABLE IF NOT EXISTS filtered.contacts (
295
469
  last_seen TIMESTAMPTZ NOT NULL DEFAULT now(),
296
470
  UNIQUE(platform, platform_id)
297
471
  );
472
+ SELECT pg_temp.exe_add_column_if_missing('filtered', 'contacts', 'id', 'id UUID DEFAULT gen_random_uuid()');
298
473
 
299
- CREATE INDEX IF NOT EXISTS idx_filtered_contacts_phone ON filtered.contacts (phone);
300
- CREATE INDEX IF NOT EXISTS idx_filtered_contacts_platform ON filtered.contacts (platform);
474
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_filtered_contacts_phone', 'filtered', 'contacts', ARRAY['phone'], 'CREATE INDEX IF NOT EXISTS idx_filtered_contacts_phone ON filtered.contacts (phone)');
475
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_filtered_contacts_platform', 'filtered', 'contacts', ARRAY['platform'], 'CREATE INDEX IF NOT EXISTS idx_filtered_contacts_platform ON filtered.contacts (platform)');
301
476
 
302
477
  -- Normalized chat threads across platforms
303
478
  -- Column names match projection-worker.ts ensureFilteredSchema (source of truth)
@@ -315,9 +490,9 @@ CREATE TABLE IF NOT EXISTS filtered.conversations (
315
490
  UNIQUE(platform, source_ref)
316
491
  );
317
492
 
318
- CREATE INDEX IF NOT EXISTS idx_filtered_conversations_contact ON filtered.conversations (contact_id, sent_at DESC);
319
- CREATE INDEX IF NOT EXISTS idx_filtered_conversations_ts ON filtered.conversations (sent_at DESC);
320
- CREATE INDEX IF NOT EXISTS idx_filtered_conversations_thread_sent ON filtered.conversations (platform, thread_id, sent_at);
493
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_filtered_conversations_contact', 'filtered', 'conversations', ARRAY['contact_id', 'sent_at'], 'CREATE INDEX IF NOT EXISTS idx_filtered_conversations_contact ON filtered.conversations (contact_id, sent_at DESC)');
494
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_filtered_conversations_ts', 'filtered', 'conversations', ARRAY['sent_at'], 'CREATE INDEX IF NOT EXISTS idx_filtered_conversations_ts ON filtered.conversations (sent_at DESC)');
495
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_filtered_conversations_thread_sent', 'filtered', 'conversations', ARRAY['platform', 'thread_id', 'sent_at'], 'CREATE INDEX IF NOT EXISTS idx_filtered_conversations_thread_sent ON filtered.conversations (platform, thread_id, sent_at)');
321
496
 
322
497
  -- Knowledge documents for wiki ingestion
323
498
  -- Column names match projection-worker.ts ensureFilteredSchema (source of truth)
@@ -333,7 +508,7 @@ CREATE TABLE IF NOT EXISTS filtered.documents (
333
508
  UNIQUE(source, source_id)
334
509
  );
335
510
 
336
- CREATE INDEX IF NOT EXISTS idx_filtered_documents_type ON filtered.documents (doc_type);
511
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_filtered_documents_type', 'filtered', 'documents', ARRAY['doc_type'], 'CREATE INDEX IF NOT EXISTS idx_filtered_documents_type ON filtered.documents (doc_type)');
337
512
 
338
513
  -- Business events (meetings, orders, milestones)
339
514
  CREATE TABLE IF NOT EXISTS filtered.events (
@@ -348,8 +523,8 @@ CREATE TABLE IF NOT EXISTS filtered.events (
348
523
  created_at TIMESTAMPTZ DEFAULT now()
349
524
  );
350
525
 
351
- CREATE INDEX IF NOT EXISTS idx_filtered_events_type ON filtered.events (event_type, occurred_at DESC);
352
- CREATE INDEX IF NOT EXISTS idx_filtered_events_contact ON filtered.events (contact_id);
526
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_filtered_events_type', 'filtered', 'events', ARRAY['event_type', 'occurred_at'], 'CREATE INDEX IF NOT EXISTS idx_filtered_events_type ON filtered.events (event_type, occurred_at DESC)');
527
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_filtered_events_contact', 'filtered', 'events', ARRAY['contact_id'], 'CREATE INDEX IF NOT EXISTS idx_filtered_events_contact ON filtered.events (contact_id)');
353
528
 
354
529
  -- ---------------------------------------------------------------------------
355
530
  -- Gateway schema — WhatsApp/messaging accounts, contacts, threads, messages.
@@ -364,6 +539,7 @@ CREATE TABLE IF NOT EXISTS gateway.accounts (
364
539
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
365
540
  UNIQUE(platform, account_name)
366
541
  );
542
+ SELECT pg_temp.exe_add_column_if_missing('gateway', 'accounts', 'id', 'id INTEGER GENERATED BY DEFAULT AS IDENTITY');
367
543
 
368
544
  CREATE TABLE IF NOT EXISTS gateway.contacts (
369
545
  id SERIAL PRIMARY KEY,
@@ -386,10 +562,11 @@ CREATE TABLE IF NOT EXISTS gateway.contacts (
386
562
  updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
387
563
  UNIQUE(platform, platform_jid)
388
564
  );
389
- CREATE INDEX IF NOT EXISTS idx_gw_contacts_phone ON gateway.contacts(phone);
390
- CREATE INDEX IF NOT EXISTS idx_gw_contacts_phone_jid ON gateway.contacts(phone_jid);
391
- CREATE INDEX IF NOT EXISTS idx_gw_contacts_lid_jid ON gateway.contacts(lid_jid);
392
- CREATE INDEX IF NOT EXISTS idx_gw_contacts_crm_person ON gateway.contacts(crm_person_id);
565
+ SELECT pg_temp.exe_add_column_if_missing('gateway', 'contacts', 'id', 'id INTEGER GENERATED BY DEFAULT AS IDENTITY');
566
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_gw_contacts_phone', 'gateway', 'contacts', ARRAY['phone'], 'CREATE INDEX IF NOT EXISTS idx_gw_contacts_phone ON gateway.contacts(phone)');
567
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_gw_contacts_phone_jid', 'gateway', 'contacts', ARRAY['phone_jid'], 'CREATE INDEX IF NOT EXISTS idx_gw_contacts_phone_jid ON gateway.contacts(phone_jid)');
568
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_gw_contacts_lid_jid', 'gateway', 'contacts', ARRAY['lid_jid'], 'CREATE INDEX IF NOT EXISTS idx_gw_contacts_lid_jid ON gateway.contacts(lid_jid)');
569
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_gw_contacts_crm_person', 'gateway', 'contacts', ARRAY['crm_person_id'], 'CREATE INDEX IF NOT EXISTS idx_gw_contacts_crm_person ON gateway.contacts(crm_person_id)');
393
570
 
394
571
  CREATE TABLE IF NOT EXISTS gateway.contact_identities (
395
572
  id SERIAL PRIMARY KEY,
@@ -403,8 +580,8 @@ CREATE TABLE IF NOT EXISTS gateway.contact_identities (
403
580
  last_seen TIMESTAMPTZ NOT NULL DEFAULT now(),
404
581
  UNIQUE(platform, identity_type, identity_value)
405
582
  );
406
- CREATE INDEX IF NOT EXISTS idx_gw_ci_contact ON gateway.contact_identities(contact_id);
407
- CREATE INDEX IF NOT EXISTS idx_gw_ci_value ON gateway.contact_identities(identity_value);
583
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_gw_ci_contact', 'gateway', 'contact_identities', ARRAY['contact_id'], 'CREATE INDEX IF NOT EXISTS idx_gw_ci_contact ON gateway.contact_identities(contact_id)');
584
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_gw_ci_value', 'gateway', 'contact_identities', ARRAY['identity_value'], 'CREATE INDEX IF NOT EXISTS idx_gw_ci_value ON gateway.contact_identities(identity_value)');
408
585
 
409
586
  CREATE TABLE IF NOT EXISTS gateway.threads (
410
587
  id SERIAL PRIMARY KEY,
@@ -440,8 +617,8 @@ CREATE TABLE IF NOT EXISTS gateway.messages (
440
617
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
441
618
  UNIQUE(account_id, message_id)
442
619
  );
443
- CREATE INDEX IF NOT EXISTS idx_gw_msg_thread_ts ON gateway.messages(thread_id, timestamp);
444
- CREATE INDEX IF NOT EXISTS idx_gw_msg_account ON gateway.messages(account_id, message_id);
620
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_gw_msg_thread_ts', 'gateway', 'messages', ARRAY['thread_id', 'timestamp'], 'CREATE INDEX IF NOT EXISTS idx_gw_msg_thread_ts ON gateway.messages(thread_id, timestamp)');
621
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_gw_msg_account', 'gateway', 'messages', ARRAY['account_id', 'message_id'], 'CREATE INDEX IF NOT EXISTS idx_gw_msg_account ON gateway.messages(account_id, message_id)');
445
622
 
446
623
  CREATE TABLE IF NOT EXISTS gateway.groups (
447
624
  id SERIAL PRIMARY KEY,
@@ -456,6 +633,7 @@ CREATE TABLE IF NOT EXISTS gateway.groups (
456
633
  updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
457
634
  UNIQUE(platform, group_jid)
458
635
  );
636
+ SELECT pg_temp.exe_add_column_if_missing('gateway', 'groups', 'id', 'id INTEGER GENERATED BY DEFAULT AS IDENTITY');
459
637
 
460
638
  CREATE TABLE IF NOT EXISTS gateway.group_members (
461
639
  id SERIAL PRIMARY KEY,
@@ -469,8 +647,8 @@ CREATE TABLE IF NOT EXISTS gateway.group_members (
469
647
  updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
470
648
  UNIQUE(group_id, member_jid)
471
649
  );
472
- CREATE INDEX IF NOT EXISTS idx_gw_gm_member ON gateway.group_members(member_jid);
473
- CREATE INDEX IF NOT EXISTS idx_gw_gm_phone ON gateway.group_members(phone_jid);
650
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_gw_gm_member', 'gateway', 'group_members', ARRAY['member_jid'], 'CREATE INDEX IF NOT EXISTS idx_gw_gm_member ON gateway.group_members(member_jid)');
651
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_gw_gm_phone', 'gateway', 'group_members', ARRAY['phone_jid'], 'CREATE INDEX IF NOT EXISTS idx_gw_gm_phone ON gateway.group_members(phone_jid)');
474
652
 
475
653
  CREATE TABLE IF NOT EXISTS gateway.provider_keys (
476
654
  id SERIAL PRIMARY KEY,
@@ -488,6 +666,7 @@ CREATE TABLE IF NOT EXISTS gateway.customers (
488
666
  last_seen_at TIMESTAMPTZ NOT NULL DEFAULT now(),
489
667
  interaction_count INT NOT NULL DEFAULT 0
490
668
  );
669
+ SELECT pg_temp.exe_add_column_if_missing('gateway', 'customers', 'id', 'id UUID DEFAULT gen_random_uuid()');
491
670
 
492
671
  CREATE TABLE IF NOT EXISTS gateway.customer_identities (
493
672
  id SERIAL PRIMARY KEY,
@@ -510,8 +689,8 @@ CREATE TABLE IF NOT EXISTS gateway.sessions (
510
689
  total_output_tokens INT NOT NULL DEFAULT 0,
511
690
  status TEXT NOT NULL DEFAULT 'active'
512
691
  );
513
- CREATE INDEX IF NOT EXISTS idx_gw_sess_cust ON gateway.sessions(customer_id, bot_id);
514
- CREATE INDEX IF NOT EXISTS idx_gw_sess_status ON gateway.sessions(status);
692
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_gw_sess_cust', 'gateway', 'sessions', ARRAY['customer_id', 'bot_id'], 'CREATE INDEX IF NOT EXISTS idx_gw_sess_cust ON gateway.sessions(customer_id, bot_id)');
693
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_gw_sess_status', 'gateway', 'sessions', ARRAY['status'], 'CREATE INDEX IF NOT EXISTS idx_gw_sess_status ON gateway.sessions(status)');
515
694
 
516
695
  -- ---------------------------------------------------------------------------
517
696
  -- Billing schema — licenses, stack releases, entitlements, deploy audits.
@@ -533,10 +712,11 @@ CREATE TABLE IF NOT EXISTS billing.licenses (
533
712
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
534
713
  created_by TEXT NOT NULL DEFAULT 'system'
535
714
  );
715
+ SELECT pg_temp.exe_add_column_if_missing('billing', 'licenses', 'key', 'key TEXT');
536
716
 
537
- CREATE INDEX IF NOT EXISTS idx_billing_licenses_key ON billing.licenses (key);
538
- CREATE INDEX IF NOT EXISTS idx_billing_licenses_status ON billing.licenses (status);
539
- CREATE INDEX IF NOT EXISTS idx_billing_licenses_email ON billing.licenses (email);
717
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_billing_licenses_key', 'billing', 'licenses', ARRAY['key'], 'CREATE INDEX IF NOT EXISTS idx_billing_licenses_key ON billing.licenses (key)');
718
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_billing_licenses_status', 'billing', 'licenses', ARRAY['status'], 'CREATE INDEX IF NOT EXISTS idx_billing_licenses_status ON billing.licenses (status)');
719
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_billing_licenses_email', 'billing', 'licenses', ARRAY['email'], 'CREATE INDEX IF NOT EXISTS idx_billing_licenses_email ON billing.licenses (email)');
540
720
 
541
721
  CREATE TABLE IF NOT EXISTS billing.stack_releases (
542
722
  id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
@@ -550,8 +730,8 @@ CREATE TABLE IF NOT EXISTS billing.stack_releases (
550
730
  created_by TEXT NOT NULL DEFAULT 'system'
551
731
  );
552
732
 
553
- CREATE INDEX IF NOT EXISTS idx_billing_stack_releases_status ON billing.stack_releases (status);
554
- CREATE INDEX IF NOT EXISTS idx_billing_stack_releases_version ON billing.stack_releases (version);
733
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_billing_stack_releases_status', 'billing', 'stack_releases', ARRAY['status'], 'CREATE INDEX IF NOT EXISTS idx_billing_stack_releases_status ON billing.stack_releases (status)');
734
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_billing_stack_releases_version', 'billing', 'stack_releases', ARRAY['version'], 'CREATE INDEX IF NOT EXISTS idx_billing_stack_releases_version ON billing.stack_releases (version)');
555
735
 
556
736
  CREATE TABLE IF NOT EXISTS billing.stack_entitlements (
557
737
  id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
@@ -567,8 +747,8 @@ CREATE TABLE IF NOT EXISTS billing.stack_entitlements (
567
747
  created_at TIMESTAMPTZ NOT NULL DEFAULT now()
568
748
  );
569
749
 
570
- CREATE INDEX IF NOT EXISTS idx_billing_entitlements_token ON billing.stack_entitlements (token_hash);
571
- CREATE INDEX IF NOT EXISTS idx_billing_entitlements_status ON billing.stack_entitlements (status);
750
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_billing_entitlements_token', 'billing', 'stack_entitlements', ARRAY['token_hash'], 'CREATE INDEX IF NOT EXISTS idx_billing_entitlements_token ON billing.stack_entitlements (token_hash)');
751
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_billing_entitlements_status', 'billing', 'stack_entitlements', ARRAY['status'], 'CREATE INDEX IF NOT EXISTS idx_billing_entitlements_status ON billing.stack_entitlements (status)');
572
752
 
573
753
  CREATE TABLE IF NOT EXISTS billing.stack_deploy_audits (
574
754
  id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
@@ -584,6 +764,6 @@ CREATE TABLE IF NOT EXISTS billing.stack_deploy_audits (
584
764
  created_at TIMESTAMPTZ NOT NULL DEFAULT now()
585
765
  );
586
766
 
587
- CREATE INDEX IF NOT EXISTS idx_billing_deploy_audits_license ON billing.stack_deploy_audits (license_key);
588
- CREATE INDEX IF NOT EXISTS idx_billing_deploy_audits_status ON billing.stack_deploy_audits (status);
589
- CREATE INDEX IF NOT EXISTS idx_billing_deploy_audits_started ON billing.stack_deploy_audits (started_at DESC NULLS LAST);
767
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_billing_deploy_audits_license', 'billing', 'stack_deploy_audits', ARRAY['license_key'], 'CREATE INDEX IF NOT EXISTS idx_billing_deploy_audits_license ON billing.stack_deploy_audits (license_key)');
768
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_billing_deploy_audits_status', 'billing', 'stack_deploy_audits', ARRAY['status'], 'CREATE INDEX IF NOT EXISTS idx_billing_deploy_audits_status ON billing.stack_deploy_audits (status)');
769
+ SELECT pg_temp.exe_create_index_if_columns_exist('idx_billing_deploy_audits_started', 'billing', 'stack_deploy_audits', ARRAY['started_at'], 'CREATE INDEX IF NOT EXISTS idx_billing_deploy_audits_started ON billing.stack_deploy_audits (started_at DESC NULLS LAST)');
package/dist/bin/cli.js CHANGED
@@ -344,7 +344,7 @@ ID: ${result.id}`);
344
344
  process.exit(1);
345
345
  }
346
346
  } else if (args[0] === "setup" || args[0] === "-setup" || args[0] === "--setup") {
347
- const { runSetupWizard } = await import("../setup-wizard-IZSKLVWW.js");
347
+ const { runSetupWizard } = await import("../setup-wizard-M7A7MXH4.js");
348
348
  await runSetupWizard({ skipModel: args.includes("--skip-model") });
349
349
  } else if (args[0] === "update") {
350
350
  const { runUpdate } = await import("./update.js");
@@ -4,7 +4,7 @@ import {
4
4
  } from "../chunk-M7GR2WO4.js";
5
5
  import {
6
6
  lightweightSearch
7
- } from "../chunk-HYI4PN4J.js";
7
+ } from "../chunk-LMYSCMSQ.js";
8
8
  import "../chunk-5MOYMGS5.js";
9
9
  import "../chunk-CHCA3ZM2.js";
10
10
  import "../chunk-RSIDQBIG.js";
@@ -13,7 +13,7 @@ import {
13
13
  } from "../chunk-7SLLNRR3.js";
14
14
  import {
15
15
  generateSessionWrappers
16
- } from "../chunk-GBCZXOWU.js";
16
+ } from "../chunk-EM4EYF3P.js";
17
17
  import {
18
18
  hireEmployee,
19
19
  registerBinSymlinks,
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  hybridSearch,
4
4
  lightweightSearch
5
- } from "../chunk-HYI4PN4J.js";
5
+ } from "../chunk-LMYSCMSQ.js";
6
6
  import {
7
7
  initStore
8
8
  } from "../chunk-5MOYMGS5.js";