coding-tool-x 3.8.0 → 3.8.2
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 +2 -0
- package/README.md +4 -6
- package/dist/web/assets/{Analytics-8dRv1aYW.js → Analytics-COEUXmd4.js} +1 -1
- package/dist/web/assets/{ConfigTemplates-BQRXSICO.js → ConfigTemplates-DLLkS53H.js} +1 -1
- package/dist/web/assets/{Home-BtzWhKIa.js → Home-DCEyLzwX.js} +1 -1
- package/dist/web/assets/{PluginManager-BTa-Ygf6.js → PluginManager-Oe1ZHoMO.js} +1 -1
- package/dist/web/assets/{ProjectList-F_cB8ldA.js → ProjectList-CWjuAFof.js} +1 -1
- package/dist/web/assets/{SessionList-LOrbPQvu.js → SessionList-v3ehGg9U.js} +1 -1
- package/dist/web/assets/{SkillManager-BzI_t-yV.js → SkillManager-DUF_qP5S.js} +1 -1
- package/dist/web/assets/{WorkspaceManager-Db9RGiz7.js → WorkspaceManager-CjAWBosO.js} +1 -1
- package/dist/web/assets/index-D5hyHPj7.js +2 -0
- package/dist/web/index.html +1 -1
- package/docs/superpowers/plans/2026-08-10-codex-conversion-compatibility.md +251 -0
- package/docs/superpowers/plans/2026-08-11-windows-command-window-hiding.md +90 -0
- package/docs/superpowers/specs/2026-08-10-codex-conversion-compatibility-design.md +61 -0
- package/docs/superpowers/specs/2026-08-11-windows-command-window-hiding-design.md +44 -0
- package/package.json +2 -2
- package/src/commands/update.js +1 -1
- package/src/config/paths.js +1 -0
- package/src/server/api/codex-sessions.js +14 -14
- package/src/server/api/gemini-sessions.js +52 -14
- package/src/server/api/omp-projects.js +2 -2
- package/src/server/api/omp-sessions.js +61 -23
- package/src/server/api/sessions.js +44 -2
- package/src/server/opencode-proxy-server.js +55 -1037
- package/src/server/services/claude-wire.js +694 -0
- package/src/server/services/codex-sessions.js +41 -233
- package/src/server/services/codex-wire.js +219 -0
- package/src/server/services/dashboard-snapshot-worker.js +5 -5
- package/src/server/services/gemini-sessions.js +67 -157
- package/src/server/services/gemini-wire.js +759 -0
- package/src/server/services/model-detector.js +49 -131
- package/src/server/services/omp-channels.js +23 -4
- package/src/server/services/omp-gateway.js +29 -1
- package/src/server/services/omp-sessions.js +102 -105
- package/src/server/services/omp-settings-manager.js +27 -3
- package/src/server/services/opencode-gateway-adapters.js +22 -1147
- package/src/server/services/opencode-normalization.js +546 -0
- package/src/server/services/opencode-sessions.js +339 -546
- package/src/server/services/session-converter.js +4 -4
- package/src/server/services/session-history-adapters/claude.js +235 -0
- package/src/server/services/session-history-adapters/codex.js +158 -0
- package/src/server/services/session-history-adapters/gemini.js +292 -0
- package/src/server/services/session-history-adapters/index.js +20 -0
- package/src/server/services/session-history-adapters/omp.js +256 -0
- package/src/server/services/session-history-index.js +930 -0
- package/src/server/services/session-history-worker.js +99 -0
- package/src/server/services/session-snapshot-worker.js +7 -7
- package/src/server/services/sessions.js +167 -775
- package/src/server/services/speed-test.js +85 -303
- package/src/server/services/sqlite-connection.js +78 -0
- package/src/server/services/workspace-service.js +3 -3
- package/dist/web/assets/index-DIWJmyL6.js +0 -2
|
@@ -4,6 +4,7 @@ const crypto = require('crypto');
|
|
|
4
4
|
const { HOME_DIR } = require('../../config/paths');
|
|
5
5
|
const { getGeminiDir } = require('./gemini-config');
|
|
6
6
|
const { resolveModelPricing } = require('../utils/pricing');
|
|
7
|
+
const { listProjects: idxListProjects, listSessions: idxListSessions, getSessionStatus: idxGetSessionStatus, getRecentSessions: idxGetRecent, searchSessions: idxSearch } = require('./session-history-index');
|
|
7
8
|
|
|
8
9
|
const HASH_RE = /^[a-f0-9]{64}$/;
|
|
9
10
|
const SESSION_FILE_RE = /^session-(.*)-([a-f0-9]+)\.(json|jsonl)$/;
|
|
@@ -628,59 +629,20 @@ function getProjectPath(projectHash, options = {}) {
|
|
|
628
629
|
* 聚合项目列表
|
|
629
630
|
* @returns {Array} 项目对象数组
|
|
630
631
|
*/
|
|
631
|
-
function getProjects(options = {}) {
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
// 如果找到了真实路径,使用目录名作为显示名称
|
|
646
|
-
let displayName;
|
|
647
|
-
if (projectPath) {
|
|
648
|
-
displayName = path.basename(projectPath);
|
|
649
|
-
// 如果是 home 目录,显示 ~
|
|
650
|
-
if (projectPath === HOME_DIR) {
|
|
651
|
-
displayName = '~';
|
|
652
|
-
}
|
|
653
|
-
} else {
|
|
654
|
-
// 未找到路径,使用 hash 前 8 位
|
|
655
|
-
displayName = `Project ${projectHash.substring(0, 8)}`;
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
projectMap.set(projectHash, {
|
|
659
|
-
name: projectHash,
|
|
660
|
-
displayName,
|
|
661
|
-
path: projectPath,
|
|
662
|
-
fullPath: projectPath,
|
|
663
|
-
storageName: session.storageName,
|
|
664
|
-
sessionCount: 0,
|
|
665
|
-
lastUpdated: session.lastUpdated,
|
|
666
|
-
source: 'gemini'
|
|
667
|
-
});
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
const project = projectMap.get(projectHash);
|
|
671
|
-
project.sessionCount++;
|
|
672
|
-
|
|
673
|
-
// 更新最后活动时间
|
|
674
|
-
if (new Date(session.lastUpdated) > new Date(project.lastUpdated)) {
|
|
675
|
-
project.lastUpdated = session.lastUpdated;
|
|
676
|
-
}
|
|
632
|
+
async function getProjects(options = {}) {
|
|
633
|
+
const projects = await idxListProjects('gemini', options);
|
|
634
|
+
const paths = buildPathMapping();
|
|
635
|
+
return projects.map(project => {
|
|
636
|
+
const fullPath = project.fullPath || paths.get(project.name) || null;
|
|
637
|
+
return {
|
|
638
|
+
...project,
|
|
639
|
+
displayName: fullPath ? path.basename(fullPath) : project.displayName,
|
|
640
|
+
path: fullPath,
|
|
641
|
+
fullPath,
|
|
642
|
+
storageName: fullPath ? path.basename(fullPath) : project.name,
|
|
643
|
+
lastUpdated: new Date(project.lastUsed).toISOString()
|
|
644
|
+
};
|
|
677
645
|
});
|
|
678
|
-
|
|
679
|
-
// 转换为数组并排序(按最后活动时间)
|
|
680
|
-
const projects = Array.from(projectMap.values());
|
|
681
|
-
projects.sort((a, b) => new Date(b.lastUpdated) - new Date(a.lastUpdated));
|
|
682
|
-
|
|
683
|
-
return projects;
|
|
684
646
|
}
|
|
685
647
|
|
|
686
648
|
/**
|
|
@@ -688,15 +650,25 @@ function getProjects(options = {}) {
|
|
|
688
650
|
* @param {string} projectHash - 项目 hash
|
|
689
651
|
* @returns {Array} 会话对象数组
|
|
690
652
|
*/
|
|
691
|
-
function getProjectSessions(projectHash, options = {}) {
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
.
|
|
653
|
+
async function getProjectSessions(projectHash, options = {}) {
|
|
654
|
+
const indexed = await idxListSessions('gemini', projectHash, options);
|
|
655
|
+
return indexed.map(session => ({
|
|
656
|
+
sessionId: session.sessionId,
|
|
657
|
+
mtime: new Date(session.mtime).toISOString(),
|
|
658
|
+
size: session.size,
|
|
659
|
+
filePath: session.filePath,
|
|
660
|
+
gitBranch: null,
|
|
661
|
+
firstMessage: session.firstMessage,
|
|
662
|
+
forkedFrom: session.extra?.forkedFrom || null,
|
|
663
|
+
source: 'gemini',
|
|
664
|
+
tokens: session.tokens?.total ?? session.tokens ?? 0,
|
|
665
|
+
cost: session.extra?.cost || 0,
|
|
666
|
+
model: session.model || 'gemini-2.5-pro',
|
|
667
|
+
projectHash: session.projectName,
|
|
668
|
+
projectName: session.projectName,
|
|
669
|
+
storageName: session.extra?.storageName || session.projectName,
|
|
670
|
+
projectRoot: session.projectFullPath || null
|
|
671
|
+
}));
|
|
700
672
|
}
|
|
701
673
|
|
|
702
674
|
/**
|
|
@@ -704,15 +676,9 @@ function getProjectSessions(projectHash, options = {}) {
|
|
|
704
676
|
* @param {string} sessionId - 会话 ID
|
|
705
677
|
* @returns {Object|null} 完整会话数据
|
|
706
678
|
*/
|
|
707
|
-
function getSession(sessionId) {
|
|
708
|
-
const
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
if (!session) {
|
|
712
|
-
return null;
|
|
713
|
-
}
|
|
714
|
-
|
|
715
|
-
return readSessionFull(session.filePath);
|
|
679
|
+
async function getSession(sessionId) {
|
|
680
|
+
const status = await idxGetSessionStatus('gemini', sessionId);
|
|
681
|
+
return status ? readSessionFull(status.filePath) : null;
|
|
716
682
|
}
|
|
717
683
|
|
|
718
684
|
/**
|
|
@@ -773,11 +739,13 @@ function saveProjectOrder(order) {
|
|
|
773
739
|
* @param {number} limit - 限制数量
|
|
774
740
|
* @returns {Array} 会话对象数组
|
|
775
741
|
*/
|
|
776
|
-
function getRecentSessions(limit = 5) {
|
|
777
|
-
const
|
|
778
|
-
return
|
|
779
|
-
|
|
780
|
-
.
|
|
742
|
+
async function getRecentSessions(limit = 5) {
|
|
743
|
+
const sessions = await idxGetRecent('gemini', limit);
|
|
744
|
+
return sessions.map(session => ({
|
|
745
|
+
...session,
|
|
746
|
+
mtime: new Date(session.mtime).toISOString(),
|
|
747
|
+
projectHash: session.projectName
|
|
748
|
+
}));
|
|
781
749
|
}
|
|
782
750
|
|
|
783
751
|
/**
|
|
@@ -785,26 +753,16 @@ function getRecentSessions(limit = 5) {
|
|
|
785
753
|
* @param {string} sessionId - 会话 ID
|
|
786
754
|
* @returns {Object|null} 完整会话数据
|
|
787
755
|
*/
|
|
788
|
-
function getSessionById(sessionId) {
|
|
789
|
-
const
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
if (!
|
|
793
|
-
return null;
|
|
794
|
-
}
|
|
795
|
-
|
|
796
|
-
const fullSession = readSessionFull(sessionMeta.filePath);
|
|
797
|
-
|
|
798
|
-
if (!fullSession) {
|
|
799
|
-
return null;
|
|
800
|
-
}
|
|
801
|
-
|
|
802
|
-
// 合并元数据
|
|
756
|
+
async function getSessionById(sessionId) {
|
|
757
|
+
const status = await idxGetSessionStatus('gemini', sessionId);
|
|
758
|
+
if (!status) return null;
|
|
759
|
+
const fullSession = readSessionFull(status.filePath);
|
|
760
|
+
if (!fullSession) return null;
|
|
803
761
|
return {
|
|
804
762
|
...fullSession,
|
|
805
|
-
filePath:
|
|
806
|
-
size:
|
|
807
|
-
mtime:
|
|
763
|
+
filePath: status.filePath,
|
|
764
|
+
size: status.size,
|
|
765
|
+
mtime: new Date(status.lastModified).toISOString(),
|
|
808
766
|
source: 'gemini'
|
|
809
767
|
};
|
|
810
768
|
}
|
|
@@ -815,70 +773,22 @@ function getSessionById(sessionId) {
|
|
|
815
773
|
* @param {number} contextLength - 上下文长度(可选)
|
|
816
774
|
* @returns {Array} 搜索结果数组
|
|
817
775
|
*/
|
|
818
|
-
function searchSessions(keyword, contextLength = 35) {
|
|
819
|
-
const
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
// 提取消息内容
|
|
835
|
-
if (msg.type === 'user' || msg.type === 'assistant' || msg.type === 'gemini') {
|
|
836
|
-
content = extractContentText(msg.content);
|
|
837
|
-
}
|
|
838
|
-
|
|
839
|
-
// 搜索关键词
|
|
840
|
-
const lowerContent = content.toLowerCase();
|
|
841
|
-
const lowerKeyword = keyword.toLowerCase();
|
|
842
|
-
|
|
843
|
-
if (lowerContent.includes(lowerKeyword)) {
|
|
844
|
-
const keywordIndex = lowerContent.indexOf(lowerKeyword);
|
|
845
|
-
|
|
846
|
-
// 提取上下文
|
|
847
|
-
const start = Math.max(0, keywordIndex - contextLength);
|
|
848
|
-
const end = Math.min(content.length, keywordIndex + keyword.length + contextLength);
|
|
849
|
-
|
|
850
|
-
let context = content.substring(start, end);
|
|
851
|
-
|
|
852
|
-
// 添加省略号
|
|
853
|
-
if (start > 0) context = '...' + context;
|
|
854
|
-
if (end < content.length) context = context + '...';
|
|
855
|
-
|
|
856
|
-
matches.push({
|
|
857
|
-
messageIndex: index,
|
|
858
|
-
role: msg.type,
|
|
859
|
-
context,
|
|
860
|
-
timestamp: msg.timestamp
|
|
861
|
-
});
|
|
862
|
-
}
|
|
863
|
-
});
|
|
864
|
-
|
|
865
|
-
if (matches.length > 0) {
|
|
866
|
-
results.push({
|
|
867
|
-
sessionId: sessionMeta.sessionId,
|
|
868
|
-
projectHash: sessionMeta.projectHash,
|
|
869
|
-
firstMessage: sessionMeta.firstMessage,
|
|
870
|
-
lastUpdated: sessionMeta.lastUpdated,
|
|
871
|
-
matches,
|
|
872
|
-
matchCount: matches.length,
|
|
873
|
-
source: 'gemini'
|
|
874
|
-
});
|
|
875
|
-
}
|
|
876
|
-
});
|
|
877
|
-
|
|
878
|
-
// 按匹配数量排序
|
|
879
|
-
results.sort((a, b) => b.matchCount - a.matchCount);
|
|
880
|
-
|
|
881
|
-
return results;
|
|
776
|
+
async function searchSessions(keyword, contextLength = 35) {
|
|
777
|
+
const results = await idxSearch('gemini', keyword, { contextLength });
|
|
778
|
+
return results.map(result => ({
|
|
779
|
+
sessionId: result.sessionId,
|
|
780
|
+
projectHash: result.projectName,
|
|
781
|
+
firstMessage: result.firstMessage,
|
|
782
|
+
lastUpdated: result.updatedAt || null,
|
|
783
|
+
matches: result.matches.map(match => ({
|
|
784
|
+
messageIndex: match.ordinal,
|
|
785
|
+
role: match.type === 'gemini' ? 'gemini' : match.role,
|
|
786
|
+
context: match.context,
|
|
787
|
+
timestamp: match.timestamp
|
|
788
|
+
})),
|
|
789
|
+
matchCount: result.matchCount,
|
|
790
|
+
source: 'gemini'
|
|
791
|
+
}));
|
|
882
792
|
}
|
|
883
793
|
|
|
884
794
|
/**
|