@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,8 +1,4 @@
1
- import { spawn } from "node:child_process";
2
- import * as fs from "node:fs/promises";
3
- import * as os from "node:os";
4
- import * as path from "node:path";
5
- import { createGit, wrapGitError } from "../git/core.js";
1
+ import { FlowError } from "../flow-error.js";
6
2
  export class ScopePatternError extends Error {
7
3
  code = "INVALID_SCOPE_PATTERN";
8
4
  constructor(message) {
@@ -36,14 +32,140 @@ function stripUnescapedTrailingSpaces(value) {
36
32
  function canonicalizeScopePatternInput(pattern) {
37
33
  return stripUnescapedTrailingSpaces(pattern.replace(/^\s+/, ""));
38
34
  }
39
- /** True when a raw Scope Add / list line has no pattern after gitignore blank rules. */
35
+ /** True when a raw scope line has no pattern after gitignore blank rules. */
40
36
  export function isBlankScopePatternLine(line) {
41
37
  return canonicalizeScopePatternInput(line).length === 0;
42
38
  }
39
+ /** Parse Keiyaku's source-line Scope opener, not a normalized Markdown node. */
40
+ export function parseScopeFenceOpening(line) {
41
+ const match = line.match(/^(`{3,})$/);
42
+ return match ? { length: match[1].length } : null;
43
+ }
44
+ /** Keiyaku closer: column-zero backticks, at least opener length, then whitespace. */
45
+ export function isScopeFenceClosing(line, fence) {
46
+ const match = line.match(/^(`+)[ \t]*$/);
47
+ return Boolean(match && match[1].length >= fence.length);
48
+ }
49
+ function fencedScopeError(heading, detail) {
50
+ return new FlowError("INVALID_KEIYAKU_DRAFT", `${heading} must contain exactly one fenced gitignore-subset block; ${detail}. ` +
51
+ `Paste-ready canonical example:\n\n${heading}\n\`\`\`\nfoo\nbar\n\`\`\``);
52
+ }
53
+ /** Validate and normalize the one fenced block that constitutes a Scope body. */
54
+ export function validateScopeFragmentLines(lines, options) {
55
+ const first = lines.findIndex((line) => line.trim().length > 0);
56
+ if (first === -1)
57
+ throw fencedScopeError(options.heading, "found no fenced block");
58
+ const fence = parseScopeFenceOpening(lines[first]);
59
+ if (!fence)
60
+ throw fencedScopeError(options.heading, `offending line '${lines[first]}'`);
61
+ let close = -1;
62
+ for (let index = first + 1; index < lines.length; index += 1) {
63
+ if (isScopeFenceClosing(lines[index], fence)) {
64
+ close = index;
65
+ break;
66
+ }
67
+ }
68
+ if (close === -1)
69
+ throw fencedScopeError(options.heading, "the fenced block is not closed");
70
+ const outside = lines.slice(close + 1).find((line) => line.trim().length > 0);
71
+ if (outside !== undefined) {
72
+ throw fencedScopeError(options.heading, `offending line '${outside}' appears outside the fenced block`);
73
+ }
74
+ const patterns = [];
75
+ for (const line of lines.slice(first + 1, close)) {
76
+ if (isBlankScopePatternLine(line))
77
+ continue;
78
+ try {
79
+ patterns.push(normalizeScopePattern(line));
80
+ }
81
+ catch (error) {
82
+ if (error instanceof ScopePatternError) {
83
+ throw new FlowError("INVALID_KEIYAKU_DRAFT", error.message);
84
+ }
85
+ throw error;
86
+ }
87
+ }
88
+ if (patterns.length === 0)
89
+ throw new FlowError("INVALID_KEIYAKU_DRAFT", options.emptyMessage);
90
+ return patterns;
91
+ }
92
+ function sourceFenceOpening(line) {
93
+ const match = line.match(/^ {0,3}(`{3,}|~{3,})(.*)$/);
94
+ if (!match)
95
+ return null;
96
+ const marker = match[1];
97
+ if (marker[0] === "`" && match[2].includes("`"))
98
+ return null;
99
+ return { delimiter: marker[0], length: marker.length };
100
+ }
101
+ function sourceFenceClosing(line, fence) {
102
+ const match = line.match(/^ {0,3}(`+|~+)[ \t]*$/);
103
+ return Boolean(match && match[1][0] === fence.delimiter && match[1].length >= fence.length);
104
+ }
105
+ /** Locate structural H1/H2 source ranges while leaving fenced headings inert. */
106
+ export function markdownSourceSections(markdown) {
107
+ const lines = [];
108
+ let start = 0;
109
+ while (start < markdown.length) {
110
+ const newline = markdown.indexOf("\n", start);
111
+ const end = newline === -1 ? markdown.length : newline;
112
+ const next = newline === -1 ? markdown.length : newline + 1;
113
+ const raw = markdown.slice(start, end);
114
+ lines.push({ text: raw.endsWith("\r") ? raw.slice(0, -1) : raw, start, next });
115
+ start = next;
116
+ }
117
+ let frontMatterEnd = -1;
118
+ if (lines[0]?.text.trim() === "---") {
119
+ frontMatterEnd = lines.findIndex((line, index) => index > 0 && line.text.trim() === "---");
120
+ }
121
+ const headings = [];
122
+ let fence = null;
123
+ for (let index = 0; index < lines.length; index += 1) {
124
+ const line = lines[index];
125
+ if (index <= frontMatterEnd)
126
+ continue;
127
+ if (fence) {
128
+ if (sourceFenceClosing(line.text, fence))
129
+ fence = null;
130
+ continue;
131
+ }
132
+ const opening = sourceFenceOpening(line.text);
133
+ if (opening) {
134
+ fence = opening;
135
+ continue;
136
+ }
137
+ // Column-0 only: indented ATX-looking lines inside list items remain content.
138
+ const heading = line.text.match(/^(#{1,2})(?!#)[ \t]+(.+)$/);
139
+ if (!heading)
140
+ continue;
141
+ headings.push({
142
+ level: heading[1].length,
143
+ title: heading[2],
144
+ start: line.start,
145
+ contentStart: line.next,
146
+ });
147
+ }
148
+ return headings.map((heading, index) => {
149
+ const next = heading.level === 2
150
+ ? headings.slice(index + 1).find((candidate) => candidate.level === 2)
151
+ : headings[index + 1];
152
+ return { ...heading, end: next?.start ?? markdown.length };
153
+ });
154
+ }
155
+ /** Render canonical Scope bytes with a fence that content cannot close. */
156
+ export function renderScopeFragment(patterns) {
157
+ let longestRun = 0;
158
+ for (const pattern of patterns) {
159
+ for (const run of pattern.match(/`+/g) ?? [])
160
+ longestRun = Math.max(longestRun, run.length);
161
+ }
162
+ const fence = "`".repeat(Math.max(3, longestRun + 1));
163
+ return `${fence}\n${patterns.join("\n")}\n${fence}`;
164
+ }
43
165
  /**
44
- * Canonicalize a scope gitignore pattern for exclude matching and persistence.
166
+ * Canonicalize a scope Gitignore-like pattern for matching and persistence.
45
167
  * Strips only a cosmetic leading `./` (including after `!`); preserves meaningful
46
- * leading `/` anchoring, gitignore backslash escapes, and escaped trailing spaces.
168
+ * leading `/` anchoring, supported backslash escapes, and escaped trailing spaces.
47
169
  */
48
170
  export function normalizeScopePattern(pattern) {
49
171
  if (pattern.includes("\0") || pattern.includes("\n") || pattern.includes("\r")) {
@@ -62,7 +184,7 @@ export function normalizeScopePattern(pattern) {
62
184
  return negative ? `!${body}` : body;
63
185
  }
64
186
  /**
65
- * Normalize a path to Git diff form for exact waiver comparison:
187
+ * Normalize a path to Git diff form for matcher comparison:
66
188
  * either slash convention, collapse separators, and strip cosmetic `./` or `/`.
67
189
  * Leading and trailing spaces are significant path bytes and must remain unchanged.
68
190
  */
@@ -78,75 +200,157 @@ export function normalizeScopePath(filePath) {
78
200
  throw new ScopePatternError("scope path cannot contain NUL");
79
201
  return normalized;
80
202
  }
81
- function runCheckIgnore(gitDir, workTree, cwd, paths) {
82
- return new Promise((resolve, reject) => {
83
- const child = spawn("git", [
84
- `--git-dir=${gitDir}`,
85
- `--work-tree=${workTree}`,
86
- "check-ignore",
87
- "--no-index",
88
- "-z",
89
- "--stdin",
90
- ], {
91
- cwd,
92
- env: {
93
- ...process.env,
94
- GIT_TERMINAL_PROMPT: "0",
95
- GCM_INTERACTIVE: "Never",
96
- GIT_CONFIG_GLOBAL: "/dev/null",
97
- GIT_CONFIG_NOSYSTEM: "1",
98
- LC_ALL: "C",
99
- },
100
- stdio: ["pipe", "pipe", "pipe"],
101
- });
102
- const stdout = [];
103
- const stderr = [];
104
- child.stdout.on("data", (chunk) => stdout.push(chunk));
105
- child.stderr.on("data", (chunk) => stderr.push(chunk));
106
- child.stdin.on("error", reject);
107
- child.on("error", reject);
108
- child.on("close", (code) => {
109
- if (code !== 0 && code !== 1) {
110
- reject(wrapGitError("check-ignore --no-index -z --stdin", {
111
- message: `git check-ignore exited with status ${code ?? "unknown"}`,
112
- stderr: Buffer.concat(stderr).toString("utf8"),
113
- stdout: Buffer.concat(stdout).toString("utf8"),
114
- }, cwd));
115
- return;
203
+ function splitPatternComponents(pattern) {
204
+ const components = [];
205
+ let component = "";
206
+ let escaped = false;
207
+ for (const character of pattern) {
208
+ if (escaped) {
209
+ component += `\\${character}`;
210
+ escaped = false;
211
+ }
212
+ else if (character === "\\") {
213
+ escaped = true;
214
+ }
215
+ else if (character === "/") {
216
+ components.push(component);
217
+ component = "";
218
+ }
219
+ else {
220
+ component += character;
221
+ }
222
+ }
223
+ if (escaped)
224
+ component += "\\\\";
225
+ components.push(component);
226
+ return components;
227
+ }
228
+ function parseScopePattern(pattern) {
229
+ const normalized = normalizeScopePattern(pattern);
230
+ const escapedLeading = normalized.startsWith("\\!") || normalized.startsWith("\\#");
231
+ const negative = normalized.startsWith("!");
232
+ const body = negative ? normalized.slice(1) : normalized;
233
+ const comment = !escapedLeading && body.startsWith("#");
234
+ const anchored = body.startsWith("/");
235
+ const unanchored = anchored ? body.slice(1) : body;
236
+ const directory = unanchored.endsWith("/");
237
+ const source = directory ? unanchored.slice(0, -1) : unanchored;
238
+ const segments = splitPatternComponents(source);
239
+ return { negative, comment, directory, segments, componentOnly: !anchored && !source.includes("/") };
240
+ }
241
+ function componentMatches(pattern, value) {
242
+ let expression = "^";
243
+ for (let index = 0; index < pattern.length; index += 1) {
244
+ const character = pattern[index];
245
+ if (character === "\\") {
246
+ index += 1;
247
+ expression += escapeRegex(pattern[index] ?? "\\");
248
+ }
249
+ else if (character === "*") {
250
+ if (pattern[index + 1] === "*") {
251
+ expression += ".*";
252
+ index += 1;
253
+ }
254
+ else
255
+ expression += "[^/]*";
256
+ }
257
+ else if (character === "?")
258
+ expression += "[^/]";
259
+ else if (character === "[") {
260
+ const close = pattern.indexOf("]", index + 1);
261
+ if (close === -1)
262
+ expression += "\\[";
263
+ else {
264
+ const rawClass = pattern.slice(index + 1, close);
265
+ const classBody = rawClass.startsWith("!") ? `^${rawClass.slice(1)}` : rawClass;
266
+ expression += `[${classBody.replace(/\\/g, "\\\\")}]`;
267
+ index = close;
268
+ }
269
+ }
270
+ else
271
+ expression += escapeRegex(character);
272
+ }
273
+ return new RegExp(`${expression}$`).test(value);
274
+ }
275
+ function escapeRegex(value) {
276
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
277
+ }
278
+ function patternMatchesPath(parsed, filePath) {
279
+ if (parsed.comment)
280
+ return false;
281
+ const pathSegments = filePath.split("/");
282
+ if (parsed.componentOnly) {
283
+ const lastMatchIndex = parsed.directory ? pathSegments.length - 1 : pathSegments.length;
284
+ return pathSegments.slice(0, lastMatchIndex).some((segment) => componentMatches(parsed.segments[0], segment));
285
+ }
286
+ const memo = new Map();
287
+ const matchesFrom = (patternIndex, pathIndex) => {
288
+ const key = `${patternIndex}:${pathIndex}`;
289
+ const cached = memo.get(key);
290
+ if (cached !== undefined)
291
+ return cached;
292
+ let matched;
293
+ if (patternIndex === parsed.segments.length) {
294
+ matched = parsed.directory ? pathIndex < pathSegments.length : pathIndex === pathSegments.length;
295
+ memo.set(key, matched);
296
+ return matched;
297
+ }
298
+ const segment = parsed.segments[patternIndex];
299
+ if (segment === "**") {
300
+ matched = false;
301
+ for (let nextPathIndex = pathIndex; nextPathIndex <= pathSegments.length; nextPathIndex += 1) {
302
+ if (matchesFrom(patternIndex + 1, nextPathIndex)) {
303
+ matched = true;
304
+ break;
305
+ }
116
306
  }
117
- resolve(new Set(Buffer.concat(stdout)
118
- .toString("utf8")
119
- .split("\0")
120
- .filter(Boolean)));
307
+ }
308
+ else {
309
+ matched = pathIndex < pathSegments.length
310
+ && componentMatches(segment, pathSegments[pathIndex])
311
+ && matchesFrom(patternIndex + 1, pathIndex + 1);
312
+ }
313
+ memo.set(key, matched);
314
+ return matched;
315
+ };
316
+ return matchesFrom(0, 0);
317
+ }
318
+ /**
319
+ * Evaluate the settled ordered Gitignore-like scope subset without invoking Git.
320
+ */
321
+ export async function scopePathEvidence(_cwd, patterns, filePaths) {
322
+ const normalizedPatterns = patterns.map(normalizeScopePattern);
323
+ const normalizedPaths = filePaths.map(normalizeScopePath);
324
+ const parsedPatterns = normalizedPatterns.map(parseScopePattern);
325
+ return normalizedPaths.map((normalizedPath) => {
326
+ const pathDecisions = parsedPatterns.flatMap((parsed, index) => {
327
+ if (!patternMatchesPath(parsed, normalizedPath))
328
+ return [];
329
+ const effect = parsed.negative ? "exclude" : "include";
330
+ return [{ index, pattern: normalizedPatterns[index], effect, matchedAfter: effect === "include" }];
121
331
  });
122
- child.stdin.end(`${paths.join("\0")}\0`);
332
+ const decisivePattern = pathDecisions.at(-1);
333
+ const hasPositiveMatch = pathDecisions.some((decision) => decision.effect === "include");
334
+ const matched = decisivePattern?.matchedAfter ?? false;
335
+ return {
336
+ path: normalizedPath,
337
+ patterns: pathDecisions,
338
+ matched,
339
+ outcome: matched ? "matched" : hasPositiveMatch ? "excluded" : "no-positive-match",
340
+ ...(decisivePattern ? { decisivePattern } : {}),
341
+ };
123
342
  });
124
343
  }
125
344
  export async function pathsMatchingScope(cwd, patterns, filePaths) {
126
- const normalizedPatterns = patterns.map(normalizeScopePattern);
127
- const normalizedPaths = filePaths.map(normalizeScopePath);
128
- if (normalizedPatterns.length === 0 || normalizedPaths.length === 0)
129
- return new Set();
130
- const temporaryRoot = await fs.mkdtemp(path.join(os.tmpdir(), "keiyaku-scope-"));
131
- const gitDir = path.join(temporaryRoot, "scope.git");
132
- const workTree = path.join(temporaryRoot, "worktree");
133
- try {
134
- await Promise.all([fs.mkdir(gitDir), fs.mkdir(workTree)]);
135
- await createGit(gitDir).init(true);
136
- await fs.writeFile(path.join(gitDir, "info", "exclude"), `${normalizedPatterns.join("\n")}\n`, "utf8");
137
- return await runCheckIgnore(gitDir, workTree, cwd, normalizedPaths);
138
- }
139
- finally {
140
- await fs.rm(temporaryRoot, { recursive: true, force: true });
141
- }
345
+ const evidence = await scopePathEvidence(cwd, patterns, filePaths);
346
+ return new Set(evidence.filter((item) => item.matched).map((item) => item.path));
142
347
  }
143
348
  export function isNegativeScopePattern(pattern) {
144
349
  return normalizeScopePattern(pattern).startsWith("!");
145
350
  }
146
351
  /**
147
- * Parse only the subset whose path language can be proved statically: literal
148
- * segments, `*` segments, and `**` segments. Anything using richer gitignore
149
- * syntax is left to Git and produces no advisory warning.
352
+ * Parse only the positive subset whose path language can be proved statically:
353
+ * literal segments, `*` segments, and `**` segments.
150
354
  */
151
355
  function staticScopeSegments(pattern) {
152
356
  const positive = normalizeScopePattern(pattern);
@@ -1,12 +1,12 @@
1
- import * as fs from "node:fs/promises";
2
- import * as path from "node:path";
3
1
  import { FlowError } from "../flow-error.js";
4
- import { createGit, wrapGitError } from "../git/core.js";
2
+ import { createGit, parseRevListOutput, wrapGitError } from "../git/core.js";
5
3
  import { KEIYAKU_FILE } from "../keiyaku.js";
4
+ import { formatLedgerEntryCommitMessage } from "./entry.js";
6
5
  import { activeLedgerRef, appendWithRetry, readLedger } from "./ledger.js";
7
- import { renderContractView } from "./contract-view.js";
8
- import { normalizeScopePath, pathsMatchingScope } from "./scope.js";
6
+ import { refreshContractView } from "./contract-view.js";
7
+ import { normalizeScopePattern, scopePathEvidence, } from "./scope.js";
9
8
  import { deriveContractState, isTerminalState } from "./status/lifecycle.js";
9
+ import { casUpdateRefLog, createRefLogCommit } from "./ref-log.js";
10
10
  function findBind(entries) {
11
11
  const bind = entries.find((entry) => entry.kind === "bind");
12
12
  if (!bind)
@@ -64,10 +64,7 @@ async function resolveCommit(cwd, revision) {
64
64
  async function revList(cwd, from, to) {
65
65
  const git = createGit(cwd);
66
66
  try {
67
- return (await git.raw(["rev-list", "--reverse", `${from}..${to}`]))
68
- .split(/\r?\n/)
69
- .map((line) => line.trim())
70
- .filter(Boolean);
67
+ return parseRevListOutput(await git.raw(["rev-list", "--reverse", `${from}..${to}`]));
71
68
  }
72
69
  catch (error) {
73
70
  throw wrapGitError(`rev-list ${from}..${to}`, error, cwd);
@@ -104,8 +101,58 @@ async function diffstat(cwd, from, to) {
104
101
  }
105
102
  async function scopeViolations(cwd, paths, scope) {
106
103
  const auditedPaths = paths.filter((changedPath) => changedPath !== KEIYAKU_FILE);
107
- const matched = await pathsMatchingScope(cwd, scope, auditedPaths);
108
- return auditedPaths.filter((changedPath) => !matched.has(changedPath));
104
+ return (await scopePathEvidence(cwd, scope, auditedPaths)).filter((evidence) => !evidence.matched);
105
+ }
106
+ async function auditScope(cwd, entries, paths) {
107
+ const scope = effectiveScope(entries);
108
+ const scopeViolationEvidence = await scopeViolations(cwd, paths, scope);
109
+ if (scopeViolationEvidence.length > 0) {
110
+ throw new ScopeAuditError(findBind(entries).contract, scope, scopeViolationEvidence);
111
+ }
112
+ const violations = scopeViolationEvidence.map((violation) => violation.path);
113
+ return {
114
+ scopeAudit: { violations },
115
+ scopeViolationEvidence,
116
+ };
117
+ }
118
+ const APPEND_SCOPE_AMENDMENT = "Scope extended by lifecycle command.";
119
+ export async function appendScopeTerms(input) {
120
+ if (!input.patterns || input.patterns.length === 0)
121
+ return null;
122
+ const patterns = input.patterns.map(normalizeScopePattern);
123
+ const at = new Date(input.nowMs).toISOString();
124
+ const result = await appendWithRetry(input.cwd, activeLedgerRef(input.contractId), (_head, entries) => {
125
+ assertOperable(input.contractId, entries);
126
+ return {
127
+ v: 1,
128
+ kind: "amend",
129
+ contract: input.contractId,
130
+ at,
131
+ actor: input.actor,
132
+ data: { amendment: APPEND_SCOPE_AMENDMENT, scopeDelta: { add: patterns } },
133
+ };
134
+ });
135
+ if (!result.ok) {
136
+ throw new FlowError("INTERNAL_STATE", `contract ${input.contractId} active ledger disappeared while appending scope`);
137
+ }
138
+ await refreshContractView({ ledgerCwd: input.cwd, renderCwd: input.renderCwd, contractId: input.contractId });
139
+ return result.head;
140
+ }
141
+ export class ScopeAuditError extends FlowError {
142
+ scopeViolationEvidence;
143
+ constructor(_contractId, scope, evidence) {
144
+ const count = evidence.length;
145
+ const fileLabel = count === 1 ? "file" : "files";
146
+ super("SCOPE_VIOLATION", `scope violation — ${count} ${fileLabel} outside declared scope`, {
147
+ facts: {
148
+ kind: "scope_violation",
149
+ scope: [...scope],
150
+ violations: evidence,
151
+ },
152
+ });
153
+ this.name = "ScopeAuditError";
154
+ this.scopeViolationEvidence = evidence;
155
+ }
109
156
  }
110
157
  function assertOperable(contractId, entries) {
111
158
  const state = deriveContractState(entries);
@@ -127,14 +174,13 @@ export function currentSealArc(entries) {
127
174
  }
128
175
  /** Stable read-only coordinate naming the receipt source a petition would seal. */
129
176
  export function petitionSealSource(entries) {
130
- const arc = currentSealArc(entries);
131
- const fence = getFence(entries);
132
- return arc === null
133
- ? `no open arc · fence ${fence}`
134
- : `a${arc} · fence ${fence}▸HEAD`;
177
+ return {
178
+ arc: currentSealArc(entries),
179
+ fence: getFence(entries),
180
+ };
135
181
  }
136
182
  /** Shared read-only owner for the seal capture and its compact changed-path evidence. */
137
- export async function previewSeal(cwd, entries, head = "HEAD", waivePaths = []) {
183
+ export async function previewSeal(cwd, entries, head = "HEAD") {
138
184
  const arc = currentSealArc(entries);
139
185
  if (arc === null)
140
186
  return { capture: null, paths: [] };
@@ -145,13 +191,7 @@ export async function previewSeal(cwd, entries, head = "HEAD", waivePaths = [])
145
191
  changedPaths(cwd, oldFence, newFence),
146
192
  diffstat(cwd, oldFence, newFence),
147
193
  ]);
148
- const scope = effectiveScope(entries);
149
- const violations = await scopeViolations(cwd, paths, scope);
150
- const waivedPaths = new Set(waivePaths.map(normalizeScopePath));
151
- const unwaived = violations.filter((violation) => !waivedPaths.has(violation));
152
- if (unwaived.length > 0) {
153
- throw new FlowError("INTERNAL_STATE", `scope audit failed for contract ${findBind(entries).contract}: paths ${unwaived.join(", ")} outside ${scope.join(", ")}`);
154
- }
194
+ const scopeAudit = await auditScope(cwd, entries, paths);
155
195
  return {
156
196
  capture: {
157
197
  arc,
@@ -159,20 +199,38 @@ export async function previewSeal(cwd, entries, head = "HEAD", waivePaths = [])
159
199
  newFence,
160
200
  receipts,
161
201
  diffstat: stat,
162
- scopeAudit: { violations, waived: violations.length > 0 },
202
+ ...scopeAudit,
163
203
  },
164
204
  paths,
165
205
  };
166
206
  }
167
- export async function captureSeal(cwd, entries, head = "HEAD", waivePaths = []) {
168
- return (await previewSeal(cwd, entries, head, waivePaths)).capture;
207
+ export async function captureSeal(cwd, entries, head = "HEAD") {
208
+ return (await previewSeal(cwd, entries, head)).capture;
169
209
  }
170
- async function renderUpdatedContract(ledgerCwd, renderCwd, contractId) {
171
- const ledger = await readLedger(ledgerCwd, contractId);
172
- if (!ledger) {
173
- throw new FlowError("INTERNAL_STATE", `contract ${contractId} active ledger disappeared before render`);
174
- }
175
- await fs.writeFile(path.join(renderCwd, KEIYAKU_FILE), renderContractView({ id: contractId, entries: ledger.entries }), "utf8");
210
+ /** Preserve original receipt hashes while auditing the rebased delivery content. */
211
+ export async function captureRenewSeal(input) {
212
+ const arc = currentSealArc(input.entries);
213
+ if (arc === null)
214
+ return null;
215
+ const oldFence = getFence(input.entries);
216
+ const [receiptHead, contentBase, contentHead] = await Promise.all([
217
+ resolveCommit(input.cwd, input.receiptHead),
218
+ resolveCommit(input.cwd, input.contentBase),
219
+ resolveCommit(input.cwd, input.contentHead),
220
+ ]);
221
+ const [receipts, paths, stat] = await Promise.all([
222
+ revList(input.cwd, oldFence, receiptHead),
223
+ changedPaths(input.cwd, contentBase, contentHead),
224
+ diffstat(input.cwd, contentBase, contentHead),
225
+ ]);
226
+ return {
227
+ arc,
228
+ oldFence,
229
+ newFence: receiptHead,
230
+ receipts,
231
+ diffstat: stat,
232
+ ...await auditScope(input.cwd, input.entries, paths),
233
+ };
176
234
  }
177
235
  export async function sealCurrentArc(input) {
178
236
  const ledger = await readLedger(input.cwd, input.contractId);
@@ -180,7 +238,7 @@ export async function sealCurrentArc(input) {
180
238
  throw new FlowError("INTERNAL_STATE", `contract ${input.contractId} not found or not active`);
181
239
  }
182
240
  assertOperable(input.contractId, ledger.entries);
183
- const capture = input.capture ?? await captureSeal(input.cwd, ledger.entries, "HEAD", input.waivePaths);
241
+ const capture = input.capture ?? await captureSeal(input.cwd, ledger.entries, "HEAD");
184
242
  if (!capture)
185
243
  return null;
186
244
  const at = new Date(input.nowMs).toISOString();
@@ -196,25 +254,92 @@ export async function sealCurrentArc(input) {
196
254
  if (currentArc !== capture.arc || getFence(entries) !== capture.oldFence) {
197
255
  throw new FlowError("INTERNAL_STATE", `contract ${input.contractId} changed while sealing arc a${capture.arc}`);
198
256
  }
257
+ const { scopeViolationEvidence: _scopeViolationEvidence, ...durableCapture } = capture;
199
258
  return {
200
- v: 1,
259
+ v: 2,
201
260
  kind: "seal",
202
261
  contract: input.contractId,
203
262
  at,
204
263
  actor: "engine",
205
- data: { ...capture, sealedBy: input.sealedBy },
264
+ data: { ...durableCapture, sealedBy: input.sealedBy },
206
265
  };
207
266
  });
208
267
  if (!result.ok) {
209
268
  throw new FlowError("INTERNAL_STATE", `failed to seal arc for ${input.contractId}: ${result.reason}`);
210
269
  }
211
- await renderUpdatedContract(input.cwd, input.renderCwd, input.contractId);
270
+ await refreshContractView({
271
+ ledgerCwd: input.cwd,
272
+ renderCwd: input.renderCwd,
273
+ contractId: input.contractId,
274
+ });
212
275
  return {
213
276
  ...capture,
214
277
  sealedBy: input.sealedBy,
215
278
  ledgerHead: result.head,
216
- incrementalDiff: capture.receipts.length === 0
217
- ? "nothing sealed"
218
- : `${capture.receipts.length} receipt${capture.receipts.length === 1 ? "" : "s"} · +${capture.diffstat.insertions} −${capture.diffstat.deletions}`,
219
279
  };
220
280
  }
281
+ function splitLedgerMessage(entry) {
282
+ const message = formatLedgerEntryCommitMessage(entry);
283
+ const separator = message.indexOf("\n\n");
284
+ return { subject: message.slice(0, separator), body: message.slice(separator + 2).trimEnd() };
285
+ }
286
+ export async function appendRenewSettlement(input) {
287
+ const ledger = await readLedger(input.cwd, input.contractId);
288
+ if (!ledger || ledger.head !== input.expectedLedgerHead) {
289
+ throw new FlowError("CONCURRENT_MODIFICATION", `contract ${input.contractId} changed while renewing`);
290
+ }
291
+ assertOperable(input.contractId, ledger.entries);
292
+ if (input.capture && (currentSealArc(ledger.entries) !== input.capture.arc || getFence(ledger.entries) !== input.capture.oldFence)) {
293
+ throw new FlowError("CONCURRENT_MODIFICATION", `contract ${input.contractId} changed while renewing`);
294
+ }
295
+ const at = new Date(input.nowMs).toISOString();
296
+ let parentHead = ledger.head;
297
+ let sealHead;
298
+ if (input.capture) {
299
+ const { scopeViolationEvidence: _evidence, ...durableCapture } = input.capture;
300
+ const sealEntry = {
301
+ v: 2,
302
+ kind: "seal",
303
+ contract: input.contractId,
304
+ at,
305
+ actor: "engine",
306
+ data: { ...durableCapture, newFence: input.newHead, sealedBy: "renew" },
307
+ };
308
+ const message = splitLedgerMessage(sealEntry);
309
+ sealHead = await createRefLogCommit(input.cwd, {
310
+ ...message,
311
+ parentHead,
312
+ errorLabel: `ledger seal ${input.contractId}`,
313
+ });
314
+ parentHead = sealHead;
315
+ }
316
+ const renewEntry = {
317
+ v: 1,
318
+ kind: "renew",
319
+ contract: input.contractId,
320
+ at,
321
+ actor: input.actor,
322
+ data: {
323
+ oldBase: input.oldBase,
324
+ newBase: input.newBase,
325
+ oldHead: input.oldHead,
326
+ newHead: input.newHead,
327
+ },
328
+ };
329
+ const message = splitLedgerMessage(renewEntry);
330
+ const renewHead = await createRefLogCommit(input.cwd, {
331
+ ...message,
332
+ parentHead,
333
+ errorLabel: `ledger renew ${input.contractId}`,
334
+ });
335
+ if (!await casUpdateRefLog(input.cwd, activeLedgerRef(input.contractId), renewHead, ledger.head)) {
336
+ throw new FlowError("CONCURRENT_MODIFICATION", `contract ${input.contractId} changed while renewing`);
337
+ }
338
+ const sealed = input.capture ? {
339
+ ...input.capture,
340
+ newFence: input.newHead,
341
+ sealedBy: "renew",
342
+ ledgerHead: sealHead,
343
+ } : null;
344
+ return { ledgerHead: renewHead, sealed };
345
+ }