@ccpocket/bridge 0.1.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/README.md +54 -0
- package/dist/claude-process.d.ts +108 -0
- package/dist/claude-process.js +471 -0
- package/dist/claude-process.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +42 -0
- package/dist/cli.js.map +1 -0
- package/dist/codex-process.d.ts +46 -0
- package/dist/codex-process.js +420 -0
- package/dist/codex-process.js.map +1 -0
- package/dist/debug-trace-store.d.ts +15 -0
- package/dist/debug-trace-store.js +78 -0
- package/dist/debug-trace-store.js.map +1 -0
- package/dist/firebase-auth.d.ts +35 -0
- package/dist/firebase-auth.js +132 -0
- package/dist/firebase-auth.js.map +1 -0
- package/dist/gallery-store.d.ts +66 -0
- package/dist/gallery-store.js +310 -0
- package/dist/gallery-store.js.map +1 -0
- package/dist/image-store.d.ts +22 -0
- package/dist/image-store.js +113 -0
- package/dist/image-store.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +153 -0
- package/dist/index.js.map +1 -0
- package/dist/mdns.d.ts +6 -0
- package/dist/mdns.js +42 -0
- package/dist/mdns.js.map +1 -0
- package/dist/parser.d.ts +381 -0
- package/dist/parser.js +218 -0
- package/dist/parser.js.map +1 -0
- package/dist/project-history.d.ts +10 -0
- package/dist/project-history.js +73 -0
- package/dist/project-history.js.map +1 -0
- package/dist/prompt-history-backup.d.ts +15 -0
- package/dist/prompt-history-backup.js +46 -0
- package/dist/prompt-history-backup.js.map +1 -0
- package/dist/push-relay.d.ts +27 -0
- package/dist/push-relay.js +69 -0
- package/dist/push-relay.js.map +1 -0
- package/dist/recording-store.d.ts +51 -0
- package/dist/recording-store.js +158 -0
- package/dist/recording-store.js.map +1 -0
- package/dist/screenshot.d.ts +28 -0
- package/dist/screenshot.js +98 -0
- package/dist/screenshot.js.map +1 -0
- package/dist/sdk-process.d.ts +151 -0
- package/dist/sdk-process.js +740 -0
- package/dist/sdk-process.js.map +1 -0
- package/dist/session.d.ts +126 -0
- package/dist/session.js +550 -0
- package/dist/session.js.map +1 -0
- package/dist/sessions-index.d.ts +86 -0
- package/dist/sessions-index.js +1027 -0
- package/dist/sessions-index.js.map +1 -0
- package/dist/setup-launchd.d.ts +8 -0
- package/dist/setup-launchd.js +109 -0
- package/dist/setup-launchd.js.map +1 -0
- package/dist/startup-info.d.ts +8 -0
- package/dist/startup-info.js +78 -0
- package/dist/startup-info.js.map +1 -0
- package/dist/usage.d.ts +17 -0
- package/dist/usage.js +236 -0
- package/dist/usage.js.map +1 -0
- package/dist/version.d.ts +11 -0
- package/dist/version.js +39 -0
- package/dist/version.js.map +1 -0
- package/dist/websocket.d.ts +71 -0
- package/dist/websocket.js +1487 -0
- package/dist/websocket.js.map +1 -0
- package/dist/worktree-store.d.ts +25 -0
- package/dist/worktree-store.js +59 -0
- package/dist/worktree-store.js.map +1 -0
- package/dist/worktree.d.ts +43 -0
- package/dist/worktree.js +295 -0
- package/dist/worktree.js.map +1 -0
- package/package.json +63 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { appendFile, mkdir, readdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
const DEFAULT_ROOT_DIR = join(homedir(), ".ccpocket", "debug");
|
|
5
|
+
const RECORDING_DIRNAME = "recordings";
|
|
6
|
+
export class RecordingStore {
|
|
7
|
+
recordingDir;
|
|
8
|
+
writeChains = new Map();
|
|
9
|
+
constructor(rootDir = DEFAULT_ROOT_DIR) {
|
|
10
|
+
this.recordingDir = join(rootDir, RECORDING_DIRNAME);
|
|
11
|
+
}
|
|
12
|
+
async init() {
|
|
13
|
+
await mkdir(this.recordingDir, { recursive: true });
|
|
14
|
+
}
|
|
15
|
+
getFilePath(sessionId) {
|
|
16
|
+
return join(this.recordingDir, `${sanitizeSegment(sessionId)}.jsonl`);
|
|
17
|
+
}
|
|
18
|
+
getMetaPath(sessionId) {
|
|
19
|
+
return join(this.recordingDir, `${sanitizeSegment(sessionId)}.meta.json`);
|
|
20
|
+
}
|
|
21
|
+
/** Save or update session metadata alongside the recording. */
|
|
22
|
+
saveMeta(sessionId, meta) {
|
|
23
|
+
const path = this.getMetaPath(sessionId);
|
|
24
|
+
this.enqueue(path, async () => {
|
|
25
|
+
await writeFile(path, JSON.stringify(meta, null, 2), "utf-8");
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
/** Read session metadata. */
|
|
29
|
+
async getMeta(sessionId) {
|
|
30
|
+
try {
|
|
31
|
+
const raw = await readFile(this.getMetaPath(sessionId), "utf-8");
|
|
32
|
+
return JSON.parse(raw);
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
record(sessionId, direction, message) {
|
|
39
|
+
const path = this.getFilePath(sessionId);
|
|
40
|
+
const event = {
|
|
41
|
+
ts: new Date().toISOString(),
|
|
42
|
+
direction,
|
|
43
|
+
message,
|
|
44
|
+
};
|
|
45
|
+
const line = `${JSON.stringify(event)}\n`;
|
|
46
|
+
this.enqueue(path, async () => {
|
|
47
|
+
await appendFile(path, line, "utf-8");
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
/** List all recording files, newest first, with metadata if available. */
|
|
51
|
+
async listRecordings() {
|
|
52
|
+
try {
|
|
53
|
+
const entries = await readdir(this.recordingDir);
|
|
54
|
+
const results = [];
|
|
55
|
+
for (const entry of entries) {
|
|
56
|
+
if (!entry.endsWith(".jsonl"))
|
|
57
|
+
continue;
|
|
58
|
+
const name = entry.replace(/\.jsonl$/, "");
|
|
59
|
+
const filePath = join(this.recordingDir, entry);
|
|
60
|
+
const s = await stat(filePath);
|
|
61
|
+
const meta = await this.getMeta(name);
|
|
62
|
+
results.push({
|
|
63
|
+
name,
|
|
64
|
+
path: filePath,
|
|
65
|
+
modified: s.mtime.toISOString(),
|
|
66
|
+
sizeBytes: s.size,
|
|
67
|
+
...(meta ? { meta } : {}),
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
results.sort((a, b) => b.modified.localeCompare(a.modified));
|
|
71
|
+
return results;
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return [];
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Extract key info directly from JSONL content without requiring meta or sessions-index.
|
|
79
|
+
* Scans for first/last user input messages and claudeSessionId from system messages.
|
|
80
|
+
*/
|
|
81
|
+
async extractInfoFromJsonl(sessionId) {
|
|
82
|
+
try {
|
|
83
|
+
const content = await readFile(this.getFilePath(sessionId), "utf-8");
|
|
84
|
+
const lines = content.trim().split("\n");
|
|
85
|
+
let firstPrompt;
|
|
86
|
+
let lastPrompt;
|
|
87
|
+
let claudeSessionId;
|
|
88
|
+
let projectPath;
|
|
89
|
+
for (const line of lines) {
|
|
90
|
+
try {
|
|
91
|
+
const event = JSON.parse(line);
|
|
92
|
+
const msg = event.message;
|
|
93
|
+
// Extract user input messages (incoming "input" type)
|
|
94
|
+
if (event.direction === "incoming" && msg.type === "input" && typeof msg.text === "string") {
|
|
95
|
+
if (!firstPrompt)
|
|
96
|
+
firstPrompt = msg.text;
|
|
97
|
+
lastPrompt = msg.text;
|
|
98
|
+
}
|
|
99
|
+
// Extract claudeSessionId from system messages
|
|
100
|
+
if (event.direction === "outgoing" && msg.type === "system" && typeof msg.sessionId === "string") {
|
|
101
|
+
// Claude CLI session IDs are full UUIDs (36 chars)
|
|
102
|
+
const sid = msg.sessionId;
|
|
103
|
+
if (sid.length > 8 && !claudeSessionId) {
|
|
104
|
+
claudeSessionId = sid;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// Extract projectPath from start messages
|
|
108
|
+
if (event.direction === "incoming" && msg.type === "start" && typeof msg.projectPath === "string") {
|
|
109
|
+
projectPath = msg.projectPath;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
// skip malformed lines
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return { firstPrompt, lastPrompt, claudeSessionId, projectPath };
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
return {};
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/** Read recording content as string. */
|
|
123
|
+
async getRecordingContent(sessionId) {
|
|
124
|
+
try {
|
|
125
|
+
const filePath = this.getFilePath(sessionId);
|
|
126
|
+
return await readFile(filePath, "utf-8");
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
async flush() {
|
|
133
|
+
const pendingWrites = [...this.writeChains.values()];
|
|
134
|
+
await Promise.all(pendingWrites.map((p) => p.catch(() => { })));
|
|
135
|
+
}
|
|
136
|
+
enqueue(path, task) {
|
|
137
|
+
const previous = this.writeChains.get(path) ?? Promise.resolve();
|
|
138
|
+
const next = previous
|
|
139
|
+
.catch(() => { })
|
|
140
|
+
.then(async () => {
|
|
141
|
+
await mkdir(dirname(path), { recursive: true });
|
|
142
|
+
await task();
|
|
143
|
+
})
|
|
144
|
+
.finally(() => {
|
|
145
|
+
if (this.writeChains.get(path) === next) {
|
|
146
|
+
this.writeChains.delete(path);
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
this.writeChains.set(path, next);
|
|
150
|
+
void next.catch((err) => {
|
|
151
|
+
console.warn(`[recording-store] Failed to write ${path}:`, err);
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
function sanitizeSegment(value) {
|
|
156
|
+
return value.replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=recording-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recording-store.js","sourceRoot":"","sources":["../src/recording-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Screenshot module — macOS native screenshot capture via CLI commands.
|
|
3
|
+
*
|
|
4
|
+
* - `listWindows()`: Enumerate on-screen windows using CGWindowListCopyWindowInfo
|
|
5
|
+
* via Swift's CoreGraphics (Quartz PyObjC is unreliable across Python installs).
|
|
6
|
+
* - `takeScreenshot()`: Capture full-screen or a specific window via `screencapture`.
|
|
7
|
+
*/
|
|
8
|
+
export interface WindowBounds {
|
|
9
|
+
x: number;
|
|
10
|
+
y: number;
|
|
11
|
+
width: number;
|
|
12
|
+
height: number;
|
|
13
|
+
}
|
|
14
|
+
export interface WindowInfo {
|
|
15
|
+
windowId: number;
|
|
16
|
+
ownerName: string;
|
|
17
|
+
windowTitle: string;
|
|
18
|
+
bounds: WindowBounds;
|
|
19
|
+
}
|
|
20
|
+
export interface ScreenshotOptions {
|
|
21
|
+
mode: "fullscreen" | "window";
|
|
22
|
+
windowId?: number;
|
|
23
|
+
}
|
|
24
|
+
export interface ScreenshotResult {
|
|
25
|
+
filePath: string;
|
|
26
|
+
}
|
|
27
|
+
export declare function listWindows(): Promise<WindowInfo[]>;
|
|
28
|
+
export declare function takeScreenshot(options: ScreenshotOptions): Promise<ScreenshotResult>;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Screenshot module — macOS native screenshot capture via CLI commands.
|
|
3
|
+
*
|
|
4
|
+
* - `listWindows()`: Enumerate on-screen windows using CGWindowListCopyWindowInfo
|
|
5
|
+
* via Swift's CoreGraphics (Quartz PyObjC is unreliable across Python installs).
|
|
6
|
+
* - `takeScreenshot()`: Capture full-screen or a specific window via `screencapture`.
|
|
7
|
+
*/
|
|
8
|
+
import { execFile } from "node:child_process";
|
|
9
|
+
import { tmpdir } from "node:os";
|
|
10
|
+
import { join } from "node:path";
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
// listWindows
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
/**
|
|
15
|
+
* Swift inline script that calls CGWindowListCopyWindowInfo and outputs JSON.
|
|
16
|
+
* Uses `swift -e` which is available on any macOS with Xcode CLT.
|
|
17
|
+
* Python + Quartz was unreliable (PyObjC missing on non-system python installs).
|
|
18
|
+
*/
|
|
19
|
+
const LIST_WINDOWS_SWIFT = `
|
|
20
|
+
import CoreGraphics
|
|
21
|
+
import Foundation
|
|
22
|
+
|
|
23
|
+
let windowList = CGWindowListCopyWindowInfo(
|
|
24
|
+
[.optionOnScreenOnly, .excludeDesktopElements],
|
|
25
|
+
kCGNullWindowID
|
|
26
|
+
) as? [[String: Any]] ?? []
|
|
27
|
+
|
|
28
|
+
var out: [[String: Any]] = []
|
|
29
|
+
for w in windowList {
|
|
30
|
+
guard let layer = w[kCGWindowLayer as String] as? Int, layer == 0 else { continue }
|
|
31
|
+
guard let owner = w[kCGWindowOwnerName as String] as? String, !owner.isEmpty else { continue }
|
|
32
|
+
let bounds = w[kCGWindowBounds as String] as? [String: Any] ?? [:]
|
|
33
|
+
let width = bounds["Width"] as? Double ?? 0
|
|
34
|
+
let height = bounds["Height"] as? Double ?? 0
|
|
35
|
+
if width < 50 || height < 50 { continue }
|
|
36
|
+
out.append([
|
|
37
|
+
"windowId": w[kCGWindowNumber as String] as? Int ?? 0,
|
|
38
|
+
"ownerName": owner,
|
|
39
|
+
"windowTitle": (w[kCGWindowName as String] as? String) ?? "",
|
|
40
|
+
"bounds": [
|
|
41
|
+
"x": (bounds["X"] as? Double ?? 0) as Any,
|
|
42
|
+
"y": (bounds["Y"] as? Double ?? 0) as Any,
|
|
43
|
+
"width": width as Any,
|
|
44
|
+
"height": height as Any,
|
|
45
|
+
] as Any,
|
|
46
|
+
])
|
|
47
|
+
}
|
|
48
|
+
let data = try JSONSerialization.data(withJSONObject: out, options: [])
|
|
49
|
+
print(String(data: data, encoding: .utf8)!)
|
|
50
|
+
`;
|
|
51
|
+
export async function listWindows() {
|
|
52
|
+
if (process.platform !== "darwin") {
|
|
53
|
+
throw new Error("listWindows is only supported on macOS");
|
|
54
|
+
}
|
|
55
|
+
return new Promise((resolve, reject) => {
|
|
56
|
+
execFile("swift", ["-e", LIST_WINDOWS_SWIFT], { timeout: 15_000 }, (err, stdout, stderr) => {
|
|
57
|
+
if (err) {
|
|
58
|
+
reject(new Error(`Failed to list windows: ${err.message}${stderr ? ` — ${stderr}` : ""}`));
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
try {
|
|
62
|
+
const windows = JSON.parse(stdout);
|
|
63
|
+
resolve(windows);
|
|
64
|
+
}
|
|
65
|
+
catch (parseErr) {
|
|
66
|
+
reject(new Error(`Failed to parse window list: ${parseErr}`));
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
// takeScreenshot
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
export async function takeScreenshot(options) {
|
|
75
|
+
if (process.platform !== "darwin") {
|
|
76
|
+
throw new Error("takeScreenshot is only supported on macOS");
|
|
77
|
+
}
|
|
78
|
+
const filePath = join(tmpdir(), `ccpocket-screenshot-${Date.now()}.png`);
|
|
79
|
+
const args = ["-x"]; // silent (no capture sound)
|
|
80
|
+
if (options.mode === "window") {
|
|
81
|
+
if (options.windowId == null) {
|
|
82
|
+
throw new Error("windowId is required for window mode");
|
|
83
|
+
}
|
|
84
|
+
args.push("-o"); // no window shadow
|
|
85
|
+
args.push("-l", String(options.windowId));
|
|
86
|
+
}
|
|
87
|
+
args.push("-t", "png", filePath);
|
|
88
|
+
return new Promise((resolve, reject) => {
|
|
89
|
+
execFile("screencapture", args, { timeout: 10_000 }, (err, _stdout, stderr) => {
|
|
90
|
+
if (err) {
|
|
91
|
+
reject(new Error(`screencapture failed: ${err.message}${stderr ? ` — ${stderr}` : ""}`));
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
resolve({ filePath });
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=screenshot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"screenshot.js","sourceRoot":"","sources":["../src/screenshot.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { EventEmitter } from "node:events";
|
|
2
|
+
import { type SDKMessage } from "@anthropic-ai/claude-agent-sdk";
|
|
3
|
+
import { type ServerMessage, type ProcessStatus, type PermissionMode } from "./parser.js";
|
|
4
|
+
export declare const ACCEPT_EDITS_AUTO_APPROVE: Set<string>;
|
|
5
|
+
export declare function isFileEditToolName(toolName: string): boolean;
|
|
6
|
+
export declare function extractTokenUsage(usage: unknown): {
|
|
7
|
+
inputTokens?: number;
|
|
8
|
+
cachedInputTokens?: number;
|
|
9
|
+
outputTokens?: number;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Parse a permission rule in ToolName(ruleContent) format.
|
|
13
|
+
* Matches the CLI's internal pzT() function: /^([^(]+)\(([^)]+)\)$/
|
|
14
|
+
*/
|
|
15
|
+
export declare function parseRule(rule: string): {
|
|
16
|
+
toolName: string;
|
|
17
|
+
ruleContent?: string;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Check if a tool invocation matches any session allow rule.
|
|
21
|
+
*/
|
|
22
|
+
export declare function matchesSessionRule(toolName: string, input: Record<string, unknown>, rules: Set<string>): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Build a session allow rule string from a tool name and input.
|
|
25
|
+
* Bash: uses first word as prefix (e.g., "Bash(npm:*)")
|
|
26
|
+
* Others: tool name only (e.g., "Edit")
|
|
27
|
+
*/
|
|
28
|
+
export declare function buildSessionRule(toolName: string, input: Record<string, unknown>): string;
|
|
29
|
+
export interface StartOptions {
|
|
30
|
+
sessionId?: string;
|
|
31
|
+
continueMode?: boolean;
|
|
32
|
+
permissionMode?: PermissionMode;
|
|
33
|
+
model?: string;
|
|
34
|
+
effort?: "low" | "medium" | "high" | "max";
|
|
35
|
+
maxTurns?: number;
|
|
36
|
+
maxBudgetUsd?: number;
|
|
37
|
+
fallbackModel?: string;
|
|
38
|
+
forkSession?: boolean;
|
|
39
|
+
persistSession?: boolean;
|
|
40
|
+
/** When resuming, only resume messages up to this UUID (for conversation rewind). */
|
|
41
|
+
resumeSessionAt?: string;
|
|
42
|
+
/** Text to send as the first user message immediately after session starts. */
|
|
43
|
+
initialInput?: string;
|
|
44
|
+
}
|
|
45
|
+
export interface RewindFilesResult {
|
|
46
|
+
canRewind: boolean;
|
|
47
|
+
error?: string;
|
|
48
|
+
filesChanged?: string[];
|
|
49
|
+
insertions?: number;
|
|
50
|
+
deletions?: number;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Convert SDK messages to the ServerMessage format used by the WebSocket protocol.
|
|
54
|
+
* Exported for testing.
|
|
55
|
+
*/
|
|
56
|
+
export declare function sdkMessageToServerMessage(msg: SDKMessage): ServerMessage | null;
|
|
57
|
+
export interface SdkProcessEvents {
|
|
58
|
+
message: [ServerMessage];
|
|
59
|
+
status: [ProcessStatus];
|
|
60
|
+
exit: [number | null];
|
|
61
|
+
}
|
|
62
|
+
export declare class SdkProcess extends EventEmitter<SdkProcessEvents> {
|
|
63
|
+
private queryInstance;
|
|
64
|
+
private _status;
|
|
65
|
+
private _sessionId;
|
|
66
|
+
private pendingPermissions;
|
|
67
|
+
private _permissionMode;
|
|
68
|
+
get permissionMode(): PermissionMode | undefined;
|
|
69
|
+
private sessionAllowRules;
|
|
70
|
+
private initTimeoutId;
|
|
71
|
+
private userMessageResolve;
|
|
72
|
+
private stopped;
|
|
73
|
+
private pendingInput;
|
|
74
|
+
private _projectPath;
|
|
75
|
+
private toolCallsSinceLastResult;
|
|
76
|
+
private fileEditsSinceLastResult;
|
|
77
|
+
get status(): ProcessStatus;
|
|
78
|
+
get isWaitingForInput(): boolean;
|
|
79
|
+
get sessionId(): string | null;
|
|
80
|
+
get isRunning(): boolean;
|
|
81
|
+
start(projectPath: string, options?: StartOptions): void;
|
|
82
|
+
stop(): void;
|
|
83
|
+
interrupt(): void;
|
|
84
|
+
sendInput(text: string): void;
|
|
85
|
+
/**
|
|
86
|
+
* Send a message with an image attachment.
|
|
87
|
+
* @param text - The text message
|
|
88
|
+
* @param image - Base64-encoded image data with mime type
|
|
89
|
+
*/
|
|
90
|
+
sendInputWithImage(text: string, image: {
|
|
91
|
+
base64: string;
|
|
92
|
+
mimeType: string;
|
|
93
|
+
}): void;
|
|
94
|
+
/**
|
|
95
|
+
* Approve a pending permission request.
|
|
96
|
+
* With the SDK, this actually blocks tool execution until approved.
|
|
97
|
+
*/
|
|
98
|
+
approve(toolUseId?: string, updatedInput?: Record<string, unknown>): void;
|
|
99
|
+
/**
|
|
100
|
+
* Approve a pending permission request and add a session-scoped allow rule.
|
|
101
|
+
*/
|
|
102
|
+
approveAlways(toolUseId?: string): void;
|
|
103
|
+
/**
|
|
104
|
+
* Reject a pending permission request.
|
|
105
|
+
* The SDK's canUseTool will return deny, which tells Claude the tool was rejected.
|
|
106
|
+
*/
|
|
107
|
+
reject(toolUseId?: string, message?: string): void;
|
|
108
|
+
/**
|
|
109
|
+
* Answer an AskUserQuestion tool call.
|
|
110
|
+
* The SDK handles this through canUseTool with updatedInput.
|
|
111
|
+
*/
|
|
112
|
+
answer(toolUseId: string, result: string): void;
|
|
113
|
+
/**
|
|
114
|
+
* Update permission mode for the current session.
|
|
115
|
+
* Only available while the query instance is active.
|
|
116
|
+
*/
|
|
117
|
+
setPermissionMode(mode: PermissionMode): Promise<void>;
|
|
118
|
+
/**
|
|
119
|
+
* Rewind files to their state at the specified user message.
|
|
120
|
+
* Requires enableFileCheckpointing to be enabled (done in start()).
|
|
121
|
+
*/
|
|
122
|
+
rewindFiles(userMessageId: string, dryRun?: boolean): Promise<RewindFilesResult>;
|
|
123
|
+
/**
|
|
124
|
+
* Proactively fetch supported commands from the SDK.
|
|
125
|
+
* This may resolve before the first user input, providing slash commands
|
|
126
|
+
* without waiting for system/init.
|
|
127
|
+
*/
|
|
128
|
+
private fetchSupportedCommands;
|
|
129
|
+
private firstPendingId;
|
|
130
|
+
/**
|
|
131
|
+
* Returns a snapshot of a pending permission request.
|
|
132
|
+
* Used by the bridge to support Clear & Accept flows.
|
|
133
|
+
*/
|
|
134
|
+
getPendingPermission(toolUseId?: string): {
|
|
135
|
+
toolUseId: string;
|
|
136
|
+
toolName: string;
|
|
137
|
+
input: Record<string, unknown>;
|
|
138
|
+
} | undefined;
|
|
139
|
+
private createUserMessageStream;
|
|
140
|
+
private processMessages;
|
|
141
|
+
/**
|
|
142
|
+
* Core permission handler: called by SDK before each tool execution.
|
|
143
|
+
* Returns a Promise that resolves when the user approves/rejects.
|
|
144
|
+
*/
|
|
145
|
+
private handleCanUseTool;
|
|
146
|
+
private waitForPermission;
|
|
147
|
+
private updateStatusFromMessage;
|
|
148
|
+
private handlePostToolUseHook;
|
|
149
|
+
private setStatus;
|
|
150
|
+
private emitMessage;
|
|
151
|
+
}
|