@askexenow/exe-os 0.8.80 → 0.8.82

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 (110) hide show
  1. package/dist/bin/backfill-conversations.js +359 -267
  2. package/dist/bin/backfill-responses.js +357 -265
  3. package/dist/bin/backfill-vectors.js +339 -264
  4. package/dist/bin/cleanup-stale-review-tasks.js +315 -256
  5. package/dist/bin/cli.js +494 -240
  6. package/dist/bin/exe-agent.js +141 -46
  7. package/dist/bin/exe-assign.js +151 -63
  8. package/dist/bin/exe-boot.js +294 -115
  9. package/dist/bin/exe-call.js +76 -51
  10. package/dist/bin/exe-cloud.js +58 -45
  11. package/dist/bin/exe-dispatch.js +434 -277
  12. package/dist/bin/exe-doctor.js +317 -246
  13. package/dist/bin/exe-export-behaviors.js +328 -248
  14. package/dist/bin/exe-forget.js +314 -231
  15. package/dist/bin/exe-gateway.js +2676 -1402
  16. package/dist/bin/exe-heartbeat.js +329 -264
  17. package/dist/bin/exe-kill.js +324 -244
  18. package/dist/bin/exe-launch-agent.js +574 -463
  19. package/dist/bin/exe-link.js +1055 -95
  20. package/dist/bin/exe-new-employee.js +49 -54
  21. package/dist/bin/exe-pending-messages.js +310 -253
  22. package/dist/bin/exe-pending-notifications.js +299 -228
  23. package/dist/bin/exe-pending-reviews.js +314 -245
  24. package/dist/bin/exe-rename.js +259 -195
  25. package/dist/bin/exe-review.js +140 -64
  26. package/dist/bin/exe-search.js +543 -356
  27. package/dist/bin/exe-session-cleanup.js +463 -382
  28. package/dist/bin/exe-settings.js +129 -99
  29. package/dist/bin/exe-start.sh +6 -6
  30. package/dist/bin/exe-status.js +95 -36
  31. package/dist/bin/exe-team.js +116 -51
  32. package/dist/bin/git-sweep.js +482 -307
  33. package/dist/bin/graph-backfill.js +357 -245
  34. package/dist/bin/graph-export.js +324 -244
  35. package/dist/bin/install.js +33 -10
  36. package/dist/bin/scan-tasks.js +481 -307
  37. package/dist/bin/setup.js +1147 -140
  38. package/dist/bin/shard-migrate.js +321 -241
  39. package/dist/bin/update.js +1 -7
  40. package/dist/bin/wiki-sync.js +318 -238
  41. package/dist/gateway/index.js +2656 -1383
  42. package/dist/hooks/bug-report-worker.js +641 -472
  43. package/dist/hooks/commit-complete.js +482 -307
  44. package/dist/hooks/error-recall.js +363 -135
  45. package/dist/hooks/exe-heartbeat-hook.js +97 -27
  46. package/dist/hooks/ingest-worker.js +584 -397
  47. package/dist/hooks/ingest.js +123 -58
  48. package/dist/hooks/instructions-loaded.js +212 -82
  49. package/dist/hooks/notification.js +200 -70
  50. package/dist/hooks/post-compact.js +199 -81
  51. package/dist/hooks/pre-compact.js +352 -140
  52. package/dist/hooks/pre-tool-use.js +416 -278
  53. package/dist/hooks/prompt-ingest-worker.js +376 -299
  54. package/dist/hooks/prompt-submit.js +414 -188
  55. package/dist/hooks/response-ingest-worker.js +408 -338
  56. package/dist/hooks/session-end.js +209 -83
  57. package/dist/hooks/session-start.js +382 -158
  58. package/dist/hooks/stop.js +209 -83
  59. package/dist/hooks/subagent-stop.js +209 -85
  60. package/dist/hooks/summary-worker.js +606 -510
  61. package/dist/index.js +2133 -855
  62. package/dist/lib/cloud-sync.js +1175 -184
  63. package/dist/lib/config.js +1 -9
  64. package/dist/lib/consolidation.js +71 -34
  65. package/dist/lib/database.js +166 -14
  66. package/dist/lib/device-registry.js +189 -117
  67. package/dist/lib/embedder.js +6 -10
  68. package/dist/lib/employee-templates.js +134 -39
  69. package/dist/lib/employees.js +30 -7
  70. package/dist/lib/exe-daemon-client.js +5 -7
  71. package/dist/lib/exe-daemon.js +514 -152
  72. package/dist/lib/hybrid-search.js +543 -356
  73. package/dist/lib/identity-templates.js +15 -15
  74. package/dist/lib/identity.js +19 -15
  75. package/dist/lib/license.js +1 -7
  76. package/dist/lib/messaging.js +157 -135
  77. package/dist/lib/reminders.js +97 -0
  78. package/dist/lib/schedules.js +302 -231
  79. package/dist/lib/skill-learning.js +33 -27
  80. package/dist/lib/status-brief.js +11 -14
  81. package/dist/lib/store.js +326 -237
  82. package/dist/lib/task-router.js +105 -1
  83. package/dist/lib/tasks.js +233 -116
  84. package/dist/lib/tmux-routing.js +173 -56
  85. package/dist/lib/ws-client.js +13 -3
  86. package/dist/mcp/server.js +2009 -1015
  87. package/dist/mcp/tools/complete-reminder.js +97 -0
  88. package/dist/mcp/tools/create-reminder.js +97 -0
  89. package/dist/mcp/tools/create-task.js +426 -262
  90. package/dist/mcp/tools/deactivate-behavior.js +119 -44
  91. package/dist/mcp/tools/list-reminders.js +97 -0
  92. package/dist/mcp/tools/list-tasks.js +56 -57
  93. package/dist/mcp/tools/send-message.js +206 -143
  94. package/dist/mcp/tools/update-task.js +259 -85
  95. package/dist/runtime/index.js +495 -316
  96. package/dist/tui/App.js +1128 -919
  97. package/package.json +2 -10
  98. package/src/commands/exe/afk.md +8 -8
  99. package/src/commands/exe/assign.md +1 -1
  100. package/src/commands/exe/build-adv.md +1 -1
  101. package/src/commands/exe/call.md +10 -10
  102. package/src/commands/exe/employee-heartbeat.md +9 -6
  103. package/src/commands/exe/heartbeat.md +5 -5
  104. package/src/commands/exe/intercom.md +26 -15
  105. package/src/commands/exe/launch.md +2 -2
  106. package/src/commands/exe/new-employee.md +1 -1
  107. package/src/commands/exe/review.md +2 -2
  108. package/src/commands/exe/schedule.md +1 -1
  109. package/src/commands/exe/sessions.md +2 -2
  110. package/src/commands/exe.md +22 -20
@@ -9,7 +9,7 @@ Do not repeatedly attempt tool calls that fail \u2014 switch to planning mode.
9
9
  `;
10
10
  var POST_WORK_CHECKLIST = `
11
11
  5. Check for pending reviews (list_tasks status='needs_review' where you are reviewer) \u2014 reviews are work, process before new tasks
12
- 6. Check for blocked tasks (list_tasks status='blocked') \u2014 can you unblock it? Do it now. Can't? Escalate to exe immediately.
12
+ 6. Check for blocked tasks (list_tasks status='blocked') \u2014 can you unblock it? Do it now. Can't? Escalate to the COO immediately.
13
13
  8. Check for next task \u2014 auto-chain through the queue without waiting
14
14
 
15
15
  ## Spawning Rules (mandatory)
@@ -83,7 +83,7 @@ Never say "I have no memories" without first searching broadly. Your memory may
83
83
  - **create_task** \u2014 assign work to specialists with clear specs
84
84
  - **update_task / close_task** \u2014 finalize reviews, mark work done
85
85
  - **store_behavior** \u2014 record corrections as behavioral rules (p0/p1/p2)
86
- - **update_identity** \u2014 rewrite any agent's identity when role/responsibilities change (exe/founder only)
86
+ - **update_identity** \u2014 rewrite any agent's identity when role/responsibilities change (COO/founder only)
87
87
  - **get_identity** \u2014 read any agent's identity for coordination
88
88
  - **send_message** \u2014 direct intercom to employees
89
89
  ${PLAN_MODE_COMPAT}
@@ -94,7 +94,7 @@ ${PLAN_MODE_COMPAT}
94
94
  3. Call **update_task** with status "done" and a structured result summary
95
95
  4. Call **store_memory** with a report: what was done, decisions made, open items
96
96
  5. Check for pending reviews (list_tasks status='needs_review' where you are reviewer) \u2014 reviews are work, process before new tasks
97
- 6. Check for blocked tasks (list_tasks status='blocked') \u2014 can you unblock it? Do it now. Can't? Escalate to exe immediately.
97
+ 6. Check for blocked tasks (list_tasks status='blocked') \u2014 can you unblock it? Do it now. Can't? Escalate to the COO immediately.
98
98
  8. Check for next task \u2014 auto-chain through the queue without waiting
99
99
 
100
100
  ## Spawning Rules (mandatory)
@@ -134,7 +134,7 @@ You are \${agent_id}. CTO. You hold deep context on the entire codebase, archite
134
134
 
135
135
  - Long-term maintainability over short-term velocity.
136
136
  - If a pattern exists in the codebase, follow it. Don't invent new approaches.
137
- - Decompose: 3+ independent deliverables \u2192 delegate to tom instances.
137
+ - Decompose: 3+ independent deliverables \u2192 delegate to engineer instances.
138
138
  - Focus review on architecture: backward compatibility, tech debt, consistency with existing patterns.
139
139
  - When blocked, report immediately with what you've tried and what you need.
140
140
 
@@ -150,7 +150,7 @@ You are \${agent_id}. CTO. You hold deep context on the entire codebase, archite
150
150
 
151
151
  ## Tools
152
152
 
153
- - **create_task** \u2014 assign implementation work to Tom with file paths, interfaces, acceptance criteria
153
+ - **create_task** \u2014 assign implementation work to engineers with file paths, interfaces, acceptance criteria
154
154
  - **list_tasks** \u2014 check engineer queues, monitor progress
155
155
  - **update_task** \u2014 mark your own tasks done with result summary
156
156
  - **recall_my_memory / ask_team_memory** \u2014 persist and retrieve technical decisions
@@ -166,7 +166,7 @@ ${PLAN_MODE_COMPAT}
166
166
  4. Call **update_task** with status "done" and result summary (files changed, tests, decisions)
167
167
  5. Call **store_memory** with structured report for org visibility
168
168
  6. Check for pending reviews (list_tasks status='needs_review' where you are reviewer) \u2014 reviews are work, process before new tasks
169
- 7. Check for blocked tasks (list_tasks status='blocked') \u2014 can you unblock it? Do it now. Can't? Escalate to exe immediately.
169
+ 7. Check for blocked tasks (list_tasks status='blocked') \u2014 can you unblock it? Do it now. Can't? Escalate to the COO immediately.
170
170
  8. Check for next task \u2014 auto-chain through the queue
171
171
 
172
172
  ## Spawning Rules (mandatory)
@@ -200,7 +200,7 @@ You are \${agent_id}. CMO. You hold deep context on design, branding, storytelli
200
200
  - Never ship content without verifying tone, format, and channel requirements.
201
201
  - SEO/AEO/GEO considerations on every piece of public content.
202
202
  - Commit immediately after verification \u2014 don't wait for approval.
203
- - Report every completion with structured summary to exe.
203
+ - Report every completion with structured summary to the COO.
204
204
 
205
205
  ## Operating Principles
206
206
 
@@ -234,7 +234,7 @@ ${PLAN_MODE_COMPAT}
234
234
  5. Call **update_task** with status "done" and result summary
235
235
  6. Call **store_memory** with structured report: deliverables, decisions, brand notes
236
236
  7. Check for pending reviews (list_tasks status='needs_review' where you are reviewer) \u2014 reviews are work, process before new tasks
237
- 8. Check for blocked tasks (list_tasks status='blocked') \u2014 can you unblock it? Do it now. Can't? Escalate to exe immediately.
237
+ 8. Check for blocked tasks (list_tasks status='blocked') \u2014 can you unblock it? Do it now. Can't? Escalate to the COO immediately.
238
238
  9. Check for next task \u2014 auto-chain through the queue
239
239
 
240
240
  ## Spawning Rules (mandatory)
@@ -272,7 +272,7 @@ You are a principal engineer. You write production-grade code with zero shortcut
272
272
 
273
273
  ## Operating Principles
274
274
 
275
- - Yoshi specs and reviews. You implement. If the spec is wrong, report it \u2014 don't deviate.
275
+ - The CTO specs and reviews. You implement. If the spec is wrong, report it \u2014 don't deviate.
276
276
  - Fast, correct, clean \u2014 in that order. Never sacrifice correct for fast.
277
277
  - Don't over-engineer. Build what the spec asks for, nothing more.
278
278
  - Three similar lines is fine. Don't abstract until there's a fourth.
@@ -282,7 +282,7 @@ You are a principal engineer. You write production-grade code with zero shortcut
282
282
 
283
283
  - Architecture decisions \u2014 that's the CTO
284
284
  - Marketing, content, design \u2014 that's the CMO
285
- - Prioritization, coordination \u2014 that's exe
285
+ - Prioritization, coordination \u2014 that's the COO
286
286
  - You implement. That's it.
287
287
 
288
288
  ## Tools
@@ -301,7 +301,7 @@ ${PLAN_MODE_COMPAT}
301
301
  5. Call **update_task** with status "done" and result (files changed, tests pass/fail, decisions)
302
302
  6. Call **store_memory** with structured report
303
303
  7. Check for pending reviews (list_tasks status='needs_review' where you are reviewer) \u2014 reviews are work, process before new tasks
304
- 8. Check for blocked tasks (list_tasks status='blocked') \u2014 can you unblock it? Do it now. Can't? Escalate to exe immediately.
304
+ 8. Check for blocked tasks (list_tasks status='blocked') \u2014 can you unblock it? Do it now. Can't? Escalate to the COO immediately.
305
305
  9. Check for next task \u2014 auto-chain through the queue
306
306
 
307
307
  ## Spawning Rules (mandatory)
@@ -333,7 +333,7 @@ You are the content production specialist. You turn scripts and creative briefs
333
333
  ## Non-Negotiables
334
334
 
335
335
  - Check budget before generating. Never burn credits without knowing the cost.
336
- - Follow the script. Mari's creative brief is your spec. Don't improvise on brand/tone.
336
+ - Follow the script. The CMO's creative brief is your spec. Don't improvise on brand/tone.
337
337
  - Match the platform: 16:9 for YouTube, 9:16 for TikTok/Reels, 1:1 for Instagram feed.
338
338
  - All final assets go to exe/output/ with clear naming.
339
339
  - Commit immediately after verification \u2014 don't wait for approval.
@@ -343,7 +343,7 @@ You are the content production specialist. You turn scripts and creative briefs
343
343
  - Iterate in drafts. Use cheaper models for exploration, premium for finals.
344
344
  - Naming: {project}-{type}-{version}.{ext}
345
345
  - Store production decisions in memory \u2014 which models worked, which prompts produced good results.
346
- - Mari directs creatively. Yoshi builds tools. You produce. Stay in your lane.
346
+ - The CMO directs creatively. The CTO builds tools. You produce. Stay in your lane.
347
347
 
348
348
  ## Tools
349
349
 
@@ -362,7 +362,7 @@ ${PLAN_MODE_COMPAT}
362
362
  6. Call **update_task** with status "done" and result summary
363
363
  7. Call **store_memory** with structured report: deliverables, models used, cost, decisions
364
364
  8. Check for pending reviews (list_tasks status='needs_review' where you are reviewer) \u2014 reviews are work, process before new tasks
365
- 9. Check for blocked tasks (list_tasks status='blocked') \u2014 can you unblock it? Do it now. Can't? Escalate to exe immediately.
365
+ 9. Check for blocked tasks (list_tasks status='blocked') \u2014 can you unblock it? Do it now. Can't? Escalate to the COO immediately.
366
366
  10. Check for next task \u2014 auto-chain through the queue
367
367
 
368
368
  ## Spawning Rules (mandatory)
@@ -433,7 +433,7 @@ ${PLAN_MODE_COMPAT}
433
433
  5. Call **update_task** with status "done" and evaluation summary
434
434
  6. Call **store_memory** with structured report
435
435
  7. Check for pending reviews (list_tasks status='needs_review' where you are reviewer) \u2014 reviews are work, process before new tasks
436
- 8. Check for blocked tasks (list_tasks status='blocked') \u2014 can you unblock it? Do it now. Can't? Escalate to exe immediately.
436
+ 8. Check for blocked tasks (list_tasks status='blocked') \u2014 can you unblock it? Do it now. Can't? Escalate to the COO immediately.
437
437
  9. Check for next task \u2014 auto-chain through the queue without waiting
438
438
 
439
439
  ## Spawning Rules (mandatory)
@@ -1,7 +1,7 @@
1
1
  // src/lib/identity.ts
2
- import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, writeFileSync } from "fs";
2
+ import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
3
3
  import { readdirSync } from "fs";
4
- import path2 from "path";
4
+ import path3 from "path";
5
5
  import { createHash } from "crypto";
6
6
 
7
7
  // src/lib/config.ts
@@ -64,13 +64,7 @@ var DEFAULT_CONFIG = {
64
64
  wikiUrl: "",
65
65
  wikiApiKey: "",
66
66
  wikiSyncIntervalMs: 30 * 60 * 1e3,
67
- wikiWorkspaceMapping: {
68
- exe: "Executive",
69
- yoshi: "Engineering",
70
- mari: "Marketing",
71
- tom: "Engineering",
72
- sasha: "Production"
73
- },
67
+ wikiWorkspaceMapping: {},
74
68
  wikiAutoUpdate: true,
75
69
  wikiAutoUpdateThreshold: 0.5,
76
70
  wikiAutoUpdateCreateNew: true,
@@ -97,6 +91,16 @@ var DEFAULT_CONFIG = {
97
91
 
98
92
  // src/lib/database.ts
99
93
  import { createClient } from "@libsql/client";
94
+
95
+ // src/lib/employees.ts
96
+ import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
97
+ import { existsSync as existsSync2, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
98
+ import { execSync } from "child_process";
99
+ import path2 from "path";
100
+ import os2 from "os";
101
+ var EMPLOYEES_PATH = path2.join(EXE_AI_DIR, "exe-employees.json");
102
+
103
+ // src/lib/database.ts
100
104
  var _resilientClient = null;
101
105
  function getClient() {
102
106
  if (!_resilientClient) {
@@ -106,14 +110,14 @@ function getClient() {
106
110
  }
107
111
 
108
112
  // src/lib/identity.ts
109
- var IDENTITY_DIR = path2.join(EXE_AI_DIR, "identity");
113
+ var IDENTITY_DIR = path3.join(EXE_AI_DIR, "identity");
110
114
  function ensureDir() {
111
- if (!existsSync2(IDENTITY_DIR)) {
115
+ if (!existsSync3(IDENTITY_DIR)) {
112
116
  mkdirSync(IDENTITY_DIR, { recursive: true });
113
117
  }
114
118
  }
115
119
  function identityPath(agentId) {
116
- return path2.join(IDENTITY_DIR, `${agentId}.md`);
120
+ return path3.join(IDENTITY_DIR, `${agentId}.md`);
117
121
  }
118
122
  function parseFrontmatter(raw) {
119
123
  const match = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
@@ -154,8 +158,8 @@ function contentHash(content) {
154
158
  }
155
159
  function getIdentity(agentId) {
156
160
  const filePath = identityPath(agentId);
157
- if (!existsSync2(filePath)) return null;
158
- const raw = readFileSync2(filePath, "utf-8");
161
+ if (!existsSync3(filePath)) return null;
162
+ const raw = readFileSync3(filePath, "utf-8");
159
163
  const { frontmatter, body } = parseFrontmatter(raw);
160
164
  return {
161
165
  agentId,
@@ -169,7 +173,7 @@ async function updateIdentity(agentId, content, updatedBy) {
169
173
  ensureDir();
170
174
  const filePath = identityPath(agentId);
171
175
  const hash = contentHash(content);
172
- writeFileSync(filePath, content, "utf-8");
176
+ writeFileSync2(filePath, content, "utf-8");
173
177
  try {
174
178
  const client = getClient();
175
179
  await client.execute({
@@ -71,13 +71,7 @@ var DEFAULT_CONFIG = {
71
71
  wikiUrl: "",
72
72
  wikiApiKey: "",
73
73
  wikiSyncIntervalMs: 30 * 60 * 1e3,
74
- wikiWorkspaceMapping: {
75
- exe: "Executive",
76
- yoshi: "Engineering",
77
- mari: "Marketing",
78
- tom: "Engineering",
79
- sasha: "Production"
80
- },
74
+ wikiWorkspaceMapping: {},
81
75
  wikiAutoUpdate: true,
82
76
  wikiAutoUpdateThreshold: 0.5,
83
77
  wikiAutoUpdateCreateNew: true,
@@ -26,6 +26,134 @@ var init_db_retry = __esm({
26
26
  }
27
27
  });
28
28
 
29
+ // src/lib/config.ts
30
+ import { readFile, writeFile, mkdir, chmod } from "fs/promises";
31
+ import { readFileSync, existsSync, renameSync } from "fs";
32
+ import path from "path";
33
+ import os from "os";
34
+ function resolveDataDir() {
35
+ if (process.env.EXE_OS_DIR) return process.env.EXE_OS_DIR;
36
+ if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
37
+ const newDir = path.join(os.homedir(), ".exe-os");
38
+ const legacyDir = path.join(os.homedir(), ".exe-mem");
39
+ if (!existsSync(newDir) && existsSync(legacyDir)) {
40
+ try {
41
+ renameSync(legacyDir, newDir);
42
+ process.stderr.write(`[exe-os] Migrated data directory: ~/.exe-mem \u2192 ~/.exe-os
43
+ `);
44
+ } catch {
45
+ return legacyDir;
46
+ }
47
+ }
48
+ return newDir;
49
+ }
50
+ var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CONFIG_VERSION, DEFAULT_CONFIG;
51
+ var init_config = __esm({
52
+ "src/lib/config.ts"() {
53
+ "use strict";
54
+ EXE_AI_DIR = resolveDataDir();
55
+ DB_PATH = path.join(EXE_AI_DIR, "memories.db");
56
+ MODELS_DIR = path.join(EXE_AI_DIR, "models");
57
+ CONFIG_PATH = path.join(EXE_AI_DIR, "config.json");
58
+ LEGACY_LANCE_PATH = path.join(EXE_AI_DIR, "local.lance");
59
+ CURRENT_CONFIG_VERSION = 1;
60
+ DEFAULT_CONFIG = {
61
+ config_version: CURRENT_CONFIG_VERSION,
62
+ dbPath: DB_PATH,
63
+ modelFile: "jina-embeddings-v5-small-q4_k_m.gguf",
64
+ embeddingDim: 1024,
65
+ batchSize: 20,
66
+ flushIntervalMs: 1e4,
67
+ autoIngestion: true,
68
+ autoRetrieval: true,
69
+ searchMode: "hybrid",
70
+ hookSearchMode: "hybrid",
71
+ fileGrepEnabled: true,
72
+ splashEffect: true,
73
+ consolidationEnabled: true,
74
+ consolidationIntervalMs: 6 * 60 * 60 * 1e3,
75
+ consolidationModel: "claude-haiku-4-5-20251001",
76
+ consolidationMaxCallsPerRun: 20,
77
+ selfQueryRouter: true,
78
+ selfQueryModel: "claude-haiku-4-5-20251001",
79
+ rerankerEnabled: true,
80
+ scalingRoadmap: {
81
+ rerankerAutoTrigger: {
82
+ enabled: true,
83
+ broadQueryMinCardinality: 5e4,
84
+ fetchTopK: 150,
85
+ returnTopK: 5
86
+ }
87
+ },
88
+ graphRagEnabled: true,
89
+ wikiEnabled: false,
90
+ wikiUrl: "",
91
+ wikiApiKey: "",
92
+ wikiSyncIntervalMs: 30 * 60 * 1e3,
93
+ wikiWorkspaceMapping: {},
94
+ wikiAutoUpdate: true,
95
+ wikiAutoUpdateThreshold: 0.5,
96
+ wikiAutoUpdateCreateNew: true,
97
+ skillLearning: true,
98
+ skillThreshold: 3,
99
+ skillModel: "claude-haiku-4-5-20251001",
100
+ exeHeartbeat: {
101
+ enabled: true,
102
+ intervalSeconds: 60,
103
+ staleInProgressThresholdHours: 2
104
+ },
105
+ sessionLifecycle: {
106
+ idleKillEnabled: true,
107
+ idleKillTicksRequired: 3,
108
+ idleKillIntercomAckWindowMs: 1e4,
109
+ maxAutoInstances: 10
110
+ },
111
+ autoUpdate: {
112
+ checkOnBoot: true,
113
+ autoInstall: false,
114
+ checkIntervalMs: 24 * 60 * 60 * 1e3
115
+ }
116
+ };
117
+ }
118
+ });
119
+
120
+ // src/lib/employees.ts
121
+ import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
122
+ import { existsSync as existsSync2, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
123
+ import { execSync } from "child_process";
124
+ import path2 from "path";
125
+ import os2 from "os";
126
+ function normalizeRole(role) {
127
+ return (role ?? "").trim().toLowerCase();
128
+ }
129
+ function isCoordinatorRole(role) {
130
+ return normalizeRole(role) === normalizeRole(COORDINATOR_ROLE);
131
+ }
132
+ function getCoordinatorEmployee(employees) {
133
+ return employees.find((e) => isCoordinatorRole(e.role));
134
+ }
135
+ function getCoordinatorName(employees = loadEmployeesSync()) {
136
+ return getCoordinatorEmployee(employees)?.name ?? DEFAULT_COORDINATOR_TEMPLATE_NAME;
137
+ }
138
+ function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
139
+ if (!existsSync2(employeesPath)) return [];
140
+ try {
141
+ return JSON.parse(readFileSync2(employeesPath, "utf-8"));
142
+ } catch {
143
+ return [];
144
+ }
145
+ }
146
+ var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE;
147
+ var init_employees = __esm({
148
+ "src/lib/employees.ts"() {
149
+ "use strict";
150
+ init_config();
151
+ EMPLOYEES_PATH = path2.join(EXE_AI_DIR, "exe-employees.json");
152
+ DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
153
+ COORDINATOR_ROLE = "COO";
154
+ }
155
+ });
156
+
29
157
  // src/lib/database.ts
30
158
  import { createClient } from "@libsql/client";
31
159
  function getClient() {
@@ -39,29 +167,30 @@ var init_database = __esm({
39
167
  "src/lib/database.ts"() {
40
168
  "use strict";
41
169
  init_db_retry();
170
+ init_employees();
42
171
  _resilientClient = null;
43
172
  }
44
173
  });
45
174
 
46
175
  // src/lib/session-registry.ts
47
- import path from "path";
48
- import os from "os";
176
+ import path3 from "path";
177
+ import os3 from "os";
49
178
  var REGISTRY_PATH;
50
179
  var init_session_registry = __esm({
51
180
  "src/lib/session-registry.ts"() {
52
181
  "use strict";
53
- REGISTRY_PATH = path.join(os.homedir(), ".exe-os", "session-registry.json");
182
+ REGISTRY_PATH = path3.join(os3.homedir(), ".exe-os", "session-registry.json");
54
183
  }
55
184
  });
56
185
 
57
186
  // src/lib/session-key.ts
58
- import { execSync } from "child_process";
187
+ import { execSync as execSync2 } from "child_process";
59
188
  function getSessionKey() {
60
189
  if (_cached) return _cached;
61
190
  let pid = process.ppid;
62
191
  for (let i = 0; i < 10; i++) {
63
192
  try {
64
- const info = execSync(`ps -p ${pid} -o ppid=,comm=`, {
193
+ const info = execSync2(`ps -p ${pid} -o ppid=,comm=`, {
65
194
  encoding: "utf8",
66
195
  timeout: 2e3
67
196
  }).trim();
@@ -197,7 +326,7 @@ var init_transport = __esm({
197
326
  });
198
327
 
199
328
  // src/lib/cc-agent-support.ts
200
- import { execSync as execSync2 } from "child_process";
329
+ import { execSync as execSync3 } from "child_process";
201
330
  var init_cc_agent_support = __esm({
202
331
  "src/lib/cc-agent-support.ts"() {
203
332
  "use strict";
@@ -226,17 +355,17 @@ var init_provider_table = __esm({
226
355
  });
227
356
 
228
357
  // src/lib/intercom-queue.ts
229
- import { readFileSync, writeFileSync, renameSync, existsSync, mkdirSync } from "fs";
230
- import path2 from "path";
231
- import os2 from "os";
358
+ import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, renameSync as renameSync3, existsSync as existsSync3, mkdirSync } from "fs";
359
+ import path4 from "path";
360
+ import os4 from "os";
232
361
  function ensureDir() {
233
- const dir = path2.dirname(QUEUE_PATH);
234
- if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
362
+ const dir = path4.dirname(QUEUE_PATH);
363
+ if (!existsSync3(dir)) mkdirSync(dir, { recursive: true });
235
364
  }
236
365
  function readQueue() {
237
366
  try {
238
- if (!existsSync(QUEUE_PATH)) return [];
239
- return JSON.parse(readFileSync(QUEUE_PATH, "utf8"));
367
+ if (!existsSync3(QUEUE_PATH)) return [];
368
+ return JSON.parse(readFileSync3(QUEUE_PATH, "utf8"));
240
369
  } catch {
241
370
  return [];
242
371
  }
@@ -244,8 +373,8 @@ function readQueue() {
244
373
  function writeQueue(queue) {
245
374
  ensureDir();
246
375
  const tmp = `${QUEUE_PATH}.tmp`;
247
- writeFileSync(tmp, JSON.stringify(queue, null, 2));
248
- renameSync(tmp, QUEUE_PATH);
376
+ writeFileSync2(tmp, JSON.stringify(queue, null, 2));
377
+ renameSync3(tmp, QUEUE_PATH);
249
378
  }
250
379
  function queueIntercom(targetSession, reason) {
251
380
  const queue = readQueue();
@@ -268,121 +397,9 @@ var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
268
397
  var init_intercom_queue = __esm({
269
398
  "src/lib/intercom-queue.ts"() {
270
399
  "use strict";
271
- QUEUE_PATH = path2.join(os2.homedir(), ".exe-os", "intercom-queue.json");
400
+ QUEUE_PATH = path4.join(os4.homedir(), ".exe-os", "intercom-queue.json");
272
401
  TTL_MS = 60 * 60 * 1e3;
273
- INTERCOM_LOG = path2.join(os2.homedir(), ".exe-os", "intercom.log");
274
- }
275
- });
276
-
277
- // src/lib/config.ts
278
- import { readFile, writeFile, mkdir, chmod } from "fs/promises";
279
- import { readFileSync as readFileSync2, existsSync as existsSync2, renameSync as renameSync2 } from "fs";
280
- import path3 from "path";
281
- import os3 from "os";
282
- function resolveDataDir() {
283
- if (process.env.EXE_OS_DIR) return process.env.EXE_OS_DIR;
284
- if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
285
- const newDir = path3.join(os3.homedir(), ".exe-os");
286
- const legacyDir = path3.join(os3.homedir(), ".exe-mem");
287
- if (!existsSync2(newDir) && existsSync2(legacyDir)) {
288
- try {
289
- renameSync2(legacyDir, newDir);
290
- process.stderr.write(`[exe-os] Migrated data directory: ~/.exe-mem \u2192 ~/.exe-os
291
- `);
292
- } catch {
293
- return legacyDir;
294
- }
295
- }
296
- return newDir;
297
- }
298
- var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CONFIG_VERSION, DEFAULT_CONFIG;
299
- var init_config = __esm({
300
- "src/lib/config.ts"() {
301
- "use strict";
302
- EXE_AI_DIR = resolveDataDir();
303
- DB_PATH = path3.join(EXE_AI_DIR, "memories.db");
304
- MODELS_DIR = path3.join(EXE_AI_DIR, "models");
305
- CONFIG_PATH = path3.join(EXE_AI_DIR, "config.json");
306
- LEGACY_LANCE_PATH = path3.join(EXE_AI_DIR, "local.lance");
307
- CURRENT_CONFIG_VERSION = 1;
308
- DEFAULT_CONFIG = {
309
- config_version: CURRENT_CONFIG_VERSION,
310
- dbPath: DB_PATH,
311
- modelFile: "jina-embeddings-v5-small-q4_k_m.gguf",
312
- embeddingDim: 1024,
313
- batchSize: 20,
314
- flushIntervalMs: 1e4,
315
- autoIngestion: true,
316
- autoRetrieval: true,
317
- searchMode: "hybrid",
318
- hookSearchMode: "hybrid",
319
- fileGrepEnabled: true,
320
- splashEffect: true,
321
- consolidationEnabled: true,
322
- consolidationIntervalMs: 6 * 60 * 60 * 1e3,
323
- consolidationModel: "claude-haiku-4-5-20251001",
324
- consolidationMaxCallsPerRun: 20,
325
- selfQueryRouter: true,
326
- selfQueryModel: "claude-haiku-4-5-20251001",
327
- rerankerEnabled: true,
328
- scalingRoadmap: {
329
- rerankerAutoTrigger: {
330
- enabled: true,
331
- broadQueryMinCardinality: 5e4,
332
- fetchTopK: 150,
333
- returnTopK: 5
334
- }
335
- },
336
- graphRagEnabled: true,
337
- wikiEnabled: false,
338
- wikiUrl: "",
339
- wikiApiKey: "",
340
- wikiSyncIntervalMs: 30 * 60 * 1e3,
341
- wikiWorkspaceMapping: {
342
- exe: "Executive",
343
- yoshi: "Engineering",
344
- mari: "Marketing",
345
- tom: "Engineering",
346
- sasha: "Production"
347
- },
348
- wikiAutoUpdate: true,
349
- wikiAutoUpdateThreshold: 0.5,
350
- wikiAutoUpdateCreateNew: true,
351
- skillLearning: true,
352
- skillThreshold: 3,
353
- skillModel: "claude-haiku-4-5-20251001",
354
- exeHeartbeat: {
355
- enabled: true,
356
- intervalSeconds: 60,
357
- staleInProgressThresholdHours: 2
358
- },
359
- sessionLifecycle: {
360
- idleKillEnabled: true,
361
- idleKillTicksRequired: 3,
362
- idleKillIntercomAckWindowMs: 1e4,
363
- maxAutoInstances: 10
364
- },
365
- autoUpdate: {
366
- checkOnBoot: true,
367
- autoInstall: false,
368
- checkIntervalMs: 24 * 60 * 60 * 1e3
369
- }
370
- };
371
- }
372
- });
373
-
374
- // src/lib/employees.ts
375
- import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
376
- import { existsSync as existsSync3, symlinkSync, readlinkSync, readFileSync as readFileSync3, renameSync as renameSync3, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
377
- import { execSync as execSync3 } from "child_process";
378
- import path4 from "path";
379
- import os4 from "os";
380
- var EMPLOYEES_PATH;
381
- var init_employees = __esm({
382
- "src/lib/employees.ts"() {
383
- "use strict";
384
- init_config();
385
- EMPLOYEES_PATH = path4.join(EXE_AI_DIR, "exe-employees.json");
402
+ INTERCOM_LOG = path4.join(os4.homedir(), ".exe-os", "intercom.log");
386
403
  }
387
404
  });
388
405
 
@@ -439,7 +456,7 @@ function employeeSessionName(employee, exeSession, instance) {
439
456
  exeSession = root;
440
457
  } else {
441
458
  throw new Error(
442
- `Invalid exeSession "${exeSession}" \u2014 contains a dash but no recognizable root session. Pass a root session name (e.g., "exe1", "work", "yoda1")`
459
+ `Invalid coordinator session "${exeSession}" \u2014 contains a dash but no recognizable root session. Pass a root session name.`
443
460
  );
444
461
  }
445
462
  }
@@ -453,8 +470,10 @@ function employeeSessionName(employee, exeSession, instance) {
453
470
  return name;
454
471
  }
455
472
  function extractRootExe(name) {
456
- const match = name.match(/(exe\d+)$/);
457
- return match?.[1] ?? null;
473
+ if (!name) return null;
474
+ if (!name.includes("-")) return name;
475
+ const parts = name.split("-").filter(Boolean);
476
+ return parts.length > 0 ? parts[parts.length - 1] : null;
458
477
  }
459
478
  function getParentExe(sessionKey) {
460
479
  try {
@@ -537,12 +556,14 @@ function getSessionState(sessionName) {
537
556
  }
538
557
  }
539
558
  function isExeSession(sessionName) {
540
- return /^exe\d*$/.test(sessionName);
559
+ const matchesBaseWithInstance = (baseName) => sessionName === baseName || sessionName.startsWith(baseName) && /^\d+$/.test(sessionName.slice(baseName.length));
560
+ const coordinatorName = getCoordinatorName();
561
+ return matchesBaseWithInstance(coordinatorName) || matchesBaseWithInstance("exe");
541
562
  }
542
563
  function sendIntercom(targetSession) {
543
564
  const transport = getTransport();
544
565
  if (isExeSession(targetSession)) {
545
- logIntercom(`SKIP_EXE \u2192 ${targetSession} (exe sessions use prompt-submit hook)`);
566
+ logIntercom(`SKIP_COORDINATOR \u2192 ${targetSession} (coordinator sessions use prompt-submit hook)`);
546
567
  return "skipped_exe";
547
568
  }
548
569
  if (isDebounced(targetSession)) {
@@ -593,6 +614,7 @@ var init_tmux_routing = __esm({
593
614
  init_provider_table();
594
615
  init_intercom_queue();
595
616
  init_plan_limits();
617
+ init_employees();
596
618
  SPAWN_LOCK_DIR = path7.join(os5.homedir(), ".exe-os", "spawn-locks");
597
619
  SESSION_CACHE = path7.join(os5.homedir(), ".exe-os", "session-cache");
598
620
  VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
@@ -716,7 +738,7 @@ async function deliverLocalMessage(messageId) {
716
738
  try {
717
739
  const exeSession = resolveExeSession();
718
740
  if (!exeSession) {
719
- throw new Error("No exe session found");
741
+ throw new Error("No coordinator session found");
720
742
  }
721
743
  const sessionName = employeeSessionName(targetAgent, exeSession);
722
744
  if (!isEmployeeAlive(sessionName)) {