greprag 5.31.1 → 5.34.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/codex-hook-events.d.ts +20 -0
  2. package/dist/codex-hook-events.js +156 -0
  3. package/dist/codex-hook-events.js.map +1 -0
  4. package/dist/commands/codex-app-server.d.ts +1 -0
  5. package/dist/commands/codex-app-server.js +179 -0
  6. package/dist/commands/codex-app-server.js.map +1 -0
  7. package/dist/commands/codex-doctor.js +3 -1
  8. package/dist/commands/codex-doctor.js.map +1 -1
  9. package/dist/commands/codex.js +6 -0
  10. package/dist/commands/codex.js.map +1 -1
  11. package/dist/commands/corpus/index.d.ts +1 -0
  12. package/dist/commands/corpus/index.js +5 -0
  13. package/dist/commands/corpus/index.js.map +1 -1
  14. package/dist/commands/corpus/refresh.d.ts +1 -0
  15. package/dist/commands/corpus/refresh.js +60 -0
  16. package/dist/commands/corpus/refresh.js.map +1 -1
  17. package/dist/commands/desk-line.d.ts +36 -0
  18. package/dist/commands/desk-line.js +230 -0
  19. package/dist/commands/desk-line.js.map +1 -0
  20. package/dist/commands/init.js +75 -7
  21. package/dist/commands/init.js.map +1 -1
  22. package/dist/commands/opencode-relay.d.ts +136 -0
  23. package/dist/commands/opencode-relay.js +529 -0
  24. package/dist/commands/opencode-relay.js.map +1 -0
  25. package/dist/commands/opencode-watch.d.ts +17 -0
  26. package/dist/commands/opencode-watch.js +493 -0
  27. package/dist/commands/opencode-watch.js.map +1 -0
  28. package/dist/commands/status.d.ts +2 -0
  29. package/dist/commands/status.js +5 -1
  30. package/dist/commands/status.js.map +1 -1
  31. package/dist/commands/watcher-registry.d.ts +8 -0
  32. package/dist/commands/watcher-registry.js +19 -0
  33. package/dist/commands/watcher-registry.js.map +1 -1
  34. package/dist/hook.js +54 -83
  35. package/dist/hook.js.map +1 -1
  36. package/dist/index.js +220 -1
  37. package/dist/index.js.map +1 -1
  38. package/dist/opencode-plugin-helpers.d.ts +200 -0
  39. package/dist/opencode-plugin-helpers.js +512 -0
  40. package/dist/opencode-plugin-helpers.js.map +1 -0
  41. package/dist/opencode-plugin.d.ts +37 -134
  42. package/dist/opencode-plugin.js +648 -364
  43. package/dist/opencode-plugin.js.map +1 -1
  44. package/dist/session-id.d.ts +8 -6
  45. package/dist/session-id.js +10 -9
  46. package/dist/session-id.js.map +1 -1
  47. package/package.json +8 -4
@@ -0,0 +1,512 @@
1
+ "use strict";
2
+ /** GrepRAG opencode plugin — test-friendly helpers.
3
+ *
4
+ * Pure functions and type definitions extracted from `opencode-plugin.ts` so
5
+ * the deployed plugin file can use a single `export = { id, server }` shape
6
+ * (no `__esModule: true` wrapper, no `__test` helper export). The opencode
7
+ * legacy plugin loader iterates `Object.values(mod)` and rejects any value
8
+ * that isn't a function or `{ server: function }`; an `__esModule: true`
9
+ * boolean in that iteration throws "Plugin export is not a function" and the
10
+ * plugin registers zero hooks. See `adr/opencode-monitor-relay.md` 2026-06-06
11
+ * entries (e) and (f) for the full diagnosis.
12
+ *
13
+ * Three callers, all out-of-band of opencode's loader:
14
+ * - `opencode-plugin.ts` — the deployed plugin source imports these for use
15
+ * inside the V1 server function (recap renderer + anchor + lockfile).
16
+ * - `hook.ts` — Claude/Codex SessionStart hook imports the recap renderer
17
+ * so the recap body pushed to the system prompt is identical between
18
+ * harnesses. The hook keeps its own preamble (setup warning, checkpoint
19
+ * hint) — those are session-start UX concerns, not recap content.
20
+ * - `tests/test-opencode-plugin.cjs` and `tests/test-opencode-relay-spawn.cjs`
21
+ * — unit tests pull the same helpers by `require()` to exercise envelope
22
+ * construction, anchor resolution, and lockfile dedup without booting
23
+ * opencode.
24
+ *
25
+ * opencode never loads this file directly. Its presence at
26
+ * `~/.config/opencode/plugins/greprag-memory-helpers.js` is incidental to the
27
+ * deploy step; only `greprag-memory.js` is registered in the user's
28
+ * `opencode.json` plugin list.
29
+ */
30
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
31
+ if (k2 === undefined) k2 = k;
32
+ var desc = Object.getOwnPropertyDescriptor(m, k);
33
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
34
+ desc = { enumerable: true, get: function() { return m[k]; } };
35
+ }
36
+ Object.defineProperty(o, k2, desc);
37
+ }) : (function(o, m, k, k2) {
38
+ if (k2 === undefined) k2 = k;
39
+ o[k2] = m[k];
40
+ }));
41
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
42
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
43
+ }) : function(o, v) {
44
+ o["default"] = v;
45
+ });
46
+ var __importStar = (this && this.__importStar) || (function () {
47
+ var ownKeys = function(o) {
48
+ ownKeys = Object.getOwnPropertyNames || function (o) {
49
+ var ar = [];
50
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
51
+ return ar;
52
+ };
53
+ return ownKeys(o);
54
+ };
55
+ return function (mod) {
56
+ if (mod && mod.__esModule) return mod;
57
+ var result = {};
58
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
59
+ __setModuleDefault(result, mod);
60
+ return result;
61
+ };
62
+ })();
63
+ Object.defineProperty(exports, "__esModule", { value: true });
64
+ exports.HOURLY_CAP = exports.HOME = void 0;
65
+ exports.isPidAlive = isPidAlive;
66
+ exports.formatUuid = formatUuid;
67
+ exports.computeGitDerivedProjectId = computeGitDerivedProjectId;
68
+ exports.deterministicProjectId = deterministicProjectId;
69
+ exports.isEphemeralCwd = isEphemeralCwd;
70
+ exports.readAnchorFile = readAnchorFile;
71
+ exports.findExistingAnchorFile = findExistingAnchorFile;
72
+ exports.readAnchor = readAnchor;
73
+ exports.extractText = extractText;
74
+ exports.extractToolCalls = extractToolCalls;
75
+ exports.extractFilesTouched = extractFilesTouched;
76
+ exports.classifyUserText = classifyUserText;
77
+ exports.provenanceElisionMarker = provenanceElisionMarker;
78
+ exports.buildEnvelope = buildEnvelope;
79
+ exports.relayLockPath = relayLockPath;
80
+ exports.tryClaimRelayLock = tryClaimRelayLock;
81
+ exports.stripRecapNoise = stripRecapNoise;
82
+ exports.fmtHoursAgo = fmtHoursAgo;
83
+ exports.buildRecapBody = buildRecapBody;
84
+ const crypto = __importStar(require("crypto"));
85
+ const fs = __importStar(require("fs"));
86
+ const path = __importStar(require("path"));
87
+ const child_process_1 = require("child_process");
88
+ const HOME = process.env.HOME || process.env.USERPROFILE || '';
89
+ exports.HOME = HOME;
90
+ function readAnchorFile(filePath) {
91
+ try {
92
+ const raw = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
93
+ if (!raw || typeof raw !== 'object')
94
+ return null;
95
+ const notify = raw.inbox_notify;
96
+ const inboxNotify = notify === 'off' || notify === 'session_start_only' ? notify : 'every_turn';
97
+ return {
98
+ projectId: typeof raw.project_id === 'string' ? raw.project_id : undefined,
99
+ projectName: typeof raw.project_name === 'string' ? raw.project_name : undefined,
100
+ memoryCapture: raw.memory_capture !== false,
101
+ sessionStartRecap: raw.session_start_recap !== false,
102
+ inboxNotify,
103
+ };
104
+ }
105
+ catch {
106
+ return null;
107
+ }
108
+ }
109
+ /** Walk up from cwd looking for an anchor file. Checks canonical `.greprag/`
110
+ * first, then legacy `.claude/` and `.opencode/` at each level. Returns the
111
+ * first hit. Skips home-level globals; those are reserved for the
112
+ * ephemeral-cwd path of the cascade. */
113
+ function findExistingAnchorFile(startDir) {
114
+ const globalAnchorPath = path.join(HOME, '.greprag', 'project.json');
115
+ const legacyGlobalAnchorPath = path.join(HOME, '.claude', 'project.json');
116
+ let dir = path.resolve(startDir);
117
+ while (true) {
118
+ for (const subdir of ['.greprag', '.claude', '.opencode']) {
119
+ const candidate = path.join(dir, subdir, 'project.json');
120
+ if (candidate !== globalAnchorPath && candidate !== legacyGlobalAnchorPath && fs.existsSync(candidate)) {
121
+ return candidate;
122
+ }
123
+ }
124
+ const parent = path.dirname(dir);
125
+ if (parent === dir)
126
+ return null;
127
+ dir = parent;
128
+ }
129
+ }
130
+ /** Format the SHA-256 of an input string into a deterministic UUID v4-shape
131
+ * string. Must match the algorithm in packages/cli/src/project-anchor.ts so
132
+ * the plugin resolves identical IDs to the Claude Code CLI. */
133
+ function formatUuid(hashHex) {
134
+ return [
135
+ hashHex.slice(0, 8),
136
+ hashHex.slice(8, 12),
137
+ '4' + hashHex.slice(13, 16),
138
+ '8' + hashHex.slice(17, 20),
139
+ hashHex.slice(20, 32),
140
+ ].join('-');
141
+ }
142
+ /** Derive a stable project_id from the repo's root commit SHA. Sorted +
143
+ * hashed so disjoint-history merges produce one deterministic id everywhere.
144
+ * Returns null when cwd isn't a git repo or has no commits yet. */
145
+ function computeGitDerivedProjectId(cwd) {
146
+ try {
147
+ const out = (0, child_process_1.execSync)('git rev-list --max-parents=0 HEAD', {
148
+ cwd,
149
+ encoding: 'utf-8',
150
+ stdio: ['pipe', 'pipe', 'pipe'],
151
+ });
152
+ const roots = out.trim().split(/\s+/).filter(Boolean).sort();
153
+ if (roots.length === 0)
154
+ return null;
155
+ const hash = crypto.createHash('sha256').update(roots.join('\n')).digest('hex');
156
+ return formatUuid(hash);
157
+ }
158
+ catch {
159
+ return null;
160
+ }
161
+ }
162
+ /** Hash the cwd path into a stable UUID. Last-resort fallback — when no git
163
+ * history and no anchor file exist, this keeps capture flowing under a
164
+ * per-path identity that `greprag doctor` can later consolidate. */
165
+ function deterministicProjectId(cwd) {
166
+ const normalized = path.resolve(cwd).toLowerCase();
167
+ const hash = crypto.createHash('sha256').update(normalized).digest('hex');
168
+ return formatUuid(hash);
169
+ }
170
+ /** True when cwd is an ephemeral session path (Cowork, tmp dirs). The
171
+ * deterministic-hash fallback would mint a fresh id every session in those
172
+ * paths, so we prefer the global anchor instead. */
173
+ function isEphemeralCwd(cwd) {
174
+ const norm = path.resolve(cwd).replace(/\\/g, '/').toLowerCase();
175
+ if (norm.includes('/appdata/roaming/claude/local-agent-mode-sessions/'))
176
+ return true;
177
+ if (norm.includes('/appdata/local/claude/local-agent-mode-sessions/'))
178
+ return true;
179
+ if (norm.startsWith('/tmp/'))
180
+ return true;
181
+ if (norm.startsWith('/var/tmp/'))
182
+ return true;
183
+ if (norm.startsWith('/private/tmp/'))
184
+ return true;
185
+ return false;
186
+ }
187
+ /** Resolve the project anchor for `worktree` using the same 4-level cascade
188
+ * the Claude Code CLI uses (packages/cli/src/project-anchor.ts). Settings
189
+ * always come from the nearest repo-level file when one exists, regardless
190
+ * of which identity level resolved.
191
+ *
192
+ * 1. Anchor file with explicit `project_id` → file-based identity
193
+ * 2. Git repo with at least one commit → root-commit-derived UUID
194
+ * 3. Ephemeral cwd + ~/.greprag/project.json exists → global anchor
195
+ * 4. Path-hash fallback (never returns null; lets capture flow until
196
+ * `greprag init` runs and `greprag doctor` consolidates) */
197
+ function readAnchor(worktree) {
198
+ const filePath = findExistingAnchorFile(worktree);
199
+ const file = filePath ? readAnchorFile(filePath) : null;
200
+ const root = path.resolve(worktree);
201
+ // 1. File with explicit project_id
202
+ if (file && file.projectId && file.projectName) {
203
+ return {
204
+ projectId: file.projectId,
205
+ projectName: file.projectName,
206
+ memoryCapture: file.memoryCapture,
207
+ sessionStartRecap: file.sessionStartRecap,
208
+ inboxNotify: file.inboxNotify,
209
+ };
210
+ }
211
+ // 2. Git-derived identity. Settings layer in from the settings-only file
212
+ // when one exists; otherwise defaults apply.
213
+ const gitId = computeGitDerivedProjectId(worktree);
214
+ if (gitId) {
215
+ return {
216
+ projectId: gitId,
217
+ projectName: file?.projectName || path.basename(root).toLowerCase(),
218
+ memoryCapture: file?.memoryCapture ?? true,
219
+ sessionStartRecap: file?.sessionStartRecap ?? true,
220
+ inboxNotify: file?.inboxNotify ?? 'every_turn',
221
+ };
222
+ }
223
+ // 3. Ephemeral cwd + global anchor
224
+ if (isEphemeralCwd(worktree)) {
225
+ const canonicalGlobal = path.join(HOME, '.greprag', 'project.json');
226
+ const legacyGlobal = path.join(HOME, '.claude', 'project.json');
227
+ const globalPath = fs.existsSync(canonicalGlobal) ? canonicalGlobal : legacyGlobal;
228
+ const globalFile = fs.existsSync(globalPath) ? readAnchorFile(globalPath) : null;
229
+ if (globalFile && globalFile.projectId && globalFile.projectName) {
230
+ return {
231
+ projectId: globalFile.projectId,
232
+ projectName: globalFile.projectName,
233
+ memoryCapture: globalFile.memoryCapture,
234
+ sessionStartRecap: globalFile.sessionStartRecap,
235
+ inboxNotify: globalFile.inboxNotify,
236
+ };
237
+ }
238
+ }
239
+ // 4. Path-hash fallback — keep capture flowing for uninitialized repos.
240
+ return {
241
+ projectId: deterministicProjectId(worktree),
242
+ projectName: file?.projectName || path.basename(root).toLowerCase(),
243
+ memoryCapture: file?.memoryCapture ?? true,
244
+ sessionStartRecap: file?.sessionStartRecap ?? true,
245
+ inboxNotify: file?.inboxNotify ?? 'every_turn',
246
+ };
247
+ }
248
+ // ============================================================================
249
+ // Envelope construction (real opencode Part schema)
250
+ // ============================================================================
251
+ function extractText(parts) {
252
+ const out = [];
253
+ for (const p of parts) {
254
+ if (p.type !== 'text')
255
+ continue;
256
+ const tp = p;
257
+ if (tp.synthetic || tp.ignored)
258
+ continue;
259
+ if (tp.text)
260
+ out.push(tp.text);
261
+ }
262
+ return out.join('\n').trim();
263
+ }
264
+ /** Pull a one-line summary out of each tool call: name + a target string + an
265
+ * optional brief for shell commands. Mirrors the shape the Claude Code hook
266
+ * posts so server-side compaction sees identical structure regardless of
267
+ * client origin. */
268
+ function extractToolCalls(parts) {
269
+ const calls = [];
270
+ for (const p of parts) {
271
+ if (p.type !== 'tool')
272
+ continue;
273
+ const tp = p;
274
+ const name = tp.tool || 'unknown';
275
+ const input = (tp.state && tp.state.input) || {};
276
+ const call = { name };
277
+ if (input.command !== undefined) {
278
+ const desc = input.description;
279
+ call.target =
280
+ typeof desc === 'string' && desc
281
+ ? desc
282
+ : String(input.command).split(/\s+/)[0] || '';
283
+ const cmd = String(input.command);
284
+ call.brief = cmd.length > 800 ? cmd.slice(0, 800) + '…' : cmd;
285
+ }
286
+ else if (typeof input.file_path === 'string') {
287
+ call.target = input.file_path;
288
+ }
289
+ else if (typeof input.filePath === 'string') {
290
+ call.target = input.filePath;
291
+ }
292
+ else if (typeof input.pattern === 'string') {
293
+ call.target = input.pattern;
294
+ }
295
+ else if (typeof input.url === 'string') {
296
+ call.target = input.url;
297
+ }
298
+ else if (typeof input.query === 'string') {
299
+ call.target = input.query;
300
+ }
301
+ calls.push(call);
302
+ }
303
+ return calls;
304
+ }
305
+ function extractFilesTouched(parts) {
306
+ const files = new Set();
307
+ for (const p of parts) {
308
+ if (p.type !== 'tool')
309
+ continue;
310
+ const tp = p;
311
+ const input = (tp.state && tp.state.input) || {};
312
+ if (typeof input.file_path === 'string')
313
+ files.add(input.file_path);
314
+ if (typeof input.filePath === 'string')
315
+ files.add(input.filePath);
316
+ }
317
+ return Array.from(files).sort();
318
+ }
319
+ function classifyUserText(text) {
320
+ const t = (text || '').trimStart();
321
+ if (!t)
322
+ return 'session-turn';
323
+ if (/^Base directory for this skill:/.test(t))
324
+ return 'skill-injection';
325
+ if (/^This session is being continued from a previous conversation/.test(t)) {
326
+ return 'continuation-summary';
327
+ }
328
+ if (/^You are a .{0,60}\bchip\b/.test(t) ||
329
+ (/\bgit worktree add\b/.test(t) &&
330
+ /(^|\n)\s*(\*\*Setup\b|Chip:|#\s*Chip\b|report back\b)/m.test(t))) {
331
+ return 'chip-prompt';
332
+ }
333
+ return 'session-turn';
334
+ }
335
+ function provenanceElisionMarker(p, text) {
336
+ const label = p === 'skill-injection' ? 'skill body' :
337
+ p === 'continuation-summary' ? 'context-continuation summary' :
338
+ p === 'chip-prompt' ? 'chip task prompt' : 'injected text';
339
+ let hint = '';
340
+ if (p === 'skill-injection') {
341
+ const m = (text || '').match(/skills[/\\]([A-Za-z0-9._-]+)/) ||
342
+ (text || '').match(/^#\s+(.+)$/m);
343
+ if (m)
344
+ hint = ` (${m[1].trim().slice(0, 40)})`;
345
+ }
346
+ return `[greprag: harness-injected ${label}${hint} elided from episodic capture]`;
347
+ }
348
+ function buildEnvelope(userParts, assistantParts, errored) {
349
+ // Elide harness-injected user text pre-LLM at capture (see the classifier
350
+ // above). The marker replaces the 1-6k-word block so it never reaches the
351
+ // server / content_tsv.
352
+ const rawUser = extractText(userParts);
353
+ const provenance = classifyUserText(rawUser);
354
+ const userPrompt = provenance === 'session-turn'
355
+ ? rawUser
356
+ : provenanceElisionMarker(provenance, rawUser);
357
+ return {
358
+ userPrompt,
359
+ agentResponse: extractText(assistantParts),
360
+ toolCalls: extractToolCalls(assistantParts),
361
+ filesTouched: extractFilesTouched(assistantParts),
362
+ status: errored ? 'errored' : 'completed',
363
+ provenance,
364
+ };
365
+ }
366
+ // ============================================================================
367
+ // Process liveness + relay lockfile
368
+ // ============================================================================
369
+ /** True when the OS reports `pid` as a running process. Used to decide whether
370
+ * a stale-lockfile check should trust the recorded PID or treat the file as
371
+ * abandoned. */
372
+ function isPidAlive(pid) {
373
+ if (!Number.isFinite(pid) || pid <= 0)
374
+ return false;
375
+ try {
376
+ process.kill(pid, 0);
377
+ return true;
378
+ }
379
+ catch {
380
+ return false;
381
+ }
382
+ }
383
+ const RELAY_LOCK_PREFIX = 'relay.';
384
+ const RELAY_STALE_MS = 30_000;
385
+ function relayLockPath(sessionId) {
386
+ const eight = sessionId.replace(/[^0-9a-f]/gi, '').slice(0, 8) || 'unknown';
387
+ return path.join(HOME, '.greprag', `${RELAY_LOCK_PREFIX}${eight}.pid`);
388
+ }
389
+ function tryClaimRelayLock(lockPath) {
390
+ try {
391
+ const fd = fs.openSync(lockPath, 'wx');
392
+ return { ok: true, fd };
393
+ }
394
+ catch (err) {
395
+ if (err.code !== 'EEXIST') {
396
+ return { ok: false, reason: 'lock-create-failed' };
397
+ }
398
+ try {
399
+ const stat = fs.statSync(lockPath);
400
+ const ageMs = Date.now() - stat.mtimeMs;
401
+ let pidAlive = false;
402
+ try {
403
+ const pid = parseInt(fs.readFileSync(lockPath, 'utf-8').trim(), 10);
404
+ pidAlive = pid > 0 && isPidAlive(pid);
405
+ }
406
+ catch { /* unreadable — treat as stale */ }
407
+ if (ageMs < RELAY_STALE_MS && pidAlive) {
408
+ return { ok: false, reason: 'busy' };
409
+ }
410
+ try {
411
+ fs.unlinkSync(lockPath);
412
+ }
413
+ catch { /* raced */ }
414
+ const fd = fs.openSync(lockPath, 'wx');
415
+ return { ok: true, fd };
416
+ }
417
+ catch (err2) {
418
+ return { ok: false, reason: 'lock-stale-replace-failed' };
419
+ }
420
+ }
421
+ }
422
+ /** Cap on the number of hourlies surfaced in the recap body. 3 — the hook's
423
+ * established value; if the user wants more they pull on demand via
424
+ * `greprag memory recap`. adr: adr/memory-recap-pyramid.md. */
425
+ const HOURLY_CAP = 3;
426
+ exports.HOURLY_CAP = HOURLY_CAP;
427
+ /** Strip noise blocks from compacted content before injection.
428
+ * Compactor contract: numbered items end with a trailer ("Open: ..." for
429
+ * hourly, "Shipped: ..." for daily) which may span multiple lines. Trailers
430
+ * always come AFTER the numbered list — so we drop from the trigger line
431
+ * through end-of-string.
432
+ *
433
+ * - daily: drop the deterministic "Shipped: <UUID-list>" trailer (useful for
434
+ * /greprag deep-dive, but a wall of IDs at session start)
435
+ * - hourly: drop the per-hour "Open:" block (stale snapshot of open items
436
+ * that were resolved or superseded in later hours) */
437
+ function stripRecapNoise(content, type) {
438
+ const target = type === 'daily' ? 'Shipped:' : 'Open:';
439
+ const lines = content.split('\n');
440
+ const cutAt = lines.findIndex(line => line.trim().startsWith(target));
441
+ const kept = cutAt === -1 ? lines : lines.slice(0, cutAt);
442
+ while (kept.length > 0 && kept[kept.length - 1].trim() === '')
443
+ kept.pop();
444
+ return kept.join('\n');
445
+ }
446
+ /** Render an hourly window's recency: "5 hours ago", "1 hour ago",
447
+ * "30 min ago", "just now". Reference is the end of the window — when the
448
+ * hour wrapped up. */
449
+ function fmtHoursAgo(windowEndIso, now) {
450
+ const diffMs = now.getTime() - new Date(windowEndIso).getTime();
451
+ const diffMin = Math.floor(diffMs / 60_000);
452
+ if (diffMin < 1)
453
+ return 'just now';
454
+ if (diffMin < 60)
455
+ return `${diffMin} min ago`;
456
+ const diffHrs = Math.round(diffMs / 3_600_000);
457
+ return diffHrs === 1 ? '1 hour ago' : `${diffHrs} hours ago`;
458
+ }
459
+ /** Build the recap body — hourlies-only render. Recap is hourlies-only by
460
+ * design: daily summaries used to render here (one prose paragraph per
461
+ * daily window) but added ~1500 tokens to every SessionStart for marginal
462
+ * value. Dailies still exist in the DB; agents who want historic context
463
+ * pull on demand via `greprag memory recap` (or
464
+ * `greprag memory search "<query>"` for a specific topic). Pull, don't push.
465
+ *
466
+ * Window: 2 days back to now (50-row pull), filtered to last 24h, sliced
467
+ * to HOURLY_CAP most-recent.
468
+ *
469
+ * Returns "" when there are no recent hourlies — caller treats that as
470
+ * "no recap block". Empty body is not an error; the query itself is the
471
+ * only network call and any failure is swallowed (returns ""). */
472
+ async function buildRecapBody(apiUrl, apiKey, anchor, now = new Date()) {
473
+ if (!anchor.projectId)
474
+ return '';
475
+ const hourlyFromIso = new Date(now.getTime() - 2 * 86_400_000).toISOString();
476
+ const toIso = now.toISOString();
477
+ const hourlyCutoffMs = now.getTime() - 24 * 3_600_000;
478
+ const url = `${apiUrl}/v1/memory/by-period`
479
+ + `?projectId=${encodeURIComponent(anchor.projectId)}`
480
+ + `&from=${encodeURIComponent(hourlyFromIso)}`
481
+ + `&to=${encodeURIComponent(toIso)}`
482
+ + `&type=hourly&limit=50`;
483
+ let hourlies = [];
484
+ try {
485
+ const res = await fetch(url, { headers: { 'Authorization': `Bearer ${apiKey}` } });
486
+ if (res.ok) {
487
+ const data = await res.json();
488
+ hourlies = data.memories || [];
489
+ }
490
+ }
491
+ catch {
492
+ // Network error / parse error — treat as no data, never block the hook.
493
+ }
494
+ const recent = hourlies
495
+ .filter(h => h.windowEnd && new Date(h.windowEnd).getTime() >= hourlyCutoffMs)
496
+ .slice(-HOURLY_CAP);
497
+ if (recent.length === 0)
498
+ return '';
499
+ const parts = [];
500
+ parts.push(`[GrepRAG memory: ${anchor.projectName}]`);
501
+ parts.push('');
502
+ parts.push('Recent sessions:');
503
+ for (const h of recent) {
504
+ if (!h.windowEnd)
505
+ continue;
506
+ parts.push('');
507
+ parts.push(`${fmtHoursAgo(h.windowEnd, now)}:`);
508
+ parts.push(stripRecapNoise(h.content.trim(), 'hourly'));
509
+ }
510
+ return parts.join('\n');
511
+ }
512
+ //# sourceMappingURL=opencode-plugin-helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opencode-plugin-helpers.js","sourceRoot":"","sources":["../src/opencode-plugin-helpers.ts"],"names":[],"mappings":"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"}