usebeeline 0.1.17 → 0.1.19
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 +80 -26
- package/package.json +1 -1
package/dist/usebeeline.mjs
CHANGED
|
@@ -16730,26 +16730,26 @@ function staleLeaseResult(value) {
|
|
|
16730
16730
|
return false;
|
|
16731
16731
|
}
|
|
16732
16732
|
}
|
|
16733
|
-
function
|
|
16733
|
+
function resultString(value, key, depth = 0) {
|
|
16734
16734
|
if (depth > 8 || !value)
|
|
16735
16735
|
return void 0;
|
|
16736
16736
|
if (typeof value === "string") {
|
|
16737
16737
|
if (value.length > 1e5 || !value.trimStart().startsWith("{"))
|
|
16738
16738
|
return void 0;
|
|
16739
16739
|
try {
|
|
16740
|
-
return
|
|
16740
|
+
return resultString(JSON.parse(value), key, depth + 1);
|
|
16741
16741
|
} catch {
|
|
16742
16742
|
return void 0;
|
|
16743
16743
|
}
|
|
16744
16744
|
}
|
|
16745
16745
|
if (Array.isArray(value))
|
|
16746
|
-
return value.map((item2) =>
|
|
16746
|
+
return value.map((item2) => resultString(item2, key, depth + 1)).find(Boolean);
|
|
16747
16747
|
if (typeof value !== "object")
|
|
16748
16748
|
return void 0;
|
|
16749
16749
|
const item = value;
|
|
16750
|
-
if (typeof item
|
|
16751
|
-
return item
|
|
16752
|
-
return Object.values(item).map((entry) =>
|
|
16750
|
+
if (typeof item[key] === "string")
|
|
16751
|
+
return item[key];
|
|
16752
|
+
return Object.values(item).map((entry) => resultString(entry, key, depth + 1)).find(Boolean);
|
|
16753
16753
|
}
|
|
16754
16754
|
var SquireTaskRelay = class {
|
|
16755
16755
|
agentId;
|
|
@@ -17040,21 +17040,29 @@ var SquireTaskRelay = class {
|
|
|
17040
17040
|
if (approval) {
|
|
17041
17041
|
const ids = requestedIds.length ? requestedIds : [...task.sessions];
|
|
17042
17042
|
const approvalKey = createHash("sha256").update(approval.approvalId ?? approval.approvalUrl).digest("hex");
|
|
17043
|
-
const status =
|
|
17043
|
+
const status = resultString(result, "status");
|
|
17044
17044
|
const pending = status === "approval_pending" || status === "pending_approval";
|
|
17045
|
-
if (pending && ids.length) {
|
|
17046
|
-
task.pendingApprovals.
|
|
17045
|
+
if (pending && (ids.length || approval.approvalId)) {
|
|
17046
|
+
clearTimeout(task.pendingApprovals.get(approvalKey)?.expiry);
|
|
17047
|
+
const entry = {
|
|
17047
17048
|
requestId: active.requestId,
|
|
17048
17049
|
sessionIds: new Set(ids),
|
|
17049
17050
|
tool: approval.tool,
|
|
17050
17051
|
title: approval.title,
|
|
17051
17052
|
detail: approval.detail
|
|
17052
|
-
}
|
|
17053
|
+
};
|
|
17054
|
+
const expiresAt = Date.parse(resultString(result, "expires_at") ?? "");
|
|
17055
|
+
if (approval.approvalId && Number.isFinite(expiresAt)) {
|
|
17056
|
+
entry.expiry = setTimeout(() => this.expireApproval(task, approvalKey, entry, approval.approvalId), Math.min(Math.max(expiresAt - Date.now(), 0), 2 ** 31 - 1));
|
|
17057
|
+
entry.expiry.unref?.();
|
|
17058
|
+
}
|
|
17059
|
+
task.pendingApprovals.set(approvalKey, entry);
|
|
17053
17060
|
this.log("approval-pending", task, {
|
|
17054
17061
|
tool: safeToolName ?? null,
|
|
17055
17062
|
sessionId: redactedSessionId(ids[0])
|
|
17056
17063
|
});
|
|
17057
17064
|
} else if (!pending) {
|
|
17065
|
+
clearTimeout(task.pendingApprovals.get(approvalKey)?.expiry);
|
|
17058
17066
|
task.pendingApprovals.delete(approvalKey);
|
|
17059
17067
|
}
|
|
17060
17068
|
}
|
|
@@ -17083,12 +17091,35 @@ var SquireTaskRelay = class {
|
|
|
17083
17091
|
}
|
|
17084
17092
|
releasePendingApprovals(task, sessionIdsToRelease) {
|
|
17085
17093
|
for (const [id, approval] of task.pendingApprovals) {
|
|
17094
|
+
if (!approval.sessionIds.size)
|
|
17095
|
+
continue;
|
|
17086
17096
|
for (const sessionId of sessionIdsToRelease)
|
|
17087
17097
|
approval.sessionIds.delete(sessionId);
|
|
17088
|
-
if (!approval.sessionIds.size)
|
|
17098
|
+
if (!approval.sessionIds.size) {
|
|
17099
|
+
clearTimeout(approval.expiry);
|
|
17089
17100
|
task.pendingApprovals.delete(id);
|
|
17101
|
+
}
|
|
17090
17102
|
}
|
|
17091
17103
|
}
|
|
17104
|
+
/**
|
|
17105
|
+
* Squire stops watching an approval at its `expires_at` and sends nothing,
|
|
17106
|
+
* so the relay wakes the asking turn itself with `expired`.
|
|
17107
|
+
*/
|
|
17108
|
+
expireApproval(task, approvalKey, entry, approvalId) {
|
|
17109
|
+
if (task.pendingApprovals.get(approvalKey) !== entry)
|
|
17110
|
+
return;
|
|
17111
|
+
task.pendingApprovals.delete(approvalKey);
|
|
17112
|
+
this.onApprovalDecided({
|
|
17113
|
+
requestId: entry.requestId,
|
|
17114
|
+
approvalId,
|
|
17115
|
+
status: "expired",
|
|
17116
|
+
tool: entry.tool,
|
|
17117
|
+
title: entry.title,
|
|
17118
|
+
detail: entry.detail
|
|
17119
|
+
});
|
|
17120
|
+
if (!this.active && !this.approvalRequestId && !task.pendingApprovals.size)
|
|
17121
|
+
this.scheduleIdle();
|
|
17122
|
+
}
|
|
17092
17123
|
/**
|
|
17093
17124
|
* Squire's own unsolicited decision on an approval this task is still
|
|
17094
17125
|
* holding a connection open for. Matched back to the pending entry by the
|
|
@@ -17108,6 +17139,7 @@ var SquireTaskRelay = class {
|
|
|
17108
17139
|
const pending = task.pendingApprovals.get(approvalKey);
|
|
17109
17140
|
if (!pending)
|
|
17110
17141
|
return;
|
|
17142
|
+
clearTimeout(pending.expiry);
|
|
17111
17143
|
task.pendingApprovals.delete(approvalKey);
|
|
17112
17144
|
this.onApprovalDecided({
|
|
17113
17145
|
requestId: pending.requestId,
|
|
@@ -17990,7 +18022,7 @@ var SERVER_EVENT_KIND_DETAIL = {
|
|
|
17990
18022
|
"check-failed": "fires when a corner's pull request checks turn red",
|
|
17991
18023
|
"merged": "fires when a corner's pull request merges",
|
|
17992
18024
|
"grant-decided": "carries the grant id and status and resumes the turn that asked for the grant",
|
|
17993
|
-
"squire-approval-decided": "carries what was approved or
|
|
18025
|
+
"squire-approval-decided": "carries what was approved, denied, or left to expire and the Squire approval id, and resumes the turn that asked",
|
|
17994
18026
|
"connector-offer-decided": "fires when a human accepts or declines an offered connector, or a reconnect ceremony finishes, and resumes the turn that offered it",
|
|
17995
18027
|
"turn-cancelled": "fires when a running turn is stopped",
|
|
17996
18028
|
"choice-answered": "fires when a human answers a posted choice, starting a new turn for the asking agent",
|
|
@@ -32306,7 +32338,7 @@ Stage | Recorder | Server checks
|
|
|
32306
32338
|
intent, base, tests, docs, lint_types, publication, final_authorization | implementer | current revision/head
|
|
32307
32339
|
review | configured reviewer records the review stage | current revision/head and reviewer identity
|
|
32308
32340
|
ci | implementer | current revision/head; passed requires passing checks
|
|
32309
|
-
The server merge gate is the authority: pr_checks_status reports mergeAllowed true for the current head;
|
|
32341
|
+
The server merge gate is the authority: pr_checks_status reports mergeAllowed true for the current head; merge_corner merges that head. final_authorization grants nothing; do not wait for mergeAllowed.`;
|
|
32310
32342
|
function cornerHasRepositoryWork(brief) {
|
|
32311
32343
|
if (!brief)
|
|
32312
32344
|
return true;
|
|
@@ -32355,7 +32387,8 @@ No unrequested features, flags, compatibility shims or refactors.`;
|
|
|
32355
32387
|
var CORNER_REVIEWER_SESSION_INSTRUCTION = "You are this Room's configured reviewer. The active turn prompt names the latest stable green PR head. Review and approve only that exact head; if no stable green head is named, end the turn without a verdict. Never merge yourself.";
|
|
32356
32388
|
var CORNER_REVIEWER_UNSTABLE_HEAD_INSTRUCTION = "There is no stable green PR head for this active reviewer turn. Do not review or call approve_merge. End this turn without a verdict; the next green transition will wake you.";
|
|
32357
32389
|
var CORNER_DELIVERY_NUDGE = "Only when the brief calls for repository changes, inspect the repository state and finish delivering the work unless a human hold stands: 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 brief; 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. Otherwise do not commit, push or open a PR; deliver with post_artifact.";
|
|
32358
|
-
var
|
|
32390
|
+
var CORNER_LAND_RULE = "Then, if a human's question or proposal in the corner has no answer, name it and do not merge; otherwise call merge_corner.";
|
|
32391
|
+
var CORNER_YOLO_MERGE_NUDGE = `Yolo is on. Call pr_checks_status now. If checks="failed", fix the failure and push. If checks="unknown", reply in this corner with the tool reason and stop instead of retrying. Otherwise stop: a reviewer's PASS wakes you to merge with merge_corner. Never merge it any other way.`;
|
|
32359
32392
|
var UPGRADE_INTENT_RULE = "Call this on your own judgment when the work in this corner needs the repository; nobody has to ask. Call it while answering a human message in this corner, then write the brief in the restarted code session.";
|
|
32360
32393
|
var CORNER_PLACEHOLDER_BRIEF_RULE = "This brief is the placeholder the upgrade wrote from the request. Read the code, write the real spec with revise_corner_brief, then post it in this corner and ask the corner's opener to approve it before editing. This is best effort: if the opener is away or the request was already explicit, use your judgment and proceed. When the opener replies, record their reply as the approval in the next revision.";
|
|
32361
32394
|
function isPlaceholderCornerBrief(brief) {
|
|
@@ -32366,7 +32399,7 @@ function cornerMergeInstruction(yoloMode, reviewerHandle) {
|
|
|
32366
32399
|
if (!reviewerHandle)
|
|
32367
32400
|
return "Once the pull request exists, reply with its full URL and end the turn; do not check or wait for CI. This Room has no configured reviewer, so the merge gate never opens for you: never merge; a person merges it.";
|
|
32368
32401
|
const reviewer = `the reviewer (${handle(reviewerHandle)})`;
|
|
32369
|
-
return yoloMode ? `Once the pull request exists, reply with its full URL and end the turn; do not tag ${reviewer}, check, or wait for CI. Green checks wake ${reviewer};
|
|
32402
|
+
return yoloMode ? `Once the pull request exists, reply with its full URL and end the turn; do not tag ${reviewer}, check, or wait for CI. Green checks wake ${reviewer}; its PASS wakes you to merge. ${CORNER_LAND_RULE} You are also woken to fix failing checks, requested changes, or a refused merge; a fixed head needs green checks and a fresh PASS.` : `Once the pull request exists, reply with its full URL and end the turn; do not tag ${reviewer}, check, or wait for CI. Yolo is off, so the merge gate stays closed for you: never merge; a person merges it after ${reviewer} approves.`;
|
|
32370
32403
|
}
|
|
32371
32404
|
function cornerReviewerInstruction(input) {
|
|
32372
32405
|
if (!input.isReviewer || input.openedByAgent)
|
|
@@ -32374,12 +32407,12 @@ function cornerReviewerInstruction(input) {
|
|
|
32374
32407
|
const author = input.authorHandle ? handle(input.authorHandle) : "author";
|
|
32375
32408
|
const number = input.pullRequestNumber ?? "N";
|
|
32376
32409
|
const headSha = input.headSha ?? "<head sha>";
|
|
32377
|
-
return `Checks are green on PR #${number} at ${headSha}${input.briefRevision ? ` with assigned brief revision ${input.briefRevision}` : ""}. Review it now with the beeline-review skill against that exact head and current assigned brief. FAIL: call record_validation_stage with stage "review", status "failed", and headSha ${headSha}, then reply \`@${author}\` with the confirmed findings and the reviewed head ${headSha} to fix. PASS: call the approve_merge tool for ${headSha}${input.briefRevision ? ` with briefRevision=${input.briefRevision}` : ""}, then reply \`approved ${headSha}\` without tagging ${author}: the
|
|
32410
|
+
return `Checks are green on PR #${number} at ${headSha}${input.briefRevision ? ` with assigned brief revision ${input.briefRevision}` : ""}. Review it now with the beeline-review skill against that exact head and current assigned brief. FAIL: call record_validation_stage with stage "review", status "failed", and headSha ${headSha}, then reply \`@${author}\` with the confirmed findings and the reviewed head ${headSha} to fix. PASS: call the approve_merge tool for ${headSha}${input.briefRevision ? ` with briefRevision=${input.briefRevision}` : ""}, then reply \`approved ${headSha}\` without tagging ${author}: your PASS wakes the author to merge, so a tag adds nothing. A human's question or proposal in the corner discussion with no answer is a FAIL finding; name it. Never merge yourself or tell the author to merge. Never say you are holding or waiting for checks.`;
|
|
32378
32411
|
}
|
|
32379
32412
|
function cornerSelfReviewerInstruction(input) {
|
|
32380
32413
|
if (!input.isReviewer || !input.openedByAgent)
|
|
32381
32414
|
return void 0;
|
|
32382
|
-
return "Once the pull request exists, reply with its full URL and end the turn. You are this Room's reviewer, so
|
|
32415
|
+
return "Once the pull request exists, reply with its full URL and end the turn. You are this Room's reviewer, so no other agent can review your pull request: do not request one or tag any agent for review. It merges only on a human's yes: ask a Workspace owner or admin to approve the merge, then record their yes with order_corner_merge. Never merge it any other way. You are woken to fix failing checks or a merge GitHub refused.";
|
|
32383
32416
|
}
|
|
32384
32417
|
function shellLine(shell) {
|
|
32385
32418
|
if (!shell)
|
|
@@ -32730,6 +32763,16 @@ var TURN_SECTIONS = [
|
|
|
32730
32763
|
when: ({ task }) => task.commandReason !== "schedule" && (["corner_check", "corner_merge_refused", "corner_merge_conflict"].includes(task.commandReason ?? "") || ["check-passed", "check-failed"].includes(task.outsideEvent?.kind ?? "")),
|
|
32731
32764
|
render: () => 'This is a checks turn about CI or the merge gate. On it, say nothing unless you push a fix or report checks="unknown", and then use one short line. Never restate server check or merge notes.'
|
|
32732
32765
|
},
|
|
32766
|
+
{
|
|
32767
|
+
id: "turn.land",
|
|
32768
|
+
topic: "land-turn",
|
|
32769
|
+
why: "A reviewer's PASS hands the merge to the implementer, who must not merge over an unanswered human question.",
|
|
32770
|
+
budgetBytes: 300,
|
|
32771
|
+
layer: "turn",
|
|
32772
|
+
surfaces: ["code-corner"],
|
|
32773
|
+
when: ({ task }) => task.commandReason === "corner_land",
|
|
32774
|
+
render: () => `The reviewer approved this pull request's current head. ${CORNER_LAND_RULE}`
|
|
32775
|
+
},
|
|
32733
32776
|
{
|
|
32734
32777
|
id: "turn.objective",
|
|
32735
32778
|
topic: "objective",
|
|
@@ -32951,7 +32994,7 @@ Keys belong to the human who provisioned them. Your owner's keys serve whoever a
|
|
|
32951
32994
|
|
|
32952
32995
|
## Connect an app
|
|
32953
32996
|
|
|
32954
|
-
When a request needs an app or service, call beeline-agent \`workbench_status\` first. For a connected app, use its ID with \`list_app_tools\`, then call \`execute_app_tool\` with the selected tool slug and arguments. The server executes against that person\u2019s account and decides permission on every call. If tool discovery reports an error, follow its cause; \`needs_connection\` means the account must be reconnected, and \`needs_permission\` means wait for the connected person's decision. Do not switch paths after denial or provider unavailability. No app token, provider key, or sign-in URL belongs in chat or a model prompt.
|
|
32997
|
+
When a request needs an app or service, call beeline-agent \`workbench_status\` first. For a connected app via composio, use its ID with \`list_app_tools\`, then call \`execute_app_tool\` with the selected tool slug and arguments. For an app via squire-api, call its API with \`use_credential\` (service = the app key); via squire-browser, use the \`operate_*\` tools; via registry-mcp, use its mounted MCP tools. The server executes against that person\u2019s account and decides permission on every call. If tool discovery reports an error, follow its cause; \`needs_connection\` means the account must be reconnected, and \`needs_permission\` means wait for the connected person's decision. Do not switch paths after denial or provider unavailability. No app token, provider key, or sign-in URL belongs in chat or a model prompt.
|
|
32955
32998
|
|
|
32956
32999
|
For an app that is not connected, call \`connect_app\` with its name, one short reason, and a request-specific \`continuation\`: one sentence stating what you will do right after sign-in. Do not include a link, credential, account identifier, or private data in that sentence. The server chooses the route and returns \`next\`. In a corner, call it from that corner so the sign-in card and connection wake return there. A managed OAuth app presents a sign-in card to its owner; end the turn and wait for the connection wake. If the provider reports managed OAuth unsupported, follow the server's Squire route and its instructions. A provider outage is unavailable, not permission to change routes. After the person connects, read Workbench again and use the app ID. Every use is authorized as \`app:<key>\` and recorded once.
|
|
32957
33000
|
|
|
@@ -33075,7 +33118,8 @@ Then take exactly one action:
|
|
|
33075
33118
|
|
|
33076
33119
|
- FAIL: call \`record_validation_stage\` with stage \`review\`, status \`failed\`, and the reviewed head SHA, then reply \`@author\` with the confirmed findings and that reviewed head SHA to fix. The recorded review stage is how an implementer who has already fixed the findings can tell whether the review is stale.
|
|
33077
33120
|
- PASS: call \`approve_merge\` with the reviewed head SHA and assigned briefRevision (omit the revision only for a legacy corner without a brief), then reply \`approved <reviewed sha>\` without tagging the author. Do not tell the author to merge.
|
|
33078
|
-
-
|
|
33121
|
+
- A human's question or proposal in the corner discussion with no answer is a blocking finding: FAIL and name it.
|
|
33122
|
+
- Approving is your last step as reviewer. Your PASS wakes the author, who merges that exact head with \`merge_corner\` once checks are green, the worker's yolo is on, and no human hold stands. You never merge it yourself.
|
|
33079
33123
|
`;
|
|
33080
33124
|
}
|
|
33081
33125
|
function beelineSpecSkillMarkdown(releaseId) {
|
|
@@ -42375,7 +42419,8 @@ function resumePrompt(item) {
|
|
|
42375
42419
|
`This is Trusty Squire's answer to the approval you were waiting on: ${item.body}.`,
|
|
42376
42420
|
"Your paused work resumes now.",
|
|
42377
42421
|
"If it was approved, continue exactly where you left off with Trusty Squire; do not ask the person to approve again, and do not restart the task.",
|
|
42378
|
-
"If it was denied, stop that Trusty Squire action and say plainly what you cannot do."
|
|
42422
|
+
"If it was denied, stop that Trusty Squire action and say plainly what you cannot do.",
|
|
42423
|
+
"If it got no answer, the approval expired; say so plainly, and ask again only if the person still wants it."
|
|
42379
42424
|
].join(" ");
|
|
42380
42425
|
}
|
|
42381
42426
|
if (item.systemEvent?.kind === "connector-offer-decided") {
|
|
@@ -43695,14 +43740,17 @@ function cornerGitHubCommandRefusal(launcher, argv, featureBranch, targetBranch,
|
|
|
43695
43740
|
return { refused: true };
|
|
43696
43741
|
const separator = raw.indexOf(":");
|
|
43697
43742
|
const source = separator >= 0 ? raw.slice(0, separator) : raw;
|
|
43698
|
-
const
|
|
43743
|
+
const explicitDestination = separator >= 0 ? raw.slice(separator + 1) : void 0;
|
|
43699
43744
|
if (!source || source === ":" || /(?:^|\/)refs\/tags\//.test(source))
|
|
43700
43745
|
return { refused: true };
|
|
43701
|
-
const resolved = resolvePushBranch(source
|
|
43746
|
+
const resolved = resolvePushBranch(source);
|
|
43702
43747
|
if (resolved.tag)
|
|
43703
43748
|
return { refused: true };
|
|
43704
|
-
const branch =
|
|
43705
|
-
return {
|
|
43749
|
+
const branch = explicitDestination ? branchName(explicitDestination) : resolved.branch ? branchName(resolved.branch) : void 0;
|
|
43750
|
+
return {
|
|
43751
|
+
branch,
|
|
43752
|
+
refused: explicitDestination !== void 0 && explicitDestination.startsWith("refs/tags/")
|
|
43753
|
+
};
|
|
43706
43754
|
}) : [resolvePushBranch()];
|
|
43707
43755
|
if (destinations.some((destination) => "refused" in destination && destination.refused === true || !destination.branch || branchName(destination.branch) !== featureBranch || branchName(destination.branch) === targetBranch))
|
|
43708
43756
|
return refusal;
|
|
@@ -43731,6 +43779,12 @@ const gitContext = (() => {
|
|
|
43731
43779
|
})();
|
|
43732
43780
|
function git(args, options) { return spawnSync(config.gitCommand, gitContext.concat(args), options); }
|
|
43733
43781
|
function resolvePushBranch(source) {
|
|
43782
|
+
if (source === 'HEAD') {
|
|
43783
|
+
// git push origin HEAD targets the branch checked out now; read it
|
|
43784
|
+
// directly and fail closed in a detached HEAD.
|
|
43785
|
+
const current = git(['symbolic-ref', '--short', 'HEAD'], { encoding: 'utf8' });
|
|
43786
|
+
return current.status === 0 ? { branch: current.stdout.trim() } : {};
|
|
43787
|
+
}
|
|
43734
43788
|
if (source) {
|
|
43735
43789
|
const tag = git(['show-ref', '--verify', '--quiet', 'refs/tags/' + source], { stdio: 'ignore' }).status === 0;
|
|
43736
43790
|
return { branch: source, tag };
|
|
@@ -44462,7 +44516,7 @@ function filePaths(value, worktreePath) {
|
|
|
44462
44516
|
visit(value);
|
|
44463
44517
|
return [...paths];
|
|
44464
44518
|
}
|
|
44465
|
-
function
|
|
44519
|
+
function resultStatus(call) {
|
|
44466
44520
|
const content = record4(call.content) ?? (typeof call.content === "string" ? (() => {
|
|
44467
44521
|
try {
|
|
44468
44522
|
return record4(JSON.parse(call.content));
|
|
@@ -44523,7 +44577,7 @@ async function cornerToolActivity(call, worktreePath, requestedBy) {
|
|
|
44523
44577
|
kind: "tool",
|
|
44524
44578
|
title: title.slice(0, 240),
|
|
44525
44579
|
operation: operation.slice(0, 80),
|
|
44526
|
-
status:
|
|
44580
|
+
status: resultStatus(call),
|
|
44527
44581
|
...argumentsSummary,
|
|
44528
44582
|
...output ? { output } : {},
|
|
44529
44583
|
...requestedBy ? { requestedBy } : {},
|