@stackmemoryai/stackmemory 1.6.2 → 1.8.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/dist/src/agents/core/agent-task-manager.js +3 -3
- package/dist/src/agents/verifiers/formatter-verifier.js +1 -1
- package/dist/src/agents/verifiers/llm-judge.js +2 -2
- package/dist/src/cli/commands/conductor-traces.js +314 -0
- package/dist/src/cli/commands/context-rehydrate.js +2 -2
- package/dist/src/cli/commands/log.js +1 -1
- package/dist/src/cli/commands/onboard.js +4 -4
- package/dist/src/cli/commands/orchestrate.js +328 -27
- package/dist/src/cli/commands/orchestrator.js +50 -3
- package/dist/src/cli/commands/search.js +3 -3
- package/dist/src/cli/commands/setup.js +1 -1
- package/dist/src/cli/commands/signup.js +1 -1
- package/dist/src/cli/commands/skills.js +2 -2
- package/dist/src/cli/commands/worktree.js +1 -1
- package/dist/src/core/config/config-manager.js +3 -1
- package/dist/src/core/config/types.js +7 -0
- package/dist/src/core/context/dual-stack-manager.js +2 -2
- package/dist/src/core/context/frame-database.js +38 -0
- package/dist/src/core/context/frame-enrichment.js +93 -0
- package/dist/src/core/context/frame-handoff-manager.js +1 -1
- package/dist/src/core/context/frame-manager.js +4 -4
- package/dist/src/core/context/rehydration.js +6 -6
- package/dist/src/core/database/sqlite-adapter.js +136 -15
- package/dist/src/core/digest/frame-digest-integration.js +1 -1
- package/dist/src/core/digest/hybrid-digest-generator.js +1 -1
- package/dist/src/core/digest/hybrid-digest.js +3 -3
- package/dist/src/core/errors/recovery.js +1 -1
- package/dist/src/core/extensions/loader.js +10 -10
- package/dist/src/core/extensions/plugin-system.js +1 -1
- package/dist/src/core/monitoring/logger.js +2 -2
- package/dist/src/core/monitoring/metrics.js +2 -2
- package/dist/src/core/monitoring/progress-tracker.js +2 -2
- package/dist/src/core/performance/lazy-context-loader.js +1 -1
- package/dist/src/core/performance/performance-benchmark.js +8 -8
- package/dist/src/core/performance/performance-profiler.js +2 -2
- package/dist/src/core/performance/streaming-jsonl-parser.js +1 -1
- package/dist/src/core/projects/project-isolation.js +1 -1
- package/dist/src/core/projects/project-manager.js +5 -5
- package/dist/src/core/session/clear-survival.js +3 -3
- package/dist/src/core/session/handoff-generator.js +1 -1
- package/dist/src/core/session/session-manager.js +4 -4
- package/dist/src/core/skills/skill-storage.js +2 -2
- package/dist/src/core/storage/remote-storage.js +2 -2
- package/dist/src/core/trace/cli-trace-wrapper.js +3 -3
- package/dist/src/core/trace/debug-trace.js +2 -2
- package/dist/src/core/trace/trace-detector.js +1 -1
- package/dist/src/core/worktree/worktree-manager.js +2 -2
- package/dist/src/features/analytics/api/analytics-api.js +1 -1
- package/dist/src/features/analytics/core/analytics-service.js +2 -2
- package/dist/src/features/analytics/queries/metrics-queries.js +1 -1
- package/dist/src/features/web/server/index.js +8 -8
- package/dist/src/integrations/anthropic/client.js +4 -4
- package/dist/src/integrations/claude-code/post-task-hooks.js +3 -3
- package/dist/src/integrations/claude-code/subagent-client.js +2 -2
- package/dist/src/integrations/diffmem/client.js +1 -1
- package/dist/src/integrations/linear/client.js +1 -1
- package/dist/src/integrations/linear/migration.js +1 -1
- package/dist/src/integrations/linear/oauth-server.js +2 -2
- package/dist/src/integrations/linear/sync.js +1 -1
- package/dist/src/integrations/linear/webhook-handler.js +2 -2
- package/dist/src/integrations/linear/webhook-server.js +2 -2
- package/dist/src/integrations/linear/webhook.js +2 -2
- package/dist/src/integrations/mcp/handlers/discovery-handlers.js +3 -3
- package/dist/src/integrations/mcp/handlers/linear-handlers.js +1 -1
- package/dist/src/integrations/mcp/handlers/skill-handlers.js +2 -2
- package/dist/src/integrations/mcp/handlers/task-handlers.js +2 -2
- package/dist/src/integrations/mcp/handlers/trace-handlers.js +1 -1
- package/dist/src/integrations/mcp/refactored-server.js +2 -2
- package/dist/src/integrations/mcp/remote-server.js +1 -1
- package/dist/src/integrations/mcp/server.js +4 -4
- package/dist/src/integrations/ralph/bridge/ralph-stackmemory-bridge.js +13 -13
- package/dist/src/integrations/ralph/context/stackmemory-context-loader.js +1 -1
- package/dist/src/integrations/ralph/learning/pattern-learner.js +3 -3
- package/dist/src/integrations/ralph/orchestration/multi-loop-orchestrator.js +1 -1
- package/dist/src/integrations/ralph/patterns/compounding-engineering-pattern.js +2 -2
- package/dist/src/integrations/ralph/patterns/extended-coherence-sessions.js +19 -19
- package/dist/src/integrations/ralph/patterns/oracle-worker-pattern.js +5 -5
- package/dist/src/integrations/ralph/performance/performance-optimizer.js +1 -1
- package/dist/src/integrations/ralph/recovery/crash-recovery.js +1 -1
- package/dist/src/integrations/ralph/state/state-reconciler.js +1 -1
- package/dist/src/integrations/ralph/swarm/git-workflow-manager.js +4 -4
- package/dist/src/integrations/ralph/swarm/swarm-coordinator.js +8 -8
- package/dist/src/integrations/ralph/visualization/ralph-debugger.js +3 -3
- package/dist/src/orchestrators/multimodal/harness.js +3 -3
- package/dist/src/servers/production/auth-middleware.js +2 -2
- package/package.json +1 -1
|
@@ -161,7 +161,7 @@ class AgentTaskManager {
|
|
|
161
161
|
/**
|
|
162
162
|
* Run a single verifier
|
|
163
163
|
*/
|
|
164
|
-
async runVerifier(verifierId,
|
|
164
|
+
async runVerifier(verifierId, _action, _context) {
|
|
165
165
|
const mockResults = {
|
|
166
166
|
formatter: () => ({
|
|
167
167
|
verifierId: "formatter",
|
|
@@ -317,7 +317,7 @@ class AgentTaskManager {
|
|
|
317
317
|
* Generate feedback from verification results
|
|
318
318
|
*/
|
|
319
319
|
generateFeedback(results) {
|
|
320
|
-
const
|
|
320
|
+
const _failed = results.filter((r) => !r.passed);
|
|
321
321
|
const warnings = results.filter(
|
|
322
322
|
(r) => !r.passed && r.severity === "warning"
|
|
323
323
|
);
|
|
@@ -363,7 +363,7 @@ ${warningMessages}`;
|
|
|
363
363
|
taskId: session.taskId,
|
|
364
364
|
turnCount: session.turnCount
|
|
365
365
|
});
|
|
366
|
-
const
|
|
366
|
+
const _task = this.taskStore.getTask(session.taskId);
|
|
367
367
|
const isComplete = this.assessTaskCompletion(session);
|
|
368
368
|
if (isComplete) {
|
|
369
369
|
await this.completeSession(session);
|
|
@@ -95,7 +95,7 @@ class FormatterVerifier extends BaseVerifier {
|
|
|
95
95
|
async runFormatter(formatter, context) {
|
|
96
96
|
const command = `${formatter.checkCommand} "${context.filePath}"`;
|
|
97
97
|
try {
|
|
98
|
-
const {
|
|
98
|
+
const { _stdout, _stderr } = await execAsync(command, {
|
|
99
99
|
cwd: process.cwd(),
|
|
100
100
|
timeout: this.config.timeout
|
|
101
101
|
});
|
|
@@ -28,7 +28,7 @@ class LLMJudge extends BaseVerifier {
|
|
|
28
28
|
...config
|
|
29
29
|
});
|
|
30
30
|
}
|
|
31
|
-
shouldActivate(
|
|
31
|
+
shouldActivate(_context) {
|
|
32
32
|
return true;
|
|
33
33
|
}
|
|
34
34
|
async verify(input, context) {
|
|
@@ -185,7 +185,7 @@ class LLMJudge extends BaseVerifier {
|
|
|
185
185
|
}
|
|
186
186
|
);
|
|
187
187
|
}
|
|
188
|
-
generateJudgementFeedback(criteria, overallScore,
|
|
188
|
+
generateJudgementFeedback(criteria, overallScore, _context) {
|
|
189
189
|
if (overallScore >= this.VETO_THRESHOLD) {
|
|
190
190
|
return `Semantic validation PASSED (${(overallScore * 100).toFixed(1)}% confidence). Changes adequately address the requirements.`;
|
|
191
191
|
}
|
|
@@ -0,0 +1,314 @@
|
|
|
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 Database from "better-sqlite3";
|
|
6
|
+
import { mkdirSync } from "fs";
|
|
7
|
+
import { join } from "path";
|
|
8
|
+
import { homedir } from "os";
|
|
9
|
+
import { randomUUID } from "crypto";
|
|
10
|
+
function classifyErrorText(text) {
|
|
11
|
+
const lower = text.toLowerCase();
|
|
12
|
+
if (lower.includes("lint") || lower.includes("eslint") || lower.includes("prettier"))
|
|
13
|
+
return "lint_failure";
|
|
14
|
+
if (lower.includes("test") && (lower.includes("fail") || lower.includes("error")))
|
|
15
|
+
return "test_failure";
|
|
16
|
+
if (lower.includes("timeout") || lower.includes("timed out"))
|
|
17
|
+
return "timeout";
|
|
18
|
+
if (lower.includes("conflict") || lower.includes("merge"))
|
|
19
|
+
return "git_conflict";
|
|
20
|
+
if (lower.includes("429") || lower.includes("rate limit"))
|
|
21
|
+
return "rate_limit";
|
|
22
|
+
if (lower.includes("permission") || lower.includes("EACCES") || lower.includes("not found"))
|
|
23
|
+
return "permission_or_missing";
|
|
24
|
+
if (lower.includes("build") && lower.includes("error"))
|
|
25
|
+
return "build_failure";
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
function getTracesDbPath() {
|
|
29
|
+
return join(homedir(), ".stackmemory", "conductor", "traces.db");
|
|
30
|
+
}
|
|
31
|
+
function openTracesDb(dbPath) {
|
|
32
|
+
const path = dbPath ?? getTracesDbPath();
|
|
33
|
+
mkdirSync(join(path, ".."), { recursive: true });
|
|
34
|
+
const db = new Database(path);
|
|
35
|
+
db.pragma("journal_mode = WAL");
|
|
36
|
+
db.pragma("foreign_keys = ON");
|
|
37
|
+
db.exec(`
|
|
38
|
+
CREATE TABLE IF NOT EXISTS conductor_traces (
|
|
39
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
40
|
+
issue_id TEXT NOT NULL,
|
|
41
|
+
session_id TEXT NOT NULL,
|
|
42
|
+
attempt INTEGER NOT NULL,
|
|
43
|
+
turn_number INTEGER NOT NULL,
|
|
44
|
+
timestamp INTEGER NOT NULL,
|
|
45
|
+
phase TEXT,
|
|
46
|
+
tool_names TEXT,
|
|
47
|
+
tool_count INTEGER DEFAULT 0,
|
|
48
|
+
files_modified INTEGER DEFAULT 0,
|
|
49
|
+
input_tokens INTEGER DEFAULT 0,
|
|
50
|
+
output_tokens INTEGER DEFAULT 0,
|
|
51
|
+
cache_creation_tokens INTEGER DEFAULT 0,
|
|
52
|
+
cache_read_tokens INTEGER DEFAULT 0,
|
|
53
|
+
message_preview TEXT,
|
|
54
|
+
event_json TEXT NOT NULL,
|
|
55
|
+
UNIQUE(session_id, turn_number)
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
CREATE INDEX IF NOT EXISTS idx_traces_issue
|
|
59
|
+
ON conductor_traces(issue_id, attempt);
|
|
60
|
+
CREATE INDEX IF NOT EXISTS idx_traces_session
|
|
61
|
+
ON conductor_traces(session_id);
|
|
62
|
+
CREATE INDEX IF NOT EXISTS idx_traces_phase
|
|
63
|
+
ON conductor_traces(phase);
|
|
64
|
+
CREATE INDEX IF NOT EXISTS idx_traces_timestamp
|
|
65
|
+
ON conductor_traces(timestamp DESC);
|
|
66
|
+
`);
|
|
67
|
+
return db;
|
|
68
|
+
}
|
|
69
|
+
function withDb(db, fn) {
|
|
70
|
+
const ownDb = db ?? openTracesDb();
|
|
71
|
+
try {
|
|
72
|
+
return fn(ownDb);
|
|
73
|
+
} finally {
|
|
74
|
+
if (!db) ownDb.close();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
class TraceCollector {
|
|
78
|
+
db;
|
|
79
|
+
ownsDb;
|
|
80
|
+
sessionId;
|
|
81
|
+
issueId;
|
|
82
|
+
attempt;
|
|
83
|
+
turnCounter = 0;
|
|
84
|
+
insertStmt;
|
|
85
|
+
constructor(opts) {
|
|
86
|
+
this.issueId = opts.issueId;
|
|
87
|
+
this.attempt = opts.attempt;
|
|
88
|
+
this.sessionId = `${opts.issueId}-${opts.attempt}-${randomUUID().slice(0, 8)}`;
|
|
89
|
+
this.ownsDb = !opts.db;
|
|
90
|
+
this.db = opts.db ?? openTracesDb();
|
|
91
|
+
this.insertStmt = this.db.prepare(`
|
|
92
|
+
INSERT INTO conductor_traces (
|
|
93
|
+
issue_id, session_id, attempt, turn_number, timestamp,
|
|
94
|
+
phase, tool_names, tool_count, files_modified,
|
|
95
|
+
input_tokens, output_tokens, cache_creation_tokens, cache_read_tokens,
|
|
96
|
+
message_preview, event_json
|
|
97
|
+
) VALUES (
|
|
98
|
+
@issue_id, @session_id, @attempt, @turn_number, @timestamp,
|
|
99
|
+
@phase, @tool_names, @tool_count, @files_modified,
|
|
100
|
+
@input_tokens, @output_tokens, @cache_creation_tokens, @cache_read_tokens,
|
|
101
|
+
@message_preview, @event_json
|
|
102
|
+
)
|
|
103
|
+
`);
|
|
104
|
+
}
|
|
105
|
+
get session() {
|
|
106
|
+
return this.sessionId;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Record a turn using pre-extracted data from the orchestrator's stream parser.
|
|
110
|
+
* Avoids re-iterating content blocks — the caller already did that work.
|
|
111
|
+
*/
|
|
112
|
+
recordTurn(turnData, phase, eventJson) {
|
|
113
|
+
this.insertStmt.run({
|
|
114
|
+
issue_id: this.issueId,
|
|
115
|
+
session_id: this.sessionId,
|
|
116
|
+
attempt: this.attempt,
|
|
117
|
+
turn_number: this.turnCounter++,
|
|
118
|
+
timestamp: Date.now(),
|
|
119
|
+
phase: phase ?? null,
|
|
120
|
+
tool_names: turnData.toolNames.length > 0 ? JSON.stringify(turnData.toolNames) : null,
|
|
121
|
+
tool_count: turnData.toolCount,
|
|
122
|
+
files_modified: turnData.filesModified,
|
|
123
|
+
input_tokens: turnData.inputTokens,
|
|
124
|
+
output_tokens: turnData.outputTokens,
|
|
125
|
+
cache_creation_tokens: turnData.cacheCreationTokens,
|
|
126
|
+
cache_read_tokens: turnData.cacheReadTokens,
|
|
127
|
+
message_preview: turnData.textPreview,
|
|
128
|
+
event_json: eventJson
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
/** Record a result event (final output) */
|
|
132
|
+
recordResult(event) {
|
|
133
|
+
const resultText = typeof event.result === "string" ? event.result : JSON.stringify(event.result);
|
|
134
|
+
this.insertStmt.run({
|
|
135
|
+
issue_id: this.issueId,
|
|
136
|
+
session_id: this.sessionId,
|
|
137
|
+
attempt: this.attempt,
|
|
138
|
+
turn_number: this.turnCounter++,
|
|
139
|
+
timestamp: Date.now(),
|
|
140
|
+
phase: "result",
|
|
141
|
+
tool_names: null,
|
|
142
|
+
tool_count: 0,
|
|
143
|
+
files_modified: 0,
|
|
144
|
+
input_tokens: 0,
|
|
145
|
+
output_tokens: 0,
|
|
146
|
+
cache_creation_tokens: 0,
|
|
147
|
+
cache_read_tokens: 0,
|
|
148
|
+
message_preview: (resultText || "").slice(0, 500),
|
|
149
|
+
event_json: JSON.stringify(event).slice(0, 5e4)
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
/** Close the DB connection only if we own it */
|
|
153
|
+
close() {
|
|
154
|
+
if (!this.ownsDb) return;
|
|
155
|
+
try {
|
|
156
|
+
this.db.close();
|
|
157
|
+
} catch {
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
function stringifyEventTruncated(event) {
|
|
162
|
+
return JSON.stringify(event, (_key, value) => {
|
|
163
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
164
|
+
const obj = value;
|
|
165
|
+
if (obj.type === "tool_use" && obj.input) {
|
|
166
|
+
const inputStr = JSON.stringify(obj.input);
|
|
167
|
+
if (inputStr.length > 2e3) {
|
|
168
|
+
return {
|
|
169
|
+
...obj,
|
|
170
|
+
input: { _truncated: true, length: inputStr.length }
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
if (obj.type === "tool_result" && obj.content) {
|
|
175
|
+
const contentStr = typeof obj.content === "string" ? obj.content : JSON.stringify(obj.content);
|
|
176
|
+
if (contentStr.length > 2e3) {
|
|
177
|
+
return { ...obj, content: `[truncated: ${contentStr.length} chars]` };
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return value;
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
function listSessions(issueId, db) {
|
|
185
|
+
return withDb(db, (d) => {
|
|
186
|
+
const rows = d.prepare(
|
|
187
|
+
`
|
|
188
|
+
SELECT
|
|
189
|
+
issue_id,
|
|
190
|
+
session_id,
|
|
191
|
+
attempt,
|
|
192
|
+
COUNT(*) as total_turns,
|
|
193
|
+
SUM(tool_count) as total_tool_calls,
|
|
194
|
+
SUM(files_modified) as total_files_modified,
|
|
195
|
+
SUM(input_tokens) as total_input_tokens,
|
|
196
|
+
SUM(output_tokens) as total_output_tokens,
|
|
197
|
+
GROUP_CONCAT(DISTINCT phase) as phases,
|
|
198
|
+
MIN(timestamp) as started_at,
|
|
199
|
+
MAX(timestamp) as ended_at
|
|
200
|
+
FROM conductor_traces
|
|
201
|
+
WHERE issue_id = ?
|
|
202
|
+
GROUP BY session_id
|
|
203
|
+
ORDER BY started_at DESC
|
|
204
|
+
`
|
|
205
|
+
).all(issueId);
|
|
206
|
+
return rows.map((r) => ({
|
|
207
|
+
issue_id: r.issue_id,
|
|
208
|
+
session_id: r.session_id,
|
|
209
|
+
attempt: r.attempt,
|
|
210
|
+
total_turns: r.total_turns,
|
|
211
|
+
total_tool_calls: r.total_tool_calls || 0,
|
|
212
|
+
total_files_modified: r.total_files_modified || 0,
|
|
213
|
+
total_input_tokens: r.total_input_tokens || 0,
|
|
214
|
+
total_output_tokens: r.total_output_tokens || 0,
|
|
215
|
+
phases: (r.phases || "").split(",").filter(Boolean),
|
|
216
|
+
started_at: r.started_at,
|
|
217
|
+
ended_at: r.ended_at,
|
|
218
|
+
duration_ms: r.ended_at - r.started_at
|
|
219
|
+
}));
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
function getSessionTurns(sessionId, db) {
|
|
223
|
+
return withDb(
|
|
224
|
+
db,
|
|
225
|
+
(d) => d.prepare(
|
|
226
|
+
`
|
|
227
|
+
SELECT * FROM conductor_traces
|
|
228
|
+
WHERE session_id = ?
|
|
229
|
+
ORDER BY turn_number ASC
|
|
230
|
+
`
|
|
231
|
+
).all(sessionId)
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
function getPhaseBreakdown(sessionId, db) {
|
|
235
|
+
return withDb(
|
|
236
|
+
db,
|
|
237
|
+
(d) => d.prepare(
|
|
238
|
+
`
|
|
239
|
+
SELECT
|
|
240
|
+
phase,
|
|
241
|
+
COUNT(*) as turns,
|
|
242
|
+
SUM(tool_count) as tool_calls,
|
|
243
|
+
SUM(input_tokens) as input_tokens,
|
|
244
|
+
SUM(output_tokens) as output_tokens
|
|
245
|
+
FROM conductor_traces
|
|
246
|
+
WHERE session_id = ? AND phase IS NOT NULL
|
|
247
|
+
GROUP BY phase
|
|
248
|
+
ORDER BY MIN(turn_number) ASC
|
|
249
|
+
`
|
|
250
|
+
).all(sessionId)
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
function getToolFrequencies(issueId, db) {
|
|
254
|
+
return withDb(
|
|
255
|
+
db,
|
|
256
|
+
(d) => d.prepare(
|
|
257
|
+
`
|
|
258
|
+
SELECT j.value as tool_name, COUNT(*) as count
|
|
259
|
+
FROM conductor_traces, json_each(tool_names) j
|
|
260
|
+
WHERE issue_id = ? AND tool_names IS NOT NULL
|
|
261
|
+
GROUP BY j.value
|
|
262
|
+
ORDER BY count DESC
|
|
263
|
+
`
|
|
264
|
+
).all(issueId)
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
function getFailureTurns(issueId, tailCount = 5, db) {
|
|
268
|
+
return withDb(
|
|
269
|
+
db,
|
|
270
|
+
(d) => d.prepare(
|
|
271
|
+
`
|
|
272
|
+
SELECT t.* FROM conductor_traces t
|
|
273
|
+
INNER JOIN (
|
|
274
|
+
SELECT session_id, MAX(turn_number) as max_turn
|
|
275
|
+
FROM conductor_traces
|
|
276
|
+
WHERE issue_id = ?
|
|
277
|
+
GROUP BY session_id
|
|
278
|
+
) latest ON t.session_id = latest.session_id
|
|
279
|
+
AND t.turn_number > latest.max_turn - ?
|
|
280
|
+
WHERE t.issue_id = ?
|
|
281
|
+
ORDER BY t.session_id, t.turn_number ASC
|
|
282
|
+
`
|
|
283
|
+
).all(issueId, tailCount, issueId)
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
function getTraceStats(db) {
|
|
287
|
+
return withDb(
|
|
288
|
+
db,
|
|
289
|
+
(d) => d.prepare(
|
|
290
|
+
`
|
|
291
|
+
SELECT
|
|
292
|
+
COUNT(DISTINCT session_id) as total_sessions,
|
|
293
|
+
COUNT(*) as total_turns,
|
|
294
|
+
SUM(input_tokens) as total_input_tokens,
|
|
295
|
+
SUM(output_tokens) as total_output_tokens,
|
|
296
|
+
COUNT(DISTINCT issue_id) as issues_traced
|
|
297
|
+
FROM conductor_traces
|
|
298
|
+
`
|
|
299
|
+
).get()
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
export {
|
|
303
|
+
TraceCollector,
|
|
304
|
+
classifyErrorText,
|
|
305
|
+
getFailureTurns,
|
|
306
|
+
getPhaseBreakdown,
|
|
307
|
+
getSessionTurns,
|
|
308
|
+
getToolFrequencies,
|
|
309
|
+
getTraceStats,
|
|
310
|
+
getTracesDbPath,
|
|
311
|
+
listSessions,
|
|
312
|
+
openTracesDb,
|
|
313
|
+
stringifyEventTruncated
|
|
314
|
+
};
|
|
@@ -289,7 +289,7 @@ async function listCheckpoints() {
|
|
|
289
289
|
console.log(
|
|
290
290
|
"\u{1F4A1} Verify: stackmemory context rehydrate --verify -c <checkpoint-id>"
|
|
291
291
|
);
|
|
292
|
-
} catch
|
|
292
|
+
} catch {
|
|
293
293
|
console.log("\u{1F4ED} No rehydration checkpoints directory found");
|
|
294
294
|
console.log(
|
|
295
295
|
"\u{1F4A1} Create first checkpoint with: stackmemory context rehydrate --create"
|
|
@@ -382,7 +382,7 @@ async function captureStackTraces() {
|
|
|
382
382
|
try {
|
|
383
383
|
const traces = [];
|
|
384
384
|
const fs = await import("fs/promises");
|
|
385
|
-
const {
|
|
385
|
+
const { _execSync } = await import("child_process");
|
|
386
386
|
const stackMemoryLogs = [
|
|
387
387
|
".stackmemory/error.log",
|
|
388
388
|
".stackmemory/compaction.log",
|
|
@@ -10,7 +10,7 @@ function createLogCommand() {
|
|
|
10
10
|
const log = new Command("log").alias("history").description("View recent activity log").option("-n, --lines <n>", "Number of entries to show", "20").option("-t, --type <type>", "Filter by type (task, frame, event, sync)").option("-f, --follow", "Follow log in real-time").action(async (options) => {
|
|
11
11
|
const projectRoot = process.cwd();
|
|
12
12
|
const dbPath = join(projectRoot, ".stackmemory", "context.db");
|
|
13
|
-
const
|
|
13
|
+
const _tasksPath = join(projectRoot, ".stackmemory", "tasks.jsonl");
|
|
14
14
|
if (!existsSync(dbPath)) {
|
|
15
15
|
console.log(
|
|
16
16
|
'\u274C StackMemory not initialized. Run "stackmemory init" first.'
|
|
@@ -99,7 +99,7 @@ async function runOnboarding() {
|
|
|
99
99
|
console.log(chalk.gray(`Opening signup page: ${signupUrl}`));
|
|
100
100
|
const mod = await import("open");
|
|
101
101
|
await mod.default(signupUrl);
|
|
102
|
-
} catch
|
|
102
|
+
} catch {
|
|
103
103
|
console.log(
|
|
104
104
|
chalk.yellow(
|
|
105
105
|
"Could not open browser automatically. Please sign up and obtain your DATABASE_URL."
|
|
@@ -379,7 +379,7 @@ DATABASE_URL=${config.databaseUrl}
|
|
|
379
379
|
" Tip: export DATABASE_URL from this file in your shell profile."
|
|
380
380
|
)
|
|
381
381
|
);
|
|
382
|
-
} catch
|
|
382
|
+
} catch {
|
|
383
383
|
console.log(chalk.yellow(" \u26A0 Could not write hosted DB env file"));
|
|
384
384
|
}
|
|
385
385
|
}
|
|
@@ -410,7 +410,7 @@ exec stackmemory "$@"
|
|
|
410
410
|
execFileSync("ln", ["-s", sourcePath, binPath]);
|
|
411
411
|
console.log(chalk.green(" \u2713 Created claude-sm command"));
|
|
412
412
|
}
|
|
413
|
-
} catch
|
|
413
|
+
} catch {
|
|
414
414
|
console.log(
|
|
415
415
|
chalk.yellow(" \u26A0 Could not create claude-sm symlink (may need sudo)")
|
|
416
416
|
);
|
|
@@ -506,7 +506,7 @@ fi
|
|
|
506
506
|
execFileSync("ln", ["-s", codexSourcePath, codexBinPath]);
|
|
507
507
|
console.log(chalk.green(" \u2713 Created codex-sm command"));
|
|
508
508
|
}
|
|
509
|
-
} catch
|
|
509
|
+
} catch {
|
|
510
510
|
console.log(
|
|
511
511
|
chalk.yellow(" \u26A0 Could not create codex-sm symlink (may need sudo)")
|
|
512
512
|
);
|