@kafca/agentdock 0.1.33 → 0.1.35

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 (68) hide show
  1. package/README.md +67 -0
  2. package/dist/renderer/assets/{Badge-VeSLCPPV.js → Badge-BM4WCcua.js} +1 -1
  3. package/dist/renderer/assets/{Chat-DWTQeTgn.js → Chat-DoyBHOsx.js} +1 -1
  4. package/dist/renderer/assets/{ChatMarkdown-C9gSQIVb.js → ChatMarkdown-BWj04kgW.js} +1 -1
  5. package/dist/renderer/assets/{Config-CTA-pZNR.js → Config-A95OuazQ.js} +1 -1
  6. package/dist/renderer/assets/{CronList-BngBCnFY.js → CronList-DsPU4zGT.js} +1 -1
  7. package/dist/renderer/assets/{Dashboard-D4pGvDpc.js → Dashboard-D8Vpj97x.js} +2 -2
  8. package/dist/renderer/assets/{EmptyState-DMf8rzDs.js → EmptyState-x1uVoSxZ.js} +1 -1
  9. package/dist/renderer/assets/{KnowledgeDetail-C1Ym_cHk.js → KnowledgeDetail-C9TbcyNJ.js} +1 -1
  10. package/dist/renderer/assets/{KnowledgeHome-DPRiR72G.js → KnowledgeHome-Cg9Fb41Q.js} +1 -1
  11. package/dist/renderer/assets/Logs-oWaKA60u.js +1 -0
  12. package/dist/renderer/assets/{Modal-BDhhPv2l.js → Modal-24hTXXHK.js} +1 -1
  13. package/dist/renderer/assets/{Page-DdDZN7AE.js → Page-YRtQonKZ.js} +1 -1
  14. package/dist/renderer/assets/{ProjectDetail-DCsr3LkW.js → ProjectDetail-DScsxJO-.js} +1 -1
  15. package/dist/renderer/assets/{ProjectList-Cnm-iLvg.js → ProjectList-8L5GD7PN.js} +1 -1
  16. package/dist/renderer/assets/{Select-Dw4FCXhJ.js → Select-BI8Uw_DF.js} +1 -1
  17. package/dist/renderer/assets/{SessionChat-O-6abK8x.js → SessionChat-BIoCWdDD.js} +1 -1
  18. package/dist/renderer/assets/{SessionList-5yptvVL9.js → SessionList-BsEJeDxI.js} +1 -1
  19. package/dist/renderer/assets/{ThreadChat-CIM_o2HO.js → ThreadChat-DJi0UBta.js} +1 -1
  20. package/dist/renderer/assets/{Workspace-D9UeUCNr.js → Workspace-tlJxrgC5.js} +1 -1
  21. package/dist/renderer/assets/{arrow-left-CKfxNOXE.js → arrow-left-pzaBhi9y.js} +1 -1
  22. package/dist/renderer/assets/{book-open-CQddlENV.js → book-open-CNhlVyqh.js} +1 -1
  23. package/dist/renderer/assets/{check-CZYvOmIS.js → check-Cg2LLCdl.js} +1 -1
  24. package/dist/renderer/assets/{chevron-down-CVIWFoXF.js → chevron-down-Dgqg07wf.js} +1 -1
  25. package/dist/renderer/assets/{circle-DSfdQM7k.js → circle-BBd_jIS2.js} +1 -1
  26. package/dist/renderer/assets/{desktop-B9KUgeOV.js → desktop-C0S-Yv8G.js} +1 -1
  27. package/dist/renderer/assets/{funnel-pB5NegZB.js → funnel-DwSh-SrX.js} +1 -1
  28. package/dist/renderer/assets/{heart-BT5laZ_b.js → heart-CWVc-KhZ.js} +1 -1
  29. package/dist/renderer/assets/{index-DFiJR0vv.css → index-CaQZSRbg.css} +1 -1
  30. package/dist/renderer/assets/{index-BYyDk28K.js → index-DZbeAYVk.js} +2 -2
  31. package/dist/renderer/assets/{index-zTUUYax3.js → index-HYmDNQ9k.js} +1 -1
  32. package/dist/renderer/assets/{pencil-C0thxLi6.js → pencil-tI4tCLz0.js} +1 -1
  33. package/dist/renderer/assets/{play-CmZ0kWtt.js → play-Coi2HA1w.js} +1 -1
  34. package/dist/renderer/assets/{plug-CeDQatBe.js → plug-D4TCyW9b.js} +1 -1
  35. package/dist/renderer/assets/{plus-Di__xFOZ.js → plus-p62AgpoB.js} +1 -1
  36. package/dist/renderer/assets/projects-CTDuVxeQ.js +1 -0
  37. package/dist/renderer/assets/{save-BDatCjfO.js → save-fpMhkVV0.js} +1 -1
  38. package/dist/renderer/assets/{search-DnTOjP0C.js → search-BHKIStdA.js} +1 -1
  39. package/dist/renderer/assets/{server-Ey_iHY6m.js → server-0oTWed8U.js} +1 -1
  40. package/dist/renderer/assets/{session-utils-DWaM7Rkr.js → session-utils-D0Qv0I0-.js} +1 -1
  41. package/dist/renderer/assets/{sessions-CYYjLD5I.js → sessions-C8ApKQgC.js} +1 -1
  42. package/dist/renderer/assets/{shield-check-Br8BQzcn.js → shield-check-BAJI9jzC.js} +1 -1
  43. package/dist/renderer/assets/{trash-2-7YD616fw.js → trash-2-B-Ygm-x6.js} +1 -1
  44. package/dist/renderer/assets/{user-BR_5jmr9.js → user-Cv8rzw8l.js} +1 -1
  45. package/dist/renderer/assets/{wifi-off-By9QdREz.js → wifi-off-BImS3nkm.js} +1 -1
  46. package/dist/renderer/index.html +2 -2
  47. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-backend.js +3 -5
  48. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-session-coordinator.js +23 -6
  49. package/dist-electron/services/local-ai-core/src/cli/lac.js +7 -1
  50. package/dist-electron/services/local-ai-core/src/kernel/bootstrap.js +9 -19
  51. package/dist-electron/services/local-ai-core/src/kernel/rotating-logger.js +232 -0
  52. package/dist-electron/services/local-ai-core/src/runtime/local-core-controller.js +12 -44
  53. package/dist-electron/services/local-ai-core/src/runtime/local-core-runtime-state.js +40 -84
  54. package/dist-electron/services/local-ai-core/src/runtime/server-routes.js +3 -0
  55. package/dist-electron/services/local-ai-core/src/runtime/server.js +14 -0
  56. package/dist-electron/services/local-ai-core/src/scheduler/lark-schedule-adapter.js +6 -5
  57. package/dist-electron/services/local-ai-core/src/scheduler/scheduled-conversation-executor.js +22 -0
  58. package/dist-electron/services/local-ai-core/src/scheduler/scheduled-job-application-service.js +84 -0
  59. package/dist-electron/services/local-ai-core/src/scheduler/scheduled-job-route.js +35 -2
  60. package/dist-electron/services/local-ai-core/src/scheduler/weixin-schedule-adapter.js +5 -5
  61. package/dist-electron/src/api/client.js +1 -1
  62. package/dist-electron/tests/electron/lac-cli.test.js +50 -0
  63. package/dist-electron/tests/electron/plugin-kernel.test.js +162 -44
  64. package/dist-electron/tests/electron/workspace-task-store.test.js +123 -0
  65. package/dist-electron/tests/integration/local-core-refactor.test.js +13 -3
  66. package/package.json +1 -1
  67. package/dist/renderer/assets/Logs-CRHecmzO.js +0 -1
  68. package/dist/renderer/assets/projects-B-pbhhtH.js +0 -1
@@ -18,6 +18,60 @@ const plugin_registry_js_1 = require("../../services/local-ai-core/src/kernel/pl
18
18
  const local_core_controller_js_1 = require("../../services/local-ai-core/src/runtime/local-core-controller.js");
19
19
  const local_core_runtime_state_js_1 = require("../../services/local-ai-core/src/runtime/local-core-runtime-state.js");
20
20
  const server_js_1 = require("../../services/local-ai-core/src/runtime/server.js");
21
+ function withLogEnv(logDir, fn, options = {}) {
22
+ const previousLogDir = process.env.AGENTDOCK_LOG_DIR;
23
+ const previousMaxBytes = process.env.AGENTDOCK_LOG_MAX_BYTES;
24
+ const previousMaxFiles = process.env.AGENTDOCK_LOG_MAX_FILES;
25
+ process.env.AGENTDOCK_LOG_DIR = logDir;
26
+ if (options.maxBytes !== undefined) {
27
+ process.env.AGENTDOCK_LOG_MAX_BYTES = String(options.maxBytes);
28
+ }
29
+ else {
30
+ delete process.env.AGENTDOCK_LOG_MAX_BYTES;
31
+ }
32
+ if (options.maxFiles !== undefined) {
33
+ process.env.AGENTDOCK_LOG_MAX_FILES = String(options.maxFiles);
34
+ }
35
+ else {
36
+ delete process.env.AGENTDOCK_LOG_MAX_FILES;
37
+ }
38
+ const restore = () => {
39
+ if (previousLogDir === undefined) {
40
+ delete process.env.AGENTDOCK_LOG_DIR;
41
+ }
42
+ else {
43
+ process.env.AGENTDOCK_LOG_DIR = previousLogDir;
44
+ }
45
+ if (previousMaxBytes === undefined) {
46
+ delete process.env.AGENTDOCK_LOG_MAX_BYTES;
47
+ }
48
+ else {
49
+ process.env.AGENTDOCK_LOG_MAX_BYTES = previousMaxBytes;
50
+ }
51
+ if (previousMaxFiles === undefined) {
52
+ delete process.env.AGENTDOCK_LOG_MAX_FILES;
53
+ }
54
+ else {
55
+ process.env.AGENTDOCK_LOG_MAX_FILES = previousMaxFiles;
56
+ }
57
+ };
58
+ try {
59
+ const result = fn();
60
+ const maybePromise = result;
61
+ if (maybePromise && typeof maybePromise.finally === 'function') {
62
+ return maybePromise.finally(restore);
63
+ }
64
+ restore();
65
+ return result;
66
+ }
67
+ catch (error) {
68
+ restore();
69
+ throw error;
70
+ }
71
+ }
72
+ function parseLogLine(line) {
73
+ return JSON.parse(line);
74
+ }
21
75
  function plugin(id, dependsOn = []) {
22
76
  return {
23
77
  manifest: {
@@ -540,6 +594,7 @@ model = "deepseek-v4-flash"
540
594
  plugins: {},
541
595
  }),
542
596
  getLogs: () => [],
597
+ getLogEntries: () => [],
543
598
  readConfigFile: async () => ({
544
599
  path: '',
545
600
  exists: false,
@@ -562,6 +617,7 @@ model = "deepseek-v4-flash"
562
617
  knowledgeAttachments: {},
563
618
  workspaceRouter: {},
564
619
  scheduler: {},
620
+ scheduledJobs: {},
565
621
  start: async () => {
566
622
  started = true;
567
623
  },
@@ -587,20 +643,41 @@ model = "deepseek-v4-flash"
587
643
  await controller.close();
588
644
  strict_1.default.equal(stopped, true);
589
645
  });
590
- (0, node_test_1.default)('runtime logs are persisted to local-core.log', () => {
646
+ (0, node_test_1.default)('runtime logs are persisted to unified sys and level logs', () => {
591
647
  const userDataPath = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'agentdock-logs-'));
648
+ const logDir = (0, node_path_1.join)(userDataPath, 'logs');
592
649
  try {
593
- const runtime = (0, bootstrap_js_2.bootstrapLocalCoreRuntime)({
594
- userDataPath,
595
- enableKnowledge: false,
596
- log: () => { },
650
+ withLogEnv(logDir, () => {
651
+ const runtime = (0, bootstrap_js_2.bootstrapLocalCoreRuntime)({
652
+ userDataPath,
653
+ enableKnowledge: false,
654
+ log: () => { },
655
+ });
656
+ runtime.state.pushLog('localcore-weixin send failed for sessionKey=test');
657
+ runtime.state.pushLog('second line');
658
+ const sysRaw = (0, node_fs_1.readFileSync)((0, node_path_1.join)(logDir, 'sys.log'), 'utf-8');
659
+ const errorRaw = (0, node_fs_1.readFileSync)((0, node_path_1.join)(logDir, 'error.log'), 'utf-8');
660
+ const infoRaw = (0, node_fs_1.readFileSync)((0, node_path_1.join)(logDir, 'info.log'), 'utf-8');
661
+ const sysLines = sysRaw.trim().split(/\r?\n/).map(parseLogLine);
662
+ strict_1.default.equal(runtime.state.logPath, (0, node_path_1.join)(logDir, 'sys.log'));
663
+ for (const fileName of ['sys.log', 'debug.log', 'info.log', 'warn.log', 'error.log']) {
664
+ strict_1.default.equal((0, node_fs_1.existsSync)((0, node_path_1.join)(logDir, fileName)), true);
665
+ }
666
+ strict_1.default.equal(sysLines.at(-2)?.level, 'error');
667
+ strict_1.default.match(sysLines.at(-2)?.ts || '', /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}$/);
668
+ strict_1.default.equal(sysLines.at(-2)?.message, 'localcore-weixin send failed for sessionKey=test');
669
+ strict_1.default.equal(sysLines.at(-1)?.level, 'info');
670
+ strict_1.default.equal(sysLines.at(-1)?.message, 'second line');
671
+ strict_1.default.match(errorRaw, /localcore-weixin send failed for sessionKey=test/);
672
+ strict_1.default.match(infoRaw, /second line/);
673
+ strict_1.default.deepEqual(runtime.state.getLogEntries('error', 10).map((entry) => entry.message), [
674
+ 'localcore-weixin send failed for sessionKey=test',
675
+ ]);
676
+ strict_1.default.deepEqual(runtime.state.getLogEntries('sys', 2).map((entry) => entry.message), [
677
+ 'localcore-weixin send failed for sessionKey=test',
678
+ 'second line',
679
+ ]);
597
680
  });
598
- runtime.state.pushLog('localcore-weixin send failed for sessionKey=test');
599
- runtime.state.pushLog('second line');
600
- const logPath = (0, node_path_1.join)(userDataPath, 'runtime', 'local-core.log');
601
- const raw = (0, node_fs_1.readFileSync)(logPath, 'utf-8');
602
- strict_1.default.match(raw, /^\d{4}-\d{2}-\d{2}T.* localcore-weixin send failed for sessionKey=test/m);
603
- strict_1.default.match(raw, /^\d{4}-\d{2}-\d{2}T.* second line/m);
604
681
  }
605
682
  finally {
606
683
  (0, node_fs_1.rmSync)(userDataPath, { recursive: true, force: true });
@@ -608,15 +685,18 @@ model = "deepseek-v4-flash"
608
685
  });
609
686
  (0, node_test_1.default)('runtime getLogs reads from disk after state is recreated', () => {
610
687
  const userDataPath = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'agentdock-disk-logs-'));
688
+ const logDir = (0, node_path_1.join)(userDataPath, 'logs');
611
689
  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
- ]);
690
+ withLogEnv(logDir, () => {
691
+ const state = (0, local_core_runtime_state_js_1.createLocalCoreRuntimeState)({ userDataPath });
692
+ state.pushLog('first persisted line');
693
+ state.pushLog('second persisted line');
694
+ const recreated = (0, local_core_runtime_state_js_1.createLocalCoreRuntimeState)({ userDataPath });
695
+ strict_1.default.deepEqual(recreated.getLogs(2).map((line) => parseLogLine(line).message), [
696
+ 'first persisted line',
697
+ 'second persisted line',
698
+ ]);
699
+ });
620
700
  }
621
701
  finally {
622
702
  (0, node_fs_1.rmSync)(userDataPath, { recursive: true, force: true });
@@ -624,11 +704,19 @@ model = "deepseek-v4-flash"
624
704
  });
625
705
  (0, node_test_1.default)('runtime getLogs fills from rotated log when current log has fewer lines', () => {
626
706
  const userDataPath = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'agentdock-rotated-logs-'));
707
+ const logDir = (0, node_path_1.join)(userDataPath, 'logs');
627
708
  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']);
709
+ withLogEnv(logDir, () => {
710
+ const state = (0, local_core_runtime_state_js_1.createLocalCoreRuntimeState)({ userDataPath });
711
+ (0, node_fs_1.writeFileSync)(`${state.logPath}.1`, [
712
+ JSON.stringify({ ts: '2026-01-01 00:00:00.000', level: 'info', scope: 'test', message: 'old-1' }),
713
+ JSON.stringify({ ts: '2026-01-01 00:00:01.000', level: 'info', scope: 'test', message: 'old-2' }),
714
+ JSON.stringify({ ts: '2026-01-01 00:00:02.000', level: 'info', scope: 'test', message: 'old-3' }),
715
+ '',
716
+ ].join('\n'), 'utf8');
717
+ (0, node_fs_1.writeFileSync)(state.logPath, `${JSON.stringify({ ts: '2026-01-01 00:00:03.000', level: 'info', scope: 'test', message: 'new-1' })}\n`, 'utf8');
718
+ strict_1.default.deepEqual(state.getLogs(3).map((line) => parseLogLine(line).message), ['old-2', 'old-3', 'new-1']);
719
+ });
632
720
  }
633
721
  finally {
634
722
  (0, node_fs_1.rmSync)(userDataPath, { recursive: true, force: true });
@@ -636,30 +724,58 @@ model = "deepseek-v4-flash"
636
724
  });
637
725
  (0, node_test_1.default)('runtime getLogs returns only the requested tail lines from disk', () => {
638
726
  const userDataPath = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'agentdock-tail-logs-'));
727
+ const logDir = (0, node_path_1.join)(userDataPath, 'logs');
639
728
  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']);
729
+ withLogEnv(logDir, () => {
730
+ const state = (0, local_core_runtime_state_js_1.createLocalCoreRuntimeState)({ userDataPath });
731
+ (0, node_fs_1.writeFileSync)(state.logPath, Array.from({ length: 1000 }, (_, index) => JSON.stringify({ ts: '2026-01-01 00:00:00.000', level: 'info', scope: 'test', message: `line-${index + 1}` })).join('\n') + '\n', 'utf8');
732
+ strict_1.default.deepEqual(state.getLogs(4).map((line) => parseLogLine(line).message), ['line-997', 'line-998', 'line-999', 'line-1000']);
733
+ });
643
734
  }
644
735
  finally {
645
736
  (0, node_fs_1.rmSync)(userDataPath, { recursive: true, force: true });
646
737
  }
647
738
  });
648
- (0, node_test_1.default)('controller logs are persisted to local-core.log', () => {
739
+ (0, node_test_1.default)('runtime logs rotate by file size', () => {
740
+ const userDataPath = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'agentdock-size-rotated-logs-'));
741
+ const logDir = (0, node_path_1.join)(userDataPath, 'logs');
742
+ try {
743
+ withLogEnv(logDir, () => {
744
+ const state = (0, local_core_runtime_state_js_1.createLocalCoreRuntimeState)({ userDataPath });
745
+ state.pushLog('first failed line with enough text to rotate');
746
+ state.pushLog('second failed line with enough text to rotate');
747
+ state.pushLog('third failed line with enough text to rotate');
748
+ const currentSys = (0, node_fs_1.readFileSync)((0, node_path_1.join)(logDir, 'sys.log'), 'utf8');
749
+ const rotatedSys = (0, node_fs_1.readFileSync)((0, node_path_1.join)(logDir, 'sys.log.1'), 'utf8');
750
+ const currentError = (0, node_fs_1.readFileSync)((0, node_path_1.join)(logDir, 'error.log'), 'utf8');
751
+ const rotatedError = (0, node_fs_1.readFileSync)((0, node_path_1.join)(logDir, 'error.log.1'), 'utf8');
752
+ strict_1.default.match(currentSys, /third failed line/);
753
+ strict_1.default.match(rotatedSys, /second failed line/);
754
+ strict_1.default.match(currentError, /third failed line/);
755
+ strict_1.default.match(rotatedError, /second failed line/);
756
+ }, { maxBytes: 120, maxFiles: 2 });
757
+ }
758
+ finally {
759
+ (0, node_fs_1.rmSync)(userDataPath, { recursive: true, force: true });
760
+ }
761
+ });
762
+ (0, node_test_1.default)('controller logs are persisted to sys.log', () => {
649
763
  const userDataPath = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'agentdock-controller-logs-'));
764
+ const logDir = (0, node_path_1.join)(userDataPath, 'logs');
650
765
  try {
651
- const runtime = (0, bootstrap_js_2.bootstrapLocalCoreRuntime)({
652
- userDataPath,
653
- enableKnowledge: false,
766
+ withLogEnv(logDir, () => {
767
+ const runtime = (0, bootstrap_js_2.bootstrapLocalCoreRuntime)({
768
+ userDataPath,
769
+ enableKnowledge: false,
770
+ });
771
+ const controller = new local_core_controller_js_1.LocalCoreController(userDataPath, runtime);
772
+ const emittedLogs = [];
773
+ controller.on('logs', (line) => emittedLogs.push(line));
774
+ controller.handleLog('localcore-lark inbound message for project-1');
775
+ const raw = (0, node_fs_1.readFileSync)((0, node_path_1.join)(logDir, 'sys.log'), 'utf-8');
776
+ strict_1.default.deepEqual(emittedLogs, ['localcore-lark inbound message for project-1']);
777
+ strict_1.default.equal(parseLogLine(raw.trim().split(/\r?\n/).at(-1) || '').message, 'localcore-lark inbound message for project-1');
654
778
  });
655
- const controller = new local_core_controller_js_1.LocalCoreController(userDataPath, runtime);
656
- const emittedLogs = [];
657
- controller.on('logs', (line) => emittedLogs.push(line));
658
- controller.handleLog('localcore-lark inbound message for project-1');
659
- const logPath = (0, node_path_1.join)(userDataPath, 'runtime', 'local-core.log');
660
- const raw = (0, node_fs_1.readFileSync)(logPath, 'utf-8');
661
- strict_1.default.deepEqual(emittedLogs, ['localcore-lark inbound message for project-1']);
662
- strict_1.default.match(raw, /^\d{4}-\d{2}-\d{2}T.* localcore-lark inbound message for project-1/m);
663
779
  }
664
780
  finally {
665
781
  (0, node_fs_1.rmSync)(userDataPath, { recursive: true, force: true });
@@ -667,13 +783,15 @@ model = "deepseek-v4-flash"
667
783
  });
668
784
  (0, node_test_1.default)('controller buffers bootstrap logs until runtime state is assigned', () => {
669
785
  const userDataPath = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'agentdock-bootstrap-logs-'));
786
+ const logDir = (0, node_path_1.join)(userDataPath, 'logs');
670
787
  try {
671
- const controller = new local_core_controller_js_1.LocalCoreController(userDataPath);
672
- const logPath = (0, node_path_1.join)(userDataPath, 'runtime', 'local-core.log');
673
- const raw = (0, node_fs_1.readFileSync)(logPath, 'utf-8');
674
- strict_1.default.match(raw, /\[plugin:builtin\.agent-codex\] registered/);
675
- strict_1.default.equal((raw.match(/\[plugin:builtin\.agent-codex\] registered/g) || []).length, 1);
676
- void controller.close();
788
+ withLogEnv(logDir, () => {
789
+ const controller = new local_core_controller_js_1.LocalCoreController(userDataPath);
790
+ const raw = (0, node_fs_1.readFileSync)((0, node_path_1.join)(logDir, 'sys.log'), 'utf-8');
791
+ strict_1.default.match(raw, /\[plugin:builtin\.agent-codex\] registered/);
792
+ strict_1.default.equal((raw.match(/\[plugin:builtin\.agent-codex\] registered/g) || []).length, 1);
793
+ void controller.close();
794
+ });
677
795
  }
678
796
  finally {
679
797
  (0, node_fs_1.rmSync)(userDataPath, { recursive: true, force: true });
@@ -82,6 +82,50 @@ const local_core_controller_js_1 = require("../../services/local-ai-core/src/run
82
82
  (0, node_fs_1.rmSync)(userDataPath, { recursive: true, force: true });
83
83
  }
84
84
  });
85
+ (0, node_test_1.default)('scheduler create from a bound thread preserves channel instance route', async () => {
86
+ const userDataPath = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'scheduler-instance-route-'));
87
+ try {
88
+ const runtime = (0, bootstrap_js_1.bootstrapLocalCoreRuntime)({
89
+ userDataPath,
90
+ enableKnowledge: false,
91
+ log: () => { },
92
+ });
93
+ const controller = new local_core_controller_js_1.LocalCoreController(userDataPath, runtime);
94
+ const thread = runtime.store.createThread('workspace-a', 'Lark instance thread');
95
+ const now = new Date().toISOString();
96
+ runtime.store.upsertPlatformThreadBinding({
97
+ workspace_id: 'workspace-a',
98
+ platform: 'lark:lark-1',
99
+ chat_id: 'chat-1',
100
+ platform_user_id: 'user-1',
101
+ thread_id: thread.id,
102
+ last_platform_message_id: null,
103
+ created_at: now,
104
+ updated_at: now,
105
+ });
106
+ const job = await controller.createScheduledJob({
107
+ workspaceId: 'workspace-a',
108
+ threadId: thread.id,
109
+ executionMode: 'side-thread',
110
+ triggerType: 'cron',
111
+ cronExpr: '30 18 * * *',
112
+ promptTemplate: 'ping',
113
+ description: 'bound lark task',
114
+ enabled: true,
115
+ });
116
+ strict_1.default.equal(job.platform, 'lark:lark-1');
117
+ strict_1.default.deepEqual(job.route, {
118
+ type: 'channel.chat',
119
+ channelId: 'chat-1',
120
+ instanceId: 'lark-1',
121
+ participantId: 'user-1',
122
+ });
123
+ await controller.close();
124
+ }
125
+ finally {
126
+ (0, node_fs_1.rmSync)(userDataPath, { recursive: true, force: true });
127
+ }
128
+ });
85
129
  (0, node_test_1.default)('Lark scheduled same-thread execution resolves the latest channel thread and keeps channel delivery', async () => {
86
130
  const userDataPath = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'scheduler-lark-latest-thread-'));
87
131
  try {
@@ -170,6 +214,85 @@ const local_core_controller_js_1 = require("../../services/local-ai-core/src/run
170
214
  (0, node_fs_1.rmSync)(userDataPath, { recursive: true, force: true });
171
215
  }
172
216
  });
217
+ (0, node_test_1.default)('Lark scheduled execution supports instance-qualified platform keys', async () => {
218
+ const userDataPath = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'scheduler-lark-instance-'));
219
+ try {
220
+ const store = new local_core_acp_store_js_1.LocalCoreAcpStore(userDataPath);
221
+ const thread = store.createThread('workspace-a', 'Lark instance thread');
222
+ const now = new Date().toISOString();
223
+ store.upsertPlatformThreadBinding({
224
+ workspace_id: 'workspace-a',
225
+ platform: 'lark:lark-1',
226
+ chat_id: 'chat-1',
227
+ platform_user_id: 'user-1',
228
+ thread_id: thread.id,
229
+ last_platform_message_id: null,
230
+ created_at: now,
231
+ updated_at: now,
232
+ });
233
+ const job = store.createScheduledJob({
234
+ workspaceId: 'workspace-a',
235
+ platform: 'lark:lark-1',
236
+ route: { type: 'channel.chat', channelId: 'chat-1', participantId: 'user-1' },
237
+ executionMode: 'same-thread',
238
+ triggerType: 'cron',
239
+ cronExpr: '30 18 * * *',
240
+ promptTemplate: 'ping',
241
+ description: 'bound lark task',
242
+ enabled: true,
243
+ });
244
+ let deliveredRoute;
245
+ const adapter = new lark_schedule_adapter_js_1.LarkScheduleAdapter({
246
+ store,
247
+ getWorkspaceRouter: () => ({
248
+ getThread: async (threadId) => ({
249
+ id: threadId,
250
+ workspaceId: 'workspace-a',
251
+ title: 'Thread',
252
+ live: false,
253
+ updatedAt: now,
254
+ createdAt: now,
255
+ historyCount: 1,
256
+ excerpt: '',
257
+ bridgeSessionKey: '',
258
+ agentType: 'localcore-acp',
259
+ selectedKnowledgeBaseIds: [],
260
+ pendingPermissionRequest: null,
261
+ messages: [{ id: 'message-1', role: 'assistant', kind: 'final', content: 'pong', timestamp: now }],
262
+ }),
263
+ sendThreadMessage: async (threadId, _prompt, options) => {
264
+ strict_1.default.equal(threadId, thread.id);
265
+ strict_1.default.equal(options?.runtimeEnv?.LOCAL_AI_PLATFORM, 'lark');
266
+ strict_1.default.equal(options?.runtimeEnv?.LOCAL_AI_PLATFORM_INSTANCE_ID, 'lark-1');
267
+ strict_1.default.equal(options?.runtimeEnv?.LOCAL_AI_CHAT_ID, 'chat-1');
268
+ store.updateRun('run-1', threadId, 'completed');
269
+ return { runId: 'run-1' };
270
+ },
271
+ }),
272
+ getChannelRuntime: () => ({
273
+ muteThreadBridge: () => { },
274
+ unmuteThreadBridge: () => { },
275
+ sendScheduledMessage: async (_workspaceId, route) => {
276
+ deliveredRoute = route;
277
+ return 'platform-message-1';
278
+ },
279
+ }),
280
+ });
281
+ const result = await adapter.execute({ job, triggeredAt: now });
282
+ strict_1.default.equal(result.threadId, thread.id);
283
+ strict_1.default.equal(result.platformMessageId, 'platform-message-1');
284
+ strict_1.default.deepEqual(deliveredRoute, {
285
+ type: 'channel.chat',
286
+ channelId: 'chat-1',
287
+ instanceId: 'lark-1',
288
+ participantId: 'user-1',
289
+ });
290
+ store.close();
291
+ }
292
+ finally {
293
+ (0, node_fs_1.rmSync)(userDataPath, { recursive: true, force: true });
294
+ }
295
+ });
173
296
  (0, node_test_1.default)('ACP runtime env includes the current workspace path for file returns', async () => {
174
297
  const userDataPath = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'workspace-env-'));
175
298
  try {
@@ -25,6 +25,7 @@ const local_core_acp_permission_lifecycle_js_1 = require("../../services/local-a
25
25
  const workspace_acp_permissions_js_1 = require("../../services/local-ai-core/src/acp/workspace-acp-permissions.js");
26
26
  const server_routes_js_1 = require("../../services/local-ai-core/src/runtime/server-routes.js");
27
27
  (0, node_test_1.default)('local core route parser separates runtime refresh and runtime detail routes', () => {
28
+ strict_1.default.deepEqual((0, server_routes_js_1.parseLocalAiCoreRoute)('GET', '/api/local/v1/logs'), { name: 'logs.list' });
28
29
  strict_1.default.deepEqual((0, server_routes_js_1.parseLocalAiCoreRoute)('GET', '/api/local/v1/runtimes'), { name: 'runtimes.list' });
29
30
  strict_1.default.deepEqual((0, server_routes_js_1.parseLocalAiCoreRoute)('POST', '/api/local/v1/runtimes/refresh'), { name: 'runtimes.refresh' });
30
31
  strict_1.default.deepEqual((0, server_routes_js_1.parseLocalAiCoreRoute)('GET', '/api/local/v1/runtimes/codex'), {
@@ -3512,11 +3513,12 @@ const server_routes_js_1 = require("../../services/local-ai-core/src/runtime/ser
3512
3513
  });
3513
3514
  (0, node_test_1.default)('scheduled conversation executor uses execution policy hooks around a thread run', async () => {
3514
3515
  const calls = [];
3516
+ let runtimeEnv;
3515
3517
  const job = {
3516
3518
  id: 'job-1',
3517
3519
  workspaceId: '知识库',
3518
- platform: 'lark',
3519
- route: { type: 'channel.chat', channelId: 'chat-1', participantId: 'user-1', threadId: 'thread-1' },
3520
+ platform: 'lark:lark-1',
3521
+ route: { type: 'channel.chat', channelId: 'chat-1', instanceId: 'lark-1', participantId: 'user-1', threadId: 'thread-1' },
3520
3522
  executionMode: 'same-thread',
3521
3523
  triggerType: 'cron',
3522
3524
  cronExpr: '*/2 * * * *',
@@ -3533,6 +3535,7 @@ const server_routes_js_1 = require("../../services/local-ai-core/src/runtime/ser
3533
3535
  },
3534
3536
  workspaceRouter: {
3535
3537
  sendThreadMessage: async (threadId, prompt, options) => {
3538
+ runtimeEnv = options?.runtimeEnv;
3536
3539
  calls.push(`send:${threadId}:${prompt}:${options?.permissionMode || ''}`);
3537
3540
  return { runId: 'run-1' };
3538
3541
  },
@@ -3549,7 +3552,7 @@ const server_routes_js_1 = require("../../services/local-ai-core/src/runtime/ser
3549
3552
  kind: 'thread',
3550
3553
  threadId: 'thread-1',
3551
3554
  workspaceId: '知识库',
3552
- platform: 'lark',
3555
+ platform: 'lark:lark-1',
3553
3556
  route: job.route,
3554
3557
  }),
3555
3558
  beforeExecute: (target) => {
@@ -3564,6 +3567,13 @@ const server_routes_js_1 = require("../../services/local-ai-core/src/runtime/ser
3564
3567
  'send:thread-1:ping:bypassPermissions',
3565
3568
  'after:thread-1',
3566
3569
  ]);
3570
+ strict_1.default.deepEqual(runtimeEnv, {
3571
+ LOCAL_AI_PLATFORM: 'lark',
3572
+ LOCAL_AI_ROUTE_TYPE: 'channel.chat',
3573
+ LOCAL_AI_PLATFORM_INSTANCE_ID: 'lark-1',
3574
+ LOCAL_AI_CHAT_ID: 'chat-1',
3575
+ LOCAL_AI_PLATFORM_USER_ID: 'user-1',
3576
+ });
3567
3577
  strict_1.default.equal(result.replyText, 'done');
3568
3578
  });
3569
3579
  (0, node_test_1.default)('local scheduler adapter runs a workspace thread without channel delivery', async () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kafca/agentdock",
3
- "version": "0.1.33",
3
+ "version": "0.1.35",
4
4
  "license": "PolyForm-Noncommercial-1.0.0",
5
5
  "type": "module",
6
6
  "main": "dist-electron/electron/main.js",
@@ -1 +0,0 @@
1
- import{u as h,r as t,az as v,j as e,L as j,B as d,C as y}from"./index-BYyDk28K.js";import{B as N}from"./Badge-VeSLCPPV.js";import{S as m}from"./Select-Dw4FCXhJ.js";import{P as b}from"./Page-DdDZN7AE.js";import{A as w}from"./arrow-left-CKfxNOXE.js";import{F as L}from"./funnel-pB5NegZB.js";import"./index-zTUUYax3.js";import"./chevron-down-CVIWFoXF.js";import"./check-CZYvOmIS.js";const C={debug:"text-gray-400",info:"text-blue-400",warn:"text-amber-400",error:"text-red-400"},S={debug:"default",info:"info",warn:"warning",error:"danger"};function I(){const{t:a}=h(),[i,x]=t.useState([]),[r,u]=t.useState("info"),[n,f]=t.useState("100"),[g,l]=t.useState(!0),o=t.useCallback(async()=>{l(!0);try{const s=await v({level:r,limit:n});x(s.entries||[])}finally{l(!1)}},[r,n]);return t.useEffect(()=>{o()},[o]),e.jsxs("div",{className:"space-y-4 animate-fade-in",children:[e.jsx(b,{title:a("system.logs"),description:"Filtered runtime logs for troubleshooting.",actions:e.jsx(j,{to:"/system",children:e.jsxs(d,{variant:"secondary",size:"sm",children:[e.jsx(w,{size:14})," ",a("nav.system")]})})}),e.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(L,{size:14,className:"text-muted-foreground"}),e.jsxs(m,{value:r,onChange:s=>u(s.target.value),className:"w-auto",children:[e.jsx("option",{value:"debug",children:"Debug"}),e.jsx("option",{value:"info",children:"Info"}),e.jsx("option",{value:"warn",children:"Warn"}),e.jsx("option",{value:"error",children:"Error"})]})]}),e.jsxs(m,{value:n,onChange:s=>f(s.target.value),className:"w-auto",children:[e.jsx("option",{value:"50",children:"50"}),e.jsx("option",{value:"100",children:"100"}),e.jsx("option",{value:"500",children:"500"}),e.jsx("option",{value:"1000",children:"1000"})]}),e.jsx(d,{size:"sm",variant:"secondary",onClick:o,children:a("common.refresh")})]}),e.jsx(y,{children:g?e.jsx("div",{className:"text-muted-foreground animate-pulse text-sm",children:"Loading..."}):i.length===0?e.jsx("p",{className:"text-sm text-muted-foreground text-center py-8",children:a("common.noData")}):e.jsx("div",{className:"space-y-1 max-h-[65vh] overflow-y-auto font-mono text-xs",children:i.map((s,p)=>{var c;return e.jsxs("div",{className:"flex items-start gap-3 py-1.5 border-b last:border-0",children:[e.jsx("span",{className:"text-muted-foreground shrink-0 w-36",children:(c=s.time)==null?void 0:c.slice(0,19)}),e.jsx(N,{variant:S[s.level]||"default",children:s.level}),e.jsx("span",{className:`${C[s.level]||"text-gray-500"} flex-1`,children:s.message})]},p)})})})]})}export{I as default};
@@ -1 +0,0 @@
1
- import{z as t}from"./index-BYyDk28K.js";const e=()=>t.get("/projects"),r=o=>t.get(`/projects/${o}`);export{r as g,e as l};