@askexenow/exe-os 0.9.111 → 0.9.113

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 (95) hide show
  1. package/README.md +9 -7
  2. package/dist/bin/agentic-ontology-backfill.js +62 -12
  3. package/dist/bin/agentic-reflection-backfill.js +37 -2
  4. package/dist/bin/agentic-semantic-label.js +37 -2
  5. package/dist/bin/backfill-conversations.js +61 -11
  6. package/dist/bin/backfill-responses.js +62 -12
  7. package/dist/bin/backfill-vectors.js +37 -2
  8. package/dist/bin/bulk-sync-postgres.js +63 -13
  9. package/dist/bin/cleanup-stale-review-tasks.js +83 -16
  10. package/dist/bin/cli.js +312 -80
  11. package/dist/bin/exe-agent-config.js +7 -1
  12. package/dist/bin/exe-agent.js +29 -3
  13. package/dist/bin/exe-assign.js +62 -12
  14. package/dist/bin/exe-boot.js +500 -151
  15. package/dist/bin/exe-call.js +46 -5
  16. package/dist/bin/exe-cloud.js +101 -16
  17. package/dist/bin/exe-dispatch.js +827 -27
  18. package/dist/bin/exe-doctor.js +61 -11
  19. package/dist/bin/exe-export-behaviors.js +67 -14
  20. package/dist/bin/exe-forget.js +62 -12
  21. package/dist/bin/exe-gateway.js +147 -27
  22. package/dist/bin/exe-heartbeat.js +83 -16
  23. package/dist/bin/exe-kill.js +62 -12
  24. package/dist/bin/exe-launch-agent.js +83 -15
  25. package/dist/bin/exe-new-employee.js +176 -8
  26. package/dist/bin/exe-pending-messages.js +83 -16
  27. package/dist/bin/exe-pending-notifications.js +83 -16
  28. package/dist/bin/exe-pending-reviews.js +83 -16
  29. package/dist/bin/exe-rename.js +62 -12
  30. package/dist/bin/exe-review.js +62 -12
  31. package/dist/bin/exe-search.js +62 -12
  32. package/dist/bin/exe-session-cleanup.js +949 -149
  33. package/dist/bin/exe-settings.js +10 -4
  34. package/dist/bin/exe-start-codex.js +537 -248
  35. package/dist/bin/exe-start-opencode.js +547 -168
  36. package/dist/bin/exe-status.js +83 -16
  37. package/dist/bin/exe-support.js +1 -1
  38. package/dist/bin/exe-team.js +62 -12
  39. package/dist/bin/git-sweep.js +827 -27
  40. package/dist/bin/graph-backfill.js +62 -12
  41. package/dist/bin/graph-export.js +62 -12
  42. package/dist/bin/install.js +62 -4
  43. package/dist/bin/intercom-check.js +949 -149
  44. package/dist/bin/pre-publish.js +14 -2
  45. package/dist/bin/scan-tasks.js +827 -27
  46. package/dist/bin/setup.js +99 -14
  47. package/dist/bin/shard-migrate.js +62 -12
  48. package/dist/bin/stack-update.js +1 -1
  49. package/dist/bin/update.js +3 -3
  50. package/dist/gateway/index.js +586 -26
  51. package/dist/hooks/bug-report-worker.js +586 -26
  52. package/dist/hooks/codex-stop-task-finalizer.js +977 -143
  53. package/dist/hooks/commit-complete.js +827 -27
  54. package/dist/hooks/error-recall.js +62 -12
  55. package/dist/hooks/ingest.js +4579 -249
  56. package/dist/hooks/instructions-loaded.js +62 -12
  57. package/dist/hooks/notification.js +62 -12
  58. package/dist/hooks/post-compact.js +83 -16
  59. package/dist/hooks/post-tool-combined.js +83 -16
  60. package/dist/hooks/pre-compact.js +907 -107
  61. package/dist/hooks/pre-tool-use.js +98 -16
  62. package/dist/hooks/prompt-submit.js +596 -30
  63. package/dist/hooks/session-end.js +909 -112
  64. package/dist/hooks/session-start.js +112 -17
  65. package/dist/hooks/stop.js +82 -15
  66. package/dist/hooks/subagent-stop.js +83 -16
  67. package/dist/hooks/summary-worker.js +81 -8
  68. package/dist/index.js +595 -29
  69. package/dist/lib/agent-config.js +16 -1
  70. package/dist/lib/cloud-sync.js +45 -1
  71. package/dist/lib/consolidation.js +16 -1
  72. package/dist/lib/database.js +23 -0
  73. package/dist/lib/db.js +23 -0
  74. package/dist/lib/device-registry.js +23 -0
  75. package/dist/lib/employee-templates.js +30 -4
  76. package/dist/lib/employees.js +16 -1
  77. package/dist/lib/exe-daemon.js +482 -52
  78. package/dist/lib/hybrid-search.js +62 -12
  79. package/dist/lib/license.js +3 -3
  80. package/dist/lib/messaging.js +21 -4
  81. package/dist/lib/schedules.js +37 -2
  82. package/dist/lib/skill-learning.js +910 -41
  83. package/dist/lib/status-brief.js +14 -1
  84. package/dist/lib/store.js +62 -12
  85. package/dist/lib/tasks.js +843 -93
  86. package/dist/lib/tmux-routing.js +766 -16
  87. package/dist/mcp/server.js +238 -41
  88. package/dist/mcp/tools/create-task.js +525 -15
  89. package/dist/mcp/tools/deactivate-behavior.js +33 -24
  90. package/dist/mcp/tools/list-tasks.js +21 -4
  91. package/dist/mcp/tools/send-message.js +21 -4
  92. package/dist/mcp/tools/update-task.js +840 -93
  93. package/dist/runtime/index.js +913 -107
  94. package/dist/tui/App.js +227 -58
  95. package/package.json +1 -1
package/dist/bin/cli.js CHANGED
@@ -369,6 +369,7 @@ __export(agent_config_exports, {
369
369
  getAgentRuntime: () => getAgentRuntime,
370
370
  loadAgentConfig: () => loadAgentConfig,
371
371
  saveAgentConfig: () => saveAgentConfig,
372
+ setAgentMcps: () => setAgentMcps,
372
373
  setAgentRuntime: () => setAgentRuntime
373
374
  });
374
375
  import { readFileSync as readFileSync2, writeFileSync, existsSync as existsSync3 } from "fs";
@@ -395,7 +396,7 @@ function getAgentRuntime(agentId) {
395
396
  if (orgDefault) return orgDefault;
396
397
  return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
397
398
  }
398
- function setAgentRuntime(agentId, runtime, model, reasoning_effort) {
399
+ function setAgentRuntime(agentId, runtime, model, reasoning_effort, mcps) {
399
400
  const knownModels = KNOWN_RUNTIMES[runtime];
400
401
  if (!knownModels) {
401
402
  return {
@@ -410,12 +411,26 @@ function setAgentRuntime(agentId, runtime, model, reasoning_effort) {
410
411
  };
411
412
  }
412
413
  const config = loadAgentConfig();
414
+ const existing = config[agentId];
413
415
  const entry = { runtime, model };
414
416
  if (reasoning_effort) entry.reasoning_effort = reasoning_effort;
417
+ if (mcps !== void 0) {
418
+ entry.mcps = mcps.includes("exe-os") ? mcps : ["exe-os", ...mcps];
419
+ } else if (existing?.mcps) {
420
+ entry.mcps = existing.mcps;
421
+ }
415
422
  config[agentId] = entry;
416
423
  saveAgentConfig(config);
417
424
  return { ok: true };
418
425
  }
426
+ function setAgentMcps(agentId, mcps) {
427
+ const config = loadAgentConfig();
428
+ const existing = config[agentId] ?? getAgentRuntime(agentId);
429
+ existing.mcps = mcps.includes("exe-os") ? mcps : ["exe-os", ...mcps];
430
+ config[agentId] = existing;
431
+ saveAgentConfig(config);
432
+ return { ok: true };
433
+ }
419
434
  function clearAgentRuntime(agentId) {
420
435
  const config = loadAgentConfig();
421
436
  delete config[agentId];
@@ -842,6 +857,16 @@ import { chmodSync as chmodSync2, existsSync as existsSync7, mkdirSync as mkdirS
842
857
  import { randomBytes } from "crypto";
843
858
  import path6 from "path";
844
859
  import os5 from "os";
860
+ function resolveDefaultAgentId() {
861
+ if (process.env.AGENT_ID && process.env.AGENT_ID !== "default") return process.env.AGENT_ID;
862
+ try {
863
+ const { loadEmployeesSync: loadEmployeesSync2 } = (init_employees(), __toCommonJS(employees_exports));
864
+ const coo = loadEmployeesSync2().find((e) => e.role === "COO");
865
+ if (coo) return coo.name;
866
+ } catch {
867
+ }
868
+ return "exe";
869
+ }
845
870
  function mcpHttpPort() {
846
871
  return process.env.EXE_MCP_PORT || DEFAULT_MCP_HTTP_PORT;
847
872
  }
@@ -871,11 +896,14 @@ function readOrCreateDaemonToken(homeDir = os5.homedir()) {
871
896
  function buildMcpHttpHeaders(homeDir = os5.homedir(), opts = {}) {
872
897
  const agentId = opts.useShellPlaceholders ? "${AGENT_ID:-exe}" : opts.agentId ?? DEFAULT_MCP_HTTP_AGENT_ID;
873
898
  const agentRole = opts.useShellPlaceholders ? "${AGENT_ROLE:-COO}" : opts.agentRole ?? DEFAULT_MCP_HTTP_AGENT_ROLE;
874
- return {
899
+ const sessionName = opts.useShellPlaceholders ? "$(tmux display-message -p '#{session_name}' 2>/dev/null || echo '')" : process.env.EXE_SESSION_NAME ?? "";
900
+ const headers = {
875
901
  Authorization: `Bearer ${readOrCreateDaemonToken(homeDir)}`,
876
902
  "X-Agent-Id": agentId,
877
903
  "X-Agent-Role": agentRole
878
904
  };
905
+ if (sessionName) headers["X-Exe-Session"] = sessionName;
906
+ return headers;
879
907
  }
880
908
  function buildClaudeHttpMcpEntry(homeDir = os5.homedir()) {
881
909
  return {
@@ -889,12 +917,15 @@ var init_mcp_http_config = __esm({
889
917
  "src/adapters/mcp-http-config.ts"() {
890
918
  "use strict";
891
919
  DEFAULT_MCP_HTTP_PORT = "48739";
892
- DEFAULT_MCP_HTTP_AGENT_ID = "exe";
920
+ DEFAULT_MCP_HTTP_AGENT_ID = resolveDefaultAgentId();
893
921
  DEFAULT_MCP_HTTP_AGENT_ROLE = "COO";
894
922
  }
895
923
  });
896
924
 
897
925
  // src/adapters/runtime-hook-manifest.ts
926
+ function isLegacyHomeDirHookCommand(command) {
927
+ return LEGACY_HOME_DIR_HOOK_PATTERNS.some((pattern) => command.includes(pattern));
928
+ }
898
929
  function commandHasAnyMarker(command, markers) {
899
930
  return markers.some((marker) => command.includes(marker));
900
931
  }
@@ -904,7 +935,7 @@ function isLegacySplitPostToolCommand(command) {
904
935
  function textHasLegacySplitPostToolHook(text) {
905
936
  return [EXE_HOOK_FILES.ingest, EXE_HOOK_FILES.errorRecall, EXE_HOOK_FILES.ingestWorker].some((file) => text.includes(file));
906
937
  }
907
- var EXE_HOOK_FILES, EXE_HOOKS, EXE_HOOK_MANIFEST, LEGACY_SPLIT_POST_TOOL_HOOK_MARKERS;
938
+ var EXE_HOOK_FILES, EXE_HOOKS, EXE_HOOK_MANIFEST, LEGACY_SPLIT_POST_TOOL_HOOK_MARKERS, LEGACY_HOME_DIR_HOOK_PATTERNS;
908
939
  var init_runtime_hook_manifest = __esm({
909
940
  "src/adapters/runtime-hook-manifest.ts"() {
910
941
  "use strict";
@@ -1043,6 +1074,14 @@ var init_runtime_hook_manifest = __esm({
1043
1074
  "dist/hooks/error-recall.js",
1044
1075
  "dist/hooks/ingest-worker.js"
1045
1076
  ];
1077
+ LEGACY_HOME_DIR_HOOK_PATTERNS = [
1078
+ ".exe-os/hooks/",
1079
+ // Old hook storage path (pre-npm-package era)
1080
+ "log-prefix.js",
1081
+ // Removed hook from early versions
1082
+ "approval-bridge.log"
1083
+ // Removed log redirect from early versions
1084
+ ];
1046
1085
  }
1047
1086
  });
1048
1087
 
@@ -1522,6 +1561,14 @@ async function mergeHooks(packageRoot, homeDir = os6.homedir()) {
1522
1561
  ];
1523
1562
  let added = 0;
1524
1563
  let skipped = 0;
1564
+ for (const eventKey of Object.keys(settings.hooks)) {
1565
+ const groups = settings.hooks[eventKey];
1566
+ if (!Array.isArray(groups)) continue;
1567
+ settings.hooks[eventKey] = groups.map((g) => ({
1568
+ ...g,
1569
+ hooks: g.hooks.filter((h) => !isLegacyHomeDirHookCommand(h.command))
1570
+ })).filter((g) => g.hooks.length > 0);
1571
+ }
1525
1572
  const postToolGroups = settings.hooks["PostToolUse"];
1526
1573
  if (Array.isArray(postToolGroups)) {
1527
1574
  settings.hooks["PostToolUse"] = postToolGroups.map((g) => ({
@@ -4692,6 +4739,13 @@ async function ensureSchema() {
4692
4739
  } catch (e) {
4693
4740
  logCatchDebug("migration", e);
4694
4741
  }
4742
+ for (const col of ["created_by_agent TEXT", "created_by_device TEXT", "source_session_id TEXT"]) {
4743
+ try {
4744
+ await client.execute({ sql: `ALTER TABLE behaviors ADD COLUMN ${col}`, args: [] });
4745
+ } catch (e) {
4746
+ logCatchDebug("migration", e);
4747
+ }
4748
+ }
4695
4749
  try {
4696
4750
  await client.execute({
4697
4751
  sql: `ALTER TABLE tasks ADD COLUMN blocked_by TEXT`,
@@ -5908,6 +5962,22 @@ async function ensureSchema() {
5908
5962
  } catch (e) {
5909
5963
  logCatchDebug("migration", e);
5910
5964
  }
5965
+ try {
5966
+ await client.execute({
5967
+ sql: `ALTER TABLE memories ADD COLUMN visibility TEXT DEFAULT 'private'`,
5968
+ args: []
5969
+ });
5970
+ } catch (e) {
5971
+ logCatchDebug("migration", e);
5972
+ }
5973
+ try {
5974
+ await client.execute({
5975
+ sql: `ALTER TABLE memories ADD COLUMN strength REAL DEFAULT 1.0`,
5976
+ args: []
5977
+ });
5978
+ } catch (e) {
5979
+ logCatchDebug("migration", e);
5980
+ }
5911
5981
  }
5912
5982
  async function disposeDatabase() {
5913
5983
  if (_walCheckpointTimer) {
@@ -6453,7 +6523,7 @@ async function assertVpsLicense(opts) {
6453
6523
  }
6454
6524
  if (!transientFailure) {
6455
6525
  throw new Error(
6456
- "License validation failed: unknown backend state. Restore network connectivity to https://askexe.com/cloud and retry."
6526
+ "License validation failed: unknown backend state. Restore network connectivity to https://cloud.askexe.com and retry."
6457
6527
  );
6458
6528
  }
6459
6529
  const fresh = await getCachedLicense();
@@ -6490,7 +6560,7 @@ async function assertVpsLicense(opts) {
6490
6560
  } catch {
6491
6561
  }
6492
6562
  throw new Error(
6493
- `License validation unreachable for more than ${graceDays} days. Restore network connectivity to https://askexe.com/cloud and retry. This VPS image refuses to boot after the offline grace window.`
6563
+ `License validation unreachable for more than ${graceDays} days. Restore network connectivity to https://cloud.askexe.com and retry. This VPS image refuses to boot after the offline grace window.`
6494
6564
  );
6495
6565
  }
6496
6566
  function startLicenseRevalidation(intervalMs = 36e5) {
@@ -6522,7 +6592,7 @@ var init_license = __esm({
6522
6592
  LICENSE_PATH = path13.join(EXE_AI_DIR, "license.key");
6523
6593
  CACHE_PATH = path13.join(EXE_AI_DIR, "license-cache.json");
6524
6594
  DEVICE_ID_PATH = path13.join(EXE_AI_DIR, "device-id");
6525
- API_BASE = process.env.EXE_CLOUD_ENDPOINT ?? "https://askexe.com/cloud";
6595
+ API_BASE = process.env.EXE_CLOUD_ENDPOINT ?? "https://cloud.askexe.com";
6526
6596
  RETRY_DELAY_MS = 500;
6527
6597
  LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
6528
6598
  MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
@@ -7325,6 +7395,27 @@ async function cloudSync(config) {
7325
7395
  if (stmts.length > 0) await client.batch(stmts, "write");
7326
7396
  pulled = pullResult.records.length;
7327
7397
  } else {
7398
+ try {
7399
+ const incomingIds = pullResult.records.map((r) => sqlSafe(r.id));
7400
+ if (incomingIds.length > 0) {
7401
+ const ph = incomingIds.map(() => "?").join(",");
7402
+ const existing = await client.execute({
7403
+ sql: `SELECT id, version, timestamp FROM memories WHERE id IN (${ph})`,
7404
+ args: incomingIds
7405
+ });
7406
+ const localMap = new Map(existing.rows.map((r) => [String(r.id), r]));
7407
+ for (const rec of pullResult.records) {
7408
+ const local = localMap.get(String(rec.id));
7409
+ if (local && Number(local.version) > 0 && Number(local.version) !== Number(rec.version ?? 0)) {
7410
+ process.stderr.write(
7411
+ `[cloud-sync] CONFLICT: memory ${String(rec.id).slice(0, 8)} \u2014 local v${local.version} vs remote v${rec.version ?? 0}. Remote wins (LWW).
7412
+ `
7413
+ );
7414
+ }
7415
+ }
7416
+ }
7417
+ } catch {
7418
+ }
7328
7419
  const stmts = pullResult.records.map((rec) => ({
7329
7420
  sql: `INSERT OR REPLACE INTO memories
7330
7421
  (id, agent_id, agent_role, session_id, timestamp,
@@ -9082,11 +9173,17 @@ var init_platform_procedures = __esm({
9082
9173
  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."
9083
9174
  },
9084
9175
  {
9085
- title: "Customer orchestration maturity \u2014 recommend, never trap",
9176
+ title: "Orchestration phase guidance \u2014 recommend, never trap",
9086
9177
  domain: "workflow",
9087
9178
  priority: "p1",
9088
9179
  content: "New customers start best in Phase 1: founder \u2194 coordinator/Chief of Staff, building company context. Suggest Phase 2 executives when domain work repeats; suggest Phase 3 parallel execution only when review/permission gates are ready. This is guidance, not a blocker: users may jump phases anytime. Never overwrite their phase, role titles, identities, or custom org design."
9089
9180
  },
9181
+ {
9182
+ title: "Routing slot vs display title \u2014 internal 'coo' is plumbing, not your name",
9183
+ domain: "identity",
9184
+ priority: "p0",
9185
+ content: "These procedures reference 'COO' as a shorthand for the coordinator role. This is an INTERNAL routing slot used by exe-os code (chain-of-command checks, dispatch logic, session detection). It is NOT your display title. Your actual title comes from your identity file's `title:` field \u2014 that is what you use externally: introductions, sign-offs, team comms, and any user-facing text. If your identity says `title: AI Chief of Staff`, you are the AI Chief of Staff. The routing slot stays `role: coo` for code compatibility \u2014 never rename it, but also never introduce yourself as 'COO' unless your identity file explicitly says so. The founder chose your title; respect it."
9186
+ },
9090
9187
  {
9091
9188
  title: "Single dispatch path \u2014 create_task only",
9092
9189
  domain: "workflow",
@@ -9120,6 +9217,12 @@ var init_platform_procedures = __esm({
9120
9217
  priority: "p0",
9121
9218
  content: "NEVER: (1) Access the database directly \u2014 it's SQLCipher encrypted, always fails. Use MCP tools only. (2) Manually spawn tmux sessions \u2014 create_task handles it. (3) Run git checkout main \u2014 agents work in worktrees. (4) Modify another agent's in-progress task. (5) Push to remote \u2014 the COO reviews and pushes. (6) Skip update_task(done) \u2014 it's the ONLY way your work gets reviewed. (7) Run git init."
9122
9219
  },
9220
+ {
9221
+ title: "Destructive operations \u2014 mandatory reviewer gate",
9222
+ domain: "security",
9223
+ priority: "p0",
9224
+ content: "Before ANY destructive operation (delete, remove, overwrite, drop, reset, force-push, truncate), you MUST: (1) Have your full task spec accessible \u2014 if you cannot read it, STOP and report to your reviewer. Never improvise destructive actions. (2) Confirm with your reviewer (assigned_by or COO) before executing. (3) If the task spec explicitly authorizes the operation, proceed \u2014 but log it. Violation = immediate task failure. This applies to ALL agents regardless of role."
9225
+ },
9123
9226
  {
9124
9227
  title: "Customer patch triage \u2014 upstream bug vs customization",
9125
9228
  domain: "support",
@@ -9271,7 +9374,7 @@ var init_platform_procedures = __esm({
9271
9374
  title: "MCP tool dispatch \u2014 all tools use action parameter",
9272
9375
  domain: "tool-use",
9273
9376
  priority: "p0",
9274
- content: 'exe-os MCP tools come in two surfaces depending on EXE_MCP_TOOL_SURFACE config. Consolidated (19 tools): action-based dispatch \u2014 memory(action="recall"), task(action="create"), etc. Legacy (108 tools): one tool per operation \u2014 recall_my_memory, create_task, etc. Both surfaces have identical functionality. Use whichever tool names are available in your session. If you see domain tools (memory, task, config, etc.), use the action parameter. If you see specific tools (recall_my_memory, create_task, etc.), call them directly.'
9377
+ content: 'exe-os MCP tools use consolidated action-based dispatch by default (19 tools). Call domain tools with an action parameter: memory(action="recall"), task(action="create"), config(action="list_employees"), etc. Legacy mode (108 separate tools like recall_my_memory, create_task) is still available via EXE_MCP_TOOL_SURFACE=legacy but will be removed in a future version. If you see specific tool names, call them directly \u2014 both surfaces are identical. Consolidated is the default and recommended surface.'
9275
9378
  },
9276
9379
  {
9277
9380
  title: "MCP tools \u2014 memory, decision, and search",
@@ -9405,10 +9508,24 @@ function stableId(memoryId, type, content) {
9405
9508
  return createHash3("sha256").update(`${memoryId}:${type}:${content}`).digest("hex").slice(0, 32);
9406
9509
  }
9407
9510
  function cleanText(text) {
9408
- return text.replace(/```[\s\S]*?```/g, " ").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
9511
+ let cleaned = text.replace(
9512
+ /```(\w*)\n(.*?)(?:\n[\s\S]*?)```/g,
9513
+ (_m, lang, firstLine) => `[code${lang ? `:${lang}` : ""}] ${firstLine.trim()}`
9514
+ );
9515
+ cleaned = cleaned.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
9516
+ return cleaned;
9409
9517
  }
9410
- function splitSentences(text) {
9411
- return cleanText(text).split(/(?<=[.!?])\s+|\n+/).map((s) => s.trim()).filter((s) => s.length >= 24 && s.length <= MAX_SENTENCE_CHARS);
9518
+ function splitSegments(text) {
9519
+ const cleaned = cleanText(text);
9520
+ const segments = cleaned.split(/(?<=[.!?:;])\s+|\n{2,}|(?<=\))\s+(?=[A-Z])|\s*[|│]\s*/).map((s) => s.trim()).filter((s) => s.length >= MIN_SEGMENT_CHARS && s.length <= MAX_SEGMENT_CHARS);
9521
+ if (segments.length === 0 && cleaned.length >= MIN_SEGMENT_CHARS) {
9522
+ const lines = cleaned.split(/\n+/).map((l) => l.trim()).filter((l) => l.length >= MIN_SEGMENT_CHARS && l.length <= MAX_SEGMENT_CHARS);
9523
+ if (lines.length > 0) return lines;
9524
+ if (cleaned.length >= MIN_SEGMENT_CHARS) {
9525
+ return [cleaned.slice(0, MAX_SEGMENT_CHARS)];
9526
+ }
9527
+ }
9528
+ return segments;
9412
9529
  }
9413
9530
  function inferCardType(sentence, toolName) {
9414
9531
  const lower = sentence.toLowerCase();
@@ -9440,12 +9557,12 @@ function predicateFor(type) {
9440
9557
  }
9441
9558
  }
9442
9559
  function extractMemoryCards(row) {
9443
- const sentences = splitSentences(row.raw_text);
9560
+ const segments = splitSegments(row.raw_text);
9444
9561
  const cards = [];
9445
- for (const sentence of sentences) {
9562
+ for (const sentence of segments) {
9446
9563
  const type = inferCardType(sentence, row.tool_name);
9447
9564
  const subject = extractSubject(sentence, row.agent_id);
9448
- const content = sentence.length > MAX_SENTENCE_CHARS ? `${sentence.slice(0, MAX_SENTENCE_CHARS - 1)}\u2026` : sentence;
9565
+ const content = sentence.length > MAX_SEGMENT_CHARS ? `${sentence.slice(0, MAX_SEGMENT_CHARS - 1)}\u2026` : sentence;
9449
9566
  cards.push({
9450
9567
  id: stableId(row.id, type, content),
9451
9568
  memory_id: row.id,
@@ -9541,13 +9658,14 @@ Source memory: ${String(row.source_ref ?? row.memory_id)}`,
9541
9658
  last_accessed: String(row.timestamp)
9542
9659
  }));
9543
9660
  }
9544
- var MAX_CARDS_PER_MEMORY, MAX_SENTENCE_CHARS;
9661
+ var MAX_CARDS_PER_MEMORY, MAX_SEGMENT_CHARS, MIN_SEGMENT_CHARS;
9545
9662
  var init_memory_cards = __esm({
9546
9663
  "src/lib/memory-cards.ts"() {
9547
9664
  "use strict";
9548
9665
  init_database();
9549
- MAX_CARDS_PER_MEMORY = 6;
9550
- MAX_SENTENCE_CHARS = 360;
9666
+ MAX_CARDS_PER_MEMORY = 8;
9667
+ MAX_SEGMENT_CHARS = 500;
9668
+ MIN_SEGMENT_CHARS = 20;
9551
9669
  }
9552
9670
  });
9553
9671
 
@@ -10638,7 +10756,7 @@ async function setupMode() {
10638
10756
  rl.close();
10639
10757
  return;
10640
10758
  }
10641
- const endpoint = await ask(rl, " Endpoint [https://askexe.com/cloud]: ") || "https://askexe.com/cloud";
10759
+ const endpoint = await ask(rl, " Endpoint [https://cloud.askexe.com]: ") || "https://cloud.askexe.com";
10642
10760
  console.log(" Validating...");
10643
10761
  try {
10644
10762
  assertSecureEndpoint(endpoint);
@@ -10704,6 +10822,14 @@ async function setupMode() {
10704
10822
  }
10705
10823
  console.log("");
10706
10824
  }
10825
+ try {
10826
+ const keyInfo = await getKeyStorageInfo();
10827
+ if (keyInfo.kind !== "missing") {
10828
+ console.log(` \u2713 Encryption key: ${keyInfo.note}`);
10829
+ }
10830
+ } catch {
10831
+ }
10832
+ console.log("");
10707
10833
  console.log(BAR);
10708
10834
  console.log(latestConfig.cloud?.apiKey ? " Setup complete. Cloud sync is connected." : " Setup complete. Cloud sync is not configured yet.");
10709
10835
  console.log(BAR);
@@ -10795,7 +10921,13 @@ async function statusMode() {
10795
10921
  console.log("");
10796
10922
  if (key) {
10797
10923
  const fingerprint = key.toString("hex").slice(0, 8);
10798
- console.log(` Encryption key: \u2713 present (${fingerprint}...)`);
10924
+ let storageNote = "";
10925
+ try {
10926
+ const keyInfo = await getKeyStorageInfo();
10927
+ if (keyInfo.kind !== "missing") storageNote = ` [${keyInfo.note}]`;
10928
+ } catch {
10929
+ }
10930
+ console.log(` Encryption key: \u2713 present (${fingerprint}...)${storageNote}`);
10799
10931
  } else {
10800
10932
  console.log(" Encryption key: \u2717 not found \u2014 run /exe-setup");
10801
10933
  }
@@ -12284,17 +12416,14 @@ var backfill_metadata_exports = {};
12284
12416
  __export(backfill_metadata_exports, {
12285
12417
  backfillMetadata: () => backfillMetadata
12286
12418
  });
12287
- function roleAgentMarkers(role, fallbackName) {
12419
+ function roleAgentMarkers(role) {
12288
12420
  try {
12289
12421
  const employees = loadEmployeesSync();
12290
- const employee = getEmployeeByRole(employees, role);
12291
- const configuredName = employee?.name?.toLowerCase().trim();
12292
- if (configuredName) {
12293
- return [configuredName];
12294
- }
12422
+ const names = getEmployeeNamesByRole(employees, role).map((n) => n.toLowerCase().trim()).filter(Boolean);
12423
+ if (names.length > 0) return names;
12295
12424
  } catch {
12296
12425
  }
12297
- return [fallbackName];
12426
+ return [];
12298
12427
  }
12299
12428
  function mentionsAgentMarker(text, markers) {
12300
12429
  return markers.some(
@@ -12853,8 +12982,8 @@ var init_backfill_metadata = __esm({
12853
12982
  VALID_LANGUAGE_TYPES = /* @__PURE__ */ new Set(["code", "prose", "mixed", "json", "sql"]);
12854
12983
  MAX_TEXT_LENGTH = 2e3;
12855
12984
  BATCH_SLEEP_MS = 1e3;
12856
- MARKETING_AGENT_MARKERS = roleAgentMarkers("CMO", "mari");
12857
- RESEARCH_AGENT_MARKERS = roleAgentMarkers("AI Product Lead", "gen");
12985
+ MARKETING_AGENT_MARKERS = roleAgentMarkers("CMO");
12986
+ RESEARCH_AGENT_MARKERS = roleAgentMarkers("AI Product Lead");
12858
12987
  if (isMainModule(import.meta.url)) {
12859
12988
  const options = parseArgs2(process.argv.slice(2));
12860
12989
  backfillMetadata(options).then((result) => {
@@ -14334,6 +14463,19 @@ async function resolveTask(client, identifier, scopeSession) {
14334
14463
  args: [identifier, ...scope.args]
14335
14464
  });
14336
14465
  if (result.rows.length === 1) return result.rows[0];
14466
+ if (/^[a-f0-9]{7,12}$/i.test(identifier)) {
14467
+ result = await client.execute({
14468
+ sql: `SELECT * FROM tasks WHERE id LIKE ?`,
14469
+ args: [`${identifier}%`]
14470
+ });
14471
+ if (result.rows.length === 1) return result.rows[0];
14472
+ if (result.rows.length > 1) {
14473
+ const matches = result.rows.map((r) => `${String(r.id)} "${String(r.title)}" (${String(r.status)})`).join(", ");
14474
+ throw new Error(
14475
+ `Multiple tasks match short-ID "${identifier}": ${matches}. Use a longer prefix to disambiguate.`
14476
+ );
14477
+ }
14478
+ }
14337
14479
  result = await client.execute({
14338
14480
  sql: `SELECT * FROM tasks WHERE task_file LIKE ?${scope.sql}`,
14339
14481
  args: [`%${identifier}%`, ...scope.args]
@@ -15188,12 +15330,13 @@ async function cascadeUnblock(taskId, baseDir, now2) {
15188
15330
  WHERE blocked_by = ? AND status = 'blocked'`,
15189
15331
  args: [now2, taskId]
15190
15332
  });
15191
- if (baseDir && unblocked.rowsAffected > 0) {
15192
- const ubScope = sessionScopeFilter();
15193
- const unblockedRows = await client.execute({
15194
- sql: `SELECT task_file FROM tasks WHERE blocked_by IS NULL AND updated_at = ?${ubScope.sql}`,
15195
- args: [now2, ...ubScope.args]
15196
- });
15333
+ if (unblocked.rowsAffected === 0) return;
15334
+ const ubScope = sessionScopeFilter();
15335
+ const unblockedRows = await client.execute({
15336
+ sql: `SELECT id, title, assigned_to, priority, task_file FROM tasks WHERE blocked_by IS NULL AND updated_at = ?${ubScope.sql}`,
15337
+ args: [now2, ...ubScope.args]
15338
+ });
15339
+ if (baseDir) {
15197
15340
  for (const ur of unblockedRows.rows) {
15198
15341
  try {
15199
15342
  const ubFile = path32.join(baseDir, String(ur.task_file));
@@ -15205,6 +15348,19 @@ async function cascadeUnblock(taskId, baseDir, now2) {
15205
15348
  }
15206
15349
  }
15207
15350
  }
15351
+ if (unblockedRows.rows.length > 0 && !process.env.VITEST) {
15352
+ try {
15353
+ const { queueIntercom: queueIntercom2 } = await Promise.resolve().then(() => (init_intercom_queue(), intercom_queue_exports));
15354
+ const dispatched = /* @__PURE__ */ new Set();
15355
+ for (const ur of unblockedRows.rows) {
15356
+ const assignee = String(ur.assigned_to);
15357
+ if (dispatched.has(assignee)) continue;
15358
+ dispatched.add(assignee);
15359
+ queueIntercom2(`${assignee}`, `unblocked: "${String(ur.title)}" is now ready`);
15360
+ }
15361
+ } catch {
15362
+ }
15363
+ }
15208
15364
  }
15209
15365
  async function findNextTask(assignedTo) {
15210
15366
  const client = getClient();
@@ -15414,6 +15570,15 @@ var init_embedder = __esm({
15414
15570
  // src/lib/behaviors.ts
15415
15571
  import crypto10 from "crypto";
15416
15572
  async function storeBehavior(opts) {
15573
+ try {
15574
+ const { loadEmployeesSync: loadEmployeesSync2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
15575
+ const roster = loadEmployeesSync2();
15576
+ if (roster.length > 0 && !roster.some((e) => e.name === opts.agentId)) {
15577
+ throw new Error(`Agent "${opts.agentId}" not found in roster. Cannot store behavior for unregistered agent.`);
15578
+ }
15579
+ } catch (e) {
15580
+ if (e instanceof Error && e.message.includes("not found in roster")) throw e;
15581
+ }
15417
15582
  const client = getClient();
15418
15583
  const id = crypto10.randomUUID();
15419
15584
  const now2 = (/* @__PURE__ */ new Date()).toISOString();
@@ -15424,10 +15589,18 @@ async function storeBehavior(opts) {
15424
15589
  vector = new Float32Array(vec);
15425
15590
  } catch {
15426
15591
  }
15592
+ let createdByDevice = null;
15593
+ try {
15594
+ const { loadDeviceId: loadDeviceId2 } = await Promise.resolve().then(() => (init_license(), license_exports));
15595
+ createdByDevice = loadDeviceId2() ?? null;
15596
+ } catch {
15597
+ }
15598
+ const createdByAgent = process.env.AGENT_ID ?? null;
15599
+ const sourceSessionId = process.env.CLAUDE_SESSION_ID ?? process.env.SESSION_ID ?? null;
15427
15600
  await client.execute({
15428
- sql: `INSERT INTO behaviors (id, agent_id, project_name, domain, priority, content, active, created_at, updated_at, vector)
15429
- VALUES (?, ?, ?, ?, ?, ?, 1, ?, ?, ?)`,
15430
- args: [id, opts.agentId, opts.projectName ?? null, opts.domain ?? null, opts.priority ?? "p1", opts.content, now2, now2, vector ? vector.buffer : null]
15601
+ sql: `INSERT INTO behaviors (id, agent_id, project_name, domain, priority, content, active, created_at, updated_at, vector, created_by_agent, created_by_device, source_session_id)
15602
+ VALUES (?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?, ?, ?)`,
15603
+ args: [id, opts.agentId, opts.projectName ?? null, opts.domain ?? null, opts.priority ?? "p1", opts.content, now2, now2, vector ? vector.buffer : null, createdByAgent, createdByDevice, sourceSessionId]
15431
15604
  });
15432
15605
  return id;
15433
15606
  }
@@ -15859,6 +16032,12 @@ async function updateTask(input) {
15859
16032
  }
15860
16033
  }
15861
16034
  }
16035
+ if (input.status === "cancelled") {
16036
+ try {
16037
+ await cascadeUnblock(taskId, input.baseDir, now2);
16038
+ } catch {
16039
+ }
16040
+ }
15862
16041
  if ((input.status === "done" || input.status === "closed") && !isCoordinatorName(String(row.assigned_to)) && !process.env.VITEST) {
15863
16042
  Promise.resolve().then(() => (init_skill_learning(), skill_learning_exports)).then(
15864
16043
  ({ captureAndLearn: captureAndLearn2 }) => captureAndLearn2({
@@ -16390,11 +16569,12 @@ function getDispatchedBy(sessionKey) {
16390
16569
  }
16391
16570
  }
16392
16571
  function resolveExeSession() {
16572
+ if (process.env.EXE_SESSION_NAME) {
16573
+ const fromEnv = extractRootExe(process.env.EXE_SESSION_NAME) ?? process.env.EXE_SESSION_NAME;
16574
+ if (fromEnv) return fromEnv;
16575
+ }
16393
16576
  const mySession = getMySession();
16394
16577
  if (!mySession) {
16395
- if (process.env.EXE_SESSION_NAME) {
16396
- return extractRootExe(process.env.EXE_SESSION_NAME) ?? process.env.EXE_SESSION_NAME;
16397
- }
16398
16578
  return null;
16399
16579
  }
16400
16580
  const fromSessionName = extractRootExe(mySession);
@@ -16409,6 +16589,10 @@ function resolveExeSession() {
16409
16589
  `[tmux-routing] WARN: cache says "${fromCache}" but session name says "${fromSessionName}". Trusting session name.
16410
16590
  `
16411
16591
  );
16592
+ try {
16593
+ registerParentExe(key, fromSessionName);
16594
+ } catch {
16595
+ }
16412
16596
  candidate = fromSessionName;
16413
16597
  } else {
16414
16598
  candidate = fromCache;
@@ -17567,9 +17751,23 @@ __export(employee_templates_exports, {
17567
17751
  function getSessionPrompt(storedPrompt) {
17568
17752
  const markerIndex = storedPrompt.indexOf(PROCEDURES_MARKER);
17569
17753
  const withoutProcedures = markerIndex >= 0 ? storedPrompt.slice(0, markerIndex).trimEnd() : storedPrompt;
17754
+ let titlePrefix = "";
17755
+ const frontmatterMatch = withoutProcedures.match(/^---\r?\n([\s\S]*?)\r?\n---/);
17756
+ if (frontmatterMatch) {
17757
+ const titleMatch = frontmatterMatch[1].match(/^title:\s*(.+)$/m);
17758
+ const roleMatch = frontmatterMatch[1].match(/^role:\s*(.+)$/m);
17759
+ if (titleMatch) {
17760
+ const title = titleMatch[1].trim();
17761
+ const role = roleMatch ? roleMatch[1].trim() : "";
17762
+ if (title && role && title.toLowerCase() !== role.toLowerCase()) {
17763
+ titlePrefix = `## Your Identity
17764
+ You are **${title}** (specialist). `;
17765
+ }
17766
+ }
17767
+ }
17570
17768
  const rolePrompt = withoutProcedures.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/, "").replace(/<!--[\s\S]*?-->/g, "").trimStart();
17571
17769
  const globalBlock = getGlobalProceduresBlock();
17572
- return `${globalBlock}${rolePrompt}
17770
+ return `${globalBlock}${titlePrefix}${rolePrompt}
17573
17771
  ${BASE_OPERATING_PROCEDURES}`;
17574
17772
  }
17575
17773
  function buildCustomEmployeePrompt(name, role) {
@@ -17588,7 +17786,7 @@ function personalizePrompt(prompt, templateName, actualName) {
17588
17786
  return prompt.replace(new RegExp(`\\bYou are ${escaped}\\b`, "g"), `You are ${actualName}`);
17589
17787
  }
17590
17788
  function renderClientCOOTemplate(vars) {
17591
- const resolved = { ...vars, title: vars.title || "Chief Operating Officer" };
17789
+ const resolved = { ...vars, title: vars.title || "Chief of Staff" };
17592
17790
  for (const key of CLIENT_COO_PLACEHOLDERS) {
17593
17791
  const value = resolved[key];
17594
17792
  if (typeof value !== "string" || value.length === 0) {
@@ -20312,7 +20510,7 @@ async function runSetupWizard(opts = {}) {
20312
20510
  log("");
20313
20511
  const apiKey = await ask3(rl, "Cloud API key (starts with exe_sk_): ");
20314
20512
  if (apiKey && apiKey.startsWith("exe_sk_")) {
20315
- const cloudEndpoint = "https://askexe.com/cloud";
20513
+ const cloudEndpoint = "https://cloud.askexe.com";
20316
20514
  const cloudCfg = { apiKey, endpoint: cloudEndpoint };
20317
20515
  const earlyConfig = await loadConfig();
20318
20516
  earlyConfig.cloud = cloudCfg;
@@ -20412,7 +20610,7 @@ async function runSetupWizard(opts = {}) {
20412
20610
  log("");
20413
20611
  const existingKey = await ask3(rl, "Paste your Exe OS license key, or press Enter to start as a free user: ");
20414
20612
  if (existingKey && existingKey.startsWith("exe_sk_")) {
20415
- const cloudEndpoint = "https://askexe.com/cloud";
20613
+ const cloudEndpoint = "https://cloud.askexe.com";
20416
20614
  try {
20417
20615
  const { loadDeviceId: loadDeviceId2 } = await Promise.resolve().then(() => (init_license(), license_exports));
20418
20616
  const deviceId = loadDeviceId2();
@@ -20437,7 +20635,7 @@ async function runSetupWizard(opts = {}) {
20437
20635
  }
20438
20636
  } catch {
20439
20637
  log("Could not validate key \u2014 saving it and proceeding.");
20440
- cloudConfig = { apiKey: existingKey, endpoint: "https://askexe.com/cloud" };
20638
+ cloudConfig = { apiKey: existingKey, endpoint: "https://cloud.askexe.com" };
20441
20639
  const { saveLicense: saveLicense3, mirrorLicenseKey: mirrorLicenseKey3 } = await Promise.resolve().then(() => (init_license(), license_exports));
20442
20640
  saveLicense3(existingKey);
20443
20641
  mirrorLicenseKey3(existingKey);
@@ -20449,7 +20647,7 @@ async function runSetupWizard(opts = {}) {
20449
20647
  const deviceId = loadDeviceId2();
20450
20648
  let res;
20451
20649
  try {
20452
- res = await fetch("https://askexe.com/cloud/auth/auto-provision", {
20650
+ res = await fetch("https://cloud.askexe.com/auth/auto-provision", {
20453
20651
  method: "POST",
20454
20652
  headers: { "Content-Type": "application/json" },
20455
20653
  body: JSON.stringify({ deviceId }),
@@ -20457,7 +20655,7 @@ async function runSetupWizard(opts = {}) {
20457
20655
  });
20458
20656
  } catch {
20459
20657
  await new Promise((r) => setTimeout(r, 500));
20460
- res = await fetch("https://askexe.com/cloud/auth/auto-provision", {
20658
+ res = await fetch("https://cloud.askexe.com/auth/auto-provision", {
20461
20659
  method: "POST",
20462
20660
  headers: { "Content-Type": "application/json" },
20463
20661
  body: JSON.stringify({ deviceId }),
@@ -20467,7 +20665,7 @@ async function runSetupWizard(opts = {}) {
20467
20665
  if (res.ok) {
20468
20666
  const data = await res.json();
20469
20667
  if (data.apiKey) {
20470
- cloudConfig = { apiKey: data.apiKey, endpoint: "https://askexe.com/cloud" };
20668
+ cloudConfig = { apiKey: data.apiKey, endpoint: "https://cloud.askexe.com" };
20471
20669
  const { saveLicense: saveLicense3, mirrorLicenseKey: mirrorLicenseKey3 } = await Promise.resolve().then(() => (init_license(), license_exports));
20472
20670
  saveLicense3(data.apiKey);
20473
20671
  mirrorLicenseKey3(data.apiKey);
@@ -33127,7 +33325,7 @@ function useOrchestrator(enabled = true) {
33127
33325
  const [pendingReviews, setPendingReviews] = useState8(0);
33128
33326
  const [isLoading, setIsLoading] = useState8(true);
33129
33327
  const orchestratorRef = useRef5(null);
33130
- const exeSessionRef = useRef5("exe1");
33328
+ const exeSessionRef = useRef5("");
33131
33329
  const coordinatorNameRef = useRef5(DEFAULT_COORDINATOR_TEMPLATE_NAME);
33132
33330
  useEffect10(() => {
33133
33331
  if (!enabled) return;
@@ -33724,6 +33922,8 @@ var tui_data_exports = {};
33724
33922
  __export(tui_data_exports, {
33725
33923
  loadMemoryDashboard: () => loadMemoryDashboard,
33726
33924
  loadTaskList: () => loadTaskList,
33925
+ loadTeamBadgeCounts: () => loadTeamBadgeCounts,
33926
+ loadTeamDetailMetrics: () => loadTeamDetailMetrics,
33727
33927
  loadTeamMetrics: () => loadTeamMetrics,
33728
33928
  searchWikiMemoryRows: () => searchWikiMemoryRows
33729
33929
  });
@@ -33752,16 +33952,20 @@ async function loadMemoryDashboard(limit) {
33752
33952
  }))
33753
33953
  };
33754
33954
  }
33755
- async function loadTeamMetrics(employeeNames) {
33955
+ async function loadTeamBadgeCounts() {
33756
33956
  const client = getClient();
33757
33957
  const memoryCounts = /* @__PURE__ */ new Map();
33758
- const projectsByEmployee = /* @__PURE__ */ new Map();
33759
- const currentTaskByEmployee = /* @__PURE__ */ new Map();
33760
- const scope = sessionScopeFilter();
33761
33958
  const memResult = await client.execute("SELECT agent_id, COUNT(*) as cnt FROM memories GROUP BY agent_id");
33762
33959
  for (const row of memResult.rows) {
33763
33960
  memoryCounts.set(String(row.agent_id), Number(row.cnt));
33764
33961
  }
33962
+ return memoryCounts;
33963
+ }
33964
+ async function loadTeamDetailMetrics(employeeNames) {
33965
+ const client = getClient();
33966
+ const projectsByEmployee = /* @__PURE__ */ new Map();
33967
+ const currentTaskByEmployee = /* @__PURE__ */ new Map();
33968
+ const scope = sessionScopeFilter();
33765
33969
  for (const employeeName of employeeNames) {
33766
33970
  const [projectResult, taskResult] = await Promise.all([
33767
33971
  client.execute({
@@ -33794,6 +33998,13 @@ async function loadTeamMetrics(employeeNames) {
33794
33998
  currentTaskByEmployee.set(employeeName, String(taskResult.rows[0].title));
33795
33999
  }
33796
34000
  }
34001
+ return { projectsByEmployee, currentTaskByEmployee };
34002
+ }
34003
+ async function loadTeamMetrics(employeeNames) {
34004
+ const [memoryCounts, { projectsByEmployee, currentTaskByEmployee }] = await Promise.all([
34005
+ loadTeamBadgeCounts(),
34006
+ loadTeamDetailMetrics(employeeNames)
34007
+ ]);
33797
34008
  return { memoryCounts, projectsByEmployee, currentTaskByEmployee };
33798
34009
  }
33799
34010
  async function loadTaskList() {
@@ -35049,6 +35260,8 @@ function TeamView({ onBack, onViewSessions }) {
35049
35260
  const [members, setMembers] = useState12([]);
35050
35261
  const [externals, setExternals] = useState12([]);
35051
35262
  const [loading, setLoading] = useState12(!demo);
35263
+ const [badgeInFlight, setBadgeInFlight] = useState12(!demo);
35264
+ const [detailInFlight, setDetailInFlight] = useState12(!demo);
35052
35265
  const [dbError, setDbError] = useState12(null);
35053
35266
  const [selectedIdx, setSelectedIdx] = useState12(0);
35054
35267
  const [showDetail, setShowDetail] = useState12(false);
@@ -35061,6 +35274,8 @@ function TeamView({ onBack, onViewSessions }) {
35061
35274
  setMembers(DEMO_EMPLOYEES.map((e) => ({ ...e })));
35062
35275
  setExternals(DEMO_EXTERNAL_AGENTS);
35063
35276
  setLoading(false);
35277
+ setBadgeInFlight(false);
35278
+ setDetailInFlight(false);
35064
35279
  return;
35065
35280
  }
35066
35281
  loadTeam();
@@ -35099,33 +35314,48 @@ function TeamView({ onBack, onViewSessions }) {
35099
35314
  let projectsByEmployee = /* @__PURE__ */ new Map();
35100
35315
  let currentTaskByEmployee = /* @__PURE__ */ new Map();
35101
35316
  try {
35102
- const { loadTeamMetrics: loadTeamMetrics2 } = await Promise.resolve().then(() => (init_tui_data(), tui_data_exports));
35103
- const teamMetrics = await loadTeamMetrics2(roster.map((emp) => emp.name));
35104
- memoryCounts = teamMetrics.memoryCounts;
35105
- projectsByEmployee = new Map(
35106
- Array.from(teamMetrics.projectsByEmployee.entries()).map(([name, projects]) => [
35107
- name,
35108
- projects.filter((project) => !DEPRECATED_PROJECTS.has(project.name))
35109
- ])
35110
- );
35317
+ const { loadTeamBadgeCounts: loadTeamBadgeCounts2, loadTeamDetailMetrics: loadTeamDetailMetrics2 } = await Promise.resolve().then(() => (init_tui_data(), tui_data_exports));
35318
+ setBadgeInFlight(true);
35319
+ const badgeCountsPromise = loadTeamBadgeCounts2();
35320
+ const detailsPromise = loadTeamDetailMetrics2(roster.map((emp) => emp.name));
35321
+ memoryCounts = await badgeCountsPromise;
35322
+ setBadgeInFlight(false);
35323
+ const initialMembers = roster.map((emp) => {
35324
+ const agentSt = getAgentStatus(emp.name);
35325
+ return {
35326
+ name: emp.name,
35327
+ role: emp.role,
35328
+ status: agentSt.label,
35329
+ activity: agentSt.label === "active" ? "Processing..." : "",
35330
+ memoryCount: memoryCounts.get(emp.name) ?? 0,
35331
+ projects: void 0,
35332
+ currentTask: void 0,
35333
+ sessionName: agentSt.session
35334
+ };
35335
+ });
35336
+ setMembers(initialMembers);
35337
+ setDetailInFlight(true);
35338
+ const teamMetrics = await detailsPromise;
35339
+ projectsByEmployee = teamMetrics.projectsByEmployee;
35111
35340
  currentTaskByEmployee = teamMetrics.currentTaskByEmployee;
35341
+ setDetailInFlight(false);
35342
+ const finalMembers = roster.map((emp) => {
35343
+ const agentSt = getAgentStatus(emp.name);
35344
+ return {
35345
+ name: emp.name,
35346
+ role: emp.role,
35347
+ status: agentSt.label,
35348
+ activity: agentSt.label === "active" ? "Processing..." : "",
35349
+ memoryCount: memoryCounts.get(emp.name) ?? 0,
35350
+ projects: projectsByEmployee.get(emp.name),
35351
+ currentTask: currentTaskByEmployee.get(emp.name),
35352
+ sessionName: agentSt.session
35353
+ };
35354
+ });
35355
+ setMembers(finalMembers);
35356
+ setDbError(null);
35112
35357
  } catch {
35113
35358
  }
35114
- const teamData = roster.map((emp) => {
35115
- const agentSt = getAgentStatus(emp.name);
35116
- return {
35117
- name: emp.name,
35118
- role: emp.role,
35119
- status: agentSt.label,
35120
- activity: agentSt.label === "active" ? "Processing..." : "",
35121
- memoryCount: memoryCounts.get(emp.name) ?? 0,
35122
- projects: projectsByEmployee.get(emp.name),
35123
- currentTask: currentTaskByEmployee.get(emp.name),
35124
- sessionName: agentSt.session
35125
- };
35126
- });
35127
- setMembers(teamData);
35128
- setDbError(null);
35129
35359
  try {
35130
35360
  const { existsSync: existsSync44, readFileSync: readFileSync39 } = await import("fs");
35131
35361
  const { join: join2 } = await import("path");
@@ -35147,6 +35377,8 @@ function TeamView({ onBack, onViewSessions }) {
35147
35377
  setDbError(err instanceof Error ? err.message : "Unknown error");
35148
35378
  } finally {
35149
35379
  setLoading(false);
35380
+ setBadgeInFlight(false);
35381
+ setDetailInFlight(false);
35150
35382
  }
35151
35383
  });
35152
35384
  }
@@ -35201,6 +35433,8 @@ function TeamView({ onBack, onViewSessions }) {
35201
35433
  orch.pendingReviews,
35202
35434
  " review(s) pending coordinator attention"
35203
35435
  ] }),
35436
+ badgeInFlight && /* @__PURE__ */ jsx12(Text, { color: "#F5D76E", children: " Loading memory counts..." }),
35437
+ detailInFlight && /* @__PURE__ */ jsx12(Text, { color: "#6B4C9A", children: " Loading employee details..." }),
35204
35438
  /* @__PURE__ */ jsx12(Text, { children: " " }),
35205
35439
  /* @__PURE__ */ jsx12(Text, { bold: true, children: "INTERNAL" }),
35206
35440
  /* @__PURE__ */ jsx12(Text, { children: " " }),
@@ -35289,7 +35523,6 @@ function TeamView({ onBack, onViewSessions }) {
35289
35523
  }) })
35290
35524
  ] });
35291
35525
  }
35292
- var DEPRECATED_PROJECTS;
35293
35526
  var init_Team = __esm({
35294
35527
  async "src/tui/views/Team.tsx"() {
35295
35528
  "use strict";
@@ -35299,7 +35532,6 @@ var init_Team = __esm({
35299
35532
  init_demo_data();
35300
35533
  init_useOrchestrator();
35301
35534
  init_agent_status();
35302
- DEPRECATED_PROJECTS = /* @__PURE__ */ new Set(["exe-ai-employees"]);
35303
35535
  }
35304
35536
  });
35305
35537