@astrosheep/keiyaku 0.1.87 → 1.0.0

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.
Files changed (158) hide show
  1. package/README.md +12 -22
  2. package/build/.tsbuildinfo +1 -1
  3. package/build/agents/effective-policy.js +32 -0
  4. package/build/agents/harness/event-channel.js +178 -0
  5. package/build/agents/harness/execution-handle.js +117 -0
  6. package/build/agents/harness/index.js +622 -0
  7. package/build/agents/harness/pump.js +152 -0
  8. package/build/agents/harness/runtime.js +68 -0
  9. package/build/agents/index.js +104 -213
  10. package/build/agents/opencode-sdk.js +12 -18
  11. package/build/agents/providers/claude-agent-sdk.js +529 -0
  12. package/build/agents/providers/codex-app-server.js +656 -0
  13. package/build/agents/providers/codex-sdk.js +193 -0
  14. package/build/agents/providers/opencode-sdk.js +257 -0
  15. package/build/agents/providers/pi.js +345 -0
  16. package/build/agents/selector.js +15 -6
  17. package/build/agents/session.js +29 -0
  18. package/build/agents/types.js +5 -11
  19. package/build/cli/commands/akuma.js +79 -0
  20. package/build/cli/completion.js +71 -0
  21. package/build/cli/draft-artifact.js +50 -0
  22. package/build/cli/flags.js +96 -0
  23. package/build/cli/help.js +108 -0
  24. package/build/cli/index.js +204 -912
  25. package/build/cli/parse.js +280 -0
  26. package/build/cli/render/arc.js +63 -0
  27. package/build/{responses/tool-errors.js → cli/render/errors.js} +15 -16
  28. package/build/cli/render/format.js +199 -0
  29. package/build/cli/render/misc.js +40 -0
  30. package/build/cli/render/petition.js +32 -0
  31. package/build/{responses → cli/render}/response-style.js +4 -4
  32. package/build/cli/render/shared.js +122 -0
  33. package/build/cli/render/status.js +69 -0
  34. package/build/cli/render/summon.js +17 -0
  35. package/build/cli/render/tell.js +11 -0
  36. package/build/cli/skills-install.js +237 -0
  37. package/build/cli/subagent-guard.js +6 -3
  38. package/build/config/akuma-loader.js +268 -0
  39. package/build/config/env-keys.js +0 -10
  40. package/build/config/{schema.js → env.js} +117 -23
  41. package/build/config/settings.js +137 -260
  42. package/build/core/amend.js +120 -0
  43. package/build/core/arc.js +225 -0
  44. package/build/core/atomic-publish.js +64 -0
  45. package/build/core/bind.js +281 -0
  46. package/build/core/claim.js +360 -0
  47. package/build/core/command-io.js +174 -0
  48. package/build/core/context.js +108 -0
  49. package/build/core/contract.js +14 -0
  50. package/build/core/draft.js +82 -0
  51. package/build/core/entry.js +203 -0
  52. package/build/core/forfeit.js +60 -0
  53. package/build/core/hints.js +108 -0
  54. package/build/core/ids.js +70 -0
  55. package/build/core/ledger.js +117 -0
  56. package/build/core/log.js +24 -0
  57. package/build/{protocol → core}/markdown/parser.js +68 -0
  58. package/build/{protocol → core}/markdown/sections.js +2 -28
  59. package/build/core/markdown/titles.js +9 -0
  60. package/build/{tools/petition/claim-gates.js → core/petition-claim-gates.js} +43 -29
  61. package/build/core/petition-claim.js +116 -0
  62. package/build/core/petition-forfeit.js +39 -0
  63. package/build/{tools/round/head-guard.js → core/petition-head-guard.js} +2 -2
  64. package/build/core/petition-run.js +81 -0
  65. package/build/core/petition.js +96 -0
  66. package/build/core/places.js +82 -0
  67. package/build/core/projection-core.js +541 -0
  68. package/build/core/projection-mint.js +79 -0
  69. package/build/core/projection-status.js +179 -0
  70. package/build/core/projection-wake.js +252 -0
  71. package/build/core/queue.js +73 -0
  72. package/build/core/ref-log.js +94 -0
  73. package/build/core/registry.js +96 -0
  74. package/build/core/render.js +326 -0
  75. package/build/core/renew.js +195 -0
  76. package/build/core/scope.js +163 -0
  77. package/build/core/seal.js +195 -0
  78. package/build/core/status.js +476 -0
  79. package/build/{tools/summon/persist.js → core/summon-persist.js} +10 -9
  80. package/build/core/summon.js +377 -0
  81. package/build/{protocol/response-history.js → core/transcripts.js} +83 -39
  82. package/build/core/verdict.js +96 -0
  83. package/build/core/worktree-path.js +134 -0
  84. package/build/flow-error.js +80 -4
  85. package/build/generated/version.js +1 -1
  86. package/build/git/branches.js +8 -9
  87. package/build/git/core.js +1 -1
  88. package/build/git/diff/pathspec.js +2 -3
  89. package/build/git/diff/preview.js +7 -2
  90. package/build/git/diff/read.js +4 -3
  91. package/build/git/staging.js +1 -1
  92. package/build/index.js +12 -6
  93. package/build/keiyaku.js +17 -13
  94. package/build/telemetry/debug-log.js +1 -1
  95. package/package.json +16 -9
  96. package/skills/keiyaku/SKILL.md +16 -13
  97. package/build/agents/claude-agent-sdk-exec.js +0 -352
  98. package/build/agents/codex-cli-exec.js +0 -237
  99. package/build/agents/codex-sdk-exec.js +0 -291
  100. package/build/agents/gemini-cli-core-exec.js +0 -499
  101. package/build/agents/opencode-exec.js +0 -297
  102. package/build/agents/process-runner.js +0 -239
  103. package/build/agents/progress-reporter.js +0 -137
  104. package/build/agents/round-runner.js +0 -53
  105. package/build/config/apply-argument-descriptions.js +0 -16
  106. package/build/config/architect-hints.js +0 -374
  107. package/build/config/base-rules.js +0 -23
  108. package/build/config/config.js +0 -50
  109. package/build/config/dotenv.js +0 -61
  110. package/build/config/keiyaku-home.js +0 -9
  111. package/build/config/path-utils.js +0 -11
  112. package/build/config/render-template.js +0 -8
  113. package/build/git/diff/filter.js +0 -67
  114. package/build/git/keiyaku-state.js +0 -58
  115. package/build/git/snapshot.js +0 -41
  116. package/build/git/stash.js +0 -62
  117. package/build/protocol/bind-draft.js +0 -195
  118. package/build/protocol/draft-artifacts.js +0 -99
  119. package/build/protocol/file-guards.js +0 -24
  120. package/build/protocol/keiyaku-draft.js +0 -168
  121. package/build/protocol/ledger.js +0 -374
  122. package/build/protocol/markdown/index.js +0 -14
  123. package/build/protocol/markdown/normalization.js +0 -71
  124. package/build/protocol/markdown/render.js +0 -68
  125. package/build/protocol/oath.js +0 -36
  126. package/build/protocol/render-keiyaku.js +0 -37
  127. package/build/protocol/review.js +0 -1
  128. package/build/protocol/status-previews.js +0 -68
  129. package/build/responses/responses.js +0 -515
  130. package/build/tools/amend/index.js +0 -18
  131. package/build/tools/amend/run.js +0 -44
  132. package/build/tools/bind/index.js +0 -44
  133. package/build/tools/bind/run.js +0 -237
  134. package/build/tools/contracts.js +0 -1
  135. package/build/tools/create-handler.js +0 -31
  136. package/build/tools/help.js +0 -9
  137. package/build/tools/petition/claim.js +0 -174
  138. package/build/tools/petition/forfeit.js +0 -100
  139. package/build/tools/petition/index.js +0 -83
  140. package/build/tools/petition/run.js +0 -66
  141. package/build/tools/round/guidance.js +0 -7
  142. package/build/tools/round/prompt.js +0 -70
  143. package/build/tools/round/report.js +0 -153
  144. package/build/tools/round/worktree.js +0 -55
  145. package/build/tools/round-close/index.js +0 -19
  146. package/build/tools/round-close/run.js +0 -98
  147. package/build/tools/round-open/index.js +0 -20
  148. package/build/tools/round-open/run.js +0 -77
  149. package/build/tools/schema.js +0 -69
  150. package/build/tools/status/index.js +0 -16
  151. package/build/tools/status/read.js +0 -155
  152. package/build/tools/summon/index.js +0 -27
  153. package/build/tools/summon/run.js +0 -80
  154. /package/build/{config/toml.js → agents/harness/events.js} +0 -0
  155. /package/build/{git/diff/contracts.js → cli/render/types.js} +0 -0
  156. /package/build/{protocol/bind-input.js → cli/types.js} +0 -0
  157. /package/build/{protocol → core}/markdown/lex.js +0 -0
  158. /package/build/{protocol → core}/markdown/types.js +0 -0
@@ -1,44 +0,0 @@
1
- import * as fs from "node:fs/promises";
2
- import * as path from "node:path";
3
- import { KEIYAKU_BRANCH_PREFIX, KEIYAKU_FILE } from "../../keiyaku.js";
4
- import { FlowError, requireText } from "../../flow-error.js";
5
- import { isGitRepo } from "../../git/branches.js";
6
- import { getActiveKeiyakuGitState } from "../../git/keiyaku-state.js";
7
- import { addFiles, commit, getLatestCommitHash } from "../../git/staging.js";
8
- import { assertKeiyakuProtocolFiles } from "../../protocol/file-guards.js";
9
- import { appendKeiyakuAmendment } from "../../protocol/render-keiyaku.js";
10
- import { buildNoActiveKeiyakuGuidance } from "../round/guidance.js";
11
- import { assertCleanWorkingTree } from "../round/worktree.js";
12
- function buildAmendCommitMessage(titleToken, amendmentNumber) {
13
- return `keiyaku(${titleToken}): amend ${amendmentNumber}`;
14
- }
15
- export async function amendKeiyaku(input) {
16
- const isRepo = await isGitRepo(input.cwd);
17
- if (!isRepo) {
18
- throw new FlowError("NOT_GIT_REPO", `${input.cwd} is not a git repository`);
19
- }
20
- const activeState = await getActiveKeiyakuGitState(input.cwd);
21
- if (!activeState) {
22
- const guidance = await buildNoActiveKeiyakuGuidance(input.cwd, "amend");
23
- throw new FlowError("NOT_ACTIVE_KEIYAKU_BRANCH", guidance.message, { hints: guidance.hints });
24
- }
25
- await assertCleanWorkingTree(input.cwd, []);
26
- await assertKeiyakuProtocolFiles(input.cwd);
27
- const amendment = requireText("amendment", input.amendment);
28
- const keiyakuPath = path.join(input.cwd, KEIYAKU_FILE);
29
- const currentKeiyaku = await fs.readFile(keiyakuPath, "utf-8");
30
- const nextKeiyaku = appendKeiyakuAmendment(currentKeiyaku, { amendment });
31
- await fs.writeFile(keiyakuPath, nextKeiyaku.content, "utf-8");
32
- await addFiles(input.cwd, [KEIYAKU_FILE]);
33
- const title = activeState.branch.slice(KEIYAKU_BRANCH_PREFIX.length);
34
- await commit(input.cwd, buildAmendCommitMessage(title, nextKeiyaku.amendmentNumber));
35
- const commitHash = await getLatestCommitHash(input.cwd);
36
- return {
37
- status: "success",
38
- amendmentNumber: nextKeiyaku.amendmentNumber,
39
- currentBranch: activeState.branch,
40
- baseBranch: activeState.baseBranch,
41
- commit: commitHash,
42
- summary: `Appended Amendment ${nextKeiyaku.amendmentNumber} to ${KEIYAKU_FILE}.`,
43
- };
44
- }
@@ -1,44 +0,0 @@
1
- import { bindKeiyaku } from "./run.js";
2
- import { buildBindSuccessResponse, } from "../../responses/responses.js";
3
- import { createToolHandler } from "../create-handler.js";
4
- function normalizeOptionalArg(value) {
5
- if (value === undefined)
6
- return undefined;
7
- return value.trim().length > 0 ? value : undefined;
8
- }
9
- export function createBindHandler() {
10
- return createToolHandler({
11
- logLabel: "tool bind",
12
- doneLog: (result) => `tool bind success branch=${result.currentBranch} base=${result.baseBranch} round=${result.round}`,
13
- async run({ from_draft, draft_only, title, goal, context, rules, criteria, cwd }, extra) {
14
- const normalizedFromDraft = normalizeOptionalArg(from_draft);
15
- const parsedCriteria = normalizeOptionalArg(criteria);
16
- const parsedRules = normalizeOptionalArg(rules);
17
- return normalizedFromDraft
18
- ? bindKeiyaku({
19
- cwd,
20
- from_draft: normalizedFromDraft,
21
- draft_only,
22
- title: normalizeOptionalArg(title),
23
- goal: normalizeOptionalArg(goal),
24
- context: normalizeOptionalArg(context),
25
- rules: parsedRules,
26
- criteria: parsedCriteria,
27
- signal: extra.signal,
28
- })
29
- : bindKeiyaku({
30
- cwd,
31
- draft_only,
32
- title: title ?? "",
33
- goal: goal ?? "",
34
- context: context ?? "",
35
- rules: parsedRules,
36
- criteria: parsedCriteria ?? "",
37
- signal: extra.signal,
38
- });
39
- },
40
- buildResponse(result) {
41
- return buildBindSuccessResponse(result);
42
- },
43
- });
44
- }
@@ -1,237 +0,0 @@
1
- import * as fs from "fs/promises";
2
- import * as path from "path";
3
- import { KEIYAKU_BRANCH_PREFIX, KEIYAKU_FILE } from "../../keiyaku.js";
4
- import { isErrnoException } from "../../errno.js";
5
- import { logInfo, logWarn } from "../../telemetry/logger.js";
6
- import { FlowError } from "../../flow-error.js";
7
- import { assertValidBranchName, checkoutBranch, createAndCheckoutBranch, deleteBranch, getCurrentBranch, hasLocalBranch, isGitRepo, listLocalKeiyakuBranches } from "../../git/branches.js";
8
- import { clearKeiyakuBase, getActiveKeiyakuGitState, setKeiyakuBase } from "../../git/keiyaku-state.js";
9
- import { addFiles, addFilesForce, commit as commitChanges, getLatestCommitHash } from "../../git/staging.js";
10
- import { discardAllWorkingTreeChanges } from "../../git/stash.js";
11
- import { isPathTracked } from "../../git/worktree.js";
12
- import { assertCleanWorkingTree } from "../round/worktree.js";
13
- import { renderKeiyaku } from "../../protocol/render-keiyaku.js";
14
- import { readBaseRules } from "../../config/base-rules.js";
15
- import { buildBindRollbackFailureWarning, evaluateWorkflowHints, getBindProtocolFileWarning, } from "../../config/architect-hints.js";
16
- import { persistResponseHistory } from "../../protocol/response-history.js";
17
- import { appendDebugLog } from "../../telemetry/debug-log.js";
18
- import { writeDraftArtifact } from "../../protocol/draft-artifacts.js";
19
- import { captureRollbackDraftSnapshots, handleBindFailure, resolveGitRelativePath, resolveBindInput, restoreRollbackDraftSnapshots, } from "../../protocol/bind-draft.js";
20
- const BIND_CONSUME_FROM_DRAFT_COMMIT_SUFFIX = "consume from_draft";
21
- const BIND_READY_SUMMARY = "Bound keiyaku branch and KEIYAKU.md. Run round open to frame round 1.";
22
- const BIND_READY_DIFF = "No diff.";
23
- function buildActiveKeiyakuBindMessage(branch) {
24
- return `Active keiyaku detected on branch '${branch}'.`;
25
- }
26
- async function fileExists(filePath) {
27
- try {
28
- await fs.access(filePath);
29
- return true;
30
- }
31
- catch (error) {
32
- if (isErrnoException(error) && error.code === "ENOENT") {
33
- return false;
34
- }
35
- throw error;
36
- }
37
- }
38
- async function assertBindPreFlight(cwd) {
39
- const existing = (await fileExists(path.join(cwd, KEIYAKU_FILE))) ? [KEIYAKU_FILE] : [];
40
- if (existing.length > 0) {
41
- throw new FlowError("KEIYAKU_FILE_EXISTS", `pre-flight failed: ${existing.join(", ")} already exist in cwd — remove them before starting`);
42
- }
43
- }
44
- function normalizeTitleForBranch(title) {
45
- const normalized = title
46
- .trim()
47
- .toLowerCase()
48
- .replace(/[^\p{Script=Han}a-z0-9]+/gu, "-")
49
- .replace(/-+/g, "-")
50
- .replace(/^-+/, "")
51
- .replace(/-+$/, "");
52
- if (!normalized) {
53
- throw new FlowError("INVALID_BRANCH_TITLE", "title cannot be converted to a valid branch name; branch tokens support letters and numbers");
54
- }
55
- return normalized;
56
- }
57
- async function buildKeiyakuContent(cwd, resolved) {
58
- const baseRules = (await readBaseRules(cwd)) ?? "";
59
- const content = renderKeiyaku(resolved.title, resolved.goal, resolved.context, baseRules, resolved.rules, resolved.criteria);
60
- return { content, baseRules };
61
- }
62
- async function initKeiyakuBranch(cwd, resolved, keiyakuContent) {
63
- const isRepo = await isGitRepo(cwd);
64
- if (!isRepo) {
65
- throw new FlowError("NOT_GIT_REPO", `${cwd} is not a git repository`);
66
- }
67
- const activeState = await getActiveKeiyakuGitState(cwd);
68
- if (activeState) {
69
- throw new FlowError("ACTIVE_KEIYAKU_EXISTS", buildActiveKeiyakuBindMessage(activeState.branch));
70
- }
71
- let existingBranches;
72
- const existingKeiyakuBranches = await listLocalKeiyakuBranches(cwd);
73
- if (existingKeiyakuBranches.length > 0) {
74
- existingBranches = existingKeiyakuBranches;
75
- const branchWarning = `[keiyaku] existing local keiyaku branches detected (non-blocking): ${existingKeiyakuBranches.join(", ")}`;
76
- logInfo(branchWarning, { cwd, section: "script", progressOnly: true });
77
- }
78
- await assertBindPreFlight(cwd);
79
- const dirtyAllowlist = Array.from(new Set(resolved.dirtyAllowlist));
80
- await assertCleanWorkingTree(cwd, dirtyAllowlist);
81
- const baseBranch = await getCurrentBranch(cwd);
82
- const branchToken = normalizeTitleForBranch(resolved.title);
83
- const keiyakuBranch = `${KEIYAKU_BRANCH_PREFIX}${branchToken}`;
84
- await assertValidBranchName(cwd, keiyakuBranch);
85
- await createAndCheckoutBranch(cwd, keiyakuBranch);
86
- await setKeiyakuBase(cwd, keiyakuBranch, baseBranch);
87
- logInfo(`Switched to branch: ${keiyakuBranch} (base: ${baseBranch})`, { cwd, section: "script", progressOnly: true });
88
- await fs.writeFile(path.join(cwd, KEIYAKU_FILE), keiyakuContent);
89
- await addFilesForce(cwd, [KEIYAKU_FILE]);
90
- await commitChanges(cwd, `keiyaku(${branchToken}): open`);
91
- const commit = await getLatestCommitHash(cwd);
92
- return {
93
- branchToken,
94
- keiyakuBranch,
95
- baseBranch,
96
- commit,
97
- existingBranches,
98
- };
99
- }
100
- async function finalizeBindKeiyaku(input, resolved, setup, baseRules) {
101
- const { cwd } = input;
102
- const { branchToken, baseBranch, existingBranches, keiyakuBranch } = setup;
103
- const summary = BIND_READY_SUMMARY;
104
- const diff = BIND_READY_DIFF;
105
- let commit = setup.commit;
106
- let consumedFromDraft;
107
- if (resolved.fromDraft && resolved.fromDraftPath) {
108
- const trackedFromDraftPath = resolveGitRelativePath(cwd, resolved.fromDraftPath);
109
- const shouldCommitDeletion = trackedFromDraftPath !== null && (await isPathTracked(cwd, trackedFromDraftPath));
110
- await fs.unlink(resolved.fromDraftPath);
111
- if (shouldCommitDeletion && trackedFromDraftPath) {
112
- await addFiles(cwd, trackedFromDraftPath);
113
- await commitChanges(cwd, `keiyaku(${branchToken}): ${BIND_CONSUME_FROM_DRAFT_COMMIT_SUFFIX}`);
114
- commit = await getLatestCommitHash(cwd);
115
- }
116
- consumedFromDraft = resolved.fromDraft;
117
- logInfo(`[keiyaku] Consumed from_draft and deleted source draft: ${resolved.fromDraft}`, {
118
- cwd,
119
- section: "script",
120
- progressOnly: true,
121
- });
122
- }
123
- let responsePath;
124
- try {
125
- responsePath = await persistResponseHistory({
126
- cwd,
127
- tool: "bind",
128
- title: resolved.title.trim() || branchToken || "bind",
129
- goal: resolved.goal,
130
- criteria: resolved.criteria,
131
- summary,
132
- diff,
133
- branch: keiyakuBranch,
134
- commit,
135
- });
136
- }
137
- catch (historyError) {
138
- const historyErrorMessage = historyError instanceof Error ? historyError.message : String(historyError);
139
- logWarn(`Failed to persist bind response: ${historyErrorMessage}`, { cwd, section: "script" });
140
- appendDebugLog(`tool bind response persistence failed: ${historyErrorMessage}`, {
141
- cwd,
142
- section: "script",
143
- });
144
- }
145
- return {
146
- status: "success",
147
- round: 0,
148
- diff,
149
- summary,
150
- rules: baseRules,
151
- responsePath,
152
- consumedFromDraft,
153
- existingBranches,
154
- currentBranch: keiyakuBranch,
155
- baseBranch,
156
- commit,
157
- meta: {
158
- warnings: [getBindProtocolFileWarning()],
159
- hints: evaluateWorkflowHints("bind"),
160
- },
161
- };
162
- }
163
- async function rollbackBranchCreation(cwd, keiyakuBranch, baseBranch) {
164
- // Discard all working tree changes before switching branches to avoid checkout conflicts
165
- await discardAllWorkingTreeChanges(cwd);
166
- await checkoutBranch(cwd, baseBranch);
167
- if (await hasLocalBranch(cwd, keiyakuBranch)) {
168
- await deleteBranch(cwd, keiyakuBranch, true);
169
- }
170
- await clearKeiyakuBase(cwd, keiyakuBranch);
171
- }
172
- export async function bindKeiyaku(input) {
173
- const { cwd, signal, draft_only } = input;
174
- const resolved = await resolveBindInput(cwd, input);
175
- let keiyakuContent;
176
- let setup;
177
- let rollbackDraftSnapshots = [];
178
- let baseRules = "";
179
- try {
180
- // Eagerly render content to enable draft recovery on early failures.
181
- const rendered = await buildKeiyakuContent(cwd, resolved);
182
- keiyakuContent = rendered.content;
183
- baseRules = rendered.baseRules;
184
- if (draft_only) {
185
- const draftPath = await writeDraftArtifact({
186
- cwd,
187
- title: resolved.title,
188
- content: keiyakuContent,
189
- });
190
- logInfo(`[keiyaku] Draft-only bind wrote ${draftPath}.`, { cwd, section: "script", progressOnly: true });
191
- return {
192
- status: "success",
193
- round: 0,
194
- diff: BIND_READY_DIFF,
195
- summary: `Draft generated at ${draftPath}.`,
196
- rules: baseRules,
197
- draftPath,
198
- draftOnly: true,
199
- currentBranch: "",
200
- baseBranch: "",
201
- meta: {
202
- warnings: [getBindProtocolFileWarning()],
203
- hints: evaluateWorkflowHints("bind"),
204
- },
205
- };
206
- }
207
- setup = await initKeiyakuBranch(cwd, resolved, keiyakuContent);
208
- rollbackDraftSnapshots = await captureRollbackDraftSnapshots(cwd, resolved.fromDraftPath);
209
- return await finalizeBindKeiyaku({ cwd, signal }, resolved, setup, baseRules);
210
- }
211
- catch (err) {
212
- if (setup?.baseBranch && setup.keiyakuBranch) {
213
- try {
214
- await rollbackBranchCreation(cwd, setup.keiyakuBranch, setup.baseBranch);
215
- }
216
- catch (rollbackError) {
217
- const rollbackMessage = rollbackError instanceof Error ? rollbackError.message : String(rollbackError);
218
- logWarn(buildBindRollbackFailureWarning(rollbackMessage, setup.baseBranch, setup.keiyakuBranch), {
219
- cwd,
220
- section: "script",
221
- });
222
- }
223
- finally {
224
- if (rollbackDraftSnapshots.length > 0) {
225
- try {
226
- await restoreRollbackDraftSnapshots(cwd, rollbackDraftSnapshots);
227
- }
228
- catch (restoreError) {
229
- const restoreMessage = restoreError instanceof Error ? restoreError.message : String(restoreError);
230
- logWarn(`[keiyaku] Bind rollback draft restoration failed: ${restoreMessage}`, { cwd, section: "script" });
231
- }
232
- }
233
- }
234
- }
235
- return handleBindFailure(cwd, err, keiyakuContent, resolved.title, resolved.fromDraft);
236
- }
237
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,31 +0,0 @@
1
- import { appendDebugLog } from "../telemetry/debug-log.js";
2
- import { handleToolError } from "../responses/tool-errors.js";
3
- const TOOL_LOG_SECTION = "script";
4
- function resolveWorkingDirectory(cwd) {
5
- return typeof cwd === "string" && cwd.length > 0 ? cwd : process.cwd();
6
- }
7
- export function createToolHandler(config) {
8
- return async (input, extra) => {
9
- const normalizedInput = { ...input, cwd: resolveWorkingDirectory(input.cwd) };
10
- try {
11
- appendDebugLog(`${config.logLabel} cwd=${normalizedInput.cwd}`, {
12
- cwd: normalizedInput.cwd,
13
- section: TOOL_LOG_SECTION,
14
- });
15
- const result = await config.run(normalizedInput, extra);
16
- const doneLog = typeof config.doneLog === "function" ? config.doneLog(result) : config.doneLog;
17
- appendDebugLog(doneLog, {
18
- cwd: normalizedInput.cwd,
19
- section: TOOL_LOG_SECTION,
20
- });
21
- return config.buildResponse(result, normalizedInput);
22
- }
23
- catch (error) {
24
- return await handleToolError({
25
- error,
26
- cwd: normalizedInput.cwd,
27
- logLabel: config.logLabel,
28
- });
29
- }
30
- };
31
- }
@@ -1,9 +0,0 @@
1
- import { buildHelpBody } from "../config/architect-hints.js";
2
- import { buildHelpResponse } from "../responses/responses.js";
3
- export function createHelpHandler(version) {
4
- return async ({}) => {
5
- return buildHelpResponse({
6
- text: buildHelpBody(version),
7
- });
8
- };
9
- }
@@ -1,174 +0,0 @@
1
- import * as fs from "fs/promises";
2
- import * as path from "path";
3
- import { KEIYAKU_FILE, RESPONSE_HISTORY_DIR, } from "../../keiyaku.js";
4
- import { FlowError, wrapFlowError } from "../../flow-error.js";
5
- import { checkoutBranch, deleteBranch } from "../../git/branches.js";
6
- import { getDiffStats } from "../../git/diff/preview.js";
7
- import { clearKeiyakuBase } from "../../git/keiyaku-state.js";
8
- import { commitAllowEmpty, getLatestCommitHash, getUnmergedFiles, mergeSquashStaged, restoreFilesFromHead } from "../../git/staging.js";
9
- import { resetHardHead } from "../../git/stash.js";
10
- import { logInfo, logWarn } from "../../telemetry/logger.js";
11
- import { renderRoundLedgerHistory, scanRoundLedger, } from "../../protocol/ledger.js";
12
- import { assertKeiyakuProtocolFiles } from "../../protocol/file-guards.js";
13
- import { assertCleanWorkingTree } from "../round/worktree.js";
14
- import { buildClaimGatePipeline, } from "./claim-gates.js";
15
- import { assertHeadUnchanged } from "../round/head-guard.js";
16
- function buildMergeMessage(title, plea, keiyakuContent, reportContent) {
17
- return `keiyaku(${title}): done\n\nPlea: ${plea}\n\n---\n${keiyakuContent}\n---\n${reportContent}\n---\n`;
18
- }
19
- function formatCloseDiffSummary(stats, baseBranch) {
20
- return `Range ${baseBranch}...HEAD | Files ${stats.filesChanged} | +${stats.insertions} / -${stats.deletions}`;
21
- }
22
- function renderReviewForAudit(review) {
23
- return [
24
- `## Review ${review.review}`,
25
- `Result: ${review.result}`,
26
- ...(review.historyPath ? [`See: ${review.historyPath}`] : []),
27
- ...(review.findings ? ["", review.findings.trim()] : []),
28
- "",
29
- ].join("\n");
30
- }
31
- function renderVerdictForAudit(input) {
32
- const lines = [
33
- "## Verdict",
34
- `**Status**: ${input.status}`,
35
- `**Title**: ${input.title}`,
36
- `**Plea**: ${input.plea}`,
37
- ];
38
- if (input.bypassedByArchitect) {
39
- lines.push("**Gates**: bypassed by Architect");
40
- }
41
- if (input.checkFailures?.length) {
42
- lines.push("", "### Check Failures", ...input.checkFailures.map((failure) => `- ${failure}`));
43
- }
44
- return `${lines.join("\n")}\n`;
45
- }
46
- async function throwClaimGateFailure(failure, input, context, dependencies) {
47
- const { cwd, titleToken } = context;
48
- void titleToken;
49
- void dependencies;
50
- if (failure.reviewHeadBeforeWrite) {
51
- await assertHeadUnchanged(cwd, failure.reviewHeadBeforeWrite, "petition claim review");
52
- }
53
- throw new FlowError(failure.code, failure.message, {
54
- hints: failure.hints,
55
- review: failure.review,
56
- });
57
- }
58
- async function runClaimGatePipelineOrThrow(input, context, dependencies) {
59
- const { verificationCommands } = await dependencies.resolveClaimGateConfig(context.cwd);
60
- let review;
61
- let reviewHeadBeforeWrite;
62
- for (const gate of buildClaimGatePipeline()) {
63
- const result = await gate.evaluate({
64
- cwd: context.cwd,
65
- input,
66
- verificationCommands,
67
- baseBranch: dependencies.baseBranch,
68
- reviewNumber: dependencies.reviewNumber,
69
- });
70
- if (result.review) {
71
- review = result.review;
72
- reviewHeadBeforeWrite = result.reviewHeadBeforeWrite;
73
- }
74
- if (!result.pass) {
75
- await throwClaimGateFailure(result, input, context, dependencies);
76
- }
77
- }
78
- return { review, reviewHeadBeforeWrite };
79
- }
80
- export async function claimKeiyaku(input, context, dependencies) {
81
- const { cwd, baseBranch, keiyakuBranch, titleToken } = context;
82
- await assertKeiyakuProtocolFiles(cwd);
83
- const ledgerEntries = await scanRoundLedger(cwd);
84
- const ledgerView = renderRoundLedgerHistory(ledgerEntries);
85
- let attemptedBaseMerge = false;
86
- const claimTitle = input.title;
87
- const claimPlea = input.plea;
88
- const claimResult = "dangerouslyBypassGates" in input && input.dangerouslyBypassGates
89
- ? { review: undefined, reviewHeadBeforeWrite: undefined, bypassedByArchitect: true }
90
- : {
91
- ...(await runClaimGatePipelineOrThrow(input, { cwd, titleToken }, {
92
- ...dependencies,
93
- baseBranch,
94
- reviewNumber: ledgerEntries.length + 1,
95
- })),
96
- bypassedByArchitect: false,
97
- };
98
- await assertCleanWorkingTree(cwd, [RESPONSE_HISTORY_DIR]);
99
- try {
100
- logInfo(`[CLAIM] Collecting diff preview against base '${baseBranch}'`, { cwd, section: "script", progressOnly: true });
101
- logInfo("[CLAIM] Reading keiyaku protocol files", { cwd, section: "script", progressOnly: true });
102
- const keiyakuContent = await fs.readFile(path.join(cwd, KEIYAKU_FILE), "utf-8");
103
- if (claimResult.review && claimResult.reviewHeadBeforeWrite) {
104
- await assertHeadUnchanged(cwd, claimResult.reviewHeadBeforeWrite, "petition claim review");
105
- }
106
- const reportContent = [
107
- "# Keiyaku Ledger",
108
- "",
109
- ledgerView,
110
- "",
111
- claimResult.review ? renderReviewForAudit(claimResult.review) : "",
112
- renderVerdictForAudit({
113
- status: "ACCEPTED",
114
- title: claimTitle,
115
- plea: claimPlea,
116
- bypassedByArchitect: claimResult.bypassedByArchitect,
117
- }),
118
- ].filter((chunk) => chunk.trim().length > 0).join("\n");
119
- const message = buildMergeMessage(claimTitle, claimPlea, keiyakuContent, reportContent);
120
- const diffStats = await getDiffStats(cwd, baseBranch);
121
- const diff = formatCloseDiffSummary(diffStats, baseBranch);
122
- logInfo(`[CLAIM] Checking out base branch '${baseBranch}'`, { cwd, section: "script", progressOnly: true });
123
- await checkoutBranch(cwd, baseBranch);
124
- attemptedBaseMerge = true;
125
- logInfo(`[CLAIM] Merging '${keiyakuBranch}' into '${baseBranch}'`, { cwd, section: "script", progressOnly: true });
126
- await mergeSquashStaged(cwd, keiyakuBranch);
127
- logInfo("[CLAIM] Restoring protocol files from base branch before merge commit", {
128
- cwd,
129
- section: "script",
130
- progressOnly: true,
131
- });
132
- await restoreFilesFromHead(cwd, [KEIYAKU_FILE]);
133
- await commitAllowEmpty(cwd, message);
134
- const commit = await getLatestCommitHash(cwd);
135
- logInfo(`[CLAIM] Deleting merged branch '${keiyakuBranch}' and clearing metadata`, {
136
- cwd,
137
- section: "script",
138
- progressOnly: true,
139
- });
140
- await deleteBranch(cwd, keiyakuBranch, true);
141
- await clearKeiyakuBase(cwd, keiyakuBranch);
142
- const round = ledgerEntries.reduce((max, entry) => Math.max(max, entry.round), 0);
143
- return {
144
- status: "success",
145
- result: "merged",
146
- review: claimResult.review,
147
- round,
148
- currentBranch: baseBranch,
149
- baseBranch,
150
- commit,
151
- mergedInto: baseBranch,
152
- deletedBranch: keiyakuBranch,
153
- ledgerView,
154
- diff,
155
- };
156
- }
157
- catch (error) {
158
- const conflictFiles = attemptedBaseMerge ? await getUnmergedFiles(cwd) : [];
159
- if (attemptedBaseMerge) {
160
- try {
161
- await resetHardHead(cwd);
162
- await checkoutBranch(cwd, keiyakuBranch);
163
- }
164
- catch (recoveryError) {
165
- const warning = `[CLAIM] Failed to restore keiyaku branch state after merge error: ${recoveryError instanceof Error ? recoveryError.message : String(recoveryError)}`;
166
- logWarn(warning, { cwd, section: "script" });
167
- }
168
- }
169
- if (conflictFiles.length > 0) {
170
- throw new FlowError("CLOSE_MERGE_CONFLICT", `CLAIM merge conflict between ${keiyakuBranch} and ${baseBranch} (CONFLICTS: ${conflictFiles.join(", ")})`, { cause: error });
171
- }
172
- throw wrapFlowError(`execute CLAIM (merge ${keiyakuBranch} into ${baseBranch})`, error);
173
- }
174
- }
@@ -1,100 +0,0 @@
1
- import { KEIYAKU_ARCHIVE_TAG_PREFIX } from "../../keiyaku.js";
2
- import { FlowError, wrapFlowError } from "../../flow-error.js";
3
- import { restoreDraftSnapshot } from "../../protocol/draft-artifacts.js";
4
- import { checkoutBranch, deleteBranch } from "../../git/branches.js";
5
- import { clearKeiyakuBase } from "../../git/keiyaku-state.js";
6
- import { createTagAtHead } from "../../git/staging.js";
7
- import { applyStash, createSafetyStash, discardAllWorkingTreeChanges, dropStash } from "../../git/stash.js";
8
- import { getDirtyFiles, renderDirtyFileStatusLine } from "../../git/worktree.js";
9
- import { renderRoundLedgerHistory, scanRoundLedger } from "../../protocol/ledger.js";
10
- import { buildForfeitReturnBranchFailureHint, buildForfeitRollbackApplyHints, buildForfeitRollbackCheckoutHints, getForfeitRollbackRestoredHint, } from "../../config/architect-hints.js";
11
- function buildForfeitSafetyStashMessage(titleToken) {
12
- return `keiyaku(${titleToken}): forfeit safety snapshot`;
13
- }
14
- function buildArchiveTag(titleToken, now = Date.now()) {
15
- return `${KEIYAKU_ARCHIVE_TAG_PREFIX}${titleToken}-${now}`;
16
- }
17
- async function restoreForfeitSafetySnapshot(cwd, keiyakuBranch, stashRef) {
18
- const hints = [];
19
- try {
20
- await checkoutBranch(cwd, keiyakuBranch);
21
- }
22
- catch (checkoutError) {
23
- const checkoutFailure = checkoutError instanceof Error ? checkoutError.message : String(checkoutError);
24
- hints.push(...buildForfeitRollbackCheckoutHints(keiyakuBranch, checkoutFailure, stashRef));
25
- return hints;
26
- }
27
- try {
28
- await applyStash(cwd, stashRef);
29
- hints.push(getForfeitRollbackRestoredHint());
30
- }
31
- catch (applyError) {
32
- const applyFailure = applyError instanceof Error ? applyError.message : String(applyError);
33
- hints.push(...buildForfeitRollbackApplyHints(keiyakuBranch, stashRef, applyFailure));
34
- }
35
- return hints;
36
- }
37
- export async function forfeitKeiyaku(context) {
38
- const { cwd, baseBranch, keiyakuBranch, titleToken, draftSnapshot } = context;
39
- const archiveTag = buildArchiveTag(titleToken);
40
- const ledgerEntries = await scanRoundLedger(cwd);
41
- const round = ledgerEntries.reduce((max, entry) => Math.max(max, entry.round), 0);
42
- const ledgerView = renderRoundLedgerHistory(ledgerEntries);
43
- const dirtyFiles = await getDirtyFiles(cwd);
44
- const droppedChanges = dirtyFiles.map((file) => renderDirtyFileStatusLine(file));
45
- let safetyStashRef = null;
46
- try {
47
- if (dirtyFiles.length > 0) {
48
- safetyStashRef = await createSafetyStash(cwd, buildForfeitSafetyStashMessage(titleToken));
49
- await discardAllWorkingTreeChanges(cwd);
50
- }
51
- await createTagAtHead(cwd, archiveTag);
52
- await checkoutBranch(cwd, baseBranch);
53
- if (draftSnapshot) {
54
- await restoreDraftSnapshot(cwd, draftSnapshot);
55
- }
56
- await deleteBranch(cwd, keiyakuBranch, true);
57
- await clearKeiyakuBase(cwd, keiyakuBranch);
58
- if (safetyStashRef) {
59
- await dropStash(cwd, safetyStashRef);
60
- }
61
- }
62
- catch (error) {
63
- const rollbackHints = [];
64
- if (safetyStashRef) {
65
- const recoveryHints = await restoreForfeitSafetySnapshot(cwd, keiyakuBranch, safetyStashRef);
66
- rollbackHints.push(...recoveryHints);
67
- }
68
- else {
69
- try {
70
- await checkoutBranch(cwd, keiyakuBranch);
71
- }
72
- catch (checkoutError) {
73
- const checkoutFailure = checkoutError instanceof Error ? checkoutError.message : String(checkoutError);
74
- rollbackHints.push(buildForfeitReturnBranchFailureHint(keiyakuBranch, checkoutFailure));
75
- }
76
- }
77
- const wrappedError = wrapFlowError(`execute FORFEIT (${keiyakuBranch} -> ${baseBranch})`, error);
78
- if (rollbackHints.length > 0) {
79
- throw new FlowError("INTERNAL_STATE", wrappedError.message, {
80
- cause: wrappedError,
81
- hints: rollbackHints,
82
- });
83
- }
84
- throw wrappedError;
85
- }
86
- return {
87
- status: "success",
88
- result: "dropped",
89
- round,
90
- currentBranch: baseBranch,
91
- baseBranch,
92
- deletedBranch: keiyakuBranch,
93
- archiveTag,
94
- ledgerView,
95
- diff: droppedChanges.length > 0
96
- ? `Forfeited without merge. Dropped ${droppedChanges.length} local change(s).`
97
- : "Forfeited without merge.",
98
- droppedChanges,
99
- };
100
- }