@astrosheep/keiyaku 0.1.9 → 0.1.10
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.
|
@@ -19,7 +19,7 @@ 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.',
|
|
@@ -81,7 +81,7 @@ export const DEFAULT_PRESET = {
|
|
|
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.',
|
|
@@ -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.',
|
|
@@ -187,11 +187,11 @@ export const POCKET_PRESET = {
|
|
|
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 ${IDENTITY} doing the
|
|
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
|
},
|
|
@@ -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,7 +241,7 @@ 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.',
|
|
@@ -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: oi → [neh x N] →
|
|
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: oi → [neh x N] → dayaa",
|
|
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.',
|
|
@@ -272,7 +272,7 @@ export const MISCHIEF_PRESET = {
|
|
|
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: oi → [neh x N] →
|
|
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: oi → [neh x N] → dayaa',
|
|
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.',
|
|
@@ -281,28 +281,28 @@ export const MISCHIEF_PRESET = {
|
|
|
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 ${IDENTITY} to
|
|
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_TOOL_NAME} → [${DRIVE_TOOL_NAME} x N] → ${CLOSE_TOOL_NAME}',
|
|
298
298
|
args: {
|
|
299
299
|
petition: 'REQUIRED. CLAIM demands rule; FORFEIT admits defeat.\nREQUIRES AN ACTIVE SCHEME (started via ${START_TOOL_NAME}).\nIf the plan is weak, improve it with ${DRIVE_TOOL_NAME}.',
|
|
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
|
|
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
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
|
},
|
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) {
|
|
@@ -399,7 +399,21 @@ export async function handleAsk(input) {
|
|
|
399
399
|
const prompt = buildAskPrompt(request, context);
|
|
400
400
|
// TODO: enforce read-only access and persist summary to .keiyaku/notes/.
|
|
401
401
|
const summary = await runSubagent(selectSubagent(name), prompt, cwd, 0, signal);
|
|
402
|
-
|
|
402
|
+
let branch;
|
|
403
|
+
let diffStats;
|
|
404
|
+
try {
|
|
405
|
+
branch = await git.getCurrentBranch(cwd);
|
|
406
|
+
if (branch && branch.startsWith("keiyaku/")) {
|
|
407
|
+
const baseBranch = await git.getKeiyakuBase(cwd, branch);
|
|
408
|
+
if (baseBranch) {
|
|
409
|
+
diffStats = await git.getDiffPreviewText(cwd, baseBranch);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
catch {
|
|
414
|
+
branch = undefined;
|
|
415
|
+
}
|
|
416
|
+
return { summary, branch, diffStats };
|
|
403
417
|
}
|
|
404
418
|
export async function handleClose(input) {
|
|
405
419
|
const { cwd } = input;
|
|
@@ -503,7 +517,7 @@ export async function handleClose(input) {
|
|
|
503
517
|
const invokeFinalizeLog = `[CLAIM] Deleting merged branch '${keiyakuBranch}' and clearing metadata`;
|
|
504
518
|
console.error(invokeFinalizeLog);
|
|
505
519
|
appendDebugLog(invokeFinalizeLog, { cwd, section: "script" });
|
|
506
|
-
await git.deleteBranch(cwd, keiyakuBranch);
|
|
520
|
+
await git.deleteBranch(cwd, keiyakuBranch, true);
|
|
507
521
|
await git.clearKeiyakuBase(cwd, keiyakuBranch);
|
|
508
522
|
const round = computeTraceState(traceContent).maxRound;
|
|
509
523
|
return {
|
|
@@ -31,8 +31,33 @@ 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
|
+
}
|
|
34
49
|
function formatHeader(title) {
|
|
35
|
-
|
|
50
|
+
const headerWidth = 60;
|
|
51
|
+
const normalizedTitle = title.trim().toUpperCase();
|
|
52
|
+
const titleLabel = ` ${normalizedTitle} `;
|
|
53
|
+
if (!supportsHeaderColor()) {
|
|
54
|
+
const plainPrefix = `──${titleLabel}`;
|
|
55
|
+
const divider = "─".repeat(Math.max(0, headerWidth - plainPrefix.length));
|
|
56
|
+
return divider.length > 0 ? `\n${plainPrefix}${divider}` : `\n${plainPrefix}`;
|
|
57
|
+
}
|
|
58
|
+
const coloredTitle = colorizeHeaderTitle(titleLabel);
|
|
59
|
+
const divider = "─".repeat(Math.max(0, headerWidth - titleLabel.length - 1));
|
|
60
|
+
return divider.length > 0 ? `\n${coloredTitle} ${divider}` : `\n${coloredTitle}`;
|
|
36
61
|
}
|
|
37
62
|
function assembleResponse(status, summary, sections, nextHints, infoLines = []) {
|
|
38
63
|
// Main Status Block
|
|
@@ -173,7 +198,11 @@ export function buildAskResponse(result, input) {
|
|
|
173
198
|
];
|
|
174
199
|
const nextHints = renderHints(resolveTermPreset().nextHints.ask);
|
|
175
200
|
const inputSection = buildSection("Input", inputEcho);
|
|
176
|
-
const infoLines = [
|
|
201
|
+
const infoLines = [
|
|
202
|
+
...formatMaybe("CWD", input.cwd, 300),
|
|
203
|
+
...formatMaybe("Current Branch", result.branch, 200),
|
|
204
|
+
...formatMaybe("Diff Stats", result.diffStats, 1000),
|
|
205
|
+
];
|
|
177
206
|
const text = assembleResponse("Answered", result.summary, [inputSection], nextHints, infoLines);
|
|
178
207
|
return {
|
|
179
208
|
content: [{ type: "text", text }],
|