claudeck 1.3.1 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/README.md +13 -9
  2. package/db/sqlite.js +1697 -0
  3. package/db.js +3 -1645
  4. package/package.json +2 -1
  5. package/plugins/claude-editor/manifest.json +10 -0
  6. package/plugins/linear/manifest.json +10 -0
  7. package/plugins/repos/manifest.json +10 -0
  8. package/public/css/ui/messages.css +25 -0
  9. package/public/css/ui/right-panel.css +207 -0
  10. package/public/css/ui/settings.css +75 -0
  11. package/public/index.html +7 -0
  12. package/public/js/components/settings-modal.js +65 -0
  13. package/public/js/core/api.js +23 -6
  14. package/public/js/core/events.js +11 -0
  15. package/public/js/core/plugin-loader.js +96 -11
  16. package/public/js/core/store.js +11 -0
  17. package/public/js/core/ws.js +12 -0
  18. package/public/js/features/chat.js +4 -0
  19. package/public/js/features/sessions.js +102 -10
  20. package/public/js/main.js +1 -0
  21. package/public/js/panels/assistant-bot.js +16 -0
  22. package/public/js/panels/dev-docs.js +2 -2
  23. package/public/js/panels/memory.js +1 -0
  24. package/public/js/ui/context-gauge.js +10 -1
  25. package/public/js/ui/header-dropdowns.js +30 -0
  26. package/public/js/ui/input-meta.js +13 -6
  27. package/public/js/ui/max-turns.js +6 -3
  28. package/public/js/ui/messages.js +42 -0
  29. package/public/js/ui/model-selector.js +1 -0
  30. package/public/js/ui/parallel.js +2 -4
  31. package/public/js/ui/permissions.js +1 -0
  32. package/public/js/ui/tab-sdk.js +395 -176
  33. package/public/style.css +1 -0
  34. package/server/agent-loop.js +26 -26
  35. package/server/memory-extractor.js +4 -4
  36. package/server/memory-injector.js +11 -11
  37. package/server/memory-optimizer.js +19 -15
  38. package/server/notification-logger.js +5 -5
  39. package/server/orchestrator.js +15 -15
  40. package/server/push-sender.js +2 -2
  41. package/server/routes/agents.js +2 -2
  42. package/server/routes/marketplace.js +316 -0
  43. package/server/routes/memory.js +20 -20
  44. package/server/routes/messages.js +41 -10
  45. package/server/routes/notifications.js +20 -20
  46. package/server/routes/sessions.js +17 -17
  47. package/server/routes/stats.js +37 -37
  48. package/server/routes/worktrees.js +9 -9
  49. package/server/summarizer.js +3 -3
  50. package/server/ws-handler.js +163 -58
  51. package/server.js +20 -2
  52. package/plugins/event-stream/client.css +0 -207
  53. package/plugins/event-stream/client.js +0 -271
  54. package/plugins/sudoku/client.css +0 -196
  55. package/plugins/sudoku/client.js +0 -329
  56. package/plugins/tasks/client.css +0 -414
  57. package/plugins/tasks/client.js +0 -394
  58. package/plugins/tasks/server.js +0 -116
  59. package/plugins/tic-tac-toe/client.css +0 -167
  60. package/plugins/tic-tac-toe/client.js +0 -241
package/public/style.css CHANGED
@@ -24,6 +24,7 @@
24
24
  @import url("css/panels/git-panel.css");
25
25
 
26
26
  @import url("css/panels/mcp-manager.css");
27
+ @import url("css/ui/settings.css");
27
28
  @import url("css/ui/image-attachments.css");
28
29
  @import url("css/panels/tips-feed.css");
29
30
  @import url("css/ui/context-gauge.css");
@@ -40,7 +40,7 @@ import { logNotification } from "./notification-logger.js";
40
40
  * Build the agent system prompt that instructs Claude to work autonomously
41
41
  * toward the given goal.
42
42
  */
43
- function buildAgentPrompt(agentDef, userContext, sharedContext, cwd) {
43
+ async function buildAgentPrompt(agentDef, userContext, sharedContext, cwd) {
44
44
  let prompt = `You are an autonomous AI agent. Work toward the following goal step by step, using any tools available to you.\n\n`;
45
45
  prompt += `## Goal\n${agentDef.goal}\n\n`;
46
46
  if (userContext) {
@@ -48,7 +48,7 @@ function buildAgentPrompt(agentDef, userContext, sharedContext, cwd) {
48
48
  }
49
49
  // Inject persistent memories from previous sessions
50
50
  if (cwd) {
51
- const memoryPrompt = buildAgentMemoryPrompt(cwd, 8);
51
+ const memoryPrompt = await buildAgentMemoryPrompt(cwd, 8);
52
52
  if (memoryPrompt) {
53
53
  prompt += memoryPrompt + '\n\n';
54
54
  console.log(`\n══════ AGENT MEMORY INJECTION ══════`);
@@ -105,7 +105,7 @@ export async function runAgent({
105
105
  const monitorRunId = runId || `single-${Date.now()}`;
106
106
  const effectiveRunType = runType || 'single';
107
107
  try {
108
- recordAgentRunStart(monitorRunId, agentId, agentDef.title, effectiveRunType, parentRunId);
108
+ await recordAgentRunStart(monitorRunId, agentId, agentDef.title, effectiveRunType, parentRunId);
109
109
  } catch (e) { /* ignore duplicates */ }
110
110
 
111
111
  function agentSend(payload) {
@@ -161,8 +161,8 @@ export async function runAgent({
161
161
  if (resumeId) opts.resume = resumeId;
162
162
 
163
163
  // Load shared context from previous agents in this run
164
- const sharedContext = runId ? getAllAgentContext(runId) : [];
165
- const prompt = buildAgentPrompt(agentDef, userContext, sharedContext, cwd);
164
+ const sharedContext = runId ? await getAllAgentContext(runId) : [];
165
+ const prompt = await buildAgentPrompt(agentDef, userContext, sharedContext, cwd);
166
166
  let resolvedSid = clientSid;
167
167
  let claudeSessionId = null;
168
168
  let sessionModel = null;
@@ -185,15 +185,15 @@ export async function runAgent({
185
185
 
186
186
  sessionIds.set(ourSid, claudeSessionId);
187
187
 
188
- if (!getSession(ourSid)) {
189
- createSession(ourSid, claudeSessionId, projectName || "Agent Session", cwd || "");
190
- updateSessionTitle(ourSid, `Agent: ${agentDef.title}`);
188
+ if (!await getSession(ourSid)) {
189
+ await createSession(ourSid, claudeSessionId, projectName || "Agent Session", cwd || "");
190
+ await updateSessionTitle(ourSid, `Agent: ${agentDef.title}`);
191
191
  } else {
192
- updateClaudeSessionId(ourSid, claudeSessionId);
192
+ await updateClaudeSessionId(ourSid, claudeSessionId);
193
193
  }
194
194
 
195
195
  agentSend({ type: "session", sessionId: ourSid });
196
- addMessage(resolvedSid, "user", JSON.stringify({ text: `[Agent: ${agentDef.title}] ${agentDef.goal}` }), null);
196
+ await addMessage(resolvedSid, "user", JSON.stringify({ text: `[Agent: ${agentDef.title}] ${agentDef.goal}` }), null);
197
197
  continue;
198
198
  }
199
199
 
@@ -204,7 +204,7 @@ export async function runAgent({
204
204
  lastAssistantText += (lastAssistantText ? "\n\n" : "") + block.text;
205
205
  agentSend({ type: "text", text: block.text });
206
206
  if (resolvedSid) {
207
- addMessage(resolvedSid, "assistant", JSON.stringify({ text: block.text }), null);
207
+ await addMessage(resolvedSid, "assistant", JSON.stringify({ text: block.text }), null);
208
208
  }
209
209
  } else if (block.type === "tool_use") {
210
210
  turnCount++;
@@ -220,7 +220,7 @@ export async function runAgent({
220
220
  : "",
221
221
  });
222
222
  if (resolvedSid) {
223
- addMessage(resolvedSid, "tool", JSON.stringify({ id: block.id, name: block.name, input: block.input }), null);
223
+ await addMessage(resolvedSid, "tool", JSON.stringify({ id: block.id, name: block.name, input: block.input }), null);
224
224
  }
225
225
  }
226
226
  }
@@ -242,7 +242,7 @@ export async function runAgent({
242
242
  isError: block.is_error || false,
243
243
  });
244
244
  if (resolvedSid) {
245
- addMessage(resolvedSid, "tool_result", JSON.stringify({
245
+ await addMessage(resolvedSid, "tool_result", JSON.stringify({
246
246
  toolUseId: block.tool_use_id,
247
247
  content: text.slice(0, 10000),
248
248
  isError: block.is_error || false,
@@ -266,7 +266,7 @@ export async function runAgent({
266
266
  const resultModel = Object.keys(sdkMsg.modelUsage || {})[0] || sessionModel;
267
267
 
268
268
  if (resolvedSid) {
269
- addCost(resolvedSid, costUsd, durationMs, numTurns, inputTokens, outputTokens, {
269
+ await addCost(resolvedSid, costUsd, durationMs, numTurns, inputTokens, outputTokens, {
270
270
  model: resultModel,
271
271
  stopReason: sdkMsg.subtype,
272
272
  isError: 0,
@@ -280,7 +280,7 @@ export async function runAgent({
280
280
  duration_ms: durationMs,
281
281
  num_turns: numTurns,
282
282
  cost_usd: costUsd,
283
- totalCost: getTotalCost(),
283
+ totalCost: await getTotalCost(),
284
284
  input_tokens: inputTokens,
285
285
  output_tokens: outputTokens,
286
286
  cache_read_tokens: cacheReadTokens,
@@ -301,11 +301,11 @@ export async function runAgent({
301
301
 
302
302
  // Record completion for monitoring
303
303
  try {
304
- recordAgentRunComplete(monitorRunId, agentId, 'completed', numTurns, costUsd, durationMs, inputTokens, outputTokens);
304
+ await recordAgentRunComplete(monitorRunId, agentId, 'completed', numTurns, costUsd, durationMs, inputTokens, outputTokens);
305
305
  } catch (e) { /* ignore */ }
306
306
 
307
307
  // Log notification
308
- logNotification('agent', `Agent "${agentDef.title}" completed`,
308
+ await logNotification('agent', `Agent "${agentDef.title}" completed`,
309
309
  `${numTurns} turns · $${costUsd.toFixed(4)} · ${(durationMs / 1000).toFixed(1)}s`,
310
310
  JSON.stringify({ costUsd, durationMs, inputTokens, outputTokens, turns: numTurns }),
311
311
  resolvedSid, agentId);
@@ -315,7 +315,7 @@ export async function runAgent({
315
315
  const summary = lastAssistantText.length > 4000
316
316
  ? lastAssistantText.slice(0, 4000) + "\n\n[truncated]"
317
317
  : lastAssistantText;
318
- setAgentContext(runId, agentId, "output", summary);
318
+ await setAgentContext(runId, agentId, "output", summary);
319
319
  }
320
320
  } else if (sdkMsg.subtype?.startsWith("error")) {
321
321
  const errMsg = sdkMsg.errors?.join(", ") || "Unknown error";
@@ -329,14 +329,14 @@ export async function runAgent({
329
329
  const resultModel = Object.keys(sdkMsg.modelUsage || {})[0] || sessionModel;
330
330
 
331
331
  if (resolvedSid) {
332
- addCost(resolvedSid, costUsd, durationMs, numTurns, inputTokens, outputTokens, {
332
+ await addCost(resolvedSid, costUsd, durationMs, numTurns, inputTokens, outputTokens, {
333
333
  model: resultModel,
334
334
  stopReason: sdkMsg.subtype,
335
335
  isError: 1,
336
336
  cacheReadTokens,
337
337
  cacheCreationTokens,
338
338
  });
339
- addMessage(resolvedSid, "error", JSON.stringify({ error: errMsg, subtype: sdkMsg.subtype }), null);
339
+ await addMessage(resolvedSid, "error", JSON.stringify({ error: errMsg, subtype: sdkMsg.subtype }), null);
340
340
  }
341
341
 
342
342
  lastAgentMetrics = { durationMs, costUsd, inputTokens, outputTokens, model: resultModel, turns: numTurns, isError: true, error: errMsg };
@@ -345,11 +345,11 @@ export async function runAgent({
345
345
 
346
346
  // Record error for monitoring
347
347
  try {
348
- recordAgentRunComplete(monitorRunId, agentId, 'error', numTurns, costUsd, durationMs, inputTokens, outputTokens, errMsg);
348
+ await recordAgentRunComplete(monitorRunId, agentId, 'error', numTurns, costUsd, durationMs, inputTokens, outputTokens, errMsg);
349
349
  } catch (e) { /* ignore */ }
350
350
 
351
351
  // Log error notification
352
- logNotification('error', `Agent "${agentDef.title}" failed`,
352
+ await logNotification('error', `Agent "${agentDef.title}" failed`,
353
353
  errMsg.slice(0, 200),
354
354
  JSON.stringify({ costUsd, durationMs, error: errMsg }),
355
355
  resolvedSid, agentId);
@@ -361,11 +361,11 @@ export async function runAgent({
361
361
  if (err.name === "AbortError") {
362
362
  agentSend({ type: "agent_aborted", agentId, turn: turnCount });
363
363
  agentSend({ type: "aborted" });
364
- try { recordAgentRunComplete(monitorRunId, agentId, 'aborted', turnCount, 0, 0, 0, 0, 'Aborted'); } catch (e) { /* ignore */ }
364
+ try { await recordAgentRunComplete(monitorRunId, agentId, 'aborted', turnCount, 0, 0, 0, 0, 'Aborted'); } catch (e) { /* ignore */ }
365
365
  } else {
366
366
  agentSend({ type: "agent_error", agentId, error: err.message, turn: turnCount });
367
367
  agentSend({ type: "error", error: err.message });
368
- try { recordAgentRunComplete(monitorRunId, agentId, 'error', turnCount, 0, 0, 0, 0, err.message); } catch (e) { /* ignore */ }
368
+ try { await recordAgentRunComplete(monitorRunId, agentId, 'error', turnCount, 0, 0, 0, 0, err.message); } catch (e) { /* ignore */ }
369
369
  }
370
370
  throw err; // Re-throw so callers (chains, DAGs) know the agent failed
371
371
  } finally {
@@ -413,8 +413,8 @@ export async function runAgent({
413
413
  // Auto-capture memories from agent output
414
414
  if (cwd && lastAssistantText) {
415
415
  try {
416
- const explicitCount = saveExplicitMemories(cwd, lastAssistantText, resolvedSid);
417
- const autoCount = captureMemories(cwd, lastAssistantText, resolvedSid, agentId);
416
+ const explicitCount = await saveExplicitMemories(cwd, lastAssistantText, resolvedSid);
417
+ const autoCount = await captureMemories(cwd, lastAssistantText, resolvedSid, agentId);
418
418
  const totalCaptured = explicitCount + autoCount;
419
419
  if (totalCaptured > 0) {
420
420
  console.log(`Captured ${totalCaptured} memories (${explicitCount} explicit, ${autoCount} auto) from agent ${agentId}`);
@@ -107,7 +107,7 @@ export function extractMemories(text) {
107
107
  * @param {string|null} agentId - Source agent ID (for agent runs)
108
108
  * @returns {number} Number of new memories saved
109
109
  */
110
- export function captureMemories(projectPath, assistantText, sessionId = null, agentId = null) {
110
+ export async function captureMemories(projectPath, assistantText, sessionId = null, agentId = null) {
111
111
  if (!projectPath || !assistantText) return 0;
112
112
 
113
113
  const extracted = extractMemories(assistantText);
@@ -115,7 +115,7 @@ export function captureMemories(projectPath, assistantText, sessionId = null, ag
115
115
 
116
116
  for (const { category, content } of extracted) {
117
117
  try {
118
- const result = createMemory(projectPath, category, content, sessionId, agentId);
118
+ const result = await createMemory(projectPath, category, content, sessionId, agentId);
119
119
  if (!result.isDuplicate) saved++;
120
120
  } catch {
121
121
  // Ignore individual save errors
@@ -129,10 +129,10 @@ export function captureMemories(projectPath, assistantText, sessionId = null, ag
129
129
  * Run memory maintenance for a project.
130
130
  * Call this on session start to decay stale memories and clean expired ones.
131
131
  */
132
- export function runMaintenance(projectPath) {
132
+ export async function runMaintenance(projectPath) {
133
133
  if (!projectPath) return;
134
134
  try {
135
- maintainMemories(projectPath);
135
+ await maintainMemories(projectPath);
136
136
  } catch {
137
137
  // Non-critical — don't break session startup
138
138
  }
@@ -36,11 +36,11 @@ function dedup(memories) {
36
36
  * @param {string|null} userMessage - Current user message for relevance matching
37
37
  * @returns {{ prompt: string|null, count: number }}
38
38
  */
39
- export function buildMemoryPrompt(projectPath, limit = 10, userMessage = null) {
39
+ export async function buildMemoryPrompt(projectPath, limit = 10, userMessage = null) {
40
40
  if (!projectPath) return { prompt: null, count: 0 };
41
41
 
42
42
  // Get top memories by relevance score
43
- let memories = getTopMemories(projectPath, limit);
43
+ let memories = await getTopMemories(projectPath, limit);
44
44
 
45
45
  // If we have a user message, also search for query-relevant memories
46
46
  if (userMessage && userMessage.length > 10) {
@@ -53,7 +53,7 @@ export function buildMemoryPrompt(projectPath, limit = 10, userMessage = null) {
53
53
  .filter(w => w.length > 2 && !stopWords.has(w));
54
54
 
55
55
  if (keywords.length > 0) {
56
- const queryRelevant = searchMemories(projectPath, keywords.join(' '), limit);
56
+ const queryRelevant = await searchMemories(projectPath, keywords.join(' '), limit);
57
57
  memories = dedup([...memories, ...queryRelevant]);
58
58
  }
59
59
  } catch {
@@ -68,7 +68,7 @@ export function buildMemoryPrompt(projectPath, limit = 10, userMessage = null) {
68
68
 
69
69
  // Touch each memory to boost relevance on access
70
70
  for (const m of memories) {
71
- touchMemory(m.id);
71
+ await touchMemory(m.id);
72
72
  }
73
73
 
74
74
  let prompt = `## Project Memory (persistent knowledge from previous sessions)\n`;
@@ -100,14 +100,14 @@ export function buildMemoryPrompt(projectPath, limit = 10, userMessage = null) {
100
100
  /**
101
101
  * Build a shorter memory section for agent prompts (tighter budget).
102
102
  */
103
- export function buildAgentMemoryPrompt(projectPath, limit = 8) {
103
+ export async function buildAgentMemoryPrompt(projectPath, limit = 8) {
104
104
  if (!projectPath) return null;
105
105
 
106
- const memories = getTopMemories(projectPath, limit);
106
+ const memories = await getTopMemories(projectPath, limit);
107
107
  if (!memories || memories.length === 0) return null;
108
108
 
109
109
  for (const m of memories) {
110
- touchMemory(m.id);
110
+ await touchMemory(m.id);
111
111
  }
112
112
 
113
113
  let prompt = `## Prior Knowledge\n`;
@@ -157,7 +157,7 @@ export function parseMemoryBlocks(text) {
157
157
  * @param {string|null} sessionId
158
158
  * @returns {number} count of saved memories
159
159
  */
160
- export function saveExplicitMemories(projectPath, assistantText, sessionId = null) {
160
+ export async function saveExplicitMemories(projectPath, assistantText, sessionId = null) {
161
161
  if (!projectPath || !assistantText) return 0;
162
162
 
163
163
  const blocks = parseMemoryBlocks(assistantText);
@@ -165,7 +165,7 @@ export function saveExplicitMemories(projectPath, assistantText, sessionId = nul
165
165
 
166
166
  for (const { category, content } of blocks) {
167
167
  try {
168
- const result = createMemory(projectPath, category, content, sessionId, null);
168
+ const result = await createMemory(projectPath, category, content, sessionId, null);
169
169
  if (!result.isDuplicate) saved++;
170
170
  } catch {
171
171
  // Ignore individual save errors
@@ -188,7 +188,7 @@ export function saveExplicitMemories(projectPath, assistantText, sessionId = nul
188
188
  * @param {string|null} sessionId
189
189
  * @returns {{ saved: boolean, content: string, category: string }|null}
190
190
  */
191
- export function parseRememberCommand(message, projectPath, sessionId = null) {
191
+ export async function parseRememberCommand(message, projectPath, sessionId = null) {
192
192
  if (!message || !projectPath) return null;
193
193
 
194
194
  const trimmed = message.trim();
@@ -213,7 +213,7 @@ export function parseRememberCommand(message, projectPath, sessionId = null) {
213
213
  const content = text.slice(0, 300);
214
214
 
215
215
  try {
216
- const result = createMemory(projectPath, category, content, sessionId, null);
216
+ const result = await createMemory(projectPath, category, content, sessionId, null);
217
217
  return { saved: !result.isDuplicate, content, category };
218
218
  } catch {
219
219
  return null;
@@ -7,7 +7,7 @@
7
7
  */
8
8
  import { query } from "@anthropic-ai/claude-code";
9
9
  import { execPath } from "process";
10
- import { listMemories, createMemory, deleteMemory, getDb } from "../db.js";
10
+ import { listMemories, getDb } from "../db.js";
11
11
 
12
12
  const VALID_CATEGORIES = new Set(["convention", "decision", "discovery", "warning"]);
13
13
 
@@ -163,7 +163,7 @@ function parseOptimizerOutput(text) {
163
163
  */
164
164
  export async function optimizeMemories(projectPath, onProgress = () => {}) {
165
165
  // 1. Load all memories
166
- const allMemories = listMemories(projectPath);
166
+ const allMemories = await listMemories(projectPath);
167
167
  if (!allMemories.length) {
168
168
  return { preview: { before: 0, after: 0, summary: "No memories to optimize." } };
169
169
  }
@@ -251,29 +251,33 @@ export async function optimizeMemories(projectPath, onProgress = () => {}) {
251
251
  * @param {Array<{category: string, content: string}>} optimized
252
252
  * @returns {{ deleted: number, created: number }}
253
253
  */
254
- export function applyOptimization(projectPath, optimized) {
254
+ export async function applyOptimization(projectPath, optimized) {
255
+ const existing = await listMemories(projectPath);
255
256
  const db = getDb();
256
257
 
257
- // Run in a transaction for atomicity
258
- const apply = db.transaction(() => {
259
- // 1. Delete all existing memories for this project
260
- const existing = listMemories(projectPath);
261
- for (const m of existing) {
262
- deleteMemory(m.id);
258
+ // Atomic transaction deletes + inserts succeed or fail together
259
+ const applyTxn = db.transaction((existingRows, newRows) => {
260
+ const del = db.prepare(`DELETE FROM memories WHERE id = ?`);
261
+ const ins = db.prepare(
262
+ `INSERT OR IGNORE INTO memories (project_path, category, content, content_hash, source_session_id, source_agent_id)
263
+ VALUES (?, ?, ?, ?, ?, ?)`
264
+ );
265
+
266
+ for (const m of existingRows) {
267
+ del.run(m.id);
263
268
  }
264
269
 
265
- // 2. Insert optimized memories
266
270
  let created = 0;
267
- for (const { category, content } of optimized) {
271
+ for (const { category, content } of newRows) {
268
272
  if (content && content.trim()) {
269
273
  const cat = VALID_CATEGORIES.has(category) ? category : "discovery";
270
- createMemory(projectPath, cat, content.trim(), null, "optimizer");
274
+ ins.run(projectPath, cat, content.trim(), null, null, "optimizer");
271
275
  created++;
272
276
  }
273
277
  }
274
-
275
- return { deleted: existing.length, created };
278
+ return created;
276
279
  });
277
280
 
278
- return apply();
281
+ const created = applyTxn(existing, optimized);
282
+ return { deleted: existing.length, created };
279
283
  }
@@ -14,14 +14,14 @@ function broadcast(payload) {
14
14
  }
15
15
  }
16
16
 
17
- export function logNotification(type, title, body = null, metadata = null, sourceSessionId = null, sourceAgentId = null) {
18
- const notification = createNotification(type, title, body, metadata, sourceSessionId, sourceAgentId);
19
- const unreadCount = getUnreadNotificationCount();
17
+ export async function logNotification(type, title, body = null, metadata = null, sourceSessionId = null, sourceAgentId = null) {
18
+ const notification = await createNotification(type, title, body, metadata, sourceSessionId, sourceAgentId);
19
+ const unreadCount = await getUnreadNotificationCount();
20
20
  broadcast({ type: "notification:new", notification, unreadCount });
21
21
  return notification;
22
22
  }
23
23
 
24
- export function broadcastReadUpdate(ids) {
25
- const unreadCount = getUnreadNotificationCount();
24
+ export async function broadcastReadUpdate(ids) {
25
+ const unreadCount = await getUnreadNotificationCount();
26
26
  broadcast({ type: "notification:read", ids, unreadCount });
27
27
  }
@@ -68,10 +68,10 @@ For each sub-task you want to delegate, output a fenced code block with the lang
68
68
  ${task}`;
69
69
  }
70
70
 
71
- function buildOrchestratorPromptWithMemory(task, agents, cwd) {
71
+ async function buildOrchestratorPromptWithMemory(task, agents, cwd) {
72
72
  let prompt = buildOrchestratorPrompt(task, agents);
73
73
  if (cwd) {
74
- const memPrompt = buildAgentMemoryPrompt(cwd, 6);
74
+ const memPrompt = await buildAgentMemoryPrompt(cwd, 6);
75
75
  if (memPrompt) {
76
76
  prompt += '\n\n' + memPrompt;
77
77
  }
@@ -186,7 +186,7 @@ export async function runOrchestrator({
186
186
  orchSend({ type: "orchestrator_phase", phase: "planning" });
187
187
 
188
188
  try {
189
- const prompt = buildOrchestratorPromptWithMemory(task, agents, cwd);
189
+ const prompt = await buildOrchestratorPromptWithMemory(task, agents, cwd);
190
190
  const q = query({ prompt, options: plannerOpts });
191
191
 
192
192
  for await (const sdkMsg of q) {
@@ -198,20 +198,20 @@ export async function runOrchestrator({
198
198
  resolvedSid = ourSid;
199
199
  sessionIds.set(ourSid, claudeSessionId);
200
200
 
201
- if (!getSession(ourSid)) {
202
- createSession(
201
+ if (!await getSession(ourSid)) {
202
+ await createSession(
203
203
  ourSid,
204
204
  claudeSessionId,
205
205
  projectName || "Orchestrator",
206
206
  cwd || "",
207
207
  );
208
- updateSessionTitle(ourSid, `Orchestrator: ${task.slice(0, 60)}`);
208
+ await updateSessionTitle(ourSid, `Orchestrator: ${task.slice(0, 60)}`);
209
209
  } else {
210
- updateClaudeSessionId(ourSid, claudeSessionId);
210
+ await updateClaudeSessionId(ourSid, claudeSessionId);
211
211
  }
212
212
 
213
213
  orchSend({ type: "session", sessionId: ourSid });
214
- addMessage(
214
+ await addMessage(
215
215
  resolvedSid,
216
216
  "user",
217
217
  JSON.stringify({ text: `[Orchestrator] ${task}` }),
@@ -226,7 +226,7 @@ export async function runOrchestrator({
226
226
  plannerText += block.text;
227
227
  orchSend({ type: "text", text: block.text });
228
228
  if (resolvedSid) {
229
- addMessage(
229
+ await addMessage(
230
230
  resolvedSid,
231
231
  "assistant",
232
232
  JSON.stringify({ text: block.text }),
@@ -252,7 +252,7 @@ export async function runOrchestrator({
252
252
  Object.keys(sdkMsg.modelUsage || {})[0] || null;
253
253
 
254
254
  if (resolvedSid) {
255
- addCost(
255
+ await addCost(
256
256
  resolvedSid,
257
257
  costUsd,
258
258
  durationMs,
@@ -274,7 +274,7 @@ export async function runOrchestrator({
274
274
  duration_ms: durationMs,
275
275
  num_turns: numTurns,
276
276
  cost_usd: costUsd,
277
- totalCost: getTotalCost(),
277
+ totalCost: await getTotalCost(),
278
278
  input_tokens: inputTokens,
279
279
  output_tokens: outputTokens,
280
280
  model: resultModel,
@@ -375,7 +375,7 @@ export async function runOrchestrator({
375
375
  if (result?.claudeSessionId) chainResumeId = result.claudeSessionId;
376
376
 
377
377
  // Read context that the agent stored
378
- const ctx = getAllAgentContext(runId).find(
378
+ const ctx = (await getAllAgentContext(runId)).find(
379
379
  (c) => c.agent_id === agentDef.id,
380
380
  );
381
381
 
@@ -439,7 +439,7 @@ export async function runOrchestrator({
439
439
  if (block.type === "text" && block.text) {
440
440
  orchSend({ type: "text", text: block.text });
441
441
  if (resolvedSid) {
442
- addMessage(
442
+ await addMessage(
443
443
  resolvedSid,
444
444
  "assistant",
445
445
  JSON.stringify({ text: block.text }),
@@ -465,7 +465,7 @@ export async function runOrchestrator({
465
465
  Object.keys(sdkMsg.modelUsage || {})[0] || null;
466
466
 
467
467
  if (resolvedSid) {
468
- addCost(
468
+ await addCost(
469
469
  resolvedSid,
470
470
  costUsd,
471
471
  durationMs,
@@ -487,7 +487,7 @@ export async function runOrchestrator({
487
487
  duration_ms: durationMs,
488
488
  num_turns: numTurns,
489
489
  cost_usd: costUsd,
490
- totalCost: getTotalCost(),
490
+ totalCost: await getTotalCost(),
491
491
  input_tokens: inputTokens,
492
492
  output_tokens: outputTokens,
493
493
  model: resultModel,
@@ -9,7 +9,7 @@ export function initPushSender(webpush) {
9
9
  export async function sendPushNotification(title, body, tag) {
10
10
  if (!webpushInstance) return;
11
11
 
12
- const subs = getAllPushSubscriptions();
12
+ const subs = await getAllPushSubscriptions();
13
13
  if (!subs.length) return;
14
14
 
15
15
  const payload = JSON.stringify({ title, body, tag });
@@ -23,7 +23,7 @@ export async function sendPushNotification(title, body, tag) {
23
23
  );
24
24
  } catch (err) {
25
25
  if (err.statusCode === 404 || err.statusCode === 410) {
26
- deletePushSubscription(sub.endpoint);
26
+ await deletePushSubscription(sub.endpoint);
27
27
  }
28
28
  }
29
29
  })
@@ -46,9 +46,9 @@ function slugify(text) {
46
46
 
47
47
  // ── Agent Context (shared memory) ──
48
48
 
49
- router.get("/context/:runId", (req, res) => {
49
+ router.get("/context/:runId", async (req, res) => {
50
50
  try {
51
- const rows = getAllAgentContext(req.params.runId);
51
+ const rows = await getAllAgentContext(req.params.runId);
52
52
  res.json(rows);
53
53
  } catch (err) {
54
54
  res.status(500).json({ error: err.message });