@borgee/agents-host 0.2.2 → 0.2.28

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 (84) hide show
  1. package/README.md +184 -21
  2. package/dist/agents-host-supervisor.d.ts +7 -5
  3. package/dist/agents-host-supervisor.js +24 -4
  4. package/dist/agents-host.d.ts +114 -15
  5. package/dist/agents-host.js +2712 -141
  6. package/dist/chat/chat-control-plane.d.ts +13 -2
  7. package/dist/chat/sdk-chat-control-plane.d.ts +14 -3
  8. package/dist/chat/sdk-chat-control-plane.js +54 -2
  9. package/dist/cli-args.d.ts +46 -5
  10. package/dist/cli-args.js +313 -32
  11. package/dist/cli.d.ts +9 -0
  12. package/dist/cli.js +112 -5
  13. package/dist/compatibility-gates.d.ts +39 -0
  14. package/dist/compatibility-gates.js +131 -0
  15. package/dist/config.d.ts +1 -0
  16. package/dist/config.js +23 -5
  17. package/dist/connections-state-store.d.ts +81 -0
  18. package/dist/connections-state-store.js +228 -0
  19. package/dist/context/attention.d.ts +12 -0
  20. package/dist/context/attention.js +137 -0
  21. package/dist/context/collaboration-capabilities-diagnostics.d.ts +3 -0
  22. package/dist/context/collaboration-capabilities-diagnostics.js +18 -0
  23. package/dist/context/collaboration-outcome.d.ts +2 -0
  24. package/dist/context/collaboration-outcome.js +26 -0
  25. package/dist/context/injection.d.ts +134 -0
  26. package/dist/context/injection.js +355 -0
  27. package/dist/context/prompt.d.ts +4 -1
  28. package/dist/context/prompt.js +231 -1
  29. package/dist/context/task-thread-collaboration.d.ts +6 -0
  30. package/dist/context/task-thread-collaboration.js +31 -0
  31. package/dist/context/turn-preparation.d.ts +9 -0
  32. package/dist/context/turn-preparation.js +135 -0
  33. package/dist/debug.d.ts +44 -0
  34. package/dist/debug.js +135 -0
  35. package/dist/gateway/localhost-gateway.d.ts +52 -0
  36. package/dist/gateway/localhost-gateway.js +857 -0
  37. package/dist/index.js +7 -5
  38. package/dist/local-config.d.ts +4 -1
  39. package/dist/local-config.js +24 -7
  40. package/dist/managed-daemon-log.d.ts +34 -0
  41. package/dist/managed-daemon-log.js +261 -0
  42. package/dist/managed-daemon.d.ts +220 -0
  43. package/dist/managed-daemon.js +1601 -0
  44. package/dist/policy/authorization-audit.d.ts +63 -0
  45. package/dist/policy/authorization-audit.js +94 -0
  46. package/dist/policy/copilot-permission.d.ts +15 -0
  47. package/dist/policy/copilot-permission.js +193 -0
  48. package/dist/policy/gateway-authorization.d.ts +42 -0
  49. package/dist/policy/gateway-authorization.js +162 -0
  50. package/dist/providers/awaiting-user.d.ts +12 -0
  51. package/dist/providers/awaiting-user.js +192 -0
  52. package/dist/providers/claude/adapter.d.ts +3 -1
  53. package/dist/providers/claude/adapter.js +8 -12
  54. package/dist/providers/claude/cli-client.d.ts +12 -5
  55. package/dist/providers/claude/cli-client.js +184 -37
  56. package/dist/providers/claude/session-store.d.ts +1 -0
  57. package/dist/providers/codex/adapter.d.ts +11 -0
  58. package/dist/providers/codex/adapter.js +19 -0
  59. package/dist/providers/codex/cli-client.d.ts +103 -0
  60. package/dist/providers/codex/cli-client.js +1133 -0
  61. package/dist/providers/codex/project-doc.d.ts +3 -0
  62. package/dist/providers/codex/project-doc.js +90 -0
  63. package/dist/providers/codex/session-store.d.ts +38 -0
  64. package/dist/providers/codex/session-store.js +150 -0
  65. package/dist/providers/copilot/adapter.d.ts +3 -1
  66. package/dist/providers/copilot/adapter.js +8 -12
  67. package/dist/providers/copilot/cli-client.d.ts +20 -2
  68. package/dist/providers/copilot/cli-client.js +251 -71
  69. package/dist/providers/copilot/session-store.d.ts +1 -0
  70. package/dist/providers/create-provider.d.ts +11 -2
  71. package/dist/providers/create-provider.js +131 -12
  72. package/dist/run.d.ts +1 -0
  73. package/dist/run.js +5 -2
  74. package/dist/state-paths.d.ts +14 -1
  75. package/dist/state-paths.js +87 -3
  76. package/dist/task-thread-resolution.d.ts +10 -0
  77. package/dist/task-thread-resolution.js +48 -0
  78. package/dist/types.d.ts +267 -1
  79. package/dist/visible-mentions.d.ts +3 -0
  80. package/dist/visible-mentions.js +15 -0
  81. package/package.json +19 -17
  82. package/skills/borgee-agent/SKILL.md +33 -0
  83. package/skills/borgee-agent/borgee-agent.mjs +473 -0
  84. package/skills/borgee-agent/borgee-agent.py +409 -0
@@ -0,0 +1,473 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { readFile } from 'node:fs/promises';
4
+
5
+ const TASK_THREAD_COLLECTION_COMMAND_ERROR
6
+ = 'Task assignment threads only support --get-task and --update-task. Create/list tasks belong to the parent channel.';
7
+ const TASK_THREAD_MISSING_TASK_ID_ERROR
8
+ = 'Task assignment thread could not resolve the current task from persisted context or local fallback. Pass --task-id explicitly.';
9
+
10
+ function parseArgs(argv) {
11
+ let contextPath;
12
+ let authPath;
13
+ let turnExecutionId;
14
+ let action = 'print-bootstrap';
15
+ let limit;
16
+ let before;
17
+ let after;
18
+ let body;
19
+ let replyToId;
20
+ let mentionTargetId;
21
+ let title;
22
+ let description;
23
+ let assigneeId;
24
+ let taskId;
25
+ let status;
26
+ const mentions = [];
27
+
28
+ function setAction(nextAction) {
29
+ if (action !== 'print-bootstrap') {
30
+ throw new Error('Only one action flag may be used per invocation');
31
+ }
32
+ action = nextAction;
33
+ }
34
+
35
+ function parseIntegerOption(flag, value) {
36
+ if (value == null) {
37
+ throw new Error(`Missing value after ${flag}`);
38
+ }
39
+ const parsed = Number.parseInt(value, 10);
40
+ if (!Number.isFinite(parsed)) {
41
+ throw new Error(`Invalid integer for ${flag}: ${value}`);
42
+ }
43
+ return parsed;
44
+ }
45
+
46
+ for (let index = 0; index < argv.length; index += 1) {
47
+ const arg = argv[index];
48
+ if (arg === '--context') {
49
+ contextPath = argv[index + 1];
50
+ index += 1;
51
+ continue;
52
+ }
53
+ if (arg === '--auth-path') {
54
+ authPath = argv[index + 1];
55
+ index += 1;
56
+ continue;
57
+ }
58
+ if (arg === '--turn-execution-id') {
59
+ turnExecutionId = argv[index + 1];
60
+ index += 1;
61
+ continue;
62
+ }
63
+ if (arg === '--print-bootstrap') {
64
+ action = 'print-bootstrap';
65
+ continue;
66
+ }
67
+ if (arg === '--health') {
68
+ setAction('health');
69
+ continue;
70
+ }
71
+ if (arg === '--read-bootstrap') {
72
+ setAction('read-bootstrap');
73
+ continue;
74
+ }
75
+ if (arg === '--get-me') {
76
+ setAction('get-me');
77
+ continue;
78
+ }
79
+ if (arg === '--read-history') {
80
+ setAction('read-history');
81
+ continue;
82
+ }
83
+ if (arg === '--read-draft') {
84
+ setAction('read-draft');
85
+ continue;
86
+ }
87
+ if (arg === '--list-users') {
88
+ setAction('list-users');
89
+ continue;
90
+ }
91
+ if (arg === '--send-message') {
92
+ setAction('send-message');
93
+ continue;
94
+ }
95
+ if (arg === '--send-mention') {
96
+ setAction('send-mention');
97
+ mentionTargetId = argv[index + 1];
98
+ index += 1;
99
+ continue;
100
+ }
101
+ if (arg === '--create-task') {
102
+ setAction('create-task');
103
+ continue;
104
+ }
105
+ if (arg === '--list-tasks') {
106
+ setAction('list-tasks');
107
+ continue;
108
+ }
109
+ if (arg === '--get-task') {
110
+ setAction('get-task');
111
+ continue;
112
+ }
113
+ if (arg === '--update-task') {
114
+ setAction('update-task');
115
+ continue;
116
+ }
117
+ if (arg === '--limit') {
118
+ limit = parseIntegerOption(arg, argv[index + 1]);
119
+ index += 1;
120
+ continue;
121
+ }
122
+ if (arg === '--before') {
123
+ before = parseIntegerOption(arg, argv[index + 1]);
124
+ index += 1;
125
+ continue;
126
+ }
127
+ if (arg === '--after') {
128
+ after = parseIntegerOption(arg, argv[index + 1]);
129
+ index += 1;
130
+ continue;
131
+ }
132
+ if (arg === '--body') {
133
+ body = argv[index + 1];
134
+ index += 1;
135
+ continue;
136
+ }
137
+ if (arg === '--reply-to') {
138
+ replyToId = argv[index + 1];
139
+ index += 1;
140
+ continue;
141
+ }
142
+ if (arg === '--mention') {
143
+ const mention = argv[index + 1];
144
+ if (mention == null || mention.trim().length === 0) {
145
+ throw new Error('Missing value after --mention');
146
+ }
147
+ mentions.push(mention.trim());
148
+ index += 1;
149
+ continue;
150
+ }
151
+ if (arg === '--title') {
152
+ title = argv[index + 1];
153
+ index += 1;
154
+ continue;
155
+ }
156
+ if (arg === '--description') {
157
+ description = argv[index + 1];
158
+ index += 1;
159
+ continue;
160
+ }
161
+ if (arg === '--assignee-id') {
162
+ assigneeId = argv[index + 1];
163
+ index += 1;
164
+ continue;
165
+ }
166
+ if (arg === '--task-id') {
167
+ taskId = argv[index + 1];
168
+ index += 1;
169
+ continue;
170
+ }
171
+ if (arg === '--status') {
172
+ status = argv[index + 1];
173
+ index += 1;
174
+ continue;
175
+ }
176
+ throw new Error(`Unknown argument: ${arg}`);
177
+ }
178
+
179
+ if (!contextPath) {
180
+ throw new Error('Missing required --context <path> argument');
181
+ }
182
+
183
+ return {
184
+ contextPath,
185
+ authPath,
186
+ turnExecutionId: turnExecutionId?.trim(),
187
+ action,
188
+ limit,
189
+ before,
190
+ after,
191
+ body,
192
+ replyToId,
193
+ mentionTargetId: mentionTargetId?.trim(),
194
+ mentions,
195
+ title,
196
+ description,
197
+ assigneeId,
198
+ taskId,
199
+ status,
200
+ };
201
+ }
202
+
203
+ function ensureVisibleMention(body, participantId) {
204
+ if (body.includes(`<@${participantId}>`)) {
205
+ return body;
206
+ }
207
+ const separator = /\s$/u.test(body) ? '' : ' ';
208
+ return `${body}${separator}<@${participantId}>`;
209
+ }
210
+
211
+ function ensureVisibleMentions(body, participantIds) {
212
+ return participantIds.reduce(
213
+ (nextBody, participantId) => ensureVisibleMention(nextBody, participantId),
214
+ body,
215
+ );
216
+ }
217
+
218
+ function explicitTaskIdProvided(options) {
219
+ return typeof options.taskId === 'string' && options.taskId.trim().length > 0;
220
+ }
221
+
222
+ function resolveTaskId(payload, action, options) {
223
+ const explicitTaskId = typeof options.taskId === 'string'
224
+ ? options.taskId.trim()
225
+ : '';
226
+ if (explicitTaskId) {
227
+ return explicitTaskId;
228
+ }
229
+ if (payload.taskAssignmentContext?.active === true) {
230
+ const persistedTaskId = typeof payload.taskAssignmentContext.currentTaskId === 'string'
231
+ ? payload.taskAssignmentContext.currentTaskId.trim()
232
+ : '';
233
+ if (persistedTaskId) {
234
+ return persistedTaskId;
235
+ }
236
+ return null;
237
+ }
238
+ throw new Error(`Missing required --task-id <value> for --${action}`);
239
+ }
240
+
241
+ function resolveGatewayRequest(payload, action, options) {
242
+ const gateway = payload.localhostGateway;
243
+ if (!gateway?.baseUrl) {
244
+ throw new Error('Missing localhostGateway bootstrap metadata in the context payload');
245
+ }
246
+ if ((action === 'create-task' || action === 'list-tasks') && payload.taskAssignmentContext?.active === true) {
247
+ throw new Error(TASK_THREAD_COLLECTION_COMMAND_ERROR);
248
+ }
249
+ const encodedChannelId = encodeURIComponent(String(payload.channelId ?? ''));
250
+ switch (action) {
251
+ case 'health':
252
+ return { url: new URL('/health', gateway.baseUrl), method: 'GET' };
253
+ case 'read-bootstrap':
254
+ return { url: new URL(`/v1/channels/${encodedChannelId}/bootstrap`, gateway.baseUrl), method: 'GET' };
255
+ case 'get-me':
256
+ return { url: new URL(`/v1/channels/${encodedChannelId}/me`, gateway.baseUrl), method: 'GET' };
257
+ case 'read-history': {
258
+ const url = new URL(`/v1/channels/${encodedChannelId}/history`, gateway.baseUrl);
259
+ if (options.limit != null) {
260
+ url.searchParams.set('limit', String(options.limit));
261
+ }
262
+ if (options.before != null) {
263
+ url.searchParams.set('before', String(options.before));
264
+ }
265
+ if (options.after != null) {
266
+ url.searchParams.set('after', String(options.after));
267
+ }
268
+ return { url, method: 'GET' };
269
+ }
270
+ case 'read-draft': {
271
+ if (!options.turnExecutionId || options.turnExecutionId.trim().length === 0) {
272
+ throw new Error('Missing required --turn-execution-id value for --read-draft');
273
+ }
274
+ const url = new URL(`/v1/channels/${encodedChannelId}/draft`, gateway.baseUrl);
275
+ url.searchParams.set('turnExecutionId', options.turnExecutionId.trim());
276
+ return { url, method: 'GET' };
277
+ }
278
+ case 'list-users':
279
+ return { url: new URL(`/v1/channels/${encodedChannelId}/users`, gateway.baseUrl), method: 'GET' };
280
+ case 'send-message':
281
+ case 'send-mention':
282
+ return { url: new URL(`/v1/channels/${encodedChannelId}/messages`, gateway.baseUrl), method: 'POST' };
283
+ case 'create-task': {
284
+ if (!options.title) {
285
+ throw new Error('Missing required --title <value> for --create-task');
286
+ }
287
+ return {
288
+ url: new URL(`/v1/channels/${encodedChannelId}/tasks`, gateway.baseUrl),
289
+ method: 'POST',
290
+ body: {
291
+ title: options.title,
292
+ ...(options.description != null ? { description: options.description } : {}),
293
+ ...(options.assigneeId != null ? { assigneeId: options.assigneeId } : {}),
294
+ },
295
+ };
296
+ }
297
+ case 'list-tasks':
298
+ return { url: new URL(`/v1/channels/${encodedChannelId}/tasks`, gateway.baseUrl), method: 'GET' };
299
+ case 'get-task': {
300
+ const taskId = resolveTaskId(payload, action, options);
301
+ if (payload.taskAssignmentContext?.active === true && !explicitTaskIdProvided(options)) {
302
+ return {
303
+ url: new URL(`/v1/channels/${encodedChannelId}/current-task`, gateway.baseUrl),
304
+ method: 'GET',
305
+ usesCurrentThreadFallback: true,
306
+ };
307
+ }
308
+ return {
309
+ url: new URL(`/v1/tasks/${encodeURIComponent(taskId)}`, gateway.baseUrl),
310
+ method: 'GET',
311
+ usesCurrentThreadFallback: false,
312
+ };
313
+ }
314
+ case 'update-task': {
315
+ const taskId = resolveTaskId(payload, action, options);
316
+ const requestBody = {
317
+ ...(options.status != null ? { status: options.status } : {}),
318
+ ...(options.assigneeId != null ? { assigneeId: options.assigneeId } : {}),
319
+ ...(options.title != null ? { title: options.title } : {}),
320
+ };
321
+ if (Object.keys(requestBody).length === 0) {
322
+ throw new Error('At least one of --status, --assignee-id, or --title is required for --update-task');
323
+ }
324
+ if (payload.taskAssignmentContext?.active === true && !explicitTaskIdProvided(options)) {
325
+ return {
326
+ url: new URL(`/v1/channels/${encodedChannelId}/current-task`, gateway.baseUrl),
327
+ method: 'PATCH',
328
+ body: requestBody,
329
+ usesCurrentThreadFallback: true,
330
+ };
331
+ }
332
+ return {
333
+ url: new URL(`/v1/tasks/${encodeURIComponent(taskId)}`, gateway.baseUrl),
334
+ method: 'PATCH',
335
+ body: requestBody,
336
+ usesCurrentThreadFallback: false,
337
+ };
338
+ }
339
+ default:
340
+ throw new Error(`Unsupported gateway action: ${action}`);
341
+ }
342
+ }
343
+
344
+ async function readGatewayAuth(authPath, expectedChannelId) {
345
+ if (!authPath) {
346
+ throw new Error('Missing required --auth-path <path> argument for gateway access');
347
+ }
348
+ const authPayload = JSON.parse(await readFile(authPath, 'utf8'));
349
+ if (authPayload?.channelId !== expectedChannelId || !authPayload?.localhostGateway?.token) {
350
+ throw new Error('Missing localhost gateway auth payload for this channel');
351
+ }
352
+ return { token: authPayload.localhostGateway.token };
353
+ }
354
+
355
+ async function callGateway(payload, action, options) {
356
+ const request = resolveGatewayRequest(payload, action, options);
357
+ const auth = await readGatewayAuth(options.authPath, payload.channelId);
358
+ const httpRequest = {
359
+ method: request.method,
360
+ headers: auth.token
361
+ ? {
362
+ authorization: `Bearer ${auth.token}`,
363
+ ...(request.body || action === 'send-message' || action === 'send-mention'
364
+ ? { 'content-type': 'application/json; charset=utf-8' }
365
+ : {}),
366
+ }
367
+ : undefined,
368
+ };
369
+
370
+ if (action === 'send-message' || action === 'send-mention') {
371
+ if (!options.body || options.body.trim().length === 0) {
372
+ throw new Error(`Missing required --body value for --${action}`);
373
+ }
374
+ if (!options.turnExecutionId || options.turnExecutionId.trim().length === 0) {
375
+ throw new Error(`Missing required --turn-execution-id value for --${action}`);
376
+ }
377
+ const requestMentions =
378
+ action === 'send-mention'
379
+ ? [options.mentionTargetId?.trim()].filter(
380
+ (value) => typeof value === 'string' && value.length > 0,
381
+ )
382
+ : options.mentions;
383
+ if (action === 'send-mention' && requestMentions.length !== 1) {
384
+ throw new Error('Missing required target user id after --send-mention');
385
+ }
386
+ if (action === 'send-mention' && options.mentions.length > 0) {
387
+ throw new Error('Do not combine --send-mention with additional --mention flags');
388
+ }
389
+ const requestBody =
390
+ requestMentions.length > 0
391
+ ? ensureVisibleMentions(options.body, requestMentions)
392
+ : options.body;
393
+ httpRequest.body = JSON.stringify({
394
+ body: requestBody,
395
+ replyToId: options.replyToId,
396
+ turnExecutionId: options.turnExecutionId,
397
+ });
398
+ } else if (request.body) {
399
+ httpRequest.body = JSON.stringify(request.body);
400
+ }
401
+
402
+ const response = await fetch(request.url, httpRequest);
403
+ const bodyText = await response.text();
404
+ const responseBody = bodyText.length > 0 ? JSON.parse(bodyText) : null;
405
+ if (!response.ok) {
406
+ if (responseBody?.error === 'not_found' && request.usesCurrentThreadFallback === true) {
407
+ throw new Error(TASK_THREAD_MISSING_TASK_ID_ERROR);
408
+ }
409
+ throw new Error(`Gateway request failed with ${response.status}: ${JSON.stringify(responseBody)}`);
410
+ }
411
+ return responseBody;
412
+ }
413
+
414
+ function redactBootstrap(payload, contextPath) {
415
+ return {
416
+ kind: 'borgee-agent-skill-bootstrap',
417
+ contextPath,
418
+ channelId: payload.channelId,
419
+ skillRuntime: payload.skillRuntime ?? null,
420
+ taskAssignmentContext: payload.taskAssignmentContext ?? null,
421
+ localhostGateway: payload.localhostGateway?.baseUrl
422
+ ? {
423
+ baseUrl: payload.localhostGateway.baseUrl,
424
+ ...(payload.localhostGateway.collaboration
425
+ ? { collaboration: payload.localhostGateway.collaboration }
426
+ : {}),
427
+ }
428
+ : null,
429
+ };
430
+ }
431
+
432
+ const {
433
+ contextPath,
434
+ authPath,
435
+ turnExecutionId,
436
+ action,
437
+ limit,
438
+ before,
439
+ after,
440
+ body,
441
+ replyToId,
442
+ mentionTargetId,
443
+ mentions,
444
+ title,
445
+ description,
446
+ assigneeId,
447
+ taskId,
448
+ status,
449
+ } = parseArgs(process.argv.slice(2));
450
+ const payload = JSON.parse(await readFile(contextPath, 'utf8'));
451
+
452
+ if (action === 'print-bootstrap') {
453
+ console.log(JSON.stringify(redactBootstrap(payload, contextPath), null, 2));
454
+ } else {
455
+ const result = await callGateway(payload, action, {
456
+ contextPath,
457
+ authPath,
458
+ turnExecutionId,
459
+ limit,
460
+ before,
461
+ after,
462
+ body,
463
+ replyToId,
464
+ mentionTargetId,
465
+ mentions,
466
+ title,
467
+ description,
468
+ assigneeId,
469
+ taskId,
470
+ status,
471
+ });
472
+ console.log(JSON.stringify(result, null, 2));
473
+ }