@kafca/agentdock 0.1.23 → 0.1.25

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 (93) hide show
  1. package/README.md +3 -0
  2. package/dist/renderer/assets/{Badge-C2K5apfV.js → Badge-Bn2h-Qkf.js} +1 -1
  3. package/dist/renderer/assets/{Chat-DI2YeVKb.js → Chat-Cgo9aneg.js} +1 -1
  4. package/dist/renderer/assets/{ChatMarkdown-DMAr15Oi.js → ChatMarkdown-CYzHfSiR.js} +1 -1
  5. package/dist/renderer/assets/{Config-7rP3EuUf.js → Config-DljB2-eP.js} +1 -1
  6. package/dist/renderer/assets/{CronList-81QslYE8.js → CronList-DeVbiY9a.js} +1 -1
  7. package/dist/renderer/assets/{Dashboard-Db2T7rSZ.js → Dashboard-fSqx5sm8.js} +2 -2
  8. package/dist/renderer/assets/{EmptyState-BBJ3cTvB.js → EmptyState-DgqKDwlq.js} +1 -1
  9. package/dist/renderer/assets/{KnowledgeDetail-Dz_6flG3.js → KnowledgeDetail-u8s2SmPV.js} +1 -1
  10. package/dist/renderer/assets/{KnowledgeHome-DIh046mN.js → KnowledgeHome-BdQw8nbY.js} +1 -1
  11. package/dist/renderer/assets/{Logs-BXBtHJLf.js → Logs-DSbndMpy.js} +1 -1
  12. package/dist/renderer/assets/{Modal-BB2Av_Xs.js → Modal-0d0EmAuK.js} +1 -1
  13. package/dist/renderer/assets/{Page-DPSdvMgU.js → Page-CVbOH_Kh.js} +1 -1
  14. package/dist/renderer/assets/{ProjectDetail-C6EWGvGg.js → ProjectDetail-C91tF7uA.js} +1 -1
  15. package/dist/renderer/assets/{ProjectList-BBo5ygnS.js → ProjectList-D78Pc-BQ.js} +1 -1
  16. package/dist/renderer/assets/{Select-CNX-Tx_O.js → Select-BbKzAIuO.js} +1 -1
  17. package/dist/renderer/assets/{SessionChat-BIn46jqZ.js → SessionChat-BERvL5e4.js} +1 -1
  18. package/dist/renderer/assets/{SessionList-CZt6f1Rd.js → SessionList-Bomz335M.js} +1 -1
  19. package/dist/renderer/assets/ThreadChat-CLr3amU2.js +23 -0
  20. package/dist/renderer/assets/{Workspace-C_4tdpjX.js → Workspace-In91z4W2.js} +1 -1
  21. package/dist/renderer/assets/{arrow-left-cHr5wkpq.js → arrow-left-FBnVKKBl.js} +1 -1
  22. package/dist/renderer/assets/{book-open-4nx5C8T-.js → book-open-4_CuP6Sa.js} +1 -1
  23. package/dist/renderer/assets/{check-exTS-R-x.js → check-vsoVjvac.js} +1 -1
  24. package/dist/renderer/assets/{chevron-down-DSvxXQa0.js → chevron-down-DFpmFTJW.js} +1 -1
  25. package/dist/renderer/assets/{circle-DyvEovdw.js → circle-vRULegER.js} +1 -1
  26. package/dist/renderer/assets/desktop-BkMW-h5p.js +4 -0
  27. package/dist/renderer/assets/{desktop-B-KVT10D.js → desktop-ul0Tpzyc.js} +1 -1
  28. package/dist/renderer/assets/{funnel-DA9qVdTy.js → funnel-Gu0E_hJ_.js} +1 -1
  29. package/dist/renderer/assets/{heart-DuEV0ZRJ.js → heart-DsdofOHf.js} +1 -1
  30. package/dist/renderer/assets/{index-Biz-aexG.js → index-BD3aCyBa.js} +3 -3
  31. package/dist/renderer/assets/{index-BgflqkCN.js → index-pJUFobU7.js} +1 -1
  32. package/dist/renderer/assets/{pencil-DBDxeNmO.js → pencil-DbKmV8nD.js} +1 -1
  33. package/dist/renderer/assets/{play-IzlP83_7.js → play-BDMsRxSm.js} +1 -1
  34. package/dist/renderer/assets/{plug-CuT-qFnW.js → plug-t2dMl78-.js} +1 -1
  35. package/dist/renderer/assets/{plus-DEqgkn63.js → plus-BUb6zOAe.js} +1 -1
  36. package/dist/renderer/assets/projects-4F6D_Q8t.js +1 -0
  37. package/dist/renderer/assets/{save-D4sRo07y.js → save-C-_5rQdv.js} +1 -1
  38. package/dist/renderer/assets/{search-DbPZLuV8.js → search-R3ekHFPM.js} +1 -1
  39. package/dist/renderer/assets/{server-D1jUQmwN.js → server-BTuvHf5n.js} +1 -1
  40. package/dist/renderer/assets/{session-utils-Aife8ep2.js → session-utils-ClX6VPFG.js} +1 -1
  41. package/dist/renderer/assets/{sessions-DaH3H7gC.js → sessions-AFKIC-ub.js} +1 -1
  42. package/dist/renderer/assets/{shield-check-BGwUFWNr.js → shield-check-CqMW8CHe.js} +1 -1
  43. package/dist/renderer/assets/{trash-2-CIFBioBa.js → trash-2-BNLcHyUw.js} +1 -1
  44. package/dist/renderer/assets/{user-CnKcvHdo.js → user-BCCN8FYK.js} +1 -1
  45. package/dist/renderer/assets/{wifi-off-ClO53WGa.js → wifi-off-BsNsx3oX.js} +1 -1
  46. package/dist/renderer/index.html +1 -1
  47. package/dist-electron/electron/agent-runtime-detector.test.js +64 -0
  48. package/dist-electron/electron/architecture-docs.test.js +56 -0
  49. package/dist-electron/electron/channel-content.test.js +37 -0
  50. package/dist-electron/electron/lac-cli.test.js +297 -4
  51. package/dist-electron/electron/local-core-acp-content.test.js +39 -0
  52. package/dist-electron/electron/local-core-contracts.test.js +67 -0
  53. package/dist-electron/electron/local-core-refactor.test.js +789 -3
  54. package/dist-electron/electron/plugin-kernel.test.js +108 -0
  55. package/dist-electron/electron/renderer-packaging.test.js +77 -0
  56. package/dist-electron/electron/workspace-task-store.test.js +181 -0
  57. package/dist-electron/packages/contracts/src/local-core.js +110 -0
  58. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-backend.js +67 -6
  59. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-content.js +25 -4
  60. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-permission-lifecycle.js +76 -0
  61. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-progress.js +201 -0
  62. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-response-processor.js +3 -2
  63. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-session-coordinator.js +29 -0
  64. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-store.js +74 -46
  65. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-turn-coordinator.js +112 -210
  66. package/dist-electron/services/local-ai-core/src/acp/local-core-slash-commands.js +60 -0
  67. package/dist-electron/services/local-ai-core/src/acp/workspace-acp-permissions.js +5 -48
  68. package/dist-electron/services/local-ai-core/src/channel/lark/local-core-lark-gateway.js +83 -28
  69. package/dist-electron/services/local-ai-core/src/channel/lark/runtime-state.js +11 -0
  70. package/dist-electron/services/local-ai-core/src/channel/shared/content.js +23 -0
  71. package/dist-electron/services/local-ai-core/src/channel/shared/file-utils.js +13 -1
  72. package/dist-electron/services/local-ai-core/src/channel/weixin/local-core-weixin-gateway.js +31 -29
  73. package/dist-electron/services/local-ai-core/src/cli/lac.js +22 -17
  74. package/dist-electron/services/local-ai-core/src/kernel/bootstrap.js +1 -0
  75. package/dist-electron/services/local-ai-core/src/plugins/builtin/agent-localcore-acp-plugin.js +9 -0
  76. package/dist-electron/services/local-ai-core/src/router/workspace-route-config.js +221 -10
  77. package/dist-electron/services/local-ai-core/src/runtime/agent-runtime-detector.js +39 -9
  78. package/dist-electron/services/local-ai-core/src/runtime/local-core-controller.js +1 -0
  79. package/dist-electron/services/local-ai-core/src/runtime/runtime-detection-service.js +1 -0
  80. package/dist-electron/services/local-ai-core/src/runtime/server-routes.js +439 -0
  81. package/dist-electron/services/local-ai-core/src/runtime/server.js +208 -303
  82. package/dist-electron/services/local-ai-core/src/scheduler/job-id.js +15 -0
  83. package/dist-electron/services/local-ai-core/src/scheduler/scheduler-service.js +30 -5
  84. package/dist-electron/shared/desktop.js +34 -8
  85. package/dist-electron/src/pages/Threads/thread-chat-message-blocks.js +187 -0
  86. package/dist-electron/src/pages/Threads/thread-chat-model.js +58 -0
  87. package/dist-electron/src/pages/Threads/thread-chat-page-state.js +96 -0
  88. package/dist-electron/src/pages/Threads/thread-chat-permission.js +18 -0
  89. package/dist-electron/src/pages/Threads/thread-chat-permission.test.js +347 -0
  90. package/package.json +4 -2
  91. package/dist/renderer/assets/ThreadChat-BotD0gKQ.js +0 -23
  92. package/dist/renderer/assets/desktop-CVibRyAw.js +0 -4
  93. package/dist/renderer/assets/projects-DDtDN1rc.js +0 -1
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createScheduledJobId = createScheduledJobId;
4
+ exports.toPublicScheduledJobId = toPublicScheduledJobId;
5
+ const node_crypto_1 = require("node:crypto");
6
+ function createScheduledJobId() {
7
+ return (0, node_crypto_1.randomUUID)().split('-')[0] || (0, node_crypto_1.randomUUID)();
8
+ }
9
+ function toPublicScheduledJobId(jobId) {
10
+ const normalized = jobId.startsWith('job:') ? jobId.slice(4) : jobId;
11
+ if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(normalized)) {
12
+ return normalized.split('-')[0] || normalized;
13
+ }
14
+ return normalized;
15
+ }
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SchedulerService = void 0;
4
4
  const node_events_1 = require("node:events");
5
+ const job_id_js_1 = require("./job-id.js");
5
6
  const scheduler_run_lifecycle_js_1 = require("./scheduler-run-lifecycle.js");
6
7
  class SchedulerService extends node_events_1.EventEmitter {
7
8
  options;
@@ -34,7 +35,8 @@ class SchedulerService extends node_events_1.EventEmitter {
34
35
  return this.options.store.listScheduledJobs(workspaceId);
35
36
  }
36
37
  getJob(jobId) {
37
- return this.options.store.getScheduledJob(jobId);
38
+ const resolvedJobId = this.resolveJobId(jobId);
39
+ return resolvedJobId ? this.options.store.getScheduledJob(resolvedJobId) : undefined;
38
40
  }
39
41
  createJob(input) {
40
42
  const job = this.options.store.createScheduledJob(input);
@@ -43,24 +45,47 @@ class SchedulerService extends node_events_1.EventEmitter {
43
45
  return job;
44
46
  }
45
47
  updateJob(jobId, input) {
46
- const job = this.options.store.updateScheduledJob(jobId, input);
48
+ const job = this.options.store.updateScheduledJob(this.resolveRequiredJobId(jobId), input);
47
49
  this.emit('job', job);
48
50
  this.options.eventBus.emit({ type: 'scheduler.job.updated', payload: job });
49
51
  return job;
50
52
  }
51
53
  deleteJob(jobId) {
52
- return this.options.store.deleteScheduledJob(jobId);
54
+ return this.options.store.deleteScheduledJob(this.resolveRequiredJobId(jobId));
53
55
  }
54
56
  listJobRuns(jobId) {
55
- return this.options.store.listScheduledJobRuns(jobId);
57
+ return this.options.store.listScheduledJobRuns(this.resolveRequiredJobId(jobId));
56
58
  }
57
59
  async runJobNow(jobId) {
58
- const job = this.options.store.getScheduledJob(jobId);
60
+ const resolvedJobId = this.resolveRequiredJobId(jobId);
61
+ const job = this.options.store.getScheduledJob(resolvedJobId);
59
62
  if (!job) {
60
63
  throw new Error(`Scheduled job not found: ${jobId}`);
61
64
  }
62
65
  return this.executeJob(job, new Date().toISOString(), true);
63
66
  }
67
+ resolveJobId(jobId) {
68
+ if (this.options.store.getScheduledJob(jobId)) {
69
+ return jobId;
70
+ }
71
+ const matches = this.options.store
72
+ .listScheduledJobs()
73
+ .filter((job) => (0, job_id_js_1.toPublicScheduledJobId)(job.id) === jobId);
74
+ if (matches.length === 0) {
75
+ return '';
76
+ }
77
+ if (matches.length > 1) {
78
+ throw new Error(`Scheduled job id is ambiguous: ${jobId}`);
79
+ }
80
+ return matches[0].id;
81
+ }
82
+ resolveRequiredJobId(jobId) {
83
+ const resolvedJobId = this.resolveJobId(jobId);
84
+ if (!resolvedJobId) {
85
+ throw new Error(`Scheduled job not found: ${jobId}`);
86
+ }
87
+ return resolvedJobId;
88
+ }
64
89
  async tick() {
65
90
  if (this.pollInFlight) {
66
91
  return;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CHANNEL_PROTOCOL_INSTRUCTION = exports.SCHEDULER_PROTOCOL_INSTRUCTION = exports.LOCALCORE_ACP_AGENT_TYPE = exports.DESKTOP_INTERACTIVE_PERMISSION_AGENT_TYPES = exports.DESKTOP_PROVIDER_THINKING_OPTIONS = exports.DESKTOP_PROVIDER_PRESET_OPTIONS = exports.DESKTOP_PLATFORM_TYPE_OPTIONS = exports.DESKTOP_AGENT_TYPE_OPTIONS = exports.DESKTOP_LARK_SDK_PACKAGE = exports.DESKTOP_CLAUDECODE_ACP_PACKAGE = exports.DESKTOP_CODEX_ACP_PACKAGE = exports.DEFAULT_DESKTOP_CLAUDECODE_MODEL = exports.DEFAULT_DESKTOP_OPENCODE_MODEL = exports.DEFAULT_DESKTOP_AGENT_TYPE = void 0;
3
+ exports.CHANNEL_PROTOCOL_INSTRUCTION = exports.SCHEDULER_PROTOCOL_INSTRUCTION = exports.LOCALCORE_ACP_AGENT_TYPE = exports.DESKTOP_INTERACTIVE_PERMISSION_AGENT_TYPES = exports.DESKTOP_PROVIDER_THINKING_OPTIONS = exports.DESKTOP_PROVIDER_PRESET_OPTIONS = exports.DESKTOP_PLATFORM_TYPE_OPTIONS = exports.DESKTOP_AGENT_TYPE_OPTIONS = exports.DESKTOP_LARK_SDK_PACKAGE = exports.DESKTOP_CLAUDECODE_ACP_PACKAGE = exports.DESKTOP_CODEX_ACP_PACKAGE = exports.DESKTOP_PI_CODING_AGENT_PACKAGE = exports.DESKTOP_PI_ACP_PACKAGE = exports.DEFAULT_DESKTOP_CLAUDECODE_MODEL = exports.DEFAULT_DESKTOP_OPENCODE_MODEL = exports.DEFAULT_DESKTOP_AGENT_TYPE = void 0;
4
4
  exports.deriveDesktopRuntimePhase = deriveDesktopRuntimePhase;
5
5
  exports.deriveDesktopRuntimeRoles = deriveDesktopRuntimeRoles;
6
6
  exports.normalizeDesktopPlatformType = normalizeDesktopPlatformType;
@@ -12,13 +12,16 @@ exports.isPermissionButtonOption = isPermissionButtonOption;
12
12
  exports.normalizeDesktopBridgeButtonOption = normalizeDesktopBridgeButtonOption;
13
13
  exports.supportsInteractivePermission = supportsInteractivePermission;
14
14
  exports.isAcpAgentType = isAcpAgentType;
15
- exports.DEFAULT_DESKTOP_AGENT_TYPE = 'opencode';
15
+ exports.DEFAULT_DESKTOP_AGENT_TYPE = 'pi';
16
16
  exports.DEFAULT_DESKTOP_OPENCODE_MODEL = 'opencode/minimax-m2.5-free';
17
17
  exports.DEFAULT_DESKTOP_CLAUDECODE_MODEL = '';
18
+ exports.DESKTOP_PI_ACP_PACKAGE = 'pi-acp';
19
+ exports.DESKTOP_PI_CODING_AGENT_PACKAGE = '@mariozechner/pi-coding-agent';
18
20
  exports.DESKTOP_CODEX_ACP_PACKAGE = '@zed-industries/codex-acp';
19
21
  exports.DESKTOP_CLAUDECODE_ACP_PACKAGE = '@agentclientprotocol/claude-agent-acp';
20
22
  exports.DESKTOP_LARK_SDK_PACKAGE = '@larksuiteoapi/node-sdk';
21
23
  exports.DESKTOP_AGENT_TYPE_OPTIONS = [
24
+ 'pi',
22
25
  'opencode',
23
26
  'codex',
24
27
  'claudecode',
@@ -53,7 +56,7 @@ exports.DESKTOP_PROVIDER_PRESET_OPTIONS = [
53
56
  'ollama',
54
57
  ];
55
58
  exports.DESKTOP_PROVIDER_THINKING_OPTIONS = ['', 'enabled', 'disabled'];
56
- exports.DESKTOP_INTERACTIVE_PERMISSION_AGENT_TYPES = ['opencode', 'codex', 'claudecode', 'acp', 'localcore-acp'];
59
+ exports.DESKTOP_INTERACTIVE_PERMISSION_AGENT_TYPES = ['pi', 'opencode', 'codex', 'claudecode', 'acp', 'localcore-acp'];
57
60
  exports.LOCALCORE_ACP_AGENT_TYPE = 'localcore-acp';
58
61
  exports.SCHEDULER_PROTOCOL_INSTRUCTION = [
59
62
  '[Scheduler Tools]',
@@ -62,13 +65,14 @@ exports.SCHEDULER_PROTOCOL_INSTRUCTION = [
62
65
  'lac scheduler add --cron "<5-field cron>" --message "<exact message to send>" --desc "<short label>" [--execution-mode same-thread|side-thread]',
63
66
  'lac scheduler list',
64
67
  'lac scheduler list --thread',
65
- 'lac scheduler info <job-id>',
66
- 'lac scheduler edit <job-id> [--cron "<5-field cron>"] [--message "<exact message>"] [--desc "<short label>"] [--enabled true|false] [--execution-mode same-thread|side-thread]',
67
- 'lac scheduler del <job-id>',
68
- 'lac scheduler run <job-id>',
68
+ 'lac scheduler info <short-job-id>',
69
+ 'lac scheduler edit <short-job-id> [--cron "<5-field cron>"] [--message "<exact message>"] [--desc "<short label>"] [--enabled true|false] [--execution-mode same-thread|side-thread]',
70
+ 'lac scheduler del <short-job-id>',
71
+ 'lac scheduler run <short-job-id>',
69
72
  'Environment variables LOCAL_AI_WORKSPACE_ID, LOCAL_AI_THREAD_ID, LOCAL_AI_PLATFORM, LOCAL_AI_CHAT_ID, and LOCAL_AI_PLATFORM_USER_ID are already set when available.',
70
73
  'Prefer relying on those variables instead of inventing your own route or creating session-only cron jobs.',
71
74
  'By default, `lac scheduler list` shows all scheduled tasks in the current workspace. Use `lac scheduler list --thread` to show only the current conversation thread.',
75
+ 'Use the short job id shown by `lac scheduler list`; do not add a `job:` prefix or expand it to a full UUID.',
72
76
  'Use `--execution-mode same-thread` to reuse the current thread, or `--execution-mode side-thread` to run in a dedicated scheduled thread.',
73
77
  'Only use the scheduler CLI when the user explicitly asks for scheduled automation.',
74
78
  '[/Scheduler Tools]',
@@ -169,7 +173,28 @@ function normalizePermissionResponse(input) {
169
173
  if (!input) {
170
174
  return null;
171
175
  }
172
- return PERMISSION_RESPONSE_MAP[String(input).trim().toLowerCase()] || null;
176
+ const normalized = String(input).trim().toLowerCase();
177
+ const mapped = PERMISSION_RESPONSE_MAP[normalized];
178
+ if (mapped) {
179
+ return mapped;
180
+ }
181
+ if (normalized.includes('allow_all') ||
182
+ normalized.includes('allow-always') ||
183
+ normalized.includes('allow_always') ||
184
+ normalized.includes('allow always') ||
185
+ normalized.includes('always allow') ||
186
+ normalized.includes('allow all') ||
187
+ normalized.includes('始终允许') ||
188
+ normalized.includes('永久允许')) {
189
+ return 'allow all';
190
+ }
191
+ if (normalized.startsWith('reject') || normalized.startsWith('deny')) {
192
+ return 'deny';
193
+ }
194
+ if (normalized.startsWith('allow')) {
195
+ return 'allow';
196
+ }
197
+ return null;
173
198
  }
174
199
  function isPermissionButtonOption(option) {
175
200
  return Boolean(normalizePermissionResponse(option?.data));
@@ -213,6 +238,7 @@ function supportsInteractivePermission(agentType) {
213
238
  function isAcpAgentType(agentType) {
214
239
  const normalized = String(agentType || '').trim().toLowerCase();
215
240
  return normalized === 'acp'
241
+ || normalized === 'pi'
216
242
  || normalized === 'opencode'
217
243
  || normalized === 'codex'
218
244
  || normalized === 'claudecode'
@@ -0,0 +1,187 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isInteractivePermissionMessage = isInteractivePermissionMessage;
4
+ exports.parseToolResultCard = parseToolResultCard;
5
+ exports.toolCallToResultCard = toolCallToResultCard;
6
+ exports.isEmptyRunningToolUpdateContent = isEmptyRunningToolUpdateContent;
7
+ exports.isHiddenProgressMessage = isHiddenProgressMessage;
8
+ exports.shouldCollapseToolResultByDefault = shouldCollapseToolResultByDefault;
9
+ exports.parsePermissionCardContent = parsePermissionCardContent;
10
+ const thread_chat_permission_1 = require("./thread-chat-permission");
11
+ function isInteractivePermissionMessage(message, pendingPermissionRequest) {
12
+ if (message.role === 'system') {
13
+ return false;
14
+ }
15
+ return (0, thread_chat_permission_1.isStructuredPermissionMessage)({
16
+ id: message.id,
17
+ role: message.role,
18
+ actionMode: message.actionMode,
19
+ actionInteractive: message.actionInteractive,
20
+ }, pendingPermissionRequest);
21
+ }
22
+ function parseToolResultCard(content) {
23
+ const statusFirstMatch = content.match(/^\s*🔧\s*(.+?)\s*:\s*(running|completed|failed|error|cancelled|canceled)(?:\s*-\s*([\s\S]+?))?\s*$/i);
24
+ if (statusFirstMatch) {
25
+ const [, toolName, status, payload = ''] = statusFirstMatch;
26
+ return {
27
+ title: toolName.trim() || 'Tool call',
28
+ status: status.trim(),
29
+ output: parseToolResultPayload(payload),
30
+ label: /^running$/i.test(status) ? '工具调用' : '工具结果',
31
+ };
32
+ }
33
+ const namedStatusMatch = content.match(/^\s*🔧\s*(.+?)\s*:\s*([\s\S]*?)\s*-\s*(running|completed|failed|error|cancelled|canceled)(?:\s*-\s*([\s\S]+?))?\s*$/i);
34
+ if (namedStatusMatch) {
35
+ const [, toolName, detail, status, payload = ''] = namedStatusMatch;
36
+ const trimmedDetail = detail.trim();
37
+ return {
38
+ title: toolName.trim() || 'Tool call',
39
+ status: status.trim(),
40
+ output: parseToolResultPayload(payload),
41
+ label: /^running$/i.test(status) ? '工具调用' : '工具结果',
42
+ subtitle: trimmedDetail || undefined,
43
+ };
44
+ }
45
+ const namedUpdateMatch = content.match(/^\s*🔧\s*(.+?)\s*:\s*(Tool update)\s*-\s*([^-]+?)\s*-\s*([\s\S]+?)\s*$/i);
46
+ if (namedUpdateMatch) {
47
+ const [, toolName, updateTitle, status, payload] = namedUpdateMatch;
48
+ const trimmedPayload = payload.trim();
49
+ try {
50
+ const parsed = JSON.parse(trimmedPayload);
51
+ const value = typeof parsed.output === 'string'
52
+ ? parsed.output
53
+ : parsed.output ?? parsed.error ?? parsed;
54
+ return {
55
+ title: toolName.trim() || updateTitle,
56
+ status: status.trim(),
57
+ output: typeof value === 'string' ? value : JSON.stringify(value, null, 2),
58
+ label: '工具结果',
59
+ };
60
+ }
61
+ catch {
62
+ return {
63
+ title: toolName.trim() || updateTitle,
64
+ status: status.trim(),
65
+ output: trimmedPayload,
66
+ label: '工具结果',
67
+ };
68
+ }
69
+ }
70
+ const updateMatch = content.match(/^\s*(?:🔧\s*)?(Tool update)\s*-\s*([^-]+?)\s*-\s*([\s\S]+?)\s*$/i);
71
+ if (updateMatch) {
72
+ const [, title, status, payload] = updateMatch;
73
+ const trimmedPayload = payload.trim();
74
+ if (isEmptyRunningToolUpdateContent(title, status.trim(), trimmedPayload)) {
75
+ return null;
76
+ }
77
+ try {
78
+ const parsed = JSON.parse(trimmedPayload);
79
+ const value = typeof parsed.output === 'string'
80
+ ? parsed.output
81
+ : parsed.output ?? parsed.error ?? parsed;
82
+ return {
83
+ title,
84
+ status: status.trim(),
85
+ output: typeof value === 'string' ? value : JSON.stringify(value, null, 2),
86
+ label: '工具结果',
87
+ };
88
+ }
89
+ catch {
90
+ return {
91
+ title,
92
+ status: status.trim(),
93
+ output: trimmedPayload,
94
+ label: '工具结果',
95
+ };
96
+ }
97
+ }
98
+ const callMatch = content.match(/^\s*🔧\s*(.+?)\s*$/);
99
+ if (callMatch) {
100
+ const rawTitle = callMatch[1].trim();
101
+ if (/^Tool update\s*-\s*running(?:\s*-\s*)?$/i.test(rawTitle)) {
102
+ return null;
103
+ }
104
+ const [name, ...rest] = rawTitle.split(':');
105
+ const output = rest.join(':').trim();
106
+ const statusMatch = output.match(/^(.*?)\s*-\s*(running|completed|failed|error|cancelled|canceled)\s*$/i);
107
+ return {
108
+ title: name.trim() || 'Tool call',
109
+ status: statusMatch?.[2]?.trim() || 'running',
110
+ output: statusMatch?.[1]?.trim() || output,
111
+ label: statusMatch && !/^running$/i.test(statusMatch[2]) ? '工具结果' : '工具调用',
112
+ };
113
+ }
114
+ return null;
115
+ }
116
+ function toolCallToResultCard(toolCall) {
117
+ if (!toolCall) {
118
+ return null;
119
+ }
120
+ const status = toolCall.status.trim() || 'running';
121
+ return {
122
+ title: toolCall.name.trim() || 'Tool call',
123
+ status,
124
+ output: toolCall.output || '',
125
+ label: toolCall.label || (/^running$/i.test(status) ? '工具调用' : '工具结果'),
126
+ subtitle: toolCall.detail?.trim() || summarizeToolCallInput(toolCall.input),
127
+ };
128
+ }
129
+ function summarizeToolCallInput(input) {
130
+ if (!input || typeof input !== 'object') {
131
+ return typeof input === 'string' && input.trim() ? input.trim() : undefined;
132
+ }
133
+ const record = input;
134
+ for (const key of ['command', 'cmd', 'path', 'file', 'query']) {
135
+ const value = record[key];
136
+ if (typeof value === 'string' && value.trim()) {
137
+ return value.trim();
138
+ }
139
+ }
140
+ const entries = Object.entries(record)
141
+ .filter(([, value]) => value !== undefined && value !== null && value !== '')
142
+ .slice(0, 2)
143
+ .map(([key, value]) => `${key}: ${typeof value === 'string' ? value : JSON.stringify(value)}`);
144
+ return entries.length > 0 ? entries.join(', ') : undefined;
145
+ }
146
+ function parseToolResultPayload(payload) {
147
+ const trimmedPayload = payload.trim();
148
+ if (!trimmedPayload) {
149
+ return '';
150
+ }
151
+ try {
152
+ const parsed = JSON.parse(trimmedPayload);
153
+ const value = typeof parsed.output === 'string'
154
+ ? parsed.output
155
+ : parsed.output ?? parsed.error ?? parsed;
156
+ return typeof value === 'string' ? value : JSON.stringify(value, null, 2);
157
+ }
158
+ catch {
159
+ return trimmedPayload;
160
+ }
161
+ }
162
+ function isEmptyRunningToolUpdateContent(title, status, payload) {
163
+ return /^Tool update$/i.test(title.trim()) && /^running$/i.test(status.trim()) && !payload.trim();
164
+ }
165
+ function isHiddenProgressMessage(content) {
166
+ const normalized = content.trim();
167
+ return /^🔧\s*Tool update\s*-\s*running(?:\s*-\s*)?$/i.test(normalized);
168
+ }
169
+ function shouldCollapseToolResultByDefault(card) {
170
+ return card.label === '工具结果' && Boolean(card.output.trim());
171
+ }
172
+ function parsePermissionCardContent(content) {
173
+ const lines = content
174
+ .split('\n')
175
+ .map((line) => line.trim())
176
+ .filter(Boolean);
177
+ const fallbackIndex = lines.findIndex((line) => line.includes('若按钮没有显示'));
178
+ const visibleLines = fallbackIndex >= 0 ? lines.slice(0, fallbackIndex) : lines;
179
+ const title = visibleLines[0] || '等待工具确认';
180
+ const bodyLines = visibleLines
181
+ .slice(1)
182
+ .filter((line) => !line.includes('请选择一个选项继续执行'));
183
+ return {
184
+ title,
185
+ bodyLines,
186
+ };
187
+ }
@@ -5,6 +5,9 @@ exports.isInternalProgressMessage = isInternalProgressMessage;
5
5
  exports.isAwaitingInputMessage = isAwaitingInputMessage;
6
6
  exports.findStreamingPreviewMessage = findStreamingPreviewMessage;
7
7
  exports.shouldReplacePreviewWithReply = shouldReplacePreviewWithReply;
8
+ exports.advancePreviewContent = advancePreviewContent;
9
+ exports.settlePreviewMessages = settlePreviewMessages;
10
+ exports.finalizeTurnMessageKinds = finalizeTurnMessageKinds;
8
11
  exports.extractVisibleMessageContent = extractVisibleMessageContent;
9
12
  exports.sessionMatchesDesktop = sessionMatchesDesktop;
10
13
  exports.toMessages = toMessages;
@@ -65,6 +68,60 @@ function shouldReplacePreviewWithReply(message, replyContent, replyCtx) {
65
68
  const content = message.streamTargetContent ?? message.content;
66
69
  return Boolean(replyContent && content === replyContent && !isInternalProgressMessage(content));
67
70
  }
71
+ function advancePreviewContent(content, target) {
72
+ if (!target) {
73
+ return '';
74
+ }
75
+ if (!content || !target.startsWith(content)) {
76
+ return target.slice(0, Math.min(target.length, Math.max(1, Math.ceil(target.length / 24))));
77
+ }
78
+ if (content === target) {
79
+ return target;
80
+ }
81
+ const remaining = target.length - content.length;
82
+ const step = remaining > 160 ? 14 : remaining > 80 ? 8 : remaining > 24 ? 4 : 2;
83
+ return target.slice(0, Math.min(target.length, content.length + step));
84
+ }
85
+ function settlePreviewMessages(messages, turnKey) {
86
+ let changed = false;
87
+ const next = messages.map((message) => {
88
+ if (!message.preview) {
89
+ return message;
90
+ }
91
+ if (turnKey && message.turnKey !== turnKey) {
92
+ return message;
93
+ }
94
+ changed = true;
95
+ return {
96
+ ...message,
97
+ content: message.streamTargetContent ?? message.content,
98
+ streamTargetContent: undefined,
99
+ preview: false,
100
+ previewPlainText: false,
101
+ };
102
+ });
103
+ return changed ? next : messages;
104
+ }
105
+ function finalizeTurnMessageKinds(messages, turnKey) {
106
+ if (!turnKey) {
107
+ return messages;
108
+ }
109
+ const candidates = messages.filter((message) => message.turnKey === turnKey && !message.preview);
110
+ if (candidates.length === 0) {
111
+ return messages;
112
+ }
113
+ const finalMessage = [...candidates].reverse().find((message) => !isInternalProgressMessage(message.content));
114
+ const finalId = finalMessage?.id;
115
+ return messages.map((message) => {
116
+ if (message.turnKey !== turnKey || message.preview) {
117
+ return message;
118
+ }
119
+ return {
120
+ ...message,
121
+ kind: finalId && message.id === finalId ? 'final' : 'progress',
122
+ };
123
+ });
124
+ }
68
125
  function extractVisibleMessageContent(content) {
69
126
  if (!content) {
70
127
  return '';
@@ -93,6 +150,7 @@ function toMessagesFromThread(history) {
93
150
  id: message.id || `${index}-${message.timestamp || message.role}`,
94
151
  role: message.role === 'user' ? 'user' : message.role === 'system' ? 'system' : 'assistant',
95
152
  content: message.role === 'user' ? extractVisibleMessageContent(message.content) : message.content,
153
+ toolCall: message.toolCall,
96
154
  kind: message.kind === 'progress'
97
155
  ? 'progress'
98
156
  : message.kind === 'system'
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toSelectedKnowledgeBases = toSelectedKnowledgeBases;
4
+ exports.filterKnowledgeBases = filterKnowledgeBases;
5
+ exports.orderKnowledgeBases = orderKnowledgeBases;
6
+ exports.getVisibleSessionGroups = getVisibleSessionGroups;
7
+ exports.getVisibleProjects = getVisibleProjects;
8
+ exports.hasVisibleSessions = hasVisibleSessions;
9
+ exports.toComposerPermissionCard = toComposerPermissionCard;
10
+ exports.shouldRenderThreadChatMessage = shouldRenderThreadChatMessage;
11
+ exports.getComposerPlaceholder = getComposerPlaceholder;
12
+ exports.canSubmitComposer = canSubmitComposer;
13
+ const thread_chat_message_blocks_1 = require("./thread-chat-message-blocks");
14
+ function toSelectedKnowledgeBases(knowledgeBaseIds, availableKnowledgeBases) {
15
+ return knowledgeBaseIds.map((knowledgeBaseId) => {
16
+ const matched = availableKnowledgeBases.find((base) => base.id === knowledgeBaseId);
17
+ return {
18
+ id: knowledgeBaseId,
19
+ name: matched?.name || knowledgeBaseId,
20
+ fileCount: matched?.fileCount || 0,
21
+ };
22
+ });
23
+ }
24
+ function filterKnowledgeBases(knowledgeBases, search) {
25
+ const query = search.trim().toLowerCase();
26
+ if (!query) {
27
+ return knowledgeBases;
28
+ }
29
+ return knowledgeBases.filter((base) => [base.name, base.description, base.id].join(' ').toLowerCase().includes(query));
30
+ }
31
+ function orderKnowledgeBases(knowledgeBases, selectedKnowledgeBaseIds) {
32
+ const selectedIds = new Set(selectedKnowledgeBaseIds);
33
+ return [...knowledgeBases].sort((a, b) => {
34
+ const aSelected = selectedIds.has(a.id);
35
+ const bSelected = selectedIds.has(b.id);
36
+ if (aSelected !== bSelected) {
37
+ return aSelected ? -1 : 1;
38
+ }
39
+ return a.name.localeCompare(b.name, 'zh-CN');
40
+ });
41
+ }
42
+ function getVisibleSessionGroups(sessionGroups, selectedProject) {
43
+ if (!selectedProject) {
44
+ return sessionGroups;
45
+ }
46
+ return sessionGroups.filter((group) => group.project === selectedProject);
47
+ }
48
+ function getVisibleProjects(projects, selectedProject) {
49
+ return selectedProject && !projects.includes(selectedProject) ? [selectedProject, ...projects] : projects;
50
+ }
51
+ function hasVisibleSessions(sessionGroups) {
52
+ return sessionGroups.some((group) => group.sessions.length > 0);
53
+ }
54
+ function toComposerPermissionCard(pendingPermissionRequest) {
55
+ if (!pendingPermissionRequest) {
56
+ return null;
57
+ }
58
+ return {
59
+ id: pendingPermissionRequest.id,
60
+ content: pendingPermissionRequest.content,
61
+ actions: pendingPermissionRequest.actions,
62
+ actionReplyCtx: pendingPermissionRequest.actionReplyCtx,
63
+ actionPending: pendingPermissionRequest.actionPending,
64
+ actionStatus: pendingPermissionRequest.actionStatus,
65
+ actionMode: 'permission',
66
+ actionInteractive: true,
67
+ };
68
+ }
69
+ function shouldRenderThreadChatMessage(message, composerPermissionCard) {
70
+ if (message.kind === 'progress' && (0, thread_chat_message_blocks_1.isHiddenProgressMessage)(message.content)) {
71
+ return false;
72
+ }
73
+ return !(0, thread_chat_message_blocks_1.isInteractivePermissionMessage)(message, composerPermissionCard);
74
+ }
75
+ function getComposerPlaceholder(input) {
76
+ if (!input.serviceRunning) {
77
+ return input.startFirstPlaceholder;
78
+ }
79
+ if (!input.transportReady) {
80
+ return input.waitingRuntimePlaceholder;
81
+ }
82
+ if (input.taskState === 'awaiting_input') {
83
+ return 'Agent 正在等待你的回复,可直接继续输入。';
84
+ }
85
+ if (input.taskInputLocked) {
86
+ return '任务正在运行,点击停止可中断当前执行。';
87
+ }
88
+ return input.sendPlaceholder;
89
+ }
90
+ function canSubmitComposer(input) {
91
+ return Boolean(input.draft.trim() &&
92
+ input.serviceRunning &&
93
+ input.transportReady &&
94
+ !input.sending &&
95
+ input.selectedProject);
96
+ }
@@ -1,10 +1,20 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.permissionSubmittedStatus = void 0;
3
4
  exports.shouldEchoBridgeActionResponse = shouldEchoBridgeActionResponse;
5
+ exports.isStructuredPermissionMessage = isStructuredPermissionMessage;
4
6
  exports.toPendingPermissionRequest = toPendingPermissionRequest;
7
+ exports.markPermissionMessageSubmitted = markPermissionMessageSubmitted;
8
+ exports.permissionSubmittedStatus = 'Permission sent. Waiting for the agent to continue…';
5
9
  function shouldEchoBridgeActionResponse(message) {
6
10
  return !(message.actionMode === 'permission' && message.actionInteractive);
7
11
  }
12
+ function isStructuredPermissionMessage(message, pendingPermissionRequest) {
13
+ if (pendingPermissionRequest?.id === message.id) {
14
+ return true;
15
+ }
16
+ return message.role !== 'user' && message.actionMode === 'permission' && Boolean(message.actionInteractive);
17
+ }
8
18
  function toPendingPermissionRequest(message) {
9
19
  if (!message.id ||
10
20
  message.role !== 'assistant' ||
@@ -28,3 +38,11 @@ function toPendingPermissionRequest(message) {
28
38
  actionInteractive: true,
29
39
  };
30
40
  }
41
+ function markPermissionMessageSubmitted(message) {
42
+ return {
43
+ ...message,
44
+ actions: [],
45
+ actionPending: false,
46
+ actionStatus: exports.permissionSubmittedStatus,
47
+ };
48
+ }