sidekick-shared 0.27.6 → 0.28.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.
- package/CHANGELOG.md +28 -0
- package/README.md +58 -18
- package/dist/browser.d.ts +13 -2
- package/dist/browser.js +30 -2
- package/dist/claudePaths.d.ts +11 -0
- package/dist/claudePaths.js +61 -0
- package/dist/claudeProfiles.d.ts +2 -9
- package/dist/claudeProfiles.js +10 -25
- package/dist/codexPaths.d.ts +22 -0
- package/dist/codexPaths.js +67 -0
- package/dist/codexProfiles.d.ts +1 -4
- package/dist/codexProfiles.js +5 -43
- package/dist/doctor.js +2 -2
- package/dist/esm/accountChangeSignal.js +15 -0
- package/dist/esm/accountChanges.js +152 -0
- package/dist/esm/accountHealth.js +288 -0
- package/dist/esm/accountLaunch.js +145 -0
- package/dist/esm/accountLease.js +60 -0
- package/dist/esm/accountManager.js +606 -0
- package/dist/esm/accountRegistry.js +214 -0
- package/dist/esm/accountStatus.js +51 -0
- package/dist/esm/accountSwitch.js +74 -0
- package/dist/esm/accountSync.js +156 -0
- package/dist/esm/accountSyncTypes.js +4 -0
- package/dist/esm/accounts.js +1291 -0
- package/dist/esm/aggregation/EventAggregator.js +2034 -0
- package/dist/esm/aggregation/FrequencyTracker.js +69 -0
- package/dist/esm/aggregation/HeatmapTracker.js +89 -0
- package/dist/esm/aggregation/PatternExtractor.js +168 -0
- package/dist/esm/aggregation/costProvenance.js +31 -0
- package/dist/esm/aggregation/snapshot.js +161 -0
- package/dist/esm/aggregation/types.js +5 -0
- package/dist/esm/analytics/codeImpact.js +18 -0
- package/dist/esm/analytics/compactionLedger.js +37 -0
- package/dist/esm/analytics/qualityScore.js +112 -0
- package/dist/esm/autoSwitch.js +185 -0
- package/dist/esm/browser.js +34 -0
- package/dist/esm/claudeCredentialDoctor.js +239 -0
- package/dist/esm/claudeCredentialLedger.js +91 -0
- package/dist/esm/claudeCredentials.js +111 -0
- package/dist/esm/claudeLiveGuard.js +43 -0
- package/dist/esm/claudePaths.js +22 -0
- package/dist/esm/claudeProfiles.js +142 -0
- package/dist/esm/claudeRefreshLock.js +106 -0
- package/dist/esm/codexAuth.js +101 -0
- package/dist/esm/codexCredentialDoctor.js +265 -0
- package/dist/esm/codexCredentialStore.js +164 -0
- package/dist/esm/codexKeepAlive.js +112 -0
- package/dist/esm/codexPaths.js +172 -0
- package/dist/esm/codexProfiles.js +1251 -0
- package/dist/esm/codexQuota.js +564 -0
- package/dist/esm/codexQuotaWatcher.js +363 -0
- package/dist/esm/context/composer.js +71 -0
- package/dist/esm/context/sessionContext.js +546 -0
- package/dist/esm/credentialIO.js +283 -0
- package/dist/esm/credentials.js +49 -0
- package/dist/esm/doctor.js +305 -0
- package/dist/esm/ensureDefaultAccounts.js +62 -0
- package/dist/esm/errorHistory.js +56 -0
- package/dist/esm/extractors/errorTaxonomy.js +43 -0
- package/dist/esm/extractors/gatherAssets.js +32 -0
- package/dist/esm/extractors/sessionAssets.js +176 -0
- package/dist/esm/extractors/sources/claudeAssets.js +158 -0
- package/dist/esm/extractors/sources/codexAssets.js +234 -0
- package/dist/esm/extractors/tokenUsage.js +41 -0
- package/dist/esm/extractors/toolCall.js +142 -0
- package/dist/esm/failingTools.js +65 -0
- package/dist/esm/fileHead.js +27 -0
- package/dist/esm/formatters/eventHighlighter.js +332 -0
- package/dist/esm/formatters/noiseClassifier.js +209 -0
- package/dist/esm/formatters/sessionDump.js +328 -0
- package/dist/esm/formatters/toolSummary.js +226 -0
- package/dist/esm/formatting.js +82 -0
- package/dist/esm/handoffUrl.js +23 -0
- package/dist/esm/historicalStore.js +305 -0
- package/dist/esm/humanPrompt.js +88 -0
- package/dist/esm/index.js +213 -0
- package/dist/esm/keepAlive.js +189 -0
- package/dist/esm/liveCredentialGuard.js +33 -0
- package/dist/esm/modelAliases.js +51 -0
- package/dist/esm/modelCatalog.js +139 -0
- package/dist/esm/modelContext.js +280 -0
- package/dist/esm/modelInfo.js +832 -0
- package/dist/esm/multiProviderQuotaService.js +450 -0
- package/dist/esm/node.js +46 -0
- package/dist/esm/observedContextWindows.js +165 -0
- package/dist/esm/observedSessionCollector.js +939 -0
- package/dist/esm/parsers/changelogParser.js +71 -0
- package/dist/esm/parsers/codexHistory.js +89 -0
- package/dist/esm/parsers/codexParser.js +906 -0
- package/dist/esm/parsers/debugLogParser.js +126 -0
- package/dist/esm/parsers/jsonl.js +66 -0
- package/dist/esm/parsers/mcpToolName.js +28 -0
- package/dist/esm/parsers/openCodeParser.js +625 -0
- package/dist/esm/parsers/planExtractor.js +335 -0
- package/dist/esm/parsers/sessionActivityDetector.js +246 -0
- package/dist/esm/parsers/sessionPathResolver.js +713 -0
- package/dist/esm/parsers/subagentScanner.js +360 -0
- package/dist/esm/parsers/subagentStatsCache.js +45 -0
- package/dist/esm/parsers/subagentTraceParser.js +325 -0
- package/dist/esm/paths.js +134 -0
- package/dist/esm/peakHours.js +194 -0
- package/dist/esm/phrases.js +1330 -0
- package/dist/esm/pricingCatalog.js +247 -0
- package/dist/esm/processDetection.js +200 -0
- package/dist/esm/projectMigration.js +59 -0
- package/dist/esm/promptHistory.js +1221 -0
- package/dist/esm/providerFailure.js +362 -0
- package/dist/esm/providerIds.js +6 -0
- package/dist/esm/providerQuota.js +1 -0
- package/dist/esm/providerServiceStatus.js +145 -0
- package/dist/esm/providerServiceStatusTypes.js +1 -0
- package/dist/esm/providerStatus.js +117 -0
- package/dist/esm/providers/claudeCode.js +575 -0
- package/dist/esm/providers/claudeListing.js +121 -0
- package/dist/esm/providers/codex.js +1034 -0
- package/dist/esm/providers/codexDatabase.js +297 -0
- package/dist/esm/providers/codexRollouts.js +215 -0
- package/dist/esm/providers/detect.js +185 -0
- package/dist/esm/providers/diagnostics.js +83 -0
- package/dist/esm/providers/directoryListingCache.js +206 -0
- package/dist/esm/providers/factory.js +54 -0
- package/dist/esm/providers/openCode.js +2008 -0
- package/dist/esm/providers/openCodeDatabase.js +419 -0
- package/dist/esm/providers/rolloutWalker.js +252 -0
- package/dist/esm/providers/types.js +12 -0
- package/dist/esm/quota.js +182 -0
- package/dist/esm/quotaHistory.js +364 -0
- package/dist/esm/quotaPoller.js +230 -0
- package/dist/esm/quotaPresentation.js +97 -0
- package/dist/esm/quotaResolver.js +231 -0
- package/dist/esm/quotaSnapshots.js +130 -0
- package/dist/esm/quotaThresholds.js +85 -0
- package/dist/esm/readers/decisions.js +24 -0
- package/dist/esm/readers/handoff.js +20 -0
- package/dist/esm/readers/helpers.js +27 -0
- package/dist/esm/readers/history.js +9 -0
- package/dist/esm/readers/notes.js +48 -0
- package/dist/esm/readers/plans.js +225 -0
- package/dist/esm/readers/tasks.js +19 -0
- package/dist/esm/report/htmlHelpers.js +280 -0
- package/dist/esm/report/htmlReportGenerator.js +704 -0
- package/dist/esm/report/index.js +7 -0
- package/dist/esm/report/logo.js +2 -0
- package/dist/esm/report/openBrowser.js +19 -0
- package/dist/esm/report/sessionReportInputs.js +33 -0
- package/dist/esm/report/transcriptParser.js +83 -0
- package/dist/esm/report/types.js +4 -0
- package/dist/esm/schemas/accountManager.js +204 -0
- package/dist/esm/schemas/accountStatus.js +25 -0
- package/dist/esm/schemas/assistantTurn.js +74 -0
- package/dist/esm/schemas/index.js +25 -0
- package/dist/esm/schemas/observedSessionV1.js +77 -0
- package/dist/esm/schemas/providerFailure.js +37 -0
- package/dist/esm/schemas/quota.js +132 -0
- package/dist/esm/schemas/quotaHistory.js +40 -0
- package/dist/esm/schemas/sessionEvent.js +216 -0
- package/dist/esm/schemas/stateFile.js +75 -0
- package/dist/esm/schemas/tokenEstimation.js +7 -0
- package/dist/esm/schemas/transcript.js +86 -0
- package/dist/esm/schemas/usageNormalization.js +38 -0
- package/dist/esm/search/advancedFilter.js +197 -0
- package/dist/esm/search/sessionSearch.js +66 -0
- package/dist/esm/sessionFingerprint.js +40 -0
- package/dist/esm/sessionMonitor.js +198 -0
- package/dist/esm/sessionPreviews.js +522 -0
- package/dist/esm/sessionPromptHistory.js +254 -0
- package/dist/esm/sessionPromptSignals.js +364 -0
- package/dist/esm/sessionStats.js +160 -0
- package/dist/esm/sessionTokenTotals.js +98 -0
- package/dist/esm/sessionTranscripts.js +49 -0
- package/dist/esm/stateFile.js +119 -0
- package/dist/esm/statusline/BurnRateCalculator.js +40 -0
- package/dist/esm/statusline/claudeStatuslinePayload.js +148 -0
- package/dist/esm/statusline/formatter.js +122 -0
- package/dist/esm/statusline/index.js +8 -0
- package/dist/esm/terminalSync.js +95 -0
- package/dist/esm/testing/credentialGuard.js +197 -0
- package/dist/esm/testing/index.js +12 -0
- package/dist/esm/testing/sessionLogFixtures.js +128 -0
- package/dist/esm/tokenEstimation.js +67 -0
- package/dist/esm/tokenSummary.js +113 -0
- package/dist/esm/toolCategory.js +82 -0
- package/dist/esm/transcript.js +257 -0
- package/dist/esm/turns/assistantTurn.js +373 -0
- package/dist/esm/types/codex.js +23 -0
- package/dist/esm/types/decisionLog.js +5 -0
- package/dist/esm/types/historicalData.js +47 -0
- package/dist/esm/types/knowledgeNote.js +15 -0
- package/dist/esm/types/observedSessionV1.js +257 -0
- package/dist/esm/types/opencode.js +12 -0
- package/dist/esm/types/plan.js +7 -0
- package/dist/esm/types/sessionEvent.js +10 -0
- package/dist/esm/types/taskPersistence.js +12 -0
- package/dist/esm/usage/billingBlocks.js +148 -0
- package/dist/esm/usage/claudeUsageDedupe.js +189 -0
- package/dist/esm/usage/importSessionHistory.js +84 -0
- package/dist/esm/usage/subagentUsage.js +18 -0
- package/dist/esm/usage/usageEvents.js +402 -0
- package/dist/esm/usage/usageReports.js +202 -0
- package/dist/esm/usageNormalization.js +95 -0
- package/dist/esm/watchers/eventBridge.js +219 -0
- package/dist/esm/watchers/factory.js +63 -0
- package/dist/esm/watchers/jsonlTail.js +289 -0
- package/dist/esm/watchers/jsonlWatcher.js +435 -0
- package/dist/esm/watchers/providerReaderWatcher.js +118 -0
- package/dist/esm/watchers/sqliteWatcher.js +285 -0
- package/dist/esm/watchers/types.js +4 -0
- package/dist/esm/workspaceRoots.js +56 -0
- package/dist/esm/writers/atomic.js +375 -0
- package/dist/esm/writers/decisions.js +51 -0
- package/dist/esm/writers/notes.js +46 -0
- package/dist/esm/writers/tasks.js +63 -0
- package/dist/esm/zaiQuota.js +323 -0
- package/dist/esm/zaiQuotaApi.js +271 -0
- package/dist/esm/zaiQuotaWatcher.js +265 -0
- package/dist/fileHead.d.ts +22 -0
- package/dist/fileHead.js +33 -0
- package/dist/index.d.ts +16 -7
- package/dist/index.js +49 -15
- package/dist/node.d.ts +13 -1
- package/dist/node.js +43 -2
- package/dist/parsers/codexHistory.js +2 -2
- package/dist/parsers/codexParser.d.ts +12 -0
- package/dist/parsers/codexParser.js +34 -12
- package/dist/parsers/debugLogParser.js +2 -2
- package/dist/parsers/sessionPathResolver.js +5 -4
- package/dist/promptHistory.d.ts +32 -0
- package/dist/promptHistory.js +115 -59
- package/dist/providerFailure.d.ts +12 -6
- package/dist/providerFailure.js +45 -0
- package/dist/providers/claudeCode.js +7 -99
- package/dist/providers/claudeListing.d.ts +22 -0
- package/dist/providers/claudeListing.js +158 -0
- package/dist/providers/codex.d.ts +3 -1
- package/dist/providers/codex.js +26 -227
- package/dist/providers/codexRollouts.d.ts +44 -0
- package/dist/providers/codexRollouts.js +261 -0
- package/dist/providers/detect.js +4 -4
- package/dist/readers/plans.js +3 -3
- package/dist/schemas/index.d.ts +2 -0
- package/dist/schemas/index.js +7 -2
- package/dist/schemas/providerFailure.d.ts +154 -0
- package/dist/schemas/providerFailure.js +40 -0
- package/dist/sessionPromptHistory.d.ts +12 -7
- package/dist/sessionPromptHistory.js +15 -3
- package/dist/sessionPromptSignals.d.ts +9 -0
- package/dist/sessionPromptSignals.js +13 -0
- package/dist/testing/credentialGuard.d.ts +23 -0
- package/dist/testing/credentialGuard.js +233 -0
- package/dist/testing/index.d.ts +14 -0
- package/dist/testing/index.js +22 -0
- package/dist/testing/sessionLogFixtures.d.ts +28 -0
- package/dist/testing/sessionLogFixtures.js +169 -0
- package/dist/tokenEstimation.d.ts +2 -0
- package/dist/tokenEstimation.js +21 -11
- package/dist/toolCategory.d.ts +18 -0
- package/dist/toolCategory.js +86 -0
- package/dist/types/codex.d.ts +4 -0
- package/dist/usage/usageEvents.d.ts +16 -0
- package/dist/usage/usageEvents.js +53 -9
- package/dist/watchers/jsonlTail.d.ts +26 -1
- package/dist/watchers/jsonlTail.js +136 -28
- package/dist/watchers/jsonlWatcher.js +7 -0
- package/dist/watchers/providerReaderWatcher.js +1 -0
- package/dist/watchers/types.d.ts +6 -0
- package/dist/workspaceRoots.d.ts +23 -0
- package/dist/workspaceRoots.js +93 -0
- package/package.json +22 -2
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Claude Code session-file listing, kept apart from the provider class so a
|
|
4
|
+
* caller that only lists files does not bundle the provider's stats,
|
|
5
|
+
* context and transcript code.
|
|
6
|
+
*/
|
|
7
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
+
if (k2 === undefined) k2 = k;
|
|
9
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
+
}
|
|
13
|
+
Object.defineProperty(o, k2, desc);
|
|
14
|
+
}) : (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
o[k2] = m[k];
|
|
17
|
+
}));
|
|
18
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
19
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
20
|
+
}) : function(o, v) {
|
|
21
|
+
o["default"] = v;
|
|
22
|
+
});
|
|
23
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
24
|
+
var ownKeys = function(o) {
|
|
25
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
26
|
+
var ar = [];
|
|
27
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
28
|
+
return ar;
|
|
29
|
+
};
|
|
30
|
+
return ownKeys(o);
|
|
31
|
+
};
|
|
32
|
+
return function (mod) {
|
|
33
|
+
if (mod && mod.__esModule) return mod;
|
|
34
|
+
var result = {};
|
|
35
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
36
|
+
__setModuleDefault(result, mod);
|
|
37
|
+
return result;
|
|
38
|
+
};
|
|
39
|
+
})();
|
|
40
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
+
exports.workspaceDirectoryFilter = workspaceDirectoryFilter;
|
|
42
|
+
exports.listClaudeSessionFilesAsync = listClaudeSessionFilesAsync;
|
|
43
|
+
const fs = __importStar(require("fs"));
|
|
44
|
+
const path = __importStar(require("path"));
|
|
45
|
+
const claudePaths_1 = require("../claudePaths");
|
|
46
|
+
const sessionPathResolver_1 = require("../parsers/sessionPathResolver");
|
|
47
|
+
const directoryListingCache_1 = require("./directoryListingCache");
|
|
48
|
+
/** Matches project directory names that may hold sessions for `workspacePath`. */
|
|
49
|
+
function workspaceDirectoryFilter(workspacePath) {
|
|
50
|
+
if (!workspacePath)
|
|
51
|
+
return () => true;
|
|
52
|
+
const encodedWorkspace = (0, sessionPathResolver_1.encodeWorkspacePath)(workspacePath).toLowerCase();
|
|
53
|
+
const workspaceBasename = path
|
|
54
|
+
.basename(workspacePath)
|
|
55
|
+
.replace(/[^a-zA-Z0-9]/g, '-')
|
|
56
|
+
.toLowerCase();
|
|
57
|
+
return (directoryName) => {
|
|
58
|
+
const name = directoryName.toLowerCase();
|
|
59
|
+
return (name === encodedWorkspace ||
|
|
60
|
+
name.startsWith(`${encodedWorkspace}-`) ||
|
|
61
|
+
name === workspaceBasename ||
|
|
62
|
+
name.endsWith(`-${workspaceBasename}`));
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Enumerate session files across project directories through the
|
|
67
|
+
* directory cache: one stat per project directory, a readdir only for
|
|
68
|
+
* directories whose mtime changed, and a stat only for files new to a
|
|
69
|
+
* changed directory (or recently modified, with `revalidateRecent`).
|
|
70
|
+
*
|
|
71
|
+
* With `limit`, directories are visited newest-mtime first and the walk
|
|
72
|
+
* stops once the remaining directories are older than the newest `limit`
|
|
73
|
+
* files found. A directory's mtime ignores appends, so a cold limited walk
|
|
74
|
+
* can miss a long-running session in an old directory until its next watch
|
|
75
|
+
* event; `since` filters files and shares the caveat.
|
|
76
|
+
*/
|
|
77
|
+
async function listClaudeSessionFilesAsync(workspacePath, options = {}, cache = new directoryListingCache_1.DirectoryListingCache()) {
|
|
78
|
+
const projectsRoot = (0, claudePaths_1.getClaudeProjectsDir)();
|
|
79
|
+
if (options.stats) {
|
|
80
|
+
options.stats.directoriesListed ??= 0;
|
|
81
|
+
options.stats.directoriesStatted ??= 0;
|
|
82
|
+
options.stats.filesStatted ??= 0;
|
|
83
|
+
}
|
|
84
|
+
const root = await cache.listDirectory(projectsRoot, () => false, {
|
|
85
|
+
revalidateRecent: options.revalidateRecent,
|
|
86
|
+
stats: options.stats,
|
|
87
|
+
});
|
|
88
|
+
if (!root) {
|
|
89
|
+
return [];
|
|
90
|
+
}
|
|
91
|
+
const limit = options.limit !== undefined && Number.isFinite(options.limit)
|
|
92
|
+
? Math.max(0, Math.floor(options.limit))
|
|
93
|
+
: null;
|
|
94
|
+
if (limit === 0) {
|
|
95
|
+
return [];
|
|
96
|
+
}
|
|
97
|
+
const since = options.since !== undefined && Number.isFinite(options.since) ? options.since : null;
|
|
98
|
+
const matchesWorkspace = workspaceDirectoryFilter(workspacePath);
|
|
99
|
+
const candidates = [];
|
|
100
|
+
let sinceYield = 0;
|
|
101
|
+
for (const name of root.subdirectories) {
|
|
102
|
+
if (!matchesWorkspace(name))
|
|
103
|
+
continue;
|
|
104
|
+
const directory = path.join(projectsRoot, name);
|
|
105
|
+
try {
|
|
106
|
+
const stat = await fs.promises.stat(directory);
|
|
107
|
+
if (options.stats) {
|
|
108
|
+
options.stats.directoriesStatted = (options.stats.directoriesStatted ?? 0) + 1;
|
|
109
|
+
}
|
|
110
|
+
if (stat.isDirectory())
|
|
111
|
+
candidates.push({ directory, stat });
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
if (++sinceYield >= 50) {
|
|
117
|
+
sinceYield = 0;
|
|
118
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (limit !== null)
|
|
122
|
+
candidates.sort((left, right) => right.stat.mtimeMs - left.stat.mtimeMs);
|
|
123
|
+
const byNewest = (left, right) => right.mtime.getTime() - left.mtime.getTime();
|
|
124
|
+
const results = [];
|
|
125
|
+
let cutoffMs = null;
|
|
126
|
+
for (const candidate of candidates) {
|
|
127
|
+
if (limit !== null && cutoffMs !== null && candidate.stat.mtimeMs < cutoffMs)
|
|
128
|
+
break;
|
|
129
|
+
const listing = await cache.listDirectory(candidate.directory, (name) => name.endsWith('.jsonl'), {
|
|
130
|
+
dirStat: candidate.stat,
|
|
131
|
+
revalidateRecent: options.revalidateRecent,
|
|
132
|
+
stats: options.stats,
|
|
133
|
+
});
|
|
134
|
+
if (!listing)
|
|
135
|
+
continue;
|
|
136
|
+
for (const [name, stat] of listing.files) {
|
|
137
|
+
if (stat.sizeBytes <= 0)
|
|
138
|
+
continue;
|
|
139
|
+
if (since !== null && stat.mtimeMs < since)
|
|
140
|
+
continue;
|
|
141
|
+
const sessionPath = path.join(candidate.directory, name);
|
|
142
|
+
results.push({
|
|
143
|
+
path: sessionPath,
|
|
144
|
+
mtime: new Date(stat.mtimeMs),
|
|
145
|
+
sizeBytes: stat.sizeBytes,
|
|
146
|
+
sessionId: path.basename(sessionPath, '.jsonl'),
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
if (limit !== null && results.length >= limit) {
|
|
150
|
+
results.sort(byNewest);
|
|
151
|
+
results.length = limit;
|
|
152
|
+
cutoffMs = results[limit - 1].mtime.getTime();
|
|
153
|
+
}
|
|
154
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
155
|
+
}
|
|
156
|
+
results.sort(byNewest);
|
|
157
|
+
return limit !== null && results.length > limit ? results.slice(0, limit) : results;
|
|
158
|
+
}
|
|
@@ -22,7 +22,9 @@ export interface FindCodexRolloutFileOptions {
|
|
|
22
22
|
}
|
|
23
23
|
/**
|
|
24
24
|
* Locates the rollout file for a Codex session id by walking
|
|
25
|
-
* `<home>/sessions/YYYY/MM/DD/rollout-<timestamp>-<id>.jsonl
|
|
25
|
+
* `<home>/sessions/YYYY/MM/DD/rollout-<timestamp>-<id>.jsonl`, then
|
|
26
|
+
* `<home>/archived_sessions/`, where Codex moves the rollouts of archived
|
|
27
|
+
* threads.
|
|
26
28
|
*
|
|
27
29
|
* Filename-only match, case-insensitive on the id — no file contents are read
|
|
28
30
|
* and files are only stat'ed once their name matches, so the walk stays cheap
|
package/dist/providers/codex.js
CHANGED
|
@@ -53,8 +53,9 @@ const sessionStats_1 = require("../sessionStats");
|
|
|
53
53
|
const codexParser_1 = require("../parsers/codexParser");
|
|
54
54
|
const codexDatabase_1 = require("./codexDatabase");
|
|
55
55
|
const subagentStatsCache_1 = require("../parsers/subagentStatsCache");
|
|
56
|
-
const codexProfiles_1 = require("../codexProfiles");
|
|
57
56
|
const rolloutWalker_1 = require("./rolloutWalker");
|
|
57
|
+
const codexPaths_1 = require("../codexPaths");
|
|
58
|
+
const codexRollouts_1 = require("./codexRollouts");
|
|
58
59
|
const directoryListingCache_1 = require("./directoryListingCache");
|
|
59
60
|
const diagnostics_1 = require("./diagnostics");
|
|
60
61
|
const modelContext_1 = require("../modelContext");
|
|
@@ -64,19 +65,6 @@ const subagentUsage_1 = require("../usage/subagentUsage");
|
|
|
64
65
|
// ---------------------------------------------------------------------------
|
|
65
66
|
// Helper functions
|
|
66
67
|
// ---------------------------------------------------------------------------
|
|
67
|
-
/**
|
|
68
|
-
* Gets all candidate Codex homes to monitor.
|
|
69
|
-
*
|
|
70
|
-
* Managed profiles stay first so Sidekick-launched sessions keep working, but
|
|
71
|
-
* we also fall back to the system ~/.codex home when no explicit CODEX_HOME is set.
|
|
72
|
-
*/
|
|
73
|
-
function getCodexHomes() {
|
|
74
|
-
return (0, codexProfiles_1.getCodexMonitoringHomes)();
|
|
75
|
-
}
|
|
76
|
-
/** Get every sessions base directory that may contain live Codex rollouts. */
|
|
77
|
-
function getSessionsDirs() {
|
|
78
|
-
return getCodexHomes().map((home) => path.join(home, 'sessions'));
|
|
79
|
-
}
|
|
80
68
|
/** Truncate a string to maxLen with ellipsis. */
|
|
81
69
|
function truncate(text, maxLen) {
|
|
82
70
|
const trimmed = text.trim().replace(/\s+/g, ' ');
|
|
@@ -94,11 +82,13 @@ function hasRolloutFile(dir) {
|
|
|
94
82
|
}
|
|
95
83
|
/** Every rollout across the monitored homes, newest first, deduplicated by path. */
|
|
96
84
|
function findRolloutFilesInConfiguredHomes(options = {}) {
|
|
97
|
-
return (0, rolloutWalker_1.walkRolloutFiles)(getSessionsDirs(), options);
|
|
85
|
+
return (0, rolloutWalker_1.walkRolloutFiles)((0, codexRollouts_1.getSessionsDirs)(), options);
|
|
98
86
|
}
|
|
99
87
|
/**
|
|
100
88
|
* Locates the rollout file for a Codex session id by walking
|
|
101
|
-
* `<home>/sessions/YYYY/MM/DD/rollout-<timestamp>-<id>.jsonl
|
|
89
|
+
* `<home>/sessions/YYYY/MM/DD/rollout-<timestamp>-<id>.jsonl`, then
|
|
90
|
+
* `<home>/archived_sessions/`, where Codex moves the rollouts of archived
|
|
91
|
+
* threads.
|
|
102
92
|
*
|
|
103
93
|
* Filename-only match, case-insensitive on the id — no file contents are read
|
|
104
94
|
* and files are only stat'ed once their name matches, so the walk stays cheap
|
|
@@ -112,14 +102,14 @@ function findCodexRolloutFile(sessionId, options = {}) {
|
|
|
112
102
|
if (!normalizedId)
|
|
113
103
|
return null;
|
|
114
104
|
const sessionsDirs = options.codexHome
|
|
115
|
-
?
|
|
116
|
-
: getSessionsDirs();
|
|
105
|
+
? (0, codexPaths_1.getCodexSessionsDirs)([options.codexHome])
|
|
106
|
+
: (0, codexRollouts_1.getSessionsDirs)();
|
|
117
107
|
// Name-only filter, one walk across the homes, newest modification first.
|
|
118
108
|
return (0, rolloutWalker_1.walkRolloutFiles)(sessionsDirs, { sessionId: normalizedId })[0]?.path ?? null;
|
|
119
109
|
}
|
|
120
110
|
/** Pick the best sessions directory for UI/search entrypoints. */
|
|
121
111
|
function getSessionsDir() {
|
|
122
|
-
const dirs =
|
|
112
|
+
const dirs = (0, codexPaths_1.getCodexSessionsDirs)(undefined, { includeArchived: false });
|
|
123
113
|
for (const dir of dirs) {
|
|
124
114
|
if (hasRolloutFile(dir)) {
|
|
125
115
|
return dir;
|
|
@@ -140,174 +130,6 @@ function isSystemInjection(text) {
|
|
|
140
130
|
const t = text.trimStart();
|
|
141
131
|
return t.startsWith('<') || t.startsWith('#');
|
|
142
132
|
}
|
|
143
|
-
/**
|
|
144
|
-
* Read the first N complete lines from a file using chunked reads.
|
|
145
|
-
* Handles arbitrarily long lines (Codex session_meta can be 10KB+).
|
|
146
|
-
*/
|
|
147
|
-
function readFirstLines(filePath, maxLines, maxBytes = 256 * 1024) {
|
|
148
|
-
const lines = [];
|
|
149
|
-
let fd;
|
|
150
|
-
try {
|
|
151
|
-
fd = fs.openSync(filePath, 'r');
|
|
152
|
-
}
|
|
153
|
-
catch {
|
|
154
|
-
return [];
|
|
155
|
-
}
|
|
156
|
-
let pending = '';
|
|
157
|
-
let totalRead = 0;
|
|
158
|
-
const chunkSize = 16384;
|
|
159
|
-
try {
|
|
160
|
-
while (totalRead < maxBytes && lines.length < maxLines) {
|
|
161
|
-
const buf = Buffer.alloc(Math.min(chunkSize, maxBytes - totalRead));
|
|
162
|
-
const bytesRead = fs.readSync(fd, buf, 0, buf.length, totalRead);
|
|
163
|
-
if (bytesRead === 0)
|
|
164
|
-
break;
|
|
165
|
-
totalRead += bytesRead;
|
|
166
|
-
pending += buf.toString('utf-8', 0, bytesRead);
|
|
167
|
-
let nlIdx;
|
|
168
|
-
while ((nlIdx = pending.indexOf('\n')) !== -1 && lines.length < maxLines) {
|
|
169
|
-
lines.push(pending.substring(0, nlIdx));
|
|
170
|
-
pending = pending.substring(nlIdx + 1);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
if (pending.trim() && lines.length < maxLines) {
|
|
174
|
-
lines.push(pending);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
finally {
|
|
178
|
-
fs.closeSync(fd);
|
|
179
|
-
}
|
|
180
|
-
return lines;
|
|
181
|
-
}
|
|
182
|
-
/** Read session_meta from the beginning of a rollout file. */
|
|
183
|
-
function readSessionMeta(rolloutPath) {
|
|
184
|
-
try {
|
|
185
|
-
const lines = readFirstLines(rolloutPath, 1);
|
|
186
|
-
const firstLine = lines[0]?.trim();
|
|
187
|
-
if (!firstLine)
|
|
188
|
-
return null;
|
|
189
|
-
const parsed = JSON.parse(firstLine);
|
|
190
|
-
if (parsed.type === 'session_meta') {
|
|
191
|
-
return parsed.payload;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
catch {
|
|
195
|
-
// Skip
|
|
196
|
-
}
|
|
197
|
-
return null;
|
|
198
|
-
}
|
|
199
|
-
/**
|
|
200
|
-
* First line of a rollout, chunk-read under the same 256 KiB cap as
|
|
201
|
-
* readFirstLines(). `complete` is false while the line has no newline yet
|
|
202
|
-
* (a rollout that was just created) or the file could not be read, so
|
|
203
|
-
* callers know not to cache the answer.
|
|
204
|
-
*/
|
|
205
|
-
async function readFirstLineAsync(rolloutPath) {
|
|
206
|
-
// Mirrors readSessionMeta()/readFirstLines(): chunk-read until the first
|
|
207
|
-
// line is complete under the same 256 KiB cap — session_meta carries
|
|
208
|
-
// `instructions` and can far exceed a single chunk.
|
|
209
|
-
const maxBytes = 256 * 1024;
|
|
210
|
-
const chunkSize = 64 * 1024;
|
|
211
|
-
let handle = null;
|
|
212
|
-
try {
|
|
213
|
-
handle = await fs.promises.open(rolloutPath, 'r');
|
|
214
|
-
const chunks = [];
|
|
215
|
-
let totalRead = 0;
|
|
216
|
-
let newlineFound = false;
|
|
217
|
-
while (totalRead < maxBytes && !newlineFound) {
|
|
218
|
-
const buffer = Buffer.alloc(Math.min(chunkSize, maxBytes - totalRead));
|
|
219
|
-
const { bytesRead } = await handle.read(buffer, 0, buffer.length, totalRead);
|
|
220
|
-
if (bytesRead === 0)
|
|
221
|
-
break;
|
|
222
|
-
const chunk = buffer.subarray(0, bytesRead);
|
|
223
|
-
chunks.push(chunk);
|
|
224
|
-
totalRead += bytesRead;
|
|
225
|
-
newlineFound = chunk.includes(0x0a);
|
|
226
|
-
}
|
|
227
|
-
const firstLine = Buffer.concat(chunks).toString('utf8').split('\n', 1)[0]?.trim();
|
|
228
|
-
return { line: firstLine || null, complete: newlineFound || totalRead >= maxBytes };
|
|
229
|
-
}
|
|
230
|
-
catch {
|
|
231
|
-
return { line: null, complete: false };
|
|
232
|
-
}
|
|
233
|
-
finally {
|
|
234
|
-
await handle?.close().catch(() => undefined);
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
function parseSessionMetaLine(line) {
|
|
238
|
-
if (!line)
|
|
239
|
-
return null;
|
|
240
|
-
try {
|
|
241
|
-
const parsed = JSON.parse(line);
|
|
242
|
-
return parsed.type === 'session_meta' ? parsed.payload : null;
|
|
243
|
-
}
|
|
244
|
-
catch {
|
|
245
|
-
return null;
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
/**
|
|
249
|
-
* Read the CWD from a rollout file's session_meta. Cached per path, bounded
|
|
250
|
-
* so a long-lived host watching a large history cannot grow it without limit
|
|
251
|
-
* (insertion order doubles as an eviction order).
|
|
252
|
-
*/
|
|
253
|
-
const CWD_CACHE_LIMIT = 5000;
|
|
254
|
-
const cwdCache = new Map();
|
|
255
|
-
function rememberCwd(rolloutPath, cwd) {
|
|
256
|
-
if (!cwdCache.has(rolloutPath) && cwdCache.size >= CWD_CACHE_LIMIT) {
|
|
257
|
-
const oldest = cwdCache.keys().next().value;
|
|
258
|
-
if (oldest !== undefined)
|
|
259
|
-
cwdCache.delete(oldest);
|
|
260
|
-
}
|
|
261
|
-
cwdCache.set(rolloutPath, cwd);
|
|
262
|
-
}
|
|
263
|
-
function readSessionCwd(rolloutPath) {
|
|
264
|
-
const cached = cwdCache.get(rolloutPath);
|
|
265
|
-
if (cached !== undefined)
|
|
266
|
-
return cached;
|
|
267
|
-
const meta = readSessionMeta(rolloutPath);
|
|
268
|
-
const cwd = meta?.cwd || null;
|
|
269
|
-
rememberCwd(rolloutPath, cwd);
|
|
270
|
-
return cwd;
|
|
271
|
-
}
|
|
272
|
-
/** Async twin of readSessionCwd, sharing its cache so repeat listings do no content reads. */
|
|
273
|
-
async function readSessionCwdAsync(rolloutPath) {
|
|
274
|
-
const cached = cwdCache.get(rolloutPath);
|
|
275
|
-
if (cached !== undefined)
|
|
276
|
-
return cached;
|
|
277
|
-
const { line, complete } = await readFirstLineAsync(rolloutPath);
|
|
278
|
-
const cwd = parseSessionMetaLine(line)?.cwd || null;
|
|
279
|
-
// A rollout observed before its session_meta line is flushed has no cwd
|
|
280
|
-
// yet; caching that null would hide the session from its workspace until
|
|
281
|
-
// the entry aged out, so only conclusive answers are remembered.
|
|
282
|
-
if (cwd !== null || complete)
|
|
283
|
-
rememberCwd(rolloutPath, cwd);
|
|
284
|
-
return cwd;
|
|
285
|
-
}
|
|
286
|
-
/** Built-in enumerators report explicit zeros rather than leaving a counter unset. */
|
|
287
|
-
function initializeCounters(stats) {
|
|
288
|
-
if (!stats)
|
|
289
|
-
return;
|
|
290
|
-
stats.directoriesListed ??= 0;
|
|
291
|
-
stats.directoriesStatted ??= 0;
|
|
292
|
-
stats.filesStatted ??= 0;
|
|
293
|
-
}
|
|
294
|
-
/** Check if a session's CWD matches a workspace path. */
|
|
295
|
-
function cwdMatches(sessionCwd, workspacePath) {
|
|
296
|
-
const normalizedSession = normalizePath(sessionCwd);
|
|
297
|
-
const normalizedWorkspace = normalizePath(workspacePath);
|
|
298
|
-
return (normalizedSession === normalizedWorkspace ||
|
|
299
|
-
normalizedWorkspace.startsWith(normalizedSession + path.sep) ||
|
|
300
|
-
normalizedSession.startsWith(normalizedWorkspace + path.sep));
|
|
301
|
-
}
|
|
302
|
-
/** Normalize a path using realpathSync. */
|
|
303
|
-
function normalizePath(input) {
|
|
304
|
-
try {
|
|
305
|
-
return fs.realpathSync(input);
|
|
306
|
-
}
|
|
307
|
-
catch {
|
|
308
|
-
return path.resolve(input);
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
133
|
/**
|
|
312
134
|
* Read the first user message text from a rollout file.
|
|
313
135
|
* Reads up to 20 lines to find a real user message (lines can be 10KB+ each).
|
|
@@ -315,7 +137,7 @@ function normalizePath(input) {
|
|
|
315
137
|
*/
|
|
316
138
|
function extractFirstUserMessage(rolloutPath) {
|
|
317
139
|
try {
|
|
318
|
-
return extractFirstUserMessageFromLines(readFirstLines(rolloutPath, 20));
|
|
140
|
+
return extractFirstUserMessageFromLines((0, codexRollouts_1.readFirstLines)(rolloutPath, 20));
|
|
319
141
|
}
|
|
320
142
|
catch {
|
|
321
143
|
return null;
|
|
@@ -754,8 +576,8 @@ class CodexProvider {
|
|
|
754
576
|
return null;
|
|
755
577
|
}
|
|
756
578
|
for (const file of files) {
|
|
757
|
-
const cwd = readSessionCwd(file.path);
|
|
758
|
-
if (cwd && cwdMatches(cwd, workspacePath)) {
|
|
579
|
+
const cwd = (0, codexRollouts_1.readSessionCwd)(file.path);
|
|
580
|
+
if (cwd && (0, codexRollouts_1.cwdMatches)(cwd, workspacePath)) {
|
|
759
581
|
this.recordDatabaseFallback('discoverSessionDirectory', true);
|
|
760
582
|
return path.dirname(file.path);
|
|
761
583
|
}
|
|
@@ -778,8 +600,8 @@ class CodexProvider {
|
|
|
778
600
|
}
|
|
779
601
|
// File scan fallback (newest first; cwd reads are cached per path)
|
|
780
602
|
for (const file of findRolloutFilesInConfiguredHomes()) {
|
|
781
|
-
const cwd = readSessionCwd(file.path);
|
|
782
|
-
if (cwd && cwdMatches(cwd, workspacePath)) {
|
|
603
|
+
const cwd = (0, codexRollouts_1.readSessionCwd)(file.path);
|
|
604
|
+
if (cwd && (0, codexRollouts_1.cwdMatches)(cwd, workspacePath)) {
|
|
783
605
|
this.recordDatabaseFallback('findActiveSession', true);
|
|
784
606
|
return file.path;
|
|
785
607
|
}
|
|
@@ -803,8 +625,8 @@ class CodexProvider {
|
|
|
803
625
|
// File scan (newest first; cwd reads are cached per path)
|
|
804
626
|
const sessions = findRolloutFilesInConfiguredHomes()
|
|
805
627
|
.filter((f) => {
|
|
806
|
-
const cwd = readSessionCwd(f.path);
|
|
807
|
-
return cwd !== null && cwdMatches(cwd, workspacePath);
|
|
628
|
+
const cwd = (0, codexRollouts_1.readSessionCwd)(f.path);
|
|
629
|
+
return cwd !== null && (0, codexRollouts_1.cwdMatches)(cwd, workspacePath);
|
|
808
630
|
})
|
|
809
631
|
.map((f) => f.path);
|
|
810
632
|
this.recordDatabaseFallback('findAllSessions', true);
|
|
@@ -834,30 +656,7 @@ class CodexProvider {
|
|
|
834
656
|
return files;
|
|
835
657
|
}
|
|
836
658
|
async listSessionFilesAsync(workspacePath, options = {}) {
|
|
837
|
-
const results =
|
|
838
|
-
initializeCounters(options.stats);
|
|
839
|
-
// One capped walk across the homes (deduplicated, newest first) through
|
|
840
|
-
// the directory cache. With a workspace filter the limit applies after
|
|
841
|
-
// filtering, so the walk itself is bounded only by its file cap.
|
|
842
|
-
const files = await (0, rolloutWalker_1.walkRolloutFilesAsync)(getSessionsDirs(), {
|
|
843
|
-
limit: workspacePath ? undefined : options.limit,
|
|
844
|
-
since: options.since,
|
|
845
|
-
cache: this.directoryCache,
|
|
846
|
-
revalidateRecent: options.revalidateRecent,
|
|
847
|
-
stats: options.stats,
|
|
848
|
-
});
|
|
849
|
-
for (const file of files) {
|
|
850
|
-
if (options.limit !== undefined && results.length >= options.limit)
|
|
851
|
-
break;
|
|
852
|
-
const info = { ...file };
|
|
853
|
-
if (workspacePath) {
|
|
854
|
-
const cwd = await readSessionCwdAsync(file.path);
|
|
855
|
-
if (!cwd || !cwdMatches(cwd, workspacePath))
|
|
856
|
-
continue;
|
|
857
|
-
info.workspacePath = cwd;
|
|
858
|
-
}
|
|
859
|
-
results.push(info);
|
|
860
|
-
}
|
|
659
|
+
const results = await (0, codexRollouts_1.listCodexSessionFilesAsync)(workspacePath, options, this.directoryCache);
|
|
861
660
|
// Filesystem enumeration bypasses the database, so record that here as
|
|
862
661
|
// the sync listing paths do; otherwise `getLastOperationStatus()` keeps
|
|
863
662
|
// describing whichever operation ran before this one.
|
|
@@ -898,8 +697,8 @@ class CodexProvider {
|
|
|
898
697
|
sessionId,
|
|
899
698
|
};
|
|
900
699
|
if (workspacePath) {
|
|
901
|
-
const cwd = await readSessionCwdAsync(fullPath);
|
|
902
|
-
if (!cwd || !cwdMatches(cwd, workspacePath))
|
|
700
|
+
const cwd = await (0, codexRollouts_1.readSessionCwdAsync)(fullPath);
|
|
701
|
+
if (!cwd || !(0, codexRollouts_1.cwdMatches)(cwd, workspacePath))
|
|
903
702
|
return { status: 'ignored' };
|
|
904
703
|
file.workspacePath = cwd;
|
|
905
704
|
}
|
|
@@ -930,7 +729,7 @@ class CodexProvider {
|
|
|
930
729
|
for (const file of findRolloutFilesInConfiguredHomes()) {
|
|
931
730
|
if (db && indexedUpTo > 0 && file.mtime.getTime() <= indexedUpTo)
|
|
932
731
|
continue;
|
|
933
|
-
const cwd = readSessionCwd(file.path);
|
|
732
|
+
const cwd = (0, codexRollouts_1.readSessionCwd)(file.path);
|
|
934
733
|
if (!cwd)
|
|
935
734
|
continue;
|
|
936
735
|
const existing = seenCwds.get(cwd);
|
|
@@ -952,11 +751,11 @@ class CodexProvider {
|
|
|
952
751
|
}
|
|
953
752
|
folders.push(...seenCwds.values());
|
|
954
753
|
// Sort: current workspace first, then by recency
|
|
955
|
-
const normalizedWorkspace = workspacePath ? normalizePath(workspacePath) : null;
|
|
754
|
+
const normalizedWorkspace = workspacePath ? (0, codexRollouts_1.normalizePath)(workspacePath) : null;
|
|
956
755
|
folders.sort((a, b) => {
|
|
957
756
|
if (normalizedWorkspace) {
|
|
958
|
-
const aMatch = cwdMatches(a.name, normalizedWorkspace);
|
|
959
|
-
const bMatch = cwdMatches(b.name, normalizedWorkspace);
|
|
757
|
+
const aMatch = (0, codexRollouts_1.cwdMatches)(a.name, normalizedWorkspace);
|
|
758
|
+
const bMatch = (0, codexRollouts_1.cwdMatches)(b.name, normalizedWorkspace);
|
|
960
759
|
if (aMatch && !bMatch)
|
|
961
760
|
return -1;
|
|
962
761
|
if (!aMatch && bMatch)
|
|
@@ -1074,7 +873,7 @@ class CodexProvider {
|
|
|
1074
873
|
// forked_from_id. The walk stops after the 50 newest-dated files instead
|
|
1075
874
|
// of enumerating the whole history and slicing afterwards.
|
|
1076
875
|
for (const file of findRolloutFilesInConfiguredHomes({ limit: 50 })) {
|
|
1077
|
-
const meta = readSessionMeta(file.path);
|
|
876
|
+
const meta = (0, codexRollouts_1.readSessionMeta)(file.path);
|
|
1078
877
|
if (meta &&
|
|
1079
878
|
(meta.forked_from_id === sessionId || (0, codexDatabase_1.spawnParentFromSource)(meta.source) === sessionId)) {
|
|
1080
879
|
const childId = (0, rolloutWalker_1.extractRolloutSessionId)(path.basename(file.path));
|
|
@@ -1187,7 +986,7 @@ class CodexProvider {
|
|
|
1187
986
|
line: snippet.replace(/\n/g, ' '),
|
|
1188
987
|
eventType: parsed.type,
|
|
1189
988
|
timestamp: parsed.timestamp || '',
|
|
1190
|
-
projectPath: readSessionCwd(sessionPath) || sessionPath,
|
|
989
|
+
projectPath: (0, codexRollouts_1.readSessionCwd)(sessionPath) || sessionPath,
|
|
1191
990
|
});
|
|
1192
991
|
}
|
|
1193
992
|
catch {
|
|
@@ -1204,7 +1003,7 @@ class CodexProvider {
|
|
|
1204
1003
|
return getSessionsDir();
|
|
1205
1004
|
}
|
|
1206
1005
|
getWatchRoots() {
|
|
1207
|
-
return getSessionsDirs();
|
|
1006
|
+
return (0, codexRollouts_1.getSessionsDirs)();
|
|
1208
1007
|
}
|
|
1209
1008
|
// --- Stats ---
|
|
1210
1009
|
readSessionStats(sessionPath) {
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codex rollout-file helpers shared by the provider and by callers that only
|
|
3
|
+
* list rollouts: bounded first-line reads, session_meta and cwd lookups, and
|
|
4
|
+
* the async session-file listing. Kept apart from the provider class so a
|
|
5
|
+
* listing does not bundle the provider's stats, context and reader code.
|
|
6
|
+
*/
|
|
7
|
+
import type { CodexSessionMeta } from '../types/codex';
|
|
8
|
+
import { DirectoryListingCache } from './directoryListingCache';
|
|
9
|
+
import type { ListSessionFilesOptions, SessionFileInfo } from './types';
|
|
10
|
+
/** Every directory across the monitored homes that may hold rollouts, archived ones included. */
|
|
11
|
+
export declare function getSessionsDirs(): string[];
|
|
12
|
+
/**
|
|
13
|
+
* Read the first N complete lines from a file using chunked reads.
|
|
14
|
+
* Handles arbitrarily long lines (Codex session_meta can be 10KB+).
|
|
15
|
+
*/
|
|
16
|
+
export declare function readFirstLines(filePath: string, maxLines: number, maxBytes?: number): string[];
|
|
17
|
+
/** Read session_meta from the beginning of a rollout file. */
|
|
18
|
+
export declare function readSessionMeta(rolloutPath: string): CodexSessionMeta | null;
|
|
19
|
+
/**
|
|
20
|
+
* First line of a rollout, chunk-read under the same 256 KiB cap as
|
|
21
|
+
* readFirstLines(). `complete` is false while the line has no newline yet
|
|
22
|
+
* (a rollout that was just created) or the file could not be read, so
|
|
23
|
+
* callers know not to cache the answer.
|
|
24
|
+
*/
|
|
25
|
+
export declare function readFirstLineAsync(rolloutPath: string): Promise<{
|
|
26
|
+
line: string | null;
|
|
27
|
+
complete: boolean;
|
|
28
|
+
}>;
|
|
29
|
+
export declare function parseSessionMetaLine(line: string | null): CodexSessionMeta | null;
|
|
30
|
+
export declare function readSessionCwd(rolloutPath: string): string | null;
|
|
31
|
+
/** Async twin of readSessionCwd, sharing its cache so repeat listings do no content reads. */
|
|
32
|
+
export declare function readSessionCwdAsync(rolloutPath: string): Promise<string | null>;
|
|
33
|
+
/** Built-in enumerators report explicit zeros rather than leaving a counter unset. */
|
|
34
|
+
export declare function initializeCounters(stats: ListSessionFilesOptions['stats']): void;
|
|
35
|
+
/** Check if a session's CWD matches a workspace path. */
|
|
36
|
+
export declare function cwdMatches(sessionCwd: string, workspacePath: string): boolean;
|
|
37
|
+
/** Normalize a path using realpathSync. */
|
|
38
|
+
export declare function normalizePath(input: string): string;
|
|
39
|
+
/**
|
|
40
|
+
* List rollout files across the monitored Codex homes, newest first. With
|
|
41
|
+
* `workspacePath`, keeps rollouts whose session_meta cwd equals, contains, or
|
|
42
|
+
* sits inside it.
|
|
43
|
+
*/
|
|
44
|
+
export declare function listCodexSessionFilesAsync(workspacePath?: string, options?: ListSessionFilesOptions, cache?: DirectoryListingCache): Promise<SessionFileInfo[]>;
|