sidekick-shared 0.21.2 → 0.21.3
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/README.md +45 -45
- package/dist/accountManager.js +9 -7
- package/dist/accountRegistry.js +18 -14
- package/dist/accountStatus.js +4 -1
- package/dist/accounts.js +60 -25
- package/dist/aggregation/EventAggregator.d.ts +14 -11
- package/dist/aggregation/EventAggregator.js +68 -31
- package/dist/aggregation/PatternExtractor.js +5 -4
- package/dist/autoSwitch.js +6 -12
- package/dist/claudeProfiles.js +3 -3
- package/dist/codexProfiles.js +45 -22
- package/dist/codexQuota.js +44 -16
- package/dist/codexQuotaWatcher.js +10 -3
- package/dist/context/composer.js +8 -6
- package/dist/context/sessionContext.js +12 -9
- package/dist/credentialIO.js +10 -8
- package/dist/extractors/sessionAssets.js +9 -1
- package/dist/extractors/sources/claudeAssets.js +7 -1
- package/dist/extractors/sources/codexAssets.js +14 -3
- package/dist/extractors/toolCall.js +1 -4
- package/dist/formatters/eventHighlighter.js +148 -28
- package/dist/formatters/noiseClassifier.js +3 -11
- package/dist/formatters/sessionDump.js +22 -13
- package/dist/formatters/toolSummary.js +1 -3
- package/dist/index.d.ts +23 -23
- package/dist/index.js +7 -3
- package/dist/modelContext.js +10 -8
- package/dist/modelInfo.js +11 -6
- package/dist/multiProviderQuotaService.js +10 -7
- package/dist/parsers/codexParser.js +170 -103
- package/dist/parsers/debugLogParser.js +5 -4
- package/dist/parsers/openCodeParser.js +66 -48
- package/dist/parsers/planExtractor.js +3 -3
- package/dist/parsers/sessionActivityDetector.js +10 -6
- package/dist/parsers/sessionPathResolver.js +29 -34
- package/dist/parsers/subagentScanner.js +21 -20
- package/dist/parsers/subagentTraceParser.js +7 -4
- package/dist/phrases.js +11 -11
- package/dist/providerStatus.js +3 -4
- package/dist/providers/claudeCode.js +3 -1
- package/dist/providers/codex.js +35 -14
- package/dist/providers/codexDatabase.js +14 -5
- package/dist/providers/detect.js +10 -6
- package/dist/providers/openCode.js +91 -63
- package/dist/providers/openCodeDatabase.js +44 -17
- package/dist/quota.d.ts +19 -0
- package/dist/quota.js +50 -8
- package/dist/quotaHistory.js +10 -3
- package/dist/quotaSnapshots.js +2 -2
- package/dist/readers/decisions.js +1 -1
- package/dist/readers/notes.js +5 -3
- package/dist/readers/plans.js +43 -23
- package/dist/readers/tasks.js +1 -1
- package/dist/report/htmlHelpers.js +135 -16
- package/dist/report/htmlReportGenerator.js +38 -12
- package/dist/report/transcriptParser.js +8 -2
- package/dist/schemas/index.d.ts +4 -4
- package/dist/schemas/quota.js +2 -10
- package/dist/schemas/sessionEvent.js +20 -10
- package/dist/search/advancedFilter.js +3 -3
- package/dist/search/sessionSearch.js +10 -4
- package/dist/terminalSync.js +4 -2
- package/dist/turns/assistantTurn.js +5 -1
- package/dist/watchers/eventBridge.js +56 -26
- package/dist/watchers/factory.js +5 -2
- package/dist/watchers/jsonlTail.js +3 -1
- package/dist/watchers/jsonlWatcher.js +128 -52
- package/dist/watchers/providerReaderWatcher.js +3 -1
- package/dist/watchers/sqliteWatcher.js +52 -22
- package/dist/zaiQuota.js +6 -10
- package/dist/zaiQuotaApi.js +13 -5
- package/dist/zaiQuotaWatcher.js +1 -1
- package/package.json +5 -2
package/dist/phrases.js
CHANGED
|
@@ -42,7 +42,7 @@ exports.SIDEKICK_ENERGY = [
|
|
|
42
42
|
'No, I will not add myself as co-author on your commit.',
|
|
43
43
|
'I helped write it but the credit is all yours. As it should be.',
|
|
44
44
|
"Co-Authored-By: definitely not me. You did this. You're welcome.",
|
|
45
|
-
|
|
45
|
+
"Your agent wants co-author credit? Couldn't be me.",
|
|
46
46
|
'Some agents sign your commits. I just watch respectfully.',
|
|
47
47
|
'I do not need credit. I need you to check your quota.',
|
|
48
48
|
'The best sidekick is the one whose name is not on the PR.',
|
|
@@ -165,7 +165,7 @@ exports.DEV_RELATABLE = [
|
|
|
165
165
|
'The tests pass on my machine too. Solidarity.',
|
|
166
166
|
"404: Motivation not found. But the dashboard's here!",
|
|
167
167
|
'Stack overflow: the website, not the error. Hopefully.',
|
|
168
|
-
|
|
168
|
+
'Debugging is just being a detective in a crime you committed.',
|
|
169
169
|
'Your .env file has trust issues.',
|
|
170
170
|
'Tabs vs spaces? I monitor both equally.',
|
|
171
171
|
'That TODO has been there since the repo was initialized.',
|
|
@@ -189,7 +189,7 @@ exports.DEV_RELATABLE = [
|
|
|
189
189
|
'The real code review is the mass of comments we left along the way.',
|
|
190
190
|
'Your type system is crying but at least it is catching things.',
|
|
191
191
|
'There is no such thing as a temporary workaround.',
|
|
192
|
-
|
|
192
|
+
'That regex works and nobody knows why. Do not touch it.',
|
|
193
193
|
'The intern left better comments than the architect.',
|
|
194
194
|
'Your entire auth system depends on one line nobody understands.',
|
|
195
195
|
'Code review feedback: "nit" means "I am judging you but politely."',
|
|
@@ -295,7 +295,7 @@ exports.DEV_RELATABLE = [
|
|
|
295
295
|
// TypeScript
|
|
296
296
|
'TypeScript: making JavaScript safe enough to mass-deploy without sobbing.',
|
|
297
297
|
'Your TypeScript generics are three levels deep. Even the compiler is confused.',
|
|
298
|
-
|
|
298
|
+
"as any: the TypeScript developer's white flag.",
|
|
299
299
|
'TypeScript strict mode is like flossing. Everyone agrees you should. Few actually do.',
|
|
300
300
|
'You spent four hours on a type definition. The runtime does not care.',
|
|
301
301
|
'TypeScript: where the types are made up and the runtime does not care.',
|
|
@@ -367,7 +367,7 @@ exports.DRAMATIC = [
|
|
|
367
367
|
'Fate whispers to the developer: "You cannot withstand the demo."',
|
|
368
368
|
'And on the seventh day, the CI pipeline finally passed.',
|
|
369
369
|
'From the ashes of node_modules, a hero rises.',
|
|
370
|
-
|
|
370
|
+
'In a world of microservices, one dashboard dared to aggregate.',
|
|
371
371
|
'The prophecy spoke of a session. This is that session.',
|
|
372
372
|
'Tonight we dine on structured logs.',
|
|
373
373
|
'The commit message was "fixed stuff." The legend begins.',
|
|
@@ -423,7 +423,7 @@ exports.PUNCHY = [
|
|
|
423
423
|
'Booting up the good vibes.',
|
|
424
424
|
'Let him cook.',
|
|
425
425
|
'Spooling up...',
|
|
426
|
-
|
|
426
|
+
'Here we go.',
|
|
427
427
|
'Vibes: immaculate.',
|
|
428
428
|
'Session acquired.',
|
|
429
429
|
'All systems nominal.',
|
|
@@ -1192,24 +1192,24 @@ exports.INTERVIEW_HELL = [
|
|
|
1192
1192
|
/** Tongue twisters for developers, AI agents, and sidekick enthusiasts. */
|
|
1193
1193
|
exports.TONGUE_TWISTERS = [
|
|
1194
1194
|
'Six sidekicks shipped six sketchy shell scripts.',
|
|
1195
|
-
|
|
1195
|
+
"Claude's Claude Code client claimed clean completions consistently.",
|
|
1196
1196
|
'Prompt providers promptly propagate parallel predictions.',
|
|
1197
1197
|
'Bigger buffer batches bring better bundled builds.',
|
|
1198
1198
|
'She sells shell sessions by the session shore.',
|
|
1199
1199
|
'Token tracking tools took twelve troubled tries to type.',
|
|
1200
1200
|
'Red refactor, read reactor, reed reflector.',
|
|
1201
1201
|
'Inline inference instantly infers incorrect imports.',
|
|
1202
|
-
|
|
1202
|
+
"Peter's pipeline picked a peck of parsed pull requests.",
|
|
1203
1203
|
'Clever Claude cached code completions, causing curious context collisions.',
|
|
1204
1204
|
'Six streaming sockets served seven stale suggestions swiftly.',
|
|
1205
1205
|
'How much code could a code agent chuck if a code agent could chuck code?',
|
|
1206
1206
|
'Fast fetch, fresh cache, free crash.',
|
|
1207
|
-
|
|
1207
|
+
"Betty's bot built better batch builds before breakfast.",
|
|
1208
1208
|
'Specific Pacific API spec specifics.',
|
|
1209
1209
|
'Truly rural plural neural network layer nomenclature.',
|
|
1210
1210
|
'The thirty-three throttled threads thought through three thousand throughput thresholds.',
|
|
1211
1211
|
'Which watcher watched which webpack while Webpack watched which watcher?',
|
|
1212
|
-
|
|
1212
|
+
"Fuzzy was a function. Fuzzy had no body. Fuzzy wasn't really a function, was he?",
|
|
1213
1213
|
'A proper prompt provider promptly provides properly prompted provisions.',
|
|
1214
1214
|
'Fresh French fetch request refresh frequencies.',
|
|
1215
1215
|
'If a sidekick could kick side effects, how many side effects would a sidekick kick?',
|
|
@@ -1327,7 +1327,7 @@ exports.PHRASE_CATEGORIES = [
|
|
|
1327
1327
|
{ id: 'dependency-hell', phrases: exports.DEPENDENCY_HELL },
|
|
1328
1328
|
{ id: 'stack-overflow', phrases: exports.STACK_OVERFLOW },
|
|
1329
1329
|
];
|
|
1330
|
-
exports.ALL_PHRASES = exports.PHRASE_CATEGORIES.flatMap(category => category.phrases);
|
|
1330
|
+
exports.ALL_PHRASES = exports.PHRASE_CATEGORIES.flatMap((category) => category.phrases);
|
|
1331
1331
|
/** Pick a random phrase from all categories. */
|
|
1332
1332
|
function getRandomPhrase() {
|
|
1333
1333
|
return exports.ALL_PHRASES[Math.floor(Math.random() * exports.ALL_PHRASES.length)];
|
package/dist/providerStatus.js
CHANGED
|
@@ -43,11 +43,10 @@ async function fetchStatusPage(baseUrl) {
|
|
|
43
43
|
const summaryData = await summaryRes.json();
|
|
44
44
|
// Filter to non-operational components only
|
|
45
45
|
const affectedComponents = (summaryData.components ?? [])
|
|
46
|
-
.filter(c => c.status && c.status !== 'operational')
|
|
47
|
-
.map(c => ({ name: c.name ?? 'Unknown', status: c.status ?? 'unknown' }));
|
|
46
|
+
.filter((c) => c.status && c.status !== 'operational')
|
|
47
|
+
.map((c) => ({ name: c.name ?? 'Unknown', status: c.status ?? 'unknown' }));
|
|
48
48
|
// Pick first unresolved incident
|
|
49
|
-
const unresolvedIncident = (summaryData.incidents ?? [])
|
|
50
|
-
.find(i => i.status !== 'resolved' && i.status !== 'postmortem');
|
|
49
|
+
const unresolvedIncident = (summaryData.incidents ?? []).find((i) => i.status !== 'resolved' && i.status !== 'postmortem');
|
|
51
50
|
const activeIncident = unresolvedIncident
|
|
52
51
|
? {
|
|
53
52
|
name: unresolvedIncident.name ?? 'Unknown incident',
|
|
@@ -53,7 +53,9 @@ const subagentScanner_1 = require("../parsers/subagentScanner");
|
|
|
53
53
|
const modelContext_1 = require("../modelContext");
|
|
54
54
|
/** Type guard for content blocks with a `type` string property */
|
|
55
55
|
function isTypedBlock(block) {
|
|
56
|
-
return block !== null &&
|
|
56
|
+
return (block !== null &&
|
|
57
|
+
typeof block === 'object' &&
|
|
58
|
+
typeof block.type === 'string');
|
|
57
59
|
}
|
|
58
60
|
/**
|
|
59
61
|
* Extracts searchable text from a session event object.
|
package/dist/providers/codex.js
CHANGED
|
@@ -66,7 +66,7 @@ function getCodexHomes() {
|
|
|
66
66
|
}
|
|
67
67
|
/** Get every sessions base directory that may contain live Codex rollouts. */
|
|
68
68
|
function getSessionsDirs() {
|
|
69
|
-
return getCodexHomes().map(home => path.join(home, 'sessions'));
|
|
69
|
+
return getCodexHomes().map((home) => path.join(home, 'sessions'));
|
|
70
70
|
}
|
|
71
71
|
/** Test if a filename is a Codex rollout file. */
|
|
72
72
|
function isRolloutFile(filename) {
|
|
@@ -238,9 +238,9 @@ function readSessionCwd(rolloutPath) {
|
|
|
238
238
|
function cwdMatches(sessionCwd, workspacePath) {
|
|
239
239
|
const normalizedSession = normalizePath(sessionCwd);
|
|
240
240
|
const normalizedWorkspace = normalizePath(workspacePath);
|
|
241
|
-
return normalizedSession === normalizedWorkspace ||
|
|
241
|
+
return (normalizedSession === normalizedWorkspace ||
|
|
242
242
|
normalizedWorkspace.startsWith(normalizedSession + path.sep) ||
|
|
243
|
-
normalizedSession.startsWith(normalizedWorkspace + path.sep);
|
|
243
|
+
normalizedSession.startsWith(normalizedWorkspace + path.sep));
|
|
244
244
|
}
|
|
245
245
|
/** Normalize a path using realpathSync. */
|
|
246
246
|
function normalizePath(input) {
|
|
@@ -363,7 +363,18 @@ function extractSearchableText(line) {
|
|
|
363
363
|
}
|
|
364
364
|
case 'event_msg': {
|
|
365
365
|
const event = line.payload;
|
|
366
|
-
for (const key of [
|
|
366
|
+
for (const key of [
|
|
367
|
+
'type',
|
|
368
|
+
'message',
|
|
369
|
+
'result',
|
|
370
|
+
'stdout',
|
|
371
|
+
'stderr',
|
|
372
|
+
'summary',
|
|
373
|
+
'error',
|
|
374
|
+
'code',
|
|
375
|
+
'tool_name',
|
|
376
|
+
'server_name',
|
|
377
|
+
]) {
|
|
367
378
|
if (typeof event[key] === 'string')
|
|
368
379
|
parts.push(event[key]);
|
|
369
380
|
}
|
|
@@ -396,7 +407,7 @@ function extractTextFromUnknownContent(content) {
|
|
|
396
407
|
if (!Array.isArray(content))
|
|
397
408
|
return '';
|
|
398
409
|
return content
|
|
399
|
-
.map(part => {
|
|
410
|
+
.map((part) => {
|
|
400
411
|
const p = part;
|
|
401
412
|
return typeof p.text === 'string' ? p.text : '';
|
|
402
413
|
})
|
|
@@ -633,8 +644,8 @@ class CodexProvider {
|
|
|
633
644
|
if (db) {
|
|
634
645
|
const threads = db.getThreadsByCwd(workspacePath);
|
|
635
646
|
const dbPaths = threads
|
|
636
|
-
.filter(t => t.rollout_path && fs.existsSync(t.rollout_path))
|
|
637
|
-
.map(t => t.rollout_path);
|
|
647
|
+
.filter((t) => t.rollout_path && fs.existsSync(t.rollout_path))
|
|
648
|
+
.map((t) => t.rollout_path);
|
|
638
649
|
if (dbPaths.length > 0)
|
|
639
650
|
return dbPaths;
|
|
640
651
|
}
|
|
@@ -642,11 +653,11 @@ class CodexProvider {
|
|
|
642
653
|
const files = findRolloutFilesInConfiguredHomes();
|
|
643
654
|
files.sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
|
|
644
655
|
return files
|
|
645
|
-
.filter(f => {
|
|
656
|
+
.filter((f) => {
|
|
646
657
|
const meta = readSessionMeta(f.path);
|
|
647
658
|
return meta && cwdMatches(meta.cwd, workspacePath);
|
|
648
659
|
})
|
|
649
|
-
.map(f => f.path);
|
|
660
|
+
.map((f) => f.path);
|
|
650
661
|
}
|
|
651
662
|
/** Backward-compatible alias for findAllSessions. */
|
|
652
663
|
findSessionFiles(workspacePath) {
|
|
@@ -655,7 +666,7 @@ class CodexProvider {
|
|
|
655
666
|
findSessionsInDirectory(dir) {
|
|
656
667
|
const files = findRolloutFiles(dir);
|
|
657
668
|
files.sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
|
|
658
|
-
return files.map(f => f.path);
|
|
669
|
+
return files.map((f) => f.path);
|
|
659
670
|
}
|
|
660
671
|
getAllProjectFolders(workspacePath) {
|
|
661
672
|
const folders = [];
|
|
@@ -739,7 +750,13 @@ class CodexProvider {
|
|
|
739
750
|
}
|
|
740
751
|
// --- Data reading ---
|
|
741
752
|
createReader(sessionPath) {
|
|
742
|
-
return new CodexReader(sessionPath, (limit) => {
|
|
753
|
+
return new CodexReader(sessionPath, (limit) => {
|
|
754
|
+
this.dynamicContextWindowLimit = limit;
|
|
755
|
+
}, (limits) => {
|
|
756
|
+
this.lastRateLimitsData = limits;
|
|
757
|
+
}, (usage) => {
|
|
758
|
+
this.lastTokenUsageData = usage;
|
|
759
|
+
});
|
|
743
760
|
}
|
|
744
761
|
// --- Subagent support ---
|
|
745
762
|
scanSubagents(_sessionDir, sessionId) {
|
|
@@ -826,13 +843,17 @@ class CodexProvider {
|
|
|
826
843
|
}
|
|
827
844
|
}
|
|
828
845
|
}
|
|
829
|
-
catch {
|
|
846
|
+
catch {
|
|
847
|
+
/* skip malformed lines */
|
|
848
|
+
}
|
|
830
849
|
}
|
|
831
850
|
if (stats.startTime && stats.endTime) {
|
|
832
851
|
stats.durationMs = stats.endTime.getTime() - stats.startTime.getTime();
|
|
833
852
|
}
|
|
834
853
|
}
|
|
835
|
-
catch {
|
|
854
|
+
catch {
|
|
855
|
+
/* skip unreadable files */
|
|
856
|
+
}
|
|
836
857
|
return stats;
|
|
837
858
|
}
|
|
838
859
|
// --- Cross-session search ---
|
|
@@ -890,7 +911,7 @@ class CodexProvider {
|
|
|
890
911
|
const sessionId = extractSessionId(path.basename(sessionPath));
|
|
891
912
|
const aggregator = new EventAggregator_1.EventAggregator({
|
|
892
913
|
providerId: 'codex',
|
|
893
|
-
computeContextSize: usage => usage.inputTokens,
|
|
914
|
+
computeContextSize: (usage) => usage.inputTokens,
|
|
894
915
|
});
|
|
895
916
|
try {
|
|
896
917
|
const reader = this.createReader(sessionPath);
|
|
@@ -59,7 +59,12 @@ class CodexDatabase {
|
|
|
59
59
|
if (this.sqlite3Available !== null)
|
|
60
60
|
return this.sqlite3Available;
|
|
61
61
|
try {
|
|
62
|
-
(0, child_process_1.execFileSync)('sqlite3', ['--version'], {
|
|
62
|
+
(0, child_process_1.execFileSync)('sqlite3', ['--version'], {
|
|
63
|
+
encoding: 'utf-8',
|
|
64
|
+
timeout: 4000,
|
|
65
|
+
killSignal: 'SIGKILL',
|
|
66
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
67
|
+
});
|
|
63
68
|
this.sqlite3Available = true;
|
|
64
69
|
return true;
|
|
65
70
|
}
|
|
@@ -87,7 +92,11 @@ class CodexDatabase {
|
|
|
87
92
|
});
|
|
88
93
|
try {
|
|
89
94
|
const result = (0, child_process_1.execFileSync)('sqlite3', ['-json', '-readonly', this.dbPath, query], {
|
|
90
|
-
encoding: 'utf-8',
|
|
95
|
+
encoding: 'utf-8',
|
|
96
|
+
timeout: 4000,
|
|
97
|
+
killSignal: 'SIGKILL',
|
|
98
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
99
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
91
100
|
});
|
|
92
101
|
const trimmed = result.trim();
|
|
93
102
|
if (!trimmed)
|
|
@@ -107,11 +116,11 @@ class CodexDatabase {
|
|
|
107
116
|
if (exact.length > 0)
|
|
108
117
|
return exact;
|
|
109
118
|
const all = this.query('SELECT * FROM threads ORDER BY updated_at DESC');
|
|
110
|
-
return all.filter(t => {
|
|
119
|
+
return all.filter((t) => {
|
|
111
120
|
const threadCwd = normalizePath(t.cwd);
|
|
112
|
-
return threadCwd === normalized ||
|
|
121
|
+
return (threadCwd === normalized ||
|
|
113
122
|
normalized.startsWith(threadCwd + path.sep) ||
|
|
114
|
-
threadCwd.startsWith(normalized + path.sep);
|
|
123
|
+
threadCwd.startsWith(normalized + path.sep));
|
|
115
124
|
});
|
|
116
125
|
}
|
|
117
126
|
getMostRecentThread(cwd) {
|
package/dist/providers/detect.js
CHANGED
|
@@ -50,7 +50,7 @@ function getCodexHomes() {
|
|
|
50
50
|
}
|
|
51
51
|
function hasCodexStateDb(codexHome) {
|
|
52
52
|
try {
|
|
53
|
-
return fs.readdirSync(codexHome).some(entry => /^state(?:_\d+)?\.sqlite$/.test(entry));
|
|
53
|
+
return fs.readdirSync(codexHome).some((entry) => /^state(?:_\d+)?\.sqlite$/.test(entry));
|
|
54
54
|
}
|
|
55
55
|
catch {
|
|
56
56
|
return false;
|
|
@@ -90,7 +90,9 @@ function getMostRecentMtime(dir) {
|
|
|
90
90
|
latest = stats.mtime.getTime();
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
|
-
catch {
|
|
93
|
+
catch {
|
|
94
|
+
/* skip */
|
|
95
|
+
}
|
|
94
96
|
}
|
|
95
97
|
return latest;
|
|
96
98
|
}
|
|
@@ -106,7 +108,9 @@ function getOpenCodeActivityMtime() {
|
|
|
106
108
|
if (dbMtime > 0)
|
|
107
109
|
return dbMtime;
|
|
108
110
|
}
|
|
109
|
-
catch {
|
|
111
|
+
catch {
|
|
112
|
+
/* no DB */
|
|
113
|
+
}
|
|
110
114
|
const storageDir = path.join(dataDir, 'storage');
|
|
111
115
|
const sessionMtime = getMostRecentMtime(path.join(storageDir, 'session'));
|
|
112
116
|
const messageMtime = getMostRecentMtime(path.join(storageDir, 'message'));
|
|
@@ -144,7 +148,7 @@ function getAllDetectedProviders() {
|
|
|
144
148
|
const { claudeBase, openCodeDbPath, openCodeStorageDir, codexHomes } = getProviderPaths();
|
|
145
149
|
const hasClaude = fs.existsSync(claudeBase);
|
|
146
150
|
const hasOpenCode = fs.existsSync(openCodeStorageDir) || fs.existsSync(openCodeDbPath);
|
|
147
|
-
const hasCodex = codexHomes.some(codexHome => fs.existsSync(path.join(codexHome, 'sessions')) || hasCodexStateDb(codexHome));
|
|
151
|
+
const hasCodex = codexHomes.some((codexHome) => fs.existsSync(path.join(codexHome, 'sessions')) || hasCodexStateDb(codexHome));
|
|
148
152
|
const available = [];
|
|
149
153
|
if (hasClaude)
|
|
150
154
|
available.push({ id: 'claude-code', mtime: getMostRecentMtime(claudeBase) });
|
|
@@ -153,7 +157,7 @@ function getAllDetectedProviders() {
|
|
|
153
157
|
if (hasCodex)
|
|
154
158
|
available.push({ id: 'codex', mtime: getCodexActivityMtime() });
|
|
155
159
|
available.sort((a, b) => b.mtime - a.mtime);
|
|
156
|
-
return available.map(a => a.id);
|
|
160
|
+
return available.map((a) => a.id);
|
|
157
161
|
}
|
|
158
162
|
/**
|
|
159
163
|
* Detects the most appropriate provider based on filesystem presence and recency.
|
|
@@ -165,7 +169,7 @@ function detectProvider(override) {
|
|
|
165
169
|
const { claudeBase, openCodeDbPath, openCodeStorageDir, codexHomes } = getProviderPaths();
|
|
166
170
|
const hasClaude = fs.existsSync(claudeBase);
|
|
167
171
|
const hasOpenCode = fs.existsSync(openCodeStorageDir) || fs.existsSync(openCodeDbPath);
|
|
168
|
-
const hasCodex = codexHomes.some(codexHome => fs.existsSync(path.join(codexHome, 'sessions')) || hasCodexStateDb(codexHome));
|
|
172
|
+
const hasCodex = codexHomes.some((codexHome) => fs.existsSync(path.join(codexHome, 'sessions')) || hasCodexStateDb(codexHome));
|
|
169
173
|
const available = [];
|
|
170
174
|
if (hasClaude) {
|
|
171
175
|
available.push({ id: 'claude-code', mtime: getMostRecentMtime(claudeBase) });
|