@kafca/agentdock 0.1.40 → 0.1.42
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 +9 -0
- package/dist/renderer/assets/{Badge-CmP99fZV.js → Badge-D-WU4kUV.js} +1 -1
- package/dist/renderer/assets/{Chat-BHxpB0Vz.js → Chat-BGkC5tAe.js} +1 -1
- package/dist/renderer/assets/{ChatMarkdown-Cnhe-XvR.js → ChatMarkdown-CfbC1jRd.js} +1 -1
- package/dist/renderer/assets/{Config-CreR5RZX.js → Config-qQb4bX5D.js} +1 -1
- package/dist/renderer/assets/{CronList-OHg6JWsr.js → CronList-CKhggzYk.js} +1 -1
- package/dist/renderer/assets/{Dashboard-C083Q4zC.js → Dashboard-xn6cUy_n.js} +2 -2
- package/dist/renderer/assets/{EmptyState-Br-H8kqG.js → EmptyState-BdKBBUpr.js} +1 -1
- package/dist/renderer/assets/{KnowledgeDetail-DKhVUY4_.js → KnowledgeDetail-Duk8IQP3.js} +1 -1
- package/dist/renderer/assets/{KnowledgeHome-BM3TMxhj.js → KnowledgeHome-BfjX_4Sv.js} +1 -1
- package/dist/renderer/assets/{Logs-debYolKz.js → Logs-Bfq61QMn.js} +1 -1
- package/dist/renderer/assets/{Modal-BIetew5T.js → Modal-B3vlBmBr.js} +1 -1
- package/dist/renderer/assets/{Page-183Y5-ef.js → Page-CPsLOP3z.js} +1 -1
- package/dist/renderer/assets/{ProjectDetail-CB6-zRBY.js → ProjectDetail-D-g46wyF.js} +1 -1
- package/dist/renderer/assets/{ProjectList-BEUflZUB.js → ProjectList-BrQEKDQ8.js} +1 -1
- package/dist/renderer/assets/{Select-CNIQBVMx.js → Select-C4CFMQmF.js} +1 -1
- package/dist/renderer/assets/{SessionChat-CLpfIftJ.js → SessionChat-06Jny5_G.js} +1 -1
- package/dist/renderer/assets/{SessionList-BUwfQcGl.js → SessionList-DPWIUbOg.js} +1 -1
- package/dist/renderer/assets/{ThreadChat-B9EcRcki.js → ThreadChat-BjtU-j9q.js} +1 -1
- package/dist/renderer/assets/{Workspace-D82il8Vz.js → Workspace-BcNmHuJx.js} +1 -1
- package/dist/renderer/assets/{arrow-left-T9D9J6Ln.js → arrow-left-DPzSmidS.js} +1 -1
- package/dist/renderer/assets/{book-open-Bfdr9s70.js → book-open-B0xhoRqZ.js} +1 -1
- package/dist/renderer/assets/{check-CPJsC_C4.js → check-BTJTyd0C.js} +1 -1
- package/dist/renderer/assets/{chevron-down-BDoIQdna.js → chevron-down-B6jJXlhi.js} +1 -1
- package/dist/renderer/assets/{circle-CRGTgPlR.js → circle-qRhJR9qR.js} +1 -1
- package/dist/renderer/assets/{desktop-DJ_OjjxL.js → desktop-DXmXjjUR.js} +1 -1
- package/dist/renderer/assets/{funnel-BISvzz6U.js → funnel-CbYKGTn8.js} +1 -1
- package/dist/renderer/assets/{heart-EllaLuEV.js → heart-DjwWJfkz.js} +1 -1
- package/dist/renderer/assets/{index-YUnN4zTb.js → index-BWmHJRhe.js} +2 -2
- package/dist/renderer/assets/{index-Db87Dhd_.js → index-CyZs_2NJ.js} +1 -1
- package/dist/renderer/assets/{pencil-w4F5pFB6.js → pencil-1dfAivmj.js} +1 -1
- package/dist/renderer/assets/{play-CNY6DepD.js → play-CB3w1G6S.js} +1 -1
- package/dist/renderer/assets/{plug-DnMzECJy.js → plug-Bvep5o3r.js} +1 -1
- package/dist/renderer/assets/{plus-D33HMCG5.js → plus-DJVg9m09.js} +1 -1
- package/dist/renderer/assets/projects-xnW0fTtq.js +1 -0
- package/dist/renderer/assets/{save-B0PXgtN_.js → save-xjJn3qf2.js} +1 -1
- package/dist/renderer/assets/{search-zNtpxpxG.js → search-BK3UrQxM.js} +1 -1
- package/dist/renderer/assets/{server-DIsU-ww0.js → server-Dyd2eXJu.js} +1 -1
- package/dist/renderer/assets/{session-utils-CxQ3KCei.js → session-utils-eXC0020s.js} +1 -1
- package/dist/renderer/assets/{sessions-DFDVZGz-.js → sessions-WLYpkyUt.js} +1 -1
- package/dist/renderer/assets/{shield-check-5hrgmi9Y.js → shield-check-C0N6aWzF.js} +1 -1
- package/dist/renderer/assets/{trash-2-DWftp5eL.js → trash-2-BGMTNJA6.js} +1 -1
- package/dist/renderer/assets/{user-CKjiW1bV.js → user-BcGMLyhu.js} +1 -1
- package/dist/renderer/assets/{wifi-off-DyBtTbdO.js → wifi-off-FhcQx0HK.js} +1 -1
- package/dist/renderer/index.html +1 -1
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-backend.js +27 -39
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-progress.js +25 -0
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-session-coordinator.js +13 -0
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-store.js +7 -0
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-turn-coordinator.js +31 -8
- package/dist-electron/services/local-ai-core/src/acp/local-core-slash-commands.js +28 -0
- package/dist-electron/services/local-ai-core/src/channel/lark/local-core-lark-gateway.js +21 -11
- package/dist-electron/services/local-ai-core/src/channel/lark/post.js +7 -16
- package/dist-electron/services/local-ai-core/src/channel/lark/rendering/markdown.js +94 -0
- package/dist-electron/services/local-ai-core/src/channel/lark/rendering/messages.js +51 -0
- package/dist-electron/services/local-ai-core/src/channel/lark/runtime-state.js +14 -0
- package/dist-electron/services/local-ai-core/src/router/workspace-router.js +40 -4
- package/dist-electron/services/local-ai-core/src/thread/thread-command-service.js +134 -0
- package/dist-electron/tests/electron/plugin-kernel.test.js +26 -0
- package/dist-electron/tests/integration/lark-rendering.test.js +123 -0
- package/dist-electron/tests/integration/local-core-refactor.test.js +335 -4
- package/package.json +1 -1
- package/dist/renderer/assets/projects-DcYpVq_W.js +0 -1
|
@@ -18,8 +18,10 @@ const local_schedule_adapter_js_1 = require("../../services/local-ai-core/src/sc
|
|
|
18
18
|
const local_core_weixin_gateway_js_1 = require("../../services/local-ai-core/src/channel/weixin/local-core-weixin-gateway.js");
|
|
19
19
|
const local_core_lark_gateway_js_1 = require("../../services/local-ai-core/src/channel/lark/local-core-lark-gateway.js");
|
|
20
20
|
const runtime_state_js_1 = require("../../services/local-ai-core/src/channel/lark/runtime-state.js");
|
|
21
|
+
const local_core_acp_backend_js_1 = require("../../services/local-ai-core/src/acp/local-core-acp-backend.js");
|
|
21
22
|
const local_core_acp_turn_coordinator_js_1 = require("../../services/local-ai-core/src/acp/local-core-acp-turn-coordinator.js");
|
|
22
23
|
const local_core_acp_store_js_1 = require("../../services/local-ai-core/src/acp/local-core-acp-store.js");
|
|
24
|
+
const thread_command_service_js_1 = require("../../services/local-ai-core/src/thread/thread-command-service.js");
|
|
23
25
|
const local_core_acp_progress_js_1 = require("../../services/local-ai-core/src/acp/local-core-acp-progress.js");
|
|
24
26
|
const local_core_acp_permission_lifecycle_js_1 = require("../../services/local-ai-core/src/acp/local-core-acp-permission-lifecycle.js");
|
|
25
27
|
const workspace_acp_permissions_js_1 = require("../../services/local-ai-core/src/acp/workspace-acp-permissions.js");
|
|
@@ -35,7 +37,7 @@ function extractLarkCreatedMessage(request) {
|
|
|
35
37
|
}
|
|
36
38
|
function extractLarkCreatedMessageText(msgType, content) {
|
|
37
39
|
if (msgType === 'interactive') {
|
|
38
|
-
return String(content.elements?.[0]?.content || '');
|
|
40
|
+
return String(content.elements?.[0]?.content || content.body?.elements?.[0]?.content || '');
|
|
39
41
|
}
|
|
40
42
|
if (msgType === 'post') {
|
|
41
43
|
return (content.zh_cn?.content || [])
|
|
@@ -1142,6 +1144,92 @@ function findLarkPostMdText(content) {
|
|
|
1142
1144
|
strict_1.default.equal(emitted[0]?.content, '🔧 Terminal');
|
|
1143
1145
|
strict_1.default.equal(session.currentTurn.assistantText, 'done');
|
|
1144
1146
|
});
|
|
1147
|
+
(0, node_test_1.default)('ACP closes assistant message segments at event boundaries without folding them into final', () => {
|
|
1148
|
+
const upserted = [];
|
|
1149
|
+
const emitted = [];
|
|
1150
|
+
const coordinator = new local_core_acp_turn_coordinator_js_1.LocalCoreAcpTurnCoordinator({
|
|
1151
|
+
appendMessage: () => { },
|
|
1152
|
+
upsertMessage: (_threadId, id, _role, content, _kind, _toolCall, bridgeKind) => {
|
|
1153
|
+
upserted.push({ id, content, bridgeKind });
|
|
1154
|
+
},
|
|
1155
|
+
emitBridge: (event) => emitted.push(event),
|
|
1156
|
+
updateRunStatus: () => { },
|
|
1157
|
+
sendRaw: () => true,
|
|
1158
|
+
});
|
|
1159
|
+
const session = {
|
|
1160
|
+
threadId: 'thread-1',
|
|
1161
|
+
bridgeSessionKey: 'session:thread-1',
|
|
1162
|
+
currentRunId: 'run-1',
|
|
1163
|
+
currentTurn: {
|
|
1164
|
+
runId: 'run-1',
|
|
1165
|
+
replyCtx: 'run-1',
|
|
1166
|
+
previewHandle: 'run-1-assistant-preview-1',
|
|
1167
|
+
assistantMessageId: 'run-1-assistant-1',
|
|
1168
|
+
assistantSequence: 1,
|
|
1169
|
+
thoughtPreviewHandle: 'thought-preview-1',
|
|
1170
|
+
thoughtMessageId: 'run-1-thought-1',
|
|
1171
|
+
assistantText: '',
|
|
1172
|
+
rawAssistantText: '',
|
|
1173
|
+
thoughtText: '',
|
|
1174
|
+
typingStarted: true,
|
|
1175
|
+
previewStarted: false,
|
|
1176
|
+
thoughtPreviewStarted: false,
|
|
1177
|
+
pendingToolCalls: {},
|
|
1178
|
+
pendingToolCallOrder: [],
|
|
1179
|
+
toolCallSequence: 0,
|
|
1180
|
+
toolObservations: [],
|
|
1181
|
+
permission: null,
|
|
1182
|
+
},
|
|
1183
|
+
loadReplayMode: false,
|
|
1184
|
+
schedulerJobCreatedByRun: new Map(),
|
|
1185
|
+
};
|
|
1186
|
+
coordinator.handleAgentNotification(session, {
|
|
1187
|
+
method: 'session/update',
|
|
1188
|
+
params: {
|
|
1189
|
+
update: {
|
|
1190
|
+
sessionUpdate: 'agent_message_chunk',
|
|
1191
|
+
content: { type: 'text', text: '我先检查一下' },
|
|
1192
|
+
},
|
|
1193
|
+
},
|
|
1194
|
+
});
|
|
1195
|
+
strict_1.default.deepEqual(emitted, []);
|
|
1196
|
+
strict_1.default.deepEqual(upserted, []);
|
|
1197
|
+
coordinator.handleAgentNotification(session, {
|
|
1198
|
+
method: 'session/update',
|
|
1199
|
+
params: {
|
|
1200
|
+
update: {
|
|
1201
|
+
sessionUpdate: 'tool_call',
|
|
1202
|
+
title: 'Terminal',
|
|
1203
|
+
},
|
|
1204
|
+
},
|
|
1205
|
+
});
|
|
1206
|
+
strict_1.default.deepEqual(upserted, [{
|
|
1207
|
+
id: 'run-1-assistant-1',
|
|
1208
|
+
content: '我先检查一下',
|
|
1209
|
+
bridgeKind: 'assistant',
|
|
1210
|
+
}]);
|
|
1211
|
+
strict_1.default.equal(emitted.length, 1);
|
|
1212
|
+
strict_1.default.equal(emitted[0]?.type, 'reply');
|
|
1213
|
+
strict_1.default.equal(emitted[0]?.content, '我先检查一下');
|
|
1214
|
+
strict_1.default.equal(emitted[0]?.messageId, 'run-1-assistant-1');
|
|
1215
|
+
strict_1.default.equal(emitted[0]?.bridgeKind, 'assistant');
|
|
1216
|
+
strict_1.default.equal(session.currentTurn.assistantText, '');
|
|
1217
|
+
strict_1.default.equal(session.currentTurn.rawAssistantText, '');
|
|
1218
|
+
coordinator.handleAgentNotification(session, {
|
|
1219
|
+
method: 'session/update',
|
|
1220
|
+
params: {
|
|
1221
|
+
update: {
|
|
1222
|
+
sessionUpdate: 'agent_message_chunk',
|
|
1223
|
+
content: { type: 'text', text: '最终回答' },
|
|
1224
|
+
},
|
|
1225
|
+
},
|
|
1226
|
+
});
|
|
1227
|
+
strict_1.default.equal(session.currentTurn.assistantText, '最终回答');
|
|
1228
|
+
strict_1.default.equal(session.currentTurn.rawAssistantText, '最终回答');
|
|
1229
|
+
strict_1.default.equal(upserted.filter((entry) => entry.bridgeKind === 'assistant').length, 1);
|
|
1230
|
+
strict_1.default.equal(emitted.length, 2);
|
|
1231
|
+
strict_1.default.equal(emitted[1]?.bridgeKind, 'tool');
|
|
1232
|
+
});
|
|
1145
1233
|
(0, node_test_1.default)('ACP tool-scoped assistant chunks stay out of final assistant buffer', () => {
|
|
1146
1234
|
const appended = [];
|
|
1147
1235
|
const emitted = [];
|
|
@@ -1237,7 +1325,7 @@ function findLarkPostMdText(content) {
|
|
|
1237
1325
|
});
|
|
1238
1326
|
}
|
|
1239
1327
|
strict_1.default.equal(session.currentTurn.assistantText, '确认删除前需要你确认。');
|
|
1240
|
-
strict_1.default.deepEqual(emitted.map((event) => event.content), [
|
|
1328
|
+
strict_1.default.deepEqual(emitted.map((event) => event.content), []);
|
|
1241
1329
|
});
|
|
1242
1330
|
(0, node_test_1.default)('Hermes ACP assistant chunks strip replay even when stored prior final is already polluted', () => {
|
|
1243
1331
|
const emitted = [];
|
|
@@ -1291,7 +1379,7 @@ function findLarkPostMdText(content) {
|
|
|
1291
1379
|
});
|
|
1292
1380
|
}
|
|
1293
1381
|
strict_1.default.equal(session.currentTurn.assistantText, '已删除 **Sisyphus_介绍.txt**,现在 Text 文件夹是空的了。');
|
|
1294
|
-
strict_1.default.deepEqual(emitted.map((event) => event.content), [
|
|
1382
|
+
strict_1.default.deepEqual(emitted.map((event) => event.content), []);
|
|
1295
1383
|
});
|
|
1296
1384
|
(0, node_test_1.default)('Hermes ACP assistant chunks keep a fresh answer when no replay anchor is present', () => {
|
|
1297
1385
|
const emitted = [];
|
|
@@ -1330,7 +1418,7 @@ function findLarkPostMdText(content) {
|
|
|
1330
1418
|
},
|
|
1331
1419
|
});
|
|
1332
1420
|
strict_1.default.equal(session.currentTurn.assistantText, '已删除文件。');
|
|
1333
|
-
strict_1.default.deepEqual(emitted.map((event) => event.content), [
|
|
1421
|
+
strict_1.default.deepEqual(emitted.map((event) => event.content), []);
|
|
1334
1422
|
});
|
|
1335
1423
|
(0, node_test_1.default)('Hermes ACP progress updates suppress restored tool and thought replay only', () => {
|
|
1336
1424
|
const upserted = [];
|
|
@@ -2029,6 +2117,86 @@ function findLarkPostMdText(content) {
|
|
|
2029
2117
|
strict_1.default.deepEqual(patchedCards, []);
|
|
2030
2118
|
strict_1.default.deepEqual(storedMessageIds, ['lark-msg-1']);
|
|
2031
2119
|
});
|
|
2120
|
+
(0, node_test_1.default)('lark bridge sends completed assistant segments as separate non-final messages', async () => {
|
|
2121
|
+
const createdMessages = [];
|
|
2122
|
+
const patchedCards = [];
|
|
2123
|
+
const storedMessageIds = [];
|
|
2124
|
+
const client = {
|
|
2125
|
+
im: {
|
|
2126
|
+
message: {
|
|
2127
|
+
create: async (request) => {
|
|
2128
|
+
const messageId = `lark-msg-${createdMessages.length + 1}`;
|
|
2129
|
+
const message = extractLarkCreatedMessage(request);
|
|
2130
|
+
createdMessages.push({
|
|
2131
|
+
messageId,
|
|
2132
|
+
msgType: message.msgType,
|
|
2133
|
+
text: message.text,
|
|
2134
|
+
content: message.content,
|
|
2135
|
+
});
|
|
2136
|
+
return { data: { message_id: messageId } };
|
|
2137
|
+
},
|
|
2138
|
+
patch: async (request) => {
|
|
2139
|
+
const card = JSON.parse(String(request.data.content || '{}'));
|
|
2140
|
+
patchedCards.push({
|
|
2141
|
+
messageId: String(request.path.message_id || ''),
|
|
2142
|
+
text: String(card.elements?.[0]?.content || ''),
|
|
2143
|
+
});
|
|
2144
|
+
},
|
|
2145
|
+
},
|
|
2146
|
+
},
|
|
2147
|
+
};
|
|
2148
|
+
const gateway = new local_core_lark_gateway_js_1.LocalCoreLarkGateway({
|
|
2149
|
+
store: {
|
|
2150
|
+
getPlatformThreadBinding: () => ({
|
|
2151
|
+
workspace_id: 'default',
|
|
2152
|
+
platform: 'lark',
|
|
2153
|
+
chat_id: 'chat-1',
|
|
2154
|
+
platform_user_id: 'user-1',
|
|
2155
|
+
thread_id: 'thread-1',
|
|
2156
|
+
last_platform_message_id: null,
|
|
2157
|
+
}),
|
|
2158
|
+
updatePlatformThreadMessageId: (_workspaceId, _chatId, _platformUserId, messageId) => {
|
|
2159
|
+
storedMessageIds.push(messageId);
|
|
2160
|
+
},
|
|
2161
|
+
},
|
|
2162
|
+
readConfig: async () => null,
|
|
2163
|
+
getWorkspaceRouter: () => ({}),
|
|
2164
|
+
eventBus: { emit: () => { }, on: () => () => { } },
|
|
2165
|
+
});
|
|
2166
|
+
const internals = gateway;
|
|
2167
|
+
internals.runtime.set('default', {
|
|
2168
|
+
workspaceId: 'default',
|
|
2169
|
+
enabled: true,
|
|
2170
|
+
status: 'running',
|
|
2171
|
+
connected: true,
|
|
2172
|
+
appId: 'app-1',
|
|
2173
|
+
client,
|
|
2174
|
+
});
|
|
2175
|
+
internals.threadRouting.set('session:thread-1', {
|
|
2176
|
+
workspaceId: 'default',
|
|
2177
|
+
platformUserId: 'user-1',
|
|
2178
|
+
chatId: 'chat-1',
|
|
2179
|
+
threadId: 'thread-1',
|
|
2180
|
+
});
|
|
2181
|
+
await gateway.onBridgeEvent({
|
|
2182
|
+
type: 'reply',
|
|
2183
|
+
sessionKey: 'session:thread-1',
|
|
2184
|
+
replyCtx: 'run-1',
|
|
2185
|
+
messageId: 'run-1-assistant-1',
|
|
2186
|
+
bridgeKind: 'assistant',
|
|
2187
|
+
content: '我先检查一下',
|
|
2188
|
+
});
|
|
2189
|
+
await gateway.onBridgeEvent({
|
|
2190
|
+
type: 'reply',
|
|
2191
|
+
sessionKey: 'session:thread-1',
|
|
2192
|
+
replyCtx: 'run-1',
|
|
2193
|
+
content: '最终回答',
|
|
2194
|
+
});
|
|
2195
|
+
strict_1.default.deepEqual(createdMessages.map((message) => message.msgType), ['post', 'post']);
|
|
2196
|
+
strict_1.default.deepEqual(createdMessages.map((message) => message.text), ['我先检查一下', '最终回答']);
|
|
2197
|
+
strict_1.default.deepEqual(patchedCards, []);
|
|
2198
|
+
strict_1.default.deepEqual(storedMessageIds, ['lark-msg-2']);
|
|
2199
|
+
});
|
|
2032
2200
|
(0, node_test_1.default)('lark bridge creates final replies without patching prior final messages', async () => {
|
|
2033
2201
|
const createdMessages = [];
|
|
2034
2202
|
const patchedCards = [];
|
|
@@ -3552,6 +3720,94 @@ function findLarkPostMdText(content) {
|
|
|
3552
3720
|
strict_1.default.equal((0, local_core_slash_commands_js_1.formatAgentMode)('bypassPermissions'), 'yolo');
|
|
3553
3721
|
strict_1.default.match((0, local_core_slash_commands_js_1.modeHelpText)('bypassPermissions'), /当前模式:yolo/);
|
|
3554
3722
|
});
|
|
3723
|
+
(0, node_test_1.default)('slash agent commands normalize aliases and expose current help', () => {
|
|
3724
|
+
strict_1.default.deepEqual((0, local_core_slash_commands_js_1.parseSlashCommand)('/agent use Pi'), { name: 'agent', args: ['use', 'Pi'] });
|
|
3725
|
+
strict_1.default.equal((0, local_core_slash_commands_js_1.normalizeAgentCommandTarget)('Pi'), 'pi');
|
|
3726
|
+
strict_1.default.equal((0, local_core_slash_commands_js_1.normalizeAgentCommandTarget)('claude'), 'claudecode');
|
|
3727
|
+
strict_1.default.equal((0, local_core_slash_commands_js_1.normalizeAgentCommandTarget)('claude-code'), 'claudecode');
|
|
3728
|
+
strict_1.default.match((0, local_core_slash_commands_js_1.agentHelpText)({
|
|
3729
|
+
currentAgent: 'pi',
|
|
3730
|
+
defaultAgent: 'codex',
|
|
3731
|
+
availableAgents: ['codex', 'pi', 'hermes'],
|
|
3732
|
+
}), /当前线程 Agent:pi/);
|
|
3733
|
+
});
|
|
3734
|
+
(0, node_test_1.default)('thread command service handles local slash commands without ACP transport', async () => {
|
|
3735
|
+
const row = {
|
|
3736
|
+
id: 'thread-1',
|
|
3737
|
+
workspace_id: 'workspace-a',
|
|
3738
|
+
session_id: 'session-1',
|
|
3739
|
+
bridge_session_key: 'bridge-1',
|
|
3740
|
+
title: 'Command service',
|
|
3741
|
+
agent_type: 'codex',
|
|
3742
|
+
created_at: '2026-05-11T00:00:00.000Z',
|
|
3743
|
+
updated_at: '2026-05-11T00:00:00.000Z',
|
|
3744
|
+
history_count: 0,
|
|
3745
|
+
excerpt: '',
|
|
3746
|
+
acp_session_id: null,
|
|
3747
|
+
acp_supports_load: 0,
|
|
3748
|
+
agent_mode: 'default',
|
|
3749
|
+
};
|
|
3750
|
+
const audits = [];
|
|
3751
|
+
const syncedModes = [];
|
|
3752
|
+
const closedThreads = [];
|
|
3753
|
+
const service = new thread_command_service_js_1.ThreadCommandService({
|
|
3754
|
+
getThreadRow: () => row,
|
|
3755
|
+
updateThreadAgentMode: (_threadId, mode) => {
|
|
3756
|
+
row.agent_mode = mode;
|
|
3757
|
+
},
|
|
3758
|
+
updateThreadAgentType: (_threadId, agentType) => {
|
|
3759
|
+
row.agent_type = agentType;
|
|
3760
|
+
},
|
|
3761
|
+
getLatestRunForThread: () => undefined,
|
|
3762
|
+
createAuditEvent: (input) => {
|
|
3763
|
+
audits.push(input);
|
|
3764
|
+
},
|
|
3765
|
+
getAgentTypes: () => ['codex', 'pi', 'hermes', 'claudecode'],
|
|
3766
|
+
setThreadMode: async (_threadId, mode) => {
|
|
3767
|
+
syncedModes.push(mode);
|
|
3768
|
+
},
|
|
3769
|
+
closeThreadSession: (threadId) => {
|
|
3770
|
+
closedThreads.push(threadId);
|
|
3771
|
+
},
|
|
3772
|
+
});
|
|
3773
|
+
strict_1.default.deepEqual(await service.execute({
|
|
3774
|
+
threadId: row.id,
|
|
3775
|
+
workspaceId: row.workspace_id,
|
|
3776
|
+
content: '/not-local',
|
|
3777
|
+
defaultAgentType: 'codex',
|
|
3778
|
+
}), { handled: false, displayText: '' });
|
|
3779
|
+
const modeResult = await service.execute({
|
|
3780
|
+
threadId: row.id,
|
|
3781
|
+
workspaceId: row.workspace_id,
|
|
3782
|
+
content: '/mode yolo',
|
|
3783
|
+
defaultAgentType: 'codex',
|
|
3784
|
+
});
|
|
3785
|
+
strict_1.default.equal(modeResult.handled, true);
|
|
3786
|
+
strict_1.default.equal(row.agent_mode, 'bypassPermissions');
|
|
3787
|
+
strict_1.default.deepEqual(syncedModes, ['bypassPermissions']);
|
|
3788
|
+
strict_1.default.equal(audits.at(-1)?.type, 'permission.changed');
|
|
3789
|
+
const agentResult = await service.execute({
|
|
3790
|
+
threadId: row.id,
|
|
3791
|
+
workspaceId: row.workspace_id,
|
|
3792
|
+
content: '/agent use pi',
|
|
3793
|
+
defaultAgentType: 'codex',
|
|
3794
|
+
});
|
|
3795
|
+
strict_1.default.equal(agentResult.handled, true);
|
|
3796
|
+
strict_1.default.equal(row.agent_type, 'pi');
|
|
3797
|
+
strict_1.default.match(agentResult.displayText, /已将当前线程 Agent 切换为 pi/);
|
|
3798
|
+
strict_1.default.deepEqual(closedThreads, ['thread-1']);
|
|
3799
|
+
strict_1.default.equal(audits.at(-1)?.type, 'agent.changed');
|
|
3800
|
+
const resetResult = await service.execute({
|
|
3801
|
+
threadId: row.id,
|
|
3802
|
+
workspaceId: row.workspace_id,
|
|
3803
|
+
content: '/agent reset',
|
|
3804
|
+
defaultAgentType: 'codex',
|
|
3805
|
+
});
|
|
3806
|
+
strict_1.default.equal(resetResult.handled, true);
|
|
3807
|
+
strict_1.default.equal(row.agent_type, 'codex');
|
|
3808
|
+
strict_1.default.match(resetResult.displayText, /回到默认 Agent:codex/);
|
|
3809
|
+
strict_1.default.deepEqual(closedThreads, ['thread-1', 'thread-1']);
|
|
3810
|
+
});
|
|
3555
3811
|
(0, node_test_1.default)('thread agent mode persists with thread state', () => {
|
|
3556
3812
|
const dir = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'agentdock-mode-'));
|
|
3557
3813
|
try {
|
|
@@ -3568,6 +3824,81 @@ function findLarkPostMdText(content) {
|
|
|
3568
3824
|
(0, node_fs_1.rmSync)(dir, { recursive: true, force: true });
|
|
3569
3825
|
}
|
|
3570
3826
|
});
|
|
3827
|
+
(0, node_test_1.default)('thread agent type persists and clears stale ACP session state', () => {
|
|
3828
|
+
const dir = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'agentdock-agent-type-'));
|
|
3829
|
+
try {
|
|
3830
|
+
const store = new local_core_acp_store_js_1.LocalCoreAcpStore(dir);
|
|
3831
|
+
const thread = store.createThread('workspace-a', 'Agent test', 'codex');
|
|
3832
|
+
store.updateThreadSession(thread.id, 'old-session', true);
|
|
3833
|
+
store.updateThreadAgentType(thread.id, 'pi');
|
|
3834
|
+
const row = store.getThreadRow(thread.id);
|
|
3835
|
+
strict_1.default.equal(row?.agent_type, 'pi');
|
|
3836
|
+
strict_1.default.equal(row?.acp_session_id, null);
|
|
3837
|
+
strict_1.default.equal(row?.acp_supports_load, 0);
|
|
3838
|
+
store.close();
|
|
3839
|
+
}
|
|
3840
|
+
finally {
|
|
3841
|
+
(0, node_fs_1.rmSync)(dir, { recursive: true, force: true });
|
|
3842
|
+
}
|
|
3843
|
+
});
|
|
3844
|
+
(0, node_test_1.default)('slash agent commands switch and reset the current thread agent', async () => {
|
|
3845
|
+
const dir = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'agentdock-agent-command-'));
|
|
3846
|
+
try {
|
|
3847
|
+
const store = new local_core_acp_store_js_1.LocalCoreAcpStore(dir);
|
|
3848
|
+
const thread = store.createThread('workspace-a', 'Agent command', 'codex');
|
|
3849
|
+
const bridgeEvents = [];
|
|
3850
|
+
const acceptedMessages = [];
|
|
3851
|
+
const backend = new local_core_acp_backend_js_1.LocalCoreAcpBackend({
|
|
3852
|
+
store,
|
|
3853
|
+
runThreadMap: new Map(),
|
|
3854
|
+
emitBridge: (event) => bridgeEvents.push(event),
|
|
3855
|
+
eventBus: {
|
|
3856
|
+
emit: (event) => acceptedMessages.push(event),
|
|
3857
|
+
on: () => () => { },
|
|
3858
|
+
},
|
|
3859
|
+
scheduler: {
|
|
3860
|
+
createJob: async () => { throw new Error('not used'); },
|
|
3861
|
+
listJobsForThread: async () => [],
|
|
3862
|
+
deleteJob: async () => { },
|
|
3863
|
+
},
|
|
3864
|
+
getAgentTypes: () => ['codex', 'pi', 'hermes', 'claudecode'],
|
|
3865
|
+
});
|
|
3866
|
+
const config = {
|
|
3867
|
+
workspaceId: 'workspace-a',
|
|
3868
|
+
agentType: 'codex',
|
|
3869
|
+
workDir: dir,
|
|
3870
|
+
command: process.execPath,
|
|
3871
|
+
args: ['-e', ''],
|
|
3872
|
+
env: {},
|
|
3873
|
+
model: '',
|
|
3874
|
+
};
|
|
3875
|
+
strict_1.default.deepEqual(await backend.sendThreadMessage(thread.id, '/agent use pi', config), { runId: '' });
|
|
3876
|
+
strict_1.default.equal(store.getThreadRow(thread.id)?.agent_type, 'pi');
|
|
3877
|
+
strict_1.default.match(store.getThread(thread.id, []).messages.at(-1)?.content || '', /已将当前线程 Agent 切换为 pi/);
|
|
3878
|
+
strict_1.default.equal(bridgeEvents.at(-2)?.type, 'reply');
|
|
3879
|
+
strict_1.default.match(bridgeEvents.at(-2)?.content || '', /后续消息将使用 pi 处理/);
|
|
3880
|
+
await backend.sendThreadMessage(thread.id, '/agent current', config);
|
|
3881
|
+
strict_1.default.match(store.getThread(thread.id, []).messages.at(-1)?.content || '', /来源:线程设置/);
|
|
3882
|
+
await backend.sendThreadMessage(thread.id, '/agent use claude', config);
|
|
3883
|
+
strict_1.default.equal(store.getThreadRow(thread.id)?.agent_type, 'claudecode');
|
|
3884
|
+
await backend.sendThreadMessage(thread.id, '/agent reset', config);
|
|
3885
|
+
strict_1.default.equal(store.getThreadRow(thread.id)?.agent_type, 'codex');
|
|
3886
|
+
strict_1.default.match(store.getThread(thread.id, []).messages.at(-1)?.content || '', /回到默认 Agent:codex/);
|
|
3887
|
+
await backend.sendThreadMessage(thread.id, '/agent use missing-agent', config);
|
|
3888
|
+
strict_1.default.equal(store.getThreadRow(thread.id)?.agent_type, 'codex');
|
|
3889
|
+
strict_1.default.match(store.getThread(thread.id, []).messages.at(-1)?.content || '', /未知 Agent:missing-agent/);
|
|
3890
|
+
store.updateRun('run-active', thread.id, 'running');
|
|
3891
|
+
await backend.sendThreadMessage(thread.id, '/agent use hermes', config);
|
|
3892
|
+
strict_1.default.equal(store.getThreadRow(thread.id)?.agent_type, 'hermes');
|
|
3893
|
+
strict_1.default.match(store.getThread(thread.id, []).messages.at(-1)?.content || '', /下一轮开始生效/);
|
|
3894
|
+
strict_1.default.ok(acceptedMessages.length >= 8);
|
|
3895
|
+
backend.close();
|
|
3896
|
+
store.close();
|
|
3897
|
+
}
|
|
3898
|
+
finally {
|
|
3899
|
+
(0, node_fs_1.rmSync)(dir, { recursive: true, force: true });
|
|
3900
|
+
}
|
|
3901
|
+
});
|
|
3571
3902
|
(0, node_test_1.default)('scheduled conversation executor uses execution policy hooks around a thread run', async () => {
|
|
3572
3903
|
const calls = [];
|
|
3573
3904
|
let runtimeEnv;
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{z as t}from"./index-YUnN4zTb.js";const e=()=>t.get("/projects"),r=o=>t.get(`/projects/${o}`);export{r as g,e as l};
|