@askexenow/exe-os 0.9.69 → 0.9.71

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 (79) hide show
  1. package/deploy/stack-manifests/v0.9.json +96 -16
  2. package/dist/bin/agentic-ontology-backfill.js +33 -0
  3. package/dist/bin/agentic-reflection-backfill.js +33 -0
  4. package/dist/bin/agentic-semantic-label.js +33 -0
  5. package/dist/bin/backfill-conversations.js +33 -0
  6. package/dist/bin/backfill-responses.js +33 -0
  7. package/dist/bin/backfill-vectors.js +33 -0
  8. package/dist/bin/bulk-sync-postgres.js +33 -0
  9. package/dist/bin/cleanup-stale-review-tasks.js +33 -0
  10. package/dist/bin/cli.js +1284 -178
  11. package/dist/bin/exe-agent.js +6 -0
  12. package/dist/bin/exe-assign.js +33 -0
  13. package/dist/bin/exe-boot.js +33 -0
  14. package/dist/bin/exe-call.js +6 -0
  15. package/dist/bin/exe-cloud.js +33 -0
  16. package/dist/bin/exe-dispatch.js +33 -0
  17. package/dist/bin/exe-doctor.js +33 -0
  18. package/dist/bin/exe-export-behaviors.js +33 -0
  19. package/dist/bin/exe-forget.js +33 -0
  20. package/dist/bin/exe-gateway.js +178 -110
  21. package/dist/bin/exe-heartbeat.js +33 -0
  22. package/dist/bin/exe-kill.js +33 -0
  23. package/dist/bin/exe-launch-agent.js +33 -0
  24. package/dist/bin/exe-new-employee.js +6 -0
  25. package/dist/bin/exe-pending-messages.js +33 -0
  26. package/dist/bin/exe-pending-notifications.js +33 -0
  27. package/dist/bin/exe-pending-reviews.js +33 -0
  28. package/dist/bin/exe-rename.js +40 -4
  29. package/dist/bin/exe-review.js +33 -0
  30. package/dist/bin/exe-search.js +33 -0
  31. package/dist/bin/exe-session-cleanup.js +33 -0
  32. package/dist/bin/exe-start-codex.js +33 -0
  33. package/dist/bin/exe-start-opencode.js +33 -0
  34. package/dist/bin/exe-status.js +33 -0
  35. package/dist/bin/exe-team.js +33 -0
  36. package/dist/bin/git-sweep.js +33 -0
  37. package/dist/bin/graph-backfill.js +177 -110
  38. package/dist/bin/graph-export.js +33 -0
  39. package/dist/bin/intercom-check.js +33 -0
  40. package/dist/bin/registry-proxy.js +207 -0
  41. package/dist/bin/scan-tasks.js +33 -0
  42. package/dist/bin/setup.js +33 -0
  43. package/dist/bin/shard-migrate.js +33 -0
  44. package/dist/bin/stack-update.js +128 -0
  45. package/dist/gateway/index.js +178 -110
  46. package/dist/hooks/bug-report-worker.js +33 -0
  47. package/dist/hooks/codex-stop-task-finalizer.js +33 -0
  48. package/dist/hooks/commit-complete.js +33 -0
  49. package/dist/hooks/error-recall.js +33 -0
  50. package/dist/hooks/ingest.js +33 -0
  51. package/dist/hooks/instructions-loaded.js +33 -0
  52. package/dist/hooks/notification.js +33 -0
  53. package/dist/hooks/post-compact.js +33 -0
  54. package/dist/hooks/post-tool-combined.js +698 -17
  55. package/dist/hooks/pre-compact.js +33 -0
  56. package/dist/hooks/pre-tool-use.js +33 -0
  57. package/dist/hooks/prompt-submit.js +314 -0
  58. package/dist/hooks/session-end.js +33 -0
  59. package/dist/hooks/session-start.js +33 -0
  60. package/dist/hooks/stop.js +279 -12
  61. package/dist/hooks/subagent-stop.js +33 -0
  62. package/dist/hooks/summary-worker.js +33 -0
  63. package/dist/index.js +178 -110
  64. package/dist/lib/cloud-sync.js +27 -0
  65. package/dist/lib/database.js +27 -0
  66. package/dist/lib/db.js +27 -0
  67. package/dist/lib/device-registry.js +27 -0
  68. package/dist/lib/employee-templates.js +6 -0
  69. package/dist/lib/exe-daemon.js +639 -259
  70. package/dist/lib/hybrid-search.js +33 -0
  71. package/dist/lib/registry-proxy.js +162 -0
  72. package/dist/lib/schedules.js +33 -0
  73. package/dist/lib/store.js +33 -0
  74. package/dist/mcp/server.js +561 -244
  75. package/dist/runtime/index.js +33 -0
  76. package/dist/tui/App.js +33 -0
  77. package/package.json +3 -2
  78. package/stack.release.json +6 -4
  79. package/stack.release.schema.json +89 -18
@@ -1,5 +1,7 @@
1
1
  var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
2
3
  var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
3
5
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
4
6
  get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
5
7
  }) : x)(function(x) {
@@ -13,6 +15,15 @@ var __export = (target, all) => {
13
15
  for (var name in all)
14
16
  __defProp(target, name, { get: all[name], enumerable: true });
15
17
  };
18
+ var __copyProps = (to, from, except, desc) => {
19
+ if (from && typeof from === "object" || typeof from === "function") {
20
+ for (let key of __getOwnPropNames(from))
21
+ if (!__hasOwnProp.call(to, key) && key !== except)
22
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
23
+ }
24
+ return to;
25
+ };
26
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
16
27
 
17
28
  // src/lib/secure-files.ts
18
29
  import { chmodSync, existsSync, mkdirSync } from "fs";
@@ -1218,6 +1229,17 @@ var init_daemon_auth = __esm({
1218
1229
  });
1219
1230
 
1220
1231
  // src/lib/exe-daemon-client.ts
1232
+ var exe_daemon_client_exports = {};
1233
+ __export(exe_daemon_client_exports, {
1234
+ connectEmbedDaemon: () => connectEmbedDaemon,
1235
+ disconnectClient: () => disconnectClient,
1236
+ embedBatchViaClient: () => embedBatchViaClient,
1237
+ embedViaClient: () => embedViaClient,
1238
+ isClientConnected: () => isClientConnected,
1239
+ pingDaemon: () => pingDaemon,
1240
+ sendDaemonRequest: () => sendDaemonRequest,
1241
+ sendIngestRequest: () => sendIngestRequest
1242
+ });
1221
1243
  import net from "net";
1222
1244
  import os4 from "os";
1223
1245
  import { spawn } from "child_process";
@@ -1285,8 +1307,8 @@ function findPackageRoot() {
1285
1307
  function getAvailableMemoryGB() {
1286
1308
  if (process.platform === "darwin") {
1287
1309
  try {
1288
- const { execSync: execSync7 } = __require("child_process");
1289
- const vmstat = execSync7("vm_stat", { encoding: "utf8" });
1310
+ const { execSync: execSync8 } = __require("child_process");
1311
+ const vmstat = execSync8("vm_stat", { encoding: "utf8" });
1290
1312
  const pageSize = 16384;
1291
1313
  const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
1292
1314
  const actualPageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : pageSize;
@@ -1606,6 +1628,15 @@ async function embedViaClient(text, priority = "high") {
1606
1628
  );
1607
1629
  return !result.error && result.vectors?.[0] ? result.vectors[0] : null;
1608
1630
  }
1631
+ async function embedBatchViaClient(texts, priority = "high") {
1632
+ if (!_connected && !await connectEmbedDaemon()) return null;
1633
+ _requestCount++;
1634
+ const result = await retryThenRestart(
1635
+ () => sendRequest(texts, priority),
1636
+ "Batch embed"
1637
+ );
1638
+ return !result.error && result.vectors ? result.vectors : null;
1639
+ }
1609
1640
  function disconnectClient() {
1610
1641
  if (_socket) {
1611
1642
  _socket.destroy();
@@ -1622,6 +1653,17 @@ function disconnectClient() {
1622
1653
  function isClientConnected() {
1623
1654
  return _connected;
1624
1655
  }
1656
+ function sendIngestRequest(payload) {
1657
+ if (!_socket || !_connected) return false;
1658
+ try {
1659
+ const id = randomUUID();
1660
+ const token = process.env[DAEMON_TOKEN_ENV] ?? readDaemonToken();
1661
+ _socket.write(JSON.stringify({ id, token, type: "ingest", ...payload }) + "\n");
1662
+ return true;
1663
+ } catch {
1664
+ return false;
1665
+ }
1666
+ }
1625
1667
  var SOCKET_PATH, PID_PATH, SPAWN_LOCK_PATH, SPAWN_LOCK_STALE_MS, CONNECT_TIMEOUT_MS, REQUEST_TIMEOUT_MS, DAEMON_TOKEN_ENV, _socket, _connected, _buffer, _requestCount, _consecutiveFailures, HEALTH_CHECK_INTERVAL, MAX_RETRIES_BEFORE_RESTART, RETRY_DELAYS_MS, MIN_DAEMON_AGE_MS, _pending, MAX_BUFFER;
1626
1668
  var init_exe_daemon_client = __esm({
1627
1669
  "src/lib/exe-daemon-client.ts"() {
@@ -1650,6 +1692,15 @@ var init_exe_daemon_client = __esm({
1650
1692
  });
1651
1693
 
1652
1694
  // src/lib/daemon-protocol.ts
1695
+ var daemon_protocol_exports = {};
1696
+ __export(daemon_protocol_exports, {
1697
+ deserializeArgs: () => deserializeArgs,
1698
+ deserializeResultSet: () => deserializeResultSet,
1699
+ deserializeValue: () => deserializeValue,
1700
+ serializeArgs: () => serializeArgs,
1701
+ serializeResultSet: () => serializeResultSet,
1702
+ serializeValue: () => serializeValue
1703
+ });
1653
1704
  function serializeValue(v) {
1654
1705
  if (v === null || v === void 0) return null;
1655
1706
  if (typeof v === "bigint") return Number(v);
@@ -1674,6 +1725,32 @@ function deserializeValue(v) {
1674
1725
  }
1675
1726
  return v;
1676
1727
  }
1728
+ function serializeArgs(args) {
1729
+ return args.map(serializeValue);
1730
+ }
1731
+ function deserializeArgs(args) {
1732
+ return args.map(deserializeValue);
1733
+ }
1734
+ function serializeResultSet(rs) {
1735
+ const rows = [];
1736
+ for (const row of rs.rows) {
1737
+ const obj = {};
1738
+ for (let i = 0; i < rs.columns.length; i++) {
1739
+ const col = rs.columns[i];
1740
+ if (col !== void 0) {
1741
+ obj[col] = serializeValue(row[i]);
1742
+ }
1743
+ }
1744
+ rows.push(obj);
1745
+ }
1746
+ return {
1747
+ columns: [...rs.columns],
1748
+ columnTypes: [...rs.columnTypes ?? []],
1749
+ rows,
1750
+ rowsAffected: typeof rs.rowsAffected === "bigint" ? Number(rs.rowsAffected) : rs.rowsAffected ?? 0,
1751
+ lastInsertRowid: rs.lastInsertRowid != null ? typeof rs.lastInsertRowid === "bigint" ? Number(rs.lastInsertRowid) : rs.lastInsertRowid : null
1752
+ };
1753
+ }
1677
1754
  function deserializeResultSet(srs) {
1678
1755
  const rows = srs.rows.map((obj) => {
1679
1756
  const values = srs.columns.map(
@@ -2613,6 +2690,33 @@ async function ensureSchema() {
2613
2690
  CREATE INDEX IF NOT EXISTS idx_chat_history_session
2614
2691
  ON chat_history(session_id, id);
2615
2692
  `);
2693
+ await client.executeMultiple(`
2694
+ CREATE TABLE IF NOT EXISTS session_events (
2695
+ id TEXT PRIMARY KEY,
2696
+ agent_id TEXT NOT NULL,
2697
+ agent_role TEXT NOT NULL,
2698
+ session_id TEXT NOT NULL,
2699
+ session_scope TEXT,
2700
+ project_name TEXT NOT NULL,
2701
+ event_index INTEGER NOT NULL,
2702
+ event_type TEXT NOT NULL,
2703
+ tool_name TEXT,
2704
+ tool_use_id TEXT,
2705
+ content TEXT NOT NULL,
2706
+ payload_json TEXT,
2707
+ has_error INTEGER NOT NULL DEFAULT 0,
2708
+ created_at TEXT NOT NULL
2709
+ );
2710
+
2711
+ CREATE INDEX IF NOT EXISTS idx_session_events_agent_time
2712
+ ON session_events(agent_id, created_at DESC);
2713
+
2714
+ CREATE INDEX IF NOT EXISTS idx_session_events_session_index
2715
+ ON session_events(session_id, event_index);
2716
+
2717
+ CREATE INDEX IF NOT EXISTS idx_session_events_scope_agent_time
2718
+ ON session_events(session_scope, agent_id, created_at DESC);
2719
+ `);
2616
2720
  await client.executeMultiple(`
2617
2721
  CREATE TABLE IF NOT EXISTS workspaces (
2618
2722
  id TEXT PRIMARY KEY,
@@ -3380,8 +3484,8 @@ function deriveMachineKey() {
3380
3484
  }
3381
3485
  function readMachineId() {
3382
3486
  try {
3383
- const { readFileSync: readFileSync8 } = __require("fs");
3384
- return readFileSync8("/etc/machine-id", "utf-8").trim();
3487
+ const { readFileSync: readFileSync13 } = __require("fs");
3488
+ return readFileSync13("/etc/machine-id", "utf-8").trim();
3385
3489
  } catch {
3386
3490
  return "";
3387
3491
  }
@@ -4301,6 +4405,12 @@ var init_platform_procedures = __esm({
4301
4405
  priority: "p0",
4302
4406
  content: "exe-build-adv is MANDATORY for ALL work touching 3+ files. Run /exe-build-adv --auto BEFORE implementation. Pipeline: Spec \u2192 AC \u2192 Tests \u2192 Evaluate \u2192 Fix. No multi-file feature ships without pipeline artifacts. No exceptions \u2014 managers reject work without them."
4303
4407
  },
4408
+ {
4409
+ title: "Code context first for repository orientation",
4410
+ domain: "workflow",
4411
+ priority: "p1",
4412
+ content: "Before broad repo exploration, symbol tracing, blast-radius review, or codebase Q&A, agents should use the consolidated code_context MCP tool instead of manual grep/read loops. Use action=index or stats to refresh/check the index; action=search with query, limit, offset, languages, paths, refresh_index for fresh multi-language code/doc search; action=trace for symbol imports/dependents; action=blast_radius for impact analysis before edits. CLI parity exists via exe-os code-context init|index|status|stats|search|doctor. Keep code_context separate from durable employee memory: promote only validated decisions, procedures, or lessons into store_memory/commit_memory."
4413
+ },
4304
4414
  {
4305
4415
  title: "Commit discipline \u2014 never leave verified work floating",
4306
4416
  domain: "workflow",
@@ -5770,10 +5880,10 @@ async function disposeEmbedder() {
5770
5880
  async function embedDirect(text) {
5771
5881
  const llamaCpp = await import("node-llama-cpp");
5772
5882
  const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
5773
- const { existsSync: existsSync11 } = await import("fs");
5774
- const path13 = await import("path");
5775
- const modelPath = path13.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
5776
- if (!existsSync11(modelPath)) {
5883
+ const { existsSync: existsSync17 } = await import("fs");
5884
+ const path20 = await import("path");
5885
+ const modelPath = path20.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
5886
+ if (!existsSync17(modelPath)) {
5777
5887
  throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
5778
5888
  }
5779
5889
  const llama = await llamaCpp.getLlama();
@@ -6864,10 +6974,10 @@ async function hybridSearch(queryText, agentId, options) {
6864
6974
  };
6865
6975
  try {
6866
6976
  const fs = await import("fs");
6867
- const path13 = await import("path");
6868
- const os6 = await import("os");
6869
- const logPath = path13.join(os6.homedir(), ".exe-os", "search-quality.jsonl");
6870
- fs.mkdirSync(path13.dirname(logPath), { recursive: true });
6977
+ const path20 = await import("path");
6978
+ const os11 = await import("os");
6979
+ const logPath = path20.join(os11.homedir(), ".exe-os", "search-quality.jsonl");
6980
+ fs.mkdirSync(path20.dirname(logPath), { recursive: true });
6871
6981
  fs.appendFileSync(logPath, JSON.stringify(logEntry) + "\n");
6872
6982
  } catch {
6873
6983
  }
@@ -7401,8 +7511,8 @@ function findContainingChunk(filePath, snippet) {
7401
7511
  try {
7402
7512
  const ext = filePath.split(".").pop()?.toLowerCase();
7403
7513
  if (ext !== "ts" && ext !== "tsx" && ext !== "js" && ext !== "jsx") return "";
7404
- const { readFileSync: readFileSync8 } = __require("fs");
7405
- const source = readFileSync8(filePath, "utf8");
7514
+ const { readFileSync: readFileSync13 } = __require("fs");
7515
+ const source = readFileSync13(filePath, "utf8");
7406
7516
  const lines = source.split("\n");
7407
7517
  const lowerSnippet = snippet.toLowerCase().slice(0, 80);
7408
7518
  let matchLine = -1;
@@ -7468,9 +7578,9 @@ function extractBash(input2, response) {
7468
7578
  }
7469
7579
  function extractGrep(input2, response) {
7470
7580
  const pattern = String(input2.pattern ?? "");
7471
- const path13 = input2.path ? String(input2.path) : "";
7581
+ const path20 = input2.path ? String(input2.path) : "";
7472
7582
  const output = String(response.text ?? response.content ?? JSON.stringify(response).slice(0, MAX_OUTPUT));
7473
- return `Searched for "${pattern}"${path13 ? ` in ${path13}` : ""}
7583
+ return `Searched for "${pattern}"${path20 ? ` in ${path20}` : ""}
7474
7584
  ${output.slice(0, MAX_OUTPUT)}`;
7475
7585
  }
7476
7586
  function extractGlob(input2, response) {
@@ -7875,6 +7985,551 @@ var init_active_agent2 = __esm({
7875
7985
  }
7876
7986
  });
7877
7987
 
7988
+ // src/bin/fast-db-init.ts
7989
+ var fast_db_init_exports = {};
7990
+ __export(fast_db_init_exports, {
7991
+ fastDbInit: () => fastDbInit
7992
+ });
7993
+ async function fastDbInit() {
7994
+ const { isInitialized: isInitialized2, getClient: getClient2, setExternalClient: setExternalClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
7995
+ if (isInitialized2()) {
7996
+ return getClient2();
7997
+ }
7998
+ try {
7999
+ const { connectEmbedDaemon: connectEmbedDaemon2, sendDaemonRequest: sendDaemonRequest2, isClientConnected: isClientConnected2 } = await Promise.resolve().then(() => (init_exe_daemon_client(), exe_daemon_client_exports));
8000
+ const { deserializeResultSet: deserializeResultSet2 } = await Promise.resolve().then(() => (init_daemon_protocol(), daemon_protocol_exports));
8001
+ await connectEmbedDaemon2();
8002
+ if (isClientConnected2()) {
8003
+ const daemonClient = {
8004
+ async execute(stmt) {
8005
+ const sql = typeof stmt === "string" ? stmt : stmt.sql;
8006
+ const args = typeof stmt === "string" ? [] : Array.isArray(stmt.args) ? stmt.args : [];
8007
+ const resp = await sendDaemonRequest2({ type: "db-execute", sql, args });
8008
+ if (resp.error) throw new Error(String(resp.error));
8009
+ if (resp.db) return deserializeResultSet2(resp.db);
8010
+ throw new Error("Unexpected daemon response");
8011
+ },
8012
+ async batch(stmts, mode) {
8013
+ const statements = stmts.map((s) => {
8014
+ const sql = typeof s === "string" ? s : s.sql;
8015
+ const args = typeof s === "string" ? [] : Array.isArray(s.args) ? s.args : [];
8016
+ return { sql, args };
8017
+ });
8018
+ const resp = await sendDaemonRequest2({ type: "db-batch", statements, mode: mode ?? "deferred" });
8019
+ if (resp.error) throw new Error(String(resp.error));
8020
+ const batchResults = resp["db-batch"];
8021
+ if (batchResults) return batchResults.map(deserializeResultSet2);
8022
+ throw new Error("Unexpected daemon batch response");
8023
+ },
8024
+ async transaction(_mode) {
8025
+ throw new Error("Transactions not supported via daemon socket");
8026
+ },
8027
+ async executeMultiple(_sql) {
8028
+ throw new Error("executeMultiple not supported via daemon socket");
8029
+ },
8030
+ async migrate(_stmts) {
8031
+ throw new Error("migrate not supported via daemon socket");
8032
+ },
8033
+ sync() {
8034
+ return Promise.resolve(void 0);
8035
+ },
8036
+ close() {
8037
+ },
8038
+ get closed() {
8039
+ return false;
8040
+ },
8041
+ get protocol() {
8042
+ return "file";
8043
+ }
8044
+ };
8045
+ setExternalClient2(daemonClient);
8046
+ return daemonClient;
8047
+ }
8048
+ } catch {
8049
+ }
8050
+ const { initStore: initStore2 } = await Promise.resolve().then(() => (init_store(), store_exports));
8051
+ await initStore2({ lightweight: true });
8052
+ return getClient2();
8053
+ }
8054
+ var init_fast_db_init = __esm({
8055
+ "src/bin/fast-db-init.ts"() {
8056
+ "use strict";
8057
+ }
8058
+ });
8059
+
8060
+ // src/lib/session-registry.ts
8061
+ import path13 from "path";
8062
+ import os6 from "os";
8063
+ var REGISTRY_PATH;
8064
+ var init_session_registry = __esm({
8065
+ "src/lib/session-registry.ts"() {
8066
+ "use strict";
8067
+ REGISTRY_PATH = path13.join(os6.homedir(), ".exe-os", "session-registry.json");
8068
+ }
8069
+ });
8070
+
8071
+ // src/lib/tmux-transport.ts
8072
+ var tmux_transport_exports = {};
8073
+ __export(tmux_transport_exports, {
8074
+ TmuxTransport: () => TmuxTransport
8075
+ });
8076
+ import { execFileSync } from "child_process";
8077
+ var QUIET, TmuxTransport;
8078
+ var init_tmux_transport = __esm({
8079
+ "src/lib/tmux-transport.ts"() {
8080
+ "use strict";
8081
+ QUIET = {
8082
+ encoding: "utf8",
8083
+ stdio: ["pipe", "pipe", "pipe"]
8084
+ };
8085
+ TmuxTransport = class {
8086
+ getMySession() {
8087
+ try {
8088
+ return execFileSync("tmux", ["display-message", "-p", "#{session_name}"], QUIET).trim() || null;
8089
+ } catch {
8090
+ return null;
8091
+ }
8092
+ }
8093
+ listSessions() {
8094
+ try {
8095
+ return execFileSync("tmux", ["list-sessions", "-F", "#{session_name}"], QUIET).trim().split("\n").filter(Boolean);
8096
+ } catch {
8097
+ return [];
8098
+ }
8099
+ }
8100
+ isAlive(target) {
8101
+ try {
8102
+ const sessions = this.listSessions();
8103
+ if (!sessions.includes(target)) return false;
8104
+ const paneStatus = execFileSync(
8105
+ "tmux",
8106
+ ["list-panes", "-t", target, "-F", "#{pane_dead}"],
8107
+ QUIET
8108
+ ).trim();
8109
+ return paneStatus !== "1";
8110
+ } catch {
8111
+ return false;
8112
+ }
8113
+ }
8114
+ sendKeys(target, keys) {
8115
+ execFileSync("tmux", ["send-keys", "-t", target, keys, "Enter"], QUIET);
8116
+ }
8117
+ /**
8118
+ * Send text as literal characters, then submit with Enter as a separate call.
8119
+ * Fixes Codex intercom bug: long text + Enter in one send-keys blast causes
8120
+ * Codex to drop the Enter. Splitting them ensures the text renders before
8121
+ * the submit keystroke arrives.
8122
+ */
8123
+ sendKeysLiteral(target, text) {
8124
+ execFileSync("tmux", ["send-keys", "-t", target, "-l", text], QUIET);
8125
+ execFileSync("tmux", ["send-keys", "-t", target, "Enter"], QUIET);
8126
+ }
8127
+ capturePane(target, lines) {
8128
+ const args = ["capture-pane", "-t", target, "-p"];
8129
+ if (lines) args.push("-S", `-${lines}`);
8130
+ return execFileSync("tmux", args, { ...QUIET, timeout: 3e3 });
8131
+ }
8132
+ isPaneInCopyMode(target) {
8133
+ try {
8134
+ const result = execFileSync(
8135
+ "tmux",
8136
+ ["display-message", "-p", "-t", target, "#{pane_in_mode}"],
8137
+ { ...QUIET, timeout: 3e3 }
8138
+ ).trim();
8139
+ return result === "1";
8140
+ } catch {
8141
+ return false;
8142
+ }
8143
+ }
8144
+ spawn(name, config) {
8145
+ try {
8146
+ const args = ["new-session", "-d", "-s", name];
8147
+ if (config.cwd) args.push("-c", config.cwd);
8148
+ args.push(config.command);
8149
+ execFileSync("tmux", args);
8150
+ return { sessionName: name };
8151
+ } catch (e) {
8152
+ return { sessionName: name, error: `spawn failed: ${e}` };
8153
+ }
8154
+ }
8155
+ kill(target) {
8156
+ try {
8157
+ execFileSync("tmux", ["kill-session", "-t", target], QUIET);
8158
+ } catch {
8159
+ }
8160
+ }
8161
+ pipeLog(target, logFile) {
8162
+ try {
8163
+ const safePath = logFile.replace(/'/g, "'\\''");
8164
+ execFileSync("tmux", ["pipe-pane", "-t", target, `cat >> '${safePath}'`], QUIET);
8165
+ } catch {
8166
+ }
8167
+ }
8168
+ };
8169
+ }
8170
+ });
8171
+
8172
+ // src/lib/transport.ts
8173
+ function getTransport() {
8174
+ if (!_transport) {
8175
+ const { TmuxTransport: TmuxTransport2 } = (init_tmux_transport(), __toCommonJS(tmux_transport_exports));
8176
+ _transport = new TmuxTransport2();
8177
+ }
8178
+ return _transport;
8179
+ }
8180
+ var _transport;
8181
+ var init_transport = __esm({
8182
+ "src/lib/transport.ts"() {
8183
+ "use strict";
8184
+ _transport = null;
8185
+ }
8186
+ });
8187
+
8188
+ // src/lib/cc-agent-support.ts
8189
+ import { execSync as execSync7 } from "child_process";
8190
+ var init_cc_agent_support = __esm({
8191
+ "src/lib/cc-agent-support.ts"() {
8192
+ "use strict";
8193
+ }
8194
+ });
8195
+
8196
+ // src/lib/provider-table.ts
8197
+ var init_provider_table = __esm({
8198
+ "src/lib/provider-table.ts"() {
8199
+ "use strict";
8200
+ }
8201
+ });
8202
+
8203
+ // src/lib/runtime-table.ts
8204
+ var RUNTIME_TABLE;
8205
+ var init_runtime_table = __esm({
8206
+ "src/lib/runtime-table.ts"() {
8207
+ "use strict";
8208
+ RUNTIME_TABLE = {
8209
+ codex: {
8210
+ binary: "codex",
8211
+ launchMode: "interactive",
8212
+ autoApproveFlag: "--dangerously-bypass-approvals-and-sandbox",
8213
+ inlineFlag: "--no-alt-screen",
8214
+ apiKeyEnv: "OPENAI_API_KEY",
8215
+ defaultModel: "gpt-5.5"
8216
+ },
8217
+ opencode: {
8218
+ binary: "opencode",
8219
+ launchMode: "exec",
8220
+ autoApproveFlag: "--dangerously-skip-permissions",
8221
+ inlineFlag: "",
8222
+ apiKeyEnv: "ANTHROPIC_API_KEY",
8223
+ defaultModel: "anthropic/claude-sonnet-4-6"
8224
+ }
8225
+ };
8226
+ }
8227
+ });
8228
+
8229
+ // src/lib/agent-config.ts
8230
+ import { readFileSync as readFileSync8, writeFileSync as writeFileSync4, existsSync as existsSync11 } from "fs";
8231
+ import path14 from "path";
8232
+ var AGENT_CONFIG_PATH, DEFAULT_MODELS;
8233
+ var init_agent_config = __esm({
8234
+ "src/lib/agent-config.ts"() {
8235
+ "use strict";
8236
+ init_config();
8237
+ init_runtime_table();
8238
+ init_secure_files();
8239
+ AGENT_CONFIG_PATH = path14.join(EXE_AI_DIR, "agent-config.json");
8240
+ DEFAULT_MODELS = {
8241
+ claude: "claude-opus-4.6",
8242
+ codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
8243
+ opencode: RUNTIME_TABLE.opencode?.defaultModel ?? "anthropic/claude-sonnet-4-6"
8244
+ };
8245
+ }
8246
+ });
8247
+
8248
+ // src/lib/intercom-queue.ts
8249
+ import { readFileSync as readFileSync9, writeFileSync as writeFileSync5, renameSync as renameSync5, existsSync as existsSync12, mkdirSync as mkdirSync4 } from "fs";
8250
+ import path15 from "path";
8251
+ import os7 from "os";
8252
+ var QUEUE_PATH2, TTL_MS2, INTERCOM_LOG;
8253
+ var init_intercom_queue = __esm({
8254
+ "src/lib/intercom-queue.ts"() {
8255
+ "use strict";
8256
+ QUEUE_PATH2 = path15.join(os7.homedir(), ".exe-os", "intercom-queue.json");
8257
+ TTL_MS2 = 60 * 60 * 1e3;
8258
+ INTERCOM_LOG = path15.join(os7.homedir(), ".exe-os", "intercom.log");
8259
+ }
8260
+ });
8261
+
8262
+ // src/lib/license.ts
8263
+ import { readFileSync as readFileSync10, writeFileSync as writeFileSync6, existsSync as existsSync13, mkdirSync as mkdirSync5 } from "fs";
8264
+ import { randomUUID as randomUUID3 } from "crypto";
8265
+ import { createRequire as createRequire2 } from "module";
8266
+ import { pathToFileURL as pathToFileURL2 } from "url";
8267
+ import os8 from "os";
8268
+ import path16 from "path";
8269
+ import { jwtVerify, importSPKI } from "jose";
8270
+ var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH;
8271
+ var init_license = __esm({
8272
+ "src/lib/license.ts"() {
8273
+ "use strict";
8274
+ init_config();
8275
+ LICENSE_PATH = path16.join(EXE_AI_DIR, "license.key");
8276
+ CACHE_PATH = path16.join(EXE_AI_DIR, "license-cache.json");
8277
+ DEVICE_ID_PATH = path16.join(EXE_AI_DIR, "device-id");
8278
+ }
8279
+ });
8280
+
8281
+ // src/lib/plan-limits.ts
8282
+ import { readFileSync as readFileSync11, existsSync as existsSync14 } from "fs";
8283
+ import path17 from "path";
8284
+ var CACHE_PATH2;
8285
+ var init_plan_limits = __esm({
8286
+ "src/lib/plan-limits.ts"() {
8287
+ "use strict";
8288
+ init_database();
8289
+ init_employees();
8290
+ init_license();
8291
+ init_config();
8292
+ CACHE_PATH2 = path17.join(EXE_AI_DIR, "license-cache.json");
8293
+ }
8294
+ });
8295
+
8296
+ // src/lib/agent-symlinks.ts
8297
+ import os9 from "os";
8298
+ import path18 from "path";
8299
+ import {
8300
+ existsSync as existsSync15,
8301
+ lstatSync,
8302
+ mkdirSync as mkdirSync6,
8303
+ readlinkSync as readlinkSync2,
8304
+ symlinkSync as symlinkSync2
8305
+ } from "fs";
8306
+ var init_agent_symlinks = __esm({
8307
+ "src/lib/agent-symlinks.ts"() {
8308
+ "use strict";
8309
+ init_employees();
8310
+ }
8311
+ });
8312
+
8313
+ // src/lib/tmux-routing.ts
8314
+ import { readFileSync as readFileSync12, writeFileSync as writeFileSync7, mkdirSync as mkdirSync7, existsSync as existsSync16, appendFileSync as appendFileSync2, readdirSync as readdirSync4 } from "fs";
8315
+ import path19 from "path";
8316
+ import os10 from "os";
8317
+ import { fileURLToPath as fileURLToPath2 } from "url";
8318
+ function getMySession() {
8319
+ return getTransport().getMySession();
8320
+ }
8321
+ function extractRootExe(name) {
8322
+ if (!name) return null;
8323
+ if (!name.includes("-")) return name;
8324
+ const parts = name.split("-").filter(Boolean);
8325
+ return parts.length > 0 ? parts[parts.length - 1] : null;
8326
+ }
8327
+ function getParentExe(sessionKey) {
8328
+ try {
8329
+ const data = JSON.parse(readFileSync12(path19.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
8330
+ return data.parentExe || null;
8331
+ } catch {
8332
+ return null;
8333
+ }
8334
+ }
8335
+ function resolveExeSession() {
8336
+ const mySession = getMySession();
8337
+ if (!mySession) return null;
8338
+ const fromSessionName = extractRootExe(mySession);
8339
+ try {
8340
+ const key = getSessionKey();
8341
+ const parentExe = getParentExe(key);
8342
+ if (parentExe) {
8343
+ const fromCache = extractRootExe(parentExe) ?? parentExe;
8344
+ if (fromSessionName && fromCache !== fromSessionName) {
8345
+ process.stderr.write(
8346
+ `[tmux-routing] WARN: cache says "${fromCache}" but session name says "${fromSessionName}". Trusting session name.
8347
+ `
8348
+ );
8349
+ return fromSessionName;
8350
+ }
8351
+ return fromCache;
8352
+ }
8353
+ } catch {
8354
+ }
8355
+ return fromSessionName ?? mySession;
8356
+ }
8357
+ var SPAWN_LOCK_DIR, SESSION_CACHE, INTERCOM_LOG2, DEBOUNCE_FILE, DEBOUNCE_CLEANUP_AGE_MS;
8358
+ var init_tmux_routing = __esm({
8359
+ "src/lib/tmux-routing.ts"() {
8360
+ "use strict";
8361
+ init_session_registry();
8362
+ init_session_key();
8363
+ init_transport();
8364
+ init_cc_agent_support();
8365
+ init_mcp_prefix();
8366
+ init_provider_table();
8367
+ init_agent_config();
8368
+ init_runtime_table();
8369
+ init_intercom_queue();
8370
+ init_plan_limits();
8371
+ init_employees();
8372
+ init_agent_symlinks();
8373
+ SPAWN_LOCK_DIR = path19.join(os10.homedir(), ".exe-os", "spawn-locks");
8374
+ SESSION_CACHE = path19.join(os10.homedir(), ".exe-os", "session-cache");
8375
+ INTERCOM_LOG2 = path19.join(os10.homedir(), ".exe-os", "intercom.log");
8376
+ DEBOUNCE_FILE = path19.join(SESSION_CACHE, "intercom-debounce.json");
8377
+ DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
8378
+ }
8379
+ });
8380
+
8381
+ // src/lib/task-scope.ts
8382
+ function getCurrentSessionScope() {
8383
+ try {
8384
+ return resolveExeSession();
8385
+ } catch {
8386
+ return null;
8387
+ }
8388
+ }
8389
+ function strictSessionScopeFilter(sessionScope, tableAlias) {
8390
+ const scope = sessionScope !== void 0 ? sessionScope : getCurrentSessionScope();
8391
+ if (!scope) return { sql: "", args: [] };
8392
+ const col = tableAlias ? `${tableAlias}.session_scope` : "session_scope";
8393
+ return {
8394
+ sql: ` AND ${col} = ?`,
8395
+ args: [scope]
8396
+ };
8397
+ }
8398
+ var init_task_scope = __esm({
8399
+ "src/lib/task-scope.ts"() {
8400
+ "use strict";
8401
+ init_tmux_routing();
8402
+ }
8403
+ });
8404
+
8405
+ // src/lib/session-events.ts
8406
+ var session_events_exports = {};
8407
+ __export(session_events_exports, {
8408
+ ensureSessionEventsTable: () => ensureSessionEventsTable,
8409
+ listRecentSessionEvents: () => listRecentSessionEvents,
8410
+ recordSessionEvent: () => recordSessionEvent
8411
+ });
8412
+ import { randomUUID as randomUUID4 } from "crypto";
8413
+ async function ensureSessionEventsTable(client) {
8414
+ await client.execute(`
8415
+ CREATE TABLE IF NOT EXISTS session_events (
8416
+ id TEXT PRIMARY KEY,
8417
+ agent_id TEXT NOT NULL,
8418
+ agent_role TEXT NOT NULL,
8419
+ session_id TEXT NOT NULL,
8420
+ session_scope TEXT,
8421
+ project_name TEXT NOT NULL,
8422
+ event_index INTEGER NOT NULL,
8423
+ event_type TEXT NOT NULL,
8424
+ tool_name TEXT,
8425
+ tool_use_id TEXT,
8426
+ content TEXT NOT NULL,
8427
+ payload_json TEXT,
8428
+ has_error INTEGER NOT NULL DEFAULT 0,
8429
+ created_at TEXT NOT NULL
8430
+ )
8431
+ `);
8432
+ await client.execute(`
8433
+ CREATE INDEX IF NOT EXISTS idx_session_events_agent_time
8434
+ ON session_events(agent_id, created_at DESC)
8435
+ `);
8436
+ await client.execute(`
8437
+ CREATE INDEX IF NOT EXISTS idx_session_events_session_index
8438
+ ON session_events(session_id, event_index)
8439
+ `);
8440
+ await client.execute(`
8441
+ CREATE INDEX IF NOT EXISTS idx_session_events_scope_agent_time
8442
+ ON session_events(session_scope, agent_id, created_at DESC)
8443
+ `);
8444
+ }
8445
+ async function recordSessionEvent(client, input2) {
8446
+ if (!input2.content || input2.content.trim().length === 0) return;
8447
+ await ensureSessionEventsTable(client);
8448
+ const maxResult = await client.execute({
8449
+ sql: "SELECT COALESCE(MAX(event_index), 0) AS max_index FROM session_events WHERE session_id = ?",
8450
+ args: [input2.sessionId]
8451
+ });
8452
+ const currentMax = Number(maxResult.rows[0]?.max_index ?? 0);
8453
+ const eventIndex = Number.isFinite(currentMax) ? currentMax + 1 : 1;
8454
+ await client.execute({
8455
+ sql: `INSERT INTO session_events (
8456
+ id, agent_id, agent_role, session_id, session_scope, project_name,
8457
+ event_index, event_type, tool_name, tool_use_id, content,
8458
+ payload_json, has_error, created_at
8459
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
8460
+ args: [
8461
+ randomUUID4(),
8462
+ input2.agentId,
8463
+ input2.agentRole,
8464
+ input2.sessionId,
8465
+ input2.sessionScope ?? getCurrentSessionScope(),
8466
+ input2.projectName ?? getProjectName(input2.cwd),
8467
+ eventIndex,
8468
+ input2.eventType,
8469
+ input2.toolName ?? null,
8470
+ input2.toolUseId ?? null,
8471
+ input2.content,
8472
+ input2.payloadJson ?? null,
8473
+ input2.hasError ? 1 : 0,
8474
+ input2.timestamp ?? (/* @__PURE__ */ new Date()).toISOString()
8475
+ ]
8476
+ });
8477
+ }
8478
+ async function listRecentSessionEvents(client, options) {
8479
+ await ensureSessionEventsTable(client);
8480
+ const conditions = ["agent_id = ?"];
8481
+ const args = [options.agentId];
8482
+ if (options.sessionId) {
8483
+ conditions.push("session_id = ?");
8484
+ args.push(options.sessionId);
8485
+ }
8486
+ if (options.eventType) {
8487
+ conditions.push("event_type = ?");
8488
+ args.push(options.eventType);
8489
+ }
8490
+ if (options.projectName && options.projectName !== "all") {
8491
+ conditions.push("project_name = ?");
8492
+ args.push(options.projectName);
8493
+ }
8494
+ const scope = strictSessionScopeFilter(options.sessionScope);
8495
+ const where = `WHERE ${conditions.join(" AND ")}${scope.sql}`;
8496
+ args.push(...scope.args);
8497
+ args.push(Math.min(Math.max(options.limit ?? 20, 1), 100));
8498
+ const result = await client.execute({
8499
+ sql: `SELECT id, agent_id, agent_role, session_id, session_scope,
8500
+ project_name, event_index, event_type, tool_name, tool_use_id,
8501
+ content, payload_json, has_error, created_at
8502
+ FROM session_events
8503
+ ${where}
8504
+ ORDER BY created_at DESC, event_index DESC
8505
+ LIMIT ?`,
8506
+ args
8507
+ });
8508
+ return result.rows.map((row) => ({
8509
+ id: String(row.id),
8510
+ agentId: String(row.agent_id),
8511
+ agentRole: String(row.agent_role),
8512
+ sessionId: String(row.session_id),
8513
+ sessionScope: row.session_scope == null ? null : String(row.session_scope),
8514
+ projectName: String(row.project_name),
8515
+ eventIndex: Number(row.event_index),
8516
+ eventType: String(row.event_type),
8517
+ toolName: row.tool_name == null ? null : String(row.tool_name),
8518
+ toolUseId: row.tool_use_id == null ? null : String(row.tool_use_id),
8519
+ content: String(row.content),
8520
+ payloadJson: row.payload_json == null ? null : String(row.payload_json),
8521
+ hasError: Number(row.has_error) === 1,
8522
+ createdAt: String(row.created_at)
8523
+ }));
8524
+ }
8525
+ var init_session_events = __esm({
8526
+ "src/lib/session-events.ts"() {
8527
+ "use strict";
8528
+ init_task_scope();
8529
+ init_project_name();
8530
+ }
8531
+ });
8532
+
7878
8533
  // src/adapters/claude/hooks/post-tool-combined.ts
7879
8534
  if (!process.env.AGENT_ID) {
7880
8535
  process.env.AGENT_ID = "default";
@@ -7924,7 +8579,33 @@ ${context}`
7924
8579
  const { writeMemoryViaDaemon: writeMemoryViaDaemon2 } = await Promise.resolve().then(() => (init_memory_queue_client(), memory_queue_client_exports));
7925
8580
  const { buildPostToolMemoryEntry: buildPostToolMemoryEntry2 } = await Promise.resolve().then(() => (init_post_tool_memory(), post_tool_memory_exports));
7926
8581
  const { getActiveAgent: getActiveAgent2 } = await Promise.resolve().then(() => (init_active_agent2(), active_agent_exports));
7927
- const entry = buildPostToolMemoryEntry2(data, getActiveAgent2());
8582
+ const { detectError: detectError2 } = await Promise.resolve().then(() => (init_error_detector(), error_detector_exports));
8583
+ const agent = getActiveAgent2();
8584
+ try {
8585
+ const { fastDbInit: fastDbInit2 } = await Promise.resolve().then(() => (init_fast_db_init(), fast_db_init_exports));
8586
+ const { recordSessionEvent: recordSessionEvent2 } = await Promise.resolve().then(() => (init_session_events(), session_events_exports));
8587
+ const client = await fastDbInit2();
8588
+ const toolName = String(data.tool_name ?? "unknown");
8589
+ const toolInput = JSON.stringify(data.tool_input ?? {});
8590
+ const toolResponse = JSON.stringify(data.tool_response ?? data.tool_result ?? {});
8591
+ await recordSessionEvent2(client, {
8592
+ agentId: agent.agentId,
8593
+ agentRole: agent.agentRole,
8594
+ sessionId: String(data.session_id ?? "unknown"),
8595
+ eventType: "tool_call",
8596
+ toolName,
8597
+ toolUseId: data.tool_use_id ? String(data.tool_use_id) : null,
8598
+ content: `${toolName}
8599
+ input: ${toolInput.slice(0, 8e3)}
8600
+ result: ${toolResponse.slice(0, 8e3)}`,
8601
+ payloadJson: JSON.stringify(data).slice(0, 3e4),
8602
+ hasError: detectError2(data),
8603
+ cwd: typeof data.cwd === "string" ? data.cwd : process.cwd(),
8604
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
8605
+ });
8606
+ } catch {
8607
+ }
8608
+ const entry = buildPostToolMemoryEntry2(data, agent);
7928
8609
  if (entry) await writeMemoryViaDaemon2(entry);
7929
8610
  } catch {
7930
8611
  }