@viberaven/cli 1.6.9 → 1.6.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/README.md +8 -8
- package/dist/cli.js +91 -14
- package/dist/stack/scene.css +484 -0
- package/dist/stack/stack.css +95 -390
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,10 +10,10 @@ Requires Node.js 20 or newer. Run from the app's project root:
|
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
12
|
# Open the local Studio
|
|
13
|
-
npx -y viberaven@1.6.
|
|
13
|
+
npx -y viberaven@1.6.11
|
|
14
14
|
|
|
15
15
|
# Fresh terminal check
|
|
16
|
-
npx -y viberaven@1.6.
|
|
16
|
+
npx -y viberaven@1.6.11 check
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
The `viberaven` package launches this CLI. Studio combines findings, provider context and git comparisons. For chat, select an installed/authenticated Codex CLI, Claude Code or Gemini CLI and use **Test connection**. Access modes: `ask`, `approve`, `full`. Stop Studio with Ctrl+C.
|
|
@@ -27,10 +27,10 @@ Checks include migration tables without RLS, unrestricted policy conditions such
|
|
|
27
27
|
`check --json` prints a findings summary and artifact paths. `--json` without `check` runs a fresh scan and prints the full gate object.
|
|
28
28
|
|
|
29
29
|
```bash
|
|
30
|
-
npx -y viberaven@1.6.
|
|
31
|
-
npx -y viberaven@1.6.
|
|
32
|
-
npx -y viberaven@1.6.
|
|
33
|
-
npx -y viberaven@1.6.
|
|
30
|
+
npx -y viberaven@1.6.11 check --json
|
|
31
|
+
npx -y viberaven@1.6.11 audit --vercel-supabase --json
|
|
32
|
+
npx -y viberaven@1.6.11 fix --gap <gapId> --dry-run
|
|
33
|
+
npx -y viberaven@1.6.11 init --agents all --dry-run
|
|
34
34
|
```
|
|
35
35
|
|
|
36
36
|
Read tasks and source before targeted edits. Preview fixes first. The `rls_disabled` recipe adds an RLS migration without policies: agree before applying, because browser roles lose row access until policies exist. Apply/test through your database workflow; recheck after a batch. Provider actions require provider evidence.
|
|
@@ -41,9 +41,9 @@ Read tasks and source before targeted edits. Preview fixes first. The `rls_disab
|
|
|
41
41
|
|
|
42
42
|
```bash
|
|
43
43
|
# Fail on blockers
|
|
44
|
-
npx -y viberaven@1.6.
|
|
44
|
+
npx -y viberaven@1.6.11 --strict --json
|
|
45
45
|
# Also fail on warnings
|
|
46
|
-
npx -y viberaven@1.6.
|
|
46
|
+
npx -y viberaven@1.6.11 --strict=warning --json
|
|
47
47
|
```
|
|
48
48
|
|
|
49
49
|
Default `--strict` returns 0 for `clear`/`warning`, 1 for `not_clear`, 2 for `error`, 3 for `unknown` or unavailable results. `--strict=warning` also returns 1 for warnings.
|
package/dist/cli.js
CHANGED
|
@@ -15051,7 +15051,7 @@ var VERSION;
|
|
|
15051
15051
|
var init_version = __esm({
|
|
15052
15052
|
"src/version.ts"() {
|
|
15053
15053
|
"use strict";
|
|
15054
|
-
VERSION = "1.6.
|
|
15054
|
+
VERSION = "1.6.11";
|
|
15055
15055
|
}
|
|
15056
15056
|
});
|
|
15057
15057
|
|
|
@@ -21533,6 +21533,9 @@ async function readMaybe(path) {
|
|
|
21533
21533
|
return null;
|
|
21534
21534
|
}
|
|
21535
21535
|
}
|
|
21536
|
+
function blobId(content, like) {
|
|
21537
|
+
return (0, import_node_crypto5.createHash)(like.length === 64 ? "sha256" : "sha1").update(`blob ${content.length}\0`).update(content).digest("hex");
|
|
21538
|
+
}
|
|
21536
21539
|
function parsePorcelain(raw) {
|
|
21537
21540
|
const parts = raw.split("\0");
|
|
21538
21541
|
const entries = [];
|
|
@@ -21578,17 +21581,61 @@ async function takeBaseline(cwd) {
|
|
|
21578
21581
|
secret: secret || void 0
|
|
21579
21582
|
};
|
|
21580
21583
|
}
|
|
21581
|
-
|
|
21584
|
+
const headId = head.code === 0 ? head.stdout.toString("utf8").trim() : null;
|
|
21585
|
+
const checkout = headId ? await checkoutForms(cwd, root, headId, dirty, MAX_SNAPSHOT_TOTAL - total) : {};
|
|
21586
|
+
return { git: true, root, head: headId, takenAt, dirty, checkout };
|
|
21587
|
+
}
|
|
21588
|
+
async function checkoutForms(cwd, root, head, dirty, budget) {
|
|
21589
|
+
const tree = await safeGit(cwd, ["ls-tree", "-r", "-z", "--full-name", head], 15e3);
|
|
21590
|
+
if (tree.code !== 0) return {};
|
|
21591
|
+
const files = [];
|
|
21592
|
+
for (const record of tree.stdout.toString("utf8").split("\0")) {
|
|
21593
|
+
const tab = record.indexOf(" ");
|
|
21594
|
+
if (tab < 0) continue;
|
|
21595
|
+
const [mode, type, id] = record.slice(0, tab).split(" ");
|
|
21596
|
+
const path = record.slice(tab + 1);
|
|
21597
|
+
if (type !== "blob" || mode !== "100644" && mode !== "100755") continue;
|
|
21598
|
+
if (path in dirty || isSecretPath(path) || /(?:^|\/)\.viberaven\//.test(path)) continue;
|
|
21599
|
+
files.push({ path, id });
|
|
21600
|
+
}
|
|
21601
|
+
const forms = {};
|
|
21602
|
+
let scanned = 0;
|
|
21603
|
+
const look = async ({ path, id }) => {
|
|
21604
|
+
const target = (0, import_node_path42.join)(root, path);
|
|
21605
|
+
const size = await (0, import_promises33.stat)(target).then((info) => info.size, () => null);
|
|
21606
|
+
if (size === null || scanned + size > MAX_CHECKOUT_SCAN) return;
|
|
21607
|
+
scanned += size;
|
|
21608
|
+
const content = await readMaybe(target);
|
|
21609
|
+
if (!content || blobId(content, id) === id) return;
|
|
21610
|
+
const asLf = withoutCrlf(content);
|
|
21611
|
+
if (asLf.length < content.length && blobId(asLf, id) === id && withCrlf(asLf).equals(content)) {
|
|
21612
|
+
forms[path] = { eol: "crlf" };
|
|
21613
|
+
} else if (content.length <= MAX_SNAPSHOT_BYTES && content.length <= budget) {
|
|
21614
|
+
budget -= content.length;
|
|
21615
|
+
forms[path] = { content: content.toString("base64") };
|
|
21616
|
+
} else {
|
|
21617
|
+
forms[path] = { tooLarge: true };
|
|
21618
|
+
}
|
|
21619
|
+
};
|
|
21620
|
+
let next = 0;
|
|
21621
|
+
await Promise.all(Array.from({ length: CHECKOUT_READS_AT_ONCE }, async () => {
|
|
21622
|
+
while (next < files.length) await look(files[next++]);
|
|
21623
|
+
}));
|
|
21624
|
+
return forms;
|
|
21582
21625
|
}
|
|
21583
21626
|
async function baseContent(baseline, path) {
|
|
21584
21627
|
const entry = baseline.dirty[path];
|
|
21585
21628
|
if (entry) {
|
|
21586
21629
|
if (entry.hash === null) return null;
|
|
21587
|
-
return entry.content ? Buffer.from(entry.content, "base64") : void 0;
|
|
21630
|
+
return entry.content !== void 0 ? Buffer.from(entry.content, "base64") : void 0;
|
|
21588
21631
|
}
|
|
21589
21632
|
if (!baseline.root || !baseline.head) return null;
|
|
21633
|
+
const checkout = baseline.checkout?.[path];
|
|
21634
|
+
if (checkout?.content !== void 0) return Buffer.from(checkout.content, "base64");
|
|
21635
|
+
if (checkout?.tooLarge) return void 0;
|
|
21590
21636
|
const shown = await safeGit(baseline.root, ["show", `${baseline.head}:${path}`]);
|
|
21591
|
-
|
|
21637
|
+
if (shown.code !== 0) return null;
|
|
21638
|
+
return checkout?.eol === "crlf" ? withCrlf(shown.stdout) : shown.stdout;
|
|
21592
21639
|
}
|
|
21593
21640
|
function lineStats(before, after) {
|
|
21594
21641
|
const count = (text2) => {
|
|
@@ -21794,7 +21841,7 @@ async function loadBaseline(runsDir, runId) {
|
|
|
21794
21841
|
return null;
|
|
21795
21842
|
}
|
|
21796
21843
|
}
|
|
21797
|
-
var import_node_child_process9, import_node_crypto5, import_promises33, import_node_os3, import_node_path42, STATUS_PATHSPEC, MAX_SNAPSHOT_FILES, MAX_SNAPSHOT_BYTES, MAX_SNAPSHOT_TOTAL, SECRET_FILE, lf, NOT_PROVEN;
|
|
21844
|
+
var import_node_child_process9, import_node_crypto5, import_promises33, import_node_os3, import_node_path42, STATUS_PATHSPEC, MAX_SNAPSHOT_FILES, MAX_SNAPSHOT_BYTES, MAX_SNAPSHOT_TOTAL, MAX_CHECKOUT_SCAN, CHECKOUT_READS_AT_ONCE, SECRET_FILE, withCrlf, withoutCrlf, lf, NOT_PROVEN;
|
|
21798
21845
|
var init_workspace = __esm({
|
|
21799
21846
|
"src/local-ui/actions/workspace.ts"() {
|
|
21800
21847
|
"use strict";
|
|
@@ -21808,7 +21855,11 @@ var init_workspace = __esm({
|
|
|
21808
21855
|
MAX_SNAPSHOT_FILES = 300;
|
|
21809
21856
|
MAX_SNAPSHOT_BYTES = 1e6;
|
|
21810
21857
|
MAX_SNAPSHOT_TOTAL = 2e7;
|
|
21858
|
+
MAX_CHECKOUT_SCAN = 2e8;
|
|
21859
|
+
CHECKOUT_READS_AT_ONCE = 16;
|
|
21811
21860
|
SECRET_FILE = /(?:^|\/)\.env(?:\.[^/]*)?$|\.(?:pem|key|p12|pfx|keystore)$|(?:^|\/)id_(?:rsa|ed25519|ecdsa)$/i;
|
|
21861
|
+
withCrlf = (content) => Buffer.from(content.toString("latin1").replace(/\n/g, "\r\n"), "latin1");
|
|
21862
|
+
withoutCrlf = (content) => Buffer.from(content.toString("latin1").replace(/\r\n/g, "\n"), "latin1");
|
|
21812
21863
|
lf = (text2) => text2.replace(/\r\n/g, "\n");
|
|
21813
21864
|
NOT_PROVEN = "Changed during the run, but not proven to be only the agent\u2019s edit (you or another tool may have changed it), so Undo left it alone. Review it and put it back yourself if you want.";
|
|
21814
21865
|
}
|
|
@@ -21829,7 +21880,7 @@ async function detectPreviewCommand(cwd) {
|
|
|
21829
21880
|
const packageManager = await exists2("pnpm-lock.yaml") ? "pnpm" : await exists2("yarn.lock") ? "yarn" : await exists2("bun.lockb") || await exists2("bun.lock") ? "bun" : "npm";
|
|
21830
21881
|
const deps = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
|
|
21831
21882
|
const framework = FRAMEWORKS.find(([dep]) => dep in deps)?.[1] ?? null;
|
|
21832
|
-
return { packageManager, script, framework, display: `${packageManager} run ${script}
|
|
21883
|
+
return { packageManager, script, framework, display: `${packageManager} run ${script}`, reloadsItself: RELOADS_ITSELF.test(scripts[script]) };
|
|
21833
21884
|
}
|
|
21834
21885
|
function answers(host, port) {
|
|
21835
21886
|
return new Promise((resolveAnswer) => {
|
|
@@ -21873,7 +21924,7 @@ function previewFailureReason(log) {
|
|
|
21873
21924
|
if (/Missing script/i.test(log)) return "The script VibeRaven picked is not in package.json.";
|
|
21874
21925
|
return void 0;
|
|
21875
21926
|
}
|
|
21876
|
-
var import_node_child_process10, import_promises34, import_node_net, import_node_path43, URL_PATTERN, READY_TIMEOUT_MS, LOG_LIMIT, FRAMEWORKS, PreviewManager;
|
|
21927
|
+
var import_node_child_process10, import_promises34, import_node_net, import_node_path43, URL_PATTERN, READY_TIMEOUT_MS, LOG_LIMIT, FRAMEWORKS, RELOADS_ITSELF, PreviewManager;
|
|
21877
21928
|
var init_preview2 = __esm({
|
|
21878
21929
|
"src/local-ui/preview.ts"() {
|
|
21879
21930
|
"use strict";
|
|
@@ -21886,6 +21937,7 @@ var init_preview2 = __esm({
|
|
|
21886
21937
|
READY_TIMEOUT_MS = 12e4;
|
|
21887
21938
|
LOG_LIMIT = 6e3;
|
|
21888
21939
|
FRAMEWORKS = [["next", "Next.js"], ["vite", "Vite"], ["@remix-run/dev", "Remix"], ["astro", "Astro"], ["@sveltejs/kit", "SvelteKit"], ["nuxt", "Nuxt"], ["react-scripts", "Create React App"]];
|
|
21940
|
+
RELOADS_ITSELF = /\b(?:next\s+dev|vite\b(?!\s+(?:build|preview))|astro\s+dev|nuxi?\s+dev|remix\s+(?:vite:)?dev|react-scripts\s+start|webpack(?:-dev-server|\s+serve)|nodemon|tsx\s+watch|ts-node-dev|svelte-kit\s+dev|ng\s+serve|parcel\b(?!\s+build))|--watch\b/i;
|
|
21889
21941
|
PreviewManager = class {
|
|
21890
21942
|
constructor(cwd, home, preferredPort = 3e3) {
|
|
21891
21943
|
this.cwd = cwd;
|
|
@@ -21939,7 +21991,7 @@ var init_preview2 = __esm({
|
|
|
21939
21991
|
return this.snapshot();
|
|
21940
21992
|
}
|
|
21941
21993
|
this.assignedPort = port;
|
|
21942
|
-
this.status = { state: "starting", command: command.display, framework: command.framework, startedAt: (/* @__PURE__ */ new Date()).toISOString(), log: "", revision: this.status.revision };
|
|
21994
|
+
this.status = { state: "starting", command: command.display, framework: command.framework, reloadsItself: command.reloadsItself, startedAt: (/* @__PURE__ */ new Date()).toISOString(), log: "", revision: this.status.revision };
|
|
21943
21995
|
const child = (0, import_node_child_process10.spawn)(`${command.packageManager} run ${command.script}`, {
|
|
21944
21996
|
cwd: this.cwd,
|
|
21945
21997
|
shell: true,
|
|
@@ -22027,6 +22079,25 @@ var init_preview2 = __esm({
|
|
|
22027
22079
|
if (this.status.state !== "starting") return Promise.resolve(this.snapshot());
|
|
22028
22080
|
return new Promise((resolveWait) => this.readyWaiters.push(() => resolveWait(this.snapshot())));
|
|
22029
22081
|
}
|
|
22082
|
+
/**
|
|
22083
|
+
* The app's code changed. A dev server that reloads by itself only needs the frame reloaded; any other one is
|
|
22084
|
+
* restarted, so the preview never keeps serving the code from before the change.
|
|
22085
|
+
*/
|
|
22086
|
+
async reload() {
|
|
22087
|
+
if (!this.isRunning()) return this.snapshot();
|
|
22088
|
+
if (this.status.reloadsItself) {
|
|
22089
|
+
this.bumpRevision();
|
|
22090
|
+
return this.snapshot();
|
|
22091
|
+
}
|
|
22092
|
+
const port = this.assignedPort;
|
|
22093
|
+
this.stop();
|
|
22094
|
+
for (let tries = 0; tries < 50 && port && await portTaken(port); tries += 1) {
|
|
22095
|
+
await new Promise((resolveDelay) => setTimeout(resolveDelay, 200));
|
|
22096
|
+
}
|
|
22097
|
+
await this.start();
|
|
22098
|
+
this.bumpRevision();
|
|
22099
|
+
return this.waitForReady();
|
|
22100
|
+
}
|
|
22030
22101
|
/** Marks that the app's code changed, so the Studio reloads the frame exactly once. */
|
|
22031
22102
|
bumpRevision() {
|
|
22032
22103
|
this.status = { ...this.status, revision: this.status.revision + 1 };
|
|
@@ -22382,7 +22453,7 @@ var init_engine = __esm({
|
|
|
22382
22453
|
const outcome = await revertChanges(baseline, paths.map((path) => ({ path, kind: "modified", additions: 0, deletions: 0 })), keep);
|
|
22383
22454
|
this.deps.store.update(runId, { reverted: { at: (/* @__PURE__ */ new Date()).toISOString(), ...outcome } });
|
|
22384
22455
|
this.deps.store.emit(runId, "run.reverted", { restored: outcome.restored.length, skipped: outcome.skipped.length });
|
|
22385
|
-
if (outcome.restored.length && this.deps.preview.isRunning()) this.deps.preview.
|
|
22456
|
+
if (outcome.restored.length && this.deps.preview.isRunning()) await this.deps.preview.reload();
|
|
22386
22457
|
return outcome;
|
|
22387
22458
|
}
|
|
22388
22459
|
/**
|
|
@@ -22401,7 +22472,7 @@ var init_engine = __esm({
|
|
|
22401
22472
|
if ("error" in outcome) return outcome;
|
|
22402
22473
|
this.deps.store.update(runId, { restoredFiles: [.../* @__PURE__ */ new Set([...run.restoredFiles ?? [], path])] });
|
|
22403
22474
|
this.deps.store.emit(runId, "file.restored", { path });
|
|
22404
|
-
if (this.deps.preview.isRunning()) this.deps.preview.
|
|
22475
|
+
if (this.deps.preview.isRunning()) await this.deps.preview.reload();
|
|
22405
22476
|
return outcome;
|
|
22406
22477
|
}
|
|
22407
22478
|
stopped(runId) {
|
|
@@ -22556,7 +22627,8 @@ var init_engine = __esm({
|
|
|
22556
22627
|
const cancelledNow = () => this.stopped(runId);
|
|
22557
22628
|
if (!checkSpecs.length) unknowns.push("No typecheck or test script, so the code was not checked.");
|
|
22558
22629
|
if (this.deps.preview.isRunning()) {
|
|
22559
|
-
this.deps.preview.
|
|
22630
|
+
if (changes.length) await this.deps.preview.reload();
|
|
22631
|
+
else this.deps.preview.bumpRevision();
|
|
22560
22632
|
const ready = await this.deps.preview.waitForReady();
|
|
22561
22633
|
if (cancelledNow()) return this.finishCancelled(runId, changes, notProven);
|
|
22562
22634
|
const answerHttp = ready.url ? await this.deps.preview.fetchStatus(ready.url, 6e4) : null;
|
|
@@ -24253,9 +24325,13 @@ async function sendStackAppJs(response) {
|
|
|
24253
24325
|
}
|
|
24254
24326
|
async function sendStackAppCss(response) {
|
|
24255
24327
|
try {
|
|
24256
|
-
const
|
|
24328
|
+
const [shell, scene] = await Promise.all([
|
|
24329
|
+
(0, import_promises36.readFile)((0, import_node_path45.join)(__dirname, "stack", "stack.css"), "utf8"),
|
|
24330
|
+
(0, import_promises36.readFile)((0, import_node_path45.join)(__dirname, "stack", "scene.css"), "utf8").catch(() => "")
|
|
24331
|
+
]);
|
|
24257
24332
|
response.writeHead(200, { "content-type": "text/css; charset=utf-8", "cache-control": "no-store" });
|
|
24258
|
-
response.end(
|
|
24333
|
+
response.end(`${shell}
|
|
24334
|
+
${scene}`);
|
|
24259
24335
|
} catch {
|
|
24260
24336
|
sendText(response, 404, "Stack stylesheet not found: src/local-ui/stack/stack.css is missing.");
|
|
24261
24337
|
}
|
|
@@ -25649,7 +25725,8 @@ async function runConnect(options, deps) {
|
|
|
25649
25725
|
const reply = await call(deps, "POST", `/v1/runner/jobs/${encodeURIComponent(job.id)}/result`, result, runnerAccessToken);
|
|
25650
25726
|
if (unauthorized(reply.status)) break;
|
|
25651
25727
|
if (reply.status >= 200 && reply.status < 300) {
|
|
25652
|
-
|
|
25728
|
+
const sign = { succeeded: "\u2713", needs_user: "\u2022", cancelled: "\u25A0", failed: "\u2717" }[result.status] ?? "\u2717";
|
|
25729
|
+
log(` ${sign} ${result.outputSummary[0] ?? "Could not finish."} (sent to the site)`);
|
|
25653
25730
|
return;
|
|
25654
25731
|
}
|
|
25655
25732
|
} catch {
|