@askexenow/exe-os 0.8.57 → 0.8.59

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.
package/dist/bin/cli.js CHANGED
@@ -13238,6 +13238,21 @@ var init_session_kill_telemetry = __esm({
13238
13238
  });
13239
13239
 
13240
13240
  // src/lib/tasks-crud.ts
13241
+ var tasks_crud_exports = {};
13242
+ __export(tasks_crud_exports, {
13243
+ TASK_ALREADY_CLAIMED_PREFIX: () => TASK_ALREADY_CLAIMED_PREFIX,
13244
+ checkStaleCompletion: () => checkStaleCompletion,
13245
+ createTaskCore: () => createTaskCore,
13246
+ deleteTaskCore: () => deleteTaskCore,
13247
+ ensureArchitectureDoc: () => ensureArchitectureDoc,
13248
+ ensureGitignoreExe: () => ensureGitignoreExe,
13249
+ extractParentFromContext: () => extractParentFromContext,
13250
+ listTasks: () => listTasks,
13251
+ resolveTask: () => resolveTask,
13252
+ slugify: () => slugify,
13253
+ updateTaskStatus: () => updateTaskStatus,
13254
+ writeCheckpoint: () => writeCheckpoint
13255
+ });
13241
13256
  import crypto6 from "crypto";
13242
13257
  import path19 from "path";
13243
13258
  import { execSync as execSync8 } from "child_process";
@@ -13713,13 +13728,20 @@ async function cleanupOrphanedReviews() {
13713
13728
  const client = getClient();
13714
13729
  const now = (/* @__PURE__ */ new Date()).toISOString();
13715
13730
  const r1 = await client.execute({
13716
- sql: `UPDATE tasks SET status = 'done', updated_at = ?
13717
- WHERE status = 'needs_review'
13731
+ sql: `UPDATE tasks SET status = 'cancelled', updated_at = ?
13732
+ WHERE status IN ('open', 'needs_review', 'in_progress')
13718
13733
  AND assigned_by = 'system'
13719
13734
  AND title LIKE 'Review:%'
13720
13735
  AND parent_task_id IN (SELECT id FROM tasks WHERE status IN ('done', 'cancelled'))`,
13721
13736
  args: [now]
13722
13737
  });
13738
+ const r1b = await client.execute({
13739
+ sql: `UPDATE tasks SET status = 'cancelled', updated_at = ?
13740
+ WHERE status IN ('open', 'needs_review')
13741
+ AND title LIKE 'Review:%completed%'
13742
+ AND (parent_task_id IS NULL OR parent_task_id NOT IN (SELECT id FROM tasks WHERE status IN ('open', 'in_progress', 'needs_review', 'blocked')))`,
13743
+ args: [now]
13744
+ });
13723
13745
  const staleThreshold = new Date(Date.now() - 60 * 60 * 1e3).toISOString();
13724
13746
  const r2 = await client.execute({
13725
13747
  sql: `UPDATE tasks SET status = 'done', updated_at = ?
@@ -13728,10 +13750,10 @@ async function cleanupOrphanedReviews() {
13728
13750
  AND updated_at < ?`,
13729
13751
  args: [now, staleThreshold]
13730
13752
  });
13731
- const total = r1.rowsAffected + r2.rowsAffected;
13753
+ const total = r1.rowsAffected + (r1b?.rowsAffected ?? 0) + r2.rowsAffected;
13732
13754
  if (total > 0) {
13733
13755
  process.stderr.write(
13734
- `[cleanup] Closed ${total} orphaned review(s): ${r1.rowsAffected} cascade + ${r2.rowsAffected} stale
13756
+ `[cleanup] Closed ${total} orphaned review(s): ${r1.rowsAffected} cascade + ${r1b?.rowsAffected ?? 0} orphan + ${r2.rowsAffected} stale
13735
13757
  `
13736
13758
  );
13737
13759
  }
@@ -13847,7 +13869,6 @@ var init_tasks_review = __esm({
13847
13869
  init_config();
13848
13870
  init_employees();
13849
13871
  init_notifications();
13850
- init_tasks_crud();
13851
13872
  init_tmux_routing();
13852
13873
  init_session_key();
13853
13874
  init_state_bus();
@@ -19508,6 +19529,7 @@ var init_orchestrator = __esm({
19508
19529
  init_task_router();
19509
19530
  init_tmux_routing();
19510
19531
  init_task_scope();
19532
+ init_tasks_crud();
19511
19533
  STALE_THRESHOLD_MS = 2 * 60 * 60 * 1e3;
19512
19534
  MultiAgentOrchestrator = class {
19513
19535
  config;
@@ -19544,6 +19566,26 @@ ${task.context}`,
19544
19566
  targetEmployee = routed.employee;
19545
19567
  routingScore = routed.score;
19546
19568
  }
19569
+ try {
19570
+ await createTaskCore({
19571
+ title: task.title,
19572
+ assignedTo: targetEmployee.name,
19573
+ assignedBy: "exe",
19574
+ projectName: task.projectName,
19575
+ priority: task.priority,
19576
+ context: task.context,
19577
+ baseDir: this.config.projectDir,
19578
+ skipDispatch: true
19579
+ });
19580
+ } catch (err) {
19581
+ return {
19582
+ employee: targetEmployee.name,
19583
+ sessionName: "",
19584
+ status: "failed",
19585
+ routingScore,
19586
+ error: `Task creation failed: ${err instanceof Error ? err.message : String(err)}`
19587
+ };
19588
+ }
19547
19589
  const result = ensureEmployee(
19548
19590
  targetEmployee.name,
19549
19591
  this.config.exeSession,
@@ -19831,7 +19873,17 @@ function useOrchestrator(enabled = true) {
19831
19873
  const spawnSession = useCallback5(
19832
19874
  async (agentId) => {
19833
19875
  try {
19876
+ const { createTaskCore: createTaskCore2 } = await Promise.resolve().then(() => (init_tasks_crud(), tasks_crud_exports));
19834
19877
  const { ensureEmployee: ensureEmployee2 } = await Promise.resolve().then(() => (init_tmux_routing(), tmux_routing_exports));
19878
+ await createTaskCore2({
19879
+ title: `Session launched for ${agentId} (TUI)`,
19880
+ assignedTo: agentId,
19881
+ assignedBy: "exe",
19882
+ projectName: "exe-os",
19883
+ priority: "p2",
19884
+ context: "Session spawned from TUI Sessions view. Agent will pick up any queued tasks via intercom.",
19885
+ skipDispatch: true
19886
+ });
19835
19887
  return ensureEmployee2(agentId, exeSessionRef.current, process.cwd());
19836
19888
  } catch {
19837
19889
  return null;
@@ -0,0 +1,127 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/bin/customer-readiness.ts
4
+ import { readFileSync, existsSync } from "fs";
5
+ import { execSync } from "child_process";
6
+ import path from "path";
7
+ import { fileURLToPath } from "url";
8
+ var __dirname = path.dirname(fileURLToPath(import.meta.url));
9
+ var ROOT = path.resolve(__dirname, "../..");
10
+ var pass = 0;
11
+ var fail = 0;
12
+ function test(name, fn) {
13
+ try {
14
+ const result = fn();
15
+ if (result === true || result === "pass") {
16
+ console.log(` \x1B[32m\u2713\x1B[0m ${name}`);
17
+ pass++;
18
+ } else {
19
+ console.log(` \x1B[31m\u2717\x1B[0m ${name}: ${result}`);
20
+ fail++;
21
+ }
22
+ } catch (err) {
23
+ console.log(` \x1B[31m\u2717\x1B[0m ${name}: ${err instanceof Error ? err.message : String(err)}`);
24
+ fail++;
25
+ }
26
+ }
27
+ function readSrc(relPath) {
28
+ return readFileSync(path.join(ROOT, relPath), "utf8");
29
+ }
30
+ console.log("\n\x1B[1mCustomer Readiness Gate\x1B[0m\n");
31
+ test("Mode 1 detection \u2014 bare exe-os shows guidance, not TUI", () => {
32
+ const cli = readSrc("src/bin/cli.ts");
33
+ if (!cli.includes("Mode 1 detected")) return "cli.ts missing Mode 1 detection";
34
+ if (!cli.includes("hasClaudeCode")) return "cli.ts missing Claude Code check";
35
+ return true;
36
+ });
37
+ test("Review orphans \u2014 no createTaskCore in review generation", () => {
38
+ const review = readSrc("src/lib/tasks-review.ts");
39
+ if (review.includes("createTaskCore(")) return "createTaskCore still called \u2014 will create orphan tasks";
40
+ return true;
41
+ });
42
+ test("Cloud sync \u2014 sqlSafe() protects all cloudPull functions", () => {
43
+ const sync = readSrc("src/lib/cloud-sync.ts");
44
+ if (!sync.includes("function sqlSafe")) return "sqlSafe() helper missing";
45
+ const count = (sync.match(/sqlSafe\(/g) || []).length;
46
+ if (count < 20) return `Only ${count} sqlSafe() usages (expected 20+)`;
47
+ return true;
48
+ });
49
+ test("Session scoping \u2014 task-scope.ts helper exists", () => {
50
+ if (!existsSync(path.join(ROOT, "src/lib/task-scope.ts"))) return "task-scope.ts missing";
51
+ const scope = readSrc("src/lib/task-scope.ts");
52
+ if (!scope.includes("sessionScopeFilter")) return "sessionScopeFilter not exported";
53
+ return true;
54
+ });
55
+ test("Session scoping \u2014 all task query files import scope helper", () => {
56
+ const taskFiles = execSync(
57
+ `grep -rl "FROM tasks" src/ --include="*.ts" --include="*.tsx"`,
58
+ { encoding: "utf8", cwd: ROOT }
59
+ ).trim().split("\n").filter(Boolean);
60
+ const exempt = ["close-task.ts", "tasks-review.ts", "tasks.ts", "cloud-sync.ts", "task-scope.ts", "database.ts"];
61
+ const unscoped = [];
62
+ for (const f of taskFiles) {
63
+ const basename = path.basename(f);
64
+ if (exempt.some((e) => basename === e)) continue;
65
+ const content = readFileSync(path.join(ROOT, f), "utf8");
66
+ if (!content.includes("task-scope") && !content.includes("sessionScopeFilter") && !content.includes("intentionally unscoped")) {
67
+ unscoped.push(f);
68
+ }
69
+ }
70
+ if (unscoped.length > 0) return `${unscoped.length} files missing scope: ${unscoped.slice(0, 3).join(", ")}`;
71
+ return true;
72
+ });
73
+ test("Platform procedures \u2014 shipped as code (not DB only)", () => {
74
+ const procs = readSrc("src/lib/platform-procedures.ts");
75
+ const count = (procs.match(/title:/g) || []).length;
76
+ if (count < 13) return `Only ${count} procedures (expected 13+)`;
77
+ if (!procs.includes("PLATFORM_PROCEDURE_TITLES")) return "Missing dedup set";
78
+ return true;
79
+ });
80
+ test("Platform procedures \u2014 customer procedures stay in DB", () => {
81
+ const global = readSrc("src/lib/global-procedures.ts");
82
+ if (!global.includes("PLATFORM_PROCEDURE_TITLES")) return "Not filtering platform titles from DB";
83
+ if (!global.includes("_platformCache")) return "No platform cache";
84
+ if (!global.includes("_customerCache")) return "No customer cache separation";
85
+ return true;
86
+ });
87
+ test("Backfill exclusive lock \u2014 only 1 backfill at a time", () => {
88
+ const gate = readSrc("src/lib/worker-gate.ts");
89
+ if (!gate.includes("tryAcquireBackfillLock")) return "Missing backfill lock";
90
+ if (!gate.includes("backfill.lock")) return "Missing lockfile path";
91
+ const bf = readSrc("src/bin/backfill-vectors.ts");
92
+ if (!bf.includes("tryAcquireBackfillLock")) return "backfill-vectors.ts not using lock";
93
+ return true;
94
+ });
95
+ test("Daemon restart \u2014 uses SIGKILL + kills orphans", () => {
96
+ const install = readSrc("src/bin/install.ts");
97
+ if (!install.includes("SIGKILL")) return "Still using SIGTERM";
98
+ if (!install.includes("pgrep")) return "No orphan kill via pgrep";
99
+ return true;
100
+ });
101
+ test("License self-heal \u2014 update mirrors cloud.apiKey to license.key", () => {
102
+ const update = readSrc("src/bin/update.ts");
103
+ if (!update.includes("mirrorLicenseKey")) return "update.ts missing license self-heal";
104
+ return true;
105
+ });
106
+ test("Golden path \u2014 orchestration model documented", () => {
107
+ if (!existsSync(path.join(ROOT, ".planning/ARCHITECTURE.md"))) return "ARCHITECTURE.md missing";
108
+ const arch = readFileSync(path.join(ROOT, ".planning/ARCHITECTURE.md"), "utf8");
109
+ if (!arch.includes("Orchestration Model")) return "Golden path section missing";
110
+ if (!arch.includes("create_task") || !arch.includes("Dispatch")) return "Dispatch rule missing";
111
+ return true;
112
+ });
113
+ test("No hardcoded 'yoshi'/'mari' in runtime task routing", () => {
114
+ const router = readSrc("src/lib/task-router.ts");
115
+ if (router.includes('"yoshi"') || router.includes("'yoshi'")) return "Hardcoded 'yoshi' in task-router.ts";
116
+ if (router.includes('"mari"') || router.includes("'mari'")) return "Hardcoded 'mari' in task-router.ts";
117
+ return true;
118
+ });
119
+ console.log(`
120
+ \x1B[1m${pass + fail} tests: ${pass} passed, ${fail} failed\x1B[0m
121
+ `);
122
+ if (fail > 0) {
123
+ console.log("\x1B[31mCustomer readiness gate FAILED \u2014 do not publish.\x1B[0m\n");
124
+ process.exit(1);
125
+ } else {
126
+ console.log("\x1B[32mCustomer readiness gate PASSED \u2014 safe to publish.\x1B[0m\n");
127
+ }
@@ -3501,13 +3501,20 @@ async function cleanupOrphanedReviews() {
3501
3501
  const client = getClient();
3502
3502
  const now = (/* @__PURE__ */ new Date()).toISOString();
3503
3503
  const r1 = await client.execute({
3504
- sql: `UPDATE tasks SET status = 'done', updated_at = ?
3505
- WHERE status = 'needs_review'
3504
+ sql: `UPDATE tasks SET status = 'cancelled', updated_at = ?
3505
+ WHERE status IN ('open', 'needs_review', 'in_progress')
3506
3506
  AND assigned_by = 'system'
3507
3507
  AND title LIKE 'Review:%'
3508
3508
  AND parent_task_id IN (SELECT id FROM tasks WHERE status IN ('done', 'cancelled'))`,
3509
3509
  args: [now]
3510
3510
  });
3511
+ const r1b = await client.execute({
3512
+ sql: `UPDATE tasks SET status = 'cancelled', updated_at = ?
3513
+ WHERE status IN ('open', 'needs_review')
3514
+ AND title LIKE 'Review:%completed%'
3515
+ AND (parent_task_id IS NULL OR parent_task_id NOT IN (SELECT id FROM tasks WHERE status IN ('open', 'in_progress', 'needs_review', 'blocked')))`,
3516
+ args: [now]
3517
+ });
3511
3518
  const staleThreshold = new Date(Date.now() - 60 * 60 * 1e3).toISOString();
3512
3519
  const r2 = await client.execute({
3513
3520
  sql: `UPDATE tasks SET status = 'done', updated_at = ?
@@ -3516,10 +3523,10 @@ async function cleanupOrphanedReviews() {
3516
3523
  AND updated_at < ?`,
3517
3524
  args: [now, staleThreshold]
3518
3525
  });
3519
- const total = r1.rowsAffected + r2.rowsAffected;
3526
+ const total = r1.rowsAffected + (r1b?.rowsAffected ?? 0) + r2.rowsAffected;
3520
3527
  if (total > 0) {
3521
3528
  process.stderr.write(
3522
- `[cleanup] Closed ${total} orphaned review(s): ${r1.rowsAffected} cascade + ${r2.rowsAffected} stale
3529
+ `[cleanup] Closed ${total} orphaned review(s): ${r1.rowsAffected} cascade + ${r1b?.rowsAffected ?? 0} orphan + ${r2.rowsAffected} stale
3523
3530
  `
3524
3531
  );
3525
3532
  }
@@ -3635,7 +3642,6 @@ var init_tasks_review = __esm({
3635
3642
  init_config();
3636
3643
  init_employees();
3637
3644
  init_notifications();
3638
- init_tasks_crud();
3639
3645
  init_tmux_routing();
3640
3646
  init_session_key();
3641
3647
  init_state_bus();
@@ -5709,6 +5715,9 @@ import { readFileSync as readFileSync12, writeFileSync as writeFileSync8, exists
5709
5715
  import crypto8 from "crypto";
5710
5716
  import path19 from "path";
5711
5717
  import { homedir } from "os";
5718
+ function sqlSafe(v) {
5719
+ return v === void 0 ? null : v;
5720
+ }
5712
5721
  function logError(msg) {
5713
5722
  try {
5714
5723
  const logPath = path19.join(homedir(), ".exe-os", "workers.log");
@@ -5879,18 +5888,18 @@ async function cloudSync(config) {
5879
5888
  author_device_id, scope)
5880
5889
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
5881
5890
  args: [
5882
- rec.id ?? null,
5883
- rec.agent_id ?? null,
5884
- rec.agent_role ?? null,
5885
- rec.session_id ?? null,
5886
- rec.timestamp ?? null,
5887
- rec.tool_name ?? null,
5888
- rec.project_name ?? null,
5889
- rec.has_error ?? 0,
5890
- rec.raw_text ?? "",
5891
- rec.version ?? 0,
5892
- rec.author_device_id ?? null,
5893
- rec.scope ?? "business"
5891
+ sqlSafe(rec.id),
5892
+ sqlSafe(rec.agent_id),
5893
+ sqlSafe(rec.agent_role),
5894
+ sqlSafe(rec.session_id),
5895
+ sqlSafe(rec.timestamp),
5896
+ sqlSafe(rec.tool_name),
5897
+ sqlSafe(rec.project_name),
5898
+ sqlSafe(rec.has_error ?? 0),
5899
+ sqlSafe(rec.raw_text ?? ""),
5900
+ sqlSafe(rec.version ?? 0),
5901
+ sqlSafe(rec.author_device_id),
5902
+ sqlSafe(rec.scope ?? "business")
5894
5903
  ]
5895
5904
  }));
5896
5905
  await client.batch(stmts, "write");
@@ -6311,14 +6320,14 @@ async function cloudPullGlobalProcedures(config) {
6311
6320
  updated_at = excluded.updated_at
6312
6321
  WHERE excluded.updated_at > global_procedures.updated_at`,
6313
6322
  args: [
6314
- p.id ?? null,
6315
- p.title ?? null,
6316
- p.content ?? null,
6317
- p.priority ?? "p0",
6318
- p.domain ?? null,
6319
- p.active ?? 1,
6320
- p.created_at ?? null,
6321
- p.updated_at ?? null
6323
+ sqlSafe(p.id),
6324
+ sqlSafe(p.title),
6325
+ sqlSafe(p.content),
6326
+ sqlSafe(p.priority ?? "p0"),
6327
+ sqlSafe(p.domain),
6328
+ sqlSafe(p.active ?? 1),
6329
+ sqlSafe(p.created_at),
6330
+ sqlSafe(p.updated_at)
6322
6331
  ]
6323
6332
  }));
6324
6333
  await client.batch(stmts, "write");
@@ -6348,7 +6357,7 @@ async function cloudPullBehaviors(config) {
6348
6357
  const existing = await client.execute({
6349
6358
  sql: `SELECT COUNT(*) as cnt FROM behaviors
6350
6359
  WHERE agent_id = ? AND content = ?`,
6351
- args: [behavior.agent_id ?? null, behavior.content ?? null]
6360
+ args: [sqlSafe(behavior.agent_id), sqlSafe(behavior.content)]
6352
6361
  });
6353
6362
  if (Number(existing.rows[0]?.cnt) > 0) continue;
6354
6363
  await client.execute({
@@ -6356,15 +6365,15 @@ async function cloudPullBehaviors(config) {
6356
6365
  (id, agent_id, project_name, domain, content, active, priority, created_at, updated_at)
6357
6366
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
6358
6367
  args: [
6359
- behavior.id ?? null,
6360
- behavior.agent_id ?? null,
6361
- behavior.project_name ?? null,
6362
- behavior.domain ?? null,
6363
- behavior.content ?? null,
6364
- behavior.active ?? 1,
6365
- behavior.priority ?? "p1",
6366
- behavior.created_at ?? null,
6367
- behavior.updated_at ?? null
6368
+ sqlSafe(behavior.id),
6369
+ sqlSafe(behavior.agent_id),
6370
+ sqlSafe(behavior.project_name),
6371
+ sqlSafe(behavior.domain),
6372
+ sqlSafe(behavior.content),
6373
+ sqlSafe(behavior.active ?? 1),
6374
+ sqlSafe(behavior.priority ?? "p1"),
6375
+ sqlSafe(behavior.created_at),
6376
+ sqlSafe(behavior.updated_at)
6368
6377
  ]
6369
6378
  });
6370
6379
  pulled++;
@@ -6412,7 +6421,7 @@ async function cloudPullGraphRAG(config) {
6412
6421
  const stmts = blob.entities.map((e) => ({
6413
6422
  sql: `INSERT OR IGNORE INTO entities (id, name, type, first_seen, last_seen, properties)
6414
6423
  VALUES (?, ?, ?, ?, ?, ?)`,
6415
- args: [e.id, e.name, e.type, e.first_seen, e.last_seen, e.properties ?? "{}"]
6424
+ args: [sqlSafe(e.id), sqlSafe(e.name), sqlSafe(e.type), sqlSafe(e.first_seen), sqlSafe(e.last_seen), sqlSafe(e.properties ?? "{}")]
6416
6425
  }));
6417
6426
  await client.batch(stmts, "write");
6418
6427
  pulled += stmts.length;
@@ -6423,15 +6432,15 @@ async function cloudPullGraphRAG(config) {
6423
6432
  (id, source_entity_id, target_entity_id, type, weight, timestamp, properties, confidence, confidence_label)
6424
6433
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
6425
6434
  args: [
6426
- r.id,
6427
- r.source_entity_id,
6428
- r.target_entity_id,
6429
- r.type,
6430
- r.weight ?? 1,
6431
- r.timestamp,
6432
- r.properties ?? "{}",
6433
- r.confidence ?? 1,
6434
- r.confidence_label ?? "extracted"
6435
+ sqlSafe(r.id),
6436
+ sqlSafe(r.source_entity_id),
6437
+ sqlSafe(r.target_entity_id),
6438
+ sqlSafe(r.type),
6439
+ sqlSafe(r.weight ?? 1),
6440
+ sqlSafe(r.timestamp),
6441
+ sqlSafe(r.properties ?? "{}"),
6442
+ sqlSafe(r.confidence ?? 1),
6443
+ sqlSafe(r.confidence_label ?? "extracted")
6435
6444
  ]
6436
6445
  }));
6437
6446
  await client.batch(stmts, "write");
@@ -6440,7 +6449,7 @@ async function cloudPullGraphRAG(config) {
6440
6449
  if (blob.entity_aliases.length > 0) {
6441
6450
  const stmts = blob.entity_aliases.map((a) => ({
6442
6451
  sql: `INSERT OR IGNORE INTO entity_aliases (alias, canonical_entity_id) VALUES (?, ?)`,
6443
- args: [a.alias, a.canonical_entity_id]
6452
+ args: [sqlSafe(a.alias), sqlSafe(a.canonical_entity_id)]
6444
6453
  }));
6445
6454
  await client.batch(stmts, "write");
6446
6455
  pulled += stmts.length;
@@ -6448,7 +6457,7 @@ async function cloudPullGraphRAG(config) {
6448
6457
  if (blob.entity_memories.length > 0) {
6449
6458
  const stmts = blob.entity_memories.map((em) => ({
6450
6459
  sql: `INSERT OR IGNORE INTO entity_memories (entity_id, memory_id) VALUES (?, ?)`,
6451
- args: [em.entity_id, em.memory_id]
6460
+ args: [sqlSafe(em.entity_id), sqlSafe(em.memory_id)]
6452
6461
  }));
6453
6462
  await client.batch(stmts, "write");
6454
6463
  pulled += stmts.length;
@@ -6456,7 +6465,7 @@ async function cloudPullGraphRAG(config) {
6456
6465
  if (blob.relationship_memories.length > 0) {
6457
6466
  const stmts = blob.relationship_memories.map((rm) => ({
6458
6467
  sql: `INSERT OR IGNORE INTO relationship_memories (relationship_id, memory_id) VALUES (?, ?)`,
6459
- args: [rm.relationship_id, rm.memory_id]
6468
+ args: [sqlSafe(rm.relationship_id), sqlSafe(rm.memory_id)]
6460
6469
  }));
6461
6470
  await client.batch(stmts, "write");
6462
6471
  pulled += stmts.length;
@@ -6465,7 +6474,7 @@ async function cloudPullGraphRAG(config) {
6465
6474
  const stmts = blob.hyperedges.map((h) => ({
6466
6475
  sql: `INSERT OR IGNORE INTO hyperedges (id, label, relation, confidence, timestamp)
6467
6476
  VALUES (?, ?, ?, ?, ?)`,
6468
- args: [h.id, h.label, h.relation, h.confidence ?? 1, h.timestamp]
6477
+ args: [sqlSafe(h.id), sqlSafe(h.label), sqlSafe(h.relation), sqlSafe(h.confidence ?? 1), sqlSafe(h.timestamp)]
6469
6478
  }));
6470
6479
  await client.batch(stmts, "write");
6471
6480
  pulled += stmts.length;
@@ -6473,7 +6482,7 @@ async function cloudPullGraphRAG(config) {
6473
6482
  if (blob.hyperedge_nodes.length > 0) {
6474
6483
  const stmts = blob.hyperedge_nodes.map((hn) => ({
6475
6484
  sql: `INSERT OR IGNORE INTO hyperedge_nodes (hyperedge_id, entity_id) VALUES (?, ?)`,
6476
- args: [hn.hyperedge_id, hn.entity_id]
6485
+ args: [sqlSafe(hn.hyperedge_id), sqlSafe(hn.entity_id)]
6477
6486
  }));
6478
6487
  await client.batch(stmts, "write");
6479
6488
  pulled += stmts.length;
@@ -6505,22 +6514,22 @@ async function cloudPullTasks(config) {
6505
6514
  blocked_by, parent_task_id, budget_tokens, budget_fallback_model, tokens_used, tokens_warned_at)
6506
6515
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
6507
6516
  args: [
6508
- t.id ?? null,
6509
- t.title ?? null,
6510
- t.assigned_to ?? null,
6511
- t.assigned_by ?? null,
6512
- t.project_name ?? null,
6513
- t.priority ?? "p1",
6514
- t.status ?? "open",
6515
- t.task_file ?? null,
6516
- t.created_at ?? null,
6517
- t.updated_at ?? null,
6518
- t.blocked_by ?? null,
6519
- t.parent_task_id ?? null,
6520
- t.budget_tokens ?? null,
6521
- t.budget_fallback_model ?? null,
6522
- t.tokens_used ?? 0,
6523
- t.tokens_warned_at ?? null
6517
+ sqlSafe(t.id),
6518
+ sqlSafe(t.title),
6519
+ sqlSafe(t.assigned_to),
6520
+ sqlSafe(t.assigned_by),
6521
+ sqlSafe(t.project_name),
6522
+ sqlSafe(t.priority ?? "p1"),
6523
+ sqlSafe(t.status ?? "open"),
6524
+ sqlSafe(t.task_file),
6525
+ sqlSafe(t.created_at),
6526
+ sqlSafe(t.updated_at),
6527
+ sqlSafe(t.blocked_by),
6528
+ sqlSafe(t.parent_task_id),
6529
+ sqlSafe(t.budget_tokens),
6530
+ sqlSafe(t.budget_fallback_model),
6531
+ sqlSafe(t.tokens_used ?? 0),
6532
+ sqlSafe(t.tokens_warned_at)
6524
6533
  ]
6525
6534
  }));
6526
6535
  await client.batch(stmts, "write");
@@ -6552,24 +6561,24 @@ async function cloudPullConversations(config) {
6552
6561
  content_metadata, agent_response, agent_name, timestamp, ingested_at)
6553
6562
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
6554
6563
  args: [
6555
- c.id ?? null,
6556
- c.platform ?? null,
6557
- c.external_id ?? null,
6558
- c.sender_id ?? null,
6559
- c.sender_name ?? null,
6560
- c.sender_phone ?? null,
6561
- c.sender_email ?? null,
6562
- c.recipient_id ?? null,
6563
- c.channel_id ?? null,
6564
- c.thread_id ?? null,
6565
- c.reply_to_id ?? null,
6566
- c.content_text ?? null,
6567
- c.content_media ?? null,
6568
- c.content_metadata ?? null,
6569
- c.agent_response ?? null,
6570
- c.agent_name ?? null,
6571
- c.timestamp ?? null,
6572
- c.ingested_at ?? null
6564
+ sqlSafe(c.id),
6565
+ sqlSafe(c.platform),
6566
+ sqlSafe(c.external_id),
6567
+ sqlSafe(c.sender_id),
6568
+ sqlSafe(c.sender_name),
6569
+ sqlSafe(c.sender_phone),
6570
+ sqlSafe(c.sender_email),
6571
+ sqlSafe(c.recipient_id),
6572
+ sqlSafe(c.channel_id),
6573
+ sqlSafe(c.thread_id),
6574
+ sqlSafe(c.reply_to_id),
6575
+ sqlSafe(c.content_text),
6576
+ sqlSafe(c.content_media),
6577
+ sqlSafe(c.content_metadata),
6578
+ sqlSafe(c.agent_response),
6579
+ sqlSafe(c.agent_name),
6580
+ sqlSafe(c.timestamp),
6581
+ sqlSafe(c.ingested_at)
6573
6582
  ]
6574
6583
  }));
6575
6584
  await client.batch(stmts, "write");
@@ -6606,7 +6615,7 @@ async function cloudPullDocuments(config) {
6606
6615
  const stmts = blob.workspaces.map((w) => ({
6607
6616
  sql: `INSERT OR IGNORE INTO workspaces (id, slug, name, owner_agent_id, created_at, metadata)
6608
6617
  VALUES (?, ?, ?, ?, ?, ?)`,
6609
- args: [w.id, w.slug, w.name, w.owner_agent_id ?? null, w.created_at, w.metadata ?? null]
6618
+ args: [sqlSafe(w.id), sqlSafe(w.slug), sqlSafe(w.name), sqlSafe(w.owner_agent_id), sqlSafe(w.created_at), sqlSafe(w.metadata)]
6610
6619
  }));
6611
6620
  await client.batch(stmts, "write");
6612
6621
  pulled += stmts.length;
@@ -6617,14 +6626,14 @@ async function cloudPullDocuments(config) {
6617
6626
  (id, workspace_id, filename, mime, source_type, user_id, uploaded_at, metadata)
6618
6627
  VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
6619
6628
  args: [
6620
- d.id,
6621
- d.workspace_id,
6622
- d.filename,
6623
- d.mime ?? null,
6624
- d.source_type ?? null,
6625
- d.user_id ?? null,
6626
- d.uploaded_at,
6627
- d.metadata ?? null
6629
+ sqlSafe(d.id),
6630
+ sqlSafe(d.workspace_id),
6631
+ sqlSafe(d.filename),
6632
+ sqlSafe(d.mime),
6633
+ sqlSafe(d.source_type),
6634
+ sqlSafe(d.user_id),
6635
+ sqlSafe(d.uploaded_at),
6636
+ sqlSafe(d.metadata)
6628
6637
  ]
6629
6638
  }));
6630
6639
  await client.batch(stmts, "write");