@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
@@ -1377,6 +1377,24 @@ var PLATFORM_PROCEDURES = [
1377
1377
  priority: "p0",
1378
1378
  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."
1379
1379
  },
1380
+ {
1381
+ title: "Bug report status check \u2014 surface available fixes on boot",
1382
+ domain: "support",
1383
+ priority: "p1",
1384
+ 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."
1385
+ },
1386
+ {
1387
+ title: "Feature request triage \u2014 upstream feature vs local customization",
1388
+ domain: "support",
1389
+ priority: "p0",
1390
+ 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."
1391
+ },
1392
+ {
1393
+ title: "Feature request status check \u2014 surface shipped features on boot",
1394
+ domain: "support",
1395
+ priority: "p1",
1396
+ 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."
1397
+ },
1380
1398
  // --- Operations ---
1381
1399
  {
1382
1400
  title: "Managers must supervise deployed workers",
@@ -356,7 +356,7 @@ var init_daemon_auth = __esm({
356
356
  // src/lib/exe-daemon-client.ts
357
357
  import net from "net";
358
358
  import os3 from "os";
359
- import { spawn } from "child_process";
359
+ import { spawn, execSync as execSync2 } from "child_process";
360
360
  import { randomUUID as randomUUID2 } from "crypto";
361
361
  import { existsSync as existsSync5, unlinkSync as unlinkSync2, readFileSync as readFileSync4, openSync, closeSync, statSync } from "fs";
362
362
  import path4 from "path";
@@ -386,6 +386,14 @@ function handleData(chunk) {
386
386
  }
387
387
  }
388
388
  }
389
+ function isZombie(pid) {
390
+ try {
391
+ const state = execSync2(`ps -p ${pid} -o state=`, { encoding: "utf8", timeout: 2e3 }).trim();
392
+ return state.startsWith("Z");
393
+ } catch {
394
+ return false;
395
+ }
396
+ }
389
397
  function cleanupStaleFiles() {
390
398
  if (existsSync5(PID_PATH)) {
391
399
  try {
@@ -393,7 +401,11 @@ function cleanupStaleFiles() {
393
401
  if (pid > 0) {
394
402
  try {
395
403
  process.kill(pid, 0);
396
- return;
404
+ if (!isZombie(pid)) {
405
+ return;
406
+ }
407
+ process.stderr.write(`[exed-client] PID ${pid} is a zombie \u2014 cleaning up stale files
408
+ `);
397
409
  } catch {
398
410
  }
399
411
  }
@@ -421,8 +433,8 @@ function findPackageRoot() {
421
433
  function getAvailableMemoryGB() {
422
434
  if (process.platform === "darwin") {
423
435
  try {
424
- const { execSync: execSync3 } = __require("child_process");
425
- const vmstat = execSync3("vm_stat", { encoding: "utf8" });
436
+ const { execSync: execSync4 } = __require("child_process");
437
+ const vmstat = execSync4("vm_stat", { encoding: "utf8" });
426
438
  const pageSize = 16384;
427
439
  const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
428
440
  const actualPageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : pageSize;
@@ -2983,6 +2995,12 @@ async function disposeDatabase() {
2983
2995
  clearInterval(_walCheckpointTimer);
2984
2996
  _walCheckpointTimer = null;
2985
2997
  }
2998
+ if (_client) {
2999
+ try {
3000
+ await _client.execute("PRAGMA wal_checkpoint(PASSIVE)");
3001
+ } catch {
3002
+ }
3003
+ }
2986
3004
  if (_daemonClient) {
2987
3005
  _daemonClient.close();
2988
3006
  _daemonClient = null;
@@ -3514,6 +3532,24 @@ var init_platform_procedures = __esm({
3514
3532
  priority: "p0",
3515
3533
  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."
3516
3534
  },
3535
+ {
3536
+ title: "Bug report status check \u2014 surface available fixes on boot",
3537
+ domain: "support",
3538
+ priority: "p1",
3539
+ 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."
3540
+ },
3541
+ {
3542
+ title: "Feature request triage \u2014 upstream feature vs local customization",
3543
+ domain: "support",
3544
+ priority: "p0",
3545
+ 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."
3546
+ },
3547
+ {
3548
+ title: "Feature request status check \u2014 surface shipped features on boot",
3549
+ domain: "support",
3550
+ priority: "p1",
3551
+ 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."
3552
+ },
3517
3553
  // --- Operations ---
3518
3554
  {
3519
3555
  title: "Managers must supervise deployed workers",
@@ -4283,7 +4319,7 @@ init_database();
4283
4319
  // src/lib/keychain.ts
4284
4320
  import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
4285
4321
  import { existsSync as existsSync6, statSync as statSync2 } from "fs";
4286
- import { execSync as execSync2 } from "child_process";
4322
+ import { execSync as execSync3 } from "child_process";
4287
4323
  import path6 from "path";
4288
4324
  import os5 from "os";
4289
4325
  var SERVICE = "exe-os";
@@ -4304,13 +4340,13 @@ function linuxSecretAvailable() {
4304
4340
  if (process.platform !== "linux") return false;
4305
4341
  if (linuxSecretAvailability !== null) return linuxSecretAvailability;
4306
4342
  try {
4307
- execSync2("command -v secret-tool >/dev/null 2>&1", { timeout: 1e3 });
4343
+ execSync3("command -v secret-tool >/dev/null 2>&1", { timeout: 1e3 });
4308
4344
  } catch {
4309
4345
  linuxSecretAvailability = false;
4310
4346
  return false;
4311
4347
  }
4312
4348
  try {
4313
- execSync2("secret-tool search --all exe-os probe >/dev/null 2>&1", { timeout: 1e3 });
4349
+ execSync3("secret-tool search --all exe-os probe >/dev/null 2>&1", { timeout: 1e3 });
4314
4350
  linuxSecretAvailability = true;
4315
4351
  } catch {
4316
4352
  linuxSecretAvailability = false;
@@ -4334,7 +4370,7 @@ function macKeychainGet(service = SERVICE) {
4334
4370
  if (!nativeKeychainAllowed()) return null;
4335
4371
  if (process.platform !== "darwin") return null;
4336
4372
  try {
4337
- return execSync2(
4373
+ return execSync3(
4338
4374
  `security find-generic-password -s "${service}" -a "${ACCOUNT}" -w 2>/dev/null`,
4339
4375
  { encoding: "utf-8", timeout: 5e3 }
4340
4376
  ).trim();
@@ -4347,13 +4383,13 @@ function macKeychainSet(value, service = SERVICE) {
4347
4383
  if (process.platform !== "darwin") return false;
4348
4384
  try {
4349
4385
  try {
4350
- execSync2(
4386
+ execSync3(
4351
4387
  `security delete-generic-password -s "${service}" -a "${ACCOUNT}" 2>/dev/null`,
4352
4388
  { timeout: 5e3 }
4353
4389
  );
4354
4390
  } catch {
4355
4391
  }
4356
- execSync2(
4392
+ execSync3(
4357
4393
  `security add-generic-password -s "${service}" -a "${ACCOUNT}" -w "${value}"`,
4358
4394
  { timeout: 5e3 }
4359
4395
  );
@@ -4366,7 +4402,7 @@ function macKeychainDelete(service = SERVICE) {
4366
4402
  if (!nativeKeychainAllowed()) return false;
4367
4403
  if (process.platform !== "darwin") return false;
4368
4404
  try {
4369
- execSync2(
4405
+ execSync3(
4370
4406
  `security delete-generic-password -s "${service}" -a "${ACCOUNT}" 2>/dev/null`,
4371
4407
  { timeout: 5e3 }
4372
4408
  );
@@ -4378,7 +4414,7 @@ function macKeychainDelete(service = SERVICE) {
4378
4414
  function linuxSecretGet(service = SERVICE) {
4379
4415
  if (!linuxSecretAvailable()) return null;
4380
4416
  try {
4381
- return execSync2(
4417
+ return execSync3(
4382
4418
  `secret-tool lookup service "${service}" account "${ACCOUNT}" 2>/dev/null`,
4383
4419
  { encoding: "utf-8", timeout: 5e3 }
4384
4420
  ).trim();
@@ -4389,7 +4425,7 @@ function linuxSecretGet(service = SERVICE) {
4389
4425
  function linuxSecretSet(value, service = SERVICE) {
4390
4426
  if (!linuxSecretAvailable()) return false;
4391
4427
  try {
4392
- execSync2(
4428
+ execSync3(
4393
4429
  `echo -n "${value}" | secret-tool store --label="exe-os master key" service "${service}" account "${ACCOUNT}" 2>/dev/null`,
4394
4430
  { timeout: 5e3 }
4395
4431
  );
@@ -4402,7 +4438,7 @@ function linuxSecretDelete(service = SERVICE) {
4402
4438
  if (!nativeKeychainAllowed()) return false;
4403
4439
  if (process.platform !== "linux") return false;
4404
4440
  try {
4405
- execSync2(
4441
+ execSync3(
4406
4442
  `secret-tool clear service "${service}" account "${ACCOUNT}" 2>/dev/null`,
4407
4443
  { timeout: 5e3 }
4408
4444
  );
@@ -1134,7 +1134,7 @@ var init_daemon_auth = __esm({
1134
1134
  // src/lib/exe-daemon-client.ts
1135
1135
  import net from "net";
1136
1136
  import os4 from "os";
1137
- import { spawn } from "child_process";
1137
+ import { spawn, execSync as execSync2 } from "child_process";
1138
1138
  import { randomUUID } from "crypto";
1139
1139
  import { existsSync as existsSync5, unlinkSync as unlinkSync2, readFileSync as readFileSync4, openSync, closeSync, statSync } from "fs";
1140
1140
  import path5 from "path";
@@ -1164,6 +1164,14 @@ function handleData(chunk) {
1164
1164
  }
1165
1165
  }
1166
1166
  }
1167
+ function isZombie(pid) {
1168
+ try {
1169
+ const state = execSync2(`ps -p ${pid} -o state=`, { encoding: "utf8", timeout: 2e3 }).trim();
1170
+ return state.startsWith("Z");
1171
+ } catch {
1172
+ return false;
1173
+ }
1174
+ }
1167
1175
  function cleanupStaleFiles() {
1168
1176
  if (existsSync5(PID_PATH)) {
1169
1177
  try {
@@ -1171,7 +1179,11 @@ function cleanupStaleFiles() {
1171
1179
  if (pid > 0) {
1172
1180
  try {
1173
1181
  process.kill(pid, 0);
1174
- return;
1182
+ if (!isZombie(pid)) {
1183
+ return;
1184
+ }
1185
+ process.stderr.write(`[exed-client] PID ${pid} is a zombie \u2014 cleaning up stale files
1186
+ `);
1175
1187
  } catch {
1176
1188
  }
1177
1189
  }
@@ -1199,8 +1211,8 @@ function findPackageRoot() {
1199
1211
  function getAvailableMemoryGB() {
1200
1212
  if (process.platform === "darwin") {
1201
1213
  try {
1202
- const { execSync: execSync11 } = __require("child_process");
1203
- const vmstat = execSync11("vm_stat", { encoding: "utf8" });
1214
+ const { execSync: execSync12 } = __require("child_process");
1215
+ const vmstat = execSync12("vm_stat", { encoding: "utf8" });
1204
1216
  const pageSize = 16384;
1205
1217
  const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
1206
1218
  const actualPageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : pageSize;
@@ -3135,6 +3147,12 @@ async function disposeDatabase() {
3135
3147
  clearInterval(_walCheckpointTimer);
3136
3148
  _walCheckpointTimer = null;
3137
3149
  }
3150
+ if (_client) {
3151
+ try {
3152
+ await _client.execute("PRAGMA wal_checkpoint(PASSIVE)");
3153
+ } catch {
3154
+ }
3155
+ }
3138
3156
  if (_daemonClient) {
3139
3157
  _daemonClient.close();
3140
3158
  _daemonClient = null;
@@ -3251,6 +3269,24 @@ var init_platform_procedures = __esm({
3251
3269
  priority: "p0",
3252
3270
  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."
3253
3271
  },
3272
+ {
3273
+ title: "Bug report status check \u2014 surface available fixes on boot",
3274
+ domain: "support",
3275
+ priority: "p1",
3276
+ 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."
3277
+ },
3278
+ {
3279
+ title: "Feature request triage \u2014 upstream feature vs local customization",
3280
+ domain: "support",
3281
+ priority: "p0",
3282
+ 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."
3283
+ },
3284
+ {
3285
+ title: "Feature request status check \u2014 surface shipped features on boot",
3286
+ domain: "support",
3287
+ priority: "p1",
3288
+ 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."
3289
+ },
3254
3290
  // --- Operations ---
3255
3291
  {
3256
3292
  title: "Managers must supervise deployed workers",
@@ -3453,7 +3489,7 @@ __export(keychain_exports, {
3453
3489
  });
3454
3490
  import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
3455
3491
  import { existsSync as existsSync6, statSync as statSync2 } from "fs";
3456
- import { execSync as execSync2 } from "child_process";
3492
+ import { execSync as execSync3 } from "child_process";
3457
3493
  import path6 from "path";
3458
3494
  import os5 from "os";
3459
3495
  function getKeyDir() {
@@ -3470,13 +3506,13 @@ function linuxSecretAvailable() {
3470
3506
  if (process.platform !== "linux") return false;
3471
3507
  if (linuxSecretAvailability !== null) return linuxSecretAvailability;
3472
3508
  try {
3473
- execSync2("command -v secret-tool >/dev/null 2>&1", { timeout: 1e3 });
3509
+ execSync3("command -v secret-tool >/dev/null 2>&1", { timeout: 1e3 });
3474
3510
  } catch {
3475
3511
  linuxSecretAvailability = false;
3476
3512
  return false;
3477
3513
  }
3478
3514
  try {
3479
- execSync2("secret-tool search --all exe-os probe >/dev/null 2>&1", { timeout: 1e3 });
3515
+ execSync3("secret-tool search --all exe-os probe >/dev/null 2>&1", { timeout: 1e3 });
3480
3516
  linuxSecretAvailability = true;
3481
3517
  } catch {
3482
3518
  linuxSecretAvailability = false;
@@ -3500,7 +3536,7 @@ function macKeychainGet(service = SERVICE) {
3500
3536
  if (!nativeKeychainAllowed()) return null;
3501
3537
  if (process.platform !== "darwin") return null;
3502
3538
  try {
3503
- return execSync2(
3539
+ return execSync3(
3504
3540
  `security find-generic-password -s "${service}" -a "${ACCOUNT}" -w 2>/dev/null`,
3505
3541
  { encoding: "utf-8", timeout: 5e3 }
3506
3542
  ).trim();
@@ -3513,13 +3549,13 @@ function macKeychainSet(value, service = SERVICE) {
3513
3549
  if (process.platform !== "darwin") return false;
3514
3550
  try {
3515
3551
  try {
3516
- execSync2(
3552
+ execSync3(
3517
3553
  `security delete-generic-password -s "${service}" -a "${ACCOUNT}" 2>/dev/null`,
3518
3554
  { timeout: 5e3 }
3519
3555
  );
3520
3556
  } catch {
3521
3557
  }
3522
- execSync2(
3558
+ execSync3(
3523
3559
  `security add-generic-password -s "${service}" -a "${ACCOUNT}" -w "${value}"`,
3524
3560
  { timeout: 5e3 }
3525
3561
  );
@@ -3532,7 +3568,7 @@ function macKeychainDelete(service = SERVICE) {
3532
3568
  if (!nativeKeychainAllowed()) return false;
3533
3569
  if (process.platform !== "darwin") return false;
3534
3570
  try {
3535
- execSync2(
3571
+ execSync3(
3536
3572
  `security delete-generic-password -s "${service}" -a "${ACCOUNT}" 2>/dev/null`,
3537
3573
  { timeout: 5e3 }
3538
3574
  );
@@ -3544,7 +3580,7 @@ function macKeychainDelete(service = SERVICE) {
3544
3580
  function linuxSecretGet(service = SERVICE) {
3545
3581
  if (!linuxSecretAvailable()) return null;
3546
3582
  try {
3547
- return execSync2(
3583
+ return execSync3(
3548
3584
  `secret-tool lookup service "${service}" account "${ACCOUNT}" 2>/dev/null`,
3549
3585
  { encoding: "utf-8", timeout: 5e3 }
3550
3586
  ).trim();
@@ -3555,7 +3591,7 @@ function linuxSecretGet(service = SERVICE) {
3555
3591
  function linuxSecretSet(value, service = SERVICE) {
3556
3592
  if (!linuxSecretAvailable()) return false;
3557
3593
  try {
3558
- execSync2(
3594
+ execSync3(
3559
3595
  `echo -n "${value}" | secret-tool store --label="exe-os master key" service "${service}" account "${ACCOUNT}" 2>/dev/null`,
3560
3596
  { timeout: 5e3 }
3561
3597
  );
@@ -3568,7 +3604,7 @@ function linuxSecretDelete(service = SERVICE) {
3568
3604
  if (!nativeKeychainAllowed()) return false;
3569
3605
  if (process.platform !== "linux") return false;
3570
3606
  try {
3571
- execSync2(
3607
+ execSync3(
3572
3608
  `secret-tool clear service "${service}" account "${ACCOUNT}" 2>/dev/null`,
3573
3609
  { timeout: 5e3 }
3574
3610
  );
@@ -4502,7 +4538,7 @@ __export(session_registry_exports, {
4502
4538
  registerSession: () => registerSession
4503
4539
  });
4504
4540
  import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3, existsSync as existsSync8 } from "fs";
4505
- import { execSync as execSync3 } from "child_process";
4541
+ import { execSync as execSync4 } from "child_process";
4506
4542
  import path8 from "path";
4507
4543
  import os6 from "os";
4508
4544
  function registerSession(entry) {
@@ -4542,7 +4578,7 @@ function pruneStaleSessions() {
4542
4578
  if (sessions.length === 0) return 0;
4543
4579
  let liveSessions = [];
4544
4580
  try {
4545
- liveSessions = execSync3("tmux list-sessions -F '#{session_name}' 2>/dev/null", {
4581
+ liveSessions = execSync4("tmux list-sessions -F '#{session_name}' 2>/dev/null", {
4546
4582
  encoding: "utf8"
4547
4583
  }).trim().split("\n").filter(Boolean);
4548
4584
  } catch {
@@ -4565,7 +4601,7 @@ var init_session_registry = __esm({
4565
4601
  });
4566
4602
 
4567
4603
  // src/lib/session-key.ts
4568
- import { execSync as execSync4 } from "child_process";
4604
+ import { execSync as execSync5 } from "child_process";
4569
4605
  function normalizeCommand(command) {
4570
4606
  const trimmed = command.trim().toLowerCase();
4571
4607
  const parts = trimmed.split(/[\\/]/);
@@ -4584,7 +4620,7 @@ function resolveRuntimeProcess() {
4584
4620
  let pid = process.ppid;
4585
4621
  for (let i = 0; i < 10; i++) {
4586
4622
  try {
4587
- const info = execSync4(`ps -p ${pid} -o ppid=,comm=`, {
4623
+ const info = execSync5(`ps -p ${pid} -o ppid=,comm=`, {
4588
4624
  encoding: "utf8",
4589
4625
  timeout: 2e3
4590
4626
  }).trim();
@@ -4750,14 +4786,14 @@ var init_transport = __esm({
4750
4786
  });
4751
4787
 
4752
4788
  // src/lib/cc-agent-support.ts
4753
- import { execSync as execSync5 } from "child_process";
4789
+ import { execSync as execSync6 } from "child_process";
4754
4790
  function _resetCcAgentSupportCache() {
4755
4791
  _cachedSupport = null;
4756
4792
  }
4757
4793
  function claudeSupportsAgentFlag() {
4758
4794
  if (_cachedSupport !== null) return _cachedSupport;
4759
4795
  try {
4760
- const helpOutput = execSync5("claude --help 2>&1", {
4796
+ const helpOutput = execSync6("claude --help 2>&1", {
4761
4797
  encoding: "utf-8",
4762
4798
  timeout: 5e3
4763
4799
  });
@@ -5914,7 +5950,7 @@ __export(project_name_exports, {
5914
5950
  _resetCache: () => _resetCache,
5915
5951
  getProjectName: () => getProjectName
5916
5952
  });
5917
- import { execSync as execSync6 } from "child_process";
5953
+ import { execSync as execSync7 } from "child_process";
5918
5954
  import path15 from "path";
5919
5955
  function getProjectName(cwd) {
5920
5956
  const dir = cwd ?? process.cwd();
@@ -5922,7 +5958,7 @@ function getProjectName(cwd) {
5922
5958
  try {
5923
5959
  let repoRoot;
5924
5960
  try {
5925
- const gitCommonDir = execSync6("git rev-parse --path-format=absolute --git-common-dir", {
5961
+ const gitCommonDir = execSync7("git rev-parse --path-format=absolute --git-common-dir", {
5926
5962
  cwd: dir,
5927
5963
  encoding: "utf8",
5928
5964
  timeout: 2e3,
@@ -5930,7 +5966,7 @@ function getProjectName(cwd) {
5930
5966
  }).trim();
5931
5967
  repoRoot = path15.dirname(gitCommonDir);
5932
5968
  } catch {
5933
- repoRoot = execSync6("git rev-parse --show-toplevel", {
5969
+ repoRoot = execSync7("git rev-parse --show-toplevel", {
5934
5970
  cwd: dir,
5935
5971
  encoding: "utf8",
5936
5972
  timeout: 2e3,
@@ -6025,7 +6061,7 @@ var init_session_scope = __esm({
6025
6061
  import crypto4 from "crypto";
6026
6062
  import path16 from "path";
6027
6063
  import os11 from "os";
6028
- import { execSync as execSync7 } from "child_process";
6064
+ import { execSync as execSync8 } from "child_process";
6029
6065
  import { mkdir as mkdir4, writeFile as writeFile4, appendFile } from "fs/promises";
6030
6066
  import { existsSync as existsSync15, readFileSync as readFileSync11 } from "fs";
6031
6067
  async function writeCheckpoint(input) {
@@ -6370,14 +6406,14 @@ function isTmuxSessionAlive(identifier) {
6370
6406
  if (!identifier || identifier === "unknown") return true;
6371
6407
  try {
6372
6408
  if (identifier.startsWith("%")) {
6373
- const output = execSync7("tmux list-panes -a -F '#{pane_id}'", {
6409
+ const output = execSync8("tmux list-panes -a -F '#{pane_id}'", {
6374
6410
  timeout: 2e3,
6375
6411
  encoding: "utf8",
6376
6412
  stdio: ["pipe", "pipe", "pipe"]
6377
6413
  });
6378
6414
  return output.split("\n").some((l) => l.trim() === identifier);
6379
6415
  } else {
6380
- execSync7(`tmux has-session -t ${JSON.stringify(identifier)}`, {
6416
+ execSync8(`tmux has-session -t ${JSON.stringify(identifier)}`, {
6381
6417
  timeout: 2e3,
6382
6418
  stdio: ["pipe", "pipe", "pipe"]
6383
6419
  });
@@ -6386,7 +6422,7 @@ function isTmuxSessionAlive(identifier) {
6386
6422
  } catch {
6387
6423
  if (identifier.startsWith("%")) return true;
6388
6424
  try {
6389
- execSync7("tmux list-sessions", {
6425
+ execSync8("tmux list-sessions", {
6390
6426
  timeout: 2e3,
6391
6427
  stdio: ["pipe", "pipe", "pipe"]
6392
6428
  });
@@ -6401,12 +6437,12 @@ function checkStaleCompletion(taskContext, taskCreatedAt) {
6401
6437
  if (!DELEGATION_KEYWORDS.test(taskContext)) return null;
6402
6438
  try {
6403
6439
  const since = new Date(taskCreatedAt).toISOString();
6404
- const branch = execSync7(
6440
+ const branch = execSync8(
6405
6441
  "git rev-parse --abbrev-ref HEAD 2>/dev/null",
6406
6442
  { encoding: "utf8", timeout: 3e3 }
6407
6443
  ).trim();
6408
6444
  const branchArg = branch && branch !== "HEAD" ? branch : "";
6409
- const commitCount = execSync7(
6445
+ const commitCount = execSync8(
6410
6446
  `git log --oneline --since="${since}" ${branchArg} 2>/dev/null | wc -l`,
6411
6447
  { encoding: "utf8", timeout: 5e3 }
6412
6448
  ).trim();
@@ -8005,7 +8041,7 @@ __export(tmux_routing_exports, {
8005
8041
  spawnEmployee: () => spawnEmployee,
8006
8042
  verifyPaneAtCapacity: () => verifyPaneAtCapacity
8007
8043
  });
8008
- import { execFileSync as execFileSync2, execSync as execSync8 } from "child_process";
8044
+ import { execFileSync as execFileSync2, execSync as execSync9 } from "child_process";
8009
8045
  import { readFileSync as readFileSync12, writeFileSync as writeFileSync8, mkdirSync as mkdirSync8, existsSync as existsSync17, appendFileSync, readdirSync as readdirSync4 } from "fs";
8010
8046
  import path20 from "path";
8011
8047
  import os12 from "os";
@@ -8726,7 +8762,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
8726
8762
  let booted = false;
8727
8763
  for (let i = 0; i < 30; i++) {
8728
8764
  try {
8729
- execSync8("sleep 0.5");
8765
+ execSync9("sleep 0.5");
8730
8766
  } catch {
8731
8767
  }
8732
8768
  try {
@@ -10692,7 +10728,7 @@ __export(schedules_exports, {
10692
10728
  parseHumanCron: () => parseHumanCron
10693
10729
  });
10694
10730
  import crypto9 from "crypto";
10695
- import { execSync as execSync10 } from "child_process";
10731
+ import { execSync as execSync11 } from "child_process";
10696
10732
  function isValidCron(cron) {
10697
10733
  const fields = cron.trim().split(/\s+/);
10698
10734
  if (fields.length !== 5) return false;
@@ -10852,7 +10888,7 @@ function addToCrontab(id, cron, prompt, projectDir) {
10852
10888
  const cwd = projectDir ? `cd ${JSON.stringify(projectDir)} && ` : "";
10853
10889
  const escapedPrompt = prompt.replace(/"/g, '\\"');
10854
10890
  const entry = `${cron} ${cwd}claude -p --dangerously-skip-permissions "${escapedPrompt}" # exe-schedule:${id}`;
10855
- execSync10(
10891
+ execSync11(
10856
10892
  `(crontab -l 2>/dev/null; echo ${JSON.stringify(entry)}) | crontab -`,
10857
10893
  { timeout: 5e3, stdio: "ignore" }
10858
10894
  );
@@ -10863,7 +10899,7 @@ function addToCrontab(id, cron, prompt, projectDir) {
10863
10899
  function removeFromCrontab(id) {
10864
10900
  if (!isValidScheduleId(id)) return;
10865
10901
  try {
10866
- execSync10(
10902
+ execSync11(
10867
10903
  `crontab -l 2>/dev/null | grep -v "exe-schedule:${id}" | crontab -`,
10868
10904
  { timeout: 5e3, stdio: "ignore" }
10869
10905
  );
@@ -11428,7 +11464,7 @@ init_notifications();
11428
11464
  init_config();
11429
11465
  init_session_key();
11430
11466
  import { readFileSync as readFileSync13, writeFileSync as writeFileSync9, mkdirSync as mkdirSync9, unlinkSync as unlinkSync7, readdirSync as readdirSync5 } from "fs";
11431
- import { execSync as execSync9 } from "child_process";
11467
+ import { execSync as execSync10 } from "child_process";
11432
11468
  import path21 from "path";
11433
11469
 
11434
11470
  // src/mcp/agent-context.ts
@@ -12178,8 +12214,8 @@ async function boot(options) {
12178
12214
  updatedAt: String(row.updated_at)
12179
12215
  }));
12180
12216
  try {
12181
- const { execSync: execSync11 } = await import("child_process");
12182
- const gitLog = execSync11(
12217
+ const { execSync: execSync12 } = await import("child_process");
12218
+ const gitLog = execSync12(
12183
12219
  "git log --oneline -10 --grep='Co-Authored-By: Claude' --grep='task(' --all-match 2>/dev/null || git log --oneline -5 --grep='Co-Authored-By: Claude' 2>/dev/null || git log --oneline -5 --grep='^task(' 2>/dev/null",
12184
12220
  {
12185
12221
  encoding: "utf8",
@@ -12468,11 +12504,11 @@ async function updateIdleKillSuspectStreak(client, killsToday, liveSessions, tod
12468
12504
  }
12469
12505
  function runSplash() {
12470
12506
  try {
12471
- const { execSync: execSync11 } = __require("child_process");
12507
+ const { execSync: execSync12 } = __require("child_process");
12472
12508
  const { loadConfigSync: loadConfigSync2 } = (init_config(), __toCommonJS(config_exports));
12473
12509
  const config = loadConfigSync2();
12474
12510
  if (!config.splashEffect) return;
12475
- execSync11(
12511
+ execSync12(
12476
12512
  'echo "EXE OS" | python3 -m terminaltexteffects decrypt --typing-speed 2 --ciphertext-colors 6B4C9A F5D76E --final-gradient-stops F5D76E F0EDE8 --final-gradient-direction vertical',
12477
12513
  { stdio: "inherit", timeout: 5e3 }
12478
12514
  );
@@ -315,6 +315,24 @@ var init_platform_procedures = __esm({
315
315
  priority: "p0",
316
316
  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."
317
317
  },
318
+ {
319
+ title: "Bug report status check \u2014 surface available fixes on boot",
320
+ domain: "support",
321
+ priority: "p1",
322
+ 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."
323
+ },
324
+ {
325
+ title: "Feature request triage \u2014 upstream feature vs local customization",
326
+ domain: "support",
327
+ priority: "p0",
328
+ 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."
329
+ },
330
+ {
331
+ title: "Feature request status check \u2014 surface shipped features on boot",
332
+ domain: "support",
333
+ priority: "p1",
334
+ 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."
335
+ },
318
336
  // --- Operations ---
319
337
  {
320
338
  title: "Managers must supervise deployed workers",