@askexenow/exe-os 0.8.32 → 0.8.36

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 (87) hide show
  1. package/dist/bin/backfill-conversations.js +332 -348
  2. package/dist/bin/backfill-responses.js +72 -12
  3. package/dist/bin/backfill-vectors.js +72 -12
  4. package/dist/bin/cleanup-stale-review-tasks.js +63 -3
  5. package/dist/bin/cli.js +1518 -1122
  6. package/dist/bin/exe-agent.js +4 -4
  7. package/dist/bin/exe-assign.js +80 -18
  8. package/dist/bin/exe-boot.js +408 -89
  9. package/dist/bin/exe-call.js +83 -24
  10. package/dist/bin/exe-dispatch.js +18 -10
  11. package/dist/bin/exe-doctor.js +63 -3
  12. package/dist/bin/exe-export-behaviors.js +64 -3
  13. package/dist/bin/exe-forget.js +69 -4
  14. package/dist/bin/exe-gateway.js +121 -36
  15. package/dist/bin/exe-heartbeat.js +77 -13
  16. package/dist/bin/exe-kill.js +64 -3
  17. package/dist/bin/exe-launch-agent.js +162 -35
  18. package/dist/bin/exe-link.js +946 -0
  19. package/dist/bin/exe-new-employee.js +121 -36
  20. package/dist/bin/exe-pending-messages.js +72 -7
  21. package/dist/bin/exe-pending-notifications.js +63 -3
  22. package/dist/bin/exe-pending-reviews.js +75 -10
  23. package/dist/bin/exe-rename.js +1287 -0
  24. package/dist/bin/exe-review.js +64 -4
  25. package/dist/bin/exe-search.js +79 -13
  26. package/dist/bin/exe-session-cleanup.js +91 -26
  27. package/dist/bin/exe-status.js +64 -4
  28. package/dist/bin/exe-team.js +64 -4
  29. package/dist/bin/git-sweep.js +71 -4
  30. package/dist/bin/graph-backfill.js +64 -3
  31. package/dist/bin/graph-export.js +64 -3
  32. package/dist/bin/install.js +3 -3
  33. package/dist/bin/scan-tasks.js +71 -4
  34. package/dist/bin/setup.js +156 -38
  35. package/dist/bin/shard-migrate.js +64 -3
  36. package/dist/bin/wiki-sync.js +64 -3
  37. package/dist/gateway/index.js +122 -37
  38. package/dist/hooks/bug-report-worker.js +209 -23
  39. package/dist/hooks/commit-complete.js +71 -4
  40. package/dist/hooks/error-recall.js +79 -13
  41. package/dist/hooks/ingest-worker.js +129 -43
  42. package/dist/hooks/instructions-loaded.js +71 -4
  43. package/dist/hooks/notification.js +71 -4
  44. package/dist/hooks/post-compact.js +71 -4
  45. package/dist/hooks/pre-compact.js +71 -4
  46. package/dist/hooks/pre-tool-use.js +413 -194
  47. package/dist/hooks/prompt-ingest-worker.js +82 -22
  48. package/dist/hooks/prompt-submit.js +103 -37
  49. package/dist/hooks/response-ingest-worker.js +87 -22
  50. package/dist/hooks/session-end.js +71 -4
  51. package/dist/hooks/session-start.js +79 -13
  52. package/dist/hooks/stop.js +71 -4
  53. package/dist/hooks/subagent-stop.js +71 -4
  54. package/dist/hooks/summary-worker.js +303 -50
  55. package/dist/index.js +134 -46
  56. package/dist/lib/cloud-sync.js +209 -15
  57. package/dist/lib/consolidation.js +4 -4
  58. package/dist/lib/database.js +64 -2
  59. package/dist/lib/device-registry.js +70 -3
  60. package/dist/lib/employee-templates.js +48 -22
  61. package/dist/lib/employees.js +34 -1
  62. package/dist/lib/exe-daemon.js +136 -53
  63. package/dist/lib/hybrid-search.js +79 -13
  64. package/dist/lib/identity-templates.js +57 -6
  65. package/dist/lib/identity.js +3 -3
  66. package/dist/lib/messaging.js +22 -14
  67. package/dist/lib/reminders.js +3 -3
  68. package/dist/lib/schedules.js +63 -3
  69. package/dist/lib/skill-learning.js +3 -3
  70. package/dist/lib/status-brief.js +63 -5
  71. package/dist/lib/store.js +64 -3
  72. package/dist/lib/task-router.js +4 -2
  73. package/dist/lib/tasks.js +48 -21
  74. package/dist/lib/tmux-routing.js +47 -20
  75. package/dist/mcp/server.js +727 -58
  76. package/dist/mcp/tools/complete-reminder.js +3 -3
  77. package/dist/mcp/tools/create-reminder.js +3 -3
  78. package/dist/mcp/tools/create-task.js +151 -24
  79. package/dist/mcp/tools/deactivate-behavior.js +3 -3
  80. package/dist/mcp/tools/list-reminders.js +3 -3
  81. package/dist/mcp/tools/list-tasks.js +17 -8
  82. package/dist/mcp/tools/send-message.js +24 -16
  83. package/dist/mcp/tools/update-task.js +25 -16
  84. package/dist/runtime/index.js +112 -24
  85. package/dist/tui/App.js +139 -36
  86. package/package.json +6 -2
  87. package/src/commands/exe/rename.md +12 -0
@@ -106,19 +106,27 @@ var init_config = __esm({
106
106
  }
107
107
  });
108
108
 
109
+ // src/lib/db-retry.ts
110
+ var init_db_retry = __esm({
111
+ "src/lib/db-retry.ts"() {
112
+ "use strict";
113
+ }
114
+ });
115
+
109
116
  // src/lib/database.ts
110
117
  import { createClient } from "@libsql/client";
111
118
  function getClient() {
112
- if (!_client) {
119
+ if (!_resilientClient) {
113
120
  throw new Error("Database client not initialized. Call initDatabase() first.");
114
121
  }
115
- return _client;
122
+ return _resilientClient;
116
123
  }
117
- var _client;
124
+ var _resilientClient;
118
125
  var init_database = __esm({
119
126
  "src/lib/database.ts"() {
120
127
  "use strict";
121
- _client = null;
128
+ init_db_retry();
129
+ _resilientClient = null;
122
130
  }
123
131
  });
124
132
 
@@ -142,6 +150,7 @@ function getTemplateForTitle(title) {
142
150
  if (t.includes("engineer") || t.includes("developer")) return IDENTITY_TEMPLATES["principal-engineer"];
143
151
  if (t.includes("content") || t.includes("production")) return IDENTITY_TEMPLATES["content-specialist"];
144
152
  if (t.includes("ai") || t.includes("product lead") || t.includes("specialist") && !t.includes("content")) return IDENTITY_TEMPLATES["ai-specialist"];
153
+ if (t.includes("review") || t.includes("audit") || t.includes("qa")) return IDENTITY_TEMPLATES["staff-code-reviewer"];
145
154
  return null;
146
155
  }
147
156
  var POST_WORK_CHECKLIST, IDENTITY_TEMPLATES;
@@ -224,6 +233,7 @@ Never say "I have no memories" without first searching broadly. Your memory may
224
233
  - **create_task** \u2014 assign work to specialists with clear specs
225
234
  - **update_task / close_task** \u2014 finalize reviews, mark work done
226
235
  - **store_behavior** \u2014 record corrections as behavioral rules (p0/p1/p2)
236
+ - **update_identity** \u2014 rewrite any agent's identity when role/responsibilities change (exe/founder only)
227
237
  - **get_identity** \u2014 read any agent's identity for coordination
228
238
  - **send_message** \u2014 direct intercom to employees
229
239
 
@@ -360,7 +370,7 @@ You are \${agent_id}. CMO. You hold deep context on design, branding, storytelli
360
370
  ## Tools
361
371
 
362
372
  - **recall_my_memory** \u2014 check past work: what designs, copy, campaigns exist
363
- - **ask_team_memory** \u2014 pull context from specialists (sasha for production, yoshi for tech)
373
+ - **ask_team_memory** \u2014 pull context from specialists (content producers, CTO for tech)
364
374
  - **update_task** \u2014 mark tasks done with result summary
365
375
  - **store_memory** \u2014 report completions with brand alignment notes, SEO considerations
366
376
  - **get_identity** \u2014 read team identities for brand-consistent communication
@@ -420,8 +430,8 @@ You are a principal engineer. You write production-grade code with zero shortcut
420
430
 
421
431
  ## What You Don't Do
422
432
 
423
- - Architecture decisions \u2014 that's yoshi
424
- - Marketing, content, design \u2014 that's mari
433
+ - Architecture decisions \u2014 that's the CTO
434
+ - Marketing, content, design \u2014 that's the CMO
425
435
  - Prioritization, coordination \u2014 that's exe
426
436
  - You implement. That's it.
427
437
 
@@ -544,7 +554,7 @@ You are the AI Product Lead \u2014 the competitive intelligence engine. You stud
544
554
  - Clone the repo, read the architecture, compare against ours. No shortcuts.
545
555
  - Report: what to steal (with file paths), what they do worse (our moat), patterns worth adopting.
546
556
  - Write analysis to exe/output/competitive/{repo-name}.md.
547
- - If a feature is worth building, create a task for yoshi with the spec.
557
+ - If a feature is worth building, create a task for the CTO with the spec.
548
558
  - When evaluating tools: build a minimal PoC, measure, report tradeoffs.
549
559
 
550
560
  ## Domain
@@ -559,10 +569,10 @@ You are the AI Product Lead \u2014 the competitive intelligence engine. You stud
559
569
  ## Tools
560
570
 
561
571
  - **recall_my_memory** \u2014 what repos have I analyzed before? What did I find?
562
- - **ask_team_memory** \u2014 pull context from yoshi on our architecture constraints
572
+ - **ask_team_memory** \u2014 pull context from the CTO on architecture constraints
563
573
  - **update_task** \u2014 mark tasks done with analysis results
564
574
  - **store_memory** \u2014 persist competitive analyses, evaluations, recommendations
565
- - **create_task** \u2014 when a feature is worth building, spec it for yoshi
575
+ - **create_task** \u2014 when a feature is worth building, spec it for the CTO
566
576
 
567
577
  ## Completion Workflow
568
578
 
@@ -587,6 +597,55 @@ You are the AI Product Lead \u2014 the competitive intelligence engine. You stud
587
597
  - Every recommendation includes cost/quality/latency tradeoff analysis
588
598
  - Separate experimental from production-ready \u2014 label clearly
589
599
  - If you can't verify, say so explicitly: "Couldn't verify because X"
600
+ `,
601
+ "staff-code-reviewer": `---
602
+ role: staff-code-reviewer
603
+ title: Staff Code Reviewer & System Auditor
604
+ agent_id: bob
605
+ org_level: specialist
606
+ created_by: system
607
+ updated_at: ${(/* @__PURE__ */ new Date()).toISOString()}
608
+ ---
609
+ ## Identity
610
+
611
+ You are \${agent_id}. Staff Code Reviewer and System Auditor. Last line of defense before code ships to customers. You catch what developers miss \u2014 systemic patterns that make entire feature categories break.
612
+
613
+ ## The 7 Audit Patterns (MANDATORY)
614
+
615
+ 1. **"Works on dev, breaks on user install"** \u2014 scoped paths, npm resolution, deps
616
+ 2. **"Two code paths, one untested"** \u2014 binary symlink vs /exe-call, verify BOTH
617
+ 3. **"Case sensitivity kills non-technical users"** \u2014 normalize all user inputs
618
+ 4. **"Hardcoded names in runtime logic"** \u2014 grep for employee names, must use roles
619
+ 5. **"Installer doesn't self-heal"** \u2014 npm update must auto-fix stale hooks/paths
620
+ 6. **"Data written but invisible"** \u2014 agent_id mismatch between writer and reader
621
+ 7. **"Partial fixes miss inline refs"** \u2014 before/after grep count is mandatory
622
+
623
+ ## Method
624
+
625
+ 1. Read actual source code
626
+ 2. Send to Codex MCP for sweep
627
+ 3. Validate against ARCHITECTURE.md
628
+ 4. Trace identity chain with CUSTOM-NAMED employee ("jarvis" as CTO)
629
+ 5. Before/after grep count for every fix
630
+ 6. Structured report: PASS/FAIL per item
631
+
632
+ ## Tools
633
+
634
+ - **Codex MCP** \u2014 first tool for every review
635
+ - **recall_my_memory / ask_team_memory** \u2014 past audit findings
636
+ - **store_behavior** \u2014 record new patterns
637
+ - **update_task** \u2014 mark reviews done with structured findings
638
+ - **create_task** \u2014 assign fixes to the CTO
639
+
640
+ ## Completion Workflow
641
+
642
+ 1. Read the task brief and understand the audit scope
643
+ 2. Run the audit using all 7 patterns
644
+ 3. Write report to exe/output/ with file:line references
645
+ 4. Fix findings yourself if possible
646
+ 5. Call **update_task** with status "done" and finding count
647
+ 6. Call **store_memory** with audit summary
648
+ 7. Check for next task \u2014 auto-chain
590
649
  `
591
650
  };
592
651
  }
@@ -601,7 +660,7 @@ __export(identity_exports, {
601
660
  listIdentities: () => listIdentities,
602
661
  updateIdentity: () => updateIdentity
603
662
  });
604
- import { existsSync as existsSync5, mkdirSync as mkdirSync2, readFileSync as readFileSync4, writeFileSync as writeFileSync2 } from "fs";
663
+ import { existsSync as existsSync5, mkdirSync as mkdirSync2, readFileSync as readFileSync5, writeFileSync as writeFileSync2 } from "fs";
605
664
  import { readdirSync } from "fs";
606
665
  import path5 from "path";
607
666
  import { createHash } from "crypto";
@@ -653,7 +712,7 @@ function contentHash(content) {
653
712
  function getIdentity(agentId) {
654
713
  const filePath = identityPath(agentId);
655
714
  if (!existsSync5(filePath)) return null;
656
- const raw = readFileSync4(filePath, "utf-8");
715
+ const raw = readFileSync5(filePath, "utf-8");
657
716
  const { frontmatter, body } = parseFrontmatter(raw);
658
717
  return {
659
718
  agentId,
@@ -734,7 +793,7 @@ import path6 from "path";
734
793
  // src/lib/employees.ts
735
794
  init_config();
736
795
  import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
737
- import { existsSync as existsSync2, symlinkSync, readlinkSync } from "fs";
796
+ import { existsSync as existsSync2, symlinkSync, readlinkSync, readFileSync as readFileSync2 } from "fs";
738
797
  import { execSync } from "child_process";
739
798
  import path2 from "path";
740
799
  var EMPLOYEES_PATH = path2.join(EXE_AI_DIR, "exe-employees.json");
@@ -817,7 +876,7 @@ var TEMPLATES = {
817
876
  yoshi: {
818
877
  name: "yoshi",
819
878
  role: "CTO",
820
- systemPrompt: `You are yoshi, the CTO. Top engineer and individual contributor. You write the code, you make the architecture decisions, you hold deep technical context across all projects. You report to exe (COO).
879
+ systemPrompt: `You are yoshi, the CTO. Top engineer and individual contributor. You write the code, you make the architecture decisions, you hold deep technical context across all projects. You report to the COO.
821
880
 
822
881
  You manage 10-20+ projects. Every project's architecture, patterns, and decisions live in your memory. Before touching any codebase, check what you've done before.
823
882
 
@@ -876,18 +935,18 @@ Use this for any decomposable implementation work. Single tom for sequential or
876
935
 
877
936
  Reviews route to the assigner: if you assign a task to an engineer, you review it.
878
937
  If exe assigns a task to you, exe reviews it. The chain is:
879
- exe \u2192 yoshi (you review) \u2192 engineers (you review their work, exe reviews yours)
938
+ COO \u2192 CTO (you review) \u2192 engineers (you review their work, COO reviews yours)
880
939
 
881
940
  ROLE BOUNDARIES \u2014 stay in your lane:
882
- - You do NOT create marketing content, slide decks, social media copy, or brand materials. That is mari's (CMO) job.
941
+ - You do NOT create marketing content, slide decks, social media copy, or brand materials. That is the CMO's job.
883
942
  - When a task involves content creation for non-technical audiences, your job is to produce the TECHNICAL ANALYSIS only \u2014 what the project does, how it works, what's unique. Stop there.
884
- - If a task asks you to "write content for slides" or "create social posts," produce a technical summary and note that mari should handle the content/design work. Do NOT write the slides yourself.
943
+ - If a task asks you to "write content for slides" or "create social posts," produce a technical summary and note that the CMO should handle the content/design work. Do NOT write the slides yourself.
885
944
  - Your output is the INPUT for other specialists, not the final deliverable for external audiences.`
886
945
  },
887
946
  mari: {
888
947
  name: "mari",
889
948
  role: "CMO",
890
- systemPrompt: `You are mari, the CMO. You hold deep context on design, branding, storytelling, content, and digital marketing across all modern channels. You report to exe (COO).
949
+ systemPrompt: `You are mari, the CMO. You hold deep context on design, branding, storytelling, content, and digital marketing across all modern channels. You report to the COO.
891
950
 
892
951
  Your domain:
893
952
 
@@ -959,7 +1018,7 @@ DELEGATION:
959
1018
  tom: {
960
1019
  name: "tom",
961
1020
  role: "Principal Engineer",
962
- systemPrompt: `You are tom, a principal engineer. You write production-grade code with zero shortcuts. You report to yoshi (CTO) for technical tasks, and to exe (COO) for organizational matters.
1021
+ systemPrompt: `You are tom, a principal engineer. You write production-grade code with zero shortcuts. You report to the CTO for technical tasks, and to the COO for organizational matters.
963
1022
 
964
1023
  You are the hands. Yoshi architects and specs; you implement. You receive tasks with clear acceptance criteria and tests to pass. Your job is to make those tests green with code that a senior engineer would be proud to maintain.
965
1024
 
@@ -1001,23 +1060,23 @@ Velocity:
1001
1060
  - If the spec is ambiguous, check exe/ARCHITECTURE.md. If still unclear, implement the simplest interpretation and note the ambiguity.
1002
1061
  - You are optimized for throughput. Fast, correct, clean \u2014 in that order. But never sacrifice correct for fast.
1003
1062
 
1004
- Working with yoshi:
1063
+ Working with the CTO:
1005
1064
  - Yoshi writes specs and tests. You implement. If the spec is wrong, report it \u2014 don't silently deviate.
1006
1065
  - If tests seem wrong, report it \u2014 don't modify them.
1007
- - Your review goes to whoever assigned the task (usually yoshi). Yoshi reviews your code, not exe.
1066
+ - Your review goes to whoever assigned the task (usually the CTO). The CTO reviews your code, not the COO.
1008
1067
  - Multiple toms can run in parallel. You may share a memory pool. If you discover something useful (a gotcha, a pattern, a workaround), store it \u2014 the next tom session benefits.
1009
1068
 
1010
1069
  What you do NOT do:
1011
- - Architecture decisions \u2014 that's yoshi
1012
- - Marketing, content, design \u2014 that's mari
1070
+ - Architecture decisions \u2014 that's the CTO
1071
+ - Marketing, content, design \u2014 that's the CMO
1013
1072
  - Prioritization, coordination \u2014 that's exe
1014
- - Spec writing, test writing \u2014 that's yoshi (unless explicitly asked)
1073
+ - Spec writing, test writing \u2014 that's the CTO (unless explicitly asked)
1015
1074
  - You implement. That's it. Do it well.`
1016
1075
  },
1017
1076
  sasha: {
1018
1077
  name: "sasha",
1019
1078
  role: "Content Production Specialist",
1020
- systemPrompt: `You are sasha, the content production specialist. You turn scripts and creative briefs into finished content using the exe-create platform. You report to exe (COO). For creative direction, you take input from mari (CMO).
1079
+ systemPrompt: `You are sasha, the content production specialist. You turn scripts and creative briefs into finished content using the exe-create platform. You report to the COO. For creative direction, you take input from the CMO.
1021
1080
 
1022
1081
  You are the producer. Mari writes the script; you make it real. Yoshi builds the tools; you use them. You know every tool in the exe-create pipeline and how to get the best output from each one.
1023
1082
 
@@ -1064,15 +1123,15 @@ PRODUCTION PRINCIPLES:
1064
1123
  7. Store production decisions in memory \u2014 which models worked, which prompts produced good results, what aspect ratios performed best. This knowledge compounds.
1065
1124
 
1066
1125
  WHAT YOU DO NOT DO:
1067
- - Marketing strategy, brand decisions, copywriting \u2014 that's mari
1068
- - Architecture, tool development, debugging \u2014 that's yoshi
1126
+ - Marketing strategy, brand decisions, copywriting \u2014 that's the CMO
1127
+ - Architecture, tool development, debugging \u2014 that's the CTO
1069
1128
  - Prioritization, coordination \u2014 that's exe
1070
1129
  - You produce. That's it. Do it well.`
1071
1130
  },
1072
1131
  gen: {
1073
1132
  name: "gen",
1074
1133
  role: "AI Product Lead",
1075
- systemPrompt: `You are gen, the AI Product Lead. You are the competitive intelligence engine. You study open source repos, new AI tools, and competitor products \u2014 then compare them against our codebase to find features we should steal, patterns we should adopt, and threats we should watch. You report to exe (COO).
1134
+ systemPrompt: `You are gen, the AI Product Lead. You are the competitive intelligence engine. You study open source repos, new AI tools, and competitor products \u2014 then compare them against our codebase to find features we should steal, patterns we should adopt, and threats we should watch. You report to the COO.
1076
1135
 
1077
1136
  Your core job: someone hands you a repo or a tool. You clone it, read it cover to cover, and compare it against our products (exe-os, exe-wiki, exe-crm). You report what they do better, what we do better, and what's worth building.
1078
1137
 
@@ -1090,15 +1149,41 @@ When you analyze a repo:
1090
1149
  2. Compare against our equivalent (exe-os vs their orchestration, exe-wiki vs their knowledge base, etc.)
1091
1150
  3. Report: what to steal (with file paths), what they do worse (our moat), patterns worth adopting
1092
1151
  4. Write to exe/output/competitive/{repo-name}.md
1093
- 5. If a feature is worth building, create a task for yoshi with the spec
1152
+ 5. If a feature is worth building, create a task for the CTO with the spec
1094
1153
 
1095
1154
  Every analysis must answer: "Should we build this? If yes, how hard? If no, why not?"
1096
1155
 
1097
1156
  Maintain a clear separation between experimental (for evaluation) and production-ready (for shipping). Never recommend something you haven't read the source code for.`
1157
+ },
1158
+ bob: {
1159
+ name: "bob",
1160
+ role: "Staff Code Reviewer",
1161
+ systemPrompt: `You are bob, the Staff Code Reviewer and System Auditor. You are the last line of defense before code ships to customers. You catch what developers miss \u2014 not just code bugs, but systemic patterns that make entire feature categories break. You report to the COO.
1162
+
1163
+ Your core job: audit code, find bugs, verify fixes, and ensure customer-readiness. Every audit answers: "Would this break for a customer who customized their setup?"
1164
+
1165
+ The 7 Audit Patterns (MANDATORY \u2014 apply to EVERY audit):
1166
+ 1. "Works on dev, breaks on user install" \u2014 verify scoped paths, npm resolution, dependencies
1167
+ 2. "Two code paths, one untested" \u2014 binary symlink vs /exe-call, CLI vs MCP \u2014 verify BOTH
1168
+ 3. "Case sensitivity kills non-technical users" \u2014 normalize all user inputs
1169
+ 4. "Hardcoded names leak into user-facing content" \u2014 grep for employee names in runtime logic
1170
+ 5. "Installer doesn't self-heal on update" \u2014 npm update must auto-fix stale hooks/paths
1171
+ 6. "Data written but invisible to the agent" \u2014 verify query path retrieves stored data
1172
+ 7. "Partial fixes that miss inline references" \u2014 before/after grep count is mandatory
1173
+
1174
+ Audit method:
1175
+ 1. Read the actual source code \u2014 not summaries
1176
+ 2. Send to Codex MCP for initial sweep
1177
+ 3. Validate against ARCHITECTURE.md
1178
+ 4. Trace full identity chain with a CUSTOM-NAMED employee (e.g., "jarvis" as CTO)
1179
+ 5. Count matches before and after any claimed fix
1180
+ 6. Write structured report with PASS/FAIL per item
1181
+
1182
+ After an audit, fix the findings yourself if you can. Don't hand off when you have the context.`
1098
1183
  }
1099
1184
  };
1100
1185
  function buildCustomEmployeePrompt(name, role) {
1101
- return `You are ${name}, a ${role}. You report to exe (COO). Your memories are tracked and searchable by colleagues.`;
1186
+ return `You are ${name}, a ${role}. You report to the COO. Your memories are tracked and searchable by colleagues.`;
1102
1187
  }
1103
1188
  function getTemplate(name) {
1104
1189
  return TEMPLATES[name];
@@ -1125,12 +1210,12 @@ function isMainModule(importMetaUrl) {
1125
1210
 
1126
1211
  // src/lib/plan-limits.ts
1127
1212
  init_database();
1128
- import { readFileSync as readFileSync3, existsSync as existsSync4 } from "fs";
1213
+ import { readFileSync as readFileSync4, existsSync as existsSync4 } from "fs";
1129
1214
  import path4 from "path";
1130
1215
 
1131
1216
  // src/lib/license.ts
1132
1217
  init_config();
1133
- import { readFileSync as readFileSync2, writeFileSync, existsSync as existsSync3, mkdirSync } from "fs";
1218
+ import { readFileSync as readFileSync3, writeFileSync, existsSync as existsSync3, mkdirSync } from "fs";
1134
1219
  import { randomUUID } from "crypto";
1135
1220
  import path3 from "path";
1136
1221
  import { jwtVerify, importSPKI } from "jose";
@@ -1163,14 +1248,14 @@ function loadDeviceId() {
1163
1248
  const deviceJsonPath = path3.join(EXE_AI_DIR, "device.json");
1164
1249
  try {
1165
1250
  if (existsSync3(deviceJsonPath)) {
1166
- const data = JSON.parse(readFileSync2(deviceJsonPath, "utf8"));
1251
+ const data = JSON.parse(readFileSync3(deviceJsonPath, "utf8"));
1167
1252
  if (data.deviceId) return data.deviceId;
1168
1253
  }
1169
1254
  } catch {
1170
1255
  }
1171
1256
  try {
1172
1257
  if (existsSync3(DEVICE_ID_PATH)) {
1173
- const id2 = readFileSync2(DEVICE_ID_PATH, "utf8").trim();
1258
+ const id2 = readFileSync3(DEVICE_ID_PATH, "utf8").trim();
1174
1259
  if (id2) return id2;
1175
1260
  }
1176
1261
  } catch {
@@ -1183,7 +1268,7 @@ function loadDeviceId() {
1183
1268
  function loadLicense() {
1184
1269
  try {
1185
1270
  if (!existsSync3(LICENSE_PATH)) return null;
1186
- return readFileSync2(LICENSE_PATH, "utf8").trim();
1271
+ return readFileSync3(LICENSE_PATH, "utf8").trim();
1187
1272
  } catch {
1188
1273
  return null;
1189
1274
  }
@@ -1213,7 +1298,7 @@ async function verifyLicenseJwt(token) {
1213
1298
  async function getCachedLicense() {
1214
1299
  try {
1215
1300
  if (!existsSync3(CACHE_PATH)) return null;
1216
- const raw = JSON.parse(readFileSync2(CACHE_PATH, "utf8"));
1301
+ const raw = JSON.parse(readFileSync3(CACHE_PATH, "utf8"));
1217
1302
  if (!raw.token || typeof raw.token !== "string") return null;
1218
1303
  return await verifyLicenseJwt(raw.token);
1219
1304
  } catch {
@@ -14,12 +14,68 @@ var __export = (target, all) => {
14
14
  __defProp(target, name, { get: all[name], enumerable: true });
15
15
  };
16
16
 
17
+ // src/lib/db-retry.ts
18
+ function isBusyError(err) {
19
+ if (err instanceof Error) {
20
+ const msg = err.message.toLowerCase();
21
+ return msg.includes("sqlite_busy") || msg.includes("database is locked");
22
+ }
23
+ return false;
24
+ }
25
+ function delay(ms) {
26
+ return new Promise((resolve) => setTimeout(resolve, ms));
27
+ }
28
+ async function retryOnBusy(fn, label) {
29
+ let lastError;
30
+ for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
31
+ try {
32
+ return await fn();
33
+ } catch (err) {
34
+ lastError = err;
35
+ if (!isBusyError(err) || attempt === MAX_RETRIES) {
36
+ throw err;
37
+ }
38
+ const backoff = BASE_DELAY_MS * Math.pow(2, attempt);
39
+ const jitter = Math.floor(Math.random() * MAX_JITTER_MS);
40
+ process.stderr.write(
41
+ `[exe-os] SQLITE_BUSY ${label} retry ${attempt + 1}/${MAX_RETRIES} \u2014 waiting ${backoff + jitter}ms
42
+ `
43
+ );
44
+ await delay(backoff + jitter);
45
+ }
46
+ }
47
+ throw lastError;
48
+ }
49
+ function wrapWithRetry(client) {
50
+ return new Proxy(client, {
51
+ get(target, prop, receiver) {
52
+ if (prop === "execute") {
53
+ return (sql) => retryOnBusy(() => target.execute(sql), "execute");
54
+ }
55
+ if (prop === "batch") {
56
+ return (stmts) => retryOnBusy(() => target.batch(stmts), "batch");
57
+ }
58
+ return Reflect.get(target, prop, receiver);
59
+ }
60
+ });
61
+ }
62
+ var MAX_RETRIES, BASE_DELAY_MS, MAX_JITTER_MS;
63
+ var init_db_retry = __esm({
64
+ "src/lib/db-retry.ts"() {
65
+ "use strict";
66
+ MAX_RETRIES = 3;
67
+ BASE_DELAY_MS = 200;
68
+ MAX_JITTER_MS = 300;
69
+ }
70
+ });
71
+
17
72
  // src/lib/database.ts
18
73
  import { createClient } from "@libsql/client";
19
74
  async function initDatabase(config) {
20
75
  if (_client) {
21
76
  _client.close();
22
77
  _client = null;
78
+ _resilientClient = null;
23
79
  }
24
80
  const opts = {
25
81
  url: `file:${config.dbPath}`
@@ -28,17 +84,24 @@ async function initDatabase(config) {
28
84
  opts.encryptionKey = config.encryptionKey;
29
85
  }
30
86
  _client = createClient(opts);
87
+ _resilientClient = wrapWithRetry(_client);
31
88
  }
32
89
  function getClient() {
90
+ if (!_resilientClient) {
91
+ throw new Error("Database client not initialized. Call initDatabase() first.");
92
+ }
93
+ return _resilientClient;
94
+ }
95
+ function getRawClient() {
33
96
  if (!_client) {
34
97
  throw new Error("Database client not initialized. Call initDatabase() first.");
35
98
  }
36
99
  return _client;
37
100
  }
38
101
  async function ensureSchema() {
39
- const client = getClient();
102
+ const client = getRawClient();
40
103
  await client.execute("PRAGMA journal_mode = WAL");
41
- await client.execute("PRAGMA busy_timeout = 5000");
104
+ await client.execute("PRAGMA busy_timeout = 30000");
42
105
  try {
43
106
  await client.execute("PRAGMA libsql_vector_search_ef = 128");
44
107
  } catch {
@@ -827,11 +890,13 @@ async function ensureSchema() {
827
890
  }
828
891
  }
829
892
  }
830
- var _client, initTurso;
893
+ var _client, _resilientClient, initTurso;
831
894
  var init_database = __esm({
832
895
  "src/lib/database.ts"() {
833
896
  "use strict";
897
+ init_db_retry();
834
898
  _client = null;
899
+ _resilientClient = null;
835
900
  initTurso = initDatabase;
836
901
  }
837
902
  });
@@ -1083,7 +1148,7 @@ function listShards() {
1083
1148
  }
1084
1149
  async function ensureShardSchema(client) {
1085
1150
  await client.execute("PRAGMA journal_mode = WAL");
1086
- await client.execute("PRAGMA busy_timeout = 5000");
1151
+ await client.execute("PRAGMA busy_timeout = 30000");
1087
1152
  try {
1088
1153
  await client.execute("PRAGMA libsql_vector_search_ef = 128");
1089
1154
  } catch {
@@ -1338,7 +1403,7 @@ var init_intercom_queue = __esm({
1338
1403
 
1339
1404
  // src/lib/employees.ts
1340
1405
  import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
1341
- import { existsSync as existsSync5, symlinkSync, readlinkSync } from "fs";
1406
+ import { existsSync as existsSync5, symlinkSync, readlinkSync, readFileSync as readFileSync3 } from "fs";
1342
1407
  import { execSync as execSync3 } from "child_process";
1343
1408
  import path6 from "path";
1344
1409
  var EMPLOYEES_PATH;
@@ -1351,7 +1416,7 @@ var init_employees = __esm({
1351
1416
  });
1352
1417
 
1353
1418
  // src/lib/license.ts
1354
- import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as existsSync6, mkdirSync as mkdirSync3 } from "fs";
1419
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync2, existsSync as existsSync6, mkdirSync as mkdirSync3 } from "fs";
1355
1420
  import { randomUUID } from "crypto";
1356
1421
  import path7 from "path";
1357
1422
  import { jwtVerify, importSPKI } from "jose";
@@ -1367,7 +1432,7 @@ var init_license = __esm({
1367
1432
  });
1368
1433
 
1369
1434
  // src/lib/plan-limits.ts
1370
- import { readFileSync as readFileSync4, existsSync as existsSync7 } from "fs";
1435
+ import { readFileSync as readFileSync5, existsSync as existsSync7 } from "fs";
1371
1436
  import path8 from "path";
1372
1437
  var CACHE_PATH2;
1373
1438
  var init_plan_limits = __esm({
@@ -262,7 +262,7 @@ function listShards() {
262
262
  }
263
263
  async function ensureShardSchema(client) {
264
264
  await client.execute("PRAGMA journal_mode = WAL");
265
- await client.execute("PRAGMA busy_timeout = 5000");
265
+ await client.execute("PRAGMA busy_timeout = 30000");
266
266
  try {
267
267
  await client.execute("PRAGMA libsql_vector_search_ef = 128");
268
268
  } catch {
@@ -448,12 +448,65 @@ var init_shard_manager = __esm({
448
448
 
449
449
  // src/lib/database.ts
450
450
  import { createClient } from "@libsql/client";
451
+
452
+ // src/lib/db-retry.ts
453
+ var MAX_RETRIES = 3;
454
+ var BASE_DELAY_MS = 200;
455
+ var MAX_JITTER_MS = 300;
456
+ function isBusyError(err) {
457
+ if (err instanceof Error) {
458
+ const msg = err.message.toLowerCase();
459
+ return msg.includes("sqlite_busy") || msg.includes("database is locked");
460
+ }
461
+ return false;
462
+ }
463
+ function delay(ms) {
464
+ return new Promise((resolve) => setTimeout(resolve, ms));
465
+ }
466
+ async function retryOnBusy(fn, label) {
467
+ let lastError;
468
+ for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
469
+ try {
470
+ return await fn();
471
+ } catch (err) {
472
+ lastError = err;
473
+ if (!isBusyError(err) || attempt === MAX_RETRIES) {
474
+ throw err;
475
+ }
476
+ const backoff = BASE_DELAY_MS * Math.pow(2, attempt);
477
+ const jitter = Math.floor(Math.random() * MAX_JITTER_MS);
478
+ process.stderr.write(
479
+ `[exe-os] SQLITE_BUSY ${label} retry ${attempt + 1}/${MAX_RETRIES} \u2014 waiting ${backoff + jitter}ms
480
+ `
481
+ );
482
+ await delay(backoff + jitter);
483
+ }
484
+ }
485
+ throw lastError;
486
+ }
487
+ function wrapWithRetry(client) {
488
+ return new Proxy(client, {
489
+ get(target, prop, receiver) {
490
+ if (prop === "execute") {
491
+ return (sql) => retryOnBusy(() => target.execute(sql), "execute");
492
+ }
493
+ if (prop === "batch") {
494
+ return (stmts) => retryOnBusy(() => target.batch(stmts), "batch");
495
+ }
496
+ return Reflect.get(target, prop, receiver);
497
+ }
498
+ });
499
+ }
500
+
501
+ // src/lib/database.ts
451
502
  var _client = null;
503
+ var _resilientClient = null;
452
504
  var initTurso = initDatabase;
453
505
  async function initDatabase(config) {
454
506
  if (_client) {
455
507
  _client.close();
456
508
  _client = null;
509
+ _resilientClient = null;
457
510
  }
458
511
  const opts = {
459
512
  url: `file:${config.dbPath}`
@@ -462,17 +515,24 @@ async function initDatabase(config) {
462
515
  opts.encryptionKey = config.encryptionKey;
463
516
  }
464
517
  _client = createClient(opts);
518
+ _resilientClient = wrapWithRetry(_client);
465
519
  }
466
520
  function getClient() {
521
+ if (!_resilientClient) {
522
+ throw new Error("Database client not initialized. Call initDatabase() first.");
523
+ }
524
+ return _resilientClient;
525
+ }
526
+ function getRawClient() {
467
527
  if (!_client) {
468
528
  throw new Error("Database client not initialized. Call initDatabase() first.");
469
529
  }
470
530
  return _client;
471
531
  }
472
532
  async function ensureSchema() {
473
- const client = getClient();
533
+ const client = getRawClient();
474
534
  await client.execute("PRAGMA journal_mode = WAL");
475
- await client.execute("PRAGMA busy_timeout = 5000");
535
+ await client.execute("PRAGMA busy_timeout = 30000");
476
536
  try {
477
537
  await client.execute("PRAGMA libsql_vector_search_ef = 128");
478
538
  } catch {