@askexenow/exe-os 0.9.66 → 0.9.67

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 (99) hide show
  1. package/deploy/stack-manifests/v0.9.json +54 -5
  2. package/dist/bin/age-ontology-load.js +61 -0
  3. package/dist/bin/agentic-ontology-backfill.js +4708 -0
  4. package/dist/bin/agentic-reflection-backfill.js +4144 -0
  5. package/dist/bin/{exe-link.js → agentic-semantic-label.js} +1523 -2275
  6. package/dist/bin/backfill-conversations.js +506 -20
  7. package/dist/bin/backfill-responses.js +506 -20
  8. package/dist/bin/backfill-vectors.js +233 -20
  9. package/dist/bin/bulk-sync-postgres.js +4876 -0
  10. package/dist/bin/cleanup-stale-review-tasks.js +507 -21
  11. package/dist/bin/cli.js +2450 -1530
  12. package/dist/bin/exe-assign.js +506 -20
  13. package/dist/bin/exe-boot.js +410 -60
  14. package/dist/bin/exe-cloud.js +795 -105
  15. package/dist/bin/exe-dispatch.js +516 -22
  16. package/dist/bin/exe-doctor.js +587 -30
  17. package/dist/bin/exe-export-behaviors.js +518 -24
  18. package/dist/bin/exe-forget.js +507 -21
  19. package/dist/bin/exe-gateway.js +571 -25
  20. package/dist/bin/exe-heartbeat.js +518 -24
  21. package/dist/bin/exe-kill.js +507 -21
  22. package/dist/bin/exe-launch-agent.js +2312 -1069
  23. package/dist/bin/exe-new-employee.js +197 -165
  24. package/dist/bin/exe-pending-messages.js +507 -21
  25. package/dist/bin/exe-pending-notifications.js +507 -21
  26. package/dist/bin/exe-pending-reviews.js +507 -21
  27. package/dist/bin/exe-rename.js +507 -21
  28. package/dist/bin/exe-review.js +507 -21
  29. package/dist/bin/exe-search.js +518 -24
  30. package/dist/bin/exe-session-cleanup.js +516 -22
  31. package/dist/bin/exe-settings.js +4 -0
  32. package/dist/bin/exe-start-codex.js +682 -143
  33. package/dist/bin/exe-start-opencode.js +627 -79
  34. package/dist/bin/exe-status.js +507 -21
  35. package/dist/bin/exe-team.js +507 -21
  36. package/dist/bin/git-sweep.js +516 -22
  37. package/dist/bin/graph-backfill.js +558 -21
  38. package/dist/bin/graph-export.js +507 -21
  39. package/dist/bin/graph-layer-benchmark.js +109 -0
  40. package/dist/bin/install.js +305 -288
  41. package/dist/bin/intercom-check.js +516 -22
  42. package/dist/bin/postgres-agentic-reflection-backfill.js +187 -0
  43. package/dist/bin/postgres-agentic-semantic-backfill.js +237 -0
  44. package/dist/bin/scan-tasks.js +516 -22
  45. package/dist/bin/setup.js +412 -62
  46. package/dist/bin/shard-migrate.js +506 -20
  47. package/dist/gateway/index.js +569 -23
  48. package/dist/hooks/bug-report-worker.js +519 -25
  49. package/dist/hooks/codex-stop-task-finalizer.js +516 -22
  50. package/dist/hooks/commit-complete.js +516 -22
  51. package/dist/hooks/error-recall.js +518 -24
  52. package/dist/hooks/ingest.js +516 -22
  53. package/dist/hooks/instructions-loaded.js +507 -21
  54. package/dist/hooks/notification.js +507 -21
  55. package/dist/hooks/post-compact.js +507 -21
  56. package/dist/hooks/post-tool-combined.js +519 -25
  57. package/dist/hooks/pre-compact.js +516 -22
  58. package/dist/hooks/pre-tool-use.js +507 -21
  59. package/dist/hooks/prompt-submit.js +519 -25
  60. package/dist/hooks/session-end.js +516 -22
  61. package/dist/hooks/session-start.js +520 -26
  62. package/dist/hooks/stop.js +517 -23
  63. package/dist/hooks/subagent-stop.js +507 -21
  64. package/dist/hooks/summary-worker.js +411 -61
  65. package/dist/index.js +569 -23
  66. package/dist/lib/cloud-sync.js +391 -53
  67. package/dist/lib/config.js +13 -1
  68. package/dist/lib/consolidation.js +1 -1
  69. package/dist/lib/database.js +124 -0
  70. package/dist/lib/db.js +124 -0
  71. package/dist/lib/device-registry.js +124 -0
  72. package/dist/lib/embedder.js +13 -1
  73. package/dist/lib/exe-daemon.js +2184 -561
  74. package/dist/lib/hybrid-search.js +518 -24
  75. package/dist/lib/identity.js +3 -0
  76. package/dist/lib/keychain.js +178 -22
  77. package/dist/lib/messaging.js +3 -0
  78. package/dist/lib/reminders.js +3 -0
  79. package/dist/lib/schedules.js +233 -20
  80. package/dist/lib/skill-learning.js +16 -1
  81. package/dist/lib/store.js +506 -20
  82. package/dist/lib/tasks.js +16 -1
  83. package/dist/lib/tmux-routing.js +16 -1
  84. package/dist/lib/token-spend.js +3 -0
  85. package/dist/mcp/server.js +1757 -428
  86. package/dist/mcp/tools/complete-reminder.js +3 -0
  87. package/dist/mcp/tools/create-reminder.js +3 -0
  88. package/dist/mcp/tools/create-task.js +16 -1
  89. package/dist/mcp/tools/deactivate-behavior.js +3 -0
  90. package/dist/mcp/tools/list-reminders.js +3 -0
  91. package/dist/mcp/tools/list-tasks.js +3 -0
  92. package/dist/mcp/tools/send-message.js +3 -0
  93. package/dist/mcp/tools/update-task.js +16 -1
  94. package/dist/runtime/index.js +516 -22
  95. package/dist/tui/App.js +594 -29
  96. package/package.json +8 -5
  97. package/src/commands/exe/cloud.md +6 -10
  98. package/stack.release.json +3 -3
  99. package/src/commands/exe/link.md +0 -18
package/dist/index.js CHANGED
@@ -183,6 +183,10 @@ async function loadConfig() {
183
183
  if (config2.dbPath.startsWith("~")) {
184
184
  config2.dbPath = config2.dbPath.replace(/^~/, os2.homedir());
185
185
  }
186
+ const envDbPath = path2.join(dir, "memories.db");
187
+ if (process.env.EXE_OS_DIR && config2.dbPath !== envDbPath && !existsSync2(config2.dbPath) && existsSync2(envDbPath)) {
188
+ config2.dbPath = envDbPath;
189
+ }
186
190
  return config2;
187
191
  } catch {
188
192
  return { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db") };
@@ -203,7 +207,15 @@ function loadConfigSync() {
203
207
  normalizeSessionLifecycle(migratedCfg);
204
208
  normalizeAutoUpdate(migratedCfg);
205
209
  normalizeOrchestration(migratedCfg);
206
- return { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db"), ...migratedCfg };
210
+ const config2 = { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db"), ...migratedCfg };
211
+ if (config2.dbPath.startsWith("~")) {
212
+ config2.dbPath = config2.dbPath.replace(/^~/, os2.homedir());
213
+ }
214
+ const envDbPath = path2.join(dir, "memories.db");
215
+ if (process.env.EXE_OS_DIR && config2.dbPath !== envDbPath && !existsSync2(config2.dbPath) && existsSync2(envDbPath)) {
216
+ config2.dbPath = envDbPath;
217
+ }
218
+ return config2;
207
219
  } catch {
208
220
  return { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db") };
209
221
  }
@@ -2545,6 +2557,9 @@ function getClient() {
2545
2557
  if (_daemonClient && _daemonClient._isDaemonActive()) {
2546
2558
  return _daemonClient;
2547
2559
  }
2560
+ if (!_resilientClient) {
2561
+ return _adapterClient;
2562
+ }
2548
2563
  return _resilientClient;
2549
2564
  }
2550
2565
  async function initDaemonClient() {
@@ -3577,6 +3592,127 @@ async function ensureSchema() {
3577
3592
  VALUES (new.rowid, new.content, new.subject, new.predicate, new.object);
3578
3593
  END;
3579
3594
  `);
3595
+ await client.executeMultiple(`
3596
+ CREATE TABLE IF NOT EXISTS agent_sessions (
3597
+ id TEXT PRIMARY KEY,
3598
+ agent_id TEXT NOT NULL,
3599
+ project_name TEXT,
3600
+ started_at TEXT NOT NULL,
3601
+ last_event_at TEXT NOT NULL,
3602
+ event_count INTEGER NOT NULL DEFAULT 0,
3603
+ properties TEXT DEFAULT '{}'
3604
+ );
3605
+
3606
+ CREATE INDEX IF NOT EXISTS idx_agent_sessions_agent_time
3607
+ ON agent_sessions(agent_id, started_at);
3608
+
3609
+ CREATE TABLE IF NOT EXISTS agent_goals (
3610
+ id TEXT PRIMARY KEY,
3611
+ statement TEXT NOT NULL,
3612
+ owner_agent_id TEXT,
3613
+ project_name TEXT,
3614
+ status TEXT NOT NULL DEFAULT 'open',
3615
+ priority INTEGER NOT NULL DEFAULT 5,
3616
+ success_criteria TEXT,
3617
+ parent_goal_id TEXT,
3618
+ due_at TEXT,
3619
+ achieved_at TEXT,
3620
+ supersedes_id TEXT,
3621
+ created_at TEXT NOT NULL,
3622
+ updated_at TEXT NOT NULL,
3623
+ source_memory_id TEXT
3624
+ );
3625
+
3626
+ CREATE INDEX IF NOT EXISTS idx_agent_goals_project_status
3627
+ ON agent_goals(project_name, status, priority);
3628
+
3629
+ CREATE TABLE IF NOT EXISTS agent_events (
3630
+ id TEXT PRIMARY KEY,
3631
+ event_type TEXT NOT NULL,
3632
+ occurred_at TEXT NOT NULL,
3633
+ sequence_index INTEGER NOT NULL,
3634
+ actor_agent_id TEXT,
3635
+ agent_role TEXT,
3636
+ project_name TEXT,
3637
+ session_id TEXT,
3638
+ task_id TEXT,
3639
+ goal_id TEXT,
3640
+ parent_event_id TEXT,
3641
+ intention TEXT,
3642
+ outcome TEXT,
3643
+ evidence_memory_id TEXT,
3644
+ impact TEXT,
3645
+ payload TEXT DEFAULT '{}',
3646
+ created_at TEXT NOT NULL
3647
+ );
3648
+
3649
+ CREATE INDEX IF NOT EXISTS idx_agent_events_time
3650
+ ON agent_events(occurred_at, sequence_index);
3651
+
3652
+ CREATE INDEX IF NOT EXISTS idx_agent_events_session_seq
3653
+ ON agent_events(session_id, sequence_index);
3654
+
3655
+ CREATE INDEX IF NOT EXISTS idx_agent_events_goal_time
3656
+ ON agent_events(goal_id, occurred_at);
3657
+
3658
+ CREATE INDEX IF NOT EXISTS idx_agent_events_memory
3659
+ ON agent_events(evidence_memory_id);
3660
+
3661
+ CREATE TABLE IF NOT EXISTS agent_goal_links (
3662
+ id TEXT PRIMARY KEY,
3663
+ goal_id TEXT NOT NULL,
3664
+ link_type TEXT NOT NULL,
3665
+ target_id TEXT NOT NULL,
3666
+ target_type TEXT NOT NULL,
3667
+ created_at TEXT NOT NULL
3668
+ );
3669
+
3670
+ CREATE INDEX IF NOT EXISTS idx_agent_goal_links_goal
3671
+ ON agent_goal_links(goal_id, target_type);
3672
+
3673
+ CREATE TABLE IF NOT EXISTS agent_semantic_labels (
3674
+ id TEXT PRIMARY KEY,
3675
+ source_memory_id TEXT NOT NULL,
3676
+ event_id TEXT,
3677
+ labeler TEXT NOT NULL,
3678
+ schema_version INTEGER NOT NULL DEFAULT 1,
3679
+ confidence REAL NOT NULL DEFAULT 0,
3680
+ labels TEXT NOT NULL,
3681
+ created_at TEXT NOT NULL,
3682
+ updated_at TEXT NOT NULL
3683
+ );
3684
+
3685
+ CREATE INDEX IF NOT EXISTS idx_agent_semantic_labels_memory
3686
+ ON agent_semantic_labels(source_memory_id, labeler);
3687
+
3688
+ CREATE INDEX IF NOT EXISTS idx_agent_semantic_labels_event
3689
+ ON agent_semantic_labels(event_id);
3690
+
3691
+ CREATE TABLE IF NOT EXISTS agent_reflection_checkpoints (
3692
+ id TEXT PRIMARY KEY,
3693
+ project_name TEXT,
3694
+ session_id TEXT,
3695
+ window_start_at TEXT NOT NULL,
3696
+ window_end_at TEXT NOT NULL,
3697
+ event_count INTEGER NOT NULL DEFAULT 0,
3698
+ goal_count INTEGER NOT NULL DEFAULT 0,
3699
+ success_count INTEGER NOT NULL DEFAULT 0,
3700
+ failure_count INTEGER NOT NULL DEFAULT 0,
3701
+ risk_count INTEGER NOT NULL DEFAULT 0,
3702
+ summary TEXT NOT NULL,
3703
+ learnings TEXT NOT NULL DEFAULT '[]',
3704
+ next_actions TEXT NOT NULL DEFAULT '[]',
3705
+ evidence_event_ids TEXT NOT NULL DEFAULT '[]',
3706
+ confidence REAL NOT NULL DEFAULT 0,
3707
+ created_at TEXT NOT NULL
3708
+ );
3709
+
3710
+ CREATE INDEX IF NOT EXISTS idx_agent_reflection_project_time
3711
+ ON agent_reflection_checkpoints(project_name, window_end_at);
3712
+
3713
+ CREATE INDEX IF NOT EXISTS idx_agent_reflection_session_time
3714
+ ON agent_reflection_checkpoints(session_id, window_end_at);
3715
+ `);
3580
3716
  try {
3581
3717
  await client.execute({
3582
3718
  sql: `ALTER TABLE memories ADD COLUMN tier INTEGER DEFAULT 3`,
@@ -7035,7 +7171,7 @@ var init_tmux_routing = __esm({
7035
7171
 
7036
7172
  // src/lib/keychain.ts
7037
7173
  import { readFile as readFile4, writeFile as writeFile5, unlink, mkdir as mkdir4, chmod as chmod2 } from "fs/promises";
7038
- import { existsSync as existsSync16 } from "fs";
7174
+ import { existsSync as existsSync16, statSync as statSync2 } from "fs";
7039
7175
  import { execSync as execSync8 } from "child_process";
7040
7176
  import path20 from "path";
7041
7177
  import os13 from "os";
@@ -7045,29 +7181,65 @@ function getKeyDir() {
7045
7181
  function getKeyPath() {
7046
7182
  return path20.join(getKeyDir(), "master.key");
7047
7183
  }
7048
- function macKeychainGet() {
7184
+ function nativeKeychainAllowed() {
7185
+ return process.env.EXE_OS_DISABLE_NATIVE_KEYCHAIN !== "1";
7186
+ }
7187
+ function linuxSecretAvailable() {
7188
+ if (!nativeKeychainAllowed()) return false;
7189
+ if (process.platform !== "linux") return false;
7190
+ if (linuxSecretAvailability !== null) return linuxSecretAvailability;
7191
+ try {
7192
+ execSync8("command -v secret-tool >/dev/null 2>&1", { timeout: 1e3 });
7193
+ } catch {
7194
+ linuxSecretAvailability = false;
7195
+ return false;
7196
+ }
7197
+ try {
7198
+ execSync8("secret-tool search --all exe-os probe >/dev/null 2>&1", { timeout: 1e3 });
7199
+ linuxSecretAvailability = true;
7200
+ } catch {
7201
+ linuxSecretAvailability = false;
7202
+ }
7203
+ return linuxSecretAvailability;
7204
+ }
7205
+ function isRootOnlyTrustedServerKeyFile(keyPath) {
7206
+ if (process.platform !== "linux") return false;
7207
+ try {
7208
+ const uid = typeof os13.userInfo().uid === "number" ? os13.userInfo().uid : -1;
7209
+ const st = statSync2(keyPath);
7210
+ if (!st.isFile() || (st.mode & 63) !== 0) return false;
7211
+ if (uid === 0) return true;
7212
+ const exeOsDir = process.env.EXE_OS_DIR;
7213
+ return Boolean(exeOsDir && path20.resolve(keyPath).startsWith(path20.resolve(exeOsDir) + path20.sep));
7214
+ } catch {
7215
+ return false;
7216
+ }
7217
+ }
7218
+ function macKeychainGet(service = SERVICE) {
7219
+ if (!nativeKeychainAllowed()) return null;
7049
7220
  if (process.platform !== "darwin") return null;
7050
7221
  try {
7051
7222
  return execSync8(
7052
- `security find-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w 2>/dev/null`,
7223
+ `security find-generic-password -s "${service}" -a "${ACCOUNT}" -w 2>/dev/null`,
7053
7224
  { encoding: "utf-8", timeout: 5e3 }
7054
7225
  ).trim();
7055
7226
  } catch {
7056
7227
  return null;
7057
7228
  }
7058
7229
  }
7059
- function macKeychainSet(value) {
7230
+ function macKeychainSet(value, service = SERVICE) {
7231
+ if (!nativeKeychainAllowed()) return false;
7060
7232
  if (process.platform !== "darwin") return false;
7061
7233
  try {
7062
7234
  try {
7063
7235
  execSync8(
7064
- `security delete-generic-password -s "${SERVICE}" -a "${ACCOUNT}" 2>/dev/null`,
7236
+ `security delete-generic-password -s "${service}" -a "${ACCOUNT}" 2>/dev/null`,
7065
7237
  { timeout: 5e3 }
7066
7238
  );
7067
7239
  } catch {
7068
7240
  }
7069
7241
  execSync8(
7070
- `security add-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w "${value}"`,
7242
+ `security add-generic-password -s "${service}" -a "${ACCOUNT}" -w "${value}"`,
7071
7243
  { timeout: 5e3 }
7072
7244
  );
7073
7245
  return true;
@@ -7075,22 +7247,48 @@ function macKeychainSet(value) {
7075
7247
  return false;
7076
7248
  }
7077
7249
  }
7078
- function linuxSecretGet() {
7079
- if (process.platform !== "linux") return null;
7250
+ function macKeychainDelete(service = SERVICE) {
7251
+ if (!nativeKeychainAllowed()) return false;
7252
+ if (process.platform !== "darwin") return false;
7253
+ try {
7254
+ execSync8(
7255
+ `security delete-generic-password -s "${service}" -a "${ACCOUNT}" 2>/dev/null`,
7256
+ { timeout: 5e3 }
7257
+ );
7258
+ return true;
7259
+ } catch {
7260
+ return false;
7261
+ }
7262
+ }
7263
+ function linuxSecretGet(service = SERVICE) {
7264
+ if (!linuxSecretAvailable()) return null;
7080
7265
  try {
7081
7266
  return execSync8(
7082
- `secret-tool lookup service "${SERVICE}" account "${ACCOUNT}" 2>/dev/null`,
7267
+ `secret-tool lookup service "${service}" account "${ACCOUNT}" 2>/dev/null`,
7083
7268
  { encoding: "utf-8", timeout: 5e3 }
7084
7269
  ).trim();
7085
7270
  } catch {
7086
7271
  return null;
7087
7272
  }
7088
7273
  }
7089
- function linuxSecretSet(value) {
7274
+ function linuxSecretSet(value, service = SERVICE) {
7275
+ if (!linuxSecretAvailable()) return false;
7276
+ try {
7277
+ execSync8(
7278
+ `echo -n "${value}" | secret-tool store --label="exe-os master key" service "${service}" account "${ACCOUNT}" 2>/dev/null`,
7279
+ { timeout: 5e3 }
7280
+ );
7281
+ return true;
7282
+ } catch {
7283
+ return false;
7284
+ }
7285
+ }
7286
+ function linuxSecretDelete(service = SERVICE) {
7287
+ if (!nativeKeychainAllowed()) return false;
7090
7288
  if (process.platform !== "linux") return false;
7091
7289
  try {
7092
7290
  execSync8(
7093
- `echo -n "${value}" | secret-tool store --label="exe-os master key" service "${SERVICE}" account "${ACCOUNT}"`,
7291
+ `secret-tool clear service "${service}" account "${ACCOUNT}" 2>/dev/null`,
7094
7292
  { timeout: 5e3 }
7095
7293
  );
7096
7294
  return true;
@@ -7099,6 +7297,7 @@ function linuxSecretSet(value) {
7099
7297
  }
7100
7298
  }
7101
7299
  async function tryKeytar() {
7300
+ if (!nativeKeychainAllowed()) return null;
7102
7301
  try {
7103
7302
  return await import("keytar");
7104
7303
  } catch {
@@ -7172,7 +7371,19 @@ async function writeMachineBoundFileFallback(b64) {
7172
7371
  return "plaintext";
7173
7372
  }
7174
7373
  async function getMasterKey() {
7175
- const nativeValue = macKeychainGet() ?? linuxSecretGet();
7374
+ let nativeValue = macKeychainGet() ?? linuxSecretGet();
7375
+ if (!nativeValue) {
7376
+ const legacyValue = macKeychainGet(LEGACY_SERVICE) ?? linuxSecretGet(LEGACY_SERVICE);
7377
+ if (legacyValue) {
7378
+ const migrated = macKeychainSet(legacyValue) || linuxSecretSet(legacyValue);
7379
+ if (migrated) {
7380
+ macKeychainDelete(LEGACY_SERVICE);
7381
+ linuxSecretDelete(LEGACY_SERVICE);
7382
+ process.stderr.write("[keychain] Migrated keychain service from exe-mem to exe-os.\n");
7383
+ }
7384
+ nativeValue = legacyValue;
7385
+ }
7386
+ }
7176
7387
  if (nativeValue) {
7177
7388
  return Buffer.from(nativeValue, "base64");
7178
7389
  }
@@ -7180,12 +7391,17 @@ async function getMasterKey() {
7180
7391
  if (keytar) {
7181
7392
  try {
7182
7393
  const keytarValue = await keytar.getPassword(SERVICE, ACCOUNT);
7183
- if (keytarValue) {
7184
- const migrated = macKeychainSet(keytarValue) || linuxSecretSet(keytarValue);
7394
+ const legacyKeytarValue = keytarValue ?? await keytar.getPassword(LEGACY_SERVICE, ACCOUNT);
7395
+ if (legacyKeytarValue) {
7396
+ const migrated = macKeychainSet(legacyKeytarValue) || linuxSecretSet(legacyKeytarValue);
7185
7397
  if (migrated) {
7186
7398
  process.stderr.write("[keychain] Migrated key from keytar to native keychain.\n");
7399
+ try {
7400
+ await keytar.deletePassword(LEGACY_SERVICE, ACCOUNT);
7401
+ } catch {
7402
+ }
7187
7403
  }
7188
- return Buffer.from(keytarValue, "base64");
7404
+ return Buffer.from(legacyKeytarValue, "base64");
7189
7405
  }
7190
7406
  } catch {
7191
7407
  }
@@ -7210,7 +7426,7 @@ async function getMasterKey() {
7210
7426
  const decrypted = decryptWithMachineKey(content, machineKey);
7211
7427
  if (!decrypted) {
7212
7428
  process.stderr.write(
7213
- "[keychain] Key decryption failed \u2014 machine may have changed.\n Use your 24-word recovery phrase: exe-os link import\n"
7429
+ "[keychain] Key decryption failed \u2014 machine may have changed.\n Use your 24-word recovery phrase during setup: exe-os setup\n"
7214
7430
  );
7215
7431
  return null;
7216
7432
  }
@@ -7219,6 +7435,9 @@ async function getMasterKey() {
7219
7435
  b64Value = content;
7220
7436
  }
7221
7437
  const key = Buffer.from(b64Value, "base64");
7438
+ if (!content.startsWith(ENCRYPTED_PREFIX) && isRootOnlyTrustedServerKeyFile(keyPath)) {
7439
+ return key;
7440
+ }
7222
7441
  const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
7223
7442
  if (migrated) {
7224
7443
  process.stderr.write("[keychain] Migrated key from file to native keychain.\n");
@@ -7246,12 +7465,14 @@ async function getMasterKey() {
7246
7465
  return null;
7247
7466
  }
7248
7467
  }
7249
- var SERVICE, ACCOUNT, ENCRYPTED_PREFIX;
7468
+ var SERVICE, LEGACY_SERVICE, ACCOUNT, linuxSecretAvailability, ENCRYPTED_PREFIX;
7250
7469
  var init_keychain = __esm({
7251
7470
  "src/lib/keychain.ts"() {
7252
7471
  "use strict";
7253
- SERVICE = "exe-mem";
7472
+ SERVICE = "exe-os";
7473
+ LEGACY_SERVICE = "exe-mem";
7254
7474
  ACCOUNT = "master-key";
7475
+ linuxSecretAvailability = null;
7255
7476
  ENCRYPTED_PREFIX = "enc:";
7256
7477
  }
7257
7478
  });
@@ -7466,7 +7687,7 @@ __export(shard_manager_exports, {
7466
7687
  shardExists: () => shardExists
7467
7688
  });
7468
7689
  import path21 from "path";
7469
- import { existsSync as existsSync17, mkdirSync as mkdirSync8, readdirSync as readdirSync4, renameSync as renameSync4, statSync as statSync2 } from "fs";
7690
+ import { existsSync as existsSync17, mkdirSync as mkdirSync8, readdirSync as readdirSync4, renameSync as renameSync4, statSync as statSync3 } from "fs";
7470
7691
  import { createClient as createClient2 } from "@libsql/client";
7471
7692
  function initShardManager(encryptionKey) {
7472
7693
  _encryptionKey = encryptionKey;
@@ -7530,7 +7751,7 @@ async function auditShardHealth(options = {}) {
7530
7751
  const shards = [];
7531
7752
  for (const name of names) {
7532
7753
  const dbPath = path21.join(SHARDS_DIR, `${name}.db`);
7533
- const stat = statSync2(dbPath);
7754
+ const stat = statSync3(dbPath);
7534
7755
  const item = {
7535
7756
  name,
7536
7757
  path: dbPath,
@@ -7783,7 +8004,7 @@ async function getReadyShardClient(projectName) {
7783
8004
  _shardLastAccess.delete(safeName);
7784
8005
  const dbPath = path21.join(SHARDS_DIR, `${safeName}.db`);
7785
8006
  if (existsSync17(dbPath)) {
7786
- const stat = statSync2(dbPath);
8007
+ const stat = statSync3(dbPath);
7787
8008
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
7788
8009
  const archivedPath = path21.join(SHARDS_DIR, `${safeName}.db.broken-${stamp}`);
7789
8010
  renameSync4(dbPath, archivedPath);
@@ -8290,6 +8511,274 @@ var init_memory_cards = __esm({
8290
8511
  }
8291
8512
  });
8292
8513
 
8514
+ // src/lib/agentic-ontology.ts
8515
+ var agentic_ontology_exports = {};
8516
+ __export(agentic_ontology_exports, {
8517
+ clean: () => clean,
8518
+ extractGoalCandidates: () => extractGoalCandidates,
8519
+ inferIntention: () => inferIntention,
8520
+ inferOntologyEventType: () => inferOntologyEventType,
8521
+ inferOutcome: () => inferOutcome,
8522
+ inferSemanticLabel: () => inferSemanticLabel,
8523
+ insertOntologyForBatch: () => insertOntologyForBatch,
8524
+ insertOntologyForMemory: () => insertOntologyForMemory,
8525
+ ontologyPayload: () => ontologyPayload,
8526
+ stableId: () => stableId2
8527
+ });
8528
+ import { createHash as createHash3 } from "crypto";
8529
+ function stableId2(...parts) {
8530
+ return createHash3("sha256").update(parts.map((p) => String(p ?? "")).join("::")).digest("hex").slice(0, 32);
8531
+ }
8532
+ function clean(text, max = 240) {
8533
+ return text.replace(/\u0000/g, "").replace(/```[\s\S]*?```/g, " ").replace(/\s+/g, " ").trim().slice(0, max);
8534
+ }
8535
+ function inferOntologyEventType(row) {
8536
+ const lower = row.raw_text.toLowerCase();
8537
+ if (row.has_error) return "error";
8538
+ if (/\b(done|complete|completed|fixed|resolved|shipped|deployed|pushed|published)\b/.test(lower)) return "milestone";
8539
+ if (/\b(blocked|failed|error|bug|regression|broken)\b/.test(lower)) return "problem";
8540
+ if (/\b(decided|decision|adr|we chose|approved|rejected)\b/.test(lower)) return "decision";
8541
+ if (/\b(goal|need to|we need|want to|trying to|objective)\b/.test(lower)) return "goal_signal";
8542
+ if (["Bash", "Read", "Edit", "Write", "Grep", "Glob"].includes(row.tool_name)) return "tool_action";
8543
+ if (row.tool_name.startsWith("memory_card")) return "memory_card";
8544
+ return "memory_observation";
8545
+ }
8546
+ function inferIntention(row) {
8547
+ if (row.intent) return clean(row.intent, 220);
8548
+ const text = clean(row.raw_text, 1e3);
8549
+ const patterns = [
8550
+ /(?:we need to|need to|let'?s|i want to|we should|goal is to|objective is to|trying to)\s+([^.!?\n]{8,220})/i,
8551
+ /(?:so that|in order to)\s+([^.!?\n]{8,220})/i,
8552
+ /(?:task|plan):\s*([^.!?\n]{8,220})/i
8553
+ ];
8554
+ for (const p of patterns) {
8555
+ const m = text.match(p);
8556
+ if (m?.[1]) return clean(m[1], 220);
8557
+ }
8558
+ if (["Bash", "Read", "Edit", "Write", "Grep", "Glob"].includes(row.tool_name)) {
8559
+ return `${row.tool_name} during ${row.project_name}`;
8560
+ }
8561
+ return null;
8562
+ }
8563
+ function inferOutcome(row) {
8564
+ if (row.outcome) return clean(row.outcome, 220);
8565
+ if (row.has_error) return "error";
8566
+ const lower = row.raw_text.toLowerCase();
8567
+ if (/\b(done|complete|completed|fixed|resolved|shipped|deployed|pushed|published|passed)\b/.test(lower)) return "success_signal";
8568
+ if (/\b(blocked|failed|error|regression|broken|not working|could not)\b/.test(lower)) return "failure_signal";
8569
+ if (/\b(warning|risk|concern|caveat)\b/.test(lower)) return "risk_signal";
8570
+ return null;
8571
+ }
8572
+ function extractGoalCandidates(row) {
8573
+ const text = clean(row.raw_text, 1600);
8574
+ const patterns = [
8575
+ /(?:we need to|need to|i want to|we should|goal is to|objective is to|trying to|let'?s)\s+([^.!?\n]{12,220})/gi,
8576
+ /(?:success means|success criteria|so that)\s+([^.!?\n]{12,220})/gi
8577
+ ];
8578
+ const out = [];
8579
+ for (const pattern of patterns) {
8580
+ for (const m of text.matchAll(pattern)) {
8581
+ const candidate = clean(m[1] ?? "", 220);
8582
+ if (candidate.length >= 12 && !out.some((x) => x.toLowerCase() === candidate.toLowerCase())) out.push(candidate);
8583
+ if (out.length >= 3) return out;
8584
+ }
8585
+ }
8586
+ return out;
8587
+ }
8588
+ function uniq(values, max = 6) {
8589
+ const out = [];
8590
+ for (const value of values.map((v) => clean(v, 220)).filter(Boolean)) {
8591
+ if (!out.some((x) => x.toLowerCase() === value.toLowerCase())) out.push(value);
8592
+ if (out.length >= max) break;
8593
+ }
8594
+ return out;
8595
+ }
8596
+ function extractMatches(text, patterns, max = 5) {
8597
+ const out = [];
8598
+ for (const pattern of patterns) {
8599
+ for (const match of text.matchAll(pattern)) {
8600
+ const value = match[1] ?? match[0];
8601
+ if (value) out.push(value);
8602
+ if (out.length >= max) return uniq(out, max);
8603
+ }
8604
+ }
8605
+ return uniq(out, max);
8606
+ }
8607
+ function inferSemanticLabel(row) {
8608
+ const text = clean(row.raw_text, 2400);
8609
+ const eventType = inferOntologyEventType(row);
8610
+ const intention = inferIntention(row);
8611
+ const outcome = inferOutcome(row);
8612
+ const goals = extractGoalCandidates(row);
8613
+ const milestones = extractMatches(text, [
8614
+ /\b(?:completed|finished|fixed|resolved|shipped|deployed|published|pushed|passed)\b([^.!?\n]{0,180})/gi,
8615
+ /(?:milestone|done):\s*([^.!?\n]{8,220})/gi
8616
+ ]);
8617
+ const problems = extractMatches(text, [
8618
+ /\b(?:blocked by|failed because|bug|regression|broken|not working|error)\b([^.!?\n]{0,180})/gi,
8619
+ /(?:problem|issue|risk):\s*([^.!?\n]{8,220})/gi
8620
+ ]);
8621
+ const decisions = extractMatches(text, [
8622
+ /(?:decided|decision|adr|we chose|approved|rejected)\s+([^.!?\n]{8,220})/gi
8623
+ ]);
8624
+ const temporalAnchors = extractMatches(text, [
8625
+ /\b(\d{4}-\d{2}-\d{2}(?:[T ][0-9:.+-Z]+)?)\b/g,
8626
+ /\b(today|yesterday|tomorrow|this week|next week|last week|morning|afternoon|tonight)\b/gi
8627
+ ], 8);
8628
+ const nextActions = extractMatches(text, [
8629
+ /(?:next|todo|follow[- ]?up|remaining|need to)\s*:?\s*([^.!?\n]{8,220})/gi
8630
+ ]);
8631
+ const actors = uniq([
8632
+ row.agent_id,
8633
+ ...extractMatches(text, [/\b(?:agent|employee|owner|assignee)[:= ]+([a-zA-Z][a-zA-Z0-9_-]{1,40})/gi], 5)
8634
+ ], 6);
8635
+ const successSignals = milestones.length ? milestones : outcome === "success_signal" ? [clean(text, 180)] : [];
8636
+ const failureSignals = problems.length ? problems : outcome === "failure_signal" || row.has_error ? [clean(text, 180)] : [];
8637
+ const impact = successSignals.length && failureSignals.length ? "mixed" : failureSignals.length ? "negative" : successSignals.length ? "positive" : "neutral";
8638
+ const signalCount = goals.length + milestones.length + problems.length + decisions.length + nextActions.length;
8639
+ return {
8640
+ labeler: "deterministic",
8641
+ schemaVersion: 1,
8642
+ eventType,
8643
+ intention,
8644
+ outcome,
8645
+ impact,
8646
+ confidence: Math.min(0.95, 0.45 + signalCount * 0.08 + (intention ? 0.1 : 0) + (outcome ? 0.1 : 0)),
8647
+ goals,
8648
+ milestones,
8649
+ problems,
8650
+ decisions,
8651
+ actors,
8652
+ temporalAnchors,
8653
+ successSignals,
8654
+ failureSignals,
8655
+ nextActions,
8656
+ summary: clean(text, 280)
8657
+ };
8658
+ }
8659
+ function ontologyPayload(row) {
8660
+ const semantic = inferSemanticLabel(row);
8661
+ return {
8662
+ tool_name: row.tool_name,
8663
+ memory_version: row.version ?? null,
8664
+ domain: row.domain ?? null,
8665
+ trajectory: row.trajectory ? safeJson(row.trajectory) : null,
8666
+ semantic
8667
+ };
8668
+ }
8669
+ function safeJson(value) {
8670
+ try {
8671
+ return JSON.parse(value);
8672
+ } catch {
8673
+ return value.slice(0, 1e3);
8674
+ }
8675
+ }
8676
+ async function resolveClient(client) {
8677
+ if (client) return client;
8678
+ const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
8679
+ return getClient2();
8680
+ }
8681
+ async function insertOntologyForMemory(row, client) {
8682
+ const db = await resolveClient(client);
8683
+ const occurredAt = row.timestamp;
8684
+ const sequence = Number(row.version ?? 0) || Math.floor(new Date(occurredAt).getTime() / 1e3);
8685
+ const eventType = inferOntologyEventType(row);
8686
+ const intention = inferIntention(row);
8687
+ const outcome = inferOutcome(row);
8688
+ const eventId = stableId2("event", row.id);
8689
+ const now = (/* @__PURE__ */ new Date()).toISOString();
8690
+ await db.execute({
8691
+ sql: `INSERT INTO agent_sessions (id, agent_id, project_name, started_at, last_event_at, event_count, properties)
8692
+ VALUES (?, ?, ?, ?, ?, 1, ?)
8693
+ ON CONFLICT(id) DO UPDATE SET last_event_at = MAX(last_event_at, excluded.last_event_at),
8694
+ event_count = event_count + 1`,
8695
+ args: [row.session_id, row.agent_id, row.project_name, occurredAt, occurredAt, JSON.stringify({ agent_role: row.agent_role })]
8696
+ });
8697
+ await db.execute({
8698
+ sql: `INSERT OR IGNORE INTO agent_events
8699
+ (id, event_type, occurred_at, sequence_index, actor_agent_id, agent_role, project_name,
8700
+ session_id, task_id, goal_id, parent_event_id, intention, outcome, evidence_memory_id,
8701
+ impact, payload, created_at)
8702
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, NULL, ?, ?, ?, ?, ?, ?)`,
8703
+ args: [
8704
+ eventId,
8705
+ eventType,
8706
+ occurredAt,
8707
+ sequence,
8708
+ row.agent_id,
8709
+ row.agent_role,
8710
+ row.project_name,
8711
+ row.session_id,
8712
+ row.task_id ?? null,
8713
+ intention,
8714
+ outcome,
8715
+ row.id,
8716
+ row.has_error ? "negative" : outcome === "success_signal" ? "positive" : "neutral",
8717
+ JSON.stringify(ontologyPayload(row)),
8718
+ now
8719
+ ]
8720
+ });
8721
+ const semantic = inferSemanticLabel(row);
8722
+ await db.execute({
8723
+ sql: `INSERT INTO agent_semantic_labels
8724
+ (id, source_memory_id, event_id, labeler, schema_version, confidence, labels, created_at, updated_at)
8725
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
8726
+ ON CONFLICT(id) DO UPDATE SET confidence = excluded.confidence,
8727
+ labels = excluded.labels, updated_at = excluded.updated_at`,
8728
+ args: [
8729
+ stableId2("semantic", row.id, semantic.labeler, semantic.schemaVersion),
8730
+ row.id,
8731
+ eventId,
8732
+ semantic.labeler,
8733
+ semantic.schemaVersion,
8734
+ semantic.confidence,
8735
+ JSON.stringify(semantic),
8736
+ now,
8737
+ now
8738
+ ]
8739
+ });
8740
+ for (const statement of extractGoalCandidates(row)) {
8741
+ const goalId = stableId2("goal", row.project_name, statement.toLowerCase());
8742
+ await db.execute({
8743
+ sql: `INSERT INTO agent_goals
8744
+ (id, statement, owner_agent_id, project_name, status, priority, success_criteria,
8745
+ parent_goal_id, due_at, achieved_at, supersedes_id, created_at, updated_at, source_memory_id)
8746
+ VALUES (?, ?, ?, ?, 'open', 5, NULL, NULL, NULL, NULL, NULL, ?, ?, ?)
8747
+ ON CONFLICT(id) DO UPDATE SET updated_at = excluded.updated_at`,
8748
+ args: [goalId, statement, row.agent_id, row.project_name, now, now, row.id]
8749
+ });
8750
+ await db.execute({
8751
+ sql: `INSERT OR IGNORE INTO agent_goal_links
8752
+ (id, goal_id, link_type, target_id, target_type, created_at)
8753
+ VALUES (?, ?, 'evidence', ?, 'memory', ?)`,
8754
+ args: [stableId2("goal_link", goalId, row.id, "memory"), goalId, row.id, now]
8755
+ });
8756
+ await db.execute({
8757
+ sql: `INSERT OR IGNORE INTO agent_goal_links
8758
+ (id, goal_id, link_type, target_id, target_type, created_at)
8759
+ VALUES (?, ?, 'event', ?, 'event', ?)`,
8760
+ args: [stableId2("goal_link", goalId, eventId, "event"), goalId, eventId, now]
8761
+ });
8762
+ }
8763
+ }
8764
+ async function insertOntologyForBatch(rows, client) {
8765
+ const db = await resolveClient(client);
8766
+ let count = 0;
8767
+ for (const row of rows) {
8768
+ try {
8769
+ await insertOntologyForMemory(row, db);
8770
+ count++;
8771
+ } catch {
8772
+ }
8773
+ }
8774
+ return count;
8775
+ }
8776
+ var init_agentic_ontology = __esm({
8777
+ "src/lib/agentic-ontology.ts"() {
8778
+ "use strict";
8779
+ }
8780
+ });
8781
+
8293
8782
  // src/lib/store.ts
8294
8783
  var store_exports = {};
8295
8784
  __export(store_exports, {
@@ -8633,6 +9122,11 @@ async function flushBatch() {
8633
9122
  await insertMemoryCardsForBatch2(batch);
8634
9123
  } catch {
8635
9124
  }
9125
+ try {
9126
+ const { insertOntologyForBatch: insertOntologyForBatch2 } = await Promise.resolve().then(() => (init_agentic_ontology(), agentic_ontology_exports));
9127
+ await insertOntologyForBatch2(batch);
9128
+ } catch {
9129
+ }
8636
9130
  schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
8637
9131
  _pendingRecords.splice(0, batch.length);
8638
9132
  try {
@@ -9841,6 +10335,7 @@ __export(graph_rag_exports, {
9841
10335
  extractBatch: () => extractBatch,
9842
10336
  extractFromCode: () => extractFromCode,
9843
10337
  extractFromMemory: () => extractFromMemory,
10338
+ extractHeuristicMemoryGraph: () => extractHeuristicMemoryGraph,
9844
10339
  mergeEntities: () => mergeEntities,
9845
10340
  normalizeEntityName: () => normalizeEntityName,
9846
10341
  registerAlias: () => registerAlias,
@@ -9996,6 +10491,57 @@ function extractFromCode(source, filePath) {
9996
10491
  }
9997
10492
  return { entities, relationships, hyperedges: [] };
9998
10493
  }
10494
+ function pushUniqueEntity(entities, seen, name, type) {
10495
+ const normalized = normalizeEntityName(name);
10496
+ if (!normalized || normalized.length < 2) return;
10497
+ const key = `${normalized.toLowerCase()}::${type.toLowerCase()}`;
10498
+ if (seen.has(key)) return;
10499
+ seen.add(key);
10500
+ entities.push({ name: normalized.slice(0, 160), type });
10501
+ }
10502
+ function pushHeuristicRelationship(relationships, source, sourceType, target, targetType, relationship, confidence = 0.6) {
10503
+ if (!source || !target || source === target) return;
10504
+ relationships.push({
10505
+ source,
10506
+ sourceType,
10507
+ target,
10508
+ targetType,
10509
+ relationship,
10510
+ confidence,
10511
+ confidenceLabel: "inferred"
10512
+ });
10513
+ }
10514
+ function extractHeuristicMemoryGraph(content, agentId) {
10515
+ const entities = [];
10516
+ const relationships = [];
10517
+ const seen = /* @__PURE__ */ new Set();
10518
+ pushUniqueEntity(entities, seen, agentId, "person");
10519
+ const toolMatch = content.match(/^(Bash|Read|Edit|Write|Grep|Glob|AssistantResponse|Tool|Ran|Wrote|Edited):/m);
10520
+ if (toolMatch?.[1]) {
10521
+ pushUniqueEntity(entities, seen, toolMatch[1], "tool");
10522
+ pushHeuristicRelationship(relationships, agentId, "person", toolMatch[1], "tool", "uses", 0.75);
10523
+ }
10524
+ const repoMatches = [...content.matchAll(/\/Users\/[^/\s]+\/([A-Za-z0-9_.-]+)|\/opt\/([A-Za-z0-9_.-]+)/g)].map((m) => m[1] ?? m[2]).filter((repo) => Boolean(repo)).slice(0, 6);
10525
+ for (const repo of repoMatches) {
10526
+ pushUniqueEntity(entities, seen, repo, "project");
10527
+ pushHeuristicRelationship(relationships, agentId, "person", repo, "project", "worked_on", 0.7);
10528
+ }
10529
+ const pathMatches = new Set(
10530
+ (content.match(/(?:\/[\w .@-]+)+(?:\.[A-Za-z0-9]{1,10})|(?:[\w@.-]+\/)+[\w@.-]+\.(?:ts|tsx|js|jsx|json|md|yml|yaml|sql|py|go|rs|sh|css|html)/g) ?? []).slice(0, 10)
10531
+ );
10532
+ for (const filePath of pathMatches) {
10533
+ pushUniqueEntity(entities, seen, filePath, "file");
10534
+ pushHeuristicRelationship(relationships, agentId, "person", filePath, "file", "uses", 0.65);
10535
+ }
10536
+ const backtickTerms = [...content.matchAll(/`([^`\n]{2,80})`/g)].map((m) => m[1]).slice(0, 10);
10537
+ for (const term of backtickTerms) {
10538
+ if (!term || term.length < 2) continue;
10539
+ const type = term.includes("/") || /\.[A-Za-z0-9]{1,10}$/.test(term) ? "file" : "concept";
10540
+ pushUniqueEntity(entities, seen, term, type);
10541
+ pushHeuristicRelationship(relationships, agentId, "person", term, type, "uses", 0.55);
10542
+ }
10543
+ return { entities, relationships, hyperedges: [] };
10544
+ }
9999
10545
  async function extractFromMemory(content, agentId, model = "claude-haiku-4-5-20251001", filePath) {
10000
10546
  if (content.length < 50) {
10001
10547
  return { entities: [], relationships: [], hyperedges: [] };
@@ -10051,7 +10597,7 @@ async function extractFromMemory(content, agentId, model = "claude-haiku-4-5-202
10051
10597
  `
10052
10598
  );
10053
10599
  }
10054
- return { entities: [], relationships: [], hyperedges: [] };
10600
+ return extractHeuristicMemoryGraph(content, agentId);
10055
10601
  }
10056
10602
  async function storeExtraction(client, extraction, memoryId, timestamp) {
10057
10603
  let entitiesStored = 0;