@kafca/agentdock 0.1.41 → 0.1.43

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 (102) hide show
  1. package/README.md +10 -0
  2. package/dist/renderer/assets/{Badge-BX3RC8l6.js → Badge-CbG6yRSm.js} +1 -1
  3. package/dist/renderer/assets/{Chat-DJwIciel.js → Chat-BvNNWGGX.js} +1 -1
  4. package/dist/renderer/assets/{ChatMarkdown-DfGbRR0S.js → ChatMarkdown-Ct-PvJB8.js} +1 -1
  5. package/dist/renderer/assets/{Config-2x2RDL3j.js → Config-lQX2qVVV.js} +2 -2
  6. package/dist/renderer/assets/CronList-Dj_3muVG.js +1 -0
  7. package/dist/renderer/assets/{Dashboard-2Wcx_bvJ.js → Dashboard-eh_RhGYb.js} +2 -2
  8. package/dist/renderer/assets/{EmptyState-DoCpF2tn.js → EmptyState-Bn2Qh14U.js} +1 -1
  9. package/dist/renderer/assets/{KnowledgeDetail-CBRu2bXX.js → KnowledgeDetail-Bsz6Ou41.js} +2 -2
  10. package/dist/renderer/assets/{KnowledgeHome-CItdlDVR.js → KnowledgeHome-Cgj4XFXn.js} +2 -2
  11. package/dist/renderer/assets/{Logs-Cd_7ZOXc.js → Logs-Dp-NF6GN.js} +1 -1
  12. package/dist/renderer/assets/{Modal-B4eOiBsB.js → Modal-B6YPPBN6.js} +1 -1
  13. package/dist/renderer/assets/MonitorList-xEZWg460.js +1 -0
  14. package/dist/renderer/assets/{Page-C5VH4D9U.js → Page-Bn7RjGOS.js} +1 -1
  15. package/dist/renderer/assets/{ProjectDetail-D_DA--IP.js → ProjectDetail-Cv_jIE61.js} +2 -2
  16. package/dist/renderer/assets/{ProjectList-CtCXJ50u.js → ProjectList-BDk5_gqY.js} +1 -1
  17. package/dist/renderer/assets/{Select-B6E68LcN.js → Select-xshfMIEQ.js} +1 -1
  18. package/dist/renderer/assets/SessionChat-BkHy90z3.js +1 -0
  19. package/dist/renderer/assets/{SessionList-Do-5-Xx6.js → SessionList-BZyXT92L.js} +1 -1
  20. package/dist/renderer/assets/{ThreadChat-B1tEtE3V.js → ThreadChat-DUOIyXrS.js} +7 -7
  21. package/dist/renderer/assets/{Workspace-BlhS2RFw.js → Workspace-Dl80fNEC.js} +1 -1
  22. package/dist/renderer/assets/{arrow-left-DF1_F9Pk.js → arrow-left-C54ZI-AS.js} +1 -1
  23. package/dist/renderer/assets/{book-open-DxRTGpWO.js → book-open-Dl7GO0zn.js} +1 -1
  24. package/dist/renderer/assets/{check-BAqPPYkf.js → check-CiqgtrOL.js} +1 -1
  25. package/dist/renderer/assets/{chevron-down-DIZZgSb3.js → chevron-down-DTL2OuVh.js} +1 -1
  26. package/dist/renderer/assets/{circle-B5raL_XK.js → circle-DaVKfa3P.js} +1 -1
  27. package/dist/renderer/assets/desktop-C6q6wBae.js +5 -0
  28. package/dist/renderer/assets/desktop-jaAiayNB.js +1 -0
  29. package/dist/renderer/assets/en-D2SkCrhG.js +1 -0
  30. package/dist/renderer/assets/{funnel-BPjLpVSB.js → funnel-CrmnLMJI.js} +1 -1
  31. package/dist/renderer/assets/{heart-D2M1xN1N.js → heart-BMfQI7y_.js} +1 -1
  32. package/dist/renderer/assets/{index-Cx71F_Lz.js → index-HPNb1zfx.js} +39 -34
  33. package/dist/renderer/assets/{index-BijJAYmo.js → index-nreiKY1f.js} +3 -3
  34. package/dist/renderer/assets/{pencil-DlDr8Mmp.js → pencil-wTQ4l465.js} +1 -1
  35. package/dist/renderer/assets/{play-BOEG_mY8.js → play-BK--MXmw.js} +1 -1
  36. package/dist/renderer/assets/{plug-BI27elC-.js → plug-BIx9fjip.js} +1 -1
  37. package/dist/renderer/assets/{plus-BhURuFIQ.js → plus-Dn7JFWQ8.js} +1 -1
  38. package/dist/renderer/assets/projects-brJZgwEJ.js +1 -0
  39. package/dist/renderer/assets/{save-RwkHNm9e.js → save-CC3zOSWb.js} +1 -1
  40. package/dist/renderer/assets/{search-DMNtm2WP.js → search-CDTy9Czu.js} +1 -1
  41. package/dist/renderer/assets/{server-CNaxKyAq.js → server-DtQk3t2a.js} +1 -1
  42. package/dist/renderer/assets/{session-utils-vsALZkZN.js → session-utils-4ep5D66T.js} +1 -1
  43. package/dist/renderer/assets/{sessions-BY-R1IL_.js → sessions-Dor1LteH.js} +1 -1
  44. package/dist/renderer/assets/{shield-check-BF-4oJbj.js → shield-check-Cz2LpU6r.js} +1 -1
  45. package/dist/renderer/assets/{trash-2-DduflM4q.js → trash-2-C2EmWFZV.js} +1 -1
  46. package/dist/renderer/assets/{user-DBcvnuW4.js → user-I8B-cs5A.js} +1 -1
  47. package/dist/renderer/assets/{wifi-off-X1nXESYu.js → wifi-off-CPevTQJn.js} +1 -1
  48. package/dist/renderer/assets/zh-DIcdHycM.js +1 -0
  49. package/dist/renderer/index.html +1 -1
  50. package/dist-electron/packages/contracts/src/local-core.js +28 -0
  51. package/dist-electron/packages/core-sdk/src/index.js +32 -0
  52. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-backend.js +76 -39
  53. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-session-coordinator.js +13 -0
  54. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-store.js +4 -1357
  55. package/dist-electron/services/local-ai-core/src/acp/local-core-slash-commands.js +28 -0
  56. package/dist-electron/services/local-ai-core/src/acp/store/agent-task-store.js +166 -0
  57. package/dist-electron/services/local-ai-core/src/acp/store/automation-monitor-store.js +231 -0
  58. package/dist-electron/services/local-ai-core/src/acp/store/local-core-acp-store.js +263 -0
  59. package/dist-electron/services/local-ai-core/src/acp/store/platform-store.js +186 -0
  60. package/dist-electron/services/local-ai-core/src/acp/store/scheduler-store.js +201 -0
  61. package/dist-electron/services/local-ai-core/src/acp/store/schema.js +275 -0
  62. package/dist-electron/services/local-ai-core/src/acp/store/security-store.js +266 -0
  63. package/dist-electron/services/local-ai-core/src/acp/store/thread-store.js +232 -0
  64. package/dist-electron/services/local-ai-core/src/acp/store/utils.js +47 -0
  65. package/dist-electron/services/local-ai-core/src/acp/store/workspace-registry-store.js +109 -0
  66. package/dist-electron/services/local-ai-core/src/automation/automation-conversation-executor.js +136 -0
  67. package/dist-electron/services/local-ai-core/src/automation/automation-monitor-repository.js +56 -0
  68. package/dist-electron/services/local-ai-core/src/automation/automation-monitor-service.js +359 -0
  69. package/dist-electron/services/local-ai-core/src/automation/condition-evaluator.js +77 -0
  70. package/dist-electron/services/local-ai-core/src/automation/mock-stock-provider.js +40 -0
  71. package/dist-electron/services/local-ai-core/src/automation/monitor-id.js +10 -0
  72. package/dist-electron/services/local-ai-core/src/channel/lark/cards.js +55 -0
  73. package/dist-electron/services/local-ai-core/src/channel/lark/local-core-lark-gateway.js +101 -29
  74. package/dist-electron/services/local-ai-core/src/channel/shared/session-command-runtime.js +53 -0
  75. package/dist-electron/services/local-ai-core/src/channel/weixin/local-core-weixin-gateway.js +51 -33
  76. package/dist-electron/services/local-ai-core/src/cli/lac.js +196 -0
  77. package/dist-electron/services/local-ai-core/src/cli/monitor-cli-parsers.js +37 -0
  78. package/dist-electron/services/local-ai-core/src/kernel/bootstrap.js +43 -0
  79. package/dist-electron/services/local-ai-core/src/kernel/capability-registry.js +12 -0
  80. package/dist-electron/services/local-ai-core/src/plugins/builtin/monitor-stock-plugin.js +30 -0
  81. package/dist-electron/services/local-ai-core/src/router/workspace-router.js +40 -4
  82. package/dist-electron/services/local-ai-core/src/runtime/local-core-controller.js +41 -0
  83. package/dist-electron/services/local-ai-core/src/runtime/server-routes.js +31 -0
  84. package/dist-electron/services/local-ai-core/src/runtime/server.js +36 -0
  85. package/dist-electron/services/local-ai-core/src/scheduler/scheduled-bridge-session.js +25 -11
  86. package/dist-electron/services/local-ai-core/src/thread/session-command-service.js +275 -0
  87. package/dist-electron/services/local-ai-core/src/thread/slash-command-registry.js +27 -0
  88. package/dist-electron/services/local-ai-core/src/thread/thread-command-service.js +134 -0
  89. package/dist-electron/shared/desktop.js +21 -1
  90. package/dist-electron/tests/contracts/local-core-contracts.test.js +9 -0
  91. package/dist-electron/tests/electron/automation-monitor.test.js +38 -0
  92. package/dist-electron/tests/electron/lac-cli.test.js +146 -0
  93. package/dist-electron/tests/electron/plugin-kernel.test.js +26 -0
  94. package/dist-electron/tests/integration/local-core-refactor.test.js +359 -0
  95. package/package.json +1 -1
  96. package/dist/renderer/assets/CronList-C6nPAmEo.js +0 -1
  97. package/dist/renderer/assets/SessionChat-D1HtMdQS.js +0 -1
  98. package/dist/renderer/assets/desktop-CFcnzwcY.js +0 -1
  99. package/dist/renderer/assets/desktop-O8_6ZCVZ.js +0 -4
  100. package/dist/renderer/assets/en-CKhCF6St.js +0 -1
  101. package/dist/renderer/assets/projects-DpR972HM.js +0 -1
  102. package/dist/renderer/assets/zh-Dz5FLTBV.js +0 -1
@@ -326,6 +326,152 @@ function createIo() {
326
326
  });
327
327
  strict_1.default.match(read().stdout, /Sent file absolute\.pdf to chat-1: msg-file-2/);
328
328
  });
329
+ (0, node_test_1.default)('lac monitor add posts thread context and stock source config', async () => {
330
+ let capturedBody = null;
331
+ const server = (0, node_http_1.createServer)(async (req, res) => {
332
+ if (req.method === 'POST' && req.url === '/api/local/v1/automation/monitors') {
333
+ const chunks = [];
334
+ for await (const chunk of req) {
335
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
336
+ }
337
+ capturedBody = Buffer.concat(chunks).toString('utf8');
338
+ res.setHeader('content-type', 'application/json');
339
+ res.end(JSON.stringify({
340
+ ok: true,
341
+ data: {
342
+ id: 'monitor:826aff79-570b-4308-822e-18318e2c96ba',
343
+ workspaceId: '知识库',
344
+ title: 'AAPL swing',
345
+ sourceType: 'stock.quote',
346
+ sourceConfig: { symbol: 'AAPL', price: 188.5 },
347
+ condition: { metric: 'abs_change_percent', operator: '>=', value: 3 },
348
+ promptTemplate: 'analyze AAPL',
349
+ platform: 'lark',
350
+ route: { type: 'channel.chat', channelId: 'chat-1', participantId: 'user-1' },
351
+ executionMode: 'side-thread',
352
+ enabled: true,
353
+ cooldownMs: 900000,
354
+ concurrencyPolicy: 'skip_if_running',
355
+ createdAt: '2026-04-22T06:00:00.000Z',
356
+ updatedAt: '2026-04-22T06:00:00.000Z',
357
+ },
358
+ }));
359
+ return;
360
+ }
361
+ res.statusCode = 404;
362
+ res.end(JSON.stringify({ ok: false, error: 'not found' }));
363
+ });
364
+ await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve));
365
+ const address = server.address();
366
+ (0, strict_1.default)(address && typeof address === 'object');
367
+ const { io, read } = createIo();
368
+ const exitCode = await (0, lac_js_1.runCli)([
369
+ 'monitor',
370
+ 'add',
371
+ '--title',
372
+ 'AAPL swing',
373
+ '--source',
374
+ 'stock.quote',
375
+ '--symbol',
376
+ 'aapl',
377
+ '--price',
378
+ '188.5',
379
+ '--condition',
380
+ 'abs_change_percent >= 3',
381
+ '--message',
382
+ 'analyze AAPL',
383
+ ], {
384
+ LOCAL_AI_CORE_BASE: `http://127.0.0.1:${address.port}/api/local/v1`,
385
+ LOCAL_AI_WORKSPACE_ID: '知识库',
386
+ LOCAL_AI_THREAD_ID: 'thread-1',
387
+ LOCAL_AI_PLATFORM: 'lark',
388
+ LOCAL_AI_CHAT_ID: 'chat-1',
389
+ LOCAL_AI_PLATFORM_USER_ID: 'user-1',
390
+ }, io);
391
+ server.close();
392
+ strict_1.default.equal(exitCode, 0);
393
+ (0, strict_1.default)(capturedBody);
394
+ strict_1.default.deepEqual(JSON.parse(capturedBody), {
395
+ workspaceId: '知识库',
396
+ threadId: 'thread-1',
397
+ title: 'AAPL swing',
398
+ sourceType: 'stock.quote',
399
+ sourceConfig: { symbol: 'AAPL', price: 188.5 },
400
+ condition: { metric: 'abs_change_percent', operator: '>=', value: 3 },
401
+ promptTemplate: 'analyze AAPL',
402
+ executionMode: 'side-thread',
403
+ cooldownMs: 900000,
404
+ enabled: true,
405
+ });
406
+ strict_1.default.match(read().stdout, /Created monitor 826aff79/);
407
+ });
408
+ (0, node_test_1.default)('lac monitor list filters by current thread context', async () => {
409
+ const server = (0, node_http_1.createServer)((req, res) => {
410
+ if (req.method === 'GET' && req.url === '/api/local/v1/automation/monitors?workspace_id=%E7%9F%A5%E8%AF%86%E5%BA%93') {
411
+ res.setHeader('content-type', 'application/json');
412
+ res.end(JSON.stringify({
413
+ ok: true,
414
+ data: {
415
+ monitors: [
416
+ {
417
+ id: 'monitor-1',
418
+ workspaceId: '知识库',
419
+ title: 'current',
420
+ sourceType: 'stock.quote',
421
+ sourceConfig: { symbol: 'AAPL' },
422
+ condition: { metric: 'abs_change_percent', operator: '>=', value: 3 },
423
+ promptTemplate: 'ping',
424
+ platform: 'lark',
425
+ route: { type: 'channel.chat', channelId: 'chat-1', participantId: 'user-1' },
426
+ executionMode: 'side-thread',
427
+ enabled: true,
428
+ cooldownMs: 900000,
429
+ concurrencyPolicy: 'skip_if_running',
430
+ createdAt: '2026-04-22T06:00:00.000Z',
431
+ updatedAt: '2026-04-22T06:00:00.000Z',
432
+ },
433
+ {
434
+ id: 'monitor-2',
435
+ workspaceId: '知识库',
436
+ title: 'other',
437
+ sourceType: 'stock.quote',
438
+ sourceConfig: { symbol: 'MSFT' },
439
+ condition: { metric: 'abs_change_percent', operator: '>=', value: 3 },
440
+ promptTemplate: 'pong',
441
+ platform: 'lark',
442
+ route: { type: 'channel.chat', channelId: 'chat-2', participantId: 'user-2' },
443
+ executionMode: 'side-thread',
444
+ enabled: true,
445
+ cooldownMs: 900000,
446
+ concurrencyPolicy: 'skip_if_running',
447
+ createdAt: '2026-04-22T06:00:00.000Z',
448
+ updatedAt: '2026-04-22T06:00:00.000Z',
449
+ },
450
+ ],
451
+ },
452
+ }));
453
+ return;
454
+ }
455
+ res.statusCode = 404;
456
+ res.end(JSON.stringify({ ok: false, error: 'not found' }));
457
+ });
458
+ await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve));
459
+ const address = server.address();
460
+ (0, strict_1.default)(address && typeof address === 'object');
461
+ const { io, read } = createIo();
462
+ const exitCode = await (0, lac_js_1.runCli)(['monitor', 'list', '--thread'], {
463
+ LOCAL_AI_CORE_BASE: `http://127.0.0.1:${address.port}/api/local/v1`,
464
+ LOCAL_AI_WORKSPACE_ID: '知识库',
465
+ LOCAL_AI_THREAD_ID: 'thread-1',
466
+ LOCAL_AI_PLATFORM: 'lark',
467
+ LOCAL_AI_CHAT_ID: 'chat-1',
468
+ LOCAL_AI_PLATFORM_USER_ID: 'user-1',
469
+ }, io);
470
+ server.close();
471
+ strict_1.default.equal(exitCode, 0);
472
+ strict_1.default.match(read().stdout, /monitor-1/);
473
+ strict_1.default.doesNotMatch(read().stdout, /monitor-2/);
474
+ });
329
475
  (0, node_test_1.default)('lac scheduler list shows workspace jobs by default', async () => {
330
476
  const server = (0, node_http_1.createServer)((req, res) => {
331
477
  if (req.method === 'GET' && req.url === '/api/local/v1/scheduler/jobs?workspace_id=%E7%9F%A5%E8%AF%86%E5%BA%93') {
@@ -302,6 +302,32 @@ type = "codex"
302
302
  (0, node_fs_1.rmSync)(userDataPath, { recursive: true, force: true });
303
303
  }
304
304
  });
305
+ (0, node_test_1.default)('thread slash agent reset resolves the workspace default agent through the router', async () => {
306
+ const userDataPath = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'agentdock-kernel-agent-reset-'));
307
+ try {
308
+ const runtime = (0, bootstrap_js_2.bootstrapLocalCoreRuntime)({
309
+ userDataPath,
310
+ enableKnowledge: false,
311
+ });
312
+ await runtime.state.saveRawConfigFile(`
313
+ [[projects]]
314
+ name = "agent-workspace"
315
+
316
+ [projects.agent]
317
+ type = "codex"
318
+ `);
319
+ const thread = await runtime.workspaceRouter.createThread('agent-workspace', 'Agent reset');
320
+ await runtime.workspaceRouter.sendThreadMessage(thread.id, '/agent use pi');
321
+ strict_1.default.equal(runtime.store.getThreadRow(thread.id)?.agent_type, 'pi');
322
+ await runtime.workspaceRouter.sendThreadMessage(thread.id, '/agent reset');
323
+ strict_1.default.equal(runtime.store.getThreadRow(thread.id)?.agent_type, 'codex');
324
+ strict_1.default.match(runtime.store.getThread(thread.id, []).messages.at(-1)?.content || '', /回到默认 Agent:codex/);
325
+ await runtime.stop();
326
+ }
327
+ finally {
328
+ (0, node_fs_1.rmSync)(userDataPath, { recursive: true, force: true });
329
+ }
330
+ });
305
331
  (0, node_test_1.default)('hermes agent runtime routes projects through hermes ACP command', async () => {
306
332
  const userDataPath = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'agentdock-kernel-'));
307
333
  try {
@@ -17,9 +17,13 @@ const lark_execution_policies_js_1 = require("../../services/local-ai-core/src/s
17
17
  const local_schedule_adapter_js_1 = require("../../services/local-ai-core/src/scheduler/local-schedule-adapter.js");
18
18
  const local_core_weixin_gateway_js_1 = require("../../services/local-ai-core/src/channel/weixin/local-core-weixin-gateway.js");
19
19
  const local_core_lark_gateway_js_1 = require("../../services/local-ai-core/src/channel/lark/local-core-lark-gateway.js");
20
+ const cards_js_1 = require("../../services/local-ai-core/src/channel/lark/cards.js");
20
21
  const runtime_state_js_1 = require("../../services/local-ai-core/src/channel/lark/runtime-state.js");
22
+ const local_core_acp_backend_js_1 = require("../../services/local-ai-core/src/acp/local-core-acp-backend.js");
21
23
  const local_core_acp_turn_coordinator_js_1 = require("../../services/local-ai-core/src/acp/local-core-acp-turn-coordinator.js");
22
24
  const local_core_acp_store_js_1 = require("../../services/local-ai-core/src/acp/local-core-acp-store.js");
25
+ const session_command_service_js_1 = require("../../services/local-ai-core/src/thread/session-command-service.js");
26
+ const thread_command_service_js_1 = require("../../services/local-ai-core/src/thread/thread-command-service.js");
23
27
  const local_core_acp_progress_js_1 = require("../../services/local-ai-core/src/acp/local-core-acp-progress.js");
24
28
  const local_core_acp_permission_lifecycle_js_1 = require("../../services/local-ai-core/src/acp/local-core-acp-permission-lifecycle.js");
25
29
  const workspace_acp_permissions_js_1 = require("../../services/local-ai-core/src/acp/workspace-acp-permissions.js");
@@ -3718,6 +3722,94 @@ function findLarkPostMdText(content) {
3718
3722
  strict_1.default.equal((0, local_core_slash_commands_js_1.formatAgentMode)('bypassPermissions'), 'yolo');
3719
3723
  strict_1.default.match((0, local_core_slash_commands_js_1.modeHelpText)('bypassPermissions'), /当前模式:yolo/);
3720
3724
  });
3725
+ (0, node_test_1.default)('slash agent commands normalize aliases and expose current help', () => {
3726
+ strict_1.default.deepEqual((0, local_core_slash_commands_js_1.parseSlashCommand)('/agent use Pi'), { name: 'agent', args: ['use', 'Pi'] });
3727
+ strict_1.default.equal((0, local_core_slash_commands_js_1.normalizeAgentCommandTarget)('Pi'), 'pi');
3728
+ strict_1.default.equal((0, local_core_slash_commands_js_1.normalizeAgentCommandTarget)('claude'), 'claudecode');
3729
+ strict_1.default.equal((0, local_core_slash_commands_js_1.normalizeAgentCommandTarget)('claude-code'), 'claudecode');
3730
+ strict_1.default.match((0, local_core_slash_commands_js_1.agentHelpText)({
3731
+ currentAgent: 'pi',
3732
+ defaultAgent: 'codex',
3733
+ availableAgents: ['codex', 'pi', 'hermes'],
3734
+ }), /当前线程 Agent:pi/);
3735
+ });
3736
+ (0, node_test_1.default)('thread command service handles local slash commands without ACP transport', async () => {
3737
+ const row = {
3738
+ id: 'thread-1',
3739
+ workspace_id: 'workspace-a',
3740
+ session_id: 'session-1',
3741
+ bridge_session_key: 'bridge-1',
3742
+ title: 'Command service',
3743
+ agent_type: 'codex',
3744
+ created_at: '2026-05-11T00:00:00.000Z',
3745
+ updated_at: '2026-05-11T00:00:00.000Z',
3746
+ history_count: 0,
3747
+ excerpt: '',
3748
+ acp_session_id: null,
3749
+ acp_supports_load: 0,
3750
+ agent_mode: 'default',
3751
+ };
3752
+ const audits = [];
3753
+ const syncedModes = [];
3754
+ const closedThreads = [];
3755
+ const service = new thread_command_service_js_1.ThreadCommandService({
3756
+ getThreadRow: () => row,
3757
+ updateThreadAgentMode: (_threadId, mode) => {
3758
+ row.agent_mode = mode;
3759
+ },
3760
+ updateThreadAgentType: (_threadId, agentType) => {
3761
+ row.agent_type = agentType;
3762
+ },
3763
+ getLatestRunForThread: () => undefined,
3764
+ createAuditEvent: (input) => {
3765
+ audits.push(input);
3766
+ },
3767
+ getAgentTypes: () => ['codex', 'pi', 'hermes', 'claudecode'],
3768
+ setThreadMode: async (_threadId, mode) => {
3769
+ syncedModes.push(mode);
3770
+ },
3771
+ closeThreadSession: (threadId) => {
3772
+ closedThreads.push(threadId);
3773
+ },
3774
+ });
3775
+ strict_1.default.deepEqual(await service.execute({
3776
+ threadId: row.id,
3777
+ workspaceId: row.workspace_id,
3778
+ content: '/not-local',
3779
+ defaultAgentType: 'codex',
3780
+ }), { handled: false, displayText: '' });
3781
+ const modeResult = await service.execute({
3782
+ threadId: row.id,
3783
+ workspaceId: row.workspace_id,
3784
+ content: '/mode yolo',
3785
+ defaultAgentType: 'codex',
3786
+ });
3787
+ strict_1.default.equal(modeResult.handled, true);
3788
+ strict_1.default.equal(row.agent_mode, 'bypassPermissions');
3789
+ strict_1.default.deepEqual(syncedModes, ['bypassPermissions']);
3790
+ strict_1.default.equal(audits.at(-1)?.type, 'permission.changed');
3791
+ const agentResult = await service.execute({
3792
+ threadId: row.id,
3793
+ workspaceId: row.workspace_id,
3794
+ content: '/agent use pi',
3795
+ defaultAgentType: 'codex',
3796
+ });
3797
+ strict_1.default.equal(agentResult.handled, true);
3798
+ strict_1.default.equal(row.agent_type, 'pi');
3799
+ strict_1.default.match(agentResult.displayText, /已将当前线程 Agent 切换为 pi/);
3800
+ strict_1.default.deepEqual(closedThreads, ['thread-1']);
3801
+ strict_1.default.equal(audits.at(-1)?.type, 'agent.changed');
3802
+ const resetResult = await service.execute({
3803
+ threadId: row.id,
3804
+ workspaceId: row.workspace_id,
3805
+ content: '/agent reset',
3806
+ defaultAgentType: 'codex',
3807
+ });
3808
+ strict_1.default.equal(resetResult.handled, true);
3809
+ strict_1.default.equal(row.agent_type, 'codex');
3810
+ strict_1.default.match(resetResult.displayText, /回到默认 Agent:codex/);
3811
+ strict_1.default.deepEqual(closedThreads, ['thread-1', 'thread-1']);
3812
+ });
3721
3813
  (0, node_test_1.default)('thread agent mode persists with thread state', () => {
3722
3814
  const dir = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'agentdock-mode-'));
3723
3815
  try {
@@ -3734,6 +3826,273 @@ function findLarkPostMdText(content) {
3734
3826
  (0, node_fs_1.rmSync)(dir, { recursive: true, force: true });
3735
3827
  }
3736
3828
  });
3829
+ (0, node_test_1.default)('thread agent type persists and clears stale ACP session state', () => {
3830
+ const dir = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'agentdock-agent-type-'));
3831
+ try {
3832
+ const store = new local_core_acp_store_js_1.LocalCoreAcpStore(dir);
3833
+ const thread = store.createThread('workspace-a', 'Agent test', 'codex');
3834
+ store.updateThreadSession(thread.id, 'old-session', true);
3835
+ store.updateThreadAgentType(thread.id, 'pi');
3836
+ const row = store.getThreadRow(thread.id);
3837
+ strict_1.default.equal(row?.agent_type, 'pi');
3838
+ strict_1.default.equal(row?.acp_session_id, null);
3839
+ strict_1.default.equal(row?.acp_supports_load, 0);
3840
+ store.close();
3841
+ }
3842
+ finally {
3843
+ (0, node_fs_1.rmSync)(dir, { recursive: true, force: true });
3844
+ }
3845
+ });
3846
+ (0, node_test_1.default)('slash agent commands switch and reset the current thread agent', async () => {
3847
+ const dir = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'agentdock-agent-command-'));
3848
+ try {
3849
+ const store = new local_core_acp_store_js_1.LocalCoreAcpStore(dir);
3850
+ const thread = store.createThread('workspace-a', 'Agent command', 'codex');
3851
+ const bridgeEvents = [];
3852
+ const acceptedMessages = [];
3853
+ const backend = new local_core_acp_backend_js_1.LocalCoreAcpBackend({
3854
+ store,
3855
+ runThreadMap: new Map(),
3856
+ emitBridge: (event) => bridgeEvents.push(event),
3857
+ eventBus: {
3858
+ emit: (event) => acceptedMessages.push(event),
3859
+ on: () => () => { },
3860
+ },
3861
+ scheduler: {
3862
+ createJob: async () => { throw new Error('not used'); },
3863
+ listJobsForThread: async () => [],
3864
+ deleteJob: async () => { },
3865
+ },
3866
+ getAgentTypes: () => ['codex', 'pi', 'hermes', 'claudecode'],
3867
+ });
3868
+ const config = {
3869
+ workspaceId: 'workspace-a',
3870
+ agentType: 'codex',
3871
+ workDir: dir,
3872
+ command: process.execPath,
3873
+ args: ['-e', ''],
3874
+ env: {},
3875
+ model: '',
3876
+ };
3877
+ strict_1.default.deepEqual(await backend.sendThreadMessage(thread.id, '/agent use pi', config), { runId: '' });
3878
+ strict_1.default.equal(store.getThreadRow(thread.id)?.agent_type, 'pi');
3879
+ strict_1.default.match(store.getThread(thread.id, []).messages.at(-1)?.content || '', /已将当前线程 Agent 切换为 pi/);
3880
+ strict_1.default.equal(bridgeEvents.at(-2)?.type, 'reply');
3881
+ strict_1.default.match(bridgeEvents.at(-2)?.content || '', /后续消息将使用 pi 处理/);
3882
+ await backend.sendThreadMessage(thread.id, '/agent current', config);
3883
+ strict_1.default.match(store.getThread(thread.id, []).messages.at(-1)?.content || '', /来源:线程设置/);
3884
+ await backend.sendThreadMessage(thread.id, '/agent use claude', config);
3885
+ strict_1.default.equal(store.getThreadRow(thread.id)?.agent_type, 'claudecode');
3886
+ await backend.sendThreadMessage(thread.id, '/agent reset', config);
3887
+ strict_1.default.equal(store.getThreadRow(thread.id)?.agent_type, 'codex');
3888
+ strict_1.default.match(store.getThread(thread.id, []).messages.at(-1)?.content || '', /回到默认 Agent:codex/);
3889
+ await backend.sendThreadMessage(thread.id, '/agent use missing-agent', config);
3890
+ strict_1.default.equal(store.getThreadRow(thread.id)?.agent_type, 'codex');
3891
+ strict_1.default.match(store.getThread(thread.id, []).messages.at(-1)?.content || '', /未知 Agent:missing-agent/);
3892
+ store.updateRun('run-active', thread.id, 'running');
3893
+ await backend.sendThreadMessage(thread.id, '/agent use hermes', config);
3894
+ strict_1.default.equal(store.getThreadRow(thread.id)?.agent_type, 'hermes');
3895
+ strict_1.default.match(store.getThread(thread.id, []).messages.at(-1)?.content || '', /下一轮开始生效/);
3896
+ strict_1.default.ok(acceptedMessages.length >= 8);
3897
+ backend.close();
3898
+ store.close();
3899
+ }
3900
+ finally {
3901
+ (0, node_fs_1.rmSync)(dir, { recursive: true, force: true });
3902
+ }
3903
+ });
3904
+ (0, node_test_1.default)('session command matcher resolves by number, id, title, and excerpt in order', () => {
3905
+ const threads = [
3906
+ { id: 'thread-alpha-123', title: 'Alpha notes', excerpt: 'budget review', historyCount: 2, updatedAt: '2026-05-11T08:00:00.000Z' },
3907
+ { id: 'thread-beta-456', title: 'Beta plan', excerpt: 'alpha appears here', historyCount: 1, updatedAt: '2026-05-11T07:00:00.000Z' },
3908
+ { id: 'thread-gamma-789', title: 'Gamma', excerpt: 'release checklist', historyCount: 4, updatedAt: '2026-05-11T06:00:00.000Z' },
3909
+ ];
3910
+ strict_1.default.equal((0, session_command_service_js_1.matchThread)(threads, '2')?.id, 'thread-beta-456');
3911
+ strict_1.default.equal((0, session_command_service_js_1.matchThread)(threads, 'thread-gamma')?.id, 'thread-gamma-789');
3912
+ strict_1.default.equal((0, session_command_service_js_1.matchThread)(threads, 'Beta plan')?.id, 'thread-beta-456');
3913
+ strict_1.default.equal((0, session_command_service_js_1.matchThread)(threads, 'Alpha')?.id, 'thread-alpha-123');
3914
+ strict_1.default.equal((0, session_command_service_js_1.matchThread)(threads, 'release')?.id, 'thread-gamma-789');
3915
+ });
3916
+ (0, node_test_1.default)('session slash commands manage thread sessions through shared operations', async () => {
3917
+ const dir = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'agentdock-session-command-'));
3918
+ try {
3919
+ const store = new local_core_acp_store_js_1.LocalCoreAcpStore(dir);
3920
+ const current = store.createThread('workspace-a', 'Current', 'codex');
3921
+ const other = store.createThread('workspace-a', 'Other session', 'codex');
3922
+ store.appendMessage(current.id, 'user', 'ping', 'final');
3923
+ store.appendMessage(current.id, 'assistant', 'pong', 'final');
3924
+ const service = new session_command_service_js_1.SessionCommandService({
3925
+ listThreads: (workspaceId) => store.listThreadSummaries(workspaceId),
3926
+ getThread: (threadId) => store.getThread(threadId, []),
3927
+ createThread: (workspaceId, title) => store.createThread(workspaceId, title, 'codex'),
3928
+ renameThread: (threadId, title) => {
3929
+ store.renameThread(threadId, title);
3930
+ return store.getThread(threadId, []);
3931
+ },
3932
+ deleteThread: (threadId) => {
3933
+ store.deleteThread(threadId);
3934
+ return { deleted: true };
3935
+ },
3936
+ });
3937
+ const context = { workspaceId: 'workspace-a', currentThreadId: current.id, defaultTitle: 'Untitled' };
3938
+ const listResult = await service.execute('/list', context);
3939
+ strict_1.default.equal(listResult.handled, true);
3940
+ strict_1.default.match(listResult.displayText, /会话列表/);
3941
+ strict_1.default.ok(listResult.card?.actions.flat().some((action) => action.command.startsWith('/switch ')));
3942
+ const historyResult = await service.execute('/history 2', context);
3943
+ strict_1.default.match(historyResult.displayText, /ping/);
3944
+ strict_1.default.match(historyResult.displayText, /pong/);
3945
+ const newResult = await service.execute('/new Scratch session', context);
3946
+ const createdThreadEffect = newResult.effects?.find((effect) => effect.type === 'created_thread');
3947
+ const activatedCreatedEffect = newResult.effects?.find((effect) => effect.type === 'activate_thread' && effect.reason === 'created');
3948
+ strict_1.default.equal(createdThreadEffect?.threadId, activatedCreatedEffect?.threadId);
3949
+ strict_1.default.equal(store.getThread(createdThreadEffect?.threadId || '', []).title, 'Scratch session');
3950
+ const switchResult = await service.execute('/switch Other session', context);
3951
+ strict_1.default.equal(switchResult.effects?.find((effect) => effect.type === 'activate_thread')?.threadId, other.id);
3952
+ strict_1.default.match(switchResult.displayText, /后续消息将发送到该会话/);
3953
+ const renameResult = await service.execute('/name Renamed current', context);
3954
+ strict_1.default.match(renameResult.displayText, /Renamed current/);
3955
+ strict_1.default.equal(store.getThread(current.id, []).title, 'Renamed current');
3956
+ const currentDeleteResult = await service.execute('/del Renamed current --confirm', context);
3957
+ strict_1.default.match(currentDeleteResult.displayText, /不能删除当前正在使用的会话/);
3958
+ const deletePrompt = await service.execute('/del Other session', context);
3959
+ strict_1.default.match(deletePrompt.displayText, /确认删除会话/);
3960
+ strict_1.default.ok(deletePrompt.card?.actions.flat().some((action) => action.command.includes('--confirm')));
3961
+ const deleteResult = await service.execute('/del Other session --confirm', context);
3962
+ strict_1.default.equal(deleteResult.effects?.find((effect) => effect.type === 'deleted_thread')?.threadId, other.id);
3963
+ strict_1.default.equal(store.listThreadSummaries('workspace-a').some((thread) => thread.id === other.id), false);
3964
+ store.close();
3965
+ }
3966
+ finally {
3967
+ (0, node_fs_1.rmSync)(dir, { recursive: true, force: true });
3968
+ }
3969
+ });
3970
+ (0, node_test_1.default)('store deleteThread clears channel references without backend help', () => {
3971
+ const dir = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'agentdock-store-delete-thread-'));
3972
+ try {
3973
+ const store = new local_core_acp_store_js_1.LocalCoreAcpStore(dir);
3974
+ const thread = store.createThread('workspace-a', 'Bound thread', 'codex');
3975
+ const now = new Date().toISOString();
3976
+ store.createAuthorizedUser({
3977
+ id: 'lark-user-store',
3978
+ workspace_id: 'workspace-a',
3979
+ platform: 'lark',
3980
+ platform_user_id: 'user-store',
3981
+ chat_id: 'chat-store',
3982
+ display_name: 'User',
3983
+ thread_id: thread.id,
3984
+ authorized_at: now,
3985
+ });
3986
+ store.upsertPlatformThreadBinding({
3987
+ workspace_id: 'workspace-a',
3988
+ platform: 'lark',
3989
+ chat_id: 'chat-store',
3990
+ platform_user_id: 'user-store',
3991
+ thread_id: thread.id,
3992
+ last_platform_message_id: 'msg-store',
3993
+ created_at: now,
3994
+ updated_at: now,
3995
+ });
3996
+ store.deleteThread(thread.id);
3997
+ strict_1.default.equal(store.getThreadRow(thread.id), undefined);
3998
+ strict_1.default.equal(store.getAuthorizedUser('workspace-a', 'user-store', 'lark')?.thread_id, null);
3999
+ strict_1.default.equal(store.getPlatformThreadBinding('workspace-a', 'chat-store', 'user-store', 'lark'), undefined);
4000
+ store.close();
4001
+ }
4002
+ finally {
4003
+ (0, node_fs_1.rmSync)(dir, { recursive: true, force: true });
4004
+ }
4005
+ });
4006
+ (0, node_test_1.default)('backend session delete command clears channel bindings for deleted threads', async () => {
4007
+ const dir = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'agentdock-session-delete-'));
4008
+ try {
4009
+ const store = new local_core_acp_store_js_1.LocalCoreAcpStore(dir);
4010
+ const current = store.createThread('workspace-a', 'Current', 'codex');
4011
+ const other = store.createThread('workspace-a', 'Other session', 'codex');
4012
+ const now = new Date().toISOString();
4013
+ store.createAuthorizedUser({
4014
+ id: 'lark-user-1',
4015
+ workspace_id: 'workspace-a',
4016
+ platform: 'lark',
4017
+ platform_user_id: 'user-1',
4018
+ chat_id: 'chat-1',
4019
+ display_name: 'User',
4020
+ thread_id: other.id,
4021
+ authorized_at: now,
4022
+ });
4023
+ store.upsertPlatformThreadBinding({
4024
+ workspace_id: 'workspace-a',
4025
+ platform: 'lark',
4026
+ chat_id: 'chat-1',
4027
+ platform_user_id: 'user-1',
4028
+ thread_id: other.id,
4029
+ last_platform_message_id: 'msg-1',
4030
+ created_at: now,
4031
+ updated_at: now,
4032
+ });
4033
+ const events = [];
4034
+ const backend = new local_core_acp_backend_js_1.LocalCoreAcpBackend({
4035
+ store,
4036
+ runThreadMap: new Map(),
4037
+ emitBridge: () => { },
4038
+ eventBus: {
4039
+ emit: (event) => events.push(event),
4040
+ on: () => () => { },
4041
+ },
4042
+ scheduler: {
4043
+ createJob: async () => { throw new Error('not used'); },
4044
+ listJobsForThread: async () => [],
4045
+ deleteJob: async () => { },
4046
+ },
4047
+ getAgentTypes: () => ['codex'],
4048
+ });
4049
+ await backend.sendThreadMessage(current.id, '/del Other session --confirm', {
4050
+ workspaceId: 'workspace-a',
4051
+ agentType: 'codex',
4052
+ workDir: dir,
4053
+ command: process.execPath,
4054
+ args: ['-e', ''],
4055
+ env: {},
4056
+ model: '',
4057
+ });
4058
+ strict_1.default.equal(store.getThreadRow(other.id), undefined);
4059
+ strict_1.default.equal(store.getAuthorizedUser('workspace-a', 'user-1', 'lark')?.thread_id, null);
4060
+ strict_1.default.equal(store.getPlatformThreadBinding('workspace-a', 'chat-1', 'user-1', 'lark'), undefined);
4061
+ const created = await backend.createThread('workspace-a', 'Switch target', 'codex');
4062
+ await backend.sendThreadMessage(current.id, '/switch Switch target', {
4063
+ workspaceId: 'workspace-a',
4064
+ agentType: 'codex',
4065
+ workDir: dir,
4066
+ command: process.execPath,
4067
+ args: ['-e', ''],
4068
+ env: {},
4069
+ model: '',
4070
+ });
4071
+ strict_1.default.deepEqual(events.find((event) => event.type === 'thread.session.activated')?.payload, {
4072
+ workspaceId: 'workspace-a',
4073
+ threadId: created.id,
4074
+ previousThreadId: current.id,
4075
+ reason: 'switched',
4076
+ });
4077
+ backend.close();
4078
+ store.close();
4079
+ }
4080
+ finally {
4081
+ (0, node_fs_1.rmSync)(dir, { recursive: true, force: true });
4082
+ }
4083
+ });
4084
+ (0, node_test_1.default)('Lark session command cards round-trip slash command action values', () => {
4085
+ const card = (0, cards_js_1.buildSessionCommandCard)('会话列表', [[
4086
+ { label: '1. Current', command: '/switch 1', type: 'primary' },
4087
+ { label: '删除', command: '/del 1', type: 'danger' },
4088
+ ]], 'session-key-1', 'thread-1');
4089
+ const actionElement = card.elements.find((element) => element.tag === 'action');
4090
+ const value = actionElement.actions[0].value;
4091
+ const extracted = (0, cards_js_1.extractSessionCommandActionValue)({ event: { action: { value } } });
4092
+ strict_1.default.equal(extracted?.command, '/switch 1');
4093
+ strict_1.default.equal(extracted?.threadId, 'thread-1');
4094
+ strict_1.default.equal(extracted?.sessionKey, 'session-key-1');
4095
+ });
3737
4096
  (0, node_test_1.default)('scheduled conversation executor uses execution policy hooks around a thread run', async () => {
3738
4097
  const calls = [];
3739
4098
  let runtimeEnv;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kafca/agentdock",
3
- "version": "0.1.41",
3
+ "version": "0.1.43",
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{H as R,l as b,J as z,K as D,N as W,O,u as B,r as n,j as t,P as F,B as c,E as L,C as U,D as k,I as f,T as H}from"./index-Cx71F_Lz.js";import{B as u}from"./Badge-BX3RC8l6.js";import{M as K}from"./Modal-B4eOiBsB.js";import{S as w}from"./Select-B6E68LcN.js";import{E as _}from"./EmptyState-DoCpF2tn.js";import{P as q}from"./Page-C5VH4D9U.js";import{P as G}from"./plus-BhURuFIQ.js";import{P as Q}from"./play-BOEG_mY8.js";import{P as V}from"./pencil-DlDr8Mmp.js";import{T as X}from"./trash-2-DduflM4q.js";import"./index-BijJAYmo.js";import"./chevron-down-DIZZgSb3.js";import"./check-BAqPPYkf.js";const Y=a=>R(),Z=a=>D(a),$=(a,o)=>z(a,o),ee=a=>W(a),te=a=>O(a),ae=()=>b().then(a=>a.workspaces),x={workspaceId:"",executionMode:"same-thread",triggerType:"cron",cronExpr:"0 9 * * *",runAt:"",promptTemplate:"",description:"",chatId:"",platformUserId:"",threadId:"",enabled:!0};function se(a){return a?{workspaceId:a.workspaceId,executionMode:a.executionMode,triggerType:a.triggerType,cronExpr:a.cronExpr||"0 9 * * *",runAt:a.runAt?String(a.runAt).slice(0,16):"",promptTemplate:a.promptTemplate,description:a.description,chatId:a.route.channelId,platformUserId:a.route.participantId||"",threadId:a.route.threadId||"",enabled:a.enabled}:x}function re(a){return{workspaceId:a.workspaceId,platform:"local",route:{type:"local.thread",channelId:a.workspaceId||"local",...a.threadId?{threadId:a.threadId}:{}},executionMode:a.executionMode||"same-thread",triggerType:a.triggerType,...a.triggerType==="cron"?{cronExpr:a.cronExpr,runAt:void 0}:{runAt:new Date(a.runAt).toISOString(),cronExpr:void 0},promptTemplate:a.promptTemplate,description:a.description,enabled:a.enabled}}function ye(){const{t:a}=B(),[o,I]=n.useState([]),[m,T]=n.useState([]),[C,y]=n.useState(!0),[S,d]=n.useState(!1),[j,v]=n.useState(!1),[p,h]=n.useState(null),[s,r]=n.useState(x),E=n.useMemo(()=>m.map(e=>t.jsx("option",{value:e.id,children:e.name},e.id)),[m]),i=n.useCallback(async()=>{y(!0);try{const[e,l]=await Promise.all([Y(),ae()]);I(e.jobs||[]),T(l),r(g=>g.workspaceId||l.length===0?g:{...g,workspaceId:l[0].id})}finally{y(!1)}},[]);n.useEffect(()=>{i();const e=F(l=>{(l.type==="scheduler.job.updated"||l.type==="scheduler.run.updated")&&i()});return()=>e()},[i]);const J=()=>{var e;h(null),r({...x,workspaceId:((e=m[0])==null?void 0:e.id)||""}),d(!0)},N=e=>{h(e),r(se(e)),d(!0)},A=async()=>{if(!(!s.workspaceId||!s.promptTemplate.trim())&&!(s.triggerType==="once"&&!s.runAt)){v(!0);try{const e=re(s);p?await $(p.id,e):await Z(e),d(!1),h(null),r(x),await i()}finally{v(!1)}}},M=async e=>{confirm(a("common.confirmDelete"))&&(await ee(e),await i())},P=async e=>{await te(e),await i()};return C&&o.length===0?t.jsx("div",{className:"flex items-center justify-center h-64 text-gray-400 animate-pulse",children:a("common.loading")}):t.jsxs("div",{className:"space-y-4 animate-fade-in",children:[t.jsx(q,{title:a("cron.title"),description:"Create simple scheduled prompts for a workspace.",actions:t.jsxs(c,{onClick:J,children:[t.jsx(G,{size:16})," ",a("cron.add")]})}),o.length===0?t.jsx(_,{message:a("cron.noJobs"),icon:L}):t.jsx("div",{className:"space-y-3",children:o.map(e=>t.jsx(U,{children:t.jsxs("div",{className:"flex items-start justify-between gap-3",children:[t.jsxs("div",{className:"flex-1",children:[t.jsxs("div",{className:"flex items-center gap-2 mb-1 flex-wrap",children:[t.jsx("span",{className:"font-medium text-gray-900 dark:text-white text-sm",children:e.description||e.id}),t.jsx(u,{variant:e.enabled?"success":"default",children:e.enabled?a("cron.enabled"):"disabled"}),t.jsx(u,{variant:"default",children:e.triggerType}),t.jsx(u,{variant:"default",children:e.platform}),e.lastStatus&&t.jsx(u,{variant:e.lastStatus==="failed"?"danger":"default",children:e.lastStatus})]}),t.jsxs("div",{className:"flex flex-wrap gap-x-4 gap-y-1 text-xs text-gray-500 dark:text-gray-400 mt-2",children:[t.jsxs("span",{children:[t.jsx("strong",{children:"Workspace:"})," ",e.workspaceId]}),t.jsxs("span",{children:[t.jsx("strong",{children:"Execution:"})," ",e.executionMode]}),t.jsxs("span",{children:[t.jsx("strong",{children:"Route:"})," ",e.route.channelId," / ",e.route.participantId]}),t.jsxs("span",{children:[t.jsxs("strong",{children:[e.triggerType==="cron"?a("cron.expression"):"Run at",":"]})," ",e.triggerType==="cron"?e.cronExpr:k(e.runAt||"")]}),e.route.threadId&&t.jsxs("span",{children:[t.jsx("strong",{children:"Thread:"})," ",e.route.threadId]}),e.lastRunAt&&t.jsxs("span",{children:[t.jsxs("strong",{children:[a("cron.lastRun"),":"]})," ",k(e.lastRunAt)]})]}),t.jsx("p",{className:"text-sm text-gray-700 dark:text-gray-300 mt-2 whitespace-pre-wrap",children:e.promptTemplate}),e.lastError&&t.jsx("p",{className:"text-xs text-red-500 mt-2",children:e.lastError})]}),t.jsxs("div",{className:"flex gap-2",children:[t.jsx(c,{size:"sm",variant:"secondary",onClick:()=>void P(e.id),children:t.jsx(Q,{size:14})}),t.jsx(c,{size:"sm",variant:"secondary",onClick:()=>N(e),children:t.jsx(V,{size:14})}),t.jsx(c,{size:"sm",variant:"danger",onClick:()=>void M(e.id),children:t.jsx(X,{size:14})})]})]})},e.id))}),t.jsx(K,{open:S,onClose:()=>d(!1),title:p?"Edit scheduler job":a("cron.add"),children:t.jsxs("div",{className:"space-y-3",children:[t.jsxs(w,{label:"Workspace",value:s.workspaceId,onChange:e=>r({...s,workspaceId:e.target.value}),children:[t.jsx("option",{value:"",children:"Select workspace"}),E]}),t.jsxs(w,{label:"Schedule type",value:s.triggerType,onChange:e=>r({...s,triggerType:e.target.value}),children:[t.jsx("option",{value:"cron",children:"Repeating"}),t.jsx("option",{value:"once",children:"One time"})]}),s.triggerType==="cron"?t.jsx(f,{label:a("cron.expression"),value:s.cronExpr,onChange:e=>r({...s,cronExpr:e.target.value}),placeholder:"0 9 * * *"}):t.jsx(f,{label:"Run at",type:"datetime-local",value:s.runAt,onChange:e=>r({...s,runAt:e.target.value})}),t.jsx(f,{label:a("cron.description"),value:s.description,onChange:e=>r({...s,description:e.target.value})}),t.jsx(H,{label:a("cron.prompt"),value:s.promptTemplate,onChange:e=>r({...s,promptTemplate:e.target.value}),rows:4,placeholder:"Summarize today's blockers and post a status update."}),t.jsxs("label",{className:"flex items-center gap-2 text-sm text-gray-700 dark:text-gray-300",children:[t.jsx("input",{type:"checkbox",checked:s.enabled,onChange:e=>r({...s,enabled:e.target.checked})}),a("cron.enabled")]}),t.jsxs("div",{className:"flex justify-end gap-2 pt-2",children:[t.jsx(c,{variant:"secondary",onClick:()=>d(!1),children:a("common.cancel")}),t.jsx(c,{onClick:()=>void A(),disabled:j,children:a(p?"common.save":"cron.add")})]})]})})]})}export{ye as default};
@@ -1 +0,0 @@
1
- import{u as C,A as z,r as a,j as e,L as S,B as g,g as j,T as B}from"./index-Cx71F_Lz.js";import{B as b}from"./Badge-BX3RC8l6.js";import{g as E,a as L}from"./sessions-BY-R1IL_.js";import{C as _,A}from"./ChatMarkdown-DfGbRR0S.js";import{A as I}from"./arrow-left-DF1_F9Pk.js";import{C as M}from"./circle-B5raL_XK.js";import{W as y,R}from"./wifi-off-X1nXESYu.js";import{B as T,U}from"./user-DBcvnuW4.js";import"./check-BAqPPYkf.js";function G(){var p;const{t:r}=C(),{project:i,id:l}=z(),[s,v]=a.useState(null),[d,m]=a.useState(""),[c,x]=a.useState(!1),[w,u]=a.useState(!0),f=a.useRef(null),o=a.useCallback(async()=>{if(!(!i||!l))try{u(!0);const t=await E(i,l,200);v(t)}finally{u(!1)}},[i,l]);a.useEffect(()=>{o()},[o]),a.useEffect(()=>{var t;(t=f.current)==null||t.scrollIntoView({behavior:"smooth"})},[s==null?void 0:s.history]);const h=async()=>{if(!d.trim()||!i||!s)return;const t=d.trim();m(""),x(!0);try{await L(i,{session_key:s.session_key,message:t}),setTimeout(o,1500)}finally{x(!1)}},N=t=>{t.key==="Enter"&&!t.shiftKey&&(t.preventDefault(),h())};return w&&!s?e.jsx("div",{className:"flex items-center justify-center h-64 text-muted-foreground animate-pulse",children:"Loading..."}):e.jsxs("div",{className:"flex flex-col h-[calc(100vh-8rem)] animate-fade-in",children:[e.jsxs("div",{className:"flex items-center justify-between pb-4 border-b",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx(S,{to:"/sessions",className:"p-2 rounded-md hover:bg-accent/10 transition-colors",children:e.jsx(I,{size:18,className:"text-muted-foreground"})}),e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("h2",{className:"text-lg font-semibold text-foreground",children:(s==null?void 0:s.name)||l}),s!=null&&s.live?e.jsxs("span",{className:"flex items-center gap-1 text-[10px] text-primary bg-primary/10 px-1.5 py-0.5 rounded-full",children:[e.jsx(M,{size:5,className:"fill-current"})," live"]}):e.jsxs("span",{className:"flex items-center gap-1 text-[10px] text-muted-foreground bg-muted px-1.5 py-0.5 rounded-full",children:[e.jsx(y,{size:9})," ",r("sessions.offline")]})]}),e.jsxs("div",{className:"flex items-center gap-2 mt-0.5",children:[e.jsx(b,{children:i}),(s==null?void 0:s.platform)&&e.jsx(b,{variant:"info",children:s.platform}),e.jsx("span",{className:"text-xs text-muted-foreground",children:s==null?void 0:s.session_key})]})]})]}),e.jsxs(g,{size:"sm",variant:"ghost",onClick:o,children:[e.jsx(R,{size:14})," ",r("common.refresh")]})]}),e.jsxs("div",{className:"flex-1 overflow-y-auto py-6 space-y-5",children:[(!(s!=null&&s.history)||s.history.length===0)&&e.jsx("p",{className:"text-center text-sm text-muted-foreground py-12",children:r("sessions.noMessages")}),(p=s==null?void 0:s.history)==null?void 0:p.map((t,k)=>{const n=t.role==="user";return e.jsxs("div",{className:j("flex gap-3",n?"justify-end":"justify-start"),children:[!n&&e.jsx("div",{className:"w-8 h-8 rounded-md bg-primary/10 flex items-center justify-center shrink-0 mt-1",children:e.jsx(T,{size:16,className:"text-primary"})}),e.jsx("div",{className:j("rounded-lg px-5 py-3.5 text-sm",n?"max-w-[70%] bg-primary text-primary-foreground rounded-br-md":"max-w-[85%] bg-card border text-card-foreground rounded-bl-md shadow-sm"),children:e.jsx(_,{content:t.content,isUser:n})}),n&&e.jsx("div",{className:"w-8 h-8 rounded-md bg-muted flex items-center justify-center shrink-0 mt-1",children:e.jsx(U,{size:16,className:"text-muted-foreground"})})]},k)}),e.jsx("div",{ref:f})]}),e.jsx("div",{className:"border-t pt-4",children:s!=null&&s.live?e.jsxs("div",{className:"relative",children:[e.jsx(B,{value:d,onChange:t=>m(t.target.value),onKeyDown:N,placeholder:r("sessions.messageInput"),rows:2,className:"min-h-[88px] rounded-[24px] border-gray-200 bg-white px-4 pb-14 pt-3 text-[15px] leading-6 shadow-[0_12px_34px_rgba(15,23,42,0.08)] dark:border-white/[0.08] dark:bg-[rgba(0,0,0,0.42)] sm:min-h-[96px] sm:px-5 sm:pt-4",disabled:c}),e.jsx(g,{onClick:h,disabled:c||!d.trim(),size:"icon","aria-label":r("sessions.messageInput"),className:"absolute bottom-3 right-3 h-10 w-10 rounded-full bg-slate-900 px-0 text-white shadow-none hover:bg-slate-800 disabled:bg-slate-300 disabled:text-white disabled:opacity-100 dark:bg-slate-100 dark:text-slate-950 dark:hover:bg-white dark:disabled:bg-white/20 dark:disabled:text-white/55 sm:h-11 sm:w-11",children:c?e.jsxs("svg",{className:"animate-spin h-4 w-4",viewBox:"0 0 24 24",children:[e.jsx("circle",{className:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4",fill:"none"}),e.jsx("path",{className:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"})]}):e.jsx(A,{size:20,strokeWidth:2.2})})]}):e.jsxs("div",{className:"flex items-center gap-2 px-4 py-3 text-sm text-muted-foreground bg-muted rounded-lg",children:[e.jsx(y,{size:14}),e.jsx("span",{children:r("sessions.notLiveHint")})]})})]})}export{G as default};
@@ -1 +0,0 @@
1
- import{V as l,P as d,X as c,Y as u,_ as h,$ as C,a0 as k,a1 as w,a2 as p,a3 as v,a4 as S,a5 as m,a6 as L,a7 as y,a8 as P,a9 as f,aa as R,ab as b,ac as G,ad as Q,ae as B,af as A,ag as F,ah as E,ai as I,aj as W,ak as D,al as K,am as T,an as x,ao as $,ap as j,aq as U,o as i,m as z,ar as _,as as q,at as M,au as V,av as X,aw as Y,ax as H,ay as J,i as N}from"./index-Cx71F_Lz.js";function s(){if(!window.desktop)throw new Error("Desktop APIs are unavailable in the browser build");return window.desktop}const O={getRuntimeStatus:()=>s().getRuntimeStatus(),startService:()=>s().startService(),stopService:()=>s().stopService(),restartService:()=>s().restartService(),getLogs:e=>s().getLogs(e),listInstalledAgentRuntimes:()=>x().then(e=>e.runtimes),refreshInstalledAgentRuntimes:()=>T().then(e=>e.runtimes),readConfigFile:()=>s().readConfigFile(),saveRawConfigFile:e=>s().saveRawConfigFile(e),saveStructuredConfigFile:e=>s().saveStructuredConfigFile(e),getThreadKnowledgeBases:(e,a)=>s().getThreadKnowledgeBases(e,a),updateThreadKnowledgeBases:(e,a,t)=>s().updateThreadKnowledgeBases(e,a,t),deleteThreadKnowledgeBases:(e,a)=>s().deleteThreadKnowledgeBases(e,a),saveSettings:e=>s().saveSettings(e),getCapabilitySnapshot:()=>K(),getPluginDiagnostics:()=>D(),listChannelGateways:e=>W(e).then(a=>a.gateways),getChannelGatewayStatus:(e,a,t)=>I(e,a,t),testChannelConnection:(e,a,t)=>E(e,a,t),enableChannelGateway:(e,a,t)=>F(e,a,t),disableChannelGateway:(e,a,t)=>A(e,a,t),listChannelPendingPairings:(e,a)=>B(e,a).then(t=>t.pairings),approveChannelPairing:(e,a)=>Q(e,a),rejectChannelPairing:(e,a)=>G(e,a),listChannelAuthorizedUsers:(e,a)=>b(e,a).then(t=>t.users),getChannelQrCode:(e,a,t)=>R(e,a,t),checkChannelQrCodeStatus:(e,a,t,r)=>f(e,a,t,r),getWeixinQrCode:(e,a)=>P(e,a),checkWeixinQrCodeStatus:(e,a,t)=>y(e,a,t),getLarkQrCode:(e,a)=>L(e,a),checkLarkQrCodeStatus:(e,a,t)=>m(e,a,t),listLarkGateways:()=>S().then(e=>e.gateways),getLarkGatewayStatus:(e,a)=>v(e,a),testLarkConnection:(e,a)=>p(e,a),enableLarkGateway:(e,a)=>w(e,a),disableLarkGateway:(e,a)=>k(e,a),listLarkPendingPairings:e=>C(e).then(a=>a.pairings),approveLarkPairing:e=>h(e),rejectLarkPairing:e=>u(e),listLarkAuthorizedUsers:e=>c(e).then(a=>a.users),probeWorkspaceStreaming:e=>s().probeWorkspaceStreaming(e),onRuntimeEvent:e=>s().onRuntimeEvent(e),onRuntimeDetectionEvent:e=>d(a=>{(a.type.startsWith("runtime.detect.")||a.type==="runtime.status.changed")&&e(a)}),onBridgeEvent:e=>l(e)},o={getRuntimeStatus:()=>J(),startService:()=>H(),stopService:()=>Y(),restartService:()=>X(),getLogs:e=>V(e),listInstalledAgentRuntimes:()=>x().then(e=>e.runtimes),refreshInstalledAgentRuntimes:()=>T().then(e=>e.runtimes),readConfigFile:()=>M(),saveRawConfigFile:e=>q(e),saveStructuredConfigFile:e=>_(e),getThreadKnowledgeBases:(e,a)=>z(a).then(t=>t.selectedKnowledgeBaseIds||[]),updateThreadKnowledgeBases:(e,a,t)=>i(a,t).then(r=>r.knowledgeBaseIds),deleteThreadKnowledgeBases:(e,a)=>i(a,[]).then(()=>({deleted:!0})),saveSettings:e=>U(e),getCapabilitySnapshot:()=>K(),getPluginDiagnostics:()=>D(),listChannelGateways:e=>W(e).then(a=>a.gateways),getChannelGatewayStatus:(e,a,t)=>I(e,a,t),testChannelConnection:(e,a,t)=>E(e,a,t),enableChannelGateway:(e,a,t)=>F(e,a,t),disableChannelGateway:(e,a,t)=>A(e,a,t),listChannelPendingPairings:(e,a)=>B(e,a).then(t=>t.pairings),approveChannelPairing:(e,a)=>Q(e,a),rejectChannelPairing:(e,a)=>G(e,a),listChannelAuthorizedUsers:(e,a)=>b(e,a).then(t=>t.users),getChannelQrCode:(e,a,t)=>R(e,a,t),checkChannelQrCodeStatus:(e,a,t,r)=>f(e,a,t,r),getWeixinQrCode:(e,a)=>P(e,a),checkWeixinQrCodeStatus:(e,a,t)=>y(e,a,t),getLarkQrCode:(e,a)=>L(e,a),checkLarkQrCodeStatus:(e,a,t)=>m(e,a,t),listLarkGateways:()=>S().then(e=>e.gateways),getLarkGatewayStatus:(e,a)=>v(e,a),testLarkConnection:(e,a)=>p(e,a),enableLarkGateway:(e,a)=>w(e,a),disableLarkGateway:(e,a)=>k(e,a),listLarkPendingPairings:e=>C(e).then(a=>a.pairings),approveLarkPairing:e=>h(e),rejectLarkPairing:e=>u(e),listLarkAuthorizedUsers:e=>c(e).then(a=>a.users),probeWorkspaceStreaming:e=>j(e),onRuntimeEvent:e=>$(e),onRuntimeDetectionEvent:e=>d(a=>{(a.type.startsWith("runtime.detect.")||a.type==="runtime.status.changed")&&e(a)}),onBridgeEvent:e=>l(e)};let g=null;function Z(e){return e==="electron"&&window.desktop?O:o}function n(){const e=g||Z(N());if(!e)throw new Error("Managed desktop APIs are unavailable in this build");return g=e,e}const ae=()=>n().getRuntimeStatus(),te=()=>n().startService(),ne=()=>n().listInstalledAgentRuntimes(),se=()=>n().refreshInstalledAgentRuntimes(),re=()=>n().readConfigFile(),ie=e=>n().saveStructuredConfigFile(e),oe=(e,a,t)=>n().updateThreadKnowledgeBases(e,a,t),ge=e=>n().saveSettings(e),le=()=>n().getPluginDiagnostics(),de=(e,a)=>n().getWeixinQrCode(e,a),ce=(e,a,t)=>n().checkWeixinQrCodeStatus(e,a,t),ue=(e,a)=>n().getLarkQrCode(e,a),he=(e,a,t)=>n().checkLarkQrCodeStatus(e,a,t),Ce=(e,a)=>n().testLarkConnection(e,a),ke=(e,a)=>n().enableLarkGateway(e,a),we=e=>n().onRuntimeEvent(e),pe=e=>n().onRuntimeDetectionEvent(e),ve=e=>n().onBridgeEvent(e);export{pe as a,ve as b,re as c,ie as d,ke as e,de as f,ae as g,ue as h,ce as i,he as j,le as k,ne as l,ge as m,we as o,se as r,te as s,Ce as t,oe as u};
@@ -1,4 +0,0 @@
1
- const h="pi",s="opencode/minimax-m2.5-free";const w=["pi","opencode","codex","claudecode","cursor","gemini","qoder","iflow","hermes","localcore-acp"],f=["telegram","feishu","lark","discord","slack","dingtalk","wecom","weixin","qq","qqbot","line"],n=["pi","opencode","codex","claudecode","hermes","acp","localcore-acp"],c="localcore-acp",i=["[Scheduler Tools]","If the user asks to create, view, edit, delete, or manually run a scheduled task for this conversation, use the Bash tool to run the local scheduler CLI.","Use these commands:",'lac scheduler add --cron "<5-field cron>" --message "<exact message to send>" --desc "<short label>" [--execution-mode same-thread|side-thread]',"lac scheduler list","lac scheduler list --thread","lac scheduler info <short-job-id>",'lac scheduler edit <short-job-id> [--cron "<5-field cron>"] [--message "<exact message>"] [--desc "<short label>"] [--enabled true|false] [--execution-mode same-thread|side-thread]',"lac scheduler del <short-job-id>","lac scheduler run <short-job-id>","Environment variables LOCAL_AI_WORKSPACE_ID, LOCAL_AI_THREAD_ID, LOCAL_AI_PLATFORM, LOCAL_AI_CHAT_ID, and LOCAL_AI_PLATFORM_USER_ID are already set when available.","Prefer relying on those variables instead of inventing your own route or creating session-only cron jobs.","By default, `lac scheduler list` shows all scheduled tasks in the current workspace. Use `lac scheduler list --thread` to show only the current conversation thread.","Use the short job id shown by `lac scheduler list`; do not add a `job:` prefix or expand it to a full UUID.","Use `--execution-mode same-thread` to reuse the current thread, or `--execution-mode side-thread` to run in a dedicated scheduled thread.","Only use the scheduler CLI when the user explicitly asks for scheduled automation.","[/Scheduler Tools]"].join(`
2
- `),d=["[Channel Tools]","If the user asks you to send a local file back through the current channel conversation, use the Bash tool to run the local channel CLI.","Use this command:",'lac channel send-file --path "<absolute-or-workdir-relative-file-path>" [--target "<channel-chat-or-user-id>"]',"By default, the file is sent to the current platform conversation from LOCAL_AI_CHAT_ID.","Use --target only when the user explicitly names a different channel chat or user id.","The CLI accepts absolute paths. Check that the file exists before sending when practical.","Only use the channel CLI when the user explicitly asks to send a file through the channel.","[/Channel Tools]"].join(`
3
- `),u={allow:"allow",deny:"deny","allow all":"allow all",allowall:"allow all",allow_all:"allow all",allow_always:"allow all",always:"allow all",always_allow:"allow all","always allow":"allow all","allow always":"allow all",始终允许:"allow all",永久允许:"allow all","perm:allow":"allow","perm:deny":"deny","perm:allow_all":"allow all","perm:allow_always":"allow all","perm:always":"allow all"};function _(l,e=[]){return[i,"",d,...e.flatMap(a=>a?["",a]:[]),"","[User Message]",l,"[/User Message]"].join(`
4
- `)}function m(l){switch(String(l||"").trim().toLowerCase()){case"opencode":return s;case"claudecode":return"";default:return""}}function p(l,e){const a=String(l||"").trim().toLowerCase(),t=String(e||"").trim();return a?a==="opencode"?t||s:a==="claudecode"&&t.startsWith("opencode/")?"":t:t}function r(l){if(!l)return null;const e=String(l).trim().toLowerCase(),a=u[e];return a||(e.includes("allow_all")||e.includes("allow-always")||e.includes("allow_always")||e.includes("allow always")||e.includes("always allow")||e.includes("allow all")||e.includes("始终允许")||e.includes("永久允许")?"allow all":e.startsWith("reject")||e.startsWith("deny")?"deny":e.startsWith("allow")?"allow":null)}function O(l){return!!r(l==null?void 0:l.data)}function T(l){if(!l||typeof l!="object")return null;const e=l,a=typeof e.text=="string"?e.text:typeof e.Text=="string"?e.Text:"",t=typeof e.data=="string"?e.data:typeof e.Data=="string"?e.Data:"";if(!a||!t)return null;const o=r(t);return o?{text:o,data:o}:{text:a,data:t}}function E(l){return l?n.includes(String(l).trim().toLowerCase()):!1}function L(l){const e=String(l||"").trim().toLowerCase();return e==="acp"||e==="pi"||e==="opencode"||e==="codex"||e==="claudecode"||e==="hermes"||e===c}export{w as D,r as a,L as b,p as c,f as d,h as e,m as g,O as i,T as n,E as s,_ as w};