@aayambansal/squint 0.2.7 → 0.2.8
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
CHANGED
|
@@ -132,6 +132,7 @@ squint config set models.claude claude-sonnet-5
|
|
|
132
132
|
squint config set autoDev true # dev server starts with the TUI
|
|
133
133
|
squint config set autoFix true # errors auto-route back (max 2 tries)
|
|
134
134
|
squint config set autoCheck false # skip the per-turn typecheck+lint pass
|
|
135
|
+
squint config set autoReview true # big visual change → automatic self-critique
|
|
135
136
|
squint config set theme ocean # amber · ocean · moss · rose · mono
|
|
136
137
|
squint config set bell false # no bell on turn completion
|
|
137
138
|
squint doctor # engines + Chrome + WebSocket check
|
|
@@ -9,6 +9,7 @@ var COMMANDS = [
|
|
|
9
9
|
{ name: "shot", description: "screenshot the app at mobile/tablet/desktop" },
|
|
10
10
|
{ name: "review", args: "[focus]", description: "screenshots + the engine critiques its own rendered work" },
|
|
11
11
|
{ name: "variants", args: "<2-4> <ask>", description: "parallel design explorations; apply/list/clean" },
|
|
12
|
+
{ name: "sandbox", args: "[on|diff|apply|discard]", description: "asks accumulate in a shadow worktree until you apply" },
|
|
12
13
|
{ name: "undo", description: "revert the last ask (files only)" },
|
|
13
14
|
{ name: "checkpoints", description: "list per-ask checkpoints" },
|
|
14
15
|
{ name: "restore", args: "<n>", description: "rewind files to before ask n" },
|
package/dist/cli.js
CHANGED
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
} from "./chunk-CHZE3UHK.js";
|
|
31
31
|
import {
|
|
32
32
|
completeCommand
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-YTO2YRF7.js";
|
|
34
34
|
import {
|
|
35
35
|
runAgent
|
|
36
36
|
} from "./chunk-C7WKNJG6.js";
|
|
@@ -265,22 +265,22 @@ function registerProject(program2) {
|
|
|
265
265
|
}
|
|
266
266
|
});
|
|
267
267
|
skillsCommand.command("init").description("Scaffold .squint/rules.md and an example skill").action(async () => {
|
|
268
|
-
const
|
|
268
|
+
const fs3 = await import("fs");
|
|
269
269
|
const nodePath = await import("path");
|
|
270
270
|
const cwd = process.cwd();
|
|
271
271
|
const skillsDir = nodePath.join(cwd, ".squint", "skills");
|
|
272
|
-
|
|
272
|
+
fs3.mkdirSync(skillsDir, { recursive: true });
|
|
273
273
|
const rules = nodePath.join(cwd, ".squint", "rules.md");
|
|
274
|
-
if (!
|
|
275
|
-
|
|
274
|
+
if (!fs3.existsSync(rules)) {
|
|
275
|
+
fs3.writeFileSync(
|
|
276
276
|
rules,
|
|
277
277
|
"# Project rules\n\nThese ride along on every squint ask. Keep them short \u2014 cut anything that would not cause a mistake if removed.\n"
|
|
278
278
|
);
|
|
279
279
|
console.log(pc3.green("\u2713 .squint/rules.md"));
|
|
280
280
|
}
|
|
281
281
|
const example = nodePath.join(skillsDir, "example.md");
|
|
282
|
-
if (!
|
|
283
|
-
|
|
282
|
+
if (!fs3.existsSync(example)) {
|
|
283
|
+
fs3.writeFileSync(
|
|
284
284
|
example,
|
|
285
285
|
"---\ntriggers: example, sample\n---\n\nThis note is injected only when an ask mentions one of the triggers above.\nDocument the parts of this repo an agent would otherwise rediscover every time:\nwhere state lives, which helpers to reuse, what not to touch.\n"
|
|
286
286
|
);
|
|
@@ -289,7 +289,7 @@ function registerProject(program2) {
|
|
|
289
289
|
console.log(pc3.dim("rules are always-on; skills inject when an ask mentions a trigger"));
|
|
290
290
|
});
|
|
291
291
|
program2.command("brief").description("Set a committed design direction for this project (.squint/brief.md)").argument("[family]", "aesthetic family id (omit to list)").option("--force", "overwrite an existing project brief").action(async (familyId, options) => {
|
|
292
|
-
const
|
|
292
|
+
const fs3 = await import("fs");
|
|
293
293
|
const nodePath = await import("path");
|
|
294
294
|
const { FAMILIES, getFamily, renderFamilyBrief } = await import("./families-2G5SLLY7.js");
|
|
295
295
|
if (!familyId) {
|
|
@@ -307,13 +307,13 @@ function registerProject(program2) {
|
|
|
307
307
|
return;
|
|
308
308
|
}
|
|
309
309
|
const target = nodePath.join(process.cwd(), ".squint", "brief.md");
|
|
310
|
-
if (
|
|
310
|
+
if (fs3.existsSync(target) && !options.force) {
|
|
311
311
|
console.error(pc3.red(`\u2717 ${target} exists \u2014 use --force to overwrite`));
|
|
312
312
|
process.exitCode = 1;
|
|
313
313
|
return;
|
|
314
314
|
}
|
|
315
|
-
|
|
316
|
-
|
|
315
|
+
fs3.mkdirSync(nodePath.dirname(target), { recursive: true });
|
|
316
|
+
fs3.writeFileSync(target, renderFamilyBrief(family) + "\n");
|
|
317
317
|
console.log(pc3.green(`\u2713 ${family.name} direction written to .squint/brief.md`));
|
|
318
318
|
console.log(pc3.dim("every squint ask in this repo now holds this direction \u2014 edit the file to remix"));
|
|
319
319
|
});
|
|
@@ -533,21 +533,21 @@ Next: ${pc6.bold(`${cd}${options.install ? "" : "npm install && "}squint`)}`);
|
|
|
533
533
|
console.log(pc6.dim("then describe what to build \u2014 /dev starts the preview server"));
|
|
534
534
|
});
|
|
535
535
|
program2.command("tag").description("Add the element picker to this Vite app (Alt+S in the browser \u2192 click \u2192 file:line:col)").action(async () => {
|
|
536
|
-
const
|
|
536
|
+
const fs3 = await import("fs");
|
|
537
537
|
const nodePath = await import("path");
|
|
538
538
|
const { patchViteConfig, TAGGER_FILENAME, TAGGER_SOURCE } = await import("./source-ZZU245VN.js");
|
|
539
539
|
const cwd = process.cwd();
|
|
540
540
|
const taggerPath = nodePath.join(cwd, TAGGER_FILENAME);
|
|
541
|
-
|
|
541
|
+
fs3.writeFileSync(taggerPath, TAGGER_SOURCE);
|
|
542
542
|
console.log(pc6.green(`\u2713 ${TAGGER_FILENAME} written`));
|
|
543
|
-
const configPath = ["vite.config.ts", "vite.config.js", "vite.config.mjs"].map((name) => nodePath.join(cwd, name)).find((candidate) =>
|
|
543
|
+
const configPath = ["vite.config.ts", "vite.config.js", "vite.config.mjs"].map((name) => nodePath.join(cwd, name)).find((candidate) => fs3.existsSync(candidate));
|
|
544
544
|
if (!configPath) {
|
|
545
545
|
console.log(pc6.yellow("\u25CB no vite config found \u2014 add the plugin manually:"));
|
|
546
546
|
console.log(pc6.dim(` import squintTagger from './${TAGGER_FILENAME}'
|
|
547
547
|
plugins: [squintTagger(), \u2026]`));
|
|
548
548
|
return;
|
|
549
549
|
}
|
|
550
|
-
const source =
|
|
550
|
+
const source = fs3.readFileSync(configPath, "utf8");
|
|
551
551
|
const patched = patchViteConfig(source);
|
|
552
552
|
if (patched === "already") {
|
|
553
553
|
console.log(pc6.dim("vite config already wired"));
|
|
@@ -556,7 +556,7 @@ Next: ${pc6.bold(`${cd}${options.install ? "" : "npm install && "}squint`)}`);
|
|
|
556
556
|
console.log(pc6.dim(` import squintTagger from './${TAGGER_FILENAME}'
|
|
557
557
|
plugins: [squintTagger(), \u2026]`));
|
|
558
558
|
} else {
|
|
559
|
-
|
|
559
|
+
fs3.writeFileSync(configPath, patched);
|
|
560
560
|
console.log(pc6.green(`\u2713 ${nodePath.basename(configPath)} wired`));
|
|
561
561
|
}
|
|
562
562
|
console.log(
|
|
@@ -570,11 +570,97 @@ import { render } from "ink";
|
|
|
570
570
|
|
|
571
571
|
// src/tui/App.tsx
|
|
572
572
|
import { Box as Box2, Static, Text as Text3, useApp, useInput } from "ink";
|
|
573
|
-
import
|
|
573
|
+
import path4 from "path";
|
|
574
574
|
import { useMemo, useRef, useState as useState2, useSyncExternalStore } from "react";
|
|
575
575
|
|
|
576
576
|
// src/session/engine.ts
|
|
577
|
+
import path3 from "path";
|
|
578
|
+
|
|
579
|
+
// src/vcs/sandbox.ts
|
|
580
|
+
import { execFileSync } from "child_process";
|
|
581
|
+
import fs2 from "fs";
|
|
577
582
|
import path2 from "path";
|
|
583
|
+
function git(cwd, args) {
|
|
584
|
+
return execFileSync("git", args, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
|
|
585
|
+
}
|
|
586
|
+
function sandboxDir(cwd) {
|
|
587
|
+
return path2.join(cwd, ".squint", "sandbox");
|
|
588
|
+
}
|
|
589
|
+
function sandboxExists(cwd) {
|
|
590
|
+
return fs2.existsSync(path2.join(sandboxDir(cwd), ".git"));
|
|
591
|
+
}
|
|
592
|
+
function openSandbox(cwd) {
|
|
593
|
+
const dir = sandboxDir(cwd);
|
|
594
|
+
if (sandboxExists(cwd)) return { dir, reused: true };
|
|
595
|
+
fs2.rmSync(dir, { recursive: true, force: true });
|
|
596
|
+
fs2.mkdirSync(path2.dirname(dir), { recursive: true });
|
|
597
|
+
git(cwd, ["worktree", "add", "--force", "--detach", dir, "HEAD"]);
|
|
598
|
+
const mainModules = path2.join(cwd, "node_modules");
|
|
599
|
+
const sandboxModules = path2.join(dir, "node_modules");
|
|
600
|
+
if (fs2.existsSync(mainModules) && !fs2.existsSync(sandboxModules)) {
|
|
601
|
+
fs2.symlinkSync(mainModules, sandboxModules, "dir");
|
|
602
|
+
}
|
|
603
|
+
return { dir, reused: false };
|
|
604
|
+
}
|
|
605
|
+
function sandboxDiffStat(cwd) {
|
|
606
|
+
if (!sandboxExists(cwd)) return null;
|
|
607
|
+
const dir = sandboxDir(cwd);
|
|
608
|
+
try {
|
|
609
|
+
git(dir, ["add", "-A"]);
|
|
610
|
+
const stat = git(dir, ["diff", "--cached", "--shortstat", "HEAD"]);
|
|
611
|
+
return stat.length > 0 ? stat : null;
|
|
612
|
+
} catch {
|
|
613
|
+
return null;
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
function sandboxFiles(cwd) {
|
|
617
|
+
if (!sandboxExists(cwd)) return [];
|
|
618
|
+
const dir = sandboxDir(cwd);
|
|
619
|
+
try {
|
|
620
|
+
git(dir, ["add", "-A"]);
|
|
621
|
+
const out = git(dir, ["diff", "--cached", "--name-status", "HEAD"]);
|
|
622
|
+
return out.length > 0 ? out.split("\n") : [];
|
|
623
|
+
} catch {
|
|
624
|
+
return [];
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
function applySandbox(cwd) {
|
|
628
|
+
if (!sandboxExists(cwd)) return { ok: false, detail: "no sandbox open" };
|
|
629
|
+
const dir = sandboxDir(cwd);
|
|
630
|
+
try {
|
|
631
|
+
git(dir, ["add", "-A"]);
|
|
632
|
+
const patch = git(dir, ["diff", "--binary", "--cached", "HEAD"]);
|
|
633
|
+
if (patch.length === 0) return { ok: false, detail: "sandbox has no changes" };
|
|
634
|
+
const patchFile = path2.join(cwd, ".squint", "sandbox.patch");
|
|
635
|
+
fs2.writeFileSync(patchFile, patch + "\n");
|
|
636
|
+
git(cwd, ["apply", "--whitespace=nowarn", patchFile]);
|
|
637
|
+
fs2.rmSync(patchFile, { force: true });
|
|
638
|
+
return { ok: true };
|
|
639
|
+
} catch (err) {
|
|
640
|
+
return { ok: false, detail: err instanceof Error ? err.message.split("\n")[0] : String(err) };
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
function discardSandbox(cwd) {
|
|
644
|
+
if (!sandboxExists(cwd)) return false;
|
|
645
|
+
const dir = sandboxDir(cwd);
|
|
646
|
+
try {
|
|
647
|
+
const link = path2.join(dir, "node_modules");
|
|
648
|
+
if (fs2.existsSync(link) && fs2.lstatSync(link).isSymbolicLink()) fs2.rmSync(link);
|
|
649
|
+
} catch {
|
|
650
|
+
}
|
|
651
|
+
try {
|
|
652
|
+
git(cwd, ["worktree", "remove", "--force", dir]);
|
|
653
|
+
} catch {
|
|
654
|
+
fs2.rmSync(dir, { recursive: true, force: true });
|
|
655
|
+
}
|
|
656
|
+
try {
|
|
657
|
+
git(cwd, ["worktree", "prune"]);
|
|
658
|
+
} catch {
|
|
659
|
+
}
|
|
660
|
+
return true;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
// src/session/engine.ts
|
|
578
664
|
var MAX_AUTO_FIX_ATTEMPTS = 2;
|
|
579
665
|
var delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
580
666
|
var Session = class {
|
|
@@ -592,7 +678,8 @@ var Session = class {
|
|
|
592
678
|
totals: { costUsd: 0, turns: 0 },
|
|
593
679
|
queue: [],
|
|
594
680
|
mode: "safe",
|
|
595
|
-
problems: []
|
|
681
|
+
problems: [],
|
|
682
|
+
sandbox: false
|
|
596
683
|
};
|
|
597
684
|
if (opts.autoDev && detectDevCommand(opts.cwd)) {
|
|
598
685
|
this.devServer().start();
|
|
@@ -762,15 +849,33 @@ var Session = class {
|
|
|
762
849
|
this.push("assistant", text);
|
|
763
850
|
}
|
|
764
851
|
}
|
|
852
|
+
/** Where engines run and servers start: the sandbox worktree when on. */
|
|
853
|
+
execCwd() {
|
|
854
|
+
return this.state.sandbox ? sandboxDir(this.opts.cwd) : this.opts.cwd;
|
|
855
|
+
}
|
|
765
856
|
devServer() {
|
|
766
857
|
if (!this.dev) {
|
|
767
|
-
this.dev = new DevServer(this.
|
|
858
|
+
this.dev = new DevServer(this.execCwd(), {
|
|
768
859
|
onStateChange: (devState) => this.notify({ devState }),
|
|
769
860
|
onUrl: (url) => this.notify({ devUrl: url })
|
|
770
861
|
});
|
|
771
862
|
}
|
|
772
863
|
return this.dev;
|
|
773
864
|
}
|
|
865
|
+
/** Rebind the dev server after the execution tree changes. */
|
|
866
|
+
resetDevServer() {
|
|
867
|
+
const wasRunning = this.dev && this.dev.state !== "stopped";
|
|
868
|
+
this.dev?.stop();
|
|
869
|
+
this.dev = null;
|
|
870
|
+
this.notify({ devUrl: null, devState: "stopped" });
|
|
871
|
+
if (wasRunning) {
|
|
872
|
+
const command = detectDevCommand(this.execCwd());
|
|
873
|
+
if (command) {
|
|
874
|
+
this.devServer().start(command);
|
|
875
|
+
this.push("status", `dev server restarting in ${this.state.sandbox ? "the sandbox" : "the real tree"}`);
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
}
|
|
774
879
|
turnEdits = 0;
|
|
775
880
|
turnTools = 0;
|
|
776
881
|
toolStreak = 0;
|
|
@@ -849,7 +954,7 @@ var Session = class {
|
|
|
849
954
|
engine,
|
|
850
955
|
{
|
|
851
956
|
prompt,
|
|
852
|
-
cwd: this.
|
|
957
|
+
cwd: this.execCwd(),
|
|
853
958
|
model: this.state.model,
|
|
854
959
|
mode: this.state.mode,
|
|
855
960
|
sessionId: engine.supportsResume ? this.sessionId : void 0
|
|
@@ -892,9 +997,9 @@ var Session = class {
|
|
|
892
997
|
}
|
|
893
998
|
}
|
|
894
999
|
if (result.ok && this.opts.autoCheck !== false) {
|
|
895
|
-
const fastGates = detectFastGates(this.
|
|
1000
|
+
const fastGates = detectFastGates(this.execCwd());
|
|
896
1001
|
if (fastGates.length > 0) {
|
|
897
|
-
const gateResults = await runGates(this.
|
|
1002
|
+
const gateResults = await runGates(this.execCwd(), fastGates);
|
|
898
1003
|
const failures = gateResults.filter((r) => !r.ok);
|
|
899
1004
|
if (failures.length > 0) {
|
|
900
1005
|
this.addProblem(
|
|
@@ -969,7 +1074,7 @@ ${errors.slice(-5).join("\n")}`);
|
|
|
969
1074
|
async submit(ask) {
|
|
970
1075
|
this.fixAttempts = 0;
|
|
971
1076
|
this.autoReviewedThisAsk = false;
|
|
972
|
-
const snapshot = takeSnapshot(this.opts.cwd);
|
|
1077
|
+
const snapshot = this.state.sandbox ? null : takeSnapshot(this.opts.cwd);
|
|
973
1078
|
if (snapshot) {
|
|
974
1079
|
this.checkpoints.push({
|
|
975
1080
|
snapshot,
|
|
@@ -1049,7 +1154,7 @@ ${errors.slice(-5).join("\n")}`);
|
|
|
1049
1154
|
if (result.shots.length > 0) {
|
|
1050
1155
|
this.push(
|
|
1051
1156
|
"status",
|
|
1052
|
-
`captured ${result.shots.map((s) => s.name).join(", ")} \u2192 ${
|
|
1157
|
+
`captured ${result.shots.map((s) => s.name).join(", ")} \u2192 ${path3.dirname(result.shots[0].path)}`
|
|
1053
1158
|
);
|
|
1054
1159
|
}
|
|
1055
1160
|
if (result.runtime) {
|
|
@@ -1176,12 +1281,12 @@ They are objective defects, not style preferences.`
|
|
|
1176
1281
|
}
|
|
1177
1282
|
case "save": {
|
|
1178
1283
|
void (async () => {
|
|
1179
|
-
const
|
|
1180
|
-
const
|
|
1181
|
-
const dir =
|
|
1182
|
-
|
|
1284
|
+
const fs3 = await import("fs");
|
|
1285
|
+
const path5 = await import("path");
|
|
1286
|
+
const dir = path5.join(this.opts.cwd, ".squint", "transcripts");
|
|
1287
|
+
fs3.mkdirSync(dir, { recursive: true });
|
|
1183
1288
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
1184
|
-
const file =
|
|
1289
|
+
const file = path5.join(dir, `${stamp}.md`);
|
|
1185
1290
|
const lines = [`# squint session \u2014 ${(/* @__PURE__ */ new Date()).toISOString().slice(0, 16)}`, ""];
|
|
1186
1291
|
for (const item of this.state.items) {
|
|
1187
1292
|
switch (item.role) {
|
|
@@ -1201,8 +1306,8 @@ They are objective defects, not style preferences.`
|
|
|
1201
1306
|
}
|
|
1202
1307
|
}
|
|
1203
1308
|
lines.push("", `> ${this.summary()}`);
|
|
1204
|
-
|
|
1205
|
-
this.push("status", `saved transcript \u2192 ${
|
|
1309
|
+
fs3.writeFileSync(file, lines.join("\n") + "\n");
|
|
1310
|
+
this.push("status", `saved transcript \u2192 ${path5.relative(this.opts.cwd, file)}`);
|
|
1206
1311
|
})();
|
|
1207
1312
|
break;
|
|
1208
1313
|
}
|
|
@@ -1320,6 +1425,57 @@ They are objective defects, not style preferences.`
|
|
|
1320
1425
|
this.push("status", `resumed ${saved.engine} session${saved.lastAsk ? ` \xB7 "${saved.lastAsk}"` : ""}`);
|
|
1321
1426
|
break;
|
|
1322
1427
|
}
|
|
1428
|
+
case "sandbox": {
|
|
1429
|
+
if (this.state.running) {
|
|
1430
|
+
this.push("status", "wait for the current turn before changing sandbox state");
|
|
1431
|
+
break;
|
|
1432
|
+
}
|
|
1433
|
+
if (arg === "diff") {
|
|
1434
|
+
const stat = sandboxDiffStat(this.opts.cwd);
|
|
1435
|
+
if (!stat) {
|
|
1436
|
+
this.push("status", sandboxExists(this.opts.cwd) ? "sandbox is clean" : "no sandbox open \u2014 /sandbox on");
|
|
1437
|
+
} else {
|
|
1438
|
+
this.push("status", `${stat}
|
|
1439
|
+
${sandboxFiles(this.opts.cwd).join("\n")}`);
|
|
1440
|
+
}
|
|
1441
|
+
break;
|
|
1442
|
+
}
|
|
1443
|
+
if (arg === "apply") {
|
|
1444
|
+
const applied = applySandbox(this.opts.cwd);
|
|
1445
|
+
if (applied.ok) {
|
|
1446
|
+
discardSandbox(this.opts.cwd);
|
|
1447
|
+
this.notify({ sandbox: false });
|
|
1448
|
+
this.resetDevServer();
|
|
1449
|
+
this.push("status", "sandbox applied to the real tree \u2014 review with git diff");
|
|
1450
|
+
} else {
|
|
1451
|
+
this.push("error", applied.detail ?? "apply failed");
|
|
1452
|
+
}
|
|
1453
|
+
break;
|
|
1454
|
+
}
|
|
1455
|
+
if (arg === "discard" || arg === "off") {
|
|
1456
|
+
const had = discardSandbox(this.opts.cwd);
|
|
1457
|
+
this.notify({ sandbox: false });
|
|
1458
|
+
this.resetDevServer();
|
|
1459
|
+
this.push("status", had ? "sandbox discarded \u2014 the real tree was never touched" : "no sandbox open");
|
|
1460
|
+
break;
|
|
1461
|
+
}
|
|
1462
|
+
if (arg === "on" || arg === "") {
|
|
1463
|
+
if (!isGitRepo(this.opts.cwd)) {
|
|
1464
|
+
this.push("error", "sandbox needs a git repo with at least one commit");
|
|
1465
|
+
break;
|
|
1466
|
+
}
|
|
1467
|
+
const { reused } = openSandbox(this.opts.cwd);
|
|
1468
|
+
this.notify({ sandbox: true });
|
|
1469
|
+
this.resetDevServer();
|
|
1470
|
+
this.push(
|
|
1471
|
+
"status",
|
|
1472
|
+
`${reused ? "rejoined the open sandbox" : "sandbox opened"} \u2014 asks now accumulate in a shadow worktree; /sandbox diff \xB7 apply \xB7 discard`
|
|
1473
|
+
);
|
|
1474
|
+
break;
|
|
1475
|
+
}
|
|
1476
|
+
this.push("status", "usage: /sandbox [on] \xB7 diff \xB7 apply \xB7 discard");
|
|
1477
|
+
break;
|
|
1478
|
+
}
|
|
1323
1479
|
case "variants": {
|
|
1324
1480
|
const [sub, ...subRest] = arg.split(/\s+/);
|
|
1325
1481
|
if (sub === "apply") {
|
|
@@ -1395,7 +1551,7 @@ They are objective defects, not style preferences.`
|
|
|
1395
1551
|
this.notify({ items: [], totals: { costUsd: 0, turns: 0 } });
|
|
1396
1552
|
break;
|
|
1397
1553
|
case "help": {
|
|
1398
|
-
void import("./commands-
|
|
1554
|
+
void import("./commands-N33DKZKC.js").then(({ commandHelp }) => this.push("status", commandHelp()));
|
|
1399
1555
|
break;
|
|
1400
1556
|
}
|
|
1401
1557
|
case "quit":
|
|
@@ -1925,11 +2081,12 @@ function App({
|
|
|
1925
2081
|
]
|
|
1926
2082
|
}
|
|
1927
2083
|
),
|
|
2084
|
+
state.sandbox && /* @__PURE__ */ jsx3(Text3, { color: theme2.accent, bold: true, children: " [sandbox]" }),
|
|
1928
2085
|
" ",
|
|
1929
2086
|
state.engineId,
|
|
1930
2087
|
state.model ? ` \xB7 ${state.model}` : "",
|
|
1931
2088
|
" \xB7 ",
|
|
1932
|
-
|
|
2089
|
+
path4.basename(cwd),
|
|
1933
2090
|
devBadge,
|
|
1934
2091
|
totalsBadge,
|
|
1935
2092
|
state.problems.length > 0 && /* @__PURE__ */ jsxs3(Text3, { color: theme2.error, children: [
|
|
@@ -1979,7 +2136,7 @@ function registerTui(program2) {
|
|
|
1979
2136
|
}
|
|
1980
2137
|
|
|
1981
2138
|
// src/cli.tsx
|
|
1982
|
-
var VERSION = "0.2.
|
|
2139
|
+
var VERSION = "0.2.8";
|
|
1983
2140
|
var program = new Command();
|
|
1984
2141
|
program.name("squint").description("Lovable for your terminal \u2014 a frontend harness on top of Claude Code, Codex, and friends.").version(VERSION);
|
|
1985
2142
|
registerRun(program);
|
package/package.json
CHANGED