@yanlinglabs/winter-agent-sdk 0.0.32 → 0.0.34

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/index.d.ts CHANGED
@@ -3,7 +3,7 @@ export type { Query, SdkMessage, SessionMessagingFacet } from "./query.js";
3
3
  export type { QueryInternal, ControlRequestHandler, ControlRequestHandlerResult } from "./query.js";
4
4
  export type { Options } from "./options.js";
5
5
  export { SYSTEM_PROMPT_DYNAMIC_BOUNDARY, DEFAULT_CONTEXT_WINDOW_TOKENS, DEFAULT_COMPACTION_THRESHOLD, DEFAULT_PLANS_DIRECTORY, DEFAULT_OUTPUT_STYLE } from "./options.js";
6
- export { DEFAULT_PROVIDER_STALL_TIMEOUT_MS, DEFAULT_KEYCHAIN_SERVICE, MCP_OAUTH_REFRESH_SUBTYPE, CREDENTIAL_RESOLVE_SUBTYPE } from "./options.js";
6
+ export { DEFAULT_PROVIDER_STALL_TIMEOUT_MS, DEFAULT_KEYCHAIN_SERVICE, TEST_KEYCHAIN_ENV, TEST_KEYCHAIN_MEMORY, MCP_OAUTH_REFRESH_SUBTYPE, CREDENTIAL_RESOLVE_SUBTYPE } from "./options.js";
7
7
  export { WEB_TOOLS_DEFAULTS, resolveWebToolsConfig } from "./options.js";
8
8
  export type { ResolvedWebToolsConfig } from "./options.js";
9
9
  export type { WebToolsConfig, WebSearchConfig, WebFetchConfig, WebPrivateAddressPolicy, AutoMemoryConfig } from "./protocol/config.js";
@@ -50,9 +50,9 @@ export type { SettingSource, ResolvedSettingSource, PolicySettingsOrigin, Settin
50
50
  export type { WorkspaceTrustFilterOptions } from "./settings/resolve.js";
51
51
  export type { PermissionMode, PermissionBehavior, PermissionRuleValue } from "./permissions/types.js";
52
52
  export type { PermissionUpdate, PermissionUpdateDestination, RuleSource } from "./permissions/types.js";
53
- export type { CanUseTool, PermissionResult, PermissionDecisionClassification, PermissionRequestPayload } from "./permissions/types.js";
53
+ export type { CanUseTool, McpServerIdentity, PermissionResult, PermissionDecisionClassification, PermissionRequestPayload } from "./permissions/types.js";
54
54
  export { HOOK_EVENTS } from "./permissions/types.js";
55
- export type { HookEvent, HookEventName, HookSource, HookPermissionDecision, BaseHookInput, McpToolProvenance, PreToolUseHookInput, PostToolUseHookInput, PostToolUseFailureHookInput, UserPromptSubmitHookInput, StopHookInput, SessionStartHookInput, SessionEndHookInput, NotificationHookInput, PermissionRequestHookInput, PermissionDeniedHookInput, SubagentStartHookInput, SubagentStopHookInput, GenericHookInput, HookInput, AsyncHookJSONOutput, SyncHookJSONOutput, HookJSONOutput, PreToolUseHookSpecificOutput, PostToolUseHookSpecificOutput, PostToolUseFailureHookSpecificOutput, UserPromptSubmitHookSpecificOutput, StopHookSpecificOutput, SubagentStartHookSpecificOutput, SubagentStopHookSpecificOutput, SessionStartHookSpecificOutput, NotificationHookSpecificOutput, PermissionRequestHookSpecificOutput, PermissionDeniedHookSpecificOutput, GenericHookSpecificOutput, HookSpecificOutput, HookCallback, HookCallbackMatcher, HookInvocationPayload, } from "./permissions/types.js";
55
+ export type { HookEvent, HookEventName, HookSource, HookPermissionDecision, BaseHookInput, McpToolProvenance, WinterMcpServerHookField, PreToolUseHookInput, PostToolUseHookInput, PostToolUseFailureHookInput, UserPromptSubmitHookInput, StopHookInput, SessionStartHookInput, SessionEndHookInput, NotificationHookInput, PermissionRequestHookInput, PermissionDeniedHookInput, SubagentStartHookInput, SubagentStopHookInput, GenericHookInput, HookInput, AsyncHookJSONOutput, SyncHookJSONOutput, HookJSONOutput, PreToolUseHookSpecificOutput, PostToolUseHookSpecificOutput, PostToolUseFailureHookSpecificOutput, UserPromptSubmitHookSpecificOutput, StopHookSpecificOutput, SubagentStartHookSpecificOutput, SubagentStopHookSpecificOutput, SessionStartHookSpecificOutput, NotificationHookSpecificOutput, PermissionRequestHookSpecificOutput, PermissionDeniedHookSpecificOutput, GenericHookSpecificOutput, HookSpecificOutput, HookCallback, HookCallbackMatcher, HookInvocationPayload, } from "./permissions/types.js";
56
56
  export { CATALOG_TAG_RENAMES } from "@yanlinglabs/winter-provider-catalog";
57
57
  export { PluginManagerError, listMarketplaces, addMarketplace, removeMarketplace, updateMarketplace, installPlugin, uninstallPlugin, setPluginEnabled, updatePlugin, listPlugins } from "./plugins/manage.js";
58
58
  export type { PluginScope, PluginManagerOptions, MarketplaceInfo, InstalledPlugin, PluginListing } from "./plugins/manage.js";
package/dist/index.js CHANGED
@@ -66,6 +66,8 @@ var DEFAULT_PLANS_DIRECTORY = `${WINTER_BRAND2.projectDirName}/plans`;
66
66
  var DEFAULT_OUTPUT_STYLE = "default";
67
67
  var DEFAULT_PROVIDER_STALL_TIMEOUT_MS = 120000;
68
68
  var DEFAULT_KEYCHAIN_SERVICE = WINTER_BRAND2.keychainService;
69
+ var TEST_KEYCHAIN_ENV = "WINTER_TEST_KEYCHAIN";
70
+ var TEST_KEYCHAIN_MEMORY = "memory";
69
71
  var MCP_OAUTH_REFRESH_SUBTYPE = "mcp_oauth_refresh";
70
72
  var CREDENTIAL_RESOLVE_SUBTYPE = "credential_resolve";
71
73
  var WEB_TOOLS_DEFAULTS = {
@@ -448,13 +450,17 @@ function makeSdkMcpCallHandler(mcpServers) {
448
450
  };
449
451
  }
450
452
  function makeElicitationHandler(onElicitation, abortController) {
451
- return async (payload) => {
453
+ return async (payload, handlerCtx) => {
452
454
  const req = payload;
453
455
  const controller = new AbortController;
454
456
  if (abortController?.signal.aborted)
455
457
  controller.abort();
456
458
  else
457
459
  abortController?.signal.addEventListener("abort", () => controller.abort(), { once: true });
460
+ if (handlerCtx?.signal.aborted === true)
461
+ controller.abort();
462
+ else
463
+ handlerCtx?.signal.addEventListener("abort", () => controller.abort(), { once: true });
458
464
  let result;
459
465
  try {
460
466
  result = await onElicitation({
@@ -565,6 +571,9 @@ function buildRuntimeHooksConfig(hooks) {
565
571
  }
566
572
  return Object.keys(out).length > 0 ? out : undefined;
567
573
  }
574
+ function winterMcpServerHookField(server) {
575
+ return { name: server.name, config_name: server.configName, ...server.readOnlyHint !== undefined ? { read_only_hint: server.readOnlyHint } : {} };
576
+ }
568
577
  function buildHookInput(req, cwd) {
569
578
  const payload = req.payload ?? {};
570
579
  return {
@@ -576,6 +585,7 @@ function buildHookInput(req, cwd) {
576
585
  ...req.toolName !== undefined ? { tool_name: req.toolName } : {},
577
586
  ...req.mcpServerName !== undefined ? { mcp_server_name: req.mcpServerName } : {},
578
587
  ...req.mcpToolName !== undefined ? { mcp_tool_name: req.mcpToolName } : {},
588
+ ...req.mcpServer !== undefined ? { winter_mcp_server: winterMcpServerHookField(req.mcpServer) } : {},
579
589
  ...req.input !== undefined ? { tool_input: req.input } : {},
580
590
  ...req.toolUseID !== undefined ? { tool_use_id: req.toolUseID } : {},
581
591
  ...payload
@@ -722,7 +732,7 @@ function query(args) {
722
732
  command,
723
733
  args: ["--run", "--config-json", JSON.stringify(config)],
724
734
  cwd: config.cwd,
725
- env: options.env ?? process.env,
735
+ env: withTestKeychainRedirect(options.env) ?? process.env,
726
736
  ...options.abortController ? { signal: options.abortController.signal } : {}
727
737
  };
728
738
  const proc = (options.spawnClaudeCodeProcess ?? defaultSpawn)(spawnOptions);
@@ -810,7 +820,8 @@ function query(args) {
810
820
  toolUseID: req.toolUseID,
811
821
  ...req.agentID !== undefined ? { agentID: req.agentID } : {},
812
822
  requestId: req.requestId,
813
- ...req.matchedAskRule !== undefined ? { matchedAskRule: req.matchedAskRule } : {}
823
+ ...req.matchedAskRule !== undefined ? { matchedAskRule: req.matchedAskRule } : {},
824
+ ...req.mcpServer !== undefined ? { mcpServer: req.mcpServer } : {}
814
825
  });
815
826
  } catch (err) {
816
827
  const message = err instanceof Error ? err.message : String(err);
@@ -1118,8 +1129,14 @@ function query(args) {
1118
1129
  };
1119
1130
  return gen;
1120
1131
  }
1132
+ function withTestKeychainRedirect(env) {
1133
+ const redirect = process.env[TEST_KEYCHAIN_ENV];
1134
+ if (env === undefined || redirect === undefined || redirect === "" || env[TEST_KEYCHAIN_ENV] !== undefined)
1135
+ return env;
1136
+ return { ...env, [TEST_KEYCHAIN_ENV]: redirect };
1137
+ }
1121
1138
  // src/version.ts
1122
- var SDK_VERSION = "0.0.32";
1139
+ var SDK_VERSION = "0.0.34";
1123
1140
  // src/paths/project-key.ts
1124
1141
  var TRANSCRIPT_PROJECT_KEY_MAX_LENGTH = 64;
1125
1142
  var VENDOR_PROJECT_KEY_PATTERN = /^[A-Za-z0-9_-]{1,64}$/;
@@ -2314,6 +2331,8 @@ export {
2314
2331
  SETTING_SOURCES,
2315
2332
  SYSTEM_PROMPT_DYNAMIC_BOUNDARY,
2316
2333
  SessionNotFoundError,
2334
+ TEST_KEYCHAIN_ENV,
2335
+ TEST_KEYCHAIN_MEMORY,
2317
2336
  TRANSCRIPT_PROJECT_KEY_MAX_LENGTH,
2318
2337
  WEB_TOOLS_DEFAULTS,
2319
2338
  WINTER_BRAND2 as WINTER_BRAND,
package/dist/options.d.ts CHANGED
@@ -15,6 +15,28 @@ export declare const DEFAULT_PLANS_DIRECTORY: string;
15
15
  export declare const DEFAULT_OUTPUT_STYLE = "default";
16
16
  export declare const DEFAULT_PROVIDER_STALL_TIMEOUT_MS = 120000;
17
17
  export declare const DEFAULT_KEYCHAIN_SERVICE: string;
18
+ /**
19
+ * TEST-ONLY. The environment variable that redirects every DEFAULT secrets backend (the runtime's
20
+ * `provider/keychain-store.ts`, the one site that may reach the macOS Keychain) to a per-process
21
+ * in-memory store. Exactly `TEST_KEYCHAIN_MEMORY` enables the redirect; unset or empty leaves the real
22
+ * Keychain; any other value is REFUSED (a typed `io` credential error, which stops the store stack),
23
+ * never a silent fall through to the real store or to "no credential". The first time the in-memory
24
+ * store engages, the process prints one stderr line saying so.
25
+ *
26
+ * WHY. A test that resolves a `{ kind: "keychain" }` ref in a process that was handed no store of its
27
+ * own (a real `winter` child, an embedded Worker) reached the developer's REAL login Keychain -- service
28
+ * `DEFAULT_KEYCHAIN_SERVICE` by default -- and macOS raised a consent dialog, which also hung the child. Every
29
+ * `bun test` run sets this through `scripts/test-keychain-guard.ts` (each package's `bunfig.toml`), and
30
+ * `query()` carries it into the child's environment even when a host supplies an explicit `env`.
31
+ *
32
+ * Honoured by a compiled binary too, deliberately: the compiled legs of the test suite run the
33
+ * release-shaped artifact, and a build that ignored the variable would put exactly those legs back on
34
+ * the real Keychain. Left on by accident it fails CLOSED -- credentials read as absent, writes vanish
35
+ * with the process -- and it exposes nothing. Never set it outside a test run.
36
+ */
37
+ export declare const TEST_KEYCHAIN_ENV = "WINTER_TEST_KEYCHAIN";
38
+ /** The one value of `TEST_KEYCHAIN_ENV` that selects the in-memory backend. */
39
+ export declare const TEST_KEYCHAIN_MEMORY = "memory";
18
40
  /**
19
41
  * WS-25 (MCP OAuth): the runtime -> host control subtype a session sends when a stored MCP sign-in needs
20
42
  * refreshing (`McpOAuthRefreshRequest` -> `McpOAuthRefreshAnswer`, protocol/config.ts). Spelled once:
@@ -34,6 +34,31 @@ export type PermissionUpdate = {
34
34
  };
35
35
  export type PermissionUpdateDestination = "userSettings" | "projectSettings" | "localSettings" | "session" | "cliArg";
36
36
  export type RuleSource = "managed" | "user" | "project" | "local" | "cliArg" | "session" | "sdk";
37
+ /**
38
+ * WS-27 (Winter-only): WHICH MCP SERVER a tool call is for, stated exactly by the runtime -- on
39
+ * `canUseTool`'s options as `mcpServer`, and on the PreToolUse / PostToolUse / PostToolUseFailure hook
40
+ * input as `winter_mcp_server` (`WinterMcpServerHookField`, the same facts in snake_case). Present when
41
+ * the tool belongs to a connected MCP server (a stdio/http/sse server, or a host's in-process `sdk` one);
42
+ * absent for every other tool, and on an older runtime -- a host keeps its own resolver as the fallback.
43
+ *
44
+ * - `name`: the server's name as it appears in the tool name `mcp__<name>__<tool>` -- AFTER any rename.
45
+ * A subagent definition's inline server that collides with a name already in use is connected under a
46
+ * fresh one (`cf` -> `cf_2`); `name` is then `cf_2`.
47
+ * - `configName`: the key the server had in the config it came from, BEFORE any rename (`cf` above);
48
+ * equal to `name` when nothing was renamed. For a plugin's server, the raw name its `.mcp.json` (or
49
+ * manifest) declares -- the runtime registers plugin servers under exactly that name.
50
+ * - `readOnlyHint`: the tool's own `annotations.readOnlyHint` from that server's `tools/list`, only when
51
+ * the server states it as a boolean. Absent means "not stated", never "false".
52
+ *
53
+ * Why the runtime states it: `mcp__<server>__<tool>` cannot be split reliably (a server name may contain
54
+ * `__`), a rename is invisible in the tool name, and the annotation lives only on the runtime's side of
55
+ * the wire.
56
+ */
57
+ export interface McpServerIdentity {
58
+ name: string;
59
+ configName: string;
60
+ readOnlyHint?: boolean;
61
+ }
37
62
  export type CanUseTool = (toolName: string, input: Record<string, unknown>, options: {
38
63
  signal: AbortSignal;
39
64
  suggestions?: PermissionUpdate[];
@@ -50,6 +75,8 @@ export type CanUseTool = (toolName: string, input: Record<string, unknown>, opti
50
75
  toolName: string;
51
76
  ruleContent?: string;
52
77
  };
78
+ /** WS-27, Winter-only: the MCP server this tool belongs to -- see `McpServerIdentity`. */
79
+ mcpServer?: McpServerIdentity;
53
80
  }) => Promise<PermissionResult | null>;
54
81
  export type PermissionDecisionClassification = "user_temporary" | "user_permanent" | "user_reject";
55
82
  export type PermissionResult = {
@@ -82,6 +109,8 @@ export interface PermissionRequestPayload {
82
109
  toolName: string;
83
110
  ruleContent?: string;
84
111
  };
112
+ /** WS-27: forwarded to `canUseTool` verbatim -- see `McpServerIdentity`. */
113
+ mcpServer?: McpServerIdentity;
85
114
  policyVersion: number;
86
115
  }
87
116
  export declare const HOOK_EVENTS: readonly ["PreToolUse", "PostToolUse", "PostToolUseFailure", "UserPromptSubmit", "Stop", "SubagentStart", "SubagentStop", "PreCompact", "PermissionRequest", "Notification", "PostToolBatch", "UserPromptExpansion", "MessageDisplay", "StopFailure", "PostCompact", "PermissionDenied", "SessionStart", "SessionEnd", "Setup", "TeammateIdle", "TaskCreated", "TaskCompleted", "Elicitation", "ElicitationResult", "ConfigChange", "InstructionsLoaded", "WorktreeCreate", "WorktreeRemove", "CwdChanged", "FileChanged", "DirectoryAdded"];
@@ -105,13 +134,23 @@ export interface McpToolProvenance {
105
134
  mcp_server_name?: string;
106
135
  mcp_tool_name?: string;
107
136
  }
108
- export interface PreToolUseHookInput extends BaseHookInput, McpToolProvenance {
137
+ export interface WinterMcpServerHookField {
138
+ winter_mcp_server?: {
139
+ /** The server's name in the called tool's name `mcp__<name>__<tool>`, after any rename. */
140
+ name: string;
141
+ /** The server's key in the config it came from, before any rename (a plugin server: the raw name its `.mcp.json` declares). */
142
+ config_name: string;
143
+ /** The tool's own `annotations.readOnlyHint` from the server's `tools/list`, only when stated. */
144
+ read_only_hint?: boolean;
145
+ };
146
+ }
147
+ export interface PreToolUseHookInput extends BaseHookInput, McpToolProvenance, WinterMcpServerHookField {
109
148
  hook_event_name: "PreToolUse";
110
149
  tool_name: string;
111
150
  tool_input: unknown;
112
151
  tool_use_id: string;
113
152
  }
114
- export interface PostToolUseHookInput extends BaseHookInput, McpToolProvenance {
153
+ export interface PostToolUseHookInput extends BaseHookInput, McpToolProvenance, WinterMcpServerHookField {
115
154
  hook_event_name: "PostToolUse";
116
155
  tool_name: string;
117
156
  tool_input: unknown;
@@ -119,7 +158,7 @@ export interface PostToolUseHookInput extends BaseHookInput, McpToolProvenance {
119
158
  tool_use_id: string;
120
159
  duration_ms?: number;
121
160
  }
122
- export interface PostToolUseFailureHookInput extends BaseHookInput, McpToolProvenance {
161
+ export interface PostToolUseFailureHookInput extends BaseHookInput, McpToolProvenance, WinterMcpServerHookField {
123
162
  hook_event_name: "PostToolUseFailure";
124
163
  tool_name: string;
125
164
  tool_input: unknown;
@@ -302,6 +341,8 @@ export interface HookInvocationPayload {
302
341
  mcpServerName?: string;
303
342
  /** WS-24: for an MCP tool, the tool's own name on that server -- see `McpToolProvenance`. */
304
343
  mcpToolName?: string;
344
+ /** WS-27: PreToolUse/PostToolUse/PostToolUseFailure only -- becomes `winter_mcp_server`, see `McpServerIdentity`. */
345
+ mcpServer?: McpServerIdentity;
305
346
  input?: Record<string, unknown>;
306
347
  payload?: unknown;
307
348
  policyVersion: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yanlinglabs/winter-agent-sdk",
3
- "version": "0.0.32",
3
+ "version": "0.0.34",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "engines": {
@@ -45,15 +45,15 @@
45
45
  }
46
46
  },
47
47
  "dependencies": {
48
- "@yanlinglabs/winter-provider-catalog": "0.0.32"
48
+ "@yanlinglabs/winter-provider-catalog": "0.0.34"
49
49
  },
50
50
  "optionalDependencies": {
51
- "@yanlinglabs/winter-agent-sdk-darwin-arm64": "0.0.32"
51
+ "@yanlinglabs/winter-agent-sdk-darwin-arm64": "0.0.34"
52
52
  },
53
53
  "devDependencies": {
54
54
  "@types/node": "^26.4.0",
55
- "@yanlinglabs/winter-conformance": "0.0.32",
56
- "@yanlinglabs/winter-agent-runtime": "0.0.32"
55
+ "@yanlinglabs/winter-agent-runtime": "0.0.34",
56
+ "@yanlinglabs/winter-conformance": "0.0.34"
57
57
  },
58
58
  "scripts": {}
59
59
  }