claudeck 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -3
- package/db/sqlite.js +1697 -0
- package/db.js +3 -1645
- package/package.json +2 -1
- package/plugins/tasks/server.js +21 -21
- package/public/css/ui/messages.css +25 -0
- package/public/js/core/api.js +23 -6
- package/public/js/core/ws.js +12 -0
- package/public/js/features/chat.js +4 -0
- package/public/js/features/sessions.js +102 -10
- package/public/js/ui/messages.js +42 -0
- package/public/js/ui/parallel.js +2 -4
- package/server/agent-loop.js +27 -26
- package/server/memory-extractor.js +4 -4
- package/server/memory-injector.js +11 -11
- package/server/memory-optimizer.js +2 -2
- package/server/notification-logger.js +5 -5
- package/server/orchestrator.js +16 -15
- package/server/push-sender.js +2 -2
- package/server/routes/agents.js +2 -2
- package/server/routes/memory.js +20 -20
- package/server/routes/messages.js +41 -10
- package/server/routes/notifications.js +20 -20
- package/server/routes/sessions.js +17 -17
- package/server/routes/stats.js +37 -37
- package/server/routes/worktrees.js +9 -9
- package/server/summarizer.js +3 -3
- package/server/ws-handler.js +153 -53
- package/server.js +2 -2
|
@@ -22,10 +22,10 @@ export function setSessionIds(map) {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
// List sessions (optionally filtered by project_path)
|
|
25
|
-
router.get("/", (req, res) => {
|
|
25
|
+
router.get("/", async (req, res) => {
|
|
26
26
|
try {
|
|
27
27
|
const projectPath = req.query.project_path || undefined;
|
|
28
|
-
const sessions = listSessions(20, projectPath);
|
|
28
|
+
const sessions = await listSessions(20, projectPath);
|
|
29
29
|
res.json(sessions);
|
|
30
30
|
} catch (err) {
|
|
31
31
|
res.status(500).json({ error: err.message });
|
|
@@ -33,11 +33,11 @@ router.get("/", (req, res) => {
|
|
|
33
33
|
});
|
|
34
34
|
|
|
35
35
|
// Search sessions
|
|
36
|
-
router.get("/search", (req, res) => {
|
|
36
|
+
router.get("/search", async (req, res) => {
|
|
37
37
|
try {
|
|
38
38
|
const q = req.query.q || "";
|
|
39
39
|
const projectPath = req.query.project_path || undefined;
|
|
40
|
-
const sessions = searchSessions(q, 20, projectPath);
|
|
40
|
+
const sessions = await searchSessions(q, 20, projectPath);
|
|
41
41
|
res.json(sessions);
|
|
42
42
|
} catch (err) {
|
|
43
43
|
res.status(500).json({ error: err.message });
|
|
@@ -54,10 +54,10 @@ router.get("/active", (req, res) => {
|
|
|
54
54
|
});
|
|
55
55
|
|
|
56
56
|
// Delete a session
|
|
57
|
-
router.delete("/:id", (req, res) => {
|
|
57
|
+
router.delete("/:id", async (req, res) => {
|
|
58
58
|
try {
|
|
59
59
|
const id = req.params.id;
|
|
60
|
-
dbDeleteSession(id);
|
|
60
|
+
await dbDeleteSession(id);
|
|
61
61
|
// Clean up sessionIds map entries for this session
|
|
62
62
|
for (const [key] of sessionIds) {
|
|
63
63
|
if (key === id || key.startsWith(id + "::")) {
|
|
@@ -71,13 +71,13 @@ router.delete("/:id", (req, res) => {
|
|
|
71
71
|
});
|
|
72
72
|
|
|
73
73
|
// Update session title
|
|
74
|
-
router.put("/:id/title", (req, res) => {
|
|
74
|
+
router.put("/:id/title", async (req, res) => {
|
|
75
75
|
try {
|
|
76
76
|
const { title } = req.body;
|
|
77
77
|
if (typeof title !== "string") {
|
|
78
78
|
return res.status(400).json({ error: "title is required" });
|
|
79
79
|
}
|
|
80
|
-
updateSessionTitle(req.params.id, title.slice(0, 200));
|
|
80
|
+
await updateSessionTitle(req.params.id, title.slice(0, 200));
|
|
81
81
|
res.json({ ok: true });
|
|
82
82
|
} catch (err) {
|
|
83
83
|
res.status(500).json({ error: err.message });
|
|
@@ -85,9 +85,9 @@ router.put("/:id/title", (req, res) => {
|
|
|
85
85
|
});
|
|
86
86
|
|
|
87
87
|
// Toggle session pin
|
|
88
|
-
router.put("/:id/pin", (req, res) => {
|
|
88
|
+
router.put("/:id/pin", async (req, res) => {
|
|
89
89
|
try {
|
|
90
|
-
toggleSessionPin(req.params.id);
|
|
90
|
+
await toggleSessionPin(req.params.id);
|
|
91
91
|
res.json({ ok: true });
|
|
92
92
|
} catch (err) {
|
|
93
93
|
res.status(500).json({ error: err.message });
|
|
@@ -107,15 +107,15 @@ router.post("/:id/summary", async (req, res) => {
|
|
|
107
107
|
// ── Session Branching / Forking ─────────────────────────
|
|
108
108
|
|
|
109
109
|
// Fork a session at a given message
|
|
110
|
-
router.post("/:id/fork", (req, res) => {
|
|
110
|
+
router.post("/:id/fork", async (req, res) => {
|
|
111
111
|
try {
|
|
112
112
|
const { messageId } = req.body || {};
|
|
113
|
-
const session = getSession(req.params.id);
|
|
113
|
+
const session = await getSession(req.params.id);
|
|
114
114
|
if (!session) return res.status(404).json({ error: "Session not found" });
|
|
115
115
|
if (messageId != null && (typeof messageId !== "number" || messageId < 1)) {
|
|
116
116
|
return res.status(400).json({ error: "Invalid messageId" });
|
|
117
117
|
}
|
|
118
|
-
const forked = dbForkSession(req.params.id, messageId || null);
|
|
118
|
+
const forked = await dbForkSession(req.params.id, messageId || null);
|
|
119
119
|
res.json(forked);
|
|
120
120
|
} catch (err) {
|
|
121
121
|
const status = err.message === "No messages to fork" || err.message === "Session not found" ? 400 : 500;
|
|
@@ -124,18 +124,18 @@ router.post("/:id/fork", (req, res) => {
|
|
|
124
124
|
});
|
|
125
125
|
|
|
126
126
|
// List direct child forks of a session
|
|
127
|
-
router.get("/:id/branches", (req, res) => {
|
|
127
|
+
router.get("/:id/branches", async (req, res) => {
|
|
128
128
|
try {
|
|
129
|
-
res.json(getSessionBranches(req.params.id));
|
|
129
|
+
res.json(await getSessionBranches(req.params.id));
|
|
130
130
|
} catch (err) {
|
|
131
131
|
res.status(500).json({ error: err.message });
|
|
132
132
|
}
|
|
133
133
|
});
|
|
134
134
|
|
|
135
135
|
// Get full ancestor chain + siblings
|
|
136
|
-
router.get("/:id/lineage", (req, res) => {
|
|
136
|
+
router.get("/:id/lineage", async (req, res) => {
|
|
137
137
|
try {
|
|
138
|
-
res.json(getSessionLineage(req.params.id));
|
|
138
|
+
res.json(await getSessionLineage(req.params.id));
|
|
139
139
|
} catch (err) {
|
|
140
140
|
res.status(500).json({ error: err.message });
|
|
141
141
|
}
|
package/server/routes/stats.js
CHANGED
|
@@ -74,15 +74,15 @@ router.get("/account", async (req, res) => {
|
|
|
74
74
|
});
|
|
75
75
|
|
|
76
76
|
// Cost dashboard
|
|
77
|
-
router.get("/dashboard", (req, res) => {
|
|
77
|
+
router.get("/dashboard", async (req, res) => {
|
|
78
78
|
try {
|
|
79
79
|
const projectPath = req.query.project_path || undefined;
|
|
80
|
-
const sessions = getSessionCosts(projectPath);
|
|
81
|
-
const timeline = getCostTimeline(projectPath);
|
|
82
|
-
const totalCost = getTotalCost();
|
|
83
|
-
const projectCost = projectPath ? getProjectCost(projectPath) : null;
|
|
84
|
-
const totalTokens = getTotalTokens();
|
|
85
|
-
const projectTokens = projectPath ? getProjectTokens(projectPath) : null;
|
|
80
|
+
const sessions = await getSessionCosts(projectPath);
|
|
81
|
+
const timeline = await getCostTimeline(projectPath);
|
|
82
|
+
const totalCost = await getTotalCost();
|
|
83
|
+
const projectCost = projectPath ? await getProjectCost(projectPath) : null;
|
|
84
|
+
const totalTokens = await getTotalTokens();
|
|
85
|
+
const projectTokens = projectPath ? await getProjectTokens(projectPath) : null;
|
|
86
86
|
res.json({ sessions, timeline, totalCost, projectCost, totalTokens, projectTokens });
|
|
87
87
|
} catch (err) {
|
|
88
88
|
res.status(500).json({ error: err.message });
|
|
@@ -90,27 +90,27 @@ router.get("/dashboard", (req, res) => {
|
|
|
90
90
|
});
|
|
91
91
|
|
|
92
92
|
// Analytics dashboard
|
|
93
|
-
router.get("/analytics", (req, res) => {
|
|
93
|
+
router.get("/analytics", async (req, res) => {
|
|
94
94
|
try {
|
|
95
95
|
const projectPath = req.query.project_path || undefined;
|
|
96
96
|
res.json({
|
|
97
|
-
overview: getAnalyticsOverview(projectPath),
|
|
98
|
-
dailyBreakdown: getDailyBreakdown(projectPath),
|
|
99
|
-
hourlyActivity: getHourlyActivity(projectPath),
|
|
100
|
-
projectBreakdown: getProjectBreakdown(),
|
|
101
|
-
topSessions: getTopSessionsByCost(projectPath),
|
|
102
|
-
toolUsage: getToolUsage(projectPath),
|
|
103
|
-
toolErrors: getToolErrors(projectPath),
|
|
104
|
-
sessionDepth: getSessionDepth(projectPath),
|
|
105
|
-
msgLength: getMsgLengthDistribution(projectPath),
|
|
106
|
-
topBashCommands: getTopBashCommands(projectPath),
|
|
107
|
-
topFiles: getTopFiles(projectPath),
|
|
108
|
-
errorCategories: getErrorCategories(projectPath),
|
|
109
|
-
errorTimeline: getErrorTimeline(projectPath),
|
|
110
|
-
errorsByTool: getErrorsByTool(projectPath),
|
|
111
|
-
recentErrors: getRecentErrors(projectPath),
|
|
112
|
-
modelUsage: getModelUsage(projectPath),
|
|
113
|
-
cacheEfficiency: getCacheEfficiency(projectPath),
|
|
97
|
+
overview: await getAnalyticsOverview(projectPath),
|
|
98
|
+
dailyBreakdown: await getDailyBreakdown(projectPath),
|
|
99
|
+
hourlyActivity: await getHourlyActivity(projectPath),
|
|
100
|
+
projectBreakdown: await getProjectBreakdown(),
|
|
101
|
+
topSessions: await getTopSessionsByCost(projectPath),
|
|
102
|
+
toolUsage: await getToolUsage(projectPath),
|
|
103
|
+
toolErrors: await getToolErrors(projectPath),
|
|
104
|
+
sessionDepth: await getSessionDepth(projectPath),
|
|
105
|
+
msgLength: await getMsgLengthDistribution(projectPath),
|
|
106
|
+
topBashCommands: await getTopBashCommands(projectPath),
|
|
107
|
+
topFiles: await getTopFiles(projectPath),
|
|
108
|
+
errorCategories: await getErrorCategories(projectPath),
|
|
109
|
+
errorTimeline: await getErrorTimeline(projectPath),
|
|
110
|
+
errorsByTool: await getErrorsByTool(projectPath),
|
|
111
|
+
recentErrors: await getRecentErrors(projectPath),
|
|
112
|
+
modelUsage: await getModelUsage(projectPath),
|
|
113
|
+
cacheEfficiency: await getCacheEfficiency(projectPath),
|
|
114
114
|
});
|
|
115
115
|
} catch (err) {
|
|
116
116
|
res.status(500).json({ error: err.message });
|
|
@@ -118,10 +118,10 @@ router.get("/analytics", (req, res) => {
|
|
|
118
118
|
});
|
|
119
119
|
|
|
120
120
|
// Home page data — yearly activity grid + overview
|
|
121
|
-
router.get("/home", (req, res) => {
|
|
121
|
+
router.get("/home", async (req, res) => {
|
|
122
122
|
try {
|
|
123
|
-
const yearlyActivity = getYearlyActivity();
|
|
124
|
-
const overview = getAnalyticsOverview();
|
|
123
|
+
const yearlyActivity = await getYearlyActivity();
|
|
124
|
+
const overview = await getAnalyticsOverview();
|
|
125
125
|
res.json({ yearlyActivity, overview });
|
|
126
126
|
} catch (err) {
|
|
127
127
|
res.status(500).json({ error: err.message });
|
|
@@ -129,14 +129,14 @@ router.get("/home", (req, res) => {
|
|
|
129
129
|
});
|
|
130
130
|
|
|
131
131
|
// Agent monitoring dashboard
|
|
132
|
-
router.get("/agent-metrics", (req, res) => {
|
|
132
|
+
router.get("/agent-metrics", async (req, res) => {
|
|
133
133
|
try {
|
|
134
134
|
res.json({
|
|
135
|
-
overview: getAgentRunsOverview(),
|
|
136
|
-
agents: getAgentRunsSummary(),
|
|
137
|
-
byType: getAgentRunsByType(),
|
|
138
|
-
daily: getAgentRunsDaily(),
|
|
139
|
-
recent: getAgentRunsRecent(30),
|
|
135
|
+
overview: await getAgentRunsOverview(),
|
|
136
|
+
agents: await getAgentRunsSummary(),
|
|
137
|
+
byType: await getAgentRunsByType(),
|
|
138
|
+
daily: await getAgentRunsDaily(),
|
|
139
|
+
recent: await getAgentRunsRecent(30),
|
|
140
140
|
});
|
|
141
141
|
} catch (err) {
|
|
142
142
|
res.status(500).json({ error: err.message });
|
|
@@ -144,11 +144,11 @@ router.get("/agent-metrics", (req, res) => {
|
|
|
144
144
|
});
|
|
145
145
|
|
|
146
146
|
// Stats — total cost (optionally filtered by project_path)
|
|
147
|
-
router.get("/", (req, res) => {
|
|
147
|
+
router.get("/", async (req, res) => {
|
|
148
148
|
try {
|
|
149
149
|
const projectPath = req.query.project_path;
|
|
150
|
-
const totalCost = getTotalCost();
|
|
151
|
-
const projectCost = projectPath ? getProjectCost(projectPath) : null;
|
|
150
|
+
const totalCost = await getTotalCost();
|
|
151
|
+
const projectCost = projectPath ? await getProjectCost(projectPath) : null;
|
|
152
152
|
res.json({ totalCost, projectCost });
|
|
153
153
|
} catch (err) {
|
|
154
154
|
res.status(500).json({ error: err.message });
|
|
@@ -15,11 +15,11 @@ import {
|
|
|
15
15
|
const router = Router();
|
|
16
16
|
|
|
17
17
|
// GET / — list worktrees for a project
|
|
18
|
-
router.get("/", (req, res) => {
|
|
18
|
+
router.get("/", async (req, res) => {
|
|
19
19
|
try {
|
|
20
20
|
const projectPath = req.query.project_path;
|
|
21
21
|
if (!projectPath) return res.status(400).json({ error: "project_path is required" });
|
|
22
|
-
const worktrees = listWorktreesByProject(projectPath);
|
|
22
|
+
const worktrees = await listWorktreesByProject(projectPath);
|
|
23
23
|
res.json(worktrees);
|
|
24
24
|
} catch (err) {
|
|
25
25
|
res.status(500).json({ error: err.message });
|
|
@@ -27,9 +27,9 @@ router.get("/", (req, res) => {
|
|
|
27
27
|
});
|
|
28
28
|
|
|
29
29
|
// GET /:id — get single worktree
|
|
30
|
-
router.get("/:id", (req, res) => {
|
|
30
|
+
router.get("/:id", async (req, res) => {
|
|
31
31
|
try {
|
|
32
|
-
const wt = getWorktreeRecord(req.params.id);
|
|
32
|
+
const wt = await getWorktreeRecord(req.params.id);
|
|
33
33
|
if (!wt) return res.status(404).json({ error: "Worktree not found" });
|
|
34
34
|
res.json(wt);
|
|
35
35
|
} catch (err) {
|
|
@@ -40,7 +40,7 @@ router.get("/:id", (req, res) => {
|
|
|
40
40
|
// GET /:id/diff — get diff for a worktree
|
|
41
41
|
router.get("/:id/diff", async (req, res) => {
|
|
42
42
|
try {
|
|
43
|
-
const wt = getWorktreeRecord(req.params.id);
|
|
43
|
+
const wt = await getWorktreeRecord(req.params.id);
|
|
44
44
|
if (!wt) return res.status(404).json({ error: "Worktree not found" });
|
|
45
45
|
|
|
46
46
|
await autoCommitWorktree(wt.worktree_path, "claudeck: auto-commit for diff");
|
|
@@ -56,7 +56,7 @@ router.get("/:id/diff", async (req, res) => {
|
|
|
56
56
|
// POST /:id/merge — squash merge worktree back to main branch
|
|
57
57
|
router.post("/:id/merge", async (req, res) => {
|
|
58
58
|
try {
|
|
59
|
-
const wt = getWorktreeRecord(req.params.id);
|
|
59
|
+
const wt = await getWorktreeRecord(req.params.id);
|
|
60
60
|
if (!wt) return res.status(404).json({ error: "Worktree not found" });
|
|
61
61
|
if (wt.status === "merged") return res.status(400).json({ error: "Already merged" });
|
|
62
62
|
if (wt.status === "discarded") return res.status(400).json({ error: "Already discarded" });
|
|
@@ -68,7 +68,7 @@ router.post("/:id/merge", async (req, res) => {
|
|
|
68
68
|
wt.project_path, wt.worktree_path, wt.branch_name, commitMessage
|
|
69
69
|
);
|
|
70
70
|
|
|
71
|
-
updateWorktreeStatus(wt.id, "merged");
|
|
71
|
+
await updateWorktreeStatus(wt.id, "merged");
|
|
72
72
|
res.json({ ok: true, hash: result.hash });
|
|
73
73
|
} catch (err) {
|
|
74
74
|
res.status(500).json({ error: err.message });
|
|
@@ -78,11 +78,11 @@ router.post("/:id/merge", async (req, res) => {
|
|
|
78
78
|
// DELETE /:id — discard worktree
|
|
79
79
|
router.delete("/:id", async (req, res) => {
|
|
80
80
|
try {
|
|
81
|
-
const wt = getWorktreeRecord(req.params.id);
|
|
81
|
+
const wt = await getWorktreeRecord(req.params.id);
|
|
82
82
|
if (!wt) return res.status(404).json({ error: "Worktree not found" });
|
|
83
83
|
|
|
84
84
|
await removeWorktree(wt.project_path, wt.worktree_path, wt.branch_name);
|
|
85
|
-
updateWorktreeStatus(wt.id, "discarded");
|
|
85
|
+
await updateWorktreeStatus(wt.id, "discarded");
|
|
86
86
|
|
|
87
87
|
res.json({ ok: true });
|
|
88
88
|
} catch (err) {
|
package/server/summarizer.js
CHANGED
|
@@ -3,10 +3,10 @@ import { execPath } from "process";
|
|
|
3
3
|
import { getMessagesNoChatId, updateSessionSummary, getSession } from "../db.js";
|
|
4
4
|
|
|
5
5
|
export async function generateSessionSummary(sessionId) {
|
|
6
|
-
const session = getSession(sessionId);
|
|
6
|
+
const session = await getSession(sessionId);
|
|
7
7
|
if (!session) return null;
|
|
8
8
|
|
|
9
|
-
const messages = getMessagesNoChatId(sessionId);
|
|
9
|
+
const messages = await getMessagesNoChatId(sessionId);
|
|
10
10
|
const conversation = [];
|
|
11
11
|
for (const msg of messages) {
|
|
12
12
|
try {
|
|
@@ -49,7 +49,7 @@ export async function generateSessionSummary(sessionId) {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
if (summary) {
|
|
52
|
-
updateSessionSummary(sessionId, summary);
|
|
52
|
+
await updateSessionSummary(sessionId, summary);
|
|
53
53
|
}
|
|
54
54
|
return summary;
|
|
55
55
|
}
|