@stackmemoryai/stackmemory 1.10.5 → 1.14.0

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 (225) hide show
  1. package/LICENSE +131 -64
  2. package/README.md +107 -24
  3. package/bin/claude-sm +16 -1
  4. package/bin/claude-smd +16 -1
  5. package/bin/codex-smd +16 -1
  6. package/bin/gemini-sm +16 -1
  7. package/bin/hermes-sm +21 -0
  8. package/bin/hermes-smd +21 -0
  9. package/bin/opencode-sm +16 -1
  10. package/dist/src/cli/claude-sm.js +266 -84
  11. package/dist/src/cli/codex-sm.js +225 -33
  12. package/dist/src/cli/commands/bench.js +209 -2
  13. package/dist/src/cli/commands/brain.js +206 -0
  14. package/dist/src/cli/commands/cache.js +126 -0
  15. package/dist/src/cli/commands/company-os.js +184 -0
  16. package/dist/src/cli/commands/context.js +5 -0
  17. package/dist/src/cli/commands/daemon.js +41 -0
  18. package/dist/src/cli/commands/handoff.js +40 -9
  19. package/dist/src/cli/commands/onboard.js +70 -3
  20. package/dist/src/cli/commands/operator.js +127 -0
  21. package/dist/src/cli/commands/optimize.js +117 -0
  22. package/dist/src/cli/commands/orchestrate.js +232 -5
  23. package/dist/src/cli/commands/orchestrator.js +315 -26
  24. package/dist/src/cli/commands/pack.js +322 -0
  25. package/dist/src/cli/commands/patterns.js +254 -0
  26. package/dist/src/cli/commands/portal.js +161 -0
  27. package/dist/src/cli/commands/scaffold.js +92 -0
  28. package/dist/src/cli/commands/search.js +40 -1
  29. package/dist/src/cli/commands/setup.js +178 -11
  30. package/dist/src/cli/commands/skills.js +10 -1
  31. package/dist/src/cli/commands/state.js +265 -0
  32. package/dist/src/cli/commands/sync.js +253 -0
  33. package/dist/src/cli/commands/tasks.js +130 -1
  34. package/dist/src/cli/commands/vision.js +221 -0
  35. package/dist/src/cli/gemini-sm.js +19 -29
  36. package/dist/src/cli/hermes-sm.js +224 -0
  37. package/dist/src/cli/index.js +105 -39
  38. package/dist/src/cli/opencode-sm.js +38 -21
  39. package/dist/src/cli/utils/determinism-watcher.js +66 -0
  40. package/dist/src/cli/utils/real-cli-bin.js +116 -0
  41. package/dist/src/core/brain/brain-store.js +187 -0
  42. package/dist/src/core/brain/brain-sync.js +193 -0
  43. package/dist/src/core/brain/index.js +78 -0
  44. package/dist/src/core/brain/types.js +10 -0
  45. package/dist/src/core/cache/content-cache.js +238 -0
  46. package/dist/src/{integrations/diffmem → core/cache}/index.js +5 -5
  47. package/dist/src/core/cache/token-estimator.js +39 -0
  48. package/dist/src/core/config/feature-flags.js +2 -6
  49. package/dist/src/core/context/frame-database.js +79 -27
  50. package/dist/src/core/context/recursive-context-manager.js +1 -1
  51. package/dist/src/core/context/rehydration.js +2 -1
  52. package/dist/src/core/cross-search/cross-project-search.js +269 -0
  53. package/dist/src/core/cross-search/index.js +10 -0
  54. package/dist/src/core/database/sqlite-adapter.js +14 -84
  55. package/dist/src/core/extensions/provider-adapter.js +5 -0
  56. package/dist/src/core/models/model-router.js +54 -2
  57. package/dist/src/core/models/provider-pricing.js +58 -4
  58. package/dist/src/core/monitoring/logger.js +2 -1
  59. package/dist/src/core/optimization/trace-optimizer.js +413 -0
  60. package/dist/src/core/patterns/index.js +22 -0
  61. package/dist/src/core/patterns/pattern-applier.js +39 -0
  62. package/dist/src/core/patterns/pattern-observer.js +157 -0
  63. package/dist/src/core/patterns/pattern-store.js +259 -0
  64. package/dist/src/core/patterns/types.js +19 -0
  65. package/dist/src/core/provenance/confidence-scorer.js +128 -0
  66. package/dist/src/core/provenance/index.js +40 -0
  67. package/dist/src/core/provenance/provenance-store.js +194 -0
  68. package/dist/src/core/provenance/types.js +82 -0
  69. package/dist/src/core/retrieval/llm-context-retrieval.js +5 -4
  70. package/dist/src/core/retrieval/unified-context-assembler.js +11 -66
  71. package/dist/src/core/session/project-handoff.js +64 -0
  72. package/dist/src/core/session/session-manager.js +28 -0
  73. package/dist/src/core/shared-state/canonical-store.js +564 -0
  74. package/dist/src/core/skill-packs/index.js +18 -0
  75. package/dist/src/core/skill-packs/parser.js +42 -0
  76. package/dist/src/core/skill-packs/registry.js +224 -0
  77. package/dist/src/core/skill-packs/types.js +79 -0
  78. package/dist/src/core/storage/cloud-sync-manager.js +116 -0
  79. package/dist/src/core/storage/cloud-sync.js +574 -0
  80. package/dist/src/core/storage/two-tier-storage.js +5 -1
  81. package/dist/src/core/tasks/master-tasks-template.js +43 -0
  82. package/dist/src/core/tasks/md-task-parser.js +138 -0
  83. package/dist/src/core/trace/trace-event-store.js +282 -0
  84. package/dist/src/core/vision/index.js +27 -0
  85. package/dist/src/core/vision/signals.js +79 -0
  86. package/dist/src/core/vision/types.js +22 -0
  87. package/dist/src/core/vision/vision-file.js +146 -0
  88. package/dist/src/core/vision/vision-loop.js +220 -0
  89. package/dist/src/core/wiki/wiki-compiler.js +103 -1
  90. package/dist/src/daemon/daemon-config.js +52 -0
  91. package/dist/src/daemon/services/desire-path-service.js +566 -0
  92. package/dist/src/daemon/services/github-service.js +126 -0
  93. package/dist/src/daemon/services/research-stream-service.js +320 -0
  94. package/dist/src/daemon/services/telemetry-service.js +192 -0
  95. package/dist/src/daemon/unified-daemon.js +58 -1
  96. package/dist/src/features/browser/cli-browser-agent.js +417 -0
  97. package/dist/src/features/browser/stagehand-workflows.js +578 -0
  98. package/dist/src/features/operator/adapter-factory.js +62 -0
  99. package/dist/src/features/operator/browser-adapter.js +109 -0
  100. package/dist/src/features/operator/desktop-adapter.js +125 -0
  101. package/dist/src/features/operator/index.js +39 -0
  102. package/dist/src/features/operator/llm-decision.js +137 -0
  103. package/dist/src/features/operator/operator-logger.js +92 -0
  104. package/dist/src/features/operator/overnight-runner.js +327 -0
  105. package/dist/src/features/operator/screen-adapter.js +91 -0
  106. package/dist/src/features/operator/session-manager.js +127 -0
  107. package/dist/src/features/operator/state-machine.js +227 -0
  108. package/dist/src/features/operator/task-queue.js +81 -0
  109. package/dist/src/features/portal/index.js +26 -0
  110. package/dist/src/features/portal/server.js +240 -0
  111. package/dist/src/features/portal/types.js +14 -0
  112. package/dist/src/features/portal/ui.js +195 -0
  113. package/dist/src/features/sweep/pty-wrapper.js +13 -5
  114. package/dist/src/features/tasks/task-aware-context.js +2 -1
  115. package/dist/src/features/tui/simple-monitor.js +0 -23
  116. package/dist/src/features/tui/swarm-monitor.js +8 -66
  117. package/dist/src/features/web/client/hooks/use-socket.js +12 -0
  118. package/dist/src/{core/merge/index.js → features/web/client/lib/utils.js} +8 -4
  119. package/dist/src/features/web/client/next-env.d.js +4 -0
  120. package/dist/src/features/web/client/stores/session-store.js +12 -0
  121. package/dist/src/features/web/server/gcp-billing.js +76 -0
  122. package/dist/src/features/web/server/index.js +10 -0
  123. package/dist/src/features/web/server/spend-calculator.js +228 -0
  124. package/dist/src/hooks/schemas.js +6 -1
  125. package/dist/src/integrations/anthropic/client.js +3 -2
  126. package/dist/src/integrations/claude-code/agent-bridge.js +0 -3
  127. package/dist/src/integrations/claude-code/subagent-client.js +307 -11
  128. package/dist/src/integrations/claude-code/task-coordinator.js +2 -1
  129. package/dist/src/integrations/github/pr-state.js +158 -0
  130. package/dist/src/integrations/linear/client.js +4 -1
  131. package/dist/src/integrations/linear/webhook-retry.js +196 -0
  132. package/dist/src/integrations/linear/webhook-server.js +18 -22
  133. package/dist/src/integrations/mcp/handlers/cloud-sync-handlers.js +101 -0
  134. package/dist/src/integrations/mcp/handlers/index.js +40 -84
  135. package/dist/src/integrations/mcp/server.js +542 -641
  136. package/dist/src/integrations/mcp/tool-alias-registry.js +297 -0
  137. package/dist/src/integrations/mcp/tool-definitions.js +152 -682
  138. package/dist/src/mcp/stackmemory-mcp-server.js +571 -231
  139. package/dist/src/orchestrators/multimodal/determinism.js +244 -0
  140. package/dist/src/orchestrators/multimodal/harness.js +149 -78
  141. package/dist/src/orchestrators/multimodal/providers.js +44 -3
  142. package/dist/src/skills/recursive-agent-orchestrator.js +2 -4
  143. package/dist/src/utils/hook-installer.js +0 -8
  144. package/dist/src/utils/process-cleanup.js +1 -7
  145. package/docs/README.md +42 -0
  146. package/docs/guides/README_INSTALL.md +208 -0
  147. package/package.json +27 -9
  148. package/packs/coding/python-fastapi/instructions.md +60 -0
  149. package/packs/coding/python-fastapi/pack.yaml +28 -0
  150. package/packs/coding/typescript-react/instructions.md +47 -0
  151. package/packs/coding/typescript-react/pack.yaml +28 -0
  152. package/packs/core/commands/capture.md +32 -0
  153. package/packs/core/commands/learn.md +73 -0
  154. package/packs/core/commands/next.md +36 -0
  155. package/packs/core/commands/restart.md +58 -0
  156. package/packs/core/commands/restore.md +29 -0
  157. package/packs/core/commands/start.md +57 -0
  158. package/packs/core/commands/stop.md +65 -0
  159. package/packs/core/commands/summary.md +40 -0
  160. package/packs/core/manifest.json +24 -0
  161. package/packs/ops/decision-recovery/instructions.md +65 -0
  162. package/packs/ops/decision-recovery/pack.yaml +89 -0
  163. package/scripts/claude-code-wrapper.sh +11 -0
  164. package/scripts/claude-sm-setup.sh +12 -1
  165. package/scripts/codex-wrapper.sh +11 -0
  166. package/scripts/git-hooks/branch-context-manager.sh +11 -0
  167. package/scripts/git-hooks/post-checkout-stackmemory.sh +11 -0
  168. package/scripts/git-hooks/post-commit-stackmemory.sh +11 -0
  169. package/scripts/git-hooks/pre-commit-stackmemory.sh +11 -0
  170. package/scripts/hooks/cleanup-shell.sh +12 -1
  171. package/scripts/hooks/task-complete.sh +12 -1
  172. package/scripts/install-code-execution-hooks.sh +12 -1
  173. package/scripts/install-sweep-hook.sh +12 -0
  174. package/scripts/install.sh +11 -0
  175. package/scripts/opencode-wrapper.sh +11 -0
  176. package/scripts/portal/cloud-init.yaml +69 -0
  177. package/scripts/portal/setup.sh +69 -0
  178. package/scripts/portal/stackmemory-portal.service +34 -0
  179. package/scripts/setup-claude-integration.sh +12 -1
  180. package/scripts/smoke-init-db.sh +23 -0
  181. package/scripts/stackmemory-daemon.sh +11 -0
  182. package/scripts/verify-dist.cjs +11 -4
  183. package/dist/src/cli/commands/ralph.js +0 -1053
  184. package/dist/src/cli/commands/team.js +0 -168
  185. package/dist/src/core/context/shared-context-layer.js +0 -620
  186. package/dist/src/core/context/stack-merge-resolver.js +0 -748
  187. package/dist/src/core/merge/conflict-detector.js +0 -430
  188. package/dist/src/core/merge/resolution-engine.js +0 -557
  189. package/dist/src/core/merge/stack-diff.js +0 -531
  190. package/dist/src/core/merge/unified-merge-resolver.js +0 -302
  191. package/dist/src/hooks/diffmem-hooks.js +0 -376
  192. package/dist/src/integrations/diffmem/client.js +0 -208
  193. package/dist/src/integrations/diffmem/config.js +0 -14
  194. package/dist/src/integrations/greptile/client.js +0 -101
  195. package/dist/src/integrations/greptile/config.js +0 -14
  196. package/dist/src/integrations/greptile/index.js +0 -11
  197. package/dist/src/integrations/mcp/handlers/cord-handlers.js +0 -397
  198. package/dist/src/integrations/mcp/handlers/diffmem-handlers.js +0 -455
  199. package/dist/src/integrations/mcp/handlers/greptile-handlers.js +0 -456
  200. package/dist/src/integrations/mcp/handlers/provider-handlers.js +0 -227
  201. package/dist/src/integrations/mcp/handlers/team-handlers.js +0 -211
  202. package/dist/src/integrations/ralph/bridge/ralph-stackmemory-bridge.js +0 -863
  203. package/dist/src/integrations/ralph/context/context-budget-manager.js +0 -308
  204. package/dist/src/integrations/ralph/context/stackmemory-context-loader.js +0 -391
  205. package/dist/src/integrations/ralph/index.js +0 -17
  206. package/dist/src/integrations/ralph/learning/pattern-learner.js +0 -435
  207. package/dist/src/integrations/ralph/lifecycle/iteration-lifecycle.js +0 -448
  208. package/dist/src/integrations/ralph/loopmax.js +0 -488
  209. package/dist/src/integrations/ralph/monitoring/swarm-dashboard.js +0 -293
  210. package/dist/src/integrations/ralph/monitoring/swarm-registry.js +0 -107
  211. package/dist/src/integrations/ralph/orchestration/multi-loop-orchestrator.js +0 -508
  212. package/dist/src/integrations/ralph/patterns/compounding-engineering-pattern.js +0 -407
  213. package/dist/src/integrations/ralph/patterns/extended-coherence-sessions.js +0 -495
  214. package/dist/src/integrations/ralph/patterns/oracle-worker-pattern.js +0 -387
  215. package/dist/src/integrations/ralph/performance/performance-optimizer.js +0 -357
  216. package/dist/src/integrations/ralph/recovery/crash-recovery.js +0 -461
  217. package/dist/src/integrations/ralph/state/state-reconciler.js +0 -420
  218. package/dist/src/integrations/ralph/swarm/git-workflow-manager.js +0 -444
  219. package/dist/src/integrations/ralph/swarm/swarm-coordinator.js +0 -1007
  220. package/dist/src/integrations/ralph/visualization/ralph-debugger.js +0 -635
  221. package/scripts/ralph-loop-implementation.js +0 -404
  222. /package/dist/src/core/{merge → cache}/types.js +0 -0
  223. /package/dist/src/{integrations/diffmem/types.js → core/storage/cloud-sync-types.js} +0 -0
  224. /package/dist/src/{integrations/greptile/types.js → core/trace/trace-event.js} +0 -0
  225. /package/dist/src/{integrations/ralph → features/operator}/types.js +0 -0
@@ -0,0 +1,138 @@
1
+ import { fileURLToPath as __fileURLToPath } from 'url';
2
+ import { dirname as __pathDirname } from 'path';
3
+ const __filename = __fileURLToPath(import.meta.url);
4
+ const __dirname = __pathDirname(__filename);
5
+ import { readFileSync, writeFileSync } from "fs";
6
+ const HEADER_RE = /^\|\s*id\s*\|/i;
7
+ const SEPARATOR_RE = /^\|[\s-|]+\|$/;
8
+ const PRIORITIES = ["P0", "P1", "P2", "P3"];
9
+ const STATUSES = ["todo", "active", "done", "blocked", "cut"];
10
+ const SYNCS = ["local", "linear", "gh"];
11
+ function parseMasterTasks(content) {
12
+ const lines = content.split("\n");
13
+ const tasks = [];
14
+ let inTable = false;
15
+ for (const line of lines) {
16
+ const trimmed = line.trim();
17
+ if (!trimmed.startsWith("|")) {
18
+ if (inTable) break;
19
+ continue;
20
+ }
21
+ if (HEADER_RE.test(trimmed)) {
22
+ inTable = true;
23
+ continue;
24
+ }
25
+ if (SEPARATOR_RE.test(trimmed)) continue;
26
+ if (!inTable) continue;
27
+ const cells = trimmed.split("|").slice(1, -1).map((c) => c.trim());
28
+ if (cells.length < 8) continue;
29
+ const [id, priority, status, owner, sync, task, branchPr, notes] = cells;
30
+ if (!id || !PRIORITIES.includes(priority)) continue;
31
+ tasks.push({
32
+ id,
33
+ priority,
34
+ status: STATUSES.includes(status) ? status : "todo",
35
+ owner: owner || "@me",
36
+ sync: SYNCS.includes(sync) ? sync : "local",
37
+ task: task || "",
38
+ branchPr: branchPr || "",
39
+ notes: notes || ""
40
+ });
41
+ }
42
+ return tasks;
43
+ }
44
+ function serializeTaskRows(tasks) {
45
+ return tasks.map(
46
+ (t) => `| ${t.id} | ${t.priority} | ${t.status} | ${t.owner} | ${t.sync} | ${t.task} | ${t.branchPr} | ${t.notes} |`
47
+ ).join("\n");
48
+ }
49
+ function updateTaskInFile(filePath, taskId, updates) {
50
+ const content = readFileSync(filePath, "utf-8");
51
+ const lines = content.split("\n");
52
+ let found = false;
53
+ const updated = lines.map((line) => {
54
+ const trimmed = line.trim();
55
+ if (!trimmed.startsWith("|") || HEADER_RE.test(trimmed) || SEPARATOR_RE.test(trimmed)) {
56
+ return line;
57
+ }
58
+ const cells = trimmed.split("|").slice(1, -1).map((c) => c.trim());
59
+ if (cells.length < 8 || cells[0] !== taskId) return line;
60
+ found = true;
61
+ const task = {
62
+ id: cells[0],
63
+ priority: updates.priority ?? cells[1],
64
+ status: updates.status ?? cells[2],
65
+ owner: updates.owner ?? cells[3],
66
+ sync: updates.sync ?? cells[4],
67
+ task: updates.task ?? cells[5],
68
+ branchPr: updates.branchPr ?? cells[6],
69
+ notes: updates.notes ?? cells[7]
70
+ };
71
+ return `| ${task.id} | ${task.priority} | ${task.status} | ${task.owner} | ${task.sync} | ${task.task} | ${task.branchPr} | ${task.notes} |`;
72
+ });
73
+ if (!found) throw new Error(`Task ${taskId} not found in ${filePath}`);
74
+ writeFileSync(filePath, updated.join("\n"), "utf-8");
75
+ }
76
+ function addTaskToFile(filePath, task) {
77
+ const content = readFileSync(filePath, "utf-8");
78
+ const existing = parseMasterTasks(content);
79
+ const maxNum = existing.reduce((max, t) => {
80
+ const n = parseInt(t.id.replace(/^T/, ""), 10);
81
+ return isNaN(n) ? max : Math.max(max, n);
82
+ }, 0);
83
+ const id = `T${String(maxNum + 1).padStart(2, "0")}`;
84
+ const newRow = `| ${id} | ${task.priority} | ${task.status} | ${task.owner} | ${task.sync} | ${task.task} | ${task.branchPr} | ${task.notes} |`;
85
+ const lines = content.split("\n");
86
+ let insertIdx = -1;
87
+ let inTable = false;
88
+ for (let i = 0; i < lines.length; i++) {
89
+ const trimmed = lines[i].trim();
90
+ if (HEADER_RE.test(trimmed)) {
91
+ inTable = true;
92
+ continue;
93
+ }
94
+ if (inTable && trimmed.startsWith("|") && !SEPARATOR_RE.test(trimmed)) {
95
+ insertIdx = i;
96
+ }
97
+ if (inTable && !trimmed.startsWith("|") && trimmed !== "") {
98
+ break;
99
+ }
100
+ }
101
+ if (insertIdx === -1) {
102
+ for (let i = 0; i < lines.length; i++) {
103
+ if (SEPARATOR_RE.test(lines[i].trim())) {
104
+ insertIdx = i;
105
+ break;
106
+ }
107
+ }
108
+ }
109
+ lines.splice(insertIdx + 1, 0, newRow);
110
+ writeFileSync(filePath, lines.join("\n"), "utf-8");
111
+ return id;
112
+ }
113
+ function getNextTask(tasks) {
114
+ const actionable = tasks.filter(
115
+ (t) => t.status === "todo" || t.status === "active"
116
+ );
117
+ if (actionable.length === 0) return void 0;
118
+ const ownerRank = {
119
+ "@agent": 0,
120
+ "@me": 1,
121
+ "@defer": 2
122
+ };
123
+ actionable.sort((a, b) => {
124
+ const pDiff = PRIORITIES.indexOf(a.priority) - PRIORITIES.indexOf(b.priority);
125
+ if (pDiff !== 0) return pDiff;
126
+ const aRank = ownerRank[a.owner] ?? 1;
127
+ const bRank = ownerRank[b.owner] ?? 1;
128
+ return aRank - bRank;
129
+ });
130
+ return actionable[0];
131
+ }
132
+ export {
133
+ addTaskToFile,
134
+ getNextTask,
135
+ parseMasterTasks,
136
+ serializeTaskRows,
137
+ updateTaskInFile
138
+ };
@@ -0,0 +1,282 @@
1
+ import { fileURLToPath as __fileURLToPath } from 'url';
2
+ import { dirname as __pathDirname } from 'path';
3
+ const __filename = __fileURLToPath(import.meta.url);
4
+ const __dirname = __pathDirname(__filename);
5
+ import { v4 as uuidv4 } from "uuid";
6
+ import { logger } from "../monitoring/logger.js";
7
+ class TraceEventStore {
8
+ db;
9
+ constructor(db) {
10
+ this.db = db;
11
+ this.initSchema();
12
+ }
13
+ initSchema() {
14
+ this.db.exec(`
15
+ CREATE TABLE IF NOT EXISTS trace_events (
16
+ id TEXT PRIMARY KEY,
17
+ timestamp TEXT NOT NULL,
18
+ session_id TEXT NOT NULL,
19
+ trace_id TEXT NOT NULL,
20
+ parent_trace_id TEXT,
21
+ tenant_id TEXT NOT NULL DEFAULT 'local',
22
+ actor_host TEXT NOT NULL DEFAULT 'unknown',
23
+ actor_agent TEXT NOT NULL DEFAULT 'stackmemory-mcp',
24
+ actor_user TEXT NOT NULL DEFAULT 'anonymous',
25
+ operation TEXT NOT NULL,
26
+ inputs TEXT NOT NULL DEFAULT '{}',
27
+ outputs TEXT NOT NULL DEFAULT '{}',
28
+ tokens_in INTEGER NOT NULL DEFAULT 0,
29
+ tokens_out INTEGER NOT NULL DEFAULT 0,
30
+ cost_usd REAL NOT NULL DEFAULT 0,
31
+ duration_ms INTEGER NOT NULL DEFAULT 0,
32
+ score REAL,
33
+ feedback TEXT,
34
+ provenance TEXT NOT NULL DEFAULT '{"sources":[],"derivation":[],"confidence":1}',
35
+ error TEXT,
36
+ tags TEXT
37
+ );
38
+
39
+ CREATE INDEX IF NOT EXISTS idx_te_session ON trace_events(session_id);
40
+ CREATE INDEX IF NOT EXISTS idx_te_trace ON trace_events(trace_id);
41
+ CREATE INDEX IF NOT EXISTS idx_te_operation ON trace_events(operation);
42
+ CREATE INDEX IF NOT EXISTS idx_te_timestamp ON trace_events(timestamp);
43
+ CREATE INDEX IF NOT EXISTS idx_te_score ON trace_events(score) WHERE score IS NOT NULL;
44
+ `);
45
+ }
46
+ // ------------------------------------------------------------------
47
+ // Write
48
+ // ------------------------------------------------------------------
49
+ /**
50
+ * Record a trace event. Generates ID if not present in trace_id.
51
+ */
52
+ record(event) {
53
+ const id = uuidv4();
54
+ this.db.prepare(
55
+ `INSERT INTO trace_events (
56
+ id, timestamp, session_id, trace_id, parent_trace_id, tenant_id,
57
+ actor_host, actor_agent, actor_user,
58
+ operation, inputs, outputs,
59
+ tokens_in, tokens_out, cost_usd, duration_ms,
60
+ score, feedback, provenance, error, tags
61
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
62
+ ).run(
63
+ id,
64
+ event.timestamp,
65
+ event.session_id,
66
+ event.trace_id,
67
+ event.parent_trace_id ?? null,
68
+ event.tenant_id,
69
+ event.actor.host,
70
+ event.actor.agent,
71
+ event.actor.user,
72
+ event.operation,
73
+ JSON.stringify(event.inputs),
74
+ JSON.stringify(event.outputs),
75
+ event.tokens_in,
76
+ event.tokens_out,
77
+ event.cost_usd,
78
+ event.duration_ms,
79
+ event.score ?? null,
80
+ event.feedback ?? null,
81
+ JSON.stringify(event.provenance),
82
+ event.error ?? null,
83
+ event.tags ? JSON.stringify(event.tags) : null
84
+ );
85
+ logger.debug(`TraceEvent recorded: ${event.operation} [${id}]`);
86
+ return id;
87
+ }
88
+ /**
89
+ * Record multiple events in a single transaction.
90
+ */
91
+ recordBatch(events) {
92
+ const ids = [];
93
+ this.db.transaction(() => {
94
+ for (const event of events) {
95
+ ids.push(this.record(event));
96
+ }
97
+ })();
98
+ return ids;
99
+ }
100
+ /**
101
+ * Add score and/or feedback to an existing event.
102
+ */
103
+ annotate(id, annotation) {
104
+ const sets = [];
105
+ const params = [];
106
+ if (annotation.score !== void 0) {
107
+ sets.push("score = ?");
108
+ params.push(annotation.score);
109
+ }
110
+ if (annotation.feedback !== void 0) {
111
+ sets.push("feedback = ?");
112
+ params.push(annotation.feedback);
113
+ }
114
+ if (sets.length === 0) return false;
115
+ params.push(id);
116
+ const result = this.db.prepare(`UPDATE trace_events SET ${sets.join(", ")} WHERE id = ?`).run(...params);
117
+ return result.changes > 0;
118
+ }
119
+ // ------------------------------------------------------------------
120
+ // Read
121
+ // ------------------------------------------------------------------
122
+ /**
123
+ * Get a single event by ID.
124
+ */
125
+ get(id) {
126
+ const row = this.db.prepare("SELECT * FROM trace_events WHERE id = ?").get(id);
127
+ return row ? this.rowToEvent(row) : void 0;
128
+ }
129
+ /**
130
+ * Query events with filters.
131
+ */
132
+ query(filter = {}) {
133
+ const conditions = [];
134
+ const params = [];
135
+ if (filter.session_id) {
136
+ conditions.push("session_id = ?");
137
+ params.push(filter.session_id);
138
+ }
139
+ if (filter.operation) {
140
+ conditions.push("operation = ?");
141
+ params.push(filter.operation);
142
+ }
143
+ if (filter.min_score !== void 0) {
144
+ conditions.push("score >= ?");
145
+ params.push(filter.min_score);
146
+ }
147
+ if (filter.has_feedback) {
148
+ conditions.push("feedback IS NOT NULL");
149
+ }
150
+ if (filter.since) {
151
+ conditions.push("timestamp >= ?");
152
+ params.push(filter.since);
153
+ }
154
+ if (filter.until) {
155
+ conditions.push("timestamp <= ?");
156
+ params.push(filter.until);
157
+ }
158
+ const where = conditions.length ? "WHERE " + conditions.join(" AND ") : "";
159
+ const limit = filter.limit ?? 100;
160
+ const offset = filter.offset ?? 0;
161
+ const rows = this.db.prepare(
162
+ `SELECT * FROM trace_events ${where} ORDER BY timestamp DESC LIMIT ? OFFSET ?`
163
+ ).all(...params, limit, offset);
164
+ return rows.map((r) => this.rowToEvent(r));
165
+ }
166
+ /**
167
+ * Get events for a specific session.
168
+ */
169
+ getBySession(sessionId) {
170
+ return this.query({ session_id: sessionId, limit: 1e3 });
171
+ }
172
+ /**
173
+ * Get events with scores (for GEPA consumption).
174
+ */
175
+ getScoredEvents(minScore) {
176
+ return this.query({
177
+ min_score: minScore ?? 0,
178
+ limit: 500
179
+ });
180
+ }
181
+ /**
182
+ * Get events with feedback (for GEPA ASI consumption).
183
+ */
184
+ getFeedbackEvents() {
185
+ return this.query({ has_feedback: true, limit: 500 });
186
+ }
187
+ // ------------------------------------------------------------------
188
+ // Stats
189
+ // ------------------------------------------------------------------
190
+ /**
191
+ * Aggregate statistics across all events.
192
+ */
193
+ getStats(filter) {
194
+ const conditions = [];
195
+ const params = [];
196
+ if (filter?.session_id) {
197
+ conditions.push("session_id = ?");
198
+ params.push(filter.session_id);
199
+ }
200
+ if (filter?.since) {
201
+ conditions.push("timestamp >= ?");
202
+ params.push(filter.since);
203
+ }
204
+ const where = conditions.length ? "WHERE " + conditions.join(" AND ") : "";
205
+ const agg = this.db.prepare(
206
+ `SELECT
207
+ COUNT(*) as total_events,
208
+ COALESCE(SUM(tokens_in), 0) as total_tokens_in,
209
+ COALESCE(SUM(tokens_out), 0) as total_tokens_out,
210
+ COALESCE(SUM(cost_usd), 0) as total_cost_usd,
211
+ AVG(score) as avg_score,
212
+ SUM(CASE WHEN feedback IS NOT NULL THEN 1 ELSE 0 END) as events_with_feedback,
213
+ SUM(CASE WHEN error IS NOT NULL THEN 1 ELSE 0 END) as events_with_errors
214
+ FROM trace_events ${where}`
215
+ ).get(...params);
216
+ const opRows = this.db.prepare(
217
+ `SELECT operation, COUNT(*) as cnt FROM trace_events ${where} GROUP BY operation ORDER BY cnt DESC`
218
+ ).all(...params);
219
+ const hostRows = this.db.prepare(
220
+ `SELECT actor_host, COUNT(*) as cnt FROM trace_events ${where} GROUP BY actor_host ORDER BY cnt DESC`
221
+ ).all(...params);
222
+ const operations = {};
223
+ for (const r of opRows) operations[r.operation] = r.cnt;
224
+ const hosts = {};
225
+ for (const r of hostRows) hosts[r.actor_host] = r.cnt;
226
+ return {
227
+ total_events: agg["total_events"] || 0,
228
+ total_tokens_in: agg["total_tokens_in"] || 0,
229
+ total_tokens_out: agg["total_tokens_out"] || 0,
230
+ total_cost_usd: agg["total_cost_usd"] || 0,
231
+ avg_score: agg["avg_score"],
232
+ events_with_feedback: agg["events_with_feedback"] || 0,
233
+ events_with_errors: agg["events_with_errors"] || 0,
234
+ operations,
235
+ hosts
236
+ };
237
+ }
238
+ // ------------------------------------------------------------------
239
+ // Lifecycle
240
+ // ------------------------------------------------------------------
241
+ /**
242
+ * Delete events older than the given ISO timestamp.
243
+ */
244
+ evict(olderThan) {
245
+ const result = this.db.prepare("DELETE FROM trace_events WHERE timestamp < ?").run(olderThan);
246
+ return result.changes;
247
+ }
248
+ // ------------------------------------------------------------------
249
+ // Helpers
250
+ // ------------------------------------------------------------------
251
+ rowToEvent(row) {
252
+ const provenance = JSON.parse(row.provenance);
253
+ const actor = {
254
+ host: row.actor_host,
255
+ agent: row.actor_agent,
256
+ user: row.actor_user
257
+ };
258
+ return {
259
+ timestamp: row.timestamp,
260
+ session_id: row.session_id,
261
+ trace_id: row.trace_id,
262
+ parent_trace_id: row.parent_trace_id ?? void 0,
263
+ tenant_id: row.tenant_id,
264
+ actor,
265
+ operation: row.operation,
266
+ inputs: JSON.parse(row.inputs),
267
+ outputs: JSON.parse(row.outputs),
268
+ tokens_in: row.tokens_in,
269
+ tokens_out: row.tokens_out,
270
+ cost_usd: row.cost_usd,
271
+ duration_ms: row.duration_ms,
272
+ score: row.score ?? void 0,
273
+ feedback: row.feedback ?? void 0,
274
+ provenance,
275
+ error: row.error ?? void 0,
276
+ tags: row.tags ? JSON.parse(row.tags) : void 0
277
+ };
278
+ }
279
+ }
280
+ export {
281
+ TraceEventStore
282
+ };
@@ -0,0 +1,27 @@
1
+ import { fileURLToPath as __fileURLToPath } from 'url';
2
+ import { dirname as __pathDirname } from 'path';
3
+ const __filename = __fileURLToPath(import.meta.url);
4
+ const __dirname = __pathDirname(__filename);
5
+ export * from "./types.js";
6
+ import {
7
+ parseVision,
8
+ loadVision,
9
+ setObjectiveDone,
10
+ scaffoldVision,
11
+ objectiveId,
12
+ VISION_TEMPLATE
13
+ } from "./vision-file.js";
14
+ import { SignalInbox } from "./signals.js";
15
+ import {
16
+ VisionLoop
17
+ } from "./vision-loop.js";
18
+ export {
19
+ SignalInbox,
20
+ VISION_TEMPLATE,
21
+ VisionLoop,
22
+ loadVision,
23
+ objectiveId,
24
+ parseVision,
25
+ scaffoldVision,
26
+ setObjectiveDone
27
+ };
@@ -0,0 +1,79 @@
1
+ import { fileURLToPath as __fileURLToPath } from 'url';
2
+ import { dirname as __pathDirname } from 'path';
3
+ const __filename = __fileURLToPath(import.meta.url);
4
+ const __dirname = __pathDirname(__filename);
5
+ import {
6
+ existsSync,
7
+ mkdirSync,
8
+ readFileSync,
9
+ writeFileSync,
10
+ appendFileSync
11
+ } from "fs";
12
+ import { dirname } from "path";
13
+ import { randomUUID } from "crypto";
14
+ class SignalInbox {
15
+ constructor(path) {
16
+ this.path = path;
17
+ }
18
+ ensureDir() {
19
+ const dir = dirname(this.path);
20
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
21
+ }
22
+ add(input) {
23
+ this.ensureDir();
24
+ const signal = {
25
+ id: randomUUID(),
26
+ source: input.source ?? "manual",
27
+ severity: input.severity ?? "medium",
28
+ text: input.text,
29
+ createdAt: Date.now(),
30
+ ...input.refs ? { refs: input.refs } : {}
31
+ };
32
+ appendFileSync(this.path, JSON.stringify(signal) + "\n");
33
+ return signal;
34
+ }
35
+ all() {
36
+ if (!existsSync(this.path)) return [];
37
+ return readFileSync(this.path, "utf-8").split(/\r?\n/).filter(Boolean).map((l) => {
38
+ try {
39
+ return JSON.parse(l);
40
+ } catch {
41
+ return null;
42
+ }
43
+ }).filter((s) => !!s);
44
+ }
45
+ /** Unresolved signals, most severe + oldest first. */
46
+ pending() {
47
+ const rank = {
48
+ low: 1,
49
+ medium: 2,
50
+ high: 3,
51
+ critical: 4
52
+ };
53
+ return this.all().filter((s) => !s.resolvedAt).sort(
54
+ (a, b) => rank[b.severity] - rank[a.severity] || a.createdAt - b.createdAt
55
+ );
56
+ }
57
+ /** Rewrite the file marking a signal resolved (compacts the log). */
58
+ resolve(id) {
59
+ const signals = this.all();
60
+ let changed = false;
61
+ for (const s of signals) {
62
+ if (s.id === id && !s.resolvedAt) {
63
+ s.resolvedAt = Date.now();
64
+ changed = true;
65
+ }
66
+ }
67
+ if (changed) {
68
+ this.ensureDir();
69
+ writeFileSync(
70
+ this.path,
71
+ signals.map((s) => JSON.stringify(s)).join("\n") + "\n"
72
+ );
73
+ }
74
+ return changed;
75
+ }
76
+ }
77
+ export {
78
+ SignalInbox
79
+ };
@@ -0,0 +1,22 @@
1
+ import { fileURLToPath as __fileURLToPath } from 'url';
2
+ import { dirname as __pathDirname } from 'path';
3
+ const __filename = __fileURLToPath(import.meta.url);
4
+ const __dirname = __pathDirname(__filename);
5
+ const DEFAULT_LIMITS = {
6
+ maxIterations: 10,
7
+ maxIterationsPerDay: 50,
8
+ maxConsecutiveFailures: 3,
9
+ tickIntervalSec: 60,
10
+ requireApproval: false,
11
+ stopWhenComplete: true
12
+ };
13
+ const SEVERITY_RANK = {
14
+ low: 1,
15
+ medium: 2,
16
+ high: 3,
17
+ critical: 4
18
+ };
19
+ export {
20
+ DEFAULT_LIMITS,
21
+ SEVERITY_RANK
22
+ };
@@ -0,0 +1,146 @@
1
+ import { fileURLToPath as __fileURLToPath } from 'url';
2
+ import { dirname as __pathDirname } from 'path';
3
+ const __filename = __fileURLToPath(import.meta.url);
4
+ const __dirname = __pathDirname(__filename);
5
+ import { existsSync, readFileSync, writeFileSync } from "fs";
6
+ import { createHash } from "crypto";
7
+ import {
8
+ DEFAULT_LIMITS
9
+ } from "./types.js";
10
+ function objectiveId(text) {
11
+ return createHash("sha1").update(text.trim()).digest("hex").slice(0, 10);
12
+ }
13
+ function splitSections(text) {
14
+ const lines = text.split(/\r?\n/);
15
+ const sections = /* @__PURE__ */ new Map();
16
+ const preamble = [];
17
+ let current = null;
18
+ for (const line of lines) {
19
+ const h2 = line.match(/^##\s+(.+?)\s*$/);
20
+ if (h2?.[1]) {
21
+ current = { body: [] };
22
+ sections.set(h2[1].toLowerCase(), current);
23
+ continue;
24
+ }
25
+ if (/^#\s+/.test(line)) continue;
26
+ if (current) {
27
+ current.body.push(line);
28
+ } else {
29
+ preamble.push(line);
30
+ }
31
+ }
32
+ return { preamble, sections };
33
+ }
34
+ function bulletLines(body) {
35
+ return body.map((l) => l.match(/^\s*[-*]\s+(.*\S)\s*$/)?.[1]?.trim()).filter((s) => !!s).filter((s) => !/^\[[ xX]\]/.test(s));
36
+ }
37
+ function parseObjectives(body) {
38
+ const objectives = [];
39
+ for (const line of body) {
40
+ const m = line.match(/^\s*[-*]\s+\[([ xX])\]\s+(.*\S)\s*$/);
41
+ if (!m?.[2]) continue;
42
+ const text = m[2].trim();
43
+ objectives.push({
44
+ id: objectiveId(text),
45
+ text,
46
+ done: (m[1] ?? "").toLowerCase() === "x"
47
+ });
48
+ }
49
+ return objectives;
50
+ }
51
+ function parseLimits(body) {
52
+ const limits = { ...DEFAULT_LIMITS };
53
+ for (const line of body) {
54
+ const m = line.match(/^\s*([a-zA-Z]+)\s*:\s*(.+?)\s*$/);
55
+ if (!m?.[1] || m[2] === void 0) continue;
56
+ const key = m[1];
57
+ const raw = m[2];
58
+ if (!(key in limits)) continue;
59
+ if (key === "requireApproval" || key === "stopWhenComplete") {
60
+ limits[key] = /^(true|yes|1)$/i.test(raw);
61
+ } else {
62
+ const n = parseInt(raw, 10);
63
+ if (Number.isFinite(n)) limits[key] = n;
64
+ }
65
+ }
66
+ return limits;
67
+ }
68
+ function parseVision(text) {
69
+ const { preamble, sections } = splitSections(text);
70
+ const body = (name) => sections.get(name)?.body ?? [];
71
+ const mission = preamble.map((l) => l.trim()).filter(Boolean).join(" ").trim();
72
+ return {
73
+ mission,
74
+ guardrails: bulletLines(body("guardrails")),
75
+ scope: bulletLines(body("scope")),
76
+ objectives: parseObjectives(body("objectives")),
77
+ limits: sections.has("limits") ? parseLimits(body("limits")) : { ...DEFAULT_LIMITS }
78
+ };
79
+ }
80
+ function loadVision(path) {
81
+ if (!existsSync(path)) return null;
82
+ return parseVision(readFileSync(path, "utf-8"));
83
+ }
84
+ function setObjectiveDone(path, objId, done) {
85
+ if (!existsSync(path)) return false;
86
+ const lines = readFileSync(path, "utf-8").split(/\r?\n/);
87
+ let changed = false;
88
+ for (let i = 0; i < lines.length; i++) {
89
+ const line = lines[i];
90
+ if (line === void 0) continue;
91
+ const m = line.match(/^(\s*[-*]\s+)\[([ xX])\]\s+(.*\S)\s*$/);
92
+ if (!m?.[3]) continue;
93
+ if (objectiveId(m[3].trim()) === objId) {
94
+ lines[i] = `${m[1] ?? ""}[${done ? "x" : " "}] ${m[3].trim()}`;
95
+ changed = true;
96
+ break;
97
+ }
98
+ }
99
+ if (changed) writeFileSync(path, lines.join("\n"));
100
+ return changed;
101
+ }
102
+ const VISION_TEMPLATE = `# Vision
103
+
104
+ State the single north-star mission this autonomous loop serves. Keep it to a
105
+ sentence or two \u2014 concrete enough to judge whether a piece of work belongs.
106
+
107
+ ## Guardrails
108
+
109
+ - Stay within the scope below; do not touch anything outside it.
110
+ - Never modify secrets, production credentials, or deploy/publish.
111
+ - Open a PR for review; never merge to the default branch autonomously.
112
+ - If an objective is ambiguous or risky, stop and ask a human.
113
+
114
+ ## Scope
115
+
116
+ - src/**
117
+ - docs/**
118
+
119
+ ## Objectives
120
+
121
+ - [ ] First concrete objective the loop should pursue
122
+ - [ ] Second objective
123
+ - [ ] Third objective
124
+
125
+ ## Limits
126
+
127
+ maxIterations: 10
128
+ maxIterationsPerDay: 50
129
+ maxConsecutiveFailures: 3
130
+ tickIntervalSec: 60
131
+ requireApproval: false
132
+ stopWhenComplete: true
133
+ `;
134
+ function scaffoldVision(path, force = false) {
135
+ if (existsSync(path) && !force) return false;
136
+ writeFileSync(path, VISION_TEMPLATE);
137
+ return true;
138
+ }
139
+ export {
140
+ VISION_TEMPLATE,
141
+ loadVision,
142
+ objectiveId,
143
+ parseVision,
144
+ scaffoldVision,
145
+ setObjectiveDone
146
+ };