@warble/claude-agent-sdk 0.17.0 → 0.18.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/README.md CHANGED
@@ -111,7 +111,11 @@ owned by the current user, with no group or other permission bits (`chmod 600`).
111
111
  `[a-z0-9_]{1,32}`, `tools` is a non-empty list of `[a-z0-9_]{1,64}`, `instruction` is one line of at
112
112
  most 300 characters, and unknown keys are rejected. The server is passed to `query()` as a stdio
113
113
  `mcpServers` entry; the read-only guardrail then allows exactly `mcp__<name>__<tool>` for the listed
114
- tools and still refuses every other `mcp__*` tool, and the `wren`-only Bash rule is unchanged. Keep
114
+ tools and still refuses every other `mcp__*` tool, and the `wren`-only Bash rule is unchanged. In a
115
+ per-step-tier split the steps run as subagents with an exhaustive tool list, so every subagent that
116
+ has `Bash` (the data-access ones) also gets the listed host tools and the instruction line. That
117
+ includes the subagents of a setup or mutating component with data access: the guardrail allows the
118
+ listed host tools by exact name in every component, as it already did for the driver. Keep
115
119
  secrets out of this file — pass a token file path in `args` instead; the CLI never prints the file,
116
120
  its `args`, or the environment. Hybrid-staged plans refuse the flag. Without it, `chat` behaves
117
121
  exactly as before.
@@ -138,7 +138,7 @@ function makeReadOnlyGuard(cfg: {
138
138
  const denials: Denial[] = [];
139
139
  const hooks: never[] = [];
140
140
  const canUseTool = async (toolName: string, input: Record<string, unknown>) => {
141
- if (toolName === "Read" || toolName === "Task" || toolName === "TodoWrite") {
141
+ if (toolName === "Read" || toolName === "Task" || toolName === "Agent" || toolName === "TodoWrite") {
142
142
  return { behavior: "allow" as const, updatedInput: input };
143
143
  }
144
144
  if (toolName === "Bash") {
@@ -2121,12 +2121,17 @@ import { resolve as resolvePath, sep as pathSep } from "path";
2121
2121
  function withinScope(abs, scopeAbs) {
2122
2122
  return abs === scopeAbs || abs.startsWith(scopeAbs.endsWith(pathSep) ? scopeAbs : scopeAbs + pathSep);
2123
2123
  }
2124
+ var OUT_OF_BAND_DENIAL = {
2125
+ behavior: "deny",
2126
+ message: "the embedding host answered this permission request out-of-band, which the guardrail cannot compose with"
2127
+ };
2124
2128
  function composeCanUseTool(embedder, floor) {
2125
2129
  if (embedder === void 0) return floor;
2126
2130
  return async (toolName, input, options) => {
2127
2131
  const fromEmbedder = await embedder(toolName, input, options);
2132
+ if (fromEmbedder === null) return OUT_OF_BAND_DENIAL;
2128
2133
  if (fromEmbedder.behavior !== "allow") return fromEmbedder;
2129
- return floor(toolName, fromEmbedder.updatedInput, options);
2134
+ return floor(toolName, fromEmbedder.updatedInput ?? input, options);
2130
2135
  };
2131
2136
  }
2132
2137
  function composeHooks(embedder, guardHooks) {
@@ -2191,7 +2196,7 @@ function makeReadOnlyGuard(cfg) {
2191
2196
  }
2192
2197
  return allow(input);
2193
2198
  }
2194
- if (toolName === "Task" || toolName === "TodoWrite") {
2199
+ if (toolName === "Task" || toolName === "Agent" || toolName === "TodoWrite") {
2195
2200
  return allow(input);
2196
2201
  }
2197
2202
  if (toolName === "Bash") {
@@ -2627,7 +2632,7 @@ var ChatEventMapper = class {
2627
2632
  return [{ t: "step_start", id: this.stepId, name: this.stepId, parent: null, depth: 0 }];
2628
2633
  }
2629
2634
  onAssistant(message) {
2630
- const content = message.message?.content;
2635
+ const content = isRecord(message.message) ? message.message["content"] : void 0;
2631
2636
  if (!Array.isArray(content)) return [];
2632
2637
  const parent = message.parent_tool_use_id ?? null;
2633
2638
  const depth = parent ? 1 : 0;
@@ -2648,7 +2653,7 @@ var ChatEventMapper = class {
2648
2653
  return events;
2649
2654
  }
2650
2655
  onUser(message) {
2651
- const content = message.message?.content;
2656
+ const content = isRecord(message.message) ? message.message["content"] : void 0;
2652
2657
  if (!Array.isArray(content)) return [];
2653
2658
  const events = [];
2654
2659
  for (const block of content) {
@@ -2720,6 +2725,20 @@ function applyHostMcp(options, hostMcp) {
2720
2725
  next.systemPrompt = `${options.systemPrompt}
2721
2726
  ${hostMcp.instruction}`;
2722
2727
  }
2728
+ if (options.agents !== void 0) {
2729
+ const hostTools = hostMcpToolNames(hostMcp);
2730
+ next.agents = Object.fromEntries(
2731
+ Object.entries(options.agents).map(([name, agent]) => {
2732
+ if (!agent.tools?.includes("Bash")) return [name, agent];
2733
+ return [name, {
2734
+ ...agent,
2735
+ tools: [...agent.tools, ...hostTools],
2736
+ ...hostMcp.instruction !== void 0 ? { prompt: `${agent.prompt}
2737
+ ${hostMcp.instruction}` } : {}
2738
+ }];
2739
+ })
2740
+ );
2741
+ }
2723
2742
  return next;
2724
2743
  }
2725
2744
  var DispatchSessionError = class extends DispatchError {
@@ -3716,7 +3735,7 @@ function componentStepSystemPrompt(run) {
3716
3735
  function componentTools(component) {
3717
3736
  const configured = component.plan.options.tools;
3718
3737
  if (!Array.isArray(configured)) return ["Read"];
3719
- return configured.filter((name) => name !== "Task" && name !== "Write" && name !== "Edit");
3738
+ return configured.filter((name) => name !== "Task" && name !== "Agent" && name !== "Write" && name !== "Edit");
3720
3739
  }
3721
3740
  function createSdkComponentStepRunner(cfg = {}) {
3722
3741
  const denials = [];
@@ -3764,7 +3783,8 @@ function createSdkComponentStepRunner(cfg = {}) {
3764
3783
  if (!toolNames.has(name)) return originalCanUseTool(name, input, options2);
3765
3784
  if (!cfg.hostCanUseTool) return { behavior: "allow", updatedInput: input };
3766
3785
  const permission = await cfg.hostCanUseTool(name, input, options2);
3767
- if (permission.behavior === "allow") rememberApproval(name, permission.updatedInput);
3786
+ if (permission === null) return OUT_OF_BAND_DENIAL;
3787
+ if (permission.behavior === "allow") rememberApproval(name, permission.updatedInput ?? input);
3768
3788
  return permission;
3769
3789
  };
3770
3790
  const componentCalls = run.aliases.map((alias) => tool2(
@@ -3775,14 +3795,16 @@ function createSdkComponentStepRunner(cfg = {}) {
3775
3795
  const name = `mcp__${MCP_SERVER_NAME2}__${alias}`;
3776
3796
  let input = { request: args.request, input: args.input ?? {} };
3777
3797
  if (cfg.hostCanUseTool && !consumeApproval(name, input)) {
3798
+ const toolUseID = `${run.rootRunId}:${run.callId ?? "root"}:${run.step.name}:${alias}`;
3778
3799
  const permission = await cfg.hostCanUseTool(name, input, {
3779
3800
  signal: run.signal,
3780
- toolUseID: `${run.rootRunId}:${run.callId ?? "root"}:${run.step.name}:${alias}`
3801
+ toolUseID,
3802
+ requestId: toolUseID
3781
3803
  });
3782
- if (permission.behavior !== "allow") {
3804
+ if (permission === null || permission.behavior !== "allow") {
3783
3805
  throw new DispatchError("component invocation was denied by the embedding host");
3784
3806
  }
3785
- input = permission.updatedInput;
3807
+ input = permission.updatedInput ?? input;
3786
3808
  }
3787
3809
  const result2 = await run.invoke(alias, input);
3788
3810
  return {
@@ -4662,4 +4684,4 @@ export {
4662
4684
  ChatSession,
4663
4685
  createChatSession
4664
4686
  };
4665
- //# sourceMappingURL=chunk-74JAAZB7.js.map
4687
+ //# sourceMappingURL=chunk-MIW7NT66.js.map