@askexenow/exe-os 0.8.55 → 0.8.57

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 (71) hide show
  1. package/dist/bin/backfill-conversations.js +13 -0
  2. package/dist/bin/backfill-responses.js +13 -0
  3. package/dist/bin/backfill-vectors.js +65 -6
  4. package/dist/bin/cleanup-stale-review-tasks.js +407 -57
  5. package/dist/bin/cli.js +6364 -6248
  6. package/dist/bin/exe-agent.js +13 -0
  7. package/dist/bin/exe-assign.js +13 -0
  8. package/dist/bin/exe-boot.js +541 -433
  9. package/dist/bin/exe-call.js +13 -0
  10. package/dist/bin/exe-doctor.js +76 -5
  11. package/dist/bin/exe-export-behaviors.js +13 -0
  12. package/dist/bin/exe-forget.js +13 -0
  13. package/dist/bin/exe-gateway.js +73 -29
  14. package/dist/bin/exe-heartbeat.js +248 -41
  15. package/dist/bin/exe-kill.js +14 -1
  16. package/dist/bin/exe-launch-agent.js +13 -0
  17. package/dist/bin/exe-new-employee.js +13 -0
  18. package/dist/bin/exe-pending-messages.js +13 -0
  19. package/dist/bin/exe-pending-notifications.js +13 -0
  20. package/dist/bin/exe-pending-reviews.js +56 -34
  21. package/dist/bin/exe-rename.js +13 -0
  22. package/dist/bin/exe-review.js +13 -0
  23. package/dist/bin/exe-search.js +13 -0
  24. package/dist/bin/exe-session-cleanup.js +2972 -2924
  25. package/dist/bin/exe-status.js +410 -66
  26. package/dist/bin/exe-team.js +13 -0
  27. package/dist/bin/git-sweep.js +3442 -3392
  28. package/dist/bin/graph-backfill.js +13 -0
  29. package/dist/bin/graph-export.js +13 -0
  30. package/dist/bin/install.js +47 -3
  31. package/dist/bin/scan-tasks.js +3602 -3556
  32. package/dist/bin/setup.js +13 -0
  33. package/dist/bin/shard-migrate.js +13 -0
  34. package/dist/bin/update.js +485 -0
  35. package/dist/bin/wiki-sync.js +13 -0
  36. package/dist/gateway/index.js +73 -29
  37. package/dist/hooks/bug-report-worker.js +73 -29
  38. package/dist/hooks/commit-complete.js +3437 -3392
  39. package/dist/hooks/error-recall.js +13 -0
  40. package/dist/hooks/ingest-worker.js +130 -34
  41. package/dist/hooks/ingest.js +25 -6
  42. package/dist/hooks/instructions-loaded.js +13 -0
  43. package/dist/hooks/notification.js +13 -0
  44. package/dist/hooks/post-compact.js +371 -53
  45. package/dist/hooks/pre-compact.js +3121 -3075
  46. package/dist/hooks/pre-tool-use.js +400 -93
  47. package/dist/hooks/prompt-ingest-worker.js +13 -0
  48. package/dist/hooks/prompt-submit.js +73 -29
  49. package/dist/hooks/response-ingest-worker.js +13 -0
  50. package/dist/hooks/session-end.js +382 -64
  51. package/dist/hooks/session-start.js +355 -37
  52. package/dist/hooks/stop.js +381 -62
  53. package/dist/hooks/subagent-stop.js +371 -53
  54. package/dist/hooks/summary-worker.js +739 -219
  55. package/dist/index.js +93 -37
  56. package/dist/lib/employee-templates.js +13 -0
  57. package/dist/lib/exe-daemon.js +94 -41
  58. package/dist/lib/hybrid-search.js +13 -0
  59. package/dist/lib/schedules.js +13 -0
  60. package/dist/lib/store.js +13 -0
  61. package/dist/lib/tasks.js +60 -29
  62. package/dist/lib/tmux-routing.js +60 -29
  63. package/dist/mcp/server.js +136 -38
  64. package/dist/mcp/tools/create-task.js +60 -29
  65. package/dist/mcp/tools/list-tasks.js +116 -2511
  66. package/dist/mcp/tools/update-task.js +273 -243
  67. package/dist/runtime/index.js +93 -37
  68. package/dist/tui/App.js +5609 -5541
  69. package/package.json +1 -1
  70. package/src/commands/exe/build-adv.md +2 -2
  71. package/src/commands/exe/heartbeat.md +2 -1
@@ -1,6 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
4
6
  var __esm = (fn, res) => function __init() {
5
7
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
6
8
  };
@@ -8,6 +10,15 @@ var __export = (target, all) => {
8
10
  for (var name in all)
9
11
  __defProp(target, name, { get: all[name], enumerable: true });
10
12
  };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
20
+ };
21
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
11
22
 
12
23
  // src/lib/db-retry.ts
13
24
  function isBusyError(err) {
@@ -1105,6 +1116,61 @@ var init_config = __esm({
1105
1116
  }
1106
1117
  });
1107
1118
 
1119
+ // src/lib/state-bus.ts
1120
+ var StateBus, orgBus;
1121
+ var init_state_bus = __esm({
1122
+ "src/lib/state-bus.ts"() {
1123
+ "use strict";
1124
+ StateBus = class {
1125
+ handlers = /* @__PURE__ */ new Map();
1126
+ globalHandlers = /* @__PURE__ */ new Set();
1127
+ /** Emit an event to all subscribers */
1128
+ emit(event) {
1129
+ const typeHandlers = this.handlers.get(event.type);
1130
+ if (typeHandlers) {
1131
+ for (const handler of typeHandlers) {
1132
+ try {
1133
+ handler(event);
1134
+ } catch {
1135
+ }
1136
+ }
1137
+ }
1138
+ for (const handler of this.globalHandlers) {
1139
+ try {
1140
+ handler(event);
1141
+ } catch {
1142
+ }
1143
+ }
1144
+ }
1145
+ /** Subscribe to a specific event type */
1146
+ on(type, handler) {
1147
+ if (!this.handlers.has(type)) {
1148
+ this.handlers.set(type, /* @__PURE__ */ new Set());
1149
+ }
1150
+ this.handlers.get(type).add(handler);
1151
+ }
1152
+ /** Subscribe to ALL events */
1153
+ onAny(handler) {
1154
+ this.globalHandlers.add(handler);
1155
+ }
1156
+ /** Unsubscribe from a specific event type */
1157
+ off(type, handler) {
1158
+ this.handlers.get(type)?.delete(handler);
1159
+ }
1160
+ /** Unsubscribe from ALL events */
1161
+ offAny(handler) {
1162
+ this.globalHandlers.delete(handler);
1163
+ }
1164
+ /** Remove all listeners */
1165
+ clear() {
1166
+ this.handlers.clear();
1167
+ this.globalHandlers.clear();
1168
+ }
1169
+ };
1170
+ orgBus = new StateBus();
1171
+ }
1172
+ });
1173
+
1108
1174
  // src/lib/shard-manager.ts
1109
1175
  var shard_manager_exports = {};
1110
1176
  __export(shard_manager_exports, {
@@ -1435,6 +1501,19 @@ var init_platform_procedures = __esm({
1435
1501
  domain: "architecture",
1436
1502
  priority: "p0",
1437
1503
  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."
1504
+ },
1505
+ // --- Orchestration golden path ---
1506
+ {
1507
+ title: "Task lifecycle \u2014 the golden path every agent follows",
1508
+ domain: "workflow",
1509
+ priority: "p0",
1510
+ content: "create_task is dispatch + delivery. Task lifecycle: open \u2192 in_progress (you start) \u2192 done (update_task when finished) \u2192 needs_review (reviewer nudged) \u2192 closed (COO only via close_task). DB is the reliable delivery \u2014 intercom is just a speedup nudge. If you finish a task, self-chain: check for next task immediately (step 7). Never wait for a nudge. Never say 'standing by.'"
1511
+ },
1512
+ {
1513
+ title: "Intercom is a speedup, not delivery \u2014 DB is the source of truth",
1514
+ domain: "architecture",
1515
+ priority: "p0",
1516
+ content: "Tasks live in the DB. Intercom (tmux send-keys) is fire-and-forget \u2014 it may fail, get garbled, or arrive mid-work. Never rely on intercom for task delivery. The UserPromptSubmit hook checks the DB for new tasks on every prompt. Your operating procedures step 7 says check for next work. The daemon nudges idle agents as a speedup. If you have no tasks, you found them all."
1438
1517
  }
1439
1518
  ];
1440
1519
  PLATFORM_PROCEDURE_TITLES = new Set(
@@ -1514,6 +1593,324 @@ ${p.content}`).join("\n\n");
1514
1593
  }
1515
1594
  });
1516
1595
 
1596
+ // src/lib/session-registry.ts
1597
+ import path4 from "path";
1598
+ import os3 from "os";
1599
+ var REGISTRY_PATH;
1600
+ var init_session_registry = __esm({
1601
+ "src/lib/session-registry.ts"() {
1602
+ "use strict";
1603
+ REGISTRY_PATH = path4.join(os3.homedir(), ".exe-os", "session-registry.json");
1604
+ }
1605
+ });
1606
+
1607
+ // src/lib/session-key.ts
1608
+ import { execSync } from "child_process";
1609
+ function getSessionKey() {
1610
+ if (_cached) return _cached;
1611
+ let pid = process.ppid;
1612
+ for (let i = 0; i < 10; i++) {
1613
+ try {
1614
+ const info = execSync(`ps -p ${pid} -o ppid=,comm=`, {
1615
+ encoding: "utf8",
1616
+ timeout: 2e3
1617
+ }).trim();
1618
+ const match = info.match(/^\s*(\d+)\s+(.+)$/);
1619
+ if (!match) break;
1620
+ const [, ppid, cmd] = match;
1621
+ if (cmd === "claude" || cmd.endsWith("/claude")) {
1622
+ _cached = String(pid);
1623
+ return _cached;
1624
+ }
1625
+ pid = parseInt(ppid, 10);
1626
+ if (pid <= 1) break;
1627
+ } catch {
1628
+ break;
1629
+ }
1630
+ }
1631
+ _cached = process.env.CLAUDE_CODE_SSE_PORT ?? String(process.ppid);
1632
+ return _cached;
1633
+ }
1634
+ var _cached;
1635
+ var init_session_key = __esm({
1636
+ "src/lib/session-key.ts"() {
1637
+ "use strict";
1638
+ _cached = null;
1639
+ }
1640
+ });
1641
+
1642
+ // src/lib/tmux-transport.ts
1643
+ var tmux_transport_exports = {};
1644
+ __export(tmux_transport_exports, {
1645
+ TmuxTransport: () => TmuxTransport
1646
+ });
1647
+ import { execFileSync } from "child_process";
1648
+ var QUIET, TmuxTransport;
1649
+ var init_tmux_transport = __esm({
1650
+ "src/lib/tmux-transport.ts"() {
1651
+ "use strict";
1652
+ QUIET = {
1653
+ encoding: "utf8",
1654
+ stdio: ["pipe", "pipe", "pipe"]
1655
+ };
1656
+ TmuxTransport = class {
1657
+ getMySession() {
1658
+ try {
1659
+ return execFileSync("tmux", ["display-message", "-p", "#{session_name}"], QUIET).trim() || null;
1660
+ } catch {
1661
+ return null;
1662
+ }
1663
+ }
1664
+ listSessions() {
1665
+ try {
1666
+ return execFileSync("tmux", ["list-sessions", "-F", "#{session_name}"], QUIET).trim().split("\n").filter(Boolean);
1667
+ } catch {
1668
+ return [];
1669
+ }
1670
+ }
1671
+ isAlive(target) {
1672
+ try {
1673
+ const sessions = this.listSessions();
1674
+ if (!sessions.includes(target)) return false;
1675
+ const paneStatus = execFileSync(
1676
+ "tmux",
1677
+ ["list-panes", "-t", target, "-F", "#{pane_dead}"],
1678
+ QUIET
1679
+ ).trim();
1680
+ return paneStatus !== "1";
1681
+ } catch {
1682
+ return false;
1683
+ }
1684
+ }
1685
+ sendKeys(target, keys) {
1686
+ execFileSync("tmux", ["send-keys", "-t", target, keys, "Enter"], QUIET);
1687
+ }
1688
+ capturePane(target, lines) {
1689
+ const args = ["capture-pane", "-t", target, "-p"];
1690
+ if (lines) args.push("-S", `-${lines}`);
1691
+ return execFileSync("tmux", args, { ...QUIET, timeout: 3e3 });
1692
+ }
1693
+ isPaneInCopyMode(target) {
1694
+ try {
1695
+ const result = execFileSync(
1696
+ "tmux",
1697
+ ["display-message", "-p", "-t", target, "#{pane_in_mode}"],
1698
+ { ...QUIET, timeout: 3e3 }
1699
+ ).trim();
1700
+ return result === "1";
1701
+ } catch {
1702
+ return false;
1703
+ }
1704
+ }
1705
+ spawn(name, config) {
1706
+ try {
1707
+ const args = ["new-session", "-d", "-s", name];
1708
+ if (config.cwd) args.push("-c", config.cwd);
1709
+ args.push(config.command);
1710
+ execFileSync("tmux", args);
1711
+ return { sessionName: name };
1712
+ } catch (e) {
1713
+ return { sessionName: name, error: `spawn failed: ${e}` };
1714
+ }
1715
+ }
1716
+ kill(target) {
1717
+ try {
1718
+ execFileSync("tmux", ["kill-session", "-t", target], QUIET);
1719
+ } catch {
1720
+ }
1721
+ }
1722
+ pipeLog(target, logFile) {
1723
+ try {
1724
+ const safePath = logFile.replace(/'/g, "'\\''");
1725
+ execFileSync("tmux", ["pipe-pane", "-t", target, `cat >> '${safePath}'`], QUIET);
1726
+ } catch {
1727
+ }
1728
+ }
1729
+ };
1730
+ }
1731
+ });
1732
+
1733
+ // src/lib/transport.ts
1734
+ function getTransport() {
1735
+ if (!_transport) {
1736
+ const { TmuxTransport: TmuxTransport2 } = (init_tmux_transport(), __toCommonJS(tmux_transport_exports));
1737
+ _transport = new TmuxTransport2();
1738
+ }
1739
+ return _transport;
1740
+ }
1741
+ var _transport;
1742
+ var init_transport = __esm({
1743
+ "src/lib/transport.ts"() {
1744
+ "use strict";
1745
+ _transport = null;
1746
+ }
1747
+ });
1748
+
1749
+ // src/lib/cc-agent-support.ts
1750
+ import { execSync as execSync2 } from "child_process";
1751
+ var init_cc_agent_support = __esm({
1752
+ "src/lib/cc-agent-support.ts"() {
1753
+ "use strict";
1754
+ }
1755
+ });
1756
+
1757
+ // src/lib/mcp-prefix.ts
1758
+ var MCP_PRIMARY_KEY, MCP_LEGACY_KEY, MCP_TOOL_PREFIXES;
1759
+ var init_mcp_prefix = __esm({
1760
+ "src/lib/mcp-prefix.ts"() {
1761
+ "use strict";
1762
+ MCP_PRIMARY_KEY = "exe-os";
1763
+ MCP_LEGACY_KEY = "exe-mem";
1764
+ MCP_TOOL_PREFIXES = [
1765
+ `mcp__${MCP_PRIMARY_KEY}__`,
1766
+ `mcp__${MCP_LEGACY_KEY}__`
1767
+ ];
1768
+ }
1769
+ });
1770
+
1771
+ // src/lib/provider-table.ts
1772
+ var init_provider_table = __esm({
1773
+ "src/lib/provider-table.ts"() {
1774
+ "use strict";
1775
+ }
1776
+ });
1777
+
1778
+ // src/lib/intercom-queue.ts
1779
+ import { readFileSync as readFileSync2, writeFileSync, renameSync as renameSync2, existsSync as existsSync4, mkdirSync as mkdirSync2 } from "fs";
1780
+ import path5 from "path";
1781
+ import os4 from "os";
1782
+ var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
1783
+ var init_intercom_queue = __esm({
1784
+ "src/lib/intercom-queue.ts"() {
1785
+ "use strict";
1786
+ QUEUE_PATH = path5.join(os4.homedir(), ".exe-os", "intercom-queue.json");
1787
+ TTL_MS = 60 * 60 * 1e3;
1788
+ INTERCOM_LOG = path5.join(os4.homedir(), ".exe-os", "intercom.log");
1789
+ }
1790
+ });
1791
+
1792
+ // src/lib/employees.ts
1793
+ import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
1794
+ import { existsSync as existsSync5, symlinkSync, readlinkSync, readFileSync as readFileSync3 } from "fs";
1795
+ import { execSync as execSync3 } from "child_process";
1796
+ import path6 from "path";
1797
+ var EMPLOYEES_PATH;
1798
+ var init_employees = __esm({
1799
+ "src/lib/employees.ts"() {
1800
+ "use strict";
1801
+ init_config();
1802
+ EMPLOYEES_PATH = path6.join(EXE_AI_DIR, "exe-employees.json");
1803
+ }
1804
+ });
1805
+
1806
+ // src/lib/license.ts
1807
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync2, existsSync as existsSync6, mkdirSync as mkdirSync3 } from "fs";
1808
+ import { randomUUID as randomUUID2 } from "crypto";
1809
+ import path7 from "path";
1810
+ import { jwtVerify, importSPKI } from "jose";
1811
+ var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH;
1812
+ var init_license = __esm({
1813
+ "src/lib/license.ts"() {
1814
+ "use strict";
1815
+ init_config();
1816
+ LICENSE_PATH = path7.join(EXE_AI_DIR, "license.key");
1817
+ CACHE_PATH = path7.join(EXE_AI_DIR, "license-cache.json");
1818
+ DEVICE_ID_PATH = path7.join(EXE_AI_DIR, "device-id");
1819
+ }
1820
+ });
1821
+
1822
+ // src/lib/plan-limits.ts
1823
+ import { readFileSync as readFileSync5, existsSync as existsSync7 } from "fs";
1824
+ import path8 from "path";
1825
+ var CACHE_PATH2;
1826
+ var init_plan_limits = __esm({
1827
+ "src/lib/plan-limits.ts"() {
1828
+ "use strict";
1829
+ init_database();
1830
+ init_employees();
1831
+ init_license();
1832
+ init_config();
1833
+ CACHE_PATH2 = path8.join(EXE_AI_DIR, "license-cache.json");
1834
+ }
1835
+ });
1836
+
1837
+ // src/lib/tmux-routing.ts
1838
+ import { readFileSync as readFileSync6, writeFileSync as writeFileSync3, mkdirSync as mkdirSync4, existsSync as existsSync8, appendFileSync } from "fs";
1839
+ import path9 from "path";
1840
+ import os5 from "os";
1841
+ import { fileURLToPath } from "url";
1842
+ function getMySession() {
1843
+ return getTransport().getMySession();
1844
+ }
1845
+ function extractRootExe(name) {
1846
+ const match = name.match(/(exe\d+)$/);
1847
+ return match?.[1] ?? null;
1848
+ }
1849
+ function getParentExe(sessionKey) {
1850
+ try {
1851
+ const data = JSON.parse(readFileSync6(path9.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
1852
+ return data.parentExe || null;
1853
+ } catch {
1854
+ return null;
1855
+ }
1856
+ }
1857
+ function resolveExeSession() {
1858
+ const mySession = getMySession();
1859
+ if (!mySession) return null;
1860
+ try {
1861
+ const key = getSessionKey();
1862
+ const parentExe = getParentExe(key);
1863
+ if (parentExe) {
1864
+ return extractRootExe(parentExe) ?? parentExe;
1865
+ }
1866
+ } catch {
1867
+ }
1868
+ return extractRootExe(mySession) ?? mySession;
1869
+ }
1870
+ var SPAWN_LOCK_DIR, SESSION_CACHE, INTERCOM_LOG2, DEBOUNCE_FILE, DEBOUNCE_CLEANUP_AGE_MS;
1871
+ var init_tmux_routing = __esm({
1872
+ "src/lib/tmux-routing.ts"() {
1873
+ "use strict";
1874
+ init_session_registry();
1875
+ init_session_key();
1876
+ init_transport();
1877
+ init_cc_agent_support();
1878
+ init_mcp_prefix();
1879
+ init_provider_table();
1880
+ init_intercom_queue();
1881
+ init_plan_limits();
1882
+ SPAWN_LOCK_DIR = path9.join(os5.homedir(), ".exe-os", "spawn-locks");
1883
+ SESSION_CACHE = path9.join(os5.homedir(), ".exe-os", "session-cache");
1884
+ INTERCOM_LOG2 = path9.join(os5.homedir(), ".exe-os", "intercom.log");
1885
+ DEBOUNCE_FILE = path9.join(SESSION_CACHE, "intercom-debounce.json");
1886
+ DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
1887
+ }
1888
+ });
1889
+
1890
+ // src/lib/task-scope.ts
1891
+ function getCurrentSessionScope() {
1892
+ try {
1893
+ return resolveExeSession();
1894
+ } catch {
1895
+ return null;
1896
+ }
1897
+ }
1898
+ function sessionScopeFilter(sessionScope, tableAlias) {
1899
+ const scope = sessionScope !== void 0 ? sessionScope : getCurrentSessionScope();
1900
+ if (!scope) return { sql: "", args: [] };
1901
+ const col = tableAlias ? `${tableAlias}.session_scope` : "session_scope";
1902
+ return {
1903
+ sql: ` AND (${col} IS NULL OR ${col} = ?)`,
1904
+ args: [scope]
1905
+ };
1906
+ }
1907
+ var init_task_scope = __esm({
1908
+ "src/lib/task-scope.ts"() {
1909
+ "use strict";
1910
+ init_tmux_routing();
1911
+ }
1912
+ });
1913
+
1517
1914
  // src/lib/store.ts
1518
1915
  init_database();
1519
1916
 
@@ -1563,57 +1960,7 @@ async function getMasterKey() {
1563
1960
 
1564
1961
  // src/lib/store.ts
1565
1962
  init_config();
1566
-
1567
- // src/lib/state-bus.ts
1568
- var StateBus = class {
1569
- handlers = /* @__PURE__ */ new Map();
1570
- globalHandlers = /* @__PURE__ */ new Set();
1571
- /** Emit an event to all subscribers */
1572
- emit(event) {
1573
- const typeHandlers = this.handlers.get(event.type);
1574
- if (typeHandlers) {
1575
- for (const handler of typeHandlers) {
1576
- try {
1577
- handler(event);
1578
- } catch {
1579
- }
1580
- }
1581
- }
1582
- for (const handler of this.globalHandlers) {
1583
- try {
1584
- handler(event);
1585
- } catch {
1586
- }
1587
- }
1588
- }
1589
- /** Subscribe to a specific event type */
1590
- on(type, handler) {
1591
- if (!this.handlers.has(type)) {
1592
- this.handlers.set(type, /* @__PURE__ */ new Set());
1593
- }
1594
- this.handlers.get(type).add(handler);
1595
- }
1596
- /** Subscribe to ALL events */
1597
- onAny(handler) {
1598
- this.globalHandlers.add(handler);
1599
- }
1600
- /** Unsubscribe from a specific event type */
1601
- off(type, handler) {
1602
- this.handlers.get(type)?.delete(handler);
1603
- }
1604
- /** Unsubscribe from ALL events */
1605
- offAny(handler) {
1606
- this.globalHandlers.delete(handler);
1607
- }
1608
- /** Remove all listeners */
1609
- clear() {
1610
- this.handlers.clear();
1611
- this.globalHandlers.clear();
1612
- }
1613
- };
1614
- var orgBus = new StateBus();
1615
-
1616
- // src/lib/store.ts
1963
+ init_state_bus();
1617
1964
  var INIT_MAX_RETRIES = 3;
1618
1965
  var INIT_RETRY_DELAY_MS = 1e3;
1619
1966
  function isBusyError2(err) {
@@ -1693,15 +2040,16 @@ async function initStore(options) {
1693
2040
 
1694
2041
  // src/bin/cleanup-stale-review-tasks.ts
1695
2042
  init_database();
2043
+ init_task_scope();
1696
2044
 
1697
2045
  // src/lib/is-main.ts
1698
2046
  import { realpathSync } from "fs";
1699
- import { fileURLToPath } from "url";
2047
+ import { fileURLToPath as fileURLToPath2 } from "url";
1700
2048
  function isMainModule(importMetaUrl) {
1701
2049
  if (process.argv[1] == null) return false;
1702
2050
  try {
1703
2051
  const scriptPath = realpathSync(process.argv[1]);
1704
- const modulePath = realpathSync(fileURLToPath(importMetaUrl));
2052
+ const modulePath = realpathSync(fileURLToPath2(importMetaUrl));
1705
2053
  return scriptPath === modulePath;
1706
2054
  } catch {
1707
2055
  return importMetaUrl === `file://${process.argv[1]}` || importMetaUrl === new URL(process.argv[1], "file://").href;
@@ -1722,15 +2070,16 @@ async function findZombies(beforeIso, assignedTo) {
1722
2070
  assigneeClause = "AND assigned_to = ?";
1723
2071
  args.push(assignedTo);
1724
2072
  }
2073
+ const csScope = sessionScopeFilter();
1725
2074
  const result = await client.execute({
1726
2075
  sql: `SELECT id, assigned_to, title, created_at
1727
2076
  FROM tasks
1728
2077
  WHERE status IN ('open', 'in_progress')
1729
2078
  AND title LIKE 'Review:%'
1730
2079
  ${beforeClause}
1731
- ${assigneeClause}
2080
+ ${assigneeClause}${csScope.sql}
1732
2081
  ORDER BY created_at ASC`,
1733
- args
2082
+ args: [...args, ...csScope.args]
1734
2083
  });
1735
2084
  return result.rows.map((r) => ({
1736
2085
  id: String(r.id),
@@ -1741,12 +2090,13 @@ async function findZombies(beforeIso, assignedTo) {
1741
2090
  }
1742
2091
  async function statsByAssignee() {
1743
2092
  const client = getClient();
2093
+ const sbScope = sessionScopeFilter();
1744
2094
  const r = await client.execute({
1745
2095
  sql: `SELECT assigned_to, COUNT(*) as n, MIN(created_at) as oldest, MAX(created_at) as newest
1746
2096
  FROM tasks
1747
- WHERE status IN ('open','in_progress') AND title LIKE 'Review:%'
2097
+ WHERE status IN ('open','in_progress') AND title LIKE 'Review:%'${sbScope.sql}
1748
2098
  GROUP BY assigned_to ORDER BY n DESC`,
1749
- args: []
2099
+ args: [...sbScope.args]
1750
2100
  });
1751
2101
  console.log("Stats by assignee:");
1752
2102
  for (const row of r.rows) {