@astrosheep/keiyaku 2.8.5 → 2.9.1

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 (238) hide show
  1. package/README.md +35 -15
  2. package/build/.tsbuildinfo +1 -1
  3. package/build/agents/{call-terms_v2.js → call-terms.js} +12 -8
  4. package/build/agents/harness/control-types.js +1 -0
  5. package/build/agents/harness/execution-handle.js +23 -3
  6. package/build/agents/harness/index.js +6 -607
  7. package/build/agents/harness/outcome.js +141 -0
  8. package/build/agents/harness/projection.js +310 -0
  9. package/build/agents/harness/router.js +201 -0
  10. package/build/agents/harness/runtime.js +2 -1
  11. package/build/agents/{launch-snapshot_v2.js → launch-snapshot/model.js} +69 -74
  12. package/build/agents/launch-snapshot/resolve.js +72 -0
  13. package/build/agents/opencode-sdk.js +24 -3
  14. package/build/agents/providers/{claude-agent-sdk.js → claude-agent-sdk/adapter.js} +46 -368
  15. package/build/agents/providers/claude-agent-sdk/events.js +218 -0
  16. package/build/agents/providers/claude-agent-sdk/session.js +158 -0
  17. package/build/agents/providers/codex-app-server/adapter.js +347 -0
  18. package/build/agents/providers/codex-app-server/events.js +352 -0
  19. package/build/agents/providers/codex-app-server/session.js +266 -0
  20. package/build/agents/providers/codex-sdk.js +23 -5
  21. package/build/agents/providers/opencode-sdk/adapter.js +344 -0
  22. package/build/agents/providers/opencode-sdk/events.js +354 -0
  23. package/build/agents/providers/opencode-sdk/session.js +180 -0
  24. package/build/agents/providers/pi/adapter.js +269 -0
  25. package/build/agents/providers/pi/checkpoint.js +41 -0
  26. package/build/agents/providers/pi/events.js +282 -0
  27. package/build/agents/{selector_v2.js → selector.js} +8 -6
  28. package/build/cli/commands/akuma/akuma/handler.js +4 -0
  29. package/build/cli/commands/akuma/akuma/meta.js +16 -0
  30. package/build/cli/commands/akuma/catalog.js +8 -0
  31. package/build/cli/commands/akuma/list/handler.js +15 -0
  32. package/build/cli/commands/akuma/list/meta-ls.js +9 -0
  33. package/build/cli/commands/akuma/view/handler.js +34 -0
  34. package/build/cli/commands/akuma/view/meta.js +8 -0
  35. package/build/cli/commands/akuma.js +1 -1
  36. package/build/cli/commands/contract/amend/handler.js +10 -0
  37. package/build/cli/commands/contract/amend/meta.js +12 -0
  38. package/build/cli/commands/contract/arc/handler.js +9 -0
  39. package/build/cli/commands/contract/arc/meta.js +26 -0
  40. package/build/cli/commands/contract/bind/handler.js +23 -0
  41. package/build/cli/commands/contract/bind/meta.js +30 -0
  42. package/build/cli/commands/contract/catalog.js +16 -0
  43. package/build/cli/commands/contract/forfeit/handler.js +13 -0
  44. package/build/cli/commands/contract/forfeit/meta.js +12 -0
  45. package/build/cli/commands/contract/log/handler.js +12 -0
  46. package/build/cli/commands/contract/log/meta.js +12 -0
  47. package/build/cli/commands/contract/petition/handler.js +26 -0
  48. package/build/cli/commands/contract/petition/meta.js +23 -0
  49. package/build/cli/commands/contract/renew/handler.js +10 -0
  50. package/build/cli/commands/contract/renew/meta.js +17 -0
  51. package/build/cli/commands/projection/call/handler.js +42 -0
  52. package/build/cli/commands/projection/call/meta.js +9 -0
  53. package/build/cli/commands/projection/catalog.js +14 -0
  54. package/build/cli/commands/projection/kill/handler.js +37 -0
  55. package/build/cli/commands/projection/kill/meta.js +11 -0
  56. package/build/cli/commands/projection/revive/handler.js +56 -0
  57. package/build/cli/commands/projection/revive/meta.js +9 -0
  58. package/build/cli/commands/projection/status/handler.js +25 -0
  59. package/build/cli/commands/projection/status/meta.js +9 -0
  60. package/build/cli/commands/projection/tell/handler.js +36 -0
  61. package/build/cli/commands/projection/tell/meta.js +9 -0
  62. package/build/cli/commands/projection/wait/handler.js +23 -0
  63. package/build/cli/commands/projection/wait/meta.js +11 -0
  64. package/build/cli/commands/registry.js +100 -0
  65. package/build/cli/commands/shared.js +71 -0
  66. package/build/cli/commands/skills/catalog.js +6 -0
  67. package/build/cli/commands/skills/install/handler.js +10 -0
  68. package/build/cli/commands/skills/install/meta.js +9 -0
  69. package/build/cli/commands/skills/skills/handler.js +4 -0
  70. package/build/cli/commands/skills/skills/meta.js +10 -0
  71. package/build/cli/commands/system/catalog.js +8 -0
  72. package/build/cli/commands/system/completion/handler.js +10 -0
  73. package/build/cli/commands/system/completion/meta.js +9 -0
  74. package/build/cli/commands/system/dump-env/handler.js +3 -0
  75. package/build/cli/commands/system/dump-env/meta.js +10 -0
  76. package/build/cli/commands/system/guide/handler.js +4 -0
  77. package/build/cli/commands/system/guide/meta.js +9 -0
  78. package/build/cli/commands/task/add/handler.js +21 -0
  79. package/build/cli/commands/task/add/meta.js +8 -0
  80. package/build/cli/commands/task/catalog.js +22 -0
  81. package/build/cli/commands/task/doctor/handler.js +4 -0
  82. package/build/cli/commands/task/doctor/meta.js +8 -0
  83. package/build/cli/commands/task/done/handler.js +17 -0
  84. package/build/cli/commands/task/done/meta.js +8 -0
  85. package/build/cli/commands/task/drop/handler.js +6 -0
  86. package/build/cli/commands/task/drop/meta.js +8 -0
  87. package/build/cli/commands/task/ls/handler.js +13 -0
  88. package/build/cli/commands/task/ls/meta.js +8 -0
  89. package/build/cli/commands/task/shared.js +131 -0
  90. package/build/cli/commands/task/start/handler.js +6 -0
  91. package/build/cli/commands/task/start/meta.js +8 -0
  92. package/build/cli/commands/task/stop/handler.js +17 -0
  93. package/build/cli/commands/task/stop/meta.js +8 -0
  94. package/build/cli/commands/task/task/handler.js +5 -0
  95. package/build/cli/commands/task/task/meta.js +11 -0
  96. package/build/cli/commands/task/update/handler.js +18 -0
  97. package/build/cli/commands/task/update/meta.js +8 -0
  98. package/build/cli/commands/task/view/handler.js +14 -0
  99. package/build/cli/commands/task/view/meta.js +8 -0
  100. package/build/cli/completion.js +26 -27
  101. package/build/cli/flags.js +79 -2
  102. package/build/cli/help.js +27 -49
  103. package/build/cli/index.js +121 -374
  104. package/build/cli/output-stream-error-policy.js +17 -0
  105. package/build/cli/parse-flags.js +197 -0
  106. package/build/cli/parse-metadata.js +129 -0
  107. package/build/cli/parse-selectors.js +65 -0
  108. package/build/cli/parse.js +46 -313
  109. package/build/cli/projection-address.js +5 -0
  110. package/build/cli/render/arc.js +1 -1
  111. package/build/cli/render/errors.js +4 -3
  112. package/build/cli/render/format.js +14 -0
  113. package/build/cli/render/kanshi.js +106 -0
  114. package/build/cli/render/petition.js +24 -1
  115. package/build/cli/render/projection-activity.js +5 -1
  116. package/build/cli/render/shared.js +2 -2
  117. package/build/cli/render/status.js +79 -13
  118. package/build/cli/render/task.js +113 -0
  119. package/build/cli/render/wait.js +23 -3
  120. package/build/cli/types.js +1 -1
  121. package/build/config/{akuma-loader_v2.js → akuma-loader.js} +7 -4
  122. package/build/config/env.js +9 -4
  123. package/build/config/settings/disease.js +26 -0
  124. package/build/config/settings/knobs.js +8 -0
  125. package/build/config/settings/loader.js +244 -0
  126. package/build/config/settings/schema.js +276 -0
  127. package/build/core/addressing.js +1 -1
  128. package/build/core/amend.js +5 -8
  129. package/build/core/arc.js +7 -8
  130. package/build/core/bind-workspace.js +123 -0
  131. package/build/core/bind.js +75 -155
  132. package/build/core/call/call.js +229 -0
  133. package/build/core/call/context.js +251 -0
  134. package/build/core/call/execution.js +217 -0
  135. package/build/core/call/prompt.js +42 -0
  136. package/build/core/call/reference.js +24 -0
  137. package/build/core/call-persist.js +10 -3
  138. package/build/core/claim-delivery.js +247 -0
  139. package/build/core/claim.js +39 -277
  140. package/build/core/context.js +2 -1
  141. package/build/core/{render.js → contract-view.js} +12 -140
  142. package/build/core/draft.js +107 -9
  143. package/build/core/entry.js +9 -1
  144. package/build/core/execution-coordinate.js +4 -20
  145. package/build/core/execution-pact.js +16 -31
  146. package/build/core/forfeit.js +35 -22
  147. package/build/core/hints.js +2 -2
  148. package/build/core/log.js +2 -2
  149. package/build/core/path-coordinate.js +27 -0
  150. package/build/core/petition-claim-gates.js +8 -6
  151. package/build/core/petition-preview.js +97 -0
  152. package/build/core/petition-run.js +5 -7
  153. package/build/core/petition.js +39 -26
  154. package/build/core/projection/generation/database.js +306 -0
  155. package/build/core/projection/generation/identity.js +84 -0
  156. package/build/core/projection/generation/model.js +201 -0
  157. package/build/core/projection/generation/store.js +73 -0
  158. package/build/core/projection/generation/transitions.js +258 -0
  159. package/build/core/projection/heart.js +0 -307
  160. package/build/core/projection/tell/database.js +109 -0
  161. package/build/core/projection/tell/model.js +97 -0
  162. package/build/core/{projection-tells.js → projection/tell/store.js} +3 -158
  163. package/build/core/projection-activity.js +23 -2
  164. package/build/core/projection-coordinate.js +14 -2
  165. package/build/core/projection-core.js +2 -1
  166. package/build/core/projection-execution-observer.js +259 -0
  167. package/build/core/projection-generation-continuation.js +1 -1
  168. package/build/core/projection-generation-execution.js +90 -20
  169. package/build/core/projection-generation-launcher.js +1 -1
  170. package/build/core/projection-generation-runner.js +198 -4
  171. package/build/core/projection-identity.js +1 -1
  172. package/build/core/projection-kill.js +50 -17
  173. package/build/core/projection-life-observer.js +1 -1
  174. package/build/core/projection-life-protocol.js +10 -0
  175. package/build/core/projection-mint.js +1 -1
  176. package/build/core/projection-status.js +45 -32
  177. package/build/core/projection-wait.js +12 -2
  178. package/build/core/projection-wake.js +5 -2
  179. package/build/core/{queue_v2.js → queue.js} +2 -1
  180. package/build/core/registry.js +1 -1
  181. package/build/core/renew.js +9 -11
  182. package/build/core/response-artifact-catalog-sqlite.js +112 -0
  183. package/build/core/response-artifact-catalog.js +7 -0
  184. package/build/core/seal.js +44 -16
  185. package/build/core/status/board.js +289 -0
  186. package/build/core/status/drift.js +99 -0
  187. package/build/core/status/lifecycle.js +84 -0
  188. package/build/core/status/reconciliation.js +131 -0
  189. package/build/core/stored-agent-event.js +28 -4
  190. package/build/core/target-ref.js +10 -0
  191. package/build/core/task/board.js +175 -0
  192. package/build/core/task/commands.js +211 -0
  193. package/build/core/task/document.js +189 -0
  194. package/build/core/task/model.js +1 -0
  195. package/build/core/task/settlement-git.js +207 -0
  196. package/build/core/task/settlement-policy.js +82 -0
  197. package/build/core/task/source-board.js +84 -0
  198. package/build/core/task/source-model.js +1 -0
  199. package/build/core/task/validation.js +44 -0
  200. package/build/core/task-contract.js +237 -0
  201. package/build/core/task-doctor.js +14 -0
  202. package/build/core/task-git-actor.js +38 -0
  203. package/build/core/task-git-runtime.js +37 -0
  204. package/build/core/task-git-store.js +385 -0
  205. package/build/core/task-repository.js +1 -0
  206. package/build/core/task-store-repository.js +86 -0
  207. package/build/core/task-store.js +1 -0
  208. package/build/core/task-worktree.js +51 -0
  209. package/build/core/task.js +4 -0
  210. package/build/core/transcripts.js +138 -56
  211. package/build/core/validation.js +17 -0
  212. package/build/core/verdict.js +2 -2
  213. package/build/core/worktree-path.js +33 -8
  214. package/build/flow-error.js +5 -2
  215. package/build/generated/version.js +1 -1
  216. package/build/git/branches.js +33 -9
  217. package/build/git/commits.js +3 -0
  218. package/build/git/core.js +9 -0
  219. package/build/git/diff/parsers.js +0 -94
  220. package/build/index.js +2 -0
  221. package/build/keiyaku-constants.js +2 -0
  222. package/build/keiyaku.js +4 -3
  223. package/package.json +3 -2
  224. package/skills/keiyaku/SKILL.md +30 -13
  225. package/skills/keiyaku-akuma/SKILL.md +30 -57
  226. package/skills/keiyaku-task/SKILL.md +51 -0
  227. package/skills/keiyaku-workflow/SKILL.md +71 -0
  228. package/build/agents/harness/pump.js +0 -158
  229. package/build/agents/providers/codex-app-server.js +0 -864
  230. package/build/agents/providers/opencode-sdk.js +0 -363
  231. package/build/agents/providers/pi.js +0 -557
  232. package/build/config/settings.js +0 -533
  233. package/build/core/call.js +0 -686
  234. package/build/core/projection/generation.js +0 -412
  235. package/build/core/projection/identity.js +0 -81
  236. package/build/core/projection/mint.js +0 -174
  237. package/build/core/projection-generation-store.js +0 -707
  238. package/build/core/status.js +0 -539
@@ -1,7 +1,5 @@
1
1
  import * as path from "node:path";
2
- import { nativePolicyOwnership } from "../config/provider-policy-ownership.js";
3
- import { FlowError } from "../flow-error.js";
4
- import { buildCodexAppServerWorkspaceWriteSandboxPolicy, configOwnsApprovalPolicy, configOwnsSandboxPolicy, } from "./providers/codex-app-server.js";
2
+ import { FlowError } from "../../flow-error.js";
5
3
  const ACCESS_VALUES = new Set(["read", "write", "auto"]);
6
4
  const NETWORK_VALUES = new Set(["disabled", "enabled"]);
7
5
  const WEB_SEARCH_VALUES = new Set(["disabled", "cached", "live"]);
@@ -110,6 +108,42 @@ function assertEffortAllowed(effort, options) {
110
108
  return;
111
109
  throw new FlowError("INVALID_EFFORT_OVERRIDE", `Effort '${effort}' is not permitted; legal values: ${options.join(", ")}.`);
112
110
  }
111
+ /** Effective effort requires an explicit effective model. Model without effort remains legal. */
112
+ function assertEffortRequiresModel(model, effort, kind, akumaName) {
113
+ if (effort === undefined || model !== undefined)
114
+ return;
115
+ if (kind === "profile") {
116
+ throw new FlowError("INVALID_SETTINGS", `Akuma '${akumaName ?? ""}' sets effort '${effort}' without a model; set model whenever effort is configured.`);
117
+ }
118
+ throw new FlowError("INVALID_EFFORT_OVERRIDE", `Effort '${effort}' requires an explicit model.`);
119
+ }
120
+ function providerEffortAndModel(provider) {
121
+ switch (provider.kind) {
122
+ case "codex-sdk": {
123
+ const model = typeof provider.threadOptions.model === "string" ? provider.threadOptions.model : undefined;
124
+ const effort = typeof provider.threadOptions.modelReasoningEffort === "string"
125
+ ? provider.threadOptions.modelReasoningEffort
126
+ : undefined;
127
+ return { model, effort };
128
+ }
129
+ case "codex-app-server":
130
+ case "claude-agent-sdk":
131
+ case "opencode-sdk":
132
+ return { model: provider.model, effort: provider.effort };
133
+ case "pi":
134
+ return { model: provider.model, effort: provider.thinkingLevel };
135
+ }
136
+ }
137
+ function assertSnapshotEffortRequiresModel(snapshot) {
138
+ const fromAkuma = { model: snapshot.akuma.model, effort: snapshot.akuma.effort };
139
+ if (fromAkuma.effort !== undefined && fromAkuma.model === undefined) {
140
+ throw snapshotError("akuma.effort", "requires akuma.model");
141
+ }
142
+ const fromProvider = providerEffortAndModel(snapshot.provider);
143
+ if (fromProvider.effort !== undefined && fromProvider.model === undefined) {
144
+ throw snapshotError(`provider.${snapshot.provider.kind === "codex-sdk" ? "threadOptions.modelReasoningEffort" : snapshot.provider.kind === "pi" ? "thinkingLevel" : "effort"}`, "requires an explicit model");
145
+ }
146
+ }
113
147
  function parsePolicy(value) {
114
148
  const policy = objectAt(value, "akuma.policy");
115
149
  exactKeys(policy, ["access", "network", "webSearch"], "akuma.policy");
@@ -153,6 +187,21 @@ function parseProviderCommon(provider) {
153
187
  function optionalJsonObject(provider, key) {
154
188
  return key in provider ? cloneJsonObject(provider[key], `provider.${key}`) : undefined;
155
189
  }
190
+ function optionalStringRecord(provider, key) {
191
+ if (!(key in provider))
192
+ return undefined;
193
+ const value = provider[key];
194
+ if (!isPlainObject(value))
195
+ throw snapshotError(`provider.${key}`, "must be a plain JSON object");
196
+ const result = {};
197
+ for (const [entryKey, entryValue] of Object.entries(value)) {
198
+ if (typeof entryValue !== "string") {
199
+ throw snapshotError(`provider.${key}.${entryKey}`, "must be a string");
200
+ }
201
+ result[entryKey] = entryValue;
202
+ }
203
+ return Object.freeze(result);
204
+ }
156
205
  function parseSandboxPolicy(value) {
157
206
  const sandbox = objectAt(value, "provider.sandboxPolicy");
158
207
  exactKeys(sandbox, ["type", "writableRoots", "networkAccess", "excludeTmpdirEnvVar", "excludeSlashTmp"], "provider.sandboxPolicy");
@@ -198,7 +247,7 @@ function parseProvider(value) {
198
247
  return Object.freeze({ ...common, kind, ...(executable !== undefined ? { executable } : {}), ...(profile !== undefined ? { profile } : {}), ...(config !== undefined ? { config } : {}), threadOptions: cloneJsonObject(provider.threadOptions, "provider.threadOptions") });
199
248
  }
200
249
  case "codex-app-server": {
201
- exactKeys(provider, ["name", "source", "kind", "executable", "profile", "config", "model", "effort", "sandboxPolicy", "approvalPolicy"], "provider");
250
+ exactKeys(provider, ["name", "source", "kind", "executable", "profile", "config", "model", "effort", "sandboxPolicy", "approvalPolicy", "env"], "provider");
202
251
  if ("approvalPolicy" in provider && provider.approvalPolicy !== "never")
203
252
  throw snapshotError("provider.approvalPolicy", "must equal 'never'");
204
253
  const executable = optionalString(provider, "executable", "provider");
@@ -207,10 +256,11 @@ function parseProvider(value) {
207
256
  const model = optionalString(provider, "model", "provider");
208
257
  const effort = optionalString(provider, "effort", "provider");
209
258
  const sandboxPolicy = "sandboxPolicy" in provider ? parseSandboxPolicy(provider.sandboxPolicy) : undefined;
210
- return Object.freeze({ ...common, kind, ...(executable !== undefined ? { executable } : {}), ...(profile !== undefined ? { profile } : {}), ...(config !== undefined ? { config } : {}), ...(model !== undefined ? { model } : {}), ...(effort !== undefined ? { effort } : {}), ...(sandboxPolicy !== undefined ? { sandboxPolicy } : {}), ...(provider.approvalPolicy === "never" ? { approvalPolicy: "never" } : {}) });
259
+ const env = optionalStringRecord(provider, "env");
260
+ return Object.freeze({ ...common, kind, ...(executable !== undefined ? { executable } : {}), ...(profile !== undefined ? { profile } : {}), ...(config !== undefined ? { config } : {}), ...(model !== undefined ? { model } : {}), ...(effort !== undefined ? { effort } : {}), ...(sandboxPolicy !== undefined ? { sandboxPolicy } : {}), ...(provider.approvalPolicy === "never" ? { approvalPolicy: "never" } : {}), ...(env !== undefined ? { env } : {}) });
211
261
  }
212
262
  case "claude-agent-sdk": {
213
- exactKeys(provider, ["name", "source", "kind", "executable", "model", "effort", "settingSources", "permissionMode", "allowDangerouslySkipPermissions", "disallowedTools"], "provider");
263
+ exactKeys(provider, ["name", "source", "kind", "executable", "model", "effort", "settingSources", "permissionMode", "allowDangerouslySkipPermissions", "disallowedTools", "env"], "provider");
214
264
  const modes = new Set(["default", "plan", "acceptEdits", "bypassPermissions"]);
215
265
  const permissionMode = requiredEnum(provider, "permissionMode", "provider", modes);
216
266
  if (permissionMode === "bypassPermissions") {
@@ -240,20 +290,23 @@ function parseProvider(value) {
240
290
  const executable = optionalString(provider, "executable", "provider");
241
291
  const model = optionalString(provider, "model", "provider");
242
292
  const effort = optionalString(provider, "effort", "provider");
243
- return Object.freeze({ ...common, kind, ...(executable !== undefined ? { executable } : {}), ...(model !== undefined ? { model } : {}), ...(effort !== undefined ? { effort } : {}), ...(settingSources !== undefined ? { settingSources } : {}), permissionMode, ...(permissionMode === "bypassPermissions" ? { allowDangerouslySkipPermissions: true } : {}), ...(disallowedTools !== undefined ? { disallowedTools } : {}) });
293
+ const env = optionalStringRecord(provider, "env");
294
+ return Object.freeze({ ...common, kind, ...(executable !== undefined ? { executable } : {}), ...(model !== undefined ? { model } : {}), ...(effort !== undefined ? { effort } : {}), ...(settingSources !== undefined ? { settingSources } : {}), permissionMode, ...(permissionMode === "bypassPermissions" ? { allowDangerouslySkipPermissions: true } : {}), ...(disallowedTools !== undefined ? { disallowedTools } : {}), ...(env !== undefined ? { env } : {}) });
244
295
  }
245
296
  case "opencode-sdk": {
246
- exactKeys(provider, ["name", "source", "kind", "executable", "model", "effort"], "provider");
297
+ exactKeys(provider, ["name", "source", "kind", "executable", "model", "effort", "env"], "provider");
247
298
  const executable = optionalString(provider, "executable", "provider");
248
299
  const model = optionalString(provider, "model", "provider");
249
300
  const effort = optionalString(provider, "effort", "provider");
250
- return Object.freeze({ ...common, kind, ...(executable !== undefined ? { executable } : {}), ...(model !== undefined ? { model } : {}), ...(effort !== undefined ? { effort } : {}) });
301
+ const env = optionalStringRecord(provider, "env");
302
+ return Object.freeze({ ...common, kind, ...(executable !== undefined ? { executable } : {}), ...(model !== undefined ? { model } : {}), ...(effort !== undefined ? { effort } : {}), ...(env !== undefined ? { env } : {}) });
251
303
  }
252
304
  case "pi": {
253
- exactKeys(provider, ["name", "source", "kind", "model", "thinkingLevel"], "provider");
305
+ exactKeys(provider, ["name", "source", "kind", "model", "thinkingLevel", "env"], "provider");
254
306
  const model = optionalString(provider, "model", "provider");
255
307
  const thinkingLevel = optionalString(provider, "thinkingLevel", "provider");
256
- return Object.freeze({ ...common, kind, ...(model !== undefined ? { model } : {}), ...(thinkingLevel !== undefined ? { thinkingLevel } : {}) });
308
+ const env = optionalStringRecord(provider, "env");
309
+ return Object.freeze({ ...common, kind, ...(model !== undefined ? { model } : {}), ...(thinkingLevel !== undefined ? { thinkingLevel } : {}), ...(env !== undefined ? { env } : {}) });
257
310
  }
258
311
  default:
259
312
  throw snapshotError("provider.kind", `has invalid value '${kind}'`);
@@ -268,72 +321,13 @@ export function parseResolvedAkumaLaunchSnapshot(value) {
268
321
  throw snapshotError("akuma", "is required");
269
322
  if (!("provider" in snapshot))
270
323
  throw snapshotError("provider", "is required");
271
- return Object.freeze({ version: 1, akuma: parseAkuma(snapshot.akuma), provider: parseProvider(snapshot.provider) });
272
- }
273
- export function resolveAkumaLaunchSnapshot(selected, input) {
274
- const model = input.model ?? selected.profile.model;
275
- const effort = input.effort ?? selected.profile.effort;
276
- assertEffortAllowed(effort, selected.profile.effortOptions);
277
- const policy = {
278
- ...(selected.profile.access !== undefined ? { access: selected.profile.access } : {}),
279
- ...(selected.profile.network !== undefined ? { network: selected.profile.network } : {}),
280
- ...(selected.profile.webSearch !== undefined ? { webSearch: selected.profile.webSearch } : {}),
281
- };
282
- const akuma = {
283
- name: selected.name,
284
- source: selected.definition.source,
285
- body: selected.definition.body,
286
- ...(selected.profile.description !== undefined ? { description: selected.profile.description } : {}),
287
- ...(model !== undefined ? { model } : {}),
288
- ...(effort !== undefined ? { effort } : {}),
289
- ...(selected.profile.effortOptions !== undefined ? { effortOptions: selected.profile.effortOptions } : {}),
290
- policy,
291
- };
292
- const instance = selected.profile.providerInstance;
293
- const common = { name: selected.profile.provider, source: selected.profile.providerSource, kind: instance.kind };
294
- let provider;
295
- switch (instance.kind) {
296
- case "codex-sdk": {
297
- const threadOptions = { ...(instance.threadOptions ?? {}) };
298
- const ownership = nativePolicyOwnership(selected.profile.provider, instance);
299
- if (ownership.access.length === 0) {
300
- threadOptions.sandboxMode = selected.profile.access === "read" ? "read-only" : selected.profile.access === "auto" ? "danger-full-access" : "workspace-write";
301
- }
302
- if (ownership.network.length === 0)
303
- threadOptions.networkAccessEnabled = selected.profile.network === "enabled";
304
- if (ownership.webSearch.length === 0)
305
- threadOptions.webSearchMode = selected.profile.webSearch ?? "disabled";
306
- if (model !== undefined)
307
- threadOptions.model = model;
308
- if (effort !== undefined)
309
- threadOptions.modelReasoningEffort = effort;
310
- threadOptions.workingDirectory = input.executionCwd;
311
- threadOptions.skipGitRepoCheck = true;
312
- provider = { ...common, ...(instance.executable !== undefined ? { executable: instance.executable } : {}), ...(instance.profile !== undefined ? { profile: instance.profile } : {}), ...(instance.config !== undefined ? { config: instance.config } : {}), threadOptions };
313
- break;
314
- }
315
- case "codex-app-server": {
316
- const roots = [path.resolve(input.executionCwd), ...(instance.writableRoots ?? []).map((root) => path.resolve(input.projectRoot, root))];
317
- const writableRoots = [...new Set(roots)];
318
- provider = { ...common, ...(instance.executable !== undefined ? { executable: instance.executable } : {}), ...(instance.profile !== undefined ? { profile: instance.profile } : {}), ...(instance.config !== undefined ? { config: instance.config } : {}), ...(model !== undefined ? { model } : {}), ...(effort !== undefined ? { effort } : {}), ...(!configOwnsSandboxPolicy(instance.config) ? { sandboxPolicy: buildCodexAppServerWorkspaceWriteSandboxPolicy({ writableRoots, networkAccess: selected.profile.network === "enabled" }) } : {}), ...(!configOwnsApprovalPolicy(instance.config) ? { approvalPolicy: "never" } : {}) };
319
- break;
320
- }
321
- case "claude-agent-sdk": {
322
- const permissionMode = selected.profile.access === "read" ? "plan" : selected.profile.access === "write" ? "acceptEdits" : selected.profile.access === "auto" ? "bypassPermissions" : "default";
323
- provider = { ...common, ...(instance.executable !== undefined ? { executable: instance.executable } : {}), ...(model !== undefined ? { model } : {}), ...(effort !== undefined ? { effort } : {}), ...(instance.settingSources !== undefined ? { settingSources: instance.settingSources } : {}), permissionMode, ...(permissionMode === "bypassPermissions" ? { allowDangerouslySkipPermissions: true } : {}), ...(selected.profile.webSearch === "disabled" ? { disallowedTools: ["WebSearch"] } : {}) };
324
- break;
325
- }
326
- case "opencode-sdk":
327
- provider = { ...common, ...(instance.executable !== undefined ? { executable: instance.executable } : {}), ...(model !== undefined ? { model } : {}), ...(effort !== undefined ? { effort } : {}) };
328
- break;
329
- case "pi":
330
- provider = { ...common, ...(model !== undefined ? { model } : {}), ...(effort !== undefined ? { thinkingLevel: effort } : {}) };
331
- break;
332
- }
333
- return parseResolvedAkumaLaunchSnapshot({ version: 1, akuma, provider });
324
+ const parsed = Object.freeze({ version: 1, akuma: parseAkuma(snapshot.akuma), provider: parseProvider(snapshot.provider) });
325
+ assertSnapshotEffortRequiresModel(parsed);
326
+ return parsed;
334
327
  }
335
328
  export function applySnapshotEffort(snapshot, effort) {
336
329
  assertEffortAllowed(effort, snapshot.akuma.effortOptions);
330
+ assertEffortRequiresModel(snapshot.akuma.model, effort, "override");
337
331
  const akuma = { ...snapshot.akuma, effort };
338
332
  let provider;
339
333
  switch (snapshot.provider.kind) {
@@ -351,3 +345,4 @@ export function applySnapshotEffort(snapshot, effort) {
351
345
  }
352
346
  return parseResolvedAkumaLaunchSnapshot({ version: 1, akuma, provider });
353
347
  }
348
+ export { assertEffortAllowed, assertEffortRequiresModel };
@@ -0,0 +1,72 @@
1
+ import * as path from "node:path";
2
+ import { nativePolicyOwnership } from "../../config/provider-policy-ownership.js";
3
+ import { buildCodexAppServerWorkspaceWriteSandboxPolicy, configOwnsApprovalPolicy, configOwnsSandboxPolicy, } from "../providers/codex-app-server/adapter.js";
4
+ import { assertEffortAllowed, assertEffortRequiresModel, parseResolvedAkumaLaunchSnapshot, } from "./model.js";
5
+ export function resolveAkumaLaunchSnapshot(selected, input) {
6
+ const model = input.model ?? selected.profile.model;
7
+ const effort = input.effort ?? selected.profile.effort;
8
+ assertEffortAllowed(effort, selected.profile.effortOptions);
9
+ if (input.effort !== undefined) {
10
+ assertEffortRequiresModel(model, effort, "override");
11
+ }
12
+ else {
13
+ assertEffortRequiresModel(model, effort, "profile", selected.name);
14
+ }
15
+ const policy = {
16
+ ...(selected.profile.access !== undefined ? { access: selected.profile.access } : {}),
17
+ ...(selected.profile.network !== undefined ? { network: selected.profile.network } : {}),
18
+ ...(selected.profile.webSearch !== undefined ? { webSearch: selected.profile.webSearch } : {}),
19
+ };
20
+ const akuma = {
21
+ name: selected.name,
22
+ source: selected.definition.source,
23
+ body: selected.definition.body,
24
+ ...(selected.profile.description !== undefined ? { description: selected.profile.description } : {}),
25
+ ...(model !== undefined ? { model } : {}),
26
+ ...(effort !== undefined ? { effort } : {}),
27
+ ...(selected.profile.effortOptions !== undefined ? { effortOptions: selected.profile.effortOptions } : {}),
28
+ policy,
29
+ };
30
+ const instance = selected.profile.providerInstance;
31
+ const common = { name: selected.profile.provider, source: selected.profile.providerSource, kind: instance.kind };
32
+ let provider;
33
+ switch (instance.kind) {
34
+ case "codex-sdk": {
35
+ const threadOptions = { ...(instance.threadOptions ?? {}) };
36
+ const ownership = nativePolicyOwnership(selected.profile.provider, instance);
37
+ if (ownership.access.length === 0) {
38
+ threadOptions.sandboxMode = selected.profile.access === "read" ? "read-only" : selected.profile.access === "auto" ? "danger-full-access" : "workspace-write";
39
+ }
40
+ if (ownership.network.length === 0)
41
+ threadOptions.networkAccessEnabled = selected.profile.network === "enabled";
42
+ if (ownership.webSearch.length === 0)
43
+ threadOptions.webSearchMode = selected.profile.webSearch ?? "disabled";
44
+ if (model !== undefined)
45
+ threadOptions.model = model;
46
+ if (effort !== undefined)
47
+ threadOptions.modelReasoningEffort = effort;
48
+ threadOptions.workingDirectory = input.executionCwd;
49
+ threadOptions.skipGitRepoCheck = true;
50
+ provider = { ...common, ...(instance.executable !== undefined ? { executable: instance.executable } : {}), ...(instance.profile !== undefined ? { profile: instance.profile } : {}), ...(instance.config !== undefined ? { config: instance.config } : {}), threadOptions };
51
+ break;
52
+ }
53
+ case "codex-app-server": {
54
+ const roots = [path.resolve(input.executionCwd), ...(instance.writableRoots ?? []).map((root) => path.resolve(input.projectRoot, root))];
55
+ const writableRoots = [...new Set(roots)];
56
+ provider = { ...common, ...(instance.executable !== undefined ? { executable: instance.executable } : {}), ...(instance.profile !== undefined ? { profile: instance.profile } : {}), ...(instance.config !== undefined ? { config: instance.config } : {}), ...(model !== undefined ? { model } : {}), ...(effort !== undefined ? { effort } : {}), ...(!configOwnsSandboxPolicy(instance.config) ? { sandboxPolicy: buildCodexAppServerWorkspaceWriteSandboxPolicy({ writableRoots, networkAccess: selected.profile.network === "enabled" }) } : {}), ...(!configOwnsApprovalPolicy(instance.config) ? { approvalPolicy: "never" } : {}), ...(instance.env !== undefined ? { env: instance.env } : {}) };
57
+ break;
58
+ }
59
+ case "claude-agent-sdk": {
60
+ const permissionMode = selected.profile.access === "read" ? "plan" : selected.profile.access === "write" ? "acceptEdits" : selected.profile.access === "auto" ? "bypassPermissions" : "default";
61
+ provider = { ...common, ...(instance.executable !== undefined ? { executable: instance.executable } : {}), ...(model !== undefined ? { model } : {}), ...(effort !== undefined ? { effort } : {}), ...(instance.settingSources !== undefined ? { settingSources: instance.settingSources } : {}), permissionMode, ...(permissionMode === "bypassPermissions" ? { allowDangerouslySkipPermissions: true } : {}), ...(selected.profile.webSearch === "disabled" ? { disallowedTools: ["WebSearch"] } : {}), ...(instance.env !== undefined ? { env: instance.env } : {}) };
62
+ break;
63
+ }
64
+ case "opencode-sdk":
65
+ provider = { ...common, ...(instance.executable !== undefined ? { executable: instance.executable } : {}), ...(model !== undefined ? { model } : {}), ...(effort !== undefined ? { effort } : {}), ...(instance.env !== undefined ? { env: instance.env } : {}) };
66
+ break;
67
+ case "pi":
68
+ provider = { ...common, ...(model !== undefined ? { model } : {}), ...(effort !== undefined ? { thinkingLevel: effort } : {}), ...(instance.env !== undefined ? { env: instance.env } : {}) };
69
+ break;
70
+ }
71
+ return parseResolvedAkumaLaunchSnapshot({ version: 1, akuma, provider });
72
+ }
@@ -51,7 +51,7 @@ export async function createOpencodeServer(options = {}) {
51
51
  const startupTimeoutMs = options.startupTimeoutMs ?? DEFAULT_STARTUP_TIMEOUT_MS;
52
52
  const child = spawn(executable, [OPENCODE_SERVE_SUBCOMMAND, OPENCODE_HOSTNAME_FLAG, hostname, OPENCODE_PORT_FLAG, String(port)], {
53
53
  cwd: directory,
54
- env: { ...process.env, ...(options.env ?? {}) },
54
+ env: options.env !== undefined ? { ...options.env } : { ...process.env },
55
55
  stdio: ["ignore", "pipe", "pipe"],
56
56
  });
57
57
  let exited = false;
@@ -60,10 +60,30 @@ export async function createOpencodeServer(options = {}) {
60
60
  child.on("error", (error) => { stderr += `${stderr ? " " : ""}${error.message}`; });
61
61
  child.on("close", () => { exited = true; });
62
62
  const client = createOpencodeClient({ baseUrl: url, directory });
63
- const stop = async () => {
63
+ let gracefulStop;
64
+ let forceStop;
65
+ const stop = async (mode = "graceful") => {
64
66
  if (exited)
65
67
  return;
66
- await new Promise((resolve) => {
68
+ if (mode === "force") {
69
+ forceStop ??= new Promise((resolve, reject) => {
70
+ child.once("close", resolve);
71
+ try {
72
+ if (!child.kill("SIGKILL") && !exited)
73
+ reject(new Error("OpenCode server force kill failed"));
74
+ }
75
+ catch (error) {
76
+ reject(error);
77
+ }
78
+ });
79
+ await forceStop;
80
+ return;
81
+ }
82
+ if (forceStop) {
83
+ await forceStop;
84
+ return;
85
+ }
86
+ gracefulStop ??= new Promise((resolve) => {
67
87
  let settled = false;
68
88
  let forceKill;
69
89
  const finish = () => {
@@ -82,6 +102,7 @@ export async function createOpencodeServer(options = {}) {
82
102
  }, SERVER_SHUTDOWN_FORCE_KILL_MS);
83
103
  forceKill.unref();
84
104
  });
105
+ await gracefulStop;
85
106
  };
86
107
  try {
87
108
  await waitForServerReady(client, directory, startupTimeoutMs, options.signal);