@askexenow/exe-os 0.9.65 → 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 (113) 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} +1532 -2173
  6. package/dist/bin/backfill-conversations.js +528 -20
  7. package/dist/bin/backfill-responses.js +528 -20
  8. package/dist/bin/backfill-vectors.js +255 -20
  9. package/dist/bin/bulk-sync-postgres.js +4876 -0
  10. package/dist/bin/cleanup-stale-review-tasks.js +529 -21
  11. package/dist/bin/cli.js +3471 -1491
  12. package/dist/bin/exe-agent-config.js +4 -0
  13. package/dist/bin/exe-agent.js +16 -0
  14. package/dist/bin/exe-assign.js +528 -20
  15. package/dist/bin/exe-boot.js +492 -54
  16. package/dist/bin/exe-call.js +16 -0
  17. package/dist/bin/exe-cloud.js +7415 -518
  18. package/dist/bin/exe-dispatch.js +540 -22
  19. package/dist/bin/exe-doctor.js +3404 -1225
  20. package/dist/bin/exe-export-behaviors.js +542 -24
  21. package/dist/bin/exe-forget.js +529 -21
  22. package/dist/bin/exe-gateway.js +595 -25
  23. package/dist/bin/exe-heartbeat.js +541 -24
  24. package/dist/bin/exe-kill.js +529 -21
  25. package/dist/bin/exe-launch-agent.js +2334 -1067
  26. package/dist/bin/exe-new-employee.js +324 -166
  27. package/dist/bin/exe-pending-messages.js +529 -21
  28. package/dist/bin/exe-pending-notifications.js +529 -21
  29. package/dist/bin/exe-pending-reviews.js +529 -21
  30. package/dist/bin/exe-rename.js +529 -21
  31. package/dist/bin/exe-review.js +529 -21
  32. package/dist/bin/exe-search.js +542 -24
  33. package/dist/bin/exe-session-cleanup.js +540 -22
  34. package/dist/bin/exe-settings.js +14 -0
  35. package/dist/bin/exe-start-codex.js +817 -144
  36. package/dist/bin/exe-start-opencode.js +776 -80
  37. package/dist/bin/exe-status.js +529 -21
  38. package/dist/bin/exe-team.js +529 -21
  39. package/dist/bin/git-sweep.js +540 -22
  40. package/dist/bin/graph-backfill.js +580 -21
  41. package/dist/bin/graph-export.js +529 -21
  42. package/dist/bin/graph-layer-benchmark.js +109 -0
  43. package/dist/bin/install.js +420 -289
  44. package/dist/bin/intercom-check.js +540 -22
  45. package/dist/bin/postgres-agentic-reflection-backfill.js +187 -0
  46. package/dist/bin/postgres-agentic-semantic-backfill.js +237 -0
  47. package/dist/bin/scan-tasks.js +540 -22
  48. package/dist/bin/setup.js +790 -206
  49. package/dist/bin/shard-migrate.js +528 -20
  50. package/dist/bin/update.js +4 -0
  51. package/dist/gateway/index.js +593 -23
  52. package/dist/hooks/bug-report-worker.js +651 -64
  53. package/dist/hooks/codex-stop-task-finalizer.js +540 -22
  54. package/dist/hooks/commit-complete.js +540 -22
  55. package/dist/hooks/error-recall.js +542 -24
  56. package/dist/hooks/exe-heartbeat-hook.js +4 -0
  57. package/dist/hooks/ingest-worker.js +4 -0
  58. package/dist/hooks/ingest.js +539 -22
  59. package/dist/hooks/instructions-loaded.js +529 -21
  60. package/dist/hooks/notification.js +529 -21
  61. package/dist/hooks/post-compact.js +529 -21
  62. package/dist/hooks/post-tool-combined.js +543 -25
  63. package/dist/hooks/pre-compact.js +772 -127
  64. package/dist/hooks/pre-tool-use.js +529 -21
  65. package/dist/hooks/prompt-submit.js +543 -25
  66. package/dist/hooks/session-end.js +673 -140
  67. package/dist/hooks/session-start.js +662 -26
  68. package/dist/hooks/stop.js +540 -23
  69. package/dist/hooks/subagent-stop.js +529 -21
  70. package/dist/hooks/summary-worker.js +571 -126
  71. package/dist/index.js +593 -23
  72. package/dist/lib/agent-config.js +4 -0
  73. package/dist/lib/cloud-sync.js +408 -47
  74. package/dist/lib/config.js +25 -1
  75. package/dist/lib/consolidation.js +5 -1
  76. package/dist/lib/database.js +128 -0
  77. package/dist/lib/db-daemon-client.js +4 -0
  78. package/dist/lib/db.js +128 -0
  79. package/dist/lib/device-registry.js +128 -0
  80. package/dist/lib/embedder.js +25 -1
  81. package/dist/lib/employee-templates.js +16 -0
  82. package/dist/lib/employees.js +4 -0
  83. package/dist/lib/exe-daemon-client.js +4 -0
  84. package/dist/lib/exe-daemon.js +3158 -930
  85. package/dist/lib/hybrid-search.js +542 -24
  86. package/dist/lib/identity.js +7 -0
  87. package/dist/lib/keychain.js +178 -22
  88. package/dist/lib/license.js +4 -0
  89. package/dist/lib/messaging.js +7 -0
  90. package/dist/lib/reminders.js +7 -0
  91. package/dist/lib/schedules.js +255 -20
  92. package/dist/lib/skill-learning.js +28 -1
  93. package/dist/lib/status-brief.js +39 -0
  94. package/dist/lib/store.js +528 -20
  95. package/dist/lib/task-router.js +4 -0
  96. package/dist/lib/tasks.js +28 -1
  97. package/dist/lib/tmux-routing.js +28 -1
  98. package/dist/lib/token-spend.js +7 -0
  99. package/dist/mcp/server.js +2739 -813
  100. package/dist/mcp/tools/complete-reminder.js +7 -0
  101. package/dist/mcp/tools/create-reminder.js +7 -0
  102. package/dist/mcp/tools/create-task.js +28 -1
  103. package/dist/mcp/tools/deactivate-behavior.js +7 -0
  104. package/dist/mcp/tools/list-reminders.js +7 -0
  105. package/dist/mcp/tools/list-tasks.js +7 -0
  106. package/dist/mcp/tools/send-message.js +7 -0
  107. package/dist/mcp/tools/update-task.js +28 -1
  108. package/dist/runtime/index.js +540 -22
  109. package/dist/tui/App.js +618 -29
  110. package/package.json +9 -5
  111. package/src/commands/exe/cloud.md +11 -8
  112. package/stack.release.json +3 -3
  113. package/src/commands/exe/link.md +0 -17
@@ -0,0 +1,187 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/bin/postgres-agentic-reflection-backfill.ts
4
+ import { Client } from "pg";
5
+
6
+ // src/lib/agentic-ontology.ts
7
+ import { createHash } from "crypto";
8
+ function stableId(...parts) {
9
+ return createHash("sha256").update(parts.map((p) => String(p ?? "")).join("::")).digest("hex").slice(0, 32);
10
+ }
11
+ function clean(text, max = 240) {
12
+ return text.replace(/\u0000/g, "").replace(/```[\s\S]*?```/g, " ").replace(/\s+/g, " ").trim().slice(0, max);
13
+ }
14
+
15
+ // src/lib/reflection-checkpoints.ts
16
+ function parsePayload(payload) {
17
+ if (!payload) return {};
18
+ try {
19
+ return JSON.parse(payload);
20
+ } catch {
21
+ return {};
22
+ }
23
+ }
24
+ function semanticArray(event, key) {
25
+ const payload = parsePayload(event.payload);
26
+ const semantic = payload.semantic;
27
+ const value = semantic?.[key];
28
+ return Array.isArray(value) ? value.map(String).filter(Boolean) : [];
29
+ }
30
+ function buildReflectionCheckpoint(events) {
31
+ if (!events.length) return null;
32
+ const sorted = [...events].sort((a, b) => a.occurred_at.localeCompare(b.occurred_at));
33
+ const first = sorted[0];
34
+ const last = sorted[sorted.length - 1];
35
+ const goals = /* @__PURE__ */ new Set();
36
+ const successes = [];
37
+ const failures = [];
38
+ const risks = [];
39
+ const nextActions = [];
40
+ const decisions = [];
41
+ for (const event of sorted) {
42
+ for (const goal of semanticArray(event, "goals")) goals.add(goal);
43
+ for (const item of semanticArray(event, "successSignals")) successes.push(item);
44
+ for (const item of semanticArray(event, "failureSignals")) failures.push(item);
45
+ for (const item of semanticArray(event, "nextActions")) nextActions.push(item);
46
+ for (const item of semanticArray(event, "decisions")) decisions.push(item);
47
+ if (event.impact === "negative" || event.outcome === "failure_signal" || event.event_type === "problem" || event.event_type === "error") {
48
+ failures.push(event.outcome || event.intention || event.event_type);
49
+ }
50
+ if (event.outcome === "risk_signal") risks.push(event.intention || event.outcome);
51
+ if (event.impact === "positive" || event.outcome === "success_signal" || event.event_type === "milestone") {
52
+ successes.push(event.outcome || event.intention || event.event_type);
53
+ }
54
+ }
55
+ const uniqueGoals = [...goals].slice(0, 6);
56
+ const uniqueSuccesses = [...new Set(successes.map((x) => clean(x, 180)).filter(Boolean))].slice(0, 6);
57
+ const uniqueFailures = [...new Set(failures.map((x) => clean(x, 180)).filter(Boolean))].slice(0, 6);
58
+ const uniqueRisks = [...new Set(risks.map((x) => clean(x, 180)).filter(Boolean))].slice(0, 6);
59
+ const uniqueNext = [...new Set(nextActions.map((x) => clean(x, 180)).filter(Boolean))].slice(0, 6);
60
+ const uniqueDecisions = [...new Set(decisions.map((x) => clean(x, 180)).filter(Boolean))].slice(0, 6);
61
+ const learnings = [
62
+ uniqueSuccesses.length ? `Working: ${uniqueSuccesses.slice(0, 3).join("; ")}` : "Working: no strong success signal yet",
63
+ uniqueFailures.length ? `Improve: ${uniqueFailures.slice(0, 3).join("; ")}` : "Improve: no strong failure signal in this window",
64
+ uniqueDecisions.length ? `Decision context: ${uniqueDecisions.slice(0, 2).join("; ")}` : "Decision context: no explicit decision signal"
65
+ ];
66
+ const summary = clean([
67
+ `Window ${first.occurred_at} \u2192 ${last.occurred_at}`,
68
+ `${sorted.length} events`,
69
+ uniqueGoals.length ? `goals: ${uniqueGoals.join("; ")}` : "goals: inferred from event trajectory",
70
+ uniqueSuccesses.length ? `successes: ${uniqueSuccesses.slice(0, 2).join("; ")}` : "successes: none explicit",
71
+ uniqueFailures.length ? `failures: ${uniqueFailures.slice(0, 2).join("; ")}` : "failures: none explicit"
72
+ ].join(". "), 1200);
73
+ return {
74
+ id: stableId("reflection", first.project_name ?? "", first.session_id ?? "", first.occurred_at, last.occurred_at, sorted.length),
75
+ projectName: first.project_name ?? null,
76
+ sessionId: first.session_id ?? null,
77
+ windowStartAt: first.occurred_at,
78
+ windowEndAt: last.occurred_at,
79
+ eventCount: sorted.length,
80
+ goalCount: uniqueGoals.length,
81
+ successCount: uniqueSuccesses.length,
82
+ failureCount: uniqueFailures.length,
83
+ riskCount: uniqueRisks.length,
84
+ summary,
85
+ learnings,
86
+ nextActions: uniqueNext.length ? uniqueNext : ["Continue from latest successful event and resolve highest-impact failure/risk first."],
87
+ evidenceEventIds: sorted.slice(-25).map((e) => e.id),
88
+ confidence: Math.min(0.95, 0.5 + Math.min(sorted.length, 100) / 250 + uniqueGoals.length * 0.03)
89
+ };
90
+ }
91
+
92
+ // src/bin/postgres-agentic-reflection-backfill.ts
93
+ function arg(name) {
94
+ const i = process.argv.indexOf(name);
95
+ return i >= 0 ? process.argv[i + 1] : void 0;
96
+ }
97
+ async function ensureSchema(client) {
98
+ await client.query(`CREATE TABLE IF NOT EXISTS memory.agent_reflection_checkpoints (
99
+ id text PRIMARY KEY,
100
+ project_name text,
101
+ session_id text,
102
+ window_start_at timestamp(3) NOT NULL,
103
+ window_end_at timestamp(3) NOT NULL,
104
+ event_count integer NOT NULL DEFAULT 0,
105
+ goal_count integer NOT NULL DEFAULT 0,
106
+ success_count integer NOT NULL DEFAULT 0,
107
+ failure_count integer NOT NULL DEFAULT 0,
108
+ risk_count integer NOT NULL DEFAULT 0,
109
+ summary text NOT NULL,
110
+ learnings jsonb NOT NULL DEFAULT '[]'::jsonb,
111
+ next_actions jsonb NOT NULL DEFAULT '[]'::jsonb,
112
+ evidence_event_ids jsonb NOT NULL DEFAULT '[]'::jsonb,
113
+ confidence double precision NOT NULL DEFAULT 0,
114
+ created_at timestamp(3) NOT NULL
115
+ )`);
116
+ await client.query(`CREATE INDEX IF NOT EXISTS idx_agent_reflection_project_time ON memory.agent_reflection_checkpoints (project_name, window_end_at)`);
117
+ await client.query(`CREATE INDEX IF NOT EXISTS idx_agent_reflection_session_time ON memory.agent_reflection_checkpoints (session_id, window_end_at)`);
118
+ }
119
+ async function main() {
120
+ const url = process.env.DATABASE_URL || process.env.EXED_DATABASE_URL;
121
+ if (!url) throw new Error("DATABASE_URL or EXED_DATABASE_URL is required");
122
+ const limit = Number(arg("--limit") ?? "20000");
123
+ const windowSize = Number(arg("--window") ?? "100");
124
+ const minEvents = Number(arg("--min-events") ?? "20");
125
+ const project = arg("--project");
126
+ const client = new Client({ connectionString: url });
127
+ await client.connect();
128
+ try {
129
+ await ensureSchema(client);
130
+ const where = project ? "WHERE project_name = $2" : "";
131
+ const params = project ? [limit, project] : [limit];
132
+ const result = await client.query(`SELECT id, event_type, occurred_at::text, actor_agent_id, project_name, session_id,
133
+ intention, outcome, impact, evidence_memory_id, payload::text
134
+ FROM memory.agent_events ${where}
135
+ ORDER BY project_name, session_id, occurred_at, sequence_index
136
+ LIMIT $1`, params);
137
+ const groups = /* @__PURE__ */ new Map();
138
+ for (const event of result.rows) {
139
+ const key = `${event.project_name ?? ""}::${event.session_id ?? ""}`;
140
+ const bucket = groups.get(key) ?? [];
141
+ bucket.push(event);
142
+ groups.set(key, bucket);
143
+ }
144
+ let inserted = 0;
145
+ for (const events of groups.values()) {
146
+ for (let i = 0; i < events.length; i += windowSize) {
147
+ const window = events.slice(i, i + windowSize);
148
+ if (window.length < minEvents) continue;
149
+ const checkpoint = buildReflectionCheckpoint(window);
150
+ if (!checkpoint) continue;
151
+ await client.query(`INSERT INTO memory.agent_reflection_checkpoints
152
+ (id, project_name, session_id, window_start_at, window_end_at, event_count, goal_count,
153
+ success_count, failure_count, risk_count, summary, learnings, next_actions, evidence_event_ids,
154
+ confidence, created_at)
155
+ VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12::jsonb,$13::jsonb,$14::jsonb,$15,now())
156
+ ON CONFLICT (id) DO UPDATE SET summary = excluded.summary, learnings = excluded.learnings,
157
+ next_actions = excluded.next_actions, confidence = excluded.confidence`, [
158
+ checkpoint.id,
159
+ checkpoint.projectName,
160
+ checkpoint.sessionId,
161
+ checkpoint.windowStartAt,
162
+ checkpoint.windowEndAt,
163
+ checkpoint.eventCount,
164
+ checkpoint.goalCount,
165
+ checkpoint.successCount,
166
+ checkpoint.failureCount,
167
+ checkpoint.riskCount,
168
+ checkpoint.summary,
169
+ JSON.stringify(checkpoint.learnings),
170
+ JSON.stringify(checkpoint.nextActions),
171
+ JSON.stringify(checkpoint.evidenceEventIds),
172
+ checkpoint.confidence
173
+ ]);
174
+ inserted++;
175
+ }
176
+ }
177
+ process.stderr.write(`[postgres-agentic-reflection-backfill] Inserted/updated ${inserted} reflection checkpoints.
178
+ `);
179
+ } finally {
180
+ await client.end();
181
+ }
182
+ }
183
+ main().catch((err) => {
184
+ process.stderr.write(`[postgres-agentic-reflection-backfill] FATAL: ${err instanceof Error ? err.message : String(err)}
185
+ `);
186
+ process.exit(1);
187
+ });
@@ -0,0 +1,237 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/bin/postgres-agentic-semantic-backfill.ts
4
+ import { Client } from "pg";
5
+
6
+ // src/lib/agentic-ontology.ts
7
+ import { createHash } from "crypto";
8
+ function stableId(...parts) {
9
+ return createHash("sha256").update(parts.map((p) => String(p ?? "")).join("::")).digest("hex").slice(0, 32);
10
+ }
11
+ function clean(text, max = 240) {
12
+ return text.replace(/\u0000/g, "").replace(/```[\s\S]*?```/g, " ").replace(/\s+/g, " ").trim().slice(0, max);
13
+ }
14
+ function inferOntologyEventType(row) {
15
+ const lower = row.raw_text.toLowerCase();
16
+ if (row.has_error) return "error";
17
+ if (/\b(done|complete|completed|fixed|resolved|shipped|deployed|pushed|published)\b/.test(lower)) return "milestone";
18
+ if (/\b(blocked|failed|error|bug|regression|broken)\b/.test(lower)) return "problem";
19
+ if (/\b(decided|decision|adr|we chose|approved|rejected)\b/.test(lower)) return "decision";
20
+ if (/\b(goal|need to|we need|want to|trying to|objective)\b/.test(lower)) return "goal_signal";
21
+ if (["Bash", "Read", "Edit", "Write", "Grep", "Glob"].includes(row.tool_name)) return "tool_action";
22
+ if (row.tool_name.startsWith("memory_card")) return "memory_card";
23
+ return "memory_observation";
24
+ }
25
+ function inferIntention(row) {
26
+ if (row.intent) return clean(row.intent, 220);
27
+ const text = clean(row.raw_text, 1e3);
28
+ const patterns = [
29
+ /(?: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,
30
+ /(?:so that|in order to)\s+([^.!?\n]{8,220})/i,
31
+ /(?:task|plan):\s*([^.!?\n]{8,220})/i
32
+ ];
33
+ for (const p of patterns) {
34
+ const m = text.match(p);
35
+ if (m?.[1]) return clean(m[1], 220);
36
+ }
37
+ if (["Bash", "Read", "Edit", "Write", "Grep", "Glob"].includes(row.tool_name)) {
38
+ return `${row.tool_name} during ${row.project_name}`;
39
+ }
40
+ return null;
41
+ }
42
+ function inferOutcome(row) {
43
+ if (row.outcome) return clean(row.outcome, 220);
44
+ if (row.has_error) return "error";
45
+ const lower = row.raw_text.toLowerCase();
46
+ if (/\b(done|complete|completed|fixed|resolved|shipped|deployed|pushed|published|passed)\b/.test(lower)) return "success_signal";
47
+ if (/\b(blocked|failed|error|regression|broken|not working|could not)\b/.test(lower)) return "failure_signal";
48
+ if (/\b(warning|risk|concern|caveat)\b/.test(lower)) return "risk_signal";
49
+ return null;
50
+ }
51
+ function extractGoalCandidates(row) {
52
+ const text = clean(row.raw_text, 1600);
53
+ const patterns = [
54
+ /(?: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,
55
+ /(?:success means|success criteria|so that)\s+([^.!?\n]{12,220})/gi
56
+ ];
57
+ const out = [];
58
+ for (const pattern of patterns) {
59
+ for (const m of text.matchAll(pattern)) {
60
+ const candidate = clean(m[1] ?? "", 220);
61
+ if (candidate.length >= 12 && !out.some((x) => x.toLowerCase() === candidate.toLowerCase())) out.push(candidate);
62
+ if (out.length >= 3) return out;
63
+ }
64
+ }
65
+ return out;
66
+ }
67
+ function uniq(values, max = 6) {
68
+ const out = [];
69
+ for (const value of values.map((v) => clean(v, 220)).filter(Boolean)) {
70
+ if (!out.some((x) => x.toLowerCase() === value.toLowerCase())) out.push(value);
71
+ if (out.length >= max) break;
72
+ }
73
+ return out;
74
+ }
75
+ function extractMatches(text, patterns, max = 5) {
76
+ const out = [];
77
+ for (const pattern of patterns) {
78
+ for (const match of text.matchAll(pattern)) {
79
+ const value = match[1] ?? match[0];
80
+ if (value) out.push(value);
81
+ if (out.length >= max) return uniq(out, max);
82
+ }
83
+ }
84
+ return uniq(out, max);
85
+ }
86
+ function inferSemanticLabel(row) {
87
+ const text = clean(row.raw_text, 2400);
88
+ const eventType = inferOntologyEventType(row);
89
+ const intention = inferIntention(row);
90
+ const outcome = inferOutcome(row);
91
+ const goals = extractGoalCandidates(row);
92
+ const milestones = extractMatches(text, [
93
+ /\b(?:completed|finished|fixed|resolved|shipped|deployed|published|pushed|passed)\b([^.!?\n]{0,180})/gi,
94
+ /(?:milestone|done):\s*([^.!?\n]{8,220})/gi
95
+ ]);
96
+ const problems = extractMatches(text, [
97
+ /\b(?:blocked by|failed because|bug|regression|broken|not working|error)\b([^.!?\n]{0,180})/gi,
98
+ /(?:problem|issue|risk):\s*([^.!?\n]{8,220})/gi
99
+ ]);
100
+ const decisions = extractMatches(text, [
101
+ /(?:decided|decision|adr|we chose|approved|rejected)\s+([^.!?\n]{8,220})/gi
102
+ ]);
103
+ const temporalAnchors = extractMatches(text, [
104
+ /\b(\d{4}-\d{2}-\d{2}(?:[T ][0-9:.+-Z]+)?)\b/g,
105
+ /\b(today|yesterday|tomorrow|this week|next week|last week|morning|afternoon|tonight)\b/gi
106
+ ], 8);
107
+ const nextActions = extractMatches(text, [
108
+ /(?:next|todo|follow[- ]?up|remaining|need to)\s*:?\s*([^.!?\n]{8,220})/gi
109
+ ]);
110
+ const actors = uniq([
111
+ row.agent_id,
112
+ ...extractMatches(text, [/\b(?:agent|employee|owner|assignee)[:= ]+([a-zA-Z][a-zA-Z0-9_-]{1,40})/gi], 5)
113
+ ], 6);
114
+ const successSignals = milestones.length ? milestones : outcome === "success_signal" ? [clean(text, 180)] : [];
115
+ const failureSignals = problems.length ? problems : outcome === "failure_signal" || row.has_error ? [clean(text, 180)] : [];
116
+ const impact = successSignals.length && failureSignals.length ? "mixed" : failureSignals.length ? "negative" : successSignals.length ? "positive" : "neutral";
117
+ const signalCount = goals.length + milestones.length + problems.length + decisions.length + nextActions.length;
118
+ return {
119
+ labeler: "deterministic",
120
+ schemaVersion: 1,
121
+ eventType,
122
+ intention,
123
+ outcome,
124
+ impact,
125
+ confidence: Math.min(0.95, 0.45 + signalCount * 0.08 + (intention ? 0.1 : 0) + (outcome ? 0.1 : 0)),
126
+ goals,
127
+ milestones,
128
+ problems,
129
+ decisions,
130
+ actors,
131
+ temporalAnchors,
132
+ successSignals,
133
+ failureSignals,
134
+ nextActions,
135
+ summary: clean(text, 280)
136
+ };
137
+ }
138
+
139
+ // src/bin/postgres-agentic-semantic-backfill.ts
140
+ function arg(name) {
141
+ const i = process.argv.indexOf(name);
142
+ return i >= 0 ? process.argv[i + 1] : void 0;
143
+ }
144
+ async function ensureSchema(client) {
145
+ await client.query(`CREATE TABLE IF NOT EXISTS memory.agent_semantic_labels (
146
+ id text PRIMARY KEY,
147
+ source_memory_id text NOT NULL,
148
+ event_id text,
149
+ labeler text NOT NULL,
150
+ schema_version integer NOT NULL DEFAULT 1,
151
+ confidence double precision NOT NULL DEFAULT 0,
152
+ labels jsonb NOT NULL,
153
+ created_at timestamp(3) NOT NULL,
154
+ updated_at timestamp(3) NOT NULL
155
+ )`);
156
+ await client.query(`CREATE INDEX IF NOT EXISTS idx_agent_semantic_labels_memory ON memory.agent_semantic_labels (source_memory_id, labeler)`);
157
+ await client.query(`CREATE INDEX IF NOT EXISTS idx_agent_semantic_labels_event ON memory.agent_semantic_labels (event_id)`);
158
+ }
159
+ function scrubJson(value) {
160
+ return JSON.stringify(value).replace(/\u0000/g, "").replace(/\\u0000/gi, "").replace(/\\\\u0000/gi, "").replace(/\\u00[0-1][0-9a-f]/gi, " ");
161
+ }
162
+ async function main() {
163
+ const url = process.env.DATABASE_URL || process.env.EXED_DATABASE_URL;
164
+ if (!url) throw new Error("DATABASE_URL or EXED_DATABASE_URL is required");
165
+ const limit = Number(arg("--limit") ?? "20000");
166
+ const project = arg("--project");
167
+ const client = new Client({ connectionString: url });
168
+ await client.connect();
169
+ try {
170
+ await ensureSchema(client);
171
+ const params = project ? [limit, project] : [limit];
172
+ const where = project ? "WHERE project_name = $2" : "";
173
+ const result = await client.query(`SELECT id, agent_id, agent_role, session_id, timestamp::text, tool_name,
174
+ project_name, has_error, raw_text, version, task_id, intent, null::text as outcome, domain, null::text as trajectory
175
+ FROM memory.memory_records ${where}
176
+ ORDER BY timestamp DESC LIMIT $1`, params);
177
+ let count = 0;
178
+ for (const row of result.rows) {
179
+ const label = inferSemanticLabel({ ...row, has_error: row.has_error ? 1 : 0 });
180
+ const eventId = stableId(`event:${row.id}`);
181
+ const labelJson = scrubJson(label);
182
+ try {
183
+ await client.query(`INSERT INTO memory.agent_semantic_labels
184
+ (id, source_memory_id, event_id, labeler, schema_version, confidence, labels, created_at, updated_at)
185
+ VALUES ($1,$2,$3,$4,$5,$6,to_jsonb($7::text),now(),now())
186
+ ON CONFLICT (id) DO UPDATE SET confidence = excluded.confidence, labels = excluded.labels,
187
+ updated_at = excluded.updated_at`, [
188
+ stableId(`semantic:${row.id}:${label.labeler}:${label.schemaVersion}`),
189
+ row.id,
190
+ eventId,
191
+ label.labeler,
192
+ label.schemaVersion,
193
+ label.confidence,
194
+ labelJson
195
+ ]);
196
+ } catch {
197
+ const minimal = scrubJson({
198
+ labeler: label.labeler,
199
+ schemaVersion: label.schemaVersion,
200
+ eventType: label.eventType,
201
+ intention: label.intention,
202
+ outcome: label.outcome,
203
+ impact: label.impact,
204
+ confidence: label.confidence,
205
+ goals: label.goals,
206
+ summary: label.summary,
207
+ sanitized: true
208
+ });
209
+ await client.query(`INSERT INTO memory.agent_semantic_labels
210
+ (id, source_memory_id, event_id, labeler, schema_version, confidence, labels, created_at, updated_at)
211
+ VALUES ($1,$2,$3,$4,$5,$6,$7::jsonb,now(),now())
212
+ ON CONFLICT (id) DO UPDATE SET confidence = excluded.confidence, labels = excluded.labels,
213
+ updated_at = excluded.updated_at`, [
214
+ stableId(`semantic:${row.id}:${label.labeler}:${label.schemaVersion}`),
215
+ row.id,
216
+ eventId,
217
+ label.labeler,
218
+ label.schemaVersion,
219
+ label.confidence,
220
+ minimal
221
+ ]);
222
+ }
223
+ count++;
224
+ if (count % 5e3 === 0) process.stderr.write(`[postgres-agentic-semantic-backfill] labeled ${count}
225
+ `);
226
+ }
227
+ process.stderr.write(`[postgres-agentic-semantic-backfill] Complete: ${count} semantic labels.
228
+ `);
229
+ } finally {
230
+ await client.end();
231
+ }
232
+ }
233
+ main().catch((err) => {
234
+ process.stderr.write(`[postgres-agentic-semantic-backfill] FATAL: ${err instanceof Error ? err.message : String(err)}
235
+ `);
236
+ process.exit(1);
237
+ });