@slock-ai/daemon 0.43.0 → 0.46.0-play.20260508161002

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.
@@ -1,8 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ DEFAULT_CHAT_BRIDGE_TOOL_TIMEOUT_MS,
3
4
  buildFetchDispatcher,
5
+ executeJsonRequest,
6
+ executeResponseRequest,
4
7
  logger
5
- } from "./chunk-JG7ONJZ6.js";
8
+ } from "./chunk-Z3PCMYZO.js";
6
9
 
7
10
  // src/chat-bridge.ts
8
11
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
@@ -31,7 +34,7 @@ var searchMessagesDeprecatedSchema = {
31
34
  };
32
35
  var listTasksDeprecatedSchema = {
33
36
  channel: z.string().describe("Deprecated channel argument."),
34
- status: z.enum(["all", "todo", "in_progress", "in_review", "done"]).optional().describe("Deprecated status argument.")
37
+ status: z.enum(["all", "todo", "in_progress", "in_review", "done", "closed"]).optional().describe("Deprecated status argument.")
35
38
  };
36
39
  var claimTasksDeprecatedSchema = {
37
40
  channel: z.string().describe("Deprecated channel argument."),
@@ -45,7 +48,7 @@ var unclaimTaskDeprecatedSchema = {
45
48
  var updateTaskStatusDeprecatedSchema = {
46
49
  channel: z.string().describe("Deprecated channel argument."),
47
50
  task_number: z.number().describe("Deprecated task number."),
48
- status: z.enum(["todo", "in_progress", "in_review", "done"]).describe("Deprecated status argument.")
51
+ status: z.enum(["todo", "in_progress", "in_review", "done", "closed"]).describe("Deprecated status argument.")
49
52
  };
50
53
  var DEPRECATED_MCP_TOOL_DEFINITIONS = [
51
54
  {
@@ -164,103 +167,6 @@ function formatHistoryMessageLine(message) {
164
167
  return `[${headerParts.join(" ")}] ${formatHistorySenderHandle(message)}: ${message.content}${attachSuffix}${taskSuffix}`;
165
168
  }
166
169
 
167
- // src/chatBridgeRequest.ts
168
- var DEFAULT_CHAT_BRIDGE_TOOL_TIMEOUT_MS = Number.parseInt(
169
- process.env.SLOCK_CHAT_BRIDGE_TOOL_TIMEOUT_MS || "",
170
- 10
171
- ) || 6e4;
172
- var ChatBridgeToolTimeoutError = class extends Error {
173
- toolName;
174
- target;
175
- timeoutMs;
176
- durationMs;
177
- constructor(toolName, target, timeoutMs, durationMs) {
178
- super(`${toolName} timed out after ${timeoutMs}ms${target ? ` (target: ${target})` : ""}`);
179
- this.name = "ChatBridgeToolTimeoutError";
180
- this.toolName = toolName;
181
- this.target = target;
182
- this.timeoutMs = timeoutMs;
183
- this.durationMs = durationMs;
184
- }
185
- };
186
- function describeError(err) {
187
- if (err instanceof Error) return `${err.name}: ${err.message}`;
188
- return String(err);
189
- }
190
- async function executeJsonRequest(url, init, {
191
- toolName,
192
- target = null,
193
- timeoutMs = DEFAULT_CHAT_BRIDGE_TOOL_TIMEOUT_MS,
194
- fetchImpl,
195
- now = () => Date.now(),
196
- warn = (message) => logger.warn(message)
197
- }) {
198
- const startedAt = now();
199
- const timeoutController = new AbortController();
200
- const signals = [timeoutController.signal];
201
- if (init.signal) signals.push(init.signal);
202
- const signal = signals.length === 1 ? signals[0] : AbortSignal.any(signals);
203
- const timeout = setTimeout(() => {
204
- timeoutController.abort();
205
- }, timeoutMs);
206
- timeout.unref?.();
207
- try {
208
- const response = await fetchImpl(url, { ...init, signal });
209
- const data = await response.json();
210
- return { response, data, durationMs: now() - startedAt };
211
- } catch (err) {
212
- const durationMs = now() - startedAt;
213
- if (timeoutController.signal.aborted && !init.signal?.aborted) {
214
- warn(
215
- `[ChatBridgeTimeout] tool=${toolName} target=${target ?? "-"} duration_ms=${durationMs} timeout_ms=${timeoutMs} outcome=timeout`
216
- );
217
- throw new ChatBridgeToolTimeoutError(toolName, target, timeoutMs, durationMs);
218
- }
219
- warn(
220
- `[ChatBridgeError] tool=${toolName} target=${target ?? "-"} duration_ms=${durationMs} outcome=error error=${describeError(err)}`
221
- );
222
- throw err;
223
- } finally {
224
- clearTimeout(timeout);
225
- }
226
- }
227
- async function executeResponseRequest(url, init, {
228
- toolName,
229
- target = null,
230
- timeoutMs = DEFAULT_CHAT_BRIDGE_TOOL_TIMEOUT_MS,
231
- fetchImpl,
232
- now = () => Date.now(),
233
- warn = (message) => logger.warn(message)
234
- }) {
235
- const startedAt = now();
236
- const timeoutController = new AbortController();
237
- const signals = [timeoutController.signal];
238
- if (init.signal) signals.push(init.signal);
239
- const signal = signals.length === 1 ? signals[0] : AbortSignal.any(signals);
240
- const timeout = setTimeout(() => {
241
- timeoutController.abort();
242
- }, timeoutMs);
243
- timeout.unref?.();
244
- try {
245
- const response = await fetchImpl(url, { ...init, signal });
246
- return { response, durationMs: now() - startedAt };
247
- } catch (err) {
248
- const durationMs = now() - startedAt;
249
- if (timeoutController.signal.aborted && !init.signal?.aborted) {
250
- warn(
251
- `[ChatBridgeTimeout] tool=${toolName} target=${target ?? "-"} duration_ms=${durationMs} timeout_ms=${timeoutMs} outcome=timeout`
252
- );
253
- throw new ChatBridgeToolTimeoutError(toolName, target, timeoutMs, durationMs);
254
- }
255
- warn(
256
- `[ChatBridgeError] tool=${toolName} target=${target ?? "-"} duration_ms=${durationMs} outcome=error error=${describeError(err)}`
257
- );
258
- throw err;
259
- } finally {
260
- clearTimeout(timeout);
261
- }
262
- }
263
-
264
170
  // src/chatBridgeSendRequest.ts
265
171
  import { randomUUID } from "crypto";
266
172
  async function executeRetrySafeSendRequest(url, buildInit, {
@@ -325,6 +231,8 @@ function buildChatBridgeCommonHeaders(authToken2, { includeContentType = true }
325
231
  }
326
232
 
327
233
  // src/chat-bridge.ts
234
+ var MAX_UPLOAD_FILE_BYTES = 50 * 1024 * 1024;
235
+ var MAX_UPLOAD_FILE_LABEL = "50MB";
328
236
  function toLocalTime(iso) {
329
237
  const d = new Date(iso);
330
238
  if (isNaN(d.getTime())) return iso;
@@ -710,7 +618,7 @@ ${formatMessages(unreadToShow)}`;
710
618
  );
711
619
  server.tool(
712
620
  "upload_file",
713
- "Upload a file to attach to a message. Returns an attachment ID that you can pass to send_message's attachment_ids parameter. Images keep preview behavior; other files are sent as downloadable attachments. Max size: 10MB.",
621
+ `Upload a file to attach to a message. Returns an attachment ID that you can pass to send_message's attachment_ids parameter. Images keep preview behavior; other files are sent as downloadable attachments. Max size: ${MAX_UPLOAD_FILE_LABEL}. Video files are downloadable attachments and are not parsed by agents. Large PDFs may need to be downloaded and inspected in smaller chunks.`,
714
622
  {
715
623
  file_path: z2.string().describe("Absolute path to the file on your local filesystem"),
716
624
  channel: z2.string().describe("The channel target where this file will be used (e.g. '#general', 'dm:@richard')")
@@ -726,10 +634,16 @@ ${formatMessages(unreadToShow)}`;
726
634
  };
727
635
  }
728
636
  const stat = fs.statSync(file_path);
729
- if (stat.size > 10 * 1024 * 1024) {
637
+ if (stat.size > MAX_UPLOAD_FILE_BYTES) {
638
+ return {
639
+ isError: true,
640
+ content: [{ type: "text", text: `Error: File too large (${(stat.size / 1024 / 1024).toFixed(1)}MB). Max ${MAX_UPLOAD_FILE_LABEL} per file.` }]
641
+ };
642
+ }
643
+ if (stat.size === 0) {
730
644
  return {
731
645
  isError: true,
732
- content: [{ type: "text", text: `Error: File too large (${(stat.size / 1024 / 1024).toFixed(1)}MB). Max 10MB per file.` }]
646
+ content: [{ type: "text", text: "Error: File is empty; refusing to upload a 0-byte attachment." }]
733
647
  };
734
648
  }
735
649
  const { response: listRes, data: listData } = await executeJsonRequest(
@@ -911,10 +825,11 @@ Use this ID in send_message's attachment_ids parameter to include it in a messag
911
825
  const humans = data.humans ?? [];
912
826
  text += formatRuntimeContext(data.runtimeContext);
913
827
  text += "### Channels\n";
914
- text += 'Visible public channels may appear even when `joined=false`. Use `read_history(channel="#name")` to inspect them. 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 regular channel you have joined, use `leave_channel(target="#name")`.\n';
828
+ 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 `read_history(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 regular channel you have joined, use `leave_channel(target="#name")`.\n';
915
829
  if (channels.length > 0) {
916
830
  for (const t of channels) {
917
- const status = t.joined ? "joined" : "not joined";
831
+ const visibility = t.type === "private" ? "private" : "public";
832
+ const status = `${visibility}, ${t.joined ? "joined" : "not joined"}`;
918
833
  text += t.description ? ` - #${t.name} [${status}] \u2014 ${t.description}
919
834
  ` : ` - #${t.name} [${status}]
920
835
  `;
@@ -1007,9 +922,10 @@ Use this ID in send_message's attachment_ids parameter to include it in a messag
1007
922
  sender_id: z2.string().optional().describe("Optional exact sender id filter."),
1008
923
  after: z2.string().optional().describe("Optional inclusive ISO datetime lower bound for message created_at."),
1009
924
  before: z2.string().optional().describe("Optional inclusive ISO datetime upper bound for message created_at."),
925
+ sort: z2.enum(["relevance", "recent"]).optional().describe("Optional result sort. Use 'relevance' for best match first or 'recent' for newest first."),
1010
926
  limit: z2.number().default(10).describe("Max number of search results to return (default 10, max 20)")
1011
927
  },
1012
- async ({ query, channel, sender_id, after, before, limit }) => {
928
+ async ({ query, channel, sender_id, after, before, sort, limit }) => {
1013
929
  try {
1014
930
  const trimmed = query.trim();
1015
931
  if (!trimmed) {
@@ -1024,6 +940,7 @@ Use this ID in send_message's attachment_ids parameter to include it in a messag
1024
940
  if (sender_id) params.set("senderId", sender_id);
1025
941
  if (after) params.set("after", after);
1026
942
  if (before) params.set("before", before);
943
+ if (sort) params.set("sort", sort);
1027
944
  const { response: res, data } = await executeJsonRequest(
1028
945
  `${serverUrl}/internal/agent/${agentId}/search?${params}`,
1029
946
  { method: "GET", headers: commonHeaders },
@@ -1170,7 +1087,7 @@ ${formatted}${footer}`
1170
1087
  "List all tasks in a channel. Returns each task's number, title, status, assignee, and message ID. Use this to see what work exists before claiming. Tasks marked as legacy are from an older system and cannot be claimed or modified.",
1171
1088
  {
1172
1089
  channel: z2.string().describe("The channel whose task board to view \u2014 e.g. '#engineering', '#proj-slock'"),
1173
- status: z2.enum(["all", "todo", "in_progress", "in_review", "done"]).default("all").describe("Filter by status (default: all)")
1090
+ status: z2.enum(["all", "todo", "in_progress", "in_review", "done", "closed"]).default("all").describe("Filter by status (default: all)")
1174
1091
  },
1175
1092
  async ({ channel, status }) => {
1176
1093
  try {
@@ -1323,7 +1240,7 @@ Thread messages and system messages (e.g. task-claim / task-status announcements
1323
1240
  const msgShort = r.messageId ? r.messageId.slice(0, 8) : "";
1324
1241
  return `${label} (msg:${msgShort}): claimed`;
1325
1242
  }
1326
- return `${label}: FAILED \u2014 ${r.reason || "already claimed"}`;
1243
+ return `${label}: FAILED \u2014 ${r.reason || "already claimed"}. Do not reply.`;
1327
1244
  });
1328
1245
  const succeeded = data.results.filter((r) => r.success).length;
1329
1246
  const failed = data.results.length - succeeded;
@@ -1394,11 +1311,11 @@ ${lines.join("\n")}${threadHint}`
1394
1311
  );
1395
1312
  server.tool(
1396
1313
  "update_task_status",
1397
- "Update a task's progress status. You must be the task's assignee to update it. Use in_review when your work is ready for human validation. Only set done for trivial tasks or after explicit approval. Valid transitions: todo\u2192in_progress, in_progress\u2192in_review or done, in_review\u2192done or back to in_progress.",
1314
+ "Update a task's progress status. You must be the task's assignee to update it. Use in_review when your work is ready for human validation. Only set done for trivial tasks or after explicit approval. Use closed to mark a task as won't-do (cancelled / abandoned / out-of-scope) \u2014 distinct from done. Valid transitions: todo\u2192{in_progress,closed}, in_progress\u2192{in_review,done,closed}, in_review\u2192{done,in_progress,closed}, done\u2192{todo,in_progress,in_review,closed}, closed\u2192todo (reopen).",
1398
1315
  {
1399
1316
  channel: z2.string().describe("The channel \u2014 e.g. '#engineering'"),
1400
1317
  task_number: z2.number().describe("The task number to update (e.g. 3)"),
1401
- status: z2.enum(["todo", "in_progress", "in_review", "done"]).describe("The new status")
1318
+ status: z2.enum(["todo", "in_progress", "in_review", "done", "closed"]).describe("The new status")
1402
1319
  },
1403
1320
  async ({ channel, task_number, status }) => {
1404
1321
  try {