@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
@@ -248,6 +248,10 @@ async function loadConfig() {
248
248
  if (config.dbPath.startsWith("~")) {
249
249
  config.dbPath = config.dbPath.replace(/^~/, os.homedir());
250
250
  }
251
+ const envDbPath = path.join(dir, "memories.db");
252
+ if (process.env.EXE_OS_DIR && config.dbPath !== envDbPath && !existsSync2(config.dbPath) && existsSync2(envDbPath)) {
253
+ config.dbPath = envDbPath;
254
+ }
251
255
  return config;
252
256
  } catch {
253
257
  return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db") };
@@ -268,7 +272,15 @@ function loadConfigSync() {
268
272
  normalizeSessionLifecycle(migratedCfg);
269
273
  normalizeAutoUpdate(migratedCfg);
270
274
  normalizeOrchestration(migratedCfg);
271
- return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db"), ...migratedCfg };
275
+ const config = { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db"), ...migratedCfg };
276
+ if (config.dbPath.startsWith("~")) {
277
+ config.dbPath = config.dbPath.replace(/^~/, os.homedir());
278
+ }
279
+ const envDbPath = path.join(dir, "memories.db");
280
+ if (process.env.EXE_OS_DIR && config.dbPath !== envDbPath && !existsSync2(config.dbPath) && existsSync2(envDbPath)) {
281
+ config.dbPath = envDbPath;
282
+ }
283
+ return config;
272
284
  } catch {
273
285
  return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db") };
274
286
  }
@@ -1608,6 +1620,9 @@ function getClient() {
1608
1620
  if (_daemonClient && _daemonClient._isDaemonActive()) {
1609
1621
  return _daemonClient;
1610
1622
  }
1623
+ if (!_resilientClient) {
1624
+ return _adapterClient;
1625
+ }
1611
1626
  return _resilientClient;
1612
1627
  }
1613
1628
  async function initDaemonClient() {
@@ -2640,6 +2655,127 @@ async function ensureSchema() {
2640
2655
  VALUES (new.rowid, new.content, new.subject, new.predicate, new.object);
2641
2656
  END;
2642
2657
  `);
2658
+ await client.executeMultiple(`
2659
+ CREATE TABLE IF NOT EXISTS agent_sessions (
2660
+ id TEXT PRIMARY KEY,
2661
+ agent_id TEXT NOT NULL,
2662
+ project_name TEXT,
2663
+ started_at TEXT NOT NULL,
2664
+ last_event_at TEXT NOT NULL,
2665
+ event_count INTEGER NOT NULL DEFAULT 0,
2666
+ properties TEXT DEFAULT '{}'
2667
+ );
2668
+
2669
+ CREATE INDEX IF NOT EXISTS idx_agent_sessions_agent_time
2670
+ ON agent_sessions(agent_id, started_at);
2671
+
2672
+ CREATE TABLE IF NOT EXISTS agent_goals (
2673
+ id TEXT PRIMARY KEY,
2674
+ statement TEXT NOT NULL,
2675
+ owner_agent_id TEXT,
2676
+ project_name TEXT,
2677
+ status TEXT NOT NULL DEFAULT 'open',
2678
+ priority INTEGER NOT NULL DEFAULT 5,
2679
+ success_criteria TEXT,
2680
+ parent_goal_id TEXT,
2681
+ due_at TEXT,
2682
+ achieved_at TEXT,
2683
+ supersedes_id TEXT,
2684
+ created_at TEXT NOT NULL,
2685
+ updated_at TEXT NOT NULL,
2686
+ source_memory_id TEXT
2687
+ );
2688
+
2689
+ CREATE INDEX IF NOT EXISTS idx_agent_goals_project_status
2690
+ ON agent_goals(project_name, status, priority);
2691
+
2692
+ CREATE TABLE IF NOT EXISTS agent_events (
2693
+ id TEXT PRIMARY KEY,
2694
+ event_type TEXT NOT NULL,
2695
+ occurred_at TEXT NOT NULL,
2696
+ sequence_index INTEGER NOT NULL,
2697
+ actor_agent_id TEXT,
2698
+ agent_role TEXT,
2699
+ project_name TEXT,
2700
+ session_id TEXT,
2701
+ task_id TEXT,
2702
+ goal_id TEXT,
2703
+ parent_event_id TEXT,
2704
+ intention TEXT,
2705
+ outcome TEXT,
2706
+ evidence_memory_id TEXT,
2707
+ impact TEXT,
2708
+ payload TEXT DEFAULT '{}',
2709
+ created_at TEXT NOT NULL
2710
+ );
2711
+
2712
+ CREATE INDEX IF NOT EXISTS idx_agent_events_time
2713
+ ON agent_events(occurred_at, sequence_index);
2714
+
2715
+ CREATE INDEX IF NOT EXISTS idx_agent_events_session_seq
2716
+ ON agent_events(session_id, sequence_index);
2717
+
2718
+ CREATE INDEX IF NOT EXISTS idx_agent_events_goal_time
2719
+ ON agent_events(goal_id, occurred_at);
2720
+
2721
+ CREATE INDEX IF NOT EXISTS idx_agent_events_memory
2722
+ ON agent_events(evidence_memory_id);
2723
+
2724
+ CREATE TABLE IF NOT EXISTS agent_goal_links (
2725
+ id TEXT PRIMARY KEY,
2726
+ goal_id TEXT NOT NULL,
2727
+ link_type TEXT NOT NULL,
2728
+ target_id TEXT NOT NULL,
2729
+ target_type TEXT NOT NULL,
2730
+ created_at TEXT NOT NULL
2731
+ );
2732
+
2733
+ CREATE INDEX IF NOT EXISTS idx_agent_goal_links_goal
2734
+ ON agent_goal_links(goal_id, target_type);
2735
+
2736
+ CREATE TABLE IF NOT EXISTS agent_semantic_labels (
2737
+ id TEXT PRIMARY KEY,
2738
+ source_memory_id TEXT NOT NULL,
2739
+ event_id TEXT,
2740
+ labeler TEXT NOT NULL,
2741
+ schema_version INTEGER NOT NULL DEFAULT 1,
2742
+ confidence REAL NOT NULL DEFAULT 0,
2743
+ labels TEXT NOT NULL,
2744
+ created_at TEXT NOT NULL,
2745
+ updated_at TEXT NOT NULL
2746
+ );
2747
+
2748
+ CREATE INDEX IF NOT EXISTS idx_agent_semantic_labels_memory
2749
+ ON agent_semantic_labels(source_memory_id, labeler);
2750
+
2751
+ CREATE INDEX IF NOT EXISTS idx_agent_semantic_labels_event
2752
+ ON agent_semantic_labels(event_id);
2753
+
2754
+ CREATE TABLE IF NOT EXISTS agent_reflection_checkpoints (
2755
+ id TEXT PRIMARY KEY,
2756
+ project_name TEXT,
2757
+ session_id TEXT,
2758
+ window_start_at TEXT NOT NULL,
2759
+ window_end_at TEXT NOT NULL,
2760
+ event_count INTEGER NOT NULL DEFAULT 0,
2761
+ goal_count INTEGER NOT NULL DEFAULT 0,
2762
+ success_count INTEGER NOT NULL DEFAULT 0,
2763
+ failure_count INTEGER NOT NULL DEFAULT 0,
2764
+ risk_count INTEGER NOT NULL DEFAULT 0,
2765
+ summary TEXT NOT NULL,
2766
+ learnings TEXT NOT NULL DEFAULT '[]',
2767
+ next_actions TEXT NOT NULL DEFAULT '[]',
2768
+ evidence_event_ids TEXT NOT NULL DEFAULT '[]',
2769
+ confidence REAL NOT NULL DEFAULT 0,
2770
+ created_at TEXT NOT NULL
2771
+ );
2772
+
2773
+ CREATE INDEX IF NOT EXISTS idx_agent_reflection_project_time
2774
+ ON agent_reflection_checkpoints(project_name, window_end_at);
2775
+
2776
+ CREATE INDEX IF NOT EXISTS idx_agent_reflection_session_time
2777
+ ON agent_reflection_checkpoints(session_id, window_end_at);
2778
+ `);
2643
2779
  try {
2644
2780
  await client.execute({
2645
2781
  sql: `ALTER TABLE memories ADD COLUMN tier INTEGER DEFAULT 3`,
@@ -2803,7 +2939,7 @@ __export(shard_manager_exports, {
2803
2939
  shardExists: () => shardExists
2804
2940
  });
2805
2941
  import path7 from "path";
2806
- import { existsSync as existsSync7, mkdirSync as mkdirSync2, readdirSync, renameSync as renameSync3, statSync as statSync2 } from "fs";
2942
+ import { existsSync as existsSync7, mkdirSync as mkdirSync2, readdirSync, renameSync as renameSync3, statSync as statSync3 } from "fs";
2807
2943
  import { createClient as createClient2 } from "@libsql/client";
2808
2944
  function initShardManager(encryptionKey) {
2809
2945
  _encryptionKey = encryptionKey;
@@ -2867,7 +3003,7 @@ async function auditShardHealth(options = {}) {
2867
3003
  const shards = [];
2868
3004
  for (const name of names) {
2869
3005
  const dbPath = path7.join(SHARDS_DIR, `${name}.db`);
2870
- const stat = statSync2(dbPath);
3006
+ const stat = statSync3(dbPath);
2871
3007
  const item = {
2872
3008
  name,
2873
3009
  path: dbPath,
@@ -3120,7 +3256,7 @@ async function getReadyShardClient(projectName) {
3120
3256
  _shardLastAccess.delete(safeName);
3121
3257
  const dbPath = path7.join(SHARDS_DIR, `${safeName}.db`);
3122
3258
  if (existsSync7(dbPath)) {
3123
- const stat = statSync2(dbPath);
3259
+ const stat = statSync3(dbPath);
3124
3260
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
3125
3261
  const archivedPath = path7.join(SHARDS_DIR, `${safeName}.db.broken-${stamp}`);
3126
3262
  renameSync3(dbPath, archivedPath);
@@ -3627,6 +3763,274 @@ var init_memory_cards = __esm({
3627
3763
  }
3628
3764
  });
3629
3765
 
3766
+ // src/lib/agentic-ontology.ts
3767
+ var agentic_ontology_exports = {};
3768
+ __export(agentic_ontology_exports, {
3769
+ clean: () => clean,
3770
+ extractGoalCandidates: () => extractGoalCandidates,
3771
+ inferIntention: () => inferIntention,
3772
+ inferOntologyEventType: () => inferOntologyEventType,
3773
+ inferOutcome: () => inferOutcome,
3774
+ inferSemanticLabel: () => inferSemanticLabel,
3775
+ insertOntologyForBatch: () => insertOntologyForBatch,
3776
+ insertOntologyForMemory: () => insertOntologyForMemory,
3777
+ ontologyPayload: () => ontologyPayload,
3778
+ stableId: () => stableId2
3779
+ });
3780
+ import { createHash as createHash3 } from "crypto";
3781
+ function stableId2(...parts) {
3782
+ return createHash3("sha256").update(parts.map((p) => String(p ?? "")).join("::")).digest("hex").slice(0, 32);
3783
+ }
3784
+ function clean(text, max = 240) {
3785
+ return text.replace(/\u0000/g, "").replace(/```[\s\S]*?```/g, " ").replace(/\s+/g, " ").trim().slice(0, max);
3786
+ }
3787
+ function inferOntologyEventType(row) {
3788
+ const lower = row.raw_text.toLowerCase();
3789
+ if (row.has_error) return "error";
3790
+ if (/\b(done|complete|completed|fixed|resolved|shipped|deployed|pushed|published)\b/.test(lower)) return "milestone";
3791
+ if (/\b(blocked|failed|error|bug|regression|broken)\b/.test(lower)) return "problem";
3792
+ if (/\b(decided|decision|adr|we chose|approved|rejected)\b/.test(lower)) return "decision";
3793
+ if (/\b(goal|need to|we need|want to|trying to|objective)\b/.test(lower)) return "goal_signal";
3794
+ if (["Bash", "Read", "Edit", "Write", "Grep", "Glob"].includes(row.tool_name)) return "tool_action";
3795
+ if (row.tool_name.startsWith("memory_card")) return "memory_card";
3796
+ return "memory_observation";
3797
+ }
3798
+ function inferIntention(row) {
3799
+ if (row.intent) return clean(row.intent, 220);
3800
+ const text = clean(row.raw_text, 1e3);
3801
+ const patterns = [
3802
+ /(?: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,
3803
+ /(?:so that|in order to)\s+([^.!?\n]{8,220})/i,
3804
+ /(?:task|plan):\s*([^.!?\n]{8,220})/i
3805
+ ];
3806
+ for (const p of patterns) {
3807
+ const m = text.match(p);
3808
+ if (m?.[1]) return clean(m[1], 220);
3809
+ }
3810
+ if (["Bash", "Read", "Edit", "Write", "Grep", "Glob"].includes(row.tool_name)) {
3811
+ return `${row.tool_name} during ${row.project_name}`;
3812
+ }
3813
+ return null;
3814
+ }
3815
+ function inferOutcome(row) {
3816
+ if (row.outcome) return clean(row.outcome, 220);
3817
+ if (row.has_error) return "error";
3818
+ const lower = row.raw_text.toLowerCase();
3819
+ if (/\b(done|complete|completed|fixed|resolved|shipped|deployed|pushed|published|passed)\b/.test(lower)) return "success_signal";
3820
+ if (/\b(blocked|failed|error|regression|broken|not working|could not)\b/.test(lower)) return "failure_signal";
3821
+ if (/\b(warning|risk|concern|caveat)\b/.test(lower)) return "risk_signal";
3822
+ return null;
3823
+ }
3824
+ function extractGoalCandidates(row) {
3825
+ const text = clean(row.raw_text, 1600);
3826
+ const patterns = [
3827
+ /(?: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,
3828
+ /(?:success means|success criteria|so that)\s+([^.!?\n]{12,220})/gi
3829
+ ];
3830
+ const out = [];
3831
+ for (const pattern of patterns) {
3832
+ for (const m of text.matchAll(pattern)) {
3833
+ const candidate = clean(m[1] ?? "", 220);
3834
+ if (candidate.length >= 12 && !out.some((x) => x.toLowerCase() === candidate.toLowerCase())) out.push(candidate);
3835
+ if (out.length >= 3) return out;
3836
+ }
3837
+ }
3838
+ return out;
3839
+ }
3840
+ function uniq(values, max = 6) {
3841
+ const out = [];
3842
+ for (const value of values.map((v) => clean(v, 220)).filter(Boolean)) {
3843
+ if (!out.some((x) => x.toLowerCase() === value.toLowerCase())) out.push(value);
3844
+ if (out.length >= max) break;
3845
+ }
3846
+ return out;
3847
+ }
3848
+ function extractMatches(text, patterns, max = 5) {
3849
+ const out = [];
3850
+ for (const pattern of patterns) {
3851
+ for (const match of text.matchAll(pattern)) {
3852
+ const value = match[1] ?? match[0];
3853
+ if (value) out.push(value);
3854
+ if (out.length >= max) return uniq(out, max);
3855
+ }
3856
+ }
3857
+ return uniq(out, max);
3858
+ }
3859
+ function inferSemanticLabel(row) {
3860
+ const text = clean(row.raw_text, 2400);
3861
+ const eventType = inferOntologyEventType(row);
3862
+ const intention = inferIntention(row);
3863
+ const outcome = inferOutcome(row);
3864
+ const goals = extractGoalCandidates(row);
3865
+ const milestones = extractMatches(text, [
3866
+ /\b(?:completed|finished|fixed|resolved|shipped|deployed|published|pushed|passed)\b([^.!?\n]{0,180})/gi,
3867
+ /(?:milestone|done):\s*([^.!?\n]{8,220})/gi
3868
+ ]);
3869
+ const problems = extractMatches(text, [
3870
+ /\b(?:blocked by|failed because|bug|regression|broken|not working|error)\b([^.!?\n]{0,180})/gi,
3871
+ /(?:problem|issue|risk):\s*([^.!?\n]{8,220})/gi
3872
+ ]);
3873
+ const decisions = extractMatches(text, [
3874
+ /(?:decided|decision|adr|we chose|approved|rejected)\s+([^.!?\n]{8,220})/gi
3875
+ ]);
3876
+ const temporalAnchors = extractMatches(text, [
3877
+ /\b(\d{4}-\d{2}-\d{2}(?:[T ][0-9:.+-Z]+)?)\b/g,
3878
+ /\b(today|yesterday|tomorrow|this week|next week|last week|morning|afternoon|tonight)\b/gi
3879
+ ], 8);
3880
+ const nextActions = extractMatches(text, [
3881
+ /(?:next|todo|follow[- ]?up|remaining|need to)\s*:?\s*([^.!?\n]{8,220})/gi
3882
+ ]);
3883
+ const actors = uniq([
3884
+ row.agent_id,
3885
+ ...extractMatches(text, [/\b(?:agent|employee|owner|assignee)[:= ]+([a-zA-Z][a-zA-Z0-9_-]{1,40})/gi], 5)
3886
+ ], 6);
3887
+ const successSignals = milestones.length ? milestones : outcome === "success_signal" ? [clean(text, 180)] : [];
3888
+ const failureSignals = problems.length ? problems : outcome === "failure_signal" || row.has_error ? [clean(text, 180)] : [];
3889
+ const impact = successSignals.length && failureSignals.length ? "mixed" : failureSignals.length ? "negative" : successSignals.length ? "positive" : "neutral";
3890
+ const signalCount = goals.length + milestones.length + problems.length + decisions.length + nextActions.length;
3891
+ return {
3892
+ labeler: "deterministic",
3893
+ schemaVersion: 1,
3894
+ eventType,
3895
+ intention,
3896
+ outcome,
3897
+ impact,
3898
+ confidence: Math.min(0.95, 0.45 + signalCount * 0.08 + (intention ? 0.1 : 0) + (outcome ? 0.1 : 0)),
3899
+ goals,
3900
+ milestones,
3901
+ problems,
3902
+ decisions,
3903
+ actors,
3904
+ temporalAnchors,
3905
+ successSignals,
3906
+ failureSignals,
3907
+ nextActions,
3908
+ summary: clean(text, 280)
3909
+ };
3910
+ }
3911
+ function ontologyPayload(row) {
3912
+ const semantic = inferSemanticLabel(row);
3913
+ return {
3914
+ tool_name: row.tool_name,
3915
+ memory_version: row.version ?? null,
3916
+ domain: row.domain ?? null,
3917
+ trajectory: row.trajectory ? safeJson(row.trajectory) : null,
3918
+ semantic
3919
+ };
3920
+ }
3921
+ function safeJson(value) {
3922
+ try {
3923
+ return JSON.parse(value);
3924
+ } catch {
3925
+ return value.slice(0, 1e3);
3926
+ }
3927
+ }
3928
+ async function resolveClient(client) {
3929
+ if (client) return client;
3930
+ const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
3931
+ return getClient2();
3932
+ }
3933
+ async function insertOntologyForMemory(row, client) {
3934
+ const db = await resolveClient(client);
3935
+ const occurredAt = row.timestamp;
3936
+ const sequence = Number(row.version ?? 0) || Math.floor(new Date(occurredAt).getTime() / 1e3);
3937
+ const eventType = inferOntologyEventType(row);
3938
+ const intention = inferIntention(row);
3939
+ const outcome = inferOutcome(row);
3940
+ const eventId = stableId2("event", row.id);
3941
+ const now = (/* @__PURE__ */ new Date()).toISOString();
3942
+ await db.execute({
3943
+ sql: `INSERT INTO agent_sessions (id, agent_id, project_name, started_at, last_event_at, event_count, properties)
3944
+ VALUES (?, ?, ?, ?, ?, 1, ?)
3945
+ ON CONFLICT(id) DO UPDATE SET last_event_at = MAX(last_event_at, excluded.last_event_at),
3946
+ event_count = event_count + 1`,
3947
+ args: [row.session_id, row.agent_id, row.project_name, occurredAt, occurredAt, JSON.stringify({ agent_role: row.agent_role })]
3948
+ });
3949
+ await db.execute({
3950
+ sql: `INSERT OR IGNORE INTO agent_events
3951
+ (id, event_type, occurred_at, sequence_index, actor_agent_id, agent_role, project_name,
3952
+ session_id, task_id, goal_id, parent_event_id, intention, outcome, evidence_memory_id,
3953
+ impact, payload, created_at)
3954
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, NULL, ?, ?, ?, ?, ?, ?)`,
3955
+ args: [
3956
+ eventId,
3957
+ eventType,
3958
+ occurredAt,
3959
+ sequence,
3960
+ row.agent_id,
3961
+ row.agent_role,
3962
+ row.project_name,
3963
+ row.session_id,
3964
+ row.task_id ?? null,
3965
+ intention,
3966
+ outcome,
3967
+ row.id,
3968
+ row.has_error ? "negative" : outcome === "success_signal" ? "positive" : "neutral",
3969
+ JSON.stringify(ontologyPayload(row)),
3970
+ now
3971
+ ]
3972
+ });
3973
+ const semantic = inferSemanticLabel(row);
3974
+ await db.execute({
3975
+ sql: `INSERT INTO agent_semantic_labels
3976
+ (id, source_memory_id, event_id, labeler, schema_version, confidence, labels, created_at, updated_at)
3977
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
3978
+ ON CONFLICT(id) DO UPDATE SET confidence = excluded.confidence,
3979
+ labels = excluded.labels, updated_at = excluded.updated_at`,
3980
+ args: [
3981
+ stableId2("semantic", row.id, semantic.labeler, semantic.schemaVersion),
3982
+ row.id,
3983
+ eventId,
3984
+ semantic.labeler,
3985
+ semantic.schemaVersion,
3986
+ semantic.confidence,
3987
+ JSON.stringify(semantic),
3988
+ now,
3989
+ now
3990
+ ]
3991
+ });
3992
+ for (const statement of extractGoalCandidates(row)) {
3993
+ const goalId = stableId2("goal", row.project_name, statement.toLowerCase());
3994
+ await db.execute({
3995
+ sql: `INSERT INTO agent_goals
3996
+ (id, statement, owner_agent_id, project_name, status, priority, success_criteria,
3997
+ parent_goal_id, due_at, achieved_at, supersedes_id, created_at, updated_at, source_memory_id)
3998
+ VALUES (?, ?, ?, ?, 'open', 5, NULL, NULL, NULL, NULL, NULL, ?, ?, ?)
3999
+ ON CONFLICT(id) DO UPDATE SET updated_at = excluded.updated_at`,
4000
+ args: [goalId, statement, row.agent_id, row.project_name, now, now, row.id]
4001
+ });
4002
+ await db.execute({
4003
+ sql: `INSERT OR IGNORE INTO agent_goal_links
4004
+ (id, goal_id, link_type, target_id, target_type, created_at)
4005
+ VALUES (?, ?, 'evidence', ?, 'memory', ?)`,
4006
+ args: [stableId2("goal_link", goalId, row.id, "memory"), goalId, row.id, now]
4007
+ });
4008
+ await db.execute({
4009
+ sql: `INSERT OR IGNORE INTO agent_goal_links
4010
+ (id, goal_id, link_type, target_id, target_type, created_at)
4011
+ VALUES (?, ?, 'event', ?, 'event', ?)`,
4012
+ args: [stableId2("goal_link", goalId, eventId, "event"), goalId, eventId, now]
4013
+ });
4014
+ }
4015
+ }
4016
+ async function insertOntologyForBatch(rows, client) {
4017
+ const db = await resolveClient(client);
4018
+ let count = 0;
4019
+ for (const row of rows) {
4020
+ try {
4021
+ await insertOntologyForMemory(row, db);
4022
+ count++;
4023
+ } catch {
4024
+ }
4025
+ }
4026
+ return count;
4027
+ }
4028
+ var init_agentic_ontology = __esm({
4029
+ "src/lib/agentic-ontology.ts"() {
4030
+ "use strict";
4031
+ }
4032
+ });
4033
+
3630
4034
  // src/lib/runtime-table.ts
3631
4035
  var RUNTIME_TABLE;
3632
4036
  var init_runtime_table = __esm({
@@ -3954,6 +4358,56 @@ var init_preferences = __esm({
3954
4358
  }
3955
4359
  });
3956
4360
 
4361
+ // src/adapters/mcp-http-config.ts
4362
+ import { chmodSync as chmodSync2, existsSync as existsSync11, mkdirSync as mkdirSync6, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "fs";
4363
+ import { randomBytes } from "crypto";
4364
+ import path12 from "path";
4365
+ import os9 from "os";
4366
+ function mcpHttpPort() {
4367
+ return process.env.EXE_MCP_PORT || DEFAULT_MCP_HTTP_PORT;
4368
+ }
4369
+ function mcpHttpUrl() {
4370
+ return `http://127.0.0.1:${mcpHttpPort()}/mcp`;
4371
+ }
4372
+ function readOrCreateDaemonToken(homeDir = os9.homedir()) {
4373
+ const exeDir = path12.join(homeDir, ".exe-os");
4374
+ const tokenPath = path12.join(exeDir, "exed.token");
4375
+ if (existsSync11(tokenPath)) {
4376
+ try {
4377
+ const token2 = readFileSync7(tokenPath, "utf-8").trim();
4378
+ if (/^[a-f0-9]{64}$/i.test(token2)) return token2;
4379
+ } catch {
4380
+ }
4381
+ }
4382
+ const token = randomBytes(32).toString("hex");
4383
+ mkdirSync6(exeDir, { recursive: true });
4384
+ writeFileSync6(tokenPath, `${token}
4385
+ `, "utf-8");
4386
+ try {
4387
+ chmodSync2(tokenPath, 384);
4388
+ } catch {
4389
+ }
4390
+ return token;
4391
+ }
4392
+ function buildMcpHttpHeaders(homeDir = os9.homedir(), opts = {}) {
4393
+ const agentId = opts.useShellPlaceholders ? "${AGENT_ID:-exe}" : opts.agentId ?? DEFAULT_MCP_HTTP_AGENT_ID;
4394
+ const agentRole = opts.useShellPlaceholders ? "${AGENT_ROLE:-COO}" : opts.agentRole ?? DEFAULT_MCP_HTTP_AGENT_ROLE;
4395
+ return {
4396
+ Authorization: `Bearer ${readOrCreateDaemonToken(homeDir)}`,
4397
+ "X-Agent-Id": agentId,
4398
+ "X-Agent-Role": agentRole
4399
+ };
4400
+ }
4401
+ var DEFAULT_MCP_HTTP_PORT, DEFAULT_MCP_HTTP_AGENT_ID, DEFAULT_MCP_HTTP_AGENT_ROLE;
4402
+ var init_mcp_http_config = __esm({
4403
+ "src/adapters/mcp-http-config.ts"() {
4404
+ "use strict";
4405
+ DEFAULT_MCP_HTTP_PORT = "48739";
4406
+ DEFAULT_MCP_HTTP_AGENT_ID = "exe";
4407
+ DEFAULT_MCP_HTTP_AGENT_ROLE = "COO";
4408
+ }
4409
+ });
4410
+
3957
4411
  // src/adapters/runtime-hook-manifest.ts
3958
4412
  function textHasLegacySplitPostToolHook(text) {
3959
4413
  return [EXE_HOOK_FILES.ingest, EXE_HOOK_FILES.errorRecall, EXE_HOOK_FILES.ingestWorker].some((file) => text.includes(file));
@@ -4096,29 +4550,29 @@ var init_runtime_hook_manifest = __esm({
4096
4550
  });
4097
4551
 
4098
4552
  // src/adapters/claude/installer.ts
4099
- import { readFile as readFile4, writeFile as writeFile4, mkdir as mkdir4, readdir } from "fs/promises";
4100
- import { existsSync as existsSync11, readFileSync as readFileSync7, writeFileSync as writeFileSync6, copyFileSync, mkdirSync as mkdirSync6, chmodSync as chmodSync2 } from "fs";
4101
- import { createHash as createHash3, randomBytes } from "crypto";
4102
- import path12 from "path";
4103
- import os9 from "os";
4553
+ import { readFile as readFile4, writeFile as writeFile4, mkdir as mkdir4, readdir, rm } from "fs/promises";
4554
+ import { existsSync as existsSync12, readFileSync as readFileSync8, writeFileSync as writeFileSync7, copyFileSync, mkdirSync as mkdirSync7 } from "fs";
4555
+ import { createHash as createHash4 } from "crypto";
4556
+ import path13 from "path";
4557
+ import os10 from "os";
4104
4558
  import { execSync as execSync5 } from "child_process";
4105
4559
  import { fileURLToPath as fileURLToPath2 } from "url";
4106
4560
  function resolvePackageRoot() {
4107
4561
  const thisFile = fileURLToPath2(import.meta.url);
4108
- let dir = path12.dirname(thisFile);
4109
- const root = path12.parse(dir).root;
4562
+ let dir = path13.dirname(thisFile);
4563
+ const root = path13.parse(dir).root;
4110
4564
  while (dir !== root) {
4111
- const pkgPath = path12.join(dir, "package.json");
4112
- if (existsSync11(pkgPath)) {
4565
+ const pkgPath = path13.join(dir, "package.json");
4566
+ if (existsSync12(pkgPath)) {
4113
4567
  try {
4114
- const pkg = JSON.parse(readFileSync7(pkgPath, "utf-8"));
4568
+ const pkg = JSON.parse(readFileSync8(pkgPath, "utf-8"));
4115
4569
  if (pkg.name === "@askexenow/exe-os" || pkg.name === "exe-os") return dir;
4116
4570
  } catch {
4117
4571
  }
4118
4572
  }
4119
- dir = path12.dirname(dir);
4573
+ dir = path13.dirname(dir);
4120
4574
  }
4121
- return path12.resolve(path12.dirname(thisFile), "..", "..", "..");
4575
+ return path13.resolve(path13.dirname(thisFile), "..", "..", "..");
4122
4576
  }
4123
4577
  var EXE_SECTION_START, EXE_SECTION_END, ORCHESTRATION_RULES;
4124
4578
  var init_installer = __esm({
@@ -4127,6 +4581,7 @@ var init_installer = __esm({
4127
4581
  init_agent_symlinks();
4128
4582
  init_mcp_prefix();
4129
4583
  init_preferences();
4584
+ init_mcp_http_config();
4130
4585
  init_runtime_hook_manifest();
4131
4586
  EXE_SECTION_START = "<!-- exe-os:orchestration-start -->";
4132
4587
  EXE_SECTION_END = "<!-- exe-os:orchestration-end -->";
@@ -4337,15 +4792,16 @@ __export(installer_exports, {
4337
4792
  verifyOpenCodeHooks: () => verifyOpenCodeHooks
4338
4793
  });
4339
4794
  import { readFile as readFile5, writeFile as writeFile5, mkdir as mkdir5 } from "fs/promises";
4340
- import { existsSync as existsSync12, readFileSync as readFileSync8 } from "fs";
4341
- import path13 from "path";
4342
- import os10 from "os";
4343
- async function registerOpenCodeMcp(packageRoot, homeDir = os10.homedir()) {
4344
- const configDir = path13.join(homeDir, ".config", "opencode");
4345
- const configPath = path13.join(configDir, "opencode.json");
4795
+ import { existsSync as existsSync13, readFileSync as readFileSync9 } from "fs";
4796
+ import path14 from "path";
4797
+ import os11 from "os";
4798
+ async function registerOpenCodeMcp(packageRoot, homeDir = os11.homedir()) {
4799
+ void packageRoot;
4800
+ const configDir = path14.join(homeDir, ".config", "opencode");
4801
+ const configPath = path14.join(configDir, "opencode.json");
4346
4802
  await mkdir5(configDir, { recursive: true });
4347
4803
  let config = {};
4348
- if (existsSync12(configPath)) {
4804
+ if (existsSync13(configPath)) {
4349
4805
  try {
4350
4806
  config = JSON.parse(await readFile5(configPath, "utf-8"));
4351
4807
  } catch {
@@ -4356,8 +4812,9 @@ async function registerOpenCodeMcp(packageRoot, homeDir = os10.homedir()) {
4356
4812
  config.mcp = {};
4357
4813
  }
4358
4814
  const newEntry = {
4359
- type: "local",
4360
- command: ["node", path13.join(packageRoot, "dist", "mcp", "server.js")],
4815
+ type: "remote",
4816
+ url: mcpHttpUrl(),
4817
+ headers: buildMcpHttpHeaders(homeDir),
4361
4818
  enabled: true
4362
4819
  };
4363
4820
  const current = config.mcp["exe-os"];
@@ -4371,15 +4828,15 @@ async function registerOpenCodeMcp(packageRoot, homeDir = os10.homedir()) {
4371
4828
  await writeFile5(configPath, JSON.stringify(config, null, 2) + "\n");
4372
4829
  return true;
4373
4830
  }
4374
- async function installOpenCodePlugin(packageRoot, homeDir = os10.homedir()) {
4375
- const pluginDir = path13.join(homeDir, ".config", "opencode", "plugins");
4376
- const pluginPath = path13.join(pluginDir, "exe-os.mjs");
4831
+ async function installOpenCodePlugin(packageRoot, homeDir = os11.homedir()) {
4832
+ const pluginDir = path14.join(homeDir, ".config", "opencode", "plugins");
4833
+ const pluginPath = path14.join(pluginDir, "exe-os.mjs");
4377
4834
  await mkdir5(pluginDir, { recursive: true });
4378
4835
  const pluginContent = PLUGIN_TEMPLATE.replace(
4379
4836
  /__PACKAGE_ROOT__/g,
4380
4837
  packageRoot.replace(/\\/g, "\\\\")
4381
4838
  );
4382
- if (existsSync12(pluginPath)) {
4839
+ if (existsSync13(pluginPath)) {
4383
4840
  const existing = await readFile5(pluginPath, "utf-8");
4384
4841
  if (existing === pluginContent) {
4385
4842
  return false;
@@ -4388,19 +4845,19 @@ async function installOpenCodePlugin(packageRoot, homeDir = os10.homedir()) {
4388
4845
  await writeFile5(pluginPath, pluginContent);
4389
4846
  return true;
4390
4847
  }
4391
- function verifyOpenCodeHooks(homeDir = os10.homedir()) {
4392
- const configPath = path13.join(homeDir, ".config", "opencode", "opencode.json");
4393
- const pluginPath = path13.join(homeDir, ".config", "opencode", "plugins", "exe-os.mjs");
4394
- if (!existsSync12(configPath)) return false;
4848
+ function verifyOpenCodeHooks(homeDir = os11.homedir()) {
4849
+ const configPath = path14.join(homeDir, ".config", "opencode", "opencode.json");
4850
+ const pluginPath = path14.join(homeDir, ".config", "opencode", "plugins", "exe-os.mjs");
4851
+ if (!existsSync13(configPath)) return false;
4395
4852
  try {
4396
- const config = JSON.parse(readFileSync8(configPath, "utf-8"));
4853
+ const config = JSON.parse(readFileSync9(configPath, "utf-8"));
4397
4854
  if (!config.mcp?.["exe-os"]?.enabled) return false;
4398
4855
  } catch {
4399
4856
  return false;
4400
4857
  }
4401
- if (!existsSync12(pluginPath)) return false;
4858
+ if (!existsSync13(pluginPath)) return false;
4402
4859
  try {
4403
- const plugin = readFileSync8(pluginPath, "utf-8");
4860
+ const plugin = readFileSync9(pluginPath, "utf-8");
4404
4861
  if (!plugin.includes(EXE_HOOK_FILES.postToolCombined)) return false;
4405
4862
  if (textHasLegacySplitPostToolHook(plugin)) return false;
4406
4863
  } catch {
@@ -4427,17 +4884,18 @@ var init_installer2 = __esm({
4427
4884
  init_installer();
4428
4885
  init_plugin_template();
4429
4886
  init_runtime_hook_manifest();
4887
+ init_mcp_http_config();
4430
4888
  }
4431
4889
  });
4432
4890
 
4433
4891
  // src/bin/exe-start-opencode.ts
4434
- import os11 from "os";
4435
- import path14 from "path";
4892
+ import os12 from "os";
4893
+ import path15 from "path";
4436
4894
  import {
4437
- existsSync as existsSync13,
4438
- readFileSync as readFileSync9,
4439
- writeFileSync as writeFileSync7,
4440
- mkdirSync as mkdirSync7,
4895
+ existsSync as existsSync14,
4896
+ readFileSync as readFileSync10,
4897
+ writeFileSync as writeFileSync8,
4898
+ mkdirSync as mkdirSync8,
4441
4899
  readdirSync as readdirSync4
4442
4900
  } from "fs";
4443
4901
  import { spawnSync } from "child_process";
@@ -4448,11 +4906,12 @@ init_database();
4448
4906
 
4449
4907
  // src/lib/keychain.ts
4450
4908
  import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
4451
- import { existsSync as existsSync6 } from "fs";
4909
+ import { existsSync as existsSync6, statSync as statSync2 } from "fs";
4452
4910
  import { execSync as execSync2 } from "child_process";
4453
4911
  import path6 from "path";
4454
4912
  import os5 from "os";
4455
- var SERVICE = "exe-mem";
4913
+ var SERVICE = "exe-os";
4914
+ var LEGACY_SERVICE = "exe-mem";
4456
4915
  var ACCOUNT = "master-key";
4457
4916
  function getKeyDir() {
4458
4917
  return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path6.join(os5.homedir(), ".exe-os");
@@ -4460,29 +4919,79 @@ function getKeyDir() {
4460
4919
  function getKeyPath() {
4461
4920
  return path6.join(getKeyDir(), "master.key");
4462
4921
  }
4463
- function macKeychainGet() {
4922
+ function nativeKeychainAllowed() {
4923
+ return process.env.EXE_OS_DISABLE_NATIVE_KEYCHAIN !== "1";
4924
+ }
4925
+ var linuxSecretAvailability = null;
4926
+ function linuxSecretAvailable() {
4927
+ if (!nativeKeychainAllowed()) return false;
4928
+ if (process.platform !== "linux") return false;
4929
+ if (linuxSecretAvailability !== null) return linuxSecretAvailability;
4930
+ try {
4931
+ execSync2("command -v secret-tool >/dev/null 2>&1", { timeout: 1e3 });
4932
+ } catch {
4933
+ linuxSecretAvailability = false;
4934
+ return false;
4935
+ }
4936
+ try {
4937
+ execSync2("secret-tool search --all exe-os probe >/dev/null 2>&1", { timeout: 1e3 });
4938
+ linuxSecretAvailability = true;
4939
+ } catch {
4940
+ linuxSecretAvailability = false;
4941
+ }
4942
+ return linuxSecretAvailability;
4943
+ }
4944
+ function isRootOnlyTrustedServerKeyFile(keyPath) {
4945
+ if (process.platform !== "linux") return false;
4946
+ try {
4947
+ const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
4948
+ const st = statSync2(keyPath);
4949
+ if (!st.isFile() || (st.mode & 63) !== 0) return false;
4950
+ if (uid === 0) return true;
4951
+ const exeOsDir = process.env.EXE_OS_DIR;
4952
+ return Boolean(exeOsDir && path6.resolve(keyPath).startsWith(path6.resolve(exeOsDir) + path6.sep));
4953
+ } catch {
4954
+ return false;
4955
+ }
4956
+ }
4957
+ function macKeychainGet(service = SERVICE) {
4958
+ if (!nativeKeychainAllowed()) return null;
4464
4959
  if (process.platform !== "darwin") return null;
4465
4960
  try {
4466
4961
  return execSync2(
4467
- `security find-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w 2>/dev/null`,
4962
+ `security find-generic-password -s "${service}" -a "${ACCOUNT}" -w 2>/dev/null`,
4468
4963
  { encoding: "utf-8", timeout: 5e3 }
4469
4964
  ).trim();
4470
4965
  } catch {
4471
4966
  return null;
4472
4967
  }
4473
4968
  }
4474
- function macKeychainSet(value) {
4969
+ function macKeychainSet(value, service = SERVICE) {
4970
+ if (!nativeKeychainAllowed()) return false;
4475
4971
  if (process.platform !== "darwin") return false;
4476
4972
  try {
4477
4973
  try {
4478
4974
  execSync2(
4479
- `security delete-generic-password -s "${SERVICE}" -a "${ACCOUNT}" 2>/dev/null`,
4975
+ `security delete-generic-password -s "${service}" -a "${ACCOUNT}" 2>/dev/null`,
4480
4976
  { timeout: 5e3 }
4481
4977
  );
4482
4978
  } catch {
4483
4979
  }
4484
4980
  execSync2(
4485
- `security add-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w "${value}"`,
4981
+ `security add-generic-password -s "${service}" -a "${ACCOUNT}" -w "${value}"`,
4982
+ { timeout: 5e3 }
4983
+ );
4984
+ return true;
4985
+ } catch {
4986
+ return false;
4987
+ }
4988
+ }
4989
+ function macKeychainDelete(service = SERVICE) {
4990
+ if (!nativeKeychainAllowed()) return false;
4991
+ if (process.platform !== "darwin") return false;
4992
+ try {
4993
+ execSync2(
4994
+ `security delete-generic-password -s "${service}" -a "${ACCOUNT}" 2>/dev/null`,
4486
4995
  { timeout: 5e3 }
4487
4996
  );
4488
4997
  return true;
@@ -4490,22 +4999,35 @@ function macKeychainSet(value) {
4490
4999
  return false;
4491
5000
  }
4492
5001
  }
4493
- function linuxSecretGet() {
4494
- if (process.platform !== "linux") return null;
5002
+ function linuxSecretGet(service = SERVICE) {
5003
+ if (!linuxSecretAvailable()) return null;
4495
5004
  try {
4496
5005
  return execSync2(
4497
- `secret-tool lookup service "${SERVICE}" account "${ACCOUNT}" 2>/dev/null`,
5006
+ `secret-tool lookup service "${service}" account "${ACCOUNT}" 2>/dev/null`,
4498
5007
  { encoding: "utf-8", timeout: 5e3 }
4499
5008
  ).trim();
4500
5009
  } catch {
4501
5010
  return null;
4502
5011
  }
4503
5012
  }
4504
- function linuxSecretSet(value) {
5013
+ function linuxSecretSet(value, service = SERVICE) {
5014
+ if (!linuxSecretAvailable()) return false;
5015
+ try {
5016
+ execSync2(
5017
+ `echo -n "${value}" | secret-tool store --label="exe-os master key" service "${service}" account "${ACCOUNT}" 2>/dev/null`,
5018
+ { timeout: 5e3 }
5019
+ );
5020
+ return true;
5021
+ } catch {
5022
+ return false;
5023
+ }
5024
+ }
5025
+ function linuxSecretDelete(service = SERVICE) {
5026
+ if (!nativeKeychainAllowed()) return false;
4505
5027
  if (process.platform !== "linux") return false;
4506
5028
  try {
4507
5029
  execSync2(
4508
- `echo -n "${value}" | secret-tool store --label="exe-os master key" service "${SERVICE}" account "${ACCOUNT}"`,
5030
+ `secret-tool clear service "${service}" account "${ACCOUNT}" 2>/dev/null`,
4509
5031
  { timeout: 5e3 }
4510
5032
  );
4511
5033
  return true;
@@ -4514,6 +5036,7 @@ function linuxSecretSet(value) {
4514
5036
  }
4515
5037
  }
4516
5038
  async function tryKeytar() {
5039
+ if (!nativeKeychainAllowed()) return null;
4517
5040
  try {
4518
5041
  return await import("keytar");
4519
5042
  } catch {
@@ -4539,8 +5062,8 @@ function deriveMachineKey() {
4539
5062
  }
4540
5063
  function readMachineId() {
4541
5064
  try {
4542
- const { readFileSync: readFileSync10 } = __require("fs");
4543
- return readFileSync10("/etc/machine-id", "utf-8").trim();
5065
+ const { readFileSync: readFileSync11 } = __require("fs");
5066
+ return readFileSync11("/etc/machine-id", "utf-8").trim();
4544
5067
  } catch {
4545
5068
  return "";
4546
5069
  }
@@ -4588,7 +5111,19 @@ async function writeMachineBoundFileFallback(b64) {
4588
5111
  return "plaintext";
4589
5112
  }
4590
5113
  async function getMasterKey() {
4591
- const nativeValue = macKeychainGet() ?? linuxSecretGet();
5114
+ let nativeValue = macKeychainGet() ?? linuxSecretGet();
5115
+ if (!nativeValue) {
5116
+ const legacyValue = macKeychainGet(LEGACY_SERVICE) ?? linuxSecretGet(LEGACY_SERVICE);
5117
+ if (legacyValue) {
5118
+ const migrated = macKeychainSet(legacyValue) || linuxSecretSet(legacyValue);
5119
+ if (migrated) {
5120
+ macKeychainDelete(LEGACY_SERVICE);
5121
+ linuxSecretDelete(LEGACY_SERVICE);
5122
+ process.stderr.write("[keychain] Migrated keychain service from exe-mem to exe-os.\n");
5123
+ }
5124
+ nativeValue = legacyValue;
5125
+ }
5126
+ }
4592
5127
  if (nativeValue) {
4593
5128
  return Buffer.from(nativeValue, "base64");
4594
5129
  }
@@ -4596,12 +5131,17 @@ async function getMasterKey() {
4596
5131
  if (keytar) {
4597
5132
  try {
4598
5133
  const keytarValue = await keytar.getPassword(SERVICE, ACCOUNT);
4599
- if (keytarValue) {
4600
- const migrated = macKeychainSet(keytarValue) || linuxSecretSet(keytarValue);
5134
+ const legacyKeytarValue = keytarValue ?? await keytar.getPassword(LEGACY_SERVICE, ACCOUNT);
5135
+ if (legacyKeytarValue) {
5136
+ const migrated = macKeychainSet(legacyKeytarValue) || linuxSecretSet(legacyKeytarValue);
4601
5137
  if (migrated) {
4602
5138
  process.stderr.write("[keychain] Migrated key from keytar to native keychain.\n");
5139
+ try {
5140
+ await keytar.deletePassword(LEGACY_SERVICE, ACCOUNT);
5141
+ } catch {
5142
+ }
4603
5143
  }
4604
- return Buffer.from(keytarValue, "base64");
5144
+ return Buffer.from(legacyKeytarValue, "base64");
4605
5145
  }
4606
5146
  } catch {
4607
5147
  }
@@ -4626,7 +5166,7 @@ async function getMasterKey() {
4626
5166
  const decrypted = decryptWithMachineKey(content, machineKey);
4627
5167
  if (!decrypted) {
4628
5168
  process.stderr.write(
4629
- "[keychain] Key decryption failed \u2014 machine may have changed.\n Use your 24-word recovery phrase: exe-os link import\n"
5169
+ "[keychain] Key decryption failed \u2014 machine may have changed.\n Use your 24-word recovery phrase during setup: exe-os setup\n"
4630
5170
  );
4631
5171
  return null;
4632
5172
  }
@@ -4635,6 +5175,9 @@ async function getMasterKey() {
4635
5175
  b64Value = content;
4636
5176
  }
4637
5177
  const key = Buffer.from(b64Value, "base64");
5178
+ if (!content.startsWith(ENCRYPTED_PREFIX) && isRootOnlyTrustedServerKeyFile(keyPath)) {
5179
+ return key;
5180
+ }
4638
5181
  const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
4639
5182
  if (migrated) {
4640
5183
  process.stderr.write("[keychain] Migrated key from file to native keychain.\n");
@@ -5001,6 +5544,11 @@ async function flushBatch() {
5001
5544
  await insertMemoryCardsForBatch2(batch);
5002
5545
  } catch {
5003
5546
  }
5547
+ try {
5548
+ const { insertOntologyForBatch: insertOntologyForBatch2 } = await Promise.resolve().then(() => (init_agentic_ontology(), agentic_ontology_exports));
5549
+ await insertOntologyForBatch2(batch);
5550
+ } catch {
5551
+ }
5004
5552
  schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
5005
5553
  _pendingRecords.splice(0, batch.length);
5006
5554
  try {
@@ -5069,7 +5617,7 @@ import {
5069
5617
  existsSync as existsSync8,
5070
5618
  mkdirSync as mkdirSync3,
5071
5619
  readdirSync as readdirSync2,
5072
- statSync as statSync3,
5620
+ statSync as statSync4,
5073
5621
  unlinkSync as unlinkSync3,
5074
5622
  writeFileSync as writeFileSync3
5075
5623
  } from "fs";
@@ -5141,7 +5689,7 @@ function sweepStaleBehaviorExports(now = Date.now()) {
5141
5689
  for (const entry of entries) {
5142
5690
  const filePath = path8.join(BEHAVIORS_EXPORT_DIR, entry);
5143
5691
  try {
5144
- const stat = statSync3(filePath);
5692
+ const stat = statSync4(filePath);
5145
5693
  if (now - stat.mtimeMs > STALE_EXPORT_AGE_MS) {
5146
5694
  unlinkSync3(filePath);
5147
5695
  }
@@ -5204,7 +5752,7 @@ When done with a task: call update_task with status "done".
5204
5752
  Always call store_memory to persist important findings.
5205
5753
  `;
5206
5754
  function resolveAgent(argv) {
5207
- const invokedAs = path14.basename(argv[1] ?? "");
5755
+ const invokedAs = path15.basename(argv[1] ?? "");
5208
5756
  if (invokedAs && invokedAs !== "exe-start-opencode" && !invokedAs.endsWith(".js")) {
5209
5757
  const agent2 = invokedAs.replace(/-opencode$/, "").toLowerCase();
5210
5758
  return { agent: agent2, passthrough: argv.slice(2) };
@@ -5221,24 +5769,24 @@ function resolveAgent(argv) {
5221
5769
  return { agent, passthrough };
5222
5770
  }
5223
5771
  function loadIdentity(agent) {
5224
- const dir = path14.join(os11.homedir(), ".exe-os", "identity");
5225
- const exact = path14.join(dir, `${agent}.md`);
5226
- if (existsSync13(exact)) {
5227
- const content = readFileSync9(exact, "utf-8").trim();
5772
+ const dir = path15.join(os12.homedir(), ".exe-os", "identity");
5773
+ const exact = path15.join(dir, `${agent}.md`);
5774
+ if (existsSync14(exact)) {
5775
+ const content = readFileSync10(exact, "utf-8").trim();
5228
5776
  if (content) return content;
5229
5777
  }
5230
5778
  try {
5231
5779
  const files = readdirSync4(dir);
5232
5780
  const match = files.find((f) => f.toLowerCase() === `${agent.toLowerCase()}.md`);
5233
5781
  if (match) {
5234
- const content = readFileSync9(path14.join(dir, match), "utf-8").trim();
5782
+ const content = readFileSync10(path15.join(dir, match), "utf-8").trim();
5235
5783
  if (content) return content;
5236
5784
  }
5237
5785
  } catch {
5238
5786
  }
5239
5787
  try {
5240
- const rosterPath = path14.join(os11.homedir(), ".exe-os", "exe-employees.json");
5241
- const roster = JSON.parse(readFileSync9(rosterPath, "utf8"));
5788
+ const rosterPath = path15.join(os12.homedir(), ".exe-os", "exe-employees.json");
5789
+ const roster = JSON.parse(readFileSync10(rosterPath, "utf8"));
5242
5790
  const emp = roster.find((e) => e.name.toLowerCase() === agent.toLowerCase());
5243
5791
  if (emp?.systemPrompt && emp.systemPrompt.trim().length > 20) {
5244
5792
  return emp.systemPrompt;
@@ -5248,18 +5796,18 @@ function loadIdentity(agent) {
5248
5796
  return null;
5249
5797
  }
5250
5798
  function writeAgentFile(agent, identity, behaviorsPath) {
5251
- const agentDir = path14.join(os11.homedir(), ".config", "opencode", "agents");
5252
- mkdirSync7(agentDir, { recursive: true });
5799
+ const agentDir = path15.join(os12.homedir(), ".config", "opencode", "agents");
5800
+ mkdirSync8(agentDir, { recursive: true });
5253
5801
  let content = identity;
5254
- if (behaviorsPath && existsSync13(behaviorsPath)) {
5255
- const behaviors = readFileSync9(behaviorsPath, "utf-8").trim();
5802
+ if (behaviorsPath && existsSync14(behaviorsPath)) {
5803
+ const behaviors = readFileSync10(behaviorsPath, "utf-8").trim();
5256
5804
  if (behaviors) {
5257
5805
  content += "\n\n" + behaviors;
5258
5806
  }
5259
5807
  }
5260
5808
  content += "\n" + BOOT_INSTRUCTIONS;
5261
- const outPath = path14.join(agentDir, `${agent}.md`);
5262
- writeFileSync7(outPath, content, "utf-8");
5809
+ const outPath = path15.join(agentDir, `${agent}.md`);
5810
+ writeFileSync8(outPath, content, "utf-8");
5263
5811
  return outPath;
5264
5812
  }
5265
5813
  async function main() {
@@ -5320,8 +5868,8 @@ async function main() {
5320
5868
  process.env.EXE_RUNTIME = "opencode";
5321
5869
  const empRole = (() => {
5322
5870
  try {
5323
- const emps = readFileSync9(
5324
- path14.join(os11.homedir(), ".exe-os", "exe-employees.json"),
5871
+ const emps = readFileSync10(
5872
+ path15.join(os12.homedir(), ".exe-os", "exe-employees.json"),
5325
5873
  "utf-8"
5326
5874
  );
5327
5875
  const found = JSON.parse(emps).find(