@aiwg/cli 2026.7.20 → 2026.7.21

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 (53) hide show
  1. package/README.md +4 -4
  2. package/dist/src/api/index.d.ts +1 -0
  3. package/dist/src/api/index.js +1 -0
  4. package/dist/src/artifacts/browser-export.js +7 -0
  5. package/dist/src/artifacts/citation-parser.js +96 -35
  6. package/dist/src/artifacts/index-builder.js +54 -17
  7. package/dist/src/artifacts/state-transfer.js +27 -0
  8. package/dist/src/artifacts/stats.js +8 -0
  9. package/dist/src/cli/cli-extension-loader.js +73 -0
  10. package/dist/src/cli/handlers/index.js +3 -1
  11. package/dist/src/cli/handlers/sessions.js +966 -0
  12. package/dist/src/cli/handlers/skill-lint.js +49 -45
  13. package/dist/src/cli/handlers/use.js +143 -60
  14. package/dist/src/cli/handlers/utilities.js +22 -8
  15. package/dist/src/cli/skill-usage.js +146 -24
  16. package/dist/src/extensions/commands/definitions.js +29 -0
  17. package/dist/src/extensions/manifest.js +29 -0
  18. package/dist/src/sessions/adapters/claude.js +357 -0
  19. package/dist/src/sessions/adapters/codex.js +521 -0
  20. package/dist/src/sessions/adapters/copilot.js +226 -0
  21. package/dist/src/sessions/adapters/cursor.js +372 -0
  22. package/dist/src/sessions/adapters/factory.js +345 -0
  23. package/dist/src/sessions/adapters/generic.js +225 -0
  24. package/dist/src/sessions/adapters/hermes.js +341 -0
  25. package/dist/src/sessions/adapters/openclaw.js +381 -0
  26. package/dist/src/sessions/adapters/opencode.js +454 -0
  27. package/dist/src/sessions/adapters/openhuman.js +315 -0
  28. package/dist/src/sessions/adapters/warp.js +160 -0
  29. package/dist/src/sessions/adapters/windsurf.js +212 -0
  30. package/dist/src/sessions/candidates.js +210 -0
  31. package/dist/src/sessions/contracts.js +310 -0
  32. package/dist/src/sessions/discovery.js +51 -0
  33. package/dist/src/sessions/fixtures.js +12 -0
  34. package/dist/src/sessions/importer.js +315 -0
  35. package/dist/src/sessions/index.js +25 -0
  36. package/dist/src/sessions/knowledge-shard.js +61 -0
  37. package/dist/src/sessions/optional-backends.js +238 -0
  38. package/dist/src/sessions/policy.js +192 -0
  39. package/dist/src/sessions/ports.js +2 -0
  40. package/dist/src/sessions/promotion.js +367 -0
  41. package/dist/src/sessions/readers.js +176 -0
  42. package/dist/src/sessions/repository.js +1551 -0
  43. package/dist/src/skills/adapters/agent-skills.js +59 -0
  44. package/dist/src/skills/adapters/local.js +19 -1
  45. package/dist/src/skills/agent-skills.js +249 -0
  46. package/dist/src/skills/cli.js +463 -7
  47. package/dist/src/skills/deployer.js +554 -0
  48. package/dist/src/skills/doctor.js +105 -0
  49. package/dist/src/skills/exporter.js +382 -0
  50. package/dist/src/skills/importer.js +921 -0
  51. package/dist/src/skills/registry.js +19 -0
  52. package/dist/src/skills/validator.js +323 -0
  53. package/package.json +2 -2
@@ -0,0 +1,521 @@
1
+ import { opendir } from 'node:fs/promises';
2
+ import { basename, resolve } from 'node:path';
3
+ import { z } from 'zod';
4
+ import { SessionContractError, assertSupportedSchemaMajor, } from '../contracts.js';
5
+ import { readBoundedJsonLines, streamBoundedJsonLines, } from '../readers.js';
6
+ export const CODEX_ADAPTER_VERSION = '1.0.0';
7
+ export const CODEX_SOURCE_SCHEMA_VERSION = '1.0.0';
8
+ const AppServerEnvelopeSchema = z.object({
9
+ schemaVersion: z.string().optional(),
10
+ productVersion: z.string().optional(),
11
+ method: z.string().min(1),
12
+ result: z.unknown().optional(),
13
+ params: z.unknown().optional(),
14
+ }).passthrough();
15
+ const ThreadSchema = z.object({
16
+ id: z.string().min(1),
17
+ sessionId: z.string().min(1).optional(),
18
+ parentThreadId: z.string().nullable().optional(),
19
+ forkedFromId: z.string().nullable().optional(),
20
+ name: z.string().nullable().optional(),
21
+ preview: z.string().optional(),
22
+ modelProvider: z.string().optional(),
23
+ cliVersion: z.string().optional(),
24
+ createdAt: z.number().int().optional(),
25
+ updatedAt: z.number().int().optional(),
26
+ cwd: z.string().optional(),
27
+ path: z.string().nullable().optional(),
28
+ ephemeral: z.boolean().optional(),
29
+ status: z.unknown().optional(),
30
+ source: z.unknown().optional(),
31
+ gitInfo: z.unknown().optional(),
32
+ turns: z.array(z.unknown()).optional(),
33
+ }).passthrough();
34
+ const RolloutEnvelopeSchema = z.object({
35
+ schemaVersion: z.string().optional(),
36
+ timestamp: z.string().optional(),
37
+ type: z.string().min(1),
38
+ payload: z.unknown(),
39
+ }).passthrough();
40
+ export class CodexSessionAdapter {
41
+ limits;
42
+ discoveryLimits;
43
+ provider = 'codex';
44
+ adapterVersion = CODEX_ADAPTER_VERSION;
45
+ disposition = 'implemented';
46
+ supportedOperations = ['discover', 'inspect', 'stream'];
47
+ acquisitionModes = ['api', 'jsonl'];
48
+ constructor(limits, discoveryLimits = { maxDepth: 8, maxFiles: 10_000 }) {
49
+ this.limits = limits;
50
+ this.discoveryLimits = discoveryLimits;
51
+ }
52
+ async *discover(scope) {
53
+ if (scope.allowedRoots.length === 0) {
54
+ throw new SessionContractError('SOURCE_NOT_AUTHORIZED', 'Codex discovery requires an explicitly authorized export or sessions root');
55
+ }
56
+ let emitted = 0;
57
+ for (const root of [...scope.allowedRoots].sort()) {
58
+ for await (const locator of discoverJsonl(resolve(root), this.discoveryLimits.maxDepth)) {
59
+ if (++emitted > this.discoveryLimits.maxFiles) {
60
+ throw new SessionContractError('RESOURCE_LIMIT_EXCEEDED', 'Codex source discovery exceeded the authorized file limit');
61
+ }
62
+ yield {
63
+ provider: 'codex',
64
+ locator,
65
+ locatorClass: isAppServerLocator(locator)
66
+ ? 'codex-app-server-jsonl'
67
+ : 'codex-rollout-jsonl',
68
+ };
69
+ }
70
+ }
71
+ }
72
+ async inspect(source) {
73
+ const parsed = await this.readSource(source);
74
+ return {
75
+ sourceSchemaVersion: parsed.schemaVersion,
76
+ consistency: parsed.consistency,
77
+ operationalState: 'available',
78
+ };
79
+ }
80
+ async *stream(source, cursor) {
81
+ const start = parseCursor(cursor?.value);
82
+ const input = await streamBoundedJsonLines({ selectedPath: source.locator, allowedRoots: source.authorizedScope.allowedRoots }, { consistency: 'provisional', limits: this.limits });
83
+ let mode = isAppServerLocator(source.locator)
84
+ ? 'app-server' : null;
85
+ let schemaVersion = null;
86
+ let nativeSessionId = rolloutIdFromFilename(source.locator);
87
+ const identities = new Map();
88
+ let outputIndex = 0;
89
+ let sawRecord = false;
90
+ for await (const line of input) {
91
+ sawRecord = true;
92
+ mode ??= isAppServerRecord(line.value) ? 'app-server' : 'rollout';
93
+ const currentSchema = declaredSchemaVersion([line]);
94
+ if (schemaVersion && schemaVersion !== currentSchema) {
95
+ throw new SessionContractError('SCHEMA_DRIFT', 'Codex source declares mixed schema versions');
96
+ }
97
+ schemaVersion = currentSchema;
98
+ assertSupportedSchemaMajor(schemaVersion);
99
+ let normalized;
100
+ if (mode === 'app-server') {
101
+ const parsed = AppServerEnvelopeSchema.safeParse(line.value);
102
+ if (!parsed.success) {
103
+ throw new SessionContractError('MALFORMED_SOURCE', 'Codex App Server record is malformed');
104
+ }
105
+ for (const thread of extractThreads(parsed.data)) {
106
+ validateThreadIdentity(thread, identities);
107
+ }
108
+ normalized = normalizeAppServer([line]).records;
109
+ }
110
+ else {
111
+ const parsed = RolloutEnvelopeSchema.safeParse(line.value);
112
+ if (!parsed.success) {
113
+ throw new SessionContractError('MALFORMED_SOURCE', 'Codex rollout record is malformed');
114
+ }
115
+ const payload = asObject(parsed.data.payload);
116
+ if (parsed.data.type === 'session_meta') {
117
+ const declaredId = stringValue(payload.id);
118
+ if (!declaredId) {
119
+ throw new SessionContractError('MALFORMED_SOURCE', 'Codex session metadata is missing its id');
120
+ }
121
+ if (nativeSessionId && nativeSessionId !== declaredId) {
122
+ throw new SessionContractError('SCHEMA_DRIFT', 'Codex rollout session identity differs from its filename identity');
123
+ }
124
+ nativeSessionId = declaredId;
125
+ }
126
+ if (!nativeSessionId) {
127
+ throw new SessionContractError('MALFORMED_SOURCE', 'Codex rollout has no session identity before content records');
128
+ }
129
+ normalized = [rolloutRecord(nativeSessionId, parsed.data, payload, line)];
130
+ }
131
+ for (const record of normalized) {
132
+ if (outputIndex++ >= start)
133
+ yield record;
134
+ }
135
+ }
136
+ if (!sawRecord && !input.incompleteTail) {
137
+ throw new SessionContractError('MALFORMED_SOURCE', 'Codex JSONL source is empty');
138
+ }
139
+ }
140
+ async readSource(source) {
141
+ const input = await readBoundedJsonLines({ selectedPath: source.locator, allowedRoots: source.authorizedScope.allowedRoots }, { consistency: 'provisional', limits: this.limits });
142
+ if (input.records.length === 0 && !input.incompleteTail) {
143
+ throw new SessionContractError('MALFORMED_SOURCE', 'Codex JSONL source is empty');
144
+ }
145
+ const appServer = isAppServerLocator(source.locator)
146
+ || input.records.some((record) => isAppServerRecord(record.value));
147
+ const schemaVersion = declaredSchemaVersion(input.records);
148
+ assertSupportedSchemaMajor(schemaVersion);
149
+ const normalized = appServer
150
+ ? normalizeAppServer(input.records)
151
+ : normalizeRollout(input.records, source.locator);
152
+ return {
153
+ records: normalized.records,
154
+ schemaVersion,
155
+ consistency: normalized.complete ? 'complete' : 'provisional',
156
+ };
157
+ }
158
+ }
159
+ function normalizeAppServer(input) {
160
+ const records = [];
161
+ const identities = new Map();
162
+ let complete = false;
163
+ let sawActive = false;
164
+ for (const line of input) {
165
+ const parsed = AppServerEnvelopeSchema.safeParse(line.value);
166
+ if (!parsed.success) {
167
+ throw new SessionContractError('MALFORMED_SOURCE', 'Codex App Server record is malformed');
168
+ }
169
+ const envelope = parsed.data;
170
+ const threads = extractThreads(envelope);
171
+ for (const thread of threads) {
172
+ validateThreadIdentity(thread, identities);
173
+ sawActive ||= statusType(thread.status) === 'active';
174
+ records.push(threadEvidence(thread, envelope, line));
175
+ for (const [turnIndex, turn] of (thread.turns ?? []).entries()) {
176
+ for (const [itemIndex, item] of extractItems(turn).entries()) {
177
+ records.push(threadItem(thread, turn, item, line, turnIndex, itemIndex));
178
+ }
179
+ }
180
+ }
181
+ const threadId = notificationThreadId(envelope);
182
+ if (threadId) {
183
+ const event = lifecycleEvent(envelope.method);
184
+ complete ||= event === 'deleted' || event === 'archived';
185
+ records.push({
186
+ nativeSessionId: threadId,
187
+ nativeEventId: `${envelope.method}:${line.sequence}`,
188
+ sequence: line.sequence * 1_000,
189
+ kind: event === 'compacted' ? 'summary' : 'codex.lifecycle',
190
+ role: 'system',
191
+ text: '',
192
+ rawReference: { locatorClass: 'codex-app-server-jsonl', offset: line.byteOffset },
193
+ extensions: {
194
+ lifecycleEvent: event,
195
+ provenance: { acquisition: 'codex-app-server', method: envelope.method },
196
+ unknownFields: unknownFields(envelope, APP_SERVER_KEYS),
197
+ },
198
+ });
199
+ }
200
+ }
201
+ return { records, complete: complete && !sawActive };
202
+ }
203
+ function normalizeRollout(input, locator) {
204
+ let nativeSessionId = rolloutIdFromFilename(locator);
205
+ const records = [];
206
+ for (const line of input) {
207
+ const parsed = RolloutEnvelopeSchema.safeParse(line.value);
208
+ if (!parsed.success) {
209
+ throw new SessionContractError('MALFORMED_SOURCE', 'Codex rollout record is malformed');
210
+ }
211
+ const envelope = parsed.data;
212
+ const payload = asObject(envelope.payload);
213
+ if (envelope.type === 'session_meta') {
214
+ const declaredId = stringValue(payload.id);
215
+ if (!declaredId) {
216
+ throw new SessionContractError('MALFORMED_SOURCE', 'Codex session metadata is missing its id');
217
+ }
218
+ if (nativeSessionId && nativeSessionId !== declaredId) {
219
+ throw new SessionContractError('SCHEMA_DRIFT', 'Codex rollout session identity differs from its filename identity');
220
+ }
221
+ nativeSessionId = declaredId;
222
+ }
223
+ if (!nativeSessionId) {
224
+ throw new SessionContractError('MALFORMED_SOURCE', 'Codex rollout has no session identity before content records');
225
+ }
226
+ records.push(rolloutRecord(nativeSessionId, envelope, payload, line));
227
+ }
228
+ return { records, complete: false };
229
+ }
230
+ function threadEvidence(thread, envelope, line) {
231
+ const status = statusType(thread.status);
232
+ return {
233
+ nativeSessionId: thread.id,
234
+ nativeEventId: `${envelope.method}:${thread.id}:${line.sequence}`,
235
+ sequence: line.sequence * 1_000,
236
+ kind: 'codex.thread-state',
237
+ role: 'system',
238
+ occurredAt: unixTimestamp(thread.updatedAt ?? thread.createdAt),
239
+ text: '',
240
+ rawReference: { locatorClass: 'codex-app-server-jsonl', offset: line.byteOffset },
241
+ extensions: {
242
+ method: envelope.method,
243
+ status,
244
+ lifecycle: status === 'active' ? 'active' : status === 'notLoaded' ? 'idle' : status,
245
+ sessionTreeId: thread.sessionId,
246
+ parentThreadId: thread.parentThreadId,
247
+ forkedFromId: thread.forkedFromId,
248
+ productVersion: thread.cliVersion ?? envelope.productVersion,
249
+ modelProvider: thread.modelProvider,
250
+ ephemeral: thread.ephemeral,
251
+ workspace: {
252
+ cwdClass: thread.cwd ? '<workspace>' : undefined,
253
+ git: sanitizeGitInfo(thread.gitInfo),
254
+ },
255
+ pagination: paginationEvidence(envelope.result),
256
+ provenance: { acquisition: 'codex-app-server', method: envelope.method },
257
+ unknownFields: unknownFields(thread, THREAD_KEYS),
258
+ },
259
+ };
260
+ }
261
+ function threadItem(thread, turn, item, line, turnIndex, itemIndex) {
262
+ const type = stringValue(item.type) ?? 'unknown';
263
+ const itemId = stringValue(item.id);
264
+ return {
265
+ nativeSessionId: thread.id,
266
+ nativeEventId: itemId ?? `${stringValue(asObject(turn).id) ?? turnIndex}:${itemIndex}`,
267
+ sequence: line.sequence * 1_000 + turnIndex * 100 + itemIndex + 1,
268
+ kind: itemKind(type),
269
+ role: itemRole(type),
270
+ participant: itemRole(type),
271
+ toolName: stringValue(item.name) ?? stringValue(item.tool_name),
272
+ toolCallId: stringValue(item.call_id),
273
+ occurredAt: stringValue(item.timestamp),
274
+ text: itemText(item),
275
+ rawReference: { locatorClass: 'codex-app-server-jsonl', offset: line.byteOffset },
276
+ extensions: {
277
+ turnId: stringValue(asObject(turn).id),
278
+ itemType: type,
279
+ provenance: { acquisition: 'codex-app-server', method: 'thread/read' },
280
+ unknownFields: unknownFields(item, ITEM_KEYS),
281
+ },
282
+ };
283
+ }
284
+ function rolloutRecord(nativeSessionId, envelope, payload, line) {
285
+ const nativeId = stringValue(payload.id)
286
+ ?? stringValue(payload.call_id)
287
+ ?? `${envelope.type}:${line.sequence}`;
288
+ const message = asObject(payload.message);
289
+ const role = stringValue(payload.role) ?? stringValue(message.role);
290
+ return {
291
+ nativeSessionId,
292
+ nativeEventId: nativeId,
293
+ sequence: line.sequence,
294
+ kind: rolloutKind(envelope.type, payload),
295
+ role,
296
+ participant: role,
297
+ toolName: stringValue(payload.name) ?? stringValue(payload.tool_name),
298
+ toolCallId: stringValue(payload.call_id),
299
+ model: stringValue(payload.model),
300
+ occurredAt: envelope.timestamp,
301
+ text: rolloutText(payload),
302
+ rawReference: { locatorClass: 'codex-rollout-jsonl', offset: line.byteOffset },
303
+ extensions: {
304
+ rolloutType: envelope.type,
305
+ workspace: envelope.type === 'session_meta'
306
+ ? {
307
+ cwdClass: stringValue(payload.cwd) ? '<workspace>' : undefined,
308
+ git: sanitizeGitInfo(payload.git),
309
+ }
310
+ : undefined,
311
+ productVersion: stringValue(payload.cli_version),
312
+ provenance: { acquisition: 'codex-rollout', durableReplay: true },
313
+ opaque: !KNOWN_ROLLOUT_TYPES.has(envelope.type),
314
+ unknownFields: unknownFields(payload, ROLLOUT_KEYS),
315
+ },
316
+ };
317
+ }
318
+ function extractThreads(envelope) {
319
+ const result = asObject(envelope.result);
320
+ const candidates = Array.isArray(result.data)
321
+ ? result.data
322
+ : result.thread ? [result.thread] : [];
323
+ return candidates.map((candidate) => {
324
+ const parsed = ThreadSchema.safeParse(candidate);
325
+ if (!parsed.success) {
326
+ throw new SessionContractError('MALFORMED_SOURCE', 'Codex App Server thread is malformed');
327
+ }
328
+ return parsed.data;
329
+ });
330
+ }
331
+ function validateThreadIdentity(thread, identities) {
332
+ const sessionTree = thread.sessionId ?? thread.id;
333
+ const previous = identities.get(thread.id);
334
+ if (previous && previous !== sessionTree) {
335
+ throw new SessionContractError('SCHEMA_DRIFT', 'Codex thread session-tree identity changed');
336
+ }
337
+ identities.set(thread.id, sessionTree);
338
+ }
339
+ function extractItems(turn) {
340
+ const value = asObject(turn);
341
+ if (!Array.isArray(value.items))
342
+ return [];
343
+ return value.items.map(asObject);
344
+ }
345
+ function notificationThreadId(envelope) {
346
+ if (!/^thread\/(status\/changed|archived|unarchived|deleted|compacted)$/.test(envelope.method)
347
+ && envelope.method !== 'context/compacted')
348
+ return undefined;
349
+ const params = asObject(envelope.params);
350
+ return stringValue(params.threadId) ?? stringValue(params.thread_id);
351
+ }
352
+ function lifecycleEvent(method) {
353
+ if (method.includes('status'))
354
+ return 'status-changed';
355
+ if (method.includes('unarchive'))
356
+ return 'unarchived';
357
+ if (method.includes('archive'))
358
+ return 'archived';
359
+ if (method.includes('delete'))
360
+ return 'deleted';
361
+ return 'compacted';
362
+ }
363
+ function itemKind(type) {
364
+ if (type === 'userMessage' || type === 'agentMessage')
365
+ return 'message';
366
+ if (type.includes('Command') || type.includes('Tool') || type.includes('Mcp'))
367
+ return 'tool-call';
368
+ if (type.includes('FileChange'))
369
+ return 'artifact';
370
+ if (type.includes('Compaction'))
371
+ return 'summary';
372
+ return `codex.${type}`;
373
+ }
374
+ function itemRole(type) {
375
+ if (type === 'userMessage')
376
+ return 'user';
377
+ if (type === 'agentMessage')
378
+ return 'assistant';
379
+ return 'tool';
380
+ }
381
+ function itemText(item) {
382
+ return stringValue(item.text)
383
+ ?? stringValue(item.command)
384
+ ?? stringValue(item.name)
385
+ ?? '';
386
+ }
387
+ function rolloutKind(type, payload) {
388
+ if (type === 'compacted')
389
+ return 'summary';
390
+ if (type === 'response_item') {
391
+ const payloadType = stringValue(payload.type);
392
+ if (payloadType === 'message')
393
+ return 'message';
394
+ if (payloadType?.includes('call'))
395
+ return 'tool-call';
396
+ if (payloadType?.includes('output'))
397
+ return 'tool-result';
398
+ }
399
+ return `codex.${type}`;
400
+ }
401
+ function rolloutText(payload) {
402
+ const direct = stringValue(payload.text);
403
+ if (direct)
404
+ return direct;
405
+ const content = payload.content;
406
+ if (!Array.isArray(content))
407
+ return '';
408
+ return content.map((entry) => {
409
+ const value = asObject(entry);
410
+ return stringValue(value.text) ?? stringValue(value.input_text) ?? stringValue(value.output_text) ?? '';
411
+ }).filter(Boolean).join('\n');
412
+ }
413
+ function statusType(value) {
414
+ if (typeof value === 'string')
415
+ return value;
416
+ return stringValue(asObject(value).type) ?? 'unknown';
417
+ }
418
+ function paginationEvidence(value) {
419
+ const result = asObject(value);
420
+ if (!('nextCursor' in result) && !('backwardsCursor' in result))
421
+ return undefined;
422
+ return {
423
+ hasNext: typeof result.nextCursor === 'string',
424
+ hasBackwards: typeof result.backwardsCursor === 'string',
425
+ };
426
+ }
427
+ function sanitizeGitInfo(value) {
428
+ const git = asObject(value);
429
+ if (Object.keys(git).length === 0)
430
+ return undefined;
431
+ return {
432
+ branch: stringValue(git.branch),
433
+ commit: stringValue(git.commitHash) ?? stringValue(git.commit),
434
+ repositoryClass: stringValue(git.repositoryUrl) ? '<repository>' : undefined,
435
+ };
436
+ }
437
+ async function* discoverJsonl(root, maxDepth) {
438
+ const pending = [{ path: root, depth: 0 }];
439
+ while (pending.length > 0) {
440
+ const current = pending.shift();
441
+ let directory;
442
+ try {
443
+ directory = await opendir(current.path);
444
+ }
445
+ catch {
446
+ throw new SessionContractError('SOURCE_NOT_AUTHORIZED', 'authorized Codex source root is inaccessible');
447
+ }
448
+ const directories = [];
449
+ const files = [];
450
+ for await (const entry of directory) {
451
+ const path = resolve(current.path, entry.name);
452
+ if (entry.isSymbolicLink())
453
+ continue;
454
+ if (entry.isDirectory() && current.depth < maxDepth)
455
+ directories.push(path);
456
+ else if (entry.isFile() && entry.name.endsWith('.jsonl'))
457
+ files.push(path);
458
+ }
459
+ for (const file of files.sort())
460
+ yield file;
461
+ for (const directoryPath of directories.sort()) {
462
+ pending.push({ path: directoryPath, depth: current.depth + 1 });
463
+ }
464
+ }
465
+ }
466
+ function isAppServerLocator(locator) {
467
+ return /\.app-server\.jsonl$/i.test(locator);
468
+ }
469
+ function isAppServerRecord(value) {
470
+ const record = asObject(value);
471
+ return typeof record.method === 'string';
472
+ }
473
+ function declaredSchemaVersion(records) {
474
+ for (const record of records) {
475
+ const version = asObject(record.value).schemaVersion;
476
+ if (typeof version === 'string')
477
+ return version;
478
+ }
479
+ return CODEX_SOURCE_SCHEMA_VERSION;
480
+ }
481
+ function rolloutIdFromFilename(locator) {
482
+ const match = /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.jsonl$/i
483
+ .exec(basename(locator));
484
+ return match?.[1];
485
+ }
486
+ function parseCursor(value) {
487
+ if (value === undefined || value === '')
488
+ return 0;
489
+ if (!/^\d+$/.test(value))
490
+ throw new SessionContractError('SCHEMA_DRIFT', 'Codex record cursor is invalid');
491
+ return Number(value);
492
+ }
493
+ function unixTimestamp(value) {
494
+ return value === undefined ? undefined : new Date(value * 1_000).toISOString();
495
+ }
496
+ function asObject(value) {
497
+ return value && typeof value === 'object' && !Array.isArray(value)
498
+ ? value
499
+ : {};
500
+ }
501
+ function stringValue(value) {
502
+ return typeof value === 'string' && value.length > 0 ? value : undefined;
503
+ }
504
+ function unknownFields(value, known) {
505
+ return Object.fromEntries(Object.entries(value).filter(([key]) => !known.has(key)));
506
+ }
507
+ const APP_SERVER_KEYS = new Set(['schemaVersion', 'productVersion', 'method', 'result', 'params']);
508
+ const THREAD_KEYS = new Set([
509
+ 'id', 'sessionId', 'parentThreadId', 'forkedFromId', 'name', 'preview',
510
+ 'modelProvider', 'cliVersion', 'createdAt', 'updatedAt', 'cwd', 'path',
511
+ 'ephemeral', 'status', 'source', 'gitInfo', 'turns',
512
+ ]);
513
+ const ITEM_KEYS = new Set(['id', 'type', 'text', 'command', 'name', 'timestamp']);
514
+ const ROLLOUT_KEYS = new Set([
515
+ 'id', 'call_id', 'type', 'role', 'message', 'text', 'content', 'cwd',
516
+ 'git', 'cli_version',
517
+ ]);
518
+ const KNOWN_ROLLOUT_TYPES = new Set([
519
+ 'session_meta', 'turn_context', 'event_msg', 'response_item', 'compacted',
520
+ ]);
521
+ //# sourceMappingURL=codex.js.map