@askexenow/exe-os 0.8.37 → 0.8.38

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 (66) hide show
  1. package/dist/bin/backfill-conversations.js +66 -60
  2. package/dist/bin/backfill-responses.js +7 -8
  3. package/dist/bin/backfill-vectors.js +1 -8
  4. package/dist/bin/cleanup-stale-review-tasks.js +1 -8
  5. package/dist/bin/cli.js +520 -325
  6. package/dist/bin/exe-assign.js +7 -8
  7. package/dist/bin/exe-boot.js +54 -21
  8. package/dist/bin/exe-call.js +9 -4
  9. package/dist/bin/exe-cloud.js +37 -3
  10. package/dist/bin/exe-doctor.js +1 -8
  11. package/dist/bin/exe-export-behaviors.js +4 -11
  12. package/dist/bin/exe-forget.js +1 -8
  13. package/dist/bin/exe-gateway.js +72 -30
  14. package/dist/bin/exe-heartbeat.js +4 -11
  15. package/dist/bin/exe-kill.js +1 -8
  16. package/dist/bin/exe-launch-agent.js +51 -14
  17. package/dist/bin/exe-link.js +13 -3
  18. package/dist/bin/exe-new-employee.js +35 -10
  19. package/dist/bin/exe-pending-messages.js +1 -8
  20. package/dist/bin/exe-pending-notifications.js +1 -8
  21. package/dist/bin/exe-pending-reviews.js +4 -11
  22. package/dist/bin/exe-review.js +7 -8
  23. package/dist/bin/exe-search.js +10 -11
  24. package/dist/bin/exe-session-cleanup.js +11 -12
  25. package/dist/bin/exe-status.js +1 -8
  26. package/dist/bin/exe-team.js +1 -8
  27. package/dist/bin/git-sweep.js +7 -8
  28. package/dist/bin/graph-backfill.js +1 -8
  29. package/dist/bin/graph-export.js +1 -8
  30. package/dist/bin/install.js +9 -0
  31. package/dist/bin/scan-tasks.js +7 -8
  32. package/dist/bin/setup.js +396 -245
  33. package/dist/bin/shard-migrate.js +1 -8
  34. package/dist/bin/wiki-sync.js +1 -8
  35. package/dist/gateway/index.js +30 -30
  36. package/dist/hooks/bug-report-worker.js +4 -11
  37. package/dist/hooks/commit-complete.js +7 -8
  38. package/dist/hooks/error-recall.js +11 -12
  39. package/dist/hooks/ingest-worker.js +24 -9
  40. package/dist/hooks/instructions-loaded.js +7 -8
  41. package/dist/hooks/notification.js +7 -8
  42. package/dist/hooks/post-compact.js +7 -8
  43. package/dist/hooks/pre-compact.js +7 -8
  44. package/dist/hooks/pre-tool-use.js +7 -8
  45. package/dist/hooks/prompt-ingest-worker.js +19 -4
  46. package/dist/hooks/prompt-submit.js +14 -9
  47. package/dist/hooks/response-ingest-worker.js +20 -5
  48. package/dist/hooks/session-end.js +11 -12
  49. package/dist/hooks/session-start.js +11 -12
  50. package/dist/hooks/stop.js +7 -8
  51. package/dist/hooks/subagent-stop.js +7 -8
  52. package/dist/hooks/summary-worker.js +24 -9
  53. package/dist/index.js +11 -5
  54. package/dist/lib/cloud-sync.js +19 -2
  55. package/dist/lib/employee-templates.js +5 -0
  56. package/dist/lib/exe-daemon.js +24 -8
  57. package/dist/lib/hybrid-search.js +10 -11
  58. package/dist/lib/identity-templates.js +16 -7
  59. package/dist/lib/license.js +43 -2
  60. package/dist/lib/schedules.js +1 -8
  61. package/dist/lib/store.js +7 -8
  62. package/dist/mcp/server.js +184 -113
  63. package/dist/mcp/tools/list-tasks.js +35 -27
  64. package/dist/runtime/index.js +7 -2
  65. package/dist/tui/App.js +44 -5
  66. package/package.json +4 -2
@@ -1642,7 +1642,7 @@ __export(shard_manager_exports, {
1642
1642
  shardExists: () => shardExists
1643
1643
  });
1644
1644
  import path4 from "path";
1645
- import { existsSync as existsSync4, mkdirSync } from "fs";
1645
+ import { existsSync as existsSync4, mkdirSync, readdirSync } from "fs";
1646
1646
  import { createClient as createClient2 } from "@libsql/client";
1647
1647
  function initShardManager(encryptionKey) {
1648
1648
  _encryptionKey = encryptionKey;
@@ -1681,8 +1681,7 @@ function shardExists(projectName) {
1681
1681
  }
1682
1682
  function listShards() {
1683
1683
  if (!existsSync4(SHARDS_DIR)) return [];
1684
- const { readdirSync: readdirSync8 } = __require("fs");
1685
- return readdirSync8(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
1684
+ return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
1686
1685
  }
1687
1686
  async function ensureShardSchema(client) {
1688
1687
  await client.execute("PRAGMA journal_mode = WAL");
@@ -1965,6 +1964,12 @@ async function writeMemory(record) {
1965
1964
  supersedes_id: record.supersedes_id ?? null
1966
1965
  };
1967
1966
  _pendingRecords.push(dbRow);
1967
+ const MAX_PENDING = 1e3;
1968
+ if (_pendingRecords.length > MAX_PENDING) {
1969
+ const dropped = _pendingRecords.length - MAX_PENDING;
1970
+ _pendingRecords = _pendingRecords.slice(-MAX_PENDING);
1971
+ console.warn(`[store] Dropped ${dropped} oldest pending records (overflow)`);
1972
+ }
1968
1973
  if (_flushTimer === null) {
1969
1974
  _flushTimer = setInterval(() => {
1970
1975
  void flushBatch();
@@ -2459,7 +2464,7 @@ __export(file_grep_exports, {
2459
2464
  grepProjectFiles: () => grepProjectFiles
2460
2465
  });
2461
2466
  import { execSync as execSync2 } from "child_process";
2462
- import { readFileSync as readFileSync3, readdirSync, statSync as statSync2, existsSync as existsSync5 } from "fs";
2467
+ import { readFileSync as readFileSync3, readdirSync as readdirSync2, statSync as statSync2, existsSync as existsSync5 } from "fs";
2463
2468
  import path6 from "path";
2464
2469
  import crypto2 from "crypto";
2465
2470
  function hasRipgrep() {
@@ -2604,7 +2609,7 @@ function collectFiles(root, patterns) {
2604
2609
  const basename = path6.basename(dir);
2605
2610
  if (EXCLUDE_DIRS.includes(basename)) return;
2606
2611
  try {
2607
- const entries = readdirSync(dir, { withFileTypes: true });
2612
+ const entries = readdirSync2(dir, { withFileTypes: true });
2608
2613
  for (const entry of entries) {
2609
2614
  if (files.length >= MAX_FILES) return;
2610
2615
  const rel = path6.join(relative, entry.name);
@@ -2836,7 +2841,7 @@ __export(active_agent_exports, {
2836
2841
  getAllActiveAgents: () => getAllActiveAgents,
2837
2842
  writeActiveAgent: () => writeActiveAgent
2838
2843
  });
2839
- import { readFileSync as readFileSync4, writeFileSync, mkdirSync as mkdirSync2, unlinkSync as unlinkSync2, readdirSync as readdirSync2 } from "fs";
2844
+ import { readFileSync as readFileSync4, writeFileSync, mkdirSync as mkdirSync2, unlinkSync as unlinkSync2, readdirSync as readdirSync3 } from "fs";
2840
2845
  import { execSync as execSync4 } from "child_process";
2841
2846
  import path8 from "path";
2842
2847
  function getMarkerPath() {
@@ -2907,7 +2912,7 @@ function getActiveAgent() {
2907
2912
  }
2908
2913
  function getAllActiveAgents() {
2909
2914
  try {
2910
- const files = readdirSync2(CACHE_DIR);
2915
+ const files = readdirSync3(CACHE_DIR);
2911
2916
  const sessions = [];
2912
2917
  for (const file of files) {
2913
2918
  if (!file.startsWith("active-agent-") || !file.endsWith(".json")) continue;
@@ -3108,6 +3113,8 @@ __export(license_exports, {
3108
3113
  loadLicense: () => loadLicense,
3109
3114
  mirrorLicenseKey: () => mirrorLicenseKey,
3110
3115
  saveLicense: () => saveLicense,
3116
+ startLicenseRevalidation: () => startLicenseRevalidation,
3117
+ stopLicenseRevalidation: () => stopLicenseRevalidation,
3111
3118
  validateLicense: () => validateLicense
3112
3119
  });
3113
3120
  import { readFileSync as readFileSync6, writeFileSync as writeFileSync2, existsSync as existsSync8, mkdirSync as mkdirSync3 } from "fs";
@@ -3232,14 +3239,23 @@ async function validateLicense(apiKey, deviceId) {
3232
3239
  } catch {
3233
3240
  const cached = await getCachedLicense();
3234
3241
  if (cached) return cached;
3235
- return FREE_LICENSE;
3242
+ return { ...FREE_LICENSE, valid: false, error: "offline" };
3243
+ }
3244
+ }
3245
+ function getCacheAgeMs() {
3246
+ try {
3247
+ const { statSync: statSync4 } = __require("fs");
3248
+ const s = statSync4(CACHE_PATH);
3249
+ return Date.now() - s.mtimeMs;
3250
+ } catch {
3251
+ return Infinity;
3236
3252
  }
3237
3253
  }
3238
3254
  async function checkLicense() {
3239
3255
  const key = loadLicense();
3240
3256
  if (!key) return FREE_LICENSE;
3241
3257
  const cached = await getCachedLicense();
3242
- if (cached) return cached;
3258
+ if (cached && getCacheAgeMs() < CACHE_MAX_AGE_MS) return cached;
3243
3259
  const deviceId = loadDeviceId();
3244
3260
  return validateLicense(key, deviceId);
3245
3261
  }
@@ -3360,7 +3376,28 @@ async function assertVpsLicense(opts) {
3360
3376
  `License validation unreachable for more than ${graceDays} days. Restore network connectivity to https://askexe.com/cloud and retry. This VPS image refuses to boot after the offline grace window.`
3361
3377
  );
3362
3378
  }
3363
- var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, API_BASE, LICENSE_PUBLIC_KEY_PEM, LICENSE_JWT_ALG, PLAN_LIMITS, FREE_LICENSE;
3379
+ function startLicenseRevalidation(intervalMs = 36e5) {
3380
+ if (_revalTimer) return;
3381
+ _revalTimer = setInterval(async () => {
3382
+ try {
3383
+ const license = await checkLicense();
3384
+ if (!license.valid) {
3385
+ process.stderr.write("[exe-os] License expired or invalid \u2014 features may be restricted\n");
3386
+ }
3387
+ } catch {
3388
+ }
3389
+ }, intervalMs);
3390
+ if (_revalTimer && typeof _revalTimer === "object" && "unref" in _revalTimer) {
3391
+ _revalTimer.unref();
3392
+ }
3393
+ }
3394
+ function stopLicenseRevalidation() {
3395
+ if (_revalTimer) {
3396
+ clearInterval(_revalTimer);
3397
+ _revalTimer = null;
3398
+ }
3399
+ }
3400
+ var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, API_BASE, LICENSE_PUBLIC_KEY_PEM, LICENSE_JWT_ALG, PLAN_LIMITS, FREE_LICENSE, CACHE_MAX_AGE_MS, _revalTimer;
3364
3401
  var init_license = __esm({
3365
3402
  "src/lib/license.ts"() {
3366
3403
  "use strict";
@@ -3390,6 +3427,8 @@ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
3390
3427
  employeeLimit: 1,
3391
3428
  memoryLimit: 5e3
3392
3429
  };
3430
+ CACHE_MAX_AGE_MS = 36e5;
3431
+ _revalTimer = null;
3393
3432
  }
3394
3433
  });
3395
3434
 
@@ -3524,7 +3563,7 @@ import path14 from "path";
3524
3563
  import os2 from "os";
3525
3564
  import {
3526
3565
  readFileSync as readFileSync8,
3527
- readdirSync as readdirSync3,
3566
+ readdirSync as readdirSync4,
3528
3567
  unlinkSync as unlinkSync3,
3529
3568
  existsSync as existsSync10,
3530
3569
  rmdirSync
@@ -4776,7 +4815,7 @@ var init_tmux_routing = __esm({
4776
4815
 
4777
4816
  // src/lib/tasks-review.ts
4778
4817
  import path19 from "path";
4779
- import { existsSync as existsSync15, readdirSync as readdirSync4, unlinkSync as unlinkSync5 } from "fs";
4818
+ import { existsSync as existsSync15, readdirSync as readdirSync5, unlinkSync as unlinkSync5 } from "fs";
4780
4819
  async function countPendingReviews() {
4781
4820
  const client = getClient();
4782
4821
  const result = await client.execute({
@@ -4898,7 +4937,7 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
4898
4937
  try {
4899
4938
  const cacheDir = path19.join(EXE_AI_DIR, "session-cache");
4900
4939
  if (existsSync15(cacheDir)) {
4901
- for (const f of readdirSync4(cacheDir)) {
4940
+ for (const f of readdirSync5(cacheDir)) {
4902
4941
  if (f.startsWith("review-notified-")) {
4903
4942
  unlinkSync5(path19.join(cacheDir, f));
4904
4943
  }
@@ -6681,50 +6720,59 @@ function registerRecallMyMemory(server2) {
6681
6720
  user_id,
6682
6721
  include_source
6683
6722
  }) => {
6684
- const { agentId } = getActiveAgent();
6685
- const searchOptions = {
6686
- projectName: project_name,
6687
- hasError: has_error,
6688
- toolName: tool_name,
6689
- limit,
6690
- since,
6691
- includeArchived: include_archived,
6692
- workspaceId: workspace_id,
6693
- includeSource: include_source,
6694
- ...user_id !== void 0 ? { userId: user_id } : {}
6695
- };
6696
- const results = await hybridSearch(query, agentId, searchOptions);
6697
- if (results.length === 0) {
6723
+ try {
6724
+ const { agentId } = getActiveAgent();
6725
+ const searchOptions = {
6726
+ projectName: project_name,
6727
+ hasError: has_error,
6728
+ toolName: tool_name,
6729
+ limit,
6730
+ since,
6731
+ includeArchived: include_archived,
6732
+ workspaceId: workspace_id,
6733
+ includeSource: include_source,
6734
+ ...user_id !== void 0 ? { userId: user_id } : {}
6735
+ };
6736
+ const results = await hybridSearch(query, agentId, searchOptions);
6737
+ if (results.length === 0) {
6738
+ return {
6739
+ content: [
6740
+ { type: "text", text: "No matching memories found." }
6741
+ ]
6742
+ };
6743
+ }
6744
+ const formatted = results.map((r) => {
6745
+ const header = `[${r.timestamp}] ${r.tool_name} (${r.project_name})${r.has_error ? " [ERROR]" : ""}`;
6746
+ const body = r.raw_text.slice(0, 500);
6747
+ const parts = [header];
6748
+ if (r.source_path) {
6749
+ const typeTag = r.source_type && r.source_type !== "text" ? ` [${r.source_type}]` : "";
6750
+ parts.push(`source: ${r.source_path}${typeTag}`);
6751
+ } else if (include_source) {
6752
+ const sourceLine = formatSourceLine(r);
6753
+ if (sourceLine) parts.push(sourceLine);
6754
+ }
6755
+ parts.push(body);
6756
+ return parts.join("\n");
6757
+ }).join("\n\n---\n\n");
6698
6758
  return {
6699
6759
  content: [
6700
- { type: "text", text: "No matching memories found." }
6760
+ {
6761
+ type: "text",
6762
+ text: `Found ${results.length} memories:
6763
+
6764
+ ${formatted}`
6765
+ }
6701
6766
  ]
6702
6767
  };
6768
+ } catch (err) {
6769
+ const msg = err instanceof Error ? err.message : String(err);
6770
+ const friendly = msg.includes("SQLITE_BUSY") ? "Memory system is busy \u2014 please retry." : "Failed to search memories. Please retry.";
6771
+ return {
6772
+ content: [{ type: "text", text: friendly }],
6773
+ isError: true
6774
+ };
6703
6775
  }
6704
- const formatted = results.map((r) => {
6705
- const header = `[${r.timestamp}] ${r.tool_name} (${r.project_name})${r.has_error ? " [ERROR]" : ""}`;
6706
- const body = r.raw_text.slice(0, 500);
6707
- const parts = [header];
6708
- if (r.source_path) {
6709
- const typeTag = r.source_type && r.source_type !== "text" ? ` [${r.source_type}]` : "";
6710
- parts.push(`source: ${r.source_path}${typeTag}`);
6711
- } else if (include_source) {
6712
- const sourceLine = formatSourceLine(r);
6713
- if (sourceLine) parts.push(sourceLine);
6714
- }
6715
- parts.push(body);
6716
- return parts.join("\n");
6717
- }).join("\n\n---\n\n");
6718
- return {
6719
- content: [
6720
- {
6721
- type: "text",
6722
- text: `Found ${results.length} memories:
6723
-
6724
- ${formatted}`
6725
- }
6726
- ]
6727
- };
6728
6776
  }
6729
6777
  );
6730
6778
  }
@@ -6751,36 +6799,45 @@ function registerAskTeamMemory(server2) {
6751
6799
  }
6752
6800
  },
6753
6801
  async ({ team_member, query, project_name, limit, since, include_archived }) => {
6754
- const results = await hybridSearch(query, team_member, {
6755
- projectName: project_name,
6756
- limit,
6757
- since,
6758
- includeArchived: include_archived
6759
- });
6760
- if (results.length === 0) {
6802
+ try {
6803
+ const results = await hybridSearch(query, team_member, {
6804
+ projectName: project_name,
6805
+ limit,
6806
+ since,
6807
+ includeArchived: include_archived
6808
+ });
6809
+ if (results.length === 0) {
6810
+ return {
6811
+ content: [
6812
+ {
6813
+ type: "text",
6814
+ text: `No memories found for team member '${team_member}'.`
6815
+ }
6816
+ ]
6817
+ };
6818
+ }
6819
+ const formatted = results.map(
6820
+ (r) => `[${r.timestamp}] ${r.tool_name} (${r.project_name})${r.has_error ? " [ERROR]" : ""}
6821
+ ${r.raw_text.slice(0, 500)}`
6822
+ ).join("\n\n---\n\n");
6761
6823
  return {
6762
6824
  content: [
6763
6825
  {
6764
6826
  type: "text",
6765
- text: `No memories found for team member '${team_member}'.`
6827
+ text: `From ${team_member}'s memories (${results.length} results):
6828
+
6829
+ ${formatted}`
6766
6830
  }
6767
6831
  ]
6768
6832
  };
6833
+ } catch (err) {
6834
+ const msg = err instanceof Error ? err.message : String(err);
6835
+ const friendly = msg.includes("SQLITE_BUSY") ? "Memory system is busy \u2014 please retry." : "Failed to search team memories. Please retry.";
6836
+ return {
6837
+ content: [{ type: "text", text: friendly }],
6838
+ isError: true
6839
+ };
6769
6840
  }
6770
- const formatted = results.map(
6771
- (r) => `[${r.timestamp}] ${r.tool_name} (${r.project_name})${r.has_error ? " [ERROR]" : ""}
6772
- ${r.raw_text.slice(0, 500)}`
6773
- ).join("\n\n---\n\n");
6774
- return {
6775
- content: [
6776
- {
6777
- type: "text",
6778
- text: `From ${team_member}'s memories (${results.length} results):
6779
-
6780
- ${formatted}`
6781
- }
6782
- ]
6783
- };
6784
6841
  }
6785
6842
  );
6786
6843
  }
@@ -7428,36 +7485,44 @@ function registerListTasks(server2) {
7428
7485
  }
7429
7486
  },
7430
7487
  async ({ assigned_to, status, project_name, priority }) => {
7431
- const resolvedProject = project_name === "all" ? void 0 : project_name ?? getProjectName();
7432
- const tasks = await listTasks({
7433
- assignedTo: assigned_to,
7434
- status,
7435
- projectName: resolvedProject,
7436
- priority
7437
- });
7438
- if (tasks.length === 0) {
7488
+ try {
7489
+ const resolvedProject = project_name === "all" ? void 0 : project_name ?? getProjectName();
7490
+ const tasks = await listTasks({
7491
+ assignedTo: assigned_to,
7492
+ status,
7493
+ projectName: resolvedProject,
7494
+ priority
7495
+ });
7496
+ if (tasks.length === 0) {
7497
+ return {
7498
+ content: [{ type: "text", text: "No tasks found." }]
7499
+ };
7500
+ }
7501
+ const lines = tasks.map((t) => {
7502
+ const cpIndicator = t.checkpointCount && t.checkpointCount > 0 ? ` [cp:${t.checkpointCount}]` : "";
7503
+ let budgetNote = "";
7504
+ if (t.budgetTokens !== null) {
7505
+ const pct = Math.round(t.tokensUsed / t.budgetTokens * 100);
7506
+ budgetNote = ` [${t.tokensUsed}/${t.budgetTokens} tokens, ${pct}%]`;
7507
+ }
7508
+ return `- [${t.priority.toUpperCase()}] ${t.title} (${t.projectName}) \u2014 ${t.status}${cpIndicator}${budgetNote} \u2192 ${t.assignedTo}`;
7509
+ });
7510
+ return {
7511
+ content: [
7512
+ {
7513
+ type: "text",
7514
+ text: `${tasks.length} task(s):
7515
+ ${lines.join("\n")}`
7516
+ }
7517
+ ]
7518
+ };
7519
+ } catch (err) {
7520
+ const msg = err instanceof Error ? err.message : String(err);
7439
7521
  return {
7440
- content: [{ type: "text", text: "No tasks found." }]
7522
+ content: [{ type: "text", text: `Failed to list tasks: ${msg}` }],
7523
+ isError: true
7441
7524
  };
7442
7525
  }
7443
- const lines = tasks.map((t) => {
7444
- const cpIndicator = t.checkpointCount && t.checkpointCount > 0 ? ` [cp:${t.checkpointCount}]` : "";
7445
- let budgetNote = "";
7446
- if (t.budgetTokens !== null) {
7447
- const pct = Math.round(t.tokensUsed / t.budgetTokens * 100);
7448
- budgetNote = ` [${t.tokensUsed}/${t.budgetTokens} tokens, ${pct}%]`;
7449
- }
7450
- return `- [${t.priority.toUpperCase()}] ${t.title} (${t.projectName}) \u2014 ${t.status}${cpIndicator}${budgetNote} \u2192 ${t.assignedTo}`;
7451
- });
7452
- return {
7453
- content: [
7454
- {
7455
- type: "text",
7456
- text: `${tasks.length} task(s):
7457
- ${lines.join("\n")}`
7458
- }
7459
- ]
7460
- };
7461
7526
  }
7462
7527
  );
7463
7528
  }
@@ -8171,7 +8236,7 @@ import { z as z20 } from "zod";
8171
8236
  init_config();
8172
8237
  init_database();
8173
8238
  import { existsSync as existsSync16, mkdirSync as mkdirSync8, readFileSync as readFileSync13, writeFileSync as writeFileSync9 } from "fs";
8174
- import { readdirSync as readdirSync5 } from "fs";
8239
+ import { readdirSync as readdirSync6 } from "fs";
8175
8240
  import path22 from "path";
8176
8241
  import { createHash } from "crypto";
8177
8242
  var IDENTITY_DIR = path22.join(EXE_AI_DIR, "identity");
@@ -8254,7 +8319,7 @@ async function updateIdentity(agentId, content, updatedBy) {
8254
8319
  }
8255
8320
  function listIdentities() {
8256
8321
  ensureDir2();
8257
- const files = readdirSync5(IDENTITY_DIR).filter((f) => f.endsWith(".md"));
8322
+ const files = readdirSync6(IDENTITY_DIR).filter((f) => f.endsWith(".md"));
8258
8323
  const results = [];
8259
8324
  for (const file of files) {
8260
8325
  const agentId = file.replace(".md", "");
@@ -8725,10 +8790,12 @@ function registerIngestDocument(server2) {
8725
8790
  }]
8726
8791
  };
8727
8792
  } catch (err) {
8793
+ const raw = err instanceof Error ? err.message : String(err);
8794
+ const friendly = raw.includes("SQLITE_BUSY") ? "Memory system is busy, please retry in a moment." : raw.includes("SQLITE_") ? "A database error occurred. Please retry." : `ingest_document failed: ${raw}`;
8728
8795
  return {
8729
8796
  content: [{
8730
8797
  type: "text",
8731
- text: `ingest_document failed: ${err instanceof Error ? err.message : String(err)}`
8798
+ text: friendly
8732
8799
  }],
8733
8800
  isError: true
8734
8801
  };
@@ -9108,8 +9175,8 @@ async function sendWhatsAppMessage(phoneNumberId, accessToken, to, text) {
9108
9175
  })
9109
9176
  });
9110
9177
  if (!res.ok) {
9111
- const errBody = await res.text();
9112
- throw new Error(`WhatsApp send failed (${res.status}): ${errBody}`);
9178
+ await res.text();
9179
+ throw new Error(`WhatsApp message could not be delivered (HTTP ${res.status}). Check your WhatsApp configuration.`);
9113
9180
  }
9114
9181
  }
9115
9182
  function isPhoneNumber(value) {
@@ -9193,11 +9260,13 @@ function registerSendWhatsapp(server2) {
9193
9260
  });
9194
9261
  results.push({ recipient, phone, ok: true });
9195
9262
  } catch (err) {
9263
+ const raw = err instanceof Error ? err.message : String(err);
9264
+ const friendly = raw.includes("HTTP") ? raw : `Message delivery failed. Check WhatsApp configuration.`;
9196
9265
  results.push({
9197
9266
  recipient,
9198
9267
  phone,
9199
9268
  ok: false,
9200
- error: err instanceof Error ? err.message : String(err)
9269
+ error: friendly
9201
9270
  });
9202
9271
  }
9203
9272
  }
@@ -9522,14 +9591,14 @@ function registerListTriggers(server2) {
9522
9591
  import { z as z31 } from "zod";
9523
9592
 
9524
9593
  // src/automation/starter-packs/index.ts
9525
- import { readFileSync as readFileSync16, readdirSync as readdirSync6, existsSync as existsSync18 } from "fs";
9594
+ import { readFileSync as readFileSync16, readdirSync as readdirSync7, existsSync as existsSync18 } from "fs";
9526
9595
  import path24 from "path";
9527
9596
  import { fileURLToPath as fileURLToPath3 } from "url";
9528
9597
  var __dirname = path24.dirname(fileURLToPath3(import.meta.url));
9529
9598
  function listPacks() {
9530
9599
  const packsDir = path24.join(__dirname, ".");
9531
9600
  if (!existsSync18(packsDir)) return [];
9532
- return readdirSync6(packsDir, { withFileTypes: true }).filter(
9601
+ return readdirSync7(packsDir, { withFileTypes: true }).filter(
9533
9602
  (d) => d.isDirectory() && existsSync18(path24.join(packsDir, d.name, "custom-objects.json"))
9534
9603
  ).map((d) => d.name);
9535
9604
  }
@@ -9561,7 +9630,7 @@ function loadPack(industry) {
9561
9630
  }
9562
9631
  const wikiSeeds = [];
9563
9632
  if (existsSync18(wikiDir)) {
9564
- const files = readdirSync6(wikiDir).filter((f) => f.endsWith(".md"));
9633
+ const files = readdirSync7(wikiDir).filter((f) => f.endsWith(".md"));
9565
9634
  for (const file of files) {
9566
9635
  const content = readFileSync16(path24.join(wikiDir, file), "utf-8");
9567
9636
  const titleMatch = content.match(/^#\s+(.+)/m);
@@ -11047,11 +11116,13 @@ function registerQueryConversations(server2) {
11047
11116
  ]
11048
11117
  };
11049
11118
  } catch (err) {
11119
+ const raw = err instanceof Error ? err.message : String(err);
11120
+ const friendly = raw.includes("SQLITE_BUSY") ? "Memory system is busy, please retry in a moment." : raw.includes("SQLITE_") ? "A database error occurred. Please retry." : `Error querying conversations: ${raw}`;
11050
11121
  return {
11051
11122
  content: [
11052
11123
  {
11053
11124
  type: "text",
11054
- text: `Error querying conversations: ${err instanceof Error ? err.message : String(err)}`
11125
+ text: friendly
11055
11126
  }
11056
11127
  ],
11057
11128
  isError: true
@@ -11063,13 +11134,13 @@ function registerQueryConversations(server2) {
11063
11134
 
11064
11135
  // src/mcp/tools/load-skill.ts
11065
11136
  import { z as z39 } from "zod";
11066
- import { readFileSync as readFileSync17, readdirSync as readdirSync7, statSync as statSync3 } from "fs";
11137
+ import { readFileSync as readFileSync17, readdirSync as readdirSync8, statSync as statSync3 } from "fs";
11067
11138
  import path27 from "path";
11068
11139
  import { homedir as homedir2 } from "os";
11069
11140
  var SKILLS_DIR = path27.join(homedir2(), ".claude", "skills");
11070
11141
  function listAvailableSkills() {
11071
11142
  try {
11072
- const entries = readdirSync7(SKILLS_DIR);
11143
+ const entries = readdirSync8(SKILLS_DIR);
11073
11144
  return entries.filter((entry) => {
11074
11145
  try {
11075
11146
  const entryPath = path27.join(SKILLS_DIR, entry);
@@ -455,36 +455,44 @@ function registerListTasks(server) {
455
455
  }
456
456
  },
457
457
  async ({ assigned_to, status, project_name, priority }) => {
458
- const resolvedProject = project_name === "all" ? void 0 : project_name ?? getProjectName();
459
- const tasks = await listTasks({
460
- assignedTo: assigned_to,
461
- status,
462
- projectName: resolvedProject,
463
- priority
464
- });
465
- if (tasks.length === 0) {
458
+ try {
459
+ const resolvedProject = project_name === "all" ? void 0 : project_name ?? getProjectName();
460
+ const tasks = await listTasks({
461
+ assignedTo: assigned_to,
462
+ status,
463
+ projectName: resolvedProject,
464
+ priority
465
+ });
466
+ if (tasks.length === 0) {
467
+ return {
468
+ content: [{ type: "text", text: "No tasks found." }]
469
+ };
470
+ }
471
+ const lines = tasks.map((t) => {
472
+ const cpIndicator = t.checkpointCount && t.checkpointCount > 0 ? ` [cp:${t.checkpointCount}]` : "";
473
+ let budgetNote = "";
474
+ if (t.budgetTokens !== null) {
475
+ const pct = Math.round(t.tokensUsed / t.budgetTokens * 100);
476
+ budgetNote = ` [${t.tokensUsed}/${t.budgetTokens} tokens, ${pct}%]`;
477
+ }
478
+ return `- [${t.priority.toUpperCase()}] ${t.title} (${t.projectName}) \u2014 ${t.status}${cpIndicator}${budgetNote} \u2192 ${t.assignedTo}`;
479
+ });
480
+ return {
481
+ content: [
482
+ {
483
+ type: "text",
484
+ text: `${tasks.length} task(s):
485
+ ${lines.join("\n")}`
486
+ }
487
+ ]
488
+ };
489
+ } catch (err) {
490
+ const msg = err instanceof Error ? err.message : String(err);
466
491
  return {
467
- content: [{ type: "text", text: "No tasks found." }]
492
+ content: [{ type: "text", text: `Failed to list tasks: ${msg}` }],
493
+ isError: true
468
494
  };
469
495
  }
470
- const lines = tasks.map((t) => {
471
- const cpIndicator = t.checkpointCount && t.checkpointCount > 0 ? ` [cp:${t.checkpointCount}]` : "";
472
- let budgetNote = "";
473
- if (t.budgetTokens !== null) {
474
- const pct = Math.round(t.tokensUsed / t.budgetTokens * 100);
475
- budgetNote = ` [${t.tokensUsed}/${t.budgetTokens} tokens, ${pct}%]`;
476
- }
477
- return `- [${t.priority.toUpperCase()}] ${t.title} (${t.projectName}) \u2014 ${t.status}${cpIndicator}${budgetNote} \u2192 ${t.assignedTo}`;
478
- });
479
- return {
480
- content: [
481
- {
482
- type: "text",
483
- text: `${tasks.length} task(s):
484
- ${lines.join("\n")}`
485
- }
486
- ]
487
- };
488
496
  }
489
497
  );
490
498
  }
@@ -3966,7 +3966,7 @@ __export(shard_manager_exports, {
3966
3966
  shardExists: () => shardExists
3967
3967
  });
3968
3968
  import path16 from "path";
3969
- import { existsSync as existsSync12, mkdirSync as mkdirSync6 } from "fs";
3969
+ import { existsSync as existsSync12, mkdirSync as mkdirSync6, readdirSync as readdirSync3 } from "fs";
3970
3970
  import { createClient as createClient2 } from "@libsql/client";
3971
3971
  function initShardManager(encryptionKey) {
3972
3972
  _encryptionKey = encryptionKey;
@@ -4005,7 +4005,6 @@ function shardExists(projectName) {
4005
4005
  }
4006
4006
  function listShards() {
4007
4007
  if (!existsSync12(SHARDS_DIR)) return [];
4008
- const { readdirSync: readdirSync3 } = __require("fs");
4009
4008
  return readdirSync3(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
4010
4009
  }
4011
4010
  async function ensureShardSchema(client) {
@@ -4289,6 +4288,12 @@ async function writeMemory(record) {
4289
4288
  supersedes_id: record.supersedes_id ?? null
4290
4289
  };
4291
4290
  _pendingRecords.push(dbRow);
4291
+ const MAX_PENDING = 1e3;
4292
+ if (_pendingRecords.length > MAX_PENDING) {
4293
+ const dropped = _pendingRecords.length - MAX_PENDING;
4294
+ _pendingRecords = _pendingRecords.slice(-MAX_PENDING);
4295
+ console.warn(`[store] Dropped ${dropped} oldest pending records (overflow)`);
4296
+ }
4292
4297
  if (_flushTimer === null) {
4293
4298
  _flushTimer = setInterval(() => {
4294
4299
  void flushBatch();