@astrosheep/keiyaku 4.5.19 → 4.5.21

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 (197) hide show
  1. package/README.md +4 -4
  2. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +14 -7
  3. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +53 -20
  4. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/references/automation.md +237 -0
  5. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +6 -7
  6. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-task/SKILL.md +2 -4
  7. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +3 -3
  8. package/build/src/akuma/akuma-handle.d.ts +5 -1
  9. package/build/src/akuma/akuma-handle.js +4 -1
  10. package/build/src/akuma/akuma-instance.d.ts +7 -2
  11. package/build/src/akuma/akuma-instance.js +14 -7
  12. package/build/src/akuma/akuma-observe.d.ts +11 -0
  13. package/build/src/akuma/akuma-observe.js +23 -0
  14. package/build/src/akuma/akuma-product.d.ts +2 -0
  15. package/build/src/akuma/akuma-product.js +6 -0
  16. package/build/src/akuma/akuma.d.ts +20 -1
  17. package/build/src/akuma/akuma.js +2 -0
  18. package/build/src/akuma/allowed.d.ts +20 -0
  19. package/build/src/akuma/allowed.js +11 -0
  20. package/build/src/akuma/archetype.js +3 -0
  21. package/build/src/akuma/body.d.ts +25 -5
  22. package/build/src/akuma/body.js +70 -31
  23. package/build/src/akuma/call-request.d.ts +5 -0
  24. package/build/src/akuma/call-request.js +14 -4
  25. package/build/src/akuma/fleet-execution.d.ts +28 -0
  26. package/build/src/akuma/fleet-execution.js +36 -4
  27. package/build/src/akuma/fleet-observation.d.ts +54 -0
  28. package/build/src/akuma/fleet-request.d.ts +10 -0
  29. package/build/src/akuma/fleet-request.js +13 -3
  30. package/build/src/akuma/heart/facts.d.ts +2 -0
  31. package/build/src/akuma/heart/index.d.ts +1 -0
  32. package/build/src/akuma/heart/index.js +4 -1
  33. package/build/src/akuma/heart/rows.d.ts +2 -0
  34. package/build/src/akuma/heart/rows.js +7 -5
  35. package/build/src/akuma/heart/schema.d.ts +1 -1
  36. package/build/src/akuma/heart/schema.js +3 -1
  37. package/build/src/akuma/heart/tells.js +6 -5
  38. package/build/src/akuma/heart/timeline.js +1 -1
  39. package/build/src/akuma/provider-recipe.d.ts +1 -0
  40. package/build/src/akuma/provider-recipe.js +5 -0
  41. package/build/src/akuma/provider.d.ts +1 -1
  42. package/build/src/akuma/provider.js +1 -1
  43. package/build/src/akuma/providers/acp/core.js +3 -6
  44. package/build/src/akuma/providers/acp/index.js +3 -0
  45. package/build/src/akuma/providers/claude/index.js +10 -10
  46. package/build/src/akuma/providers/codex-app-server/index.js +12 -11
  47. package/build/src/akuma/providers/execution-environment.d.ts +6 -0
  48. package/build/src/akuma/providers/execution-environment.js +24 -0
  49. package/build/src/akuma/providers/grok-build/index.js +3 -0
  50. package/build/src/akuma/providers/opencode-sdk/index.js +32 -23
  51. package/build/src/akuma/providers/opencode-sdk/session.d.ts +8 -1
  52. package/build/src/akuma/providers/opencode-sdk/session.js +6 -5
  53. package/build/src/akuma/providers/pi/events.js +7 -2
  54. package/build/src/akuma/providers/pi/index.js +5 -2
  55. package/build/src/akuma/request-observation.d.ts +45 -0
  56. package/build/src/akuma/request-observation.js +162 -0
  57. package/build/src/akuma/request-rendezvous.d.ts +6 -3
  58. package/build/src/akuma/request-rendezvous.js +80 -14
  59. package/build/src/akuma/request-serve.js +27 -4
  60. package/build/src/akuma/request-wire.d.ts +5 -0
  61. package/build/src/akuma/request-wire.js +2 -0
  62. package/build/src/akuma/turn-drive.d.ts +1 -0
  63. package/build/src/akuma/turn-drive.js +2 -0
  64. package/build/src/akuma-body.js +5 -0
  65. package/build/src/body/amend.js +6 -4
  66. package/build/src/body/decode.d.ts +3 -1
  67. package/build/src/body/decode.js +53 -17
  68. package/build/src/body/region.d.ts +9 -1
  69. package/build/src/body/region.js +87 -12
  70. package/build/src/body/render.js +1 -1
  71. package/build/src/body/verification.d.ts +3 -1
  72. package/build/src/body/verification.js +4 -1
  73. package/build/src/cli/accepted.js +19 -2
  74. package/build/src/cli/commands/akuma-invoke.d.ts +3 -1
  75. package/build/src/cli/commands/akuma-invoke.js +134 -14
  76. package/build/src/cli/commands/akuma.js +24 -12
  77. package/build/src/cli/commands/contract-help.d.ts +15 -15
  78. package/build/src/cli/commands/contract-help.js +45 -19
  79. package/build/src/cli/commands/contract-invoke.d.ts +3 -0
  80. package/build/src/cli/commands/contract-invoke.js +25 -11
  81. package/build/src/cli/commands/contract.js +6 -4
  82. package/build/src/cli/commands/install.d.ts +1 -1
  83. package/build/src/cli/commands/install.js +1 -1
  84. package/build/src/cli/commands/status-set.js +15 -24
  85. package/build/src/cli/commands/task.js +18 -18
  86. package/build/src/cli/invoke.d.ts +3 -0
  87. package/build/src/cli/invoke.js +58 -23
  88. package/build/src/cli/main.js +5 -0
  89. package/build/src/cli/parse.d.ts +3 -0
  90. package/build/src/cli/parse.js +26 -4
  91. package/build/src/cli/render/akuma-activity.d.ts +100 -2
  92. package/build/src/cli/render/akuma-activity.js +485 -40
  93. package/build/src/cli/render/akuma.d.ts +10 -0
  94. package/build/src/cli/render/akuma.js +31 -21
  95. package/build/src/cli/render/audit.js +1 -1
  96. package/build/src/cli/render/board.js +1 -1
  97. package/build/src/cli/render/catalog.js +16 -13
  98. package/build/src/cli/render/contract-history.js +39 -10
  99. package/build/src/cli/render/contract-observation.js +10 -6
  100. package/build/src/cli/render/contract.js +109 -106
  101. package/build/src/cli/render/execution-progress.d.ts +26 -0
  102. package/build/src/cli/render/execution-progress.js +178 -0
  103. package/build/src/cli/render/kanshi-akuma.js +27 -39
  104. package/build/src/cli/render/kanshi.js +33 -26
  105. package/build/src/cli/render/nuke.js +1 -1
  106. package/build/src/cli/render/receipt.d.ts +1 -1
  107. package/build/src/cli/render/receipt.js +6 -6
  108. package/build/src/cli/render/refusal.js +10 -7
  109. package/build/src/cli/render/region.js +1 -1
  110. package/build/src/cli/render/settings.js +12 -2
  111. package/build/src/cli/render/status-line.d.ts +30 -0
  112. package/build/src/cli/render/status-line.js +58 -0
  113. package/build/src/cli/render/status-set.js +1 -1
  114. package/build/src/cli/render/task.d.ts +2 -0
  115. package/build/src/cli/render/task.js +11 -7
  116. package/build/src/cli/render/terminal.d.ts +0 -1
  117. package/build/src/cli/render/terminal.js +47 -15
  118. package/build/src/cli/result.d.ts +1 -0
  119. package/build/src/cli/runtime.d.ts +2 -0
  120. package/build/src/cli/runtime.js +36 -4
  121. package/build/src/cli/usage.js +2 -2
  122. package/build/src/cli/version.d.ts +1 -0
  123. package/build/src/cli/version.js +25 -0
  124. package/build/src/git/hooks.d.ts +13 -1
  125. package/build/src/git/hooks.js +2 -1
  126. package/build/src/git/workspace.d.ts +1 -1
  127. package/build/src/git/workspace.js +1 -1
  128. package/build/src/identity/mint.d.ts +13 -0
  129. package/build/src/identity/mint.js +26 -0
  130. package/build/src/identity/normalize.d.ts +4 -0
  131. package/build/src/identity/normalize.js +30 -0
  132. package/build/src/index.d.ts +2 -0
  133. package/build/src/index.js +1 -0
  134. package/build/src/kanshi/read.js +17 -4
  135. package/build/src/kanshi/report.d.ts +1 -0
  136. package/build/src/library/akuma-creation.d.ts +2 -0
  137. package/build/src/library/akuma-creation.js +34 -18
  138. package/build/src/library/audit.d.ts +2 -0
  139. package/build/src/library/audit.js +1 -0
  140. package/build/src/library/bind.js +18 -16
  141. package/build/src/library/composition.d.ts +1 -0
  142. package/build/src/library/contract-bind.d.ts +3 -1
  143. package/build/src/library/contract-bind.js +5 -3
  144. package/build/src/library/contract-execution.d.ts +2 -0
  145. package/build/src/library/contract-execution.js +15 -1
  146. package/build/src/library/contract-forwarding.d.ts +4 -0
  147. package/build/src/library/contract-forwarding.js +3 -0
  148. package/build/src/library/contract-handle.d.ts +7 -0
  149. package/build/src/library/contract-handle.js +25 -0
  150. package/build/src/library/contract-operations.d.ts +7 -2
  151. package/build/src/library/contract-operations.js +21 -1
  152. package/build/src/library/contract-types.d.ts +1 -0
  153. package/build/src/library/execution-result.d.ts +2 -2
  154. package/build/src/library/execution.d.ts +8 -0
  155. package/build/src/library/execution.js +102 -0
  156. package/build/src/library/fleet.d.ts +4 -1
  157. package/build/src/library/fleet.js +32 -8
  158. package/build/src/library/keiyaku.d.ts +2 -0
  159. package/build/src/library/mutation.js +15 -7
  160. package/build/src/plugin/akuma-signals.d.ts +6 -0
  161. package/build/src/plugin/akuma-signals.js +9 -1
  162. package/build/src/plugin/public.d.ts +6 -2
  163. package/build/src/plugin/runtime.d.ts +1 -3
  164. package/build/src/plugin/runtime.js +95 -103
  165. package/build/src/protocol/amend.js +4 -3
  166. package/build/src/protocol/attempt.d.ts +2 -0
  167. package/build/src/protocol/bind.js +41 -14
  168. package/build/src/protocol/completion.d.ts +3 -0
  169. package/build/src/protocol/completion.js +35 -11
  170. package/build/src/protocol/deliver.js +165 -92
  171. package/build/src/protocol/execution-observation.d.ts +181 -0
  172. package/build/src/protocol/execution-observation.js +45 -0
  173. package/build/src/protocol/intent.d.ts +18 -22
  174. package/build/src/protocol/intent.js +63 -41
  175. package/build/src/protocol/operations.d.ts +2 -0
  176. package/build/src/protocol/placement.js +5 -1
  177. package/build/src/protocol/progress.d.ts +5 -1
  178. package/build/src/protocol/progress.js +10 -1
  179. package/build/src/protocol/read/status.d.ts +1 -0
  180. package/build/src/protocol/read/status.js +10 -2
  181. package/build/src/protocol/reintegrate.d.ts +1 -1
  182. package/build/src/protocol/reintegrate.js +70 -43
  183. package/build/src/protocol/result-codec.js +27 -11
  184. package/build/src/protocol/review.js +53 -30
  185. package/build/src/protocol/run.d.ts +83 -36
  186. package/build/src/protocol/run.js +90 -75
  187. package/build/src/runtime/proc/run.d.ts +16 -4
  188. package/build/src/runtime/proc/run.js +64 -22
  189. package/build/src/runtime/proc/windows-launch.exe +0 -0
  190. package/build/src/settings.js +5 -14
  191. package/build/src/task/document.d.ts +5 -1
  192. package/build/src/task/document.js +6 -1
  193. package/build/src/verification/execution.d.ts +10 -2
  194. package/build/src/verification/execution.js +143 -42
  195. package/build/src/verification/observation.d.ts +41 -0
  196. package/build/src/verification/observation.js +29 -0
  197. package/package.json +3 -1
@@ -26,7 +26,7 @@ function retainTrailingFailure(context, operation, error) {
26
26
  }
27
27
  /** The channel's own retirement cannot hide an already returned admission. */
28
28
  export async function withContractExecution(input, operation, run) {
29
- const progress = new ExecutionProgress();
29
+ const progress = new ExecutionProgress(input.observe);
30
30
  const scope = withScopeAbortSignal(input.scope, input.signal);
31
31
  let produced;
32
32
  try {
@@ -71,6 +71,13 @@ async function advanceAndContinue(context, checkpoint, start) {
71
71
  ...(context.actor === undefined ? {} : { actor: context.actor }),
72
72
  ...(context.signal === undefined ? {} : { signal: context.signal }),
73
73
  });
74
+ if (result.kind === "completed")
75
+ context.progress.observe({
76
+ kind: "stage",
77
+ contractId: context.contractId,
78
+ stage: "continuation",
79
+ state: "started",
80
+ });
74
81
  const continuation = result.kind !== "completed"
75
82
  ? undefined
76
83
  : await continueDeliveredDependents({
@@ -78,6 +85,13 @@ async function advanceAndContinue(context, checkpoint, start) {
78
85
  completed: result,
79
86
  deriveDocument: derivedDocument,
80
87
  });
88
+ if (result.kind === "completed")
89
+ context.progress.observe({
90
+ kind: "stage",
91
+ contractId: context.contractId,
92
+ stage: "continuation",
93
+ state: "finished",
94
+ });
81
95
  return { ...result.evidence, ...(continuation === undefined ? {} : { continuation }) };
82
96
  }
83
97
  /** Review records testimony, then the same shared node judges automatic placement. */
@@ -1,4 +1,5 @@
1
1
  import type { ActorId, ContractId } from "../core/facts/types.js";
2
+ import type { ExecutionObserver } from "../protocol/execution-observation.js";
2
3
  import type { IntegrationConflictMaterialized } from "../protocol/deliver.js";
3
4
  import type { AuditReport } from "../protocol/audit.js";
4
5
  import { type AuditComposition } from "./audit.js";
@@ -20,6 +21,7 @@ export declare function executeForwardedDeliver(input: Readonly<{
20
21
  requireBranchesToBeUpToDate: boolean;
21
22
  hooks: Parameters<typeof executeLocalDelivery>[0]["hooks"];
22
23
  signal?: AbortSignal;
24
+ observe?: ExecutionObserver;
23
25
  }>): Promise<Readonly<{
24
26
  result: MutationResult<DeliveryValue> | IntegrationConflictMaterialized;
25
27
  deliveryFactId?: string;
@@ -32,6 +34,7 @@ export declare function executeForwardedReview(input: Readonly<{
32
34
  summary?: string;
33
35
  signal?: AbortSignal;
34
36
  hooks: Parameters<typeof executeLocalReview>[0]["hooks"];
37
+ observe?: ExecutionObserver;
35
38
  }>): Promise<Readonly<{
36
39
  result: MutationResult<Review>;
37
40
  reviewFactId?: string;
@@ -45,6 +48,7 @@ export declare function executeForwardedAudit(input: Readonly<{
45
48
  requireBranchesToBeUpToDate: boolean;
46
49
  hooks: NonNullable<AuditComposition["hooks"]>;
47
50
  signal?: AbortSignal;
51
+ observe?: ExecutionObserver;
48
52
  }>): Promise<Readonly<{
49
53
  result: MutationResult<AuditReport>;
50
54
  auditReport?: AuditReport;
@@ -16,6 +16,7 @@ export async function executeForwardedDeliver(input) {
16
16
  overwrite: input.overwrite ?? false,
17
17
  ...(input.signal === undefined ? {} : { signal: input.signal }),
18
18
  hooks: input.hooks,
19
+ ...(input.observe === undefined ? {} : { observe: input.observe }),
19
20
  });
20
21
  if (result.kind !== "accepted")
21
22
  return { result };
@@ -38,6 +39,7 @@ export async function executeForwardedReview(input) {
38
39
  verdict: input.verdict,
39
40
  ...(input.summary === undefined ? {} : { summary: input.summary }),
40
41
  hooks: input.hooks,
42
+ ...(input.observe === undefined ? {} : { observe: input.observe }),
41
43
  ...(input.signal === undefined ? {} : { signal: input.signal }),
42
44
  });
43
45
  const review = result.facts.find((fact) => fact.kind === "attestation");
@@ -49,6 +51,7 @@ export async function executeForwardedAudit(input) {
49
51
  const result = await auditContract({
50
52
  scope: scopeForRepo(input.repo),
51
53
  contractId: input.contractId,
54
+ ...(input.observe === undefined ? {} : { observe: input.observe }),
52
55
  input: {
53
56
  includeDirty: input.includeDirty,
54
57
  showDiff: input.showDiff,
@@ -1,3 +1,4 @@
1
+ import { type ContractExecution } from "./execution.js";
1
2
  import { type ContractId, type ContractState } from "../core/facts/types.js";
2
3
  import { type RepositoryScope } from "../protocol/operations.js";
3
4
  import type { AuditReport } from "../protocol/audit.js";
@@ -22,11 +23,17 @@ export declare class KeiyakuHandle {
22
23
  guidance(): Promise<string>;
23
24
  delivery(): Promise<Delivery | null>;
24
25
  amend(input: AmendInput): Promise<AmendResult>;
26
+ startDelivery(input?: DeliverInput): ContractExecution<MutationResult<Delivery> | IntegrationConflictMaterialized>;
25
27
  deliver(input?: DeliverInput): Promise<MutationResult<Delivery> | IntegrationConflictMaterialized>;
28
+ private runDelivery;
29
+ startReview(input: ReviewInput): ContractExecution<MutationResult<Review>>;
26
30
  review(input: ReviewInput): Promise<MutationResult<Review>>;
31
+ private runReview;
27
32
  abandon(input?: AbandonInput): Promise<MutationResult<void>>;
28
33
  arc(input: ArcInput): Promise<MutationResult<void>>;
34
+ startAudit(input?: AuditInput): ContractExecution<MutationResult<AuditReport>>;
29
35
  audit(input?: AuditInput): Promise<MutationResult<AuditReport>>;
36
+ private runAudit;
30
37
  reconcile(input?: ReconcileInput): Promise<ReconcileReport>;
31
38
  private deliveryHandle;
32
39
  }
@@ -1,5 +1,6 @@
1
1
  /** @architectureCompositionRoot */
2
2
  import { documentDiff } from "../markdown/diff.js";
3
+ import { startContractExecution } from "./execution.js";
3
4
  import { applyAmendDocument } from "../body/amend.js";
4
5
  import { decodeArcDocument } from "../body/arc.js";
5
6
  import { decodeContractDocument } from "../body/decode.js";
@@ -156,7 +157,13 @@ export class KeiyakuHandle {
156
157
  ...regionObservation,
157
158
  };
158
159
  }
160
+ startDelivery(input) {
161
+ return startContractExecution((observe) => this.runDelivery(input, observe));
162
+ }
159
163
  async deliver(input) {
164
+ return this.startDelivery(input).result;
165
+ }
166
+ async runDelivery(input, observe) {
160
167
  const values = input === undefined
161
168
  ? undefined
162
169
  : requireInput(input, "deliver input", [
@@ -184,10 +191,12 @@ export class KeiyakuHandle {
184
191
  overwrite,
185
192
  ...(signal === undefined ? {} : { signal }),
186
193
  hooks: this.composition.hooks,
194
+ observe,
187
195
  })
188
196
  : await requestForwardedContractLive({
189
197
  directory: channel.directory,
190
198
  action: "contract.deliver",
199
+ observe,
191
200
  request: {
192
201
  action: "contract.deliver",
193
202
  repoRoot: this.scope.primaryWorktree,
@@ -201,7 +210,13 @@ export class KeiyakuHandle {
201
210
  });
202
211
  return "facts" in result ? { ...result, value: this.deliveryHandle(result.value) } : result;
203
212
  }
213
+ startReview(input) {
214
+ return startContractExecution((observe) => this.runReview(input, observe));
215
+ }
204
216
  async review(input) {
217
+ return this.startReview(input).result;
218
+ }
219
+ async runReview(input, observe) {
205
220
  const values = requireInput(input, "review input", ["verdict", "summary", "signal"]);
206
221
  const verdict = values.verdict;
207
222
  if (verdict !== "satisfied" && verdict !== "unsatisfied") {
@@ -214,6 +229,7 @@ export class KeiyakuHandle {
214
229
  return await requestForwardedContractLive({
215
230
  directory: channel.directory,
216
231
  action: "contract.review",
232
+ observe,
217
233
  ...(signal === undefined ? {} : { signal }),
218
234
  request: {
219
235
  action: "contract.review",
@@ -231,6 +247,7 @@ export class KeiyakuHandle {
231
247
  verdict,
232
248
  ...(summary === undefined ? {} : { summary }),
233
249
  hooks: this.composition.hooks,
250
+ observe,
234
251
  ...(signal === undefined ? {} : { signal }),
235
252
  });
236
253
  }
@@ -290,7 +307,13 @@ export class KeiyakuHandle {
290
307
  });
291
308
  });
292
309
  }
310
+ startAudit(input) {
311
+ return startContractExecution((observe) => this.runAudit(input, observe));
312
+ }
293
313
  async audit(input) {
314
+ return this.startAudit(input).result;
315
+ }
316
+ async runAudit(input, observe) {
294
317
  const values = input === undefined ? undefined : requireInput(input, "audit input", ["includeDirty", "showDiff", "signal"]);
295
318
  const includeDirty = optionalBoolean(values?.includeDirty, "includeDirty") ?? false;
296
319
  const showDiff = optionalBoolean(values?.showDiff, "showDiff") ?? false;
@@ -305,6 +328,7 @@ export class KeiyakuHandle {
305
328
  return await requestForwardedContractLive({
306
329
  directory: channel.directory,
307
330
  action: "contract.audit",
331
+ observe,
308
332
  request: {
309
333
  action: "contract.audit",
310
334
  repoRoot: this.scope.primaryWorktree,
@@ -320,6 +344,7 @@ export class KeiyakuHandle {
320
344
  contractId: this.id,
321
345
  input: auditInput,
322
346
  composition: this.composition,
347
+ observe,
323
348
  });
324
349
  }
325
350
  async reconcile(input) {
@@ -1,3 +1,4 @@
1
+ import { type ExecutionObserver } from "../protocol/execution-observation.js";
1
2
  import { type ErasedRequestCommand, type RequestProtocol, type ServiceRequestCommand } from "../akuma/request-wire.js";
2
3
  import type { AuditReport } from "../protocol/audit.js";
3
4
  import type { IntegrationConflictMaterialized } from "../protocol/deliver.js";
@@ -90,7 +91,7 @@ declare const materializedHandoffReferenceSchema: z.ZodObject<{
90
91
  handoffBase: z.ZodPipe<z.ZodString, z.ZodTransform<import("../core/facts/types.js").SnapshotId, string>>;
91
92
  recovery: z.ZodObject<{
92
93
  materialize: z.ZodLiteral<"deliver --materialize-conflict --include-dirty">;
93
- continue: z.ZodLiteral<"deliver --include-dirty">;
94
+ deliver: z.ZodLiteral<"deliver --include-dirty">;
94
95
  staging: z.ZodLiteral<"not-required">;
95
96
  }, z.core.$strict>;
96
97
  conflictPaths: z.ZodPipe<z.ZodArray<z.ZodString>, z.ZodTransform<readonly string[], string[]>>;
@@ -215,7 +216,7 @@ declare const contractServiceSchema: z.ZodUnion<readonly [z.ZodObject<{
215
216
  handoffBase: z.ZodPipe<z.ZodString, z.ZodTransform<import("../core/facts/types.js").SnapshotId, string>>;
216
217
  recovery: z.ZodObject<{
217
218
  materialize: z.ZodLiteral<"deliver --materialize-conflict --include-dirty">;
218
- continue: z.ZodLiteral<"deliver --include-dirty">;
219
+ deliver: z.ZodLiteral<"deliver --include-dirty">;
219
220
  staging: z.ZodLiteral<"not-required">;
220
221
  }, z.core.$strict>;
221
222
  conflictPaths: z.ZodPipe<z.ZodArray<z.ZodString>, z.ZodTransform<readonly string[], string[]>>;
@@ -235,6 +236,7 @@ export type ContractRequestPort = Readonly<{
235
236
  audit(input: AuditRequest & Readonly<{
236
237
  requester: ContractRequester;
237
238
  signal: AbortSignal;
239
+ observe?: ExecutionObserver;
238
240
  }>): Promise<Readonly<{
239
241
  result: AuditResult;
240
242
  auditReport?: AuditReport;
@@ -242,6 +244,7 @@ export type ContractRequestPort = Readonly<{
242
244
  deliver(input: DeliverRequest & Readonly<{
243
245
  requester: ContractRequester;
244
246
  signal: AbortSignal;
247
+ observe?: ExecutionObserver;
245
248
  }>): Promise<Readonly<{
246
249
  result: DeliveryResult;
247
250
  deliveryFactId?: string;
@@ -249,6 +252,7 @@ export type ContractRequestPort = Readonly<{
249
252
  review(input: ReviewRequest & Readonly<{
250
253
  requester: ContractRequester;
251
254
  signal: AbortSignal;
255
+ observe?: ExecutionObserver;
252
256
  }>): Promise<Readonly<{
253
257
  result: ReviewResult;
254
258
  reviewFactId?: string;
@@ -262,6 +266,7 @@ export declare function requestForwardedContractLive<Action extends ContractRequ
262
266
  action: Action;
263
267
  request: ContractRequestFor<Action>;
264
268
  signal?: AbortSignal;
269
+ observe?: ExecutionObserver;
265
270
  }>): Promise<ContractResultFor<Action>>;
266
271
  export { executeLocalDelivery, executeLocalReview, executeForwardedAudit, executeForwardedDeliver, executeForwardedReview, } from "./contract-forwarding.js";
267
272
  export type { AttestationVerdict, DeliveryExecutionInput, Review, ReviewExecutionInput, } from "./contract-forwarding.js";
@@ -1,4 +1,5 @@
1
1
  import { executionReceipt } from "./execution-result.js";
2
+ import { decodeExecutionEvent, observeExecution } from "../protocol/execution-observation.js";
2
3
  import { contractId, snapshotId } from "../core/facts/types.js";
3
4
  import { AkumaBodyRequestError, requestBodyCommand } from "../akuma/request-rendezvous.js";
4
5
  import { eraseRequestCommand, } from "../akuma/request-wire.js";
@@ -30,7 +31,7 @@ const contractRequestBaseSchema = z.object({ repoRoot: absolutePathSchema, contr
30
31
  const conflictRecoverySchema = z
31
32
  .object({
32
33
  materialize: z.literal("deliver --materialize-conflict --include-dirty"),
33
- continue: z.literal("deliver --include-dirty"),
34
+ deliver: z.literal("deliver --include-dirty"),
34
35
  staging: z.literal("not-required"),
35
36
  })
36
37
  .strict();
@@ -138,10 +139,17 @@ function decodeContractReference(action, value) {
138
139
  throw new Error(`malformed stored Contract service evidence for ${action}`);
139
140
  return parsed.data;
140
141
  }
142
+ function executionObservation(facts) {
143
+ if (facts.progress === undefined)
144
+ return {};
145
+ return { observe: (event) => facts.progress?.(event) };
146
+ }
141
147
  async function executeContractRequest(request, facts, port) {
148
+ const observation = executionObservation(facts);
142
149
  if (request.action === "contract.audit") {
143
150
  const served = await port.audit({
144
151
  ...request,
152
+ ...observation,
145
153
  requester: facts.requester,
146
154
  signal: facts.signal,
147
155
  });
@@ -160,6 +168,7 @@ async function executeContractRequest(request, facts, port) {
160
168
  if (request.action === "contract.deliver") {
161
169
  const served = await port.deliver({
162
170
  ...request,
171
+ ...observation,
163
172
  overwrite: request.overwrite ?? false,
164
173
  requester: facts.requester,
165
174
  signal: facts.signal,
@@ -193,6 +202,7 @@ async function executeContractRequest(request, facts, port) {
193
202
  }
194
203
  const served = await port.review({
195
204
  ...request,
205
+ ...observation,
196
206
  requester: facts.requester,
197
207
  signal: facts.signal,
198
208
  });
@@ -222,6 +232,7 @@ function decodedContractResult(action, value) {
222
232
  export function contractRequestProtocol(action) {
223
233
  return {
224
234
  action,
235
+ supportsCancellation: true,
225
236
  encodeRequest: (request) => {
226
237
  const { action: _action, ...payload } = request;
227
238
  return payload;
@@ -258,6 +269,15 @@ export async function requestForwardedContractLive(input) {
258
269
  directory: input.directory,
259
270
  command,
260
271
  value: input.request,
272
+ onProgress: (value) => {
273
+ try {
274
+ observeExecution(input.observe, decodeExecutionEvent(value));
275
+ }
276
+ catch {
277
+ observeExecution(input.observe, { kind: "progress-dropped", count: 1 });
278
+ }
279
+ },
280
+ onProgressGap: (count) => observeExecution(input.observe, { kind: "progress-dropped", count }),
261
281
  ...(input.signal === undefined ? {} : { signal: input.signal }),
262
282
  }).catch((error) => {
263
283
  if (error instanceof AkumaBodyRequestError &&
@@ -13,6 +13,7 @@ import type { ContractWorkspaceLocation } from "../workspace-place.js";
13
13
  export type BindResult = Readonly<Omit<MutationResult<Keiyaku>, "value"> & {
14
14
  keiyaku: Keiyaku;
15
15
  workspace?: ContractWorkspaceLocation;
16
+ warnings?: readonly string[];
16
17
  } & RegionObservation>;
17
18
  export type Fact = JournalEntry;
18
19
  export type ContractHistoryEvent = Readonly<{
@@ -103,9 +103,9 @@ export declare const executionStopSchema: z.ZodObject<{
103
103
  admission: "admission";
104
104
  placement: "placement";
105
105
  verification: "verification";
106
- reintegration: "reintegration";
107
106
  continuation: "continuation";
108
107
  reconciliation: "reconciliation";
108
+ reintegration: "reintegration";
109
109
  }>;
110
110
  reason: z.ZodEnum<{
111
111
  failed: "failed";
@@ -226,9 +226,9 @@ export declare const executionReceiptSchema: z.ZodObject<{
226
226
  admission: "admission";
227
227
  placement: "placement";
228
228
  verification: "verification";
229
- reintegration: "reintegration";
230
229
  continuation: "continuation";
231
230
  reconciliation: "reconciliation";
231
+ reintegration: "reintegration";
232
232
  }>;
233
233
  reason: z.ZodEnum<{
234
234
  failed: "failed";
@@ -0,0 +1,8 @@
1
+ import type { ExecutionEvent, ExecutionObserver } from "../protocol/execution-observation.js";
2
+ export type { ExecutionEvent } from "../protocol/execution-observation.js";
3
+ export type ContractExecution<Result> = Readonly<{
4
+ progress: AsyncIterable<ExecutionEvent>;
5
+ result: Promise<Result>;
6
+ }>;
7
+ /** An eager invocation with one bounded, optional progress subscription. */
8
+ export declare function startContractExecution<Result>(run: (observe: ExecutionObserver) => Promise<Result>): ContractExecution<Result>;
@@ -0,0 +1,102 @@
1
+ const MAX_EVENTS = 256;
2
+ const MAX_BYTES = 128 * 1024;
3
+ class BoundedExecutionProgress {
4
+ pending = [];
5
+ bytes = 0;
6
+ dropped = 0;
7
+ finished = false;
8
+ unsubscribed = false;
9
+ subscribed = false;
10
+ wake;
11
+ notify() {
12
+ const waiter = this.wake;
13
+ this.wake = undefined;
14
+ waiter?.();
15
+ }
16
+ publish = (event) => {
17
+ if (this.unsubscribed || this.finished)
18
+ return;
19
+ const size = Buffer.byteLength(JSON.stringify(event));
20
+ if (size > MAX_BYTES) {
21
+ this.dropped += 1;
22
+ this.notify();
23
+ return;
24
+ }
25
+ while (this.pending.length >= MAX_EVENTS || this.bytes + size > MAX_BYTES) {
26
+ this.bytes -= this.pending.shift().bytes;
27
+ this.dropped += 1;
28
+ }
29
+ this.pending.push({ event, bytes: size });
30
+ this.bytes += size;
31
+ this.notify();
32
+ };
33
+ close() {
34
+ this.finished = true;
35
+ this.notify();
36
+ }
37
+ iterable() {
38
+ return {
39
+ [Symbol.asyncIterator]: () => this.iterator(),
40
+ };
41
+ }
42
+ iterator() {
43
+ if (this.subscribed)
44
+ throw new Error("execution progress supports one subscription");
45
+ this.subscribed = true;
46
+ let reading = false;
47
+ return {
48
+ next: async () => {
49
+ if (reading)
50
+ throw new Error("execution progress next calls must be serial");
51
+ reading = true;
52
+ try {
53
+ for (;;) {
54
+ const next = await this.next();
55
+ if (next !== undefined)
56
+ return next;
57
+ }
58
+ }
59
+ finally {
60
+ reading = false;
61
+ }
62
+ },
63
+ return: async () => {
64
+ this.unsubscribed = true;
65
+ this.pending.length = 0;
66
+ this.bytes = 0;
67
+ this.dropped = 0;
68
+ this.notify();
69
+ return { done: true, value: undefined };
70
+ },
71
+ };
72
+ }
73
+ async next() {
74
+ if (this.unsubscribed)
75
+ return { done: true, value: undefined };
76
+ if (this.dropped > 0) {
77
+ const count = this.dropped;
78
+ this.dropped = 0;
79
+ return { done: false, value: { kind: "progress-dropped", count } };
80
+ }
81
+ const pending = this.pending.shift();
82
+ if (pending !== undefined) {
83
+ this.bytes -= pending.bytes;
84
+ return { done: false, value: pending.event };
85
+ }
86
+ if (this.finished)
87
+ return { done: true, value: undefined };
88
+ await new Promise((resolve) => {
89
+ this.wake = resolve;
90
+ });
91
+ return undefined;
92
+ }
93
+ }
94
+ /** An eager invocation with one bounded, optional progress subscription. */
95
+ export function startContractExecution(run) {
96
+ const observations = new BoundedExecutionProgress();
97
+ const result = Promise.resolve()
98
+ .then(() => run(observations.publish))
99
+ .finally(() => observations.close());
100
+ void result.catch(() => undefined);
101
+ return Object.freeze({ progress: observations.iterable(), result });
102
+ }
@@ -1,6 +1,7 @@
1
1
  /** @architectureCompositionRoot */
2
2
  import { type ActivityHistory, type OutcomeRow, type AkumaStatus, type InterruptReceipt } from "../akuma/akuma.js";
3
3
  import { type ExecutionContext } from "../akuma/requests.js";
4
+ import type { WaitObserver } from "../akuma/fleet-execution.js";
4
5
  import { type DispatchAssociation } from "../dispatch/index.js";
5
6
  import { type AkumaAddressInput, type AkumaSetAddressInput } from "./address.js";
6
7
  import { type AkumaKillResult, type AkumaObservation, type AkumaObservationStage, type AkumaTellResult, type AkumaWaitResult } from "../akuma/fleet-observation.js";
@@ -10,6 +11,7 @@ export type AkumaWaitInput = AkumaSetAddressInput & Readonly<{
10
11
  }>;
11
12
  export type AkumaTellInput = AkumaAddressInput & Readonly<{
12
13
  body: string;
14
+ initiator?: string;
13
15
  }>;
14
16
  export type { TellResult, TellWake } from "../akuma/akuma.js";
15
17
  export type { CreatedTaskObservation } from "../task/created-observation.js";
@@ -17,6 +19,7 @@ export type { DispatchAssociation } from "../dispatch/association.js";
17
19
  export type { AkumaKillResult, AkumaObservation, AkumaObservationStage, AkumaTellResult, AkumaUnobserved, AkumaWaitResult, } from "../akuma/fleet-observation.js";
18
20
  export type AkumaInterruptInput = AkumaAddressInput & Readonly<{
19
21
  body: string;
22
+ initiator?: string;
20
23
  }>;
21
24
  export type AkumaInterruptResult = Readonly<{
22
25
  id: AkumaStatus["id"];
@@ -56,7 +59,7 @@ export type AkumaHistoryResult = Readonly<{
56
59
  contract: DispatchAssociation;
57
60
  }>;
58
61
  export declare function statusAkuma(input: AkumaAddressInput): Promise<AkumaObservation>;
59
- export declare function waitAkuma(input: AkumaWaitInput, execution?: ExecutionContext): Promise<AkumaWaitResult>;
62
+ export declare function waitAkuma(input: AkumaWaitInput, execution?: ExecutionContext, observer?: WaitObserver): Promise<AkumaWaitResult>;
60
63
  export declare function killAkuma(input: AkumaSetAddressInput, execution?: ExecutionContext): Promise<AkumaKillResult>;
61
64
  export declare function tellAkuma(input: AkumaTellInput, execution?: ExecutionContext): Promise<AkumaTellResult>;
62
65
  export declare function interruptAkuma(input: AkumaInterruptInput): Promise<AkumaInterruptResult>;
@@ -4,6 +4,7 @@ import { createAkumaProduct } from "../akuma/akuma-product.js";
4
4
  import { executionChannel, localExecutionContext } from "../akuma/requests.js";
5
5
  import { requestForwardedFleetKill, requestForwardedFleetTell, requestForwardedFleetWait, } from "../akuma/fleet-request.js";
6
6
  import { executeKillAkuma, executeTellAkuma, executeWaitAkuma } from "../akuma/fleet-execution.js";
7
+ import { readAliases } from "../alias/index.js";
7
8
  import { observeDispatchAssociation } from "../dispatch/index.js";
8
9
  import { observeCreatedTaskObservations } from "../task/created-observation.js";
9
10
  import { addressAkuma, addressAkumaSet } from "./address.js";
@@ -23,6 +24,26 @@ async function dispatchAssociation(repo, id) {
23
24
  async function createdTasksFor(path, statuses) {
24
25
  return await observeCreatedTaskObservations(path, statuses.map((status) => status.id));
25
26
  }
27
+ /**
28
+ * One wait's identity-fact resolver: the alias bound to an Akuma in its world and
29
+ * its Dispatch association. The alias index is read once, on the first observed
30
+ * Akuma, and each Akuma's alias is the first binding the canonical order offers.
31
+ */
32
+ function waitIdentityFacts(path, repo) {
33
+ let aliases;
34
+ return async (id) => {
35
+ if (aliases === undefined) {
36
+ const bound = new Map();
37
+ for (const binding of await readAliases(path)) {
38
+ if (!bound.has(binding.akuId))
39
+ bound.set(binding.akuId, binding.alias);
40
+ }
41
+ aliases = bound;
42
+ }
43
+ const alias = aliases.get(id);
44
+ return { ...(alias === undefined ? {} : { alias }), contract: await dispatchAssociation(repo, id) };
45
+ };
46
+ }
26
47
  async function observeAkuma(status, path, repo) {
27
48
  return (await observeAkumaSet([status], path, repo))[0];
28
49
  }
@@ -85,7 +106,7 @@ export async function statusAkuma(input) {
85
106
  const addressed = await addressAkuma(input);
86
107
  return await observeAkuma(await source(addressed.path).selectHandle({ id: addressed.id }).status(), addressed.path, input.repo);
87
108
  }
88
- export async function waitAkuma(input, execution = localExecutionContext()) {
109
+ export async function waitAkuma(input, execution = localExecutionContext(), observer) {
89
110
  const values = requireInput(input, "Keiyaku.wait input");
90
111
  for (const key of Object.keys(values)) {
91
112
  if (!["path", "akuma", "repo", "completion", "timeoutMs"].includes(key)) {
@@ -94,13 +115,11 @@ export async function waitAkuma(input, execution = localExecutionContext()) {
94
115
  }
95
116
  const addressed = await addressAkumaSet(setAddress(values));
96
117
  const completion = values.completion;
97
- if (addressed.ids.length > 1 && completion !== "any" && completion !== "all") {
98
- throw new TypeError("completion must be any or all when waiting for multiple Akuma");
99
- }
100
118
  if (completion !== undefined && completion !== "any" && completion !== "all") {
101
119
  throw new TypeError("completion must be any or all");
102
120
  }
103
- const selected = completion ?? "all";
121
+ // An omitted mode is any: a plural wait returns when any selected Akuma is complete.
122
+ const selected = completion ?? "any";
104
123
  const timeoutMs = timeout(values.timeoutMs);
105
124
  const channel = executionChannel(execution);
106
125
  const repo = values.repo;
@@ -117,6 +136,9 @@ export async function waitAkuma(input, execution = localExecutionContext()) {
117
136
  ids: addressed.ids,
118
137
  completion: selected,
119
138
  ...(timeoutMs === undefined ? {} : { timeoutMs }),
139
+ identity: waitIdentityFacts(addressed.path, repo),
140
+ ...(observer?.selected === undefined ? {} : { onSelected: observer.selected }),
141
+ ...(observer?.observe === undefined ? {} : { observe: observer.observe }),
120
142
  }));
121
143
  }
122
144
  export async function killAkuma(input, execution = localExecutionContext()) {
@@ -136,7 +158,7 @@ export async function killAkuma(input, execution = localExecutionContext()) {
136
158
  export async function tellAkuma(input, execution = localExecutionContext()) {
137
159
  const values = requireInput(input, "Keiyaku.tell input");
138
160
  for (const key of Object.keys(values)) {
139
- if (!["path", "akuma", "body", "repo"].includes(key)) {
161
+ if (!["path", "akuma", "body", "repo", "initiator"].includes(key)) {
140
162
  throw new TypeError(`Keiyaku.tell input has unknown field: ${key}`);
141
163
  }
142
164
  }
@@ -149,18 +171,20 @@ export async function tellAkuma(input, execution = localExecutionContext()) {
149
171
  directory: channel.directory,
150
172
  target: addressed.id,
151
173
  body: values.body,
174
+ ...(input.initiator === undefined ? {} : { initiator: input.initiator }),
152
175
  });
153
176
  }
154
177
  return await executeTellAkuma({
155
178
  path: addressed.path,
156
179
  id: addressed.id,
157
180
  body: values.body,
181
+ ...(input.initiator === undefined ? {} : { initiator: input.initiator }),
158
182
  });
159
183
  }
160
184
  export async function interruptAkuma(input) {
161
185
  const values = requireInput(input, "Keiyaku.interrupt input");
162
186
  for (const key of Object.keys(values)) {
163
- if (!["path", "akuma", "body", "repo"].includes(key)) {
187
+ if (!["path", "akuma", "body", "repo", "initiator"].includes(key)) {
164
188
  throw new TypeError(`Keiyaku.interrupt input has unknown field: ${key}`);
165
189
  }
166
190
  }
@@ -168,7 +192,7 @@ export async function interruptAkuma(input) {
168
192
  throw new TypeError("body must be a string");
169
193
  const addressed = await addressAkuma(directAddress(values));
170
194
  const handle = source(addressed.path).selectHandle({ id: addressed.id });
171
- const receipt = await handle.interrupt(values.body);
195
+ const receipt = await handle.interrupt(values.body, input.initiator === undefined ? {} : { initiator: input.initiator });
172
196
  const observation = await observeAkumaStage(addressed.path, addressed.id, values.repo);
173
197
  return { id: addressed.id, receipt, observation };
174
198
  }
@@ -122,6 +122,7 @@ export declare const Keiyaku: Readonly<{
122
122
  status: {
123
123
  id: import("../akuma/identity.js").AkuId;
124
124
  life: "killed" | "hung" | "untidy" | "running" | "asleep" | "stranded";
125
+ allowed: import("../akuma/allowed.js").AllowedActions;
125
126
  timeline: {
126
127
  reportedChanges: readonly {
127
128
  sequence: number;
@@ -418,4 +419,5 @@ export declare const Keiyaku: Readonly<{
418
419
  }>;
419
420
  }>;
420
421
  export { executionReceipt } from "./execution-result.js";
422
+ export type { ContractExecution, ExecutionEvent } from "./execution.js";
421
423
  export type { ExecutionCleanup, ExecutionStop, ExecutionReceipt, MutationOperation } from "./execution-result.js";
@@ -184,13 +184,21 @@ async function reconcileExecution(input, progress) {
184
184
  for (const contractId of contracts) {
185
185
  try {
186
186
  input.scope.signal?.throwIfAborted();
187
- const report = await completeReconcile({
188
- scope: input.scope,
189
- channel: input.channel,
190
- contractId,
191
- hooks: input.hooks,
192
- retryHooks: false,
193
- });
187
+ progress.observe({ kind: "stage", contractId, stage: "reconciliation", state: "started" });
188
+ const report = await (async () => {
189
+ try {
190
+ return await completeReconcile({
191
+ scope: input.scope,
192
+ channel: input.channel,
193
+ contractId,
194
+ hooks: input.hooks,
195
+ retryHooks: false,
196
+ });
197
+ }
198
+ finally {
199
+ progress.observe({ kind: "stage", contractId, stage: "reconciliation", state: "finished" });
200
+ }
201
+ })();
194
202
  reports.push(report);
195
203
  progress.recordResidue(contractId, report.settlement);
196
204
  }