sidekick-shared 0.27.4 → 0.27.6

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 (64) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/README.md +92 -45
  3. package/dist/accountHealth.d.ts +14 -0
  4. package/dist/accountHealth.js +61 -14
  5. package/dist/accountLaunch.d.ts +6 -0
  6. package/dist/accountLaunch.js +61 -4
  7. package/dist/accountLease.d.ts +5 -0
  8. package/dist/accountLease.js +98 -0
  9. package/dist/accountManager.d.ts +7 -0
  10. package/dist/accountManager.js +226 -89
  11. package/dist/accountSync.d.ts +1 -5
  12. package/dist/accountSync.js +22 -6
  13. package/dist/accountSyncTypes.d.ts +9 -0
  14. package/dist/accounts.d.ts +75 -18
  15. package/dist/accounts.js +712 -189
  16. package/dist/claudeCredentialDoctor.d.ts +50 -0
  17. package/dist/claudeCredentialDoctor.js +277 -0
  18. package/dist/claudeCredentialLedger.d.ts +15 -0
  19. package/dist/claudeCredentialLedger.js +130 -0
  20. package/dist/claudeCredentials.d.ts +20 -3
  21. package/dist/claudeCredentials.js +50 -3
  22. package/dist/claudeLiveGuard.d.ts +33 -0
  23. package/dist/claudeLiveGuard.js +46 -0
  24. package/dist/claudeProfiles.d.ts +14 -0
  25. package/dist/claudeProfiles.js +22 -0
  26. package/dist/claudeRefreshLock.d.ts +15 -0
  27. package/dist/claudeRefreshLock.js +145 -0
  28. package/dist/codexAuth.d.ts +4 -0
  29. package/dist/codexAuth.js +18 -0
  30. package/dist/codexCredentialDoctor.d.ts +33 -0
  31. package/dist/codexCredentialDoctor.js +302 -0
  32. package/dist/codexCredentialStore.d.ts +29 -0
  33. package/dist/codexCredentialStore.js +213 -0
  34. package/dist/codexKeepAlive.d.ts +2 -0
  35. package/dist/codexKeepAlive.js +116 -0
  36. package/dist/codexPaths.d.ts +8 -2
  37. package/dist/codexPaths.js +51 -7
  38. package/dist/codexProfiles.d.ts +37 -31
  39. package/dist/codexProfiles.js +842 -671
  40. package/dist/credentialIO.d.ts +67 -7
  41. package/dist/credentialIO.js +211 -47
  42. package/dist/ensureDefaultAccounts.js +1 -8
  43. package/dist/index.d.ts +17 -4
  44. package/dist/index.js +36 -11
  45. package/dist/keepAlive.d.ts +2 -1
  46. package/dist/keepAlive.js +116 -29
  47. package/dist/liveCredentialGuard.d.ts +28 -0
  48. package/dist/liveCredentialGuard.js +36 -0
  49. package/dist/node.d.ts +3 -0
  50. package/dist/node.js +4 -2
  51. package/dist/processDetection.d.ts +10 -3
  52. package/dist/processDetection.js +44 -11
  53. package/dist/promptHistory.d.ts +66 -0
  54. package/dist/promptHistory.js +37 -18
  55. package/dist/schemas/accountManager.d.ts +22 -0
  56. package/dist/schemas/accountManager.js +4 -0
  57. package/dist/schemas/assistantTurn.d.ts +2 -2
  58. package/dist/sessionPromptHistory.d.ts +120 -0
  59. package/dist/sessionPromptHistory.js +278 -0
  60. package/dist/sessionPromptSignals.d.ts +56 -0
  61. package/dist/sessionPromptSignals.js +355 -0
  62. package/dist/terminalSync.d.ts +12 -2
  63. package/dist/terminalSync.js +27 -2
  64. package/package.json +1 -1
@@ -34,11 +34,13 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.ACCOUNT_CONSUMER_REACHABILITY = void 0;
37
- exports.findRunningProcessesSync = findRunningProcessesSync;
38
- exports.findRunningProcesses = findRunningProcesses;
39
37
  exports.detectRunningAccountConsumers = detectRunningAccountConsumers;
40
38
  exports.detectRunningAccountConsumersSync = detectRunningAccountConsumersSync;
41
39
  exports.describeAccountConsumer = describeAccountConsumer;
40
+ exports.findRunningProcessesSync = findRunningProcessesSync;
41
+ exports.findRunningProcesses = findRunningProcesses;
42
+ exports.inspectRunningAccountConsumersSync = inspectRunningAccountConsumersSync;
43
+ exports.inspectRunningAccountConsumers = inspectRunningAccountConsumers;
42
44
  /**
43
45
  * Cross-platform detection of running CLI/app processes that hold provider
44
46
  * credentials in memory. Bounded, never throws, never spawns a shell.
@@ -47,6 +49,7 @@ const child_process_1 = require("child_process");
47
49
  const path = __importStar(require("path"));
48
50
  const PROBE_TIMEOUT_MS = 4000;
49
51
  const CLAUDE_NPM_ENTRY = /claude-code[\\/]cli\.js/;
52
+ const CODEX_NPM_ENTRY = /(?:@openai[\\/]codex|codex[\\/]bin)[\\/].*codex\.js/;
50
53
  function parseUnixTable(stdout) {
51
54
  const rows = [];
52
55
  for (const line of stdout.split('\n')) {
@@ -87,6 +90,15 @@ function matchRows(rows, names) {
87
90
  CLAUDE_NPM_ENTRY.test(row.args)) {
88
91
  name = 'claude';
89
92
  }
93
+ if (!name &&
94
+ wanted.has('codex') &&
95
+ /^node(\.exe)?$/i.test(base) &&
96
+ CODEX_NPM_ENTRY.test(row.args))
97
+ name = 'codex';
98
+ if (!name &&
99
+ wanted.has('Codex') &&
100
+ /(?:^|[\\/])Codex\.app[\\/]/.test(row.command + ' ' + row.args))
101
+ name = 'Codex';
90
102
  if (name)
91
103
  found.push({ pid: row.pid, name, command: row.command });
92
104
  }
@@ -101,9 +113,9 @@ function parseOutput(stdout) {
101
113
  return process.platform === 'win32' ? parseWindowsCsv(stdout) : parseUnixTable(stdout);
102
114
  }
103
115
  /** Sync sibling of {@link findRunningProcesses}; blocks up to 4 s. */
104
- function findRunningProcessesSync(names) {
116
+ function inspectProcessesSync(names) {
105
117
  if (names.length === 0)
106
- return [];
118
+ return { ok: true, processes: [] };
107
119
  try {
108
120
  const { command, args } = probeCommand();
109
121
  const result = (0, child_process_1.spawnSync)(command, args, {
@@ -114,16 +126,16 @@ function findRunningProcessesSync(names) {
114
126
  windowsHide: true,
115
127
  });
116
128
  if (result.error || result.status !== 0)
117
- return [];
118
- return matchRows(parseOutput(String(result.stdout ?? '')), names);
129
+ return { ok: false, processes: [] };
130
+ return { ok: true, processes: matchRows(parseOutput(String(result.stdout ?? '')), names) };
119
131
  }
120
132
  catch {
121
- return [];
133
+ return { ok: false, processes: [] };
122
134
  }
123
135
  }
124
- function findRunningProcesses(names) {
136
+ function inspectProcesses(names) {
125
137
  if (names.length === 0)
126
- return Promise.resolve([]);
138
+ return Promise.resolve({ ok: true, processes: [] });
127
139
  return new Promise((resolve) => {
128
140
  try {
129
141
  const { command, args } = probeCommand();
@@ -134,11 +146,14 @@ function findRunningProcesses(names) {
134
146
  windowsHide: true,
135
147
  maxBuffer: 16 * 1024 * 1024,
136
148
  }, (error, stdout) => {
137
- resolve(error ? [] : matchRows(parseOutput(String(stdout ?? '')), names));
149
+ resolve({
150
+ ok: !error,
151
+ processes: error ? [] : matchRows(parseOutput(String(stdout ?? '')), names),
152
+ });
138
153
  });
139
154
  }
140
155
  catch {
141
- resolve([]);
156
+ resolve({ ok: false, processes: [] });
142
157
  }
143
158
  });
144
159
  }
@@ -208,3 +223,21 @@ function detectRunningAccountConsumersSync(provider) {
208
223
  function describeAccountConsumer(kind, pids = []) {
209
224
  return toConsumer(kind, pids);
210
225
  }
226
+ /** Compatibility wrappers keep the established best-effort list API. */
227
+ function findRunningProcessesSync(names) {
228
+ return inspectProcessesSync(names).processes;
229
+ }
230
+ async function findRunningProcesses(names) {
231
+ return (await inspectProcesses(names)).processes;
232
+ }
233
+ /** Safety decisions must distinguish a failed process scan from an empty one. */
234
+ function inspectRunningAccountConsumersSync(provider) {
235
+ const kinds = kindsForProvider(provider);
236
+ const result = inspectProcessesSync(kinds.map((kind) => CONSUMER_PROCESS_NAMES[kind]));
237
+ return { ok: result.ok, consumers: groupConsumers(result.processes, kinds) };
238
+ }
239
+ async function inspectRunningAccountConsumers(provider) {
240
+ const kinds = kindsForProvider(provider);
241
+ const result = await inspectProcesses(kinds.map((kind) => CONSUMER_PROCESS_NAMES[kind]));
242
+ return { ok: result.ok, consumers: groupConsumers(result.processes, kinds) };
243
+ }
@@ -19,6 +19,7 @@
19
19
  * the prompt is returned again under the same identity once its first
20
20
  * answering call brings model or usage (`metadataStatus` says how settled).
21
21
  */
22
+ import * as fs from 'fs';
22
23
  import { type HumanPromptProvider } from './humanPrompt';
23
24
  export type PromptHistoryProvider = HumanPromptProvider;
24
25
  export type PromptHistoryBound = 'maxSessions' | 'maxFileBytes' | 'maxTotalBytes' | 'maxEntries' | 'deadline' | 'aborted';
@@ -213,9 +214,74 @@ export interface PromptHistoryResult {
213
214
  /** A bound left bytes or files unread; call again with the cursor to continue. */
214
215
  hasMore: boolean;
215
216
  }
217
+ /** @internal */
218
+ export declare const DEFAULT_BOUNDS: Required<PromptHistoryBounds>;
216
219
  /** Test hooks; not part of the public entry points. */
217
220
  export declare const __promptHistoryTesting: {
218
221
  setReadChunkBytes(bytes: number | null): void;
219
222
  };
223
+ /** @internal */
224
+ export interface Candidate {
225
+ provider: PromptHistoryProvider;
226
+ sessionId: string;
227
+ filePath: string;
228
+ key: string;
229
+ }
230
+ /**
231
+ * Sees every parsed record of a file after the scanner, with the ordinal of the
232
+ * latest human prompt so far (-1 before the first). Used for whole-session reads.
233
+ * @internal
234
+ */
235
+ export type RecordObserver = (record: Record<string, unknown>, info: {
236
+ ordinal: number;
237
+ lineOffset: number;
238
+ }) => void;
239
+ /** @internal */
240
+ export interface ScanContext {
241
+ roots: string[];
242
+ sinceMs: number | null;
243
+ stats: PromptHistoryStats;
244
+ realpaths: Map<string, string | null>;
245
+ bounds: Required<PromptHistoryBounds>;
246
+ shouldStop: () => PromptHistoryBound | null;
247
+ /** Entries already collected from earlier files in this call. */
248
+ entriesSoFar: () => number;
249
+ exclude: (exclusion: PromptHistoryExclusion) => void;
250
+ observe?: RecordObserver;
251
+ }
252
+ /** @internal */
253
+ export interface FileBudget {
254
+ bytes: number;
255
+ /** Which bound `bytes` came from. */
256
+ bound: 'maxFileBytes' | 'maxTotalBytes';
257
+ /** First file of the call: may finish its first record even past the budget. */
258
+ forceProgress: boolean;
259
+ }
260
+ /** @internal */
261
+ export interface FileOutcome {
262
+ entries: PromptHistoryEntry[];
263
+ /** The pass moved the file's offset forward. */
264
+ progressed: boolean;
265
+ /** New cursor state, or undefined to drop it (rewrite found mid-pass). */
266
+ session: PromptHistoryCursorSession | undefined;
267
+ bytesRead: number;
268
+ stoppedBy: PromptHistoryBound | null;
269
+ notInteractive: boolean;
270
+ inScope: number;
271
+ outOfScope: number;
272
+ }
220
273
  /** Collect human-typed prompts from Claude Code and Codex logs under the given roots. */
221
274
  export declare function collectPromptHistory(options: CollectPromptHistoryOptions): Promise<PromptHistoryResult>;
275
+ /** @internal */
276
+ export declare function emptyStats(): PromptHistoryStats;
277
+ /** @internal */
278
+ export declare function compareStrings(left: string, right: string): number;
279
+ /** @internal */
280
+ export declare function resolveRoots(workspacePaths: string[], includeWorktrees: boolean, realpaths: Map<string, string | null>): {
281
+ roots: string[];
282
+ listingRoots: string[];
283
+ };
284
+ /** @internal */
285
+ export declare function listCandidates(providers: PromptHistoryProvider[], listingRoots: string[], sinceMs: number | null): Promise<Candidate[]>;
286
+ /** @internal */
287
+ export declare function scanFile(candidate: Candidate, stat: fs.Stats, prior: PromptHistoryCursorSession | undefined, budget: FileBudget, context: ScanContext): Promise<FileOutcome>;
@@ -54,8 +54,13 @@ var __importStar = (this && this.__importStar) || (function () {
54
54
  };
55
55
  })();
56
56
  Object.defineProperty(exports, "__esModule", { value: true });
57
- exports.__promptHistoryTesting = void 0;
57
+ exports.__promptHistoryTesting = exports.DEFAULT_BOUNDS = void 0;
58
58
  exports.collectPromptHistory = collectPromptHistory;
59
+ exports.emptyStats = emptyStats;
60
+ exports.compareStrings = compareStrings;
61
+ exports.resolveRoots = resolveRoots;
62
+ exports.listCandidates = listCandidates;
63
+ exports.scanFile = scanFile;
59
64
  const crypto_1 = require("crypto");
60
65
  const fs = __importStar(require("fs"));
61
66
  const path = __importStar(require("path"));
@@ -63,7 +68,8 @@ const humanPrompt_1 = require("./humanPrompt");
63
68
  const sessionPathResolver_1 = require("./parsers/sessionPathResolver");
64
69
  const claudeCode_1 = require("./providers/claudeCode");
65
70
  const codex_1 = require("./providers/codex");
66
- const DEFAULT_BOUNDS = {
71
+ /** @internal */
72
+ exports.DEFAULT_BOUNDS = {
67
73
  maxSessions: 1000,
68
74
  maxFileBytes: 16 * 1024 * 1024,
69
75
  maxTotalBytes: 256 * 1024 * 1024,
@@ -85,22 +91,10 @@ exports.__promptHistoryTesting = {
85
91
  };
86
92
  /** Collect human-typed prompts from Claude Code and Codex logs under the given roots. */
87
93
  async function collectPromptHistory(options) {
88
- const bounds = { ...DEFAULT_BOUNDS, ...definedBounds(options.bounds) };
94
+ const bounds = { ...exports.DEFAULT_BOUNDS, ...definedBounds(options.bounds) };
89
95
  const startedAt = Date.now();
90
96
  const boundsHit = new Set();
91
- const stats = {
92
- sessionsScanned: 0,
93
- sessionsSkippedUnchanged: 0,
94
- sessionsOutOfScope: 0,
95
- filesOverSizeLimit: 0,
96
- sessionsWithBacklog: 0,
97
- sessionsRewritten: 0,
98
- sessionsNotInteractive: 0,
99
- recordsOverSizeLimit: 0,
100
- recordsMalformed: 0,
101
- promptsMissingTimestamp: 0,
102
- promptsOutOfScope: 0,
103
- };
97
+ const stats = emptyStats();
104
98
  const { sessions: previous, next: previousNext } = acceptedCursor(options.cursor);
105
99
  const cursor = { version: 3, sessions: { ...previous } };
106
100
  const entries = [];
@@ -231,11 +225,27 @@ async function collectPromptHistory(options) {
231
225
  }
232
226
  return finish();
233
227
  }
228
+ /** @internal */
229
+ function emptyStats() {
230
+ return {
231
+ sessionsScanned: 0,
232
+ sessionsSkippedUnchanged: 0,
233
+ sessionsOutOfScope: 0,
234
+ filesOverSizeLimit: 0,
235
+ sessionsWithBacklog: 0,
236
+ sessionsRewritten: 0,
237
+ sessionsNotInteractive: 0,
238
+ recordsOverSizeLimit: 0,
239
+ recordsMalformed: 0,
240
+ promptsMissingTimestamp: 0,
241
+ promptsOutOfScope: 0,
242
+ };
243
+ }
234
244
  function definedBounds(bounds) {
235
245
  const result = {};
236
246
  if (!bounds)
237
247
  return result;
238
- for (const key of Object.keys(DEFAULT_BOUNDS)) {
248
+ for (const key of Object.keys(exports.DEFAULT_BOUNDS)) {
239
249
  const value = bounds[key];
240
250
  if (typeof value === 'number' && !Number.isNaN(value))
241
251
  result[key] = Math.max(0, value);
@@ -321,6 +331,7 @@ function compareEntries(left, right) {
321
331
  compareStrings(left.sessionId, right.sessionId) ||
322
332
  left.ordinal - right.ordinal);
323
333
  }
334
+ /** @internal */
324
335
  function compareStrings(left, right) {
325
336
  return left < right ? -1 : left > right ? 1 : 0;
326
337
  }
@@ -342,6 +353,7 @@ function realpathOrNull(input, cache) {
342
353
  cache.set(input, resolved);
343
354
  return resolved;
344
355
  }
356
+ /** @internal */
345
357
  function resolveRoots(workspacePaths, includeWorktrees, realpaths) {
346
358
  const roots = new Set();
347
359
  const listingRoots = new Set();
@@ -385,6 +397,7 @@ function scopedCwd(cwd, roots, realpaths) {
385
397
  }
386
398
  return null;
387
399
  }
400
+ /** @internal */
388
401
  async function listCandidates(providers, listingRoots, sinceMs) {
389
402
  const byPath = new Map();
390
403
  const listOptions = sinceMs !== null ? { since: sinceMs } : {};
@@ -468,6 +481,7 @@ async function verifyFile(handle, size, session) {
468
481
  }
469
482
  return { head: { bytes: head.length, hash: hashBytes(head) }, bytesRead };
470
483
  }
484
+ /** @internal */
471
485
  async function scanFile(candidate, stat, prior, budget, context) {
472
486
  const handle = await fs.promises.open(candidate.filePath, 'r');
473
487
  try {
@@ -728,7 +742,12 @@ function acceptLine(line, lineOffset, lineBytes, scanner, context, candidate) {
728
742
  }
729
743
  if (typeof record !== 'object' || record === null)
730
744
  return 'ok';
731
- return scanner.accept(record, lineOffset, lineBytes);
745
+ const row = record;
746
+ const accepted = scanner.accept(row, lineOffset, lineBytes);
747
+ if (accepted === 'ok' && context.observe) {
748
+ context.observe(row, { ordinal: scanner.lastOrdinal(), lineOffset });
749
+ }
750
+ return accepted;
732
751
  }
733
752
  /** Shared per-file prompt bookkeeping for both providers. */
734
753
  class LineScanner {
@@ -143,6 +143,7 @@ export declare const accountHealthSidecarSchema: z.ZodObject<{
143
143
  "api-key": "api-key";
144
144
  oauth: "oauth";
145
145
  }>>;
146
+ refreshFp: z.ZodOptional<z.ZodString>;
146
147
  source: z.ZodEnum<{
147
148
  login: "login";
148
149
  "live-sync": "live-sync";
@@ -310,6 +311,13 @@ export declare const providerSyncReportSchema: z.ZodObject<{
310
311
  folded: z.ZodOptional<z.ZodString>;
311
312
  repointed: z.ZodOptional<z.ZodString>;
312
313
  merged: z.ZodOptional<z.ZodArray<z.ZodString>>;
314
+ demoted: z.ZodOptional<z.ZodString>;
315
+ repaired: z.ZodOptional<z.ZodString>;
316
+ journal: z.ZodOptional<z.ZodEnum<{
317
+ finished: "finished";
318
+ "rolled-back": "rolled-back";
319
+ cleared: "cleared";
320
+ }>>;
313
321
  skipped: z.ZodOptional<z.ZodString>;
314
322
  warnings: z.ZodArray<z.ZodString>;
315
323
  }, z.core.$strip>;
@@ -322,6 +330,13 @@ export declare const syncReportSchema: z.ZodObject<{
322
330
  folded: z.ZodOptional<z.ZodString>;
323
331
  repointed: z.ZodOptional<z.ZodString>;
324
332
  merged: z.ZodOptional<z.ZodArray<z.ZodString>>;
333
+ demoted: z.ZodOptional<z.ZodString>;
334
+ repaired: z.ZodOptional<z.ZodString>;
335
+ journal: z.ZodOptional<z.ZodEnum<{
336
+ finished: "finished";
337
+ "rolled-back": "rolled-back";
338
+ cleared: "cleared";
339
+ }>>;
325
340
  skipped: z.ZodOptional<z.ZodString>;
326
341
  warnings: z.ZodArray<z.ZodString>;
327
342
  }, z.core.$strip>;
@@ -333,6 +348,13 @@ export declare const syncReportSchema: z.ZodObject<{
333
348
  folded: z.ZodOptional<z.ZodString>;
334
349
  repointed: z.ZodOptional<z.ZodString>;
335
350
  merged: z.ZodOptional<z.ZodArray<z.ZodString>>;
351
+ demoted: z.ZodOptional<z.ZodString>;
352
+ repaired: z.ZodOptional<z.ZodString>;
353
+ journal: z.ZodOptional<z.ZodEnum<{
354
+ finished: "finished";
355
+ "rolled-back": "rolled-back";
356
+ cleared: "cleared";
357
+ }>>;
336
358
  skipped: z.ZodOptional<z.ZodString>;
337
359
  warnings: z.ZodArray<z.ZodString>;
338
360
  }, z.core.$strip>;
@@ -107,6 +107,7 @@ exports.accountHealthSidecarSchema = zod_1.z.object({
107
107
  lastRefreshAt: zod_1.z.number().optional(),
108
108
  hasRefreshToken: zod_1.z.boolean().optional(),
109
109
  authMode: zod_1.z.enum(['chatgpt', 'api-key', 'oauth']).optional(),
110
+ refreshFp: zod_1.z.string().optional(),
110
111
  source: exports.accountHealthSourceSchema,
111
112
  });
112
113
  exports.accountHealthSchema = zod_1.z.object({
@@ -178,6 +179,9 @@ exports.providerSyncReportSchema = zod_1.z.object({
178
179
  folded: zod_1.z.string().optional(),
179
180
  repointed: zod_1.z.string().optional(),
180
181
  merged: zod_1.z.array(zod_1.z.string()).optional(),
182
+ demoted: zod_1.z.string().optional(),
183
+ repaired: zod_1.z.string().optional(),
184
+ journal: zod_1.z.enum(['finished', 'rolled-back', 'cleared']).optional(),
181
185
  skipped: zod_1.z.string().optional(),
182
186
  warnings: zod_1.z.array(zod_1.z.string()),
183
187
  });
@@ -7,8 +7,8 @@
7
7
  import { z } from 'zod';
8
8
  export declare const assistantTurnEventTypeSchema: z.ZodEnum<{
9
9
  error: "error";
10
- text: "text";
11
10
  status: "status";
11
+ text: "text";
12
12
  tool_use: "tool_use";
13
13
  tool_result: "tool_result";
14
14
  progress: "progress";
@@ -18,8 +18,8 @@ export declare const assistantTurnEventTypeSchema: z.ZodEnum<{
18
18
  export declare const assistantTurnEventSchema: z.ZodObject<{
19
19
  eventType: z.ZodEnum<{
20
20
  error: "error";
21
- text: "text";
22
21
  status: "status";
22
+ text: "text";
23
23
  tool_use: "tool_use";
24
24
  tool_result: "tool_result";
25
25
  progress: "progress";
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Node-only whole-session view of prompt history: every human prompt of a
3
+ * Claude Code or Codex session, grouped by session, for consumers that
4
+ * classify a session as a whole (intent, conflict, issues).
5
+ *
6
+ * Sessions are read from the start with the same scanners as
7
+ * `collectPromptHistory()`, so scope rules, prompt text, first-call model and
8
+ * usage, and ordinals are identical. The replies and interaction signals that
9
+ * the prompt filter leaves out are opt-in through `include`.
10
+ *
11
+ * There is no cursor: each call returns whole sessions. A bound that stops a
12
+ * call lists the sessions it did not read in `unread`; passing them back as
13
+ * `sessionIds` continues. Scope fails closed as in `collectPromptHistory()`,
14
+ * and replies or signals that belong to an out-of-scope prompt are dropped.
15
+ */
16
+ import { type PromptHistoryEntry, type PromptHistoryExclusion, type PromptHistoryProvider } from './promptHistory';
17
+ import { type PromptHistoryReply, type PromptHistorySignal } from './sessionPromptSignals';
18
+ export interface SessionPromptHistoryInclude {
19
+ /** Interrupts, rejected and failed tool calls, compactions, API errors, rollbacks. */
20
+ signals?: boolean;
21
+ /** The agent's last text for each prompt's turn. */
22
+ replies?: boolean;
23
+ }
24
+ export interface SessionPromptHistoryBounds {
25
+ /** Session files read in one call. Default 1000. */
26
+ maxSessions?: number;
27
+ /** Bytes read from one session; a longer session is returned `truncated`. Default 256 MiB. */
28
+ maxSessionBytes?: number;
29
+ /** Bytes read across all sessions in one call. Default 256 MiB. */
30
+ maxTotalBytes?: number;
31
+ /** Largest single log record that is parsed. Default 16 MiB. */
32
+ maxRecordBytes?: number;
33
+ /** Wall-clock budget for the call. Default 60 000 ms. */
34
+ deadlineMs?: number;
35
+ }
36
+ export interface CollectSessionPromptHistoryOptions {
37
+ /** Absolute workspace roots; realpath-normalized internally. */
38
+ workspacePaths: string[];
39
+ /** Add git worktree siblings of each root. Default true. */
40
+ includeWorktrees?: boolean;
41
+ /** Default both. */
42
+ providers?: PromptHistoryProvider[];
43
+ /** Only these sessions (exact ids). */
44
+ sessionIds?: string[];
45
+ /** Only sessions whose file changed at or after this. Each comes back whole. */
46
+ since?: Date;
47
+ /** Return at most this many sessions, most recently modified first. */
48
+ limit?: number;
49
+ /** Opt-in content beyond the prompts. */
50
+ include?: SessionPromptHistoryInclude;
51
+ bounds?: SessionPromptHistoryBounds;
52
+ signal?: AbortSignal;
53
+ }
54
+ export interface PromptHistorySessionPrompt extends Omit<PromptHistoryEntry, 'provider' | 'sessionId'> {
55
+ /** With `include.replies`: the agent's last text for this prompt's turn. */
56
+ reply?: PromptHistoryReply;
57
+ }
58
+ export interface PromptHistorySession {
59
+ provider: PromptHistoryProvider;
60
+ sessionId: string;
61
+ /** Earliest timestamp in the session log. */
62
+ startedAt: string;
63
+ /** Latest timestamp in the session log. */
64
+ lastActivityAt: string;
65
+ /** Distinct prompt working directories, in order of first use. */
66
+ cwds: string[];
67
+ /** Distinct prompt git branches, in order of first use. */
68
+ gitBranches: string[];
69
+ /** Distinct models that answered a prompt, in order of first use. */
70
+ models: string[];
71
+ /** Every human prompt in scope, by ordinal. */
72
+ prompts: PromptHistorySessionPrompt[];
73
+ /** With `include.signals`: interaction signals in log order. */
74
+ signals?: PromptHistorySignal[];
75
+ /** Read to the end with no dropped prompts and no excluded records. */
76
+ complete: boolean;
77
+ /** `maxSessionBytes` stopped the read; later prompts are missing. */
78
+ truncated: boolean;
79
+ /** Prompts left out because their cwd was out of scope or they had no timestamp. */
80
+ droppedPrompts: number;
81
+ /** Records left out as oversized or malformed (see `exclusions`). */
82
+ excludedRecords: number;
83
+ }
84
+ export interface PromptHistorySessionRef {
85
+ provider: PromptHistoryProvider;
86
+ sessionId: string;
87
+ }
88
+ export type SessionPromptHistoryBound = 'maxSessions' | 'maxSessionBytes' | 'maxTotalBytes' | 'deadline' | 'aborted';
89
+ export interface SessionPromptHistoryStats {
90
+ /** Session files that matched the provider, id, and `since` filters. */
91
+ sessionsMatched: number;
92
+ sessionsScanned: number;
93
+ sessionsReturned: number;
94
+ /** Scanned sessions with no human prompt at all. */
95
+ sessionsWithoutPrompts: number;
96
+ /** Scanned sessions with human prompts but none inside the allowed roots. */
97
+ sessionsOutOfScope: number;
98
+ /** Codex sessions skipped as non-interactive (subagent, fork, unknown source). */
99
+ sessionsNotInteractive: number;
100
+ sessionsTruncated: number;
101
+ recordsOverSizeLimit: number;
102
+ recordsMalformed: number;
103
+ promptsMissingTimestamp: number;
104
+ promptsOutOfScope: number;
105
+ }
106
+ export interface SessionPromptHistoryResult {
107
+ /** Most recent activity first. */
108
+ sessions: PromptHistorySession[];
109
+ /**
110
+ * Sessions this call did not read, because a bound stopped it or the file
111
+ * changed while it was read; pass them as `sessionIds` to continue.
112
+ */
113
+ unread: PromptHistorySessionRef[];
114
+ boundsHit: SessionPromptHistoryBound[];
115
+ /** Permanent exclusions found in this call (at most 1000; stats count all). */
116
+ exclusions: PromptHistoryExclusion[];
117
+ stats: SessionPromptHistoryStats;
118
+ }
119
+ /** Collect every human prompt of each matching session, grouped by session. */
120
+ export declare function collectSessionPromptHistory(options: CollectSessionPromptHistoryOptions): Promise<SessionPromptHistoryResult>;