@astrosheep/keiyaku 2.9.3 → 2.9.5

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 (282) hide show
  1. package/build/.tsbuildinfo +1 -1
  2. package/build/agents/call-terms.js +14 -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 +26 -222
  6. package/build/agents/harness/index.js +3 -1
  7. package/build/agents/harness/outcome.js +68 -5
  8. package/build/agents/harness/projection.js +179 -124
  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 +82 -53
  21. package/build/agents/providers/codex-app-server/events.js +90 -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/events.js +4 -3
  36. package/build/agents/providers/pi/registration.js +145 -0
  37. package/build/agents/providers/pi/session-schema.js +6 -0
  38. package/build/agents/providers/pi/terms.js +1 -0
  39. package/build/agents/providers/registration.js +7 -0
  40. package/build/agents/providers/registry.js +76 -0
  41. package/build/agents/selector.js +2 -29
  42. package/build/agents/types.js +10 -0
  43. package/build/artifact-directories.js +22 -0
  44. package/build/cli/commands/akuma/akuma/handler.js +1 -1
  45. package/build/cli/commands/akuma/akuma/meta.js +1 -1
  46. package/build/cli/commands/akuma/list/meta-ls.js +1 -1
  47. package/build/cli/commands/akuma/view/handler.js +5 -4
  48. package/build/cli/commands/akuma/view/meta.js +1 -1
  49. package/build/cli/commands/akuma.js +6 -0
  50. package/build/cli/commands/contract/amend/handler.js +8 -2
  51. package/build/cli/commands/contract/amend/meta.js +4 -4
  52. package/build/cli/commands/contract/arc/handler.js +8 -2
  53. package/build/cli/commands/contract/arc/meta.js +4 -4
  54. package/build/cli/commands/contract/audit/handler.js +16 -0
  55. package/build/cli/commands/contract/audit/meta.js +16 -0
  56. package/build/cli/commands/contract/bind/handler.js +4 -3
  57. package/build/cli/commands/contract/bind/meta.js +44 -8
  58. package/build/cli/commands/contract/catalog.js +2 -0
  59. package/build/cli/commands/contract/forfeit/handler.js +4 -4
  60. package/build/cli/commands/contract/forfeit/meta.js +1 -1
  61. package/build/cli/commands/contract/log/handler.js +3 -3
  62. package/build/cli/commands/contract/log/meta.js +1 -1
  63. package/build/cli/commands/contract/petition/handler.js +5 -8
  64. package/build/cli/commands/contract/petition/meta.js +6 -6
  65. package/build/cli/commands/contract/renew/handler.js +20 -6
  66. package/build/cli/commands/contract/renew/meta.js +6 -5
  67. package/build/cli/commands/metadata.js +59 -0
  68. package/build/cli/commands/projection/call/handler.js +6 -5
  69. package/build/cli/commands/projection/call/meta.js +4 -1
  70. package/build/cli/commands/projection/kill/handler.js +16 -32
  71. package/build/cli/commands/projection/kill/meta.js +1 -1
  72. package/build/cli/commands/projection/revive/meta.js +4 -1
  73. package/build/cli/commands/projection/shared.js +28 -0
  74. package/build/cli/commands/projection/status/handler.js +1 -1
  75. package/build/cli/commands/projection/status/meta.js +1 -1
  76. package/build/cli/commands/projection/tell/handler.js +14 -30
  77. package/build/cli/commands/projection/tell/meta.js +4 -1
  78. package/build/cli/commands/projection/wait/handler.js +45 -22
  79. package/build/cli/commands/projection/wait/meta.js +8 -3
  80. package/build/cli/commands/registry.js +2 -54
  81. package/build/cli/commands/shared.js +10 -7
  82. package/build/cli/commands/skills/install/handler.js +2 -5
  83. package/build/cli/commands/skills/install/meta.js +1 -1
  84. package/build/cli/commands/skills/skills/handler.js +1 -1
  85. package/build/cli/commands/skills/skills/meta.js +1 -1
  86. package/build/cli/commands/system/completion/meta.js +1 -1
  87. package/build/cli/commands/system/dump-env/meta.js +1 -1
  88. package/build/cli/commands/system/guide/meta.js +1 -1
  89. package/build/cli/commands/task/add/handler.js +7 -15
  90. package/build/cli/commands/task/add/meta.js +4 -1
  91. package/build/cli/commands/task/catalog.js +2 -2
  92. package/build/cli/commands/task/doctor/meta.js +1 -1
  93. package/build/cli/commands/task/done/handler.js +4 -8
  94. package/build/cli/commands/task/done/meta.js +1 -1
  95. package/build/cli/commands/task/drop/handler.js +3 -6
  96. package/build/cli/commands/task/drop/meta.js +1 -1
  97. package/build/cli/commands/task/ls/handler.js +12 -8
  98. package/build/cli/commands/task/ls/meta.js +3 -3
  99. package/build/cli/commands/task/shared.js +14 -4
  100. package/build/cli/commands/task/{view → show}/handler.js +7 -8
  101. package/build/cli/commands/task/show/meta.js +8 -0
  102. package/build/cli/commands/task/start/handler.js +3 -6
  103. package/build/cli/commands/task/start/meta.js +1 -1
  104. package/build/cli/commands/task/stop/handler.js +4 -8
  105. package/build/cli/commands/task/stop/meta.js +1 -1
  106. package/build/cli/commands/task/task/handler.js +1 -1
  107. package/build/cli/commands/task/task/meta.js +1 -1
  108. package/build/cli/commands/task/update/handler.js +6 -11
  109. package/build/cli/commands/task/update/meta.js +4 -1
  110. package/build/cli/completion.js +1 -1
  111. package/build/cli/flags.js +37 -6
  112. package/build/cli/help.js +7 -14
  113. package/build/cli/index.js +112 -154
  114. package/build/cli/missing-subcommand.js +7 -0
  115. package/build/cli/output-stream-error-policy.js +19 -5
  116. package/build/cli/parse-flags.js +33 -7
  117. package/build/cli/parse-metadata.js +3 -9
  118. package/build/cli/parse-selectors.js +2 -1
  119. package/build/cli/parse.js +35 -5
  120. package/build/cli/projection-address.js +12 -12
  121. package/build/cli/render/address.js +41 -37
  122. package/build/cli/render/arc.js +24 -12
  123. package/build/cli/render/audit.js +121 -0
  124. package/build/cli/render/call.js +11 -5
  125. package/build/cli/render/errors.js +36 -1
  126. package/build/cli/render/format.js +4 -0
  127. package/build/cli/render/kanshi.js +6 -12
  128. package/build/cli/render/kill.js +9 -0
  129. package/build/cli/render/misc.js +58 -13
  130. package/build/cli/render/petition.js +20 -15
  131. package/build/cli/render/projection-activity.js +15 -6
  132. package/build/cli/render/shared.js +60 -21
  133. package/build/cli/render/skills.js +10 -0
  134. package/build/cli/render/status.js +56 -23
  135. package/build/cli/render/success-response.js +78 -0
  136. package/build/cli/render/task.js +66 -57
  137. package/build/cli/render/tell.js +5 -0
  138. package/build/cli/render/terminal-failure.js +63 -0
  139. package/build/cli/render/types.js +1 -0
  140. package/build/cli/render/wait.js +68 -38
  141. package/build/cli/types.js +1 -1
  142. package/build/config/akuma-loader.js +0 -5
  143. package/build/config/env-keys.js +3 -1
  144. package/build/config/env.js +3 -0
  145. package/build/config/provider-policy-ownership.js +3 -32
  146. package/build/config/settings/disease.js +8 -1
  147. package/build/config/settings/loader.js +11 -3
  148. package/build/config/settings/provider-instance-fields.js +51 -0
  149. package/build/config/settings/schema.js +6 -176
  150. package/build/core/addressing.js +66 -16
  151. package/build/core/amend.js +61 -18
  152. package/build/core/arc.js +33 -73
  153. package/build/core/audit.js +650 -0
  154. package/build/core/bind.js +82 -35
  155. package/build/core/call/call.js +15 -9
  156. package/build/core/call/context.js +6 -51
  157. package/build/core/call/execution.js +22 -22
  158. package/build/core/call/prompt.js +14 -1
  159. package/build/core/command-markdown.js +45 -0
  160. package/build/core/context.js +13 -7
  161. package/build/core/contract-view.js +22 -6
  162. package/build/core/draft.js +139 -19
  163. package/build/core/entry.js +3 -4
  164. package/build/core/forfeit.js +5 -2
  165. package/build/core/hints.js +1 -75
  166. package/build/core/identifier-slug.js +66 -0
  167. package/build/core/ids.js +25 -11
  168. package/build/core/ledger.js +20 -68
  169. package/build/core/markdown/lex.js +2 -1
  170. package/build/core/markdown/parser.js +0 -68
  171. package/build/core/markdown/render.js +68 -0
  172. package/build/core/markdown/sections.js +2 -1
  173. package/build/core/outcome-base.js +4 -0
  174. package/build/core/projection/generation/database.js +41 -52
  175. package/build/core/projection/generation/model.js +63 -2
  176. package/build/core/{projection-generation-continuation.js → projection/generation/projection-generation-continuation.js} +3 -3
  177. package/build/core/{projection-generation-execution.js → projection/generation/projection-generation-execution.js} +36 -53
  178. package/build/core/{projection-generation-identity.js → projection/generation/projection-generation-identity.js} +2 -2
  179. package/build/core/{projection-generation-launcher.js → projection/generation/projection-generation-launcher.js} +9 -7
  180. package/build/core/{projection-generation-process.js → projection/generation/projection-generation-process.js} +2 -1
  181. package/build/core/{projection-generation-runner.js → projection/generation/projection-generation-runner.js} +19 -3
  182. package/build/core/projection/generation/store.js +3 -3
  183. package/build/core/projection/generation/transitions.js +19 -3
  184. package/build/core/projection/index.js +27 -0
  185. package/build/core/{projection-activity.js → projection/projection-activity.js} +12 -0
  186. package/build/core/{projection-alias.js → projection/projection-alias.js} +13 -13
  187. package/build/core/projection/projection-coordinate.js +61 -0
  188. package/build/core/{projection-core.js → projection/projection-core.js} +9 -9
  189. package/build/core/{projection-execution-observer.js → projection/projection-execution-observer.js} +37 -78
  190. package/build/core/{projection-identity.js → projection/projection-identity.js} +1 -1
  191. package/build/core/{projection-kill.js → projection/projection-kill.js} +1 -1
  192. package/build/core/{projection-life-observer.js → projection/projection-life-observer.js} +16 -2
  193. package/build/core/{projection-mint.js → projection/projection-mint.js} +10 -10
  194. package/build/core/{projection-status.js → projection/projection-status.js} +163 -45
  195. package/build/core/projection/projection-terminal-failure.js +106 -0
  196. package/build/core/projection/projection-wait.js +275 -0
  197. package/build/core/projection/projection-wake.js +227 -0
  198. package/build/core/provider-loader-ports.js +4 -0
  199. package/build/core/ref-log.js +65 -40
  200. package/build/core/registry.js +63 -10
  201. package/build/core/renew-session.js +128 -0
  202. package/build/core/renew.js +448 -102
  203. package/build/core/scope.js +272 -68
  204. package/build/core/seal.js +165 -40
  205. package/build/core/{claim-delivery.js → settlement/claim-delivery.js} +8 -8
  206. package/build/core/{claim.js → settlement/claim.js} +32 -8
  207. package/build/core/settlement/index.js +19 -0
  208. package/build/core/{petition-claim-gates.js → settlement/petition-claim-gates.js} +24 -49
  209. package/build/core/{petition-forfeit.js → settlement/petition-forfeit.js} +2 -2
  210. package/build/core/{petition-head-guard.js → settlement/petition-head-guard.js} +2 -2
  211. package/build/core/settlement/petition-io.js +1 -0
  212. package/build/core/{petition-preview.js → settlement/petition-preview.js} +2 -2
  213. package/build/core/{petition.js → settlement/petition.js} +21 -12
  214. package/build/core/settlement/queue-read-model.js +143 -0
  215. package/build/core/settlement/queue-seat-allocation.js +156 -0
  216. package/build/core/settlement/queue.js +6 -0
  217. package/build/core/settlement/settlement.js +288 -0
  218. package/build/core/{verdict.js → settlement/verdict.js} +9 -37
  219. package/build/core/settlement/verification.js +59 -0
  220. package/build/core/status/board.js +62 -41
  221. package/build/core/status/ledger-batch.js +158 -0
  222. package/build/core/status/reconciliation.js +10 -4
  223. package/build/core/stored-agent-event.js +6 -2
  224. package/build/core/task/board.js +41 -4
  225. package/build/core/task/commands.js +45 -28
  226. package/build/core/task/document.js +5 -0
  227. package/build/core/task/index.js +12 -0
  228. package/build/core/task/model.js +8 -1
  229. package/build/core/task/query.js +172 -0
  230. package/build/core/task/settlement-git.js +265 -74
  231. package/build/core/task/settlement-policy.js +67 -29
  232. package/build/core/task/source-board.js +1 -0
  233. package/build/core/task/task-contract.js +444 -0
  234. package/build/core/{task-doctor.js → task/task-doctor.js} +1 -1
  235. package/build/core/{task-git-actor.js → task/task-git-actor.js} +5 -10
  236. package/build/core/{task-git-runtime.js → task/task-git-runtime.js} +3 -3
  237. package/build/core/{task-git-store.js → task/task-git-store.js} +90 -19
  238. package/build/core/task/task-repository.js +1 -0
  239. package/build/core/{task-store-repository.js → task/task-store-repository.js} +6 -4
  240. package/build/core/task/task-store.js +1 -0
  241. package/build/core/{task-worktree.js → task/task-worktree.js} +2 -1
  242. package/build/core/task/task.js +7 -0
  243. package/build/core/task/tree.js +37 -0
  244. package/build/core/task/validation.js +5 -2
  245. package/build/core/transcripts.js +15 -3
  246. package/build/core/worktree-path.js +43 -28
  247. package/build/flow-error.js +83 -39
  248. package/build/fs/path-coordinate.js +16 -0
  249. package/build/generated/version.js +3 -2
  250. package/build/git/branches.js +2 -1
  251. package/build/git/core.js +106 -2
  252. package/build/git/diff/parsers.js +23 -13
  253. package/build/git/diff/structured.js +127 -0
  254. package/build/git/path-coordinate.js +17 -0
  255. package/build/git/refs.js +57 -0
  256. package/build/git/streaming-batch.js +301 -0
  257. package/build/git/worktree.js +65 -0
  258. package/build/index.js +9 -9
  259. package/build/keiyaku.js +2 -36
  260. package/build/telemetry/logger.js +4 -2
  261. package/package.json +4 -10
  262. package/skills/keiyaku/SKILL.md +5 -4
  263. package/skills/keiyaku-akuma/SKILL.md +25 -11
  264. package/skills/keiyaku-task/SKILL.md +17 -8
  265. package/skills/keiyaku-workflow/SKILL.md +58 -9
  266. package/build/agents/providers/codex-sdk.js +0 -329
  267. package/build/cli/commands/task/view/meta.js +0 -8
  268. package/build/core/command-io.js +0 -174
  269. package/build/core/path-coordinate.js +0 -27
  270. package/build/core/petition-claim.js +0 -117
  271. package/build/core/petition-run.js +0 -83
  272. package/build/core/projection-coordinate.js +0 -63
  273. package/build/core/projection-wait.js +0 -165
  274. package/build/core/projection-wake.js +0 -136
  275. package/build/core/queue.js +0 -343
  276. package/build/core/task-contract.js +0 -237
  277. package/build/core/task.js +0 -4
  278. /package/build/{core/task-repository.js → agents/launch-snapshot/types.js} +0 -0
  279. /package/build/{core/task-store.js → agents/providers/claude-agent-sdk/terms.js} +0 -0
  280. /package/build/core/{projection-generation-runtime.js → projection/generation/projection-generation-runtime.js} +0 -0
  281. /package/build/core/{projection-life-protocol.js → projection/projection-life-protocol.js} +0 -0
  282. /package/build/core/{projection-runner-lock.js → projection/projection-runner-lock.js} +0 -0
@@ -1,185 +1,15 @@
1
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
- ]);
2
+ import { BUILTIN_PROVIDER_INSTANCE_CANDIDATES as REGISTRY_BUILTIN_PROVIDER_INSTANCE_CANDIDATES, providerInstanceSchema as registryProviderInstanceSchema, } from "../../agents/providers/registry.js";
3
+ export const providerInstanceSchema = registryProviderInstanceSchema;
4
+ export const BUILTIN_PROVIDER_INSTANCE_CANDIDATES = REGISTRY_BUILTIN_PROVIDER_INSTANCE_CANDIDATES;
159
5
  const PROVIDER_INSTANCE_NAME_PATTERN = /^[a-z0-9][a-z0-9-]*$/;
160
6
  export const providerInstanceNameSchema = z
161
7
  .string()
162
8
  .max(64, "must contain at most 64 characters.")
163
9
  .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
- };
10
+ // Ensure the registry builtin map stays keyed by the closed provider vocabulary.
11
+ const _builtinCheck = BUILTIN_PROVIDER_INSTANCE_CANDIDATES;
12
+ void _builtinCheck;
183
13
  const AGENT_NAME_PATTERN = /^[a-zA-Z0-9]+(?:[.-][a-zA-Z0-9]+)*$/;
184
14
  export const agentNameSchema = z
185
15
  .string()
@@ -1,9 +1,13 @@
1
1
  import * as path from "node:path";
2
2
  import { FlowError } from "../flow-error.js";
3
+ import { errorContainsAnyPattern, NOT_GIT_REPOSITORY_PATTERNS } from "../git/core.js";
4
+ import { commissionSlug, formatCommissionCoordinate } from "./ids.js";
3
5
  import { listContractIds, readLedger } from "./ledger.js";
4
6
  import { isResponseArtifactId } from "./response-artifact-id.js";
5
- import { stableRepoRoot } from "./worktree-path.js";
7
+ import { activeContractBoundByEngineWorktree, stableRepoRoot } from "./worktree-path.js";
8
+ import { assertNoRenewRecoverySession } from "./renew-session.js";
6
9
  import { deriveContractState, isTerminalState, } from "./status/lifecycle.js";
10
+ const AMBIGUOUS_OBJECTIVE_MAX_CHARS = 60;
7
11
  function normalizeAddressQuery(raw) {
8
12
  const value = raw.startsWith("@") ? raw.slice(1) : raw;
9
13
  if (!value.trim()) {
@@ -17,8 +21,8 @@ class AddressedFlowError extends FlowError {
17
21
  constructor(error, carrier) {
18
22
  super(error.code, error.message, {
19
23
  cause: error,
20
- hints: error.hints,
21
24
  review: error.review,
25
+ facts: error.facts,
22
26
  });
23
27
  this.name = error.name;
24
28
  this[ADDRESS_CARRIER] = carrier;
@@ -108,9 +112,8 @@ export class AddressResolutionError extends FlowError {
108
112
  this.attempt = attempt;
109
113
  }
110
114
  }
111
- function contractSlug(contractId) {
112
- const separator = contractId.indexOf(".");
113
- return separator > 0 ? contractId.slice(0, separator) : contractId;
115
+ function candidatePlace(candidate) {
116
+ return candidate.bind.data.workspace === "worktree" ? candidate.bind.data.place ?? null : null;
114
117
  }
115
118
  async function commissionAddressCandidates(cwd) {
116
119
  const ids = await listContractIds(cwd);
@@ -135,9 +138,9 @@ function matchCommissionAddress(query, candidates) {
135
138
  const matches = [];
136
139
  if (candidate.contractId === query)
137
140
  matches.push({ ...candidate, spelling: "id" });
138
- if (contractSlug(candidate.contractId) === query)
141
+ if (commissionSlug(candidate.contractId) === query)
139
142
  matches.push({ ...candidate, spelling: "slug" });
140
- if (candidate.active && candidate.bind.data.place === query) {
143
+ if (candidate.active && candidatePlace(candidate) === query) {
141
144
  matches.push({ ...candidate, spelling: "place" });
142
145
  }
143
146
  return matches;
@@ -146,16 +149,28 @@ function matchCommissionAddress(query, candidates) {
146
149
  function attemptCandidates(candidates) {
147
150
  return candidates.map((candidate) => ({
148
151
  commissionId: candidate.contractId,
149
- place: candidate.bind.data.place ?? null,
152
+ place: candidatePlace(candidate),
150
153
  name: candidate.bind.data.name,
151
154
  objective: candidate.bind.data.objective,
152
155
  lifecycle: candidate.lifecycle,
153
156
  target: { branch: candidate.bind.data.target },
154
157
  }));
155
158
  }
156
- function formatAmbiguousCandidate(query, candidate) {
157
- const label = candidate.matchedBy ?? "candidate";
158
- return `${label} @${query}: ${candidate.name} · ${candidate.objective} · commission ${candidate.commissionId}`;
159
+ function truncateObjectiveFirstLine(objective) {
160
+ const firstLine = objective.split(/\r?\n/, 1)[0]?.trim() ?? "";
161
+ if (firstLine.length <= AMBIGUOUS_OBJECTIVE_MAX_CHARS)
162
+ return firstLine;
163
+ return `${firstLine.slice(0, AMBIGUOUS_OBJECTIVE_MAX_CHARS)}…`;
164
+ }
165
+ function formatAmbiguousCandidate(candidate) {
166
+ const coordinate = formatCommissionCoordinate({
167
+ commissionId: candidate.commissionId,
168
+ place: candidate.place,
169
+ });
170
+ const objective = truncateObjectiveFirstLine(candidate.objective);
171
+ return [coordinate, objective || undefined, candidate.commissionId]
172
+ .filter((part) => part !== undefined)
173
+ .join(" · ");
159
174
  }
160
175
  async function resolvedRepository(cwd) {
161
176
  return { kind: "repository", stableRoot: await stableRepoRoot(cwd) };
@@ -166,7 +181,7 @@ function buildResolvedAddress(input) {
166
181
  workdir: input.workdir,
167
182
  binding: { kind: "commission", commissionId: input.candidate.contractId },
168
183
  spelling: { asTyped: input.asTyped, source: input.source, matchedBy: input.matchedBy },
169
- place: { display: input.candidate.bind.data.place ?? null },
184
+ place: { display: candidatePlace(input.candidate) },
170
185
  lifecycle: input.candidate.lifecycle,
171
186
  target: { branch: input.candidate.bind.data.target },
172
187
  inference: input.inference,
@@ -188,8 +203,8 @@ export function buildUncommissionedRepositoryAddress(input) {
188
203
  inference: input.inference,
189
204
  });
190
205
  }
191
- export async function resolveContractAddress(cwd, raw, source = raw?.startsWith("@") ? "at-address" : "explicit-flag") {
192
- const workdir = path.resolve(cwd);
206
+ export async function resolveContractAddress(cwd, raw, source = raw?.startsWith("@") ? "at-address" : "explicit-flag", effectiveDirectory = cwd) {
207
+ const workdir = path.resolve(effectiveDirectory);
193
208
  const repo = await resolvedRepository(cwd);
194
209
  if (raw !== undefined) {
195
210
  const query = normalizeAddressQuery(raw);
@@ -216,7 +231,7 @@ export async function resolveContractAddress(cwd, raw, source = raw?.startsWith(
216
231
  candidates: matches.map((candidate) => ({
217
232
  commissionId: candidate.contractId,
218
233
  matchedBy: candidate.spelling,
219
- place: candidate.bind.data.place ?? null,
234
+ place: candidatePlace(candidate),
220
235
  name: candidate.bind.data.name,
221
236
  objective: candidate.bind.data.objective,
222
237
  lifecycle: candidate.lifecycle,
@@ -238,9 +253,34 @@ export async function resolveContractAddress(cwd, raw, source = raw?.startsWith(
238
253
  if (matches.length === 0) {
239
254
  throw new AddressResolutionError("EMPTY_PARAM", `unknown contract address @${query}`, attempt);
240
255
  }
241
- throw new AddressResolutionError("CONTRACT_AMBIGUOUS", `contract address @${query} is ambiguous: ${attempt.candidates.map((candidate) => formatAmbiguousCandidate(query, candidate)).join("; ")}; use a full @commission-id`, attempt);
256
+ throw new AddressResolutionError("CONTRACT_AMBIGUOUS", `@${query} is ambiguous:\n${attempt.candidates.map((candidate) => ` ${formatAmbiguousCandidate(candidate)}`).join("\n")}\nuse a full @commission-id`, attempt);
242
257
  }
243
258
  const candidates = await commissionAddressCandidates(repo.stableRoot);
259
+ let boundContractId;
260
+ try {
261
+ const effectiveRepo = await stableRepoRoot(workdir);
262
+ if (effectiveRepo === repo.stableRoot) {
263
+ boundContractId = await activeContractBoundByEngineWorktree(workdir);
264
+ }
265
+ }
266
+ catch (error) {
267
+ if (!errorContainsAnyPattern(error, NOT_GIT_REPOSITORY_PATTERNS))
268
+ throw error;
269
+ }
270
+ if (boundContractId) {
271
+ const candidate = candidates.find((item) => item.active && item.contractId === boundContractId);
272
+ if (candidate) {
273
+ return buildResolvedAddress({
274
+ repo,
275
+ workdir,
276
+ candidate,
277
+ matchedBy: "id",
278
+ asTyped: `@${candidate.contractId}`,
279
+ source: "worktree-binding",
280
+ inference: ["verified active engine worktree binding"],
281
+ });
282
+ }
283
+ }
244
284
  const operable = candidates.filter((candidate) => candidate.active);
245
285
  const attempt = {
246
286
  repo,
@@ -265,3 +305,13 @@ export async function resolveContractAddress(cwd, raw, source = raw?.startsWith(
265
305
  ? "no active commission found; pass @place, @slug, full @commission-id, or --contract <addr>"
266
306
  : "multiple active commissions found; pass @place, @slug, full @commission-id, or --contract <addr>", attempt);
267
307
  }
308
+ export async function resolveExistingContractAddress(cwd, raw, source = raw?.startsWith("@") ? "at-address" : "explicit-flag", effectiveDirectory = cwd) {
309
+ const address = await resolveContractAddress(cwd, raw, source, effectiveDirectory);
310
+ try {
311
+ await assertNoRenewRecoverySession(address.repo.stableRoot, address.binding.commissionId);
312
+ }
313
+ catch (error) {
314
+ throw attachAddressCarrier(error, address);
315
+ }
316
+ return address;
317
+ }
@@ -1,15 +1,63 @@
1
- import * as fs from "node:fs/promises";
2
- import * as path from "node:path";
3
1
  import { FlowError } from "../flow-error.js";
4
2
  import { getCurrentBranch, requireGitRepository } from "../git/branches.js";
5
- import { KEIYAKU_FILE } from "../keiyaku.js";
6
- import { activeLedgerRef, appendWithRetry, readLedger } from "./ledger.js";
7
- import { renderContractView } from "./contract-view.js";
3
+ import { activeLedgerRef, appendWithRetry } from "./ledger.js";
4
+ import { refreshContractView } from "./contract-view.js";
8
5
  import { deriveContractState, isTerminalState } from "./status/lifecycle.js";
9
6
  import { resolveContractAddress, withResolvedAddress } from "./addressing.js";
10
7
  import { resolveDefaultBranch } from "./status/drift.js";
11
- import { assertCleanWorkingTree } from "./arc.js";
12
- import { normalizeScopePattern } from "./scope.js";
8
+ import { markdownSourceSections, normalizeScopePattern, validateScopeFragmentLines } from "./scope.js";
9
+ import { normalizeSectionTitle } from "./markdown/titles.js";
10
+ import { resolveContractDeliveryCwd } from "./worktree-path.js";
11
+ function amendScopeHeading(name) {
12
+ return `## Scope ${name[0].toUpperCase()}${name.slice(1)}`;
13
+ }
14
+ function parseAmendScopeSections(markdown) {
15
+ const sections = {};
16
+ for (const section of markdownSourceSections(markdown)) {
17
+ if (section.level !== 2)
18
+ continue;
19
+ const title = normalizeSectionTitle(section.title);
20
+ if (title === "scope add") {
21
+ throw new FlowError("INVALID_KEIYAKU_DRAFT", "Scope Add is obsolete; use ## Scope Append with a fenced gitignore-subset block");
22
+ }
23
+ if (title !== "scope append")
24
+ continue;
25
+ if (sections.append) {
26
+ throw new FlowError("INVALID_KEIYAKU_DRAFT", `amend input may contain ${amendScopeHeading("append")} at most once`);
27
+ }
28
+ sections.append = {
29
+ name: "append",
30
+ start: section.start,
31
+ contentStart: section.contentStart,
32
+ end: section.end,
33
+ };
34
+ }
35
+ let prose = markdown;
36
+ for (const section of Object.values(sections).sort((left, right) => right.start - left.start)) {
37
+ prose = `${prose.slice(0, section.start)}${prose.slice(section.end)}`;
38
+ }
39
+ return { sections, prose };
40
+ }
41
+ function scopePatterns(markdown, section) {
42
+ return validateScopeFragmentLines(markdown.slice(section.contentStart, section.end).split(/\r?\n/), {
43
+ heading: amendScopeHeading(section.name),
44
+ emptyMessage: `amend input has an empty ${amendScopeHeading(section.name)} section`,
45
+ });
46
+ }
47
+ export function buildAmendInput(markdown, cwd, contractId, contractAddressSource) {
48
+ const { sections, prose } = parseAmendScopeSections(markdown);
49
+ const append = sections.append ? scopePatterns(markdown, sections.append) : [];
50
+ if (!prose.trim()) {
51
+ throw new FlowError("EMPTY_PARAM", "amendment cannot be empty");
52
+ }
53
+ return {
54
+ cwd,
55
+ ...(contractId ? { contractId } : {}),
56
+ ...(contractAddressSource ? { contractAddressSource } : {}),
57
+ amendment: prose,
58
+ ...(sections.append ? { scopeDelta: { add: append } } : {}),
59
+ };
60
+ }
13
61
  function requireAmendment(value) {
14
62
  if (!value.trim())
15
63
  throw new FlowError("EMPTY_PARAM", "amendment cannot be empty");
@@ -24,13 +72,6 @@ function assertContractOperable(contractId, entries) {
24
72
  throw new FlowError("INTERNAL_STATE", `contract ${contractId} is terminal (${state.state})`);
25
73
  }
26
74
  }
27
- async function renderUpdatedContract(cwd, contractId) {
28
- const ledger = await readLedger(cwd, contractId);
29
- if (!ledger) {
30
- throw new FlowError("INTERNAL_STATE", `contract ${contractId} active ledger disappeared before render`);
31
- }
32
- await fs.writeFile(path.join(cwd, KEIYAKU_FILE), renderContractView({ id: contractId, entries: ledger.entries }), "utf8");
33
- }
34
75
  function normalizeScopeDelta(scopeDelta) {
35
76
  if (!scopeDelta)
36
77
  return undefined;
@@ -43,6 +84,7 @@ function normalizeScopeDelta(scopeDelta) {
43
84
  export async function amendContract(input) {
44
85
  const amendment = requireAmendment(input.amendment);
45
86
  const scopeDelta = normalizeScopeDelta(input.scopeDelta);
87
+ const renderCwd = input.renderCwd ?? input.cwd;
46
88
  const at = new Date(input.nowMs).toISOString();
47
89
  const ref = activeLedgerRef(input.contractId);
48
90
  let amendmentNumber = 0;
@@ -67,20 +109,21 @@ export async function amendContract(input) {
67
109
  if (amendmentNumber === 0) {
68
110
  throw new FlowError("INTERNAL_STATE", `contract ${input.contractId} active ledger disappeared during amend`);
69
111
  }
70
- await renderUpdatedContract(input.cwd, input.contractId);
112
+ await refreshContractView({ ledgerCwd: input.cwd, renderCwd, contractId: input.contractId });
71
113
  return { contractId: input.contractId, amendmentNumber, ledgerHead: result.head };
72
114
  }
73
115
  export async function amendKeiyaku(input) {
74
116
  await requireGitRepository(input.cwd, "amend");
75
- const address = await resolveContractAddress(input.cwd, input.contractId, input.contractAddressSource);
117
+ const address = input.address ?? await resolveContractAddress(input.cwd, input.contractId, input.contractAddressSource);
76
118
  return await withResolvedAddress(address, async () => {
77
119
  const contractId = address.binding.commissionId;
78
- await assertCleanWorkingTree(input.cwd, []);
120
+ const renderCwd = await resolveContractDeliveryCwd(input.cwd, contractId);
79
121
  const amendment = requireAmendment(input.amendment);
80
- const currentBranch = await getCurrentBranch(input.cwd);
122
+ const currentBranch = await getCurrentBranch(renderCwd);
81
123
  const baseBranch = (await resolveDefaultBranch(input.cwd))?.branch ?? currentBranch;
82
124
  const amended = await amendContract({
83
125
  cwd: input.cwd,
126
+ renderCwd,
84
127
  contractId,
85
128
  actor: "keiyaku",
86
129
  nowMs: Date.now(),
package/build/core/arc.js CHANGED
@@ -2,63 +2,18 @@ import * as fs from "node:fs/promises";
2
2
  import * as path from "node:path";
3
3
  import { requireText, FlowError } from "../flow-error.js";
4
4
  import { getCurrentBranch, requireGitRepository } from "../git/branches.js";
5
- import { DIRTY_FILE_CATEGORY, getDirtyFiles, renderDirtyFileStatusLine } from "../git/worktree.js";
5
+ import { assertCleanTrackedWorkingTree } from "../git/worktree.js";
6
6
  import { KEIYAKU_FILE, ACTOR_IDENTITY } from "../keiyaku.js";
7
- import { buildDirtyWorktreeArtifactHint } from "./hints.js";
8
7
  import { normalizeInlineTitle } from "./markdown/titles.js";
9
- import { parseCommandMarkdown, requireMarkdownTextSection, requireMarkdownTitle, } from "./command-io.js";
8
+ import { parseCommandMarkdown, requireMarkdownTextSection, requireMarkdownTitle, } from "./command-markdown.js";
10
9
  import { resolveContractAddress, withResolvedAddress } from "./addressing.js";
11
10
  import { activeLedgerRef, appendWithRetry, readLedger } from "./ledger.js";
12
- import { renderContractView } from "./contract-view.js";
13
- import { findOpenArc, getMaxArc, sealCurrentArc } from "./seal.js";
11
+ import { refreshContractView } from "./contract-view.js";
12
+ import { appendScopeTerms, findOpenArc, getMaxArc, sealCurrentArc } from "./seal.js";
14
13
  import { deriveContractState, isTerminalState } from "./status/lifecycle.js";
15
14
  import { resolveDefaultBranch } from "./status/drift.js";
16
15
  import { persistResponseHistory } from "./transcripts.js";
17
- const DIRTY_WORKTREE_LIST_LIMIT = 10;
18
- const KEIYAKU_ARTIFACT_DIR_PREFIX = ".keiyaku/";
19
- function normalizePathForDirtyMatch(cwd, filePath) {
20
- const normalizedPath = filePath.trim();
21
- if (!normalizedPath)
22
- return "";
23
- const repoRelativePath = path.isAbsolute(normalizedPath) ? path.relative(cwd, normalizedPath) : normalizedPath;
24
- const platformNormalizedPath = path.normalize(repoRelativePath.replace(/[\\/]+/g, path.sep));
25
- return platformNormalizedPath.split(path.sep).join("/").replace(/^\.\/+/, "").replace(/^\/+/, "");
26
- }
27
- function pathSegments(normalizedPath) {
28
- return normalizedPath.split("/").filter((segment) => segment.length > 0 && segment !== ".");
29
- }
30
- function matchesIgnorePattern(filePath, ignorePattern) {
31
- const patternSegments = pathSegments(ignorePattern);
32
- const fileSegments = pathSegments(filePath);
33
- return patternSegments.length > 0
34
- && fileSegments.length >= patternSegments.length
35
- && patternSegments.every((segment, index) => fileSegments[index] === segment);
36
- }
37
- export function filterDirtyFilesByAllowlist(cwd, dirtyFiles, ignorePatterns) {
38
- const ignoredPaths = Array.from(new Set((ignorePatterns ?? []).map((pattern) => normalizePathForDirtyMatch(cwd, pattern)).filter(Boolean)));
39
- return {
40
- dirtyFiles: dirtyFiles.filter((file) => {
41
- const normalizedFilePath = normalizePathForDirtyMatch(cwd, file.path);
42
- return !ignoredPaths.some((ignoredPath) => matchesIgnorePattern(normalizedFilePath, ignoredPath));
43
- }),
44
- ignoredPaths,
45
- };
46
- }
47
- export function filterBlockingDirtyFiles(dirtyFiles) {
48
- return dirtyFiles.filter((file) => file.category !== DIRTY_FILE_CATEGORY.untracked);
49
- }
50
- export async function assertCleanWorkingTree(cwd, ignorePatterns) {
51
- const blockingDirtyFiles = filterBlockingDirtyFiles(await getDirtyFiles(cwd));
52
- const { dirtyFiles } = filterDirtyFilesByAllowlist(cwd, blockingDirtyFiles, ignorePatterns);
53
- if (dirtyFiles.length === 0)
54
- return;
55
- const hasDirtyKeiyakuArtifacts = dirtyFiles.some((file) => normalizePathForDirtyMatch(cwd, file.path).startsWith(KEIYAKU_ARTIFACT_DIR_PREFIX));
56
- const shown = dirtyFiles.slice(0, DIRTY_WORKTREE_LIST_LIMIT);
57
- const list = shown.map((file) => ` ${renderDirtyFileStatusLine(file)}`).join("\n");
58
- const overflowCount = dirtyFiles.length - shown.length;
59
- const overflowLine = overflowCount > 0 ? `\n ... (+${overflowCount} more)` : "";
60
- throw new FlowError("DIRTY_WORKTREE", `Uncommitted changes detected in working tree:\n${list}${overflowLine}\n\nBlocking changes must be committed or stashed before proceeding.`, hasDirtyKeiyakuArtifacts ? { hints: [buildDirtyWorktreeArtifactHint()] } : undefined);
61
- }
16
+ import { resolveContractDeliveryCwd } from "./worktree-path.js";
62
17
  export function buildArcViews(entries) {
63
18
  const arcs = new Map();
64
19
  for (const entry of entries) {
@@ -96,29 +51,31 @@ function assertArcOpenable(contractId, entries) {
96
51
  throw new FlowError("INTERNAL_STATE", `contract ${contractId} cannot open arc from state ${state.state}`);
97
52
  }
98
53
  }
99
- async function renderUpdatedContract(cwd, contractId) {
100
- const ledger = await readLedger(cwd, contractId);
101
- if (!ledger) {
102
- throw new FlowError("INTERNAL_STATE", `contract ${contractId} active ledger disappeared before render`);
103
- }
104
- await fs.writeFile(path.join(cwd, KEIYAKU_FILE), renderContractView({ id: contractId, entries: ledger.entries }), "utf8");
105
- }
106
54
  export async function openArc(input) {
107
55
  const title = requireText("title", input.title);
108
56
  const objective = requireText("objective", input.objective);
109
57
  const brief = requireText("brief", input.brief);
58
+ const renderCwd = input.renderCwd ?? input.cwd;
110
59
  const ledger = await readLedger(input.cwd, input.contractId);
111
60
  if (!ledger) {
112
61
  throw new FlowError("INTERNAL_STATE", `contract ${input.contractId} not found or not active`);
113
62
  }
114
63
  assertArcOpenable(input.contractId, ledger.entries);
115
- const sealed = await sealCurrentArc({
64
+ await appendScopeTerms({
116
65
  cwd: input.cwd,
117
- renderCwd: input.cwd,
66
+ renderCwd,
67
+ contractId: input.contractId,
68
+ patterns: input.appendScope,
69
+ actor: input.actor,
70
+ nowMs: input.nowMs,
71
+ });
72
+ // Seal capture needs delivery HEAD; ledger append may use hub or delivery (shared refs).
73
+ const sealed = await sealCurrentArc({
74
+ cwd: renderCwd,
75
+ renderCwd,
118
76
  contractId: input.contractId,
119
77
  sealedBy: "arc",
120
78
  nowMs: input.nowMs,
121
- waivePaths: input.waivePaths,
122
79
  });
123
80
  const at = new Date(input.nowMs).toISOString();
124
81
  let arcNumber = 0;
@@ -140,10 +97,10 @@ export async function openArc(input) {
140
97
  if (!result.ok || arcNumber === 0) {
141
98
  throw new FlowError("INTERNAL_STATE", `contract ${input.contractId} active ledger disappeared during arc`);
142
99
  }
143
- await renderUpdatedContract(input.cwd, input.contractId);
100
+ await refreshContractView({ ledgerCwd: input.cwd, renderCwd, contractId: input.contractId });
144
101
  return { contractId: input.contractId, arc: arcNumber, ledgerHead: result.head, sealed };
145
102
  }
146
- export function buildArcInput(content, cwd, waivePaths = [], contractId, contractAddressSource) {
103
+ export function buildArcInput(content, cwd, appendScope = [], contractId, contractAddressSource) {
147
104
  const parts = parseCommandMarkdown(content);
148
105
  return {
149
106
  cwd,
@@ -152,7 +109,7 @@ export function buildArcInput(content, cwd, waivePaths = [], contractId, contrac
152
109
  title: requireMarkdownTitle(parts),
153
110
  objective: requireMarkdownTextSection(parts, "Objective"),
154
111
  brief: requireMarkdownTextSection(parts, "Brief"),
155
- waivePaths,
112
+ appendScope,
156
113
  };
157
114
  }
158
115
  async function readBranchLabels(cwd) {
@@ -162,11 +119,13 @@ async function readBranchLabels(cwd) {
162
119
  }
163
120
  export async function arcKeiyaku(input) {
164
121
  await requireGitRepository(input.cwd, "arc");
165
- const address = await resolveContractAddress(input.cwd, input.contractId, input.contractAddressSource);
122
+ const address = input.address ?? await resolveContractAddress(input.cwd, input.contractId, input.contractAddressSource);
166
123
  return await withResolvedAddress(address, async () => {
167
- await assertCleanWorkingTree(input.cwd, []);
124
+ const contractId = address.binding.commissionId;
125
+ const renderCwd = await resolveContractDeliveryCwd(input.cwd, contractId);
126
+ await assertCleanTrackedWorkingTree(renderCwd);
168
127
  try {
169
- await fs.access(path.join(input.cwd, KEIYAKU_FILE));
128
+ await fs.access(path.join(renderCwd, KEIYAKU_FILE));
170
129
  }
171
130
  catch {
172
131
  throw new FlowError("MISSING_PROTOCOL_FILES", `missing protocol file for current keiyaku (${KEIYAKU_FILE})`);
@@ -174,22 +133,22 @@ export async function arcKeiyaku(input) {
174
133
  const title = normalizeInlineTitle(requireText("title", input.title));
175
134
  const objective = requireText("objective", input.objective);
176
135
  const brief = requireText("brief", input.brief);
177
- const contractId = address.binding.commissionId;
136
+ const nowMs = Date.now();
178
137
  const opened = await openArc({
179
138
  cwd: input.cwd,
139
+ renderCwd,
180
140
  contractId,
181
141
  actor: ACTOR_IDENTITY,
182
- nowMs: Date.now(),
142
+ nowMs,
183
143
  title,
184
144
  objective,
185
145
  brief,
186
- waivePaths: input.waivePaths,
146
+ appendScope: input.appendScope,
187
147
  });
188
- const { currentBranch, baseBranch } = await readBranchLabels(input.cwd);
148
+ const { currentBranch, baseBranch } = await readBranchLabels(renderCwd);
189
149
  const summary = opened.sealed
190
150
  ? `a${opened.sealed.arc} sealed; a${opened.arc} open: ${title}.`
191
151
  : `a${opened.arc} open: ${title}.`;
192
- const diff = opened.sealed?.incrementalDiff ?? "working tree untouched";
193
152
  let responsePath;
194
153
  let artifactId;
195
154
  try {
@@ -202,7 +161,7 @@ export async function arcKeiyaku(input) {
202
161
  brief,
203
162
  ledgerCommit: opened.ledgerHead,
204
163
  summary,
205
- diff,
164
+ emptyDiffLabel: "working tree untouched",
206
165
  ...(opened.sealed ? { sealed: opened.sealed } : {}),
207
166
  });
208
167
  responsePath = persisted.responsePath;
@@ -217,7 +176,8 @@ export async function arcKeiyaku(input) {
217
176
  currentBranch,
218
177
  baseBranch,
219
178
  commit: opened.ledgerHead,
220
- diff,
179
+ // CLI/render synthesizes public face bytes from sealed typed facts.
180
+ diff: "",
221
181
  summary,
222
182
  title,
223
183
  objective,