@astrosheep/keiyaku 2.9.2 → 2.9.4

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/build/.tsbuildinfo +1 -1
  2. package/build/agents/call-terms.js +13 -94
  3. package/build/agents/harness/activity-values.js +16 -0
  4. package/build/agents/harness/event-persistence.js +218 -0
  5. package/build/agents/harness/execution-handle.js +25 -222
  6. package/build/agents/harness/index.js +3 -1
  7. package/build/agents/harness/outcome.js +47 -4
  8. package/build/agents/harness/projection.js +42 -59
  9. package/build/agents/harness/provider-adapter.js +58 -0
  10. package/build/agents/harness/router.js +11 -187
  11. package/build/agents/harness/runtime.js +17 -4
  12. package/build/agents/harness/session.js +15 -0
  13. package/build/agents/launch-snapshot/model.js +15 -236
  14. package/build/agents/launch-snapshot/parse-helpers.js +114 -0
  15. package/build/agents/launch-snapshot/resolve.js +17 -43
  16. package/build/agents/opencode-sdk.js +45 -12
  17. package/build/agents/providers/claude-agent-sdk/adapter.js +6 -17
  18. package/build/agents/providers/claude-agent-sdk/registration.js +214 -0
  19. package/build/agents/providers/claude-agent-sdk/session-schema.js +2 -0
  20. package/build/agents/providers/codex-app-server/adapter.js +50 -53
  21. package/build/agents/providers/codex-app-server/events.js +67 -11
  22. package/build/agents/providers/codex-app-server/identity.js +1 -0
  23. package/build/agents/providers/codex-app-server/policy.js +29 -0
  24. package/build/agents/providers/codex-app-server/registration.js +248 -0
  25. package/build/agents/providers/codex-app-server/session-schema.js +6 -0
  26. package/build/agents/providers/codex-app-server/session.js +23 -17
  27. package/build/agents/providers/codex-app-server/terms.js +1 -0
  28. package/build/agents/providers/opencode-sdk/adapter.js +94 -50
  29. package/build/agents/providers/opencode-sdk/events.js +8 -4
  30. package/build/agents/providers/opencode-sdk/registration.js +135 -0
  31. package/build/agents/providers/opencode-sdk/session-schema.js +2 -0
  32. package/build/agents/providers/opencode-sdk/session.js +21 -14
  33. package/build/agents/providers/opencode-sdk/terms.js +1 -0
  34. package/build/agents/providers/pi/adapter.js +36 -30
  35. package/build/agents/providers/pi/registration.js +145 -0
  36. package/build/agents/providers/pi/session-schema.js +6 -0
  37. package/build/agents/providers/pi/terms.js +1 -0
  38. package/build/agents/providers/registration.js +7 -0
  39. package/build/agents/providers/registry.js +76 -0
  40. package/build/agents/selector.js +2 -29
  41. package/build/agents/types.js +8 -0
  42. package/build/artifact-directories.js +22 -0
  43. package/build/cli/commands/akuma/akuma/handler.js +1 -1
  44. package/build/cli/commands/akuma/view/handler.js +5 -4
  45. package/build/cli/commands/akuma.js +6 -0
  46. package/build/cli/commands/contract/amend/handler.js +8 -2
  47. package/build/cli/commands/contract/arc/handler.js +7 -1
  48. package/build/cli/commands/contract/bind/handler.js +4 -3
  49. package/build/cli/commands/contract/bind/meta.js +34 -7
  50. package/build/cli/commands/contract/forfeit/handler.js +4 -4
  51. package/build/cli/commands/contract/log/handler.js +3 -3
  52. package/build/cli/commands/contract/petition/handler.js +4 -6
  53. package/build/cli/commands/contract/renew/handler.js +20 -6
  54. package/build/cli/commands/contract/renew/meta.js +5 -4
  55. package/build/cli/commands/metadata.js +58 -0
  56. package/build/cli/commands/projection/call/handler.js +6 -5
  57. package/build/cli/commands/projection/kill/handler.js +16 -32
  58. package/build/cli/commands/projection/shared.js +28 -0
  59. package/build/cli/commands/projection/status/handler.js +1 -1
  60. package/build/cli/commands/projection/tell/handler.js +14 -30
  61. package/build/cli/commands/projection/wait/handler.js +45 -22
  62. package/build/cli/commands/projection/wait/meta.js +7 -2
  63. package/build/cli/commands/registry.js +2 -54
  64. package/build/cli/commands/shared.js +10 -7
  65. package/build/cli/commands/skills/install/handler.js +2 -5
  66. package/build/cli/commands/skills/skills/handler.js +1 -1
  67. package/build/cli/commands/task/add/handler.js +5 -13
  68. package/build/cli/commands/task/catalog.js +2 -2
  69. package/build/cli/commands/task/done/handler.js +4 -8
  70. package/build/cli/commands/task/drop/handler.js +3 -6
  71. package/build/cli/commands/task/ls/handler.js +3 -5
  72. package/build/cli/commands/task/shared.js +14 -4
  73. package/build/cli/commands/task/{view → show}/handler.js +7 -8
  74. package/build/cli/commands/task/show/meta.js +8 -0
  75. package/build/cli/commands/task/start/handler.js +3 -6
  76. package/build/cli/commands/task/stop/handler.js +4 -8
  77. package/build/cli/commands/task/task/handler.js +1 -1
  78. package/build/cli/commands/task/update/handler.js +4 -8
  79. package/build/cli/completion.js +1 -1
  80. package/build/cli/flags.js +19 -3
  81. package/build/cli/help.js +4 -11
  82. package/build/cli/index.js +57 -83
  83. package/build/cli/missing-subcommand.js +7 -0
  84. package/build/cli/parse-flags.js +14 -5
  85. package/build/cli/parse-metadata.js +3 -3
  86. package/build/cli/parse-selectors.js +1 -1
  87. package/build/cli/parse.js +21 -0
  88. package/build/cli/projection-address.js +7 -12
  89. package/build/cli/render/address.js +41 -37
  90. package/build/cli/render/arc.js +24 -12
  91. package/build/cli/render/call.js +11 -5
  92. package/build/cli/render/errors.js +36 -1
  93. package/build/cli/render/format.js +4 -0
  94. package/build/cli/render/kanshi.js +6 -12
  95. package/build/cli/render/kill.js +9 -0
  96. package/build/cli/render/misc.js +55 -12
  97. package/build/cli/render/petition.js +20 -15
  98. package/build/cli/render/projection-activity.js +3 -0
  99. package/build/cli/render/shared.js +60 -21
  100. package/build/cli/render/skills.js +10 -0
  101. package/build/cli/render/status.js +37 -14
  102. package/build/cli/render/success-response.js +77 -0
  103. package/build/cli/render/task.js +54 -14
  104. package/build/cli/render/tell.js +5 -0
  105. package/build/cli/render/terminal-failure.js +58 -0
  106. package/build/cli/render/types.js +1 -0
  107. package/build/cli/render/wait.js +38 -36
  108. package/build/cli/types.js +1 -1
  109. package/build/config/akuma-loader.js +0 -5
  110. package/build/config/env-keys.js +1 -1
  111. package/build/config/provider-policy-ownership.js +3 -32
  112. package/build/config/settings/disease.js +8 -1
  113. package/build/config/settings/loader.js +11 -3
  114. package/build/config/settings/provider-instance-fields.js +51 -0
  115. package/build/config/settings/schema.js +6 -176
  116. package/build/core/addressing.js +66 -16
  117. package/build/core/amend.js +135 -18
  118. package/build/core/arc.js +19 -67
  119. package/build/core/bind.js +82 -35
  120. package/build/core/call/call.js +15 -9
  121. package/build/core/call/context.js +6 -51
  122. package/build/core/call/execution.js +21 -22
  123. package/build/core/call/prompt.js +14 -1
  124. package/build/core/command-markdown.js +45 -0
  125. package/build/core/context.js +13 -7
  126. package/build/core/contract-view.js +20 -3
  127. package/build/core/draft.js +123 -16
  128. package/build/core/forfeit.js +5 -2
  129. package/build/core/hints.js +1 -75
  130. package/build/core/identifier-slug.js +66 -0
  131. package/build/core/ids.js +25 -11
  132. package/build/core/ledger.js +20 -68
  133. package/build/core/markdown/parser.js +0 -68
  134. package/build/core/markdown/render.js +68 -0
  135. package/build/core/markdown/sections.js +2 -1
  136. package/build/core/outcome-base.js +4 -0
  137. package/build/core/projection/generation/database.js +2 -38
  138. package/build/core/projection/generation/model.js +42 -1
  139. package/build/core/{projection-generation-continuation.js → projection/generation/projection-generation-continuation.js} +3 -3
  140. package/build/core/{projection-generation-execution.js → projection/generation/projection-generation-execution.js} +19 -49
  141. package/build/core/{projection-generation-identity.js → projection/generation/projection-generation-identity.js} +2 -2
  142. package/build/core/{projection-generation-launcher.js → projection/generation/projection-generation-launcher.js} +5 -3
  143. package/build/core/{projection-generation-process.js → projection/generation/projection-generation-process.js} +2 -1
  144. package/build/core/{projection-generation-runner.js → projection/generation/projection-generation-runner.js} +18 -3
  145. package/build/core/projection/generation/store.js +2 -2
  146. package/build/core/projection/generation/transitions.js +1 -1
  147. package/build/core/projection/index.js +27 -0
  148. package/build/core/{projection-activity.js → projection/projection-activity.js} +12 -0
  149. package/build/core/{projection-alias.js → projection/projection-alias.js} +14 -19
  150. package/build/core/projection/projection-coordinate.js +61 -0
  151. package/build/core/{projection-core.js → projection/projection-core.js} +9 -9
  152. package/build/core/{projection-execution-observer.js → projection/projection-execution-observer.js} +2 -57
  153. package/build/core/{projection-identity.js → projection/projection-identity.js} +1 -1
  154. package/build/core/{projection-kill.js → projection/projection-kill.js} +1 -1
  155. package/build/core/{projection-life-observer.js → projection/projection-life-observer.js} +1 -1
  156. package/build/core/{projection-mint.js → projection/projection-mint.js} +10 -10
  157. package/build/core/{projection-status.js → projection/projection-status.js} +98 -25
  158. package/build/core/projection/projection-terminal-failure.js +104 -0
  159. package/build/core/projection/projection-wait.js +278 -0
  160. package/build/core/projection/projection-wake.js +203 -0
  161. package/build/core/provider-loader-ports.js +4 -0
  162. package/build/core/ref-log.js +65 -40
  163. package/build/core/registry.js +63 -10
  164. package/build/core/renew-session.js +128 -0
  165. package/build/core/renew.js +426 -99
  166. package/build/core/scope.js +143 -66
  167. package/build/core/seal.js +139 -35
  168. package/build/core/{claim-delivery.js → settlement/claim-delivery.js} +9 -14
  169. package/build/core/{claim.js → settlement/claim.js} +32 -8
  170. package/build/core/settlement/index.js +19 -0
  171. package/build/core/{petition-claim-gates.js → settlement/petition-claim-gates.js} +22 -18
  172. package/build/core/{petition-forfeit.js → settlement/petition-forfeit.js} +2 -2
  173. package/build/core/{petition-head-guard.js → settlement/petition-head-guard.js} +2 -2
  174. package/build/core/settlement/petition-io.js +1 -0
  175. package/build/core/{petition-preview.js → settlement/petition-preview.js} +1 -1
  176. package/build/core/{petition.js → settlement/petition.js} +12 -10
  177. package/build/core/settlement/queue-read-model.js +143 -0
  178. package/build/core/settlement/queue-seat-allocation.js +156 -0
  179. package/build/core/settlement/queue.js +6 -0
  180. package/build/core/settlement/settlement.js +295 -0
  181. package/build/core/{verdict.js → settlement/verdict.js} +9 -37
  182. package/build/core/status/board.js +24 -23
  183. package/build/core/status/ledger-batch.js +158 -0
  184. package/build/core/status/reconciliation.js +10 -4
  185. package/build/core/stored-agent-event.js +3 -0
  186. package/build/core/task/board.js +40 -4
  187. package/build/core/task/commands.js +30 -21
  188. package/build/core/task/index.js +12 -0
  189. package/build/core/task/settlement-git.js +157 -65
  190. package/build/core/task/settlement-policy.js +54 -24
  191. package/build/core/task/task-contract.js +370 -0
  192. package/build/core/{task-doctor.js → task/task-doctor.js} +1 -1
  193. package/build/core/{task-git-actor.js → task/task-git-actor.js} +5 -10
  194. package/build/core/{task-git-runtime.js → task/task-git-runtime.js} +3 -3
  195. package/build/core/{task-git-store.js → task/task-git-store.js} +92 -29
  196. package/build/core/task/task-repository.js +1 -0
  197. package/build/core/{task-store-repository.js → task/task-store-repository.js} +5 -4
  198. package/build/core/task/task-store.js +1 -0
  199. package/build/core/{task-worktree.js → task/task-worktree.js} +2 -1
  200. package/build/core/task/task.js +5 -0
  201. package/build/core/task/tree.js +37 -0
  202. package/build/core/task/validation.js +5 -2
  203. package/build/core/transcripts.js +15 -3
  204. package/build/core/worktree-path.js +43 -28
  205. package/build/flow-error.js +85 -39
  206. package/build/fs/durability.js +27 -0
  207. package/build/fs/path-coordinate.js +16 -0
  208. package/build/generated/version.js +3 -2
  209. package/build/git/branches.js +2 -1
  210. package/build/git/core.js +106 -2
  211. package/build/git/path-coordinate.js +17 -0
  212. package/build/git/refs.js +57 -0
  213. package/build/git/streaming-batch.js +301 -0
  214. package/build/git/worktree.js +65 -0
  215. package/build/index.js +3 -3
  216. package/build/keiyaku.js +2 -36
  217. package/package.json +4 -10
  218. package/skills/keiyaku/SKILL.md +3 -2
  219. package/skills/keiyaku-akuma/SKILL.md +10 -6
  220. package/skills/keiyaku-task/SKILL.md +1 -1
  221. package/skills/keiyaku-workflow/SKILL.md +25 -4
  222. package/build/agents/providers/codex-sdk.js +0 -329
  223. package/build/cli/commands/task/view/meta.js +0 -8
  224. package/build/core/command-io.js +0 -174
  225. package/build/core/path-coordinate.js +0 -27
  226. package/build/core/petition-claim.js +0 -117
  227. package/build/core/petition-run.js +0 -83
  228. package/build/core/projection-coordinate.js +0 -63
  229. package/build/core/projection-wait.js +0 -165
  230. package/build/core/projection-wake.js +0 -136
  231. package/build/core/queue.js +0 -343
  232. package/build/core/task-contract.js +0 -237
  233. package/build/core/task.js +0 -4
  234. /package/build/{core/task-repository.js → agents/launch-snapshot/types.js} +0 -0
  235. /package/build/{core/task-store.js → agents/providers/claude-agent-sdk/terms.js} +0 -0
  236. /package/build/core/{projection-generation-runtime.js → projection/generation/projection-generation-runtime.js} +0 -0
  237. /package/build/core/{projection-life-protocol.js → projection/projection-life-protocol.js} +0 -0
  238. /package/build/core/{projection-runner-lock.js → projection/projection-runner-lock.js} +0 -0
@@ -0,0 +1,214 @@
1
+ import { z } from "zod";
2
+ import { claudeSettingSourceSchema, executableSchema, providerCommonFields, providerEnvSchema, } from "../../../config/settings/provider-instance-fields.js";
3
+ import { FlowError } from "../../../flow-error.js";
4
+ import { exactKeys, optionalString, optionalStringRecord, requiredEnum, snapshotError, } from "../../launch-snapshot/parse-helpers.js";
5
+ import { SUBAGENT_SESSION_VERSION, subagentSessionEnvelopeSchema, } from "../../session.js";
6
+ import { CLAUDE_AGENT_SDK_PROVIDER } from "./session.js";
7
+ import { claudeSessionSchema } from "./session-schema.js";
8
+ const startClaudeAgentSdk = async (prompt, cwd, options) => {
9
+ const { startClaudeAgentSdk: start } = await import("./adapter.js");
10
+ return start(prompt, cwd, options);
11
+ };
12
+ const CLAUDE_SETTING_SOURCES = new Set(["project", "user", "local"]);
13
+ const ACCESS_VALUES = ["read", "write", "auto"];
14
+ function admitResumeShape(schema, session, resumePath) {
15
+ const envelopeResult = subagentSessionEnvelopeSchema.safeParse(session);
16
+ if (!envelopeResult.success) {
17
+ throw new FlowError("INVALID_RESPONSE_PATH", `Resume path file '${resumePath}' includes an invalid session envelope.`);
18
+ }
19
+ if (session.provider !== CLAUDE_AGENT_SDK_PROVIDER) {
20
+ throw new FlowError("INVALID_RESPONSE_PATH", `Resume path file '${resumePath}' was created with provider '${session.provider}', but the selected subagent resolves to '${CLAUDE_AGENT_SDK_PROVIDER}'. Cross-provider resume is not supported.`);
21
+ }
22
+ if (session.version !== SUBAGENT_SESSION_VERSION) {
23
+ throw new FlowError("INVALID_RESPONSE_PATH", `Resume path file '${resumePath}' uses unsupported session version '${session.version}' for provider '${session.provider}'.`);
24
+ }
25
+ const shapeResult = schema.safeParse(session.handle);
26
+ if (!shapeResult.success) {
27
+ throw new FlowError("INVALID_RESPONSE_PATH", `Resume path file '${resumePath}' includes an invalid session handle for provider '${session.provider}'.`);
28
+ }
29
+ return shapeResult.data;
30
+ }
31
+ export const claudeAgentSdkRegistration = {
32
+ name: CLAUDE_AGENT_SDK_PROVIDER,
33
+ start: startClaudeAgentSdk,
34
+ sessionSchema: claudeSessionSchema,
35
+ effortField: "effort",
36
+ instanceSchema: z
37
+ .object({
38
+ kind: z.literal(CLAUDE_AGENT_SDK_PROVIDER),
39
+ ...providerCommonFields,
40
+ executable: executableSchema.optional(),
41
+ settingSources: z.array(claudeSettingSourceSchema).optional(),
42
+ env: providerEnvSchema,
43
+ })
44
+ .strict(),
45
+ builtinInstance: {
46
+ name: CLAUDE_AGENT_SDK_PROVIDER,
47
+ source: "builtin",
48
+ instance: {
49
+ kind: CLAUDE_AGENT_SDK_PROVIDER,
50
+ executable: "claude",
51
+ settingSources: ["project"],
52
+ },
53
+ },
54
+ builtinAkumaProfiles: [
55
+ { name: "akuma-claude", description: "Default Claude Agent SDK Akuma." },
56
+ ],
57
+ portablePolicy: {
58
+ access: new Set(ACCESS_VALUES),
59
+ network: new Set(),
60
+ webSearch: new Set(["disabled"]),
61
+ },
62
+ maxCaptureChars: (config) => config.claude.execMaxCaptureChars,
63
+ buildCallTerms: ({ snapshot, baseTerms, body }) => {
64
+ const provider = snapshot.provider;
65
+ return {
66
+ ...baseTerms,
67
+ provider: CLAUDE_AGENT_SDK_PROVIDER,
68
+ ...(provider.model !== undefined ? { model: provider.model } : {}),
69
+ ...(provider.effort !== undefined ? { effort: provider.effort } : {}),
70
+ ...(provider.executable !== undefined ? { executable: provider.executable } : {}),
71
+ ...(provider.settingSources !== undefined ? { settingSources: provider.settingSources } : {}),
72
+ permissionMode: provider.permissionMode,
73
+ ...(provider.allowDangerouslySkipPermissions !== undefined
74
+ ? { allowDangerouslySkipPermissions: provider.allowDangerouslySkipPermissions }
75
+ : {}),
76
+ ...(provider.disallowedTools !== undefined ? { disallowedTools: provider.disallowedTools } : {}),
77
+ ...(provider.env !== undefined ? { env: provider.env } : {}),
78
+ systemPrompt: body
79
+ ? { type: "preset", preset: "claude_code", append: body }
80
+ : undefined,
81
+ onCheckpoint() { },
82
+ };
83
+ },
84
+ resolveLaunchProvider: ({ common, instance, model, effort, access, webSearch }) => {
85
+ if (instance.kind !== CLAUDE_AGENT_SDK_PROVIDER) {
86
+ throw new Error(`resolveLaunchProvider expected ${CLAUDE_AGENT_SDK_PROVIDER}`);
87
+ }
88
+ const claudeInstance = instance;
89
+ const permissionMode = access === "read"
90
+ ? "plan"
91
+ : access === "write"
92
+ ? "acceptEdits"
93
+ : access === "auto"
94
+ ? "bypassPermissions"
95
+ : "default";
96
+ return Object.freeze({
97
+ ...common,
98
+ kind: CLAUDE_AGENT_SDK_PROVIDER,
99
+ ...(claudeInstance.executable !== undefined ? { executable: claudeInstance.executable } : {}),
100
+ ...(model !== undefined ? { model } : {}),
101
+ ...(effort !== undefined ? { effort } : {}),
102
+ ...(claudeInstance.settingSources !== undefined ? { settingSources: claudeInstance.settingSources } : {}),
103
+ permissionMode,
104
+ ...(permissionMode === "bypassPermissions" ? { allowDangerouslySkipPermissions: true } : {}),
105
+ ...(webSearch === "disabled" ? { disallowedTools: ["WebSearch"] } : {}),
106
+ ...(claudeInstance.env !== undefined ? { env: claudeInstance.env } : {}),
107
+ });
108
+ },
109
+ parseLaunchProvider: (provider, common) => {
110
+ exactKeys(provider, [
111
+ "name",
112
+ "source",
113
+ "kind",
114
+ "executable",
115
+ "model",
116
+ "effort",
117
+ "settingSources",
118
+ "permissionMode",
119
+ "allowDangerouslySkipPermissions",
120
+ "disallowedTools",
121
+ "env",
122
+ ], "provider");
123
+ const modes = new Set(["default", "plan", "acceptEdits", "bypassPermissions"]);
124
+ const permissionMode = requiredEnum(provider, "permissionMode", "provider", modes);
125
+ if (permissionMode === "bypassPermissions") {
126
+ if (provider.allowDangerouslySkipPermissions !== true) {
127
+ throw snapshotError("provider.allowDangerouslySkipPermissions", "must be true for bypassPermissions");
128
+ }
129
+ }
130
+ else if ("allowDangerouslySkipPermissions" in provider) {
131
+ throw snapshotError("provider.allowDangerouslySkipPermissions", "is only valid for bypassPermissions");
132
+ }
133
+ let settingSources;
134
+ if ("settingSources" in provider) {
135
+ if (!Array.isArray(provider.settingSources))
136
+ throw snapshotError("provider.settingSources", "must be an array");
137
+ settingSources = Object.freeze(provider.settingSources.map((source, index) => {
138
+ if (typeof source !== "string" || !CLAUDE_SETTING_SOURCES.has(source)) {
139
+ throw snapshotError(`provider.settingSources[${index}]`, "has an invalid setting source");
140
+ }
141
+ return source;
142
+ }));
143
+ }
144
+ let disallowedTools;
145
+ if ("disallowedTools" in provider) {
146
+ if (!Array.isArray(provider.disallowedTools) ||
147
+ provider.disallowedTools.length !== 1 ||
148
+ provider.disallowedTools[0] !== "WebSearch") {
149
+ throw snapshotError("provider.disallowedTools", "must equal ['WebSearch']");
150
+ }
151
+ disallowedTools = Object.freeze(["WebSearch"]);
152
+ }
153
+ const executable = optionalString(provider, "executable", "provider");
154
+ const model = optionalString(provider, "model", "provider");
155
+ const effort = optionalString(provider, "effort", "provider");
156
+ const env = optionalStringRecord(provider, "env");
157
+ return Object.freeze({
158
+ ...common,
159
+ kind: CLAUDE_AGENT_SDK_PROVIDER,
160
+ ...(executable !== undefined ? { executable } : {}),
161
+ ...(model !== undefined ? { model } : {}),
162
+ ...(effort !== undefined ? { effort } : {}),
163
+ ...(settingSources !== undefined ? { settingSources } : {}),
164
+ permissionMode,
165
+ ...(permissionMode === "bypassPermissions" ? { allowDangerouslySkipPermissions: true } : {}),
166
+ ...(disallowedTools !== undefined ? { disallowedTools } : {}),
167
+ ...(env !== undefined ? { env } : {}),
168
+ });
169
+ },
170
+ applyEffort: (provider, effort) => Object.freeze({ ...provider, effort }),
171
+ providerEffortAndModel: (provider) => {
172
+ const resolved = provider;
173
+ return { model: resolved.model, effort: resolved.effort };
174
+ },
175
+ attachLoader: (terms, ports) => {
176
+ if (terms.provider !== CLAUDE_AGENT_SDK_PROVIDER)
177
+ return terms;
178
+ const loader = ports.claudeAgentSdk;
179
+ return loader ? { ...terms, loader } : terms;
180
+ },
181
+ nativePolicyOwnership: () => null,
182
+ startLive: async ({ terms, signal, reviveTerms, onSyncCheckpoint, onIngress }) => {
183
+ if (terms.provider !== CLAUDE_AGENT_SDK_PROVIDER) {
184
+ throw new Error(`startLive expected ${CLAUDE_AGENT_SDK_PROVIDER}`);
185
+ }
186
+ const claudeTerms = terms;
187
+ const claudeOptions = {
188
+ model: claudeTerms.model,
189
+ executable: claudeTerms.executable,
190
+ effort: claudeTerms.effort,
191
+ env: claudeTerms.env,
192
+ signal,
193
+ permissionMode: claudeTerms.permissionMode,
194
+ settingSources: claudeTerms.settingSources,
195
+ allowDangerouslySkipPermissions: claudeTerms.allowDangerouslySkipPermissions,
196
+ disallowedTools: claudeTerms.disallowedTools,
197
+ systemPrompt: claudeTerms.systemPrompt,
198
+ onSyncCheckpoint,
199
+ onEvidence: claudeTerms.onEvidence,
200
+ onIngress,
201
+ initialTurn: claudeTerms.initialTurn,
202
+ loader: claudeTerms.loader,
203
+ };
204
+ const { startClaudeAgentSdk: start } = await import("./adapter.js");
205
+ if (reviveTerms) {
206
+ const session = admitResumeShape(claudeSessionSchema, reviveTerms.session, reviveTerms.resumePath);
207
+ return start(claudeTerms.prompt, claudeTerms.workdir, {
208
+ ...claudeOptions,
209
+ sessionId: session.sessionId,
210
+ });
211
+ }
212
+ return start(claudeTerms.prompt, claudeTerms.workdir, claudeOptions);
213
+ },
214
+ };
@@ -0,0 +1,2 @@
1
+ import { z } from "zod";
2
+ export const claudeSessionSchema = z.object({ sessionId: z.string().trim().min(1) });
@@ -1,52 +1,22 @@
1
- import { z } from "zod";
2
1
  import { appendDebugLog } from "../../../telemetry/debug-log.js";
3
2
  import { SUBAGENT_SESSION_VERSION } from "../../session.js";
4
3
  import { createProjectionDriver } from "../../harness/execution-handle.js";
5
- import { buildSubagentEnv, createAbortError, emitProviderEvidence, coerceString } from "../../harness/runtime.js";
4
+ import { createProviderFailure } from "../../harness/provider-adapter.js";
5
+ import { awaitProviderAbortSettlement, buildSubagentEnv, createAbortError, emitProviderEvidence, coerceString, } from "../../harness/runtime.js";
6
+ import { CODEX_APP_SERVER_PROVIDER } from "./identity.js";
6
7
  import { CodexAppServerProcess } from "./session.js";
7
8
  import { createCodexAppServerTurnMonitor, createCodexAppServerTurnState, recordTurnStartResponse, } from "./events.js";
9
+ export { CODEX_APP_SERVER_PROVIDER } from "./identity.js";
8
10
  /** Identity-only opacity boundary for codex-app-server turn/start effort. */
9
11
  function toCodexAppServerEffort(effort) {
10
12
  return effort;
11
13
  }
12
- /** Session handle for codex-app-server: thread id plus optional CODEX_HOME for cross-process resume. */
13
- export const codexAppServerSessionSchema = z.object({
14
- threadId: z.string().trim().min(1),
15
- codexHome: z.string().trim().min(1).optional(),
16
- });
17
- const CODEX_APP_SERVER_PROVIDER = "codex-app-server";
14
+ export { codexAppServerSessionSchema } from "./session-schema.js";
18
15
  const MINIMUM_CODEX_APP_SERVER_VERSION = { major: 0, minor: 143, patch: 0 };
19
16
  /** Non-interactive defaults for turn/start (faye #316 policy A). */
20
17
  export const CODEX_APP_SERVER_TURN_APPROVAL_POLICY = "never";
21
- export function buildCodexAppServerWorkspaceWriteSandboxPolicy(input) {
22
- return {
23
- type: "workspaceWrite",
24
- writableRoots: [...input.writableRoots],
25
- networkAccess: input.networkAccess,
26
- excludeTmpdirEnvVar: false,
27
- excludeSlashTmp: false,
28
- };
29
- }
30
- /** True when config.* already owns approval policy — omit turn-level approvalPolicy default. */
31
- export function configOwnsApprovalPolicy(config) {
32
- if (!config)
33
- return false;
34
- return Object.prototype.hasOwnProperty.call(config, "approval_policy");
35
- }
36
- /**
37
- * True when config.* already owns sandbox settings — omit turn-level sandboxPolicy default.
38
- * Matches `sandbox_mode` or any `sandbox_workspace_write` / `sandbox_workspace_write.*` key.
39
- */
40
- export function configOwnsSandboxPolicy(config) {
41
- if (!config)
42
- return false;
43
- for (const key of Object.keys(config)) {
44
- if (key === "sandbox_mode" || key === "sandbox_workspace_write" || key.startsWith("sandbox_workspace_write.")) {
45
- return true;
46
- }
47
- }
48
- return false;
49
- }
18
+ export { buildCodexAppServerWorkspaceWriteSandboxPolicy, configOwnsApprovalPolicy, configOwnsSandboxPolicy, } from "./policy.js";
19
+ import { buildCodexAppServerWorkspaceWriteSandboxPolicy, configOwnsApprovalPolicy, configOwnsSandboxPolicy, } from "./policy.js";
50
20
  function parseSemver(version) {
51
21
  const match = version.trim().match(/(\d+)\.(\d+)\.(\d+)/);
52
22
  if (!match)
@@ -83,6 +53,14 @@ function extractVersionFromInitialize(result) {
83
53
  }
84
54
  return coerceString(record.version) ?? coerceString(record.cliVersion);
85
55
  }
56
+ export async function settleCodexGracefulInterrupt(input) {
57
+ await input.requestInterrupt();
58
+ const terminal = await input.completion;
59
+ const terminalTurnId = coerceString(terminal.turn.id);
60
+ if (terminalTurnId !== input.turnId || terminal.status !== "interrupted") {
61
+ throw new Error(`${CODEX_APP_SERVER_PROVIDER} graceful abort expected interrupted turn '${input.turnId}', got '${terminalTurnId ?? "unknown"}' status '${terminal.status}'`);
62
+ }
63
+ }
86
64
  /** Gate-facing production entry: the harness owns clocks, capture, classification, and outcome construction. */
87
65
  export async function startCodexAppServer(prompt, cwd, options = {}) {
88
66
  const executable = options.executable?.trim() || "codex";
@@ -91,6 +69,7 @@ export async function startCodexAppServer(prompt, cwd, options = {}) {
91
69
  const turnState = createCodexAppServerTurnState();
92
70
  let activeThreadId;
93
71
  let interruptRequested = false;
72
+ let activeTurnCompletion;
94
73
  let builderDiagnostic;
95
74
  let emitTurnStarted;
96
75
  const pendingTells = [];
@@ -204,19 +183,29 @@ export async function startCodexAppServer(prompt, cwd, options = {}) {
204
183
  await server?.close("force");
205
184
  return;
206
185
  }
207
- if (server && activeThreadId && turnState.activeTurnId) {
208
- try {
209
- // RPC acknowledgement is NOT terminal proof; wait for turn/completed interrupted.
210
- await server.request("turn/interrupt", {
211
- threadId: activeThreadId,
212
- turnId: turnState.activeTurnId,
213
- });
214
- }
215
- catch {
216
- // idle interrupt may error; still rely on process teardown
186
+ if (!server)
187
+ return;
188
+ if (activeThreadId && turnState.activeTurnId) {
189
+ const turnId = turnState.activeTurnId;
190
+ const completion = activeTurnCompletion;
191
+ if (!completion) {
192
+ throw new Error(`${CODEX_APP_SERVER_PROVIDER} graceful abort lacked an active turn monitor`);
217
193
  }
194
+ await awaitProviderAbortSettlement(CODEX_APP_SERVER_PROVIDER, (async () => {
195
+ // RPC acknowledgement is submission evidence only. Keep the monitor
196
+ // and server alive until the matching terminal notification arrives.
197
+ await settleCodexGracefulInterrupt({
198
+ turnId,
199
+ requestInterrupt: () => server.request("turn/interrupt", {
200
+ threadId: activeThreadId,
201
+ turnId,
202
+ }),
203
+ completion,
204
+ });
205
+ })());
206
+ return;
218
207
  }
219
- await server?.close("graceful");
208
+ await awaitProviderAbortSettlement(CODEX_APP_SERVER_PROVIDER, server.close("force"), "startup abort could not force-close owned server");
220
209
  },
221
210
  async run(builder) {
222
211
  builderDiagnostic = (text) => builder.emit({ type: "diagnostic", text });
@@ -239,6 +228,7 @@ export async function startCodexAppServer(prompt, cwd, options = {}) {
239
228
  isDrainingTells: () => drainingTells,
240
229
  setFinishAfterTellDrain: (finish) => { finishAfterTellDrain = finish; },
241
230
  });
231
+ activeTurnCompletion = turnCompleted;
242
232
  try {
243
233
  const initResult = await server.request("initialize", {
244
234
  clientInfo: {
@@ -255,7 +245,7 @@ export async function startCodexAppServer(prompt, cwd, options = {}) {
255
245
  if (isCodexAppServerVersionBelowMinimum(version)) {
256
246
  const message = `${CODEX_APP_SERVER_PROVIDER} refused: initialize version '${version}' is below minimum supported version 0.143.0`;
257
247
  builder.emit({ type: "fail", message });
258
- throw new Error(message);
248
+ throw createProviderFailure(message);
259
249
  }
260
250
  const initRecord = (initResult && typeof initResult === "object" ? initResult : {});
261
251
  const serverCodexHome = coerceString(initRecord.codexHome) ?? options.codexHome;
@@ -280,7 +270,7 @@ export async function startCodexAppServer(prompt, cwd, options = {}) {
280
270
  if (!activeThreadId) {
281
271
  const message = `${CODEX_APP_SERVER_PROVIDER} exec could not determine thread id`;
282
272
  builder.emit({ type: "fail", message });
283
- throw new Error(message);
273
+ throw createProviderFailure(message);
284
274
  }
285
275
  if (options.onEvidence)
286
276
  emitProviderEvidence(options.onEvidence, { type: "session", provider: CODEX_APP_SERVER_PROVIDER, threadId: activeThreadId }, builderDiagnostic);
@@ -303,6 +293,8 @@ export async function startCodexAppServer(prompt, cwd, options = {}) {
303
293
  turnState.activeTurnId = undefined;
304
294
  turnState.activeTurnSource = undefined;
305
295
  turnState.activeTurnAcceptingSteer = false;
296
+ turnState.failureCause = undefined;
297
+ turnState.turnInFlight = true;
306
298
  const turnStart = await server.request("turn/start", turnStartParams);
307
299
  const turn = turnStart && typeof turnStart === "object"
308
300
  ? (turnStart.turn ?? undefined)
@@ -311,18 +303,20 @@ export async function startCodexAppServer(prompt, cwd, options = {}) {
311
303
  if (options.onEvidence)
312
304
  emitProviderEvidence(options.onEvidence, { type: "checkpoint", provider: CODEX_APP_SERVER_PROVIDER, fence: { kind: "turn", turnId }, source: "response" }, builderDiagnostic);
313
305
  const completed = await turnCompleted;
306
+ turnState.turnInFlight = false;
314
307
  if (completed.status === "interrupted" || interruptRequested) {
315
308
  throw createAbortError(`${CODEX_APP_SERVER_PROVIDER} turn interrupted`);
316
309
  }
317
310
  if (completed.status === "failed") {
318
311
  const message = `${CODEX_APP_SERVER_PROVIDER} turn failed`;
319
- builder.emit({ type: "fail", message });
320
- throw new Error(message);
312
+ throw createProviderFailure(message, {
313
+ ...(turnState.failureCause ? { publicCause: turnState.failureCause } : {}),
314
+ });
321
315
  }
322
316
  if (completed.status !== "completed") {
323
317
  const message = `${CODEX_APP_SERVER_PROVIDER} turn ended with status '${completed.status}'`;
324
318
  builder.emit({ type: "fail", message });
325
- throw new Error(message);
319
+ throw createProviderFailure(message);
326
320
  }
327
321
  // Successful turn/completed is consumption evidence; interrupt ack alone is not terminal proof.
328
322
  const session = {
@@ -338,6 +332,7 @@ export async function startCodexAppServer(prompt, cwd, options = {}) {
338
332
  return { finalMessage, session };
339
333
  }
340
334
  finally {
335
+ activeTurnCompletion = undefined;
341
336
  rejectPendingTells(new Error(`${CODEX_APP_SERVER_PROVIDER} execution ended before queued tell acceptance`));
342
337
  await server?.close();
343
338
  server = undefined;
@@ -345,3 +340,5 @@ export async function startCodexAppServer(prompt, cwd, options = {}) {
345
340
  },
346
341
  });
347
342
  }
343
+ // Compiler-level binding to the named ProviderAdapter function contract.
344
+ startCodexAppServer;
@@ -1,7 +1,8 @@
1
1
  import { boundActivityExcerpt, diffstatFromUnifiedPatch } from "../../harness/activity-values.js";
2
2
  import { AGENT_PLAN_ITEM_TEXT_MAX_CHARS, AGENT_PLAN_MAX_ITEMS, AGENT_THOUGHT_TEXT_MAX_CHARS, } from "../../harness/events.js";
3
+ import { createProviderFailure } from "../../harness/provider-adapter.js";
3
4
  import { createAbortError, emitProviderEvidence, coerceString } from "../../harness/runtime.js";
4
- const CODEX_APP_SERVER_PROVIDER = "codex-app-server";
5
+ import { CODEX_APP_SERVER_PROVIDER } from "./identity.js";
5
6
  const CODEX_APP_SERVER_NOTIFICATION_ACKNOWLEDGED = new Set([
6
7
  "item/agentMessage/delta",
7
8
  "item/commandExecution/outputDelta",
@@ -16,11 +17,13 @@ const CODEX_APP_SERVER_NOTIFICATION_MAPPED = new Set([
16
17
  "turn/completed",
17
18
  "error",
18
19
  ]);
19
- export function codexAppServerNotificationDisposition(method) {
20
+ export function codexAppServerNotificationDisposition(method, params) {
20
21
  if (CODEX_APP_SERVER_NOTIFICATION_ACKNOWLEDGED.has(method))
21
22
  return "acknowledged-unpersisted";
22
23
  if (CODEX_APP_SERVER_NOTIFICATION_MAPPED.has(method))
23
24
  return "mapped";
25
+ if (method === "account/rateLimits/updated" && codexAppServerRateLimitCause(params))
26
+ return "mapped";
24
27
  return "unknown";
25
28
  }
26
29
  export function appServerRecord(value) {
@@ -37,6 +40,41 @@ const CODEX_APP_SERVER_ACTIVITY_ITEM_TYPES = [
37
40
  function isCodexAppServerActivityItemType(value) {
38
41
  return CODEX_APP_SERVER_ACTIVITY_ITEM_TYPES.includes(value);
39
42
  }
43
+ /** Map a native or legacy fileChange kind fact into the public op. */
44
+ function appServerFileChangeOp(kind) {
45
+ if (kind === "add" || kind === "update" || kind === "delete")
46
+ return kind;
47
+ const record = appServerRecord(kind);
48
+ if (!record)
49
+ return undefined;
50
+ if (record.type === "add" || record.type === "update" || record.type === "delete")
51
+ return record.type;
52
+ return undefined;
53
+ }
54
+ /** Trustworthy provider patch text only: per-change native `diff`, else legacy `details.patch`. */
55
+ function appServerFileChangeDiffstat(item) {
56
+ let additions = 0;
57
+ let deletions = 0;
58
+ let saw = false;
59
+ if (Array.isArray(item.changes)) {
60
+ for (const entry of item.changes) {
61
+ const change = appServerRecord(entry);
62
+ if (!change || typeof change.diff !== "string" || !change.diff)
63
+ continue;
64
+ const partial = diffstatFromUnifiedPatch(change.diff);
65
+ if (!partial)
66
+ continue;
67
+ saw = true;
68
+ additions += partial.additions;
69
+ deletions += partial.deletions;
70
+ }
71
+ }
72
+ if (saw)
73
+ return additions || deletions ? { additions, deletions } : undefined;
74
+ const details = appServerRecord(item.details);
75
+ const patch = typeof details?.patch === "string" ? details.patch : undefined;
76
+ return patch ? diffstatFromUnifiedPatch(patch) : undefined;
77
+ }
40
78
  export function appServerActivityCall(itemType, item) {
41
79
  switch (itemType) {
42
80
  case "commandExecution":
@@ -53,9 +91,9 @@ export function appServerActivityCall(itemType, item) {
53
91
  const change = appServerRecord(entry);
54
92
  if (!change || typeof change.path !== "string")
55
93
  return [];
56
- if (change.kind !== "add" && change.kind !== "update" && change.kind !== "delete")
94
+ const op = appServerFileChangeOp(change.kind);
95
+ if (!op)
57
96
  return [];
58
- const op = change.kind;
59
97
  return [{ op, path: change.path }];
60
98
  })
61
99
  : [];
@@ -80,11 +118,7 @@ export function appServerActivityResult(item) {
80
118
  : typeof item.error === "string" && item.error
81
119
  ? boundActivityExcerpt(item.error)
82
120
  : undefined;
83
- const details = item.details !== null && typeof item.details === "object" && !Array.isArray(item.details)
84
- ? item.details
85
- : undefined;
86
- const patch = typeof details?.patch === "string" ? details.patch : undefined;
87
- const diffstat = patch ? diffstatFromUnifiedPatch(patch) : undefined;
121
+ const diffstat = appServerFileChangeDiffstat(item);
88
122
  return {
89
123
  status: item.status === "failed" || (exitCode !== undefined && exitCode !== 0) ? "error" : "ok",
90
124
  ...(message ? { message } : {}),
@@ -131,9 +165,23 @@ export function createCodexAppServerTurnState() {
131
165
  responseSeenTurnIds: new Set(),
132
166
  completedBeforeResponseTurnIds: new Set(),
133
167
  activeTurnAcceptingSteer: false,
168
+ turnInFlight: false,
134
169
  lastAgentMessage: "",
135
170
  };
136
171
  }
172
+ /** Admit only positive native exhaustion evidence; no provider strings survive. */
173
+ export function codexAppServerRateLimitCause(params) {
174
+ const rateLimits = appServerRecord(appServerRecord(params)?.rateLimits);
175
+ if (!rateLimits)
176
+ return undefined;
177
+ for (const value of Object.values(rateLimits)) {
178
+ const window = appServerRecord(value);
179
+ if (typeof window?.usedPercent === "number" && window.usedPercent >= 100) {
180
+ return { kind: "rate_limit_exhausted" };
181
+ }
182
+ }
183
+ return undefined;
184
+ }
137
185
  export function recordActiveTurnId(state, candidate, source) {
138
186
  const turnId = coerceString(candidate);
139
187
  if (!turnId)
@@ -178,7 +226,7 @@ export function createCodexAppServerTurnMonitor(options) {
178
226
  const failServerRequest = (request) => {
179
227
  // Policy A forbids interactive server→client requests. Fail immediately with named diagnostic.
180
228
  const message = `${CODEX_APP_SERVER_PROVIDER} unexpected server request '${request.method}' (id=${String(request.id)}); non-interactive policy forbids server→client requests`;
181
- failTurn(new Error(message));
229
+ failTurn(createProviderFailure(message));
182
230
  };
183
231
  const requestDeliveryOpportunity = () => {
184
232
  try {
@@ -200,7 +248,7 @@ export function createCodexAppServerTurnMonitor(options) {
200
248
  });
201
249
  unsubNotifications = server.onNotification((notification) => {
202
250
  try {
203
- builder.ingress(CODEX_APP_SERVER_PROVIDER, notification.method, notification, codexAppServerNotificationDisposition(notification.method), () => {
251
+ builder.ingress(CODEX_APP_SERVER_PROVIDER, notification.method, notification, codexAppServerNotificationDisposition(notification.method, notification.params), () => {
204
252
  if (notification.method === "item/agentMessage/delta") {
205
253
  const delta = coerceString(notification.params?.delta);
206
254
  if (delta) {
@@ -274,6 +322,14 @@ export function createCodexAppServerTurnMonitor(options) {
274
322
  onSyncCheckpoint?.({ enqueue }, checkpoint);
275
323
  void drainPendingTells();
276
324
  }
325
+ if (notification.method === "account/rateLimits/updated") {
326
+ const cause = codexAppServerRateLimitCause(notification.params);
327
+ if (cause) {
328
+ builder.emit({ type: "warning", warning: { reason: "rate-limit", state: "exhausted" } });
329
+ if (state.turnInFlight)
330
+ state.failureCause ??= cause;
331
+ }
332
+ }
277
333
  if (notification.method === "turn/completed") {
278
334
  const turn = notification.params?.turn ?? {};
279
335
  const status = coerceString(turn.status) ?? "unknown";
@@ -0,0 +1 @@
1
+ export const CODEX_APP_SERVER_PROVIDER = "codex-app-server";
@@ -0,0 +1,29 @@
1
+ export function buildCodexAppServerWorkspaceWriteSandboxPolicy(input) {
2
+ return {
3
+ type: "workspaceWrite",
4
+ writableRoots: [...input.writableRoots],
5
+ networkAccess: input.networkAccess,
6
+ excludeTmpdirEnvVar: false,
7
+ excludeSlashTmp: false,
8
+ };
9
+ }
10
+ /** True when config.* already owns approval policy — omit turn-level approvalPolicy default. */
11
+ export function configOwnsApprovalPolicy(config) {
12
+ if (!config)
13
+ return false;
14
+ return Object.prototype.hasOwnProperty.call(config, "approval_policy");
15
+ }
16
+ /**
17
+ * True when config.* already owns sandbox settings — omit turn-level sandboxPolicy default.
18
+ * Matches `sandbox_mode` or any `sandbox_workspace_write` / `sandbox_workspace_write.*` key.
19
+ */
20
+ export function configOwnsSandboxPolicy(config) {
21
+ if (!config)
22
+ return false;
23
+ for (const key of Object.keys(config)) {
24
+ if (key === "sandbox_mode" || key === "sandbox_workspace_write" || key.startsWith("sandbox_workspace_write.")) {
25
+ return true;
26
+ }
27
+ }
28
+ return false;
29
+ }