diff --git a/cli.js b/cli.js index 531b8dd6..e69eaaee 100644 --- a/cli.js +++ b/cli.js @@ -4879,27 +4879,29 @@ function listClaudeSessions(limit, options = {}) { } } - if (sessions.length === 0) { - const fallbackFiles = collectRecentJsonlFiles(claudeProjectsDir, { - returnCount: scanCount, - maxFilesScanned, - ignoreSubPath: `${path.sep}subagents${path.sep}` + // 补充扫描未索引的 .jsonl 文件(包括 sessions-index.json 中遗漏的会话) + const seenFilePaths = new Set(sessions.map((item) => item.filePath).filter(Boolean)); + const fallbackFiles = collectRecentJsonlFiles(claudeProjectsDir, { + returnCount: scanCount, + maxFilesScanned, + ignoreSubPath: `${path.sep}subagents${path.sep}` + }); + for (const filePath of fallbackFiles) { + if (seenFilePaths.has(filePath)) continue; + const summary = parseClaudeSessionSummary(filePath, { + summaryReadBytes, + titleReadBytes }); - for (const filePath of fallbackFiles) { - const summary = parseClaudeSessionSummary(filePath, { - summaryReadBytes, - titleReadBytes - }); - if (summary) { - sessions.push(attachSessionNativeStatus({ - ...summary, - derived: isDerivedSessionFile(filePath) - })); - } + if (summary) { + sessions.push(attachSessionNativeStatus({ + ...summary, + derived: isDerivedSessionFile(filePath) + })); + seenFilePaths.add(filePath); + } - if (sessions.length >= targetCount) { - break; - } + if (sessions.length >= targetCount) { + break; } } diff --git a/package.json b/package.json index d810a16c..c7f93208 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codexmate", - "version": "0.0.35", + "version": "0.0.36", "description": "Codex/Claude Code/OpenClaw 配置、会话与任务编排 CLI + Web 工具", "main": "cli.js", "bin": { diff --git a/tests/unit/web-ui-behavior-parity.test.mjs b/tests/unit/web-ui-behavior-parity.test.mjs index ff780498..7d4a058c 100644 --- a/tests/unit/web-ui-behavior-parity.test.mjs +++ b/tests/unit/web-ui-behavior-parity.test.mjs @@ -325,6 +325,7 @@ test('captured bundled app skeleton only exposes expected data key drift versus const missingCurrentKeys = headDataKeys.filter((key) => !currentDataKeys.includes(key)).sort(); const allowedExtraCurrentKeys = parityAgainstHead ? [ 'appVersion', + 'brandHovered', 'sessionListInitialBatchSize', 'sessionListLoadStep', 'sessionListVisibleCount', @@ -354,6 +355,7 @@ test('captured bundled app skeleton only exposes expected data key drift versus 'showEditProviderKey' ] : [ 'appVersion', + 'brandHovered', '__mainTabSwitchState', 'openclawAuthProfilesByProvider', 'openclawPendingAuthProfileUpdates', diff --git a/tests/unit/web-ui-logic.test.mjs b/tests/unit/web-ui-logic.test.mjs index 711a3d69..8e927ef0 100644 --- a/tests/unit/web-ui-logic.test.mjs +++ b/tests/unit/web-ui-logic.test.mjs @@ -957,8 +957,8 @@ test('activeSessionVisibleMessages falls back to the initial preview batch befor }); test('formatSessionTimelineTimestamp normalizes ISO-like strings for timeline labels', () => { - assert.strictEqual(formatSessionTimelineTimestamp('2026-03-23T09:10:11.000Z'), '03-23 09:10:11'); - assert.strictEqual(formatSessionTimelineTimestamp('2026-03-23 19:20:00'), '03-23 19:20:00'); + assert.strictEqual(formatSessionTimelineTimestamp('2026-03-23T09:10:11.000Z'), '2026-03-23 09:10'); + assert.strictEqual(formatSessionTimelineTimestamp('2026-03-23 19:20:00'), '2026-03-23 19:20'); assert.strictEqual(formatSessionTimelineTimestamp('not-a-time'), 'not-a-time'); assert.strictEqual(formatSessionTimelineTimestamp(''), ''); }); @@ -978,8 +978,8 @@ test('buildSessionTimelineNodes builds per-message node metadata', () => { assert.strictEqual(nodes[0].key, 'user-0'); assert.strictEqual(nodes[0].role, 'user'); assert.strictEqual(nodes[0].roleShort, 'U'); - assert.strictEqual(nodes[0].displayTime, '03-23 09:00:00'); - assert.strictEqual(nodes[0].title, '#1 · User · 03-23 09:00:00'); + assert.strictEqual(nodes[0].displayTime, '2026-03-23 09:00'); + assert.strictEqual(nodes[0].title, '#1 · User · 2026-03-23 09:00'); assert.strictEqual(nodes[0].percent, 0); assert.strictEqual(nodes[0].safePercent, 6); diff --git a/web-ui/app.js b/web-ui/app.js index bb24d331..a2b3840d 100644 --- a/web-ui/app.js +++ b/web-ui/app.js @@ -31,6 +31,7 @@ document.addEventListener('DOMContentLoaded', () => { const appOptions = { data() { return { + brandHovered: false, lang: 'zh', appVersion: '', mainTab: 'dashboard', diff --git a/web-ui/logic.sessions.mjs b/web-ui/logic.sessions.mjs index 1187780d..125ca822 100644 --- a/web-ui/logic.sessions.mjs +++ b/web-ui/logic.sessions.mjs @@ -180,12 +180,9 @@ export function formatSessionTimelineTimestamp(timestamp) { if (!value) return ''; const matched = value.match(/^(\d{4})-(\d{2})-(\d{2})[T\s](\d{2}):(\d{2})(?::(\d{2}))?/); - if (matched) { - const second = matched[6] || '00'; - return `${matched[2]}-${matched[3]} ${matched[4]}:${matched[5]}:${second}`; - } + if (!matched) return value; - return value; + return `${matched[1]}-${matched[2]}-${matched[3]} ${matched[4]}:${matched[5]}`; } function normalizeUsageRange(range) { diff --git a/web-ui/modules/i18n.dict.mjs b/web-ui/modules/i18n.dict.mjs index 861c19f9..47d7f63d 100644 --- a/web-ui/modules/i18n.dict.mjs +++ b/web-ui/modules/i18n.dict.mjs @@ -532,6 +532,7 @@ const DICT = Object.freeze({ 'sessions.loadingList': '会话加载中...', 'sessions.empty': '暂无可用会话记录', 'sessions.unknownTime': '未知时间', + 'sessions.query.placeholder.enabled': '关键词检索(支持 Codex/Claude/Gemini/CodeBuddy,例:claude code)', 'sessions.query.placeholder.disabled': '当前来源暂不支持关键词检索', 'sessions.pin': '置顶', @@ -1602,6 +1603,8 @@ const DICT = Object.freeze({ 'sessions.loadingList': 'セッション一覧を読み込み中...', 'sessions.empty': 'セッションがありません', 'sessions.unknownTime': '不明な時間', + + 'sessions.query.placeholder.enabled': 'セッションを検索...', 'sessions.query.placeholder.disabled': '現在のソースでは検索は利用できません', 'sessions.pin': 'ピン留め', @@ -2658,6 +2661,8 @@ const DICT = Object.freeze({ 'sessions.loadingList': 'Loading sessions...', 'sessions.empty': 'No sessions found', 'sessions.unknownTime': 'unknown time', + + 'sessions.query.placeholder.enabled': 'Search keywords (Codex/Claude/Gemini/CodeBuddy, e.g. claude code)', 'sessions.query.placeholder.disabled': 'Keyword search is not available for this source', 'sessions.pin': 'Pin', diff --git a/web-ui/partials/index/layout-header.html b/web-ui/partials/index/layout-header.html index 0d51e292..0aa4abe0 100644 --- a/web-ui/partials/index/layout-header.html +++ b/web-ui/partials/index/layout-header.html @@ -118,14 +118,13 @@