@kafca/agentdock 0.1.36 → 0.1.38

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 (63) hide show
  1. package/README.md +11 -0
  2. package/dist/renderer/assets/{Badge-DUa4J-09.js → Badge-PKJavQmQ.js} +1 -1
  3. package/dist/renderer/assets/{Chat-B1FWuTWV.js → Chat-DWm4h9aa.js} +1 -1
  4. package/dist/renderer/assets/{ChatMarkdown-DqOgFSgI.js → ChatMarkdown-DKxW2GbO.js} +1 -1
  5. package/dist/renderer/assets/{Config-CM5bqUrV.js → Config-Bqn3cy0z.js} +1 -1
  6. package/dist/renderer/assets/{CronList-CfXE7S0M.js → CronList-CPI_C7FW.js} +1 -1
  7. package/dist/renderer/assets/{Dashboard-D5Dwbotu.js → Dashboard-0e9JS5t7.js} +2 -2
  8. package/dist/renderer/assets/{EmptyState-Bs_6ISc0.js → EmptyState-CuA0koT7.js} +1 -1
  9. package/dist/renderer/assets/{KnowledgeDetail-0kdWnKyy.js → KnowledgeDetail-B1YSDbFa.js} +1 -1
  10. package/dist/renderer/assets/{KnowledgeHome-Bg8xbRe2.js → KnowledgeHome-KHYwWGDu.js} +1 -1
  11. package/dist/renderer/assets/{Logs-BfgvW7qZ.js → Logs-X4LJw-00.js} +1 -1
  12. package/dist/renderer/assets/{Modal-BkuKCDDx.js → Modal-BzEv4CK6.js} +1 -1
  13. package/dist/renderer/assets/{Page-ddaAS_jP.js → Page-BrZMoKtK.js} +1 -1
  14. package/dist/renderer/assets/{ProjectDetail-C9x-Ib5p.js → ProjectDetail-DpO00Ozx.js} +1 -1
  15. package/dist/renderer/assets/{ProjectList-XIIikxrj.js → ProjectList-DFtJHTic.js} +1 -1
  16. package/dist/renderer/assets/{Select-BBL_5aa5.js → Select-DMrwDcus.js} +1 -1
  17. package/dist/renderer/assets/{SessionChat-BFsTM0c7.js → SessionChat-Bh9AfkK5.js} +1 -1
  18. package/dist/renderer/assets/{SessionList-DWh6n10K.js → SessionList-Y3gWAe96.js} +1 -1
  19. package/dist/renderer/assets/{ThreadChat-CzPiDA92.js → ThreadChat-Cq0ZRNOh.js} +1 -1
  20. package/dist/renderer/assets/{Workspace-BW8v3Nia.js → Workspace-DMSPypFO.js} +1 -1
  21. package/dist/renderer/assets/{arrow-left-CcoHvwbx.js → arrow-left-CgYQZlK9.js} +1 -1
  22. package/dist/renderer/assets/{book-open-RweyWxPq.js → book-open-cAfg0BWS.js} +1 -1
  23. package/dist/renderer/assets/{check-B5YOrBNT.js → check-BNRlfwZx.js} +1 -1
  24. package/dist/renderer/assets/{chevron-down-HjaPrxdd.js → chevron-down-B9vVz3wf.js} +1 -1
  25. package/dist/renderer/assets/{circle-C-aaO7LR.js → circle-TBXQ38et.js} +1 -1
  26. package/dist/renderer/assets/{desktop-DUWkNnbA.js → desktop-DfkCIN1l.js} +1 -1
  27. package/dist/renderer/assets/{funnel-IWZmi-_V.js → funnel-BdZjZcqK.js} +1 -1
  28. package/dist/renderer/assets/{heart-DM5_F2nX.js → heart-CBPXb4dq.js} +1 -1
  29. package/dist/renderer/assets/{index-Bin2xyBS.js → index-CXrYAFUE.js} +2 -2
  30. package/dist/renderer/assets/{index-DvIUdsAm.js → index-C_Yr2rQ1.js} +1 -1
  31. package/dist/renderer/assets/{pencil-DcxwCYPi.js → pencil-BlLIWP1h.js} +1 -1
  32. package/dist/renderer/assets/{play-DUdnnxLC.js → play-F-oO0VwG.js} +1 -1
  33. package/dist/renderer/assets/{plug-B-rDbk24.js → plug-B5BduKTi.js} +1 -1
  34. package/dist/renderer/assets/{plus-DslMGvrO.js → plus-Bbe6vc8z.js} +1 -1
  35. package/dist/renderer/assets/projects-CGLECySt.js +1 -0
  36. package/dist/renderer/assets/{save-DlkR3jLs.js → save-CbX1ymi_.js} +1 -1
  37. package/dist/renderer/assets/{search-ULTp3p_0.js → search-KyB8P1Ie.js} +1 -1
  38. package/dist/renderer/assets/{server-DBdiKfv9.js → server-D2EQ0I-I.js} +1 -1
  39. package/dist/renderer/assets/{session-utils-BPyVVONo.js → session-utils-C4Eq8h8o.js} +1 -1
  40. package/dist/renderer/assets/{sessions-B0NecMYO.js → sessions-CchD99QT.js} +1 -1
  41. package/dist/renderer/assets/{shield-check-BNSk8nza.js → shield-check-BTTXqP3n.js} +1 -1
  42. package/dist/renderer/assets/{trash-2-CGydl763.js → trash-2-CDOrVaia.js} +1 -1
  43. package/dist/renderer/assets/{user-D1xkQo35.js → user-BR0zEuV_.js} +1 -1
  44. package/dist/renderer/assets/{wifi-off-Iy1XPeZ3.js → wifi-off-W_cPAMcl.js} +1 -1
  45. package/dist/renderer/index.html +1 -1
  46. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-store.js +22 -7
  47. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-turn-coordinator.js +2 -1
  48. package/dist-electron/services/local-ai-core/src/channel/lark/local-core-lark-gateway.js +59 -9
  49. package/dist-electron/services/local-ai-core/src/channel/lark/runtime-state.js +9 -6
  50. package/dist-electron/services/local-ai-core/src/channel/weixin/local-core-weixin-gateway.js +31 -1
  51. package/dist-electron/services/local-ai-core/src/scheduler/channel-execution-policy.js +79 -0
  52. package/dist-electron/services/local-ai-core/src/scheduler/lark-execution-policies.js +7 -61
  53. package/dist-electron/services/local-ai-core/src/scheduler/lark-schedule-adapter.js +3 -12
  54. package/dist-electron/services/local-ai-core/src/scheduler/local-schedule-adapter.js +23 -30
  55. package/dist-electron/services/local-ai-core/src/scheduler/scheduled-bridge-session.js +55 -0
  56. package/dist-electron/services/local-ai-core/src/scheduler/scheduler-run-lifecycle.js +13 -1
  57. package/dist-electron/services/local-ai-core/src/scheduler/scheduler-service.js +1 -1
  58. package/dist-electron/services/local-ai-core/src/scheduler/weixin-execution-policies.js +7 -61
  59. package/dist-electron/services/local-ai-core/src/scheduler/weixin-schedule-adapter.js +3 -12
  60. package/dist-electron/tests/electron/workspace-task-store.test.js +188 -28
  61. package/dist-electron/tests/integration/local-core-refactor.test.js +140 -50
  62. package/package.json +1 -1
  63. package/dist/renderer/assets/projects-JFuOB4DM.js +0 -1
@@ -10,6 +10,7 @@ const node_path_1 = require("node:path");
10
10
  const node_os_1 = require("node:os");
11
11
  const local_core_acp_store_js_1 = require("../../services/local-ai-core/src/acp/local-core-acp-store.js");
12
12
  const local_core_acp_session_coordinator_js_1 = require("../../services/local-ai-core/src/acp/local-core-acp-session-coordinator.js");
13
+ const local_core_acp_turn_coordinator_js_1 = require("../../services/local-ai-core/src/acp/local-core-acp-turn-coordinator.js");
13
14
  const scheduler_service_js_1 = require("../../services/local-ai-core/src/scheduler/scheduler-service.js");
14
15
  const lark_schedule_adapter_js_1 = require("../../services/local-ai-core/src/scheduler/lark-schedule-adapter.js");
15
16
  const bootstrap_js_1 = require("../../services/local-ai-core/src/kernel/bootstrap.js");
@@ -165,10 +166,13 @@ const local_core_controller_js_1 = require("../../services/local-ai-core/src/run
165
166
  enabled: true,
166
167
  });
167
168
  let sentThreadId = '';
168
- let deliveredRoute;
169
+ let registeredBridge;
170
+ const bridgeEvents = [];
171
+ let unregisteredBridge = false;
169
172
  const adapter = new lark_schedule_adapter_js_1.LarkScheduleAdapter({
170
173
  store,
171
174
  getWorkspaceRouter: () => ({
175
+ getThreadSessionKey: (threadId) => `session:${threadId}`,
172
176
  getThread: async (threadId) => ({
173
177
  id: threadId,
174
178
  workspaceId: 'workspace-a',
@@ -191,23 +195,38 @@ const local_core_controller_js_1 = require("../../services/local-ai-core/src/run
191
195
  },
192
196
  }),
193
197
  getChannelRuntime: () => ({
194
- muteThreadBridge: () => { },
195
- unmuteThreadBridge: () => { },
196
- sendScheduledMessage: async (_workspaceId, route) => {
197
- deliveredRoute = route;
198
- return 'platform-message-1';
198
+ onBridgeEvent: async (event) => {
199
+ bridgeEvents.push(event);
200
+ },
201
+ registerScheduledThreadBridge: (input) => {
202
+ registeredBridge = input;
203
+ return () => {
204
+ unregisteredBridge = true;
205
+ };
206
+ },
207
+ sendScheduledMessage: async () => {
208
+ throw new Error('scheduled Lark replies should be delivered through bridge events');
199
209
  },
200
210
  }),
201
211
  });
202
212
  const result = await adapter.execute({ job, triggeredAt: now });
203
213
  strict_1.default.equal(sentThreadId, latestThread.id);
204
214
  strict_1.default.equal(result.threadId, latestThread.id);
205
- strict_1.default.equal(result.platformMessageId, 'platform-message-1');
206
- strict_1.default.deepEqual(deliveredRoute, {
207
- type: 'channel.chat',
208
- channelId: 'chat-1',
209
- participantId: 'user-1',
215
+ strict_1.default.equal('platformMessageId' in result, false);
216
+ strict_1.default.deepEqual(registeredBridge, {
217
+ workspaceId: 'workspace-a',
218
+ platform: 'lark',
219
+ route: { type: 'channel.chat', channelId: 'chat-1', participantId: 'user-1', threadId: oldThread.id },
220
+ threadId: latestThread.id,
221
+ sessionKey: `session:${latestThread.id}`,
222
+ });
223
+ strict_1.default.deepEqual(bridgeEvents[0], {
224
+ type: 'status',
225
+ sessionKey: `session:${latestThread.id}`,
226
+ bridgeKind: 'status',
227
+ content: '⏰ bound lark task',
210
228
  });
229
+ strict_1.default.equal(unregisteredBridge, true);
211
230
  store.close();
212
231
  }
213
232
  finally {
@@ -247,12 +266,14 @@ const local_core_controller_js_1 = require("../../services/local-ai-core/src/run
247
266
  store,
248
267
  getWorkspaceRouter: () => workspaceRouter,
249
268
  getChannelRuntime: () => ({
250
- muteThreadBridge: () => { },
251
- unmuteThreadBridge: () => { },
252
- sendScheduledMessage: async () => 'platform-message-1',
269
+ registerScheduledThreadBridge: () => () => { },
270
+ sendScheduledMessage: async () => {
271
+ throw new Error('scheduled Lark replies should be delivered through bridge events');
272
+ },
253
273
  }),
254
274
  });
255
275
  workspaceRouter = {
276
+ getThreadSessionKey: (threadId) => `session:${threadId}`,
256
277
  getThread: async (threadId) => ({
257
278
  id: threadId,
258
279
  workspaceId: 'workspace-a',
@@ -277,7 +298,7 @@ const local_core_controller_js_1 = require("../../services/local-ai-core/src/run
277
298
  const result = await adapter.execute({ job, triggeredAt: now });
278
299
  strict_1.default.equal(sentThreadId, thread.id);
279
300
  strict_1.default.equal(result.threadId, thread.id);
280
- strict_1.default.equal(result.platformMessageId, 'platform-message-1');
301
+ strict_1.default.equal('platformMessageId' in result, false);
281
302
  store.close();
282
303
  }
283
304
  finally {
@@ -311,10 +332,11 @@ const local_core_controller_js_1 = require("../../services/local-ai-core/src/run
311
332
  description: 'bound lark task',
312
333
  enabled: true,
313
334
  });
314
- let deliveredRoute;
335
+ let registeredBridge;
315
336
  const adapter = new lark_schedule_adapter_js_1.LarkScheduleAdapter({
316
337
  store,
317
338
  getWorkspaceRouter: () => ({
339
+ getThreadSessionKey: (threadId) => `session:${threadId}`,
318
340
  getThread: async (threadId) => ({
319
341
  id: threadId,
320
342
  workspaceId: 'workspace-a',
@@ -340,22 +362,24 @@ const local_core_controller_js_1 = require("../../services/local-ai-core/src/run
340
362
  },
341
363
  }),
342
364
  getChannelRuntime: () => ({
343
- muteThreadBridge: () => { },
344
- unmuteThreadBridge: () => { },
345
- sendScheduledMessage: async (_workspaceId, route) => {
346
- deliveredRoute = route;
347
- return 'platform-message-1';
365
+ registerScheduledThreadBridge: (input) => {
366
+ registeredBridge = input;
367
+ return () => { };
368
+ },
369
+ sendScheduledMessage: async () => {
370
+ throw new Error('scheduled Lark replies should be delivered through bridge events');
348
371
  },
349
372
  }),
350
373
  });
351
374
  const result = await adapter.execute({ job, triggeredAt: now });
352
375
  strict_1.default.equal(result.threadId, thread.id);
353
- strict_1.default.equal(result.platformMessageId, 'platform-message-1');
354
- strict_1.default.deepEqual(deliveredRoute, {
355
- type: 'channel.chat',
356
- channelId: 'chat-1',
357
- instanceId: 'lark-1',
358
- participantId: 'user-1',
376
+ strict_1.default.equal('platformMessageId' in result, false);
377
+ strict_1.default.deepEqual(registeredBridge, {
378
+ workspaceId: 'workspace-a',
379
+ platform: 'lark:lark-1',
380
+ route: { type: 'channel.chat', channelId: 'chat-1', participantId: 'user-1' },
381
+ threadId: thread.id,
382
+ sessionKey: `session:${thread.id}`,
359
383
  });
360
384
  store.close();
361
385
  }
@@ -491,6 +515,59 @@ const local_core_controller_js_1 = require("../../services/local-ai-core/src/run
491
515
  (0, node_fs_1.rmSync)(userDataPath, { recursive: true, force: true });
492
516
  }
493
517
  });
518
+ (0, node_test_1.default)('ACP permission requests honor scheduled session permission override', () => {
519
+ const sentPayloads = [];
520
+ let approvalCreated = false;
521
+ let awaitingInput = false;
522
+ const coordinator = new local_core_acp_turn_coordinator_js_1.LocalCoreAcpTurnCoordinator({
523
+ emitBridge: () => { },
524
+ appendMessage: () => { },
525
+ updateRunStatus: () => {
526
+ awaitingInput = true;
527
+ },
528
+ createApprovalRequest: () => {
529
+ approvalCreated = true;
530
+ return 'approval-1';
531
+ },
532
+ getThreadAgentMode: () => 'default',
533
+ sendRaw: (_session, payload) => {
534
+ sentPayloads.push(payload);
535
+ return true;
536
+ },
537
+ });
538
+ coordinator.handleAgentRequest({
539
+ threadId: 'thread-1',
540
+ bridgeSessionKey: 'bridge-1',
541
+ currentRunId: 'run-1',
542
+ currentTurn: null,
543
+ pendingPermissionByRun: new Map(),
544
+ schedulerJobCreatedByRun: new Map(),
545
+ launchPermissionMode: 'bypassPermissions',
546
+ }, {
547
+ jsonrpc: '2.0',
548
+ id: 42,
549
+ method: 'session/request_permission',
550
+ params: {
551
+ toolCall: { title: 'Write AI早报/AI早报-2026-05-08.md' },
552
+ options: [
553
+ { optionId: 'deny', name: 'Deny', kind: 'deny' },
554
+ { optionId: 'allow', name: 'Allow', kind: 'allow' },
555
+ ],
556
+ },
557
+ });
558
+ strict_1.default.equal(approvalCreated, false);
559
+ strict_1.default.equal(awaitingInput, false);
560
+ strict_1.default.deepEqual(sentPayloads[0], {
561
+ jsonrpc: '2.0',
562
+ id: 42,
563
+ result: {
564
+ outcome: {
565
+ outcome: 'selected',
566
+ optionId: 'allow',
567
+ },
568
+ },
569
+ });
570
+ });
494
571
  (0, node_test_1.default)('scheduler uses short ids for new jobs and resolves legacy full ids by short id', () => {
495
572
  const userDataPath = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'scheduler-id-store-'));
496
573
  try {
@@ -537,6 +614,78 @@ const local_core_controller_js_1 = require("../../services/local-ai-core/src/run
537
614
  (0, node_fs_1.rmSync)(userDataPath, { recursive: true, force: true });
538
615
  }
539
616
  });
617
+ (0, node_test_1.default)('scheduler dispatches due jobs without waiting for long-running jobs', async () => {
618
+ const userDataPath = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'scheduler-dispatch-'));
619
+ try {
620
+ const store = new local_core_acp_store_js_1.LocalCoreAcpStore(userDataPath);
621
+ store.createScheduledJob({
622
+ workspaceId: 'workspace-a',
623
+ platform: 'local',
624
+ route: { type: 'local.thread', channelId: 'workspace-a', threadId: 'thread-1' },
625
+ executionMode: 'side-thread',
626
+ triggerType: 'cron',
627
+ cronExpr: '* * * * *',
628
+ promptTemplate: 'slow',
629
+ description: 'slow job',
630
+ enabled: true,
631
+ });
632
+ store.createScheduledJob({
633
+ workspaceId: 'workspace-a',
634
+ platform: 'local',
635
+ route: { type: 'local.thread', channelId: 'workspace-a', threadId: 'thread-2' },
636
+ executionMode: 'side-thread',
637
+ triggerType: 'cron',
638
+ cronExpr: '* * * * *',
639
+ promptTemplate: 'fast',
640
+ description: 'fast job',
641
+ enabled: true,
642
+ });
643
+ let releaseSlow;
644
+ const slowDone = new Promise((resolve) => {
645
+ releaseSlow = resolve;
646
+ });
647
+ const started = [];
648
+ let slowJobId = '';
649
+ const scheduler = new scheduler_service_js_1.SchedulerService({
650
+ store,
651
+ triggers: [{
652
+ triggerTypes: ['cron'],
653
+ supports: () => true,
654
+ isDue: () => true,
655
+ }],
656
+ executors: [{
657
+ deliveryTargets: ['local'],
658
+ supports: () => true,
659
+ execute: async ({ job }) => {
660
+ const isFirstStartedJob = started.length === 0;
661
+ started.push(job.id);
662
+ if (isFirstStartedJob) {
663
+ slowJobId = job.id;
664
+ await slowDone;
665
+ }
666
+ return {
667
+ threadId: String(job.route.threadId || job.id),
668
+ runId: `run:${job.id}`,
669
+ };
670
+ },
671
+ }],
672
+ eventBus: { emit: () => { }, on: () => () => { } },
673
+ });
674
+ await scheduler.tick();
675
+ await new Promise((resolve) => setImmediate(resolve));
676
+ strict_1.default.equal(started.length, 2);
677
+ const fastJobId = started.find((id) => id !== slowJobId);
678
+ strict_1.default.equal(store.listScheduledJobRuns(slowJobId)[0]?.status, 'running');
679
+ strict_1.default.equal(store.listScheduledJobRuns(fastJobId)[0]?.status, 'succeeded');
680
+ releaseSlow();
681
+ await new Promise((resolve) => setImmediate(resolve));
682
+ strict_1.default.equal(store.listScheduledJobRuns(slowJobId)[0]?.status, 'succeeded');
683
+ store.close();
684
+ }
685
+ finally {
686
+ (0, node_fs_1.rmSync)(userDataPath, { recursive: true, force: true });
687
+ }
688
+ });
540
689
  (0, node_test_1.default)('scheduled jobs normalize enum-like input before persistence', () => {
541
690
  const userDataPath = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'scheduler-enum-store-'));
542
691
  try {
@@ -633,10 +782,21 @@ const local_core_controller_js_1 = require("../../services/local-ai-core/src/run
633
782
  description: 'daily ping',
634
783
  enabled: true,
635
784
  });
636
- const run = store.createScheduledJobRun(job.id, 'complete');
785
+ const run = store.createScheduledJobRun(job.id, 'complete', {
786
+ deliveryMode: 'bridge-stream',
787
+ deliveryStatus: 'streaming',
788
+ platformMessageIds: ['msg-1', 'msg-2'],
789
+ lastBridgeEventAt: '2026-04-22T06:00:03.000Z',
790
+ });
637
791
  strict_1.default.equal(run.status, 'succeeded');
792
+ strict_1.default.equal(run.deliveryMode, 'bridge-stream');
793
+ strict_1.default.equal(run.deliveryStatus, 'streaming');
794
+ strict_1.default.deepEqual(run.platformMessageIds, ['msg-1', 'msg-2']);
795
+ strict_1.default.equal(run.lastBridgeEventAt, '2026-04-22T06:00:03.000Z');
638
796
  const skipped = store.updateScheduledJobRun(run.id, { status: 'cancelled' });
639
797
  strict_1.default.equal(skipped.status, 'skipped');
798
+ strict_1.default.equal(skipped.deliveryMode, 'bridge-stream');
799
+ strict_1.default.deepEqual(skipped.platformMessageIds, ['msg-1', 'msg-2']);
640
800
  strict_1.default.equal(store.getScheduledJob(job.id)?.lastStatus, 'skipped');
641
801
  store.close();
642
802
  }