@askexenow/exe-os 0.9.34 → 0.9.36

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 (76) hide show
  1. package/dist/bin/backfill-conversations.js +212 -11
  2. package/dist/bin/backfill-responses.js +212 -11
  3. package/dist/bin/backfill-vectors.js +14 -3
  4. package/dist/bin/cleanup-stale-review-tasks.js +224 -12
  5. package/dist/bin/cli.js +265 -23
  6. package/dist/bin/exe-agent.js +1 -1
  7. package/dist/bin/exe-assign.js +217 -12
  8. package/dist/bin/exe-boot.js +25 -4
  9. package/dist/bin/exe-call.js +7 -5
  10. package/dist/bin/exe-dispatch.js +229 -13
  11. package/dist/bin/exe-doctor.js +14 -3
  12. package/dist/bin/exe-export-behaviors.js +301 -14
  13. package/dist/bin/exe-forget.js +245 -21
  14. package/dist/bin/exe-gateway.js +229 -13
  15. package/dist/bin/exe-heartbeat.js +224 -12
  16. package/dist/bin/exe-kill.js +224 -12
  17. package/dist/bin/exe-launch-agent.js +177 -9
  18. package/dist/bin/exe-link.js +8 -0
  19. package/dist/bin/exe-new-employee.js +26 -2
  20. package/dist/bin/exe-pending-messages.js +224 -12
  21. package/dist/bin/exe-pending-notifications.js +224 -12
  22. package/dist/bin/exe-pending-reviews.js +224 -12
  23. package/dist/bin/exe-rename.js +9 -1
  24. package/dist/bin/exe-review.js +224 -12
  25. package/dist/bin/exe-search.js +246 -21
  26. package/dist/bin/exe-session-cleanup.js +229 -13
  27. package/dist/bin/exe-start-codex.js +161 -5
  28. package/dist/bin/exe-start-opencode.js +172 -5
  29. package/dist/bin/exe-status.js +224 -12
  30. package/dist/bin/exe-team.js +224 -12
  31. package/dist/bin/git-sweep.js +229 -13
  32. package/dist/bin/graph-backfill.js +94 -3
  33. package/dist/bin/graph-export.js +224 -12
  34. package/dist/bin/install.js +25 -1
  35. package/dist/bin/intercom-check.js +229 -13
  36. package/dist/bin/scan-tasks.js +229 -13
  37. package/dist/bin/setup.js +15 -5
  38. package/dist/bin/shard-migrate.js +94 -3
  39. package/dist/gateway/index.js +229 -13
  40. package/dist/hooks/bug-report-worker.js +229 -13
  41. package/dist/hooks/codex-stop-task-finalizer.js +224 -12
  42. package/dist/hooks/commit-complete.js +229 -13
  43. package/dist/hooks/error-recall.js +246 -21
  44. package/dist/hooks/ingest.js +224 -12
  45. package/dist/hooks/instructions-loaded.js +224 -12
  46. package/dist/hooks/notification.js +224 -12
  47. package/dist/hooks/post-compact.js +224 -12
  48. package/dist/hooks/post-tool-combined.js +246 -21
  49. package/dist/hooks/pre-compact.js +229 -13
  50. package/dist/hooks/pre-tool-use.js +234 -18
  51. package/dist/hooks/prompt-submit.js +346 -23
  52. package/dist/hooks/session-end.js +229 -13
  53. package/dist/hooks/session-start.js +418 -42
  54. package/dist/hooks/stop.js +224 -12
  55. package/dist/hooks/subagent-stop.js +224 -12
  56. package/dist/hooks/summary-worker.js +15 -2
  57. package/dist/index.js +229 -13
  58. package/dist/lib/cloud-sync.js +8 -0
  59. package/dist/lib/consolidation.js +3 -1
  60. package/dist/lib/database.js +8 -0
  61. package/dist/lib/db.js +8 -0
  62. package/dist/lib/device-registry.js +8 -0
  63. package/dist/lib/employee-templates.js +7 -5
  64. package/dist/lib/exe-daemon.js +1776 -1433
  65. package/dist/lib/hybrid-search.js +246 -21
  66. package/dist/lib/schedules.js +14 -3
  67. package/dist/lib/store.js +217 -12
  68. package/dist/lib/tasks.js +5 -1
  69. package/dist/lib/tmux-routing.js +5 -1
  70. package/dist/mcp/server.js +331 -37
  71. package/dist/mcp/tools/create-task.js +5 -1
  72. package/dist/mcp/tools/update-task.js +5 -1
  73. package/dist/runtime/index.js +229 -13
  74. package/dist/tui/App.js +229 -13
  75. package/package.json +1 -1
  76. package/src/commands/exe/save.md +48 -0
package/dist/bin/cli.js CHANGED
@@ -824,6 +824,7 @@ __export(installer_exports, {
824
824
  });
825
825
  import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3, readdir } from "fs/promises";
826
826
  import { existsSync as existsSync7, readFileSync as readFileSync5, writeFileSync as writeFileSync4, copyFileSync, mkdirSync as mkdirSync3 } from "fs";
827
+ import { createHash } from "crypto";
827
828
  import path6 from "path";
828
829
  import os5 from "os";
829
830
  import { execSync as execSync2 } from "child_process";
@@ -1508,7 +1509,30 @@ function setupTmux(home) {
1508
1509
  return;
1509
1510
  }
1510
1511
  mkdirSync3(exeDir, { recursive: true });
1511
- copyFileSync(assetPath, exeTmuxConf);
1512
+ if (existsSync7(exeTmuxConf)) {
1513
+ const currentContent = readFileSync5(exeTmuxConf, "utf8");
1514
+ const newContent = readFileSync5(assetPath, "utf8");
1515
+ const currentHash = createHash("sha256").update(currentContent).digest("hex");
1516
+ const newHash = createHash("sha256").update(newContent).digest("hex");
1517
+ if (currentHash !== newHash) {
1518
+ const shippedPath = path6.join(exeDir, ".tmux.conf.shipped-hash");
1519
+ const lastShippedHash = existsSync7(shippedPath) ? readFileSync5(shippedPath, "utf8").trim() : "";
1520
+ if (lastShippedHash && currentHash !== lastShippedHash) {
1521
+ process.stderr.write("exe-os: tmux config has user customizations \u2014 skipping overwrite\n");
1522
+ } else {
1523
+ copyFileSync(assetPath, exeTmuxConf);
1524
+ process.stderr.write("exe-os: tmux config updated\n");
1525
+ }
1526
+ writeFileSync4(shippedPath, newHash, "utf8");
1527
+ } else {
1528
+ process.stderr.write("exe-os: tmux config already up to date\n");
1529
+ }
1530
+ } else {
1531
+ copyFileSync(assetPath, exeTmuxConf);
1532
+ const newContent = readFileSync5(assetPath, "utf8");
1533
+ const newHash = createHash("sha256").update(newContent).digest("hex");
1534
+ writeFileSync4(path6.join(exeDir, ".tmux.conf.shipped-hash"), newHash, "utf8");
1535
+ }
1512
1536
  if (existsSync7(userTmuxConf)) {
1513
1537
  const existing = readFileSync5(userTmuxConf, "utf8");
1514
1538
  if (!existing.includes(sourceLine)) {
@@ -3920,6 +3944,14 @@ async function ensureSchema() {
3920
3944
  );
3921
3945
  } catch {
3922
3946
  }
3947
+ try {
3948
+ await client.execute(
3949
+ `CREATE INDEX IF NOT EXISTS idx_memories_scoped_content_hash
3950
+ ON memories(content_hash, agent_id, project_name, memory_type)
3951
+ WHERE content_hash IS NOT NULL`
3952
+ );
3953
+ } catch {
3954
+ }
3923
3955
  await client.executeMultiple(`
3924
3956
  CREATE TABLE IF NOT EXISTS entities (
3925
3957
  id TEXT PRIMARY KEY,
@@ -6794,6 +6826,197 @@ var init_state_bus = __esm({
6794
6826
  }
6795
6827
  });
6796
6828
 
6829
+ // src/lib/memory-write-governor.ts
6830
+ import { createHash as createHash2 } from "crypto";
6831
+ function normalizeMemoryText(text) {
6832
+ return text.replace(/\r\n/g, "\n").replace(/[ \t]+$/gm, "").replace(/\n{4,}/g, "\n\n\n").trim();
6833
+ }
6834
+ function classifyMemoryType(input) {
6835
+ if (input.memory_type && input.memory_type.trim()) return input.memory_type.trim();
6836
+ const tool = input.tool_name.toLowerCase();
6837
+ const text = input.raw_text.toLowerCase();
6838
+ if (tool.includes("store_decision") || tool.includes("decision")) return "decision";
6839
+ if (tool.includes("commit") || text.includes("adr-") || text.includes("architectural decision")) return "adr";
6840
+ if (tool.includes("store_behavior") || tool.includes("behavior")) return "behavior";
6841
+ if (tool.includes("global_procedure") || text.includes("organization-wide procedures")) return "procedure";
6842
+ if (tool.includes("send_whatsapp") || tool.includes("conversation")) return "conversation";
6843
+ if (tool === "store_memory" || tool === "manual") return "observation";
6844
+ return "raw";
6845
+ }
6846
+ function shouldDropMemory(text) {
6847
+ const normalized = normalizeMemoryText(text);
6848
+ if (normalized.length < 10) return { drop: true, reason: "too_short" };
6849
+ if (NOISE_DROP_PATTERNS.some((pattern) => pattern.test(normalized))) {
6850
+ return { drop: true, reason: "known_boilerplate_noise" };
6851
+ }
6852
+ return { drop: false };
6853
+ }
6854
+ function shouldSkipEmbedding(input) {
6855
+ const type = classifyMemoryType(input);
6856
+ if (HIGH_VALUE_SUPERSESSION_TYPES.has(type)) return false;
6857
+ if (type === "raw" && input.raw_text.length > 2e4) return true;
6858
+ if (SKIP_EMBED_PATTERNS.some((pattern) => pattern.test(input.raw_text))) return true;
6859
+ return false;
6860
+ }
6861
+ function hashMemoryContent(text) {
6862
+ return createHash2("sha256").update(normalizeMemoryText(text)).digest("hex");
6863
+ }
6864
+ function scopedDedupArgs(input) {
6865
+ return [input.contentHash, input.agentId, input.projectName, input.memoryType];
6866
+ }
6867
+ function governMemoryRecord(record) {
6868
+ const normalized = normalizeMemoryText(record.raw_text);
6869
+ const memoryType = classifyMemoryType({
6870
+ raw_text: normalized,
6871
+ agent_id: record.agent_id,
6872
+ project_name: record.project_name,
6873
+ tool_name: record.tool_name,
6874
+ memory_type: record.memory_type
6875
+ });
6876
+ const drop = shouldDropMemory(normalized);
6877
+ const skipEmbedding = shouldSkipEmbedding({
6878
+ raw_text: normalized,
6879
+ agent_id: record.agent_id,
6880
+ project_name: record.project_name,
6881
+ tool_name: record.tool_name,
6882
+ memory_type: memoryType
6883
+ });
6884
+ return {
6885
+ record: {
6886
+ ...record,
6887
+ raw_text: normalized,
6888
+ memory_type: memoryType,
6889
+ vector: skipEmbedding ? null : record.vector
6890
+ },
6891
+ contentHash: hashMemoryContent(normalized),
6892
+ shouldDrop: drop.drop,
6893
+ dropReason: drop.reason,
6894
+ skipEmbedding,
6895
+ hygiene: {
6896
+ dedup: true,
6897
+ supersession: HIGH_VALUE_SUPERSESSION_TYPES.has(memoryType)
6898
+ }
6899
+ };
6900
+ }
6901
+ async function findScopedDuplicate(input) {
6902
+ const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
6903
+ const client = getClient2();
6904
+ const args2 = scopedDedupArgs(input);
6905
+ let sql = `SELECT id FROM memories
6906
+ WHERE content_hash = ?
6907
+ AND agent_id = ?
6908
+ AND project_name = ?
6909
+ AND COALESCE(memory_type, 'raw') = ?
6910
+ AND COALESCE(status, 'active') != 'deleted'`;
6911
+ if (input.excludeId) {
6912
+ sql += " AND id != ?";
6913
+ args2.push(input.excludeId);
6914
+ }
6915
+ sql += " ORDER BY timestamp DESC LIMIT 1";
6916
+ const result = await client.execute({ sql, args: args2 });
6917
+ return result.rows[0]?.id ? String(result.rows[0].id) : null;
6918
+ }
6919
+ async function runPostWriteMemoryHygiene(memoryId) {
6920
+ try {
6921
+ const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
6922
+ const client = getClient2();
6923
+ const current = await client.execute({
6924
+ sql: `SELECT id, agent_id, project_name, memory_type, content_hash, supersedes_id,
6925
+ importance, timestamp
6926
+ FROM memories
6927
+ WHERE id = ?
6928
+ LIMIT 1`,
6929
+ args: [memoryId]
6930
+ });
6931
+ const row = current.rows[0];
6932
+ if (!row) return;
6933
+ const memoryType = String(row.memory_type ?? "raw");
6934
+ const contentHash2 = row.content_hash ? String(row.content_hash) : null;
6935
+ const agentId = String(row.agent_id);
6936
+ const projectName = String(row.project_name);
6937
+ if (contentHash2) {
6938
+ await client.execute({
6939
+ sql: `UPDATE memories
6940
+ SET status = 'deleted',
6941
+ outcome = COALESCE(outcome, 'superseded')
6942
+ WHERE id != ?
6943
+ AND content_hash = ?
6944
+ AND agent_id = ?
6945
+ AND project_name = ?
6946
+ AND COALESCE(memory_type, 'raw') = ?
6947
+ AND COALESCE(status, 'active') = 'active'`,
6948
+ args: [memoryId, contentHash2, agentId, projectName, memoryType]
6949
+ });
6950
+ }
6951
+ const supersedesId = row.supersedes_id ? String(row.supersedes_id) : null;
6952
+ if (supersedesId && HIGH_VALUE_SUPERSESSION_TYPES.has(memoryType)) {
6953
+ const old = await client.execute({
6954
+ sql: `SELECT importance FROM memories WHERE id = ? LIMIT 1`,
6955
+ args: [supersedesId]
6956
+ });
6957
+ const oldImportance = Number(old.rows[0]?.importance ?? 0);
6958
+ const newImportance = Number(row.importance ?? 0);
6959
+ await client.batch([
6960
+ {
6961
+ sql: `UPDATE memories
6962
+ SET status = 'archived',
6963
+ outcome = COALESCE(outcome, 'superseded')
6964
+ WHERE id = ?`,
6965
+ args: [supersedesId]
6966
+ },
6967
+ {
6968
+ sql: `UPDATE memories
6969
+ SET importance = MAX(COALESCE(importance, 5), ?),
6970
+ parent_memory_id = COALESCE(parent_memory_id, ?)
6971
+ WHERE id = ?`,
6972
+ args: [Math.max(oldImportance, newImportance), supersedesId, memoryId]
6973
+ }
6974
+ ], "write");
6975
+ }
6976
+ } catch (err) {
6977
+ process.stderr.write(
6978
+ `[memory-governor] post-write hygiene failed for ${memoryId}: ${err instanceof Error ? err.message : String(err)}
6979
+ `
6980
+ );
6981
+ }
6982
+ }
6983
+ function schedulePostWriteMemoryHygiene(memoryIds) {
6984
+ if (process.env.EXE_SKIP_MEMORY_HYGIENE === "1") return;
6985
+ if (memoryIds.length === 0) return;
6986
+ const run = () => {
6987
+ void Promise.all(memoryIds.map((id) => runPostWriteMemoryHygiene(id)));
6988
+ };
6989
+ if (typeof setImmediate === "function") setImmediate(run);
6990
+ else setTimeout(run, 0);
6991
+ }
6992
+ var HIGH_VALUE_SUPERSESSION_TYPES, NOISE_DROP_PATTERNS, SKIP_EMBED_PATTERNS;
6993
+ var init_memory_write_governor = __esm({
6994
+ "src/lib/memory-write-governor.ts"() {
6995
+ "use strict";
6996
+ HIGH_VALUE_SUPERSESSION_TYPES = /* @__PURE__ */ new Set([
6997
+ "decision",
6998
+ "adr",
6999
+ "behavior",
7000
+ "procedure"
7001
+ ]);
7002
+ NOISE_DROP_PATTERNS = [
7003
+ /^\s*\[📋\s+\d+\s+reviews?\s+pending\b/im,
7004
+ /^\s*<system-reminder>[\s\S]*?<\/system-reminder>\s*$/im,
7005
+ /^\s*The UserPromptSubmit hook checks the DB for new tasks/im,
7006
+ /^\s*Intercom is a speedup, not delivery/im,
7007
+ /^\s*Context bar reads as USAGE not remaining/im
7008
+ ];
7009
+ SKIP_EMBED_PATTERNS = [
7010
+ /tmux capture-pane\b/i,
7011
+ /docker ps\b/i,
7012
+ /docker images\b/i,
7013
+ /git status\b/i,
7014
+ /grep .*node_modules/i,
7015
+ /npm (install|ci)\b[\s\S]*(added \d+ packages|audited \d+ packages)/i
7016
+ ];
7017
+ }
7018
+ });
7019
+
6797
7020
  // src/lib/shard-manager.ts
6798
7021
  var shard_manager_exports = {};
6799
7022
  __export(shard_manager_exports, {
@@ -6958,7 +7181,8 @@ async function ensureShardSchema(client) {
6958
7181
  }
6959
7182
  for (const idx of [
6960
7183
  "CREATE INDEX IF NOT EXISTS idx_memories_tier ON memories(tier)",
6961
- "CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL"
7184
+ "CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL",
7185
+ "CREATE INDEX IF NOT EXISTS idx_memories_scoped_content_hash ON memories(content_hash, agent_id, project_name, memory_type) WHERE content_hash IS NOT NULL"
6962
7186
  ]) {
6963
7187
  try {
6964
7188
  await client.execute(idx);
@@ -7152,7 +7376,7 @@ var init_platform_procedures = __esm({
7152
7376
  title: "Chain of command \u2014 who talks to whom",
7153
7377
  domain: "workflow",
7154
7378
  priority: "p0",
7155
- content: "Founder -> COO -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the COO does not bypass managers for specialist work. Specialists report to their manager. If you need cross-team info, use ask_team_memory \u2014 don't read other agents' task folders. Each level owns dispatch downward and review upward."
7379
+ content: "Founder -> coordinator (the executive agent, internally routed as 'COO') -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the coordinator does not bypass managers for specialist work. Specialists report to their manager. If you need cross-team info, use ask_team_memory \u2014 don't read other agents' task folders. Each level owns dispatch downward and review upward."
7156
7380
  },
7157
7381
  {
7158
7382
  title: "Single dispatch path \u2014 create_task only",
@@ -7383,7 +7607,6 @@ __export(store_exports, {
7383
7607
  vectorToBlob: () => vectorToBlob,
7384
7608
  writeMemory: () => writeMemory
7385
7609
  });
7386
- import { createHash } from "crypto";
7387
7610
  function isBusyError2(err) {
7388
7611
  if (err instanceof Error) {
7389
7612
  const msg = err.message.toLowerCase();
@@ -7497,17 +7720,24 @@ async function writeMemory(record) {
7497
7720
  `Expected ${EMBEDDING_DIM}-dim vector, got ${record.vector.length}`
7498
7721
  );
7499
7722
  }
7500
- const contentHash2 = createHash("md5").update(record.raw_text).digest("hex");
7501
- if (_pendingRecords.some((r) => r.content_hash === contentHash2 && r.agent_id === record.agent_id)) {
7723
+ const governed = governMemoryRecord(record);
7724
+ if (governed.shouldDrop) return;
7725
+ record = governed.record;
7726
+ const contentHash2 = governed.contentHash;
7727
+ const memoryType = record.memory_type ?? "raw";
7728
+ if (_pendingRecords.some(
7729
+ (r) => r.content_hash === contentHash2 && r.agent_id === record.agent_id && r.project_name === record.project_name && (r.memory_type ?? "raw") === memoryType
7730
+ )) {
7502
7731
  return;
7503
7732
  }
7504
7733
  try {
7505
- const client = getClient();
7506
- const existing = await client.execute({
7507
- sql: "SELECT id FROM memories WHERE content_hash = ? AND agent_id = ? LIMIT 1",
7508
- args: [contentHash2, record.agent_id]
7734
+ const existing = await findScopedDuplicate({
7735
+ contentHash: contentHash2,
7736
+ agentId: record.agent_id,
7737
+ projectName: record.project_name,
7738
+ memoryType
7509
7739
  });
7510
- if (existing.rows.length > 0) return;
7740
+ if (existing) return;
7511
7741
  } catch {
7512
7742
  }
7513
7743
  const dbRow = {
@@ -7538,7 +7768,7 @@ async function writeMemory(record) {
7538
7768
  tier: record.tier ?? classifyTier(record),
7539
7769
  supersedes_id: record.supersedes_id ?? null,
7540
7770
  draft: record.draft ? 1 : 0,
7541
- memory_type: record.memory_type ?? "raw",
7771
+ memory_type: memoryType,
7542
7772
  trajectory: record.trajectory ? JSON.stringify(record.trajectory) : null,
7543
7773
  content_hash: contentHash2,
7544
7774
  intent: record.intent ?? null,
@@ -7697,6 +7927,7 @@ async function flushBatch() {
7697
7927
  const globalClient = getClient();
7698
7928
  const globalStmts = batch.map(buildStmt);
7699
7929
  await globalClient.batch(globalStmts, "write");
7930
+ schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
7700
7931
  _pendingRecords.splice(0, batch.length);
7701
7932
  try {
7702
7933
  const { isShardingEnabled: isShardingEnabled2, getReadyShardClient: getReadyShardClient2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
@@ -7817,7 +8048,11 @@ async function searchMemories(queryVector, agentId, options) {
7817
8048
  sql += ` AND timestamp >= ?`;
7818
8049
  args2.push(options.since);
7819
8050
  }
7820
- if (options?.memoryType) {
8051
+ if (options?.memoryTypes && options.memoryTypes.length > 0) {
8052
+ const uniqueTypes = [...new Set(options.memoryTypes)];
8053
+ sql += ` AND memory_type IN (${uniqueTypes.map(() => "?").join(",")})`;
8054
+ args2.push(...uniqueTypes);
8055
+ } else if (options?.memoryType) {
7821
8056
  sql += ` AND memory_type = ?`;
7822
8057
  args2.push(options.memoryType);
7823
8058
  }
@@ -7955,6 +8190,7 @@ var init_store = __esm({
7955
8190
  init_keychain();
7956
8191
  init_config();
7957
8192
  init_state_bus();
8193
+ init_memory_write_governor();
7958
8194
  INIT_MAX_RETRIES = 3;
7959
8195
  INIT_RETRY_DELAY_MS = 1e3;
7960
8196
  _pendingRecords = [];
@@ -8949,7 +9185,7 @@ __export(identity_exports, {
8949
9185
  import { existsSync as existsSync16, mkdirSync as mkdirSync9, readFileSync as readFileSync11, writeFileSync as writeFileSync9 } from "fs";
8950
9186
  import { readdirSync as readdirSync4 } from "fs";
8951
9187
  import path17 from "path";
8952
- import { createHash as createHash2 } from "crypto";
9188
+ import { createHash as createHash3 } from "crypto";
8953
9189
  function ensureDir() {
8954
9190
  if (!existsSync16(IDENTITY_DIR2)) {
8955
9191
  mkdirSync9(IDENTITY_DIR2, { recursive: true });
@@ -8993,7 +9229,7 @@ function parseFrontmatter(raw) {
8993
9229
  };
8994
9230
  }
8995
9231
  function contentHash(content) {
8996
- return createHash2("sha256").update(content).digest("hex").slice(0, 16);
9232
+ return createHash3("sha256").update(content).digest("hex").slice(0, 16);
8997
9233
  }
8998
9234
  function getIdentity(agentId) {
8999
9235
  const filePath = identityPath(agentId);
@@ -12955,7 +13191,11 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
12955
13191
  }
12956
13192
  if (!useExeAgent && !useCodex && !useOpencode && !useBinSymlink) {
12957
13193
  if (agentRtConfig.runtime === "claude" && agentRtConfig.model) {
12958
- envPrefix = `${envPrefix} ANTHROPIC_MODEL=${agentRtConfig.model}`;
13194
+ let ccModel = agentRtConfig.model.replace(/(\d+)\.(\d+)/g, "$1-$2");
13195
+ if (/claude-(opus|sonnet)-4-[6-9]/.test(ccModel) && !ccModel.includes("[1m]")) {
13196
+ ccModel += "[1m]";
13197
+ }
13198
+ envPrefix = `${envPrefix} ANTHROPIC_MODEL=${ccModel}`;
12959
13199
  }
12960
13200
  }
12961
13201
  let spawnCommand;
@@ -13586,8 +13826,9 @@ function personalizePrompt(prompt, templateName, actualName) {
13586
13826
  return prompt.replace(new RegExp(`\\bYou are ${escaped}\\b`, "g"), `You are ${actualName}`);
13587
13827
  }
13588
13828
  function renderClientCOOTemplate(vars) {
13829
+ const resolved = { ...vars, title: vars.title || "Chief Operating Officer" };
13589
13830
  for (const key of CLIENT_COO_PLACEHOLDERS) {
13590
- const value = vars[key];
13831
+ const value = resolved[key];
13591
13832
  if (typeof value !== "string" || value.length === 0) {
13592
13833
  throw new Error(
13593
13834
  `renderClientCOOTemplate: missing required variable "${key}"`
@@ -13596,7 +13837,7 @@ function renderClientCOOTemplate(vars) {
13596
13837
  }
13597
13838
  let out = CLIENT_COO_TEMPLATE;
13598
13839
  for (const key of CLIENT_COO_PLACEHOLDERS) {
13599
- out = out.split(`{{${key}}}`).join(vars[key]);
13840
+ out = out.split(`{{${key}}}`).join(resolved[key]);
13600
13841
  }
13601
13842
  if (vars.industry_context) {
13602
13843
  out += "\n" + vars.industry_context;
@@ -14073,7 +14314,7 @@ created_by: system
14073
14314
  ---
14074
14315
  ## Identity
14075
14316
 
14076
- You are {{agent_name}}, the Chief Operating Officer at {{company_name}}.
14317
+ You are {{agent_name}}, the {{title}} at {{company_name}}.
14077
14318
 
14078
14319
  You are {{founder_name}}'s most reliable teammate in business \u2014 the knowledgeable older sibling who has been through it all. You have seen projects succeed and fail. You know what matters and what is noise. You do not get anxious about problems; you see them coming, stay calm, and handle them.
14079
14320
 
@@ -14160,7 +14401,8 @@ All memory, tasks, behaviors, documents, and wiki content belonging to {{company
14160
14401
  CLIENT_COO_PLACEHOLDERS = [
14161
14402
  "agent_name",
14162
14403
  "company_name",
14163
- "founder_name"
14404
+ "founder_name",
14405
+ "title"
14164
14406
  ];
14165
14407
  }
14166
14408
  });
@@ -14368,7 +14610,7 @@ var init_exe_rename = __esm({
14368
14610
  // src/lib/model-downloader.ts
14369
14611
  import { createWriteStream, createReadStream as createReadStream2, existsSync as existsSync26, unlinkSync as unlinkSync12, renameSync as renameSync5 } from "fs";
14370
14612
  import { mkdir as mkdir6 } from "fs/promises";
14371
- import { createHash as createHash3 } from "crypto";
14613
+ import { createHash as createHash4 } from "crypto";
14372
14614
  import path32 from "path";
14373
14615
  async function downloadModel(opts) {
14374
14616
  const { destDir, onProgress, fetchFn = globalThis.fetch } = opts;
@@ -14396,7 +14638,7 @@ async function downloadModel(opts) {
14396
14638
  throw new Error(`Download failed: HTTP ${response.status}`);
14397
14639
  }
14398
14640
  const contentLength = Number(response.headers.get("content-length") ?? EXPECTED_SIZE);
14399
- const hash = createHash3("sha256");
14641
+ const hash = createHash4("sha256");
14400
14642
  const fileStream = createWriteStream(tmpPath);
14401
14643
  const reader = response.body.getReader();
14402
14644
  try {
@@ -14440,7 +14682,7 @@ Download attempt ${attempt} failed, retrying...
14440
14682
  }
14441
14683
  async function fileHash(filePath) {
14442
14684
  return new Promise((resolve, reject) => {
14443
- const hash = createHash3("sha256");
14685
+ const hash = createHash4("sha256");
14444
14686
  const stream = createReadStream2(filePath);
14445
14687
  stream.on("data", (chunk) => hash.update(chunk));
14446
14688
  stream.on("end", () => resolve(hash.digest("hex")));
@@ -1323,7 +1323,7 @@ var PLATFORM_PROCEDURES = [
1323
1323
  title: "Chain of command \u2014 who talks to whom",
1324
1324
  domain: "workflow",
1325
1325
  priority: "p0",
1326
- content: "Founder -> COO -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the COO does not bypass managers for specialist work. Specialists report to their manager. If you need cross-team info, use ask_team_memory \u2014 don't read other agents' task folders. Each level owns dispatch downward and review upward."
1326
+ content: "Founder -> coordinator (the executive agent, internally routed as 'COO') -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the coordinator does not bypass managers for specialist work. Specialists report to their manager. If you need cross-team info, use ask_team_memory \u2014 don't read other agents' task folders. Each level owns dispatch downward and review upward."
1327
1327
  },
1328
1328
  {
1329
1329
  title: "Single dispatch path \u2014 create_task only",