@askexenow/exe-os 0.8.101 → 0.8.102

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 (44) hide show
  1. package/dist/bin/cleanup-stale-review-tasks.js +1 -1
  2. package/dist/bin/cli.js +265 -84
  3. package/dist/bin/exe-agent-config.js +1 -1
  4. package/dist/bin/exe-boot.js +1 -1
  5. package/dist/bin/exe-dispatch.js +1 -1
  6. package/dist/bin/exe-gateway.js +1 -1
  7. package/dist/bin/exe-heartbeat.js +1 -1
  8. package/dist/bin/exe-pending-messages.js +1 -1
  9. package/dist/bin/exe-pending-reviews.js +1 -1
  10. package/dist/bin/exe-session-cleanup.js +1 -1
  11. package/dist/bin/exe-start-codex.js +298 -31
  12. package/dist/bin/exe-status.js +1 -1
  13. package/dist/bin/git-sweep.js +1 -1
  14. package/dist/bin/scan-tasks.js +1 -1
  15. package/dist/bin/setup.js +6 -9
  16. package/dist/gateway/index.js +1 -1
  17. package/dist/hooks/bug-report-worker.js +1 -1
  18. package/dist/hooks/commit-complete.js +1 -1
  19. package/dist/hooks/ingest-worker.js +1 -1
  20. package/dist/hooks/ingest.js +4 -4
  21. package/dist/hooks/post-compact.js +1 -1
  22. package/dist/hooks/pre-compact.js +1 -1
  23. package/dist/hooks/pre-tool-use.js +1 -1
  24. package/dist/hooks/prompt-submit.js +1 -1
  25. package/dist/hooks/session-end.js +1 -1
  26. package/dist/hooks/session-start.js +1 -1
  27. package/dist/hooks/stop.js +1 -1
  28. package/dist/hooks/subagent-stop.js +1 -1
  29. package/dist/hooks/summary-worker.js +1 -1
  30. package/dist/index.js +1 -1
  31. package/dist/lib/agent-config.js +1 -1
  32. package/dist/lib/exe-daemon.js +1 -1
  33. package/dist/lib/messaging.js +1 -1
  34. package/dist/lib/runtime-table.js +1 -1
  35. package/dist/lib/tasks.js +1 -1
  36. package/dist/lib/tmux-routing.js +1 -1
  37. package/dist/mcp/server.js +1 -1
  38. package/dist/mcp/tools/create-task.js +1 -1
  39. package/dist/mcp/tools/list-tasks.js +1 -1
  40. package/dist/mcp/tools/send-message.js +1 -1
  41. package/dist/mcp/tools/update-task.js +1 -1
  42. package/dist/runtime/index.js +1 -1
  43. package/dist/tui/App.js +1 -1
  44. package/package.json +1 -1
@@ -1939,7 +1939,7 @@ var init_runtime_table = __esm({
1939
1939
  RUNTIME_TABLE = {
1940
1940
  codex: {
1941
1941
  binary: "codex",
1942
- launchMode: "exec",
1942
+ launchMode: "interactive",
1943
1943
  autoApproveFlag: "--full-auto",
1944
1944
  inlineFlag: "--no-alt-screen",
1945
1945
  apiKeyEnv: "OPENAI_API_KEY",
package/dist/bin/cli.js CHANGED
@@ -6802,9 +6802,9 @@ Unclassified: ${unclassified}
6802
6802
  }
6803
6803
  async function exportBatches(options) {
6804
6804
  const fs8 = await import("fs");
6805
- const path39 = await import("path");
6805
+ const path40 = await import("path");
6806
6806
  const client = getClient();
6807
- const outDir = path39.join(process.cwd(), "exe/output/classifications/input");
6807
+ const outDir = path40.join(process.cwd(), "exe/output/classifications/input");
6808
6808
  fs8.mkdirSync(outDir, { recursive: true });
6809
6809
  const countResult = await client.execute({
6810
6810
  sql: "SELECT COUNT(*) as cnt FROM memories WHERE intent IS NULL AND outcome IS NULL AND domain IS NULL",
@@ -6828,7 +6828,7 @@ async function exportBatches(options) {
6828
6828
  const text = String(row.text || "").replace(/\n/g, " ");
6829
6829
  return JSON.stringify({ id: row.id, text });
6830
6830
  });
6831
- const batchFile = path39.join(outDir, `batch-${String(batchNum).padStart(4, "0")}.jsonl`);
6831
+ const batchFile = path40.join(outDir, `batch-${String(batchNum).padStart(4, "0")}.jsonl`);
6832
6832
  fs8.writeFileSync(batchFile, lines.join("\n") + "\n");
6833
6833
  exported += batch.rows.length;
6834
6834
  offset += options.batchSize;
@@ -6844,7 +6844,7 @@ async function exportBatches(options) {
6844
6844
  }
6845
6845
  async function importClassifications(importDir) {
6846
6846
  const fs8 = await import("fs");
6847
- const path39 = await import("path");
6847
+ const path40 = await import("path");
6848
6848
  const client = getClient();
6849
6849
  const files = fs8.readdirSync(importDir).filter((f) => f.endsWith(".jsonl")).sort();
6850
6850
  process.stderr.write(`[backfill-metadata] Found ${files.length} JSONL files to import from ${importDir}
@@ -6852,7 +6852,7 @@ async function importClassifications(importDir) {
6852
6852
  let imported = 0;
6853
6853
  let invalid = 0;
6854
6854
  for (const file of files) {
6855
- const lines = fs8.readFileSync(path39.join(importDir, file), "utf-8").split("\n").filter(Boolean);
6855
+ const lines = fs8.readFileSync(path40.join(importDir, file), "utf-8").split("\n").filter(Boolean);
6856
6856
  for (const line of lines) {
6857
6857
  try {
6858
6858
  const rec = JSON.parse(line);
@@ -7249,7 +7249,7 @@ var init_runtime_table = __esm({
7249
7249
  RUNTIME_TABLE = {
7250
7250
  codex: {
7251
7251
  binary: "codex",
7252
- launchMode: "exec",
7252
+ launchMode: "interactive",
7253
7253
  autoApproveFlag: "--full-auto",
7254
7254
  inlineFlag: "--no-alt-screen",
7255
7255
  apiKeyEnv: "OPENAI_API_KEY",
@@ -11495,10 +11495,10 @@ async function disposeEmbedder() {
11495
11495
  async function embedDirect(text) {
11496
11496
  const llamaCpp = await import("node-llama-cpp");
11497
11497
  const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
11498
- const { existsSync: existsSync26 } = await import("fs");
11499
- const path39 = await import("path");
11500
- const modelPath = path39.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
11501
- if (!existsSync26(modelPath)) {
11498
+ const { existsSync: existsSync27 } = await import("fs");
11499
+ const path40 = await import("path");
11500
+ const modelPath = path40.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
11501
+ if (!existsSync27(modelPath)) {
11502
11502
  throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
11503
11503
  }
11504
11504
  const llama = await llamaCpp.getLlama();
@@ -12994,16 +12994,13 @@ async function runSetupWizard(opts = {}) {
12994
12994
  } catch {
12995
12995
  }
12996
12996
  }
12997
- const W = 27;
12998
- const center = (s) => {
12999
- const pad = W - s.length;
13000
- return " ".repeat(Math.floor(pad / 2)) + s + " ".repeat(Math.ceil(pad / 2));
13001
- };
13002
12997
  log("");
13003
- log(` ${"\u2554" + "\u2550".repeat(W) + "\u2557"}`);
13004
- log(` ${"\u2551" + center("E X E O S") + "\u2551"}`);
13005
- if (version) log(` ${"\u2551" + center(`v${version}`) + "\u2551"}`);
13006
- log(` ${"\u255A" + "\u2550".repeat(W) + "\u255D"}`);
12998
+ log(" \u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588");
12999
+ log(" \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 ");
13000
+ log(" \u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588");
13001
+ log(" \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588");
13002
+ log(" \u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588");
13003
+ if (version) log(`${"".padStart(18)}v${version}`);
13007
13004
  log("");
13008
13005
  log("=== Next Steps ===");
13009
13006
  log("");
@@ -13168,14 +13165,14 @@ async function runUpdate(cliArgs) {
13168
13165
  }
13169
13166
  console.log(" Hooks re-wired, daemon restarted automatically.");
13170
13167
  try {
13171
- const { existsSync: exists, readFileSync: readFile6 } = await import("fs");
13168
+ const { existsSync: exists, readFileSync: readFile7 } = await import("fs");
13172
13169
  const p = await import("path");
13173
13170
  const { homedir: home } = await import("os");
13174
13171
  const exeDir = p.default.join(home(), ".exe-os");
13175
13172
  const licKeyPath = p.default.join(exeDir, "license.key");
13176
13173
  const configPath = p.default.join(exeDir, "config.json");
13177
13174
  if (!exists(licKeyPath) && exists(configPath)) {
13178
- const cfg = JSON.parse(readFile6(configPath, "utf8"));
13175
+ const cfg = JSON.parse(readFile7(configPath, "utf8"));
13179
13176
  const cloud = cfg.cloud;
13180
13177
  if (cloud?.apiKey) {
13181
13178
  const { mirrorLicenseKey: mirrorLicenseKey2 } = await Promise.resolve().then(() => (init_license(), license_exports));
@@ -17560,8 +17557,8 @@ var init_ErrorOverview = __esm({
17560
17557
  "use strict";
17561
17558
  init_Box();
17562
17559
  init_Text();
17563
- cleanupPath = (path39) => {
17564
- return path39?.replace(`file://${cwd()}/`, "");
17560
+ cleanupPath = (path40) => {
17561
+ return path40?.replace(`file://${cwd()}/`, "");
17565
17562
  };
17566
17563
  stackUtils = new StackUtils({
17567
17564
  cwd: cwd(),
@@ -19969,11 +19966,11 @@ function Footer() {
19969
19966
  } catch {
19970
19967
  }
19971
19968
  try {
19972
- const { existsSync: existsSync26 } = await import("fs");
19969
+ const { existsSync: existsSync27 } = await import("fs");
19973
19970
  const { join } = await import("path");
19974
19971
  const home = process.env.HOME ?? "";
19975
19972
  const pidPath = join(home, ".exe-os", "exed.pid");
19976
- setDaemon(existsSync26(pidPath) ? "running" : "stopped");
19973
+ setDaemon(existsSync27(pidPath) ? "running" : "stopped");
19977
19974
  } catch {
19978
19975
  setDaemon("unknown");
19979
19976
  }
@@ -22737,13 +22734,13 @@ function CommandCenterView({
22737
22734
  const { createPermissionsFromPreset: createPermissionsFromPreset2, EMPLOYEE_PERMISSIONS: EMPLOYEE_PERMISSIONS2 } = await Promise.resolve().then(() => (init_permissions(), permissions_exports));
22738
22735
  const { getPresetByRole: getPresetByRole2 } = await Promise.resolve().then(() => (init_permission_presets(), permission_presets_exports));
22739
22736
  const { createDefaultHooks: createDefaultHooks2 } = await Promise.resolve().then(() => (init_hooks(), hooks_exports));
22740
- const { readFileSync: readFileSync23, existsSync: existsSync26 } = await import("fs");
22737
+ const { readFileSync: readFileSync23, existsSync: existsSync27 } = await import("fs");
22741
22738
  const { join } = await import("path");
22742
22739
  const { homedir: homedir8 } = await import("os");
22743
22740
  const configPath = join(homedir8(), ".exe-os", "config.json");
22744
22741
  let failoverChain = ["anthropic", "opencode", "gemini", "openai"];
22745
22742
  let providerConfigs = {};
22746
- if (existsSync26(configPath)) {
22743
+ if (existsSync27(configPath)) {
22747
22744
  try {
22748
22745
  const raw = JSON.parse(readFileSync23(configPath, "utf8"));
22749
22746
  if (Array.isArray(raw.failoverChain)) failoverChain = raw.failoverChain;
@@ -22989,7 +22986,7 @@ function CommandCenterView({
22989
22986
  const { listSessions: listSessions2 } = await Promise.resolve().then(() => (init_session_registry(), session_registry_exports));
22990
22987
  const { listTmuxSessions: listTmuxSessions2, inTmux: inTmux2 } = await Promise.resolve().then(() => (init_tmux_status(), tmux_status_exports));
22991
22988
  const { loadEmployees: loadEmployees2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
22992
- const { existsSync: existsSync26 } = await import("fs");
22989
+ const { existsSync: existsSync27 } = await import("fs");
22993
22990
  const { join } = await import("path");
22994
22991
  const client = getClient2();
22995
22992
  if (!client) {
@@ -23060,7 +23057,7 @@ function CommandCenterView({
23060
23057
  }
23061
23058
  const memoryCount = memoryCounts.get(name) ?? 0;
23062
23059
  const openTaskCount = openTaskCounts.get(name) ?? 0;
23063
- const hasGit = projectDir ? existsSync26(join(projectDir, ".git")) : false;
23060
+ const hasGit = projectDir ? existsSync27(join(projectDir, ".git")) : false;
23064
23061
  const type = hasGit ? "code" : memoryCount > 0 ? "code" : "automation";
23065
23062
  projectList.push({
23066
23063
  projectName: name,
@@ -23085,7 +23082,7 @@ function CommandCenterView({
23085
23082
  setHealth((h) => ({ ...h, memories: Number(totalResult.rows[0]?.cnt ?? 0) }));
23086
23083
  try {
23087
23084
  const pidPath = join(process.env.HOME ?? "", ".exe-os", "exed.pid");
23088
- setHealth((h) => ({ ...h, daemon: existsSync26(pidPath) ? "running" : "stopped" }));
23085
+ setHealth((h) => ({ ...h, daemon: existsSync27(pidPath) ? "running" : "stopped" }));
23089
23086
  } catch {
23090
23087
  }
23091
23088
  const activityResult = await client.execute(
@@ -25096,11 +25093,11 @@ async function loadGatewayConfig() {
25096
25093
  state.running = false;
25097
25094
  }
25098
25095
  try {
25099
- const { existsSync: existsSync26, readFileSync: readFileSync23 } = await import("fs");
25096
+ const { existsSync: existsSync27, readFileSync: readFileSync23 } = await import("fs");
25100
25097
  const { join } = await import("path");
25101
25098
  const home = process.env.HOME ?? "";
25102
25099
  const configPath = join(home, ".exe-os", "gateway.json");
25103
- if (existsSync26(configPath)) {
25100
+ if (existsSync27(configPath)) {
25104
25101
  const raw = JSON.parse(readFileSync23(configPath, "utf8"));
25105
25102
  state.port = raw.port ?? 3100;
25106
25103
  state.gatewayUrl = raw.gatewayUrl ?? "";
@@ -25724,11 +25721,11 @@ function TeamView({ onBack, onViewSessions }) {
25724
25721
  setMembers(teamData);
25725
25722
  setDbError(null);
25726
25723
  try {
25727
- const { existsSync: existsSync26, readFileSync: readFileSync23 } = await import("fs");
25724
+ const { existsSync: existsSync27, readFileSync: readFileSync23 } = await import("fs");
25728
25725
  const { join } = await import("path");
25729
25726
  const home = process.env.HOME ?? "";
25730
25727
  const gatewayConfig = join(home, ".exe-os", "gateway.json");
25731
- if (existsSync26(gatewayConfig)) {
25728
+ if (existsSync27(gatewayConfig)) {
25732
25729
  const raw = JSON.parse(readFileSync23(gatewayConfig, "utf8"));
25733
25730
  if (raw.agents && raw.agents.length > 0) {
25734
25731
  setExternals(raw.agents.map((a) => ({
@@ -25910,8 +25907,8 @@ __export(wiki_client_exports, {
25910
25907
  listDocuments: () => listDocuments,
25911
25908
  listWorkspaces: () => listWorkspaces
25912
25909
  });
25913
- async function wikiFetch(config, path39, method = "GET", body) {
25914
- const url = `${config.baseUrl}/api/v1${path39}`;
25910
+ async function wikiFetch(config, path40, method = "GET", body) {
25911
+ const url = `${config.baseUrl}/api/v1${path40}`;
25915
25912
  const headers = {
25916
25913
  Authorization: `Bearer ${config.apiKey}`,
25917
25914
  "Content-Type": "application/json"
@@ -25944,7 +25941,7 @@ async function wikiFetch(config, path39, method = "GET", body) {
25944
25941
  }
25945
25942
  }
25946
25943
  if (!response.ok) {
25947
- throw new Error(`Wiki API ${method} ${path39}: ${response.status} ${response.statusText}`);
25944
+ throw new Error(`Wiki API ${method} ${path40}: ${response.status} ${response.statusText}`);
25948
25945
  }
25949
25946
  return response.json();
25950
25947
  } finally {
@@ -26554,12 +26551,12 @@ function SettingsView({ onBack }) {
26554
26551
  }
26555
26552
  setProviders(providerList);
26556
26553
  try {
26557
- const { existsSync: existsSync26 } = await import("fs");
26554
+ const { existsSync: existsSync27 } = await import("fs");
26558
26555
  const { join } = await import("path");
26559
26556
  const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
26560
26557
  const cfg = await loadConfig2();
26561
26558
  const home = process.env.HOME ?? "";
26562
- const hasKey = existsSync26(join(home, ".exe-os", "master.key"));
26559
+ const hasKey = existsSync27(join(home, ".exe-os", "master.key"));
26563
26560
  if (cfg.cloud) {
26564
26561
  setCloud({
26565
26562
  configured: true,
@@ -26572,7 +26569,7 @@ function SettingsView({ onBack }) {
26572
26569
  const pidPath = join(home, ".exe-os", "exed.pid");
26573
26570
  let daemon = "unknown";
26574
26571
  try {
26575
- daemon = existsSync26(pidPath) ? "running" : "stopped";
26572
+ daemon = existsSync27(pidPath) ? "running" : "stopped";
26576
26573
  } catch {
26577
26574
  }
26578
26575
  let version = "unknown";
@@ -27195,14 +27192,176 @@ Unhandled rejection: ${reason}
27195
27192
  }
27196
27193
  });
27197
27194
 
27198
- // src/bin/cli.ts
27199
- import { existsSync as existsSync25, readFileSync as readFileSync22, writeFileSync as writeFileSync16, readdirSync as readdirSync8, rmSync } from "fs";
27195
+ // src/adapters/codex/installer.ts
27196
+ var installer_exports2 = {};
27197
+ __export(installer_exports2, {
27198
+ mergeCodexHooks: () => mergeCodexHooks,
27199
+ runCodexInstaller: () => runCodexInstaller,
27200
+ verifyCodexHooks: () => verifyCodexHooks
27201
+ });
27202
+ import { readFile as readFile6, writeFile as writeFile7, mkdir as mkdir7 } from "fs/promises";
27203
+ import { existsSync as existsSync25 } from "fs";
27200
27204
  import path38 from "path";
27201
27205
  import os14 from "os";
27206
+ async function mergeCodexHooks(packageRoot, homeDir = os14.homedir()) {
27207
+ const codexDir = path38.join(homeDir, ".codex");
27208
+ const hooksPath = path38.join(codexDir, "hooks.json");
27209
+ await mkdir7(codexDir, { recursive: true });
27210
+ let hooksJson = {};
27211
+ if (existsSync25(hooksPath)) {
27212
+ try {
27213
+ hooksJson = JSON.parse(await readFile6(hooksPath, "utf-8"));
27214
+ } catch {
27215
+ hooksJson = {};
27216
+ }
27217
+ }
27218
+ if (!hooksJson.hooks) {
27219
+ hooksJson.hooks = {};
27220
+ }
27221
+ const hooksToRegister = [
27222
+ {
27223
+ event: "SessionStart",
27224
+ group: {
27225
+ hooks: [
27226
+ {
27227
+ type: "command",
27228
+ command: `node "${path38.join(packageRoot, "dist", "hooks", "session-start.js")}"`,
27229
+ timeout: 10,
27230
+ statusMessage: "exe-os: loading memory brief"
27231
+ }
27232
+ ]
27233
+ },
27234
+ marker: "dist/hooks/session-start.js"
27235
+ },
27236
+ {
27237
+ event: "PostToolUse",
27238
+ group: {
27239
+ matcher: "Bash|apply_patch|Edit|Write|Read|Glob|Grep|mcp__.*",
27240
+ hooks: [
27241
+ {
27242
+ type: "command",
27243
+ command: `node "${path38.join(packageRoot, "dist", "hooks", "ingest.js")}"`
27244
+ },
27245
+ {
27246
+ type: "command",
27247
+ command: `node "${path38.join(packageRoot, "dist", "hooks", "error-recall.js")}"`
27248
+ }
27249
+ ]
27250
+ },
27251
+ marker: "dist/hooks/ingest.js"
27252
+ },
27253
+ {
27254
+ event: "UserPromptSubmit",
27255
+ group: {
27256
+ hooks: [
27257
+ {
27258
+ type: "command",
27259
+ command: `node "${path38.join(packageRoot, "dist", "hooks", "prompt-submit.js")}"`
27260
+ },
27261
+ {
27262
+ type: "command",
27263
+ command: `node "${path38.join(packageRoot, "dist", "hooks", "exe-heartbeat-hook.js")}"`,
27264
+ timeout: 5
27265
+ }
27266
+ ]
27267
+ },
27268
+ marker: "dist/hooks/prompt-submit.js"
27269
+ },
27270
+ {
27271
+ event: "Stop",
27272
+ group: {
27273
+ hooks: [
27274
+ {
27275
+ type: "command",
27276
+ command: `node "${path38.join(packageRoot, "dist", "hooks", "stop.js")}"`
27277
+ }
27278
+ ]
27279
+ },
27280
+ marker: "dist/hooks/stop.js"
27281
+ },
27282
+ {
27283
+ event: "PreToolUse",
27284
+ group: {
27285
+ matcher: "Bash|apply_patch",
27286
+ hooks: [
27287
+ {
27288
+ type: "command",
27289
+ command: `node "${path38.join(packageRoot, "dist", "hooks", "pre-tool-use.js")}"`
27290
+ }
27291
+ ]
27292
+ },
27293
+ marker: "dist/hooks/pre-tool-use.js"
27294
+ }
27295
+ ];
27296
+ let added = 0;
27297
+ let skipped = 0;
27298
+ for (const { event, group, marker } of hooksToRegister) {
27299
+ if (!hooksJson.hooks[event]) {
27300
+ hooksJson.hooks[event] = [];
27301
+ }
27302
+ const existing = hooksJson.hooks[event];
27303
+ const correctCommand = group.hooks[0]?.command ?? "";
27304
+ const alreadyCorrect = existing.some(
27305
+ (g) => g.hooks.some((h) => h.command === correctCommand)
27306
+ );
27307
+ if (alreadyCorrect) {
27308
+ skipped++;
27309
+ } else {
27310
+ hooksJson.hooks[event] = existing.filter(
27311
+ (g) => !g.hooks.some((h) => h.command.includes(marker))
27312
+ );
27313
+ hooksJson.hooks[event].push(group);
27314
+ added++;
27315
+ }
27316
+ }
27317
+ await writeFile7(hooksPath, JSON.stringify(hooksJson, null, 2) + "\n");
27318
+ return { added, skipped };
27319
+ }
27320
+ function verifyCodexHooks(homeDir = os14.homedir()) {
27321
+ const hooksPath = path38.join(homeDir, ".codex", "hooks.json");
27322
+ if (!existsSync25(hooksPath)) return false;
27323
+ try {
27324
+ const hooksJson = JSON.parse(
27325
+ __require("fs").readFileSync(hooksPath, "utf-8")
27326
+ );
27327
+ if (!hooksJson.hooks) return false;
27328
+ const required = ["SessionStart", "PostToolUse", "UserPromptSubmit", "Stop"];
27329
+ for (const event of required) {
27330
+ const groups = hooksJson.hooks[event];
27331
+ if (!groups || !groups.some(
27332
+ (g) => g.hooks.some((h) => h.command.includes("dist/hooks/"))
27333
+ )) {
27334
+ return false;
27335
+ }
27336
+ }
27337
+ return true;
27338
+ } catch {
27339
+ return false;
27340
+ }
27341
+ }
27342
+ async function runCodexInstaller(homeDir) {
27343
+ const packageRoot = resolvePackageRoot();
27344
+ const result = await mergeCodexHooks(packageRoot, homeDir);
27345
+ process.stderr.write(
27346
+ `[exe-os] Codex hooks: ${result.added} added, ${result.skipped} unchanged
27347
+ `
27348
+ );
27349
+ }
27350
+ var init_installer2 = __esm({
27351
+ "src/adapters/codex/installer.ts"() {
27352
+ "use strict";
27353
+ init_installer();
27354
+ }
27355
+ });
27356
+
27357
+ // src/bin/cli.ts
27358
+ import { existsSync as existsSync26, readFileSync as readFileSync22, writeFileSync as writeFileSync16, readdirSync as readdirSync8, rmSync } from "fs";
27359
+ import path39 from "path";
27360
+ import os15 from "os";
27202
27361
  var args = process.argv.slice(2);
27203
27362
  if (args.includes("--version") || args.includes("-v")) {
27204
27363
  try {
27205
- const pkgPath = path38.join(path38.dirname(new URL(import.meta.url).pathname), "..", "..", "package.json");
27364
+ const pkgPath = path39.join(path39.dirname(new URL(import.meta.url).pathname), "..", "..", "package.json");
27206
27365
  const pkg = JSON.parse(readFileSync22(pkgPath, "utf8"));
27207
27366
  console.log(pkg.version);
27208
27367
  } catch {
@@ -27244,6 +27403,16 @@ if (args.includes("--global")) {
27244
27403
  await runClaudeInstall();
27245
27404
  break;
27246
27405
  }
27406
+ } else if (args[0] === "codex") {
27407
+ const sub = args[1];
27408
+ switch (sub) {
27409
+ case "install":
27410
+ await runCodexInstall();
27411
+ break;
27412
+ default:
27413
+ await runCodexInstall();
27414
+ break;
27415
+ }
27247
27416
  } else if (args[0] === "cloud") {
27248
27417
  const sub = args[1];
27249
27418
  if (sub === "sync") {
@@ -27341,9 +27510,9 @@ ID: ${result.id}`);
27341
27510
  });
27342
27511
  await init_App2().then(() => App_exports);
27343
27512
  } else {
27344
- const claudeDir = path38.join(os14.homedir(), ".claude");
27345
- const settingsPath = path38.join(claudeDir, "settings.json");
27346
- const hasClaudeCode = existsSync25(settingsPath) && (() => {
27513
+ const claudeDir = path39.join(os15.homedir(), ".claude");
27514
+ const settingsPath = path39.join(claudeDir, "settings.json");
27515
+ const hasClaudeCode = existsSync26(settingsPath) && (() => {
27347
27516
  try {
27348
27517
  const raw = readFileSync22(settingsPath, "utf8");
27349
27518
  return raw.includes("exe-os") || raw.includes("exe-mem");
@@ -27354,8 +27523,8 @@ ID: ${result.id}`);
27354
27523
  if (hasClaudeCode) {
27355
27524
  let cooName = "exe";
27356
27525
  try {
27357
- const rosterPath = path38.join(os14.homedir(), ".exe-os", "exe-employees.json");
27358
- if (existsSync25(rosterPath)) {
27526
+ const rosterPath = path39.join(os15.homedir(), ".exe-os", "exe-employees.json");
27527
+ if (existsSync26(rosterPath)) {
27359
27528
  const roster = JSON.parse(readFileSync22(rosterPath, "utf8"));
27360
27529
  const coo = roster.find((e) => e.role === "COO");
27361
27530
  if (coo) cooName = coo.name;
@@ -27395,12 +27564,24 @@ async function runClaudeInstall() {
27395
27564
  process.exit(1);
27396
27565
  }
27397
27566
  }
27567
+ async function runCodexInstall() {
27568
+ const { runCodexInstaller: runCodexInstaller2 } = await Promise.resolve().then(() => (init_installer2(), installer_exports2));
27569
+ try {
27570
+ await runCodexInstaller2();
27571
+ } catch (err) {
27572
+ console.error(
27573
+ "Codex hook installation failed:",
27574
+ err instanceof Error ? err.message : String(err)
27575
+ );
27576
+ process.exit(1);
27577
+ }
27578
+ }
27398
27579
  async function runClaudeCheck() {
27399
- const claudeDir = path38.join(os14.homedir(), ".claude");
27400
- const settingsPath = path38.join(claudeDir, "settings.json");
27401
- const claudeJsonPath = path38.join(os14.homedir(), ".claude.json");
27580
+ const claudeDir = path39.join(os15.homedir(), ".claude");
27581
+ const settingsPath = path39.join(claudeDir, "settings.json");
27582
+ const claudeJsonPath = path39.join(os15.homedir(), ".claude.json");
27402
27583
  let ok = true;
27403
- if (existsSync25(settingsPath)) {
27584
+ if (existsSync26(settingsPath)) {
27404
27585
  let settings;
27405
27586
  try {
27406
27587
  settings = JSON.parse(readFileSync22(settingsPath, "utf8"));
@@ -27429,7 +27610,7 @@ async function runClaudeCheck() {
27429
27610
  console.log("\x1B[31m\u2717\x1B[0m settings.json not found");
27430
27611
  ok = false;
27431
27612
  }
27432
- if (existsSync25(claudeJsonPath)) {
27613
+ if (existsSync26(claudeJsonPath)) {
27433
27614
  let claudeJson;
27434
27615
  try {
27435
27616
  claudeJson = JSON.parse(readFileSync22(claudeJsonPath, "utf8"));
@@ -27451,8 +27632,8 @@ async function runClaudeCheck() {
27451
27632
  console.log("\x1B[31m\u2717\x1B[0m claude.json not found");
27452
27633
  ok = false;
27453
27634
  }
27454
- const skillsDir = path38.join(claudeDir, "skills");
27455
- if (existsSync25(skillsDir)) {
27635
+ const skillsDir = path39.join(claudeDir, "skills");
27636
+ if (existsSync26(skillsDir)) {
27456
27637
  console.log("\x1B[32m\u2713\x1B[0m Slash skills directory exists");
27457
27638
  } else {
27458
27639
  console.log("\x1B[31m\u2717\x1B[0m Slash skills directory missing");
@@ -27468,15 +27649,15 @@ async function runClaudeCheck() {
27468
27649
  async function runClaudeUninstall(flags = []) {
27469
27650
  const dryRun = flags.includes("--dry-run");
27470
27651
  const purge = flags.includes("--purge");
27471
- const homeDir = os14.homedir();
27472
- const claudeDir = path38.join(homeDir, ".claude");
27473
- const settingsPath = path38.join(claudeDir, "settings.json");
27474
- const claudeJsonPath = path38.join(homeDir, ".claude.json");
27475
- const exeOsDir = path38.join(homeDir, ".exe-os");
27652
+ const homeDir = os15.homedir();
27653
+ const claudeDir = path39.join(homeDir, ".claude");
27654
+ const settingsPath = path39.join(claudeDir, "settings.json");
27655
+ const claudeJsonPath = path39.join(homeDir, ".claude.json");
27656
+ const exeOsDir = path39.join(homeDir, ".exe-os");
27476
27657
  let removed = 0;
27477
27658
  const log = (msg) => console.log(dryRun ? `[dry-run] ${msg}` : msg);
27478
27659
  let settings = {};
27479
- if (existsSync25(settingsPath)) {
27660
+ if (existsSync26(settingsPath)) {
27480
27661
  try {
27481
27662
  settings = JSON.parse(readFileSync22(settingsPath, "utf8"));
27482
27663
  } catch {
@@ -27523,7 +27704,7 @@ async function runClaudeUninstall(flags = []) {
27523
27704
  removed++;
27524
27705
  }
27525
27706
  }
27526
- if (existsSync25(claudeJsonPath)) {
27707
+ if (existsSync26(claudeJsonPath)) {
27527
27708
  const raw = readFileSync22(claudeJsonPath, "utf8");
27528
27709
  if (raw.length > 1e6) {
27529
27710
  console.error("claude.json exceeds 1 MB \u2014 skipping parse.");
@@ -27553,14 +27734,14 @@ async function runClaudeUninstall(flags = []) {
27553
27734
  }
27554
27735
  }
27555
27736
  }
27556
- const skillsDir = path38.join(claudeDir, "skills");
27557
- if (existsSync25(skillsDir)) {
27737
+ const skillsDir = path39.join(claudeDir, "skills");
27738
+ if (existsSync26(skillsDir)) {
27558
27739
  let skillCount = 0;
27559
27740
  try {
27560
27741
  const entries = readdirSync8(skillsDir);
27561
27742
  for (const entry of entries) {
27562
27743
  if (entry.startsWith("exe")) {
27563
- const fullPath = path38.join(skillsDir, entry);
27744
+ const fullPath = path39.join(skillsDir, entry);
27564
27745
  if (!dryRun) rmSync(fullPath, { recursive: true, force: true });
27565
27746
  skillCount++;
27566
27747
  }
@@ -27572,8 +27753,8 @@ async function runClaudeUninstall(flags = []) {
27572
27753
  removed++;
27573
27754
  }
27574
27755
  }
27575
- const claudeMdPath = path38.join(claudeDir, "CLAUDE.md");
27576
- if (existsSync25(claudeMdPath)) {
27756
+ const claudeMdPath = path39.join(claudeDir, "CLAUDE.md");
27757
+ if (existsSync26(claudeMdPath)) {
27577
27758
  const content = readFileSync22(claudeMdPath, "utf8");
27578
27759
  const startMarker = "<!-- exe-os:orchestration-start -->";
27579
27760
  const endMarker = "<!-- exe-os:orchestration-end -->";
@@ -27586,14 +27767,14 @@ async function runClaudeUninstall(flags = []) {
27586
27767
  removed++;
27587
27768
  }
27588
27769
  }
27589
- const agentsDir = path38.join(claudeDir, "agents");
27590
- if (existsSync25(agentsDir)) {
27770
+ const agentsDir = path39.join(claudeDir, "agents");
27771
+ if (existsSync26(agentsDir)) {
27591
27772
  let agentCount = 0;
27592
27773
  try {
27593
27774
  const entries = readdirSync8(agentsDir).filter((f) => f.endsWith(".md"));
27594
27775
  let knownNames = /* @__PURE__ */ new Set();
27595
- const rosterPath = path38.join(exeOsDir, "exe-employees.json");
27596
- if (existsSync25(rosterPath)) {
27776
+ const rosterPath = path39.join(exeOsDir, "exe-employees.json");
27777
+ if (existsSync26(rosterPath)) {
27597
27778
  try {
27598
27779
  const roster = JSON.parse(readFileSync22(rosterPath, "utf8"));
27599
27780
  knownNames = new Set(roster.map((e) => e.name));
@@ -27603,7 +27784,7 @@ async function runClaudeUninstall(flags = []) {
27603
27784
  for (const entry of entries) {
27604
27785
  const name = entry.replace(/\.md$/, "");
27605
27786
  if (knownNames.has(name)) {
27606
- if (!dryRun) rmSync(path38.join(agentsDir, entry), { force: true });
27787
+ if (!dryRun) rmSync(path39.join(agentsDir, entry), { force: true });
27607
27788
  agentCount++;
27608
27789
  }
27609
27790
  }
@@ -27614,14 +27795,14 @@ async function runClaudeUninstall(flags = []) {
27614
27795
  removed++;
27615
27796
  }
27616
27797
  }
27617
- const projectsDir = path38.join(claudeDir, "projects");
27618
- if (existsSync25(projectsDir)) {
27798
+ const projectsDir = path39.join(claudeDir, "projects");
27799
+ if (existsSync26(projectsDir)) {
27619
27800
  let projectCount = 0;
27620
27801
  try {
27621
27802
  const projects = readdirSync8(projectsDir);
27622
27803
  for (const proj of projects) {
27623
- const projSettings = path38.join(projectsDir, proj, "settings.json");
27624
- if (!existsSync25(projSettings)) continue;
27804
+ const projSettings = path39.join(projectsDir, proj, "settings.json");
27805
+ if (!existsSync26(projSettings)) continue;
27625
27806
  try {
27626
27807
  const pSettings = JSON.parse(readFileSync22(projSettings, "utf8"));
27627
27808
  let changed = false;
@@ -27657,17 +27838,17 @@ async function runClaudeUninstall(flags = []) {
27657
27838
  };
27658
27839
  const exeBinPath = findExeBin3();
27659
27840
  if (!exeBinPath) throw new Error("exe-os not found in PATH");
27660
- const binDir = path38.dirname(exeBinPath);
27841
+ const binDir = path39.dirname(exeBinPath);
27661
27842
  let symlinkCount = 0;
27662
- const rosterPath = path38.join(exeOsDir, "exe-employees.json");
27663
- if (existsSync25(rosterPath)) {
27843
+ const rosterPath = path39.join(exeOsDir, "exe-employees.json");
27844
+ if (existsSync26(rosterPath)) {
27664
27845
  const roster = JSON.parse(readFileSync22(rosterPath, "utf8"));
27665
27846
  const coordinatorName = roster.find((e) => e.role?.toLowerCase() === "coo")?.name ?? "exe";
27666
27847
  for (const emp of roster) {
27667
27848
  if (emp.name === coordinatorName) continue;
27668
27849
  for (const suffix of ["", "-opencode"]) {
27669
- const linkPath = path38.join(binDir, `${emp.name}${suffix}`);
27670
- if (existsSync25(linkPath)) {
27850
+ const linkPath = path39.join(binDir, `${emp.name}${suffix}`);
27851
+ if (existsSync26(linkPath)) {
27671
27852
  if (!dryRun) rmSync(linkPath, { force: true });
27672
27853
  symlinkCount++;
27673
27854
  }
@@ -27680,7 +27861,7 @@ async function runClaudeUninstall(flags = []) {
27680
27861
  }
27681
27862
  } catch {
27682
27863
  }
27683
- if (purge && existsSync25(exeOsDir)) {
27864
+ if (purge && existsSync26(exeOsDir)) {
27684
27865
  if (!dryRun) {
27685
27866
  process.stdout.write("\x1B[33m\u26A0 This will delete all memories, identities, and agent data.\x1B[0m\n");
27686
27867
  process.stdout.write(" Removing ~/.exe-os...\n");
@@ -27705,7 +27886,7 @@ async function checkForUpdateOnBoot() {
27705
27886
  const config = await loadConfig2();
27706
27887
  if (!config.autoUpdate.checkOnBoot) return;
27707
27888
  const { checkForUpdate: checkForUpdate2 } = await Promise.resolve().then(() => (init_update(), update_exports));
27708
- const packageRoot = path38.resolve(
27889
+ const packageRoot = path39.resolve(
27709
27890
  new URL("../..", import.meta.url).pathname
27710
27891
  );
27711
27892
  const result = checkForUpdate2(packageRoot);
@@ -27764,7 +27945,7 @@ async function runActivate(key) {
27764
27945
  const idTemplate = getIdentityTemplate(identityKey);
27765
27946
  if (idTemplate) {
27766
27947
  const idPath = identityPath2(name);
27767
- const dir = path38.dirname(idPath);
27948
+ const dir = path39.dirname(idPath);
27768
27949
  if (!fs8.existsSync(dir)) fs8.mkdirSync(dir, { recursive: true });
27769
27950
  fs8.writeFileSync(idPath, idTemplate.replace(/^agent_id: \w+/m, `agent_id: ${name}`), "utf-8");
27770
27951
  }