@astrosheep/keiyaku 4.5.26 → 4.5.27
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.
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +5 -4
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +16 -14
- package/build/src/akuma/akuma-errors.d.ts +6 -0
- package/build/src/akuma/akuma-errors.js +11 -0
- package/build/src/akuma/akuma-handle.d.ts +53 -1
- package/build/src/akuma/akuma-handle.js +75 -7
- package/build/src/akuma/akuma-instance.js +6 -22
- package/build/src/akuma/akuma-probe.d.ts +20 -1
- package/build/src/akuma/akuma-probe.js +20 -3
- package/build/src/akuma/akuma.d.ts +12 -0
- package/build/src/akuma/allowed.d.ts +2 -1
- package/build/src/akuma/allowed.js +9 -4
- package/build/src/akuma/archetype.js +3 -3
- package/build/src/akuma/body.js +8 -3
- package/build/src/akuma/fleet-execution.d.ts +6 -1
- package/build/src/akuma/fleet-execution.js +44 -0
- package/build/src/akuma/fleet-observation.d.ts +238 -0
- package/build/src/akuma/fleet-observation.js +13 -0
- package/build/src/akuma/fleet-owner-port.d.ts +12 -0
- package/build/src/akuma/fleet-owner-port.js +46 -0
- package/build/src/akuma/fleet-request.d.ts +55 -4
- package/build/src/akuma/fleet-request.js +101 -6
- package/build/src/akuma/heart/index.d.ts +1 -0
- package/build/src/akuma/heart/index.js +4 -1
- package/build/src/akuma/heart/rows.d.ts +1 -0
- package/build/src/akuma/heart/rows.js +8 -0
- package/build/src/akuma/heart/soul.js +2 -2
- package/build/src/akuma/projection.d.ts +36 -0
- package/build/src/akuma/projection.js +2 -1
- package/build/src/akuma/provider.d.ts +14 -0
- package/build/src/akuma/provider.js +66 -4
- package/build/src/akuma/providers/acp/events.js +16 -8
- package/build/src/akuma/providers/claude/events.js +5 -7
- package/build/src/akuma/providers/opencode-sdk/events.js +9 -5
- package/build/src/akuma/providers/pi/events.js +4 -3
- package/build/src/akuma/request-lifecycle.js +10 -1
- package/build/src/akuma-body.js +1 -33
- package/build/src/cli/commands/akuma-invoke.d.ts +8 -0
- package/build/src/cli/commands/akuma-invoke.js +58 -6
- package/build/src/cli/commands/akuma.d.ts +1 -0
- package/build/src/cli/commands/akuma.js +10 -15
- package/build/src/cli/commands/contract-help.js +8 -5
- package/build/src/cli/render/akuma-activity.d.ts +7 -1
- package/build/src/cli/render/akuma-activity.js +158 -49
- package/build/src/cli/render/akuma-tool.d.ts +5 -0
- package/build/src/cli/render/akuma-tool.js +118 -14
- package/build/src/cli/render/akuma.d.ts +3 -1
- package/build/src/cli/render/akuma.js +34 -2
- package/build/src/cli/render/catalog.js +2 -3
- package/build/src/cli/render/contract-observation.d.ts +1 -0
- package/build/src/cli/render/contract-observation.js +20 -1
- package/build/src/cli/render/contract.js +4 -4
- package/build/src/cli/render/execution-progress.d.ts +1 -0
- package/build/src/cli/render/execution-progress.js +77 -3
- package/build/src/cli/render/kanshi.js +5 -19
- package/build/src/cli/render/terminal.js +3 -1
- package/build/src/cli/runtime.d.ts +6 -0
- package/build/src/cli/runtime.js +35 -17
- package/build/src/core/facts/offer.d.ts +1 -2
- package/build/src/core/verbs/abandon.js +1 -1
- package/build/src/core/verbs/amend.js +1 -1
- package/build/src/core/verbs/arc.js +1 -1
- package/build/src/core/verbs/attestation.js +1 -1
- package/build/src/core/verbs/bind.js +1 -1
- package/build/src/core/verbs/deliver.js +1 -1
- package/build/src/core/verbs/placement.js +1 -1
- package/build/src/core/verbs/reintegrate.js +1 -1
- package/build/src/git/admission.js +18 -7
- package/build/src/identity/coordinates.js +1 -1
- package/build/src/library/address.d.ts +33 -3
- package/build/src/library/address.js +89 -28
- package/build/src/library/composition.d.ts +12 -0
- package/build/src/library/fleet.d.ts +11 -1
- package/build/src/library/fleet.js +138 -48
- package/build/src/library/keiyaku.d.ts +12 -0
- package/build/src/plugin/public.d.ts +2 -0
- package/build/src/runtime/proc/windows-launch.exe +0 -0
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** @architectureCompositionRoot */
|
|
2
2
|
import { readAliases } from "../alias/index.js";
|
|
3
3
|
import { createAkumaProduct } from "../akuma/akuma-product.js";
|
|
4
|
-
import {
|
|
4
|
+
import { akumaAddressability, requireBornAkuma } from "../akuma/akuma-probe.js";
|
|
5
5
|
import { parseAkuId } from "../akuma/identity.js";
|
|
6
6
|
import { contractId } from "../core/facts/types.js";
|
|
7
7
|
import { readDispatches } from "../dispatch/index.js";
|
|
@@ -9,6 +9,16 @@ import { matchesAkumaGlob, parseAkumaAlias, parseAkumaGlob, } from "../identity/
|
|
|
9
9
|
import { World } from "../world.js";
|
|
10
10
|
import { requireInput } from "./input.js";
|
|
11
11
|
import { scopeForRepo } from "./repo.js";
|
|
12
|
+
export class AkumaAddressError extends Error {
|
|
13
|
+
refusal;
|
|
14
|
+
constructor(refusal) {
|
|
15
|
+
super(refusal.kind === "akuma-alias-not-found"
|
|
16
|
+
? `unknown Akuma alias: ${refusal.alias}`
|
|
17
|
+
: `invalid Akuma: ${refusal.selector}`);
|
|
18
|
+
this.refusal = refusal;
|
|
19
|
+
this.name = "AkumaAddressError";
|
|
20
|
+
}
|
|
21
|
+
}
|
|
12
22
|
export class AkumaWorldScopeError extends TypeError {
|
|
13
23
|
refusal;
|
|
14
24
|
constructor(refusal) {
|
|
@@ -22,23 +32,43 @@ function nonblank(value, label) {
|
|
|
22
32
|
throw new TypeError(`${label} must be a nonblank string`);
|
|
23
33
|
return value;
|
|
24
34
|
}
|
|
35
|
+
function parseAddressAlias(selector) {
|
|
36
|
+
try {
|
|
37
|
+
return parseAkumaAlias(selector);
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
if (!(error instanceof TypeError))
|
|
41
|
+
throw error;
|
|
42
|
+
throw new AkumaAddressError({ kind: "invalid-akuma", selector });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function parseAddressId(selector) {
|
|
46
|
+
try {
|
|
47
|
+
return parseAkuId(selector);
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
if (!(error instanceof TypeError))
|
|
51
|
+
throw error;
|
|
52
|
+
throw new AkumaAddressError({ kind: "invalid-akuma", selector });
|
|
53
|
+
}
|
|
54
|
+
}
|
|
25
55
|
async function directId(path, selector) {
|
|
26
56
|
if (selector.startsWith("@")) {
|
|
27
|
-
const alias =
|
|
57
|
+
const alias = parseAddressAlias(selector);
|
|
28
58
|
const resolved = (await readAliases(path)).find((binding) => binding.alias === alias)?.akuId ?? null;
|
|
29
59
|
if (resolved === null)
|
|
30
|
-
throw new
|
|
60
|
+
throw new AkumaAddressError({ kind: "akuma-alias-not-found", alias });
|
|
31
61
|
return resolved;
|
|
32
62
|
}
|
|
33
|
-
return
|
|
63
|
+
return parseAddressId(selector).id;
|
|
34
64
|
}
|
|
35
65
|
export function resolveNamedAddress(input) {
|
|
36
66
|
const selector = nonblank(input.selector, "selector");
|
|
37
67
|
if (selector.startsWith("kei/"))
|
|
38
68
|
return { kind: "contract", id: contractId(selector) };
|
|
39
69
|
if (selector.startsWith("aku/"))
|
|
40
|
-
return { kind: "akuma", id:
|
|
41
|
-
const alias =
|
|
70
|
+
return { kind: "akuma", id: parseAddressId(selector).id };
|
|
71
|
+
const alias = parseAddressAlias(selector);
|
|
42
72
|
const contractMatches = (input.report.contracts.kind === "present" ? input.report.contracts.value.rows : []).filter((row) => row.disposition === "active" &&
|
|
43
73
|
row.workspace === "worktree" &&
|
|
44
74
|
row.worktreePath !== null &&
|
|
@@ -62,9 +92,14 @@ export function resolveNamedAddress(input) {
|
|
|
62
92
|
if (input.aliases.kind === "failed") {
|
|
63
93
|
throw new TypeError("cannot resolve a named selector while Alias authority is failed");
|
|
64
94
|
}
|
|
65
|
-
throw new
|
|
95
|
+
throw new AkumaAddressError({ kind: "akuma-alias-not-found", alias });
|
|
66
96
|
}
|
|
67
|
-
|
|
97
|
+
/**
|
|
98
|
+
* Resolves one selector to a complete identity without proving it born. The
|
|
99
|
+
* caller is a forwarding boundary: the parent Fleet answers for the target, so
|
|
100
|
+
* this process must not read its own Heart files to decide.
|
|
101
|
+
*/
|
|
102
|
+
export async function resolveAkuma(input) {
|
|
68
103
|
const values = requireInput(input, "Akuma address input");
|
|
69
104
|
for (const key of Object.keys(values)) {
|
|
70
105
|
if (!["path", "akuma", "repo"].includes(key)) {
|
|
@@ -74,7 +109,17 @@ export async function addressAkuma(input) {
|
|
|
74
109
|
if (values.repo !== undefined)
|
|
75
110
|
scopeForRepo(values.repo);
|
|
76
111
|
const path = await World.prove(nonblank(values.path, "path"));
|
|
77
|
-
|
|
112
|
+
const id = await directId(path, nonblank(values.akuma, "akuma"));
|
|
113
|
+
return { path, id };
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Resolves one selector against this World, where a local caller is answered
|
|
117
|
+
* for the target's birth by the one addressability normalization.
|
|
118
|
+
*/
|
|
119
|
+
export async function addressAkuma(input) {
|
|
120
|
+
const addressed = await resolveAkuma(input);
|
|
121
|
+
await requireBornAkuma(addressed.path, addressed.id);
|
|
122
|
+
return addressed;
|
|
78
123
|
}
|
|
79
124
|
function parseSetSelector(raw) {
|
|
80
125
|
const selector = nonblank(raw, "akuma selector");
|
|
@@ -83,13 +128,13 @@ function parseSetSelector(raw) {
|
|
|
83
128
|
if (selector.includes("*"))
|
|
84
129
|
return { kind: "glob", value: parseAkumaGlob(selector) };
|
|
85
130
|
if (selector.startsWith("@"))
|
|
86
|
-
return { kind: "alias", value:
|
|
87
|
-
return { kind: "direct", value:
|
|
131
|
+
return { kind: "alias", value: parseAddressAlias(selector) };
|
|
132
|
+
return { kind: "direct", value: parseAddressId(selector).id };
|
|
88
133
|
}
|
|
89
134
|
function hasSelectorKind(selectors, kind) {
|
|
90
135
|
return selectors.some((selector) => selector.kind === kind);
|
|
91
136
|
}
|
|
92
|
-
function addSelectorIds(selector, sources, selected, contractMembers) {
|
|
137
|
+
function addSelectorIds(selector, sources, selected, contractMembers, explicit) {
|
|
93
138
|
if (selector.kind === "contract") {
|
|
94
139
|
for (const dispatch of sources.dispatches) {
|
|
95
140
|
if (dispatch.contractId !== selector.value)
|
|
@@ -108,20 +153,18 @@ function addSelectorIds(selector, sources, selected, contractMembers) {
|
|
|
108
153
|
if (selector.kind === "alias") {
|
|
109
154
|
const id = sources.aliases.get(selector.value);
|
|
110
155
|
if (id === undefined)
|
|
111
|
-
throw new
|
|
156
|
+
throw new AkumaAddressError({ kind: "akuma-alias-not-found", alias: selector.value });
|
|
112
157
|
selected.add(id);
|
|
158
|
+
explicit.add(id);
|
|
113
159
|
return;
|
|
114
160
|
}
|
|
115
161
|
selected.add(selector.value);
|
|
162
|
+
explicit.add(selector.value);
|
|
116
163
|
}
|
|
117
164
|
async function contractMemberInWorld(path, id) {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
catch {
|
|
122
|
-
// A dispatched physical member remains selected when its Heart cannot be read.
|
|
123
|
-
return true;
|
|
124
|
-
}
|
|
165
|
+
// A dispatched physical member stays selected when its Heart cannot be read:
|
|
166
|
+
// the World, not this reader, remains the authority on its membership.
|
|
167
|
+
return (await akumaAddressability(path, id)).kind !== "absent";
|
|
125
168
|
}
|
|
126
169
|
async function refuseForeignContractMembers(path, ids, contractMembers) {
|
|
127
170
|
const foreign = [];
|
|
@@ -132,7 +175,13 @@ async function refuseForeignContractMembers(path, ids, contractMembers) {
|
|
|
132
175
|
if (foreign.length > 0)
|
|
133
176
|
throw new AkumaWorldScopeError({ kind: "akuma-not-in-world", ids: foreign, world: path });
|
|
134
177
|
}
|
|
135
|
-
|
|
178
|
+
function canonicalAkumaOrder(selected) {
|
|
179
|
+
const ids = [...selected].sort((left, right) => Buffer.compare(Buffer.from(left), Buffer.from(right)));
|
|
180
|
+
if (ids.length === 0)
|
|
181
|
+
throw new TypeError("Akuma selector snapshot is empty");
|
|
182
|
+
return ids;
|
|
183
|
+
}
|
|
184
|
+
async function readAkumaSet(input) {
|
|
136
185
|
const values = requireInput(input, "Akuma set address input");
|
|
137
186
|
for (const key of Object.keys(values)) {
|
|
138
187
|
if (!["path", "akuma", "repo"].includes(key)) {
|
|
@@ -157,13 +206,25 @@ export async function addressAkumaSet(input) {
|
|
|
157
206
|
: [];
|
|
158
207
|
const selected = new Set();
|
|
159
208
|
const contractMembers = new Set();
|
|
209
|
+
const explicit = new Set();
|
|
160
210
|
const sources = { fleetIds, aliases, dispatches };
|
|
161
211
|
for (const selector of selectors)
|
|
162
|
-
addSelectorIds(selector, sources, selected, contractMembers);
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
212
|
+
addSelectorIds(selector, sources, selected, contractMembers, explicit);
|
|
213
|
+
return { path, orderedIds: [...selected], ids: canonicalAkumaOrder(selected), contractMembers, explicit };
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Resolves a selector set to complete identities without proving any born. The
|
|
217
|
+
* caller is a forwarding boundary, the parent Fleet owns the answer, and no
|
|
218
|
+
* member's Heart is read here.
|
|
219
|
+
*/
|
|
220
|
+
export async function resolveAkumaSet(input) {
|
|
221
|
+
const resolved = await readAkumaSet(input);
|
|
222
|
+
return { path: resolved.path, ids: resolved.ids, orderedIds: resolved.orderedIds };
|
|
223
|
+
}
|
|
224
|
+
export async function addressAkumaSet(input) {
|
|
225
|
+
const resolved = await readAkumaSet(input);
|
|
226
|
+
for (const id of resolved.explicit)
|
|
227
|
+
await requireBornAkuma(resolved.path, id);
|
|
228
|
+
await refuseForeignContractMembers(resolved.path, resolved.ids, resolved.contractMembers);
|
|
229
|
+
return { path: resolved.path, ids: resolved.ids, orderedIds: resolved.orderedIds };
|
|
169
230
|
}
|
|
@@ -191,6 +191,10 @@ export declare function composeLibrary(context?: ExecutionContext, composition?:
|
|
|
191
191
|
} | {
|
|
192
192
|
kind: "other";
|
|
193
193
|
display: string;
|
|
194
|
+
input?: {
|
|
195
|
+
json: string;
|
|
196
|
+
truncated: boolean;
|
|
197
|
+
} | undefined;
|
|
194
198
|
};
|
|
195
199
|
state: "active";
|
|
196
200
|
truncated?: true | undefined;
|
|
@@ -227,6 +231,10 @@ export declare function composeLibrary(context?: ExecutionContext, composition?:
|
|
|
227
231
|
} | {
|
|
228
232
|
kind: "other";
|
|
229
233
|
display: string;
|
|
234
|
+
input?: {
|
|
235
|
+
json: string;
|
|
236
|
+
truncated: boolean;
|
|
237
|
+
} | undefined;
|
|
230
238
|
};
|
|
231
239
|
state: {
|
|
232
240
|
status: "error" | "ok";
|
|
@@ -317,6 +325,10 @@ export declare function composeLibrary(context?: ExecutionContext, composition?:
|
|
|
317
325
|
} | {
|
|
318
326
|
kind: "other";
|
|
319
327
|
display: string;
|
|
328
|
+
input?: {
|
|
329
|
+
json: string;
|
|
330
|
+
truncated: boolean;
|
|
331
|
+
} | undefined;
|
|
320
332
|
};
|
|
321
333
|
state: {
|
|
322
334
|
status: "error" | "ok";
|
|
@@ -3,8 +3,9 @@ import { type ActivityHistory, type OutcomeRow, type AkumaStatus, type Interrupt
|
|
|
3
3
|
import { type ExecutionContext } from "../akuma/requests.js";
|
|
4
4
|
import type { WaitObserver } from "../akuma/fleet-execution.js";
|
|
5
5
|
import { type DispatchAssociation } from "../dispatch/index.js";
|
|
6
|
+
import { type Schema } from "../akuma/schema.js";
|
|
6
7
|
import { type AkumaAddressInput, type AkumaSetAddressInput } from "./address.js";
|
|
7
|
-
import { type AkumaKillResult, type AkumaObservation, type AkumaObservationStage, type AkumaTellResult, type AkumaWaitResult } from "../akuma/fleet-observation.js";
|
|
8
|
+
import { type AkumaKillResult, type AkumaObservation, type AkumaObservationStage, type AkumaTellResult, type AkumaTellWaitResult, type AkumaWaitResult } from "../akuma/fleet-observation.js";
|
|
8
9
|
export type AkumaWaitInput = AkumaSetAddressInput & Readonly<{
|
|
9
10
|
completion?: "any" | "all";
|
|
10
11
|
timeoutMs?: number;
|
|
@@ -15,6 +16,14 @@ export type AkumaTellInput = AkumaAddressInput & Readonly<{
|
|
|
15
16
|
initiator?: string;
|
|
16
17
|
signal?: AbortSignal;
|
|
17
18
|
}>;
|
|
19
|
+
export type AkumaTellWaitInput = AkumaAddressInput & Readonly<{
|
|
20
|
+
body: string;
|
|
21
|
+
timeoutMs: number;
|
|
22
|
+
schema?: Schema<unknown>;
|
|
23
|
+
interrupt?: boolean;
|
|
24
|
+
initiator?: string;
|
|
25
|
+
signal?: AbortSignal;
|
|
26
|
+
}>;
|
|
18
27
|
export type { TellResult, TellWake } from "../akuma/akuma.js";
|
|
19
28
|
export type { CreatedTaskObservation } from "../task/created-observation.js";
|
|
20
29
|
export type { DispatchAssociation } from "../dispatch/association.js";
|
|
@@ -68,5 +77,6 @@ export declare function statusAkuma(input: AkumaAddressInput): Promise<AkumaObse
|
|
|
68
77
|
export declare function waitAkuma(input: AkumaWaitInput, execution?: ExecutionContext, observer?: WaitObserver): Promise<AkumaWaitResult>;
|
|
69
78
|
export declare function killAkuma(input: AkumaKillInput, execution?: ExecutionContext): Promise<AkumaKillResult>;
|
|
70
79
|
export declare function tellAkuma(input: AkumaTellInput, execution?: ExecutionContext): Promise<AkumaTellResult>;
|
|
80
|
+
export declare function tellWaitAkuma(input: AkumaTellWaitInput, execution?: ExecutionContext): Promise<AkumaTellWaitResult>;
|
|
71
81
|
export declare function interruptAkuma(input: AkumaInterruptInput): Promise<AkumaInterruptResult>;
|
|
72
82
|
export declare function historyAkuma(input: AkumaHistoryInput): Promise<AkumaHistoryResult>;
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
/** @architectureCompositionRoot */
|
|
2
2
|
import { AkumaNotBornError, readBudgetedStatus, withoutReportedChanges, } from "../akuma/akuma.js";
|
|
3
|
+
import { AkumaObservationError } from "../akuma/akuma-errors.js";
|
|
3
4
|
import { createAkumaProduct } from "../akuma/akuma-product.js";
|
|
4
5
|
import { executionChannel, localExecutionContext } from "../akuma/requests.js";
|
|
5
|
-
import { requestForwardedFleetKill, requestForwardedFleetTell, requestForwardedFleetWait, } from "../akuma/fleet-request.js";
|
|
6
|
-
import { executeKillAkuma, executeTellAkuma, executeWaitAkuma } from "../akuma/fleet-execution.js";
|
|
6
|
+
import { requestForwardedFleetKill, requestForwardedFleetTell, requestForwardedFleetTellWait, requestForwardedFleetWait, } from "../akuma/fleet-request.js";
|
|
7
|
+
import { executeKillAkuma, executeTellAkuma, executeTellWaitAkuma, executeWaitAkuma, } from "../akuma/fleet-execution.js";
|
|
7
8
|
import { readAliases } from "../alias/index.js";
|
|
8
9
|
import { observeDispatchAssociation } from "../dispatch/index.js";
|
|
9
10
|
import { observeContractAt } from "../git/observe.js";
|
|
10
11
|
import { withGitDecodeChannel } from "../git/read-observation.js";
|
|
11
12
|
import { observeCreatedTaskObservations } from "../task/created-observation.js";
|
|
12
|
-
import {
|
|
13
|
+
import { schemaJsonText } from "../akuma/schema.js";
|
|
14
|
+
import { addressAkuma, addressAkumaSet, resolveAkuma, resolveAkumaSet, } from "./address.js";
|
|
13
15
|
import { requireInput } from "./input.js";
|
|
14
16
|
import { fleetResultSchemas, parseAkumaObservation, } from "../akuma/fleet-observation.js";
|
|
15
17
|
import { scopeForRepo } from "./repo.js";
|
|
@@ -20,6 +22,11 @@ function source(path) {
|
|
|
20
22
|
function observationDiagnostic(error) {
|
|
21
23
|
return error instanceof Error ? error.message : String(error);
|
|
22
24
|
}
|
|
25
|
+
function observationError(id, error) {
|
|
26
|
+
if (error instanceof AkumaNotBornError || error instanceof AkumaObservationError)
|
|
27
|
+
return error;
|
|
28
|
+
return new AkumaObservationError(id, observationDiagnostic(error));
|
|
29
|
+
}
|
|
23
30
|
async function dispatchAssociation(repo, id) {
|
|
24
31
|
return await observeDispatchAssociation(repo === undefined ? undefined : scopeForRepo(repo), id);
|
|
25
32
|
}
|
|
@@ -153,7 +160,49 @@ function setAddress(values) {
|
|
|
153
160
|
}
|
|
154
161
|
export async function statusAkuma(input) {
|
|
155
162
|
const addressed = await addressAkuma(input);
|
|
156
|
-
|
|
163
|
+
try {
|
|
164
|
+
return await observeAkuma(await source(addressed.path).selectHandle({ id: addressed.id }).status(), addressed.path, input.repo);
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
throw observationError(addressed.id, error);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
function completionMode(value) {
|
|
171
|
+
// An omitted mode is any: a plural wait returns when any selected Akuma is complete.
|
|
172
|
+
if (value === undefined)
|
|
173
|
+
return "any";
|
|
174
|
+
if (value !== "any" && value !== "all")
|
|
175
|
+
throw new TypeError("completion must be any or all");
|
|
176
|
+
return value;
|
|
177
|
+
}
|
|
178
|
+
async function forwardedWait(addressed, input) {
|
|
179
|
+
return await attachWaitAssociations(addressed.path, input.repo, await requestForwardedFleetWait({
|
|
180
|
+
directory: input.directory,
|
|
181
|
+
targets: addressed.orderedIds,
|
|
182
|
+
completion: input.completion,
|
|
183
|
+
...(input.timeoutMs === undefined ? {} : { timeoutMs: input.timeoutMs }),
|
|
184
|
+
...(input.signal === undefined ? {} : { signal: input.signal }),
|
|
185
|
+
}));
|
|
186
|
+
}
|
|
187
|
+
async function localWait(addressed, input) {
|
|
188
|
+
try {
|
|
189
|
+
return await attachWaitAssociations(addressed.path, input.repo, await executeWaitAkuma({
|
|
190
|
+
path: addressed.path,
|
|
191
|
+
ids: addressed.orderedIds,
|
|
192
|
+
completion: input.completion,
|
|
193
|
+
...(input.timeoutMs === undefined ? {} : { timeoutMs: input.timeoutMs }),
|
|
194
|
+
...(input.signal === undefined ? {} : { signal: input.signal }),
|
|
195
|
+
identity: waitIdentityFacts(addressed.path, input.repo),
|
|
196
|
+
selectionOrder: addressed.orderedIds,
|
|
197
|
+
...(input.observer?.selected === undefined ? {} : { onSelected: input.observer.selected }),
|
|
198
|
+
...(input.observer?.observe === undefined ? {} : { observe: input.observer.observe }),
|
|
199
|
+
}));
|
|
200
|
+
}
|
|
201
|
+
catch (error) {
|
|
202
|
+
if (input.signal?.aborted === true || addressed.orderedIds.length !== 1)
|
|
203
|
+
throw error;
|
|
204
|
+
throw observationError(addressed.orderedIds[0], error);
|
|
205
|
+
}
|
|
157
206
|
}
|
|
158
207
|
export async function waitAkuma(input, execution = localExecutionContext(), observer) {
|
|
159
208
|
const values = requireInput(input, "Keiyaku.wait input");
|
|
@@ -162,37 +211,25 @@ export async function waitAkuma(input, execution = localExecutionContext(), obse
|
|
|
162
211
|
throw new TypeError(`Keiyaku.wait input has unknown field: ${key}`);
|
|
163
212
|
}
|
|
164
213
|
}
|
|
165
|
-
const
|
|
166
|
-
const completion = values.completion;
|
|
167
|
-
if (completion !== undefined && completion !== "any" && completion !== "all") {
|
|
168
|
-
throw new TypeError("completion must be any or all");
|
|
169
|
-
}
|
|
170
|
-
// An omitted mode is any: a plural wait returns when any selected Akuma is complete.
|
|
171
|
-
const selected = completion ?? "any";
|
|
214
|
+
const selected = completionMode(values.completion);
|
|
172
215
|
const timeoutMs = timeout(values.timeoutMs);
|
|
173
216
|
const callerSignal = signal(values.signal);
|
|
174
217
|
const channel = executionChannel(execution);
|
|
175
218
|
const repo = values.repo;
|
|
176
|
-
|
|
177
|
-
return await attachWaitAssociations(addressed.path, repo, await requestForwardedFleetWait({
|
|
178
|
-
directory: channel.directory,
|
|
179
|
-
targets: addressed.orderedIds,
|
|
180
|
-
completion: selected,
|
|
181
|
-
...(timeoutMs === undefined ? {} : { timeoutMs }),
|
|
182
|
-
...(callerSignal === undefined ? {} : { signal: callerSignal }),
|
|
183
|
-
}));
|
|
184
|
-
}
|
|
185
|
-
return await attachWaitAssociations(addressed.path, repo, await executeWaitAkuma({
|
|
186
|
-
path: addressed.path,
|
|
187
|
-
ids: addressed.orderedIds,
|
|
219
|
+
const mode = {
|
|
188
220
|
completion: selected,
|
|
189
221
|
...(timeoutMs === undefined ? {} : { timeoutMs }),
|
|
190
222
|
...(callerSignal === undefined ? {} : { signal: callerSignal }),
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
223
|
+
...(repo === undefined ? {} : { repo }),
|
|
224
|
+
};
|
|
225
|
+
if (channel.kind === "body-request") {
|
|
226
|
+
// A forwarded operation resolves coordinates without proving birth: the
|
|
227
|
+
// parent Fleet owns the target, so this process never probes locally.
|
|
228
|
+
const addressed = await resolveAkumaSet(setAddress(values));
|
|
229
|
+
return await forwardedWait(addressed, { ...mode, directory: channel.directory });
|
|
230
|
+
}
|
|
231
|
+
const addressed = await addressAkumaSet(setAddress(values));
|
|
232
|
+
return await localWait(addressed, { ...mode, ...(observer === undefined ? {} : { observer }) });
|
|
196
233
|
}
|
|
197
234
|
export async function killAkuma(input, execution = localExecutionContext()) {
|
|
198
235
|
const values = requireInput(input, "Keiyaku.kill input");
|
|
@@ -202,15 +239,16 @@ export async function killAkuma(input, execution = localExecutionContext()) {
|
|
|
202
239
|
}
|
|
203
240
|
}
|
|
204
241
|
const callerSignal = signal(values.signal);
|
|
205
|
-
const addressed = await addressAkumaSet(setAddress(values));
|
|
206
242
|
const channel = executionChannel(execution);
|
|
207
243
|
if (channel.kind === "body-request") {
|
|
244
|
+
const addressed = await resolveAkumaSet(setAddress(values));
|
|
208
245
|
return await requestForwardedFleetKill({
|
|
209
246
|
directory: channel.directory,
|
|
210
247
|
targets: addressed.orderedIds,
|
|
211
248
|
...(callerSignal === undefined ? {} : { signal: callerSignal }),
|
|
212
249
|
});
|
|
213
250
|
}
|
|
251
|
+
const addressed = await addressAkumaSet(setAddress(values));
|
|
214
252
|
return await executeKillAkuma({
|
|
215
253
|
path: addressed.path,
|
|
216
254
|
ids: addressed.orderedIds,
|
|
@@ -227,9 +265,9 @@ export async function tellAkuma(input, execution = localExecutionContext()) {
|
|
|
227
265
|
if (typeof values.body !== "string")
|
|
228
266
|
throw new TypeError("body must be a string");
|
|
229
267
|
const callerSignal = signal(values.signal);
|
|
230
|
-
const addressed = await addressAkuma(directAddress(values));
|
|
231
268
|
const channel = executionChannel(execution);
|
|
232
269
|
if (channel.kind === "body-request") {
|
|
270
|
+
const addressed = await resolveAkuma(directAddress(values));
|
|
233
271
|
return await requestForwardedFleetTell({
|
|
234
272
|
directory: channel.directory,
|
|
235
273
|
target: addressed.id,
|
|
@@ -238,6 +276,7 @@ export async function tellAkuma(input, execution = localExecutionContext()) {
|
|
|
238
276
|
...(callerSignal === undefined ? {} : { signal: callerSignal }),
|
|
239
277
|
});
|
|
240
278
|
}
|
|
279
|
+
const addressed = await addressAkuma(directAddress(values));
|
|
241
280
|
return await executeTellAkuma({
|
|
242
281
|
path: addressed.path,
|
|
243
282
|
id: addressed.id,
|
|
@@ -246,6 +285,52 @@ export async function tellAkuma(input, execution = localExecutionContext()) {
|
|
|
246
285
|
...(callerSignal === undefined ? {} : { signal: callerSignal }),
|
|
247
286
|
});
|
|
248
287
|
}
|
|
288
|
+
export async function tellWaitAkuma(input, execution = localExecutionContext()) {
|
|
289
|
+
const values = requireInput(input, "Keiyaku tell wait input");
|
|
290
|
+
for (const key of Object.keys(values)) {
|
|
291
|
+
if (!["path", "akuma", "body", "repo", "timeoutMs", "schema", "interrupt", "initiator", "signal"].includes(key)) {
|
|
292
|
+
throw new TypeError(`Keiyaku tell wait input has unknown field: ${key}`);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
if (typeof values.body !== "string")
|
|
296
|
+
throw new TypeError("body must be a string");
|
|
297
|
+
if (typeof values.timeoutMs !== "number" ||
|
|
298
|
+
!Number.isFinite(values.timeoutMs) ||
|
|
299
|
+
!Number.isInteger(values.timeoutMs) ||
|
|
300
|
+
values.timeoutMs < 0) {
|
|
301
|
+
throw new TypeError("timeoutMs must be a nonnegative finite millisecond duration");
|
|
302
|
+
}
|
|
303
|
+
if (values.interrupt !== undefined && typeof values.interrupt !== "boolean")
|
|
304
|
+
throw new TypeError("interrupt must be a boolean");
|
|
305
|
+
const callerSignal = signal(values.signal);
|
|
306
|
+
const channel = executionChannel(execution);
|
|
307
|
+
if (channel.kind === "body-request") {
|
|
308
|
+
// A forwarded Tell is resolved by its serving parent, so this process must
|
|
309
|
+
// not prove the target against its own Heart files.
|
|
310
|
+
const addressed = await resolveAkuma(directAddress(values));
|
|
311
|
+
return await requestForwardedFleetTellWait({
|
|
312
|
+
directory: channel.directory,
|
|
313
|
+
target: addressed.id,
|
|
314
|
+
body: values.body,
|
|
315
|
+
timeoutMs: values.timeoutMs,
|
|
316
|
+
...(input.schema === undefined ? {} : { schema: input.schema }),
|
|
317
|
+
...(input.interrupt === true ? { interrupt: true } : {}),
|
|
318
|
+
...(input.initiator === undefined ? {} : { initiator: input.initiator }),
|
|
319
|
+
...(callerSignal === undefined ? {} : { signal: callerSignal }),
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
const addressed = await addressAkuma(directAddress(values));
|
|
323
|
+
return await executeTellWaitAkuma({
|
|
324
|
+
path: addressed.path,
|
|
325
|
+
id: addressed.id,
|
|
326
|
+
body: values.body,
|
|
327
|
+
timeoutMs: values.timeoutMs,
|
|
328
|
+
...(input.schema === undefined ? {} : { schemaJson: schemaJsonText(input.schema) }),
|
|
329
|
+
...(input.interrupt === true ? { interrupt: true } : {}),
|
|
330
|
+
...(input.initiator === undefined ? {} : { initiator: input.initiator }),
|
|
331
|
+
...(callerSignal === undefined ? {} : { signal: callerSignal }),
|
|
332
|
+
});
|
|
333
|
+
}
|
|
249
334
|
export async function interruptAkuma(input) {
|
|
250
335
|
const values = requireInput(input, "Keiyaku.interrupt input");
|
|
251
336
|
for (const key of Object.keys(values)) {
|
|
@@ -284,24 +369,29 @@ export async function historyAkuma(input) {
|
|
|
284
369
|
const values = requireInput(input, "Keiyaku.history input");
|
|
285
370
|
validateHistoryInput(values);
|
|
286
371
|
const addressed = await addressAkuma(directAddress(values));
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
372
|
+
try {
|
|
373
|
+
const handle = source(addressed.path).selectHandle({ id: addressed.id });
|
|
374
|
+
const contract = await dispatchAssociation(values.repo, addressed.id);
|
|
375
|
+
if (values.last === true) {
|
|
376
|
+
const answer = await handle.lastAnswer();
|
|
377
|
+
return answer.kind === "answer"
|
|
378
|
+
? { kind: "last", id: addressed.id, answer: answer.answer, contract }
|
|
379
|
+
: { kind: "no-answer", id: addressed.id, contract };
|
|
380
|
+
}
|
|
381
|
+
const history = await handle.history({
|
|
382
|
+
...(values.id === undefined ? {} : { id: values.id }),
|
|
383
|
+
...(values.before === undefined ? {} : { before: values.before }),
|
|
384
|
+
...(values.since === undefined ? {} : { since: values.since }),
|
|
385
|
+
...(values.limit === undefined ? {} : { limit: values.limit }),
|
|
386
|
+
});
|
|
387
|
+
if (values.id !== undefined) {
|
|
388
|
+
if ("kind" in history && history.kind === "exact")
|
|
389
|
+
return { kind: "exact", id: addressed.id, outcome: history.outcome, contract };
|
|
390
|
+
return { kind: "unknown-history", id: addressed.id, historyId: values.id, contract };
|
|
391
|
+
}
|
|
392
|
+
return { kind: "history", id: addressed.id, history: history, contract };
|
|
294
393
|
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
...(values.before === undefined ? {} : { before: values.before }),
|
|
298
|
-
...(values.since === undefined ? {} : { since: values.since }),
|
|
299
|
-
...(values.limit === undefined ? {} : { limit: values.limit }),
|
|
300
|
-
});
|
|
301
|
-
if (values.id !== undefined) {
|
|
302
|
-
if ("kind" in history && history.kind === "exact")
|
|
303
|
-
return { kind: "exact", id: addressed.id, outcome: history.outcome, contract };
|
|
304
|
-
return { kind: "unknown-history", id: addressed.id, historyId: values.id, contract };
|
|
394
|
+
catch (error) {
|
|
395
|
+
throw observationError(addressed.id, error);
|
|
305
396
|
}
|
|
306
|
-
return { kind: "history", id: addressed.id, history: history, contract };
|
|
307
397
|
}
|
|
@@ -223,6 +223,10 @@ export declare const Keiyaku: Readonly<{
|
|
|
223
223
|
} | {
|
|
224
224
|
kind: "other";
|
|
225
225
|
display: string;
|
|
226
|
+
input?: {
|
|
227
|
+
json: string;
|
|
228
|
+
truncated: boolean;
|
|
229
|
+
} | undefined;
|
|
226
230
|
};
|
|
227
231
|
state: "active";
|
|
228
232
|
truncated?: true | undefined;
|
|
@@ -259,6 +263,10 @@ export declare const Keiyaku: Readonly<{
|
|
|
259
263
|
} | {
|
|
260
264
|
kind: "other";
|
|
261
265
|
display: string;
|
|
266
|
+
input?: {
|
|
267
|
+
json: string;
|
|
268
|
+
truncated: boolean;
|
|
269
|
+
} | undefined;
|
|
262
270
|
};
|
|
263
271
|
state: {
|
|
264
272
|
status: "error" | "ok";
|
|
@@ -349,6 +357,10 @@ export declare const Keiyaku: Readonly<{
|
|
|
349
357
|
} | {
|
|
350
358
|
kind: "other";
|
|
351
359
|
display: string;
|
|
360
|
+
input?: {
|
|
361
|
+
json: string;
|
|
362
|
+
truncated: boolean;
|
|
363
|
+
} | undefined;
|
|
352
364
|
};
|
|
353
365
|
state: {
|
|
354
366
|
status: "error" | "ok";
|
|
@@ -26,6 +26,7 @@ export type PluginSignalMap = Readonly<{
|
|
|
26
26
|
}>;
|
|
27
27
|
"akuma.turn-outcome": Readonly<{
|
|
28
28
|
akumaId: string;
|
|
29
|
+
bodySequence: number;
|
|
29
30
|
turnSequence: number;
|
|
30
31
|
initiator?: string;
|
|
31
32
|
outcome: PluginOutcome;
|
|
@@ -35,6 +36,7 @@ export type PluginSignalMap = Readonly<{
|
|
|
35
36
|
akumaId: string;
|
|
36
37
|
bodySequence: number;
|
|
37
38
|
end: PluginBodyEnd;
|
|
39
|
+
initiator?: string;
|
|
38
40
|
diagnostic?: string;
|
|
39
41
|
contractId?: string;
|
|
40
42
|
}>;
|
|
Binary file
|