@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.
- package/README.md +10 -0
- package/dist/renderer/assets/{Badge-BX3RC8l6.js → Badge-CbG6yRSm.js} +1 -1
- package/dist/renderer/assets/{Chat-DJwIciel.js → Chat-BvNNWGGX.js} +1 -1
- package/dist/renderer/assets/{ChatMarkdown-DfGbRR0S.js → ChatMarkdown-Ct-PvJB8.js} +1 -1
- package/dist/renderer/assets/{Config-2x2RDL3j.js → Config-lQX2qVVV.js} +2 -2
- package/dist/renderer/assets/CronList-Dj_3muVG.js +1 -0
- package/dist/renderer/assets/{Dashboard-2Wcx_bvJ.js → Dashboard-eh_RhGYb.js} +2 -2
- package/dist/renderer/assets/{EmptyState-DoCpF2tn.js → EmptyState-Bn2Qh14U.js} +1 -1
- package/dist/renderer/assets/{KnowledgeDetail-CBRu2bXX.js → KnowledgeDetail-Bsz6Ou41.js} +2 -2
- package/dist/renderer/assets/{KnowledgeHome-CItdlDVR.js → KnowledgeHome-Cgj4XFXn.js} +2 -2
- package/dist/renderer/assets/{Logs-Cd_7ZOXc.js → Logs-Dp-NF6GN.js} +1 -1
- package/dist/renderer/assets/{Modal-B4eOiBsB.js → Modal-B6YPPBN6.js} +1 -1
- package/dist/renderer/assets/MonitorList-xEZWg460.js +1 -0
- package/dist/renderer/assets/{Page-C5VH4D9U.js → Page-Bn7RjGOS.js} +1 -1
- package/dist/renderer/assets/{ProjectDetail-D_DA--IP.js → ProjectDetail-Cv_jIE61.js} +2 -2
- package/dist/renderer/assets/{ProjectList-CtCXJ50u.js → ProjectList-BDk5_gqY.js} +1 -1
- package/dist/renderer/assets/{Select-B6E68LcN.js → Select-xshfMIEQ.js} +1 -1
- package/dist/renderer/assets/SessionChat-BkHy90z3.js +1 -0
- package/dist/renderer/assets/{SessionList-Do-5-Xx6.js → SessionList-BZyXT92L.js} +1 -1
- package/dist/renderer/assets/{ThreadChat-B1tEtE3V.js → ThreadChat-DUOIyXrS.js} +7 -7
- package/dist/renderer/assets/{Workspace-BlhS2RFw.js → Workspace-Dl80fNEC.js} +1 -1
- package/dist/renderer/assets/{arrow-left-DF1_F9Pk.js → arrow-left-C54ZI-AS.js} +1 -1
- package/dist/renderer/assets/{book-open-DxRTGpWO.js → book-open-Dl7GO0zn.js} +1 -1
- package/dist/renderer/assets/{check-BAqPPYkf.js → check-CiqgtrOL.js} +1 -1
- package/dist/renderer/assets/{chevron-down-DIZZgSb3.js → chevron-down-DTL2OuVh.js} +1 -1
- package/dist/renderer/assets/{circle-B5raL_XK.js → circle-DaVKfa3P.js} +1 -1
- package/dist/renderer/assets/desktop-C6q6wBae.js +5 -0
- package/dist/renderer/assets/desktop-jaAiayNB.js +1 -0
- package/dist/renderer/assets/en-D2SkCrhG.js +1 -0
- package/dist/renderer/assets/{funnel-BPjLpVSB.js → funnel-CrmnLMJI.js} +1 -1
- package/dist/renderer/assets/{heart-D2M1xN1N.js → heart-BMfQI7y_.js} +1 -1
- package/dist/renderer/assets/{index-Cx71F_Lz.js → index-HPNb1zfx.js} +39 -34
- package/dist/renderer/assets/{index-BijJAYmo.js → index-nreiKY1f.js} +3 -3
- package/dist/renderer/assets/{pencil-DlDr8Mmp.js → pencil-wTQ4l465.js} +1 -1
- package/dist/renderer/assets/{play-BOEG_mY8.js → play-BK--MXmw.js} +1 -1
- package/dist/renderer/assets/{plug-BI27elC-.js → plug-BIx9fjip.js} +1 -1
- package/dist/renderer/assets/{plus-BhURuFIQ.js → plus-Dn7JFWQ8.js} +1 -1
- package/dist/renderer/assets/projects-brJZgwEJ.js +1 -0
- package/dist/renderer/assets/{save-RwkHNm9e.js → save-CC3zOSWb.js} +1 -1
- package/dist/renderer/assets/{search-DMNtm2WP.js → search-CDTy9Czu.js} +1 -1
- package/dist/renderer/assets/{server-CNaxKyAq.js → server-DtQk3t2a.js} +1 -1
- package/dist/renderer/assets/{session-utils-vsALZkZN.js → session-utils-4ep5D66T.js} +1 -1
- package/dist/renderer/assets/{sessions-BY-R1IL_.js → sessions-Dor1LteH.js} +1 -1
- package/dist/renderer/assets/{shield-check-BF-4oJbj.js → shield-check-Cz2LpU6r.js} +1 -1
- package/dist/renderer/assets/{trash-2-DduflM4q.js → trash-2-C2EmWFZV.js} +1 -1
- package/dist/renderer/assets/{user-DBcvnuW4.js → user-I8B-cs5A.js} +1 -1
- package/dist/renderer/assets/{wifi-off-X1nXESYu.js → wifi-off-CPevTQJn.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 +76 -39
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-session-coordinator.js +13 -0
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-store.js +4 -1357
- package/dist-electron/services/local-ai-core/src/acp/local-core-slash-commands.js +28 -0
- 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/local-core-lark-gateway.js +101 -29
- 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/weixin/local-core-weixin-gateway.js +51 -33
- 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/router/workspace-router.js +40 -4
- 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 +134 -0
- 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/electron/plugin-kernel.test.js +26 -0
- package/dist-electron/tests/integration/local-core-refactor.test.js +359 -0
- package/package.json +1 -1
- package/dist/renderer/assets/CronList-C6nPAmEo.js +0 -1
- package/dist/renderer/assets/SessionChat-D1HtMdQS.js +0 -1
- package/dist/renderer/assets/desktop-CFcnzwcY.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-DpR972HM.js +0 -1
- package/dist/renderer/assets/zh-Dz5FLTBV.js +0 -1
|
@@ -5,7 +5,17 @@ exports.parseSlashCommand = parseSlashCommand;
|
|
|
5
5
|
exports.normalizeAgentMode = normalizeAgentMode;
|
|
6
6
|
exports.formatAgentMode = formatAgentMode;
|
|
7
7
|
exports.modeHelpText = modeHelpText;
|
|
8
|
+
exports.normalizeAgentCommandTarget = normalizeAgentCommandTarget;
|
|
9
|
+
exports.formatAgentList = formatAgentList;
|
|
10
|
+
exports.agentHelpText = agentHelpText;
|
|
8
11
|
exports.DEFAULT_AGENT_MODE = 'default';
|
|
12
|
+
const AGENT_ALIASES = {
|
|
13
|
+
claude: 'claudecode',
|
|
14
|
+
'claude-code': 'claudecode',
|
|
15
|
+
claude_code: 'claudecode',
|
|
16
|
+
claudecode: 'claudecode',
|
|
17
|
+
cc: 'claudecode',
|
|
18
|
+
};
|
|
9
19
|
const MODE_ALIASES = {
|
|
10
20
|
auto: 'auto',
|
|
11
21
|
default: 'default',
|
|
@@ -58,3 +68,21 @@ function modeHelpText(currentMode) {
|
|
|
58
68
|
'`/mode yolo` 会跳过工具权限申请;使用 `/mode default` 可恢复默认权限。'
|
|
59
69
|
].join('\n');
|
|
60
70
|
}
|
|
71
|
+
function normalizeAgentCommandTarget(agent) {
|
|
72
|
+
const key = String(agent || '').trim().toLowerCase();
|
|
73
|
+
return AGENT_ALIASES[key] || key;
|
|
74
|
+
}
|
|
75
|
+
function formatAgentList(agents) {
|
|
76
|
+
return [...new Set(agents.map(normalizeAgentCommandTarget).filter(Boolean))].sort();
|
|
77
|
+
}
|
|
78
|
+
function agentHelpText(input) {
|
|
79
|
+
const currentAgent = normalizeAgentCommandTarget(input.currentAgent) || 'unknown';
|
|
80
|
+
const defaultAgent = normalizeAgentCommandTarget(input.defaultAgent) || 'unknown';
|
|
81
|
+
const availableAgents = formatAgentList(input.availableAgents);
|
|
82
|
+
return [
|
|
83
|
+
`当前线程 Agent:${currentAgent}`,
|
|
84
|
+
`默认 Agent:${defaultAgent}`,
|
|
85
|
+
`可用 Agent:${availableAgents.length ? availableAgents.join(', ') : '无'}`,
|
|
86
|
+
'可用命令:`/agent list`、`/agent current`、`/agent use <agent-id>`、`/agent reset`。',
|
|
87
|
+
].join('\n');
|
|
88
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LocalAgentTaskStore = void 0;
|
|
4
|
+
const node_crypto_1 = require("node:crypto");
|
|
5
|
+
const index_js_1 = require("../../../../../packages/contracts/src/index.js");
|
|
6
|
+
const utils_js_1 = require("./utils.js");
|
|
7
|
+
class LocalAgentTaskStore {
|
|
8
|
+
db;
|
|
9
|
+
createAuditEvent;
|
|
10
|
+
constructor(db, createAuditEvent) {
|
|
11
|
+
this.db = db;
|
|
12
|
+
this.createAuditEvent = createAuditEvent;
|
|
13
|
+
}
|
|
14
|
+
create(input) {
|
|
15
|
+
const id = `task:${(0, node_crypto_1.randomUUID)()}`;
|
|
16
|
+
const now = new Date().toISOString();
|
|
17
|
+
const status = (0, index_js_1.normalizeAgentTaskStatus)(input.status);
|
|
18
|
+
const timeline = [{
|
|
19
|
+
id: `timeline:${(0, node_crypto_1.randomUUID)()}`,
|
|
20
|
+
type: 'status_change',
|
|
21
|
+
title: `Task ${status}`,
|
|
22
|
+
status,
|
|
23
|
+
timestamp: now,
|
|
24
|
+
}];
|
|
25
|
+
this.db.prepare(`
|
|
26
|
+
INSERT INTO agent_tasks (
|
|
27
|
+
id, workspace_id, device_id, runtime_id, thread_id, run_id, title, prompt, status, created_at, updated_at, queued_at,
|
|
28
|
+
started_at, completed_at, summary, error, timeline_json, logs_json, artifacts_json, approval_ids_json, metadata_json
|
|
29
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, NULL, NULL, ?, '[]', '[]', '[]', ?)
|
|
30
|
+
`).run(id, input.workspaceId, input.deviceId, input.runtimeId, input.threadId || null, input.runId || null, input.title, input.prompt ? (0, utils_js_1.redactSecrets)(input.prompt) : null, status, now, now, status === 'queued' ? now : null, status === 'running' ? now : null, JSON.stringify(timeline), JSON.stringify(input.metadata || {}));
|
|
31
|
+
const task = this.get(id);
|
|
32
|
+
this.createAuditEvent({
|
|
33
|
+
type: 'task.created',
|
|
34
|
+
workspaceId: task.workspaceId,
|
|
35
|
+
taskId: task.taskId,
|
|
36
|
+
actor: 'local',
|
|
37
|
+
summary: `Task created: ${task.title}`,
|
|
38
|
+
metadata: { runtimeId: task.runtimeId, threadId: task.threadId, runId: task.runId },
|
|
39
|
+
});
|
|
40
|
+
return task;
|
|
41
|
+
}
|
|
42
|
+
list(query = {}) {
|
|
43
|
+
const predicates = [];
|
|
44
|
+
const params = [];
|
|
45
|
+
if (query.workspaceId) {
|
|
46
|
+
predicates.push('workspace_id = ?');
|
|
47
|
+
params.push(query.workspaceId);
|
|
48
|
+
}
|
|
49
|
+
if (query.runtimeId) {
|
|
50
|
+
predicates.push('runtime_id = ?');
|
|
51
|
+
params.push(query.runtimeId);
|
|
52
|
+
}
|
|
53
|
+
if (query.status) {
|
|
54
|
+
const statuses = (Array.isArray(query.status) ? query.status : [query.status]).map((status) => (0, index_js_1.normalizeAgentTaskStatus)(status));
|
|
55
|
+
predicates.push(`status IN (${statuses.map(() => '?').join(', ')})`);
|
|
56
|
+
params.push(...statuses);
|
|
57
|
+
}
|
|
58
|
+
const limit = Math.max(1, Math.min(Number(query.limit || 50), 100));
|
|
59
|
+
const where = predicates.length ? `WHERE ${predicates.join(' AND ')}` : '';
|
|
60
|
+
const rows = this.db.prepare(`
|
|
61
|
+
SELECT *
|
|
62
|
+
FROM agent_tasks
|
|
63
|
+
${where}
|
|
64
|
+
ORDER BY updated_at DESC
|
|
65
|
+
LIMIT ?
|
|
66
|
+
`).all(...params, limit);
|
|
67
|
+
return { tasks: rows.map((row) => this.toAgentTask(row)) };
|
|
68
|
+
}
|
|
69
|
+
get(taskId) {
|
|
70
|
+
const row = this.db.prepare('SELECT * FROM agent_tasks WHERE id = ?').get(taskId);
|
|
71
|
+
return row ? this.toAgentTask(row) : undefined;
|
|
72
|
+
}
|
|
73
|
+
getByRunId(runId) {
|
|
74
|
+
const row = this.db.prepare('SELECT * FROM agent_tasks WHERE run_id = ? ORDER BY updated_at DESC LIMIT 1').get(runId);
|
|
75
|
+
return row ? this.toAgentTask(row) : undefined;
|
|
76
|
+
}
|
|
77
|
+
update(taskId, input) {
|
|
78
|
+
const existing = this.get(taskId);
|
|
79
|
+
if (!existing) {
|
|
80
|
+
throw new Error(`Task not found: ${taskId}`);
|
|
81
|
+
}
|
|
82
|
+
const now = new Date().toISOString();
|
|
83
|
+
const nextStatus = input.status ? (0, index_js_1.normalizeAgentTaskStatus)(input.status) : existing.status;
|
|
84
|
+
const timeline = [...existing.timeline];
|
|
85
|
+
const logs = [...existing.logs];
|
|
86
|
+
const artifacts = [...existing.artifacts];
|
|
87
|
+
const approvalIds = [...existing.approvalIds];
|
|
88
|
+
if (input.status && nextStatus !== existing.status) {
|
|
89
|
+
timeline.push({
|
|
90
|
+
id: `timeline:${(0, node_crypto_1.randomUUID)()}`,
|
|
91
|
+
type: 'status_change',
|
|
92
|
+
title: `Task ${nextStatus}`,
|
|
93
|
+
status: nextStatus,
|
|
94
|
+
timestamp: now,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
if (input.timelineItem) {
|
|
98
|
+
timeline.push({
|
|
99
|
+
id: input.timelineItem.id || `timeline:${(0, node_crypto_1.randomUUID)()}`,
|
|
100
|
+
timestamp: input.timelineItem.timestamp || now,
|
|
101
|
+
...input.timelineItem,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
if (input.log) {
|
|
105
|
+
logs.push({
|
|
106
|
+
id: input.log.id || `log:${(0, node_crypto_1.randomUUID)()}`,
|
|
107
|
+
timestamp: input.log.timestamp || now,
|
|
108
|
+
...input.log,
|
|
109
|
+
message: (0, utils_js_1.redactSecrets)(input.log.message),
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
if (input.artifact) {
|
|
113
|
+
artifacts.push({
|
|
114
|
+
id: input.artifact.id || `artifact:${(0, node_crypto_1.randomUUID)()}`,
|
|
115
|
+
...input.artifact,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
if (input.approvalId && !approvalIds.includes(input.approvalId)) {
|
|
119
|
+
approvalIds.push(input.approvalId);
|
|
120
|
+
}
|
|
121
|
+
this.db.prepare(`
|
|
122
|
+
UPDATE agent_tasks
|
|
123
|
+
SET status = ?, thread_id = ?, run_id = ?, title = ?, updated_at = ?, queued_at = ?, started_at = ?, completed_at = ?,
|
|
124
|
+
summary = ?, error = ?, timeline_json = ?, logs_json = ?, artifacts_json = ?, approval_ids_json = ?, metadata_json = ?
|
|
125
|
+
WHERE id = ?
|
|
126
|
+
`).run(nextStatus, input.threadId || existing.threadId || null, input.runId || existing.runId || null, input.title || existing.title, now, existing.queuedAt || (nextStatus === 'queued' ? now : null), existing.startedAt || (nextStatus === 'running' ? now : null), existing.completedAt || (['completed', 'failed', 'cancelled'].includes(nextStatus) ? now : null), input.summary ?? existing.summary ?? null, input.error === null ? null : input.error ?? existing.error ?? null, JSON.stringify(timeline), JSON.stringify(logs), JSON.stringify(artifacts), JSON.stringify(approvalIds), JSON.stringify(input.metadata || existing.metadata || {}), taskId);
|
|
127
|
+
const task = this.get(taskId);
|
|
128
|
+
if (input.status && nextStatus !== existing.status) {
|
|
129
|
+
this.createAuditEvent({
|
|
130
|
+
type: 'task.updated',
|
|
131
|
+
workspaceId: task.workspaceId,
|
|
132
|
+
taskId: task.taskId,
|
|
133
|
+
actor: 'local',
|
|
134
|
+
summary: `Task status changed to ${nextStatus}.`,
|
|
135
|
+
metadata: { previousStatus: existing.status, status: nextStatus, runId: task.runId },
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
return task;
|
|
139
|
+
}
|
|
140
|
+
toAgentTask(row) {
|
|
141
|
+
return {
|
|
142
|
+
taskId: row.id,
|
|
143
|
+
workspaceId: row.workspace_id,
|
|
144
|
+
deviceId: row.device_id,
|
|
145
|
+
runtimeId: row.runtime_id,
|
|
146
|
+
threadId: row.thread_id || undefined,
|
|
147
|
+
runId: row.run_id || undefined,
|
|
148
|
+
title: row.title,
|
|
149
|
+
prompt: row.prompt || undefined,
|
|
150
|
+
status: (0, index_js_1.normalizeAgentTaskStatus)(row.status),
|
|
151
|
+
createdAt: row.created_at,
|
|
152
|
+
updatedAt: row.updated_at,
|
|
153
|
+
queuedAt: row.queued_at || undefined,
|
|
154
|
+
startedAt: row.started_at || undefined,
|
|
155
|
+
completedAt: row.completed_at || undefined,
|
|
156
|
+
summary: row.summary || undefined,
|
|
157
|
+
error: row.error || undefined,
|
|
158
|
+
timeline: (0, utils_js_1.parseJson)(row.timeline_json, []),
|
|
159
|
+
logs: (0, utils_js_1.parseJson)(row.logs_json, []),
|
|
160
|
+
artifacts: (0, utils_js_1.parseJson)(row.artifacts_json, []),
|
|
161
|
+
approvalIds: (0, utils_js_1.parseJson)(row.approval_ids_json, []),
|
|
162
|
+
metadata: (0, utils_js_1.parseJson)(row.metadata_json, {}),
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
exports.LocalAgentTaskStore = LocalAgentTaskStore;
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LocalAutomationMonitorStore = void 0;
|
|
4
|
+
const node_crypto_1 = require("node:crypto");
|
|
5
|
+
const index_js_1 = require("../../../../../packages/contracts/src/index.js");
|
|
6
|
+
class LocalAutomationMonitorStore {
|
|
7
|
+
db;
|
|
8
|
+
constructor(db) {
|
|
9
|
+
this.db = db;
|
|
10
|
+
}
|
|
11
|
+
list(workspaceId) {
|
|
12
|
+
const query = workspaceId
|
|
13
|
+
? `
|
|
14
|
+
SELECT id, workspace_id, title, source_type, source_config_json, condition_json, prompt_template, platform, route_type, route_config,
|
|
15
|
+
execution_mode, enabled, cooldown_ms, concurrency_policy, last_state_json, created_at, updated_at, last_triggered_at, last_status, last_error
|
|
16
|
+
FROM automation_monitors
|
|
17
|
+
WHERE workspace_id = ?
|
|
18
|
+
ORDER BY updated_at DESC
|
|
19
|
+
`
|
|
20
|
+
: `
|
|
21
|
+
SELECT id, workspace_id, title, source_type, source_config_json, condition_json, prompt_template, platform, route_type, route_config,
|
|
22
|
+
execution_mode, enabled, cooldown_ms, concurrency_policy, last_state_json, created_at, updated_at, last_triggered_at, last_status, last_error
|
|
23
|
+
FROM automation_monitors
|
|
24
|
+
ORDER BY updated_at DESC
|
|
25
|
+
`;
|
|
26
|
+
const rows = this.db.prepare(query).all(...(workspaceId ? [workspaceId] : []));
|
|
27
|
+
return rows.map((row) => this.toMonitor(row));
|
|
28
|
+
}
|
|
29
|
+
get(monitorId) {
|
|
30
|
+
const row = this.db.prepare(`
|
|
31
|
+
SELECT id, workspace_id, title, source_type, source_config_json, condition_json, prompt_template, platform, route_type, route_config,
|
|
32
|
+
execution_mode, enabled, cooldown_ms, concurrency_policy, last_state_json, created_at, updated_at, last_triggered_at, last_status, last_error
|
|
33
|
+
FROM automation_monitors
|
|
34
|
+
WHERE id = ?
|
|
35
|
+
`).get(monitorId);
|
|
36
|
+
return row ? this.toMonitor(row) : undefined;
|
|
37
|
+
}
|
|
38
|
+
create(input) {
|
|
39
|
+
const title = String(input.title || '').trim();
|
|
40
|
+
if (!title)
|
|
41
|
+
throw new Error('Automation monitor title is required.');
|
|
42
|
+
const sourceType = String(input.sourceType || '').trim();
|
|
43
|
+
if (!sourceType)
|
|
44
|
+
throw new Error('Automation monitor source type is required.');
|
|
45
|
+
const condition = {
|
|
46
|
+
...input.condition,
|
|
47
|
+
metric: String(input.condition?.metric || '').trim(),
|
|
48
|
+
operator: (0, index_js_1.normalizeAutomationMonitorConditionOperator)(input.condition?.operator),
|
|
49
|
+
};
|
|
50
|
+
if (!condition.metric)
|
|
51
|
+
throw new Error('Automation monitor condition metric is required.');
|
|
52
|
+
const id = this.createMonitorId();
|
|
53
|
+
const now = new Date().toISOString();
|
|
54
|
+
this.db.prepare(`
|
|
55
|
+
INSERT INTO automation_monitors (
|
|
56
|
+
id, workspace_id, title, source_type, source_config_json, condition_json, prompt_template, platform, route_type, route_config,
|
|
57
|
+
execution_mode, enabled, cooldown_ms, concurrency_policy, last_state_json, created_at, updated_at
|
|
58
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'skip_if_running', ?, ?, ?)
|
|
59
|
+
`).run(id, input.workspaceId, title, sourceType, JSON.stringify(input.sourceConfig || {}), JSON.stringify(condition), input.promptTemplate, (0, index_js_1.normalizeChannelPlatform)(input.platform), input.route.type, JSON.stringify(input.route), (0, index_js_1.normalizeScheduledJobExecutionMode)(input.executionMode, 'side-thread'), input.enabled === false ? 0 : 1, Math.max(0, Number(input.cooldownMs ?? 15 * 60 * 1000)), null, now, now);
|
|
60
|
+
return this.get(id);
|
|
61
|
+
}
|
|
62
|
+
update(monitorId, input) {
|
|
63
|
+
const existing = this.get(monitorId);
|
|
64
|
+
if (!existing)
|
|
65
|
+
throw new Error(`Automation monitor not found: ${monitorId}`);
|
|
66
|
+
const nextCondition = input.condition
|
|
67
|
+
? {
|
|
68
|
+
...input.condition,
|
|
69
|
+
metric: String(input.condition.metric || '').trim(),
|
|
70
|
+
operator: (0, index_js_1.normalizeAutomationMonitorConditionOperator)(input.condition.operator),
|
|
71
|
+
}
|
|
72
|
+
: existing.condition;
|
|
73
|
+
const next = {
|
|
74
|
+
...existing,
|
|
75
|
+
...(typeof input.title === 'string' ? { title: input.title.trim() } : {}),
|
|
76
|
+
...(input.sourceConfig ? { sourceConfig: input.sourceConfig } : {}),
|
|
77
|
+
condition: nextCondition,
|
|
78
|
+
...(typeof input.promptTemplate === 'string' ? { promptTemplate: input.promptTemplate } : {}),
|
|
79
|
+
...(input.route ? { route: input.route } : {}),
|
|
80
|
+
...(input.executionMode ? { executionMode: (0, index_js_1.normalizeScheduledJobExecutionMode)(input.executionMode, 'side-thread') } : {}),
|
|
81
|
+
...(typeof input.enabled === 'boolean' ? { enabled: input.enabled } : {}),
|
|
82
|
+
...(typeof input.cooldownMs === 'number' ? { cooldownMs: Math.max(0, input.cooldownMs) } : {}),
|
|
83
|
+
updatedAt: new Date().toISOString(),
|
|
84
|
+
};
|
|
85
|
+
if (!next.title)
|
|
86
|
+
throw new Error('Automation monitor title is required.');
|
|
87
|
+
this.db.prepare(`
|
|
88
|
+
UPDATE automation_monitors
|
|
89
|
+
SET title = ?, source_config_json = ?, condition_json = ?, prompt_template = ?, route_type = ?, route_config = ?,
|
|
90
|
+
execution_mode = ?, enabled = ?, cooldown_ms = ?, updated_at = ?
|
|
91
|
+
WHERE id = ?
|
|
92
|
+
`).run(next.title, JSON.stringify(next.sourceConfig || {}), JSON.stringify(next.condition), next.promptTemplate, next.route.type, JSON.stringify(next.route), next.executionMode, next.enabled ? 1 : 0, next.cooldownMs, next.updatedAt, monitorId);
|
|
93
|
+
return this.get(monitorId);
|
|
94
|
+
}
|
|
95
|
+
updateState(monitorId, input) {
|
|
96
|
+
this.db.prepare(`
|
|
97
|
+
UPDATE automation_monitors
|
|
98
|
+
SET last_state_json = CASE WHEN ? IS NULL THEN last_state_json ELSE ? END,
|
|
99
|
+
last_triggered_at = COALESCE(?, last_triggered_at),
|
|
100
|
+
last_status = COALESCE(?, last_status),
|
|
101
|
+
last_error = CASE WHEN ? IS NULL THEN last_error ELSE ? END,
|
|
102
|
+
enabled = CASE WHEN ? IS NULL THEN enabled ELSE ? END,
|
|
103
|
+
updated_at = ?
|
|
104
|
+
WHERE id = ?
|
|
105
|
+
`).run(input.lastState == null ? null : JSON.stringify(input.lastState), input.lastState == null ? null : JSON.stringify(input.lastState), input.lastTriggeredAt || null, input.lastStatus || null, input.lastError == null ? null : input.lastError, input.lastError == null ? null : input.lastError, typeof input.enabled === 'boolean' ? (input.enabled ? 1 : 0) : null, typeof input.enabled === 'boolean' ? (input.enabled ? 1 : 0) : null, new Date().toISOString(), monitorId);
|
|
106
|
+
}
|
|
107
|
+
delete(monitorId) {
|
|
108
|
+
const result = this.db.prepare('DELETE FROM automation_monitors WHERE id = ?').run(monitorId);
|
|
109
|
+
if (result.changes === 0)
|
|
110
|
+
throw new Error(`Automation monitor not found: ${monitorId}`);
|
|
111
|
+
return { deleted: true };
|
|
112
|
+
}
|
|
113
|
+
listRuns(monitorId) {
|
|
114
|
+
const rows = this.db.prepare(`
|
|
115
|
+
SELECT id, monitor_id, status, triggered_at, started_at, finished_at, error, event_snapshot_json, thread_id, run_id, delivery_mode, delivery_status, delivery_error, last_bridge_event_at
|
|
116
|
+
FROM automation_monitor_runs
|
|
117
|
+
WHERE monitor_id = ?
|
|
118
|
+
ORDER BY triggered_at DESC
|
|
119
|
+
`).all(monitorId);
|
|
120
|
+
return rows.map((row) => this.toRun(row));
|
|
121
|
+
}
|
|
122
|
+
createRun(monitorId, status, input = {}) {
|
|
123
|
+
const id = `monitorrun:${(0, node_crypto_1.randomUUID)()}`;
|
|
124
|
+
const triggeredAt = input.triggeredAt || new Date().toISOString();
|
|
125
|
+
const normalizedStatus = (0, index_js_1.normalizeAutomationMonitorStatus)(status);
|
|
126
|
+
this.db.prepare(`
|
|
127
|
+
INSERT INTO automation_monitor_runs (id, monitor_id, status, triggered_at, started_at, finished_at, error, event_snapshot_json, thread_id, run_id, delivery_mode, delivery_status, delivery_error, last_bridge_event_at)
|
|
128
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
129
|
+
`).run(id, monitorId, normalizedStatus, triggeredAt, input.startedAt || null, input.finishedAt || null, input.error || null, input.eventSnapshot ? JSON.stringify(input.eventSnapshot) : null, input.threadId || null, input.runId || null, input.deliveryMode || null, input.deliveryStatus || null, input.deliveryError || null, input.lastBridgeEventAt || null);
|
|
130
|
+
this.updateState(monitorId, {
|
|
131
|
+
lastTriggeredAt: triggeredAt,
|
|
132
|
+
lastStatus: normalizedStatus,
|
|
133
|
+
lastError: input.error || '',
|
|
134
|
+
});
|
|
135
|
+
return this.getRun(id);
|
|
136
|
+
}
|
|
137
|
+
getRun(runId) {
|
|
138
|
+
const row = this.db.prepare(`
|
|
139
|
+
SELECT id, monitor_id, status, triggered_at, started_at, finished_at, error, event_snapshot_json, thread_id, run_id, delivery_mode, delivery_status, delivery_error, last_bridge_event_at
|
|
140
|
+
FROM automation_monitor_runs
|
|
141
|
+
WHERE id = ?
|
|
142
|
+
`).get(runId);
|
|
143
|
+
return row ? this.toRun(row) : undefined;
|
|
144
|
+
}
|
|
145
|
+
updateRun(runId, input) {
|
|
146
|
+
const existing = this.getRun(runId);
|
|
147
|
+
if (!existing)
|
|
148
|
+
throw new Error(`Automation monitor run not found: ${runId}`);
|
|
149
|
+
const next = {
|
|
150
|
+
...existing,
|
|
151
|
+
...input,
|
|
152
|
+
...(input.status ? { status: (0, index_js_1.normalizeAutomationMonitorStatus)(input.status) } : {}),
|
|
153
|
+
};
|
|
154
|
+
this.db.prepare(`
|
|
155
|
+
UPDATE automation_monitor_runs
|
|
156
|
+
SET status = ?, triggered_at = ?, started_at = ?, finished_at = ?, error = ?, event_snapshot_json = ?, thread_id = ?, run_id = ?, delivery_mode = ?, delivery_status = ?, delivery_error = ?, last_bridge_event_at = ?
|
|
157
|
+
WHERE id = ?
|
|
158
|
+
`).run(next.status, next.triggeredAt, next.startedAt || null, next.finishedAt || null, next.error || null, next.eventSnapshot ? JSON.stringify(next.eventSnapshot) : null, next.threadId || null, next.runId || null, next.deliveryMode || null, next.deliveryStatus || null, next.deliveryError || null, next.lastBridgeEventAt || null, runId);
|
|
159
|
+
if (input.status || Object.prototype.hasOwnProperty.call(input, 'error') || input.finishedAt || input.triggeredAt) {
|
|
160
|
+
this.updateState(existing.monitorId, {
|
|
161
|
+
lastTriggeredAt: next.triggeredAt,
|
|
162
|
+
lastStatus: next.status,
|
|
163
|
+
lastError: next.error || '',
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
return this.getRun(runId);
|
|
167
|
+
}
|
|
168
|
+
toMonitor(row) {
|
|
169
|
+
const condition = parseJson(row.condition_json, {});
|
|
170
|
+
return {
|
|
171
|
+
id: row.id,
|
|
172
|
+
workspaceId: row.workspace_id,
|
|
173
|
+
title: row.title,
|
|
174
|
+
sourceType: row.source_type,
|
|
175
|
+
sourceConfig: parseJson(row.source_config_json || '{}', {}),
|
|
176
|
+
condition: {
|
|
177
|
+
...condition,
|
|
178
|
+
operator: (0, index_js_1.normalizeAutomationMonitorConditionOperator)(condition.operator),
|
|
179
|
+
},
|
|
180
|
+
promptTemplate: row.prompt_template,
|
|
181
|
+
platform: (0, index_js_1.normalizeChannelPlatform)(row.platform),
|
|
182
|
+
route: JSON.parse(row.route_config),
|
|
183
|
+
executionMode: (0, index_js_1.normalizeScheduledJobExecutionMode)(row.execution_mode, 'side-thread'),
|
|
184
|
+
enabled: Boolean(row.enabled),
|
|
185
|
+
cooldownMs: Number(row.cooldown_ms || 0),
|
|
186
|
+
concurrencyPolicy: row.concurrency_policy,
|
|
187
|
+
lastState: row.last_state_json ? parseJson(row.last_state_json, {}) : undefined,
|
|
188
|
+
createdAt: row.created_at,
|
|
189
|
+
updatedAt: row.updated_at,
|
|
190
|
+
lastTriggeredAt: row.last_triggered_at || undefined,
|
|
191
|
+
lastStatus: row.last_status ? (0, index_js_1.normalizeAutomationMonitorStatus)(row.last_status) : undefined,
|
|
192
|
+
lastError: row.last_error || undefined,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
toRun(row) {
|
|
196
|
+
return {
|
|
197
|
+
id: row.id,
|
|
198
|
+
monitorId: row.monitor_id,
|
|
199
|
+
status: (0, index_js_1.normalizeAutomationMonitorStatus)(row.status),
|
|
200
|
+
triggeredAt: row.triggered_at,
|
|
201
|
+
startedAt: row.started_at || undefined,
|
|
202
|
+
finishedAt: row.finished_at || undefined,
|
|
203
|
+
error: row.error || undefined,
|
|
204
|
+
eventSnapshot: row.event_snapshot_json ? parseJson(row.event_snapshot_json, {}) : undefined,
|
|
205
|
+
threadId: row.thread_id || undefined,
|
|
206
|
+
runId: row.run_id || undefined,
|
|
207
|
+
deliveryMode: row.delivery_mode || undefined,
|
|
208
|
+
deliveryStatus: row.delivery_status || undefined,
|
|
209
|
+
deliveryError: row.delivery_error || undefined,
|
|
210
|
+
lastBridgeEventAt: row.last_bridge_event_at || undefined,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
createMonitorId() {
|
|
214
|
+
let id = `monitor:${(0, node_crypto_1.randomUUID)()}`;
|
|
215
|
+
for (let attempt = 0; attempt < 5 && this.get(id); attempt += 1) {
|
|
216
|
+
id = `monitor:${(0, node_crypto_1.randomUUID)()}`;
|
|
217
|
+
}
|
|
218
|
+
if (this.get(id))
|
|
219
|
+
throw new Error('Unable to allocate a unique automation monitor id.');
|
|
220
|
+
return id;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
exports.LocalAutomationMonitorStore = LocalAutomationMonitorStore;
|
|
224
|
+
function parseJson(value, fallback) {
|
|
225
|
+
try {
|
|
226
|
+
return JSON.parse(value);
|
|
227
|
+
}
|
|
228
|
+
catch {
|
|
229
|
+
return fallback;
|
|
230
|
+
}
|
|
231
|
+
}
|