@ccpocket/bridge 1.6.0 → 1.7.0
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.js +14 -2
- package/dist/cli.js.map +1 -1
- package/dist/doctor.d.ts +49 -0
- package/dist/doctor.js +517 -0
- package/dist/doctor.js.map +1 -0
- package/dist/parser.d.ts +30 -0
- package/dist/parser.js +8 -0
- package/dist/parser.js.map +1 -1
- package/dist/websocket.d.ts +21 -0
- package/dist/websocket.js +214 -3
- package/dist/websocket.js.map +1 -1
- package/dist/worktree.d.ts +2 -0
- package/dist/worktree.js +13 -0
- package/dist/worktree.js.map +1 -1
- package/package.json +3 -2
package/dist/parser.d.ts
CHANGED
|
@@ -146,6 +146,11 @@ export type ClientMessage = {
|
|
|
146
146
|
} | {
|
|
147
147
|
type: "get_diff";
|
|
148
148
|
projectPath: string;
|
|
149
|
+
} | {
|
|
150
|
+
type: "get_diff_image";
|
|
151
|
+
projectPath: string;
|
|
152
|
+
filePath: string;
|
|
153
|
+
version: "old" | "new";
|
|
149
154
|
} | {
|
|
150
155
|
type: "interrupt";
|
|
151
156
|
sessionId?: string;
|
|
@@ -209,6 +214,22 @@ export type ClientMessage = {
|
|
|
209
214
|
provider: Provider;
|
|
210
215
|
projectPath: string;
|
|
211
216
|
};
|
|
217
|
+
/** Image change detected in a git diff (binary image file). */
|
|
218
|
+
export interface ImageChange {
|
|
219
|
+
filePath: string;
|
|
220
|
+
isNew: boolean;
|
|
221
|
+
isDeleted: boolean;
|
|
222
|
+
isSvg: boolean;
|
|
223
|
+
oldSize?: number;
|
|
224
|
+
newSize?: number;
|
|
225
|
+
/** Base64-encoded old image (included only when size ≤ 200KB). */
|
|
226
|
+
oldBase64?: string;
|
|
227
|
+
/** Base64-encoded new image (included only when size ≤ 200KB). */
|
|
228
|
+
newBase64?: string;
|
|
229
|
+
mimeType: string;
|
|
230
|
+
/** Whether the image can be loaded on demand (200KB–2MB range). */
|
|
231
|
+
loadable: boolean;
|
|
232
|
+
}
|
|
212
233
|
export interface DebugTraceEvent {
|
|
213
234
|
ts: string;
|
|
214
235
|
sessionId: string;
|
|
@@ -289,9 +310,18 @@ export type ServerMessage = {
|
|
|
289
310
|
type: "diff_result";
|
|
290
311
|
diff: string;
|
|
291
312
|
error?: string;
|
|
313
|
+
imageChanges?: ImageChange[];
|
|
314
|
+
} | {
|
|
315
|
+
type: "diff_image_result";
|
|
316
|
+
filePath: string;
|
|
317
|
+
version: "old" | "new";
|
|
318
|
+
base64?: string;
|
|
319
|
+
mimeType?: string;
|
|
320
|
+
error?: string;
|
|
292
321
|
} | {
|
|
293
322
|
type: "worktree_list";
|
|
294
323
|
worktrees: WorktreeInfo[];
|
|
324
|
+
mainBranch?: string;
|
|
295
325
|
} | {
|
|
296
326
|
type: "worktree_removed";
|
|
297
327
|
worktreePath: string;
|
package/dist/parser.js
CHANGED
|
@@ -151,6 +151,14 @@ export function parseClientMessage(data) {
|
|
|
151
151
|
if (typeof msg.projectPath !== "string")
|
|
152
152
|
return null;
|
|
153
153
|
break;
|
|
154
|
+
case "get_diff_image":
|
|
155
|
+
if (typeof msg.projectPath !== "string")
|
|
156
|
+
return null;
|
|
157
|
+
if (typeof msg.filePath !== "string")
|
|
158
|
+
return null;
|
|
159
|
+
if (msg.version !== "old" && msg.version !== "new")
|
|
160
|
+
return null;
|
|
161
|
+
break;
|
|
154
162
|
case "interrupt":
|
|
155
163
|
break;
|
|
156
164
|
case "list_project_history":
|
package/dist/parser.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parser.js","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"parser.js","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"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"}
|
package/dist/websocket.d.ts
CHANGED
|
@@ -78,6 +78,27 @@ export declare class BridgeWebSocketServer {
|
|
|
78
78
|
/** Broadcast a gallery_new_image message to all connected clients. */
|
|
79
79
|
broadcastGalleryNewImage(image: import("./gallery-store.js").GalleryImageInfo): void;
|
|
80
80
|
private collectGitDiff;
|
|
81
|
+
private static readonly IMAGE_EXTENSIONS;
|
|
82
|
+
private static readonly AUTO_DISPLAY_THRESHOLD;
|
|
83
|
+
private static readonly MAX_IMAGE_SIZE;
|
|
84
|
+
private static mimeTypeForExt;
|
|
85
|
+
/**
|
|
86
|
+
* Scan diff text for image file changes and extract base64 data where appropriate.
|
|
87
|
+
*
|
|
88
|
+
* Detection strategy:
|
|
89
|
+
* 1. Binary markers: "Binary files a/<path> and b/<path> differ"
|
|
90
|
+
* 2. diff --git headers where the file extension is an image type
|
|
91
|
+
*
|
|
92
|
+
* For each detected image file:
|
|
93
|
+
* - Old version: `git show HEAD:<path>` (committed version)
|
|
94
|
+
* - New version: read from working tree
|
|
95
|
+
* - Apply size thresholds for auto-display / on-demand / text-only
|
|
96
|
+
*/
|
|
97
|
+
private collectImageChanges;
|
|
98
|
+
/**
|
|
99
|
+
* Load a single diff image on demand (for images between auto-display and max thresholds).
|
|
100
|
+
*/
|
|
101
|
+
private loadDiffImage;
|
|
81
102
|
private extractSessionIdFromClientMessage;
|
|
82
103
|
private extractSessionIdFromServerMessage;
|
|
83
104
|
private recordDebugEvent;
|
package/dist/websocket.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { execFile, execFileSync } from "node:child_process";
|
|
2
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
2
3
|
import { unlink } from "node:fs/promises";
|
|
4
|
+
import { resolve, extname } from "node:path";
|
|
3
5
|
import { WebSocketServer, WebSocket } from "ws";
|
|
4
6
|
import { SessionManager } from "./session.js";
|
|
5
7
|
import { SdkProcess } from "./sdk-process.js";
|
|
@@ -7,7 +9,7 @@ import { parseClientMessage } from "./parser.js";
|
|
|
7
9
|
import { getAllRecentSessions, getCodexSessionHistory, getSessionHistory, findSessionsByClaudeIds, extractMessageImages, getClaudeSessionName, loadCodexSessionNames, renameClaudeSession, renameCodexSession } from "./sessions-index.js";
|
|
8
10
|
import { ArchiveStore } from "./archive-store.js";
|
|
9
11
|
import { WorktreeStore } from "./worktree-store.js";
|
|
10
|
-
import { listWorktrees, removeWorktree, worktreeExists } from "./worktree.js";
|
|
12
|
+
import { listWorktrees, removeWorktree, worktreeExists, getMainBranch } from "./worktree.js";
|
|
11
13
|
import { listWindows, takeScreenshot } from "./screenshot.js";
|
|
12
14
|
import { DebugTraceStore } from "./debug-trace-store.js";
|
|
13
15
|
import { RecordingStore } from "./recording-store.js";
|
|
@@ -247,10 +249,26 @@ export class BridgeWebSocketServer {
|
|
|
247
249
|
// otherwise lack them. This ensures get_history responses include user
|
|
248
250
|
// messages and replaceEntries on the client side preserves them.
|
|
249
251
|
// We do NOT broadcast this back — Flutter already shows it via sendMessage().
|
|
252
|
+
//
|
|
253
|
+
// Register images in the image store so they can be served via HTTP
|
|
254
|
+
// when the client re-enters the session and loads history.
|
|
255
|
+
let imageRefs;
|
|
256
|
+
if (images.length > 0 && this.imageStore) {
|
|
257
|
+
imageRefs = [];
|
|
258
|
+
for (const img of images) {
|
|
259
|
+
const ref = this.imageStore.registerFromBase64(img.base64, img.mimeType);
|
|
260
|
+
if (ref)
|
|
261
|
+
imageRefs.push(ref);
|
|
262
|
+
}
|
|
263
|
+
if (imageRefs.length === 0)
|
|
264
|
+
imageRefs = undefined;
|
|
265
|
+
}
|
|
250
266
|
session.history.push({
|
|
251
267
|
type: "user_input",
|
|
252
268
|
text,
|
|
269
|
+
timestamp: new Date().toISOString(),
|
|
253
270
|
...(images.length > 0 ? { imageCount: images.length } : {}),
|
|
271
|
+
...(imageRefs ? { images: imageRefs } : {}),
|
|
254
272
|
});
|
|
255
273
|
// Persist images to Gallery Store asynchronously (fire-and-forget)
|
|
256
274
|
if (images.length > 0 && this.galleryStore && session.projectPath) {
|
|
@@ -943,14 +961,27 @@ export class BridgeWebSocketServer {
|
|
|
943
961
|
this.send(ws, { type: "diff_result", diff: "", error: `Failed to get diff: ${error}` });
|
|
944
962
|
return;
|
|
945
963
|
}
|
|
946
|
-
this.
|
|
964
|
+
void this.collectImageChanges(msg.projectPath, diff).then((imageChanges) => {
|
|
965
|
+
if (imageChanges.length > 0) {
|
|
966
|
+
this.send(ws, { type: "diff_result", diff, imageChanges });
|
|
967
|
+
}
|
|
968
|
+
else {
|
|
969
|
+
this.send(ws, { type: "diff_result", diff });
|
|
970
|
+
}
|
|
971
|
+
});
|
|
947
972
|
});
|
|
948
973
|
break;
|
|
949
974
|
}
|
|
975
|
+
case "get_diff_image": {
|
|
976
|
+
const result = this.loadDiffImage(msg.projectPath, msg.filePath, msg.version);
|
|
977
|
+
this.send(ws, { type: "diff_image_result", filePath: msg.filePath, version: msg.version, ...result });
|
|
978
|
+
break;
|
|
979
|
+
}
|
|
950
980
|
case "list_worktrees": {
|
|
951
981
|
try {
|
|
952
982
|
const worktrees = listWorktrees(msg.projectPath);
|
|
953
|
-
|
|
983
|
+
const mainBranch = getMainBranch(msg.projectPath);
|
|
984
|
+
this.send(ws, { type: "worktree_list", worktrees, mainBranch });
|
|
954
985
|
}
|
|
955
986
|
catch (err) {
|
|
956
987
|
this.send(ws, { type: "error", message: `Failed to list worktrees: ${err}` });
|
|
@@ -1526,6 +1557,186 @@ export class BridgeWebSocketServer {
|
|
|
1526
1557
|
callback({ diff: stdout });
|
|
1527
1558
|
});
|
|
1528
1559
|
}
|
|
1560
|
+
// ---------------------------------------------------------------------------
|
|
1561
|
+
// Image diff helpers
|
|
1562
|
+
// ---------------------------------------------------------------------------
|
|
1563
|
+
static IMAGE_EXTENSIONS = new Set([
|
|
1564
|
+
".png", ".jpg", ".jpeg", ".gif", ".webp", ".ico", ".bmp", ".svg",
|
|
1565
|
+
]);
|
|
1566
|
+
// Image diff thresholds (configurable via environment variables)
|
|
1567
|
+
// - Auto-display: images ≤ threshold are sent inline as base64
|
|
1568
|
+
// - Max size: images ≤ max are available for on-demand loading
|
|
1569
|
+
// - Images > max size show text info only
|
|
1570
|
+
static AUTO_DISPLAY_THRESHOLD = (() => {
|
|
1571
|
+
const kb = parseInt(process.env.DIFF_IMAGE_AUTO_DISPLAY_KB ?? "", 10);
|
|
1572
|
+
return Number.isFinite(kb) && kb > 0 ? kb * 1024 : 1024 * 1024; // default 1 MB
|
|
1573
|
+
})();
|
|
1574
|
+
static MAX_IMAGE_SIZE = (() => {
|
|
1575
|
+
const mb = parseInt(process.env.DIFF_IMAGE_MAX_SIZE_MB ?? "", 10);
|
|
1576
|
+
return Number.isFinite(mb) && mb > 0 ? mb * 1024 * 1024 : 5 * 1024 * 1024; // default 5 MB
|
|
1577
|
+
})();
|
|
1578
|
+
static mimeTypeForExt(ext) {
|
|
1579
|
+
const map = {
|
|
1580
|
+
".png": "image/png",
|
|
1581
|
+
".jpg": "image/jpeg",
|
|
1582
|
+
".jpeg": "image/jpeg",
|
|
1583
|
+
".gif": "image/gif",
|
|
1584
|
+
".webp": "image/webp",
|
|
1585
|
+
".ico": "image/x-icon",
|
|
1586
|
+
".bmp": "image/bmp",
|
|
1587
|
+
".svg": "image/svg+xml",
|
|
1588
|
+
};
|
|
1589
|
+
return map[ext.toLowerCase()] ?? "application/octet-stream";
|
|
1590
|
+
}
|
|
1591
|
+
/**
|
|
1592
|
+
* Scan diff text for image file changes and extract base64 data where appropriate.
|
|
1593
|
+
*
|
|
1594
|
+
* Detection strategy:
|
|
1595
|
+
* 1. Binary markers: "Binary files a/<path> and b/<path> differ"
|
|
1596
|
+
* 2. diff --git headers where the file extension is an image type
|
|
1597
|
+
*
|
|
1598
|
+
* For each detected image file:
|
|
1599
|
+
* - Old version: `git show HEAD:<path>` (committed version)
|
|
1600
|
+
* - New version: read from working tree
|
|
1601
|
+
* - Apply size thresholds for auto-display / on-demand / text-only
|
|
1602
|
+
*/
|
|
1603
|
+
async collectImageChanges(cwd, diffText) {
|
|
1604
|
+
const entries = [];
|
|
1605
|
+
const processedPaths = new Set();
|
|
1606
|
+
const lines = diffText.split("\n");
|
|
1607
|
+
for (let i = 0; i < lines.length; i++) {
|
|
1608
|
+
const line = lines[i];
|
|
1609
|
+
const gitMatch = line.match(/^diff --git a\/(.+?) b\/(.+)$/);
|
|
1610
|
+
if (!gitMatch)
|
|
1611
|
+
continue;
|
|
1612
|
+
const filePath = gitMatch[2];
|
|
1613
|
+
const ext = extname(filePath).toLowerCase();
|
|
1614
|
+
if (!BridgeWebSocketServer.IMAGE_EXTENSIONS.has(ext))
|
|
1615
|
+
continue;
|
|
1616
|
+
if (processedPaths.has(filePath))
|
|
1617
|
+
continue;
|
|
1618
|
+
processedPaths.add(filePath);
|
|
1619
|
+
let isNew = false;
|
|
1620
|
+
let isDeleted = false;
|
|
1621
|
+
for (let j = i + 1; j < Math.min(i + 6, lines.length); j++) {
|
|
1622
|
+
if (lines[j].startsWith("diff --git "))
|
|
1623
|
+
break;
|
|
1624
|
+
if (lines[j].startsWith("new file mode"))
|
|
1625
|
+
isNew = true;
|
|
1626
|
+
if (lines[j].startsWith("deleted file mode"))
|
|
1627
|
+
isDeleted = true;
|
|
1628
|
+
}
|
|
1629
|
+
entries.push({
|
|
1630
|
+
filePath,
|
|
1631
|
+
isNew,
|
|
1632
|
+
isDeleted,
|
|
1633
|
+
isSvg: ext === ".svg",
|
|
1634
|
+
mimeType: BridgeWebSocketServer.mimeTypeForExt(ext),
|
|
1635
|
+
ext,
|
|
1636
|
+
});
|
|
1637
|
+
}
|
|
1638
|
+
if (entries.length === 0)
|
|
1639
|
+
return [];
|
|
1640
|
+
// Phase 2: Read image data asynchronously
|
|
1641
|
+
const { readFile } = await import("node:fs/promises");
|
|
1642
|
+
const { promisify } = await import("node:util");
|
|
1643
|
+
const execFileAsync = promisify(execFile);
|
|
1644
|
+
const changes = [];
|
|
1645
|
+
for (const entry of entries) {
|
|
1646
|
+
let oldBuf;
|
|
1647
|
+
let newBuf;
|
|
1648
|
+
// Read old image (committed version)
|
|
1649
|
+
if (!entry.isNew) {
|
|
1650
|
+
try {
|
|
1651
|
+
const result = await execFileAsync("git", ["show", `HEAD:${entry.filePath}`], {
|
|
1652
|
+
cwd,
|
|
1653
|
+
maxBuffer: BridgeWebSocketServer.MAX_IMAGE_SIZE + 1024,
|
|
1654
|
+
encoding: "buffer",
|
|
1655
|
+
});
|
|
1656
|
+
oldBuf = result.stdout;
|
|
1657
|
+
}
|
|
1658
|
+
catch {
|
|
1659
|
+
// File may not exist in HEAD (e.g. untracked)
|
|
1660
|
+
}
|
|
1661
|
+
}
|
|
1662
|
+
// Read new image (working tree)
|
|
1663
|
+
if (!entry.isDeleted) {
|
|
1664
|
+
try {
|
|
1665
|
+
const absPath = resolve(cwd, entry.filePath);
|
|
1666
|
+
if (existsSync(absPath)) {
|
|
1667
|
+
newBuf = await readFile(absPath);
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1670
|
+
catch {
|
|
1671
|
+
// Ignore read errors
|
|
1672
|
+
}
|
|
1673
|
+
}
|
|
1674
|
+
const oldSize = oldBuf?.length;
|
|
1675
|
+
const newSize = newBuf?.length;
|
|
1676
|
+
const maxSize = Math.max(oldSize ?? 0, newSize ?? 0);
|
|
1677
|
+
const autoDisplay = maxSize <= BridgeWebSocketServer.AUTO_DISPLAY_THRESHOLD;
|
|
1678
|
+
const loadable = !autoDisplay && maxSize <= BridgeWebSocketServer.MAX_IMAGE_SIZE;
|
|
1679
|
+
const change = {
|
|
1680
|
+
filePath: entry.filePath,
|
|
1681
|
+
isNew: entry.isNew,
|
|
1682
|
+
isDeleted: entry.isDeleted,
|
|
1683
|
+
isSvg: entry.isSvg,
|
|
1684
|
+
mimeType: entry.mimeType,
|
|
1685
|
+
loadable,
|
|
1686
|
+
};
|
|
1687
|
+
if (oldSize !== undefined)
|
|
1688
|
+
change.oldSize = oldSize;
|
|
1689
|
+
if (newSize !== undefined)
|
|
1690
|
+
change.newSize = newSize;
|
|
1691
|
+
if (autoDisplay) {
|
|
1692
|
+
if (oldBuf)
|
|
1693
|
+
change.oldBase64 = oldBuf.toString("base64");
|
|
1694
|
+
if (newBuf)
|
|
1695
|
+
change.newBase64 = newBuf.toString("base64");
|
|
1696
|
+
}
|
|
1697
|
+
changes.push(change);
|
|
1698
|
+
}
|
|
1699
|
+
return changes;
|
|
1700
|
+
}
|
|
1701
|
+
/**
|
|
1702
|
+
* Load a single diff image on demand (for images between auto-display and max thresholds).
|
|
1703
|
+
*/
|
|
1704
|
+
loadDiffImage(cwd, filePath, version) {
|
|
1705
|
+
// Path traversal guard: reject paths containing '..' or absolute paths
|
|
1706
|
+
if (filePath.includes("..") || filePath.startsWith("/")) {
|
|
1707
|
+
return { error: "Invalid file path" };
|
|
1708
|
+
}
|
|
1709
|
+
const ext = extname(filePath).toLowerCase();
|
|
1710
|
+
if (!BridgeWebSocketServer.IMAGE_EXTENSIONS.has(ext)) {
|
|
1711
|
+
return { error: "Not an image file" };
|
|
1712
|
+
}
|
|
1713
|
+
const mimeType = BridgeWebSocketServer.mimeTypeForExt(ext);
|
|
1714
|
+
try {
|
|
1715
|
+
let buf;
|
|
1716
|
+
if (version === "old") {
|
|
1717
|
+
buf = execFileSync("git", ["show", `HEAD:${filePath}`], {
|
|
1718
|
+
cwd,
|
|
1719
|
+
maxBuffer: BridgeWebSocketServer.MAX_IMAGE_SIZE + 1024,
|
|
1720
|
+
encoding: "buffer",
|
|
1721
|
+
});
|
|
1722
|
+
}
|
|
1723
|
+
else {
|
|
1724
|
+
const absPath = resolve(cwd, filePath);
|
|
1725
|
+
// Verify resolved path stays within cwd
|
|
1726
|
+
if (!absPath.startsWith(resolve(cwd) + "/")) {
|
|
1727
|
+
return { error: "Invalid file path" };
|
|
1728
|
+
}
|
|
1729
|
+
buf = readFileSync(absPath);
|
|
1730
|
+
}
|
|
1731
|
+
if (buf.length > BridgeWebSocketServer.MAX_IMAGE_SIZE) {
|
|
1732
|
+
return { error: "Image too large" };
|
|
1733
|
+
}
|
|
1734
|
+
return { base64: buf.toString("base64"), mimeType };
|
|
1735
|
+
}
|
|
1736
|
+
catch (err) {
|
|
1737
|
+
return { error: err instanceof Error ? err.message : String(err) };
|
|
1738
|
+
}
|
|
1739
|
+
}
|
|
1529
1740
|
extractSessionIdFromClientMessage(msg) {
|
|
1530
1741
|
return "sessionId" in msg && typeof msg.sessionId === "string" ? msg.sessionId : undefined;
|
|
1531
1742
|
}
|