mirror of
https://github.com/wu736139669/hapi.git
synced 2026-08-05 06:24:37 +00:00
refactor: remove thinking state tracking from local launcher
This commit is contained in:
@@ -1,73 +1,7 @@
|
||||
const fs = require('fs');
|
||||
|
||||
// Disable autoupdater (never works really)
|
||||
// Disable autoupdater
|
||||
process.env.DISABLE_AUTOUPDATER = '1';
|
||||
|
||||
// Helper to write JSON messages to fd 3
|
||||
function writeMessage(message) {
|
||||
try {
|
||||
fs.writeSync(3, JSON.stringify(message) + '\n');
|
||||
} catch (err) {
|
||||
// fd 3 not available, ignore
|
||||
}
|
||||
}
|
||||
|
||||
// Intercept fetch to track thinking state
|
||||
const originalFetch = global.fetch;
|
||||
let fetchCounter = 0;
|
||||
|
||||
global.fetch = function(...args) {
|
||||
const id = ++fetchCounter;
|
||||
const url = typeof args[0] === 'string' ? args[0] : args[0]?.url || '';
|
||||
const method = args[1]?.method || 'GET';
|
||||
|
||||
// Parse URL for privacy
|
||||
let hostname = '';
|
||||
let path = '';
|
||||
try {
|
||||
const urlObj = new URL(url, 'http://localhost');
|
||||
hostname = urlObj.hostname;
|
||||
path = urlObj.pathname;
|
||||
} catch (e) {
|
||||
// If URL parsing fails, use defaults
|
||||
hostname = 'unknown';
|
||||
path = url;
|
||||
}
|
||||
|
||||
// Send fetch start event
|
||||
writeMessage({
|
||||
type: 'fetch-start',
|
||||
id,
|
||||
hostname,
|
||||
path,
|
||||
method,
|
||||
timestamp: Date.now()
|
||||
});
|
||||
|
||||
// Execute the original fetch immediately
|
||||
const fetchPromise = originalFetch(...args);
|
||||
|
||||
// Attach handlers to send fetch end event
|
||||
const sendEnd = () => {
|
||||
writeMessage({
|
||||
type: 'fetch-end',
|
||||
id,
|
||||
timestamp: Date.now()
|
||||
});
|
||||
};
|
||||
|
||||
// Send end event on both success and failure
|
||||
fetchPromise.then(sendEnd, sendEnd);
|
||||
|
||||
// Return the original promise unchanged
|
||||
return fetchPromise;
|
||||
};
|
||||
|
||||
// Preserve fetch properties
|
||||
Object.defineProperty(global.fetch, 'name', { value: 'fetch' });
|
||||
Object.defineProperty(global.fetch, 'length', { value: originalFetch.length });
|
||||
|
||||
// Import global Claude Code CLI
|
||||
const { getClaudeCliPath, runClaudeCli } = require('./claude_version_utils.cjs');
|
||||
|
||||
runClaudeCli(getClaudeCliPath());
|
||||
runClaudeCli(getClaudeCliPath());
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { spawn } from "node:child_process";
|
||||
import { resolve, join } from "node:path";
|
||||
import { createInterface } from "node:readline";
|
||||
import { mkdirSync, existsSync } from "node:fs";
|
||||
import { randomUUID } from "node:crypto";
|
||||
import { logger } from "@/ui/logger";
|
||||
@@ -20,7 +19,6 @@ export async function claudeLocal(opts: {
|
||||
mcpServers?: Record<string, any>,
|
||||
path: string,
|
||||
onSessionFound: (id: string) => void,
|
||||
onThinkingChange?: (thinking: boolean) => void,
|
||||
claudeEnvVars?: Record<string, string>,
|
||||
claudeArgs?: string[]
|
||||
allowedTools?: string[]
|
||||
@@ -51,19 +49,6 @@ export async function claudeLocal(opts: {
|
||||
opts.onSessionFound(startFrom!);
|
||||
}
|
||||
|
||||
// Thinking state
|
||||
let thinking = false;
|
||||
let stopThinkingTimeout: NodeJS.Timeout | null = null;
|
||||
const updateThinking = (newThinking: boolean) => {
|
||||
if (thinking !== newThinking) {
|
||||
thinking = newThinking;
|
||||
logger.debug(`[ClaudeLocal] Thinking state changed to: ${thinking}`);
|
||||
if (opts.onThinkingChange) {
|
||||
opts.onThinkingChange(thinking);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Spawn the process
|
||||
try {
|
||||
// Start the interactive process
|
||||
@@ -100,7 +85,6 @@ export async function claudeLocal(opts: {
|
||||
|
||||
// Prepare environment variables
|
||||
// Note: Local mode uses global Claude installation with --session-id flag
|
||||
// Launcher only intercepts fetch for thinking state tracking
|
||||
const env = {
|
||||
...process.env,
|
||||
...opts.claudeEnvVars
|
||||
@@ -110,79 +94,11 @@ export async function claudeLocal(opts: {
|
||||
logger.debug(`[ClaudeLocal] Args: ${JSON.stringify(args)}`);
|
||||
|
||||
const child = spawn(process.execPath, [claudeCliPath, ...args], {
|
||||
stdio: ['inherit', 'inherit', 'inherit', 'pipe'],
|
||||
stdio: ['inherit', 'inherit', 'inherit'],
|
||||
signal: opts.abort,
|
||||
cwd: opts.path,
|
||||
env: withBunRuntimeEnv(env),
|
||||
});
|
||||
|
||||
// Listen to the custom fd (fd 3) for thinking state tracking
|
||||
if (child.stdio[3]) {
|
||||
const rl = createInterface({
|
||||
input: child.stdio[3] as any,
|
||||
crlfDelay: Infinity
|
||||
});
|
||||
|
||||
// Track active fetches for thinking state
|
||||
const activeFetches = new Map<number, { hostname: string, path: string, startTime: number }>();
|
||||
|
||||
rl.on('line', (line) => {
|
||||
try {
|
||||
const message = JSON.parse(line);
|
||||
|
||||
switch (message.type) {
|
||||
case 'fetch-start':
|
||||
activeFetches.set(message.id, {
|
||||
hostname: message.hostname,
|
||||
path: message.path,
|
||||
startTime: message.timestamp
|
||||
});
|
||||
|
||||
// Clear any pending stop timeout
|
||||
if (stopThinkingTimeout) {
|
||||
clearTimeout(stopThinkingTimeout);
|
||||
stopThinkingTimeout = null;
|
||||
}
|
||||
|
||||
// Start thinking
|
||||
updateThinking(true);
|
||||
break;
|
||||
|
||||
case 'fetch-end':
|
||||
activeFetches.delete(message.id);
|
||||
|
||||
// Stop thinking when no active fetches
|
||||
if (activeFetches.size === 0 && thinking && !stopThinkingTimeout) {
|
||||
stopThinkingTimeout = setTimeout(() => {
|
||||
if (activeFetches.size === 0) {
|
||||
updateThinking(false);
|
||||
}
|
||||
stopThinkingTimeout = null;
|
||||
}, 500); // Small delay to avoid flickering
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
logger.debug(`[ClaudeLocal] Unknown message type: ${message.type}`);
|
||||
}
|
||||
} catch (e) {
|
||||
// Not JSON, ignore (could be other output)
|
||||
logger.debug(`[ClaudeLocal] Non-JSON line from fd3: ${line}`);
|
||||
}
|
||||
});
|
||||
|
||||
rl.on('error', (err) => {
|
||||
console.error('Error reading from fd 3:', err);
|
||||
});
|
||||
|
||||
// Cleanup on child exit
|
||||
child.on('exit', () => {
|
||||
if (stopThinkingTimeout) {
|
||||
clearTimeout(stopThinkingTimeout);
|
||||
}
|
||||
updateThinking(false);
|
||||
});
|
||||
}
|
||||
child.on('error', (error) => {
|
||||
// Ignore
|
||||
});
|
||||
@@ -199,11 +115,6 @@ export async function claudeLocal(opts: {
|
||||
});
|
||||
} finally {
|
||||
process.stdin.resume();
|
||||
if (stopThinkingTimeout) {
|
||||
clearTimeout(stopThinkingTimeout);
|
||||
stopThinkingTimeout = null;
|
||||
}
|
||||
updateThinking(false);
|
||||
}
|
||||
|
||||
return effectiveSessionId;
|
||||
|
||||
@@ -95,7 +95,6 @@ export async function claudeLocalLauncher(session: Session): Promise<'switch' |
|
||||
path: session.path,
|
||||
sessionId: session.sessionId,
|
||||
onSessionFound: handleSessionStart,
|
||||
onThinkingChange: session.onThinkingChange,
|
||||
abort: processAbortController.signal,
|
||||
claudeEnvVars: session.claudeEnvVars,
|
||||
claudeArgs: session.claudeArgs,
|
||||
@@ -139,4 +138,4 @@ export async function claudeLocalLauncher(session: Session): Promise<'switch' |
|
||||
|
||||
// Return
|
||||
return exitReason || 'exit';
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user