beecork 2.5.0 → 2.5.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 +6 -5
- package/dist/index.js +70 -17
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -77,11 +77,12 @@ The agent can delegate an open-ended investigation to a **read-only sub-agent**
|
|
|
77
77
|
(reading, searching, browsing the web) in a separate context and returns just a summary — keeping the
|
|
78
78
|
main conversation clean. It cannot modify anything, run commands, or recurse.
|
|
79
79
|
|
|
80
|
-
###
|
|
80
|
+
### Pinned UI + status line
|
|
81
81
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
82
|
+
On an interactive terminal, beecork pins a persistent input box and a rich status line
|
|
83
|
+
(`mode · model · effort · git branch · ~tokens · background tasks`) to the bottom, with the
|
|
84
|
+
conversation scrolling above (Claude-Code style). Shift+Tab rotates the mode. This is **on by default**;
|
|
85
|
+
opt out with `STATUSLINE=0` to use the classic inline editor. Piped/non-TTY input is unaffected either way.
|
|
85
86
|
|
|
86
87
|
### Skipping permissions (danger)
|
|
87
88
|
|
|
@@ -125,7 +126,7 @@ All variables are read from the real shell environment only (never a project fil
|
|
|
125
126
|
| `VERIFY_COMMAND` | Command auto-run after edits (e.g. `npm run typecheck`) | — |
|
|
126
127
|
| `AUTO_APPROVE` | Headless: skip approval prompts (out-of-root/risky shell are still hard-denied) | off |
|
|
127
128
|
| `BEECORK_DANGEROUSLY_SKIP_PERMISSIONS` | Sandbox-only: skip the whole gate (also `--dangerously-skip-permissions`) | off |
|
|
128
|
-
| `STATUSLINE` / `STATUSLINE_REFRESH_MS` |
|
|
129
|
+
| `STATUSLINE` / `STATUSLINE_REFRESH_MS` | Pinned UI + status bar (set `0` to opt out) · refresh interval | on · `2000` |
|
|
129
130
|
| `NO_UPDATE_NOTIFIER` / `CI` | Disable the "update available" check | off |
|
|
130
131
|
| `MAX_STEPS` | Max tool steps per turn | `50` |
|
|
131
132
|
| `EXEC_TIMEOUT_MS` | `run_bash` timeout | `30000` |
|
package/dist/index.js
CHANGED
|
@@ -114,10 +114,11 @@ 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
|
-
//
|
|
118
|
-
//
|
|
119
|
-
//
|
|
120
|
-
|
|
117
|
+
// Pinned bottom UI: a persistent input box + a rich statusline (mode · model · effort · branch ·
|
|
118
|
+
// ~tokens · bg tasks), the conversation scrolling above. DEFAULT ON for interactive TTYs; opt out
|
|
119
|
+
// with STATUSLINE=0 (falls back to the classic inline editor). Non-TTY (piped/CI) is unaffected
|
|
120
|
+
// either way — chromeEnabled() also requires a TTY.
|
|
121
|
+
statuslineEnabled: !["0", "false", "off", "no"].includes((process.env.STATUSLINE ?? "").trim().toLowerCase()),
|
|
121
122
|
statuslineRefreshMs: num("STATUSLINE_REFRESH_MS", 2e3),
|
|
122
123
|
// bar refresh interval
|
|
123
124
|
// Integrations / modes
|
|
@@ -135,9 +136,10 @@ var config = {
|
|
|
135
136
|
};
|
|
136
137
|
|
|
137
138
|
// src/update.ts
|
|
138
|
-
import { readFile, writeFile, mkdir } from "node:fs/promises";
|
|
139
|
+
import { readFile, writeFile, mkdir, realpath } from "node:fs/promises";
|
|
139
140
|
import { homedir as homedir2 } from "node:os";
|
|
140
|
-
import { join, dirname } from "node:path";
|
|
141
|
+
import { join, dirname, basename, delimiter } from "node:path";
|
|
142
|
+
import { fileURLToPath } from "node:url";
|
|
141
143
|
import { spawn } from "node:child_process";
|
|
142
144
|
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
143
145
|
var cacheFile = () => join(homedir2(), ".beecork", "update-check.json");
|
|
@@ -149,6 +151,48 @@ async function currentVersion() {
|
|
|
149
151
|
return "0.0.0";
|
|
150
152
|
}
|
|
151
153
|
}
|
|
154
|
+
function runningPkgRoot() {
|
|
155
|
+
return fileURLToPath(new URL("..", import.meta.url));
|
|
156
|
+
}
|
|
157
|
+
function prefixFromPkgRoot(pkgRoot) {
|
|
158
|
+
const nm = dirname(pkgRoot);
|
|
159
|
+
if (basename(nm) !== "node_modules") return null;
|
|
160
|
+
const up = dirname(nm);
|
|
161
|
+
return basename(up) === "lib" ? dirname(up) : up;
|
|
162
|
+
}
|
|
163
|
+
function installPrefix() {
|
|
164
|
+
return prefixFromPkgRoot(runningPkgRoot());
|
|
165
|
+
}
|
|
166
|
+
async function findShadowingInstalls() {
|
|
167
|
+
let running;
|
|
168
|
+
try {
|
|
169
|
+
running = await realpath(runningPkgRoot());
|
|
170
|
+
} catch {
|
|
171
|
+
running = runningPkgRoot();
|
|
172
|
+
}
|
|
173
|
+
const names = process.platform === "win32" ? ["beecork.cmd", "beecork"] : ["beecork"];
|
|
174
|
+
const seenRoots = /* @__PURE__ */ new Set([running]);
|
|
175
|
+
const others = [];
|
|
176
|
+
for (const dir of (process.env.PATH ?? "").split(delimiter).filter(Boolean)) {
|
|
177
|
+
for (const name of names) {
|
|
178
|
+
try {
|
|
179
|
+
const bin = join(dir, name);
|
|
180
|
+
const root = dirname(dirname(await realpath(bin)));
|
|
181
|
+
if (seenRoots.has(root)) continue;
|
|
182
|
+
seenRoots.add(root);
|
|
183
|
+
const pkg = JSON.parse(await readFile(join(root, "package.json"), "utf8"));
|
|
184
|
+
if (String(pkg.name) === "beecork") others.push({ bin, version: String(pkg.version ?? "?").replace(/[^\w.+-]/g, "") });
|
|
185
|
+
} catch {
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return others;
|
|
190
|
+
}
|
|
191
|
+
async function shadowWarning() {
|
|
192
|
+
const others = await findShadowingInstalls();
|
|
193
|
+
if (!others.length) return null;
|
|
194
|
+
return "\u26A0 Another beecork is on your PATH and may shadow the version you just installed:\n" + others.map((o) => ` ${o.bin} (v${o.version})`).join("\n") + "\n Remove the stale one(s) so `beecork` always runs the newest install (may need sudo):\n" + others.map((o) => ` rm ${o.bin}`).join("\n");
|
|
195
|
+
}
|
|
152
196
|
function isNewer(a, b) {
|
|
153
197
|
const pa = a.split(".").map((n) => parseInt(n, 10) || 0);
|
|
154
198
|
const pb = b.split(".").map((n) => parseInt(n, 10) || 0);
|
|
@@ -195,7 +239,9 @@ async function checkForUpdate(current) {
|
|
|
195
239
|
function selfUpdate(timeoutMs = 12e4) {
|
|
196
240
|
return new Promise((resolve2) => {
|
|
197
241
|
const npm = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
198
|
-
const
|
|
242
|
+
const prefix = installPrefix();
|
|
243
|
+
const args = ["install", "-g", "beecork@latest", ...prefix ? ["--prefix", prefix] : []];
|
|
244
|
+
const child = spawn(npm, args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
199
245
|
let out3 = "", done = false;
|
|
200
246
|
const finish = (r) => {
|
|
201
247
|
if (done) return;
|
|
@@ -494,8 +540,9 @@ function markLines(width) {
|
|
|
494
540
|
}
|
|
495
541
|
return lines.filter((l) => l.length > 0);
|
|
496
542
|
}
|
|
497
|
-
function printBanner(model, sources) {
|
|
543
|
+
function printBanner(model, version, sources) {
|
|
498
544
|
const safeModel = stripControl(model);
|
|
545
|
+
const safeVersion = stripControl(version);
|
|
499
546
|
const word = [
|
|
500
547
|
" _ _ ",
|
|
501
548
|
" | |__ ___ ___ ___ ___ _ __| | __",
|
|
@@ -527,7 +574,7 @@ function printBanner(model, sources) {
|
|
|
527
574
|
const mem = sources.filter((s) => s.endsWith("memory.md"));
|
|
528
575
|
const cwd = tildify(process.cwd());
|
|
529
576
|
const rows2 = [
|
|
530
|
-
["",
|
|
577
|
+
["", `\u{1F41D} a tiny CLI coding agent \xB7 v${safeVersion}`],
|
|
531
578
|
["dir", cwd],
|
|
532
579
|
["model", safeModel],
|
|
533
580
|
["cork.md", cork.length ? cork.join(", ") : "none"],
|
|
@@ -1307,7 +1354,7 @@ async function runExplorer(task, focus, signal) {
|
|
|
1307
1354
|
|
|
1308
1355
|
// src/safety.ts
|
|
1309
1356
|
import { homedir as homedir3 } from "node:os";
|
|
1310
|
-
import { basename } from "node:path";
|
|
1357
|
+
import { basename as basename2 } from "node:path";
|
|
1311
1358
|
function pathGuard(args) {
|
|
1312
1359
|
const { abs, inRoot } = resolveInRoot(String(args.path ?? "."));
|
|
1313
1360
|
return inRoot ? {} : { needsApproval: true, reason: `path is outside the project root: ${abs}`, cacheKey: `path:${abs}` };
|
|
@@ -1315,7 +1362,7 @@ function pathGuard(args) {
|
|
|
1315
1362
|
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;
|
|
1316
1363
|
function isSecretPath(userPath) {
|
|
1317
1364
|
const { abs } = resolveInRoot(userPath);
|
|
1318
|
-
return SECRET_FILE.test(abs) || SECRET_FILE.test(
|
|
1365
|
+
return SECRET_FILE.test(abs) || SECRET_FILE.test(basename2(abs));
|
|
1319
1366
|
}
|
|
1320
1367
|
function secretGuard(args) {
|
|
1321
1368
|
const p = pathGuard(args);
|
|
@@ -3664,8 +3711,11 @@ async function handleCommand(input, messages) {
|
|
|
3664
3711
|
} else if (cmd === "/update") {
|
|
3665
3712
|
console.log(color.dim("updating beecork\u2026 (npm install -g beecork@latest)"));
|
|
3666
3713
|
const { ok, output } = await selfUpdate();
|
|
3667
|
-
if (ok)
|
|
3668
|
-
|
|
3714
|
+
if (ok) {
|
|
3715
|
+
console.log(color.green("\u2713 updated \u2014 restart beecork to use the new version.") + "\n");
|
|
3716
|
+
const w = await shadowWarning();
|
|
3717
|
+
if (w) console.log(color.yellow(w) + "\n");
|
|
3718
|
+
} else {
|
|
3669
3719
|
console.log(color.red("update failed: ") + output.split("\n").filter(Boolean).slice(-1)[0]);
|
|
3670
3720
|
console.log(color.dim(" run manually: npm install -g beecork (may need sudo / your version manager)") + "\n");
|
|
3671
3721
|
}
|
|
@@ -3835,8 +3885,11 @@ async function main() {
|
|
|
3835
3885
|
if (process.argv[2] === "update") {
|
|
3836
3886
|
console.log("Updating beecork\u2026");
|
|
3837
3887
|
const { ok, output } = await selfUpdate();
|
|
3838
|
-
if (ok)
|
|
3839
|
-
|
|
3888
|
+
if (ok) {
|
|
3889
|
+
console.log(color.green("\u2713 beecork updated. Run `beecork` to use the new version."));
|
|
3890
|
+
const w = await shadowWarning();
|
|
3891
|
+
if (w) console.log("\n" + color.yellow(w));
|
|
3892
|
+
} else {
|
|
3840
3893
|
console.error(color.red("Update failed:") + "\n" + output);
|
|
3841
3894
|
console.error(color.dim("\nTry manually: npm install -g beecork (you may need sudo, or your Node version manager)."));
|
|
3842
3895
|
process.exitCode = 1;
|
|
@@ -3917,12 +3970,12 @@ ${instr.trusted}`;
|
|
|
3917
3970
|
}
|
|
3918
3971
|
const rl = tty ? null : createInterface({ input: process.stdin, output: process.stdout, completer });
|
|
3919
3972
|
if (chromeEnabled()) process.stdout.write(ansi.clearScreen + ansi.clearScrollback + ansi.home);
|
|
3920
|
-
|
|
3973
|
+
const version = await currentVersion();
|
|
3974
|
+
printBanner(state.model, version, instr.sources.map(tildify));
|
|
3921
3975
|
if (config.dangerouslySkipPermissions) {
|
|
3922
3976
|
console.log(color.red("\u26A0 --dangerously-skip-permissions is ON: the approval gate is OFF. Out-of-root paths and risky") + "\n" + color.red(" shell commands will RUN unprompted. Use only in a disposable sandbox. (read-only mode + catastrophic-") + "\n" + color.red(" command refusal still apply.)") + "\n");
|
|
3923
3977
|
}
|
|
3924
3978
|
if (tty) {
|
|
3925
|
-
const version = await currentVersion();
|
|
3926
3979
|
const newer = await checkForUpdate(version);
|
|
3927
3980
|
if (newer) console.log(color.dim(`\u25B8 beecork ${stripControl(newer)} is available (you have ${version}) \u2014 update: npm install -g beecork`) + "\n");
|
|
3928
3981
|
}
|