@astrosheep/keiyaku 4.0.2 → 4.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (145) hide show
  1. package/build/integrations/marketplace/plugins/keiyaku/.claude-plugin/plugin.json +1 -1
  2. package/build/integrations/marketplace/plugins/keiyaku/.codex-plugin/plugin.json +1 -1
  3. package/build/integrations/marketplace/plugins/keiyaku/package.json +1 -1
  4. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +1 -1
  5. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +1 -1
  6. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +5 -0
  7. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-task/SKILL.md +3 -1
  8. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +9 -8
  9. package/build/src/akuma/akuma.d.ts +34 -11
  10. package/build/src/akuma/akuma.js +121 -61
  11. package/build/src/akuma/allowed.d.ts +7 -0
  12. package/build/src/akuma/allowed.js +40 -0
  13. package/build/src/akuma/archetype.d.ts +7 -4
  14. package/build/src/akuma/archetype.js +15 -16
  15. package/build/src/akuma/body.d.ts +3 -1
  16. package/build/src/akuma/body.js +19 -8
  17. package/build/src/akuma/heart/facts.d.ts +49 -7
  18. package/build/src/akuma/heart/index.d.ts +4 -8
  19. package/build/src/akuma/heart/index.js +76 -15
  20. package/build/src/akuma/heart/rows.d.ts +7 -5
  21. package/build/src/akuma/heart/rows.js +98 -11
  22. package/build/src/akuma/heart/schema.d.ts +1 -1
  23. package/build/src/akuma/heart/schema.js +15 -10
  24. package/build/src/akuma/heart/soul.js +3 -1
  25. package/build/src/akuma/heart/storage.d.ts +2 -0
  26. package/build/src/akuma/heart/storage.js +20 -0
  27. package/build/src/akuma/heart/timeline.d.ts +1 -5
  28. package/build/src/akuma/heart/timeline.js +8 -17
  29. package/build/src/akuma/index.d.ts +4 -1
  30. package/build/src/akuma/index.js +1 -0
  31. package/build/src/akuma/projection.d.ts +17 -3
  32. package/build/src/akuma/projection.js +40 -3
  33. package/build/src/akuma/provider.d.ts +1 -1
  34. package/build/src/akuma/provider.js +2 -1
  35. package/build/src/akuma/providers/acp/core.d.ts +3 -1
  36. package/build/src/akuma/providers/acp/core.js +4 -4
  37. package/build/src/akuma/providers/acp/events.d.ts +11 -3
  38. package/build/src/akuma/providers/acp/events.js +78 -4
  39. package/build/src/akuma/providers/claude/events.js +62 -3
  40. package/build/src/akuma/providers/codex-app-server/events.js +1 -13
  41. package/build/src/akuma/providers/grok-build/index.d.ts +2 -1
  42. package/build/src/akuma/providers/grok-build/index.js +72 -2
  43. package/build/src/akuma/providers/opencode-sdk/events.js +71 -6
  44. package/build/src/akuma/providers/pi/events.js +17 -3
  45. package/build/src/akuma/providers/unified-patch.d.ts +4 -0
  46. package/build/src/akuma/providers/unified-patch.js +14 -0
  47. package/build/src/akuma/publication.d.ts +1 -1
  48. package/build/src/akuma/publication.js +36 -7
  49. package/build/src/akuma/requests.d.ts +70 -4
  50. package/build/src/akuma/requests.js +288 -77
  51. package/build/src/akuma-body.d.ts +1 -0
  52. package/build/src/akuma-body.js +31 -0
  53. package/build/src/cli/accepted.d.ts +4 -1
  54. package/build/src/cli/accepted.js +26 -4
  55. package/build/src/cli/commands/akuma-invoke.d.ts +8 -7
  56. package/build/src/cli/commands/akuma-invoke.js +18 -10
  57. package/build/src/cli/commands/akuma.d.ts +11 -2
  58. package/build/src/cli/commands/akuma.js +67 -28
  59. package/build/src/cli/commands/amend.d.ts +1 -1
  60. package/build/src/cli/commands/amend.js +1 -1
  61. package/build/src/cli/commands/contract.d.ts +3 -3
  62. package/build/src/cli/commands/contract.js +1 -1
  63. package/build/src/cli/commands/install.js +4 -4
  64. package/build/src/cli/commands/task-query.d.ts +1 -1
  65. package/build/src/cli/commands/task-query.js +11 -5
  66. package/build/src/cli/commands/task.js +4 -4
  67. package/build/src/cli/coordinates.d.ts +1 -0
  68. package/build/src/cli/coordinates.js +5 -1
  69. package/build/src/cli/invoke.d.ts +1 -0
  70. package/build/src/cli/invoke.js +90 -73
  71. package/build/src/cli/main.d.ts +2 -0
  72. package/build/src/cli/main.js +29 -4
  73. package/build/src/cli/parse.d.ts +1 -0
  74. package/build/src/cli/parse.js +8 -4
  75. package/build/src/cli/render/akuma.d.ts +2 -2
  76. package/build/src/cli/render/akuma.js +84 -13
  77. package/build/src/cli/render/audit.js +16 -2
  78. package/build/src/cli/render/contract.d.ts +2 -0
  79. package/build/src/cli/render/contract.js +203 -36
  80. package/build/src/cli/render/kanshi.js +64 -29
  81. package/build/src/cli/render/receipt.d.ts +2 -1
  82. package/build/src/cli/render/receipt.js +9 -1
  83. package/build/src/cli/render/text.js +3 -1
  84. package/build/src/cli/result.d.ts +38 -3
  85. package/build/src/cli/selectors.d.ts +1 -0
  86. package/build/src/cli/selectors.js +9 -6
  87. package/build/src/cli/usage.d.ts +2 -0
  88. package/build/src/cli/usage.js +4 -0
  89. package/build/src/contract-worktree.js +3 -0
  90. package/build/src/dispatch/index.js +50 -39
  91. package/build/src/git/hooks.d.ts +0 -4
  92. package/build/src/git/hooks.js +0 -36
  93. package/build/src/git/integration.d.ts +2 -6
  94. package/build/src/git/integration.js +8 -8
  95. package/build/src/git/read-observation.js +1 -0
  96. package/build/src/git/reconcile.d.ts +6 -1
  97. package/build/src/git/reconcile.js +55 -9
  98. package/build/src/git/tender.d.ts +19 -4
  99. package/build/src/git/tender.js +44 -13
  100. package/build/src/git/terminal-seal.d.ts +14 -0
  101. package/build/src/git/terminal-seal.js +15 -2
  102. package/build/src/git/workspace.d.ts +1 -0
  103. package/build/src/git/workspace.js +12 -4
  104. package/build/src/index.d.ts +1 -1
  105. package/build/src/kanshi/index.d.ts +1 -1
  106. package/build/src/kanshi/index.js +1 -1
  107. package/build/src/kanshi/read.d.ts +9 -1
  108. package/build/src/kanshi/read.js +91 -37
  109. package/build/src/kanshi/report.d.ts +1 -0
  110. package/build/src/library/address.d.ts +5 -14
  111. package/build/src/library/address.js +20 -22
  112. package/build/src/library/akuma-creation.d.ts +4 -2
  113. package/build/src/library/akuma-creation.js +43 -26
  114. package/build/src/library/bind.js +3 -3
  115. package/build/src/library/catalog.d.ts +1 -2
  116. package/build/src/library/catalog.js +11 -6
  117. package/build/src/library/configuration.d.ts +4 -0
  118. package/build/src/library/configuration.js +19 -0
  119. package/build/src/library/contract.d.ts +15 -1
  120. package/build/src/library/contract.js +51 -4
  121. package/build/src/library/fleet.d.ts +47 -9
  122. package/build/src/library/fleet.js +184 -44
  123. package/build/src/library/input.js +1 -0
  124. package/build/src/library/keiyaku.d.ts +4 -4
  125. package/build/src/library/keiyaku.js +1 -2
  126. package/build/src/protocol/bind.d.ts +1 -2
  127. package/build/src/protocol/bind.js +2 -16
  128. package/build/src/protocol/operations.d.ts +4 -1
  129. package/build/src/protocol/operations.js +33 -27
  130. package/build/src/protocol/read/status.d.ts +3 -1
  131. package/build/src/protocol/read/status.js +24 -14
  132. package/build/src/runtime/proc/run.d.ts +1 -0
  133. package/build/src/runtime/proc/run.js +9 -2
  134. package/build/src/settlement/settle.d.ts +1 -0
  135. package/build/src/settlement/settle.js +4 -1
  136. package/build/src/task/board.d.ts +18 -3
  137. package/build/src/task/board.js +73 -26
  138. package/build/src/task/index.d.ts +3 -3
  139. package/build/src/task/index.js +7 -5
  140. package/build/src/task/operations.d.ts +2 -19
  141. package/build/src/task/operations.js +29 -7
  142. package/build/src/task/query.d.ts +9 -2
  143. package/build/src/task/query.js +32 -64
  144. package/build/src/verification/execution.js +2 -1
  145. package/package.json +3 -1
@@ -9,9 +9,13 @@ export type GatesFromInput = Readonly<{
9
9
  export type RequireBranchesToBeUpToDateFromInput = Readonly<{
10
10
  settings: Settings;
11
11
  }>;
12
+ export type WorktreeHooksFromInput = Readonly<{
13
+ settings: Settings;
14
+ }>;
12
15
  export { SettingsError };
13
16
  export declare function gatesFrom(input: GatesFromInput): readonly Gate[];
14
17
  export declare function requireBranchesToBeUpToDateFrom(input: RequireBranchesToBeUpToDateFromInput): boolean;
18
+ export declare function worktreeHooksFrom(input: WorktreeHooksFromInput): WorktreeHooks;
15
19
  export declare function normalizedWorktreeHooks(value: unknown): WorktreeHooks;
16
20
  export declare const EMPTY_WORKTREE_HOOKS: WorktreeHooks;
17
21
  export declare function worktreeHooksOption(value: unknown): WorktreeHooks;
@@ -76,6 +76,25 @@ export function requireBranchesToBeUpToDateFrom(input) {
76
76
  }
77
77
  return selected.value;
78
78
  }
79
+ export function worktreeHooksFrom(input) {
80
+ if (!record(input))
81
+ throw new TypeError("worktreeHooksFrom input must be an object");
82
+ const view = input.settings.namespace("worktree");
83
+ if (view.kind === "failed")
84
+ namespaceFailure(view);
85
+ for (const entry of view.entries) {
86
+ if (entry.name !== "create" && entry.name !== "destroy") {
87
+ throw new SettingsError(`worktree has unknown entry: ${entry.name}`);
88
+ }
89
+ }
90
+ const selected = (phase) => {
91
+ const entry = view.entries.find((item) => item.name === phase);
92
+ if (entry === undefined)
93
+ return Object.freeze([]);
94
+ return commands(entry.value, `worktree.${phase}`, SettingsError);
95
+ };
96
+ return Object.freeze({ create: selected("create"), destroy: selected("destroy") });
97
+ }
79
98
  export function normalizedWorktreeHooks(value) {
80
99
  if (!record(value))
81
100
  throw new TypeError("hooks must be an object");
@@ -4,6 +4,7 @@ import { type Gate, type WorktreeHooks } from "./configuration.js";
4
4
  import { type ChangeId, type ContractId, type ContractState, type JournalEntry, type SnapshotId } from "../core/facts/types.js";
5
5
  export { AuthorityCorruptionError } from "../core/facts/errors.js";
6
6
  import { type AuditReport, type ContractBoard, type ContractDisposition, type ContractGateCurrent, type ContractGateReport, type ContractObservation, type ContractPhase, type ContractRow, type FactKind, type PlacementStop, type ReconcileReport as ProtocolReconcileReport, type RepositoryScope, type ReviewValue, type VerificationReuse, type VerificationStop, type DeliveryPreparationRefusal } from "../protocol/operations.js";
7
+ import { type Dispatch } from "../dispatch/index.js";
7
8
  import { type SettlementReport } from "../settlement/settle.js";
8
9
  import { type TaskId } from "../task/identity.js";
9
10
  import { Repo, type ReconcileInput } from "./repo.js";
@@ -17,6 +18,18 @@ export type { AuditReport, DeliveryPreparationRefusal, ChangeId, ContractId, Con
17
18
  export type { TaskId };
18
19
  export type { RegionOverlap };
19
20
  export type Fact = JournalEntry;
21
+ export type ContractHistoryEvent = Readonly<{
22
+ source: "journal";
23
+ fact: Fact;
24
+ }> | Readonly<{
25
+ source: "dispatch";
26
+ dispatch: Dispatch;
27
+ }>;
28
+ export type ContractHistory = Readonly<{
29
+ id: ContractId;
30
+ state: SnapshotId;
31
+ events: readonly ContractHistoryEvent[];
32
+ }>;
20
33
  export type ActorId = string;
21
34
  export type AttestationVerdict = "satisfied" | "unsatisfied";
22
35
  export type Review = ReviewValue;
@@ -49,7 +62,7 @@ export type BindInput = Readonly<{
49
62
  hooks?: WorktreeHooks;
50
63
  }>;
51
64
  export type AmendInput = Readonly<{
52
- markdown: string;
65
+ markdown?: string;
53
66
  actor?: ActorId;
54
67
  after?: readonly ContractId[];
55
68
  gates?: readonly Gate[];
@@ -96,6 +109,7 @@ export declare class KeiyakuHandle {
96
109
  private readonly scope;
97
110
  constructor(id: ContractId, scope: RepositoryScope);
98
111
  state(): Promise<ContractState>;
112
+ history(): Promise<ContractHistory>;
99
113
  guidance(): Promise<string>;
100
114
  delivery(): Promise<Delivery | null>;
101
115
  amend(input: AmendInput): Promise<AmendResult>;
@@ -9,7 +9,10 @@ import { worktreeHooksOption } from "./configuration.js";
9
9
  import { contractId, } from "../core/facts/types.js";
10
10
  export { AuthorityCorruptionError } from "../core/facts/errors.js";
11
11
  import { abandonOperation, amendOperation, arcOperation, contractObservationOperation, contractsOperation, deliveryDiffOperation, deliverOperation, deliveryOperation, reviewOperation, stateOperation, } from "../protocol/operations.js";
12
- import { withGitDecodeChannel } from "../git/read-observation.js";
12
+ import { readDispatchesAt } from "../dispatch/index.js";
13
+ import { mintSnapshotId } from "../git/identity.js";
14
+ import { observeContractsForAdmissionInObservationAt } from "../git/observe.js";
15
+ import { withGitDecodeChannel, withGitReadObservation } from "../git/read-observation.js";
13
16
  import { claimTaskHolderWithFence, releaseTaskHolder, releaseTaskHolderWithFence, taskHolderObservationSelection, } from "../settlement/holder.js";
14
17
  import { parseTaskId } from "../task/identity.js";
15
18
  import { reconcileInput, scopeForRepo } from "./repo.js";
@@ -53,6 +56,38 @@ export class KeiyakuHandle {
53
56
  contractId: this.id,
54
57
  }));
55
58
  }
59
+ async history() {
60
+ return withGitDecodeChannel(this.scope, (channel) => withGitReadObservation(this.scope, channel, async (observation) => {
61
+ const [journals, dispatches] = await Promise.all([
62
+ observeContractsForAdmissionInObservationAt(observation, [this.id]),
63
+ readDispatchesAt(observation),
64
+ ]);
65
+ const record = journals.journals.get(this.id);
66
+ if (record === undefined)
67
+ throw new Error(`missing requested contract observation: ${this.id}`);
68
+ if (record.state === null)
69
+ throw new KeiyakuRefused({ kind: "contract-missing", contractId: this.id });
70
+ const commit = observation.snapshot.commit;
71
+ if (commit === null)
72
+ throw new Error("contract history requires a keiyaku-state snapshot");
73
+ const recordedAt = (event) => (event.source === "journal" ? event.fact.at : event.dispatch.dispatchedAt);
74
+ const events = [
75
+ ...record.entries.map((fact) => ({ source: "journal", fact })),
76
+ ...dispatches
77
+ .filter((dispatch) => dispatch.contractId === this.id)
78
+ .map((dispatch) => ({ source: "dispatch", dispatch })),
79
+ ].sort((left, right) => {
80
+ const leftAt = recordedAt(left);
81
+ const rightAt = recordedAt(right);
82
+ if (leftAt !== rightAt)
83
+ return leftAt < rightAt ? -1 : 1;
84
+ if (left.source !== right.source)
85
+ return left.source === "journal" ? -1 : 1;
86
+ return 0;
87
+ });
88
+ return { id: this.id, state: mintSnapshotId(commit), events };
89
+ }));
90
+ }
56
91
  async guidance() {
57
92
  return withGitDecodeChannel(this.scope, async (channel) => {
58
93
  const observed = await contractObservationOperation({ scope: this.scope, channel, contractId: this.id });
@@ -74,12 +109,15 @@ export class KeiyakuHandle {
74
109
  async amend(input) {
75
110
  const values = requireInput(input, "amend input");
76
111
  const hooks = worktreeHooksOption(values.hooks);
77
- const markdown = requireMarkdown(values.markdown);
112
+ const markdown = values.markdown === undefined ? undefined : requireMarkdown(values.markdown);
78
113
  const actor = actorOption(values.actor);
79
114
  const gates = values.gates === undefined ? undefined : normalizedGates(values.gates);
80
115
  const prerequisites = values.after === undefined
81
116
  ? undefined
82
117
  : normalizedList(values.after, "after", contractId);
118
+ if (markdown === undefined && gates === undefined && prerequisites === undefined) {
119
+ throw new TypeError("amend requires markdown, after, or gates");
120
+ }
83
121
  return withGitDecodeChannel(this.scope, async (channel) => {
84
122
  const accepted = requireAccepted(await amendOperation({
85
123
  scope: this.scope,
@@ -87,8 +125,17 @@ export class KeiyakuHandle {
87
125
  contractId: this.id,
88
126
  ...actor,
89
127
  deriveAmendment: (source) => {
90
- const document = decodeContractDocument(applyAmendDocument(markdown, decodeContractDocument(source.document.bytes)));
91
- const terms = contractTerms(document, gates ?? source.gates, prerequisites ?? source.after);
128
+ const document = markdown === undefined
129
+ ? decodeContractDocument(source.document.bytes)
130
+ : decodeContractDocument(applyAmendDocument(markdown, decodeContractDocument(source.document.bytes)));
131
+ const terms = markdown === undefined
132
+ ? {
133
+ document: source.document,
134
+ segments: source.segments,
135
+ gates: gates ?? source.gates,
136
+ after: prerequisites ?? source.after,
137
+ }
138
+ : contractTerms(document, gates ?? source.gates, prerequisites ?? source.after);
92
139
  return {
93
140
  terms,
94
141
  verification: documentDerivation(document, terms.gates, this.id).verification,
@@ -1,23 +1,34 @@
1
1
  import { type ActivityHistory, type AkumaStatus, type InterruptReceipt, type KillEvidence, type TellResult } from "../akuma/index.js";
2
2
  import type { ContractId } from "../core/facts/types.js";
3
+ import type { TaskRow } from "../task/index.js";
4
+ import type { WorldRoot } from "../world.js";
3
5
  import { type AkumaAddressInput, type AkumaSetAddressInput } from "./address.js";
6
+ import { type Repo } from "./repo.js";
7
+ export type CreatedTaskObservation = Readonly<{
8
+ kind: "present";
9
+ rows: readonly TaskRow[];
10
+ }> | Readonly<{
11
+ kind: "failed";
12
+ diagnostic: string;
13
+ }>;
14
+ export type AkumaObservation = Readonly<{
15
+ status: AkumaStatus;
16
+ contractId?: ContractId;
17
+ createdTasks: CreatedTaskObservation;
18
+ }>;
4
19
  export type AkumaWaitInput = AkumaSetAddressInput & Readonly<{
5
20
  completion?: "any" | "all";
6
21
  timeoutMs?: number;
7
22
  }>;
8
23
  export type AkumaWaitResult = Readonly<{
9
24
  completion: "any" | "all";
10
- statuses: readonly AkumaStatusView[];
11
- }>;
12
- export type AkumaStatusView = Readonly<{
13
- status: AkumaStatus;
14
- contractId?: ContractId;
25
+ observations: readonly AkumaObservation[];
15
26
  }>;
16
27
  export type AkumaKillResult = Readonly<{
17
28
  results: readonly Readonly<{
18
29
  id: AkumaStatus["id"];
19
30
  evidence: KillEvidence;
20
- observation: AkumaStatusView;
31
+ observation: AkumaObservation;
21
32
  }>[];
22
33
  }>;
23
34
  export type AkumaTellInput = AkumaAddressInput & Readonly<{
@@ -26,7 +37,7 @@ export type AkumaTellInput = AkumaAddressInput & Readonly<{
26
37
  export type AkumaTellResult = Readonly<{
27
38
  akuma: AkumaStatus["id"];
28
39
  tell: TellResult;
29
- observation: AkumaStatusView;
40
+ observation: AkumaObservation;
30
41
  }>;
31
42
  export type AkumaInterruptInput = AkumaAddressInput & Readonly<{
32
43
  body: string;
@@ -34,7 +45,7 @@ export type AkumaInterruptInput = AkumaAddressInput & Readonly<{
34
45
  export type AkumaInterruptResult = Readonly<{
35
46
  id: AkumaStatus["id"];
36
47
  receipt: InterruptReceipt;
37
- observation: AkumaStatusView;
48
+ observation: AkumaObservation;
38
49
  }>;
39
50
  export type AkumaHistoryInput = AkumaAddressInput & Readonly<{
40
51
  before?: number;
@@ -57,9 +68,36 @@ export type AkumaHistoryResult = Readonly<{
57
68
  id: AkumaStatus["id"];
58
69
  contractId?: ContractId;
59
70
  }>;
60
- export declare function statusAkuma(input: AkumaAddressInput): Promise<AkumaStatusView>;
71
+ type WaitExecutionInput = Readonly<{
72
+ path: WorldRoot;
73
+ ids: readonly AkumaStatus["id"][];
74
+ completion: "any" | "all";
75
+ timeoutMs?: number;
76
+ repo?: Repo;
77
+ signal?: AbortSignal;
78
+ }>;
79
+ export declare function executeWaitAkuma(input: WaitExecutionInput): Promise<AkumaWaitResult>;
80
+ type TellExecutionInput = Readonly<{
81
+ path: WorldRoot;
82
+ id: AkumaStatus["id"];
83
+ body: string;
84
+ tellId?: string;
85
+ recordedAt?: string;
86
+ repo?: Repo;
87
+ signal?: AbortSignal;
88
+ }>;
89
+ export declare function executeTellAkuma(input: TellExecutionInput): Promise<AkumaTellResult>;
90
+ type KillExecutionInput = Readonly<{
91
+ path: WorldRoot;
92
+ ids: readonly AkumaStatus["id"][];
93
+ repo?: Repo;
94
+ signal?: AbortSignal;
95
+ }>;
96
+ export declare function executeKillAkuma(input: KillExecutionInput): Promise<AkumaKillResult>;
97
+ export declare function statusAkuma(input: AkumaAddressInput): Promise<AkumaObservation>;
61
98
  export declare function waitAkuma(input: AkumaWaitInput): Promise<AkumaWaitResult>;
62
99
  export declare function killAkuma(input: AkumaSetAddressInput): Promise<AkumaKillResult>;
63
100
  export declare function tellAkuma(input: AkumaTellInput): Promise<AkumaTellResult>;
64
101
  export declare function interruptAkuma(input: AkumaInterruptInput): Promise<AkumaInterruptResult>;
65
102
  export declare function historyAkuma(input: AkumaHistoryInput): Promise<AkumaHistoryResult>;
103
+ export {};
@@ -1,19 +1,45 @@
1
- import { Akuma, } from "../akuma/index.js";
2
- import { readActionFeedbackStatus, readBudgetedStatus } from "../akuma/akuma.js";
1
+ import { Akuma, AkumaNotBornError, } from "../akuma/index.js";
2
+ import { readBudgetedStatus, tellAkumaWithId } from "../akuma/akuma.js";
3
+ import { injectedBodyRequests, requestBodyKill, requestBodyTell, requestBodyWait, } from "../akuma/requests.js";
3
4
  import { readDispatch } from "../dispatch/index.js";
5
+ import { observeTaskBoard } from "../task/operations.js";
4
6
  import { addressAkuma, addressAkumaSet } from "./address.js";
5
7
  import { requireInput } from "./input.js";
6
8
  import { scopeForRepo } from "./repo.js";
7
- function source(path, settings) {
8
- return Akuma.of(path, settings);
9
+ function source(path) {
10
+ return Akuma.of(path);
9
11
  }
10
12
  async function contractFor(repo, id) {
11
13
  const dispatch = repo === undefined ? null : await readDispatch(scopeForRepo(repo), id);
12
14
  return dispatch?.contractId;
13
15
  }
14
- async function statusView(status, repo) {
15
- const contractId = await contractFor(repo, status.id);
16
- return contractId === undefined ? { status } : { status, contractId };
16
+ function createdTaskDiagnostic(error) {
17
+ return error instanceof Error ? error.message : String(error);
18
+ }
19
+ async function createdTasksFor(path, statuses) {
20
+ let board;
21
+ try {
22
+ board = await observeTaskBoard(path);
23
+ }
24
+ catch (error) {
25
+ const failed = { kind: "failed", diagnostic: createdTaskDiagnostic(error) };
26
+ return statuses.map(() => failed);
27
+ }
28
+ return statuses.map((status) => ({ kind: "present", rows: board.selectCreatedBy(status.id) }));
29
+ }
30
+ async function observeAkuma(status, path, repo) {
31
+ return (await observeAkumaSet([status], path, repo))[0];
32
+ }
33
+ async function observeAkumaSet(statuses, path, repo) {
34
+ const created = await createdTasksFor(path, statuses);
35
+ return await Promise.all(statuses.map(async (status, index) => {
36
+ const contractId = await contractFor(repo, status.id);
37
+ return {
38
+ status,
39
+ createdTasks: created[index],
40
+ ...(contractId === undefined ? {} : { contractId }),
41
+ };
42
+ }));
17
43
  }
18
44
  function timeout(value) {
19
45
  if (value === undefined)
@@ -23,28 +49,119 @@ function timeout(value) {
23
49
  }
24
50
  return value;
25
51
  }
26
- function delay(milliseconds) {
27
- return new Promise((resolve) => setTimeout(resolve, milliseconds));
52
+ function delay(milliseconds, signal) {
53
+ return new Promise((resolve, reject) => {
54
+ let timer;
55
+ const done = () => {
56
+ signal?.removeEventListener("abort", abort);
57
+ resolve();
58
+ };
59
+ const abort = () => {
60
+ clearTimeout(timer);
61
+ signal?.removeEventListener("abort", abort);
62
+ reject(signal?.reason ?? new Error("upstream request aborted"));
63
+ };
64
+ timer = setTimeout(done, milliseconds);
65
+ if (signal?.aborted)
66
+ abort();
67
+ else
68
+ signal?.addEventListener("abort", abort, { once: true });
69
+ });
28
70
  }
29
71
  const SHARED_ORDINARY_BUDGET = 30;
30
- async function observeWaitStatuses(path, ids, settings) {
72
+ async function observeWaitStatuses(path, ids, signal) {
73
+ signal?.throwIfAborted();
31
74
  if (ids.length <= 1) {
32
- return await Promise.all(ids.map(async (id) => await source(path, settings).of({ id }).status()));
75
+ return await Promise.all(ids.map(async (id) => await source(path).of({ id }).status()));
33
76
  }
34
77
  let remaining = SHARED_ORDINARY_BUDGET;
35
78
  const statuses = [];
36
79
  for (const id of ids) {
80
+ signal?.throwIfAborted();
37
81
  const observed = await readBudgetedStatus(path, id, { ordinaryBudget: remaining });
38
82
  statuses.push(observed.status);
39
83
  remaining -= observed.ordinarySelected;
40
84
  }
41
85
  return statuses;
42
86
  }
87
+ export async function executeWaitAkuma(input) {
88
+ const deadline = input.timeoutMs === undefined ? undefined : performance.now() + input.timeoutMs;
89
+ for (;;) {
90
+ const statuses = await observeWaitStatuses(input.path, input.ids, input.signal);
91
+ const settled = statuses.map((status) => status.life !== "running");
92
+ if ((input.completion === "any" ? settled.some(Boolean) : settled.every(Boolean))
93
+ || (deadline !== undefined && performance.now() >= deadline)) {
94
+ return {
95
+ completion: input.completion,
96
+ observations: await observeAkumaSet(statuses, input.path, input.repo),
97
+ };
98
+ }
99
+ await delay(deadline === undefined ? 25 : Math.min(25, Math.max(0, deadline - performance.now())), input.signal);
100
+ }
101
+ }
102
+ export async function executeTellAkuma(input) {
103
+ input.signal?.throwIfAborted();
104
+ const handle = source(input.path).of({ id: input.id });
105
+ const tell = input.tellId === undefined
106
+ ? await handle.tell(input.body)
107
+ : await tellAkumaWithId(input.path, input.id, input.body, input.tellId, input.recordedAt);
108
+ input.signal?.throwIfAborted();
109
+ return {
110
+ akuma: input.id,
111
+ tell,
112
+ observation: await observeAkuma(await handle.status(), input.path, input.repo),
113
+ };
114
+ }
115
+ export async function executeKillAkuma(input) {
116
+ input.signal?.throwIfAborted();
117
+ const handles = input.ids.map((id) => source(input.path).of({ id }));
118
+ const evidence = await Promise.all(handles.map(async (handle) => await handle.kill()));
119
+ input.signal?.throwIfAborted();
120
+ const statuses = await Promise.all(input.ids.map(async (id) => await source(input.path).of({ id }).status()));
121
+ const observations = await observeAkumaSet(statuses, input.path, input.repo);
122
+ return {
123
+ results: input.ids.map((id, index) => ({ id, evidence: evidence[index], observation: observations[index] })),
124
+ };
125
+ }
126
+ function upstreamResult(outcome) {
127
+ if (outcome.kind === "returned")
128
+ return outcome.result;
129
+ if (outcome.failure.kind === "akuma-not-born")
130
+ throw new AkumaNotBornError(outcome.failure.id);
131
+ throw new Error(outcome.failure.diagnostic);
132
+ }
133
+ async function attachContract(repo, observation) {
134
+ if (repo === undefined || observation.contractId !== undefined)
135
+ return observation;
136
+ const contractId = await contractFor(repo, observation.status.id);
137
+ return contractId === undefined ? observation : { ...observation, contractId };
138
+ }
139
+ async function attachWaitContracts(repo, result) {
140
+ return repo === undefined
141
+ ? result
142
+ : {
143
+ ...result,
144
+ observations: await Promise.all(result.observations.map((observation) => attachContract(repo, observation))),
145
+ };
146
+ }
147
+ async function attachTellContract(repo, result) {
148
+ return repo === undefined ? result : { ...result, observation: await attachContract(repo, result.observation) };
149
+ }
150
+ async function attachKillContracts(repo, result) {
151
+ return repo === undefined
152
+ ? result
153
+ : {
154
+ ...result,
155
+ results: await Promise.all(result.results.map(async (entry) => ({
156
+ ...entry,
157
+ observation: await attachContract(repo, entry.observation),
158
+ }))),
159
+ };
160
+ }
43
161
  function directAddress(values) {
44
162
  return {
45
163
  path: values.path,
46
164
  akuma: values.akuma,
47
- ...(values.settings === undefined ? {} : { settings: values.settings }),
48
165
  ...(values.repo === undefined ? {} : { repo: values.repo }),
49
166
  };
50
167
  }
@@ -52,18 +169,17 @@ function setAddress(values) {
52
169
  return {
53
170
  path: values.path,
54
171
  akuma: values.akuma,
55
- ...(values.settings === undefined ? {} : { settings: values.settings }),
56
172
  ...(values.repo === undefined ? {} : { repo: values.repo }),
57
173
  };
58
174
  }
59
175
  export async function statusAkuma(input) {
60
176
  const addressed = await addressAkuma(input);
61
- return await statusView(await source(addressed.path, addressed.settings).of({ id: addressed.id }).status(), input.repo);
177
+ return await observeAkuma(await source(addressed.path).of({ id: addressed.id }).status(), addressed.path, input.repo);
62
178
  }
63
179
  export async function waitAkuma(input) {
64
180
  const values = requireInput(input, "Keiyaku.wait input");
65
181
  for (const key of Object.keys(values)) {
66
- if (!["path", "akuma", "settings", "repo", "completion", "timeoutMs"].includes(key)) {
182
+ if (!["path", "akuma", "repo", "completion", "timeoutMs"].includes(key)) {
67
183
  throw new TypeError(`Keiyaku.wait input has unknown field: ${key}`);
68
184
  }
69
185
  }
@@ -72,70 +188,94 @@ export async function waitAkuma(input) {
72
188
  if (addressed.ids.length > 1 && completion !== "any" && completion !== "all") {
73
189
  throw new TypeError("completion must be any or all when waiting for multiple Akuma");
74
190
  }
75
- if (completion !== undefined && completion !== "any" && completion !== "all")
191
+ if (completion !== undefined && completion !== "any" && completion !== "all") {
76
192
  throw new TypeError("completion must be any or all");
193
+ }
77
194
  const selected = completion ?? "all";
78
195
  const timeoutMs = timeout(values.timeoutMs);
79
- const deadline = timeoutMs === undefined ? undefined : performance.now() + timeoutMs;
80
- for (;;) {
81
- const statuses = await observeWaitStatuses(addressed.path, addressed.ids, addressed.settings);
82
- const settled = statuses.map((status) => status.life !== "running");
83
- if ((selected === "any" ? settled.some(Boolean) : settled.every(Boolean))
84
- || (deadline !== undefined && performance.now() >= deadline)) {
85
- return { completion: selected, statuses: await Promise.all(statuses.map(async (status) => await statusView(status, values.repo))) };
86
- }
87
- await delay(deadline === undefined ? 25 : Math.min(25, Math.max(0, deadline - performance.now())));
196
+ const requests = injectedBodyRequests();
197
+ if (requests !== null) {
198
+ const outcome = await requestBodyWait({
199
+ directory: requests,
200
+ targets: addressed.ids,
201
+ completion: selected,
202
+ ...(timeoutMs === undefined ? {} : { timeoutMs }),
203
+ });
204
+ return await attachWaitContracts(values.repo, upstreamResult(outcome));
88
205
  }
206
+ return await executeWaitAkuma({
207
+ path: addressed.path,
208
+ ids: addressed.ids,
209
+ completion: selected,
210
+ ...(timeoutMs === undefined ? {} : { timeoutMs }),
211
+ ...(values.repo === undefined ? {} : { repo: values.repo }),
212
+ });
89
213
  }
90
214
  export async function killAkuma(input) {
91
215
  const addressed = await addressAkumaSet(input);
92
- const handles = addressed.ids.map((id) => source(addressed.path, addressed.settings).of({ id }));
93
- const evidence = await Promise.all(handles.map(async (handle) => await handle.kill()));
94
- const observations = await Promise.all(addressed.ids.map(async (id) => await statusView(await readActionFeedbackStatus(addressed.path, id), input.repo)));
95
- return {
96
- results: addressed.ids.map((id, index) => ({
97
- id,
98
- evidence: evidence[index],
99
- observation: observations[index],
100
- })),
101
- };
216
+ const requests = injectedBodyRequests();
217
+ if (requests !== null) {
218
+ const outcome = await requestBodyKill({ directory: requests, targets: addressed.ids });
219
+ return await attachKillContracts(input.repo, upstreamResult(outcome));
220
+ }
221
+ return await executeKillAkuma({
222
+ path: addressed.path,
223
+ ids: addressed.ids,
224
+ ...(input.repo === undefined ? {} : { repo: input.repo }),
225
+ });
102
226
  }
103
227
  export async function tellAkuma(input) {
104
228
  const values = requireInput(input, "Keiyaku.tell input");
105
229
  for (const key of Object.keys(values)) {
106
- if (!["path", "akuma", "settings", "body", "repo"].includes(key))
230
+ if (!["path", "akuma", "body", "repo"].includes(key)) {
107
231
  throw new TypeError(`Keiyaku.tell input has unknown field: ${key}`);
232
+ }
108
233
  }
109
234
  if (typeof values.body !== "string")
110
235
  throw new TypeError("body must be a string");
111
236
  const addressed = await addressAkuma(directAddress(values));
112
- const handle = source(addressed.path, addressed.settings).of({ id: addressed.id });
113
- const tell = await handle.tell(values.body);
114
- return { akuma: addressed.id, tell, observation: await statusView(await readActionFeedbackStatus(addressed.path, addressed.id), values.repo) };
237
+ const requests = injectedBodyRequests();
238
+ if (requests !== null) {
239
+ const outcome = await requestBodyTell({
240
+ directory: requests,
241
+ target: addressed.id,
242
+ body: values.body,
243
+ });
244
+ return await attachTellContract(values.repo, upstreamResult(outcome));
245
+ }
246
+ return await executeTellAkuma({
247
+ path: addressed.path,
248
+ id: addressed.id,
249
+ body: values.body,
250
+ ...(values.repo === undefined ? {} : { repo: values.repo }),
251
+ });
115
252
  }
116
253
  export async function interruptAkuma(input) {
117
254
  const values = requireInput(input, "Keiyaku.interrupt input");
118
255
  for (const key of Object.keys(values)) {
119
- if (!["path", "akuma", "settings", "body", "repo"].includes(key))
256
+ if (!["path", "akuma", "body", "repo"].includes(key)) {
120
257
  throw new TypeError(`Keiyaku.interrupt input has unknown field: ${key}`);
258
+ }
121
259
  }
122
260
  if (typeof values.body !== "string")
123
261
  throw new TypeError("body must be a string");
124
262
  const addressed = await addressAkuma(directAddress(values));
125
- const receipt = await source(addressed.path, addressed.settings).of({ id: addressed.id }).interrupt(values.body);
126
- return { id: addressed.id, receipt, observation: await statusView(await readActionFeedbackStatus(addressed.path, addressed.id), values.repo) };
263
+ const handle = source(addressed.path).of({ id: addressed.id });
264
+ const receipt = await handle.interrupt(values.body);
265
+ const observation = await observeAkuma(await handle.status(), addressed.path, values.repo);
266
+ return { id: addressed.id, receipt, observation };
127
267
  }
128
268
  export async function historyAkuma(input) {
129
269
  const values = requireInput(input, "Keiyaku.history input");
130
270
  for (const key of Object.keys(values)) {
131
- if (!["path", "akuma", "settings", "before", "since", "limit", "last", "repo"].includes(key)) {
271
+ if (!["path", "akuma", "before", "since", "limit", "last", "repo"].includes(key)) {
132
272
  throw new TypeError(`Keiyaku.history input has unknown field: ${key}`);
133
273
  }
134
274
  }
135
275
  if (values.last !== undefined && typeof values.last !== "boolean")
136
276
  throw new TypeError("last must be a boolean");
137
277
  const addressed = await addressAkuma(directAddress(values));
138
- const handle = source(addressed.path, addressed.settings).of({ id: addressed.id });
278
+ const handle = source(addressed.path).of({ id: addressed.id });
139
279
  if (values.last === true) {
140
280
  const answer = await handle.lastAnswer();
141
281
  const contractId = await contractFor(values.repo, addressed.id);
@@ -91,6 +91,7 @@ export function contractTerms(document, gates, after) {
91
91
  export function documentDerivation(document, gates, contractId) {
92
92
  return {
93
93
  document: document.document.key,
94
+ bytes: document.document.bytes,
94
95
  title: document.title,
95
96
  verification: prepareVerificationDeclaration({
96
97
  gates,
@@ -5,10 +5,9 @@ import { listCatalog } from "./catalog.js";
5
5
  export { AuthorityCorruptionError } from "../core/facts/errors.js";
6
6
  export { Delivery, KeiyakuRefused, KeiyakuRetry, } from "./contract.js";
7
7
  export { NoGitWorldError, Repo } from "./repo.js";
8
- export { gatesFrom, requireBranchesToBeUpToDateFrom, SettingsError, } from "./configuration.js";
9
- export { worktreeHooksFrom } from "../git/hooks.js";
8
+ export { gatesFrom, requireBranchesToBeUpToDateFrom, SettingsError, worktreeHooksFrom, } from "./configuration.js";
10
9
  export { AkumaWorldScopeError } from "./address.js";
11
- export type { AbandonInput, ActorId, AmendInput, AmendResult, ArcInput, AttestationVerdict, AuditInput, AuditReport, DeliveryPreparationRefusal, BindInput, BindResult, ContractBoard, ContractDisposition, ContractGateCurrent, ContractGateReport, ContractListInput, ContractObservation, ContractObservationInput, ContractPhase, ContractRow, DeliverInput, Fact, FactKind, KeiyakuOfInput, KeiyakuRefusal, KeiyakuRetryReason, Lag, MutationResult, PlacementStop, ReconcileReport, Review, ReviewInput, TaskId, TopologyEffect, VerificationReuse, VerificationStop, } from "./contract.js";
10
+ export type { AbandonInput, ActorId, AmendInput, AmendResult, ArcInput, AttestationVerdict, AuditInput, AuditReport, DeliveryPreparationRefusal, BindInput, BindResult, ContractBoard, ContractDisposition, ContractGateCurrent, ContractGateReport, ContractHistory, ContractHistoryEvent, ContractListInput, ContractObservation, ContractObservationInput, ContractPhase, ContractRow, DeliverInput, Fact, FactKind, KeiyakuOfInput, KeiyakuRefusal, KeiyakuRetryReason, Lag, MutationResult, PlacementStop, ReconcileReport, Review, ReviewInput, TaskId, TopologyEffect, VerificationReuse, VerificationStop, } from "./contract.js";
12
11
  export type { ContractId, ContractState, ChangeId, SnapshotId, } from "../core/facts/types.js";
13
12
  export type { Gate, GatesFromInput, HookCommand, RequireBranchesToBeUpToDateFromInput, WorktreeHooks, } from "./configuration.js";
14
13
  export type { RegionOverlap } from "./region.js";
@@ -20,9 +19,10 @@ export type { Dispatch, DispatchFailure } from "../dispatch/index.js";
20
19
  export type { AkumaAlias } from "../identity/selector.js";
21
20
  export type { AkumaGlob } from "../identity/selector.js";
22
21
  export type { AkuId } from "../akuma/identity.js";
22
+ export type { AllowedAction, AllowedActions } from "../akuma/allowed.js";
23
23
  export type { Catalog, CatalogInput, CatalogQuery } from "./catalog.js";
24
24
  export type { AkumaAddressInput, AkumaSetAddressInput, AkumaWorldScopeRefusal, DirectAkumaSelector, SetAkumaSelector, } from "./address.js";
25
- export type { AkumaHistoryInput, AkumaHistoryResult, AkumaInterruptInput, AkumaInterruptResult, AkumaKillResult, AkumaStatusView, AkumaTellInput, AkumaTellResult, AkumaWaitInput, AkumaWaitResult, } from "./fleet.js";
25
+ export type { AkumaHistoryInput, AkumaHistoryResult, AkumaInterruptInput, AkumaInterruptResult, AkumaKillResult, AkumaObservation, AkumaTellInput, CreatedTaskObservation, AkumaTellResult, AkumaWaitInput, AkumaWaitResult, } from "./fleet.js";
26
26
  export type Keiyaku = KeiyakuType;
27
27
  export declare const Keiyaku: Readonly<{
28
28
  prototype: KeiyakuHandle;
@@ -5,8 +5,7 @@ import { listCatalog } from "./catalog.js";
5
5
  export { AuthorityCorruptionError } from "../core/facts/errors.js";
6
6
  export { Delivery, KeiyakuRefused, KeiyakuRetry, } from "./contract.js";
7
7
  export { NoGitWorldError, Repo } from "./repo.js";
8
- export { gatesFrom, requireBranchesToBeUpToDateFrom, SettingsError, } from "./configuration.js";
9
- export { worktreeHooksFrom } from "../git/hooks.js";
8
+ export { gatesFrom, requireBranchesToBeUpToDateFrom, SettingsError, worktreeHooksFrom, } from "./configuration.js";
10
9
  export { AkumaWorldScopeError } from "./address.js";
11
10
  export const Keiyaku = Object.freeze({
12
11
  prototype: KeiyakuHandle.prototype,
@@ -18,14 +18,13 @@ export type TargetInputRefusal = Readonly<{
18
18
  type BindOperationInput = Readonly<{
19
19
  scope: GitRepository;
20
20
  channel: GitDecodeChannel;
21
- title: string;
22
21
  terms: BindData["terms"];
23
22
  verification: VerificationDeclarationPreparation;
24
23
  target?: string;
25
24
  workspace: "worktree" | "here";
26
25
  actor?: ActorId;
27
26
  decorateOffer?: CompanionDecorator;
28
- contractId?: ContractId;
27
+ contractId: ContractId;
29
28
  }>;
30
29
  export declare function bindOperation(input: BindOperationInput): Promise<IntentOutcome<Readonly<{
31
30
  contractId: ContractId;