@agent-link/agent 0.1.202 → 0.1.206
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/backends/claude.d.ts +90 -0
- package/dist/backends/claude.js +356 -0
- package/dist/backends/claude.js.map +1 -0
- package/dist/backends/index.d.ts +27 -0
- package/dist/backends/index.js +52 -0
- package/dist/backends/index.js.map +1 -0
- package/dist/backends/types.d.ts +379 -0
- package/dist/backends/types.js +120 -0
- package/dist/backends/types.js.map +1 -0
- package/dist/claude.d.ts +22 -2
- package/dist/claude.js +54 -6
- package/dist/claude.js.map +1 -1
- package/dist/cli.js +62 -2
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +5 -0
- package/dist/config.js +1 -0
- package/dist/config.js.map +1 -1
- package/dist/connection.d.ts +4 -1
- package/dist/connection.js +335 -132
- package/dist/connection.js.map +1 -1
- package/dist/index.js +9 -1
- package/dist/index.js.map +1 -1
- package/dist/recap.d.ts +1 -0
- package/dist/recap.js.map +1 -1
- package/dist/runtime.d.ts +176 -0
- package/dist/runtime.js +286 -0
- package/dist/runtime.js.map +1 -0
- package/dist/search-sessions.d.ts +32 -0
- package/dist/search-sessions.js +247 -0
- package/dist/search-sessions.js.map +1 -0
- package/package.json +1 -1
package/dist/runtime.js
ADDED
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AgentRuntime — facade in front of the AgentBackend implementation.
|
|
3
|
+
*
|
|
4
|
+
* PR3 strategy: claude.ts stays unchanged. ClaudeBackend wraps it for the
|
|
5
|
+
* AgentBackend interface (used by future Codex backend). connection.ts no
|
|
6
|
+
* longer imports claude.ts directly — it goes through runtime.ts.
|
|
7
|
+
*
|
|
8
|
+
* The current runtime is a thin re-export of claude.ts's surface. Both the
|
|
9
|
+
* legacy `ChatFile` type (from claude.ts) and the backend-neutral
|
|
10
|
+
* `BackendFileAttachment` type are exported side-by-side; PR4+ will collapse
|
|
11
|
+
* `ChatFile` into an alias once connection.ts stops referencing it. The
|
|
12
|
+
* AgentBackend instance is constructed lazily on first import so that:
|
|
13
|
+
*
|
|
14
|
+
* 1) tests can `vi.mock('./claude.js', ...)` without forcing a backend
|
|
15
|
+
* construction order, and
|
|
16
|
+
* 2) connection.ts can swap in a different backend (Codex) in PR4 by
|
|
17
|
+
* changing only this file — connection.ts stays untouched.
|
|
18
|
+
*
|
|
19
|
+
* Future evolution: replace the direct re-export shim with NormalizedEvent
|
|
20
|
+
* subscription + outbound translation. As of PR3, claude.ts → ClaudeBackend
|
|
21
|
+
* already round-trips frames losslessly via `process_output` raw fanout, so
|
|
22
|
+
* the additional translation layer would be pure overhead. Adding Codex
|
|
23
|
+
* (PR4) is the natural trigger to flip this from re-export to translate.
|
|
24
|
+
*
|
|
25
|
+
* NOTE (PR3 → PR4 boundary): connection.ts currently still imports the
|
|
26
|
+
* legacy claude.ts surface through this file's re-exports and calls
|
|
27
|
+
* `claudeHandleChat` etc. directly — it does NOT yet go through
|
|
28
|
+
* `getBackend().startTurn(...)`. This is intentional for PR3: the
|
|
29
|
+
* AgentBackend boundary is in place and contract-tested via mocked
|
|
30
|
+
* unit tests (see test/agent/backends/contract-claude.test.ts), but
|
|
31
|
+
* production code still uses the legacy path. PR4 will rewire connection.ts
|
|
32
|
+
* to call `getBackend()` methods so the boundary is exercised end-to-end,
|
|
33
|
+
* at which point the re-exports below can be removed.
|
|
34
|
+
*/
|
|
35
|
+
import { createBackend } from './backends/index.js';
|
|
36
|
+
/**
|
|
37
|
+
* Instance-based runtime that owns the public conversationId↔BackendSessionRef
|
|
38
|
+
* mapping. Created and owned by `connection.ts` per connection lifecycle.
|
|
39
|
+
*
|
|
40
|
+
* Tests construct fresh instances against a stub backend directly. See
|
|
41
|
+
* docs/2026-05-11-pr4b-agent-runtime.md for the full design.
|
|
42
|
+
*/
|
|
43
|
+
export class AgentRuntime {
|
|
44
|
+
backend;
|
|
45
|
+
/** Public mapping. Backend keeps its own internal copy (legacy adaptation)
|
|
46
|
+
* until NormalizedEvent carries conversationId (PR-W1). */
|
|
47
|
+
convToSession = new Map();
|
|
48
|
+
convToWorkDir = new Map();
|
|
49
|
+
/** PR4-D: cache of session-id → full BackendSessionRef populated by
|
|
50
|
+
* listHistory(). Lets readHistory/rename/delete pass the real ref to
|
|
51
|
+
* the backend instead of synthesizing one from a bare id (which would
|
|
52
|
+
* be Claude-only). */
|
|
53
|
+
historyRefs = new Map();
|
|
54
|
+
constructor(backend) {
|
|
55
|
+
this.backend = backend;
|
|
56
|
+
}
|
|
57
|
+
/** Sync — no async work today. Kept sync to match index.ts signal handler. */
|
|
58
|
+
start() { }
|
|
59
|
+
/**
|
|
60
|
+
* Canonical async shutdown path. Called by `disconnect()` (which awaits).
|
|
61
|
+
*
|
|
62
|
+
* PR4-B note: we intentionally do NOT call `backend.shutdown()` here. The
|
|
63
|
+
* backend is a process-wide singleton (see `getBackend()` below) shared
|
|
64
|
+
* across reconnects within the same process — tearing it down on every
|
|
65
|
+
* disconnect would leave subsequent `connect()` calls holding a dead
|
|
66
|
+
* instance with detached subscribers and cleared maps. This matches the
|
|
67
|
+
* legacy claude.ts lifetime (also process-wide). PR-W1 will move backend
|
|
68
|
+
* ownership into AgentRuntime per-connection, at which point this can
|
|
69
|
+
* call `backend.shutdown()` and reset the singleton in lockstep.
|
|
70
|
+
* (Codex review #2, medium.)
|
|
71
|
+
*/
|
|
72
|
+
async shutdown() {
|
|
73
|
+
this.convToSession.clear();
|
|
74
|
+
this.convToWorkDir.clear();
|
|
75
|
+
this.historyRefs.clear();
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Sync best-effort path — only for the SIGINT/SIGTERM handler in index.ts
|
|
79
|
+
* which calls process.exit(0) immediately after. Currently equivalent to
|
|
80
|
+
* shutdown() for the Claude backend; kept as a distinct entry point so
|
|
81
|
+
* future async-cleanup backends (Codex) have a sync escape hatch wired
|
|
82
|
+
* from the signal handler.
|
|
83
|
+
*/
|
|
84
|
+
shutdownSyncBestEffort() {
|
|
85
|
+
this.convToSession.clear();
|
|
86
|
+
this.convToWorkDir.clear();
|
|
87
|
+
this.historyRefs.clear();
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Ensure a backend session exists for `convId`. Returns the cached ref
|
|
91
|
+
* unless it's still a `pending:` placeholder, in which case we re-call
|
|
92
|
+
* `backend.ensureSession` so the backend can return a now-resolved ref.
|
|
93
|
+
*/
|
|
94
|
+
async ensureConversation(convId, opts) {
|
|
95
|
+
this.convToWorkDir.set(convId, opts.workDir);
|
|
96
|
+
const cached = this.convToSession.get(convId);
|
|
97
|
+
if (cached && !cached.backendSessionId.startsWith('pending:'))
|
|
98
|
+
return cached;
|
|
99
|
+
const ref = await this.backend.ensureSession({
|
|
100
|
+
conversationId: convId,
|
|
101
|
+
workDir: opts.workDir,
|
|
102
|
+
resumeSessionId: opts.resumeSessionId,
|
|
103
|
+
});
|
|
104
|
+
this.convToSession.set(convId, ref);
|
|
105
|
+
return ref;
|
|
106
|
+
}
|
|
107
|
+
async startTurn(convId, input, opts) {
|
|
108
|
+
const ref = await this.ensureConversation(convId, opts);
|
|
109
|
+
await this.backend.startTurn(ref, input);
|
|
110
|
+
}
|
|
111
|
+
async interruptTurn(convId) {
|
|
112
|
+
const ref = this.convToSession.get(convId);
|
|
113
|
+
if (!ref)
|
|
114
|
+
return; // quiet no-op
|
|
115
|
+
await this.backend.interruptTurn(ref);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Evict the cached session ref + workDir for `convId`. Call this whenever
|
|
119
|
+
* the conversation is being reset (e.g. `new_conversation` handler) so the
|
|
120
|
+
* next `startTurn` calls `backend.ensureSession` fresh instead of reusing
|
|
121
|
+
* the stale ref — which would cause ClaudeBackend to compute
|
|
122
|
+
* `baseOptions.resumeSessionId` from the old session id and resume the
|
|
123
|
+
* just-cleared conversation. (Copilot review round 3.)
|
|
124
|
+
*/
|
|
125
|
+
evictConversation(convId) {
|
|
126
|
+
this.convToSession.delete(convId);
|
|
127
|
+
this.convToWorkDir.delete(convId);
|
|
128
|
+
}
|
|
129
|
+
// Funnelled through the runtime so we stay rooted on a single backend
|
|
130
|
+
// instance (Codex review #3). The runtime doesn't need convId here —
|
|
131
|
+
// requestId is globally unique in claude.ts.
|
|
132
|
+
answerUserInput(requestId, answers) {
|
|
133
|
+
this.backend.answerUserInput({ requestId, answers });
|
|
134
|
+
}
|
|
135
|
+
answerApproval(requestId, decision) {
|
|
136
|
+
this.backend.answerApproval({ requestId, decision });
|
|
137
|
+
}
|
|
138
|
+
// ── PR4-C: per-conversation user-action surface ─────────────────────────
|
|
139
|
+
// Backend methods are keyed by conversationId (not BackendSessionRef) so
|
|
140
|
+
// claude.ts can populate `pendingModels` for not-yet-started conversations
|
|
141
|
+
// (Codex finding B). Restart/mode setters use `hasConversation()` as the
|
|
142
|
+
// sole control-flow signal — runtime never inspects its own map for branch
|
|
143
|
+
// decisions (Codex finding A).
|
|
144
|
+
setModel(convId, model) {
|
|
145
|
+
this.backend.setModel?.(convId, model);
|
|
146
|
+
}
|
|
147
|
+
getEffectiveModel(convId) {
|
|
148
|
+
return this.backend.getEffectiveModel?.(convId) ?? null;
|
|
149
|
+
}
|
|
150
|
+
isCompacting(convId) {
|
|
151
|
+
return this.backend.isCompacting?.(convId) ?? false;
|
|
152
|
+
}
|
|
153
|
+
restartConversation(convId, opts) {
|
|
154
|
+
const result = this.backend.restartSession?.(convId, opts)
|
|
155
|
+
?? { claudeSessionId: null, wasTurnActive: false };
|
|
156
|
+
this.evictConversation(convId);
|
|
157
|
+
return result;
|
|
158
|
+
}
|
|
159
|
+
setPlanMode(convId, enabled, workDir) {
|
|
160
|
+
return this.applyModeOrPlaceholder(convId, workDir, { planMode: enabled });
|
|
161
|
+
}
|
|
162
|
+
setBrainMode(convId, enabled, workDir) {
|
|
163
|
+
return this.applyModeOrPlaceholder(convId, workDir, { brainMode: enabled });
|
|
164
|
+
}
|
|
165
|
+
setPermissionMode(convId, mode, workDir) {
|
|
166
|
+
return this.applyModeOrPlaceholder(convId, workDir, {
|
|
167
|
+
permissionMode: mode,
|
|
168
|
+
planMode: mode === 'plan', // mirrors connection.ts:972 derivation
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
applyModeOrPlaceholder(convId, workDir, opts) {
|
|
172
|
+
if (this.backend.hasConversation?.(convId)) {
|
|
173
|
+
const result = this.backend.restartSession?.(convId, opts)
|
|
174
|
+
?? { claudeSessionId: null, wasTurnActive: false };
|
|
175
|
+
this.evictConversation(convId);
|
|
176
|
+
return result;
|
|
177
|
+
}
|
|
178
|
+
this.backend.createPlaceholderSession?.(convId, workDir, opts);
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
// ── PR4-D: history surface ────────────────────────────────────────────────
|
|
182
|
+
// Returns backend-native rows; protocol mapping to legacy SessionInfo /
|
|
183
|
+
// HistoryMessage shapes happens at the connection.ts boundary.
|
|
184
|
+
/** List sessions in `workDir`. Caches each row's BackendSessionRef keyed
|
|
185
|
+
* by `session.backendSessionId` so subsequent read/rename/delete calls
|
|
186
|
+
* can use the real ref instead of a Claude-only synthesized one. */
|
|
187
|
+
async listHistory(workDir) {
|
|
188
|
+
const rows = await this.backend.listSessions(workDir);
|
|
189
|
+
for (const row of rows) {
|
|
190
|
+
this.historyRefs.set(row.session.backendSessionId, row.session);
|
|
191
|
+
}
|
|
192
|
+
return rows;
|
|
193
|
+
}
|
|
194
|
+
async readHistory(workDir, sessionId) {
|
|
195
|
+
return this.backend.readSession(workDir, this.refForHistory(sessionId));
|
|
196
|
+
}
|
|
197
|
+
/** Returns false if the backend has no rename capability OR the session
|
|
198
|
+
* was not found in `workDir`. connection.ts uses this to drive the
|
|
199
|
+
* BRAIN_DATA_DIR fallback + 1500 ms retry policy. */
|
|
200
|
+
async renameHistorySession(workDir, sessionId, title) {
|
|
201
|
+
if (!this.backend.renameSession)
|
|
202
|
+
return false;
|
|
203
|
+
return this.backend.renameSession(workDir, this.refForHistory(sessionId), title);
|
|
204
|
+
}
|
|
205
|
+
async deleteHistorySession(workDir, sessionId) {
|
|
206
|
+
if (!this.backend.deleteSession)
|
|
207
|
+
return false;
|
|
208
|
+
const ok = await this.backend.deleteSession(workDir, this.refForHistory(sessionId));
|
|
209
|
+
if (ok)
|
|
210
|
+
this.historyRefs.delete(sessionId);
|
|
211
|
+
return ok;
|
|
212
|
+
}
|
|
213
|
+
/** Look up the cached ref; fall back to a Claude-shaped one if we've
|
|
214
|
+
* never seen this id (e.g. web client resumes by sessionId before
|
|
215
|
+
* list_sessions ran). The fallback is Claude-only safe — ClaudeBackend's
|
|
216
|
+
* read/rename/delete consult only `backendSessionId`. A future Codex
|
|
217
|
+
* backend that needs `backendThreadId !== backendSessionId` MUST require
|
|
218
|
+
* list_sessions first and reject the synthesized fallback (PR6). */
|
|
219
|
+
refForHistory(sessionId) {
|
|
220
|
+
const cached = this.historyRefs.get(sessionId);
|
|
221
|
+
if (cached)
|
|
222
|
+
return cached;
|
|
223
|
+
return {
|
|
224
|
+
backendType: this.backend.type,
|
|
225
|
+
backendSessionId: sessionId,
|
|
226
|
+
backendThreadId: sessionId,
|
|
227
|
+
providerSessionId: sessionId,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
// ── Backend instance (singleton for this process) ───────────────────────────
|
|
232
|
+
let backendInstance = null;
|
|
233
|
+
/**
|
|
234
|
+
* Get (or lazily construct) the runtime's backend. The backend type is
|
|
235
|
+
* fixed at 'claude' for PR3; PR4 will add a config knob.
|
|
236
|
+
*/
|
|
237
|
+
export function getBackend() {
|
|
238
|
+
if (!backendInstance) {
|
|
239
|
+
backendInstance = createBackend('claude');
|
|
240
|
+
}
|
|
241
|
+
return backendInstance;
|
|
242
|
+
}
|
|
243
|
+
/** Test-only: reset the backend singleton between specs.
|
|
244
|
+
* Awaits shutdown() on the existing instance before nulling it out so the
|
|
245
|
+
* ClaudeBackend's addSendFn / addOnSessionStarted subscriptions are detached
|
|
246
|
+
* — otherwise stale instances keep receiving events and tests double-fire. */
|
|
247
|
+
export async function _resetBackendForTests() {
|
|
248
|
+
if (backendInstance) {
|
|
249
|
+
try {
|
|
250
|
+
await backendInstance.shutdown();
|
|
251
|
+
}
|
|
252
|
+
catch { /* ignore */ }
|
|
253
|
+
}
|
|
254
|
+
backendInstance = null;
|
|
255
|
+
}
|
|
256
|
+
// ── Re-exports from claude.ts ────────────────────────────────────────────────
|
|
257
|
+
//
|
|
258
|
+
// During PR3, claude.ts remains the source of truth for the Claude driver.
|
|
259
|
+
// connection.ts imports these from runtime.ts so a future Codex backend can
|
|
260
|
+
// drop in without changing connection.ts.
|
|
261
|
+
export { handleChat, // TODO(PR-W1): unused after PR4-B chat migration; keep for team.ts/scheduler.ts until they migrate to runtime.startTurn
|
|
262
|
+
setSendFn, // TODO(PR-W1): replace with getBackend().on(listener)
|
|
263
|
+
addSendFn, // TODO(PR-W1): replace with getBackend().on(listener)
|
|
264
|
+
abort, // TODO(PR-W1): folded into runtime.interruptTurn / shutdown
|
|
265
|
+
abortAll, // TODO(PR-W1): folded into runtime.shutdown
|
|
266
|
+
cancelExecution, // TODO(PR-W1): unused after PR4-B cancel migration; keep for team.ts/scheduler.ts
|
|
267
|
+
handleBtwQuestion, // TODO(PR-W1): plan-mode follow-up answer; deferred — requires backend.on() to replace addSendFn so workDir + fallback session id can flow through a typed answer payload (see docs/2026-05-11-pr4c-runtime-user-actions.md Codex finding #3)
|
|
268
|
+
getConversation, // TODO(PR-W2): replace with backend.readSession / listSessions
|
|
269
|
+
getConversations, // TODO(PR-W2): same
|
|
270
|
+
clearSessionId, // TODO(PR-W2): backend-internal once history surface migrates
|
|
271
|
+
evictByClaudeSessionId, // TODO(PR-W2): same
|
|
272
|
+
rebindConversation, // TODO(PR-W2): same
|
|
273
|
+
addOutputObserver, // TODO(PR-Team/Loop): team.ts/scheduler.ts inject observers; replace with runtime.subscribe(filter)
|
|
274
|
+
removeOutputObserver, // TODO(PR-Team/Loop): same
|
|
275
|
+
addCloseObserver, // TODO(PR-Team/Loop): same
|
|
276
|
+
removeCloseObserver, // TODO(PR-Team/Loop): same
|
|
277
|
+
setOutputObserver, // TODO(PR-Team/Loop): same
|
|
278
|
+
clearOutputObserver, // TODO(PR-Team/Loop): same
|
|
279
|
+
setCloseObserver, // TODO(PR-Team/Loop): same
|
|
280
|
+
clearCloseObserver, // TODO(PR-Team/Loop): same
|
|
281
|
+
getPendingQuestions, // TODO(PR-W2): expose via runtime.getPending(convId)
|
|
282
|
+
getPendingToolPermissions, // TODO(PR-W2): same
|
|
283
|
+
setOnSessionStarted, // TODO(PR-W1): replace with on(filter session_started)
|
|
284
|
+
addOnSessionStarted, // TODO(PR-W1): same
|
|
285
|
+
} from './claude.js';
|
|
286
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,EAAE,aAAa,EAAiD,MAAM,qBAAqB,CAAC;AAwBnG;;;;;;GAMG;AACH,MAAM,OAAO,YAAY;IAWM;IAV7B;gEAC4D;IAC3C,aAAa,GAAG,IAAI,GAAG,EAA6B,CAAC;IACrD,aAAa,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC3D;;;2BAGuB;IACN,WAAW,GAAG,IAAI,GAAG,EAA6B,CAAC;IAEpE,YAA6B,OAAqB;QAArB,YAAO,GAAP,OAAO,CAAc;IAAG,CAAC;IAEtD,8EAA8E;IAC9E,KAAK,KAAmE,CAAC;IAEzE;;;;;;;;;;;;OAYG;IACH,KAAK,CAAC,QAAQ;QACZ,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC;QAC3B,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC;QAC3B,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;IAC3B,CAAC;IAED;;;;;;OAMG;IACH,sBAAsB;QACpB,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC;QAC3B,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC;QAC3B,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;IAC3B,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,kBAAkB,CAAC,MAAc,EAAE,IAAuB;QAC9D,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QAC7C,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC9C,IAAI,MAAM,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,UAAU,CAAC,UAAU,CAAC;YAAE,OAAO,MAAM,CAAC;QAC7E,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC;YAC3C,cAAc,EAAE,MAAM;YACtB,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,eAAe,EAAE,IAAI,CAAC,eAAe;SACtC,CAAC,CAAC;QACH,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QACpC,OAAO,GAAG,CAAC;IACb,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,MAAc,EAAE,KAAuB,EAAE,IAAuB;QAC9E,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QACxD,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC3C,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,MAAc;QAChC,MAAM,GAAG,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC3C,IAAI,CAAC,GAAG;YAAE,OAAO,CAAC,cAAc;QAChC,MAAM,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;IACxC,CAAC;IAED;;;;;;;OAOG;IACH,iBAAiB,CAAC,MAAc;QAC9B,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAClC,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACpC,CAAC;IAED,sEAAsE;IACtE,qEAAqE;IACrE,6CAA6C;IAC7C,eAAe,CAAC,SAAiB,EAAE,OAA+B;QAChE,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,CAAC;IACvD,CAAC;IAED,cAAc,CAAC,SAAiB,EAAE,QAAiC;QACjE,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC;IACvD,CAAC;IAED,2EAA2E;IAC3E,yEAAyE;IACzE,2EAA2E;IAC3E,yEAAyE;IACzE,2EAA2E;IAC3E,+BAA+B;IAE/B,QAAQ,CAAC,MAAqB,EAAE,KAAoB;QAClD,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACzC,CAAC;IAED,iBAAiB,CAAC,MAAe;QAC/B,OAAO,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC;IAC1D,CAAC;IAED,YAAY,CAAC,MAAe;QAC1B,OAAO,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC;IACtD,CAAC;IAED,mBAAmB,CAAC,MAAc,EAAE,IAAkB;QACpD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC;eACrD,EAAE,eAAe,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC;QACrD,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;QAC/B,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,WAAW,CAAC,MAAc,EAAE,OAAgB,EAAE,OAAe;QAC3D,OAAO,IAAI,CAAC,sBAAsB,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;IAC7E,CAAC;IAED,YAAY,CAAC,MAAc,EAAE,OAAgB,EAAE,OAAe;QAC5D,OAAO,IAAI,CAAC,sBAAsB,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,CAAC;IAC9E,CAAC;IAED,iBAAiB,CAAC,MAAc,EAAE,IAAoB,EAAE,OAAe;QACrE,OAAO,IAAI,CAAC,sBAAsB,CAAC,MAAM,EAAE,OAAO,EAAE;YAClD,cAAc,EAAE,IAAI;YACpB,QAAQ,EAAE,IAAI,KAAK,MAAM,EAAG,uCAAuC;SACpE,CAAC,CAAC;IACL,CAAC;IAEO,sBAAsB,CAAC,MAAc,EAAE,OAAe,EAAE,IAAiB;QAC/E,IAAI,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC;YAC3C,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC;mBACrD,EAAE,eAAe,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC;YACrD,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;YAC/B,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,wBAAwB,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;QAC/D,OAAO,IAAI,CAAC;IACd,CAAC;IAED,6EAA6E;IAC7E,wEAAwE;IACxE,+DAA+D;IAE/D;;yEAEqE;IACrE,KAAK,CAAC,WAAW,CAAC,OAAe;QAC/B,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;QACtD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,gBAAgB,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;QAClE,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,OAAe,EAAE,SAAiB;QAClD,OAAO,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,OAAO,EAAE,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC;IAC1E,CAAC;IAED;;0DAEsD;IACtD,KAAK,CAAC,oBAAoB,CAAC,OAAe,EAAE,SAAiB,EAAE,KAAa;QAC1E,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa;YAAE,OAAO,KAAK,CAAC;QAC9C,OAAO,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,EAAE,KAAK,CAAC,CAAC;IACnF,CAAC;IAED,KAAK,CAAC,oBAAoB,CAAC,OAAe,EAAE,SAAiB;QAC3D,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa;YAAE,OAAO,KAAK,CAAC;QAC9C,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC;QACpF,IAAI,EAAE;YAAE,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAC3C,OAAO,EAAE,CAAC;IACZ,CAAC;IAED;;;;;yEAKqE;IAC7D,aAAa,CAAC,SAAiB;QACrC,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC/C,IAAI,MAAM;YAAE,OAAO,MAAM,CAAC;QAC1B,OAAO;YACL,WAAW,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI;YAC9B,gBAAgB,EAAE,SAAS;YAC3B,eAAe,EAAE,SAAS;YAC1B,iBAAiB,EAAE,SAAS;SAC7B,CAAC;IACJ,CAAC;CACF;AAGD,+EAA+E;AAE/E,IAAI,eAAe,GAAwB,IAAI,CAAC;AAEhD;;;GAGG;AACH,MAAM,UAAU,UAAU;IACxB,IAAI,CAAC,eAAe,EAAE,CAAC;QACrB,eAAe,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;IAC5C,CAAC;IACD,OAAO,eAAe,CAAC;AACzB,CAAC;AAED;;;+EAG+E;AAC/E,MAAM,CAAC,KAAK,UAAU,qBAAqB;IACzC,IAAI,eAAe,EAAE,CAAC;QACpB,IAAI,CAAC;YAAC,MAAM,eAAe,CAAC,QAAQ,EAAE,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;IAClE,CAAC;IACD,eAAe,GAAG,IAAI,CAAC;AACzB,CAAC;AAED,gFAAgF;AAChF,EAAE;AACF,2EAA2E;AAC3E,4EAA4E;AAC5E,0CAA0C;AAE1C,OAAO,EACL,UAAU,EAAa,wHAAwH;AAC/I,SAAS,EAAc,sDAAsD;AAC7E,SAAS,EAAc,sDAAsD;AAC7E,KAAK,EAAkB,4DAA4D;AACnF,QAAQ,EAAe,4CAA4C;AACnE,eAAe,EAAQ,kFAAkF;AACzG,iBAAiB,EAAM,8OAA8O;AACrQ,eAAe,EAAQ,+DAA+D;AACtF,gBAAgB,EAAO,oBAAoB;AAC3C,cAAc,EAAS,8DAA8D;AACrF,sBAAsB,EAAC,oBAAoB;AAC3C,kBAAkB,EAAK,oBAAoB;AAC3C,iBAAiB,EAAM,oGAAoG;AAC3H,oBAAoB,EAAG,2BAA2B;AAClD,gBAAgB,EAAO,2BAA2B;AAClD,mBAAmB,EAAI,2BAA2B;AAClD,iBAAiB,EAAM,2BAA2B;AAClD,mBAAmB,EAAI,2BAA2B;AAClD,gBAAgB,EAAO,2BAA2B;AAClD,kBAAkB,EAAK,2BAA2B;AAClD,mBAAmB,EAAI,qDAAqD;AAC5E,yBAAyB,EAAE,oBAAoB;AAC/C,mBAAmB,EAAI,uDAAuD;AAC9E,mBAAmB,EAAI,oBAAoB;EAC5C,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export interface SessionSearchHit {
|
|
2
|
+
role: 'user' | 'assistant' | 'tool';
|
|
3
|
+
ts?: string;
|
|
4
|
+
messageIdx: number;
|
|
5
|
+
snippet: string;
|
|
6
|
+
}
|
|
7
|
+
export interface SessionSearchResult {
|
|
8
|
+
sessionId: string;
|
|
9
|
+
title: string;
|
|
10
|
+
lastModified: number;
|
|
11
|
+
hits: SessionSearchHit[];
|
|
12
|
+
totalHits: number;
|
|
13
|
+
}
|
|
14
|
+
export interface SessionSearchResponse {
|
|
15
|
+
query: string;
|
|
16
|
+
results: SessionSearchResult[];
|
|
17
|
+
truncated: boolean;
|
|
18
|
+
scannedFiles: number;
|
|
19
|
+
matchedFiles: number;
|
|
20
|
+
durationMs: number;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Search every session under `workDir` for `query`.
|
|
24
|
+
*
|
|
25
|
+
* - Case-insensitive substring match (no regex).
|
|
26
|
+
* - Capped at `limit` total hits across all sessions; per-session capped at 10.
|
|
27
|
+
* - `signal` (optional) can be aborted between files for cancellation.
|
|
28
|
+
*/
|
|
29
|
+
export declare function searchSessions(workDir: string, query: string, opts?: {
|
|
30
|
+
limit?: number;
|
|
31
|
+
signal?: AbortSignal;
|
|
32
|
+
}): SessionSearchResponse;
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Global content search across session JSONL files for a single workDir.
|
|
3
|
+
*
|
|
4
|
+
* Two-stage:
|
|
5
|
+
* 1. Pre-filter — read each *.jsonl as raw text and substring-check the query.
|
|
6
|
+
* This skips the expensive parse for files that obviously don't match.
|
|
7
|
+
* 2. Extract — for matching files, parse via readSessionMessages() to get
|
|
8
|
+
* clean role/text/timestamp records, then generate snippets with the
|
|
9
|
+
* match wrapped in **bold** markers for the UI to render as <mark>.
|
|
10
|
+
*
|
|
11
|
+
* No external dependencies (no ripgrep) — keeps cross-platform behavior simple
|
|
12
|
+
* and avoids shipping a binary. At the measured scale (200+ sessions / ~200MB)
|
|
13
|
+
* pure Node fs is fast enough; substring scan over UTF-8 is dominated by I/O.
|
|
14
|
+
*/
|
|
15
|
+
import { homedir } from 'os';
|
|
16
|
+
import { existsSync, readFileSync, readdirSync, statSync } from 'fs';
|
|
17
|
+
import { join } from 'path';
|
|
18
|
+
import { pathToProjectFolder, } from './history-message-transform.js';
|
|
19
|
+
import { listSessions, readSessionMessages } from './history.js';
|
|
20
|
+
const DEFAULT_TOTAL_LIMIT = 200;
|
|
21
|
+
const PER_SESSION_LIMIT = 10;
|
|
22
|
+
const SNIPPET_RADIUS = 60; // chars on each side of the match
|
|
23
|
+
function getClaudeProjectsDir() {
|
|
24
|
+
return join(homedir(), '.claude', 'projects');
|
|
25
|
+
}
|
|
26
|
+
/** Wrap matches of `query` (case-insensitive) in **bold** markers. */
|
|
27
|
+
function highlight(text, query) {
|
|
28
|
+
if (!query)
|
|
29
|
+
return text;
|
|
30
|
+
const lower = text.toLowerCase();
|
|
31
|
+
const q = query.toLowerCase();
|
|
32
|
+
const out = [];
|
|
33
|
+
let i = 0;
|
|
34
|
+
while (i < text.length) {
|
|
35
|
+
const idx = lower.indexOf(q, i);
|
|
36
|
+
if (idx === -1) {
|
|
37
|
+
out.push(text.slice(i));
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
out.push(text.slice(i, idx));
|
|
41
|
+
out.push('**');
|
|
42
|
+
out.push(text.slice(idx, idx + q.length));
|
|
43
|
+
out.push('**');
|
|
44
|
+
i = idx + q.length;
|
|
45
|
+
}
|
|
46
|
+
return out.join('');
|
|
47
|
+
}
|
|
48
|
+
/** Extract a snippet around the first match, with markers and ellipses. */
|
|
49
|
+
function makeSnippet(text, query) {
|
|
50
|
+
const lower = text.toLowerCase();
|
|
51
|
+
const q = query.toLowerCase();
|
|
52
|
+
const idx = lower.indexOf(q);
|
|
53
|
+
if (idx === -1)
|
|
54
|
+
return null;
|
|
55
|
+
const start = Math.max(0, idx - SNIPPET_RADIUS);
|
|
56
|
+
const end = Math.min(text.length, idx + q.length + SNIPPET_RADIUS);
|
|
57
|
+
let slice = text.slice(start, end);
|
|
58
|
+
// Snap to whitespace boundary for readability
|
|
59
|
+
if (start > 0) {
|
|
60
|
+
const space = slice.indexOf(' ');
|
|
61
|
+
if (space > 0 && space < 20)
|
|
62
|
+
slice = slice.slice(space + 1);
|
|
63
|
+
}
|
|
64
|
+
if (end < text.length) {
|
|
65
|
+
const space = slice.lastIndexOf(' ');
|
|
66
|
+
if (space > slice.length - 20 && space > 0)
|
|
67
|
+
slice = slice.slice(0, space);
|
|
68
|
+
}
|
|
69
|
+
const prefix = start > 0 ? '…' : '';
|
|
70
|
+
const suffix = end < text.length ? '…' : '';
|
|
71
|
+
// Collapse newlines / tabs in snippet for compact rendering
|
|
72
|
+
const compact = slice.replace(/\s+/g, ' ').trim();
|
|
73
|
+
return prefix + highlight(compact, query) + suffix;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Count case-insensitive non-overlapping occurrences of `query` in `text`.
|
|
77
|
+
*/
|
|
78
|
+
function countOccurrences(text, query) {
|
|
79
|
+
if (!query)
|
|
80
|
+
return 0;
|
|
81
|
+
const lower = text.toLowerCase();
|
|
82
|
+
const q = query.toLowerCase();
|
|
83
|
+
let count = 0;
|
|
84
|
+
let i = 0;
|
|
85
|
+
while (i < lower.length) {
|
|
86
|
+
const idx = lower.indexOf(q, i);
|
|
87
|
+
if (idx === -1)
|
|
88
|
+
break;
|
|
89
|
+
count++;
|
|
90
|
+
i = idx + q.length;
|
|
91
|
+
}
|
|
92
|
+
return count;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Quick raw-text substring check on the JSONL file. Used as a pre-filter to
|
|
96
|
+
* skip the expensive readSessionMessages parse for non-matching files.
|
|
97
|
+
*
|
|
98
|
+
* False positives (match inside JSON metadata like uuid/tool_use_id but not
|
|
99
|
+
* in any visible text) are fine — they get filtered out in the extract phase.
|
|
100
|
+
*/
|
|
101
|
+
function fileContainsQuery(filePath, queryLower) {
|
|
102
|
+
try {
|
|
103
|
+
const buf = readFileSync(filePath);
|
|
104
|
+
return buf.toString('utf-8').toLowerCase().includes(queryLower);
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Search every session under `workDir` for `query`.
|
|
112
|
+
*
|
|
113
|
+
* - Case-insensitive substring match (no regex).
|
|
114
|
+
* - Capped at `limit` total hits across all sessions; per-session capped at 10.
|
|
115
|
+
* - `signal` (optional) can be aborted between files for cancellation.
|
|
116
|
+
*/
|
|
117
|
+
export function searchSessions(workDir, query, opts = {}) {
|
|
118
|
+
const start = Date.now();
|
|
119
|
+
const totalLimit = opts.limit && opts.limit > 0 ? opts.limit : DEFAULT_TOTAL_LIMIT;
|
|
120
|
+
const trimmed = query.trim();
|
|
121
|
+
const empty = {
|
|
122
|
+
query: trimmed,
|
|
123
|
+
results: [],
|
|
124
|
+
truncated: false,
|
|
125
|
+
scannedFiles: 0,
|
|
126
|
+
matchedFiles: 0,
|
|
127
|
+
durationMs: 0,
|
|
128
|
+
};
|
|
129
|
+
if (!trimmed)
|
|
130
|
+
return { ...empty, durationMs: Date.now() - start };
|
|
131
|
+
const projectsDir = getClaudeProjectsDir();
|
|
132
|
+
const projectFolder = pathToProjectFolder(workDir);
|
|
133
|
+
const projectPath = join(projectsDir, projectFolder);
|
|
134
|
+
if (!existsSync(projectPath))
|
|
135
|
+
return { ...empty, durationMs: Date.now() - start };
|
|
136
|
+
let files;
|
|
137
|
+
try {
|
|
138
|
+
files = readdirSync(projectPath).filter(f => f.endsWith('.jsonl'));
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
return { ...empty, durationMs: Date.now() - start };
|
|
142
|
+
}
|
|
143
|
+
// Sort newest-first by mtime so the most relevant sessions get hit budget first.
|
|
144
|
+
const fileEntries = [];
|
|
145
|
+
for (const file of files) {
|
|
146
|
+
const filePath = join(projectPath, file);
|
|
147
|
+
try {
|
|
148
|
+
const st = statSync(filePath);
|
|
149
|
+
fileEntries.push({
|
|
150
|
+
path: filePath,
|
|
151
|
+
sessionId: file.replace(/\.jsonl$/, ''),
|
|
152
|
+
mtime: st.mtime.getTime(),
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
catch { /* skip */ }
|
|
156
|
+
}
|
|
157
|
+
fileEntries.sort((a, b) => b.mtime - a.mtime);
|
|
158
|
+
// Build a sessionId → title lookup once (uses the cached listSessions parse).
|
|
159
|
+
const titleBySessionId = new Map();
|
|
160
|
+
try {
|
|
161
|
+
for (const s of listSessions(workDir))
|
|
162
|
+
titleBySessionId.set(s.sessionId, s.title);
|
|
163
|
+
}
|
|
164
|
+
catch { /* ignore */ }
|
|
165
|
+
const queryLower = trimmed.toLowerCase();
|
|
166
|
+
const results = [];
|
|
167
|
+
let totalHits = 0;
|
|
168
|
+
let truncated = false;
|
|
169
|
+
let scanned = 0;
|
|
170
|
+
let matched = 0;
|
|
171
|
+
for (const entry of fileEntries) {
|
|
172
|
+
if (opts.signal?.aborted) {
|
|
173
|
+
truncated = true;
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
scanned++;
|
|
177
|
+
if (!fileContainsQuery(entry.path, queryLower))
|
|
178
|
+
continue;
|
|
179
|
+
matched++;
|
|
180
|
+
let messages = [];
|
|
181
|
+
try {
|
|
182
|
+
messages = readSessionMessages(workDir, entry.sessionId);
|
|
183
|
+
}
|
|
184
|
+
catch { /* skip unreadable */
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
const hits = [];
|
|
188
|
+
let sessionTotal = 0;
|
|
189
|
+
for (let idx = 0; idx < messages.length; idx++) {
|
|
190
|
+
const m = messages[idx];
|
|
191
|
+
// For tool entries, search both name + input; for user/assistant search content.
|
|
192
|
+
const text = m.role === 'tool'
|
|
193
|
+
? `${m.toolName ?? ''} ${m.toolInput ?? ''}`
|
|
194
|
+
: (m.content ?? '');
|
|
195
|
+
if (!text)
|
|
196
|
+
continue;
|
|
197
|
+
const occ = countOccurrences(text, trimmed);
|
|
198
|
+
if (occ === 0)
|
|
199
|
+
continue;
|
|
200
|
+
sessionTotal += occ;
|
|
201
|
+
if (hits.length < PER_SESSION_LIMIT && totalHits < totalLimit) {
|
|
202
|
+
const snippet = makeSnippet(text, trimmed);
|
|
203
|
+
if (snippet) {
|
|
204
|
+
hits.push({
|
|
205
|
+
role: m.role,
|
|
206
|
+
ts: m.timestamp,
|
|
207
|
+
messageIdx: idx,
|
|
208
|
+
snippet,
|
|
209
|
+
});
|
|
210
|
+
totalHits++;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
if (totalHits >= totalLimit) {
|
|
214
|
+
truncated = true;
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
if (hits.length > 0) {
|
|
219
|
+
results.push({
|
|
220
|
+
sessionId: entry.sessionId,
|
|
221
|
+
title: titleBySessionId.get(entry.sessionId) ?? entry.sessionId.slice(0, 8),
|
|
222
|
+
lastModified: entry.mtime,
|
|
223
|
+
hits,
|
|
224
|
+
totalHits: sessionTotal,
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
if (totalHits >= totalLimit) {
|
|
228
|
+
truncated = true;
|
|
229
|
+
break;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
// Sort sessions: those with most hits first (then newest)
|
|
233
|
+
results.sort((a, b) => {
|
|
234
|
+
if (b.totalHits !== a.totalHits)
|
|
235
|
+
return b.totalHits - a.totalHits;
|
|
236
|
+
return b.lastModified - a.lastModified;
|
|
237
|
+
});
|
|
238
|
+
return {
|
|
239
|
+
query: trimmed,
|
|
240
|
+
results,
|
|
241
|
+
truncated,
|
|
242
|
+
scannedFiles: scanned,
|
|
243
|
+
matchedFiles: matched,
|
|
244
|
+
durationMs: Date.now() - start,
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
//# sourceMappingURL=search-sessions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-sessions.js","sourceRoot":"","sources":["../src/search-sessions.ts"],"names":[],"mappings":"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"}
|