coding-tool-x 3.8.7 → 3.8.9
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 +2 -2
- package/dist/web/assets/{AgentsDrawer-C7ePByZx.js → AgentsDrawer-Cj5CJ4d9.js} +1 -1
- package/dist/web/assets/Analytics-1doS-8uC.js +1 -0
- package/dist/web/assets/AssetPathField-C9TOPl7o.js +1 -0
- package/dist/web/assets/{ChatHistoryDrawer-Ccl4rhdz.js → ChatHistoryDrawer-BTmQ1aQr.js} +1 -1
- package/dist/web/assets/{CollapseItem-MxG_UD4o.js → CollapseItem-CwqJk3bE.js} +1 -1
- package/dist/web/assets/{CommandsDrawer-DWbaxHRZ.js → CommandsDrawer-CaZWDI_G.js} +1 -1
- package/dist/web/assets/ConfigExportDrawer-C3vSZEsS.js +1 -0
- package/dist/web/assets/{ConfigTemplates-AiRPv2cd.js → ConfigTemplates-gyERg9iC.js} +1 -1
- package/dist/web/assets/{ConfigTemplatesDrawer-CKMFsfEF.js → ConfigTemplatesDrawer-B17RqFi4.js} +1 -1
- package/dist/web/assets/{ConfigTemplatesPanel-Cvbnkvpt.js → ConfigTemplatesPanel-DKIC_FqG.js} +1 -1
- package/dist/web/assets/{Divider-D28g1gwj.js → Divider-DsdbkHrG.js} +1 -1
- package/dist/web/assets/{FavoritesDrawer-DA-dR_vP.js → FavoritesDrawer-DaziQmBp.js} +1 -1
- package/dist/web/assets/Forward-DLCL7aMY.js +1 -0
- package/dist/web/assets/{GatewayConvertDrawer-402_raGb.js → GatewayConvertDrawer-OMgWUUSc.js} +1 -1
- package/dist/web/assets/Home-DOSUTfrE.js +1 -0
- package/dist/web/assets/{MarkdownEditor-BvkDECwH.js → MarkdownEditor-9TTwTS-U.js} +1 -1
- package/dist/web/assets/McpDrawer-I8rl8lGH.js +1 -0
- package/dist/web/assets/{McpFormDrawer-DPMnyt5L.js → McpFormDrawer-DEP3C7ut.js} +1 -1
- package/dist/web/assets/{PluginManager-FKVeugr4.js → PluginManager-BuRcWuBj.js} +1 -1
- package/dist/web/assets/{PluginsDrawer-MvM1R55d.js → PluginsDrawer-_zZENaQn.js} +1 -1
- package/dist/web/assets/PluginsPanel-Bs5qZ-TK.js +1 -0
- package/dist/web/assets/PluginsPanel-CzGMK-Ap.css +1 -0
- package/dist/web/assets/ProjectList-BSxuL2td.js +1 -0
- package/dist/web/assets/{ProjectList-677RLZ8O.css → ProjectList-VbIYSHbH.css} +1 -1
- package/dist/web/assets/PromptsDrawer-CoZ-ZtsY.js +1 -0
- package/dist/web/assets/RecentSessionsDrawer-B_17aJBG.js +1 -0
- package/dist/web/assets/RecentSessionsDrawer-yrAD4p1A.css +1 -0
- package/dist/web/assets/SessionCard-BL_x0d3t.js +1 -0
- package/dist/web/assets/SessionList-DhRYZ6vl.js +1 -0
- package/dist/web/assets/SessionList-qG_XpPBJ.css +1 -0
- package/dist/web/assets/{SettingsDrawer-lMjttbkD.js → SettingsDrawer-fYb0DU7X.js} +1 -1
- package/dist/web/assets/SkillManager-S698Hns8.js +1 -0
- package/dist/web/assets/{SkillsDrawer-DF6JsSyj.js → SkillsDrawer-Ms4lPCow.js} +1 -1
- package/dist/web/assets/{SkillsPanel-B3Nm5j32.css → SkillsPanel-C4ke56nF.css} +1 -1
- package/dist/web/assets/SkillsPanel-rqnqAOGL.js +1 -0
- package/dist/web/assets/{SpeedTestDrawer-BaZkZqPP.js → SpeedTestDrawer-Bbn38SfV.js} +1 -1
- package/dist/web/assets/Upload-CdyVHxCI.js +1 -0
- package/dist/web/assets/{WorkspaceDrawer-BFSwZ5yU.js → WorkspaceDrawer-L7HJRc6u.js} +1 -1
- package/dist/web/assets/{WorkspaceManager-BHL1uYct.js → WorkspaceManager-DsoNg2z8.js} +1 -1
- package/dist/web/assets/{WorkspacePanel-B5PooBtg.js → WorkspacePanel-Be8PVZah.js} +1 -1
- package/dist/web/assets/{headers-cf-QapUq.js → headers-B5JWGn3v.js} +1 -1
- package/dist/web/assets/{icons-B2Vg-IOC.js → icons-DmFe4b5j.js} +1 -1
- package/dist/web/assets/{index-BohDDAy_.css → index-3Lp6z8TQ.css} +1 -1
- package/dist/web/assets/index-BKlAWTH-.js +2 -0
- package/dist/web/assets/{light-Cp0t7v32.js → light-0eavxNvt.js} +1 -1
- package/dist/web/assets/platforms-BmzzwnSw.js +1 -0
- package/dist/web/assets/platforms-DWXgmy2w.js +1 -0
- package/dist/web/assets/session-visibility-BAmxh3cK.js +1 -0
- package/dist/web/assets/sessions-CC0j-KH_.js +1 -0
- package/dist/web/assets/sessions-D4yQtfKb.js +1 -0
- package/dist/web/assets/use-message-DqCwefG6.js +1 -0
- package/dist/web/assets/{useResponsiveDrawer-D-DDpbnI.js → useResponsiveDrawer-V_onl9NV.js} +1 -1
- package/dist/web/index.html +7 -7
- package/package.json +1 -1
- package/src/commands/daemon.js +27 -4
- package/src/commands/search.js +17 -2
- package/src/config/paths.js +2 -0
- package/src/platforms/channel-auth-registry.js +36 -6
- package/src/platforms/channel-auth-service.js +12 -2
- package/src/platforms/driver-registry.js +9 -1
- package/src/platforms/drivers/claude/session-history-adapter.js +72 -1
- package/src/platforms/drivers/claude/sessions-implementation.js +49 -7
- package/src/platforms/drivers/claude/sessions.js +30 -6
- package/src/platforms/drivers/codex/parser.js +57 -1
- package/src/platforms/drivers/codex/session-history-adapter.js +8 -2
- package/src/platforms/drivers/codex/sessions-implementation.js +25 -3
- package/src/platforms/drivers/codex/sessions.js +18 -1
- package/src/platforms/drivers/dsh/api-operations.js +396 -0
- package/src/platforms/drivers/dsh/channels-implementation.js +458 -0
- package/src/platforms/drivers/dsh/channels.js +191 -0
- package/src/platforms/drivers/dsh/common.js +571 -0
- package/src/platforms/drivers/dsh/native-config.js +93 -0
- package/src/platforms/drivers/dsh/native-logs.js +116 -0
- package/src/platforms/drivers/dsh/plugin-manager.js +117 -0
- package/src/platforms/drivers/dsh/projects.js +23 -0
- package/src/platforms/drivers/dsh/proxy-implementation.js +260 -0
- package/src/platforms/drivers/dsh/proxy.js +23 -0
- package/src/platforms/drivers/dsh/resources.js +346 -0
- package/src/platforms/drivers/dsh/sessions.js +587 -0
- package/src/platforms/drivers/dsh/statistics-implementation.js +238 -0
- package/src/platforms/drivers/dsh/statistics.js +24 -0
- package/src/platforms/drivers/gemini/session-history-adapter.js +49 -1
- package/src/platforms/drivers/gemini/sessions-implementation.js +46 -1
- package/src/platforms/drivers/gemini/sessions.js +2 -1
- package/src/platforms/drivers/omp/prompts.js +58 -2
- package/src/platforms/drivers/omp/proxy-implementation.js +25 -1
- package/src/platforms/drivers/omp/session-history-adapter.js +42 -1
- package/src/platforms/drivers/omp/sessions-implementation.js +51 -3
- package/src/platforms/drivers/omp/sessions.js +33 -2
- package/src/platforms/drivers/opencode/channels-implementation.js +25 -22
- package/src/platforms/drivers/opencode/channels.js +6 -1
- package/src/platforms/drivers/opencode/sessions-implementation.js +89 -9
- package/src/platforms/drivers/opencode/sessions.js +37 -1
- package/src/platforms/manifest-schema.js +43 -3
- package/src/platforms/manifests/dsh.json +542 -0
- package/src/platforms/manifests/omp.json +2 -1
- package/src/platforms/manifests/opencode.json +28 -0
- package/src/platforms/native-oauth-adapters.js +318 -18
- package/src/platforms/oauth-credentials-service.js +344 -13
- package/src/platforms/path-resolver.js +2 -0
- package/src/platforms/platform-path-context.js +12 -2
- package/src/platforms/registry.js +16 -1
- package/src/platforms/runtime.js +5 -0
- package/src/platforms/session-history-adapters.js +1 -0
- package/src/server/api/platform-api-config.js +23 -2
- package/src/server/api/platform-route-factory.js +9 -2
- package/src/server/api/platforms.js +19 -1
- package/src/server/api/plugins.js +108 -13
- package/src/server/index.js +35 -1
- package/src/server/services/config-registry-service.js +10 -1
- package/src/server/services/config-templates-service.js +1 -0
- package/src/server/services/plugins-service.js +474 -103
- package/src/server/services/session-history-index.js +900 -140
- package/src/server/services/session-history-worker.js +3 -1
- package/src/server/services/skill-service.js +214 -7
- package/src/server/services/usage-log-utils.js +1 -0
- package/src/server/services/workspace-service.js +39 -10
- package/src/shared/driver-factories/api.js +22 -6
- package/src/shared/driver-factories/projects.js +8 -0
- package/dist/web/assets/Analytics-BVG6ehFv.js +0 -1
- package/dist/web/assets/AssetPathField-BZI9NvEr.js +0 -1
- package/dist/web/assets/ConfigExportDrawer-DrawKwxE.js +0 -1
- package/dist/web/assets/Home-CTF8ZWKW.js +0 -1
- package/dist/web/assets/McpDrawer-DZGHkuDm.js +0 -1
- package/dist/web/assets/PluginsPanel-CKuBs38B.js +0 -1
- package/dist/web/assets/PluginsPanel-D6ZqITcR.css +0 -1
- package/dist/web/assets/ProjectList-tsjwjXV1.js +0 -1
- package/dist/web/assets/PromptsDrawer-B-X9ci8n.js +0 -1
- package/dist/web/assets/RecentSessionsDrawer-CKFsOYDM.css +0 -1
- package/dist/web/assets/RecentSessionsDrawer-wLktMF_c.js +0 -1
- package/dist/web/assets/SessionCard-DkJPy0TY.js +0 -1
- package/dist/web/assets/SessionList-BpYRz1cX.css +0 -1
- package/dist/web/assets/SessionList-Gzhh4FOZ.js +0 -1
- package/dist/web/assets/SkillManager-CzFxWxx-.js +0 -1
- package/dist/web/assets/SkillsPanel--lLEts9y.js +0 -1
- package/dist/web/assets/Upload-BEQ-3Kqq.js +0 -1
- package/dist/web/assets/index-BFInlZGI.js +0 -2
- package/dist/web/assets/platforms-CBkB45JP.js +0 -1
- package/dist/web/assets/platforms-FTpjxAT6.js +0 -1
- package/dist/web/assets/sessions-Cmy31slD.js +0 -1
- package/dist/web/assets/sessions-yC_oVVh8.js +0 -1
- package/dist/web/assets/use-message-DoLM8C1C.js +0 -1
|
@@ -11,12 +11,12 @@ function createDriver(context = {}) {
|
|
|
11
11
|
servicePath: './omp/sessions-implementation',
|
|
12
12
|
localServicePath: '../platforms/drivers/omp/sessions-implementation',
|
|
13
13
|
adapterLocalPath: '../platforms/drivers/omp/session-history-adapter',
|
|
14
|
-
adapterMethods: { inventory: 'inventory', parse: 'parse' },
|
|
14
|
+
adapterMethods: { inventory: 'inventory', summarize: 'summarize', parse: 'parse' },
|
|
15
15
|
methods: {
|
|
16
16
|
getProjects: 'getProjects',
|
|
17
17
|
listSessions: 'getSessionsByProject',
|
|
18
|
+
listSessionsPage: 'getSessionsPage',
|
|
18
19
|
recent: 'getRecentSessions',
|
|
19
|
-
search: 'searchSessions',
|
|
20
20
|
getSessionById: 'getSessionById',
|
|
21
21
|
messages: 'getSessionMessages',
|
|
22
22
|
delete: 'deleteSession',
|
|
@@ -25,6 +25,37 @@ function createDriver(context = {}) {
|
|
|
25
25
|
buildLaunchCommand: 'buildLaunchCommand',
|
|
26
26
|
status: 'getSessionStatus'
|
|
27
27
|
},
|
|
28
|
+
customMethods: {
|
|
29
|
+
search: (service, requestOrProjectName, keyword, contextLength, options = {}) => {
|
|
30
|
+
if (requestOrProjectName && typeof requestOrProjectName === 'object' && !Array.isArray(requestOrProjectName)) {
|
|
31
|
+
const request = requestOrProjectName;
|
|
32
|
+
const query = request.query || {};
|
|
33
|
+
return service.searchSessions(query.keyword || query.q || '', Number(query.context) || 15, {
|
|
34
|
+
...request,
|
|
35
|
+
...options,
|
|
36
|
+
projectName: request.params?.projectName || null,
|
|
37
|
+
limit: Number.parseInt(query.limit, 10) || 100
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
return service.searchSessions(keyword, contextLength, {
|
|
41
|
+
...options,
|
|
42
|
+
projectName: requestOrProjectName
|
|
43
|
+
});
|
|
44
|
+
},
|
|
45
|
+
searchAcrossProjects: (service, requestOrKeyword, limit, options = {}) => {
|
|
46
|
+
if (requestOrKeyword && typeof requestOrKeyword === 'object' && !Array.isArray(requestOrKeyword)) {
|
|
47
|
+
const request = requestOrKeyword;
|
|
48
|
+
const query = request.query || {};
|
|
49
|
+
return service.searchSessions(query.keyword || query.q || '', Number(query.context) || 35, {
|
|
50
|
+
...request,
|
|
51
|
+
...options,
|
|
52
|
+
projectName: query.projectName || query.project || null,
|
|
53
|
+
limit: Number.parseInt(query.limit, 10) || 35
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
return service.searchSessions(requestOrKeyword, Number(options.contextLength) || 35, { ...options, limit });
|
|
57
|
+
}
|
|
58
|
+
},
|
|
28
59
|
onSuccess: operation => {
|
|
29
60
|
if (['delete', 'fork', 'saveSessionOrder'].includes(operation)) {
|
|
30
61
|
context.sessionHistoryIndex?.invalidateSource('omp');
|
|
@@ -68,6 +68,10 @@ function normalizeChannelName(value) {
|
|
|
68
68
|
.replace(/\s+/g, ' ');
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
function normalizeAuthMode(value) {
|
|
72
|
+
return ['api_key', 'oauth', 'none'].includes(value) ? value : 'api_key';
|
|
73
|
+
}
|
|
74
|
+
|
|
71
75
|
// 获取渠道存储文件路径
|
|
72
76
|
function getChannelsFilePath() {
|
|
73
77
|
const channelsDir = path.dirname(configuredState.channels);
|
|
@@ -98,24 +102,7 @@ function loadChannels() {
|
|
|
98
102
|
const data = JSON.parse(content);
|
|
99
103
|
// 确保渠道有必要字段(兼容旧数据)
|
|
100
104
|
if (data.channels) {
|
|
101
|
-
data.channels = data.channels.map(ch =>
|
|
102
|
-
const normalized = {
|
|
103
|
-
...ch,
|
|
104
|
-
enabled: ch.enabled !== false,
|
|
105
|
-
weight: ch.weight || 1,
|
|
106
|
-
maxConcurrency: ch.maxConcurrency || null,
|
|
107
|
-
balanceToken: ch.balanceToken || '',
|
|
108
|
-
balanceUserId: ch.balanceUserId || null,
|
|
109
|
-
modelRedirects: ch.modelRedirects || [],
|
|
110
|
-
speedTestModel: ch.speedTestModel || null,
|
|
111
|
-
wireApi: ch.wireApi || 'openai', // OpenCode 默认使用 OpenAI 兼容格式
|
|
112
|
-
gatewaySourceType: normalizeGatewaySourceType(ch.gatewaySourceType, 'codex'),
|
|
113
|
-
allowedModels: ch.allowedModels || []
|
|
114
|
-
};
|
|
115
|
-
normalized.providerKey = ch.providerKey || deriveProviderKey(normalized);
|
|
116
|
-
normalized.websiteUrl = resolveChannelWebsiteUrl('opencode', normalized);
|
|
117
|
-
return normalized;
|
|
118
|
-
});
|
|
105
|
+
data.channels = data.channels.map(ch => normalizeOpenCodeChannel(ch));
|
|
119
106
|
}
|
|
120
107
|
return data;
|
|
121
108
|
} catch (err) {
|
|
@@ -191,12 +178,18 @@ function getChannels() {
|
|
|
191
178
|
function createChannel(name, baseUrl, apiKey, extraConfig = {}) {
|
|
192
179
|
const data = loadChannels();
|
|
193
180
|
const isProxyRunning = getOpenCodeProxyRunning();
|
|
181
|
+
const authMode = normalizeAuthMode(extraConfig.authMode);
|
|
194
182
|
|
|
195
183
|
const newChannel = {
|
|
196
184
|
id: crypto.randomUUID(),
|
|
197
185
|
name,
|
|
198
|
-
baseUrl,
|
|
199
|
-
apiKey,
|
|
186
|
+
baseUrl: authMode === 'oauth' || authMode === 'none' ? '' : baseUrl,
|
|
187
|
+
apiKey: authMode === 'oauth' || authMode === 'none' ? '' : apiKey,
|
|
188
|
+
authMode,
|
|
189
|
+
authRef: authMode === 'oauth' ? (extraConfig.authRef || {}) : undefined,
|
|
190
|
+
authSource: authMode === 'oauth' ? (extraConfig.authSource || 'synced-local') : undefined,
|
|
191
|
+
authStatus: authMode === 'oauth' ? (extraConfig.authStatus || 'available') : undefined,
|
|
192
|
+
oauthProviderId: authMode === 'oauth' ? (extraConfig.oauthProviderId || extraConfig.providerKey || '') : '',
|
|
200
193
|
wireApi: extraConfig.wireApi || 'openai',
|
|
201
194
|
enabled: extraConfig.enabled !== false,
|
|
202
195
|
weight: extraConfig.weight || 1,
|
|
@@ -248,7 +241,7 @@ function updateChannel(channelId, updates) {
|
|
|
248
241
|
|
|
249
242
|
const oldChannel = data.channels[index];
|
|
250
243
|
|
|
251
|
-
const merged = {
|
|
244
|
+
const merged = normalizeOpenCodeChannel({
|
|
252
245
|
...oldChannel,
|
|
253
246
|
...updates,
|
|
254
247
|
id: channelId,
|
|
@@ -264,7 +257,7 @@ function updateChannel(channelId, updates) {
|
|
|
264
257
|
'codex'
|
|
265
258
|
),
|
|
266
259
|
updatedAt: Date.now()
|
|
267
|
-
};
|
|
260
|
+
});
|
|
268
261
|
merged.providerKey = updates.providerKey || oldChannel.providerKey || deriveProviderKey(merged);
|
|
269
262
|
merged.websiteUrl = resolveChannelWebsiteUrl('opencode', merged);
|
|
270
263
|
data.channels[index] = merged;
|
|
@@ -524,6 +517,7 @@ function findOpenCodeExistingByProvider(channels = [], providerId = '', baseUrl
|
|
|
524
517
|
}
|
|
525
518
|
|
|
526
519
|
function normalizeOpenCodeChannel(channel = {}) {
|
|
520
|
+
const authMode = normalizeAuthMode(channel.authMode);
|
|
527
521
|
const normalized = {
|
|
528
522
|
...channel,
|
|
529
523
|
enabled: channel.enabled !== false,
|
|
@@ -537,6 +531,15 @@ function normalizeOpenCodeChannel(channel = {}) {
|
|
|
537
531
|
gatewaySourceType: normalizeGatewaySourceType(channel.gatewaySourceType, 'codex'),
|
|
538
532
|
allowedModels: Array.isArray(channel.allowedModels) ? channel.allowedModels : []
|
|
539
533
|
};
|
|
534
|
+
normalized.authMode = authMode;
|
|
535
|
+
normalized.authRef = authMode === 'oauth' ? (channel.authRef || {}) : undefined;
|
|
536
|
+
normalized.authSource = authMode === 'oauth' ? (channel.authSource || 'synced-local') : undefined;
|
|
537
|
+
normalized.authStatus = authMode === 'oauth' ? (channel.authStatus || 'available') : undefined;
|
|
538
|
+
normalized.oauthProviderId = authMode === 'oauth' ? (channel.oauthProviderId || channel.providerKey || '') : '';
|
|
539
|
+
if (authMode === 'oauth' || authMode === 'none') {
|
|
540
|
+
normalized.baseUrl = '';
|
|
541
|
+
normalized.apiKey = '';
|
|
542
|
+
}
|
|
540
543
|
normalized.providerKey = normalized.providerKey || deriveProviderKey(normalized);
|
|
541
544
|
normalized.websiteUrl = resolveChannelWebsiteUrl('opencode', normalized);
|
|
542
545
|
return normalized;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
const { createChannelDriver } = require('../../../shared/channel-driver');
|
|
4
4
|
|
|
5
5
|
function createDriver(context = {}) {
|
|
6
|
-
|
|
6
|
+
const driver = createChannelDriver({
|
|
7
7
|
...context,
|
|
8
8
|
platform: 'opencode',
|
|
9
9
|
servicePath: './opencode/channels-implementation',
|
|
@@ -35,6 +35,11 @@ function createDriver(context = {}) {
|
|
|
35
35
|
},
|
|
36
36
|
dashboardChannelShape: 'array'
|
|
37
37
|
});
|
|
38
|
+
const auth = require('../../channel-auth-service');
|
|
39
|
+
driver.getAuth = context => auth.getChannelAuth('opencode', { channelId: context?.params?.channelId || context?.query?.channelId || '' });
|
|
40
|
+
driver.syncLocalAuth = context => auth.syncLocalChannelAuth('opencode', { channelId: context?.body?.channelId || context?.params?.channelId || context?.query?.channelId || '' });
|
|
41
|
+
driver.getAuthQuota = context => auth.fetchChannelAuthQuota('opencode', context?.params?.channelId, { refresh: context?.query?.refresh === 'true' });
|
|
42
|
+
return driver;
|
|
38
43
|
}
|
|
39
44
|
|
|
40
45
|
module.exports = { createDriver };
|
|
@@ -345,7 +345,33 @@ function getProjectRows() {
|
|
|
345
345
|
`);
|
|
346
346
|
}
|
|
347
347
|
|
|
348
|
-
function
|
|
348
|
+
function getProjectRowsPage(options = {}) {
|
|
349
|
+
const page = Math.max(1, Number.parseInt(options.page, 10) || 1);
|
|
350
|
+
const limit = Math.max(1, Math.min(100, Number.parseInt(options.limit, 10) || 20));
|
|
351
|
+
const query = String(options.q || options.search || '').trim();
|
|
352
|
+
const like = `%${query}%`;
|
|
353
|
+
const where = query ? 'WHERE p.id LIKE ? OR p.name LIKE ? OR p.worktree LIKE ?' : '';
|
|
354
|
+
const params = query ? [like, like, like] : [];
|
|
355
|
+
const total = Number(_query(`SELECT COUNT(*) AS total FROM project p ${where}`, ...params)[0]?.total) || 0;
|
|
356
|
+
const rows = _query(`
|
|
357
|
+
SELECT
|
|
358
|
+
p.*,
|
|
359
|
+
(SELECT s.directory FROM session s
|
|
360
|
+
WHERE s.project_id = p.id AND s.time_archived IS NULL
|
|
361
|
+
ORDER BY s.time_updated DESC LIMIT 1) AS session_directory,
|
|
362
|
+
(SELECT COUNT(*) FROM session s WHERE s.project_id = p.id AND s.time_archived IS NULL) AS session_count
|
|
363
|
+
FROM project p
|
|
364
|
+
${where}
|
|
365
|
+
ORDER BY p.time_updated DESC, p.id ASC
|
|
366
|
+
LIMIT ? OFFSET ?
|
|
367
|
+
`, ...params, limit, (page - 1) * limit);
|
|
368
|
+
return { rows, page, limit, total };
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
function getSessionRowsByProjectId(projectId, options = {}) {
|
|
372
|
+
const pagination = options.limit != null
|
|
373
|
+
? `LIMIT ${Math.max(1, Math.min(100, Number(options.limit) || 20))} OFFSET ${Math.max(0, Number(options.offset) || 0)}`
|
|
374
|
+
: '';
|
|
349
375
|
return _query(`
|
|
350
376
|
SELECT
|
|
351
377
|
s.id,
|
|
@@ -384,7 +410,8 @@ function getSessionRowsByProjectId(projectId) {
|
|
|
384
410
|
FROM session s
|
|
385
411
|
WHERE s.project_id = ?
|
|
386
412
|
AND s.time_archived IS NULL
|
|
387
|
-
ORDER BY s.time_updated DESC
|
|
413
|
+
ORDER BY s.time_updated DESC, s.id ASC
|
|
414
|
+
${pagination}
|
|
388
415
|
`, projectId);
|
|
389
416
|
}
|
|
390
417
|
|
|
@@ -484,8 +511,7 @@ function normalizeSession(session, projectId) {
|
|
|
484
511
|
// Public API
|
|
485
512
|
// ---------------------------------------------------------------------------
|
|
486
513
|
|
|
487
|
-
function
|
|
488
|
-
const projects = getProjectRows().map((project) => {
|
|
514
|
+
function normalizeProjectRow(project) {
|
|
489
515
|
const fallbackPath = project.worktree && project.worktree !== '/'
|
|
490
516
|
? project.worktree
|
|
491
517
|
: project.session_directory || project.worktree || '/';
|
|
@@ -504,12 +530,25 @@ function getProjects(_options = {}) {
|
|
|
504
530
|
lastUsed: toIsoTime(project.time_updated),
|
|
505
531
|
source: 'opencode'
|
|
506
532
|
};
|
|
507
|
-
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
function getProjects(_options = {}) {
|
|
536
|
+
const projects = getProjectRows().map(normalizeProjectRow);
|
|
508
537
|
|
|
509
538
|
const order = getProjectOrder();
|
|
510
539
|
return sortByOrder(projects, order, (a, b) => (b.lastUsed || '').localeCompare(a.lastUsed || ''));
|
|
511
540
|
}
|
|
512
541
|
|
|
542
|
+
function getProjectsPage(options = {}) {
|
|
543
|
+
const { rows, page, limit, total } = getProjectRowsPage(options);
|
|
544
|
+
const projects = rows.map(normalizeProjectRow);
|
|
545
|
+
return {
|
|
546
|
+
projects,
|
|
547
|
+
currentProject: null,
|
|
548
|
+
pagination: { page, limit, total, hasMore: page * limit < total }
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
|
|
513
552
|
function getSessionsByProjectId(projectId, _options = {}) {
|
|
514
553
|
const sessions = getSessionRowsByProjectId(projectId).map(session => normalizeSession(session, projectId));
|
|
515
554
|
const order = getSessionOrder(projectId);
|
|
@@ -523,13 +562,48 @@ function getSessionsByProjectId(projectId, _options = {}) {
|
|
|
523
562
|
);
|
|
524
563
|
}
|
|
525
564
|
|
|
526
|
-
function
|
|
565
|
+
function getSessionsPage(projectId, options = {}) {
|
|
566
|
+
const page = Math.max(1, Number.parseInt(options.page, 10) || 1);
|
|
567
|
+
const limit = Math.max(1, Math.min(100, Number.parseInt(options.limit, 10) || 20));
|
|
568
|
+
const aggregate = _query(`
|
|
569
|
+
SELECT COUNT(*) AS total,
|
|
570
|
+
COALESCE(SUM(
|
|
571
|
+
COALESCE((SELECT SUM(LENGTH(CAST(m.data AS BLOB))) FROM message m WHERE m.session_id = s.id), 0)
|
|
572
|
+
+ COALESCE((SELECT SUM(LENGTH(CAST(p.data AS BLOB))) FROM part p WHERE p.session_id = s.id), 0)
|
|
573
|
+
+ COALESCE(LENGTH(CAST(s.title AS BLOB)), 0)
|
|
574
|
+
+ COALESCE(LENGTH(CAST(s.slug AS BLOB)), 0)
|
|
575
|
+
+ COALESCE(LENGTH(CAST(s.directory AS BLOB)), 0)
|
|
576
|
+
), 0) AS total_size
|
|
577
|
+
FROM session s
|
|
578
|
+
WHERE s.project_id = ? AND s.time_archived IS NULL
|
|
579
|
+
`, projectId)[0] || {};
|
|
580
|
+
const sessions = getSessionRowsByProjectId(projectId, {
|
|
581
|
+
limit,
|
|
582
|
+
offset: (page - 1) * limit
|
|
583
|
+
}).map(session => normalizeSession(session, projectId));
|
|
584
|
+
const total = Number(aggregate.total) || 0;
|
|
585
|
+
const totalSize = Number(aggregate.total_size) || 0;
|
|
586
|
+
return {
|
|
587
|
+
sessions,
|
|
588
|
+
totalSize,
|
|
589
|
+
projectInfo: { sessionCount: total, totalSize },
|
|
590
|
+
pagination: { page, limit, total, hasMore: page * limit < total }
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
function searchSessions(keyword, options = {}) {
|
|
527
595
|
if (!keyword || !keyword.trim()) return [];
|
|
528
596
|
const lowerKeyword = keyword.toLowerCase();
|
|
597
|
+
const projectName = typeof options.projectName === 'string' && options.projectName.trim()
|
|
598
|
+
? options.projectName.trim()
|
|
599
|
+
: null;
|
|
600
|
+
const contextLength = Math.max(1, Math.min(200, Number(options.contextLength) || 35));
|
|
601
|
+
const limit = Math.max(1, Math.min(200, Number(options.limit) || 100));
|
|
529
602
|
|
|
530
603
|
const allSessions = [];
|
|
531
604
|
const projects = getProjectRows();
|
|
532
605
|
for (const project of projects) {
|
|
606
|
+
if (projectName && project.id !== projectName) continue;
|
|
533
607
|
const sessions = getSessionRowsByProjectId(project.id);
|
|
534
608
|
for (const session of sessions) {
|
|
535
609
|
const messages = getMessageRowsBySessionId(session.id);
|
|
@@ -563,7 +637,7 @@ function searchSessions(keyword) {
|
|
|
563
637
|
matchedMessages.push({
|
|
564
638
|
messageIndex: i,
|
|
565
639
|
role: data ? (data.role || 'unknown') : 'unknown',
|
|
566
|
-
context: buildContext(text, keyword),
|
|
640
|
+
context: buildContext(text, keyword, contextLength),
|
|
567
641
|
timestamp: toIsoTime(message.time_created)
|
|
568
642
|
});
|
|
569
643
|
}
|
|
@@ -577,13 +651,17 @@ function searchSessions(keyword) {
|
|
|
577
651
|
firstMessage: session.title || null,
|
|
578
652
|
matches: matchedMessages,
|
|
579
653
|
matchCount: matchedMessages.length,
|
|
654
|
+
updatedAt: normalizeTimestampMs(session.time_updated) || 0,
|
|
655
|
+
projectFullPath: project.worktree || null,
|
|
580
656
|
source: 'opencode'
|
|
581
657
|
});
|
|
582
658
|
}
|
|
583
659
|
}
|
|
584
660
|
}
|
|
585
661
|
|
|
586
|
-
return allSessions
|
|
662
|
+
return allSessions
|
|
663
|
+
.sort((a, b) => b.updatedAt - a.updatedAt || a.sessionId.localeCompare(b.sessionId))
|
|
664
|
+
.slice(0, limit);
|
|
587
665
|
}
|
|
588
666
|
|
|
589
667
|
function getRecentSessions(limit = 5) {
|
|
@@ -638,7 +716,7 @@ function getSessionMessages(sessionId, options = {}) {
|
|
|
638
716
|
const session = getSessionById(sessionId);
|
|
639
717
|
if (!session) return null;
|
|
640
718
|
const page = Math.max(1, Number.parseInt(options.page, 10) || 1);
|
|
641
|
-
const limit = Math.max(1, Math.min(200, Number.parseInt(options.limit, 10) ||
|
|
719
|
+
const limit = Math.max(1, Math.min(200, Number.parseInt(options.limit, 10) || 20));
|
|
642
720
|
const order = String(options.order || 'desc').toLowerCase() === 'asc' ? 'asc' : 'desc';
|
|
643
721
|
const ordered = order === 'asc' ? [...session.messages] : [...session.messages].reverse();
|
|
644
722
|
const offset = (page - 1) * limit;
|
|
@@ -907,7 +985,9 @@ module.exports = {
|
|
|
907
985
|
getOpenCodeDbPath,
|
|
908
986
|
isOpenCodeInstalled,
|
|
909
987
|
getProjects,
|
|
988
|
+
getProjectsPage,
|
|
910
989
|
getSessionsByProjectId,
|
|
990
|
+
getSessionsPage,
|
|
911
991
|
getSessionById,
|
|
912
992
|
getSessionStatus,
|
|
913
993
|
getSessionMessages,
|
|
@@ -12,7 +12,6 @@ function createDriver(context = {}) {
|
|
|
12
12
|
methods: {
|
|
13
13
|
getProjects: 'getProjects',
|
|
14
14
|
recent: 'getRecentSessions',
|
|
15
|
-
search: 'searchSessions',
|
|
16
15
|
getSessionById: 'getSessionById',
|
|
17
16
|
delete: 'deleteSession',
|
|
18
17
|
fork: 'forkSession',
|
|
@@ -22,11 +21,48 @@ function createDriver(context = {}) {
|
|
|
22
21
|
isAvailable: 'isOpenCodeInstalled'
|
|
23
22
|
},
|
|
24
23
|
customMethods: {
|
|
24
|
+
search: (service, requestOrProjectName, keyword, contextLength, options = {}) => {
|
|
25
|
+
if (requestOrProjectName && typeof requestOrProjectName === 'object' && !Array.isArray(requestOrProjectName)) {
|
|
26
|
+
const request = requestOrProjectName;
|
|
27
|
+
const query = request.query || {};
|
|
28
|
+
return service.searchSessions(query.keyword || query.q || '', {
|
|
29
|
+
...request,
|
|
30
|
+
...options,
|
|
31
|
+
projectName: request.params?.projectName || null,
|
|
32
|
+
contextLength: Number(query.context) || 15,
|
|
33
|
+
limit: Number.parseInt(query.limit, 10) || 100
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
return service.searchSessions(keyword, {
|
|
37
|
+
...options,
|
|
38
|
+
projectName: requestOrProjectName,
|
|
39
|
+
contextLength,
|
|
40
|
+
limit: options.limit
|
|
41
|
+
});
|
|
42
|
+
},
|
|
43
|
+
searchAcrossProjects: (service, requestOrKeyword, limit, options = {}) => {
|
|
44
|
+
if (requestOrKeyword && typeof requestOrKeyword === 'object' && !Array.isArray(requestOrKeyword)) {
|
|
45
|
+
const request = requestOrKeyword;
|
|
46
|
+
const query = request.query || {};
|
|
47
|
+
return service.searchSessions(query.keyword || query.q || '', {
|
|
48
|
+
...request,
|
|
49
|
+
...options,
|
|
50
|
+
projectName: query.projectName || query.project || null,
|
|
51
|
+
limit: Number.parseInt(query.limit, 10) || 35,
|
|
52
|
+
contextLength: Number(query.context) || 35
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
return service.searchSessions(requestOrKeyword, { ...options, limit });
|
|
56
|
+
},
|
|
25
57
|
listSessions: (service, ...args) => {
|
|
26
58
|
const method = service.getSessionsByProjectId || service.getSessionsByProject;
|
|
27
59
|
if (typeof method !== 'function') return undefined;
|
|
28
60
|
return method.apply(service, args);
|
|
29
61
|
},
|
|
62
|
+
listSessionsPage: (service, projectName, options = {}) => {
|
|
63
|
+
if (typeof service.getSessionsPage !== 'function') return undefined;
|
|
64
|
+
return service.getSessionsPage(projectName, options);
|
|
65
|
+
},
|
|
30
66
|
messages: (service, sessionId, options) => {
|
|
31
67
|
if (typeof service.getSessionMessages === 'function') {
|
|
32
68
|
return service.getSessionMessages(sessionId, options);
|
|
@@ -17,7 +17,15 @@ const DRIVER_IDS = new Set([
|
|
|
17
17
|
'legacy:opencode',
|
|
18
18
|
'legacy:omp',
|
|
19
19
|
'opencode-conversion',
|
|
20
|
-
'claude-health'
|
|
20
|
+
'claude-health',
|
|
21
|
+
'dsh-api',
|
|
22
|
+
'dsh-projects',
|
|
23
|
+
'dsh-sessions',
|
|
24
|
+
'dsh-native-config',
|
|
25
|
+
'dsh-channels',
|
|
26
|
+
'dsh-proxy',
|
|
27
|
+
'dsh-statistics',
|
|
28
|
+
'dsh-native-logs'
|
|
21
29
|
]);
|
|
22
30
|
|
|
23
31
|
const PATH_RESOLVER_IDS = new Set([
|
|
@@ -26,7 +34,8 @@ const PATH_RESOLVER_IDS = new Set([
|
|
|
26
34
|
'codex',
|
|
27
35
|
'gemini',
|
|
28
36
|
'opencode',
|
|
29
|
-
'omp'
|
|
37
|
+
'omp',
|
|
38
|
+
'dsh'
|
|
30
39
|
]);
|
|
31
40
|
|
|
32
41
|
const API_ROUTE_DESCRIPTOR_SCHEMA = {
|
|
@@ -46,7 +55,31 @@ const API_ROUTE_DESCRIPTOR_SCHEMA = {
|
|
|
46
55
|
const API_ROUTE_METHODS = new Set(['GET', 'POST', 'PUT', 'PATCH', 'DELETE']);
|
|
47
56
|
|
|
48
57
|
const CAPABILITY_OPERATIONS = Object.freeze({
|
|
49
|
-
api: new Set([
|
|
58
|
+
api: new Set([
|
|
59
|
+
'getConfig',
|
|
60
|
+
'getConfigAuthProviders',
|
|
61
|
+
'getConfigCapabilities',
|
|
62
|
+
'getConfigResources',
|
|
63
|
+
'updateConfig',
|
|
64
|
+
'listProfiles',
|
|
65
|
+
'listPlugins',
|
|
66
|
+
'listProfilePlugins',
|
|
67
|
+
'listProfileCapabilities',
|
|
68
|
+
'listProfileMcp',
|
|
69
|
+
'listProfilePrompts',
|
|
70
|
+
'installPlugin',
|
|
71
|
+
'uninstallPlugin',
|
|
72
|
+
'updatePlugin',
|
|
73
|
+
'upsertMcp',
|
|
74
|
+
'deleteMcp',
|
|
75
|
+
'upsertPrompt',
|
|
76
|
+
'deletePrompt',
|
|
77
|
+
'listSkills',
|
|
78
|
+
'getSkill',
|
|
79
|
+
'createSkill',
|
|
80
|
+
'updateSkill',
|
|
81
|
+
'deleteSkill'
|
|
82
|
+
]),
|
|
50
83
|
channels: new Set(['applyToSettings', 'bestForRestore', 'catalogMetadata', 'create', 'current', 'enabled', 'getAuth', 'getAuthQuota', 'list', 'models', 'order', 'poolStatus', 'probeModels', 'remove', 'resetHealth', 'speedTest', 'speedTestAll', 'sync', 'syncLocalAuth', 'update']),
|
|
51
84
|
health: new Set(['healthCheck']),
|
|
52
85
|
hooks: new Set(['getHooks', 'saveHooks', 'testHooks']),
|
|
@@ -102,6 +135,13 @@ const schema = {
|
|
|
102
135
|
}
|
|
103
136
|
},
|
|
104
137
|
resourceTypes: { type: 'object', additionalProperties: { type: 'boolean' } },
|
|
138
|
+
resourceActions: {
|
|
139
|
+
type: 'object',
|
|
140
|
+
additionalProperties: {
|
|
141
|
+
type: 'object',
|
|
142
|
+
additionalProperties: { type: 'boolean' }
|
|
143
|
+
}
|
|
144
|
+
},
|
|
105
145
|
skillActivation: {
|
|
106
146
|
type: 'object',
|
|
107
147
|
additionalProperties: false,
|