@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
|
@@ -216,8 +216,10 @@ function isSignalKind(kind) {
|
|
|
216
216
|
function handlers(pluginId, instance) {
|
|
217
217
|
if (!object(instance))
|
|
218
218
|
throw new TypeError("plugin activation must return an object");
|
|
219
|
-
if (Object.keys(instance).some((name) => name !== "signals"))
|
|
219
|
+
if (Object.keys(instance).some((name) => name !== "signals" && name !== "waitDeferral"))
|
|
220
220
|
throw new TypeError("plugin instance has unknown fields");
|
|
221
|
+
if (instance.waitDeferral !== undefined && typeof instance.waitDeferral !== "function")
|
|
222
|
+
throw new TypeError("plugin waitDeferral must be a function");
|
|
221
223
|
if (instance.signals === undefined)
|
|
222
224
|
return [];
|
|
223
225
|
if (!object(instance.signals))
|
|
@@ -283,11 +285,11 @@ async function activate(input) {
|
|
|
283
285
|
catch (error) {
|
|
284
286
|
markStarted();
|
|
285
287
|
reportPluginDiagnostic(report, selected.id, "import", error);
|
|
286
|
-
return [];
|
|
288
|
+
return { handlers: [] };
|
|
287
289
|
}
|
|
288
290
|
if (cancellation.aborted) {
|
|
289
291
|
markStarted();
|
|
290
|
-
return [];
|
|
292
|
+
return { handlers: [] };
|
|
291
293
|
}
|
|
292
294
|
let candidate;
|
|
293
295
|
try {
|
|
@@ -301,7 +303,7 @@ async function activate(input) {
|
|
|
301
303
|
catch (error) {
|
|
302
304
|
markStarted();
|
|
303
305
|
reportPluginDiagnostic(report, selected.id, "validation", error);
|
|
304
|
-
return [];
|
|
306
|
+
return { handlers: [] };
|
|
305
307
|
}
|
|
306
308
|
let context;
|
|
307
309
|
try {
|
|
@@ -320,24 +322,27 @@ async function activate(input) {
|
|
|
320
322
|
catch (error) {
|
|
321
323
|
markStarted();
|
|
322
324
|
reportPluginDiagnostic(report, selected.id, "validation", error);
|
|
323
|
-
return [];
|
|
325
|
+
return { handlers: [] };
|
|
324
326
|
}
|
|
325
327
|
if (cancellation.aborted) {
|
|
326
328
|
markStarted();
|
|
327
|
-
return [];
|
|
329
|
+
return { handlers: [] };
|
|
328
330
|
}
|
|
329
331
|
markStarted();
|
|
330
332
|
try {
|
|
331
333
|
const instance = await candidate.activate(context, cancellation);
|
|
332
334
|
if (cancellation.aborted)
|
|
333
|
-
return [];
|
|
335
|
+
return { handlers: [] };
|
|
334
336
|
const registered = handlers(candidate.manifest.id, instance);
|
|
335
337
|
activated.add(candidate.manifest.id);
|
|
336
|
-
return
|
|
338
|
+
return {
|
|
339
|
+
handlers: registered,
|
|
340
|
+
...(instance.waitDeferral === undefined ? {} : { waitDeferral: instance.waitDeferral.bind(instance) }),
|
|
341
|
+
};
|
|
337
342
|
}
|
|
338
343
|
catch (error) {
|
|
339
344
|
reportPluginDiagnostic(report, selected.id, "activation", error);
|
|
340
|
-
return [];
|
|
345
|
+
return { handlers: [] };
|
|
341
346
|
}
|
|
342
347
|
}
|
|
343
348
|
async function deliver(entry, signal, reportDiagnostic, timeoutMs) {
|
|
@@ -347,6 +352,60 @@ async function deliver(entry, signal, reportDiagnostic, timeoutMs) {
|
|
|
347
352
|
if (result.kind === "failed")
|
|
348
353
|
reportPluginDiagnostic(reportDiagnostic, entry.pluginId, "signal", result.error);
|
|
349
354
|
}
|
|
355
|
+
async function closeWaitDeferral(pluginId, scope, reportDiagnostic) {
|
|
356
|
+
const result = await boundedAttempt((cancellation) => scope.close(cancellation));
|
|
357
|
+
if (result.kind === "timed-out")
|
|
358
|
+
reportPluginDiagnostic(reportDiagnostic, pluginId, "wait deferral cleanup", timeoutError());
|
|
359
|
+
if (result.kind === "failed")
|
|
360
|
+
reportPluginDiagnostic(reportDiagnostic, pluginId, "wait deferral cleanup", result.error);
|
|
361
|
+
}
|
|
362
|
+
async function acquireWaitDeferral({ pluginId, activation }, input, signal, deadline, reportDiagnostic) {
|
|
363
|
+
const controller = new AbortController();
|
|
364
|
+
const abort = () => controller.abort(signal?.reason);
|
|
365
|
+
if (signal?.aborted)
|
|
366
|
+
abort();
|
|
367
|
+
else
|
|
368
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
369
|
+
const cancellation = controller.signal;
|
|
370
|
+
const timer = setTimeout(() => controller.abort(timeoutError()), Math.max(0, deadline - performance.now()));
|
|
371
|
+
const completed = activation
|
|
372
|
+
.then(async (activated) => {
|
|
373
|
+
if (cancellation.aborted)
|
|
374
|
+
return undefined;
|
|
375
|
+
const value = await activated.waitDeferral?.(input, cancellation);
|
|
376
|
+
return value === undefined ? undefined : waitDeferralResource(value, pluginId, reportDiagnostic);
|
|
377
|
+
})
|
|
378
|
+
.catch((error) => {
|
|
379
|
+
if (!cancellation.aborted)
|
|
380
|
+
reportPluginDiagnostic(reportDiagnostic, pluginId, "wait deferral", error);
|
|
381
|
+
return undefined;
|
|
382
|
+
});
|
|
383
|
+
const result = await settleBefore(completed, cancellation);
|
|
384
|
+
clearTimeout(timer);
|
|
385
|
+
signal?.removeEventListener("abort", abort);
|
|
386
|
+
if (result !== ABORTED)
|
|
387
|
+
return result;
|
|
388
|
+
if (signal?.aborted !== true)
|
|
389
|
+
reportPluginDiagnostic(reportDiagnostic, pluginId, "wait deferral", timeoutError());
|
|
390
|
+
void completed.then(async (scope) => {
|
|
391
|
+
if (scope !== undefined)
|
|
392
|
+
await closeWaitDeferral(pluginId, scope, reportDiagnostic);
|
|
393
|
+
});
|
|
394
|
+
return undefined;
|
|
395
|
+
}
|
|
396
|
+
function waitDeferralResource(value, pluginId, reportDiagnostic) {
|
|
397
|
+
try {
|
|
398
|
+
const close = object(value) ? value.close : undefined;
|
|
399
|
+
if (typeof close !== "function")
|
|
400
|
+
throw new TypeError("resource close must be a function");
|
|
401
|
+
// Normal and late acquisition have disjoint cleanup paths; the plugin owns its close lifetime.
|
|
402
|
+
return { close: close.bind(value) };
|
|
403
|
+
}
|
|
404
|
+
catch (error) {
|
|
405
|
+
reportPluginDiagnostic(reportDiagnostic, pluginId, "wait deferral validation", error);
|
|
406
|
+
return undefined;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
350
409
|
export async function pluginRuntime(input) {
|
|
351
410
|
let runtime = PROCESS_RUNTIMES.get(input.world);
|
|
352
411
|
if (runtime === undefined) {
|
|
@@ -369,12 +428,12 @@ async function createPluginRuntime(input) {
|
|
|
369
428
|
const result = await boundedAttempt((cancellation) => activate({ selected: entry, world: input.world, activated, report, cancellation, onStarted: releaseStarted }));
|
|
370
429
|
releaseStarted();
|
|
371
430
|
if (result.kind === "settled")
|
|
372
|
-
return {
|
|
431
|
+
return { ...result.value, timedOut: false };
|
|
373
432
|
reportPluginDiagnostic(report, entry.id, "activation", result.kind === "failed" ? result.error : timeoutError());
|
|
374
433
|
return { handlers: [], timedOut: result.kind === "timed-out" };
|
|
375
434
|
});
|
|
376
435
|
previousStarted = started;
|
|
377
|
-
return activation;
|
|
436
|
+
return { pluginId: entry.id, activation };
|
|
378
437
|
});
|
|
379
438
|
return Object.freeze({
|
|
380
439
|
async emit(signal, reportDiagnostic = report) {
|
|
@@ -382,10 +441,10 @@ async function createPluginRuntime(input) {
|
|
|
382
441
|
const expiry = new AbortController();
|
|
383
442
|
const timer = setTimeout(() => expiry.abort(), PLUGIN_ATTEMPT_TIMEOUT_MS);
|
|
384
443
|
try {
|
|
385
|
-
await Promise.all(activations.map(async (
|
|
444
|
+
await Promise.all(activations.map(async ({ pluginId, activation }) => {
|
|
386
445
|
const activated = await settleBefore(activation, expiry.signal);
|
|
387
446
|
if (activated === ABORTED || activated.timedOut) {
|
|
388
|
-
reportPluginDiagnostic(reportDiagnostic,
|
|
447
|
+
reportPluginDiagnostic(reportDiagnostic, pluginId, "signal", timeoutError());
|
|
389
448
|
if (activated === ABORTED)
|
|
390
449
|
return;
|
|
391
450
|
}
|
|
@@ -398,5 +457,18 @@ async function createPluginRuntime(input) {
|
|
|
398
457
|
clearTimeout(timer);
|
|
399
458
|
}
|
|
400
459
|
},
|
|
460
|
+
async withWaitDeferrals(akumaIds, signal, action, reportDiagnostic = report) {
|
|
461
|
+
signal?.throwIfAborted();
|
|
462
|
+
const input = Object.freeze({ akumaIds: Object.freeze([...akumaIds]) });
|
|
463
|
+
const deadline = performance.now() + PLUGIN_ATTEMPT_TIMEOUT_MS;
|
|
464
|
+
const scopes = await Promise.all(activations.map((plugin) => acquireWaitDeferral(plugin, input, signal, deadline, reportDiagnostic)));
|
|
465
|
+
try {
|
|
466
|
+
signal?.throwIfAborted();
|
|
467
|
+
return await action();
|
|
468
|
+
}
|
|
469
|
+
finally {
|
|
470
|
+
await Promise.all(scopes.map((scope, index) => scope === undefined ? undefined : closeWaitDeferral(activations[index].pluginId, scope, reportDiagnostic)));
|
|
471
|
+
}
|
|
472
|
+
},
|
|
401
473
|
});
|
|
402
474
|
}
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astrosheep/keiyaku",
|
|
3
|
-
"version": "4.6.
|
|
3
|
+
"version": "4.6.15",
|
|
4
4
|
"workspaces": [
|
|
5
5
|
"plugins/square",
|
|
6
6
|
"plugins/paseo/forwarder"
|
|
@@ -81,8 +81,8 @@
|
|
|
81
81
|
"dependencies": {
|
|
82
82
|
"@agentclientprotocol/sdk": "^1.3.0",
|
|
83
83
|
"@anthropic-ai/claude-agent-sdk": "^0.3.226",
|
|
84
|
-
"@astrosheep/keiyaku-plugin-square": "0.1.
|
|
85
|
-
"@astrosheep/square": "^0.3.
|
|
84
|
+
"@astrosheep/keiyaku-plugin-square": "0.1.11",
|
|
85
|
+
"@astrosheep/square": "^0.3.91",
|
|
86
86
|
"@getpaseo/client": "0.11.2",
|
|
87
87
|
"@getpaseo/protocol": "0.11.2",
|
|
88
88
|
"@opencode/client": "2.0.20",
|
package/skills/keiyaku/SKILL.md
CHANGED
|
@@ -36,6 +36,9 @@ selects the Contract repository; it never retargets that World. `call
|
|
|
36
36
|
cwd). Without it, the call uses the invocation cwd; `--contract` associates a
|
|
37
37
|
Contract without selecting an execution directory.
|
|
38
38
|
|
|
39
|
+
An Akuma caller can find its own delegation tree with `keiyaku ls --mine` (or an
|
|
40
|
+
explicit `--caller`); see `keiyaku-akuma` for the roster and its text labels.
|
|
41
|
+
|
|
39
42
|
`deliver` and `review` may take time after their leading admission.
|
|
40
43
|
`deliver --dry-run` only observes the prospective candidate, standing evidence,
|
|
41
44
|
and target followability; it never runs Verification or hooks or admits work.
|
|
@@ -87,16 +87,36 @@ keiyaku status
|
|
|
87
87
|
keiyaku status @reviewer
|
|
88
88
|
keiyaku ls aku/
|
|
89
89
|
keiyaku ls "aku/*/*"
|
|
90
|
+
keiyaku ls --mine
|
|
90
91
|
keiyaku history @reviewer --last
|
|
91
92
|
keiyaku history @reviewer --id turn/3
|
|
92
93
|
```
|
|
93
94
|
|
|
94
95
|
`status` shows the roster or one Akuma's workdir and effective actions.
|
|
95
96
|
`ls aku/` shows callable names; `ls "aku/*/*"` shows born workers.
|
|
97
|
+
`ls --mine` narrows that roster to Akumas this process's caller called and their
|
|
98
|
+
transitive descendants in this World; `--caller <integration>:<id>` or
|
|
99
|
+
`--caller aku/<name>/<suffix>` names the same selection explicitly. Descendant
|
|
100
|
+
rows show their immediate caller as `· by <akuId>`. The selection is World-local
|
|
101
|
+
and refuses for Contract, Debt, and Akuma-name catalogues.
|
|
96
102
|
`history --last` reads the latest complete answer; `history --id` reads an
|
|
97
103
|
exact result named by status or wait. Use the complete AkuId when an alias may
|
|
98
104
|
move; see `history --help` for paging.
|
|
99
105
|
|
|
106
|
+
## Retention
|
|
107
|
+
|
|
108
|
+
An Akuma whose latest durable life or activity is older than fifteen days may be
|
|
109
|
+
retired after a later successful `call` or `fork`. Retention keeps any running
|
|
110
|
+
Akuma, any current alias target, any Akuma dispatched to a Contract that is not
|
|
111
|
+
yet `claimed` or `abandoned`, unborn or stillborn allocations, and unreadable
|
|
112
|
+
entries. It removes only the Akuma's recognized runtime custody; it never kills
|
|
113
|
+
a worker and never rewrites another Akuma, Contract, Debt, or alias. Its final
|
|
114
|
+
Heart re-read keeps a pending Tell it observes; a Tell admitted immediately
|
|
115
|
+
after that read is best-effort, not atomic. There is no timer and no prune
|
|
116
|
+
command. Observation and Tell commands (`status`, `ls`, `history`, `wait`,
|
|
117
|
+
`tell`, `ask`) never trigger retention; without a later successful
|
|
118
|
+
`call`/`fork`, old entries simply remain.
|
|
119
|
+
|
|
100
120
|
## Stop and branch
|
|
101
121
|
|
|
102
122
|
```bash
|