@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.
- package/LICENSE +131 -64
- package/README.md +107 -24
- package/bin/claude-sm +16 -1
- package/bin/claude-smd +16 -1
- package/bin/codex-smd +16 -1
- package/bin/gemini-sm +16 -1
- package/bin/hermes-sm +21 -0
- package/bin/hermes-smd +21 -0
- package/bin/opencode-sm +16 -1
- package/dist/src/cli/claude-sm.js +266 -84
- package/dist/src/cli/codex-sm.js +225 -33
- package/dist/src/cli/commands/bench.js +209 -2
- package/dist/src/cli/commands/brain.js +206 -0
- package/dist/src/cli/commands/cache.js +126 -0
- package/dist/src/cli/commands/company-os.js +184 -0
- package/dist/src/cli/commands/context.js +5 -0
- package/dist/src/cli/commands/daemon.js +41 -0
- package/dist/src/cli/commands/handoff.js +40 -9
- package/dist/src/cli/commands/onboard.js +70 -3
- package/dist/src/cli/commands/operator.js +127 -0
- package/dist/src/cli/commands/optimize.js +117 -0
- package/dist/src/cli/commands/orchestrate.js +232 -5
- package/dist/src/cli/commands/orchestrator.js +315 -26
- package/dist/src/cli/commands/pack.js +322 -0
- package/dist/src/cli/commands/patterns.js +254 -0
- package/dist/src/cli/commands/portal.js +161 -0
- package/dist/src/cli/commands/scaffold.js +92 -0
- package/dist/src/cli/commands/search.js +40 -1
- package/dist/src/cli/commands/setup.js +178 -11
- package/dist/src/cli/commands/skills.js +10 -1
- package/dist/src/cli/commands/state.js +265 -0
- package/dist/src/cli/commands/sync.js +253 -0
- package/dist/src/cli/commands/tasks.js +130 -1
- package/dist/src/cli/commands/vision.js +221 -0
- package/dist/src/cli/gemini-sm.js +19 -29
- package/dist/src/cli/hermes-sm.js +224 -0
- package/dist/src/cli/index.js +105 -39
- package/dist/src/cli/opencode-sm.js +38 -21
- package/dist/src/cli/utils/determinism-watcher.js +66 -0
- package/dist/src/cli/utils/real-cli-bin.js +116 -0
- package/dist/src/core/brain/brain-store.js +187 -0
- package/dist/src/core/brain/brain-sync.js +193 -0
- package/dist/src/core/brain/index.js +78 -0
- package/dist/src/core/brain/types.js +10 -0
- package/dist/src/core/cache/content-cache.js +238 -0
- package/dist/src/{integrations/diffmem → core/cache}/index.js +5 -5
- package/dist/src/core/cache/token-estimator.js +39 -0
- package/dist/src/core/config/feature-flags.js +2 -6
- package/dist/src/core/context/frame-database.js +79 -27
- package/dist/src/core/context/recursive-context-manager.js +1 -1
- package/dist/src/core/context/rehydration.js +2 -1
- package/dist/src/core/cross-search/cross-project-search.js +269 -0
- package/dist/src/core/cross-search/index.js +10 -0
- package/dist/src/core/database/sqlite-adapter.js +14 -84
- package/dist/src/core/extensions/provider-adapter.js +5 -0
- package/dist/src/core/models/model-router.js +54 -2
- package/dist/src/core/models/provider-pricing.js +58 -4
- package/dist/src/core/monitoring/logger.js +2 -1
- package/dist/src/core/optimization/trace-optimizer.js +413 -0
- package/dist/src/core/patterns/index.js +22 -0
- package/dist/src/core/patterns/pattern-applier.js +39 -0
- package/dist/src/core/patterns/pattern-observer.js +157 -0
- package/dist/src/core/patterns/pattern-store.js +259 -0
- package/dist/src/core/patterns/types.js +19 -0
- package/dist/src/core/provenance/confidence-scorer.js +128 -0
- package/dist/src/core/provenance/index.js +40 -0
- package/dist/src/core/provenance/provenance-store.js +194 -0
- package/dist/src/core/provenance/types.js +82 -0
- package/dist/src/core/retrieval/llm-context-retrieval.js +5 -4
- package/dist/src/core/retrieval/unified-context-assembler.js +11 -66
- package/dist/src/core/session/project-handoff.js +64 -0
- package/dist/src/core/session/session-manager.js +28 -0
- package/dist/src/core/shared-state/canonical-store.js +564 -0
- package/dist/src/core/skill-packs/index.js +18 -0
- package/dist/src/core/skill-packs/parser.js +42 -0
- package/dist/src/core/skill-packs/registry.js +224 -0
- package/dist/src/core/skill-packs/types.js +79 -0
- package/dist/src/core/storage/cloud-sync-manager.js +116 -0
- package/dist/src/core/storage/cloud-sync.js +574 -0
- package/dist/src/core/storage/two-tier-storage.js +5 -1
- package/dist/src/core/tasks/master-tasks-template.js +43 -0
- package/dist/src/core/tasks/md-task-parser.js +138 -0
- package/dist/src/core/trace/trace-event-store.js +282 -0
- package/dist/src/core/vision/index.js +27 -0
- package/dist/src/core/vision/signals.js +79 -0
- package/dist/src/core/vision/types.js +22 -0
- package/dist/src/core/vision/vision-file.js +146 -0
- package/dist/src/core/vision/vision-loop.js +220 -0
- package/dist/src/core/wiki/wiki-compiler.js +103 -1
- package/dist/src/daemon/daemon-config.js +52 -0
- package/dist/src/daemon/services/desire-path-service.js +566 -0
- package/dist/src/daemon/services/github-service.js +126 -0
- package/dist/src/daemon/services/research-stream-service.js +320 -0
- package/dist/src/daemon/services/telemetry-service.js +192 -0
- package/dist/src/daemon/unified-daemon.js +58 -1
- package/dist/src/features/browser/cli-browser-agent.js +417 -0
- package/dist/src/features/browser/stagehand-workflows.js +578 -0
- package/dist/src/features/operator/adapter-factory.js +62 -0
- package/dist/src/features/operator/browser-adapter.js +109 -0
- package/dist/src/features/operator/desktop-adapter.js +125 -0
- package/dist/src/features/operator/index.js +39 -0
- package/dist/src/features/operator/llm-decision.js +137 -0
- package/dist/src/features/operator/operator-logger.js +92 -0
- package/dist/src/features/operator/overnight-runner.js +327 -0
- package/dist/src/features/operator/screen-adapter.js +91 -0
- package/dist/src/features/operator/session-manager.js +127 -0
- package/dist/src/features/operator/state-machine.js +227 -0
- package/dist/src/features/operator/task-queue.js +81 -0
- package/dist/src/features/portal/index.js +26 -0
- package/dist/src/features/portal/server.js +240 -0
- package/dist/src/features/portal/types.js +14 -0
- package/dist/src/features/portal/ui.js +195 -0
- package/dist/src/features/sweep/pty-wrapper.js +13 -5
- package/dist/src/features/tasks/task-aware-context.js +2 -1
- package/dist/src/features/tui/simple-monitor.js +0 -23
- package/dist/src/features/tui/swarm-monitor.js +8 -66
- package/dist/src/features/web/client/hooks/use-socket.js +12 -0
- package/dist/src/{core/merge/index.js → features/web/client/lib/utils.js} +8 -4
- package/dist/src/features/web/client/next-env.d.js +4 -0
- package/dist/src/features/web/client/stores/session-store.js +12 -0
- package/dist/src/features/web/server/gcp-billing.js +76 -0
- package/dist/src/features/web/server/index.js +10 -0
- package/dist/src/features/web/server/spend-calculator.js +228 -0
- package/dist/src/hooks/schemas.js +6 -1
- package/dist/src/integrations/anthropic/client.js +3 -2
- package/dist/src/integrations/claude-code/agent-bridge.js +0 -3
- package/dist/src/integrations/claude-code/subagent-client.js +307 -11
- package/dist/src/integrations/claude-code/task-coordinator.js +2 -1
- package/dist/src/integrations/github/pr-state.js +158 -0
- package/dist/src/integrations/linear/client.js +4 -1
- package/dist/src/integrations/linear/webhook-retry.js +196 -0
- package/dist/src/integrations/linear/webhook-server.js +18 -22
- package/dist/src/integrations/mcp/handlers/cloud-sync-handlers.js +101 -0
- package/dist/src/integrations/mcp/handlers/index.js +40 -84
- package/dist/src/integrations/mcp/server.js +542 -641
- package/dist/src/integrations/mcp/tool-alias-registry.js +297 -0
- package/dist/src/integrations/mcp/tool-definitions.js +152 -682
- package/dist/src/mcp/stackmemory-mcp-server.js +571 -231
- package/dist/src/orchestrators/multimodal/determinism.js +244 -0
- package/dist/src/orchestrators/multimodal/harness.js +149 -78
- package/dist/src/orchestrators/multimodal/providers.js +44 -3
- package/dist/src/skills/recursive-agent-orchestrator.js +2 -4
- package/dist/src/utils/hook-installer.js +0 -8
- package/dist/src/utils/process-cleanup.js +1 -7
- package/docs/README.md +42 -0
- package/docs/guides/README_INSTALL.md +208 -0
- package/package.json +27 -9
- package/packs/coding/python-fastapi/instructions.md +60 -0
- package/packs/coding/python-fastapi/pack.yaml +28 -0
- package/packs/coding/typescript-react/instructions.md +47 -0
- package/packs/coding/typescript-react/pack.yaml +28 -0
- package/packs/core/commands/capture.md +32 -0
- package/packs/core/commands/learn.md +73 -0
- package/packs/core/commands/next.md +36 -0
- package/packs/core/commands/restart.md +58 -0
- package/packs/core/commands/restore.md +29 -0
- package/packs/core/commands/start.md +57 -0
- package/packs/core/commands/stop.md +65 -0
- package/packs/core/commands/summary.md +40 -0
- package/packs/core/manifest.json +24 -0
- package/packs/ops/decision-recovery/instructions.md +65 -0
- package/packs/ops/decision-recovery/pack.yaml +89 -0
- package/scripts/claude-code-wrapper.sh +11 -0
- package/scripts/claude-sm-setup.sh +12 -1
- package/scripts/codex-wrapper.sh +11 -0
- package/scripts/git-hooks/branch-context-manager.sh +11 -0
- package/scripts/git-hooks/post-checkout-stackmemory.sh +11 -0
- package/scripts/git-hooks/post-commit-stackmemory.sh +11 -0
- package/scripts/git-hooks/pre-commit-stackmemory.sh +11 -0
- package/scripts/hooks/cleanup-shell.sh +12 -1
- package/scripts/hooks/task-complete.sh +12 -1
- package/scripts/install-code-execution-hooks.sh +12 -1
- package/scripts/install-sweep-hook.sh +12 -0
- package/scripts/install.sh +11 -0
- package/scripts/opencode-wrapper.sh +11 -0
- package/scripts/portal/cloud-init.yaml +69 -0
- package/scripts/portal/setup.sh +69 -0
- package/scripts/portal/stackmemory-portal.service +34 -0
- package/scripts/setup-claude-integration.sh +12 -1
- package/scripts/smoke-init-db.sh +23 -0
- package/scripts/stackmemory-daemon.sh +11 -0
- package/scripts/verify-dist.cjs +11 -4
- package/dist/src/cli/commands/ralph.js +0 -1053
- package/dist/src/cli/commands/team.js +0 -168
- package/dist/src/core/context/shared-context-layer.js +0 -620
- package/dist/src/core/context/stack-merge-resolver.js +0 -748
- package/dist/src/core/merge/conflict-detector.js +0 -430
- package/dist/src/core/merge/resolution-engine.js +0 -557
- package/dist/src/core/merge/stack-diff.js +0 -531
- package/dist/src/core/merge/unified-merge-resolver.js +0 -302
- package/dist/src/hooks/diffmem-hooks.js +0 -376
- package/dist/src/integrations/diffmem/client.js +0 -208
- package/dist/src/integrations/diffmem/config.js +0 -14
- package/dist/src/integrations/greptile/client.js +0 -101
- package/dist/src/integrations/greptile/config.js +0 -14
- package/dist/src/integrations/greptile/index.js +0 -11
- package/dist/src/integrations/mcp/handlers/cord-handlers.js +0 -397
- package/dist/src/integrations/mcp/handlers/diffmem-handlers.js +0 -455
- package/dist/src/integrations/mcp/handlers/greptile-handlers.js +0 -456
- package/dist/src/integrations/mcp/handlers/provider-handlers.js +0 -227
- package/dist/src/integrations/mcp/handlers/team-handlers.js +0 -211
- package/dist/src/integrations/ralph/bridge/ralph-stackmemory-bridge.js +0 -863
- package/dist/src/integrations/ralph/context/context-budget-manager.js +0 -308
- package/dist/src/integrations/ralph/context/stackmemory-context-loader.js +0 -391
- package/dist/src/integrations/ralph/index.js +0 -17
- package/dist/src/integrations/ralph/learning/pattern-learner.js +0 -435
- package/dist/src/integrations/ralph/lifecycle/iteration-lifecycle.js +0 -448
- package/dist/src/integrations/ralph/loopmax.js +0 -488
- package/dist/src/integrations/ralph/monitoring/swarm-dashboard.js +0 -293
- package/dist/src/integrations/ralph/monitoring/swarm-registry.js +0 -107
- package/dist/src/integrations/ralph/orchestration/multi-loop-orchestrator.js +0 -508
- package/dist/src/integrations/ralph/patterns/compounding-engineering-pattern.js +0 -407
- package/dist/src/integrations/ralph/patterns/extended-coherence-sessions.js +0 -495
- package/dist/src/integrations/ralph/patterns/oracle-worker-pattern.js +0 -387
- package/dist/src/integrations/ralph/performance/performance-optimizer.js +0 -357
- package/dist/src/integrations/ralph/recovery/crash-recovery.js +0 -461
- package/dist/src/integrations/ralph/state/state-reconciler.js +0 -420
- package/dist/src/integrations/ralph/swarm/git-workflow-manager.js +0 -444
- package/dist/src/integrations/ralph/swarm/swarm-coordinator.js +0 -1007
- package/dist/src/integrations/ralph/visualization/ralph-debugger.js +0 -635
- package/scripts/ralph-loop-implementation.js +0 -404
- /package/dist/src/core/{merge → cache}/types.js +0 -0
- /package/dist/src/{integrations/diffmem/types.js → core/storage/cloud-sync-types.js} +0 -0
- /package/dist/src/{integrations/greptile/types.js → core/trace/trace-event.js} +0 -0
- /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
|
|
117
|
+
if (frame.digestPreview) tokens += estimateTokens(frame.digestPreview);
|
|
117
118
|
return Math.floor(tokens);
|
|
118
119
|
}
|
|
119
120
|
estimateSummaryTokens(summary) {
|
|
120
|
-
return
|
|
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:
|
|
432
|
-
JSON.stringify(request.compressedSummary)
|
|
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,
|
|
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
|
-
|
|
74
|
-
|
|
75
|
-
|
|
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
|
|
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
|
-
|
|
180
|
-
return
|
|
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,
|
|
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) {
|