@astrosheep/keiyaku 4.5.19 → 4.5.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +14 -7
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +53 -20
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/references/automation.md +237 -0
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +6 -7
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-task/SKILL.md +2 -4
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +3 -3
- package/build/src/akuma/akuma-handle.d.ts +5 -1
- package/build/src/akuma/akuma-handle.js +4 -1
- package/build/src/akuma/akuma-instance.d.ts +7 -2
- package/build/src/akuma/akuma-instance.js +14 -7
- package/build/src/akuma/akuma-observe.d.ts +11 -0
- package/build/src/akuma/akuma-observe.js +23 -0
- package/build/src/akuma/akuma-product.d.ts +2 -0
- package/build/src/akuma/akuma-product.js +6 -0
- package/build/src/akuma/akuma.d.ts +20 -1
- package/build/src/akuma/akuma.js +2 -0
- package/build/src/akuma/allowed.d.ts +20 -0
- package/build/src/akuma/allowed.js +11 -0
- package/build/src/akuma/archetype.js +3 -0
- package/build/src/akuma/body.d.ts +25 -5
- package/build/src/akuma/body.js +70 -31
- package/build/src/akuma/call-request.d.ts +5 -0
- package/build/src/akuma/call-request.js +14 -4
- package/build/src/akuma/fleet-execution.d.ts +28 -0
- package/build/src/akuma/fleet-execution.js +36 -4
- package/build/src/akuma/fleet-observation.d.ts +54 -0
- package/build/src/akuma/fleet-request.d.ts +10 -0
- package/build/src/akuma/fleet-request.js +13 -3
- package/build/src/akuma/heart/facts.d.ts +2 -0
- 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 +2 -0
- package/build/src/akuma/heart/rows.js +7 -5
- package/build/src/akuma/heart/schema.d.ts +1 -1
- package/build/src/akuma/heart/schema.js +3 -1
- package/build/src/akuma/heart/tells.js +6 -5
- package/build/src/akuma/heart/timeline.js +1 -1
- package/build/src/akuma/provider-recipe.d.ts +1 -0
- package/build/src/akuma/provider-recipe.js +5 -0
- package/build/src/akuma/provider.d.ts +1 -1
- package/build/src/akuma/provider.js +1 -1
- package/build/src/akuma/providers/acp/core.js +3 -6
- package/build/src/akuma/providers/acp/index.js +3 -0
- package/build/src/akuma/providers/claude/index.js +10 -10
- package/build/src/akuma/providers/codex-app-server/index.js +12 -11
- package/build/src/akuma/providers/execution-environment.d.ts +6 -0
- package/build/src/akuma/providers/execution-environment.js +24 -0
- package/build/src/akuma/providers/grok-build/index.js +3 -0
- package/build/src/akuma/providers/opencode-sdk/index.js +32 -23
- package/build/src/akuma/providers/opencode-sdk/session.d.ts +8 -1
- package/build/src/akuma/providers/opencode-sdk/session.js +6 -5
- package/build/src/akuma/providers/pi/events.js +7 -2
- package/build/src/akuma/providers/pi/index.js +5 -2
- package/build/src/akuma/request-observation.d.ts +45 -0
- package/build/src/akuma/request-observation.js +162 -0
- package/build/src/akuma/request-rendezvous.d.ts +6 -3
- package/build/src/akuma/request-rendezvous.js +80 -14
- package/build/src/akuma/request-serve.js +27 -4
- package/build/src/akuma/request-wire.d.ts +5 -0
- package/build/src/akuma/request-wire.js +2 -0
- package/build/src/akuma/turn-drive.d.ts +1 -0
- package/build/src/akuma/turn-drive.js +2 -0
- package/build/src/akuma-body.js +5 -0
- package/build/src/body/amend.js +6 -4
- package/build/src/body/decode.d.ts +3 -1
- package/build/src/body/decode.js +53 -17
- package/build/src/body/region.d.ts +9 -1
- package/build/src/body/region.js +87 -12
- package/build/src/body/render.js +1 -1
- package/build/src/body/verification.d.ts +3 -1
- package/build/src/body/verification.js +4 -1
- package/build/src/cli/accepted.js +19 -2
- package/build/src/cli/commands/akuma-invoke.d.ts +3 -1
- package/build/src/cli/commands/akuma-invoke.js +134 -14
- package/build/src/cli/commands/akuma.js +24 -12
- package/build/src/cli/commands/contract-help.d.ts +15 -15
- package/build/src/cli/commands/contract-help.js +45 -19
- package/build/src/cli/commands/contract-invoke.d.ts +3 -0
- package/build/src/cli/commands/contract-invoke.js +25 -11
- package/build/src/cli/commands/contract.js +6 -4
- package/build/src/cli/commands/install.d.ts +1 -1
- package/build/src/cli/commands/install.js +1 -1
- package/build/src/cli/commands/status-set.js +15 -24
- package/build/src/cli/commands/task.js +18 -18
- package/build/src/cli/invoke.d.ts +3 -0
- package/build/src/cli/invoke.js +58 -23
- package/build/src/cli/main.js +5 -0
- package/build/src/cli/parse.d.ts +3 -0
- package/build/src/cli/parse.js +26 -4
- package/build/src/cli/render/akuma-activity.d.ts +100 -2
- package/build/src/cli/render/akuma-activity.js +485 -40
- package/build/src/cli/render/akuma.d.ts +10 -0
- package/build/src/cli/render/akuma.js +31 -21
- package/build/src/cli/render/audit.js +1 -1
- package/build/src/cli/render/board.js +1 -1
- package/build/src/cli/render/catalog.js +16 -13
- package/build/src/cli/render/contract-history.js +39 -10
- package/build/src/cli/render/contract-observation.js +10 -6
- package/build/src/cli/render/contract.js +109 -106
- package/build/src/cli/render/execution-progress.d.ts +26 -0
- package/build/src/cli/render/execution-progress.js +178 -0
- package/build/src/cli/render/kanshi-akuma.js +27 -39
- package/build/src/cli/render/kanshi.js +33 -26
- package/build/src/cli/render/nuke.js +1 -1
- package/build/src/cli/render/receipt.d.ts +1 -1
- package/build/src/cli/render/receipt.js +6 -6
- package/build/src/cli/render/refusal.js +10 -7
- package/build/src/cli/render/region.js +1 -1
- package/build/src/cli/render/settings.js +12 -2
- package/build/src/cli/render/status-line.d.ts +30 -0
- package/build/src/cli/render/status-line.js +58 -0
- package/build/src/cli/render/status-set.js +1 -1
- package/build/src/cli/render/task.d.ts +2 -0
- package/build/src/cli/render/task.js +11 -7
- package/build/src/cli/render/terminal.d.ts +0 -1
- package/build/src/cli/render/terminal.js +47 -15
- package/build/src/cli/result.d.ts +1 -0
- package/build/src/cli/runtime.d.ts +2 -0
- package/build/src/cli/runtime.js +36 -4
- package/build/src/cli/usage.js +2 -2
- package/build/src/cli/version.d.ts +1 -0
- package/build/src/cli/version.js +25 -0
- package/build/src/git/hooks.d.ts +13 -1
- package/build/src/git/hooks.js +2 -1
- package/build/src/git/workspace.d.ts +1 -1
- package/build/src/git/workspace.js +1 -1
- package/build/src/identity/mint.d.ts +13 -0
- package/build/src/identity/mint.js +26 -0
- package/build/src/identity/normalize.d.ts +4 -0
- package/build/src/identity/normalize.js +30 -0
- package/build/src/index.d.ts +2 -0
- package/build/src/index.js +1 -0
- package/build/src/kanshi/read.js +17 -4
- package/build/src/kanshi/report.d.ts +1 -0
- package/build/src/library/akuma-creation.d.ts +2 -0
- package/build/src/library/akuma-creation.js +34 -18
- package/build/src/library/audit.d.ts +2 -0
- package/build/src/library/audit.js +1 -0
- package/build/src/library/bind.js +18 -16
- package/build/src/library/composition.d.ts +1 -0
- package/build/src/library/contract-bind.d.ts +3 -1
- package/build/src/library/contract-bind.js +5 -3
- package/build/src/library/contract-execution.d.ts +2 -0
- package/build/src/library/contract-execution.js +15 -1
- package/build/src/library/contract-forwarding.d.ts +4 -0
- package/build/src/library/contract-forwarding.js +3 -0
- package/build/src/library/contract-handle.d.ts +7 -0
- package/build/src/library/contract-handle.js +25 -0
- package/build/src/library/contract-operations.d.ts +7 -2
- package/build/src/library/contract-operations.js +21 -1
- package/build/src/library/contract-types.d.ts +1 -0
- package/build/src/library/execution-result.d.ts +2 -2
- package/build/src/library/execution.d.ts +8 -0
- package/build/src/library/execution.js +102 -0
- package/build/src/library/fleet.d.ts +4 -1
- package/build/src/library/fleet.js +32 -8
- package/build/src/library/keiyaku.d.ts +2 -0
- package/build/src/library/mutation.js +15 -7
- package/build/src/plugin/akuma-signals.d.ts +6 -0
- package/build/src/plugin/akuma-signals.js +9 -1
- package/build/src/plugin/public.d.ts +6 -2
- package/build/src/plugin/runtime.d.ts +1 -3
- package/build/src/plugin/runtime.js +95 -103
- package/build/src/protocol/amend.js +4 -3
- package/build/src/protocol/attempt.d.ts +2 -0
- package/build/src/protocol/bind.js +41 -14
- package/build/src/protocol/completion.d.ts +3 -0
- package/build/src/protocol/completion.js +35 -11
- package/build/src/protocol/deliver.js +165 -92
- package/build/src/protocol/execution-observation.d.ts +181 -0
- package/build/src/protocol/execution-observation.js +45 -0
- package/build/src/protocol/intent.d.ts +18 -22
- package/build/src/protocol/intent.js +63 -41
- package/build/src/protocol/operations.d.ts +2 -0
- package/build/src/protocol/placement.js +5 -1
- package/build/src/protocol/progress.d.ts +5 -1
- package/build/src/protocol/progress.js +10 -1
- package/build/src/protocol/read/status.d.ts +1 -0
- package/build/src/protocol/read/status.js +10 -2
- package/build/src/protocol/reintegrate.d.ts +1 -1
- package/build/src/protocol/reintegrate.js +70 -43
- package/build/src/protocol/result-codec.js +27 -11
- package/build/src/protocol/review.js +53 -30
- package/build/src/protocol/run.d.ts +83 -36
- package/build/src/protocol/run.js +90 -75
- package/build/src/runtime/proc/run.d.ts +16 -4
- package/build/src/runtime/proc/run.js +64 -22
- package/build/src/runtime/proc/windows-launch.exe +0 -0
- package/build/src/settings.js +5 -14
- package/build/src/task/document.d.ts +5 -1
- package/build/src/task/document.js +6 -1
- package/build/src/verification/execution.d.ts +10 -2
- package/build/src/verification/execution.js +143 -42
- package/build/src/verification/observation.d.ts +41 -0
- package/build/src/verification/observation.js +29 -0
- package/package.json +3 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
import { open } from "node:fs/promises";
|
|
3
|
+
import { StringDecoder } from "node:string_decoder";
|
|
3
4
|
import crossSpawn from "cross-spawn";
|
|
4
5
|
import { spawnOptionsFor } from "./launch.js";
|
|
5
6
|
import { detachedExitStatus, retainDetachedExitEvidence } from "./process-exit.js";
|
|
@@ -73,7 +74,10 @@ function tailCapture(limit) {
|
|
|
73
74
|
const size = Math.min(total, limit);
|
|
74
75
|
const start = total > limit ? cursor : 0;
|
|
75
76
|
const value = start === 0 ? bytes.subarray(0, size) : Buffer.concat([bytes.subarray(start), bytes.subarray(0, start)]);
|
|
76
|
-
|
|
77
|
+
let startAt = 0;
|
|
78
|
+
while (startAt < value.length && (value[startAt] & 0xc0) === 0x80)
|
|
79
|
+
startAt += 1;
|
|
80
|
+
return { text: value.subarray(startAt).toString("utf8"), truncated: total > limit };
|
|
77
81
|
},
|
|
78
82
|
};
|
|
79
83
|
}
|
|
@@ -137,21 +141,55 @@ export async function spawnDetachedProcess(input) {
|
|
|
137
141
|
await log.close();
|
|
138
142
|
}
|
|
139
143
|
}
|
|
140
|
-
function
|
|
144
|
+
function capturedOutput(stdout, stderr, consuming) {
|
|
141
145
|
return {
|
|
142
|
-
kind: "terminal",
|
|
143
|
-
code,
|
|
144
146
|
stdout: consuming ? "" : stdout.text,
|
|
145
147
|
stderr: stderr.text,
|
|
146
148
|
truncated: (consuming ? false : stdout.truncated) || stderr.truncated,
|
|
147
149
|
};
|
|
148
150
|
}
|
|
151
|
+
function outputObservation(input, consumingStdout) {
|
|
152
|
+
const decoders = input.onOutput === undefined
|
|
153
|
+
? undefined
|
|
154
|
+
: {
|
|
155
|
+
...(consumingStdout ? {} : { stdout: new StringDecoder("utf8") }),
|
|
156
|
+
stderr: new StringDecoder("utf8"),
|
|
157
|
+
};
|
|
158
|
+
const report = (stream, text) => {
|
|
159
|
+
if (text.length === 0)
|
|
160
|
+
return;
|
|
161
|
+
try {
|
|
162
|
+
input.onOutput?.({ stream, text });
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
// Observation is not process ownership: a consumer cannot strand the owned child.
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
return {
|
|
169
|
+
observe(stream, chunk) {
|
|
170
|
+
const decoder = decoders?.[stream];
|
|
171
|
+
if (decoder !== undefined)
|
|
172
|
+
report(stream, decoder.write(chunk));
|
|
173
|
+
},
|
|
174
|
+
finish() {
|
|
175
|
+
if (decoders === undefined)
|
|
176
|
+
return;
|
|
177
|
+
for (const stream of ["stdout", "stderr"]) {
|
|
178
|
+
const decoder = decoders[stream];
|
|
179
|
+
if (decoder !== undefined)
|
|
180
|
+
report(stream, decoder.end());
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
};
|
|
184
|
+
}
|
|
149
185
|
async function executeProcess(input, timeoutMs, consumeStdout, spawnProcess = spawn) {
|
|
150
|
-
if (input.signal?.aborted === true)
|
|
151
|
-
return { outcome: { kind: "cancelled" }, pid: null };
|
|
186
|
+
if (input.signal?.aborted === true) {
|
|
187
|
+
return { outcome: { kind: "cancelled", stdout: "", stderr: "", truncated: false }, pid: null };
|
|
188
|
+
}
|
|
152
189
|
const child = spawnProcess(input.argv[0], input.argv.slice(1), spawnOptionsFor(input, ["ignore", "pipe", "pipe"]));
|
|
153
190
|
const stdout = tailCapture(STREAM_TAIL_BYTES);
|
|
154
191
|
const stderr = tailCapture(STREAM_TAIL_BYTES);
|
|
192
|
+
const output = outputObservation(input, consumeStdout !== undefined);
|
|
155
193
|
let stop;
|
|
156
194
|
let streamError;
|
|
157
195
|
let termination;
|
|
@@ -175,16 +213,21 @@ async function executeProcess(input, timeoutMs, consumeStdout, spawnProcess = sp
|
|
|
175
213
|
child.stdout.on("data", (chunk) => {
|
|
176
214
|
if (consumeStdout === undefined) {
|
|
177
215
|
stdout.append(chunk);
|
|
178
|
-
return;
|
|
179
|
-
}
|
|
180
|
-
try {
|
|
181
|
-
consumeStdout(chunk);
|
|
182
216
|
}
|
|
183
|
-
|
|
184
|
-
|
|
217
|
+
else {
|
|
218
|
+
try {
|
|
219
|
+
consumeStdout(chunk);
|
|
220
|
+
}
|
|
221
|
+
catch (error) {
|
|
222
|
+
failStream(error);
|
|
223
|
+
}
|
|
185
224
|
}
|
|
225
|
+
output.observe("stdout", chunk);
|
|
226
|
+
});
|
|
227
|
+
child.stderr.on("data", (chunk) => {
|
|
228
|
+
stderr.append(chunk);
|
|
229
|
+
output.observe("stderr", chunk);
|
|
186
230
|
});
|
|
187
|
-
child.stderr.on("data", (chunk) => stderr.append(chunk));
|
|
188
231
|
if (consumeStdout !== undefined) {
|
|
189
232
|
child.stdout.once("error", failStream);
|
|
190
233
|
child.stderr.once("error", failStream);
|
|
@@ -199,29 +242,28 @@ async function executeProcess(input, timeoutMs, consumeStdout, spawnProcess = sp
|
|
|
199
242
|
if (terminal.kind === "termination-error")
|
|
200
243
|
throw terminal.error;
|
|
201
244
|
await termination;
|
|
245
|
+
output.finish();
|
|
202
246
|
const pid = child.pid ?? null;
|
|
247
|
+
const capture = capturedOutput(stdout.result(), stderr.result(), consumeStdout !== undefined);
|
|
203
248
|
if (terminal.kind === "spawn-error") {
|
|
204
|
-
return { outcome: { kind: "spawn-error", diagnostic: terminal.error.message }, pid };
|
|
249
|
+
return { outcome: { kind: "spawn-error", diagnostic: terminal.error.message, ...capture }, pid };
|
|
205
250
|
}
|
|
206
251
|
if (streamError !== undefined) {
|
|
207
252
|
return {
|
|
208
253
|
outcome: {
|
|
209
254
|
kind: "stream-error",
|
|
210
255
|
diagnostic: streamError instanceof Error ? streamError.message : String(streamError),
|
|
256
|
+
stderr: capture.stderr,
|
|
257
|
+
truncated: capture.truncated,
|
|
211
258
|
},
|
|
212
259
|
pid,
|
|
213
260
|
};
|
|
214
261
|
}
|
|
215
262
|
if (stop !== undefined)
|
|
216
|
-
return { outcome: { kind: stop }, pid };
|
|
263
|
+
return { outcome: { kind: stop, ...capture }, pid };
|
|
217
264
|
if (terminal.code === null)
|
|
218
|
-
return { outcome: { kind: "unknown-exit" }, pid };
|
|
219
|
-
|
|
220
|
-
const capturedStderr = stderr.result();
|
|
221
|
-
return {
|
|
222
|
-
outcome: terminalOutcome(terminal.code, capturedStdout, capturedStderr, consumeStdout !== undefined),
|
|
223
|
-
pid,
|
|
224
|
-
};
|
|
265
|
+
return { outcome: { kind: "unknown-exit", ...capture }, pid };
|
|
266
|
+
return { outcome: { kind: "terminal", code: terminal.code, ...capture }, pid };
|
|
225
267
|
}
|
|
226
268
|
export async function runProcess(input) {
|
|
227
269
|
const result = await executeProcess(input, input.timeoutMs);
|
|
Binary file
|
package/build/src/settings.js
CHANGED
|
@@ -152,9 +152,6 @@ function bundleGates(name, value) {
|
|
|
152
152
|
if (!gateWord(gate)) {
|
|
153
153
|
throw new SettingsError(`gate bundle '${name}' contains an invalid gate word`);
|
|
154
154
|
}
|
|
155
|
-
if (gate !== "reviewed" && gate !== "verified") {
|
|
156
|
-
throw new SettingsError(`gate bundle '${name}' contains a gate without a producer: ${gate}`);
|
|
157
|
-
}
|
|
158
155
|
return gate;
|
|
159
156
|
});
|
|
160
157
|
}
|
|
@@ -167,8 +164,10 @@ export function gatesFrom(input) {
|
|
|
167
164
|
const names = input.names ?? ["default"];
|
|
168
165
|
for (const name of names) {
|
|
169
166
|
if (!gateWord(name))
|
|
170
|
-
throw new SettingsError("gate bundle name must match ^[a-z][a-z0-9-]{0,63}$");
|
|
167
|
+
throw new SettingsError("gate or bundle name must match ^[a-z][a-z0-9-]{0,63}$");
|
|
171
168
|
}
|
|
169
|
+
if (names.length === 0)
|
|
170
|
+
return Object.freeze([]);
|
|
172
171
|
const view = input.settings.namespace("gates");
|
|
173
172
|
if (view.kind === "failed")
|
|
174
173
|
namespaceFailure(view);
|
|
@@ -176,16 +175,8 @@ export function gatesFrom(input) {
|
|
|
176
175
|
const seen = new Set();
|
|
177
176
|
for (const name of names) {
|
|
178
177
|
const selected = view.entries.find((entry) => entry.name === name);
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
if (!seen.has("reviewed"))
|
|
182
|
-
expanded.push("reviewed");
|
|
183
|
-
seen.add("reviewed");
|
|
184
|
-
continue;
|
|
185
|
-
}
|
|
186
|
-
throw new SettingsError(`unknown gate bundle: ${name}`);
|
|
187
|
-
}
|
|
188
|
-
for (const gate of bundleGates(name, selected.value)) {
|
|
178
|
+
const gates = selected === undefined ? [input.names === undefined ? "reviewed" : name] : bundleGates(name, selected.value);
|
|
179
|
+
for (const gate of gates) {
|
|
189
180
|
if (seen.has(gate))
|
|
190
181
|
continue;
|
|
191
182
|
seen.add(gate);
|
|
@@ -18,7 +18,11 @@ export type TaskDocument = Readonly<{
|
|
|
18
18
|
}>;
|
|
19
19
|
export type TaskCreationDocument = Omit<TaskDocument, "id" | "createdBy" | "createdAt" | "updatedAt">;
|
|
20
20
|
export declare class TaskAuthorityCorruptionError extends Error {
|
|
21
|
-
|
|
21
|
+
/** The Task document whose bytes failed decode, when the reader knew its coordinate. */
|
|
22
|
+
readonly coordinate?: TaskId;
|
|
23
|
+
constructor(message: string, options?: ErrorOptions & {
|
|
24
|
+
coordinate?: TaskId;
|
|
25
|
+
});
|
|
22
26
|
}
|
|
23
27
|
export declare function parseTaskDocument(bytes: Uint8Array, expected: TaskCoordinate): TaskDocument;
|
|
24
28
|
export declare function parseTaskCreationDocument(markdown: string): TaskCreationDocument;
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { isMap, parseDocument, stringify } from "yaml";
|
|
2
2
|
import { formatTaskId, parseTaskId } from "./identity.js";
|
|
3
3
|
export class TaskAuthorityCorruptionError extends Error {
|
|
4
|
+
/** The Task document whose bytes failed decode, when the reader knew its coordinate. */
|
|
5
|
+
coordinate;
|
|
4
6
|
constructor(message, options) {
|
|
5
7
|
super(message, options);
|
|
6
8
|
this.name = "TaskAuthorityCorruptionError";
|
|
9
|
+
if (options?.coordinate !== undefined)
|
|
10
|
+
this.coordinate = options.coordinate;
|
|
7
11
|
}
|
|
8
12
|
}
|
|
9
13
|
const STATES = new Set(["open", "in_progress", "on_hold", "done", "drop"]);
|
|
@@ -107,8 +111,9 @@ function fields(value, body, fail) {
|
|
|
107
111
|
};
|
|
108
112
|
}
|
|
109
113
|
export function parseTaskDocument(bytes, expected) {
|
|
114
|
+
const coordinate = formatTaskId(expected);
|
|
110
115
|
const fail = (message, cause) => {
|
|
111
|
-
throw new TaskAuthorityCorruptionError(message, cause === undefined ? {} : { cause });
|
|
116
|
+
throw new TaskAuthorityCorruptionError(message, { coordinate, ...(cause === undefined ? {} : { cause }) });
|
|
112
117
|
};
|
|
113
118
|
const { value, body } = frontMatter(Buffer.from(bytes).toString("utf8"), fail);
|
|
114
119
|
closed(value, STORED_KEYS, REQUIRED_STORED_KEYS, fail);
|
|
@@ -3,6 +3,7 @@ import { type HookFailure } from "../git/hooks.js";
|
|
|
3
3
|
import type { MaterializedScratchCandidate, WorktreeLeak } from "../git/scratch.js";
|
|
4
4
|
import type { GitRepository } from "../git/process.js";
|
|
5
5
|
import type { Settings } from "../settings.js";
|
|
6
|
+
import type { VerificationObservation } from "./observation.js";
|
|
6
7
|
import type { VerificationDeclaration } from "./declaration.js";
|
|
7
8
|
type VerificationVerdict = "satisfied" | "unsatisfied";
|
|
8
9
|
export type VerificationTerminalOutcome = Readonly<{
|
|
@@ -12,14 +13,20 @@ export type VerificationTerminalOutcome = Readonly<{
|
|
|
12
13
|
total: number;
|
|
13
14
|
summary?: string;
|
|
14
15
|
}>;
|
|
15
|
-
export type
|
|
16
|
+
export type CapturedOutput = Readonly<{
|
|
17
|
+
stdout?: string;
|
|
18
|
+
stderr?: string;
|
|
19
|
+
truncated?: boolean;
|
|
20
|
+
}>;
|
|
21
|
+
export type VerificationNonterminalOutcome = CapturedOutput & (Readonly<{
|
|
16
22
|
kind: "unknown-exit";
|
|
17
23
|
}> | Readonly<{
|
|
18
24
|
kind: "cancelled";
|
|
19
25
|
}> | Readonly<{
|
|
20
26
|
kind: "spawn-error";
|
|
21
27
|
diagnostic: string;
|
|
22
|
-
}
|
|
28
|
+
}>);
|
|
29
|
+
export declare function capturedOutput(value: CapturedOutput): CapturedOutput;
|
|
23
30
|
export type VerificationExecutionStop = VerificationNonterminalOutcome | Readonly<{
|
|
24
31
|
kind: "candidate-unavailable" | "environment-failure";
|
|
25
32
|
diagnostic: string;
|
|
@@ -43,6 +50,7 @@ export type ExecuteVerificationInput = Readonly<{
|
|
|
43
50
|
declarations: readonly VerificationDeclaration[];
|
|
44
51
|
materializeScratchCandidate: (repository: GitRepository, candidate: SnapshotId) => Promise<MaterializedScratchCandidate>;
|
|
45
52
|
projectSettings: (root: string) => Promise<Settings>;
|
|
53
|
+
observe?: (event: VerificationObservation) => void;
|
|
46
54
|
signal?: AbortSignal;
|
|
47
55
|
}>;
|
|
48
56
|
/** Execute one disposable Verification attempt over the exact integration snapshot. */
|
|
@@ -1,6 +1,28 @@
|
|
|
1
1
|
import { runHookCommands, worktreeHooksFrom } from "../git/hooks.js";
|
|
2
2
|
import { runProcess } from "../runtime/proc/run.js";
|
|
3
3
|
const SUMMARY_BYTES = 32 * 1024;
|
|
4
|
+
export function capturedOutput(value) {
|
|
5
|
+
return {
|
|
6
|
+
...(value.stdout ? { stdout: value.stdout } : {}),
|
|
7
|
+
...(value.stderr ? { stderr: value.stderr } : {}),
|
|
8
|
+
...(value.truncated === true ? { truncated: true } : {}),
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
function observe(input, event) {
|
|
12
|
+
try {
|
|
13
|
+
input.observe?.(event);
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
/* Observation does not own execution. */
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function outputSummary(output) {
|
|
20
|
+
return [
|
|
21
|
+
...(output.stdout ? [`stdout:\n${output.stdout}`] : []),
|
|
22
|
+
...(output.stderr ? [`stderr:\n${output.stderr}`] : []),
|
|
23
|
+
...(output.truncated ? ["[output truncated]"] : []),
|
|
24
|
+
].join("\n");
|
|
25
|
+
}
|
|
4
26
|
function argvFor(declaration) {
|
|
5
27
|
const args = declaration.executor === "pwsh" ? ["-Command", declaration.script] : ["-c", declaration.script];
|
|
6
28
|
return [declaration.executor, ...args];
|
|
@@ -27,26 +49,63 @@ function appendSummary(current, diagnostic) {
|
|
|
27
49
|
start += 1;
|
|
28
50
|
return Buffer.concat([marker, combined.subarray(start)]).toString("utf8");
|
|
29
51
|
}
|
|
52
|
+
async function observedHooks(input) {
|
|
53
|
+
const { execution, cwd, commands, phase, signal, environment } = input;
|
|
54
|
+
for (const command of commands) {
|
|
55
|
+
const coordinate = { phase, cwd, name: command.name };
|
|
56
|
+
const started = performance.now();
|
|
57
|
+
observe(execution, { kind: "phase", ...coordinate, state: "started" });
|
|
58
|
+
const result = await runHookCommands(cwd, [command], signal, environment, (output) => observe(execution, { kind: "output", ...coordinate, ...output }));
|
|
59
|
+
observe(execution, {
|
|
60
|
+
kind: "phase",
|
|
61
|
+
...coordinate,
|
|
62
|
+
state: "finished",
|
|
63
|
+
outcome: result.kind,
|
|
64
|
+
elapsedMs: performance.now() - started,
|
|
65
|
+
});
|
|
66
|
+
if (result.kind !== "ok")
|
|
67
|
+
return result;
|
|
68
|
+
}
|
|
69
|
+
return { kind: "ok" };
|
|
70
|
+
}
|
|
71
|
+
function nonterminalOutcome(outcome) {
|
|
72
|
+
return outcome.kind === "spawn-error"
|
|
73
|
+
? { kind: outcome.kind, diagnostic: outcome.diagnostic, ...capturedOutput(outcome) }
|
|
74
|
+
: { kind: outcome.kind, ...capturedOutput(outcome) };
|
|
75
|
+
}
|
|
30
76
|
async function executeDeclarations(input) {
|
|
31
77
|
let verdict = "satisfied";
|
|
32
78
|
let passed = 0;
|
|
33
79
|
const total = input.declarations.length;
|
|
34
80
|
let summary;
|
|
35
81
|
for (const [index, declaration] of input.declarations.entries()) {
|
|
82
|
+
const coordinate = { phase: "declaration", cwd: input.cwd, index: index + 1, total };
|
|
83
|
+
const started = performance.now();
|
|
84
|
+
observe(input, { kind: "phase", ...coordinate, state: "started" });
|
|
36
85
|
const outcome = await runProcess({
|
|
37
86
|
argv: argvFor(declaration),
|
|
38
87
|
cwd: input.cwd,
|
|
39
88
|
env: input.environment,
|
|
89
|
+
onOutput: (output) => observe(input, { kind: "output", ...coordinate, ...output }),
|
|
40
90
|
...(input.signal === undefined ? {} : { signal: input.signal }),
|
|
41
91
|
...(declaration.timeoutMs === undefined ? {} : { timeoutMs: declaration.timeoutMs }),
|
|
42
92
|
});
|
|
93
|
+
observe(input, {
|
|
94
|
+
kind: "phase",
|
|
95
|
+
...coordinate,
|
|
96
|
+
state: "finished",
|
|
97
|
+
outcome: outcome.kind === "terminal" ? `exit ${outcome.code}` : outcome.kind,
|
|
98
|
+
elapsedMs: performance.now() - started,
|
|
99
|
+
});
|
|
43
100
|
if (outcome.kind === "timeout") {
|
|
44
101
|
verdict = "unsatisfied";
|
|
45
|
-
summary = appendSummary(summary, `[${index + 1} ${declaration.executor} timeout after ${declaration.timeoutMs}ms]
|
|
102
|
+
summary = appendSummary(summary, [`[${index + 1} ${declaration.executor} timeout after ${declaration.timeoutMs}ms]`, outputSummary(outcome)]
|
|
103
|
+
.filter(Boolean)
|
|
104
|
+
.join("\n"));
|
|
46
105
|
continue;
|
|
47
106
|
}
|
|
48
107
|
if (outcome.kind === "spawn-error" || outcome.kind === "unknown-exit" || outcome.kind === "cancelled")
|
|
49
|
-
return outcome;
|
|
108
|
+
return nonterminalOutcome(outcome);
|
|
50
109
|
if (outcome.code === 0)
|
|
51
110
|
passed += 1;
|
|
52
111
|
else
|
|
@@ -55,58 +114,100 @@ async function executeDeclarations(input) {
|
|
|
55
114
|
}
|
|
56
115
|
return { kind: "terminal", verdict, passed, total, ...(summary === undefined ? {} : { summary }) };
|
|
57
116
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const environment = process.env;
|
|
61
|
-
let scratch;
|
|
117
|
+
async function materializeScratch(input) {
|
|
118
|
+
observe(input, { kind: "phase", phase: "materialize", state: "started" });
|
|
62
119
|
try {
|
|
63
|
-
|
|
120
|
+
input.signal?.throwIfAborted();
|
|
121
|
+
const scratch = await input.materializeScratchCandidate(input.repository, input.candidate);
|
|
122
|
+
observe(input, { kind: "phase", phase: "materialize", state: "finished", cwd: scratch.cwd, outcome: "ok" });
|
|
123
|
+
return scratch;
|
|
64
124
|
}
|
|
65
125
|
catch (error) {
|
|
126
|
+
observe(input, {
|
|
127
|
+
kind: "phase",
|
|
128
|
+
phase: "materialize",
|
|
129
|
+
state: "finished",
|
|
130
|
+
outcome: input.signal?.aborted ? "cancelled" : "failed",
|
|
131
|
+
});
|
|
132
|
+
if (input.signal?.aborted)
|
|
133
|
+
return { outcome: { kind: "cancelled" } };
|
|
66
134
|
return {
|
|
67
135
|
outcome: { kind: "candidate-unavailable", diagnostic: error instanceof Error ? error.message : String(error) },
|
|
68
136
|
};
|
|
69
137
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
let leak = null;
|
|
73
|
-
let destroy;
|
|
138
|
+
}
|
|
139
|
+
async function runScratch(input, scratch) {
|
|
74
140
|
try {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
141
|
+
input.signal?.throwIfAborted();
|
|
142
|
+
const hooks = worktreeHooksFrom({ settings: await input.projectSettings(scratch.cwd) });
|
|
143
|
+
const readiness = await observedHooks({
|
|
144
|
+
execution: input,
|
|
145
|
+
cwd: scratch.cwd,
|
|
146
|
+
commands: hooks.create,
|
|
147
|
+
phase: "setup",
|
|
148
|
+
...(input.signal === undefined ? {} : { signal: input.signal }),
|
|
149
|
+
environment: process.env,
|
|
150
|
+
});
|
|
151
|
+
if (readiness.kind === "cancelled")
|
|
152
|
+
return { outcome: { kind: "cancelled", ...capturedOutput(readiness) }, destroy: hooks.destroy };
|
|
153
|
+
if (readiness.kind === "failed")
|
|
154
|
+
return {
|
|
155
|
+
outcome: { kind: "environment-failure", name: readiness.name, detail: readiness.failure },
|
|
156
|
+
destroy: hooks.destroy,
|
|
157
|
+
};
|
|
158
|
+
return {
|
|
159
|
+
outcome: await executeDeclarations({
|
|
160
|
+
declarations: input.declarations,
|
|
161
|
+
cwd: scratch.cwd,
|
|
162
|
+
environment: process.env,
|
|
163
|
+
...(input.observe === undefined ? {} : { observe: input.observe }),
|
|
164
|
+
...(input.signal === undefined ? {} : { signal: input.signal }),
|
|
165
|
+
}),
|
|
166
|
+
destroy: hooks.destroy,
|
|
167
|
+
};
|
|
94
168
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
cleanup = { phase: "destroy", name: result.name, detail: result.failure };
|
|
102
|
-
}
|
|
103
|
-
leak = await scratch.dispose();
|
|
169
|
+
catch (error) {
|
|
170
|
+
return {
|
|
171
|
+
outcome: input.signal?.aborted
|
|
172
|
+
? { kind: "cancelled" }
|
|
173
|
+
: { kind: "environment-failure", diagnostic: error instanceof Error ? error.message : String(error) },
|
|
174
|
+
};
|
|
104
175
|
}
|
|
105
|
-
|
|
106
|
-
|
|
176
|
+
}
|
|
177
|
+
async function retireScratch(input, scratch, destroy) {
|
|
178
|
+
observe(input, { kind: "phase", phase: "cleanup", cwd: scratch.cwd, state: "started" });
|
|
179
|
+
let cleanup;
|
|
180
|
+
if (destroy !== undefined) {
|
|
181
|
+
const result = await observedHooks({
|
|
182
|
+
execution: input,
|
|
183
|
+
cwd: scratch.cwd,
|
|
184
|
+
commands: destroy,
|
|
185
|
+
phase: "cleanup",
|
|
186
|
+
environment: process.env,
|
|
187
|
+
});
|
|
188
|
+
if (result.kind === "cancelled")
|
|
189
|
+
throw new Error("scratch destroy cancelled without a signal");
|
|
190
|
+
if (result.kind === "failed")
|
|
191
|
+
cleanup = { phase: "destroy", name: result.name, detail: result.failure };
|
|
192
|
+
}
|
|
193
|
+
const leak = await scratch.dispose();
|
|
194
|
+
observe(input, {
|
|
195
|
+
kind: "phase",
|
|
196
|
+
phase: "cleanup",
|
|
197
|
+
cwd: scratch.cwd,
|
|
198
|
+
state: "finished",
|
|
199
|
+
outcome: leak !== null || cleanup !== undefined ? "failed" : "ok",
|
|
200
|
+
});
|
|
107
201
|
return {
|
|
108
|
-
outcome,
|
|
109
202
|
...(cleanup === undefined ? {} : { cleanup }),
|
|
110
203
|
...(leak === null ? {} : { leak }),
|
|
111
204
|
};
|
|
112
205
|
}
|
|
206
|
+
/** Execute one disposable Verification attempt over the exact integration snapshot. */
|
|
207
|
+
export async function executeVerification(input) {
|
|
208
|
+
const materialized = await materializeScratch(input);
|
|
209
|
+
if ("outcome" in materialized)
|
|
210
|
+
return materialized;
|
|
211
|
+
const prepared = await runScratch(input, materialized);
|
|
212
|
+
return { outcome: prepared.outcome, ...(await retireScratch(input, materialized, prepared.destroy)) };
|
|
213
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const verificationObservationSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
3
|
+
state: z.ZodEnum<{
|
|
4
|
+
finished: "finished";
|
|
5
|
+
started: "started";
|
|
6
|
+
}>;
|
|
7
|
+
outcome: z.ZodOptional<z.ZodString>;
|
|
8
|
+
elapsedMs: z.ZodOptional<z.ZodNumber>;
|
|
9
|
+
phase: z.ZodEnum<{
|
|
10
|
+
cleanup: "cleanup";
|
|
11
|
+
materialize: "materialize";
|
|
12
|
+
setup: "setup";
|
|
13
|
+
declaration: "declaration";
|
|
14
|
+
}>;
|
|
15
|
+
cwd: z.ZodOptional<z.ZodString>;
|
|
16
|
+
name: z.ZodOptional<z.ZodString>;
|
|
17
|
+
command: z.ZodOptional<z.ZodString>;
|
|
18
|
+
index: z.ZodOptional<z.ZodNumber>;
|
|
19
|
+
total: z.ZodOptional<z.ZodNumber>;
|
|
20
|
+
kind: z.ZodLiteral<"phase">;
|
|
21
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
22
|
+
stream: z.ZodEnum<{
|
|
23
|
+
stdout: "stdout";
|
|
24
|
+
stderr: "stderr";
|
|
25
|
+
}>;
|
|
26
|
+
text: z.ZodString;
|
|
27
|
+
phase: z.ZodEnum<{
|
|
28
|
+
cleanup: "cleanup";
|
|
29
|
+
materialize: "materialize";
|
|
30
|
+
setup: "setup";
|
|
31
|
+
declaration: "declaration";
|
|
32
|
+
}>;
|
|
33
|
+
cwd: z.ZodOptional<z.ZodString>;
|
|
34
|
+
name: z.ZodOptional<z.ZodString>;
|
|
35
|
+
command: z.ZodOptional<z.ZodString>;
|
|
36
|
+
index: z.ZodOptional<z.ZodNumber>;
|
|
37
|
+
total: z.ZodOptional<z.ZodNumber>;
|
|
38
|
+
kind: z.ZodLiteral<"output">;
|
|
39
|
+
}, z.core.$strict>], "kind">;
|
|
40
|
+
/** Attempt-local observations, never testimony, liveness, or recovery authority. */
|
|
41
|
+
export type VerificationObservation = z.infer<typeof verificationObservationSchema>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
const phase = z.enum(["materialize", "setup", "declaration", "cleanup"]);
|
|
3
|
+
const coordinate = {
|
|
4
|
+
phase,
|
|
5
|
+
cwd: z.string().optional(),
|
|
6
|
+
name: z.string().optional(),
|
|
7
|
+
command: z.string().optional(),
|
|
8
|
+
index: z.number().int().positive().optional(),
|
|
9
|
+
total: z.number().int().nonnegative().optional(),
|
|
10
|
+
};
|
|
11
|
+
export const verificationObservationSchema = z.discriminatedUnion("kind", [
|
|
12
|
+
z
|
|
13
|
+
.object({
|
|
14
|
+
kind: z.literal("phase"),
|
|
15
|
+
...coordinate,
|
|
16
|
+
state: z.enum(["started", "finished"]),
|
|
17
|
+
outcome: z.string().optional(),
|
|
18
|
+
elapsedMs: z.number().nonnegative().optional(),
|
|
19
|
+
})
|
|
20
|
+
.strict(),
|
|
21
|
+
z
|
|
22
|
+
.object({
|
|
23
|
+
kind: z.literal("output"),
|
|
24
|
+
...coordinate,
|
|
25
|
+
stream: z.enum(["stdout", "stderr"]),
|
|
26
|
+
text: z.string(),
|
|
27
|
+
})
|
|
28
|
+
.strict(),
|
|
29
|
+
]);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astrosheep/keiyaku",
|
|
3
|
-
"version": "4.5.
|
|
3
|
+
"version": "4.5.21",
|
|
4
4
|
"workspaces": [
|
|
5
5
|
"plugins/*"
|
|
6
6
|
],
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
"node": ">=22.19.0"
|
|
40
40
|
},
|
|
41
41
|
"scripts": {
|
|
42
|
+
"release": "npm run test:release && npm version patch && npm publish",
|
|
42
43
|
"build": "node --input-type=module -e \"import { rmSync } from 'node:fs'; rmSync('build', { recursive: true, force: true })\" && tsc -p tsconfig.json && npm run build --workspace @astrosheep/keiyaku-plugin-square && node scripts/copy-integrations.js && node scripts/build-windows-launcher.js && node --input-type=module -e \"import { chmodSync } from 'node:fs'; chmodSync('build/src/cli/index.js', 0o755)\"",
|
|
43
44
|
"prepack": "node scripts/verify-package.js",
|
|
44
45
|
"postpack": "node scripts/verify-package.js",
|
|
@@ -80,6 +81,7 @@
|
|
|
80
81
|
"@agentclientprotocol/sdk": "^1.3.0",
|
|
81
82
|
"@anthropic-ai/claude-agent-sdk": "^0.3.226",
|
|
82
83
|
"@astrosheep/keiyaku-plugin-square": "0.1.5",
|
|
84
|
+
"@astrosheep/square": "^0.3.50",
|
|
83
85
|
"@earendil-works/pi-coding-agent": "0.85.1",
|
|
84
86
|
"@opencode-ai/sdk": "1.18.3",
|
|
85
87
|
"cross-spawn": "^7.0.6",
|