@askexenow/exe-os 0.9.69 → 0.9.71

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 (79) hide show
  1. package/deploy/stack-manifests/v0.9.json +96 -16
  2. package/dist/bin/agentic-ontology-backfill.js +33 -0
  3. package/dist/bin/agentic-reflection-backfill.js +33 -0
  4. package/dist/bin/agentic-semantic-label.js +33 -0
  5. package/dist/bin/backfill-conversations.js +33 -0
  6. package/dist/bin/backfill-responses.js +33 -0
  7. package/dist/bin/backfill-vectors.js +33 -0
  8. package/dist/bin/bulk-sync-postgres.js +33 -0
  9. package/dist/bin/cleanup-stale-review-tasks.js +33 -0
  10. package/dist/bin/cli.js +1284 -178
  11. package/dist/bin/exe-agent.js +6 -0
  12. package/dist/bin/exe-assign.js +33 -0
  13. package/dist/bin/exe-boot.js +33 -0
  14. package/dist/bin/exe-call.js +6 -0
  15. package/dist/bin/exe-cloud.js +33 -0
  16. package/dist/bin/exe-dispatch.js +33 -0
  17. package/dist/bin/exe-doctor.js +33 -0
  18. package/dist/bin/exe-export-behaviors.js +33 -0
  19. package/dist/bin/exe-forget.js +33 -0
  20. package/dist/bin/exe-gateway.js +178 -110
  21. package/dist/bin/exe-heartbeat.js +33 -0
  22. package/dist/bin/exe-kill.js +33 -0
  23. package/dist/bin/exe-launch-agent.js +33 -0
  24. package/dist/bin/exe-new-employee.js +6 -0
  25. package/dist/bin/exe-pending-messages.js +33 -0
  26. package/dist/bin/exe-pending-notifications.js +33 -0
  27. package/dist/bin/exe-pending-reviews.js +33 -0
  28. package/dist/bin/exe-rename.js +40 -4
  29. package/dist/bin/exe-review.js +33 -0
  30. package/dist/bin/exe-search.js +33 -0
  31. package/dist/bin/exe-session-cleanup.js +33 -0
  32. package/dist/bin/exe-start-codex.js +33 -0
  33. package/dist/bin/exe-start-opencode.js +33 -0
  34. package/dist/bin/exe-status.js +33 -0
  35. package/dist/bin/exe-team.js +33 -0
  36. package/dist/bin/git-sweep.js +33 -0
  37. package/dist/bin/graph-backfill.js +177 -110
  38. package/dist/bin/graph-export.js +33 -0
  39. package/dist/bin/intercom-check.js +33 -0
  40. package/dist/bin/registry-proxy.js +207 -0
  41. package/dist/bin/scan-tasks.js +33 -0
  42. package/dist/bin/setup.js +33 -0
  43. package/dist/bin/shard-migrate.js +33 -0
  44. package/dist/bin/stack-update.js +128 -0
  45. package/dist/gateway/index.js +178 -110
  46. package/dist/hooks/bug-report-worker.js +33 -0
  47. package/dist/hooks/codex-stop-task-finalizer.js +33 -0
  48. package/dist/hooks/commit-complete.js +33 -0
  49. package/dist/hooks/error-recall.js +33 -0
  50. package/dist/hooks/ingest.js +33 -0
  51. package/dist/hooks/instructions-loaded.js +33 -0
  52. package/dist/hooks/notification.js +33 -0
  53. package/dist/hooks/post-compact.js +33 -0
  54. package/dist/hooks/post-tool-combined.js +698 -17
  55. package/dist/hooks/pre-compact.js +33 -0
  56. package/dist/hooks/pre-tool-use.js +33 -0
  57. package/dist/hooks/prompt-submit.js +314 -0
  58. package/dist/hooks/session-end.js +33 -0
  59. package/dist/hooks/session-start.js +33 -0
  60. package/dist/hooks/stop.js +279 -12
  61. package/dist/hooks/subagent-stop.js +33 -0
  62. package/dist/hooks/summary-worker.js +33 -0
  63. package/dist/index.js +178 -110
  64. package/dist/lib/cloud-sync.js +27 -0
  65. package/dist/lib/database.js +27 -0
  66. package/dist/lib/db.js +27 -0
  67. package/dist/lib/device-registry.js +27 -0
  68. package/dist/lib/employee-templates.js +6 -0
  69. package/dist/lib/exe-daemon.js +639 -259
  70. package/dist/lib/hybrid-search.js +33 -0
  71. package/dist/lib/registry-proxy.js +162 -0
  72. package/dist/lib/schedules.js +33 -0
  73. package/dist/lib/store.js +33 -0
  74. package/dist/mcp/server.js +561 -244
  75. package/dist/runtime/index.js +33 -0
  76. package/dist/tui/App.js +33 -0
  77. package/package.json +3 -2
  78. package/stack.release.json +6 -4
  79. package/stack.release.schema.json +89 -18
@@ -1386,8 +1386,8 @@ function findPackageRoot() {
1386
1386
  function getAvailableMemoryGB() {
1387
1387
  if (process.platform === "darwin") {
1388
1388
  try {
1389
- const { execSync: execSync6 } = __require("child_process");
1390
- const vmstat = execSync6("vm_stat", { encoding: "utf8" });
1389
+ const { execSync: execSync7 } = __require("child_process");
1390
+ const vmstat = execSync7("vm_stat", { encoding: "utf8" });
1391
1391
  const pageSize = 16384;
1392
1392
  const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
1393
1393
  const actualPageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : pageSize;
@@ -2769,6 +2769,33 @@ async function ensureSchema() {
2769
2769
  CREATE INDEX IF NOT EXISTS idx_chat_history_session
2770
2770
  ON chat_history(session_id, id);
2771
2771
  `);
2772
+ await client.executeMultiple(`
2773
+ CREATE TABLE IF NOT EXISTS session_events (
2774
+ id TEXT PRIMARY KEY,
2775
+ agent_id TEXT NOT NULL,
2776
+ agent_role TEXT NOT NULL,
2777
+ session_id TEXT NOT NULL,
2778
+ session_scope TEXT,
2779
+ project_name TEXT NOT NULL,
2780
+ event_index INTEGER NOT NULL,
2781
+ event_type TEXT NOT NULL,
2782
+ tool_name TEXT,
2783
+ tool_use_id TEXT,
2784
+ content TEXT NOT NULL,
2785
+ payload_json TEXT,
2786
+ has_error INTEGER NOT NULL DEFAULT 0,
2787
+ created_at TEXT NOT NULL
2788
+ );
2789
+
2790
+ CREATE INDEX IF NOT EXISTS idx_session_events_agent_time
2791
+ ON session_events(agent_id, created_at DESC);
2792
+
2793
+ CREATE INDEX IF NOT EXISTS idx_session_events_session_index
2794
+ ON session_events(session_id, event_index);
2795
+
2796
+ CREATE INDEX IF NOT EXISTS idx_session_events_scope_agent_time
2797
+ ON session_events(session_scope, agent_id, created_at DESC);
2798
+ `);
2772
2799
  await client.executeMultiple(`
2773
2800
  CREATE TABLE IF NOT EXISTS workspaces (
2774
2801
  id TEXT PRIMARY KEY,
@@ -3519,6 +3546,15 @@ function sessionScopeFilter(sessionScope, tableAlias) {
3519
3546
  args: [scope]
3520
3547
  };
3521
3548
  }
3549
+ function strictSessionScopeFilter(sessionScope, tableAlias) {
3550
+ const scope = sessionScope !== void 0 ? sessionScope : getCurrentSessionScope();
3551
+ if (!scope) return { sql: "", args: [] };
3552
+ const col = tableAlias ? `${tableAlias}.session_scope` : "session_scope";
3553
+ return {
3554
+ sql: ` AND ${col} = ?`,
3555
+ args: [scope]
3556
+ };
3557
+ }
3522
3558
  var init_task_scope = __esm({
3523
3559
  "src/lib/task-scope.ts"() {
3524
3560
  "use strict";
@@ -4600,6 +4636,12 @@ var init_platform_procedures = __esm({
4600
4636
  priority: "p0",
4601
4637
  content: "exe-build-adv is MANDATORY for ALL work touching 3+ files. Run /exe-build-adv --auto BEFORE implementation. Pipeline: Spec \u2192 AC \u2192 Tests \u2192 Evaluate \u2192 Fix. No multi-file feature ships without pipeline artifacts. No exceptions \u2014 managers reject work without them."
4602
4638
  },
4639
+ {
4640
+ title: "Code context first for repository orientation",
4641
+ domain: "workflow",
4642
+ priority: "p1",
4643
+ content: "Before broad repo exploration, symbol tracing, blast-radius review, or codebase Q&A, agents should use the consolidated code_context MCP tool instead of manual grep/read loops. Use action=index or stats to refresh/check the index; action=search with query, limit, offset, languages, paths, refresh_index for fresh multi-language code/doc search; action=trace for symbol imports/dependents; action=blast_radius for impact analysis before edits. CLI parity exists via exe-os code-context init|index|status|stats|search|doctor. Keep code_context separate from durable employee memory: promote only validated decisions, procedures, or lessons into store_memory/commit_memory."
4644
+ },
4603
4645
  {
4604
4646
  title: "Commit discipline \u2014 never leave verified work floating",
4605
4647
  domain: "workflow",
@@ -5886,9 +5928,179 @@ var init_fast_db_init = __esm({
5886
5928
  }
5887
5929
  });
5888
5930
 
5931
+ // src/lib/project-name.ts
5932
+ import { execSync as execSync6 } from "child_process";
5933
+ import path16 from "path";
5934
+ function getProjectName(cwd) {
5935
+ const dir = cwd ?? process.cwd();
5936
+ if (_cached2 && _cachedCwd === dir) return _cached2;
5937
+ try {
5938
+ let repoRoot;
5939
+ try {
5940
+ const gitCommonDir = execSync6("git rev-parse --path-format=absolute --git-common-dir", {
5941
+ cwd: dir,
5942
+ encoding: "utf8",
5943
+ timeout: 2e3,
5944
+ stdio: ["pipe", "pipe", "pipe"]
5945
+ }).trim();
5946
+ repoRoot = path16.dirname(gitCommonDir);
5947
+ } catch {
5948
+ repoRoot = execSync6("git rev-parse --show-toplevel", {
5949
+ cwd: dir,
5950
+ encoding: "utf8",
5951
+ timeout: 2e3,
5952
+ stdio: ["pipe", "pipe", "pipe"]
5953
+ }).trim();
5954
+ }
5955
+ _cached2 = path16.basename(repoRoot);
5956
+ _cachedCwd = dir;
5957
+ return _cached2;
5958
+ } catch {
5959
+ _cached2 = path16.basename(dir);
5960
+ _cachedCwd = dir;
5961
+ return _cached2;
5962
+ }
5963
+ }
5964
+ var _cached2, _cachedCwd;
5965
+ var init_project_name = __esm({
5966
+ "src/lib/project-name.ts"() {
5967
+ "use strict";
5968
+ _cached2 = null;
5969
+ _cachedCwd = null;
5970
+ }
5971
+ });
5972
+
5973
+ // src/lib/session-events.ts
5974
+ var session_events_exports = {};
5975
+ __export(session_events_exports, {
5976
+ ensureSessionEventsTable: () => ensureSessionEventsTable,
5977
+ listRecentSessionEvents: () => listRecentSessionEvents,
5978
+ recordSessionEvent: () => recordSessionEvent
5979
+ });
5980
+ import { randomUUID as randomUUID4 } from "crypto";
5981
+ async function ensureSessionEventsTable(client) {
5982
+ await client.execute(`
5983
+ CREATE TABLE IF NOT EXISTS session_events (
5984
+ id TEXT PRIMARY KEY,
5985
+ agent_id TEXT NOT NULL,
5986
+ agent_role TEXT NOT NULL,
5987
+ session_id TEXT NOT NULL,
5988
+ session_scope TEXT,
5989
+ project_name TEXT NOT NULL,
5990
+ event_index INTEGER NOT NULL,
5991
+ event_type TEXT NOT NULL,
5992
+ tool_name TEXT,
5993
+ tool_use_id TEXT,
5994
+ content TEXT NOT NULL,
5995
+ payload_json TEXT,
5996
+ has_error INTEGER NOT NULL DEFAULT 0,
5997
+ created_at TEXT NOT NULL
5998
+ )
5999
+ `);
6000
+ await client.execute(`
6001
+ CREATE INDEX IF NOT EXISTS idx_session_events_agent_time
6002
+ ON session_events(agent_id, created_at DESC)
6003
+ `);
6004
+ await client.execute(`
6005
+ CREATE INDEX IF NOT EXISTS idx_session_events_session_index
6006
+ ON session_events(session_id, event_index)
6007
+ `);
6008
+ await client.execute(`
6009
+ CREATE INDEX IF NOT EXISTS idx_session_events_scope_agent_time
6010
+ ON session_events(session_scope, agent_id, created_at DESC)
6011
+ `);
6012
+ }
6013
+ async function recordSessionEvent(client, input2) {
6014
+ if (!input2.content || input2.content.trim().length === 0) return;
6015
+ await ensureSessionEventsTable(client);
6016
+ const maxResult = await client.execute({
6017
+ sql: "SELECT COALESCE(MAX(event_index), 0) AS max_index FROM session_events WHERE session_id = ?",
6018
+ args: [input2.sessionId]
6019
+ });
6020
+ const currentMax = Number(maxResult.rows[0]?.max_index ?? 0);
6021
+ const eventIndex = Number.isFinite(currentMax) ? currentMax + 1 : 1;
6022
+ await client.execute({
6023
+ sql: `INSERT INTO session_events (
6024
+ id, agent_id, agent_role, session_id, session_scope, project_name,
6025
+ event_index, event_type, tool_name, tool_use_id, content,
6026
+ payload_json, has_error, created_at
6027
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
6028
+ args: [
6029
+ randomUUID4(),
6030
+ input2.agentId,
6031
+ input2.agentRole,
6032
+ input2.sessionId,
6033
+ input2.sessionScope ?? getCurrentSessionScope(),
6034
+ input2.projectName ?? getProjectName(input2.cwd),
6035
+ eventIndex,
6036
+ input2.eventType,
6037
+ input2.toolName ?? null,
6038
+ input2.toolUseId ?? null,
6039
+ input2.content,
6040
+ input2.payloadJson ?? null,
6041
+ input2.hasError ? 1 : 0,
6042
+ input2.timestamp ?? (/* @__PURE__ */ new Date()).toISOString()
6043
+ ]
6044
+ });
6045
+ }
6046
+ async function listRecentSessionEvents(client, options) {
6047
+ await ensureSessionEventsTable(client);
6048
+ const conditions = ["agent_id = ?"];
6049
+ const args = [options.agentId];
6050
+ if (options.sessionId) {
6051
+ conditions.push("session_id = ?");
6052
+ args.push(options.sessionId);
6053
+ }
6054
+ if (options.eventType) {
6055
+ conditions.push("event_type = ?");
6056
+ args.push(options.eventType);
6057
+ }
6058
+ if (options.projectName && options.projectName !== "all") {
6059
+ conditions.push("project_name = ?");
6060
+ args.push(options.projectName);
6061
+ }
6062
+ const scope = strictSessionScopeFilter(options.sessionScope);
6063
+ const where = `WHERE ${conditions.join(" AND ")}${scope.sql}`;
6064
+ args.push(...scope.args);
6065
+ args.push(Math.min(Math.max(options.limit ?? 20, 1), 100));
6066
+ const result = await client.execute({
6067
+ sql: `SELECT id, agent_id, agent_role, session_id, session_scope,
6068
+ project_name, event_index, event_type, tool_name, tool_use_id,
6069
+ content, payload_json, has_error, created_at
6070
+ FROM session_events
6071
+ ${where}
6072
+ ORDER BY created_at DESC, event_index DESC
6073
+ LIMIT ?`,
6074
+ args
6075
+ });
6076
+ return result.rows.map((row) => ({
6077
+ id: String(row.id),
6078
+ agentId: String(row.agent_id),
6079
+ agentRole: String(row.agent_role),
6080
+ sessionId: String(row.session_id),
6081
+ sessionScope: row.session_scope == null ? null : String(row.session_scope),
6082
+ projectName: String(row.project_name),
6083
+ eventIndex: Number(row.event_index),
6084
+ eventType: String(row.event_type),
6085
+ toolName: row.tool_name == null ? null : String(row.tool_name),
6086
+ toolUseId: row.tool_use_id == null ? null : String(row.tool_use_id),
6087
+ content: String(row.content),
6088
+ payloadJson: row.payload_json == null ? null : String(row.payload_json),
6089
+ hasError: Number(row.has_error) === 1,
6090
+ createdAt: String(row.created_at)
6091
+ }));
6092
+ }
6093
+ var init_session_events = __esm({
6094
+ "src/lib/session-events.ts"() {
6095
+ "use strict";
6096
+ init_task_scope();
6097
+ init_project_name();
6098
+ }
6099
+ });
6100
+
5889
6101
  // src/lib/memory-queue.ts
5890
6102
  import { appendFileSync as appendFileSync2, readFileSync as readFileSync11, renameSync as renameSync5, unlinkSync as unlinkSync4, existsSync as existsSync14, statSync as statSync4 } from "fs";
5891
- import path16 from "path";
6103
+ import path17 from "path";
5892
6104
  function enqueueMemory(entry) {
5893
6105
  appendFileSync2(QUEUE_PATH2, JSON.stringify(entry) + "\n");
5894
6106
  }
@@ -5897,7 +6109,7 @@ var init_memory_queue = __esm({
5897
6109
  "src/lib/memory-queue.ts"() {
5898
6110
  "use strict";
5899
6111
  init_config();
5900
- QUEUE_PATH2 = path16.join(EXE_AI_DIR, "memory-queue.jsonl");
6112
+ QUEUE_PATH2 = path17.join(EXE_AI_DIR, "memory-queue.jsonl");
5901
6113
  PROCESSING_PATH = QUEUE_PATH2 + ".processing";
5902
6114
  TTL_MS2 = 24 * 60 * 60 * 1e3;
5903
6115
  }
@@ -5963,7 +6175,7 @@ init_config();
5963
6175
  init_config();
5964
6176
  import { spawn as spawn2 } from "child_process";
5965
6177
  import { existsSync as existsSync15, openSync as openSync2, closeSync as closeSync2 } from "fs";
5966
- import path17 from "path";
6178
+ import path18 from "path";
5967
6179
  import { fileURLToPath as fileURLToPath3 } from "url";
5968
6180
 
5969
6181
  // src/lib/active-agent.ts
@@ -6084,7 +6296,7 @@ if (!process.env.AGENT_ID) {
6084
6296
  if (!loadConfigSync().autoIngestion) {
6085
6297
  process.exit(0);
6086
6298
  }
6087
- var WORKER_LOG_PATH = path17.join(EXE_AI_DIR, "workers.log");
6299
+ var WORKER_LOG_PATH = path18.join(EXE_AI_DIR, "workers.log");
6088
6300
  function openWorkerLog() {
6089
6301
  try {
6090
6302
  return openSync2(WORKER_LOG_PATH, "a");
@@ -6122,13 +6334,13 @@ process.stdin.setEncoding("utf8");
6122
6334
  process.stdin.on("data", (chunk) => {
6123
6335
  if (input.length < MAX_INPUT_SIZE) input += chunk;
6124
6336
  });
6125
- process.stdin.on("end", () => {
6337
+ process.stdin.on("end", async () => {
6126
6338
  try {
6127
6339
  if (process.env.EXE_DEBUG_HOOKS || process.env.EXE_RUNTIME === "codex") {
6128
6340
  try {
6129
- const debugPath = path17.join(EXE_AI_DIR, "logs", "hook-stdin-stop.log");
6341
+ const debugPath = path18.join(EXE_AI_DIR, "logs", "hook-stdin-stop.log");
6130
6342
  const { mkdirSync: mkdirSync8, writeFileSync: writeFileSync8 } = __require("fs");
6131
- mkdirSync8(path17.dirname(debugPath), { recursive: true });
6343
+ mkdirSync8(path18.dirname(debugPath), { recursive: true });
6132
6344
  const ts = (/* @__PURE__ */ new Date()).toISOString();
6133
6345
  const snippet = input.length > 500 ? input.slice(0, 500) + "...[truncated]" : input;
6134
6346
  writeFileSync8(debugPath, `[${ts}] len=${input.length} ${snippet}
@@ -6138,11 +6350,11 @@ process.stdin.on("end", () => {
6138
6350
  }
6139
6351
  const data = JSON.parse(input);
6140
6352
  const agent = getActiveAgent();
6141
- const message = data.last_assistant_message ?? "";
6353
+ const message = data.last_assistant_message || readLastAssistantMessageFromTranscript(data.transcript_path) || "";
6142
6354
  const cwd = data.cwd ?? process.cwd();
6143
6355
  if (process.env.EXE_RUNTIME === "codex" && !canCoordinate(agent.agentId, agent.agentRole)) {
6144
- const codexFinalizerPath = path17.resolve(
6145
- path17.dirname(fileURLToPath3(import.meta.url)),
6356
+ const codexFinalizerPath = path18.resolve(
6357
+ path18.dirname(fileURLToPath3(import.meta.url)),
6146
6358
  "codex-stop-task-finalizer.js"
6147
6359
  );
6148
6360
  spawnDetachedWorker(codexFinalizerPath, {
@@ -6156,6 +6368,21 @@ process.stdin.on("end", () => {
6156
6368
  if (!message || message.length < MIN_LENGTH) {
6157
6369
  process.exit(0);
6158
6370
  }
6371
+ try {
6372
+ const { fastDbInit: fastDbInit2 } = await Promise.resolve().then(() => (init_fast_db_init(), fast_db_init_exports));
6373
+ const { recordSessionEvent: recordSessionEvent2 } = await Promise.resolve().then(() => (init_session_events(), session_events_exports));
6374
+ const client = await fastDbInit2();
6375
+ await recordSessionEvent2(client, {
6376
+ agentId: agent.agentId,
6377
+ agentRole: agent.agentRole,
6378
+ sessionId: data.session_id,
6379
+ eventType: "assistant_response",
6380
+ content: message.slice(0, 2e4),
6381
+ cwd,
6382
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
6383
+ });
6384
+ } catch {
6385
+ }
6159
6386
  const CAPACITY_SIGNALS = /context[- ]?full|hit capacity|conversation is too long|maximum context length|context window.*(?:limit|exceed|full)/i;
6160
6387
  if (!canCoordinate(agent.agentId, agent.agentRole) && CAPACITY_SIGNALS.test(message)) {
6161
6388
  Promise.resolve().then(() => (init_fast_db_init(), fast_db_init_exports)).then(({ fastDbInit: fastDbInit2 }) => fastDbInit2()).then(async (client) => {
@@ -6229,3 +6456,43 @@ process.stdin.on("end", () => {
6229
6456
  }
6230
6457
  process.exit(0);
6231
6458
  });
6459
+ function readLastAssistantMessageFromTranscript(transcriptPath) {
6460
+ if (!transcriptPath) return null;
6461
+ try {
6462
+ const { readFileSync: readFileSync12 } = __require("fs");
6463
+ const text = readFileSync12(transcriptPath, "utf8");
6464
+ const lines = text.trim().split("\n").reverse();
6465
+ for (const line of lines) {
6466
+ try {
6467
+ const event = JSON.parse(line);
6468
+ const message = extractAssistantText(event);
6469
+ if (message) return message;
6470
+ } catch {
6471
+ }
6472
+ }
6473
+ } catch {
6474
+ return null;
6475
+ }
6476
+ return null;
6477
+ }
6478
+ function extractAssistantText(event) {
6479
+ const obj = event;
6480
+ if (obj.type !== "assistant" && obj.role !== "assistant") return null;
6481
+ const message = obj.message ?? obj;
6482
+ const content = message.content;
6483
+ if (typeof content === "string") return content.trim() || null;
6484
+ if (Array.isArray(content)) {
6485
+ const parts = content.map((part) => {
6486
+ if (typeof part === "string") return part;
6487
+ if (part && typeof part === "object") {
6488
+ const p = part;
6489
+ if (typeof p.text === "string") return p.text;
6490
+ if (typeof p.content === "string") return p.content;
6491
+ }
6492
+ return "";
6493
+ }).filter(Boolean);
6494
+ const joined = parts.join("\n").trim();
6495
+ return joined || null;
6496
+ }
6497
+ return null;
6498
+ }
@@ -2741,6 +2741,33 @@ async function ensureSchema() {
2741
2741
  CREATE INDEX IF NOT EXISTS idx_chat_history_session
2742
2742
  ON chat_history(session_id, id);
2743
2743
  `);
2744
+ await client.executeMultiple(`
2745
+ CREATE TABLE IF NOT EXISTS session_events (
2746
+ id TEXT PRIMARY KEY,
2747
+ agent_id TEXT NOT NULL,
2748
+ agent_role TEXT NOT NULL,
2749
+ session_id TEXT NOT NULL,
2750
+ session_scope TEXT,
2751
+ project_name TEXT NOT NULL,
2752
+ event_index INTEGER NOT NULL,
2753
+ event_type TEXT NOT NULL,
2754
+ tool_name TEXT,
2755
+ tool_use_id TEXT,
2756
+ content TEXT NOT NULL,
2757
+ payload_json TEXT,
2758
+ has_error INTEGER NOT NULL DEFAULT 0,
2759
+ created_at TEXT NOT NULL
2760
+ );
2761
+
2762
+ CREATE INDEX IF NOT EXISTS idx_session_events_agent_time
2763
+ ON session_events(agent_id, created_at DESC);
2764
+
2765
+ CREATE INDEX IF NOT EXISTS idx_session_events_session_index
2766
+ ON session_events(session_id, event_index);
2767
+
2768
+ CREATE INDEX IF NOT EXISTS idx_session_events_scope_agent_time
2769
+ ON session_events(session_scope, agent_id, created_at DESC);
2770
+ `);
2744
2771
  await client.executeMultiple(`
2745
2772
  CREATE TABLE IF NOT EXISTS workspaces (
2746
2773
  id TEXT PRIMARY KEY,
@@ -4572,6 +4599,12 @@ var init_platform_procedures = __esm({
4572
4599
  priority: "p0",
4573
4600
  content: "exe-build-adv is MANDATORY for ALL work touching 3+ files. Run /exe-build-adv --auto BEFORE implementation. Pipeline: Spec \u2192 AC \u2192 Tests \u2192 Evaluate \u2192 Fix. No multi-file feature ships without pipeline artifacts. No exceptions \u2014 managers reject work without them."
4574
4601
  },
4602
+ {
4603
+ title: "Code context first for repository orientation",
4604
+ domain: "workflow",
4605
+ priority: "p1",
4606
+ content: "Before broad repo exploration, symbol tracing, blast-radius review, or codebase Q&A, agents should use the consolidated code_context MCP tool instead of manual grep/read loops. Use action=index or stats to refresh/check the index; action=search with query, limit, offset, languages, paths, refresh_index for fresh multi-language code/doc search; action=trace for symbol imports/dependents; action=blast_radius for impact analysis before edits. CLI parity exists via exe-os code-context init|index|status|stats|search|doctor. Keep code_context separate from durable employee memory: promote only validated decisions, procedures, or lessons into store_memory/commit_memory."
4607
+ },
4575
4608
  {
4576
4609
  title: "Commit discipline \u2014 never leave verified work floating",
4577
4610
  domain: "workflow",
@@ -2508,6 +2508,33 @@ async function ensureSchema() {
2508
2508
  CREATE INDEX IF NOT EXISTS idx_chat_history_session
2509
2509
  ON chat_history(session_id, id);
2510
2510
  `);
2511
+ await client.executeMultiple(`
2512
+ CREATE TABLE IF NOT EXISTS session_events (
2513
+ id TEXT PRIMARY KEY,
2514
+ agent_id TEXT NOT NULL,
2515
+ agent_role TEXT NOT NULL,
2516
+ session_id TEXT NOT NULL,
2517
+ session_scope TEXT,
2518
+ project_name TEXT NOT NULL,
2519
+ event_index INTEGER NOT NULL,
2520
+ event_type TEXT NOT NULL,
2521
+ tool_name TEXT,
2522
+ tool_use_id TEXT,
2523
+ content TEXT NOT NULL,
2524
+ payload_json TEXT,
2525
+ has_error INTEGER NOT NULL DEFAULT 0,
2526
+ created_at TEXT NOT NULL
2527
+ );
2528
+
2529
+ CREATE INDEX IF NOT EXISTS idx_session_events_agent_time
2530
+ ON session_events(agent_id, created_at DESC);
2531
+
2532
+ CREATE INDEX IF NOT EXISTS idx_session_events_session_index
2533
+ ON session_events(session_id, event_index);
2534
+
2535
+ CREATE INDEX IF NOT EXISTS idx_session_events_scope_agent_time
2536
+ ON session_events(session_scope, agent_id, created_at DESC);
2537
+ `);
2511
2538
  await client.executeMultiple(`
2512
2539
  CREATE TABLE IF NOT EXISTS workspaces (
2513
2540
  id TEXT PRIMARY KEY,
@@ -4171,6 +4198,12 @@ var init_platform_procedures = __esm({
4171
4198
  priority: "p0",
4172
4199
  content: "exe-build-adv is MANDATORY for ALL work touching 3+ files. Run /exe-build-adv --auto BEFORE implementation. Pipeline: Spec \u2192 AC \u2192 Tests \u2192 Evaluate \u2192 Fix. No multi-file feature ships without pipeline artifacts. No exceptions \u2014 managers reject work without them."
4173
4200
  },
4201
+ {
4202
+ title: "Code context first for repository orientation",
4203
+ domain: "workflow",
4204
+ priority: "p1",
4205
+ content: "Before broad repo exploration, symbol tracing, blast-radius review, or codebase Q&A, agents should use the consolidated code_context MCP tool instead of manual grep/read loops. Use action=index or stats to refresh/check the index; action=search with query, limit, offset, languages, paths, refresh_index for fresh multi-language code/doc search; action=trace for symbol imports/dependents; action=blast_radius for impact analysis before edits. CLI parity exists via exe-os code-context init|index|status|stats|search|doctor. Keep code_context separate from durable employee memory: promote only validated decisions, procedures, or lessons into store_memory/commit_memory."
4206
+ },
4174
4207
  {
4175
4208
  title: "Commit discipline \u2014 never leave verified work floating",
4176
4209
  domain: "workflow",