@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;
@@ -2869,7 +2887,7 @@ var init_database = __esm({
2869
2887
  // src/lib/keychain.ts
2870
2888
  import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
2871
2889
  import { existsSync as existsSync6, statSync as statSync2 } from "fs";
2872
- import { execSync as execSync2 } from "child_process";
2890
+ import { execSync as execSync3 } from "child_process";
2873
2891
  import path6 from "path";
2874
2892
  import os5 from "os";
2875
2893
  function getKeyDir() {
@@ -2886,13 +2904,13 @@ function linuxSecretAvailable() {
2886
2904
  if (process.platform !== "linux") return false;
2887
2905
  if (linuxSecretAvailability !== null) return linuxSecretAvailability;
2888
2906
  try {
2889
- execSync2("command -v secret-tool >/dev/null 2>&1", { timeout: 1e3 });
2907
+ execSync3("command -v secret-tool >/dev/null 2>&1", { timeout: 1e3 });
2890
2908
  } catch {
2891
2909
  linuxSecretAvailability = false;
2892
2910
  return false;
2893
2911
  }
2894
2912
  try {
2895
- execSync2("secret-tool search --all exe-os probe >/dev/null 2>&1", { timeout: 1e3 });
2913
+ execSync3("secret-tool search --all exe-os probe >/dev/null 2>&1", { timeout: 1e3 });
2896
2914
  linuxSecretAvailability = true;
2897
2915
  } catch {
2898
2916
  linuxSecretAvailability = false;
@@ -2916,7 +2934,7 @@ function macKeychainGet(service = SERVICE) {
2916
2934
  if (!nativeKeychainAllowed()) return null;
2917
2935
  if (process.platform !== "darwin") return null;
2918
2936
  try {
2919
- return execSync2(
2937
+ return execSync3(
2920
2938
  `security find-generic-password -s "${service}" -a "${ACCOUNT}" -w 2>/dev/null`,
2921
2939
  { encoding: "utf-8", timeout: 5e3 }
2922
2940
  ).trim();
@@ -2929,13 +2947,13 @@ function macKeychainSet(value, service = SERVICE) {
2929
2947
  if (process.platform !== "darwin") return false;
2930
2948
  try {
2931
2949
  try {
2932
- execSync2(
2950
+ execSync3(
2933
2951
  `security delete-generic-password -s "${service}" -a "${ACCOUNT}" 2>/dev/null`,
2934
2952
  { timeout: 5e3 }
2935
2953
  );
2936
2954
  } catch {
2937
2955
  }
2938
- execSync2(
2956
+ execSync3(
2939
2957
  `security add-generic-password -s "${service}" -a "${ACCOUNT}" -w "${value}"`,
2940
2958
  { timeout: 5e3 }
2941
2959
  );
@@ -2948,7 +2966,7 @@ function macKeychainDelete(service = SERVICE) {
2948
2966
  if (!nativeKeychainAllowed()) return false;
2949
2967
  if (process.platform !== "darwin") return false;
2950
2968
  try {
2951
- execSync2(
2969
+ execSync3(
2952
2970
  `security delete-generic-password -s "${service}" -a "${ACCOUNT}" 2>/dev/null`,
2953
2971
  { timeout: 5e3 }
2954
2972
  );
@@ -2960,7 +2978,7 @@ function macKeychainDelete(service = SERVICE) {
2960
2978
  function linuxSecretGet(service = SERVICE) {
2961
2979
  if (!linuxSecretAvailable()) return null;
2962
2980
  try {
2963
- return execSync2(
2981
+ return execSync3(
2964
2982
  `secret-tool lookup service "${service}" account "${ACCOUNT}" 2>/dev/null`,
2965
2983
  { encoding: "utf-8", timeout: 5e3 }
2966
2984
  ).trim();
@@ -2971,7 +2989,7 @@ function linuxSecretGet(service = SERVICE) {
2971
2989
  function linuxSecretSet(value, service = SERVICE) {
2972
2990
  if (!linuxSecretAvailable()) return false;
2973
2991
  try {
2974
- execSync2(
2992
+ execSync3(
2975
2993
  `echo -n "${value}" | secret-tool store --label="exe-os master key" service "${service}" account "${ACCOUNT}" 2>/dev/null`,
2976
2994
  { timeout: 5e3 }
2977
2995
  );
@@ -2984,7 +3002,7 @@ function linuxSecretDelete(service = SERVICE) {
2984
3002
  if (!nativeKeychainAllowed()) return false;
2985
3003
  if (process.platform !== "linux") return false;
2986
3004
  try {
2987
- execSync2(
3005
+ execSync3(
2988
3006
  `secret-tool clear service "${service}" account "${ACCOUNT}" 2>/dev/null`,
2989
3007
  { timeout: 5e3 }
2990
3008
  );
@@ -3672,6 +3690,24 @@ var init_platform_procedures = __esm({
3672
3690
  priority: "p0",
3673
3691
  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."
3674
3692
  },
3693
+ {
3694
+ title: "Bug report status check \u2014 surface available fixes on boot",
3695
+ domain: "support",
3696
+ priority: "p1",
3697
+ 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."
3698
+ },
3699
+ {
3700
+ title: "Feature request triage \u2014 upstream feature vs local customization",
3701
+ domain: "support",
3702
+ priority: "p0",
3703
+ 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."
3704
+ },
3705
+ {
3706
+ title: "Feature request status check \u2014 surface shipped features on boot",
3707
+ domain: "support",
3708
+ priority: "p1",
3709
+ 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."
3710
+ },
3675
3711
  // --- Operations ---
3676
3712
  {
3677
3713
  title: "Managers must supervise deployed workers",
@@ -1003,7 +1003,7 @@ __export(exe_daemon_client_exports, {
1003
1003
  });
1004
1004
  import net from "net";
1005
1005
  import os4 from "os";
1006
- import { spawn } from "child_process";
1006
+ import { spawn, execSync as execSync2 } from "child_process";
1007
1007
  import { randomUUID } from "crypto";
1008
1008
  import { existsSync as existsSync5, unlinkSync as unlinkSync2, readFileSync as readFileSync4, openSync, closeSync, statSync } from "fs";
1009
1009
  import path5 from "path";
@@ -1033,6 +1033,14 @@ function handleData(chunk) {
1033
1033
  }
1034
1034
  }
1035
1035
  }
1036
+ function isZombie(pid) {
1037
+ try {
1038
+ const state = execSync2(`ps -p ${pid} -o state=`, { encoding: "utf8", timeout: 2e3 }).trim();
1039
+ return state.startsWith("Z");
1040
+ } catch {
1041
+ return false;
1042
+ }
1043
+ }
1036
1044
  function cleanupStaleFiles() {
1037
1045
  if (existsSync5(PID_PATH)) {
1038
1046
  try {
@@ -1040,7 +1048,11 @@ function cleanupStaleFiles() {
1040
1048
  if (pid > 0) {
1041
1049
  try {
1042
1050
  process.kill(pid, 0);
1043
- return;
1051
+ if (!isZombie(pid)) {
1052
+ return;
1053
+ }
1054
+ process.stderr.write(`[exed-client] PID ${pid} is a zombie \u2014 cleaning up stale files
1055
+ `);
1044
1056
  } catch {
1045
1057
  }
1046
1058
  }
@@ -1068,8 +1080,8 @@ function findPackageRoot() {
1068
1080
  function getAvailableMemoryGB() {
1069
1081
  if (process.platform === "darwin") {
1070
1082
  try {
1071
- const { execSync: execSync5 } = __require("child_process");
1072
- const vmstat = execSync5("vm_stat", { encoding: "utf8" });
1083
+ const { execSync: execSync6 } = __require("child_process");
1084
+ const vmstat = execSync6("vm_stat", { encoding: "utf8" });
1073
1085
  const pageSize = 16384;
1074
1086
  const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
1075
1087
  const actualPageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : pageSize;
@@ -3059,6 +3071,12 @@ async function disposeDatabase() {
3059
3071
  clearInterval(_walCheckpointTimer);
3060
3072
  _walCheckpointTimer = null;
3061
3073
  }
3074
+ if (_client) {
3075
+ try {
3076
+ await _client.execute("PRAGMA wal_checkpoint(PASSIVE)");
3077
+ } catch {
3078
+ }
3079
+ }
3062
3080
  if (_daemonClient) {
3063
3081
  _daemonClient.close();
3064
3082
  _daemonClient = null;
@@ -3095,7 +3113,7 @@ var init_database = __esm({
3095
3113
  // src/lib/keychain.ts
3096
3114
  import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
3097
3115
  import { existsSync as existsSync6, statSync as statSync2 } from "fs";
3098
- import { execSync as execSync2 } from "child_process";
3116
+ import { execSync as execSync3 } from "child_process";
3099
3117
  import path6 from "path";
3100
3118
  import os5 from "os";
3101
3119
  function getKeyDir() {
@@ -3112,13 +3130,13 @@ function linuxSecretAvailable() {
3112
3130
  if (process.platform !== "linux") return false;
3113
3131
  if (linuxSecretAvailability !== null) return linuxSecretAvailability;
3114
3132
  try {
3115
- execSync2("command -v secret-tool >/dev/null 2>&1", { timeout: 1e3 });
3133
+ execSync3("command -v secret-tool >/dev/null 2>&1", { timeout: 1e3 });
3116
3134
  } catch {
3117
3135
  linuxSecretAvailability = false;
3118
3136
  return false;
3119
3137
  }
3120
3138
  try {
3121
- execSync2("secret-tool search --all exe-os probe >/dev/null 2>&1", { timeout: 1e3 });
3139
+ execSync3("secret-tool search --all exe-os probe >/dev/null 2>&1", { timeout: 1e3 });
3122
3140
  linuxSecretAvailability = true;
3123
3141
  } catch {
3124
3142
  linuxSecretAvailability = false;
@@ -3142,7 +3160,7 @@ function macKeychainGet(service = SERVICE) {
3142
3160
  if (!nativeKeychainAllowed()) return null;
3143
3161
  if (process.platform !== "darwin") return null;
3144
3162
  try {
3145
- return execSync2(
3163
+ return execSync3(
3146
3164
  `security find-generic-password -s "${service}" -a "${ACCOUNT}" -w 2>/dev/null`,
3147
3165
  { encoding: "utf-8", timeout: 5e3 }
3148
3166
  ).trim();
@@ -3155,13 +3173,13 @@ function macKeychainSet(value, service = SERVICE) {
3155
3173
  if (process.platform !== "darwin") return false;
3156
3174
  try {
3157
3175
  try {
3158
- execSync2(
3176
+ execSync3(
3159
3177
  `security delete-generic-password -s "${service}" -a "${ACCOUNT}" 2>/dev/null`,
3160
3178
  { timeout: 5e3 }
3161
3179
  );
3162
3180
  } catch {
3163
3181
  }
3164
- execSync2(
3182
+ execSync3(
3165
3183
  `security add-generic-password -s "${service}" -a "${ACCOUNT}" -w "${value}"`,
3166
3184
  { timeout: 5e3 }
3167
3185
  );
@@ -3174,7 +3192,7 @@ function macKeychainDelete(service = SERVICE) {
3174
3192
  if (!nativeKeychainAllowed()) return false;
3175
3193
  if (process.platform !== "darwin") return false;
3176
3194
  try {
3177
- execSync2(
3195
+ execSync3(
3178
3196
  `security delete-generic-password -s "${service}" -a "${ACCOUNT}" 2>/dev/null`,
3179
3197
  { timeout: 5e3 }
3180
3198
  );
@@ -3186,7 +3204,7 @@ function macKeychainDelete(service = SERVICE) {
3186
3204
  function linuxSecretGet(service = SERVICE) {
3187
3205
  if (!linuxSecretAvailable()) return null;
3188
3206
  try {
3189
- return execSync2(
3207
+ return execSync3(
3190
3208
  `secret-tool lookup service "${service}" account "${ACCOUNT}" 2>/dev/null`,
3191
3209
  { encoding: "utf-8", timeout: 5e3 }
3192
3210
  ).trim();
@@ -3197,7 +3215,7 @@ function linuxSecretGet(service = SERVICE) {
3197
3215
  function linuxSecretSet(value, service = SERVICE) {
3198
3216
  if (!linuxSecretAvailable()) return false;
3199
3217
  try {
3200
- execSync2(
3218
+ execSync3(
3201
3219
  `echo -n "${value}" | secret-tool store --label="exe-os master key" service "${service}" account "${ACCOUNT}" 2>/dev/null`,
3202
3220
  { timeout: 5e3 }
3203
3221
  );
@@ -3210,7 +3228,7 @@ function linuxSecretDelete(service = SERVICE) {
3210
3228
  if (!nativeKeychainAllowed()) return false;
3211
3229
  if (process.platform !== "linux") return false;
3212
3230
  try {
3213
- execSync2(
3231
+ execSync3(
3214
3232
  `secret-tool clear service "${service}" account "${ACCOUNT}" 2>/dev/null`,
3215
3233
  { timeout: 5e3 }
3216
3234
  );
@@ -4147,6 +4165,24 @@ var init_platform_procedures = __esm({
4147
4165
  priority: "p0",
4148
4166
  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."
4149
4167
  },
4168
+ {
4169
+ title: "Bug report status check \u2014 surface available fixes on boot",
4170
+ domain: "support",
4171
+ priority: "p1",
4172
+ 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."
4173
+ },
4174
+ {
4175
+ title: "Feature request triage \u2014 upstream feature vs local customization",
4176
+ domain: "support",
4177
+ priority: "p0",
4178
+ 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."
4179
+ },
4180
+ {
4181
+ title: "Feature request status check \u2014 surface shipped features on boot",
4182
+ domain: "support",
4183
+ priority: "p1",
4184
+ 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."
4185
+ },
4150
4186
  // --- Operations ---
4151
4187
  {
4152
4188
  title: "Managers must supervise deployed workers",
@@ -5398,7 +5434,7 @@ var init_session_registry = __esm({
5398
5434
  });
5399
5435
 
5400
5436
  // src/lib/session-key.ts
5401
- import { execSync as execSync3 } from "child_process";
5437
+ import { execSync as execSync4 } from "child_process";
5402
5438
  function normalizeCommand(command) {
5403
5439
  const trimmed = command.trim().toLowerCase();
5404
5440
  const parts = trimmed.split(/[\\/]/);
@@ -5417,7 +5453,7 @@ function resolveRuntimeProcess() {
5417
5453
  let pid = process.ppid;
5418
5454
  for (let i = 0; i < 10; i++) {
5419
5455
  try {
5420
- const info = execSync3(`ps -p ${pid} -o ppid=,comm=`, {
5456
+ const info = execSync4(`ps -p ${pid} -o ppid=,comm=`, {
5421
5457
  encoding: "utf8",
5422
5458
  timeout: 2e3
5423
5459
  }).trim();
@@ -5583,7 +5619,7 @@ var init_transport = __esm({
5583
5619
  });
5584
5620
 
5585
5621
  // src/lib/cc-agent-support.ts
5586
- import { execSync as execSync4 } from "child_process";
5622
+ import { execSync as execSync5 } from "child_process";
5587
5623
  var init_cc_agent_support = __esm({
5588
5624
  "src/lib/cc-agent-support.ts"() {
5589
5625
  "use strict";