@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,195 @@
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 XTERM_VERSION = "5.3.0";
6
+ const FIT_VERSION = "0.10.0";
7
+ const SOCKET_IO_VERSION = "4.7.5";
8
+ function renderPortalPage(opts) {
9
+ return `<!doctype html>
10
+ <html lang="en">
11
+ <head>
12
+ <meta charset="utf-8" />
13
+ <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
14
+ <meta name="theme-color" content="#0b0f17" />
15
+ <title>StackMemory Portal \u2014 ${escapeHtml(opts.session)}</title>
16
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@xterm/xterm@${XTERM_VERSION}/css/xterm.min.css" />
17
+ <style>
18
+ :root {
19
+ --bg: #0b0f17;
20
+ --panel: #11161f;
21
+ --border: #1e2733;
22
+ --accent: #7c5cff;
23
+ --accent-dim: #4a3a99;
24
+ --ok: #2ecc71;
25
+ --warn: #f1c40f;
26
+ --err: #e74c3c;
27
+ --text: #c7d0dc;
28
+ --muted: #6b7686;
29
+ }
30
+ * { box-sizing: border-box; }
31
+ html, body {
32
+ margin: 0; height: 100%;
33
+ background: var(--bg); color: var(--text);
34
+ font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
35
+ overflow: hidden;
36
+ }
37
+ #app { display: flex; flex-direction: column; height: 100dvh; }
38
+ header {
39
+ display: flex; align-items: center; gap: 12px;
40
+ padding: 10px 14px; background: var(--panel);
41
+ border-bottom: 1px solid var(--border);
42
+ -webkit-app-region: drag; user-select: none;
43
+ }
44
+ .brand { display: flex; align-items: center; gap: 9px; font-weight: 700; letter-spacing: .3px; }
45
+ .logo {
46
+ width: 22px; height: 22px; border-radius: 6px;
47
+ background: linear-gradient(135deg, var(--accent), #34d3ff);
48
+ box-shadow: 0 0 18px rgba(124, 92, 255, .55);
49
+ }
50
+ .session { color: var(--muted); font-size: 12px; }
51
+ .session b { color: var(--text); font-weight: 600; }
52
+ .spacer { flex: 1; }
53
+ .dot { width: 9px; height: 9px; border-radius: 50%; background: var(--muted); box-shadow: 0 0 0 0 rgba(0,0,0,0); transition: background .2s; }
54
+ .dot.ok { background: var(--ok); box-shadow: 0 0 10px var(--ok); }
55
+ .dot.err { background: var(--err); box-shadow: 0 0 10px var(--err); }
56
+ .status { font-size: 12px; color: var(--muted); min-width: 92px; text-align: right; }
57
+ button.tool {
58
+ background: transparent; color: var(--muted); border: 1px solid var(--border);
59
+ border-radius: 7px; padding: 5px 10px; font: inherit; font-size: 12px; cursor: pointer;
60
+ transition: all .15s;
61
+ }
62
+ button.tool:hover { color: var(--text); border-color: var(--accent-dim); }
63
+ #term-wrap { flex: 1; padding: 8px 10px 10px; min-height: 0; }
64
+ #terminal { height: 100%; }
65
+ #overlay {
66
+ position: fixed; inset: 0; display: none; place-items: center;
67
+ background: rgba(5, 8, 13, .85); backdrop-filter: blur(3px); z-index: 10;
68
+ }
69
+ #overlay.show { display: grid; }
70
+ .card {
71
+ background: var(--panel); border: 1px solid var(--border); border-radius: 14px;
72
+ padding: 26px 30px; max-width: 380px; text-align: center;
73
+ box-shadow: 0 24px 60px rgba(0,0,0,.5);
74
+ }
75
+ .card h2 { margin: 0 0 8px; font-size: 17px; }
76
+ .card p { margin: 0; color: var(--muted); font-size: 13px; line-height: 1.5; }
77
+ .reconnect { margin-top: 16px; }
78
+ .reconnect button {
79
+ background: var(--accent); color: #fff; border: 0; border-radius: 8px;
80
+ padding: 8px 18px; font: inherit; font-weight: 600; cursor: pointer;
81
+ }
82
+ </style>
83
+ </head>
84
+ <body>
85
+ <div id="app">
86
+ <header>
87
+ <span class="brand"><span class="logo"></span>StackMemory Portal</span>
88
+ <span class="session">session <b>${escapeHtml(opts.session)}</b></span>
89
+ <span class="spacer"></span>
90
+ <button class="tool" id="btn-clear" title="Clear the local view">clear</button>
91
+ <button class="tool" id="btn-fit" title="Re-fit the terminal">fit</button>
92
+ <span class="dot" id="dot"></span>
93
+ <span class="status" id="status">connecting\u2026</span>
94
+ </header>
95
+ <div id="term-wrap"><div id="terminal"></div></div>
96
+ </div>
97
+
98
+ <div id="overlay">
99
+ <div class="card">
100
+ <h2 id="ov-title">Disconnected</h2>
101
+ <p id="ov-msg">The connection to your agent was lost.</p>
102
+ <div class="reconnect"><button id="btn-reconnect">Reconnect</button></div>
103
+ </div>
104
+ </div>
105
+
106
+ <script src="https://cdn.jsdelivr.net/npm/@xterm/xterm@${XTERM_VERSION}/lib/xterm.min.js"></script>
107
+ <script src="https://cdn.jsdelivr.net/npm/@xterm/addon-fit@${FIT_VERSION}/lib/addon-fit.min.js"></script>
108
+ <script src="https://cdn.jsdelivr.net/npm/socket.io-client@${SOCKET_IO_VERSION}/dist/socket.io.min.js"></script>
109
+ <script>
110
+ (function () {
111
+ var params = new URLSearchParams(location.search);
112
+ var token = params.get('token') || '';
113
+
114
+ var term = new Terminal({
115
+ cursorBlink: true,
116
+ fontSize: 14,
117
+ fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Consolas, monospace',
118
+ scrollback: 10000,
119
+ theme: {
120
+ background: '#0b0f17', foreground: '#c7d0dc', cursor: '#7c5cff',
121
+ selectionBackground: '#2a3550', black: '#0b0f17', brightBlack: '#3a4658'
122
+ }
123
+ });
124
+ var fit = new FitAddon.FitAddon();
125
+ term.loadAddon(fit);
126
+ term.open(document.getElementById('terminal'));
127
+ fit.fit();
128
+
129
+ var dot = document.getElementById('dot');
130
+ var status = document.getElementById('status');
131
+ var overlay = document.getElementById('overlay');
132
+ var ovTitle = document.getElementById('ov-title');
133
+ var ovMsg = document.getElementById('ov-msg');
134
+
135
+ function setStatus(text, state) {
136
+ status.textContent = text;
137
+ dot.className = 'dot' + (state ? ' ' + state : '');
138
+ }
139
+ function showOverlay(title, msg) {
140
+ ovTitle.textContent = title; ovMsg.textContent = msg; overlay.classList.add('show');
141
+ }
142
+ function hideOverlay() { overlay.classList.remove('show'); }
143
+
144
+ var socket = io({ auth: { token: token }, query: { token: token }, reconnectionAttempts: 8 });
145
+
146
+ socket.on('connect', function () {
147
+ setStatus('connected', 'ok'); hideOverlay(); term.focus(); sendResize();
148
+ });
149
+ socket.on('output', function (data) { term.write(data); });
150
+ socket.on('portal:error', function (msg) {
151
+ setStatus('error', 'err'); showOverlay('Cannot start session', String(msg));
152
+ });
153
+ socket.on('disconnect', function () {
154
+ setStatus('disconnected', 'err');
155
+ showOverlay('Disconnected', 'The portal connection dropped. Your tmux session keeps running in the background.');
156
+ });
157
+ socket.on('connect_error', function (err) {
158
+ setStatus('auth failed', 'err');
159
+ showOverlay('Connection refused', (err && err.message) || 'Check your access token and try again.');
160
+ });
161
+
162
+ term.onData(function (data) { socket.emit('input', data); });
163
+
164
+ function sendResize() {
165
+ socket.emit('resize', { cols: term.cols, rows: term.rows });
166
+ }
167
+ function doFit() { try { fit.fit(); sendResize(); } catch (e) {} }
168
+
169
+ var rt;
170
+ window.addEventListener('resize', function () { clearTimeout(rt); rt = setTimeout(doFit, 120); });
171
+ document.getElementById('btn-fit').addEventListener('click', doFit);
172
+ document.getElementById('btn-clear').addEventListener('click', function () { term.clear(); term.focus(); });
173
+ document.getElementById('btn-reconnect').addEventListener('click', function () { hideOverlay(); socket.connect(); });
174
+
175
+ setStatus('connecting\u2026');
176
+ })();
177
+ </script>
178
+ </body>
179
+ </html>`;
180
+ }
181
+ function escapeHtml(s) {
182
+ return s.replace(
183
+ /[&<>"']/g,
184
+ (c) => ({
185
+ "&": "&amp;",
186
+ "<": "&lt;",
187
+ ">": "&gt;",
188
+ '"': "&quot;",
189
+ "'": "&#39;"
190
+ })[c]
191
+ );
192
+ }
193
+ export {
194
+ renderPortalPage
195
+ };
@@ -30,7 +30,9 @@ class PtyWrapper {
30
30
  claudeBin: config.claudeBin || this.findClaude(),
31
31
  claudeArgs: config.claudeArgs || [],
32
32
  stateFile: config.stateFile || getSweepPath("sweep-state.json"),
33
- initialInput: config.initialInput || ""
33
+ initialInput: config.initialInput || "",
34
+ onExit: config.onExit || (() => void 0),
35
+ onSignal: config.onSignal || (() => void 0)
34
36
  };
35
37
  this.stateWatcher = new SweepStateWatcher(this.config.stateFile);
36
38
  this.statusBar = new StatusBar();
@@ -115,8 +117,9 @@ class PtyWrapper {
115
117
  this.ptyProcess?.resize(newCols, newRows - 1);
116
118
  this.statusBar.resize(newRows, newCols);
117
119
  });
118
- this.ptyProcess.onExit(({ exitCode }) => {
120
+ this.ptyProcess.onExit(async ({ exitCode }) => {
119
121
  this.cleanup();
122
+ await this.config.onExit(exitCode);
120
123
  if (process.env["LINEAR_API_KEY"]) {
121
124
  try {
122
125
  execSync("stackmemory linear sync", {
@@ -128,12 +131,17 @@ class PtyWrapper {
128
131
  }
129
132
  process.exit(exitCode);
130
133
  });
131
- const onSignal = () => {
134
+ const onSignal = async (signal) => {
132
135
  this.cleanup();
136
+ await this.config.onSignal(signal);
133
137
  process.exit(0);
134
138
  };
135
- process.on("SIGINT", onSignal);
136
- process.on("SIGTERM", onSignal);
139
+ process.on("SIGINT", () => {
140
+ void onSignal("SIGINT");
141
+ });
142
+ process.on("SIGTERM", () => {
143
+ void onSignal("SIGTERM");
144
+ });
137
145
  }
138
146
  acceptPrediction() {
139
147
  if (!this.currentPrediction || !this.ptyProcess) return;
@@ -3,6 +3,7 @@ import { dirname as __pathDirname } from 'path';
3
3
  const __filename = __fileURLToPath(import.meta.url);
4
4
  const __dirname = __pathDirname(__filename);
5
5
  import { logger } from "../../core/monitoring/logger.js";
6
+ import { estimateTokens } from "../../core/cache/token-estimator.js";
6
7
  class TaskAwareContextManager {
7
8
  db;
8
9
  frameManager;
@@ -293,7 +294,7 @@ class TaskAwareContextManager {
293
294
  const line = `- [${task.status.toUpperCase()}] ${task.name} (${task.priority})
294
295
  `;
295
296
  context += line;
296
- totalTokens += line.length / 4;
297
+ totalTokens += estimateTokens(line);
297
298
  relevanceScores[task.task_id] = 1;
298
299
  });
299
300
  context += "\n";
@@ -2,7 +2,6 @@ import { fileURLToPath as __fileURLToPath } from 'url';
2
2
  import { dirname as __pathDirname } from 'path';
3
3
  const __filename = __fileURLToPath(import.meta.url);
4
4
  const __dirname = __pathDirname(__filename);
5
- import { SwarmRegistry } from "../../integrations/ralph/monitoring/swarm-registry.js";
6
5
  import { execSync } from "child_process";
7
6
  class SimpleSwarmMonitor {
8
7
  refreshInterval = null;
@@ -10,7 +9,6 @@ class SimpleSwarmMonitor {
10
9
  * Start simple text-based monitoring
11
10
  */
12
11
  start() {
13
- console.log("\u{1F9BE} Ralph Swarm Monitor (Text Mode)");
14
12
  console.log("=====================================");
15
13
  console.log("");
16
14
  console.log("Press Ctrl+C to quit");
@@ -42,7 +40,6 @@ class SimpleSwarmMonitor {
42
40
  \u23F0 ${timestamp} - Swarm Status Update`);
43
41
  console.log("\u2500".repeat(50));
44
42
  try {
45
- const registry = SwarmRegistry.getInstance();
46
43
  const activeSwarms = registry.listActiveSwarms();
47
44
  const stats = registry.getStatistics();
48
45
  console.log(
@@ -59,26 +56,6 @@ class SimpleSwarmMonitor {
59
56
  } else {
60
57
  console.log("\u274C No active swarms in registry");
61
58
  }
62
- try {
63
- const ralphProcesses = execSync(
64
- 'ps aux | grep "ralph" | grep -v grep',
65
- { encoding: "utf8" }
66
- );
67
- if (ralphProcesses.trim()) {
68
- console.log("\n\u{1F50D} External Ralph Processes:");
69
- const processLines = ralphProcesses.split("\n").filter((line) => line.trim());
70
- processLines.slice(0, 3).forEach((line) => {
71
- const parts = line.split(/\s+/);
72
- console.log(
73
- ` PID ${parts[1]}: ${parts.slice(10).join(" ").slice(0, 50)}...`
74
- );
75
- });
76
- if (processLines.length > 3) {
77
- console.log(` ... and ${processLines.length - 3} more processes`);
78
- }
79
- }
80
- } catch {
81
- }
82
59
  try {
83
60
  const recentCommits = execSync(
84
61
  'git log --oneline --since="1 hour ago" --pretty=format:"%h %an %s" | head -3',
@@ -4,8 +4,6 @@ const __filename = __fileURLToPath(import.meta.url);
4
4
  const __dirname = __pathDirname(__filename);
5
5
  import blessed from "blessed";
6
6
  import { logger } from "../../core/monitoring/logger.js";
7
- import { SwarmDashboard } from "../../integrations/ralph/monitoring/swarm-dashboard.js";
8
- import { SwarmRegistry } from "../../integrations/ralph/monitoring/swarm-registry.js";
9
7
  import { execSync } from "child_process";
10
8
  class SwarmTUI {
11
9
  screen;
@@ -14,8 +12,6 @@ class SwarmTUI {
14
12
  agentsTable;
15
13
  metricsBox;
16
14
  logBox;
17
- swarmCoordinator = null;
18
- swarmDashboard = null;
19
15
  refreshInterval = null;
20
16
  commitMetrics = /* @__PURE__ */ new Map();
21
17
  constructor() {
@@ -24,7 +20,6 @@ class SwarmTUI {
24
20
  this.screen = blessed.screen({
25
21
  smartCSR: !isGhostty,
26
22
  // Disable smart CSR for ghostty
27
- title: "Ralph Swarm Monitor",
28
23
  terminal: isGhostty ? "xterm-256color" : void 0,
29
24
  fullUnicode: !isBasicTerm,
30
25
  dockBorders: false,
@@ -39,9 +34,7 @@ class SwarmTUI {
39
34
  console.log(
40
35
  "\u26A0\uFE0F TUI display error detected. Try setting TERM=xterm-256color"
41
36
  );
42
- console.log(
43
- " Alternative: Use stackmemory ralph status for text-based monitoring"
44
- );
37
+ console.log();
45
38
  });
46
39
  this.createUI();
47
40
  this.setupKeyHandlers();
@@ -66,7 +59,6 @@ class SwarmTUI {
66
59
  left: 0,
67
60
  width: "100%",
68
61
  height: 3,
69
- content: "\u{1F9BE} Ralph Swarm Monitor - Real-time Swarm Operations",
70
62
  style: safeColors ? {
71
63
  fg: "white",
72
64
  bold: false
@@ -229,10 +221,9 @@ class SwarmTUI {
229
221
  /**
230
222
  * Initialize swarm monitoring
231
223
  */
232
- async initialize(swarmCoordinator, swarmId) {
224
+ async initialize(swarmId) {
233
225
  try {
234
226
  if (swarmId) {
235
- const registry = SwarmRegistry.getInstance();
236
227
  const swarm = registry.getSwarm(swarmId);
237
228
  if (swarm) {
238
229
  this.swarmCoordinator = swarm.coordinator;
@@ -243,7 +234,6 @@ class SwarmTUI {
243
234
  } else if (swarmCoordinator) {
244
235
  this.swarmCoordinator = swarmCoordinator;
245
236
  } else {
246
- const registry = SwarmRegistry.getInstance();
247
237
  const activeSwarms = registry.listActiveSwarms();
248
238
  if (activeSwarms.length > 0) {
249
239
  this.swarmCoordinator = activeSwarms[0].coordinator;
@@ -251,7 +241,6 @@ class SwarmTUI {
251
241
  }
252
242
  }
253
243
  if (this.swarmCoordinator) {
254
- this.swarmDashboard = new SwarmDashboard(this.swarmCoordinator);
255
244
  this.swarmDashboard.startMonitoring(2e3);
256
245
  this.swarmDashboard.on("metricsUpdated", (metrics) => {
257
246
  this.updateUI(metrics);
@@ -271,7 +260,6 @@ class SwarmTUI {
271
260
  */
272
261
  start() {
273
262
  this.screen.render();
274
- this.logBox.log("Ralph Swarm Monitor started");
275
263
  this.logBox.log("Monitoring for active swarms...");
276
264
  }
277
265
  /**
@@ -450,7 +438,6 @@ Success Rate: ${status.performance.efficiency > 0 ? (status.performance.efficien
450
438
  */
451
439
  async detectActiveSwarms() {
452
440
  try {
453
- const registry = SwarmRegistry.getInstance();
454
441
  const activeSwarms = registry.listActiveSwarms();
455
442
  const stats = registry.getStatistics();
456
443
  if (activeSwarms.length > 0) {
@@ -469,22 +456,9 @@ Success Rate: ${status.performance.efficiency > 0 ? (status.performance.efficien
469
456
  `Found ${activeSwarms.length} active swarms in registry`
470
457
  );
471
458
  } else {
472
- const ralphProcesses = execSync(
473
- 'ps aux | grep "ralph" | grep -v grep',
474
- { encoding: "utf8" }
475
- );
476
- if (ralphProcesses.trim()) {
477
- this.logBox.log("Detected Ralph processes running");
478
- this.statusBox.setContent(
479
- "External Ralph processes detected\n(Use swarm coordinator for full monitoring)"
480
- );
481
- } else {
482
- this.statusBox.setContent(`No active swarms detected
459
+ this.statusBox.setContent(`No active swarms detected
483
460
  Total swarms: ${stats.totalSwarms}
484
- Completed: ${stats.completedSwarms}
485
-
486
- Run: stackmemory ralph swarm <task>`);
487
- }
461
+ Completed: ${stats.completedSwarms}`);
488
462
  }
489
463
  } catch {
490
464
  }
@@ -518,9 +492,7 @@ Run: stackmemory ralph swarm <task>`);
518
492
  */
519
493
  startSwarmInteractive() {
520
494
  this.logBox.log("\u{1F680} Start Swarm Interactive Mode:");
521
- this.logBox.log(
522
- 'Example: stackmemory ralph swarm "Implement feature" --agents developer,tester'
523
- );
495
+ this.logBox.log();
524
496
  this.logBox.log(
525
497
  'Tip: Run the command in another terminal, then press "d" to detect it'
526
498
  );
@@ -536,14 +508,12 @@ Run: stackmemory ralph swarm <task>`);
536
508
  );
537
509
  } else {
538
510
  this.logBox.log("\u274C No active swarm coordinator to stop");
539
- this.logBox.log("External Ralph processes must be stopped manually");
540
511
  }
541
512
  }
542
513
  /**
543
514
  * Show help dialog
544
515
  */
545
516
  showHelp() {
546
- this.logBox.log("\u{1F9BE} Ralph Swarm Monitor - Help");
547
517
  this.logBox.log("");
548
518
  this.logBox.log("Keyboard Shortcuts:");
549
519
  this.logBox.log(" q, Esc, Ctrl+C - Quit TUI");
@@ -555,17 +525,11 @@ Run: stackmemory ralph swarm <task>`);
555
525
  this.logBox.log(" d - Detect and list available swarms");
556
526
  this.logBox.log("");
557
527
  this.logBox.log("Usage:");
558
- this.logBox.log(
559
- " stackmemory ralph tui # Auto-detect swarms"
560
- );
561
- this.logBox.log(
562
- " stackmemory ralph tui --swarm-id <id> # Monitor specific swarm"
563
- );
528
+ this.logBox.log();
529
+ this.logBox.log();
564
530
  this.logBox.log("");
565
531
  this.logBox.log("Starting Swarms:");
566
- this.logBox.log(
567
- ' stackmemory ralph swarm "Task description" --agents developer,tester'
568
- );
532
+ this.logBox.log();
569
533
  this.logBox.log("");
570
534
  }
571
535
  /**
@@ -581,7 +545,6 @@ Run: stackmemory ralph swarm <task>`);
581
545
  async showDetectedSwarms() {
582
546
  this.logBox.log("\u{1F50D} Detecting active swarms...");
583
547
  try {
584
- const registry = SwarmRegistry.getInstance();
585
548
  const activeSwarms = registry.listActiveSwarms();
586
549
  const stats = registry.getStatistics();
587
550
  this.logBox.log("");
@@ -601,27 +564,6 @@ Run: stackmemory ralph swarm <task>`);
601
564
  } else {
602
565
  this.logBox.log("");
603
566
  this.logBox.log("\u274C No active swarms in registry");
604
- try {
605
- const ralphProcesses = execSync(
606
- 'ps aux | grep "ralph" | grep -v grep',
607
- { encoding: "utf8" }
608
- );
609
- if (ralphProcesses.trim()) {
610
- this.logBox.log("\u{1F50D} External Ralph processes detected:");
611
- ralphProcesses.split("\n").filter((line) => line.trim()).forEach((line) => {
612
- const parts = line.split(/\s+/);
613
- this.logBox.log(
614
- ` PID ${parts[1]}: ${parts.slice(10).join(" ").slice(0, 60)}`
615
- );
616
- });
617
- }
618
- } catch {
619
- this.logBox.log("\u{1F50D} No external Ralph processes found");
620
- }
621
- this.logBox.log("");
622
- this.logBox.log(
623
- '\u{1F4A1} Start a swarm: stackmemory ralph swarm "Task" --agents developer'
624
- );
625
567
  }
626
568
  } catch (error) {
627
569
  this.logBox.log(`\u274C Detection failed: ${error.message}`);
@@ -0,0 +1,12 @@
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
+ "use client";
6
+ import { useSocketContext } from "@/components/socket-provider";
7
+ function useSocket() {
8
+ return useSocketContext();
9
+ }
10
+ export {
11
+ useSocket
12
+ };
@@ -2,7 +2,11 @@ import { fileURLToPath as __fileURLToPath } from 'url';
2
2
  import { dirname as __pathDirname } from 'path';
3
3
  const __filename = __fileURLToPath(import.meta.url);
4
4
  const __dirname = __pathDirname(__filename);
5
- export * from "./types.js";
6
- export * from "./conflict-detector.js";
7
- export * from "./stack-diff.js";
8
- export * from "./resolution-engine.js";
5
+ import { clsx } from "clsx";
6
+ import { twMerge } from "tailwind-merge";
7
+ function cn(...inputs) {
8
+ return twMerge(clsx(inputs));
9
+ }
10
+ export {
11
+ cn
12
+ };
@@ -0,0 +1,4 @@
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);
@@ -0,0 +1,12 @@
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 { create } from "zustand";
6
+ const useSessionStore = create((set) => ({
7
+ sessions: [],
8
+ setSessions: (sessions) => set({ sessions })
9
+ }));
10
+ export {
11
+ useSessionStore
12
+ };
@@ -0,0 +1,76 @@
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
+ function getTableReference() {
6
+ const fullTable = process.env["GCP_BILLING_BIGQUERY_TABLE"];
7
+ if (fullTable) return fullTable;
8
+ const project = process.env["GCP_BILLING_PROJECT_ID"];
9
+ const dataset = process.env["GCP_BILLING_DATASET"];
10
+ const table = process.env["GCP_BILLING_TABLE"];
11
+ if (project && dataset && table) {
12
+ return `${project}.${dataset}.${table}`;
13
+ }
14
+ return void 0;
15
+ }
16
+ async function getBigQuery() {
17
+ const { BigQuery } = await import("@google-cloud/bigquery");
18
+ return new BigQuery();
19
+ }
20
+ async function getGcpSpend(days = 30) {
21
+ const table = getTableReference();
22
+ if (!table) return void 0;
23
+ try {
24
+ const bq = await getBigQuery();
25
+ const [totalRows] = await bq.query({
26
+ query: `
27
+ SELECT
28
+ SUM(cost) + SUM(IFNULL((SELECT SUM(c.amount) FROM UNNEST(credits) c), 0)) AS total_cost,
29
+ currency
30
+ FROM \`${table}\`
31
+ WHERE usage_start_time >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL @days DAY)
32
+ LIMIT 1
33
+ `,
34
+ params: { days },
35
+ location: "US"
36
+ });
37
+ const [dailyRows] = await bq.query({
38
+ query: `
39
+ SELECT
40
+ DATE(usage_start_time) AS date,
41
+ SUM(cost) + SUM(IFNULL((SELECT SUM(c.amount) FROM UNNEST(credits) c), 0)) AS cost_usd
42
+ FROM \`${table}\`
43
+ WHERE usage_start_time >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL @days DAY)
44
+ GROUP BY date
45
+ ORDER BY date ASC
46
+ `,
47
+ params: { days },
48
+ location: "US"
49
+ });
50
+ const total = Number(totalRows?.[0]?.total_cost ?? 0);
51
+ const currency = String(totalRows?.[0]?.currency ?? "USD");
52
+ const daily = (dailyRows || []).map((r) => ({
53
+ date: String(r.date ?? ""),
54
+ costUsd: Number(r.cost_usd ?? 0)
55
+ })).filter((d) => d.date);
56
+ return {
57
+ totalCostUsd: total,
58
+ daily,
59
+ currency,
60
+ table
61
+ };
62
+ } catch (error) {
63
+ console.warn("Failed to fetch GCP spend from BigQuery:", error);
64
+ return void 0;
65
+ }
66
+ }
67
+ function getGcpSpendEnvFallback() {
68
+ const raw = process.env["GCP_AI_SPEND_USD"];
69
+ if (!raw) return void 0;
70
+ const value = Number.parseFloat(raw);
71
+ return Number.isFinite(value) && value >= 0 ? value : void 0;
72
+ }
73
+ export {
74
+ getGcpSpend,
75
+ getGcpSpendEnvFallback
76
+ };
@@ -12,6 +12,7 @@ import { FrameManager } from "../../../core/context/index.js";
12
12
  import Database from "better-sqlite3";
13
13
  import { existsSync } from "fs";
14
14
  import { join } from "path";
15
+ import { getSpendSummary } from "./spend-calculator.js";
15
16
  function _getEnv(key, defaultValue) {
16
17
  const value = process.env[key];
17
18
  if (value === void 0) {
@@ -149,6 +150,15 @@ app.get("/api/analytics", (req, res) => {
149
150
  res.status(500).json({ error: "Failed to fetch analytics" });
150
151
  }
151
152
  });
153
+ app.get("/api/evals", async (req, res) => {
154
+ try {
155
+ const spend = await getSpendSummary();
156
+ res.json(spend);
157
+ } catch (error) {
158
+ console.error("Error fetching evals spend:", error);
159
+ res.status(500).json({ error: "Failed to fetch AI spend estimate" });
160
+ }
161
+ });
152
162
  io.on("connection", (socket) => {
153
163
  console.log("\u{1F464} Client connected:", socket.id);
154
164
  socket.emit("initial-data", {