@diggerhq/anyware 0.6.6 → 0.7.1
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/api/auth.d.ts +25 -0
- package/dist/api/auth.d.ts.map +1 -0
- package/dist/api/auth.js +62 -0
- package/dist/api/auth.js.map +1 -0
- package/dist/api/session.d.ts +14 -0
- package/dist/api/session.d.ts.map +1 -0
- package/dist/api/session.js +60 -0
- package/dist/api/session.js.map +1 -0
- package/dist/api/wsClient.d.ts +40 -0
- package/dist/api/wsClient.d.ts.map +1 -0
- package/dist/api/wsClient.js +111 -0
- package/dist/api/wsClient.js.map +1 -0
- package/dist/claude/claudeLocal.d.ts +17 -0
- package/dist/claude/claudeLocal.d.ts.map +1 -0
- package/dist/claude/claudeLocal.js +170 -0
- package/dist/claude/claudeLocal.js.map +1 -0
- package/dist/claude/claudeLocalLauncher.d.ts +8 -0
- package/dist/claude/claudeLocalLauncher.d.ts.map +1 -0
- package/dist/claude/claudeLocalLauncher.js +153 -0
- package/dist/claude/claudeLocalLauncher.js.map +1 -0
- package/dist/claude/claudeRemote.d.ts +22 -0
- package/dist/claude/claudeRemote.d.ts.map +1 -0
- package/dist/claude/claudeRemote.js +178 -0
- package/dist/claude/claudeRemote.js.map +1 -0
- package/dist/claude/claudeRemoteLauncher.d.ts +11 -0
- package/dist/claude/claudeRemoteLauncher.d.ts.map +1 -0
- package/dist/claude/claudeRemoteLauncher.js +103 -0
- package/dist/claude/claudeRemoteLauncher.js.map +1 -0
- package/dist/claude/loop.d.ts +21 -0
- package/dist/claude/loop.d.ts.map +1 -0
- package/dist/claude/loop.js +45 -0
- package/dist/claude/loop.js.map +1 -0
- package/dist/claude/sdk/query.d.ts +71 -0
- package/dist/claude/sdk/query.d.ts.map +1 -0
- package/dist/claude/sdk/query.js +353 -0
- package/dist/claude/sdk/query.js.map +1 -0
- package/dist/claude/sdk/stream.d.ts +28 -0
- package/dist/claude/sdk/stream.d.ts.map +1 -0
- package/dist/claude/sdk/stream.js +91 -0
- package/dist/claude/sdk/stream.js.map +1 -0
- package/dist/claude/sdk/types.d.ts +166 -0
- package/dist/claude/sdk/types.d.ts.map +1 -0
- package/dist/claude/sdk/types.js +13 -0
- package/dist/claude/sdk/types.js.map +1 -0
- package/dist/claude/session.d.ts +80 -0
- package/dist/claude/session.d.ts.map +1 -0
- package/dist/claude/session.js +172 -0
- package/dist/claude/session.js.map +1 -0
- package/dist/claude/sessionScanner.d.ts +100 -0
- package/dist/claude/sessionScanner.d.ts.map +1 -0
- package/dist/claude/sessionScanner.js +194 -0
- package/dist/claude/sessionScanner.js.map +1 -0
- package/dist/config/config.d.ts +12 -0
- package/dist/config/config.d.ts.map +1 -0
- package/dist/config/config.js +40 -0
- package/dist/config/config.js.map +1 -0
- package/dist/hooks/generateHookSettings.d.ts +20 -0
- package/dist/hooks/generateHookSettings.d.ts.map +1 -0
- package/dist/hooks/generateHookSettings.js +126 -0
- package/dist/hooks/generateHookSettings.js.map +1 -0
- package/dist/hooks/hookServer.d.ts +45 -0
- package/dist/hooks/hookServer.d.ts.map +1 -0
- package/dist/hooks/hookServer.js +83 -0
- package/dist/hooks/hookServer.js.map +1 -0
- package/dist/main.d.ts +6 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +140 -0
- package/dist/main.js.map +1 -0
- package/dist/utils/messageQueue.d.ts +38 -0
- package/dist/utils/messageQueue.d.ts.map +1 -0
- package/dist/utils/messageQueue.js +85 -0
- package/dist/utils/messageQueue.js.map +1 -0
- package/package.json +27 -27
- package/scripts/session_hook_forwarder.cjs +51 -0
- package/README.md +0 -67
- package/bin/anyware +0 -29
- package/bin/anyware-darwin-amd64 +0 -0
- package/bin/anyware-darwin-arm64 +0 -0
- package/bin/anyware-linux-amd64 +0 -0
- package/bin/anyware-linux-arm64 +0 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { claudeLocal } from './claudeLocal.js';
|
|
2
|
+
import { createSessionScanner } from './sessionScanner.js';
|
|
3
|
+
import { startHookServer } from '../hooks/hookServer.js';
|
|
4
|
+
import { generateHookSettingsFile, cleanupHookSettingsFile } from '../hooks/generateHookSettings.js';
|
|
5
|
+
/**
|
|
6
|
+
* Launch Claude in local mode with session scanning
|
|
7
|
+
* Returns 'switch' if we should switch to remote mode, 'exit' if we should exit
|
|
8
|
+
*/
|
|
9
|
+
export async function claudeLocalLauncher(session) {
|
|
10
|
+
// Variable to hold scanner reference (needed in onHookEvent before scanner is created)
|
|
11
|
+
let scanner = null;
|
|
12
|
+
// Start hook server to receive session notifications from Claude
|
|
13
|
+
const hookServer = await startHookServer({
|
|
14
|
+
onSessionHook: (sessionId) => {
|
|
15
|
+
session.setClaudeSessionId(sessionId);
|
|
16
|
+
if (scanner) {
|
|
17
|
+
scanner.onNewSession(sessionId);
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
onHookEvent: (eventType, _sessionId, data) => {
|
|
21
|
+
// Forward hook events to the WebSocket as claude_event
|
|
22
|
+
// Transform hook data to the expected format
|
|
23
|
+
const claudeEvent = {
|
|
24
|
+
type: eventType,
|
|
25
|
+
hook_data: {
|
|
26
|
+
tool_name: data.tool_name,
|
|
27
|
+
tool_input: data.tool_input,
|
|
28
|
+
tool_response: data.tool_response,
|
|
29
|
+
prompt: data.prompt,
|
|
30
|
+
stop_reason: data.stop_reason,
|
|
31
|
+
response: data.response,
|
|
32
|
+
cwd: data.cwd,
|
|
33
|
+
},
|
|
34
|
+
session_id: data.session_id,
|
|
35
|
+
};
|
|
36
|
+
session.sendClaudeEvent(claudeEvent);
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
// Generate hook settings file for Claude
|
|
40
|
+
const hookSettingsPath = generateHookSettingsFile(hookServer.port);
|
|
41
|
+
// Create scanner to watch session file and forward messages to server
|
|
42
|
+
scanner = await createSessionScanner({
|
|
43
|
+
sessionId: session.claudeSessionId,
|
|
44
|
+
workingDirectory: session.path,
|
|
45
|
+
onMessage: (message) => {
|
|
46
|
+
// Skip summary messages - we generate our own
|
|
47
|
+
if (message.type !== 'summary') {
|
|
48
|
+
session.sendClaudeEvent(message);
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
// Register callback for when session ID is discovered (from other sources)
|
|
53
|
+
const scannerSessionCallback = (sessionId) => {
|
|
54
|
+
scanner.onNewSession(sessionId);
|
|
55
|
+
};
|
|
56
|
+
session.addSessionFoundCallback(scannerSessionCallback);
|
|
57
|
+
let exitReason = null;
|
|
58
|
+
const processAbortController = new AbortController();
|
|
59
|
+
// Use a deferred pattern for exit promise
|
|
60
|
+
let exitResolve = () => { };
|
|
61
|
+
const exitPromise = new Promise((resolve) => {
|
|
62
|
+
exitResolve = resolve;
|
|
63
|
+
});
|
|
64
|
+
try {
|
|
65
|
+
// Abort function
|
|
66
|
+
async function abort() {
|
|
67
|
+
if (!processAbortController.signal.aborted) {
|
|
68
|
+
processAbortController.abort();
|
|
69
|
+
}
|
|
70
|
+
await exitPromise;
|
|
71
|
+
}
|
|
72
|
+
// Handle abort request (switch to remote)
|
|
73
|
+
async function doAbort() {
|
|
74
|
+
if (!exitReason) {
|
|
75
|
+
exitReason = 'switch';
|
|
76
|
+
}
|
|
77
|
+
session.queue.reset();
|
|
78
|
+
await abort();
|
|
79
|
+
}
|
|
80
|
+
// Handle switch request
|
|
81
|
+
async function doSwitch() {
|
|
82
|
+
if (!exitReason) {
|
|
83
|
+
exitReason = 'switch';
|
|
84
|
+
}
|
|
85
|
+
await abort();
|
|
86
|
+
}
|
|
87
|
+
// Register handlers for incoming messages
|
|
88
|
+
session.onUserInput(() => {
|
|
89
|
+
// Any user input from web triggers switch to remote mode
|
|
90
|
+
doSwitch();
|
|
91
|
+
});
|
|
92
|
+
session.onSwitch(() => {
|
|
93
|
+
doSwitch();
|
|
94
|
+
});
|
|
95
|
+
// If there are already messages in the queue, switch to remote immediately
|
|
96
|
+
if (session.queue.size() > 0) {
|
|
97
|
+
return 'switch';
|
|
98
|
+
}
|
|
99
|
+
// Handle session start
|
|
100
|
+
const handleSessionStart = (sessionId) => {
|
|
101
|
+
session.setClaudeSessionId(sessionId);
|
|
102
|
+
scanner.onNewSession(sessionId);
|
|
103
|
+
};
|
|
104
|
+
// Run local mode loop
|
|
105
|
+
while (true) {
|
|
106
|
+
if (exitReason) {
|
|
107
|
+
return exitReason;
|
|
108
|
+
}
|
|
109
|
+
try {
|
|
110
|
+
await claudeLocal({
|
|
111
|
+
path: session.path,
|
|
112
|
+
sessionId: session.claudeSessionId,
|
|
113
|
+
onSessionFound: handleSessionStart,
|
|
114
|
+
onThinkingChange: (thinking) => session.sendThinking(thinking),
|
|
115
|
+
abort: processAbortController.signal,
|
|
116
|
+
claudeArgs: session.claudeArgs,
|
|
117
|
+
hookSettingsPath,
|
|
118
|
+
});
|
|
119
|
+
// Consume one-time flags after first spawn
|
|
120
|
+
session.consumeOneTimeFlags();
|
|
121
|
+
// Normal exit
|
|
122
|
+
if (!exitReason) {
|
|
123
|
+
exitReason = 'exit';
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
if (!exitReason) {
|
|
129
|
+
// Retry on error
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
finally {
|
|
139
|
+
// Resolve exit promise
|
|
140
|
+
exitResolve();
|
|
141
|
+
// Cleanup handlers
|
|
142
|
+
session.onUserInput(null);
|
|
143
|
+
session.onSwitch(null);
|
|
144
|
+
session.removeSessionFoundCallback(scannerSessionCallback);
|
|
145
|
+
// Cleanup scanner
|
|
146
|
+
await scanner.cleanup();
|
|
147
|
+
// Cleanup hook server and settings file
|
|
148
|
+
hookServer.stop();
|
|
149
|
+
cleanupHookSettingsFile(hookSettingsPath);
|
|
150
|
+
}
|
|
151
|
+
return exitReason || 'exit';
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=claudeLocalLauncher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claudeLocalLauncher.js","sourceRoot":"","sources":["../../src/claude/claudeLocalLauncher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAE3D,OAAO,EAAE,eAAe,EAA2B,MAAM,wBAAwB,CAAC;AAClF,OAAO,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AAIrG;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,OAAgB;IACxD,uFAAuF;IACvF,IAAI,OAAO,GAA4D,IAAI,CAAC;IAE5E,iEAAiE;IACjE,MAAM,UAAU,GAAG,MAAM,eAAe,CAAC;QACvC,aAAa,EAAE,CAAC,SAAS,EAAE,EAAE;YAC3B,OAAO,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC;YACtC,IAAI,OAAO,EAAE,CAAC;gBACZ,OAAO,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;YAClC,CAAC;QACH,CAAC;QACD,WAAW,EAAE,CAAC,SAAwB,EAAE,UAAkB,EAAE,IAAc,EAAE,EAAE;YAC5E,uDAAuD;YACvD,6CAA6C;YAC7C,MAAM,WAAW,GAAG;gBAClB,IAAI,EAAE,SAAS;gBACf,SAAS,EAAE;oBACT,SAAS,EAAE,IAAI,CAAC,SAAS;oBACzB,UAAU,EAAE,IAAI,CAAC,UAAU;oBAC3B,aAAa,EAAE,IAAI,CAAC,aAAa;oBACjC,MAAM,EAAE,IAAI,CAAC,MAAM;oBACnB,WAAW,EAAE,IAAI,CAAC,WAAW;oBAC7B,QAAQ,EAAE,IAAI,CAAC,QAAQ;oBACvB,GAAG,EAAE,IAAI,CAAC,GAAG;iBACd;gBACD,UAAU,EAAE,IAAI,CAAC,UAAU;aAC5B,CAAC;YACF,OAAO,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC;QACvC,CAAC;KACF,CAAC,CAAC;IAEH,yCAAyC;IACzC,MAAM,gBAAgB,GAAG,wBAAwB,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IAEnE,sEAAsE;IACtE,OAAO,GAAG,MAAM,oBAAoB,CAAC;QACnC,SAAS,EAAE,OAAO,CAAC,eAAe;QAClC,gBAAgB,EAAE,OAAO,CAAC,IAAI;QAC9B,SAAS,EAAE,CAAC,OAAO,EAAE,EAAE;YACrB,8CAA8C;YAC9C,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;gBAC/B,OAAO,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;YACnC,CAAC;QACH,CAAC;KACF,CAAC,CAAC;IAEH,2EAA2E;IAC3E,MAAM,sBAAsB,GAAG,CAAC,SAAiB,EAAE,EAAE;QACnD,OAAO,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;IAClC,CAAC,CAAC;IACF,OAAO,CAAC,uBAAuB,CAAC,sBAAsB,CAAC,CAAC;IAExD,IAAI,UAAU,GAA2B,IAAI,CAAC;IAC9C,MAAM,sBAAsB,GAAG,IAAI,eAAe,EAAE,CAAC;IAErD,0CAA0C;IAC1C,IAAI,WAAW,GAAe,GAAG,EAAE,GAAE,CAAC,CAAC;IACvC,MAAM,WAAW,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;QAChD,WAAW,GAAG,OAAO,CAAC;IACxB,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC;QACH,iBAAiB;QACjB,KAAK,UAAU,KAAK;YAClB,IAAI,CAAC,sBAAsB,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBAC3C,sBAAsB,CAAC,KAAK,EAAE,CAAC;YACjC,CAAC;YACD,MAAM,WAAW,CAAC;QACpB,CAAC;QAED,0CAA0C;QAC1C,KAAK,UAAU,OAAO;YACpB,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,UAAU,GAAG,QAAQ,CAAC;YACxB,CAAC;YACD,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YACtB,MAAM,KAAK,EAAE,CAAC;QAChB,CAAC;QAED,wBAAwB;QACxB,KAAK,UAAU,QAAQ;YACrB,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,UAAU,GAAG,QAAQ,CAAC;YACxB,CAAC;YACD,MAAM,KAAK,EAAE,CAAC;QAChB,CAAC;QAED,0CAA0C;QAC1C,OAAO,CAAC,WAAW,CAAC,GAAG,EAAE;YACvB,yDAAyD;YACzD,QAAQ,EAAE,CAAC;QACb,CAAC,CAAC,CAAC;QAEH,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE;YACpB,QAAQ,EAAE,CAAC;QACb,CAAC,CAAC,CAAC;QAEH,2EAA2E;QAC3E,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC;YAC7B,OAAO,QAAQ,CAAC;QAClB,CAAC;QAED,uBAAuB;QACvB,MAAM,kBAAkB,GAAG,CAAC,SAAiB,EAAE,EAAE;YAC/C,OAAO,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC;YACtC,OAAO,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;QAClC,CAAC,CAAC;QAEF,sBAAsB;QACtB,OAAO,IAAI,EAAE,CAAC;YACZ,IAAI,UAAU,EAAE,CAAC;gBACf,OAAO,UAAU,CAAC;YACpB,CAAC;YAED,IAAI,CAAC;gBACH,MAAM,WAAW,CAAC;oBAChB,IAAI,EAAE,OAAO,CAAC,IAAI;oBAClB,SAAS,EAAE,OAAO,CAAC,eAAe;oBAClC,cAAc,EAAE,kBAAkB;oBAClC,gBAAgB,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,OAAO,CAAC,YAAY,CAAC,QAAQ,CAAC;oBAC9D,KAAK,EAAE,sBAAsB,CAAC,MAAM;oBACpC,UAAU,EAAE,OAAO,CAAC,UAAU;oBAC9B,gBAAgB;iBACjB,CAAC,CAAC;gBAEH,2CAA2C;gBAC3C,OAAO,CAAC,mBAAmB,EAAE,CAAC;gBAE9B,cAAc;gBACd,IAAI,CAAC,UAAU,EAAE,CAAC;oBAChB,UAAU,GAAG,MAAM,CAAC;oBACpB,MAAM;gBACR,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,IAAI,CAAC,UAAU,EAAE,CAAC;oBAChB,iBAAiB;oBACjB,SAAS;gBACX,CAAC;qBAAM,CAAC;oBACN,MAAM;gBACR,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;YAAS,CAAC;QACT,uBAAuB;QACvB,WAAW,EAAE,CAAC;QAEd,mBAAmB;QACnB,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QAC1B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACvB,OAAO,CAAC,0BAA0B,CAAC,sBAAsB,CAAC,CAAC;QAE3D,kBAAkB;QAClB,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;QAExB,wCAAwC;QACxC,UAAU,CAAC,IAAI,EAAE,CAAC;QAClB,uBAAuB,CAAC,gBAAgB,CAAC,CAAC;IAC5C,CAAC;IAED,OAAO,UAAU,IAAI,MAAM,CAAC;AAC9B,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Remote mode - runs Claude via SDK with streaming responses
|
|
3
|
+
* Messages come from the web via WebSocket
|
|
4
|
+
*/
|
|
5
|
+
import type { SDKMessage } from './sdk/types.js';
|
|
6
|
+
export interface ClaudeRemoteOptions {
|
|
7
|
+
abort: AbortSignal;
|
|
8
|
+
sessionId: string | null;
|
|
9
|
+
path: string;
|
|
10
|
+
onMessage: (message: SDKMessage) => void;
|
|
11
|
+
onSessionFound: (id: string) => void;
|
|
12
|
+
onThinkingChange?: (thinking: boolean) => void;
|
|
13
|
+
nextMessage: () => Promise<{
|
|
14
|
+
message: string;
|
|
15
|
+
} | null>;
|
|
16
|
+
claudeArgs?: string[];
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Run Claude in remote mode using the SDK
|
|
20
|
+
*/
|
|
21
|
+
export declare function claudeRemote(opts: ClaudeRemoteOptions): Promise<string | null>;
|
|
22
|
+
//# sourceMappingURL=claudeRemote.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claudeRemote.d.ts","sourceRoot":"","sources":["../../src/claude/claudeRemote.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAkC,MAAM,gBAAgB,CAAC;AA0DjF,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,WAAW,CAAC;IACnB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,CAAC,OAAO,EAAE,UAAU,KAAK,IAAI,CAAC;IACzC,cAAc,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAC;IAC/C,WAAW,EAAE,MAAM,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;IACvD,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAqBD;;GAEG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAqHpF"}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Remote mode - runs Claude via SDK with streaming responses
|
|
3
|
+
* Messages come from the web via WebSocket
|
|
4
|
+
*/
|
|
5
|
+
import { query } from './sdk/query.js';
|
|
6
|
+
import { join, resolve } from 'node:path';
|
|
7
|
+
import { homedir } from 'node:os';
|
|
8
|
+
import { existsSync } from 'node:fs';
|
|
9
|
+
/**
|
|
10
|
+
* Pushable async iterable for messages
|
|
11
|
+
*/
|
|
12
|
+
class PushableAsyncIterable {
|
|
13
|
+
queue = [];
|
|
14
|
+
waitResolve = null;
|
|
15
|
+
ended = false;
|
|
16
|
+
push(value) {
|
|
17
|
+
if (this.ended)
|
|
18
|
+
return;
|
|
19
|
+
if (this.waitResolve) {
|
|
20
|
+
const resolve = this.waitResolve;
|
|
21
|
+
this.waitResolve = null;
|
|
22
|
+
resolve({ done: false, value });
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
this.queue.push(value);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
end() {
|
|
29
|
+
this.ended = true;
|
|
30
|
+
if (this.waitResolve) {
|
|
31
|
+
const resolve = this.waitResolve;
|
|
32
|
+
this.waitResolve = null;
|
|
33
|
+
resolve({ done: true, value: undefined });
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
async *[Symbol.asyncIterator]() {
|
|
37
|
+
while (true) {
|
|
38
|
+
if (this.queue.length > 0) {
|
|
39
|
+
yield this.queue.shift();
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (this.ended) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const result = await new Promise((resolve) => {
|
|
46
|
+
this.waitResolve = resolve;
|
|
47
|
+
});
|
|
48
|
+
if (result.done) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
yield result.value;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Get project path for Claude sessions
|
|
57
|
+
* Claude uses the resolved path with special chars replaced by dashes
|
|
58
|
+
*/
|
|
59
|
+
function getProjectPath(workingDirectory) {
|
|
60
|
+
const projectId = resolve(workingDirectory).replace(/[\\\/.:]/g, '-');
|
|
61
|
+
const claudeConfigDir = process.env.CLAUDE_CONFIG_DIR || join(homedir(), '.claude');
|
|
62
|
+
return join(claudeConfigDir, 'projects', projectId);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Check if Claude session exists
|
|
66
|
+
*/
|
|
67
|
+
function claudeCheckSession(sessionId, workingDirectory) {
|
|
68
|
+
const projectDir = getProjectPath(workingDirectory);
|
|
69
|
+
const sessionFile = join(projectDir, `${sessionId}.jsonl`);
|
|
70
|
+
return existsSync(sessionFile);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Run Claude in remote mode using the SDK
|
|
74
|
+
*/
|
|
75
|
+
export async function claudeRemote(opts) {
|
|
76
|
+
// Determine session to resume
|
|
77
|
+
let startFrom = opts.sessionId;
|
|
78
|
+
// Extract --resume from claudeArgs if present
|
|
79
|
+
if (!startFrom && opts.claudeArgs) {
|
|
80
|
+
for (let i = 0; i < opts.claudeArgs.length; i++) {
|
|
81
|
+
if (opts.claudeArgs[i] === '--resume') {
|
|
82
|
+
if (i + 1 < opts.claudeArgs.length) {
|
|
83
|
+
const nextArg = opts.claudeArgs[i + 1];
|
|
84
|
+
if (!nextArg.startsWith('-') && nextArg.includes('-')) {
|
|
85
|
+
startFrom = nextArg;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// Validate session exists
|
|
92
|
+
if (startFrom && !claudeCheckSession(startFrom, opts.path)) {
|
|
93
|
+
console.log(`Session ${startFrom} not found, starting fresh`);
|
|
94
|
+
startFrom = null;
|
|
95
|
+
}
|
|
96
|
+
if (startFrom) {
|
|
97
|
+
console.log(`Resuming session: ${startFrom}`);
|
|
98
|
+
}
|
|
99
|
+
// Create pushable stream for messages
|
|
100
|
+
const messages = new PushableAsyncIterable();
|
|
101
|
+
// Wait for first message
|
|
102
|
+
const firstMessage = await opts.nextMessage();
|
|
103
|
+
if (!firstMessage) {
|
|
104
|
+
return startFrom;
|
|
105
|
+
}
|
|
106
|
+
// Push first message
|
|
107
|
+
messages.push({
|
|
108
|
+
type: 'user',
|
|
109
|
+
message: { role: 'user', content: firstMessage.message },
|
|
110
|
+
});
|
|
111
|
+
// Thinking state
|
|
112
|
+
let thinking = false;
|
|
113
|
+
const updateThinking = (newThinking) => {
|
|
114
|
+
if (thinking !== newThinking) {
|
|
115
|
+
thinking = newThinking;
|
|
116
|
+
if (opts.onThinkingChange) {
|
|
117
|
+
opts.onThinkingChange(thinking);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
// Build SDK options
|
|
122
|
+
const sdkOptions = {
|
|
123
|
+
cwd: opts.path,
|
|
124
|
+
resume: startFrom ?? undefined,
|
|
125
|
+
abort: opts.abort,
|
|
126
|
+
permissionMode: 'default',
|
|
127
|
+
// Permission callback - allow all tools in remote mode for now
|
|
128
|
+
canCallTool: async (_toolName, input) => {
|
|
129
|
+
return {
|
|
130
|
+
behavior: 'allow',
|
|
131
|
+
updatedInput: input,
|
|
132
|
+
};
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
// Start query
|
|
136
|
+
const response = query({
|
|
137
|
+
prompt: messages,
|
|
138
|
+
options: sdkOptions,
|
|
139
|
+
});
|
|
140
|
+
updateThinking(true);
|
|
141
|
+
try {
|
|
142
|
+
for await (const message of response) {
|
|
143
|
+
// Forward message to callback
|
|
144
|
+
opts.onMessage(message);
|
|
145
|
+
if (message.type === 'system' && 'subtype' in message && message.subtype === 'init') {
|
|
146
|
+
updateThinking(true);
|
|
147
|
+
// Extract session ID
|
|
148
|
+
if ('session_id' in message && typeof message.session_id === 'string') {
|
|
149
|
+
opts.onSessionFound(message.session_id);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
if (message.type === 'result') {
|
|
153
|
+
updateThinking(false);
|
|
154
|
+
// Get next message
|
|
155
|
+
const next = await opts.nextMessage();
|
|
156
|
+
if (!next) {
|
|
157
|
+
messages.end();
|
|
158
|
+
return startFrom;
|
|
159
|
+
}
|
|
160
|
+
// Push next message
|
|
161
|
+
messages.push({
|
|
162
|
+
type: 'user',
|
|
163
|
+
message: { role: 'user', content: next.message },
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
catch (e) {
|
|
169
|
+
if (!opts.abort.aborted) {
|
|
170
|
+
console.error('[remote] Error:', e);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
finally {
|
|
174
|
+
updateThinking(false);
|
|
175
|
+
}
|
|
176
|
+
return startFrom;
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=claudeRemote.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claudeRemote.js","sourceRoot":"","sources":["../../src/claude/claudeRemote.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Remote launcher - handles remote mode execution with session management
|
|
3
|
+
*/
|
|
4
|
+
import type { Session } from './session.js';
|
|
5
|
+
export type RemoteExitReason = 'switch' | 'exit';
|
|
6
|
+
/**
|
|
7
|
+
* Launch Claude in remote mode
|
|
8
|
+
* Returns 'switch' if we should switch to local mode, 'exit' if we should exit
|
|
9
|
+
*/
|
|
10
|
+
export declare function claudeRemoteLauncher(session: Session): Promise<RemoteExitReason>;
|
|
11
|
+
//# sourceMappingURL=claudeRemoteLauncher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claudeRemoteLauncher.d.ts","sourceRoot":"","sources":["../../src/claude/claudeRemoteLauncher.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAG5C,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEjD;;;GAGG;AACH,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAuGtF"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Remote launcher - handles remote mode execution with session management
|
|
3
|
+
*/
|
|
4
|
+
import { claudeRemote } from './claudeRemote.js';
|
|
5
|
+
import * as readline from 'node:readline';
|
|
6
|
+
/**
|
|
7
|
+
* Launch Claude in remote mode
|
|
8
|
+
* Returns 'switch' if we should switch to local mode, 'exit' if we should exit
|
|
9
|
+
*/
|
|
10
|
+
export async function claudeRemoteLauncher(session) {
|
|
11
|
+
let exitReason = null;
|
|
12
|
+
const processAbortController = new AbortController();
|
|
13
|
+
// Setup keyboard listener for switching back to local mode
|
|
14
|
+
const rl = readline.createInterface({
|
|
15
|
+
input: process.stdin,
|
|
16
|
+
output: process.stdout,
|
|
17
|
+
});
|
|
18
|
+
// Listen for any keypress to switch back to local
|
|
19
|
+
readline.emitKeypressEvents(process.stdin);
|
|
20
|
+
if (process.stdin.isTTY) {
|
|
21
|
+
process.stdin.setRawMode(true);
|
|
22
|
+
}
|
|
23
|
+
const keypressHandler = (str, key) => {
|
|
24
|
+
// Switch to local on Enter, Escape, or 'q'
|
|
25
|
+
if (key.name === 'return' || key.name === 'escape' || str === 'q') {
|
|
26
|
+
if (!exitReason) {
|
|
27
|
+
exitReason = 'switch';
|
|
28
|
+
}
|
|
29
|
+
session.queue.reset(); // Unblock waitForMessage
|
|
30
|
+
processAbortController.abort();
|
|
31
|
+
}
|
|
32
|
+
// Ctrl+C to exit completely
|
|
33
|
+
if (key.ctrl && key.name === 'c') {
|
|
34
|
+
if (!exitReason) {
|
|
35
|
+
exitReason = 'exit';
|
|
36
|
+
}
|
|
37
|
+
session.queue.reset(); // Unblock waitForMessage
|
|
38
|
+
processAbortController.abort();
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
process.stdin.on('keypress', keypressHandler);
|
|
42
|
+
try {
|
|
43
|
+
// Handle switch request from web (user wants to go back to local mode)
|
|
44
|
+
session.onSwitch(() => {
|
|
45
|
+
if (!exitReason) {
|
|
46
|
+
exitReason = 'switch';
|
|
47
|
+
}
|
|
48
|
+
session.queue.reset(); // Unblock waitForMessage
|
|
49
|
+
processAbortController.abort();
|
|
50
|
+
});
|
|
51
|
+
// Run remote mode
|
|
52
|
+
console.log('Remote mode active. Press Enter/Escape/q to switch to local, Ctrl+C to exit.');
|
|
53
|
+
await claudeRemote({
|
|
54
|
+
path: session.path,
|
|
55
|
+
sessionId: session.claudeSessionId,
|
|
56
|
+
abort: processAbortController.signal,
|
|
57
|
+
claudeArgs: session.claudeArgs,
|
|
58
|
+
onMessage: (message) => {
|
|
59
|
+
// Forward SDK messages to server
|
|
60
|
+
session.sendClaudeEvent(message);
|
|
61
|
+
},
|
|
62
|
+
onSessionFound: (sessionId) => {
|
|
63
|
+
session.setClaudeSessionId(sessionId);
|
|
64
|
+
},
|
|
65
|
+
onThinkingChange: (thinking) => {
|
|
66
|
+
session.sendThinking(thinking);
|
|
67
|
+
},
|
|
68
|
+
nextMessage: async () => {
|
|
69
|
+
// Wait for next message from queue
|
|
70
|
+
const message = await session.queue.waitForMessage();
|
|
71
|
+
if (!message) {
|
|
72
|
+
// Queue was reset or closed
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
return { message };
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
// Consume one-time flags after spawn
|
|
79
|
+
session.consumeOneTimeFlags();
|
|
80
|
+
// Normal exit if no exit reason set
|
|
81
|
+
if (!exitReason) {
|
|
82
|
+
exitReason = 'exit';
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
catch (e) {
|
|
86
|
+
console.error('[remote] Error:', e);
|
|
87
|
+
if (!exitReason) {
|
|
88
|
+
exitReason = 'exit';
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
finally {
|
|
92
|
+
// Cleanup keyboard listener
|
|
93
|
+
process.stdin.removeListener('keypress', keypressHandler);
|
|
94
|
+
if (process.stdin.isTTY) {
|
|
95
|
+
process.stdin.setRawMode(false);
|
|
96
|
+
}
|
|
97
|
+
rl.close();
|
|
98
|
+
// Cleanup handlers
|
|
99
|
+
session.onSwitch(null);
|
|
100
|
+
}
|
|
101
|
+
return exitReason;
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=claudeRemoteLauncher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claudeRemoteLauncher.js","sourceRoot":"","sources":["../../src/claude/claudeRemoteLauncher.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mode switching loop - alternates between local and remote modes
|
|
3
|
+
*/
|
|
4
|
+
import type { Session } from './session.js';
|
|
5
|
+
export interface LoopOptions {
|
|
6
|
+
session: Session;
|
|
7
|
+
startingMode?: 'local' | 'remote';
|
|
8
|
+
onModeChange?: (mode: 'local' | 'remote') => void;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Main loop that switches between local and remote modes
|
|
12
|
+
*
|
|
13
|
+
* - Local mode: User interacts directly with Claude via terminal
|
|
14
|
+
* - Remote mode: Messages come from web via WebSocket, processed via SDK
|
|
15
|
+
*
|
|
16
|
+
* Mode switches happen when:
|
|
17
|
+
* - Local → Remote: When a message arrives from web while in local mode
|
|
18
|
+
* - Remote → Local: When user requests switch (e.g., double-space in web UI)
|
|
19
|
+
*/
|
|
20
|
+
export declare function loop(opts: LoopOptions): Promise<void>;
|
|
21
|
+
//# sourceMappingURL=loop.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loop.d.ts","sourceRoot":"","sources":["../../src/claude/loop.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAClC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,GAAG,QAAQ,KAAK,IAAI,CAAC;CACnD;AAED;;;;;;;;;GASG;AACH,wBAAsB,IAAI,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAoC3D"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mode switching loop - alternates between local and remote modes
|
|
3
|
+
*/
|
|
4
|
+
import { claudeLocalLauncher } from './claudeLocalLauncher.js';
|
|
5
|
+
import { claudeRemoteLauncher } from './claudeRemoteLauncher.js';
|
|
6
|
+
/**
|
|
7
|
+
* Main loop that switches between local and remote modes
|
|
8
|
+
*
|
|
9
|
+
* - Local mode: User interacts directly with Claude via terminal
|
|
10
|
+
* - Remote mode: Messages come from web via WebSocket, processed via SDK
|
|
11
|
+
*
|
|
12
|
+
* Mode switches happen when:
|
|
13
|
+
* - Local → Remote: When a message arrives from web while in local mode
|
|
14
|
+
* - Remote → Local: When user requests switch (e.g., double-space in web UI)
|
|
15
|
+
*/
|
|
16
|
+
export async function loop(opts) {
|
|
17
|
+
let mode = opts.startingMode ?? 'local';
|
|
18
|
+
while (true) {
|
|
19
|
+
// Notify mode change
|
|
20
|
+
if (opts.onModeChange) {
|
|
21
|
+
opts.onModeChange(mode);
|
|
22
|
+
}
|
|
23
|
+
// Send mode change to server
|
|
24
|
+
opts.session.sendModeChange(mode);
|
|
25
|
+
if (mode === 'local') {
|
|
26
|
+
const reason = await claudeLocalLauncher(opts.session);
|
|
27
|
+
if (reason === 'exit') {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
// Switch to remote mode
|
|
31
|
+
mode = 'remote';
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
if (mode === 'remote') {
|
|
35
|
+
const reason = await claudeRemoteLauncher(opts.session);
|
|
36
|
+
if (reason === 'exit') {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
// Switch to local mode
|
|
40
|
+
mode = 'local';
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=loop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loop.js","sourceRoot":"","sources":["../../src/claude/loop.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AASjE;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,IAAiB;IAC1C,IAAI,IAAI,GAAuB,IAAI,CAAC,YAAY,IAAI,OAAO,CAAC;IAE5D,OAAO,IAAI,EAAE,CAAC;QACZ,qBAAqB;QACrB,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACtB,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;QAED,6BAA6B;QAC7B,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;QAElC,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;YACrB,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAEvD,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;gBACtB,OAAO;YACT,CAAC;YAED,wBAAwB;YACxB,IAAI,GAAG,QAAQ,CAAC;YAChB,SAAS;QACX,CAAC;QAED,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;YACtB,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAExD,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;gBACtB,OAAO;YACT,CAAC;YAED,uBAAuB;YACvB,IAAI,GAAG,OAAO,CAAC;YACf,SAAS;QACX,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Query implementation for Claude Code SDK
|
|
3
|
+
* Handles spawning Claude process and managing message streams
|
|
4
|
+
*/
|
|
5
|
+
import type { Writable } from 'node:stream';
|
|
6
|
+
import { type QueryOptions, type QueryPrompt, type SDKMessage, type CanCallToolCallback } from './types.js';
|
|
7
|
+
/**
|
|
8
|
+
* Query class manages Claude Code process interaction
|
|
9
|
+
*/
|
|
10
|
+
export declare class Query implements AsyncIterableIterator<SDKMessage> {
|
|
11
|
+
private childStdin;
|
|
12
|
+
private childStdout;
|
|
13
|
+
private processExitPromise;
|
|
14
|
+
private pendingControlResponses;
|
|
15
|
+
private cancelControllers;
|
|
16
|
+
private sdkMessages;
|
|
17
|
+
private inputStream;
|
|
18
|
+
private canCallTool?;
|
|
19
|
+
constructor(childStdin: Writable | null, childStdout: NodeJS.ReadableStream, processExitPromise: Promise<void>, canCallTool?: CanCallToolCallback);
|
|
20
|
+
/**
|
|
21
|
+
* Set an error on the stream
|
|
22
|
+
*/
|
|
23
|
+
setError(error: Error): void;
|
|
24
|
+
/**
|
|
25
|
+
* AsyncIterableIterator implementation
|
|
26
|
+
*/
|
|
27
|
+
next(): Promise<IteratorResult<SDKMessage>>;
|
|
28
|
+
return(value?: unknown): Promise<IteratorResult<SDKMessage>>;
|
|
29
|
+
throw(e: Error): Promise<IteratorResult<SDKMessage>>;
|
|
30
|
+
[Symbol.asyncIterator](): AsyncIterableIterator<SDKMessage>;
|
|
31
|
+
/**
|
|
32
|
+
* Read messages from Claude process stdout
|
|
33
|
+
*/
|
|
34
|
+
private readMessages;
|
|
35
|
+
/**
|
|
36
|
+
* Async generator for SDK messages
|
|
37
|
+
*/
|
|
38
|
+
private readSdkMessages;
|
|
39
|
+
/**
|
|
40
|
+
* Send interrupt request to Claude
|
|
41
|
+
*/
|
|
42
|
+
interrupt(): Promise<void>;
|
|
43
|
+
/**
|
|
44
|
+
* Send control request to Claude process
|
|
45
|
+
*/
|
|
46
|
+
private request;
|
|
47
|
+
/**
|
|
48
|
+
* Handle incoming control requests for tool permissions
|
|
49
|
+
*/
|
|
50
|
+
private handleControlRequest;
|
|
51
|
+
/**
|
|
52
|
+
* Handle control cancel requests
|
|
53
|
+
*/
|
|
54
|
+
private handleControlCancelRequest;
|
|
55
|
+
/**
|
|
56
|
+
* Process control requests based on subtype
|
|
57
|
+
*/
|
|
58
|
+
private processControlRequest;
|
|
59
|
+
/**
|
|
60
|
+
* Cleanup method to abort all pending control requests
|
|
61
|
+
*/
|
|
62
|
+
private cleanupControllers;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Main query function to interact with Claude Code
|
|
66
|
+
*/
|
|
67
|
+
export declare function query(config: {
|
|
68
|
+
prompt: QueryPrompt;
|
|
69
|
+
options?: QueryOptions;
|
|
70
|
+
}): Query;
|
|
71
|
+
//# sourceMappingURL=query.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../../src/claude/sdk/query.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,UAAU,EAKf,KAAK,mBAAmB,EAMzB,MAAM,YAAY,CAAC;AA0CpB;;GAEG;AACH,qBAAa,KAAM,YAAW,qBAAqB,CAAC,UAAU,CAAC;IAQ3D,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,kBAAkB;IAT5B,OAAO,CAAC,uBAAuB,CAA6C;IAC5E,OAAO,CAAC,iBAAiB,CAAsC;IAC/D,OAAO,CAAC,WAAW,CAAoC;IACvD,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,WAAW,CAAC,CAAsB;gBAGhC,UAAU,EAAE,QAAQ,GAAG,IAAI,EAC3B,WAAW,EAAE,MAAM,CAAC,cAAc,EAClC,kBAAkB,EAAE,OAAO,CAAC,IAAI,CAAC,EACzC,WAAW,CAAC,EAAE,mBAAmB;IAOnC;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAI5B;;OAEG;IACH,IAAI,IAAI,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;IAI3C,MAAM,CAAC,KAAK,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;IAO5D,KAAK,CAAC,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;IAOpD,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,qBAAqB,CAAC,UAAU,CAAC;IAI3D;;OAEG;YACW,YAAY;IAwC1B;;OAEG;YACY,eAAe;IAM9B;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAQhC;;OAEG;IACH,OAAO,CAAC,OAAO;IAqBf;;OAEG;YACW,oBAAoB;IAkClC;;OAEG;IACH,OAAO,CAAC,0BAA0B;IAQlC;;OAEG;YACW,qBAAqB;IAcnC;;OAEG;IACH,OAAO,CAAC,kBAAkB;CAM3B;AAED;;GAEG;AACH,wBAAgB,KAAK,CAAC,MAAM,EAAE;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,OAAO,CAAC,EAAE,YAAY,CAAA;CAAE,GAAG,KAAK,CA4HpF"}
|