@herdctl/core 5.6.0 → 5.7.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 (54) hide show
  1. package/dist/config/__tests__/merge.test.js +1 -1
  2. package/dist/config/__tests__/merge.test.js.map +1 -1
  3. package/dist/config/schema.d.ts +10 -2
  4. package/dist/config/schema.d.ts.map +1 -1
  5. package/dist/config/schema.js +6 -2
  6. package/dist/config/schema.js.map +1 -1
  7. package/dist/scheduler/schedule-runner.d.ts.map +1 -1
  8. package/dist/scheduler/schedule-runner.js +6 -5
  9. package/dist/scheduler/schedule-runner.js.map +1 -1
  10. package/dist/state/__tests__/jsonl-parser.test.d.ts +5 -0
  11. package/dist/state/__tests__/jsonl-parser.test.d.ts.map +1 -0
  12. package/dist/state/__tests__/jsonl-parser.test.js +332 -0
  13. package/dist/state/__tests__/jsonl-parser.test.js.map +1 -0
  14. package/dist/state/__tests__/session-attribution.test.d.ts +2 -0
  15. package/dist/state/__tests__/session-attribution.test.d.ts.map +1 -0
  16. package/dist/state/__tests__/session-attribution.test.js +567 -0
  17. package/dist/state/__tests__/session-attribution.test.js.map +1 -0
  18. package/dist/state/__tests__/session-discovery.test.d.ts +2 -0
  19. package/dist/state/__tests__/session-discovery.test.d.ts.map +1 -0
  20. package/dist/state/__tests__/session-discovery.test.js +953 -0
  21. package/dist/state/__tests__/session-discovery.test.js.map +1 -0
  22. package/dist/state/__tests__/session-metadata.test.d.ts +2 -0
  23. package/dist/state/__tests__/session-metadata.test.d.ts.map +1 -0
  24. package/dist/state/__tests__/session-metadata.test.js +474 -0
  25. package/dist/state/__tests__/session-metadata.test.js.map +1 -0
  26. package/dist/state/__tests__/tool-parsing.test.d.ts +5 -0
  27. package/dist/state/__tests__/tool-parsing.test.d.ts.map +1 -0
  28. package/dist/state/__tests__/tool-parsing.test.js +315 -0
  29. package/dist/state/__tests__/tool-parsing.test.js.map +1 -0
  30. package/dist/state/index.d.ts +5 -0
  31. package/dist/state/index.d.ts.map +1 -1
  32. package/dist/state/index.js +10 -0
  33. package/dist/state/index.js.map +1 -1
  34. package/dist/state/jsonl-parser.d.ts +126 -0
  35. package/dist/state/jsonl-parser.d.ts.map +1 -0
  36. package/dist/state/jsonl-parser.js +482 -0
  37. package/dist/state/jsonl-parser.js.map +1 -0
  38. package/dist/state/session-attribution.d.ts +35 -0
  39. package/dist/state/session-attribution.d.ts.map +1 -0
  40. package/dist/state/session-attribution.js +179 -0
  41. package/dist/state/session-attribution.js.map +1 -0
  42. package/dist/state/session-discovery.d.ts +198 -0
  43. package/dist/state/session-discovery.d.ts.map +1 -0
  44. package/dist/state/session-discovery.js +555 -0
  45. package/dist/state/session-discovery.js.map +1 -0
  46. package/dist/state/session-metadata.d.ts +240 -0
  47. package/dist/state/session-metadata.d.ts.map +1 -0
  48. package/dist/state/session-metadata.js +377 -0
  49. package/dist/state/session-metadata.js.map +1 -0
  50. package/dist/state/tool-parsing.d.ts +88 -0
  51. package/dist/state/tool-parsing.d.ts.map +1 -0
  52. package/dist/state/tool-parsing.js +199 -0
  53. package/dist/state/tool-parsing.js.map +1 -0
  54. package/package.json +1 -1
@@ -0,0 +1,240 @@
1
+ /**
2
+ * Session Metadata Store
3
+ *
4
+ * Manages user-customizable metadata for Claude Code sessions.
5
+ * Metadata is stored sparsely in .herdctl/session-metadata/{agent-qualified-name}.json
6
+ * Files are only created when the first custom name is set for an agent.
7
+ */
8
+ import { z } from "zod";
9
+ /**
10
+ * Schema for a single session's metadata entry
11
+ */
12
+ export declare const SessionMetadataEntrySchema: z.ZodObject<{
13
+ customName: z.ZodOptional<z.ZodString>;
14
+ /** Auto-generated session name (extracted from JSONL summary) */
15
+ autoName: z.ZodOptional<z.ZodString>;
16
+ /** ISO 8601 timestamp of when autoName was extracted (for cache invalidation) */
17
+ autoNameMtime: z.ZodOptional<z.ZodString>;
18
+ /** First user message preview (truncated to 100 chars) */
19
+ preview: z.ZodOptional<z.ZodString>;
20
+ /** ISO 8601 timestamp of when preview was extracted (for cache invalidation) */
21
+ previewMtime: z.ZodOptional<z.ZodString>;
22
+ }, "strip", z.ZodTypeAny, {
23
+ customName?: string | undefined;
24
+ autoName?: string | undefined;
25
+ autoNameMtime?: string | undefined;
26
+ preview?: string | undefined;
27
+ previewMtime?: string | undefined;
28
+ }, {
29
+ customName?: string | undefined;
30
+ autoName?: string | undefined;
31
+ autoNameMtime?: string | undefined;
32
+ preview?: string | undefined;
33
+ previewMtime?: string | undefined;
34
+ }>;
35
+ /**
36
+ * Schema for the entire metadata file for an agent
37
+ */
38
+ export declare const SessionMetadataFileSchema: z.ZodObject<{
39
+ version: z.ZodLiteral<1>;
40
+ agentName: z.ZodString;
41
+ sessions: z.ZodRecord<z.ZodString, z.ZodObject<{
42
+ customName: z.ZodOptional<z.ZodString>;
43
+ /** Auto-generated session name (extracted from JSONL summary) */
44
+ autoName: z.ZodOptional<z.ZodString>;
45
+ /** ISO 8601 timestamp of when autoName was extracted (for cache invalidation) */
46
+ autoNameMtime: z.ZodOptional<z.ZodString>;
47
+ /** First user message preview (truncated to 100 chars) */
48
+ preview: z.ZodOptional<z.ZodString>;
49
+ /** ISO 8601 timestamp of when preview was extracted (for cache invalidation) */
50
+ previewMtime: z.ZodOptional<z.ZodString>;
51
+ }, "strip", z.ZodTypeAny, {
52
+ customName?: string | undefined;
53
+ autoName?: string | undefined;
54
+ autoNameMtime?: string | undefined;
55
+ preview?: string | undefined;
56
+ previewMtime?: string | undefined;
57
+ }, {
58
+ customName?: string | undefined;
59
+ autoName?: string | undefined;
60
+ autoNameMtime?: string | undefined;
61
+ preview?: string | undefined;
62
+ previewMtime?: string | undefined;
63
+ }>>;
64
+ }, "strip", z.ZodTypeAny, {
65
+ version: 1;
66
+ sessions: Record<string, {
67
+ customName?: string | undefined;
68
+ autoName?: string | undefined;
69
+ autoNameMtime?: string | undefined;
70
+ preview?: string | undefined;
71
+ previewMtime?: string | undefined;
72
+ }>;
73
+ agentName: string;
74
+ }, {
75
+ version: 1;
76
+ sessions: Record<string, {
77
+ customName?: string | undefined;
78
+ autoName?: string | undefined;
79
+ autoNameMtime?: string | undefined;
80
+ preview?: string | undefined;
81
+ previewMtime?: string | undefined;
82
+ }>;
83
+ agentName: string;
84
+ }>;
85
+ export type SessionMetadataEntry = z.infer<typeof SessionMetadataEntrySchema>;
86
+ export type SessionMetadataFile = z.infer<typeof SessionMetadataFileSchema>;
87
+ /**
88
+ * Store for managing user-customizable session metadata.
89
+ *
90
+ * Provides operations for getting/setting custom names for sessions.
91
+ * Data is sparse - files are only created when metadata is first set.
92
+ *
93
+ * @example
94
+ * ```typescript
95
+ * const store = new SessionMetadataStore('/path/to/.herdctl');
96
+ *
97
+ * // Set a custom name for a session
98
+ * await store.setCustomName('my-agent', 'session-123', 'Feature Work');
99
+ *
100
+ * // Get the custom name
101
+ * const name = await store.getCustomName('my-agent', 'session-123');
102
+ * // Returns: 'Feature Work'
103
+ *
104
+ * // Remove custom name
105
+ * await store.removeCustomName('my-agent', 'session-123');
106
+ * ```
107
+ */
108
+ export declare class SessionMetadataStore {
109
+ private readonly metadataDir;
110
+ private readonly cache;
111
+ /**
112
+ * Create a new SessionMetadataStore
113
+ *
114
+ * @param stateDir - Path to the .herdctl state directory
115
+ */
116
+ constructor(stateDir: string);
117
+ /**
118
+ * Get the file path for an agent's metadata
119
+ */
120
+ private getFilePath;
121
+ /**
122
+ * Load metadata for an agent from disk (or cache)
123
+ */
124
+ private loadMetadata;
125
+ /**
126
+ * Save metadata for an agent to disk
127
+ */
128
+ private saveMetadata;
129
+ /**
130
+ * Create a new empty metadata file structure
131
+ */
132
+ private createEmptyMetadata;
133
+ /**
134
+ * Get custom name for a session
135
+ *
136
+ * @param agentName - The agent's qualified name
137
+ * @param sessionId - The session ID
138
+ * @returns The custom name if set, undefined otherwise
139
+ */
140
+ getCustomName(agentName: string, sessionId: string): Promise<string | undefined>;
141
+ /**
142
+ * Set custom name for a session
143
+ *
144
+ * Creates the metadata file if it doesn't exist.
145
+ *
146
+ * @param agentName - The agent's qualified name
147
+ * @param sessionId - The session ID
148
+ * @param name - The custom name to set
149
+ */
150
+ setCustomName(agentName: string, sessionId: string, name: string): Promise<void>;
151
+ /**
152
+ * Remove custom name for a session
153
+ *
154
+ * If this was the only metadata for the session, the session entry is removed.
155
+ * If this was the only session with metadata, the file is kept but empty
156
+ * (to avoid repeatedly creating/deleting files).
157
+ *
158
+ * @param agentName - The agent's qualified name
159
+ * @param sessionId - The session ID
160
+ */
161
+ removeCustomName(agentName: string, sessionId: string): Promise<void>;
162
+ /**
163
+ * Get all metadata for an agent's sessions
164
+ *
165
+ * Useful for batch operations or displaying metadata for all sessions.
166
+ *
167
+ * @param agentName - The agent's qualified name
168
+ * @returns The full metadata file, or null if no metadata exists
169
+ */
170
+ getAgentMetadata(agentName: string): Promise<SessionMetadataFile | null>;
171
+ /**
172
+ * Get auto-generated name and its mtime for a session
173
+ *
174
+ * @param agentName - The agent's qualified name (use "adhoc" for unattributed sessions)
175
+ * @param sessionId - The session ID
176
+ * @returns Object with autoName and autoNameMtime, or undefined if not cached
177
+ */
178
+ getAutoName(agentName: string, sessionId: string): Promise<{
179
+ autoName?: string;
180
+ autoNameMtime?: string;
181
+ } | undefined>;
182
+ /**
183
+ * Set auto-generated name for a session
184
+ *
185
+ * @param agentName - The agent's qualified name (use "adhoc" for unattributed sessions)
186
+ * @param sessionId - The session ID
187
+ * @param autoName - The auto-generated name to set
188
+ * @param mtime - ISO 8601 timestamp of the session file when the name was extracted
189
+ */
190
+ setAutoName(agentName: string, sessionId: string, autoName: string, mtime: string): Promise<void>;
191
+ /**
192
+ * Batch set auto-generated names for multiple sessions
193
+ *
194
+ * More efficient than calling setAutoName repeatedly since it performs
195
+ * a single file write for all updates.
196
+ *
197
+ * @param agentName - The agent's qualified name (use "adhoc" for unattributed sessions)
198
+ * @param entries - Array of { sessionId, autoName, mtime } objects
199
+ */
200
+ batchSetAutoNames(agentName: string, entries: Array<{
201
+ sessionId: string;
202
+ autoName: string;
203
+ mtime: string;
204
+ }>): Promise<void>;
205
+ /**
206
+ * Get cached preview and its mtime for a session
207
+ *
208
+ * @param agentName - The agent's qualified name (use "adhoc" for unattributed sessions)
209
+ * @param sessionId - The session ID
210
+ * @returns Object with preview and previewMtime, or undefined if not cached
211
+ */
212
+ getPreview(agentName: string, sessionId: string): Promise<{
213
+ preview?: string;
214
+ previewMtime?: string;
215
+ } | undefined>;
216
+ /**
217
+ * Set preview for a session
218
+ *
219
+ * @param agentName - The agent's qualified name (use "adhoc" for unattributed sessions)
220
+ * @param sessionId - The session ID
221
+ * @param preview - The first user message preview text
222
+ * @param mtime - ISO 8601 timestamp of the session file when the preview was extracted
223
+ */
224
+ setPreview(agentName: string, sessionId: string, preview: string, mtime: string): Promise<void>;
225
+ /**
226
+ * Batch set previews for multiple sessions
227
+ *
228
+ * More efficient than calling setPreview repeatedly since it performs
229
+ * a single file write for all updates.
230
+ *
231
+ * @param agentName - The agent's qualified name (use "adhoc" for unattributed sessions)
232
+ * @param entries - Array of { sessionId, preview, mtime } objects
233
+ */
234
+ batchSetPreviews(agentName: string, entries: Array<{
235
+ sessionId: string;
236
+ preview: string;
237
+ mtime: string;
238
+ }>): Promise<void>;
239
+ }
240
+ //# sourceMappingURL=session-metadata.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-metadata.d.ts","sourceRoot":"","sources":["../../src/state/session-metadata.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,377 @@
1
+ /**
2
+ * Session Metadata Store
3
+ *
4
+ * Manages user-customizable metadata for Claude Code sessions.
5
+ * Metadata is stored sparsely in .herdctl/session-metadata/{agent-qualified-name}.json
6
+ * Files are only created when the first custom name is set for an agent.
7
+ */
8
+ import { mkdir } from "node:fs/promises";
9
+ import { join } from "node:path";
10
+ import { z } from "zod";
11
+ import { createLogger } from "../utils/logger.js";
12
+ import { atomicWriteJson } from "./utils/atomic.js";
13
+ import { safeReadJson } from "./utils/reads.js";
14
+ const logger = createLogger("SessionMetadataStore");
15
+ // =============================================================================
16
+ // Schemas
17
+ // =============================================================================
18
+ /**
19
+ * Schema for a single session's metadata entry
20
+ */
21
+ export const SessionMetadataEntrySchema = z.object({
22
+ customName: z.string().optional(),
23
+ /** Auto-generated session name (extracted from JSONL summary) */
24
+ autoName: z.string().optional(),
25
+ /** ISO 8601 timestamp of when autoName was extracted (for cache invalidation) */
26
+ autoNameMtime: z.string().optional(),
27
+ /** First user message preview (truncated to 100 chars) */
28
+ preview: z.string().optional(),
29
+ /** ISO 8601 timestamp of when preview was extracted (for cache invalidation) */
30
+ previewMtime: z.string().optional(),
31
+ // Future: pinned, archived, tags
32
+ });
33
+ /**
34
+ * Schema for the entire metadata file for an agent
35
+ */
36
+ export const SessionMetadataFileSchema = z.object({
37
+ version: z.literal(1),
38
+ agentName: z.string(),
39
+ sessions: z.record(z.string(), SessionMetadataEntrySchema),
40
+ });
41
+ // =============================================================================
42
+ // SessionMetadataStore
43
+ // =============================================================================
44
+ /**
45
+ * Store for managing user-customizable session metadata.
46
+ *
47
+ * Provides operations for getting/setting custom names for sessions.
48
+ * Data is sparse - files are only created when metadata is first set.
49
+ *
50
+ * @example
51
+ * ```typescript
52
+ * const store = new SessionMetadataStore('/path/to/.herdctl');
53
+ *
54
+ * // Set a custom name for a session
55
+ * await store.setCustomName('my-agent', 'session-123', 'Feature Work');
56
+ *
57
+ * // Get the custom name
58
+ * const name = await store.getCustomName('my-agent', 'session-123');
59
+ * // Returns: 'Feature Work'
60
+ *
61
+ * // Remove custom name
62
+ * await store.removeCustomName('my-agent', 'session-123');
63
+ * ```
64
+ */
65
+ export class SessionMetadataStore {
66
+ metadataDir;
67
+ cache;
68
+ /**
69
+ * Create a new SessionMetadataStore
70
+ *
71
+ * @param stateDir - Path to the .herdctl state directory
72
+ */
73
+ constructor(stateDir) {
74
+ this.metadataDir = join(stateDir, "session-metadata");
75
+ this.cache = new Map();
76
+ }
77
+ /**
78
+ * Get the file path for an agent's metadata
79
+ */
80
+ getFilePath(agentName) {
81
+ return join(this.metadataDir, `${agentName}.json`);
82
+ }
83
+ /**
84
+ * Load metadata for an agent from disk (or cache)
85
+ */
86
+ async loadMetadata(agentName) {
87
+ // Check cache first
88
+ const cached = this.cache.get(agentName);
89
+ if (cached !== undefined) {
90
+ return cached;
91
+ }
92
+ const filePath = this.getFilePath(agentName);
93
+ const result = await safeReadJson(filePath);
94
+ if (!result.success) {
95
+ // File not found is expected for sparse storage
96
+ if (result.error.code === "ENOENT") {
97
+ return null;
98
+ }
99
+ logger.warn(`Failed to read metadata file for ${agentName}: ${result.error.message}`);
100
+ return null;
101
+ }
102
+ // Validate the file structure
103
+ const parseResult = SessionMetadataFileSchema.safeParse(result.data);
104
+ if (!parseResult.success) {
105
+ logger.warn(`Corrupted metadata file for ${agentName}: ${parseResult.error.message}. Returning null.`);
106
+ return null;
107
+ }
108
+ // Cache and return
109
+ this.cache.set(agentName, parseResult.data);
110
+ return parseResult.data;
111
+ }
112
+ /**
113
+ * Save metadata for an agent to disk
114
+ */
115
+ async saveMetadata(agentName, metadata) {
116
+ // Ensure directory exists
117
+ await mkdir(this.metadataDir, { recursive: true });
118
+ const filePath = this.getFilePath(agentName);
119
+ await atomicWriteJson(filePath, metadata);
120
+ // Update cache
121
+ this.cache.set(agentName, metadata);
122
+ logger.debug(`Saved metadata for agent ${agentName}`, {
123
+ sessionCount: Object.keys(metadata.sessions).length,
124
+ });
125
+ }
126
+ /**
127
+ * Create a new empty metadata file structure
128
+ */
129
+ createEmptyMetadata(agentName) {
130
+ return {
131
+ version: 1,
132
+ agentName,
133
+ sessions: {},
134
+ };
135
+ }
136
+ /**
137
+ * Get custom name for a session
138
+ *
139
+ * @param agentName - The agent's qualified name
140
+ * @param sessionId - The session ID
141
+ * @returns The custom name if set, undefined otherwise
142
+ */
143
+ async getCustomName(agentName, sessionId) {
144
+ const metadata = await this.loadMetadata(agentName);
145
+ if (!metadata) {
146
+ return undefined;
147
+ }
148
+ return metadata.sessions[sessionId]?.customName;
149
+ }
150
+ /**
151
+ * Set custom name for a session
152
+ *
153
+ * Creates the metadata file if it doesn't exist.
154
+ *
155
+ * @param agentName - The agent's qualified name
156
+ * @param sessionId - The session ID
157
+ * @param name - The custom name to set
158
+ */
159
+ async setCustomName(agentName, sessionId, name) {
160
+ let metadata = await this.loadMetadata(agentName);
161
+ if (!metadata) {
162
+ metadata = this.createEmptyMetadata(agentName);
163
+ }
164
+ // Get or create the session entry
165
+ const sessionEntry = metadata.sessions[sessionId] ?? {};
166
+ // Update the custom name
167
+ metadata.sessions[sessionId] = {
168
+ ...sessionEntry,
169
+ customName: name,
170
+ };
171
+ await this.saveMetadata(agentName, metadata);
172
+ logger.debug(`Set custom name for session ${sessionId}`, {
173
+ agentName,
174
+ customName: name,
175
+ });
176
+ }
177
+ /**
178
+ * Remove custom name for a session
179
+ *
180
+ * If this was the only metadata for the session, the session entry is removed.
181
+ * If this was the only session with metadata, the file is kept but empty
182
+ * (to avoid repeatedly creating/deleting files).
183
+ *
184
+ * @param agentName - The agent's qualified name
185
+ * @param sessionId - The session ID
186
+ */
187
+ async removeCustomName(agentName, sessionId) {
188
+ const metadata = await this.loadMetadata(agentName);
189
+ if (!metadata) {
190
+ // No metadata file exists, nothing to remove
191
+ return;
192
+ }
193
+ const sessionEntry = metadata.sessions[sessionId];
194
+ if (!sessionEntry) {
195
+ // No entry for this session, nothing to remove
196
+ return;
197
+ }
198
+ // Remove the customName
199
+ delete sessionEntry.customName;
200
+ // If the session entry is now empty, remove it entirely
201
+ if (Object.keys(sessionEntry).length === 0) {
202
+ delete metadata.sessions[sessionId];
203
+ }
204
+ else {
205
+ metadata.sessions[sessionId] = sessionEntry;
206
+ }
207
+ await this.saveMetadata(agentName, metadata);
208
+ logger.debug(`Removed custom name for session ${sessionId}`, { agentName });
209
+ }
210
+ /**
211
+ * Get all metadata for an agent's sessions
212
+ *
213
+ * Useful for batch operations or displaying metadata for all sessions.
214
+ *
215
+ * @param agentName - The agent's qualified name
216
+ * @returns The full metadata file, or null if no metadata exists
217
+ */
218
+ async getAgentMetadata(agentName) {
219
+ return this.loadMetadata(agentName);
220
+ }
221
+ /**
222
+ * Get auto-generated name and its mtime for a session
223
+ *
224
+ * @param agentName - The agent's qualified name (use "adhoc" for unattributed sessions)
225
+ * @param sessionId - The session ID
226
+ * @returns Object with autoName and autoNameMtime, or undefined if not cached
227
+ */
228
+ async getAutoName(agentName, sessionId) {
229
+ const metadata = await this.loadMetadata(agentName);
230
+ if (!metadata) {
231
+ return undefined;
232
+ }
233
+ const entry = metadata.sessions[sessionId];
234
+ if (!entry) {
235
+ return undefined;
236
+ }
237
+ return {
238
+ autoName: entry.autoName,
239
+ autoNameMtime: entry.autoNameMtime,
240
+ };
241
+ }
242
+ /**
243
+ * Set auto-generated name for a session
244
+ *
245
+ * @param agentName - The agent's qualified name (use "adhoc" for unattributed sessions)
246
+ * @param sessionId - The session ID
247
+ * @param autoName - The auto-generated name to set
248
+ * @param mtime - ISO 8601 timestamp of the session file when the name was extracted
249
+ */
250
+ async setAutoName(agentName, sessionId, autoName, mtime) {
251
+ let metadata = await this.loadMetadata(agentName);
252
+ if (!metadata) {
253
+ metadata = this.createEmptyMetadata(agentName);
254
+ }
255
+ // Get or create the session entry
256
+ const sessionEntry = metadata.sessions[sessionId] ?? {};
257
+ // Update the auto name fields
258
+ metadata.sessions[sessionId] = {
259
+ ...sessionEntry,
260
+ autoName,
261
+ autoNameMtime: mtime,
262
+ };
263
+ await this.saveMetadata(agentName, metadata);
264
+ logger.debug(`Set auto name for session ${sessionId}`, {
265
+ agentName,
266
+ autoName,
267
+ });
268
+ }
269
+ /**
270
+ * Batch set auto-generated names for multiple sessions
271
+ *
272
+ * More efficient than calling setAutoName repeatedly since it performs
273
+ * a single file write for all updates.
274
+ *
275
+ * @param agentName - The agent's qualified name (use "adhoc" for unattributed sessions)
276
+ * @param entries - Array of { sessionId, autoName, mtime } objects
277
+ */
278
+ async batchSetAutoNames(agentName, entries) {
279
+ if (entries.length === 0) {
280
+ return;
281
+ }
282
+ let metadata = await this.loadMetadata(agentName);
283
+ if (!metadata) {
284
+ metadata = this.createEmptyMetadata(agentName);
285
+ }
286
+ // Apply all updates
287
+ for (const { sessionId, autoName, mtime } of entries) {
288
+ const sessionEntry = metadata.sessions[sessionId] ?? {};
289
+ metadata.sessions[sessionId] = {
290
+ ...sessionEntry,
291
+ autoName,
292
+ autoNameMtime: mtime,
293
+ };
294
+ }
295
+ await this.saveMetadata(agentName, metadata);
296
+ logger.debug(`Batch set auto names for ${entries.length} sessions`, {
297
+ agentName,
298
+ });
299
+ }
300
+ /**
301
+ * Get cached preview and its mtime for a session
302
+ *
303
+ * @param agentName - The agent's qualified name (use "adhoc" for unattributed sessions)
304
+ * @param sessionId - The session ID
305
+ * @returns Object with preview and previewMtime, or undefined if not cached
306
+ */
307
+ async getPreview(agentName, sessionId) {
308
+ const metadata = await this.loadMetadata(agentName);
309
+ if (!metadata) {
310
+ return undefined;
311
+ }
312
+ const entry = metadata.sessions[sessionId];
313
+ if (!entry) {
314
+ return undefined;
315
+ }
316
+ return {
317
+ preview: entry.preview,
318
+ previewMtime: entry.previewMtime,
319
+ };
320
+ }
321
+ /**
322
+ * Set preview for a session
323
+ *
324
+ * @param agentName - The agent's qualified name (use "adhoc" for unattributed sessions)
325
+ * @param sessionId - The session ID
326
+ * @param preview - The first user message preview text
327
+ * @param mtime - ISO 8601 timestamp of the session file when the preview was extracted
328
+ */
329
+ async setPreview(agentName, sessionId, preview, mtime) {
330
+ let metadata = await this.loadMetadata(agentName);
331
+ if (!metadata) {
332
+ metadata = this.createEmptyMetadata(agentName);
333
+ }
334
+ const sessionEntry = metadata.sessions[sessionId] ?? {};
335
+ metadata.sessions[sessionId] = {
336
+ ...sessionEntry,
337
+ preview,
338
+ previewMtime: mtime,
339
+ };
340
+ await this.saveMetadata(agentName, metadata);
341
+ logger.debug(`Set preview for session ${sessionId}`, {
342
+ agentName,
343
+ preview,
344
+ });
345
+ }
346
+ /**
347
+ * Batch set previews for multiple sessions
348
+ *
349
+ * More efficient than calling setPreview repeatedly since it performs
350
+ * a single file write for all updates.
351
+ *
352
+ * @param agentName - The agent's qualified name (use "adhoc" for unattributed sessions)
353
+ * @param entries - Array of { sessionId, preview, mtime } objects
354
+ */
355
+ async batchSetPreviews(agentName, entries) {
356
+ if (entries.length === 0) {
357
+ return;
358
+ }
359
+ let metadata = await this.loadMetadata(agentName);
360
+ if (!metadata) {
361
+ metadata = this.createEmptyMetadata(agentName);
362
+ }
363
+ for (const { sessionId, preview, mtime } of entries) {
364
+ const sessionEntry = metadata.sessions[sessionId] ?? {};
365
+ metadata.sessions[sessionId] = {
366
+ ...sessionEntry,
367
+ preview,
368
+ previewMtime: mtime,
369
+ };
370
+ }
371
+ await this.saveMetadata(agentName, metadata);
372
+ logger.debug(`Batch set previews for ${entries.length} sessions`, {
373
+ agentName,
374
+ });
375
+ }
376
+ }
377
+ //# sourceMappingURL=session-metadata.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-metadata.js","sourceRoot":"","sources":["../../src/state/session-metadata.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEhD,MAAM,MAAM,GAAG,YAAY,CAAC,sBAAsB,CAAC,CAAC;AAEpD,gFAAgF;AAChF,UAAU;AACV,gFAAgF;AAEhF;;GAEG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,CAAC,MAAM,CAAC;IACjD,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACjC,iEAAiE;IACjE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC/B,iFAAiF;IACjF,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACpC,0DAA0D;IAC1D,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC9B,gFAAgF;IAChF,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACnC,iCAAiC;CAClC,CAAC,CAAC;AAEH;;GAEG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC,MAAM,CAAC;IAChD,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IACrB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;IACrB,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,0BAA0B,CAAC;CAC3D,CAAC,CAAC;AAKH,gFAAgF;AAChF,uBAAuB;AACvB,gFAAgF;AAEhF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,OAAO,oBAAoB;IACd,WAAW,CAAS;IACpB,KAAK,CAAmC;IAEzD;;;;OAIG;IACH,YAAY,QAAgB;QAC1B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,QAAQ,EAAE,kBAAkB,CAAC,CAAC;QACtD,IAAI,CAAC,KAAK,GAAG,IAAI,GAAG,EAAE,CAAC;IACzB,CAAC;IAED;;OAEG;IACK,WAAW,CAAC,SAAiB;QACnC,OAAO,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,SAAS,OAAO,CAAC,CAAC;IACrD,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,YAAY,CAAC,SAAiB;QAC1C,oBAAoB;QACpB,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACzC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;QAC7C,MAAM,MAAM,GAAG,MAAM,YAAY,CAAU,QAAQ,CAAC,CAAC;QAErD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,gDAAgD;YAChD,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACnC,OAAO,IAAI,CAAC;YACd,CAAC;YAED,MAAM,CAAC,IAAI,CAAC,oCAAoC,SAAS,KAAK,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YACtF,OAAO,IAAI,CAAC;QACd,CAAC;QAED,8BAA8B;QAC9B,MAAM,WAAW,GAAG,yBAAyB,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACrE,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;YACzB,MAAM,CAAC,IAAI,CACT,+BAA+B,SAAS,KAAK,WAAW,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAC1F,CAAC;YACF,OAAO,IAAI,CAAC;QACd,CAAC;QAED,mBAAmB;QACnB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC;QAC5C,OAAO,WAAW,CAAC,IAAI,CAAC;IAC1B,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,YAAY,CAAC,SAAiB,EAAE,QAA6B;QACzE,0BAA0B;QAC1B,MAAM,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAEnD,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;QAC7C,MAAM,eAAe,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAE1C,eAAe;QACf,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QAEpC,MAAM,CAAC,KAAK,CAAC,4BAA4B,SAAS,EAAE,EAAE;YACpD,YAAY,EAAE,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,MAAM;SACpD,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACK,mBAAmB,CAAC,SAAiB;QAC3C,OAAO;YACL,OAAO,EAAE,CAAC;YACV,SAAS;YACT,QAAQ,EAAE,EAAE;SACb,CAAC;IACJ,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,aAAa,CAAC,SAAiB,EAAE,SAAiB;QACtD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;QACpD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,OAAO,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,UAAU,CAAC;IAClD,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,aAAa,CAAC,SAAiB,EAAE,SAAiB,EAAE,IAAY;QACpE,IAAI,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;QAElD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,QAAQ,GAAG,IAAI,CAAC,mBAAmB,CAAC,SAAS,CAAC,CAAC;QACjD,CAAC;QAED,kCAAkC;QAClC,MAAM,YAAY,GAAG,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;QAExD,yBAAyB;QACzB,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,GAAG;YAC7B,GAAG,YAAY;YACf,UAAU,EAAE,IAAI;SACjB,CAAC;QAEF,MAAM,IAAI,CAAC,YAAY,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QAE7C,MAAM,CAAC,KAAK,CAAC,+BAA+B,SAAS,EAAE,EAAE;YACvD,SAAS;YACT,UAAU,EAAE,IAAI;SACjB,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;;;OASG;IACH,KAAK,CAAC,gBAAgB,CAAC,SAAiB,EAAE,SAAiB;QACzD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;QAEpD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,6CAA6C;YAC7C,OAAO;QACT,CAAC;QAED,MAAM,YAAY,GAAG,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,+CAA+C;YAC/C,OAAO;QACT,CAAC;QAED,wBAAwB;QACxB,OAAO,YAAY,CAAC,UAAU,CAAC;QAE/B,wDAAwD;QACxD,IAAI,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3C,OAAO,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QACtC,CAAC;aAAM,CAAC;YACN,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,GAAG,YAAY,CAAC;QAC9C,CAAC;QAED,MAAM,IAAI,CAAC,YAAY,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QAE7C,MAAM,CAAC,KAAK,CAAC,mCAAmC,SAAS,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;IAC9E,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,gBAAgB,CAAC,SAAiB;QACtC,OAAO,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;IACtC,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,WAAW,CACf,SAAiB,EACjB,SAAiB;QAEjB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;QACpD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,MAAM,KAAK,GAAG,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QAC3C,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,OAAO;YACL,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,aAAa,EAAE,KAAK,CAAC,aAAa;SACnC,CAAC;IACJ,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,WAAW,CACf,SAAiB,EACjB,SAAiB,EACjB,QAAgB,EAChB,KAAa;QAEb,IAAI,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;QAElD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,QAAQ,GAAG,IAAI,CAAC,mBAAmB,CAAC,SAAS,CAAC,CAAC;QACjD,CAAC;QAED,kCAAkC;QAClC,MAAM,YAAY,GAAG,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;QAExD,8BAA8B;QAC9B,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,GAAG;YAC7B,GAAG,YAAY;YACf,QAAQ;YACR,aAAa,EAAE,KAAK;SACrB,CAAC;QAEF,MAAM,IAAI,CAAC,YAAY,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QAE7C,MAAM,CAAC,KAAK,CAAC,6BAA6B,SAAS,EAAE,EAAE;YACrD,SAAS;YACT,QAAQ;SACT,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,iBAAiB,CACrB,SAAiB,EACjB,OAAsE;QAEtE,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO;QACT,CAAC;QAED,IAAI,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;QAElD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,QAAQ,GAAG,IAAI,CAAC,mBAAmB,CAAC,SAAS,CAAC,CAAC;QACjD,CAAC;QAED,oBAAoB;QACpB,KAAK,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,OAAO,EAAE,CAAC;YACrD,MAAM,YAAY,GAAG,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;YACxD,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,GAAG;gBAC7B,GAAG,YAAY;gBACf,QAAQ;gBACR,aAAa,EAAE,KAAK;aACrB,CAAC;QACJ,CAAC;QAED,MAAM,IAAI,CAAC,YAAY,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QAE7C,MAAM,CAAC,KAAK,CAAC,4BAA4B,OAAO,CAAC,MAAM,WAAW,EAAE;YAClE,SAAS;SACV,CAAC,CAAC;IACL,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,UAAU,CACd,SAAiB,EACjB,SAAiB;QAEjB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;QACpD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,MAAM,KAAK,GAAG,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QAC3C,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,OAAO;YACL,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,YAAY,EAAE,KAAK,CAAC,YAAY;SACjC,CAAC;IACJ,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,UAAU,CACd,SAAiB,EACjB,SAAiB,EACjB,OAAe,EACf,KAAa;QAEb,IAAI,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;QAElD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,QAAQ,GAAG,IAAI,CAAC,mBAAmB,CAAC,SAAS,CAAC,CAAC;QACjD,CAAC;QAED,MAAM,YAAY,GAAG,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;QAExD,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,GAAG;YAC7B,GAAG,YAAY;YACf,OAAO;YACP,YAAY,EAAE,KAAK;SACpB,CAAC;QAEF,MAAM,IAAI,CAAC,YAAY,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QAE7C,MAAM,CAAC,KAAK,CAAC,2BAA2B,SAAS,EAAE,EAAE;YACnD,SAAS;YACT,OAAO;SACR,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,gBAAgB,CACpB,SAAiB,EACjB,OAAqE;QAErE,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO;QACT,CAAC;QAED,IAAI,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;QAElD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,QAAQ,GAAG,IAAI,CAAC,mBAAmB,CAAC,SAAS,CAAC,CAAC;QACjD,CAAC;QAED,KAAK,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,OAAO,EAAE,CAAC;YACpD,MAAM,YAAY,GAAG,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;YACxD,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,GAAG;gBAC7B,GAAG,YAAY;gBACf,OAAO;gBACP,YAAY,EAAE,KAAK;aACpB,CAAC;QACJ,CAAC;QAED,MAAM,IAAI,CAAC,YAAY,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QAE7C,MAAM,CAAC,KAAK,CAAC,0BAA0B,OAAO,CAAC,MAAM,WAAW,EAAE;YAChE,SAAS;SACV,CAAC,CAAC;IACL,CAAC;CACF"}