@claude-sessions/core 0.4.8-beta.0 → 0.4.8-beta.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.
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { P as Project, M as MessagePayload$1, a as Message, T as TitleDisplayMode, S as SummaryInfo, b as SessionTodos, c as MoveSessionResult, A as AgentInfo, d as SessionSortOptions, e as ProjectTreeData, C as CompressSessionOptions, f as SummarizeSessionOptions, g as ConversationLine, h as SearchResult, F as FileChange, i as SessionsIndex, j as SessionIndexEntry } from './types-CsXAWb1Q.js';
2
- export { q as CleanupPreview, p as ClearSessionsResult, w as CompressSessionResult, k as ContentItem, D as DeleteSessionResult, x as ProjectKnowledge, R as RenameSessionResult, s as ResumeSessionOptions, t as ResumeSessionResult, v as SessionAnalysis, n as SessionFilesSummary, l as SessionMeta, z as SessionSortField, B as SessionSortOrder, r as SessionTreeData, o as SplitSessionResult, y as SummarizeSessionResult, m as TodoItem, u as ToolUsageStats } from './types-CsXAWb1Q.js';
1
+ import { P as Project, M as MessagePayload$1, a as Message, T as TitleDisplayMode, S as SummaryInfo, b as SessionSortField, c as SessionTodos, d as MoveSessionResult, A as AgentInfo, e as SessionSortOptions, f as ProjectTreeData, C as CompressSessionOptions, g as SummarizeSessionOptions, h as ConversationLine, i as SearchResult, F as FileChange, j as SessionsIndex, k as SessionIndexEntry } from './types-CoLRUgPk.js';
2
+ export { r as CleanupPreview, q as ClearSessionsResult, x as CompressSessionResult, l as ContentItem, D as DeleteSessionResult, y as ProjectKnowledge, R as RenameSessionResult, t as ResumeSessionOptions, u as ResumeSessionResult, w as SessionAnalysis, o as SessionFilesSummary, m as SessionMeta, B as SessionSortOrder, s as SessionTreeData, p as SplitSessionResult, z as SummarizeSessionResult, n as TodoItem, v as ToolUsageStats } from './types-CoLRUgPk.js';
3
3
  import * as effect_Cause from 'effect/Cause';
4
4
  import { Effect } from 'effect';
5
5
 
@@ -71,7 +71,8 @@ declare const findProjectByWorkspacePath: (workspacePath: string, projectNames:
71
71
  * Sort projects with priority:
72
72
  * 1. Current project (if specified)
73
73
  * 2. Current user's home directory subpaths
74
- * 3. Others (alphabetically by displayName)
74
+ * 3. Most recently modified first (by newest session file mtime)
75
+ * 4. Alphabetically by displayName as tiebreaker
75
76
  */
76
77
  declare const sortProjects: (projects: Project[], options?: {
77
78
  currentProjectName?: string | null;
@@ -126,13 +127,28 @@ declare function getDisplayTitle(customTitle: string | undefined, currentSummary
126
127
  */
127
128
  declare const maskHomePath: (text: string, homeDir: string) => string;
128
129
  /**
129
- * Get sort timestamp for session (Unix timestamp ms)
130
- * Priority: summaries[0].timestamp > createdAt > 0
130
+ * Get summary-based sort timestamp for session (Unix timestamp ms)
131
+ * Used for 'summary' sort field. Priority: summaries[0].timestamp > createdAt > 0
131
132
  */
133
+ declare const getSummarySortTimestamp: (session: {
134
+ summaries?: SummaryInfo[];
135
+ createdAt?: string;
136
+ }) => number;
137
+ /** @deprecated Use getSummarySortTimestamp instead */
132
138
  declare const getSessionSortTimestamp: (session: {
133
139
  summaries?: SummaryInfo[];
134
140
  createdAt?: string;
135
141
  }) => number;
142
+ /**
143
+ * Get display-ready sort timestamp based on active sort field.
144
+ * Returns the timestamp matching what the user sees as the sort order.
145
+ */
146
+ declare const getDisplaySortTimestamp: (session: {
147
+ summaries?: SummaryInfo[];
148
+ createdAt?: string;
149
+ updatedAt?: string;
150
+ fileMtime?: number;
151
+ }, sortField: SessionSortField) => number;
136
152
  /**
137
153
  * Try to parse a single JSON line, returning null on failure with optional warning log
138
154
  * Use this when you want to skip invalid lines instead of throwing
@@ -503,6 +519,7 @@ declare const previewCleanup: (projectName?: string) => Effect.Effect<{
503
519
  emptyWithTodosCount: number;
504
520
  orphanAgentCount: number;
505
521
  orphanTodoCount: number;
522
+ isStale: boolean;
506
523
  }[], effect_Cause.UnknownException, never>;
507
524
  declare const clearSessions: (options: {
508
525
  projectName?: string;
@@ -511,12 +528,15 @@ declare const clearSessions: (options: {
511
528
  skipWithTodos?: boolean;
512
529
  clearOrphanAgents?: boolean;
513
530
  clearOrphanTodos?: boolean;
531
+ clearStale?: boolean;
532
+ staleProjects?: string[];
514
533
  }) => Effect.Effect<{
515
534
  success: true;
516
535
  deletedCount: number;
517
536
  removedMessageCount: number;
518
537
  deletedOrphanAgentCount: number;
519
538
  deletedOrphanTodoCount: number;
539
+ deletedStaleProjectCount: number;
520
540
  }, effect_Cause.UnknownException, never>;
521
541
 
522
542
  declare const searchSessions: (query: string, options?: {
@@ -593,9 +613,7 @@ declare function validateChain(messages: readonly GenericMessage[]): ValidationR
593
613
  errors: ChainError[];
594
614
  };
595
615
  /**
596
- * Validate for unwanted progress messages (hook outputs)
597
- *
598
- * Only 'Stop' hookEvent is treated as an error (should be removed)
616
+ * Validate for unwanted cleanup artifacts that should not remain in sessions.
599
617
  */
600
618
  declare function validateProgressMessages(messages: readonly GenericMessage[]): ValidationResult & {
601
619
  errors: ProgressError[];
@@ -690,4 +708,4 @@ declare const getLogger: () => Logger;
690
708
  */
691
709
  declare const createLogger: (namespace: string) => Logger;
692
710
 
693
- export { AgentInfo, type ChainError, CompressSessionOptions, ConversationLine, type DisplayTitleOptions, FileChange, type GenericMessage, type Logger, Message, MessagePayload$1 as MessagePayload, MoveSessionResult, type ProgressError, Project, ProjectTreeData, SearchResult, SessionIndexEntry, SessionSortOptions, SessionTodos, SessionsIndex, SummarizeSessionOptions, SummaryInfo, TREE_ICONS, TitleDisplayMode, type ToolUseResultError, type TreeItemType, type ValidationResult, analyzeSession, autoRepairChain, canMoveSession, clearSessions, compressSession, createLogger, deleteLinkedTodos, deleteMessage, deleteMessageWithChainRepair, deleteOrphanAgents, deleteOrphanTodos, deleteSession, expandHomePath, extractProjectKnowledge, extractTextContent, extractTitle, findLinkedAgents, findLinkedTodos, findOrphanAgents, findOrphanTodos, findProjectByWorkspacePath, folderNameToDisplayPath, folderNameToPath, formatRelativeTime, generateTreeNodeId, getCachePath, getDisplayTitle, getIndexEntryDisplayTitle, getLogger, getRealPathFromSession, getSessionFiles, getSessionSortTimestamp, getSessionTooltip, getSessionsDir, getTodoIcon, getTodosDir, getTotalTodoCount, hasSessionsIndex, isContinuationSummary, isInvalidApiKeyMessage, listProjects, listSessions, loadAgentMessages, loadProjectTreeData, loadSessionTreeData, loadSessionsIndex, maskHomePath, moveSession, parseCommandMessage, parseJsonlLines, parseTreeNodeId, pathToFolderName, previewCleanup, readJsonlFile, readSession, renameSession, repairChain, repairParentUuidChain, restoreMessage, searchSessions, sessionHasSubItems, sessionHasTodos, setLogger, sortIndexEntriesByModified, sortProjects, splitSession, summarizeSession, tryParseJsonLine, updateSessionSummary, validateChain, validateProgressMessages, validateToolUseResult };
711
+ export { AgentInfo, type ChainError, CompressSessionOptions, ConversationLine, type DisplayTitleOptions, FileChange, type GenericMessage, type Logger, Message, MessagePayload$1 as MessagePayload, MoveSessionResult, type ProgressError, Project, ProjectTreeData, SearchResult, SessionIndexEntry, SessionSortField, SessionSortOptions, SessionTodos, SessionsIndex, SummarizeSessionOptions, SummaryInfo, TREE_ICONS, TitleDisplayMode, type ToolUseResultError, type TreeItemType, type ValidationResult, analyzeSession, autoRepairChain, canMoveSession, clearSessions, compressSession, createLogger, deleteLinkedTodos, deleteMessage, deleteMessageWithChainRepair, deleteOrphanAgents, deleteOrphanTodos, deleteSession, expandHomePath, extractProjectKnowledge, extractTextContent, extractTitle, findLinkedAgents, findLinkedTodos, findOrphanAgents, findOrphanTodos, findProjectByWorkspacePath, folderNameToDisplayPath, folderNameToPath, formatRelativeTime, generateTreeNodeId, getCachePath, getDisplaySortTimestamp, getDisplayTitle, getIndexEntryDisplayTitle, getLogger, getRealPathFromSession, getSessionFiles, getSessionSortTimestamp, getSessionTooltip, getSessionsDir, getSummarySortTimestamp, getTodoIcon, getTodosDir, getTotalTodoCount, hasSessionsIndex, isContinuationSummary, isInvalidApiKeyMessage, listProjects, listSessions, loadAgentMessages, loadProjectTreeData, loadSessionTreeData, loadSessionsIndex, maskHomePath, moveSession, parseCommandMessage, parseJsonlLines, parseTreeNodeId, pathToFolderName, previewCleanup, readJsonlFile, readSession, renameSession, repairChain, repairParentUuidChain, restoreMessage, searchSessions, sessionHasSubItems, sessionHasTodos, setLogger, sortIndexEntriesByModified, sortProjects, splitSession, summarizeSession, tryParseJsonLine, updateSessionSummary, validateChain, validateProgressMessages, validateToolUseResult };
package/dist/index.js CHANGED
@@ -163,10 +163,27 @@ var maskHomePath = (text, homeDir) => {
163
163
  const regex = new RegExp(`${escapedHome}(?=[/\\\\]|$)`, "g");
164
164
  return text.replace(regex, "~");
165
165
  };
166
- var getSessionSortTimestamp = (session) => {
166
+ var getSummarySortTimestamp = (session) => {
167
167
  const timestampStr = session.summaries?.[0]?.timestamp ?? session.createdAt;
168
168
  return timestampStr ? new Date(timestampStr).getTime() : 0;
169
169
  };
170
+ var getSessionSortTimestamp = getSummarySortTimestamp;
171
+ var getDisplaySortTimestamp = (session, sortField) => {
172
+ switch (sortField) {
173
+ case "updated": {
174
+ if (session.updatedAt) return new Date(session.updatedAt).getTime();
175
+ return getSummarySortTimestamp(session);
176
+ }
177
+ case "created": {
178
+ if (session.createdAt) return new Date(session.createdAt).getTime();
179
+ return getSummarySortTimestamp(session);
180
+ }
181
+ case "modified":
182
+ return session.fileMtime ?? getSummarySortTimestamp(session);
183
+ default:
184
+ return getSummarySortTimestamp(session);
185
+ }
186
+ };
170
187
  var tryParseJsonLine = (line, lineNumber, filePath) => {
171
188
  try {
172
189
  return JSON.parse(line);
@@ -410,6 +427,9 @@ var sortProjects = (projects, options = {}) => {
410
427
  if (aIsUserHome && !bIsUserHome) return -1;
411
428
  if (!aIsUserHome && bIsUserHome) return 1;
412
429
  }
430
+ const aMtime = a.lastModified ?? 0;
431
+ const bMtime = b.lastModified ?? 0;
432
+ if (aMtime !== bMtime) return bMtime - aMtime;
413
433
  return a.displayName.localeCompare(b.displayName);
414
434
  });
415
435
  };
@@ -519,8 +539,8 @@ var findOrphanAgentsWithPaths = (projectName) => Effect2.gen(function* () {
519
539
  }
520
540
  for (const entry of files) {
521
541
  const entryPath = path2.join(projectPath, entry);
522
- const stat4 = yield* Effect2.tryPromise(() => fs3.stat(entryPath).catch(() => null));
523
- if (stat4?.isDirectory() && !entry.startsWith(".")) {
542
+ const stat6 = yield* Effect2.tryPromise(() => fs3.stat(entryPath).catch(() => null));
543
+ if (stat6?.isDirectory() && !entry.startsWith(".")) {
524
544
  const subagentsPath = path2.join(entryPath, "subagents");
525
545
  const subagentsExists = yield* Effect2.tryPromise(
526
546
  () => fs3.stat(subagentsPath).then(() => true).catch(() => false)
@@ -838,11 +858,24 @@ var listProjects = Effect4.gen(function* () {
838
858
  const files = yield* Effect4.tryPromise(() => fs5.readdir(projectPath));
839
859
  const sessionFiles = files.filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
840
860
  const displayName = yield* Effect4.tryPromise(() => folderNameToPath(entry.name));
861
+ let lastModified = 0;
862
+ if (sessionFiles.length > 0) {
863
+ const stats = yield* Effect4.all(
864
+ sessionFiles.map(
865
+ (f) => Effect4.tryPromise(
866
+ () => fs5.stat(path4.join(projectPath, f)).then((s) => s.mtimeMs)
867
+ ).pipe(Effect4.orElseSucceed(() => 0))
868
+ ),
869
+ { concurrency: 20 }
870
+ );
871
+ lastModified = stats.reduce((max, value) => value > max ? value : max, 0);
872
+ }
841
873
  return {
842
874
  name: entry.name,
843
875
  displayName,
844
876
  path: projectPath,
845
- sessionCount: sessionFiles.length
877
+ sessionCount: sessionFiles.length,
878
+ lastModified
846
879
  };
847
880
  })
848
881
  ),
@@ -917,19 +950,7 @@ function validateProgressMessages(messages) {
917
950
  const errors = [];
918
951
  for (let i = 0; i < messages.length; i++) {
919
952
  const msg = messages[i];
920
- if (msg.type === "progress") {
921
- const progressMsg = msg;
922
- const hookEvent = progressMsg.hookEvent ?? progressMsg.data?.hookEvent;
923
- const hookName = progressMsg.hookName ?? progressMsg.data?.hookName;
924
- if (hookEvent === "Stop") {
925
- errors.push({
926
- type: "unwanted_progress",
927
- line: i + 1,
928
- hookEvent,
929
- hookName
930
- });
931
- }
932
- } else if (msg.type === "saved_hook_context") {
953
+ if (msg.type === "saved_hook_context") {
933
954
  errors.push({
934
955
  type: "unwanted_progress",
935
956
  line: i + 1,
@@ -1219,8 +1240,8 @@ var deleteSession = (projectName, sessionId) => Effect5.gen(function* () {
1219
1240
  const projectPath = path5.join(sessionsDir, projectName);
1220
1241
  const filePath = path5.join(projectPath, `${sessionId}.jsonl`);
1221
1242
  const linkedAgents = yield* findLinkedAgents(projectName, sessionId);
1222
- const stat4 = yield* Effect5.tryPromise(() => fs6.stat(filePath));
1223
- if (stat4.size === 0) {
1243
+ const stat6 = yield* Effect5.tryPromise(() => fs6.stat(filePath));
1244
+ if (stat6.size === 0) {
1224
1245
  yield* Effect5.tryPromise(() => fs6.unlink(filePath));
1225
1246
  const agentBackupDir2 = path5.join(projectPath, ".bak");
1226
1247
  yield* Effect5.tryPromise(() => fs6.mkdir(agentBackupDir2, { recursive: true }));
@@ -1610,7 +1631,7 @@ var loadSessionTreeDataInternal = (projectName, sessionId, summariesByTargetSess
1610
1631
  }
1611
1632
  const todos = yield* findLinkedTodos(sessionId, linkedAgentIds);
1612
1633
  const createdAt = firstMessage?.timestamp ?? void 0;
1613
- const sortTimestamp = getSessionSortTimestamp({ summaries, createdAt });
1634
+ const sortTimestamp = getSummarySortTimestamp({ summaries, createdAt });
1614
1635
  return {
1615
1636
  id: sessionId,
1616
1637
  projectName,
@@ -1709,12 +1730,16 @@ var buildProjectTreeResult = (project, sessions, sort) => {
1709
1730
  if (isErrorSessionTitle(s.currentSummary)) return false;
1710
1731
  return true;
1711
1732
  });
1733
+ const displaySessions = filteredSessions.map((s) => ({
1734
+ ...s,
1735
+ sortTimestamp: getDisplaySortTimestamp(s, sort.field)
1736
+ }));
1712
1737
  return {
1713
1738
  name: project.name,
1714
1739
  displayName: project.displayName,
1715
1740
  path: project.path,
1716
- sessionCount: filteredSessions.length,
1717
- sessions: filteredSessions
1741
+ sessionCount: displaySessions.length,
1742
+ sessions: displaySessions
1718
1743
  };
1719
1744
  };
1720
1745
  var buildTreeCache = (globalUuidMap, allSummaries, sessions, fileMtimes) => {
@@ -1741,7 +1766,7 @@ var updateSessionSummaries = (cached, summariesByTargetSession) => {
1741
1766
  const oldJson = JSON.stringify(cached.summaries);
1742
1767
  const newJson = JSON.stringify(newSummaries);
1743
1768
  if (oldJson === newJson) return cached;
1744
- const newSortTimestamp = getSessionSortTimestamp({
1769
+ const newSortTimestamp = getSummarySortTimestamp({
1745
1770
  summaries: newSummaries,
1746
1771
  createdAt: cached.createdAt
1747
1772
  });
@@ -1770,8 +1795,8 @@ var loadProjectTreeData = (projectName, sortOptions) => Effect6.gen(function* ()
1770
1795
  (file) => Effect6.gen(function* () {
1771
1796
  const filePath = path7.join(projectPath, file);
1772
1797
  try {
1773
- const stat4 = yield* Effect6.tryPromise(() => fs8.stat(filePath));
1774
- fileMtimes.set(file.replace(".jsonl", ""), stat4.mtimeMs);
1798
+ const stat6 = yield* Effect6.tryPromise(() => fs8.stat(filePath));
1799
+ fileMtimes.set(file.replace(".jsonl", ""), stat6.mtimeMs);
1775
1800
  } catch {
1776
1801
  }
1777
1802
  })
@@ -2027,9 +2052,12 @@ var compressSession = (projectName, sessionId, options = {}) => Effect7.gen(func
2027
2052
  const messagesToRemove = [];
2028
2053
  const filteredMessages = messages.filter((msg, idx) => {
2029
2054
  if (msg.type === "progress") {
2030
- removedProgress++;
2031
- messagesToRemove.push(msg);
2032
- return false;
2055
+ const hookEvent = (typeof msg.hookEvent === "string" ? msg.hookEvent : void 0) ?? (typeof msg.data === "object" && msg.data !== null && "hookEvent" in msg.data ? msg.data.hookEvent : void 0);
2056
+ if (hookEvent !== "Stop") {
2057
+ removedProgress++;
2058
+ messagesToRemove.push(msg);
2059
+ return false;
2060
+ }
2033
2061
  }
2034
2062
  if (msg.type === "custom-title") {
2035
2063
  if (customTitleIndices.length > 1 && idx !== customTitleIndices[customTitleIndices.length - 1]) {
@@ -2216,6 +2244,7 @@ var summarizeSession = (projectName, sessionId, options = {}) => Effect7.gen(fun
2216
2244
  import { Effect as Effect8 } from "effect";
2217
2245
  import * as fs10 from "fs/promises";
2218
2246
  import * as path9 from "path";
2247
+ import * as os2 from "os";
2219
2248
  var cleanInvalidMessages = (projectName, sessionId) => Effect8.gen(function* () {
2220
2249
  const filePath = path9.join(getSessionsDir(), projectName, `${sessionId}.jsonl`);
2221
2250
  const content = yield* Effect8.tryPromise(() => fs10.readFile(filePath, "utf-8"));
@@ -2263,9 +2292,32 @@ var previewCleanup = (projectName) => Effect8.gen(function* () {
2263
2292
  const targetProjects = projectName ? projects.filter((p) => p.name === projectName) : projects;
2264
2293
  const orphanTodos = yield* findOrphanTodos();
2265
2294
  const orphanTodoCount = orphanTodos.length;
2295
+ const homeDir = os2.homedir();
2296
+ const staleSet = /* @__PURE__ */ new Set();
2297
+ yield* Effect8.all(
2298
+ targetProjects.map(
2299
+ (project) => Effect8.tryPromise(async () => {
2300
+ const displayPath = await folderNameToPath(project.name);
2301
+ const absPath = expandHomePath(displayPath, homeDir);
2302
+ try {
2303
+ const stats = await fs10.stat(absPath);
2304
+ if (!stats.isDirectory()) {
2305
+ staleSet.add(project.name);
2306
+ }
2307
+ } catch (error) {
2308
+ const err = error;
2309
+ if (err.code === "ENOENT") {
2310
+ staleSet.add(project.name);
2311
+ }
2312
+ }
2313
+ })
2314
+ ),
2315
+ { concurrency: 10 }
2316
+ );
2266
2317
  const results = yield* Effect8.all(
2267
2318
  targetProjects.map(
2268
2319
  (project) => Effect8.gen(function* () {
2320
+ const isStale = staleSet.has(project.name);
2269
2321
  const sessions = yield* listSessions(project.name);
2270
2322
  const emptySessions = sessions.filter((s) => s.messageCount === 0);
2271
2323
  const invalidSessions = sessions.filter(
@@ -2286,8 +2338,9 @@ var previewCleanup = (projectName) => Effect8.gen(function* () {
2286
2338
  invalidSessions,
2287
2339
  emptyWithTodosCount,
2288
2340
  orphanAgentCount: orphanAgents.length,
2289
- orphanTodoCount: 0
2341
+ orphanTodoCount: 0,
2290
2342
  // Will set for first project only
2343
+ isStale
2291
2344
  };
2292
2345
  })
2293
2346
  ),
@@ -2305,7 +2358,9 @@ var clearSessions = (options) => Effect8.gen(function* () {
2305
2358
  clearInvalid = true,
2306
2359
  skipWithTodos = true,
2307
2360
  clearOrphanAgents = true,
2308
- clearOrphanTodos = false
2361
+ clearOrphanTodos = false,
2362
+ clearStale = false,
2363
+ staleProjects = []
2309
2364
  } = options;
2310
2365
  const projects = yield* listProjects;
2311
2366
  const targetProjects = projectName ? projects.filter((p) => p.name === projectName) : projects;
@@ -2363,12 +2418,24 @@ var clearSessions = (options) => Effect8.gen(function* () {
2363
2418
  const result = yield* deleteOrphanTodos();
2364
2419
  deletedOrphanTodoCount = result.deletedCount;
2365
2420
  }
2421
+ let deletedStaleProjectCount = 0;
2422
+ if (clearStale && staleProjects.length > 0) {
2423
+ const sessionsDir = getSessionsDir();
2424
+ for (const staleProjectName of staleProjects) {
2425
+ const projectSessionsPath = path9.join(sessionsDir, staleProjectName);
2426
+ const deleted = yield* Effect8.tryPromise(
2427
+ () => fs10.rm(projectSessionsPath, { recursive: true, force: true }).then(() => true)
2428
+ ).pipe(Effect8.orElse(() => Effect8.succeed(false)));
2429
+ if (deleted) deletedStaleProjectCount++;
2430
+ }
2431
+ }
2366
2432
  return {
2367
2433
  success: true,
2368
2434
  deletedCount: deletedSessionCount,
2369
2435
  removedMessageCount,
2370
2436
  deletedOrphanAgentCount,
2371
- deletedOrphanTodoCount
2437
+ deletedOrphanTodoCount,
2438
+ deletedStaleProjectCount
2372
2439
  };
2373
2440
  });
2374
2441
 
@@ -2595,6 +2662,7 @@ export {
2595
2662
  formatRelativeTime,
2596
2663
  generateTreeNodeId,
2597
2664
  getCachePath,
2665
+ getDisplaySortTimestamp,
2598
2666
  getDisplayTitle,
2599
2667
  getIndexEntryDisplayTitle,
2600
2668
  getLogger,
@@ -2603,6 +2671,7 @@ export {
2603
2671
  getSessionSortTimestamp,
2604
2672
  getSessionTooltip,
2605
2673
  getSessionsDir,
2674
+ getSummarySortTimestamp,
2606
2675
  getTodoIcon,
2607
2676
  getTodosDir,
2608
2677
  getTotalTodoCount,