@kafca/agentdock 0.1.42 → 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 +4 -0
- package/dist/renderer/assets/{Badge-D-WU4kUV.js → Badge-CbG6yRSm.js} +1 -1
- package/dist/renderer/assets/{Chat-BGkC5tAe.js → Chat-BvNNWGGX.js} +1 -1
- package/dist/renderer/assets/{ChatMarkdown-CfbC1jRd.js → ChatMarkdown-Ct-PvJB8.js} +1 -1
- package/dist/renderer/assets/{Config-qQb4bX5D.js → Config-lQX2qVVV.js} +2 -2
- package/dist/renderer/assets/CronList-Dj_3muVG.js +1 -0
- package/dist/renderer/assets/{Dashboard-xn6cUy_n.js → Dashboard-eh_RhGYb.js} +2 -2
- package/dist/renderer/assets/{EmptyState-BdKBBUpr.js → EmptyState-Bn2Qh14U.js} +1 -1
- package/dist/renderer/assets/{KnowledgeDetail-Duk8IQP3.js → KnowledgeDetail-Bsz6Ou41.js} +2 -2
- package/dist/renderer/assets/{KnowledgeHome-BfjX_4Sv.js → KnowledgeHome-Cgj4XFXn.js} +2 -2
- package/dist/renderer/assets/{Logs-Bfq61QMn.js → Logs-Dp-NF6GN.js} +1 -1
- package/dist/renderer/assets/{Modal-B3vlBmBr.js → Modal-B6YPPBN6.js} +1 -1
- package/dist/renderer/assets/MonitorList-xEZWg460.js +1 -0
- package/dist/renderer/assets/{Page-CPsLOP3z.js → Page-Bn7RjGOS.js} +1 -1
- package/dist/renderer/assets/{ProjectDetail-D-g46wyF.js → ProjectDetail-Cv_jIE61.js} +2 -2
- package/dist/renderer/assets/{ProjectList-BrQEKDQ8.js → ProjectList-BDk5_gqY.js} +1 -1
- package/dist/renderer/assets/{Select-C4CFMQmF.js → Select-xshfMIEQ.js} +1 -1
- package/dist/renderer/assets/SessionChat-BkHy90z3.js +1 -0
- package/dist/renderer/assets/{SessionList-DPWIUbOg.js → SessionList-BZyXT92L.js} +1 -1
- package/dist/renderer/assets/{ThreadChat-BjtU-j9q.js → ThreadChat-DUOIyXrS.js} +7 -7
- package/dist/renderer/assets/{Workspace-BcNmHuJx.js → Workspace-Dl80fNEC.js} +1 -1
- package/dist/renderer/assets/{arrow-left-DPzSmidS.js → arrow-left-C54ZI-AS.js} +1 -1
- package/dist/renderer/assets/{book-open-B0xhoRqZ.js → book-open-Dl7GO0zn.js} +1 -1
- package/dist/renderer/assets/{check-BTJTyd0C.js → check-CiqgtrOL.js} +1 -1
- package/dist/renderer/assets/{chevron-down-B6jJXlhi.js → chevron-down-DTL2OuVh.js} +1 -1
- package/dist/renderer/assets/{circle-qRhJR9qR.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-CbYKGTn8.js → funnel-CrmnLMJI.js} +1 -1
- package/dist/renderer/assets/{heart-DjwWJfkz.js → heart-BMfQI7y_.js} +1 -1
- package/dist/renderer/assets/{index-BWmHJRhe.js → index-HPNb1zfx.js} +39 -34
- package/dist/renderer/assets/{index-CyZs_2NJ.js → index-nreiKY1f.js} +3 -3
- package/dist/renderer/assets/{pencil-1dfAivmj.js → pencil-wTQ4l465.js} +1 -1
- package/dist/renderer/assets/{play-CB3w1G6S.js → play-BK--MXmw.js} +1 -1
- package/dist/renderer/assets/{plug-Bvep5o3r.js → plug-BIx9fjip.js} +1 -1
- package/dist/renderer/assets/{plus-DJVg9m09.js → plus-Dn7JFWQ8.js} +1 -1
- package/dist/renderer/assets/projects-brJZgwEJ.js +1 -0
- package/dist/renderer/assets/{save-xjJn3qf2.js → save-CC3zOSWb.js} +1 -1
- package/dist/renderer/assets/{search-BK3UrQxM.js → search-CDTy9Czu.js} +1 -1
- package/dist/renderer/assets/{server-Dyd2eXJu.js → server-DtQk3t2a.js} +1 -1
- package/dist/renderer/assets/{session-utils-eXC0020s.js → session-utils-4ep5D66T.js} +1 -1
- package/dist/renderer/assets/{sessions-WLYpkyUt.js → sessions-Dor1LteH.js} +1 -1
- package/dist/renderer/assets/{shield-check-C0N6aWzF.js → shield-check-Cz2LpU6r.js} +1 -1
- package/dist/renderer/assets/{trash-2-BGMTNJA6.js → trash-2-C2EmWFZV.js} +1 -1
- package/dist/renderer/assets/{user-BcGMLyhu.js → user-I8B-cs5A.js} +1 -1
- package/dist/renderer/assets/{wifi-off-FhcQx0HK.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 +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/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/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/local-core-refactor.test.js +194 -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
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LocalSecurityStore = 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 LocalSecurityStore {
|
|
8
|
+
db;
|
|
9
|
+
updateAgentTask;
|
|
10
|
+
constructor(db, updateAgentTask) {
|
|
11
|
+
this.db = db;
|
|
12
|
+
this.updateAgentTask = updateAgentTask;
|
|
13
|
+
}
|
|
14
|
+
getWorkspaceSecuritySettings(workspaceId) {
|
|
15
|
+
const row = this.db.prepare(`
|
|
16
|
+
SELECT workspace_id, permissions_json, allow_paths_json, deny_paths_json, updated_at, updated_by
|
|
17
|
+
FROM workspace_security_settings
|
|
18
|
+
WHERE workspace_id = ?
|
|
19
|
+
`).get(workspaceId);
|
|
20
|
+
if (row) {
|
|
21
|
+
return this.toWorkspaceSecuritySettings(row);
|
|
22
|
+
}
|
|
23
|
+
const now = new Date().toISOString();
|
|
24
|
+
return {
|
|
25
|
+
workspaceId,
|
|
26
|
+
permissions: (0, utils_js_1.defaultPermissions)(),
|
|
27
|
+
allowPaths: [],
|
|
28
|
+
denyPaths: [],
|
|
29
|
+
updatedAt: now,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
updateWorkspaceSecuritySettings(workspaceId, input) {
|
|
33
|
+
const existing = this.getWorkspaceSecuritySettings(workspaceId);
|
|
34
|
+
const now = new Date().toISOString();
|
|
35
|
+
const next = {
|
|
36
|
+
workspaceId,
|
|
37
|
+
permissions: {
|
|
38
|
+
...existing.permissions,
|
|
39
|
+
...(input.permissions || {}),
|
|
40
|
+
},
|
|
41
|
+
allowPaths: Array.isArray(input.allowPaths) ? input.allowPaths : existing.allowPaths,
|
|
42
|
+
denyPaths: Array.isArray(input.denyPaths) ? input.denyPaths : existing.denyPaths,
|
|
43
|
+
updatedAt: now,
|
|
44
|
+
updatedBy: input.updatedBy || existing.updatedBy,
|
|
45
|
+
};
|
|
46
|
+
this.db.prepare(`
|
|
47
|
+
INSERT INTO workspace_security_settings (workspace_id, permissions_json, allow_paths_json, deny_paths_json, updated_at, updated_by)
|
|
48
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
49
|
+
ON CONFLICT(workspace_id) DO UPDATE SET
|
|
50
|
+
permissions_json = excluded.permissions_json,
|
|
51
|
+
allow_paths_json = excluded.allow_paths_json,
|
|
52
|
+
deny_paths_json = excluded.deny_paths_json,
|
|
53
|
+
updated_at = excluded.updated_at,
|
|
54
|
+
updated_by = excluded.updated_by
|
|
55
|
+
`).run(workspaceId, JSON.stringify(next.permissions), JSON.stringify(next.allowPaths), JSON.stringify(next.denyPaths), now, next.updatedBy || null);
|
|
56
|
+
this.createAuditEvent({
|
|
57
|
+
type: 'permission.changed',
|
|
58
|
+
workspaceId,
|
|
59
|
+
actor: next.updatedBy || 'local',
|
|
60
|
+
summary: 'Workspace security settings changed.',
|
|
61
|
+
metadata: {
|
|
62
|
+
permissions: next.permissions,
|
|
63
|
+
allowPaths: next.allowPaths,
|
|
64
|
+
denyPaths: next.denyPaths,
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
return this.getWorkspaceSecuritySettings(workspaceId);
|
|
68
|
+
}
|
|
69
|
+
createApprovalRequest(input) {
|
|
70
|
+
const id = `approval:${(0, node_crypto_1.randomUUID)()}`;
|
|
71
|
+
const now = new Date().toISOString();
|
|
72
|
+
this.db.prepare(`
|
|
73
|
+
INSERT INTO approval_requests (
|
|
74
|
+
id, workspace_id, task_id, thread_id, run_id, device_id, kind, status, risk_level, title, description,
|
|
75
|
+
requested_action, command, scopes_json, options_json, requested_by, created_at, updated_at, expires_at, metadata_json
|
|
76
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, 'pending', ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
77
|
+
`).run(id, input.workspaceId, input.taskId || null, input.threadId || null, input.runId || null, input.deviceId || 'local', input.kind, input.riskLevel, input.title, (0, utils_js_1.redactSecrets)(input.description), (0, utils_js_1.redactSecrets)(input.requestedAction), input.command ? (0, utils_js_1.redactSecrets)(input.command) : null, JSON.stringify(input.scopes || []), JSON.stringify(input.options || []), input.requestedBy || null, now, now, input.expiresAt || null, JSON.stringify(input.metadata || {}));
|
|
78
|
+
const approval = this.getApprovalRequest(id);
|
|
79
|
+
this.createAuditEvent({
|
|
80
|
+
type: 'approval.requested',
|
|
81
|
+
workspaceId: approval.workspaceId,
|
|
82
|
+
taskId: approval.taskId,
|
|
83
|
+
approvalId: approval.approvalId,
|
|
84
|
+
actor: approval.requestedBy || 'agent',
|
|
85
|
+
summary: approval.title,
|
|
86
|
+
riskLevel: approval.riskLevel,
|
|
87
|
+
metadata: {
|
|
88
|
+
kind: approval.kind,
|
|
89
|
+
requestedAction: approval.requestedAction,
|
|
90
|
+
scopes: approval.scopes,
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
if (approval.taskId) {
|
|
94
|
+
this.updateAgentTask(approval.taskId, {
|
|
95
|
+
approvalId: approval.approvalId,
|
|
96
|
+
timelineItem: {
|
|
97
|
+
type: 'approval_requested',
|
|
98
|
+
title: approval.title,
|
|
99
|
+
description: approval.description,
|
|
100
|
+
metadata: { approvalId: approval.approvalId, riskLevel: approval.riskLevel },
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
return approval;
|
|
105
|
+
}
|
|
106
|
+
listApprovalRequests(query = {}) {
|
|
107
|
+
const predicates = [];
|
|
108
|
+
const params = [];
|
|
109
|
+
if (query.workspaceId) {
|
|
110
|
+
predicates.push('workspace_id = ?');
|
|
111
|
+
params.push(query.workspaceId);
|
|
112
|
+
}
|
|
113
|
+
if (query.taskId) {
|
|
114
|
+
predicates.push('task_id = ?');
|
|
115
|
+
params.push(query.taskId);
|
|
116
|
+
}
|
|
117
|
+
if (query.status) {
|
|
118
|
+
const statuses = (Array.isArray(query.status) ? query.status : [query.status]).map((status) => (0, index_js_1.normalizeApprovalRequestStatus)(status));
|
|
119
|
+
predicates.push(`status IN (${statuses.map(() => '?').join(', ')})`);
|
|
120
|
+
params.push(...statuses);
|
|
121
|
+
}
|
|
122
|
+
const limit = Math.max(1, Math.min(Number(query.limit || 50), 100));
|
|
123
|
+
const where = predicates.length ? `WHERE ${predicates.join(' AND ')}` : '';
|
|
124
|
+
const rows = this.db.prepare(`
|
|
125
|
+
SELECT *
|
|
126
|
+
FROM approval_requests
|
|
127
|
+
${where}
|
|
128
|
+
ORDER BY updated_at DESC
|
|
129
|
+
LIMIT ?
|
|
130
|
+
`).all(...params, limit);
|
|
131
|
+
return { approvals: rows.map((row) => this.toApprovalRequest(row)) };
|
|
132
|
+
}
|
|
133
|
+
getApprovalRequest(approvalId) {
|
|
134
|
+
const row = this.db.prepare('SELECT * FROM approval_requests WHERE id = ?').get(approvalId);
|
|
135
|
+
return row ? this.toApprovalRequest(row) : undefined;
|
|
136
|
+
}
|
|
137
|
+
resolveApprovalRequest(approvalId, input) {
|
|
138
|
+
const existing = this.getApprovalRequest(approvalId);
|
|
139
|
+
if (!existing) {
|
|
140
|
+
throw new Error(`Approval not found: ${approvalId}`);
|
|
141
|
+
}
|
|
142
|
+
const now = new Date().toISOString();
|
|
143
|
+
this.db.prepare(`
|
|
144
|
+
UPDATE approval_requests
|
|
145
|
+
SET status = ?, resolved_by = ?, resolution = ?, resolved_at = ?, updated_at = ?
|
|
146
|
+
WHERE id = ?
|
|
147
|
+
`).run(input.status, input.resolvedBy || existing.resolvedBy || 'local', input.resolution || existing.resolution || null, now, now, approvalId);
|
|
148
|
+
const approval = this.getApprovalRequest(approvalId);
|
|
149
|
+
this.createAuditEvent({
|
|
150
|
+
type: input.status === 'rejected' ? 'approval.rejected' : 'approval.resolved',
|
|
151
|
+
workspaceId: approval.workspaceId,
|
|
152
|
+
taskId: approval.taskId,
|
|
153
|
+
approvalId: approval.approvalId,
|
|
154
|
+
actor: approval.resolvedBy || 'local',
|
|
155
|
+
summary: `Approval ${input.status}: ${approval.title}`,
|
|
156
|
+
riskLevel: approval.riskLevel,
|
|
157
|
+
metadata: { resolution: approval.resolution },
|
|
158
|
+
});
|
|
159
|
+
if (approval.taskId) {
|
|
160
|
+
this.updateAgentTask(approval.taskId, {
|
|
161
|
+
timelineItem: {
|
|
162
|
+
type: 'approval_resolved',
|
|
163
|
+
title: `Approval ${input.status}`,
|
|
164
|
+
description: approval.resolution || approval.title,
|
|
165
|
+
metadata: { approvalId: approval.approvalId, status: input.status },
|
|
166
|
+
},
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
return approval;
|
|
170
|
+
}
|
|
171
|
+
createAuditEvent(input) {
|
|
172
|
+
const id = `audit:${(0, node_crypto_1.randomUUID)()}`;
|
|
173
|
+
const now = new Date().toISOString();
|
|
174
|
+
this.db.prepare(`
|
|
175
|
+
INSERT INTO audit_events (id, type, workspace_id, task_id, approval_id, actor, summary, risk_level, created_at, metadata_json)
|
|
176
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
177
|
+
`).run(id, input.type, input.workspaceId || null, input.taskId || null, input.approvalId || null, input.actor || null, (0, utils_js_1.redactSecrets)(input.summary), input.riskLevel || null, now, JSON.stringify(input.metadata || {}));
|
|
178
|
+
return this.toAuditEvent(this.db.prepare('SELECT * FROM audit_events WHERE id = ?').get(id));
|
|
179
|
+
}
|
|
180
|
+
listAuditEvents(query = {}) {
|
|
181
|
+
const predicates = [];
|
|
182
|
+
const params = [];
|
|
183
|
+
if (query.workspaceId) {
|
|
184
|
+
predicates.push('workspace_id = ?');
|
|
185
|
+
params.push(query.workspaceId);
|
|
186
|
+
}
|
|
187
|
+
if (query.taskId) {
|
|
188
|
+
predicates.push('task_id = ?');
|
|
189
|
+
params.push(query.taskId);
|
|
190
|
+
}
|
|
191
|
+
if (query.approvalId) {
|
|
192
|
+
predicates.push('approval_id = ?');
|
|
193
|
+
params.push(query.approvalId);
|
|
194
|
+
}
|
|
195
|
+
if (query.type) {
|
|
196
|
+
const types = Array.isArray(query.type) ? query.type : [query.type];
|
|
197
|
+
predicates.push(`type IN (${types.map(() => '?').join(', ')})`);
|
|
198
|
+
params.push(...types);
|
|
199
|
+
}
|
|
200
|
+
const limit = Math.max(1, Math.min(Number(query.limit || 50), 100));
|
|
201
|
+
const where = predicates.length ? `WHERE ${predicates.join(' AND ')}` : '';
|
|
202
|
+
const rows = this.db.prepare(`
|
|
203
|
+
SELECT *
|
|
204
|
+
FROM audit_events
|
|
205
|
+
${where}
|
|
206
|
+
ORDER BY created_at DESC
|
|
207
|
+
LIMIT ?
|
|
208
|
+
`).all(...params, limit);
|
|
209
|
+
return { events: rows.map((row) => this.toAuditEvent(row)) };
|
|
210
|
+
}
|
|
211
|
+
toWorkspaceSecuritySettings(row) {
|
|
212
|
+
return {
|
|
213
|
+
workspaceId: row.workspace_id,
|
|
214
|
+
permissions: {
|
|
215
|
+
...(0, utils_js_1.defaultPermissions)(),
|
|
216
|
+
...(0, utils_js_1.parseJson)(row.permissions_json, {}),
|
|
217
|
+
},
|
|
218
|
+
allowPaths: (0, utils_js_1.parseJson)(row.allow_paths_json, []),
|
|
219
|
+
denyPaths: (0, utils_js_1.parseJson)(row.deny_paths_json, []),
|
|
220
|
+
updatedAt: row.updated_at,
|
|
221
|
+
updatedBy: row.updated_by || undefined,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
toApprovalRequest(row) {
|
|
225
|
+
return {
|
|
226
|
+
approvalId: row.id,
|
|
227
|
+
workspaceId: row.workspace_id,
|
|
228
|
+
taskId: row.task_id || undefined,
|
|
229
|
+
threadId: row.thread_id || undefined,
|
|
230
|
+
runId: row.run_id || undefined,
|
|
231
|
+
deviceId: row.device_id,
|
|
232
|
+
kind: row.kind,
|
|
233
|
+
status: (0, index_js_1.normalizeApprovalRequestStatus)(row.status),
|
|
234
|
+
riskLevel: row.risk_level,
|
|
235
|
+
title: row.title,
|
|
236
|
+
description: row.description,
|
|
237
|
+
requestedAction: row.requested_action,
|
|
238
|
+
command: row.command || undefined,
|
|
239
|
+
scopes: (0, utils_js_1.parseJson)(row.scopes_json, []),
|
|
240
|
+
options: (0, utils_js_1.parseJson)(row.options_json, []),
|
|
241
|
+
requestedBy: row.requested_by || undefined,
|
|
242
|
+
resolvedBy: row.resolved_by || undefined,
|
|
243
|
+
resolution: row.resolution || undefined,
|
|
244
|
+
createdAt: row.created_at,
|
|
245
|
+
updatedAt: row.updated_at,
|
|
246
|
+
resolvedAt: row.resolved_at || undefined,
|
|
247
|
+
expiresAt: row.expires_at || undefined,
|
|
248
|
+
metadata: (0, utils_js_1.parseJson)(row.metadata_json, {}),
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
toAuditEvent(row) {
|
|
252
|
+
return {
|
|
253
|
+
auditId: row.id,
|
|
254
|
+
type: row.type,
|
|
255
|
+
workspaceId: row.workspace_id || undefined,
|
|
256
|
+
taskId: row.task_id || undefined,
|
|
257
|
+
approvalId: row.approval_id || undefined,
|
|
258
|
+
actor: row.actor || undefined,
|
|
259
|
+
summary: row.summary,
|
|
260
|
+
riskLevel: row.risk_level || undefined,
|
|
261
|
+
createdAt: row.created_at,
|
|
262
|
+
metadata: (0, utils_js_1.parseJson)(row.metadata_json, {}),
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
exports.LocalSecurityStore = LocalSecurityStore;
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LocalThreadStore = void 0;
|
|
4
|
+
const node_crypto_1 = require("node:crypto");
|
|
5
|
+
const index_js_1 = require("../../../../../packages/contracts/src/index.js");
|
|
6
|
+
const desktop_js_1 = require("../../../../../shared/desktop.js");
|
|
7
|
+
const workspace_thread_mappers_js_1 = require("../../thread/workspace-thread-mappers.js");
|
|
8
|
+
const workspace_thread_id_js_1 = require("../../thread/workspace-thread-id.js");
|
|
9
|
+
const utils_js_1 = require("./utils.js");
|
|
10
|
+
class LocalThreadStore {
|
|
11
|
+
db;
|
|
12
|
+
constructor(db) {
|
|
13
|
+
this.db = db;
|
|
14
|
+
}
|
|
15
|
+
listSummaries(workspaceId) {
|
|
16
|
+
const rows = this.db.prepare(`
|
|
17
|
+
SELECT id, workspace_id, session_id, bridge_session_key, title, agent_type, created_at, updated_at, history_count, excerpt, acp_session_id, acp_supports_load, agent_mode
|
|
18
|
+
FROM threads
|
|
19
|
+
WHERE workspace_id = ?
|
|
20
|
+
ORDER BY updated_at DESC
|
|
21
|
+
`).all(workspaceId);
|
|
22
|
+
return rows.map((row) => ({
|
|
23
|
+
id: row.id,
|
|
24
|
+
workspaceId: row.workspace_id,
|
|
25
|
+
title: row.title,
|
|
26
|
+
live: false,
|
|
27
|
+
updatedAt: row.updated_at,
|
|
28
|
+
createdAt: row.created_at,
|
|
29
|
+
historyCount: row.history_count,
|
|
30
|
+
excerpt: row.excerpt,
|
|
31
|
+
runId: undefined,
|
|
32
|
+
bridgeSessionKey: row.bridge_session_key,
|
|
33
|
+
agentType: row.agent_type,
|
|
34
|
+
}));
|
|
35
|
+
}
|
|
36
|
+
count(workspaceId) {
|
|
37
|
+
const row = this.db.prepare('SELECT COUNT(*) AS total FROM threads WHERE workspace_id = ?').get(workspaceId);
|
|
38
|
+
return Number(row?.total || 0);
|
|
39
|
+
}
|
|
40
|
+
create(workspaceId, title, agentType = desktop_js_1.LOCALCORE_ACP_AGENT_TYPE, agentMode = 'default') {
|
|
41
|
+
const sessionId = (0, node_crypto_1.randomUUID)();
|
|
42
|
+
const threadId = (0, workspace_thread_id_js_1.encodeThreadId)(workspaceId, sessionId);
|
|
43
|
+
const now = new Date().toISOString();
|
|
44
|
+
const bridgeSessionKey = `${desktop_js_1.LOCALCORE_ACP_AGENT_TYPE}:${workspaceId}:${sessionId}`;
|
|
45
|
+
this.db.prepare(`
|
|
46
|
+
INSERT INTO threads (id, workspace_id, session_id, bridge_session_key, title, agent_type, created_at, updated_at, history_count, excerpt, agent_mode)
|
|
47
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, 0, '', ?)
|
|
48
|
+
`).run(threadId, workspaceId, sessionId, bridgeSessionKey, title, agentType, now, now, agentMode || 'default');
|
|
49
|
+
return {
|
|
50
|
+
id: threadId,
|
|
51
|
+
workspaceId,
|
|
52
|
+
title,
|
|
53
|
+
live: false,
|
|
54
|
+
updatedAt: now,
|
|
55
|
+
createdAt: now,
|
|
56
|
+
historyCount: 0,
|
|
57
|
+
excerpt: '',
|
|
58
|
+
bridgeSessionKey,
|
|
59
|
+
agentType,
|
|
60
|
+
messages: [],
|
|
61
|
+
selectedKnowledgeBaseIds: [],
|
|
62
|
+
pendingPermissionRequest: null,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
get(threadId, selectedKnowledgeBaseIds) {
|
|
66
|
+
const row = this.getRow(threadId);
|
|
67
|
+
if (!row) {
|
|
68
|
+
throw new Error(`Thread not found: ${threadId}`);
|
|
69
|
+
}
|
|
70
|
+
const messages = this.db.prepare(`
|
|
71
|
+
SELECT id, thread_id, role, content, tool_call_json, bridge_kind, bridge_status, timestamp, kind, seq
|
|
72
|
+
FROM messages
|
|
73
|
+
WHERE thread_id = ?
|
|
74
|
+
ORDER BY seq ASC
|
|
75
|
+
`).all(threadId);
|
|
76
|
+
return {
|
|
77
|
+
id: row.id,
|
|
78
|
+
workspaceId: row.workspace_id,
|
|
79
|
+
title: row.title,
|
|
80
|
+
live: false,
|
|
81
|
+
updatedAt: row.updated_at,
|
|
82
|
+
createdAt: row.created_at,
|
|
83
|
+
historyCount: row.history_count,
|
|
84
|
+
excerpt: row.excerpt,
|
|
85
|
+
bridgeSessionKey: row.bridge_session_key,
|
|
86
|
+
agentType: row.agent_type,
|
|
87
|
+
messages: messages.map((message) => ({
|
|
88
|
+
id: message.id,
|
|
89
|
+
role: message.role,
|
|
90
|
+
content: message.content,
|
|
91
|
+
toolCall: (0, utils_js_1.parseJson)(message.tool_call_json || 'null', null) || undefined,
|
|
92
|
+
bridgeKind: (0, utils_js_1.normalizeBridgeKind)(message.bridge_kind),
|
|
93
|
+
bridgeStatus: (0, utils_js_1.normalizeBridgeStatus)(message.bridge_status),
|
|
94
|
+
timestamp: message.timestamp,
|
|
95
|
+
kind: message.kind,
|
|
96
|
+
})),
|
|
97
|
+
selectedKnowledgeBaseIds,
|
|
98
|
+
pendingPermissionRequest: null,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
rename(threadId, title) {
|
|
102
|
+
const now = new Date().toISOString();
|
|
103
|
+
this.db.prepare('UPDATE threads SET title = ?, updated_at = ? WHERE id = ?').run(title, now, threadId);
|
|
104
|
+
}
|
|
105
|
+
delete(threadId) {
|
|
106
|
+
this.db.prepare('DELETE FROM threads WHERE id = ?').run(threadId);
|
|
107
|
+
}
|
|
108
|
+
appendMessage(threadId, role, content, kind, toolCall, bridgeKind, bridgeStatus) {
|
|
109
|
+
const timestamp = new Date().toISOString();
|
|
110
|
+
const nextSequenceRow = this.db.prepare('SELECT COALESCE(MAX(seq), -1) + 1 AS next_seq FROM messages WHERE thread_id = ?').get(threadId);
|
|
111
|
+
const nextSeq = Number(nextSequenceRow?.next_seq || 0);
|
|
112
|
+
const id = `${timestamp}-${role}-${nextSeq}`;
|
|
113
|
+
const excerpt = (0, workspace_thread_mappers_js_1.normalizeMessageContent)(content);
|
|
114
|
+
this.db.exec('BEGIN IMMEDIATE');
|
|
115
|
+
try {
|
|
116
|
+
this.db.prepare(`
|
|
117
|
+
INSERT INTO messages (id, thread_id, role, content, tool_call_json, bridge_kind, bridge_status, timestamp, kind, seq)
|
|
118
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
119
|
+
`).run(id, threadId, role, content, toolCall ? JSON.stringify(toolCall) : null, bridgeKind || null, bridgeStatus || null, timestamp, kind, nextSeq);
|
|
120
|
+
this.db.prepare(`
|
|
121
|
+
UPDATE threads
|
|
122
|
+
SET updated_at = ?, history_count = history_count + 1, excerpt = ?
|
|
123
|
+
WHERE id = ?
|
|
124
|
+
`).run(timestamp, excerpt, threadId);
|
|
125
|
+
this.db.exec('COMMIT');
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
this.db.exec('ROLLBACK');
|
|
129
|
+
throw error;
|
|
130
|
+
}
|
|
131
|
+
return { id, timestamp };
|
|
132
|
+
}
|
|
133
|
+
upsertMessage(threadId, id, role, content, kind, toolCall, bridgeKind, bridgeStatus) {
|
|
134
|
+
const timestamp = new Date().toISOString();
|
|
135
|
+
const excerpt = (0, workspace_thread_mappers_js_1.normalizeMessageContent)(content);
|
|
136
|
+
const existing = this.db.prepare('SELECT id FROM messages WHERE id = ? AND thread_id = ?').get(id, threadId);
|
|
137
|
+
this.db.exec('BEGIN IMMEDIATE');
|
|
138
|
+
try {
|
|
139
|
+
if (existing) {
|
|
140
|
+
this.db.prepare(`
|
|
141
|
+
UPDATE messages
|
|
142
|
+
SET content = ?, tool_call_json = ?, bridge_kind = ?, bridge_status = ?, timestamp = ?, kind = ?
|
|
143
|
+
WHERE id = ? AND thread_id = ?
|
|
144
|
+
`).run(content, toolCall ? JSON.stringify(toolCall) : null, bridgeKind || null, bridgeStatus || null, timestamp, kind, id, threadId);
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
const nextSequenceRow = this.db.prepare('SELECT COALESCE(MAX(seq), -1) + 1 AS next_seq FROM messages WHERE thread_id = ?').get(threadId);
|
|
148
|
+
const nextSeq = Number(nextSequenceRow?.next_seq || 0);
|
|
149
|
+
this.db.prepare(`
|
|
150
|
+
INSERT INTO messages (id, thread_id, role, content, tool_call_json, bridge_kind, bridge_status, timestamp, kind, seq)
|
|
151
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
152
|
+
`).run(id, threadId, role, content, toolCall ? JSON.stringify(toolCall) : null, bridgeKind || null, bridgeStatus || null, timestamp, kind, nextSeq);
|
|
153
|
+
this.db.prepare(`
|
|
154
|
+
UPDATE threads
|
|
155
|
+
SET history_count = history_count + 1
|
|
156
|
+
WHERE id = ?
|
|
157
|
+
`).run(threadId);
|
|
158
|
+
}
|
|
159
|
+
this.db.prepare(`
|
|
160
|
+
UPDATE threads
|
|
161
|
+
SET updated_at = ?, excerpt = ?
|
|
162
|
+
WHERE id = ?
|
|
163
|
+
`).run(timestamp, excerpt, threadId);
|
|
164
|
+
this.db.exec('COMMIT');
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
this.db.exec('ROLLBACK');
|
|
168
|
+
throw error;
|
|
169
|
+
}
|
|
170
|
+
return { id, timestamp };
|
|
171
|
+
}
|
|
172
|
+
updateRun(runId, threadId, status) {
|
|
173
|
+
const now = new Date().toISOString();
|
|
174
|
+
const normalizedStatus = (0, index_js_1.normalizeRunStatus)(status);
|
|
175
|
+
const existing = this.db.prepare('SELECT id FROM runs WHERE id = ?').get(runId);
|
|
176
|
+
if (existing) {
|
|
177
|
+
this.db.prepare('UPDATE runs SET status = ?, updated_at = ? WHERE id = ?').run(normalizedStatus, now, runId);
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
this.db.prepare(`
|
|
181
|
+
INSERT INTO runs (id, thread_id, status, started_at, updated_at)
|
|
182
|
+
VALUES (?, ?, ?, ?, ?)
|
|
183
|
+
`).run(runId, threadId, normalizedStatus, now, now);
|
|
184
|
+
}
|
|
185
|
+
getLatestRunForThread(threadId) {
|
|
186
|
+
const row = this.db.prepare(`
|
|
187
|
+
SELECT id, thread_id, status, started_at, updated_at
|
|
188
|
+
FROM runs
|
|
189
|
+
WHERE thread_id = ?
|
|
190
|
+
ORDER BY updated_at DESC
|
|
191
|
+
LIMIT 1
|
|
192
|
+
`).get(threadId);
|
|
193
|
+
return row ? { ...row, status: (0, index_js_1.normalizeRunStatus)(row.status) } : undefined;
|
|
194
|
+
}
|
|
195
|
+
getRun(runId) {
|
|
196
|
+
const row = this.db.prepare(`
|
|
197
|
+
SELECT id, thread_id, status, started_at, updated_at
|
|
198
|
+
FROM runs
|
|
199
|
+
WHERE id = ?
|
|
200
|
+
`).get(runId);
|
|
201
|
+
return row ? { ...row, status: (0, index_js_1.normalizeRunStatus)(row.status) } : undefined;
|
|
202
|
+
}
|
|
203
|
+
getRow(threadId) {
|
|
204
|
+
return this.db.prepare(`
|
|
205
|
+
SELECT id, workspace_id, session_id, bridge_session_key, title, agent_type, created_at, updated_at, history_count, excerpt, acp_session_id, acp_supports_load, agent_mode
|
|
206
|
+
FROM threads
|
|
207
|
+
WHERE id = ?
|
|
208
|
+
`).get(threadId);
|
|
209
|
+
}
|
|
210
|
+
updateAgentMode(threadId, mode) {
|
|
211
|
+
this.db.prepare(`
|
|
212
|
+
UPDATE threads
|
|
213
|
+
SET agent_mode = ?, updated_at = ?
|
|
214
|
+
WHERE id = ?
|
|
215
|
+
`).run(mode, new Date().toISOString(), threadId);
|
|
216
|
+
}
|
|
217
|
+
updateAgentType(threadId, agentType) {
|
|
218
|
+
this.db.prepare(`
|
|
219
|
+
UPDATE threads
|
|
220
|
+
SET agent_type = ?, acp_session_id = NULL, acp_supports_load = 0, updated_at = ?
|
|
221
|
+
WHERE id = ?
|
|
222
|
+
`).run(agentType, new Date().toISOString(), threadId);
|
|
223
|
+
}
|
|
224
|
+
updateSession(threadId, sessionId, supportsLoad) {
|
|
225
|
+
this.db.prepare(`
|
|
226
|
+
UPDATE threads
|
|
227
|
+
SET acp_session_id = ?, acp_supports_load = ?, updated_at = COALESCE(updated_at, ?)
|
|
228
|
+
WHERE id = ?
|
|
229
|
+
`).run(sessionId, supportsLoad ? 1 : 0, new Date().toISOString(), threadId);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
exports.LocalThreadStore = LocalThreadStore;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseJson = parseJson;
|
|
4
|
+
exports.normalizeBridgeKind = normalizeBridgeKind;
|
|
5
|
+
exports.normalizeBridgeStatus = normalizeBridgeStatus;
|
|
6
|
+
exports.defaultPermissions = defaultPermissions;
|
|
7
|
+
exports.redactSecrets = redactSecrets;
|
|
8
|
+
function parseJson(value, fallback) {
|
|
9
|
+
try {
|
|
10
|
+
return JSON.parse(value);
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return fallback;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function normalizeBridgeKind(value) {
|
|
17
|
+
switch (value) {
|
|
18
|
+
case 'assistant':
|
|
19
|
+
case 'thought':
|
|
20
|
+
case 'plan':
|
|
21
|
+
case 'tool':
|
|
22
|
+
case 'status':
|
|
23
|
+
case 'permission':
|
|
24
|
+
return value;
|
|
25
|
+
default:
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function normalizeBridgeStatus(value) {
|
|
30
|
+
return value === 'awaiting_input' ? value : undefined;
|
|
31
|
+
}
|
|
32
|
+
function defaultPermissions() {
|
|
33
|
+
return {
|
|
34
|
+
'workspace.read': 'allow',
|
|
35
|
+
'workspace.write': 'ask',
|
|
36
|
+
'command.execute': 'ask',
|
|
37
|
+
'network.access': 'ask',
|
|
38
|
+
'secrets.access': 'deny',
|
|
39
|
+
'git.modify': 'ask',
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function redactSecrets(value) {
|
|
43
|
+
return value
|
|
44
|
+
.replace(/\b(sk-[A-Za-z0-9_-]{12,})\b/g, '[REDACTED_SECRET]')
|
|
45
|
+
.replace(/\b([A-Za-z0-9_]*TOKEN[A-Za-z0-9_]*|[A-Za-z0-9_]*SECRET[A-Za-z0-9_]*|[A-Za-z0-9_]*KEY[A-Za-z0-9_]*)=([^\s]+)/gi, '$1=[REDACTED_SECRET]')
|
|
46
|
+
.replace(/\b(Bearer\s+)[A-Za-z0-9._-]+/gi, '$1[REDACTED_SECRET]');
|
|
47
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LocalWorkspaceRegistryStore = void 0;
|
|
4
|
+
const utils_js_1 = require("./utils.js");
|
|
5
|
+
class LocalWorkspaceRegistryStore {
|
|
6
|
+
db;
|
|
7
|
+
constructor(db) {
|
|
8
|
+
this.db = db;
|
|
9
|
+
}
|
|
10
|
+
list() {
|
|
11
|
+
const rows = this.db.prepare(`
|
|
12
|
+
SELECT id, display_name, path, device_id, default_runtime_id, git_json, health_json, metadata_json, created_at, updated_at, last_opened_at
|
|
13
|
+
FROM workspace_registry
|
|
14
|
+
ORDER BY display_name ASC
|
|
15
|
+
`).all();
|
|
16
|
+
return rows.map((row) => this.toEntry(row));
|
|
17
|
+
}
|
|
18
|
+
get(workspaceId) {
|
|
19
|
+
const row = this.db.prepare(`
|
|
20
|
+
SELECT id, display_name, path, device_id, default_runtime_id, git_json, health_json, metadata_json, created_at, updated_at, last_opened_at
|
|
21
|
+
FROM workspace_registry
|
|
22
|
+
WHERE id = ?
|
|
23
|
+
`).get(workspaceId);
|
|
24
|
+
return row ? this.toEntry(row) : undefined;
|
|
25
|
+
}
|
|
26
|
+
upsert(input) {
|
|
27
|
+
const id = input.workspaceId || input.displayName;
|
|
28
|
+
const now = new Date().toISOString();
|
|
29
|
+
const existing = this.get(id);
|
|
30
|
+
const health = input.health || existing?.health || {
|
|
31
|
+
status: 'unknown',
|
|
32
|
+
summary: 'Workspace health has not been checked.',
|
|
33
|
+
issues: [],
|
|
34
|
+
};
|
|
35
|
+
this.db.prepare(`
|
|
36
|
+
INSERT INTO workspace_registry (
|
|
37
|
+
id, display_name, path, device_id, default_runtime_id, git_json, health_json, metadata_json, created_at, updated_at, last_opened_at
|
|
38
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
39
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
40
|
+
display_name = excluded.display_name,
|
|
41
|
+
path = excluded.path,
|
|
42
|
+
device_id = excluded.device_id,
|
|
43
|
+
default_runtime_id = excluded.default_runtime_id,
|
|
44
|
+
git_json = excluded.git_json,
|
|
45
|
+
health_json = excluded.health_json,
|
|
46
|
+
metadata_json = excluded.metadata_json,
|
|
47
|
+
updated_at = excluded.updated_at
|
|
48
|
+
`).run(id, input.displayName, input.path, input.deviceId, input.defaultRuntimeId || null, JSON.stringify(input.git || existing?.git || {}), JSON.stringify(health), JSON.stringify(input.metadata || existing?.metadata || {}), existing?.createdAt || now, now, existing?.lastOpenedAt || null);
|
|
49
|
+
return this.get(id);
|
|
50
|
+
}
|
|
51
|
+
update(workspaceId, input) {
|
|
52
|
+
const existing = this.get(workspaceId);
|
|
53
|
+
if (!existing) {
|
|
54
|
+
throw new Error(`Workspace not found: ${workspaceId}`);
|
|
55
|
+
}
|
|
56
|
+
return this.upsert({
|
|
57
|
+
workspaceId,
|
|
58
|
+
displayName: input.displayName || existing.displayName,
|
|
59
|
+
path: input.path || existing.path,
|
|
60
|
+
deviceId: existing.deviceId,
|
|
61
|
+
defaultRuntimeId: input.defaultRuntimeId === null ? undefined : input.defaultRuntimeId || existing.defaultRuntimeId,
|
|
62
|
+
git: existing.git,
|
|
63
|
+
health: existing.health,
|
|
64
|
+
metadata: input.metadata || existing.metadata,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
delete(workspaceId) {
|
|
68
|
+
this.db.prepare('DELETE FROM workspace_registry WHERE id = ?').run(workspaceId);
|
|
69
|
+
return { deleted: true };
|
|
70
|
+
}
|
|
71
|
+
touch(workspaceId) {
|
|
72
|
+
this.db.prepare('UPDATE workspace_registry SET last_opened_at = ?, updated_at = ? WHERE id = ?')
|
|
73
|
+
.run(new Date().toISOString(), new Date().toISOString(), workspaceId);
|
|
74
|
+
}
|
|
75
|
+
toEntry(row) {
|
|
76
|
+
const activeTaskCount = Number(this.db.prepare(`
|
|
77
|
+
SELECT COUNT(*) AS total
|
|
78
|
+
FROM agent_tasks
|
|
79
|
+
WHERE workspace_id = ? AND status IN ('created', 'queued', 'running', 'waiting_for_user')
|
|
80
|
+
`).get(row.id)?.total || 0);
|
|
81
|
+
const recentTaskRows = this.db.prepare(`
|
|
82
|
+
SELECT id
|
|
83
|
+
FROM agent_tasks
|
|
84
|
+
WHERE workspace_id = ?
|
|
85
|
+
ORDER BY updated_at DESC
|
|
86
|
+
LIMIT 8
|
|
87
|
+
`).all(row.id);
|
|
88
|
+
return {
|
|
89
|
+
workspaceId: row.id,
|
|
90
|
+
displayName: row.display_name,
|
|
91
|
+
path: row.path,
|
|
92
|
+
deviceId: row.device_id,
|
|
93
|
+
createdAt: row.created_at,
|
|
94
|
+
updatedAt: row.updated_at,
|
|
95
|
+
lastOpenedAt: row.last_opened_at || undefined,
|
|
96
|
+
defaultRuntimeId: row.default_runtime_id || undefined,
|
|
97
|
+
git: (0, utils_js_1.parseJson)(row.git_json, { isRepo: false }),
|
|
98
|
+
health: (0, utils_js_1.parseJson)(row.health_json, {
|
|
99
|
+
status: 'unknown',
|
|
100
|
+
summary: 'Workspace health has not been checked.',
|
|
101
|
+
issues: [],
|
|
102
|
+
}),
|
|
103
|
+
activeTaskCount,
|
|
104
|
+
recentTaskIds: recentTaskRows.map((item) => item.id),
|
|
105
|
+
metadata: (0, utils_js_1.parseJson)(row.metadata_json, {}),
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
exports.LocalWorkspaceRegistryStore = LocalWorkspaceRegistryStore;
|