@askexenow/exe-os 0.9.38 → 0.9.40

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 (70) hide show
  1. package/dist/bin/backfill-conversations.js +34 -7
  2. package/dist/bin/backfill-responses.js +34 -7
  3. package/dist/bin/backfill-vectors.js +34 -7
  4. package/dist/bin/cleanup-stale-review-tasks.js +35 -8
  5. package/dist/bin/cli.js +108 -45
  6. package/dist/bin/exe-agent.js +11 -3
  7. package/dist/bin/exe-assign.js +34 -7
  8. package/dist/bin/exe-boot.js +48 -18
  9. package/dist/bin/exe-call.js +132 -340
  10. package/dist/bin/exe-dispatch.js +34 -7
  11. package/dist/bin/exe-doctor.js +37 -10
  12. package/dist/bin/exe-export-behaviors.js +36 -9
  13. package/dist/bin/exe-forget.js +34 -7
  14. package/dist/bin/exe-gateway.js +40 -12
  15. package/dist/bin/exe-heartbeat.js +35 -8
  16. package/dist/bin/exe-kill.js +34 -7
  17. package/dist/bin/exe-launch-agent.js +285 -1079
  18. package/dist/bin/exe-new-employee.js +29 -10
  19. package/dist/bin/exe-pending-messages.js +34 -7
  20. package/dist/bin/exe-pending-notifications.js +34 -7
  21. package/dist/bin/exe-pending-reviews.js +34 -7
  22. package/dist/bin/exe-rename.js +41 -13
  23. package/dist/bin/exe-review.js +34 -7
  24. package/dist/bin/exe-search.js +36 -9
  25. package/dist/bin/exe-session-cleanup.js +36 -9
  26. package/dist/bin/exe-start-codex.js +36 -9
  27. package/dist/bin/exe-start-opencode.js +36 -9
  28. package/dist/bin/exe-status.js +35 -8
  29. package/dist/bin/exe-team.js +34 -7
  30. package/dist/bin/git-sweep.js +34 -7
  31. package/dist/bin/graph-backfill.js +34 -7
  32. package/dist/bin/graph-export.js +34 -7
  33. package/dist/bin/install.js +2 -1
  34. package/dist/bin/intercom-check.js +36 -9
  35. package/dist/bin/scan-tasks.js +34 -7
  36. package/dist/bin/setup.js +18 -17
  37. package/dist/bin/shard-migrate.js +34 -7
  38. package/dist/bin/update.js +36 -3
  39. package/dist/gateway/index.js +38 -10
  40. package/dist/hooks/bug-report-worker.js +38 -10
  41. package/dist/hooks/codex-stop-task-finalizer.js +36 -9
  42. package/dist/hooks/commit-complete.js +34 -7
  43. package/dist/hooks/error-recall.js +36 -9
  44. package/dist/hooks/ingest.js +36 -8
  45. package/dist/hooks/instructions-loaded.js +42 -10
  46. package/dist/hooks/notification.js +34 -7
  47. package/dist/hooks/post-compact.js +34 -7
  48. package/dist/hooks/post-tool-combined.js +37 -10
  49. package/dist/hooks/pre-compact.js +35 -8
  50. package/dist/hooks/pre-tool-use.js +36 -8
  51. package/dist/hooks/prompt-submit.js +41 -13
  52. package/dist/hooks/session-end.js +35 -8
  53. package/dist/hooks/session-start.js +47 -14
  54. package/dist/hooks/stop.js +35 -8
  55. package/dist/hooks/subagent-stop.js +34 -7
  56. package/dist/hooks/summary-worker.js +43 -16
  57. package/dist/index.js +36 -8
  58. package/dist/lib/consolidation.js +2 -1
  59. package/dist/lib/employee-templates.js +2 -1
  60. package/dist/lib/employees.js +2 -1
  61. package/dist/lib/exe-daemon.js +136 -36
  62. package/dist/lib/hybrid-search.js +36 -9
  63. package/dist/lib/identity.js +8 -3
  64. package/dist/lib/schedules.js +34 -7
  65. package/dist/lib/store.js +34 -7
  66. package/dist/mcp/server.js +133 -33
  67. package/dist/mcp/tools/create-task.js +10 -4
  68. package/dist/runtime/index.js +34 -7
  69. package/dist/tui/App.js +40 -11
  70. package/package.json +2 -2
package/dist/bin/cli.js CHANGED
@@ -540,7 +540,8 @@ function isMultiInstance(agentName, employees) {
540
540
  return MULTI_INSTANCE_ROLES.has(emp.role.toLowerCase());
541
541
  }
542
542
  function addEmployee(employees, employee) {
543
- const normalized = { ...employee, name: employee.name.toLowerCase() };
543
+ const { systemPrompt: _legacyPrompt, ...rest } = employee;
544
+ const normalized = { ...rest, name: employee.name.toLowerCase() };
544
545
  if (employees.some((e) => e.name.toLowerCase() === normalized.name)) {
545
546
  throw new Error(`Employee '${normalized.name}' already exists`);
546
547
  }
@@ -4864,8 +4865,8 @@ async function validateLicense(apiKey, deviceId) {
4864
4865
  }
4865
4866
  function getCacheAgeMs() {
4866
4867
  try {
4867
- const { statSync: statSync4 } = __require("fs");
4868
- const s = statSync4(CACHE_PATH);
4868
+ const { statSync: statSync5 } = __require("fs");
4869
+ const s = statSync5(CACHE_PATH);
4869
4870
  return Date.now() - s.mtimeMs;
4870
4871
  } catch {
4871
4872
  return Infinity;
@@ -7102,7 +7103,7 @@ __export(shard_manager_exports, {
7102
7103
  shardExists: () => shardExists
7103
7104
  });
7104
7105
  import path15 from "path";
7105
- import { existsSync as existsSync15, mkdirSync as mkdirSync8, readdirSync as readdirSync3 } from "fs";
7106
+ import { existsSync as existsSync15, mkdirSync as mkdirSync8, readdirSync as readdirSync3, renameSync as renameSync3, statSync as statSync4 } from "fs";
7106
7107
  import { createClient as createClient2 } from "@libsql/client";
7107
7108
  function initShardManager(encryptionKey) {
7108
7109
  _encryptionKey = encryptionKey;
@@ -7124,7 +7125,7 @@ function getShardClient(projectName) {
7124
7125
  if (!_encryptionKey) {
7125
7126
  throw new Error("Shard manager not initialized. Call initShardManager() first.");
7126
7127
  }
7127
- const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
7128
+ const safeName = safeShardName(projectName);
7128
7129
  if (!safeName || safeName === "unknown") {
7129
7130
  throw new Error(`Invalid project name for shard: "${projectName}" (resolved to "${safeName}")`);
7130
7131
  }
@@ -7146,9 +7147,12 @@ function getShardClient(projectName) {
7146
7147
  return client;
7147
7148
  }
7148
7149
  function shardExists(projectName) {
7149
- const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
7150
+ const safeName = safeShardName(projectName);
7150
7151
  return existsSync15(path15.join(SHARDS_DIR, `${safeName}.db`));
7151
7152
  }
7153
+ function safeShardName(projectName) {
7154
+ return projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
7155
+ }
7152
7156
  function listShards() {
7153
7157
  if (!existsSync15(SHARDS_DIR)) return [];
7154
7158
  return readdirSync3(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
@@ -7242,7 +7246,8 @@ async function ensureShardSchema(client) {
7242
7246
  "ALTER TABLE memories ADD COLUMN token_cost REAL",
7243
7247
  "ALTER TABLE memories ADD COLUMN audience TEXT",
7244
7248
  "ALTER TABLE memories ADD COLUMN language_type TEXT",
7245
- "ALTER TABLE memories ADD COLUMN parent_memory_id TEXT"
7249
+ "ALTER TABLE memories ADD COLUMN parent_memory_id TEXT",
7250
+ "ALTER TABLE memories ADD COLUMN deleted_at TEXT"
7246
7251
  ]) {
7247
7252
  try {
7248
7253
  await client.execute(col);
@@ -7338,9 +7343,32 @@ async function ensureShardSchema(client) {
7338
7343
  }
7339
7344
  }
7340
7345
  async function getReadyShardClient(projectName) {
7341
- const client = getShardClient(projectName);
7342
- await ensureShardSchema(client);
7343
- return client;
7346
+ const safeName = safeShardName(projectName);
7347
+ let client = getShardClient(projectName);
7348
+ try {
7349
+ await ensureShardSchema(client);
7350
+ return client;
7351
+ } catch (err) {
7352
+ const message = err instanceof Error ? err.message : String(err);
7353
+ if (!/SQLITE_NOTADB|file is not a database/i.test(message)) throw err;
7354
+ client.close();
7355
+ _shards.delete(safeName);
7356
+ _shardLastAccess.delete(safeName);
7357
+ const dbPath = path15.join(SHARDS_DIR, `${safeName}.db`);
7358
+ if (existsSync15(dbPath)) {
7359
+ const stat2 = statSync4(dbPath);
7360
+ const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
7361
+ const archivedPath = path15.join(SHARDS_DIR, `${safeName}.db.broken-${stamp}`);
7362
+ renameSync3(dbPath, archivedPath);
7363
+ process.stderr.write(
7364
+ `[shard-manager] Archived unreadable shard ${safeName}: ${archivedPath} (${stat2.size} bytes, mtime ${stat2.mtime.toISOString()})
7365
+ `
7366
+ );
7367
+ }
7368
+ client = getShardClient(projectName);
7369
+ await ensureShardSchema(client);
7370
+ return client;
7371
+ }
7344
7372
  }
7345
7373
  function evictLRU() {
7346
7374
  let oldest = null;
@@ -9264,6 +9292,9 @@ function ensureDir() {
9264
9292
  function identityPath(agentId) {
9265
9293
  return path17.join(IDENTITY_DIR2, `${agentId}.md`);
9266
9294
  }
9295
+ function sanitizeIdentityBody(body) {
9296
+ return body.replace(/<!--[\s\S]*?-->/g, "").trim();
9297
+ }
9267
9298
  function parseFrontmatter(raw) {
9268
9299
  const match = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
9269
9300
  if (!match) {
@@ -9276,11 +9307,11 @@ function parseFrontmatter(raw) {
9276
9307
  created_by: "system",
9277
9308
  updated_at: (/* @__PURE__ */ new Date()).toISOString()
9278
9309
  },
9279
- body: raw
9310
+ body: sanitizeIdentityBody(raw)
9280
9311
  };
9281
9312
  }
9282
9313
  const yamlStr = match[1];
9283
- const body = match[2].trim();
9314
+ const body = sanitizeIdentityBody(match[2]);
9284
9315
  const fm = {};
9285
9316
  for (const line of yamlStr.split("\n")) {
9286
9317
  const kv = line.match(/^(\w+):\s*(.+)$/);
@@ -9345,7 +9376,9 @@ function listIdentities() {
9345
9376
  const summary = lines[0]?.trim().slice(0, 120) ?? identity.frontmatter.title;
9346
9377
  results.push({
9347
9378
  agentId,
9348
- title: `${identity.frontmatter.title} (${identity.frontmatter.role.toUpperCase()})`,
9379
+ // User-facing/team-facing title only. `frontmatter.role` is internal
9380
+ // routing metadata and must not leak as an external title.
9381
+ title: identity.frontmatter.title,
9349
9382
  summary
9350
9383
  });
9351
9384
  }
@@ -10176,7 +10209,7 @@ __export(intercom_queue_exports, {
10176
10209
  queueIntercom: () => queueIntercom,
10177
10210
  readQueue: () => readQueue
10178
10211
  });
10179
- import { readFileSync as readFileSync15, writeFileSync as writeFileSync13, renameSync as renameSync3, existsSync as existsSync19, mkdirSync as mkdirSync13 } from "fs";
10212
+ import { readFileSync as readFileSync15, writeFileSync as writeFileSync13, renameSync as renameSync4, existsSync as existsSync19, mkdirSync as mkdirSync13 } from "fs";
10180
10213
  import path21 from "path";
10181
10214
  import os12 from "os";
10182
10215
  function ensureDir2() {
@@ -10195,7 +10228,7 @@ function writeQueue(queue) {
10195
10228
  ensureDir2();
10196
10229
  const tmp = `${QUEUE_PATH}.tmp`;
10197
10230
  writeFileSync13(tmp, JSON.stringify(queue, null, 2));
10198
- renameSync3(tmp, QUEUE_PATH);
10231
+ renameSync4(tmp, QUEUE_PATH);
10199
10232
  }
10200
10233
  function queueIntercom(targetSession, reason) {
10201
10234
  const queue = readQueue();
@@ -13875,7 +13908,8 @@ __export(employee_templates_exports, {
13875
13908
  });
13876
13909
  function getSessionPrompt(storedPrompt) {
13877
13910
  const markerIndex = storedPrompt.indexOf(PROCEDURES_MARKER);
13878
- const rolePrompt = markerIndex >= 0 ? storedPrompt.slice(0, markerIndex).trimEnd() : storedPrompt;
13911
+ const withoutProcedures = markerIndex >= 0 ? storedPrompt.slice(0, markerIndex).trimEnd() : storedPrompt;
13912
+ const rolePrompt = withoutProcedures.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/, "").replace(/<!--[\s\S]*?-->/g, "").trimStart();
13879
13913
  const globalBlock = getGlobalProceduresBlock();
13880
13914
  return `${globalBlock}${rolePrompt}
13881
13915
  ${BASE_OPERATING_PROCEDURES}`;
@@ -14483,7 +14517,7 @@ __export(exe_rename_exports, {
14483
14517
  main: () => main2,
14484
14518
  renameEmployee: () => renameEmployee
14485
14519
  });
14486
- import { readFileSync as readFileSync21, writeFileSync as writeFileSync17, renameSync as renameSync4, unlinkSync as unlinkSync11, existsSync as existsSync25 } from "fs";
14520
+ import { readFileSync as readFileSync21, writeFileSync as writeFileSync17, renameSync as renameSync5, unlinkSync as unlinkSync11, existsSync as existsSync25 } from "fs";
14487
14521
  import { execSync as execSync11 } from "child_process";
14488
14522
  import path31 from "path";
14489
14523
  import { homedir as homedir4 } from "os";
@@ -14512,7 +14546,8 @@ async function renameEmployee(oldName, newName, opts = {}) {
14512
14546
  const originalName = employee.name;
14513
14547
  const originalPrompt = employee.systemPrompt;
14514
14548
  employee.name = newName;
14515
- employee.systemPrompt = personalizePrompt(originalPrompt, rosterOldName, newName);
14549
+ if (originalPrompt) employee.systemPrompt = personalizePrompt(originalPrompt, rosterOldName, newName);
14550
+ else delete employee.systemPrompt;
14516
14551
  await saveEmployees(employees, rosterPath);
14517
14552
  rollbackStack.push({
14518
14553
  description: "restore roster",
@@ -14530,14 +14565,14 @@ async function renameEmployee(oldName, newName, opts = {}) {
14530
14565
  /^(agent_id:\s*)\S+/m,
14531
14566
  `$1${newName}`
14532
14567
  );
14533
- renameSync4(oldIdentityPath, newIdentityPath);
14568
+ renameSync5(oldIdentityPath, newIdentityPath);
14534
14569
  writeFileSync17(newIdentityPath, updatedContent, "utf-8");
14535
14570
  rollbackStack.push({
14536
14571
  description: "restore identity file",
14537
14572
  undo: () => {
14538
14573
  if (existsSync25(newIdentityPath)) {
14539
14574
  writeFileSync17(newIdentityPath, content, "utf-8");
14540
- renameSync4(newIdentityPath, oldIdentityPath);
14575
+ renameSync5(newIdentityPath, oldIdentityPath);
14541
14576
  }
14542
14577
  }
14543
14578
  });
@@ -14546,12 +14581,12 @@ async function renameEmployee(oldName, newName, opts = {}) {
14546
14581
  const newAgentPath = path31.join(agentsDir, `${newName}.md`);
14547
14582
  if (existsSync25(oldAgentPath)) {
14548
14583
  const agentContent = readFileSync21(oldAgentPath, "utf-8");
14549
- renameSync4(oldAgentPath, newAgentPath);
14584
+ renameSync5(oldAgentPath, newAgentPath);
14550
14585
  rollbackStack.push({
14551
14586
  description: "restore agent file",
14552
14587
  undo: () => {
14553
14588
  if (existsSync25(newAgentPath)) {
14554
- renameSync4(newAgentPath, oldAgentPath);
14589
+ renameSync5(newAgentPath, oldAgentPath);
14555
14590
  writeFileSync17(oldAgentPath, agentContent, "utf-8");
14556
14591
  }
14557
14592
  }
@@ -14680,7 +14715,7 @@ var init_exe_rename = __esm({
14680
14715
  });
14681
14716
 
14682
14717
  // src/lib/model-downloader.ts
14683
- import { createWriteStream, createReadStream as createReadStream2, existsSync as existsSync26, unlinkSync as unlinkSync12, renameSync as renameSync5 } from "fs";
14718
+ import { createWriteStream, createReadStream as createReadStream2, existsSync as existsSync26, unlinkSync as unlinkSync12, renameSync as renameSync6 } from "fs";
14684
14719
  import { mkdir as mkdir6 } from "fs/promises";
14685
14720
  import { createHash as createHash4 } from "crypto";
14686
14721
  import path32 from "path";
@@ -14738,7 +14773,7 @@ async function downloadModel(opts) {
14738
14773
  `SHA256 mismatch: expected ${EXPECTED_SHA256}, got ${actualHash}`
14739
14774
  );
14740
14775
  }
14741
- renameSync5(tmpPath, destPath);
14776
+ renameSync6(tmpPath, destPath);
14742
14777
  return destPath;
14743
14778
  } catch (err) {
14744
14779
  lastErr = err instanceof Error ? err : new Error(String(err));
@@ -15542,8 +15577,8 @@ async function validateModel(log) {
15542
15577
  log("Skipping in-memory model validation (low memory \u2014 will validate on first use).");
15543
15578
  const modelPath = path34.join(MODELS_DIR, LOCAL_FILENAME);
15544
15579
  if (existsSync28(modelPath)) {
15545
- const { statSync: statSync4 } = await import("fs");
15546
- const size = statSync4(modelPath).size;
15580
+ const { statSync: statSync5 } = await import("fs");
15581
+ const size = statSync5(modelPath).size;
15547
15582
  if (size > 300 * 1e6) {
15548
15583
  log(`Model file verified (${(size / 1e6).toFixed(0)} MB).`);
15549
15584
  return;
@@ -15964,15 +15999,9 @@ async function runSetupWizard(opts = {}) {
15964
15999
  cooName = (cooNameInput || DEFAULT_COORDINATOR_TEMPLATE_NAME2).toLowerCase();
15965
16000
  let employees = await loadEmployees2(EMPLOYEES_PATH2).catch(() => []);
15966
16001
  if (!employees.some((e) => e.name === cooName)) {
15967
- const { DEFAULT_EXE: DEFAULT_EXE2, personalizePrompt: personalizePrompt2 } = await Promise.resolve().then(() => (init_employee_templates(), employee_templates_exports));
15968
16002
  const cooEmployee = {
15969
16003
  name: cooName,
15970
16004
  role: "COO",
15971
- systemPrompt: personalizePrompt2(
15972
- DEFAULT_EXE2.systemPrompt,
15973
- DEFAULT_COORDINATOR_TEMPLATE_NAME2,
15974
- cooName
15975
- ),
15976
16005
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
15977
16006
  templateName: DEFAULT_COORDINATOR_TEMPLATE_NAME2,
15978
16007
  templateVersion: 1
@@ -16066,12 +16095,12 @@ async function runSetupWizard(opts = {}) {
16066
16095
  const ctoNameInput = await ask2(rl, `Name your CTO (default: ${ctoDefault}): `);
16067
16096
  const ctoName = (ctoNameInput || ctoDefault).toLowerCase();
16068
16097
  if (!employees.some((e) => e.name === ctoName)) {
16069
- const { personalizePrompt: personalizeCto } = await Promise.resolve().then(() => (init_employee_templates(), employee_templates_exports));
16070
16098
  const ctoEmployee = {
16071
16099
  name: ctoName,
16072
16100
  role: "CTO",
16073
- systemPrompt: personalizeCto(ctoTemplate?.systemPrompt ?? "", ctoDefault, ctoName),
16074
- createdAt: (/* @__PURE__ */ new Date()).toISOString()
16101
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
16102
+ templateName: ctoDefault,
16103
+ templateVersion: 1
16075
16104
  };
16076
16105
  employees = addEmployee2(employees, ctoEmployee);
16077
16106
  await saveEmployees2(employees, EMPLOYEES_PATH2);
@@ -16089,12 +16118,12 @@ async function runSetupWizard(opts = {}) {
16089
16118
  const cmoNameInput = await ask2(rl, `Name your CMO (default: ${cmoDefault}): `);
16090
16119
  const cmoName = (cmoNameInput || cmoDefault).toLowerCase();
16091
16120
  if (!employees.some((e) => e.name === cmoName)) {
16092
- const { personalizePrompt: personalizeCmo } = await Promise.resolve().then(() => (init_employee_templates(), employee_templates_exports));
16093
16121
  const cmoEmployee = {
16094
16122
  name: cmoName,
16095
16123
  role: "CMO",
16096
- systemPrompt: personalizeCmo(cmoTemplate?.systemPrompt ?? "", cmoDefault, cmoName),
16097
- createdAt: (/* @__PURE__ */ new Date()).toISOString()
16124
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
16125
+ templateName: cmoDefault,
16126
+ templateVersion: 1
16098
16127
  };
16099
16128
  employees = addEmployee2(employees, cmoEmployee);
16100
16129
  await saveEmployees2(employees, EMPLOYEES_PATH2);
@@ -16217,7 +16246,21 @@ function resolveDataDir2() {
16217
16246
  if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
16218
16247
  return path35.join(os17.homedir(), ".exe-os");
16219
16248
  }
16220
- async function createUpdateBackup(currentVersion, dataDir) {
16249
+ function externalBackupTargets(homeDir) {
16250
+ return [
16251
+ { name: "claude.json", path: path35.join(homeDir, ".claude.json") },
16252
+ { name: "claude-settings.json", path: path35.join(homeDir, ".claude", "settings.json") },
16253
+ { name: "claude-CLAUDE.md", path: path35.join(homeDir, ".claude", "CLAUDE.md") },
16254
+ { name: "tmux.conf", path: path35.join(homeDir, ".tmux.conf") },
16255
+ { name: "zshrc", path: path35.join(homeDir, ".zshrc") },
16256
+ { name: "bashrc", path: path35.join(homeDir, ".bashrc") },
16257
+ { name: "ghostty-config", path: path35.join(homeDir, ".config", "ghostty", "config") },
16258
+ { name: "codex-config.toml", path: path35.join(homeDir, ".codex", "config.toml") },
16259
+ { name: "codex-hooks.json", path: path35.join(homeDir, ".codex", "hooks.json") },
16260
+ { name: "opencode-config.json", path: path35.join(homeDir, ".config", "opencode", "opencode.json") }
16261
+ ];
16262
+ }
16263
+ async function createUpdateBackup(currentVersion, dataDir, homeDir = os17.homedir()) {
16221
16264
  const dir = dataDir ?? resolveDataDir2();
16222
16265
  const backupDir = path35.join(dir, BACKUP_DIR_NAME);
16223
16266
  if (existsSync29(backupDir)) {
@@ -16245,10 +16288,19 @@ async function createUpdateBackup(currentVersion, dataDir) {
16245
16288
  backedUpFiles.push(entry.name);
16246
16289
  }
16247
16290
  }
16291
+ const externalFiles = [];
16292
+ const externalDir = path35.join(backupDir, "external");
16293
+ for (const target of externalBackupTargets(homeDir)) {
16294
+ if (!existsSync29(target.path)) continue;
16295
+ await mkdir7(externalDir, { recursive: true });
16296
+ await copyFile(target.path, path35.join(externalDir, target.name));
16297
+ externalFiles.push(target);
16298
+ }
16248
16299
  const manifest = {
16249
16300
  version: currentVersion,
16250
16301
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
16251
- files: backedUpFiles
16302
+ files: backedUpFiles,
16303
+ ...externalFiles.length > 0 ? { externalFiles } : {}
16252
16304
  };
16253
16305
  await writeFile7(
16254
16306
  path35.join(backupDir, "manifest.json"),
@@ -16279,6 +16331,12 @@ async function restoreFromBackup(dataDir) {
16279
16331
  await copyFile(src, dest);
16280
16332
  }
16281
16333
  }
16334
+ for (const external of manifest.externalFiles ?? []) {
16335
+ const src = path35.join(backupDir, "external", external.name);
16336
+ if (!existsSync29(src)) continue;
16337
+ await mkdir7(path35.dirname(external.path), { recursive: true });
16338
+ await copyFile(src, external.path);
16339
+ }
16282
16340
  return manifest;
16283
16341
  }
16284
16342
  async function deleteBackup(dataDir) {
@@ -16296,8 +16354,12 @@ var init_update_backup = __esm({
16296
16354
  BACKUP_TARGETS = [
16297
16355
  { name: "config.json", type: "file" },
16298
16356
  { name: "exe-employees.json", type: "file" },
16357
+ { name: "agent-config.json", type: "file" },
16299
16358
  { name: "master.key", type: "file" },
16300
- { name: "identity", type: "dir" }
16359
+ { name: "tmux.conf", type: "file" },
16360
+ { name: "identity", type: "dir" },
16361
+ { name: "shards", type: "dir" },
16362
+ { name: "mcp-configs", type: "dir" }
16301
16363
  // All .db files (SQLCipher databases) — matched dynamically
16302
16364
  ];
16303
16365
  }
@@ -16536,7 +16598,7 @@ var init_update = __esm({
16536
16598
 
16537
16599
  // src/lib/stack-update.ts
16538
16600
  import { execFileSync as execFileSync3 } from "child_process";
16539
- import { existsSync as existsSync30, mkdirSync as mkdirSync19, readFileSync as readFileSync25, renameSync as renameSync6, writeFileSync as writeFileSync20 } from "fs";
16601
+ import { existsSync as existsSync30, mkdirSync as mkdirSync19, readFileSync as readFileSync25, renameSync as renameSync7, writeFileSync as writeFileSync20 } from "fs";
16540
16602
  import http from "http";
16541
16603
  import https from "https";
16542
16604
  import path37 from "path";
@@ -16644,7 +16706,7 @@ async function runStackUpdate(options) {
16644
16706
  const patched = patchEnv(envRaw, updates);
16645
16707
  const tmp = `${options.envFile}.tmp-${process.pid}`;
16646
16708
  writeFileSync20(tmp, patched, { mode: 384 });
16647
- renameSync6(tmp, options.envFile);
16709
+ renameSync7(tmp, options.envFile);
16648
16710
  const composeArgs = ["compose", "--file", options.composeFile, "--env-file", options.envFile];
16649
16711
  try {
16650
16712
  exec2("docker", [...composeArgs, "pull"]);
@@ -32111,7 +32173,7 @@ async function runActivate(key) {
32111
32173
  }
32112
32174
  const { saveLicense: saveLicense2, mirrorLicenseKey: mirrorLicenseKey2, validateLicense: validateLicense2 } = await Promise.resolve().then(() => (init_license(), license_exports));
32113
32175
  const { loadEmployees: loadEmployees2, saveEmployees: saveEmployees2, addEmployee: addEmployee2, registerBinSymlinks: registerBinSymlinks2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
32114
- const { getTemplateByRole: getTemplateByRole2, personalizePrompt: personalizePrompt2 } = await Promise.resolve().then(() => (init_employee_templates(), employee_templates_exports));
32176
+ const { getTemplateByRole: getTemplateByRole2 } = await Promise.resolve().then(() => (init_employee_templates(), employee_templates_exports));
32115
32177
  const { getTemplate: getIdentityTemplate } = await Promise.resolve().then(() => (init_identity_templates(), identity_templates_exports));
32116
32178
  const { identityPath: identityPath2 } = await Promise.resolve().then(() => (init_identity(), identity_exports));
32117
32179
  const { createInterface: createInterface5 } = await import("readline");
@@ -32143,7 +32205,8 @@ async function runActivate(key) {
32143
32205
  if (create3.toLowerCase() === "n") return;
32144
32206
  const nameInput = await ask3(`Name your ${role} [${defaultName}]: `);
32145
32207
  const name = nameInput || defaultName;
32146
- const emp = { ...template, name, systemPrompt: personalizePrompt2(template.systemPrompt, template.name, name), createdAt: (/* @__PURE__ */ new Date()).toISOString() };
32208
+ const { systemPrompt: _templatePrompt, ...templateMeta } = template;
32209
+ const emp = { ...templateMeta, name, createdAt: (/* @__PURE__ */ new Date()).toISOString() };
32147
32210
  employees = addEmployee2(employees, emp);
32148
32211
  await saveEmployees2(employees);
32149
32212
  registerBinSymlinks2(name);
@@ -107,7 +107,7 @@ var init_config = __esm({
107
107
 
108
108
  // src/bin/exe-agent.ts
109
109
  import { createInterface } from "readline";
110
- import { readFileSync as readFileSync3 } from "fs";
110
+ import { existsSync as existsSync4, readFileSync as readFileSync3 } from "fs";
111
111
  import path10 from "path";
112
112
  import os5 from "os";
113
113
 
@@ -1613,7 +1613,8 @@ When you need to assign work to another employee (e.g., CTO assigns to an engine
1613
1613
  var PROCEDURES_MARKER = "EXE OS \u2014 VISION AND NON-NEGOTIABLE PRINCIPLES";
1614
1614
  function getSessionPrompt(storedPrompt) {
1615
1615
  const markerIndex = storedPrompt.indexOf(PROCEDURES_MARKER);
1616
- const rolePrompt = markerIndex >= 0 ? storedPrompt.slice(0, markerIndex).trimEnd() : storedPrompt;
1616
+ const withoutProcedures = markerIndex >= 0 ? storedPrompt.slice(0, markerIndex).trimEnd() : storedPrompt;
1617
+ const rolePrompt = withoutProcedures.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/, "").replace(/<!--[\s\S]*?-->/g, "").trimStart();
1617
1618
  const globalBlock = getGlobalProceduresBlock();
1618
1619
  return `${globalBlock}${rolePrompt}
1619
1620
  ${BASE_OPERATING_PROCEDURES}`;
@@ -2259,9 +2260,16 @@ function parseArgs(argv) {
2259
2260
  }
2260
2261
  function loadEmployee(name) {
2261
2262
  try {
2263
+ const identityPath = path10.join(os5.homedir(), ".exe-os", "identity", `${name}.md`);
2262
2264
  const rosterPath = path10.join(os5.homedir(), ".exe-os", "exe-employees.json");
2263
2265
  const roster = JSON.parse(readFileSync3(rosterPath, "utf8"));
2264
- return roster.find((e) => e.name.toLowerCase() === name.toLowerCase()) ?? null;
2266
+ const employee = roster.find((e) => e.name.toLowerCase() === name.toLowerCase());
2267
+ if (!employee) return null;
2268
+ if (existsSync4(identityPath)) {
2269
+ const identity = readFileSync3(identityPath, "utf8").trim();
2270
+ if (identity.length > 0) return { role: employee.role, systemPrompt: identity };
2271
+ }
2272
+ return employee.systemPrompt ? { role: employee.role, systemPrompt: employee.systemPrompt } : null;
2265
2273
  } catch {
2266
2274
  return null;
2267
2275
  }
@@ -2751,7 +2751,7 @@ __export(shard_manager_exports, {
2751
2751
  shardExists: () => shardExists
2752
2752
  });
2753
2753
  import path7 from "path";
2754
- import { existsSync as existsSync7, mkdirSync as mkdirSync2, readdirSync } from "fs";
2754
+ import { existsSync as existsSync7, mkdirSync as mkdirSync2, readdirSync, renameSync as renameSync3, statSync as statSync2 } from "fs";
2755
2755
  import { createClient as createClient2 } from "@libsql/client";
2756
2756
  function initShardManager(encryptionKey) {
2757
2757
  _encryptionKey = encryptionKey;
@@ -2773,7 +2773,7 @@ function getShardClient(projectName) {
2773
2773
  if (!_encryptionKey) {
2774
2774
  throw new Error("Shard manager not initialized. Call initShardManager() first.");
2775
2775
  }
2776
- const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
2776
+ const safeName = safeShardName(projectName);
2777
2777
  if (!safeName || safeName === "unknown") {
2778
2778
  throw new Error(`Invalid project name for shard: "${projectName}" (resolved to "${safeName}")`);
2779
2779
  }
@@ -2795,9 +2795,12 @@ function getShardClient(projectName) {
2795
2795
  return client;
2796
2796
  }
2797
2797
  function shardExists(projectName) {
2798
- const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
2798
+ const safeName = safeShardName(projectName);
2799
2799
  return existsSync7(path7.join(SHARDS_DIR, `${safeName}.db`));
2800
2800
  }
2801
+ function safeShardName(projectName) {
2802
+ return projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
2803
+ }
2801
2804
  function listShards() {
2802
2805
  if (!existsSync7(SHARDS_DIR)) return [];
2803
2806
  return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
@@ -2891,7 +2894,8 @@ async function ensureShardSchema(client) {
2891
2894
  "ALTER TABLE memories ADD COLUMN token_cost REAL",
2892
2895
  "ALTER TABLE memories ADD COLUMN audience TEXT",
2893
2896
  "ALTER TABLE memories ADD COLUMN language_type TEXT",
2894
- "ALTER TABLE memories ADD COLUMN parent_memory_id TEXT"
2897
+ "ALTER TABLE memories ADD COLUMN parent_memory_id TEXT",
2898
+ "ALTER TABLE memories ADD COLUMN deleted_at TEXT"
2895
2899
  ]) {
2896
2900
  try {
2897
2901
  await client.execute(col);
@@ -2987,9 +2991,32 @@ async function ensureShardSchema(client) {
2987
2991
  }
2988
2992
  }
2989
2993
  async function getReadyShardClient(projectName) {
2990
- const client = getShardClient(projectName);
2991
- await ensureShardSchema(client);
2992
- return client;
2994
+ const safeName = safeShardName(projectName);
2995
+ let client = getShardClient(projectName);
2996
+ try {
2997
+ await ensureShardSchema(client);
2998
+ return client;
2999
+ } catch (err) {
3000
+ const message = err instanceof Error ? err.message : String(err);
3001
+ if (!/SQLITE_NOTADB|file is not a database/i.test(message)) throw err;
3002
+ client.close();
3003
+ _shards.delete(safeName);
3004
+ _shardLastAccess.delete(safeName);
3005
+ const dbPath = path7.join(SHARDS_DIR, `${safeName}.db`);
3006
+ if (existsSync7(dbPath)) {
3007
+ const stat = statSync2(dbPath);
3008
+ const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
3009
+ const archivedPath = path7.join(SHARDS_DIR, `${safeName}.db.broken-${stamp}`);
3010
+ renameSync3(dbPath, archivedPath);
3011
+ process.stderr.write(
3012
+ `[shard-manager] Archived unreadable shard ${safeName}: ${archivedPath} (${stat.size} bytes, mtime ${stat.mtime.toISOString()})
3013
+ `
3014
+ );
3015
+ }
3016
+ client = getShardClient(projectName);
3017
+ await ensureShardSchema(client);
3018
+ return client;
3019
+ }
2993
3020
  }
2994
3021
  function evictLRU() {
2995
3022
  let oldest = null;