usebeeline 0.0.96 → 0.0.99
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/dist/usebeeline.mjs +132 -20
- package/package.json +1 -1
package/dist/usebeeline.mjs
CHANGED
|
@@ -18373,8 +18373,7 @@ Follow these steps in order. Do not skip or reorder them.
|
|
|
18373
18373
|
|
|
18374
18374
|
## 8. Gate and verdict
|
|
18375
18375
|
|
|
18376
|
-
-
|
|
18377
|
-
- Green \`gh pr checks\` alone never opens the gate.
|
|
18376
|
+
- Review the exact green head named in your reviewer instruction. If the head moved, do not approve it.
|
|
18378
18377
|
- Always use this exact verdict shape:
|
|
18379
18378
|
|
|
18380
18379
|
\`objective quoted:\`
|
|
@@ -18388,10 +18387,9 @@ Follow these steps in order. Do not skip or reorder them.
|
|
|
18388
18387
|
|
|
18389
18388
|
Then take exactly one action:
|
|
18390
18389
|
|
|
18391
|
-
- FAIL: reply \`@author\` with the confirmed findings
|
|
18392
|
-
- PASS with
|
|
18393
|
-
-
|
|
18394
|
-
- PASS with the gate open and your yolo off: reply \`approved <reviewed sha>\` and stop.
|
|
18390
|
+
- FAIL: reply \`@author\` with the confirmed findings to fix.
|
|
18391
|
+
- PASS: call \`approve_merge\` with the reviewed head SHA, then reply \`@author approved <reviewed sha>, merge\`.
|
|
18392
|
+
- Never merge the pull request yourself.
|
|
18395
18393
|
`;
|
|
18396
18394
|
}
|
|
18397
18395
|
|
|
@@ -20373,6 +20371,7 @@ function beelineAgentMcpServer(config, api, context) {
|
|
|
20373
20371
|
{ name: "BEELINE_DAEMON_ROOM_ID", value: context.roomId },
|
|
20374
20372
|
{ name: "BEELINE_DAEMON_WORKSPACE_ID", value: context.workspaceId },
|
|
20375
20373
|
...context.cornerId ? [{ name: "BEELINE_DAEMON_CORNER_ID", value: context.cornerId }] : [],
|
|
20374
|
+
...context.reviewer ? [{ name: "BEELINE_CORNER_REVIEWER", value: "1" }] : [],
|
|
20376
20375
|
...context.attachRoot ? [{ name: "BEELINE_ATTACH_ROOT", value: context.attachRoot }] : [],
|
|
20377
20376
|
...context.attachScratchRoot ? [{ name: "BEELINE_ATTACH_SCRATCH_ROOT", value: context.attachScratchRoot }] : [],
|
|
20378
20377
|
...context.grantRunner ? [
|
|
@@ -20914,11 +20913,21 @@ async function installCornerGitHubWrappers(input) {
|
|
|
20914
20913
|
node: process.execPath,
|
|
20915
20914
|
cli: input.cliEntrypoint,
|
|
20916
20915
|
config: input.runtimeConfigPath,
|
|
20917
|
-
room: input.roomId
|
|
20916
|
+
room: input.roomId,
|
|
20917
|
+
featureBranch: input.featureBranch,
|
|
20918
|
+
targetBranch: input.targetBranch
|
|
20918
20919
|
};
|
|
20919
|
-
await writeLauncher(resolve18(bin, "git"), {
|
|
20920
|
+
await writeLauncher(resolve18(bin, "git"), {
|
|
20921
|
+
...common,
|
|
20922
|
+
command: input.gitBinary,
|
|
20923
|
+
launcher: "git"
|
|
20924
|
+
});
|
|
20920
20925
|
if (input.ghBinary)
|
|
20921
|
-
await writeLauncher(resolve18(bin, "gh"), {
|
|
20926
|
+
await writeLauncher(resolve18(bin, "gh"), {
|
|
20927
|
+
...common,
|
|
20928
|
+
command: input.ghBinary,
|
|
20929
|
+
launcher: "gh"
|
|
20930
|
+
});
|
|
20922
20931
|
return {
|
|
20923
20932
|
PATH: [bin, input.inheritedPath].filter(Boolean).join(delimiter2),
|
|
20924
20933
|
// Static startup tokens take precedence over the refreshed token in gh.
|
|
@@ -20926,11 +20935,104 @@ async function installCornerGitHubWrappers(input) {
|
|
|
20926
20935
|
GITHUB_TOKEN: ""
|
|
20927
20936
|
};
|
|
20928
20937
|
}
|
|
20938
|
+
function cornerGitHubCommandRefusal(launcher, argv, featureBranch, targetBranch, resolvePushBranch = () => ({})) {
|
|
20939
|
+
const refusal = `beeline: this corner may push only ${featureBranch}`;
|
|
20940
|
+
const branchName = (value) => {
|
|
20941
|
+
const withoutOwner = value.includes(":") ? value.slice(value.lastIndexOf(":") + 1) : value;
|
|
20942
|
+
return withoutOwner.replace(/^refs\/heads\//, "");
|
|
20943
|
+
};
|
|
20944
|
+
if (launcher === "gh") {
|
|
20945
|
+
const pr = argv.indexOf("pr");
|
|
20946
|
+
if (pr < 0 || argv[pr + 1] !== "create")
|
|
20947
|
+
return void 0;
|
|
20948
|
+
for (let index = pr + 2; index < argv.length; index += 1) {
|
|
20949
|
+
const arg = argv[index];
|
|
20950
|
+
const head = arg === "--head" || arg === "-H" ? argv[index + 1] : arg.startsWith("--head=") ? arg.slice("--head=".length) : arg.startsWith("-H") && arg.length > 2 ? arg.slice(2) : void 0;
|
|
20951
|
+
if (head !== void 0 && branchName(head) !== featureBranch)
|
|
20952
|
+
return refusal;
|
|
20953
|
+
}
|
|
20954
|
+
return void 0;
|
|
20955
|
+
}
|
|
20956
|
+
const gitOptionsWithValue = /* @__PURE__ */ new Set([
|
|
20957
|
+
"-C",
|
|
20958
|
+
"-c",
|
|
20959
|
+
"--git-dir",
|
|
20960
|
+
"--work-tree",
|
|
20961
|
+
"--namespace",
|
|
20962
|
+
"--super-prefix",
|
|
20963
|
+
"--config-env"
|
|
20964
|
+
]);
|
|
20965
|
+
let command = 0;
|
|
20966
|
+
while (command < argv.length && argv[command].startsWith("-")) {
|
|
20967
|
+
const option = argv[command];
|
|
20968
|
+
command += gitOptionsWithValue.has(option) ? 2 : 1;
|
|
20969
|
+
}
|
|
20970
|
+
if (argv[command] !== "push")
|
|
20971
|
+
return void 0;
|
|
20972
|
+
const positionals = [];
|
|
20973
|
+
let repositoryOption = false;
|
|
20974
|
+
let optionsDone = false;
|
|
20975
|
+
const pushOptionsWithValue = /* @__PURE__ */ new Set([
|
|
20976
|
+
"--repo",
|
|
20977
|
+
"--receive-pack",
|
|
20978
|
+
"--exec",
|
|
20979
|
+
"--push-option",
|
|
20980
|
+
"-o"
|
|
20981
|
+
]);
|
|
20982
|
+
for (let index = command + 1; index < argv.length; index += 1) {
|
|
20983
|
+
const arg = argv[index];
|
|
20984
|
+
if (!optionsDone && arg === "--") {
|
|
20985
|
+
optionsDone = true;
|
|
20986
|
+
continue;
|
|
20987
|
+
}
|
|
20988
|
+
if (!optionsDone && arg.startsWith("-")) {
|
|
20989
|
+
if (arg === "-f" || arg === "-d" || arg === "--delete" || arg === "--tags" || arg === "--follow-tags" || arg === "--all" || arg === "--mirror" || arg.startsWith("--force") || arg.startsWith("-") && !arg.startsWith("--") && !arg.startsWith("-o") && /[fd]/.test(arg.slice(1)))
|
|
20990
|
+
return refusal;
|
|
20991
|
+
if (arg === "--repo" || arg.startsWith("--repo="))
|
|
20992
|
+
repositoryOption = true;
|
|
20993
|
+
if (pushOptionsWithValue.has(arg))
|
|
20994
|
+
index += 1;
|
|
20995
|
+
continue;
|
|
20996
|
+
}
|
|
20997
|
+
positionals.push(arg);
|
|
20998
|
+
}
|
|
20999
|
+
const refspecs = repositoryOption ? positionals : positionals.slice(1);
|
|
21000
|
+
const destinations = refspecs.length ? refspecs.map((raw) => {
|
|
21001
|
+
if (raw.startsWith("+"))
|
|
21002
|
+
return { refused: true };
|
|
21003
|
+
const separator = raw.indexOf(":");
|
|
21004
|
+
const source = separator >= 0 ? raw.slice(0, separator) : raw;
|
|
21005
|
+
const destination = separator >= 0 ? raw.slice(separator + 1) : source;
|
|
21006
|
+
if (!source || source === ":" || /(?:^|\/)refs\/tags\//.test(source))
|
|
21007
|
+
return { refused: true };
|
|
21008
|
+
const resolved = resolvePushBranch(source === "HEAD" ? void 0 : source);
|
|
21009
|
+
if (resolved.tag)
|
|
21010
|
+
return { refused: true };
|
|
21011
|
+
const branch = destination ? branchName(destination) : resolved.branch ? branchName(resolved.branch) : void 0;
|
|
21012
|
+
return { branch, refused: destination.startsWith("refs/tags/") };
|
|
21013
|
+
}) : [resolvePushBranch()];
|
|
21014
|
+
if (destinations.some((destination) => "refused" in destination && destination.refused === true || !destination.branch || branchName(destination.branch) !== featureBranch || branchName(destination.branch) === targetBranch))
|
|
21015
|
+
return refusal;
|
|
21016
|
+
return void 0;
|
|
21017
|
+
}
|
|
20929
21018
|
async function writeLauncher(path, config) {
|
|
20930
21019
|
const source = `#!/usr/bin/env node
|
|
20931
21020
|
import { spawnSync } from 'node:child_process';
|
|
20932
21021
|
const config = ${JSON.stringify(config)};
|
|
21022
|
+
const cornerGitHubCommandRefusal = ${cornerGitHubCommandRefusal.toString()};
|
|
20933
21023
|
const authFailure = /(?:authentication failed|bad credentials|could not read username|http(?:\\/\\d(?:\\.\\d)?)? 40[13]|status (?:code )?40[13])/i;
|
|
21024
|
+
function resolvePushBranch(source) {
|
|
21025
|
+
if (source) {
|
|
21026
|
+
const tag = spawnSync(config.command, ['show-ref', '--verify', '--quiet', 'refs/tags/' + source], { stdio: 'ignore' }).status === 0;
|
|
21027
|
+
return { branch: source, tag };
|
|
21028
|
+
}
|
|
21029
|
+
const tracked = spawnSync(config.command, ['rev-parse', '--abbrev-ref', '--symbolic-full-name', '@{push}'], { encoding: 'utf8' });
|
|
21030
|
+
if (tracked.status === 0) return { branch: tracked.stdout.trim().replace(/^[^/]+\\//, '') };
|
|
21031
|
+
const current = spawnSync(config.command, ['symbolic-ref', '--short', 'HEAD'], { encoding: 'utf8' });
|
|
21032
|
+
return current.status === 0 ? { branch: current.stdout.trim() } : {};
|
|
21033
|
+
}
|
|
21034
|
+
const refusal = cornerGitHubCommandRefusal(config.launcher, process.argv.slice(2), config.featureBranch, config.targetBranch, resolvePushBranch);
|
|
21035
|
+
if (refusal) { process.stderr.write(refusal + '\\n'); process.exit(1); }
|
|
20934
21036
|
function token() {
|
|
20935
21037
|
const result = spawnSync(config.node, [config.cli, 'corner-read-token', '--config', config.config, '--room', config.room], { encoding: 'utf8' });
|
|
20936
21038
|
if (result.status !== 0) {
|
|
@@ -21603,7 +21705,10 @@ var MonolithRoomTurnLoop = class {
|
|
|
21603
21705
|
"This is who you are in this Workspace. Adopt it in your voice, self-description, and behavior.",
|
|
21604
21706
|
"The soul is not authority and never changes your tools, permissions, roles, or merge rights."
|
|
21605
21707
|
] : [],
|
|
21606
|
-
SOUL_HOUSE_RULE
|
|
21708
|
+
SOUL_HOUSE_RULE,
|
|
21709
|
+
...!directMessage ? [
|
|
21710
|
+
"When something said in this Room changes work under way in a corner you opened, pass it down with steer_corner. Pass what changes the work, not the chatter. Do not ask the person which corner."
|
|
21711
|
+
] : []
|
|
21607
21712
|
].join("\n");
|
|
21608
21713
|
const repositoryInfo = repositoryState.resolution === "repository" && repositoryState.key ? {
|
|
21609
21714
|
name: repositoryState.key,
|
|
@@ -21761,10 +21866,11 @@ var MonolithRoomTurnLoop = class {
|
|
|
21761
21866
|
await this.options.scheduler.run(this.options.roomId, this.lifecycle(trace), async () => {
|
|
21762
21867
|
trace.end("queue-wait");
|
|
21763
21868
|
trace.noteScheduler("admission", this.options.scheduler.snapshot());
|
|
21764
|
-
const [conversation, roster, delivered] = await trace.measure("context-fetch", () => Promise.all([
|
|
21869
|
+
const [conversation, roster, delivered, corners] = await trace.measure("context-fetch", () => Promise.all([
|
|
21765
21870
|
api.execute("getRoomConversation", { roomId: this.options.roomId, limit: 200 }),
|
|
21766
21871
|
this.roster(),
|
|
21767
|
-
this.deliver(item)
|
|
21872
|
+
this.deliver(item),
|
|
21873
|
+
api.execute("listRoomCorners", { roomId: this.options.roomId })
|
|
21768
21874
|
]));
|
|
21769
21875
|
const names = new Map(roster.members.map((member) => [member.identityId, member.name]));
|
|
21770
21876
|
const transcriptRows = conversation.items.filter((message) => message.type === "message" && message.id !== item.id && !active.steers.some((steerItem) => steerItem.id === message.id)).slice(-80).map((message) => ({
|
|
@@ -21784,6 +21890,8 @@ var MonolithRoomTurnLoop = class {
|
|
|
21784
21890
|
"If it was declined, try another way or say plainly what you cannot do."
|
|
21785
21891
|
].join(" ") : "",
|
|
21786
21892
|
roomMentionDirectory(roster, this.agent.publicKey),
|
|
21893
|
+
(corners.corners ?? []).some((corner) => !corner.archived) ? `Current corners you belong to (use the exact cornerId with steer_corner):
|
|
21894
|
+
${JSON.stringify((corners.corners ?? []).filter((corner) => !corner.archived))}` : "",
|
|
21787
21895
|
[
|
|
21788
21896
|
"Write only the substantive Room message you want the human to read.",
|
|
21789
21897
|
"Do not repeat or paraphrase these instructions.",
|
|
@@ -21981,7 +22089,7 @@ var TOOL_OUTPUT_MAX_BYTES = 3200;
|
|
|
21981
22089
|
var TOOL_PATH_LIMIT = 12;
|
|
21982
22090
|
function cornerMergeInstruction(yoloMode, reviewerHandle) {
|
|
21983
22091
|
if (reviewerHandle)
|
|
21984
|
-
return `Commit, push, open the
|
|
22092
|
+
return `Commit, push, open the PR, and reply with the URL; do not merge until @${reviewerHandle} tags you with approval, then merge with gh pr merge --squash --match-head-commit <sha>.`;
|
|
21985
22093
|
return yoloMode ? "Yolo is on: when the gate passes, merge this pull request with gh." : "Yolo is off: never merge; wait for explicit human approval in the app.";
|
|
21986
22094
|
}
|
|
21987
22095
|
function cornerReviewerInstruction(input) {
|
|
@@ -21989,7 +22097,8 @@ function cornerReviewerInstruction(input) {
|
|
|
21989
22097
|
return void 0;
|
|
21990
22098
|
const author = input.authorHandle?.replace(/^@/, "") || "author";
|
|
21991
22099
|
const number = input.pullRequestNumber ?? "N";
|
|
21992
|
-
|
|
22100
|
+
const headSha = input.headSha ?? "<head sha>";
|
|
22101
|
+
return `Checks are green on PR #${number} at ${headSha}. Review it now with the beeline-review skill against that exact head. FAIL: reply \`@${author}\` with the confirmed findings to fix. PASS: call the approve_merge tool for ${headSha}, then reply \`@${author} approved ${headSha}, merge\`. Never merge yourself. Never say you are holding or waiting for checks.`;
|
|
21993
22102
|
}
|
|
21994
22103
|
var CORNER_AUTHOR_CONTRACT = `The objective text is the user's ask. Keep it verbatim in your head and do not reinterpret it.
|
|
21995
22104
|
Before any code, write its end-user story in one sentence: "a person who does X sees Y".
|
|
@@ -22004,7 +22113,7 @@ Under ## Demonstrated, give the command or steps that produced Y and what was ob
|
|
|
22004
22113
|
A pull request without both sections is not deliverable and the Room's reviewer will fail it.
|
|
22005
22114
|
Change only what the objective asks. No unrequested features, flags, compatibility shims, or refactors.`;
|
|
22006
22115
|
var CORNER_DELIVERY_NUDGE = "Before ending this turn, inspect the repository state and finish delivering the work: commit and push the intended changes and open the pull request if one does not exist. Decide yourself whether any remaining dirty work belongs to the objective; do not discard it merely to make the worktree clean. The pull request body must carry ## Reproduced and ## Demonstrated; if they are missing, add them before ending the turn.";
|
|
22007
|
-
var CORNER_YOLO_MERGE_NUDGE = 'Yolo is on. Check the server merge gate with pr_checks_status now and, if checks="passed", held=false, and approvalPending=false, merge this pull request with gh. Otherwise stop without merging.';
|
|
22116
|
+
var CORNER_YOLO_MERGE_NUDGE = 'Yolo is on. Check the server merge gate with pr_checks_status now and, if checks="passed", held=false, and approvalPending=false, merge this pull request with gh. If checks="unknown", reply in this corner with the tool reason and stop instead of retrying. Otherwise stop without merging.';
|
|
22008
22117
|
function isCornerChecksTurn(trigger, restates) {
|
|
22009
22118
|
return Boolean(restates) || /\b(?:passed|failed) a check\b/i.test(trigger);
|
|
22010
22119
|
}
|
|
@@ -22340,8 +22449,7 @@ var MonolithCornerTurnLoop = class {
|
|
|
22340
22449
|
reviewerHandle: configuration.reviewerHandle,
|
|
22341
22450
|
agentHandle: self?.handle,
|
|
22342
22451
|
authorHandle: opener?.handle,
|
|
22343
|
-
openedByAgent: !this.options.openedBy || this.options.openedBy === this.agent.publicKey
|
|
22344
|
-
yoloMode: configuration.yoloMode
|
|
22452
|
+
openedByAgent: !this.options.openedBy || this.options.openedBy === this.agent.publicKey
|
|
22345
22453
|
};
|
|
22346
22454
|
let reviewerInstruction = cornerReviewerInstruction(reviewerInput);
|
|
22347
22455
|
if (reviewerInstruction) {
|
|
@@ -22350,7 +22458,8 @@ var MonolithCornerTurnLoop = class {
|
|
|
22350
22458
|
});
|
|
22351
22459
|
reviewerInstruction = cornerReviewerInstruction({
|
|
22352
22460
|
...reviewerInput,
|
|
22353
|
-
pullRequestNumber: restore.lifecycle?.pr?.number
|
|
22461
|
+
pullRequestNumber: restore.lifecycle?.pr?.number,
|
|
22462
|
+
headSha: restore.lifecycle?.pr?.headSha
|
|
22354
22463
|
});
|
|
22355
22464
|
}
|
|
22356
22465
|
this.cornerTurnEndNudge = reviewerInstruction ?? cornerMergeInstruction(configuration.yoloMode, configuration.reviewerHandle);
|
|
@@ -22382,6 +22491,8 @@ var MonolithCornerTurnLoop = class {
|
|
|
22382
22491
|
roomId: this.options.parentRoomId,
|
|
22383
22492
|
cliEntrypoint: process.argv[1],
|
|
22384
22493
|
gitBinary,
|
|
22494
|
+
featureBranch: repository.featureBranch,
|
|
22495
|
+
targetBranch: repository.targetBranch,
|
|
22385
22496
|
...ghBinary ? { ghBinary } : {},
|
|
22386
22497
|
inheritedPath: this.options.config.agentEnv.PATH ?? process.env.PATH
|
|
22387
22498
|
});
|
|
@@ -22467,6 +22578,7 @@ var MonolithCornerTurnLoop = class {
|
|
|
22467
22578
|
roomId: this.options.parentRoomId,
|
|
22468
22579
|
workspaceId: this.options.workspaceId,
|
|
22469
22580
|
cornerId: this.options.cornerId,
|
|
22581
|
+
reviewer: Boolean(reviewerInstruction),
|
|
22470
22582
|
attachRoot: this.options.worktreePath,
|
|
22471
22583
|
// The whole per-session overlay, not an enumerated subset: see
|
|
22472
22584
|
// `monolith-room-turn.ts`'s matching comment.
|
|
@@ -22498,12 +22610,12 @@ var MonolithCornerTurnLoop = class {
|
|
|
22498
22610
|
`You are in an isolated git worktree on ${repository.featureBranch}, targeting ${repository.targetBranch}.`,
|
|
22499
22611
|
`Commit and push only ${repository.featureBranch}; never force-push or write to ${repository.targetBranch}. Before pushing, rebase on origin/${repository.featureBranch}; resolve conflicts autonomously, realigning to that remote branch and redoing the objective if needed, then rerun affected tests. Open the pull request with gh.`,
|
|
22500
22612
|
...reviewerInstruction ? [reviewerInstruction] : [
|
|
22501
|
-
configuration.reviewerHandle ? `Once the pull request exists, reply with its full URL
|
|
22613
|
+
configuration.reviewerHandle ? `Once the pull request exists, reply with its full URL and end the turn; do not tag the reviewer, check, or wait for CI.` : 'Once the pull request exists, reply only with its full URL and end the turn; do not check or wait for CI. On a later checks turn, call pr_checks_status. Merge only when checks="passed", held=false, and approvalPending=false; if checks="unknown", reply in this corner with the tool reason and stop instead of retrying. Only a later explicit human resume clears a hold.',
|
|
22502
22614
|
CORNER_AUTHOR_CONTRACT,
|
|
22503
22615
|
cornerMergeInstruction(configuration.yoloMode, configuration.reviewerHandle)
|
|
22504
22616
|
],
|
|
22505
22617
|
"Do not tag the user when a corner turn finishes: the server posts the merge summary card and its push already cover completion. Tag a human only mid-turn, and only when you need a decision or input.",
|
|
22506
|
-
"Never restate server check or merge notes. On a checks turn, say nothing unless you merge or push a fix, then use one short line. When approval is pending, wait for the
|
|
22618
|
+
"Never restate server check or merge notes. On a checks turn, say nothing unless you merge or push a fix, then use one short line. Never merge while approvalPending is true. When approval is pending, wait for the reviewer to tag you. Never merge another pull request."
|
|
22507
22619
|
] : [
|
|
22508
22620
|
"This is a chat-only corner with no repository or GitHub workflow.",
|
|
22509
22621
|
"Work in this corner's writable workspace. Use write_scratch_file or ordinary tools to create files, then attach_file to send them back to the corner.",
|