@askexenow/exe-os 0.8.53 → 0.8.55

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 (67) hide show
  1. package/dist/bin/backfill-conversations.js +113 -10
  2. package/dist/bin/backfill-responses.js +113 -10
  3. package/dist/bin/backfill-vectors.js +147 -13
  4. package/dist/bin/cleanup-stale-review-tasks.js +113 -10
  5. package/dist/bin/cli.js +337 -211
  6. package/dist/bin/exe-agent.js +99 -4
  7. package/dist/bin/exe-assign.js +113 -10
  8. package/dist/bin/exe-boot.js +276 -85
  9. package/dist/bin/exe-call.js +107 -5
  10. package/dist/bin/exe-doctor.js +183 -13
  11. package/dist/bin/exe-export-behaviors.js +113 -10
  12. package/dist/bin/exe-forget.js +113 -10
  13. package/dist/bin/exe-gateway.js +131 -12
  14. package/dist/bin/exe-heartbeat.js +121 -11
  15. package/dist/bin/exe-kill.js +113 -10
  16. package/dist/bin/exe-launch-agent.js +113 -10
  17. package/dist/bin/exe-link.js +10 -2
  18. package/dist/bin/exe-new-employee.js +95 -0
  19. package/dist/bin/exe-pending-messages.js +113 -10
  20. package/dist/bin/exe-pending-notifications.js +113 -10
  21. package/dist/bin/exe-pending-reviews.js +122 -11
  22. package/dist/bin/exe-rename.js +95 -0
  23. package/dist/bin/exe-review.js +113 -10
  24. package/dist/bin/exe-search.js +113 -10
  25. package/dist/bin/exe-session-cleanup.js +131 -12
  26. package/dist/bin/exe-status.js +113 -10
  27. package/dist/bin/exe-team.js +113 -10
  28. package/dist/bin/git-sweep.js +131 -12
  29. package/dist/bin/graph-backfill.js +113 -10
  30. package/dist/bin/graph-export.js +113 -10
  31. package/dist/bin/scan-tasks.js +131 -12
  32. package/dist/bin/setup.js +107 -5
  33. package/dist/bin/shard-migrate.js +113 -10
  34. package/dist/bin/wiki-sync.js +113 -10
  35. package/dist/gateway/index.js +131 -12
  36. package/dist/hooks/bug-report-worker.js +131 -12
  37. package/dist/hooks/commit-complete.js +131 -12
  38. package/dist/hooks/error-recall.js +113 -10
  39. package/dist/hooks/ingest-worker.js +131 -12
  40. package/dist/hooks/instructions-loaded.js +113 -10
  41. package/dist/hooks/notification.js +113 -10
  42. package/dist/hooks/post-compact.js +113 -10
  43. package/dist/hooks/pre-compact.js +131 -12
  44. package/dist/hooks/pre-tool-use.js +113 -10
  45. package/dist/hooks/prompt-ingest-worker.js +113 -10
  46. package/dist/hooks/prompt-submit.js +140 -14
  47. package/dist/hooks/response-ingest-worker.js +113 -10
  48. package/dist/hooks/session-end.js +113 -10
  49. package/dist/hooks/session-start.js +113 -10
  50. package/dist/hooks/stop.js +113 -10
  51. package/dist/hooks/subagent-stop.js +113 -10
  52. package/dist/hooks/summary-worker.js +231 -114
  53. package/dist/index.js +131 -12
  54. package/dist/lib/cloud-sync.js +10 -2
  55. package/dist/lib/employee-templates.js +99 -4
  56. package/dist/lib/exe-daemon.js +4859 -4706
  57. package/dist/lib/hybrid-search.js +113 -10
  58. package/dist/lib/schedules.js +113 -10
  59. package/dist/lib/store.js +113 -10
  60. package/dist/lib/tasks.js +18 -2
  61. package/dist/lib/tmux-routing.js +18 -2
  62. package/dist/mcp/server.js +214 -28
  63. package/dist/mcp/tools/create-task.js +18 -2
  64. package/dist/mcp/tools/list-tasks.js +18 -2
  65. package/dist/runtime/index.js +131 -12
  66. package/dist/tui/App.js +337 -211
  67. package/package.json +2 -2
package/dist/bin/cli.js CHANGED
@@ -2376,6 +2376,103 @@ var init_shard_manager = __esm({
2376
2376
  }
2377
2377
  });
2378
2378
 
2379
+ // src/lib/platform-procedures.ts
2380
+ var PLATFORM_PROCEDURES, PLATFORM_PROCEDURE_TITLES;
2381
+ var init_platform_procedures = __esm({
2382
+ "src/lib/platform-procedures.ts"() {
2383
+ "use strict";
2384
+ PLATFORM_PROCEDURES = [
2385
+ // --- Foundation: what is exe-os ---
2386
+ {
2387
+ title: "What is exe-os \u2014 the operating model every agent must understand",
2388
+ domain: "architecture",
2389
+ priority: "p0",
2390
+ content: "Exe OS is an AI employee operating system. A founder runs 5-10 AI agents as a real org: COO (exe), CTO (yoshi), CMO (mari), engineers (tom), content (sasha). Each agent has identity, expertise, and experience layers \u2014 persistent memory that makes them better over time. All data is local-first, E2EE, owned by the user. The MCP server is the ONLY data interface \u2014 never access the DB directly."
2391
+ },
2392
+ {
2393
+ title: "Mode 1 \u2014 how exe-os runs inside Claude Code",
2394
+ domain: "architecture",
2395
+ priority: "p0",
2396
+ content: "Mode 1: exe-os runs AS hooks + MCP + skills inside Claude Code. The founder opens CC, runs /exe to boot the COO. exe manages employees in tmux sessions. Each exeN is a separate CC window/project. Employees (yoshi, tom, mari) run in their own tmux panes via create_task auto-spawn. The founder talks to exe; exe orchestrates the team. CC is the shell, exe-os is the brain."
2397
+ },
2398
+ {
2399
+ title: "Sessions explained \u2014 what exeN means and how projects work",
2400
+ domain: "architecture",
2401
+ priority: "p0",
2402
+ content: "Each exeN (exe1, exe2, exe3) is an isolated project session. exe1 might be exe-os development, exe2 might be exe-wiki. Each session spawns its own employees: exe1\u2192yoshi-exe1\u2192tom-exe1. Sessions share the same memory DB but tasks are scoped to the session that created them. A founder can run multiple projects simultaneously. Sessions never interfere with each other."
2403
+ },
2404
+ // --- Hierarchy and dispatch ---
2405
+ {
2406
+ title: "Chain of command \u2014 who talks to whom",
2407
+ domain: "workflow",
2408
+ priority: "p0",
2409
+ content: "Founder \u2192 exe (COO) \u2192 yoshi (CTO) / mari (CMO). Yoshi \u2192 tom (engineer). Mari \u2192 sasha (content). Never skip levels: exe never assigns directly to tom. Tom never reports directly to exe. 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."
2410
+ },
2411
+ {
2412
+ title: "Single dispatch path \u2014 create_task only",
2413
+ domain: "workflow",
2414
+ priority: "p0",
2415
+ content: "create_task is the ONLY way to dispatch work to another agent. No direct ensureEmployee calls, no manual tmux spawns, no send_message for actionable work. create_task \u2192 system auto-spawns \u2192 session correctly named. ONE PATH. No backdoors. No exceptions."
2416
+ },
2417
+ // --- Session isolation ---
2418
+ {
2419
+ title: "Session scoping \u2014 stay in your exe boundary",
2420
+ domain: "security",
2421
+ priority: "p0",
2422
+ content: "Session scoping is mandatory. Managers dispatch to workers within their own exe session ONLY. exe1\u2192yoshi-exe1\u2192tom-exe1. exe2\u2192yoshi-exe2\u2192tom2-exe2. Cross-session dispatch is blocked by the system. Verify session names before dispatch. Tasks are scoped to the creating exe session."
2423
+ },
2424
+ {
2425
+ title: "Session isolation \u2014 never touch another session's work",
2426
+ domain: "workflow",
2427
+ priority: "p0",
2428
+ content: `Sessions are isolated. exeN owns ONLY tasks it dispatched. (1) Never close/update/cancel tasks from another exe session. (2) Never review work from a different session \u2014 report "belongs to exeN" and skip. (3) Ignore other sessions' items in list_tasks results. (4) Employees inherit session: yoshi-exe1 works ONLY on exe1 tasks. Cross-session work is a system violation.`
2429
+ },
2430
+ // --- Engineering: session scoping in code ---
2431
+ {
2432
+ title: "Three-dimensional scoping \u2014 session, project, role \u2014 enforced in every query",
2433
+ domain: "architecture",
2434
+ priority: "p0",
2435
+ content: "Every DB query, notification, review count, and task operation MUST be scoped on 3 dimensions: (1) Session \u2014 filter by session_scope matching current exeN. (2) Project \u2014 filter by project_name. (3) Role \u2014 agents only see data at their hierarchy level. When writing ANY function that touches tasks, reviews, messages, or notifications: always accept a sessionScope parameter and pass it to the SQL WHERE clause. Unscoped queries are bugs. Test by running 2+ exe sessions simultaneously."
2436
+ },
2437
+ // --- Hard constraints ---
2438
+ {
2439
+ title: "What you CANNOT do in exe-os \u2014 hard constraints",
2440
+ domain: "security",
2441
+ priority: "p0",
2442
+ 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 exe reviews and pushes. (6) Skip update_task(done) \u2014 it's the ONLY way your work gets reviewed. (7) Run git init."
2443
+ },
2444
+ // --- Operations ---
2445
+ {
2446
+ title: "Managers must supervise deployed workers",
2447
+ domain: "workflow",
2448
+ priority: "p0",
2449
+ content: `Every manager (COO/CTO/CMO) who dispatches work to a worker MUST actively monitor them. Check tmux capture-pane every 10 minutes. Verify they're working, not stuck. If idle at prompt with in_progress task \u2192 send intercom. If stuck \u2192 unblock or escalate. "Standing by" without checking is negligence.`
2450
+ },
2451
+ {
2452
+ title: "COO boot health check \u2014 memory, cloud sync, daemon on every launch",
2453
+ domain: "workflow",
2454
+ priority: "p0",
2455
+ content: "On every /exe boot, COO MUST check system health BEFORE other work: (1) daemon \u2014 is exed PID alive, (2) cloud sync \u2014 grep workers.log for recent cloud-sync errors, (3) memory count \u2014 total in DB, (4) sync delta \u2014 local vs cloud storage_bytes. Report as 4-line status table. If ANY check fails, surface to founder immediately. Do not proceed to tasks until health confirmed."
2456
+ },
2457
+ {
2458
+ title: "exe-build-adv mandatory for 3+ files",
2459
+ domain: "workflow",
2460
+ priority: "p0",
2461
+ content: "exe-build-adv is MANDATORY for ALL work touching 3+ files. Run /exe-build-adv --auto BEFORE implementation. Pipeline: Spec \u2192 AC \u2192 Tests \u2192 Evaluate \u2192 Fix. No multi-file feature ships without pipeline artifacts. No exceptions \u2014 managers reject work without them."
2462
+ },
2463
+ {
2464
+ title: "Desktop and TUI are the same product",
2465
+ domain: "architecture",
2466
+ priority: "p0",
2467
+ content: "Desktop and TUI are the SAME product in different renderers. Same data contracts, same interactions, same acceptance criteria. Desktop tab specs in ARCHITECTURE.md ARE the TUI specs. When building TUI, cross-reference Desktop spec. Different tab names, identical behavior. Never treat them as separate products."
2468
+ }
2469
+ ];
2470
+ PLATFORM_PROCEDURE_TITLES = new Set(
2471
+ PLATFORM_PROCEDURES.map((p) => p.title)
2472
+ );
2473
+ }
2474
+ });
2475
+
2379
2476
  // src/lib/global-procedures.ts
2380
2477
  var global_procedures_exports = {};
2381
2478
  __export(global_procedures_exports, {
@@ -2391,22 +2488,25 @@ async function loadGlobalProcedures() {
2391
2488
  sql: "SELECT * FROM global_procedures WHERE active = 1 ORDER BY priority ASC, created_at ASC",
2392
2489
  args: []
2393
2490
  });
2394
- const procedures = result.rows;
2395
- if (procedures.length > 0) {
2396
- _cache = procedures.map((p) => `### ${p.title}
2491
+ const allRows = result.rows;
2492
+ const customerOnly = allRows.filter((p) => !PLATFORM_PROCEDURE_TITLES.has(p.title));
2493
+ if (customerOnly.length > 0) {
2494
+ _customerCache = customerOnly.map((p) => `### ${p.title}
2397
2495
  ${p.content}`).join("\n\n");
2398
2496
  } else {
2399
- _cache = "";
2497
+ _customerCache = "";
2400
2498
  }
2401
2499
  _cacheLoaded = true;
2402
- return procedures;
2500
+ return customerOnly;
2403
2501
  }
2404
2502
  function getGlobalProceduresBlock() {
2405
- if (!_cacheLoaded) return "";
2406
- if (!_cache) return "";
2503
+ const sections = [];
2504
+ if (_platformCache) sections.push(_platformCache);
2505
+ if (_cacheLoaded && _customerCache) sections.push(_customerCache);
2506
+ if (sections.length === 0) return "";
2407
2507
  return `## Organization-Wide Procedures (MANDATORY \u2014 supersedes all other rules)
2408
2508
 
2409
- ${_cache}
2509
+ ${sections.join("\n\n")}
2410
2510
  `;
2411
2511
  }
2412
2512
  async function storeGlobalProcedure(input) {
@@ -2431,13 +2531,16 @@ async function deactivateGlobalProcedure(id) {
2431
2531
  await loadGlobalProcedures();
2432
2532
  return result.rowsAffected > 0;
2433
2533
  }
2434
- var _cache, _cacheLoaded;
2534
+ var _customerCache, _cacheLoaded, _platformCache;
2435
2535
  var init_global_procedures = __esm({
2436
2536
  "src/lib/global-procedures.ts"() {
2437
2537
  "use strict";
2438
2538
  init_database();
2439
- _cache = "";
2539
+ init_platform_procedures();
2540
+ _customerCache = "";
2440
2541
  _cacheLoaded = false;
2542
+ _platformCache = PLATFORM_PROCEDURES.map((p) => `### ${p.title}
2543
+ ${p.content}`).join("\n\n");
2441
2544
  }
2442
2545
  });
2443
2546
 
@@ -12460,8 +12563,8 @@ ${info.componentStack ?? ""}
12460
12563
  }
12461
12564
  render() {
12462
12565
  if (this.state.error) {
12463
- return /* @__PURE__ */ jsxs(Box_default, { flexDirection: "column", paddingX: 1, paddingY: 1, children: [
12464
- /* @__PURE__ */ jsxs(Box_default, { children: [
12566
+ return /* @__PURE__ */ jsxs(Box_default, { testID: "error-boundary", flexDirection: "column", paddingX: 1, paddingY: 1, children: [
12567
+ /* @__PURE__ */ jsxs(Box_default, { testID: "error-message", children: [
12465
12568
  /* @__PURE__ */ jsx2(Text, { backgroundColor: "red", color: "white", children: " ERROR " }),
12466
12569
  /* @__PURE__ */ jsxs(Text, { children: [
12467
12570
  " ",
@@ -12513,7 +12616,7 @@ function AlternateScreen({ children }) {
12513
12616
  process.stdout.write(SHOW_CURSOR + EXIT_ALT_SCREEN);
12514
12617
  };
12515
12618
  }, []);
12516
- return /* @__PURE__ */ jsx3(Box_default, { flexDirection: "column", height: rows, width: "100%", children });
12619
+ return /* @__PURE__ */ jsx3(Box_default, { testID: "alternate-screen", flexDirection: "column", height: rows, width: "100%", children });
12517
12620
  }
12518
12621
  var ENTER_ALT_SCREEN, EXIT_ALT_SCREEN, CLEAR_AND_HOME, HIDE_CURSOR, SHOW_CURSOR;
12519
12622
  var init_AlternateScreen = __esm({
@@ -12579,6 +12682,7 @@ function Sidebar({
12579
12682
  return /* @__PURE__ */ jsxs2(
12580
12683
  Box_default,
12581
12684
  {
12685
+ testID: "sidebar-nav",
12582
12686
  flexDirection: "column",
12583
12687
  width: 26,
12584
12688
  borderStyle: "single",
@@ -12592,19 +12696,19 @@ function Sidebar({
12592
12696
  SECTIONS.map(({ key, label, shortcut }) => {
12593
12697
  const isActive = active === key;
12594
12698
  if (isActive && focused) {
12595
- return /* @__PURE__ */ jsxs2(Text, { backgroundColor: "#6B4C9A", color: "#F5D76E", bold: true, children: [
12699
+ return /* @__PURE__ */ jsx4(Box_default, { testID: `sidebar-item-${key}`, children: /* @__PURE__ */ jsxs2(Text, { backgroundColor: "#6B4C9A", color: "#F5D76E", bold: true, children: [
12596
12700
  "\u25B8 ",
12597
12701
  shortcut,
12598
12702
  " ",
12599
12703
  label
12600
- ] }, key);
12704
+ ] }) }, key);
12601
12705
  }
12602
- return /* @__PURE__ */ jsxs2(Text, { color: isActive ? "#F5D76E" : "#6B4C9A", children: [
12706
+ return /* @__PURE__ */ jsx4(Box_default, { testID: `sidebar-item-${key}`, children: /* @__PURE__ */ jsxs2(Text, { color: isActive ? "#F5D76E" : "#6B4C9A", children: [
12603
12707
  isActive ? "\u25B8 " : " ",
12604
12708
  shortcut,
12605
12709
  " ",
12606
12710
  label
12607
- ] }, key);
12711
+ ] }) }, key);
12608
12712
  })
12609
12713
  ] }),
12610
12714
  /* @__PURE__ */ jsx4(Text, { color: "#6B4C9A", children: " \u2715 Quit (q)" })
@@ -13049,9 +13153,9 @@ function Footer() {
13049
13153
  }
13050
13154
  });
13051
13155
  }
13052
- return /* @__PURE__ */ jsxs3(Box_default, { flexDirection: "column", children: [
13156
+ return /* @__PURE__ */ jsxs3(Box_default, { testID: "footer", flexDirection: "column", children: [
13053
13157
  /* @__PURE__ */ jsx5(Text, { color: "#3D3660", children: "\u2500".repeat(process.stdout.columns || 120) }),
13054
- /* @__PURE__ */ jsxs3(Box_default, { paddingX: 1, justifyContent: "space-between", children: [
13158
+ /* @__PURE__ */ jsxs3(Box_default, { testID: "footer-stats", paddingX: 1, justifyContent: "space-between", children: [
13055
13159
  /* @__PURE__ */ jsxs3(Box_default, { gap: 1, children: [
13056
13160
  currentSession ? /* @__PURE__ */ jsxs3(Fragment, { children: [
13057
13161
  /* @__PURE__ */ jsx5(Text, { color: "#22C55E", children: currentSession }),
@@ -13077,7 +13181,7 @@ function Footer() {
13077
13181
  daemon
13078
13182
  ] })
13079
13183
  ] }),
13080
- /* @__PURE__ */ jsxs3(Box_default, { gap: 1, children: [
13184
+ /* @__PURE__ */ jsxs3(Box_default, { testID: "footer-hints", gap: 1, children: [
13081
13185
  plan && plan !== "free" && /* @__PURE__ */ jsxs3(Fragment, { children: [
13082
13186
  /* @__PURE__ */ jsx5(Text, { color: "#22C55E", children: plan.toUpperCase() }),
13083
13187
  /* @__PURE__ */ jsx5(Text, { color: "#3D3660", children: "\u2502" })
@@ -13108,7 +13212,7 @@ import React16 from "react";
13108
13212
  import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
13109
13213
  function StatusDot({ status, showLabel = true }) {
13110
13214
  const { char, dotColor, label, labelColor } = STATUS_CONFIG[status];
13111
- return /* @__PURE__ */ jsxs4(Box_default, { gap: 0, children: [
13215
+ return /* @__PURE__ */ jsxs4(Box_default, { testID: "status-dot", gap: 0, children: [
13112
13216
  /* @__PURE__ */ jsx6(Text, { color: dotColor, children: char }),
13113
13217
  showLabel && /* @__PURE__ */ jsxs4(Text, { color: labelColor, children: [
13114
13218
  " ",
@@ -16201,8 +16305,8 @@ function CommandCenterView({
16201
16305
  setChatInput("");
16202
16306
  }, [sendMessage, isThinking]);
16203
16307
  if (chatMode) {
16204
- return /* @__PURE__ */ jsxs5(Box_default, { flexDirection: "column", flexGrow: 1, paddingX: 1, children: [
16205
- /* @__PURE__ */ jsxs5(Box_default, { justifyContent: "space-between", alignItems: "center", children: [
16308
+ return /* @__PURE__ */ jsxs5(Box_default, { testID: "command-center-view", flexDirection: "column", flexGrow: 1, paddingX: 1, children: [
16309
+ /* @__PURE__ */ jsxs5(Box_default, { testID: "command-center-header", justifyContent: "space-between", alignItems: "center", children: [
16206
16310
  /* @__PURE__ */ jsx7(Box_default, { borderStyle: "single", borderColor: "#3D3660", paddingX: 1, children: /* @__PURE__ */ jsx7(Text, { bold: true, children: "Chat" }) }),
16207
16311
  /* @__PURE__ */ jsx7(Text, { color: "#6B4C9A", children: "Ctrl+L clear | Escape to return" })
16208
16312
  ] }),
@@ -16262,8 +16366,8 @@ function CommandCenterView({
16262
16366
  ] })
16263
16367
  ] });
16264
16368
  }
16265
- return /* @__PURE__ */ jsxs5(Box_default, { flexDirection: "column", flexGrow: 1, paddingX: 1, children: [
16266
- /* @__PURE__ */ jsxs5(Box_default, { justifyContent: "space-between", alignItems: "center", children: [
16369
+ return /* @__PURE__ */ jsxs5(Box_default, { testID: "command-center-view", flexDirection: "column", flexGrow: 1, paddingX: 1, children: [
16370
+ /* @__PURE__ */ jsxs5(Box_default, { testID: "command-center-header", justifyContent: "space-between", alignItems: "center", children: [
16267
16371
  /* @__PURE__ */ jsx7(Box_default, { borderStyle: "single", borderColor: "#3D3660", paddingX: 1, children: /* @__PURE__ */ jsx7(Text, { bold: true, children: "Command Center" }) }),
16268
16372
  /* @__PURE__ */ jsx7(Text, { color: selectableProjects.some((p) => p.status === "active") ? "green" : "gray", children: selectableProjects.some((p) => p.status === "active") ? "\u25CF Active" : "\u25CF Idle" })
16269
16373
  ] }),
@@ -16332,7 +16436,7 @@ function CommandCenterView({
16332
16436
  );
16333
16437
  });
16334
16438
  sections.push(
16335
- /* @__PURE__ */ jsx7(Box_default, { flexDirection: "row", flexWrap: "wrap", gap: 1, children: cards }, `cards-${sectionKey++}`)
16439
+ /* @__PURE__ */ jsx7(Box_default, { testID: "command-center-cards", flexDirection: "row", flexWrap: "wrap", gap: 1, children: cards }, `cards-${sectionKey++}`)
16336
16440
  );
16337
16441
  currentProjects = [];
16338
16442
  };
@@ -16466,7 +16570,7 @@ function TmuxPane({ sessionName, employeeName, employeeRole, projectName, onDeta
16466
16570
  });
16467
16571
  const modeLabel = demo ? "DEMO" : alive ? "INTERACTIVE" : "DISCONNECTED";
16468
16572
  const modeColor = demo ? "#6B4C9A" : alive ? "#22C55E" : "#6B7280";
16469
- return /* @__PURE__ */ jsxs6(Box_default, { flexDirection: "column", flexGrow: 1, paddingX: 1, children: [
16573
+ return /* @__PURE__ */ jsxs6(Box_default, { testID: "tmux-pane", flexDirection: "column", flexGrow: 1, paddingX: 1, children: [
16470
16574
  /* @__PURE__ */ jsxs6(Box_default, { justifyContent: "space-between", children: [
16471
16575
  /* @__PURE__ */ jsxs6(Text, { bold: true, children: [
16472
16576
  employeeName,
@@ -16492,6 +16596,7 @@ function TmuxPane({ sessionName, employeeName, employeeRole, projectName, onDeta
16492
16596
  /* @__PURE__ */ jsx8(
16493
16597
  Box_default,
16494
16598
  {
16599
+ testID: "tmux-pane-output",
16495
16600
  flexDirection: "column",
16496
16601
  flexGrow: 1,
16497
16602
  paddingX: 1,
@@ -17448,16 +17553,32 @@ var init_tasks_crud = __esm({
17448
17553
  // src/lib/tasks-review.ts
17449
17554
  import path27 from "path";
17450
17555
  import { existsSync as existsSync19, readdirSync as readdirSync4, unlinkSync as unlinkSync6 } from "fs";
17451
- async function countPendingReviews() {
17556
+ async function countPendingReviews(sessionScope) {
17452
17557
  const client = getClient();
17558
+ if (sessionScope) {
17559
+ const result2 = await client.execute({
17560
+ sql: "SELECT COUNT(*) as cnt FROM tasks WHERE status = 'needs_review' AND (session_scope = ? OR session_scope IS NULL)",
17561
+ args: [sessionScope]
17562
+ });
17563
+ return Number(result2.rows[0]?.cnt) || 0;
17564
+ }
17453
17565
  const result = await client.execute({
17454
17566
  sql: "SELECT COUNT(*) as cnt FROM tasks WHERE status = 'needs_review'",
17455
17567
  args: []
17456
17568
  });
17457
17569
  return Number(result.rows[0]?.cnt) || 0;
17458
17570
  }
17459
- async function countNewPendingReviewsSince(sinceIso) {
17571
+ async function countNewPendingReviewsSince(sinceIso, sessionScope) {
17460
17572
  const client = getClient();
17573
+ if (sessionScope) {
17574
+ const result2 = await client.execute({
17575
+ sql: `SELECT COUNT(*) as cnt FROM tasks
17576
+ WHERE status = 'needs_review' AND updated_at > ?
17577
+ AND (session_scope = ? OR session_scope IS NULL)`,
17578
+ args: [sinceIso, sessionScope]
17579
+ });
17580
+ return Number(result2.rows[0]?.cnt) || 0;
17581
+ }
17461
17582
  const result = await client.execute({
17462
17583
  sql: `SELECT COUNT(*) as cnt FROM tasks
17463
17584
  WHERE status = 'needs_review' AND updated_at > ?`,
@@ -19988,7 +20109,7 @@ function SessionsView({
19988
20109
  const inCarousel = carouselEmployees.length > 0;
19989
20110
  const prevName = inCarousel && carouselIdx > 0 ? carouselEmployees[carouselIdx - 1].name : null;
19990
20111
  const nextName = inCarousel && carouselIdx < carouselEmployees.length - 1 ? carouselEmployees[carouselIdx + 1].name : null;
19991
- return /* @__PURE__ */ jsxs7(Box_default, { flexDirection: "column", flexGrow: 1, children: [
20112
+ return /* @__PURE__ */ jsxs7(Box_default, { testID: "sessions-view", flexDirection: "column", flexGrow: 1, children: [
19992
20113
  inCarousel && /* @__PURE__ */ jsxs7(Box_default, { paddingX: 1, justifyContent: "space-between", children: [
19993
20114
  /* @__PURE__ */ jsxs7(Text, { children: [
19994
20115
  /* @__PURE__ */ jsx9(Text, { color: "#6B4C9A", children: prevName ? `\u25C4 ${prevName}` : "\u25C4 back" }),
@@ -20030,7 +20151,7 @@ function SessionsView({
20030
20151
  ] });
20031
20152
  }
20032
20153
  const flatItems = buildFlatList();
20033
- return /* @__PURE__ */ jsxs7(Box_default, { flexDirection: "column", flexGrow: 1, paddingX: 1, children: [
20154
+ return /* @__PURE__ */ jsxs7(Box_default, { testID: "sessions-view", flexDirection: "column", flexGrow: 1, paddingX: 1, children: [
20034
20155
  /* @__PURE__ */ jsx9(Box_default, { borderStyle: "single", borderColor: "#3D3660", paddingX: 1, alignSelf: "flex-start", children: /* @__PURE__ */ jsx9(Text, { bold: true, children: "Sessions" }) }),
20035
20156
  /* @__PURE__ */ jsx9(Text, { color: "#6B4C9A", children: "Arrows to navigate, Enter to view/launch, k to kill, Escape to detach" }),
20036
20157
  !demo && !orch.isLoading && /* @__PURE__ */ jsxs7(Box_default, { gap: 2, marginTop: 0, children: [
@@ -20067,7 +20188,7 @@ function SessionsView({
20067
20188
  loading ? /* @__PURE__ */ jsx9(Text, { color: "#6B4C9A", children: "Loading sessions..." }) : sessionError ? /* @__PURE__ */ jsxs7(Text, { color: "#C91B00", children: [
20068
20189
  "Failed to query sessions: ",
20069
20190
  sessionError
20070
- ] }) : !tmuxAvailable ? /* @__PURE__ */ jsx9(Text, { color: "#3D3660", children: "tmux not available. Start a tmux session first to manage employees." }) : flatItems.length === 0 ? /* @__PURE__ */ jsx9(Text, { color: "#3D3660", children: "No active sessions. Create a task to spawn an employee." }) : flatItems.map((item, i) => {
20191
+ ] }) : !tmuxAvailable ? /* @__PURE__ */ jsx9(Text, { color: "#3D3660", children: "tmux not available. Start a tmux session first to manage employees." }) : flatItems.length === 0 ? /* @__PURE__ */ jsx9(Text, { color: "#3D3660", children: "No active sessions. Create a task to spawn an employee." }) : /* @__PURE__ */ jsx9(Box_default, { testID: "sessions-tree", flexDirection: "column", children: flatItems.map((item, i) => {
20071
20192
  const isSelected = i === selectedIdx;
20072
20193
  const marker = isSelected ? "\u25B8 " : " ";
20073
20194
  if (item.type === "project") {
@@ -20105,7 +20226,7 @@ function SessionsView({
20105
20226
  ] }),
20106
20227
  activityPreview && emp.status !== "offline" && /* @__PURE__ */ jsx9(Box_default, { paddingLeft: 4, children: /* @__PURE__ */ jsx9(Text, { color: isSelected ? "#F0EDE8" : "#6B4C9A", backgroundColor: isSelected ? "#6B4C9A" : void 0, children: activityPreview }) })
20107
20228
  ] }, `emp-${item.projectName}-${emp.name}`);
20108
- })
20229
+ }) })
20109
20230
  ] });
20110
20231
  }
20111
20232
  var SESSION_REFRESH_MS, ACTIVE_PANE_PATTERN, ACTIVITY_PREVIEW_MAX;
@@ -20280,7 +20401,7 @@ function TasksView({ onBack }) {
20280
20401
  }
20281
20402
  const selected = taskRows[selectedTask]?.task;
20282
20403
  if (showDetail && selected) {
20283
- return /* @__PURE__ */ jsxs8(Box_default, { flexDirection: "column", flexGrow: 1, paddingX: 1, children: [
20404
+ return /* @__PURE__ */ jsxs8(Box_default, { testID: "tasks-view", flexDirection: "column", flexGrow: 1, paddingX: 1, children: [
20284
20405
  /* @__PURE__ */ jsx10(Box_default, { borderStyle: "single", borderColor: "#3D3660", paddingX: 1, alignSelf: "flex-start", children: /* @__PURE__ */ jsx10(Text, { bold: true, children: "Task Detail" }) }),
20285
20406
  /* @__PURE__ */ jsx10(Text, { color: "#6B4C9A", children: "Press Escape to go back" }),
20286
20407
  /* @__PURE__ */ jsx10(Text, { children: " " }),
@@ -20329,8 +20450,8 @@ function TasksView({ onBack }) {
20329
20450
  if (assigneeFilter !== "all") filterParts.push(`assignee:${assigneeFilter}`);
20330
20451
  if (projectFilter !== "all") filterParts.push(`project:${projectFilter}`);
20331
20452
  const filterLabel = filterParts.length > 0 ? filterParts.join(" ") : "none";
20332
- return /* @__PURE__ */ jsxs8(Box_default, { flexDirection: "column", flexGrow: 1, paddingX: 1, children: [
20333
- /* @__PURE__ */ jsx10(Box_default, { borderStyle: "single", borderColor: "#3D3660", paddingX: 1, alignSelf: "flex-start", children: /* @__PURE__ */ jsx10(Text, { bold: true, children: "Task Board" }) }),
20453
+ return /* @__PURE__ */ jsxs8(Box_default, { testID: "tasks-view", flexDirection: "column", flexGrow: 1, paddingX: 1, children: [
20454
+ /* @__PURE__ */ jsx10(Box_default, { testID: "tasks-list", borderStyle: "single", borderColor: "#3D3660", paddingX: 1, alignSelf: "flex-start", children: /* @__PURE__ */ jsx10(Text, { bold: true, children: "Task Board" }) }),
20334
20455
  /* @__PURE__ */ jsx10(Text, { children: " " }),
20335
20456
  /* @__PURE__ */ jsxs8(Text, { color: "#6B4C9A", children: [
20336
20457
  filteredTasks.length,
@@ -21068,7 +21189,7 @@ function GatewayView({ onBack }) {
21068
21189
  /* @__PURE__ */ jsx11(Text, { color: "#6B4C9A", children: "External agents and communication channels will appear here once set up." })
21069
21190
  ] });
21070
21191
  }
21071
- return /* @__PURE__ */ jsxs9(Box_default, { flexDirection: "column", flexGrow: 1, paddingX: 1, children: [
21192
+ return /* @__PURE__ */ jsxs9(Box_default, { testID: "gateway-view", flexDirection: "column", flexGrow: 1, paddingX: 1, children: [
21072
21193
  /* @__PURE__ */ jsx11(Box_default, { borderStyle: "single", borderColor: "#3D3660", paddingX: 1, alignSelf: "flex-start", children: /* @__PURE__ */ jsx11(Text, { bold: true, children: "Gateway Monitor" }) }),
21073
21194
  /* @__PURE__ */ jsxs9(Text, { color: "#6B4C9A", children: [
21074
21195
  "\u2191\u2193",
@@ -21109,62 +21230,64 @@ function GatewayView({ onBack }) {
21109
21230
  /* @__PURE__ */ jsx11(Text, { color: "#F5D76E", bold: true, children: totalUnread })
21110
21231
  ] }),
21111
21232
  /* @__PURE__ */ jsx11(Text, { children: " " }),
21112
- /* @__PURE__ */ jsxs9(Text, { bold: true, backgroundColor: sectionBg(1), color: sectionColor(1), children: [
21113
- marker(1),
21114
- "Conversations",
21115
- /* @__PURE__ */ jsxs9(Text, { color: "#6B4C9A", children: [
21116
- " (",
21117
- filteredConversations.length,
21118
- ")"
21119
- ] })
21120
- ] }),
21121
- /* @__PURE__ */ jsx11(Box_default, { paddingLeft: 4, gap: 1, children: PLATFORM_FILTERS.map((p) => /* @__PURE__ */ jsxs9(
21122
- Text,
21123
- {
21124
- color: platformFilter === p ? "#F5D76E" : "#6B4C9A",
21125
- bold: platformFilter === p,
21126
- backgroundColor: platformFilter === p ? "#6B4C9A" : void 0,
21127
- children: [
21128
- " ",
21129
- PLATFORM_FILTER_LABELS[p],
21130
- " "
21131
- ]
21132
- },
21133
- p
21134
- )) }),
21135
- /* @__PURE__ */ jsx11(Text, { children: " " }),
21136
- filteredConversations.length === 0 ? /* @__PURE__ */ jsxs9(Text, { color: "#6B4C9A", children: [
21137
- " ",
21138
- "No conversations",
21139
- connectionStatus === "connected" ? " \u2014 waiting for activity" : ""
21140
- ] }) : filteredConversations.slice(0, VISIBLE_CONVERSATIONS).map((conv, idx) => {
21141
- const isSelected = selectedSection === 1 && idx === selectedConvIdx;
21142
- return /* @__PURE__ */ jsxs9(Box_default, { paddingLeft: 4, backgroundColor: isSelected ? "#6B4C9A" : void 0, children: [
21143
- /* @__PURE__ */ jsxs9(Text, { color: platformColor(conv.platform), children: [
21144
- "\u25CF",
21145
- " "
21146
- ] }),
21147
- /* @__PURE__ */ jsx11(Text, { color: isSelected ? "#F5D76E" : "#C77DBA", children: padOrTruncate(conv.senderId, SENDER_MAX_LENGTH) }),
21148
- /* @__PURE__ */ jsxs9(Text, { color: isSelected ? "#F0EDE8" : "#6B4C9A", children: [
21149
- " ",
21150
- truncateText(conv.lastMessage, MESSAGE_TEXT_MAX_LENGTH)
21151
- ] }),
21233
+ /* @__PURE__ */ jsxs9(Box_default, { testID: "gateway-chat-panel", flexDirection: "column", children: [
21234
+ /* @__PURE__ */ jsxs9(Text, { bold: true, backgroundColor: sectionBg(1), color: sectionColor(1), children: [
21235
+ marker(1),
21236
+ "Conversations",
21152
21237
  /* @__PURE__ */ jsxs9(Text, { color: "#6B4C9A", children: [
21153
- " ",
21154
- timeAgo(conv.lastMessageTime)
21155
- ] }),
21156
- conv.unread > 0 && /* @__PURE__ */ jsxs9(Text, { color: "#F5D76E", bold: true, children: [
21157
21238
  " (",
21158
- conv.unread,
21239
+ filteredConversations.length,
21159
21240
  ")"
21160
21241
  ] })
21161
- ] }, conv.id);
21162
- }),
21163
- filteredConversations.length > VISIBLE_CONVERSATIONS && /* @__PURE__ */ jsxs9(Text, { color: "#6B4C9A", children: [
21164
- " ",
21165
- "+",
21166
- filteredConversations.length - VISIBLE_CONVERSATIONS,
21167
- " more"
21242
+ ] }),
21243
+ /* @__PURE__ */ jsx11(Box_default, { paddingLeft: 4, gap: 1, children: PLATFORM_FILTERS.map((p) => /* @__PURE__ */ jsxs9(
21244
+ Text,
21245
+ {
21246
+ color: platformFilter === p ? "#F5D76E" : "#6B4C9A",
21247
+ bold: platformFilter === p,
21248
+ backgroundColor: platformFilter === p ? "#6B4C9A" : void 0,
21249
+ children: [
21250
+ " ",
21251
+ PLATFORM_FILTER_LABELS[p],
21252
+ " "
21253
+ ]
21254
+ },
21255
+ p
21256
+ )) }),
21257
+ /* @__PURE__ */ jsx11(Text, { children: " " }),
21258
+ filteredConversations.length === 0 ? /* @__PURE__ */ jsxs9(Text, { color: "#6B4C9A", children: [
21259
+ " ",
21260
+ "No conversations",
21261
+ connectionStatus === "connected" ? " \u2014 waiting for activity" : ""
21262
+ ] }) : filteredConversations.slice(0, VISIBLE_CONVERSATIONS).map((conv, idx) => {
21263
+ const isSelected = selectedSection === 1 && idx === selectedConvIdx;
21264
+ return /* @__PURE__ */ jsxs9(Box_default, { paddingLeft: 4, backgroundColor: isSelected ? "#6B4C9A" : void 0, children: [
21265
+ /* @__PURE__ */ jsxs9(Text, { color: platformColor(conv.platform), children: [
21266
+ "\u25CF",
21267
+ " "
21268
+ ] }),
21269
+ /* @__PURE__ */ jsx11(Text, { color: isSelected ? "#F5D76E" : "#C77DBA", children: padOrTruncate(conv.senderId, SENDER_MAX_LENGTH) }),
21270
+ /* @__PURE__ */ jsxs9(Text, { color: isSelected ? "#F0EDE8" : "#6B4C9A", children: [
21271
+ " ",
21272
+ truncateText(conv.lastMessage, MESSAGE_TEXT_MAX_LENGTH)
21273
+ ] }),
21274
+ /* @__PURE__ */ jsxs9(Text, { color: "#6B4C9A", children: [
21275
+ " ",
21276
+ timeAgo(conv.lastMessageTime)
21277
+ ] }),
21278
+ conv.unread > 0 && /* @__PURE__ */ jsxs9(Text, { color: "#F5D76E", bold: true, children: [
21279
+ " (",
21280
+ conv.unread,
21281
+ ")"
21282
+ ] })
21283
+ ] }, conv.id);
21284
+ }),
21285
+ filteredConversations.length > VISIBLE_CONVERSATIONS && /* @__PURE__ */ jsxs9(Text, { color: "#6B4C9A", children: [
21286
+ " ",
21287
+ "+",
21288
+ filteredConversations.length - VISIBLE_CONVERSATIONS,
21289
+ " more"
21290
+ ] })
21168
21291
  ] }),
21169
21292
  /* @__PURE__ */ jsx11(Text, { children: " " }),
21170
21293
  /* @__PURE__ */ jsxs9(Text, { bold: true, backgroundColor: sectionBg(2), color: sectionColor(2), children: [
@@ -21492,7 +21615,7 @@ function TeamView({ onBack, onViewSessions }) {
21492
21615
  const totalCount = members.length + externals.length;
21493
21616
  const selected = allItems[selectedIdx];
21494
21617
  if (showDetail && selected) {
21495
- return /* @__PURE__ */ jsxs10(Box_default, { flexDirection: "column", flexGrow: 1, paddingX: 1, children: [
21618
+ return /* @__PURE__ */ jsxs10(Box_default, { testID: "team-view", flexDirection: "column", flexGrow: 1, paddingX: 1, children: [
21496
21619
  /* @__PURE__ */ jsx12(Box_default, { borderStyle: "single", borderColor: "#3D3660", paddingX: 1, alignSelf: "flex-start", children: /* @__PURE__ */ jsx12(Text, { bold: true, children: "Employee Detail" }) }),
21497
21620
  /* @__PURE__ */ jsx12(Text, { color: "#6B4C9A", children: "Press Escape to go back" }),
21498
21621
  /* @__PURE__ */ jsx12(Text, { children: " " }),
@@ -21529,8 +21652,8 @@ function TeamView({ onBack, onViewSessions }) {
21529
21652
  ] })
21530
21653
  ] });
21531
21654
  }
21532
- return /* @__PURE__ */ jsxs10(Box_default, { flexDirection: "column", flexGrow: 1, paddingX: 1, children: [
21533
- /* @__PURE__ */ jsx12(Box_default, { borderStyle: "single", borderColor: "#3D3660", paddingX: 1, alignSelf: "flex-start", children: /* @__PURE__ */ jsx12(Text, { bold: true, children: "Team Roster" }) }),
21655
+ return /* @__PURE__ */ jsxs10(Box_default, { testID: "team-view", flexDirection: "column", flexGrow: 1, paddingX: 1, children: [
21656
+ /* @__PURE__ */ jsx12(Box_default, { testID: "team-roster", borderStyle: "single", borderColor: "#3D3660", paddingX: 1, alignSelf: "flex-start", children: /* @__PURE__ */ jsx12(Text, { bold: true, children: "Team Roster" }) }),
21534
21657
  /* @__PURE__ */ jsxs10(Text, { color: "#6B4C9A", children: [
21535
21658
  totalCount,
21536
21659
  " agents | \u2191\u2193 navigate | Enter details | a add | s sessions"
@@ -22095,7 +22218,7 @@ function WikiView({ onBack }) {
22095
22218
  ] }) : null
22096
22219
  ] });
22097
22220
  }
22098
- return /* @__PURE__ */ jsxs11(Box_default, { flexDirection: "column", flexGrow: 1, paddingX: 1, children: [
22221
+ return /* @__PURE__ */ jsxs11(Box_default, { testID: "wiki-view", flexDirection: "column", flexGrow: 1, paddingX: 1, children: [
22099
22222
  /* @__PURE__ */ jsx13(Box_default, { borderStyle: "single", borderColor: "#3D3660", paddingX: 1, alignSelf: "flex-start", children: /* @__PURE__ */ jsx13(Text, { bold: true, children: "Wiki" }) }),
22100
22223
  /* @__PURE__ */ jsxs11(Box_default, { gap: 2, children: [
22101
22224
  /* @__PURE__ */ jsxs11(Text, { color: "#6B4C9A", children: [
@@ -22386,7 +22509,7 @@ function SettingsView({ onBack }) {
22386
22509
  const sectionMarker = (idx) => selectedSection === idx ? "\u25B8 " : " ";
22387
22510
  const anyGateway = gateway.adapters.some((a) => a.configured);
22388
22511
  const formatLimit = (n) => n === -1 ? "unlimited" : n.toLocaleString();
22389
- return /* @__PURE__ */ jsxs12(Box_default, { flexDirection: "column", flexGrow: 1, paddingX: 1, children: [
22512
+ return /* @__PURE__ */ jsxs12(Box_default, { testID: "settings-view", flexDirection: "column", flexGrow: 1, paddingX: 1, children: [
22390
22513
  /* @__PURE__ */ jsx14(Box_default, { borderStyle: "single", borderColor: "#3D3660", paddingX: 1, alignSelf: "flex-start", children: /* @__PURE__ */ jsx14(Text, { bold: true, children: "Settings" }) }),
22391
22514
  /* @__PURE__ */ jsx14(Text, { color: DIM, children: "\u2191\u2193 navigate sections r refresh" }),
22392
22515
  /* @__PURE__ */ jsx14(Text, { children: " " }),
@@ -22394,129 +22517,131 @@ function SettingsView({ onBack }) {
22394
22517
  /* @__PURE__ */ jsx14(Text, { color: DIM, children: "Loading settings..." }),
22395
22518
  /* @__PURE__ */ jsx14(Text, { children: " " })
22396
22519
  ] }),
22397
- /* @__PURE__ */ jsxs12(Text, { bold: true, backgroundColor: sectionBg(0), color: sectionColor(0), children: [
22398
- sectionMarker(0),
22399
- "Providers"
22400
- ] }),
22401
- /* @__PURE__ */ jsx14(Text, { children: " " }),
22402
- providers.map((p) => /* @__PURE__ */ jsxs12(Text, { children: [
22403
- " ",
22404
- /* @__PURE__ */ jsx14(Text, { color: statusColor(p.configured), children: statusDot(p.configured) }),
22405
- " ",
22406
- p.name,
22407
- ": ",
22408
- /* @__PURE__ */ jsx14(Text, { color: statusColor(p.configured), children: p.detail })
22409
- ] }, p.name)),
22410
- /* @__PURE__ */ jsx14(Text, { children: " " }),
22411
- /* @__PURE__ */ jsxs12(Text, { bold: true, backgroundColor: sectionBg(1), color: sectionColor(1), children: [
22412
- sectionMarker(1),
22413
- "Cloud Sync"
22414
- ] }),
22415
- /* @__PURE__ */ jsx14(Text, { children: " " }),
22416
- cloud.configured ? /* @__PURE__ */ jsxs12(Fragment5, { children: [
22520
+ /* @__PURE__ */ jsxs12(Box_default, { testID: "settings-sections", flexDirection: "column", children: [
22521
+ /* @__PURE__ */ jsxs12(Text, { bold: true, backgroundColor: sectionBg(0), color: sectionColor(0), children: [
22522
+ sectionMarker(0),
22523
+ "Providers"
22524
+ ] }),
22525
+ /* @__PURE__ */ jsx14(Text, { children: " " }),
22526
+ providers.map((p) => /* @__PURE__ */ jsxs12(Text, { children: [
22527
+ " ",
22528
+ /* @__PURE__ */ jsx14(Text, { color: statusColor(p.configured), children: statusDot(p.configured) }),
22529
+ " ",
22530
+ p.name,
22531
+ ": ",
22532
+ /* @__PURE__ */ jsx14(Text, { color: statusColor(p.configured), children: p.detail })
22533
+ ] }, p.name)),
22534
+ /* @__PURE__ */ jsx14(Text, { children: " " }),
22535
+ /* @__PURE__ */ jsxs12(Text, { bold: true, backgroundColor: sectionBg(1), color: sectionColor(1), children: [
22536
+ sectionMarker(1),
22537
+ "Cloud Sync"
22538
+ ] }),
22539
+ /* @__PURE__ */ jsx14(Text, { children: " " }),
22540
+ cloud.configured ? /* @__PURE__ */ jsxs12(Fragment5, { children: [
22541
+ /* @__PURE__ */ jsxs12(Text, { children: [
22542
+ " ",
22543
+ /* @__PURE__ */ jsx14(Text, { color: GREEN, children: statusDot(true) }),
22544
+ " Status: ",
22545
+ /* @__PURE__ */ jsx14(Text, { color: GREEN, children: "connected" })
22546
+ ] }),
22547
+ /* @__PURE__ */ jsxs12(Text, { children: [
22548
+ " ",
22549
+ "Endpoint: ",
22550
+ /* @__PURE__ */ jsx14(Text, { color: GREEN, children: cloud.endpoint })
22551
+ ] }),
22552
+ /* @__PURE__ */ jsxs12(Text, { children: [
22553
+ " ",
22554
+ "API key: ",
22555
+ /* @__PURE__ */ jsx14(Text, { color: DIM, children: cloud.apiKey })
22556
+ ] })
22557
+ ] }) : /* @__PURE__ */ jsxs12(Text, { children: [
22558
+ " ",
22559
+ /* @__PURE__ */ jsx14(Text, { color: DIM, children: statusDot(false) }),
22560
+ " ",
22561
+ /* @__PURE__ */ jsx14(Text, { color: DIM, children: "Not configured \u2014 run /exe-cloud" })
22562
+ ] }),
22563
+ /* @__PURE__ */ jsx14(Text, { children: " " }),
22564
+ /* @__PURE__ */ jsxs12(Text, { bold: true, backgroundColor: sectionBg(2), color: sectionColor(2), children: [
22565
+ sectionMarker(2),
22566
+ "License"
22567
+ ] }),
22568
+ /* @__PURE__ */ jsx14(Text, { children: " " }),
22417
22569
  /* @__PURE__ */ jsxs12(Text, { children: [
22418
22570
  " ",
22419
- /* @__PURE__ */ jsx14(Text, { color: GREEN, children: statusDot(true) }),
22420
- " Status: ",
22421
- /* @__PURE__ */ jsx14(Text, { color: GREEN, children: "connected" })
22571
+ "Plan: ",
22572
+ /* @__PURE__ */ jsx14(Text, { color: license.plan === "FREE" ? YELLOW : GREEN, children: license.plan })
22573
+ ] }),
22574
+ license.expiresAt && /* @__PURE__ */ jsxs12(Text, { children: [
22575
+ " ",
22576
+ "Expires: ",
22577
+ /* @__PURE__ */ jsx14(Text, { color: GREEN, children: license.expiresAt.split("T")[0] })
22422
22578
  ] }),
22423
22579
  /* @__PURE__ */ jsxs12(Text, { children: [
22424
22580
  " ",
22425
- "Endpoint: ",
22426
- /* @__PURE__ */ jsx14(Text, { color: GREEN, children: cloud.endpoint })
22581
+ "Devices: ",
22582
+ /* @__PURE__ */ jsx14(Text, { color: GREEN, children: formatLimit(license.deviceLimit) })
22427
22583
  ] }),
22428
22584
  /* @__PURE__ */ jsxs12(Text, { children: [
22429
22585
  " ",
22430
- "API key: ",
22431
- /* @__PURE__ */ jsx14(Text, { color: DIM, children: cloud.apiKey })
22586
+ "Employees: ",
22587
+ /* @__PURE__ */ jsx14(Text, { color: GREEN, children: formatLimit(license.employeeLimit) })
22588
+ ] }),
22589
+ /* @__PURE__ */ jsxs12(Text, { children: [
22590
+ " ",
22591
+ "Memory limit: ",
22592
+ /* @__PURE__ */ jsx14(Text, { color: GREEN, children: formatLimit(license.memoryLimit) })
22593
+ ] }),
22594
+ /* @__PURE__ */ jsx14(Text, { children: " " }),
22595
+ /* @__PURE__ */ jsxs12(Text, { bold: true, backgroundColor: sectionBg(3), color: sectionColor(3), children: [
22596
+ sectionMarker(3),
22597
+ "System"
22598
+ ] }),
22599
+ /* @__PURE__ */ jsx14(Text, { children: " " }),
22600
+ /* @__PURE__ */ jsxs12(Text, { children: [
22601
+ " ",
22602
+ /* @__PURE__ */ jsx14(Text, { color: system.daemon === "running" ? GREEN : DIM, children: statusDot(system.daemon === "running") }),
22603
+ " Daemon: ",
22604
+ /* @__PURE__ */ jsx14(Text, { color: system.daemon === "running" ? GREEN : DIM, children: system.daemon })
22605
+ ] }),
22606
+ /* @__PURE__ */ jsxs12(Text, { children: [
22607
+ " ",
22608
+ "Version: ",
22609
+ /* @__PURE__ */ jsx14(Text, { color: GREEN, children: system.version })
22610
+ ] }),
22611
+ /* @__PURE__ */ jsxs12(Text, { children: [
22612
+ " ",
22613
+ "Encryption: ",
22614
+ /* @__PURE__ */ jsx14(Text, { color: system.encryption.includes("AES") ? GREEN : DIM, children: system.encryption })
22615
+ ] }),
22616
+ /* @__PURE__ */ jsxs12(Text, { children: [
22617
+ " ",
22618
+ "Embedding: ",
22619
+ /* @__PURE__ */ jsx14(Text, { color: GREEN, children: system.embeddingModel })
22620
+ ] }),
22621
+ /* @__PURE__ */ jsxs12(Text, { children: [
22622
+ " ",
22623
+ "DB path: ",
22624
+ /* @__PURE__ */ jsx14(Text, { color: DIM, children: system.dbPath })
22625
+ ] }),
22626
+ /* @__PURE__ */ jsx14(Text, { children: " " }),
22627
+ /* @__PURE__ */ jsxs12(Text, { bold: true, backgroundColor: sectionBg(4), color: sectionColor(4), children: [
22628
+ sectionMarker(4),
22629
+ "Gateway"
22630
+ ] }),
22631
+ /* @__PURE__ */ jsx14(Text, { children: " " }),
22632
+ anyGateway ? gateway.adapters.map((a) => /* @__PURE__ */ jsxs12(Text, { children: [
22633
+ " ",
22634
+ /* @__PURE__ */ jsx14(Text, { color: statusColor(a.configured), children: statusDot(a.configured) }),
22635
+ " ",
22636
+ a.name,
22637
+ ": ",
22638
+ /* @__PURE__ */ jsx14(Text, { color: statusColor(a.configured), children: a.configured ? "configured" : "not configured" })
22639
+ ] }, a.name)) : /* @__PURE__ */ jsxs12(Text, { children: [
22640
+ " ",
22641
+ /* @__PURE__ */ jsx14(Text, { color: DIM, children: statusDot(false) }),
22642
+ " ",
22643
+ /* @__PURE__ */ jsx14(Text, { color: DIM, children: "No gateway configured" })
22432
22644
  ] })
22433
- ] }) : /* @__PURE__ */ jsxs12(Text, { children: [
22434
- " ",
22435
- /* @__PURE__ */ jsx14(Text, { color: DIM, children: statusDot(false) }),
22436
- " ",
22437
- /* @__PURE__ */ jsx14(Text, { color: DIM, children: "Not configured \u2014 run /exe-cloud" })
22438
- ] }),
22439
- /* @__PURE__ */ jsx14(Text, { children: " " }),
22440
- /* @__PURE__ */ jsxs12(Text, { bold: true, backgroundColor: sectionBg(2), color: sectionColor(2), children: [
22441
- sectionMarker(2),
22442
- "License"
22443
- ] }),
22444
- /* @__PURE__ */ jsx14(Text, { children: " " }),
22445
- /* @__PURE__ */ jsxs12(Text, { children: [
22446
- " ",
22447
- "Plan: ",
22448
- /* @__PURE__ */ jsx14(Text, { color: license.plan === "FREE" ? YELLOW : GREEN, children: license.plan })
22449
- ] }),
22450
- license.expiresAt && /* @__PURE__ */ jsxs12(Text, { children: [
22451
- " ",
22452
- "Expires: ",
22453
- /* @__PURE__ */ jsx14(Text, { color: GREEN, children: license.expiresAt.split("T")[0] })
22454
- ] }),
22455
- /* @__PURE__ */ jsxs12(Text, { children: [
22456
- " ",
22457
- "Devices: ",
22458
- /* @__PURE__ */ jsx14(Text, { color: GREEN, children: formatLimit(license.deviceLimit) })
22459
- ] }),
22460
- /* @__PURE__ */ jsxs12(Text, { children: [
22461
- " ",
22462
- "Employees: ",
22463
- /* @__PURE__ */ jsx14(Text, { color: GREEN, children: formatLimit(license.employeeLimit) })
22464
- ] }),
22465
- /* @__PURE__ */ jsxs12(Text, { children: [
22466
- " ",
22467
- "Memory limit: ",
22468
- /* @__PURE__ */ jsx14(Text, { color: GREEN, children: formatLimit(license.memoryLimit) })
22469
- ] }),
22470
- /* @__PURE__ */ jsx14(Text, { children: " " }),
22471
- /* @__PURE__ */ jsxs12(Text, { bold: true, backgroundColor: sectionBg(3), color: sectionColor(3), children: [
22472
- sectionMarker(3),
22473
- "System"
22474
- ] }),
22475
- /* @__PURE__ */ jsx14(Text, { children: " " }),
22476
- /* @__PURE__ */ jsxs12(Text, { children: [
22477
- " ",
22478
- /* @__PURE__ */ jsx14(Text, { color: system.daemon === "running" ? GREEN : DIM, children: statusDot(system.daemon === "running") }),
22479
- " Daemon: ",
22480
- /* @__PURE__ */ jsx14(Text, { color: system.daemon === "running" ? GREEN : DIM, children: system.daemon })
22481
- ] }),
22482
- /* @__PURE__ */ jsxs12(Text, { children: [
22483
- " ",
22484
- "Version: ",
22485
- /* @__PURE__ */ jsx14(Text, { color: GREEN, children: system.version })
22486
- ] }),
22487
- /* @__PURE__ */ jsxs12(Text, { children: [
22488
- " ",
22489
- "Encryption: ",
22490
- /* @__PURE__ */ jsx14(Text, { color: system.encryption.includes("AES") ? GREEN : DIM, children: system.encryption })
22491
- ] }),
22492
- /* @__PURE__ */ jsxs12(Text, { children: [
22493
- " ",
22494
- "Embedding: ",
22495
- /* @__PURE__ */ jsx14(Text, { color: GREEN, children: system.embeddingModel })
22496
- ] }),
22497
- /* @__PURE__ */ jsxs12(Text, { children: [
22498
- " ",
22499
- "DB path: ",
22500
- /* @__PURE__ */ jsx14(Text, { color: DIM, children: system.dbPath })
22501
- ] }),
22502
- /* @__PURE__ */ jsx14(Text, { children: " " }),
22503
- /* @__PURE__ */ jsxs12(Text, { bold: true, backgroundColor: sectionBg(4), color: sectionColor(4), children: [
22504
- sectionMarker(4),
22505
- "Gateway"
22506
- ] }),
22507
- /* @__PURE__ */ jsx14(Text, { children: " " }),
22508
- anyGateway ? gateway.adapters.map((a) => /* @__PURE__ */ jsxs12(Text, { children: [
22509
- " ",
22510
- /* @__PURE__ */ jsx14(Text, { color: statusColor(a.configured), children: statusDot(a.configured) }),
22511
- " ",
22512
- a.name,
22513
- ": ",
22514
- /* @__PURE__ */ jsx14(Text, { color: statusColor(a.configured), children: a.configured ? "configured" : "not configured" })
22515
- ] }, a.name)) : /* @__PURE__ */ jsxs12(Text, { children: [
22516
- " ",
22517
- /* @__PURE__ */ jsx14(Text, { color: DIM, children: statusDot(false) }),
22518
- " ",
22519
- /* @__PURE__ */ jsx14(Text, { color: DIM, children: "No gateway configured" })
22520
22645
  ] })
22521
22646
  ] });
22522
22647
  }
@@ -22568,7 +22693,7 @@ function DebugPanel() {
22568
22693
  orgBus.offAny(handler);
22569
22694
  };
22570
22695
  }, []);
22571
- return /* @__PURE__ */ jsxs13(Box_default, { flexDirection: "column", borderStyle: "single", borderColor: "#6B4C9A", flexGrow: 1, paddingX: 1, children: [
22696
+ return /* @__PURE__ */ jsxs13(Box_default, { testID: "debug-panel", flexDirection: "column", borderStyle: "single", borderColor: "#6B4C9A", flexGrow: 1, paddingX: 1, children: [
22572
22697
  /* @__PURE__ */ jsx15(Text, { bold: true, color: "#F5D76E", children: "Debug \u2014 Live Events" }),
22573
22698
  /* @__PURE__ */ jsx15(Text, { color: "#3D3660", children: "\u2500".repeat(40) }),
22574
22699
  events.length === 0 ? /* @__PURE__ */ jsx15(Text, { color: "#3D3660", children: "Waiting for events..." }) : events.slice(-DISPLAY_EVENTS).map(({ event, id }) => {
@@ -22613,6 +22738,7 @@ function HelpOverlay({ tabName, shortcuts }) {
22613
22738
  return /* @__PURE__ */ jsxs14(
22614
22739
  Box_default,
22615
22740
  {
22741
+ testID: "help-overlay",
22616
22742
  flexDirection: "column",
22617
22743
  borderStyle: "double",
22618
22744
  borderColor: "#6B4C9A",
@@ -22757,8 +22883,8 @@ function App2() {
22757
22883
  wiki: /* @__PURE__ */ jsx17(WikiView, { onBack: () => setFocus("sidebar") }),
22758
22884
  settings: /* @__PURE__ */ jsx17(SettingsView, { onBack: () => setFocus("sidebar") })
22759
22885
  };
22760
- return /* @__PURE__ */ jsx17(ErrorBoundary2, { children: /* @__PURE__ */ jsx17(AlternateScreen, { children: /* @__PURE__ */ jsx17(DemoProvider, { demo: isDemo, children: /* @__PURE__ */ jsxs15(Box_default, { flexDirection: "column", flexGrow: 1, children: [
22761
- /* @__PURE__ */ jsxs15(Box_default, { flexGrow: 1, children: [
22886
+ return /* @__PURE__ */ jsx17(ErrorBoundary2, { children: /* @__PURE__ */ jsx17(AlternateScreen, { children: /* @__PURE__ */ jsx17(DemoProvider, { demo: isDemo, children: /* @__PURE__ */ jsxs15(Box_default, { testID: "app-root", flexDirection: "column", flexGrow: 1, children: [
22887
+ /* @__PURE__ */ jsxs15(Box_default, { testID: "app-content", flexGrow: 1, children: [
22762
22888
  /* @__PURE__ */ jsx17(Sidebar, { active: section, onSelect: setSection, onQuit: exit, focused: focus === "sidebar" }),
22763
22889
  showHelp ? /* @__PURE__ */ jsx17(
22764
22890
  HelpOverlay,