codex-overleaf-link 1.1.1

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 (52) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +457 -0
  3. package/bin/codex-overleaf-link.mjs +223 -0
  4. package/extension/src/shared/agentTranscript.js +1175 -0
  5. package/extension/src/shared/auditRecords.js +568 -0
  6. package/extension/src/shared/compatibility.js +372 -0
  7. package/extension/src/shared/compileAdapter.js +176 -0
  8. package/extension/src/shared/governanceRules.js +252 -0
  9. package/extension/src/shared/i18n.js +565 -0
  10. package/extension/src/shared/models.js +106 -0
  11. package/extension/src/shared/otText.js +505 -0
  12. package/extension/src/shared/projectFiles.js +180 -0
  13. package/extension/src/shared/reviewing.js +99 -0
  14. package/extension/src/shared/sensitiveScan.js +116 -0
  15. package/extension/src/shared/sessionState.js +1084 -0
  16. package/extension/src/shared/staleGuard.js +150 -0
  17. package/extension/src/shared/storageDb.js +986 -0
  18. package/extension/src/shared/storageKeys.js +29 -0
  19. package/extension/src/shared/storageMigration.js +168 -0
  20. package/extension/src/shared/summary.js +248 -0
  21. package/extension/src/shared/undoOperations.js +369 -0
  22. package/native-host/src/codexArgs.js +43 -0
  23. package/native-host/src/codexHome.js +538 -0
  24. package/native-host/src/codexModels.js +247 -0
  25. package/native-host/src/codexPrompt.js +192 -0
  26. package/native-host/src/codexPromptAssembly.js +411 -0
  27. package/native-host/src/codexSessionRunner.js +1247 -0
  28. package/native-host/src/commandApproval.js +914 -0
  29. package/native-host/src/debugLog.js +78 -0
  30. package/native-host/src/diffEngine.js +247 -0
  31. package/native-host/src/index.js +132 -0
  32. package/native-host/src/launcher.js +81 -0
  33. package/native-host/src/localSkills.js +476 -0
  34. package/native-host/src/manifest.js +226 -0
  35. package/native-host/src/mirrorSensitiveScan.js +119 -0
  36. package/native-host/src/mirrorWorkspace.js +1019 -0
  37. package/native-host/src/nativeDoctor.js +826 -0
  38. package/native-host/src/nativeEnvironment.js +315 -0
  39. package/native-host/src/nativeHostPlatform.js +112 -0
  40. package/native-host/src/nativeMessaging.js +60 -0
  41. package/native-host/src/nativeQuotas.js +294 -0
  42. package/native-host/src/nativeResponseBudget.js +194 -0
  43. package/native-host/src/runtimeInstaller.js +357 -0
  44. package/native-host/src/taskRunner.js +3 -0
  45. package/native-host/src/taskRunnerRuntime.js +1083 -0
  46. package/native-host/src/textPatch.js +287 -0
  47. package/package.json +40 -0
  48. package/scripts/codex-json-agent.mjs +269 -0
  49. package/scripts/install-native-host.mjs +255 -0
  50. package/scripts/npm-package-files-v1.1.1.txt +52 -0
  51. package/scripts/uninstall-native-host.mjs +298 -0
  52. package/scripts/verify-npm-package.mjs +296 -0
@@ -0,0 +1,986 @@
1
+ (function initStorageDb(root, factory) {
2
+ if (typeof module === 'object' && module.exports) {
3
+ module.exports = factory();
4
+ } else {
5
+ root.CodexOverleafStorageDb = factory();
6
+ }
7
+ })(typeof globalThis !== 'undefined' ? globalThis : window, function storageDbFactory() {
8
+ 'use strict';
9
+
10
+ var TARGET_SCHEMA_VERSION = 2;
11
+ var DB_NAME = 'codex-overleaf';
12
+ var CUSTOM_INSTRUCTIONS_MAX_CHARS = 12000;
13
+ var PROJECT_PREF_KEY_MAX_CHARS = 160;
14
+ var LEGACY_DEFAULT_SESSION_TITLE = 'New task';
15
+ var REDACTED_SECRET = '[REDACTED_SECRET]';
16
+ var SESSION_STORAGE_LIMITS = {
17
+ maxHistory: 10,
18
+ maxRunsPerSession: 20,
19
+ maxEventsPerRun: 300,
20
+ maxAttachmentsPerRun: 8,
21
+ sessionTitleChars: 80,
22
+ taskChars: 12000,
23
+ historyTaskChars: 300,
24
+ historyResultChars: 1800,
25
+ eventTitleChars: 6000,
26
+ statusTextChars: 800,
27
+ detailChars: 3000,
28
+ reportDetailChars: 64000,
29
+ pathChars: 240
30
+ };
31
+ var VALID_EVENT_STATUSES = {
32
+ info: true,
33
+ running: true,
34
+ completed: true,
35
+ failed: true,
36
+ warning: true,
37
+ blocked: true,
38
+ skipped: true,
39
+ pending: true
40
+ };
41
+ var SECRET_REDACTION_PATTERNS = [
42
+ /-----BEGIN [A-Z0-9 ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z0-9 ]*PRIVATE KEY-----/g,
43
+ /\bBearer\s+[A-Za-z0-9._~+/=-]{12,}/gi,
44
+ /\b(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9_]{16,}\b/g,
45
+ /\bgithub_pat_[A-Za-z0-9_]{20,}\b/g,
46
+ /\bxox[baprs]-[A-Za-z0-9-]{10,}\b/gi,
47
+ /\bAKIA[0-9A-Z]{16}\b/g,
48
+ /\b(?:sk|pk)-[A-Za-z0-9][A-Za-z0-9_-]{7,}\b/g,
49
+ /\b(?:api[_-]?key|token|password|passwd|secret)\b\s*[:=]\s*["']?[^"'\s,;]+["']?/gi
50
+ ];
51
+
52
+ var STORES = {
53
+ sessions: {
54
+ keyPath: 'id',
55
+ indexes: {
56
+ projectId: { keyPath: 'projectId', unique: false },
57
+ updatedAt: { keyPath: 'updatedAt', unique: false }
58
+ }
59
+ },
60
+ turns: {
61
+ keyPath: 'id',
62
+ indexes: {
63
+ sessionId: { keyPath: 'sessionId', unique: false },
64
+ createdAt: { keyPath: 'createdAt', unique: false }
65
+ }
66
+ },
67
+ events: {
68
+ keyPath: 'id',
69
+ indexes: {
70
+ turnId: { keyPath: 'turnId', unique: false },
71
+ index: { keyPath: 'index', unique: false }
72
+ }
73
+ },
74
+ artifacts: {
75
+ keyPath: 'id',
76
+ indexes: {
77
+ turnId: { keyPath: 'turnId', unique: false },
78
+ type: { keyPath: 'type', unique: false }
79
+ }
80
+ },
81
+ auditLogs: {
82
+ keyPath: 'id',
83
+ indexes: {
84
+ projectId: { keyPath: 'projectId', unique: false },
85
+ createdAt: { keyPath: 'createdAt', unique: false }
86
+ }
87
+ }
88
+ };
89
+
90
+ // --- Database operations ---
91
+
92
+ function openDb() {
93
+ return new Promise(function (resolve, reject) {
94
+ var request = indexedDB.open(DB_NAME, TARGET_SCHEMA_VERSION);
95
+ request.onupgradeneeded = function (event) {
96
+ var db = event.target.result;
97
+ var storeNames = Object.keys(STORES);
98
+ for (var i = 0; i < storeNames.length; i++) {
99
+ var storeName = storeNames[i];
100
+ var storeConfig = STORES[storeName];
101
+ if (!db.objectStoreNames.contains(storeName)) {
102
+ var objectStore = db.createObjectStore(storeName, { keyPath: storeConfig.keyPath });
103
+ var indexNames = Object.keys(storeConfig.indexes);
104
+ for (var j = 0; j < indexNames.length; j++) {
105
+ var indexName = indexNames[j];
106
+ var indexConfig = storeConfig.indexes[indexName];
107
+ objectStore.createIndex(indexName, indexConfig.keyPath, { unique: indexConfig.unique });
108
+ }
109
+ }
110
+ }
111
+ };
112
+ request.onsuccess = function (event) {
113
+ resolve(event.target.result);
114
+ };
115
+ request.onerror = function (event) {
116
+ reject(event.target.error);
117
+ };
118
+ });
119
+ }
120
+
121
+ function putRecord(storeName, record) {
122
+ return openDb().then(function (db) {
123
+ return new Promise(function (resolve, reject) {
124
+ var tx = db.transaction(storeName, 'readwrite');
125
+ var store = tx.objectStore(storeName);
126
+ var request = store.put(record);
127
+ request.onsuccess = function () { resolve(record); };
128
+ request.onerror = function (event) { reject(event.target.error); };
129
+ });
130
+ });
131
+ }
132
+
133
+ function putRecords(storeName, records) {
134
+ return openDb().then(function (db) {
135
+ return new Promise(function (resolve, reject) {
136
+ var tx = db.transaction(storeName, 'readwrite');
137
+ var store = tx.objectStore(storeName);
138
+ for (var i = 0; i < records.length; i++) {
139
+ store.put(records[i]);
140
+ }
141
+ tx.oncomplete = function () { resolve(records); };
142
+ tx.onerror = function (event) { reject(event.target.error); };
143
+ });
144
+ });
145
+ }
146
+
147
+ function getRecord(storeName, key) {
148
+ return openDb().then(function (db) {
149
+ return new Promise(function (resolve, reject) {
150
+ var tx = db.transaction(storeName, 'readonly');
151
+ var store = tx.objectStore(storeName);
152
+ var request = store.get(key);
153
+ request.onsuccess = function (event) { resolve(event.target.result || null); };
154
+ request.onerror = function (event) { reject(event.target.error); };
155
+ });
156
+ });
157
+ }
158
+
159
+ function getAllByIndex(storeName, indexName, value) {
160
+ return openDb().then(function (db) {
161
+ return new Promise(function (resolve, reject) {
162
+ var tx = db.transaction(storeName, 'readonly');
163
+ var store = tx.objectStore(storeName);
164
+ var index = store.index(indexName);
165
+ var request = index.getAll(IDBKeyRange.only(value));
166
+ request.onsuccess = function (event) { resolve(event.target.result || []); };
167
+ request.onerror = function (event) { reject(event.target.error); };
168
+ });
169
+ });
170
+ }
171
+
172
+ function deleteRecord(storeName, key) {
173
+ return openDb().then(function (db) {
174
+ return new Promise(function (resolve, reject) {
175
+ var tx = db.transaction(storeName, 'readwrite');
176
+ var store = tx.objectStore(storeName);
177
+ var request = store.delete(key);
178
+ request.onsuccess = function () { resolve(); };
179
+ request.onerror = function (event) { reject(event.target.error); };
180
+ });
181
+ });
182
+ }
183
+
184
+ function deleteByIndex(storeName, indexName, value) {
185
+ return openDb().then(function (db) {
186
+ return new Promise(function (resolve, reject) {
187
+ var tx = db.transaction(storeName, 'readwrite');
188
+ var store = tx.objectStore(storeName);
189
+ var index = store.index(indexName);
190
+ var request = index.openCursor(IDBKeyRange.only(value));
191
+ request.onsuccess = function (event) {
192
+ var cursor = event.target.result;
193
+ if (cursor) {
194
+ cursor.delete();
195
+ cursor.continue();
196
+ }
197
+ };
198
+ tx.oncomplete = function () { resolve(); };
199
+ tx.onerror = function (event) { reject(event.target.error); };
200
+ });
201
+ });
202
+ }
203
+
204
+ function clearStore(storeName) {
205
+ return openDb().then(function (db) {
206
+ return new Promise(function (resolve, reject) {
207
+ var tx = db.transaction(storeName, 'readwrite');
208
+ var store = tx.objectStore(storeName);
209
+ var request = store.clear();
210
+ request.onsuccess = function () { resolve(); };
211
+ request.onerror = function (event) { reject(event.target.error); };
212
+ });
213
+ });
214
+ }
215
+
216
+ function clearAllStores() {
217
+ return openDb().then(function (db) {
218
+ var storeNames = Object.keys(STORES);
219
+ return new Promise(function (resolve, reject) {
220
+ var tx = db.transaction(storeNames, 'readwrite');
221
+ for (var i = 0; i < storeNames.length; i++) {
222
+ tx.objectStore(storeNames[i]).clear();
223
+ }
224
+ tx.oncomplete = function () { resolve(); };
225
+ tx.onerror = function (event) { reject(event.target.error); };
226
+ });
227
+ });
228
+ }
229
+
230
+ // --- Record builders ---
231
+
232
+ function buildSessionRecord(input) {
233
+ var now = new Date().toISOString();
234
+ var titleSource = input.titleSource === 'manual' ? 'manual' : 'auto';
235
+ return {
236
+ id: input.id || generateId('ses'),
237
+ projectId: input.projectId || '',
238
+ title: normalizeSessionTitleForStorage(input.title, titleSource),
239
+ titleSource: titleSource,
240
+ codexThreadId: typeof input.codexThreadId === 'string' ? input.codexThreadId : '',
241
+ status: typeof input.status === 'string' && input.status ? input.status : 'active',
242
+ focusFiles: normalizePathList(input.focusFiles),
243
+ history: compactHistoryForStorage(input.history),
244
+ runs: compactRunsForStorage(input.runs),
245
+ task: normalizeDisplayTextForStorage(input.task, SESSION_STORAGE_LIMITS.taskChars),
246
+ mode: typeof input.mode === 'string' ? input.mode : '',
247
+ model: typeof input.model === 'string' ? input.model : '',
248
+ reasoningEffort: typeof input.reasoningEffort === 'string' ? input.reasoningEffort : '',
249
+ speedTier: typeof input.speedTier === 'string' ? input.speedTier : '',
250
+ requireReviewing: input.requireReviewing !== false,
251
+ createdAt: typeof input.createdAt === 'string' ? input.createdAt : now,
252
+ updatedAt: typeof input.updatedAt === 'string' ? input.updatedAt : now
253
+ };
254
+ }
255
+
256
+ function buildTurnRecord(input) {
257
+ var now = new Date().toISOString();
258
+ return {
259
+ id: input.id || generateId('turn'),
260
+ sessionId: input.sessionId || '',
261
+ task: summarizeTextForStorage(input.task, 'turn task'),
262
+ mode: typeof input.mode === 'string' ? input.mode : '',
263
+ model: typeof input.model === 'string' ? input.model : '',
264
+ reasoningEffort: typeof input.reasoningEffort === 'string' ? input.reasoningEffort : '',
265
+ speedTier: typeof input.speedTier === 'string' ? input.speedTier : '',
266
+ createdAt: typeof input.createdAt === 'string' ? input.createdAt : now,
267
+ completedAt: typeof input.completedAt === 'string' ? input.completedAt : '',
268
+ finalSummary: summarizeTextForStorage(input.finalSummary, 'turn summary')
269
+ };
270
+ }
271
+
272
+ function buildEventRecord(input) {
273
+ var now = new Date().toISOString();
274
+ return {
275
+ id: input.id || generateId('evt'),
276
+ turnId: input.turnId || '',
277
+ index: typeof input.index === 'number' ? input.index : 0,
278
+ kind: typeof input.kind === 'string' ? input.kind : '',
279
+ text: summarizeTextForStorage(input.text, 'event text'),
280
+ detail: compactDetailForStorage(input.detail, SESSION_STORAGE_LIMITS.detailChars) ?? null,
281
+ createdAt: typeof input.createdAt === 'string' ? input.createdAt : now
282
+ };
283
+ }
284
+
285
+ function buildArtifactRecord(input) {
286
+ var now = new Date().toISOString();
287
+ return {
288
+ id: input.id || generateId('art'),
289
+ turnId: input.turnId || '',
290
+ type: typeof input.type === 'string' ? input.type : '',
291
+ path: normalizePath(input.path, SESSION_STORAGE_LIMITS.pathChars),
292
+ payload: compactDetailForStorage(input.payload, SESSION_STORAGE_LIMITS.detailChars) ?? null,
293
+ createdAt: typeof input.createdAt === 'string' ? input.createdAt : now
294
+ };
295
+ }
296
+
297
+ function buildAuditLogRecord(input) {
298
+ var now = new Date().toISOString();
299
+ return {
300
+ id: input.id || generateId('aud'),
301
+ projectId: typeof input.projectId === 'string' ? input.projectId : '',
302
+ sessionId: typeof input.sessionId === 'string' ? input.sessionId : '',
303
+ turnId: typeof input.turnId === 'string' ? input.turnId : '',
304
+ createdAt: typeof input.createdAt === 'string' ? input.createdAt : now,
305
+ completedAt: typeof input.completedAt === 'string' ? input.completedAt : '',
306
+ mode: typeof input.mode === 'string' ? input.mode : '',
307
+ model: typeof input.model === 'string' ? input.model : '',
308
+ reasoningEffort: typeof input.reasoningEffort === 'string' ? input.reasoningEffort : '',
309
+ speedTier: typeof input.speedTier === 'string' ? input.speedTier : '',
310
+ promptSummary: summarizeTextForStorage(input.promptSummary, 'audit prompt'),
311
+ focusFiles: normalizeStringList(input.focusFiles),
312
+ selectedSkillIds: normalizeStringList(input.selectedSkillIds),
313
+ sensitiveFindings: normalizeSensitiveFindings(input.sensitiveFindings),
314
+ changedFiles: normalizeFileSummaries(input.changedFiles),
315
+ diffSummary: normalizeDiffSummary(input.diffSummary),
316
+ blockedFiles: normalizeFileSummaries(input.blockedFiles),
317
+ appliedFiles: normalizeFileSummaries(input.appliedFiles),
318
+ skippedFiles: normalizeFileSummaries(input.skippedFiles),
319
+ resultStatus: typeof input.resultStatus === 'string' && input.resultStatus ? input.resultStatus : 'draft',
320
+ saveVerification: input.saveVerification && typeof input.saveVerification === 'object'
321
+ ? summarizeVerificationObject(input.saveVerification)
322
+ : null
323
+ };
324
+ }
325
+
326
+ // --- Helpers ---
327
+
328
+ function extractLightweightPrefs(state, projectId) {
329
+ var prefs = {
330
+ storageSchemaVersion: TARGET_SCHEMA_VERSION,
331
+ model: typeof state.model === 'string' ? state.model : '',
332
+ reasoningEffort: typeof state.reasoningEffort === 'string' ? state.reasoningEffort : '',
333
+ speedTier: typeof state.speedTier === 'string' ? state.speedTier : '',
334
+ mode: typeof state.mode === 'string' ? state.mode : '',
335
+ locale: typeof state.locale === 'string' ? state.locale : '',
336
+ requireReviewing: state.requireReviewing !== false,
337
+ autoRecompile: state.autoRecompile !== false,
338
+ loadCodexLocalSkills: state.loadCodexLocalSkills !== false,
339
+ loadCodexOverleafSkills: state.loadCodexOverleafSkills !== false,
340
+ panelWidth: Number.isFinite(Number(state.panelWidth)) ? Math.round(Number(state.panelWidth)) : 0,
341
+ activeSessionByProject: state.activeSessionByProject || {},
342
+ experimentalOtByProject: normalizeBooleanMap(state.experimentalOtByProject),
343
+ customInstructionsByProject: normalizeStringMap(state.customInstructionsByProject),
344
+ governanceRulesByProject: normalizeGovernanceRulesMap(state.governanceRulesByProject),
345
+ selectedLocalSkillIdsByProject: normalizeStringListMap(state.selectedLocalSkillIdsByProject)
346
+ };
347
+ return prefs;
348
+ }
349
+
350
+ function normalizeBooleanMap(value) {
351
+ var result = {};
352
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
353
+ return result;
354
+ }
355
+ var keys = Object.keys(value);
356
+ for (var i = 0; i < keys.length; i++) {
357
+ var key = keys[i];
358
+ if (!key) {
359
+ continue;
360
+ }
361
+ result[key] = value[key] === true;
362
+ }
363
+ return result;
364
+ }
365
+
366
+ function normalizeStringMap(value) {
367
+ var result = {};
368
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
369
+ return result;
370
+ }
371
+ var keys = Object.keys(value);
372
+ for (var i = 0; i < keys.length; i++) {
373
+ var rawKey = keys[i];
374
+ var key = normalizeProjectPrefKey(rawKey);
375
+ if (!key) {
376
+ continue;
377
+ }
378
+ result[key] = typeof value[rawKey] === 'string'
379
+ ? normalizeTextField(value[rawKey], CUSTOM_INSTRUCTIONS_MAX_CHARS)
380
+ : '';
381
+ }
382
+ return result;
383
+ }
384
+
385
+ function normalizeStringListMap(value) {
386
+ var result = {};
387
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
388
+ return result;
389
+ }
390
+ var keys = Object.keys(value);
391
+ for (var i = 0; i < keys.length; i++) {
392
+ var rawKey = keys[i];
393
+ var key = normalizeProjectPrefKey(rawKey);
394
+ if (!key) {
395
+ continue;
396
+ }
397
+ result[key] = normalizeStringList(value[rawKey]);
398
+ }
399
+ return result;
400
+ }
401
+
402
+ function normalizeGovernanceRulesMap(value) {
403
+ var result = {};
404
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
405
+ return result;
406
+ }
407
+ var keys = Object.keys(value);
408
+ for (var i = 0; i < keys.length; i++) {
409
+ var rawKey = keys[i];
410
+ var key = normalizeProjectPrefKey(rawKey);
411
+ if (!key) {
412
+ continue;
413
+ }
414
+ var rules = value[rawKey] && typeof value[rawKey] === 'object' && !Array.isArray(value[rawKey])
415
+ ? value[rawKey]
416
+ : {};
417
+ result[key] = {
418
+ readonlyPatterns: normalizePatternList(rules.readonlyPatterns),
419
+ writablePatterns: normalizePatternList(rules.writablePatterns),
420
+ sensitiveCheckEnabled: rules.sensitiveCheckEnabled !== false,
421
+ sensitiveConfirmAllowed: rules.sensitiveConfirmAllowed === true
422
+ };
423
+ }
424
+ return result;
425
+ }
426
+
427
+ function normalizePatternList(value) {
428
+ return normalizeStringList(value).map(function (pattern) {
429
+ return pattern.replace(/\\/g, '/').replace(/^\/+/, '').replace(/\/+/g, '/');
430
+ }).filter(Boolean);
431
+ }
432
+
433
+ function normalizeStringList(values) {
434
+ var result = [];
435
+ var seen = {};
436
+ if (!Array.isArray(values)) {
437
+ return result;
438
+ }
439
+ for (var i = 0; i < values.length; i++) {
440
+ var text = typeof values[i] === 'string' ? values[i].trim() : '';
441
+ if (!text || seen[text]) {
442
+ continue;
443
+ }
444
+ seen[text] = true;
445
+ result.push(text);
446
+ }
447
+ return result;
448
+ }
449
+
450
+ function normalizeSensitiveFindings(findings) {
451
+ var result = [];
452
+ if (!Array.isArray(findings)) {
453
+ return result;
454
+ }
455
+ for (var i = 0; i < findings.length; i++) {
456
+ var finding = findings[i] || {};
457
+ result.push(removeEmptyFields({
458
+ detectorId: typeof finding.detectorId === 'string' ? finding.detectorId : '',
459
+ path: typeof finding.path === 'string' ? finding.path : '',
460
+ source: typeof finding.source === 'string' ? finding.source : '',
461
+ preview: summarizeTextForStorage(finding.preview, 'sensitive preview')
462
+ }));
463
+ }
464
+ return result;
465
+ }
466
+
467
+ function summarizeVerificationObject(value) {
468
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
469
+ return null;
470
+ }
471
+ var summary = {
472
+ state: normalizeTextField(value.state, 80),
473
+ status: normalizeTextField(value.status, 80),
474
+ ok: typeof value.ok === 'boolean' ? value.ok : undefined,
475
+ errorCode: normalizeTextField(value.errorCode || value.code, 120),
476
+ errorCategory: categorizeError(value.errorCode || value.code || value.reason || value.message || value.error)
477
+ };
478
+ if (value.diagnostics && typeof value.diagnostics === 'object' && !Array.isArray(value.diagnostics)) {
479
+ summary.diagnostics = summarizeStatusObject(value.diagnostics);
480
+ }
481
+ return removeEmptySummaryFields(summary);
482
+ }
483
+
484
+ function summarizeStatusObject(value) {
485
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
486
+ return undefined;
487
+ }
488
+ return removeEmptySummaryFields({
489
+ state: normalizeTextField(value.state, 80),
490
+ status: normalizeTextField(value.status, 80),
491
+ ok: typeof value.ok === 'boolean' ? value.ok : undefined,
492
+ errorCode: normalizeTextField(value.errorCode || value.code, 120),
493
+ errorCategory: categorizeError(value.errorCode || value.code || value.message || value.error)
494
+ });
495
+ }
496
+
497
+ function normalizeSessionTitleForStorage(value, titleSource) {
498
+ var title = typeof value === 'string' ? value.trim() : '';
499
+ if (titleSource === 'manual') {
500
+ return normalizeTextField(title === LEGACY_DEFAULT_SESSION_TITLE ? '' : title, SESSION_STORAGE_LIMITS.sessionTitleChars);
501
+ }
502
+ return normalizeTextField(title === LEGACY_DEFAULT_SESSION_TITLE ? '' : title, SESSION_STORAGE_LIMITS.sessionTitleChars);
503
+ }
504
+
505
+ function compactHistoryForStorage(history) {
506
+ return (Array.isArray(history) ? history : [])
507
+ .slice(-SESSION_STORAGE_LIMITS.maxHistory)
508
+ .map(function (entry) {
509
+ return {
510
+ task: normalizeDisplayTextForStorage(entry && entry.task, SESSION_STORAGE_LIMITS.historyTaskChars),
511
+ result: normalizeDisplayTextForStorage(entry && entry.result, SESSION_STORAGE_LIMITS.historyResultChars),
512
+ at: typeof (entry && entry.at) === 'string' ? redactSecretLikeText(entry.at) : ''
513
+ };
514
+ });
515
+ }
516
+
517
+ function compactRunsForStorage(runs) {
518
+ return (Array.isArray(runs) ? runs : [])
519
+ .filter(function (run) { return run && typeof run.id === 'string'; })
520
+ .slice(-SESSION_STORAGE_LIMITS.maxRunsPerSession)
521
+ .map(compactRunForStorage);
522
+ }
523
+
524
+ function compactRunForStorage(run) {
525
+ return {
526
+ id: run.id,
527
+ task: normalizeDisplayTextForStorage(run.task || 'untitled task', SESSION_STORAGE_LIMITS.taskChars),
528
+ mode: typeof run.mode === 'string' ? redactSecretLikeText(run.mode) : '',
529
+ model: normalizeTextField(run.model, 80),
530
+ reasoningEffort: typeof run.reasoningEffort === 'string' ? redactSecretLikeText(run.reasoningEffort) : '',
531
+ speedTier: typeof run.speedTier === 'string' ? redactSecretLikeText(run.speedTier) : '',
532
+ status: normalizeRunStatus(run.status),
533
+ statusText: normalizeDisplayTextForStorage(run.statusText, SESSION_STORAGE_LIMITS.statusTextChars),
534
+ startedAt: typeof run.startedAt === 'string' ? redactSecretLikeText(run.startedAt) : '',
535
+ finishedAt: typeof run.finishedAt === 'string' ? redactSecretLikeText(run.finishedAt) : '',
536
+ events: compactRunEventsForStorage(run.events),
537
+ attachments: compactRunAttachmentsForStorage(run.attachments),
538
+ appliedOperations: [],
539
+ undoOperations: [],
540
+ undoBaseFiles: [],
541
+ undoTrackedChanges: [],
542
+ undoExpectedFiles: [],
543
+ undoStatus: normalizeDisplayTextForStorage(run.undoStatus, SESSION_STORAGE_LIMITS.statusTextChars)
544
+ };
545
+ }
546
+
547
+ function compactRunEventsForStorage(events) {
548
+ return (Array.isArray(events) ? events : [])
549
+ .filter(function (event) { return event && typeof event.title === 'string'; })
550
+ .slice(-SESSION_STORAGE_LIMITS.maxEventsPerRun)
551
+ .map(function (event) {
552
+ var compact = {
553
+ title: normalizeDisplayTextForStorage(event.title, SESSION_STORAGE_LIMITS.eventTitleChars) || 'Event',
554
+ status: normalizeEventStatus(event.status),
555
+ timestamp: typeof event.timestamp === 'string' ? redactSecretLikeText(event.timestamp) : '',
556
+ kind: typeof event.kind === 'string' ? redactSecretLikeText(event.kind) : 'activity',
557
+ streamKey: typeof event.streamKey === 'string' ? redactSecretLikeText(event.streamKey) : '',
558
+ streamRole: typeof event.streamRole === 'string' ? redactSecretLikeText(event.streamRole) : ''
559
+ };
560
+ var detail = compactDisplayDetailForStorage(event.detail, getEventDetailLimit(event));
561
+ if (detail !== undefined) {
562
+ compact.detail = detail;
563
+ }
564
+ return compact;
565
+ });
566
+ }
567
+
568
+ function getEventDetailLimit(event) {
569
+ return event && event.kind === 'report'
570
+ ? SESSION_STORAGE_LIMITS.reportDetailChars
571
+ : SESSION_STORAGE_LIMITS.detailChars;
572
+ }
573
+
574
+ function compactDetailForStorage(detail, maxChars) {
575
+ if (detail === undefined) {
576
+ return undefined;
577
+ }
578
+ if (typeof detail === 'string') {
579
+ return summarizeTextForStorage(detail, 'detail');
580
+ }
581
+ if (detail === null || typeof detail === 'number' || typeof detail === 'boolean') {
582
+ return detail;
583
+ }
584
+ return summarizeStructuredValueForStorage(detail, maxChars);
585
+ }
586
+
587
+ function compactDisplayDetailForStorage(detail, maxChars) {
588
+ if (detail === undefined) {
589
+ return undefined;
590
+ }
591
+ if (typeof detail === 'string') {
592
+ return normalizeDisplayTextForStorage(detail, maxChars);
593
+ }
594
+ if (detail === null || typeof detail === 'number' || typeof detail === 'boolean') {
595
+ return detail;
596
+ }
597
+ return summarizeStructuredValueForStorage(detail, maxChars);
598
+ }
599
+
600
+ function normalizeDisplayTextForStorage(value, maxChars) {
601
+ return normalizeTextField(value, maxChars);
602
+ }
603
+
604
+ function summarizeStructuredValueForStorage(value, maxChars) {
605
+ if (isStructuredStorageSummary(value)) {
606
+ return normalizeStructuredStorageSummary(value);
607
+ }
608
+ var serialized = safeJsonStringify(value);
609
+ var summary = {
610
+ redacted: true,
611
+ type: Array.isArray(value) ? 'array' : 'object',
612
+ chars: serialized.length,
613
+ hash: hashString(serialized)
614
+ };
615
+ var paths = collectPathMetadata(value, maxChars);
616
+ if (paths.items.length) {
617
+ summary.paths = paths.items;
618
+ summary.pathCount = paths.count;
619
+ }
620
+ return summary;
621
+ }
622
+
623
+ function normalizeStructuredStorageSummary(value) {
624
+ var result = {
625
+ redacted: true,
626
+ type: value.type === 'array' ? 'array' : 'object',
627
+ chars: nonNegativeInteger(value.chars),
628
+ hash: /^[a-f0-9]{8}$/.test(String(value.hash || '')) ? value.hash : hashString('')
629
+ };
630
+ var paths = normalizePathList(value.paths).slice(0, 5);
631
+ if (paths.length) {
632
+ result.paths = paths;
633
+ result.pathCount = nonNegativeInteger(value.pathCount) || paths.length;
634
+ }
635
+ return result;
636
+ }
637
+
638
+ function collectPathMetadata(value, maxChars, state) {
639
+ state = state || { seen: {}, items: [], count: 0 };
640
+ if (!value || typeof value !== 'object') {
641
+ return state;
642
+ }
643
+ if (Array.isArray(value)) {
644
+ for (var i = 0; i < value.length; i++) {
645
+ collectPathMetadata(value[i], maxChars, state);
646
+ }
647
+ return state;
648
+ }
649
+ var keys = Object.keys(value);
650
+ for (var j = 0; j < keys.length; j++) {
651
+ var key = keys[j];
652
+ var item = value[key];
653
+ if (/(^|[A-Z_])path$/i.test(key) && typeof item === 'string') {
654
+ var path = normalizePath(item, Math.min(maxChars || SESSION_STORAGE_LIMITS.pathChars, SESSION_STORAGE_LIMITS.pathChars));
655
+ if (path) {
656
+ state.count += 1;
657
+ if (!state.seen[path] && state.items.length < 5) {
658
+ state.seen[path] = true;
659
+ state.items.push(path);
660
+ }
661
+ }
662
+ } else {
663
+ collectPathMetadata(item, maxChars, state);
664
+ }
665
+ }
666
+ return state;
667
+ }
668
+
669
+ function compactRunAttachmentsForStorage(attachments) {
670
+ var result = [];
671
+ var items = Array.isArray(attachments) ? attachments : [];
672
+ for (var i = 0; i < items.length; i++) {
673
+ var attachment = items[i] || {};
674
+ var name = normalizeAttachmentName(attachment.name);
675
+ if (!name) {
676
+ continue;
677
+ }
678
+ var mimeType = normalizeTextField(attachment.mimeType, 120);
679
+ var size = Number(attachment.size);
680
+ var kind = attachment.kind === 'image' || /^image\//i.test(mimeType) ? 'image' : 'file';
681
+ result.push({
682
+ name: name,
683
+ mimeType: mimeType,
684
+ size: Number.isFinite(size) && size >= 0 ? Math.round(size) : 0,
685
+ kind: kind
686
+ });
687
+ if (result.length >= SESSION_STORAGE_LIMITS.maxAttachmentsPerRun) {
688
+ break;
689
+ }
690
+ }
691
+ return result;
692
+ }
693
+
694
+ function normalizeAttachmentName(value) {
695
+ return normalizeTextField(String(value || '')
696
+ .replace(/\0/g, '')
697
+ .replace(/\\/g, '/')
698
+ .split('/')
699
+ .filter(Boolean)
700
+ .pop() || '', 180);
701
+ }
702
+
703
+ function normalizePathList(values) {
704
+ var result = [];
705
+ var seen = {};
706
+ if (!Array.isArray(values)) {
707
+ return result;
708
+ }
709
+ for (var i = 0; i < values.length; i++) {
710
+ var path = normalizePath(values[i], SESSION_STORAGE_LIMITS.pathChars);
711
+ if (!path || seen[path]) {
712
+ continue;
713
+ }
714
+ seen[path] = true;
715
+ result.push(path);
716
+ }
717
+ return result;
718
+ }
719
+
720
+ function normalizePath(value, maxChars) {
721
+ return normalizeTextField(String(value || '')
722
+ .replace(/\\/g, '/')
723
+ .replace(/^\/+/, '')
724
+ .replace(/\/+/g, '/')
725
+ .trim(), maxChars || SESSION_STORAGE_LIMITS.pathChars);
726
+ }
727
+
728
+ function normalizeRunStatus(status) {
729
+ return ['running', 'completed', 'failed'].indexOf(status) !== -1 ? status : 'completed';
730
+ }
731
+
732
+ function normalizeEventStatus(status) {
733
+ return VALID_EVENT_STATUSES[status] ? status : 'info';
734
+ }
735
+
736
+ function normalizeFileSummaries(files) {
737
+ var result = [];
738
+ if (!Array.isArray(files)) {
739
+ return result;
740
+ }
741
+ for (var i = 0; i < files.length; i++) {
742
+ var file = files[i];
743
+ if (typeof file === 'string') {
744
+ result.push({ path: file });
745
+ continue;
746
+ }
747
+ file = file || {};
748
+ result.push(removeEmptyFields({
749
+ path: typeof file.path === 'string' ? file.path : '',
750
+ destinationPath: typeof file.destinationPath === 'string' ? file.destinationPath : '',
751
+ type: typeof file.type === 'string' ? file.type : '',
752
+ reason: typeof file.reason === 'string' ? file.reason : '',
753
+ status: typeof file.status === 'string' ? file.status : '',
754
+ size: Number.isFinite(Number(file.size)) ? Number(file.size) : undefined
755
+ }));
756
+ }
757
+ return result;
758
+ }
759
+
760
+ function normalizeDiffSummary(summary) {
761
+ summary = summary && typeof summary === 'object' ? summary : {};
762
+ return {
763
+ filesChanged: nonNegativeInteger(summary.filesChanged),
764
+ additions: nonNegativeInteger(summary.additions),
765
+ deletions: nonNegativeInteger(summary.deletions),
766
+ binaryFilesChanged: nonNegativeInteger(summary.binaryFilesChanged)
767
+ };
768
+ }
769
+
770
+ function normalizeProjectPrefKey(value) {
771
+ var key = typeof value === 'string' ? value.trim() : '';
772
+ if (!key) {
773
+ return '';
774
+ }
775
+ return normalizeTextField(key, PROJECT_PREF_KEY_MAX_CHARS);
776
+ }
777
+
778
+ function summarizeTextForStorage(value, label) {
779
+ if (typeof value !== 'string' || !value.trim()) {
780
+ return '';
781
+ }
782
+ var text = redactSecretLikeText(value);
783
+ if (isOmittedStorageSummary(text)) {
784
+ return text;
785
+ }
786
+ return '[' + label + ' omitted; chars=' + text.length + '; hash=' + hashString(text) + ']';
787
+ }
788
+
789
+ function isOmittedStorageSummary(value) {
790
+ return /^\[[^\]]+ omitted; chars=\d+; hash=[a-f0-9]{8}\]$/.test(String(value || '').trim());
791
+ }
792
+
793
+ function isStructuredStorageSummary(value) {
794
+ return Boolean(value && typeof value === 'object' && !Array.isArray(value)
795
+ && value.redacted === true
796
+ && (value.type === 'array' || value.type === 'object')
797
+ && Number.isFinite(Number(value.chars))
798
+ && /^[a-f0-9]{8}$/.test(String(value.hash || '')));
799
+ }
800
+
801
+ function redactSecretLikeText(value) {
802
+ if (typeof value !== 'string') {
803
+ return '';
804
+ }
805
+ var redacted = value;
806
+ for (var i = 0; i < SECRET_REDACTION_PATTERNS.length; i++) {
807
+ var pattern = SECRET_REDACTION_PATTERNS[i];
808
+ pattern.lastIndex = 0;
809
+ redacted = redacted.replace(pattern, REDACTED_SECRET);
810
+ }
811
+ return redacted;
812
+ }
813
+
814
+ function normalizeTextField(value, maxChars) {
815
+ var text = typeof value === 'string' ? redactSecretLikeText(value) : '';
816
+ if (!Number.isFinite(maxChars) || maxChars <= 0 || text.length <= maxChars) {
817
+ return text;
818
+ }
819
+ return text.slice(0, Math.max(0, maxChars - 1)) + '…';
820
+ }
821
+
822
+ function nonNegativeInteger(value) {
823
+ var number = Number(value);
824
+ return Number.isFinite(number) && number > 0 ? Math.floor(number) : 0;
825
+ }
826
+
827
+ function categorizeError(value) {
828
+ var text = redactSecretLikeText(typeof value === 'string' ? value : '').toLowerCase();
829
+ if (!text) {
830
+ return undefined;
831
+ }
832
+ if (/timeout|timed out|etimedout/.test(text)) {
833
+ return 'timeout';
834
+ }
835
+ if (/permission|denied|eacces|eperm/.test(text)) {
836
+ return 'permission';
837
+ }
838
+ if (/not found|missing|enoent|unavailable/.test(text)) {
839
+ return 'missing';
840
+ }
841
+ if (/quota|too large|limit/.test(text)) {
842
+ return 'quota';
843
+ }
844
+ return 'error';
845
+ }
846
+
847
+ function removeEmptySummaryFields(value) {
848
+ var result = {};
849
+ var keys = Object.keys(value || {});
850
+ for (var i = 0; i < keys.length; i++) {
851
+ var key = keys[i];
852
+ var item = value[key];
853
+ if (item === undefined || item === '' || item === null) {
854
+ continue;
855
+ }
856
+ if (Array.isArray(item) && item.length === 0) {
857
+ continue;
858
+ }
859
+ if (item && typeof item === 'object' && !Array.isArray(item) && Object.keys(item).length === 0) {
860
+ continue;
861
+ }
862
+ result[key] = item;
863
+ }
864
+ return result;
865
+ }
866
+
867
+ function removeEmptyFields(value) {
868
+ var result = {};
869
+ var keys = Object.keys(value);
870
+ for (var i = 0; i < keys.length; i++) {
871
+ var key = keys[i];
872
+ if (value[key] !== undefined && value[key] !== '') {
873
+ result[key] = value[key];
874
+ }
875
+ }
876
+ return result;
877
+ }
878
+
879
+ function buildActiveSessionByProject(existing, projectId, sessionId) {
880
+ var result = {};
881
+ if (existing && typeof existing === 'object') {
882
+ var keys = Object.keys(existing);
883
+ for (var i = 0; i < keys.length; i++) {
884
+ result[keys[i]] = existing[keys[i]];
885
+ }
886
+ }
887
+ if (typeof projectId === 'string' && projectId) {
888
+ result[projectId] = sessionId || '';
889
+ }
890
+ return result;
891
+ }
892
+
893
+ function createEventBuffer(turnId, flushIntervalMs, maxBatchSize) {
894
+ if (flushIntervalMs === undefined) { flushIntervalMs = 500; }
895
+ if (maxBatchSize === undefined) { maxBatchSize = 20; }
896
+
897
+ var buffer = [];
898
+ var timer = null;
899
+
900
+ function scheduleFlush() {
901
+ if (timer !== null) { return; }
902
+ timer = setTimeout(function () {
903
+ timer = null;
904
+ flush();
905
+ }, flushIntervalMs);
906
+ }
907
+
908
+ function flush() {
909
+ if (timer !== null) {
910
+ clearTimeout(timer);
911
+ timer = null;
912
+ }
913
+ if (buffer.length === 0) { return Promise.resolve([]); }
914
+ var batch = buffer.splice(0);
915
+ return putRecords('events', batch);
916
+ }
917
+
918
+ function add(event) {
919
+ var record = buildEventRecord(Object.assign({}, event, { turnId: turnId }));
920
+ buffer.push(record);
921
+ if (buffer.length >= maxBatchSize) {
922
+ flush();
923
+ } else {
924
+ scheduleFlush();
925
+ }
926
+ return record;
927
+ }
928
+
929
+ return { add: add, flush: flush };
930
+ }
931
+
932
+ // --- Utilities ---
933
+
934
+ function generateId(prefix) {
935
+ return prefix + '_' + Date.now().toString(36) + '_' + Math.random().toString(36).slice(2, 8);
936
+ }
937
+
938
+ function safeJsonStringify(value) {
939
+ try {
940
+ return JSON.stringify(value) || '';
941
+ } catch (_error) {
942
+ return '[unserializable]';
943
+ }
944
+ }
945
+
946
+ function hashString(value) {
947
+ var hash = 2166136261;
948
+ var text = String(value || '');
949
+ for (var i = 0; i < text.length; i++) {
950
+ hash ^= text.charCodeAt(i);
951
+ hash = Math.imul(hash, 16777619);
952
+ }
953
+ return (hash >>> 0).toString(16).padStart(8, '0');
954
+ }
955
+
956
+ function cloneJsonValue(value) {
957
+ try {
958
+ return JSON.parse(JSON.stringify(value));
959
+ } catch (_error) {
960
+ return Array.isArray(value) ? value.slice() : value;
961
+ }
962
+ }
963
+
964
+ return {
965
+ TARGET_SCHEMA_VERSION: TARGET_SCHEMA_VERSION,
966
+ DB_NAME: DB_NAME,
967
+ STORES: STORES,
968
+ openDb: openDb,
969
+ putRecord: putRecord,
970
+ putRecords: putRecords,
971
+ getRecord: getRecord,
972
+ getAllByIndex: getAllByIndex,
973
+ deleteRecord: deleteRecord,
974
+ deleteByIndex: deleteByIndex,
975
+ clearStore: clearStore,
976
+ clearAllStores: clearAllStores,
977
+ buildSessionRecord: buildSessionRecord,
978
+ buildTurnRecord: buildTurnRecord,
979
+ buildEventRecord: buildEventRecord,
980
+ buildArtifactRecord: buildArtifactRecord,
981
+ buildAuditLogRecord: buildAuditLogRecord,
982
+ extractLightweightPrefs: extractLightweightPrefs,
983
+ buildActiveSessionByProject: buildActiveSessionByProject,
984
+ createEventBuffer: createEventBuffer
985
+ };
986
+ });