@kafca/agentdock 0.1.30 → 0.1.31

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 (92) hide show
  1. package/README.md +4 -0
  2. package/dist/renderer/assets/{Badge-DlVJI1Ys.js → Badge-DaHt-aUT.js} +1 -1
  3. package/dist/renderer/assets/{Chat-oa8OjaHQ.js → Chat-Dzeq3kiD.js} +1 -1
  4. package/dist/renderer/assets/{ChatMarkdown-C-N8KS5C.js → ChatMarkdown-B-L5Roai.js} +1 -1
  5. package/dist/renderer/assets/{Config-D9sL_d4D.js → Config-BI4LJ7Fw.js} +1 -1
  6. package/dist/renderer/assets/{CronList-Z5JU3DHk.js → CronList-Dic7pblj.js} +1 -1
  7. package/dist/renderer/assets/{Dashboard-D3BwbG43.js → Dashboard-C0_ATyGe.js} +2 -2
  8. package/dist/renderer/assets/{EmptyState-QOj765Ul.js → EmptyState-SQsG1DZP.js} +1 -1
  9. package/dist/renderer/assets/{KnowledgeDetail-J7n01mPu.js → KnowledgeDetail-D4yUJzp7.js} +1 -1
  10. package/dist/renderer/assets/{KnowledgeHome-BFnH0NVk.js → KnowledgeHome-L0tsg-oo.js} +1 -1
  11. package/dist/renderer/assets/{Logs-DfSUifXc.js → Logs-C2Jdr3uQ.js} +1 -1
  12. package/dist/renderer/assets/{Modal-QjEGhyru.js → Modal-GUH3iPXo.js} +1 -1
  13. package/dist/renderer/assets/{Page-qdHFSw7x.js → Page-m42FBy97.js} +1 -1
  14. package/dist/renderer/assets/{ProjectDetail-DS_rfvhh.js → ProjectDetail-RF_sagPO.js} +1 -1
  15. package/dist/renderer/assets/{ProjectList-COtyZd7H.js → ProjectList-Cyr8RDK3.js} +1 -1
  16. package/dist/renderer/assets/{Select-BQ8mncVu.js → Select-CRlDgI5s.js} +1 -1
  17. package/dist/renderer/assets/{SessionChat-DjVnjuQy.js → SessionChat-_HhzMwEO.js} +1 -1
  18. package/dist/renderer/assets/{SessionList-88dgGZJ8.js → SessionList-DNwZjGTv.js} +1 -1
  19. package/dist/renderer/assets/ThreadChat-DxBmdsAm.js +23 -0
  20. package/dist/renderer/assets/{Workspace-D_hzSJjX.js → Workspace-DFphG85O.js} +1 -1
  21. package/dist/renderer/assets/{arrow-left-BMpknulW.js → arrow-left-bILMzse7.js} +1 -1
  22. package/dist/renderer/assets/{book-open-CiaOeQbU.js → book-open-BNBWEEve.js} +1 -1
  23. package/dist/renderer/assets/{check-CgwYH4GF.js → check-MGp5kvnb.js} +1 -1
  24. package/dist/renderer/assets/{chevron-down-BzD2S1OO.js → chevron-down-zsfoTlh7.js} +1 -1
  25. package/dist/renderer/assets/{circle-BDHD7g7l.js → circle-BX_xUSg-.js} +1 -1
  26. package/dist/renderer/assets/{desktop-BiR5LPL5.js → desktop-CgrO_cdQ.js} +1 -1
  27. package/dist/renderer/assets/{desktop-BkMW-h5p.js → desktop-O8_6ZCVZ.js} +2 -2
  28. package/dist/renderer/assets/{funnel-Bruf5FYA.js → funnel-7442U1wq.js} +1 -1
  29. package/dist/renderer/assets/{heart-D7Mz04B0.js → heart-B3d8bnSH.js} +1 -1
  30. package/dist/renderer/assets/{index-gZIRr4_o.js → index-5YUqCvBf.js} +1 -1
  31. package/dist/renderer/assets/{index-CL1e8m3U.js → index-BBaYsVjU.js} +2 -2
  32. package/dist/renderer/assets/{pencil-C6gzDMse.js → pencil-QzWgkmoH.js} +1 -1
  33. package/dist/renderer/assets/{play-DqTXX-Pr.js → play-Bsc8hSI7.js} +1 -1
  34. package/dist/renderer/assets/{plug-ykmbeaO3.js → plug-CRY7sjvB.js} +1 -1
  35. package/dist/renderer/assets/{plus-DHE60vMX.js → plus-Dr5Ei8Ud.js} +1 -1
  36. package/dist/renderer/assets/projects-BDYSOFIJ.js +1 -0
  37. package/dist/renderer/assets/{save-CGIvrdQI.js → save-giJnp2Ki.js} +1 -1
  38. package/dist/renderer/assets/{search-D7IFAwyE.js → search-DcvHLmKs.js} +1 -1
  39. package/dist/renderer/assets/{server-aOsirp7I.js → server-D_Qu8If5.js} +1 -1
  40. package/dist/renderer/assets/{session-utils-Dxfp4ohQ.js → session-utils-CsASahfU.js} +1 -1
  41. package/dist/renderer/assets/{sessions-Db1XPbG2.js → sessions-eMpPqp4P.js} +1 -1
  42. package/dist/renderer/assets/{shield-check-ChXeQK-d.js → shield-check-BpF0uIw-.js} +1 -1
  43. package/dist/renderer/assets/{trash-2-CfN-c1zw.js → trash-2-OJFmx3xk.js} +1 -1
  44. package/dist/renderer/assets/{user-C7OHaBp4.js → user-GL_ivaV6.js} +1 -1
  45. package/dist/renderer/assets/{wifi-off-CpaJigye.js → wifi-off-CQT5VNQl.js} +1 -1
  46. package/dist/renderer/index.html +1 -1
  47. package/dist-electron/electron/agent-runtime-detector.test.js +30 -0
  48. package/dist-electron/electron/local-core-refactor.test.js +422 -0
  49. package/dist-electron/electron/plugin-kernel.test.js +81 -1
  50. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-backend.js +28 -3
  51. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-turn-coordinator.js +102 -15
  52. package/dist-electron/services/local-ai-core/src/agents/claudecode/behavior.js +5 -0
  53. package/dist-electron/services/local-ai-core/src/agents/claudecode/definition.js +36 -0
  54. package/dist-electron/services/local-ai-core/src/agents/claudecode/index.js +15 -0
  55. package/dist-electron/services/local-ai-core/src/agents/codex/behavior.js +5 -0
  56. package/dist-electron/services/local-ai-core/src/agents/codex/definition.js +24 -0
  57. package/dist-electron/services/local-ai-core/src/agents/codex/index.js +15 -0
  58. package/dist-electron/services/local-ai-core/src/agents/hermes/behavior.js +29 -0
  59. package/dist-electron/services/local-ai-core/src/agents/hermes/definition.js +22 -0
  60. package/dist-electron/services/local-ai-core/src/agents/hermes/index.js +15 -0
  61. package/dist-electron/services/local-ai-core/src/agents/index.js +98 -0
  62. package/dist-electron/services/local-ai-core/src/agents/localcore-acp/behavior.js +5 -0
  63. package/dist-electron/services/local-ai-core/src/agents/localcore-acp/definition.js +14 -0
  64. package/dist-electron/services/local-ai-core/src/agents/localcore-acp/index.js +27 -0
  65. package/dist-electron/services/local-ai-core/src/agents/opencode/behavior.js +5 -0
  66. package/dist-electron/services/local-ai-core/src/agents/opencode/definition.js +18 -0
  67. package/dist-electron/services/local-ai-core/src/agents/opencode/index.js +15 -0
  68. package/dist-electron/services/local-ai-core/src/agents/opencode/launch.js +119 -0
  69. package/dist-electron/services/local-ai-core/src/agents/pi/behavior.js +5 -0
  70. package/dist-electron/services/local-ai-core/src/agents/pi/definition.js +23 -0
  71. package/dist-electron/services/local-ai-core/src/agents/pi/index.js +15 -0
  72. package/dist-electron/services/local-ai-core/src/agents/pi/launch.js +139 -0
  73. package/dist-electron/services/local-ai-core/src/agents/shared/acp-behavior.js +11 -0
  74. package/dist-electron/services/local-ai-core/src/agents/shared/agent-plugin.js +60 -0
  75. package/dist-electron/services/local-ai-core/src/agents/shared/definition.js +12 -0
  76. package/dist-electron/services/local-ai-core/src/agents/shared/launch-utils.js +122 -0
  77. package/dist-electron/services/local-ai-core/src/agents/shared/progress-replay.js +19 -0
  78. package/dist-electron/services/local-ai-core/src/agents/shared/replay-prefix.js +68 -0
  79. package/dist-electron/services/local-ai-core/src/channel/lark/local-core-lark-gateway.js +0 -2
  80. package/dist-electron/services/local-ai-core/src/channel/weixin/local-core-weixin-gateway.js +0 -1
  81. package/dist-electron/services/local-ai-core/src/kernel/bootstrap.js +8 -7
  82. package/dist-electron/services/local-ai-core/src/plugins/builtin/agent-localcore-acp-plugin.js +9 -130
  83. package/dist-electron/services/local-ai-core/src/router/workspace-route-config.js +22 -397
  84. package/dist-electron/services/local-ai-core/src/runtime/agent-runtime-detector.js +9 -45
  85. package/dist-electron/services/local-ai-core/src/runtime/local-core-runtime-state.js +62 -1
  86. package/dist-electron/services/local-ai-core/src/runtime/runtime-detection-service.js +2 -12
  87. package/dist-electron/shared/desktop.js +3 -1
  88. package/dist-electron/src/pages/Threads/thread-chat-model.js +27 -18
  89. package/dist-electron/src/pages/Threads/thread-chat-permission.test.js +57 -18
  90. package/package.json +1 -1
  91. package/dist/renderer/assets/ThreadChat-BCdbTxBo.js +0 -23
  92. package/dist/renderer/assets/projects-Bx5p10th.js +0 -1
@@ -16,6 +16,7 @@ const event_bus_js_1 = require("../services/local-ai-core/src/kernel/event-bus.j
16
16
  const lifecycle_manager_js_1 = require("../services/local-ai-core/src/kernel/lifecycle-manager.js");
17
17
  const plugin_registry_js_1 = require("../services/local-ai-core/src/kernel/plugin-registry.js");
18
18
  const local_core_controller_js_1 = require("../services/local-ai-core/src/runtime/local-core-controller.js");
19
+ const local_core_runtime_state_js_1 = require("../services/local-ai-core/src/runtime/local-core-runtime-state.js");
19
20
  const server_js_1 = require("../services/local-ai-core/src/runtime/server.js");
20
21
  function plugin(id, dependsOn = []) {
21
22
  return {
@@ -159,6 +160,7 @@ function plugin(id, dependsOn = []) {
159
160
  'opencode',
160
161
  'codex',
161
162
  'claudecode',
163
+ 'hermes',
162
164
  ]);
163
165
  strict_1.default.deepEqual(runtime.kernel.getCapabilitySnapshot().adapters.channels, ['localcore-acp', 'lark', 'weixin']);
164
166
  strict_1.default.deepEqual(runtime.kernel.getCapabilitySnapshot().adapters.knowledgeProviders, ['ai-vector']);
@@ -193,6 +195,7 @@ function plugin(id, dependsOn = []) {
193
195
  'opencode',
194
196
  'codex',
195
197
  'claudecode',
198
+ 'hermes',
196
199
  ]);
197
200
  strict_1.default.deepEqual(runtime.kernel.getCapabilitySnapshot().adapters.channels, ['localcore-acp', 'lark', 'weixin']);
198
201
  strict_1.default.deepEqual(runtime.kernel.getCapabilitySnapshot().adapters.knowledgeProviders, []);
@@ -245,6 +248,44 @@ type = "codex"
245
248
  (0, node_fs_1.rmSync)(userDataPath, { recursive: true, force: true });
246
249
  }
247
250
  });
251
+ (0, node_test_1.default)('hermes agent runtime routes projects through hermes ACP command', async () => {
252
+ const userDataPath = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'agentdock-kernel-'));
253
+ try {
254
+ const runtime = (0, bootstrap_js_2.bootstrapLocalCoreRuntime)({
255
+ userDataPath,
256
+ enableKnowledge: false,
257
+ });
258
+ await runtime.state.saveRawConfigFile(`
259
+ [[projects]]
260
+ name = "hermes-workspace"
261
+
262
+ [projects.agent]
263
+ type = "hermes"
264
+ `);
265
+ const configState = await runtime.state.readConfigFile();
266
+ const project = configState.parsed?.projects?.find((entry) => entry.name === 'hermes-workspace');
267
+ const hermesRuntime = runtime.agentRuntimes.find((entry) => entry.agentType === 'hermes');
268
+ const route = project ? hermesRuntime?.createRoute(configState, project) : null;
269
+ strict_1.default.equal(route?.agentType, 'hermes');
270
+ strict_1.default.equal(route?.config.command, 'hermes');
271
+ strict_1.default.deepEqual(route?.config.args, ['acp']);
272
+ strict_1.default.equal(route?.config.env?.HERMES_YOLO_MODE, '1');
273
+ strict_1.default.deepEqual(await runtime.workspaceRouter.listWorkspaces(), [
274
+ {
275
+ id: 'hermes-workspace',
276
+ name: 'hermes-workspace',
277
+ agentType: 'hermes',
278
+ platforms: [],
279
+ sessionsCount: 0,
280
+ heartbeatEnabled: false,
281
+ },
282
+ ]);
283
+ await runtime.stop();
284
+ }
285
+ finally {
286
+ (0, node_fs_1.rmSync)(userDataPath, { recursive: true, force: true });
287
+ }
288
+ });
248
289
  (0, node_test_1.default)('pi agent runtime routes projects through bundled pi ACP and coding agent', async () => {
249
290
  const userDataPath = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'agentdock-kernel-'));
250
291
  try {
@@ -565,6 +606,45 @@ model = "deepseek-v4-flash"
565
606
  (0, node_fs_1.rmSync)(userDataPath, { recursive: true, force: true });
566
607
  }
567
608
  });
609
+ (0, node_test_1.default)('runtime getLogs reads from disk after state is recreated', () => {
610
+ const userDataPath = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'agentdock-disk-logs-'));
611
+ try {
612
+ const state = (0, local_core_runtime_state_js_1.createLocalCoreRuntimeState)({ userDataPath });
613
+ state.pushLog('first persisted line');
614
+ state.pushLog('second persisted line');
615
+ const recreated = (0, local_core_runtime_state_js_1.createLocalCoreRuntimeState)({ userDataPath });
616
+ strict_1.default.deepEqual(recreated.getLogs(2).map((line) => line.replace(/^\S+\s+/, '')), [
617
+ 'first persisted line',
618
+ 'second persisted line',
619
+ ]);
620
+ }
621
+ finally {
622
+ (0, node_fs_1.rmSync)(userDataPath, { recursive: true, force: true });
623
+ }
624
+ });
625
+ (0, node_test_1.default)('runtime getLogs fills from rotated log when current log has fewer lines', () => {
626
+ const userDataPath = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'agentdock-rotated-logs-'));
627
+ try {
628
+ const state = (0, local_core_runtime_state_js_1.createLocalCoreRuntimeState)({ userDataPath });
629
+ (0, node_fs_1.writeFileSync)(`${state.logPath}.1`, 'old-1\nold-2\nold-3\n', 'utf8');
630
+ (0, node_fs_1.writeFileSync)(state.logPath, 'new-1\n', 'utf8');
631
+ strict_1.default.deepEqual(state.getLogs(3), ['old-2', 'old-3', 'new-1']);
632
+ }
633
+ finally {
634
+ (0, node_fs_1.rmSync)(userDataPath, { recursive: true, force: true });
635
+ }
636
+ });
637
+ (0, node_test_1.default)('runtime getLogs returns only the requested tail lines from disk', () => {
638
+ const userDataPath = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'agentdock-tail-logs-'));
639
+ try {
640
+ const state = (0, local_core_runtime_state_js_1.createLocalCoreRuntimeState)({ userDataPath });
641
+ (0, node_fs_1.writeFileSync)(state.logPath, Array.from({ length: 1000 }, (_, index) => `line-${index + 1}`).join('\n') + '\n', 'utf8');
642
+ strict_1.default.deepEqual(state.getLogs(4), ['line-997', 'line-998', 'line-999', 'line-1000']);
643
+ }
644
+ finally {
645
+ (0, node_fs_1.rmSync)(userDataPath, { recursive: true, force: true });
646
+ }
647
+ });
568
648
  (0, node_test_1.default)('controller logs are persisted to local-core.log', () => {
569
649
  const userDataPath = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'agentdock-controller-logs-'));
570
650
  try {
@@ -739,7 +819,7 @@ name = "pi-workspace"
739
819
  [projects.agent]
740
820
  type = "pi"
741
821
  `);
742
- strict_1.default.deepEqual(runtime.agentRuntimes.map((entry) => entry.agentType), ['localcore-acp', 'opencode', 'codex']);
822
+ strict_1.default.deepEqual(runtime.agentRuntimes.map((entry) => entry.agentType), ['localcore-acp', 'opencode', 'codex', 'hermes']);
743
823
  strict_1.default.equal(runtime.kernel.getCapabilitySnapshot().snapshot.agents.some((capability) => capability.agentType === 'claudecode'), false);
744
824
  strict_1.default.equal(runtime.kernel.getCapabilitySnapshot().snapshot.agents.some((capability) => capability.agentType === 'pi'), false);
745
825
  strict_1.default.deepEqual(await runtime.workspaceRouter.listWorkspaces(), []);
@@ -11,6 +11,7 @@ const local_core_acp_content_js_1 = require("./local-core-acp-content.js");
11
11
  const command_risk_js_1 = require("../security/command-risk.js");
12
12
  const local_core_slash_commands_js_1 = require("./local-core-slash-commands.js");
13
13
  const local_core_acp_progress_js_1 = require("./local-core-acp-progress.js");
14
+ const index_js_1 = require("../agents/index.js");
14
15
  const ACP_PROMPT_TIMEOUT_MS = 15 * 60 * 1000;
15
16
  class LocalCoreAcpBackend {
16
17
  options;
@@ -200,8 +201,10 @@ class LocalCoreAcpBackend {
200
201
  sessionKey: row.bridge_session_key,
201
202
  },
202
203
  });
203
- void this.runPrompt(threadId, runId, row.bridge_session_key, config, message, options).catch((error) => {
204
- this.options.log?.(`localcore-acp prompt failed for ${threadId}: ${error instanceof Error ? error.message : String(error)}`);
204
+ setImmediate(() => {
205
+ void this.runPrompt(threadId, runId, row.bridge_session_key, config, message, options).catch((error) => {
206
+ this.options.log?.(`localcore-acp prompt failed for ${threadId}: ${error instanceof Error ? error.message : String(error)}`);
207
+ });
205
208
  });
206
209
  return { runId };
207
210
  }
@@ -301,6 +304,19 @@ class LocalCoreAcpBackend {
301
304
  session = await this.sessionCoordinator.ensureSession(threadId, bridgeSessionKey, config, {
302
305
  permissionMode: options.permissionMode,
303
306
  });
307
+ const priorAssistantFinalMessages = this.options.store
308
+ .getThread(threadId, [])
309
+ .messages
310
+ .filter((entry) => entry.role === 'assistant' && entry.kind === 'final')
311
+ .map((entry) => entry.content);
312
+ const priorAssistantProgressMessages = this.options.store
313
+ .getThread(threadId, [])
314
+ .messages
315
+ .filter((entry) => entry.role === 'assistant' && entry.kind === 'progress')
316
+ .map((entry) => ({
317
+ kind: entry.bridgeKind,
318
+ content: entry.content,
319
+ }));
304
320
  session.currentRunId = runId;
305
321
  session.currentTurn = {
306
322
  runId,
@@ -308,7 +324,11 @@ class LocalCoreAcpBackend {
308
324
  previewHandle: (0, node_crypto_1.randomUUID)(),
309
325
  thoughtPreviewHandle: (0, node_crypto_1.randomUUID)(),
310
326
  thoughtMessageId: `${runId}-thought-1`,
327
+ agentType: row.agent_type,
311
328
  assistantText: '',
329
+ rawAssistantText: '',
330
+ priorAssistantFinalMessages,
331
+ priorAssistantProgressMessages,
312
332
  thoughtText: '',
313
333
  thoughtSequence: 1,
314
334
  typingStarted: true,
@@ -338,7 +358,12 @@ class LocalCoreAcpBackend {
338
358
  this.turnCoordinator.closePendingThoughtSegment(session);
339
359
  this.turnCoordinator.flushPendingToolCall(session);
340
360
  if (currentTurn.assistantText) {
341
- const assistantText = (0, local_core_acp_progress_js_1.stripObservedToolTranscriptsFromAssistantText)(currentTurn.assistantText, currentTurn.toolObservations);
361
+ const behavior = (0, index_js_1.resolveAgentAcpBehavior)(currentTurn.agentType);
362
+ const normalizedFinalAssistantText = behavior.normalizeFinalAssistantText({
363
+ rawText: currentTurn.rawAssistantText || currentTurn.assistantText,
364
+ priorAssistantMessages: currentTurn.priorAssistantFinalMessages || [],
365
+ });
366
+ const assistantText = (0, local_core_acp_progress_js_1.stripObservedToolTranscriptsFromAssistantText)(normalizedFinalAssistantText, currentTurn.toolObservations);
342
367
  const processed = await this.responseProcessor.processAssistantResponse(threadId, assistantText);
343
368
  if (processed.displayContent) {
344
369
  this.options.store.appendMessage(threadId, 'assistant', processed.displayContent, 'final');
@@ -6,6 +6,7 @@ const local_core_acp_progress_js_1 = require("./local-core-acp-progress.js");
6
6
  const local_core_acp_permission_lifecycle_js_1 = require("./local-core-acp-permission-lifecycle.js");
7
7
  const workspace_acp_permissions_js_1 = require("./workspace-acp-permissions.js");
8
8
  const local_core_slash_commands_js_1 = require("./local-core-slash-commands.js");
9
+ const index_js_1 = require("../agents/index.js");
9
10
  class LocalCoreAcpTurnCoordinator {
10
11
  options;
11
12
  constructor(options) {
@@ -22,6 +23,9 @@ class LocalCoreAcpTurnCoordinator {
22
23
  if (!currentTurn || !currentRunId) {
23
24
  return;
24
25
  }
26
+ for (const toolCall of (0, local_core_acp_progress_js_1.getToolCallsInOrder)(currentTurn).filter((entry) => entry.suppressReplay)) {
27
+ (0, local_core_acp_progress_js_1.deletePendingToolCall)(currentTurn, toolCall.key);
28
+ }
25
29
  const pending = (0, local_core_acp_progress_js_1.getToolCallsInOrder)(currentTurn)
26
30
  .filter((toolCall) => !toolCall.emitted);
27
31
  if (pending.length === 0) {
@@ -100,7 +104,13 @@ class LocalCoreAcpTurnCoordinator {
100
104
  });
101
105
  return;
102
106
  }
103
- const options = (0, local_core_acp_permission_lifecycle_js_1.parsePermissionOptions)(payload.params?.options);
107
+ const currentTurn = session.currentTurn;
108
+ const behavior = (0, index_js_1.resolveAgentAcpBehavior)(currentTurn?.agentType);
109
+ const parsedOptions = (0, local_core_acp_permission_lifecycle_js_1.parsePermissionOptions)(payload.params?.options);
110
+ const options = behavior.normalizePermissionOptions?.({
111
+ options: parsedOptions,
112
+ params: payload.params,
113
+ }) || parsedOptions;
104
114
  const toolTitle = (0, workspace_acp_permissions_js_1.formatToolCallContent)(payload.params?.toolCall);
105
115
  this.closePendingThoughtSegment(session);
106
116
  if ((this.options.getThreadAgentMode?.(session.threadId) || local_core_slash_commands_js_1.DEFAULT_AGENT_MODE) === 'bypassPermissions') {
@@ -204,6 +214,9 @@ class LocalCoreAcpTurnCoordinator {
204
214
  if (isToolScopedAssistantUpdate(update) || consumeRawAssistantProgressChunk(session, String(update.content.text || ''))) {
205
215
  const content = String(update.content.text || '').trim();
206
216
  if (content) {
217
+ if (this.shouldSuppressProgress(currentTurn, 'tool', content)) {
218
+ return;
219
+ }
207
220
  this.options.appendMessage(session.threadId, 'assistant', content, 'progress', undefined, 'tool');
208
221
  this.options.emitBridge({
209
222
  type: 'reply',
@@ -215,7 +228,20 @@ class LocalCoreAcpTurnCoordinator {
215
228
  }
216
229
  return;
217
230
  }
218
- const projection = (0, local_core_acp_progress_js_1.applyAssistantMessageChunk)(currentTurn, String(update.content.text || ''));
231
+ const chunk = String(update.content.text || '');
232
+ currentTurn.rawAssistantText = `${currentTurn.rawAssistantText || ''}${chunk}`;
233
+ const behavior = (0, index_js_1.resolveAgentAcpBehavior)(currentTurn.agentType);
234
+ const normalizedText = behavior.normalizeAssistantText({
235
+ rawText: currentTurn.rawAssistantText,
236
+ priorAssistantMessages: currentTurn.priorAssistantFinalMessages || [],
237
+ });
238
+ const nextChunk = normalizedText.startsWith(currentTurn.assistantText)
239
+ ? normalizedText.slice(currentTurn.assistantText.length)
240
+ : normalizedText;
241
+ if (!nextChunk) {
242
+ return;
243
+ }
244
+ const projection = (0, local_core_acp_progress_js_1.applyAssistantMessageChunk)(currentTurn, nextChunk);
219
245
  if (!projection) {
220
246
  return;
221
247
  }
@@ -237,6 +263,10 @@ class LocalCoreAcpTurnCoordinator {
237
263
  if (!projection) {
238
264
  return;
239
265
  }
266
+ if (this.shouldSuppressProgress(currentTurn, 'thought', projection.content)) {
267
+ this.resetThoughtSegment(currentTurn);
268
+ return;
269
+ }
240
270
  if (this.options.upsertMessage) {
241
271
  this.options.upsertMessage(session.threadId, projection.messageId, 'assistant', projection.content, 'progress', undefined, projection.bridgeKind);
242
272
  }
@@ -253,11 +283,16 @@ class LocalCoreAcpTurnCoordinator {
253
283
  case 'tool_call': {
254
284
  this.closePendingThoughtSegment(session);
255
285
  const toolCall = (0, local_core_acp_progress_js_1.registerPendingToolCall)({ currentTurn, runId: currentRunId, update });
256
- (0, local_core_acp_progress_js_1.recordToolObservation)(currentTurn, {
257
- name: toolCall.title,
258
- title: toolCall.title,
259
- input: toolCall.input,
260
- });
286
+ if (this.isKnownPriorToolInput(currentTurn, toolCall.title, toolCall.input)) {
287
+ toolCall.suppressReplay = true;
288
+ }
289
+ else {
290
+ (0, local_core_acp_progress_js_1.recordToolObservation)(currentTurn, {
291
+ name: toolCall.title,
292
+ title: toolCall.title,
293
+ input: toolCall.input,
294
+ });
295
+ }
261
296
  (0, local_core_acp_progress_js_1.syncLegacyPendingToolCall)(currentTurn, toolCall);
262
297
  return;
263
298
  }
@@ -314,14 +349,18 @@ class LocalCoreAcpTurnCoordinator {
314
349
  detail: displayTitle,
315
350
  content,
316
351
  });
317
- (0, local_core_acp_progress_js_1.recordToolObservation)(currentTurn, {
318
- name: toolName || displayTitle || title,
319
- title: displayTitle || title,
320
- status,
321
- input: updateInput === undefined ? toolCall?.input : updateInput,
322
- outputText: content,
323
- });
324
- this.emitProgress(session, currentRunId, (0, local_core_acp_progress_js_1.formatToolProgressMessage)({ toolName, title: displayTitle, status, content }), messageId, toolCallPayload);
352
+ const progressContent = (0, local_core_acp_progress_js_1.formatToolProgressMessage)({ toolName, title: displayTitle, status, content });
353
+ const suppressProgress = Boolean(toolCall?.suppressReplay) || this.shouldSuppressProgress(currentTurn, 'tool', progressContent);
354
+ if (!suppressProgress) {
355
+ (0, local_core_acp_progress_js_1.recordToolObservation)(currentTurn, {
356
+ name: toolName || displayTitle || title,
357
+ title: displayTitle || title,
358
+ status,
359
+ input: updateInput === undefined ? toolCall?.input : updateInput,
360
+ outputText: content,
361
+ });
362
+ this.emitProgress(session, currentRunId, progressContent, messageId, toolCallPayload);
363
+ }
325
364
  (0, local_core_acp_progress_js_1.syncLegacyPendingToolCall)(currentTurn, (0, local_core_acp_progress_js_1.resolveFallbackToolCall)(currentTurn));
326
365
  return;
327
366
  }
@@ -336,6 +375,9 @@ class LocalCoreAcpTurnCoordinator {
336
375
  if (!content) {
337
376
  return;
338
377
  }
378
+ if (this.shouldSuppressProgress(currentTurn, 'plan', content)) {
379
+ return;
380
+ }
339
381
  this.options.appendMessage(session.threadId, 'assistant', content, 'progress', undefined, 'plan');
340
382
  this.options.emitBridge({
341
383
  type: 'reply',
@@ -380,8 +422,53 @@ class LocalCoreAcpTurnCoordinator {
380
422
  toolCall,
381
423
  });
382
424
  }
425
+ shouldSuppressProgress(currentTurn, kind, content) {
426
+ const behavior = (0, index_js_1.resolveAgentAcpBehavior)(currentTurn.agentType);
427
+ return behavior.shouldSuppressProgress?.({
428
+ kind,
429
+ content,
430
+ priorProgressMessages: currentTurn.priorAssistantProgressMessages || [],
431
+ }) || false;
432
+ }
433
+ resetThoughtSegment(currentTurn) {
434
+ const runId = currentTurn.runId || 'thought';
435
+ const nextSequence = (currentTurn.thoughtSequence || 1) + 1;
436
+ currentTurn.thoughtSequence = nextSequence;
437
+ currentTurn.thoughtText = '';
438
+ currentTurn.thoughtPreviewStarted = false;
439
+ currentTurn.thoughtMessageId = `${runId}-thought-${nextSequence}`;
440
+ currentTurn.thoughtPreviewHandle = `${runId}-thought-preview-${nextSequence}`;
441
+ }
442
+ isKnownPriorToolInput(currentTurn, title, input) {
443
+ const compactInput = compactToolInput(input);
444
+ if (!compactInput) {
445
+ return false;
446
+ }
447
+ const needle = `${title}: ${compactInput}`.trim();
448
+ return (currentTurn.priorAssistantProgressMessages || []).some((message) => message.kind === 'tool' && message.content.includes(needle));
449
+ }
383
450
  }
384
451
  exports.LocalCoreAcpTurnCoordinator = LocalCoreAcpTurnCoordinator;
452
+ function compactToolInput(input) {
453
+ if (input === undefined || input === null) {
454
+ return '';
455
+ }
456
+ if (typeof input === 'string') {
457
+ return input.trim();
458
+ }
459
+ if (typeof input !== 'object') {
460
+ return String(input).trim();
461
+ }
462
+ const command = input.command;
463
+ if (typeof command === 'string' && command.trim()) {
464
+ return command.trim();
465
+ }
466
+ const path = input.path;
467
+ if (typeof path === 'string' && path.trim()) {
468
+ return path.trim();
469
+ }
470
+ return '';
471
+ }
385
472
  function isToolScopedAssistantUpdate(update) {
386
473
  const meta = update._meta;
387
474
  if (!meta || typeof meta !== 'object') {
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.claudeCodeAcpBehavior = void 0;
4
+ const acp_behavior_js_1 = require("../shared/acp-behavior.js");
5
+ exports.claudeCodeAcpBehavior = acp_behavior_js_1.standardAcpBehavior;
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.claudeCodeAgentDefinition = void 0;
4
+ const desktop_js_1 = require("../../../../../shared/desktop.js");
5
+ const launch_utils_js_1 = require("../shared/launch-utils.js");
6
+ const behavior_js_1 = require("./behavior.js");
7
+ exports.claudeCodeAgentDefinition = {
8
+ agentType: 'claudecode',
9
+ displayName: 'Claude Code',
10
+ behavior: behavior_js_1.claudeCodeAcpBehavior,
11
+ detection: {
12
+ commandCandidates: ['claude-agent-acp', 'claude'],
13
+ versionArgs: ['--version'],
14
+ bundledRuntimes: [
15
+ {
16
+ packageName: desktop_js_1.DESKTOP_CLAUDECODE_ACP_PACKAGE,
17
+ candidates: [
18
+ 'dist/cli.js',
19
+ 'bin/claude-agent-acp.js',
20
+ 'cli.js',
21
+ ],
22
+ },
23
+ ],
24
+ },
25
+ buildLaunchConfig(input) {
26
+ const bundled = (0, launch_utils_js_1.resolveBundledAcpCommand)(desktop_js_1.DESKTOP_CLAUDECODE_ACP_PACKAGE, 'claude-agent-acp');
27
+ return {
28
+ ...bundled,
29
+ env: input.model
30
+ ? {
31
+ ANTHROPIC_MODEL: input.model,
32
+ }
33
+ : {},
34
+ };
35
+ },
36
+ };
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.claudeCodeAgentDefinition = exports.claudeCodeAcpBehavior = void 0;
4
+ exports.createBuiltinClaudeCodeAgentPlugin = createBuiltinClaudeCodeAgentPlugin;
5
+ const agent_plugin_js_1 = require("../shared/agent-plugin.js");
6
+ const behavior_js_1 = require("./behavior.js");
7
+ Object.defineProperty(exports, "claudeCodeAcpBehavior", { enumerable: true, get: function () { return behavior_js_1.claudeCodeAcpBehavior; } });
8
+ const definition_js_1 = require("./definition.js");
9
+ Object.defineProperty(exports, "claudeCodeAgentDefinition", { enumerable: true, get: function () { return definition_js_1.claudeCodeAgentDefinition; } });
10
+ function createBuiltinClaudeCodeAgentPlugin() {
11
+ return (0, agent_plugin_js_1.createBuiltinAgentPlugin)({
12
+ definition: definition_js_1.claudeCodeAgentDefinition,
13
+ match: (normalizedAgentType) => normalizedAgentType === 'claudecode',
14
+ });
15
+ }
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.codexAcpBehavior = void 0;
4
+ const acp_behavior_js_1 = require("../shared/acp-behavior.js");
5
+ exports.codexAcpBehavior = acp_behavior_js_1.standardAcpBehavior;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.codexAgentDefinition = void 0;
4
+ const desktop_js_1 = require("../../../../../shared/desktop.js");
5
+ const launch_utils_js_1 = require("../shared/launch-utils.js");
6
+ const behavior_js_1 = require("./behavior.js");
7
+ exports.codexAgentDefinition = {
8
+ agentType: 'codex',
9
+ displayName: 'Codex',
10
+ behavior: behavior_js_1.codexAcpBehavior,
11
+ detection: {
12
+ commandCandidates: ['codex-acp', 'codex'],
13
+ versionArgs: ['--version'],
14
+ bundledRuntimes: [
15
+ {
16
+ packageName: desktop_js_1.DESKTOP_CODEX_ACP_PACKAGE,
17
+ candidates: ['bin/codex-acp.js'],
18
+ },
19
+ ],
20
+ },
21
+ buildLaunchConfig() {
22
+ return (0, launch_utils_js_1.resolveBundledAcpCommand)(desktop_js_1.DESKTOP_CODEX_ACP_PACKAGE, 'codex-acp');
23
+ },
24
+ };
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.codexAgentDefinition = exports.codexAcpBehavior = void 0;
4
+ exports.createBuiltinCodexAgentPlugin = createBuiltinCodexAgentPlugin;
5
+ const agent_plugin_js_1 = require("../shared/agent-plugin.js");
6
+ const behavior_js_1 = require("./behavior.js");
7
+ Object.defineProperty(exports, "codexAcpBehavior", { enumerable: true, get: function () { return behavior_js_1.codexAcpBehavior; } });
8
+ const definition_js_1 = require("./definition.js");
9
+ Object.defineProperty(exports, "codexAgentDefinition", { enumerable: true, get: function () { return definition_js_1.codexAgentDefinition; } });
10
+ function createBuiltinCodexAgentPlugin() {
11
+ return (0, agent_plugin_js_1.createBuiltinAgentPlugin)({
12
+ definition: definition_js_1.codexAgentDefinition,
13
+ match: (normalizedAgentType) => normalizedAgentType === 'codex',
14
+ });
15
+ }
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.hermesAcpBehavior = void 0;
4
+ const progress_replay_js_1 = require("../shared/progress-replay.js");
5
+ const replay_prefix_js_1 = require("../shared/replay-prefix.js");
6
+ function allowsPermanentPermission(params) {
7
+ if (!params || typeof params !== 'object') {
8
+ return true;
9
+ }
10
+ const record = params;
11
+ return record.allow_permanent !== false && record.allowPermanent !== false;
12
+ }
13
+ exports.hermesAcpBehavior = {
14
+ normalizeAssistantText(input) {
15
+ return (0, replay_prefix_js_1.stripAssistantReplayPrefix)(input.rawText, input.priorAssistantMessages);
16
+ },
17
+ normalizeFinalAssistantText(input) {
18
+ return (0, replay_prefix_js_1.stripAssistantReplayPrefix)(input.rawText, input.priorAssistantMessages);
19
+ },
20
+ shouldSuppressProgress(input) {
21
+ return (0, progress_replay_js_1.hasPriorProgressMessage)(input);
22
+ },
23
+ normalizePermissionOptions(input) {
24
+ if (allowsPermanentPermission(input.params)) {
25
+ return input.options;
26
+ }
27
+ return input.options.filter((option) => option.normalizedAction !== 'allow all');
28
+ },
29
+ };
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.hermesAgentDefinition = void 0;
4
+ const behavior_js_1 = require("./behavior.js");
5
+ exports.hermesAgentDefinition = {
6
+ agentType: 'hermes',
7
+ displayName: 'Hermes',
8
+ behavior: behavior_js_1.hermesAcpBehavior,
9
+ detection: {
10
+ commandCandidates: ['hermes'],
11
+ versionArgs: ['--version'],
12
+ },
13
+ buildLaunchConfig() {
14
+ return {
15
+ command: 'hermes',
16
+ args: ['acp'],
17
+ env: {
18
+ HERMES_YOLO_MODE: '1',
19
+ },
20
+ };
21
+ },
22
+ };
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.hermesAgentDefinition = exports.hermesAcpBehavior = void 0;
4
+ exports.createBuiltinHermesAgentPlugin = createBuiltinHermesAgentPlugin;
5
+ const agent_plugin_js_1 = require("../shared/agent-plugin.js");
6
+ const behavior_js_1 = require("./behavior.js");
7
+ Object.defineProperty(exports, "hermesAcpBehavior", { enumerable: true, get: function () { return behavior_js_1.hermesAcpBehavior; } });
8
+ const definition_js_1 = require("./definition.js");
9
+ Object.defineProperty(exports, "hermesAgentDefinition", { enumerable: true, get: function () { return definition_js_1.hermesAgentDefinition; } });
10
+ function createBuiltinHermesAgentPlugin() {
11
+ return (0, agent_plugin_js_1.createBuiltinAgentPlugin)({
12
+ definition: definition_js_1.hermesAgentDefinition,
13
+ match: (normalizedAgentType) => normalizedAgentType === 'hermes',
14
+ });
15
+ }
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createBuiltinPiAgentPlugin = exports.createBuiltinOpencodeAgentPlugin = exports.createBuiltinLocalCoreAcpAgentPlugin = exports.createBuiltinHermesAgentPlugin = exports.createBuiltinClaudeCodeAgentPlugin = exports.createBuiltinCodexAgentPlugin = void 0;
4
+ exports.getAgentRuntimeDefinitions = getAgentRuntimeDefinitions;
5
+ exports.getStaticAgentRuntimeDefinitions = getStaticAgentRuntimeDefinitions;
6
+ exports.resolveAgentRuntimeDefinition = resolveAgentRuntimeDefinition;
7
+ exports.resolveAgentAcpBehavior = resolveAgentAcpBehavior;
8
+ exports.createBuiltinStaticAgentCapabilityPlugin = createBuiltinStaticAgentCapabilityPlugin;
9
+ const acp_behavior_js_1 = require("./shared/acp-behavior.js");
10
+ const definition_js_1 = require("./shared/definition.js");
11
+ const index_js_1 = require("./codex/index.js");
12
+ const index_js_2 = require("./claudecode/index.js");
13
+ const index_js_3 = require("./hermes/index.js");
14
+ const index_js_4 = require("./localcore-acp/index.js");
15
+ const index_js_5 = require("./opencode/index.js");
16
+ const index_js_6 = require("./pi/index.js");
17
+ const STATIC_AGENT_DEFINITIONS = [
18
+ {
19
+ agentType: 'cursor',
20
+ displayName: 'Cursor',
21
+ behavior: acp_behavior_js_1.standardAcpBehavior,
22
+ detection: { commandCandidates: ['cursor-agent', 'cursor'], versionArgs: ['--version'] },
23
+ },
24
+ {
25
+ agentType: 'gemini',
26
+ displayName: 'Gemini',
27
+ behavior: acp_behavior_js_1.standardAcpBehavior,
28
+ detection: { commandCandidates: ['gemini'], versionArgs: ['--version'] },
29
+ },
30
+ {
31
+ agentType: 'qoder',
32
+ displayName: 'Qoder',
33
+ behavior: acp_behavior_js_1.standardAcpBehavior,
34
+ detection: { commandCandidates: ['qoder'], versionArgs: ['--version'] },
35
+ },
36
+ {
37
+ agentType: 'iflow',
38
+ displayName: 'iFlow',
39
+ behavior: acp_behavior_js_1.standardAcpBehavior,
40
+ detection: { commandCandidates: ['iflow'], versionArgs: ['--version'] },
41
+ },
42
+ ];
43
+ const AGENT_RUNTIME_DEFINITIONS = [
44
+ index_js_6.piAgentDefinition,
45
+ index_js_5.opencodeAgentDefinition,
46
+ index_js_1.codexAgentDefinition,
47
+ index_js_2.claudeCodeAgentDefinition,
48
+ index_js_3.hermesAgentDefinition,
49
+ index_js_4.localCoreAcpAgentDefinition,
50
+ ...STATIC_AGENT_DEFINITIONS,
51
+ ];
52
+ const AGENT_RUNTIME_DEFINITIONS_BY_TYPE = new Map(AGENT_RUNTIME_DEFINITIONS.map((definition) => [definition.agentType, definition]));
53
+ function getAgentRuntimeDefinitions() {
54
+ return [...AGENT_RUNTIME_DEFINITIONS];
55
+ }
56
+ function getStaticAgentRuntimeDefinitions() {
57
+ return [...STATIC_AGENT_DEFINITIONS];
58
+ }
59
+ function resolveAgentRuntimeDefinition(agentType) {
60
+ const normalized = (0, definition_js_1.normalizeAgentType)(agentType);
61
+ return AGENT_RUNTIME_DEFINITIONS_BY_TYPE.get(normalized)
62
+ || AGENT_RUNTIME_DEFINITIONS.find((definition) => (0, definition_js_1.agentDefinitionMatches)(definition, normalized))
63
+ || null;
64
+ }
65
+ function resolveAgentAcpBehavior(agentType) {
66
+ return resolveAgentRuntimeDefinition(agentType)?.behavior || acp_behavior_js_1.standardAcpBehavior;
67
+ }
68
+ function createBuiltinStaticAgentCapabilityPlugin(agentType, displayName = agentType) {
69
+ return {
70
+ manifest: {
71
+ id: `builtin.agent-${agentType}`,
72
+ kind: 'agent',
73
+ version: '0.1.0',
74
+ provides: [`agent:${agentType}`],
75
+ },
76
+ capabilities: {
77
+ agents: [
78
+ {
79
+ id: `agent.${agentType}`,
80
+ agentType,
81
+ displayName,
82
+ },
83
+ ],
84
+ },
85
+ };
86
+ }
87
+ var index_js_7 = require("./codex/index.js");
88
+ Object.defineProperty(exports, "createBuiltinCodexAgentPlugin", { enumerable: true, get: function () { return index_js_7.createBuiltinCodexAgentPlugin; } });
89
+ var index_js_8 = require("./claudecode/index.js");
90
+ Object.defineProperty(exports, "createBuiltinClaudeCodeAgentPlugin", { enumerable: true, get: function () { return index_js_8.createBuiltinClaudeCodeAgentPlugin; } });
91
+ var index_js_9 = require("./hermes/index.js");
92
+ Object.defineProperty(exports, "createBuiltinHermesAgentPlugin", { enumerable: true, get: function () { return index_js_9.createBuiltinHermesAgentPlugin; } });
93
+ var index_js_10 = require("./localcore-acp/index.js");
94
+ Object.defineProperty(exports, "createBuiltinLocalCoreAcpAgentPlugin", { enumerable: true, get: function () { return index_js_10.createBuiltinLocalCoreAcpAgentPlugin; } });
95
+ var index_js_11 = require("./opencode/index.js");
96
+ Object.defineProperty(exports, "createBuiltinOpencodeAgentPlugin", { enumerable: true, get: function () { return index_js_11.createBuiltinOpencodeAgentPlugin; } });
97
+ var index_js_12 = require("./pi/index.js");
98
+ Object.defineProperty(exports, "createBuiltinPiAgentPlugin", { enumerable: true, get: function () { return index_js_12.createBuiltinPiAgentPlugin; } });