@askexenow/exe-os 0.9.113 → 0.9.115

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 (86) hide show
  1. package/dist/bin/agentic-ontology-backfill.js +36 -12
  2. package/dist/bin/agentic-reflection-backfill.js +36 -12
  3. package/dist/bin/agentic-semantic-label.js +36 -12
  4. package/dist/bin/backfill-conversations.js +36 -12
  5. package/dist/bin/backfill-responses.js +36 -12
  6. package/dist/bin/backfill-vectors.js +36 -12
  7. package/dist/bin/bulk-sync-postgres.js +36 -12
  8. package/dist/bin/cleanup-stale-review-tasks.js +470 -113
  9. package/dist/bin/cli.js +413 -62
  10. package/dist/bin/exe-agent.js +27 -0
  11. package/dist/bin/exe-assign.js +36 -12
  12. package/dist/bin/exe-boot.js +246 -54
  13. package/dist/bin/exe-call.js +8 -0
  14. package/dist/bin/exe-cloud.js +47 -12
  15. package/dist/bin/exe-dispatch.js +348 -53
  16. package/dist/bin/exe-doctor.js +51 -13
  17. package/dist/bin/exe-export-behaviors.js +37 -12
  18. package/dist/bin/exe-forget.js +36 -12
  19. package/dist/bin/exe-gateway.js +348 -53
  20. package/dist/bin/exe-heartbeat.js +471 -113
  21. package/dist/bin/exe-kill.js +36 -12
  22. package/dist/bin/exe-launch-agent.js +117 -18
  23. package/dist/bin/exe-new-employee.js +9 -1
  24. package/dist/bin/exe-pending-messages.js +452 -95
  25. package/dist/bin/exe-pending-notifications.js +452 -95
  26. package/dist/bin/exe-pending-reviews.js +452 -95
  27. package/dist/bin/exe-rename.js +36 -12
  28. package/dist/bin/exe-review.js +36 -12
  29. package/dist/bin/exe-search.js +37 -12
  30. package/dist/bin/exe-session-cleanup.js +348 -53
  31. package/dist/bin/exe-settings.js +12 -0
  32. package/dist/bin/exe-start-codex.js +46 -13
  33. package/dist/bin/exe-start-opencode.js +46 -13
  34. package/dist/bin/exe-status.js +460 -114
  35. package/dist/bin/exe-support.js +12 -0
  36. package/dist/bin/exe-team.js +36 -12
  37. package/dist/bin/git-sweep.js +348 -53
  38. package/dist/bin/graph-backfill.js +36 -12
  39. package/dist/bin/graph-export.js +36 -12
  40. package/dist/bin/install.js +9 -1
  41. package/dist/bin/intercom-check.js +255 -53
  42. package/dist/bin/scan-tasks.js +348 -53
  43. package/dist/bin/setup.js +74 -12
  44. package/dist/bin/shard-migrate.js +36 -12
  45. package/dist/gateway/index.js +348 -53
  46. package/dist/hooks/bug-report-worker.js +348 -53
  47. package/dist/hooks/codex-stop-task-finalizer.js +308 -37
  48. package/dist/hooks/commit-complete.js +348 -53
  49. package/dist/hooks/error-recall.js +37 -12
  50. package/dist/hooks/ingest.js +363 -54
  51. package/dist/hooks/instructions-loaded.js +36 -12
  52. package/dist/hooks/notification.js +36 -12
  53. package/dist/hooks/post-compact.js +426 -72
  54. package/dist/hooks/post-tool-combined.js +501 -146
  55. package/dist/hooks/pre-compact.js +348 -53
  56. package/dist/hooks/pre-tool-use.js +92 -13
  57. package/dist/hooks/prompt-submit.js +348 -53
  58. package/dist/hooks/session-end.js +158 -53
  59. package/dist/hooks/session-start.js +66 -13
  60. package/dist/hooks/stop.js +420 -72
  61. package/dist/hooks/subagent-stop.js +419 -72
  62. package/dist/hooks/summary-worker.js +442 -121
  63. package/dist/index.js +375 -53
  64. package/dist/lib/agent-config.js +8 -0
  65. package/dist/lib/cloud-sync.js +35 -12
  66. package/dist/lib/config.js +13 -0
  67. package/dist/lib/consolidation.js +9 -1
  68. package/dist/lib/embedder.js +13 -0
  69. package/dist/lib/employees.js +8 -0
  70. package/dist/lib/exe-daemon.js +524 -60
  71. package/dist/lib/hybrid-search.js +37 -12
  72. package/dist/lib/keychain.js +25 -13
  73. package/dist/lib/messaging.js +395 -74
  74. package/dist/lib/schedules.js +36 -12
  75. package/dist/lib/skill-learning.js +21 -0
  76. package/dist/lib/store.js +36 -12
  77. package/dist/lib/tasks.js +324 -41
  78. package/dist/lib/tmux-routing.js +324 -41
  79. package/dist/mcp/server.js +374 -54
  80. package/dist/mcp/tools/create-task.js +324 -41
  81. package/dist/mcp/tools/list-tasks.js +406 -57
  82. package/dist/mcp/tools/send-message.js +395 -74
  83. package/dist/mcp/tools/update-task.js +324 -41
  84. package/dist/runtime/index.js +375 -53
  85. package/dist/tui/App.js +377 -55
  86. package/package.json +1 -1
@@ -139,6 +139,17 @@ function normalizeOrchestration(raw) {
139
139
  const userOrg = raw.orchestration ?? {};
140
140
  raw.orchestration = { ...defaultOrg, ...userOrg };
141
141
  }
142
+ function normalizeCloudEndpoint(raw) {
143
+ const cloud = raw.cloud;
144
+ if (!cloud?.endpoint) return;
145
+ const ep = String(cloud.endpoint);
146
+ if (ep === "https://askexe.com/cloud" || ep === "https://askexe.com/cloud/") {
147
+ cloud.endpoint = "https://cloud.askexe.com";
148
+ process.stderr.write(
149
+ "[config] Auto-migrated cloud endpoint: askexe.com/cloud \u2192 cloud.askexe.com\n"
150
+ );
151
+ }
152
+ }
142
153
  async function loadConfig() {
143
154
  const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
144
155
  await ensurePrivateDir(dir);
@@ -164,6 +175,7 @@ async function loadConfig() {
164
175
  normalizeSessionLifecycle(migratedCfg);
165
176
  normalizeAutoUpdate(migratedCfg);
166
177
  normalizeOrchestration(migratedCfg);
178
+ normalizeCloudEndpoint(migratedCfg);
167
179
  const config = { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db"), ...migratedCfg };
168
180
  if (config.dbPath.startsWith("~")) {
169
181
  config.dbPath = config.dbPath.replace(/^~/, os.homedir());
@@ -370,6 +382,7 @@ __export(agent_config_exports, {
370
382
  clearAgentRuntime: () => clearAgentRuntime,
371
383
  getAgentRuntime: () => getAgentRuntime,
372
384
  loadAgentConfig: () => loadAgentConfig,
385
+ normalizeCcModelName: () => normalizeCcModelName,
373
386
  saveAgentConfig: () => saveAgentConfig,
374
387
  setAgentMcps: () => setAgentMcps,
375
388
  setAgentRuntime: () => setAgentRuntime
@@ -398,6 +411,13 @@ function getAgentRuntime(agentId) {
398
411
  if (orgDefault) return orgDefault;
399
412
  return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
400
413
  }
414
+ function normalizeCcModelName(model) {
415
+ let ccModel = model.replace(/(\d+)\.(\d+)/g, "$1-$2");
416
+ if (/claude-(opus|sonnet)-4-[6-9]/.test(ccModel) && !ccModel.includes("[1m]")) {
417
+ ccModel += "[1m]";
418
+ }
419
+ return ccModel;
420
+ }
401
421
  function setAgentRuntime(agentId, runtime, model, reasoning_effort, mcps) {
402
422
  const knownModels = KNOWN_RUNTIMES[runtime];
403
423
  if (!knownModels) {
@@ -3980,6 +4000,21 @@ function isRootSession(name) {
3980
4000
  function extractRootExe(name) {
3981
4001
  if (!name) return null;
3982
4002
  if (!name.includes("-")) return name;
4003
+ try {
4004
+ const roster = (init_employees(), __toCommonJS(employees_exports)).loadEmployeesSync();
4005
+ if (roster.length > 0) {
4006
+ const sortedNames = roster.map((e) => e.name).sort((a, b) => b.length - a.length);
4007
+ for (const agentName of sortedNames) {
4008
+ const escaped = agentName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
4009
+ const regex = new RegExp(`^${escaped}\\d*-(.+)$`);
4010
+ const match = name.match(regex);
4011
+ if (match) {
4012
+ return extractRootExe(match[1]);
4013
+ }
4014
+ }
4015
+ }
4016
+ } catch {
4017
+ }
3983
4018
  const parts = name.split("-").filter(Boolean);
3984
4019
  return parts.length > 0 ? parts[parts.length - 1] : null;
3985
4020
  }
@@ -3998,6 +4033,10 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
3998
4033
  function getParentExe(sessionKey) {
3999
4034
  try {
4000
4035
  const data = JSON.parse(readFileSync10(path13.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
4036
+ if (data.registeredAt) {
4037
+ const age = Date.now() - new Date(data.registeredAt).getTime();
4038
+ if (age > PARENT_EXE_CACHE_TTL_MS) return null;
4039
+ }
4001
4040
  return data.parentExe || null;
4002
4041
  } catch {
4003
4042
  return null;
@@ -4070,7 +4109,7 @@ function resolveExeSession() {
4070
4109
  }
4071
4110
  return candidate;
4072
4111
  }
4073
- var SPAWN_LOCK_DIR, SESSION_CACHE, INTERCOM_LOG2, DEBOUNCE_FILE, DEBOUNCE_CLEANUP_AGE_MS;
4112
+ var SPAWN_LOCK_DIR, SESSION_CACHE, PARENT_EXE_CACHE_TTL_MS, INTERCOM_LOG2, DEBOUNCE_FILE, DEBOUNCE_CLEANUP_AGE_MS;
4074
4113
  var init_tmux_routing = __esm({
4075
4114
  "src/lib/tmux-routing.ts"() {
4076
4115
  "use strict";
@@ -4088,6 +4127,7 @@ var init_tmux_routing = __esm({
4088
4127
  init_agent_symlinks();
4089
4128
  SPAWN_LOCK_DIR = path13.join(os9.homedir(), ".exe-os", "spawn-locks");
4090
4129
  SESSION_CACHE = path13.join(os9.homedir(), ".exe-os", "session-cache");
4130
+ PARENT_EXE_CACHE_TTL_MS = 4 * 60 * 60 * 1e3;
4091
4131
  INTERCOM_LOG2 = path13.join(os9.homedir(), ".exe-os", "intercom.log");
4092
4132
  DEBOUNCE_FILE = path13.join(SESSION_CACHE, "intercom-debounce.json");
4093
4133
  DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
@@ -4303,7 +4343,7 @@ var init_cto_delegation_gate = __esm({
4303
4343
  });
4304
4344
 
4305
4345
  // src/lib/keychain.ts
4306
- import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
4346
+ import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2, rename, copyFile } from "fs/promises";
4307
4347
  import { existsSync as existsSync14, statSync as statSync4 } from "fs";
4308
4348
  import { execSync as execSync6 } from "child_process";
4309
4349
  import path15 from "path";
@@ -4338,12 +4378,14 @@ function linuxSecretAvailable() {
4338
4378
  function isRootOnlyTrustedServerKeyFile(keyPath) {
4339
4379
  if (process.platform !== "linux") return false;
4340
4380
  try {
4341
- const uid = typeof os11.userInfo().uid === "number" ? os11.userInfo().uid : -1;
4342
4381
  const st = statSync4(keyPath);
4343
4382
  if (!st.isFile() || (st.mode & 63) !== 0) return false;
4383
+ const uid = typeof os11.userInfo().uid === "number" ? os11.userInfo().uid : -1;
4344
4384
  if (uid === 0) return true;
4345
4385
  const exeOsDir = process.env.EXE_OS_DIR;
4346
- return Boolean(exeOsDir && path15.resolve(keyPath).startsWith(path15.resolve(exeOsDir) + path15.sep));
4386
+ if (exeOsDir && path15.resolve(keyPath).startsWith(path15.resolve(exeOsDir) + path15.sep)) return true;
4387
+ if (!linuxSecretAvailable()) return true;
4388
+ return false;
4347
4389
  } catch {
4348
4390
  return false;
4349
4391
  }
@@ -4493,15 +4535,25 @@ async function writeMachineBoundFileFallback(b64) {
4493
4535
  await mkdir3(dir, { recursive: true });
4494
4536
  const keyPath = getKeyPath();
4495
4537
  const machineKey = deriveMachineKey();
4496
- if (machineKey) {
4497
- const encrypted = encryptWithMachineKey(b64, machineKey);
4498
- await writeFile3(keyPath, encrypted + "\n", "utf-8");
4499
- await chmod2(keyPath, 384);
4500
- return "encrypted";
4538
+ const content = machineKey ? encryptWithMachineKey(b64, machineKey) + "\n" : b64 + "\n";
4539
+ const result = machineKey ? "encrypted" : "plaintext";
4540
+ const tmpPath = keyPath + ".tmp";
4541
+ try {
4542
+ if (existsSync14(keyPath)) {
4543
+ await copyFile(keyPath, keyPath + ".bak").catch(() => {
4544
+ });
4545
+ }
4546
+ await writeFile3(tmpPath, content, "utf-8");
4547
+ await chmod2(tmpPath, 384);
4548
+ await rename(tmpPath, keyPath);
4549
+ } catch (err) {
4550
+ try {
4551
+ await unlink(tmpPath);
4552
+ } catch {
4553
+ }
4554
+ throw err;
4501
4555
  }
4502
- await writeFile3(keyPath, b64 + "\n", "utf-8");
4503
- await chmod2(keyPath, 384);
4504
- return "plaintext";
4556
+ return result;
4505
4557
  }
4506
4558
  async function getMasterKey() {
4507
4559
  let nativeValue = macKeychainGet() ?? linuxSecretGet();
@@ -4568,7 +4620,7 @@ async function getMasterKey() {
4568
4620
  b64Value = content;
4569
4621
  }
4570
4622
  const key = Buffer.from(b64Value, "base64");
4571
- if (!content.startsWith(ENCRYPTED_PREFIX) && isRootOnlyTrustedServerKeyFile(keyPath)) {
4623
+ if (isRootOnlyTrustedServerKeyFile(keyPath)) {
4572
4624
  return key;
4573
4625
  }
4574
4626
  const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
@@ -7352,6 +7404,33 @@ Do NOT report this as successful. No file was changed. If you are a sub-agent, r
7352
7404
  } catch {
7353
7405
  }
7354
7406
  }
7407
+ if (data.tool_name === "Bash") {
7408
+ const command = String(data.tool_input?.command ?? "");
7409
+ if (command) {
7410
+ const mcpBypassPatterns = [
7411
+ { regex: /\bsqlite3\b.*\b(memories\.db|\.exe-os)\b/, reason: "Direct SQLite access to exe-os database" },
7412
+ { regex: /\bnode\s+-e\b.*\b(better-sqlite3|libsql|sqlite3)\b/, reason: "Inline Node.js script accessing SQLite" },
7413
+ { regex: /\brequire\s*\(\s*['"].*memories\.db['"]\s*\)/, reason: "Direct require of memories database" }
7414
+ ];
7415
+ for (const { regex, reason } of mcpBypassPatterns) {
7416
+ if (regex.test(command)) {
7417
+ process.stderr.write(
7418
+ `[pre-tool-use] MCP bypass BLOCKED: ${reason}
7419
+ `
7420
+ );
7421
+ const output = JSON.stringify({
7422
+ hookSpecificOutput: { permissionDecision: "deny" },
7423
+ systemMessage: `BLOCKED: ${reason}.
7424
+ The exe-os database is encrypted and must ONLY be accessed through MCP tools.
7425
+ If MCP is disconnected, tell the user: "MCP server is disconnected. Please run /mcp to reconnect."
7426
+ Do NOT attempt workarounds \u2014 direct DB access bypasses encryption, breaks data integrity, and violates the contract boundary.`
7427
+ });
7428
+ process.stdout.write(output);
7429
+ process.exit(0);
7430
+ }
7431
+ }
7432
+ }
7433
+ }
7355
7434
  } catch {
7356
7435
  }
7357
7436
  clearTimeout(timeout);