@clawos-dev/clawd 0.2.679 → 0.2.680

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/cli.cjs CHANGED
@@ -57210,7 +57210,8 @@ function writeRpcToolMcpConfig(args) {
57210
57210
  }
57211
57211
  };
57212
57212
  import_node_fs33.default.mkdirSync(args.dataDir, { recursive: true });
57213
- import_node_fs33.default.writeFileSync(cfgPath, JSON.stringify(content, null, 2), "utf8");
57213
+ import_node_fs33.default.writeFileSync(cfgPath, JSON.stringify(content, null, 2), { encoding: "utf8", mode: 384 });
57214
+ import_node_fs33.default.chmodSync(cfgPath, 384);
57214
57215
  return cfgPath;
57215
57216
  }
57216
57217
 
@@ -75335,7 +75336,7 @@ function computeMethodAccess(args) {
75335
75336
  }
75336
75337
 
75337
75338
  // src/version.ts
75338
- var version = "0.2.679".length > 0 ? "0.2.679" : "dev";
75339
+ var version = "0.2.680".length > 0 ? "0.2.680" : "dev";
75339
75340
 
75340
75341
  // src/cli-probe/probe.ts
75341
75342
  var fs86 = __toESM(require("fs"), 1);
@@ -75418,9 +75419,11 @@ function buildReadyFrame(deps, client) {
75418
75419
  };
75419
75420
  }
75420
75421
  function buildMetaHandlers(deps) {
75421
- const info = async () => ({
75422
- response: { type: "info", ...buildReadyFrame(deps) }
75423
- });
75422
+ const info = async (_frame, client) => {
75423
+ const frame = buildReadyFrame(deps);
75424
+ if (client.transport === "http") delete frame.httpToken;
75425
+ return { response: { type: "info", ...frame } };
75426
+ };
75424
75427
  const ping = async () => ({
75425
75428
  response: { type: "pong", at: Date.now() }
75426
75429
  });
@@ -21125,6 +21125,17 @@ function log(msg, extra) {
21125
21125
  } catch {
21126
21126
  }
21127
21127
  }
21128
+ var DEFAULT_TIMEOUT_MS = 6e4;
21129
+ var DEFAULT_MAX_RESULT_CHARS = 6e4;
21130
+ function positiveIntFromEnv(name, fallback) {
21131
+ const n = Number(process.env[name]);
21132
+ return Number.isInteger(n) && n > 0 ? n : fallback;
21133
+ }
21134
+ function truncateResult(text, max) {
21135
+ if (max === void 0 || text.length <= max) return text;
21136
+ return text.slice(0, max) + `
21137
+ \u2026[truncated: ${text.length - max} of ${text.length} chars omitted. Narrow the call: pass \`slim:true\` to history:read, or use limit/offset/cursor where the method supports them.]`;
21138
+ }
21128
21139
  async function handleCallToolCall(input, ctx) {
21129
21140
  const f = ctx.fetch ?? fetch;
21130
21141
  const args = input.args ?? {};
@@ -21142,9 +21153,23 @@ async function handleCallToolCall(input, ctx) {
21142
21153
  "content-type": "application/json",
21143
21154
  authorization: `Bearer ${ctx.daemonToken}`
21144
21155
  },
21145
- body: JSON.stringify(body)
21156
+ body: JSON.stringify(body),
21157
+ signal: AbortSignal.timeout(ctx.timeoutMs ?? DEFAULT_TIMEOUT_MS)
21146
21158
  });
21147
21159
  } catch (err) {
21160
+ if (err instanceof Error && err.name === "TimeoutError") {
21161
+ const secs = Math.round((ctx.timeoutMs ?? DEFAULT_TIMEOUT_MS) / 1e3);
21162
+ log("call timed out", { url, secs });
21163
+ return {
21164
+ content: [
21165
+ {
21166
+ type: "text",
21167
+ text: `RPC timed out after ${secs}s waiting for ${input.method}. The daemon may still be running it \u2014 check the result before retrying a method that writes.`
21168
+ }
21169
+ ],
21170
+ isError: true
21171
+ };
21172
+ }
21148
21173
  const msg = err instanceof Error ? err.message : String(err);
21149
21174
  log("call fetch threw", { url, msg });
21150
21175
  return {
@@ -21170,9 +21195,27 @@ async function handleCallToolCall(input, ctx) {
21170
21195
  };
21171
21196
  }
21172
21197
  log("call ok", { url });
21173
- return { content: [{ type: "text", text: JSON.stringify(json.result) }] };
21198
+ return { content: [{ type: "text", text: truncateResult(JSON.stringify(json.result), ctx.maxResultChars) }] };
21174
21199
  }
21175
- async function handleListToolCall(ctx) {
21200
+ var SUMMARY_MAX_CHARS = 100;
21201
+ function summarize(description) {
21202
+ const end = description.search(/。|\. |\n/);
21203
+ const first = end === -1 ? description : description.slice(0, end + (description[end] === "." ? 1 : 0));
21204
+ return first.length > SUMMARY_MAX_CHARS ? first.slice(0, SUMMARY_MAX_CHARS) + "\u2026" : first;
21205
+ }
21206
+ async function handleListToolCall(callerCtx, opts = {}) {
21207
+ const ctx = { ...callerCtx, maxResultChars: void 0 };
21208
+ if (opts.method) {
21209
+ const one = await handleCallToolCall({ method: "meta:methods", args: { method: opts.method } }, ctx);
21210
+ if (one.isError) return one;
21211
+ try {
21212
+ const entry = JSON.parse(one.content[0].text).methods[0];
21213
+ if (!entry) throw new Error("empty");
21214
+ return { content: [{ type: "text", text: JSON.stringify(entry, null, 2) }] };
21215
+ } catch {
21216
+ return { content: [{ type: "text", text: "meta:methods returned an unexpected shape" }], isError: true };
21217
+ }
21218
+ }
21176
21219
  const raw = await handleCallToolCall({ method: "meta:methods" }, ctx);
21177
21220
  if (raw.isError) return raw;
21178
21221
  let methods;
@@ -21181,6 +21224,13 @@ async function handleListToolCall(ctx) {
21181
21224
  } catch {
21182
21225
  return { content: [{ type: "text", text: "meta:methods returned an unexpected shape" }], isError: true };
21183
21226
  }
21227
+ if (opts.prefix) {
21228
+ const prefix = opts.prefix;
21229
+ methods = methods.filter((m) => m.name.startsWith(prefix));
21230
+ if (methods.length === 0) {
21231
+ return { content: [{ type: "text", text: `No methods start with "${prefix}". Call list with no arguments to see all.` }] };
21232
+ }
21233
+ }
21184
21234
  return { content: [{ type: "text", text: formatMethodList(methods) }] };
21185
21235
  }
21186
21236
  function formatMethodList(methods) {
@@ -21199,7 +21249,7 @@ function formatMethodList(methods) {
21199
21249
  for (const [reason, group2] of byReason) {
21200
21250
  if (reason) lines.push(`(${reason})`);
21201
21251
  for (const m of group2) {
21202
- lines.push(m.description ? `- ${m.name} \u2014 ${m.description}` : `- ${m.name}`);
21252
+ lines.push(m.description ? `- ${m.name} \u2014 ${summarize(m.description)}` : `- ${m.name}`);
21203
21253
  if (m.args && m.args.length > 0) {
21204
21254
  lines.push(` args: ${m.args.map((a) => a.required ? `${a.name}*` : a.name).join(", ")}`);
21205
21255
  } else if (m.args === null) {
@@ -21211,35 +21261,42 @@ function formatMethodList(methods) {
21211
21261
  }
21212
21262
  lines.push("");
21213
21263
  }
21214
- lines.push("Call any of these with the `call` tool: call({ method, args }). `*` marks required args.");
21264
+ lines.push(
21265
+ "Call any of these with the `call` tool: call({ method, args }). `*` marks required args. Descriptions are shortened here: list({ method }) returns one method in full with its args schema."
21266
+ );
21215
21267
  return lines.join("\n");
21216
21268
  }
21217
21269
  async function main() {
21218
21270
  const daemonUrl = process.env.CLAWD_DAEMON_URL;
21219
21271
  const daemonToken = process.env.CLAWD_DAEMON_TOKEN;
21220
21272
  const sessionId = process.env.CLAWD_SESSION_ID;
21221
- log("boot", { pid: process.pid, hasSessionId: Boolean(sessionId), logPath: RPC_LOG ?? "(stderr)" });
21273
+ const timeoutMs = positiveIntFromEnv("CLAWD_RPC_TIMEOUT_MS", DEFAULT_TIMEOUT_MS);
21274
+ const maxResultChars = positiveIntFromEnv("CLAWD_RPC_MAX_RESULT_CHARS", DEFAULT_MAX_RESULT_CHARS);
21275
+ log("boot", { pid: process.pid, hasSessionId: Boolean(sessionId), logPath: RPC_LOG ?? "(stderr)", timeoutMs, maxResultChars });
21222
21276
  const server = new McpServer({ name: "clawd-rpc", version: "0.1.0" });
21223
21277
  server.registerTool(
21224
21278
  "call",
21225
21279
  {
21226
21280
  title: "Call a clawd daemon RPC method",
21227
- description: 'Call a clawd daemon RPC method over the authenticated local channel. `method` is the canonical method name (e.g. "attachment.signUrl", "persona:list", "session:list"); `args` is the JSON body for that method. sessionId is auto-filled from this session unless explicitly provided in args. The daemon is the sole authority on method existence and authorization \u2014 unknown methods or missing permissions surface as errors from the daemon.',
21281
+ description: 'Call a clawd daemon RPC method over the authenticated local channel. `method` is the canonical method name (e.g. "attachment.signUrl", "persona:list", "session:list"); `args` is the JSON body for that method. sessionId is auto-filled from this session unless explicitly provided in args. The daemon is the sole authority on method existence and authorization \u2014 unknown methods or missing permissions surface as errors from the daemon. Gives up after the timeout, and long results are truncated with a hint to narrow the call.',
21228
21282
  inputSchema: {
21229
21283
  method: external_exports.string().min(1).describe('canonical RPC method name, e.g. "persona:list"'),
21230
21284
  args: external_exports.record(external_exports.unknown()).optional().describe("JSON arguments for the method")
21231
21285
  }
21232
21286
  },
21233
- async (input) => handleCallToolCall(input, { daemonUrl, daemonToken, sessionId })
21287
+ async (input) => handleCallToolCall(input, { daemonUrl, daemonToken, sessionId, timeoutMs, maxResultChars })
21234
21288
  );
21235
21289
  server.registerTool(
21236
21290
  "list",
21237
21291
  {
21238
21292
  title: "List callable clawd daemon RPC methods",
21239
- description: "List every RPC method this daemon exposes, grouped by whether THIS connection can call it. Use it before guessing a method name \u2014 the daemon has 100+ methods and `call` does no local validation. Takes no arguments.",
21240
- inputSchema: {}
21293
+ description: 'List the RPC methods this daemon exposes, grouped by whether THIS connection can call it, one shortened line per method. The daemon has 100+ methods and `call` does no local validation, so prefer `prefix` (e.g. "session:") to narrow the list, and `method` to get one method in full with its args schema. With no arguments it lists everything.',
21294
+ inputSchema: {
21295
+ prefix: external_exports.string().min(1).optional().describe('only methods whose name starts with this, e.g. "session:"'),
21296
+ method: external_exports.string().min(1).optional().describe("one exact method name: returns its full description and args schema")
21297
+ }
21241
21298
  },
21242
- async () => handleListToolCall({ daemonUrl, daemonToken, sessionId })
21299
+ async (input) => handleListToolCall({ daemonUrl, daemonToken, sessionId, timeoutMs }, input)
21243
21300
  );
21244
21301
  await server.connect(new StdioServerTransport());
21245
21302
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clawos-dev/clawd",
3
- "version": "0.2.679",
3
+ "version": "0.2.680",
4
4
  "description": "Standalone clawd daemon — Claude Code (and future Codex) session server over WebSocket",
5
5
  "type": "module",
6
6
  "license": "MIT",