natroc 0.0.1

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 (183) hide show
  1. package/AGENTS.md +494 -0
  2. package/LICENSE +7 -0
  3. package/README.md +0 -0
  4. package/install.ps1 +109 -0
  5. package/install.sh +132 -0
  6. package/package.json +77 -0
  7. package/server/dist/agent/agent-loop.d.ts +71 -0
  8. package/server/dist/agent/agent-loop.js +171 -0
  9. package/server/dist/agent/agent-loop.js.map +1 -0
  10. package/server/dist/agent/home-context.d.ts +29 -0
  11. package/server/dist/agent/home-context.js +134 -0
  12. package/server/dist/agent/home-context.js.map +1 -0
  13. package/server/dist/agent/improvement-engine.d.ts +23 -0
  14. package/server/dist/agent/improvement-engine.js +107 -0
  15. package/server/dist/agent/improvement-engine.js.map +1 -0
  16. package/server/dist/agent/tools/index.d.ts +14 -0
  17. package/server/dist/agent/tools/index.js +85 -0
  18. package/server/dist/agent/tools/index.js.map +1 -0
  19. package/server/dist/agent/tools/list-directory.d.ts +2 -0
  20. package/server/dist/agent/tools/list-directory.js +27 -0
  21. package/server/dist/agent/tools/list-directory.js.map +1 -0
  22. package/server/dist/agent/tools/read-file.d.ts +2 -0
  23. package/server/dist/agent/tools/read-file.js +30 -0
  24. package/server/dist/agent/tools/read-file.js.map +1 -0
  25. package/server/dist/agent/tools/run-command.d.ts +2 -0
  26. package/server/dist/agent/tools/run-command.js +72 -0
  27. package/server/dist/agent/tools/run-command.js.map +1 -0
  28. package/server/dist/agent/tools/system-info.d.ts +2 -0
  29. package/server/dist/agent/tools/system-info.js +28 -0
  30. package/server/dist/agent/tools/system-info.js.map +1 -0
  31. package/server/dist/agent/tools/types.d.ts +18 -0
  32. package/server/dist/agent/tools/types.js +2 -0
  33. package/server/dist/agent/tools/types.js.map +1 -0
  34. package/server/dist/agent/tools/util.d.ts +7 -0
  35. package/server/dist/agent/tools/util.js +24 -0
  36. package/server/dist/agent/tools/util.js.map +1 -0
  37. package/server/dist/agent/tools/write-file.d.ts +2 -0
  38. package/server/dist/agent/tools/write-file.js +25 -0
  39. package/server/dist/agent/tools/write-file.js.map +1 -0
  40. package/server/dist/app.d.ts +8 -0
  41. package/server/dist/app.js +39 -0
  42. package/server/dist/app.js.map +1 -0
  43. package/server/dist/auth/password.d.ts +7 -0
  44. package/server/dist/auth/password.js +20 -0
  45. package/server/dist/auth/password.js.map +1 -0
  46. package/server/dist/channels/channel-runtime.d.ts +32 -0
  47. package/server/dist/channels/channel-runtime.js +484 -0
  48. package/server/dist/channels/channel-runtime.js.map +1 -0
  49. package/server/dist/cli/agent-deliver.d.ts +14 -0
  50. package/server/dist/cli/agent-deliver.js +183 -0
  51. package/server/dist/cli/agent-deliver.js.map +1 -0
  52. package/server/dist/cli/args.d.ts +11 -0
  53. package/server/dist/cli/args.js +57 -0
  54. package/server/dist/cli/args.js.map +1 -0
  55. package/server/dist/cli/cli-token.d.ts +1 -0
  56. package/server/dist/cli/cli-token.js +22 -0
  57. package/server/dist/cli/cli-token.js.map +1 -0
  58. package/server/dist/cli/daemon.d.ts +2 -0
  59. package/server/dist/cli/daemon.js +252 -0
  60. package/server/dist/cli/daemon.js.map +1 -0
  61. package/server/dist/cli.d.ts +2 -0
  62. package/server/dist/cli.js +416 -0
  63. package/server/dist/cli.js.map +1 -0
  64. package/server/dist/config/natroc-home.d.ts +13 -0
  65. package/server/dist/config/natroc-home.js +730 -0
  66. package/server/dist/config/natroc-home.js.map +1 -0
  67. package/server/dist/gateway/agent-service.d.ts +16 -0
  68. package/server/dist/gateway/agent-service.js +261 -0
  69. package/server/dist/gateway/agent-service.js.map +1 -0
  70. package/server/dist/gateway/connection.d.ts +38 -0
  71. package/server/dist/gateway/connection.js +254 -0
  72. package/server/dist/gateway/connection.js.map +1 -0
  73. package/server/dist/gateway/gateway.d.ts +79 -0
  74. package/server/dist/gateway/gateway.js +150 -0
  75. package/server/dist/gateway/gateway.js.map +1 -0
  76. package/server/dist/gateway/index.d.ts +8 -0
  77. package/server/dist/gateway/index.js +26 -0
  78. package/server/dist/gateway/index.js.map +1 -0
  79. package/server/dist/gateway/protocol.d.ts +102 -0
  80. package/server/dist/gateway/protocol.js +63 -0
  81. package/server/dist/gateway/protocol.js.map +1 -0
  82. package/server/dist/gateway/rpc/agent.d.ts +3 -0
  83. package/server/dist/gateway/rpc/agent.js +174 -0
  84. package/server/dist/gateway/rpc/agent.js.map +1 -0
  85. package/server/dist/gateway/rpc/agents.d.ts +2 -0
  86. package/server/dist/gateway/rpc/agents.js +68 -0
  87. package/server/dist/gateway/rpc/agents.js.map +1 -0
  88. package/server/dist/gateway/rpc/auth.d.ts +3 -0
  89. package/server/dist/gateway/rpc/auth.js +180 -0
  90. package/server/dist/gateway/rpc/auth.js.map +1 -0
  91. package/server/dist/gateway/rpc/channels.d.ts +2 -0
  92. package/server/dist/gateway/rpc/channels.js +230 -0
  93. package/server/dist/gateway/rpc/channels.js.map +1 -0
  94. package/server/dist/gateway/rpc/conversations.d.ts +3 -0
  95. package/server/dist/gateway/rpc/conversations.js +36 -0
  96. package/server/dist/gateway/rpc/conversations.js.map +1 -0
  97. package/server/dist/gateway/rpc/projects.d.ts +3 -0
  98. package/server/dist/gateway/rpc/projects.js +49 -0
  99. package/server/dist/gateway/rpc/projects.js.map +1 -0
  100. package/server/dist/gateway/rpc/providers.d.ts +3 -0
  101. package/server/dist/gateway/rpc/providers.js +106 -0
  102. package/server/dist/gateway/rpc/providers.js.map +1 -0
  103. package/server/dist/gateway/rpc/usage.d.ts +2 -0
  104. package/server/dist/gateway/rpc/usage.js +41 -0
  105. package/server/dist/gateway/rpc/usage.js.map +1 -0
  106. package/server/dist/gateway/types.d.ts +43 -0
  107. package/server/dist/gateway/types.js +20 -0
  108. package/server/dist/gateway/types.js.map +1 -0
  109. package/server/dist/gateway/ws-server.d.ts +10 -0
  110. package/server/dist/gateway/ws-server.js +37 -0
  111. package/server/dist/gateway/ws-server.js.map +1 -0
  112. package/server/dist/index.d.ts +1 -0
  113. package/server/dist/index.js +9 -0
  114. package/server/dist/index.js.map +1 -0
  115. package/server/dist/local-runtime.d.ts +9 -0
  116. package/server/dist/local-runtime.js +16 -0
  117. package/server/dist/local-runtime.js.map +1 -0
  118. package/server/dist/providers/configured-adapters.d.ts +9 -0
  119. package/server/dist/providers/configured-adapters.js +34 -0
  120. package/server/dist/providers/configured-adapters.js.map +1 -0
  121. package/server/dist/providers/ollama.d.ts +23 -0
  122. package/server/dist/providers/ollama.js +164 -0
  123. package/server/dist/providers/ollama.js.map +1 -0
  124. package/server/dist/providers/openrouter.d.ts +24 -0
  125. package/server/dist/providers/openrouter.js +201 -0
  126. package/server/dist/providers/openrouter.js.map +1 -0
  127. package/server/dist/providers/thinking.d.ts +18 -0
  128. package/server/dist/providers/thinking.js +58 -0
  129. package/server/dist/providers/thinking.js.map +1 -0
  130. package/server/dist/providers/types.d.ts +55 -0
  131. package/server/dist/providers/types.js +2 -0
  132. package/server/dist/providers/types.js.map +1 -0
  133. package/server/dist/routes/schemas.d.ts +51 -0
  134. package/server/dist/routes/schemas.js +53 -0
  135. package/server/dist/routes/schemas.js.map +1 -0
  136. package/server/dist/runtime.d.ts +47 -0
  137. package/server/dist/runtime.js +29 -0
  138. package/server/dist/runtime.js.map +1 -0
  139. package/server/dist/server.d.ts +11 -0
  140. package/server/dist/server.js +19 -0
  141. package/server/dist/server.js.map +1 -0
  142. package/server/dist/storage/agent-repository.d.ts +59 -0
  143. package/server/dist/storage/agent-repository.js +192 -0
  144. package/server/dist/storage/agent-repository.js.map +1 -0
  145. package/server/dist/storage/auth-repository.d.ts +49 -0
  146. package/server/dist/storage/auth-repository.js +139 -0
  147. package/server/dist/storage/auth-repository.js.map +1 -0
  148. package/server/dist/storage/channel-repository.d.ts +152 -0
  149. package/server/dist/storage/channel-repository.js +413 -0
  150. package/server/dist/storage/channel-repository.js.map +1 -0
  151. package/server/dist/storage/conversation-repository.d.ts +63 -0
  152. package/server/dist/storage/conversation-repository.js +196 -0
  153. package/server/dist/storage/conversation-repository.js.map +1 -0
  154. package/server/dist/storage/database.d.ts +11 -0
  155. package/server/dist/storage/database.js +360 -0
  156. package/server/dist/storage/database.js.map +1 -0
  157. package/server/dist/storage/memory-repository.d.ts +70 -0
  158. package/server/dist/storage/memory-repository.js +279 -0
  159. package/server/dist/storage/memory-repository.js.map +1 -0
  160. package/server/dist/storage/project-repository.d.ts +25 -0
  161. package/server/dist/storage/project-repository.js +67 -0
  162. package/server/dist/storage/project-repository.js.map +1 -0
  163. package/server/dist/storage/provider-repository.d.ts +44 -0
  164. package/server/dist/storage/provider-repository.js +159 -0
  165. package/server/dist/storage/provider-repository.js.map +1 -0
  166. package/server/dist/storage/tool-call-repository.d.ts +35 -0
  167. package/server/dist/storage/tool-call-repository.js +83 -0
  168. package/server/dist/storage/tool-call-repository.js.map +1 -0
  169. package/server/dist/storage/usage-repository.d.ts +76 -0
  170. package/server/dist/storage/usage-repository.js +249 -0
  171. package/server/dist/storage/usage-repository.js.map +1 -0
  172. package/server/dist/storage/vault.d.ts +3 -0
  173. package/server/dist/storage/vault.js +57 -0
  174. package/server/dist/storage/vault.js.map +1 -0
  175. package/ui/README.md +0 -0
  176. package/ui/dist/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
  177. package/ui/dist/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
  178. package/ui/dist/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
  179. package/ui/dist/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
  180. package/ui/dist/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
  181. package/ui/dist/assets/index-DKaFmZNO.js +114 -0
  182. package/ui/dist/assets/index-DOfPcjx3.css +2 -0
  183. package/ui/dist/index.html +14 -0
@@ -0,0 +1,413 @@
1
+ /**
2
+ * Default policy. `allowlist` di DM + `disabled` di group adalah default
3
+ * konservatif: tidak akan membalas siapa pun yang tidak diizinkan eksplisit.
4
+ */
5
+ export const DEFAULT_CHANNEL_POLICY = {
6
+ dmPolicy: "allowlist",
7
+ groupPolicy: "disabled",
8
+ groupAllowFrom: [],
9
+ textChunkLimit: 4000,
10
+ chunkMode: "length",
11
+ mediaMaxMb: 50,
12
+ sendReadReceipts: false,
13
+ requireMention: true,
14
+ };
15
+ /** Mengambil policy efektif (defaults + override dari `account.metadata.policy`). */
16
+ export function getAccountPolicy(account) {
17
+ const raw = account.metadata.policy;
18
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
19
+ return { ...DEFAULT_CHANNEL_POLICY };
20
+ }
21
+ const policy = raw;
22
+ return {
23
+ dmPolicy: isDmPolicyValue(policy.dmPolicy)
24
+ ? policy.dmPolicy
25
+ : DEFAULT_CHANNEL_POLICY.dmPolicy,
26
+ groupPolicy: isGroupPolicyValue(policy.groupPolicy)
27
+ ? policy.groupPolicy
28
+ : DEFAULT_CHANNEL_POLICY.groupPolicy,
29
+ groupAllowFrom: Array.isArray(policy.groupAllowFrom)
30
+ ? policy.groupAllowFrom.filter((item) => typeof item === "string")
31
+ : [...DEFAULT_CHANNEL_POLICY.groupAllowFrom],
32
+ textChunkLimit: typeof policy.textChunkLimit === "number" && policy.textChunkLimit > 0
33
+ ? Math.floor(policy.textChunkLimit)
34
+ : DEFAULT_CHANNEL_POLICY.textChunkLimit,
35
+ chunkMode: policy.chunkMode === "length" ? "length" : "length",
36
+ mediaMaxMb: typeof policy.mediaMaxMb === "number" && policy.mediaMaxMb > 0
37
+ ? policy.mediaMaxMb
38
+ : DEFAULT_CHANNEL_POLICY.mediaMaxMb,
39
+ sendReadReceipts: typeof policy.sendReadReceipts === "boolean"
40
+ ? policy.sendReadReceipts
41
+ : DEFAULT_CHANNEL_POLICY.sendReadReceipts,
42
+ requireMention: typeof policy.requireMention === "boolean"
43
+ ? policy.requireMention
44
+ : DEFAULT_CHANNEL_POLICY.requireMention,
45
+ };
46
+ }
47
+ function isDmPolicyValue(value) {
48
+ return (value === "pairing" ||
49
+ value === "allowlist" ||
50
+ value === "open" ||
51
+ value === "disabled");
52
+ }
53
+ function isGroupPolicyValue(value) {
54
+ return value === "allowlist" || value === "open" || value === "disabled";
55
+ }
56
+ export class ChannelRepository {
57
+ db;
58
+ constructor(db) {
59
+ this.db = db;
60
+ }
61
+ listAccounts(options) {
62
+ const rows = this.db
63
+ .prepare(`
64
+ SELECT * FROM channel_accounts
65
+ WHERE user_id = ?
66
+ ORDER BY channel ASC, updated_at DESC
67
+ `)
68
+ .all(options.userId);
69
+ return rows.map(mapAccountRow);
70
+ }
71
+ listAccountsForRuntime() {
72
+ const rows = this.db
73
+ .prepare(`
74
+ SELECT * FROM channel_accounts
75
+ WHERE is_enabled = 1
76
+ ORDER BY channel ASC, updated_at DESC
77
+ `)
78
+ .all();
79
+ return rows.map(mapAccountRow);
80
+ }
81
+ getAccount(options) {
82
+ const row = this.db
83
+ .prepare("SELECT * FROM channel_accounts WHERE user_id = ? AND id = ?")
84
+ .get(options.userId, options.id);
85
+ return row ? mapAccountRow(row) : null;
86
+ }
87
+ createAccount(input) {
88
+ const id = crypto.randomUUID();
89
+ const now = new Date().toISOString();
90
+ this.db
91
+ .prepare(`
92
+ INSERT INTO channel_accounts (
93
+ id,
94
+ user_id,
95
+ channel,
96
+ display_name,
97
+ account_ref,
98
+ secret_ref,
99
+ status,
100
+ is_enabled,
101
+ allowlist_json,
102
+ metadata_json,
103
+ last_error,
104
+ connected_at,
105
+ created_at,
106
+ updated_at
107
+ )
108
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?)
109
+ `)
110
+ .run(id, input.userId, input.channel, normalizeName(input.displayName), normalizeOptional(input.accountRef), input.secretRef ?? null, input.status ?? "disconnected", input.isEnabled === false ? 0 : 1, JSON.stringify(input.allowlist ?? []), JSON.stringify(input.metadata ?? {}), input.lastError ?? null, now, now);
111
+ return (this.getAccount({ userId: input.userId, id }) ??
112
+ failPersisted("Channel account"));
113
+ }
114
+ updateAccount(input) {
115
+ const existing = this.getAccount(input);
116
+ if (!existing) {
117
+ throw new Error("Channel account not found.");
118
+ }
119
+ const now = new Date().toISOString();
120
+ this.db
121
+ .prepare(`
122
+ UPDATE channel_accounts
123
+ SET
124
+ channel = ?,
125
+ display_name = ?,
126
+ account_ref = ?,
127
+ secret_ref = ?,
128
+ status = ?,
129
+ is_enabled = ?,
130
+ allowlist_json = ?,
131
+ metadata_json = ?,
132
+ last_error = ?,
133
+ connected_at = ?,
134
+ updated_at = ?
135
+ WHERE user_id = ? AND id = ?
136
+ `)
137
+ .run(input.channel ?? existing.channel, input.displayName === undefined
138
+ ? existing.displayName
139
+ : normalizeName(input.displayName), input.accountRef === undefined
140
+ ? existing.accountRef
141
+ : normalizeOptional(input.accountRef), input.secretRef === undefined ? existing.secretRef : input.secretRef, input.status ?? existing.status, input.isEnabled === undefined
142
+ ? existing.isEnabled
143
+ ? 1
144
+ : 0
145
+ : input.isEnabled
146
+ ? 1
147
+ : 0, JSON.stringify(input.allowlist ?? existing.allowlist), JSON.stringify(input.metadata ?? existing.metadata), input.lastError === undefined ? existing.lastError : input.lastError, input.connectedAt === undefined
148
+ ? existing.connectedAt
149
+ : input.connectedAt, now, input.userId, input.id);
150
+ return this.getAccount(input) ?? failPersisted("Channel account");
151
+ }
152
+ deleteAccount(options) {
153
+ const result = this.db
154
+ .prepare("DELETE FROM channel_accounts WHERE user_id = ? AND id = ?")
155
+ .run(options.userId, options.id);
156
+ return Number(result.changes) > 0;
157
+ }
158
+ setSecret(input) {
159
+ const now = new Date().toISOString();
160
+ this.db
161
+ .prepare(`
162
+ INSERT INTO channel_secrets (
163
+ secret_ref,
164
+ user_id,
165
+ channel,
166
+ encrypted_value,
167
+ created_at,
168
+ updated_at
169
+ )
170
+ VALUES (?, ?, ?, ?, ?, ?)
171
+ ON CONFLICT(secret_ref) DO UPDATE SET
172
+ encrypted_value = excluded.encrypted_value,
173
+ updated_at = excluded.updated_at
174
+ `)
175
+ .run(input.secretRef, input.userId, input.channel, input.encryptedValue, now, now);
176
+ }
177
+ getSecret(options) {
178
+ const row = this.db
179
+ .prepare("SELECT encrypted_value FROM channel_secrets WHERE user_id = ? AND secret_ref = ?")
180
+ .get(options.userId, options.secretRef);
181
+ return row?.encrypted_value ?? null;
182
+ }
183
+ listBindings(options) {
184
+ const rows = this.db
185
+ .prepare(`
186
+ SELECT * FROM channel_bindings
187
+ WHERE user_id = ?
188
+ ORDER BY updated_at DESC, rowid DESC
189
+ `)
190
+ .all(options.userId);
191
+ return rows.map(mapBindingRow);
192
+ }
193
+ createBinding(input) {
194
+ const id = crypto.randomUUID();
195
+ const now = new Date().toISOString();
196
+ this.assertAccountBelongsToUser(input.userId, input.accountId);
197
+ this.db
198
+ .prepare(`
199
+ INSERT INTO channel_bindings (
200
+ id,
201
+ user_id,
202
+ account_id,
203
+ agent_id,
204
+ peer,
205
+ is_enabled,
206
+ created_at,
207
+ updated_at
208
+ )
209
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
210
+ ON CONFLICT(user_id, account_id, peer) DO UPDATE SET
211
+ agent_id = excluded.agent_id,
212
+ is_enabled = excluded.is_enabled,
213
+ updated_at = excluded.updated_at
214
+ `)
215
+ .run(id, input.userId, input.accountId, input.agentId, normalizePeer(input.peer), input.isEnabled === false ? 0 : 1, now, now);
216
+ return (this.resolveBinding({
217
+ userId: input.userId,
218
+ accountId: input.accountId,
219
+ peer: input.peer,
220
+ }) ?? failPersisted("Channel binding"));
221
+ }
222
+ updateBinding(input) {
223
+ const existing = this.getBinding({ userId: input.userId, id: input.id });
224
+ if (!existing) {
225
+ throw new Error("Channel binding not found.");
226
+ }
227
+ const now = new Date().toISOString();
228
+ this.db
229
+ .prepare(`
230
+ UPDATE channel_bindings
231
+ SET agent_id = ?, peer = ?, is_enabled = ?, updated_at = ?
232
+ WHERE user_id = ? AND id = ?
233
+ `)
234
+ .run(input.agentId ?? existing.agentId, input.peer === undefined ? existing.peer : normalizePeer(input.peer), input.isEnabled === undefined
235
+ ? existing.isEnabled
236
+ ? 1
237
+ : 0
238
+ : input.isEnabled
239
+ ? 1
240
+ : 0, now, input.userId, input.id);
241
+ return (this.getBinding({ userId: input.userId, id: input.id }) ??
242
+ failPersisted("Channel binding"));
243
+ }
244
+ deleteBinding(options) {
245
+ const result = this.db
246
+ .prepare("DELETE FROM channel_bindings WHERE user_id = ? AND id = ?")
247
+ .run(options.userId, options.id);
248
+ return Number(result.changes) > 0;
249
+ }
250
+ resolveBinding(options) {
251
+ const exact = this.db
252
+ .prepare(`
253
+ SELECT * FROM channel_bindings
254
+ WHERE user_id = ?
255
+ AND account_id = ?
256
+ AND peer = ?
257
+ AND is_enabled = 1
258
+ LIMIT 1
259
+ `)
260
+ .get(options.userId, options.accountId, normalizePeer(options.peer));
261
+ if (exact)
262
+ return mapBindingRow(exact);
263
+ const wildcard = this.db
264
+ .prepare(`
265
+ SELECT * FROM channel_bindings
266
+ WHERE user_id = ?
267
+ AND account_id = ?
268
+ AND peer = '*'
269
+ AND is_enabled = 1
270
+ LIMIT 1
271
+ `)
272
+ .get(options.userId, options.accountId);
273
+ return wildcard ? mapBindingRow(wildcard) : null;
274
+ }
275
+ createLog(input) {
276
+ const id = crypto.randomUUID();
277
+ const now = new Date().toISOString();
278
+ this.db
279
+ .prepare(`
280
+ INSERT INTO channel_logs (
281
+ id,
282
+ user_id,
283
+ account_id,
284
+ binding_id,
285
+ channel,
286
+ peer,
287
+ direction,
288
+ message_text,
289
+ status,
290
+ error,
291
+ created_at
292
+ )
293
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
294
+ `)
295
+ .run(id, input.userId, input.accountId, input.bindingId ?? null, input.channel, normalizePeer(input.peer), input.direction, input.messageText, input.status, input.error ?? null, now);
296
+ return {
297
+ id,
298
+ userId: input.userId,
299
+ accountId: input.accountId,
300
+ bindingId: input.bindingId ?? null,
301
+ channel: input.channel,
302
+ peer: normalizePeer(input.peer),
303
+ direction: input.direction,
304
+ messageText: input.messageText,
305
+ status: input.status,
306
+ error: input.error ?? null,
307
+ createdAt: now,
308
+ };
309
+ }
310
+ listLogs(options) {
311
+ const rows = this.db
312
+ .prepare(`
313
+ SELECT * FROM channel_logs
314
+ WHERE user_id = ?
315
+ ORDER BY created_at DESC, rowid DESC
316
+ LIMIT ?
317
+ `)
318
+ .all(options.userId, Math.max(1, options.limit ?? 100));
319
+ return rows.map(mapLogRow);
320
+ }
321
+ getBinding(options) {
322
+ const row = this.db
323
+ .prepare("SELECT * FROM channel_bindings WHERE user_id = ? AND id = ?")
324
+ .get(options.userId, options.id);
325
+ return row ? mapBindingRow(row) : null;
326
+ }
327
+ assertAccountBelongsToUser(userId, accountId) {
328
+ if (this.getAccount({ userId, id: accountId }))
329
+ return;
330
+ throw new Error("Channel account not found.");
331
+ }
332
+ }
333
+ function normalizeName(value) {
334
+ return value.trim().replace(/\s+/g, " ").slice(0, 80) || "Channel";
335
+ }
336
+ function normalizePeer(value) {
337
+ return value.trim() || "*";
338
+ }
339
+ function normalizeOptional(value) {
340
+ const trimmed = value?.trim();
341
+ return trimmed ? trimmed : null;
342
+ }
343
+ function safeParseObject(value) {
344
+ try {
345
+ const parsed = JSON.parse(value);
346
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed)
347
+ ? parsed
348
+ : {};
349
+ }
350
+ catch {
351
+ return {};
352
+ }
353
+ }
354
+ function safeParseStringArray(value) {
355
+ try {
356
+ const parsed = JSON.parse(value);
357
+ return Array.isArray(parsed)
358
+ ? parsed.filter((item) => typeof item === "string")
359
+ : [];
360
+ }
361
+ catch {
362
+ return [];
363
+ }
364
+ }
365
+ function mapAccountRow(row) {
366
+ return {
367
+ id: row.id,
368
+ userId: row.user_id,
369
+ channel: row.channel,
370
+ displayName: row.display_name,
371
+ accountRef: row.account_ref,
372
+ secretRef: row.secret_ref,
373
+ status: row.status,
374
+ isEnabled: row.is_enabled === 1,
375
+ allowlist: safeParseStringArray(row.allowlist_json),
376
+ metadata: safeParseObject(row.metadata_json),
377
+ lastError: row.last_error,
378
+ connectedAt: row.connected_at,
379
+ createdAt: row.created_at,
380
+ updatedAt: row.updated_at,
381
+ };
382
+ }
383
+ function mapBindingRow(row) {
384
+ return {
385
+ id: row.id,
386
+ userId: row.user_id,
387
+ accountId: row.account_id,
388
+ agentId: row.agent_id,
389
+ peer: row.peer,
390
+ isEnabled: row.is_enabled === 1,
391
+ createdAt: row.created_at,
392
+ updatedAt: row.updated_at,
393
+ };
394
+ }
395
+ function mapLogRow(row) {
396
+ return {
397
+ id: row.id,
398
+ userId: row.user_id,
399
+ accountId: row.account_id,
400
+ bindingId: row.binding_id,
401
+ channel: row.channel,
402
+ peer: row.peer,
403
+ direction: row.direction,
404
+ messageText: row.message_text,
405
+ status: row.status,
406
+ error: row.error,
407
+ createdAt: row.created_at,
408
+ };
409
+ }
410
+ function failPersisted(entity) {
411
+ throw new Error(`${entity} was not persisted.`);
412
+ }
413
+ //# sourceMappingURL=channel-repository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channel-repository.js","sourceRoot":"","sources":["../../src/storage/channel-repository.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ import type { DatabaseConnection } from "./database.js";
2
+ import type { ProviderName, ChatRole } from "../providers/types.js";
3
+ export type ConversationRecord = {
4
+ id: string;
5
+ userId: string | null;
6
+ agentId: string | null;
7
+ channel: string | null;
8
+ title: string;
9
+ activeProvider: ProviderName | null;
10
+ createdAt: string;
11
+ updatedAt: string;
12
+ };
13
+ export type MessageRecord = {
14
+ id: string;
15
+ userId: string | null;
16
+ conversationId: string;
17
+ role: ChatRole;
18
+ content: string;
19
+ provider: ProviderName | null;
20
+ model: string | null;
21
+ createdAt: string;
22
+ };
23
+ export type ConversationThreadMessage = Pick<MessageRecord, "content" | "createdAt" | "role">;
24
+ export type ConversationThreadRecord = Pick<ConversationRecord, "id" | "title" | "updatedAt"> & {
25
+ messages: ConversationThreadMessage[];
26
+ };
27
+ export declare class ConversationRepository {
28
+ private readonly db;
29
+ constructor(db: DatabaseConnection);
30
+ listConversations(options?: {
31
+ userId?: string;
32
+ }): ConversationRecord[];
33
+ listConversationThreads(options?: {
34
+ excludeConversationId?: string;
35
+ maxConversations?: number;
36
+ maxMessagesPerConversation?: number;
37
+ maxMessageCharacters?: number;
38
+ userId?: string;
39
+ }): ConversationThreadRecord[];
40
+ getMessages(conversationId: string, options?: {
41
+ userId?: string;
42
+ }): MessageRecord[];
43
+ private getRecentMessages;
44
+ ensureConversation(conversationId: string | undefined, title: string, provider: ProviderName, options?: {
45
+ userId?: string | null;
46
+ agentId?: string | null;
47
+ channel?: string | null;
48
+ }): ConversationRecord;
49
+ addMessage(input: {
50
+ userId?: string | null;
51
+ conversationId: string;
52
+ role: ChatRole;
53
+ content: string;
54
+ provider?: ProviderName | null;
55
+ model?: string | null;
56
+ }): MessageRecord;
57
+ deleteConversation(id: string, options?: {
58
+ userId?: string;
59
+ }): boolean;
60
+ getConversation(id: string, options?: {
61
+ userId?: string;
62
+ }): ConversationRecord | null;
63
+ }
@@ -0,0 +1,196 @@
1
+ export class ConversationRepository {
2
+ db;
3
+ constructor(db) {
4
+ this.db = db;
5
+ }
6
+ listConversations(options = {}) {
7
+ const rows = options.userId
8
+ ? this.db
9
+ .prepare("SELECT * FROM conversations WHERE user_id = ? ORDER BY updated_at DESC")
10
+ .all(options.userId)
11
+ : this.db
12
+ .prepare("SELECT * FROM conversations ORDER BY updated_at DESC")
13
+ .all();
14
+ return rows.map(mapConversationRow);
15
+ }
16
+ listConversationThreads(options = {}) {
17
+ const maxConversations = options.maxConversations === undefined
18
+ ? undefined
19
+ : Math.max(1, options.maxConversations);
20
+ const maxMessagesPerConversation = Math.max(1, options.maxMessagesPerConversation ?? 6);
21
+ const maxMessageCharacters = Math.max(12, options.maxMessageCharacters ?? 700);
22
+ const conversations = this.listConversations({ userId: options.userId })
23
+ .filter((conversation) => conversation.id !== options.excludeConversationId)
24
+ .slice(0, maxConversations);
25
+ return conversations.flatMap((conversation) => {
26
+ const messages = this.getRecentMessages(conversation.id, maxMessagesPerConversation, { userId: options.userId }).map((message) => ({
27
+ ...message,
28
+ content: truncateMessageContent(normalizeMessageContent(message.content), maxMessageCharacters)
29
+ }));
30
+ if (messages.length === 0)
31
+ return [];
32
+ return [
33
+ {
34
+ id: conversation.id,
35
+ title: conversation.title,
36
+ updatedAt: conversation.updatedAt,
37
+ messages
38
+ }
39
+ ];
40
+ });
41
+ }
42
+ getMessages(conversationId, options = {}) {
43
+ const rows = options.userId
44
+ ? this.db
45
+ .prepare("SELECT * FROM messages WHERE conversation_id = ? AND user_id = ? ORDER BY created_at ASC, rowid ASC")
46
+ .all(conversationId, options.userId)
47
+ : this.db
48
+ .prepare("SELECT * FROM messages WHERE conversation_id = ? ORDER BY created_at ASC, rowid ASC")
49
+ .all(conversationId);
50
+ return rows.map(mapMessageRow);
51
+ }
52
+ getRecentMessages(conversationId, limit, options = {}) {
53
+ const rows = options.userId
54
+ ? this.db
55
+ .prepare(`
56
+ SELECT role, content, created_at
57
+ FROM messages
58
+ WHERE conversation_id = ? AND user_id = ?
59
+ ORDER BY created_at DESC, rowid DESC
60
+ LIMIT ?
61
+ `)
62
+ .all(conversationId, options.userId, limit)
63
+ : this.db
64
+ .prepare(`
65
+ SELECT role, content, created_at
66
+ FROM messages
67
+ WHERE conversation_id = ?
68
+ ORDER BY created_at DESC, rowid DESC
69
+ LIMIT ?
70
+ `)
71
+ .all(conversationId, limit);
72
+ return rows.reverse().map((row) => ({
73
+ role: row.role,
74
+ content: row.content,
75
+ createdAt: row.created_at
76
+ }));
77
+ }
78
+ ensureConversation(conversationId, title, provider, options = {}) {
79
+ if (conversationId) {
80
+ const existing = this.getConversation(conversationId, options.userId ? { userId: options.userId } : {});
81
+ if (existing)
82
+ return existing;
83
+ }
84
+ const id = conversationId ?? crypto.randomUUID();
85
+ const now = new Date().toISOString();
86
+ const normalizedTitle = title.trim().slice(0, 60) || "New conversation";
87
+ this.db
88
+ .prepare(`
89
+ INSERT INTO conversations (
90
+ id,
91
+ user_id,
92
+ agent_id,
93
+ channel,
94
+ title,
95
+ active_provider,
96
+ created_at,
97
+ updated_at
98
+ )
99
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
100
+ `)
101
+ .run(id, options.userId ?? null, options.agentId ?? null, options.channel ?? null, normalizedTitle, provider, now, now);
102
+ return {
103
+ id,
104
+ userId: options.userId ?? null,
105
+ agentId: options.agentId ?? null,
106
+ channel: options.channel ?? null,
107
+ title: normalizedTitle,
108
+ activeProvider: provider,
109
+ createdAt: now,
110
+ updatedAt: now,
111
+ };
112
+ }
113
+ addMessage(input) {
114
+ const now = new Date().toISOString();
115
+ const id = crypto.randomUUID();
116
+ this.db
117
+ .prepare(`
118
+ INSERT INTO messages (
119
+ id,
120
+ user_id,
121
+ conversation_id,
122
+ role,
123
+ content,
124
+ provider,
125
+ model,
126
+ created_at
127
+ )
128
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
129
+ `)
130
+ .run(id, input.userId ?? null, input.conversationId, input.role, input.content, input.provider ?? null, input.model ?? null, now);
131
+ this.db
132
+ .prepare("UPDATE conversations SET updated_at = ?, active_provider = COALESCE(?, active_provider) WHERE id = ?")
133
+ .run(now, input.provider ?? null, input.conversationId);
134
+ return {
135
+ id,
136
+ userId: input.userId ?? null,
137
+ conversationId: input.conversationId,
138
+ role: input.role,
139
+ content: input.content,
140
+ provider: input.provider ?? null,
141
+ model: input.model ?? null,
142
+ createdAt: now,
143
+ };
144
+ }
145
+ deleteConversation(id, options = {}) {
146
+ const result = options.userId
147
+ ? this.db
148
+ .prepare("DELETE FROM conversations WHERE id = ? AND user_id = ?")
149
+ .run(id, options.userId)
150
+ : this.db.prepare("DELETE FROM conversations WHERE id = ?").run(id);
151
+ return Number(result.changes) > 0;
152
+ }
153
+ getConversation(id, options = {}) {
154
+ const row = options.userId
155
+ ? this.db
156
+ .prepare("SELECT * FROM conversations WHERE id = ? AND user_id = ?")
157
+ .get(id, options.userId)
158
+ : this.db
159
+ .prepare("SELECT * FROM conversations WHERE id = ?")
160
+ .get(id);
161
+ return row ? mapConversationRow(row) : null;
162
+ }
163
+ }
164
+ function mapConversationRow(row) {
165
+ return {
166
+ id: row.id,
167
+ userId: row.user_id,
168
+ agentId: row.agent_id,
169
+ channel: row.channel,
170
+ title: row.title,
171
+ activeProvider: row.active_provider,
172
+ createdAt: row.created_at,
173
+ updatedAt: row.updated_at,
174
+ };
175
+ }
176
+ function mapMessageRow(row) {
177
+ return {
178
+ id: row.id,
179
+ userId: row.user_id,
180
+ conversationId: row.conversation_id,
181
+ role: row.role,
182
+ content: row.content,
183
+ provider: row.provider,
184
+ model: row.model,
185
+ createdAt: row.created_at,
186
+ };
187
+ }
188
+ function normalizeMessageContent(value) {
189
+ return value.trim().replace(/\s+/g, " ");
190
+ }
191
+ function truncateMessageContent(value, maxCharacters) {
192
+ if (value.length <= maxCharacters)
193
+ return value;
194
+ return `${value.slice(0, maxCharacters - 3).trimEnd()}...`;
195
+ }
196
+ //# sourceMappingURL=conversation-repository.js.map