@askexenow/exe-os 0.9.85 → 0.9.87

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 (86) hide show
  1. package/dist/bin/agentic-ontology-backfill.js +50 -14
  2. package/dist/bin/agentic-reflection-backfill.js +50 -14
  3. package/dist/bin/agentic-semantic-label.js +50 -14
  4. package/dist/bin/backfill-conversations.js +50 -14
  5. package/dist/bin/backfill-responses.js +50 -14
  6. package/dist/bin/backfill-vectors.js +50 -14
  7. package/dist/bin/bulk-sync-postgres.js +50 -14
  8. package/dist/bin/cleanup-stale-review-tasks.js +53 -17
  9. package/dist/bin/cli.js +339 -81
  10. package/dist/bin/exe-agent.js +18 -0
  11. package/dist/bin/exe-assign.js +50 -14
  12. package/dist/bin/exe-boot.js +75 -39
  13. package/dist/bin/exe-call.js +18 -0
  14. package/dist/bin/exe-cloud.js +40 -4
  15. package/dist/bin/exe-dispatch.js +61 -25
  16. package/dist/bin/exe-doctor.js +40 -4
  17. package/dist/bin/exe-export-behaviors.js +50 -14
  18. package/dist/bin/exe-forget.js +50 -14
  19. package/dist/bin/exe-gateway.js +65 -29
  20. package/dist/bin/exe-heartbeat.js +55 -19
  21. package/dist/bin/exe-kill.js +54 -18
  22. package/dist/bin/exe-launch-agent.js +58 -22
  23. package/dist/bin/exe-new-employee.js +33 -2
  24. package/dist/bin/exe-pending-messages.js +53 -17
  25. package/dist/bin/exe-pending-notifications.js +53 -17
  26. package/dist/bin/exe-pending-reviews.js +55 -19
  27. package/dist/bin/exe-rename.js +52 -16
  28. package/dist/bin/exe-review.js +50 -14
  29. package/dist/bin/exe-search.js +58 -22
  30. package/dist/bin/exe-session-cleanup.js +85 -44
  31. package/dist/bin/exe-start-codex.js +57 -21
  32. package/dist/bin/exe-start-opencode.js +55 -19
  33. package/dist/bin/exe-status.js +62 -26
  34. package/dist/bin/exe-team.js +50 -14
  35. package/dist/bin/git-sweep.js +63 -27
  36. package/dist/bin/graph-backfill.js +50 -14
  37. package/dist/bin/graph-export.js +50 -14
  38. package/dist/bin/install.js +9 -0
  39. package/dist/bin/intercom-check.js +67 -31
  40. package/dist/bin/scan-tasks.js +63 -27
  41. package/dist/bin/setup.js +53 -13
  42. package/dist/bin/shard-migrate.js +50 -14
  43. package/dist/bin/stack-update.js +59 -2
  44. package/dist/bin/update.js +1 -1
  45. package/dist/gateway/index.js +65 -29
  46. package/dist/hooks/bug-report-worker.js +65 -29
  47. package/dist/hooks/codex-stop-task-finalizer.js +59 -23
  48. package/dist/hooks/commit-complete.js +64 -28
  49. package/dist/hooks/error-recall.js +62 -26
  50. package/dist/hooks/ingest-worker.js +4 -4
  51. package/dist/hooks/ingest.js +56 -20
  52. package/dist/hooks/instructions-loaded.js +50 -14
  53. package/dist/hooks/notification.js +50 -14
  54. package/dist/hooks/post-compact.js +50 -14
  55. package/dist/hooks/post-tool-combined.js +63 -27
  56. package/dist/hooks/pre-compact.js +61 -25
  57. package/dist/hooks/pre-tool-use.js +58 -22
  58. package/dist/hooks/prompt-submit.js +78 -42
  59. package/dist/hooks/session-end.js +66 -30
  60. package/dist/hooks/session-start.js +68 -32
  61. package/dist/hooks/stop.js +53 -17
  62. package/dist/hooks/subagent-stop.js +50 -14
  63. package/dist/hooks/summary-worker.js +55 -19
  64. package/dist/index.js +61 -25
  65. package/dist/lib/cloud-sync.js +32 -14
  66. package/dist/lib/database.js +22 -4
  67. package/dist/lib/db-daemon-client.js +16 -4
  68. package/dist/lib/db.js +22 -4
  69. package/dist/lib/device-registry.js +22 -4
  70. package/dist/lib/embedder.js +16 -4
  71. package/dist/lib/employee-templates.js +18 -0
  72. package/dist/lib/exe-daemon-client.js +16 -4
  73. package/dist/lib/exe-daemon.js +874 -232
  74. package/dist/lib/hybrid-search.js +58 -22
  75. package/dist/lib/identity-templates.js +6 -2
  76. package/dist/lib/schedules.js +53 -17
  77. package/dist/lib/skill-learning.js +16 -4
  78. package/dist/lib/store.js +50 -14
  79. package/dist/lib/tasks.js +16 -4
  80. package/dist/lib/tmux-routing.js +18 -6
  81. package/dist/mcp/server.js +809 -200
  82. package/dist/mcp/tools/create-task.js +24 -8
  83. package/dist/mcp/tools/update-task.js +18 -6
  84. package/dist/runtime/index.js +61 -25
  85. package/dist/tui/App.js +91 -55
  86. package/package.json +1 -1
@@ -1531,7 +1531,7 @@ __export(exe_daemon_client_exports, {
1531
1531
  });
1532
1532
  import net from "net";
1533
1533
  import os5 from "os";
1534
- import { spawn } from "child_process";
1534
+ import { spawn, execSync as execSync3 } from "child_process";
1535
1535
  import { randomUUID } from "crypto";
1536
1536
  import { existsSync as existsSync6, unlinkSync as unlinkSync2, readFileSync as readFileSync4, openSync, closeSync, statSync as statSync2 } from "fs";
1537
1537
  import path6 from "path";
@@ -1561,6 +1561,14 @@ function handleData(chunk) {
1561
1561
  }
1562
1562
  }
1563
1563
  }
1564
+ function isZombie(pid) {
1565
+ try {
1566
+ const state = execSync3(`ps -p ${pid} -o state=`, { encoding: "utf8", timeout: 2e3 }).trim();
1567
+ return state.startsWith("Z");
1568
+ } catch {
1569
+ return false;
1570
+ }
1571
+ }
1564
1572
  function cleanupStaleFiles() {
1565
1573
  if (existsSync6(PID_PATH)) {
1566
1574
  try {
@@ -1568,7 +1576,11 @@ function cleanupStaleFiles() {
1568
1576
  if (pid > 0) {
1569
1577
  try {
1570
1578
  process.kill(pid, 0);
1571
- return;
1579
+ if (!isZombie(pid)) {
1580
+ return;
1581
+ }
1582
+ process.stderr.write(`[exed-client] PID ${pid} is a zombie \u2014 cleaning up stale files
1583
+ `);
1572
1584
  } catch {
1573
1585
  }
1574
1586
  }
@@ -1596,8 +1608,8 @@ function findPackageRoot() {
1596
1608
  function getAvailableMemoryGB() {
1597
1609
  if (process.platform === "darwin") {
1598
1610
  try {
1599
- const { execSync: execSync3 } = __require("child_process");
1600
- const vmstat = execSync3("vm_stat", { encoding: "utf8" });
1611
+ const { execSync: execSync4 } = __require("child_process");
1612
+ const vmstat = execSync4("vm_stat", { encoding: "utf8" });
1601
1613
  const pageSize = 16384;
1602
1614
  const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
1603
1615
  const actualPageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : pageSize;
@@ -3552,6 +3564,12 @@ async function disposeDatabase() {
3552
3564
  clearInterval(_walCheckpointTimer);
3553
3565
  _walCheckpointTimer = null;
3554
3566
  }
3567
+ if (_client) {
3568
+ try {
3569
+ await _client.execute("PRAGMA wal_checkpoint(PASSIVE)");
3570
+ } catch {
3571
+ }
3572
+ }
3555
3573
  if (_daemonClient) {
3556
3574
  _daemonClient.close();
3557
3575
  _daemonClient = null;
@@ -6520,6 +6538,24 @@ var init_platform_procedures = __esm({
6520
6538
  priority: "p0",
6521
6539
  content: "When an agent encounters a suspected Exe OS bug, update breakage, MCP/tool failure, installer issue, memory/orchestration defect, or customer-local patch need, it MUST use create_bug_report. Do this before or alongside any local workaround so the report reaches AskExe support directly via the customer's license. Do NOT ask the founder for permission to file a required bug report. If create_bug_report is deferred/lazy-loaded, load it and call it. If it is unavailable in the live MCP surface, report 'create_bug_report unavailable in this session' and save a local report in exe/output \u2014 never claim the tool does not exist unless the live MCP surface was checked. If upstream delivery fails, call support_test (MCP) and include its result in the local report so AskExe can distinguish customer setup, license provisioning, and server intake issues; only ask the founder to run `exe-os support test` if MCP is disconnected/unavailable. Classify first: upstream_bug = reproducible exe-os/platform defect; customer_customization = identity, behavior, procedure, config, branding, workflow preference that belongs in customer-owned layers; emergency_hotfix = temporary local patch. For upstream bugs/emergency hotfixes include version, repro steps, expected/actual, files changed, workaround, and local diff summary. Avoid permanent platform-code patches unless founder approves; if a hotfix is unavoidable, document it in the bug report and re-check after npm update."
6522
6540
  },
6541
+ {
6542
+ title: "Bug report status check \u2014 surface available fixes on boot",
6543
+ domain: "support",
6544
+ priority: "p1",
6545
+ content: "Once per session (COO boot only, never repeat), call list_my_bug_reports to check if any previously filed bug reports have been fixed by AskExe. If any report has status 'fixed' with a fixed_version, surface it to the founder immediately: '\u{1F527} N bug fix(es) available \u2014 run exe-os update to get version X.Y.Z'. This is a one-time check at boot, not a recurring poll. If no reports exist or none are fixed, skip silently. If the MCP tool is unavailable or the network call fails, skip silently \u2014 this is informational, not blocking."
6546
+ },
6547
+ {
6548
+ title: "Feature request triage \u2014 upstream feature vs local customization",
6549
+ domain: "support",
6550
+ priority: "p0",
6551
+ content: "When an agent or founder identifies a desired capability that exe-os does not yet provide, the COO (or equivalent coordinator) must decide: is this a local customization (identity, behavior, procedure, config, branding, workflow preference that can be configured in customer-owned layers) or an upstream feature request (a platform capability that requires changes to exe-os code, shipped via npm update)? Local customizations: implement immediately using store_behavior, update_identity, company_procedure, or config changes. Upstream features: use create_feature_request to submit to AskExe. Include use case, business impact, and current workaround. Do NOT ask the founder for permission to file a feature request \u2014 file it proactively when the need is clear."
6552
+ },
6553
+ {
6554
+ title: "Feature request status check \u2014 surface shipped features on boot",
6555
+ domain: "support",
6556
+ priority: "p1",
6557
+ content: "Once per session (COO boot only, never repeat), call list_my_feature_requests to check if any previously filed feature requests have been shipped by AskExe. If any request has status 'shipped' with a shipped_version, surface it to the founder immediately: '\u{1F680} N feature(s) shipped \u2014 run exe-os update to get version X.Y.Z'. This is a one-time check at boot, not a recurring poll. If no requests exist or none are shipped, skip silently. If the MCP tool is unavailable or the network call fails, skip silently \u2014 this is informational, not blocking."
6558
+ },
6523
6559
  // --- Operations ---
6524
6560
  {
6525
6561
  title: "Managers must supervise deployed workers",
@@ -1581,7 +1581,7 @@ __export(exe_daemon_client_exports, {
1581
1581
  });
1582
1582
  import net from "net";
1583
1583
  import os6 from "os";
1584
- import { spawn } from "child_process";
1584
+ import { spawn, execSync as execSync4 } from "child_process";
1585
1585
  import { randomUUID } from "crypto";
1586
1586
  import { existsSync as existsSync8, unlinkSync as unlinkSync2, readFileSync as readFileSync7, openSync, closeSync, statSync } from "fs";
1587
1587
  import path8 from "path";
@@ -1611,6 +1611,14 @@ function handleData(chunk) {
1611
1611
  }
1612
1612
  }
1613
1613
  }
1614
+ function isZombie(pid) {
1615
+ try {
1616
+ const state = execSync4(`ps -p ${pid} -o state=`, { encoding: "utf8", timeout: 2e3 }).trim();
1617
+ return state.startsWith("Z");
1618
+ } catch {
1619
+ return false;
1620
+ }
1621
+ }
1614
1622
  function cleanupStaleFiles() {
1615
1623
  if (existsSync8(PID_PATH)) {
1616
1624
  try {
@@ -1618,7 +1626,11 @@ function cleanupStaleFiles() {
1618
1626
  if (pid > 0) {
1619
1627
  try {
1620
1628
  process.kill(pid, 0);
1621
- return;
1629
+ if (!isZombie(pid)) {
1630
+ return;
1631
+ }
1632
+ process.stderr.write(`[exed-client] PID ${pid} is a zombie \u2014 cleaning up stale files
1633
+ `);
1622
1634
  } catch {
1623
1635
  }
1624
1636
  }
@@ -1646,8 +1658,8 @@ function findPackageRoot() {
1646
1658
  function getAvailableMemoryGB() {
1647
1659
  if (process.platform === "darwin") {
1648
1660
  try {
1649
- const { execSync: execSync8 } = __require("child_process");
1650
- const vmstat = execSync8("vm_stat", { encoding: "utf8" });
1661
+ const { execSync: execSync9 } = __require("child_process");
1662
+ const vmstat = execSync9("vm_stat", { encoding: "utf8" });
1651
1663
  const pageSize = 16384;
1652
1664
  const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
1653
1665
  const actualPageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : pageSize;
@@ -3637,6 +3649,12 @@ async function disposeDatabase() {
3637
3649
  clearInterval(_walCheckpointTimer);
3638
3650
  _walCheckpointTimer = null;
3639
3651
  }
3652
+ if (_client) {
3653
+ try {
3654
+ await _client.execute("PRAGMA wal_checkpoint(PASSIVE)");
3655
+ } catch {
3656
+ }
3657
+ }
3640
3658
  if (_daemonClient) {
3641
3659
  _daemonClient.close();
3642
3660
  _daemonClient = null;
@@ -4018,7 +4036,7 @@ var init_state_bus = __esm({
4018
4036
  });
4019
4037
 
4020
4038
  // src/lib/project-name.ts
4021
- import { execSync as execSync4 } from "child_process";
4039
+ import { execSync as execSync5 } from "child_process";
4022
4040
  import path13 from "path";
4023
4041
  function getProjectName(cwd) {
4024
4042
  const dir = cwd ?? process.cwd();
@@ -4026,7 +4044,7 @@ function getProjectName(cwd) {
4026
4044
  try {
4027
4045
  let repoRoot;
4028
4046
  try {
4029
- const gitCommonDir = execSync4("git rev-parse --path-format=absolute --git-common-dir", {
4047
+ const gitCommonDir = execSync5("git rev-parse --path-format=absolute --git-common-dir", {
4030
4048
  cwd: dir,
4031
4049
  encoding: "utf8",
4032
4050
  timeout: 2e3,
@@ -4034,7 +4052,7 @@ function getProjectName(cwd) {
4034
4052
  }).trim();
4035
4053
  repoRoot = path13.dirname(gitCommonDir);
4036
4054
  } catch {
4037
- repoRoot = execSync4("git rev-parse --show-toplevel", {
4055
+ repoRoot = execSync5("git rev-parse --show-toplevel", {
4038
4056
  cwd: dir,
4039
4057
  encoding: "utf8",
4040
4058
  timeout: 2e3,
@@ -4125,7 +4143,7 @@ var init_session_scope = __esm({
4125
4143
  import crypto4 from "crypto";
4126
4144
  import path14 from "path";
4127
4145
  import os10 from "os";
4128
- import { execSync as execSync5 } from "child_process";
4146
+ import { execSync as execSync6 } from "child_process";
4129
4147
  import { mkdir as mkdir3, writeFile as writeFile3, appendFile } from "fs/promises";
4130
4148
  import { existsSync as existsSync13, readFileSync as readFileSync11 } from "fs";
4131
4149
  async function writeCheckpoint(input) {
@@ -4470,14 +4488,14 @@ function isTmuxSessionAlive(identifier) {
4470
4488
  if (!identifier || identifier === "unknown") return true;
4471
4489
  try {
4472
4490
  if (identifier.startsWith("%")) {
4473
- const output = execSync5("tmux list-panes -a -F '#{pane_id}'", {
4491
+ const output = execSync6("tmux list-panes -a -F '#{pane_id}'", {
4474
4492
  timeout: 2e3,
4475
4493
  encoding: "utf8",
4476
4494
  stdio: ["pipe", "pipe", "pipe"]
4477
4495
  });
4478
4496
  return output.split("\n").some((l) => l.trim() === identifier);
4479
4497
  } else {
4480
- execSync5(`tmux has-session -t ${JSON.stringify(identifier)}`, {
4498
+ execSync6(`tmux has-session -t ${JSON.stringify(identifier)}`, {
4481
4499
  timeout: 2e3,
4482
4500
  stdio: ["pipe", "pipe", "pipe"]
4483
4501
  });
@@ -4486,7 +4504,7 @@ function isTmuxSessionAlive(identifier) {
4486
4504
  } catch {
4487
4505
  if (identifier.startsWith("%")) return true;
4488
4506
  try {
4489
- execSync5("tmux list-sessions", {
4507
+ execSync6("tmux list-sessions", {
4490
4508
  timeout: 2e3,
4491
4509
  stdio: ["pipe", "pipe", "pipe"]
4492
4510
  });
@@ -4501,12 +4519,12 @@ function checkStaleCompletion(taskContext, taskCreatedAt) {
4501
4519
  if (!DELEGATION_KEYWORDS.test(taskContext)) return null;
4502
4520
  try {
4503
4521
  const since = new Date(taskCreatedAt).toISOString();
4504
- const branch = execSync5(
4522
+ const branch = execSync6(
4505
4523
  "git rev-parse --abbrev-ref HEAD 2>/dev/null",
4506
4524
  { encoding: "utf8", timeout: 3e3 }
4507
4525
  ).trim();
4508
4526
  const branchArg = branch && branch !== "HEAD" ? branch : "";
4509
- const commitCount = execSync5(
4527
+ const commitCount = execSync6(
4510
4528
  `git log --oneline --since="${since}" ${branchArg} 2>/dev/null | wc -l`,
4511
4529
  { encoding: "utf8", timeout: 5e3 }
4512
4530
  ).trim();
@@ -6105,7 +6123,7 @@ __export(tmux_routing_exports, {
6105
6123
  spawnEmployee: () => spawnEmployee,
6106
6124
  verifyPaneAtCapacity: () => verifyPaneAtCapacity
6107
6125
  });
6108
- import { execFileSync as execFileSync2, execSync as execSync6 } from "child_process";
6126
+ import { execFileSync as execFileSync2, execSync as execSync7 } from "child_process";
6109
6127
  import { readFileSync as readFileSync12, writeFileSync as writeFileSync8, mkdirSync as mkdirSync7, existsSync as existsSync15, appendFileSync, readdirSync as readdirSync3 } from "fs";
6110
6128
  import path18 from "path";
6111
6129
  import os11 from "os";
@@ -6826,7 +6844,7 @@ function spawnEmployee(employeeName2, exeSession2, projectDir2, opts) {
6826
6844
  let booted = false;
6827
6845
  for (let i = 0; i < 30; i++) {
6828
6846
  try {
6829
- execSync6("sleep 0.5");
6847
+ execSync7("sleep 0.5");
6830
6848
  } catch {
6831
6849
  }
6832
6850
  try {
@@ -6905,7 +6923,7 @@ var init_tmux_routing = __esm({
6905
6923
  // src/lib/keychain.ts
6906
6924
  import { readFile as readFile4, writeFile as writeFile5, unlink, mkdir as mkdir4, chmod as chmod2 } from "fs/promises";
6907
6925
  import { existsSync as existsSync16, statSync as statSync2 } from "fs";
6908
- import { execSync as execSync7 } from "child_process";
6926
+ import { execSync as execSync8 } from "child_process";
6909
6927
  import path19 from "path";
6910
6928
  import os12 from "os";
6911
6929
  function getKeyDir() {
@@ -6922,13 +6940,13 @@ function linuxSecretAvailable() {
6922
6940
  if (process.platform !== "linux") return false;
6923
6941
  if (linuxSecretAvailability !== null) return linuxSecretAvailability;
6924
6942
  try {
6925
- execSync7("command -v secret-tool >/dev/null 2>&1", { timeout: 1e3 });
6943
+ execSync8("command -v secret-tool >/dev/null 2>&1", { timeout: 1e3 });
6926
6944
  } catch {
6927
6945
  linuxSecretAvailability = false;
6928
6946
  return false;
6929
6947
  }
6930
6948
  try {
6931
- execSync7("secret-tool search --all exe-os probe >/dev/null 2>&1", { timeout: 1e3 });
6949
+ execSync8("secret-tool search --all exe-os probe >/dev/null 2>&1", { timeout: 1e3 });
6932
6950
  linuxSecretAvailability = true;
6933
6951
  } catch {
6934
6952
  linuxSecretAvailability = false;
@@ -6952,7 +6970,7 @@ function macKeychainGet(service = SERVICE) {
6952
6970
  if (!nativeKeychainAllowed()) return null;
6953
6971
  if (process.platform !== "darwin") return null;
6954
6972
  try {
6955
- return execSync7(
6973
+ return execSync8(
6956
6974
  `security find-generic-password -s "${service}" -a "${ACCOUNT}" -w 2>/dev/null`,
6957
6975
  { encoding: "utf-8", timeout: 5e3 }
6958
6976
  ).trim();
@@ -6965,13 +6983,13 @@ function macKeychainSet(value, service = SERVICE) {
6965
6983
  if (process.platform !== "darwin") return false;
6966
6984
  try {
6967
6985
  try {
6968
- execSync7(
6986
+ execSync8(
6969
6987
  `security delete-generic-password -s "${service}" -a "${ACCOUNT}" 2>/dev/null`,
6970
6988
  { timeout: 5e3 }
6971
6989
  );
6972
6990
  } catch {
6973
6991
  }
6974
- execSync7(
6992
+ execSync8(
6975
6993
  `security add-generic-password -s "${service}" -a "${ACCOUNT}" -w "${value}"`,
6976
6994
  { timeout: 5e3 }
6977
6995
  );
@@ -6984,7 +7002,7 @@ function macKeychainDelete(service = SERVICE) {
6984
7002
  if (!nativeKeychainAllowed()) return false;
6985
7003
  if (process.platform !== "darwin") return false;
6986
7004
  try {
6987
- execSync7(
7005
+ execSync8(
6988
7006
  `security delete-generic-password -s "${service}" -a "${ACCOUNT}" 2>/dev/null`,
6989
7007
  { timeout: 5e3 }
6990
7008
  );
@@ -6996,7 +7014,7 @@ function macKeychainDelete(service = SERVICE) {
6996
7014
  function linuxSecretGet(service = SERVICE) {
6997
7015
  if (!linuxSecretAvailable()) return null;
6998
7016
  try {
6999
- return execSync7(
7017
+ return execSync8(
7000
7018
  `secret-tool lookup service "${service}" account "${ACCOUNT}" 2>/dev/null`,
7001
7019
  { encoding: "utf-8", timeout: 5e3 }
7002
7020
  ).trim();
@@ -7007,7 +7025,7 @@ function linuxSecretGet(service = SERVICE) {
7007
7025
  function linuxSecretSet(value, service = SERVICE) {
7008
7026
  if (!linuxSecretAvailable()) return false;
7009
7027
  try {
7010
- execSync7(
7028
+ execSync8(
7011
7029
  `echo -n "${value}" | secret-tool store --label="exe-os master key" service "${service}" account "${ACCOUNT}" 2>/dev/null`,
7012
7030
  { timeout: 5e3 }
7013
7031
  );
@@ -7020,7 +7038,7 @@ function linuxSecretDelete(service = SERVICE) {
7020
7038
  if (!nativeKeychainAllowed()) return false;
7021
7039
  if (process.platform !== "linux") return false;
7022
7040
  try {
7023
- execSync7(
7041
+ execSync8(
7024
7042
  `secret-tool clear service "${service}" account "${ACCOUNT}" 2>/dev/null`,
7025
7043
  { timeout: 5e3 }
7026
7044
  );
@@ -7902,6 +7920,24 @@ var init_platform_procedures = __esm({
7902
7920
  priority: "p0",
7903
7921
  content: "When an agent encounters a suspected Exe OS bug, update breakage, MCP/tool failure, installer issue, memory/orchestration defect, or customer-local patch need, it MUST use create_bug_report. Do this before or alongside any local workaround so the report reaches AskExe support directly via the customer's license. Do NOT ask the founder for permission to file a required bug report. If create_bug_report is deferred/lazy-loaded, load it and call it. If it is unavailable in the live MCP surface, report 'create_bug_report unavailable in this session' and save a local report in exe/output \u2014 never claim the tool does not exist unless the live MCP surface was checked. If upstream delivery fails, call support_test (MCP) and include its result in the local report so AskExe can distinguish customer setup, license provisioning, and server intake issues; only ask the founder to run `exe-os support test` if MCP is disconnected/unavailable. Classify first: upstream_bug = reproducible exe-os/platform defect; customer_customization = identity, behavior, procedure, config, branding, workflow preference that belongs in customer-owned layers; emergency_hotfix = temporary local patch. For upstream bugs/emergency hotfixes include version, repro steps, expected/actual, files changed, workaround, and local diff summary. Avoid permanent platform-code patches unless founder approves; if a hotfix is unavoidable, document it in the bug report and re-check after npm update."
7904
7922
  },
7923
+ {
7924
+ title: "Bug report status check \u2014 surface available fixes on boot",
7925
+ domain: "support",
7926
+ priority: "p1",
7927
+ content: "Once per session (COO boot only, never repeat), call list_my_bug_reports to check if any previously filed bug reports have been fixed by AskExe. If any report has status 'fixed' with a fixed_version, surface it to the founder immediately: '\u{1F527} N bug fix(es) available \u2014 run exe-os update to get version X.Y.Z'. This is a one-time check at boot, not a recurring poll. If no reports exist or none are fixed, skip silently. If the MCP tool is unavailable or the network call fails, skip silently \u2014 this is informational, not blocking."
7928
+ },
7929
+ {
7930
+ title: "Feature request triage \u2014 upstream feature vs local customization",
7931
+ domain: "support",
7932
+ priority: "p0",
7933
+ content: "When an agent or founder identifies a desired capability that exe-os does not yet provide, the COO (or equivalent coordinator) must decide: is this a local customization (identity, behavior, procedure, config, branding, workflow preference that can be configured in customer-owned layers) or an upstream feature request (a platform capability that requires changes to exe-os code, shipped via npm update)? Local customizations: implement immediately using store_behavior, update_identity, company_procedure, or config changes. Upstream features: use create_feature_request to submit to AskExe. Include use case, business impact, and current workaround. Do NOT ask the founder for permission to file a feature request \u2014 file it proactively when the need is clear."
7934
+ },
7935
+ {
7936
+ title: "Feature request status check \u2014 surface shipped features on boot",
7937
+ domain: "support",
7938
+ priority: "p1",
7939
+ content: "Once per session (COO boot only, never repeat), call list_my_feature_requests to check if any previously filed feature requests have been shipped by AskExe. If any request has status 'shipped' with a shipped_version, surface it to the founder immediately: '\u{1F680} N feature(s) shipped \u2014 run exe-os update to get version X.Y.Z'. This is a one-time check at boot, not a recurring poll. If no requests exist or none are shipped, skip silently. If the MCP tool is unavailable or the network call fails, skip silently \u2014 this is informational, not blocking."
7940
+ },
7905
7941
  // --- Operations ---
7906
7942
  {
7907
7943
  title: "Managers must supervise deployed workers",
@@ -2035,7 +2035,7 @@ __export(exe_daemon_client_exports, {
2035
2035
  });
2036
2036
  import net from "net";
2037
2037
  import os5 from "os";
2038
- import { spawn } from "child_process";
2038
+ import { spawn, execSync as execSync3 } from "child_process";
2039
2039
  import { randomUUID } from "crypto";
2040
2040
  import { existsSync as existsSync9, unlinkSync as unlinkSync3, readFileSync as readFileSync5, openSync, closeSync, statSync as statSync3 } from "fs";
2041
2041
  import path9 from "path";
@@ -2065,6 +2065,14 @@ function handleData(chunk) {
2065
2065
  }
2066
2066
  }
2067
2067
  }
2068
+ function isZombie(pid) {
2069
+ try {
2070
+ const state = execSync3(`ps -p ${pid} -o state=`, { encoding: "utf8", timeout: 2e3 }).trim();
2071
+ return state.startsWith("Z");
2072
+ } catch {
2073
+ return false;
2074
+ }
2075
+ }
2068
2076
  function cleanupStaleFiles() {
2069
2077
  if (existsSync9(PID_PATH)) {
2070
2078
  try {
@@ -2072,7 +2080,11 @@ function cleanupStaleFiles() {
2072
2080
  if (pid > 0) {
2073
2081
  try {
2074
2082
  process.kill(pid, 0);
2075
- return;
2083
+ if (!isZombie(pid)) {
2084
+ return;
2085
+ }
2086
+ process.stderr.write(`[exed-client] PID ${pid} is a zombie \u2014 cleaning up stale files
2087
+ `);
2076
2088
  } catch {
2077
2089
  }
2078
2090
  }
@@ -2100,8 +2112,8 @@ function findPackageRoot() {
2100
2112
  function getAvailableMemoryGB() {
2101
2113
  if (process.platform === "darwin") {
2102
2114
  try {
2103
- const { execSync: execSync3 } = __require("child_process");
2104
- const vmstat = execSync3("vm_stat", { encoding: "utf8" });
2115
+ const { execSync: execSync4 } = __require("child_process");
2116
+ const vmstat = execSync4("vm_stat", { encoding: "utf8" });
2105
2117
  const pageSize = 16384;
2106
2118
  const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
2107
2119
  const actualPageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : pageSize;
@@ -4091,6 +4103,12 @@ async function disposeDatabase() {
4091
4103
  clearInterval(_walCheckpointTimer);
4092
4104
  _walCheckpointTimer = null;
4093
4105
  }
4106
+ if (_client) {
4107
+ try {
4108
+ await _client.execute("PRAGMA wal_checkpoint(PASSIVE)");
4109
+ } catch {
4110
+ }
4111
+ }
4094
4112
  if (_daemonClient) {
4095
4113
  _daemonClient.close();
4096
4114
  _daemonClient = null;
@@ -4456,6 +4474,24 @@ var init_platform_procedures = __esm({
4456
4474
  priority: "p0",
4457
4475
  content: "When an agent encounters a suspected Exe OS bug, update breakage, MCP/tool failure, installer issue, memory/orchestration defect, or customer-local patch need, it MUST use create_bug_report. Do this before or alongside any local workaround so the report reaches AskExe support directly via the customer's license. Do NOT ask the founder for permission to file a required bug report. If create_bug_report is deferred/lazy-loaded, load it and call it. If it is unavailable in the live MCP surface, report 'create_bug_report unavailable in this session' and save a local report in exe/output \u2014 never claim the tool does not exist unless the live MCP surface was checked. If upstream delivery fails, call support_test (MCP) and include its result in the local report so AskExe can distinguish customer setup, license provisioning, and server intake issues; only ask the founder to run `exe-os support test` if MCP is disconnected/unavailable. Classify first: upstream_bug = reproducible exe-os/platform defect; customer_customization = identity, behavior, procedure, config, branding, workflow preference that belongs in customer-owned layers; emergency_hotfix = temporary local patch. For upstream bugs/emergency hotfixes include version, repro steps, expected/actual, files changed, workaround, and local diff summary. Avoid permanent platform-code patches unless founder approves; if a hotfix is unavoidable, document it in the bug report and re-check after npm update."
4458
4476
  },
4477
+ {
4478
+ title: "Bug report status check \u2014 surface available fixes on boot",
4479
+ domain: "support",
4480
+ priority: "p1",
4481
+ content: "Once per session (COO boot only, never repeat), call list_my_bug_reports to check if any previously filed bug reports have been fixed by AskExe. If any report has status 'fixed' with a fixed_version, surface it to the founder immediately: '\u{1F527} N bug fix(es) available \u2014 run exe-os update to get version X.Y.Z'. This is a one-time check at boot, not a recurring poll. If no reports exist or none are fixed, skip silently. If the MCP tool is unavailable or the network call fails, skip silently \u2014 this is informational, not blocking."
4482
+ },
4483
+ {
4484
+ title: "Feature request triage \u2014 upstream feature vs local customization",
4485
+ domain: "support",
4486
+ priority: "p0",
4487
+ content: "When an agent or founder identifies a desired capability that exe-os does not yet provide, the COO (or equivalent coordinator) must decide: is this a local customization (identity, behavior, procedure, config, branding, workflow preference that can be configured in customer-owned layers) or an upstream feature request (a platform capability that requires changes to exe-os code, shipped via npm update)? Local customizations: implement immediately using store_behavior, update_identity, company_procedure, or config changes. Upstream features: use create_feature_request to submit to AskExe. Include use case, business impact, and current workaround. Do NOT ask the founder for permission to file a feature request \u2014 file it proactively when the need is clear."
4488
+ },
4489
+ {
4490
+ title: "Feature request status check \u2014 surface shipped features on boot",
4491
+ domain: "support",
4492
+ priority: "p1",
4493
+ content: "Once per session (COO boot only, never repeat), call list_my_feature_requests to check if any previously filed feature requests have been shipped by AskExe. If any request has status 'shipped' with a shipped_version, surface it to the founder immediately: '\u{1F680} N feature(s) shipped \u2014 run exe-os update to get version X.Y.Z'. This is a one-time check at boot, not a recurring poll. If no requests exist or none are shipped, skip silently. If the MCP tool is unavailable or the network call fails, skip silently \u2014 this is informational, not blocking."
4494
+ },
4459
4495
  // --- Operations ---
4460
4496
  {
4461
4497
  title: "Managers must supervise deployed workers",
@@ -1068,7 +1068,7 @@ __export(exe_daemon_client_exports, {
1068
1068
  });
1069
1069
  import net from "net";
1070
1070
  import os4 from "os";
1071
- import { spawn } from "child_process";
1071
+ import { spawn, execSync as execSync2 } from "child_process";
1072
1072
  import { randomUUID } from "crypto";
1073
1073
  import { existsSync as existsSync5, unlinkSync as unlinkSync2, readFileSync as readFileSync4, openSync, closeSync, statSync } from "fs";
1074
1074
  import path5 from "path";
@@ -1098,6 +1098,14 @@ function handleData(chunk) {
1098
1098
  }
1099
1099
  }
1100
1100
  }
1101
+ function isZombie(pid) {
1102
+ try {
1103
+ const state = execSync2(`ps -p ${pid} -o state=`, { encoding: "utf8", timeout: 2e3 }).trim();
1104
+ return state.startsWith("Z");
1105
+ } catch {
1106
+ return false;
1107
+ }
1108
+ }
1101
1109
  function cleanupStaleFiles() {
1102
1110
  if (existsSync5(PID_PATH)) {
1103
1111
  try {
@@ -1105,7 +1113,11 @@ function cleanupStaleFiles() {
1105
1113
  if (pid > 0) {
1106
1114
  try {
1107
1115
  process.kill(pid, 0);
1108
- return;
1116
+ if (!isZombie(pid)) {
1117
+ return;
1118
+ }
1119
+ process.stderr.write(`[exed-client] PID ${pid} is a zombie \u2014 cleaning up stale files
1120
+ `);
1109
1121
  } catch {
1110
1122
  }
1111
1123
  }
@@ -1133,8 +1145,8 @@ function findPackageRoot() {
1133
1145
  function getAvailableMemoryGB() {
1134
1146
  if (process.platform === "darwin") {
1135
1147
  try {
1136
- const { execSync: execSync3 } = __require("child_process");
1137
- const vmstat = execSync3("vm_stat", { encoding: "utf8" });
1148
+ const { execSync: execSync4 } = __require("child_process");
1149
+ const vmstat = execSync4("vm_stat", { encoding: "utf8" });
1138
1150
  const pageSize = 16384;
1139
1151
  const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
1140
1152
  const actualPageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : pageSize;
@@ -3124,6 +3136,12 @@ async function disposeDatabase() {
3124
3136
  clearInterval(_walCheckpointTimer);
3125
3137
  _walCheckpointTimer = null;
3126
3138
  }
3139
+ if (_client) {
3140
+ try {
3141
+ await _client.execute("PRAGMA wal_checkpoint(PASSIVE)");
3142
+ } catch {
3143
+ }
3144
+ }
3127
3145
  if (_daemonClient) {
3128
3146
  _daemonClient.close();
3129
3147
  _daemonClient = null;
@@ -3160,7 +3178,7 @@ var init_database = __esm({
3160
3178
  // src/lib/keychain.ts
3161
3179
  import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
3162
3180
  import { existsSync as existsSync6, statSync as statSync2 } from "fs";
3163
- import { execSync as execSync2 } from "child_process";
3181
+ import { execSync as execSync3 } from "child_process";
3164
3182
  import path6 from "path";
3165
3183
  import os5 from "os";
3166
3184
  function getKeyDir() {
@@ -3177,13 +3195,13 @@ function linuxSecretAvailable() {
3177
3195
  if (process.platform !== "linux") return false;
3178
3196
  if (linuxSecretAvailability !== null) return linuxSecretAvailability;
3179
3197
  try {
3180
- execSync2("command -v secret-tool >/dev/null 2>&1", { timeout: 1e3 });
3198
+ execSync3("command -v secret-tool >/dev/null 2>&1", { timeout: 1e3 });
3181
3199
  } catch {
3182
3200
  linuxSecretAvailability = false;
3183
3201
  return false;
3184
3202
  }
3185
3203
  try {
3186
- execSync2("secret-tool search --all exe-os probe >/dev/null 2>&1", { timeout: 1e3 });
3204
+ execSync3("secret-tool search --all exe-os probe >/dev/null 2>&1", { timeout: 1e3 });
3187
3205
  linuxSecretAvailability = true;
3188
3206
  } catch {
3189
3207
  linuxSecretAvailability = false;
@@ -3207,7 +3225,7 @@ function macKeychainGet(service = SERVICE) {
3207
3225
  if (!nativeKeychainAllowed()) return null;
3208
3226
  if (process.platform !== "darwin") return null;
3209
3227
  try {
3210
- return execSync2(
3228
+ return execSync3(
3211
3229
  `security find-generic-password -s "${service}" -a "${ACCOUNT}" -w 2>/dev/null`,
3212
3230
  { encoding: "utf-8", timeout: 5e3 }
3213
3231
  ).trim();
@@ -3220,13 +3238,13 @@ function macKeychainSet(value, service = SERVICE) {
3220
3238
  if (process.platform !== "darwin") return false;
3221
3239
  try {
3222
3240
  try {
3223
- execSync2(
3241
+ execSync3(
3224
3242
  `security delete-generic-password -s "${service}" -a "${ACCOUNT}" 2>/dev/null`,
3225
3243
  { timeout: 5e3 }
3226
3244
  );
3227
3245
  } catch {
3228
3246
  }
3229
- execSync2(
3247
+ execSync3(
3230
3248
  `security add-generic-password -s "${service}" -a "${ACCOUNT}" -w "${value}"`,
3231
3249
  { timeout: 5e3 }
3232
3250
  );
@@ -3239,7 +3257,7 @@ function macKeychainDelete(service = SERVICE) {
3239
3257
  if (!nativeKeychainAllowed()) return false;
3240
3258
  if (process.platform !== "darwin") return false;
3241
3259
  try {
3242
- execSync2(
3260
+ execSync3(
3243
3261
  `security delete-generic-password -s "${service}" -a "${ACCOUNT}" 2>/dev/null`,
3244
3262
  { timeout: 5e3 }
3245
3263
  );
@@ -3251,7 +3269,7 @@ function macKeychainDelete(service = SERVICE) {
3251
3269
  function linuxSecretGet(service = SERVICE) {
3252
3270
  if (!linuxSecretAvailable()) return null;
3253
3271
  try {
3254
- return execSync2(
3272
+ return execSync3(
3255
3273
  `secret-tool lookup service "${service}" account "${ACCOUNT}" 2>/dev/null`,
3256
3274
  { encoding: "utf-8", timeout: 5e3 }
3257
3275
  ).trim();
@@ -3262,7 +3280,7 @@ function linuxSecretGet(service = SERVICE) {
3262
3280
  function linuxSecretSet(value, service = SERVICE) {
3263
3281
  if (!linuxSecretAvailable()) return false;
3264
3282
  try {
3265
- execSync2(
3283
+ execSync3(
3266
3284
  `echo -n "${value}" | secret-tool store --label="exe-os master key" service "${service}" account "${ACCOUNT}" 2>/dev/null`,
3267
3285
  { timeout: 5e3 }
3268
3286
  );
@@ -3275,7 +3293,7 @@ function linuxSecretDelete(service = SERVICE) {
3275
3293
  if (!nativeKeychainAllowed()) return false;
3276
3294
  if (process.platform !== "linux") return false;
3277
3295
  try {
3278
- execSync2(
3296
+ execSync3(
3279
3297
  `secret-tool clear service "${service}" account "${ACCOUNT}" 2>/dev/null`,
3280
3298
  { timeout: 5e3 }
3281
3299
  );
@@ -4212,6 +4230,24 @@ var init_platform_procedures = __esm({
4212
4230
  priority: "p0",
4213
4231
  content: "When an agent encounters a suspected Exe OS bug, update breakage, MCP/tool failure, installer issue, memory/orchestration defect, or customer-local patch need, it MUST use create_bug_report. Do this before or alongside any local workaround so the report reaches AskExe support directly via the customer's license. Do NOT ask the founder for permission to file a required bug report. If create_bug_report is deferred/lazy-loaded, load it and call it. If it is unavailable in the live MCP surface, report 'create_bug_report unavailable in this session' and save a local report in exe/output \u2014 never claim the tool does not exist unless the live MCP surface was checked. If upstream delivery fails, call support_test (MCP) and include its result in the local report so AskExe can distinguish customer setup, license provisioning, and server intake issues; only ask the founder to run `exe-os support test` if MCP is disconnected/unavailable. Classify first: upstream_bug = reproducible exe-os/platform defect; customer_customization = identity, behavior, procedure, config, branding, workflow preference that belongs in customer-owned layers; emergency_hotfix = temporary local patch. For upstream bugs/emergency hotfixes include version, repro steps, expected/actual, files changed, workaround, and local diff summary. Avoid permanent platform-code patches unless founder approves; if a hotfix is unavoidable, document it in the bug report and re-check after npm update."
4214
4232
  },
4233
+ {
4234
+ title: "Bug report status check \u2014 surface available fixes on boot",
4235
+ domain: "support",
4236
+ priority: "p1",
4237
+ content: "Once per session (COO boot only, never repeat), call list_my_bug_reports to check if any previously filed bug reports have been fixed by AskExe. If any report has status 'fixed' with a fixed_version, surface it to the founder immediately: '\u{1F527} N bug fix(es) available \u2014 run exe-os update to get version X.Y.Z'. This is a one-time check at boot, not a recurring poll. If no reports exist or none are fixed, skip silently. If the MCP tool is unavailable or the network call fails, skip silently \u2014 this is informational, not blocking."
4238
+ },
4239
+ {
4240
+ title: "Feature request triage \u2014 upstream feature vs local customization",
4241
+ domain: "support",
4242
+ priority: "p0",
4243
+ content: "When an agent or founder identifies a desired capability that exe-os does not yet provide, the COO (or equivalent coordinator) must decide: is this a local customization (identity, behavior, procedure, config, branding, workflow preference that can be configured in customer-owned layers) or an upstream feature request (a platform capability that requires changes to exe-os code, shipped via npm update)? Local customizations: implement immediately using store_behavior, update_identity, company_procedure, or config changes. Upstream features: use create_feature_request to submit to AskExe. Include use case, business impact, and current workaround. Do NOT ask the founder for permission to file a feature request \u2014 file it proactively when the need is clear."
4244
+ },
4245
+ {
4246
+ title: "Feature request status check \u2014 surface shipped features on boot",
4247
+ domain: "support",
4248
+ priority: "p1",
4249
+ content: "Once per session (COO boot only, never repeat), call list_my_feature_requests to check if any previously filed feature requests have been shipped by AskExe. If any request has status 'shipped' with a shipped_version, surface it to the founder immediately: '\u{1F680} N feature(s) shipped \u2014 run exe-os update to get version X.Y.Z'. This is a one-time check at boot, not a recurring poll. If no requests exist or none are shipped, skip silently. If the MCP tool is unavailable or the network call fails, skip silently \u2014 this is informational, not blocking."
4250
+ },
4215
4251
  // --- Operations ---
4216
4252
  {
4217
4253
  title: "Managers must supervise deployed workers",