@deathbeam/pi-archive 0.0.1 → 0.0.2

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 (3) hide show
  1. package/README.md +1 -1
  2. package/index.ts +13 -9
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # @deathbeam/pi-archive
1
+ # [@deathbeam/pi-archive](https://www.npmjs.com/package/@deathbeam/pi-archive)
2
2
 
3
3
  Search past Pi sessions with `search_archive` and show recent session titles.
4
4
 
package/index.ts CHANGED
@@ -9,7 +9,6 @@ const MAX_PER_FILE = 3; // max matches per session file
9
9
  const MAX_SEARCH_LIMIT = 100;
10
10
  const READ_CHUNK_BYTES = 64 * 1024;
11
11
  const MAX_LINE_BYTES = 16 * 1024 * 1024;
12
- // ponytail: 16 MiB record ceiling; raise only if real sessions exceed it, or add incremental JSON parsing.
13
12
 
14
13
  export interface ArchiveMatch {
15
14
  file: string;
@@ -194,14 +193,16 @@ export async function searchSessions(
194
193
  if (terms.length === 0) return { matches: [], bytesScanned: 0, filesScanned: 0, truncated: false };
195
194
  const limit = opts.limit ?? 20;
196
195
  const filter = opts.sessionFilter?.toLowerCase();
197
-
198
196
  const files: { file: string; dir: string; name: string; mtime: number }[] = [];
199
197
  let rootEntries: fs.Dirent[];
200
198
  try {
201
199
  rootEntries = await fs.promises.readdir(root, { withFileTypes: true });
202
- } catch {
200
+ } catch (err) {
201
+ // A missing archive is normal; other errors must not look like clean misses.
202
+ if ((err as NodeJS.ErrnoException)?.code !== "ENOENT") throw err;
203
203
  return { matches: [], bytesScanned: 0, filesScanned: 0, truncated: false };
204
204
  }
205
+ let incompleteDiscovery = false;
205
206
  for (const entry of rootEntries) {
206
207
  if (signal?.aborted) break;
207
208
  if (!entry.isDirectory()) continue;
@@ -211,8 +212,9 @@ export async function searchSessions(
211
212
  let entries: fs.Dirent[];
212
213
  try {
213
214
  entries = await fs.promises.readdir(dir, { withFileTypes: true });
214
- } catch {
215
- continue; // directory changed or became unreadable
215
+ } catch (err) {
216
+ if ((err as NodeJS.ErrnoException)?.code !== "ENOENT") incompleteDiscovery = true;
217
+ continue;
216
218
  }
217
219
  for (const fileEntry of entries) {
218
220
  if (signal?.aborted) break;
@@ -220,7 +222,9 @@ export async function searchSessions(
220
222
  const file = path.join(dir, fileEntry.name);
221
223
  try {
222
224
  files.push({ file, dir: dirName, name: fileEntry.name, mtime: (await fs.promises.stat(file)).mtimeMs });
223
- } catch {}
225
+ } catch (err) {
226
+ if ((err as NodeJS.ErrnoException)?.code !== "ENOENT") incompleteDiscovery = true;
227
+ }
224
228
  }
225
229
  }
226
230
  if (signal?.aborted) return { matches: [], bytesScanned: 0, filesScanned: 0, truncated: true };
@@ -233,7 +237,7 @@ export async function searchSessions(
233
237
  const matches: ArchiveMatch[] = [];
234
238
  let bytes = 0;
235
239
  let filesScanned = 0;
236
- let truncated = false;
240
+ let truncated = incompleteDiscovery;
237
241
  for (const { file, dir, name } of files) {
238
242
  if (signal?.aborted || bytes >= MAX_TOTAL_BYTES) {
239
243
  truncated = true;
@@ -309,7 +313,7 @@ export function recentSessions(
309
313
  }
310
314
 
311
315
  export function formatResults(query: string, result: Awaited<ReturnType<typeof searchSessions>>): string {
312
- const note = result.truncated ? "\n(Search incomplete; narrow with the session filter.)" : "";
316
+ const note = result.truncated ? "\n(Search incomplete; narrow the search or check archive access.)" : "";
313
317
  if (result.matches.length === 0) {
314
318
  return `No matches for "${query}" in ${result.filesScanned} scanned session files.${note}`;
315
319
  }
@@ -317,7 +321,7 @@ export function formatResults(query: string, result: Awaited<ReturnType<typeof s
317
321
  (m) =>
318
322
  `${m.file}\n[${m.currentSession ? "this session" : m.sameProject ? "this project" : m.project} | ${m.date} | ${m.role}] ${m.excerpt.replace(/\s+/g, " ")}`,
319
323
  );
320
- return `Found ${result.matches.length} match(es) for "${query}" — each hit starts with the session file; read or grep it for full context:\n\n${lines.join("\n\n")}${note}`;
324
+ return `Found ${result.matches.length} match(es) for "${query}" — at most ${MAX_PER_FILE} per session file (read or grep the file for more):\n\n${lines.join("\n\n")}${note}`;
321
325
  }
322
326
 
323
327
  export default async function piArchive(pi: ExtensionAPI) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deathbeam/pi-archive",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "Search and recall past Pi session transcripts",
5
5
  "type": "module",
6
6
  "license": "MIT",