@kafca/agentdock 0.1.23 → 0.1.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/dist/renderer/assets/{Badge-C2K5apfV.js → Badge-Bn2h-Qkf.js} +1 -1
- package/dist/renderer/assets/{Chat-DI2YeVKb.js → Chat-Cgo9aneg.js} +1 -1
- package/dist/renderer/assets/{ChatMarkdown-DMAr15Oi.js → ChatMarkdown-CYzHfSiR.js} +1 -1
- package/dist/renderer/assets/{Config-7rP3EuUf.js → Config-DljB2-eP.js} +1 -1
- package/dist/renderer/assets/{CronList-81QslYE8.js → CronList-DeVbiY9a.js} +1 -1
- package/dist/renderer/assets/{Dashboard-Db2T7rSZ.js → Dashboard-fSqx5sm8.js} +2 -2
- package/dist/renderer/assets/{EmptyState-BBJ3cTvB.js → EmptyState-DgqKDwlq.js} +1 -1
- package/dist/renderer/assets/{KnowledgeDetail-Dz_6flG3.js → KnowledgeDetail-u8s2SmPV.js} +1 -1
- package/dist/renderer/assets/{KnowledgeHome-DIh046mN.js → KnowledgeHome-BdQw8nbY.js} +1 -1
- package/dist/renderer/assets/{Logs-BXBtHJLf.js → Logs-DSbndMpy.js} +1 -1
- package/dist/renderer/assets/{Modal-BB2Av_Xs.js → Modal-0d0EmAuK.js} +1 -1
- package/dist/renderer/assets/{Page-DPSdvMgU.js → Page-CVbOH_Kh.js} +1 -1
- package/dist/renderer/assets/{ProjectDetail-C6EWGvGg.js → ProjectDetail-C91tF7uA.js} +1 -1
- package/dist/renderer/assets/{ProjectList-BBo5ygnS.js → ProjectList-D78Pc-BQ.js} +1 -1
- package/dist/renderer/assets/{Select-CNX-Tx_O.js → Select-BbKzAIuO.js} +1 -1
- package/dist/renderer/assets/{SessionChat-BIn46jqZ.js → SessionChat-BERvL5e4.js} +1 -1
- package/dist/renderer/assets/{SessionList-CZt6f1Rd.js → SessionList-Bomz335M.js} +1 -1
- package/dist/renderer/assets/ThreadChat-CLr3amU2.js +23 -0
- package/dist/renderer/assets/{Workspace-C_4tdpjX.js → Workspace-In91z4W2.js} +1 -1
- package/dist/renderer/assets/{arrow-left-cHr5wkpq.js → arrow-left-FBnVKKBl.js} +1 -1
- package/dist/renderer/assets/{book-open-4nx5C8T-.js → book-open-4_CuP6Sa.js} +1 -1
- package/dist/renderer/assets/{check-exTS-R-x.js → check-vsoVjvac.js} +1 -1
- package/dist/renderer/assets/{chevron-down-DSvxXQa0.js → chevron-down-DFpmFTJW.js} +1 -1
- package/dist/renderer/assets/{circle-DyvEovdw.js → circle-vRULegER.js} +1 -1
- package/dist/renderer/assets/desktop-BkMW-h5p.js +4 -0
- package/dist/renderer/assets/{desktop-B-KVT10D.js → desktop-ul0Tpzyc.js} +1 -1
- package/dist/renderer/assets/{funnel-DA9qVdTy.js → funnel-Gu0E_hJ_.js} +1 -1
- package/dist/renderer/assets/{heart-DuEV0ZRJ.js → heart-DsdofOHf.js} +1 -1
- package/dist/renderer/assets/{index-Biz-aexG.js → index-BD3aCyBa.js} +3 -3
- package/dist/renderer/assets/{index-BgflqkCN.js → index-pJUFobU7.js} +1 -1
- package/dist/renderer/assets/{pencil-DBDxeNmO.js → pencil-DbKmV8nD.js} +1 -1
- package/dist/renderer/assets/{play-IzlP83_7.js → play-BDMsRxSm.js} +1 -1
- package/dist/renderer/assets/{plug-CuT-qFnW.js → plug-t2dMl78-.js} +1 -1
- package/dist/renderer/assets/{plus-DEqgkn63.js → plus-BUb6zOAe.js} +1 -1
- package/dist/renderer/assets/projects-4F6D_Q8t.js +1 -0
- package/dist/renderer/assets/{save-D4sRo07y.js → save-C-_5rQdv.js} +1 -1
- package/dist/renderer/assets/{search-DbPZLuV8.js → search-R3ekHFPM.js} +1 -1
- package/dist/renderer/assets/{server-D1jUQmwN.js → server-BTuvHf5n.js} +1 -1
- package/dist/renderer/assets/{session-utils-Aife8ep2.js → session-utils-ClX6VPFG.js} +1 -1
- package/dist/renderer/assets/{sessions-DaH3H7gC.js → sessions-AFKIC-ub.js} +1 -1
- package/dist/renderer/assets/{shield-check-BGwUFWNr.js → shield-check-CqMW8CHe.js} +1 -1
- package/dist/renderer/assets/{trash-2-CIFBioBa.js → trash-2-BNLcHyUw.js} +1 -1
- package/dist/renderer/assets/{user-CnKcvHdo.js → user-BCCN8FYK.js} +1 -1
- package/dist/renderer/assets/{wifi-off-ClO53WGa.js → wifi-off-BsNsx3oX.js} +1 -1
- package/dist/renderer/index.html +1 -1
- package/dist-electron/electron/agent-runtime-detector.test.js +64 -0
- package/dist-electron/electron/architecture-docs.test.js +56 -0
- package/dist-electron/electron/channel-content.test.js +37 -0
- package/dist-electron/electron/lac-cli.test.js +297 -4
- package/dist-electron/electron/local-core-acp-content.test.js +39 -0
- package/dist-electron/electron/local-core-contracts.test.js +67 -0
- package/dist-electron/electron/local-core-refactor.test.js +789 -3
- package/dist-electron/electron/plugin-kernel.test.js +108 -0
- package/dist-electron/electron/renderer-packaging.test.js +77 -0
- package/dist-electron/electron/workspace-task-store.test.js +181 -0
- package/dist-electron/packages/contracts/src/local-core.js +110 -0
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-backend.js +67 -6
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-content.js +25 -4
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-permission-lifecycle.js +76 -0
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-progress.js +201 -0
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-response-processor.js +3 -2
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-session-coordinator.js +29 -0
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-store.js +74 -46
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-turn-coordinator.js +112 -210
- package/dist-electron/services/local-ai-core/src/acp/local-core-slash-commands.js +60 -0
- package/dist-electron/services/local-ai-core/src/acp/workspace-acp-permissions.js +5 -48
- package/dist-electron/services/local-ai-core/src/channel/lark/local-core-lark-gateway.js +83 -28
- package/dist-electron/services/local-ai-core/src/channel/lark/runtime-state.js +11 -0
- package/dist-electron/services/local-ai-core/src/channel/shared/content.js +23 -0
- package/dist-electron/services/local-ai-core/src/channel/shared/file-utils.js +13 -1
- package/dist-electron/services/local-ai-core/src/channel/weixin/local-core-weixin-gateway.js +31 -29
- package/dist-electron/services/local-ai-core/src/cli/lac.js +22 -17
- package/dist-electron/services/local-ai-core/src/kernel/bootstrap.js +1 -0
- package/dist-electron/services/local-ai-core/src/plugins/builtin/agent-localcore-acp-plugin.js +9 -0
- package/dist-electron/services/local-ai-core/src/router/workspace-route-config.js +221 -10
- package/dist-electron/services/local-ai-core/src/runtime/agent-runtime-detector.js +39 -9
- package/dist-electron/services/local-ai-core/src/runtime/local-core-controller.js +1 -0
- package/dist-electron/services/local-ai-core/src/runtime/runtime-detection-service.js +1 -0
- package/dist-electron/services/local-ai-core/src/runtime/server-routes.js +439 -0
- package/dist-electron/services/local-ai-core/src/runtime/server.js +208 -303
- package/dist-electron/services/local-ai-core/src/scheduler/job-id.js +15 -0
- package/dist-electron/services/local-ai-core/src/scheduler/scheduler-service.js +30 -5
- package/dist-electron/shared/desktop.js +34 -8
- package/dist-electron/src/pages/Threads/thread-chat-message-blocks.js +187 -0
- package/dist-electron/src/pages/Threads/thread-chat-model.js +58 -0
- package/dist-electron/src/pages/Threads/thread-chat-page-state.js +96 -0
- package/dist-electron/src/pages/Threads/thread-chat-permission.js +18 -0
- package/dist-electron/src/pages/Threads/thread-chat-permission.test.js +347 -0
- package/package.json +4 -2
- package/dist/renderer/assets/ThreadChat-BotD0gKQ.js +0 -23
- package/dist/renderer/assets/desktop-CVibRyAw.js +0 -4
- package/dist/renderer/assets/projects-DDtDN1rc.js +0 -1
|
@@ -41,7 +41,7 @@ function createIo() {
|
|
|
41
41
|
res.end(JSON.stringify({
|
|
42
42
|
ok: true,
|
|
43
43
|
data: {
|
|
44
|
-
id: 'job-
|
|
44
|
+
id: 'job:826aff79-570b-4308-822e-18318e2c96ba',
|
|
45
45
|
workspaceId: '知识库',
|
|
46
46
|
platform: 'lark',
|
|
47
47
|
route: {
|
|
@@ -97,7 +97,7 @@ function createIo() {
|
|
|
97
97
|
description: 'two-minute ping',
|
|
98
98
|
enabled: true,
|
|
99
99
|
});
|
|
100
|
-
strict_1.default.match(read().stdout, /Created scheduler job
|
|
100
|
+
strict_1.default.match(read().stdout, /Created scheduler job 826aff79/);
|
|
101
101
|
});
|
|
102
102
|
(0, node_test_1.default)('lac scheduler add posts a local job without IM context', async () => {
|
|
103
103
|
let capturedBody = null;
|
|
@@ -162,6 +162,131 @@ function createIo() {
|
|
|
162
162
|
});
|
|
163
163
|
strict_1.default.match(read().stdout, /Created scheduler job job-local-1/);
|
|
164
164
|
});
|
|
165
|
+
(0, node_test_1.default)('lac channel send-file posts a workspace-relative file through outbound message parts', async () => {
|
|
166
|
+
let capturedBody = null;
|
|
167
|
+
const server = (0, node_http_1.createServer)(async (req, res) => {
|
|
168
|
+
if (req.method === 'POST' && req.url === '/api/local/v1/platforms/lark/%E7%9F%A5%E8%AF%86%E5%BA%93/messages') {
|
|
169
|
+
const chunks = [];
|
|
170
|
+
for await (const chunk of req) {
|
|
171
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
172
|
+
}
|
|
173
|
+
capturedBody = Buffer.concat(chunks).toString('utf8');
|
|
174
|
+
res.setHeader('content-type', 'application/json');
|
|
175
|
+
res.end(JSON.stringify({
|
|
176
|
+
ok: true,
|
|
177
|
+
data: {
|
|
178
|
+
platform: 'lark',
|
|
179
|
+
workspaceId: '知识库',
|
|
180
|
+
channelId: 'chat-1',
|
|
181
|
+
messageIds: ['msg-file-1'],
|
|
182
|
+
attachments: [{
|
|
183
|
+
kind: 'file',
|
|
184
|
+
attachmentId: 'file-key-1',
|
|
185
|
+
fileName: 'out.pdf',
|
|
186
|
+
fileSize: 123,
|
|
187
|
+
metadata: { fileKey: 'file-key-1' },
|
|
188
|
+
}],
|
|
189
|
+
},
|
|
190
|
+
}));
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
res.statusCode = 404;
|
|
194
|
+
res.end(JSON.stringify({ ok: false, error: 'not found' }));
|
|
195
|
+
});
|
|
196
|
+
await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve));
|
|
197
|
+
const address = server.address();
|
|
198
|
+
(0, strict_1.default)(address && typeof address === 'object');
|
|
199
|
+
const { io, read } = createIo();
|
|
200
|
+
const exitCode = await (0, lac_js_1.runCli)(['channel', 'send-file', '--path', 'reports/out.pdf', '--name', 'out.pdf'], {
|
|
201
|
+
LOCAL_AI_CORE_BASE: `http://127.0.0.1:${address.port}/api/local/v1`,
|
|
202
|
+
LOCAL_AI_WORKSPACE_ID: '知识库',
|
|
203
|
+
LOCAL_AI_WORKSPACE_PATH: '/workspace/project',
|
|
204
|
+
LOCAL_AI_PLATFORM: 'lark',
|
|
205
|
+
LOCAL_AI_CHAT_ID: 'chat-1',
|
|
206
|
+
LOCAL_AI_PLATFORM_USER_ID: 'user-1',
|
|
207
|
+
}, io);
|
|
208
|
+
server.close();
|
|
209
|
+
strict_1.default.equal(exitCode, 0);
|
|
210
|
+
(0, strict_1.default)(capturedBody);
|
|
211
|
+
strict_1.default.deepEqual(JSON.parse(capturedBody), {
|
|
212
|
+
route: {
|
|
213
|
+
type: 'channel.chat',
|
|
214
|
+
channelId: 'chat-1',
|
|
215
|
+
participantId: 'user-1',
|
|
216
|
+
},
|
|
217
|
+
parts: [{
|
|
218
|
+
type: 'file',
|
|
219
|
+
path: 'reports/out.pdf',
|
|
220
|
+
fileName: 'out.pdf',
|
|
221
|
+
metadata: {
|
|
222
|
+
workspacePath: '/workspace/project',
|
|
223
|
+
},
|
|
224
|
+
}],
|
|
225
|
+
});
|
|
226
|
+
strict_1.default.match(read().stdout, /Sent file out\.pdf to chat-1: msg-file-1/);
|
|
227
|
+
});
|
|
228
|
+
(0, node_test_1.default)('lac channel send-file posts allowed absolute paths through the same outbound message path', async () => {
|
|
229
|
+
let capturedBody = null;
|
|
230
|
+
const server = (0, node_http_1.createServer)(async (req, res) => {
|
|
231
|
+
if (req.method === 'POST' && req.url === '/api/local/v1/platforms/lark/%E7%9F%A5%E8%AF%86%E5%BA%93/messages') {
|
|
232
|
+
const chunks = [];
|
|
233
|
+
for await (const chunk of req) {
|
|
234
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
235
|
+
}
|
|
236
|
+
capturedBody = Buffer.concat(chunks).toString('utf8');
|
|
237
|
+
res.setHeader('content-type', 'application/json');
|
|
238
|
+
res.end(JSON.stringify({
|
|
239
|
+
ok: true,
|
|
240
|
+
data: {
|
|
241
|
+
platform: 'lark',
|
|
242
|
+
workspaceId: '知识库',
|
|
243
|
+
channelId: 'chat-1',
|
|
244
|
+
messageIds: ['msg-file-2'],
|
|
245
|
+
attachments: [{
|
|
246
|
+
kind: 'file',
|
|
247
|
+
attachmentId: 'file-key-2',
|
|
248
|
+
fileName: 'absolute.pdf',
|
|
249
|
+
fileSize: 456,
|
|
250
|
+
metadata: { fileKey: 'file-key-2' },
|
|
251
|
+
}],
|
|
252
|
+
},
|
|
253
|
+
}));
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
res.statusCode = 404;
|
|
257
|
+
res.end(JSON.stringify({ ok: false, error: 'not found' }));
|
|
258
|
+
});
|
|
259
|
+
await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve));
|
|
260
|
+
const address = server.address();
|
|
261
|
+
(0, strict_1.default)(address && typeof address === 'object');
|
|
262
|
+
const { io, read } = createIo();
|
|
263
|
+
const exitCode = await (0, lac_js_1.runCli)(['channel', 'send-file', '--path', '/tmp/absolute.pdf'], {
|
|
264
|
+
LOCAL_AI_CORE_BASE: `http://127.0.0.1:${address.port}/api/local/v1`,
|
|
265
|
+
LOCAL_AI_WORKSPACE_ID: '知识库',
|
|
266
|
+
LOCAL_AI_WORKSPACE_PATH: '/workspace/project',
|
|
267
|
+
LOCAL_AI_PLATFORM: 'lark',
|
|
268
|
+
LOCAL_AI_CHAT_ID: 'chat-1',
|
|
269
|
+
LOCAL_AI_PLATFORM_USER_ID: 'user-1',
|
|
270
|
+
}, io);
|
|
271
|
+
server.close();
|
|
272
|
+
strict_1.default.equal(exitCode, 0);
|
|
273
|
+
(0, strict_1.default)(capturedBody);
|
|
274
|
+
strict_1.default.deepEqual(JSON.parse(capturedBody), {
|
|
275
|
+
route: {
|
|
276
|
+
type: 'channel.chat',
|
|
277
|
+
channelId: 'chat-1',
|
|
278
|
+
participantId: 'user-1',
|
|
279
|
+
},
|
|
280
|
+
parts: [{
|
|
281
|
+
type: 'file',
|
|
282
|
+
path: '/tmp/absolute.pdf',
|
|
283
|
+
metadata: {
|
|
284
|
+
workspacePath: '/workspace/project',
|
|
285
|
+
},
|
|
286
|
+
}],
|
|
287
|
+
});
|
|
288
|
+
strict_1.default.match(read().stdout, /Sent file absolute\.pdf to chat-1: msg-file-2/);
|
|
289
|
+
});
|
|
165
290
|
(0, node_test_1.default)('lac scheduler list shows workspace jobs by default', async () => {
|
|
166
291
|
const server = (0, node_http_1.createServer)((req, res) => {
|
|
167
292
|
if (req.method === 'GET' && req.url === '/api/local/v1/scheduler/jobs?workspace_id=%E7%9F%A5%E8%AF%86%E5%BA%93') {
|
|
@@ -171,7 +296,7 @@ function createIo() {
|
|
|
171
296
|
data: {
|
|
172
297
|
jobs: [
|
|
173
298
|
{
|
|
174
|
-
id: 'job-
|
|
299
|
+
id: 'job:826aff79-570b-4308-822e-18318e2c96ba',
|
|
175
300
|
workspaceId: '知识库',
|
|
176
301
|
platform: 'lark',
|
|
177
302
|
route: { type: 'channel.chat', channelId: 'chat-1', participantId: 'user-1', threadId: 'thread-1' },
|
|
@@ -219,9 +344,177 @@ function createIo() {
|
|
|
219
344
|
}, io);
|
|
220
345
|
server.close();
|
|
221
346
|
strict_1.default.equal(exitCode, 0);
|
|
222
|
-
strict_1.default.match(read().stdout, /
|
|
347
|
+
strict_1.default.match(read().stdout, /826aff79/);
|
|
348
|
+
strict_1.default.doesNotMatch(read().stdout, /job:826aff79/);
|
|
223
349
|
strict_1.default.match(read().stdout, /job-2/);
|
|
224
350
|
});
|
|
351
|
+
(0, node_test_1.default)('lac scheduler info prints the short job id', async () => {
|
|
352
|
+
const server = (0, node_http_1.createServer)((req, res) => {
|
|
353
|
+
if (req.method === 'GET' && req.url === '/api/local/v1/scheduler/jobs/826aff79') {
|
|
354
|
+
res.setHeader('content-type', 'application/json');
|
|
355
|
+
res.end(JSON.stringify({
|
|
356
|
+
ok: true,
|
|
357
|
+
data: {
|
|
358
|
+
id: 'job:826aff79-570b-4308-822e-18318e2c96ba',
|
|
359
|
+
workspaceId: '知识库',
|
|
360
|
+
platform: 'lark',
|
|
361
|
+
route: { type: 'channel.chat', channelId: 'chat-1', participantId: 'user-1', threadId: 'thread-1' },
|
|
362
|
+
executionMode: 'side-thread',
|
|
363
|
+
triggerType: 'cron',
|
|
364
|
+
cronExpr: '30 18 * * *',
|
|
365
|
+
promptTemplate: 'ping',
|
|
366
|
+
description: 'daily ping',
|
|
367
|
+
enabled: true,
|
|
368
|
+
concurrencyPolicy: 'skip_if_running',
|
|
369
|
+
createdAt: '2026-04-22T06:00:00.000Z',
|
|
370
|
+
updatedAt: '2026-04-22T06:00:00.000Z',
|
|
371
|
+
},
|
|
372
|
+
}));
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
if (req.method === 'GET' && req.url === '/api/local/v1/scheduler/jobs/826aff79/runs') {
|
|
376
|
+
res.setHeader('content-type', 'application/json');
|
|
377
|
+
res.end(JSON.stringify({ ok: true, data: { runs: [] } }));
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
res.statusCode = 404;
|
|
381
|
+
res.end(JSON.stringify({ ok: false, error: 'not found' }));
|
|
382
|
+
});
|
|
383
|
+
await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve));
|
|
384
|
+
const address = server.address();
|
|
385
|
+
(0, strict_1.default)(address && typeof address === 'object');
|
|
386
|
+
const { io, read } = createIo();
|
|
387
|
+
const exitCode = await (0, lac_js_1.runCli)(['scheduler', 'info', '826aff79'], {
|
|
388
|
+
LOCAL_AI_CORE_BASE: `http://127.0.0.1:${address.port}/api/local/v1`,
|
|
389
|
+
}, io);
|
|
390
|
+
server.close();
|
|
391
|
+
strict_1.default.equal(exitCode, 0);
|
|
392
|
+
strict_1.default.match(read().stdout, /Job: 826aff79/);
|
|
393
|
+
strict_1.default.doesNotMatch(read().stdout, /job:826aff79/);
|
|
394
|
+
});
|
|
395
|
+
(0, node_test_1.default)('lac scheduler edit patches a short job id and normalizes execution mode', async () => {
|
|
396
|
+
let capturedBody = null;
|
|
397
|
+
const server = (0, node_http_1.createServer)(async (req, res) => {
|
|
398
|
+
if (req.method === 'PATCH' && req.url === '/api/local/v1/scheduler/jobs/826aff79') {
|
|
399
|
+
const chunks = [];
|
|
400
|
+
for await (const chunk of req) {
|
|
401
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
402
|
+
}
|
|
403
|
+
capturedBody = Buffer.concat(chunks).toString('utf8');
|
|
404
|
+
res.setHeader('content-type', 'application/json');
|
|
405
|
+
res.end(JSON.stringify({
|
|
406
|
+
ok: true,
|
|
407
|
+
data: {
|
|
408
|
+
id: 'job:826aff79-570b-4308-822e-18318e2c96ba',
|
|
409
|
+
workspaceId: '知识库',
|
|
410
|
+
platform: 'lark',
|
|
411
|
+
route: { type: 'channel.chat', channelId: 'chat-1', participantId: 'user-1', threadId: 'thread-1' },
|
|
412
|
+
executionMode: 'side-thread',
|
|
413
|
+
triggerType: 'cron',
|
|
414
|
+
cronExpr: '0 10 * * *',
|
|
415
|
+
promptTemplate: 'updated ping',
|
|
416
|
+
description: 'daily updated ping',
|
|
417
|
+
enabled: false,
|
|
418
|
+
concurrencyPolicy: 'skip_if_running',
|
|
419
|
+
createdAt: '2026-04-22T06:00:00.000Z',
|
|
420
|
+
updatedAt: '2026-04-22T07:00:00.000Z',
|
|
421
|
+
},
|
|
422
|
+
}));
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
res.statusCode = 404;
|
|
426
|
+
res.end(JSON.stringify({ ok: false, error: 'not found' }));
|
|
427
|
+
});
|
|
428
|
+
await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve));
|
|
429
|
+
const address = server.address();
|
|
430
|
+
(0, strict_1.default)(address && typeof address === 'object');
|
|
431
|
+
const { io, read } = createIo();
|
|
432
|
+
const exitCode = await (0, lac_js_1.runCli)([
|
|
433
|
+
'scheduler',
|
|
434
|
+
'edit',
|
|
435
|
+
'826aff79',
|
|
436
|
+
'--cron',
|
|
437
|
+
'0 10 * * *',
|
|
438
|
+
'--message',
|
|
439
|
+
'updated ping',
|
|
440
|
+
'--desc',
|
|
441
|
+
'daily updated ping',
|
|
442
|
+
'--enabled',
|
|
443
|
+
'false',
|
|
444
|
+
'--execution-mode',
|
|
445
|
+
'side_thread',
|
|
446
|
+
], {
|
|
447
|
+
LOCAL_AI_CORE_BASE: `http://127.0.0.1:${address.port}/api/local/v1`,
|
|
448
|
+
}, io);
|
|
449
|
+
server.close();
|
|
450
|
+
strict_1.default.equal(exitCode, 0);
|
|
451
|
+
(0, strict_1.default)(capturedBody);
|
|
452
|
+
strict_1.default.deepEqual(JSON.parse(capturedBody), {
|
|
453
|
+
cronExpr: '0 10 * * *',
|
|
454
|
+
promptTemplate: 'updated ping',
|
|
455
|
+
description: 'daily updated ping',
|
|
456
|
+
enabled: false,
|
|
457
|
+
executionMode: 'side-thread',
|
|
458
|
+
});
|
|
459
|
+
strict_1.default.match(read().stdout, /Updated scheduler job 826aff79/);
|
|
460
|
+
strict_1.default.doesNotMatch(read().stdout, /job:826aff79/);
|
|
461
|
+
});
|
|
462
|
+
(0, node_test_1.default)('lac scheduler del deletes a short job id', async () => {
|
|
463
|
+
const server = (0, node_http_1.createServer)((req, res) => {
|
|
464
|
+
if (req.method === 'DELETE' && req.url === '/api/local/v1/scheduler/jobs/826aff79') {
|
|
465
|
+
res.setHeader('content-type', 'application/json');
|
|
466
|
+
res.end(JSON.stringify({ ok: true, data: { deleted: true } }));
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
res.statusCode = 404;
|
|
470
|
+
res.end(JSON.stringify({ ok: false, error: 'not found' }));
|
|
471
|
+
});
|
|
472
|
+
await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve));
|
|
473
|
+
const address = server.address();
|
|
474
|
+
(0, strict_1.default)(address && typeof address === 'object');
|
|
475
|
+
const { io, read } = createIo();
|
|
476
|
+
const exitCode = await (0, lac_js_1.runCli)(['scheduler', 'del', '826aff79'], {
|
|
477
|
+
LOCAL_AI_CORE_BASE: `http://127.0.0.1:${address.port}/api/local/v1`,
|
|
478
|
+
}, io);
|
|
479
|
+
server.close();
|
|
480
|
+
strict_1.default.equal(exitCode, 0);
|
|
481
|
+
strict_1.default.match(read().stdout, /Deleted scheduler job 826aff79/);
|
|
482
|
+
strict_1.default.doesNotMatch(read().stdout, /job:826aff79/);
|
|
483
|
+
});
|
|
484
|
+
(0, node_test_1.default)('lac scheduler run triggers a short job id', async () => {
|
|
485
|
+
const server = (0, node_http_1.createServer)((req, res) => {
|
|
486
|
+
if (req.method === 'POST' && req.url === '/api/local/v1/scheduler/jobs/826aff79/run') {
|
|
487
|
+
res.setHeader('content-type', 'application/json');
|
|
488
|
+
res.end(JSON.stringify({
|
|
489
|
+
ok: true,
|
|
490
|
+
data: {
|
|
491
|
+
id: 'run-1',
|
|
492
|
+
jobId: 'job:826aff79-570b-4308-822e-18318e2c96ba',
|
|
493
|
+
status: 'queued',
|
|
494
|
+
triggeredAt: '2026-04-22T07:00:00.000Z',
|
|
495
|
+
startedAt: '2026-04-22T07:00:00.000Z',
|
|
496
|
+
completedAt: '',
|
|
497
|
+
output: '',
|
|
498
|
+
error: '',
|
|
499
|
+
},
|
|
500
|
+
}));
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
res.statusCode = 404;
|
|
504
|
+
res.end(JSON.stringify({ ok: false, error: 'not found' }));
|
|
505
|
+
});
|
|
506
|
+
await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve));
|
|
507
|
+
const address = server.address();
|
|
508
|
+
(0, strict_1.default)(address && typeof address === 'object');
|
|
509
|
+
const { io, read } = createIo();
|
|
510
|
+
const exitCode = await (0, lac_js_1.runCli)(['scheduler', 'run', '826aff79'], {
|
|
511
|
+
LOCAL_AI_CORE_BASE: `http://127.0.0.1:${address.port}/api/local/v1`,
|
|
512
|
+
}, io);
|
|
513
|
+
server.close();
|
|
514
|
+
strict_1.default.equal(exitCode, 0);
|
|
515
|
+
strict_1.default.match(read().stdout, /Triggered scheduler job 826aff79: queued/);
|
|
516
|
+
strict_1.default.doesNotMatch(read().stdout, /job:826aff79/);
|
|
517
|
+
});
|
|
225
518
|
(0, node_test_1.default)('lac scheduler list --thread filters by current thread context', async () => {
|
|
226
519
|
const server = (0, node_http_1.createServer)((req, res) => {
|
|
227
520
|
if (req.method === 'GET' && req.url === '/api/local/v1/scheduler/jobs?workspace_id=%E7%9F%A5%E8%AF%86%E5%BA%93') {
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const node_test_1 = __importDefault(require("node:test"));
|
|
7
|
+
const strict_1 = __importDefault(require("node:assert/strict"));
|
|
8
|
+
const local_core_acp_content_js_1 = require("../services/local-ai-core/src/acp/local-core-acp-content.js");
|
|
9
|
+
(0, node_test_1.default)('thread message input keeps inbound file content parts', () => {
|
|
10
|
+
const normalized = (0, local_core_acp_content_js_1.normalizeThreadMessageInput)({
|
|
11
|
+
displayText: '',
|
|
12
|
+
contentParts: [{
|
|
13
|
+
type: 'file',
|
|
14
|
+
uri: 'file:///tmp/report.pdf',
|
|
15
|
+
fileName: 'report.pdf',
|
|
16
|
+
mimeType: 'application/pdf',
|
|
17
|
+
size: 1234,
|
|
18
|
+
}],
|
|
19
|
+
});
|
|
20
|
+
strict_1.default.equal(normalized.displayText, '[File: report.pdf]');
|
|
21
|
+
strict_1.default.deepEqual(normalized.contentParts, [{
|
|
22
|
+
type: 'file',
|
|
23
|
+
uri: 'file:///tmp/report.pdf',
|
|
24
|
+
fileName: 'report.pdf',
|
|
25
|
+
mimeType: 'application/pdf',
|
|
26
|
+
size: 1234,
|
|
27
|
+
}]);
|
|
28
|
+
});
|
|
29
|
+
(0, node_test_1.default)('thread message input summarizes multiple non-text attachments', () => {
|
|
30
|
+
const normalized = (0, local_core_acp_content_js_1.normalizeThreadMessageInput)({
|
|
31
|
+
displayText: '',
|
|
32
|
+
contentParts: [
|
|
33
|
+
{ type: 'image', uri: 'file:///tmp/a.png', fileName: 'a.png' },
|
|
34
|
+
{ type: 'file', path: '/tmp/report.pdf', fileName: 'report.pdf' },
|
|
35
|
+
],
|
|
36
|
+
});
|
|
37
|
+
strict_1.default.equal(normalized.displayText, '[Image: a.png]\n[File: report.pdf]');
|
|
38
|
+
strict_1.default.equal(normalized.contentParts.length, 2);
|
|
39
|
+
});
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const node_test_1 = __importDefault(require("node:test"));
|
|
7
|
+
const strict_1 = __importDefault(require("node:assert/strict"));
|
|
8
|
+
const index_js_1 = require("../packages/contracts/src/index.js");
|
|
9
|
+
(0, node_test_1.default)('scheduled job execution mode normalization accepts canonical aliases', () => {
|
|
10
|
+
strict_1.default.equal((0, index_js_1.normalizeScheduledJobExecutionMode)(undefined), 'same-thread');
|
|
11
|
+
strict_1.default.equal((0, index_js_1.normalizeScheduledJobExecutionMode)('same_thread'), 'same-thread');
|
|
12
|
+
strict_1.default.equal((0, index_js_1.normalizeScheduledJobExecutionMode)('SIDE THREAD'), 'side-thread');
|
|
13
|
+
});
|
|
14
|
+
(0, node_test_1.default)('scheduled job execution mode normalization rejects unsupported values', () => {
|
|
15
|
+
strict_1.default.throws(() => (0, index_js_1.normalizeScheduledJobExecutionMode)('foreground'), /execution mode must be same-thread or side-thread/);
|
|
16
|
+
});
|
|
17
|
+
(0, node_test_1.default)('scheduled job trigger type normalization accepts canonical aliases', () => {
|
|
18
|
+
strict_1.default.equal((0, index_js_1.normalizeScheduledJobTriggerType)(undefined), 'cron');
|
|
19
|
+
strict_1.default.equal((0, index_js_1.normalizeScheduledJobTriggerType)('CRON'), 'cron');
|
|
20
|
+
strict_1.default.equal((0, index_js_1.normalizeScheduledJobTriggerType)('one time'), 'once');
|
|
21
|
+
});
|
|
22
|
+
(0, node_test_1.default)('scheduled job trigger type normalization rejects unsupported values', () => {
|
|
23
|
+
strict_1.default.throws(() => (0, index_js_1.normalizeScheduledJobTriggerType)('interval'), /trigger type must be cron or once/);
|
|
24
|
+
});
|
|
25
|
+
(0, node_test_1.default)('channel platform normalization trims and lowercases platform ids', () => {
|
|
26
|
+
strict_1.default.equal((0, index_js_1.normalizeChannelPlatform)(' Lark '), 'lark');
|
|
27
|
+
strict_1.default.equal((0, index_js_1.normalizeChannelPlatform)('Weixin:Bot-A'), 'weixin:bot-a');
|
|
28
|
+
});
|
|
29
|
+
(0, node_test_1.default)('channel platform normalization rejects empty platform ids', () => {
|
|
30
|
+
strict_1.default.throws(() => (0, index_js_1.normalizeChannelPlatform)(' '), /platform is required/);
|
|
31
|
+
});
|
|
32
|
+
(0, node_test_1.default)('permission response normalization accepts button and text aliases', () => {
|
|
33
|
+
strict_1.default.equal((0, index_js_1.normalizePermissionResponse)('perm:allow_all'), 'allow all');
|
|
34
|
+
strict_1.default.equal((0, index_js_1.normalizePermissionResponse)('allow_once'), 'allow');
|
|
35
|
+
strict_1.default.equal((0, index_js_1.normalizePermissionResponse)('reject'), 'deny');
|
|
36
|
+
strict_1.default.equal((0, index_js_1.normalizePermissionResponse)('始终允许'), 'allow all');
|
|
37
|
+
});
|
|
38
|
+
(0, node_test_1.default)('agent task status normalization accepts canonical aliases', () => {
|
|
39
|
+
strict_1.default.equal((0, index_js_1.normalizeAgentTaskStatus)(undefined), 'created');
|
|
40
|
+
strict_1.default.equal((0, index_js_1.normalizeAgentTaskStatus)('waiting for user'), 'waiting_for_user');
|
|
41
|
+
strict_1.default.equal((0, index_js_1.normalizeAgentTaskStatus)('canceled'), 'cancelled');
|
|
42
|
+
});
|
|
43
|
+
(0, node_test_1.default)('agent task status normalization rejects unsupported values', () => {
|
|
44
|
+
strict_1.default.throws(() => (0, index_js_1.normalizeAgentTaskStatus)('paused'), /Agent task status must be/);
|
|
45
|
+
});
|
|
46
|
+
(0, node_test_1.default)('run status normalization accepts canonical aliases', () => {
|
|
47
|
+
strict_1.default.equal((0, index_js_1.normalizeRunStatus)(undefined), 'queued');
|
|
48
|
+
strict_1.default.equal((0, index_js_1.normalizeRunStatus)('awaiting input'), 'awaiting_input');
|
|
49
|
+
strict_1.default.equal((0, index_js_1.normalizeRunStatus)('canceled'), 'interrupted');
|
|
50
|
+
});
|
|
51
|
+
(0, node_test_1.default)('scheduled job run status normalization accepts canonical aliases', () => {
|
|
52
|
+
strict_1.default.equal((0, index_js_1.normalizeScheduledJobRunStatus)(undefined), 'queued');
|
|
53
|
+
strict_1.default.equal((0, index_js_1.normalizeScheduledJobRunStatus)('complete'), 'succeeded');
|
|
54
|
+
strict_1.default.equal((0, index_js_1.normalizeScheduledJobRunStatus)('cancelled'), 'skipped');
|
|
55
|
+
});
|
|
56
|
+
(0, node_test_1.default)('channel content part type normalization accepts canonical aliases', () => {
|
|
57
|
+
strict_1.default.equal((0, index_js_1.normalizeChannelContentPartType)(' TEXT '), 'text');
|
|
58
|
+
strict_1.default.equal((0, index_js_1.normalizeChannelContentPartType)('permission-card'), 'permission_card');
|
|
59
|
+
});
|
|
60
|
+
(0, node_test_1.default)('channel content part type normalization rejects unsupported values', () => {
|
|
61
|
+
strict_1.default.throws(() => (0, index_js_1.normalizeChannelContentPartType)('audio'), /Channel content part type must be/);
|
|
62
|
+
});
|
|
63
|
+
(0, node_test_1.default)('approval request status normalization accepts canonical aliases', () => {
|
|
64
|
+
strict_1.default.equal((0, index_js_1.normalizeApprovalRequestStatus)(undefined), 'pending');
|
|
65
|
+
strict_1.default.equal((0, index_js_1.normalizeApprovalRequestStatus)('approve'), 'approved');
|
|
66
|
+
strict_1.default.equal((0, index_js_1.normalizeApprovalRequestStatus)('canceled'), 'cancelled');
|
|
67
|
+
});
|