@diggerhq/anyware 0.6.6 → 0.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/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 +131 -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 +74 -0
- package/dist/hooks/generateHookSettings.js.map +1 -0
- package/dist/hooks/hookServer.d.ts +33 -0
- package/dist/hooks/hookServer.d.ts.map +1 -0
- package/dist/hooks/hookServer.js +75 -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,25 @@
|
|
|
1
|
+
interface DeviceCodeResponse {
|
|
2
|
+
deviceCode: string;
|
|
3
|
+
userCode: string;
|
|
4
|
+
verificationUri: string;
|
|
5
|
+
verificationUriComplete: string;
|
|
6
|
+
expiresIn: number;
|
|
7
|
+
interval: number;
|
|
8
|
+
}
|
|
9
|
+
interface TokenResponse {
|
|
10
|
+
accessToken: string;
|
|
11
|
+
userId: string;
|
|
12
|
+
email: string;
|
|
13
|
+
}
|
|
14
|
+
interface PendingResponse {
|
|
15
|
+
status: 'pending';
|
|
16
|
+
error?: string;
|
|
17
|
+
}
|
|
18
|
+
export declare function requestDeviceCode(): Promise<DeviceCodeResponse>;
|
|
19
|
+
export declare function pollDeviceToken(deviceCode: string): Promise<TokenResponse | PendingResponse>;
|
|
20
|
+
export declare function login(): Promise<{
|
|
21
|
+
userId: string;
|
|
22
|
+
email: string;
|
|
23
|
+
}>;
|
|
24
|
+
export {};
|
|
25
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/api/auth.ts"],"names":[],"mappings":"AAEA,UAAU,kBAAkB;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,uBAAuB,EAAE,MAAM,CAAC;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,aAAa;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,UAAU,eAAe;IACvB,MAAM,EAAE,SAAS,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAWrE;AAED,wBAAsB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,eAAe,CAAC,CAmBlG;AAED,wBAAsB,KAAK,IAAI,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAsCxE"}
|
package/dist/api/auth.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { loadConfig, saveConfig } from '../config/config.js';
|
|
2
|
+
export async function requestDeviceCode() {
|
|
3
|
+
const config = loadConfig();
|
|
4
|
+
const response = await fetch(`${config.apiUrl}/api/v1/auth/device`, {
|
|
5
|
+
method: 'GET',
|
|
6
|
+
});
|
|
7
|
+
if (!response.ok) {
|
|
8
|
+
throw new Error(`Failed to request device code: ${response.statusText}`);
|
|
9
|
+
}
|
|
10
|
+
return response.json();
|
|
11
|
+
}
|
|
12
|
+
export async function pollDeviceToken(deviceCode) {
|
|
13
|
+
const config = loadConfig();
|
|
14
|
+
const response = await fetch(`${config.apiUrl}/api/v1/auth/device`, {
|
|
15
|
+
method: 'POST',
|
|
16
|
+
headers: { 'Content-Type': 'application/json' },
|
|
17
|
+
body: JSON.stringify({ deviceCode }),
|
|
18
|
+
});
|
|
19
|
+
if (response.status === 202) {
|
|
20
|
+
const data = await response.json();
|
|
21
|
+
return { status: 'pending', error: data.error };
|
|
22
|
+
}
|
|
23
|
+
if (!response.ok) {
|
|
24
|
+
const data = await response.json();
|
|
25
|
+
throw new Error(data.error || 'Authentication failed');
|
|
26
|
+
}
|
|
27
|
+
return response.json();
|
|
28
|
+
}
|
|
29
|
+
export async function login() {
|
|
30
|
+
console.log('Starting device authentication...\n');
|
|
31
|
+
const deviceCode = await requestDeviceCode();
|
|
32
|
+
console.log(`Open this URL in your browser to login:\n`);
|
|
33
|
+
console.log(` ${deviceCode.verificationUriComplete}\n`);
|
|
34
|
+
console.log(`Or go to ${deviceCode.verificationUri} and enter code: ${deviceCode.userCode}\n`);
|
|
35
|
+
console.log('Waiting for authentication...');
|
|
36
|
+
// Poll for token
|
|
37
|
+
const startTime = Date.now();
|
|
38
|
+
const timeoutMs = deviceCode.expiresIn * 1000;
|
|
39
|
+
const intervalMs = (deviceCode.interval || 5) * 1000;
|
|
40
|
+
while (Date.now() - startTime < timeoutMs) {
|
|
41
|
+
await sleep(intervalMs);
|
|
42
|
+
const result = await pollDeviceToken(deviceCode.deviceCode);
|
|
43
|
+
if ('status' in result && result.status === 'pending') {
|
|
44
|
+
process.stdout.write('.');
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
// Success
|
|
48
|
+
const tokenResult = result;
|
|
49
|
+
saveConfig({
|
|
50
|
+
accessToken: tokenResult.accessToken,
|
|
51
|
+
userId: tokenResult.userId,
|
|
52
|
+
email: tokenResult.email,
|
|
53
|
+
});
|
|
54
|
+
console.log(`\n\nLogged in as ${tokenResult.email}`);
|
|
55
|
+
return { userId: tokenResult.userId, email: tokenResult.email };
|
|
56
|
+
}
|
|
57
|
+
throw new Error('Authentication timed out');
|
|
58
|
+
}
|
|
59
|
+
function sleep(ms) {
|
|
60
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/api/auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
interface Session {
|
|
2
|
+
id: string;
|
|
3
|
+
userId: string;
|
|
4
|
+
deviceId?: string;
|
|
5
|
+
status: 'active' | 'ended';
|
|
6
|
+
cwd?: string;
|
|
7
|
+
startedAt: string;
|
|
8
|
+
endedAt?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function createSession(cwd: string): Promise<string>;
|
|
11
|
+
export declare function endSession(sessionId: string): Promise<void>;
|
|
12
|
+
export declare function getSession(sessionId: string): Promise<Session | null>;
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/api/session.ts"],"names":[],"mappings":"AAMA,UAAU,OAAO;IACf,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA4BhE;AAED,wBAAsB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBjE;AAED,wBAAsB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAuB3E"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { loadConfig } from '../config/config.js';
|
|
2
|
+
export async function createSession(cwd) {
|
|
3
|
+
const config = loadConfig();
|
|
4
|
+
if (!config.accessToken) {
|
|
5
|
+
throw new Error('Not logged in. Please run "anyware login" first.');
|
|
6
|
+
}
|
|
7
|
+
const response = await fetch(`${config.apiUrl}/api/v1/sessions`, {
|
|
8
|
+
method: 'POST',
|
|
9
|
+
headers: {
|
|
10
|
+
'Content-Type': 'application/json',
|
|
11
|
+
'Authorization': `Bearer ${config.accessToken}`,
|
|
12
|
+
},
|
|
13
|
+
body: JSON.stringify({ cwd }),
|
|
14
|
+
});
|
|
15
|
+
if (response.status === 429) {
|
|
16
|
+
const data = await response.json();
|
|
17
|
+
throw new Error(`${data.message}\nUpgrade at: ${data.upgradeUrl}`);
|
|
18
|
+
}
|
|
19
|
+
if (!response.ok) {
|
|
20
|
+
const data = await response.json();
|
|
21
|
+
throw new Error(data.error || 'Failed to create session');
|
|
22
|
+
}
|
|
23
|
+
const result = await response.json();
|
|
24
|
+
return result.sessionId;
|
|
25
|
+
}
|
|
26
|
+
export async function endSession(sessionId) {
|
|
27
|
+
const config = loadConfig();
|
|
28
|
+
if (!config.accessToken) {
|
|
29
|
+
throw new Error('Not logged in');
|
|
30
|
+
}
|
|
31
|
+
const response = await fetch(`${config.apiUrl}/api/v1/sessions/${sessionId}/end`, {
|
|
32
|
+
method: 'POST',
|
|
33
|
+
headers: {
|
|
34
|
+
'Authorization': `Bearer ${config.accessToken}`,
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
if (!response.ok) {
|
|
38
|
+
console.error('Failed to end session:', response.statusText);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export async function getSession(sessionId) {
|
|
42
|
+
const config = loadConfig();
|
|
43
|
+
if (!config.accessToken) {
|
|
44
|
+
throw new Error('Not logged in');
|
|
45
|
+
}
|
|
46
|
+
const response = await fetch(`${config.apiUrl}/api/v1/sessions/${sessionId}`, {
|
|
47
|
+
headers: {
|
|
48
|
+
'Authorization': `Bearer ${config.accessToken}`,
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
if (response.status === 404) {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
if (!response.ok) {
|
|
55
|
+
throw new Error('Failed to get session');
|
|
56
|
+
}
|
|
57
|
+
const result = await response.json();
|
|
58
|
+
return result.session;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/api/session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAgBjD,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,GAAW;IAC7C,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAE5B,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;IACtE,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,CAAC,MAAM,kBAAkB,EAAE;QAC/D,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;YAClC,eAAe,EAAE,UAAU,MAAM,CAAC,WAAW,EAAE;SAChD;QACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,CAAC;KAC9B,CAAC,CAAC;IAEH,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QAC5B,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAA4D,CAAC;QAC7F,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,CAAC,OAAO,iBAAiB,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC;IACrE,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAuB,CAAC;QACxD,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,0BAA0B,CAAC,CAAC;IAC5D,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,EAA2B,CAAC;IAC9D,OAAO,MAAM,CAAC,SAAS,CAAC;AAC1B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,SAAiB;IAChD,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAE5B,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;IACnC,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,CAAC,MAAM,oBAAoB,SAAS,MAAM,EAAE;QAChF,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,eAAe,EAAE,UAAU,MAAM,CAAC,WAAW,EAAE;SAChD;KACF,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,OAAO,CAAC,KAAK,CAAC,wBAAwB,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC;IAC/D,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,SAAiB;IAChD,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAE5B,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;IACnC,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,CAAC,MAAM,oBAAoB,SAAS,EAAE,EAAE;QAC5E,OAAO,EAAE;YACP,eAAe,EAAE,UAAU,MAAM,CAAC,WAAW,EAAE;SAChD;KACF,CAAC,CAAC;IAEH,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QAC5B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;IAC3C,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,EAA0B,CAAC;IAC7D,OAAO,MAAM,CAAC,OAAO,CAAC;AACxB,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export interface WSMessage {
|
|
2
|
+
type: string;
|
|
3
|
+
payload?: unknown;
|
|
4
|
+
}
|
|
5
|
+
export interface ClaudeEvent {
|
|
6
|
+
type: string;
|
|
7
|
+
[key: string]: unknown;
|
|
8
|
+
}
|
|
9
|
+
export interface UserInputMessage {
|
|
10
|
+
type: 'user_input';
|
|
11
|
+
payload: {
|
|
12
|
+
sessionId: string;
|
|
13
|
+
prompt: string;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export interface PermissionResponseMessage {
|
|
17
|
+
type: 'permission_response';
|
|
18
|
+
payload: {
|
|
19
|
+
sessionId: string;
|
|
20
|
+
response: 'yes' | 'no' | 'always';
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export interface SwitchMessage {
|
|
24
|
+
type: 'switch';
|
|
25
|
+
payload: {
|
|
26
|
+
sessionId: string;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export type IncomingMessage = UserInputMessage | PermissionResponseMessage | SwitchMessage;
|
|
30
|
+
export interface SessionWSClient {
|
|
31
|
+
send: (message: WSMessage) => void;
|
|
32
|
+
sendClaudeEvent: (event: ClaudeEvent, sessionId: string) => void;
|
|
33
|
+
sendThinking: (thinking: boolean) => void;
|
|
34
|
+
sendModeChange: (mode: 'local' | 'remote') => void;
|
|
35
|
+
onMessage: (handler: (message: IncomingMessage) => void) => void;
|
|
36
|
+
onClose: (handler: () => void) => void;
|
|
37
|
+
close: () => void;
|
|
38
|
+
}
|
|
39
|
+
export declare function createWSClient(sessionId: string, userId: string): Promise<SessionWSClient>;
|
|
40
|
+
//# sourceMappingURL=wsClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wsClient.d.ts","sourceRoot":"","sources":["../../src/api/wsClient.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,YAAY,CAAC;IACnB,OAAO,EAAE;QACP,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;CACH;AAED,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,qBAAqB,CAAC;IAC5B,OAAO,EAAE;QACP,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,KAAK,GAAG,IAAI,GAAG,QAAQ,CAAC;KACnC,CAAC;CACH;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,QAAQ,CAAC;IACf,OAAO,EAAE;QACP,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AAED,MAAM,MAAM,eAAe,GAAG,gBAAgB,GAAG,yBAAyB,GAAG,aAAa,CAAC;AAE3F,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,CAAC,OAAO,EAAE,SAAS,KAAK,IAAI,CAAC;IACnC,eAAe,EAAE,CAAC,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACjE,YAAY,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAC;IAC1C,cAAc,EAAE,CAAC,IAAI,EAAE,OAAO,GAAG,QAAQ,KAAK,IAAI,CAAC;IACnD,SAAS,EAAE,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,KAAK,IAAI,CAAC;IACjE,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;IACvC,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CA6H1F"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import WebSocket from 'ws';
|
|
2
|
+
import { loadConfig } from '../config/config.js';
|
|
3
|
+
export function createWSClient(sessionId, userId) {
|
|
4
|
+
return new Promise((resolve, reject) => {
|
|
5
|
+
const config = loadConfig();
|
|
6
|
+
if (!config.accessToken) {
|
|
7
|
+
reject(new Error('Not logged in'));
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
// Convert https to wss
|
|
11
|
+
const wsUrl = config.apiUrl.replace('https://', 'wss://').replace('http://', 'ws://');
|
|
12
|
+
const url = `${wsUrl}/ws/session/${sessionId}?type=cli&userId=${userId}&token=${config.accessToken}`;
|
|
13
|
+
const ws = new WebSocket(url);
|
|
14
|
+
let messageHandler = null;
|
|
15
|
+
let closeHandler = null;
|
|
16
|
+
let pingInterval = null;
|
|
17
|
+
ws.on('open', () => {
|
|
18
|
+
console.log('[ws] Connected to session');
|
|
19
|
+
// Start ping interval to keep connection alive
|
|
20
|
+
pingInterval = setInterval(() => {
|
|
21
|
+
if (ws.readyState === WebSocket.OPEN) {
|
|
22
|
+
ws.send(JSON.stringify({ type: 'ping' }));
|
|
23
|
+
}
|
|
24
|
+
}, 30000);
|
|
25
|
+
const client = {
|
|
26
|
+
send: (message) => {
|
|
27
|
+
if (ws.readyState === WebSocket.OPEN) {
|
|
28
|
+
ws.send(JSON.stringify(message));
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
sendClaudeEvent: (event, sid) => {
|
|
32
|
+
if (ws.readyState === WebSocket.OPEN) {
|
|
33
|
+
ws.send(JSON.stringify({
|
|
34
|
+
type: 'claude_event',
|
|
35
|
+
payload: {
|
|
36
|
+
sessionId: sid,
|
|
37
|
+
event,
|
|
38
|
+
timestamp: Date.now(),
|
|
39
|
+
},
|
|
40
|
+
}));
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
sendThinking: (thinking) => {
|
|
44
|
+
if (ws.readyState === WebSocket.OPEN) {
|
|
45
|
+
ws.send(JSON.stringify({
|
|
46
|
+
type: 'thinking',
|
|
47
|
+
payload: {
|
|
48
|
+
thinking,
|
|
49
|
+
timestamp: Date.now(),
|
|
50
|
+
},
|
|
51
|
+
}));
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
sendModeChange: (mode) => {
|
|
55
|
+
if (ws.readyState === WebSocket.OPEN) {
|
|
56
|
+
ws.send(JSON.stringify({
|
|
57
|
+
type: 'mode_change',
|
|
58
|
+
payload: {
|
|
59
|
+
mode,
|
|
60
|
+
timestamp: Date.now(),
|
|
61
|
+
},
|
|
62
|
+
}));
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
onMessage: (handler) => {
|
|
66
|
+
messageHandler = handler;
|
|
67
|
+
},
|
|
68
|
+
onClose: (handler) => {
|
|
69
|
+
closeHandler = handler;
|
|
70
|
+
},
|
|
71
|
+
close: () => {
|
|
72
|
+
if (pingInterval) {
|
|
73
|
+
clearInterval(pingInterval);
|
|
74
|
+
}
|
|
75
|
+
ws.close();
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
resolve(client);
|
|
79
|
+
});
|
|
80
|
+
ws.on('message', (data) => {
|
|
81
|
+
try {
|
|
82
|
+
const message = JSON.parse(data.toString());
|
|
83
|
+
// Handle pong silently
|
|
84
|
+
if (message.type === 'pong') {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
// Forward to handler
|
|
88
|
+
if (messageHandler && (message.type === 'user_input' || message.type === 'permission_response' || message.type === 'switch')) {
|
|
89
|
+
messageHandler(message);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
catch (e) {
|
|
93
|
+
console.error('[ws] Failed to parse message:', e);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
ws.on('close', () => {
|
|
97
|
+
console.log('[ws] Disconnected from session');
|
|
98
|
+
if (pingInterval) {
|
|
99
|
+
clearInterval(pingInterval);
|
|
100
|
+
}
|
|
101
|
+
if (closeHandler) {
|
|
102
|
+
closeHandler();
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
ws.on('error', (error) => {
|
|
106
|
+
console.error('[ws] WebSocket error:', error.message);
|
|
107
|
+
reject(error);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=wsClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wsClient.js","sourceRoot":"","sources":["../../src/api/wsClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface ClaudeLocalOptions {
|
|
2
|
+
abort: AbortSignal;
|
|
3
|
+
sessionId: string | null;
|
|
4
|
+
path: string;
|
|
5
|
+
onSessionFound: (id: string) => void;
|
|
6
|
+
onThinkingChange?: (thinking: boolean) => void;
|
|
7
|
+
claudeArgs?: string[];
|
|
8
|
+
/** Path to temporary settings file with SessionStart hook (required for session tracking) */
|
|
9
|
+
hookSettingsPath: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Spawn Claude Code in local (interactive) mode
|
|
13
|
+
* - Uses inherited stdio so user can interact directly
|
|
14
|
+
* - Uses fd3 pipe for thinking state tracking (optional)
|
|
15
|
+
*/
|
|
16
|
+
export declare function claudeLocal(opts: ClaudeLocalOptions): Promise<string | null>;
|
|
17
|
+
//# sourceMappingURL=claudeLocal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claudeLocal.d.ts","sourceRoot":"","sources":["../../src/claude/claudeLocal.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,WAAW,CAAC;IACnB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAC;IAC/C,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,6FAA6F;IAC7F,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AA2CD;;;;GAIG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA+IlF"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { createInterface } from 'node:readline';
|
|
3
|
+
import { existsSync, mkdirSync } from 'node:fs';
|
|
4
|
+
import { join, resolve } from 'node:path';
|
|
5
|
+
import { homedir } from 'node:os';
|
|
6
|
+
/**
|
|
7
|
+
* Get the project path for Claude Code sessions
|
|
8
|
+
* Claude uses the resolved path with special chars replaced by dashes
|
|
9
|
+
*/
|
|
10
|
+
function getProjectPath(workingDirectory) {
|
|
11
|
+
const projectId = resolve(workingDirectory).replace(/[\\\/.:]/g, '-');
|
|
12
|
+
const claudeConfigDir = process.env.CLAUDE_CONFIG_DIR || join(homedir(), '.claude');
|
|
13
|
+
return join(claudeConfigDir, 'projects', projectId);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Check if a Claude session exists
|
|
17
|
+
*/
|
|
18
|
+
function claudeCheckSession(sessionId, workingDirectory) {
|
|
19
|
+
const projectDir = getProjectPath(workingDirectory);
|
|
20
|
+
const sessionFile = join(projectDir, `${sessionId}.jsonl`);
|
|
21
|
+
return existsSync(sessionFile);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Find the claude binary path
|
|
25
|
+
*/
|
|
26
|
+
function findClaudePath() {
|
|
27
|
+
// Try common locations
|
|
28
|
+
const paths = [
|
|
29
|
+
'/usr/local/bin/claude',
|
|
30
|
+
'/opt/homebrew/bin/claude',
|
|
31
|
+
join(homedir(), '.local', 'bin', 'claude'),
|
|
32
|
+
join(homedir(), '.npm-global', 'bin', 'claude'),
|
|
33
|
+
];
|
|
34
|
+
for (const p of paths) {
|
|
35
|
+
if (existsSync(p)) {
|
|
36
|
+
return p;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// Fall back to PATH
|
|
40
|
+
return 'claude';
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Spawn Claude Code in local (interactive) mode
|
|
44
|
+
* - Uses inherited stdio so user can interact directly
|
|
45
|
+
* - Uses fd3 pipe for thinking state tracking (optional)
|
|
46
|
+
*/
|
|
47
|
+
export async function claudeLocal(opts) {
|
|
48
|
+
// Ensure project directory exists
|
|
49
|
+
const projectDir = getProjectPath(opts.path);
|
|
50
|
+
mkdirSync(projectDir, { recursive: true });
|
|
51
|
+
// Check if claudeArgs contains --continue or --resume
|
|
52
|
+
const hasContinueFlag = opts.claudeArgs?.includes('--continue');
|
|
53
|
+
const hasResumeFlag = opts.claudeArgs?.includes('--resume');
|
|
54
|
+
const hasUserSessionControl = hasContinueFlag || hasResumeFlag;
|
|
55
|
+
// Determine if we have an existing session to resume
|
|
56
|
+
let startFrom = opts.sessionId;
|
|
57
|
+
if (opts.sessionId && !claudeCheckSession(opts.sessionId, opts.path)) {
|
|
58
|
+
startFrom = null;
|
|
59
|
+
}
|
|
60
|
+
// Thinking state tracking
|
|
61
|
+
let thinking = false;
|
|
62
|
+
let stopThinkingTimeout = null;
|
|
63
|
+
const updateThinking = (newThinking) => {
|
|
64
|
+
if (thinking !== newThinking) {
|
|
65
|
+
thinking = newThinking;
|
|
66
|
+
if (opts.onThinkingChange) {
|
|
67
|
+
opts.onThinkingChange(thinking);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
const claudePath = findClaudePath();
|
|
72
|
+
try {
|
|
73
|
+
process.stdin.pause();
|
|
74
|
+
await new Promise((resolve, reject) => {
|
|
75
|
+
const args = [];
|
|
76
|
+
// Only add --resume if we have an existing session and user didn't pass their own flags
|
|
77
|
+
if (!hasUserSessionControl && startFrom) {
|
|
78
|
+
args.push('--resume', startFrom);
|
|
79
|
+
}
|
|
80
|
+
// Add custom Claude arguments
|
|
81
|
+
if (opts.claudeArgs) {
|
|
82
|
+
args.push(...opts.claudeArgs);
|
|
83
|
+
}
|
|
84
|
+
// Add hook settings for session tracking (always passed)
|
|
85
|
+
args.push('--settings', opts.hookSettingsPath);
|
|
86
|
+
const child = spawn(claudePath, args, {
|
|
87
|
+
stdio: ['inherit', 'inherit', 'inherit', 'pipe'],
|
|
88
|
+
signal: opts.abort,
|
|
89
|
+
cwd: opts.path,
|
|
90
|
+
env: process.env,
|
|
91
|
+
});
|
|
92
|
+
// Listen to fd3 for thinking state tracking (if available)
|
|
93
|
+
if (child.stdio[3]) {
|
|
94
|
+
const rl = createInterface({
|
|
95
|
+
input: child.stdio[3],
|
|
96
|
+
crlfDelay: Infinity,
|
|
97
|
+
});
|
|
98
|
+
const activeFetches = new Map();
|
|
99
|
+
rl.on('line', (line) => {
|
|
100
|
+
try {
|
|
101
|
+
const message = JSON.parse(line);
|
|
102
|
+
switch (message.type) {
|
|
103
|
+
case 'fetch-start':
|
|
104
|
+
activeFetches.set(message.id, {
|
|
105
|
+
hostname: message.hostname,
|
|
106
|
+
path: message.path,
|
|
107
|
+
startTime: message.timestamp,
|
|
108
|
+
});
|
|
109
|
+
if (stopThinkingTimeout) {
|
|
110
|
+
clearTimeout(stopThinkingTimeout);
|
|
111
|
+
stopThinkingTimeout = null;
|
|
112
|
+
}
|
|
113
|
+
updateThinking(true);
|
|
114
|
+
break;
|
|
115
|
+
case 'fetch-end':
|
|
116
|
+
activeFetches.delete(message.id);
|
|
117
|
+
if (activeFetches.size === 0 && thinking && !stopThinkingTimeout) {
|
|
118
|
+
stopThinkingTimeout = setTimeout(() => {
|
|
119
|
+
if (activeFetches.size === 0) {
|
|
120
|
+
updateThinking(false);
|
|
121
|
+
}
|
|
122
|
+
stopThinkingTimeout = null;
|
|
123
|
+
}, 500);
|
|
124
|
+
}
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
// Ignore non-JSON lines
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
rl.on('error', (err) => {
|
|
133
|
+
console.error('[local] Error reading fd3:', err);
|
|
134
|
+
});
|
|
135
|
+
child.on('exit', () => {
|
|
136
|
+
if (stopThinkingTimeout) {
|
|
137
|
+
clearTimeout(stopThinkingTimeout);
|
|
138
|
+
}
|
|
139
|
+
updateThinking(false);
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
child.on('error', (error) => {
|
|
143
|
+
// Ignore abort errors - they're expected when switching modes
|
|
144
|
+
if (error.code !== 'ABORT_ERR' && error.name !== 'AbortError') {
|
|
145
|
+
console.error('[local] Spawn error:', error);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
child.on('exit', (code, signal) => {
|
|
149
|
+
if (signal === 'SIGTERM' && opts.abort.aborted) {
|
|
150
|
+
resolve();
|
|
151
|
+
}
|
|
152
|
+
else if (signal) {
|
|
153
|
+
reject(new Error(`Process terminated with signal: ${signal}`));
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
resolve();
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
finally {
|
|
162
|
+
process.stdin.resume();
|
|
163
|
+
if (stopThinkingTimeout) {
|
|
164
|
+
clearTimeout(stopThinkingTimeout);
|
|
165
|
+
}
|
|
166
|
+
updateThinking(false);
|
|
167
|
+
}
|
|
168
|
+
return startFrom;
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=claudeLocal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claudeLocal.js","sourceRoot":"","sources":["../../src/claude/claudeLocal.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Session } from './session.js';
|
|
2
|
+
export type LocalExitReason = 'switch' | 'exit';
|
|
3
|
+
/**
|
|
4
|
+
* Launch Claude in local mode with session scanning
|
|
5
|
+
* Returns 'switch' if we should switch to remote mode, 'exit' if we should exit
|
|
6
|
+
*/
|
|
7
|
+
export declare function claudeLocalLauncher(session: Session): Promise<LocalExitReason>;
|
|
8
|
+
//# sourceMappingURL=claudeLocalLauncher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claudeLocalLauncher.d.ts","sourceRoot":"","sources":["../../src/claude/claudeLocalLauncher.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAI5C,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEhD;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,eAAe,CAAC,CA0IpF"}
|