@kafca/agentdock 0.1.42 → 0.1.44
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 +10 -0
- package/dist/renderer/assets/{Badge-D-WU4kUV.js → Badge-Qk9qHovH.js} +1 -1
- package/dist/renderer/assets/{Chat-BGkC5tAe.js → Chat-BK-fm0Xr.js} +1 -1
- package/dist/renderer/assets/{ChatMarkdown-CfbC1jRd.js → ChatMarkdown-BKdW8OON.js} +1 -1
- package/dist/renderer/assets/{Config-qQb4bX5D.js → Config-B93CQGvY.js} +2 -2
- package/dist/renderer/assets/CronList-Z3TvSRKP.js +1 -0
- package/dist/renderer/assets/{Dashboard-xn6cUy_n.js → Dashboard-Ch3QkWwf.js} +2 -2
- package/dist/renderer/assets/{EmptyState-BdKBBUpr.js → EmptyState-kD9yAwtw.js} +1 -1
- package/dist/renderer/assets/{KnowledgeDetail-Duk8IQP3.js → KnowledgeDetail-BAMCLrjz.js} +2 -2
- package/dist/renderer/assets/{KnowledgeHome-BfjX_4Sv.js → KnowledgeHome-ChvjOfrc.js} +2 -2
- package/dist/renderer/assets/{Logs-Bfq61QMn.js → Logs-Cv0nth3j.js} +1 -1
- package/dist/renderer/assets/{Modal-B3vlBmBr.js → Modal-DwY4lecS.js} +1 -1
- package/dist/renderer/assets/MonitorList-JEvMoWUm.js +1 -0
- package/dist/renderer/assets/{Page-CPsLOP3z.js → Page-CnB9ePsb.js} +1 -1
- package/dist/renderer/assets/{ProjectDetail-D-g46wyF.js → ProjectDetail-DJa3sMmU.js} +2 -2
- package/dist/renderer/assets/{ProjectList-BrQEKDQ8.js → ProjectList-D6CXumR_.js} +1 -1
- package/dist/renderer/assets/{Select-C4CFMQmF.js → Select-zfoksLGB.js} +1 -1
- package/dist/renderer/assets/SessionChat-DUTh4WoM.js +1 -0
- package/dist/renderer/assets/{SessionList-DPWIUbOg.js → SessionList-D9o-lUst.js} +1 -1
- package/dist/renderer/assets/{ThreadChat-BjtU-j9q.js → ThreadChat-BYXlT-Kc.js} +7 -7
- package/dist/renderer/assets/{Workspace-BcNmHuJx.js → Workspace-BrhSwRQ-.js} +1 -1
- package/dist/renderer/assets/{arrow-left-DPzSmidS.js → arrow-left-CNEAuElg.js} +1 -1
- package/dist/renderer/assets/{book-open-B0xhoRqZ.js → book-open-BNJMhNI-.js} +1 -1
- package/dist/renderer/assets/{check-BTJTyd0C.js → check-BnclClRU.js} +1 -1
- package/dist/renderer/assets/{chevron-down-B6jJXlhi.js → chevron-down-Bh53e0O-.js} +1 -1
- package/dist/renderer/assets/{circle-qRhJR9qR.js → circle-ClZTWCWO.js} +1 -1
- package/dist/renderer/assets/desktop-C5vBT0yM.js +1 -0
- package/dist/renderer/assets/desktop-C6q6wBae.js +5 -0
- package/dist/renderer/assets/en-D2SkCrhG.js +1 -0
- package/dist/renderer/assets/{funnel-CbYKGTn8.js → funnel-_5hsz0xI.js} +1 -1
- package/dist/renderer/assets/{heart-DjwWJfkz.js → heart-u4Q1aOqj.js} +1 -1
- package/dist/renderer/assets/{index-BWmHJRhe.js → index-B36eowj-.js} +39 -34
- package/dist/renderer/assets/{index-CyZs_2NJ.js → index-BNFx4uYv.js} +3 -3
- package/dist/renderer/assets/{pencil-1dfAivmj.js → pencil-DLh9QNmT.js} +1 -1
- package/dist/renderer/assets/{play-CB3w1G6S.js → play-BDTk9Scm.js} +1 -1
- package/dist/renderer/assets/{plug-Bvep5o3r.js → plug-BG0JHW6B.js} +1 -1
- package/dist/renderer/assets/{plus-DJVg9m09.js → plus-BSc8POsz.js} +1 -1
- package/dist/renderer/assets/projects-DwfZwxDW.js +1 -0
- package/dist/renderer/assets/{save-xjJn3qf2.js → save-D5AO_G6a.js} +1 -1
- package/dist/renderer/assets/{search-BK3UrQxM.js → search-CniPk7Ey.js} +1 -1
- package/dist/renderer/assets/{server-Dyd2eXJu.js → server-GsXyQAZm.js} +1 -1
- package/dist/renderer/assets/{session-utils-eXC0020s.js → session-utils-BDxzgTBC.js} +1 -1
- package/dist/renderer/assets/{sessions-WLYpkyUt.js → sessions-CLcKA1Tt.js} +1 -1
- package/dist/renderer/assets/{shield-check-C0N6aWzF.js → shield-check-4i0E3hmf.js} +1 -1
- package/dist/renderer/assets/{trash-2-BGMTNJA6.js → trash-2-DhtOCsO5.js} +1 -1
- package/dist/renderer/assets/{user-BcGMLyhu.js → user-BtC_pVXV.js} +1 -1
- package/dist/renderer/assets/{wifi-off-FhcQx0HK.js → wifi-off-BHPzPY_B.js} +1 -1
- package/dist/renderer/assets/zh-DIcdHycM.js +1 -0
- package/dist/renderer/index.html +1 -1
- package/dist-electron/packages/contracts/src/local-core.js +28 -0
- package/dist-electron/packages/core-sdk/src/index.js +32 -0
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-backend.js +51 -0
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-store.js +4 -1364
- package/dist-electron/services/local-ai-core/src/acp/store/agent-task-store.js +166 -0
- package/dist-electron/services/local-ai-core/src/acp/store/automation-monitor-store.js +231 -0
- package/dist-electron/services/local-ai-core/src/acp/store/local-core-acp-store.js +263 -0
- package/dist-electron/services/local-ai-core/src/acp/store/platform-store.js +186 -0
- package/dist-electron/services/local-ai-core/src/acp/store/scheduler-store.js +201 -0
- package/dist-electron/services/local-ai-core/src/acp/store/schema.js +275 -0
- package/dist-electron/services/local-ai-core/src/acp/store/security-store.js +266 -0
- package/dist-electron/services/local-ai-core/src/acp/store/thread-store.js +232 -0
- package/dist-electron/services/local-ai-core/src/acp/store/utils.js +47 -0
- package/dist-electron/services/local-ai-core/src/acp/store/workspace-registry-store.js +109 -0
- package/dist-electron/services/local-ai-core/src/automation/automation-conversation-executor.js +136 -0
- package/dist-electron/services/local-ai-core/src/automation/automation-monitor-repository.js +56 -0
- package/dist-electron/services/local-ai-core/src/automation/automation-monitor-service.js +359 -0
- package/dist-electron/services/local-ai-core/src/automation/condition-evaluator.js +77 -0
- package/dist-electron/services/local-ai-core/src/automation/mock-stock-provider.js +40 -0
- package/dist-electron/services/local-ai-core/src/automation/monitor-id.js +10 -0
- package/dist-electron/services/local-ai-core/src/channel/lark/cards.js +55 -0
- package/dist-electron/services/local-ai-core/src/channel/lark/config.js +2 -0
- package/dist-electron/services/local-ai-core/src/channel/lark/inbound.js +114 -0
- package/dist-electron/services/local-ai-core/src/channel/lark/local-core-lark-gateway.js +153 -94
- package/dist-electron/services/local-ai-core/src/channel/shared/session-command-runtime.js +53 -0
- package/dist-electron/services/local-ai-core/src/channel/shared/thread-routing.js +34 -0
- package/dist-electron/services/local-ai-core/src/channel/weixin/local-core-weixin-gateway.js +63 -51
- package/dist-electron/services/local-ai-core/src/cli/lac.js +196 -0
- package/dist-electron/services/local-ai-core/src/cli/monitor-cli-parsers.js +37 -0
- package/dist-electron/services/local-ai-core/src/kernel/bootstrap.js +43 -0
- package/dist-electron/services/local-ai-core/src/kernel/capability-registry.js +12 -0
- package/dist-electron/services/local-ai-core/src/plugins/builtin/monitor-stock-plugin.js +30 -0
- package/dist-electron/services/local-ai-core/src/runtime/local-core-controller.js +41 -0
- package/dist-electron/services/local-ai-core/src/runtime/server-routes.js +31 -0
- package/dist-electron/services/local-ai-core/src/runtime/server.js +36 -0
- package/dist-electron/services/local-ai-core/src/scheduler/scheduled-bridge-session.js +25 -11
- package/dist-electron/services/local-ai-core/src/thread/session-command-service.js +275 -0
- package/dist-electron/services/local-ai-core/src/thread/slash-command-registry.js +27 -0
- package/dist-electron/services/local-ai-core/src/thread/thread-command-service.js +15 -15
- package/dist-electron/shared/desktop.js +21 -1
- package/dist-electron/tests/contracts/local-core-contracts.test.js +9 -0
- package/dist-electron/tests/electron/automation-monitor.test.js +38 -0
- package/dist-electron/tests/electron/lac-cli.test.js +146 -0
- package/dist-electron/tests/integration/channel-gateways.test.js +32 -0
- package/dist-electron/tests/integration/lark-gateway.test.js +1918 -0
- package/dist-electron/tests/integration/local-core-acp-progress.test.js +1772 -0
- package/dist-electron/tests/integration/local-core-refactor.test.js +216 -4566
- package/dist-electron/tests/integration/local-core-routes.test.js +204 -0
- package/dist-electron/tests/integration/weixin-gateway.test.js +927 -0
- package/package.json +1 -1
- package/dist/renderer/assets/CronList-CKhggzYk.js +0 -1
- package/dist/renderer/assets/SessionChat-06Jny5_G.js +0 -1
- package/dist/renderer/assets/desktop-DXmXjjUR.js +0 -1
- package/dist/renderer/assets/desktop-O8_6ZCVZ.js +0 -4
- package/dist/renderer/assets/en-CKhCF6St.js +0 -1
- package/dist/renderer/assets/projects-xnW0fTtq.js +0 -1
- package/dist/renderer/assets/zh-Dz5FLTBV.js +0 -1
package/dist-electron/services/local-ai-core/src/channel/weixin/local-core-weixin-gateway.js
CHANGED
|
@@ -13,6 +13,9 @@ const node_crypto_2 = require("node:crypto");
|
|
|
13
13
|
const desktop_js_1 = require("../../../../../shared/desktop.js");
|
|
14
14
|
const content_js_1 = require("../shared/content.js");
|
|
15
15
|
const file_utils_js_1 = require("../shared/file-utils.js");
|
|
16
|
+
const session_command_runtime_js_1 = require("../shared/session-command-runtime.js");
|
|
17
|
+
const thread_routing_js_1 = require("../shared/thread-routing.js");
|
|
18
|
+
const session_command_service_js_1 = require("../../thread/session-command-service.js");
|
|
16
19
|
const config_js_1 = require("./config.js");
|
|
17
20
|
const transport_js_1 = require("./transport.js");
|
|
18
21
|
// ==================== Constants ====================
|
|
@@ -150,11 +153,36 @@ class LocalCoreWeixinGateway extends node_events_1.EventEmitter {
|
|
|
150
153
|
outboundTurns = new Map();
|
|
151
154
|
processedInboundMessages = new Map();
|
|
152
155
|
mutedThreadBridgeCounts = new Map();
|
|
156
|
+
sessionCommandRuntime;
|
|
153
157
|
platform = 'weixin';
|
|
154
158
|
routeType = 'channel.chat';
|
|
155
159
|
constructor(options) {
|
|
156
160
|
super();
|
|
157
161
|
this.options = options;
|
|
162
|
+
const sessionCommandService = new session_command_service_js_1.SessionCommandService({
|
|
163
|
+
listThreads: (workspaceId) => this.options.getWorkspaceRouter().listThreads(workspaceId),
|
|
164
|
+
getThread: (threadId) => this.options.getWorkspaceRouter().getThread(threadId),
|
|
165
|
+
createThread: (workspaceId, title) => this.options.getWorkspaceRouter().createThread(workspaceId, title),
|
|
166
|
+
renameThread: (threadId, title) => this.options.getWorkspaceRouter().renameThread(threadId, title),
|
|
167
|
+
deleteThread: (threadId) => this.options.getWorkspaceRouter().deleteThread(threadId),
|
|
168
|
+
});
|
|
169
|
+
this.sessionCommandRuntime = new session_command_runtime_js_1.ChannelSessionCommandRuntime({
|
|
170
|
+
service: sessionCommandService,
|
|
171
|
+
store: this.options.store,
|
|
172
|
+
getThreadSessionKey: (threadId) => this.options.getWorkspaceRouter().getThreadSessionKey(threadId),
|
|
173
|
+
setThreadRoute: (sessionKey, route) => {
|
|
174
|
+
this.threadRouting.set(sessionKey, route);
|
|
175
|
+
},
|
|
176
|
+
createRoute: (input, threadId) => ({
|
|
177
|
+
workspaceId: input.workspaceId,
|
|
178
|
+
instanceId: input.instanceId,
|
|
179
|
+
platformKey: input.platformKey,
|
|
180
|
+
platformUserId: input.platformUserId,
|
|
181
|
+
chatId: input.chatId,
|
|
182
|
+
threadId,
|
|
183
|
+
}),
|
|
184
|
+
sendResult: (input, result) => this.sendSessionCommandResult(input, result),
|
|
185
|
+
});
|
|
158
186
|
}
|
|
159
187
|
// ==================== Lifecycle ====================
|
|
160
188
|
async refreshBindings() {
|
|
@@ -630,25 +658,17 @@ class LocalCoreWeixinGateway extends node_events_1.EventEmitter {
|
|
|
630
658
|
return { paired: false };
|
|
631
659
|
}
|
|
632
660
|
const router = this.options.getWorkspaceRouter();
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
platform_user_id: input.platformUserId,
|
|
645
|
-
thread_id: threadId,
|
|
646
|
-
last_platform_message_id: null,
|
|
647
|
-
created_at: now,
|
|
648
|
-
updated_at: now,
|
|
649
|
-
});
|
|
650
|
-
}
|
|
651
|
-
const sessionKey = router.getThreadSessionKey(threadId);
|
|
661
|
+
let { threadId } = await (0, thread_routing_js_1.resolveChannelThreadRoute)({
|
|
662
|
+
store: this.options.store,
|
|
663
|
+
router,
|
|
664
|
+
workspaceId: input.workspaceId,
|
|
665
|
+
platformKey,
|
|
666
|
+
chatId: input.chatId,
|
|
667
|
+
platformUserId: input.platformUserId,
|
|
668
|
+
displayName: input.displayName,
|
|
669
|
+
fallbackTitlePrefix: 'WeChat',
|
|
670
|
+
authorized,
|
|
671
|
+
});
|
|
652
672
|
const normalizedText = String(input.text || '').trim().toLowerCase();
|
|
653
673
|
const permissionThreadId = (normalizedText === 'allow' || normalizedText === 'allow all' || normalizedText === 'deny') ? this.findAwaitingPermissionThreadId(input.workspaceId, input.chatId, input.platformUserId, input.platformKey) : '';
|
|
654
674
|
if (permissionThreadId && permissionThreadId !== threadId) {
|
|
@@ -665,38 +685,19 @@ class LocalCoreWeixinGateway extends node_events_1.EventEmitter {
|
|
|
665
685
|
});
|
|
666
686
|
// Handle slash commands
|
|
667
687
|
const slashCommand = this.parseSlashCommand(input.text);
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
platform_user_id: input.platformUserId,
|
|
682
|
-
thread_id: nextThread.id,
|
|
683
|
-
last_platform_message_id: null,
|
|
684
|
-
created_at: now,
|
|
685
|
-
updated_at: now,
|
|
686
|
-
});
|
|
687
|
-
this.threadRouting.set(router.getThreadSessionKey(nextThread.id), {
|
|
688
|
-
workspaceId: input.workspaceId,
|
|
689
|
-
instanceId,
|
|
690
|
-
platformKey,
|
|
691
|
-
platformUserId: input.platformUserId,
|
|
692
|
-
chatId: input.chatId,
|
|
693
|
-
threadId: nextThread.id,
|
|
694
|
-
});
|
|
695
|
-
const st = this.runtime.get((0, config_js_1.runtimeKey)(input.workspaceId, instanceId));
|
|
696
|
-
if (st?.connected) {
|
|
697
|
-
await this.sendTextMessage(st, input.chatId, '**已开始新会话**', input.contextToken);
|
|
698
|
-
}
|
|
699
|
-
return { paired: true, threadId: nextThread.id };
|
|
688
|
+
const sessionCommand = await this.executeSessionCommand({
|
|
689
|
+
workspaceId: input.workspaceId,
|
|
690
|
+
currentThreadId: threadId,
|
|
691
|
+
text: input.text,
|
|
692
|
+
defaultTitle: `${input.displayName || 'WeChat'} ${new Date().toLocaleTimeString()}`,
|
|
693
|
+
chatId: input.chatId,
|
|
694
|
+
platformUserId: input.platformUserId,
|
|
695
|
+
platformKey,
|
|
696
|
+
instanceId,
|
|
697
|
+
contextToken: input.contextToken,
|
|
698
|
+
});
|
|
699
|
+
if (sessionCommand.handled) {
|
|
700
|
+
return { paired: true, threadId: sessionCommand.threadId || threadId };
|
|
700
701
|
}
|
|
701
702
|
const latestRun = this.options.store.getLatestRunForThread(threadId);
|
|
702
703
|
if ((normalizedText === 'allow' || normalizedText === 'allow all' || normalizedText === 'deny')
|
|
@@ -711,6 +712,17 @@ class LocalCoreWeixinGateway extends node_events_1.EventEmitter {
|
|
|
711
712
|
await router.sendThreadMessage(threadId, (0, content_js_1.createChannelThreadMessageInput)(wrappedText, input.contentParts));
|
|
712
713
|
return { paired: true, threadId };
|
|
713
714
|
}
|
|
715
|
+
async executeSessionCommand(input) {
|
|
716
|
+
return this.sessionCommandRuntime.execute(input);
|
|
717
|
+
}
|
|
718
|
+
async sendSessionCommandResult(input, result) {
|
|
719
|
+
const state = this.resolveRuntimeState(input.workspaceId, input.instanceId).state;
|
|
720
|
+
if (!state?.connected) {
|
|
721
|
+
this.options.log?.(`localcore-weixin session command response skipped: workspace not connected: ${input.workspaceId}`);
|
|
722
|
+
return;
|
|
723
|
+
}
|
|
724
|
+
await this.sendTextMessage(state, input.chatId, result.displayText, input.contextToken);
|
|
725
|
+
}
|
|
714
726
|
// ==================== Private: Bindings ====================
|
|
715
727
|
resolveRuntimeState(workspaceId, instanceId) {
|
|
716
728
|
if (instanceId) {
|
|
@@ -8,6 +8,8 @@ const node_process_1 = __importDefault(require("node:process"));
|
|
|
8
8
|
const index_js_1 = require("../../../../packages/contracts/src/index.js");
|
|
9
9
|
const job_id_js_1 = require("../scheduler/job-id.js");
|
|
10
10
|
const scheduled_job_route_js_1 = require("../scheduler/scheduled-job-route.js");
|
|
11
|
+
const monitor_id_js_1 = require("../automation/monitor-id.js");
|
|
12
|
+
const monitor_cli_parsers_js_1 = require("./monitor-cli-parsers.js");
|
|
11
13
|
const DEFAULT_BASE_URL = 'http://127.0.0.1:9831/api/local/v1';
|
|
12
14
|
async function runCli(argv, env = node_process_1.default.env, io = node_process_1.default) {
|
|
13
15
|
try {
|
|
@@ -23,6 +25,26 @@ async function runCli(argv, env = node_process_1.default.env, io = node_process_
|
|
|
23
25
|
return 2;
|
|
24
26
|
}
|
|
25
27
|
}
|
|
28
|
+
if (domain === 'monitor') {
|
|
29
|
+
switch (action) {
|
|
30
|
+
case 'add':
|
|
31
|
+
return await handleMonitorAdd(flags, env, io, json);
|
|
32
|
+
case 'list':
|
|
33
|
+
return await handleMonitorList(flags, env, io, json);
|
|
34
|
+
case 'info':
|
|
35
|
+
return await handleMonitorInfo(maybeId, flags, env, io, json);
|
|
36
|
+
case 'edit':
|
|
37
|
+
return await handleMonitorEdit(maybeId, flags, env, io, json);
|
|
38
|
+
case 'del':
|
|
39
|
+
case 'delete':
|
|
40
|
+
return await handleMonitorDelete(maybeId, flags, env, io, json);
|
|
41
|
+
case 'run':
|
|
42
|
+
return await handleMonitorRun(maybeId, flags, env, io, json);
|
|
43
|
+
default:
|
|
44
|
+
printUsage(io.stderr);
|
|
45
|
+
return 2;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
26
48
|
if (domain !== 'scheduler') {
|
|
27
49
|
printUsage(io.stderr);
|
|
28
50
|
return 2;
|
|
@@ -51,6 +73,110 @@ async function runCli(argv, env = node_process_1.default.env, io = node_process_
|
|
|
51
73
|
return 1;
|
|
52
74
|
}
|
|
53
75
|
}
|
|
76
|
+
async function handleMonitorAdd(flags, env, io, json) {
|
|
77
|
+
const context = resolveContext(flags, env);
|
|
78
|
+
if (!context.workspaceId) {
|
|
79
|
+
throw new Error('monitor add requires a workspace context. Set LOCAL_AI_WORKSPACE_ID or pass --workspace.');
|
|
80
|
+
}
|
|
81
|
+
const title = getRequiredFlag(flags, 'title');
|
|
82
|
+
const sourceType = getRequiredFlag(flags, 'source');
|
|
83
|
+
const promptTemplate = getRequiredFlag(flags, 'message');
|
|
84
|
+
const condition = (0, monitor_cli_parsers_js_1.parseMonitorCondition)(getRequiredFlag(flags, 'condition'));
|
|
85
|
+
const sourceConfig = buildSourceConfig(sourceType, flags);
|
|
86
|
+
const monitor = await request(context.baseUrl, 'POST', '/automation/monitors', {
|
|
87
|
+
workspaceId: context.workspaceId,
|
|
88
|
+
...(context.threadId ? { threadId: context.threadId } : {}),
|
|
89
|
+
title,
|
|
90
|
+
sourceType,
|
|
91
|
+
sourceConfig,
|
|
92
|
+
condition,
|
|
93
|
+
promptTemplate,
|
|
94
|
+
executionMode: getMonitorExecutionMode(flags),
|
|
95
|
+
cooldownMs: (0, monitor_cli_parsers_js_1.parseDurationMs)(getFlag(flags, 'cooldown') || '15m'),
|
|
96
|
+
enabled: true,
|
|
97
|
+
});
|
|
98
|
+
print(json, io.stdout, presentMonitor(monitor), [
|
|
99
|
+
`Created monitor ${(0, monitor_id_js_1.toPublicAutomationMonitorId)(monitor.id)}`,
|
|
100
|
+
`Title: ${monitor.title}`,
|
|
101
|
+
`Source: ${monitor.sourceType}`,
|
|
102
|
+
`Condition: ${formatCondition(monitor.condition)}`,
|
|
103
|
+
`Execution mode: ${monitor.executionMode}`,
|
|
104
|
+
].join('\n'));
|
|
105
|
+
return 0;
|
|
106
|
+
}
|
|
107
|
+
async function handleMonitorList(flags, env, io, json) {
|
|
108
|
+
const context = resolveContext(flags, env);
|
|
109
|
+
const workspaceId = getFlag(flags, 'workspace') || context.workspaceId;
|
|
110
|
+
const threadId = flags.has('thread')
|
|
111
|
+
? normalizeMaybeBooleanFlag(getFlag(flags, 'thread')) || context.threadId
|
|
112
|
+
: '';
|
|
113
|
+
const suffix = workspaceId ? `?workspace_id=${encodeURIComponent(workspaceId)}` : '';
|
|
114
|
+
const response = await request(context.baseUrl, 'GET', `/automation/monitors${suffix}`);
|
|
115
|
+
const monitors = threadId
|
|
116
|
+
? response.monitors.filter((monitor) => monitor.route.threadId === threadId || monitorMatchesCliContext(monitor, context))
|
|
117
|
+
: response.monitors;
|
|
118
|
+
print(json, io.stdout, { monitors: monitors.map(presentMonitor) }, monitors.length === 0 ? 'No monitors.' : monitors.map(formatMonitorLine).join('\n'));
|
|
119
|
+
return 0;
|
|
120
|
+
}
|
|
121
|
+
async function handleMonitorInfo(monitorId, flags, env, io, json) {
|
|
122
|
+
if (!monitorId) {
|
|
123
|
+
throw new Error('monitor info requires a monitor id.');
|
|
124
|
+
}
|
|
125
|
+
const context = resolveContext(flags, env);
|
|
126
|
+
const monitor = await request(context.baseUrl, 'GET', `/automation/monitors/${encodeURIComponent(monitorId)}`);
|
|
127
|
+
const runs = await request(context.baseUrl, 'GET', `/automation/monitors/${encodeURIComponent(monitorId)}/runs`);
|
|
128
|
+
print(json, io.stdout, { monitor: presentMonitor(monitor), runs: runs.runs }, formatMonitorDetails(monitor, runs.runs[0]));
|
|
129
|
+
return 0;
|
|
130
|
+
}
|
|
131
|
+
async function handleMonitorEdit(monitorId, flags, env, io, json) {
|
|
132
|
+
if (!monitorId) {
|
|
133
|
+
throw new Error('monitor edit requires a monitor id.');
|
|
134
|
+
}
|
|
135
|
+
const input = {};
|
|
136
|
+
const title = getFlag(flags, 'title');
|
|
137
|
+
const promptTemplate = getFlag(flags, 'message');
|
|
138
|
+
const condition = getFlag(flags, 'condition');
|
|
139
|
+
const enabled = getOptionalBooleanFlag(flags, 'enabled');
|
|
140
|
+
const executionMode = getFlag(flags, 'execution-mode');
|
|
141
|
+
const cooldown = getFlag(flags, 'cooldown');
|
|
142
|
+
if (title)
|
|
143
|
+
input.title = title;
|
|
144
|
+
if (typeof promptTemplate === 'string' && promptTemplate)
|
|
145
|
+
input.promptTemplate = promptTemplate;
|
|
146
|
+
if (condition)
|
|
147
|
+
input.condition = (0, monitor_cli_parsers_js_1.parseMonitorCondition)(condition);
|
|
148
|
+
if (typeof enabled === 'boolean')
|
|
149
|
+
input.enabled = enabled;
|
|
150
|
+
if (executionMode)
|
|
151
|
+
input.executionMode = (0, index_js_1.normalizeScheduledJobExecutionMode)(executionMode);
|
|
152
|
+
if (cooldown)
|
|
153
|
+
input.cooldownMs = (0, monitor_cli_parsers_js_1.parseDurationMs)(cooldown);
|
|
154
|
+
if (Object.keys(input).length === 0) {
|
|
155
|
+
throw new Error('monitor edit requires at least one editable field.');
|
|
156
|
+
}
|
|
157
|
+
const context = resolveContext(flags, env);
|
|
158
|
+
const monitor = await request(context.baseUrl, 'PATCH', `/automation/monitors/${encodeURIComponent(monitorId)}`, input);
|
|
159
|
+
print(json, io.stdout, presentMonitor(monitor), `Updated monitor ${(0, monitor_id_js_1.toPublicAutomationMonitorId)(monitor.id)}`);
|
|
160
|
+
return 0;
|
|
161
|
+
}
|
|
162
|
+
async function handleMonitorDelete(monitorId, flags, env, io, json) {
|
|
163
|
+
if (!monitorId) {
|
|
164
|
+
throw new Error('monitor del requires a monitor id.');
|
|
165
|
+
}
|
|
166
|
+
const context = resolveContext(flags, env);
|
|
167
|
+
const result = await request(context.baseUrl, 'DELETE', `/automation/monitors/${encodeURIComponent(monitorId)}`);
|
|
168
|
+
print(json, io.stdout, result, `Deleted monitor ${monitorId}`);
|
|
169
|
+
return 0;
|
|
170
|
+
}
|
|
171
|
+
async function handleMonitorRun(monitorId, flags, env, io, json) {
|
|
172
|
+
if (!monitorId) {
|
|
173
|
+
throw new Error('monitor run requires a monitor id.');
|
|
174
|
+
}
|
|
175
|
+
const context = resolveContext(flags, env);
|
|
176
|
+
const run = await request(context.baseUrl, 'POST', `/automation/monitors/${encodeURIComponent(monitorId)}/run`);
|
|
177
|
+
print(json, io.stdout, run, `Triggered monitor ${monitorId}: ${run.status}`);
|
|
178
|
+
return 0;
|
|
179
|
+
}
|
|
54
180
|
async function handleChannelSendFile(flags, env, io, json) {
|
|
55
181
|
const context = resolveContext(flags, env);
|
|
56
182
|
const filePath = getRequiredFlag(flags, 'path');
|
|
@@ -282,6 +408,23 @@ function normalizeMaybeBooleanFlag(value) {
|
|
|
282
408
|
function getExecutionMode(flags) {
|
|
283
409
|
return (0, index_js_1.normalizeScheduledJobExecutionMode)(getFlag(flags, 'execution-mode'));
|
|
284
410
|
}
|
|
411
|
+
function getMonitorExecutionMode(flags) {
|
|
412
|
+
return (0, index_js_1.normalizeScheduledJobExecutionMode)(getFlag(flags, 'execution-mode') || 'side-thread');
|
|
413
|
+
}
|
|
414
|
+
function buildSourceConfig(sourceType, flags) {
|
|
415
|
+
const config = {};
|
|
416
|
+
if (sourceType === 'stock.quote') {
|
|
417
|
+
config.symbol = getRequiredFlag(flags, 'symbol').toUpperCase();
|
|
418
|
+
const price = getFlag(flags, 'price');
|
|
419
|
+
if (price)
|
|
420
|
+
config.price = Number(price);
|
|
421
|
+
}
|
|
422
|
+
const rawConfig = getFlag(flags, 'source-config');
|
|
423
|
+
if (rawConfig) {
|
|
424
|
+
return { ...config, ...JSON.parse(rawConfig) };
|
|
425
|
+
}
|
|
426
|
+
return config;
|
|
427
|
+
}
|
|
285
428
|
function print(asJson, output, payload, text) {
|
|
286
429
|
output.write(asJson ? `${JSON.stringify(payload, null, 2)}\n` : `${text}\n`);
|
|
287
430
|
}
|
|
@@ -294,6 +437,12 @@ function printUsage(output) {
|
|
|
294
437
|
' lac scheduler edit <job-id> [--cron "<expr>"] [--message "<text>"] [--desc "<label>"] [--enabled true|false] [--execution-mode same-thread|side-thread] [--json]',
|
|
295
438
|
' lac scheduler del <job-id> [--json]',
|
|
296
439
|
' lac scheduler run <job-id> [--json]',
|
|
440
|
+
' lac monitor add --title "<title>" --source stock.quote --symbol <symbol> --condition "change_percent >= 3" --message "<text>" [--cooldown 15m] [--execution-mode same-thread|side-thread] [--json]',
|
|
441
|
+
' lac monitor list [--workspace <id>] [--thread [<id>]] [--json]',
|
|
442
|
+
' lac monitor info <monitor-id> [--json]',
|
|
443
|
+
' lac monitor edit <monitor-id> [--title "<title>"] [--condition "<expr>"] [--message "<text>"] [--enabled true|false] [--cooldown 15m] [--execution-mode same-thread|side-thread] [--json]',
|
|
444
|
+
' lac monitor del <monitor-id> [--json]',
|
|
445
|
+
' lac monitor run <monitor-id> [--json]',
|
|
297
446
|
' lac channel send-file --path "<file>" [--target <chat-or-user-id>] [--workspace <id>] [--workspace-path <path>] [--platform lark] [--name <filename>] [--json]',
|
|
298
447
|
].join('\n') + '\n');
|
|
299
448
|
}
|
|
@@ -321,6 +470,53 @@ function presentJob(job) {
|
|
|
321
470
|
id: (0, job_id_js_1.toPublicScheduledJobId)(job.id),
|
|
322
471
|
};
|
|
323
472
|
}
|
|
473
|
+
function formatMonitorLine(monitor) {
|
|
474
|
+
return `${(0, monitor_id_js_1.toPublicAutomationMonitorId)(monitor.id)} | ${monitor.enabled ? 'enabled' : 'disabled'} | ${monitor.executionMode} | ${monitor.sourceType} | ${formatCondition(monitor.condition)} | ${monitor.title}`;
|
|
475
|
+
}
|
|
476
|
+
function formatMonitorDetails(monitor, latestRun) {
|
|
477
|
+
return [
|
|
478
|
+
`Monitor: ${(0, monitor_id_js_1.toPublicAutomationMonitorId)(monitor.id)}`,
|
|
479
|
+
`Title: ${monitor.title}`,
|
|
480
|
+
`Workspace: ${monitor.workspaceId}`,
|
|
481
|
+
`Platform: ${monitor.platform}`,
|
|
482
|
+
`Thread: ${monitor.route.threadId || ''}`,
|
|
483
|
+
`Execution mode: ${monitor.executionMode}`,
|
|
484
|
+
`Source: ${monitor.sourceType}`,
|
|
485
|
+
`Condition: ${formatCondition(monitor.condition)}`,
|
|
486
|
+
`Cooldown: ${monitor.cooldownMs}ms`,
|
|
487
|
+
`Enabled: ${monitor.enabled ? 'true' : 'false'}`,
|
|
488
|
+
`Message: ${monitor.promptTemplate}`,
|
|
489
|
+
latestRun ? `Latest run: ${latestRun.status} @ ${latestRun.triggeredAt}` : 'Latest run: none',
|
|
490
|
+
].join('\n');
|
|
491
|
+
}
|
|
492
|
+
function formatCondition(condition) {
|
|
493
|
+
if (condition.expression) {
|
|
494
|
+
return condition.expression;
|
|
495
|
+
}
|
|
496
|
+
return `${condition.metric} ${condition.operator} ${condition.value}`;
|
|
497
|
+
}
|
|
498
|
+
function presentMonitor(monitor) {
|
|
499
|
+
return {
|
|
500
|
+
...monitor,
|
|
501
|
+
id: (0, monitor_id_js_1.toPublicAutomationMonitorId)(monitor.id),
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
function monitorMatchesCliContext(monitor, context) {
|
|
505
|
+
return (0, scheduled_job_route_js_1.scheduledJobMatchesCliContext)({
|
|
506
|
+
id: monitor.id,
|
|
507
|
+
workspaceId: monitor.workspaceId,
|
|
508
|
+
platform: monitor.platform,
|
|
509
|
+
route: monitor.route,
|
|
510
|
+
executionMode: monitor.executionMode,
|
|
511
|
+
triggerType: 'once',
|
|
512
|
+
promptTemplate: monitor.promptTemplate,
|
|
513
|
+
description: monitor.title,
|
|
514
|
+
enabled: monitor.enabled,
|
|
515
|
+
concurrencyPolicy: monitor.concurrencyPolicy,
|
|
516
|
+
createdAt: monitor.createdAt,
|
|
517
|
+
updatedAt: monitor.updatedAt,
|
|
518
|
+
}, context);
|
|
519
|
+
}
|
|
324
520
|
function formatError(error) {
|
|
325
521
|
return error instanceof Error ? error.message : String(error);
|
|
326
522
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseMonitorCondition = parseMonitorCondition;
|
|
4
|
+
exports.parseDurationMs = parseDurationMs;
|
|
5
|
+
const index_js_1 = require("../../../../packages/contracts/src/index.js");
|
|
6
|
+
function parseMonitorCondition(value) {
|
|
7
|
+
const expression = String(value || '').trim();
|
|
8
|
+
if (expression.includes('&&') || expression.includes('||')) {
|
|
9
|
+
return {
|
|
10
|
+
metric: 'expression',
|
|
11
|
+
operator: '==',
|
|
12
|
+
value: true,
|
|
13
|
+
expression,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
const match = expression.match(/^([a-zA-Z0-9_.-]+)\s*(>=|<=|==|!=|>|<)\s*(.+)$/);
|
|
17
|
+
if (!match) {
|
|
18
|
+
throw new Error('Monitor condition must look like "change_percent >= 3".');
|
|
19
|
+
}
|
|
20
|
+
const rawValue = String(match[3] || '').trim();
|
|
21
|
+
const numeric = Number(rawValue);
|
|
22
|
+
return {
|
|
23
|
+
metric: String(match[1] || '').trim(),
|
|
24
|
+
operator: (0, index_js_1.normalizeAutomationMonitorConditionOperator)(match[2]),
|
|
25
|
+
value: Number.isFinite(numeric) && rawValue !== '' ? numeric : rawValue,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function parseDurationMs(value) {
|
|
29
|
+
const match = String(value || '').trim().match(/^(\d+(?:\.\d+)?)(ms|s|m|h)?$/i);
|
|
30
|
+
if (!match) {
|
|
31
|
+
throw new Error('Duration must be a number with optional ms, s, m, or h suffix.');
|
|
32
|
+
}
|
|
33
|
+
const amount = Number(match[1]);
|
|
34
|
+
const unit = String(match[2] || 'ms').toLowerCase();
|
|
35
|
+
const multiplier = unit === 'h' ? 60 * 60 * 1000 : unit === 'm' ? 60 * 1000 : unit === 's' ? 1000 : 1;
|
|
36
|
+
return Math.round(amount * multiplier);
|
|
37
|
+
}
|
|
@@ -17,10 +17,12 @@ const scheduler_cron_plugin_js_1 = require("../plugins/builtin/scheduler-cron-pl
|
|
|
17
17
|
const scheduler_lark_plugin_js_1 = require("../plugins/builtin/scheduler-lark-plugin.js");
|
|
18
18
|
const scheduler_local_plugin_js_1 = require("../plugins/builtin/scheduler-local-plugin.js");
|
|
19
19
|
const scheduler_weixin_plugin_js_1 = require("../plugins/builtin/scheduler-weixin-plugin.js");
|
|
20
|
+
const monitor_stock_plugin_js_1 = require("../plugins/builtin/monitor-stock-plugin.js");
|
|
20
21
|
const workspace_router_js_1 = require("../router/workspace-router.js");
|
|
21
22
|
const local_core_runtime_state_js_1 = require("../runtime/local-core-runtime-state.js");
|
|
22
23
|
const scheduled_job_application_service_js_1 = require("../scheduler/scheduled-job-application-service.js");
|
|
23
24
|
const scheduler_service_js_1 = require("../scheduler/scheduler-service.js");
|
|
25
|
+
const automation_monitor_service_js_1 = require("../automation/automation-monitor-service.js");
|
|
24
26
|
function bootstrapLocalCoreKernel(options) {
|
|
25
27
|
const capabilities = new capability_registry_js_1.LocalCoreCapabilityRegistry();
|
|
26
28
|
const plugins = new plugin_registry_js_1.LocalCorePluginRegistry(options?.disabledPluginIds);
|
|
@@ -59,6 +61,7 @@ function bootstrapLocalCoreKernel(options) {
|
|
|
59
61
|
diagnostics,
|
|
60
62
|
getCapabilitySnapshot() {
|
|
61
63
|
const snapshot = capabilities.snapshot();
|
|
64
|
+
const monitorCapabilities = snapshot.monitors || [];
|
|
62
65
|
return {
|
|
63
66
|
adapters: {
|
|
64
67
|
channels: snapshot.channels.map((capability) => capability.platform),
|
|
@@ -74,6 +77,14 @@ function bootstrapLocalCoreKernel(options) {
|
|
|
74
77
|
deliveryTargets: [...new Set(snapshot.schedulers.flatMap((capability) => capability.deliveryTargets || capability.deliveryPlatforms || []))],
|
|
75
78
|
platforms: [...new Set(snapshot.schedulers.flatMap((capability) => capability.deliveryTargets || capability.deliveryPlatforms || []))],
|
|
76
79
|
},
|
|
80
|
+
...(monitorCapabilities.length > 0
|
|
81
|
+
? {
|
|
82
|
+
monitors: {
|
|
83
|
+
enabled: monitorCapabilities.some((capability) => capability.enabled !== false),
|
|
84
|
+
sourceTypes: [...new Set(monitorCapabilities.flatMap((capability) => capability.sourceTypes))],
|
|
85
|
+
},
|
|
86
|
+
}
|
|
87
|
+
: {}),
|
|
77
88
|
snapshot,
|
|
78
89
|
};
|
|
79
90
|
},
|
|
@@ -99,6 +110,7 @@ function logCapabilityContributions(plugin, log) {
|
|
|
99
110
|
...(plugin.capabilities.channels || []).map((capability) => capability.id),
|
|
100
111
|
...(plugin.capabilities.knowledge || []).map((capability) => capability.id),
|
|
101
112
|
...(plugin.capabilities.schedulers || []).map((capability) => capability.id),
|
|
113
|
+
...(plugin.capabilities.monitors || []).map((capability) => capability.id),
|
|
102
114
|
...(plugin.capabilities.ui || []).map((capability) => capability.id),
|
|
103
115
|
];
|
|
104
116
|
for (const capabilityId of capabilityIds) {
|
|
@@ -145,6 +157,16 @@ function resolveSchedulerRuntime(plugin, context) {
|
|
|
145
157
|
}
|
|
146
158
|
return runtime;
|
|
147
159
|
}
|
|
160
|
+
function resolveMonitorRuntime(plugin, context) {
|
|
161
|
+
if (!plugin.createRuntime) {
|
|
162
|
+
throw new Error(`Monitor plugin ${plugin.manifest.id} does not provide a runtime factory.`);
|
|
163
|
+
}
|
|
164
|
+
const runtime = plugin.createRuntime(context);
|
|
165
|
+
if (runtime instanceof Promise) {
|
|
166
|
+
throw new Error(`Monitor plugin ${plugin.manifest.id} returned an async runtime factory during synchronous bootstrap.`);
|
|
167
|
+
}
|
|
168
|
+
return runtime;
|
|
169
|
+
}
|
|
148
170
|
function bootstrapLocalCoreRuntime(options) {
|
|
149
171
|
const state = (0, local_core_runtime_state_js_1.createLocalCoreRuntimeState)({
|
|
150
172
|
userDataPath: options.userDataPath,
|
|
@@ -209,6 +231,9 @@ function bootstrapLocalCoreRuntime(options) {
|
|
|
209
231
|
log: options.log,
|
|
210
232
|
}),
|
|
211
233
|
];
|
|
234
|
+
const monitorPlugins = [
|
|
235
|
+
(0, monitor_stock_plugin_js_1.createBuiltinStockMonitorPlugin)(),
|
|
236
|
+
];
|
|
212
237
|
for (const plugin of agentPlugins.filter((plugin) => plugin !== localCoreAgentPlugin)) {
|
|
213
238
|
registerPlugin(kernel, plugin);
|
|
214
239
|
}
|
|
@@ -218,6 +243,9 @@ function bootstrapLocalCoreRuntime(options) {
|
|
|
218
243
|
for (const plugin of schedulerPlugins) {
|
|
219
244
|
registerPlugin(kernel, plugin);
|
|
220
245
|
}
|
|
246
|
+
for (const plugin of monitorPlugins) {
|
|
247
|
+
registerPlugin(kernel, plugin);
|
|
248
|
+
}
|
|
221
249
|
const agentRuntimes = agentPlugins
|
|
222
250
|
.filter((plugin) => kernel.plugins.isEnabled(plugin.manifest.id))
|
|
223
251
|
.map((plugin) => resolveAgentRuntime(plugin, kernel.context).runtime);
|
|
@@ -241,6 +269,10 @@ function bootstrapLocalCoreRuntime(options) {
|
|
|
241
269
|
];
|
|
242
270
|
const schedulerTriggers = schedulerRuntimes.flatMap((runtime) => runtime.triggers || []);
|
|
243
271
|
const schedulerExecutors = schedulerRuntimes.flatMap((runtime) => runtime.executors || []);
|
|
272
|
+
const monitorRuntimes = monitorPlugins
|
|
273
|
+
.filter((plugin) => kernel.plugins.isEnabled(plugin.manifest.id))
|
|
274
|
+
.map((plugin) => resolveMonitorRuntime(plugin, kernel.context));
|
|
275
|
+
const monitorProviders = monitorRuntimes.flatMap((runtime) => runtime.providers || []);
|
|
244
276
|
const knowledgeProvider = knowledgeRuntime.provider;
|
|
245
277
|
const knowledgeAttachments = knowledgeRuntime.attachments;
|
|
246
278
|
workspaceRouter = (0, workspace_router_js_1.createWorkspaceRouter)({
|
|
@@ -266,6 +298,14 @@ function bootstrapLocalCoreRuntime(options) {
|
|
|
266
298
|
store,
|
|
267
299
|
scheduler,
|
|
268
300
|
});
|
|
301
|
+
const automationMonitors = new automation_monitor_service_js_1.AutomationMonitorService({
|
|
302
|
+
store,
|
|
303
|
+
providers: monitorProviders,
|
|
304
|
+
getWorkspaceRouter: () => workspaceRouter,
|
|
305
|
+
getChannelRuntime: (platform) => channelRuntimes.find((runtime) => runtime.platform === platform || platform.startsWith(`${runtime.platform}:`)),
|
|
306
|
+
eventBus: kernel.context.bus,
|
|
307
|
+
log: options.log,
|
|
308
|
+
});
|
|
269
309
|
workspaceRouter.setSchedulerBridge({
|
|
270
310
|
createJob: async ({ workspaceId, platform, route, name, schedule, scheduleDescription, message }) => scheduledJobs.createCronJob({ workspaceId, platform, route, name, schedule, scheduleDescription, message }),
|
|
271
311
|
listJobsForThread: async (threadId) => scheduledJobs.listJobsForThread(threadId),
|
|
@@ -286,11 +326,14 @@ function bootstrapLocalCoreRuntime(options) {
|
|
|
286
326
|
workspaceRouter,
|
|
287
327
|
scheduler,
|
|
288
328
|
scheduledJobs,
|
|
329
|
+
automationMonitors,
|
|
289
330
|
async start() {
|
|
290
331
|
await kernel.lifecycle.startAll();
|
|
291
332
|
await scheduler.start();
|
|
333
|
+
await automationMonitors.start();
|
|
292
334
|
},
|
|
293
335
|
async stop() {
|
|
336
|
+
await automationMonitors.stop();
|
|
294
337
|
await scheduler.stop();
|
|
295
338
|
await kernel.lifecycle.stopAll();
|
|
296
339
|
workspaceRouter.close();
|
|
@@ -6,6 +6,7 @@ class LocalCoreCapabilityRegistry {
|
|
|
6
6
|
channels = new Map();
|
|
7
7
|
knowledge = new Map();
|
|
8
8
|
schedulers = new Map();
|
|
9
|
+
monitors = new Map();
|
|
9
10
|
ui = new Map();
|
|
10
11
|
registerAgent(capability) {
|
|
11
12
|
this.agents.set(capability.id, capability);
|
|
@@ -19,6 +20,9 @@ class LocalCoreCapabilityRegistry {
|
|
|
19
20
|
registerScheduler(capability) {
|
|
20
21
|
this.schedulers.set(capability.id, capability);
|
|
21
22
|
}
|
|
23
|
+
registerMonitor(capability) {
|
|
24
|
+
this.monitors.set(capability.id, capability);
|
|
25
|
+
}
|
|
22
26
|
registerUi(capability) {
|
|
23
27
|
this.ui.set(capability.id, capability);
|
|
24
28
|
}
|
|
@@ -35,6 +39,9 @@ class LocalCoreCapabilityRegistry {
|
|
|
35
39
|
for (const capability of contributions.schedulers || []) {
|
|
36
40
|
this.registerScheduler(capability);
|
|
37
41
|
}
|
|
42
|
+
for (const capability of contributions.monitors || []) {
|
|
43
|
+
this.registerMonitor(capability);
|
|
44
|
+
}
|
|
38
45
|
for (const capability of contributions.ui || []) {
|
|
39
46
|
this.registerUi(capability);
|
|
40
47
|
}
|
|
@@ -51,15 +58,20 @@ class LocalCoreCapabilityRegistry {
|
|
|
51
58
|
listSchedulers() {
|
|
52
59
|
return [...this.schedulers.values()];
|
|
53
60
|
}
|
|
61
|
+
listMonitors() {
|
|
62
|
+
return [...this.monitors.values()];
|
|
63
|
+
}
|
|
54
64
|
listUi() {
|
|
55
65
|
return [...this.ui.values()];
|
|
56
66
|
}
|
|
57
67
|
snapshot() {
|
|
68
|
+
const monitors = this.listMonitors();
|
|
58
69
|
return {
|
|
59
70
|
agents: this.listAgents(),
|
|
60
71
|
channels: this.listChannels(),
|
|
61
72
|
knowledge: this.listKnowledge(),
|
|
62
73
|
schedulers: this.listSchedulers(),
|
|
74
|
+
...(monitors.length > 0 ? { monitors } : {}),
|
|
63
75
|
ui: this.listUi(),
|
|
64
76
|
};
|
|
65
77
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createBuiltinStockMonitorPlugin = createBuiltinStockMonitorPlugin;
|
|
4
|
+
const mock_stock_provider_js_1 = require("../../automation/mock-stock-provider.js");
|
|
5
|
+
function createBuiltinStockMonitorPlugin() {
|
|
6
|
+
return {
|
|
7
|
+
manifest: {
|
|
8
|
+
id: 'builtin.monitor-stock',
|
|
9
|
+
kind: 'monitor',
|
|
10
|
+
version: '0.1.0',
|
|
11
|
+
provides: ['monitor.source.stock.quote'],
|
|
12
|
+
},
|
|
13
|
+
capabilities: {
|
|
14
|
+
monitors: [
|
|
15
|
+
{
|
|
16
|
+
id: 'monitor.source.stock.quote',
|
|
17
|
+
sourceTypes: ['stock.quote'],
|
|
18
|
+
modes: ['poll'],
|
|
19
|
+
enabled: true,
|
|
20
|
+
displayName: 'Stock Quote Monitor',
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
},
|
|
24
|
+
createRuntime() {
|
|
25
|
+
return {
|
|
26
|
+
providers: [new mock_stock_provider_js_1.MockStockQuoteProvider()],
|
|
27
|
+
};
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
}
|