@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.
Files changed (106) hide show
  1. package/README.md +10 -0
  2. package/dist/renderer/assets/{Badge-D-WU4kUV.js → Badge-Qk9qHovH.js} +1 -1
  3. package/dist/renderer/assets/{Chat-BGkC5tAe.js → Chat-BK-fm0Xr.js} +1 -1
  4. package/dist/renderer/assets/{ChatMarkdown-CfbC1jRd.js → ChatMarkdown-BKdW8OON.js} +1 -1
  5. package/dist/renderer/assets/{Config-qQb4bX5D.js → Config-B93CQGvY.js} +2 -2
  6. package/dist/renderer/assets/CronList-Z3TvSRKP.js +1 -0
  7. package/dist/renderer/assets/{Dashboard-xn6cUy_n.js → Dashboard-Ch3QkWwf.js} +2 -2
  8. package/dist/renderer/assets/{EmptyState-BdKBBUpr.js → EmptyState-kD9yAwtw.js} +1 -1
  9. package/dist/renderer/assets/{KnowledgeDetail-Duk8IQP3.js → KnowledgeDetail-BAMCLrjz.js} +2 -2
  10. package/dist/renderer/assets/{KnowledgeHome-BfjX_4Sv.js → KnowledgeHome-ChvjOfrc.js} +2 -2
  11. package/dist/renderer/assets/{Logs-Bfq61QMn.js → Logs-Cv0nth3j.js} +1 -1
  12. package/dist/renderer/assets/{Modal-B3vlBmBr.js → Modal-DwY4lecS.js} +1 -1
  13. package/dist/renderer/assets/MonitorList-JEvMoWUm.js +1 -0
  14. package/dist/renderer/assets/{Page-CPsLOP3z.js → Page-CnB9ePsb.js} +1 -1
  15. package/dist/renderer/assets/{ProjectDetail-D-g46wyF.js → ProjectDetail-DJa3sMmU.js} +2 -2
  16. package/dist/renderer/assets/{ProjectList-BrQEKDQ8.js → ProjectList-D6CXumR_.js} +1 -1
  17. package/dist/renderer/assets/{Select-C4CFMQmF.js → Select-zfoksLGB.js} +1 -1
  18. package/dist/renderer/assets/SessionChat-DUTh4WoM.js +1 -0
  19. package/dist/renderer/assets/{SessionList-DPWIUbOg.js → SessionList-D9o-lUst.js} +1 -1
  20. package/dist/renderer/assets/{ThreadChat-BjtU-j9q.js → ThreadChat-BYXlT-Kc.js} +7 -7
  21. package/dist/renderer/assets/{Workspace-BcNmHuJx.js → Workspace-BrhSwRQ-.js} +1 -1
  22. package/dist/renderer/assets/{arrow-left-DPzSmidS.js → arrow-left-CNEAuElg.js} +1 -1
  23. package/dist/renderer/assets/{book-open-B0xhoRqZ.js → book-open-BNJMhNI-.js} +1 -1
  24. package/dist/renderer/assets/{check-BTJTyd0C.js → check-BnclClRU.js} +1 -1
  25. package/dist/renderer/assets/{chevron-down-B6jJXlhi.js → chevron-down-Bh53e0O-.js} +1 -1
  26. package/dist/renderer/assets/{circle-qRhJR9qR.js → circle-ClZTWCWO.js} +1 -1
  27. package/dist/renderer/assets/desktop-C5vBT0yM.js +1 -0
  28. package/dist/renderer/assets/desktop-C6q6wBae.js +5 -0
  29. package/dist/renderer/assets/en-D2SkCrhG.js +1 -0
  30. package/dist/renderer/assets/{funnel-CbYKGTn8.js → funnel-_5hsz0xI.js} +1 -1
  31. package/dist/renderer/assets/{heart-DjwWJfkz.js → heart-u4Q1aOqj.js} +1 -1
  32. package/dist/renderer/assets/{index-BWmHJRhe.js → index-B36eowj-.js} +39 -34
  33. package/dist/renderer/assets/{index-CyZs_2NJ.js → index-BNFx4uYv.js} +3 -3
  34. package/dist/renderer/assets/{pencil-1dfAivmj.js → pencil-DLh9QNmT.js} +1 -1
  35. package/dist/renderer/assets/{play-CB3w1G6S.js → play-BDTk9Scm.js} +1 -1
  36. package/dist/renderer/assets/{plug-Bvep5o3r.js → plug-BG0JHW6B.js} +1 -1
  37. package/dist/renderer/assets/{plus-DJVg9m09.js → plus-BSc8POsz.js} +1 -1
  38. package/dist/renderer/assets/projects-DwfZwxDW.js +1 -0
  39. package/dist/renderer/assets/{save-xjJn3qf2.js → save-D5AO_G6a.js} +1 -1
  40. package/dist/renderer/assets/{search-BK3UrQxM.js → search-CniPk7Ey.js} +1 -1
  41. package/dist/renderer/assets/{server-Dyd2eXJu.js → server-GsXyQAZm.js} +1 -1
  42. package/dist/renderer/assets/{session-utils-eXC0020s.js → session-utils-BDxzgTBC.js} +1 -1
  43. package/dist/renderer/assets/{sessions-WLYpkyUt.js → sessions-CLcKA1Tt.js} +1 -1
  44. package/dist/renderer/assets/{shield-check-C0N6aWzF.js → shield-check-4i0E3hmf.js} +1 -1
  45. package/dist/renderer/assets/{trash-2-BGMTNJA6.js → trash-2-DhtOCsO5.js} +1 -1
  46. package/dist/renderer/assets/{user-BcGMLyhu.js → user-BtC_pVXV.js} +1 -1
  47. package/dist/renderer/assets/{wifi-off-FhcQx0HK.js → wifi-off-BHPzPY_B.js} +1 -1
  48. package/dist/renderer/assets/zh-DIcdHycM.js +1 -0
  49. package/dist/renderer/index.html +1 -1
  50. package/dist-electron/packages/contracts/src/local-core.js +28 -0
  51. package/dist-electron/packages/core-sdk/src/index.js +32 -0
  52. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-backend.js +51 -0
  53. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-store.js +4 -1364
  54. package/dist-electron/services/local-ai-core/src/acp/store/agent-task-store.js +166 -0
  55. package/dist-electron/services/local-ai-core/src/acp/store/automation-monitor-store.js +231 -0
  56. package/dist-electron/services/local-ai-core/src/acp/store/local-core-acp-store.js +263 -0
  57. package/dist-electron/services/local-ai-core/src/acp/store/platform-store.js +186 -0
  58. package/dist-electron/services/local-ai-core/src/acp/store/scheduler-store.js +201 -0
  59. package/dist-electron/services/local-ai-core/src/acp/store/schema.js +275 -0
  60. package/dist-electron/services/local-ai-core/src/acp/store/security-store.js +266 -0
  61. package/dist-electron/services/local-ai-core/src/acp/store/thread-store.js +232 -0
  62. package/dist-electron/services/local-ai-core/src/acp/store/utils.js +47 -0
  63. package/dist-electron/services/local-ai-core/src/acp/store/workspace-registry-store.js +109 -0
  64. package/dist-electron/services/local-ai-core/src/automation/automation-conversation-executor.js +136 -0
  65. package/dist-electron/services/local-ai-core/src/automation/automation-monitor-repository.js +56 -0
  66. package/dist-electron/services/local-ai-core/src/automation/automation-monitor-service.js +359 -0
  67. package/dist-electron/services/local-ai-core/src/automation/condition-evaluator.js +77 -0
  68. package/dist-electron/services/local-ai-core/src/automation/mock-stock-provider.js +40 -0
  69. package/dist-electron/services/local-ai-core/src/automation/monitor-id.js +10 -0
  70. package/dist-electron/services/local-ai-core/src/channel/lark/cards.js +55 -0
  71. package/dist-electron/services/local-ai-core/src/channel/lark/config.js +2 -0
  72. package/dist-electron/services/local-ai-core/src/channel/lark/inbound.js +114 -0
  73. package/dist-electron/services/local-ai-core/src/channel/lark/local-core-lark-gateway.js +153 -94
  74. package/dist-electron/services/local-ai-core/src/channel/shared/session-command-runtime.js +53 -0
  75. package/dist-electron/services/local-ai-core/src/channel/shared/thread-routing.js +34 -0
  76. package/dist-electron/services/local-ai-core/src/channel/weixin/local-core-weixin-gateway.js +63 -51
  77. package/dist-electron/services/local-ai-core/src/cli/lac.js +196 -0
  78. package/dist-electron/services/local-ai-core/src/cli/monitor-cli-parsers.js +37 -0
  79. package/dist-electron/services/local-ai-core/src/kernel/bootstrap.js +43 -0
  80. package/dist-electron/services/local-ai-core/src/kernel/capability-registry.js +12 -0
  81. package/dist-electron/services/local-ai-core/src/plugins/builtin/monitor-stock-plugin.js +30 -0
  82. package/dist-electron/services/local-ai-core/src/runtime/local-core-controller.js +41 -0
  83. package/dist-electron/services/local-ai-core/src/runtime/server-routes.js +31 -0
  84. package/dist-electron/services/local-ai-core/src/runtime/server.js +36 -0
  85. package/dist-electron/services/local-ai-core/src/scheduler/scheduled-bridge-session.js +25 -11
  86. package/dist-electron/services/local-ai-core/src/thread/session-command-service.js +275 -0
  87. package/dist-electron/services/local-ai-core/src/thread/slash-command-registry.js +27 -0
  88. package/dist-electron/services/local-ai-core/src/thread/thread-command-service.js +15 -15
  89. package/dist-electron/shared/desktop.js +21 -1
  90. package/dist-electron/tests/contracts/local-core-contracts.test.js +9 -0
  91. package/dist-electron/tests/electron/automation-monitor.test.js +38 -0
  92. package/dist-electron/tests/electron/lac-cli.test.js +146 -0
  93. package/dist-electron/tests/integration/channel-gateways.test.js +32 -0
  94. package/dist-electron/tests/integration/lark-gateway.test.js +1918 -0
  95. package/dist-electron/tests/integration/local-core-acp-progress.test.js +1772 -0
  96. package/dist-electron/tests/integration/local-core-refactor.test.js +216 -4566
  97. package/dist-electron/tests/integration/local-core-routes.test.js +204 -0
  98. package/dist-electron/tests/integration/weixin-gateway.test.js +927 -0
  99. package/package.json +1 -1
  100. package/dist/renderer/assets/CronList-CKhggzYk.js +0 -1
  101. package/dist/renderer/assets/SessionChat-06Jny5_G.js +0 -1
  102. package/dist/renderer/assets/desktop-DXmXjjUR.js +0 -1
  103. package/dist/renderer/assets/desktop-O8_6ZCVZ.js +0 -4
  104. package/dist/renderer/assets/en-CKhCF6St.js +0 -1
  105. package/dist/renderer/assets/projects-xnW0fTtq.js +0 -1
  106. 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;