beecork 2.4.1 → 2.4.2
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/README.md +3 -2
- package/dist/index.js +27 -18
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -79,8 +79,9 @@ main conversation clean. It cannot modify anything, run commands, or recurse.
|
|
|
79
79
|
|
|
80
80
|
### Status line
|
|
81
81
|
|
|
82
|
-
|
|
83
|
-
|
|
82
|
+
An optional bar on the terminal's bottom row shows `model · effort · git branch · ~tokens · background
|
|
83
|
+
tasks`. It's **off by default** while a proper pinned-input version is built; opt into the interim one
|
|
84
|
+
with `STATUSLINE=1`.
|
|
84
85
|
|
|
85
86
|
### Skipping permissions (danger)
|
|
86
87
|
|
package/dist/index.js
CHANGED
|
@@ -114,9 +114,10 @@ var config = {
|
|
|
114
114
|
// Sub-agent (explore tool)
|
|
115
115
|
subAgentMaxSteps: num("SUBAGENT_MAX_STEPS", 15),
|
|
116
116
|
// child explorer's step budget (bounds cost/latency)
|
|
117
|
-
// Live status line (bottom row: model · effort · git branch · ~tokens · bg tasks)
|
|
118
|
-
|
|
119
|
-
//
|
|
117
|
+
// Live status line (bottom row: model · effort · git branch · ~tokens · bg tasks). DEFAULT OFF —
|
|
118
|
+
// the interim scroll-region version clashes with the inline input (banner loss / flicker); it's
|
|
119
|
+
// being replaced by a proper pinned-input UI. Opt in with STATUSLINE=1.
|
|
120
|
+
statuslineEnabled: ["1", "true", "on", "yes"].includes((process.env.STATUSLINE ?? "").trim().toLowerCase()),
|
|
120
121
|
statuslineRefreshMs: num("STATUSLINE_REFRESH_MS", 2e3),
|
|
121
122
|
// bar refresh interval
|
|
122
123
|
// Integrations / modes
|
|
@@ -1249,7 +1250,7 @@ import { homedir as homedir3 } from "node:os";
|
|
|
1249
1250
|
import { basename } from "node:path";
|
|
1250
1251
|
function pathGuard(args) {
|
|
1251
1252
|
const { abs, inRoot } = resolveInRoot(String(args.path ?? "."));
|
|
1252
|
-
return inRoot ? {} : { needsApproval: true, reason: `path is outside the project root: ${abs}` };
|
|
1253
|
+
return inRoot ? {} : { needsApproval: true, reason: `path is outside the project root: ${abs}`, cacheKey: `path:${abs}` };
|
|
1253
1254
|
}
|
|
1254
1255
|
var SECRET_FILE = /(^|\/)(\.env(\.[\w.-]+)?|[\w.-]*\.(env|pem|key|secret|pfx|p12|jks|keystore)|id_(rsa|ed25519|ecdsa|dsa)|credentials|\.git-credentials|\.pgpass|\.npmrc|\.netrc)$/i;
|
|
1255
1256
|
function isSecretPath(userPath) {
|
|
@@ -2388,7 +2389,7 @@ async function callModel(messages, includeTools = true, signal, opts) {
|
|
|
2388
2389
|
stopSpinner();
|
|
2389
2390
|
if (!quiet) {
|
|
2390
2391
|
if (!printedText) {
|
|
2391
|
-
process.stdout.write("\n" + color.cyan("bee: "));
|
|
2392
|
+
process.stdout.write((printedReasoning ? "\n\n" : "\n") + color.cyan("bee: "));
|
|
2392
2393
|
printedText = true;
|
|
2393
2394
|
}
|
|
2394
2395
|
const safe = stripControl(ev.content);
|
|
@@ -2796,7 +2797,7 @@ var SYSTEM_PROMPT = `You are beecork, a coding assistant working in a terminal o
|
|
|
2796
2797
|
# Safety
|
|
2797
2798
|
- Be careful with anything that deletes or overwrites. Don't do destructive things unless the user clearly asked.
|
|
2798
2799
|
- Don't commit or push to git, publish, deploy, or take other outward or hard-to-undo actions unless the user explicitly asked.`;
|
|
2799
|
-
async function askApproval(ask, call, reason) {
|
|
2800
|
+
async function askApproval(ask, call, reason, offerAlways = true) {
|
|
2800
2801
|
let args = {};
|
|
2801
2802
|
try {
|
|
2802
2803
|
args = JSON.parse(call.function.arguments);
|
|
@@ -2818,8 +2819,9 @@ async function askApproval(ask, call, reason) {
|
|
|
2818
2819
|
} else {
|
|
2819
2820
|
console.log(color.yellow(` ${stripControl(call.function.arguments)}`));
|
|
2820
2821
|
}
|
|
2821
|
-
const
|
|
2822
|
-
|
|
2822
|
+
const prompt = offerAlways ? " allow? [y]es / [n]o / [a]lways: " : " allow? [y]es / [n]o: ";
|
|
2823
|
+
const answer = (await ask(color.yellow(prompt))).trim().toLowerCase();
|
|
2824
|
+
if (offerAlways && (answer === "a" || answer === "always")) return "always";
|
|
2823
2825
|
if (answer === "y" || answer === "yes") return "once";
|
|
2824
2826
|
return "deny";
|
|
2825
2827
|
}
|
|
@@ -2830,8 +2832,9 @@ function decideApproval(tool, args, ctx) {
|
|
|
2830
2832
|
if (ctx.dangerouslySkip) return { action: "run" };
|
|
2831
2833
|
const guard = tool?.guard?.(args);
|
|
2832
2834
|
if (guard?.needsApproval) {
|
|
2835
|
+
if (guard.cacheKey && ctx.approvedGuardKeys?.has(guard.cacheKey)) return { action: "run" };
|
|
2833
2836
|
if (ctx.autoApprove) return { action: "deny", kind: "headless", reason: guard.reason ?? "blocked" };
|
|
2834
|
-
return { action: "ask", cacheable: false, reason: guard.reason };
|
|
2837
|
+
return guard.cacheKey ? { action: "ask", cacheable: true, reason: guard.reason, guardKey: guard.cacheKey } : { action: "ask", cacheable: false, reason: guard.reason };
|
|
2835
2838
|
}
|
|
2836
2839
|
if (tool?.needsApproval && !ctx.autoApprove && ctx.mode !== "auto") {
|
|
2837
2840
|
if (tool.alwaysAsk) return { action: "ask", cacheable: false };
|
|
@@ -2867,7 +2870,7 @@ async function handleAskUser(args) {
|
|
|
2867
2870
|
return askUserMessage(question, choice, true);
|
|
2868
2871
|
}
|
|
2869
2872
|
async function handleToolCall(call, messages, step, deps) {
|
|
2870
|
-
const { approvedTools, callCounts, ask, signal } = deps;
|
|
2873
|
+
const { approvedTools, approvedGuardKeys, callCounts, ask, signal } = deps;
|
|
2871
2874
|
const pushTool = (content) => messages.push({ role: "tool", tool_call_id: call.id, content });
|
|
2872
2875
|
const sig = `${call.function.name}:${call.function.arguments}`;
|
|
2873
2876
|
const seen = (callCounts.get(sig) ?? 0) + 1;
|
|
@@ -2892,6 +2895,7 @@ async function handleToolCall(call, messages, step, deps) {
|
|
|
2892
2895
|
mode: state.mode,
|
|
2893
2896
|
autoApprove: config.autoApprove,
|
|
2894
2897
|
approvedTools,
|
|
2898
|
+
approvedGuardKeys,
|
|
2895
2899
|
toolName: call.function.name,
|
|
2896
2900
|
dangerouslySkip: config.dangerouslySkipPermissions
|
|
2897
2901
|
});
|
|
@@ -2906,15 +2910,19 @@ async function handleToolCall(call, messages, step, deps) {
|
|
|
2906
2910
|
return;
|
|
2907
2911
|
}
|
|
2908
2912
|
if (decision.action === "ask") {
|
|
2909
|
-
const answer = await askApproval(ask, call, decision.
|
|
2913
|
+
const answer = await askApproval(ask, call, decision.reason, decision.cacheable);
|
|
2910
2914
|
if (answer === "deny") {
|
|
2911
2915
|
console.log(color.red(" \u21B3 denied") + "\n");
|
|
2912
|
-
pushTool(decision.
|
|
2916
|
+
pushTool(decision.reason ? `The user DENIED this (${decision.reason}). Do not retry, and do not route around it with run_bash/cat or another tool.` : "The user DENIED permission to run this tool. Do not retry it.");
|
|
2913
2917
|
return;
|
|
2914
2918
|
}
|
|
2915
|
-
if (
|
|
2916
|
-
|
|
2917
|
-
|
|
2919
|
+
if (answer === "always" && decision.cacheable) {
|
|
2920
|
+
if (decision.guardKey) {
|
|
2921
|
+
approvedGuardKeys.add(decision.guardKey);
|
|
2922
|
+
} else {
|
|
2923
|
+
approvedTools.add(call.function.name);
|
|
2924
|
+
void addProjectApproval(call.function.name);
|
|
2925
|
+
}
|
|
2918
2926
|
}
|
|
2919
2927
|
}
|
|
2920
2928
|
if (config.traceFile) trace.push({ tool: call.function.name, args: call.function.arguments, step });
|
|
@@ -2970,13 +2978,13 @@ ${content}` }];
|
|
|
2970
2978
|
}
|
|
2971
2979
|
return [...messages, { role: "user", content }];
|
|
2972
2980
|
}
|
|
2973
|
-
async function runTurn(messages, userInput, ask, approvedTools, signal, steering) {
|
|
2981
|
+
async function runTurn(messages, userInput, ask, approvedTools, approvedGuardKeys, signal, steering) {
|
|
2974
2982
|
messages.push({ role: "user", content: userInput });
|
|
2975
2983
|
const snapshot = messages.slice();
|
|
2976
2984
|
try {
|
|
2977
2985
|
let answered = false;
|
|
2978
2986
|
const callCounts = /* @__PURE__ */ new Map();
|
|
2979
|
-
const deps = { approvedTools, callCounts, ask, signal };
|
|
2987
|
+
const deps = { approvedTools, approvedGuardKeys, callCounts, ask, signal };
|
|
2980
2988
|
for (let step = 0; step < config.maxSteps && !answered && !signal?.aborted; step++) {
|
|
2981
2989
|
try {
|
|
2982
2990
|
messages = await compactIfNeeded(messages, signal);
|
|
@@ -3469,6 +3477,7 @@ ${instr.trusted}`;
|
|
|
3469
3477
|
}
|
|
3470
3478
|
let messages = [{ role: "system", content: systemContent }];
|
|
3471
3479
|
const approvedTools = /* @__PURE__ */ new Set();
|
|
3480
|
+
const approvedGuardKeys = /* @__PURE__ */ new Set();
|
|
3472
3481
|
for (const t of settings.alwaysAllow) approvedTools.add(t);
|
|
3473
3482
|
for (const t of projectApprovals) approvedTools.add(t);
|
|
3474
3483
|
let saved = false;
|
|
@@ -3641,7 +3650,7 @@ ${instr.trusted}`;
|
|
|
3641
3650
|
}) : () => {
|
|
3642
3651
|
};
|
|
3643
3652
|
try {
|
|
3644
|
-
messages = await runTurn(messages, userInput, ask, approvedTools, activeTurn.signal, steering);
|
|
3653
|
+
messages = await runTurn(messages, userInput, ask, approvedTools, approvedGuardKeys, activeTurn.signal, steering);
|
|
3645
3654
|
} finally {
|
|
3646
3655
|
restoreKeys();
|
|
3647
3656
|
setSteeringActive(false);
|