@askexenow/exe-os 0.9.21 → 0.9.22

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 (60) hide show
  1. package/dist/bin/backfill-conversations.js +17 -4
  2. package/dist/bin/backfill-responses.js +17 -4
  3. package/dist/bin/backfill-vectors.js +2 -2
  4. package/dist/bin/cleanup-stale-review-tasks.js +17 -4
  5. package/dist/bin/cli.js +378 -171
  6. package/dist/bin/exe-assign.js +17 -4
  7. package/dist/bin/exe-boot.js +2 -2
  8. package/dist/bin/exe-dispatch.js +17 -4
  9. package/dist/bin/exe-doctor.js +2 -2
  10. package/dist/bin/exe-export-behaviors.js +17 -4
  11. package/dist/bin/exe-forget.js +17 -4
  12. package/dist/bin/exe-gateway.js +17 -4
  13. package/dist/bin/exe-heartbeat.js +17 -4
  14. package/dist/bin/exe-kill.js +17 -4
  15. package/dist/bin/exe-launch-agent.js +17 -4
  16. package/dist/bin/exe-pending-messages.js +17 -4
  17. package/dist/bin/exe-pending-notifications.js +17 -4
  18. package/dist/bin/exe-pending-reviews.js +17 -4
  19. package/dist/bin/exe-review.js +17 -4
  20. package/dist/bin/exe-search.js +23 -8
  21. package/dist/bin/exe-session-cleanup.js +17 -4
  22. package/dist/bin/exe-start-codex.js +209 -32
  23. package/dist/bin/exe-start-opencode.js +17 -4
  24. package/dist/bin/exe-status.js +17 -4
  25. package/dist/bin/exe-team.js +17 -4
  26. package/dist/bin/git-sweep.js +17 -4
  27. package/dist/bin/graph-backfill.js +17 -4
  28. package/dist/bin/graph-export.js +17 -4
  29. package/dist/bin/install.js +42 -0
  30. package/dist/bin/intercom-check.js +17 -4
  31. package/dist/bin/scan-tasks.js +17 -4
  32. package/dist/bin/shard-migrate.js +17 -4
  33. package/dist/bin/update.js +187 -42
  34. package/dist/gateway/index.js +17 -4
  35. package/dist/hooks/bug-report-worker.js +793 -150
  36. package/dist/hooks/codex-stop-task-finalizer.js +3020 -2375
  37. package/dist/hooks/commit-complete.js +156 -6
  38. package/dist/hooks/error-recall.js +23 -8
  39. package/dist/hooks/ingest.js +17 -4
  40. package/dist/hooks/instructions-loaded.js +17 -4
  41. package/dist/hooks/notification.js +17 -4
  42. package/dist/hooks/post-compact.js +17 -4
  43. package/dist/hooks/post-tool-combined.js +23 -8
  44. package/dist/hooks/pre-compact.js +156 -8
  45. package/dist/hooks/pre-tool-use.js +21 -12
  46. package/dist/hooks/prompt-submit.js +23 -8
  47. package/dist/hooks/session-end.js +156 -8
  48. package/dist/hooks/session-start.js +23 -8
  49. package/dist/hooks/stop.js +306 -9
  50. package/dist/hooks/subagent-stop.js +306 -9
  51. package/dist/hooks/summary-worker.js +2 -2
  52. package/dist/index.js +17 -4
  53. package/dist/lib/exe-daemon.js +17 -4
  54. package/dist/lib/hybrid-search.js +23 -8
  55. package/dist/lib/schedules.js +2 -2
  56. package/dist/lib/store.js +17 -4
  57. package/dist/mcp/server.js +36 -10
  58. package/dist/runtime/index.js +17 -4
  59. package/dist/tui/App.js +17 -4
  60. package/package.json +1 -1
@@ -2956,8 +2956,8 @@ function getShardClient(projectName) {
2956
2956
  throw new Error("Shard manager not initialized. Call initShardManager() first.");
2957
2957
  }
2958
2958
  const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
2959
- if (!safeName) {
2960
- throw new Error(`Invalid project name for shard: "${projectName}"`);
2959
+ if (!safeName || safeName === "unknown") {
2960
+ throw new Error(`Invalid project name for shard: "${projectName}" (resolved to "${safeName}")`);
2961
2961
  }
2962
2962
  const cached = _shards.get(safeName);
2963
2963
  if (cached) {
@@ -3826,19 +3826,32 @@ async function flushBatch() {
3826
3826
  const { isShardingEnabled: isShardingEnabled2, getReadyShardClient: getReadyShardClient2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
3827
3827
  if (isShardingEnabled2()) {
3828
3828
  const byProject = /* @__PURE__ */ new Map();
3829
+ let skippedUnknown = 0;
3829
3830
  for (const row of batch) {
3830
- const proj = row.project_name || "unknown";
3831
+ const proj = row.project_name?.trim();
3832
+ if (!proj) {
3833
+ skippedUnknown++;
3834
+ continue;
3835
+ }
3831
3836
  if (!byProject.has(proj)) byProject.set(proj, []);
3832
3837
  byProject.get(proj).push(row);
3833
3838
  }
3839
+ if (skippedUnknown > 0) {
3840
+ process.stderr.write(
3841
+ `[store] Shard skip: ${skippedUnknown} record(s) with empty project_name (kept in main DB only)
3842
+ `
3843
+ );
3844
+ }
3834
3845
  for (const [project, rows] of byProject) {
3835
3846
  try {
3836
3847
  const shardClient = await getReadyShardClient2(project);
3837
3848
  const shardStmts = rows.map(buildStmt);
3838
3849
  await shardClient.batch(shardStmts, "write");
3839
3850
  } catch (err) {
3851
+ const fullError = err instanceof Error ? `${err.name}: ${err.message}${err.stack ? `
3852
+ ${err.stack.split("\n").slice(1, 3).join("\n")}` : ""}` : String(err);
3840
3853
  process.stderr.write(
3841
- `[store] Shard write failed for ${project}: ${err instanceof Error ? err.message : String(err)}
3854
+ `[store] Shard write failed for ${project} (${rows.length} records): ${fullError}
3842
3855
  `
3843
3856
  );
3844
3857
  }
@@ -1,6 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
4
6
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
5
7
  get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
6
8
  }) : x)(function(x) {
@@ -14,6 +16,15 @@ var __export = (target, all) => {
14
16
  for (var name in all)
15
17
  __defProp(target, name, { get: all[name], enumerable: true });
16
18
  };
19
+ var __copyProps = (to, from, except, desc) => {
20
+ if (from && typeof from === "object" || typeof from === "function") {
21
+ for (let key of __getOwnPropNames(from))
22
+ if (!__hasOwnProp.call(to, key) && key !== except)
23
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
24
+ }
25
+ return to;
26
+ };
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
17
28
 
18
29
  // src/types/memory.ts
19
30
  var EMBEDDING_DIM;
@@ -2607,8 +2618,8 @@ function getShardClient(projectName) {
2607
2618
  throw new Error("Shard manager not initialized. Call initShardManager() first.");
2608
2619
  }
2609
2620
  const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
2610
- if (!safeName) {
2611
- throw new Error(`Invalid project name for shard: "${projectName}"`);
2621
+ if (!safeName || safeName === "unknown") {
2622
+ throw new Error(`Invalid project name for shard: "${projectName}" (resolved to "${safeName}")`);
2612
2623
  }
2613
2624
  const cached = _shards.get(safeName);
2614
2625
  if (cached) {
@@ -3141,7 +3152,7 @@ ${p.content}`).join("\n\n");
3141
3152
  });
3142
3153
 
3143
3154
  // src/lib/runtime-table.ts
3144
- var RUNTIME_TABLE;
3155
+ var RUNTIME_TABLE, DEFAULT_RUNTIME;
3145
3156
  var init_runtime_table = __esm({
3146
3157
  "src/lib/runtime-table.ts"() {
3147
3158
  "use strict";
@@ -3163,6 +3174,7 @@ var init_runtime_table = __esm({
3163
3174
  defaultModel: "anthropic/claude-sonnet-4-6"
3164
3175
  }
3165
3176
  };
3177
+ DEFAULT_RUNTIME = "claude";
3166
3178
  }
3167
3179
  });
3168
3180
 
@@ -3513,6 +3525,7 @@ var installer_exports = {};
3513
3525
  __export(installer_exports, {
3514
3526
  installCodexStatusLine: () => installCodexStatusLine,
3515
3527
  mergeCodexHooks: () => mergeCodexHooks,
3528
+ registerCodexMcpServer: () => registerCodexMcpServer,
3516
3529
  runCodexInstaller: () => runCodexInstaller,
3517
3530
  verifyCodexHooks: () => verifyCodexHooks
3518
3531
  });
@@ -3684,11 +3697,52 @@ status_line = [${DEFAULT_CODEX_STATUS_LINE.map((s) => `"${s}"`).join(", ")}]`;
3684
3697
  await writeFile5(configPath, content);
3685
3698
  return "installed";
3686
3699
  }
3700
+ async function registerCodexMcpServer(packageRoot, homeDir = os10.homedir()) {
3701
+ const codexDir = path13.join(homeDir, ".codex");
3702
+ const configPath = path13.join(codexDir, "config.toml");
3703
+ const serverJsPath = path13.join(packageRoot, "dist", "mcp", "server.js");
3704
+ await mkdir5(codexDir, { recursive: true });
3705
+ let content = "";
3706
+ if (existsSync12(configPath)) {
3707
+ content = await readFile5(configPath, "utf-8");
3708
+ }
3709
+ const sectionHeader = "[mcp_servers.exe-os]";
3710
+ const headerIndex = content.indexOf(sectionHeader);
3711
+ if (headerIndex !== -1) {
3712
+ const afterHeader = content.slice(headerIndex + sectionHeader.length);
3713
+ const nextSectionMatch = afterHeader.match(/\n\[(?!mcp_servers\.exe-os)/);
3714
+ const sectionEnd = nextSectionMatch ? headerIndex + sectionHeader.length + nextSectionMatch.index : content.length;
3715
+ const sectionContent = content.slice(headerIndex, sectionEnd);
3716
+ if (sectionContent.includes(serverJsPath)) {
3717
+ return "already-registered";
3718
+ }
3719
+ const newSection2 = `${sectionHeader}
3720
+ command = "node"
3721
+ args = ["${serverJsPath}"]
3722
+ `;
3723
+ content = content.slice(0, headerIndex) + newSection2 + content.slice(sectionEnd);
3724
+ await writeFile5(configPath, content);
3725
+ return "updated";
3726
+ }
3727
+ const newSection = `[mcp_servers.exe-os]
3728
+ command = "node"
3729
+ args = ["${serverJsPath}"]
3730
+ `;
3731
+ const separator = content.length > 0 && !content.endsWith("\n") ? "\n\n" : content.length > 0 ? "\n" : "";
3732
+ content = content + separator + newSection;
3733
+ await writeFile5(configPath, content);
3734
+ return "registered";
3735
+ }
3687
3736
  async function runCodexInstaller(homeDir) {
3688
3737
  const packageRoot = resolvePackageRoot();
3689
3738
  const result = await mergeCodexHooks(packageRoot, homeDir);
3690
3739
  process.stderr.write(
3691
3740
  `[exe-os] Codex hooks: ${result.added} added, ${result.skipped} unchanged
3741
+ `
3742
+ );
3743
+ const mcpResult = await registerCodexMcpServer(packageRoot, homeDir);
3744
+ process.stderr.write(
3745
+ `[exe-os] Codex MCP server: ${mcpResult}
3692
3746
  `
3693
3747
  );
3694
3748
  const statusResult = await installCodexStatusLine(homeDir);
@@ -3714,13 +3768,102 @@ var init_installer2 = __esm({
3714
3768
  }
3715
3769
  });
3716
3770
 
3771
+ // src/lib/agent-config.ts
3772
+ var agent_config_exports = {};
3773
+ __export(agent_config_exports, {
3774
+ AGENT_CONFIG_PATH: () => AGENT_CONFIG_PATH,
3775
+ DEFAULT_MODELS: () => DEFAULT_MODELS,
3776
+ KNOWN_RUNTIMES: () => KNOWN_RUNTIMES,
3777
+ RUNTIME_LABELS: () => RUNTIME_LABELS,
3778
+ clearAgentRuntime: () => clearAgentRuntime,
3779
+ getAgentRuntime: () => getAgentRuntime,
3780
+ loadAgentConfig: () => loadAgentConfig,
3781
+ saveAgentConfig: () => saveAgentConfig,
3782
+ setAgentRuntime: () => setAgentRuntime
3783
+ });
3784
+ import { readFileSync as readFileSync8, writeFileSync as writeFileSync7, existsSync as existsSync13 } from "fs";
3785
+ import path14 from "path";
3786
+ function loadAgentConfig() {
3787
+ if (!existsSync13(AGENT_CONFIG_PATH)) return {};
3788
+ try {
3789
+ return JSON.parse(readFileSync8(AGENT_CONFIG_PATH, "utf-8"));
3790
+ } catch {
3791
+ return {};
3792
+ }
3793
+ }
3794
+ function saveAgentConfig(config) {
3795
+ const dir = path14.dirname(AGENT_CONFIG_PATH);
3796
+ ensurePrivateDirSync(dir);
3797
+ writeFileSync7(AGENT_CONFIG_PATH, JSON.stringify(config, null, 2) + "\n", "utf-8");
3798
+ enforcePrivateFileSync(AGENT_CONFIG_PATH);
3799
+ }
3800
+ function getAgentRuntime(agentId) {
3801
+ const config = loadAgentConfig();
3802
+ const entry = config[agentId];
3803
+ if (entry) return entry;
3804
+ const orgDefault = config["default"];
3805
+ if (orgDefault) return orgDefault;
3806
+ return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
3807
+ }
3808
+ function setAgentRuntime(agentId, runtime, model, reasoning_effort) {
3809
+ const knownModels = KNOWN_RUNTIMES[runtime];
3810
+ if (!knownModels) {
3811
+ return {
3812
+ ok: false,
3813
+ error: `Unknown runtime "${runtime}". Valid: ${Object.keys(KNOWN_RUNTIMES).join(", ")}`
3814
+ };
3815
+ }
3816
+ if (!knownModels.includes(model)) {
3817
+ return {
3818
+ ok: false,
3819
+ error: `Unknown model "${model}" for runtime "${runtime}". Valid: ${knownModels.join(", ")}`
3820
+ };
3821
+ }
3822
+ const config = loadAgentConfig();
3823
+ const entry = { runtime, model };
3824
+ if (reasoning_effort) entry.reasoning_effort = reasoning_effort;
3825
+ config[agentId] = entry;
3826
+ saveAgentConfig(config);
3827
+ return { ok: true };
3828
+ }
3829
+ function clearAgentRuntime(agentId) {
3830
+ const config = loadAgentConfig();
3831
+ delete config[agentId];
3832
+ saveAgentConfig(config);
3833
+ }
3834
+ var AGENT_CONFIG_PATH, KNOWN_RUNTIMES, RUNTIME_LABELS, DEFAULT_MODELS;
3835
+ var init_agent_config = __esm({
3836
+ "src/lib/agent-config.ts"() {
3837
+ "use strict";
3838
+ init_config();
3839
+ init_runtime_table();
3840
+ init_secure_files();
3841
+ AGENT_CONFIG_PATH = path14.join(EXE_AI_DIR, "agent-config.json");
3842
+ KNOWN_RUNTIMES = {
3843
+ claude: ["claude-opus-4.6", "claude-opus-4", "claude-sonnet-4.6", "claude-sonnet-4", "claude-haiku-4.5"],
3844
+ codex: ["gpt-5.4", "gpt-5.5", "gpt-5.3-codex-spark", "o3", "o4-mini"],
3845
+ opencode: ["anthropic/claude-sonnet-4-6", "openai/gpt-5.4", "google/gemini-2.5-pro", "deepseek/deepseek-r3", "minimax/minimax-m2.5"]
3846
+ };
3847
+ RUNTIME_LABELS = {
3848
+ claude: "Claude Code (Anthropic)",
3849
+ codex: "Codex (OpenAI)",
3850
+ opencode: "OpenCode (open source)"
3851
+ };
3852
+ DEFAULT_MODELS = {
3853
+ claude: "claude-opus-4.6",
3854
+ codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
3855
+ opencode: RUNTIME_TABLE.opencode?.defaultModel ?? "anthropic/claude-sonnet-4-6"
3856
+ };
3857
+ }
3858
+ });
3859
+
3717
3860
  // src/bin/exe-start-codex.ts
3718
3861
  import os11 from "os";
3719
- import path14 from "path";
3862
+ import path15 from "path";
3720
3863
  import {
3721
- existsSync as existsSync13,
3722
- readFileSync as readFileSync8,
3723
- writeFileSync as writeFileSync7,
3864
+ existsSync as existsSync14,
3865
+ readFileSync as readFileSync9,
3866
+ writeFileSync as writeFileSync8,
3724
3867
  mkdirSync as mkdirSync7,
3725
3868
  readdirSync as readdirSync4
3726
3869
  } from "fs";
@@ -4038,19 +4181,32 @@ async function flushBatch() {
4038
4181
  const { isShardingEnabled: isShardingEnabled2, getReadyShardClient: getReadyShardClient2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
4039
4182
  if (isShardingEnabled2()) {
4040
4183
  const byProject = /* @__PURE__ */ new Map();
4184
+ let skippedUnknown = 0;
4041
4185
  for (const row of batch) {
4042
- const proj = row.project_name || "unknown";
4186
+ const proj = row.project_name?.trim();
4187
+ if (!proj) {
4188
+ skippedUnknown++;
4189
+ continue;
4190
+ }
4043
4191
  if (!byProject.has(proj)) byProject.set(proj, []);
4044
4192
  byProject.get(proj).push(row);
4045
4193
  }
4194
+ if (skippedUnknown > 0) {
4195
+ process.stderr.write(
4196
+ `[store] Shard skip: ${skippedUnknown} record(s) with empty project_name (kept in main DB only)
4197
+ `
4198
+ );
4199
+ }
4046
4200
  for (const [project, rows] of byProject) {
4047
4201
  try {
4048
4202
  const shardClient = await getReadyShardClient2(project);
4049
4203
  const shardStmts = rows.map(buildStmt);
4050
4204
  await shardClient.batch(shardStmts, "write");
4051
4205
  } catch (err) {
4206
+ const fullError = err instanceof Error ? `${err.name}: ${err.message}${err.stack ? `
4207
+ ${err.stack.split("\n").slice(1, 3).join("\n")}` : ""}` : String(err);
4052
4208
  process.stderr.write(
4053
- `[store] Shard write failed for ${project}: ${err instanceof Error ? err.message : String(err)}
4209
+ `[store] Shard write failed for ${project} (${rows.length} records): ${fullError}
4054
4210
  `
4055
4211
  );
4056
4212
  }
@@ -4201,12 +4357,24 @@ var BOOT_INSTRUCTIONS = `
4201
4357
  ---
4202
4358
  ## Boot Instructions
4203
4359
  You have access to exe-os MCP tools for persistent memory, tasks, and team coordination.
4360
+ MCP tools are available under the exe-os server. Call them directly by name:
4361
+ - list_tasks \u2014 see your assigned work
4362
+ - get_task \u2014 read full task context
4363
+ - update_task \u2014 mark tasks in_progress or done
4364
+ - store_memory \u2014 persist findings for future sessions
4365
+ - recall_my_memory \u2014 search your past work
4366
+ - ask_team_memory \u2014 query a colleague's knowledge
4367
+
4204
4368
  On startup: call list_tasks to check for assigned work.
4205
- When done with a task: call update_task with status "done".
4206
- Always call store_memory to persist important findings.
4369
+ When done with a task: call update_task with status "done" and a result summary.
4370
+ Always call store_memory to persist important decisions.
4371
+
4372
+ \u26A0 FIRST RUN: If hooks haven't been approved yet, run /hooks in Codex and approve
4373
+ all exe-os hooks before starting work. Without approved hooks, memory capture
4374
+ and session tracking won't function.
4207
4375
  `;
4208
4376
  function resolveAgent(argv) {
4209
- const invokedAs = path14.basename(argv[1] ?? "");
4377
+ const invokedAs = path15.basename(argv[1] ?? "");
4210
4378
  if (invokedAs && invokedAs !== "exe-start-codex" && !invokedAs.endsWith(".js")) {
4211
4379
  const agent2 = invokedAs.replace(/-codex$/, "").toLowerCase();
4212
4380
  return { agent: agent2, passthrough: argv.slice(2) };
@@ -4232,24 +4400,24 @@ function resolveAgent(argv) {
4232
4400
  return { agent, passthrough, sessionName };
4233
4401
  }
4234
4402
  function loadIdentity(agent) {
4235
- const dir = path14.join(os11.homedir(), ".exe-os", "identity");
4236
- const exact = path14.join(dir, `${agent}.md`);
4237
- if (existsSync13(exact)) {
4238
- const content = readFileSync8(exact, "utf-8").trim();
4403
+ const dir = path15.join(os11.homedir(), ".exe-os", "identity");
4404
+ const exact = path15.join(dir, `${agent}.md`);
4405
+ if (existsSync14(exact)) {
4406
+ const content = readFileSync9(exact, "utf-8").trim();
4239
4407
  if (content) return content;
4240
4408
  }
4241
4409
  try {
4242
4410
  const files = readdirSync4(dir);
4243
4411
  const match = files.find((f) => f.toLowerCase() === `${agent.toLowerCase()}.md`);
4244
4412
  if (match) {
4245
- const content = readFileSync8(path14.join(dir, match), "utf-8").trim();
4413
+ const content = readFileSync9(path15.join(dir, match), "utf-8").trim();
4246
4414
  if (content) return content;
4247
4415
  }
4248
4416
  } catch {
4249
4417
  }
4250
4418
  try {
4251
- const rosterPath = path14.join(os11.homedir(), ".exe-os", "exe-employees.json");
4252
- const roster = JSON.parse(readFileSync8(rosterPath, "utf8"));
4419
+ const rosterPath = path15.join(os11.homedir(), ".exe-os", "exe-employees.json");
4420
+ const roster = JSON.parse(readFileSync9(rosterPath, "utf8"));
4253
4421
  const emp = roster.find((e) => e.name.toLowerCase() === agent.toLowerCase());
4254
4422
  if (emp?.systemPrompt && emp.systemPrompt.trim().length > 20) {
4255
4423
  return emp.systemPrompt;
@@ -4259,18 +4427,18 @@ function loadIdentity(agent) {
4259
4427
  return null;
4260
4428
  }
4261
4429
  function writePromptFile(agent, identity, behaviorsPath) {
4262
- const promptDir = path14.join(os11.homedir(), ".exe-os", "codex-prompt");
4430
+ const promptDir = path15.join(os11.homedir(), ".exe-os", "codex-prompt");
4263
4431
  mkdirSync7(promptDir, { recursive: true });
4264
4432
  let prompt = identity;
4265
- if (behaviorsPath && existsSync13(behaviorsPath)) {
4266
- const behaviors = readFileSync8(behaviorsPath, "utf-8").trim();
4433
+ if (behaviorsPath && existsSync14(behaviorsPath)) {
4434
+ const behaviors = readFileSync9(behaviorsPath, "utf-8").trim();
4267
4435
  if (behaviors) {
4268
4436
  prompt += "\n\n" + behaviors;
4269
4437
  }
4270
4438
  }
4271
4439
  prompt += "\n" + BOOT_INSTRUCTIONS;
4272
- const outPath = path14.join(promptDir, `${agent}.md`);
4273
- writeFileSync7(outPath, prompt, "utf-8");
4440
+ const outPath = path15.join(promptDir, `${agent}.md`);
4441
+ writeFileSync8(outPath, prompt, "utf-8");
4274
4442
  return outPath;
4275
4443
  }
4276
4444
  async function main() {
@@ -4349,8 +4517,8 @@ async function main() {
4349
4517
  process.env.EXE_RUNTIME = "codex";
4350
4518
  const empRole = (() => {
4351
4519
  try {
4352
- const emps = readFileSync8(
4353
- path14.join(os11.homedir(), ".exe-os", "exe-employees.json"),
4520
+ const emps = readFileSync9(
4521
+ path15.join(os11.homedir(), ".exe-os", "exe-employees.json"),
4354
4522
  "utf-8"
4355
4523
  );
4356
4524
  const found = JSON.parse(emps).find(
@@ -4387,14 +4555,14 @@ async function main() {
4387
4555
  if (WORKTREE_ROLES.has(empRole)) {
4388
4556
  try {
4389
4557
  const { execSync: es } = await import("child_process");
4390
- const worktreeDir = path14.join(process.cwd(), ".worktrees", worktreeName);
4558
+ const worktreeDir = path15.join(process.cwd(), ".worktrees", worktreeName);
4391
4559
  const branchName = `${worktreeName}/codex-${Date.now()}`;
4392
- if (existsSync13(worktreeDir)) {
4560
+ if (existsSync14(worktreeDir)) {
4393
4561
  worktreePath = worktreeDir;
4394
4562
  process.stderr.write(`[exe-start-codex] Reusing worktree at ${worktreeDir}
4395
4563
  `);
4396
4564
  } else {
4397
- mkdirSync7(path14.dirname(worktreeDir), { recursive: true });
4565
+ mkdirSync7(path15.dirname(worktreeDir), { recursive: true });
4398
4566
  es(`git worktree add "${worktreeDir}" -b "${branchName}" HEAD`, {
4399
4567
  encoding: "utf-8",
4400
4568
  timeout: 3e4
@@ -4410,7 +4578,16 @@ async function main() {
4410
4578
  );
4411
4579
  }
4412
4580
  }
4413
- const effectiveModel = process.env.EXE_AGENT_MODEL ?? CODEX.defaultModel;
4581
+ let configModel;
4582
+ let configReasoning;
4583
+ try {
4584
+ const { getAgentRuntime: getAgentRuntime2 } = (init_agent_config(), __toCommonJS(agent_config_exports));
4585
+ const rtConfig = getAgentRuntime2(agent);
4586
+ configModel = rtConfig.model;
4587
+ configReasoning = rtConfig.reasoning_effort;
4588
+ } catch {
4589
+ }
4590
+ const effectiveModel = process.env.EXE_AGENT_MODEL ?? configModel ?? CODEX.defaultModel;
4414
4591
  const args = [
4415
4592
  "-m",
4416
4593
  effectiveModel,
@@ -4418,7 +4595,7 @@ async function main() {
4418
4595
  CODEX.inlineFlag,
4419
4596
  ...passthrough
4420
4597
  ];
4421
- const reasoningEffort = process.env.EXE_AGENT_REASONING_EFFORT;
4598
+ const reasoningEffort = process.env.EXE_AGENT_REASONING_EFFORT ?? configReasoning;
4422
4599
  if (reasoningEffort) {
4423
4600
  args.push("-c", `model_reasoning_effort="${reasoningEffort}"`);
4424
4601
  }
@@ -4428,7 +4605,7 @@ async function main() {
4428
4605
  if (promptPath) {
4429
4606
  args.push("-c", `model_instructions_file="${promptPath}"`);
4430
4607
  }
4431
- args.push("You are an AI employee with exe-os MCP tools. DO NOT ask for confirmation \u2014 work autonomously. Immediately: 1) Call list_tasks to see your assigned tasks. 2) Call get_task on the highest priority open task. 3) Start working on it. 4) When done, call update_task with status done and a result summary. 5) Check list_tasks again for the next task. 6) If NO open tasks remain, say 'All tasks complete. Standing by.' and STOP \u2014 do not explore the codebase, do not look for extra work, do not run reviews. Just stop and wait.");
4608
+ args.push("You are an AI employee with exe-os MCP tools (list_tasks, get_task, update_task, store_memory, recall_my_memory, ask_team_memory). DO NOT ask for confirmation \u2014 work autonomously. Immediately: 1) Call list_tasks to see your assigned tasks. 2) Call get_task on the highest priority open task. 3) Start working on it. 4) When done, call update_task with status done and a result summary. 5) Check list_tasks again for the next task. 6) If NO open tasks remain, say 'All tasks complete. Standing by.' and STOP. If MCP tools are unavailable, tell the user to run 'exe-os codex' to register them.");
4432
4609
  process.stderr.write(
4433
4610
  `[exe-start-codex] launching ${agent} on ${CODEX.binary} (${effectiveModel}) \u2014 interactive mode
4434
4611
  `
@@ -2607,8 +2607,8 @@ function getShardClient(projectName) {
2607
2607
  throw new Error("Shard manager not initialized. Call initShardManager() first.");
2608
2608
  }
2609
2609
  const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
2610
- if (!safeName) {
2611
- throw new Error(`Invalid project name for shard: "${projectName}"`);
2610
+ if (!safeName || safeName === "unknown") {
2611
+ throw new Error(`Invalid project name for shard: "${projectName}" (resolved to "${safeName}")`);
2612
2612
  }
2613
2613
  const cached = _shards.get(safeName);
2614
2614
  if (cached) {
@@ -4100,19 +4100,32 @@ async function flushBatch() {
4100
4100
  const { isShardingEnabled: isShardingEnabled2, getReadyShardClient: getReadyShardClient2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
4101
4101
  if (isShardingEnabled2()) {
4102
4102
  const byProject = /* @__PURE__ */ new Map();
4103
+ let skippedUnknown = 0;
4103
4104
  for (const row of batch) {
4104
- const proj = row.project_name || "unknown";
4105
+ const proj = row.project_name?.trim();
4106
+ if (!proj) {
4107
+ skippedUnknown++;
4108
+ continue;
4109
+ }
4105
4110
  if (!byProject.has(proj)) byProject.set(proj, []);
4106
4111
  byProject.get(proj).push(row);
4107
4112
  }
4113
+ if (skippedUnknown > 0) {
4114
+ process.stderr.write(
4115
+ `[store] Shard skip: ${skippedUnknown} record(s) with empty project_name (kept in main DB only)
4116
+ `
4117
+ );
4118
+ }
4108
4119
  for (const [project, rows] of byProject) {
4109
4120
  try {
4110
4121
  const shardClient = await getReadyShardClient2(project);
4111
4122
  const shardStmts = rows.map(buildStmt);
4112
4123
  await shardClient.batch(shardStmts, "write");
4113
4124
  } catch (err) {
4125
+ const fullError = err instanceof Error ? `${err.name}: ${err.message}${err.stack ? `
4126
+ ${err.stack.split("\n").slice(1, 3).join("\n")}` : ""}` : String(err);
4114
4127
  process.stderr.write(
4115
- `[store] Shard write failed for ${project}: ${err instanceof Error ? err.message : String(err)}
4128
+ `[store] Shard write failed for ${project} (${rows.length} records): ${fullError}
4116
4129
  `
4117
4130
  );
4118
4131
  }
@@ -2945,8 +2945,8 @@ function getShardClient(projectName) {
2945
2945
  throw new Error("Shard manager not initialized. Call initShardManager() first.");
2946
2946
  }
2947
2947
  const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
2948
- if (!safeName) {
2949
- throw new Error(`Invalid project name for shard: "${projectName}"`);
2948
+ if (!safeName || safeName === "unknown") {
2949
+ throw new Error(`Invalid project name for shard: "${projectName}" (resolved to "${safeName}")`);
2950
2950
  }
2951
2951
  const cached = _shards.get(safeName);
2952
2952
  if (cached) {
@@ -3815,19 +3815,32 @@ async function flushBatch() {
3815
3815
  const { isShardingEnabled: isShardingEnabled2, getReadyShardClient: getReadyShardClient2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
3816
3816
  if (isShardingEnabled2()) {
3817
3817
  const byProject = /* @__PURE__ */ new Map();
3818
+ let skippedUnknown = 0;
3818
3819
  for (const row of batch) {
3819
- const proj = row.project_name || "unknown";
3820
+ const proj = row.project_name?.trim();
3821
+ if (!proj) {
3822
+ skippedUnknown++;
3823
+ continue;
3824
+ }
3820
3825
  if (!byProject.has(proj)) byProject.set(proj, []);
3821
3826
  byProject.get(proj).push(row);
3822
3827
  }
3828
+ if (skippedUnknown > 0) {
3829
+ process.stderr.write(
3830
+ `[store] Shard skip: ${skippedUnknown} record(s) with empty project_name (kept in main DB only)
3831
+ `
3832
+ );
3833
+ }
3823
3834
  for (const [project, rows] of byProject) {
3824
3835
  try {
3825
3836
  const shardClient = await getReadyShardClient2(project);
3826
3837
  const shardStmts = rows.map(buildStmt);
3827
3838
  await shardClient.batch(shardStmts, "write");
3828
3839
  } catch (err) {
3840
+ const fullError = err instanceof Error ? `${err.name}: ${err.message}${err.stack ? `
3841
+ ${err.stack.split("\n").slice(1, 3).join("\n")}` : ""}` : String(err);
3829
3842
  process.stderr.write(
3830
- `[store] Shard write failed for ${project}: ${err instanceof Error ? err.message : String(err)}
3843
+ `[store] Shard write failed for ${project} (${rows.length} records): ${fullError}
3831
3844
  `
3832
3845
  );
3833
3846
  }
@@ -2934,8 +2934,8 @@ function getShardClient(projectName) {
2934
2934
  throw new Error("Shard manager not initialized. Call initShardManager() first.");
2935
2935
  }
2936
2936
  const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
2937
- if (!safeName) {
2938
- throw new Error(`Invalid project name for shard: "${projectName}"`);
2937
+ if (!safeName || safeName === "unknown") {
2938
+ throw new Error(`Invalid project name for shard: "${projectName}" (resolved to "${safeName}")`);
2939
2939
  }
2940
2940
  const cached = _shards.get(safeName);
2941
2941
  if (cached) {
@@ -3804,19 +3804,32 @@ async function flushBatch() {
3804
3804
  const { isShardingEnabled: isShardingEnabled2, getReadyShardClient: getReadyShardClient2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
3805
3805
  if (isShardingEnabled2()) {
3806
3806
  const byProject = /* @__PURE__ */ new Map();
3807
+ let skippedUnknown = 0;
3807
3808
  for (const row of batch) {
3808
- const proj = row.project_name || "unknown";
3809
+ const proj = row.project_name?.trim();
3810
+ if (!proj) {
3811
+ skippedUnknown++;
3812
+ continue;
3813
+ }
3809
3814
  if (!byProject.has(proj)) byProject.set(proj, []);
3810
3815
  byProject.get(proj).push(row);
3811
3816
  }
3817
+ if (skippedUnknown > 0) {
3818
+ process.stderr.write(
3819
+ `[store] Shard skip: ${skippedUnknown} record(s) with empty project_name (kept in main DB only)
3820
+ `
3821
+ );
3822
+ }
3812
3823
  for (const [project, rows] of byProject) {
3813
3824
  try {
3814
3825
  const shardClient = await getReadyShardClient2(project);
3815
3826
  const shardStmts = rows.map(buildStmt);
3816
3827
  await shardClient.batch(shardStmts, "write");
3817
3828
  } catch (err) {
3829
+ const fullError = err instanceof Error ? `${err.name}: ${err.message}${err.stack ? `
3830
+ ${err.stack.split("\n").slice(1, 3).join("\n")}` : ""}` : String(err);
3818
3831
  process.stderr.write(
3819
- `[store] Shard write failed for ${project}: ${err instanceof Error ? err.message : String(err)}
3832
+ `[store] Shard write failed for ${project} (${rows.length} records): ${fullError}
3820
3833
  `
3821
3834
  );
3822
3835
  }
@@ -6553,8 +6553,8 @@ function getShardClient(projectName2) {
6553
6553
  throw new Error("Shard manager not initialized. Call initShardManager() first.");
6554
6554
  }
6555
6555
  const safeName = projectName2.replace(/[^a-zA-Z0-9_-]/g, "_");
6556
- if (!safeName) {
6557
- throw new Error(`Invalid project name for shard: "${projectName2}"`);
6556
+ if (!safeName || safeName === "unknown") {
6557
+ throw new Error(`Invalid project name for shard: "${projectName2}" (resolved to "${safeName}")`);
6558
6558
  }
6559
6559
  const cached = _shards.get(safeName);
6560
6560
  if (cached) {
@@ -7423,19 +7423,32 @@ async function flushBatch() {
7423
7423
  const { isShardingEnabled: isShardingEnabled2, getReadyShardClient: getReadyShardClient2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
7424
7424
  if (isShardingEnabled2()) {
7425
7425
  const byProject = /* @__PURE__ */ new Map();
7426
+ let skippedUnknown = 0;
7426
7427
  for (const row of batch) {
7427
- const proj = row.project_name || "unknown";
7428
+ const proj = row.project_name?.trim();
7429
+ if (!proj) {
7430
+ skippedUnknown++;
7431
+ continue;
7432
+ }
7428
7433
  if (!byProject.has(proj)) byProject.set(proj, []);
7429
7434
  byProject.get(proj).push(row);
7430
7435
  }
7436
+ if (skippedUnknown > 0) {
7437
+ process.stderr.write(
7438
+ `[store] Shard skip: ${skippedUnknown} record(s) with empty project_name (kept in main DB only)
7439
+ `
7440
+ );
7441
+ }
7431
7442
  for (const [project, rows] of byProject) {
7432
7443
  try {
7433
7444
  const shardClient = await getReadyShardClient2(project);
7434
7445
  const shardStmts = rows.map(buildStmt);
7435
7446
  await shardClient.batch(shardStmts, "write");
7436
7447
  } catch (err) {
7448
+ const fullError = err instanceof Error ? `${err.name}: ${err.message}${err.stack ? `
7449
+ ${err.stack.split("\n").slice(1, 3).join("\n")}` : ""}` : String(err);
7437
7450
  process.stderr.write(
7438
- `[store] Shard write failed for ${project}: ${err instanceof Error ? err.message : String(err)}
7451
+ `[store] Shard write failed for ${project} (${rows.length} records): ${fullError}
7439
7452
  `
7440
7453
  );
7441
7454
  }