@borgee/agents-host 0.2.94 → 0.2.101
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/dist/agents-host.d.ts +8 -0
- package/dist/agents-host.js +266 -64
- package/dist/background-runs.d.ts +4 -0
- package/dist/background-runs.js +8 -4
- package/dist/chat/chat-control-plane.d.ts +14 -3
- package/dist/chat/sdk-chat-control-plane.d.ts +31 -5
- package/dist/chat/sdk-chat-control-plane.js +134 -3
- package/dist/context/skill-manual.js +1 -1
- package/dist/execution-telemetry.d.ts +96 -0
- package/dist/execution-telemetry.js +583 -0
- package/dist/gateway/channel-file-workspace.d.ts +15 -0
- package/dist/gateway/channel-file-workspace.js +130 -0
- package/dist/gateway/localhost-gateway.js +140 -0
- package/dist/plugin-sdk.js +85 -4
- package/dist/plugin-sdk.js.map +2 -2
- package/dist/policy/gateway-authorization.d.ts +1 -1
- package/dist/policy/gateway-authorization.js +22 -2
- package/dist/progress-to-activity.d.ts +3 -3
- package/dist/providers/claude/adapter.d.ts +2 -1
- package/dist/providers/claude/adapter.js +11 -0
- package/dist/providers/claude/cli-client.d.ts +3 -1
- package/dist/providers/claude/cli-client.js +267 -13
- package/dist/providers/codex/adapter.js +1 -0
- package/dist/providers/codex/cli-client.js +5 -0
- package/dist/providers/copilot/adapter.js +4 -0
- package/dist/providers/copilot/cli-client.js +11 -1
- package/dist/providers/copilot/sdk-session.d.ts +12 -3
- package/dist/providers/copilot/sdk-session.js +222 -5
- package/dist/providers/create-provider.js +4 -0
- package/dist/providers/prompt-usage.d.ts +8 -0
- package/dist/providers/prompt-usage.js +52 -0
- package/dist/state-paths.d.ts +2 -0
- package/dist/state-paths.js +6 -0
- package/dist/types.d.ts +41 -0
- package/dist/typing-lease.d.ts +14 -0
- package/dist/typing-lease.js +31 -0
- package/package.json +9 -9
- package/skills/borgee-agent/SKILL.md +12 -4
- package/skills/borgee-agent/scripts/borgee-agent.mjs +89 -0
- package/skills/borgee-agent/scripts/borgee-agent.py +90 -0
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { constants as fsConstants, promises as fs } from 'node:fs';
|
|
2
|
+
import { dirname, isAbsolute, relative, resolve, sep } from 'node:path';
|
|
3
|
+
export const CHANNEL_FILE_WORKING_COPY_DIRECTORY = '.borgee/channel-files';
|
|
4
|
+
export const CHANNEL_FILE_TRANSFER_MAX_BYTES = 10 * 1024 * 1024;
|
|
5
|
+
export class ChannelFileWorkspaceError extends Error {
|
|
6
|
+
code;
|
|
7
|
+
constructor(code, message) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.code = code;
|
|
10
|
+
this.name = 'ChannelFileWorkspaceError';
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export function validatePortableRelativePath(path) {
|
|
14
|
+
if (path.length === 0
|
|
15
|
+
|| isAbsolute(path)
|
|
16
|
+
|| path.includes('\\')
|
|
17
|
+
|| path.includes('\0')
|
|
18
|
+
|| path.split('/').some((part) => part === '' || part === '.' || part === '..' || /[\u0000-\u001f\u007f]/u.test(part))
|
|
19
|
+
|| /^[A-Za-z]:/u.test(path)) {
|
|
20
|
+
throw new ChannelFileWorkspaceError('invalid_file_path', `Invalid relative file path: ${path}`);
|
|
21
|
+
}
|
|
22
|
+
return path;
|
|
23
|
+
}
|
|
24
|
+
export function requireExecutionRoot(payload) {
|
|
25
|
+
const workspace = payload.resolvedWorkspace;
|
|
26
|
+
if (workspace?.authority !== 'task-execution-target' || !isAbsolute(workspace.rootPath)) {
|
|
27
|
+
throw new ChannelFileWorkspaceError('execution_local_directory_required', 'Channel file transfer requires a task execution.local_directory');
|
|
28
|
+
}
|
|
29
|
+
return workspace.rootPath;
|
|
30
|
+
}
|
|
31
|
+
export async function readWorkspaceFile(rootPath, sourcePath) {
|
|
32
|
+
const safePath = validatePortableRelativePath(sourcePath);
|
|
33
|
+
const rootRealPath = await fs.realpath(rootPath);
|
|
34
|
+
const candidate = resolve(rootRealPath, ...safePath.split('/'));
|
|
35
|
+
assertContained(rootRealPath, candidate);
|
|
36
|
+
await rejectSymlinks(rootRealPath, candidate);
|
|
37
|
+
let stat;
|
|
38
|
+
try {
|
|
39
|
+
stat = await fs.stat(candidate);
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
if (error.code === 'ENOENT') {
|
|
43
|
+
throw new ChannelFileWorkspaceError('file_not_found', `Workspace file not found: ${sourcePath}`);
|
|
44
|
+
}
|
|
45
|
+
throw error;
|
|
46
|
+
}
|
|
47
|
+
if (!stat.isFile()) {
|
|
48
|
+
throw new ChannelFileWorkspaceError('file_not_found', `Workspace path is not a file: ${sourcePath}`);
|
|
49
|
+
}
|
|
50
|
+
if (stat.size > CHANNEL_FILE_TRANSFER_MAX_BYTES) {
|
|
51
|
+
throw new ChannelFileWorkspaceError('file_too_large', 'File too large (max 10MB)');
|
|
52
|
+
}
|
|
53
|
+
return await fs.readFile(candidate);
|
|
54
|
+
}
|
|
55
|
+
export async function writeWorkingCopy(rootPath, channelPath, content, overwrite) {
|
|
56
|
+
if (content.byteLength > CHANNEL_FILE_TRANSFER_MAX_BYTES) {
|
|
57
|
+
throw new ChannelFileWorkspaceError('file_too_large', 'File too large (max 10MB)');
|
|
58
|
+
}
|
|
59
|
+
const safePath = validatePortableRelativePath(channelPath);
|
|
60
|
+
const executionRoot = await fs.realpath(rootPath);
|
|
61
|
+
const workingRoot = resolve(executionRoot, ...CHANNEL_FILE_WORKING_COPY_DIRECTORY.split('/'));
|
|
62
|
+
assertContained(executionRoot, workingRoot);
|
|
63
|
+
await ensureSafeDirectory(executionRoot, workingRoot);
|
|
64
|
+
const destination = resolve(workingRoot, ...safePath.split('/'));
|
|
65
|
+
assertContained(workingRoot, destination);
|
|
66
|
+
await ensureSafeDirectory(workingRoot, dirname(destination));
|
|
67
|
+
await rejectSymlinks(workingRoot, destination, true);
|
|
68
|
+
try {
|
|
69
|
+
await fs.writeFile(destination, content, { flag: overwrite ? 'w' : 'wx', mode: 0o600 });
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
if (error.code === 'EEXIST') {
|
|
73
|
+
throw new ChannelFileWorkspaceError('file_exists', `Working copy already exists: ${channelPath}`);
|
|
74
|
+
}
|
|
75
|
+
throw error;
|
|
76
|
+
}
|
|
77
|
+
return destination;
|
|
78
|
+
}
|
|
79
|
+
async function ensureSafeDirectory(rootPath, directoryPath) {
|
|
80
|
+
const rel = relative(rootPath, directoryPath);
|
|
81
|
+
if (rel === '') {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
let current = rootPath;
|
|
85
|
+
for (const segment of rel.split(sep)) {
|
|
86
|
+
current = resolve(current, segment);
|
|
87
|
+
try {
|
|
88
|
+
const stat = await fs.lstat(current);
|
|
89
|
+
if (stat.isSymbolicLink()) {
|
|
90
|
+
throw new ChannelFileWorkspaceError('symlink_not_allowed', `Symbolic link is not allowed: ${current}`);
|
|
91
|
+
}
|
|
92
|
+
if (!stat.isDirectory()) {
|
|
93
|
+
throw new ChannelFileWorkspaceError('invalid_file_path', `Path component is not a directory: ${current}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
if (error.code !== 'ENOENT') {
|
|
98
|
+
throw error;
|
|
99
|
+
}
|
|
100
|
+
await fs.mkdir(current, { mode: 0o700 });
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
async function rejectSymlinks(rootPath, candidate, allowMissingLeaf = false) {
|
|
105
|
+
const rel = relative(rootPath, candidate);
|
|
106
|
+
let current = rootPath;
|
|
107
|
+
const parts = rel.split(sep);
|
|
108
|
+
for (const [index, segment] of parts.entries()) {
|
|
109
|
+
current = resolve(current, segment);
|
|
110
|
+
try {
|
|
111
|
+
const stat = await fs.lstat(current);
|
|
112
|
+
if (stat.isSymbolicLink()) {
|
|
113
|
+
throw new ChannelFileWorkspaceError('symlink_not_allowed', `Symbolic link is not allowed: ${current}`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
if (error.code === 'ENOENT' && allowMissingLeaf && index === parts.length - 1) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
throw error;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
await fs.access(candidate, fsConstants.F_OK);
|
|
124
|
+
}
|
|
125
|
+
function assertContained(rootPath, candidate) {
|
|
126
|
+
const rel = relative(rootPath, candidate);
|
|
127
|
+
if (rel === '..' || rel.startsWith(`..${sep}`) || isAbsolute(rel)) {
|
|
128
|
+
throw new ChannelFileWorkspaceError('invalid_file_path', 'Path escapes the execution directory');
|
|
129
|
+
}
|
|
130
|
+
}
|
|
@@ -7,6 +7,7 @@ import { evaluateGatewayAuthorization, } from '../policy/gateway-authorization.j
|
|
|
7
7
|
import { resolveConnectionsStatePath } from '../state-paths.js';
|
|
8
8
|
import { findTaskForThread } from '../task-thread-resolution.js';
|
|
9
9
|
import { extractVisibleMentionIds } from '../visible-mentions.js';
|
|
10
|
+
import { ChannelFileWorkspaceError, readWorkspaceFile, requireExecutionRoot, validatePortableRelativePath, writeWorkingCopy, } from './channel-file-workspace.js';
|
|
10
11
|
const LOOPBACK_HOST = '127.0.0.1';
|
|
11
12
|
export const LOCALHOST_GATEWAY_HISTORY_LIMIT = 20;
|
|
12
13
|
const LOCALHOST_GATEWAY_BODY_LIMIT_BYTES = 32 * 1024;
|
|
@@ -422,6 +423,89 @@ class LoopbackLocalhostGatewayController {
|
|
|
422
423
|
this.recordAudit('authorized', 200, decision.path, request.method ?? 'GET', decision.binding);
|
|
423
424
|
return;
|
|
424
425
|
}
|
|
426
|
+
case 'files': {
|
|
427
|
+
const files = await this.controlPlane.listChannelFiles({ channelId: binding.channelId });
|
|
428
|
+
this.sendJson(response, 200, { files });
|
|
429
|
+
this.recordAudit('authorized', 200, decision.path, request.method ?? 'GET', decision.binding);
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
case 'file-content': {
|
|
433
|
+
const url = new URL(request.url ?? '/', baseUrl);
|
|
434
|
+
const path = readRequiredQueryString(url, 'path');
|
|
435
|
+
if (!path) {
|
|
436
|
+
throw new GatewayHttpError(400, { error: 'missing_file_path' }, 'bad-request');
|
|
437
|
+
}
|
|
438
|
+
validatePortableRelativePath(path);
|
|
439
|
+
const content = await this.controlPlane.readChannelFile({
|
|
440
|
+
channelId: binding.channelId,
|
|
441
|
+
path,
|
|
442
|
+
textOnly: true,
|
|
443
|
+
});
|
|
444
|
+
this.sendJson(response, 200, content);
|
|
445
|
+
this.recordAudit('authorized', 200, decision.path, request.method ?? 'GET', decision.binding);
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
case 'file-download': {
|
|
449
|
+
const body = parseFileTransferBody(await readGatewayJsonBody(request));
|
|
450
|
+
const rootPath = requireExecutionRoot(binding.payload ?? {});
|
|
451
|
+
const content = await this.controlPlane.readChannelFile({
|
|
452
|
+
channelId: binding.channelId,
|
|
453
|
+
path: body.path,
|
|
454
|
+
textOnly: false,
|
|
455
|
+
});
|
|
456
|
+
if (content.base64 == null) {
|
|
457
|
+
throw new GatewayHttpError(502, { error: 'invalid_file_content' }, 'invalid-file-content');
|
|
458
|
+
}
|
|
459
|
+
const localPath = await writeWorkingCopy(rootPath, body.path, Buffer.from(content.base64, 'base64'), body.overwrite);
|
|
460
|
+
this.sendJson(response, 200, { path: body.path, localPath, sizeBytes: content.sizeBytes });
|
|
461
|
+
this.recordAudit('authorized', 200, decision.path, request.method ?? 'POST', decision.binding);
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
case 'file-sync': {
|
|
465
|
+
const body = parseFileSyncBody(await readGatewayJsonBody(request));
|
|
466
|
+
const rootPath = requireExecutionRoot(binding.payload ?? {});
|
|
467
|
+
const entries = (await this.controlPlane.listChannelFiles({ channelId: binding.channelId }))
|
|
468
|
+
.filter((file) => !file.isDirectory)
|
|
469
|
+
.filter((file) => body.path == null || file.path === body.path || file.path.startsWith(`${body.path}/`));
|
|
470
|
+
const synced = [];
|
|
471
|
+
for (const file of entries) {
|
|
472
|
+
const content = await this.controlPlane.readChannelFile({
|
|
473
|
+
channelId: binding.channelId,
|
|
474
|
+
path: file.path,
|
|
475
|
+
textOnly: false,
|
|
476
|
+
});
|
|
477
|
+
if (content.base64 == null) {
|
|
478
|
+
throw new GatewayHttpError(502, { error: 'invalid_file_content' }, 'invalid-file-content');
|
|
479
|
+
}
|
|
480
|
+
synced.push({
|
|
481
|
+
path: file.path,
|
|
482
|
+
localPath: await writeWorkingCopy(rootPath, file.path, Buffer.from(content.base64, 'base64'), body.overwrite),
|
|
483
|
+
sizeBytes: content.sizeBytes,
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
this.sendJson(response, 200, { synced });
|
|
487
|
+
this.recordAudit('authorized', 200, decision.path, request.method ?? 'POST', decision.binding);
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
case 'file-publish': {
|
|
491
|
+
const body = parseFilePublishBody(await readGatewayJsonBody(request));
|
|
492
|
+
const rootPath = requireExecutionRoot(binding.payload ?? {});
|
|
493
|
+
const workspace = binding.payload?.resolvedWorkspace;
|
|
494
|
+
if (workspace?.authority !== 'task-execution-target' || !binding.agentId) {
|
|
495
|
+
throw new GatewayHttpError(403, { error: 'publish_context_required' }, 'publish-context-required');
|
|
496
|
+
}
|
|
497
|
+
const content = await readWorkspaceFile(rootPath, body.sourcePath);
|
|
498
|
+
const file = await this.controlPlane.publishChannelFile({
|
|
499
|
+
channelId: binding.channelId,
|
|
500
|
+
path: body.channelPath,
|
|
501
|
+
contentType: body.contentType ?? inferContentType(body.sourcePath),
|
|
502
|
+
base64: content.toString('base64'),
|
|
503
|
+
overwrite: body.overwrite,
|
|
504
|
+
});
|
|
505
|
+
this.sendJson(response, 200, { file });
|
|
506
|
+
this.recordAudit('authorized', 200, decision.path, request.method ?? 'POST', decision.binding);
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
425
509
|
case 'draft': {
|
|
426
510
|
if (!binding.payload?.localhostGateway?.collaboration?.enabled) {
|
|
427
511
|
this.sendJson(response, 404, { error: 'not_found' });
|
|
@@ -599,6 +683,20 @@ class LoopbackLocalhostGatewayController {
|
|
|
599
683
|
}
|
|
600
684
|
}
|
|
601
685
|
catch (error) {
|
|
686
|
+
if (error instanceof ChannelFileWorkspaceError) {
|
|
687
|
+
const statusCode = error.code === 'file_not_found'
|
|
688
|
+
? 404
|
|
689
|
+
: error.code === 'file_exists'
|
|
690
|
+
? 409
|
|
691
|
+
: error.code === 'file_too_large'
|
|
692
|
+
? 413
|
|
693
|
+
: error.code === 'execution_local_directory_required'
|
|
694
|
+
? 403
|
|
695
|
+
: 400;
|
|
696
|
+
this.sendJson(response, statusCode, { error: error.code });
|
|
697
|
+
this.recordAudit(error.code, statusCode, decision.path, request.method ?? 'GET', decision.binding);
|
|
698
|
+
return;
|
|
699
|
+
}
|
|
602
700
|
const gatewayError = error instanceof GatewayHttpError
|
|
603
701
|
? error
|
|
604
702
|
: mapGatewayControlPlaneError(error, 'authorized');
|
|
@@ -757,6 +855,48 @@ async function readGatewayJsonBody(request) {
|
|
|
757
855
|
throw new GatewayHttpError(400, { error: 'invalid_json' }, 'invalid-json');
|
|
758
856
|
}
|
|
759
857
|
}
|
|
858
|
+
function parseFileTransferBody(value) {
|
|
859
|
+
if (!isRecord(value) || typeof value.path !== 'string') {
|
|
860
|
+
throw new GatewayHttpError(400, { error: 'invalid_file_request' }, 'bad-request');
|
|
861
|
+
}
|
|
862
|
+
return { path: validatePortableRelativePath(value.path), overwrite: value.overwrite === true };
|
|
863
|
+
}
|
|
864
|
+
function parseFileSyncBody(value) {
|
|
865
|
+
if (!isRecord(value) || (value.path != null && typeof value.path !== 'string')) {
|
|
866
|
+
throw new GatewayHttpError(400, { error: 'invalid_file_request' }, 'bad-request');
|
|
867
|
+
}
|
|
868
|
+
return {
|
|
869
|
+
...(typeof value.path === 'string' ? { path: validatePortableRelativePath(value.path) } : {}),
|
|
870
|
+
overwrite: value.overwrite === true,
|
|
871
|
+
};
|
|
872
|
+
}
|
|
873
|
+
function parseFilePublishBody(value) {
|
|
874
|
+
if (!isRecord(value)
|
|
875
|
+
|| typeof value.sourcePath !== 'string'
|
|
876
|
+
|| typeof value.channelPath !== 'string'
|
|
877
|
+
|| (value.contentType != null && typeof value.contentType !== 'string')) {
|
|
878
|
+
throw new GatewayHttpError(400, { error: 'invalid_file_request' }, 'bad-request');
|
|
879
|
+
}
|
|
880
|
+
return {
|
|
881
|
+
sourcePath: validatePortableRelativePath(value.sourcePath),
|
|
882
|
+
channelPath: validatePortableRelativePath(value.channelPath),
|
|
883
|
+
...(typeof value.contentType === 'string' ? { contentType: value.contentType } : {}),
|
|
884
|
+
overwrite: value.overwrite === true,
|
|
885
|
+
};
|
|
886
|
+
}
|
|
887
|
+
function inferContentType(path) {
|
|
888
|
+
const extension = path.toLowerCase().split('.').at(-1);
|
|
889
|
+
const byExtension = {
|
|
890
|
+
css: 'text/css', csv: 'text/csv', gif: 'image/gif', html: 'text/html',
|
|
891
|
+
jpeg: 'image/jpeg', jpg: 'image/jpeg', js: 'text/javascript',
|
|
892
|
+
json: 'application/json', md: 'text/markdown', pdf: 'application/pdf',
|
|
893
|
+
png: 'image/png', py: 'text/x-python', toml: 'application/toml',
|
|
894
|
+
ts: 'text/typescript', txt: 'text/plain', webp: 'image/webp',
|
|
895
|
+
xml: 'application/xml', yaml: 'application/yaml', yml: 'application/yaml',
|
|
896
|
+
zip: 'application/zip',
|
|
897
|
+
};
|
|
898
|
+
return (extension && byExtension[extension]) || 'application/octet-stream';
|
|
899
|
+
}
|
|
760
900
|
async function readCollaborationRequestBody(request) {
|
|
761
901
|
const bodyText = await readRequestBody(request, LOCALHOST_GATEWAY_COLLABORATION_BODY_LIMIT_BYTES);
|
|
762
902
|
if (!bodyText.ok) {
|
package/dist/plugin-sdk.js
CHANGED
|
@@ -4502,7 +4502,7 @@ var BppTransport = class {
|
|
|
4502
4502
|
};
|
|
4503
4503
|
this.send(frame);
|
|
4504
4504
|
}
|
|
4505
|
-
// sendActivity flattens the
|
|
4505
|
+
// sendActivity flattens the activity union onto one frame. The union is
|
|
4506
4506
|
// how a producer says which shape it is reporting; the wire puts the
|
|
4507
4507
|
// discriminator beside its payload with no wrapper object, matching both the
|
|
4508
4508
|
// protocol this relays and inbound_message's own `kind`.
|
|
@@ -4575,6 +4575,18 @@ var BppTransport = class {
|
|
|
4575
4575
|
frame.stop_supported = action.activity.stopSupported;
|
|
4576
4576
|
frame.stop_unsupported_reason = action.activity.stopUnsupportedReason ?? "";
|
|
4577
4577
|
break;
|
|
4578
|
+
case "normalized":
|
|
4579
|
+
frame.protocol_version = action.activity.protocolVersion;
|
|
4580
|
+
frame.task_id = action.activity.taskId;
|
|
4581
|
+
frame.event = action.activity.event;
|
|
4582
|
+
break;
|
|
4583
|
+
}
|
|
4584
|
+
if (action.activity.shape === "normalized") {
|
|
4585
|
+
const ids = [frame.channel_id, frame.task_id];
|
|
4586
|
+
if (ids.some((value) => new TextEncoder().encode(value).byteLength > 256))
|
|
4587
|
+
return;
|
|
4588
|
+
if (new TextEncoder().encode(JSON.stringify(frame)).byteLength > 32768)
|
|
4589
|
+
return;
|
|
4578
4590
|
}
|
|
4579
4591
|
this.send(frame);
|
|
4580
4592
|
}
|
|
@@ -4705,6 +4717,18 @@ function encodeActionPayload(action) {
|
|
|
4705
4717
|
after: action.after,
|
|
4706
4718
|
limit: action.limit
|
|
4707
4719
|
};
|
|
4720
|
+
case "list_channel_files":
|
|
4721
|
+
return { channel_id: action.channelId };
|
|
4722
|
+
case "read_channel_file":
|
|
4723
|
+
return { channel_id: action.channelId, path: action.path, text_only: action.textOnly };
|
|
4724
|
+
case "publish_channel_file":
|
|
4725
|
+
return {
|
|
4726
|
+
channel_id: action.channelId,
|
|
4727
|
+
path: action.path,
|
|
4728
|
+
content_type: action.contentType,
|
|
4729
|
+
base64: action.base64,
|
|
4730
|
+
overwrite: action.overwrite ?? false
|
|
4731
|
+
};
|
|
4708
4732
|
case "list_users":
|
|
4709
4733
|
case "list_channels":
|
|
4710
4734
|
return {};
|
|
@@ -4811,6 +4835,53 @@ function decodeActionResult(op, payloadJSON, zoneInput) {
|
|
|
4811
4835
|
editedAt: m.edited_at != null ? Number(m.edited_at) : void 0
|
|
4812
4836
|
}));
|
|
4813
4837
|
}
|
|
4838
|
+
case "list_channel_files": {
|
|
4839
|
+
const arr = Array.isArray(p) ? p : [];
|
|
4840
|
+
return arr.map((file) => ({
|
|
4841
|
+
id: String(file.id ?? ""),
|
|
4842
|
+
ownerUserId: String(file.owner_user_id ?? ""),
|
|
4843
|
+
channelId: String(file.channel_id ?? ""),
|
|
4844
|
+
path: String(file.path ?? ""),
|
|
4845
|
+
parentPath: String(file.parent_path ?? ""),
|
|
4846
|
+
name: String(file.name ?? ""),
|
|
4847
|
+
isDirectory: Boolean(file.is_directory),
|
|
4848
|
+
mimeType: String(file.mime_type ?? ""),
|
|
4849
|
+
sizeBytes: Number(file.size_bytes ?? 0),
|
|
4850
|
+
source: String(file.source ?? ""),
|
|
4851
|
+
sourceMessageId: String(file.source_message_id ?? ""),
|
|
4852
|
+
createdAt: Number(file.created_at ?? 0),
|
|
4853
|
+
updatedAt: Number(file.updated_at ?? 0)
|
|
4854
|
+
}));
|
|
4855
|
+
}
|
|
4856
|
+
case "read_channel_file": {
|
|
4857
|
+
const content = p;
|
|
4858
|
+
return {
|
|
4859
|
+
path: String(content.path ?? ""),
|
|
4860
|
+
filename: String(content.filename ?? ""),
|
|
4861
|
+
contentType: String(content.content_type ?? ""),
|
|
4862
|
+
sizeBytes: Number(content.size_bytes ?? 0),
|
|
4863
|
+
...content.base64 != null ? { base64: String(content.base64) } : {},
|
|
4864
|
+
...content.text != null ? { text: String(content.text) } : {}
|
|
4865
|
+
};
|
|
4866
|
+
}
|
|
4867
|
+
case "publish_channel_file": {
|
|
4868
|
+
const file = p;
|
|
4869
|
+
return {
|
|
4870
|
+
id: String(file.id ?? ""),
|
|
4871
|
+
ownerUserId: String(file.owner_user_id ?? ""),
|
|
4872
|
+
channelId: String(file.channel_id ?? ""),
|
|
4873
|
+
path: String(file.path ?? ""),
|
|
4874
|
+
parentPath: String(file.parent_path ?? ""),
|
|
4875
|
+
name: String(file.name ?? ""),
|
|
4876
|
+
isDirectory: Boolean(file.is_directory),
|
|
4877
|
+
mimeType: String(file.mime_type ?? ""),
|
|
4878
|
+
sizeBytes: Number(file.size_bytes ?? 0),
|
|
4879
|
+
source: String(file.source ?? ""),
|
|
4880
|
+
sourceMessageId: String(file.source_message_id ?? ""),
|
|
4881
|
+
createdAt: Number(file.created_at ?? 0),
|
|
4882
|
+
updatedAt: Number(file.updated_at ?? 0)
|
|
4883
|
+
};
|
|
4884
|
+
}
|
|
4814
4885
|
case "list_users": {
|
|
4815
4886
|
const arr = Array.isArray(p) ? p : [];
|
|
4816
4887
|
return arr.map((u) => ({
|
|
@@ -5155,6 +5226,15 @@ var Client = class {
|
|
|
5155
5226
|
async listUsers() {
|
|
5156
5227
|
return await this.t.perform({ op: "list_users" });
|
|
5157
5228
|
}
|
|
5229
|
+
async listChannelFiles(input) {
|
|
5230
|
+
return await this.t.perform({ op: "list_channel_files", channelId: input.channelId });
|
|
5231
|
+
}
|
|
5232
|
+
async readChannelFile(input) {
|
|
5233
|
+
return await this.t.perform({ op: "read_channel_file", ...input });
|
|
5234
|
+
}
|
|
5235
|
+
async publishChannelFile(input) {
|
|
5236
|
+
return await this.t.perform({ op: "publish_channel_file", ...input });
|
|
5237
|
+
}
|
|
5158
5238
|
async listChannels() {
|
|
5159
5239
|
return await this.t.perform({ op: "list_channels" });
|
|
5160
5240
|
}
|
|
@@ -5295,10 +5375,11 @@ var Client = class {
|
|
|
5295
5375
|
async listTaskPropertyDefinitions() {
|
|
5296
5376
|
return await this.t.perform({ op: "list_task_property_definitions" });
|
|
5297
5377
|
}
|
|
5378
|
+
reportTyping(channelId) {
|
|
5379
|
+
void this.t.perform({ op: "report_typing", channelId }).catch((err) => this.logger.warn("reportTyping failed", err));
|
|
5380
|
+
}
|
|
5298
5381
|
startTyping(channelId) {
|
|
5299
|
-
const emit = () =>
|
|
5300
|
-
void this.t.perform({ op: "report_typing", channelId }).catch((err) => this.logger.warn("startTyping failed", err));
|
|
5301
|
-
};
|
|
5382
|
+
const emit = () => this.reportTyping(channelId);
|
|
5302
5383
|
emit();
|
|
5303
5384
|
const interval = setInterval(emit, 2e3);
|
|
5304
5385
|
interval.unref?.();
|