@stackmemoryai/stackmemory 0.3.5 → 0.3.7
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/agents/verifiers/base-verifier.js.map +2 -2
- package/dist/agents/verifiers/formatter-verifier.js.map +2 -2
- package/dist/agents/verifiers/llm-judge.js.map +2 -2
- package/dist/cli/claude-sm.js +24 -13
- package/dist/cli/claude-sm.js.map +2 -2
- package/dist/cli/codex-sm.js +24 -13
- package/dist/cli/codex-sm.js.map +2 -2
- package/dist/cli/commands/agent.js.map +2 -2
- package/dist/cli/commands/chromadb.js +217 -32
- package/dist/cli/commands/chromadb.js.map +2 -2
- package/dist/cli/commands/clear.js +12 -1
- package/dist/cli/commands/clear.js.map +2 -2
- package/dist/cli/commands/context.js +13 -2
- package/dist/cli/commands/context.js.map +2 -2
- package/dist/cli/commands/dashboard.js.map +2 -2
- package/dist/cli/commands/gc.js +202 -0
- package/dist/cli/commands/gc.js.map +7 -0
- package/dist/cli/commands/handoff.js +12 -1
- package/dist/cli/commands/handoff.js.map +2 -2
- package/dist/cli/commands/infinite-storage.js +251 -0
- package/dist/cli/commands/infinite-storage.js.map +7 -0
- package/dist/cli/commands/linear-create.js +13 -2
- package/dist/cli/commands/linear-create.js.map +2 -2
- package/dist/cli/commands/linear-list.js +12 -1
- package/dist/cli/commands/linear-list.js.map +2 -2
- package/dist/cli/commands/linear-migrate.js +12 -1
- package/dist/cli/commands/linear-migrate.js.map +2 -2
- package/dist/cli/commands/linear-test.js +12 -1
- package/dist/cli/commands/linear-test.js.map +2 -2
- package/dist/cli/commands/linear-unified.js +262 -0
- package/dist/cli/commands/linear-unified.js.map +7 -0
- package/dist/cli/commands/linear.js +17 -6
- package/dist/cli/commands/linear.js.map +2 -2
- package/dist/cli/commands/monitor.js.map +2 -2
- package/dist/cli/commands/onboard.js.map +2 -2
- package/dist/cli/commands/quality.js.map +2 -2
- package/dist/cli/commands/search.js.map +2 -2
- package/dist/cli/commands/session.js.map +2 -2
- package/dist/cli/commands/skills.js +12 -1
- package/dist/cli/commands/skills.js.map +2 -2
- package/dist/cli/commands/storage.js +18 -7
- package/dist/cli/commands/storage.js.map +2 -2
- package/dist/cli/commands/tasks.js.map +2 -2
- package/dist/cli/commands/tui.js +13 -2
- package/dist/cli/commands/tui.js.map +2 -2
- package/dist/cli/commands/webhook.js +14 -3
- package/dist/cli/commands/webhook.js.map +2 -2
- package/dist/cli/commands/workflow.js +14 -3
- package/dist/cli/commands/workflow.js.map +2 -2
- package/dist/cli/commands/worktree.js.map +2 -2
- package/dist/cli/index.js +20 -5
- package/dist/cli/index.js.map +2 -2
- package/dist/core/config/config-manager.js.map +2 -2
- package/dist/core/context/auto-context.js.map +2 -2
- package/dist/core/context/compaction-handler.js.map +2 -2
- package/dist/core/context/context-bridge.js.map +2 -2
- package/dist/core/context/dual-stack-manager.js.map +2 -2
- package/dist/core/context/frame-database.js.map +2 -2
- package/dist/core/context/frame-digest.js.map +2 -2
- package/dist/core/context/frame-handoff-manager.js.map +2 -2
- package/dist/core/context/frame-manager.js +12 -1
- package/dist/core/context/frame-manager.js.map +2 -2
- package/dist/core/context/frame-stack.js.map +2 -2
- package/dist/core/context/incremental-gc.js +279 -0
- package/dist/core/context/incremental-gc.js.map +7 -0
- package/dist/core/context/permission-manager.js +12 -1
- package/dist/core/context/permission-manager.js.map +2 -2
- package/dist/core/context/refactored-frame-manager.js.map +2 -2
- package/dist/core/context/shared-context-layer.js +12 -1
- package/dist/core/context/shared-context-layer.js.map +2 -2
- package/dist/core/context/stack-merge-resolver.js.map +2 -2
- package/dist/core/context/validation.js.map +2 -2
- package/dist/core/database/batch-operations.js.map +2 -2
- package/dist/core/database/connection-pool.js.map +2 -2
- package/dist/core/database/migration-manager.js.map +2 -2
- package/dist/core/database/paradedb-adapter.js.map +2 -2
- package/dist/core/database/query-cache.js.map +2 -2
- package/dist/core/database/query-router.js.map +2 -2
- package/dist/core/database/sqlite-adapter.js.map +2 -2
- package/dist/core/digest/enhanced-hybrid-digest.js.map +2 -2
- package/dist/core/errors/recovery.js.map +2 -2
- package/dist/core/merge/resolution-engine.js.map +2 -2
- package/dist/core/monitoring/error-handler.js.map +2 -2
- package/dist/core/monitoring/logger.js +14 -3
- package/dist/core/monitoring/logger.js.map +2 -2
- package/dist/core/monitoring/metrics.js +13 -2
- package/dist/core/monitoring/metrics.js.map +2 -2
- package/dist/core/monitoring/progress-tracker.js +12 -1
- package/dist/core/monitoring/progress-tracker.js.map +2 -2
- package/dist/core/monitoring/session-monitor.js.map +2 -2
- package/dist/core/performance/context-cache.js.map +2 -2
- package/dist/core/performance/lazy-context-loader.js.map +2 -2
- package/dist/core/performance/monitor.js.map +2 -2
- package/dist/core/performance/optimized-frame-context.js.map +2 -2
- package/dist/core/performance/performance-benchmark.js.map +2 -2
- package/dist/core/performance/performance-profiler.js +12 -1
- package/dist/core/performance/performance-profiler.js.map +2 -2
- package/dist/core/performance/streaming-jsonl-parser.js.map +2 -2
- package/dist/core/persistence/postgres-adapter.js.map +2 -2
- package/dist/core/projects/project-manager.js.map +2 -2
- package/dist/core/retrieval/context-retriever.js.map +2 -2
- package/dist/core/retrieval/graph-retrieval.js.map +2 -2
- package/dist/core/retrieval/llm-context-retrieval.js.map +2 -2
- package/dist/core/retrieval/retrieval-benchmarks.js.map +2 -2
- package/dist/core/retrieval/summary-generator.js.map +2 -2
- package/dist/core/session/clear-survival.js.map +2 -2
- package/dist/core/session/handoff-generator.js.map +2 -2
- package/dist/core/session/session-manager.js +16 -5
- package/dist/core/session/session-manager.js.map +2 -2
- package/dist/core/skills/skill-storage.js +13 -2
- package/dist/core/skills/skill-storage.js.map +2 -2
- package/dist/core/storage/chromadb-adapter.js.map +2 -2
- package/dist/core/storage/chromadb-simple.js +160 -0
- package/dist/core/storage/chromadb-simple.js.map +7 -0
- package/dist/core/storage/infinite-storage.js +443 -0
- package/dist/core/storage/infinite-storage.js.map +7 -0
- package/dist/core/storage/railway-optimized-storage.js +19 -8
- package/dist/core/storage/railway-optimized-storage.js.map +2 -2
- package/dist/core/storage/remote-storage.js +12 -1
- package/dist/core/storage/remote-storage.js.map +2 -2
- package/dist/core/trace/cli-trace-wrapper.js +16 -5
- package/dist/core/trace/cli-trace-wrapper.js.map +2 -2
- package/dist/core/trace/db-trace-wrapper.js.map +2 -2
- package/dist/core/trace/debug-trace.js +21 -10
- package/dist/core/trace/debug-trace.js.map +2 -2
- package/dist/core/trace/index.js +46 -35
- package/dist/core/trace/index.js.map +2 -2
- package/dist/core/trace/trace-demo.js +12 -1
- package/dist/core/trace/trace-demo.js.map +2 -2
- package/dist/core/trace/trace-detector.js.map +2 -2
- package/dist/core/trace/trace-store.js.map +2 -2
- package/dist/core/utils/compression.js +79 -0
- package/dist/core/utils/compression.js.map +7 -0
- package/dist/core/utils/update-checker.js.map +2 -2
- package/dist/core/worktree/worktree-manager.js.map +2 -2
- package/dist/features/analytics/api/analytics-api.js.map +2 -2
- package/dist/features/analytics/core/analytics-service.js +12 -1
- package/dist/features/analytics/core/analytics-service.js.map +2 -2
- package/dist/features/analytics/queries/metrics-queries.js.map +2 -2
- package/dist/features/tasks/pebbles-task-store.js.map +2 -2
- package/dist/features/tui/components/analytics-panel.js.map +2 -2
- package/dist/features/tui/components/pr-tracker.js.map +2 -2
- package/dist/features/tui/components/session-monitor.js.map +2 -2
- package/dist/features/tui/components/subagent-fleet.js.map +2 -2
- package/dist/features/tui/components/task-board.js +650 -2
- package/dist/features/tui/components/task-board.js.map +2 -2
- package/dist/features/tui/index.js +16 -5
- package/dist/features/tui/index.js.map +2 -2
- package/dist/features/tui/services/data-service.js +35 -52
- package/dist/features/tui/services/data-service.js.map +2 -2
- package/dist/features/tui/services/linear-task-reader.js +100 -0
- package/dist/features/tui/services/linear-task-reader.js.map +7 -0
- package/dist/features/tui/services/websocket-client.js +13 -2
- package/dist/features/tui/services/websocket-client.js.map +2 -2
- package/dist/features/tui/terminal-compat.js +27 -16
- package/dist/features/tui/terminal-compat.js.map +2 -2
- package/dist/features/web/client/stores/task-store.js +22 -0
- package/dist/features/web/client/stores/task-store.js.map +7 -0
- package/dist/features/web/server/index.js +182 -0
- package/dist/features/web/server/index.js.map +7 -0
- package/dist/integrations/claude-code/enhanced-pre-clear-hooks.js.map +2 -2
- package/dist/integrations/claude-code/lifecycle-hooks.js.map +2 -2
- package/dist/integrations/claude-code/post-task-hooks.js.map +2 -2
- package/dist/integrations/linear/auth.js +17 -6
- package/dist/integrations/linear/auth.js.map +2 -2
- package/dist/integrations/linear/auto-sync.js.map +2 -2
- package/dist/integrations/linear/client.js.map +2 -2
- package/dist/integrations/linear/config.js.map +2 -2
- package/dist/integrations/linear/migration.js.map +2 -2
- package/dist/integrations/linear/oauth-server.js +13 -2
- package/dist/integrations/linear/oauth-server.js.map +2 -2
- package/dist/integrations/linear/rest-client.js.map +2 -2
- package/dist/integrations/linear/sync-enhanced.js +202 -0
- package/dist/integrations/linear/sync-enhanced.js.map +7 -0
- package/dist/integrations/linear/sync-manager.js.map +2 -2
- package/dist/integrations/linear/sync-service.js +12 -1
- package/dist/integrations/linear/sync-service.js.map +2 -2
- package/dist/integrations/linear/sync.js +34 -3
- package/dist/integrations/linear/sync.js.map +2 -2
- package/dist/integrations/linear/unified-sync.js +560 -0
- package/dist/integrations/linear/unified-sync.js.map +7 -0
- package/dist/integrations/linear/webhook-handler.js +12 -1
- package/dist/integrations/linear/webhook-handler.js.map +2 -2
- package/dist/integrations/linear/webhook-server.js +14 -3
- package/dist/integrations/linear/webhook-server.js.map +2 -2
- package/dist/integrations/linear/webhook.js +12 -1
- package/dist/integrations/linear/webhook.js.map +2 -2
- package/dist/integrations/mcp/handlers/context-handlers.js.map +2 -2
- package/dist/integrations/mcp/handlers/linear-handlers.js.map +2 -2
- package/dist/integrations/mcp/handlers/skill-handlers.js +13 -2
- package/dist/integrations/mcp/handlers/skill-handlers.js.map +2 -2
- package/dist/integrations/mcp/handlers/task-handlers.js.map +2 -2
- package/dist/integrations/mcp/handlers/trace-handlers.js.map +2 -2
- package/dist/integrations/mcp/middleware/tool-scoring.js.map +2 -2
- package/dist/integrations/mcp/refactored-server.js +15 -4
- package/dist/integrations/mcp/refactored-server.js.map +2 -2
- package/dist/integrations/mcp/server.js +12 -1
- package/dist/integrations/mcp/server.js.map +2 -2
- package/dist/integrations/mcp/tool-definitions.js.map +2 -2
- package/dist/integrations/pg-aiguide/embedding-provider.js +13 -2
- package/dist/integrations/pg-aiguide/embedding-provider.js.map +2 -2
- package/dist/integrations/pg-aiguide/semantic-search.js.map +2 -2
- package/dist/mcp/stackmemory-mcp-server.js +12 -1
- package/dist/mcp/stackmemory-mcp-server.js.map +2 -2
- package/dist/middleware/exponential-rate-limiter.js.map +2 -2
- package/dist/servers/production/auth-middleware.js +13 -2
- package/dist/servers/production/auth-middleware.js.map +2 -2
- package/dist/servers/railway/index.js +22 -11
- package/dist/servers/railway/index.js.map +2 -2
- package/dist/services/config-service.js.map +2 -2
- package/dist/services/context-service.js.map +2 -2
- package/dist/skills/claude-skills.js +150 -1
- package/dist/skills/claude-skills.js.map +2 -2
- package/dist/skills/dashboard-launcher.js +212 -0
- package/dist/skills/dashboard-launcher.js.map +7 -0
- package/dist/skills/repo-ingestion-skill.js +561 -0
- package/dist/skills/repo-ingestion-skill.js.map +7 -0
- package/dist/utils/logger.js +12 -1
- package/dist/utils/logger.js.map +2 -2
- package/package.json +7 -1
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import express from "express";
|
|
2
|
+
import { createServer } from "http";
|
|
3
|
+
import { Server as SocketServer } from "socket.io";
|
|
4
|
+
import cors from "cors";
|
|
5
|
+
import { LinearTaskReader } from "../../tui/services/linear-task-reader.js";
|
|
6
|
+
import { SessionManager } from "../../../core/session/session-manager.js";
|
|
7
|
+
import { FrameManager } from "../../../core/context/frame-manager.js";
|
|
8
|
+
import Database from "better-sqlite3";
|
|
9
|
+
import { existsSync } from "fs";
|
|
10
|
+
import { join } from "path";
|
|
11
|
+
function getEnv(key, defaultValue) {
|
|
12
|
+
const value = process.env[key];
|
|
13
|
+
if (value === void 0) {
|
|
14
|
+
if (defaultValue !== void 0) return defaultValue;
|
|
15
|
+
throw new Error(`Environment variable ${key} is required`);
|
|
16
|
+
}
|
|
17
|
+
return value;
|
|
18
|
+
}
|
|
19
|
+
function getOptionalEnv(key) {
|
|
20
|
+
return process.env[key];
|
|
21
|
+
}
|
|
22
|
+
const app = express();
|
|
23
|
+
const httpServer = createServer(app);
|
|
24
|
+
const io = new SocketServer(httpServer, {
|
|
25
|
+
cors: {
|
|
26
|
+
origin: process.env["CLIENT_URL"] || "http://localhost:3000",
|
|
27
|
+
methods: ["GET", "POST"]
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
app.use(cors());
|
|
31
|
+
app.use(express.json());
|
|
32
|
+
let taskReader;
|
|
33
|
+
let sessionManager;
|
|
34
|
+
let frameManager = null;
|
|
35
|
+
let db = null;
|
|
36
|
+
function initializeServices() {
|
|
37
|
+
console.log("\u{1F680} Initializing StackMemory Web Server...");
|
|
38
|
+
taskReader = new LinearTaskReader(process.cwd());
|
|
39
|
+
console.log(`\u{1F4CB} TaskReader initialized with ${taskReader.getTasks().length} tasks`);
|
|
40
|
+
sessionManager = new SessionManager({ enableMonitoring: true });
|
|
41
|
+
console.log("\u{1F4CA} SessionManager initialized");
|
|
42
|
+
const dbPath = join(process.cwd(), ".stackmemory", "context.db");
|
|
43
|
+
if (existsSync(dbPath)) {
|
|
44
|
+
try {
|
|
45
|
+
db = new Database(dbPath);
|
|
46
|
+
frameManager = new FrameManager(db, "web");
|
|
47
|
+
console.log("\u{1F4BE} Database and FrameManager initialized");
|
|
48
|
+
} catch (error) {
|
|
49
|
+
console.error("\u274C Failed to initialize database:", error);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
app.get("/api/health", (req, res) => {
|
|
54
|
+
res.json({ status: "ok", timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
55
|
+
});
|
|
56
|
+
app.get("/api/tasks", (req, res) => {
|
|
57
|
+
try {
|
|
58
|
+
const tasks = taskReader.getTasks();
|
|
59
|
+
res.json({ tasks, total: tasks.length });
|
|
60
|
+
} catch (error) {
|
|
61
|
+
res.status(500).json({ error: "Failed to fetch tasks" });
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
app.get("/api/tasks/active", (req, res) => {
|
|
65
|
+
try {
|
|
66
|
+
const tasks = taskReader.getActiveTasks();
|
|
67
|
+
res.json({ tasks, total: tasks.length });
|
|
68
|
+
} catch (error) {
|
|
69
|
+
res.status(500).json({ error: "Failed to fetch active tasks" });
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
app.get("/api/tasks/by-state/:state", (req, res) => {
|
|
73
|
+
try {
|
|
74
|
+
const tasks = taskReader.getTasksByState(req.params.state);
|
|
75
|
+
res.json({ tasks, total: tasks.length });
|
|
76
|
+
} catch (error) {
|
|
77
|
+
res.status(500).json({ error: "Failed to fetch tasks by state" });
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
app.get("/api/sessions", (req, res) => {
|
|
81
|
+
try {
|
|
82
|
+
const sessions = sessionManager?.getActiveSessions ? sessionManager.getActiveSessions() : [];
|
|
83
|
+
res.json({ sessions, total: sessions.length });
|
|
84
|
+
} catch (error) {
|
|
85
|
+
res.status(500).json({ error: "Failed to fetch sessions" });
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
app.get("/api/frames", (req, res) => {
|
|
89
|
+
try {
|
|
90
|
+
if (!frameManager) {
|
|
91
|
+
res.json({ frames: [], total: 0 });
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const frames = frameManager.getAllFrames();
|
|
95
|
+
res.json({ frames, total: frames.length });
|
|
96
|
+
} catch (error) {
|
|
97
|
+
res.status(500).json({ error: "Failed to fetch frames" });
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
app.get("/api/analytics", (req, res) => {
|
|
101
|
+
try {
|
|
102
|
+
const tasks = taskReader.getTasks();
|
|
103
|
+
const sessions = sessionManager?.getActiveSessions ? sessionManager.getActiveSessions() : [];
|
|
104
|
+
const frames = frameManager?.getAllFrames() || [];
|
|
105
|
+
const analytics = {
|
|
106
|
+
summary: {
|
|
107
|
+
totalTasks: tasks.length,
|
|
108
|
+
activeTasks: tasks.filter((t) => t.state === "In Progress").length,
|
|
109
|
+
completedTasks: tasks.filter((t) => t.state === "Done").length,
|
|
110
|
+
totalSessions: sessions.length,
|
|
111
|
+
totalFrames: frames.length
|
|
112
|
+
},
|
|
113
|
+
tasksByState: tasks.reduce((acc, task) => {
|
|
114
|
+
acc[task.state] = (acc[task.state] || 0) + 1;
|
|
115
|
+
return acc;
|
|
116
|
+
}, {}),
|
|
117
|
+
tasksByPriority: tasks.reduce((acc, task) => {
|
|
118
|
+
const priority = task.priority || 4;
|
|
119
|
+
acc[priority] = (acc[priority] || 0) + 1;
|
|
120
|
+
return acc;
|
|
121
|
+
}, {}),
|
|
122
|
+
recentActivity: {
|
|
123
|
+
tasksUpdatedToday: tasks.filter((t) => {
|
|
124
|
+
const updated = new Date(t.updatedAt);
|
|
125
|
+
const today = /* @__PURE__ */ new Date();
|
|
126
|
+
return updated.toDateString() === today.toDateString();
|
|
127
|
+
}).length,
|
|
128
|
+
sessionsToday: sessions.filter((s) => {
|
|
129
|
+
const started = new Date(s.startTime);
|
|
130
|
+
const today = /* @__PURE__ */ new Date();
|
|
131
|
+
return started.toDateString() === today.toDateString();
|
|
132
|
+
}).length
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
res.json(analytics);
|
|
136
|
+
} catch (error) {
|
|
137
|
+
res.status(500).json({ error: "Failed to fetch analytics" });
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
io.on("connection", (socket) => {
|
|
141
|
+
console.log("\u{1F464} Client connected:", socket.id);
|
|
142
|
+
socket.emit("initial-data", {
|
|
143
|
+
tasks: taskReader.getTasks(),
|
|
144
|
+
sessions: sessionManager?.getActiveSessions ? sessionManager.getActiveSessions() : [],
|
|
145
|
+
frames: frameManager?.getAllFrames() || []
|
|
146
|
+
});
|
|
147
|
+
socket.on("refresh-tasks", () => {
|
|
148
|
+
socket.emit("tasks:update", taskReader.getTasks());
|
|
149
|
+
});
|
|
150
|
+
socket.on("refresh-sessions", () => {
|
|
151
|
+
const sessions = sessionManager?.getActiveSessions ? sessionManager.getActiveSessions() : [];
|
|
152
|
+
socket.emit("sessions:update", sessions);
|
|
153
|
+
});
|
|
154
|
+
socket.on("refresh-frames", () => {
|
|
155
|
+
socket.emit("frames:update", frameManager?.getAllFrames() || []);
|
|
156
|
+
});
|
|
157
|
+
socket.on("disconnect", () => {
|
|
158
|
+
console.log("\u{1F44B} Client disconnected:", socket.id);
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
setInterval(() => {
|
|
162
|
+
try {
|
|
163
|
+
io.emit("tasks:update", taskReader.getTasks());
|
|
164
|
+
const sessions = sessionManager?.getActiveSessions ? sessionManager.getActiveSessions() : [];
|
|
165
|
+
io.emit("sessions:update", sessions);
|
|
166
|
+
io.emit("frames:update", frameManager?.getAllFrames() || []);
|
|
167
|
+
} catch (error) {
|
|
168
|
+
console.error("Error in periodic update:", error);
|
|
169
|
+
}
|
|
170
|
+
}, 5e3);
|
|
171
|
+
const PORT = process.env["WS_PORT"] || 8080;
|
|
172
|
+
initializeServices();
|
|
173
|
+
httpServer.listen(PORT, () => {
|
|
174
|
+
console.log(`
|
|
175
|
+
\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
|
|
176
|
+
\u2551 StackMemory Web Dashboard Server \u2551
|
|
177
|
+
\u2551 Running on http://localhost:${PORT} \u2551
|
|
178
|
+
\u2551 WebSocket: ws://localhost:${PORT} \u2551
|
|
179
|
+
\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
|
|
180
|
+
`);
|
|
181
|
+
});
|
|
182
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/features/web/server/index.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * StackMemory Web Dashboard Server\n * Express + Socket.io server for real-time dashboard\n */\n\nimport express from 'express';\nimport { createServer } from 'http';\nimport { Server as SocketServer } from 'socket.io';\nimport cors from 'cors';\nimport { LinearTaskReader } from '../../tui/services/linear-task-reader.js';\nimport { SessionManager } from '../../../core/session/session-manager.js';\nimport { FrameManager } from '../../../core/context/frame-manager.js';\nimport Database from 'better-sqlite3';\nimport { existsSync } from 'fs';\nimport { join } from 'path';\n// Type-safe environment variable access\nfunction getEnv(key: string, defaultValue?: string): string {\n const value = process.env[key];\n if (value === undefined) {\n if (defaultValue !== undefined) return defaultValue;\n throw new Error(`Environment variable ${key} is required`);\n }\n return value;\n}\n\nfunction getOptionalEnv(key: string): string | undefined {\n return process.env[key];\n}\n\n\nconst app = express();\nconst httpServer = createServer(app);\nconst io = new SocketServer(httpServer, {\n cors: {\n origin: process.env['CLIENT_URL'] || 'http://localhost:3000',\n methods: ['GET', 'POST'],\n },\n});\n\n// Middleware\napp.use(cors());\napp.use(express.json());\n\n// Data services\nlet taskReader: LinearTaskReader;\nlet sessionManager: SessionManager;\nlet frameManager: FrameManager | null = null;\nlet db: Database.Database | null = null;\n\n// Initialize services\nfunction initializeServices() {\n console.log('\uD83D\uDE80 Initializing StackMemory Web Server...');\n \n // Initialize task reader\n taskReader = new LinearTaskReader(process.cwd());\n console.log(`\uD83D\uDCCB TaskReader initialized with ${taskReader.getTasks().length} tasks`);\n \n // Initialize session manager\n sessionManager = new SessionManager({ enableMonitoring: true });\n console.log('\uD83D\uDCCA SessionManager initialized');\n \n // Initialize database and frame manager\n const dbPath = join(process.cwd(), '.stackmemory', 'context.db');\n if (existsSync(dbPath)) {\n try {\n db = new Database(dbPath);\n frameManager = new FrameManager(db, 'web');\n console.log('\uD83D\uDCBE Database and FrameManager initialized');\n } catch (error: unknown) {\n console.error('\u274C Failed to initialize database:', error);\n }\n }\n}\n\n// REST API Routes\napp.get('/api/health', (req, res) => {\n res.json({ status: 'ok', timestamp: new Date().toISOString() });\n});\n\napp.get('/api/tasks', (req, res) => {\n try {\n const tasks = taskReader.getTasks();\n res.json({ tasks, total: tasks.length });\n } catch (error: unknown) {\n res.status(500).json({ error: 'Failed to fetch tasks' });\n }\n});\n\napp.get('/api/tasks/active', (req, res) => {\n try {\n const tasks = taskReader.getActiveTasks();\n res.json({ tasks, total: tasks.length });\n } catch (error: unknown) {\n res.status(500).json({ error: 'Failed to fetch active tasks' });\n }\n});\n\napp.get('/api/tasks/by-state/:state', (req, res) => {\n try {\n const tasks = taskReader.getTasksByState(req.params.state);\n res.json({ tasks, total: tasks.length });\n } catch (error: unknown) {\n res.status(500).json({ error: 'Failed to fetch tasks by state' });\n }\n});\n\napp.get('/api/sessions', (req, res) => {\n try {\n const sessions = sessionManager?.getActiveSessions ? sessionManager.getActiveSessions() : [];\n res.json({ sessions, total: sessions.length });\n } catch (error: unknown) {\n res.status(500).json({ error: 'Failed to fetch sessions' });\n }\n});\n\napp.get('/api/frames', (req, res) => {\n try {\n if (!frameManager) {\n res.json({ frames: [], total: 0 });\n return;\n }\n const frames = frameManager.getAllFrames();\n res.json({ frames, total: frames.length });\n } catch (error: unknown) {\n res.status(500).json({ error: 'Failed to fetch frames' });\n }\n});\n\napp.get('/api/analytics', (req, res) => {\n try {\n const tasks = taskReader.getTasks();\n const sessions = sessionManager?.getActiveSessions ? sessionManager.getActiveSessions() : [];\n const frames = frameManager?.getAllFrames() || [];\n \n // Calculate analytics\n const analytics = {\n summary: {\n totalTasks: tasks.length,\n activeTasks: tasks.filter((t: any) => t.state === 'In Progress').length,\n completedTasks: tasks.filter((t: any) => t.state === 'Done').length,\n totalSessions: sessions.length,\n totalFrames: frames.length,\n },\n tasksByState: tasks.reduce((acc, task) => {\n acc[task.state] = (acc[task.state] || 0) + 1;\n return acc;\n }, {} as Record<string, number>),\n tasksByPriority: tasks.reduce((acc, task) => {\n const priority = task.priority || 4;\n acc[priority] = (acc[priority] || 0) + 1;\n return acc;\n }, {} as Record<number, number>),\n recentActivity: {\n tasksUpdatedToday: tasks.filter((t: any) => {\n const updated = new Date(t.updatedAt);\n const today = new Date();\n return updated.toDateString() === today.toDateString();\n }).length,\n sessionsToday: sessions.filter((s: any) => {\n const started = new Date(s.startTime);\n const today = new Date();\n return started.toDateString() === today.toDateString();\n }).length,\n },\n };\n \n res.json(analytics);\n } catch (error: unknown) {\n res.status(500).json({ error: 'Failed to fetch analytics' });\n }\n});\n\n// WebSocket handling\nio.on('connection', (socket) => {\n console.log('\uD83D\uDC64 Client connected:', socket.id);\n \n // Send initial data\n socket.emit('initial-data', {\n tasks: taskReader.getTasks(),\n sessions: sessionManager?.getActiveSessions ? sessionManager.getActiveSessions() : [],\n frames: frameManager?.getAllFrames() || [],\n });\n \n // Handle client requests\n socket.on('refresh-tasks', () => {\n socket.emit('tasks:update', taskReader.getTasks());\n });\n \n socket.on('refresh-sessions', () => {\n const sessions = sessionManager?.getActiveSessions ? sessionManager.getActiveSessions() : [];\n socket.emit('sessions:update', sessions);\n });\n \n socket.on('refresh-frames', () => {\n socket.emit('frames:update', frameManager?.getAllFrames() || []);\n });\n \n socket.on('disconnect', () => {\n console.log('\uD83D\uDC4B Client disconnected:', socket.id);\n });\n});\n\n// Periodic updates (every 5 seconds)\nsetInterval(() => {\n try {\n io.emit('tasks:update', taskReader.getTasks());\n // SessionManager might not have getActiveSessions yet\n const sessions = sessionManager?.getActiveSessions ? sessionManager.getActiveSessions() : [];\n io.emit('sessions:update', sessions);\n io.emit('frames:update', frameManager?.getAllFrames() || []);\n } catch (error: unknown) {\n console.error('Error in periodic update:', error);\n }\n}, 5000);\n\n// Start server\nconst PORT = process.env['WS_PORT'] || 8080;\n\ninitializeServices();\n\nhttpServer.listen(PORT, () => {\n console.log(`\n\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557\n\u2551 StackMemory Web Dashboard Server \u2551\n\u2551 Running on http://localhost:${PORT} \u2551\n\u2551 WebSocket: ws://localhost:${PORT} \u2551\n\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D\n `);\n});"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/integrations/claude-code/enhanced-pre-clear-hooks.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Enhanced Pre-Clear Context Preservation System\n * Comprehensive session state capture before /clear or /compact operations\n */\n\nimport { EventEmitter } from 'events';\nimport { ClearSurvival } from '../../core/session/clear-survival';\nimport { HandoffGenerator } from '../../core/session/handoff-generator';\nimport { FrameManager } from '../../core/frame/frame-manager';\nimport { DatabaseManager } from '../../core/storage/database-manager';\nimport * as fs from 'fs/promises';\nimport * as path from 'path';\nimport { execSync } from 'child_process';\n\nexport interface PreClearContext {\n // Session metadata\n sessionId: string;\n timestamp: string;\n trigger:\n | 'manual_clear'\n | 'auto_compact'\n | 'context_overflow'\n | 'user_request';\n\n // Context analysis\n contextUsage: {\n estimatedTokens: number;\n maxTokens: number;\n percentage: number;\n components: {\n frames: number;\n traces: number;\n conversations: number;\n codeBlocks: number;\n };\n };\n\n // Active work state\n workingState: {\n currentTask: string;\n activeFiles: string[];\n recentCommands: string[];\n pendingActions: string[];\n blockers: string[];\n };\n\n // Conversation state\n conversationState: {\n lastUserMessage: string;\n lastAssistantMessage: string;\n conversationTopic: string;\n messageCount: number;\n recentContext: string[];\n };\n\n // Code context\n codeContext: {\n modifiedFiles: FileContext[];\n gitStatus: GitStatus;\n testResults?: TestResults;\n buildStatus?: BuildStatus;\n dependencies: DependencyInfo[];\n };\n\n // Cognitive state\n cognitiveState: {\n currentFocus: string;\n mentalModel: string[];\n assumptions: string[];\n hypotheses: string[];\n explorationPaths: string[];\n };\n\n // Environment snapshot\n environment: {\n workingDirectory: string;\n gitBranch: string;\n nodeVersion?: string;\n packageJson?: any;\n environmentVars: Record<string, string>;\n };\n}\n\ninterface FileContext {\n path: string;\n lastModified: string;\n changeType: 'created' | 'modified' | 'deleted';\n lineChanges: { added: number; removed: number };\n purpose: string;\n relatedFiles: string[];\n}\n\ninterface GitStatus {\n branch: string;\n ahead: number;\n behind: number;\n staged: string[];\n unstaged: string[];\n untracked: string[];\n lastCommit: {\n hash: string;\n message: string;\n timestamp: string;\n };\n}\n\ninterface TestResults {\n framework: string;\n passed: number;\n failed: number;\n skipped: number;\n coverage?: number;\n failures: string[];\n}\n\ninterface BuildStatus {\n success: boolean;\n errors: string[];\n warnings: string[];\n timestamp: string;\n}\n\ninterface DependencyInfo {\n name: string;\n version: string;\n type: 'dependency' | 'devDependency' | 'global';\n critical: boolean;\n}\n\nexport class EnhancedPreClearHooks extends EventEmitter {\n private frameManager: FrameManager;\n private dbManager: DatabaseManager;\n private clearSurvival: ClearSurvival;\n private handoffGenerator: HandoffGenerator;\n private projectRoot: string;\n\n constructor(\n frameManager: FrameManager,\n dbManager: DatabaseManager,\n clearSurvival: ClearSurvival,\n handoffGenerator: HandoffGenerator,\n projectRoot: string\n ) {\n super();\n this.frameManager = frameManager;\n this.dbManager = dbManager;\n this.clearSurvival = clearSurvival;\n this.handoffGenerator = handoffGenerator;\n this.projectRoot = projectRoot;\n }\n\n /**\n * Comprehensive pre-clear context capture\n */\n async capturePreClearContext(\n trigger: PreClearContext['trigger']\n ): Promise<PreClearContext> {\n console.log('\uD83D\uDD0D Capturing comprehensive session context...');\n\n const context: PreClearContext = {\n sessionId: await this.dbManager.getCurrentSessionId(),\n timestamp: new Date().toISOString(),\n trigger,\n\n contextUsage: await this.analyzeContextUsage(),\n workingState: await this.captureWorkingState(),\n conversationState: await this.captureConversationState(),\n codeContext: await this.captureCodeContext(),\n cognitiveState: await this.captureCognitiveState(),\n environment: await this.captureEnvironment(),\n };\n\n // Save comprehensive context\n await this.saveEnhancedContext(context);\n\n // Emit for other systems to react\n this.emit('context:captured', context);\n\n console.log('\u2705 Comprehensive context captured');\n return context;\n }\n\n /**\n * Analyze current context usage with detailed breakdown\n */\n private async analyzeContextUsage(): Promise<\n PreClearContext['contextUsage']\n > {\n const sessionId = await this.dbManager.getCurrentSessionId();\n const frames = await this.dbManager.getRecentFrames(sessionId, 1000);\n const traces = await this.dbManager.getRecentTraces(sessionId, 1000);\n\n // Estimate token usage by component\n const frameTokens = frames.length * 200; // Average tokens per frame\n const traceTokens = traces.length * 100; // Average tokens per trace\n const conversationTokens = await this.estimateConversationTokens();\n const codeBlockTokens = await this.estimateCodeBlockTokens();\n\n const estimatedTokens =\n frameTokens + traceTokens + conversationTokens + codeBlockTokens;\n const maxTokens = 100000; // Claude's limit\n\n return {\n estimatedTokens,\n maxTokens,\n percentage: estimatedTokens / maxTokens,\n components: {\n frames: frameTokens,\n traces: traceTokens,\n conversations: conversationTokens,\n codeBlocks: codeBlockTokens,\n },\n };\n }\n\n /**\n * Capture current working state\n */\n private async captureWorkingState(): Promise<\n PreClearContext['workingState']\n > {\n const activeFrame = await this.getCurrentActiveFrame();\n const recentTraces = await this.dbManager.getRecentTraces(\n await this.dbManager.getCurrentSessionId(),\n 50\n );\n\n // Extract active files from recent operations\n const activeFiles = this.extractActiveFiles(recentTraces);\n\n // Get recent commands\n const recentCommands = recentTraces\n .filter((t) => t.type === 'bash' || t.type === 'command')\n .map((t) => t.content.command)\n .slice(0, 10);\n\n // Identify pending actions from frame metadata\n const pendingActions = this.extractPendingActions(activeFrame);\n\n // Identify blockers\n const blockers = this.extractBlockers(recentTraces);\n\n return {\n currentTask: activeFrame?.description || 'No active task',\n activeFiles,\n recentCommands,\n pendingActions,\n blockers,\n };\n }\n\n /**\n * Capture conversation state and recent context\n */\n private async captureConversationState(): Promise<\n PreClearContext['conversationState']\n > {\n const sessionId = await this.dbManager.getCurrentSessionId();\n const recentTraces = await this.dbManager.getRecentTraces(sessionId, 100);\n\n // Find last user and assistant messages\n const userMessages = recentTraces\n .filter((t) => t.type === 'user_message' || t.type === 'input')\n .slice(0, 5);\n\n const assistantMessages = recentTraces\n .filter((t) => t.type === 'assistant_message' || t.type === 'response')\n .slice(0, 5);\n\n // Extract conversation topic from recent interactions\n const conversationTopic = this.inferConversationTopic(recentTraces);\n\n // Build recent context summary\n const recentContext = this.buildRecentContextSummary(recentTraces);\n\n return {\n lastUserMessage:\n userMessages[0]?.content.message || 'No recent user message',\n lastAssistantMessage:\n assistantMessages[0]?.content.message || 'No recent assistant message',\n conversationTopic,\n messageCount: userMessages.length + assistantMessages.length,\n recentContext,\n };\n }\n\n /**\n * Capture comprehensive code context\n */\n private async captureCodeContext(): Promise<PreClearContext['codeContext']> {\n const gitStatus = await this.captureGitStatus();\n const modifiedFiles = await this.captureModifiedFiles();\n const testResults = await this.captureTestResults();\n const buildStatus = await this.captureBuildStatus();\n const dependencies = await this.captureDependencies();\n\n return {\n modifiedFiles,\n gitStatus,\n testResults,\n buildStatus,\n dependencies,\n };\n }\n\n /**\n * Capture cognitive state and mental model\n */\n private async captureCognitiveState(): Promise<\n PreClearContext['cognitiveState']\n > {\n const sessionId = await this.dbManager.getCurrentSessionId();\n const recentTraces = await this.dbManager.getRecentTraces(sessionId, 100);\n\n // Extract cognitive elements from traces and frames\n const currentFocus = await this.extractCurrentFocus();\n const mentalModel = this.extractMentalModel(recentTraces);\n const assumptions = this.extractAssumptions(recentTraces);\n const hypotheses = this.extractHypotheses(recentTraces);\n const explorationPaths = this.extractExplorationPaths(recentTraces);\n\n return {\n currentFocus,\n mentalModel,\n assumptions,\n hypotheses,\n explorationPaths,\n };\n }\n\n /**\n * Capture environment snapshot\n */\n private async captureEnvironment(): Promise<PreClearContext['environment']> {\n const gitBranch = await this.getCurrentGitBranch();\n const packageJson = await this.getPackageJson();\n const environmentVars = this.getRelevantEnvVars();\n\n return {\n workingDirectory: this.projectRoot,\n gitBranch,\n nodeVersion: process.version,\n packageJson,\n environmentVars,\n };\n }\n\n /**\n * Save enhanced context to multiple locations for reliability\n */\n private async saveEnhancedContext(context: PreClearContext): Promise<void> {\n const timestamp = context.timestamp.replace(/[:.]/g, '-');\n\n // Save to primary location\n const primaryPath = path.join(\n this.projectRoot,\n '.stackmemory',\n 'pre-clear',\n `context-${timestamp}.json`\n );\n\n // Save to backup location\n const backupPath = path.join(\n this.projectRoot,\n '.stackmemory',\n 'pre-clear',\n 'latest-context.json'\n );\n\n // Create markdown summary\n const markdownPath = path.join(\n this.projectRoot,\n '.stackmemory',\n 'pre-clear',\n `context-${timestamp}.md`\n );\n\n await fs.mkdir(path.dirname(primaryPath), { recursive: true });\n\n // Save JSON\n await fs.writeFile(primaryPath, JSON.stringify(context, null, 2), 'utf-8');\n await fs.writeFile(backupPath, JSON.stringify(context, null, 2), 'utf-8');\n\n // Save markdown summary\n const markdown = this.generateMarkdownSummary(context);\n await fs.writeFile(markdownPath, markdown, 'utf-8');\n\n console.log(\n `\uD83D\uDCC1 Context saved to ${path.relative(this.projectRoot, primaryPath)}`\n );\n }\n\n /**\n * Generate human-readable markdown summary\n */\n private generateMarkdownSummary(context: PreClearContext): string {\n const lines = [\n `# Pre-Clear Context Snapshot`,\n `**Timestamp**: ${new Date(context.timestamp).toLocaleString()}`,\n `**Trigger**: ${context.trigger}`,\n `**Session ID**: ${context.sessionId}`,\n '',\n\n `## \uD83D\uDCCA Context Usage`,\n `- **Total Tokens**: ${context.contextUsage.estimatedTokens.toLocaleString()} / ${context.contextUsage.maxTokens.toLocaleString()} (${Math.round(context.contextUsage.percentage * 100)}%)`,\n `- **Frames**: ${context.contextUsage.components.frames} tokens`,\n `- **Traces**: ${context.contextUsage.components.traces} tokens`,\n `- **Conversations**: ${context.contextUsage.components.conversations} tokens`,\n `- **Code Blocks**: ${context.contextUsage.components.codeBlocks} tokens`,\n '',\n\n `## \uD83C\uDFAF Current Work State`,\n `**Task**: ${context.workingState.currentTask}`,\n `**Active Files** (${context.workingState.activeFiles.length}):`,\n ...context.workingState.activeFiles.slice(0, 10).map((f) => `- ${f}`),\n '',\n `**Recent Commands**:`,\n ...context.workingState.recentCommands\n .slice(0, 5)\n .map((c) => `- \\`${c}\\``),\n '',\n\n `## \uD83D\uDCAC Conversation State`,\n `**Topic**: ${context.conversationState.conversationTopic}`,\n `**Messages**: ${context.conversationState.messageCount}`,\n `**Last User**: ${context.conversationState.lastUserMessage.substring(0, 100)}...`,\n '',\n\n `## \uD83D\uDCDD Code Context`,\n `**Git Branch**: ${context.codeContext.gitStatus.branch}`,\n `**Modified Files**: ${context.codeContext.modifiedFiles.length}`,\n `**Staged**: ${context.codeContext.gitStatus.staged.length}`,\n `**Unstaged**: ${context.codeContext.gitStatus.unstaged.length}`,\n '',\n\n `## \uD83E\uDDE0 Cognitive State`,\n `**Current Focus**: ${context.cognitiveState.currentFocus}`,\n `**Mental Model**:`,\n ...context.cognitiveState.mentalModel.slice(0, 5).map((m) => `- ${m}`),\n '',\n\n `## \uD83C\uDF0D Environment`,\n `**Directory**: ${context.environment.workingDirectory}`,\n `**Node Version**: ${context.environment.nodeVersion}`,\n `**Git Branch**: ${context.environment.gitBranch}`,\n '',\n ];\n\n return lines.filter((l) => l !== undefined).join('\\n');\n }\n\n // Helper methods (simplified implementations)\n\n private async estimateConversationTokens(): Promise<number> {\n // Simplified - would analyze recent conversation history\n return 15000;\n }\n\n private async estimateCodeBlockTokens(): Promise<number> {\n // Simplified - would analyze code blocks in context\n return 8000;\n }\n\n private async getCurrentActiveFrame(): Promise<any> {\n const stack = await this.frameManager.getStack();\n return stack.frames.find((f) => f.status === 'open');\n }\n\n private extractActiveFiles(traces: any[]): string[] {\n const files = new Set<string>();\n traces.forEach((trace) => {\n if (trace.content?.file_path) files.add(trace.content.file_path);\n if (trace.content?.path) files.add(trace.content.path);\n });\n return Array.from(files).slice(0, 20);\n }\n\n private extractPendingActions(frame: any): string[] {\n if (!frame?.metadata?.pendingActions) return [];\n return frame.metadata.pendingActions;\n }\n\n private extractBlockers(traces: any[]): string[] {\n return traces\n .filter((t) => t.type === 'error' && !t.metadata?.resolved)\n .map((t) => t.content.error || 'Unknown error')\n .slice(0, 5);\n }\n\n private inferConversationTopic(traces: any[]): string {\n // Simplified - would use NLP to infer topic\n return 'Code implementation and debugging';\n }\n\n private buildRecentContextSummary(traces: any[]): string[] {\n return traces\n .slice(0, 10)\n .map(\n (t) =>\n `${t.type}: ${t.content.summary || t.content.description || 'No description'}`\n )\n .filter((s) => s.length > 10);\n }\n\n private async captureGitStatus(): Promise<GitStatus> {\n try {\n const branch = execSync('git branch --show-current', {\n encoding: 'utf-8',\n cwd: this.projectRoot,\n }).trim();\n const staged = execSync('git diff --cached --name-only', {\n encoding: 'utf-8',\n cwd: this.projectRoot,\n })\n .trim()\n .split('\\n')\n .filter(Boolean);\n const unstaged = execSync('git diff --name-only', {\n encoding: 'utf-8',\n cwd: this.projectRoot,\n })\n .trim()\n .split('\\n')\n .filter(Boolean);\n const untracked = execSync('git ls-files --others --exclude-standard', {\n encoding: 'utf-8',\n cwd: this.projectRoot,\n })\n .trim()\n .split('\\n')\n .filter(Boolean);\n\n return {\n branch,\n ahead: 0, // Would implement git status parsing\n behind: 0,\n staged,\n unstaged,\n untracked,\n lastCommit: {\n hash: 'abc123', // Would get from git log\n message: 'Recent commit',\n timestamp: new Date().toISOString(),\n },\n };\n } catch (error) {\n return {\n branch: 'unknown',\n ahead: 0,\n behind: 0,\n staged: [],\n unstaged: [],\n untracked: [],\n lastCommit: { hash: '', message: '', timestamp: '' },\n };\n }\n }\n\n private async captureModifiedFiles(): Promise<FileContext[]> {\n try {\n const output = execSync('git diff --name-status', {\n encoding: 'utf-8',\n cwd: this.projectRoot,\n });\n return output\n .trim()\n .split('\\n')\n .filter(Boolean)\n .map((line) => {\n const [status, path] = line.split('\\t');\n return {\n path,\n lastModified: new Date().toISOString(),\n changeType:\n status === 'A'\n ? 'created'\n : status === 'D'\n ? 'deleted'\n : 'modified',\n lineChanges: { added: 0, removed: 0 }, // Would get from git diff --stat\n purpose: 'Code changes',\n relatedFiles: [],\n };\n });\n } catch (error) {\n return [];\n }\n }\n\n private async captureTestResults(): Promise<TestResults | undefined> {\n // Would implement test result parsing\n return undefined;\n }\n\n private async captureBuildStatus(): Promise<BuildStatus | undefined> {\n // Would implement build status checking\n return undefined;\n }\n\n private async captureDependencies(): Promise<DependencyInfo[]> {\n try {\n const packageJsonPath = path.join(this.projectRoot, 'package.json');\n const content = await fs.readFile(packageJsonPath, 'utf-8');\n const packageJson = JSON.parse(content);\n\n const deps: DependencyInfo[] = [];\n\n Object.entries(packageJson.dependencies || {}).forEach(\n ([name, version]) => {\n deps.push({\n name,\n version: version as string,\n type: 'dependency',\n critical: ['react', 'express', 'next'].includes(name),\n });\n }\n );\n\n return deps;\n } catch (error) {\n return [];\n }\n }\n\n private async extractCurrentFocus(): Promise<string> {\n const activeFrame = await this.getCurrentActiveFrame();\n return activeFrame?.description || 'No current focus';\n }\n\n private extractMentalModel(traces: any[]): string[] {\n // Would extract mental model concepts from traces\n return [\n 'Component architecture',\n 'Data flow patterns',\n 'Error handling strategy',\n ];\n }\n\n private extractAssumptions(traces: any[]): string[] {\n // Would extract assumptions from traces\n return [\n 'User input is validated',\n 'Database is available',\n 'Network is stable',\n ];\n }\n\n private extractHypotheses(traces: any[]): string[] {\n // Would extract hypotheses being tested\n return [\n 'Bug is in validation logic',\n 'Performance issue is database-related',\n ];\n }\n\n private extractExplorationPaths(traces: any[]): string[] {\n // Would extract different approaches being explored\n return [\n 'Try different algorithm',\n 'Refactor data structure',\n 'Add caching layer',\n ];\n }\n\n private async getCurrentGitBranch(): Promise<string> {\n try {\n return execSync('git branch --show-current', {\n encoding: 'utf-8',\n cwd: this.projectRoot,\n }).trim();\n } catch (error) {\n return 'unknown';\n }\n }\n\n private async getPackageJson(): Promise<any> {\n try {\n const content = await fs.readFile(\n path.join(this.projectRoot, 'package.json'),\n 'utf-8'\n );\n return JSON.parse(content);\n } catch (error) {\n return null;\n }\n }\n\n private getRelevantEnvVars(): Record<string, string> {\n const relevantVars = ['NODE_ENV', 'DEBUG', 'PORT', 'DATABASE_URL'];\n const result: Record<string, string> = {};\n\n relevantVars.forEach((varName) => {\n if (process.env[varName]) {\n result[varName] = process.env[varName]!;\n }\n });\n\n return result;\n }\n\n /**\n * Restore context after /clear\n */\n async restoreFromEnhancedContext(): Promise<boolean> {\n const latestPath = path.join(\n this.projectRoot,\n '.stackmemory',\n 'pre-clear',\n 'latest-context.json'\n );\n\n try {\n const content = await fs.readFile(latestPath, 'utf-8');\n const context: PreClearContext = JSON.parse(content);\n\n console.log('\uD83D\uDCDA Restoring enhanced context...');\n console.log(` Session: ${context.sessionId}`);\n console.log(` Task: ${context.workingState.currentTask}`);\n console.log(` Files: ${context.workingState.activeFiles.length}`);\n console.log(` Focus: ${context.cognitiveState.currentFocus}`);\n\n // Restore using existing systems\n await this.clearSurvival.restoreFromLedger();\n\n // Additional restoration logic would go here\n\n return true;\n } catch (error) {\n console.error('Failed to restore enhanced context:', error);\n return false;\n }\n }\n}\n"],
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["/**\n * Enhanced Pre-Clear Context Preservation System\n * Comprehensive session state capture before /clear or /compact operations\n */\n\nimport { EventEmitter } from 'events';\nimport { ClearSurvival } from '../../core/session/clear-survival';\nimport { HandoffGenerator } from '../../core/session/handoff-generator';\nimport { FrameManager } from '../../core/frame/frame-manager';\nimport { DatabaseManager } from '../../core/storage/database-manager';\nimport * as fs from 'fs/promises';\nimport * as path from 'path';\nimport { execSync } from 'child_process';\n\nexport interface PreClearContext {\n // Session metadata\n sessionId: string;\n timestamp: string;\n trigger:\n | 'manual_clear'\n | 'auto_compact'\n | 'context_overflow'\n | 'user_request';\n\n // Context analysis\n contextUsage: {\n estimatedTokens: number;\n maxTokens: number;\n percentage: number;\n components: {\n frames: number;\n traces: number;\n conversations: number;\n codeBlocks: number;\n };\n };\n\n // Active work state\n workingState: {\n currentTask: string;\n activeFiles: string[];\n recentCommands: string[];\n pendingActions: string[];\n blockers: string[];\n };\n\n // Conversation state\n conversationState: {\n lastUserMessage: string;\n lastAssistantMessage: string;\n conversationTopic: string;\n messageCount: number;\n recentContext: string[];\n };\n\n // Code context\n codeContext: {\n modifiedFiles: FileContext[];\n gitStatus: GitStatus;\n testResults?: TestResults;\n buildStatus?: BuildStatus;\n dependencies: DependencyInfo[];\n };\n\n // Cognitive state\n cognitiveState: {\n currentFocus: string;\n mentalModel: string[];\n assumptions: string[];\n hypotheses: string[];\n explorationPaths: string[];\n };\n\n // Environment snapshot\n environment: {\n workingDirectory: string;\n gitBranch: string;\n nodeVersion?: string;\n packageJson?: any;\n environmentVars: Record<string, string>;\n };\n}\n\ninterface FileContext {\n path: string;\n lastModified: string;\n changeType: 'created' | 'modified' | 'deleted';\n lineChanges: { added: number; removed: number };\n purpose: string;\n relatedFiles: string[];\n}\n\ninterface GitStatus {\n branch: string;\n ahead: number;\n behind: number;\n staged: string[];\n unstaged: string[];\n untracked: string[];\n lastCommit: {\n hash: string;\n message: string;\n timestamp: string;\n };\n}\n\ninterface TestResults {\n framework: string;\n passed: number;\n failed: number;\n skipped: number;\n coverage?: number;\n failures: string[];\n}\n\ninterface BuildStatus {\n success: boolean;\n errors: string[];\n warnings: string[];\n timestamp: string;\n}\n\ninterface DependencyInfo {\n name: string;\n version: string;\n type: 'dependency' | 'devDependency' | 'global';\n critical: boolean;\n}\n\nexport class EnhancedPreClearHooks extends EventEmitter {\n private frameManager: FrameManager;\n private dbManager: DatabaseManager;\n private clearSurvival: ClearSurvival;\n private handoffGenerator: HandoffGenerator;\n private projectRoot: string;\n\n constructor(\n frameManager: FrameManager,\n dbManager: DatabaseManager,\n clearSurvival: ClearSurvival,\n handoffGenerator: HandoffGenerator,\n projectRoot: string\n ) {\n super();\n this.frameManager = frameManager;\n this.dbManager = dbManager;\n this.clearSurvival = clearSurvival;\n this.handoffGenerator = handoffGenerator;\n this.projectRoot = projectRoot;\n }\n\n /**\n * Comprehensive pre-clear context capture\n */\n async capturePreClearContext(\n trigger: PreClearContext['trigger']\n ): Promise<PreClearContext> {\n console.log('\uD83D\uDD0D Capturing comprehensive session context...');\n\n const context: PreClearContext = {\n sessionId: await this.dbManager.getCurrentSessionId(),\n timestamp: new Date().toISOString(),\n trigger,\n\n contextUsage: await this.analyzeContextUsage(),\n workingState: await this.captureWorkingState(),\n conversationState: await this.captureConversationState(),\n codeContext: await this.captureCodeContext(),\n cognitiveState: await this.captureCognitiveState(),\n environment: await this.captureEnvironment(),\n };\n\n // Save comprehensive context\n await this.saveEnhancedContext(context);\n\n // Emit for other systems to react\n this.emit('context:captured', context);\n\n console.log('\u2705 Comprehensive context captured');\n return context;\n }\n\n /**\n * Analyze current context usage with detailed breakdown\n */\n private async analyzeContextUsage(): Promise<\n PreClearContext['contextUsage']\n > {\n const sessionId = await this.dbManager.getCurrentSessionId();\n const frames = await this.dbManager.getRecentFrames(sessionId, 1000);\n const traces = await this.dbManager.getRecentTraces(sessionId, 1000);\n\n // Estimate token usage by component\n const frameTokens = frames.length * 200; // Average tokens per frame\n const traceTokens = traces.length * 100; // Average tokens per trace\n const conversationTokens = await this.estimateConversationTokens();\n const codeBlockTokens = await this.estimateCodeBlockTokens();\n\n const estimatedTokens =\n frameTokens + traceTokens + conversationTokens + codeBlockTokens;\n const maxTokens = 100000; // Claude's limit\n\n return {\n estimatedTokens,\n maxTokens,\n percentage: estimatedTokens / maxTokens,\n components: {\n frames: frameTokens,\n traces: traceTokens,\n conversations: conversationTokens,\n codeBlocks: codeBlockTokens,\n },\n };\n }\n\n /**\n * Capture current working state\n */\n private async captureWorkingState(): Promise<\n PreClearContext['workingState']\n > {\n const activeFrame = await this.getCurrentActiveFrame();\n const recentTraces = await this.dbManager.getRecentTraces(\n await this.dbManager.getCurrentSessionId(),\n 50\n );\n\n // Extract active files from recent operations\n const activeFiles = this.extractActiveFiles(recentTraces);\n\n // Get recent commands\n const recentCommands = recentTraces\n .filter((t) => t.type === 'bash' || t.type === 'command')\n .map((t) => t.content.command)\n .slice(0, 10);\n\n // Identify pending actions from frame metadata\n const pendingActions = this.extractPendingActions(activeFrame);\n\n // Identify blockers\n const blockers = this.extractBlockers(recentTraces);\n\n return {\n currentTask: activeFrame?.description || 'No active task',\n activeFiles,\n recentCommands,\n pendingActions,\n blockers,\n };\n }\n\n /**\n * Capture conversation state and recent context\n */\n private async captureConversationState(): Promise<\n PreClearContext['conversationState']\n > {\n const sessionId = await this.dbManager.getCurrentSessionId();\n const recentTraces = await this.dbManager.getRecentTraces(sessionId, 100);\n\n // Find last user and assistant messages\n const userMessages = recentTraces\n .filter((t) => t.type === 'user_message' || t.type === 'input')\n .slice(0, 5);\n\n const assistantMessages = recentTraces\n .filter((t) => t.type === 'assistant_message' || t.type === 'response')\n .slice(0, 5);\n\n // Extract conversation topic from recent interactions\n const conversationTopic = this.inferConversationTopic(recentTraces);\n\n // Build recent context summary\n const recentContext = this.buildRecentContextSummary(recentTraces);\n\n return {\n lastUserMessage:\n userMessages[0]?.content.message || 'No recent user message',\n lastAssistantMessage:\n assistantMessages[0]?.content.message || 'No recent assistant message',\n conversationTopic,\n messageCount: userMessages.length + assistantMessages.length,\n recentContext,\n };\n }\n\n /**\n * Capture comprehensive code context\n */\n private async captureCodeContext(): Promise<PreClearContext['codeContext']> {\n const gitStatus = await this.captureGitStatus();\n const modifiedFiles = await this.captureModifiedFiles();\n const testResults = await this.captureTestResults();\n const buildStatus = await this.captureBuildStatus();\n const dependencies = await this.captureDependencies();\n\n return {\n modifiedFiles,\n gitStatus,\n testResults,\n buildStatus,\n dependencies,\n };\n }\n\n /**\n * Capture cognitive state and mental model\n */\n private async captureCognitiveState(): Promise<\n PreClearContext['cognitiveState']\n > {\n const sessionId = await this.dbManager.getCurrentSessionId();\n const recentTraces = await this.dbManager.getRecentTraces(sessionId, 100);\n\n // Extract cognitive elements from traces and frames\n const currentFocus = await this.extractCurrentFocus();\n const mentalModel = this.extractMentalModel(recentTraces);\n const assumptions = this.extractAssumptions(recentTraces);\n const hypotheses = this.extractHypotheses(recentTraces);\n const explorationPaths = this.extractExplorationPaths(recentTraces);\n\n return {\n currentFocus,\n mentalModel,\n assumptions,\n hypotheses,\n explorationPaths,\n };\n }\n\n /**\n * Capture environment snapshot\n */\n private async captureEnvironment(): Promise<PreClearContext['environment']> {\n const gitBranch = await this.getCurrentGitBranch();\n const packageJson = await this.getPackageJson();\n const environmentVars = this.getRelevantEnvVars();\n\n return {\n workingDirectory: this.projectRoot,\n gitBranch,\n nodeVersion: process.version,\n packageJson,\n environmentVars,\n };\n }\n\n /**\n * Save enhanced context to multiple locations for reliability\n */\n private async saveEnhancedContext(context: PreClearContext): Promise<void> {\n const timestamp = context.timestamp.replace(/[:.]/g, '-');\n\n // Save to primary location\n const primaryPath = path.join(\n this.projectRoot,\n '.stackmemory',\n 'pre-clear',\n `context-${timestamp}.json`\n );\n\n // Save to backup location\n const backupPath = path.join(\n this.projectRoot,\n '.stackmemory',\n 'pre-clear',\n 'latest-context.json'\n );\n\n // Create markdown summary\n const markdownPath = path.join(\n this.projectRoot,\n '.stackmemory',\n 'pre-clear',\n `context-${timestamp}.md`\n );\n\n await fs.mkdir(path.dirname(primaryPath), { recursive: true });\n\n // Save JSON\n await fs.writeFile(primaryPath, JSON.stringify(context, null, 2), 'utf-8');\n await fs.writeFile(backupPath, JSON.stringify(context, null, 2), 'utf-8');\n\n // Save markdown summary\n const markdown = this.generateMarkdownSummary(context);\n await fs.writeFile(markdownPath, markdown, 'utf-8');\n\n console.log(\n `\uD83D\uDCC1 Context saved to ${path.relative(this.projectRoot, primaryPath)}`\n );\n }\n\n /**\n * Generate human-readable markdown summary\n */\n private generateMarkdownSummary(context: PreClearContext): string {\n const lines = [\n `# Pre-Clear Context Snapshot`,\n `**Timestamp**: ${new Date(context.timestamp).toLocaleString()}`,\n `**Trigger**: ${context.trigger}`,\n `**Session ID**: ${context.sessionId}`,\n '',\n\n `## \uD83D\uDCCA Context Usage`,\n `- **Total Tokens**: ${context.contextUsage.estimatedTokens.toLocaleString()} / ${context.contextUsage.maxTokens.toLocaleString()} (${Math.round(context.contextUsage.percentage * 100)}%)`,\n `- **Frames**: ${context.contextUsage.components.frames} tokens`,\n `- **Traces**: ${context.contextUsage.components.traces} tokens`,\n `- **Conversations**: ${context.contextUsage.components.conversations} tokens`,\n `- **Code Blocks**: ${context.contextUsage.components.codeBlocks} tokens`,\n '',\n\n `## \uD83C\uDFAF Current Work State`,\n `**Task**: ${context.workingState.currentTask}`,\n `**Active Files** (${context.workingState.activeFiles.length}):`,\n ...context.workingState.activeFiles.slice(0, 10).map((f) => `- ${f}`),\n '',\n `**Recent Commands**:`,\n ...context.workingState.recentCommands\n .slice(0, 5)\n .map((c) => `- \\`${c}\\``),\n '',\n\n `## \uD83D\uDCAC Conversation State`,\n `**Topic**: ${context.conversationState.conversationTopic}`,\n `**Messages**: ${context.conversationState.messageCount}`,\n `**Last User**: ${context.conversationState.lastUserMessage.substring(0, 100)}...`,\n '',\n\n `## \uD83D\uDCDD Code Context`,\n `**Git Branch**: ${context.codeContext.gitStatus.branch}`,\n `**Modified Files**: ${context.codeContext.modifiedFiles.length}`,\n `**Staged**: ${context.codeContext.gitStatus.staged.length}`,\n `**Unstaged**: ${context.codeContext.gitStatus.unstaged.length}`,\n '',\n\n `## \uD83E\uDDE0 Cognitive State`,\n `**Current Focus**: ${context.cognitiveState.currentFocus}`,\n `**Mental Model**:`,\n ...context.cognitiveState.mentalModel.slice(0, 5).map((m) => `- ${m}`),\n '',\n\n `## \uD83C\uDF0D Environment`,\n `**Directory**: ${context.environment.workingDirectory}`,\n `**Node Version**: ${context.environment.nodeVersion}`,\n `**Git Branch**: ${context.environment.gitBranch}`,\n '',\n ];\n\n return lines.filter((l) => l !== undefined).join('\\n');\n }\n\n // Helper methods (simplified implementations)\n\n private async estimateConversationTokens(): Promise<number> {\n // Simplified - would analyze recent conversation history\n return 15000;\n }\n\n private async estimateCodeBlockTokens(): Promise<number> {\n // Simplified - would analyze code blocks in context\n return 8000;\n }\n\n private async getCurrentActiveFrame(): Promise<any> {\n const stack = await this.frameManager.getStack();\n return stack.frames.find((f) => f.status === 'open');\n }\n\n private extractActiveFiles(traces: any[]): string[] {\n const files = new Set<string>();\n traces.forEach((trace) => {\n if (trace.content?.file_path) files.add(trace.content.file_path);\n if (trace.content?.path) files.add(trace.content.path);\n });\n return Array.from(files).slice(0, 20);\n }\n\n private extractPendingActions(frame: any): string[] {\n if (!frame?.metadata?.pendingActions) return [];\n return frame.metadata.pendingActions;\n }\n\n private extractBlockers(traces: any[]): string[] {\n return traces\n .filter((t) => t.type === 'error' && !t.metadata?.resolved)\n .map((t) => t.content.error || 'Unknown error')\n .slice(0, 5);\n }\n\n private inferConversationTopic(traces: any[]): string {\n // Simplified - would use NLP to infer topic\n return 'Code implementation and debugging';\n }\n\n private buildRecentContextSummary(traces: any[]): string[] {\n return traces\n .slice(0, 10)\n .map(\n (t) =>\n `${t.type}: ${t.content.summary || t.content.description || 'No description'}`\n )\n .filter((s) => s.length > 10);\n }\n\n private async captureGitStatus(): Promise<GitStatus> {\n try {\n const branch = execSync('git branch --show-current', {\n encoding: 'utf-8',\n cwd: this.projectRoot,\n }).trim();\n const staged = execSync('git diff --cached --name-only', {\n encoding: 'utf-8',\n cwd: this.projectRoot,\n })\n .trim()\n .split('\\n')\n .filter(Boolean);\n const unstaged = execSync('git diff --name-only', {\n encoding: 'utf-8',\n cwd: this.projectRoot,\n })\n .trim()\n .split('\\n')\n .filter(Boolean);\n const untracked = execSync('git ls-files --others --exclude-standard', {\n encoding: 'utf-8',\n cwd: this.projectRoot,\n })\n .trim()\n .split('\\n')\n .filter(Boolean);\n\n return {\n branch,\n ahead: 0, // Would implement git status parsing\n behind: 0,\n staged,\n unstaged,\n untracked,\n lastCommit: {\n hash: 'abc123', // Would get from git log\n message: 'Recent commit',\n timestamp: new Date().toISOString(),\n },\n };\n } catch (error: unknown) {\n return {\n branch: 'unknown',\n ahead: 0,\n behind: 0,\n staged: [],\n unstaged: [],\n untracked: [],\n lastCommit: { hash: '', message: '', timestamp: '' },\n };\n }\n }\n\n private async captureModifiedFiles(): Promise<FileContext[]> {\n try {\n const output = execSync('git diff --name-status', {\n encoding: 'utf-8',\n cwd: this.projectRoot,\n });\n return output\n .trim()\n .split('\\n')\n .filter(Boolean)\n .map((line) => {\n const [status, path] = line.split('\\t');\n return {\n path,\n lastModified: new Date().toISOString(),\n changeType:\n status === 'A'\n ? 'created'\n : status === 'D'\n ? 'deleted'\n : 'modified',\n lineChanges: { added: 0, removed: 0 }, // Would get from git diff --stat\n purpose: 'Code changes',\n relatedFiles: [],\n };\n });\n } catch (error: unknown) {\n return [];\n }\n }\n\n private async captureTestResults(): Promise<TestResults | undefined> {\n // Would implement test result parsing\n return undefined;\n }\n\n private async captureBuildStatus(): Promise<BuildStatus | undefined> {\n // Would implement build status checking\n return undefined;\n }\n\n private async captureDependencies(): Promise<DependencyInfo[]> {\n try {\n const packageJsonPath = path.join(this.projectRoot, 'package.json');\n const content = await fs.readFile(packageJsonPath, 'utf-8');\n const packageJson = JSON.parse(content);\n\n const deps: DependencyInfo[] = [];\n\n Object.entries(packageJson.dependencies || {}).forEach(\n ([name, version]) => {\n deps.push({\n name,\n version: version as string,\n type: 'dependency',\n critical: ['react', 'express', 'next'].includes(name),\n });\n }\n );\n\n return deps;\n } catch (error: unknown) {\n return [];\n }\n }\n\n private async extractCurrentFocus(): Promise<string> {\n const activeFrame = await this.getCurrentActiveFrame();\n return activeFrame?.description || 'No current focus';\n }\n\n private extractMentalModel(traces: any[]): string[] {\n // Would extract mental model concepts from traces\n return [\n 'Component architecture',\n 'Data flow patterns',\n 'Error handling strategy',\n ];\n }\n\n private extractAssumptions(traces: any[]): string[] {\n // Would extract assumptions from traces\n return [\n 'User input is validated',\n 'Database is available',\n 'Network is stable',\n ];\n }\n\n private extractHypotheses(traces: any[]): string[] {\n // Would extract hypotheses being tested\n return [\n 'Bug is in validation logic',\n 'Performance issue is database-related',\n ];\n }\n\n private extractExplorationPaths(traces: any[]): string[] {\n // Would extract different approaches being explored\n return [\n 'Try different algorithm',\n 'Refactor data structure',\n 'Add caching layer',\n ];\n }\n\n private async getCurrentGitBranch(): Promise<string> {\n try {\n return execSync('git branch --show-current', {\n encoding: 'utf-8',\n cwd: this.projectRoot,\n }).trim();\n } catch (error: unknown) {\n return 'unknown';\n }\n }\n\n private async getPackageJson(): Promise<any> {\n try {\n const content = await fs.readFile(\n path.join(this.projectRoot, 'package.json'),\n 'utf-8'\n );\n return JSON.parse(content);\n } catch (error: unknown) {\n return null;\n }\n }\n\n private getRelevantEnvVars(): Record<string, string> {\n const relevantVars = ['NODE_ENV', 'DEBUG', 'PORT', 'DATABASE_URL'];\n const result: Record<string, string> = {};\n\n relevantVars.forEach((varName) => {\n if (process.env[varName]) {\n result[varName] = process.env[varName]!;\n }\n });\n\n return result;\n }\n\n /**\n * Restore context after /clear\n */\n async restoreFromEnhancedContext(): Promise<boolean> {\n const latestPath = path.join(\n this.projectRoot,\n '.stackmemory',\n 'pre-clear',\n 'latest-context.json'\n );\n\n try {\n const content = await fs.readFile(latestPath, 'utf-8');\n const context: PreClearContext = JSON.parse(content);\n\n console.log('\uD83D\uDCDA Restoring enhanced context...');\n console.log(` Session: ${context.sessionId}`);\n console.log(` Task: ${context.workingState.currentTask}`);\n console.log(` Files: ${context.workingState.activeFiles.length}`);\n console.log(` Focus: ${context.cognitiveState.currentFocus}`);\n\n // Restore using existing systems\n await this.clearSurvival.restoreFromLedger();\n\n // Additional restoration logic would go here\n\n return true;\n } catch (error: unknown) {\n console.error('Failed to restore enhanced context:', error);\n return false;\n }\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["path"]
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/integrations/claude-code/lifecycle-hooks.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Claude Code Lifecycle Hooks for StackMemory\n * Integrates with Claude Code's session lifecycle\n */\n\nimport { SessionMonitor } from '../../core/monitoring/session-monitor';\nimport { FrameManager } from '../../core/frame/frame-manager';\nimport { DatabaseManager } from '../../core/storage/database-manager';\nimport * as fs from 'fs/promises';\nimport * as path from 'path';\nimport * as os from 'os';\n\nexport interface ClaudeCodeHookConfig {\n projectRoot: string;\n autoTriggers: {\n onContextHigh: boolean; // Auto-save at 70%\n onContextCritical: boolean; // Force-save at 85%\n onSessionIdle: boolean; // Handoff on 5min idle\n onSessionEnd: boolean; // Handoff on close\n onClearCommand: boolean; // Save before /clear\n };\n claudeHooksPath?: string; // Path to .claude/hooks\n}\n\nexport class ClaudeCodeLifecycleHooks {\n private monitor?: SessionMonitor;\n private config: ClaudeCodeHookConfig;\n private isActive: boolean = false;\n private hookScripts: Map<string, string> = new Map();\n\n constructor(config: ClaudeCodeHookConfig) {\n this.config = {\n ...config,\n claudeHooksPath:\n config.claudeHooksPath || path.join(os.homedir(), '.claude', 'hooks'),\n };\n }\n\n /**\n * Initialize hooks and start monitoring\n */\n async initialize(): Promise<void> {\n if (this.isActive) return;\n\n // Initialize database and managers\n const dbPath = path.join(\n this.config.projectRoot,\n '.stackmemory',\n 'db',\n 'stackmemory.db'\n );\n const dbManager = new DatabaseManager(dbPath);\n await dbManager.initialize();\n\n const frameManager = new FrameManager(dbManager);\n\n // Create session monitor\n this.monitor = new SessionMonitor(\n frameManager,\n dbManager,\n this.config.projectRoot,\n {\n contextWarningThreshold: 0.6,\n contextCriticalThreshold: 0.7,\n contextAutoSaveThreshold: 0.85,\n idleTimeoutMinutes: 5,\n autoSaveLedger: this.config.autoTriggers.onContextCritical,\n autoGenerateHandoff: this.config.autoTriggers.onSessionIdle,\n sessionEndHandoff: this.config.autoTriggers.onSessionEnd,\n }\n );\n\n // Register event handlers\n this.registerEventHandlers();\n\n // Install Claude Code hooks\n await this.installClaudeHooks();\n\n // Start monitoring\n await this.monitor.start();\n\n this.isActive = true;\n console.log('\u2705 Claude Code lifecycle hooks initialized');\n }\n\n /**\n * Register event handlers for monitor events\n */\n private registerEventHandlers(): void {\n if (!this.monitor) return;\n\n // Context events\n this.monitor.on('context:warning', (data) => {\n console.log(`\u26A0\uFE0F Context at ${Math.round(data.percentage * 100)}%`);\n });\n\n this.monitor.on('context:high', async (data) => {\n if (this.config.autoTriggers.onContextHigh) {\n console.log('\uD83D\uDFE1 High context - preparing auto-save');\n await this.executeHook('on-context-high', data);\n }\n });\n\n this.monitor.on('context:ledger_saved', (data) => {\n console.log(`\u2705 Ledger saved (${data.compression}x compression)`);\n console.log('\uD83D\uDCA1 You can now safely use /clear');\n });\n\n // Handoff events\n this.monitor.on('handoff:generated', (data) => {\n console.log(`\uD83D\uDCCB Handoff saved (trigger: ${data.trigger})`);\n });\n }\n\n /**\n * Install hooks into Claude Code configuration\n */\n private async installClaudeHooks(): Promise<void> {\n // Create hooks directory if it doesn't exist\n await fs.mkdir(this.config.claudeHooksPath!, { recursive: true });\n\n // Install context monitor hook\n await this.installHook(\n 'on-message-submit',\n `\n#!/bin/bash\n# StackMemory Context Monitor Hook\n# Monitors token usage and triggers auto-save when needed\n\n# Get estimated token count from Claude (if available)\nTOKEN_COUNT=\\${CLAUDE_TOKEN_COUNT:-0}\nMAX_TOKENS=\\${CLAUDE_MAX_TOKENS:-100000}\n\nif [ \"\\$TOKEN_COUNT\" -gt 0 ]; then\n USAGE=\\$((TOKEN_COUNT * 100 / MAX_TOKENS))\n \n if [ \"\\$USAGE\" -gt 85 ]; then\n echo \"\uD83D\uDD34 Critical: Context at \\${USAGE}% - Auto-saving...\"\n stackmemory clear --save > /dev/null 2>&1\n echo \"\u2705 Ledger saved. Consider using /clear\"\n elif [ \"\\$USAGE\" -gt 70 ]; then\n echo \"\u26A0\uFE0F Warning: Context at \\${USAGE}%\"\n echo \"\uD83D\uDCA1 Run: stackmemory clear --save\"\n fi\nfi\n\n# Update activity timestamp\nstackmemory monitor --activity 2>/dev/null || true\n`\n );\n\n // Install session end hook\n await this.installHook(\n 'on-session-end',\n `\n#!/bin/bash\n# StackMemory Session End Hook\n# Generates handoff document when session ends\n\necho \"\uD83D\uDCE6 Saving session state...\"\n\n# Generate handoff\nstackmemory handoff --generate > /dev/null 2>&1 && echo \"\u2705 Handoff saved\"\n\n# Save ledger if context is significant\nCONTEXT_STATUS=$(stackmemory clear --check 2>/dev/null | grep -o '[0-9]\\\\+%' | head -1 | tr -d '%')\nif [ \"\\${CONTEXT_STATUS:-0}\" -gt 30 ]; then\n stackmemory clear --save > /dev/null 2>&1 && echo \"\u2705 Continuity ledger saved\"\nfi\n\necho \"\uD83D\uDC4B Session state preserved for next time\"\n`\n );\n\n // Install clear command interceptor\n await this.installHook(\n 'on-command-clear',\n `\n#!/bin/bash\n# StackMemory Clear Interceptor\n# Saves state before /clear command\n\necho \"\uD83D\uDD04 Preparing for /clear...\"\n\n# Save continuity ledger\nstackmemory clear --save > /dev/null 2>&1\necho \"\u2705 Continuity ledger saved\"\n\n# Generate quick handoff\nstackmemory handoff --generate > /dev/null 2>&1\necho \"\u2705 Handoff document saved\"\n\necho \"\u2705 Ready for /clear - context will be restored automatically\"\necho \"\uD83D\uDCA1 After /clear, run: stackmemory clear --restore\"\n`\n );\n\n // Install idle detector\n await this.installHook(\n 'on-idle-5min',\n `\n#!/bin/bash\n# StackMemory Idle Detector\n# Generates handoff after 5 minutes of inactivity\n\necho \"\u23F8\uFE0F Session idle - generating handoff...\"\nstackmemory handoff --generate > /dev/null 2>&1\necho \"\u2705 Handoff saved. Ready to resume anytime.\"\n`\n );\n }\n\n /**\n * Install a specific hook script\n */\n private async installHook(name: string, script: string): Promise<void> {\n const hookPath = path.join(this.config.claudeHooksPath!, name);\n\n // Store script content\n this.hookScripts.set(name, script);\n\n // Write hook file\n await fs.writeFile(hookPath, script.trim(), { mode: 0o755 });\n\n // Make executable\n await fs.chmod(hookPath, 0o755);\n }\n\n /**\n * Execute a hook with context\n */\n private async executeHook(hookName: string, context: any): Promise<void> {\n const hookPath = path.join(this.config.claudeHooksPath!, hookName);\n\n try {\n // Check if hook exists\n await fs.access(hookPath);\n\n // Execute hook with environment variables\n const { exec } = await import('child_process');\n const { promisify } = await import('util');\n const execAsync = promisify(exec);\n\n const env = {\n ...process.env,\n STACKMEMORY_CONTEXT: JSON.stringify(context),\n STACKMEMORY_PROJECT: this.config.projectRoot,\n };\n\n const { stdout, stderr } = await execAsync(hookPath, { env });\n\n if (stdout) console.log(stdout);\n if (stderr) console.error(stderr);\n } catch (error) {\n // Hook doesn't exist or failed\n console.debug(`Hook ${hookName} not found or failed:`, error);\n }\n }\n\n /**\n * Stop monitoring and cleanup\n */\n async stop(): Promise<void> {\n if (this.monitor) {\n await this.monitor.stop();\n }\n this.isActive = false;\n console.log('\uD83D\uDED1 Claude Code lifecycle hooks stopped');\n }\n\n /**\n * Get current status\n */\n getStatus(): any {\n return {\n isActive: this.isActive,\n monitorStatus: this.monitor?.getStatus(),\n config: this.config,\n installedHooks: Array.from(this.hookScripts.keys()),\n };\n }\n}\n\n/**\n * Global singleton instance\n */\nlet globalInstance: ClaudeCodeLifecycleHooks | undefined;\n\n/**\n * Initialize global hooks\n */\nexport async function initializeClaudeHooks(\n projectRoot?: string\n): Promise<ClaudeCodeLifecycleHooks> {\n if (!projectRoot) {\n projectRoot = process.cwd();\n }\n\n if (!globalInstance) {\n globalInstance = new ClaudeCodeLifecycleHooks({\n projectRoot,\n autoTriggers: {\n onContextHigh: true,\n onContextCritical: true,\n onSessionIdle: true,\n onSessionEnd: true,\n onClearCommand: true,\n },\n });\n\n await globalInstance.initialize();\n }\n\n return globalInstance;\n}\n\n/**\n * Get global instance\n */\nexport function getClaudeHooks(): ClaudeCodeLifecycleHooks | undefined {\n return globalInstance;\n}\n\n/**\n * Stop global hooks\n */\nexport async function stopClaudeHooks(): Promise<void> {\n if (globalInstance) {\n await globalInstance.stop();\n globalInstance = undefined;\n }\n}\n"],
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["/**\n * Claude Code Lifecycle Hooks for StackMemory\n * Integrates with Claude Code's session lifecycle\n */\n\nimport { SessionMonitor } from '../../core/monitoring/session-monitor';\nimport { FrameManager } from '../../core/frame/frame-manager';\nimport { DatabaseManager } from '../../core/storage/database-manager';\nimport * as fs from 'fs/promises';\nimport * as path from 'path';\nimport * as os from 'os';\n\nexport interface ClaudeCodeHookConfig {\n projectRoot: string;\n autoTriggers: {\n onContextHigh: boolean; // Auto-save at 70%\n onContextCritical: boolean; // Force-save at 85%\n onSessionIdle: boolean; // Handoff on 5min idle\n onSessionEnd: boolean; // Handoff on close\n onClearCommand: boolean; // Save before /clear\n };\n claudeHooksPath?: string; // Path to .claude/hooks\n}\n\nexport class ClaudeCodeLifecycleHooks {\n private monitor?: SessionMonitor;\n private config: ClaudeCodeHookConfig;\n private isActive: boolean = false;\n private hookScripts: Map<string, string> = new Map();\n\n constructor(config: ClaudeCodeHookConfig) {\n this.config = {\n ...config,\n claudeHooksPath:\n config.claudeHooksPath || path.join(os.homedir(), '.claude', 'hooks'),\n };\n }\n\n /**\n * Initialize hooks and start monitoring\n */\n async initialize(): Promise<void> {\n if (this.isActive) return;\n\n // Initialize database and managers\n const dbPath = path.join(\n this.config.projectRoot,\n '.stackmemory',\n 'db',\n 'stackmemory.db'\n );\n const dbManager = new DatabaseManager(dbPath);\n await dbManager.initialize();\n\n const frameManager = new FrameManager(dbManager);\n\n // Create session monitor\n this.monitor = new SessionMonitor(\n frameManager,\n dbManager,\n this.config.projectRoot,\n {\n contextWarningThreshold: 0.6,\n contextCriticalThreshold: 0.7,\n contextAutoSaveThreshold: 0.85,\n idleTimeoutMinutes: 5,\n autoSaveLedger: this.config.autoTriggers.onContextCritical,\n autoGenerateHandoff: this.config.autoTriggers.onSessionIdle,\n sessionEndHandoff: this.config.autoTriggers.onSessionEnd,\n }\n );\n\n // Register event handlers\n this.registerEventHandlers();\n\n // Install Claude Code hooks\n await this.installClaudeHooks();\n\n // Start monitoring\n await this.monitor.start();\n\n this.isActive = true;\n console.log('\u2705 Claude Code lifecycle hooks initialized');\n }\n\n /**\n * Register event handlers for monitor events\n */\n private registerEventHandlers(): void {\n if (!this.monitor) return;\n\n // Context events\n this.monitor.on('context:warning', (data) => {\n console.log(`\u26A0\uFE0F Context at ${Math.round(data.percentage * 100)}%`);\n });\n\n this.monitor.on('context:high', async (data) => {\n if (this.config.autoTriggers.onContextHigh) {\n console.log('\uD83D\uDFE1 High context - preparing auto-save');\n await this.executeHook('on-context-high', data);\n }\n });\n\n this.monitor.on('context:ledger_saved', (data) => {\n console.log(`\u2705 Ledger saved (${data.compression}x compression)`);\n console.log('\uD83D\uDCA1 You can now safely use /clear');\n });\n\n // Handoff events\n this.monitor.on('handoff:generated', (data) => {\n console.log(`\uD83D\uDCCB Handoff saved (trigger: ${data.trigger})`);\n });\n }\n\n /**\n * Install hooks into Claude Code configuration\n */\n private async installClaudeHooks(): Promise<void> {\n // Create hooks directory if it doesn't exist\n await fs.mkdir(this.config.claudeHooksPath!, { recursive: true });\n\n // Install context monitor hook\n await this.installHook(\n 'on-message-submit',\n `\n#!/bin/bash\n# StackMemory Context Monitor Hook\n# Monitors token usage and triggers auto-save when needed\n\n# Get estimated token count from Claude (if available)\nTOKEN_COUNT=\\${CLAUDE_TOKEN_COUNT:-0}\nMAX_TOKENS=\\${CLAUDE_MAX_TOKENS:-100000}\n\nif [ \"\\$TOKEN_COUNT\" -gt 0 ]; then\n USAGE=\\$((TOKEN_COUNT * 100 / MAX_TOKENS))\n \n if [ \"\\$USAGE\" -gt 85 ]; then\n echo \"\uD83D\uDD34 Critical: Context at \\${USAGE}% - Auto-saving...\"\n stackmemory clear --save > /dev/null 2>&1\n echo \"\u2705 Ledger saved. Consider using /clear\"\n elif [ \"\\$USAGE\" -gt 70 ]; then\n echo \"\u26A0\uFE0F Warning: Context at \\${USAGE}%\"\n echo \"\uD83D\uDCA1 Run: stackmemory clear --save\"\n fi\nfi\n\n# Update activity timestamp\nstackmemory monitor --activity 2>/dev/null || true\n`\n );\n\n // Install session end hook\n await this.installHook(\n 'on-session-end',\n `\n#!/bin/bash\n# StackMemory Session End Hook\n# Generates handoff document when session ends\n\necho \"\uD83D\uDCE6 Saving session state...\"\n\n# Generate handoff\nstackmemory handoff --generate > /dev/null 2>&1 && echo \"\u2705 Handoff saved\"\n\n# Save ledger if context is significant\nCONTEXT_STATUS=$(stackmemory clear --check 2>/dev/null | grep -o '[0-9]\\\\+%' | head -1 | tr -d '%')\nif [ \"\\${CONTEXT_STATUS:-0}\" -gt 30 ]; then\n stackmemory clear --save > /dev/null 2>&1 && echo \"\u2705 Continuity ledger saved\"\nfi\n\necho \"\uD83D\uDC4B Session state preserved for next time\"\n`\n );\n\n // Install clear command interceptor\n await this.installHook(\n 'on-command-clear',\n `\n#!/bin/bash\n# StackMemory Clear Interceptor\n# Saves state before /clear command\n\necho \"\uD83D\uDD04 Preparing for /clear...\"\n\n# Save continuity ledger\nstackmemory clear --save > /dev/null 2>&1\necho \"\u2705 Continuity ledger saved\"\n\n# Generate quick handoff\nstackmemory handoff --generate > /dev/null 2>&1\necho \"\u2705 Handoff document saved\"\n\necho \"\u2705 Ready for /clear - context will be restored automatically\"\necho \"\uD83D\uDCA1 After /clear, run: stackmemory clear --restore\"\n`\n );\n\n // Install idle detector\n await this.installHook(\n 'on-idle-5min',\n `\n#!/bin/bash\n# StackMemory Idle Detector\n# Generates handoff after 5 minutes of inactivity\n\necho \"\u23F8\uFE0F Session idle - generating handoff...\"\nstackmemory handoff --generate > /dev/null 2>&1\necho \"\u2705 Handoff saved. Ready to resume anytime.\"\n`\n );\n }\n\n /**\n * Install a specific hook script\n */\n private async installHook(name: string, script: string): Promise<void> {\n const hookPath = path.join(this.config.claudeHooksPath!, name);\n\n // Store script content\n this.hookScripts.set(name, script);\n\n // Write hook file\n await fs.writeFile(hookPath, script.trim(), { mode: 0o755 });\n\n // Make executable\n await fs.chmod(hookPath, 0o755);\n }\n\n /**\n * Execute a hook with context\n */\n private async executeHook(hookName: string, context: any): Promise<void> {\n const hookPath = path.join(this.config.claudeHooksPath!, hookName);\n\n try {\n // Check if hook exists\n await fs.access(hookPath);\n\n // Execute hook with environment variables\n const { exec } = await import('child_process');\n const { promisify } = await import('util');\n const execAsync = promisify(exec);\n\n const env = {\n ...process.env,\n STACKMEMORY_CONTEXT: JSON.stringify(context),\n STACKMEMORY_PROJECT: this.config.projectRoot,\n };\n\n const { stdout, stderr } = await execAsync(hookPath, { env });\n\n if (stdout) console.log(stdout);\n if (stderr) console.error(stderr);\n } catch (error: unknown) {\n // Hook doesn't exist or failed\n console.debug(`Hook ${hookName} not found or failed:`, error);\n }\n }\n\n /**\n * Stop monitoring and cleanup\n */\n async stop(): Promise<void> {\n if (this.monitor) {\n await this.monitor.stop();\n }\n this.isActive = false;\n console.log('\uD83D\uDED1 Claude Code lifecycle hooks stopped');\n }\n\n /**\n * Get current status\n */\n getStatus(): any {\n return {\n isActive: this.isActive,\n monitorStatus: this.monitor?.getStatus(),\n config: this.config,\n installedHooks: Array.from(this.hookScripts.keys()),\n };\n }\n}\n\n/**\n * Global singleton instance\n */\nlet globalInstance: ClaudeCodeLifecycleHooks | undefined;\n\n/**\n * Initialize global hooks\n */\nexport async function initializeClaudeHooks(\n projectRoot?: string\n): Promise<ClaudeCodeLifecycleHooks> {\n if (!projectRoot) {\n projectRoot = process.cwd();\n }\n\n if (!globalInstance) {\n globalInstance = new ClaudeCodeLifecycleHooks({\n projectRoot,\n autoTriggers: {\n onContextHigh: true,\n onContextCritical: true,\n onSessionIdle: true,\n onSessionEnd: true,\n onClearCommand: true,\n },\n });\n\n await globalInstance.initialize();\n }\n\n return globalInstance;\n}\n\n/**\n * Get global instance\n */\nexport function getClaudeHooks(): ClaudeCodeLifecycleHooks | undefined {\n return globalInstance;\n}\n\n/**\n * Stop global hooks\n */\nexport async function stopClaudeHooks(): Promise<void> {\n if (globalInstance) {\n await globalInstance.stop();\n globalInstance = undefined;\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/integrations/claude-code/post-task-hooks.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Post-Task Completion Hooks for StackMemory\n * Automatically runs tests and code review after Claude completes tasks\n */\n\nimport { EventEmitter } from 'events';\nimport { execSync } from 'child_process';\nimport * as fs from 'fs/promises';\nimport * as path from 'path';\nimport { FrameManager } from '../../core/frame/frame-manager';\nimport { DatabaseManager } from '../../core/storage/database-manager';\n\nexport interface PostTaskConfig {\n projectRoot: string;\n qualityGates: {\n runTests: boolean; // Auto-run tests after code changes\n requireTestCoverage: boolean; // Require test coverage for new code\n runCodeReview: boolean; // Auto-trigger code review agent\n runLinter: boolean; // Auto-run linter/formatter\n blockOnFailure: boolean; // Block further work if quality gates fail\n };\n testFrameworks: {\n detected: string[]; // Auto-detected test frameworks\n testCommand?: string; // Custom test command\n coverageCommand?: string; // Custom coverage command\n lintCommand?: string; // Custom lint command\n };\n reviewConfig: {\n reviewOnEveryChange: boolean; // Review every file change\n reviewOnTaskComplete: boolean; // Review when task frame closes\n focusAreas: string[]; // What to focus on in reviews\n skipPatterns: string[]; // Files/patterns to skip review\n };\n}\n\nexport interface TaskCompletionEvent {\n taskType: 'code_change' | 'task_complete' | 'file_modified' | 'frame_closed';\n files: string[];\n frameId: string;\n frameName: string;\n changes: {\n added: number;\n removed: number;\n modified: number;\n };\n metadata: Record<string, any>;\n}\n\nexport interface QualityGateResult {\n gate: string;\n passed: boolean;\n output: string;\n duration: number;\n issues?: QualityIssue[];\n}\n\nexport interface QualityIssue {\n type: 'test_failure' | 'lint_error' | 'coverage_low' | 'review_concern';\n file: string;\n line?: number;\n message: string;\n severity: 'error' | 'warning' | 'info';\n}\n\nexport class PostTaskHooks extends EventEmitter {\n private config: PostTaskConfig;\n private frameManager: FrameManager;\n private dbManager: DatabaseManager;\n private isActive: boolean = false;\n private lastProcessedFrame?: string;\n\n constructor(\n frameManager: FrameManager,\n dbManager: DatabaseManager,\n config: Partial<PostTaskConfig>\n ) {\n super();\n this.frameManager = frameManager;\n this.dbManager = dbManager;\n\n // Default configuration\n this.config = {\n projectRoot: process.cwd(),\n qualityGates: {\n runTests: true,\n requireTestCoverage: false,\n runCodeReview: true,\n runLinter: true,\n blockOnFailure: false,\n },\n testFrameworks: {\n detected: [],\n },\n reviewConfig: {\n reviewOnEveryChange: false,\n reviewOnTaskComplete: true,\n focusAreas: [\n 'security',\n 'performance',\n 'maintainability',\n 'correctness',\n ],\n skipPatterns: ['*.test.ts', '*.spec.js', 'dist/', 'node_modules/'],\n },\n ...config,\n };\n }\n\n /**\n * Initialize post-task hooks\n */\n async initialize(): Promise<void> {\n if (this.isActive) return;\n\n // Detect test frameworks and commands\n await this.detectTestFrameworks();\n\n // Set up frame event listeners\n this.setupFrameListeners();\n\n // Set up file watchers for code changes\n await this.setupFileWatchers();\n\n this.isActive = true;\n console.log('\u2705 Post-task hooks initialized');\n this.emit('initialized', this.config);\n }\n\n /**\n * Detect available test frameworks and commands\n */\n private async detectTestFrameworks(): Promise<void> {\n const packageJsonPath = path.join(this.config.projectRoot, 'package.json');\n\n try {\n const packageJson = JSON.parse(\n await fs.readFile(packageJsonPath, 'utf-8')\n );\n const scripts = packageJson.scripts || {};\n const dependencies = {\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n };\n\n // Detect test frameworks\n const frameworks: string[] = [];\n if (dependencies.jest) frameworks.push('jest');\n if (dependencies.vitest) frameworks.push('vitest');\n if (dependencies.mocha) frameworks.push('mocha');\n if (dependencies.playwright) frameworks.push('playwright');\n if (dependencies.cypress) frameworks.push('cypress');\n\n this.config.testFrameworks.detected = frameworks;\n\n // Detect commands\n if (scripts.test) {\n this.config.testFrameworks.testCommand = 'npm test';\n } else if (scripts['test:run']) {\n this.config.testFrameworks.testCommand = 'npm run test:run';\n }\n\n if (scripts.coverage) {\n this.config.testFrameworks.coverageCommand = 'npm run coverage';\n }\n\n if (scripts.lint) {\n this.config.testFrameworks.lintCommand = 'npm run lint';\n }\n } catch (error) {\n console.warn('Could not detect test frameworks:', error);\n }\n }\n\n /**\n * Set up frame event listeners\n */\n private setupFrameListeners(): void {\n // Listen for frame closures (task completion)\n this.frameManager.on(\n 'frame:closed',\n async (frameId: string, frameData: any) => {\n if (frameData.type === 'task' || frameData.type === 'subtask') {\n await this.handleTaskCompletion({\n taskType: 'task_complete',\n frameId,\n frameName: frameData.name || 'Unnamed task',\n files: this.extractFilesFromFrame(frameData),\n changes: this.calculateChanges(frameData),\n metadata: frameData.metadata || {},\n });\n }\n }\n );\n\n // Listen for significant events\n this.frameManager.on(\n 'frame:event',\n async (frameId: string, eventType: string, data: any) => {\n if (eventType === 'code_change' || eventType === 'file_modified') {\n await this.handleTaskCompletion({\n taskType: 'code_change',\n frameId,\n frameName: data.description || 'Code change',\n files: data.files || [],\n changes: data.changes || { added: 0, removed: 0, modified: 1 },\n metadata: data,\n });\n }\n }\n );\n }\n\n /**\n * Set up file watchers for real-time code change detection\n */\n private async setupFileWatchers(): Promise<void> {\n try {\n const chokidar = await import('chokidar');\n\n const watcher = chokidar.watch(\n [\n '**/*.{ts,js,tsx,jsx,py,go,rs,java,cpp,c}',\n '!node_modules/**',\n '!dist/**',\n '!build/**',\n ],\n {\n cwd: this.config.projectRoot,\n ignored: /node_modules/,\n persistent: true,\n }\n );\n\n let changeQueue: string[] = [];\n let debounceTimer: NodeJS.Timeout | null = null;\n\n watcher.on('change', (filePath: string) => {\n changeQueue.push(filePath);\n\n // Debounce to avoid too many triggers\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(async () => {\n if (changeQueue.length > 0) {\n await this.handleFileChanges([...changeQueue]);\n changeQueue = [];\n }\n }, 2000); // 2 second debounce\n });\n } catch (error) {\n console.warn('File watching not available:', error);\n }\n }\n\n /**\n * Handle task completion events\n */\n private async handleTaskCompletion(\n event: TaskCompletionEvent\n ): Promise<void> {\n // Avoid duplicate processing\n if (\n this.lastProcessedFrame === event.frameId &&\n event.taskType !== 'code_change'\n ) {\n return;\n }\n\n this.lastProcessedFrame = event.frameId;\n\n console.log(\n `\uD83D\uDD0D Task completed: ${event.frameName} (${event.files.length} files changed)`\n );\n this.emit('task:completed', event);\n\n // Run quality gates\n const results = await this.runQualityGates(event);\n\n // Check if gates passed\n const allPassed = results.every((r) => r.passed);\n\n if (allPassed) {\n console.log('\u2705 All quality gates passed');\n this.emit('quality:passed', { event, results });\n } else {\n console.log('\u26A0\uFE0F Quality gate failures detected');\n this.emit('quality:failed', { event, results });\n\n if (this.config.qualityGates.blockOnFailure) {\n await this.blockFurtherWork(results);\n }\n }\n\n // Record results in frame metadata\n await this.recordQualityResults(event.frameId, results);\n }\n\n /**\n * Handle file changes\n */\n private async handleFileChanges(files: string[]): Promise<void> {\n if (!this.config.reviewConfig.reviewOnEveryChange) return;\n\n // Filter out files that should be skipped\n const filteredFiles = files.filter((file) => {\n return !this.config.reviewConfig.skipPatterns.some((pattern) => {\n return file.includes(pattern.replace('*', ''));\n });\n });\n\n if (filteredFiles.length === 0) return;\n\n await this.handleTaskCompletion({\n taskType: 'file_modified',\n frameId: 'file-watcher',\n frameName: 'File changes detected',\n files: filteredFiles,\n changes: { added: 0, removed: 0, modified: filteredFiles.length },\n metadata: { trigger: 'file_watcher' },\n });\n }\n\n /**\n * Run all configured quality gates\n */\n private async runQualityGates(\n event: TaskCompletionEvent\n ): Promise<QualityGateResult[]> {\n const results: QualityGateResult[] = [];\n\n // Run linter first (fastest)\n if (this.config.qualityGates.runLinter) {\n results.push(await this.runLinter(event.files));\n }\n\n // Run tests (slower)\n if (this.config.qualityGates.runTests) {\n results.push(await this.runTests(event.files));\n }\n\n // Check test coverage\n if (this.config.qualityGates.requireTestCoverage) {\n results.push(await this.checkTestCoverage(event.files));\n }\n\n // Run code review (slowest, most thorough)\n if (this.config.qualityGates.runCodeReview) {\n results.push(await this.runCodeReview(event));\n }\n\n return results;\n }\n\n /**\n * Run linter on changed files\n */\n private async runLinter(files: string[]): Promise<QualityGateResult> {\n const start = Date.now();\n\n try {\n if (!this.config.testFrameworks.lintCommand) {\n return {\n gate: 'linter',\n passed: true,\n output: 'No lint command configured',\n duration: Date.now() - start,\n };\n }\n\n const output = execSync(this.config.testFrameworks.lintCommand, {\n cwd: this.config.projectRoot,\n encoding: 'utf-8',\n timeout: 30000, // 30 second timeout\n });\n\n return {\n gate: 'linter',\n passed: true,\n output,\n duration: Date.now() - start,\n };\n } catch (error: any) {\n return {\n gate: 'linter',\n passed: false,\n output: error.stdout || error.message,\n duration: Date.now() - start,\n issues: this.parseLintErrors(error.stdout || error.message),\n };\n }\n }\n\n /**\n * Run tests\n */\n private async runTests(files: string[]): Promise<QualityGateResult> {\n const start = Date.now();\n\n try {\n if (!this.config.testFrameworks.testCommand) {\n return {\n gate: 'tests',\n passed: true,\n output: 'No test command configured',\n duration: Date.now() - start,\n };\n }\n\n const output = execSync(this.config.testFrameworks.testCommand, {\n cwd: this.config.projectRoot,\n encoding: 'utf-8',\n timeout: 120000, // 2 minute timeout\n });\n\n return {\n gate: 'tests',\n passed: true,\n output,\n duration: Date.now() - start,\n };\n } catch (error: any) {\n return {\n gate: 'tests',\n passed: false,\n output: error.stdout || error.message,\n duration: Date.now() - start,\n issues: this.parseTestFailures(error.stdout || error.message),\n };\n }\n }\n\n /**\n * Check test coverage\n */\n private async checkTestCoverage(files: string[]): Promise<QualityGateResult> {\n const start = Date.now();\n\n try {\n if (!this.config.testFrameworks.coverageCommand) {\n return {\n gate: 'coverage',\n passed: true,\n output: 'No coverage command configured',\n duration: Date.now() - start,\n };\n }\n\n const output = execSync(this.config.testFrameworks.coverageCommand, {\n cwd: this.config.projectRoot,\n encoding: 'utf-8',\n timeout: 120000,\n });\n\n // Parse coverage percentage (simplified)\n const coverageMatch = output.match(/(\\d+\\.?\\d*)%/);\n const coverage = coverageMatch ? parseFloat(coverageMatch[1]) : 0;\n const threshold = 80; // 80% coverage threshold\n\n return {\n gate: 'coverage',\n passed: coverage >= threshold,\n output,\n duration: Date.now() - start,\n issues:\n coverage < threshold\n ? [\n {\n type: 'coverage_low',\n file: 'overall',\n message: `Coverage ${coverage}% is below threshold ${threshold}%`,\n severity: 'warning' as const,\n },\n ]\n : undefined,\n };\n } catch (error: any) {\n return {\n gate: 'coverage',\n passed: false,\n output: error.stdout || error.message,\n duration: Date.now() - start,\n issues: [\n {\n type: 'coverage_low',\n file: 'overall',\n message: 'Coverage check failed',\n severity: 'error' as const,\n },\n ],\n };\n }\n }\n\n /**\n * Run code review using AI agent\n */\n private async runCodeReview(\n event: TaskCompletionEvent\n ): Promise<QualityGateResult> {\n const start = Date.now();\n\n try {\n // This would integrate with the code review agent\n const reviewPrompt = this.generateCodeReviewPrompt(event);\n\n // For now, simulate a review (in real implementation, call agent)\n const review = await this.callCodeReviewAgent(reviewPrompt, event.files);\n\n return {\n gate: 'code_review',\n passed: !review.issues || review.issues.length === 0,\n output: review.summary,\n duration: Date.now() - start,\n issues: review.issues,\n };\n } catch (error: any) {\n return {\n gate: 'code_review',\n passed: false,\n output: `Code review failed: ${error.message}`,\n duration: Date.now() - start,\n };\n }\n }\n\n /**\n * Generate code review prompt\n */\n private generateCodeReviewPrompt(event: TaskCompletionEvent): string {\n return `\nPlease review the following code changes:\n\nTask: ${event.frameName}\nFiles changed: ${event.files.join(', ')}\nChanges: +${event.changes.added}, -${event.changes.removed}, ~${event.changes.modified}\n\nFocus areas: ${this.config.reviewConfig.focusAreas.join(', ')}\n\nPlease check for:\n1. Security vulnerabilities\n2. Performance issues \n3. Code maintainability\n4. Correctness and logic errors\n5. Best practices adherence\n\nProvide specific, actionable feedback.\n`;\n }\n\n /**\n * Call code review agent (placeholder for actual implementation)\n */\n private async callCodeReviewAgent(\n prompt: string,\n files: string[]\n ): Promise<{\n summary: string;\n issues?: QualityIssue[];\n }> {\n // This would integrate with Claude Code's agent system\n // For now, return a mock review\n return {\n summary: `Reviewed ${files.length} files. Code quality looks good.`,\n issues: [],\n };\n }\n\n /**\n * Parse lint errors into structured issues\n */\n private parseLintErrors(output: string): QualityIssue[] {\n const issues: QualityIssue[] = [];\n\n // Simple parser for common lint formats\n const lines = output.split('\\n');\n for (const line of lines) {\n const match = line.match(\n /^(.+?):(\\d+):(\\d+):\\s*(error|warning):\\s*(.+)$/\n );\n if (match) {\n issues.push({\n type: 'lint_error',\n file: match[1],\n line: parseInt(match[2]),\n message: match[5],\n severity: match[4] as 'error' | 'warning',\n });\n }\n }\n\n return issues;\n }\n\n /**\n * Parse test failures into structured issues\n */\n private parseTestFailures(output: string): QualityIssue[] {\n const issues: QualityIssue[] = [];\n\n // Simple parser for test failures\n const lines = output.split('\\n');\n for (const line of lines) {\n if (line.includes('FAIL') || line.includes('\u2717')) {\n issues.push({\n type: 'test_failure',\n file: 'unknown',\n message: line.trim(),\n severity: 'error',\n });\n }\n }\n\n return issues;\n }\n\n /**\n * Block further work when quality gates fail\n */\n private async blockFurtherWork(results: QualityGateResult[]): Promise<void> {\n const failedGates = results.filter((r) => !r.passed);\n\n console.log('\uD83D\uDEAB Quality gates failed - blocking further work:');\n failedGates.forEach((gate) => {\n console.log(` ${gate.gate}: ${gate.output}`);\n if (gate.issues) {\n gate.issues.forEach((issue) => {\n console.log(\n ` - ${issue.severity}: ${issue.message} (${issue.file}:${issue.line || 0})`\n );\n });\n }\n });\n\n console.log('\\n\uD83D\uDD27 Fix these issues before continuing:');\n const allIssues = failedGates.flatMap((g) => g.issues || []);\n allIssues.forEach((issue, i) => {\n console.log(`${i + 1}. ${issue.message}`);\n });\n }\n\n /**\n * Record quality results in frame metadata\n */\n private async recordQualityResults(\n frameId: string,\n results: QualityGateResult[]\n ): Promise<void> {\n try {\n const frame = await this.frameManager.getFrame(frameId);\n if (frame) {\n frame.metadata = {\n ...frame.metadata,\n qualityGates: {\n timestamp: new Date().toISOString(),\n results,\n passed: results.every((r) => r.passed),\n totalDuration: results.reduce((sum, r) => sum + r.duration, 0),\n },\n };\n\n // Update frame with quality results\n await this.frameManager.updateFrame(frameId, frame);\n }\n } catch (error) {\n console.error('Failed to record quality results:', error);\n }\n }\n\n /**\n * Extract files from frame data\n */\n private extractFilesFromFrame(frameData: any): string[] {\n // Extract file paths from various possible locations\n const files: string[] = [];\n\n if (frameData.metadata?.files) {\n files.push(...frameData.metadata.files);\n }\n\n if (frameData.events) {\n frameData.events.forEach((event: any) => {\n if (event.type === 'file_change' && event.data?.file) {\n files.push(event.data.file);\n }\n });\n }\n\n return [...new Set(files)]; // Remove duplicates\n }\n\n /**\n * Calculate changes from frame data\n */\n private calculateChanges(frameData: any): {\n added: number;\n removed: number;\n modified: number;\n } {\n return {\n added: frameData.metadata?.linesAdded || 0,\n removed: frameData.metadata?.linesRemoved || 0,\n modified: frameData.metadata?.filesModified || 1,\n };\n }\n\n /**\n * Stop post-task hooks\n */\n async stop(): Promise<void> {\n this.isActive = false;\n this.removeAllListeners();\n console.log('\uD83D\uDED1 Post-task hooks stopped');\n }\n\n /**\n * Get current configuration\n */\n getConfig(): PostTaskConfig {\n return { ...this.config };\n }\n\n /**\n * Update configuration\n */\n updateConfig(updates: Partial<PostTaskConfig>): void {\n this.config = { ...this.config, ...updates };\n this.emit('config:updated', this.config);\n }\n}\n"],
|
|
5
|
-
"mappings": "AAKA,SAAS,oBAAoB;AAC7B,SAAS,gBAAgB;AACzB,YAAY,QAAQ;AACpB,YAAY,UAAU;AAwDf,MAAM,sBAAsB,aAAa;AAAA,EACtC;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAoB;AAAA,EACpB;AAAA,EAER,YACE,cACA,WACA,QACA;AACA,UAAM;AACN,SAAK,eAAe;AACpB,SAAK,YAAY;AAGjB,SAAK,SAAS;AAAA,MACZ,aAAa,QAAQ,IAAI;AAAA,MACzB,cAAc;AAAA,QACZ,UAAU;AAAA,QACV,qBAAqB;AAAA,QACrB,eAAe;AAAA,QACf,WAAW;AAAA,QACX,gBAAgB;AAAA,MAClB;AAAA,MACA,gBAAgB;AAAA,QACd,UAAU,CAAC;AAAA,MACb;AAAA,MACA,cAAc;AAAA,QACZ,qBAAqB;AAAA,QACrB,sBAAsB;AAAA,QACtB,YAAY;AAAA,UACV;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,QACA,cAAc,CAAC,aAAa,aAAa,SAAS,eAAe;AAAA,MACnE;AAAA,MACA,GAAG;AAAA,IACL;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAA4B;AAChC,QAAI,KAAK,SAAU;AAGnB,UAAM,KAAK,qBAAqB;AAGhC,SAAK,oBAAoB;AAGzB,UAAM,KAAK,kBAAkB;AAE7B,SAAK,WAAW;AAChB,YAAQ,IAAI,oCAA+B;AAC3C,SAAK,KAAK,eAAe,KAAK,MAAM;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,uBAAsC;AAClD,UAAM,kBAAkB,KAAK,KAAK,KAAK,OAAO,aAAa,cAAc;AAEzE,QAAI;AACF,YAAM,cAAc,KAAK;AAAA,QACvB,MAAM,GAAG,SAAS,iBAAiB,OAAO;AAAA,MAC5C;AACA,YAAM,UAAU,YAAY,WAAW,CAAC;AACxC,YAAM,eAAe;AAAA,QACnB,GAAG,YAAY;AAAA,QACf,GAAG,YAAY;AAAA,MACjB;AAGA,YAAM,aAAuB,CAAC;AAC9B,UAAI,aAAa,KAAM,YAAW,KAAK,MAAM;AAC7C,UAAI,aAAa,OAAQ,YAAW,KAAK,QAAQ;AACjD,UAAI,aAAa,MAAO,YAAW,KAAK,OAAO;AAC/C,UAAI,aAAa,WAAY,YAAW,KAAK,YAAY;AACzD,UAAI,aAAa,QAAS,YAAW,KAAK,SAAS;AAEnD,WAAK,OAAO,eAAe,WAAW;AAGtC,UAAI,QAAQ,MAAM;AAChB,aAAK,OAAO,eAAe,cAAc;AAAA,MAC3C,WAAW,QAAQ,UAAU,GAAG;AAC9B,aAAK,OAAO,eAAe,cAAc;AAAA,MAC3C;AAEA,UAAI,QAAQ,UAAU;AACpB,aAAK,OAAO,eAAe,kBAAkB;AAAA,MAC/C;AAEA,UAAI,QAAQ,MAAM;AAChB,aAAK,OAAO,eAAe,cAAc;AAAA,MAC3C;AAAA,IACF,SAAS,
|
|
4
|
+
"sourcesContent": ["/**\n * Post-Task Completion Hooks for StackMemory\n * Automatically runs tests and code review after Claude completes tasks\n */\n\nimport { EventEmitter } from 'events';\nimport { execSync } from 'child_process';\nimport * as fs from 'fs/promises';\nimport * as path from 'path';\nimport { FrameManager } from '../../core/frame/frame-manager';\nimport { DatabaseManager } from '../../core/storage/database-manager';\n\nexport interface PostTaskConfig {\n projectRoot: string;\n qualityGates: {\n runTests: boolean; // Auto-run tests after code changes\n requireTestCoverage: boolean; // Require test coverage for new code\n runCodeReview: boolean; // Auto-trigger code review agent\n runLinter: boolean; // Auto-run linter/formatter\n blockOnFailure: boolean; // Block further work if quality gates fail\n };\n testFrameworks: {\n detected: string[]; // Auto-detected test frameworks\n testCommand?: string; // Custom test command\n coverageCommand?: string; // Custom coverage command\n lintCommand?: string; // Custom lint command\n };\n reviewConfig: {\n reviewOnEveryChange: boolean; // Review every file change\n reviewOnTaskComplete: boolean; // Review when task frame closes\n focusAreas: string[]; // What to focus on in reviews\n skipPatterns: string[]; // Files/patterns to skip review\n };\n}\n\nexport interface TaskCompletionEvent {\n taskType: 'code_change' | 'task_complete' | 'file_modified' | 'frame_closed';\n files: string[];\n frameId: string;\n frameName: string;\n changes: {\n added: number;\n removed: number;\n modified: number;\n };\n metadata: Record<string, any>;\n}\n\nexport interface QualityGateResult {\n gate: string;\n passed: boolean;\n output: string;\n duration: number;\n issues?: QualityIssue[];\n}\n\nexport interface QualityIssue {\n type: 'test_failure' | 'lint_error' | 'coverage_low' | 'review_concern';\n file: string;\n line?: number;\n message: string;\n severity: 'error' | 'warning' | 'info';\n}\n\nexport class PostTaskHooks extends EventEmitter {\n private config: PostTaskConfig;\n private frameManager: FrameManager;\n private dbManager: DatabaseManager;\n private isActive: boolean = false;\n private lastProcessedFrame?: string;\n\n constructor(\n frameManager: FrameManager,\n dbManager: DatabaseManager,\n config: Partial<PostTaskConfig>\n ) {\n super();\n this.frameManager = frameManager;\n this.dbManager = dbManager;\n\n // Default configuration\n this.config = {\n projectRoot: process.cwd(),\n qualityGates: {\n runTests: true,\n requireTestCoverage: false,\n runCodeReview: true,\n runLinter: true,\n blockOnFailure: false,\n },\n testFrameworks: {\n detected: [],\n },\n reviewConfig: {\n reviewOnEveryChange: false,\n reviewOnTaskComplete: true,\n focusAreas: [\n 'security',\n 'performance',\n 'maintainability',\n 'correctness',\n ],\n skipPatterns: ['*.test.ts', '*.spec.js', 'dist/', 'node_modules/'],\n },\n ...config,\n };\n }\n\n /**\n * Initialize post-task hooks\n */\n async initialize(): Promise<void> {\n if (this.isActive) return;\n\n // Detect test frameworks and commands\n await this.detectTestFrameworks();\n\n // Set up frame event listeners\n this.setupFrameListeners();\n\n // Set up file watchers for code changes\n await this.setupFileWatchers();\n\n this.isActive = true;\n console.log('\u2705 Post-task hooks initialized');\n this.emit('initialized', this.config);\n }\n\n /**\n * Detect available test frameworks and commands\n */\n private async detectTestFrameworks(): Promise<void> {\n const packageJsonPath = path.join(this.config.projectRoot, 'package.json');\n\n try {\n const packageJson = JSON.parse(\n await fs.readFile(packageJsonPath, 'utf-8')\n );\n const scripts = packageJson.scripts || {};\n const dependencies = {\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n };\n\n // Detect test frameworks\n const frameworks: string[] = [];\n if (dependencies.jest) frameworks.push('jest');\n if (dependencies.vitest) frameworks.push('vitest');\n if (dependencies.mocha) frameworks.push('mocha');\n if (dependencies.playwright) frameworks.push('playwright');\n if (dependencies.cypress) frameworks.push('cypress');\n\n this.config.testFrameworks.detected = frameworks;\n\n // Detect commands\n if (scripts.test) {\n this.config.testFrameworks.testCommand = 'npm test';\n } else if (scripts['test:run']) {\n this.config.testFrameworks.testCommand = 'npm run test:run';\n }\n\n if (scripts.coverage) {\n this.config.testFrameworks.coverageCommand = 'npm run coverage';\n }\n\n if (scripts.lint) {\n this.config.testFrameworks.lintCommand = 'npm run lint';\n }\n } catch (error: unknown) {\n console.warn('Could not detect test frameworks:', error);\n }\n }\n\n /**\n * Set up frame event listeners\n */\n private setupFrameListeners(): void {\n // Listen for frame closures (task completion)\n this.frameManager.on(\n 'frame:closed',\n async (frameId: string, frameData: any) => {\n if (frameData.type === 'task' || frameData.type === 'subtask') {\n await this.handleTaskCompletion({\n taskType: 'task_complete',\n frameId,\n frameName: frameData.name || 'Unnamed task',\n files: this.extractFilesFromFrame(frameData),\n changes: this.calculateChanges(frameData),\n metadata: frameData.metadata || {},\n });\n }\n }\n );\n\n // Listen for significant events\n this.frameManager.on(\n 'frame:event',\n async (frameId: string, eventType: string, data: any) => {\n if (eventType === 'code_change' || eventType === 'file_modified') {\n await this.handleTaskCompletion({\n taskType: 'code_change',\n frameId,\n frameName: data.description || 'Code change',\n files: data.files || [],\n changes: data.changes || { added: 0, removed: 0, modified: 1 },\n metadata: data,\n });\n }\n }\n );\n }\n\n /**\n * Set up file watchers for real-time code change detection\n */\n private async setupFileWatchers(): Promise<void> {\n try {\n const chokidar = await import('chokidar');\n\n const watcher = chokidar.watch(\n [\n '**/*.{ts,js,tsx,jsx,py,go,rs,java,cpp,c}',\n '!node_modules/**',\n '!dist/**',\n '!build/**',\n ],\n {\n cwd: this.config.projectRoot,\n ignored: /node_modules/,\n persistent: true,\n }\n );\n\n let changeQueue: string[] = [];\n let debounceTimer: NodeJS.Timeout | null = null;\n\n watcher.on('change', (filePath: string) => {\n changeQueue.push(filePath);\n\n // Debounce to avoid too many triggers\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(async () => {\n if (changeQueue.length > 0) {\n await this.handleFileChanges([...changeQueue]);\n changeQueue = [];\n }\n }, 2000); // 2 second debounce\n });\n } catch (error: unknown) {\n console.warn('File watching not available:', error);\n }\n }\n\n /**\n * Handle task completion events\n */\n private async handleTaskCompletion(\n event: TaskCompletionEvent\n ): Promise<void> {\n // Avoid duplicate processing\n if (\n this.lastProcessedFrame === event.frameId &&\n event.taskType !== 'code_change'\n ) {\n return;\n }\n\n this.lastProcessedFrame = event.frameId;\n\n console.log(\n `\uD83D\uDD0D Task completed: ${event.frameName} (${event.files.length} files changed)`\n );\n this.emit('task:completed', event);\n\n // Run quality gates\n const results = await this.runQualityGates(event);\n\n // Check if gates passed\n const allPassed = results.every((r) => r.passed);\n\n if (allPassed) {\n console.log('\u2705 All quality gates passed');\n this.emit('quality:passed', { event, results });\n } else {\n console.log('\u26A0\uFE0F Quality gate failures detected');\n this.emit('quality:failed', { event, results });\n\n if (this.config.qualityGates.blockOnFailure) {\n await this.blockFurtherWork(results);\n }\n }\n\n // Record results in frame metadata\n await this.recordQualityResults(event.frameId, results);\n }\n\n /**\n * Handle file changes\n */\n private async handleFileChanges(files: string[]): Promise<void> {\n if (!this.config.reviewConfig.reviewOnEveryChange) return;\n\n // Filter out files that should be skipped\n const filteredFiles = files.filter((file) => {\n return !this.config.reviewConfig.skipPatterns.some((pattern) => {\n return file.includes(pattern.replace('*', ''));\n });\n });\n\n if (filteredFiles.length === 0) return;\n\n await this.handleTaskCompletion({\n taskType: 'file_modified',\n frameId: 'file-watcher',\n frameName: 'File changes detected',\n files: filteredFiles,\n changes: { added: 0, removed: 0, modified: filteredFiles.length },\n metadata: { trigger: 'file_watcher' },\n });\n }\n\n /**\n * Run all configured quality gates\n */\n private async runQualityGates(\n event: TaskCompletionEvent\n ): Promise<QualityGateResult[]> {\n const results: QualityGateResult[] = [];\n\n // Run linter first (fastest)\n if (this.config.qualityGates.runLinter) {\n results.push(await this.runLinter(event.files));\n }\n\n // Run tests (slower)\n if (this.config.qualityGates.runTests) {\n results.push(await this.runTests(event.files));\n }\n\n // Check test coverage\n if (this.config.qualityGates.requireTestCoverage) {\n results.push(await this.checkTestCoverage(event.files));\n }\n\n // Run code review (slowest, most thorough)\n if (this.config.qualityGates.runCodeReview) {\n results.push(await this.runCodeReview(event));\n }\n\n return results;\n }\n\n /**\n * Run linter on changed files\n */\n private async runLinter(files: string[]): Promise<QualityGateResult> {\n const start = Date.now();\n\n try {\n if (!this.config.testFrameworks.lintCommand) {\n return {\n gate: 'linter',\n passed: true,\n output: 'No lint command configured',\n duration: Date.now() - start,\n };\n }\n\n const output = execSync(this.config.testFrameworks.lintCommand, {\n cwd: this.config.projectRoot,\n encoding: 'utf-8',\n timeout: 30000, // 30 second timeout\n });\n\n return {\n gate: 'linter',\n passed: true,\n output,\n duration: Date.now() - start,\n };\n } catch (error: any) {\n return {\n gate: 'linter',\n passed: false,\n output: error.stdout || error.message,\n duration: Date.now() - start,\n issues: this.parseLintErrors(error.stdout || error.message),\n };\n }\n }\n\n /**\n * Run tests\n */\n private async runTests(files: string[]): Promise<QualityGateResult> {\n const start = Date.now();\n\n try {\n if (!this.config.testFrameworks.testCommand) {\n return {\n gate: 'tests',\n passed: true,\n output: 'No test command configured',\n duration: Date.now() - start,\n };\n }\n\n const output = execSync(this.config.testFrameworks.testCommand, {\n cwd: this.config.projectRoot,\n encoding: 'utf-8',\n timeout: 120000, // 2 minute timeout\n });\n\n return {\n gate: 'tests',\n passed: true,\n output,\n duration: Date.now() - start,\n };\n } catch (error: any) {\n return {\n gate: 'tests',\n passed: false,\n output: error.stdout || error.message,\n duration: Date.now() - start,\n issues: this.parseTestFailures(error.stdout || error.message),\n };\n }\n }\n\n /**\n * Check test coverage\n */\n private async checkTestCoverage(files: string[]): Promise<QualityGateResult> {\n const start = Date.now();\n\n try {\n if (!this.config.testFrameworks.coverageCommand) {\n return {\n gate: 'coverage',\n passed: true,\n output: 'No coverage command configured',\n duration: Date.now() - start,\n };\n }\n\n const output = execSync(this.config.testFrameworks.coverageCommand, {\n cwd: this.config.projectRoot,\n encoding: 'utf-8',\n timeout: 120000,\n });\n\n // Parse coverage percentage (simplified)\n const coverageMatch = output.match(/(\\d+\\.?\\d*)%/);\n const coverage = coverageMatch ? parseFloat(coverageMatch[1]) : 0;\n const threshold = 80; // 80% coverage threshold\n\n return {\n gate: 'coverage',\n passed: coverage >= threshold,\n output,\n duration: Date.now() - start,\n issues:\n coverage < threshold\n ? [\n {\n type: 'coverage_low',\n file: 'overall',\n message: `Coverage ${coverage}% is below threshold ${threshold}%`,\n severity: 'warning' as const,\n },\n ]\n : undefined,\n };\n } catch (error: any) {\n return {\n gate: 'coverage',\n passed: false,\n output: error.stdout || error.message,\n duration: Date.now() - start,\n issues: [\n {\n type: 'coverage_low',\n file: 'overall',\n message: 'Coverage check failed',\n severity: 'error' as const,\n },\n ],\n };\n }\n }\n\n /**\n * Run code review using AI agent\n */\n private async runCodeReview(\n event: TaskCompletionEvent\n ): Promise<QualityGateResult> {\n const start = Date.now();\n\n try {\n // This would integrate with the code review agent\n const reviewPrompt = this.generateCodeReviewPrompt(event);\n\n // For now, simulate a review (in real implementation, call agent)\n const review = await this.callCodeReviewAgent(reviewPrompt, event.files);\n\n return {\n gate: 'code_review',\n passed: !review.issues || review.issues.length === 0,\n output: review.summary,\n duration: Date.now() - start,\n issues: review.issues,\n };\n } catch (error: any) {\n return {\n gate: 'code_review',\n passed: false,\n output: `Code review failed: ${error.message}`,\n duration: Date.now() - start,\n };\n }\n }\n\n /**\n * Generate code review prompt\n */\n private generateCodeReviewPrompt(event: TaskCompletionEvent): string {\n return `\nPlease review the following code changes:\n\nTask: ${event.frameName}\nFiles changed: ${event.files.join(', ')}\nChanges: +${event.changes.added}, -${event.changes.removed}, ~${event.changes.modified}\n\nFocus areas: ${this.config.reviewConfig.focusAreas.join(', ')}\n\nPlease check for:\n1. Security vulnerabilities\n2. Performance issues \n3. Code maintainability\n4. Correctness and logic errors\n5. Best practices adherence\n\nProvide specific, actionable feedback.\n`;\n }\n\n /**\n * Call code review agent (placeholder for actual implementation)\n */\n private async callCodeReviewAgent(\n prompt: string,\n files: string[]\n ): Promise<{\n summary: string;\n issues?: QualityIssue[];\n }> {\n // This would integrate with Claude Code's agent system\n // For now, return a mock review\n return {\n summary: `Reviewed ${files.length} files. Code quality looks good.`,\n issues: [],\n };\n }\n\n /**\n * Parse lint errors into structured issues\n */\n private parseLintErrors(output: string): QualityIssue[] {\n const issues: QualityIssue[] = [];\n\n // Simple parser for common lint formats\n const lines = output.split('\\n');\n for (const line of lines) {\n const match = line.match(\n /^(.+?):(\\d+):(\\d+):\\s*(error|warning):\\s*(.+)$/\n );\n if (match) {\n issues.push({\n type: 'lint_error',\n file: match[1],\n line: parseInt(match[2]),\n message: match[5],\n severity: match[4] as 'error' | 'warning',\n });\n }\n }\n\n return issues;\n }\n\n /**\n * Parse test failures into structured issues\n */\n private parseTestFailures(output: string): QualityIssue[] {\n const issues: QualityIssue[] = [];\n\n // Simple parser for test failures\n const lines = output.split('\\n');\n for (const line of lines) {\n if (line.includes('FAIL') || line.includes('\u2717')) {\n issues.push({\n type: 'test_failure',\n file: 'unknown',\n message: line.trim(),\n severity: 'error',\n });\n }\n }\n\n return issues;\n }\n\n /**\n * Block further work when quality gates fail\n */\n private async blockFurtherWork(results: QualityGateResult[]): Promise<void> {\n const failedGates = results.filter((r) => !r.passed);\n\n console.log('\uD83D\uDEAB Quality gates failed - blocking further work:');\n failedGates.forEach((gate) => {\n console.log(` ${gate.gate}: ${gate.output}`);\n if (gate.issues) {\n gate.issues.forEach((issue) => {\n console.log(\n ` - ${issue.severity}: ${issue.message} (${issue.file}:${issue.line || 0})`\n );\n });\n }\n });\n\n console.log('\\n\uD83D\uDD27 Fix these issues before continuing:');\n const allIssues = failedGates.flatMap((g) => g.issues || []);\n allIssues.forEach((issue, i) => {\n console.log(`${i + 1}. ${issue.message}`);\n });\n }\n\n /**\n * Record quality results in frame metadata\n */\n private async recordQualityResults(\n frameId: string,\n results: QualityGateResult[]\n ): Promise<void> {\n try {\n const frame = await this.frameManager.getFrame(frameId);\n if (frame) {\n frame.metadata = {\n ...frame.metadata,\n qualityGates: {\n timestamp: new Date().toISOString(),\n results,\n passed: results.every((r) => r.passed),\n totalDuration: results.reduce((sum, r) => sum + r.duration, 0),\n },\n };\n\n // Update frame with quality results\n await this.frameManager.updateFrame(frameId, frame);\n }\n } catch (error: unknown) {\n console.error('Failed to record quality results:', error);\n }\n }\n\n /**\n * Extract files from frame data\n */\n private extractFilesFromFrame(frameData: any): string[] {\n // Extract file paths from various possible locations\n const files: string[] = [];\n\n if (frameData.metadata?.files) {\n files.push(...frameData.metadata.files);\n }\n\n if (frameData.events) {\n frameData.events.forEach((event: any) => {\n if (event.type === 'file_change' && event.data?.file) {\n files.push(event.data.file);\n }\n });\n }\n\n return [...new Set(files)]; // Remove duplicates\n }\n\n /**\n * Calculate changes from frame data\n */\n private calculateChanges(frameData: any): {\n added: number;\n removed: number;\n modified: number;\n } {\n return {\n added: frameData.metadata?.linesAdded || 0,\n removed: frameData.metadata?.linesRemoved || 0,\n modified: frameData.metadata?.filesModified || 1,\n };\n }\n\n /**\n * Stop post-task hooks\n */\n async stop(): Promise<void> {\n this.isActive = false;\n this.removeAllListeners();\n console.log('\uD83D\uDED1 Post-task hooks stopped');\n }\n\n /**\n * Get current configuration\n */\n getConfig(): PostTaskConfig {\n return { ...this.config };\n }\n\n /**\n * Update configuration\n */\n updateConfig(updates: Partial<PostTaskConfig>): void {\n this.config = { ...this.config, ...updates };\n this.emit('config:updated', this.config);\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|