@kafca/agentdock 0.1.33 → 0.1.34

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 (60) hide show
  1. package/dist/renderer/assets/{Badge-VeSLCPPV.js → Badge-BDxYXRKv.js} +1 -1
  2. package/dist/renderer/assets/{Chat-DWTQeTgn.js → Chat-B-ZXd4Ld.js} +1 -1
  3. package/dist/renderer/assets/{ChatMarkdown-C9gSQIVb.js → ChatMarkdown-Dn4XvCke.js} +1 -1
  4. package/dist/renderer/assets/{Config-CTA-pZNR.js → Config-DMOYyKOD.js} +1 -1
  5. package/dist/renderer/assets/{CronList-BngBCnFY.js → CronList-CMBhMs1J.js} +1 -1
  6. package/dist/renderer/assets/{Dashboard-D4pGvDpc.js → Dashboard-DApD4wOA.js} +2 -2
  7. package/dist/renderer/assets/{EmptyState-DMf8rzDs.js → EmptyState-CqcPky2i.js} +1 -1
  8. package/dist/renderer/assets/{KnowledgeDetail-C1Ym_cHk.js → KnowledgeDetail-DMOXK9Nz.js} +1 -1
  9. package/dist/renderer/assets/{KnowledgeHome-DPRiR72G.js → KnowledgeHome-Dv4Ttb6N.js} +1 -1
  10. package/dist/renderer/assets/{Logs-CRHecmzO.js → Logs-CHrUm25Y.js} +1 -1
  11. package/dist/renderer/assets/{Modal-BDhhPv2l.js → Modal-Cj_0qtXr.js} +1 -1
  12. package/dist/renderer/assets/{Page-DdDZN7AE.js → Page-BlKjqLN4.js} +1 -1
  13. package/dist/renderer/assets/{ProjectDetail-DCsr3LkW.js → ProjectDetail-aMl1VGTt.js} +1 -1
  14. package/dist/renderer/assets/{ProjectList-Cnm-iLvg.js → ProjectList-R2YvsII0.js} +1 -1
  15. package/dist/renderer/assets/{Select-Dw4FCXhJ.js → Select-CrqwGrrm.js} +1 -1
  16. package/dist/renderer/assets/{SessionChat-O-6abK8x.js → SessionChat-CGtpyGKR.js} +1 -1
  17. package/dist/renderer/assets/{SessionList-5yptvVL9.js → SessionList-D8gRUc8M.js} +1 -1
  18. package/dist/renderer/assets/{ThreadChat-CIM_o2HO.js → ThreadChat-BCGm6bQP.js} +1 -1
  19. package/dist/renderer/assets/{Workspace-D9UeUCNr.js → Workspace-DnePK6tn.js} +1 -1
  20. package/dist/renderer/assets/{arrow-left-CKfxNOXE.js → arrow-left-SVmCyBR4.js} +1 -1
  21. package/dist/renderer/assets/{book-open-CQddlENV.js → book-open-CZi1avEJ.js} +1 -1
  22. package/dist/renderer/assets/{check-CZYvOmIS.js → check-C76I9BFh.js} +1 -1
  23. package/dist/renderer/assets/{chevron-down-CVIWFoXF.js → chevron-down-C7YSxzHw.js} +1 -1
  24. package/dist/renderer/assets/{circle-DSfdQM7k.js → circle-_s8tmsAJ.js} +1 -1
  25. package/dist/renderer/assets/{desktop-B9KUgeOV.js → desktop-66ot_8sB.js} +1 -1
  26. package/dist/renderer/assets/{funnel-pB5NegZB.js → funnel-cDV0Q_Mr.js} +1 -1
  27. package/dist/renderer/assets/{heart-BT5laZ_b.js → heart-qMUQm0tf.js} +1 -1
  28. package/dist/renderer/assets/{index-BYyDk28K.js → index-BY88QEsS.js} +2 -2
  29. package/dist/renderer/assets/{index-zTUUYax3.js → index-Cr6erCLm.js} +1 -1
  30. package/dist/renderer/assets/{pencil-C0thxLi6.js → pencil-C3MA3apq.js} +1 -1
  31. package/dist/renderer/assets/{play-CmZ0kWtt.js → play-VZKHv5dN.js} +1 -1
  32. package/dist/renderer/assets/{plug-CeDQatBe.js → plug-Cm7l0fVk.js} +1 -1
  33. package/dist/renderer/assets/{plus-Di__xFOZ.js → plus-DjGK7f-K.js} +1 -1
  34. package/dist/renderer/assets/projects-Dcki78KB.js +1 -0
  35. package/dist/renderer/assets/{save-BDatCjfO.js → save-Doi-FwDR.js} +1 -1
  36. package/dist/renderer/assets/{search-DnTOjP0C.js → search-DHqpbK_c.js} +1 -1
  37. package/dist/renderer/assets/{server-Ey_iHY6m.js → server-Bmtxxlph.js} +1 -1
  38. package/dist/renderer/assets/{session-utils-DWaM7Rkr.js → session-utils-Z-jLtVLY.js} +1 -1
  39. package/dist/renderer/assets/{sessions-CYYjLD5I.js → sessions-C5TSSo_R.js} +1 -1
  40. package/dist/renderer/assets/{shield-check-Br8BQzcn.js → shield-check-DhZ05nhI.js} +1 -1
  41. package/dist/renderer/assets/{trash-2-7YD616fw.js → trash-2-DiyFflVR.js} +1 -1
  42. package/dist/renderer/assets/{user-BR_5jmr9.js → user-CgsIPd7T.js} +1 -1
  43. package/dist/renderer/assets/{wifi-off-By9QdREz.js → wifi-off-CqWbWFzp.js} +1 -1
  44. package/dist/renderer/index.html +1 -1
  45. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-backend.js +3 -5
  46. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-session-coordinator.js +23 -6
  47. package/dist-electron/services/local-ai-core/src/cli/lac.js +7 -1
  48. package/dist-electron/services/local-ai-core/src/kernel/bootstrap.js +9 -19
  49. package/dist-electron/services/local-ai-core/src/runtime/local-core-controller.js +9 -44
  50. package/dist-electron/services/local-ai-core/src/scheduler/lark-schedule-adapter.js +6 -5
  51. package/dist-electron/services/local-ai-core/src/scheduler/scheduled-conversation-executor.js +22 -0
  52. package/dist-electron/services/local-ai-core/src/scheduler/scheduled-job-application-service.js +84 -0
  53. package/dist-electron/services/local-ai-core/src/scheduler/scheduled-job-route.js +35 -2
  54. package/dist-electron/services/local-ai-core/src/scheduler/weixin-schedule-adapter.js +5 -5
  55. package/dist-electron/tests/electron/lac-cli.test.js +50 -0
  56. package/dist-electron/tests/electron/plugin-kernel.test.js +1 -0
  57. package/dist-electron/tests/electron/workspace-task-store.test.js +123 -0
  58. package/dist-electron/tests/integration/local-core-refactor.test.js +12 -3
  59. package/package.json +1 -1
  60. package/dist/renderer/assets/projects-B-pbhhtH.js +0 -1
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ScheduledJobApplicationService = void 0;
4
+ const scheduled_job_route_js_1 = require("./scheduled-job-route.js");
5
+ class ScheduledJobApplicationService {
6
+ options;
7
+ constructor(options) {
8
+ this.options = options;
9
+ }
10
+ listJobs(workspaceId) {
11
+ return this.options.scheduler.listJobs(workspaceId);
12
+ }
13
+ getJob(jobId) {
14
+ return this.options.scheduler.getJob(jobId);
15
+ }
16
+ createJob(input) {
17
+ return this.options.scheduler.createJob(this.resolveCreateInput(input));
18
+ }
19
+ createCronJob(input) {
20
+ return this.options.scheduler.createJob({
21
+ workspaceId: input.workspaceId,
22
+ platform: input.platform,
23
+ route: this.resolveExplicitRoute(input.platform, input.route),
24
+ triggerType: 'cron',
25
+ cronExpr: input.schedule,
26
+ promptTemplate: input.message,
27
+ description: `${input.name} · ${input.scheduleDescription}`,
28
+ enabled: true,
29
+ });
30
+ }
31
+ updateJob(jobId, input) {
32
+ return this.options.scheduler.updateJob(jobId, {
33
+ ...input,
34
+ ...(input.route ? { route: (0, scheduled_job_route_js_1.withoutThreadRoute)(input.route) } : {}),
35
+ });
36
+ }
37
+ deleteJob(jobId) {
38
+ return this.options.scheduler.deleteJob(jobId);
39
+ }
40
+ runJobNow(jobId) {
41
+ return this.options.scheduler.runJobNow(jobId);
42
+ }
43
+ listJobRuns(jobId) {
44
+ return this.options.scheduler.listJobRuns(jobId);
45
+ }
46
+ listJobsForThread(threadId) {
47
+ const binding = this.options.store.getPlatformThreadBindingByThreadId(threadId);
48
+ return this.options.scheduler
49
+ .listJobs()
50
+ .filter((job) => job.route.threadId === threadId ||
51
+ (binding ? (0, scheduled_job_route_js_1.scheduledJobMatchesPlatformBinding)(job, binding) : false));
52
+ }
53
+ resolveCreateInput(input) {
54
+ if (input.platform && input.route) {
55
+ return {
56
+ ...input,
57
+ route: this.resolveExplicitRoute(input.platform, input.route),
58
+ };
59
+ }
60
+ const threadId = String(input.threadId || input.route?.threadId || '').trim();
61
+ if (threadId) {
62
+ const binding = this.options.store.getPlatformThreadBindingByThreadId(threadId);
63
+ if (binding && binding.workspace_id === input.workspaceId) {
64
+ return {
65
+ ...input,
66
+ platform: binding.platform,
67
+ route: (0, scheduled_job_route_js_1.routeFromPlatformThreadBinding)(binding),
68
+ };
69
+ }
70
+ }
71
+ return {
72
+ ...input,
73
+ platform: 'local',
74
+ route: {
75
+ type: 'local.thread',
76
+ channelId: input.workspaceId,
77
+ },
78
+ };
79
+ }
80
+ resolveExplicitRoute(platform, route) {
81
+ return (0, scheduled_job_route_js_1.routeWithPlatformInstance)((0, scheduled_job_route_js_1.withoutThreadRoute)(route), platform);
82
+ }
83
+ }
84
+ exports.ScheduledJobApplicationService = ScheduledJobApplicationService;
@@ -1,15 +1,48 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.withoutThreadRoute = withoutThreadRoute;
4
+ exports.getChannelPlatformBase = getChannelPlatformBase;
5
+ exports.getChannelPlatformInstanceId = getChannelPlatformInstanceId;
6
+ exports.platformMatches = platformMatches;
7
+ exports.routeWithPlatformInstance = routeWithPlatformInstance;
8
+ exports.routeTypeForPlatform = routeTypeForPlatform;
9
+ exports.routeFromPlatformThreadBinding = routeFromPlatformThreadBinding;
4
10
  exports.scheduledJobMatchesPlatformBinding = scheduledJobMatchesPlatformBinding;
5
11
  exports.scheduledJobMatchesCliContext = scheduledJobMatchesCliContext;
6
12
  function withoutThreadRoute(route) {
7
13
  const { threadId: _threadId, ...deliveryRoute } = route;
8
14
  return deliveryRoute;
9
15
  }
16
+ function getChannelPlatformBase(platform) {
17
+ return String(platform || '').trim().toLowerCase().split(':', 1)[0] || '';
18
+ }
19
+ function getChannelPlatformInstanceId(platform) {
20
+ const normalized = String(platform || '').trim().toLowerCase();
21
+ const separator = normalized.indexOf(':');
22
+ return separator >= 0 ? normalized.slice(separator + 1) : '';
23
+ }
24
+ function platformMatches(candidate, expectedBase) {
25
+ return getChannelPlatformBase(candidate) === expectedBase;
26
+ }
27
+ function routeWithPlatformInstance(route, platform) {
28
+ const instanceId = route.instanceId || getChannelPlatformInstanceId(platform);
29
+ return instanceId ? { ...route, instanceId } : route;
30
+ }
31
+ function routeTypeForPlatform(platform) {
32
+ const base = getChannelPlatformBase(platform);
33
+ return base === 'lark' || base === 'weixin' ? 'channel.chat' : base;
34
+ }
35
+ function routeFromPlatformThreadBinding(binding) {
36
+ return {
37
+ type: routeTypeForPlatform(binding.platform),
38
+ channelId: binding.chat_id,
39
+ instanceId: getChannelPlatformInstanceId(binding.platform) || undefined,
40
+ participantId: binding.platform_user_id,
41
+ };
42
+ }
10
43
  function scheduledJobMatchesPlatformBinding(job, binding) {
11
44
  return (job.workspaceId === binding.workspace_id &&
12
- job.platform === binding.platform &&
45
+ getChannelPlatformBase(job.platform) === getChannelPlatformBase(binding.platform) &&
13
46
  job.route.channelId === binding.chat_id &&
14
47
  String(job.route.participantId || '') === String(binding.platform_user_id || ''));
15
48
  }
@@ -18,7 +51,7 @@ function scheduledJobMatchesCliContext(job, context) {
18
51
  return false;
19
52
  }
20
53
  return (job.workspaceId === context.workspaceId &&
21
- job.platform === context.platform &&
54
+ getChannelPlatformBase(job.platform) === getChannelPlatformBase(context.platform) &&
22
55
  job.route.channelId === context.chatId &&
23
56
  String(job.route.participantId || '') === String(context.platformUserId || ''));
24
57
  }
@@ -16,7 +16,7 @@ class WeixinScheduleAdapter {
16
16
  });
17
17
  }
18
18
  supports(job) {
19
- return job.platform === 'weixin' && (job.route.type === 'channel.chat' || job.route.type === 'weixin_chat');
19
+ return (0, scheduled_job_route_js_1.platformMatches)(job.platform, 'weixin') && (job.route.type === 'channel.chat' || job.route.type === 'weixin_chat');
20
20
  }
21
21
  async execute(context) {
22
22
  const { job } = context;
@@ -32,7 +32,7 @@ class WeixinScheduleAdapter {
32
32
  if (!channelRuntime.sendScheduledMessage) {
33
33
  throw new Error('WeChat channel runtime does not support scheduled delivery.');
34
34
  }
35
- platformMessageId = await channelRuntime.sendScheduledMessage(job.workspaceId, (0, scheduled_job_route_js_1.withoutThreadRoute)(job.route), execution.replyText);
35
+ platformMessageId = await channelRuntime.sendScheduledMessage(job.workspaceId, (0, scheduled_job_route_js_1.routeWithPlatformInstance)((0, scheduled_job_route_js_1.withoutThreadRoute)(job.route), job.platform), execution.replyText);
36
36
  if (!platformMessageId) {
37
37
  throw new Error('WeChat gateway did not return a message id for scheduled delivery.');
38
38
  }
@@ -49,7 +49,7 @@ class WeixinScheduleAdapter {
49
49
  const route = job.route;
50
50
  const channelId = route.channelId;
51
51
  const participantId = route.participantId || '';
52
- const binding = this.options.store.getPlatformThreadBinding(job.workspaceId, channelId, participantId, 'weixin');
52
+ const binding = this.options.store.getPlatformThreadBinding(job.workspaceId, channelId, participantId, job.platform);
53
53
  if (binding?.thread_id && await this.threadExists(binding.thread_id)) {
54
54
  return binding.thread_id;
55
55
  }
@@ -68,9 +68,9 @@ class WeixinScheduleAdapter {
68
68
  created_at: now,
69
69
  updated_at: now,
70
70
  });
71
- const authorized = this.options.store.getAuthorizedUser(job.workspaceId, participantId, 'weixin');
71
+ const authorized = this.options.store.getAuthorizedUser(job.workspaceId, participantId, job.platform);
72
72
  if (authorized) {
73
- this.options.store.updateAuthorizedUserThread(job.workspaceId, participantId, thread.id, 'weixin');
73
+ this.options.store.updateAuthorizedUserThread(job.workspaceId, participantId, thread.id, job.platform);
74
74
  }
75
75
  return thread.id;
76
76
  }
@@ -214,6 +214,56 @@ function createIo() {
214
214
  });
215
215
  strict_1.default.match(read().stdout, /Sent file out\.pdf to chat-1: msg-file-1/);
216
216
  });
217
+ (0, node_test_1.default)('lac channel send-file normalizes instance-qualified platform env into route instance', async () => {
218
+ let capturedUrl = '';
219
+ let capturedBody = null;
220
+ const server = (0, node_http_1.createServer)(async (req, res) => {
221
+ if (req.method === 'POST') {
222
+ capturedUrl = req.url || '';
223
+ const chunks = [];
224
+ for await (const chunk of req) {
225
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
226
+ }
227
+ capturedBody = Buffer.concat(chunks).toString('utf8');
228
+ res.setHeader('content-type', 'application/json');
229
+ res.end(JSON.stringify({
230
+ ok: true,
231
+ data: {
232
+ platform: 'lark',
233
+ workspaceId: '知识库',
234
+ channelId: 'chat-1',
235
+ messageIds: ['msg-file-1'],
236
+ attachments: [{ kind: 'file', fileName: 'out.pdf', fileSize: 123 }],
237
+ },
238
+ }));
239
+ return;
240
+ }
241
+ res.statusCode = 404;
242
+ res.end(JSON.stringify({ ok: false, error: 'not found' }));
243
+ });
244
+ await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve));
245
+ const address = server.address();
246
+ (0, strict_1.default)(address && typeof address === 'object');
247
+ const { io } = createIo();
248
+ const exitCode = await (0, lac_js_1.runCli)(['channel', 'send-file', '--path', 'reports/out.pdf'], {
249
+ LOCAL_AI_CORE_BASE: `http://127.0.0.1:${address.port}/api/local/v1`,
250
+ LOCAL_AI_WORKSPACE_ID: '知识库',
251
+ LOCAL_AI_WORKSPACE_PATH: '/workspace/project',
252
+ LOCAL_AI_PLATFORM: 'lark:lark-1',
253
+ LOCAL_AI_CHAT_ID: 'chat-1',
254
+ LOCAL_AI_PLATFORM_USER_ID: 'user-1',
255
+ }, io);
256
+ server.close();
257
+ strict_1.default.equal(exitCode, 0);
258
+ strict_1.default.equal(capturedUrl, '/api/local/v1/platforms/lark/%E7%9F%A5%E8%AF%86%E5%BA%93/messages');
259
+ (0, strict_1.default)(capturedBody);
260
+ strict_1.default.deepEqual(JSON.parse(capturedBody).route, {
261
+ type: 'channel.chat',
262
+ channelId: 'chat-1',
263
+ instanceId: 'lark-1',
264
+ participantId: 'user-1',
265
+ });
266
+ });
217
267
  (0, node_test_1.default)('lac channel send-file posts allowed absolute paths through the same outbound message path', async () => {
218
268
  let capturedBody = null;
219
269
  const server = (0, node_http_1.createServer)(async (req, res) => {
@@ -562,6 +562,7 @@ model = "deepseek-v4-flash"
562
562
  knowledgeAttachments: {},
563
563
  workspaceRouter: {},
564
564
  scheduler: {},
565
+ scheduledJobs: {},
565
566
  start: async () => {
566
567
  started = true;
567
568
  },
@@ -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 {
@@ -3512,11 +3512,12 @@ const server_routes_js_1 = require("../../services/local-ai-core/src/runtime/ser
3512
3512
  });
3513
3513
  (0, node_test_1.default)('scheduled conversation executor uses execution policy hooks around a thread run', async () => {
3514
3514
  const calls = [];
3515
+ let runtimeEnv;
3515
3516
  const job = {
3516
3517
  id: 'job-1',
3517
3518
  workspaceId: '知识库',
3518
- platform: 'lark',
3519
- route: { type: 'channel.chat', channelId: 'chat-1', participantId: 'user-1', threadId: 'thread-1' },
3519
+ platform: 'lark:lark-1',
3520
+ route: { type: 'channel.chat', channelId: 'chat-1', instanceId: 'lark-1', participantId: 'user-1', threadId: 'thread-1' },
3520
3521
  executionMode: 'same-thread',
3521
3522
  triggerType: 'cron',
3522
3523
  cronExpr: '*/2 * * * *',
@@ -3533,6 +3534,7 @@ const server_routes_js_1 = require("../../services/local-ai-core/src/runtime/ser
3533
3534
  },
3534
3535
  workspaceRouter: {
3535
3536
  sendThreadMessage: async (threadId, prompt, options) => {
3537
+ runtimeEnv = options?.runtimeEnv;
3536
3538
  calls.push(`send:${threadId}:${prompt}:${options?.permissionMode || ''}`);
3537
3539
  return { runId: 'run-1' };
3538
3540
  },
@@ -3549,7 +3551,7 @@ const server_routes_js_1 = require("../../services/local-ai-core/src/runtime/ser
3549
3551
  kind: 'thread',
3550
3552
  threadId: 'thread-1',
3551
3553
  workspaceId: '知识库',
3552
- platform: 'lark',
3554
+ platform: 'lark:lark-1',
3553
3555
  route: job.route,
3554
3556
  }),
3555
3557
  beforeExecute: (target) => {
@@ -3564,6 +3566,13 @@ const server_routes_js_1 = require("../../services/local-ai-core/src/runtime/ser
3564
3566
  'send:thread-1:ping:bypassPermissions',
3565
3567
  'after:thread-1',
3566
3568
  ]);
3569
+ strict_1.default.deepEqual(runtimeEnv, {
3570
+ LOCAL_AI_PLATFORM: 'lark',
3571
+ LOCAL_AI_ROUTE_TYPE: 'channel.chat',
3572
+ LOCAL_AI_PLATFORM_INSTANCE_ID: 'lark-1',
3573
+ LOCAL_AI_CHAT_ID: 'chat-1',
3574
+ LOCAL_AI_PLATFORM_USER_ID: 'user-1',
3575
+ });
3567
3576
  strict_1.default.equal(result.replyText, 'done');
3568
3577
  });
3569
3578
  (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.34",
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{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};