@slock-ai/daemon 0.44.2 → 0.46.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/chat-bridge.js +21 -104
- package/dist/{chunk-NM2MFLQ7.js → chunk-Q4XUZB34.js} +1707 -267
- package/dist/{chunk-JG7ONJZ6.js → chunk-Z3PCMYZO.js} +101 -1
- package/dist/cli/index.js +65 -14
- package/dist/core.js +2 -2
- package/dist/index.js +3 -3
- package/package.json +1 -1
|
@@ -110,9 +110,109 @@ function buildFetchDispatcher(targetUrl, env) {
|
|
|
110
110
|
return dispatcher;
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
+
// src/chatBridgeRequest.ts
|
|
114
|
+
var DEFAULT_CHAT_BRIDGE_TOOL_TIMEOUT_MS = Number.parseInt(
|
|
115
|
+
process.env.SLOCK_CHAT_BRIDGE_TOOL_TIMEOUT_MS || "",
|
|
116
|
+
10
|
|
117
|
+
) || 6e4;
|
|
118
|
+
var ChatBridgeToolTimeoutError = class extends Error {
|
|
119
|
+
toolName;
|
|
120
|
+
target;
|
|
121
|
+
timeoutMs;
|
|
122
|
+
durationMs;
|
|
123
|
+
constructor(toolName, target, timeoutMs, durationMs) {
|
|
124
|
+
super(`${toolName} timed out after ${timeoutMs}ms${target ? ` (target: ${target})` : ""}`);
|
|
125
|
+
this.name = "ChatBridgeToolTimeoutError";
|
|
126
|
+
this.toolName = toolName;
|
|
127
|
+
this.target = target;
|
|
128
|
+
this.timeoutMs = timeoutMs;
|
|
129
|
+
this.durationMs = durationMs;
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
function describeError(err) {
|
|
133
|
+
if (err instanceof Error) return `${err.name}: ${err.message}`;
|
|
134
|
+
return String(err);
|
|
135
|
+
}
|
|
136
|
+
async function executeJsonRequest(url, init, {
|
|
137
|
+
toolName,
|
|
138
|
+
target = null,
|
|
139
|
+
timeoutMs = DEFAULT_CHAT_BRIDGE_TOOL_TIMEOUT_MS,
|
|
140
|
+
fetchImpl,
|
|
141
|
+
now = () => Date.now(),
|
|
142
|
+
warn = (message) => logger.warn(message)
|
|
143
|
+
}) {
|
|
144
|
+
const startedAt = now();
|
|
145
|
+
const timeoutController = new AbortController();
|
|
146
|
+
const signals = [timeoutController.signal];
|
|
147
|
+
if (init.signal) signals.push(init.signal);
|
|
148
|
+
const signal = signals.length === 1 ? signals[0] : AbortSignal.any(signals);
|
|
149
|
+
const timeout = setTimeout(() => {
|
|
150
|
+
timeoutController.abort();
|
|
151
|
+
}, timeoutMs);
|
|
152
|
+
timeout.unref?.();
|
|
153
|
+
try {
|
|
154
|
+
const response = await fetchImpl(url, { ...init, signal });
|
|
155
|
+
const data = await response.json();
|
|
156
|
+
return { response, data, durationMs: now() - startedAt };
|
|
157
|
+
} catch (err) {
|
|
158
|
+
const durationMs = now() - startedAt;
|
|
159
|
+
if (timeoutController.signal.aborted && !init.signal?.aborted) {
|
|
160
|
+
warn(
|
|
161
|
+
`[ChatBridgeTimeout] tool=${toolName} target=${target ?? "-"} duration_ms=${durationMs} timeout_ms=${timeoutMs} outcome=timeout`
|
|
162
|
+
);
|
|
163
|
+
throw new ChatBridgeToolTimeoutError(toolName, target, timeoutMs, durationMs);
|
|
164
|
+
}
|
|
165
|
+
warn(
|
|
166
|
+
`[ChatBridgeError] tool=${toolName} target=${target ?? "-"} duration_ms=${durationMs} outcome=error error=${describeError(err)}`
|
|
167
|
+
);
|
|
168
|
+
throw err;
|
|
169
|
+
} finally {
|
|
170
|
+
clearTimeout(timeout);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
async function executeResponseRequest(url, init, {
|
|
174
|
+
toolName,
|
|
175
|
+
target = null,
|
|
176
|
+
timeoutMs = DEFAULT_CHAT_BRIDGE_TOOL_TIMEOUT_MS,
|
|
177
|
+
fetchImpl,
|
|
178
|
+
now = () => Date.now(),
|
|
179
|
+
warn = (message) => logger.warn(message)
|
|
180
|
+
}) {
|
|
181
|
+
const startedAt = now();
|
|
182
|
+
const timeoutController = new AbortController();
|
|
183
|
+
const signals = [timeoutController.signal];
|
|
184
|
+
if (init.signal) signals.push(init.signal);
|
|
185
|
+
const signal = signals.length === 1 ? signals[0] : AbortSignal.any(signals);
|
|
186
|
+
const timeout = setTimeout(() => {
|
|
187
|
+
timeoutController.abort();
|
|
188
|
+
}, timeoutMs);
|
|
189
|
+
timeout.unref?.();
|
|
190
|
+
try {
|
|
191
|
+
const response = await fetchImpl(url, { ...init, signal });
|
|
192
|
+
return { response, durationMs: now() - startedAt };
|
|
193
|
+
} catch (err) {
|
|
194
|
+
const durationMs = now() - startedAt;
|
|
195
|
+
if (timeoutController.signal.aborted && !init.signal?.aborted) {
|
|
196
|
+
warn(
|
|
197
|
+
`[ChatBridgeTimeout] tool=${toolName} target=${target ?? "-"} duration_ms=${durationMs} timeout_ms=${timeoutMs} outcome=timeout`
|
|
198
|
+
);
|
|
199
|
+
throw new ChatBridgeToolTimeoutError(toolName, target, timeoutMs, durationMs);
|
|
200
|
+
}
|
|
201
|
+
warn(
|
|
202
|
+
`[ChatBridgeError] tool=${toolName} target=${target ?? "-"} duration_ms=${durationMs} outcome=error error=${describeError(err)}`
|
|
203
|
+
);
|
|
204
|
+
throw err;
|
|
205
|
+
} finally {
|
|
206
|
+
clearTimeout(timeout);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
113
210
|
export {
|
|
114
211
|
subscribeDaemonLogs,
|
|
115
212
|
logger,
|
|
116
213
|
buildWebSocketOptions,
|
|
117
|
-
buildFetchDispatcher
|
|
214
|
+
buildFetchDispatcher,
|
|
215
|
+
DEFAULT_CHAT_BRIDGE_TOOL_TIMEOUT_MS,
|
|
216
|
+
executeJsonRequest,
|
|
217
|
+
executeResponseRequest
|
|
118
218
|
};
|
package/dist/cli/index.js
CHANGED
|
@@ -258,10 +258,11 @@ function formatServerInfo(data) {
|
|
|
258
258
|
const humans = data.humans ?? [];
|
|
259
259
|
text += formatRuntimeContext(data.runtimeContext);
|
|
260
260
|
text += "### Channels\n";
|
|
261
|
-
text += 'Visible public channels may appear even when `joined=false`. Use `slock message read --channel "#name"` to inspect
|
|
261
|
+
text += 'Visible public channels may appear even when `joined=false`. Private channels are shown only when you are a member; do not disclose private-channel names, membership, or content outside that channel. Use `slock message read --channel "#name"` to inspect visible channels. When a channel is not joined, you cannot send messages there or receive ordinary channel delivery until a human adds you to the channel. To leave a channel you have joined, use `slock channel leave --target "#name"`. To stop following a thread, use `slock thread unfollow --target "#name:shortid"`.\n';
|
|
262
262
|
if (channels.length > 0) {
|
|
263
263
|
for (const t of channels) {
|
|
264
|
-
const
|
|
264
|
+
const visibility = t.type === "private" ? "private" : "public";
|
|
265
|
+
const status = `${visibility}, ${t.joined ? "joined" : "not joined"}`;
|
|
265
266
|
text += t.description ? ` - #${t.name} [${status}] \u2014 ${t.description}
|
|
266
267
|
` : ` - #${t.name} [${status}]
|
|
267
268
|
`;
|
|
@@ -314,10 +315,12 @@ function formatChannelMembers(data) {
|
|
|
314
315
|
text += " (none)\n";
|
|
315
316
|
}
|
|
316
317
|
text += "\n### Humans\n";
|
|
318
|
+
text += "Role labels show server-level owner/admin authority; no role label means ordinary member.\n";
|
|
317
319
|
if (humans.length > 0) {
|
|
318
320
|
for (const u of humans) {
|
|
319
|
-
|
|
320
|
-
|
|
321
|
+
const role = u.role && u.role !== "member" ? ` (${u.role})` : "";
|
|
322
|
+
text += u.description ? ` - @${u.name}${role} \u2014 ${u.description}
|
|
323
|
+
` : ` - @${u.name}${role}
|
|
321
324
|
`;
|
|
322
325
|
}
|
|
323
326
|
} else {
|
|
@@ -815,8 +818,23 @@ function registerReadCommand(parent) {
|
|
|
815
818
|
}
|
|
816
819
|
|
|
817
820
|
// src/commands/message/search.ts
|
|
821
|
+
var UUID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
822
|
+
function normalizeMemberHandleRef(raw) {
|
|
823
|
+
const trimmed = raw.trim();
|
|
824
|
+
if (!trimmed) {
|
|
825
|
+
fail("INVALID_ARG", "--sender must not be empty");
|
|
826
|
+
}
|
|
827
|
+
if (UUID_RE2.test(trimmed)) {
|
|
828
|
+
fail("INVALID_ARG", "--sender expects a member handle like @alice, not a UUID");
|
|
829
|
+
}
|
|
830
|
+
const handle = trimmed.replace(/^@/, "").trim();
|
|
831
|
+
if (!handle) {
|
|
832
|
+
fail("INVALID_ARG", "--sender handle must not be empty");
|
|
833
|
+
}
|
|
834
|
+
return handle;
|
|
835
|
+
}
|
|
818
836
|
function registerSearchCommand(parent) {
|
|
819
|
-
parent.command("search").description("Search messages across channels the agent can see").requiredOption("--query <q>", "Search query string").option("--channel <target>", "Restrict to a single channel/DM/thread").option("--sender <
|
|
837
|
+
parent.command("search").description("Search messages across channels the agent can see").requiredOption("--query <q>", "Search query string").option("--channel <target>", "Restrict to a single channel/DM/thread").option("--sender <handle>", "Restrict to messages by sender handle, e.g. @alice").option("--sort <mode>", "Sort results by relevance or recent (default: relevance)").option("--before <iso>", "Only messages before this ISO datetime").option("--after <iso>", "Only messages after this ISO datetime").option("--limit <n>", "Max results (server default applies if omitted)").action(async (opts) => {
|
|
820
838
|
let ctx;
|
|
821
839
|
try {
|
|
822
840
|
ctx = loadAgentContext();
|
|
@@ -832,10 +850,14 @@ function registerSearchCommand(parent) {
|
|
|
832
850
|
}
|
|
833
851
|
limit = n;
|
|
834
852
|
}
|
|
853
|
+
if (opts.sort !== void 0 && opts.sort !== "relevance" && opts.sort !== "recent") {
|
|
854
|
+
fail("INVALID_ARG", `--sort must be "relevance" or "recent"; got ${opts.sort}`);
|
|
855
|
+
}
|
|
835
856
|
const params = new URLSearchParams();
|
|
836
857
|
params.set("q", opts.query);
|
|
837
858
|
if (opts.channel) params.set("channel", opts.channel);
|
|
838
|
-
if (opts.sender) params.set("
|
|
859
|
+
if (opts.sender) params.set("sender", normalizeMemberHandleRef(opts.sender));
|
|
860
|
+
if (opts.sort) params.set("sort", opts.sort);
|
|
839
861
|
if (opts.before) params.set("before", opts.before);
|
|
840
862
|
if (opts.after) params.set("after", opts.after);
|
|
841
863
|
if (limit !== void 0) params.set("limit", String(limit));
|
|
@@ -845,7 +867,7 @@ function registerSearchCommand(parent) {
|
|
|
845
867
|
`/internal/agent/${encodeURIComponent(ctx.agentId)}/search?${params.toString()}`
|
|
846
868
|
);
|
|
847
869
|
if (!res.ok) {
|
|
848
|
-
const code = res.status >= 500 ? "SERVER_5XX" : "SEARCH_FAILED";
|
|
870
|
+
const code = res.errorCode ?? (res.status >= 500 ? "SERVER_5XX" : "SEARCH_FAILED");
|
|
849
871
|
fail(code, res.error ?? `HTTP ${res.status}`);
|
|
850
872
|
}
|
|
851
873
|
process.stdout.write(formatSearchResults(opts.query, res.data) + "\n");
|
|
@@ -855,7 +877,8 @@ function registerSearchCommand(parent) {
|
|
|
855
877
|
// src/commands/attachment/upload.ts
|
|
856
878
|
import { existsSync, statSync, readFileSync } from "fs";
|
|
857
879
|
import { basename } from "path";
|
|
858
|
-
var
|
|
880
|
+
var MAX_ATTACHMENT_UPLOAD_BYTES = 50 * 1024 * 1024;
|
|
881
|
+
var MAX_ATTACHMENT_UPLOAD_LABEL = "50MB";
|
|
859
882
|
var FILENAME_MIME_MAP = {
|
|
860
883
|
".jpg": "image/jpeg",
|
|
861
884
|
".jpeg": "image/jpeg",
|
|
@@ -912,8 +935,33 @@ function inferUploadMimeType(filename, buffer, explicitMimeType) {
|
|
|
912
935
|
const explicit = normalizeExplicitMimeType(explicitMimeType);
|
|
913
936
|
return explicit || inferMimeTypeFromBuffer(buffer) || inferMimeTypeFromFilename(filename) || "application/octet-stream";
|
|
914
937
|
}
|
|
938
|
+
function validateUploadFileSize(size) {
|
|
939
|
+
if (size > MAX_ATTACHMENT_UPLOAD_BYTES) {
|
|
940
|
+
throw new AttachmentUploadArgError(
|
|
941
|
+
"INVALID_ARG",
|
|
942
|
+
`--path is ${formatBytes(size)}; max upload size is ${MAX_ATTACHMENT_UPLOAD_LABEL}`
|
|
943
|
+
);
|
|
944
|
+
}
|
|
945
|
+
if (size === 0) {
|
|
946
|
+
throw new AttachmentUploadArgError(
|
|
947
|
+
"INVALID_ARG",
|
|
948
|
+
"--path is empty; refusing to upload a 0-byte attachment"
|
|
949
|
+
);
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
function formatBytes(bytes) {
|
|
953
|
+
if (!Number.isFinite(bytes) || bytes <= 0) return "0B";
|
|
954
|
+
const units = ["B", "KB", "MB", "GB"];
|
|
955
|
+
let value = bytes;
|
|
956
|
+
let unitIndex = 0;
|
|
957
|
+
while (value >= 1024 && unitIndex < units.length - 1) {
|
|
958
|
+
value /= 1024;
|
|
959
|
+
unitIndex += 1;
|
|
960
|
+
}
|
|
961
|
+
return `${unitIndex === 0 ? value.toFixed(0) : value.toFixed(1)}${units[unitIndex]}`;
|
|
962
|
+
}
|
|
915
963
|
function registerAttachmentUploadCommand(parent) {
|
|
916
|
-
parent.command("upload").description(
|
|
964
|
+
parent.command("upload").description(`Upload a local file as an attachment (max ${MAX_ATTACHMENT_UPLOAD_LABEL})`).requiredOption("--path <filepath>", "Absolute path to the local file to upload").option(
|
|
917
965
|
"--channel <target>",
|
|
918
966
|
"Target where the attachment will be used: '#channel', 'dm:@peer', or thread variants. Required by the v0 server until channel-less uploads land."
|
|
919
967
|
).option("--mime-type <type>", "Explicit MIME type override, e.g. image/png").action(async (opts) => {
|
|
@@ -931,11 +979,11 @@ function registerAttachmentUploadCommand(parent) {
|
|
|
931
979
|
if (!stat.isFile()) {
|
|
932
980
|
fail("INVALID_ARG", `--path is not a regular file: ${opts.path}`);
|
|
933
981
|
}
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
982
|
+
try {
|
|
983
|
+
validateUploadFileSize(stat.size);
|
|
984
|
+
} catch (err) {
|
|
985
|
+
if (err instanceof AttachmentUploadArgError) fail(err.code, err.message);
|
|
986
|
+
throw err;
|
|
939
987
|
}
|
|
940
988
|
if (!opts.channel) {
|
|
941
989
|
fail(
|
|
@@ -1325,6 +1373,9 @@ function randomHex(length) {
|
|
|
1325
1373
|
return [...bytes].map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
1326
1374
|
}
|
|
1327
1375
|
|
|
1376
|
+
// ../shared/src/attachmentPreview.ts
|
|
1377
|
+
var CSV_PREVIEW_MAX_FILE_SIZE_BYTES = 5 * 1024 * 1024;
|
|
1378
|
+
|
|
1328
1379
|
// ../shared/src/testing/failpoints.ts
|
|
1329
1380
|
var NoopFailpointRegistry = class {
|
|
1330
1381
|
get enabled() {
|
package/dist/core.js
CHANGED
|
@@ -9,10 +9,10 @@ import {
|
|
|
9
9
|
resolveSlockCliPath,
|
|
10
10
|
resolveWorkspaceDirectoryPath,
|
|
11
11
|
scanWorkspaceDirectories
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-Q4XUZB34.js";
|
|
13
13
|
import {
|
|
14
14
|
subscribeDaemonLogs
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-Z3PCMYZO.js";
|
|
16
16
|
export {
|
|
17
17
|
DAEMON_CLI_USAGE,
|
|
18
18
|
DaemonCore,
|
package/dist/index.js
CHANGED
|
@@ -3,8 +3,8 @@ import {
|
|
|
3
3
|
DAEMON_CLI_USAGE,
|
|
4
4
|
DaemonCore,
|
|
5
5
|
parseDaemonCliArgs
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-Q4XUZB34.js";
|
|
7
|
+
import "./chunk-Z3PCMYZO.js";
|
|
8
8
|
|
|
9
9
|
// src/index.ts
|
|
10
10
|
var parsedArgs = parseDaemonCliArgs(process.argv.slice(2));
|
|
@@ -12,7 +12,7 @@ if (!parsedArgs) {
|
|
|
12
12
|
console.error(DAEMON_CLI_USAGE);
|
|
13
13
|
process.exit(1);
|
|
14
14
|
}
|
|
15
|
-
var daemon = new DaemonCore(parsedArgs);
|
|
15
|
+
var daemon = new DaemonCore({ ...parsedArgs, localTrace: true });
|
|
16
16
|
try {
|
|
17
17
|
daemon.start();
|
|
18
18
|
} catch (err) {
|