@astrosheep/keiyaku 2.9.3 → 2.9.4
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 +13 -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 +25 -222
- package/build/agents/harness/index.js +3 -1
- package/build/agents/harness/outcome.js +47 -4
- package/build/agents/harness/projection.js +42 -59
- 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 +50 -53
- package/build/agents/providers/codex-app-server/events.js +67 -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/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 +8 -0
- package/build/artifact-directories.js +22 -0
- package/build/cli/commands/akuma/akuma/handler.js +1 -1
- package/build/cli/commands/akuma/view/handler.js +5 -4
- package/build/cli/commands/akuma.js +6 -0
- package/build/cli/commands/contract/amend/handler.js +8 -2
- package/build/cli/commands/contract/arc/handler.js +7 -1
- package/build/cli/commands/contract/bind/handler.js +4 -3
- package/build/cli/commands/contract/bind/meta.js +34 -7
- package/build/cli/commands/contract/forfeit/handler.js +4 -4
- package/build/cli/commands/contract/log/handler.js +3 -3
- package/build/cli/commands/contract/petition/handler.js +4 -6
- package/build/cli/commands/contract/renew/handler.js +20 -6
- package/build/cli/commands/contract/renew/meta.js +5 -4
- package/build/cli/commands/metadata.js +58 -0
- package/build/cli/commands/projection/call/handler.js +6 -5
- package/build/cli/commands/projection/kill/handler.js +16 -32
- package/build/cli/commands/projection/shared.js +28 -0
- package/build/cli/commands/projection/status/handler.js +1 -1
- package/build/cli/commands/projection/tell/handler.js +14 -30
- package/build/cli/commands/projection/wait/handler.js +45 -22
- package/build/cli/commands/projection/wait/meta.js +7 -2
- 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/skills/handler.js +1 -1
- package/build/cli/commands/task/add/handler.js +5 -13
- package/build/cli/commands/task/catalog.js +2 -2
- package/build/cli/commands/task/done/handler.js +4 -8
- package/build/cli/commands/task/drop/handler.js +3 -6
- package/build/cli/commands/task/ls/handler.js +3 -5
- 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/stop/handler.js +4 -8
- package/build/cli/commands/task/task/handler.js +1 -1
- package/build/cli/commands/task/update/handler.js +4 -8
- package/build/cli/completion.js +1 -1
- package/build/cli/flags.js +19 -3
- package/build/cli/help.js +4 -11
- package/build/cli/index.js +57 -83
- package/build/cli/missing-subcommand.js +7 -0
- package/build/cli/parse-flags.js +14 -5
- package/build/cli/parse-metadata.js +3 -3
- package/build/cli/parse-selectors.js +1 -1
- package/build/cli/parse.js +21 -0
- package/build/cli/projection-address.js +7 -12
- package/build/cli/render/address.js +41 -37
- package/build/cli/render/arc.js +24 -12
- 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 +55 -12
- package/build/cli/render/petition.js +20 -15
- package/build/cli/render/projection-activity.js +3 -0
- package/build/cli/render/shared.js +60 -21
- package/build/cli/render/skills.js +10 -0
- package/build/cli/render/status.js +37 -14
- package/build/cli/render/success-response.js +77 -0
- package/build/cli/render/task.js +54 -14
- package/build/cli/render/tell.js +5 -0
- package/build/cli/render/terminal-failure.js +58 -0
- package/build/cli/render/types.js +1 -0
- package/build/cli/render/wait.js +38 -36
- package/build/cli/types.js +1 -1
- package/build/config/akuma-loader.js +0 -5
- package/build/config/env-keys.js +1 -1
- 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 +135 -18
- package/build/core/arc.js +19 -67
- 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 +21 -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 +20 -3
- package/build/core/draft.js +123 -16
- 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/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 +2 -38
- package/build/core/projection/generation/model.js +42 -1
- 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} +19 -49
- 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} +5 -3
- 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} +18 -3
- package/build/core/projection/generation/store.js +2 -2
- package/build/core/projection/generation/transitions.js +1 -1
- 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} +2 -57
- 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} +1 -1
- package/build/core/{projection-mint.js → projection/projection-mint.js} +10 -10
- package/build/core/{projection-status.js → projection/projection-status.js} +98 -25
- package/build/core/projection/projection-terminal-failure.js +104 -0
- package/build/core/projection/projection-wait.js +278 -0
- package/build/core/projection/projection-wake.js +203 -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 +426 -99
- package/build/core/scope.js +143 -66
- package/build/core/seal.js +139 -35
- 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} +22 -18
- 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} +1 -1
- package/build/core/{petition.js → settlement/petition.js} +12 -10
- 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 +295 -0
- package/build/core/{verdict.js → settlement/verdict.js} +9 -37
- package/build/core/status/board.js +24 -23
- package/build/core/status/ledger-batch.js +158 -0
- package/build/core/status/reconciliation.js +10 -4
- package/build/core/stored-agent-event.js +3 -0
- package/build/core/task/board.js +40 -4
- package/build/core/task/commands.js +30 -21
- package/build/core/task/index.js +12 -0
- package/build/core/task/settlement-git.js +157 -65
- package/build/core/task/settlement-policy.js +54 -24
- package/build/core/task/task-contract.js +370 -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} +5 -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 +5 -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 +85 -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/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 +3 -3
- package/build/keiyaku.js +2 -36
- package/package.json +4 -10
- package/skills/keiyaku/SKILL.md +3 -2
- package/skills/keiyaku-akuma/SKILL.md +9 -6
- package/skills/keiyaku-task/SKILL.md +1 -1
- package/skills/keiyaku-workflow/SKILL.md +23 -3
- 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,10 +1,10 @@
|
|
|
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
6
|
import { logErrorWithCause } from "./telemetry/logger.js";
|
|
7
|
-
import { runProjectionGenerationRuntime } from "./core/projection
|
|
7
|
+
import { runProjectionGenerationRuntime } from "./core/projection/index.js";
|
|
8
8
|
import { renderCliHelp, runCliCommand } from "./cli/index.js";
|
|
9
9
|
import { installCliOutputStreamErrorPolicy } from "./cli/output-stream-error-policy.js";
|
|
10
10
|
import { assertSubagentCliCommandAllowed } from "./cli/subagent-guard.js";
|
|
@@ -45,7 +45,7 @@ async function main() {
|
|
|
45
45
|
args: cliArgs,
|
|
46
46
|
});
|
|
47
47
|
if (cliArgs.length === 1 && cliArgs[0] === "--version") {
|
|
48
|
-
console.log(packageVersion);
|
|
48
|
+
console.log(GIT_HASH ? `${packageVersion} (${GIT_HASH})` : packageVersion);
|
|
49
49
|
return;
|
|
50
50
|
}
|
|
51
51
|
if (cliArgs.length === 0 || (cliArgs.length === 1 && (cliArgs[0] === "--help" || cliArgs[0] === "-h"))) {
|
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"];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astrosheep/keiyaku",
|
|
3
|
-
"version": "2.9.
|
|
3
|
+
"version": "2.9.4",
|
|
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,8 +21,9 @@ 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
28
|
keiyaku petition <<'EOF' # done: seal + settle; the oath is required
|
|
28
29
|
## Oath
|
|
@@ -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
|
|
|
@@ -14,7 +14,9 @@ Running devils. Contract lifecycle = `keiyaku-workflow` skill.
|
|
|
14
14
|
- **projection** (`name/8hex`) — one live run of a devil. This is the id for `wait` / `tell` / `kill`.
|
|
15
15
|
- **artifact** (`rsp_…`) — what a finished run left behind. This is the id for `revive`.
|
|
16
16
|
|
|
17
|
-
Rule of thumb:
|
|
17
|
+
Rule of thumb: continue the same conversation with its projection id. Use an
|
|
18
|
+
artifact id with `revive` only when deliberately starting a new projection;
|
|
19
|
+
failed/dead state alone is not a reason to revive.
|
|
18
20
|
|
|
19
21
|
## Common usage
|
|
20
22
|
|
|
@@ -26,8 +28,7 @@ keiyaku call NAME --detach "do the thing" # fire and forget; note the projec
|
|
|
26
28
|
keiyaku call NAME - < prompt.md # long prompt: literal `-` reads stdin
|
|
27
29
|
keiyaku wait <proj-id> # join a running one; prints its activity
|
|
28
30
|
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
|
|
31
|
+
keiyaku tell <proj-id> [--wait DURATION] <BODY|-> # optionally tell, then bounded-join
|
|
31
32
|
keiyaku revive rsp_XXXX "continue..." # new run continuing from a record
|
|
32
33
|
keiyaku kill <proj-id> # stop it; record survives, revive still works
|
|
33
34
|
keiyaku status # forgot an id? it's on the board
|
|
@@ -35,11 +36,13 @@ keiyaku status # forgot an id? it's on the board
|
|
|
35
36
|
|
|
36
37
|
## Expectations
|
|
37
38
|
|
|
38
|
-
-
|
|
39
|
+
- Omit tell's bracketed `--wait DURATION` option for silent success: exit 0,
|
|
40
|
+
zero output. Supply it to perform the ordinary bounded join after acceptance.
|
|
41
|
+
Silence **is** the receipt — do not re-send. Effects show up in `wait`/`status`.
|
|
39
42
|
- Body is required for `call`/`tell`. Piping stdin without a literal `-` does nothing.
|
|
40
43
|
- A `--wait`/`--timeout` expiry prints a live snapshot and exits 0 — the run continues; rejoin with `wait` anytime.
|
|
41
44
|
- `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`
|
|
45
|
+
- Only `--contract ADDR` attaches a new call to a contract (by place, slug, or full id). Without it, call is standalone; `--bare` remains an explicit synonym. `call` only — `revive` takes neither and follows artifact provenance.
|
|
43
46
|
|
|
44
47
|
## Occasional flags
|
|
45
48
|
|
|
@@ -24,7 +24,7 @@ open ⇄ in_progress → done | drop
|
|
|
24
24
|
keiyaku task add "fix the flaky pump test" # body: pipe stdin for details
|
|
25
25
|
keiyaku task add "title" --pri 1 --needs k-aaa # priority + dependency at birth
|
|
26
26
|
keiyaku task ls # all open, priority order
|
|
27
|
-
keiyaku task
|
|
27
|
+
keiyaku task show k-xxxx # full detail and parent-children tree
|
|
28
28
|
keiyaku task start k-xxxx # mark in_progress (start ≠ execute)
|
|
29
29
|
keiyaku task stop k-xxxx # back to open
|
|
30
30
|
keiyaku task done k-xxxx
|
|
@@ -10,7 +10,7 @@ How a contract lives. Running akuma is the `keiyaku-akuma` skill; task planning
|
|
|
10
10
|
|
|
11
11
|
## Mind model
|
|
12
12
|
|
|
13
|
-
A contract = one branch + one worktree + a ledger (its record file in the repo).
|
|
13
|
+
A contract = one branch + one linked worktree + a ledger (its record file in the repo). A sandbox worker edits and tests inside that worktree, then hands the host coordinator an uncommitted dirty tree plus its changed-file and check report. The host reviews and commits accepted bytes before running workflow verbs that seal or rewrite delivery. States:
|
|
14
14
|
|
|
15
15
|
```
|
|
16
16
|
bound → active → petitioned → claimed | forfeited
|
|
@@ -25,7 +25,11 @@ keiyaku bind --place fix-pump --objective "make the pump test pass" \
|
|
|
25
25
|
# (# <name> / ## Objective / ## Scope / ## Checks)
|
|
26
26
|
# or promote a ready task: keiyaku bind --task k-xxxx
|
|
27
27
|
|
|
28
|
-
cd .keiyaku/wt/fix-pump #
|
|
28
|
+
cd .keiyaku/wt/fix-pump # worker edits/tests here and leaves a dirty tree
|
|
29
|
+
|
|
30
|
+
# Back on the host after reviewing the worker's diff and test report:
|
|
31
|
+
git -C .keiyaku/wt/fix-pump add -- <accepted-paths>
|
|
32
|
+
git -C .keiyaku/wt/fix-pump commit -m "fix pump"
|
|
29
33
|
|
|
30
34
|
keiyaku petition <<'EOF'
|
|
31
35
|
## Oath
|
|
@@ -37,7 +41,9 @@ EOF
|
|
|
37
41
|
# The oath is required (OATH_MISSING otherwise) and checked for presence, not content.
|
|
38
42
|
```
|
|
39
43
|
|
|
40
|
-
That's the whole small case: bind → commit → petition.
|
|
44
|
+
That's the whole small case: bind → worker dirty-tree handoff → host review/commit → petition.
|
|
45
|
+
|
|
46
|
+
Commissioned workers never run `git add`, `git commit`, or another command that writes Git metadata. Codex workspace-write deliberately keeps `.git` and a linked worktree's resolved gitdir read-only; adding either location to writable roots is not an authorization mechanism. A worker-side Git metadata refusal is therefore not failed delivery. The host coordinator alone commits accepted bytes with native Git, then continues `arc`, `renew`, or `petition`.
|
|
41
47
|
|
|
42
48
|
## Mid-flight commands (use when needed, skip otherwise)
|
|
43
49
|
|
|
@@ -51,6 +57,20 @@ keiyaku amend < amendment.md # scope/checks changed → update the paper before
|
|
|
51
57
|
keiyaku log # this contract's history
|
|
52
58
|
```
|
|
53
59
|
|
|
60
|
+
`amend` accepts prose plus an optional ordered scope-pattern delta:
|
|
61
|
+
|
|
62
|
+
```markdown
|
|
63
|
+
Clarify the owned documentation surface.
|
|
64
|
+
|
|
65
|
+
## Scope Add
|
|
66
|
+
docs/**
|
|
67
|
+
!docs/generated/**
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
`Scope Add` appends patterns to the contract; it is not set-union semantics.
|
|
71
|
+
Patterns retain ordered Git-ignore behavior, so a later `!pattern` excludes a
|
|
72
|
+
previous match and can narrow the effective scope.
|
|
73
|
+
|
|
54
74
|
Gotchas:
|
|
55
75
|
- Base drift blocks petition — if main moved, `renew` first; petition tells you.
|
|
56
76
|
- After an explicit `arc` seals, new loose commits need another `arc` before `renew`/`petition` accept them.
|