@astrosheep/keiyaku 2.8.4 → 2.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (229) 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 +39 -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 +35 -0
  55. package/build/cli/commands/projection/kill/meta.js +11 -0
  56. package/build/cli/commands/projection/revive/handler.js +53 -0
  57. package/build/cli/commands/projection/revive/meta.js +9 -0
  58. package/build/cli/commands/projection/status/handler.js +23 -0
  59. package/build/cli/commands/projection/status/meta.js +9 -0
  60. package/build/cli/commands/projection/tell/handler.js +34 -0
  61. package/build/cli/commands/projection/tell/meta.js +9 -0
  62. package/build/cli/commands/projection/wait/handler.js +21 -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.js +159 -72
  106. package/build/cli/projection-address.js +5 -0
  107. package/build/cli/render/arc.js +1 -1
  108. package/build/cli/render/errors.js +4 -3
  109. package/build/cli/render/format.js +14 -0
  110. package/build/cli/render/kanshi.js +106 -0
  111. package/build/cli/render/petition.js +24 -1
  112. package/build/cli/render/projection-activity.js +5 -1
  113. package/build/cli/render/shared.js +2 -2
  114. package/build/cli/render/status.js +79 -13
  115. package/build/cli/render/task.js +113 -0
  116. package/build/cli/render/wait.js +23 -3
  117. package/build/cli/types.js +1 -1
  118. package/build/config/{akuma-loader_v2.js → akuma-loader.js} +2 -2
  119. package/build/config/env.js +9 -4
  120. package/build/config/settings/disease.js +26 -0
  121. package/build/config/settings/knobs.js +8 -0
  122. package/build/config/settings/loader.js +244 -0
  123. package/build/config/settings/schema.js +276 -0
  124. package/build/core/addressing.js +1 -1
  125. package/build/core/amend.js +3 -3
  126. package/build/core/arc.js +5 -4
  127. package/build/core/bind-workspace.js +123 -0
  128. package/build/core/bind.js +75 -155
  129. package/build/core/call/call.js +224 -0
  130. package/build/core/call/context.js +238 -0
  131. package/build/core/call/execution.js +217 -0
  132. package/build/core/call/prompt.js +42 -0
  133. package/build/core/call/reference.js +24 -0
  134. package/build/core/call-persist.js +1 -1
  135. package/build/core/claim-delivery.js +247 -0
  136. package/build/core/claim.js +39 -277
  137. package/build/core/context.js +2 -1
  138. package/build/core/{render.js → contract-view.js} +12 -140
  139. package/build/core/draft.js +107 -9
  140. package/build/core/entry.js +9 -1
  141. package/build/core/execution-coordinate.js +4 -20
  142. package/build/core/execution-pact.js +16 -31
  143. package/build/core/forfeit.js +35 -22
  144. package/build/core/hints.js +2 -2
  145. package/build/core/log.js +2 -2
  146. package/build/core/petition-claim-gates.js +8 -6
  147. package/build/core/petition-preview.js +97 -0
  148. package/build/core/petition-run.js +3 -2
  149. package/build/core/petition.js +39 -26
  150. package/build/core/projection/generation/database.js +306 -0
  151. package/build/core/projection/generation/identity.js +84 -0
  152. package/build/core/projection/generation/model.js +201 -0
  153. package/build/core/projection/generation/store.js +73 -0
  154. package/build/core/projection/generation/transitions.js +258 -0
  155. package/build/core/projection/heart.js +0 -307
  156. package/build/core/projection/tell/database.js +109 -0
  157. package/build/core/projection/tell/model.js +97 -0
  158. package/build/core/{projection-tells.js → projection/tell/store.js} +3 -158
  159. package/build/core/projection-activity.js +23 -2
  160. package/build/core/projection-core.js +2 -1
  161. package/build/core/projection-execution-observer.js +259 -0
  162. package/build/core/projection-generation-continuation.js +1 -1
  163. package/build/core/projection-generation-execution.js +90 -20
  164. package/build/core/projection-generation-launcher.js +1 -1
  165. package/build/core/projection-generation-runner.js +198 -4
  166. package/build/core/projection-identity.js +1 -1
  167. package/build/core/projection-kill.js +50 -17
  168. package/build/core/projection-life-observer.js +1 -1
  169. package/build/core/projection-life-protocol.js +10 -0
  170. package/build/core/projection-mint.js +1 -1
  171. package/build/core/projection-status.js +45 -32
  172. package/build/core/projection-wait.js +12 -2
  173. package/build/core/projection-wake.js +5 -2
  174. package/build/core/{queue_v2.js → queue.js} +2 -1
  175. package/build/core/registry.js +1 -1
  176. package/build/core/renew.js +7 -7
  177. package/build/core/response-artifact-catalog-sqlite.js +112 -0
  178. package/build/core/response-artifact-catalog.js +7 -0
  179. package/build/core/seal.js +44 -16
  180. package/build/core/status/board.js +286 -0
  181. package/build/core/status/drift.js +99 -0
  182. package/build/core/status/lifecycle.js +84 -0
  183. package/build/core/status/reconciliation.js +131 -0
  184. package/build/core/stored-agent-event.js +28 -4
  185. package/build/core/target-ref.js +10 -0
  186. package/build/core/task/board.js +175 -0
  187. package/build/core/task/commands.js +211 -0
  188. package/build/core/task/document.js +189 -0
  189. package/build/core/task/model.js +1 -0
  190. package/build/core/task/settlement-git.js +207 -0
  191. package/build/core/task/settlement-policy.js +82 -0
  192. package/build/core/task/source-board.js +84 -0
  193. package/build/core/task/source-model.js +1 -0
  194. package/build/core/task/validation.js +44 -0
  195. package/build/core/task-contract.js +224 -0
  196. package/build/core/task-doctor.js +14 -0
  197. package/build/core/task-git-actor.js +38 -0
  198. package/build/core/task-git-runtime.js +34 -0
  199. package/build/core/task-git-store.js +375 -0
  200. package/build/core/task-repository.js +1 -0
  201. package/build/core/task-store-repository.js +86 -0
  202. package/build/core/task-store.js +1 -0
  203. package/build/core/task-worktree.js +51 -0
  204. package/build/core/task.js +4 -0
  205. package/build/core/transcripts.js +138 -56
  206. package/build/core/validation.js +17 -0
  207. package/build/core/verdict.js +2 -2
  208. package/build/core/worktree-path.js +24 -6
  209. package/build/flow-error.js +3 -2
  210. package/build/generated/version.js +1 -1
  211. package/build/git/commits.js +3 -0
  212. package/build/git/diff/parsers.js +0 -94
  213. package/build/index.js +2 -0
  214. package/build/keiyaku-constants.js +2 -0
  215. package/build/keiyaku.js +4 -3
  216. package/package.json +3 -2
  217. package/skills/keiyaku/SKILL.md +1 -1
  218. package/skills/keiyaku-akuma/SKILL.md +11 -6
  219. package/build/agents/harness/pump.js +0 -158
  220. package/build/agents/providers/codex-app-server.js +0 -864
  221. package/build/agents/providers/opencode-sdk.js +0 -363
  222. package/build/agents/providers/pi.js +0 -557
  223. package/build/config/settings.js +0 -533
  224. package/build/core/call.js +0 -686
  225. package/build/core/projection/generation.js +0 -412
  226. package/build/core/projection/identity.js +0 -81
  227. package/build/core/projection/mint.js +0 -174
  228. package/build/core/projection-generation-store.js +0 -707
  229. package/build/core/status.js +0 -539
@@ -0,0 +1,276 @@
1
+ import { z } from "zod";
2
+ import { CLAUDE_SETTING_SOURCES, } from "../../keiyaku.js";
3
+ const tomlValueSchema = z.lazy(() => z.union([
4
+ z.string(),
5
+ z.number(),
6
+ z.boolean(),
7
+ z.array(tomlValueSchema),
8
+ z.record(z.string(), tomlValueSchema),
9
+ ]));
10
+ const structuredTomlValueSchema = z.record(z.string(), tomlValueSchema);
11
+ const executableSchema = z.string().superRefine((value, ctx) => {
12
+ if (value.length === 0 || /\s/.test(value) || value.includes("\"") || value.includes("'")) {
13
+ ctx.addIssue({
14
+ code: z.ZodIssueCode.custom,
15
+ message: "must be a single program name token with no spaces or quotes.",
16
+ });
17
+ }
18
+ });
19
+ const nonblankOptionalString = z
20
+ .string()
21
+ .refine((value) => value.trim().length > 0, { message: "must not be blank." })
22
+ .optional();
23
+ const providerCommonFields = {
24
+ description: nonblankOptionalString,
25
+ };
26
+ const providerEnvSchema = z.record(z.string(), z.string()).optional();
27
+ function refinePiEnvInjection(data, ctx) {
28
+ if (data.env === undefined)
29
+ return;
30
+ if (Object.keys(data.env).length === 0)
31
+ return;
32
+ ctx.addIssue({
33
+ code: z.ZodIssueCode.custom,
34
+ path: ["env"],
35
+ message: "env injection not supported for provider pi",
36
+ });
37
+ }
38
+ const CODEX_SDK_FORBIDDEN_THREAD_OPTIONS_KEYS = [
39
+ "model",
40
+ "modelReasoningEffort",
41
+ "sandboxMode",
42
+ "networkAccessEnabled",
43
+ "webSearchMode",
44
+ "approvalPolicy",
45
+ "workingDirectory",
46
+ "skipGitRepoCheck",
47
+ ];
48
+ const FORBIDDEN_CONFIG_KEYS = [
49
+ "model",
50
+ "model_reasoning_effort",
51
+ ];
52
+ function isConfigKeyForbidden(key) {
53
+ return FORBIDDEN_CONFIG_KEYS.includes(key);
54
+ }
55
+ const claudeSettingSourceSchema = z.enum(CLAUDE_SETTING_SOURCES);
56
+ const writableRootItemSchema = z.string().superRefine((value, ctx) => {
57
+ if (value.length === 0) {
58
+ ctx.addIssue({ code: z.ZodIssueCode.custom, message: "must not be empty." });
59
+ return;
60
+ }
61
+ if (value.startsWith("~")) {
62
+ ctx.addIssue({ code: z.ZodIssueCode.custom, message: "must not begin with tilde." });
63
+ return;
64
+ }
65
+ if (value.includes("\0")) {
66
+ ctx.addIssue({ code: z.ZodIssueCode.custom, message: "must not contain NUL byte." });
67
+ return;
68
+ }
69
+ if (/\$[A-Za-z_]/.test(value) || /\$\{/.test(value)) {
70
+ ctx.addIssue({ code: z.ZodIssueCode.custom, message: "must not contain environment variable references." });
71
+ return;
72
+ }
73
+ });
74
+ export const providerInstanceSchema = z.discriminatedUnion("kind", [
75
+ z
76
+ .object({
77
+ kind: z.literal("codex-sdk"),
78
+ ...providerCommonFields,
79
+ executable: executableSchema.optional(),
80
+ profile: z.string().optional(),
81
+ config: structuredTomlValueSchema.optional(),
82
+ threadOptions: structuredTomlValueSchema.optional(),
83
+ })
84
+ .strict()
85
+ .superRefine((data, ctx) => {
86
+ if (data.threadOptions) {
87
+ for (const key of CODEX_SDK_FORBIDDEN_THREAD_OPTIONS_KEYS) {
88
+ if (key in data.threadOptions) {
89
+ ctx.addIssue({
90
+ code: z.ZodIssueCode.custom,
91
+ path: ["threadOptions", key],
92
+ message: `"${key}" is owned by the Akuma or Keiyaku execution, not this provider instance`,
93
+ });
94
+ }
95
+ }
96
+ }
97
+ if (data.config) {
98
+ for (const key of Object.keys(data.config)) {
99
+ if (isConfigKeyForbidden(key)) {
100
+ ctx.addIssue({
101
+ code: z.ZodIssueCode.custom,
102
+ path: ["config", key],
103
+ message: `"${key}" is owned by the Akuma or Keiyaku execution, not this provider instance`,
104
+ });
105
+ }
106
+ }
107
+ }
108
+ }),
109
+ z
110
+ .object({
111
+ kind: z.literal("codex-app-server"),
112
+ ...providerCommonFields,
113
+ executable: executableSchema.optional(),
114
+ profile: z.string().optional(),
115
+ config: structuredTomlValueSchema.optional(),
116
+ writableRoots: z.array(writableRootItemSchema).optional(),
117
+ env: providerEnvSchema,
118
+ })
119
+ .strict()
120
+ .superRefine((data, ctx) => {
121
+ if (data.config) {
122
+ for (const key of Object.keys(data.config)) {
123
+ if (isConfigKeyForbidden(key)) {
124
+ ctx.addIssue({
125
+ code: z.ZodIssueCode.custom,
126
+ path: ["config", key],
127
+ message: `"${key}" is owned by the Akuma or Keiyaku execution, not this provider instance`,
128
+ });
129
+ }
130
+ }
131
+ }
132
+ }),
133
+ z
134
+ .object({
135
+ kind: z.literal("claude-agent-sdk"),
136
+ ...providerCommonFields,
137
+ executable: executableSchema.optional(),
138
+ settingSources: z.array(claudeSettingSourceSchema).optional(),
139
+ env: providerEnvSchema,
140
+ })
141
+ .strict(),
142
+ z
143
+ .object({
144
+ kind: z.literal("opencode-sdk"),
145
+ ...providerCommonFields,
146
+ executable: executableSchema.optional(),
147
+ env: providerEnvSchema,
148
+ })
149
+ .strict(),
150
+ z
151
+ .object({
152
+ kind: z.literal("pi"),
153
+ ...providerCommonFields,
154
+ env: providerEnvSchema,
155
+ })
156
+ .strict()
157
+ .superRefine(refinePiEnvInjection),
158
+ ]);
159
+ const PROVIDER_INSTANCE_NAME_PATTERN = /^[a-z0-9][a-z0-9-]*$/;
160
+ export const providerInstanceNameSchema = z
161
+ .string()
162
+ .max(64, "must contain at most 64 characters.")
163
+ .regex(PROVIDER_INSTANCE_NAME_PATTERN, "must match ^[a-z0-9][a-z0-9-]*$.");
164
+ export const BUILTIN_PROVIDER_INSTANCE_CANDIDATES = {
165
+ "codex-sdk": { name: "codex-sdk", source: "builtin", instance: { kind: "codex-sdk", executable: "codex" } },
166
+ "codex-app-server": {
167
+ name: "codex-app-server",
168
+ source: "builtin",
169
+ instance: { kind: "codex-app-server", executable: "codex" },
170
+ },
171
+ "claude-agent-sdk": {
172
+ name: "claude-agent-sdk",
173
+ source: "builtin",
174
+ instance: { kind: "claude-agent-sdk", executable: "claude", settingSources: ["project"] },
175
+ },
176
+ "opencode-sdk": {
177
+ name: "opencode-sdk",
178
+ source: "builtin",
179
+ instance: { kind: "opencode-sdk", executable: "opencode" },
180
+ },
181
+ pi: { name: "pi", source: "builtin", instance: { kind: "pi" } },
182
+ };
183
+ const AGENT_NAME_PATTERN = /^[a-zA-Z0-9]+(?:[.-][a-zA-Z0-9]+)*$/;
184
+ export const agentNameSchema = z
185
+ .string()
186
+ .min(1, "must not be empty.")
187
+ .regex(AGENT_NAME_PATTERN, "must contain only alphanumeric characters, dots, and hyphens, and must not start or end with a separator.");
188
+ function optionalTrimmedString() {
189
+ return z.string().transform((value) => {
190
+ const trimmed = value.trim();
191
+ return trimmed.length > 0 ? trimmed : undefined;
192
+ }).optional();
193
+ }
194
+ function requiredTrimmedString(message) {
195
+ return z.string().transform((value, ctx) => {
196
+ const trimmed = value.trim();
197
+ if (trimmed.length === 0) {
198
+ ctx.addIssue({
199
+ code: z.ZodIssueCode.custom,
200
+ message,
201
+ });
202
+ return z.NEVER;
203
+ }
204
+ return trimmed;
205
+ });
206
+ }
207
+ const gateCommandSchema = z
208
+ .object({
209
+ label: requiredTrimmedString("must not be empty."),
210
+ command: requiredTrimmedString("must not be empty.").superRefine((value, ctx) => {
211
+ if (/\s/.test(value) || value.includes("\"") || value.includes("'")) {
212
+ ctx.addIssue({
213
+ code: z.ZodIssueCode.custom,
214
+ message: "must be a single program name token with no spaces or quotes.",
215
+ });
216
+ }
217
+ }),
218
+ args: z.array(z.string()).optional(),
219
+ })
220
+ .strict()
221
+ .transform((value) => ({
222
+ ...value,
223
+ args: value.args ?? [],
224
+ }));
225
+ const gateSchema = z
226
+ .object({
227
+ commands: z.array(gateCommandSchema).optional(),
228
+ })
229
+ .strict();
230
+ const WORKTREE_BOOTSTRAP_DEFAULT_TIMEOUT_MS = 300_000;
231
+ const WORKTREE_BOOTSTRAP_MIN_TIMEOUT_MS = 1;
232
+ const WORKTREE_BOOTSTRAP_MAX_TIMEOUT_MS = 3_600_000;
233
+ export const worktreeBootstrapSchema = z
234
+ .object({
235
+ command: z
236
+ .array(z.string())
237
+ .min(1, "command must be a nonempty argv array.")
238
+ .superRefine((items, ctx) => {
239
+ items.forEach((item, index) => {
240
+ if (item.trim().length === 0) {
241
+ ctx.addIssue({
242
+ code: z.ZodIssueCode.custom,
243
+ path: [index],
244
+ message: "command items must be nonempty after trimming.",
245
+ });
246
+ }
247
+ });
248
+ }),
249
+ timeoutMs: z
250
+ .number()
251
+ .int("timeoutMs must be an integer.")
252
+ .min(WORKTREE_BOOTSTRAP_MIN_TIMEOUT_MS, `timeoutMs must be >= ${WORKTREE_BOOTSTRAP_MIN_TIMEOUT_MS}.`)
253
+ .max(WORKTREE_BOOTSTRAP_MAX_TIMEOUT_MS, `timeoutMs must be <= ${WORKTREE_BOOTSTRAP_MAX_TIMEOUT_MS}.`)
254
+ .optional(),
255
+ })
256
+ .strict()
257
+ .transform((value) => ({
258
+ command: value.command,
259
+ timeoutMs: value.timeoutMs ?? WORKTREE_BOOTSTRAP_DEFAULT_TIMEOUT_MS,
260
+ }));
261
+ const settingsSchema = z
262
+ .object({
263
+ default: agentNameSchema.optional(),
264
+ reviewer: agentNameSchema.optional(),
265
+ gate: gateSchema.optional(),
266
+ defaultBranch: optionalTrimmedString(),
267
+ worktreeBootstrap: worktreeBootstrapSchema.optional(),
268
+ })
269
+ .strict();
270
+ export const knobSchemas = {
271
+ default: agentNameSchema,
272
+ reviewer: agentNameSchema,
273
+ gate: gateSchema,
274
+ defaultBranch: optionalTrimmedString(),
275
+ worktreeBootstrap: worktreeBootstrapSchema,
276
+ };
@@ -3,7 +3,7 @@ import { FlowError } from "../flow-error.js";
3
3
  import { listContractIds, readLedger } from "./ledger.js";
4
4
  import { isResponseArtifactId } from "./response-artifact-id.js";
5
5
  import { stableRepoRoot } from "./worktree-path.js";
6
- import { deriveContractState, isTerminalState, } from "./status.js";
6
+ import { deriveContractState, isTerminalState, } from "./status/lifecycle.js";
7
7
  function normalizeAddressQuery(raw) {
8
8
  const value = raw.startsWith("@") ? raw.slice(1) : raw;
9
9
  if (!value.trim()) {
@@ -4,10 +4,10 @@ import { FlowError } from "../flow-error.js";
4
4
  import { getCurrentBranch, isGitRepo } from "../git/branches.js";
5
5
  import { KEIYAKU_FILE } from "../keiyaku.js";
6
6
  import { activeLedgerRef, appendWithRetry, readLedger } from "./ledger.js";
7
- import { renderContractView } from "./render.js";
8
- import { deriveContractState, isTerminalState } from "./status.js";
7
+ import { renderContractView } from "./contract-view.js";
8
+ import { deriveContractState, isTerminalState } from "./status/lifecycle.js";
9
9
  import { resolveContractAddress, withResolvedAddress } from "./addressing.js";
10
- import { resolveDefaultBranch } from "./status.js";
10
+ import { resolveDefaultBranch } from "./status/drift.js";
11
11
  import { assertCleanWorkingTree } from "./arc.js";
12
12
  import { normalizeScopePattern } from "./scope.js";
13
13
  function requireAmendment(value) {
package/build/core/arc.js CHANGED
@@ -9,9 +9,10 @@ import { normalizeInlineTitle } from "./markdown/titles.js";
9
9
  import { parseCommandMarkdown, requireMarkdownTextSection, requireMarkdownTitle, } from "./command-io.js";
10
10
  import { resolveContractAddress, withResolvedAddress } from "./addressing.js";
11
11
  import { activeLedgerRef, appendWithRetry, readLedger } from "./ledger.js";
12
- import { renderContractView } from "./render.js";
13
- import { findOpenArc, getMaxArc, sealOpenArc } from "./seal.js";
14
- import { deriveContractState, isTerminalState, resolveDefaultBranch } from "./status.js";
12
+ import { renderContractView } from "./contract-view.js";
13
+ import { findOpenArc, getMaxArc, sealCurrentArc } from "./seal.js";
14
+ import { deriveContractState, isTerminalState } from "./status/lifecycle.js";
15
+ import { resolveDefaultBranch } from "./status/drift.js";
15
16
  import { persistResponseHistory } from "./transcripts.js";
16
17
  const DIRTY_WORKTREE_LIST_LIMIT = 10;
17
18
  const KEIYAKU_ARTIFACT_DIR_PREFIX = ".keiyaku/";
@@ -111,7 +112,7 @@ export async function openArc(input) {
111
112
  throw new FlowError("INTERNAL_STATE", `contract ${input.contractId} not found or not active`);
112
113
  }
113
114
  assertArcOpenable(input.contractId, ledger.entries);
114
- const sealed = await sealOpenArc({
115
+ const sealed = await sealCurrentArc({
115
116
  cwd: input.cwd,
116
117
  renderCwd: input.cwd,
117
118
  contractId: input.contractId,
@@ -0,0 +1,123 @@
1
+ import * as fs from "node:fs/promises";
2
+ import * as path from "node:path";
3
+ import { KEIYAKU_FILE } from "../keiyaku.js";
4
+ import { createGit, wrapGitError } from "../git/core.js";
5
+ import { listContractIds, readLedger } from "./ledger.js";
6
+ import { CONTRACT_PLACES } from "./places.js";
7
+ import { renderContractView } from "./contract-view.js";
8
+ import { deriveContractState, isTerminalState } from "./status/lifecycle.js";
9
+ import { contractWorktreePathFromBind, findBindEntry } from "./worktree-path.js";
10
+ export async function createContractBranch(cwd, branch, base) {
11
+ const git = createGit(cwd);
12
+ try {
13
+ await git.raw(["branch", branch, base]);
14
+ }
15
+ catch (error) {
16
+ throw wrapGitError(`branch ${branch} ${base}`, error, cwd);
17
+ }
18
+ }
19
+ export async function defaultCreateWorktree(input) {
20
+ void input.id;
21
+ void input.base;
22
+ const git = createGit(input.cwd);
23
+ try {
24
+ await git.raw(["worktree", "add", input.worktreePath, input.branch]);
25
+ }
26
+ catch (error) {
27
+ throw wrapGitError(`worktree add ${input.worktreePath} ${input.branch}`, error, input.cwd);
28
+ }
29
+ }
30
+ export async function resolveTreeRoot(cwd, workspace, contractId, bind) {
31
+ const repoRoot = await fs.realpath(cwd);
32
+ if (workspace === "here")
33
+ return repoRoot;
34
+ return await contractWorktreePathFromBind(repoRoot, contractId, bind);
35
+ }
36
+ async function removeWorktree(cwd, worktreePath) {
37
+ const git = createGit(cwd);
38
+ try {
39
+ await git.raw(["worktree", "remove", "--force", worktreePath]);
40
+ }
41
+ catch (error) {
42
+ throw wrapGitError(`worktree remove ${worktreePath}`, error, cwd);
43
+ }
44
+ }
45
+ async function deleteBranch(cwd, branch) {
46
+ const git = createGit(cwd);
47
+ try {
48
+ await git.raw(["branch", "-D", branch]);
49
+ }
50
+ catch (error) {
51
+ throw wrapGitError(`branch -D ${branch}`, error, cwd);
52
+ }
53
+ }
54
+ /** Best-effort cleanup of resources created by the current bind attempt. */
55
+ export async function cleanupCreatedBindResources(cwd, resources) {
56
+ const failures = [];
57
+ if (resources.keiyakuPath) {
58
+ try {
59
+ await fs.rm(resources.keiyakuPath, { force: true });
60
+ }
61
+ catch (error) {
62
+ failures.push(`delete ${resources.keiyakuPath}: ${error instanceof Error ? error.message : String(error)}`);
63
+ }
64
+ }
65
+ if (resources.worktreePath) {
66
+ try {
67
+ await removeWorktree(cwd, resources.worktreePath);
68
+ }
69
+ catch (error) {
70
+ failures.push(`remove worktree: ${error instanceof Error ? error.message : String(error)}`);
71
+ }
72
+ }
73
+ if (resources.branch) {
74
+ try {
75
+ await deleteBranch(cwd, resources.branch);
76
+ }
77
+ catch (error) {
78
+ failures.push(`delete branch: ${error instanceof Error ? error.message : String(error)}`);
79
+ }
80
+ }
81
+ return failures;
82
+ }
83
+ export async function materializeContractView(input) {
84
+ const keiyakuPath = path.join(input.targetRoot, KEIYAKU_FILE);
85
+ await fs.mkdir(path.dirname(keiyakuPath), { recursive: true });
86
+ await fs.writeFile(keiyakuPath, renderContractView({ id: input.id, entries: input.entries }), "utf8");
87
+ return keiyakuPath;
88
+ }
89
+ async function occupiedWorktreePlaces(cwd) {
90
+ const occupied = new Set();
91
+ for (const id of await listContractIds(cwd)) {
92
+ const ledger = await readLedger(cwd, id);
93
+ if (!ledger || isTerminalState(deriveContractState(ledger.entries)))
94
+ continue;
95
+ const place = findBindEntry(ledger.entries)?.data.place;
96
+ if (place)
97
+ occupied.add(place);
98
+ }
99
+ return occupied;
100
+ }
101
+ function randomIndex(randomBytes, size) {
102
+ let value = 0;
103
+ for (const byte of randomBytes) {
104
+ value = (value * 256 + byte) % size;
105
+ }
106
+ return value;
107
+ }
108
+ function nextGenerationPlace(base, occupied) {
109
+ for (let generation = 2;; generation += 1) {
110
+ const candidate = `${base}${generation}`;
111
+ if (!occupied.has(candidate))
112
+ return candidate;
113
+ }
114
+ }
115
+ export async function allocateWorktreePlace(cwd, randomBytes) {
116
+ const occupied = await occupiedWorktreePlaces(cwd);
117
+ const candidates = CONTRACT_PLACES.filter((place) => !occupied.has(place));
118
+ if (candidates.length > 0) {
119
+ return candidates[randomIndex(randomBytes, candidates.length)];
120
+ }
121
+ const base = CONTRACT_PLACES[randomIndex(randomBytes, CONTRACT_PLACES.length)];
122
+ return nextGenerationPlace(base, occupied);
123
+ }