@askexenow/exe-os 0.9.86 → 0.9.88

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 (103) hide show
  1. package/deploy/compose/docker-compose.yml +3 -3
  2. package/dist/bin/age-ontology-load.js +8 -2
  3. package/dist/bin/agentic-ontology-backfill.js +29 -0
  4. package/dist/bin/agentic-reflection-backfill.js +29 -0
  5. package/dist/bin/agentic-semantic-label.js +29 -0
  6. package/dist/bin/backfill-conversations.js +30 -0
  7. package/dist/bin/backfill-responses.js +30 -0
  8. package/dist/bin/backfill-vectors.js +30 -0
  9. package/dist/bin/bulk-sync-postgres.js +47 -1
  10. package/dist/bin/cc-doctor.js +3 -2
  11. package/dist/bin/cleanup-stale-review-tasks.js +30 -0
  12. package/dist/bin/cli.js +357 -19
  13. package/dist/bin/exe-agent.js +19 -0
  14. package/dist/bin/exe-assign.js +30 -0
  15. package/dist/bin/exe-boot.js +157 -4
  16. package/dist/bin/exe-call.js +20 -0
  17. package/dist/bin/exe-cloud.js +156 -3
  18. package/dist/bin/exe-dispatch.js +30 -1
  19. package/dist/bin/exe-doctor.js +30 -0
  20. package/dist/bin/exe-export-behaviors.js +29 -0
  21. package/dist/bin/exe-forget.js +30 -0
  22. package/dist/bin/exe-gateway.js +150 -35
  23. package/dist/bin/exe-healthcheck.js +2 -1
  24. package/dist/bin/exe-heartbeat.js +30 -0
  25. package/dist/bin/exe-kill.js +29 -0
  26. package/dist/bin/exe-launch-agent.js +29 -0
  27. package/dist/bin/exe-new-employee.js +37 -4
  28. package/dist/bin/exe-pending-messages.js +29 -0
  29. package/dist/bin/exe-pending-notifications.js +30 -0
  30. package/dist/bin/exe-pending-reviews.js +30 -0
  31. package/dist/bin/exe-rename.js +30 -0
  32. package/dist/bin/exe-review.js +30 -0
  33. package/dist/bin/exe-search.js +30 -0
  34. package/dist/bin/exe-session-cleanup.js +30 -1
  35. package/dist/bin/exe-settings.js +3 -0
  36. package/dist/bin/exe-start-codex.js +31 -2
  37. package/dist/bin/exe-start-opencode.js +31 -2
  38. package/dist/bin/exe-status.js +30 -0
  39. package/dist/bin/exe-team.js +30 -0
  40. package/dist/bin/git-sweep.js +30 -1
  41. package/dist/bin/graph-backfill.js +29 -0
  42. package/dist/bin/graph-export.js +29 -0
  43. package/dist/bin/graph-layer-benchmark.js +9 -1
  44. package/dist/bin/install.js +9 -0
  45. package/dist/bin/intercom-check.js +31 -1
  46. package/dist/bin/list-providers.js +1 -0
  47. package/dist/bin/postgres-agentic-reflection-backfill.js +7 -1
  48. package/dist/bin/postgres-agentic-semantic-backfill.js +7 -1
  49. package/dist/bin/registry-proxy.js +1 -0
  50. package/dist/bin/scan-tasks.js +31 -1
  51. package/dist/bin/setup.js +165 -9
  52. package/dist/bin/shard-migrate.js +29 -0
  53. package/dist/bin/stack-update.js +24 -7
  54. package/dist/bin/update.js +5 -0
  55. package/dist/gateway/index.js +30 -1
  56. package/dist/hooks/bug-report-worker.js +30 -1
  57. package/dist/hooks/codex-stop-task-finalizer.js +30 -1
  58. package/dist/hooks/commit-complete.js +30 -1
  59. package/dist/hooks/error-recall.js +29 -0
  60. package/dist/hooks/ingest.js +29 -0
  61. package/dist/hooks/instructions-loaded.js +29 -0
  62. package/dist/hooks/notification.js +29 -0
  63. package/dist/hooks/post-compact.js +29 -0
  64. package/dist/hooks/post-tool-combined.js +29 -0
  65. package/dist/hooks/pre-compact.js +30 -1
  66. package/dist/hooks/pre-tool-use.js +29 -0
  67. package/dist/hooks/prompt-submit.js +30 -1
  68. package/dist/hooks/session-end.js +30 -1
  69. package/dist/hooks/session-start.js +29 -0
  70. package/dist/hooks/stop.js +29 -0
  71. package/dist/hooks/subagent-stop.js +29 -0
  72. package/dist/hooks/summary-worker.js +155 -3
  73. package/dist/index.js +30 -1
  74. package/dist/lib/cloud-sync.js +136 -2
  75. package/dist/lib/consolidation.js +1 -0
  76. package/dist/lib/database.js +11 -0
  77. package/dist/lib/db.js +11 -0
  78. package/dist/lib/device-registry.js +11 -0
  79. package/dist/lib/employee-templates.js +19 -0
  80. package/dist/lib/exe-daemon.js +1455 -208
  81. package/dist/lib/hybrid-search.js +29 -0
  82. package/dist/lib/identity-templates.js +6 -2
  83. package/dist/lib/identity.js +1 -0
  84. package/dist/lib/messaging.js +2 -1
  85. package/dist/lib/reminders.js +1 -0
  86. package/dist/lib/schedules.js +29 -0
  87. package/dist/lib/skill-learning.js +1 -0
  88. package/dist/lib/store.js +29 -0
  89. package/dist/lib/tasks.js +2 -1
  90. package/dist/lib/tmux-routing.js +2 -1
  91. package/dist/lib/token-spend.js +1 -0
  92. package/dist/mcp/server.js +1278 -165
  93. package/dist/mcp/tools/complete-reminder.js +1 -0
  94. package/dist/mcp/tools/create-reminder.js +1 -0
  95. package/dist/mcp/tools/create-task.js +8 -3
  96. package/dist/mcp/tools/deactivate-behavior.js +1 -0
  97. package/dist/mcp/tools/list-reminders.js +1 -0
  98. package/dist/mcp/tools/list-tasks.js +1 -0
  99. package/dist/mcp/tools/send-message.js +2 -1
  100. package/dist/mcp/tools/update-task.js +2 -1
  101. package/dist/runtime/index.js +30 -1
  102. package/dist/tui/App.js +30 -1
  103. package/package.json +2 -2
@@ -2745,6 +2745,7 @@ __export(database_exports, {
2745
2745
  isInitialized: () => isInitialized,
2746
2746
  setExternalClient: () => setExternalClient
2747
2747
  });
2748
+ import { chmodSync as chmodSync2 } from "fs";
2748
2749
  import { createClient as createClient2 } from "@libsql/client";
2749
2750
  async function initDatabase(config) {
2750
2751
  if (_walCheckpointTimer) {
@@ -2786,6 +2787,16 @@ async function initDatabase(config) {
2786
2787
  if (process.env.DATABASE_URL && process.env.EXE_USE_POSTGRES === "1") {
2787
2788
  _adapterClient = await createPrismaDbAdapter(_resilientClient);
2788
2789
  }
2790
+ try {
2791
+ chmodSync2(config.dbPath, 384);
2792
+ for (const suffix of ["-wal", "-shm"]) {
2793
+ try {
2794
+ chmodSync2(config.dbPath + suffix, 384);
2795
+ } catch {
2796
+ }
2797
+ }
2798
+ } catch {
2799
+ }
2789
2800
  }
2790
2801
  function isInitialized() {
2791
2802
  return _adapterClient !== null || _client !== null;
@@ -4474,6 +4485,24 @@ var init_platform_procedures = __esm({
4474
4485
  priority: "p0",
4475
4486
  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."
4476
4487
  },
4488
+ {
4489
+ title: "Bug report status check \u2014 surface available fixes on boot",
4490
+ domain: "support",
4491
+ priority: "p1",
4492
+ 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."
4493
+ },
4494
+ {
4495
+ title: "Feature request triage \u2014 upstream feature vs local customization",
4496
+ domain: "support",
4497
+ priority: "p0",
4498
+ 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."
4499
+ },
4500
+ {
4501
+ title: "Feature request status check \u2014 surface shipped features on boot",
4502
+ domain: "support",
4503
+ priority: "p1",
4504
+ 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."
4505
+ },
4477
4506
  // --- Operations ---
4478
4507
  {
4479
4508
  title: "Managers must supervise deployed workers",
@@ -5897,6 +5926,7 @@ import { fileURLToPath } from "url";
5897
5926
  function isMainModule(importMetaUrl) {
5898
5927
  if (process.argv[1] == null) return false;
5899
5928
  if (process.argv[1].includes("mcp/server")) return false;
5929
+ if (process.argv[1].includes("exe-daemon")) return false;
5900
5930
  try {
5901
5931
  const scriptPath = realpathSync(process.argv[1]);
5902
5932
  const modulePath = realpathSync(fileURLToPath(importMetaUrl));
@@ -1778,6 +1778,7 @@ __export(database_exports, {
1778
1778
  isInitialized: () => isInitialized,
1779
1779
  setExternalClient: () => setExternalClient
1780
1780
  });
1781
+ import { chmodSync as chmodSync2 } from "fs";
1781
1782
  import { createClient } from "@libsql/client";
1782
1783
  async function initDatabase(config) {
1783
1784
  if (_walCheckpointTimer) {
@@ -1819,6 +1820,16 @@ async function initDatabase(config) {
1819
1820
  if (process.env.DATABASE_URL && process.env.EXE_USE_POSTGRES === "1") {
1820
1821
  _adapterClient = await createPrismaDbAdapter(_resilientClient);
1821
1822
  }
1823
+ try {
1824
+ chmodSync2(config.dbPath, 384);
1825
+ for (const suffix of ["-wal", "-shm"]) {
1826
+ try {
1827
+ chmodSync2(config.dbPath + suffix, 384);
1828
+ } catch {
1829
+ }
1830
+ }
1831
+ } catch {
1832
+ }
1822
1833
  }
1823
1834
  function isInitialized() {
1824
1835
  return _adapterClient !== null || _client !== null;
@@ -4230,6 +4241,24 @@ var init_platform_procedures = __esm({
4230
4241
  priority: "p0",
4231
4242
  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."
4232
4243
  },
4244
+ {
4245
+ title: "Bug report status check \u2014 surface available fixes on boot",
4246
+ domain: "support",
4247
+ priority: "p1",
4248
+ 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."
4249
+ },
4250
+ {
4251
+ title: "Feature request triage \u2014 upstream feature vs local customization",
4252
+ domain: "support",
4253
+ priority: "p0",
4254
+ 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."
4255
+ },
4256
+ {
4257
+ title: "Feature request status check \u2014 surface shipped features on boot",
4258
+ domain: "support",
4259
+ priority: "p1",
4260
+ 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."
4261
+ },
4233
4262
  // --- Operations ---
4234
4263
  {
4235
4264
  title: "Managers must supervise deployed workers",
@@ -1702,6 +1702,7 @@ __export(database_exports, {
1702
1702
  isInitialized: () => isInitialized,
1703
1703
  setExternalClient: () => setExternalClient
1704
1704
  });
1705
+ import { chmodSync as chmodSync2 } from "fs";
1705
1706
  import { createClient } from "@libsql/client";
1706
1707
  async function initDatabase(config) {
1707
1708
  if (_walCheckpointTimer) {
@@ -1743,6 +1744,16 @@ async function initDatabase(config) {
1743
1744
  if (process.env.DATABASE_URL && process.env.EXE_USE_POSTGRES === "1") {
1744
1745
  _adapterClient = await createPrismaDbAdapter(_resilientClient);
1745
1746
  }
1747
+ try {
1748
+ chmodSync2(config.dbPath, 384);
1749
+ for (const suffix of ["-wal", "-shm"]) {
1750
+ try {
1751
+ chmodSync2(config.dbPath + suffix, 384);
1752
+ } catch {
1753
+ }
1754
+ }
1755
+ } catch {
1756
+ }
1746
1757
  }
1747
1758
  function isInitialized() {
1748
1759
  return _adapterClient !== null || _client !== null;
@@ -4154,6 +4165,24 @@ var init_platform_procedures = __esm({
4154
4165
  priority: "p0",
4155
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."
4156
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
+ },
4157
4186
  // --- Operations ---
4158
4187
  {
4159
4188
  title: "Managers must supervise deployed workers",
@@ -5764,6 +5793,7 @@ import { fileURLToPath as fileURLToPath2 } from "url";
5764
5793
  function isMainModule(importMetaUrl) {
5765
5794
  if (process.argv[1] == null) return false;
5766
5795
  if (process.argv[1].includes("mcp/server")) return false;
5796
+ if (process.argv[1].includes("exe-daemon")) return false;
5767
5797
  try {
5768
5798
  const scriptPath = realpathSync(process.argv[1]);
5769
5799
  const modulePath = realpathSync(fileURLToPath2(importMetaUrl));
@@ -26,6 +26,21 @@ var __copyProps = (to, from, except, desc) => {
26
26
  };
27
27
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
28
 
29
+ // src/lib/pg-ssl.ts
30
+ var pg_ssl_exports = {};
31
+ __export(pg_ssl_exports, {
32
+ pgSslConfig: () => pgSslConfig
33
+ });
34
+ function pgSslConfig() {
35
+ if (process.env.EXE_DB_SSL_DISABLED === "true") return {};
36
+ return { ssl: { rejectUnauthorized: process.env.EXE_DB_SSL_ALLOW_SELFSIGNED !== "true" } };
37
+ }
38
+ var init_pg_ssl = __esm({
39
+ "src/lib/pg-ssl.ts"() {
40
+ "use strict";
41
+ }
42
+ });
43
+
29
44
  // src/lib/state-bus.ts
30
45
  var StateBus, orgBus;
31
46
  var init_state_bus = __esm({
@@ -1664,7 +1679,7 @@ var init_memory = __esm({
1664
1679
  });
1665
1680
 
1666
1681
  // src/lib/daemon-auth.ts
1667
- import crypto from "crypto";
1682
+ import crypto2 from "crypto";
1668
1683
  import path6 from "path";
1669
1684
  import { existsSync as existsSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
1670
1685
  function normalizeToken(token) {
@@ -1683,7 +1698,7 @@ function readDaemonToken() {
1683
1698
  function ensureDaemonToken(seed) {
1684
1699
  const existing = readDaemonToken();
1685
1700
  if (existing) return existing;
1686
- const token = normalizeToken(seed) ?? crypto.randomBytes(32).toString("hex");
1701
+ const token = normalizeToken(seed) ?? crypto2.randomBytes(32).toString("hex");
1687
1702
  ensurePrivateDirSync(EXE_AI_DIR);
1688
1703
  writeFileSync3(DAEMON_TOKEN_PATH, `${token}
1689
1704
  `, "utf8");
@@ -2358,6 +2373,7 @@ __export(database_exports, {
2358
2373
  isInitialized: () => isInitialized,
2359
2374
  setExternalClient: () => setExternalClient
2360
2375
  });
2376
+ import { chmodSync as chmodSync2 } from "fs";
2361
2377
  import { createClient } from "@libsql/client";
2362
2378
  async function initDatabase(config2) {
2363
2379
  if (_walCheckpointTimer) {
@@ -2399,6 +2415,16 @@ async function initDatabase(config2) {
2399
2415
  if (process.env.DATABASE_URL && process.env.EXE_USE_POSTGRES === "1") {
2400
2416
  _adapterClient = await createPrismaDbAdapter(_resilientClient);
2401
2417
  }
2418
+ try {
2419
+ chmodSync2(config2.dbPath, 384);
2420
+ for (const suffix of ["-wal", "-shm"]) {
2421
+ try {
2422
+ chmodSync2(config2.dbPath + suffix, 384);
2423
+ } catch {
2424
+ }
2425
+ }
2426
+ } catch {
2427
+ }
2402
2428
  }
2403
2429
  function isInitialized() {
2404
2430
  return _adapterClient !== null || _client !== null;
@@ -3960,7 +3986,7 @@ async function tryKeytar() {
3960
3986
  }
3961
3987
  function deriveMachineKey() {
3962
3988
  try {
3963
- const crypto10 = __require("crypto");
3989
+ const crypto11 = __require("crypto");
3964
3990
  const material = [
3965
3991
  os6.hostname(),
3966
3992
  os6.userInfo().username,
@@ -3969,7 +3995,7 @@ function deriveMachineKey() {
3969
3995
  // Machine ID on Linux (stable across reboots)
3970
3996
  process.platform === "linux" ? readMachineId() : ""
3971
3997
  ].join("|");
3972
- return crypto10.createHash("sha256").update(material).digest();
3998
+ return crypto11.createHash("sha256").update(material).digest();
3973
3999
  } catch {
3974
4000
  return null;
3975
4001
  }
@@ -3983,9 +4009,9 @@ function readMachineId() {
3983
4009
  }
3984
4010
  }
3985
4011
  function encryptWithMachineKey(plaintext, machineKey) {
3986
- const crypto10 = __require("crypto");
3987
- const iv = crypto10.randomBytes(12);
3988
- const cipher = crypto10.createCipheriv("aes-256-gcm", machineKey, iv);
4012
+ const crypto11 = __require("crypto");
4013
+ const iv = crypto11.randomBytes(12);
4014
+ const cipher = crypto11.createCipheriv("aes-256-gcm", machineKey, iv);
3989
4015
  let encrypted = cipher.update(plaintext, "utf-8", "base64");
3990
4016
  encrypted += cipher.final("base64");
3991
4017
  const authTag = cipher.getAuthTag().toString("base64");
@@ -3994,13 +4020,13 @@ function encryptWithMachineKey(plaintext, machineKey) {
3994
4020
  function decryptWithMachineKey(encrypted, machineKey) {
3995
4021
  if (!encrypted.startsWith(ENCRYPTED_PREFIX)) return null;
3996
4022
  try {
3997
- const crypto10 = __require("crypto");
4023
+ const crypto11 = __require("crypto");
3998
4024
  const parts = encrypted.slice(ENCRYPTED_PREFIX.length).split(":");
3999
4025
  if (parts.length !== 3) return null;
4000
4026
  const [ivB64, tagB64, cipherB64] = parts;
4001
4027
  const iv = Buffer.from(ivB64, "base64");
4002
4028
  const authTag = Buffer.from(tagB64, "base64");
4003
- const decipher = crypto10.createDecipheriv("aes-256-gcm", machineKey, iv);
4029
+ const decipher = crypto11.createDecipheriv("aes-256-gcm", machineKey, iv);
4004
4030
  decipher.setAuthTag(authTag);
4005
4031
  let decrypted = decipher.update(cipherB64, "base64", "utf-8");
4006
4032
  decrypted += decipher.final("utf-8");
@@ -4823,6 +4849,24 @@ var init_platform_procedures = __esm({
4823
4849
  priority: "p0",
4824
4850
  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."
4825
4851
  },
4852
+ {
4853
+ title: "Bug report status check \u2014 surface available fixes on boot",
4854
+ domain: "support",
4855
+ priority: "p1",
4856
+ 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."
4857
+ },
4858
+ {
4859
+ title: "Feature request triage \u2014 upstream feature vs local customization",
4860
+ domain: "support",
4861
+ priority: "p0",
4862
+ 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."
4863
+ },
4864
+ {
4865
+ title: "Feature request status check \u2014 surface shipped features on boot",
4866
+ domain: "support",
4867
+ priority: "p1",
4868
+ 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."
4869
+ },
4826
4870
  // --- Operations ---
4827
4871
  {
4828
4872
  title: "Managers must supervise deployed workers",
@@ -6434,13 +6478,13 @@ __export(graph_rag_exports, {
6434
6478
  resolveAlias: () => resolveAlias,
6435
6479
  storeExtraction: () => storeExtraction
6436
6480
  });
6437
- import crypto2 from "crypto";
6481
+ import crypto3 from "crypto";
6438
6482
  function normalizeEntityName(name) {
6439
6483
  return name.replace(/\s*\([^)]*\)\s*/g, "").trim().toLowerCase();
6440
6484
  }
6441
6485
  function entityId(name, type) {
6442
6486
  const normalized = normalizeEntityName(name);
6443
- return crypto2.createHash("sha256").update(`${normalized}::${type.toLowerCase()}`).digest("hex").slice(0, 16);
6487
+ return crypto3.createHash("sha256").update(`${normalized}::${type.toLowerCase()}`).digest("hex").slice(0, 16);
6444
6488
  }
6445
6489
  async function resolveAlias(client, name) {
6446
6490
  const normalized = normalizeEntityName(name);
@@ -6741,7 +6785,7 @@ async function storeExtraction(client, extraction, memoryId, timestamp) {
6741
6785
  const targetAlias = await resolveAlias(client, r.target);
6742
6786
  const sourceId = sourceAlias ?? entityId(r.source, r.sourceType);
6743
6787
  const targetId = targetAlias ?? entityId(r.target, r.targetType);
6744
- const relId = crypto2.randomUUID().slice(0, 16);
6788
+ const relId = crypto3.randomUUID().slice(0, 16);
6745
6789
  try {
6746
6790
  await client.execute({
6747
6791
  sql: `INSERT OR IGNORE INTO entities (id, name, type, first_seen, last_seen)
@@ -6804,7 +6848,7 @@ async function storeExtraction(client, extraction, memoryId, timestamp) {
6804
6848
  }
6805
6849
  }
6806
6850
  for (const h of extraction.hyperedges) {
6807
- const hId = crypto2.randomUUID().slice(0, 16);
6851
+ const hId = crypto3.randomUUID().slice(0, 16);
6808
6852
  try {
6809
6853
  await client.execute({
6810
6854
  sql: `INSERT OR IGNORE INTO hyperedges (id, label, relation, confidence, timestamp)
@@ -6868,7 +6912,7 @@ async function extractBatch(client, batchSize = 50, model = "claude-haiku-4-5-20
6868
6912
  totalEntities += stored.entitiesStored;
6869
6913
  totalRelationships += stored.relationshipsStored;
6870
6914
  }
6871
- const contentHash = crypto2.createHash("sha256").update(rawContent).digest("hex").slice(0, 32);
6915
+ const contentHash = crypto3.createHash("sha256").update(rawContent).digest("hex").slice(0, 32);
6872
6916
  await client.execute({
6873
6917
  sql: "UPDATE memories SET graph_extracted = 1, content_hash = ?, graph_extracted_hash = ? WHERE id = ?",
6874
6918
  args: [contentHash, contentHash, memoryId]
@@ -9708,7 +9752,7 @@ function readQueue() {
9708
9752
  function writeQueue(queue) {
9709
9753
  ensureDir();
9710
9754
  const tmp = `${QUEUE_PATH}.tmp`;
9711
- writeFileSync6(tmp, JSON.stringify(queue, null, 2));
9755
+ writeFileSync6(tmp, JSON.stringify(queue, null, 2), { mode: 384 });
9712
9756
  renameSync4(tmp, QUEUE_PATH);
9713
9757
  }
9714
9758
  function queueIntercom(targetSession, reason) {
@@ -9983,7 +10027,7 @@ var init_task_scope = __esm({
9983
10027
  });
9984
10028
 
9985
10029
  // src/lib/notifications.ts
9986
- import crypto4 from "crypto";
10030
+ import crypto5 from "crypto";
9987
10031
  import path16 from "path";
9988
10032
  import os12 from "os";
9989
10033
  import {
@@ -9996,7 +10040,7 @@ import {
9996
10040
  async function writeNotification(notification) {
9997
10041
  try {
9998
10042
  const client = getClient();
9999
- const id = crypto4.randomUUID();
10043
+ const id = crypto5.randomUUID();
10000
10044
  const now = (/* @__PURE__ */ new Date()).toISOString();
10001
10045
  const sessionScope = notification.sessionScope === void 0 ? getCurrentSessionScope() : notification.sessionScope;
10002
10046
  await client.execute({
@@ -10040,7 +10084,7 @@ var init_notifications = __esm({
10040
10084
  });
10041
10085
 
10042
10086
  // src/lib/session-kill-telemetry.ts
10043
- import crypto5 from "crypto";
10087
+ import crypto6 from "crypto";
10044
10088
  async function recordSessionKill(input) {
10045
10089
  try {
10046
10090
  const client = getClient();
@@ -10050,7 +10094,7 @@ async function recordSessionKill(input) {
10050
10094
  ticks_idle, estimated_tokens_saved)
10051
10095
  VALUES (?, ?, ?, ?, ?, ?, ?)`,
10052
10096
  args: [
10053
- crypto5.randomUUID(),
10097
+ crypto6.randomUUID(),
10054
10098
  input.sessionName,
10055
10099
  input.agentId,
10056
10100
  (/* @__PURE__ */ new Date()).toISOString(),
@@ -10178,7 +10222,7 @@ var init_session_scope = __esm({
10178
10222
  });
10179
10223
 
10180
10224
  // src/lib/tasks-crud.ts
10181
- import crypto6 from "crypto";
10225
+ import crypto7 from "crypto";
10182
10226
  import path18 from "path";
10183
10227
  import os13 from "os";
10184
10228
  import { execSync as execSync7 } from "child_process";
@@ -10299,7 +10343,7 @@ async function resolveTask(client, identifier, scopeSession) {
10299
10343
  }
10300
10344
  async function createTaskCore(input) {
10301
10345
  const client = getClient();
10302
- const id = crypto6.randomUUID();
10346
+ const id = crypto7.randomUUID();
10303
10347
  const now = (/* @__PURE__ */ new Date()).toISOString();
10304
10348
  const slug = slugify(input.title);
10305
10349
  let earlySessionScope = null;
@@ -11264,10 +11308,10 @@ var init_tasks_notify = __esm({
11264
11308
  });
11265
11309
 
11266
11310
  // src/lib/behaviors.ts
11267
- import crypto7 from "crypto";
11311
+ import crypto8 from "crypto";
11268
11312
  async function storeBehavior(opts) {
11269
11313
  const client = getClient();
11270
- const id = crypto7.randomUUID();
11314
+ const id = crypto8.randomUUID();
11271
11315
  const now = (/* @__PURE__ */ new Date()).toISOString();
11272
11316
  let vector = null;
11273
11317
  try {
@@ -11303,7 +11347,7 @@ __export(skill_learning_exports, {
11303
11347
  storeTrajectory: () => storeTrajectory,
11304
11348
  sweepTrajectories: () => sweepTrajectories
11305
11349
  });
11306
- import crypto8 from "crypto";
11350
+ import crypto9 from "crypto";
11307
11351
  async function extractTrajectory(taskId, agentId) {
11308
11352
  const client = getClient();
11309
11353
  const result = await client.execute({
@@ -11332,11 +11376,11 @@ async function extractTrajectory(taskId, agentId) {
11332
11376
  return signature;
11333
11377
  }
11334
11378
  function hashSignature(signature) {
11335
- return crypto8.createHash("sha256").update(signature.join("|")).digest("hex").slice(0, 16);
11379
+ return crypto9.createHash("sha256").update(signature.join("|")).digest("hex").slice(0, 16);
11336
11380
  }
11337
11381
  async function storeTrajectory(opts) {
11338
11382
  const client = getClient();
11339
- const id = crypto8.randomUUID();
11383
+ const id = crypto9.randomUUID();
11340
11384
  const now = (/* @__PURE__ */ new Date()).toISOString();
11341
11385
  const signatureHash = hashSignature(opts.signature);
11342
11386
  await client.execute({
@@ -12907,10 +12951,10 @@ __export(messaging_exports, {
12907
12951
  sendMessage: () => sendMessage,
12908
12952
  setWsClientSend: () => setWsClientSend
12909
12953
  });
12910
- import crypto9 from "crypto";
12954
+ import crypto10 from "crypto";
12911
12955
  function generateUlid() {
12912
12956
  const timestamp = Date.now().toString(36).padStart(10, "0");
12913
- const random = crypto9.randomBytes(10).toString("hex").slice(0, 16);
12957
+ const random = crypto10.randomBytes(10).toString("hex").slice(0, 16);
12914
12958
  return (timestamp + random).toUpperCase();
12915
12959
  }
12916
12960
  function rowToMessage(row) {
@@ -13531,6 +13575,7 @@ import os16 from "os";
13531
13575
  import { fileURLToPath as fileURLToPath3 } from "url";
13532
13576
 
13533
13577
  // src/gateway/webhook-server.ts
13578
+ import crypto from "crypto";
13534
13579
  import {
13535
13580
  createServer
13536
13581
  } from "http";
@@ -13878,7 +13923,7 @@ var ReadOnlySqlRunner = class {
13878
13923
  this.config = config2;
13879
13924
  }
13880
13925
  async run(sql, maxRows) {
13881
- const databaseUrl = this.config.databaseUrl ?? process.env.EXE_GATEWAY_SQL_DATABASE_URL ?? process.env.EXE_COMPANY_BRAIN_SQL_DATABASE_URL ?? process.env.DATABASE_URL;
13926
+ const databaseUrl = this.config.databaseUrl ?? process.env.EXE_GATEWAY_SQL_DATABASE_URL ?? process.env.MCP_READONLY_DATABASE_URL ?? process.env.EXE_COMPANY_BRAIN_SQL_DATABASE_URL ?? process.env.DATABASE_URL;
13882
13927
  if (!databaseUrl) {
13883
13928
  throw new Error("Read-only SQL is not configured. Set EXE_GATEWAY_SQL_DATABASE_URL or DATABASE_URL.");
13884
13929
  }
@@ -13886,7 +13931,8 @@ var ReadOnlySqlRunner = class {
13886
13931
  const limit = clampRows(maxRows ?? this.config.maxRows ?? DEFAULT_MAX_ROWS);
13887
13932
  const timeoutMs = this.config.statementTimeoutMs ?? DEFAULT_TIMEOUT_MS;
13888
13933
  const wrappedSql = `SELECT * FROM (${cleaned}) AS exe_readonly_sql LIMIT ${limit + 1}`;
13889
- const client = new Client({ connectionString: databaseUrl });
13934
+ const { pgSslConfig: pgSslConfig2 } = await Promise.resolve().then(() => (init_pg_ssl(), pg_ssl_exports));
13935
+ const client = new Client({ connectionString: databaseUrl, ...pgSslConfig2() });
13890
13936
  const start = Date.now();
13891
13937
  try {
13892
13938
  await client.connect();
@@ -13949,6 +13995,61 @@ function clampRows(value) {
13949
13995
  // src/gateway/webhook-server.ts
13950
13996
  var DEFAULT_HOST = process.env.EXE_WEBHOOK_HOST || "127.0.0.1";
13951
13997
  var BODY_SIZE_LIMIT = 1048576;
13998
+ function verifyWebhookSignature(rawBody, signature, secret, toleranceSec = 300) {
13999
+ if (!signature) return false;
14000
+ const dotIdx = signature.indexOf(".");
14001
+ if (dotIdx < 0) return false;
14002
+ const timestampStr = signature.slice(0, dotIdx);
14003
+ const hash = signature.slice(dotIdx + 1);
14004
+ const timestamp = parseInt(timestampStr, 10);
14005
+ if (isNaN(timestamp)) return false;
14006
+ if (Math.abs(Date.now() / 1e3 - timestamp) > toleranceSec) return false;
14007
+ const expected = crypto.createHmac("sha256", secret).update(`${timestamp}.${rawBody}`).digest("hex");
14008
+ if (hash.length !== expected.length) return false;
14009
+ return crypto.timingSafeEqual(
14010
+ Buffer.from(hash, "hex"),
14011
+ Buffer.from(expected, "hex")
14012
+ );
14013
+ }
14014
+ function readRawBody(req) {
14015
+ return new Promise((resolve, reject) => {
14016
+ const chunks = [];
14017
+ let size = 0;
14018
+ let done = false;
14019
+ req.on("data", (chunk) => {
14020
+ size += chunk.length;
14021
+ if (size > BODY_SIZE_LIMIT) {
14022
+ if (!done) {
14023
+ done = true;
14024
+ req.resume();
14025
+ reject(new Error("Body too large"));
14026
+ }
14027
+ return;
14028
+ }
14029
+ chunks.push(chunk);
14030
+ });
14031
+ req.on("end", () => {
14032
+ if (done) return;
14033
+ done = true;
14034
+ const raw = Buffer.concat(chunks).toString("utf-8");
14035
+ if (!raw) {
14036
+ resolve({ raw: "", parsed: {} });
14037
+ return;
14038
+ }
14039
+ try {
14040
+ resolve({ raw, parsed: JSON.parse(raw) });
14041
+ } catch {
14042
+ reject(new Error("Invalid JSON"));
14043
+ }
14044
+ });
14045
+ req.on("error", (err) => {
14046
+ if (!done) {
14047
+ done = true;
14048
+ reject(err);
14049
+ }
14050
+ });
14051
+ });
14052
+ }
13952
14053
  var WebhookServer = class {
13953
14054
  constructor(config2, queryHandler = new QueryHandler()) {
13954
14055
  this.config = config2;
@@ -14092,13 +14193,26 @@ var WebhookServer = class {
14092
14193
  }
14093
14194
  async handleWebhookPost(req, res, url) {
14094
14195
  let body;
14196
+ let rawBody = "";
14095
14197
  let parseError = null;
14096
14198
  try {
14097
- body = await readBody(req);
14199
+ const result = await readRawBody(req);
14200
+ rawBody = result.raw;
14201
+ body = result.parsed;
14098
14202
  } catch (err) {
14099
14203
  parseError = err instanceof Error ? err : new Error(String(err));
14100
14204
  }
14101
- if (this.config.authToken && !this.verifyAuth(req)) {
14205
+ if (this.config.webhookSigningSecret) {
14206
+ const sig = req.headers["x-webhook-signature"];
14207
+ if (!verifyWebhookSignature(
14208
+ rawBody,
14209
+ sig,
14210
+ this.config.webhookSigningSecret
14211
+ )) {
14212
+ sendJson(res, 401, { error: "Invalid webhook signature" });
14213
+ return;
14214
+ }
14215
+ } else if (this.config.authToken && !this.verifyAuth(req)) {
14102
14216
  sendJson(res, 401, { error: "Unauthorized" });
14103
14217
  return;
14104
14218
  }
@@ -14142,6 +14256,7 @@ var WebhookServer = class {
14142
14256
  if (!expectedToken) return false;
14143
14257
  const authHeader = req.headers.authorization ?? "";
14144
14258
  if (authHeader === `Bearer ${expectedToken}`) return true;
14259
+ if (process.env.NODE_ENV === "production") return false;
14145
14260
  const url = new URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`);
14146
14261
  return url.searchParams.get("token") === expectedToken;
14147
14262
  }
@@ -14265,11 +14380,11 @@ init_crm_bridge();
14265
14380
 
14266
14381
  // src/lib/pipeline-router.ts
14267
14382
  init_database();
14268
- import crypto3 from "crypto";
14383
+ import crypto4 from "crypto";
14269
14384
  async function sinkConversationStore(msg, agentResponse, agentName) {
14270
14385
  try {
14271
14386
  const client = getClient();
14272
- const id = crypto3.randomUUID();
14387
+ const id = crypto4.randomUUID();
14273
14388
  const mediaJson = msg.media ? JSON.stringify(msg.media) : null;
14274
14389
  await client.execute({
14275
14390
  sql: `INSERT INTO conversations
@@ -14319,7 +14434,7 @@ async function sinkMemory(msg, agentResponse, agentName) {
14319
14434
  ].filter(Boolean).join("\n");
14320
14435
  const vector = await embed2(rawText);
14321
14436
  await writeMemory2({
14322
- id: crypto3.randomUUID(),
14437
+ id: crypto4.randomUUID(),
14323
14438
  agent_id: agentName ?? "gateway",
14324
14439
  agent_role: "gateway",
14325
14440
  session_id: `gateway-${msg.platform}`,
@@ -12,6 +12,7 @@ import { fileURLToPath } from "url";
12
12
  function isMainModule(importMetaUrl) {
13
13
  if (process.argv[1] == null) return false;
14
14
  if (process.argv[1].includes("mcp/server")) return false;
15
+ if (process.argv[1].includes("exe-daemon")) return false;
15
16
  try {
16
17
  const scriptPath = realpathSync(process.argv[1]);
17
18
  const modulePath = realpathSync(fileURLToPath(importMetaUrl));
@@ -587,7 +588,7 @@ function runHealthCheck() {
587
588
  const failed = results.filter((r) => !r.pass).length;
588
589
  return { results, passed, failed };
589
590
  }
590
- if (isMainModule(import.meta.url)) {
591
+ if (isMainModule(import.meta.url) && (process.argv[1] ?? "").includes("exe-healthcheck")) {
591
592
  const { results, passed, failed } = runHealthCheck();
592
593
  console.log("\n exe-os Health Check\n");
593
594
  for (const r of results) {