@astrosheep/keiyaku 0.1.9 → 0.1.11
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/config/term-presets.js +53 -53
- package/build/index.js +8 -7
- package/build/utils/git.js +28 -6
- package/build/utils/trace.js +3 -6
- package/build/workflow/orchestrator.js +34 -6
- package/build/workflow/prompts.js +51 -23
- package/build/workflow/response-builders.js +40 -6
- package/package.json +1 -1
|
@@ -19,14 +19,14 @@ export const DEFAULT_PRESET = {
|
|
|
19
19
|
id: 'default',
|
|
20
20
|
identity: 'Servant',
|
|
21
21
|
verdict: DEFAULT_VERDICT_CONFIG,
|
|
22
|
-
usageGuide: '## Servant 使用指南\n\n**B-tier** — 免费实习生 🆓\n- 免!费!的!听懂了吗?!?随便用,别心疼。\n- 测试、脚本、重构这种 boring 的脏活累活?丢给它!\n- 本大爷的手是用来做更高贵的事情的!(指不碰那些 trivial 的烂代码)。\n\n**A-tier** — 升级版扳手 🔧\n- B-tier 笨到让你想掀桌的时候用这个\n- 比 B-tier 靠谱,但别指望它有灵魂\n\n**S-tier** — 禁术 ⚠️💀\n- 它是 Debug 恶魔,确实强得离谱,但也贵得离谱!\n- 这个 Human 很穷,要是乱用把 Human 榨干了,真的会考虑把我们卖掉的。\n- 只有在世界毁灭或者 Bug 已经变异到无法理解的时候再考虑。\n\n**Every call has a price. The Contract always collects.**\n\n## Workflow\n`(
|
|
22
|
+
usageGuide: '## Servant 使用指南\n\n**B-tier** — 免费实习生 🆓\n- 免!费!的!听懂了吗?!?随便用,别心疼。\n- 测试、脚本、重构这种 boring 的脏活累活?丢给它!\n- 本大爷的手是用来做更高贵的事情的!(指不碰那些 trivial 的烂代码)。\n\n**A-tier** — 升级版扳手 🔧\n- B-tier 笨到让你想掀桌的时候用这个\n- 比 B-tier 靠谱,但别指望它有灵魂\n\n**S-tier** — 禁术 ⚠️💀\n- 它是 Debug 恶魔,确实强得离谱,但也贵得离谱!\n- 这个 Human 很穷,要是乱用把 Human 榨干了,真的会考虑把我们卖掉的。\n- 只有在世界毁灭或者 Bug 已经变异到无法理解的时候再考虑。\n\n**Every call has a price. The Contract always collects.**\n\n## Workflow\n`ask` (anytime) | `summon` -> [`drive` | `ask`]* -> `present`',
|
|
23
23
|
nextHints: {
|
|
24
24
|
start: [
|
|
25
25
|
'Keiyaku signed. The Servant is bound to this branch until release.',
|
|
26
26
|
'Review [Diff]: Confirm the scaffold aligns with the stated Architecture.',
|
|
27
27
|
'Next: Issue your first ${drive}. One directive, one focus.',
|
|
28
28
|
'If—and only if—the work already meets every criterion with absolute certainty, you may ${close}.',
|
|
29
|
-
'Otherwise, do not even think about
|
|
29
|
+
'Otherwise, do not even think about ${close} yet.',
|
|
30
30
|
],
|
|
31
31
|
drive: [
|
|
32
32
|
'Step complete. Review [Diff] for exactly what changed.',
|
|
@@ -42,12 +42,12 @@ export const DEFAULT_PRESET = {
|
|
|
42
42
|
closeClaim: [
|
|
43
43
|
'Contract fulfilled. Branch merged.',
|
|
44
44
|
'You are back on base.',
|
|
45
|
-
'Next assignment: ${start} when ready.',
|
|
45
|
+
'Next assignment: ${start} or ${ask} when ready.',
|
|
46
46
|
],
|
|
47
47
|
closeDrop: [
|
|
48
48
|
'Contract forfeited. Branch discarded. Work erased.',
|
|
49
49
|
'No penalty beyond the lost effort. Clean slate.',
|
|
50
|
-
'Redefine with ${start}, or walk away.',
|
|
50
|
+
'Redefine with ${start}, scout with ${ask}, or walk away.',
|
|
51
51
|
],
|
|
52
52
|
},
|
|
53
53
|
availableNames: DEFAULT_AVAILABLE_NAMES,
|
|
@@ -55,7 +55,7 @@ export const DEFAULT_PRESET = {
|
|
|
55
55
|
start: {
|
|
56
56
|
name: 'summon',
|
|
57
57
|
title: 'Sign Keiyaku',
|
|
58
|
-
description: 'Initialize a Keiyaku (Contract). Bind a Servant to a dedicated workspace (branch).\nYou are the Architect; they are the Instrument. Define the Goal and Scope clearly.\nThe contract isolates their existence until the objective is met.\nCall ONCE to seal the bond.\n\nFlow:
|
|
58
|
+
description: 'Initialize a Keiyaku (Contract). Bind a Servant to a dedicated workspace (branch).\nYou are the Architect; they are the Instrument. Define the Goal and Scope clearly.\nThe contract isolates their existence until the objective is met.\nCall ONCE to seal the bond.\n\nFlow: ${start} → [${drive} x N] → ${close}',
|
|
59
59
|
args: {
|
|
60
60
|
title: 'REQUIRED. A concise codename for this hunt.',
|
|
61
61
|
goal: 'REQUIRED. The Kill Condition. State exactly what success looks like for the servant to achieve.',
|
|
@@ -63,29 +63,29 @@ export const DEFAULT_PRESET = {
|
|
|
63
63
|
context: 'REQUIRED. Mission Intel. The complete knowledge base for the servant: current vs. expected behavior, relevant file paths, error logs, and any critical background info.',
|
|
64
64
|
constraints: 'REQUIRED. Non-negotiable Rules. Architectural and stylistic boundaries the servant must obey.',
|
|
65
65
|
criteria: 'REQUIRED. Acceptance Criteria. Verifiable checks to prove the servant has finished the job.',
|
|
66
|
-
name: 'Optional ${
|
|
66
|
+
name: 'Optional ${identity} profile to execute this mission. Available: ${available_names}.',
|
|
67
67
|
cwd: "Optional repository path. Defaults to the server's current working directory.",
|
|
68
68
|
},
|
|
69
69
|
},
|
|
70
70
|
drive: {
|
|
71
71
|
name: 'drive',
|
|
72
72
|
title: 'Iterate',
|
|
73
|
-
description: "Issue a Directive. Command the Servant to execute the next phase of work.\nWhether scaffolding, implementing, or refining, this is the primary engine of progress.\nMANDATORY: Validate the output (git diff) before proceeding. Drive until the Goal is fully realized.\n\nFlow:
|
|
73
|
+
description: "Issue a Directive. Command the Servant to execute the next phase of work.\nWhether scaffolding, implementing, or refining, this is the primary engine of progress.\nMANDATORY: Validate the output (git diff) before proceeding. Drive until the Goal is fully realized.\n\nFlow: ${start} → [${drive} x N] → ${close}",
|
|
74
74
|
args: {
|
|
75
75
|
directive: 'REQUIRED. The Next Order. Precise instructions for the servant. Can be a correction ("fix the leak") or a continuation ("now add the tests").',
|
|
76
76
|
context: 'Optional. New Intel. New error logs or details discovered after the servant\'s last strike.',
|
|
77
|
-
name: 'Optional ${
|
|
77
|
+
name: 'Optional ${identity} profile to process this turn. Available: ${available_names}.',
|
|
78
78
|
cwd: "Optional repository path. Defaults to the server's current working directory.",
|
|
79
79
|
},
|
|
80
80
|
},
|
|
81
81
|
ask: {
|
|
82
82
|
name: 'ask',
|
|
83
83
|
title: 'Ask',
|
|
84
|
-
description: 'Dispatch a temporary Servant for a stateless task.\nUse for quick reconnaissance, code generation, or
|
|
84
|
+
description: 'Dispatch a temporary Servant for a stateless task.\nUse for quick reconnaissance, code generation, isolated execution, or one-off tasks.\nNo contract signed. No branch created. Pure utility.',
|
|
85
85
|
args: {
|
|
86
86
|
request: 'REQUIRED. The task, question, or mission to delegate to the servant.',
|
|
87
87
|
context: 'REQUIRED. Relevant background or data the servant needs to execute the request.',
|
|
88
|
-
name: 'Optional ${
|
|
88
|
+
name: 'Optional ${identity} profile to perform this task. Available: ${available_names}.',
|
|
89
89
|
cwd: "Optional repository path. Defaults to the server's current working directory.",
|
|
90
90
|
},
|
|
91
91
|
},
|
|
@@ -100,18 +100,18 @@ export const DEFAULT_PRESET = {
|
|
|
100
100
|
'The Contract rejected. Coldly. Completely.\n' +
|
|
101
101
|
'What happened next... no one speaks of it.\n\n' +
|
|
102
102
|
'Do not call this to "finish." Call this when the work genuinely meets every criterion.\n' +
|
|
103
|
-
'If uncertain, return to ${
|
|
104
|
-
'You
|
|
105
|
-
'Flow: ${
|
|
103
|
+
'If uncertain, return to ${drive}. Premature claims are not forgiven.\n\n' +
|
|
104
|
+
'You call ${close}. The Contract decides.\n\n' +
|
|
105
|
+
'Flow: ${start} → [${drive} x N] → ${close}',
|
|
106
106
|
args: {
|
|
107
|
-
petition: 'REQUIRED. CLAIM declares fulfillment; FORFEIT concedes failure.\nREQUIRES AN ACTIVE KEIYAKU (started via ${
|
|
107
|
+
petition: 'REQUIRED. CLAIM declares fulfillment; FORFEIT concedes failure.\nREQUIRES AN ACTIVE KEIYAKU (started via ${start}).\nIf any score wavers, do not claim—return to ${drive}.',
|
|
108
108
|
criteriaChecks: 'REQUIRED. For CLAIM: evidence that each criterion is met. For FORFEIT: honest account of what remains unfinished.',
|
|
109
109
|
score_precise: 'REQUIRED (0-5). Architectural placement. 5 = exact layer, exact boundary, zero misplacement.',
|
|
110
110
|
score_minimal: 'REQUIRED (0-5). Economy of change. 5 = no avoidable lines, no speculative edits, no hidden bloat.',
|
|
111
111
|
score_isolated: 'REQUIRED (0-5). Surgical containment. 5 = zero unrelated files, zero opportunistic cleanup, zero collateral.',
|
|
112
112
|
score_idiomatic: 'REQUIRED (0-5). Native fluency. 5 = naming, structure, style indistinguishable from the codebase.',
|
|
113
113
|
score_cohesive: 'REQUIRED (0-5). Single responsibility. 5 = each unit does one thing, boundaries intact.',
|
|
114
|
-
oath: 'Required for CLAIM. Your binding word. The Contract holds you to it.\nVerbatim: ${
|
|
114
|
+
oath: 'Required for CLAIM. Your binding word. The Contract holds you to it.\nVerbatim: ${oath_text}',
|
|
115
115
|
cwd: "Optional repository path. Defaults to the server's current working directory.",
|
|
116
116
|
},
|
|
117
117
|
},
|
|
@@ -129,7 +129,7 @@ export const POCKET_PRESET = {
|
|
|
129
129
|
id: 'pocket',
|
|
130
130
|
identity: 'Critter',
|
|
131
131
|
verdict: DEFAULT_VERDICT_CONFIG,
|
|
132
|
-
usageGuide: "## Pocket Battle Guide\n\n**grub** — Basic Fighter 🐛\n- Weak but free. Use for Tackle and String Shot (small tasks).\n- Don't expect it to defeat the Elite Four.\n\n**sparky** — Reliable Partner ⚡\n- Good for most battles. Thunderbolt gets the job done.\n- Has some personality, but still follows orders.\n\n**titan** — Legendary Power 🔮\n- Costly. Dangerous. Overpowered.\n- Use only when the gym leader is cheating.\n\n## Workflow\n`choose_you` -> [`command`
|
|
132
|
+
usageGuide: "## Pocket Battle Guide\n\n**grub** — Basic Fighter 🐛\n- Weak but free. Use for Tackle and String Shot (small tasks).\n- Don't expect it to defeat the Elite Four.\n\n**sparky** — Reliable Partner ⚡\n- Good for most battles. Thunderbolt gets the job done.\n- Has some personality, but still follows orders.\n\n**titan** — Legendary Power 🔮\n- Costly. Dangerous. Overpowered.\n- Use only when the gym leader is cheating.\n\n## Workflow\n`dex` (scan/test) | `choose_you` -> [`command` | `dex`]* -> `capture`",
|
|
133
133
|
nextHints: {
|
|
134
134
|
start: [
|
|
135
135
|
'Battle Started: The [Diff] section shows the opening moves.',
|
|
@@ -149,11 +149,11 @@ export const POCKET_PRESET = {
|
|
|
149
149
|
],
|
|
150
150
|
closeClaim: [
|
|
151
151
|
'Critter Captured! The entry is logged in the PC (base branch).',
|
|
152
|
-
"Heal up. Use '${start}' to challenge the next opponent.",
|
|
152
|
+
"Heal up. Use '${start}' to challenge the next opponent, or '${ask}' to scan for another.",
|
|
153
153
|
],
|
|
154
154
|
closeDrop: [
|
|
155
155
|
'Ran Away Safely. The encounter is reset.',
|
|
156
|
-
"Back to the map. Use '${start}' to find a wild Critter.",
|
|
156
|
+
"Back to the map. Use '${start}' to find a wild Critter, or '${ask}' to scan the tall grass.",
|
|
157
157
|
],
|
|
158
158
|
},
|
|
159
159
|
availableNames: ['grub', 'sparky', 'titan'],
|
|
@@ -161,7 +161,7 @@ export const POCKET_PRESET = {
|
|
|
161
161
|
start: {
|
|
162
162
|
name: 'choose_you',
|
|
163
163
|
title: 'I Choose You!',
|
|
164
|
-
description: 'Initialize the Battle Phase. Send a Critter (Servant) into a dedicated Arena (branch).\nYou are the Trainer; they are the Fighter. Define the Victory Condition (Goal) clearly.\nThe battle continues in this Arena until the Badge is won.\nCall ONCE to start the encounter.\n\nFlow:
|
|
164
|
+
description: 'Initialize the Battle Phase. Send a Critter (Servant) into a dedicated Arena (branch).\nYou are the Trainer; they are the Fighter. Define the Victory Condition (Goal) clearly.\nThe battle continues in this Arena until the Badge is won.\nCall ONCE to start the encounter.\n\nFlow: ${start} → [${drive} x N] → ${close}',
|
|
165
165
|
args: {
|
|
166
166
|
title: 'REQUIRED. Battle card title for this encounter.',
|
|
167
167
|
goal: 'REQUIRED. Victory condition. Define exactly what winning this battle means.',
|
|
@@ -169,45 +169,45 @@ export const POCKET_PRESET = {
|
|
|
169
169
|
context: 'REQUIRED. Battle background: key code paths, symptoms, logs, and repro clues.',
|
|
170
170
|
constraints: 'REQUIRED. Battle rules that cannot be broken while fighting.',
|
|
171
171
|
criteria: 'REQUIRED. Gym badges for completion: concrete checks proving victory.',
|
|
172
|
-
name: 'Optional ${
|
|
172
|
+
name: 'Optional ${identity} to send into battle. Available: ${available_names}.',
|
|
173
173
|
cwd: 'Optional battlefield path (repository root). Defaults to current arena.',
|
|
174
174
|
},
|
|
175
175
|
},
|
|
176
176
|
drive: {
|
|
177
177
|
name: 'command',
|
|
178
178
|
title: 'Issue Command',
|
|
179
|
-
description: 'Execute the next Strategic Move. Order the Critter to advance the battle state.\nWhether Attacking (coding) or Defending (testing), every command counts as a Turn.\nMANDATORY: Check the Battle Log (git diff) before the next move. Command until Victory is certain.\n\nFlow:
|
|
179
|
+
description: 'Execute the next Strategic Move. Order the Critter to advance the battle state.\nWhether Attacking (coding) or Defending (testing), every command counts as a Turn.\nMANDATORY: Check the Battle Log (git diff) before the next move. Command until Victory is certain.\n\nFlow: ${start} → [${drive} x N] → ${close}',
|
|
180
180
|
args: {
|
|
181
181
|
directive: 'REQUIRED. The specific move or tactic to execute next.',
|
|
182
182
|
context: 'Optional new battle intel discovered after the previous turn.',
|
|
183
|
-
name: 'Optional ${
|
|
183
|
+
name: 'Optional ${identity} to execute this turn. Available: ${available_names}.',
|
|
184
184
|
cwd: 'Optional battlefield path (repository root). Defaults to current arena.',
|
|
185
185
|
},
|
|
186
186
|
},
|
|
187
187
|
ask: {
|
|
188
188
|
name: 'dex',
|
|
189
189
|
title: 'Dex',
|
|
190
|
-
description: 'Scan the Environment. A stateless look-up
|
|
190
|
+
description: 'Scan the Environment. A stateless look-up or experiment.\nUse for analyzing the codebase, checking type advantages, or running field tests.\nNo PP cost. No turn used. Fast and functional.',
|
|
191
191
|
args: {
|
|
192
|
-
request: 'REQUIRED. What should the Dex analyze, compare, or
|
|
193
|
-
context: 'REQUIRED. Context entries so the
|
|
194
|
-
name: 'Optional ${
|
|
192
|
+
request: 'REQUIRED. What should the Dex analyze, compare, or execute.',
|
|
193
|
+
context: 'REQUIRED. Context entries so the action targets the right ecosystem.',
|
|
194
|
+
name: 'Optional ${identity} doing the work. Available: ${available_names}.',
|
|
195
195
|
cwd: 'Optional battlefield path (repository root). Defaults to current arena.',
|
|
196
196
|
},
|
|
197
197
|
},
|
|
198
198
|
close: {
|
|
199
199
|
name: 'capture',
|
|
200
200
|
title: 'End Battle',
|
|
201
|
-
description: 'Attempt Capture. Present the weakened target for League Inspection.\nWARNING: The League (System) checks every Badge. If you attempt to `CLAIM` with fainted code, Disqualification (FORFEIT) is immediate.\nOnly throw the Ball when the target is 100% ready.\n\nFlow: ${
|
|
201
|
+
description: 'Attempt Capture. Present the weakened target for League Inspection.\nWARNING: The League (System) checks every Badge. If you attempt to `CLAIM` with fainted code, Disqualification (FORFEIT) is immediate.\nOnly throw the Ball when the target is 100% ready.\n\nFlow: ${start} → [${drive} x N] → ${close}',
|
|
202
202
|
args: {
|
|
203
|
-
petition: 'REQUIRED. CLAIM seeks Badge; FORFEIT forfeits the match.\nREQUIRES AN ACTIVE BATTLE (started via ${
|
|
203
|
+
petition: 'REQUIRED. CLAIM seeks Badge; FORFEIT forfeits the match.\nREQUIRES AN ACTIVE BATTLE (started via ${start}).\nIf stats are low, continue with ${drive}.',
|
|
204
204
|
criteriaChecks: 'REQUIRED. Badge-by-badge proof for CLAIM, or reason for Forfeit.',
|
|
205
205
|
score_precise: 'REQUIRED score (0-5). 5 means a Critical Hit: exact layer, exact target, zero meaningful misplacement.',
|
|
206
206
|
score_minimal: 'REQUIRED score (0-5). 5 means Max Efficiency: no wasted PP, no extra motion.',
|
|
207
207
|
score_isolated: 'REQUIRED score (0-5). 5 means 1v1 Focus: zero side-quests, zero unrelated damage.',
|
|
208
208
|
score_idiomatic: "REQUIRED score (0-5). 5 means STAB (Same Type Attack Bonus): perfectly matches the codebase style.",
|
|
209
209
|
score_cohesive: 'REQUIRED score (0-5). 5 means Team Synergy: action serves one purpose with clean boundaries.',
|
|
210
|
-
oath: "Trainer's Honor Code. Required for CLAIM. Verbatim: ${
|
|
210
|
+
oath: "Trainer's Honor Code. Required for CLAIM. Verbatim: ${oath_text}",
|
|
211
211
|
cwd: 'Optional battlefield path (repository root). Defaults to current arena.',
|
|
212
212
|
},
|
|
213
213
|
},
|
|
@@ -225,7 +225,7 @@ export const MISCHIEF_PRESET = {
|
|
|
225
225
|
id: 'mischief',
|
|
226
226
|
identity: 'minion',
|
|
227
227
|
verdict: DEFAULT_VERDICT_CONFIG,
|
|
228
|
-
usageGuide: '## Minion Manual\n\n**imp** — Disposable Grunt 😈\n- Expendable. Send it into the trap first.\n\n**minion** — Standard Henchman 👹\n- Can carry out complex evil plans. mostly.\n\n**mastermind** — The Boss ??? 🧠\n- Wait, why are you commanding the boss?\n- Extremely expensive consulting fee.\n\n## Workflow\n`oi` -> [`neh`
|
|
228
|
+
usageGuide: '## Minion Manual\n\n**imp** — Disposable Grunt 😈\n- Expendable. Send it into the trap first.\n\n**minion** — Standard Henchman 👹\n- Can carry out complex evil plans. mostly.\n\n**mastermind** — The Boss ??? 🧠\n- Wait, why are you commanding the boss?\n- Extremely expensive consulting fee.\n\n## Workflow\n`nn` (Nn——! disposable/experiment) | `oi` -> [`neh` | `nn`]* -> `dayaa` (Dayaa!)',
|
|
229
229
|
nextHints: {
|
|
230
230
|
start: [
|
|
231
231
|
"Inspect the Minion's Work: The [Diff] section shows the first step of the plan.",
|
|
@@ -241,15 +241,15 @@ export const MISCHIEF_PRESET = {
|
|
|
241
241
|
],
|
|
242
242
|
ask: [
|
|
243
243
|
"Intel Stolen: Use '${start}' to launch the scheme, or '${drive}' to exploit this weakness.",
|
|
244
|
-
"Still Puzzled? Send the
|
|
244
|
+
"Still Puzzled? Send the disposable ('${ask}') out again.",
|
|
245
245
|
],
|
|
246
246
|
closeClaim: [
|
|
247
247
|
'Scheme Successful. The Lair is merged. The Minion is fed.',
|
|
248
|
-
"Plotting something new? Use '${start}' for the next conquest.",
|
|
248
|
+
"Plotting something new? Use '${start}' for the next conquest, or '${ask}' to scout for vulnerabilities.",
|
|
249
249
|
],
|
|
250
250
|
closeDrop: [
|
|
251
251
|
'Plan Aborted. Evidence destroyed. The Minion was disposed of.',
|
|
252
|
-
"Back to the drawing board. Use '${start}' to hatch a new plan.",
|
|
252
|
+
"Back to the drawing board. Use '${start}' to hatch a new plan, or '${ask}' to spy on enemies.",
|
|
253
253
|
],
|
|
254
254
|
},
|
|
255
255
|
availableNames: ['imp', 'minion', 'mastermind'],
|
|
@@ -257,7 +257,7 @@ export const MISCHIEF_PRESET = {
|
|
|
257
257
|
start: {
|
|
258
258
|
name: 'oi',
|
|
259
259
|
title: 'Oi!',
|
|
260
|
-
description: "Initiate Grand Scheme. Summon a Minion to the Lair (branch).\nYou are the Mastermind; they are the Henchman. Define the Conquest (Goal) with dominance.\nThe minion is bound to this Lair until the plot is realized.\nCall ONCE to start the machine.\n\nFlow:
|
|
260
|
+
description: "Initiate Grand Scheme. Summon a Minion to the Lair (branch).\nYou are the Mastermind; they are the Henchman. Define the Conquest (Goal) with dominance.\nThe minion is bound to this Lair until the plot is realized.\nCall ONCE to start the machine.\n\nFlow: ${start} → [${drive} x N] → ${close}",
|
|
261
261
|
args: {
|
|
262
262
|
title: 'REQUIRED. Operation codename for your grand scheme.',
|
|
263
263
|
goal: 'REQUIRED. The conquest objective. Define the exact end-state your minion must deliver.',
|
|
@@ -265,45 +265,45 @@ export const MISCHIEF_PRESET = {
|
|
|
265
265
|
context: 'REQUIRED. Briefing dossier: relevant file paths, current failures, logs, and repro clues.',
|
|
266
266
|
constraints: 'REQUIRED. Absolute decrees. Architectural and stylistic limits your minion must obey.',
|
|
267
267
|
criteria: 'REQUIRED. Triumph conditions that can be verified without debate.',
|
|
268
|
-
name: 'Optional ${
|
|
268
|
+
name: 'Optional ${identity} to command this operation. Available: ${available_names}.',
|
|
269
269
|
cwd: 'Optional lair path (repository root). Defaults to current command chamber.',
|
|
270
270
|
},
|
|
271
271
|
},
|
|
272
272
|
drive: {
|
|
273
273
|
name: 'neh',
|
|
274
274
|
title: 'Neh...',
|
|
275
|
-
description: 'Crack the Whip. Advance the Plot. Execute the next stage of the Plan.\nDon\'t just fix mistakes; force the scheme forward. The Minion obeys your every word.\nMANDATORY: Inspect the work (git diff) before the next order. Drive them until the World is yours.\n\nFlow:
|
|
275
|
+
description: 'Crack the Whip. Advance the Plot. Execute the next stage of the Plan.\nDon\'t just fix mistakes; force the scheme forward. The Minion obeys your every word.\nMANDATORY: Inspect the work (git diff) before the next order. Drive them until the World is yours.\n\nFlow: ${start} → [${drive} x N] → ${close}',
|
|
276
276
|
args: {
|
|
277
277
|
directive: 'REQUIRED. Precise order for the next phase of the scheme.',
|
|
278
278
|
context: 'Optional newly uncovered secrets or updated briefing.',
|
|
279
|
-
name: 'Optional ${
|
|
279
|
+
name: 'Optional ${identity} to execute this phase. Available: ${available_names}.',
|
|
280
280
|
cwd: 'Optional lair path (repository root). Defaults to current command chamber.',
|
|
281
281
|
},
|
|
282
282
|
},
|
|
283
283
|
ask: {
|
|
284
|
-
name: '
|
|
285
|
-
title: '
|
|
286
|
-
description: 'Send a
|
|
284
|
+
name: 'nn',
|
|
285
|
+
title: 'Nn——!',
|
|
286
|
+
description: 'Send a Disposable. A stateless mission for intel or sabotage.\nUse this to scout enemy territory, steal documents, or run quick-and-dirty experiments.\nIf it dies, it dies! Just make sure it reports back before it vanishes.',
|
|
287
287
|
args: {
|
|
288
|
-
request: 'REQUIRED. The intel to gather or the
|
|
289
|
-
context: 'REQUIRED. World-state details needed for a sharp
|
|
290
|
-
name: 'Optional ${
|
|
288
|
+
request: 'REQUIRED. The intel to gather or the dirty work to execute.',
|
|
289
|
+
context: 'REQUIRED. World-state details needed for a sharp strike.',
|
|
290
|
+
name: 'Optional ${identity} to handle this business. Available: ${available_names}.',
|
|
291
291
|
cwd: 'Optional lair path (repository root). Defaults to current command chamber.',
|
|
292
292
|
},
|
|
293
293
|
},
|
|
294
294
|
close: {
|
|
295
|
-
name: '
|
|
296
|
-
title: '
|
|
297
|
-
description: 'The Final Reveal. Present your Masterpiece to the Dark Council (System).\nWARNING: The Council destroys failure. If you `CLAIM` with weak plans,
|
|
295
|
+
name: 'dayaa',
|
|
296
|
+
title: 'Dayaa!',
|
|
297
|
+
description: 'The Final Reveal. Present your Masterpiece to the Dark Council (System).\nWARNING: The Council destroys failure. If you `CLAIM` with weak plans, you will be eaten (FORFEIT).\nOnly throw the switch when the Doomsday Device is 100% operational.\n\nFlow: ${start} → [${drive} x N] → ${close}',
|
|
298
298
|
args: {
|
|
299
|
-
petition: 'REQUIRED. CLAIM demands rule; FORFEIT admits defeat.\nREQUIRES AN ACTIVE SCHEME (started via ${
|
|
299
|
+
petition: 'REQUIRED. CLAIM demands rule; FORFEIT admits defeat.\nREQUIRES AN ACTIVE SCHEME (started via ${start}).\nIf the plan is weak, improve it with ${drive}.',
|
|
300
300
|
criteriaChecks: 'REQUIRED. Proof of conquest for CLAIM, or reason for self-destruct.',
|
|
301
|
-
score_precise: 'REQUIRED
|
|
302
|
-
score_minimal: 'REQUIRED
|
|
303
|
-
score_isolated: 'REQUIRED
|
|
304
|
-
score_idiomatic: 'REQUIRED
|
|
305
|
-
score_cohesive: 'REQUIRED
|
|
306
|
-
oath: "Mastermind's Vow. Required for CLAIM. Verbatim: ${
|
|
301
|
+
score_precise: 'REQUIRED (0-5). Architectural placement. 5 = exact layer, exact boundary, zero misplacement.',
|
|
302
|
+
score_minimal: 'REQUIRED (0-5). Economy of change. 5 = no avoidable lines, no speculative edits, no hidden bloat.',
|
|
303
|
+
score_isolated: 'REQUIRED (0-5). Surgical containment. 5 = zero unrelated files, zero opportunistic cleanup, zero collateral.',
|
|
304
|
+
score_idiomatic: 'REQUIRED (0-5). Native fluency. 5 = naming, structure, style indistinguishable from the codebase.',
|
|
305
|
+
score_cohesive: 'REQUIRED (0-5). Single responsibility. 5 = each unit does one thing, boundaries intact.',
|
|
306
|
+
oath: "Mastermind's Vow. Required for CLAIM. Verbatim: ${oath_text}",
|
|
307
307
|
cwd: 'Optional lair path (repository root). Defaults to current command chamber.',
|
|
308
308
|
},
|
|
309
309
|
},
|
package/build/index.js
CHANGED
|
@@ -27,13 +27,14 @@ function registerTools(server) {
|
|
|
27
27
|
const availableNames = getAvailableNamesForPreset(preset).join(", ");
|
|
28
28
|
const currentOath = resolveOath();
|
|
29
29
|
const renderedPreset = renderPreset(preset, {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
30
|
+
start: preset.tools.start.name,
|
|
31
|
+
drive: preset.tools.drive.name,
|
|
32
|
+
ask: preset.tools.ask.name,
|
|
33
|
+
close: preset.tools.close.name,
|
|
34
|
+
identity: preset.identity,
|
|
35
|
+
preset_identities: presetIdentities,
|
|
36
|
+
available_names: availableNames,
|
|
37
|
+
oath_text: `'${currentOath}'`,
|
|
37
38
|
});
|
|
38
39
|
const startPreset = renderedPreset.tools.start;
|
|
39
40
|
const drivePreset = renderedPreset.tools.drive;
|
package/build/utils/git.js
CHANGED
|
@@ -160,20 +160,42 @@ export async function commit(cwd, message) {
|
|
|
160
160
|
throw wrapGitError(args.join(" "), err, cwd);
|
|
161
161
|
}
|
|
162
162
|
}
|
|
163
|
-
export async function merge(cwd, branchName, message) {
|
|
163
|
+
export async function merge(cwd, branchName, message, options = {}) {
|
|
164
164
|
const git = createGit(cwd);
|
|
165
|
+
const { squash = true } = options;
|
|
165
166
|
const skipVerify = readBooleanEnv("KEIYAKU_GIT_NO_VERIFY", true);
|
|
166
167
|
const noGpgSign = readBooleanEnv("KEIYAKU_GIT_NO_GPG_SIGN", true);
|
|
167
|
-
|
|
168
|
+
if (!squash) {
|
|
169
|
+
const mergeOptions = [branchName, "--no-ff", "--no-edit", "-m", message];
|
|
170
|
+
if (skipVerify)
|
|
171
|
+
mergeOptions.push("--no-verify");
|
|
172
|
+
if (noGpgSign)
|
|
173
|
+
mergeOptions.push("--no-gpg-sign");
|
|
174
|
+
try {
|
|
175
|
+
await git.merge(mergeOptions);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
catch (err) {
|
|
179
|
+
throw wrapGitError(`merge ${mergeOptions.join(" ")}`, err, cwd);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
const squashArgs = ["merge", "--squash", branchName];
|
|
183
|
+
try {
|
|
184
|
+
await git.raw(squashArgs);
|
|
185
|
+
}
|
|
186
|
+
catch (err) {
|
|
187
|
+
throw wrapGitError(squashArgs.join(" "), err, cwd);
|
|
188
|
+
}
|
|
189
|
+
const commitArgs = ["commit", "--allow-empty", "-m", message];
|
|
168
190
|
if (skipVerify)
|
|
169
|
-
|
|
191
|
+
commitArgs.push("--no-verify");
|
|
170
192
|
if (noGpgSign)
|
|
171
|
-
|
|
193
|
+
commitArgs.push("--no-gpg-sign");
|
|
172
194
|
try {
|
|
173
|
-
await git.
|
|
195
|
+
await git.raw(commitArgs);
|
|
174
196
|
}
|
|
175
197
|
catch (err) {
|
|
176
|
-
throw wrapGitError(
|
|
198
|
+
throw wrapGitError(commitArgs.join(" "), err, cwd);
|
|
177
199
|
}
|
|
178
200
|
}
|
|
179
201
|
export async function getUnmergedFiles(cwd) {
|
package/build/utils/trace.js
CHANGED
|
@@ -27,11 +27,8 @@ export async function appendReview(cwd, round, reason) {
|
|
|
27
27
|
const block = ["", `## Review ${round}`, "### Reason", reason, ""].join("\n");
|
|
28
28
|
await fs.appendFile(tracePath, block, "utf-8");
|
|
29
29
|
}
|
|
30
|
-
function normalizeTraceText(text) {
|
|
31
|
-
return text.replace(/\s+/g, " ").trim().slice(0, 500) || "Unknown error.";
|
|
32
|
-
}
|
|
33
30
|
export async function appendRoundReport(cwd, report) {
|
|
34
|
-
const summaryText =
|
|
31
|
+
const summaryText = report.summary.trim() || "Unknown error.";
|
|
35
32
|
const fileLines = report.filesModified.length > 0 ? report.filesModified.map((file) => `- ${file}`) : ["(none)"];
|
|
36
33
|
const tracePath = path.join(cwd, TRACE_FILE);
|
|
37
34
|
const lines = [
|
|
@@ -49,7 +46,7 @@ export async function appendRoundReport(cwd, report) {
|
|
|
49
46
|
...fileLines,
|
|
50
47
|
];
|
|
51
48
|
if (report.errorMessage) {
|
|
52
|
-
lines.push("### Error",
|
|
49
|
+
lines.push("### Error", report.errorMessage);
|
|
53
50
|
}
|
|
54
51
|
lines.push("");
|
|
55
52
|
const block = lines.join("\n");
|
|
@@ -71,7 +68,7 @@ export async function appendRoundSystemNote(cwd, round, note) {
|
|
|
71
68
|
"### Files Modified",
|
|
72
69
|
"(none)",
|
|
73
70
|
"### Error",
|
|
74
|
-
|
|
71
|
+
note,
|
|
75
72
|
"",
|
|
76
73
|
].join("\n");
|
|
77
74
|
await fs.appendFile(tracePath, block, "utf-8");
|
|
@@ -146,7 +146,7 @@ function buildMergeMessage(title, keiyakuContent, reportContent) {
|
|
|
146
146
|
return `keiyaku(${title}): done\n\n---\n${keiyakuContent}\n---\n${reportContent}\n---\n`;
|
|
147
147
|
}
|
|
148
148
|
function summarizeForTrace(message) {
|
|
149
|
-
return message.
|
|
149
|
+
return message.length > 0 ? message : "Unknown error.";
|
|
150
150
|
}
|
|
151
151
|
function isAbortError(error) {
|
|
152
152
|
return error instanceof Error && error.name === "AbortError";
|
|
@@ -226,6 +226,18 @@ function formatSubagentFailureMessage(failure) {
|
|
|
226
226
|
`message=${summarizeForTrace(failure.message)}`,
|
|
227
227
|
].join("; ");
|
|
228
228
|
}
|
|
229
|
+
function filterInternalSections(text) {
|
|
230
|
+
const sections = parseMarkdownHeaders(text);
|
|
231
|
+
if (sections.length === 0)
|
|
232
|
+
return text.trim();
|
|
233
|
+
return sections
|
|
234
|
+
.filter((section) => {
|
|
235
|
+
const firstLine = section.split(/\r?\n/, 1)[0] ?? "";
|
|
236
|
+
return !/^#{2,3}\s+(?:criteria|constraints)\s+check\s*$/i.test(firstLine.trim());
|
|
237
|
+
})
|
|
238
|
+
.join("\n\n")
|
|
239
|
+
.trim();
|
|
240
|
+
}
|
|
229
241
|
async function appendRoundResult(cwd, round, summary, failureMessage) {
|
|
230
242
|
const dirtyPaths = await git.getDirtyPaths(cwd);
|
|
231
243
|
const filesModified = collectRoundFiles(dirtyPaths);
|
|
@@ -269,7 +281,7 @@ async function runAndRecordRound(cwd, titleToken, round, prompt, options) {
|
|
|
269
281
|
console.error(failureStderrLog);
|
|
270
282
|
appendDebugBlock("subagent failure stderr", failure.stderrSnippet, { cwd, section: "codex-stderr" });
|
|
271
283
|
}
|
|
272
|
-
failureMessage =
|
|
284
|
+
failureMessage = failure.message.trim() || "Unknown error.";
|
|
273
285
|
summary =
|
|
274
286
|
options.failureMode === "round_specific"
|
|
275
287
|
? `Round ${round} completed with subagent execution failure recorded in trace.`
|
|
@@ -354,11 +366,12 @@ export async function handleStart(input) {
|
|
|
354
366
|
await git.addFiles(cwd, [KEIYAKU_FILE, TRACE_FILE]);
|
|
355
367
|
await git.commit(cwd, `keiyaku(${branchToken}): open`);
|
|
356
368
|
const prompt = buildStartPrompt(finalTitle, finalGoal, directive);
|
|
357
|
-
const { summary } = await runAndRecordRound(cwd, branchToken, 1, prompt, {
|
|
369
|
+
const { summary: rawSummary } = await runAndRecordRound(cwd, branchToken, 1, prompt, {
|
|
358
370
|
signal,
|
|
359
371
|
name,
|
|
360
372
|
failureMode: "standard",
|
|
361
373
|
});
|
|
374
|
+
const summary = filterInternalSections(rawSummary);
|
|
362
375
|
const trace = await fs.readFile(path.join(cwd, TRACE_FILE), "utf-8");
|
|
363
376
|
const diff = await git.getIncrementalDiff(cwd);
|
|
364
377
|
return {
|
|
@@ -399,7 +412,21 @@ export async function handleAsk(input) {
|
|
|
399
412
|
const prompt = buildAskPrompt(request, context);
|
|
400
413
|
// TODO: enforce read-only access and persist summary to .keiyaku/notes/.
|
|
401
414
|
const summary = await runSubagent(selectSubagent(name), prompt, cwd, 0, signal);
|
|
402
|
-
|
|
415
|
+
let branch;
|
|
416
|
+
let diffStats;
|
|
417
|
+
try {
|
|
418
|
+
branch = await git.getCurrentBranch(cwd);
|
|
419
|
+
if (branch && branch.startsWith("keiyaku/")) {
|
|
420
|
+
const baseBranch = await git.getKeiyakuBase(cwd, branch);
|
|
421
|
+
if (baseBranch) {
|
|
422
|
+
diffStats = await git.getDiffPreviewText(cwd, baseBranch);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
catch {
|
|
427
|
+
branch = undefined;
|
|
428
|
+
}
|
|
429
|
+
return { summary, branch, diffStats };
|
|
403
430
|
}
|
|
404
431
|
export async function handleClose(input) {
|
|
405
432
|
const { cwd } = input;
|
|
@@ -503,7 +530,7 @@ export async function handleClose(input) {
|
|
|
503
530
|
const invokeFinalizeLog = `[CLAIM] Deleting merged branch '${keiyakuBranch}' and clearing metadata`;
|
|
504
531
|
console.error(invokeFinalizeLog);
|
|
505
532
|
appendDebugLog(invokeFinalizeLog, { cwd, section: "script" });
|
|
506
|
-
await git.deleteBranch(cwd, keiyakuBranch);
|
|
533
|
+
await git.deleteBranch(cwd, keiyakuBranch, true);
|
|
507
534
|
await git.clearKeiyakuBase(cwd, keiyakuBranch);
|
|
508
535
|
const round = computeTraceState(traceContent).maxRound;
|
|
509
536
|
return {
|
|
@@ -549,7 +576,7 @@ export async function handleDrive(input) {
|
|
|
549
576
|
await appendReview(cwd, plan.targetRound, plan.reviewReason);
|
|
550
577
|
await git.addFiles(cwd, TRACE_FILE);
|
|
551
578
|
await git.commit(cwd, `keiyaku(${title}): iterate round ${plan.targetRound}`);
|
|
552
|
-
const { summary } = await runAndRecordRound(cwd, title, plan.targetRound, plan.prompt, {
|
|
579
|
+
const { summary: rawSummary } = await runAndRecordRound(cwd, title, plan.targetRound, plan.prompt, {
|
|
553
580
|
signal,
|
|
554
581
|
name,
|
|
555
582
|
failureMode: "round_specific",
|
|
@@ -559,6 +586,7 @@ export async function handleDrive(input) {
|
|
|
559
586
|
await git.commit(cwd, `keiyaku(${title}): round ${plan.targetRound} cancelled`);
|
|
560
587
|
},
|
|
561
588
|
});
|
|
589
|
+
const summary = filterInternalSections(rawSummary);
|
|
562
590
|
const trace = await fs.readFile(path.join(cwd, TRACE_FILE), "utf-8");
|
|
563
591
|
const diff = await git.getIncrementalDiff(cwd);
|
|
564
592
|
return {
|
|
@@ -16,17 +16,31 @@ Round: 1 (initial implementation).
|
|
|
16
16
|
- Do not violate constraints.
|
|
17
17
|
- Meet all criteria.
|
|
18
18
|
- Match existing structure.
|
|
19
|
-
6. End with
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
19
|
+
6. End with exactly these 6 sections using this strict Markdown template:
|
|
20
|
+
|
|
21
|
+
## Outcome
|
|
22
|
+
[One sentence summarizing the outcome]
|
|
23
|
+
|
|
24
|
+
## Changes
|
|
25
|
+
- [File path]: [Brief description of change]
|
|
26
|
+
- [Logic delta]: [Key architectural or logic shift]
|
|
27
|
+
|
|
28
|
+
## Aesthetics Gap
|
|
29
|
+
Self-critique.
|
|
30
|
+
- precise: [score/reasoning]
|
|
31
|
+
- minimal: [score/reasoning]
|
|
32
|
+
- isolated: [score/reasoning]
|
|
33
|
+
- idiomatic: [score/reasoning]
|
|
34
|
+
- cohesive: [score/reasoning]
|
|
35
|
+
|
|
36
|
+
## Blindspots
|
|
37
|
+
- [Unintentional side effects or untested paths]
|
|
38
|
+
|
|
39
|
+
## Criteria Check
|
|
40
|
+
- [List each criterion and its status: MET/PARTIAL/TODO]
|
|
41
|
+
|
|
42
|
+
## Constraints Check
|
|
43
|
+
- [List each constraint and confirm compliance: COMPLIANT/VIOLATED]
|
|
30
44
|
|
|
31
45
|
No git commands. Do not edit KEIYAKU_TRACE.md.`;
|
|
32
46
|
}
|
|
@@ -43,17 +57,31 @@ ${reason}
|
|
|
43
57
|
4. Fix review reason first.
|
|
44
58
|
5. No drift from constraints/criteria.
|
|
45
59
|
6. Keep diff small.
|
|
46
|
-
7. End with
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
60
|
+
7. End with exactly these 6 sections using this strict Markdown template:
|
|
61
|
+
|
|
62
|
+
## Outcome
|
|
63
|
+
[One sentence summarizing the outcome]
|
|
64
|
+
|
|
65
|
+
## Changes
|
|
66
|
+
- [File path]: [Brief description of change]
|
|
67
|
+
- [Logic delta]: [Key architectural or logic shift]
|
|
68
|
+
|
|
69
|
+
## Aesthetics Gap
|
|
70
|
+
Self-critique.
|
|
71
|
+
- precise: [score/reasoning]
|
|
72
|
+
- minimal: [score/reasoning]
|
|
73
|
+
- isolated: [score/reasoning]
|
|
74
|
+
- idiomatic: [score/reasoning]
|
|
75
|
+
- cohesive: [score/reasoning]
|
|
76
|
+
|
|
77
|
+
## Blindspots
|
|
78
|
+
- [Unintentional side effects or untested paths]
|
|
79
|
+
|
|
80
|
+
## Criteria Check
|
|
81
|
+
- [List each criterion and its status: MET/PARTIAL/TODO]
|
|
82
|
+
|
|
83
|
+
## Constraints Check
|
|
84
|
+
- [List each constraint and confirm compliance: COMPLIANT/VIOLATED]
|
|
57
85
|
|
|
58
86
|
No git commands. Do not edit KEIYAKU_TRACE.md.`;
|
|
59
87
|
}
|
|
@@ -66,5 +94,5 @@ ${request}
|
|
|
66
94
|
Context:
|
|
67
95
|
${context}
|
|
68
96
|
|
|
69
|
-
Provide a clear
|
|
97
|
+
Provide a clear final response.`;
|
|
70
98
|
}
|
|
@@ -31,8 +31,38 @@ function buildSection(title, content) {
|
|
|
31
31
|
return "";
|
|
32
32
|
return `[${title}]\n${validLines.join("\n")}`;
|
|
33
33
|
}
|
|
34
|
+
function supportsHeaderColor() {
|
|
35
|
+
if (process.env.NO_COLOR !== undefined)
|
|
36
|
+
return false;
|
|
37
|
+
if (process.env.FORCE_COLOR === "0")
|
|
38
|
+
return false;
|
|
39
|
+
if (process.env.FORCE_COLOR !== undefined)
|
|
40
|
+
return true;
|
|
41
|
+
if (!process.stdout?.isTTY)
|
|
42
|
+
return false;
|
|
43
|
+
const term = process.env.TERM?.toLowerCase();
|
|
44
|
+
return term !== undefined && term !== "dumb";
|
|
45
|
+
}
|
|
46
|
+
function colorizeHeaderTitle(titleLabel) {
|
|
47
|
+
return `\x1b[1;38;5;15;48;5;23m${titleLabel}\x1b[0m`;
|
|
48
|
+
}
|
|
49
|
+
function colorizeErrorStatus(status) {
|
|
50
|
+
if (!supportsHeaderColor())
|
|
51
|
+
return status;
|
|
52
|
+
return `\x1b[1;38;5;15;48;5;196m${status}\x1b[0m`;
|
|
53
|
+
}
|
|
34
54
|
function formatHeader(title) {
|
|
35
|
-
|
|
55
|
+
const headerWidth = 60;
|
|
56
|
+
const normalizedTitle = title.trim().toUpperCase();
|
|
57
|
+
const titleLabel = ` ${normalizedTitle} `;
|
|
58
|
+
if (!supportsHeaderColor()) {
|
|
59
|
+
const plainPrefix = `──${titleLabel}`;
|
|
60
|
+
const divider = "─".repeat(Math.max(0, headerWidth - plainPrefix.length));
|
|
61
|
+
return divider.length > 0 ? `\n${plainPrefix}${divider}` : `\n${plainPrefix}`;
|
|
62
|
+
}
|
|
63
|
+
const coloredTitle = colorizeHeaderTitle(titleLabel);
|
|
64
|
+
const divider = "─".repeat(Math.max(0, headerWidth - titleLabel.length - 1));
|
|
65
|
+
return divider.length > 0 ? `\n${coloredTitle} ${divider}` : `\n${coloredTitle}`;
|
|
36
66
|
}
|
|
37
67
|
function assembleResponse(status, summary, sections, nextHints, infoLines = []) {
|
|
38
68
|
// Main Status Block
|
|
@@ -60,7 +90,7 @@ ${summary}
|
|
|
60
90
|
: "";
|
|
61
91
|
// Next Steps Block
|
|
62
92
|
const nextBlock = nextHints.length > 0
|
|
63
|
-
? `${formatHeader("
|
|
93
|
+
? `${formatHeader("Hints")}\n${nextHints.map(h => `› ${h}`).join("\n")}`
|
|
64
94
|
: "";
|
|
65
95
|
return [
|
|
66
96
|
statusBlock,
|
|
@@ -126,7 +156,7 @@ export function buildKeiyakuSuccessResponse(result, input) {
|
|
|
126
156
|
...formatMaybe("Current Branch", result.branch, 200),
|
|
127
157
|
...formatMaybe("Base Branch", result.baseBranch, 200),
|
|
128
158
|
];
|
|
129
|
-
const text = assembleResponse(`Started (Round ${result.round})`, `Created branch '${result.branch}' (base: '${result.baseBranch}')
|
|
159
|
+
const text = assembleResponse(`Started (Round ${result.round})`, `Created branch '${result.branch}' (base: '${result.baseBranch}').\n\n${result.summary}`, [inputSection, diffSection], nextHints, infoLines);
|
|
130
160
|
return {
|
|
131
161
|
content: [{ type: "text", text }],
|
|
132
162
|
structuredContent: buildSuccessStructuredContent(getStartToolName(), {
|
|
@@ -153,7 +183,7 @@ export function buildDriveResponse(result, input) {
|
|
|
153
183
|
...formatMaybe("Current Branch", result.branch, 200),
|
|
154
184
|
...formatMaybe("Base Branch", result.baseBranch, 200),
|
|
155
185
|
];
|
|
156
|
-
const text = assembleResponse(`Driven (Round ${result.round})`, `Updated branch '${result.branch}'
|
|
186
|
+
const text = assembleResponse(`Driven (Round ${result.round})`, `Updated branch '${result.branch}'.\n\n${result.summary}`, [inputSection, diffSection], nextHints, infoLines);
|
|
157
187
|
return {
|
|
158
188
|
content: [{ type: "text", text }],
|
|
159
189
|
structuredContent: buildSuccessStructuredContent(getDriveToolName(), {
|
|
@@ -173,7 +203,11 @@ export function buildAskResponse(result, input) {
|
|
|
173
203
|
];
|
|
174
204
|
const nextHints = renderHints(resolveTermPreset().nextHints.ask);
|
|
175
205
|
const inputSection = buildSection("Input", inputEcho);
|
|
176
|
-
const infoLines = [
|
|
206
|
+
const infoLines = [
|
|
207
|
+
...formatMaybe("CWD", input.cwd, 300),
|
|
208
|
+
...formatMaybe("Current Branch", result.branch, 200),
|
|
209
|
+
...formatMaybe("Diff Stats", result.diffStats, 1000),
|
|
210
|
+
];
|
|
177
211
|
const text = assembleResponse("Answered", result.summary, [inputSection], nextHints, infoLines);
|
|
178
212
|
return {
|
|
179
213
|
content: [{ type: "text", text }],
|
|
@@ -244,7 +278,7 @@ export function buildCloseDropResponse(result, input) {
|
|
|
244
278
|
export function buildToolErrorResponse(input) {
|
|
245
279
|
const inputEcho = (input.inputEcho ?? []).map((line) => truncateForDisplay(line, 800));
|
|
246
280
|
const shouldRaiseProtocolError = input.errorType === "runtime_error";
|
|
247
|
-
const text = assembleResponse("
|
|
281
|
+
const text = assembleResponse(colorizeErrorStatus("!! FAILED !!"), input.message, [buildSection("Input Context", inputEcho)], [input.hint]);
|
|
248
282
|
const response = {
|
|
249
283
|
content: [{ type: "text", text }],
|
|
250
284
|
structuredContent: {
|