@ccpocket/bridge 1.33.0 → 1.33.2
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/LICENSE +12 -0
- package/README.md +15 -1
- package/dist/codex-process.d.ts +12 -0
- package/dist/codex-process.js +33 -6
- package/dist/codex-process.js.map +1 -1
- package/dist/doctor.js +19 -12
- package/dist/doctor.js.map +1 -1
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -1
- package/dist/path-utils.d.ts +4 -0
- package/dist/path-utils.js +34 -0
- package/dist/path-utils.js.map +1 -0
- package/dist/sdk-process.js.map +1 -1
- package/dist/sessions-index.js +2 -2
- package/dist/sessions-index.js.map +1 -1
- package/dist/websocket.d.ts +2 -0
- package/dist/websocket.js +23 -19
- package/dist/websocket.js.map +1 -1
- package/dist/worktree-store.d.ts +2 -1
- package/dist/worktree-store.js +8 -6
- package/dist/worktree-store.js.map +1 -1
- package/package.json +6 -4
package/dist/websocket.js
CHANGED
|
@@ -20,6 +20,7 @@ import { PushRelayClient } from "./push-relay.js";
|
|
|
20
20
|
import { normalizePushLocale, t } from "./push-i18n.js";
|
|
21
21
|
import { fetchAllUsage } from "./usage.js";
|
|
22
22
|
import { getPackageVersion } from "./version.js";
|
|
23
|
+
import { isPathWithinAllowedDirectory, resolvePlatformPath, } from "./path-utils.js";
|
|
23
24
|
// ---- Available model lists (delivered to clients via session_list) ----
|
|
24
25
|
const CLAUDE_MODELS = [
|
|
25
26
|
"claude-opus-4-6",
|
|
@@ -151,8 +152,9 @@ export class BridgeWebSocketServer {
|
|
|
151
152
|
tokenPrivacyMode = new Map();
|
|
152
153
|
failSetPermissionMode = envFlagEnabled("BRIDGE_FAIL_SET_PERMISSION_MODE");
|
|
153
154
|
failSetSandboxMode = envFlagEnabled("BRIDGE_FAIL_SET_SANDBOX_MODE");
|
|
155
|
+
platform;
|
|
154
156
|
constructor(options) {
|
|
155
|
-
const { server, apiKey, allowedDirs, imageStore, galleryStore, projectHistory, debugTraceStore, recordingStore, firebaseAuth, promptHistoryBackup, } = options;
|
|
157
|
+
const { server, apiKey, allowedDirs, imageStore, galleryStore, projectHistory, debugTraceStore, recordingStore, firebaseAuth, promptHistoryBackup, platform, } = options;
|
|
156
158
|
this.apiKey = apiKey ?? null;
|
|
157
159
|
this.allowedDirs = allowedDirs ?? [];
|
|
158
160
|
this.imageStore = imageStore ?? null;
|
|
@@ -163,6 +165,7 @@ export class BridgeWebSocketServer {
|
|
|
163
165
|
this.worktreeStore = new WorktreeStore();
|
|
164
166
|
this.pushRelay = new PushRelayClient({ firebaseAuth });
|
|
165
167
|
this.promptHistoryBackup = promptHistoryBackup ?? null;
|
|
168
|
+
this.platform = platform ?? process.platform;
|
|
166
169
|
this.archiveStore = new ArchiveStore();
|
|
167
170
|
void this.debugTraceStore.init().catch((err) => {
|
|
168
171
|
console.error("[ws] Failed to initialize debug trace store:", err);
|
|
@@ -218,8 +221,7 @@ export class BridgeWebSocketServer {
|
|
|
218
221
|
isPathAllowed(path) {
|
|
219
222
|
if (this.allowedDirs.length === 0)
|
|
220
223
|
return true;
|
|
221
|
-
|
|
222
|
-
return this.allowedDirs.some((dir) => resolved === dir || resolved.startsWith(dir + "/"));
|
|
224
|
+
return this.allowedDirs.some((dir) => isPathWithinAllowedDirectory(path, dir, this.platform));
|
|
223
225
|
}
|
|
224
226
|
/** Build a user-friendly error for disallowed project paths. */
|
|
225
227
|
buildPathNotAllowedError(projectPath) {
|
|
@@ -385,7 +387,8 @@ export class BridgeWebSocketServer {
|
|
|
385
387
|
}
|
|
386
388
|
switch (msg.type) {
|
|
387
389
|
case "start": {
|
|
388
|
-
|
|
390
|
+
const projectPath = resolvePlatformPath(msg.projectPath, this.platform);
|
|
391
|
+
if (!this.isPathAllowed(projectPath)) {
|
|
389
392
|
this.send(ws, this.buildPathNotAllowedError(msg.projectPath));
|
|
390
393
|
break;
|
|
391
394
|
}
|
|
@@ -414,9 +417,9 @@ export class BridgeWebSocketServer {
|
|
|
414
417
|
console.log(`[ws] start(codex): execution=${executionMode} plan=${planMode}`);
|
|
415
418
|
}
|
|
416
419
|
const cached = provider === "claude"
|
|
417
|
-
? this.sessionManager.getCachedCommands(
|
|
420
|
+
? this.sessionManager.getCachedCommands(projectPath)
|
|
418
421
|
: undefined;
|
|
419
|
-
const sessionId = this.sessionManager.create(
|
|
422
|
+
const sessionId = this.sessionManager.create(projectPath, {
|
|
420
423
|
sessionId: msg.sessionId,
|
|
421
424
|
continueMode: msg.continue,
|
|
422
425
|
permissionMode: legacyPermissionMode,
|
|
@@ -453,11 +456,11 @@ export class BridgeWebSocketServer {
|
|
|
453
456
|
: undefined);
|
|
454
457
|
const createdSession = this.sessionManager.get(sessionId);
|
|
455
458
|
// Load saved session name from CLI storage (for resumed sessions)
|
|
456
|
-
void this.loadAndSetSessionName(createdSession, provider,
|
|
459
|
+
void this.loadAndSetSessionName(createdSession, provider, projectPath, msg.sessionId).then(() => {
|
|
457
460
|
this.send(ws, this.buildSessionCreatedMessage({
|
|
458
461
|
sessionId,
|
|
459
462
|
provider,
|
|
460
|
-
projectPath
|
|
463
|
+
projectPath,
|
|
461
464
|
session: createdSession,
|
|
462
465
|
permissionMode: legacyPermissionMode,
|
|
463
466
|
executionMode,
|
|
@@ -491,14 +494,14 @@ export class BridgeWebSocketServer {
|
|
|
491
494
|
direction: "internal",
|
|
492
495
|
channel: "bridge",
|
|
493
496
|
type: "session_created",
|
|
494
|
-
detail: `provider=${provider} projectPath=${
|
|
497
|
+
detail: `provider=${provider} projectPath=${projectPath}`,
|
|
495
498
|
});
|
|
496
499
|
this.recordingStore?.saveMeta(sessionId, {
|
|
497
500
|
bridgeSessionId: sessionId,
|
|
498
|
-
projectPath
|
|
501
|
+
projectPath,
|
|
499
502
|
createdAt: new Date().toISOString(),
|
|
500
503
|
});
|
|
501
|
-
this.projectHistory?.addProject(
|
|
504
|
+
this.projectHistory?.addProject(projectPath);
|
|
502
505
|
}
|
|
503
506
|
catch (err) {
|
|
504
507
|
console.error(`[ws] Failed to start session:`, err);
|
|
@@ -1481,7 +1484,8 @@ export class BridgeWebSocketServer {
|
|
|
1481
1484
|
}
|
|
1482
1485
|
case "resume_session": {
|
|
1483
1486
|
console.log(`[ws] resume_session: sessionId=${msg.sessionId} projectPath=${msg.projectPath} provider=${msg.provider ?? "claude"}`);
|
|
1484
|
-
|
|
1487
|
+
const resumeProjectPath = resolvePlatformPath(msg.projectPath, this.platform);
|
|
1488
|
+
if (!this.isPathAllowed(resumeProjectPath)) {
|
|
1485
1489
|
this.send(ws, this.buildPathNotAllowedError(msg.projectPath));
|
|
1486
1490
|
break;
|
|
1487
1491
|
}
|
|
@@ -1510,7 +1514,7 @@ export class BridgeWebSocketServer {
|
|
|
1510
1514
|
// via get_history(sessionId) to avoid duplicate/missed replay races.
|
|
1511
1515
|
if (provider === "codex") {
|
|
1512
1516
|
const wtMapping = this.worktreeStore.get(sessionRefId);
|
|
1513
|
-
const effectiveProjectPath = wtMapping?.projectPath ??
|
|
1517
|
+
const effectiveProjectPath = resolvePlatformPath(wtMapping?.projectPath ?? resumeProjectPath, this.platform);
|
|
1514
1518
|
let worktreeOpts;
|
|
1515
1519
|
if (wtMapping) {
|
|
1516
1520
|
if (worktreeExists(wtMapping.worktreePath)) {
|
|
@@ -1576,7 +1580,7 @@ export class BridgeWebSocketServer {
|
|
|
1576
1580
|
break;
|
|
1577
1581
|
}
|
|
1578
1582
|
const claudeSessionId = sessionRefId;
|
|
1579
|
-
const cached = this.sessionManager.getCachedCommands(
|
|
1583
|
+
const cached = this.sessionManager.getCachedCommands(resumeProjectPath);
|
|
1580
1584
|
// Look up worktree mapping for this Claude session
|
|
1581
1585
|
const wtMapping = this.worktreeStore.get(claudeSessionId);
|
|
1582
1586
|
let worktreeOpts;
|
|
@@ -1598,7 +1602,7 @@ export class BridgeWebSocketServer {
|
|
|
1598
1602
|
}
|
|
1599
1603
|
getSessionHistory(claudeSessionId)
|
|
1600
1604
|
.then((pastMessages) => {
|
|
1601
|
-
const sessionId = this.sessionManager.create(
|
|
1605
|
+
const sessionId = this.sessionManager.create(resumeProjectPath, {
|
|
1602
1606
|
sessionId: claudeSessionId,
|
|
1603
1607
|
permissionMode: legacyPermissionMode,
|
|
1604
1608
|
model: msg.model,
|
|
@@ -1613,12 +1617,12 @@ export class BridgeWebSocketServer {
|
|
|
1613
1617
|
: {}),
|
|
1614
1618
|
}, pastMessages, worktreeOpts);
|
|
1615
1619
|
const createdSession = this.sessionManager.get(sessionId);
|
|
1616
|
-
void this.loadAndSetSessionName(createdSession, "claude",
|
|
1620
|
+
void this.loadAndSetSessionName(createdSession, "claude", resumeProjectPath, claudeSessionId).then(() => {
|
|
1617
1621
|
this.send(ws, {
|
|
1618
1622
|
...this.buildSessionCreatedMessage({
|
|
1619
1623
|
sessionId,
|
|
1620
1624
|
provider: "claude",
|
|
1621
|
-
projectPath:
|
|
1625
|
+
projectPath: resumeProjectPath,
|
|
1622
1626
|
session: createdSession,
|
|
1623
1627
|
permissionMode: legacyPermissionMode,
|
|
1624
1628
|
executionMode,
|
|
@@ -1645,7 +1649,7 @@ export class BridgeWebSocketServer {
|
|
|
1645
1649
|
type: "session_resumed",
|
|
1646
1650
|
detail: `provider=claude session=${claudeSessionId}`,
|
|
1647
1651
|
});
|
|
1648
|
-
this.projectHistory?.addProject(
|
|
1652
|
+
this.projectHistory?.addProject(resumeProjectPath);
|
|
1649
1653
|
})
|
|
1650
1654
|
.catch((err) => {
|
|
1651
1655
|
this.send(ws, {
|
|
@@ -3333,7 +3337,7 @@ export class BridgeWebSocketServer {
|
|
|
3333
3337
|
else {
|
|
3334
3338
|
const absPath = resolve(cwd, filePath);
|
|
3335
3339
|
// Verify resolved path stays within cwd
|
|
3336
|
-
if (!absPath
|
|
3340
|
+
if (!isPathWithinAllowedDirectory(absPath, cwd, this.platform)) {
|
|
3337
3341
|
return { error: "Invalid file path" };
|
|
3338
3342
|
}
|
|
3339
3343
|
buf = await readFile(absPath);
|