@astrosheep/keiyaku 2.9.3 → 2.9.5
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/.tsbuildinfo +1 -1
- package/build/agents/call-terms.js +14 -94
- package/build/agents/harness/activity-values.js +16 -0
- package/build/agents/harness/event-persistence.js +218 -0
- package/build/agents/harness/execution-handle.js +26 -222
- package/build/agents/harness/index.js +3 -1
- package/build/agents/harness/outcome.js +68 -5
- package/build/agents/harness/projection.js +179 -124
- package/build/agents/harness/provider-adapter.js +58 -0
- package/build/agents/harness/router.js +11 -187
- package/build/agents/harness/runtime.js +17 -4
- package/build/agents/harness/session.js +15 -0
- package/build/agents/launch-snapshot/model.js +15 -236
- package/build/agents/launch-snapshot/parse-helpers.js +114 -0
- package/build/agents/launch-snapshot/resolve.js +17 -43
- package/build/agents/opencode-sdk.js +45 -12
- package/build/agents/providers/claude-agent-sdk/adapter.js +6 -17
- package/build/agents/providers/claude-agent-sdk/registration.js +214 -0
- package/build/agents/providers/claude-agent-sdk/session-schema.js +2 -0
- package/build/agents/providers/codex-app-server/adapter.js +82 -53
- package/build/agents/providers/codex-app-server/events.js +90 -11
- package/build/agents/providers/codex-app-server/identity.js +1 -0
- package/build/agents/providers/codex-app-server/policy.js +29 -0
- package/build/agents/providers/codex-app-server/registration.js +248 -0
- package/build/agents/providers/codex-app-server/session-schema.js +6 -0
- package/build/agents/providers/codex-app-server/session.js +23 -17
- package/build/agents/providers/codex-app-server/terms.js +1 -0
- package/build/agents/providers/opencode-sdk/adapter.js +94 -50
- package/build/agents/providers/opencode-sdk/events.js +8 -4
- package/build/agents/providers/opencode-sdk/registration.js +135 -0
- package/build/agents/providers/opencode-sdk/session-schema.js +2 -0
- package/build/agents/providers/opencode-sdk/session.js +21 -14
- package/build/agents/providers/opencode-sdk/terms.js +1 -0
- package/build/agents/providers/pi/adapter.js +36 -30
- package/build/agents/providers/pi/events.js +4 -3
- package/build/agents/providers/pi/registration.js +145 -0
- package/build/agents/providers/pi/session-schema.js +6 -0
- package/build/agents/providers/pi/terms.js +1 -0
- package/build/agents/providers/registration.js +7 -0
- package/build/agents/providers/registry.js +76 -0
- package/build/agents/selector.js +2 -29
- package/build/agents/types.js +10 -0
- package/build/artifact-directories.js +22 -0
- package/build/cli/commands/akuma/akuma/handler.js +1 -1
- package/build/cli/commands/akuma/akuma/meta.js +1 -1
- package/build/cli/commands/akuma/list/meta-ls.js +1 -1
- package/build/cli/commands/akuma/view/handler.js +5 -4
- package/build/cli/commands/akuma/view/meta.js +1 -1
- package/build/cli/commands/akuma.js +6 -0
- package/build/cli/commands/contract/amend/handler.js +8 -2
- package/build/cli/commands/contract/amend/meta.js +4 -4
- package/build/cli/commands/contract/arc/handler.js +8 -2
- package/build/cli/commands/contract/arc/meta.js +4 -4
- package/build/cli/commands/contract/audit/handler.js +16 -0
- package/build/cli/commands/contract/audit/meta.js +16 -0
- package/build/cli/commands/contract/bind/handler.js +4 -3
- package/build/cli/commands/contract/bind/meta.js +44 -8
- package/build/cli/commands/contract/catalog.js +2 -0
- package/build/cli/commands/contract/forfeit/handler.js +4 -4
- package/build/cli/commands/contract/forfeit/meta.js +1 -1
- package/build/cli/commands/contract/log/handler.js +3 -3
- package/build/cli/commands/contract/log/meta.js +1 -1
- package/build/cli/commands/contract/petition/handler.js +5 -8
- package/build/cli/commands/contract/petition/meta.js +6 -6
- package/build/cli/commands/contract/renew/handler.js +20 -6
- package/build/cli/commands/contract/renew/meta.js +6 -5
- package/build/cli/commands/metadata.js +59 -0
- package/build/cli/commands/projection/call/handler.js +6 -5
- package/build/cli/commands/projection/call/meta.js +4 -1
- package/build/cli/commands/projection/kill/handler.js +16 -32
- package/build/cli/commands/projection/kill/meta.js +1 -1
- package/build/cli/commands/projection/revive/meta.js +4 -1
- package/build/cli/commands/projection/shared.js +28 -0
- package/build/cli/commands/projection/status/handler.js +1 -1
- package/build/cli/commands/projection/status/meta.js +1 -1
- package/build/cli/commands/projection/tell/handler.js +14 -30
- package/build/cli/commands/projection/tell/meta.js +4 -1
- package/build/cli/commands/projection/wait/handler.js +45 -22
- package/build/cli/commands/projection/wait/meta.js +8 -3
- package/build/cli/commands/registry.js +2 -54
- package/build/cli/commands/shared.js +10 -7
- package/build/cli/commands/skills/install/handler.js +2 -5
- package/build/cli/commands/skills/install/meta.js +1 -1
- package/build/cli/commands/skills/skills/handler.js +1 -1
- package/build/cli/commands/skills/skills/meta.js +1 -1
- package/build/cli/commands/system/completion/meta.js +1 -1
- package/build/cli/commands/system/dump-env/meta.js +1 -1
- package/build/cli/commands/system/guide/meta.js +1 -1
- package/build/cli/commands/task/add/handler.js +7 -15
- package/build/cli/commands/task/add/meta.js +4 -1
- package/build/cli/commands/task/catalog.js +2 -2
- package/build/cli/commands/task/doctor/meta.js +1 -1
- package/build/cli/commands/task/done/handler.js +4 -8
- package/build/cli/commands/task/done/meta.js +1 -1
- package/build/cli/commands/task/drop/handler.js +3 -6
- package/build/cli/commands/task/drop/meta.js +1 -1
- package/build/cli/commands/task/ls/handler.js +12 -8
- package/build/cli/commands/task/ls/meta.js +3 -3
- package/build/cli/commands/task/shared.js +14 -4
- package/build/cli/commands/task/{view → show}/handler.js +7 -8
- package/build/cli/commands/task/show/meta.js +8 -0
- package/build/cli/commands/task/start/handler.js +3 -6
- package/build/cli/commands/task/start/meta.js +1 -1
- package/build/cli/commands/task/stop/handler.js +4 -8
- package/build/cli/commands/task/stop/meta.js +1 -1
- package/build/cli/commands/task/task/handler.js +1 -1
- package/build/cli/commands/task/task/meta.js +1 -1
- package/build/cli/commands/task/update/handler.js +6 -11
- package/build/cli/commands/task/update/meta.js +4 -1
- package/build/cli/completion.js +1 -1
- package/build/cli/flags.js +37 -6
- package/build/cli/help.js +7 -14
- package/build/cli/index.js +112 -154
- package/build/cli/missing-subcommand.js +7 -0
- package/build/cli/output-stream-error-policy.js +19 -5
- package/build/cli/parse-flags.js +33 -7
- package/build/cli/parse-metadata.js +3 -9
- package/build/cli/parse-selectors.js +2 -1
- package/build/cli/parse.js +35 -5
- package/build/cli/projection-address.js +12 -12
- package/build/cli/render/address.js +41 -37
- package/build/cli/render/arc.js +24 -12
- package/build/cli/render/audit.js +121 -0
- package/build/cli/render/call.js +11 -5
- package/build/cli/render/errors.js +36 -1
- package/build/cli/render/format.js +4 -0
- package/build/cli/render/kanshi.js +6 -12
- package/build/cli/render/kill.js +9 -0
- package/build/cli/render/misc.js +58 -13
- package/build/cli/render/petition.js +20 -15
- package/build/cli/render/projection-activity.js +15 -6
- package/build/cli/render/shared.js +60 -21
- package/build/cli/render/skills.js +10 -0
- package/build/cli/render/status.js +56 -23
- package/build/cli/render/success-response.js +78 -0
- package/build/cli/render/task.js +66 -57
- package/build/cli/render/tell.js +5 -0
- package/build/cli/render/terminal-failure.js +63 -0
- package/build/cli/render/types.js +1 -0
- package/build/cli/render/wait.js +68 -38
- package/build/cli/types.js +1 -1
- package/build/config/akuma-loader.js +0 -5
- package/build/config/env-keys.js +3 -1
- package/build/config/env.js +3 -0
- package/build/config/provider-policy-ownership.js +3 -32
- package/build/config/settings/disease.js +8 -1
- package/build/config/settings/loader.js +11 -3
- package/build/config/settings/provider-instance-fields.js +51 -0
- package/build/config/settings/schema.js +6 -176
- package/build/core/addressing.js +66 -16
- package/build/core/amend.js +61 -18
- package/build/core/arc.js +33 -73
- package/build/core/audit.js +650 -0
- package/build/core/bind.js +82 -35
- package/build/core/call/call.js +15 -9
- package/build/core/call/context.js +6 -51
- package/build/core/call/execution.js +22 -22
- package/build/core/call/prompt.js +14 -1
- package/build/core/command-markdown.js +45 -0
- package/build/core/context.js +13 -7
- package/build/core/contract-view.js +22 -6
- package/build/core/draft.js +139 -19
- package/build/core/entry.js +3 -4
- package/build/core/forfeit.js +5 -2
- package/build/core/hints.js +1 -75
- package/build/core/identifier-slug.js +66 -0
- package/build/core/ids.js +25 -11
- package/build/core/ledger.js +20 -68
- package/build/core/markdown/lex.js +2 -1
- package/build/core/markdown/parser.js +0 -68
- package/build/core/markdown/render.js +68 -0
- package/build/core/markdown/sections.js +2 -1
- package/build/core/outcome-base.js +4 -0
- package/build/core/projection/generation/database.js +41 -52
- package/build/core/projection/generation/model.js +63 -2
- package/build/core/{projection-generation-continuation.js → projection/generation/projection-generation-continuation.js} +3 -3
- package/build/core/{projection-generation-execution.js → projection/generation/projection-generation-execution.js} +36 -53
- package/build/core/{projection-generation-identity.js → projection/generation/projection-generation-identity.js} +2 -2
- package/build/core/{projection-generation-launcher.js → projection/generation/projection-generation-launcher.js} +9 -7
- package/build/core/{projection-generation-process.js → projection/generation/projection-generation-process.js} +2 -1
- package/build/core/{projection-generation-runner.js → projection/generation/projection-generation-runner.js} +19 -3
- package/build/core/projection/generation/store.js +3 -3
- package/build/core/projection/generation/transitions.js +19 -3
- package/build/core/projection/index.js +27 -0
- package/build/core/{projection-activity.js → projection/projection-activity.js} +12 -0
- package/build/core/{projection-alias.js → projection/projection-alias.js} +13 -13
- package/build/core/projection/projection-coordinate.js +61 -0
- package/build/core/{projection-core.js → projection/projection-core.js} +9 -9
- package/build/core/{projection-execution-observer.js → projection/projection-execution-observer.js} +37 -78
- package/build/core/{projection-identity.js → projection/projection-identity.js} +1 -1
- package/build/core/{projection-kill.js → projection/projection-kill.js} +1 -1
- package/build/core/{projection-life-observer.js → projection/projection-life-observer.js} +16 -2
- package/build/core/{projection-mint.js → projection/projection-mint.js} +10 -10
- package/build/core/{projection-status.js → projection/projection-status.js} +163 -45
- package/build/core/projection/projection-terminal-failure.js +106 -0
- package/build/core/projection/projection-wait.js +275 -0
- package/build/core/projection/projection-wake.js +227 -0
- package/build/core/provider-loader-ports.js +4 -0
- package/build/core/ref-log.js +65 -40
- package/build/core/registry.js +63 -10
- package/build/core/renew-session.js +128 -0
- package/build/core/renew.js +448 -102
- package/build/core/scope.js +272 -68
- package/build/core/seal.js +165 -40
- package/build/core/{claim-delivery.js → settlement/claim-delivery.js} +8 -8
- package/build/core/{claim.js → settlement/claim.js} +32 -8
- package/build/core/settlement/index.js +19 -0
- package/build/core/{petition-claim-gates.js → settlement/petition-claim-gates.js} +24 -49
- package/build/core/{petition-forfeit.js → settlement/petition-forfeit.js} +2 -2
- package/build/core/{petition-head-guard.js → settlement/petition-head-guard.js} +2 -2
- package/build/core/settlement/petition-io.js +1 -0
- package/build/core/{petition-preview.js → settlement/petition-preview.js} +2 -2
- package/build/core/{petition.js → settlement/petition.js} +21 -12
- package/build/core/settlement/queue-read-model.js +143 -0
- package/build/core/settlement/queue-seat-allocation.js +156 -0
- package/build/core/settlement/queue.js +6 -0
- package/build/core/settlement/settlement.js +288 -0
- package/build/core/{verdict.js → settlement/verdict.js} +9 -37
- package/build/core/settlement/verification.js +59 -0
- package/build/core/status/board.js +62 -41
- package/build/core/status/ledger-batch.js +158 -0
- package/build/core/status/reconciliation.js +10 -4
- package/build/core/stored-agent-event.js +6 -2
- package/build/core/task/board.js +41 -4
- package/build/core/task/commands.js +45 -28
- package/build/core/task/document.js +5 -0
- package/build/core/task/index.js +12 -0
- package/build/core/task/model.js +8 -1
- package/build/core/task/query.js +172 -0
- package/build/core/task/settlement-git.js +265 -74
- package/build/core/task/settlement-policy.js +67 -29
- package/build/core/task/source-board.js +1 -0
- package/build/core/task/task-contract.js +444 -0
- package/build/core/{task-doctor.js → task/task-doctor.js} +1 -1
- package/build/core/{task-git-actor.js → task/task-git-actor.js} +5 -10
- package/build/core/{task-git-runtime.js → task/task-git-runtime.js} +3 -3
- package/build/core/{task-git-store.js → task/task-git-store.js} +90 -19
- package/build/core/task/task-repository.js +1 -0
- package/build/core/{task-store-repository.js → task/task-store-repository.js} +6 -4
- package/build/core/task/task-store.js +1 -0
- package/build/core/{task-worktree.js → task/task-worktree.js} +2 -1
- package/build/core/task/task.js +7 -0
- package/build/core/task/tree.js +37 -0
- package/build/core/task/validation.js +5 -2
- package/build/core/transcripts.js +15 -3
- package/build/core/worktree-path.js +43 -28
- package/build/flow-error.js +83 -39
- package/build/fs/path-coordinate.js +16 -0
- package/build/generated/version.js +3 -2
- package/build/git/branches.js +2 -1
- package/build/git/core.js +106 -2
- package/build/git/diff/parsers.js +23 -13
- package/build/git/diff/structured.js +127 -0
- package/build/git/path-coordinate.js +17 -0
- package/build/git/refs.js +57 -0
- package/build/git/streaming-batch.js +301 -0
- package/build/git/worktree.js +65 -0
- package/build/index.js +9 -9
- package/build/keiyaku.js +2 -36
- package/build/telemetry/logger.js +4 -2
- package/package.json +4 -10
- package/skills/keiyaku/SKILL.md +5 -4
- package/skills/keiyaku-akuma/SKILL.md +25 -11
- package/skills/keiyaku-task/SKILL.md +17 -8
- package/skills/keiyaku-workflow/SKILL.md +58 -9
- package/build/agents/providers/codex-sdk.js +0 -329
- package/build/cli/commands/task/view/meta.js +0 -8
- package/build/core/command-io.js +0 -174
- package/build/core/path-coordinate.js +0 -27
- package/build/core/petition-claim.js +0 -117
- package/build/core/petition-run.js +0 -83
- package/build/core/projection-coordinate.js +0 -63
- package/build/core/projection-wait.js +0 -165
- package/build/core/projection-wake.js +0 -136
- package/build/core/queue.js +0 -343
- package/build/core/task-contract.js +0 -237
- package/build/core/task.js +0 -4
- /package/build/{core/task-repository.js → agents/launch-snapshot/types.js} +0 -0
- /package/build/{core/task-store.js → agents/providers/claude-agent-sdk/terms.js} +0 -0
- /package/build/core/{projection-generation-runtime.js → projection/generation/projection-generation-runtime.js} +0 -0
- /package/build/core/{projection-life-protocol.js → projection/projection-life-protocol.js} +0 -0
- /package/build/core/{projection-runner-lock.js → projection/projection-runner-lock.js} +0 -0
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { normalizeFilesystemCoordinate } from "../fs/path-coordinate.js";
|
|
3
|
+
import { gitProcessEnv, resolveGitTimeoutMs, } from "./core.js";
|
|
4
|
+
/** Default long-lived batch argv. One-shot calls must not use this gate. */
|
|
5
|
+
export const GIT_STREAMING_BATCH_DEFAULT_ARGS = ["cat-file", "--batch"];
|
|
6
|
+
/** Safety cap for a single response header line before the body frame. */
|
|
7
|
+
export const GIT_STREAMING_BATCH_MAX_HEADER_BYTES = 64 * 1024;
|
|
8
|
+
/** Wire/framing failure while reading batch stdout. */
|
|
9
|
+
export class GitStreamingBatchFramingError extends Error {
|
|
10
|
+
name = "GitStreamingBatchFramingError";
|
|
11
|
+
}
|
|
12
|
+
/** Stdout ended before a complete frame arrived. */
|
|
13
|
+
export class GitStreamingBatchResponseEndedError extends Error {
|
|
14
|
+
name = "GitStreamingBatchResponseEndedError";
|
|
15
|
+
}
|
|
16
|
+
class BufferedReader {
|
|
17
|
+
#iterator;
|
|
18
|
+
#buffer = Buffer.alloc(0);
|
|
19
|
+
#ended = false;
|
|
20
|
+
constructor(stream) {
|
|
21
|
+
this.#iterator = stream[Symbol.asyncIterator]();
|
|
22
|
+
}
|
|
23
|
+
async #fill() {
|
|
24
|
+
if (this.#ended) {
|
|
25
|
+
throw new GitStreamingBatchResponseEndedError("git streaming batch response ended unexpectedly");
|
|
26
|
+
}
|
|
27
|
+
const next = await this.#iterator.next();
|
|
28
|
+
if (next.done) {
|
|
29
|
+
this.#ended = true;
|
|
30
|
+
throw new GitStreamingBatchResponseEndedError("git streaming batch response ended unexpectedly");
|
|
31
|
+
}
|
|
32
|
+
const chunk = Buffer.isBuffer(next.value) ? next.value : Buffer.from(next.value);
|
|
33
|
+
this.#buffer = this.#buffer.length === 0 ? chunk : Buffer.concat([this.#buffer, chunk]);
|
|
34
|
+
}
|
|
35
|
+
async readLine(maxBytes) {
|
|
36
|
+
for (;;) {
|
|
37
|
+
const newline = this.#buffer.indexOf(0x0a);
|
|
38
|
+
if (newline >= 0) {
|
|
39
|
+
if (newline > maxBytes) {
|
|
40
|
+
throw new GitStreamingBatchFramingError(`git streaming batch header exceeds ${maxBytes} bytes`);
|
|
41
|
+
}
|
|
42
|
+
const line = this.#buffer.subarray(0, newline).toString("ascii");
|
|
43
|
+
this.#buffer = this.#buffer.subarray(newline + 1);
|
|
44
|
+
return line;
|
|
45
|
+
}
|
|
46
|
+
if (this.#buffer.length > maxBytes) {
|
|
47
|
+
throw new GitStreamingBatchFramingError(`git streaming batch header exceeds ${maxBytes} bytes without a newline`);
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
await this.#fill();
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
if (error instanceof GitStreamingBatchResponseEndedError) {
|
|
54
|
+
throw new GitStreamingBatchFramingError("git streaming batch response ended before a header newline");
|
|
55
|
+
}
|
|
56
|
+
throw error;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
async readExactly(length) {
|
|
61
|
+
while (this.#buffer.length < length)
|
|
62
|
+
await this.#fill();
|
|
63
|
+
const value = this.#buffer.subarray(0, length);
|
|
64
|
+
this.#buffer = this.#buffer.subarray(length);
|
|
65
|
+
return value;
|
|
66
|
+
}
|
|
67
|
+
async discardExactly(length) {
|
|
68
|
+
let remaining = length;
|
|
69
|
+
while (remaining > 0) {
|
|
70
|
+
if (this.#buffer.length === 0)
|
|
71
|
+
await this.#fill();
|
|
72
|
+
const consumed = Math.min(remaining, this.#buffer.length);
|
|
73
|
+
this.#buffer = this.#buffer.subarray(consumed);
|
|
74
|
+
remaining -= consumed;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Long-lived Git batch subprocess: raw request lines, framed response records,
|
|
80
|
+
* and exit/timeout/close facts only. No domain vocabulary or FlowError decisions.
|
|
81
|
+
*/
|
|
82
|
+
export class GitStreamingBatchSession {
|
|
83
|
+
cwd;
|
|
84
|
+
#child;
|
|
85
|
+
#reader;
|
|
86
|
+
#stderr = [];
|
|
87
|
+
#timeout;
|
|
88
|
+
#closed;
|
|
89
|
+
#maxHeaderBytes;
|
|
90
|
+
#state = { kind: "open" };
|
|
91
|
+
#timedOut = false;
|
|
92
|
+
#aborted = false;
|
|
93
|
+
#inputError = null;
|
|
94
|
+
#requestInFlight = false;
|
|
95
|
+
#closePromise = null;
|
|
96
|
+
constructor(cwd, child, timeoutMs, maxHeaderBytes) {
|
|
97
|
+
this.cwd = cwd;
|
|
98
|
+
this.#child = child;
|
|
99
|
+
this.#reader = new BufferedReader(this.#child.stdout);
|
|
100
|
+
this.#maxHeaderBytes = maxHeaderBytes;
|
|
101
|
+
this.#child.stderr.on("data", (chunk) => this.#stderr.push(chunk));
|
|
102
|
+
this.#child.stdin.on("error", (error) => {
|
|
103
|
+
this.#inputError = error;
|
|
104
|
+
});
|
|
105
|
+
this.#closed = new Promise((resolve) => {
|
|
106
|
+
this.#child.once("error", (error) => {
|
|
107
|
+
resolve({ code: null, signal: null, processError: error });
|
|
108
|
+
});
|
|
109
|
+
this.#child.once("close", (code, signal) => {
|
|
110
|
+
resolve({ code, signal });
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
this.#timeout = setTimeout(() => {
|
|
114
|
+
this.#timedOut = true;
|
|
115
|
+
this.#child.kill("SIGKILL");
|
|
116
|
+
}, timeoutMs);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Open the sole long-lived Git batch process for `cwd`.
|
|
120
|
+
* Default argv is `cat-file --batch`; callers supply compatible batch modes only.
|
|
121
|
+
*/
|
|
122
|
+
static open(cwd, options) {
|
|
123
|
+
const args = options?.args ?? GIT_STREAMING_BATCH_DEFAULT_ARGS;
|
|
124
|
+
const timeoutMs = options?.timeoutMs ?? resolveGitTimeoutMs();
|
|
125
|
+
const maxHeaderBytes = options?.maxHeaderBytes ?? GIT_STREAMING_BATCH_MAX_HEADER_BYTES;
|
|
126
|
+
const child = spawn("git", [...args], {
|
|
127
|
+
cwd: normalizeFilesystemCoordinate(cwd),
|
|
128
|
+
env: gitProcessEnv(),
|
|
129
|
+
shell: false,
|
|
130
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
131
|
+
});
|
|
132
|
+
return new GitStreamingBatchSession(cwd, child, timeoutMs, maxHeaderBytes);
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Write one request line and read one framed response record.
|
|
136
|
+
* Honors stdin backpressure. Concurrent requests are rejected.
|
|
137
|
+
*/
|
|
138
|
+
async request(expression, options) {
|
|
139
|
+
if (this.#state.kind !== "open") {
|
|
140
|
+
throw new Error("git streaming batch session is not open");
|
|
141
|
+
}
|
|
142
|
+
if (this.#requestInFlight) {
|
|
143
|
+
throw new Error("git streaming batch rejects concurrent requests");
|
|
144
|
+
}
|
|
145
|
+
this.#requestInFlight = true;
|
|
146
|
+
try {
|
|
147
|
+
if (this.#inputError)
|
|
148
|
+
throw this.#inputError;
|
|
149
|
+
const line = `${expression}\n`;
|
|
150
|
+
if (!this.#child.stdin.write(line)) {
|
|
151
|
+
await new Promise((resolve, reject) => {
|
|
152
|
+
const onDrain = () => {
|
|
153
|
+
this.#child.stdin.off("error", onError);
|
|
154
|
+
resolve();
|
|
155
|
+
};
|
|
156
|
+
const onError = (error) => {
|
|
157
|
+
this.#child.stdin.off("drain", onDrain);
|
|
158
|
+
reject(error);
|
|
159
|
+
};
|
|
160
|
+
this.#child.stdin.once("drain", onDrain);
|
|
161
|
+
this.#child.stdin.once("error", onError);
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
let header;
|
|
165
|
+
try {
|
|
166
|
+
header = await this.#reader.readLine(this.#maxHeaderBytes);
|
|
167
|
+
}
|
|
168
|
+
catch (error) {
|
|
169
|
+
if (error instanceof GitStreamingBatchFramingError
|
|
170
|
+
|| error instanceof GitStreamingBatchResponseEndedError) {
|
|
171
|
+
this.abort();
|
|
172
|
+
}
|
|
173
|
+
throw error;
|
|
174
|
+
}
|
|
175
|
+
if (header === `${expression} missing`) {
|
|
176
|
+
return { kind: "missing", expression };
|
|
177
|
+
}
|
|
178
|
+
if (header === `${expression} ambiguous`) {
|
|
179
|
+
return { kind: "ambiguous", expression };
|
|
180
|
+
}
|
|
181
|
+
const parts = header.split(" ");
|
|
182
|
+
const [oid, type, sizeText, ...unexpected] = parts;
|
|
183
|
+
const size = Number(sizeText);
|
|
184
|
+
if (unexpected.length > 0
|
|
185
|
+
|| !oid
|
|
186
|
+
|| !/^[0-9a-f]{40,64}$/.test(oid)
|
|
187
|
+
|| !type
|
|
188
|
+
|| !Number.isSafeInteger(size)
|
|
189
|
+
|| size < 0) {
|
|
190
|
+
this.abort();
|
|
191
|
+
throw new GitStreamingBatchFramingError(`git streaming batch returned invalid object header: ${header}`);
|
|
192
|
+
}
|
|
193
|
+
if (options?.maxContentBytes !== undefined && size > options.maxContentBytes) {
|
|
194
|
+
try {
|
|
195
|
+
await this.#reader.discardExactly(size + 1);
|
|
196
|
+
}
|
|
197
|
+
catch (error) {
|
|
198
|
+
this.abort();
|
|
199
|
+
throw error;
|
|
200
|
+
}
|
|
201
|
+
// Stream stays aligned after discard; oversized is a record limit, not a framing break.
|
|
202
|
+
throw new Error(`git streaming batch object ${oid} exceeds ${options.maxContentBytes} bytes`);
|
|
203
|
+
}
|
|
204
|
+
let content;
|
|
205
|
+
let terminator;
|
|
206
|
+
try {
|
|
207
|
+
content = await this.#reader.readExactly(size);
|
|
208
|
+
terminator = await this.#reader.readExactly(1);
|
|
209
|
+
}
|
|
210
|
+
catch (error) {
|
|
211
|
+
this.abort();
|
|
212
|
+
throw error;
|
|
213
|
+
}
|
|
214
|
+
if (terminator[0] !== 0x0a) {
|
|
215
|
+
this.abort();
|
|
216
|
+
throw new GitStreamingBatchFramingError(`git streaming batch object ${oid} has an invalid frame terminator`);
|
|
217
|
+
}
|
|
218
|
+
return {
|
|
219
|
+
kind: "object",
|
|
220
|
+
record: { oid, type, size, content },
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
finally {
|
|
224
|
+
this.#requestInFlight = false;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Idempotent kill of the child after a framing or stream-end failure.
|
|
229
|
+
* Immediately leaves `open` so no later request can write/read the destroyed child.
|
|
230
|
+
*/
|
|
231
|
+
abort() {
|
|
232
|
+
if (this.#aborted)
|
|
233
|
+
return;
|
|
234
|
+
this.#aborted = true;
|
|
235
|
+
if (this.#state.kind === "open") {
|
|
236
|
+
this.#state = { kind: "closing" };
|
|
237
|
+
}
|
|
238
|
+
this.#child.stdin.destroy();
|
|
239
|
+
this.#child.kill("SIGKILL");
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* End stdin, await process exit, and return structured close facts.
|
|
243
|
+
* First close may reject on process spawn error after storing the closed fact;
|
|
244
|
+
* a later close returns that stored fact. Successful and aborted close stay idempotent.
|
|
245
|
+
*/
|
|
246
|
+
close() {
|
|
247
|
+
if (this.#state.kind === "closed")
|
|
248
|
+
return Promise.resolve(this.#state.fact);
|
|
249
|
+
if (this.#closePromise)
|
|
250
|
+
return this.#closePromise;
|
|
251
|
+
this.#state = { kind: "closing" };
|
|
252
|
+
// Clear the in-flight promise after settlement so a later close() returns the
|
|
253
|
+
// stored fact instead of replaying a rejected process-error promise. The
|
|
254
|
+
// returned chain is what callers await; bookkeeping must not create a second
|
|
255
|
+
// unhandled rejection.
|
|
256
|
+
this.#closePromise = this.#closeOnce().then((fact) => {
|
|
257
|
+
this.#closePromise = null;
|
|
258
|
+
return fact;
|
|
259
|
+
}, (error) => {
|
|
260
|
+
this.#closePromise = null;
|
|
261
|
+
throw error;
|
|
262
|
+
});
|
|
263
|
+
return this.#closePromise;
|
|
264
|
+
}
|
|
265
|
+
async #closeOnce() {
|
|
266
|
+
if (!this.#aborted && this.#child.stdin?.writable) {
|
|
267
|
+
this.#child.stdin.end();
|
|
268
|
+
}
|
|
269
|
+
let exit;
|
|
270
|
+
try {
|
|
271
|
+
exit = await this.#closed;
|
|
272
|
+
}
|
|
273
|
+
finally {
|
|
274
|
+
clearTimeout(this.#timeout);
|
|
275
|
+
}
|
|
276
|
+
if (exit.processError && !this.#aborted) {
|
|
277
|
+
const fact = {
|
|
278
|
+
code: null,
|
|
279
|
+
signal: null,
|
|
280
|
+
timedOut: this.#timedOut,
|
|
281
|
+
aborted: this.#aborted,
|
|
282
|
+
stderr: Buffer.concat(this.#stderr),
|
|
283
|
+
};
|
|
284
|
+
this.#state = { kind: "closed", fact };
|
|
285
|
+
throw exit.processError;
|
|
286
|
+
}
|
|
287
|
+
const fact = {
|
|
288
|
+
code: exit.code,
|
|
289
|
+
signal: exit.signal,
|
|
290
|
+
timedOut: this.#timedOut,
|
|
291
|
+
aborted: this.#aborted,
|
|
292
|
+
stderr: Buffer.concat(this.#stderr),
|
|
293
|
+
};
|
|
294
|
+
this.#state = { kind: "closed", fact };
|
|
295
|
+
return fact;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
/** Open the sole long-lived Git batch subprocess primitive. */
|
|
299
|
+
export function openGitStreamingBatch(cwd, options) {
|
|
300
|
+
return GitStreamingBatchSession.open(cwd, options);
|
|
301
|
+
}
|
package/build/git/worktree.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { FlowError } from "../flow-error.js";
|
|
1
4
|
import { createGit, wrapGitError } from "./core.js";
|
|
2
5
|
export const DIRTY_FILE_CATEGORY = {
|
|
3
6
|
modified: "modified",
|
|
@@ -8,6 +11,8 @@ export const DIRTY_FILE_CATEGORY = {
|
|
|
8
11
|
copied: "copied",
|
|
9
12
|
untracked: "untracked",
|
|
10
13
|
};
|
|
14
|
+
const DIRTY_WORKTREE_LIST_LIMIT = 10;
|
|
15
|
+
const KEIYAKU_ARTIFACT_DIR_PREFIX = ".keiyaku/";
|
|
11
16
|
function normalizeGitPath(filePath) {
|
|
12
17
|
return filePath.trim().replace(/^\.\/+/, "");
|
|
13
18
|
}
|
|
@@ -67,6 +72,28 @@ export async function getDirtyFiles(cwd) {
|
|
|
67
72
|
category: deriveDirtyFileCategory(file, statusPathSets),
|
|
68
73
|
}));
|
|
69
74
|
}
|
|
75
|
+
function normalizePathForDirtyMatch(cwd, filePath) {
|
|
76
|
+
const normalizedPath = filePath.trim();
|
|
77
|
+
if (!normalizedPath)
|
|
78
|
+
return "";
|
|
79
|
+
const repoRelativePath = path.isAbsolute(normalizedPath) ? path.relative(cwd, normalizedPath) : normalizedPath;
|
|
80
|
+
const platformNormalizedPath = path.normalize(repoRelativePath.replace(/[\\/]+/g, path.sep));
|
|
81
|
+
return platformNormalizedPath.split(path.sep).join("/").replace(/^\.\/+/, "").replace(/^\/+/, "");
|
|
82
|
+
}
|
|
83
|
+
/** Refuse mutations that can overwrite tracked changes in this worktree. */
|
|
84
|
+
export async function assertCleanTrackedWorkingTree(cwd) {
|
|
85
|
+
const dirtyFiles = (await getDirtyFiles(cwd)).filter((file) => file.category !== DIRTY_FILE_CATEGORY.untracked);
|
|
86
|
+
if (dirtyFiles.length === 0)
|
|
87
|
+
return;
|
|
88
|
+
const shown = dirtyFiles.slice(0, DIRTY_WORKTREE_LIST_LIMIT);
|
|
89
|
+
const list = shown.map((file) => ` ${renderDirtyFileStatusLine(file)}`).join("\n");
|
|
90
|
+
const overflowCount = dirtyFiles.length - shown.length;
|
|
91
|
+
const overflowLine = overflowCount > 0 ? `\n ... (+${overflowCount} more)` : "";
|
|
92
|
+
const hasDirtyKeiyakuArtifacts = dirtyFiles.some((file) => normalizePathForDirtyMatch(cwd, file.path).startsWith(KEIYAKU_ARTIFACT_DIR_PREFIX));
|
|
93
|
+
throw new FlowError("DIRTY_WORKTREE", `Uncommitted changes detected in working tree:\n${list}${overflowLine}\n\nBlocking changes must be committed or stashed before proceeding.`, hasDirtyKeiyakuArtifacts
|
|
94
|
+
? { facts: { kind: "dirty_worktree", hasKeiyakuArtifacts: true } }
|
|
95
|
+
: undefined);
|
|
96
|
+
}
|
|
70
97
|
export async function getUntrackedFiles(cwd) {
|
|
71
98
|
const git = createGit(cwd);
|
|
72
99
|
let output;
|
|
@@ -82,6 +109,44 @@ export async function getUntrackedFiles(cwd) {
|
|
|
82
109
|
.filter((line) => line.length > 0);
|
|
83
110
|
return Array.from(new Set(files));
|
|
84
111
|
}
|
|
112
|
+
/** Capture conflicted paths while the index still contains unmerged entries. */
|
|
113
|
+
export async function getUnmergedPaths(cwd) {
|
|
114
|
+
const git = createGit(cwd);
|
|
115
|
+
let output;
|
|
116
|
+
try {
|
|
117
|
+
output = await git.raw(["diff", "--name-only", "--diff-filter=U", "-z"]);
|
|
118
|
+
}
|
|
119
|
+
catch (err) {
|
|
120
|
+
throw wrapGitError("diff --name-only --diff-filter=U", err, cwd);
|
|
121
|
+
}
|
|
122
|
+
return Array.from(new Set(output.split("\0").filter((filePath) => filePath.length > 0)));
|
|
123
|
+
}
|
|
124
|
+
async function directoryExists(directory) {
|
|
125
|
+
try {
|
|
126
|
+
return (await fs.stat(directory)).isDirectory();
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
if (error.code === "ENOENT")
|
|
130
|
+
return false;
|
|
131
|
+
throw error;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
/** Git owns these paths; a lingering REBASE_HEAD alone is not active-rebase evidence. */
|
|
135
|
+
export async function hasActiveRebase(cwd) {
|
|
136
|
+
const git = createGit(cwd);
|
|
137
|
+
let paths;
|
|
138
|
+
try {
|
|
139
|
+
paths = await Promise.all([
|
|
140
|
+
git.raw(["rev-parse", "--git-path", "rebase-merge"]),
|
|
141
|
+
git.raw(["rev-parse", "--git-path", "rebase-apply"]),
|
|
142
|
+
]);
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
throw wrapGitError("rev-parse --git-path rebase state", error, cwd);
|
|
146
|
+
}
|
|
147
|
+
const directories = paths.map((candidate) => path.resolve(cwd, candidate.trim()));
|
|
148
|
+
return (await Promise.all(directories.map(directoryExists))).some(Boolean);
|
|
149
|
+
}
|
|
85
150
|
export async function isPathTracked(cwd, filePath) {
|
|
86
151
|
const git = createGit(cwd);
|
|
87
152
|
let output;
|
package/build/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { VERSION } from "./generated/version.js";
|
|
2
|
+
import { VERSION, GIT_HASH } from "./generated/version.js";
|
|
3
3
|
import * as fs from "node:fs/promises";
|
|
4
4
|
import { getConfig, initializeConfig } from "./config/env.js";
|
|
5
5
|
import { ENV_KEYS } from "./config/env-keys.js";
|
|
6
|
-
import {
|
|
7
|
-
import { runProjectionGenerationRuntime } from "./core/projection
|
|
6
|
+
import { formatErrorWithCause } from "./telemetry/logger.js";
|
|
7
|
+
import { runProjectionGenerationRuntime } from "./core/projection/index.js";
|
|
8
8
|
import { renderCliHelp, runCliCommand } from "./cli/index.js";
|
|
9
|
-
import { installCliOutputStreamErrorPolicy } from "./cli/output-stream-error-policy.js";
|
|
9
|
+
import { installCliOutputStreamErrorPolicy, writeCliOutput } from "./cli/output-stream-error-policy.js";
|
|
10
10
|
import { assertSubagentCliCommandAllowed } from "./cli/subagent-guard.js";
|
|
11
11
|
installCliOutputStreamErrorPolicy(process.stdout, process.stderr);
|
|
12
12
|
const packageVersion = VERSION;
|
|
@@ -45,16 +45,16 @@ async function main() {
|
|
|
45
45
|
args: cliArgs,
|
|
46
46
|
});
|
|
47
47
|
if (cliArgs.length === 1 && cliArgs[0] === "--version") {
|
|
48
|
-
|
|
48
|
+
await writeCliOutput(process.stdout, `${GIT_HASH ? `${packageVersion} (${GIT_HASH})` : packageVersion}\n`);
|
|
49
49
|
return;
|
|
50
50
|
}
|
|
51
51
|
if (cliArgs.length === 0 || (cliArgs.length === 1 && (cliArgs[0] === "--help" || cliArgs[0] === "-h"))) {
|
|
52
|
-
|
|
52
|
+
await writeCliOutput(process.stdout, `${renderCliHelp(packageVersion)}\n`);
|
|
53
53
|
return;
|
|
54
54
|
}
|
|
55
55
|
process.exitCode = await runCliCommand(cliArgs);
|
|
56
56
|
}
|
|
57
|
-
main().catch((err) => {
|
|
58
|
-
|
|
59
|
-
process.
|
|
57
|
+
await main().catch(async (err) => {
|
|
58
|
+
await writeCliOutput(process.stderr, `${formatErrorWithCause("Fatal error:", err)}\n`);
|
|
59
|
+
process.exitCode = 1;
|
|
60
60
|
});
|
package/build/keiyaku.js
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import * as path from "path";
|
|
2
2
|
import { ACTOR_IDENTITY, SETTINGS_PATH_SEGMENTS } from "./keiyaku-constants.js";
|
|
3
3
|
export { ACTOR_IDENTITY } from "./keiyaku-constants.js";
|
|
4
|
+
export { DRAFT_ARTIFACT_NOTICE, formatArtifactDirectories, KEIYAKU_ARTIFACT_DIRS, KEIYAKU_DRAFT_DIR, RESPONSE_ARTIFACT_NOTICE, RESPONSE_HISTORY_DIR, } from "./artifact-directories.js";
|
|
4
5
|
export const KEIYAKU_FILE = path.join(".keiyaku", "KEIYAKU.md");
|
|
5
|
-
export const KEIYAKU_DRAFT_DIR = path.join(".keiyaku", "draft");
|
|
6
|
-
export const RESPONSE_HISTORY_DIR = path.join(".keiyaku", "response");
|
|
7
|
-
export const KEIYAKU_ARTIFACT_DIRS = [KEIYAKU_DRAFT_DIR, RESPONSE_HISTORY_DIR];
|
|
8
6
|
export const TOOL_NAMES = {
|
|
9
7
|
bind: "bind",
|
|
10
8
|
arc: "arc",
|
|
@@ -16,44 +14,12 @@ export const TOOL_NAMES = {
|
|
|
16
14
|
help: "help",
|
|
17
15
|
};
|
|
18
16
|
export const ACTOR_IDENTITY_PLURAL = `${ACTOR_IDENTITY}s`;
|
|
19
|
-
function formatArtifactDirectory(directory) {
|
|
20
|
-
return `\`${directory}/\``;
|
|
21
|
-
}
|
|
22
|
-
export function formatArtifactDirectories(directories) {
|
|
23
|
-
const formatted = directories.map(formatArtifactDirectory);
|
|
24
|
-
if (formatted.length === 0)
|
|
25
|
-
return "";
|
|
26
|
-
if (formatted.length === 1)
|
|
27
|
-
return formatted[0];
|
|
28
|
-
if (formatted.length === 2)
|
|
29
|
-
return `${formatted[0]} and ${formatted[1]}`;
|
|
30
|
-
return `${formatted.slice(0, -1).join(", ")}, and ${formatted[formatted.length - 1]}`;
|
|
31
|
-
}
|
|
32
|
-
function buildArtifactNotice(directory) {
|
|
33
|
-
return `Auto-generated artifact. Add ${formatArtifactDirectory(directory)} to \`.gitignore\` if you do not want it tracked.`;
|
|
34
|
-
}
|
|
35
|
-
export const DRAFT_ARTIFACT_NOTICE = buildArtifactNotice(KEIYAKU_ARTIFACT_DIRS[0]);
|
|
36
|
-
export const RESPONSE_ARTIFACT_NOTICE = buildArtifactNotice(KEIYAKU_ARTIFACT_DIRS[1]);
|
|
37
17
|
export const KEIYAKU_BRANCH_PREFIX = "keiyaku/";
|
|
38
18
|
export const BASE_RULES_FILE = path.join(".keiyaku", "base-rules.md");
|
|
39
19
|
export const SETTINGS_FILE = path.join(...SETTINGS_PATH_SEGMENTS);
|
|
40
|
-
export
|
|
41
|
-
"codex-sdk",
|
|
42
|
-
"codex-app-server",
|
|
43
|
-
"claude-agent-sdk",
|
|
44
|
-
"opencode-sdk",
|
|
45
|
-
"pi",
|
|
46
|
-
];
|
|
47
|
-
export function isSubagentProvider(value) {
|
|
48
|
-
return SUBAGENT_PROVIDERS.includes(value);
|
|
49
|
-
}
|
|
20
|
+
export { SUBAGENT_PROVIDERS, isSubagentProvider, BUILTIN_AGENT_PROFILES, BUILTIN_AGENT_NAMES, } from "./agents/providers/registry.js";
|
|
50
21
|
export const CODEX_MODEL_REASONING_EFFORT_CONFIG_KEY = "model_reasoning_effort";
|
|
51
|
-
export const BUILTIN_AGENT_NAMES = ["akuma-codex", "akuma-claude"];
|
|
52
22
|
export const DEFAULT_AGENT_NAME = "akuma-codex";
|
|
53
|
-
export const BUILTIN_AGENT_PROFILES = {
|
|
54
|
-
"akuma-codex": { provider: "codex-sdk", description: "Deprecated Codex SDK Akuma; use codex-app-server." },
|
|
55
|
-
"akuma-claude": { provider: "claude-agent-sdk", description: "Default Claude Agent SDK Akuma." },
|
|
56
|
-
};
|
|
57
23
|
export const CLAUDE_PERMISSION_MODES = ["default", "acceptEdits", "bypassPermissions", "plan", "dontAsk", "auto"];
|
|
58
24
|
export const CLAUDE_SETTING_SOURCES = ["project", "user", "local"];
|
|
59
25
|
export const CLAUDE_DEFAULT_SETTING_SOURCES = ["project"];
|
|
@@ -31,6 +31,9 @@ function stringifyUnknown(error) {
|
|
|
31
31
|
return String(error);
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
|
+
export function formatErrorWithCause(message, error) {
|
|
35
|
+
return `${message} ${stringifyUnknown(error)}`;
|
|
36
|
+
}
|
|
34
37
|
export function logInfo(message, options = {}) {
|
|
35
38
|
log("info", message, options);
|
|
36
39
|
}
|
|
@@ -41,6 +44,5 @@ export function logError(message, options = {}) {
|
|
|
41
44
|
log("error", message, options);
|
|
42
45
|
}
|
|
43
46
|
export function logErrorWithCause(message, error, options = {}) {
|
|
44
|
-
|
|
45
|
-
logError(`${message} ${details}`, options);
|
|
47
|
+
logError(formatErrorWithCause(message, error), options);
|
|
46
48
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astrosheep/keiyaku",
|
|
3
|
-
"version": "2.9.
|
|
3
|
+
"version": "2.9.5",
|
|
4
4
|
"description": "CLI for running iterative keiyaku workflows with Codex subagents.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -24,12 +24,6 @@
|
|
|
24
24
|
},
|
|
25
25
|
"scripts": {
|
|
26
26
|
"sync:version": "node scripts/generate-version.mjs",
|
|
27
|
-
"predev": "npm run sync:version --silent",
|
|
28
|
-
"prebuild": "npm run sync:version --silent",
|
|
29
|
-
"pretest:unit": "npm run sync:version --silent",
|
|
30
|
-
"pretest:typecheck": "npm run sync:version --silent",
|
|
31
|
-
"pretest:integration": "npm run sync:version --silent",
|
|
32
|
-
"prestart": "npm run sync:version --silent",
|
|
33
27
|
"preversion": "npm test --silent",
|
|
34
28
|
"version": "npm run sync:version --silent && git add src/generated/version.ts",
|
|
35
29
|
"dev": "npx tsx src/index.ts",
|
|
@@ -37,12 +31,13 @@
|
|
|
37
31
|
"test:typecheck": "npx tsc --project tsconfig.tests.json",
|
|
38
32
|
"prepublishOnly": "npm run build",
|
|
39
33
|
"start": "node build/index.js",
|
|
40
|
-
"test:unit": "node
|
|
34
|
+
"test:unit": "node scripts/run-unit-tests.mjs",
|
|
35
|
+
"test:boundaries": "node scripts/check-import-boundaries.mjs",
|
|
41
36
|
"test:integration": "node --import ./tests/support/real-provider-path-sentinel.mjs --import tsx --test tests/integration/integration.test.ts",
|
|
42
37
|
"pretest:cli-expect": "npm run build",
|
|
43
38
|
"test:cli-expect": "node --import ./tests/support/real-provider-path-sentinel.mjs --test --test-concurrency=8 tests/cli-expect/suite/*.test.mjs",
|
|
44
39
|
"test:real-providers": "KEIYAKU_REAL_PROVIDERS=1 node --import tsx --test --test-concurrency=1 tests/real-provider/matrix.test.ts",
|
|
45
|
-
"test": "npm run test:unit && npm run test:typecheck && npm run test:integration && npm run test:cli-expect",
|
|
40
|
+
"test": "npm run test:unit && npm run test:typecheck && npm run test:boundaries && npm run test:integration && npm run test:cli-expect",
|
|
46
41
|
"release": "npm version patch && npm publish"
|
|
47
42
|
},
|
|
48
43
|
"dependencies": {
|
|
@@ -50,7 +45,6 @@
|
|
|
50
45
|
"@anthropic-ai/sdk": "^0.110.0",
|
|
51
46
|
"@earendil-works/pi-coding-agent": "^0.80.10",
|
|
52
47
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
53
|
-
"@openai/codex-sdk": "^0.113.0",
|
|
54
48
|
"@opencode-ai/sdk": "1.18.3",
|
|
55
49
|
"simple-git": "^3.21.0",
|
|
56
50
|
"yaml": "^2.9.0",
|
package/skills/keiyaku/SKILL.md
CHANGED
|
@@ -21,10 +21,11 @@ Three kinds of objects:
|
|
|
21
21
|
```bash
|
|
22
22
|
keiyaku task add "fix the flaky pump test" # write the idea down → k-3f9a21c4b0d2
|
|
23
23
|
keiyaku bind --task k-3f9a21c4b0d2 # start it: branch + worktree
|
|
24
|
-
cd .keiyaku/wt/<place> # work
|
|
25
|
-
|
|
24
|
+
cd .keiyaku/wt/<place> # work here yourself, or call an Akuma
|
|
25
|
+
keiyaku call <akuma> "fix it" # worker leaves reviewed source as a dirty tree
|
|
26
|
+
# host coordinator reviews, then git -C <worktree> add/commit accepted paths
|
|
26
27
|
keiyaku status # is anything stuck? what's next?
|
|
27
|
-
keiyaku petition <<'EOF'
|
|
28
|
+
keiyaku petition - <<'EOF' # done: seal + settle; the oath is required
|
|
28
29
|
## Oath
|
|
29
30
|
I fixed the flaky test; suite is green.
|
|
30
31
|
EOF
|
|
@@ -32,7 +33,7 @@ EOF
|
|
|
32
33
|
```
|
|
33
34
|
|
|
34
35
|
That's the whole loop. Skip the task when the work needs no planning:
|
|
35
|
-
`keiyaku bind --place NAME --objective TEXT --scope GLOB --checks CHECK` (or the same as Markdown
|
|
36
|
+
`keiyaku bind --place NAME --objective TEXT --scope GLOB --checks CHECK` (or the same as Markdown through `keiyaku bind -` — `bind --help` shows the shape).
|
|
36
37
|
|
|
37
38
|
## Getting oriented
|
|
38
39
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: keiyaku-akuma
|
|
3
|
-
description: Use
|
|
3
|
+
description: Use whenever a request mentions an Akuma, akuma, devil, demon, or 恶魔 and the work may involve calling, watching, telling, killing, or reviving one; covers Keiyaku Akuma profiles, projections, artifacts, lifecycle control, and rejoin operations.
|
|
4
4
|
allowed-tools: Bash(keiyaku *)
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -8,42 +8,56 @@ allowed-tools: Bash(keiyaku *)
|
|
|
8
8
|
|
|
9
9
|
Running devils. Contract lifecycle = `keiyaku-workflow` skill.
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## Core ideas
|
|
12
12
|
|
|
13
|
-
- **profile** —
|
|
13
|
+
- **profile** — callable configuration: frontmatter selects provider/model;
|
|
14
|
+
Markdown body gives instructions. Project overrides user, which overrides builtin.
|
|
14
15
|
- **projection** (`name/8hex`) — one live run of a devil. This is the id for `wait` / `tell` / `kill`.
|
|
15
16
|
- **artifact** (`rsp_…`) — what a finished run left behind. This is the id for `revive`.
|
|
16
17
|
|
|
17
|
-
Rule of thumb:
|
|
18
|
+
Rule of thumb: continue the same conversation with its projection id. Use an
|
|
19
|
+
artifact id with `revive` only when deliberately starting a new projection;
|
|
20
|
+
failed/dead state alone is not a reason to revive.
|
|
18
21
|
|
|
19
22
|
## Common usage
|
|
20
23
|
|
|
21
24
|
```bash
|
|
22
25
|
keiyaku akuma ls # who's callable
|
|
26
|
+
keiyaku akuma view NAME # resolved profile + live projections
|
|
23
27
|
keiyaku call NAME "do the thing" # run in foreground until it finishes
|
|
24
28
|
keiyaku call NAME --wait 10m "do the thing" # bounded: after 10m you get a snapshot, it keeps running
|
|
25
29
|
keiyaku call NAME --detach "do the thing" # fire and forget; note the projection id
|
|
26
30
|
keiyaku call NAME - < prompt.md # long prompt: literal `-` reads stdin
|
|
27
31
|
keiyaku wait <proj-id> # join a running one; prints its activity
|
|
28
32
|
keiyaku wait <proj-id> --timeout 5m # peek for 5m; timeout = snapshot, not death
|
|
29
|
-
keiyaku tell <proj-id>
|
|
30
|
-
keiyaku tell <proj-id> --wait 5m "also do X" # tell, then watch the response
|
|
33
|
+
keiyaku tell <proj-id> [--wait DURATION] <BODY|-> # optionally tell, then bounded-join
|
|
31
34
|
keiyaku revive rsp_XXXX "continue..." # new run continuing from a record
|
|
32
35
|
keiyaku kill <proj-id> # stop it; record survives, revive still works
|
|
33
36
|
keiyaku status # forgot an id? it's on the board
|
|
34
37
|
```
|
|
35
38
|
|
|
39
|
+
## Configuration
|
|
40
|
+
|
|
41
|
+
```text
|
|
42
|
+
<repo>/.keiyaku/akuma/<name>.md project profile
|
|
43
|
+
<KEIYAKU_HOME>/akuma/<name>.md user profile (normally ~/.keiyaku)
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Use `keiyaku akuma view NAME` to inspect the resolved source and configuration.
|
|
47
|
+
|
|
36
48
|
## Expectations
|
|
37
49
|
|
|
38
|
-
-
|
|
39
|
-
|
|
50
|
+
- Omit tell's bracketed `--wait DURATION` option for silent success: exit 0,
|
|
51
|
+
zero output. Supply it to perform the ordinary bounded join after acceptance.
|
|
52
|
+
Silence **is** the receipt — do not re-send. Effects show up in `wait`/`status`.
|
|
53
|
+
- Body is required for `call`/`tell`. Literal `-` selects stdin; unselected
|
|
54
|
+
piped bytes are ignored and cannot change an argv body.
|
|
40
55
|
- A `--wait`/`--timeout` expiry prints a live snapshot and exits 0 — the run continues; rejoin with `wait` anytime.
|
|
41
56
|
- `wait` is repeatable: on a finished run it shows the final transcript again.
|
|
42
|
-
- `--contract ADDR` attaches a call to a contract (by place, slug, or full id); `--bare` skips attachment explicitly. `call` only — `revive` takes neither.
|
|
43
57
|
|
|
44
58
|
## Occasional flags
|
|
45
59
|
|
|
46
60
|
- `--incognito` — no artifact written, no revive possible (call)
|
|
47
61
|
- `--effort LEVEL` — provider effort override; needs a model set (call, revive, tell)
|
|
48
|
-
-
|
|
49
|
-
|
|
62
|
+
- `--repo DIR` — override repository inference only when the contract ledger
|
|
63
|
+
lives in a different repository.
|