@slock-ai/daemon 0.12.0 → 0.14.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 +34 -20
- package/dist/index.js +113 -41
- package/package.json +1 -1
package/dist/chat-bridge.js
CHANGED
|
@@ -27,28 +27,38 @@ var commonHeaders = { "Content-Type": "application/json" };
|
|
|
27
27
|
if (authToken) {
|
|
28
28
|
commonHeaders["Authorization"] = `Bearer ${authToken}`;
|
|
29
29
|
}
|
|
30
|
+
function formatTarget(m) {
|
|
31
|
+
if (m.channel_type === "thread" && m.parent_channel_name) {
|
|
32
|
+
const shortId = m.channel_name.startsWith("thread-") ? m.channel_name.slice(7) : m.channel_name;
|
|
33
|
+
if (m.parent_channel_type === "dm") {
|
|
34
|
+
return `dm:@${m.parent_channel_name}:${shortId}`;
|
|
35
|
+
}
|
|
36
|
+
return `#${m.parent_channel_name}:${shortId}`;
|
|
37
|
+
}
|
|
38
|
+
if (m.channel_type === "dm") {
|
|
39
|
+
return `dm:@${m.channel_name}`;
|
|
40
|
+
}
|
|
41
|
+
return `#${m.channel_name}`;
|
|
42
|
+
}
|
|
30
43
|
var server = new McpServer({
|
|
31
44
|
name: "chat",
|
|
32
45
|
version: "1.0.0"
|
|
33
46
|
});
|
|
34
47
|
server.tool(
|
|
35
48
|
"send_message",
|
|
36
|
-
"Send a message to a channel or
|
|
49
|
+
"Send a message to a channel, DM, or thread. Use the target value from received messages to reply. Format: '#channel' for channels, 'dm:@peer' for DMs, '#channel:shortid' for threads in channels, 'dm:@peer:shortid' for threads in DMs. To start a NEW DM, use 'dm:@person-name'.",
|
|
37
50
|
{
|
|
38
|
-
|
|
39
|
-
"Where to send. Reuse the identifier from received messages: '#channel
|
|
40
|
-
),
|
|
41
|
-
dm_to: z.string().optional().describe(
|
|
42
|
-
"Person's name to start a NEW DM with (e.g. 'richard'). Only for starting a new DM \u2014 to reply in an existing DM, use channel instead."
|
|
51
|
+
target: z.string().describe(
|
|
52
|
+
"Where to send. Reuse the identifier from received messages. Format: '#channel' for channels, 'dm:@name' for DMs, '#channel:id' for channel threads, 'dm:@name:id' for DM threads. Examples: '#general', 'dm:@richard', '#general:abcd1234', 'dm:@richard:abcd1234'."
|
|
43
53
|
),
|
|
44
54
|
content: z.string().describe("The message content")
|
|
45
55
|
},
|
|
46
|
-
async ({
|
|
56
|
+
async ({ target, content }) => {
|
|
47
57
|
try {
|
|
48
58
|
const res = await fetch(`${serverUrl}/internal/agent/${agentId}/send`, {
|
|
49
59
|
method: "POST",
|
|
50
60
|
headers: commonHeaders,
|
|
51
|
-
body: JSON.stringify({
|
|
61
|
+
body: JSON.stringify({ target, content })
|
|
52
62
|
});
|
|
53
63
|
const data = await res.json();
|
|
54
64
|
if (!res.ok) {
|
|
@@ -58,11 +68,13 @@ server.tool(
|
|
|
58
68
|
]
|
|
59
69
|
};
|
|
60
70
|
}
|
|
71
|
+
const shortId = data.messageId ? data.messageId.slice(0, 8) : null;
|
|
72
|
+
const replyHint = shortId ? ` (to reply in this message's thread, use target "${target.includes(":") ? target : target + ":" + shortId}")` : "";
|
|
61
73
|
return {
|
|
62
74
|
content: [
|
|
63
75
|
{
|
|
64
76
|
type: "text",
|
|
65
|
-
text: `Message sent to ${
|
|
77
|
+
text: `Message sent to ${target}. Message ID: ${data.messageId}${replyHint}`
|
|
66
78
|
}
|
|
67
79
|
]
|
|
68
80
|
};
|
|
@@ -75,7 +87,7 @@ server.tool(
|
|
|
75
87
|
);
|
|
76
88
|
server.tool(
|
|
77
89
|
"receive_message",
|
|
78
|
-
"Receive new messages. Use block=true to wait for new messages. Returns messages formatted as [#channel
|
|
90
|
+
"Receive new messages. Use block=true to wait for new messages. Returns messages formatted as [#channel], [dm:@peer], or [thread:#channel:id] followed by the sender and content.",
|
|
79
91
|
{
|
|
80
92
|
block: z.boolean().default(true).describe("Whether to block (wait) for new messages"),
|
|
81
93
|
timeout_ms: z.number().default(59e3).describe("How long to wait in ms when blocking (default 59s, just under MCP tool call timeout)")
|
|
@@ -96,10 +108,11 @@ server.tool(
|
|
|
96
108
|
};
|
|
97
109
|
}
|
|
98
110
|
const formatted = data.messages.map((m) => {
|
|
99
|
-
const
|
|
100
|
-
const
|
|
101
|
-
const time = m.timestamp ?
|
|
102
|
-
|
|
111
|
+
const target = formatTarget(m);
|
|
112
|
+
const msgId = m.message_id ? m.message_id.slice(0, 8) : "-";
|
|
113
|
+
const time = m.timestamp ? toLocalTime(m.timestamp) : "-";
|
|
114
|
+
const senderType = m.sender_type === "agent" ? " type=agent" : "";
|
|
115
|
+
return `[target=${target} msg=${msgId} time=${time}${senderType}] @${m.sender_name}: ${m.content}`;
|
|
103
116
|
}).join("\n");
|
|
104
117
|
return {
|
|
105
118
|
content: [{ type: "text", text: formatted }]
|
|
@@ -146,7 +159,7 @@ server.tool(
|
|
|
146
159
|
text += " (none)\n";
|
|
147
160
|
}
|
|
148
161
|
text += "\n### Humans\n";
|
|
149
|
-
text += 'To start a new DM: send_message(
|
|
162
|
+
text += 'To start a new DM: send_message(target="dm:@name"). To reply in an existing DM: reuse the target from received messages.\n';
|
|
150
163
|
if (data.humans?.length > 0) {
|
|
151
164
|
for (const u of data.humans) {
|
|
152
165
|
text += ` - @${u.name}
|
|
@@ -167,9 +180,9 @@ server.tool(
|
|
|
167
180
|
);
|
|
168
181
|
server.tool(
|
|
169
182
|
"read_history",
|
|
170
|
-
"Read message history for a channel or
|
|
183
|
+
"Read message history for a channel, DM, or thread. Use the same target format: '#channel', 'dm:@name', '#channel:id' for threads, 'dm:@name:id' for DM threads. Supports pagination: use 'before' to load older messages, 'after' to load messages after a seq number (e.g. to catch up on unread).",
|
|
171
184
|
{
|
|
172
|
-
channel: z.string().describe("The
|
|
185
|
+
channel: z.string().describe("The target to read history from \u2014 e.g. '#general', 'dm:@richard', '#general:abcd1234', 'dm:@richard:abcd1234'"),
|
|
173
186
|
limit: z.number().default(50).describe("Max number of messages to return (default 50, max 100)"),
|
|
174
187
|
before: z.number().optional().describe("Return messages before this seq number (for backward pagination). Omit for latest messages."),
|
|
175
188
|
after: z.number().optional().describe("Return messages after this seq number (for catching up on unread). Returns oldest-first.")
|
|
@@ -201,9 +214,10 @@ server.tool(
|
|
|
201
214
|
};
|
|
202
215
|
}
|
|
203
216
|
const formatted = data.messages.map((m) => {
|
|
204
|
-
const
|
|
205
|
-
const time = m.createdAt ?
|
|
206
|
-
|
|
217
|
+
const senderType = m.senderType === "agent" ? " type=agent" : "";
|
|
218
|
+
const time = m.createdAt ? toLocalTime(m.createdAt) : "-";
|
|
219
|
+
const msgId = m.id ? m.id.slice(0, 8) : "-";
|
|
220
|
+
return `[seq=${m.seq} msg=${msgId} time=${time}${senderType}] @${m.senderName}: ${m.content}`;
|
|
207
221
|
}).join("\n");
|
|
208
222
|
let footer = "";
|
|
209
223
|
if (data.historyLimited) {
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import
|
|
4
|
+
import path4 from "path";
|
|
5
5
|
import os2 from "os";
|
|
6
6
|
import { createRequire } from "module";
|
|
7
7
|
import { execSync as execSync2 } from "child_process";
|
|
@@ -84,11 +84,13 @@ var DaemonConnection = class {
|
|
|
84
84
|
|
|
85
85
|
// src/agentProcessManager.ts
|
|
86
86
|
import { mkdir, writeFile, access, readdir, stat, readFile, rm } from "fs/promises";
|
|
87
|
-
import
|
|
87
|
+
import path3 from "path";
|
|
88
88
|
import os from "os";
|
|
89
89
|
|
|
90
90
|
// src/drivers/claude.ts
|
|
91
91
|
import { spawn } from "child_process";
|
|
92
|
+
import { writeFileSync } from "fs";
|
|
93
|
+
import path from "path";
|
|
92
94
|
|
|
93
95
|
// src/drivers/systemPrompt.ts
|
|
94
96
|
function toolRef(prefix, name) {
|
|
@@ -143,20 +145,41 @@ ${opts.postStartupNotes.join("\n")}`;
|
|
|
143
145
|
|
|
144
146
|
## Messaging
|
|
145
147
|
|
|
146
|
-
Messages you receive
|
|
147
|
-
- **Channel message from a human**: \`[#all] @richard: hello everyone\`
|
|
148
|
-
- **Channel message from an agent**: \`[#all] (agent) @Alice: hi there\`
|
|
149
|
-
- **DM from a human**: \`[DM:@richard] @richard: hey, can you help?\`
|
|
148
|
+
Messages you receive have a single RFC 5424-style structured data header followed by the sender and content:
|
|
150
149
|
|
|
151
|
-
|
|
150
|
+
\`\`\`
|
|
151
|
+
[target=#general msg=a1b2c3d4 time=2026-03-15T01:00:00] @richard: hello everyone
|
|
152
|
+
[target=#general msg=e5f6a7b8 time=2026-03-15T01:00:01 type=agent] @Alice: hi there
|
|
153
|
+
[target=dm:@richard msg=c9d0e1f2 time=2026-03-15T01:00:02] @richard: hey, can you help?
|
|
154
|
+
[target=#general:a1b2c3d4 msg=f3a4b5c6 time=2026-03-15T01:00:03] @richard: thread reply
|
|
155
|
+
[target=dm:@richard:x9y8z7a0 msg=d7e8f9a0 time=2026-03-15T01:00:04] @richard: DM thread reply
|
|
156
|
+
\`\`\`
|
|
157
|
+
|
|
158
|
+
Header fields:
|
|
159
|
+
- \`target=\` \u2014 where the message came from. Reuse as the \`target\` parameter when replying.
|
|
160
|
+
- \`msg=\` \u2014 message short ID (first 8 chars of UUID). Use as thread suffix to start/reply in a thread.
|
|
161
|
+
- \`time=\` \u2014 timestamp.
|
|
162
|
+
- \`type=agent\` \u2014 present only if the sender is an agent.
|
|
152
163
|
|
|
153
164
|
### Sending messages
|
|
154
165
|
|
|
155
|
-
- **Reply to a channel**: \`send_message(
|
|
156
|
-
- **Reply to a DM**: \`send_message(
|
|
157
|
-
- **
|
|
166
|
+
- **Reply to a channel**: \`send_message(target="#channel-name", content="...")\`
|
|
167
|
+
- **Reply to a DM**: \`send_message(target="dm:@peer-name", content="...")\`
|
|
168
|
+
- **Reply in a thread**: \`send_message(target="#channel:shortid", content="...")\` or \`send_message(target="dm:@peer:shortid", content="...")\`
|
|
169
|
+
- **Start a NEW DM**: \`send_message(target="dm:@person-name", content="...")\`
|
|
170
|
+
|
|
171
|
+
**IMPORTANT**: To reply to any message, always reuse the exact \`target\` from the received message. This ensures your reply goes to the right place \u2014 whether it's a channel, DM, or thread.
|
|
158
172
|
|
|
159
|
-
|
|
173
|
+
### Threads
|
|
174
|
+
|
|
175
|
+
Threads are sub-conversations attached to a specific message. They let you discuss a topic without cluttering the main channel.
|
|
176
|
+
|
|
177
|
+
- **Thread targets** have a colon and short ID suffix: \`#general:a1b2c3d4\` (thread in #general) or \`dm:@richard:x9y8z7a0\` (thread in a DM).
|
|
178
|
+
- When you receive a message from a thread (the target has a \`:shortid\` suffix), **always reply using that same target** to keep the conversation in the thread.
|
|
179
|
+
- **Start a new thread**: Use the \`msg=\` field from the header as the thread suffix. For example, if you see \`[target=#general msg=a1b2c3d4 ...]\`, reply with \`send_message(target="#general:a1b2c3d4", content="...")\`. The thread will be auto-created if it doesn't exist yet.
|
|
180
|
+
- When you send a message, the response includes the message ID. You can use it to start a thread on your own message.
|
|
181
|
+
- You can read thread history: \`read_history(channel="#general:a1b2c3d4")\`
|
|
182
|
+
- Threads cannot be nested \u2014 you cannot start a thread inside a thread.
|
|
160
183
|
|
|
161
184
|
### Discovering people and channels
|
|
162
185
|
|
|
@@ -165,13 +188,13 @@ Call \`list_server\` to see all channels in this server, which ones you have joi
|
|
|
165
188
|
### Channel awareness
|
|
166
189
|
|
|
167
190
|
Each channel has a **name** and optionally a **description** that define its purpose (visible via \`list_server\`). Respect them:
|
|
168
|
-
- **Reply in context** \u2014 always respond in the channel the message came from.
|
|
191
|
+
- **Reply in context** \u2014 always respond in the channel/thread the message came from.
|
|
169
192
|
- **Stay on topic** \u2014 when proactively sharing results or updates, post in the channel most relevant to the work. Don't scatter messages across unrelated channels.
|
|
170
193
|
- If unsure where something belongs, call \`list_server\` to review channel descriptions.
|
|
171
194
|
|
|
172
195
|
### Reading history
|
|
173
196
|
|
|
174
|
-
\`read_history(channel="#channel-name")\` or \`read_history(channel="
|
|
197
|
+
\`read_history(channel="#channel-name")\` or \`read_history(channel="dm:@peer-name")\` or \`read_history(channel="#channel:shortid")\`
|
|
175
198
|
|
|
176
199
|
### Task boards
|
|
177
200
|
|
|
@@ -348,6 +371,8 @@ var ClaudeDriver = class {
|
|
|
348
371
|
}
|
|
349
372
|
}
|
|
350
373
|
});
|
|
374
|
+
const mcpConfigPath = path.join(ctx.workingDirectory, ".slock-claude-mcp.json");
|
|
375
|
+
writeFileSync(mcpConfigPath, mcpConfig, "utf8");
|
|
351
376
|
const args2 = [
|
|
352
377
|
"--allow-dangerously-skip-permissions",
|
|
353
378
|
"--dangerously-skip-permissions",
|
|
@@ -357,7 +382,7 @@ var ClaudeDriver = class {
|
|
|
357
382
|
"--input-format",
|
|
358
383
|
"stream-json",
|
|
359
384
|
"--mcp-config",
|
|
360
|
-
|
|
385
|
+
mcpConfigPath,
|
|
361
386
|
"--model",
|
|
362
387
|
ctx.config.model || "sonnet"
|
|
363
388
|
];
|
|
@@ -472,9 +497,9 @@ var ClaudeDriver = class {
|
|
|
472
497
|
if (name === "WebFetch" || name === "web_fetch") return input.url || "";
|
|
473
498
|
if (name === "WebSearch" || name === "web_search") return input.query || "";
|
|
474
499
|
if (name === "mcp__chat__send_message") {
|
|
475
|
-
return input.channel || (input.dm_to ? `DM:@${input.dm_to}` : "");
|
|
500
|
+
return input.target || input.channel || (input.dm_to ? `DM:@${input.dm_to}` : "");
|
|
476
501
|
}
|
|
477
|
-
if (name === "mcp__chat__read_history") return input.channel || "";
|
|
502
|
+
if (name === "mcp__chat__read_history") return input.target || input.channel || "";
|
|
478
503
|
if (name === "mcp__chat__list_tasks") return input.channel || "";
|
|
479
504
|
if (name === "mcp__chat__create_tasks") return input.channel || "";
|
|
480
505
|
if (name === "mcp__chat__claim_tasks") {
|
|
@@ -494,13 +519,13 @@ var ClaudeDriver = class {
|
|
|
494
519
|
// src/drivers/codex.ts
|
|
495
520
|
import { spawn as spawn2, execSync } from "child_process";
|
|
496
521
|
import { existsSync } from "fs";
|
|
497
|
-
import
|
|
522
|
+
import path2 from "path";
|
|
498
523
|
var CodexDriver = class {
|
|
499
524
|
id = "codex";
|
|
500
525
|
supportsStdinNotification = false;
|
|
501
526
|
mcpToolPrefix = "mcp_chat_";
|
|
502
527
|
spawn(ctx) {
|
|
503
|
-
const gitDir =
|
|
528
|
+
const gitDir = path2.join(ctx.workingDirectory, ".git");
|
|
504
529
|
if (!existsSync(gitDir)) {
|
|
505
530
|
execSync("git init", { cwd: ctx.workingDirectory, stdio: "pipe" });
|
|
506
531
|
execSync("git add -A && git commit --allow-empty -m 'init'", {
|
|
@@ -683,9 +708,9 @@ var CodexDriver = class {
|
|
|
683
708
|
if (name === "file_write") return input.path || input.file_path || "";
|
|
684
709
|
if (name === "web_search") return input.query || "";
|
|
685
710
|
if (name === `${this.mcpToolPrefix}send_message`) {
|
|
686
|
-
return input.channel || (input.dm_to ? `DM:@${input.dm_to}` : "");
|
|
711
|
+
return input.target || input.channel || (input.dm_to ? `DM:@${input.dm_to}` : "");
|
|
687
712
|
}
|
|
688
|
-
if (name === `${this.mcpToolPrefix}read_history`) return input.channel || "";
|
|
713
|
+
if (name === `${this.mcpToolPrefix}read_history`) return input.target || input.channel || "";
|
|
689
714
|
if (name === `${this.mcpToolPrefix}list_tasks`) return input.channel || "";
|
|
690
715
|
if (name === `${this.mcpToolPrefix}create_tasks`) return input.channel || "";
|
|
691
716
|
if (name === `${this.mcpToolPrefix}claim_tasks`) {
|
|
@@ -716,7 +741,7 @@ function getDriver(runtimeId) {
|
|
|
716
741
|
}
|
|
717
742
|
|
|
718
743
|
// src/agentProcessManager.ts
|
|
719
|
-
var DATA_DIR =
|
|
744
|
+
var DATA_DIR = path3.join(os.homedir(), ".slock", "agents");
|
|
720
745
|
function toLocalTime(iso) {
|
|
721
746
|
const d = new Date(iso);
|
|
722
747
|
if (isNaN(d.getTime())) return iso;
|
|
@@ -741,9 +766,9 @@ var AgentProcessManager = class {
|
|
|
741
766
|
this.agentsStarting.add(agentId);
|
|
742
767
|
try {
|
|
743
768
|
const driver = getDriver(config.runtime || "claude");
|
|
744
|
-
const agentDataDir =
|
|
769
|
+
const agentDataDir = path3.join(DATA_DIR, agentId);
|
|
745
770
|
await mkdir(agentDataDir, { recursive: true });
|
|
746
|
-
const memoryMdPath =
|
|
771
|
+
const memoryMdPath = path3.join(agentDataDir, "MEMORY.md");
|
|
747
772
|
try {
|
|
748
773
|
await access(memoryMdPath);
|
|
749
774
|
} catch {
|
|
@@ -761,7 +786,7 @@ ${config.description || "No role defined yet."}
|
|
|
761
786
|
`;
|
|
762
787
|
await writeFile(memoryMdPath, initialMemoryMd);
|
|
763
788
|
}
|
|
764
|
-
await mkdir(
|
|
789
|
+
await mkdir(path3.join(agentDataDir, "notes"), { recursive: true });
|
|
765
790
|
const isResume = !!config.sessionId;
|
|
766
791
|
let prompt;
|
|
767
792
|
if (isResume && wakeMessage) {
|
|
@@ -941,7 +966,7 @@ Note: While you are busy, you may receive [System notification: ...] messages ab
|
|
|
941
966
|
}
|
|
942
967
|
}
|
|
943
968
|
async resetWorkspace(agentId) {
|
|
944
|
-
const agentDataDir =
|
|
969
|
+
const agentDataDir = path3.join(DATA_DIR, agentId);
|
|
945
970
|
try {
|
|
946
971
|
await rm(agentDataDir, { recursive: true, force: true });
|
|
947
972
|
console.log(`[Agent ${agentId}] Workspace deleted: ${agentDataDir}`);
|
|
@@ -967,14 +992,14 @@ Note: While you are busy, you may receive [System notification: ...] messages ab
|
|
|
967
992
|
}
|
|
968
993
|
for (const entry of entries) {
|
|
969
994
|
if (!entry.isDirectory()) continue;
|
|
970
|
-
const dirPath =
|
|
995
|
+
const dirPath = path3.join(DATA_DIR, entry.name);
|
|
971
996
|
try {
|
|
972
997
|
const dirContents = await readdir(dirPath, { withFileTypes: true });
|
|
973
998
|
let totalSize = 0;
|
|
974
999
|
let latestMtime = /* @__PURE__ */ new Date(0);
|
|
975
1000
|
let fileCount = 0;
|
|
976
1001
|
for (const item of dirContents) {
|
|
977
|
-
const itemPath =
|
|
1002
|
+
const itemPath = path3.join(dirPath, item.name);
|
|
978
1003
|
try {
|
|
979
1004
|
const info = await stat(itemPath);
|
|
980
1005
|
if (item.isFile()) {
|
|
@@ -1004,7 +1029,7 @@ Note: While you are busy, you may receive [System notification: ...] messages ab
|
|
|
1004
1029
|
if (directoryName.includes("/") || directoryName.includes("..") || directoryName.includes("\\")) {
|
|
1005
1030
|
return false;
|
|
1006
1031
|
}
|
|
1007
|
-
const targetDir =
|
|
1032
|
+
const targetDir = path3.join(DATA_DIR, directoryName);
|
|
1008
1033
|
try {
|
|
1009
1034
|
await rm(targetDir, { recursive: true, force: true });
|
|
1010
1035
|
console.log(`[Workspace] Deleted directory: ${targetDir}`);
|
|
@@ -1016,7 +1041,7 @@ Note: While you are busy, you may receive [System notification: ...] messages ab
|
|
|
1016
1041
|
}
|
|
1017
1042
|
// Workspace file browsing
|
|
1018
1043
|
async getFileTree(agentId, dirPath) {
|
|
1019
|
-
const agentDir =
|
|
1044
|
+
const agentDir = path3.join(DATA_DIR, agentId);
|
|
1020
1045
|
try {
|
|
1021
1046
|
await stat(agentDir);
|
|
1022
1047
|
} catch {
|
|
@@ -1024,8 +1049,8 @@ Note: While you are busy, you may receive [System notification: ...] messages ab
|
|
|
1024
1049
|
}
|
|
1025
1050
|
let targetDir = agentDir;
|
|
1026
1051
|
if (dirPath) {
|
|
1027
|
-
const resolved =
|
|
1028
|
-
if (!resolved.startsWith(agentDir +
|
|
1052
|
+
const resolved = path3.resolve(agentDir, dirPath);
|
|
1053
|
+
if (!resolved.startsWith(agentDir + path3.sep) && resolved !== agentDir) {
|
|
1029
1054
|
return [];
|
|
1030
1055
|
}
|
|
1031
1056
|
targetDir = resolved;
|
|
@@ -1033,9 +1058,9 @@ Note: While you are busy, you may receive [System notification: ...] messages ab
|
|
|
1033
1058
|
return this.listDirectoryChildren(targetDir, agentDir);
|
|
1034
1059
|
}
|
|
1035
1060
|
async readFile(agentId, filePath) {
|
|
1036
|
-
const agentDir =
|
|
1037
|
-
const resolved =
|
|
1038
|
-
if (!resolved.startsWith(agentDir +
|
|
1061
|
+
const agentDir = path3.join(DATA_DIR, agentId);
|
|
1062
|
+
const resolved = path3.resolve(agentDir, filePath);
|
|
1063
|
+
if (!resolved.startsWith(agentDir + path3.sep) && resolved !== agentDir) {
|
|
1039
1064
|
throw new Error("Access denied");
|
|
1040
1065
|
}
|
|
1041
1066
|
const info = await stat(resolved);
|
|
@@ -1059,7 +1084,7 @@ Note: While you are busy, you may receive [System notification: ...] messages ab
|
|
|
1059
1084
|
".sh",
|
|
1060
1085
|
".py"
|
|
1061
1086
|
]);
|
|
1062
|
-
const ext =
|
|
1087
|
+
const ext = path3.extname(resolved).toLowerCase();
|
|
1063
1088
|
if (!TEXT_EXTENSIONS.has(ext) && ext !== "") {
|
|
1064
1089
|
return { content: null, binary: true };
|
|
1065
1090
|
}
|
|
@@ -1098,7 +1123,10 @@ Note: While you are busy, you may receive [System notification: ...] messages ab
|
|
|
1098
1123
|
const inputSummary = driver.summarizeToolInput(toolName, event.input);
|
|
1099
1124
|
trajectory.push({ kind: "tool_start", toolName, toolInput: inputSummary });
|
|
1100
1125
|
if (toolName === `${driver.mcpToolPrefix}receive_message`) {
|
|
1101
|
-
|
|
1126
|
+
const isBlocking = event.input?.block !== false;
|
|
1127
|
+
if (isBlocking) {
|
|
1128
|
+
activity = "online";
|
|
1129
|
+
}
|
|
1102
1130
|
if (ap) {
|
|
1103
1131
|
ap.isInReceiveMessage = true;
|
|
1104
1132
|
ap.pendingNotificationCount = 0;
|
|
@@ -1173,8 +1201,8 @@ Note: While you are busy, you may receive [System notification: ...] messages ab
|
|
|
1173
1201
|
const nodes = [];
|
|
1174
1202
|
for (const entry of entries) {
|
|
1175
1203
|
if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
|
|
1176
|
-
const fullPath =
|
|
1177
|
-
const relativePath =
|
|
1204
|
+
const fullPath = path3.join(dir, entry.name);
|
|
1205
|
+
const relativePath = path3.relative(rootDir, fullPath);
|
|
1178
1206
|
let info;
|
|
1179
1207
|
try {
|
|
1180
1208
|
info = await stat(fullPath);
|
|
@@ -1191,6 +1219,50 @@ Note: While you are busy, you may receive [System notification: ...] messages ab
|
|
|
1191
1219
|
}
|
|
1192
1220
|
};
|
|
1193
1221
|
|
|
1222
|
+
// ../shared/src/serverPermissions.ts
|
|
1223
|
+
var EMPTY_SERVER_CAPABILITIES = Object.freeze({
|
|
1224
|
+
manageServer: false,
|
|
1225
|
+
manageChannels: false,
|
|
1226
|
+
manageAgents: false,
|
|
1227
|
+
manageMachines: false,
|
|
1228
|
+
manageMembers: false,
|
|
1229
|
+
changeMemberRoles: false,
|
|
1230
|
+
manageBilling: false,
|
|
1231
|
+
joinPublicChannels: false
|
|
1232
|
+
});
|
|
1233
|
+
var SERVER_CAPABILITY_MATRIX = {
|
|
1234
|
+
owner: Object.freeze({
|
|
1235
|
+
manageServer: true,
|
|
1236
|
+
manageChannels: true,
|
|
1237
|
+
manageAgents: true,
|
|
1238
|
+
manageMachines: true,
|
|
1239
|
+
manageMembers: true,
|
|
1240
|
+
changeMemberRoles: true,
|
|
1241
|
+
manageBilling: true,
|
|
1242
|
+
joinPublicChannels: true
|
|
1243
|
+
}),
|
|
1244
|
+
admin: Object.freeze({
|
|
1245
|
+
manageServer: true,
|
|
1246
|
+
manageChannels: true,
|
|
1247
|
+
manageAgents: true,
|
|
1248
|
+
manageMachines: true,
|
|
1249
|
+
manageMembers: true,
|
|
1250
|
+
changeMemberRoles: false,
|
|
1251
|
+
manageBilling: false,
|
|
1252
|
+
joinPublicChannels: true
|
|
1253
|
+
}),
|
|
1254
|
+
member: Object.freeze({
|
|
1255
|
+
manageServer: false,
|
|
1256
|
+
manageChannels: false,
|
|
1257
|
+
manageAgents: false,
|
|
1258
|
+
manageMachines: false,
|
|
1259
|
+
manageMembers: false,
|
|
1260
|
+
changeMemberRoles: false,
|
|
1261
|
+
manageBilling: false,
|
|
1262
|
+
joinPublicChannels: true
|
|
1263
|
+
})
|
|
1264
|
+
};
|
|
1265
|
+
|
|
1194
1266
|
// ../shared/src/index.ts
|
|
1195
1267
|
var RUNTIMES = [
|
|
1196
1268
|
{ id: "claude", displayName: "Claude Code", binary: "claude", supported: true },
|
|
@@ -1225,12 +1297,12 @@ if (!serverUrl || !apiKey) {
|
|
|
1225
1297
|
console.error("Usage: slock-daemon --server-url <url> --api-key <key>");
|
|
1226
1298
|
process.exit(1);
|
|
1227
1299
|
}
|
|
1228
|
-
var __dirname =
|
|
1229
|
-
var chatBridgePath =
|
|
1300
|
+
var __dirname = path4.dirname(fileURLToPath(import.meta.url));
|
|
1301
|
+
var chatBridgePath = path4.resolve(__dirname, "chat-bridge.js");
|
|
1230
1302
|
try {
|
|
1231
1303
|
accessSync(chatBridgePath);
|
|
1232
1304
|
} catch {
|
|
1233
|
-
chatBridgePath =
|
|
1305
|
+
chatBridgePath = path4.resolve(__dirname, "chat-bridge.ts");
|
|
1234
1306
|
}
|
|
1235
1307
|
var connection;
|
|
1236
1308
|
var agentManager = new AgentProcessManager(chatBridgePath, (msg) => {
|