@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,194 @@
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 { logger } from "../monitoring/logger.js";
6
+ import { TraceEventSchema } from "./types.js";
7
+ class ProvenanceStore {
8
+ db;
9
+ constructor(db) {
10
+ this.db = db;
11
+ this.initializeSchema();
12
+ }
13
+ /**
14
+ * Initialize database schema for trace events
15
+ */
16
+ initializeSchema() {
17
+ this.db.exec(`
18
+ CREATE TABLE IF NOT EXISTS trace_events (
19
+ trace_id TEXT PRIMARY KEY,
20
+ session_id TEXT NOT NULL,
21
+ parent_trace_id TEXT,
22
+ tenant_id TEXT NOT NULL,
23
+ timestamp TEXT NOT NULL,
24
+ actor TEXT NOT NULL,
25
+ operation TEXT NOT NULL,
26
+ inputs TEXT NOT NULL,
27
+ outputs TEXT NOT NULL,
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
+ score REAL,
32
+ feedback TEXT,
33
+ provenance TEXT NOT NULL,
34
+ created_at INTEGER DEFAULT (unixepoch())
35
+ )
36
+ `);
37
+ this.db.exec(`
38
+ CREATE INDEX IF NOT EXISTS idx_trace_events_session_id ON trace_events(session_id);
39
+ CREATE INDEX IF NOT EXISTS idx_trace_events_tenant_id ON trace_events(tenant_id);
40
+ CREATE INDEX IF NOT EXISTS idx_trace_events_operation ON trace_events(operation);
41
+ CREATE INDEX IF NOT EXISTS idx_trace_events_timestamp ON trace_events(timestamp);
42
+ CREATE INDEX IF NOT EXISTS idx_trace_events_parent_trace_id ON trace_events(parent_trace_id);
43
+ `);
44
+ }
45
+ /**
46
+ * Record a trace event
47
+ */
48
+ record(event) {
49
+ const stmt = this.db.prepare(`
50
+ INSERT OR REPLACE INTO trace_events (
51
+ trace_id, session_id, parent_trace_id, tenant_id, timestamp,
52
+ actor, operation, inputs, outputs,
53
+ tokens_in, tokens_out, cost_usd, score, feedback, provenance
54
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
55
+ `);
56
+ try {
57
+ stmt.run(
58
+ event.traceId,
59
+ event.sessionId,
60
+ event.parentTraceId ?? null,
61
+ event.tenantId,
62
+ event.timestamp,
63
+ JSON.stringify(event.actor),
64
+ event.operation,
65
+ JSON.stringify(event.inputs),
66
+ JSON.stringify(event.outputs),
67
+ event.tokensIn,
68
+ event.tokensOut,
69
+ event.costUsd,
70
+ event.score ?? null,
71
+ event.feedback ?? null,
72
+ JSON.stringify(event.provenance)
73
+ );
74
+ logger.debug(`Recorded trace event ${event.traceId}`);
75
+ } catch (error) {
76
+ logger.error(
77
+ `Failed to record trace event ${event.traceId}:`,
78
+ error
79
+ );
80
+ throw error;
81
+ }
82
+ }
83
+ /**
84
+ * Get a trace event by traceId
85
+ */
86
+ get(traceId) {
87
+ const row = this.db.prepare("SELECT * FROM trace_events WHERE trace_id = ?").get(traceId);
88
+ if (!row) return void 0;
89
+ return this.rowToEvent(row);
90
+ }
91
+ /**
92
+ * Query trace events with filters
93
+ */
94
+ query(opts = {}) {
95
+ const conditions = [];
96
+ const params = [];
97
+ if (opts.sessionId) {
98
+ conditions.push("session_id = ?");
99
+ params.push(opts.sessionId);
100
+ }
101
+ if (opts.tenantId) {
102
+ conditions.push("tenant_id = ?");
103
+ params.push(opts.tenantId);
104
+ }
105
+ if (opts.operation) {
106
+ conditions.push("operation = ?");
107
+ params.push(opts.operation);
108
+ }
109
+ if (opts.since) {
110
+ conditions.push("timestamp >= ?");
111
+ params.push(opts.since);
112
+ }
113
+ const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
114
+ const limit = opts.limit ?? 100;
115
+ const rows = this.db.prepare(
116
+ `SELECT * FROM trace_events ${where} ORDER BY timestamp DESC LIMIT ?`
117
+ ).all(...params, limit);
118
+ return rows.map((row) => this.rowToEvent(row));
119
+ }
120
+ /**
121
+ * Mark a trace event as superseded by another
122
+ */
123
+ supersede(traceId, supersededBy) {
124
+ const row = this.db.prepare("SELECT provenance FROM trace_events WHERE trace_id = ?").get(traceId);
125
+ if (!row) return;
126
+ const provenance = JSON.parse(row.provenance);
127
+ provenance.supersededBy = supersededBy;
128
+ this.db.prepare("UPDATE trace_events SET provenance = ? WHERE trace_id = ?").run(JSON.stringify(provenance), traceId);
129
+ }
130
+ /**
131
+ * Follow parentTraceId chain to build lineage
132
+ */
133
+ getLineage(traceId) {
134
+ const lineage = [];
135
+ let currentId = traceId;
136
+ while (currentId) {
137
+ const event = this.get(currentId);
138
+ if (!event) break;
139
+ lineage.push(event);
140
+ currentId = event.parentTraceId;
141
+ }
142
+ return lineage;
143
+ }
144
+ /**
145
+ * Aggregate stats across trace events
146
+ */
147
+ getStats(tenantId) {
148
+ const where = tenantId ? "WHERE tenant_id = ?" : "";
149
+ const params = tenantId ? [tenantId] : [];
150
+ const row = this.db.prepare(
151
+ `
152
+ SELECT
153
+ COUNT(*) as total_events,
154
+ COALESCE(SUM(tokens_in), 0) as total_tokens_in,
155
+ COALESCE(SUM(tokens_out), 0) as total_tokens_out,
156
+ COALESCE(SUM(cost_usd), 0) as total_cost_usd,
157
+ COALESCE(AVG(json_extract(provenance, '$.confidence')), 0) as avg_confidence
158
+ FROM trace_events ${where}
159
+ `
160
+ ).get(...params);
161
+ return {
162
+ totalEvents: row.total_events,
163
+ totalTokensIn: row.total_tokens_in,
164
+ totalTokensOut: row.total_tokens_out,
165
+ totalCostUsd: row.total_cost_usd,
166
+ avgConfidence: row.avg_confidence
167
+ };
168
+ }
169
+ /**
170
+ * Convert a database row to a TraceEvent
171
+ */
172
+ rowToEvent(row) {
173
+ return TraceEventSchema.parse({
174
+ timestamp: row.timestamp,
175
+ sessionId: row.session_id,
176
+ traceId: row.trace_id,
177
+ parentTraceId: row.parent_trace_id ?? void 0,
178
+ tenantId: row.tenant_id,
179
+ actor: JSON.parse(row.actor),
180
+ operation: row.operation,
181
+ inputs: JSON.parse(row.inputs),
182
+ outputs: JSON.parse(row.outputs),
183
+ tokensIn: row.tokens_in,
184
+ tokensOut: row.tokens_out,
185
+ costUsd: row.cost_usd,
186
+ score: row.score ?? void 0,
187
+ feedback: row.feedback ?? void 0,
188
+ provenance: JSON.parse(row.provenance)
189
+ });
190
+ }
191
+ }
192
+ export {
193
+ ProvenanceStore
194
+ };
@@ -0,0 +1,82 @@
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 { z } from "zod";
6
+ const SourceRefSchema = z.object({
7
+ system: z.string(),
8
+ // e.g., "linear", "github", "slack", "manual"
9
+ externalId: z.string(),
10
+ // ID in source system
11
+ url: z.string().optional(),
12
+ // link to source
13
+ fetchedAt: z.string().datetime(),
14
+ // ISO8601
15
+ hash: z.string().optional()
16
+ // content hash for change detection
17
+ });
18
+ const ProvenanceRecordSchema = z.object({
19
+ sources: z.array(SourceRefSchema),
20
+ derivation: z.array(z.string()),
21
+ // chain of transformations
22
+ confidence: z.number().min(0).max(1),
23
+ supersededBy: z.string().optional(),
24
+ // ID of superseding record
25
+ programVersion: z.string().optional()
26
+ // version that produced this
27
+ });
28
+ const ActorSchema = z.object({
29
+ host: z.string(),
30
+ // e.g., "claude-code", "cursor", "codex"
31
+ agent: z.string(),
32
+ // agent identifier
33
+ user: z.string()
34
+ // user identifier
35
+ });
36
+ const TraceEventSchema = z.object({
37
+ timestamp: z.string().datetime(),
38
+ // ISO8601
39
+ sessionId: z.string(),
40
+ traceId: z.string(),
41
+ parentTraceId: z.string().optional(),
42
+ tenantId: z.string(),
43
+ actor: ActorSchema,
44
+ operation: z.string(),
45
+ // what happened
46
+ inputs: z.unknown(),
47
+ outputs: z.unknown(),
48
+ tokensIn: z.number().int().min(0),
49
+ tokensOut: z.number().int().min(0),
50
+ costUsd: z.number().min(0),
51
+ score: z.number().optional(),
52
+ // numeric eval (ASI-shaped)
53
+ feedback: z.string().optional(),
54
+ // textual feedback for GEPA
55
+ provenance: ProvenanceRecordSchema
56
+ });
57
+ const ConfidenceClassificationSchema = z.enum([
58
+ "accept",
59
+ "review",
60
+ "discard"
61
+ ]);
62
+ const ConfidenceScoreSchema = z.object({
63
+ confidence: z.number().min(0).max(1),
64
+ signals: z.record(z.string(), z.unknown()),
65
+ classification: ConfidenceClassificationSchema
66
+ });
67
+ const ConfidenceConfigSchema = z.object({
68
+ thresholds: z.object({
69
+ accept: z.number().min(0).max(1),
70
+ review: z.number().min(0).max(1)
71
+ }),
72
+ weights: z.record(z.string(), z.number())
73
+ });
74
+ export {
75
+ ActorSchema,
76
+ ConfidenceClassificationSchema,
77
+ ConfidenceConfigSchema,
78
+ ConfidenceScoreSchema,
79
+ ProvenanceRecordSchema,
80
+ SourceRefSchema,
81
+ TraceEventSchema
82
+ };
@@ -8,6 +8,7 @@ import {
8
8
  DEFAULT_RETRIEVAL_CONFIG
9
9
  } from "./types.js";
10
10
  import { logger } from "../monitoring/logger.js";
11
+ import { estimateTokens } from "../cache/token-estimator.js";
11
12
  import { LazyContextLoader } from "../performance/lazy-context-loader.js";
12
13
  import { ContextCache } from "../performance/context-cache.js";
13
14
  import { createLLMProvider } from "./llm-provider.js";
@@ -113,11 +114,11 @@ class HeuristicAnalyzer {
113
114
  let tokens = 50;
114
115
  tokens += frame.eventCount * 30;
115
116
  tokens += frame.anchorCount * 40;
116
- if (frame.digestPreview) tokens += frame.digestPreview.length / 4;
117
+ if (frame.digestPreview) tokens += estimateTokens(frame.digestPreview);
117
118
  return Math.floor(tokens);
118
119
  }
119
120
  estimateSummaryTokens(summary) {
120
- return Math.floor(JSON.stringify(summary).length / 4);
121
+ return estimateTokens(JSON.stringify(summary));
121
122
  }
122
123
  assessQueryComplexity(query, parsedQuery) {
123
124
  const wordCount = query.split(/\s+/).length;
@@ -428,8 +429,8 @@ Respond with only the JSON object, no other text.`;
428
429
  })),
429
430
  metadata: {
430
431
  analysisTimeMs: 0,
431
- summaryTokens: Math.floor(
432
- JSON.stringify(request.compressedSummary).length / 4
432
+ summaryTokens: estimateTokens(
433
+ JSON.stringify(request.compressedSummary)
433
434
  ),
434
435
  queryComplexity: this.assessQueryComplexity(request.currentQuery),
435
436
  matchedPatterns: [],
@@ -6,6 +6,7 @@ import {
6
6
  createPrivacyFilter
7
7
  } from "./privacy-filter.js";
8
8
  import { logger } from "../monitoring/logger.js";
9
+ import { estimateTokens } from "../cache/token-estimator.js";
9
10
  const DEFAULT_UNIFIED_CONTEXT_CONFIG = {
10
11
  totalTokenBudget: 8e3,
11
12
  userKnowledgeBudget: 0.2,
@@ -16,10 +17,6 @@ const DEFAULT_UNIFIED_CONTEXT_CONFIG = {
16
17
  // 10%
17
18
  privacyMode: "standard"
18
19
  };
19
- function estimateTokens(content) {
20
- if (!content) return 0;
21
- return Math.ceil(content.length / 4);
22
- }
23
20
  function truncateToTokenBudget(content, tokenBudget) {
24
21
  if (!content) return "";
25
22
  const estimatedTokens = estimateTokens(content);
@@ -36,12 +33,10 @@ function truncateToTokenBudget(content, tokenBudget) {
36
33
  }
37
34
  class UnifiedContextAssembler {
38
35
  stackMemoryRetrieval;
39
- diffMemHooks;
40
36
  config;
41
37
  privacyFilter;
42
- constructor(stackMemoryRetrieval, diffMemHooks, config = {}) {
38
+ constructor(stackMemoryRetrieval, config = {}) {
43
39
  this.stackMemoryRetrieval = stackMemoryRetrieval;
44
- this.diffMemHooks = diffMemHooks;
45
40
  this.config = { ...DEFAULT_UNIFIED_CONTEXT_CONFIG, ...config };
46
41
  this.privacyFilter = createPrivacyFilter(this.config.privacyMode);
47
42
  const totalAllocation = this.config.userKnowledgeBudget + this.config.taskContextBudget + this.config.systemContextBudget;
@@ -69,11 +64,10 @@ class UnifiedContextAssembler {
69
64
  const systemContextBudget = Math.floor(
70
65
  this.config.totalTokenBudget * this.config.systemContextBudget
71
66
  );
72
- const {
73
- content: userKnowledge,
74
- memories: diffMemMemories,
75
- available: diffMemAvailable
76
- } = await this.gatherUserKnowledge(query, userKnowledgeBudget);
67
+ const { content: userKnowledge } = await this.gatherUserKnowledge(
68
+ query,
69
+ userKnowledgeBudget
70
+ );
77
71
  const userKnowledgeFiltered = this.privacyFilter.filter(userKnowledge);
78
72
  totalPrivacyFiltered += userKnowledgeFiltered.redactedCount;
79
73
  const filteredUserKnowledge = truncateToTokenBudget(
@@ -110,8 +104,6 @@ class UnifiedContextAssembler {
110
104
  budget: this.config.totalTokenBudget
111
105
  };
112
106
  const metadata = {
113
- diffMemAvailable,
114
- diffMemMemories,
115
107
  stackMemoryFrames: frameCount,
116
108
  privacyFiltered: totalPrivacyFiltered
117
109
  };
@@ -131,53 +123,10 @@ class UnifiedContextAssembler {
131
123
  };
132
124
  }
133
125
  /**
134
- * Gather user knowledge from DiffMem
135
- */
136
- async gatherUserKnowledge(query, tokenBudget) {
137
- if (!this.diffMemHooks) {
138
- return { content: "", memories: 0, available: false };
139
- }
140
- try {
141
- const status = await this.diffMemHooks.getStatus();
142
- if (!status.connected) {
143
- logger.debug("DiffMem not connected");
144
- return { content: "", memories: 0, available: false };
145
- }
146
- const memories = await this.diffMemHooks.getRelevantMemories(query, 10);
147
- if (memories.length === 0) {
148
- return { content: "", memories: 0, available: true };
149
- }
150
- const sections = ["## User Knowledge"];
151
- const byCategory = /* @__PURE__ */ new Map();
152
- for (const memory of memories) {
153
- const existing = byCategory.get(memory.category) || [];
154
- existing.push(memory);
155
- byCategory.set(memory.category, existing);
156
- }
157
- for (const [category, categoryMemories] of byCategory) {
158
- sections.push(`
159
- ### ${this.formatCategory(category)}`);
160
- for (const memory of categoryMemories) {
161
- const confidence = memory.confidence >= 0.8 ? "(high confidence)" : memory.confidence >= 0.5 ? "" : "(tentative)";
162
- sections.push(`- ${memory.content} ${confidence}`);
163
- }
164
- }
165
- const content = sections.join("\n");
166
- return {
167
- content: truncateToTokenBudget(content, tokenBudget),
168
- memories: memories.length,
169
- available: true
170
- };
171
- } catch (error) {
172
- logger.warn("Failed to gather user knowledge from DiffMem", { error });
173
- return { content: "", memories: 0, available: false };
174
- }
175
- }
176
- /**
177
- * Format category name for display
126
+ * Gather user knowledge (stub — memory service removed in v1.14)
178
127
  */
179
- formatCategory(category) {
180
- return category.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
128
+ async gatherUserKnowledge(_query, _tokenBudget) {
129
+ return { content: "", memories: 0, available: false };
181
130
  }
182
131
  /**
183
132
  * Gather task context from StackMemory
@@ -258,12 +207,8 @@ class UnifiedContextAssembler {
258
207
  }
259
208
  }
260
209
  }
261
- function createUnifiedContextAssembler(stackMemoryRetrieval, diffMemHooks = null, config = {}) {
262
- return new UnifiedContextAssembler(
263
- stackMemoryRetrieval,
264
- diffMemHooks,
265
- config
266
- );
210
+ function createUnifiedContextAssembler(stackMemoryRetrieval, config = {}) {
211
+ return new UnifiedContextAssembler(stackMemoryRetrieval, config);
267
212
  }
268
213
  export {
269
214
  DEFAULT_UNIFIED_CONTEXT_CONFIG,
@@ -0,0 +1,64 @@
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 } from "fs";
6
+ import { join } from "path";
7
+ function getProjectHandoffPaths(projectRoot) {
8
+ return {
9
+ handoffPath: join(projectRoot, ".stackmemory", "last-handoff.md"),
10
+ metadataPath: join(projectRoot, ".stackmemory", "last-handoff-meta.json")
11
+ };
12
+ }
13
+ function parseBranchFromHandoffContent(content) {
14
+ const compactMatch = content.match(/^# Handoff:\s+.+?@([^\n]+)$/m);
15
+ if (compactMatch?.[1]) {
16
+ return compactMatch[1].trim();
17
+ }
18
+ const verboseMatch = content.match(/^\*\*Branch\*\*:\s+([^\n]+)$/m);
19
+ if (verboseMatch?.[1]) {
20
+ return verboseMatch[1].trim();
21
+ }
22
+ const ultraMatch = content.match(/^\[H\].+?@([^|\n]+)\|/m);
23
+ if (ultraMatch?.[1]) {
24
+ return ultraMatch[1].trim();
25
+ }
26
+ return null;
27
+ }
28
+ function loadProjectHandoff(projectRoot, currentBranch) {
29
+ const { handoffPath, metadataPath } = getProjectHandoffPaths(projectRoot);
30
+ if (!existsSync(handoffPath)) {
31
+ return null;
32
+ }
33
+ const content = readFileSync(handoffPath, "utf8").trim();
34
+ if (!content) {
35
+ return null;
36
+ }
37
+ let metadata = null;
38
+ if (existsSync(metadataPath)) {
39
+ try {
40
+ metadata = JSON.parse(readFileSync(metadataPath, "utf8"));
41
+ } catch {
42
+ metadata = null;
43
+ }
44
+ }
45
+ const branch = metadata?.branch || parseBranchFromHandoffContent(content);
46
+ if (currentBranch && branch && branch !== currentBranch) {
47
+ return {
48
+ content,
49
+ branch,
50
+ compatible: false,
51
+ mismatchReason: `handoff is for branch ${branch}, current branch is ${currentBranch}`
52
+ };
53
+ }
54
+ return {
55
+ content,
56
+ branch: branch || null,
57
+ compatible: true
58
+ };
59
+ }
60
+ export {
61
+ getProjectHandoffPaths,
62
+ loadProjectHandoff,
63
+ parseBranchFromHandoffContent
64
+ };
@@ -7,6 +7,7 @@ import * as fs from "fs/promises";
7
7
  import * as path from "path";
8
8
  import { logger } from "../monitoring/logger.js";
9
9
  import { SystemError, ErrorCode } from "../errors/index.js";
10
+ import { canonicalStateStore } from "../shared-state/canonical-store.js";
10
11
  function _getEnv(key, defaultValue) {
11
12
  const value = process.env[key];
12
13
  if (value === void 0) {
@@ -119,6 +120,16 @@ class SessionManager {
119
120
  };
120
121
  await this.saveSession(session);
121
122
  await this.setProjectActiveSession(params.projectId, session.sessionId);
123
+ await canonicalStateStore.appendEvent({
124
+ type: "session_created",
125
+ tool: "stackmemory",
126
+ sessionId: session.sessionId,
127
+ projectId: session.projectId,
128
+ branch: session.branch,
129
+ payload: {
130
+ state: session.state
131
+ }
132
+ });
122
133
  this.currentSession = session;
123
134
  logger.info("Created new session", {
124
135
  sessionId: session.sessionId,
@@ -152,6 +163,14 @@ class SessionManager {
152
163
  `${session.sessionId}.json`
153
164
  );
154
165
  await fs.writeFile(sessionPath, JSON.stringify(session, null, 2));
166
+ await canonicalStateStore.upsertSession({
167
+ sessionId: session.sessionId,
168
+ tool: "stackmemory",
169
+ projectId: session.projectId,
170
+ branch: session.branch,
171
+ status: session.state,
172
+ metadata: session.metadata
173
+ });
155
174
  }
156
175
  async suspendSession(sessionId) {
157
176
  const id = sessionId || this.currentSession?.sessionId;
@@ -193,6 +212,15 @@ class SessionManager {
193
212
  `${session.sessionId}.json`
194
213
  );
195
214
  await fs.rename(sessionPath, historyPath);
215
+ await canonicalStateStore.endSession(session.sessionId, "closed");
216
+ await canonicalStateStore.appendEvent({
217
+ type: "session_closed",
218
+ tool: "stackmemory",
219
+ sessionId: session.sessionId,
220
+ projectId: session.projectId,
221
+ branch: session.branch,
222
+ payload: {}
223
+ });
196
224
  }
197
225
  }
198
226
  async listSessions(filter) {