@askexenow/exe-os 0.8.58 → 0.8.60

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 (38) hide show
  1. package/dist/bin/cli.js +92 -12
  2. package/dist/bin/exe-boot.js +137 -100
  3. package/dist/bin/exe-cloud.js +35 -3
  4. package/dist/bin/exe-dispatch.js +3746 -250
  5. package/dist/bin/exe-gateway.js +50 -15
  6. package/dist/bin/exe-heartbeat.js +34 -49
  7. package/dist/bin/exe-link.js +91 -88
  8. package/dist/bin/exe-new-employee.js +44 -3
  9. package/dist/bin/exe-pending-reviews.js +4 -27
  10. package/dist/bin/exe-session-cleanup.js +846 -2946
  11. package/dist/bin/git-sweep.js +13 -11
  12. package/dist/bin/scan-tasks.js +13 -11
  13. package/dist/bin/setup.js +35 -3
  14. package/dist/bin/update.js +35 -3
  15. package/dist/gateway/index.js +17 -14
  16. package/dist/hooks/bug-report-worker.js +13 -11
  17. package/dist/hooks/commit-complete.js +13 -11
  18. package/dist/hooks/ingest-worker.js +55 -12
  19. package/dist/hooks/pre-compact.js +13 -11
  20. package/dist/hooks/prompt-ingest-worker.js +44 -3
  21. package/dist/hooks/prompt-submit.js +516 -2611
  22. package/dist/hooks/response-ingest-worker.js +44 -3
  23. package/dist/hooks/summary-worker.js +126 -91
  24. package/dist/index.js +38 -14
  25. package/dist/lib/cloud-sync.js +91 -88
  26. package/dist/lib/exe-daemon.js +45 -56
  27. package/dist/lib/license.js +35 -3
  28. package/dist/lib/messaging.js +31 -524
  29. package/dist/lib/tasks.js +13 -11
  30. package/dist/lib/tmux-routing.js +13 -11
  31. package/dist/mcp/server.js +51 -16
  32. package/dist/mcp/tools/create-task.js +13 -11
  33. package/dist/mcp/tools/list-tasks.js +0 -1
  34. package/dist/mcp/tools/send-message.js +37 -530
  35. package/dist/mcp/tools/update-task.js +0 -1
  36. package/dist/runtime/index.js +34 -11
  37. package/dist/tui/App.js +92 -12
  38. package/package.json +1 -1
package/dist/bin/cli.js CHANGED
@@ -4864,6 +4864,32 @@ function readCachedToken() {
4864
4864
  return null;
4865
4865
  }
4866
4866
  }
4867
+ function getRawCachedPlan() {
4868
+ try {
4869
+ const token = readCachedToken();
4870
+ if (!token) return null;
4871
+ const parts = token.split(".");
4872
+ if (parts.length !== 3) return null;
4873
+ const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString());
4874
+ const plan = payload.plan ?? "free";
4875
+ const limits = PLAN_LIMITS[plan] ?? PLAN_LIMITS.free;
4876
+ process.stderr.write(
4877
+ `[license] WARN: using unverified cached plan (API unreachable, JWT expired). Plan: ${plan}
4878
+ `
4879
+ );
4880
+ return {
4881
+ valid: true,
4882
+ plan,
4883
+ email: payload.sub ?? "",
4884
+ expiresAt: payload.exp ? new Date(payload.exp * 1e3).toISOString() : null,
4885
+ deviceLimit: limits.devices,
4886
+ employeeLimit: limits.employees,
4887
+ memoryLimit: limits.memories
4888
+ };
4889
+ } catch {
4890
+ return null;
4891
+ }
4892
+ }
4867
4893
  function cacheResponse(token) {
4868
4894
  try {
4869
4895
  writeFileSync2(CACHE_PATH, JSON.stringify({ token }), "utf8");
@@ -4884,6 +4910,8 @@ async function validateLicense(apiKey, deviceId) {
4884
4910
  if (data.error === "device_limit_exceeded") {
4885
4911
  const cached2 = await getCachedLicense();
4886
4912
  if (cached2) return cached2;
4913
+ const raw2 = getRawCachedPlan();
4914
+ if (raw2) return { ...raw2, valid: false };
4887
4915
  return { ...FREE_LICENSE, valid: false, plan: "free" };
4888
4916
  }
4889
4917
  if (data.token) {
@@ -4904,10 +4932,14 @@ async function validateLicense(apiKey, deviceId) {
4904
4932
  }
4905
4933
  const cached = await getCachedLicense();
4906
4934
  if (cached) return cached;
4935
+ const raw = getRawCachedPlan();
4936
+ if (raw) return raw;
4907
4937
  return { ...FREE_LICENSE, valid: false, plan: "free" };
4908
4938
  } catch {
4909
4939
  const cached = await getCachedLicense();
4910
4940
  if (cached) return cached;
4941
+ const rawFallback = getRawCachedPlan();
4942
+ if (rawFallback) return rawFallback;
4911
4943
  return { ...FREE_LICENSE, valid: false, error: "offline" };
4912
4944
  }
4913
4945
  }
@@ -5096,8 +5128,8 @@ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
5096
5128
  -----END PUBLIC KEY-----`;
5097
5129
  LICENSE_JWT_ALG = "ES256";
5098
5130
  PLAN_LIMITS = {
5099
- free: { devices: 1, employees: 1, memories: 5e3 },
5100
- pro: { devices: 2, employees: 5, memories: 1e5 },
5131
+ free: { devices: 1, employees: 1, memories: 5e4 },
5132
+ pro: { devices: 2, employees: 5, memories: 25e4 },
5101
5133
  team: { devices: 10, employees: 20, memories: 1e6 },
5102
5134
  agency: { devices: 50, employees: 100, memories: 1e7 },
5103
5135
  enterprise: { devices: -1, employees: -1, memories: -1 }
@@ -5109,7 +5141,7 @@ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
5109
5141
  expiresAt: null,
5110
5142
  deviceLimit: 1,
5111
5143
  employeeLimit: 1,
5112
- memoryLimit: 5e3
5144
+ memoryLimit: 5e4
5113
5145
  };
5114
5146
  CACHE_MAX_AGE_MS = 36e5;
5115
5147
  _revalTimer = null;
@@ -13238,6 +13270,21 @@ var init_session_kill_telemetry = __esm({
13238
13270
  });
13239
13271
 
13240
13272
  // src/lib/tasks-crud.ts
13273
+ var tasks_crud_exports = {};
13274
+ __export(tasks_crud_exports, {
13275
+ TASK_ALREADY_CLAIMED_PREFIX: () => TASK_ALREADY_CLAIMED_PREFIX,
13276
+ checkStaleCompletion: () => checkStaleCompletion,
13277
+ createTaskCore: () => createTaskCore,
13278
+ deleteTaskCore: () => deleteTaskCore,
13279
+ ensureArchitectureDoc: () => ensureArchitectureDoc,
13280
+ ensureGitignoreExe: () => ensureGitignoreExe,
13281
+ extractParentFromContext: () => extractParentFromContext,
13282
+ listTasks: () => listTasks,
13283
+ resolveTask: () => resolveTask,
13284
+ slugify: () => slugify,
13285
+ updateTaskStatus: () => updateTaskStatus,
13286
+ writeCheckpoint: () => writeCheckpoint
13287
+ });
13241
13288
  import crypto6 from "crypto";
13242
13289
  import path19 from "path";
13243
13290
  import { execSync as execSync8 } from "child_process";
@@ -13854,7 +13901,6 @@ var init_tasks_review = __esm({
13854
13901
  init_config();
13855
13902
  init_employees();
13856
13903
  init_notifications();
13857
- init_tasks_crud();
13858
13904
  init_tmux_routing();
13859
13905
  init_session_key();
13860
13906
  init_state_bus();
@@ -14990,18 +15036,21 @@ function exportBehaviorsSync(agentId, projectName, sessionKey) {
14990
15036
  function getMySession() {
14991
15037
  return getTransport().getMySession();
14992
15038
  }
15039
+ function isRootSession(name) {
15040
+ return name.length > 0 && !name.includes("-");
15041
+ }
14993
15042
  function employeeSessionName(employee, exeSession, instance) {
14994
- if (!/^exe\d+$/.test(exeSession)) {
15043
+ if (!isRootSession(exeSession)) {
14995
15044
  const root = extractRootExe(exeSession);
14996
15045
  if (root) {
14997
15046
  process.stderr.write(
14998
- `[tmux-routing] WARN: exeSession="${exeSession}" is not a root exe session, using "${root}" instead
15047
+ `[tmux-routing] WARN: exeSession="${exeSession}" is not a root session, using "${root}" instead
14999
15048
  `
15000
15049
  );
15001
15050
  exeSession = root;
15002
15051
  } else {
15003
15052
  throw new Error(
15004
- `Invalid exeSession "${exeSession}" \u2014 must be a root exe session (e.g., "exe1"), not an agent session`
15053
+ `Invalid exeSession "${exeSession}" \u2014 contains a dash but no recognizable root session. Pass a root session name (e.g., "exe1", "work", "yoda1")`
15005
15054
  );
15006
15055
  }
15007
15056
  }
@@ -15009,7 +15058,7 @@ function employeeSessionName(employee, exeSession, instance) {
15009
15058
  const name = `${employee}${suffix}-${exeSession}`;
15010
15059
  if (!VALID_SESSION_NAME.test(name)) {
15011
15060
  throw new Error(
15012
- `Invalid session name "${name}" \u2014 must match {agent}-exe{N} or {agent}{instance}-exe{N}`
15061
+ `Invalid session name "${name}" \u2014 must match {agent}-{rootSession} or {agent}{instance}-{rootSession}`
15013
15062
  );
15014
15063
  }
15015
15064
  return name;
@@ -15252,11 +15301,11 @@ function ensureEmployee(employeeName, exeSession, projectDir, opts) {
15252
15301
  error: `Error: pass employee name ('${bare}'), not session name ('${employeeName}')`
15253
15302
  };
15254
15303
  }
15255
- if (!/^exe\d+$/.test(exeSession)) {
15304
+ if (!isRootSession(exeSession)) {
15256
15305
  const root = extractRootExe(exeSession);
15257
15306
  if (root) {
15258
15307
  process.stderr.write(
15259
- `[ensureEmployee] WARN: caller passed exeSession="${exeSession}" (not a root exe). Auto-correcting to "${root}".
15308
+ `[ensureEmployee] WARN: caller passed exeSession="${exeSession}" (not a root session). Auto-correcting to "${root}".
15260
15309
  `
15261
15310
  );
15262
15311
  exeSession = root;
@@ -15264,7 +15313,7 @@ function ensureEmployee(employeeName, exeSession, projectDir, opts) {
15264
15313
  return {
15265
15314
  status: "failed",
15266
15315
  sessionName: "",
15267
- error: `Invalid exeSession "${exeSession}" \u2014 must be a root exe session (e.g., "exe1")`
15316
+ error: `Invalid exeSession "${exeSession}" \u2014 contains a dash but no recognizable root session. Pass a root session name (e.g., "exe1", "work", "yoda1")`
15268
15317
  };
15269
15318
  }
15270
15319
  }
@@ -15529,7 +15578,7 @@ var init_tmux_routing = __esm({
15529
15578
  SPAWN_LOCK_DIR = path24.join(os9.homedir(), ".exe-os", "spawn-locks");
15530
15579
  SESSION_CACHE = path24.join(os9.homedir(), ".exe-os", "session-cache");
15531
15580
  BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
15532
- VALID_SESSION_NAME = /^[a-z]+-exe\d+$|^[a-z]+\d+-exe\d+$/;
15581
+ VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
15533
15582
  VERIFY_PANE_LINES = 200;
15534
15583
  INTERCOM_DEBOUNCE_MS = 3e4;
15535
15584
  INTERCOM_LOG2 = path24.join(os9.homedir(), ".exe-os", "intercom.log");
@@ -19515,6 +19564,7 @@ var init_orchestrator = __esm({
19515
19564
  init_task_router();
19516
19565
  init_tmux_routing();
19517
19566
  init_task_scope();
19567
+ init_tasks_crud();
19518
19568
  STALE_THRESHOLD_MS = 2 * 60 * 60 * 1e3;
19519
19569
  MultiAgentOrchestrator = class {
19520
19570
  config;
@@ -19551,6 +19601,26 @@ ${task.context}`,
19551
19601
  targetEmployee = routed.employee;
19552
19602
  routingScore = routed.score;
19553
19603
  }
19604
+ try {
19605
+ await createTaskCore({
19606
+ title: task.title,
19607
+ assignedTo: targetEmployee.name,
19608
+ assignedBy: "exe",
19609
+ projectName: task.projectName,
19610
+ priority: task.priority,
19611
+ context: task.context,
19612
+ baseDir: this.config.projectDir,
19613
+ skipDispatch: true
19614
+ });
19615
+ } catch (err) {
19616
+ return {
19617
+ employee: targetEmployee.name,
19618
+ sessionName: "",
19619
+ status: "failed",
19620
+ routingScore,
19621
+ error: `Task creation failed: ${err instanceof Error ? err.message : String(err)}`
19622
+ };
19623
+ }
19554
19624
  const result = ensureEmployee(
19555
19625
  targetEmployee.name,
19556
19626
  this.config.exeSession,
@@ -19838,7 +19908,17 @@ function useOrchestrator(enabled = true) {
19838
19908
  const spawnSession = useCallback5(
19839
19909
  async (agentId) => {
19840
19910
  try {
19911
+ const { createTaskCore: createTaskCore2 } = await Promise.resolve().then(() => (init_tasks_crud(), tasks_crud_exports));
19841
19912
  const { ensureEmployee: ensureEmployee2 } = await Promise.resolve().then(() => (init_tmux_routing(), tmux_routing_exports));
19913
+ await createTaskCore2({
19914
+ title: `Session launched for ${agentId} (TUI)`,
19915
+ assignedTo: agentId,
19916
+ assignedBy: "exe",
19917
+ projectName: "exe-os",
19918
+ priority: "p2",
19919
+ context: "Session spawned from TUI Sessions view. Agent will pick up any queued tasks via intercom.",
19920
+ skipDispatch: true
19921
+ });
19842
19922
  return ensureEmployee2(agentId, exeSessionRef.current, process.cwd());
19843
19923
  } catch {
19844
19924
  return null;
@@ -2418,6 +2418,32 @@ function readCachedToken() {
2418
2418
  return null;
2419
2419
  }
2420
2420
  }
2421
+ function getRawCachedPlan() {
2422
+ try {
2423
+ const token = readCachedToken();
2424
+ if (!token) return null;
2425
+ const parts = token.split(".");
2426
+ if (parts.length !== 3) return null;
2427
+ const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString());
2428
+ const plan = payload.plan ?? "free";
2429
+ const limits = PLAN_LIMITS[plan] ?? PLAN_LIMITS.free;
2430
+ process.stderr.write(
2431
+ `[license] WARN: using unverified cached plan (API unreachable, JWT expired). Plan: ${plan}
2432
+ `
2433
+ );
2434
+ return {
2435
+ valid: true,
2436
+ plan,
2437
+ email: payload.sub ?? "",
2438
+ expiresAt: payload.exp ? new Date(payload.exp * 1e3).toISOString() : null,
2439
+ deviceLimit: limits.devices,
2440
+ employeeLimit: limits.employees,
2441
+ memoryLimit: limits.memories
2442
+ };
2443
+ } catch {
2444
+ return null;
2445
+ }
2446
+ }
2421
2447
  function cacheResponse(token) {
2422
2448
  try {
2423
2449
  writeFileSync3(CACHE_PATH, JSON.stringify({ token }), "utf8");
@@ -2438,6 +2464,8 @@ async function validateLicense(apiKey, deviceId) {
2438
2464
  if (data.error === "device_limit_exceeded") {
2439
2465
  const cached2 = await getCachedLicense();
2440
2466
  if (cached2) return cached2;
2467
+ const raw2 = getRawCachedPlan();
2468
+ if (raw2) return { ...raw2, valid: false };
2441
2469
  return { ...FREE_LICENSE, valid: false, plan: "free" };
2442
2470
  }
2443
2471
  if (data.token) {
@@ -2458,10 +2486,14 @@ async function validateLicense(apiKey, deviceId) {
2458
2486
  }
2459
2487
  const cached = await getCachedLicense();
2460
2488
  if (cached) return cached;
2489
+ const raw = getRawCachedPlan();
2490
+ if (raw) return raw;
2461
2491
  return { ...FREE_LICENSE, valid: false, plan: "free" };
2462
2492
  } catch {
2463
2493
  const cached = await getCachedLicense();
2464
2494
  if (cached) return cached;
2495
+ const rawFallback = getRawCachedPlan();
2496
+ if (rawFallback) return rawFallback;
2465
2497
  return { ...FREE_LICENSE, valid: false, error: "offline" };
2466
2498
  }
2467
2499
  }
@@ -2650,8 +2682,8 @@ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
2650
2682
  -----END PUBLIC KEY-----`;
2651
2683
  LICENSE_JWT_ALG = "ES256";
2652
2684
  PLAN_LIMITS = {
2653
- free: { devices: 1, employees: 1, memories: 5e3 },
2654
- pro: { devices: 2, employees: 5, memories: 1e5 },
2685
+ free: { devices: 1, employees: 1, memories: 5e4 },
2686
+ pro: { devices: 2, employees: 5, memories: 25e4 },
2655
2687
  team: { devices: 10, employees: 20, memories: 1e6 },
2656
2688
  agency: { devices: 50, employees: 100, memories: 1e7 },
2657
2689
  enterprise: { devices: -1, employees: -1, memories: -1 }
@@ -2663,7 +2695,7 @@ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
2663
2695
  expiresAt: null,
2664
2696
  deviceLimit: 1,
2665
2697
  employeeLimit: 1,
2666
- memoryLimit: 5e3
2698
+ memoryLimit: 5e4
2667
2699
  };
2668
2700
  CACHE_MAX_AGE_MS = 36e5;
2669
2701
  _revalTimer = null;
@@ -3642,7 +3674,6 @@ var init_tasks_review = __esm({
3642
3674
  init_config();
3643
3675
  init_employees();
3644
3676
  init_notifications();
3645
- init_tasks_crud();
3646
3677
  init_tmux_routing();
3647
3678
  init_session_key();
3648
3679
  init_state_bus();
@@ -4787,18 +4818,21 @@ function exportBehaviorsSync(agentId, projectName, sessionKey) {
4787
4818
  function getMySession() {
4788
4819
  return getTransport().getMySession();
4789
4820
  }
4821
+ function isRootSession(name) {
4822
+ return name.length > 0 && !name.includes("-");
4823
+ }
4790
4824
  function employeeSessionName(employee, exeSession, instance) {
4791
- if (!/^exe\d+$/.test(exeSession)) {
4825
+ if (!isRootSession(exeSession)) {
4792
4826
  const root = extractRootExe(exeSession);
4793
4827
  if (root) {
4794
4828
  process.stderr.write(
4795
- `[tmux-routing] WARN: exeSession="${exeSession}" is not a root exe session, using "${root}" instead
4829
+ `[tmux-routing] WARN: exeSession="${exeSession}" is not a root session, using "${root}" instead
4796
4830
  `
4797
4831
  );
4798
4832
  exeSession = root;
4799
4833
  } else {
4800
4834
  throw new Error(
4801
- `Invalid exeSession "${exeSession}" \u2014 must be a root exe session (e.g., "exe1"), not an agent session`
4835
+ `Invalid exeSession "${exeSession}" \u2014 contains a dash but no recognizable root session. Pass a root session name (e.g., "exe1", "work", "yoda1")`
4802
4836
  );
4803
4837
  }
4804
4838
  }
@@ -4806,7 +4840,7 @@ function employeeSessionName(employee, exeSession, instance) {
4806
4840
  const name = `${employee}${suffix}-${exeSession}`;
4807
4841
  if (!VALID_SESSION_NAME.test(name)) {
4808
4842
  throw new Error(
4809
- `Invalid session name "${name}" \u2014 must match {agent}-exe{N} or {agent}{instance}-exe{N}`
4843
+ `Invalid session name "${name}" \u2014 must match {agent}-{rootSession} or {agent}{instance}-{rootSession}`
4810
4844
  );
4811
4845
  }
4812
4846
  return name;
@@ -5049,11 +5083,11 @@ function ensureEmployee(employeeName, exeSession, projectDir, opts) {
5049
5083
  error: `Error: pass employee name ('${bare}'), not session name ('${employeeName}')`
5050
5084
  };
5051
5085
  }
5052
- if (!/^exe\d+$/.test(exeSession)) {
5086
+ if (!isRootSession(exeSession)) {
5053
5087
  const root = extractRootExe(exeSession);
5054
5088
  if (root) {
5055
5089
  process.stderr.write(
5056
- `[ensureEmployee] WARN: caller passed exeSession="${exeSession}" (not a root exe). Auto-correcting to "${root}".
5090
+ `[ensureEmployee] WARN: caller passed exeSession="${exeSession}" (not a root session). Auto-correcting to "${root}".
5057
5091
  `
5058
5092
  );
5059
5093
  exeSession = root;
@@ -5061,7 +5095,7 @@ function ensureEmployee(employeeName, exeSession, projectDir, opts) {
5061
5095
  return {
5062
5096
  status: "failed",
5063
5097
  sessionName: "",
5064
- error: `Invalid exeSession "${exeSession}" \u2014 must be a root exe session (e.g., "exe1")`
5098
+ error: `Invalid exeSession "${exeSession}" \u2014 contains a dash but no recognizable root session. Pass a root session name (e.g., "exe1", "work", "yoda1")`
5065
5099
  };
5066
5100
  }
5067
5101
  }
@@ -5326,7 +5360,7 @@ var init_tmux_routing = __esm({
5326
5360
  SPAWN_LOCK_DIR = path15.join(os6.homedir(), ".exe-os", "spawn-locks");
5327
5361
  SESSION_CACHE = path15.join(os6.homedir(), ".exe-os", "session-cache");
5328
5362
  BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
5329
- VALID_SESSION_NAME = /^[a-z]+-exe\d+$|^[a-z]+\d+-exe\d+$/;
5363
+ VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
5330
5364
  VERIFY_PANE_LINES = 200;
5331
5365
  INTERCOM_DEBOUNCE_MS = 3e4;
5332
5366
  INTERCOM_LOG2 = path15.join(os6.homedir(), ".exe-os", "intercom.log");
@@ -5716,6 +5750,9 @@ import { readFileSync as readFileSync12, writeFileSync as writeFileSync8, exists
5716
5750
  import crypto8 from "crypto";
5717
5751
  import path19 from "path";
5718
5752
  import { homedir } from "os";
5753
+ function sqlSafe(v) {
5754
+ return v === void 0 ? null : v;
5755
+ }
5719
5756
  function logError(msg) {
5720
5757
  try {
5721
5758
  const logPath = path19.join(homedir(), ".exe-os", "workers.log");
@@ -5886,18 +5923,18 @@ async function cloudSync(config) {
5886
5923
  author_device_id, scope)
5887
5924
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
5888
5925
  args: [
5889
- rec.id ?? null,
5890
- rec.agent_id ?? null,
5891
- rec.agent_role ?? null,
5892
- rec.session_id ?? null,
5893
- rec.timestamp ?? null,
5894
- rec.tool_name ?? null,
5895
- rec.project_name ?? null,
5896
- rec.has_error ?? 0,
5897
- rec.raw_text ?? "",
5898
- rec.version ?? 0,
5899
- rec.author_device_id ?? null,
5900
- rec.scope ?? "business"
5926
+ sqlSafe(rec.id),
5927
+ sqlSafe(rec.agent_id),
5928
+ sqlSafe(rec.agent_role),
5929
+ sqlSafe(rec.session_id),
5930
+ sqlSafe(rec.timestamp),
5931
+ sqlSafe(rec.tool_name),
5932
+ sqlSafe(rec.project_name),
5933
+ sqlSafe(rec.has_error ?? 0),
5934
+ sqlSafe(rec.raw_text ?? ""),
5935
+ sqlSafe(rec.version ?? 0),
5936
+ sqlSafe(rec.author_device_id),
5937
+ sqlSafe(rec.scope ?? "business")
5901
5938
  ]
5902
5939
  }));
5903
5940
  await client.batch(stmts, "write");
@@ -6318,14 +6355,14 @@ async function cloudPullGlobalProcedures(config) {
6318
6355
  updated_at = excluded.updated_at
6319
6356
  WHERE excluded.updated_at > global_procedures.updated_at`,
6320
6357
  args: [
6321
- p.id ?? null,
6322
- p.title ?? null,
6323
- p.content ?? null,
6324
- p.priority ?? "p0",
6325
- p.domain ?? null,
6326
- p.active ?? 1,
6327
- p.created_at ?? null,
6328
- p.updated_at ?? null
6358
+ sqlSafe(p.id),
6359
+ sqlSafe(p.title),
6360
+ sqlSafe(p.content),
6361
+ sqlSafe(p.priority ?? "p0"),
6362
+ sqlSafe(p.domain),
6363
+ sqlSafe(p.active ?? 1),
6364
+ sqlSafe(p.created_at),
6365
+ sqlSafe(p.updated_at)
6329
6366
  ]
6330
6367
  }));
6331
6368
  await client.batch(stmts, "write");
@@ -6355,7 +6392,7 @@ async function cloudPullBehaviors(config) {
6355
6392
  const existing = await client.execute({
6356
6393
  sql: `SELECT COUNT(*) as cnt FROM behaviors
6357
6394
  WHERE agent_id = ? AND content = ?`,
6358
- args: [behavior.agent_id ?? null, behavior.content ?? null]
6395
+ args: [sqlSafe(behavior.agent_id), sqlSafe(behavior.content)]
6359
6396
  });
6360
6397
  if (Number(existing.rows[0]?.cnt) > 0) continue;
6361
6398
  await client.execute({
@@ -6363,15 +6400,15 @@ async function cloudPullBehaviors(config) {
6363
6400
  (id, agent_id, project_name, domain, content, active, priority, created_at, updated_at)
6364
6401
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
6365
6402
  args: [
6366
- behavior.id ?? null,
6367
- behavior.agent_id ?? null,
6368
- behavior.project_name ?? null,
6369
- behavior.domain ?? null,
6370
- behavior.content ?? null,
6371
- behavior.active ?? 1,
6372
- behavior.priority ?? "p1",
6373
- behavior.created_at ?? null,
6374
- behavior.updated_at ?? null
6403
+ sqlSafe(behavior.id),
6404
+ sqlSafe(behavior.agent_id),
6405
+ sqlSafe(behavior.project_name),
6406
+ sqlSafe(behavior.domain),
6407
+ sqlSafe(behavior.content),
6408
+ sqlSafe(behavior.active ?? 1),
6409
+ sqlSafe(behavior.priority ?? "p1"),
6410
+ sqlSafe(behavior.created_at),
6411
+ sqlSafe(behavior.updated_at)
6375
6412
  ]
6376
6413
  });
6377
6414
  pulled++;
@@ -6419,7 +6456,7 @@ async function cloudPullGraphRAG(config) {
6419
6456
  const stmts = blob.entities.map((e) => ({
6420
6457
  sql: `INSERT OR IGNORE INTO entities (id, name, type, first_seen, last_seen, properties)
6421
6458
  VALUES (?, ?, ?, ?, ?, ?)`,
6422
- args: [e.id, e.name, e.type, e.first_seen, e.last_seen, e.properties ?? "{}"]
6459
+ args: [sqlSafe(e.id), sqlSafe(e.name), sqlSafe(e.type), sqlSafe(e.first_seen), sqlSafe(e.last_seen), sqlSafe(e.properties ?? "{}")]
6423
6460
  }));
6424
6461
  await client.batch(stmts, "write");
6425
6462
  pulled += stmts.length;
@@ -6430,15 +6467,15 @@ async function cloudPullGraphRAG(config) {
6430
6467
  (id, source_entity_id, target_entity_id, type, weight, timestamp, properties, confidence, confidence_label)
6431
6468
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
6432
6469
  args: [
6433
- r.id,
6434
- r.source_entity_id,
6435
- r.target_entity_id,
6436
- r.type,
6437
- r.weight ?? 1,
6438
- r.timestamp,
6439
- r.properties ?? "{}",
6440
- r.confidence ?? 1,
6441
- r.confidence_label ?? "extracted"
6470
+ sqlSafe(r.id),
6471
+ sqlSafe(r.source_entity_id),
6472
+ sqlSafe(r.target_entity_id),
6473
+ sqlSafe(r.type),
6474
+ sqlSafe(r.weight ?? 1),
6475
+ sqlSafe(r.timestamp),
6476
+ sqlSafe(r.properties ?? "{}"),
6477
+ sqlSafe(r.confidence ?? 1),
6478
+ sqlSafe(r.confidence_label ?? "extracted")
6442
6479
  ]
6443
6480
  }));
6444
6481
  await client.batch(stmts, "write");
@@ -6447,7 +6484,7 @@ async function cloudPullGraphRAG(config) {
6447
6484
  if (blob.entity_aliases.length > 0) {
6448
6485
  const stmts = blob.entity_aliases.map((a) => ({
6449
6486
  sql: `INSERT OR IGNORE INTO entity_aliases (alias, canonical_entity_id) VALUES (?, ?)`,
6450
- args: [a.alias, a.canonical_entity_id]
6487
+ args: [sqlSafe(a.alias), sqlSafe(a.canonical_entity_id)]
6451
6488
  }));
6452
6489
  await client.batch(stmts, "write");
6453
6490
  pulled += stmts.length;
@@ -6455,7 +6492,7 @@ async function cloudPullGraphRAG(config) {
6455
6492
  if (blob.entity_memories.length > 0) {
6456
6493
  const stmts = blob.entity_memories.map((em) => ({
6457
6494
  sql: `INSERT OR IGNORE INTO entity_memories (entity_id, memory_id) VALUES (?, ?)`,
6458
- args: [em.entity_id, em.memory_id]
6495
+ args: [sqlSafe(em.entity_id), sqlSafe(em.memory_id)]
6459
6496
  }));
6460
6497
  await client.batch(stmts, "write");
6461
6498
  pulled += stmts.length;
@@ -6463,7 +6500,7 @@ async function cloudPullGraphRAG(config) {
6463
6500
  if (blob.relationship_memories.length > 0) {
6464
6501
  const stmts = blob.relationship_memories.map((rm) => ({
6465
6502
  sql: `INSERT OR IGNORE INTO relationship_memories (relationship_id, memory_id) VALUES (?, ?)`,
6466
- args: [rm.relationship_id, rm.memory_id]
6503
+ args: [sqlSafe(rm.relationship_id), sqlSafe(rm.memory_id)]
6467
6504
  }));
6468
6505
  await client.batch(stmts, "write");
6469
6506
  pulled += stmts.length;
@@ -6472,7 +6509,7 @@ async function cloudPullGraphRAG(config) {
6472
6509
  const stmts = blob.hyperedges.map((h) => ({
6473
6510
  sql: `INSERT OR IGNORE INTO hyperedges (id, label, relation, confidence, timestamp)
6474
6511
  VALUES (?, ?, ?, ?, ?)`,
6475
- args: [h.id, h.label, h.relation, h.confidence ?? 1, h.timestamp]
6512
+ args: [sqlSafe(h.id), sqlSafe(h.label), sqlSafe(h.relation), sqlSafe(h.confidence ?? 1), sqlSafe(h.timestamp)]
6476
6513
  }));
6477
6514
  await client.batch(stmts, "write");
6478
6515
  pulled += stmts.length;
@@ -6480,7 +6517,7 @@ async function cloudPullGraphRAG(config) {
6480
6517
  if (blob.hyperedge_nodes.length > 0) {
6481
6518
  const stmts = blob.hyperedge_nodes.map((hn) => ({
6482
6519
  sql: `INSERT OR IGNORE INTO hyperedge_nodes (hyperedge_id, entity_id) VALUES (?, ?)`,
6483
- args: [hn.hyperedge_id, hn.entity_id]
6520
+ args: [sqlSafe(hn.hyperedge_id), sqlSafe(hn.entity_id)]
6484
6521
  }));
6485
6522
  await client.batch(stmts, "write");
6486
6523
  pulled += stmts.length;
@@ -6512,22 +6549,22 @@ async function cloudPullTasks(config) {
6512
6549
  blocked_by, parent_task_id, budget_tokens, budget_fallback_model, tokens_used, tokens_warned_at)
6513
6550
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
6514
6551
  args: [
6515
- t.id ?? null,
6516
- t.title ?? null,
6517
- t.assigned_to ?? null,
6518
- t.assigned_by ?? null,
6519
- t.project_name ?? null,
6520
- t.priority ?? "p1",
6521
- t.status ?? "open",
6522
- t.task_file ?? null,
6523
- t.created_at ?? null,
6524
- t.updated_at ?? null,
6525
- t.blocked_by ?? null,
6526
- t.parent_task_id ?? null,
6527
- t.budget_tokens ?? null,
6528
- t.budget_fallback_model ?? null,
6529
- t.tokens_used ?? 0,
6530
- t.tokens_warned_at ?? null
6552
+ sqlSafe(t.id),
6553
+ sqlSafe(t.title),
6554
+ sqlSafe(t.assigned_to),
6555
+ sqlSafe(t.assigned_by),
6556
+ sqlSafe(t.project_name),
6557
+ sqlSafe(t.priority ?? "p1"),
6558
+ sqlSafe(t.status ?? "open"),
6559
+ sqlSafe(t.task_file),
6560
+ sqlSafe(t.created_at),
6561
+ sqlSafe(t.updated_at),
6562
+ sqlSafe(t.blocked_by),
6563
+ sqlSafe(t.parent_task_id),
6564
+ sqlSafe(t.budget_tokens),
6565
+ sqlSafe(t.budget_fallback_model),
6566
+ sqlSafe(t.tokens_used ?? 0),
6567
+ sqlSafe(t.tokens_warned_at)
6531
6568
  ]
6532
6569
  }));
6533
6570
  await client.batch(stmts, "write");
@@ -6559,24 +6596,24 @@ async function cloudPullConversations(config) {
6559
6596
  content_metadata, agent_response, agent_name, timestamp, ingested_at)
6560
6597
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
6561
6598
  args: [
6562
- c.id ?? null,
6563
- c.platform ?? null,
6564
- c.external_id ?? null,
6565
- c.sender_id ?? null,
6566
- c.sender_name ?? null,
6567
- c.sender_phone ?? null,
6568
- c.sender_email ?? null,
6569
- c.recipient_id ?? null,
6570
- c.channel_id ?? null,
6571
- c.thread_id ?? null,
6572
- c.reply_to_id ?? null,
6573
- c.content_text ?? null,
6574
- c.content_media ?? null,
6575
- c.content_metadata ?? null,
6576
- c.agent_response ?? null,
6577
- c.agent_name ?? null,
6578
- c.timestamp ?? null,
6579
- c.ingested_at ?? null
6599
+ sqlSafe(c.id),
6600
+ sqlSafe(c.platform),
6601
+ sqlSafe(c.external_id),
6602
+ sqlSafe(c.sender_id),
6603
+ sqlSafe(c.sender_name),
6604
+ sqlSafe(c.sender_phone),
6605
+ sqlSafe(c.sender_email),
6606
+ sqlSafe(c.recipient_id),
6607
+ sqlSafe(c.channel_id),
6608
+ sqlSafe(c.thread_id),
6609
+ sqlSafe(c.reply_to_id),
6610
+ sqlSafe(c.content_text),
6611
+ sqlSafe(c.content_media),
6612
+ sqlSafe(c.content_metadata),
6613
+ sqlSafe(c.agent_response),
6614
+ sqlSafe(c.agent_name),
6615
+ sqlSafe(c.timestamp),
6616
+ sqlSafe(c.ingested_at)
6580
6617
  ]
6581
6618
  }));
6582
6619
  await client.batch(stmts, "write");
@@ -6613,7 +6650,7 @@ async function cloudPullDocuments(config) {
6613
6650
  const stmts = blob.workspaces.map((w) => ({
6614
6651
  sql: `INSERT OR IGNORE INTO workspaces (id, slug, name, owner_agent_id, created_at, metadata)
6615
6652
  VALUES (?, ?, ?, ?, ?, ?)`,
6616
- args: [w.id, w.slug, w.name, w.owner_agent_id ?? null, w.created_at, w.metadata ?? null]
6653
+ args: [sqlSafe(w.id), sqlSafe(w.slug), sqlSafe(w.name), sqlSafe(w.owner_agent_id), sqlSafe(w.created_at), sqlSafe(w.metadata)]
6617
6654
  }));
6618
6655
  await client.batch(stmts, "write");
6619
6656
  pulled += stmts.length;
@@ -6624,14 +6661,14 @@ async function cloudPullDocuments(config) {
6624
6661
  (id, workspace_id, filename, mime, source_type, user_id, uploaded_at, metadata)
6625
6662
  VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
6626
6663
  args: [
6627
- d.id,
6628
- d.workspace_id,
6629
- d.filename,
6630
- d.mime ?? null,
6631
- d.source_type ?? null,
6632
- d.user_id ?? null,
6633
- d.uploaded_at,
6634
- d.metadata ?? null
6664
+ sqlSafe(d.id),
6665
+ sqlSafe(d.workspace_id),
6666
+ sqlSafe(d.filename),
6667
+ sqlSafe(d.mime),
6668
+ sqlSafe(d.source_type),
6669
+ sqlSafe(d.user_id),
6670
+ sqlSafe(d.uploaded_at),
6671
+ sqlSafe(d.metadata)
6635
6672
  ]
6636
6673
  }));
6637
6674
  await client.batch(stmts, "write");