@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.
- package/dist/bin/backfill-conversations.js +332 -348
- package/dist/bin/backfill-responses.js +72 -12
- package/dist/bin/backfill-vectors.js +72 -12
- package/dist/bin/cleanup-stale-review-tasks.js +63 -3
- package/dist/bin/cli.js +1518 -1122
- package/dist/bin/exe-agent.js +4 -4
- package/dist/bin/exe-assign.js +80 -18
- package/dist/bin/exe-boot.js +408 -89
- package/dist/bin/exe-call.js +83 -24
- package/dist/bin/exe-dispatch.js +18 -10
- package/dist/bin/exe-doctor.js +63 -3
- package/dist/bin/exe-export-behaviors.js +64 -3
- package/dist/bin/exe-forget.js +69 -4
- package/dist/bin/exe-gateway.js +121 -36
- package/dist/bin/exe-heartbeat.js +77 -13
- package/dist/bin/exe-kill.js +64 -3
- package/dist/bin/exe-launch-agent.js +162 -35
- package/dist/bin/exe-link.js +946 -0
- package/dist/bin/exe-new-employee.js +121 -36
- package/dist/bin/exe-pending-messages.js +72 -7
- package/dist/bin/exe-pending-notifications.js +63 -3
- package/dist/bin/exe-pending-reviews.js +75 -10
- package/dist/bin/exe-rename.js +1287 -0
- package/dist/bin/exe-review.js +64 -4
- package/dist/bin/exe-search.js +79 -13
- package/dist/bin/exe-session-cleanup.js +91 -26
- package/dist/bin/exe-status.js +64 -4
- package/dist/bin/exe-team.js +64 -4
- package/dist/bin/git-sweep.js +71 -4
- package/dist/bin/graph-backfill.js +64 -3
- package/dist/bin/graph-export.js +64 -3
- package/dist/bin/install.js +3 -3
- package/dist/bin/scan-tasks.js +71 -4
- package/dist/bin/setup.js +156 -38
- package/dist/bin/shard-migrate.js +64 -3
- package/dist/bin/wiki-sync.js +64 -3
- package/dist/gateway/index.js +122 -37
- package/dist/hooks/bug-report-worker.js +209 -23
- package/dist/hooks/commit-complete.js +71 -4
- package/dist/hooks/error-recall.js +79 -13
- package/dist/hooks/ingest-worker.js +129 -43
- package/dist/hooks/instructions-loaded.js +71 -4
- package/dist/hooks/notification.js +71 -4
- package/dist/hooks/post-compact.js +71 -4
- package/dist/hooks/pre-compact.js +71 -4
- package/dist/hooks/pre-tool-use.js +413 -194
- package/dist/hooks/prompt-ingest-worker.js +82 -22
- package/dist/hooks/prompt-submit.js +103 -37
- package/dist/hooks/response-ingest-worker.js +87 -22
- package/dist/hooks/session-end.js +71 -4
- package/dist/hooks/session-start.js +79 -13
- package/dist/hooks/stop.js +71 -4
- package/dist/hooks/subagent-stop.js +71 -4
- package/dist/hooks/summary-worker.js +303 -50
- package/dist/index.js +134 -46
- package/dist/lib/cloud-sync.js +209 -15
- package/dist/lib/consolidation.js +4 -4
- package/dist/lib/database.js +64 -2
- package/dist/lib/device-registry.js +70 -3
- package/dist/lib/employee-templates.js +48 -22
- package/dist/lib/employees.js +34 -1
- package/dist/lib/exe-daemon.js +136 -53
- package/dist/lib/hybrid-search.js +79 -13
- package/dist/lib/identity-templates.js +57 -6
- package/dist/lib/identity.js +3 -3
- package/dist/lib/messaging.js +22 -14
- package/dist/lib/reminders.js +3 -3
- package/dist/lib/schedules.js +63 -3
- package/dist/lib/skill-learning.js +3 -3
- package/dist/lib/status-brief.js +63 -5
- package/dist/lib/store.js +64 -3
- package/dist/lib/task-router.js +4 -2
- package/dist/lib/tasks.js +48 -21
- package/dist/lib/tmux-routing.js +47 -20
- package/dist/mcp/server.js +727 -58
- package/dist/mcp/tools/complete-reminder.js +3 -3
- package/dist/mcp/tools/create-reminder.js +3 -3
- package/dist/mcp/tools/create-task.js +151 -24
- package/dist/mcp/tools/deactivate-behavior.js +3 -3
- package/dist/mcp/tools/list-reminders.js +3 -3
- package/dist/mcp/tools/list-tasks.js +17 -8
- package/dist/mcp/tools/send-message.js +24 -16
- package/dist/mcp/tools/update-task.js +25 -16
- package/dist/runtime/index.js +112 -24
- package/dist/tui/App.js +139 -36
- package/package.json +6 -2
- 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 (!
|
|
119
|
+
if (!_resilientClient) {
|
|
113
120
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
114
121
|
}
|
|
115
|
-
return
|
|
122
|
+
return _resilientClient;
|
|
116
123
|
}
|
|
117
|
-
var
|
|
124
|
+
var _resilientClient;
|
|
118
125
|
var init_database = __esm({
|
|
119
126
|
"src/lib/database.ts"() {
|
|
120
127
|
"use strict";
|
|
121
|
-
|
|
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 (
|
|
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
|
|
424
|
-
- Marketing, content, design \u2014 that's
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
1012
|
-
- Marketing, content, design \u2014 that's
|
|
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
|
|
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
|
|
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
|
|
1068
|
-
- Architecture, tool development, debugging \u2014 that's
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
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 =
|
|
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
|
|
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(
|
|
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 =
|
|
102
|
+
const client = getRawClient();
|
|
40
103
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
41
|
-
await client.execute("PRAGMA busy_timeout =
|
|
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 =
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
533
|
+
const client = getRawClient();
|
|
474
534
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
475
|
-
await client.execute("PRAGMA busy_timeout =
|
|
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 {
|