@kafca/agentdock 0.1.28 → 0.1.29

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.
Files changed (70) hide show
  1. package/README.md +5 -0
  2. package/dist/renderer/assets/{Badge-B-Ayib4h.js → Badge-ngf0eCzI.js} +1 -1
  3. package/dist/renderer/assets/{Chat-CNEOxtyz.js → Chat-tCGY5odh.js} +1 -1
  4. package/dist/renderer/assets/{ChatMarkdown-BTd1QBj9.js → ChatMarkdown-vqDWgVNb.js} +1 -1
  5. package/dist/renderer/assets/{Config-ByKhcLa6.js → Config-YsVDQmIs.js} +1 -1
  6. package/dist/renderer/assets/{CronList-0mi8dcC5.js → CronList-DQN0T7Yc.js} +1 -1
  7. package/dist/renderer/assets/{Dashboard-C8-tB_qg.js → Dashboard-C2O6Yxq3.js} +2 -2
  8. package/dist/renderer/assets/{EmptyState-TR-9nr5e.js → EmptyState-CTkA-fBQ.js} +1 -1
  9. package/dist/renderer/assets/{KnowledgeDetail-DKAxFOXc.js → KnowledgeDetail-DjLZDItQ.js} +1 -1
  10. package/dist/renderer/assets/{KnowledgeHome-CM-1IDr4.js → KnowledgeHome-2NHeRZxW.js} +1 -1
  11. package/dist/renderer/assets/{Logs-DI5RFPri.js → Logs-CQ6j-Sct.js} +1 -1
  12. package/dist/renderer/assets/{Modal-CQpa4NPP.js → Modal-9g1uWJfC.js} +1 -1
  13. package/dist/renderer/assets/{Page-BHXEAwzQ.js → Page-B4mPLn6n.js} +1 -1
  14. package/dist/renderer/assets/{ProjectDetail-Dn5elnHx.js → ProjectDetail-pBXOAeL4.js} +1 -1
  15. package/dist/renderer/assets/{ProjectList-D6yvEgb5.js → ProjectList-B9PYfZaS.js} +1 -1
  16. package/dist/renderer/assets/{Select-BbkcXnXL.js → Select-BWFQJ2R8.js} +1 -1
  17. package/dist/renderer/assets/{SessionChat-Vkf-7gvX.js → SessionChat-fBrzJs3A.js} +1 -1
  18. package/dist/renderer/assets/{SessionList-c5encjWd.js → SessionList-DjHOsk7X.js} +1 -1
  19. package/dist/renderer/assets/ThreadChat-MagPeJD0.js +23 -0
  20. package/dist/renderer/assets/{Workspace-BC7hWqhP.js → Workspace-nfTcxlhw.js} +1 -1
  21. package/dist/renderer/assets/{arrow-left-I_Y1kdN9.js → arrow-left-CIWZ6JEB.js} +1 -1
  22. package/dist/renderer/assets/{book-open-B3anUYvp.js → book-open-Ck6BgBhN.js} +1 -1
  23. package/dist/renderer/assets/{check-BPNCDKgS.js → check-CtB2ZLVE.js} +1 -1
  24. package/dist/renderer/assets/{chevron-down-BaxUcOIV.js → chevron-down--8lODnN0.js} +1 -1
  25. package/dist/renderer/assets/{circle-DJQiypFS.js → circle-CKQOJcbh.js} +1 -1
  26. package/dist/renderer/assets/{desktop-Cv51clcN.js → desktop-Do2I28CT.js} +1 -1
  27. package/dist/renderer/assets/{funnel-DqKBtiqE.js → funnel-CkZuFIwa.js} +1 -1
  28. package/dist/renderer/assets/{heart-CmoNjvMO.js → heart-CAX_CqFQ.js} +1 -1
  29. package/dist/renderer/assets/{index-BfXqhQ1Z.js → index--_L0Y77h.js} +1 -1
  30. package/dist/renderer/assets/{index-DXJl2HOK.js → index-DvAYflFj.js} +2 -2
  31. package/dist/renderer/assets/{pencil-CLUBszbw.js → pencil-sIRhtchu.js} +1 -1
  32. package/dist/renderer/assets/{play-l2RPZuAi.js → play-CJNRbCL5.js} +1 -1
  33. package/dist/renderer/assets/{plug-CeUPIjRt.js → plug-DsFe9GBx.js} +1 -1
  34. package/dist/renderer/assets/{plus-BjkefS2P.js → plus-KDwEI-Rs.js} +1 -1
  35. package/dist/renderer/assets/projects-CJUs2vaq.js +1 -0
  36. package/dist/renderer/assets/{save-D0yYt9tz.js → save-C-p5r3K-.js} +1 -1
  37. package/dist/renderer/assets/{search-B7s473Y4.js → search-BZxQJb2k.js} +1 -1
  38. package/dist/renderer/assets/{server-Dz_h8X_8.js → server-BV-K022I.js} +1 -1
  39. package/dist/renderer/assets/{session-utils-BvNRTRXA.js → session-utils-ClQTa8yS.js} +1 -1
  40. package/dist/renderer/assets/{sessions-KPJsgKbQ.js → sessions-B0FSCA9O.js} +1 -1
  41. package/dist/renderer/assets/{shield-check-Wc5wfUUs.js → shield-check-B6AjkXUd.js} +1 -1
  42. package/dist/renderer/assets/{trash-2-7INdaB9w.js → trash-2-41Pv4qRx.js} +1 -1
  43. package/dist/renderer/assets/{user-CLbCgWNR.js → user-NKKHCKm9.js} +1 -1
  44. package/dist/renderer/assets/{wifi-off-BfDVPXbO.js → wifi-off-E1ZNhLG5.js} +1 -1
  45. package/dist/renderer/index.html +1 -1
  46. package/dist-electron/electron/agent-runtime-detector.test.js +20 -0
  47. package/dist-electron/electron/lac-cli.test.js +2 -13
  48. package/dist-electron/electron/local-core-refactor.test.js +127 -50
  49. package/dist-electron/electron/workspace-task-store.test.js +112 -0
  50. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-backend.js +10 -8
  51. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-progress.js +6 -2
  52. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-session-coordinator.js +15 -6
  53. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-store.js +36 -11
  54. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-transport.js +1 -0
  55. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-turn-coordinator.js +11 -5
  56. package/dist-electron/services/local-ai-core/src/channel/lark/runtime-state.js +34 -39
  57. package/dist-electron/services/local-ai-core/src/channel/weixin/local-core-weixin-gateway.js +31 -18
  58. package/dist-electron/services/local-ai-core/src/cli/lac.js +1 -17
  59. package/dist-electron/services/local-ai-core/src/router/workspace-router.js +2 -2
  60. package/dist-electron/services/local-ai-core/src/runtime/agent-runtime-detector.js +1 -1
  61. package/dist-electron/services/local-ai-core/src/runtime/local-core-controller.js +31 -1
  62. package/dist-electron/services/local-ai-core/src/scheduler/local-schedule-adapter.js +4 -1
  63. package/dist-electron/services/local-ai-core/src/scheduler/scheduled-conversation-executor.js +4 -1
  64. package/dist-electron/src/pages/Threads/thread-chat-message-blocks.js +4 -114
  65. package/dist-electron/src/pages/Threads/thread-chat-model.js +14 -23
  66. package/dist-electron/src/pages/Threads/thread-chat-page-state.js +1 -1
  67. package/dist-electron/src/pages/Threads/thread-chat-permission.test.js +58 -31
  68. package/package.json +1 -1
  69. package/dist/renderer/assets/ThreadChat-DY4wzomi.js +0 -23
  70. package/dist/renderer/assets/projects-De73QY_o.js +0 -1
@@ -1,4 +1,4 @@
1
- import{c as a}from"./index-DXJl2HOK.js";/**
1
+ import{c as a}from"./index-DvAYflFj.js";/**
2
2
  * @license lucide-react v0.487.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1,4 +1,4 @@
1
- import{c as o}from"./index-DXJl2HOK.js";/**
1
+ import{c as o}from"./index-DvAYflFj.js";/**
2
2
  * @license lucide-react v0.487.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1,4 +1,4 @@
1
- import{c as o}from"./index-DXJl2HOK.js";/**
1
+ import{c as o}from"./index-DvAYflFj.js";/**
2
2
  * @license lucide-react v0.487.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1,4 +1,4 @@
1
- import{c as e}from"./index-DXJl2HOK.js";/**
1
+ import{c as e}from"./index-DvAYflFj.js";/**
2
2
  * @license lucide-react v0.487.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -0,0 +1 @@
1
+ import{z as t}from"./index-DvAYflFj.js";const e=()=>t.get("/projects"),r=o=>t.get(`/projects/${o}`);export{r as g,e as l};
@@ -1,4 +1,4 @@
1
- import{c as a}from"./index-DXJl2HOK.js";/**
1
+ import{c as a}from"./index-DvAYflFj.js";/**
2
2
  * @license lucide-react v0.487.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1,4 +1,4 @@
1
- import{c}from"./index-DXJl2HOK.js";/**
1
+ import{c}from"./index-DvAYflFj.js";/**
2
2
  * @license lucide-react v0.487.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1,4 +1,4 @@
1
- import{c as e}from"./index-DXJl2HOK.js";/**
1
+ import{c as e}from"./index-DvAYflFj.js";/**
2
2
  * @license lucide-react v0.487.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1,4 +1,4 @@
1
- import{c as o}from"./index-DXJl2HOK.js";/**
1
+ import{c as o}from"./index-DvAYflFj.js";/**
2
2
  * @license lucide-react v0.487.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1 +1 @@
1
- import{z as o}from"./index-DXJl2HOK.js";const i=s=>o.get(`/projects/${s}/sessions`),c=(s,e,t)=>o.get(`/projects/${s}/sessions/${e}`,{history_limit:String(t)}),r=(s,e,t)=>o.patch(`/projects/${s}/sessions/${e}`,t),a=(s,e)=>o.delete(`/projects/${s}/sessions/${e}`),p=(s,e)=>o.post(`/projects/${s}/sessions/switch`,e),$=(s,e)=>o.post(`/projects/${s}/send`,e);export{$ as a,a as d,c as g,i as l,r,p as s};
1
+ import{z as o}from"./index-DvAYflFj.js";const i=s=>o.get(`/projects/${s}/sessions`),c=(s,e,t)=>o.get(`/projects/${s}/sessions/${e}`,{history_limit:String(t)}),r=(s,e,t)=>o.patch(`/projects/${s}/sessions/${e}`,t),a=(s,e)=>o.delete(`/projects/${s}/sessions/${e}`),p=(s,e)=>o.post(`/projects/${s}/sessions/switch`,e),$=(s,e)=>o.post(`/projects/${s}/send`,e);export{$ as a,a as d,c as g,i as l,r,p as s};
@@ -1,4 +1,4 @@
1
- import{c}from"./index-DXJl2HOK.js";/**
1
+ import{c}from"./index-DvAYflFj.js";/**
2
2
  * @license lucide-react v0.487.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1,4 +1,4 @@
1
- import{c as e}from"./index-DXJl2HOK.js";/**
1
+ import{c as e}from"./index-DvAYflFj.js";/**
2
2
  * @license lucide-react v0.487.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1,4 +1,4 @@
1
- import{c as e}from"./index-DXJl2HOK.js";/**
1
+ import{c as e}from"./index-DvAYflFj.js";/**
2
2
  * @license lucide-react v0.487.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1,4 +1,4 @@
1
- import{c as a}from"./index-DXJl2HOK.js";/**
1
+ import{c as a}from"./index-DvAYflFj.js";/**
2
2
  * @license lucide-react v0.487.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -5,7 +5,7 @@
5
5
  <link rel="icon" type="image/svg+xml" href="./favicon.svg" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <title>AgentDock</title>
8
- <script type="module" crossorigin src="./assets/index-DXJl2HOK.js"></script>
8
+ <script type="module" crossorigin src="./assets/index-DvAYflFj.js"></script>
9
9
  <link rel="stylesheet" crossorigin href="./assets/index-DFiJR0vv.css">
10
10
  </head>
11
11
  <body class="bg-[#f5f5f7] dark:bg-[#151516]">
@@ -159,6 +159,26 @@ const agent_runtime_detector_js_1 = require("../services/local-ai-core/src/runti
159
159
  (0, node_fs_1.rmSync)(dir, { recursive: true, force: true });
160
160
  }
161
161
  });
162
+ (0, node_test_1.default)('agent runtime detector reports Claude Code when claude command is available', () => {
163
+ const dir = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'agent-runtime-claude-version-'));
164
+ try {
165
+ const claude = (0, node_path_1.join)(dir, 'claude');
166
+ (0, node_fs_1.writeFileSync)(claude, '#!/bin/sh\necho "2.1.114 (Claude Code)"\n', 'utf8');
167
+ (0, node_fs_1.chmodSync)(claude, 0o755);
168
+ const claudeRuntime = (0, agent_runtime_detector_js_1.detectInstalledAgentRuntimes)({
169
+ env: { PATH: dir },
170
+ requireFrom: (0, node_path_1.join)(dir, 'package.json'),
171
+ }).find((runtime) => runtime.agentType === 'claudecode');
172
+ strict_1.default.equal(claudeRuntime?.status, 'installed');
173
+ strict_1.default.equal(claudeRuntime?.source, 'path');
174
+ strict_1.default.equal(claudeRuntime?.command, claude);
175
+ strict_1.default.equal(claudeRuntime?.version, '2.1.114');
176
+ strict_1.default.equal(claudeRuntime?.issues.length, 0);
177
+ }
178
+ finally {
179
+ (0, node_fs_1.rmSync)(dir, { recursive: true, force: true });
180
+ }
181
+ });
162
182
  (0, node_test_1.default)('agent runtime detector keeps runtime installed when version command fails', () => {
163
183
  const dir = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'agent-runtime-version-fail-'));
164
184
  try {
@@ -28,7 +28,7 @@ function createIo() {
28
28
  read: () => ({ stdout, stderr }),
29
29
  };
30
30
  }
31
- (0, node_test_1.default)('lac scheduler add posts a persistent Lark job from env context', async () => {
31
+ (0, node_test_1.default)('lac scheduler add posts thread context and lets local core resolve platform binding', async () => {
32
32
  let capturedBody = null;
33
33
  const server = (0, node_http_1.createServer)(async (req, res) => {
34
34
  if (req.method === 'POST' && req.url === '/api/local/v1/scheduler/jobs') {
@@ -83,13 +83,7 @@ function createIo() {
83
83
  (0, strict_1.default)(capturedBody);
84
84
  strict_1.default.deepEqual(JSON.parse(capturedBody), {
85
85
  workspaceId: '知识库',
86
- platform: 'lark',
87
- route: {
88
- type: 'channel.chat',
89
- channelId: 'chat-1',
90
- participantId: 'user-1',
91
- threadId: 'thread-1',
92
- },
86
+ threadId: 'thread-1',
93
87
  executionMode: 'same-thread',
94
88
  triggerType: 'cron',
95
89
  cronExpr: '*/2 * * * *',
@@ -148,11 +142,6 @@ function createIo() {
148
142
  (0, strict_1.default)(capturedBody);
149
143
  strict_1.default.deepEqual(JSON.parse(capturedBody), {
150
144
  workspaceId: '知识库',
151
- platform: 'local',
152
- route: {
153
- type: 'local.thread',
154
- channelId: '知识库',
155
- },
156
145
  executionMode: 'same-thread',
157
146
  triggerType: 'cron',
158
147
  cronExpr: '*/5 * * * *',
@@ -470,23 +470,27 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
470
470
  bridgeType: 'preview_start',
471
471
  previewHandle: 'preview-1',
472
472
  content: 'hello',
473
+ bridgeKind: 'assistant',
473
474
  });
474
475
  strict_1.default.deepEqual((0, local_core_acp_progress_js_1.applyAssistantMessageChunk)(currentTurn, ' world'), {
475
476
  bridgeType: 'update_message',
476
477
  previewHandle: 'preview-1',
477
478
  content: 'hello world',
479
+ bridgeKind: 'assistant',
478
480
  });
479
481
  strict_1.default.deepEqual((0, local_core_acp_progress_js_1.applyThoughtChunk)(currentTurn, '先理解'), {
480
482
  bridgeType: 'preview_start',
481
483
  previewHandle: 'thought-preview-1',
482
484
  messageId: 'run-1-thought',
483
- content: '💭 先理解',
485
+ content: '先理解',
486
+ bridgeKind: 'thought',
484
487
  });
485
488
  strict_1.default.deepEqual((0, local_core_acp_progress_js_1.applyThoughtChunk)(currentTurn, ',再修改'), {
486
489
  bridgeType: 'update_message',
487
490
  previewHandle: 'thought-preview-1',
488
491
  messageId: 'run-1-thought',
489
- content: '💭 先理解,再修改',
492
+ content: '先理解,再修改',
493
+ bridgeKind: 'thought',
490
494
  });
491
495
  });
492
496
  (0, node_test_1.default)('ACP thought chunks merge provider snapshots without duplicating text', () => {
@@ -500,13 +504,15 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
500
504
  bridgeType: 'preview_start',
501
505
  previewHandle: 'thought-preview-1',
502
506
  messageId: 'run-1-thought',
503
- content: '💭 The user wants to see their desktop files.',
507
+ content: 'The user wants to see their desktop files.',
508
+ bridgeKind: 'thought',
504
509
  });
505
510
  strict_1.default.deepEqual((0, local_core_acp_progress_js_1.applyThoughtChunk)(currentTurn, 'The user wants to see their desktop files. Let me show them.'), {
506
511
  bridgeType: 'update_message',
507
512
  previewHandle: 'thought-preview-1',
508
513
  messageId: 'run-1-thought',
509
- content: '💭 The user wants to see their desktop files. Let me show them.',
514
+ content: 'The user wants to see their desktop files. Let me show them.',
515
+ bridgeKind: 'thought',
510
516
  });
511
517
  strict_1.default.equal(currentTurn.thoughtText, 'The user wants to see their desktop files. Let me show them.');
512
518
  });
@@ -557,7 +563,7 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
557
563
  { content: '检查消息流' },
558
564
  { content: ' ' },
559
565
  { content: '修复持久化' },
560
- ]), '💭 检查消息流 | 修复持久化');
566
+ ]), '检查消息流 | 修复持久化');
561
567
  strict_1.default.equal((0, local_core_acp_progress_js_1.formatPlanProgress)([{ content: '' }]), '');
562
568
  });
563
569
  (0, node_test_1.default)('ACP tool call running and completed updates share one message id', () => {
@@ -863,10 +869,11 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
863
869
  strict_1.default.match(upserted[0]?.content || '', /ls -la ~\/Desktop/);
864
870
  strict_1.default.match(upserted[0]?.content || '', /completed - Desktop file list/);
865
871
  });
866
- (0, node_test_1.default)('ACP permission button rows preserve always allow actions', () => {
872
+ (0, node_test_1.default)('ACP permission button rows preserve always allow actions with structured status', () => {
873
+ const appended = [];
867
874
  const emitted = [];
868
875
  const coordinator = new local_core_acp_turn_coordinator_js_1.LocalCoreAcpTurnCoordinator({
869
- appendMessage: () => { },
876
+ appendMessage: (_threadId, _role, content, kind, _toolCall, bridgeKind, bridgeStatus) => appended.push({ content, kind, bridgeKind, bridgeStatus }),
870
877
  emitBridge: (event) => emitted.push(event),
871
878
  updateRunStatus: () => { },
872
879
  sendRaw: () => true,
@@ -905,6 +912,10 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
905
912
  ],
906
913
  },
907
914
  });
915
+ strict_1.default.equal(appended[0]?.bridgeKind, 'permission');
916
+ strict_1.default.equal(appended[0]?.bridgeStatus, 'awaiting_input');
917
+ strict_1.default.equal(emitted[0]?.bridgeKind, 'permission');
918
+ strict_1.default.equal(emitted[0]?.bridgeStatus, 'awaiting_input');
908
919
  strict_1.default.deepEqual(emitted[0]?.buttonRows, [[
909
920
  { text: 'allow', data: 'allow' },
910
921
  { text: 'allow all', data: 'allow all' },
@@ -1053,12 +1064,13 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
1053
1064
  });
1054
1065
  strict_1.default.deepEqual(appended, [
1055
1066
  {
1056
- content: '💭 检查消息流 | 修复持久化',
1067
+ content: '检查消息流 | 修复持久化',
1057
1068
  kind: 'progress',
1058
1069
  },
1059
1070
  ]);
1060
1071
  strict_1.default.equal(emitted.length, 1);
1061
1072
  strict_1.default.equal(emitted[0]?.type, 'reply');
1073
+ strict_1.default.equal(emitted[0]?.bridgeKind, 'plan');
1062
1074
  strict_1.default.equal(emitted[0]?.content, appended[0]?.content);
1063
1075
  });
1064
1076
  (0, node_test_1.default)('ACP thought chunks are streamed as thinking preview updates', () => {
@@ -1114,34 +1126,39 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
1114
1126
  strict_1.default.deepEqual(upserted, [
1115
1127
  {
1116
1128
  id: 'run-1-thought',
1117
- content: '💭 先理解问题',
1129
+ content: '先理解问题',
1118
1130
  kind: 'progress',
1119
1131
  },
1120
1132
  {
1121
1133
  id: 'run-1-thought',
1122
- content: '💭 先理解问题,再检查代码',
1134
+ content: '先理解问题,再检查代码',
1123
1135
  kind: 'progress',
1124
1136
  },
1125
1137
  ]);
1126
1138
  strict_1.default.deepEqual(emitted.map((event) => event.type), ['preview_start', 'update_message']);
1127
1139
  strict_1.default.equal(emitted[0]?.previewHandle, 'thought-preview-1');
1128
- strict_1.default.equal(emitted[0]?.content, '💭 先理解问题');
1129
- strict_1.default.equal(emitted[1]?.content, '💭 先理解问题,再检查代码');
1140
+ strict_1.default.equal(emitted[0]?.bridgeKind, 'thought');
1141
+ strict_1.default.equal(emitted[0]?.content, '先理解问题');
1142
+ strict_1.default.equal(emitted[1]?.content, '先理解问题,再检查代码');
1130
1143
  strict_1.default.equal(session.currentTurn.thoughtText, '先理解问题,再检查代码');
1131
1144
  });
1132
- (0, node_test_1.default)('ACP store upserts thought progress as one durable message', () => {
1145
+ (0, node_test_1.default)('ACP store preserves structured progress metadata', () => {
1133
1146
  const userDataPath = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'agentdock-thought-store-'));
1134
1147
  const store = new local_core_acp_store_js_1.LocalCoreAcpStore(userDataPath);
1135
1148
  try {
1136
1149
  const thread = store.createThread('project-1', 'Thread');
1137
- store.upsertMessage(thread.id, 'run-1-thought', 'assistant', '💭 先理解问题', 'progress');
1138
- store.upsertMessage(thread.id, 'run-1-thought', 'assistant', '💭 先理解问题,再检查代码', 'progress');
1150
+ store.upsertMessage(thread.id, 'run-1-thought', 'assistant', '先理解问题', 'progress', undefined, 'thought');
1151
+ store.upsertMessage(thread.id, 'run-1-thought', 'assistant', '先理解问题,再检查代码', 'progress', undefined, 'thought');
1152
+ store.appendMessage(thread.id, 'assistant', '等待确认', 'progress', undefined, 'permission', 'awaiting_input');
1139
1153
  const detail = store.getThread(thread.id, []);
1140
- strict_1.default.equal(detail.messages.length, 1);
1154
+ strict_1.default.equal(detail.messages.length, 2);
1141
1155
  strict_1.default.equal(detail.messages[0]?.id, 'run-1-thought');
1142
1156
  strict_1.default.equal(detail.messages[0]?.kind, 'progress');
1143
- strict_1.default.equal(detail.messages[0]?.content, '💭 先理解问题,再检查代码');
1144
- strict_1.default.equal(detail.historyCount, 1);
1157
+ strict_1.default.equal(detail.messages[0]?.bridgeKind, 'thought');
1158
+ strict_1.default.equal(detail.messages[0]?.content, '先理解问题,再检查代码');
1159
+ strict_1.default.equal(detail.messages[1]?.bridgeKind, 'permission');
1160
+ strict_1.default.equal(detail.messages[1]?.bridgeStatus, 'awaiting_input');
1161
+ strict_1.default.equal(detail.historyCount, 2);
1145
1162
  }
1146
1163
  finally {
1147
1164
  store.close();
@@ -1240,14 +1257,16 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
1240
1257
  sessionKey: 'session:thread-1',
1241
1258
  replyCtx: 'run-1',
1242
1259
  previewHandle: 'thought-preview-1',
1243
- content: '💭 先理解问题',
1260
+ bridgeKind: 'thought',
1261
+ content: '先理解问题',
1244
1262
  });
1245
1263
  await gateway.onBridgeEvent({
1246
1264
  type: 'update_message',
1247
1265
  sessionKey: 'session:thread-1',
1248
1266
  replyCtx: 'run-1',
1249
1267
  previewHandle: 'thought-preview-1',
1250
- content: '💭 先理解问题,再检查代码',
1268
+ bridgeKind: 'thought',
1269
+ content: '先理解问题,再检查代码',
1251
1270
  });
1252
1271
  await gateway.onBridgeEvent({
1253
1272
  type: 'reply',
@@ -1256,7 +1275,7 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
1256
1275
  content: '最终回答',
1257
1276
  });
1258
1277
  strict_1.default.equal(createdCards.length, 2);
1259
- strict_1.default.equal(createdCards[0]?.text, '💭 先理解问题,再检查代码');
1278
+ strict_1.default.equal(createdCards[0]?.text, '先理解问题,再检查代码');
1260
1279
  strict_1.default.equal(createdCards[1]?.text, '最终回答');
1261
1280
  strict_1.default.equal(patchedCards.length, 0);
1262
1281
  strict_1.default.deepEqual(storedMessageIds, ['lark-msg-2']);
@@ -1406,7 +1425,14 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
1406
1425
  sessionKey: 'session:thread-1',
1407
1426
  replyCtx: 'run-1',
1408
1427
  messageId: 'tool-1',
1409
- content: '🔧 bash: completed - Sent file CLAUDE.md to chat-1: msg-file-1',
1428
+ bridgeKind: 'tool',
1429
+ content: 'bash completed',
1430
+ toolCall: {
1431
+ id: 'tool-1',
1432
+ name: 'bash',
1433
+ status: 'completed',
1434
+ output: 'Sent file CLAUDE.md to chat-1: msg-file-1',
1435
+ },
1410
1436
  });
1411
1437
  await gateway.onBridgeEvent({
1412
1438
  type: 'reply',
@@ -1485,25 +1511,30 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
1485
1511
  sessionKey: 'session:thread-1',
1486
1512
  replyCtx: 'run-1',
1487
1513
  previewHandle: 'thought-preview-1',
1488
- content: '💭 先理解',
1514
+ bridgeKind: 'thought',
1515
+ content: '先理解',
1489
1516
  });
1490
1517
  await gateway.onBridgeEvent({
1491
1518
  type: 'update_message',
1492
1519
  sessionKey: 'session:thread-1',
1493
1520
  replyCtx: 'run-1',
1494
1521
  previewHandle: 'thought-preview-1',
1495
- content: '💭 先理解用户需求',
1522
+ bridgeKind: 'thought',
1523
+ content: '先理解用户需求',
1496
1524
  });
1497
1525
  await gateway.onBridgeEvent({
1498
1526
  type: 'reply',
1499
1527
  sessionKey: 'session:thread-1',
1500
1528
  replyCtx: 'run-1',
1501
1529
  messageId: 'run-1-tool-1',
1502
- content: '🔧 Terminal: config - running',
1530
+ bridgeKind: 'tool',
1531
+ content: 'Terminal running',
1503
1532
  toolCall: {
1504
1533
  id: 'call-1',
1505
1534
  name: 'Terminal',
1535
+ status: 'running',
1506
1536
  input: { command: 'uname -a', description: 'Get system info' },
1537
+ output: '',
1507
1538
  },
1508
1539
  });
1509
1540
  await gateway.onBridgeEvent({
@@ -1511,11 +1542,14 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
1511
1542
  sessionKey: 'session:thread-1',
1512
1543
  replyCtx: 'run-1',
1513
1544
  messageId: 'run-1-tool-1',
1514
- content: '🔧 Terminal: config - completed - Linux',
1545
+ bridgeKind: 'tool',
1546
+ content: 'Terminal completed',
1515
1547
  toolCall: {
1516
1548
  id: 'call-1',
1517
1549
  name: 'Terminal',
1550
+ status: 'completed',
1518
1551
  input: { command: 'uname -a', description: 'Get system info' },
1552
+ output: 'Linux',
1519
1553
  },
1520
1554
  });
1521
1555
  await gateway.onBridgeEvent({
@@ -1523,7 +1557,8 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
1523
1557
  sessionKey: 'session:thread-1',
1524
1558
  replyCtx: 'run-1',
1525
1559
  previewHandle: 'thought-preview-1',
1526
- content: '💭 看到了 Linux',
1560
+ bridgeKind: 'thought',
1561
+ content: '看到了 Linux',
1527
1562
  });
1528
1563
  await gateway.onBridgeEvent({
1529
1564
  type: 'reply',
@@ -1532,9 +1567,9 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
1532
1567
  content: '最终回答',
1533
1568
  });
1534
1569
  strict_1.default.deepEqual(createdCards.map((card) => card.text), [
1535
- '💭 先理解用户需求',
1570
+ '先理解用户需求',
1536
1571
  '🔧 Terminal\n\n参数:`{"command":"uname -a","description":"Get system info"}`',
1537
- '💭 看到了 Linux',
1572
+ '看到了 Linux',
1538
1573
  '最终回答',
1539
1574
  ]);
1540
1575
  strict_1.default.deepEqual(patchedCards, []);
@@ -1606,28 +1641,31 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
1606
1641
  sessionKey: 'session:thread-1',
1607
1642
  replyCtx: 'run-1',
1608
1643
  previewHandle: 'thought-preview-1',
1609
- content: '💭 The user',
1644
+ bridgeKind: 'thought',
1645
+ content: 'The user',
1610
1646
  });
1611
1647
  await gateway.onBridgeEvent({
1612
1648
  type: 'update_message',
1613
1649
  sessionKey: 'session:thread-1',
1614
1650
  replyCtx: 'run-1',
1615
1651
  previewHandle: 'thought-preview-1',
1616
- content: '💭 The user sent a short casual message.',
1652
+ bridgeKind: 'thought',
1653
+ content: 'The user sent a short casual message.',
1617
1654
  });
1618
1655
  await gateway.onBridgeEvent({
1619
1656
  type: 'update_message',
1620
1657
  sessionKey: 'session:thread-1',
1621
1658
  replyCtx: 'run-1',
1622
1659
  previewHandle: 'thought-preview-1',
1623
- content: '💭 The user sent a short casual message. I should reply briefly.',
1660
+ bridgeKind: 'thought',
1661
+ content: 'The user sent a short casual message. I should reply briefly.',
1624
1662
  });
1625
1663
  await gateway.onBridgeEvent({
1626
1664
  type: 'typing_stop',
1627
1665
  sessionKey: 'session:thread-1',
1628
1666
  replyCtx: 'run-1',
1629
1667
  });
1630
- strict_1.default.deepEqual(createdCards.map((card) => card.text), ['💭 The user sent a short casual message. I should reply briefly.']);
1668
+ strict_1.default.deepEqual(createdCards.map((card) => card.text), ['The user sent a short casual message. I should reply briefly.']);
1631
1669
  strict_1.default.deepEqual(patchedCards.map((card) => card.text), []);
1632
1670
  strict_1.default.ok(!createdCards.some((card) => /处理中|正在思考/.test(card.text)));
1633
1671
  });
@@ -1905,7 +1943,8 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
1905
1943
  sessionKey: 'session:thread-1',
1906
1944
  replyCtx: 'run-1',
1907
1945
  messageId: 'tool-1',
1908
- content: '🔧 Terminal',
1946
+ bridgeKind: 'tool',
1947
+ content: 'Terminal running',
1909
1948
  toolCall: {
1910
1949
  id: 'tool-1',
1911
1950
  name: 'Terminal',
@@ -1919,7 +1958,8 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
1919
1958
  sessionKey: 'session:thread-1',
1920
1959
  replyCtx: 'run-1',
1921
1960
  messageId: 'tool-1',
1922
- content: '🔧 Terminal: ls ~/Desktop - completed - secret terminal output',
1961
+ bridgeKind: 'tool',
1962
+ content: 'Terminal completed',
1923
1963
  toolCall: {
1924
1964
  id: 'tool-1',
1925
1965
  name: 'Terminal',
@@ -2590,7 +2630,14 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
2590
2630
  sessionKey: 'session-1',
2591
2631
  replyCtx: 'run-1',
2592
2632
  previewHandle: 'tool-1',
2593
- content: '🔧 bash: Tool update - pending',
2633
+ bridgeKind: 'tool',
2634
+ content: 'bash pending',
2635
+ toolCall: {
2636
+ id: 'tool-1',
2637
+ name: 'bash',
2638
+ status: 'pending',
2639
+ output: '',
2640
+ },
2594
2641
  });
2595
2642
  strict_1.default.equal(rendered.text, '');
2596
2643
  strict_1.default.equal(rendered.key, 'noop');
@@ -2599,7 +2646,14 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
2599
2646
  sessionKey: 'session-1',
2600
2647
  replyCtx: 'run-1',
2601
2648
  previewHandle: 'tool-1',
2602
- content: '🔧 bash: Tool update - completed - verbose output',
2649
+ bridgeKind: 'tool',
2650
+ content: 'bash completed',
2651
+ toolCall: {
2652
+ id: 'tool-1',
2653
+ name: 'bash: Tool update',
2654
+ status: 'completed',
2655
+ output: 'verbose output',
2656
+ },
2603
2657
  });
2604
2658
  strict_1.default.equal(completed.text, '🔧 bash: Tool update');
2605
2659
  });
@@ -2773,8 +2827,8 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
2773
2827
  getRun: () => ({ status: 'completed' }),
2774
2828
  },
2775
2829
  workspaceRouter: {
2776
- sendThreadMessage: async (threadId, prompt) => {
2777
- calls.push(`send:${threadId}:${prompt}`);
2830
+ sendThreadMessage: async (threadId, prompt, options) => {
2831
+ calls.push(`send:${threadId}:${prompt}:${options?.permissionMode || ''}`);
2778
2832
  return { runId: 'run-1' };
2779
2833
  },
2780
2834
  getThread: async (threadId) => ({
@@ -2802,7 +2856,7 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
2802
2856
  }, 1000);
2803
2857
  strict_1.default.deepEqual(calls, [
2804
2858
  'before:thread-1',
2805
- 'send:thread-1:ping',
2859
+ 'send:thread-1:ping:bypassPermissions',
2806
2860
  'after:thread-1',
2807
2861
  ]);
2808
2862
  strict_1.default.equal(result.replyText, 'done');
@@ -2837,8 +2891,8 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
2837
2891
  calls.push(`create:${workspaceId}:${title}`);
2838
2892
  return { id: 'thread-local-1', title };
2839
2893
  },
2840
- sendThreadMessage: async (threadId, prompt) => {
2841
- calls.push(`send:${threadId}:${prompt}`);
2894
+ sendThreadMessage: async (threadId, prompt, options) => {
2895
+ calls.push(`send:${threadId}:${prompt}:${options?.permissionMode || ''}`);
2842
2896
  return { runId: 'run-local-1' };
2843
2897
  },
2844
2898
  getThread: async (threadId) => ({
@@ -2853,7 +2907,7 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
2853
2907
  strict_1.default.deepEqual(calls, [
2854
2908
  'list:知识库',
2855
2909
  'create:知识库:[Scheduled] local ping',
2856
- 'send:thread-local-1:ping local',
2910
+ 'send:thread-local-1:ping local:bypassPermissions',
2857
2911
  ]);
2858
2912
  strict_1.default.equal(result.threadId, 'thread-local-1');
2859
2913
  strict_1.default.equal(result.runId, 'run-local-1');
@@ -3635,14 +3689,24 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
3635
3689
  threadId: 'thread-1',
3636
3690
  });
3637
3691
  try {
3638
- await gateway.onBridgeEvent({ type: 'reply', sessionKey: 'session:thread-1', content: '🔧 list desktop' });
3692
+ await gateway.onBridgeEvent({
3693
+ type: 'reply',
3694
+ sessionKey: 'session:thread-1',
3695
+ bridgeKind: 'tool',
3696
+ content: 'list desktop',
3697
+ toolCall: {
3698
+ name: 'list desktop',
3699
+ status: 'running',
3700
+ output: '',
3701
+ },
3702
+ });
3639
3703
  await gateway.onBridgeEvent({ type: 'reply', sessionKey: 'session:thread-1', content: 'final reply' });
3640
3704
  strict_1.default.equal(sentBodies.length, 2);
3641
3705
  strict_1.default.equal(sentBodies[0]?.msg?.message_state, 2);
3642
3706
  strict_1.default.equal(sentBodies[1]?.msg?.message_state, 2);
3643
3707
  strict_1.default.equal(sentBodies[0]?.msg?.context_token, 'ctx-1');
3644
3708
  strict_1.default.equal(sentBodies[1]?.msg?.context_token, 'ctx-1');
3645
- strict_1.default.equal(sentBodies[0]?.msg?.item_list?.[0]?.text_item?.text, '🔧 list desktop');
3709
+ strict_1.default.equal(sentBodies[0]?.msg?.item_list?.[0]?.text_item?.text, '**处理中**\n• list desktop - running');
3646
3710
  strict_1.default.equal(sentBodies[1]?.msg?.item_list?.[0]?.text_item?.text, 'final reply');
3647
3711
  }
3648
3712
  finally {
@@ -3700,7 +3764,13 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
3700
3764
  await gateway.onBridgeEvent({
3701
3765
  type: 'reply',
3702
3766
  sessionKey: 'session:thread-1',
3703
- content: '🔧 Tool update - completed - /Users/mochuxian/Desktop has many files and this result should not be sent',
3767
+ bridgeKind: 'tool',
3768
+ content: 'Tool update completed',
3769
+ toolCall: {
3770
+ name: 'Tool update',
3771
+ status: 'completed',
3772
+ output: '/Users/mochuxian/Desktop has many files and this result should not be sent',
3773
+ },
3704
3774
  });
3705
3775
  await gateway.onBridgeEvent({ type: 'reply', sessionKey: 'session:thread-1', content: 'final reply' });
3706
3776
  strict_1.default.equal(sentBodies.length, 1);
@@ -3762,10 +3832,16 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
3762
3832
  await gateway.onBridgeEvent({
3763
3833
  type: 'reply',
3764
3834
  sessionKey: 'session:thread-1',
3765
- content: '🔧 Tool update - failed - stack trace and command output should not be sent',
3835
+ bridgeKind: 'tool',
3836
+ content: 'Tool update failed',
3837
+ toolCall: {
3838
+ name: 'Tool update',
3839
+ status: 'failed',
3840
+ output: 'stack trace and command output should not be sent',
3841
+ },
3766
3842
  });
3767
3843
  strict_1.default.equal(sentBodies.length, 1);
3768
- strict_1.default.equal(sentBodies[0]?.msg?.item_list?.[0]?.text_item?.text, '🔧 Tool update - failed');
3844
+ strict_1.default.equal(sentBodies[0]?.msg?.item_list?.[0]?.text_item?.text, '**处理中**\n• Tool update - failed');
3769
3845
  }
3770
3846
  finally {
3771
3847
  globalThis.fetch = originalFetch;
@@ -3823,13 +3899,14 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
3823
3899
  await gateway.onBridgeEvent({
3824
3900
  type: 'reply',
3825
3901
  sessionKey: 'session:thread-1',
3902
+ bridgeKind: 'status',
3826
3903
  content: `🔧 tool ${index}`,
3827
3904
  });
3828
3905
  }
3829
3906
  await gateway.onBridgeEvent({ type: 'reply', sessionKey: 'session:thread-1', content: 'final reply' });
3830
3907
  strict_1.default.equal(sentBodies.length, 10);
3831
- strict_1.default.equal(sentBodies[0]?.msg?.item_list?.[0]?.text_item?.text, '🔧 tool 1');
3832
- strict_1.default.equal(sentBodies[8]?.msg?.item_list?.[0]?.text_item?.text, '🔧 tool 9');
3908
+ strict_1.default.equal(sentBodies[0]?.msg?.item_list?.[0]?.text_item?.text, '**处理中**\n• 🔧 tool 1');
3909
+ strict_1.default.match(sentBodies[8]?.msg?.item_list?.[0]?.text_item?.text, /🔧 tool 9/);
3833
3910
  strict_1.default.doesNotMatch(sentBodies.map((body) => body?.msg?.item_list?.[0]?.text_item?.text || '').join('\n'), /🔧 tool 10|🔧 tool 11|🔧 tool 12/);
3834
3911
  strict_1.default.match(sentBodies[9]?.msg?.item_list?.[0]?.text_item?.text, /已省略 3 条过程消息/);
3835
3912
  strict_1.default.match(sentBodies[9]?.msg?.item_list?.[0]?.text_item?.text, /final reply/);