glassbox 0.12.0-beta.2 → 0.12.0-beta.3
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 +1 -1
- package/dist/cli-difftool.js +39 -13
- package/dist/cli.js +12 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -299,7 +299,7 @@ git difftool HEAD~1 HEAD # step through changed files one at a time
|
|
|
299
299
|
|
|
300
300
|
When you're finished, click **Done** in the review (a difftool session shows this instead of the normal completion flow) — the `git difftool` command returns to your prompt cleanly, no Ctrl-C needed. Closing the browser tab ends the session too.
|
|
301
301
|
|
|
302
|
-
**Desktop vs browser:**
|
|
302
|
+
**Desktop vs browser:** the accumulating model is the same either way — only the window differs. In a browser (npm) install the review opens in a tab; if the desktop app is installed, it opens in one Glassbox window (matching what `glassbox --commit` does from the same folder) on macOS, Linux, and Windows, and per-file mode accumulates into that single window just like the browser. Closing the window ends the session.
|
|
303
303
|
|
|
304
304
|
**Under the hood:** `git difftool --dir-diff` materializes its two snapshot directories asymmetrically — the right side is symlinks pointing into your working tree, which trips up plain `git diff --no-index`. `glassbox-difftool` dereferences those symlinks into a temp tree before handing the dirs to `glassbox --diff`, then cleans up when the session ends. In per-file mode the wrapper reads each file's content before it returns (git deletes the temp files the instant the tool exits) and POSTs it to the accumulating server; the last file holds the connection open so `git difftool` stays attached until you click Done. Without the wrapper you'd see every modified file show up as a "deleted + added" pair instead of a modified entry, and per-file mode would hang waiting for a manual Ctrl-C between files.
|
|
305
305
|
|
package/dist/cli-difftool.js
CHANGED
|
@@ -14590,6 +14590,7 @@ function tryAcquireStartingLock(home = difftoolHome()) {
|
|
|
14590
14590
|
|
|
14591
14591
|
// src/git/difftool-client.ts
|
|
14592
14592
|
var DISCOVER_TIMEOUT_MS = 15 * 1e3;
|
|
14593
|
+
var DESKTOP_DISCOVER_TIMEOUT_MS = 30 * 1e3;
|
|
14593
14594
|
var PROBE_INTERVAL_MS = 150;
|
|
14594
14595
|
function delay(ms) {
|
|
14595
14596
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -14609,7 +14610,7 @@ async function ping(port) {
|
|
|
14609
14610
|
return false;
|
|
14610
14611
|
}
|
|
14611
14612
|
}
|
|
14612
|
-
function
|
|
14613
|
+
function spawnDetachedBrowserServer(cliPath, cwd) {
|
|
14613
14614
|
const child = spawn(process.execPath, [cliPath, "--difftool-serve"], {
|
|
14614
14615
|
cwd,
|
|
14615
14616
|
detached: true,
|
|
@@ -14617,8 +14618,22 @@ function spawnDetachedServer(cliPath, cwd) {
|
|
|
14617
14618
|
});
|
|
14618
14619
|
child.unref();
|
|
14619
14620
|
}
|
|
14620
|
-
|
|
14621
|
-
|
|
14621
|
+
function launchDetachedDesktopSession(launcher, cwd) {
|
|
14622
|
+
if (process.platform === "win32") {
|
|
14623
|
+
const child = spawn(`"${launcher}" --difftool-serve`, {
|
|
14624
|
+
cwd,
|
|
14625
|
+
detached: true,
|
|
14626
|
+
stdio: "ignore",
|
|
14627
|
+
shell: true
|
|
14628
|
+
});
|
|
14629
|
+
child.unref();
|
|
14630
|
+
} else {
|
|
14631
|
+
const child = spawn(launcher, ["--difftool-serve"], { cwd, detached: true, stdio: "ignore" });
|
|
14632
|
+
child.unref();
|
|
14633
|
+
}
|
|
14634
|
+
}
|
|
14635
|
+
async function discoverOrStartServer(startServer, timeoutMs = DISCOVER_TIMEOUT_MS) {
|
|
14636
|
+
const deadline = Date.now() + timeoutMs;
|
|
14622
14637
|
let startedByUs = false;
|
|
14623
14638
|
while (Date.now() < deadline) {
|
|
14624
14639
|
const discovery = readDiscovery();
|
|
@@ -14627,7 +14642,7 @@ async function discoverOrStartServer(cliPath, cwd) {
|
|
|
14627
14642
|
}
|
|
14628
14643
|
if (!startedByUs && tryAcquireStartingLock()) {
|
|
14629
14644
|
startedByUs = true;
|
|
14630
|
-
|
|
14645
|
+
startServer();
|
|
14631
14646
|
}
|
|
14632
14647
|
await delay(PROBE_INTERVAL_MS);
|
|
14633
14648
|
}
|
|
@@ -14752,11 +14767,11 @@ function readFileOrEmpty(p) {
|
|
|
14752
14767
|
return Buffer.alloc(0);
|
|
14753
14768
|
}
|
|
14754
14769
|
}
|
|
14755
|
-
async function runThinClient(
|
|
14770
|
+
async function runThinClient(start, timeoutMs) {
|
|
14756
14771
|
const oldContent = readFileOrEmpty(local);
|
|
14757
14772
|
const newContent = readFileOrEmpty(remote);
|
|
14758
14773
|
const displayPath = merged || basename(remote) || basename(local) || "file";
|
|
14759
|
-
const port = await discoverOrStartServer(
|
|
14774
|
+
const port = await discoverOrStartServer(start, timeoutMs);
|
|
14760
14775
|
await appendFile(port, displayPath, oldContent, newContent);
|
|
14761
14776
|
if (shouldHoldForSession(process.env)) {
|
|
14762
14777
|
await holdUntilEnd(port);
|
|
@@ -14799,16 +14814,27 @@ function runBlockingLaunch() {
|
|
|
14799
14814
|
cleanup();
|
|
14800
14815
|
}
|
|
14801
14816
|
}
|
|
14817
|
+
var onThinClientDone = () => process.exit(0);
|
|
14818
|
+
var onThinClientError = (err) => {
|
|
14819
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
14820
|
+
return process.exit(1);
|
|
14821
|
+
};
|
|
14802
14822
|
if (localIsFile && target.kind === "browser") {
|
|
14803
|
-
|
|
14823
|
+
const cliPath = target.cli;
|
|
14824
|
+
void runThinClient(() => {
|
|
14825
|
+
spawnDetachedBrowserServer(cliPath, process.cwd());
|
|
14826
|
+
}).then(
|
|
14827
|
+
onThinClientDone,
|
|
14828
|
+
onThinClientError
|
|
14829
|
+
);
|
|
14830
|
+
} else if (localIsFile && target.kind === "desktop") {
|
|
14831
|
+
const launcher = target.launcher;
|
|
14832
|
+
void runThinClient(
|
|
14804
14833
|
() => {
|
|
14805
|
-
process.
|
|
14834
|
+
launchDetachedDesktopSession(launcher, process.cwd());
|
|
14806
14835
|
},
|
|
14807
|
-
|
|
14808
|
-
|
|
14809
|
-
process.exit(1);
|
|
14810
|
-
}
|
|
14811
|
-
);
|
|
14836
|
+
DESKTOP_DISCOVER_TIMEOUT_MS
|
|
14837
|
+
).then(onThinClientDone, onThinClientError);
|
|
14812
14838
|
} else {
|
|
14813
14839
|
runBlockingLaunch();
|
|
14814
14840
|
}
|
package/dist/cli.js
CHANGED
|
@@ -17019,8 +17019,15 @@ import { basename, dirname, join as join3, resolve } from "path";
|
|
|
17019
17019
|
|
|
17020
17020
|
// src/git/repo.ts
|
|
17021
17021
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
17022
|
+
function scrubbedGitEnv() {
|
|
17023
|
+
const env = { ...process.env };
|
|
17024
|
+
delete env.GIT_EXTERNAL_DIFF;
|
|
17025
|
+
delete env.GIT_DIFF_PATH_COUNTER;
|
|
17026
|
+
delete env.GIT_DIFF_PATH_TOTAL;
|
|
17027
|
+
return env;
|
|
17028
|
+
}
|
|
17022
17029
|
function git(args, cwd) {
|
|
17023
|
-
const result = spawnSync3("git", args, { cwd, encoding: "utf-8", maxBuffer: 50 * 1024 * 1024 });
|
|
17030
|
+
const result = spawnSync3("git", args, { cwd, encoding: "utf-8", maxBuffer: 50 * 1024 * 1024, env: scrubbedGitEnv() });
|
|
17024
17031
|
if (result.status === 0) return result.stdout;
|
|
17025
17032
|
if (result.stdout !== "") return result.stdout;
|
|
17026
17033
|
const err = new Error(result.stderr);
|
|
@@ -17045,7 +17052,7 @@ function isGitRepo(cwd) {
|
|
|
17045
17052
|
}
|
|
17046
17053
|
}
|
|
17047
17054
|
function getHeadCommit(cwd) {
|
|
17048
|
-
return spawnSync3("git", ["rev-parse", "HEAD"], { cwd, encoding: "utf-8" }).stdout.trim();
|
|
17055
|
+
return spawnSync3("git", ["rev-parse", "HEAD"], { cwd, encoding: "utf-8", env: scrubbedGitEnv() }).stdout.trim();
|
|
17049
17056
|
}
|
|
17050
17057
|
|
|
17051
17058
|
// src/git/types.ts
|
|
@@ -17096,7 +17103,7 @@ function parseDiffData(raw) {
|
|
|
17096
17103
|
// src/git/diff.ts
|
|
17097
17104
|
var toGitArg = (p) => process.platform === "win32" ? p.replace(/\\/g, "/") : p;
|
|
17098
17105
|
function git2(args, cwd) {
|
|
17099
|
-
const result = spawnSync4("git", args, { cwd, encoding: "utf-8", maxBuffer: 50 * 1024 * 1024 });
|
|
17106
|
+
const result = spawnSync4("git", args, { cwd, encoding: "utf-8", maxBuffer: 50 * 1024 * 1024, env: scrubbedGitEnv() });
|
|
17100
17107
|
if (result.status === 0) return result.stdout;
|
|
17101
17108
|
if (result.stdout !== "") return result.stdout;
|
|
17102
17109
|
const err = new Error(result.stderr);
|
|
@@ -21050,7 +21057,7 @@ function getNewRef(mode) {
|
|
|
21050
21057
|
}
|
|
21051
21058
|
function gitShowFile(ref, filePath, repoRoot) {
|
|
21052
21059
|
const spec = ref === ":" ? `:${filePath}` : `${ref}:${filePath}`;
|
|
21053
|
-
const result = spawnSync6("git", ["show", spec], { cwd: repoRoot, maxBuffer: 50 * 1024 * 1024 });
|
|
21060
|
+
const result = spawnSync6("git", ["show", spec], { cwd: repoRoot, maxBuffer: 50 * 1024 * 1024, env: scrubbedGitEnv() });
|
|
21054
21061
|
if (result.status !== 0 || result.stdout.length === 0) return null;
|
|
21055
21062
|
return result.stdout;
|
|
21056
21063
|
}
|
|
@@ -23810,7 +23817,7 @@ async function main() {
|
|
|
23810
23817
|
console.log("AI service test mode enabled \u2014 using mock AI responses");
|
|
23811
23818
|
}
|
|
23812
23819
|
if (debug) {
|
|
23813
|
-
console.log(`[debug] Build timestamp: ${"2026-06-
|
|
23820
|
+
console.log(`[debug] Build timestamp: ${"2026-06-04T01:28:18.249Z"}`);
|
|
23814
23821
|
}
|
|
23815
23822
|
if (projectDir !== null) {
|
|
23816
23823
|
process.chdir(projectDir);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "glassbox",
|
|
3
|
-
"version": "0.12.0-beta.
|
|
3
|
+
"version": "0.12.0-beta.3",
|
|
4
4
|
"description": "A local code review tool for AI-generated code. Review diffs, annotate lines, and export structured feedback that AI tools can act on.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|