claude-code-session-manager 0.113.0 → 0.115.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.
Files changed (49) hide show
  1. package/dist/assets/{AgentLibrary-wvrcLGGS.js → AgentLibrary-CjsZLl5e.js} +1 -1
  2. package/dist/assets/{Button-B6h0F0XT.js → Button-mj0vvcdc.js} +1 -1
  3. package/dist/assets/{DataModel-C5pW9E3u.js → DataModel-CG6ycpfG.js} +1 -1
  4. package/dist/assets/{History-BV4e8YOM.js → History-DDqLQiAN.js} +1 -1
  5. package/dist/assets/{Hooks-CrFSv4x1.js → Hooks-dRje24Nk.js} +1 -1
  6. package/dist/assets/{Library-D-GIt3EY.js → Library-Dl71nylN.js} +1 -1
  7. package/dist/assets/{ListDetail-Bco_wfs6.js → ListDetail-DcAD_cuA.js} +1 -1
  8. package/dist/assets/{MarkdownEditor-C-yHSXNV.js → MarkdownEditor-D7JTNOOp.js} +1 -1
  9. package/dist/assets/{McpServers-CfDekadG.js → McpServers-BbvbhemH.js} +1 -1
  10. package/dist/assets/Memory-dyz8ZU1e.js +8 -0
  11. package/dist/assets/{Panel-DGMEuYYG.js → Panel-BkfK-W74.js} +1 -1
  12. package/dist/assets/{Permissions-Cx2zjtYZ.js → Permissions-BnjsXblr.js} +1 -1
  13. package/dist/assets/{Plugins-Bc_W3IyR.js → Plugins-DSyTJtTp.js} +2 -2
  14. package/dist/assets/{ProvenanceBadge-DiKAUR1u.js → ProvenanceBadge-CQXSiPHq.js} +1 -1
  15. package/dist/assets/{RemoteMachines-8_77-WPD.js → RemoteMachines-li6EBPAt.js} +1 -1
  16. package/dist/assets/{SaveBar-Blpzdq1R.js → SaveBar-0aiuy1L2.js} +1 -1
  17. package/dist/assets/{Scheduler-Bd70AM4X.js → Scheduler-Ul4jiK7q.js} +1 -1
  18. package/dist/assets/{ScopeSwitcher-wxN0h4YW.js → ScopeSwitcher-DR262W_R.js} +1 -1
  19. package/dist/assets/{Settings-CQ7DA3zW.js → Settings-BwUcGuar.js} +1 -1
  20. package/dist/assets/{SkillReferenceGraph-DH1NLOiS.js → SkillReferenceGraph-fv2FJUNK.js} +1 -1
  21. package/dist/assets/{Skills-CmyRyu4_.js → Skills-BA2I-iRE.js} +1 -1
  22. package/dist/assets/{SystemPrompt-KAc3UMCd.js → SystemPrompt-BgvyrAKx.js} +1 -1
  23. package/dist/assets/{TagLibrary-C8EvHnpg.js → TagLibrary-B5rKEDVT.js} +1 -1
  24. package/dist/assets/{TiptapBody-d423mH6D.js → TiptapBody-CBxxEulT.js} +1 -1
  25. package/dist/assets/{Toggle-D1wsGE9S.js → Toggle-W944m375.js} +1 -1
  26. package/dist/assets/{ViewTabs-CjHw3kGY.js → ViewTabs-BLQrBE2n.js} +1 -1
  27. package/dist/assets/{historyTotals-DFHzqLt7.js → historyTotals-BUeyjlNY.js} +1 -1
  28. package/dist/assets/{index-Dutcsly-.css → index-HpEbvDiE.css} +1 -1
  29. package/dist/assets/{index-Ci1u018F.js → index-t37UuEZu.js} +101 -101
  30. package/dist/assets/{settingsSchema-Ctf3pZVI.js → settingsSchema-HwiOXtC7.js} +1 -1
  31. package/dist/assets/{useAgentsDirWatch-B1NBmOAe.js → useAgentsDirWatch-D0rI9G_h.js} +1 -1
  32. package/dist/assets/{useRemotePeers-BHjSJs9D.js → useRemotePeers-BipAySOB.js} +1 -1
  33. package/dist/index.html +2 -2
  34. package/package.json +1 -1
  35. package/src/main/build-info.json +4 -4
  36. package/src/main/chatRunner.cjs +8 -2
  37. package/src/main/index.cjs +0 -2
  38. package/src/main/ipcSchemas.cjs +50 -35
  39. package/src/main/lib/memoryDirResolve.cjs +139 -0
  40. package/src/main/lib/memoryIndex.cjs +98 -0
  41. package/src/main/lib/remoteDrilldown.cjs +91 -0
  42. package/src/main/lib/remoteTranscriptTail.cjs +90 -0
  43. package/src/main/memoryAggregate.cjs +15 -8
  44. package/src/main/memoryTool.cjs +151 -22
  45. package/src/main/webRemote.cjs +90 -57
  46. package/src/preload/api.d.ts +44 -52
  47. package/src/preload/index.cjs +19 -21
  48. package/dist/assets/Memory-CGGLexkR.js +0 -8
  49. package/src/main/agentMemory.cjs +0 -246
@@ -1,246 +0,0 @@
1
- /**
2
- * agentMemory.cjs — per-subagent memory backend.
3
- *
4
- * Distinct from the workspace-scoped Memory tool (memoryTool.cjs): this stores
5
- * memory entries keyed by **agentId** (the subagent name, e.g. "code-reviewer"),
6
- * not by workspace cwd. Conceptually mirrors Anthropic's "give each subagent its
7
- * own scratchpad" pattern.
8
- *
9
- * Storage: `~/.claude/session-manager/agent-memory/<agentId>.json`
10
- *
11
- * {
12
- * "agentId": "code-reviewer",
13
- * "entries": [
14
- * { "id": "mem_<ts>_<rand>", "body": "<markdown>",
15
- * "category": "command|preference|pattern|failure|workflow" (optional),
16
- * "createdAt": <epoch ms>, "updatedAt": <epoch ms> }
17
- * ],
18
- * "lastUpdated": <epoch ms>
19
- * }
20
- *
21
- * Deviation from Unleashed (which keys by projectPath hash and writes to
22
- * `~/.claudecodeui/agent-memory/<hash>.json` with raw fs.writeFile): we key by
23
- * agentId per the user's spec, write under `~/.claude/session-manager/` (the
24
- * conventional spot for this app's own state), and route every mutation through
25
- * config.cjs's writeJson / validatePath helpers.
26
- *
27
- * Hard caps:
28
- * - agentId must match /^[A-Za-z0-9._-]{1,128}$/
29
- * - entryId must match /^[A-Za-z0-9._-]{1,128}$/
30
- * - body up to 1 MiB
31
- * - up to 200 entries per agent (oldest dropped when over cap on set())
32
- */
33
-
34
- 'use strict';
35
-
36
- const { ipcMain } = require('electron');
37
- const fs = require('node:fs');
38
- const fsp = require('node:fs/promises');
39
- const path = require('node:path');
40
- const os = require('node:os');
41
- const config = require('./config.cjs');
42
-
43
- const MAX_BODY_BYTES = 1024 * 1024; // 1 MiB
44
- const MAX_ENTRIES = 200;
45
- const AGENT_ID_RE = /^[A-Za-z0-9._-]{1,128}$/;
46
- const ENTRY_ID_RE = /^[A-Za-z0-9._-]{1,128}$/;
47
-
48
- function rootDir() {
49
- return path.join(os.homedir(), '.claude', 'session-manager', 'agent-memory');
50
- }
51
-
52
- function recordPath(agentId) {
53
- if (!AGENT_ID_RE.test(agentId)) {
54
- throw new Error(`invalid agentId (must match ${AGENT_ID_RE.source})`);
55
- }
56
- return path.join(rootDir(), `${agentId}.json`);
57
- }
58
-
59
- async function ensureRoot() {
60
- await fsp.mkdir(rootDir(), { recursive: true });
61
- }
62
-
63
- function emptyRecord(agentId) {
64
- return { agentId, entries: [], lastUpdated: 0 };
65
- }
66
-
67
- async function loadRecord(agentId) {
68
- const abs = recordPath(agentId);
69
- const r = await config.readJson(abs).catch(() => ({ exists: false, data: null }));
70
- if (!r || !r.exists || !r.data) return emptyRecord(agentId);
71
- const data = r.data;
72
- if (!data || typeof data !== 'object' || !Array.isArray(data.entries)) {
73
- return emptyRecord(agentId);
74
- }
75
- return {
76
- agentId,
77
- entries: data.entries.filter(
78
- (e) => e && typeof e === 'object' && typeof e.id === 'string' && typeof e.body === 'string'
79
- ),
80
- lastUpdated: typeof data.lastUpdated === 'number' ? data.lastUpdated : 0,
81
- };
82
- }
83
-
84
- async function persist(record) {
85
- await ensureRoot();
86
- // Cap entry count: drop oldest by updatedAt (or createdAt) ascending.
87
- if (record.entries.length > MAX_ENTRIES) {
88
- record.entries = record.entries
89
- .slice()
90
- .sort((a, b) => (b.updatedAt ?? b.createdAt ?? 0) - (a.updatedAt ?? a.createdAt ?? 0))
91
- .slice(0, MAX_ENTRIES);
92
- }
93
- const abs = recordPath(record.agentId);
94
- const out = { ...record, lastUpdated: Date.now() };
95
- await config.writeJson(abs, out);
96
- return out;
97
- }
98
-
99
- // ────────────────────────────────────────────────── handlers
100
-
101
- async function list({ agentId }) {
102
- if (!AGENT_ID_RE.test(agentId || '')) {
103
- return { entries: [], agentId: agentId || '', error: 'invalid agentId' };
104
- }
105
- try {
106
- const record = await loadRecord(agentId);
107
- const entries = record.entries
108
- .slice()
109
- .sort((a, b) => (b.updatedAt ?? b.createdAt ?? 0) - (a.updatedAt ?? a.createdAt ?? 0))
110
- .map((e) => ({
111
- id: e.id,
112
- body: e.body,
113
- category: e.category ?? null,
114
- createdAt: e.createdAt ?? 0,
115
- updatedAt: e.updatedAt ?? e.createdAt ?? 0,
116
- bytes: Buffer.byteLength(e.body, 'utf8'),
117
- }));
118
- return { entries, agentId, error: null };
119
- } catch (e) {
120
- return { entries: [], agentId, error: e.message };
121
- }
122
- }
123
-
124
- async function get({ agentId, entryId }) {
125
- if (!AGENT_ID_RE.test(agentId || '') || !ENTRY_ID_RE.test(entryId || '')) {
126
- return { entry: null, error: 'invalid id' };
127
- }
128
- try {
129
- const record = await loadRecord(agentId);
130
- const entry = record.entries.find((e) => e.id === entryId) ?? null;
131
- if (!entry) return { entry: null, error: null };
132
- return {
133
- entry: {
134
- id: entry.id,
135
- body: entry.body,
136
- category: entry.category ?? null,
137
- createdAt: entry.createdAt ?? 0,
138
- updatedAt: entry.updatedAt ?? entry.createdAt ?? 0,
139
- bytes: Buffer.byteLength(entry.body, 'utf8'),
140
- },
141
- error: null,
142
- };
143
- } catch (e) {
144
- return { entry: null, error: e.message };
145
- }
146
- }
147
-
148
- async function set({ agentId, entryId, body, category }) {
149
- if (!AGENT_ID_RE.test(agentId || '')) {
150
- return { ok: false, error: 'invalid agentId' };
151
- }
152
- if (!ENTRY_ID_RE.test(entryId || '')) {
153
- return { ok: false, error: 'invalid entryId' };
154
- }
155
- if (typeof body !== 'string') {
156
- return { ok: false, error: 'body must be a string' };
157
- }
158
- const bytes = Buffer.byteLength(body, 'utf8');
159
- if (bytes > MAX_BODY_BYTES) {
160
- return { ok: false, error: `body exceeds 1 MiB cap (${bytes} bytes)` };
161
- }
162
- try {
163
- const record = await loadRecord(agentId);
164
- const now = Date.now();
165
- const idx = record.entries.findIndex((e) => e.id === entryId);
166
- if (idx >= 0) {
167
- // Update — preserve createdAt
168
- record.entries[idx] = {
169
- ...record.entries[idx],
170
- id: entryId,
171
- body,
172
- category: category ?? record.entries[idx].category ?? null,
173
- updatedAt: now,
174
- };
175
- } else {
176
- // Enforce cap on create
177
- if (record.entries.length >= MAX_ENTRIES) {
178
- return { ok: false, error: `agent at ${MAX_ENTRIES}-entry cap` };
179
- }
180
- record.entries.push({
181
- id: entryId,
182
- body,
183
- category: category ?? null,
184
- createdAt: now,
185
- updatedAt: now,
186
- });
187
- }
188
- await persist(record);
189
- return { ok: true, error: null };
190
- } catch (e) {
191
- return { ok: false, error: e.message };
192
- }
193
- }
194
-
195
- async function deleteEntry({ agentId, entryId }) {
196
- if (!AGENT_ID_RE.test(agentId || '') || !ENTRY_ID_RE.test(entryId || '')) {
197
- return { ok: false, error: 'invalid id' };
198
- }
199
- try {
200
- const record = await loadRecord(agentId);
201
- const before = record.entries.length;
202
- record.entries = record.entries.filter((e) => e.id !== entryId);
203
- if (record.entries.length === before) {
204
- // No-op delete (entry didn't exist) — treat as success, same as fs unlink ENOENT.
205
- return { ok: true, error: null };
206
- }
207
- // If we just emptied the record, remove the file outright so listProjects()
208
- // doesn't report a stale ghost agent.
209
- if (record.entries.length === 0) {
210
- const abs = recordPath(agentId);
211
- let real;
212
- try {
213
- real = config.validatePath(abs);
214
- config.validateWrite(real);
215
- await fsp.unlink(real);
216
- } catch (e) {
217
- if (e.code !== 'ENOENT') {
218
- // Fall back to persisting an empty record; better than throwing.
219
- await persist(record);
220
- }
221
- }
222
- return { ok: true, error: null };
223
- }
224
- await persist(record);
225
- return { ok: true, error: null };
226
- } catch (e) {
227
- return { ok: false, error: e.message };
228
- }
229
- }
230
-
231
- function registerAgentMemoryHandlers() {
232
- const { schemas: s, validated: v } = require('./ipcSchemas.cjs');
233
- ipcMain.handle('agent-memory:list', v(s.agentMemoryList, list));
234
- ipcMain.handle('agent-memory:get', v(s.agentMemoryGet, get));
235
- ipcMain.handle('agent-memory:set', v(s.agentMemorySet, set));
236
- ipcMain.handle('agent-memory:delete', v(s.agentMemoryDelete, deleteEntry));
237
- }
238
-
239
- module.exports = {
240
- registerAgentMemoryHandlers,
241
- // exported for tests
242
- rootDir,
243
- recordPath,
244
- AGENT_ID_RE,
245
- ENTRY_ID_RE,
246
- };