@astrosheep/keiyaku 4.6.13 → 4.6.15
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/plugins/claude/skills/keiyaku/SKILL.md +3 -0
- package/build/plugins/claude/skills/keiyaku-akuma/SKILL.md +20 -0
- package/build/plugins/codex/skills/keiyaku/SKILL.md +3 -0
- package/build/plugins/codex/skills/keiyaku-akuma/SKILL.md +20 -0
- package/build/plugins/opencode/skills/keiyaku/SKILL.md +3 -0
- package/build/plugins/opencode/skills/keiyaku-akuma/SKILL.md +20 -0
- package/build/skills/keiyaku/SKILL.md +3 -0
- package/build/skills/keiyaku-akuma/SKILL.md +20 -0
- package/build/src/akuma/akuma-instance.js +7 -5
- package/build/src/akuma/akuma-observe.js +1 -0
- package/build/src/akuma/akuma-owner.js +3 -2
- package/build/src/akuma/akuma-wait.d.ts +1 -2
- package/build/src/akuma/akuma-wait.js +1 -4
- package/build/src/akuma/akuma.d.ts +9 -4
- package/build/src/akuma/akuma.js +208 -35
- package/build/src/akuma/body.js +4 -0
- package/build/src/akuma/caller.d.ts +2 -0
- package/build/src/akuma/caller.js +6 -0
- package/build/src/akuma/custody.d.ts +11 -0
- package/build/src/akuma/custody.js +102 -0
- package/build/src/akuma/lineage-cache.d.ts +39 -0
- package/build/src/akuma/lineage-cache.js +162 -0
- package/build/src/akuma/nuke.d.ts +1 -3
- package/build/src/akuma/nuke.js +11 -102
- package/build/src/akuma/retention.d.ts +44 -0
- package/build/src/akuma/retention.js +106 -0
- package/build/src/akuma/selection-owner-port.d.ts +1 -1
- package/build/src/akuma/selection-owner-port.js +3 -6
- package/build/src/akuma/selection-request.d.ts +131 -4
- package/build/src/akuma/selection-request.js +25 -15
- package/build/src/alias/index.d.ts +11 -0
- package/build/src/alias/index.js +20 -1
- package/build/src/cli/commands/contract-grammar.d.ts +12 -0
- package/build/src/cli/commands/contract-grammar.js +65 -13
- package/build/src/cli/commands/contract-help.d.ts +3 -1
- package/build/src/cli/commands/contract-help.js +5 -2
- package/build/src/cli/commands/contract.js +31 -4
- package/build/src/cli/render/catalog.d.ts +2 -1
- package/build/src/cli/render/catalog.js +8 -2
- package/build/src/cli/square-identity.d.ts +0 -5
- package/build/src/cli/square-identity.js +51 -101
- package/build/src/index.d.ts +1 -1
- package/build/src/library/akuma-retention.d.ts +11 -0
- package/build/src/library/akuma-retention.js +131 -0
- package/build/src/library/akumas.d.ts +8 -0
- package/build/src/library/akumas.js +42 -2
- package/build/src/library/selection.js +22 -9
- package/build/src/plugin/akuma-signals.d.ts +1 -0
- package/build/src/plugin/akuma-signals.js +17 -0
- package/build/src/plugin/public.d.ts +7 -0
- package/build/src/plugin/runtime.d.ts +1 -0
- package/build/src/plugin/runtime.js +85 -13
- package/build/src/runtime/proc/windows-launch.exe +0 -0
- package/package.json +3 -3
- package/skills/keiyaku/SKILL.md +3 -0
- package/skills/keiyaku-akuma/SKILL.md +20 -0
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { AkumaSelfInterruptError } from "./akuma-errors.js";
|
|
2
|
-
import { outcomePluginObserver } from "../plugin/akuma-signals.js";
|
|
3
2
|
import { requireBornAkuma } from "./akuma-probe.js";
|
|
4
3
|
import { executeAskAkuma, executeKillAkuma, executeTellAkuma } from "./akuma-selection-execution.js";
|
|
5
4
|
import { executeWaitAkuma } from "./akuma-wait.js";
|
|
@@ -13,13 +12,13 @@ import { akumaObservationOf } from "./selection-observation.js";
|
|
|
13
12
|
* unaddressable member never starts; the executor's own access to the target is
|
|
14
13
|
* then the product act, never a second addressing probe.
|
|
15
14
|
*/
|
|
16
|
-
export function selectionRequestPort(world,
|
|
15
|
+
export function selectionRequestPort(world, _reportDiagnostic, servingBodyId) {
|
|
17
16
|
const prove = async (targets) => {
|
|
18
17
|
for (const id of targets)
|
|
19
18
|
await requireBornAkuma(world, id);
|
|
20
19
|
};
|
|
21
20
|
return {
|
|
22
|
-
wait: async ({ targets,
|
|
21
|
+
wait: async ({ targets, ...request }) => {
|
|
23
22
|
await prove(targets);
|
|
24
23
|
// The lower wait owner returns association-free native evidence; the
|
|
25
24
|
// actual request crossing composes its canonical transport shape.
|
|
@@ -27,7 +26,6 @@ export function selectionRequestPort(world, reportDiagnostic, servingBodyId) {
|
|
|
27
26
|
path: world,
|
|
28
27
|
ids: targets,
|
|
29
28
|
...request,
|
|
30
|
-
outcomeObserved: outcomePluginObserver({ world, reportDiagnostic }, observer),
|
|
31
29
|
});
|
|
32
30
|
return { ...native, observations: native.observations.map(akumaObservationOf) };
|
|
33
31
|
},
|
|
@@ -37,7 +35,7 @@ export function selectionRequestPort(world, reportDiagnostic, servingBodyId) {
|
|
|
37
35
|
await prove([target]);
|
|
38
36
|
return await executeTellAkuma({ path: world, id: target, ...request });
|
|
39
37
|
},
|
|
40
|
-
ask: async ({ target,
|
|
38
|
+
ask: async ({ target, ...request }) => {
|
|
41
39
|
if (request.interrupt === true && servingBodyId === target)
|
|
42
40
|
throw new AkumaSelfInterruptError(target);
|
|
43
41
|
await prove([target]);
|
|
@@ -45,7 +43,6 @@ export function selectionRequestPort(world, reportDiagnostic, servingBodyId) {
|
|
|
45
43
|
path: world,
|
|
46
44
|
id: target,
|
|
47
45
|
...request,
|
|
48
|
-
outcomeObserved: outcomePluginObserver({ world, reportDiagnostic }, observer),
|
|
49
46
|
});
|
|
50
47
|
},
|
|
51
48
|
kill: async ({ targets, ...request }) => {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import type { AkumaStatus } from "./akuma.js";
|
|
3
3
|
import type { KillEvidence } from "./heart/index.js";
|
|
4
|
+
import type { OutcomeObserver } from "./akuma-observe.js";
|
|
4
5
|
import { type ErasedRequestCommand, type RequestProtocol, type ServiceRequestCommand } from "./request-wire.js";
|
|
5
6
|
import type { Schema } from "./schema.js";
|
|
6
7
|
import { type AkumaAskResult, type AkumaKillResult, type AkumaTellResult, type AkumaWaitResult } from "./selection-observation.js";
|
|
@@ -100,13 +101,139 @@ export declare function encodeSelectionLiveFailure(error: unknown): unknown | nu
|
|
|
100
101
|
export declare function decodeSelectionLiveFailure(value: unknown): Error | null;
|
|
101
102
|
export type SelectionRequest = z.infer<typeof waitRequestSchema> | z.infer<typeof tellRequestSchema> | z.infer<typeof askRequestSchema> | z.infer<typeof killRequestSchema>;
|
|
102
103
|
export type SelectionService = z.infer<typeof waitServiceSchema> | z.infer<typeof tellServiceSchema> | z.infer<typeof askServiceSchema> | z.infer<typeof killServiceSchema>;
|
|
103
|
-
|
|
104
|
+
declare const forwardedAskResultSchema: z.ZodObject<{
|
|
105
|
+
result: z.ZodObject<{
|
|
106
|
+
akuma: z.ZodPipe<z.ZodString, z.ZodTransform<import("./identity.js").AkuId, string>>;
|
|
107
|
+
tell: z.ZodObject<{
|
|
108
|
+
admission: z.ZodObject<{
|
|
109
|
+
fact: z.ZodLiteral<"recorded">;
|
|
110
|
+
tellId: z.ZodString;
|
|
111
|
+
}, z.core.$strict>;
|
|
112
|
+
row: z.ZodObject<{
|
|
113
|
+
kind: z.ZodLiteral<"tell">;
|
|
114
|
+
sequence: z.ZodNumber;
|
|
115
|
+
at: z.ZodString;
|
|
116
|
+
tellId: z.ZodString;
|
|
117
|
+
text: z.ZodString;
|
|
118
|
+
state: z.ZodEnum<{
|
|
119
|
+
pending: "pending";
|
|
120
|
+
told: "told";
|
|
121
|
+
}>;
|
|
122
|
+
deliveries: z.ZodReadonly<z.ZodArray<z.ZodPipe<z.ZodObject<{
|
|
123
|
+
deliveredAt: z.ZodString;
|
|
124
|
+
route: z.ZodEnum<{
|
|
125
|
+
live: "live";
|
|
126
|
+
launch: "launch";
|
|
127
|
+
}>;
|
|
128
|
+
turnSequence: z.ZodNumber;
|
|
129
|
+
receipt: z.ZodOptional<z.ZodEnum<{
|
|
130
|
+
unavailable: "unavailable";
|
|
131
|
+
required: "required";
|
|
132
|
+
}>>;
|
|
133
|
+
}, z.core.$strict>, z.ZodTransform<Readonly<{
|
|
134
|
+
turnSequence: number;
|
|
135
|
+
route: "launch" | "live";
|
|
136
|
+
receipt?: "unavailable" | "required";
|
|
137
|
+
deliveredAt: string;
|
|
138
|
+
}>, {
|
|
139
|
+
deliveredAt: string;
|
|
140
|
+
route: "live" | "launch";
|
|
141
|
+
turnSequence: number;
|
|
142
|
+
receipt?: "unavailable" | "required" | undefined;
|
|
143
|
+
}>>>>;
|
|
144
|
+
}, z.core.$strict>;
|
|
145
|
+
wake: z.ZodUnion<readonly [z.ZodObject<{
|
|
146
|
+
kind: z.ZodLiteral<"told">;
|
|
147
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
148
|
+
kind: z.ZodLiteral<"held">;
|
|
149
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
150
|
+
kind: z.ZodLiteral<"pursuing">;
|
|
151
|
+
bodySequence: z.ZodNumber;
|
|
152
|
+
}, z.core.$strict>, z.ZodPipe<z.ZodObject<{
|
|
153
|
+
kind: z.ZodLiteral<"failed">;
|
|
154
|
+
diagnostic: z.ZodString;
|
|
155
|
+
child: z.ZodOptional<z.ZodObject<{
|
|
156
|
+
code: z.ZodNullable<z.ZodNumber>;
|
|
157
|
+
signal: z.ZodNullable<z.ZodString>;
|
|
158
|
+
log: z.ZodObject<{
|
|
159
|
+
path: z.ZodString;
|
|
160
|
+
from: z.ZodNumber;
|
|
161
|
+
to: z.ZodNumber;
|
|
162
|
+
}, z.core.$strict>;
|
|
163
|
+
}, z.core.$strict>>;
|
|
164
|
+
}, z.core.$strict>, z.ZodTransform<{
|
|
165
|
+
kind: "failed";
|
|
166
|
+
diagnostic: string;
|
|
167
|
+
} | {
|
|
168
|
+
child: {
|
|
169
|
+
code: number | null;
|
|
170
|
+
signal: string | null;
|
|
171
|
+
log: {
|
|
172
|
+
path: string;
|
|
173
|
+
from: number;
|
|
174
|
+
to: number;
|
|
175
|
+
};
|
|
176
|
+
};
|
|
177
|
+
kind: "failed";
|
|
178
|
+
diagnostic: string;
|
|
179
|
+
}, {
|
|
180
|
+
kind: "failed";
|
|
181
|
+
diagnostic: string;
|
|
182
|
+
child?: {
|
|
183
|
+
code: number | null;
|
|
184
|
+
signal: string | null;
|
|
185
|
+
log: {
|
|
186
|
+
path: string;
|
|
187
|
+
from: number;
|
|
188
|
+
to: number;
|
|
189
|
+
};
|
|
190
|
+
} | undefined;
|
|
191
|
+
}>>]>;
|
|
192
|
+
interruption: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
193
|
+
kind: z.ZodLiteral<"completed">;
|
|
194
|
+
bodySequence: z.ZodNumber;
|
|
195
|
+
putDown: z.ZodEnum<{
|
|
196
|
+
"was-idle": "was-idle";
|
|
197
|
+
"self-aborted": "self-aborted";
|
|
198
|
+
}>;
|
|
199
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
200
|
+
kind: z.ZodLiteral<"pending">;
|
|
201
|
+
bodySequence: z.ZodNumber;
|
|
202
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
203
|
+
kind: z.ZodLiteral<"unavailable">;
|
|
204
|
+
bodySequence: z.ZodNumber;
|
|
205
|
+
evidence: z.ZodEnum<{
|
|
206
|
+
hung: "hung";
|
|
207
|
+
untidy: "untidy";
|
|
208
|
+
}>;
|
|
209
|
+
}, z.core.$strict>], "kind">>;
|
|
210
|
+
}, z.core.$strict>;
|
|
211
|
+
observation: z.ZodUnion<readonly [z.ZodObject<{
|
|
212
|
+
reason: z.ZodLiteral<"answered">;
|
|
213
|
+
answer: z.ZodUnknown;
|
|
214
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
215
|
+
reason: z.ZodLiteral<"failed">;
|
|
216
|
+
diagnostic: z.ZodString;
|
|
217
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
218
|
+
reason: z.ZodLiteral<"invalid-output">;
|
|
219
|
+
diagnostic: z.ZodString;
|
|
220
|
+
answer: z.ZodString;
|
|
221
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
222
|
+
reason: z.ZodLiteral<"unanswered">;
|
|
223
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
224
|
+
reason: z.ZodLiteral<"deadline">;
|
|
225
|
+
}, z.core.$strict>]>;
|
|
226
|
+
completedAt: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
227
|
+
}, z.core.$strict>;
|
|
228
|
+
historyIds: z.ZodReadonly<z.ZodArray<z.ZodString>>;
|
|
229
|
+
}, z.core.$strict>;
|
|
230
|
+
type ForwardedAskResult = z.infer<typeof forwardedAskResultSchema>;
|
|
231
|
+
type SelectionResult = AkumaWaitResult | AkumaTellResult | ForwardedAskResult | AkumaKillResult;
|
|
104
232
|
export type SelectionRequestPort = Readonly<{
|
|
105
233
|
wait(input: Readonly<{
|
|
106
234
|
targets: readonly AkumaStatus["id"][];
|
|
107
235
|
completion: "any" | "all";
|
|
108
236
|
timeoutMs?: number;
|
|
109
|
-
observer: string;
|
|
110
237
|
signal: AbortSignal;
|
|
111
238
|
}>): Promise<AkumaWaitResult>;
|
|
112
239
|
tell(input: Readonly<{
|
|
@@ -127,7 +254,7 @@ export type SelectionRequestPort = Readonly<{
|
|
|
127
254
|
schemaJson?: string;
|
|
128
255
|
initiator?: string;
|
|
129
256
|
interrupt?: boolean;
|
|
130
|
-
|
|
257
|
+
outcomeObserved: OutcomeObserver;
|
|
131
258
|
signal: AbortSignal;
|
|
132
259
|
}>): Promise<AkumaAskResult>;
|
|
133
260
|
kill(input: Readonly<{
|
|
@@ -169,7 +296,7 @@ export declare function requestForwardedSelectionAsk(input: Readonly<{
|
|
|
169
296
|
initiator?: string;
|
|
170
297
|
interrupt?: boolean;
|
|
171
298
|
signal?: AbortSignal;
|
|
172
|
-
}>): Promise<
|
|
299
|
+
}>): Promise<ForwardedAskResult>;
|
|
173
300
|
export declare function requestForwardedSelectionKill(input: Readonly<{
|
|
174
301
|
directory: string;
|
|
175
302
|
targets: readonly AkumaStatus["id"][];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { AkumaNotBornError, AkumaObservationError, AkumaSelfInterruptError } from "./akuma-errors.js";
|
|
3
|
-
import { akumaIdSchema } from "./identity.js";
|
|
3
|
+
import { akumaIdSchema, parsePublicHistoryId } from "./identity.js";
|
|
4
4
|
import { requestBodyCommand } from "./request-rendezvous.js";
|
|
5
5
|
import { eraseRequestCommand, } from "./request-wire.js";
|
|
6
6
|
import { schemaJsonText } from "./schema.js";
|
|
@@ -104,6 +104,12 @@ export function decodeSelectionLiveFailure(value) {
|
|
|
104
104
|
? new AkumaSelfInterruptError(failure.id)
|
|
105
105
|
: new AkumaObservationError(failure.id, failure.diagnostic);
|
|
106
106
|
}
|
|
107
|
+
const forwardedAskResultSchema = z
|
|
108
|
+
.object({
|
|
109
|
+
result: selectionResultSchemas.ask,
|
|
110
|
+
historyIds: z.array(z.string().refine((id) => parsePublicHistoryId(id) !== null)).readonly(),
|
|
111
|
+
})
|
|
112
|
+
.strict();
|
|
107
113
|
function decodeSelectionRequest(action, value) {
|
|
108
114
|
const schema = action === "akuma.wait"
|
|
109
115
|
? waitRequestSchema
|
|
@@ -134,7 +140,7 @@ function decodedSelectionResult(action, value) {
|
|
|
134
140
|
: action === "akuma.tell"
|
|
135
141
|
? selectionResultSchemas.tell
|
|
136
142
|
: action === "akuma.ask"
|
|
137
|
-
?
|
|
143
|
+
? forwardedAskResultSchema
|
|
138
144
|
: selectionResultSchemas.kill;
|
|
139
145
|
const parsed = schema.safeParse(value);
|
|
140
146
|
if (!parsed.success)
|
|
@@ -172,7 +178,7 @@ export function selectionRequestCommand(action, port) {
|
|
|
172
178
|
if (request.action === "akuma.wait") {
|
|
173
179
|
return {
|
|
174
180
|
kind: "served",
|
|
175
|
-
result: await port.wait({ ...request,
|
|
181
|
+
result: await port.wait({ ...request, signal: facts.signal }),
|
|
176
182
|
service: { action: request.action },
|
|
177
183
|
};
|
|
178
184
|
}
|
|
@@ -194,20 +200,24 @@ export function selectionRequestCommand(action, port) {
|
|
|
194
200
|
if (request.action === "akuma.ask") {
|
|
195
201
|
if (port.ask === undefined)
|
|
196
202
|
throw new Error("bounded Tell Selection port is unavailable");
|
|
203
|
+
let historyIds = [];
|
|
204
|
+
const result = await port.ask({
|
|
205
|
+
target: request.target,
|
|
206
|
+
body: request.body,
|
|
207
|
+
tellId: facts.id,
|
|
208
|
+
recordedAt: facts.admittedAt,
|
|
209
|
+
outcomeObserved: async (_id, observed) => {
|
|
210
|
+
historyIds = observed;
|
|
211
|
+
},
|
|
212
|
+
...(request.timeoutMs === undefined ? {} : { timeoutMs: request.timeoutMs }),
|
|
213
|
+
...(request.schemaJson === undefined ? {} : { schemaJson: request.schemaJson }),
|
|
214
|
+
...(request.initiator === undefined ? {} : { initiator: request.initiator }),
|
|
215
|
+
...(request.interrupt === undefined ? {} : { interrupt: request.interrupt }),
|
|
216
|
+
signal: facts.signal,
|
|
217
|
+
});
|
|
197
218
|
return {
|
|
198
219
|
kind: "served",
|
|
199
|
-
result:
|
|
200
|
-
target: request.target,
|
|
201
|
-
body: request.body,
|
|
202
|
-
tellId: facts.id,
|
|
203
|
-
recordedAt: facts.admittedAt,
|
|
204
|
-
observer: facts.requester,
|
|
205
|
-
...(request.timeoutMs === undefined ? {} : { timeoutMs: request.timeoutMs }),
|
|
206
|
-
...(request.schemaJson === undefined ? {} : { schemaJson: request.schemaJson }),
|
|
207
|
-
...(request.initiator === undefined ? {} : { initiator: request.initiator }),
|
|
208
|
-
...(request.interrupt === undefined ? {} : { interrupt: request.interrupt }),
|
|
209
|
-
signal: facts.signal,
|
|
210
|
-
}),
|
|
220
|
+
result: { result, historyIds },
|
|
211
221
|
service: { action: request.action, target: request.target, tellId: facts.id },
|
|
212
222
|
};
|
|
213
223
|
}
|
|
@@ -11,6 +11,17 @@ export type AliasMove = Readonly<{
|
|
|
11
11
|
}>;
|
|
12
12
|
export declare function nukeAliases(world: WorldRoot): Promise<void>;
|
|
13
13
|
export declare function readAliases(world: WorldRoot): Promise<readonly AliasBinding[]>;
|
|
14
|
+
export type HeldAliasCustody = Readonly<{
|
|
15
|
+
bindings: readonly AliasBinding[];
|
|
16
|
+
release(): void;
|
|
17
|
+
}>;
|
|
18
|
+
/**
|
|
19
|
+
* Take the same authority lock Alias writers use and read the current bindings
|
|
20
|
+
* under it. A holder keeps the lock across its cross-authority decision and
|
|
21
|
+
* effect, so no Alias move can commit between them. Null means another writer
|
|
22
|
+
* holds the authority; the caller must leave its subject untouched.
|
|
23
|
+
*/
|
|
24
|
+
export declare function tryAcquireAliasCustody(world: WorldRoot): Promise<HeldAliasCustody | null>;
|
|
14
25
|
export declare function moveAlias(input: Readonly<{
|
|
15
26
|
world: WorldRoot;
|
|
16
27
|
alias: AkumaAlias;
|
package/build/src/alias/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { lstat, mkdir, readFile, unlink } from "node:fs/promises";
|
|
|
2
2
|
import { dirname, resolve } from "node:path";
|
|
3
3
|
import { parseAkuId } from "../akuma/identity.js";
|
|
4
4
|
import { replaceFileDurably } from "../coordination/durable-file.js";
|
|
5
|
-
import { acquireSqliteTransactionLock } from "../coordination/sqlite-transaction-lock.js";
|
|
5
|
+
import { acquireSqliteTransactionLock, tryAcquireSqliteTransactionLock, } from "../coordination/sqlite-transaction-lock.js";
|
|
6
6
|
import { AuthorityCorruptionError } from "../core/facts/errors.js";
|
|
7
7
|
import { parseAkumaAlias, parseReadableAkumaAlias } from "../identity/selector.js";
|
|
8
8
|
const VERSION = 1;
|
|
@@ -113,6 +113,25 @@ export async function nukeAliases(world) {
|
|
|
113
113
|
export async function readAliases(world) {
|
|
114
114
|
return await read(paths(world).authority);
|
|
115
115
|
}
|
|
116
|
+
/**
|
|
117
|
+
* Take the same authority lock Alias writers use and read the current bindings
|
|
118
|
+
* under it. A holder keeps the lock across its cross-authority decision and
|
|
119
|
+
* effect, so no Alias move can commit between them. Null means another writer
|
|
120
|
+
* holds the authority; the caller must leave its subject untouched.
|
|
121
|
+
*/
|
|
122
|
+
export async function tryAcquireAliasCustody(world) {
|
|
123
|
+
const location = paths(world);
|
|
124
|
+
const held = await tryAcquireSqliteTransactionLock({ path: location.lock, mode: "immediate" });
|
|
125
|
+
if (held === null)
|
|
126
|
+
return null;
|
|
127
|
+
try {
|
|
128
|
+
return { bindings: await read(location.authority), release: () => held.close() };
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
held.close();
|
|
132
|
+
throw error;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
116
135
|
export async function moveAlias(input) {
|
|
117
136
|
const alias = parseAkumaAlias(input.alias);
|
|
118
137
|
const akuId = parseAkuId(input.akuId).id;
|
|
@@ -1,4 +1,15 @@
|
|
|
1
|
+
import { type AkumaCaller } from "../../akuma/caller.js";
|
|
2
|
+
import { type AkuId } from "../../akuma/identity.js";
|
|
1
3
|
import { type ContractCommand } from "./contract-help.js";
|
|
4
|
+
type AkumaCallerSelector = Readonly<{
|
|
5
|
+
kind: "mine";
|
|
6
|
+
}> | Readonly<{
|
|
7
|
+
kind: "external";
|
|
8
|
+
caller: AkumaCaller;
|
|
9
|
+
}> | Readonly<{
|
|
10
|
+
kind: "akuma";
|
|
11
|
+
akuId: AkuId;
|
|
12
|
+
}>;
|
|
2
13
|
type CatalogQuery = Readonly<{
|
|
3
14
|
kind: "debts";
|
|
4
15
|
namespace?: readonly string[];
|
|
@@ -12,6 +23,7 @@ type CatalogQuery = Readonly<{
|
|
|
12
23
|
}> | Readonly<{
|
|
13
24
|
kind: "akuma";
|
|
14
25
|
archetype?: string;
|
|
26
|
+
caller?: AkumaCallerSelector;
|
|
15
27
|
limit?: number;
|
|
16
28
|
}>;
|
|
17
29
|
type Output = Readonly<{
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { validateAkumaName } from "../../identity/normalize.js";
|
|
2
|
+
import { decodeAkumaCaller } from "../../akuma/caller.js";
|
|
3
|
+
import { parseAkuId } from "../../akuma/identity.js";
|
|
2
4
|
import { parseDebtNamespaceSelector } from "../../debt/catalog.js";
|
|
3
5
|
import { CliUsageError, commandGuide } from "../usage.js";
|
|
4
6
|
import { CONTRACT_COMMAND_SPECS } from "./contract-help.js";
|
|
@@ -231,26 +233,76 @@ function debtCatalogQuery(path, limit) {
|
|
|
231
233
|
refuse("ls", error instanceof Error ? error.message : `invalid Debt namespace selector: ${path}`);
|
|
232
234
|
}
|
|
233
235
|
}
|
|
236
|
+
function parseCallerSelector(parts) {
|
|
237
|
+
const mine = parts.flags.mine === true;
|
|
238
|
+
const value = optionalFlag(parts.flags, "caller");
|
|
239
|
+
if (mine && value !== undefined)
|
|
240
|
+
refuse("ls", "--mine and --caller are mutually exclusive");
|
|
241
|
+
if (mine)
|
|
242
|
+
return { kind: "mine" };
|
|
243
|
+
if (value === undefined)
|
|
244
|
+
return undefined;
|
|
245
|
+
const text = value.trim();
|
|
246
|
+
if (text.startsWith("aku/")) {
|
|
247
|
+
try {
|
|
248
|
+
return { kind: "akuma", akuId: parseAkuId(text).id };
|
|
249
|
+
}
|
|
250
|
+
catch (error) {
|
|
251
|
+
refuse("ls", `--caller has an invalid Akuma identity: ${error instanceof Error ? error.message : text}`);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
const colon = text.indexOf(":");
|
|
255
|
+
if (colon < 0)
|
|
256
|
+
refuse("ls", "--caller requires <integration>:<id> or aku/<name>/<suffix>");
|
|
257
|
+
try {
|
|
258
|
+
const caller = decodeAkumaCaller({
|
|
259
|
+
kind: "external",
|
|
260
|
+
integration: text.slice(0, colon),
|
|
261
|
+
id: text.slice(colon + 1),
|
|
262
|
+
});
|
|
263
|
+
if (caller === undefined)
|
|
264
|
+
refuse("ls", "--caller requires <integration>:<id> or aku/<name>/<suffix>");
|
|
265
|
+
return { kind: "external", caller };
|
|
266
|
+
}
|
|
267
|
+
catch (error) {
|
|
268
|
+
refuse("ls", `--caller is invalid: ${error instanceof Error ? error.message : String(error)}`);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
234
271
|
function parseLs(parts) {
|
|
235
272
|
const path = parts.positionals[0];
|
|
236
|
-
if (path === undefined)
|
|
237
|
-
refuse("ls", "ls requires a selector");
|
|
238
273
|
const limit = listLimit(parts);
|
|
239
|
-
const
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
output: parts.output
|
|
247
|
-
}
|
|
274
|
+
const caller = parseCallerSelector(parts);
|
|
275
|
+
const callerRefusal = "--mine and --caller select Akuma instances only";
|
|
276
|
+
if (path !== undefined) {
|
|
277
|
+
const debtQuery = debtCatalogQuery(path, limit);
|
|
278
|
+
if (debtQuery !== null) {
|
|
279
|
+
if (caller !== undefined)
|
|
280
|
+
refuse("ls", callerRefusal);
|
|
281
|
+
return { command: "ls", query: debtQuery, output: parts.output };
|
|
282
|
+
}
|
|
283
|
+
if (path === "kei" || path === "kei/") {
|
|
284
|
+
if (caller !== undefined)
|
|
285
|
+
refuse("ls", callerRefusal);
|
|
286
|
+
return {
|
|
287
|
+
command: "ls",
|
|
288
|
+
query: { kind: "contracts", ...(limit === undefined ? {} : { limit }) },
|
|
289
|
+
output: parts.output,
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
if (caller !== undefined && (path === "aku" || path === "aku/"))
|
|
293
|
+
refuse("ls", "--mine and --caller need an Akuma instance catalogue, not Akuma names");
|
|
248
294
|
}
|
|
295
|
+
if (path === undefined && caller === undefined)
|
|
296
|
+
refuse("ls", "ls requires a selector");
|
|
249
297
|
try {
|
|
250
|
-
const query = parseAkumaCatalogPath(path);
|
|
298
|
+
const query = path === undefined ? { kind: "akuma" } : parseAkumaCatalogPath(path);
|
|
251
299
|
if (query === null)
|
|
252
300
|
refuse("ls", "ls requires a supported identity directory selector");
|
|
253
|
-
return {
|
|
301
|
+
return {
|
|
302
|
+
command: "ls",
|
|
303
|
+
query: { ...query, ...(limit === undefined ? {} : { limit }), ...(caller === undefined ? {} : { caller }) },
|
|
304
|
+
output: parts.output,
|
|
305
|
+
};
|
|
254
306
|
}
|
|
255
307
|
catch (error) {
|
|
256
308
|
if (error instanceof CliUsageError)
|
|
@@ -118,8 +118,10 @@ export declare const CONTRACT_COMMAND_SPECS: {
|
|
|
118
118
|
readonly flags: {
|
|
119
119
|
readonly limit: "value";
|
|
120
120
|
readonly json: "boolean";
|
|
121
|
+
readonly mine: "boolean";
|
|
122
|
+
readonly caller: "value";
|
|
121
123
|
};
|
|
122
|
-
readonly usage: "ls debt[/] [--limit <count>]\nls kei[/] [--limit <count>]\nls aku[/] [--limit <count>]\nls aku/<name>[/] [--limit <count>]\nls \"aku/<name>/*\" [--limit <count>]\nls \"aku/*/*\" [--limit <count>]";
|
|
124
|
+
readonly usage: "ls debt[/] [--limit <count>]\nls kei[/] [--limit <count>]\nls aku[/] [--limit <count>]\nls aku/<name>[/] [--limit <count>]\nls \"aku/<name>/*\" [--limit <count>]\nls \"aku/*/*\" [--limit <count>]\nls [\"aku/*/*\"] --mine\nls [\"aku/*/*\"] --caller <integration>:<id> | aku/<name>/<suffix>";
|
|
123
125
|
readonly purpose: "List debts (ls debt), contracts (ls kei), or akumas (ls aku).";
|
|
124
126
|
readonly details: string;
|
|
125
127
|
};
|
|
@@ -182,13 +182,16 @@ export const CONTRACT_COMMAND_SPECS = {
|
|
|
182
182
|
ls: {
|
|
183
183
|
positional: "optional",
|
|
184
184
|
stdin: "none",
|
|
185
|
-
flags: { limit: "value", json: "boolean" },
|
|
186
|
-
usage: 'ls debt[/] [--limit <count>]\nls kei[/] [--limit <count>]\nls aku[/] [--limit <count>]\nls aku/<name>[/] [--limit <count>]\nls "aku/<name>/*" [--limit <count>]\nls "aku/*/*" [--limit <count>]',
|
|
185
|
+
flags: { limit: "value", json: "boolean", mine: "boolean", caller: "value" },
|
|
186
|
+
usage: 'ls debt[/] [--limit <count>]\nls kei[/] [--limit <count>]\nls aku[/] [--limit <count>]\nls aku/<name>[/] [--limit <count>]\nls "aku/<name>/*" [--limit <count>]\nls "aku/*/*" [--limit <count>]\nls ["aku/*/*"] --mine\nls ["aku/*/*"] --caller <integration>:<id> | aku/<name>/<suffix>',
|
|
187
187
|
purpose: "List debts (ls debt), contracts (ls kei), or akumas (ls aku).",
|
|
188
188
|
details: [
|
|
189
189
|
"ls kei lists active Contracts; accepted and abandoned ones leave the list, and their record stays in history and Git.",
|
|
190
190
|
"ls aku/ lists the callable Akuma-name catalog; ls aku/<name> lists the living Akumas under one name.",
|
|
191
191
|
'ls "aku/<name>/*" is the same living set in glob form; ls "aku/*/*" lists every living Akuma.',
|
|
192
|
+
"--mine selects the caller identity of this process and lists that caller's direct and transitive descendants in this World.",
|
|
193
|
+
"--caller selects an explicit caller instead; both selectors are World-local and refuse for Contract, Debt, or Akuma-name catalogues.",
|
|
194
|
+
"Descendant rows name their immediate calling Akuma beside the row.",
|
|
192
195
|
].join("\n"),
|
|
193
196
|
},
|
|
194
197
|
reconcile: {
|
|
@@ -6,6 +6,7 @@ import { composeContractLibrary, observeKeiyaku } from "../../library/contract-c
|
|
|
6
6
|
import { validateArcMarkdown, validateContractMarkdown } from "../../library/input.js";
|
|
7
7
|
import { createKeiyakuHandle } from "../../library/keiyaku.js";
|
|
8
8
|
import { SettingsError, settings } from "../../settings.js";
|
|
9
|
+
import { akumaCallerFromEnvironment } from "../akuma-caller.js";
|
|
9
10
|
import { Debts } from "../../debt/index.js";
|
|
10
11
|
import { actorFromEdge } from "../actor.js";
|
|
11
12
|
import { resolveInvocationCwd } from "../coordinates.js";
|
|
@@ -21,7 +22,8 @@ import { renderRegionText } from "../render/region.js";
|
|
|
21
22
|
import { renderSettingsText, settingsJsonValue } from "../render/settings.js";
|
|
22
23
|
import { canonicalContractSelector, contractFromInput, resolveContractId } from "../selectors.js";
|
|
23
24
|
import { displayContext, emit, writeJson, writeStderr, writeStdout } from "../streams.js";
|
|
24
|
-
import { CliUsageError, isBlankInput } from "../usage.js";
|
|
25
|
+
import { CliUsageError, commandGuide, isBlankInput } from "../usage.js";
|
|
26
|
+
import { CONTRACT_COMMAND_SPECS } from "./contract-help.js";
|
|
25
27
|
function requiredRepo(coordinates) {
|
|
26
28
|
if (coordinates.repo === undefined)
|
|
27
29
|
throw new CliUsageError("this command requires a resolved Repo");
|
|
@@ -305,7 +307,7 @@ async function runNuke(command, coordinates) {
|
|
|
305
307
|
});
|
|
306
308
|
return emit(command.output, result, () => renderNukeText(result), nukeExitCode(result));
|
|
307
309
|
}
|
|
308
|
-
async function runLs(command, coordinates, home) {
|
|
310
|
+
async function runLs(command, coordinates, home, runtime) {
|
|
309
311
|
const query = command.query;
|
|
310
312
|
if (query.kind === "contracts") {
|
|
311
313
|
const list = await Keiyaku.with().list({
|
|
@@ -334,11 +336,36 @@ async function runLs(command, coordinates, home) {
|
|
|
334
336
|
throw new Error("Debt list did not return an accepted observation");
|
|
335
337
|
return emit(command.output, listed, () => renderDebtCatalogue(listed.value, query.namespace ?? []), 0);
|
|
336
338
|
}
|
|
339
|
+
const caller = await lsCaller(query.caller, coordinates, runtime);
|
|
337
340
|
const listed = await Akumas.of(coordinates.world).list({
|
|
338
341
|
...(query.archetype === undefined ? {} : { archetype: query.archetype }),
|
|
339
342
|
...(query.limit === undefined ? {} : { limit: query.limit }),
|
|
343
|
+
...(caller === undefined ? {} : { caller }),
|
|
340
344
|
});
|
|
341
|
-
return emit(command.output, listed, () => renderAkumaCatalogue(listed, query.archetype ?? null), 0);
|
|
345
|
+
return emit(command.output, listed, () => renderAkumaCatalogue(listed, query.archetype ?? null, caller), 0);
|
|
346
|
+
}
|
|
347
|
+
/** `--mine` is the process caller identity; `--caller` names the same coordinate explicitly. */
|
|
348
|
+
async function lsCaller(selection, coordinates, runtime) {
|
|
349
|
+
const usage = (diagnostic) => new CliUsageError(diagnostic, commandGuide("ls", CONTRACT_COMMAND_SPECS.ls.usage));
|
|
350
|
+
if (selection === undefined)
|
|
351
|
+
return undefined;
|
|
352
|
+
if (selection.kind === "external")
|
|
353
|
+
return selection.caller;
|
|
354
|
+
if (selection.kind === "akuma") {
|
|
355
|
+
if (coordinates.world === null)
|
|
356
|
+
throw usage("no Keiyaku world contains the invocation cwd");
|
|
357
|
+
return { kind: "akuma", world: coordinates.world, akuId: selection.akuId };
|
|
358
|
+
}
|
|
359
|
+
let caller;
|
|
360
|
+
try {
|
|
361
|
+
caller = await akumaCallerFromEnvironment(runtime.environment);
|
|
362
|
+
}
|
|
363
|
+
catch (error) {
|
|
364
|
+
throw usage(error instanceof Error ? error.message : String(error));
|
|
365
|
+
}
|
|
366
|
+
if (caller === undefined)
|
|
367
|
+
throw usage("--mine requires a caller identity; set KEIYAKU_ACTOR_ID and KEIYAKU_ACTOR_WORLD or run inside a calling host");
|
|
368
|
+
return caller;
|
|
342
369
|
}
|
|
343
370
|
async function readAkumaStatus(akuma, alias, coordinates) {
|
|
344
371
|
if (coordinates.world === null)
|
|
@@ -531,7 +558,7 @@ export async function runContractCommand(command, coordinates, runtime) {
|
|
|
531
558
|
case "nuke":
|
|
532
559
|
return await runNuke(command, coordinates);
|
|
533
560
|
case "ls":
|
|
534
|
-
return await runLs(command, coordinates, home);
|
|
561
|
+
return await runLs(command, coordinates, home, runtime);
|
|
535
562
|
case "show":
|
|
536
563
|
return await runShow(command, coordinates);
|
|
537
564
|
case "status":
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { AkumaList } from "../../akuma/akuma.js";
|
|
2
|
+
import { type AkumaCaller } from "../../akuma/caller.js";
|
|
2
3
|
import type { ArchetypeCatalog } from "../../index.js";
|
|
3
4
|
import type { ContractList } from "../../library/contract-types.js";
|
|
4
5
|
import type { DebtPage, DebtRow } from "../../debt/index.js";
|
|
5
|
-
export declare function renderAkumaCatalogue(list: AkumaList, archetype: string | null): string;
|
|
6
|
+
export declare function renderAkumaCatalogue(list: AkumaList, archetype: string | null, caller?: AkumaCaller): string;
|
|
6
7
|
export declare function renderContractCatalogue(list: ContractList): string;
|
|
7
8
|
export declare function renderArchetypeCatalogue(list: ArchetypeCatalog): string;
|
|
8
9
|
export declare function renderDebtCatalogue(list: DebtPage<DebtRow>, namespace: readonly string[]): string;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { akumaCallerKey } from "../../akuma/caller.js";
|
|
1
2
|
import { abbreviateGitIds, displayGitId, gitIdsInRow, lifecycleWord, progressStrip } from "./contract-observation.js";
|
|
2
3
|
import { ageText, emptyCatalogue, renderBoundedPayload, safeText } from "./terminal.js";
|
|
3
4
|
import { akumaMark, contractMark } from "./marks.js";
|
|
@@ -7,11 +8,12 @@ function relativeAge(source, observedAt) {
|
|
|
7
8
|
return null;
|
|
8
9
|
return ageText(source, observedAt);
|
|
9
10
|
}
|
|
10
|
-
export function renderAkumaCatalogue(list, archetype) {
|
|
11
|
+
export function renderAkumaCatalogue(list, archetype, caller) {
|
|
11
12
|
const rows = list.rows;
|
|
12
13
|
if (rows.length === 0) {
|
|
13
14
|
return emptyCatalogue("akuma");
|
|
14
15
|
}
|
|
16
|
+
const root = caller === undefined ? undefined : akumaCallerKey(caller);
|
|
15
17
|
const lines = [archetype === null ? "AKUMA // recent" : `AKUMA // ${safeText(archetype)}`, ""];
|
|
16
18
|
for (const row of rows) {
|
|
17
19
|
const lifeAt = "lifeAt" in row ? row.lifeAt : null;
|
|
@@ -23,7 +25,11 @@ export function renderAkumaCatalogue(list, archetype) {
|
|
|
23
25
|
...(activityAge === null || activityAge === lifeAge ? [] : [`activity ${activityAge}`]),
|
|
24
26
|
];
|
|
25
27
|
const aliases = row.aliases.length === 0 ? "" : ` (${row.aliases.map((alias) => safeText(alias)).join(" ")})`;
|
|
26
|
-
|
|
28
|
+
const rowCaller = "caller" in row ? row.caller : undefined;
|
|
29
|
+
const by = root !== undefined && rowCaller?.kind === "akuma" && akumaCallerKey(rowCaller) !== root
|
|
30
|
+
? ` · by ${safeText(rowCaller.akuId)}`
|
|
31
|
+
: "";
|
|
32
|
+
lines.push(`${akumaMark(row.life)} ${safeText(row.id)}${aliases} · ${row.life}${ages.length === 0 ? "" : ` · ${ages.join(" · ")}`}${by}`);
|
|
27
33
|
}
|
|
28
34
|
if (list.hasMore)
|
|
29
35
|
lines.push("…");
|
|
@@ -7,9 +7,4 @@ export type SquareSeatControl = Readonly<{
|
|
|
7
7
|
signal?: AbortSignal;
|
|
8
8
|
budgetMs?: number;
|
|
9
9
|
}>;
|
|
10
|
-
/**
|
|
11
|
-
* The Square participant name this submitting session should speak as, or
|
|
12
|
-
* undefined when no honest choice exists. Identity preparation is optional, so it
|
|
13
|
-
* never refuses the enclosing operation and always settles within one budget.
|
|
14
|
-
*/
|
|
15
10
|
export declare function squareSeat(input: SquareSeatInput, control?: SquareSeatControl): Promise<string | undefined>;
|