@yanlinglabs/winter-agent-runtime 0.0.27

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.
Files changed (311) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE +41 -0
  3. package/README.md +64 -0
  4. package/dist/checkpoint/file-history.d.ts +81 -0
  5. package/dist/checkpoint/rewind.d.ts +55 -0
  6. package/dist/checkpoint/seam.d.ts +47 -0
  7. package/dist/checkpoint/sink.d.ts +66 -0
  8. package/dist/commands/builtins-listing.d.ts +40 -0
  9. package/dist/commands/resolver.d.ts +103 -0
  10. package/dist/commands/seam.d.ts +53 -0
  11. package/dist/compaction/controller.d.ts +23 -0
  12. package/dist/compaction/retention.d.ts +35 -0
  13. package/dist/compaction/seam.d.ts +115 -0
  14. package/dist/compaction/summarizer.d.ts +79 -0
  15. package/dist/context/agent-listing.d.ts +39 -0
  16. package/dist/context/assembler.d.ts +46 -0
  17. package/dist/context/attachments.d.ts +104 -0
  18. package/dist/context/dynamic-sections.d.ts +31 -0
  19. package/dist/context/git-fixture.d.ts +18 -0
  20. package/dist/context/git-status.d.ts +16 -0
  21. package/dist/context/imports.d.ts +22 -0
  22. package/dist/context/injection.d.ts +53 -0
  23. package/dist/context/memory-key.d.ts +46 -0
  24. package/dist/context/memory.d.ts +28 -0
  25. package/dist/context/minimal-prompt.d.ts +5 -0
  26. package/dist/context/output-styles.d.ts +68 -0
  27. package/dist/context/plan-mode.d.ts +29 -0
  28. package/dist/context/request-layout.d.ts +138 -0
  29. package/dist/context/rules.d.ts +63 -0
  30. package/dist/context/seam.d.ts +136 -0
  31. package/dist/context/tool-epoch.d.ts +118 -0
  32. package/dist/context/winter-code-preset.d.ts +39 -0
  33. package/dist/context/winter-md.d.ts +81 -0
  34. package/dist/embedded-host.d.ts +48 -0
  35. package/dist/embedded-host.js +155 -0
  36. package/dist/embedded-protocol.d.ts +44 -0
  37. package/dist/embedded-worker.d.ts +1 -0
  38. package/dist/embedded-worker.js +74 -0
  39. package/dist/embedded.d.ts +34 -0
  40. package/dist/embedded.js +9 -0
  41. package/dist/engine.d.ts +1298 -0
  42. package/dist/hooks/additional-context.d.ts +21 -0
  43. package/dist/hooks/bounds.d.ts +6 -0
  44. package/dist/hooks/bridge-invoker.d.ts +3 -0
  45. package/dist/hooks/command-invoker.d.ts +52 -0
  46. package/dist/hooks/from-config.d.ts +31 -0
  47. package/dist/hooks/hook-stage.d.ts +25 -0
  48. package/dist/hooks/input-validator.d.ts +6 -0
  49. package/dist/hooks/reducer.d.ts +74 -0
  50. package/dist/hooks/registry.d.ts +33 -0
  51. package/dist/hooks/runner.d.ts +105 -0
  52. package/dist/index-584yahed.js +6037 -0
  53. package/dist/index-97t2rmtf.js +42 -0
  54. package/dist/index-9qgkpv56.js +27183 -0
  55. package/dist/index-bef62z3r.js +437 -0
  56. package/dist/index-rkhh0457.js +187 -0
  57. package/dist/index.d.ts +37 -0
  58. package/dist/index.js +353 -0
  59. package/dist/main.d.ts +1 -0
  60. package/dist/mcp/client.d.ts +105 -0
  61. package/dist/mcp/control-seam.d.ts +25 -0
  62. package/dist/mcp/control.d.ts +5 -0
  63. package/dist/mcp/elicitation.d.ts +35 -0
  64. package/dist/mcp/env.d.ts +12 -0
  65. package/dist/mcp/lifecycle.d.ts +142 -0
  66. package/dist/mcp/output-cap.d.ts +15 -0
  67. package/dist/mcp/state.d.ts +24 -0
  68. package/dist/mcp/test-fixtures.d.ts +88 -0
  69. package/dist/mcp/transports/__fixtures__/stdio-server.d.ts +1 -0
  70. package/dist/mcp/transports/http.d.ts +5 -0
  71. package/dist/mcp/transports/sdk.d.ts +5 -0
  72. package/dist/mcp/transports/sse.d.ts +3 -0
  73. package/dist/mcp/transports/stdio.d.ts +35 -0
  74. package/dist/mcp/winter-server.d.ts +2 -0
  75. package/dist/messaging/reference-adapter.d.ts +88 -0
  76. package/dist/messaging/router.d.ts +8 -0
  77. package/dist/paths/project-dir-name.d.ts +2 -0
  78. package/dist/paths/temp.d.ts +25 -0
  79. package/dist/permissions/approvals.d.ts +107 -0
  80. package/dist/permissions/auto/caches.d.ts +53 -0
  81. package/dist/permissions/auto/config.d.ts +37 -0
  82. package/dist/permissions/auto/engine.d.ts +74 -0
  83. package/dist/permissions/auto/envelope.d.ts +45 -0
  84. package/dist/permissions/auto/inheritance.d.ts +27 -0
  85. package/dist/permissions/edit-recognition.d.ts +30 -0
  86. package/dist/permissions/evaluator.d.ts +284 -0
  87. package/dist/permissions/file-rules.d.ts +384 -0
  88. package/dist/permissions/grammar.d.ts +113 -0
  89. package/dist/permissions/paths.d.ts +32 -0
  90. package/dist/permissions/policy-state.d.ts +64 -0
  91. package/dist/permissions/prompt-stage.d.ts +3 -0
  92. package/dist/permissions/protected.d.ts +54 -0
  93. package/dist/permissions/ruleset.d.ts +134 -0
  94. package/dist/permissions/shell-structure.d.ts +41 -0
  95. package/dist/plugins/bundle.d.ts +100 -0
  96. package/dist/plugins/installed.d.ts +30 -0
  97. package/dist/plugins/loader.d.ts +56 -0
  98. package/dist/plugins/manifest.d.ts +115 -0
  99. package/dist/production-wiring.d.ts +340 -0
  100. package/dist/protocol/channel.d.ts +22 -0
  101. package/dist/provider/advisor-route.d.ts +47 -0
  102. package/dist/provider/bridge.d.ts +124 -0
  103. package/dist/provider/classifier/model-classifier.d.ts +82 -0
  104. package/dist/provider/classifier/prompt.d.ts +62 -0
  105. package/dist/provider/classifier/verdict-schema.d.ts +83 -0
  106. package/dist/provider/credential-api.d.ts +160 -0
  107. package/dist/provider/family-listing.d.ts +27 -0
  108. package/dist/provider/first-party.d.ts +4 -0
  109. package/dist/provider/keychain-store.d.ts +59 -0
  110. package/dist/provider/lean-prompt.d.ts +7 -0
  111. package/dist/provider/mock.d.ts +55 -0
  112. package/dist/provider/scenario-fake.d.ts +96 -0
  113. package/dist/provider/selection.d.ts +115 -0
  114. package/dist/provider/session-provider.d.ts +426 -0
  115. package/dist/provider/slots.d.ts +120 -0
  116. package/dist/provider/stream-frames.d.ts +25 -0
  117. package/dist/provider/tool-secret.d.ts +57 -0
  118. package/dist/rpc/bridge.d.ts +14 -0
  119. package/dist/rpc/mcp-control.d.ts +26 -0
  120. package/dist/runtime.d.ts +14 -0
  121. package/dist/sandbox/profile.d.ts +249 -0
  122. package/dist/sandbox/spawn.d.ts +139 -0
  123. package/dist/settings/env-filter.d.ts +52 -0
  124. package/dist/settings/loaders/hooks.d.ts +44 -0
  125. package/dist/settings/loaders/mcp-config.d.ts +83 -0
  126. package/dist/settings/loaders/plugin-mcp.d.ts +3 -0
  127. package/dist/settings/loaders/strict-plugin-only.d.ts +13 -0
  128. package/dist/settings/resolve.d.ts +2 -0
  129. package/dist/settings/sources.d.ts +2 -0
  130. package/dist/settings/trust.d.ts +36 -0
  131. package/dist/skills/attachment.d.ts +25 -0
  132. package/dist/skills/frontmatter.d.ts +64 -0
  133. package/dist/skills/index.d.ts +16 -0
  134. package/dist/skills/listing.d.ts +89 -0
  135. package/dist/skills/loader.d.ts +104 -0
  136. package/dist/skills/option.d.ts +68 -0
  137. package/dist/skills/permission-rules.d.ts +21 -0
  138. package/dist/skills/runtime.d.ts +21 -0
  139. package/dist/skills/store.d.ts +163 -0
  140. package/dist/store/continuation-attach.d.ts +44 -0
  141. package/dist/store/dialect.d.ts +526 -0
  142. package/dist/store/provider-state.d.ts +188 -0
  143. package/dist/store/resume.d.ts +92 -0
  144. package/dist/structured/ajv-seam.d.ts +7 -0
  145. package/dist/structured/descriptor.d.ts +9 -0
  146. package/dist/structured/seam.d.ts +51 -0
  147. package/dist/structured/validator.d.ts +22 -0
  148. package/dist/subagents/activity.d.ts +13 -0
  149. package/dist/subagents/availability.d.ts +30 -0
  150. package/dist/subagents/builtin-agents.d.ts +37 -0
  151. package/dist/subagents/child-engine.d.ts +198 -0
  152. package/dist/subagents/child-handle.d.ts +344 -0
  153. package/dist/subagents/definitions.d.ts +189 -0
  154. package/dist/subagents/fork.d.ts +55 -0
  155. package/dist/subagents/git-root.d.ts +1 -0
  156. package/dist/subagents/limits.d.ts +28 -0
  157. package/dist/subagents/notification-queue.d.ts +233 -0
  158. package/dist/subagents/plugin-agents.d.ts +5 -0
  159. package/dist/subagents/policy.d.ts +46 -0
  160. package/dist/subagents/register-default-factory.d.ts +66 -0
  161. package/dist/subagents/resolution.d.ts +56 -0
  162. package/dist/subagents/restore.d.ts +9 -0
  163. package/dist/subagents/roster.d.ts +17 -0
  164. package/dist/subagents/test-fakes.d.ts +12 -0
  165. package/dist/subagents/tool-pools.d.ts +69 -0
  166. package/dist/subagents/watchdog.d.ts +13 -0
  167. package/dist/subagents/workspace.d.ts +27 -0
  168. package/dist/testing.d.ts +5 -0
  169. package/dist/testing.js +194 -0
  170. package/dist/tools/background-tasks.d.ts +10 -0
  171. package/dist/tools/descriptors/_shared.d.ts +34 -0
  172. package/dist/tools/descriptors/advisor.d.ts +1 -0
  173. package/dist/tools/descriptors/agent.d.ts +47 -0
  174. package/dist/tools/descriptors/artifact.d.ts +1 -0
  175. package/dist/tools/descriptors/ask-user-question.d.ts +1 -0
  176. package/dist/tools/descriptors/bash.d.ts +20 -0
  177. package/dist/tools/descriptors/claude-design.d.ts +1 -0
  178. package/dist/tools/descriptors/cron-create.d.ts +1 -0
  179. package/dist/tools/descriptors/cron-delete.d.ts +1 -0
  180. package/dist/tools/descriptors/cron-list.d.ts +1 -0
  181. package/dist/tools/descriptors/edit.d.ts +1 -0
  182. package/dist/tools/descriptors/end-conversation.d.ts +1 -0
  183. package/dist/tools/descriptors/enter-plan-mode.d.ts +1 -0
  184. package/dist/tools/descriptors/enter-worktree.d.ts +1 -0
  185. package/dist/tools/descriptors/exit-plan-mode.d.ts +1 -0
  186. package/dist/tools/descriptors/exit-worktree.d.ts +1 -0
  187. package/dist/tools/descriptors/glob.d.ts +1 -0
  188. package/dist/tools/descriptors/grep.d.ts +1 -0
  189. package/dist/tools/descriptors/index.d.ts +59 -0
  190. package/dist/tools/descriptors/list-agents.d.ts +1 -0
  191. package/dist/tools/descriptors/list-mcp-resources-tool.d.ts +1 -0
  192. package/dist/tools/descriptors/lsp.d.ts +1 -0
  193. package/dist/tools/descriptors/monitor.d.ts +1 -0
  194. package/dist/tools/descriptors/notebook-edit.d.ts +1 -0
  195. package/dist/tools/descriptors/powershell.d.ts +1 -0
  196. package/dist/tools/descriptors/projects.d.ts +1 -0
  197. package/dist/tools/descriptors/propose-goal.d.ts +1 -0
  198. package/dist/tools/descriptors/propose-skills.d.ts +1 -0
  199. package/dist/tools/descriptors/push-notification.d.ts +1 -0
  200. package/dist/tools/descriptors/read-mcp-resource-dir-tool.d.ts +1 -0
  201. package/dist/tools/descriptors/read-mcp-resource-tool.d.ts +1 -0
  202. package/dist/tools/descriptors/read-notifications.d.ts +1 -0
  203. package/dist/tools/descriptors/read.d.ts +1 -0
  204. package/dist/tools/descriptors/refresh-mcp-tools.d.ts +1 -0
  205. package/dist/tools/descriptors/remote-trigger.d.ts +1 -0
  206. package/dist/tools/descriptors/repl.d.ts +1 -0
  207. package/dist/tools/descriptors/report-findings.d.ts +1 -0
  208. package/dist/tools/descriptors/schedule-wakeup.d.ts +1 -0
  209. package/dist/tools/descriptors/send-feedback.d.ts +1 -0
  210. package/dist/tools/descriptors/send-message.d.ts +1 -0
  211. package/dist/tools/descriptors/send-user-file.d.ts +1 -0
  212. package/dist/tools/descriptors/share-onboarding-guide.d.ts +1 -0
  213. package/dist/tools/descriptors/show-onboarding-role-picker.d.ts +1 -0
  214. package/dist/tools/descriptors/skill.d.ts +1 -0
  215. package/dist/tools/descriptors/structured-output.d.ts +1 -0
  216. package/dist/tools/descriptors/task-create.d.ts +1 -0
  217. package/dist/tools/descriptors/task-get.d.ts +1 -0
  218. package/dist/tools/descriptors/task-list.d.ts +1 -0
  219. package/dist/tools/descriptors/task-output.d.ts +1 -0
  220. package/dist/tools/descriptors/task-stop.d.ts +1 -0
  221. package/dist/tools/descriptors/task-update.d.ts +1 -0
  222. package/dist/tools/descriptors/todo-write.d.ts +1 -0
  223. package/dist/tools/descriptors/tool-search.d.ts +1 -0
  224. package/dist/tools/descriptors/wait-for-mcp-servers.d.ts +1 -0
  225. package/dist/tools/descriptors/web-fetch.d.ts +8 -0
  226. package/dist/tools/descriptors/web-search.d.ts +15 -0
  227. package/dist/tools/descriptors/winter-list-agents.d.ts +1 -0
  228. package/dist/tools/descriptors/winter-send-message.d.ts +1 -0
  229. package/dist/tools/descriptors/workflow.d.ts +1 -0
  230. package/dist/tools/descriptors/write.d.ts +1 -0
  231. package/dist/tools/impl/_caller.d.ts +14 -0
  232. package/dist/tools/impl/_domains.d.ts +25 -0
  233. package/dist/tools/impl/_exa-client.d.ts +122 -0
  234. package/dist/tools/impl/_exa-session-client.d.ts +23 -0
  235. package/dist/tools/impl/_inner-model.d.ts +135 -0
  236. package/dist/tools/impl/_search-budget.d.ts +36 -0
  237. package/dist/tools/impl/_web-fetch-cache.d.ts +37 -0
  238. package/dist/tools/impl/_web-fetch-html.d.ts +26 -0
  239. package/dist/tools/impl/_web-fetch-net.d.ts +99 -0
  240. package/dist/tools/impl/_web-search-assembler.d.ts +57 -0
  241. package/dist/tools/impl/advisor.d.ts +37 -0
  242. package/dist/tools/impl/agent.d.ts +10 -0
  243. package/dist/tools/impl/ask-user-question.d.ts +5 -0
  244. package/dist/tools/impl/background-task-runtime.d.ts +272 -0
  245. package/dist/tools/impl/bash.d.ts +78 -0
  246. package/dist/tools/impl/cron.d.ts +11 -0
  247. package/dist/tools/impl/edit.d.ts +1 -0
  248. package/dist/tools/impl/enter-plan-mode.d.ts +4 -0
  249. package/dist/tools/impl/enter-worktree.d.ts +25 -0
  250. package/dist/tools/impl/exit-plan-mode.d.ts +4 -0
  251. package/dist/tools/impl/exit-worktree.d.ts +4 -0
  252. package/dist/tools/impl/glob.d.ts +1 -0
  253. package/dist/tools/impl/grep.d.ts +19 -0
  254. package/dist/tools/impl/index.d.ts +37 -0
  255. package/dist/tools/impl/list-agents.d.ts +7 -0
  256. package/dist/tools/impl/list-mcp-resources-tool.d.ts +9 -0
  257. package/dist/tools/impl/monitor.d.ts +66 -0
  258. package/dist/tools/impl/notebook-edit.d.ts +1 -0
  259. package/dist/tools/impl/push-notification.d.ts +4 -0
  260. package/dist/tools/impl/read-ladder.d.ts +25 -0
  261. package/dist/tools/impl/read-mcp-resource-dir-tool.d.ts +9 -0
  262. package/dist/tools/impl/read-mcp-resource-tool.d.ts +9 -0
  263. package/dist/tools/impl/read-notifications.d.ts +5 -0
  264. package/dist/tools/impl/read.d.ts +44 -0
  265. package/dist/tools/impl/refresh-mcp-tools.d.ts +8 -0
  266. package/dist/tools/impl/report-findings.d.ts +1 -0
  267. package/dist/tools/impl/schedule-wakeup.d.ts +2 -0
  268. package/dist/tools/impl/send-message.d.ts +7 -0
  269. package/dist/tools/impl/skill.d.ts +5 -0
  270. package/dist/tools/impl/task-graph.d.ts +1 -0
  271. package/dist/tools/impl/task-output.d.ts +16 -0
  272. package/dist/tools/impl/task-stop.d.ts +11 -0
  273. package/dist/tools/impl/todo-write.d.ts +8 -0
  274. package/dist/tools/impl/tool-search.d.ts +4 -0
  275. package/dist/tools/impl/wait-for-mcp-servers.d.ts +29 -0
  276. package/dist/tools/impl/web-fetch.d.ts +36 -0
  277. package/dist/tools/impl/web-search.d.ts +30 -0
  278. package/dist/tools/impl/workflow.d.ts +5 -0
  279. package/dist/tools/impl/write.d.ts +8 -0
  280. package/dist/tools/paths-seam.d.ts +6 -0
  281. package/dist/tools/read-state.d.ts +12 -0
  282. package/dist/tools/registry.d.ts +423 -0
  283. package/dist/tools/task-graph-store.d.ts +61 -0
  284. package/dist/toolsearch/aliases.d.ts +26 -0
  285. package/dist/toolsearch/exposure.d.ts +30 -0
  286. package/dist/toolsearch/ranking.d.ts +6 -0
  287. package/dist/toolsearch/search.d.ts +45 -0
  288. package/dist/version.d.ts +1 -0
  289. package/dist/version.js +5 -0
  290. package/dist/web/fetchable-url.d.ts +28 -0
  291. package/dist/web/preapproved-hosts.d.ts +52 -0
  292. package/dist/web/private-address.d.ts +55 -0
  293. package/dist/web/session-runtime.d.ts +86 -0
  294. package/dist/workflows/bridge.d.ts +87 -0
  295. package/dist/workflows/budget.d.ts +24 -0
  296. package/dist/workflows/host-registry.d.ts +142 -0
  297. package/dist/workflows/journal.d.ts +29 -0
  298. package/dist/workflows/meta.d.ts +45 -0
  299. package/dist/workflows/registry.d.ts +24 -0
  300. package/dist/workflows/runtime.d.ts +254 -0
  301. package/dist/workflows/sandbox.d.ts +49 -0
  302. package/dist/workflows/script-api.d.ts +58 -0
  303. package/dist/workflows/seam.d.ts +92 -0
  304. package/dist/workflows/semaphore.d.ts +16 -0
  305. package/dist/workflows/store.d.ts +177 -0
  306. package/dist/workflows/subprocess-entry.d.ts +38 -0
  307. package/dist/workflows/subprocess-entry.js +14 -0
  308. package/dist/workflows/transcript.d.ts +56 -0
  309. package/dist/workflows/types.d.ts +84 -0
  310. package/dist/workflows/worker-harness.d.ts +45 -0
  311. package/package.json +76 -0
@@ -0,0 +1,25 @@
1
+ import type { ProtocolSdkMessage as SdkMessage } from "@yanlinglabs/winter-agent-sdk";
2
+ import type { ProviderStreamSink } from "../engine.js";
3
+ export interface StreamFrameSinkDeps {
4
+ sessionId: string;
5
+ /** The pin's own `Options.includePartialMessages`. Absent/false gates `stream_event` OFF and nothing else. */
6
+ includePartialMessages: boolean;
7
+ /** Writes one frame. Never throws to the caller -- see the wrapper below. */
8
+ write: (message: SdkMessage) => void;
9
+ /** Read LIVE, not captured: a `set_model` between generations changes what `reasoning_summary` should name. */
10
+ identity: () => {
11
+ providerId?: string;
12
+ modelKey?: string;
13
+ } | undefined;
14
+ /** The session's CURRENT model, for the same reason. */
15
+ model: () => string;
16
+ /** Injected for deterministic `ttft_ms` in tests. */
17
+ now?: () => number;
18
+ }
19
+ /**
20
+ * Builds the sink for ONE generation.
21
+ *
22
+ * Per generation, not per session, because `ttft_ms` is per generation: capture (F) observed exactly
23
+ * two frames carrying it across a run -- one per FORWARDED turn, on that turn's `message_start`.
24
+ */
25
+ export declare function createStreamFrameSink(deps: StreamFrameSinkDeps): ProviderStreamSink;
@@ -0,0 +1,57 @@
1
+ import type { CredentialRef } from "@yanlinglabs/winter-agent-sdk";
2
+ import type { CredentialStore } from "@yanlinglabs/winter-provider-runtime";
3
+ import type { KeychainSecretReader } from "./keychain-store.js";
4
+ /**
5
+ * `found` the key, trimmed.
6
+ * `missing` the ref resolves to nothing (no such item, an empty value, `{ kind: "none" }`). The
7
+ * ordinary "no key configured" state -- never an error.
8
+ * `unreadable` something IS there (or the store failed) and it cannot be used as a key. `code` is
9
+ * the store's own vocabulary; `message` names the redacted ref and the reason.
10
+ */
11
+ export type ToolSecretResult = {
12
+ status: "found";
13
+ key: string;
14
+ } | {
15
+ status: "missing";
16
+ } | {
17
+ status: "unreadable";
18
+ code: "io" | "malformed" | "unsupported";
19
+ message: string;
20
+ };
21
+ /** What an executor is handed. A test fake is a one-line function returning one of the three arms. */
22
+ export type ToolSecretResolver = (ref: CredentialRef) => Promise<ToolSecretResult>;
23
+ export interface ToolSecretResolverDeps {
24
+ /** Serves every NON-keychain ref (`env`, `inline`, `file`, `none`), and keychain refs too when no raw reader is supplied. */
25
+ credentials: CredentialStore;
26
+ /**
27
+ * The keychain's RAW reader (`createKeychainSecretReader`). When present, a keychain ref is read
28
+ * through it EXACTLY ONCE and interpreted here -- never through `credentials.get` first, which
29
+ * would throw `malformed` on a bare key and would cost a second keychain access (each of which can
30
+ * raise an OS consent prompt). ABSENT for a wiring built over an injected store: a test must never
31
+ * reach the real keychain, so an injected store means "this is the only source".
32
+ */
33
+ readKeychainSecret?: KeychainSecretReader;
34
+ }
35
+ /**
36
+ * What one stored string means. Exported for its own tests.
37
+ *
38
+ * NOTHING FROM THE STORED VALUE EVER APPEARS IN A MESSAGE -- these messages travel into a tool
39
+ * RESULT, which a model reads. That includes the value of a `kind` field: it is quoted only when it
40
+ * is one of the kinds this SDK writes, because anything else is content of unknown provenance and
41
+ * may be the secret itself (an item holding `{"kind":"sk-live-..."}` must not be echoed).
42
+ *
43
+ * JSON `{ "kind": "api-key", "key": "<non-empty>" }` -> the key
44
+ * a JSON string -> that string, held to the bare-key rule
45
+ * JSON `null` -> missing (a serialised "no value")
46
+ * any other JSON object, array, `true`/`false` -> unreadable: structured, and not an API key
47
+ * text that STARTS like JSON (`{` / `[`) but does not
48
+ * parse -> unreadable. It was meant to be structured;
49
+ * sending the whole blob as the key header
50
+ * would put a broken record on the wire
51
+ * any other text -> the trimmed text, if it has no whitespace
52
+ *
53
+ * A JSON NUMBER is deliberately a key: one made only of digits parses as a number, and it is still
54
+ * the key.
55
+ */
56
+ export declare function interpretToolSecret(raw: string, locator: string): ToolSecretResult;
57
+ export declare function createToolSecretResolver(deps: ToolSecretResolverDeps): ToolSecretResolver;
@@ -0,0 +1,14 @@
1
+ import { type ControlResponseFrame } from "@yanlinglabs/winter-agent-sdk";
2
+ import type { FrameSink } from "../protocol/channel.js";
3
+ export interface RpcBridge {
4
+ request<T = unknown>(subtype: string, payload: unknown, opts?: {
5
+ timeoutMs?: number;
6
+ requestId?: string;
7
+ signal?: AbortSignal;
8
+ }): Promise<T>;
9
+ handleResponse(frame: ControlResponseFrame): boolean;
10
+ ownsRequest(requestId: string): boolean;
11
+ rejectAllPending(err: unknown): void;
12
+ cancel(requestId: string): void;
13
+ }
14
+ export declare function createRpcBridge(output: FrameSink): RpcBridge;
@@ -0,0 +1,26 @@
1
+ import type { McpServerState, McpServerStateKind, McpServerStateSource } from "../mcp/state.js";
2
+ import type { McpControlSeam } from "../mcp/control-seam.js";
3
+ export type McpControlResult = {
4
+ ok: true;
5
+ payload?: unknown;
6
+ } | {
7
+ ok: false;
8
+ error: {
9
+ code: string;
10
+ message: string;
11
+ };
12
+ };
13
+ export declare function toWireMcpStatus(kind: McpServerStateKind): string;
14
+ export declare function mcpServerStatesToWire(states: readonly McpServerState[]): Array<{
15
+ name: string;
16
+ status: string;
17
+ protocolVersion?: string;
18
+ }>;
19
+ export interface McpControlDeps {
20
+ stateSource?: McpServerStateSource;
21
+ controlSeam?: McpControlSeam;
22
+ }
23
+ export declare function handleMcpStatus(deps: McpControlDeps): Promise<McpControlResult>;
24
+ export declare function handleMcpReconnect(deps: McpControlDeps, payload: unknown): Promise<McpControlResult>;
25
+ export declare function handleMcpToggle(deps: McpControlDeps, payload: unknown): Promise<McpControlResult>;
26
+ export declare function handleMcpSetServers(deps: McpControlDeps, payload: unknown): Promise<McpControlResult>;
@@ -0,0 +1,14 @@
1
+ import type { FrameSource, FrameSink } from "./protocol/channel.js";
2
+ import { type Provider, type ToolExecutor, type SessionPersistence } from "./engine.js";
3
+ export declare function runWinterRuntime(opts: {
4
+ input: FrameSource;
5
+ output: FrameSink;
6
+ provider: Provider;
7
+ sessionId: string;
8
+ cwd: string;
9
+ model: string;
10
+ permissionMode?: string;
11
+ maxTurns?: number;
12
+ tools?: ToolExecutor;
13
+ store?: SessionPersistence;
14
+ }): Promise<void>;
@@ -0,0 +1,249 @@
1
+ import { type BrandProfile } from "@yanlinglabs/winter-agent-sdk";
2
+ /**
3
+ * P7a (D19): the two dot-dir names the seatbelt fences. `homeDirName` anchors the winter root under
4
+ * the OS home (the run-dir read deny, the backups write deny, the provider-state read deny);
5
+ * `projectDirName` anchors the per-writable-root control plane (WS-12 §5.2's carve-out).
6
+ */
7
+ export type SandboxBrand = Pick<BrandProfile, "homeDirName" | "projectDirName">;
8
+ import { type GlobDenyEntry } from "../permissions/file-rules.js";
9
+ export interface SandboxFilesystemSettings {
10
+ allowWrite?: string[];
11
+ denyWrite?: string[];
12
+ allowRead?: string[];
13
+ denyRead?: string[];
14
+ /**
15
+ * Fix round 16, item 2 (claude's own `ag()`, dump-verified: `function ag(){return
16
+ * pe?.filesystem?.allowGitConfig??!1}`): `sandbox.filesystem.allowGitConfig` in settings.json --
17
+ * the ONE settings-facing door for `SeatbeltProfileInput.allowGitConfigWrites`/
18
+ * `RunCommandOptions.allowGitConfigWrites`, which this module and spawn.ts already had (round 15)
19
+ * but nothing set. Wired through `tools/impl/{bash,monitor}.ts`'s own options-builders (each reads
20
+ * `ctx.sandboxSettings.filesystem?.allowGitConfig` directly) -- `buildSeatbeltProfile` itself never
21
+ * reads this field; it is CONSUMED at the caller boundary (spawn.ts's own `allowGitConfigWrites`
22
+ * param), matching every other filesystem key's own "settings shape carries it, a caller resolves
23
+ * it into the profile-builder's own dedicated param" pattern in this file.
24
+ */
25
+ allowGitConfig?: boolean;
26
+ }
27
+ export interface SandboxNetworkSettings {
28
+ allowedDomains?: string[];
29
+ deniedDomains?: string[];
30
+ [key: string]: unknown;
31
+ }
32
+ export interface SandboxSettings {
33
+ enabled?: boolean;
34
+ autoAllowBashIfSandboxed?: boolean;
35
+ excludedCommands?: string[];
36
+ allowUnsandboxedCommands?: boolean;
37
+ filesystem?: SandboxFilesystemSettings;
38
+ network?: SandboxNetworkSettings;
39
+ }
40
+ export declare const DEFAULT_SANDBOX_SETTINGS: Readonly<SandboxSettings>;
41
+ export declare class SandboxConfigError extends Error {
42
+ constructor(message: string);
43
+ }
44
+ export declare function resolveNetworkPosture(network: SandboxNetworkSettings | undefined): boolean;
45
+ export declare function canonicalizePath(p: string): string;
46
+ /**
47
+ * P7a fix r1 (Important-1): render ONE brand token as a case-insensitive, regex-escaped SBPL literal.
48
+ *
49
+ * The three any-depth control-plane regexes below used to hard-code `[Ww][Ii][Nn][Tt][Ee][Rr]` while
50
+ * the per-root LITERAL denies beside them already derived from `brand.projectDirName`. WS-12 §5.2
51
+ * names those regexes as the closure for the nested-store hole -- a broad writable parent makes
52
+ * `<parent>/proj/<dot-dir>/settings.json` writable with no literal deny for it -- and §5.2 also
53
+ * records that the seatbelt is the ONLY enforcement point left for a bash-invoked write to the
54
+ * permission control plane. Hard-coded, they fenced a directory a reuser's product never reads while
55
+ * leaving the reuser's own control plane open to `echo x > <root>/<nested>/.acme/settings.json`.
56
+ *
57
+ * ESCAPE FIRST, FOLD SECOND, per character: a letter becomes `[Xx]`, and everything else is escaped
58
+ * exactly as `sbplRegexLiteral` escapes it (the brand grammar admits `-` and, for a dot-dir, the
59
+ * leading `.` -- which MUST be escaped or it matches any character). Applied to Winter's own dot-dir
60
+ * it renders `\.[Ww][Ii][Nn][Tt][Ee][Rr]`, byte for byte what the constant it replaces spelled, so
61
+ * the rendered profile is unchanged under `WINTER_BRAND` (a test diffs the whole profile text).
62
+ *
63
+ * Exported so the deny suite can assert the rendering directly rather than by reading the profile.
64
+ */
65
+ export declare function caseFoldSegment(segment: string): string;
66
+ export interface SeatbeltProfileInput {
67
+ /** The session's own working directory -- always a writable root. */
68
+ cwd: string;
69
+ /** Extra writable subpaths: session scratch (ctx.tempDir), configured filesystem.allowWrite, outputs dir, etc. */
70
+ writableRoots?: string[];
71
+ /** WS-12 §5.3: filesystem.denyWrite, layered AFTER the write-allow block (last-match-wins). */
72
+ denyWritePaths?: string[];
73
+ /** WS-12 §5.3: filesystem.denyRead, layered AFTER the read-allow block (last-match-wins). */
74
+ denyReadPaths?: string[];
75
+ /**
76
+ * Fix round 11 (claude's `Li`/`Rt`, dump byte 15365905/15282610, pinned 2.1.250): glob-shaped
77
+ * deny entries, PRE-CONVERTED by the caller to SBPL regex SOURCE TEXT (`permissions/file-rules.ts`'s
78
+ * `globToSbplRegexSource`/`recursiveGlobToSbplRegexSource`/`splitDenyPathsByGlobShape`) -- this
79
+ * module has no glob grammar of its own (mirrors `denyWritePaths`/`denyReadPaths`'s own "already
80
+ * resolved by the caller" posture) and only quotes/renders. Claude's own macOS sandbox profile
81
+ * builder renders a glob-shaped deny as `(regex ...)` and a plain one as `(subpath ...)` (`Li`); a
82
+ * `subpath` deny alone -- Winter's pre-round-11 posture -- silently drops a glob-shaped Edit deny
83
+ * (e.g. a globstar-anchored `.env` pattern) or `denyWrite` entry from the sandbox layer entirely
84
+ * (the PERMISSION-RULE layer still enforced it for a recognized tool call; a bash-invoked
85
+ * `tee`/`cp` bypassing that layer did not).
86
+ */
87
+ denyWriteRegexes?: string[];
88
+ denyReadRegexes?: string[];
89
+ /**
90
+ * Fix round 12 ("Important" item, claude's own `Ch`/`ed`/`mR`/`pR`, dump byte 15368116/15367994/
91
+ * 15369065/15368380, pinned 2.1.250): the ancestor-rename-bypass fix. `denyWriteGlobFixedPrefixes`/
92
+ * `denyReadGlobFixedPrefixes` are the CANONICALIZED fixed-prefix directory of each glob-shaped
93
+ * denyWrite/denyRead entry (`permissions/file-rules.ts`'s `splitDenyPathsByGlobShape`, its own
94
+ * `globFixedPrefixes` output) -- this module has no glob grammar of its own, mirrors the other
95
+ * caller-pre-resolved fields above. Combined with `denyWritePaths`/`denyReadPaths` (the PLAIN
96
+ * entries, reused directly -- no new field needed for those), `buildAncestorRenameBypassBlock`
97
+ * below builds a `(deny file-write-unlink file-write-create ...)` clause naming every ANCESTOR of
98
+ * each denied path/glob-fixed-prefix, PLUS the fixed prefix itself, so a sandboxed `mv <ancestor>
99
+ * <elsewhere> && <write inside where it used to be> && mv <elsewhere> <ancestor>` cannot rename an
100
+ * ancestor of a denied path out of the way (and back) to slip a write past the deny.
101
+ */
102
+ denyWriteGlobFixedPrefixes?: string[];
103
+ denyReadGlobFixedPrefixes?: string[];
104
+ /**
105
+ * Fix round 13 ("Important" item 1, claude's own `fR`, dump byte 15367091): "keep read-denied
106
+ * paths inside write roots in place." Winter's read-deny/write-allow sections previously composed
107
+ * exactly the way claude's OWN `mR`/`pR` alone would -- last-match-wins, and the write-allow
108
+ * (`(allow file-write* (subpath <root>))`) is emitted AFTER the read-deny section, so it silently
109
+ * overrides any read-deny's own implicit protection against being UNLINKED (renamed away): with
110
+ * `Read(.env)` denied and cwd writable, a sandboxed `mv .env x && cat x` renamed the read-denied
111
+ * file to a new, non-denied name and read the secret through it. claude closes this with a THIRD
112
+ * section, `fR`, emitted AFTER the write-allow block: for each read-denied path (or glob-shaped
113
+ * entry, `denyReadGlobEntries` below) that sits inside a write root, denies `file-write-unlink` on
114
+ * its own recursive clause (minus any write root nested INSIDE it, carved back out) and on every
115
+ * one of its ancestor directories that is ALSO inside a write root.
116
+ */
117
+ denyReadGlobEntries?: GlobDenyEntry[];
118
+ /** Resolved network posture -- see resolveNetworkPosture's own header for why this is a plain boolean here. */
119
+ allowNetwork: boolean;
120
+ /**
121
+ * The real per-user temp dir (`confstr(_CS_DARWIN_USER_TEMP_DIR)`, exposed by `getconf
122
+ * DARWIN_USER_TEMP_DIR` -- resolved by spawn.ts, never by this module, to keep profile.ts
123
+ * platform-free). Omitted entirely -> the mktemp convenience rule is simply not emitted, which is
124
+ * still a CORRECT (if less ergonomic) profile -- mirrors Norma's own "a profile without this
125
+ * convenience rule is still a correct profile" comment.
126
+ */
127
+ darwinUserTempDir?: string;
128
+ /**
129
+ * WS-12 §2: "the sole baseline read denial is `<home>/<homeDirName>/run`, enforced via profile
130
+ * deny rules layered over allow-read." The daemon's own runtime dir (control socket, PID/lock
131
+ * files) -- a bash-invoked `cat ~/<homeDirName>/run/core.sock` never passes through a read-tool's own
132
+ * permission fence at all (reads are otherwise deliberately unrestricted, per this product's own
133
+ * tool-surface design), so the seatbelt profile is the only enforcement point left. Omitted
134
+ * entirely -> no baseline deny is emitted, still a correct (if less defended) profile -- mirrors
135
+ * `darwinUserTempDir`'s own "omitted is still correct" posture; there is no ToolExecutionContext
136
+ * seam this module can reach into itself (profile.ts stays platform/context-free by design, per
137
+ * this file's own header), so every caller (spawn.ts -> tools/impl/{bash,monitor}.ts) is
138
+ * responsible for threading its own `ctx.home` through.
139
+ */
140
+ home?: string;
141
+ /**
142
+ * Phase 5 fix wave, I1: the RESOLVED winter root (`<PREFIX>HOME` when set), when it differs
143
+ * from `<home>/<homeDirName>`.
144
+ *
145
+ * `home` above is the OS home and this module appends `brand.homeDirName` to it -- correct only
146
+ * when the resolved root is literally named that. Under a `<PREFIX>HOME` pointing anywhere
147
+ * else, the run read-deny and the backups write-deny both landed on a directory that does not
148
+ * exist while the real one stayed open.
149
+ *
150
+ * ADDED, NEVER SWAPPED: both anchors are emitted, because the carried WS-12 §5.2 deny corpus and
151
+ * every default-home session still assume the literal default, and two denies of overlapping scope
152
+ * cost nothing.
153
+ */
154
+ winterHome?: string;
155
+ /**
156
+ * WS-21 §3.7/§6.3 item 11: the shared runtime home's durable-paths root (`config.storeHome`),
157
+ * preferred over `winterHome` for the two DURABLE denies below -- the checkpoint (backups) write
158
+ * deny and the provider-state read deny, both of which protect `projects/`-rooted content that
159
+ * lives under the store home once the router links `buildRunHome`, a directory now DISTINCT from
160
+ * the per-run folder `winterHome` names. The run-dir read deny is left anchored on `winterHome`
161
+ * unchanged: it protects the daemon's own `run/` (sockets, pidfiles), which is neither the
162
+ * per-run folder nor the store home in the WS-21 layout, so this module has no better anchor for
163
+ * it than it already had -- a disclosed, unchanged limitation, not a regression.
164
+ */
165
+ storeHome?: string;
166
+ /**
167
+ * P7a (D19): the brand whose dot-dir and project dot-dir this profile fences.
168
+ *
169
+ * Every winter-owned path segment below is `brand.homeDirName` (the root under the OS home) or
170
+ * `brand.projectDirName` (the per-writable-root control plane). Omitted = `WINTER_BRAND`, so a
171
+ * caller that threads none emits byte-identical SBPL -- which is what the carried WS-12 §5.2 deny
172
+ * corpus and the darwin deny suite assert.
173
+ */
174
+ brand?: SandboxBrand;
175
+ /**
176
+ * Fix round 15 (claude's own `cR(e=false)` / `mR`'s own `r=false` default parameter): when true,
177
+ * `.git/config` is NOT added to the default write-protected entries (`buildDefaultWriteProtectionBlock`
178
+ * above) -- every OTHER default protection (shell/tool config files, editor/agent dot-dirs,
179
+ * `.git/hooks`) is unaffected; this flag only ever gates `.git/config`, matching `cR`'s own `!e`
180
+ * guard exactly. Omitted = `false` = protected, matching claude's own default. No caller sets this
181
+ * true yet -- kept for parity since claude's own signature carries the knob.
182
+ */
183
+ allowGitConfigWrites?: boolean;
184
+ }
185
+ /**
186
+ * Build a macOS Seatbelt (SBPL) profile: deny-by-default, read anywhere (minus configured
187
+ * denyRead layers and, when `home` is given, the WS-12 §2 baseline `<home>/<homeDirName>/run` denial --
188
+ * see `SeatbeltProfileInput.home`'s own header), write only under the given roots (minus configured
189
+ * denyWrite layers), network denied unless explicitly allowed.
190
+ *
191
+ * WS-12 §5.2 (verbatim carry, Winter-renamed): EVERY writable root (cwd + each of `writableRoots`)
192
+ * additionally gets an explicit `(deny <ops> (literal "<root>/<projectDir>/<file>"))` line, for
193
+ * each of `permissions.local.json`/`settings.json`/`settings.local.json`, unconditionally, with no
194
+ * opt-in flag to forget -- a bash-invoked `echo x > <projectDir>/permissions.local.json` never passes
195
+ * through a write/edit TOOL's own permission fence at all, so the seatbelt is the only enforcement
196
+ * point left for a shell-invoked write to the permission/settings control plane. SBPL evaluates a
197
+ * profile's rules for a given operation in FILE ORDER, last-match-wins, WITH ONE EMPIRICALLY-VERIFIED
198
+ * EXCEPTION (fix round 14, `WRITE_OPS_SURVIVING_READ_DENY_REPERMIT`'s own header): a clause naming
199
+ * `file-write-unlink`/`file-write-create` EXPLICITLY beats one that only reaches them via the
200
+ * `file-write*` wildcard, independent of file order -- which is why `<ops>` here is
201
+ * `WRITE_OPS_SURVIVING_READ_DENY_REPERMIT` (`file-write* file-write-unlink file-write-create`), not a
202
+ * bare `file-write*`, since round 14 added an EARLIER, blanket, explicit-named re-permit
203
+ * (`buildReadDenyWritePermitBlock`) that a bare-wildcard deny here would no longer survive. Ordinary
204
+ * last-match-wins still governs every OTHER write operation (`file-write-data`, etc.) and governs
205
+ * `<ops>` vs. `<ops>` ties among explicit-named clauses -- placing these denies AFTER the
206
+ * `(allow file-write* (subpath ...))` block carves out exactly these files from an otherwise-writable
207
+ * subpath, without touching a sibling file or an entire OTHER subdirectory like the MEMDIR.
208
+ *
209
+ * A companion `(deny <ops> (regex ...))` per filename, placed after the per-root literals, closes
210
+ * the NESTED-store hole a literal-only deny misses: a broad `writableRoots` entry makes a nested
211
+ * `<root>/projB/<projectDir>/settings.json` writable too, with no literal deny naming that exact
212
+ * path. Case-folded per character (see the module-level regex constants' own comment).
213
+ */
214
+ export declare function buildSeatbeltProfile(input: SeatbeltProfileInput): string;
215
+ /**
216
+ * Tight Seatbelt profile for a workflow-worker subprocess (WS-11 §1.7's own consumer -- that phase
217
+ * has not shipped a real worker yet; this ships the tested mechanism now, verbatim-ported from
218
+ * Norma's `workflows/sandbox.ts`). Strictly tighter than the ordinary Bash profile:
219
+ * - deny file-write* EVERYWHERE (the worker writes nothing; the journal is appended parent-side),
220
+ * - deny network*,
221
+ * - deny process-fork AND allow process-exec ONLY for the self binary.
222
+ *
223
+ * Part B item 2 (fix wave, P3 close-out) -- THE READ-AXIS CARRY IS NOW CLOSED (Phase 5 Task 3,
224
+ * R5-5: "the P3 worker seatbelt profile PLUS the ledgered run-directory deny"). `opts.home`, when
225
+ * supplied, emits the same baseline `<home>/<homeDirName>/run` read-deny rule the ordinary Bash profile
226
+ * carries (buildSeatbeltProfile's own `home` field), making this profile a strict superset of that
227
+ * one's denials on every axis.
228
+ *
229
+ * `opts` is REQUIRED and `opts.home` is `string | undefined` -- NOT an optional property (fix round
230
+ * 1): "Lane W's spawner must remember to pass it" is exactly the obligation that gets forgotten, and
231
+ * an optional parameter makes forgetting compile. Making the argument mandatory while allowing an
232
+ * explicit `undefined` turns the silent gap into a compile error at every call site, and leaves the
233
+ * genuinely home-less callers (profile.test.ts, the string-shape half of the darwin suite) able to
234
+ * state that they mean it. A profile built with `{ home: undefined }` is still correct, just less
235
+ * defended -- exactly as buildSeatbeltProfile documents for its own `home`.
236
+ *
237
+ * THE #1 RISK (verified empirically by the Norma original): a blanket `(deny process-exec*)` makes
238
+ * sandbox-exec's own execvp() of the target fail ("Operation not permitted"), because the
239
+ * sandbox->target transition is itself an exec checked against the profile. So this allows exec of
240
+ * EXACTLY `selfExecPath` (canonicalized) and nothing else -- enough for the runtime binary to boot
241
+ * (it dyld-loads its libs via the allowed file-read*), while a workflow script still cannot exec
242
+ * /bin/sh etc. Note the operation is `process-fork` (no star) -- `process-fork*` is an unbound
243
+ * variable that fails to load.
244
+ */
245
+ export declare function buildWorkflowWorkerSeatbeltProfile(selfExecPath: string, opts: {
246
+ home: string | undefined;
247
+ winterHome?: string;
248
+ brand?: SandboxBrand;
249
+ }): string;
@@ -0,0 +1,139 @@
1
+ import { type SandboxBrand, type SandboxSettings } from "./profile.js";
2
+ import type { GlobDenyEntry } from "../permissions/file-rules.js";
3
+ export declare function isSandboxAvailable(checkPath?: string): boolean;
4
+ export declare class SandboxUnavailableError extends Error {
5
+ constructor(message: string);
6
+ }
7
+ export declare function resolveDarwinUserTempDir(): string | null;
8
+ /** Test seam: forget the cached per-user temp dir so a test can observe resolution again. */
9
+ export declare function resetDarwinUserTempDirCacheForTest(): void;
10
+ export type SandboxPosture = "config-disabled" | "override-requested" | "excluded" | "sandboxed" | "unavailable";
11
+ export interface ResolveExecutionPathInput {
12
+ settings: SandboxSettings;
13
+ dangerouslyDisableSandbox?: boolean;
14
+ command: string;
15
+ }
16
+ export interface ExecutionPathDecision {
17
+ posture: Exclude<SandboxPosture, "unavailable">;
18
+ /**
19
+ * WS-12 §4: the call's OWN raw `dangerouslyDisableSandbox` flag, independent of which posture
20
+ * actually won the first-match-wins table below -- so a result can show "the model asked for the
21
+ * override" even on the rare path where `enabled: false` already made it moot (row 1 beats row 2).
22
+ */
23
+ sandboxOverrideRequested: boolean;
24
+ }
25
+ /**
26
+ * WS-12 §4.1's own table, first-match-wins:
27
+ * 1. `sandbox.enabled === false` -> unsandboxed (config-disabled)
28
+ * 2. `dangerouslyDisableSandbox: true` on the call, UNLESS `allowUnsandboxedCommands === false`
29
+ * -> unsandboxed (override-requested)
30
+ * 3. command matches `excludedCommands` AND `allowUnsandboxedCommands` -> unsandboxed (excluded)
31
+ * 4. otherwise -> sandboxed
32
+ *
33
+ * R3-6 (capture-pending, per this task's own brief): `excludedCommands` matching is EXACT-FULL-
34
+ * COMMAND-STRING equality only -- no trimming, no argv[0] extraction, no prefix rule. WS-12 §12
35
+ * open question 2 leaves the real matching semantics for a future WS-17 differential capture; this
36
+ * is the deliberately narrow placeholder until that capture lands.
37
+ */
38
+ export declare function resolveExecutionPath(input: ResolveExecutionPathInput): ExecutionPathDecision;
39
+ export interface RunCommandOptions {
40
+ command: string;
41
+ /**
42
+ * Task 8 (P3 close-out, "excludedCommands raw-match" MUST): the command string `resolveExecutionPath`
43
+ * matches against `settings.excludedCommands`, when it differs from `command` above (the string
44
+ * that actually gets spawned). Defaults to `command` when omitted -- byte-identical to every caller
45
+ * before this field existed (background execution, Monitor's command half, both of which already
46
+ * spawn the model's raw command with no wrapper). bash.ts's own foreground path is the one caller
47
+ * that needs this: it wraps the raw command in a pwd-capture script before spawning (see that
48
+ * file's own `buildPwdCaptureScript`/`runForeground` header comment, "LATENT TRAP") but must match
49
+ * `excludedCommands` against what the model/settings author actually wrote, never the wrapper.
50
+ */
51
+ matchCommand?: string;
52
+ /** Real, existing, already-canonicalized directory to spawn the shell in. */
53
+ cwd: string;
54
+ env: NodeJS.ProcessEnv;
55
+ timeoutMs: number;
56
+ signal?: AbortSignal;
57
+ onStdout?: (chunk: Buffer) => void;
58
+ onStderr?: (chunk: Buffer) => void;
59
+ /**
60
+ * Fires synchronously once the child is spawned, before any output arrives -- the ONLY way a
61
+ * caller can learn the process-group pid early enough to track/kill it while it is still
62
+ * running (`RunCommandResult.exitCode` etc. only resolve once the process has already exited).
63
+ * `run_in_background` callers (tools/impl/bash.ts) need this to register the task BEFORE
64
+ * awaiting the eventual result; a foreground caller simply omits it.
65
+ */
66
+ onSpawned?: (info: {
67
+ pid: number;
68
+ }) => void;
69
+ maxStreamedBytes?: number;
70
+ settings: SandboxSettings;
71
+ dangerouslyDisableSandbox?: boolean;
72
+ /**
73
+ * TEST-ONLY injection seam: overrides which path the internal `isSandboxAvailable` check probes
74
+ * for existence, WITHOUT changing the real spawn target (`REAL_SANDBOX_EXEC_PATH` below is always
75
+ * what actually runs once availability passes). WS-12 §3's typed-unavailability path is otherwise
76
+ * unreachable on any dev/CI box that genuinely has /usr/bin/sandbox-exec -- which is every darwin
77
+ * box this product ships on -- so without this seam the throw site below has zero live coverage.
78
+ * Never read from model input (bash.ts's own BashInput has no such field): a model-controllable
79
+ * override of its own sandbox-availability check would be a containment hole, not a test seam.
80
+ */
81
+ sandboxExecPath?: string;
82
+ /** Extra writable roots beyond cwd -- session scratch, configured filesystem.allowWrite, outputs dir. */
83
+ writableRoots?: string[];
84
+ denyWritePaths?: string[];
85
+ denyReadPaths?: string[];
86
+ /**
87
+ * Fix round 11 (claude's `Li`/`Rt`, dump byte 15365905/15282610): glob-shaped `denyWritePaths`/
88
+ * `denyReadPaths` entries, PRE-CONVERTED to SBPL regex source by the caller (`permissions/
89
+ * file-rules.ts`'s `splitDenyPathsByGlobShape`) -- this module stays glob-grammar-free, exactly
90
+ * like `denyWritePaths`/`denyReadPaths` themselves are already resolved, absolute paths by the
91
+ * time they reach here.
92
+ */
93
+ denyWriteRegexes?: string[];
94
+ denyReadRegexes?: string[];
95
+ /**
96
+ * Fix round 12 ("Important" item, claude's own `Ch`/`ed`): the ancestor-rename-bypass fix -- each
97
+ * glob-shaped `denyWritePaths`/`denyReadPaths` entry's OWN canonicalized fixed-prefix directory
98
+ * (see `SeatbeltProfileInput.denyWriteGlobFixedPrefixes`'s own header). Same "caller pre-resolves,
99
+ * this module stays glob-grammar-free" posture as `denyWriteRegexes`/`denyReadRegexes` above.
100
+ */
101
+ denyWriteGlobFixedPrefixes?: string[];
102
+ denyReadGlobFixedPrefixes?: string[];
103
+ /**
104
+ * Fix round 13 ("Important" item 1, claude's own `fR`): the read-deny-keep-in-place fix -- each
105
+ * glob-shaped `denyReadPaths` entry, PAIRED with its own fixed prefix (see
106
+ * `SeatbeltProfileInput.denyReadGlobEntries`'s own header). Read-only -- claude's own `fR` is a
107
+ * read-deny-specific concern.
108
+ */
109
+ denyReadGlobEntries?: GlobDenyEntry[];
110
+ /**
111
+ * WS-12 §2: the caller's `ctx.home`, threaded straight through to `buildSeatbeltProfile`'s own
112
+ * `home` field for the baseline `<home>/<homeDirName>/run` read denial -- see that field's own header
113
+ * for why this module (rather than profile.ts) is where a real `ctx.home` value gets plugged in.
114
+ * Omitted -> no baseline deny is emitted, same graceful-degradation posture as every other
115
+ * optional profile input here.
116
+ */
117
+ home?: string;
118
+ /** Phase 5 fix wave, I1: the resolved winter root -- see `SeatbeltProfileInput.winterHome`. */
119
+ winterHome?: string;
120
+ /** WS-21 §3.7: the shared runtime home's durable-paths root -- see `SeatbeltProfileInput.storeHome`. */
121
+ storeHome?: string;
122
+ /** P7a (D19): the session's brand -- the dot-dir names the profile fences. Omitted = `WINTER_BRAND`. */
123
+ brand?: SandboxBrand;
124
+ /** Fix round 15: see `SeatbeltProfileInput.allowGitConfigWrites`'s own header. Omitted = `false`. */
125
+ allowGitConfigWrites?: boolean;
126
+ }
127
+ export interface RunCommandResult {
128
+ exitCode: number | null;
129
+ timedOut: boolean;
130
+ aborted: boolean;
131
+ streamKilled: boolean;
132
+ posture: Exclude<SandboxPosture, "unavailable">;
133
+ sandboxOverrideRequested: boolean;
134
+ /** The generated SBPL profile text, only present when posture === "sandboxed" (debug/test aid). */
135
+ profile?: string;
136
+ /** Set when the child never actually launched (Node's "error" event) -- distinct from a signal-killed exit (exitCode null, this unset). */
137
+ spawnError?: string;
138
+ }
139
+ export declare function runCommand(opts: RunCommandOptions): Promise<RunCommandResult>;
@@ -0,0 +1,52 @@
1
+ export type EnvFilterTier = "user" | "project" | "local" | "flag";
2
+ /**
3
+ * F17 (V8): what a PROJECT or LOCAL tier's `env` block may never set, on top of
4
+ * `ALL_TIER_REFUSED_ENV`. `CLAUDE_CODE_PLUGIN_SEED_DIR`/`CLAUDE_CODE_PROCESS_WRAPPER` are claude's
5
+ * own names (no Winter twin exists); `pluginCacheDirEnvName` is `CLAUDE_CODE_PLUGIN_CACHE_DIR`'s
6
+ * twin, refused at this tier for the identical reason claude refuses the original.
7
+ */
8
+ export declare const PROJECT_TIER_REFUSED_ENV: readonly string[];
9
+ /**
10
+ * F17's "every tier drops" list, plus every variable ONLY the router may set (spec §3.4.4 step 4 /
11
+ * the Global Constraints list) -- claude-named and Winter-brand-twinned alike. `CLAUDE_CONFIG_DIR`
12
+ * is explicitly HERE despite F17 saying claude itself never drops it (F17 describes claude's OWN
13
+ * base rule; Winter's router additionally refuses it from settings because only the router may ever
14
+ * set the child's config dir -- the Global Constraints list is the authority for that addition).
15
+ */
16
+ export declare const ALL_TIER_REFUSED_ENV: readonly string[];
17
+ /**
18
+ * F20: once host-managed provider auth is on, every tier's `env` additionally loses every
19
+ * provider/auth/proxy/TLS key -- DISCLOSED, not exhaustively pinned against a live capture (F20's
20
+ * own wording is categorical: "provider, auth, proxy and TLS keys", not a closed name list). Grown
21
+ * by a fixture the way V19's own repo-read enumeration is, rather than guessed complete here.
22
+ *
23
+ * Fix round 1 (Important 3): `/^ANTHROPIC_/` alone caught Anthropic's own `ANTHROPIC_BASE_URL`, but
24
+ * every OTHER provider's base-URL override (`OPENAI_BASE_URL`, `DEEPSEEK_BASE_URL`, ...) sailed
25
+ * through -- F20's own wording ("provider... keys") is provider-AGNOSTIC, and a settings `env`
26
+ * block redirecting ANY provider's endpoint is the identical class of hole a redirected Anthropic
27
+ * endpoint is. `/^CLAUDE_CODE_USE_/` (+ its Winter-brand twin) closes the PROVIDER-SWITCH class
28
+ * (claude's own `CLAUDE_CODE_USE_BEDROCK`/`CLAUDE_CODE_USE_VERTEX`-shaped variables): flipping which
29
+ * backend a host-managed session talks to is an endpoint redirect by another name.
30
+ */
31
+ export declare const HOST_MANAGED_REFUSED_ENV_PATTERNS: readonly RegExp[];
32
+ /**
33
+ * `Settings` KEYS (not env vars) that host-managed mode disables (F20: "disables apiKeyHelper/
34
+ * awsAuthRefresh/awsCredentialExport"). Only `apiKeyHelper` is modelled in Winter's own `Settings`
35
+ * shape today (`packages/sdk/src/settings/types.ts:95`) -- claude's `awsAuthRefresh`/
36
+ * `awsCredentialExport` have no Winter field to disable yet, so there is nothing to add for them
37
+ * until one exists.
38
+ */
39
+ export declare const HOST_MANAGED_DISABLED_SETTINGS_KEYS: readonly string[];
40
+ /**
41
+ * Filters one settings tier's `env` block before it reaches the child's process env. `undefined`
42
+ * input (no `env` block at all) yields `{}`, never a throw.
43
+ */
44
+ export declare function filterSettingsEnv(env: Record<string, string> | undefined, tier: EnvFilterTier, opts: {
45
+ hostManaged: boolean;
46
+ }): Record<string, string>;
47
+ /**
48
+ * F20's settings-KEY half of host-managed mode: strips `HOST_MANAGED_DISABLED_SETTINGS_KEYS` from a
49
+ * settings-shaped object when `hostManaged` is on. Generic over the object shape (`production-
50
+ * wiring.ts` applies it to a tier's resolved `Settings`, never re-deriving the key list itself).
51
+ */
52
+ export declare function applyHostManagedSettingsFilter(settings: Record<string, unknown>, hostManaged: boolean): Record<string, unknown>;
@@ -0,0 +1,44 @@
1
+ import { type HookEntriesFromSettings, type SettingsHookSourceInput } from "../../hooks/from-config.js";
2
+ import type { PluginBundle } from "../../plugins/bundle.js";
3
+ /**
4
+ * The `HookSource` a plugin's hooks are filed under.
5
+ *
6
+ * WAS `sdk`, A DISCLOSED STAND-IN -- Phase 5 Task 8 (rider 19) added the real `plugin` member to
7
+ * `HookSource`, closing this lane's own NEEDS_CONTEXT 4. The stand-in's visible cost was that a
8
+ * plugin hook was indistinguishable from an `Options.hooks` registration in an audit record's
9
+ * `source` field; it now names itself.
10
+ *
11
+ * UNGATED by workspace trust, unchanged: a plugin is loaded because a decision was made outside the
12
+ * repository, so gating it on which directory the session is in is neither the pin's model nor
13
+ * Winter's (`subagents/definitions.ts` records the identical reasoning for `pluginAgents`). It ranks
14
+ * LAST in the merge order (`SOURCE_RANK.plugin = 5`, after `sdk`) -- a plugin ships defaults every
15
+ * more-specific source may override.
16
+ */
17
+ export declare const PLUGIN_HOOK_SOURCE: "plugin";
18
+ /** The `resolveSettingsDetailed` / pinned `ResolvedSettings` shapes this accepts -- either field. */
19
+ export interface ResolvedSettingsHookInput {
20
+ perSource?: readonly SettingsHookSourceInput[] | undefined;
21
+ sources?: readonly SettingsHookSourceInput[] | undefined;
22
+ }
23
+ /**
24
+ * Project a settings resolution onto `buildHookEntriesFromSettings`' input.
25
+ *
26
+ * `perSource` is preferred (it is a superset carrying `loaded`/`error`); the pinned `sources` array
27
+ * is the fallback so a caller holding only a `ResolvedSettings` can still produce hooks. Both are
28
+ * already highest-precedence-first, and this preserves that order -- the registry's own stable sort
29
+ * uses registration order as its within-source tiebreak.
30
+ */
31
+ export declare function settingsHookSourceInputs(resolved: ResolvedSettingsHookInput | undefined): SettingsHookSourceInput[];
32
+ /**
33
+ * Turn every loaded plugin's manifest `hooks` block into real entries.
34
+ *
35
+ * ONE `buildHookEntriesFromSettings` CALL PER PLUGIN, then the ids are re-stamped with the plugin's
36
+ * name. That is not tidiness -- it is a correctness requirement. That function derives an id
37
+ * positionally, `${event}:${source}:${groupIndex}:${hookIndex}`, which is deterministic on both
38
+ * sides of the wire and therefore IDENTICAL for two different plugins whose blocks have the same
39
+ * shape. `createCommandHookInvoker` builds `commandsById` as a `Map`, so two colliding ids would
40
+ * leave the LAST plugin's command answering for both entries -- one plugin's hook silently running
41
+ * another plugin's shell command. Prefixing with the plugin name also keeps a plugin id disjoint
42
+ * from every `Options.hooks` id, which shares the same `sdk` source.
43
+ */
44
+ export declare function pluginHookEntries(bundles: readonly PluginBundle[]): HookEntriesFromSettings;