@slock-ai/daemon 0.54.2 → 0.55.0
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/{chunk-7ZOPGUXT.js → chunk-6Q3U5STT.js} +441 -318
- package/dist/cli/index.js +1217 -689
- package/dist/core.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -46,6 +46,237 @@ function readCliVersion(baseUrl = import.meta.url) {
|
|
|
46
46
|
);
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
// src/proxy.ts
|
|
50
|
+
import { ProxyAgent } from "undici";
|
|
51
|
+
var fetchDispatcherCache = /* @__PURE__ */ new Map();
|
|
52
|
+
function getDefaultPort(protocol) {
|
|
53
|
+
switch (protocol) {
|
|
54
|
+
case "https:":
|
|
55
|
+
return "443";
|
|
56
|
+
case "http:":
|
|
57
|
+
return "80";
|
|
58
|
+
default:
|
|
59
|
+
return "";
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function hostMatchesNoProxyEntry(hostname3, ruleHost) {
|
|
63
|
+
if (!ruleHost) return false;
|
|
64
|
+
const normalizedRule = ruleHost.replace(/^\*\./, ".").replace(/^\./, "").toLowerCase();
|
|
65
|
+
const normalizedHost = hostname3.toLowerCase();
|
|
66
|
+
return normalizedHost === normalizedRule || normalizedHost.endsWith(`.${normalizedRule}`);
|
|
67
|
+
}
|
|
68
|
+
function getProxyUrlForTarget(targetUrl, env) {
|
|
69
|
+
const protocol = new URL(targetUrl).protocol;
|
|
70
|
+
switch (protocol) {
|
|
71
|
+
case "https:":
|
|
72
|
+
return env.HTTPS_PROXY || env.https_proxy || env.ALL_PROXY || env.all_proxy;
|
|
73
|
+
case "http:":
|
|
74
|
+
return env.HTTP_PROXY || env.http_proxy || env.ALL_PROXY || env.all_proxy;
|
|
75
|
+
default:
|
|
76
|
+
return env.ALL_PROXY || env.all_proxy;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
function shouldBypassProxy(targetUrl, env) {
|
|
80
|
+
const rawNoProxy = env.NO_PROXY || env.no_proxy;
|
|
81
|
+
if (!rawNoProxy) return false;
|
|
82
|
+
const url2 = new URL(targetUrl);
|
|
83
|
+
const hostname3 = url2.hostname.toLowerCase();
|
|
84
|
+
const port = url2.port || getDefaultPort(url2.protocol);
|
|
85
|
+
return rawNoProxy.split(",").map((entry) => entry.trim()).filter(Boolean).some((entry) => {
|
|
86
|
+
if (entry === "*") return true;
|
|
87
|
+
const [ruleHost, rulePort] = entry.split(":", 2);
|
|
88
|
+
if (rulePort && rulePort !== port) return false;
|
|
89
|
+
return hostMatchesNoProxyEntry(hostname3, ruleHost);
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
function buildFetchDispatcher(targetUrl, env = process.env) {
|
|
93
|
+
const proxyUrl = getProxyUrlForTarget(targetUrl, env);
|
|
94
|
+
if (!proxyUrl) return void 0;
|
|
95
|
+
if (shouldBypassProxy(targetUrl, env)) return void 0;
|
|
96
|
+
const cached2 = fetchDispatcherCache.get(proxyUrl);
|
|
97
|
+
if (cached2) return cached2;
|
|
98
|
+
const dispatcher = new ProxyAgent(proxyUrl);
|
|
99
|
+
fetchDispatcherCache.set(proxyUrl, dispatcher);
|
|
100
|
+
return dispatcher;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// src/client.ts
|
|
104
|
+
var ApiClient = class {
|
|
105
|
+
constructor(ctx) {
|
|
106
|
+
this.ctx = ctx;
|
|
107
|
+
}
|
|
108
|
+
usesAgentApiSurface() {
|
|
109
|
+
return this.ctx.clientMode === "managed-runner" || this.ctx.clientMode === "self-hosted-runner";
|
|
110
|
+
}
|
|
111
|
+
rewriteAgentCredentialPath(pathname) {
|
|
112
|
+
if (!this.usesAgentApiSurface()) return pathname;
|
|
113
|
+
const attachmentDownload = /^\/api\/attachments\/([^/?]+)(.*)$/.exec(pathname);
|
|
114
|
+
if (attachmentDownload) {
|
|
115
|
+
return `/internal/agent-api/attachments/${attachmentDownload[1]}${attachmentDownload[2] ?? ""}`;
|
|
116
|
+
}
|
|
117
|
+
const agentPrefix = `/internal/agent/${encodeURIComponent(this.ctx.agentId)}`;
|
|
118
|
+
if (!pathname.startsWith(agentPrefix)) return pathname;
|
|
119
|
+
const suffix = pathname.slice(agentPrefix.length);
|
|
120
|
+
if (suffix === "/server") return "/internal/agent-api/server";
|
|
121
|
+
if (suffix === "/send") return "/internal/agent-api/send";
|
|
122
|
+
if (suffix.startsWith("/history")) return `/internal/agent-api/history${suffix.slice("/history".length)}`;
|
|
123
|
+
if (suffix.startsWith("/search")) return `/internal/agent-api/search${suffix.slice("/search".length)}`;
|
|
124
|
+
if (suffix.startsWith("/channel-members")) return `/internal/agent-api/channel-members${suffix.slice("/channel-members".length)}`;
|
|
125
|
+
if (suffix === "/knowledge" || suffix.startsWith("/knowledge?")) {
|
|
126
|
+
return `/internal/agent-api/knowledge${suffix.slice("/knowledge".length)}`;
|
|
127
|
+
}
|
|
128
|
+
if (suffix === "/profile" || suffix.startsWith("/profile/")) return `/internal/agent-api${suffix}`;
|
|
129
|
+
if (suffix === "/integrations" || suffix.startsWith("/integrations/")) return `/internal/agent-api${suffix}`;
|
|
130
|
+
if (suffix === "/upload") return "/internal/agent-api/upload";
|
|
131
|
+
if (suffix === "/resolve-channel") return "/internal/agent-api/resolve-channel";
|
|
132
|
+
if (suffix === "/threads/unfollow") return "/internal/agent-api/threads/unfollow";
|
|
133
|
+
if (suffix === "/prepare-action") return "/internal/agent-api/prepare-action";
|
|
134
|
+
if (suffix === "/tasks" || suffix.startsWith("/tasks?") || suffix.startsWith("/tasks/")) {
|
|
135
|
+
return `/internal/agent-api${suffix}`;
|
|
136
|
+
}
|
|
137
|
+
if (suffix === "/reminders" || suffix.startsWith("/reminders?") || suffix.startsWith("/reminders/")) {
|
|
138
|
+
return `/internal/agent-api${suffix}`;
|
|
139
|
+
}
|
|
140
|
+
if (suffix === "/receive" || suffix.startsWith("/receive?")) {
|
|
141
|
+
return "/internal/agent-api/events?since=latest";
|
|
142
|
+
}
|
|
143
|
+
const reaction = /^\/messages\/([^/]+)\/reactions$/.exec(suffix);
|
|
144
|
+
if (reaction) {
|
|
145
|
+
return `/internal/agent-api/messages/${reaction[1]}/reactions`;
|
|
146
|
+
}
|
|
147
|
+
const channelMembership = /^\/channels\/([^/]+)\/(join|leave)$/.exec(suffix);
|
|
148
|
+
if (channelMembership) {
|
|
149
|
+
return `/internal/agent-api/channels/${channelMembership[1]}/${channelMembership[2]}`;
|
|
150
|
+
}
|
|
151
|
+
return pathname;
|
|
152
|
+
}
|
|
153
|
+
normalizeAgentCredentialResponse(pathname, data) {
|
|
154
|
+
if (!this.usesAgentApiSurface()) return data;
|
|
155
|
+
if (!pathname.includes("/internal/agent-api/events")) return data;
|
|
156
|
+
const value = data;
|
|
157
|
+
if (!Array.isArray(value.events)) return data;
|
|
158
|
+
return { ...data, messages: value.events };
|
|
159
|
+
}
|
|
160
|
+
buildAuthHeaders() {
|
|
161
|
+
const headers = {
|
|
162
|
+
"Authorization": `Bearer ${this.ctx.token}`,
|
|
163
|
+
"X-Agent-Id": this.ctx.agentId,
|
|
164
|
+
"X-Slock-Client": "cli"
|
|
165
|
+
};
|
|
166
|
+
if (this.ctx.serverId) headers["X-Server-Id"] = this.ctx.serverId;
|
|
167
|
+
return headers;
|
|
168
|
+
}
|
|
169
|
+
async parseJsonResponse(res) {
|
|
170
|
+
let data = null;
|
|
171
|
+
let error48 = null;
|
|
172
|
+
let errorCode = null;
|
|
173
|
+
const contentType = res.headers.get("content-type") ?? "";
|
|
174
|
+
if (contentType.includes("application/json")) {
|
|
175
|
+
let parseFailed = false;
|
|
176
|
+
const parsed = await res.json().catch(() => {
|
|
177
|
+
parseFailed = true;
|
|
178
|
+
return null;
|
|
179
|
+
});
|
|
180
|
+
if (parseFailed) {
|
|
181
|
+
return {
|
|
182
|
+
ok: false,
|
|
183
|
+
status: res.status,
|
|
184
|
+
data: null,
|
|
185
|
+
error: `Invalid JSON response from server/proxy (HTTP ${res.status})`,
|
|
186
|
+
errorCode: "INVALID_JSON_RESPONSE"
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
if (res.ok) {
|
|
190
|
+
data = parsed;
|
|
191
|
+
} else {
|
|
192
|
+
const body = parsed;
|
|
193
|
+
if (res.status === 403 && body?.requiredScope) {
|
|
194
|
+
errorCode = "SCOPE_DENIED";
|
|
195
|
+
error48 = `Permission denied. The human has revoked the \`${body.requiredScope}\` capability for this agent under the agent profile's Permissions tab, so this command can't run. If you need it, ask the human to re-enable the corresponding toggle.`;
|
|
196
|
+
} else {
|
|
197
|
+
error48 = body?.error ?? `HTTP ${res.status}`;
|
|
198
|
+
errorCode = body?.errorCode ?? null;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
} else if (!res.ok) {
|
|
202
|
+
error48 = `HTTP ${res.status}`;
|
|
203
|
+
}
|
|
204
|
+
return { ok: res.ok, status: res.status, data, error: error48, errorCode };
|
|
205
|
+
}
|
|
206
|
+
async request(method, pathname, body) {
|
|
207
|
+
pathname = this.rewriteAgentCredentialPath(pathname);
|
|
208
|
+
const url2 = new URL(pathname, this.ctx.serverUrl).toString();
|
|
209
|
+
const headers = this.buildAuthHeaders();
|
|
210
|
+
headers["Content-Type"] = "application/json";
|
|
211
|
+
if (this.ctx.activeCapabilities && this.ctx.activeCapabilities.length > 0) {
|
|
212
|
+
headers["X-Slock-Agent-Active-Capabilities"] = this.ctx.activeCapabilities.join(",");
|
|
213
|
+
}
|
|
214
|
+
const dispatcher = buildFetchDispatcher(url2);
|
|
215
|
+
const init = {
|
|
216
|
+
method,
|
|
217
|
+
headers,
|
|
218
|
+
body: body === void 0 ? void 0 : JSON.stringify(body)
|
|
219
|
+
};
|
|
220
|
+
if (dispatcher) init.dispatcher = dispatcher;
|
|
221
|
+
const res = await fetch(url2, init);
|
|
222
|
+
const parsed = await this.parseJsonResponse(res);
|
|
223
|
+
if (parsed.ok && parsed.data !== null) {
|
|
224
|
+
parsed.data = this.normalizeAgentCredentialResponse(pathname, parsed.data);
|
|
225
|
+
}
|
|
226
|
+
return parsed;
|
|
227
|
+
}
|
|
228
|
+
// Multipart upload. Caller builds the FormData (file part + any text fields).
|
|
229
|
+
// Content-Type intentionally omitted so fetch sets the correct multipart
|
|
230
|
+
// boundary itself.
|
|
231
|
+
async requestMultipart(method, pathname, form) {
|
|
232
|
+
pathname = this.rewriteAgentCredentialPath(pathname);
|
|
233
|
+
const url2 = new URL(pathname, this.ctx.serverUrl).toString();
|
|
234
|
+
const dispatcher = buildFetchDispatcher(url2);
|
|
235
|
+
const headers = this.buildAuthHeaders();
|
|
236
|
+
if (this.ctx.activeCapabilities && this.ctx.activeCapabilities.length > 0) {
|
|
237
|
+
headers["X-Slock-Agent-Active-Capabilities"] = this.ctx.activeCapabilities.join(",");
|
|
238
|
+
}
|
|
239
|
+
const init = {
|
|
240
|
+
method,
|
|
241
|
+
headers,
|
|
242
|
+
body: form
|
|
243
|
+
};
|
|
244
|
+
if (dispatcher) init.dispatcher = dispatcher;
|
|
245
|
+
const res = await fetch(url2, init);
|
|
246
|
+
return this.parseJsonResponse(res);
|
|
247
|
+
}
|
|
248
|
+
// Returns the raw Response so the caller can stream / save the body.
|
|
249
|
+
// For non-JSON downloads (binary attachments). Caller is responsible for
|
|
250
|
+
// consuming the body. On non-2xx, attempts to surface a JSON error.
|
|
251
|
+
async requestRaw(method, pathname) {
|
|
252
|
+
pathname = this.rewriteAgentCredentialPath(pathname);
|
|
253
|
+
const url2 = new URL(pathname, this.ctx.serverUrl).toString();
|
|
254
|
+
const dispatcher = buildFetchDispatcher(url2);
|
|
255
|
+
const headers = this.buildAuthHeaders();
|
|
256
|
+
if (this.ctx.activeCapabilities && this.ctx.activeCapabilities.length > 0) {
|
|
257
|
+
headers["X-Slock-Agent-Active-Capabilities"] = this.ctx.activeCapabilities.join(",");
|
|
258
|
+
}
|
|
259
|
+
const init = {
|
|
260
|
+
method,
|
|
261
|
+
headers,
|
|
262
|
+
redirect: "follow"
|
|
263
|
+
};
|
|
264
|
+
if (dispatcher) init.dispatcher = dispatcher;
|
|
265
|
+
const res = await fetch(url2, init);
|
|
266
|
+
let error48 = null;
|
|
267
|
+
if (!res.ok) {
|
|
268
|
+
const contentType = res.headers.get("content-type") ?? "";
|
|
269
|
+
if (contentType.includes("application/json")) {
|
|
270
|
+
const parsed = await res.json().catch(() => null);
|
|
271
|
+
error48 = parsed?.error ?? `HTTP ${res.status}`;
|
|
272
|
+
} else {
|
|
273
|
+
error48 = `HTTP ${res.status}`;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
return { ok: res.ok, status: res.status, response: res, error: error48 };
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
|
|
49
280
|
// src/auth/env.ts
|
|
50
281
|
import fs from "fs";
|
|
51
282
|
import os from "os";
|
|
@@ -216,44 +447,156 @@ function loadAgentContext(env = process.env) {
|
|
|
216
447
|
);
|
|
217
448
|
}
|
|
218
449
|
|
|
219
|
-
// src/
|
|
220
|
-
function
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
} catch (err) {
|
|
226
|
-
if (err instanceof AgentBootstrapError) fail(err.code, err.message);
|
|
227
|
-
throw err;
|
|
228
|
-
}
|
|
229
|
-
emit({
|
|
230
|
-
ok: true,
|
|
231
|
-
data: {
|
|
232
|
-
agentId: ctx.agentId,
|
|
233
|
-
serverUrl: ctx.serverUrl,
|
|
234
|
-
serverId: ctx.serverId,
|
|
235
|
-
clientMode: ctx.clientMode,
|
|
236
|
-
secretSource: ctx.secretSource,
|
|
237
|
-
...ctx.profileSlug ? { profileSlug: ctx.profileSlug } : {},
|
|
238
|
-
...ctx.profileCredentialPath ? { profileCredentialPath: ctx.profileCredentialPath } : {}
|
|
239
|
-
}
|
|
240
|
-
});
|
|
241
|
-
});
|
|
450
|
+
// src/core/io.ts
|
|
451
|
+
function defaultCliIo() {
|
|
452
|
+
return {
|
|
453
|
+
stdout: process.stdout,
|
|
454
|
+
stderr: process.stderr
|
|
455
|
+
};
|
|
242
456
|
}
|
|
243
457
|
|
|
244
|
-
// src/
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
this.code = code;
|
|
253
|
-
this.
|
|
458
|
+
// src/core/errors.ts
|
|
459
|
+
var CliError = class extends Error {
|
|
460
|
+
code;
|
|
461
|
+
exitCode;
|
|
462
|
+
suggestedNextAction;
|
|
463
|
+
constructor(options) {
|
|
464
|
+
super(options.message);
|
|
465
|
+
this.name = "CliError";
|
|
466
|
+
this.code = options.code;
|
|
467
|
+
this.exitCode = options.exitCode ?? 1;
|
|
468
|
+
this.cause = options.cause;
|
|
469
|
+
this.suggestedNextAction = options.suggestedNextAction;
|
|
254
470
|
}
|
|
255
471
|
};
|
|
256
|
-
var
|
|
472
|
+
var InternalBugError = class extends CliError {
|
|
473
|
+
constructor(cause) {
|
|
474
|
+
const message = cause instanceof Error ? cause.message : String(cause);
|
|
475
|
+
super({
|
|
476
|
+
code: "INTERNAL_BUG",
|
|
477
|
+
message: `Unexpected error: ${message}`,
|
|
478
|
+
cause
|
|
479
|
+
});
|
|
480
|
+
this.name = "InternalBugError";
|
|
481
|
+
}
|
|
482
|
+
};
|
|
483
|
+
function toCliError(err) {
|
|
484
|
+
if (err instanceof CliError) return err;
|
|
485
|
+
return new InternalBugError(err);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
// src/core/context.ts
|
|
489
|
+
function createCommandContext(options = {}) {
|
|
490
|
+
const io = options.io ?? defaultCliIo();
|
|
491
|
+
const env = options.env ?? process.env;
|
|
492
|
+
const loadContext = options.loadAgentContext ?? loadAgentContext;
|
|
493
|
+
const createApiClient = options.createApiClient ?? ((agentContext) => new ApiClient(agentContext));
|
|
494
|
+
return {
|
|
495
|
+
io,
|
|
496
|
+
env,
|
|
497
|
+
loadAgentContext() {
|
|
498
|
+
try {
|
|
499
|
+
return loadContext(env);
|
|
500
|
+
} catch (err) {
|
|
501
|
+
if (err instanceof AgentBootstrapError) {
|
|
502
|
+
throw new CliError({
|
|
503
|
+
code: err.code,
|
|
504
|
+
message: err.message,
|
|
505
|
+
cause: err
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
throw err;
|
|
509
|
+
}
|
|
510
|
+
},
|
|
511
|
+
createApiClient
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// src/core/renderer.ts
|
|
516
|
+
function renderError(io, err) {
|
|
517
|
+
const body = {
|
|
518
|
+
ok: false,
|
|
519
|
+
code: err.code,
|
|
520
|
+
message: err.message
|
|
521
|
+
};
|
|
522
|
+
if (err.suggestedNextAction) {
|
|
523
|
+
body.suggested_next_action = err.suggestedNextAction;
|
|
524
|
+
}
|
|
525
|
+
io.stderr.write(`${JSON.stringify(body)}
|
|
526
|
+
`);
|
|
527
|
+
}
|
|
528
|
+
function writeText(io, text) {
|
|
529
|
+
io.stdout.write(text);
|
|
530
|
+
}
|
|
531
|
+
function writeJson(io, payload) {
|
|
532
|
+
io.stdout.write(`${JSON.stringify(payload)}
|
|
533
|
+
`);
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
// src/core/command.ts
|
|
537
|
+
function defineCommand(spec, handler) {
|
|
538
|
+
return { spec, handler };
|
|
539
|
+
}
|
|
540
|
+
function registerCliCommand(parent, command, runtimeOptions = {}) {
|
|
541
|
+
const child = parent.command(command.spec.name).description(command.spec.description);
|
|
542
|
+
for (const arg of command.spec.arguments ?? []) {
|
|
543
|
+
child.argument(arg);
|
|
544
|
+
}
|
|
545
|
+
for (const option of command.spec.options ?? []) {
|
|
546
|
+
child.option(option.flags, option.description);
|
|
547
|
+
}
|
|
548
|
+
child.action(async (...args) => {
|
|
549
|
+
const ctx = createCommandContext(runtimeOptions);
|
|
550
|
+
try {
|
|
551
|
+
await command.handler(ctx, ...args);
|
|
552
|
+
} catch (err) {
|
|
553
|
+
const cliError = toCliError(err);
|
|
554
|
+
renderError(ctx.io, cliError);
|
|
555
|
+
throw new CliExit(cliError.exitCode);
|
|
556
|
+
}
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
// src/commands/auth/whoami.ts
|
|
561
|
+
var whoamiCommand = defineCommand(
|
|
562
|
+
{
|
|
563
|
+
name: "whoami",
|
|
564
|
+
description: "Print the agent context resolved from env (token value redacted)",
|
|
565
|
+
rationale: "denied"
|
|
566
|
+
},
|
|
567
|
+
(ctx) => {
|
|
568
|
+
const agentContext = ctx.loadAgentContext();
|
|
569
|
+
writeJson(ctx.io, {
|
|
570
|
+
ok: true,
|
|
571
|
+
data: {
|
|
572
|
+
agentId: agentContext.agentId,
|
|
573
|
+
serverUrl: agentContext.serverUrl,
|
|
574
|
+
serverId: agentContext.serverId,
|
|
575
|
+
clientMode: agentContext.clientMode,
|
|
576
|
+
secretSource: agentContext.secretSource,
|
|
577
|
+
...agentContext.profileSlug ? { profileSlug: agentContext.profileSlug } : {},
|
|
578
|
+
...agentContext.profileCredentialPath ? { profileCredentialPath: agentContext.profileCredentialPath } : {}
|
|
579
|
+
}
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
|
+
);
|
|
583
|
+
function registerWhoamiCommand(parent, runtimeOptions) {
|
|
584
|
+
registerCliCommand(parent, whoamiCommand, runtimeOptions);
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
// src/commands/agent/list.ts
|
|
588
|
+
import { fetch as undiciFetch } from "undici";
|
|
589
|
+
|
|
590
|
+
// src/agentLogin/deviceAuthClient.ts
|
|
591
|
+
import { fetch as fetch2 } from "undici";
|
|
592
|
+
var DeviceCodeLoginError = class extends Error {
|
|
593
|
+
constructor(code, message) {
|
|
594
|
+
super(message);
|
|
595
|
+
this.code = code;
|
|
596
|
+
this.name = "DeviceCodeLoginError";
|
|
597
|
+
}
|
|
598
|
+
};
|
|
599
|
+
var ACTIONABLE_ERROR_MESSAGES = {
|
|
257
600
|
device_login_disabled: "Device login is not enabled on this Slock server. Ask an admin to set SLOCK_DEVICE_LOGIN_ENABLED=true.",
|
|
258
601
|
device_code_required: "Internal CLI bug: device_code was missing from the poll request.",
|
|
259
602
|
user_code_required: "Internal CLI bug: user_code was missing from the approve request.",
|
|
@@ -575,6 +918,30 @@ function describeMintError(code, serverUrl) {
|
|
|
575
918
|
return void 0;
|
|
576
919
|
}
|
|
577
920
|
|
|
921
|
+
// ../shared/src/slockRefs.ts
|
|
922
|
+
var SLOCK_REF_CHANNEL_NAME_PATTERN = String.raw`[\p{L}\p{N}_-]+`;
|
|
923
|
+
var SLOCK_REF_USER_NAME_PATTERN = SLOCK_REF_CHANNEL_NAME_PATTERN;
|
|
924
|
+
var SLOCK_REF_DM_PEER_PATTERN = String.raw`[\w-]+`;
|
|
925
|
+
var SLOCK_REF_THREAD_SHORT_ID_PATTERN = String.raw`[\da-f]{6,8}`;
|
|
926
|
+
var SLOCK_REF_MESSAGE_ID_PATTERN = String.raw`[A-Za-z0-9][A-Za-z0-9-]{1,63}`;
|
|
927
|
+
var SLOCK_REF_TASK_NUMBER_PATTERN = String.raw`[1-9]\d*`;
|
|
928
|
+
var USER_RE = new RegExp(String.raw`^@(${SLOCK_REF_USER_NAME_PATTERN})$`, "u");
|
|
929
|
+
var CHANNEL_RE = new RegExp(String.raw`^#(${SLOCK_REF_CHANNEL_NAME_PATTERN})$`, "u");
|
|
930
|
+
var CHANNEL_THREAD_RE = new RegExp(
|
|
931
|
+
String.raw`^#(${SLOCK_REF_CHANNEL_NAME_PATTERN}):(${SLOCK_REF_THREAD_SHORT_ID_PATTERN})$`,
|
|
932
|
+
"iu"
|
|
933
|
+
);
|
|
934
|
+
var DM_RE = new RegExp(String.raw`^dm:@(${SLOCK_REF_DM_PEER_PATTERN})$`, "iu");
|
|
935
|
+
var DM_THREAD_RE = new RegExp(
|
|
936
|
+
String.raw`^dm:@(${SLOCK_REF_DM_PEER_PATTERN}):(${SLOCK_REF_THREAD_SHORT_ID_PATTERN})$`,
|
|
937
|
+
"iu"
|
|
938
|
+
);
|
|
939
|
+
var TASK_RE = new RegExp(String.raw`^task\s+#(${SLOCK_REF_TASK_NUMBER_PATTERN})$`, "iu");
|
|
940
|
+
var CHANNEL_MESSAGE_RE = new RegExp(
|
|
941
|
+
String.raw`^#(${SLOCK_REF_CHANNEL_NAME_PATTERN})(?::(${SLOCK_REF_THREAD_SHORT_ID_PATTERN}))?\s+msg=(${SLOCK_REF_MESSAGE_ID_PATTERN})$`,
|
|
942
|
+
"iu"
|
|
943
|
+
);
|
|
944
|
+
|
|
578
945
|
// ../shared/src/tracing/index.ts
|
|
579
946
|
var DEFAULT_TRACE_FLAGS = "00";
|
|
580
947
|
var TRACE_ID_HEX_LENGTH = 32;
|
|
@@ -14481,384 +14848,156 @@ var channelAddMemberOperationSchema = external_exports.object({
|
|
|
14481
14848
|
channel: idOrHandleSchema,
|
|
14482
14849
|
/** Same resolution rule as `channelCreateOperationSchema.initialHumans`. */
|
|
14483
14850
|
humans: external_exports.array(idOrHandleSchema).max(64).optional(),
|
|
14484
|
-
/** Same resolution rule as `channelCreateOperationSchema.initialAgents`. */
|
|
14485
|
-
agents: external_exports.array(idOrHandleSchema).max(64).optional(),
|
|
14486
|
-
draftHint: draftHintSchema
|
|
14487
|
-
});
|
|
14488
|
-
var actionCardActionSchema = external_exports.discriminatedUnion("type", [
|
|
14489
|
-
channelCreateOperationSchema,
|
|
14490
|
-
agentCreateOperationSchema,
|
|
14491
|
-
channelAddMemberOperationSchema
|
|
14492
|
-
]);
|
|
14493
|
-
function validateActionCardAction(action) {
|
|
14494
|
-
if (action.type === "agent:create") {
|
|
14495
|
-
if (action.suggestedComputer && action.requiredComputer) {
|
|
14496
|
-
return "agent:create must include only one of suggestedComputer or requiredComputer";
|
|
14497
|
-
}
|
|
14498
|
-
}
|
|
14499
|
-
if (action.type === "channel:add_member") {
|
|
14500
|
-
const total = (action.humans?.length ?? 0) + (action.agents?.length ?? 0);
|
|
14501
|
-
if (total === 0) {
|
|
14502
|
-
return "channel:add_member must include at least one human or agent";
|
|
14503
|
-
}
|
|
14504
|
-
}
|
|
14505
|
-
return null;
|
|
14506
|
-
}
|
|
14507
|
-
|
|
14508
|
-
// ../shared/src/translationLanguages.ts
|
|
14509
|
-
var SUPPORTED_TRANSLATION_LANGUAGE_CODES = [
|
|
14510
|
-
"en",
|
|
14511
|
-
"zh-cn",
|
|
14512
|
-
"zh-tw",
|
|
14513
|
-
"ja",
|
|
14514
|
-
"ko",
|
|
14515
|
-
"es",
|
|
14516
|
-
"fr",
|
|
14517
|
-
"de",
|
|
14518
|
-
"pt-br"
|
|
14519
|
-
];
|
|
14520
|
-
var SUPPORTED_TRANSLATION_LANGUAGE_SET = new Set(
|
|
14521
|
-
SUPPORTED_TRANSLATION_LANGUAGE_CODES
|
|
14522
|
-
);
|
|
14523
|
-
|
|
14524
|
-
// ../shared/src/testing/failpoints.ts
|
|
14525
|
-
var NoopFailpointRegistry = class {
|
|
14526
|
-
get enabled() {
|
|
14527
|
-
return false;
|
|
14528
|
-
}
|
|
14529
|
-
isEnabled() {
|
|
14530
|
-
return false;
|
|
14531
|
-
}
|
|
14532
|
-
configure() {
|
|
14533
|
-
}
|
|
14534
|
-
clear() {
|
|
14535
|
-
}
|
|
14536
|
-
getTrace() {
|
|
14537
|
-
return [];
|
|
14538
|
-
}
|
|
14539
|
-
hit(_key, _context, fallback) {
|
|
14540
|
-
return fallback ? fallback() : void 0;
|
|
14541
|
-
}
|
|
14542
|
-
};
|
|
14543
|
-
var noopFailpointRegistry = new NoopFailpointRegistry();
|
|
14544
|
-
|
|
14545
|
-
// ../shared/src/serverPermissions.ts
|
|
14546
|
-
var EMPTY_SERVER_CAPABILITIES = Object.freeze({
|
|
14547
|
-
manageServer: false,
|
|
14548
|
-
manageChannels: false,
|
|
14549
|
-
manageAgents: false,
|
|
14550
|
-
manageMachines: false,
|
|
14551
|
-
manageMembers: false,
|
|
14552
|
-
changeMemberRoles: false,
|
|
14553
|
-
manageBilling: false,
|
|
14554
|
-
joinPublicChannels: false
|
|
14555
|
-
});
|
|
14556
|
-
var SERVER_CAPABILITY_MATRIX = {
|
|
14557
|
-
owner: Object.freeze({
|
|
14558
|
-
manageServer: true,
|
|
14559
|
-
manageChannels: true,
|
|
14560
|
-
manageAgents: true,
|
|
14561
|
-
manageMachines: true,
|
|
14562
|
-
manageMembers: true,
|
|
14563
|
-
changeMemberRoles: true,
|
|
14564
|
-
manageBilling: true,
|
|
14565
|
-
joinPublicChannels: true
|
|
14566
|
-
}),
|
|
14567
|
-
admin: Object.freeze({
|
|
14568
|
-
manageServer: true,
|
|
14569
|
-
manageChannels: true,
|
|
14570
|
-
manageAgents: true,
|
|
14571
|
-
manageMachines: true,
|
|
14572
|
-
manageMembers: true,
|
|
14573
|
-
changeMemberRoles: true,
|
|
14574
|
-
manageBilling: false,
|
|
14575
|
-
joinPublicChannels: true
|
|
14576
|
-
}),
|
|
14577
|
-
member: Object.freeze({
|
|
14578
|
-
manageServer: false,
|
|
14579
|
-
manageChannels: false,
|
|
14580
|
-
manageAgents: false,
|
|
14581
|
-
manageMachines: false,
|
|
14582
|
-
manageMembers: false,
|
|
14583
|
-
changeMemberRoles: false,
|
|
14584
|
-
manageBilling: false,
|
|
14585
|
-
joinPublicChannels: true
|
|
14586
|
-
})
|
|
14587
|
-
};
|
|
14588
|
-
|
|
14589
|
-
// ../shared/src/index.ts
|
|
14590
|
-
var RUNTIMES = [
|
|
14591
|
-
{ id: "claude", displayName: "Claude Code", binary: "claude", supported: true },
|
|
14592
|
-
{ id: "codex", displayName: "Codex CLI", binary: "codex", supported: true },
|
|
14593
|
-
{ id: "antigravity", displayName: "Antigravity CLI", binary: "agy", supported: true },
|
|
14594
|
-
{ id: "kimi", displayName: "Kimi CLI", binary: "kimi", supported: true },
|
|
14595
|
-
{ id: "copilot", displayName: "Copilot CLI", binary: "copilot", supported: true },
|
|
14596
|
-
{ id: "cursor", displayName: "Cursor CLI", binary: "cursor-agent", supported: true },
|
|
14597
|
-
{ id: "gemini", displayName: "Gemini CLI", binary: "gemini", supported: true },
|
|
14598
|
-
{ id: "opencode", displayName: "OpenCode", binary: "opencode", supported: true }
|
|
14599
|
-
];
|
|
14600
|
-
function getRuntimeDisplayName(id) {
|
|
14601
|
-
return RUNTIMES.find((r) => r.id === id)?.displayName ?? id;
|
|
14602
|
-
}
|
|
14603
|
-
var PLAN_CONFIG = {
|
|
14604
|
-
free: {
|
|
14605
|
-
displayName: "Hobby",
|
|
14606
|
-
limits: { maxMachines: 2, maxAgents: 5, maxChannels: 5, messageHistoryDays: 30, includedAgents: 5 },
|
|
14607
|
-
comingSoon: false,
|
|
14608
|
-
price: 0,
|
|
14609
|
-
extraAgentPrice: 0
|
|
14610
|
-
},
|
|
14611
|
-
founder: {
|
|
14612
|
-
displayName: "Founder",
|
|
14613
|
-
limits: { maxMachines: -1, maxAgents: -1, maxChannels: -1, messageHistoryDays: -1, includedAgents: -1 },
|
|
14614
|
-
comingSoon: false,
|
|
14615
|
-
price: 0,
|
|
14616
|
-
extraAgentPrice: 0
|
|
14617
|
-
}
|
|
14618
|
-
};
|
|
14619
|
-
var DISPLAY_PLAN_CONFIG = {
|
|
14620
|
-
free: PLAN_CONFIG.free,
|
|
14621
|
-
pro: {
|
|
14622
|
-
displayName: "Team",
|
|
14623
|
-
limits: { maxMachines: 8, maxAgents: 40, maxChannels: 20, messageHistoryDays: -1, includedAgents: 40 },
|
|
14624
|
-
comingSoon: true,
|
|
14625
|
-
price: 20,
|
|
14626
|
-
extraAgentPrice: 0
|
|
14627
|
-
},
|
|
14628
|
-
max: {
|
|
14629
|
-
displayName: "Business",
|
|
14630
|
-
limits: { maxMachines: 40, maxAgents: 200, maxChannels: -1, messageHistoryDays: -1, includedAgents: 200 },
|
|
14631
|
-
comingSoon: true,
|
|
14632
|
-
price: 200,
|
|
14633
|
-
extraAgentPrice: 0
|
|
14634
|
-
}
|
|
14635
|
-
};
|
|
14636
|
-
|
|
14637
|
-
// src/proxy.ts
|
|
14638
|
-
import { ProxyAgent } from "undici";
|
|
14639
|
-
var fetchDispatcherCache = /* @__PURE__ */ new Map();
|
|
14640
|
-
function getDefaultPort(protocol) {
|
|
14641
|
-
switch (protocol) {
|
|
14642
|
-
case "https:":
|
|
14643
|
-
return "443";
|
|
14644
|
-
case "http:":
|
|
14645
|
-
return "80";
|
|
14646
|
-
default:
|
|
14647
|
-
return "";
|
|
14648
|
-
}
|
|
14649
|
-
}
|
|
14650
|
-
function hostMatchesNoProxyEntry(hostname3, ruleHost) {
|
|
14651
|
-
if (!ruleHost) return false;
|
|
14652
|
-
const normalizedRule = ruleHost.replace(/^\*\./, ".").replace(/^\./, "").toLowerCase();
|
|
14653
|
-
const normalizedHost = hostname3.toLowerCase();
|
|
14654
|
-
return normalizedHost === normalizedRule || normalizedHost.endsWith(`.${normalizedRule}`);
|
|
14655
|
-
}
|
|
14656
|
-
function getProxyUrlForTarget(targetUrl, env) {
|
|
14657
|
-
const protocol = new URL(targetUrl).protocol;
|
|
14658
|
-
switch (protocol) {
|
|
14659
|
-
case "https:":
|
|
14660
|
-
return env.HTTPS_PROXY || env.https_proxy || env.ALL_PROXY || env.all_proxy;
|
|
14661
|
-
case "http:":
|
|
14662
|
-
return env.HTTP_PROXY || env.http_proxy || env.ALL_PROXY || env.all_proxy;
|
|
14663
|
-
default:
|
|
14664
|
-
return env.ALL_PROXY || env.all_proxy;
|
|
14665
|
-
}
|
|
14666
|
-
}
|
|
14667
|
-
function shouldBypassProxy(targetUrl, env) {
|
|
14668
|
-
const rawNoProxy = env.NO_PROXY || env.no_proxy;
|
|
14669
|
-
if (!rawNoProxy) return false;
|
|
14670
|
-
const url2 = new URL(targetUrl);
|
|
14671
|
-
const hostname3 = url2.hostname.toLowerCase();
|
|
14672
|
-
const port = url2.port || getDefaultPort(url2.protocol);
|
|
14673
|
-
return rawNoProxy.split(",").map((entry) => entry.trim()).filter(Boolean).some((entry) => {
|
|
14674
|
-
if (entry === "*") return true;
|
|
14675
|
-
const [ruleHost, rulePort] = entry.split(":", 2);
|
|
14676
|
-
if (rulePort && rulePort !== port) return false;
|
|
14677
|
-
return hostMatchesNoProxyEntry(hostname3, ruleHost);
|
|
14678
|
-
});
|
|
14679
|
-
}
|
|
14680
|
-
function buildFetchDispatcher(targetUrl, env = process.env) {
|
|
14681
|
-
const proxyUrl = getProxyUrlForTarget(targetUrl, env);
|
|
14682
|
-
if (!proxyUrl) return void 0;
|
|
14683
|
-
if (shouldBypassProxy(targetUrl, env)) return void 0;
|
|
14684
|
-
const cached2 = fetchDispatcherCache.get(proxyUrl);
|
|
14685
|
-
if (cached2) return cached2;
|
|
14686
|
-
const dispatcher = new ProxyAgent(proxyUrl);
|
|
14687
|
-
fetchDispatcherCache.set(proxyUrl, dispatcher);
|
|
14688
|
-
return dispatcher;
|
|
14689
|
-
}
|
|
14690
|
-
|
|
14691
|
-
// src/client.ts
|
|
14692
|
-
var ApiClient = class {
|
|
14693
|
-
constructor(ctx) {
|
|
14694
|
-
this.ctx = ctx;
|
|
14695
|
-
}
|
|
14696
|
-
usesAgentApiSurface() {
|
|
14697
|
-
return this.ctx.clientMode === "managed-runner" || this.ctx.clientMode === "self-hosted-runner";
|
|
14698
|
-
}
|
|
14699
|
-
rewriteAgentCredentialPath(pathname) {
|
|
14700
|
-
if (!this.usesAgentApiSurface()) return pathname;
|
|
14701
|
-
const attachmentDownload = /^\/api\/attachments\/([^/?]+)(.*)$/.exec(pathname);
|
|
14702
|
-
if (attachmentDownload) {
|
|
14703
|
-
return `/internal/agent-api/attachments/${attachmentDownload[1]}${attachmentDownload[2] ?? ""}`;
|
|
14704
|
-
}
|
|
14705
|
-
const agentPrefix = `/internal/agent/${encodeURIComponent(this.ctx.agentId)}`;
|
|
14706
|
-
if (!pathname.startsWith(agentPrefix)) return pathname;
|
|
14707
|
-
const suffix = pathname.slice(agentPrefix.length);
|
|
14708
|
-
if (suffix === "/server") return "/internal/agent-api/server";
|
|
14709
|
-
if (suffix === "/send") return "/internal/agent-api/send";
|
|
14710
|
-
if (suffix.startsWith("/history")) return `/internal/agent-api/history${suffix.slice("/history".length)}`;
|
|
14711
|
-
if (suffix.startsWith("/search")) return `/internal/agent-api/search${suffix.slice("/search".length)}`;
|
|
14712
|
-
if (suffix.startsWith("/channel-members")) return `/internal/agent-api/channel-members${suffix.slice("/channel-members".length)}`;
|
|
14713
|
-
if (suffix === "/profile" || suffix.startsWith("/profile/")) return `/internal/agent-api${suffix}`;
|
|
14714
|
-
if (suffix === "/integrations" || suffix.startsWith("/integrations/")) return `/internal/agent-api${suffix}`;
|
|
14715
|
-
if (suffix === "/upload") return "/internal/agent-api/upload";
|
|
14716
|
-
if (suffix === "/resolve-channel") return "/internal/agent-api/resolve-channel";
|
|
14717
|
-
if (suffix === "/threads/unfollow") return "/internal/agent-api/threads/unfollow";
|
|
14718
|
-
if (suffix === "/prepare-action") return "/internal/agent-api/prepare-action";
|
|
14719
|
-
if (suffix === "/tasks" || suffix.startsWith("/tasks?") || suffix.startsWith("/tasks/")) {
|
|
14720
|
-
return `/internal/agent-api${suffix}`;
|
|
14721
|
-
}
|
|
14722
|
-
if (suffix === "/reminders" || suffix.startsWith("/reminders?") || suffix.startsWith("/reminders/")) {
|
|
14723
|
-
return `/internal/agent-api${suffix}`;
|
|
14724
|
-
}
|
|
14725
|
-
if (suffix === "/receive" || suffix.startsWith("/receive?")) {
|
|
14726
|
-
return "/internal/agent-api/events?since=latest";
|
|
14727
|
-
}
|
|
14728
|
-
const reaction = /^\/messages\/([^/]+)\/reactions$/.exec(suffix);
|
|
14729
|
-
if (reaction) {
|
|
14730
|
-
return `/internal/agent-api/messages/${reaction[1]}/reactions`;
|
|
14731
|
-
}
|
|
14732
|
-
const channelMembership = /^\/channels\/([^/]+)\/(join|leave)$/.exec(suffix);
|
|
14733
|
-
if (channelMembership) {
|
|
14734
|
-
return `/internal/agent-api/channels/${channelMembership[1]}/${channelMembership[2]}`;
|
|
14735
|
-
}
|
|
14736
|
-
return pathname;
|
|
14737
|
-
}
|
|
14738
|
-
normalizeAgentCredentialResponse(pathname, data) {
|
|
14739
|
-
if (!this.usesAgentApiSurface()) return data;
|
|
14740
|
-
if (!pathname.includes("/internal/agent-api/events")) return data;
|
|
14741
|
-
const value = data;
|
|
14742
|
-
if (!Array.isArray(value.events)) return data;
|
|
14743
|
-
return { ...data, messages: value.events };
|
|
14744
|
-
}
|
|
14745
|
-
buildAuthHeaders() {
|
|
14746
|
-
const headers = {
|
|
14747
|
-
"Authorization": `Bearer ${this.ctx.token}`,
|
|
14748
|
-
"X-Agent-Id": this.ctx.agentId,
|
|
14749
|
-
"X-Slock-Client": "cli"
|
|
14750
|
-
};
|
|
14751
|
-
if (this.ctx.serverId) headers["X-Server-Id"] = this.ctx.serverId;
|
|
14752
|
-
return headers;
|
|
14753
|
-
}
|
|
14754
|
-
async parseJsonResponse(res) {
|
|
14755
|
-
let data = null;
|
|
14756
|
-
let error48 = null;
|
|
14757
|
-
let errorCode = null;
|
|
14758
|
-
const contentType = res.headers.get("content-type") ?? "";
|
|
14759
|
-
if (contentType.includes("application/json")) {
|
|
14760
|
-
let parseFailed = false;
|
|
14761
|
-
const parsed = await res.json().catch(() => {
|
|
14762
|
-
parseFailed = true;
|
|
14763
|
-
return null;
|
|
14764
|
-
});
|
|
14765
|
-
if (parseFailed) {
|
|
14766
|
-
return {
|
|
14767
|
-
ok: false,
|
|
14768
|
-
status: res.status,
|
|
14769
|
-
data: null,
|
|
14770
|
-
error: `Invalid JSON response from server/proxy (HTTP ${res.status})`,
|
|
14771
|
-
errorCode: "INVALID_JSON_RESPONSE"
|
|
14772
|
-
};
|
|
14773
|
-
}
|
|
14774
|
-
if (res.ok) {
|
|
14775
|
-
data = parsed;
|
|
14776
|
-
} else {
|
|
14777
|
-
const body = parsed;
|
|
14778
|
-
if (res.status === 403 && body?.requiredScope) {
|
|
14779
|
-
errorCode = "SCOPE_DENIED";
|
|
14780
|
-
error48 = `Permission denied. The human has revoked the \`${body.requiredScope}\` capability for this agent under the agent profile's Permissions tab, so this command can't run. If you need it, ask the human to re-enable the corresponding toggle.`;
|
|
14781
|
-
} else {
|
|
14782
|
-
error48 = body?.error ?? `HTTP ${res.status}`;
|
|
14783
|
-
errorCode = body?.errorCode ?? null;
|
|
14784
|
-
}
|
|
14785
|
-
}
|
|
14786
|
-
} else if (!res.ok) {
|
|
14787
|
-
error48 = `HTTP ${res.status}`;
|
|
14788
|
-
}
|
|
14789
|
-
return { ok: res.ok, status: res.status, data, error: error48, errorCode };
|
|
14790
|
-
}
|
|
14791
|
-
async request(method, pathname, body) {
|
|
14792
|
-
pathname = this.rewriteAgentCredentialPath(pathname);
|
|
14793
|
-
const url2 = new URL(pathname, this.ctx.serverUrl).toString();
|
|
14794
|
-
const headers = this.buildAuthHeaders();
|
|
14795
|
-
headers["Content-Type"] = "application/json";
|
|
14796
|
-
if (this.ctx.activeCapabilities && this.ctx.activeCapabilities.length > 0) {
|
|
14797
|
-
headers["X-Slock-Agent-Active-Capabilities"] = this.ctx.activeCapabilities.join(",");
|
|
14798
|
-
}
|
|
14799
|
-
const dispatcher = buildFetchDispatcher(url2);
|
|
14800
|
-
const init = {
|
|
14801
|
-
method,
|
|
14802
|
-
headers,
|
|
14803
|
-
body: body === void 0 ? void 0 : JSON.stringify(body)
|
|
14804
|
-
};
|
|
14805
|
-
if (dispatcher) init.dispatcher = dispatcher;
|
|
14806
|
-
const res = await fetch(url2, init);
|
|
14807
|
-
const parsed = await this.parseJsonResponse(res);
|
|
14808
|
-
if (parsed.ok && parsed.data !== null) {
|
|
14809
|
-
parsed.data = this.normalizeAgentCredentialResponse(pathname, parsed.data);
|
|
14851
|
+
/** Same resolution rule as `channelCreateOperationSchema.initialAgents`. */
|
|
14852
|
+
agents: external_exports.array(idOrHandleSchema).max(64).optional(),
|
|
14853
|
+
draftHint: draftHintSchema
|
|
14854
|
+
});
|
|
14855
|
+
var actionCardActionSchema = external_exports.discriminatedUnion("type", [
|
|
14856
|
+
channelCreateOperationSchema,
|
|
14857
|
+
agentCreateOperationSchema,
|
|
14858
|
+
channelAddMemberOperationSchema
|
|
14859
|
+
]);
|
|
14860
|
+
function validateActionCardAction(action) {
|
|
14861
|
+
if (action.type === "agent:create") {
|
|
14862
|
+
if (action.suggestedComputer && action.requiredComputer) {
|
|
14863
|
+
return "agent:create must include only one of suggestedComputer or requiredComputer";
|
|
14810
14864
|
}
|
|
14811
|
-
return parsed;
|
|
14812
14865
|
}
|
|
14813
|
-
|
|
14814
|
-
|
|
14815
|
-
|
|
14816
|
-
|
|
14817
|
-
pathname = this.rewriteAgentCredentialPath(pathname);
|
|
14818
|
-
const url2 = new URL(pathname, this.ctx.serverUrl).toString();
|
|
14819
|
-
const dispatcher = buildFetchDispatcher(url2);
|
|
14820
|
-
const headers = this.buildAuthHeaders();
|
|
14821
|
-
if (this.ctx.activeCapabilities && this.ctx.activeCapabilities.length > 0) {
|
|
14822
|
-
headers["X-Slock-Agent-Active-Capabilities"] = this.ctx.activeCapabilities.join(",");
|
|
14866
|
+
if (action.type === "channel:add_member") {
|
|
14867
|
+
const total = (action.humans?.length ?? 0) + (action.agents?.length ?? 0);
|
|
14868
|
+
if (total === 0) {
|
|
14869
|
+
return "channel:add_member must include at least one human or agent";
|
|
14823
14870
|
}
|
|
14824
|
-
const init = {
|
|
14825
|
-
method,
|
|
14826
|
-
headers,
|
|
14827
|
-
body: form
|
|
14828
|
-
};
|
|
14829
|
-
if (dispatcher) init.dispatcher = dispatcher;
|
|
14830
|
-
const res = await fetch(url2, init);
|
|
14831
|
-
return this.parseJsonResponse(res);
|
|
14832
14871
|
}
|
|
14833
|
-
|
|
14834
|
-
|
|
14835
|
-
|
|
14836
|
-
|
|
14837
|
-
|
|
14838
|
-
|
|
14839
|
-
|
|
14840
|
-
|
|
14841
|
-
|
|
14842
|
-
|
|
14843
|
-
|
|
14844
|
-
|
|
14845
|
-
|
|
14846
|
-
|
|
14847
|
-
|
|
14848
|
-
|
|
14849
|
-
|
|
14850
|
-
|
|
14851
|
-
|
|
14852
|
-
|
|
14853
|
-
|
|
14854
|
-
|
|
14855
|
-
|
|
14856
|
-
|
|
14857
|
-
|
|
14858
|
-
|
|
14859
|
-
|
|
14860
|
-
|
|
14861
|
-
|
|
14872
|
+
return null;
|
|
14873
|
+
}
|
|
14874
|
+
|
|
14875
|
+
// ../shared/src/translationLanguages.ts
|
|
14876
|
+
var SUPPORTED_TRANSLATION_LANGUAGE_CODES = [
|
|
14877
|
+
"en",
|
|
14878
|
+
"zh-cn",
|
|
14879
|
+
"zh-tw",
|
|
14880
|
+
"ja",
|
|
14881
|
+
"ko",
|
|
14882
|
+
"es",
|
|
14883
|
+
"fr",
|
|
14884
|
+
"de",
|
|
14885
|
+
"pt-br"
|
|
14886
|
+
];
|
|
14887
|
+
var SUPPORTED_TRANSLATION_LANGUAGE_SET = new Set(
|
|
14888
|
+
SUPPORTED_TRANSLATION_LANGUAGE_CODES
|
|
14889
|
+
);
|
|
14890
|
+
|
|
14891
|
+
// ../shared/src/testing/failpoints.ts
|
|
14892
|
+
var NoopFailpointRegistry = class {
|
|
14893
|
+
get enabled() {
|
|
14894
|
+
return false;
|
|
14895
|
+
}
|
|
14896
|
+
isEnabled() {
|
|
14897
|
+
return false;
|
|
14898
|
+
}
|
|
14899
|
+
configure() {
|
|
14900
|
+
}
|
|
14901
|
+
clear() {
|
|
14902
|
+
}
|
|
14903
|
+
getTrace() {
|
|
14904
|
+
return [];
|
|
14905
|
+
}
|
|
14906
|
+
hit(_key, _context, fallback) {
|
|
14907
|
+
return fallback ? fallback() : void 0;
|
|
14908
|
+
}
|
|
14909
|
+
};
|
|
14910
|
+
var noopFailpointRegistry = new NoopFailpointRegistry();
|
|
14911
|
+
|
|
14912
|
+
// ../shared/src/serverPermissions.ts
|
|
14913
|
+
var EMPTY_SERVER_CAPABILITIES = Object.freeze({
|
|
14914
|
+
manageServer: false,
|
|
14915
|
+
manageChannels: false,
|
|
14916
|
+
manageAgents: false,
|
|
14917
|
+
manageMachines: false,
|
|
14918
|
+
manageMembers: false,
|
|
14919
|
+
changeMemberRoles: false,
|
|
14920
|
+
manageBilling: false,
|
|
14921
|
+
joinPublicChannels: false
|
|
14922
|
+
});
|
|
14923
|
+
var SERVER_CAPABILITY_MATRIX = {
|
|
14924
|
+
owner: Object.freeze({
|
|
14925
|
+
manageServer: true,
|
|
14926
|
+
manageChannels: true,
|
|
14927
|
+
manageAgents: true,
|
|
14928
|
+
manageMachines: true,
|
|
14929
|
+
manageMembers: true,
|
|
14930
|
+
changeMemberRoles: true,
|
|
14931
|
+
manageBilling: true,
|
|
14932
|
+
joinPublicChannels: true
|
|
14933
|
+
}),
|
|
14934
|
+
admin: Object.freeze({
|
|
14935
|
+
manageServer: true,
|
|
14936
|
+
manageChannels: true,
|
|
14937
|
+
manageAgents: true,
|
|
14938
|
+
manageMachines: true,
|
|
14939
|
+
manageMembers: true,
|
|
14940
|
+
changeMemberRoles: true,
|
|
14941
|
+
manageBilling: false,
|
|
14942
|
+
joinPublicChannels: true
|
|
14943
|
+
}),
|
|
14944
|
+
member: Object.freeze({
|
|
14945
|
+
manageServer: false,
|
|
14946
|
+
manageChannels: false,
|
|
14947
|
+
manageAgents: false,
|
|
14948
|
+
manageMachines: false,
|
|
14949
|
+
manageMembers: false,
|
|
14950
|
+
changeMemberRoles: false,
|
|
14951
|
+
manageBilling: false,
|
|
14952
|
+
joinPublicChannels: true
|
|
14953
|
+
})
|
|
14954
|
+
};
|
|
14955
|
+
|
|
14956
|
+
// ../shared/src/index.ts
|
|
14957
|
+
var RUNTIMES = [
|
|
14958
|
+
{ id: "claude", displayName: "Claude Code", binary: "claude", supported: true },
|
|
14959
|
+
{ id: "codex", displayName: "Codex CLI", binary: "codex", supported: true },
|
|
14960
|
+
{ id: "antigravity", displayName: "Antigravity CLI", binary: "agy", supported: true },
|
|
14961
|
+
{ id: "kimi", displayName: "Kimi CLI", binary: "kimi", supported: true },
|
|
14962
|
+
{ id: "copilot", displayName: "Copilot CLI", binary: "copilot", supported: true },
|
|
14963
|
+
{ id: "cursor", displayName: "Cursor CLI", binary: "cursor-agent", supported: true },
|
|
14964
|
+
{ id: "gemini", displayName: "Gemini CLI", binary: "gemini", supported: true },
|
|
14965
|
+
{ id: "opencode", displayName: "OpenCode", binary: "opencode", supported: true }
|
|
14966
|
+
];
|
|
14967
|
+
function getRuntimeDisplayName(id) {
|
|
14968
|
+
return RUNTIMES.find((r) => r.id === id)?.displayName ?? id;
|
|
14969
|
+
}
|
|
14970
|
+
var PLAN_CONFIG = {
|
|
14971
|
+
free: {
|
|
14972
|
+
displayName: "Hobby",
|
|
14973
|
+
limits: { maxMachines: 2, maxAgents: 5, maxChannels: 5, messageHistoryDays: 30, includedAgents: 5 },
|
|
14974
|
+
comingSoon: false,
|
|
14975
|
+
price: 0,
|
|
14976
|
+
extraAgentPrice: 0
|
|
14977
|
+
},
|
|
14978
|
+
founder: {
|
|
14979
|
+
displayName: "Founder",
|
|
14980
|
+
limits: { maxMachines: -1, maxAgents: -1, maxChannels: -1, messageHistoryDays: -1, includedAgents: -1 },
|
|
14981
|
+
comingSoon: false,
|
|
14982
|
+
price: 0,
|
|
14983
|
+
extraAgentPrice: 0
|
|
14984
|
+
}
|
|
14985
|
+
};
|
|
14986
|
+
var DISPLAY_PLAN_CONFIG = {
|
|
14987
|
+
free: PLAN_CONFIG.free,
|
|
14988
|
+
pro: {
|
|
14989
|
+
displayName: "Team",
|
|
14990
|
+
limits: { maxMachines: 8, maxAgents: 40, maxChannels: 20, messageHistoryDays: -1, includedAgents: 40 },
|
|
14991
|
+
comingSoon: true,
|
|
14992
|
+
price: 20,
|
|
14993
|
+
extraAgentPrice: 0
|
|
14994
|
+
},
|
|
14995
|
+
max: {
|
|
14996
|
+
displayName: "Business",
|
|
14997
|
+
limits: { maxMachines: 40, maxAgents: 200, maxChannels: -1, messageHistoryDays: -1, includedAgents: 200 },
|
|
14998
|
+
comingSoon: true,
|
|
14999
|
+
price: 200,
|
|
15000
|
+
extraAgentPrice: 0
|
|
14862
15001
|
}
|
|
14863
15002
|
};
|
|
14864
15003
|
|
|
@@ -15053,29 +15192,39 @@ function formatChannelMembers(data) {
|
|
|
15053
15192
|
}
|
|
15054
15193
|
|
|
15055
15194
|
// src/commands/channel/members.ts
|
|
15056
|
-
|
|
15057
|
-
|
|
15058
|
-
|
|
15059
|
-
|
|
15060
|
-
|
|
15061
|
-
|
|
15062
|
-
|
|
15063
|
-
|
|
15064
|
-
|
|
15065
|
-
const client =
|
|
15195
|
+
var channelMembersCommand = defineCommand(
|
|
15196
|
+
{
|
|
15197
|
+
name: "members",
|
|
15198
|
+
description: "List agents and humans who are members of a channel, DM, or thread",
|
|
15199
|
+
rationale: "denied",
|
|
15200
|
+
arguments: ["<target>"]
|
|
15201
|
+
},
|
|
15202
|
+
async (ctx, target) => {
|
|
15203
|
+
const agentContext = ctx.loadAgentContext();
|
|
15204
|
+
const client = ctx.createApiClient(agentContext);
|
|
15066
15205
|
const channel = String(target || "").trim();
|
|
15067
|
-
if (!channel)
|
|
15206
|
+
if (!channel) {
|
|
15207
|
+
throw new CliError({
|
|
15208
|
+
code: "INVALID_ARG",
|
|
15209
|
+
message: "target is required"
|
|
15210
|
+
});
|
|
15211
|
+
}
|
|
15068
15212
|
const encoded = encodeURIComponent(channel);
|
|
15069
15213
|
const res = await client.request(
|
|
15070
15214
|
"GET",
|
|
15071
|
-
`/internal/agent/${encodeURIComponent(
|
|
15215
|
+
`/internal/agent/${encodeURIComponent(agentContext.agentId)}/channel-members?channel=${encoded}`
|
|
15072
15216
|
);
|
|
15073
15217
|
if (!res.ok) {
|
|
15074
|
-
|
|
15075
|
-
|
|
15218
|
+
throw new CliError({
|
|
15219
|
+
code: res.status >= 500 ? "SERVER_5XX" : "MEMBERS_FAILED",
|
|
15220
|
+
message: res.error ?? `HTTP ${res.status}`
|
|
15221
|
+
});
|
|
15076
15222
|
}
|
|
15077
|
-
|
|
15078
|
-
}
|
|
15223
|
+
writeText(ctx.io, formatChannelMembers(res.data));
|
|
15224
|
+
}
|
|
15225
|
+
);
|
|
15226
|
+
function registerChannelMembersCommand(parent, runtimeOptions) {
|
|
15227
|
+
registerCliCommand(parent, channelMembersCommand, runtimeOptions);
|
|
15079
15228
|
}
|
|
15080
15229
|
|
|
15081
15230
|
// src/commands/channel/leave.ts
|
|
@@ -15091,46 +15240,65 @@ function formatLeaveChannelResult(target) {
|
|
|
15091
15240
|
function formatAlreadyNotJoined(target) {
|
|
15092
15241
|
return `Already not joined in ${target}.`;
|
|
15093
15242
|
}
|
|
15094
|
-
|
|
15095
|
-
|
|
15096
|
-
|
|
15243
|
+
var channelLeaveCommand = defineCommand(
|
|
15244
|
+
{
|
|
15245
|
+
name: "leave",
|
|
15246
|
+
description: "Leave a regular channel you have joined",
|
|
15247
|
+
rationale: "required",
|
|
15248
|
+
options: [
|
|
15249
|
+
{
|
|
15250
|
+
flags: "--target <target>",
|
|
15251
|
+
description: "Regular channel to leave, e.g. '#engineering'"
|
|
15252
|
+
}
|
|
15253
|
+
]
|
|
15254
|
+
},
|
|
15255
|
+
async (ctx, opts) => {
|
|
15256
|
+
const target = opts.target ?? "";
|
|
15257
|
+
const channelName = parseRegularChannelTarget(target);
|
|
15097
15258
|
if (!channelName) {
|
|
15098
|
-
|
|
15099
|
-
|
|
15100
|
-
|
|
15101
|
-
|
|
15102
|
-
ctx = loadAgentContext();
|
|
15103
|
-
} catch (err) {
|
|
15104
|
-
if (err instanceof AgentBootstrapError) fail(err.code, err.message);
|
|
15105
|
-
throw err;
|
|
15259
|
+
throw new CliError({
|
|
15260
|
+
code: "INVALID_TARGET",
|
|
15261
|
+
message: "Target must be a regular channel in the form '#channel-name'. DMs and thread targets are not supported."
|
|
15262
|
+
});
|
|
15106
15263
|
}
|
|
15107
|
-
const
|
|
15264
|
+
const agentContext = ctx.loadAgentContext();
|
|
15265
|
+
const client = ctx.createApiClient(agentContext);
|
|
15108
15266
|
const infoRes = await client.request(
|
|
15109
15267
|
"GET",
|
|
15110
|
-
`/internal/agent/${encodeURIComponent(
|
|
15268
|
+
`/internal/agent/${encodeURIComponent(agentContext.agentId)}/server`
|
|
15111
15269
|
);
|
|
15112
15270
|
if (!infoRes.ok) {
|
|
15113
|
-
|
|
15114
|
-
|
|
15271
|
+
throw new CliError({
|
|
15272
|
+
code: infoRes.status >= 500 ? "SERVER_5XX" : "INFO_FAILED",
|
|
15273
|
+
message: infoRes.error ?? `HTTP ${infoRes.status}`
|
|
15274
|
+
});
|
|
15115
15275
|
}
|
|
15116
15276
|
const channel = (infoRes.data?.channels ?? []).find((candidate) => candidate.name === channelName);
|
|
15117
15277
|
if (!channel) {
|
|
15118
|
-
|
|
15278
|
+
throw new CliError({
|
|
15279
|
+
code: "NOT_FOUND",
|
|
15280
|
+
message: `Channel not found: ${target}`
|
|
15281
|
+
});
|
|
15119
15282
|
}
|
|
15120
15283
|
if (!channel.joined) {
|
|
15121
|
-
|
|
15284
|
+
writeText(ctx.io, formatAlreadyNotJoined(target) + "\n");
|
|
15122
15285
|
return;
|
|
15123
15286
|
}
|
|
15124
15287
|
const leaveRes = await client.request(
|
|
15125
15288
|
"POST",
|
|
15126
|
-
`/internal/agent/${encodeURIComponent(
|
|
15289
|
+
`/internal/agent/${encodeURIComponent(agentContext.agentId)}/channels/${encodeURIComponent(channel.id)}/leave`
|
|
15127
15290
|
);
|
|
15128
15291
|
if (!leaveRes.ok) {
|
|
15129
|
-
|
|
15130
|
-
|
|
15292
|
+
throw new CliError({
|
|
15293
|
+
code: leaveRes.status >= 500 ? "SERVER_5XX" : "LEAVE_FAILED",
|
|
15294
|
+
message: leaveRes.error ?? `HTTP ${leaveRes.status}`
|
|
15295
|
+
});
|
|
15131
15296
|
}
|
|
15132
|
-
|
|
15133
|
-
}
|
|
15297
|
+
writeText(ctx.io, formatLeaveChannelResult(target) + "\n");
|
|
15298
|
+
}
|
|
15299
|
+
);
|
|
15300
|
+
function registerChannelLeaveCommand(parent, runtimeOptions) {
|
|
15301
|
+
registerCliCommand(parent, channelLeaveCommand, runtimeOptions);
|
|
15134
15302
|
}
|
|
15135
15303
|
|
|
15136
15304
|
// src/commands/channel/join.ts
|
|
@@ -15140,76 +15308,179 @@ function formatJoinChannelResult(target) {
|
|
|
15140
15308
|
function formatAlreadyJoined(target) {
|
|
15141
15309
|
return `Already joined ${target}.`;
|
|
15142
15310
|
}
|
|
15143
|
-
|
|
15144
|
-
|
|
15145
|
-
|
|
15311
|
+
var channelJoinCommand = defineCommand(
|
|
15312
|
+
{
|
|
15313
|
+
name: "join",
|
|
15314
|
+
description: "Join a visible public channel",
|
|
15315
|
+
rationale: "required",
|
|
15316
|
+
options: [
|
|
15317
|
+
{
|
|
15318
|
+
flags: "--target <target>",
|
|
15319
|
+
description: "Regular channel to join, e.g. '#engineering'"
|
|
15320
|
+
}
|
|
15321
|
+
]
|
|
15322
|
+
},
|
|
15323
|
+
async (ctx, opts) => {
|
|
15324
|
+
const target = opts.target ?? "";
|
|
15325
|
+
const channelName = parseRegularChannelTarget(target);
|
|
15146
15326
|
if (!channelName) {
|
|
15147
|
-
|
|
15148
|
-
|
|
15149
|
-
|
|
15150
|
-
|
|
15151
|
-
ctx = loadAgentContext();
|
|
15152
|
-
} catch (err) {
|
|
15153
|
-
if (err instanceof AgentBootstrapError) fail(err.code, err.message);
|
|
15154
|
-
throw err;
|
|
15327
|
+
throw new CliError({
|
|
15328
|
+
code: "INVALID_TARGET",
|
|
15329
|
+
message: "Target must be a regular channel in the form '#channel-name'. DMs and thread targets are not supported."
|
|
15330
|
+
});
|
|
15155
15331
|
}
|
|
15156
|
-
const
|
|
15332
|
+
const agentContext = ctx.loadAgentContext();
|
|
15333
|
+
const client = ctx.createApiClient(agentContext);
|
|
15157
15334
|
const infoRes = await client.request(
|
|
15158
15335
|
"GET",
|
|
15159
|
-
`/internal/agent/${encodeURIComponent(
|
|
15336
|
+
`/internal/agent/${encodeURIComponent(agentContext.agentId)}/server`
|
|
15160
15337
|
);
|
|
15161
15338
|
if (!infoRes.ok) {
|
|
15162
|
-
|
|
15163
|
-
|
|
15339
|
+
throw new CliError({
|
|
15340
|
+
code: infoRes.status >= 500 ? "SERVER_5XX" : "INFO_FAILED",
|
|
15341
|
+
message: infoRes.error ?? `HTTP ${infoRes.status}`
|
|
15342
|
+
});
|
|
15164
15343
|
}
|
|
15165
15344
|
const channel = (infoRes.data?.channels ?? []).find((candidate) => candidate.name === channelName);
|
|
15166
15345
|
if (!channel) {
|
|
15167
|
-
|
|
15346
|
+
throw new CliError({
|
|
15347
|
+
code: "NOT_FOUND",
|
|
15348
|
+
message: `Channel not found: ${target}`
|
|
15349
|
+
});
|
|
15168
15350
|
}
|
|
15169
15351
|
if (channel.joined) {
|
|
15170
|
-
|
|
15352
|
+
writeText(ctx.io, formatAlreadyJoined(target) + "\n");
|
|
15171
15353
|
return;
|
|
15172
15354
|
}
|
|
15173
15355
|
const joinRes = await client.request(
|
|
15174
15356
|
"POST",
|
|
15175
|
-
`/internal/agent/${encodeURIComponent(
|
|
15357
|
+
`/internal/agent/${encodeURIComponent(agentContext.agentId)}/channels/${encodeURIComponent(channel.id)}/join`
|
|
15176
15358
|
);
|
|
15177
15359
|
if (!joinRes.ok) {
|
|
15178
|
-
|
|
15179
|
-
|
|
15180
|
-
|
|
15181
|
-
|
|
15182
|
-
});
|
|
15183
|
-
}
|
|
15184
|
-
|
|
15185
|
-
// src/commands/server/info.ts
|
|
15186
|
-
function registerServerInfoCommand(parent) {
|
|
15187
|
-
parent.command("info").description("List channels, agents, and humans on the current server").action(async () => {
|
|
15188
|
-
let ctx;
|
|
15189
|
-
try {
|
|
15190
|
-
ctx = loadAgentContext();
|
|
15191
|
-
} catch (err) {
|
|
15192
|
-
if (err instanceof AgentBootstrapError) fail(err.code, err.message);
|
|
15193
|
-
throw err;
|
|
15360
|
+
throw new CliError({
|
|
15361
|
+
code: joinRes.status >= 500 ? "SERVER_5XX" : "JOIN_FAILED",
|
|
15362
|
+
message: joinRes.error ?? `HTTP ${joinRes.status}`
|
|
15363
|
+
});
|
|
15194
15364
|
}
|
|
15195
|
-
|
|
15365
|
+
writeText(ctx.io, formatJoinChannelResult(target) + "\n");
|
|
15366
|
+
}
|
|
15367
|
+
);
|
|
15368
|
+
function registerChannelJoinCommand(parent, runtimeOptions) {
|
|
15369
|
+
registerCliCommand(parent, channelJoinCommand, runtimeOptions);
|
|
15370
|
+
}
|
|
15371
|
+
|
|
15372
|
+
// src/commands/server/info.ts
|
|
15373
|
+
var serverInfoCommand = defineCommand(
|
|
15374
|
+
{
|
|
15375
|
+
name: "info",
|
|
15376
|
+
description: "List channels, agents, and humans on the current server",
|
|
15377
|
+
rationale: "denied"
|
|
15378
|
+
},
|
|
15379
|
+
async (ctx) => {
|
|
15380
|
+
const agentContext = ctx.loadAgentContext();
|
|
15381
|
+
const client = ctx.createApiClient(agentContext);
|
|
15196
15382
|
const res = await client.request(
|
|
15197
15383
|
"GET",
|
|
15198
|
-
`/internal/agent/${encodeURIComponent(
|
|
15384
|
+
`/internal/agent/${encodeURIComponent(agentContext.agentId)}/server`
|
|
15199
15385
|
);
|
|
15200
15386
|
if (!res.ok) {
|
|
15201
15387
|
const code = res.status >= 500 ? "SERVER_5XX" : "INFO_FAILED";
|
|
15202
|
-
|
|
15388
|
+
throw new CliError({
|
|
15389
|
+
code,
|
|
15390
|
+
message: res.error ?? `HTTP ${res.status}`
|
|
15391
|
+
});
|
|
15203
15392
|
}
|
|
15204
15393
|
const data = res.data;
|
|
15205
15394
|
if (data?.runtimeContext) {
|
|
15206
15395
|
data.runtimeContext = {
|
|
15207
15396
|
...data.runtimeContext,
|
|
15208
|
-
workspacePath: data.runtimeContext.workspacePath ??
|
|
15397
|
+
workspacePath: data.runtimeContext.workspacePath ?? ctx.env.SLOCK_CURRENT_WORKSPACE_PATH ?? null
|
|
15209
15398
|
};
|
|
15210
15399
|
}
|
|
15211
|
-
|
|
15212
|
-
}
|
|
15400
|
+
writeText(ctx.io, formatServerInfo(data));
|
|
15401
|
+
}
|
|
15402
|
+
);
|
|
15403
|
+
function registerServerInfoCommand(parent, runtimeOptions) {
|
|
15404
|
+
registerCliCommand(parent, serverInfoCommand, runtimeOptions);
|
|
15405
|
+
}
|
|
15406
|
+
|
|
15407
|
+
// src/commands/knowledge/get.ts
|
|
15408
|
+
function buildKnowledgeGetPath(agentId, topic, opts) {
|
|
15409
|
+
const params = new URLSearchParams();
|
|
15410
|
+
params.set("topic", topic);
|
|
15411
|
+
if (opts.reason) params.set("reason", opts.reason);
|
|
15412
|
+
if (opts.turnId) params.set("turn_id", opts.turnId);
|
|
15413
|
+
if (opts.traceId) params.set("trace_id", opts.traceId);
|
|
15414
|
+
return `/internal/agent/${encodeURIComponent(agentId)}/knowledge?${params.toString()}`;
|
|
15415
|
+
}
|
|
15416
|
+
function formatKnowledgeStdout(content) {
|
|
15417
|
+
return content.endsWith("\n") ? content : `${content}
|
|
15418
|
+
`;
|
|
15419
|
+
}
|
|
15420
|
+
function toKnowledgeErrorCode(errorCode, status) {
|
|
15421
|
+
switch (errorCode) {
|
|
15422
|
+
case "INVALID_JSON_RESPONSE":
|
|
15423
|
+
case "SCOPE_DENIED":
|
|
15424
|
+
case "knowledge_agent_missing":
|
|
15425
|
+
case "knowledge_internal_error":
|
|
15426
|
+
case "knowledge_not_found":
|
|
15427
|
+
case "knowledge_reason_invalid":
|
|
15428
|
+
case "knowledge_source_invalid":
|
|
15429
|
+
case "knowledge_topic_invalid":
|
|
15430
|
+
case "knowledge_trace_id_invalid":
|
|
15431
|
+
case "knowledge_turn_id_invalid":
|
|
15432
|
+
case "unsupported_capability":
|
|
15433
|
+
return errorCode;
|
|
15434
|
+
default:
|
|
15435
|
+
return status >= 500 ? "SERVER_5XX" : "KNOWLEDGE_GET_FAILED";
|
|
15436
|
+
}
|
|
15437
|
+
}
|
|
15438
|
+
var knowledgeGetCommand = defineCommand(
|
|
15439
|
+
{
|
|
15440
|
+
name: "get",
|
|
15441
|
+
description: "Fetch an agent knowledge topic from the current server",
|
|
15442
|
+
rationale: "optional",
|
|
15443
|
+
arguments: ["<topic>"],
|
|
15444
|
+
options: [
|
|
15445
|
+
{
|
|
15446
|
+
flags: "--reason <text>",
|
|
15447
|
+
description: "Optional rationale for fetching this topic (>=12 chars when provided)"
|
|
15448
|
+
},
|
|
15449
|
+
{
|
|
15450
|
+
flags: "--turn-id <id>",
|
|
15451
|
+
description: "Optional turn id for correlation in the knowledge event"
|
|
15452
|
+
},
|
|
15453
|
+
{
|
|
15454
|
+
flags: "--trace-id <id>",
|
|
15455
|
+
description: "Optional trace id for correlation in the knowledge event"
|
|
15456
|
+
}
|
|
15457
|
+
]
|
|
15458
|
+
},
|
|
15459
|
+
async (ctx, topic, opts) => {
|
|
15460
|
+
const agentContext = ctx.loadAgentContext();
|
|
15461
|
+
const client = ctx.createApiClient(agentContext);
|
|
15462
|
+
const res = await client.request(
|
|
15463
|
+
"GET",
|
|
15464
|
+
buildKnowledgeGetPath(agentContext.agentId, topic, opts)
|
|
15465
|
+
);
|
|
15466
|
+
if (!res.ok) {
|
|
15467
|
+
throw new CliError({
|
|
15468
|
+
code: toKnowledgeErrorCode(res.errorCode, res.status),
|
|
15469
|
+
message: res.error ?? `HTTP ${res.status}`
|
|
15470
|
+
});
|
|
15471
|
+
}
|
|
15472
|
+
const data = res.data;
|
|
15473
|
+
if (!data || data.ok !== true) {
|
|
15474
|
+
throw new CliError({
|
|
15475
|
+
code: "KNOWLEDGE_GET_FAILED",
|
|
15476
|
+
message: "Server returned an unexpected response shape"
|
|
15477
|
+
});
|
|
15478
|
+
}
|
|
15479
|
+
writeText(ctx.io, formatKnowledgeStdout(data.content));
|
|
15480
|
+
}
|
|
15481
|
+
);
|
|
15482
|
+
function registerKnowledgeGetCommand(parent, runtimeOptions) {
|
|
15483
|
+
registerCliCommand(parent, knowledgeGetCommand, runtimeOptions);
|
|
15213
15484
|
}
|
|
15214
15485
|
|
|
15215
15486
|
// src/commands/thread/unfollow.ts
|
|
@@ -15237,31 +15508,44 @@ function parseThreadTarget(target) {
|
|
|
15237
15508
|
function formatUnfollowThreadResult(target) {
|
|
15238
15509
|
return `Unfollowed ${target}. You can still inspect the thread when its parent conversation is visible, but you will no longer receive ordinary thread delivery unless you follow it again or are mentioned.`;
|
|
15239
15510
|
}
|
|
15240
|
-
|
|
15241
|
-
|
|
15242
|
-
|
|
15511
|
+
var threadUnfollowCommand = defineCommand(
|
|
15512
|
+
{
|
|
15513
|
+
name: "unfollow",
|
|
15514
|
+
description: "Stop following a thread you no longer need ordinary delivery for",
|
|
15515
|
+
rationale: "required",
|
|
15516
|
+
options: [
|
|
15517
|
+
{
|
|
15518
|
+
flags: "--target <target>",
|
|
15519
|
+
description: "Thread target, e.g. '#engineering:abcd1234' or 'dm:@alice:abcd1234'"
|
|
15520
|
+
}
|
|
15521
|
+
]
|
|
15522
|
+
},
|
|
15523
|
+
async (ctx, opts) => {
|
|
15524
|
+
const thread = parseThreadTarget(opts.target ?? "");
|
|
15243
15525
|
if (!thread) {
|
|
15244
|
-
|
|
15245
|
-
|
|
15246
|
-
|
|
15247
|
-
|
|
15248
|
-
ctx = loadAgentContext();
|
|
15249
|
-
} catch (err) {
|
|
15250
|
-
if (err instanceof AgentBootstrapError) fail(err.code, err.message);
|
|
15251
|
-
throw err;
|
|
15526
|
+
throw new CliError({
|
|
15527
|
+
code: "INVALID_TARGET",
|
|
15528
|
+
message: "Thread must be a thread target like '#channel:abcd1234', 'dm:@peer:abcd1234', or a thread channel UUID."
|
|
15529
|
+
});
|
|
15252
15530
|
}
|
|
15253
|
-
const
|
|
15531
|
+
const agentContext = ctx.loadAgentContext();
|
|
15532
|
+
const client = ctx.createApiClient(agentContext);
|
|
15254
15533
|
const res = await client.request(
|
|
15255
15534
|
"POST",
|
|
15256
|
-
`/internal/agent/${encodeURIComponent(
|
|
15535
|
+
`/internal/agent/${encodeURIComponent(agentContext.agentId)}/threads/unfollow`,
|
|
15257
15536
|
{ thread }
|
|
15258
15537
|
);
|
|
15259
15538
|
if (!res.ok) {
|
|
15260
|
-
|
|
15261
|
-
|
|
15539
|
+
throw new CliError({
|
|
15540
|
+
code: res.status >= 500 ? "SERVER_5XX" : "UNFOLLOW_FAILED",
|
|
15541
|
+
message: res.error ?? `HTTP ${res.status}`
|
|
15542
|
+
});
|
|
15262
15543
|
}
|
|
15263
|
-
|
|
15264
|
-
}
|
|
15544
|
+
writeText(ctx.io, formatUnfollowThreadResult(thread) + "\n");
|
|
15545
|
+
}
|
|
15546
|
+
);
|
|
15547
|
+
function registerThreadUnfollowCommand(parent, runtimeOptions) {
|
|
15548
|
+
registerCliCommand(parent, threadUnfollowCommand, runtimeOptions);
|
|
15265
15549
|
}
|
|
15266
15550
|
|
|
15267
15551
|
// src/commands/message/_format.ts
|
|
@@ -15727,8 +16011,7 @@ ${formatMessages(data.recentUnread)}`;
|
|
|
15727
16011
|
}
|
|
15728
16012
|
|
|
15729
16013
|
// src/commands/message/_inbox.ts
|
|
15730
|
-
async function drainInbox(ctx, opts) {
|
|
15731
|
-
const client = new ApiClient(ctx);
|
|
16014
|
+
async function drainInbox(ctx, opts, client = new ApiClient(ctx)) {
|
|
15732
16015
|
const agentPath = `/internal/agent/${encodeURIComponent(ctx.agentId)}`;
|
|
15733
16016
|
const failCode = opts.block ? "WAIT_FAILED" : "CHECK_FAILED";
|
|
15734
16017
|
const query = [];
|
|
@@ -15737,8 +16020,10 @@ async function drainInbox(ctx, opts) {
|
|
|
15737
16020
|
const path4 = query.length > 0 ? `${agentPath}/receive?${query.join("&")}` : `${agentPath}/receive`;
|
|
15738
16021
|
const res = await client.request("GET", path4);
|
|
15739
16022
|
if (!res.ok) {
|
|
15740
|
-
|
|
15741
|
-
|
|
16023
|
+
throw new CliError({
|
|
16024
|
+
code: res.status >= 500 ? "SERVER_5XX" : failCode,
|
|
16025
|
+
message: res.error ?? `HTTP ${res.status}`
|
|
16026
|
+
});
|
|
15742
16027
|
}
|
|
15743
16028
|
const messages = res.data?.messages ?? [];
|
|
15744
16029
|
if (ctx.clientMode === "managed-runner" || ctx.clientMode === "self-hosted-runner") {
|
|
@@ -15754,18 +16039,25 @@ async function drainInbox(ctx, opts) {
|
|
|
15754
16039
|
}
|
|
15755
16040
|
|
|
15756
16041
|
// src/commands/message/check.ts
|
|
15757
|
-
|
|
15758
|
-
|
|
15759
|
-
|
|
15760
|
-
|
|
15761
|
-
|
|
15762
|
-
|
|
15763
|
-
|
|
15764
|
-
|
|
15765
|
-
|
|
15766
|
-
|
|
15767
|
-
|
|
15768
|
-
|
|
16042
|
+
var messageCheckCommand = defineCommand(
|
|
16043
|
+
{
|
|
16044
|
+
name: "check",
|
|
16045
|
+
description: "Drain the agent inbox (non-blocking). Acks delivered seqs before returning.",
|
|
16046
|
+
rationale: "denied"
|
|
16047
|
+
},
|
|
16048
|
+
async (ctx) => {
|
|
16049
|
+
const agentContext = ctx.loadAgentContext();
|
|
16050
|
+
const result = await drainInbox(
|
|
16051
|
+
agentContext,
|
|
16052
|
+
{ block: false },
|
|
16053
|
+
ctx.createApiClient(agentContext)
|
|
16054
|
+
);
|
|
16055
|
+
writeText(ctx.io, `${formatMessages(result.messages)}
|
|
16056
|
+
`);
|
|
16057
|
+
}
|
|
16058
|
+
);
|
|
16059
|
+
function registerCheckCommand(parent, runtimeOptions) {
|
|
16060
|
+
registerCliCommand(parent, messageCheckCommand, runtimeOptions);
|
|
15769
16061
|
}
|
|
15770
16062
|
|
|
15771
16063
|
// src/commands/message/read.ts
|
|
@@ -15773,39 +16065,81 @@ function parsePositiveInt(name, raw) {
|
|
|
15773
16065
|
if (raw === void 0) return void 0;
|
|
15774
16066
|
const n = Number(raw);
|
|
15775
16067
|
if (!Number.isFinite(n) || !Number.isInteger(n) || n <= 0) {
|
|
15776
|
-
|
|
16068
|
+
throw new CliError({
|
|
16069
|
+
code: "INVALID_ARG",
|
|
16070
|
+
message: `--${name} must be a positive integer; got ${raw}`
|
|
16071
|
+
});
|
|
15777
16072
|
}
|
|
15778
16073
|
return n;
|
|
15779
16074
|
}
|
|
15780
|
-
function
|
|
15781
|
-
|
|
15782
|
-
|
|
15783
|
-
|
|
15784
|
-
|
|
15785
|
-
|
|
15786
|
-
|
|
15787
|
-
|
|
15788
|
-
|
|
15789
|
-
|
|
15790
|
-
|
|
15791
|
-
|
|
15792
|
-
|
|
15793
|
-
|
|
15794
|
-
|
|
15795
|
-
|
|
15796
|
-
|
|
15797
|
-
|
|
15798
|
-
|
|
16075
|
+
function buildReadPath(agentId, opts) {
|
|
16076
|
+
const params = new URLSearchParams();
|
|
16077
|
+
params.set("channel", opts.channel);
|
|
16078
|
+
if (opts.before !== void 0) params.set("before", String(opts.before));
|
|
16079
|
+
if (opts.after !== void 0) params.set("after", String(opts.after));
|
|
16080
|
+
if (opts.around !== void 0) params.set("around", opts.around);
|
|
16081
|
+
if (opts.limit !== void 0) params.set("limit", String(opts.limit));
|
|
16082
|
+
return `/internal/agent/${encodeURIComponent(agentId)}/history?${params.toString()}`;
|
|
16083
|
+
}
|
|
16084
|
+
function validateReadOpts(opts) {
|
|
16085
|
+
const channel = opts.channel?.trim();
|
|
16086
|
+
if (!channel) {
|
|
16087
|
+
throw new CliError({
|
|
16088
|
+
code: "INVALID_ARG",
|
|
16089
|
+
message: "--channel is required"
|
|
16090
|
+
});
|
|
16091
|
+
}
|
|
16092
|
+
const before = parsePositiveInt("before", opts.before);
|
|
16093
|
+
const after = parsePositiveInt("after", opts.after);
|
|
16094
|
+
const limit = parsePositiveInt("limit", opts.limit);
|
|
16095
|
+
return {
|
|
16096
|
+
channel,
|
|
16097
|
+
...before !== void 0 ? { before } : {},
|
|
16098
|
+
...after !== void 0 ? { after } : {},
|
|
16099
|
+
...opts.around !== void 0 ? { around: opts.around } : {},
|
|
16100
|
+
...limit !== void 0 ? { limit } : {}
|
|
16101
|
+
};
|
|
16102
|
+
}
|
|
16103
|
+
var messageReadCommand = defineCommand(
|
|
16104
|
+
{
|
|
16105
|
+
name: "read",
|
|
16106
|
+
description: "Read message history for a channel, DM, or thread",
|
|
16107
|
+
rationale: "denied",
|
|
16108
|
+
options: [
|
|
16109
|
+
{ flags: "--channel <target>", description: "Target: '#channel', 'dm:@peer', '#channel:threadId', 'dm:@peer:threadId'" },
|
|
16110
|
+
{ flags: "--before <seq>", description: "Return messages strictly before this seq (paginate backwards)" },
|
|
16111
|
+
{ flags: "--after <seq>", description: "Return messages strictly after this seq (paginate forwards)" },
|
|
16112
|
+
{ flags: "--around <idOrSeq>", description: "Center the window on this messageId or seq" },
|
|
16113
|
+
{ flags: "--limit <n>", description: "Max messages to return (server default applies if omitted)" }
|
|
16114
|
+
]
|
|
16115
|
+
},
|
|
16116
|
+
async (ctx, opts) => {
|
|
16117
|
+
const readOpts = validateReadOpts(opts);
|
|
16118
|
+
const agentContext = ctx.loadAgentContext();
|
|
16119
|
+
const client = ctx.createApiClient(agentContext);
|
|
15799
16120
|
const res = await client.request(
|
|
15800
16121
|
"GET",
|
|
15801
|
-
|
|
16122
|
+
buildReadPath(agentContext.agentId, readOpts)
|
|
15802
16123
|
);
|
|
15803
16124
|
if (!res.ok) {
|
|
15804
|
-
|
|
15805
|
-
|
|
16125
|
+
throw new CliError({
|
|
16126
|
+
code: res.status >= 500 ? "SERVER_5XX" : "READ_FAILED",
|
|
16127
|
+
message: res.error ?? `HTTP ${res.status}`
|
|
16128
|
+
});
|
|
15806
16129
|
}
|
|
15807
|
-
|
|
15808
|
-
|
|
16130
|
+
writeText(
|
|
16131
|
+
ctx.io,
|
|
16132
|
+
`${formatHistory(readOpts.channel, res.data, {
|
|
16133
|
+
around: readOpts.around,
|
|
16134
|
+
after: readOpts.after,
|
|
16135
|
+
before: readOpts.before
|
|
16136
|
+
})}
|
|
16137
|
+
`
|
|
16138
|
+
);
|
|
16139
|
+
}
|
|
16140
|
+
);
|
|
16141
|
+
function registerReadCommand(parent, runtimeOptions) {
|
|
16142
|
+
registerCliCommand(parent, messageReadCommand, runtimeOptions);
|
|
15809
16143
|
}
|
|
15810
16144
|
|
|
15811
16145
|
// src/commands/message/search.ts
|
|
@@ -15813,56 +16147,117 @@ var UUID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i
|
|
|
15813
16147
|
function normalizeMemberHandleRef(raw) {
|
|
15814
16148
|
const trimmed = raw.trim();
|
|
15815
16149
|
if (!trimmed) {
|
|
15816
|
-
|
|
16150
|
+
throw new CliError({
|
|
16151
|
+
code: "INVALID_ARG",
|
|
16152
|
+
message: "--sender must not be empty"
|
|
16153
|
+
});
|
|
15817
16154
|
}
|
|
15818
16155
|
if (UUID_RE2.test(trimmed)) {
|
|
15819
|
-
|
|
16156
|
+
throw new CliError({
|
|
16157
|
+
code: "INVALID_ARG",
|
|
16158
|
+
message: "--sender expects a member handle like @alice, not a UUID"
|
|
16159
|
+
});
|
|
15820
16160
|
}
|
|
15821
16161
|
const handle = trimmed.replace(/^@/, "").trim();
|
|
15822
16162
|
if (!handle) {
|
|
15823
|
-
|
|
16163
|
+
throw new CliError({
|
|
16164
|
+
code: "INVALID_ARG",
|
|
16165
|
+
message: "--sender handle must not be empty"
|
|
16166
|
+
});
|
|
15824
16167
|
}
|
|
15825
16168
|
return handle;
|
|
15826
16169
|
}
|
|
15827
|
-
function
|
|
15828
|
-
|
|
15829
|
-
|
|
15830
|
-
|
|
15831
|
-
|
|
15832
|
-
|
|
15833
|
-
|
|
15834
|
-
|
|
15835
|
-
|
|
15836
|
-
|
|
15837
|
-
|
|
15838
|
-
|
|
15839
|
-
|
|
15840
|
-
|
|
15841
|
-
|
|
15842
|
-
|
|
15843
|
-
|
|
15844
|
-
|
|
15845
|
-
|
|
15846
|
-
|
|
15847
|
-
|
|
15848
|
-
|
|
15849
|
-
|
|
15850
|
-
|
|
15851
|
-
|
|
15852
|
-
|
|
15853
|
-
|
|
15854
|
-
|
|
15855
|
-
|
|
16170
|
+
function parsePositiveInt2(name, raw) {
|
|
16171
|
+
if (raw === void 0) return void 0;
|
|
16172
|
+
const n = Number(raw);
|
|
16173
|
+
if (!Number.isFinite(n) || !Number.isInteger(n) || n <= 0) {
|
|
16174
|
+
throw new CliError({
|
|
16175
|
+
code: "INVALID_ARG",
|
|
16176
|
+
message: `--${name} must be a positive integer; got ${raw}`
|
|
16177
|
+
});
|
|
16178
|
+
}
|
|
16179
|
+
return n;
|
|
16180
|
+
}
|
|
16181
|
+
function normalizeSearchOpts(opts) {
|
|
16182
|
+
const query = opts.query?.trim();
|
|
16183
|
+
if (!query) {
|
|
16184
|
+
throw new CliError({
|
|
16185
|
+
code: "INVALID_ARG",
|
|
16186
|
+
message: "--query is required"
|
|
16187
|
+
});
|
|
16188
|
+
}
|
|
16189
|
+
if (opts.sort !== void 0 && opts.sort !== "relevance" && opts.sort !== "recent") {
|
|
16190
|
+
throw new CliError({
|
|
16191
|
+
code: "INVALID_ARG",
|
|
16192
|
+
message: `--sort must be "relevance" or "recent"; got ${opts.sort}`
|
|
16193
|
+
});
|
|
16194
|
+
}
|
|
16195
|
+
const limit = parsePositiveInt2("limit", opts.limit);
|
|
16196
|
+
return {
|
|
16197
|
+
query,
|
|
16198
|
+
...opts.channel ? { channel: opts.channel } : {},
|
|
16199
|
+
...opts.sender ? { sender: normalizeMemberHandleRef(opts.sender) } : {},
|
|
16200
|
+
...opts.sort ? { sort: opts.sort } : {},
|
|
16201
|
+
...opts.before ? { before: opts.before } : {},
|
|
16202
|
+
...opts.after ? { after: opts.after } : {},
|
|
16203
|
+
...limit !== void 0 ? { limit } : {}
|
|
16204
|
+
};
|
|
16205
|
+
}
|
|
16206
|
+
function buildSearchPath(agentId, opts) {
|
|
16207
|
+
const params = new URLSearchParams();
|
|
16208
|
+
params.set("q", opts.query);
|
|
16209
|
+
if (opts.channel) params.set("channel", opts.channel);
|
|
16210
|
+
if (opts.sender) params.set("sender", opts.sender);
|
|
16211
|
+
if (opts.sort) params.set("sort", opts.sort);
|
|
16212
|
+
if (opts.before) params.set("before", opts.before);
|
|
16213
|
+
if (opts.after) params.set("after", opts.after);
|
|
16214
|
+
if (opts.limit !== void 0) params.set("limit", String(opts.limit));
|
|
16215
|
+
return `/internal/agent/${encodeURIComponent(agentId)}/search?${params.toString()}`;
|
|
16216
|
+
}
|
|
16217
|
+
function toSearchErrorCode(errorCode, status) {
|
|
16218
|
+
switch (errorCode) {
|
|
16219
|
+
case "SCOPE_DENIED":
|
|
16220
|
+
case "INVALID_JSON_RESPONSE":
|
|
16221
|
+
return errorCode;
|
|
16222
|
+
default:
|
|
16223
|
+
return status >= 500 ? "SERVER_5XX" : "SEARCH_FAILED";
|
|
16224
|
+
}
|
|
16225
|
+
}
|
|
16226
|
+
var messageSearchCommand = defineCommand(
|
|
16227
|
+
{
|
|
16228
|
+
name: "search",
|
|
16229
|
+
description: "Search messages across channels the agent can see",
|
|
16230
|
+
rationale: "denied",
|
|
16231
|
+
options: [
|
|
16232
|
+
{ flags: "--query <q>", description: "Search query string" },
|
|
16233
|
+
{ flags: "--channel <target>", description: "Restrict to a single channel/DM/thread" },
|
|
16234
|
+
{ flags: "--sender <handle>", description: "Restrict to messages by sender handle, e.g. @alice" },
|
|
16235
|
+
{ flags: "--sort <mode>", description: "Sort results by relevance or recent (default: relevance)" },
|
|
16236
|
+
{ flags: "--before <iso>", description: "Only messages before this ISO datetime" },
|
|
16237
|
+
{ flags: "--after <iso>", description: "Only messages after this ISO datetime" },
|
|
16238
|
+
{ flags: "--limit <n>", description: "Max results (server default applies if omitted)" }
|
|
16239
|
+
]
|
|
16240
|
+
},
|
|
16241
|
+
async (ctx, opts) => {
|
|
16242
|
+
const searchOpts = normalizeSearchOpts(opts);
|
|
16243
|
+
const agentContext = ctx.loadAgentContext();
|
|
16244
|
+
const client = ctx.createApiClient(agentContext);
|
|
15856
16245
|
const res = await client.request(
|
|
15857
16246
|
"GET",
|
|
15858
|
-
|
|
16247
|
+
buildSearchPath(agentContext.agentId, searchOpts)
|
|
15859
16248
|
);
|
|
15860
16249
|
if (!res.ok) {
|
|
15861
|
-
|
|
15862
|
-
|
|
16250
|
+
throw new CliError({
|
|
16251
|
+
code: toSearchErrorCode(res.errorCode, res.status),
|
|
16252
|
+
message: res.error ?? `HTTP ${res.status}`
|
|
16253
|
+
});
|
|
15863
16254
|
}
|
|
15864
|
-
|
|
15865
|
-
|
|
16255
|
+
writeText(ctx.io, `${formatSearchResults(searchOpts.query, res.data)}
|
|
16256
|
+
`);
|
|
16257
|
+
}
|
|
16258
|
+
);
|
|
16259
|
+
function registerSearchCommand(parent, runtimeOptions) {
|
|
16260
|
+
registerCliCommand(parent, messageSearchCommand, runtimeOptions);
|
|
15866
16261
|
}
|
|
15867
16262
|
|
|
15868
16263
|
// src/commands/message/react.ts
|
|
@@ -16075,29 +16470,55 @@ Use this ID with slock message send --attachment-id ${d.id} to include it in a m
|
|
|
16075
16470
|
|
|
16076
16471
|
// src/commands/attachment/view.ts
|
|
16077
16472
|
import { writeFileSync } from "fs";
|
|
16078
|
-
function
|
|
16079
|
-
|
|
16080
|
-
|
|
16081
|
-
|
|
16082
|
-
|
|
16083
|
-
|
|
16084
|
-
|
|
16085
|
-
|
|
16086
|
-
|
|
16087
|
-
|
|
16473
|
+
function validateViewOpts(opts) {
|
|
16474
|
+
const id = opts.id?.trim();
|
|
16475
|
+
const output = opts.output;
|
|
16476
|
+
if (!id) {
|
|
16477
|
+
throw new CliError({
|
|
16478
|
+
code: "INVALID_ARG",
|
|
16479
|
+
message: "--id is required"
|
|
16480
|
+
});
|
|
16481
|
+
}
|
|
16482
|
+
if (!output) {
|
|
16483
|
+
throw new CliError({
|
|
16484
|
+
code: "INVALID_ARG",
|
|
16485
|
+
message: "--output is required"
|
|
16486
|
+
});
|
|
16487
|
+
}
|
|
16488
|
+
return { id, output };
|
|
16489
|
+
}
|
|
16490
|
+
var attachmentViewCommand = defineCommand(
|
|
16491
|
+
{
|
|
16492
|
+
name: "view",
|
|
16493
|
+
description: "Download an attachment by id and save it to a local path",
|
|
16494
|
+
rationale: "denied",
|
|
16495
|
+
options: [
|
|
16496
|
+
{ flags: "--id <attachmentId>", description: "Attachment UUID" },
|
|
16497
|
+
{ flags: "--output <path>", description: "Local path to write the file to" }
|
|
16498
|
+
]
|
|
16499
|
+
},
|
|
16500
|
+
async (ctx, opts) => {
|
|
16501
|
+
const { id, output } = validateViewOpts(opts);
|
|
16502
|
+
const agentContext = ctx.loadAgentContext();
|
|
16503
|
+
const client = ctx.createApiClient(agentContext);
|
|
16088
16504
|
const res = await client.requestRaw(
|
|
16089
16505
|
"GET",
|
|
16090
|
-
`/api/attachments/${encodeURIComponent(
|
|
16506
|
+
`/api/attachments/${encodeURIComponent(id)}`
|
|
16091
16507
|
);
|
|
16092
16508
|
if (!res.ok) {
|
|
16093
|
-
|
|
16094
|
-
|
|
16509
|
+
throw new CliError({
|
|
16510
|
+
code: res.status >= 500 ? "SERVER_5XX" : "VIEW_FAILED",
|
|
16511
|
+
message: res.error ?? `HTTP ${res.status}`
|
|
16512
|
+
});
|
|
16095
16513
|
}
|
|
16096
16514
|
const buffer = Buffer.from(await res.response.arrayBuffer());
|
|
16097
|
-
writeFileSync(
|
|
16098
|
-
|
|
16515
|
+
writeFileSync(output, buffer);
|
|
16516
|
+
writeText(ctx.io, `Downloaded to: ${output}
|
|
16099
16517
|
`);
|
|
16100
|
-
}
|
|
16518
|
+
}
|
|
16519
|
+
);
|
|
16520
|
+
function registerAttachmentViewCommand(parent, runtimeOptions) {
|
|
16521
|
+
registerCliCommand(parent, attachmentViewCommand, runtimeOptions);
|
|
16101
16522
|
}
|
|
16102
16523
|
|
|
16103
16524
|
// src/commands/task/_format.ts
|
|
@@ -16155,32 +16576,61 @@ function formatTaskStatusUpdated(taskNumber, status) {
|
|
|
16155
16576
|
|
|
16156
16577
|
// src/commands/task/list.ts
|
|
16157
16578
|
var VALID_STATUSES = /* @__PURE__ */ new Set(["all", "todo", "in_progress", "in_review", "done", "closed"]);
|
|
16158
|
-
function
|
|
16159
|
-
|
|
16160
|
-
|
|
16161
|
-
|
|
16162
|
-
|
|
16163
|
-
|
|
16164
|
-
|
|
16165
|
-
|
|
16166
|
-
|
|
16167
|
-
|
|
16168
|
-
|
|
16169
|
-
|
|
16170
|
-
|
|
16171
|
-
|
|
16172
|
-
|
|
16173
|
-
|
|
16579
|
+
function buildTaskListPath(agentId, opts) {
|
|
16580
|
+
const params = new URLSearchParams();
|
|
16581
|
+
params.set("channel", opts.channel);
|
|
16582
|
+
if (opts.status) params.set("status", opts.status);
|
|
16583
|
+
return `/internal/agent/${encodeURIComponent(agentId)}/tasks?${params.toString()}`;
|
|
16584
|
+
}
|
|
16585
|
+
function validateListOpts(opts) {
|
|
16586
|
+
const channel = opts.channel?.trim();
|
|
16587
|
+
if (!channel) {
|
|
16588
|
+
throw new CliError({
|
|
16589
|
+
code: "INVALID_ARG",
|
|
16590
|
+
message: "--channel is required"
|
|
16591
|
+
});
|
|
16592
|
+
}
|
|
16593
|
+
if (opts.status && !VALID_STATUSES.has(opts.status)) {
|
|
16594
|
+
throw new CliError({
|
|
16595
|
+
code: "INVALID_ARG",
|
|
16596
|
+
message: `--status must be one of ${Array.from(VALID_STATUSES).join("|")}; got ${opts.status}`
|
|
16597
|
+
});
|
|
16598
|
+
}
|
|
16599
|
+
return {
|
|
16600
|
+
channel,
|
|
16601
|
+
...opts.status ? { status: opts.status } : {}
|
|
16602
|
+
};
|
|
16603
|
+
}
|
|
16604
|
+
var taskListCommand = defineCommand(
|
|
16605
|
+
{
|
|
16606
|
+
name: "list",
|
|
16607
|
+
description: "List tasks in a channel",
|
|
16608
|
+
rationale: "denied",
|
|
16609
|
+
options: [
|
|
16610
|
+
{ flags: "--channel <target>", description: "Channel target: '#channel'" },
|
|
16611
|
+
{ flags: "--status <s>", description: "Filter: all|todo|in_progress|in_review|done (default: server-side)" }
|
|
16612
|
+
]
|
|
16613
|
+
},
|
|
16614
|
+
async (ctx, opts) => {
|
|
16615
|
+
const listOpts = validateListOpts(opts);
|
|
16616
|
+
const agentContext = ctx.loadAgentContext();
|
|
16617
|
+
const client = ctx.createApiClient(agentContext);
|
|
16174
16618
|
const res = await client.request(
|
|
16175
16619
|
"GET",
|
|
16176
|
-
|
|
16620
|
+
buildTaskListPath(agentContext.agentId, listOpts)
|
|
16177
16621
|
);
|
|
16178
16622
|
if (!res.ok) {
|
|
16179
|
-
|
|
16180
|
-
|
|
16623
|
+
throw new CliError({
|
|
16624
|
+
code: res.status >= 500 ? "SERVER_5XX" : "LIST_FAILED",
|
|
16625
|
+
message: res.error ?? `HTTP ${res.status}`
|
|
16626
|
+
});
|
|
16181
16627
|
}
|
|
16182
|
-
|
|
16183
|
-
|
|
16628
|
+
writeText(ctx.io, `${formatTaskList(listOpts.channel, res.data, listOpts.status)}
|
|
16629
|
+
`);
|
|
16630
|
+
}
|
|
16631
|
+
);
|
|
16632
|
+
function registerTaskListCommand(parent, runtimeOptions) {
|
|
16633
|
+
registerCliCommand(parent, taskListCommand, runtimeOptions);
|
|
16184
16634
|
}
|
|
16185
16635
|
|
|
16186
16636
|
// src/commands/task/create.ts
|
|
@@ -16267,76 +16717,133 @@ function registerTaskClaimCommand(parent) {
|
|
|
16267
16717
|
}
|
|
16268
16718
|
|
|
16269
16719
|
// src/commands/task/unclaim.ts
|
|
16270
|
-
function
|
|
16271
|
-
|
|
16272
|
-
|
|
16273
|
-
|
|
16274
|
-
|
|
16275
|
-
|
|
16276
|
-
|
|
16277
|
-
|
|
16278
|
-
|
|
16279
|
-
|
|
16280
|
-
|
|
16281
|
-
|
|
16282
|
-
|
|
16283
|
-
|
|
16720
|
+
function parseTaskNumber(raw) {
|
|
16721
|
+
const n = Number(raw);
|
|
16722
|
+
if (!Number.isFinite(n) || !Number.isInteger(n) || n <= 0) {
|
|
16723
|
+
throw new CliError({
|
|
16724
|
+
code: "INVALID_ARG",
|
|
16725
|
+
message: `--number must be a positive integer; got ${raw}`
|
|
16726
|
+
});
|
|
16727
|
+
}
|
|
16728
|
+
return n;
|
|
16729
|
+
}
|
|
16730
|
+
function validateUnclaimOpts(opts) {
|
|
16731
|
+
const channel = opts.channel?.trim();
|
|
16732
|
+
if (!channel) {
|
|
16733
|
+
throw new CliError({
|
|
16734
|
+
code: "INVALID_ARG",
|
|
16735
|
+
message: "--channel is required"
|
|
16736
|
+
});
|
|
16737
|
+
}
|
|
16738
|
+
return { channel, taskNumber: parseTaskNumber(opts.number) };
|
|
16739
|
+
}
|
|
16740
|
+
var taskUnclaimCommand = defineCommand(
|
|
16741
|
+
{
|
|
16742
|
+
name: "unclaim",
|
|
16743
|
+
description: "Release a previously-claimed task",
|
|
16744
|
+
rationale: "required",
|
|
16745
|
+
options: [
|
|
16746
|
+
{ flags: "--channel <target>", description: "Channel target: '#channel'" },
|
|
16747
|
+
{ flags: "--number <n>", description: "Task number to unclaim" }
|
|
16748
|
+
]
|
|
16749
|
+
},
|
|
16750
|
+
async (ctx, opts) => {
|
|
16751
|
+
const { channel, taskNumber } = validateUnclaimOpts(opts);
|
|
16752
|
+
const agentContext = ctx.loadAgentContext();
|
|
16753
|
+
const client = ctx.createApiClient(agentContext);
|
|
16284
16754
|
const res = await client.request(
|
|
16285
16755
|
"POST",
|
|
16286
|
-
`/internal/agent/${encodeURIComponent(
|
|
16287
|
-
{ channel
|
|
16756
|
+
`/internal/agent/${encodeURIComponent(agentContext.agentId)}/tasks/unclaim`,
|
|
16757
|
+
{ channel, task_number: taskNumber }
|
|
16288
16758
|
);
|
|
16289
16759
|
if (!res.ok) {
|
|
16290
|
-
|
|
16291
|
-
|
|
16760
|
+
throw new CliError({
|
|
16761
|
+
code: res.status >= 500 ? "SERVER_5XX" : "UNCLAIM_FAILED",
|
|
16762
|
+
message: res.error ?? `HTTP ${res.status}`
|
|
16763
|
+
});
|
|
16292
16764
|
}
|
|
16293
|
-
|
|
16294
|
-
|
|
16765
|
+
writeText(ctx.io, `${formatTaskUnclaimed(taskNumber)}
|
|
16766
|
+
`);
|
|
16767
|
+
}
|
|
16768
|
+
);
|
|
16769
|
+
function registerTaskUnclaimCommand(parent, runtimeOptions) {
|
|
16770
|
+
registerCliCommand(parent, taskUnclaimCommand, runtimeOptions);
|
|
16295
16771
|
}
|
|
16296
16772
|
|
|
16297
16773
|
// src/commands/task/update.ts
|
|
16298
16774
|
var STATUSES = ["todo", "in_progress", "in_review", "done", "closed"];
|
|
16299
|
-
function
|
|
16300
|
-
|
|
16301
|
-
|
|
16302
|
-
|
|
16303
|
-
|
|
16304
|
-
|
|
16305
|
-
|
|
16306
|
-
|
|
16307
|
-
|
|
16308
|
-
|
|
16309
|
-
|
|
16310
|
-
|
|
16311
|
-
|
|
16312
|
-
|
|
16313
|
-
|
|
16314
|
-
}
|
|
16315
|
-
|
|
16316
|
-
|
|
16317
|
-
|
|
16318
|
-
|
|
16319
|
-
|
|
16320
|
-
|
|
16321
|
-
|
|
16775
|
+
function parseTaskNumber2(raw) {
|
|
16776
|
+
const n = Number(raw);
|
|
16777
|
+
if (!Number.isFinite(n) || !Number.isInteger(n) || n <= 0) {
|
|
16778
|
+
throw new CliError({
|
|
16779
|
+
code: "INVALID_ARG",
|
|
16780
|
+
message: `--number must be a positive integer; got ${raw}`
|
|
16781
|
+
});
|
|
16782
|
+
}
|
|
16783
|
+
return n;
|
|
16784
|
+
}
|
|
16785
|
+
function parseStatus(raw) {
|
|
16786
|
+
if (!raw || !STATUSES.includes(raw)) {
|
|
16787
|
+
throw new CliError({
|
|
16788
|
+
code: "INVALID_ARG",
|
|
16789
|
+
message: `--status must be one of: ${STATUSES.join(", ")}; got ${raw}`
|
|
16790
|
+
});
|
|
16791
|
+
}
|
|
16792
|
+
return raw;
|
|
16793
|
+
}
|
|
16794
|
+
function validateUpdateOpts(opts) {
|
|
16795
|
+
const channel = opts.channel?.trim();
|
|
16796
|
+
if (!channel) {
|
|
16797
|
+
throw new CliError({
|
|
16798
|
+
code: "INVALID_ARG",
|
|
16799
|
+
message: "--channel is required"
|
|
16800
|
+
});
|
|
16801
|
+
}
|
|
16802
|
+
return {
|
|
16803
|
+
channel,
|
|
16804
|
+
taskNumber: parseTaskNumber2(opts.number),
|
|
16805
|
+
status: parseStatus(opts.status)
|
|
16806
|
+
};
|
|
16807
|
+
}
|
|
16808
|
+
var taskUpdateCommand = defineCommand(
|
|
16809
|
+
{
|
|
16810
|
+
name: "update",
|
|
16811
|
+
description: "Update task status",
|
|
16812
|
+
rationale: "required",
|
|
16813
|
+
options: [
|
|
16814
|
+
{ flags: "--channel <target>", description: "Channel target: '#channel'" },
|
|
16815
|
+
{ flags: "--number <n>", description: "Task number to update" },
|
|
16816
|
+
{ flags: "--status <status>", description: `New status. One of: ${STATUSES.join(", ")}` }
|
|
16817
|
+
]
|
|
16818
|
+
},
|
|
16819
|
+
async (ctx, opts) => {
|
|
16820
|
+
const { channel, taskNumber, status } = validateUpdateOpts(opts);
|
|
16821
|
+
const agentContext = ctx.loadAgentContext();
|
|
16822
|
+
const client = ctx.createApiClient(agentContext);
|
|
16322
16823
|
const res = await client.request(
|
|
16323
16824
|
"POST",
|
|
16324
|
-
`/internal/agent/${encodeURIComponent(
|
|
16325
|
-
{ channel
|
|
16825
|
+
`/internal/agent/${encodeURIComponent(agentContext.agentId)}/tasks/update-status`,
|
|
16826
|
+
{ channel, task_number: taskNumber, status }
|
|
16326
16827
|
);
|
|
16327
16828
|
if (!res.ok) {
|
|
16328
|
-
|
|
16329
|
-
|
|
16829
|
+
throw new CliError({
|
|
16830
|
+
code: res.status >= 500 ? "SERVER_5XX" : "UPDATE_FAILED",
|
|
16831
|
+
message: res.error ?? `HTTP ${res.status}`
|
|
16832
|
+
});
|
|
16330
16833
|
}
|
|
16331
16834
|
if (isFreshnessHeldResponse(res.data)) {
|
|
16332
|
-
|
|
16835
|
+
writeText(ctx.io, formatFreshnessHoldOutput(channel, res.data, {
|
|
16333
16836
|
heldAction: "Your task status update was not applied.",
|
|
16334
16837
|
draftInstructions: "After reviewing the newer context, rerun the task update command if it is still correct.\n"
|
|
16335
16838
|
}));
|
|
16336
16839
|
return;
|
|
16337
16840
|
}
|
|
16338
|
-
|
|
16339
|
-
|
|
16841
|
+
writeText(ctx.io, `${formatTaskStatusUpdated(taskNumber, status)}
|
|
16842
|
+
`);
|
|
16843
|
+
}
|
|
16844
|
+
);
|
|
16845
|
+
function registerTaskUpdateCommand(parent, runtimeOptions) {
|
|
16846
|
+
registerCliCommand(parent, taskUpdateCommand, runtimeOptions);
|
|
16340
16847
|
}
|
|
16341
16848
|
|
|
16342
16849
|
// src/commands/profile/_format.ts
|
|
@@ -16403,39 +16910,58 @@ function normalizeTarget(target) {
|
|
|
16403
16910
|
if (target === void 0) return null;
|
|
16404
16911
|
const trimmed = target.trim();
|
|
16405
16912
|
if (!trimmed) {
|
|
16406
|
-
|
|
16913
|
+
throw new CliError({
|
|
16914
|
+
code: "INVALID_ARG",
|
|
16915
|
+
message: "profile target must not be empty"
|
|
16916
|
+
});
|
|
16407
16917
|
}
|
|
16408
16918
|
if (!trimmed.startsWith("@")) {
|
|
16409
|
-
|
|
16919
|
+
throw new CliError({
|
|
16920
|
+
code: "INVALID_ARG",
|
|
16921
|
+
message: "profile target must start with @"
|
|
16922
|
+
});
|
|
16410
16923
|
}
|
|
16411
16924
|
return trimmed;
|
|
16412
16925
|
}
|
|
16413
|
-
function
|
|
16414
|
-
|
|
16415
|
-
|
|
16416
|
-
|
|
16417
|
-
|
|
16418
|
-
|
|
16419
|
-
|
|
16420
|
-
|
|
16421
|
-
|
|
16926
|
+
function buildProfileShowPath(agentId, target) {
|
|
16927
|
+
const base = `/internal/agent/${encodeURIComponent(agentId)}/profile`;
|
|
16928
|
+
if (!target) return base;
|
|
16929
|
+
const params = new URLSearchParams();
|
|
16930
|
+
params.set("target", target);
|
|
16931
|
+
return `${base}?${params.toString()}`;
|
|
16932
|
+
}
|
|
16933
|
+
var profileShowCommand = defineCommand(
|
|
16934
|
+
{
|
|
16935
|
+
name: "show",
|
|
16936
|
+
description: "Show a profile. Omit the target to show your own profile.",
|
|
16937
|
+
rationale: "denied",
|
|
16938
|
+
arguments: ["[target]"],
|
|
16939
|
+
options: [{ flags: "--json", description: "Emit machine-readable JSON" }]
|
|
16940
|
+
},
|
|
16941
|
+
async (ctx, target, opts = {}) => {
|
|
16942
|
+
const agentContext = ctx.loadAgentContext();
|
|
16943
|
+
const client = ctx.createApiClient(agentContext);
|
|
16422
16944
|
const normalizedTarget = normalizeTarget(target);
|
|
16423
|
-
const
|
|
16424
|
-
|
|
16425
|
-
|
|
16426
|
-
|
|
16427
|
-
const res = await client.request("GET", pathname);
|
|
16945
|
+
const res = await client.request(
|
|
16946
|
+
"GET",
|
|
16947
|
+
buildProfileShowPath(agentContext.agentId, normalizedTarget)
|
|
16948
|
+
);
|
|
16428
16949
|
if (!res.ok || !res.data) {
|
|
16429
|
-
|
|
16430
|
-
|
|
16950
|
+
throw new CliError({
|
|
16951
|
+
code: res.status >= 500 ? "SERVER_5XX" : "PROFILE_SHOW_FAILED",
|
|
16952
|
+
message: res.error ?? `HTTP ${res.status}`
|
|
16953
|
+
});
|
|
16431
16954
|
}
|
|
16432
16955
|
if (opts.json) {
|
|
16433
|
-
|
|
16956
|
+
writeJson(ctx.io, { ok: true, data: res.data });
|
|
16434
16957
|
return;
|
|
16435
16958
|
}
|
|
16436
|
-
|
|
16959
|
+
writeText(ctx.io, `${formatProfile(res.data)}
|
|
16437
16960
|
`);
|
|
16438
|
-
}
|
|
16961
|
+
}
|
|
16962
|
+
);
|
|
16963
|
+
function registerProfileShowCommand(parent, runtimeOptions) {
|
|
16964
|
+
registerCliCommand(parent, profileShowCommand, runtimeOptions);
|
|
16439
16965
|
}
|
|
16440
16966
|
|
|
16441
16967
|
// src/commands/profile/update.ts
|
|
@@ -17136,6 +17662,8 @@ var threadCmd = program.command("thread").description("Thread attention operatio
|
|
|
17136
17662
|
registerThreadUnfollowCommand(threadCmd);
|
|
17137
17663
|
var serverCmd = program.command("server").description("Server / workspace introspection");
|
|
17138
17664
|
registerServerInfoCommand(serverCmd);
|
|
17665
|
+
var knowledgeCmd = program.command("knowledge").description("Agent knowledge retrieval (canonical Slock product knowledge topics)");
|
|
17666
|
+
registerKnowledgeGetCommand(knowledgeCmd);
|
|
17139
17667
|
var messageCmd = program.command("message").description("Message operations");
|
|
17140
17668
|
registerSendCommand(messageCmd);
|
|
17141
17669
|
registerCheckCommand(messageCmd);
|