@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
@@ -981,7 +981,7 @@ var init_daemon_auth = __esm({
981
981
  // src/lib/exe-daemon-client.ts
982
982
  import net from "net";
983
983
  import os4 from "os";
984
- import { spawn } from "child_process";
984
+ import { spawn, execSync as execSync2 } from "child_process";
985
985
  import { randomUUID } from "crypto";
986
986
  import { existsSync as existsSync5, unlinkSync as unlinkSync2, readFileSync as readFileSync4, openSync, closeSync, statSync } from "fs";
987
987
  import path5 from "path";
@@ -1011,6 +1011,14 @@ function handleData(chunk) {
1011
1011
  }
1012
1012
  }
1013
1013
  }
1014
+ function isZombie(pid) {
1015
+ try {
1016
+ const state = execSync2(`ps -p ${pid} -o state=`, { encoding: "utf8", timeout: 2e3 }).trim();
1017
+ return state.startsWith("Z");
1018
+ } catch {
1019
+ return false;
1020
+ }
1021
+ }
1014
1022
  function cleanupStaleFiles() {
1015
1023
  if (existsSync5(PID_PATH)) {
1016
1024
  try {
@@ -1018,7 +1026,11 @@ function cleanupStaleFiles() {
1018
1026
  if (pid > 0) {
1019
1027
  try {
1020
1028
  process.kill(pid, 0);
1021
- return;
1029
+ if (!isZombie(pid)) {
1030
+ return;
1031
+ }
1032
+ process.stderr.write(`[exed-client] PID ${pid} is a zombie \u2014 cleaning up stale files
1033
+ `);
1022
1034
  } catch {
1023
1035
  }
1024
1036
  }
@@ -1046,8 +1058,8 @@ function findPackageRoot() {
1046
1058
  function getAvailableMemoryGB() {
1047
1059
  if (process.platform === "darwin") {
1048
1060
  try {
1049
- const { execSync: execSync3 } = __require("child_process");
1050
- const vmstat = execSync3("vm_stat", { encoding: "utf8" });
1061
+ const { execSync: execSync4 } = __require("child_process");
1062
+ const vmstat = execSync4("vm_stat", { encoding: "utf8" });
1051
1063
  const pageSize = 16384;
1052
1064
  const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
1053
1065
  const actualPageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : pageSize;
@@ -2833,6 +2845,12 @@ async function disposeDatabase() {
2833
2845
  clearInterval(_walCheckpointTimer);
2834
2846
  _walCheckpointTimer = null;
2835
2847
  }
2848
+ if (_client) {
2849
+ try {
2850
+ await _client.execute("PRAGMA wal_checkpoint(PASSIVE)");
2851
+ } catch {
2852
+ }
2853
+ }
2836
2854
  if (_daemonClient) {
2837
2855
  _daemonClient.close();
2838
2856
  _daemonClient = null;
@@ -3364,6 +3382,24 @@ var init_platform_procedures = __esm({
3364
3382
  priority: "p0",
3365
3383
  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."
3366
3384
  },
3385
+ {
3386
+ title: "Bug report status check \u2014 surface available fixes on boot",
3387
+ domain: "support",
3388
+ priority: "p1",
3389
+ 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."
3390
+ },
3391
+ {
3392
+ title: "Feature request triage \u2014 upstream feature vs local customization",
3393
+ domain: "support",
3394
+ priority: "p0",
3395
+ 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."
3396
+ },
3397
+ {
3398
+ title: "Feature request status check \u2014 surface shipped features on boot",
3399
+ domain: "support",
3400
+ priority: "p1",
3401
+ 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."
3402
+ },
3367
3403
  // --- Operations ---
3368
3404
  {
3369
3405
  title: "Managers must supervise deployed workers",
@@ -3987,7 +4023,7 @@ init_database();
3987
4023
  // src/lib/keychain.ts
3988
4024
  import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
3989
4025
  import { existsSync as existsSync6, statSync as statSync2 } from "fs";
3990
- import { execSync as execSync2 } from "child_process";
4026
+ import { execSync as execSync3 } from "child_process";
3991
4027
  import path6 from "path";
3992
4028
  import os5 from "os";
3993
4029
  var SERVICE = "exe-os";
@@ -4008,13 +4044,13 @@ function linuxSecretAvailable() {
4008
4044
  if (process.platform !== "linux") return false;
4009
4045
  if (linuxSecretAvailability !== null) return linuxSecretAvailability;
4010
4046
  try {
4011
- execSync2("command -v secret-tool >/dev/null 2>&1", { timeout: 1e3 });
4047
+ execSync3("command -v secret-tool >/dev/null 2>&1", { timeout: 1e3 });
4012
4048
  } catch {
4013
4049
  linuxSecretAvailability = false;
4014
4050
  return false;
4015
4051
  }
4016
4052
  try {
4017
- execSync2("secret-tool search --all exe-os probe >/dev/null 2>&1", { timeout: 1e3 });
4053
+ execSync3("secret-tool search --all exe-os probe >/dev/null 2>&1", { timeout: 1e3 });
4018
4054
  linuxSecretAvailability = true;
4019
4055
  } catch {
4020
4056
  linuxSecretAvailability = false;
@@ -4038,7 +4074,7 @@ function macKeychainGet(service = SERVICE) {
4038
4074
  if (!nativeKeychainAllowed()) return null;
4039
4075
  if (process.platform !== "darwin") return null;
4040
4076
  try {
4041
- return execSync2(
4077
+ return execSync3(
4042
4078
  `security find-generic-password -s "${service}" -a "${ACCOUNT}" -w 2>/dev/null`,
4043
4079
  { encoding: "utf-8", timeout: 5e3 }
4044
4080
  ).trim();
@@ -4051,13 +4087,13 @@ function macKeychainSet(value, service = SERVICE) {
4051
4087
  if (process.platform !== "darwin") return false;
4052
4088
  try {
4053
4089
  try {
4054
- execSync2(
4090
+ execSync3(
4055
4091
  `security delete-generic-password -s "${service}" -a "${ACCOUNT}" 2>/dev/null`,
4056
4092
  { timeout: 5e3 }
4057
4093
  );
4058
4094
  } catch {
4059
4095
  }
4060
- execSync2(
4096
+ execSync3(
4061
4097
  `security add-generic-password -s "${service}" -a "${ACCOUNT}" -w "${value}"`,
4062
4098
  { timeout: 5e3 }
4063
4099
  );
@@ -4070,7 +4106,7 @@ function macKeychainDelete(service = SERVICE) {
4070
4106
  if (!nativeKeychainAllowed()) return false;
4071
4107
  if (process.platform !== "darwin") return false;
4072
4108
  try {
4073
- execSync2(
4109
+ execSync3(
4074
4110
  `security delete-generic-password -s "${service}" -a "${ACCOUNT}" 2>/dev/null`,
4075
4111
  { timeout: 5e3 }
4076
4112
  );
@@ -4082,7 +4118,7 @@ function macKeychainDelete(service = SERVICE) {
4082
4118
  function linuxSecretGet(service = SERVICE) {
4083
4119
  if (!linuxSecretAvailable()) return null;
4084
4120
  try {
4085
- return execSync2(
4121
+ return execSync3(
4086
4122
  `secret-tool lookup service "${service}" account "${ACCOUNT}" 2>/dev/null`,
4087
4123
  { encoding: "utf-8", timeout: 5e3 }
4088
4124
  ).trim();
@@ -4093,7 +4129,7 @@ function linuxSecretGet(service = SERVICE) {
4093
4129
  function linuxSecretSet(value, service = SERVICE) {
4094
4130
  if (!linuxSecretAvailable()) return false;
4095
4131
  try {
4096
- execSync2(
4132
+ execSync3(
4097
4133
  `echo -n "${value}" | secret-tool store --label="exe-os master key" service "${service}" account "${ACCOUNT}" 2>/dev/null`,
4098
4134
  { timeout: 5e3 }
4099
4135
  );
@@ -4106,7 +4142,7 @@ function linuxSecretDelete(service = SERVICE) {
4106
4142
  if (!nativeKeychainAllowed()) return false;
4107
4143
  if (process.platform !== "linux") return false;
4108
4144
  try {
4109
- execSync2(
4145
+ execSync3(
4110
4146
  `secret-tool clear service "${service}" account "${ACCOUNT}" 2>/dev/null`,
4111
4147
  { timeout: 5e3 }
4112
4148
  );
@@ -981,7 +981,7 @@ var init_daemon_auth = __esm({
981
981
  // src/lib/exe-daemon-client.ts
982
982
  import net from "net";
983
983
  import os4 from "os";
984
- import { spawn } from "child_process";
984
+ import { spawn, execSync as execSync2 } from "child_process";
985
985
  import { randomUUID } from "crypto";
986
986
  import { existsSync as existsSync5, unlinkSync as unlinkSync2, readFileSync as readFileSync4, openSync, closeSync, statSync } from "fs";
987
987
  import path5 from "path";
@@ -1011,6 +1011,14 @@ function handleData(chunk) {
1011
1011
  }
1012
1012
  }
1013
1013
  }
1014
+ function isZombie(pid) {
1015
+ try {
1016
+ const state = execSync2(`ps -p ${pid} -o state=`, { encoding: "utf8", timeout: 2e3 }).trim();
1017
+ return state.startsWith("Z");
1018
+ } catch {
1019
+ return false;
1020
+ }
1021
+ }
1014
1022
  function cleanupStaleFiles() {
1015
1023
  if (existsSync5(PID_PATH)) {
1016
1024
  try {
@@ -1018,7 +1026,11 @@ function cleanupStaleFiles() {
1018
1026
  if (pid > 0) {
1019
1027
  try {
1020
1028
  process.kill(pid, 0);
1021
- return;
1029
+ if (!isZombie(pid)) {
1030
+ return;
1031
+ }
1032
+ process.stderr.write(`[exed-client] PID ${pid} is a zombie \u2014 cleaning up stale files
1033
+ `);
1022
1034
  } catch {
1023
1035
  }
1024
1036
  }
@@ -1046,8 +1058,8 @@ function findPackageRoot() {
1046
1058
  function getAvailableMemoryGB() {
1047
1059
  if (process.platform === "darwin") {
1048
1060
  try {
1049
- const { execSync: execSync3 } = __require("child_process");
1050
- const vmstat = execSync3("vm_stat", { encoding: "utf8" });
1061
+ const { execSync: execSync4 } = __require("child_process");
1062
+ const vmstat = execSync4("vm_stat", { encoding: "utf8" });
1051
1063
  const pageSize = 16384;
1052
1064
  const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
1053
1065
  const actualPageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : pageSize;
@@ -2833,6 +2845,12 @@ async function disposeDatabase() {
2833
2845
  clearInterval(_walCheckpointTimer);
2834
2846
  _walCheckpointTimer = null;
2835
2847
  }
2848
+ if (_client) {
2849
+ try {
2850
+ await _client.execute("PRAGMA wal_checkpoint(PASSIVE)");
2851
+ } catch {
2852
+ }
2853
+ }
2836
2854
  if (_daemonClient) {
2837
2855
  _daemonClient.close();
2838
2856
  _daemonClient = null;
@@ -3364,6 +3382,24 @@ var init_platform_procedures = __esm({
3364
3382
  priority: "p0",
3365
3383
  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."
3366
3384
  },
3385
+ {
3386
+ title: "Bug report status check \u2014 surface available fixes on boot",
3387
+ domain: "support",
3388
+ priority: "p1",
3389
+ 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."
3390
+ },
3391
+ {
3392
+ title: "Feature request triage \u2014 upstream feature vs local customization",
3393
+ domain: "support",
3394
+ priority: "p0",
3395
+ 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."
3396
+ },
3397
+ {
3398
+ title: "Feature request status check \u2014 surface shipped features on boot",
3399
+ domain: "support",
3400
+ priority: "p1",
3401
+ 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."
3402
+ },
3367
3403
  // --- Operations ---
3368
3404
  {
3369
3405
  title: "Managers must supervise deployed workers",
@@ -3575,7 +3611,7 @@ init_database();
3575
3611
  // src/lib/keychain.ts
3576
3612
  import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
3577
3613
  import { existsSync as existsSync6, statSync as statSync2 } from "fs";
3578
- import { execSync as execSync2 } from "child_process";
3614
+ import { execSync as execSync3 } from "child_process";
3579
3615
  import path6 from "path";
3580
3616
  import os5 from "os";
3581
3617
  var SERVICE = "exe-os";
@@ -3596,13 +3632,13 @@ function linuxSecretAvailable() {
3596
3632
  if (process.platform !== "linux") return false;
3597
3633
  if (linuxSecretAvailability !== null) return linuxSecretAvailability;
3598
3634
  try {
3599
- execSync2("command -v secret-tool >/dev/null 2>&1", { timeout: 1e3 });
3635
+ execSync3("command -v secret-tool >/dev/null 2>&1", { timeout: 1e3 });
3600
3636
  } catch {
3601
3637
  linuxSecretAvailability = false;
3602
3638
  return false;
3603
3639
  }
3604
3640
  try {
3605
- execSync2("secret-tool search --all exe-os probe >/dev/null 2>&1", { timeout: 1e3 });
3641
+ execSync3("secret-tool search --all exe-os probe >/dev/null 2>&1", { timeout: 1e3 });
3606
3642
  linuxSecretAvailability = true;
3607
3643
  } catch {
3608
3644
  linuxSecretAvailability = false;
@@ -3626,7 +3662,7 @@ function macKeychainGet(service = SERVICE) {
3626
3662
  if (!nativeKeychainAllowed()) return null;
3627
3663
  if (process.platform !== "darwin") return null;
3628
3664
  try {
3629
- return execSync2(
3665
+ return execSync3(
3630
3666
  `security find-generic-password -s "${service}" -a "${ACCOUNT}" -w 2>/dev/null`,
3631
3667
  { encoding: "utf-8", timeout: 5e3 }
3632
3668
  ).trim();
@@ -3639,13 +3675,13 @@ function macKeychainSet(value, service = SERVICE) {
3639
3675
  if (process.platform !== "darwin") return false;
3640
3676
  try {
3641
3677
  try {
3642
- execSync2(
3678
+ execSync3(
3643
3679
  `security delete-generic-password -s "${service}" -a "${ACCOUNT}" 2>/dev/null`,
3644
3680
  { timeout: 5e3 }
3645
3681
  );
3646
3682
  } catch {
3647
3683
  }
3648
- execSync2(
3684
+ execSync3(
3649
3685
  `security add-generic-password -s "${service}" -a "${ACCOUNT}" -w "${value}"`,
3650
3686
  { timeout: 5e3 }
3651
3687
  );
@@ -3658,7 +3694,7 @@ function macKeychainDelete(service = SERVICE) {
3658
3694
  if (!nativeKeychainAllowed()) return false;
3659
3695
  if (process.platform !== "darwin") return false;
3660
3696
  try {
3661
- execSync2(
3697
+ execSync3(
3662
3698
  `security delete-generic-password -s "${service}" -a "${ACCOUNT}" 2>/dev/null`,
3663
3699
  { timeout: 5e3 }
3664
3700
  );
@@ -3670,7 +3706,7 @@ function macKeychainDelete(service = SERVICE) {
3670
3706
  function linuxSecretGet(service = SERVICE) {
3671
3707
  if (!linuxSecretAvailable()) return null;
3672
3708
  try {
3673
- return execSync2(
3709
+ return execSync3(
3674
3710
  `secret-tool lookup service "${service}" account "${ACCOUNT}" 2>/dev/null`,
3675
3711
  { encoding: "utf-8", timeout: 5e3 }
3676
3712
  ).trim();
@@ -3681,7 +3717,7 @@ function linuxSecretGet(service = SERVICE) {
3681
3717
  function linuxSecretSet(value, service = SERVICE) {
3682
3718
  if (!linuxSecretAvailable()) return false;
3683
3719
  try {
3684
- execSync2(
3720
+ execSync3(
3685
3721
  `echo -n "${value}" | secret-tool store --label="exe-os master key" service "${service}" account "${ACCOUNT}" 2>/dev/null`,
3686
3722
  { timeout: 5e3 }
3687
3723
  );
@@ -3694,7 +3730,7 @@ function linuxSecretDelete(service = SERVICE) {
3694
3730
  if (!nativeKeychainAllowed()) return false;
3695
3731
  if (process.platform !== "linux") return false;
3696
3732
  try {
3697
- execSync2(
3733
+ execSync3(
3698
3734
  `secret-tool clear service "${service}" account "${ACCOUNT}" 2>/dev/null`,
3699
3735
  { timeout: 5e3 }
3700
3736
  );
@@ -981,7 +981,7 @@ var init_daemon_auth = __esm({
981
981
  // src/lib/exe-daemon-client.ts
982
982
  import net from "net";
983
983
  import os4 from "os";
984
- import { spawn } from "child_process";
984
+ import { spawn, execSync as execSync2 } from "child_process";
985
985
  import { randomUUID } from "crypto";
986
986
  import { existsSync as existsSync5, unlinkSync as unlinkSync2, readFileSync as readFileSync4, openSync, closeSync, statSync } from "fs";
987
987
  import path5 from "path";
@@ -1011,6 +1011,14 @@ function handleData(chunk) {
1011
1011
  }
1012
1012
  }
1013
1013
  }
1014
+ function isZombie(pid) {
1015
+ try {
1016
+ const state = execSync2(`ps -p ${pid} -o state=`, { encoding: "utf8", timeout: 2e3 }).trim();
1017
+ return state.startsWith("Z");
1018
+ } catch {
1019
+ return false;
1020
+ }
1021
+ }
1014
1022
  function cleanupStaleFiles() {
1015
1023
  if (existsSync5(PID_PATH)) {
1016
1024
  try {
@@ -1018,7 +1026,11 @@ function cleanupStaleFiles() {
1018
1026
  if (pid > 0) {
1019
1027
  try {
1020
1028
  process.kill(pid, 0);
1021
- return;
1029
+ if (!isZombie(pid)) {
1030
+ return;
1031
+ }
1032
+ process.stderr.write(`[exed-client] PID ${pid} is a zombie \u2014 cleaning up stale files
1033
+ `);
1022
1034
  } catch {
1023
1035
  }
1024
1036
  }
@@ -1046,8 +1058,8 @@ function findPackageRoot() {
1046
1058
  function getAvailableMemoryGB() {
1047
1059
  if (process.platform === "darwin") {
1048
1060
  try {
1049
- const { execSync: execSync3 } = __require("child_process");
1050
- const vmstat = execSync3("vm_stat", { encoding: "utf8" });
1061
+ const { execSync: execSync4 } = __require("child_process");
1062
+ const vmstat = execSync4("vm_stat", { encoding: "utf8" });
1051
1063
  const pageSize = 16384;
1052
1064
  const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
1053
1065
  const actualPageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : pageSize;
@@ -2833,6 +2845,12 @@ async function disposeDatabase() {
2833
2845
  clearInterval(_walCheckpointTimer);
2834
2846
  _walCheckpointTimer = null;
2835
2847
  }
2848
+ if (_client) {
2849
+ try {
2850
+ await _client.execute("PRAGMA wal_checkpoint(PASSIVE)");
2851
+ } catch {
2852
+ }
2853
+ }
2836
2854
  if (_daemonClient) {
2837
2855
  _daemonClient.close();
2838
2856
  _daemonClient = null;
@@ -3364,6 +3382,24 @@ var init_platform_procedures = __esm({
3364
3382
  priority: "p0",
3365
3383
  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."
3366
3384
  },
3385
+ {
3386
+ title: "Bug report status check \u2014 surface available fixes on boot",
3387
+ domain: "support",
3388
+ priority: "p1",
3389
+ 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."
3390
+ },
3391
+ {
3392
+ title: "Feature request triage \u2014 upstream feature vs local customization",
3393
+ domain: "support",
3394
+ priority: "p0",
3395
+ 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."
3396
+ },
3397
+ {
3398
+ title: "Feature request status check \u2014 surface shipped features on boot",
3399
+ domain: "support",
3400
+ priority: "p1",
3401
+ 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."
3402
+ },
3367
3403
  // --- Operations ---
3368
3404
  {
3369
3405
  title: "Managers must supervise deployed workers",
@@ -3699,7 +3735,7 @@ init_database();
3699
3735
  // src/lib/keychain.ts
3700
3736
  import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
3701
3737
  import { existsSync as existsSync6, statSync as statSync2 } from "fs";
3702
- import { execSync as execSync2 } from "child_process";
3738
+ import { execSync as execSync3 } from "child_process";
3703
3739
  import path6 from "path";
3704
3740
  import os5 from "os";
3705
3741
  var SERVICE = "exe-os";
@@ -3720,13 +3756,13 @@ function linuxSecretAvailable() {
3720
3756
  if (process.platform !== "linux") return false;
3721
3757
  if (linuxSecretAvailability !== null) return linuxSecretAvailability;
3722
3758
  try {
3723
- execSync2("command -v secret-tool >/dev/null 2>&1", { timeout: 1e3 });
3759
+ execSync3("command -v secret-tool >/dev/null 2>&1", { timeout: 1e3 });
3724
3760
  } catch {
3725
3761
  linuxSecretAvailability = false;
3726
3762
  return false;
3727
3763
  }
3728
3764
  try {
3729
- execSync2("secret-tool search --all exe-os probe >/dev/null 2>&1", { timeout: 1e3 });
3765
+ execSync3("secret-tool search --all exe-os probe >/dev/null 2>&1", { timeout: 1e3 });
3730
3766
  linuxSecretAvailability = true;
3731
3767
  } catch {
3732
3768
  linuxSecretAvailability = false;
@@ -3750,7 +3786,7 @@ function macKeychainGet(service = SERVICE) {
3750
3786
  if (!nativeKeychainAllowed()) return null;
3751
3787
  if (process.platform !== "darwin") return null;
3752
3788
  try {
3753
- return execSync2(
3789
+ return execSync3(
3754
3790
  `security find-generic-password -s "${service}" -a "${ACCOUNT}" -w 2>/dev/null`,
3755
3791
  { encoding: "utf-8", timeout: 5e3 }
3756
3792
  ).trim();
@@ -3763,13 +3799,13 @@ function macKeychainSet(value, service = SERVICE) {
3763
3799
  if (process.platform !== "darwin") return false;
3764
3800
  try {
3765
3801
  try {
3766
- execSync2(
3802
+ execSync3(
3767
3803
  `security delete-generic-password -s "${service}" -a "${ACCOUNT}" 2>/dev/null`,
3768
3804
  { timeout: 5e3 }
3769
3805
  );
3770
3806
  } catch {
3771
3807
  }
3772
- execSync2(
3808
+ execSync3(
3773
3809
  `security add-generic-password -s "${service}" -a "${ACCOUNT}" -w "${value}"`,
3774
3810
  { timeout: 5e3 }
3775
3811
  );
@@ -3782,7 +3818,7 @@ function macKeychainDelete(service = SERVICE) {
3782
3818
  if (!nativeKeychainAllowed()) return false;
3783
3819
  if (process.platform !== "darwin") return false;
3784
3820
  try {
3785
- execSync2(
3821
+ execSync3(
3786
3822
  `security delete-generic-password -s "${service}" -a "${ACCOUNT}" 2>/dev/null`,
3787
3823
  { timeout: 5e3 }
3788
3824
  );
@@ -3794,7 +3830,7 @@ function macKeychainDelete(service = SERVICE) {
3794
3830
  function linuxSecretGet(service = SERVICE) {
3795
3831
  if (!linuxSecretAvailable()) return null;
3796
3832
  try {
3797
- return execSync2(
3833
+ return execSync3(
3798
3834
  `secret-tool lookup service "${service}" account "${ACCOUNT}" 2>/dev/null`,
3799
3835
  { encoding: "utf-8", timeout: 5e3 }
3800
3836
  ).trim();
@@ -3805,7 +3841,7 @@ function linuxSecretGet(service = SERVICE) {
3805
3841
  function linuxSecretSet(value, service = SERVICE) {
3806
3842
  if (!linuxSecretAvailable()) return false;
3807
3843
  try {
3808
- execSync2(
3844
+ execSync3(
3809
3845
  `echo -n "${value}" | secret-tool store --label="exe-os master key" service "${service}" account "${ACCOUNT}" 2>/dev/null`,
3810
3846
  { timeout: 5e3 }
3811
3847
  );
@@ -3818,7 +3854,7 @@ function linuxSecretDelete(service = SERVICE) {
3818
3854
  if (!nativeKeychainAllowed()) return false;
3819
3855
  if (process.platform !== "linux") return false;
3820
3856
  try {
3821
- execSync2(
3857
+ execSync3(
3822
3858
  `secret-tool clear service "${service}" account "${ACCOUNT}" 2>/dev/null`,
3823
3859
  { timeout: 5e3 }
3824
3860
  );