@kafca/agentdock 0.1.47 → 0.1.49
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 +6 -0
- package/dist/renderer/assets/{Badge-BYREM3t3.js → Badge-DXjx3T4U.js} +1 -1
- package/dist/renderer/assets/{Chat-Dtb5X7sB.js → Chat-BdLcSBda.js} +1 -1
- package/dist/renderer/assets/{ChatMarkdown-_slLloCh.js → ChatMarkdown-CSc8mfpv.js} +1 -1
- package/dist/renderer/assets/{Config-pHichs7H.js → Config-b5NK6ZGX.js} +2 -2
- package/dist/renderer/assets/{CronList-CJQMeCjz.js → CronList-B4vdtNHN.js} +1 -1
- package/dist/renderer/assets/{Dashboard-CY77Imde.js → Dashboard-BItoWTOa.js} +2 -2
- package/dist/renderer/assets/{EmptyState-DCqmct2y.js → EmptyState-DUDyUsLL.js} +1 -1
- package/dist/renderer/assets/{KnowledgeDetail-DFrxa-pv.js → KnowledgeDetail-WWH6KxiG.js} +2 -2
- package/dist/renderer/assets/{KnowledgeHome-DL-vAfrH.js → KnowledgeHome-Dn-NmRxu.js} +2 -2
- package/dist/renderer/assets/{Logs-jw9Uv590.js → Logs-4zMv4FvK.js} +1 -1
- package/dist/renderer/assets/{Modal-ChSm7tk6.js → Modal-BYTZpyD2.js} +3 -3
- package/dist/renderer/assets/{MonitorList-DrEwyS71.js → MonitorList-DzcwVuQO.js} +1 -1
- package/dist/renderer/assets/{Page-DhD-zgMU.js → Page-B0lex3w0.js} +1 -1
- package/dist/renderer/assets/{ProjectDetail-BVSjpfpL.js → ProjectDetail-zhmSLySm.js} +2 -2
- package/dist/renderer/assets/{ProjectList-CHGbTJjk.js → ProjectList-DZr7agnE.js} +1 -1
- package/dist/renderer/assets/{Select-rHs9CSam.js → Select-CybeCWXZ.js} +1 -1
- package/dist/renderer/assets/SessionChat-DfsXUkfX.js +1 -0
- package/dist/renderer/assets/{SessionList-Mr1uAnRW.js → SessionList-BHzY2T_K.js} +1 -1
- package/dist/renderer/assets/ThreadChat-BB_Y2SLO.js +28 -0
- package/dist/renderer/assets/{Workspace-MRRg8ndJ.js → Workspace-COip3Zy2.js} +1 -1
- package/dist/renderer/assets/{arrow-left-BU2NB2LA.js → arrow-left-SFlZE8SW.js} +1 -1
- package/dist/renderer/assets/{book-open-D-TGvWwa.js → book-open-CENFRKvo.js} +1 -1
- package/dist/renderer/assets/{bot-IYNh8tH5.js → bot-DeqZUVXX.js} +1 -1
- package/dist/renderer/assets/{check-CCZ0JO_S.js → check-BNBksd9W.js} +1 -1
- package/dist/renderer/assets/{chevron-down-00bRZi15.js → chevron-down-BOhwopXd.js} +1 -1
- package/dist/renderer/assets/{circle-CpQ8x4k_.js → circle-BTT_e1ZT.js} +1 -1
- package/dist/renderer/assets/{desktop-D0k2aGSj.js → desktop-D88Gquih.js} +1 -1
- package/dist/renderer/assets/{funnel-UbcrCBCp.js → funnel-Btin4gwi.js} +1 -1
- package/dist/renderer/assets/{heart-DvLsV7tL.js → heart-BCqqkImr.js} +1 -1
- package/dist/renderer/assets/index-CjCuR6DI.css +11 -0
- package/dist/renderer/assets/{index-B2L4G-b_.js → index-DvKeLUQ8.js} +2 -2
- package/dist/renderer/assets/{index-dy-g2Bh4.js → index-on-scaWG.js} +9 -9
- package/dist/renderer/assets/{pencil-qBYOgW5M.js → pencil-BHu_seP7.js} +1 -1
- package/dist/renderer/assets/{play-Dn6b4AGj.js → play-BoIfwVcE.js} +1 -1
- package/dist/renderer/assets/{plus-CaApUwEm.js → plus-_5sDk2H8.js} +1 -1
- package/dist/renderer/assets/projects-BR_Y3Dov.js +1 -0
- package/dist/renderer/assets/{save-CN6yvTfD.js → save-Bn9HUt7T.js} +1 -1
- package/dist/renderer/assets/{search-Dn2MxYiO.js → search-BOU1rpMw.js} +1 -1
- package/dist/renderer/assets/{server-DpcVLHeh.js → server-BKF47usT.js} +1 -1
- package/dist/renderer/assets/{session-utils-DnD2Q_y1.js → session-utils-B4vjXX1q.js} +1 -1
- package/dist/renderer/assets/{sessions-eK5D4FLt.js → sessions-CtFBPvOB.js} +1 -1
- package/dist/renderer/assets/{shield-check-DSSJkacw.js → shield-check-Q1O3wIT4.js} +1 -1
- package/dist/renderer/assets/{trash-2-DmYJlEvO.js → trash-2-CANqI4Db.js} +1 -1
- package/dist/renderer/assets/{user-Cvf_uiyQ.js → user-DTURDktb.js} +1 -1
- package/dist/renderer/assets/{wifi-off-CCTloj-V.js → wifi-off-YfCo8Dbk.js} +1 -1
- package/dist/renderer/index.html +2 -2
- package/dist-electron/packages/core-sdk/src/index.js +4 -0
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-session-coordinator.js +51 -6
- package/dist-electron/services/local-ai-core/src/acp/store/local-core-acp-store.js +3 -0
- package/dist-electron/services/local-ai-core/src/acp/store/platform-store.js +13 -5
- package/dist-electron/services/local-ai-core/src/acp/store/schema.js +1 -0
- package/dist-electron/services/local-ai-core/src/acp/store/thread-store.js +3 -0
- package/dist-electron/services/local-ai-core/src/channel/shared/base-channel-gateway.js +4 -1
- package/dist-electron/services/local-ai-core/src/channel/shared/session-command-runtime.js +14 -3
- package/dist-electron/services/local-ai-core/src/router/workspace-router.js +10 -3
- package/dist-electron/services/local-ai-core/src/runtime/handlers/thread-handler.js +4 -0
- package/dist-electron/services/local-ai-core/src/runtime/server-routes.js +3 -0
- package/dist-electron/services/local-ai-core/src/scheduler/channel-execution-policy.js +3 -1
- package/dist-electron/services/local-ai-core/src/scheduler/lark-execution-policies.js +2 -1
- package/dist-electron/services/local-ai-core/src/scheduler/lark-schedule-adapter.js +10 -1
- package/dist-electron/services/local-ai-core/src/scheduler/weixin-execution-policies.js +2 -1
- package/dist-electron/services/local-ai-core/src/scheduler/weixin-schedule-adapter.js +10 -1
- package/dist-electron/services/local-ai-core/src/thread/thread-command-service.js +23 -2
- package/dist-electron/services/local-ai-core/src/thread/thread-slash-command-dispatcher.js +1 -0
- package/dist-electron/src/pages/Threads/thread-chat-model.js +2 -0
- package/dist-electron/tests/electron/workspace-task-store.test.js +22 -3
- package/dist-electron/tests/integration/local-core-refactor.test.js +253 -0
- package/dist-electron/tests/integration/local-core-routes.test.js +45 -0
- package/package.json +2 -2
- package/dist/renderer/assets/SessionChat-CDc2FNMA.js +0 -1
- package/dist/renderer/assets/ThreadChat-Detu5UfN.js +0 -23
- package/dist/renderer/assets/index-CO4fGqmv.css +0 -11
- package/dist/renderer/assets/projects-BwF5RlNV.js +0 -1
|
@@ -585,7 +585,7 @@ const env_utils_js_1 = require("../../services/local-ai-core/src/runtime/env-uti
|
|
|
585
585
|
process.env.HOME = '/home/agentdock-test';
|
|
586
586
|
try {
|
|
587
587
|
const existingPath = ['/usr/bin', '/bin'].join(node_path_1.delimiter);
|
|
588
|
-
const path = (0, local_core_acp_session_coordinator_js_1.buildAgentPath)(existingPath, '/opt/agentdock/bin');
|
|
588
|
+
const path = (0, local_core_acp_session_coordinator_js_1.buildAgentPath)(existingPath, '/opt/agentdock/bin', { pathExists: () => false });
|
|
589
589
|
const expectedEntries = process.platform === 'win32'
|
|
590
590
|
? ['/opt/agentdock/bin', '/usr/bin', '/bin']
|
|
591
591
|
: ['/opt/agentdock/bin', '/home/agentdock-test/.local/bin', '/home/agentdock-test/bin', '/usr/bin', '/bin'];
|
|
@@ -600,6 +600,21 @@ const env_utils_js_1 = require("../../services/local-ai-core/src/runtime/env-uti
|
|
|
600
600
|
}
|
|
601
601
|
}
|
|
602
602
|
});
|
|
603
|
+
(0, node_test_1.default)('ACP runtime PATH adds Git Bash bin when Windows PATH only has Git cmd', () => {
|
|
604
|
+
const existingPath = [
|
|
605
|
+
'C:\\Windows\\System32',
|
|
606
|
+
'D:\\Program Files\\Git\\cmd',
|
|
607
|
+
].join(';');
|
|
608
|
+
const path = (0, local_core_acp_session_coordinator_js_1.buildAgentPath)(existingPath, undefined, {
|
|
609
|
+
platform: 'win32',
|
|
610
|
+
pathExists: (candidate) => candidate === 'D:\\Program Files\\Git\\bin\\bash.exe',
|
|
611
|
+
});
|
|
612
|
+
strict_1.default.equal(path, [
|
|
613
|
+
'D:\\Program Files\\Git\\bin',
|
|
614
|
+
'C:\\Windows\\System32',
|
|
615
|
+
'D:\\Program Files\\Git\\cmd',
|
|
616
|
+
].join(';'));
|
|
617
|
+
});
|
|
603
618
|
(0, node_test_1.default)('ACP runtime reads Windows Path env regardless of key casing', () => {
|
|
604
619
|
strict_1.default.equal((0, env_utils_js_1.getPathEnv)({ Path: 'C:\\Windows\\System32;C:\\Program Files\\nodejs' }), 'C:\\Windows\\System32;C:\\Program Files\\nodejs');
|
|
605
620
|
strict_1.default.equal((0, env_utils_js_1.getPathEnv)({ PATH: '/usr/bin:/bin' }), '/usr/bin:/bin');
|
|
@@ -635,8 +650,9 @@ const env_utils_js_1 = require("../../services/local-ai-core/src/runtime/env-uti
|
|
|
635
650
|
});
|
|
636
651
|
(0, node_test_1.default)('ACP scheduled session can override permission mode without changing thread mode', async () => {
|
|
637
652
|
const userDataPath = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'scheduler-permission-mode-'));
|
|
653
|
+
let store = null;
|
|
638
654
|
try {
|
|
639
|
-
|
|
655
|
+
store = new local_core_acp_store_js_1.LocalCoreAcpStore(userDataPath);
|
|
640
656
|
const thread = store.createThread('workspace-a', 'Thread');
|
|
641
657
|
const capturedSessionNewParams = [];
|
|
642
658
|
let closeCount = 0;
|
|
@@ -702,13 +718,15 @@ const env_utils_js_1 = require("../../services/local-ai-core/src/runtime/env-uti
|
|
|
702
718
|
});
|
|
703
719
|
}
|
|
704
720
|
finally {
|
|
721
|
+
store?.close();
|
|
705
722
|
(0, node_fs_1.rmSync)(userDataPath, { recursive: true, force: true });
|
|
706
723
|
}
|
|
707
724
|
});
|
|
708
725
|
(0, node_test_1.default)('ACP sandbox sessions use container workspace cwd', async () => {
|
|
709
726
|
const userDataPath = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'sandbox-session-cwd-'));
|
|
727
|
+
let store = null;
|
|
710
728
|
try {
|
|
711
|
-
|
|
729
|
+
store = new local_core_acp_store_js_1.LocalCoreAcpStore(userDataPath);
|
|
712
730
|
const thread = store.createThread('workspace-a', 'Thread');
|
|
713
731
|
let sessionNewParams;
|
|
714
732
|
const coordinator = new local_core_acp_session_coordinator_js_1.LocalCoreAcpSessionCoordinator({
|
|
@@ -779,6 +797,7 @@ const env_utils_js_1 = require("../../services/local-ai-core/src/runtime/env-uti
|
|
|
779
797
|
strict_1.default.equal(sessionNewParams?.cwd, '/workspace');
|
|
780
798
|
}
|
|
781
799
|
finally {
|
|
800
|
+
store?.close();
|
|
782
801
|
(0, node_fs_1.rmSync)(userDataPath, { recursive: true, force: true });
|
|
783
802
|
}
|
|
784
803
|
});
|
|
@@ -313,11 +313,15 @@ const thread_slash_command_dispatcher_js_1 = require("../../services/local-ai-co
|
|
|
313
313
|
try {
|
|
314
314
|
const store = new local_core_acp_store_js_1.LocalCoreAcpStore(dir);
|
|
315
315
|
const thread = store.createThread('workspace-a', 'Mode test', 'claudecode');
|
|
316
|
+
strict_1.default.equal(thread.agentMode, 'default');
|
|
316
317
|
strict_1.default.equal(store.getThreadRow(thread.id)?.agent_mode, 'default');
|
|
317
318
|
const inheritedThread = store.createThread('workspace-a', 'Inherited mode test', 'claudecode', 'bypassPermissions');
|
|
319
|
+
strict_1.default.equal(inheritedThread.agentMode, 'bypassPermissions');
|
|
318
320
|
strict_1.default.equal(store.getThreadRow(inheritedThread.id)?.agent_mode, 'bypassPermissions');
|
|
319
321
|
store.updateThreadAgentMode(thread.id, 'bypassPermissions');
|
|
320
322
|
strict_1.default.equal(store.getThreadRow(thread.id)?.agent_mode, 'bypassPermissions');
|
|
323
|
+
strict_1.default.equal(store.getThread(thread.id, []).agentMode, 'bypassPermissions');
|
|
324
|
+
strict_1.default.equal(store.listThreadSummaries('workspace-a').find((item) => item.id === thread.id)?.agentMode, 'bypassPermissions');
|
|
321
325
|
store.close();
|
|
322
326
|
}
|
|
323
327
|
finally {
|
|
@@ -854,6 +858,82 @@ const thread_slash_command_dispatcher_js_1 = require("../../services/local-ai-co
|
|
|
854
858
|
policy.afterExecute?.(target, job);
|
|
855
859
|
strict_1.default.equal(unregisteredBridge, true);
|
|
856
860
|
});
|
|
861
|
+
(0, node_test_1.default)('lark side-thread execution policy applies preferred agent when creating a new scheduled thread', async () => {
|
|
862
|
+
const job = {
|
|
863
|
+
id: 'job-1',
|
|
864
|
+
workspaceId: '知识库',
|
|
865
|
+
platform: 'lark',
|
|
866
|
+
route: { type: 'channel.chat', channelId: 'chat-1', participantId: 'user-1', threadId: 'thread-origin' },
|
|
867
|
+
executionMode: 'side-thread',
|
|
868
|
+
triggerType: 'cron',
|
|
869
|
+
cronExpr: '*/2 * * * *',
|
|
870
|
+
promptTemplate: 'ping',
|
|
871
|
+
description: 'two-minute ping',
|
|
872
|
+
enabled: true,
|
|
873
|
+
concurrencyPolicy: 'skip_if_running',
|
|
874
|
+
createdAt: '2026-04-22T06:00:00.000Z',
|
|
875
|
+
updatedAt: '2026-04-22T06:00:00.000Z',
|
|
876
|
+
};
|
|
877
|
+
const createThreadCalls = [];
|
|
878
|
+
const policy = (0, lark_execution_policies_js_1.createLarkExecutionPolicy)(job, {
|
|
879
|
+
store: {},
|
|
880
|
+
workspaceRouter: {
|
|
881
|
+
getThreadSessionKey: (threadId) => `session:${threadId}`,
|
|
882
|
+
listThreads: async () => [],
|
|
883
|
+
createThread: async (workspaceId, title, agentType) => {
|
|
884
|
+
createThreadCalls.push({ workspaceId, title: title || '', agentType });
|
|
885
|
+
return { id: 'thread-new' };
|
|
886
|
+
},
|
|
887
|
+
},
|
|
888
|
+
getChannelRuntime: () => ({
|
|
889
|
+
registerScheduledThreadBridge: () => () => { },
|
|
890
|
+
}),
|
|
891
|
+
}, async () => 'thread-origin', () => 'claudecode');
|
|
892
|
+
const target = await policy.resolveTarget(job);
|
|
893
|
+
strict_1.default.equal(target.threadId, 'thread-new');
|
|
894
|
+
strict_1.default.equal(createThreadCalls.length, 1);
|
|
895
|
+
strict_1.default.deepEqual(createThreadCalls[0], {
|
|
896
|
+
workspaceId: '知识库',
|
|
897
|
+
title: '[Scheduled:Lark] two-minute ping',
|
|
898
|
+
agentType: 'claudecode',
|
|
899
|
+
});
|
|
900
|
+
});
|
|
901
|
+
(0, node_test_1.default)('lark side-thread execution policy falls back to workspace default when no preferred agent is set', async () => {
|
|
902
|
+
const job = {
|
|
903
|
+
id: 'job-1',
|
|
904
|
+
workspaceId: '知识库',
|
|
905
|
+
platform: 'lark',
|
|
906
|
+
route: { type: 'channel.chat', channelId: 'chat-1', participantId: 'user-1', threadId: 'thread-origin' },
|
|
907
|
+
executionMode: 'side-thread',
|
|
908
|
+
triggerType: 'cron',
|
|
909
|
+
cronExpr: '*/2 * * * *',
|
|
910
|
+
promptTemplate: 'ping',
|
|
911
|
+
description: 'two-minute ping',
|
|
912
|
+
enabled: true,
|
|
913
|
+
concurrencyPolicy: 'skip_if_running',
|
|
914
|
+
createdAt: '2026-04-22T06:00:00.000Z',
|
|
915
|
+
updatedAt: '2026-04-22T06:00:00.000Z',
|
|
916
|
+
};
|
|
917
|
+
const createThreadCalls = [];
|
|
918
|
+
const policy = (0, lark_execution_policies_js_1.createLarkExecutionPolicy)(job, {
|
|
919
|
+
store: {},
|
|
920
|
+
workspaceRouter: {
|
|
921
|
+
getThreadSessionKey: (threadId) => `session:${threadId}`,
|
|
922
|
+
listThreads: async () => [],
|
|
923
|
+
createThread: async (workspaceId, title, agentType) => {
|
|
924
|
+
createThreadCalls.push({ workspaceId, title: title || '', agentType });
|
|
925
|
+
return { id: 'thread-new' };
|
|
926
|
+
},
|
|
927
|
+
},
|
|
928
|
+
getChannelRuntime: () => ({
|
|
929
|
+
registerScheduledThreadBridge: () => () => { },
|
|
930
|
+
}),
|
|
931
|
+
}, async () => 'thread-origin', () => '');
|
|
932
|
+
const target = await policy.resolveTarget(job);
|
|
933
|
+
strict_1.default.equal(target.threadId, 'thread-new');
|
|
934
|
+
strict_1.default.equal(createThreadCalls.length, 1);
|
|
935
|
+
strict_1.default.equal(createThreadCalls[0].agentType, undefined);
|
|
936
|
+
});
|
|
857
937
|
(0, node_test_1.default)('lark same-thread execution policy keeps the original thread target', async () => {
|
|
858
938
|
const job = {
|
|
859
939
|
id: 'job-1',
|
|
@@ -894,3 +974,176 @@ const thread_slash_command_dispatcher_js_1 = require("../../services/local-ai-co
|
|
|
894
974
|
sessionKey: 'session:thread-origin',
|
|
895
975
|
});
|
|
896
976
|
});
|
|
977
|
+
(0, node_test_1.default)('platform thread binding persists preferred agent across upserts and updates', () => {
|
|
978
|
+
const dir = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'agentdock-binding-pref-'));
|
|
979
|
+
try {
|
|
980
|
+
const store = new local_core_acp_store_js_1.LocalCoreAcpStore(dir);
|
|
981
|
+
const now = new Date().toISOString();
|
|
982
|
+
store.upsertPlatformThreadBinding({
|
|
983
|
+
workspace_id: 'workspace-a',
|
|
984
|
+
platform: 'lark',
|
|
985
|
+
chat_id: 'chat-1',
|
|
986
|
+
platform_user_id: 'user-1',
|
|
987
|
+
thread_id: 'thread-1',
|
|
988
|
+
last_platform_message_id: null,
|
|
989
|
+
created_at: now,
|
|
990
|
+
updated_at: now,
|
|
991
|
+
});
|
|
992
|
+
store.updatePlatformThreadPreferredAgent('workspace-a', 'chat-1', 'user-1', 'claudecode', 'lark');
|
|
993
|
+
let binding = store.getPlatformThreadBinding('workspace-a', 'chat-1', 'user-1', 'lark');
|
|
994
|
+
strict_1.default.equal(binding?.preferred_agent_type, 'claudecode');
|
|
995
|
+
const later = new Date().toISOString();
|
|
996
|
+
store.upsertPlatformThreadBinding({
|
|
997
|
+
workspace_id: 'workspace-a',
|
|
998
|
+
platform: 'lark',
|
|
999
|
+
chat_id: 'chat-1',
|
|
1000
|
+
platform_user_id: 'user-1',
|
|
1001
|
+
thread_id: 'thread-2',
|
|
1002
|
+
last_platform_message_id: null,
|
|
1003
|
+
created_at: later,
|
|
1004
|
+
updated_at: later,
|
|
1005
|
+
});
|
|
1006
|
+
binding = store.getPlatformThreadBinding('workspace-a', 'chat-1', 'user-1', 'lark');
|
|
1007
|
+
strict_1.default.equal(binding?.thread_id, 'thread-2');
|
|
1008
|
+
strict_1.default.equal(binding?.preferred_agent_type, 'claudecode');
|
|
1009
|
+
store.updatePlatformThreadPreferredAgent('workspace-a', 'chat-1', 'user-1', null, 'lark');
|
|
1010
|
+
binding = store.getPlatformThreadBinding('workspace-a', 'chat-1', 'user-1', 'lark');
|
|
1011
|
+
strict_1.default.equal(binding?.preferred_agent_type, null);
|
|
1012
|
+
store.close();
|
|
1013
|
+
}
|
|
1014
|
+
finally {
|
|
1015
|
+
(0, node_fs_1.rmSync)(dir, { recursive: true, force: true });
|
|
1016
|
+
}
|
|
1017
|
+
});
|
|
1018
|
+
(0, node_test_1.default)('slash agent command in a channel writes preferred agent to the binding', async () => {
|
|
1019
|
+
const dir = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'agentdock-channel-agent-cmd-'));
|
|
1020
|
+
try {
|
|
1021
|
+
const store = new local_core_acp_store_js_1.LocalCoreAcpStore(dir);
|
|
1022
|
+
const thread = store.createThread('workspace-a', 'Channel thread', 'codex');
|
|
1023
|
+
const now = new Date().toISOString();
|
|
1024
|
+
store.upsertPlatformThreadBinding({
|
|
1025
|
+
workspace_id: 'workspace-a',
|
|
1026
|
+
platform: 'lark',
|
|
1027
|
+
chat_id: 'chat-1',
|
|
1028
|
+
platform_user_id: 'user-1',
|
|
1029
|
+
thread_id: thread.id,
|
|
1030
|
+
last_platform_message_id: null,
|
|
1031
|
+
created_at: now,
|
|
1032
|
+
updated_at: now,
|
|
1033
|
+
});
|
|
1034
|
+
const row = store.getThreadRow(thread.id);
|
|
1035
|
+
const dispatcher = new thread_slash_command_dispatcher_js_1.ThreadSlashCommandDispatcher({
|
|
1036
|
+
session: {
|
|
1037
|
+
listThreads: () => [],
|
|
1038
|
+
getThread: (id) => ({ id, title: row.title, messages: [] }),
|
|
1039
|
+
createThread: (workspaceId, title) => ({ id: 'new-thread', title, messages: [] }),
|
|
1040
|
+
renameThread: (id, title) => ({ id, title, messages: [] }),
|
|
1041
|
+
deleteThread: () => ({ deleted: true }),
|
|
1042
|
+
},
|
|
1043
|
+
thread: {
|
|
1044
|
+
getThreadRow: (id) => store.getThreadRow(id),
|
|
1045
|
+
updateThreadAgentMode: (id, mode) => store.updateThreadAgentMode(id, mode),
|
|
1046
|
+
updateThreadAgentType: (id, agentType) => store.updateThreadAgentType(id, agentType),
|
|
1047
|
+
getLatestRunForThread: () => undefined,
|
|
1048
|
+
createAuditEvent: () => { },
|
|
1049
|
+
getAgentTypes: () => ['codex', 'pi', 'claudecode'],
|
|
1050
|
+
setChannelPreferredAgent: (input) => store.updatePlatformThreadPreferredAgent(input.workspaceId, input.chatId, input.platformUserId, input.agentType, input.platform),
|
|
1051
|
+
},
|
|
1052
|
+
});
|
|
1053
|
+
const useResult = await dispatcher.execute({
|
|
1054
|
+
threadId: thread.id,
|
|
1055
|
+
workspaceId: 'workspace-a',
|
|
1056
|
+
content: '/agent use claudecode',
|
|
1057
|
+
defaultAgentType: 'codex',
|
|
1058
|
+
channel: { chatId: 'chat-1', platformUserId: 'user-1', platform: 'lark' },
|
|
1059
|
+
});
|
|
1060
|
+
strict_1.default.equal(useResult.handled, true);
|
|
1061
|
+
strict_1.default.equal(store.getThreadRow(thread.id)?.agent_type, 'claudecode');
|
|
1062
|
+
strict_1.default.equal(store.getPlatformThreadBinding('workspace-a', 'chat-1', 'user-1', 'lark')?.preferred_agent_type, 'claudecode');
|
|
1063
|
+
const resetResult = await dispatcher.execute({
|
|
1064
|
+
threadId: thread.id,
|
|
1065
|
+
workspaceId: 'workspace-a',
|
|
1066
|
+
content: '/agent reset',
|
|
1067
|
+
defaultAgentType: 'codex',
|
|
1068
|
+
channel: { chatId: 'chat-1', platformUserId: 'user-1', platform: 'lark' },
|
|
1069
|
+
});
|
|
1070
|
+
strict_1.default.equal(resetResult.handled, true);
|
|
1071
|
+
strict_1.default.equal(store.getThreadRow(thread.id)?.agent_type, 'codex');
|
|
1072
|
+
strict_1.default.equal(store.getPlatformThreadBinding('workspace-a', 'chat-1', 'user-1', 'lark')?.preferred_agent_type, null);
|
|
1073
|
+
store.close();
|
|
1074
|
+
}
|
|
1075
|
+
finally {
|
|
1076
|
+
(0, node_fs_1.rmSync)(dir, { recursive: true, force: true });
|
|
1077
|
+
}
|
|
1078
|
+
});
|
|
1079
|
+
(0, node_test_1.default)('channel session runtime applies preferred agent when creating a new thread', async () => {
|
|
1080
|
+
const dir = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'agentdock-channel-new-inherit-'));
|
|
1081
|
+
try {
|
|
1082
|
+
const store = new local_core_acp_store_js_1.LocalCoreAcpStore(dir);
|
|
1083
|
+
const original = store.createThread('workspace-a', 'Original channel thread', 'codex');
|
|
1084
|
+
const now = new Date().toISOString();
|
|
1085
|
+
store.upsertPlatformThreadBinding({
|
|
1086
|
+
workspace_id: 'workspace-a',
|
|
1087
|
+
platform: 'lark',
|
|
1088
|
+
chat_id: 'chat-1',
|
|
1089
|
+
platform_user_id: 'user-1',
|
|
1090
|
+
thread_id: original.id,
|
|
1091
|
+
last_platform_message_id: null,
|
|
1092
|
+
created_at: now,
|
|
1093
|
+
updated_at: now,
|
|
1094
|
+
});
|
|
1095
|
+
store.updatePlatformThreadPreferredAgent('workspace-a', 'chat-1', 'user-1', 'claudecode', 'lark');
|
|
1096
|
+
store.updateThreadAgentType(original.id, 'claudecode');
|
|
1097
|
+
const createdThreadIds = [];
|
|
1098
|
+
const routes = new Map();
|
|
1099
|
+
const dispatcher = new thread_slash_command_dispatcher_js_1.ThreadSlashCommandDispatcher({
|
|
1100
|
+
session: {
|
|
1101
|
+
listThreads: () => [],
|
|
1102
|
+
getThread: (id) => ({ id, title: 'X', messages: [] }),
|
|
1103
|
+
createThread: (_workspaceId, title) => {
|
|
1104
|
+
const created = store.createThread('workspace-a', title, 'codex');
|
|
1105
|
+
createdThreadIds.push({ id: created.id, initialAgentType: 'codex' });
|
|
1106
|
+
return created;
|
|
1107
|
+
},
|
|
1108
|
+
renameThread: (id, title) => ({ id, title, messages: [] }),
|
|
1109
|
+
deleteThread: () => ({ deleted: true }),
|
|
1110
|
+
},
|
|
1111
|
+
thread: {
|
|
1112
|
+
getThreadRow: (id) => store.getThreadRow(id),
|
|
1113
|
+
updateThreadAgentMode: (id, mode) => store.updateThreadAgentMode(id, mode),
|
|
1114
|
+
updateThreadAgentType: (id, agentType) => store.updateThreadAgentType(id, agentType),
|
|
1115
|
+
getLatestRunForThread: () => undefined,
|
|
1116
|
+
createAuditEvent: () => { },
|
|
1117
|
+
getAgentTypes: () => ['codex', 'claudecode'],
|
|
1118
|
+
},
|
|
1119
|
+
});
|
|
1120
|
+
const runtime = new session_command_runtime_js_1.ChannelSessionCommandRuntime({
|
|
1121
|
+
dispatcher,
|
|
1122
|
+
store,
|
|
1123
|
+
getThreadSessionKey: (id) => `session:${id}`,
|
|
1124
|
+
setThreadRoute: (sessionKey, route) => { routes.set(sessionKey, route); },
|
|
1125
|
+
createRoute: (input, id) => ({ workspaceId: input.workspaceId, chatId: input.chatId, threadId: id }),
|
|
1126
|
+
sendResult: async () => { },
|
|
1127
|
+
});
|
|
1128
|
+
const result = await runtime.execute({
|
|
1129
|
+
workspaceId: 'workspace-a',
|
|
1130
|
+
currentThreadId: original.id,
|
|
1131
|
+
text: '/new Follow up',
|
|
1132
|
+
defaultTitle: 'Follow up',
|
|
1133
|
+
defaultAgentType: 'codex',
|
|
1134
|
+
chatId: 'chat-1',
|
|
1135
|
+
platformUserId: 'user-1',
|
|
1136
|
+
platformKey: 'lark',
|
|
1137
|
+
instanceId: 'default',
|
|
1138
|
+
});
|
|
1139
|
+
strict_1.default.equal(result.handled, true);
|
|
1140
|
+
strict_1.default.equal(result.threadId, createdThreadIds[0]?.id);
|
|
1141
|
+
strict_1.default.equal(createdThreadIds[0]?.initialAgentType, 'codex', 'createThread starts with default agent before inheritance');
|
|
1142
|
+
strict_1.default.equal(store.getThreadRow(result.threadId)?.agent_type, 'claudecode', 'new thread should inherit preferred agent after creation');
|
|
1143
|
+
strict_1.default.equal(store.getPlatformThreadBinding('workspace-a', 'chat-1', 'user-1', 'lark')?.preferred_agent_type, 'claudecode');
|
|
1144
|
+
store.close();
|
|
1145
|
+
}
|
|
1146
|
+
finally {
|
|
1147
|
+
(0, node_fs_1.rmSync)(dir, { recursive: true, force: true });
|
|
1148
|
+
}
|
|
1149
|
+
});
|
|
@@ -5,7 +5,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const node_test_1 = __importDefault(require("node:test"));
|
|
7
7
|
const strict_1 = __importDefault(require("node:assert/strict"));
|
|
8
|
+
const node_stream_1 = require("node:stream");
|
|
8
9
|
const server_routes_js_1 = require("../../services/local-ai-core/src/runtime/server-routes.js");
|
|
10
|
+
const thread_handler_js_1 = require("../../services/local-ai-core/src/runtime/handlers/thread-handler.js");
|
|
9
11
|
(0, node_test_1.default)('local core route parser separates runtime refresh and runtime detail routes', () => {
|
|
10
12
|
strict_1.default.deepEqual((0, server_routes_js_1.parseLocalAiCoreRoute)('GET', '/api/local/v1/logs'), { name: 'logs.list' });
|
|
11
13
|
strict_1.default.deepEqual((0, server_routes_js_1.parseLocalAiCoreRoute)('GET', '/api/local/v1/runtimes'), { name: 'runtimes.list' });
|
|
@@ -45,6 +47,10 @@ const server_routes_js_1 = require("../../services/local-ai-core/src/runtime/ser
|
|
|
45
47
|
name: 'thread.update-knowledge-bases',
|
|
46
48
|
threadId: 'thread-1',
|
|
47
49
|
});
|
|
50
|
+
strict_1.default.deepEqual((0, server_routes_js_1.parseLocalAiCoreRoute)('PATCH', '/api/local/v1/threads/thread-1/mode'), {
|
|
51
|
+
name: 'thread.update-mode',
|
|
52
|
+
threadId: 'thread-1',
|
|
53
|
+
});
|
|
48
54
|
strict_1.default.deepEqual((0, server_routes_js_1.parseLocalAiCoreRoute)('POST', '/api/local/v1/threads/thread-1/messages'), {
|
|
49
55
|
name: 'thread.messages.send',
|
|
50
56
|
threadId: 'thread-1',
|
|
@@ -55,6 +61,45 @@ const server_routes_js_1 = require("../../services/local-ai-core/src/runtime/ser
|
|
|
55
61
|
});
|
|
56
62
|
strict_1.default.equal((0, server_routes_js_1.parseLocalAiCoreRoute)('GET', '/api/local/v1/threads/thread-1/messages'), null);
|
|
57
63
|
});
|
|
64
|
+
(0, node_test_1.default)('thread mode route handler persists normalized mode through workspace router', async () => {
|
|
65
|
+
const calls = [];
|
|
66
|
+
const map = new Map();
|
|
67
|
+
(0, thread_handler_js_1.registerThreadHandlers)(map, {
|
|
68
|
+
setThreadMode: async (threadId, mode) => {
|
|
69
|
+
calls.push({ threadId, mode });
|
|
70
|
+
return {
|
|
71
|
+
id: threadId,
|
|
72
|
+
workspaceId: 'workspace-a',
|
|
73
|
+
title: 'Thread',
|
|
74
|
+
live: false,
|
|
75
|
+
updatedAt: '2026-06-14T00:00:00.000Z',
|
|
76
|
+
createdAt: '2026-06-14T00:00:00.000Z',
|
|
77
|
+
historyCount: 0,
|
|
78
|
+
excerpt: '',
|
|
79
|
+
agentMode: 'bypassPermissions',
|
|
80
|
+
messages: [],
|
|
81
|
+
selectedKnowledgeBaseIds: [],
|
|
82
|
+
};
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
const req = node_stream_1.Readable.from([Buffer.from(JSON.stringify({ mode: 'bypassPermissions' }))]);
|
|
86
|
+
const headers = {};
|
|
87
|
+
let responseBody = '';
|
|
88
|
+
const res = {
|
|
89
|
+
statusCode: 0,
|
|
90
|
+
setHeader: (name, value) => {
|
|
91
|
+
headers[name] = value;
|
|
92
|
+
},
|
|
93
|
+
end: (body) => {
|
|
94
|
+
responseBody = body;
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
await map.get('thread.update-mode')({ name: 'thread.update-mode', threadId: 'thread-1' }, req, res, new URL('http://127.0.0.1/api/local/v1/threads/thread-1/mode'));
|
|
98
|
+
strict_1.default.deepEqual(calls, [{ threadId: 'thread-1', mode: 'bypassPermissions' }]);
|
|
99
|
+
strict_1.default.equal(res.statusCode, 200);
|
|
100
|
+
strict_1.default.equal(headers['Content-Type'], 'application/json; charset=utf-8');
|
|
101
|
+
strict_1.default.equal(JSON.parse(responseBody).data.agentMode, 'bypassPermissions');
|
|
102
|
+
});
|
|
58
103
|
(0, node_test_1.default)('local core route parser only accepts run interrupt action with POST', () => {
|
|
59
104
|
strict_1.default.deepEqual((0, server_routes_js_1.parseLocalAiCoreRoute)('POST', '/api/local/v1/runs/run-1/interrupt'), {
|
|
60
105
|
name: 'run.interrupt',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kafca/agentdock",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.49",
|
|
4
4
|
"license": "PolyForm-Noncommercial-1.0.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist-electron/electron/main.js",
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
"@types/react-dom": "^19.1.2",
|
|
75
75
|
"@vitejs/plugin-react": "^4.4.1",
|
|
76
76
|
"autoprefixer": "^10.4.21",
|
|
77
|
-
"electron": "^35.
|
|
77
|
+
"electron": "^35.7.5",
|
|
78
78
|
"electron-builder": "^26.8.1",
|
|
79
79
|
"postcss": "^8.5.3",
|
|
80
80
|
"tailwindcss": "^3.4.17",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{u as C,D as z,r,j as e,L as S,B as g,g as b,T as B}from"./index-dy-g2Bh4.js";import{B as j}from"./Badge-BYREM3t3.js";import{g as E,a as L}from"./sessions-eK5D4FLt.js";import{C as A,A as D}from"./ChatMarkdown-_slLloCh.js";import{A as I}from"./arrow-left-BU2NB2LA.js";import{C as M}from"./circle-CpQ8x4k_.js";import{W as y,R}from"./wifi-off-CCTloj-V.js";import{B as T}from"./bot-IYNh8tH5.js";import{U}from"./user-Cvf_uiyQ.js";import"./check-CCZ0JO_S.js";function J(){var p;const{t:a}=C(),{project:i,id:l}=z(),[s,v]=r.useState(null),[d,m]=r.useState(""),[c,x]=r.useState(!1),[w,f]=r.useState(!0),u=r.useRef(null),o=r.useCallback(async()=>{if(!(!i||!l))try{f(!0);const t=await E(i,l,200);v(t)}finally{f(!1)}},[i,l]);r.useEffect(()=>{o()},[o]),r.useEffect(()=>{var t;(t=u.current)==null||t.scrollIntoView({behavior:"smooth"})},[s==null?void 0:s.history]);const h=async()=>{if(!d.trim()||!i||!s)return;const t=d.trim();m(""),x(!0);try{await L(i,{session_key:s.session_key,message:t}),setTimeout(o,1500)}finally{x(!1)}},N=t=>{t.key==="Enter"&&!t.shiftKey&&(t.preventDefault(),h())};return w&&!s?e.jsx("div",{className:"flex items-center justify-center h-64 text-muted-foreground animate-pulse",children:"Loading..."}):e.jsxs("div",{className:"flex flex-col h-[calc(100vh-8rem)] animate-fade-in",children:[e.jsxs("div",{className:"flex items-center justify-between border-b border-slate-200/80 pb-4 dark:border-white/[0.08]",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx(S,{to:"/sessions",className:"p-2 rounded-md hover:bg-accent/10 transition-colors",children:e.jsx(I,{size:18,className:"text-muted-foreground"})}),e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("h2",{className:"text-[1.4rem] font-semibold text-foreground",children:(s==null?void 0:s.name)||l}),s!=null&&s.live?e.jsxs("span",{className:"flex items-center gap-1 rounded-full bg-primary/10 px-2 py-0.5 text-[10px] text-primary",children:[e.jsx(M,{size:5,className:"fill-current"})," live"]}):e.jsxs("span",{className:"flex items-center gap-1 text-[10px] text-muted-foreground bg-muted px-1.5 py-0.5 rounded-full",children:[e.jsx(y,{size:9})," ",a("sessions.offline")]})]}),e.jsxs("div",{className:"flex items-center gap-2 mt-0.5",children:[e.jsx(j,{children:i}),(s==null?void 0:s.platform)&&e.jsx(j,{variant:"info",children:s.platform}),e.jsx("span",{className:"text-xs text-muted-foreground",children:s==null?void 0:s.session_key})]})]})]}),e.jsxs(g,{size:"sm",variant:"ghost",onClick:o,children:[e.jsx(R,{size:14})," ",a("common.refresh")]})]}),e.jsxs("div",{className:"flex-1 overflow-y-auto py-6",children:[(!(s!=null&&s.history)||s.history.length===0)&&e.jsx("p",{className:"text-center text-sm text-muted-foreground py-12",children:a("sessions.noMessages")}),e.jsx("div",{className:"mx-auto max-w-4xl space-y-5",children:(p=s==null?void 0:s.history)==null?void 0:p.map((t,k)=>{const n=t.role==="user";return e.jsxs("div",{className:b("flex gap-3",n?"justify-end":"justify-start"),children:[!n&&e.jsx("div",{className:"mt-1 flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-primary/10 dark:bg-white/[0.06]",children:e.jsx(T,{size:16,className:"text-primary"})}),e.jsx("div",{className:b("rounded-[20px] px-5 py-3.5 text-sm",n?"chat-user-glass max-w-[70%] rounded-br-sm text-slate-950 dark:text-slate-50":"max-w-[78%] rounded-bl-sm border border-slate-200 bg-[#fbfbfd] text-card-foreground dark:border-white/[0.08] dark:bg-white/[0.04]"),children:e.jsx(A,{content:t.content,isUser:n})}),n&&e.jsx("div",{className:"mt-1 flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-muted dark:bg-white/[0.08]",children:e.jsx(U,{size:16,className:"text-muted-foreground"})})]},k)})}),e.jsx("div",{ref:u})]}),e.jsx("div",{className:"border-t pt-4",children:s!=null&&s.live?e.jsx("div",{className:"mx-auto max-w-4xl",children:e.jsxs("div",{className:"relative",children:[e.jsx(B,{value:d,onChange:t=>m(t.target.value),onKeyDown:N,placeholder:a("sessions.messageInput"),rows:2,className:"min-h-[88px] rounded-[22px] border-gray-200 bg-[#fbfbfd] px-4 pb-14 pt-3 text-[15px] leading-6 dark:border-white/[0.08] dark:bg-[rgba(255,255,255,0.04)] sm:min-h-[96px] sm:px-5 sm:pt-4",disabled:c}),e.jsx(g,{onClick:h,disabled:c||!d.trim(),size:"icon","aria-label":a("sessions.messageInput"),className:"absolute bottom-3 right-3 h-10 w-10 rounded-full bg-primary px-0 text-white shadow-none hover:bg-[#0071e3] disabled:bg-slate-300 disabled:text-white disabled:opacity-100 dark:bg-primary dark:text-white dark:hover:bg-[#2997ff] dark:disabled:bg-white/20 dark:disabled:text-white/55 sm:h-11 sm:w-11",children:c?e.jsxs("svg",{className:"animate-spin h-4 w-4",viewBox:"0 0 24 24",children:[e.jsx("circle",{className:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4",fill:"none"}),e.jsx("path",{className:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"})]}):e.jsx(D,{size:20,strokeWidth:2.2})})]})}):e.jsxs("div",{className:"flex items-center gap-2 px-4 py-3 text-sm text-muted-foreground bg-muted rounded-lg",children:[e.jsx(y,{size:14}),e.jsx("span",{children:a("sessions.notLiveHint")})]})})]})}export{J as default};
|