@diggerhq/anyware 0.7.32 → 0.7.34
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/wsClient.d.ts +34 -0
- package/dist/api/wsClient.d.ts.map +1 -1
- package/dist/api/wsClient.js +214 -0
- package/dist/api/wsClient.js.map +1 -1
- package/dist/main.d.ts +1 -1
- package/dist/main.js +14 -113
- package/dist/main.js.map +1 -1
- package/dist/server/display.d.ts +5 -0
- package/dist/server/display.d.ts.map +1 -0
- package/dist/server/display.js +21 -0
- package/dist/server/display.js.map +1 -0
- package/dist/server/index.d.ts +5 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +94 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/lockfile.d.ts +3 -0
- package/dist/server/lockfile.d.ts.map +1 -0
- package/dist/server/lockfile.js +32 -0
- package/dist/server/lockfile.js.map +1 -0
- package/dist/server/sessionManager.d.ts +20 -0
- package/dist/server/sessionManager.d.ts.map +1 -0
- package/dist/server/sessionManager.js +112 -0
- package/dist/server/sessionManager.js.map +1 -0
- package/package.json +5 -2
- package/dist/claude/claudeLocal.d.ts +0 -17
- package/dist/claude/claudeLocal.d.ts.map +0 -1
- package/dist/claude/claudeLocal.js +0 -171
- package/dist/claude/claudeLocal.js.map +0 -1
- package/dist/claude/claudeLocalLauncher.d.ts +0 -14
- package/dist/claude/claudeLocalLauncher.d.ts.map +0 -1
- package/dist/claude/claudeLocalLauncher.js +0 -167
- package/dist/claude/claudeLocalLauncher.js.map +0 -1
- package/dist/claude/claudeRemote.d.ts +0 -27
- package/dist/claude/claudeRemote.d.ts.map +0 -1
- package/dist/claude/claudeRemote.js +0 -250
- package/dist/claude/claudeRemote.js.map +0 -1
- package/dist/claude/claudeRemoteLauncher.d.ts +0 -15
- package/dist/claude/claudeRemoteLauncher.d.ts.map +0 -1
- package/dist/claude/claudeRemoteLauncher.js +0 -182
- package/dist/claude/claudeRemoteLauncher.js.map +0 -1
- package/dist/claude/loop.d.ts +0 -24
- package/dist/claude/loop.d.ts.map +0 -1
- package/dist/claude/loop.js +0 -52
- package/dist/claude/loop.js.map +0 -1
- package/dist/claude/sessionScanner.d.ts +0 -102
- package/dist/claude/sessionScanner.d.ts.map +0 -1
- package/dist/claude/sessionScanner.js +0 -241
- package/dist/claude/sessionScanner.js.map +0 -1
- package/dist/hooks/generateHookSettings.d.ts +0 -20
- package/dist/hooks/generateHookSettings.d.ts.map +0 -1
- package/dist/hooks/generateHookSettings.js +0 -126
- package/dist/hooks/generateHookSettings.js.map +0 -1
- package/dist/hooks/hookServer.d.ts +0 -45
- package/dist/hooks/hookServer.d.ts.map +0 -1
- package/dist/hooks/hookServer.js +0 -83
- package/dist/hooks/hookServer.js.map +0 -1
|
@@ -1,167 +0,0 @@
|
|
|
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(opts) {
|
|
10
|
-
const { session, onThinkingChange, onIdle } = opts;
|
|
11
|
-
// Variable to hold scanner reference (needed in onHookEvent before scanner is created)
|
|
12
|
-
let scanner = null;
|
|
13
|
-
// Start hook server to receive session notifications from Claude
|
|
14
|
-
const hookServer = await startHookServer({
|
|
15
|
-
onSessionHook: (sessionId) => {
|
|
16
|
-
session.setClaudeSessionId(sessionId);
|
|
17
|
-
if (scanner) {
|
|
18
|
-
scanner.onNewSession(sessionId);
|
|
19
|
-
}
|
|
20
|
-
},
|
|
21
|
-
onHookEvent: (eventType, _sessionId, data) => {
|
|
22
|
-
// Forward hook events to the WebSocket as claude_event
|
|
23
|
-
// Transform hook data to the expected format
|
|
24
|
-
const claudeEvent = {
|
|
25
|
-
type: eventType,
|
|
26
|
-
hook_data: {
|
|
27
|
-
tool_name: data.tool_name,
|
|
28
|
-
tool_input: data.tool_input,
|
|
29
|
-
tool_response: data.tool_response,
|
|
30
|
-
prompt: data.prompt,
|
|
31
|
-
stop_reason: data.stop_reason,
|
|
32
|
-
response: data.response,
|
|
33
|
-
cwd: data.cwd,
|
|
34
|
-
},
|
|
35
|
-
session_id: data.session_id,
|
|
36
|
-
};
|
|
37
|
-
session.sendClaudeEvent(claudeEvent);
|
|
38
|
-
},
|
|
39
|
-
});
|
|
40
|
-
// Generate hook settings file for Claude
|
|
41
|
-
const hookSettingsPath = generateHookSettingsFile(hookServer.port);
|
|
42
|
-
// Create scanner to watch session file and forward messages to server
|
|
43
|
-
scanner = await createSessionScanner({
|
|
44
|
-
sessionId: session.claudeSessionId,
|
|
45
|
-
workingDirectory: session.path,
|
|
46
|
-
onMessage: (message) => {
|
|
47
|
-
// Skip summary messages - we generate our own
|
|
48
|
-
if (message.type !== 'summary') {
|
|
49
|
-
session.sendClaudeEvent(message);
|
|
50
|
-
}
|
|
51
|
-
},
|
|
52
|
-
onIdle,
|
|
53
|
-
});
|
|
54
|
-
// Register callback for when session ID is discovered (from other sources)
|
|
55
|
-
const scannerSessionCallback = (sessionId) => {
|
|
56
|
-
scanner.onNewSession(sessionId);
|
|
57
|
-
};
|
|
58
|
-
session.addSessionFoundCallback(scannerSessionCallback);
|
|
59
|
-
let exitReason = null;
|
|
60
|
-
const processAbortController = new AbortController();
|
|
61
|
-
// Use a deferred pattern for exit promise
|
|
62
|
-
let exitResolve = () => { };
|
|
63
|
-
const exitPromise = new Promise((resolve) => {
|
|
64
|
-
exitResolve = resolve;
|
|
65
|
-
});
|
|
66
|
-
try {
|
|
67
|
-
// Abort function
|
|
68
|
-
async function abort() {
|
|
69
|
-
if (!processAbortController.signal.aborted) {
|
|
70
|
-
processAbortController.abort();
|
|
71
|
-
}
|
|
72
|
-
await exitPromise;
|
|
73
|
-
}
|
|
74
|
-
// Handle abort request (switch to remote)
|
|
75
|
-
async function doAbort() {
|
|
76
|
-
if (!exitReason) {
|
|
77
|
-
exitReason = 'switch';
|
|
78
|
-
}
|
|
79
|
-
session.queue.reset();
|
|
80
|
-
await abort();
|
|
81
|
-
}
|
|
82
|
-
// Handle switch request
|
|
83
|
-
async function doSwitch() {
|
|
84
|
-
if (!exitReason) {
|
|
85
|
-
exitReason = 'switch';
|
|
86
|
-
}
|
|
87
|
-
await abort();
|
|
88
|
-
}
|
|
89
|
-
// Register handlers for incoming messages
|
|
90
|
-
session.onUserInput(() => {
|
|
91
|
-
// Any user input from web triggers switch to remote mode
|
|
92
|
-
doSwitch();
|
|
93
|
-
});
|
|
94
|
-
session.onSwitch(() => {
|
|
95
|
-
doSwitch();
|
|
96
|
-
});
|
|
97
|
-
// When a permission response comes from web while in local mode,
|
|
98
|
-
// switch to remote mode to handle it
|
|
99
|
-
session.onPermissionResponseTriggerSwitch(() => {
|
|
100
|
-
console.log('\n\x1b[36mPermission response received from web, switching to remote mode...\x1b[0m\n');
|
|
101
|
-
doSwitch();
|
|
102
|
-
});
|
|
103
|
-
// If there are already messages in the queue, switch to remote immediately
|
|
104
|
-
if (session.queue.size() > 0) {
|
|
105
|
-
return 'switch';
|
|
106
|
-
}
|
|
107
|
-
// Handle session start
|
|
108
|
-
const handleSessionStart = (sessionId) => {
|
|
109
|
-
session.setClaudeSessionId(sessionId);
|
|
110
|
-
scanner.onNewSession(sessionId);
|
|
111
|
-
};
|
|
112
|
-
// Run local mode loop
|
|
113
|
-
while (true) {
|
|
114
|
-
if (exitReason) {
|
|
115
|
-
return exitReason;
|
|
116
|
-
}
|
|
117
|
-
try {
|
|
118
|
-
await claudeLocal({
|
|
119
|
-
path: session.path,
|
|
120
|
-
sessionId: session.claudeSessionId,
|
|
121
|
-
onSessionFound: handleSessionStart,
|
|
122
|
-
onThinkingChange: (thinking) => {
|
|
123
|
-
session.sendThinking(thinking);
|
|
124
|
-
if (onThinkingChange) {
|
|
125
|
-
onThinkingChange(thinking);
|
|
126
|
-
}
|
|
127
|
-
},
|
|
128
|
-
abort: processAbortController.signal,
|
|
129
|
-
claudeArgs: session.claudeArgs,
|
|
130
|
-
hookSettingsPath,
|
|
131
|
-
});
|
|
132
|
-
// Consume one-time flags after first spawn
|
|
133
|
-
session.consumeOneTimeFlags();
|
|
134
|
-
// Normal exit
|
|
135
|
-
if (!exitReason) {
|
|
136
|
-
exitReason = 'exit';
|
|
137
|
-
break;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
catch {
|
|
141
|
-
if (!exitReason) {
|
|
142
|
-
// Retry on error
|
|
143
|
-
continue;
|
|
144
|
-
}
|
|
145
|
-
else {
|
|
146
|
-
break;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
finally {
|
|
152
|
-
// Resolve exit promise
|
|
153
|
-
exitResolve();
|
|
154
|
-
// Cleanup handlers
|
|
155
|
-
session.onUserInput(null);
|
|
156
|
-
session.onSwitch(null);
|
|
157
|
-
session.onPermissionResponseTriggerSwitch(null);
|
|
158
|
-
session.removeSessionFoundCallback(scannerSessionCallback);
|
|
159
|
-
// Cleanup scanner
|
|
160
|
-
await scanner.cleanup();
|
|
161
|
-
// Cleanup hook server and settings file
|
|
162
|
-
hookServer.stop();
|
|
163
|
-
cleanupHookSettingsFile(hookSettingsPath);
|
|
164
|
-
}
|
|
165
|
-
return exitReason || 'exit';
|
|
166
|
-
}
|
|
167
|
-
//# sourceMappingURL=claudeLocalLauncher.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"claudeLocalLauncher.js","sourceRoot":"","sources":["../../src/claude/claudeLocalLauncher.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,27 +0,0 @@
|
|
|
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
|
-
import type { ImageAttachment } from '../utils/messageQueue.js';
|
|
7
|
-
export type PermissionResponse = 'yes' | 'no' | 'always';
|
|
8
|
-
export interface ClaudeRemoteOptions {
|
|
9
|
-
abort: AbortSignal;
|
|
10
|
-
sessionId: string | null;
|
|
11
|
-
path: string;
|
|
12
|
-
onMessage: (message: SDKMessage) => void;
|
|
13
|
-
onSessionFound: (id: string) => void;
|
|
14
|
-
onThinkingChange?: (thinking: boolean) => void;
|
|
15
|
-
nextMessage: () => Promise<{
|
|
16
|
-
message: string;
|
|
17
|
-
images?: ImageAttachment[];
|
|
18
|
-
} | null>;
|
|
19
|
-
waitForPermission: (toolName: string) => Promise<PermissionResponse>;
|
|
20
|
-
onPermissionRequest?: (toolName: string, toolInput: unknown) => void;
|
|
21
|
-
claudeArgs?: string[];
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Run Claude in remote mode using the SDK
|
|
25
|
-
*/
|
|
26
|
-
export declare function claudeRemote(opts: ClaudeRemoteOptions): Promise<string | null>;
|
|
27
|
-
//# sourceMappingURL=claudeRemote.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"claudeRemote.d.ts","sourceRoot":"","sources":["../../src/claude/claudeRemote.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAmD,MAAM,gBAAgB,CAAC;AAClG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AA0DhE,MAAM,MAAM,kBAAkB,GAAG,KAAK,GAAG,IAAI,GAAG,QAAQ,CAAC;AAEzD,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,CAAC;QAAC,MAAM,CAAC,EAAE,eAAe,EAAE,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;IACnF,iBAAiB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACrE,mBAAmB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,KAAK,IAAI,CAAC;IACrE,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAuDD;;GAEG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAwKpF"}
|
|
@@ -1,250 +0,0 @@
|
|
|
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
|
-
* Build SDK content from text and optional images
|
|
57
|
-
*/
|
|
58
|
-
function buildContent(text, images) {
|
|
59
|
-
if (!images || images.length === 0) {
|
|
60
|
-
return text;
|
|
61
|
-
}
|
|
62
|
-
// Build content array with images first, then text
|
|
63
|
-
const content = [];
|
|
64
|
-
// Add images
|
|
65
|
-
for (const img of images) {
|
|
66
|
-
content.push({
|
|
67
|
-
type: 'image',
|
|
68
|
-
source: {
|
|
69
|
-
type: 'base64',
|
|
70
|
-
media_type: img.mimeType,
|
|
71
|
-
data: img.data,
|
|
72
|
-
},
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
// Add text if present
|
|
76
|
-
if (text) {
|
|
77
|
-
content.push({
|
|
78
|
-
type: 'text',
|
|
79
|
-
text: text,
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
return content;
|
|
83
|
-
}
|
|
84
|
-
/**
|
|
85
|
-
* Get project path for Claude sessions
|
|
86
|
-
* Claude uses the resolved path with special chars replaced by dashes
|
|
87
|
-
*/
|
|
88
|
-
function getProjectPath(workingDirectory) {
|
|
89
|
-
const projectId = resolve(workingDirectory).replace(/[\\\/.:]/g, '-');
|
|
90
|
-
const claudeConfigDir = process.env.CLAUDE_CONFIG_DIR || join(homedir(), '.claude');
|
|
91
|
-
return join(claudeConfigDir, 'projects', projectId);
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* Check if Claude session exists
|
|
95
|
-
*/
|
|
96
|
-
function claudeCheckSession(sessionId, workingDirectory) {
|
|
97
|
-
const projectDir = getProjectPath(workingDirectory);
|
|
98
|
-
const sessionFile = join(projectDir, `${sessionId}.jsonl`);
|
|
99
|
-
return existsSync(sessionFile);
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
|
-
* Run Claude in remote mode using the SDK
|
|
103
|
-
*/
|
|
104
|
-
export async function claudeRemote(opts) {
|
|
105
|
-
// Determine session to resume
|
|
106
|
-
let startFrom = opts.sessionId;
|
|
107
|
-
// Extract --resume from claudeArgs if present
|
|
108
|
-
if (!startFrom && opts.claudeArgs) {
|
|
109
|
-
for (let i = 0; i < opts.claudeArgs.length; i++) {
|
|
110
|
-
if (opts.claudeArgs[i] === '--resume') {
|
|
111
|
-
if (i + 1 < opts.claudeArgs.length) {
|
|
112
|
-
const nextArg = opts.claudeArgs[i + 1];
|
|
113
|
-
if (!nextArg.startsWith('-') && nextArg.includes('-')) {
|
|
114
|
-
startFrom = nextArg;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
// Validate session exists
|
|
121
|
-
if (startFrom && !claudeCheckSession(startFrom, opts.path)) {
|
|
122
|
-
startFrom = null;
|
|
123
|
-
}
|
|
124
|
-
// Wait for first message
|
|
125
|
-
const firstMessage = await opts.nextMessage();
|
|
126
|
-
if (!firstMessage) {
|
|
127
|
-
return startFrom;
|
|
128
|
-
}
|
|
129
|
-
// Thinking state
|
|
130
|
-
let thinking = false;
|
|
131
|
-
const updateThinking = (newThinking) => {
|
|
132
|
-
if (thinking !== newThinking) {
|
|
133
|
-
thinking = newThinking;
|
|
134
|
-
if (opts.onThinkingChange) {
|
|
135
|
-
opts.onThinkingChange(thinking);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
};
|
|
139
|
-
// Build SDK options (resume is passed to runQuery separately)
|
|
140
|
-
const sdkOptions = {
|
|
141
|
-
cwd: opts.path,
|
|
142
|
-
abort: opts.abort,
|
|
143
|
-
permissionMode: 'default',
|
|
144
|
-
// Permission callback - notify web UI and wait for response
|
|
145
|
-
canCallTool: async (toolName, input) => {
|
|
146
|
-
// Send permission request to web UI (may be skipped if already always-allowed)
|
|
147
|
-
if (opts.onPermissionRequest) {
|
|
148
|
-
opts.onPermissionRequest(toolName, input);
|
|
149
|
-
}
|
|
150
|
-
// Wait for response from web UI (or get auto-approval if always-allowed)
|
|
151
|
-
const response = await opts.waitForPermission(toolName);
|
|
152
|
-
if (response === 'yes' || response === 'always') {
|
|
153
|
-
return {
|
|
154
|
-
behavior: 'allow',
|
|
155
|
-
updatedInput: input,
|
|
156
|
-
};
|
|
157
|
-
}
|
|
158
|
-
else {
|
|
159
|
-
return {
|
|
160
|
-
behavior: 'deny',
|
|
161
|
-
message: 'User denied permission',
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
},
|
|
165
|
-
};
|
|
166
|
-
// Helper function to run the query loop
|
|
167
|
-
const runQuery = async (sessionToResume, initialMessage) => {
|
|
168
|
-
// Create fresh pushable stream for messages
|
|
169
|
-
const msgStream = new PushableAsyncIterable();
|
|
170
|
-
// Push the initial message
|
|
171
|
-
const initialUserMsg = {
|
|
172
|
-
type: 'user',
|
|
173
|
-
message: { role: 'user', content: buildContent(initialMessage.message, initialMessage.images) },
|
|
174
|
-
};
|
|
175
|
-
msgStream.push(initialUserMsg);
|
|
176
|
-
// Also send to callback so it gets rendered
|
|
177
|
-
opts.onMessage(initialUserMsg);
|
|
178
|
-
const options = {
|
|
179
|
-
...sdkOptions,
|
|
180
|
-
resume: sessionToResume,
|
|
181
|
-
};
|
|
182
|
-
const response = query({
|
|
183
|
-
prompt: msgStream,
|
|
184
|
-
options,
|
|
185
|
-
});
|
|
186
|
-
updateThinking(true);
|
|
187
|
-
console.error('\x1b[90m[debug] Starting message loop\x1b[0m');
|
|
188
|
-
let messageCount = 0;
|
|
189
|
-
for await (const message of response) {
|
|
190
|
-
messageCount++;
|
|
191
|
-
console.error(`\x1b[90m[debug] Message #${messageCount}: type=${message.type}${message.subtype ? `, subtype=${message.subtype}` : ''}\x1b[0m`);
|
|
192
|
-
// Forward message to callback
|
|
193
|
-
opts.onMessage(message);
|
|
194
|
-
if (message.type === 'system' && 'subtype' in message && message.subtype === 'init') {
|
|
195
|
-
updateThinking(true);
|
|
196
|
-
// Extract session ID
|
|
197
|
-
if ('session_id' in message && typeof message.session_id === 'string') {
|
|
198
|
-
opts.onSessionFound(message.session_id);
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
if (message.type === 'result') {
|
|
202
|
-
console.error('\x1b[90m[debug] Got result, waiting for next user message...\x1b[0m');
|
|
203
|
-
updateThinking(false);
|
|
204
|
-
// Get next message
|
|
205
|
-
const next = await opts.nextMessage();
|
|
206
|
-
if (!next) {
|
|
207
|
-
console.error('\x1b[90m[debug] No next message, ending stream\x1b[0m');
|
|
208
|
-
msgStream.end();
|
|
209
|
-
return sessionToResume ?? null;
|
|
210
|
-
}
|
|
211
|
-
console.error(`\x1b[90m[debug] Got next message: "${next.message.slice(0, 50)}..."\x1b[0m`);
|
|
212
|
-
// Push next message (with optional images)
|
|
213
|
-
const nextUserMsg = {
|
|
214
|
-
type: 'user',
|
|
215
|
-
message: { role: 'user', content: buildContent(next.message, next.images) },
|
|
216
|
-
};
|
|
217
|
-
msgStream.push(nextUserMsg);
|
|
218
|
-
// Also send to callback so it gets rendered
|
|
219
|
-
opts.onMessage(nextUserMsg);
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
console.error(`\x1b[90m[debug] Message loop ended after ${messageCount} messages\x1b[0m`);
|
|
223
|
-
return sessionToResume ?? null;
|
|
224
|
-
};
|
|
225
|
-
try {
|
|
226
|
-
return await runQuery(startFrom ?? undefined, firstMessage);
|
|
227
|
-
}
|
|
228
|
-
catch (e) {
|
|
229
|
-
// If resume failed and we were trying to resume, try starting fresh
|
|
230
|
-
if (startFrom && !opts.abort.aborted) {
|
|
231
|
-
console.log(`[remote] Could not resume session ${startFrom}, starting fresh`);
|
|
232
|
-
try {
|
|
233
|
-
return await runQuery(undefined, firstMessage);
|
|
234
|
-
}
|
|
235
|
-
catch (e2) {
|
|
236
|
-
if (!opts.abort.aborted) {
|
|
237
|
-
console.error('[remote] Error starting fresh session:', e2);
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
else if (!opts.abort.aborted) {
|
|
242
|
-
console.error('[remote] Error:', e);
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
finally {
|
|
246
|
-
updateThinking(false);
|
|
247
|
-
}
|
|
248
|
-
return startFrom;
|
|
249
|
-
}
|
|
250
|
-
//# sourceMappingURL=claudeRemote.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"claudeRemote.js","sourceRoot":"","sources":["../../src/claude/claudeRemote.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,15 +0,0 @@
|
|
|
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
|
-
export interface RemoteLauncherOptions {
|
|
7
|
-
session: Session;
|
|
8
|
-
onThinkingChange?: (thinking: boolean) => void;
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* Launch Claude in remote mode
|
|
12
|
-
* Returns 'switch' if we should switch to local mode, 'exit' if we should exit
|
|
13
|
-
*/
|
|
14
|
-
export declare function claudeRemoteLauncher(opts: RemoteLauncherOptions): Promise<RemoteExitReason>;
|
|
15
|
-
//# sourceMappingURL=claudeRemoteLauncher.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
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;AAI5C,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEjD,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAC;CAChD;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,qBAAqB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA+LjG"}
|
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Remote launcher - handles remote mode execution with session management
|
|
3
|
-
*/
|
|
4
|
-
import { claudeRemote } from './claudeRemote.js';
|
|
5
|
-
import { createTerminalRenderer } from './terminalRenderer.js';
|
|
6
|
-
import * as readline from 'node:readline';
|
|
7
|
-
/**
|
|
8
|
-
* Launch Claude in remote mode
|
|
9
|
-
* Returns 'switch' if we should switch to local mode, 'exit' if we should exit
|
|
10
|
-
*/
|
|
11
|
-
export async function claudeRemoteLauncher(opts) {
|
|
12
|
-
const { session, onThinkingChange } = opts;
|
|
13
|
-
let exitReason = null;
|
|
14
|
-
const processAbortController = new AbortController();
|
|
15
|
-
// Setup keyboard listener for switching back to local mode
|
|
16
|
-
const rl = readline.createInterface({
|
|
17
|
-
input: process.stdin,
|
|
18
|
-
output: process.stdout,
|
|
19
|
-
});
|
|
20
|
-
// Listen for any keypress to switch back to local
|
|
21
|
-
readline.emitKeypressEvents(process.stdin);
|
|
22
|
-
if (process.stdin.isTTY) {
|
|
23
|
-
process.stdin.setRawMode(true);
|
|
24
|
-
}
|
|
25
|
-
const keypressHandler = (str, key) => {
|
|
26
|
-
// Switch to local on Enter, Escape, or 'q'
|
|
27
|
-
if (key.name === 'return' || key.name === 'escape' || str === 'q') {
|
|
28
|
-
if (!exitReason) {
|
|
29
|
-
exitReason = 'switch';
|
|
30
|
-
}
|
|
31
|
-
session.queue.reset(); // Unblock waitForMessage
|
|
32
|
-
processAbortController.abort();
|
|
33
|
-
}
|
|
34
|
-
// Ctrl+C to exit completely
|
|
35
|
-
if (key.ctrl && key.name === 'c') {
|
|
36
|
-
if (!exitReason) {
|
|
37
|
-
exitReason = 'exit';
|
|
38
|
-
}
|
|
39
|
-
session.queue.reset(); // Unblock waitForMessage
|
|
40
|
-
processAbortController.abort();
|
|
41
|
-
}
|
|
42
|
-
};
|
|
43
|
-
process.stdin.on('keypress', keypressHandler);
|
|
44
|
-
// Create terminal renderer for displaying messages
|
|
45
|
-
const renderer = createTerminalRenderer();
|
|
46
|
-
try {
|
|
47
|
-
// Handle switch request from web (user wants to go back to local mode)
|
|
48
|
-
session.onSwitch(() => {
|
|
49
|
-
if (!exitReason) {
|
|
50
|
-
exitReason = 'switch';
|
|
51
|
-
}
|
|
52
|
-
session.queue.reset(); // Unblock waitForMessage
|
|
53
|
-
processAbortController.abort();
|
|
54
|
-
});
|
|
55
|
-
// If we have a pending permission response (from local mode) and no messages in queue,
|
|
56
|
-
// queue a "continue" message to trigger Claude to resume.
|
|
57
|
-
// NOTE: Don't do this if there's already a message in queue - that handles AskUserQuestion
|
|
58
|
-
// where the user's selection is sent as user_input.
|
|
59
|
-
if (session.hasPendingPermissionResponse() && session.queue.size() === 0) {
|
|
60
|
-
console.log('\x1b[90m[remote] Pending permission response detected, queueing "continue" to resume Claude\x1b[0m');
|
|
61
|
-
session.queue.push('continue');
|
|
62
|
-
}
|
|
63
|
-
// Run remote mode
|
|
64
|
-
console.log('');
|
|
65
|
-
console.log('\x1b[36m\x1b[1mRemote Mode Active\x1b[0m');
|
|
66
|
-
console.log('\x1b[90mMessages from web will appear here. Press Enter/q to switch to local, Ctrl+C to exit.\x1b[0m');
|
|
67
|
-
console.log('');
|
|
68
|
-
await claudeRemote({
|
|
69
|
-
path: session.path,
|
|
70
|
-
sessionId: session.claudeSessionId,
|
|
71
|
-
abort: processAbortController.signal,
|
|
72
|
-
claudeArgs: session.claudeArgs,
|
|
73
|
-
onMessage: (message) => {
|
|
74
|
-
// Render message in terminal
|
|
75
|
-
renderer.render(message);
|
|
76
|
-
// Forward SDK messages to server
|
|
77
|
-
session.sendClaudeEvent(message);
|
|
78
|
-
},
|
|
79
|
-
onSessionFound: (sessionId) => {
|
|
80
|
-
session.setClaudeSessionId(sessionId);
|
|
81
|
-
},
|
|
82
|
-
onThinkingChange: (thinking) => {
|
|
83
|
-
// Show/hide thinking indicator in terminal
|
|
84
|
-
if (thinking) {
|
|
85
|
-
renderer.showThinking();
|
|
86
|
-
}
|
|
87
|
-
else {
|
|
88
|
-
renderer.clearThinking();
|
|
89
|
-
}
|
|
90
|
-
session.sendThinking(thinking);
|
|
91
|
-
if (onThinkingChange) {
|
|
92
|
-
onThinkingChange(thinking);
|
|
93
|
-
}
|
|
94
|
-
},
|
|
95
|
-
nextMessage: async () => {
|
|
96
|
-
// Wait for next message from queue (includes optional images)
|
|
97
|
-
const queueMsg = await session.queue.waitForMessage();
|
|
98
|
-
if (!queueMsg) {
|
|
99
|
-
// Queue was reset or closed
|
|
100
|
-
return null;
|
|
101
|
-
}
|
|
102
|
-
return { message: queueMsg.message, images: queueMsg.images };
|
|
103
|
-
},
|
|
104
|
-
waitForPermission: async (toolName) => {
|
|
105
|
-
// Check if tool is already "always allowed"
|
|
106
|
-
if (session.isToolAlwaysAllowed(toolName)) {
|
|
107
|
-
console.log(`\x1b[32m✓ Auto-approved: ${toolName} (always allowed)\x1b[0m`);
|
|
108
|
-
return 'always';
|
|
109
|
-
}
|
|
110
|
-
// Check if there's a pending permission response from local mode switch
|
|
111
|
-
const pending = session.consumePendingPermissionResponse();
|
|
112
|
-
if (pending) {
|
|
113
|
-
console.log(`\x1b[32m✓ Using pending permission response: ${pending}\x1b[0m`);
|
|
114
|
-
if (pending === 'always') {
|
|
115
|
-
session.markToolAlwaysAllowed(toolName);
|
|
116
|
-
}
|
|
117
|
-
return pending;
|
|
118
|
-
}
|
|
119
|
-
// Otherwise wait for new response from web
|
|
120
|
-
const response = await session.waitForPermissionResponse();
|
|
121
|
-
// If user selected "always", remember it for this session
|
|
122
|
-
if (response === 'always') {
|
|
123
|
-
session.markToolAlwaysAllowed(toolName);
|
|
124
|
-
}
|
|
125
|
-
return response;
|
|
126
|
-
},
|
|
127
|
-
onPermissionRequest: (toolName, toolInput) => {
|
|
128
|
-
// If tool is already "always allowed", don't show permission request
|
|
129
|
-
if (session.isToolAlwaysAllowed(toolName)) {
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
|
-
// IMPORTANT: Clear ALL pending permission responses before requesting new permission
|
|
133
|
-
// This prevents an OLD response from being consumed by the NEW request
|
|
134
|
-
// (e.g., user approved Bash 20s ago, now Edit is asking - shouldn't auto-approve Edit)
|
|
135
|
-
session.clearPendingPermissionResponse(0);
|
|
136
|
-
// Extra safety: AskUserQuestion should never be auto-answered by a stale queued message
|
|
137
|
-
// (e.g. an old "proceed" sitting in the queue from a previous UI bug).
|
|
138
|
-
if (toolName === 'AskUserQuestion') {
|
|
139
|
-
session.queue.reset();
|
|
140
|
-
}
|
|
141
|
-
// Send permission request event to web UI
|
|
142
|
-
const permissionEvent = {
|
|
143
|
-
type: 'PermissionRequest',
|
|
144
|
-
hook_data: {
|
|
145
|
-
tool_name: toolName,
|
|
146
|
-
tool_input: toolInput,
|
|
147
|
-
},
|
|
148
|
-
};
|
|
149
|
-
session.sendClaudeEvent(permissionEvent);
|
|
150
|
-
// Also render in terminal
|
|
151
|
-
console.log('');
|
|
152
|
-
console.log('\x1b[33m⚠️ Permission Required\x1b[0m');
|
|
153
|
-
console.log(`\x1b[90mTool: ${toolName}\x1b[0m`);
|
|
154
|
-
console.log('\x1b[90mWaiting for approval from web UI...\x1b[0m');
|
|
155
|
-
},
|
|
156
|
-
});
|
|
157
|
-
// Consume one-time flags after spawn
|
|
158
|
-
session.consumeOneTimeFlags();
|
|
159
|
-
// Normal exit if no exit reason set
|
|
160
|
-
if (!exitReason) {
|
|
161
|
-
exitReason = 'exit';
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
catch (e) {
|
|
165
|
-
console.error('[remote] Error:', e);
|
|
166
|
-
if (!exitReason) {
|
|
167
|
-
exitReason = 'exit';
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
finally {
|
|
171
|
-
// Cleanup keyboard listener
|
|
172
|
-
process.stdin.removeListener('keypress', keypressHandler);
|
|
173
|
-
if (process.stdin.isTTY) {
|
|
174
|
-
process.stdin.setRawMode(false);
|
|
175
|
-
}
|
|
176
|
-
rl.close();
|
|
177
|
-
// Cleanup handlers
|
|
178
|
-
session.onSwitch(null);
|
|
179
|
-
}
|
|
180
|
-
return exitReason;
|
|
181
|
-
}
|
|
182
|
-
//# sourceMappingURL=claudeRemoteLauncher.js.map
|