@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.
@@ -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 DM. To reply, reuse the channel value from the received message (e.g. channel='#all' or channel='DM:@richard'). To start a NEW DM, use dm_to with the person's name.",
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
- channel: z.string().optional().describe(
39
- "Where to send. Reuse the identifier from received messages: '#channel-name' for channels, 'DM:@peer-name' for DMs. Examples: '#all', '#general', 'DM:@richard'."
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 ({ channel, dm_to, content }) => {
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({ channel, dm_to, content })
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 ${channel || `new DM with ${dm_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-name] or [DM:@peer-name] followed by the sender and content.",
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 channel = m.channel_type === "dm" ? `DM:@${m.channel_name}` : `#${m.channel_name}`;
100
- const senderPrefix = m.sender_type === "agent" ? "(agent) " : "";
101
- const time = m.timestamp ? ` (${toLocalTime(m.timestamp)})` : "";
102
- return `[${channel}]${time} ${senderPrefix}@${m.sender_name}: ${m.content}`;
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(dm_to="<name>"). To reply in an existing DM: reuse channel from the received message.\n';
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 DM. Use #channel-name for channels or DM:@name for DMs. Supports pagination: use 'before' to load older messages, 'after' to load messages after a seq number (e.g. to catch up on unread).",
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 channel to read history from \u2014 e.g. '#all', '#general', 'DM:@richard'"),
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 senderPrefix = m.senderType === "agent" ? "(agent) " : "";
205
- const time = m.createdAt ? ` (${toLocalTime(m.createdAt)})` : "";
206
- return `[seq:${m.seq}]${time} ${senderPrefix}@${m.senderName}: ${m.content}`;
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 path3 from "path";
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 path2 from "path";
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 look like:
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
- The \`[...]\` prefix identifies where the message came from. Reuse it as the \`channel\` parameter when replying.
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(channel="#channel-name", content="...")\`
156
- - **Reply to a DM**: \`send_message(channel="DM:@peer-name", content="...")\` \u2014 reuse the channel value from the received message
157
- - **Start a NEW DM**: \`send_message(dm_to="peer-name", content="...")\` \u2014 use the human's name from list_server (no @ prefix)
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
- **IMPORTANT**: To reply to any message (channel or DM), always use \`channel\` with the exact identifier from the received message. Only use \`dm_to\` when you want to start a brand new DM that doesn't exist yet.
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="DM:@peer-name")\`
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
- mcpConfig,
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 path from "path";
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 = path.join(ctx.workingDirectory, ".git");
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 = path2.join(os.homedir(), ".slock", "agents");
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 = path2.join(DATA_DIR, agentId);
769
+ const agentDataDir = path3.join(DATA_DIR, agentId);
745
770
  await mkdir(agentDataDir, { recursive: true });
746
- const memoryMdPath = path2.join(agentDataDir, "MEMORY.md");
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(path2.join(agentDataDir, "notes"), { recursive: true });
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 = path2.join(DATA_DIR, agentId);
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 = path2.join(DATA_DIR, entry.name);
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 = path2.join(dirPath, item.name);
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 = path2.join(DATA_DIR, directoryName);
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 = path2.join(DATA_DIR, agentId);
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 = path2.resolve(agentDir, dirPath);
1028
- if (!resolved.startsWith(agentDir + path2.sep) && resolved !== 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 = path2.join(DATA_DIR, agentId);
1037
- const resolved = path2.resolve(agentDir, filePath);
1038
- if (!resolved.startsWith(agentDir + path2.sep) && resolved !== 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 = path2.extname(resolved).toLowerCase();
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
- activity = "online";
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 = path2.join(dir, entry.name);
1177
- const relativePath = path2.relative(rootDir, fullPath);
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 = path3.dirname(fileURLToPath(import.meta.url));
1229
- var chatBridgePath = path3.resolve(__dirname, "chat-bridge.js");
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 = path3.resolve(__dirname, "chat-bridge.ts");
1305
+ chatBridgePath = path4.resolve(__dirname, "chat-bridge.ts");
1234
1306
  }
1235
1307
  var connection;
1236
1308
  var agentManager = new AgentProcessManager(chatBridgePath, (msg) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@slock-ai/daemon",
3
- "version": "0.12.0",
3
+ "version": "0.14.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "slock-daemon": "dist/index.js"