gearbox-code 0.1.10 → 0.1.11
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/cli.mjs +405 -17
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -70313,7 +70313,7 @@ var import_react21 = __toESM(require_react(), 1);
|
|
|
70313
70313
|
import { createInterface } from "node:readline/promises";
|
|
70314
70314
|
import { execFileSync as execFileSync4, spawnSync } from "node:child_process";
|
|
70315
70315
|
import { resolve as resolve11 } from "node:path";
|
|
70316
|
-
import { existsSync as
|
|
70316
|
+
import { existsSync as existsSync10 } from "node:fs";
|
|
70317
70317
|
|
|
70318
70318
|
// src/ui/App.tsx
|
|
70319
70319
|
var import_react26 = __toESM(require_react(), 1);
|
|
@@ -132189,6 +132189,70 @@ async function runShellStream(command, opts = {}) {
|
|
|
132189
132189
|
|
|
132190
132190
|
// src/tools.ts
|
|
132191
132191
|
init_proc();
|
|
132192
|
+
|
|
132193
|
+
// src/fetch.ts
|
|
132194
|
+
var MAX_FETCH_CHARS = 80000;
|
|
132195
|
+
var MAX_RETURN_CHARS = 20000;
|
|
132196
|
+
var ENTITY = {
|
|
132197
|
+
amp: "&",
|
|
132198
|
+
lt: "<",
|
|
132199
|
+
gt: ">",
|
|
132200
|
+
quot: '"',
|
|
132201
|
+
apos: "'",
|
|
132202
|
+
nbsp: " "
|
|
132203
|
+
};
|
|
132204
|
+
function urlsInText(text2, limit = 2) {
|
|
132205
|
+
const out = [];
|
|
132206
|
+
const re = /\bhttps?:\/\/[^\s<>"')\]]+/gi;
|
|
132207
|
+
for (const m2 of text2.matchAll(re)) {
|
|
132208
|
+
const url2 = m2[0].replace(/[.,;:!?]+$/, "");
|
|
132209
|
+
if (!out.includes(url2))
|
|
132210
|
+
out.push(url2);
|
|
132211
|
+
if (out.length >= limit)
|
|
132212
|
+
break;
|
|
132213
|
+
}
|
|
132214
|
+
return out;
|
|
132215
|
+
}
|
|
132216
|
+
function decodeEntities(text2) {
|
|
132217
|
+
return text2.replace(/&(#x?[0-9a-f]+|[a-z]+);/gi, (_, raw) => {
|
|
132218
|
+
const key = raw.toLowerCase();
|
|
132219
|
+
if (key[0] === "#") {
|
|
132220
|
+
const n = key[1] === "x" ? Number.parseInt(key.slice(2), 16) : Number.parseInt(key.slice(1), 10);
|
|
132221
|
+
return Number.isFinite(n) ? String.fromCodePoint(n) : "";
|
|
132222
|
+
}
|
|
132223
|
+
return ENTITY[key] ?? "";
|
|
132224
|
+
});
|
|
132225
|
+
}
|
|
132226
|
+
function stripHtml(html2) {
|
|
132227
|
+
return decodeEntities(html2.replace(/<script\b[\s\S]*?<\/script>/gi, " ").replace(/<style\b[\s\S]*?<\/style>/gi, " ").replace(/<noscript\b[\s\S]*?<\/noscript>/gi, " ").replace(/<\/(p|div|section|article|header|footer|li|tr|h[1-6])>/gi, `
|
|
132228
|
+
`).replace(/<br\s*\/?>/gi, `
|
|
132229
|
+
`).replace(/<[^>]+>/g, " ").replace(/[ \t]+\n/g, `
|
|
132230
|
+
`).replace(/\n{3,}/g, `
|
|
132231
|
+
|
|
132232
|
+
`).replace(/[ \t]{2,}/g, " ").trim());
|
|
132233
|
+
}
|
|
132234
|
+
async function fetchUrlText(url2) {
|
|
132235
|
+
const u = new URL(url2);
|
|
132236
|
+
if (u.protocol !== "http:" && u.protocol !== "https:")
|
|
132237
|
+
throw new Error("only http(s) URLs are supported");
|
|
132238
|
+
const res = await fetch(u, {
|
|
132239
|
+
headers: {
|
|
132240
|
+
"user-agent": "Gearbox/0.1 (+https://github.com/AnayGarodia/gearbox)",
|
|
132241
|
+
accept: "text/html,text/plain,application/json;q=0.8,*/*;q=0.2"
|
|
132242
|
+
}
|
|
132243
|
+
});
|
|
132244
|
+
if (!res.ok)
|
|
132245
|
+
throw new Error(`fetch failed: HTTP ${res.status}`);
|
|
132246
|
+
const raw = (await res.text()).slice(0, MAX_FETCH_CHARS);
|
|
132247
|
+
const contentType = res.headers.get("content-type") ?? "";
|
|
132248
|
+
const title = raw.match(/<title[^>]*>([\s\S]*?)<\/title>/i)?.[1]?.replace(/\s+/g, " ").trim();
|
|
132249
|
+
const text2 = (/html/i.test(contentType) || /<html|<body|<p\b|<div\b/i.test(raw) ? stripHtml(raw) : raw.trim()).slice(0, MAX_RETURN_CHARS);
|
|
132250
|
+
if (!text2)
|
|
132251
|
+
throw new Error("fetched URL had no readable text");
|
|
132252
|
+
return { url: u.toString(), title: title ? decodeEntities(title) : undefined, text: text2, chars: text2.length };
|
|
132253
|
+
}
|
|
132254
|
+
|
|
132255
|
+
// src/tools.ts
|
|
132192
132256
|
var ROOT = process.cwd();
|
|
132193
132257
|
var CAP2 = 60000;
|
|
132194
132258
|
var DENIED = "Permission denied by the user — they declined this action.";
|
|
@@ -132202,6 +132266,44 @@ function safe(path) {
|
|
|
132202
132266
|
}
|
|
132203
132267
|
var clip2 = (s2) => s2.length > CAP2 ? s2.slice(0, CAP2) + `
|
|
132204
132268
|
… [clipped ${s2.length - CAP2} chars]` : s2;
|
|
132269
|
+
function countOccurrences(text2, find2) {
|
|
132270
|
+
if (!find2)
|
|
132271
|
+
return 0;
|
|
132272
|
+
let count = 0;
|
|
132273
|
+
let at3 = 0;
|
|
132274
|
+
while ((at3 = text2.indexOf(find2, at3)) >= 0) {
|
|
132275
|
+
count++;
|
|
132276
|
+
at3 += find2.length;
|
|
132277
|
+
}
|
|
132278
|
+
return count;
|
|
132279
|
+
}
|
|
132280
|
+
function replaceOccurrence(text2, find2, replace2, occurrence) {
|
|
132281
|
+
let at3 = -1;
|
|
132282
|
+
let from = 0;
|
|
132283
|
+
for (let i2 = 0;i2 < occurrence; i2++) {
|
|
132284
|
+
at3 = text2.indexOf(find2, from);
|
|
132285
|
+
if (at3 < 0)
|
|
132286
|
+
return text2;
|
|
132287
|
+
from = at3 + find2.length;
|
|
132288
|
+
}
|
|
132289
|
+
return text2.slice(0, at3) + replace2 + text2.slice(at3 + find2.length);
|
|
132290
|
+
}
|
|
132291
|
+
function notFoundHint(path, before2, find2) {
|
|
132292
|
+
const needle = find2.trim().split(/\s+/).filter((w) => w.length >= 3)[0]?.toLowerCase();
|
|
132293
|
+
if (!needle)
|
|
132294
|
+
return `text not found in ${path}`;
|
|
132295
|
+
const lines = before2.split(`
|
|
132296
|
+
`);
|
|
132297
|
+
const hit = lines.findIndex((l) => l.toLowerCase().includes(needle));
|
|
132298
|
+
if (hit < 0)
|
|
132299
|
+
return `text not found in ${path}`;
|
|
132300
|
+
const start = Math.max(0, hit - 2);
|
|
132301
|
+
const end = Math.min(lines.length, hit + 3);
|
|
132302
|
+
const snippet = lines.slice(start, end).map((l, i2) => `${start + i2 + 1}: ${l}`).join(`
|
|
132303
|
+
`);
|
|
132304
|
+
return `text not found in ${path}. Nearby match for "${needle}":
|
|
132305
|
+
${snippet}`;
|
|
132306
|
+
}
|
|
132205
132307
|
function createTools(onEvent) {
|
|
132206
132308
|
return {
|
|
132207
132309
|
read_file: tool5({
|
|
@@ -132224,19 +132326,38 @@ function createTools(onEvent) {
|
|
|
132224
132326
|
}
|
|
132225
132327
|
}),
|
|
132226
132328
|
edit_file: tool5({
|
|
132227
|
-
description: "
|
|
132228
|
-
inputSchema: exports_external2.object({
|
|
132229
|
-
|
|
132329
|
+
description: "Edit a file by exact text replacement. Use occurrence for a specific match, or replaceAll for every exact match.",
|
|
132330
|
+
inputSchema: exports_external2.object({
|
|
132331
|
+
path: exports_external2.string(),
|
|
132332
|
+
find: exports_external2.string().min(1),
|
|
132333
|
+
replace: exports_external2.string(),
|
|
132334
|
+
occurrence: exports_external2.number().int().positive().default(1).describe("1-based match to replace when replaceAll is false"),
|
|
132335
|
+
replaceAll: exports_external2.boolean().default(false).describe("replace every exact occurrence")
|
|
132336
|
+
}),
|
|
132337
|
+
execute: async ({ path, find: find2, replace: replace2, occurrence, replaceAll }) => {
|
|
132230
132338
|
const abs = safe(path);
|
|
132231
132339
|
const before2 = await readFile(abs, "utf8");
|
|
132232
|
-
|
|
132233
|
-
|
|
132340
|
+
const matches2 = countOccurrences(before2, find2);
|
|
132341
|
+
if (matches2 === 0)
|
|
132342
|
+
throw new Error(notFoundHint(path, before2, find2));
|
|
132343
|
+
if (!replaceAll && occurrence > matches2)
|
|
132344
|
+
throw new Error(`only found ${matches2} occurrence${matches2 === 1 ? "" : "s"} in ${path}; requested occurrence ${occurrence}`);
|
|
132234
132345
|
if (!await requestPermission({ kind: "edit", title: "Edit a file", detail: path }))
|
|
132235
132346
|
throw new Error(DENIED);
|
|
132236
|
-
const after2 = before2.
|
|
132347
|
+
const after2 = replaceAll ? before2.split(find2).join(replace2) : replaceOccurrence(before2, find2, replace2, occurrence);
|
|
132237
132348
|
await writeFile2(abs, after2, "utf8");
|
|
132238
132349
|
const diff2 = computeDiff(before2, after2);
|
|
132239
|
-
|
|
132350
|
+
const changed = replaceAll ? matches2 : 1;
|
|
132351
|
+
return { summary: `edited ${path} · ${changed} replacement${changed === 1 ? "" : "s"} (${diffStat(diff2)})`, diff: diff2 };
|
|
132352
|
+
}
|
|
132353
|
+
}),
|
|
132354
|
+
fetch_url: tool5({
|
|
132355
|
+
description: "Fetch a public http(s) URL and return readable text. Use this for docs, release notes, issue pages, or pasted links.",
|
|
132356
|
+
inputSchema: exports_external2.object({ url: exports_external2.string().url() }),
|
|
132357
|
+
execute: async ({ url: url2 }) => {
|
|
132358
|
+
const page = await fetchUrlText(url2);
|
|
132359
|
+
return clip2([`URL: ${page.url}`, page.title ? `Title: ${page.title}` : "", "", page.text].filter(Boolean).join(`
|
|
132360
|
+
`));
|
|
132240
132361
|
}
|
|
132241
132362
|
}),
|
|
132242
132363
|
search: tool5({
|
|
@@ -132342,7 +132463,8 @@ var readOnlyTools = {
|
|
|
132342
132463
|
read_file: tools.read_file,
|
|
132343
132464
|
list_dir: tools.list_dir,
|
|
132344
132465
|
search: tools.search,
|
|
132345
|
-
glob: tools.glob
|
|
132466
|
+
glob: tools.glob,
|
|
132467
|
+
fetch_url: tools.fetch_url
|
|
132346
132468
|
};
|
|
132347
132469
|
|
|
132348
132470
|
// node_modules/js-tiktoken/dist/chunk-VL2OQCWN.js
|
|
@@ -132799,6 +132921,42 @@ function retrieveFiles(query, cwd2 = process.cwd(), k = 6, budget = 8000, modelI
|
|
|
132799
132921
|
return out;
|
|
132800
132922
|
}
|
|
132801
132923
|
|
|
132924
|
+
// src/context/git.ts
|
|
132925
|
+
init_proc();
|
|
132926
|
+
function git(args, cwd2) {
|
|
132927
|
+
const r2 = spawnSyncProc(["git", ...args], { cwd: cwd2, stdout: "pipe", stderr: "ignore" });
|
|
132928
|
+
return r2.exitCode === 0 ? r2.stdout.toString().trim() : "";
|
|
132929
|
+
}
|
|
132930
|
+
function gitContext(cwd2 = process.cwd()) {
|
|
132931
|
+
if (!git(["rev-parse", "--is-inside-work-tree"], cwd2))
|
|
132932
|
+
return "";
|
|
132933
|
+
const branch = git(["branch", "--show-current"], cwd2) || git(["rev-parse", "--short", "HEAD"], cwd2);
|
|
132934
|
+
const status = git(["status", "--short"], cwd2);
|
|
132935
|
+
const staged = git(["diff", "--cached", "--stat"], cwd2);
|
|
132936
|
+
const unstaged = git(["diff", "--stat"], cwd2);
|
|
132937
|
+
const commits = git(["log", "--oneline", "-5"], cwd2);
|
|
132938
|
+
const parts = [];
|
|
132939
|
+
if (branch)
|
|
132940
|
+
parts.push(`branch: ${branch}`);
|
|
132941
|
+
if (status)
|
|
132942
|
+
parts.push(`dirty files:
|
|
132943
|
+
${status}`);
|
|
132944
|
+
else
|
|
132945
|
+
parts.push("working tree: clean");
|
|
132946
|
+
if (staged)
|
|
132947
|
+
parts.push(`staged diff stat:
|
|
132948
|
+
${staged}`);
|
|
132949
|
+
if (unstaged)
|
|
132950
|
+
parts.push(`unstaged diff stat:
|
|
132951
|
+
${unstaged}`);
|
|
132952
|
+
if (commits)
|
|
132953
|
+
parts.push(`recent commits:
|
|
132954
|
+
${commits}`);
|
|
132955
|
+
return parts.join(`
|
|
132956
|
+
|
|
132957
|
+
`);
|
|
132958
|
+
}
|
|
132959
|
+
|
|
132802
132960
|
// src/context/builder.ts
|
|
132803
132961
|
var BASE_SYSTEM = `You are Gearbox, a precise terminal coding agent.
|
|
132804
132962
|
Work in small, verifiable steps. Use the tools to read before you write, and
|
|
@@ -132910,6 +133068,14 @@ function buildContext(opts) {
|
|
|
132910
133068
|
${memory}`;
|
|
132911
133069
|
sections.push({ name: "memory", tokens: countTokens(memory, modelId) });
|
|
132912
133070
|
}
|
|
133071
|
+
const git2 = safe2(() => gitContext(cwd2), "");
|
|
133072
|
+
if (git2) {
|
|
133073
|
+
system += `
|
|
133074
|
+
|
|
133075
|
+
# GIT CONTEXT (current repository state; do not overwrite unrelated user changes)
|
|
133076
|
+
${git2}`;
|
|
133077
|
+
sections.push({ name: "git", tokens: countTokens(git2, modelId) });
|
|
133078
|
+
}
|
|
132913
133079
|
const mapBudget = Math.min(4000, Math.floor(inputBudget * 0.05));
|
|
132914
133080
|
const map3 = safe2(() => repoMap(cwd2, mapBudget), "");
|
|
132915
133081
|
if (map3) {
|
|
@@ -133379,6 +133545,171 @@ ${summary}` },
|
|
|
133379
133545
|
return { messages, summarizedTurns: old.length, before: before2, after: after2 };
|
|
133380
133546
|
}
|
|
133381
133547
|
|
|
133548
|
+
// src/init.ts
|
|
133549
|
+
import { existsSync as existsSync8, readdirSync as readdirSync4, readFileSync as readFileSync13, writeFileSync as writeFileSync7 } from "node:fs";
|
|
133550
|
+
import { join as join12 } from "node:path";
|
|
133551
|
+
|
|
133552
|
+
// src/verify.ts
|
|
133553
|
+
import { existsSync as existsSync7, readFileSync as readFileSync12 } from "node:fs";
|
|
133554
|
+
import { join as join11 } from "node:path";
|
|
133555
|
+
function readJson(path) {
|
|
133556
|
+
try {
|
|
133557
|
+
return JSON.parse(readFileSync12(path, "utf8"));
|
|
133558
|
+
} catch {
|
|
133559
|
+
return null;
|
|
133560
|
+
}
|
|
133561
|
+
}
|
|
133562
|
+
function packageManager(cwd2) {
|
|
133563
|
+
if (existsSync7(join11(cwd2, "bun.lock")) || existsSync7(join11(cwd2, "bun.lockb")))
|
|
133564
|
+
return "bun";
|
|
133565
|
+
if (existsSync7(join11(cwd2, "pnpm-lock.yaml")))
|
|
133566
|
+
return "pnpm";
|
|
133567
|
+
if (existsSync7(join11(cwd2, "yarn.lock")))
|
|
133568
|
+
return "yarn";
|
|
133569
|
+
return "npm";
|
|
133570
|
+
}
|
|
133571
|
+
function packageCommands(cwd2) {
|
|
133572
|
+
const pkg = readJson(join11(cwd2, "package.json"));
|
|
133573
|
+
const scripts = pkg?.scripts ?? {};
|
|
133574
|
+
if (!scripts || typeof scripts !== "object")
|
|
133575
|
+
return [];
|
|
133576
|
+
const pm = packageManager(cwd2);
|
|
133577
|
+
const run = (name31) => pm === "npm" ? `npm run ${name31}` : `${pm} run ${name31}`;
|
|
133578
|
+
const cmds = [];
|
|
133579
|
+
if (scripts.typecheck)
|
|
133580
|
+
cmds.push({ command: run("typecheck"), reason: "typecheck script" });
|
|
133581
|
+
if (scripts.test)
|
|
133582
|
+
cmds.push({ command: pm === "npm" ? "npm test" : pm === "bun" ? "bun test" : `${pm} test`, reason: "test script" });
|
|
133583
|
+
if (scripts.build)
|
|
133584
|
+
cmds.push({ command: run("build"), reason: "build script" });
|
|
133585
|
+
return cmds;
|
|
133586
|
+
}
|
|
133587
|
+
function detectVerificationCommands(cwd2 = process.cwd(), changedFiles = []) {
|
|
133588
|
+
const cmds = packageCommands(cwd2);
|
|
133589
|
+
const hasPython = changedFiles.some((f3) => /\.py$/.test(f3)) || existsSync7(join11(cwd2, "pyproject.toml")) || existsSync7(join11(cwd2, "pytest.ini"));
|
|
133590
|
+
const hasRust = changedFiles.some((f3) => /\.rs$/.test(f3)) || existsSync7(join11(cwd2, "Cargo.toml"));
|
|
133591
|
+
const hasGo = changedFiles.some((f3) => /\.go$/.test(f3)) || existsSync7(join11(cwd2, "go.mod"));
|
|
133592
|
+
if (hasPython && !cmds.some((c) => /\bpytest\b/.test(c.command)))
|
|
133593
|
+
cmds.push({ command: "pytest", reason: "python project" });
|
|
133594
|
+
if (hasRust && !cmds.some((c) => /\bcargo\s+test\b/.test(c.command)))
|
|
133595
|
+
cmds.push({ command: "cargo test", reason: "rust project" });
|
|
133596
|
+
if (hasGo && !cmds.some((c) => /\bgo\s+test\b/.test(c.command)))
|
|
133597
|
+
cmds.push({ command: "go test ./...", reason: "go project" });
|
|
133598
|
+
return cmds.slice(0, 3);
|
|
133599
|
+
}
|
|
133600
|
+
function summarize(output) {
|
|
133601
|
+
const lines = output.split(`
|
|
133602
|
+
`).map((l) => l.trim()).filter(Boolean);
|
|
133603
|
+
const fail = lines.find((l) => /\b(error|failed|failures?|exception|panic)\b/i.test(l));
|
|
133604
|
+
return (fail ?? lines[0] ?? "(no output)").slice(0, 160);
|
|
133605
|
+
}
|
|
133606
|
+
async function runVerification(commands, opts) {
|
|
133607
|
+
const results = [];
|
|
133608
|
+
for (const c of commands) {
|
|
133609
|
+
opts.onEvent({ type: "phase", label: "verifying", detail: `${c.command} · ${c.reason}`, state: "running" });
|
|
133610
|
+
const r2 = await runShellStream(c.command, { signal: opts.signal, timeoutMs: opts.timeoutMs ?? 120000 });
|
|
133611
|
+
results.push(r2);
|
|
133612
|
+
opts.onEvent({ type: "verification", command: c.command, ok: r2.ok, summary: r2.ok ? "passed" : summarize(r2.output) });
|
|
133613
|
+
opts.onEvent({ type: "phase", label: "verification", detail: c.command, state: r2.ok ? "ok" : "err" });
|
|
133614
|
+
if (!r2.ok)
|
|
133615
|
+
break;
|
|
133616
|
+
}
|
|
133617
|
+
return results;
|
|
133618
|
+
}
|
|
133619
|
+
|
|
133620
|
+
// src/init.ts
|
|
133621
|
+
function readJson2(path) {
|
|
133622
|
+
try {
|
|
133623
|
+
return JSON.parse(readFileSync13(path, "utf8"));
|
|
133624
|
+
} catch {
|
|
133625
|
+
return null;
|
|
133626
|
+
}
|
|
133627
|
+
}
|
|
133628
|
+
function rootEntries(cwd2) {
|
|
133629
|
+
try {
|
|
133630
|
+
return readdirSync4(cwd2, { withFileTypes: true }).filter((e2) => ![".git", "node_modules", "dist", "build", ".next", "coverage"].includes(e2.name)).map((e2) => e2.name + (e2.isDirectory() ? "/" : "")).sort().slice(0, 80);
|
|
133631
|
+
} catch {
|
|
133632
|
+
return [];
|
|
133633
|
+
}
|
|
133634
|
+
}
|
|
133635
|
+
function detectStack(cwd2) {
|
|
133636
|
+
const out = [];
|
|
133637
|
+
const pkg = readJson2(join12(cwd2, "package.json"));
|
|
133638
|
+
if (pkg) {
|
|
133639
|
+
const deps = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
|
|
133640
|
+
out.push("JavaScript/TypeScript");
|
|
133641
|
+
if (deps.react || deps.ink)
|
|
133642
|
+
out.push(deps.ink ? "Ink terminal UI" : "React");
|
|
133643
|
+
if (existsSync8(join12(cwd2, "bun.lock")) || existsSync8(join12(cwd2, "bun.lockb")))
|
|
133644
|
+
out.push("Bun");
|
|
133645
|
+
}
|
|
133646
|
+
if (existsSync8(join12(cwd2, "pyproject.toml")))
|
|
133647
|
+
out.push("Python");
|
|
133648
|
+
if (existsSync8(join12(cwd2, "Cargo.toml")))
|
|
133649
|
+
out.push("Rust");
|
|
133650
|
+
if (existsSync8(join12(cwd2, "go.mod")))
|
|
133651
|
+
out.push("Go");
|
|
133652
|
+
return [...new Set(out)];
|
|
133653
|
+
}
|
|
133654
|
+
function packageScripts(cwd2) {
|
|
133655
|
+
const pkg = readJson2(join12(cwd2, "package.json"));
|
|
133656
|
+
const scripts = pkg?.scripts ?? {};
|
|
133657
|
+
return Object.keys(scripts).sort().map((k) => `${k}: ${scripts[k]}`).slice(0, 20);
|
|
133658
|
+
}
|
|
133659
|
+
function existingDocs(cwd2) {
|
|
133660
|
+
return ["README.md", "DESIGN.md", "ROADMAP.md", "VISION.md", "AGENTS.md", "CLAUDE.md"].filter((name31) => existsSync8(join12(cwd2, name31)));
|
|
133661
|
+
}
|
|
133662
|
+
function buildProjectGuide(cwd2 = process.cwd()) {
|
|
133663
|
+
const name31 = readJson2(join12(cwd2, "package.json"))?.name ?? cwd2.split(/[\\/]/).filter(Boolean).at(-1) ?? "project";
|
|
133664
|
+
const stack = detectStack(cwd2);
|
|
133665
|
+
const checks3 = detectVerificationCommands(cwd2).map((c) => c.command);
|
|
133666
|
+
const scripts = packageScripts(cwd2);
|
|
133667
|
+
const entries = rootEntries(cwd2);
|
|
133668
|
+
const docs = existingDocs(cwd2);
|
|
133669
|
+
return `# ${name31} - Gearbox Guide
|
|
133670
|
+
|
|
133671
|
+
## What This Project Is
|
|
133672
|
+
|
|
133673
|
+
This file was generated from the repository structure so Gearbox has project context before editing.
|
|
133674
|
+
${stack.length ? `Detected stack: ${stack.join(", ")}.` : "Detected stack: unknown from root files."}
|
|
133675
|
+
|
|
133676
|
+
## Run And Verify
|
|
133677
|
+
|
|
133678
|
+
${checks3.length ? checks3.map((c) => `- \`${c}\``).join(`
|
|
133679
|
+
`) : "- No standard verification command was detected. Add one here when known."}
|
|
133680
|
+
|
|
133681
|
+
## Layout
|
|
133682
|
+
|
|
133683
|
+
${entries.length ? entries.map((e2) => `- \`${e2}\``).join(`
|
|
133684
|
+
`) : "- Root layout could not be read."}
|
|
133685
|
+
|
|
133686
|
+
${scripts.length ? `## Package Scripts
|
|
133687
|
+
|
|
133688
|
+
${scripts.map((s2) => `- \`${s2}\``).join(`
|
|
133689
|
+
`)}
|
|
133690
|
+
|
|
133691
|
+
` : ""}## Existing Project Docs
|
|
133692
|
+
|
|
133693
|
+
${docs.length ? docs.map((d) => `- \`${d}\``).join(`
|
|
133694
|
+
`) : "- No common docs detected."}
|
|
133695
|
+
|
|
133696
|
+
## Agent Conventions
|
|
133697
|
+
|
|
133698
|
+
- Read relevant files before editing.
|
|
133699
|
+
- Keep changes scoped to the user request.
|
|
133700
|
+
- Do not overwrite unrelated dirty work.
|
|
133701
|
+
- Run the verification commands above after edits when practical.
|
|
133702
|
+
`;
|
|
133703
|
+
}
|
|
133704
|
+
function writeProjectGuide(cwd2 = process.cwd()) {
|
|
133705
|
+
const path = join12(cwd2, "GEARBOX.md");
|
|
133706
|
+
const before2 = existsSync8(path) ? readFileSync13(path, "utf8") : "";
|
|
133707
|
+
const after2 = buildProjectGuide(cwd2);
|
|
133708
|
+
writeFileSync7(path, after2, "utf8");
|
|
133709
|
+
const diff2 = computeDiff(before2, after2);
|
|
133710
|
+
return { path, summary: `wrote GEARBOX.md (${diffStat(diff2)})`, diff: diff2 };
|
|
133711
|
+
}
|
|
133712
|
+
|
|
133382
133713
|
// src/ui/clipboard.ts
|
|
133383
133714
|
init_proc();
|
|
133384
133715
|
function osc52(text2) {
|
|
@@ -133582,7 +133913,7 @@ function gitBranch() {
|
|
|
133582
133913
|
init_proc();
|
|
133583
133914
|
var jsx_dev_runtime12 = __toESM(require_jsx_dev_runtime(), 1);
|
|
133584
133915
|
import { basename as basename2, extname } from "node:path";
|
|
133585
|
-
import { existsSync as
|
|
133916
|
+
import { existsSync as existsSync9, readFileSync as readFileSync14, statSync as statSync4 } from "node:fs";
|
|
133586
133917
|
import { writeFile as fsWriteFile } from "node:fs/promises";
|
|
133587
133918
|
import { spawnSync as nodeSpawnSync2 } from "node:child_process";
|
|
133588
133919
|
var accountResolver = new AccountResolver;
|
|
@@ -133686,12 +134017,12 @@ function previewLang(path) {
|
|
|
133686
134017
|
}
|
|
133687
134018
|
function filePreview(path) {
|
|
133688
134019
|
try {
|
|
133689
|
-
if (!path || !
|
|
134020
|
+
if (!path || !existsSync9(path))
|
|
133690
134021
|
return null;
|
|
133691
134022
|
const st = statSync4(path);
|
|
133692
134023
|
if (!st.isFile() || st.size > 400000)
|
|
133693
134024
|
return null;
|
|
133694
|
-
const raw =
|
|
134025
|
+
const raw = readFileSync14(path, "utf8").replace(/\r\n?/g, `
|
|
133695
134026
|
`);
|
|
133696
134027
|
const lines = raw.split(`
|
|
133697
134028
|
`);
|
|
@@ -134754,9 +135085,32 @@ function App2({ selector: initialSelector, runner, fullscreen = false, resumeId
|
|
|
134754
135085
|
echo(prompt);
|
|
134755
135086
|
lastPromptRef.current = prompt;
|
|
134756
135087
|
setVerb(nextVerb());
|
|
134757
|
-
|
|
135088
|
+
let { text: modelPrompt, attached } = expandMentions(prompt);
|
|
134758
135089
|
if (attached.length)
|
|
134759
135090
|
notice(`attached ${attached.length} file${attached.length > 1 ? "s" : ""}: ${attached.join(", ")}`);
|
|
135091
|
+
const urls = urlsInText(modelPrompt);
|
|
135092
|
+
if (urls.length) {
|
|
135093
|
+
const fetched = [];
|
|
135094
|
+
for (const url2 of urls) {
|
|
135095
|
+
try {
|
|
135096
|
+
const page = await fetchUrlText(url2);
|
|
135097
|
+
fetched.push(`=== ${page.url}${page.title ? ` · ${page.title}` : ""} ===
|
|
135098
|
+
${page.text}`);
|
|
135099
|
+
} catch (e2) {
|
|
135100
|
+
notice(`couldn't fetch ${url2}: ${(e2?.message ?? String(e2)).split(`
|
|
135101
|
+
`)[0]}`);
|
|
135102
|
+
}
|
|
135103
|
+
}
|
|
135104
|
+
if (fetched.length) {
|
|
135105
|
+
notice(`fetched ${fetched.length} URL${fetched.length === 1 ? "" : "s"} for context`);
|
|
135106
|
+
modelPrompt += `
|
|
135107
|
+
|
|
135108
|
+
# FETCHED URL CONTEXT
|
|
135109
|
+
${fetched.join(`
|
|
135110
|
+
|
|
135111
|
+
`)}`;
|
|
135112
|
+
}
|
|
135113
|
+
}
|
|
134760
135114
|
setBusy(true);
|
|
134761
135115
|
setSuggestion(null);
|
|
134762
135116
|
const turnStart = Date.now();
|
|
@@ -134915,6 +135269,16 @@ function App2({ selector: initialSelector, runner, fullscreen = false, resumeId
|
|
|
134915
135269
|
try {
|
|
134916
135270
|
const r2 = await (runner ?? defaultRunner)({ prompt: modelPrompt, messages: msgRef.current, onEvent, selector: selectorRef.current, signal: ac.signal });
|
|
134917
135271
|
msgRef.current = r2.messages;
|
|
135272
|
+
if (!hadError && !ac.signal.aborted && changedFiles.size && checks3.length === 0) {
|
|
135273
|
+
const commands = detectVerificationCommands(process.cwd(), [...changedFiles]);
|
|
135274
|
+
if (commands.length) {
|
|
135275
|
+
const results = await runVerification(commands, { onEvent, signal: ac.signal });
|
|
135276
|
+
if (results.some((res) => !res.ok))
|
|
135277
|
+
hadError = true;
|
|
135278
|
+
} else {
|
|
135279
|
+
onEvent({ type: "phase", label: "verification skipped", detail: "no test/build/typecheck command detected", state: "err" });
|
|
135280
|
+
}
|
|
135281
|
+
}
|
|
134918
135282
|
let modelId = activeCliRef.current?.id ?? routedRef.current?.model.id;
|
|
134919
135283
|
if (!modelId) {
|
|
134920
135284
|
try {
|
|
@@ -135619,7 +135983,31 @@ function App2({ selector: initialSelector, runner, fullscreen = false, resumeId
|
|
|
135619
135983
|
notice("busy — try /init again once the current turn finishes");
|
|
135620
135984
|
return;
|
|
135621
135985
|
}
|
|
135622
|
-
|
|
135986
|
+
echo(text2);
|
|
135987
|
+
setBusy(true);
|
|
135988
|
+
setSuggestion(null);
|
|
135989
|
+
(async () => {
|
|
135990
|
+
const id = idRef.current++;
|
|
135991
|
+
try {
|
|
135992
|
+
push({ kind: "tool", id, callId: `init:${id}`, name: "write_file", arg: "GEARBOX.md", status: "running", summary: "", startedAt: Date.now() });
|
|
135993
|
+
const res = writeProjectGuide(process.cwd());
|
|
135994
|
+
setItems((prev) => prev.map((i2) => i2.id === id && i2.kind === "tool" ? { ...i2, status: "ok", summary: res.summary, diff: res.diff, endedAt: Date.now() } : i2));
|
|
135995
|
+
const commands = detectVerificationCommands(process.cwd(), ["GEARBOX.md"]);
|
|
135996
|
+
if (commands.length)
|
|
135997
|
+
await runVerification(commands.slice(0, 1), { onEvent: (e2) => {
|
|
135998
|
+
if (e2.type === "verification")
|
|
135999
|
+
push({ kind: "verification", id: idRef.current++, command: e2.command, ok: e2.ok, summary: e2.summary });
|
|
136000
|
+
else if (e2.type === "phase")
|
|
136001
|
+
push({ kind: "phase", id: idRef.current++, label: e2.label, detail: e2.detail, state: e2.state ?? "running" });
|
|
136002
|
+
} });
|
|
136003
|
+
notice("initialized GEARBOX.md");
|
|
136004
|
+
persist();
|
|
136005
|
+
} catch (e2) {
|
|
136006
|
+
setItems((prev) => prev.map((i2) => i2.id === id && i2.kind === "tool" ? { ...i2, status: "err", summary: e2?.message ?? String(e2), endedAt: Date.now() } : i2));
|
|
136007
|
+
} finally {
|
|
136008
|
+
setBusy(false);
|
|
136009
|
+
}
|
|
136010
|
+
})();
|
|
135623
136011
|
return;
|
|
135624
136012
|
default: {
|
|
135625
136013
|
echo(text2);
|
|
@@ -135897,7 +136285,7 @@ function App2({ selector: initialSelector, runner, fullscreen = false, resumeId
|
|
|
135897
136285
|
if (!busyRef.current && input.length > 3 && !input.includes(`
|
|
135898
136286
|
`)) {
|
|
135899
136287
|
const p = sanitizeInputText(input).trim().replace(/^'|'$/g, "").replace(/\\ /g, " ");
|
|
135900
|
-
if (/[/\\.]/.test(p) && p.length < 1024 &&
|
|
136288
|
+
if (/[/\\.]/.test(p) && p.length < 1024 && existsSync9(p)) {
|
|
135901
136289
|
const e2 = editRef.current;
|
|
135902
136290
|
const ins = `@${p} `;
|
|
135903
136291
|
setEdit({ value: e2.value.slice(0, e2.cursor) + ins + e2.value.slice(e2.cursor), cursor: e2.cursor + ins.length });
|
|
@@ -136307,7 +136695,7 @@ function App2({ selector: initialSelector, runner, fullscreen = false, resumeId
|
|
|
136307
136695
|
var jsx_dev_runtime13 = __toESM(require_jsx_dev_runtime(), 1);
|
|
136308
136696
|
process.env.LANG = process.env.LANG || "en_US.UTF-8";
|
|
136309
136697
|
process.env.LC_ALL = process.env.LC_ALL || "en_US.UTF-8";
|
|
136310
|
-
var VERSION16 = "0.1.
|
|
136698
|
+
var VERSION16 = "0.1.11";
|
|
136311
136699
|
var args = process.argv.slice(2);
|
|
136312
136700
|
var supportsAnsi = process.env.NO_COLOR !== "1" && process.env.TERM !== "dumb" && (process.stdout.isTTY || process.env.FORCE_COLOR === "1");
|
|
136313
136701
|
var ansi = (code) => supportsAnsi ? `\x1B[${code}m` : "";
|
|
@@ -136525,7 +136913,7 @@ async function readStdin() {
|
|
|
136525
136913
|
}
|
|
136526
136914
|
if (args[0] === "upgrade" || args[0] === "update") {
|
|
136527
136915
|
const root2 = resolve11(import.meta.dir, "..");
|
|
136528
|
-
if (!
|
|
136916
|
+
if (!existsSync10(resolve11(root2, ".git"))) {
|
|
136529
136917
|
console.log("This build can't self-update (not a git checkout).");
|
|
136530
136918
|
console.log("Update by pulling the repo and reinstalling: git pull && bun install");
|
|
136531
136919
|
process.exit(0);
|
package/package.json
CHANGED