@adhdev/daemon-core 0.6.18 → 0.6.21
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/index.d.ts +3 -0
- package/dist/index.js +122 -9
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/commands/handler.ts +85 -0
- package/src/daemon/dev-server.ts +28 -10
package/package.json
CHANGED
package/src/commands/handler.ts
CHANGED
|
@@ -369,6 +369,12 @@ export class DaemonCommandHandler implements CommandHelpers {
|
|
|
369
369
|
case 'list_extension_modes': return Stream.handleExtensionScript(this, args, 'listModes');
|
|
370
370
|
case 'set_extension_mode': return Stream.handleExtensionScript(this, args, 'setMode');
|
|
371
371
|
|
|
372
|
+
// ─── Provider Auto-Fix / Clone (DevServer proxy) ──────────
|
|
373
|
+
case 'provider_auto_fix': return this.proxyDevServerPost(args, 'auto-implement');
|
|
374
|
+
case 'provider_auto_fix_cancel': return this.proxyDevServerPost(args, 'auto-implement/cancel');
|
|
375
|
+
case 'provider_auto_fix_status': return this.proxyDevServerGet(args, 'auto-implement/status');
|
|
376
|
+
case 'provider_clone': return this.proxyDevServerScaffold(args);
|
|
377
|
+
|
|
372
378
|
default:
|
|
373
379
|
return { success: false, error: `Unknown command: ${cmd}` };
|
|
374
380
|
}
|
|
@@ -398,4 +404,83 @@ export class DaemonCommandHandler implements CommandHelpers {
|
|
|
398
404
|
}
|
|
399
405
|
return { success: false, error: 'ProviderLoader not initialized' };
|
|
400
406
|
}
|
|
407
|
+
|
|
408
|
+
// ─── DevServer HTTP proxy helpers ─────────────────
|
|
409
|
+
// These bridge WS commands to the DevServer REST API (localhost:19280)
|
|
410
|
+
|
|
411
|
+
private async proxyDevServerPost(args: any, endpoint: string): Promise<CommandResult> {
|
|
412
|
+
const { providerType, ...body } = args || {};
|
|
413
|
+
if (!providerType) return { success: false, error: 'providerType required' };
|
|
414
|
+
try {
|
|
415
|
+
const http = await import('http');
|
|
416
|
+
const postData = JSON.stringify(body);
|
|
417
|
+
const result = await new Promise<any>((resolve, reject) => {
|
|
418
|
+
const req = http.request({
|
|
419
|
+
hostname: '127.0.0.1', port: 19280,
|
|
420
|
+
path: `/api/providers/${providerType}/${endpoint}`,
|
|
421
|
+
method: 'POST',
|
|
422
|
+
headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(postData) },
|
|
423
|
+
}, (res) => {
|
|
424
|
+
let data = '';
|
|
425
|
+
res.on('data', (chunk: Buffer) => data += chunk);
|
|
426
|
+
res.on('end', () => {
|
|
427
|
+
try { resolve(JSON.parse(data)); } catch { resolve({ raw: data }); }
|
|
428
|
+
});
|
|
429
|
+
});
|
|
430
|
+
req.on('error', reject);
|
|
431
|
+
req.write(postData);
|
|
432
|
+
req.end();
|
|
433
|
+
});
|
|
434
|
+
return { success: true, ...result };
|
|
435
|
+
} catch (e: any) {
|
|
436
|
+
return { success: false, error: `DevServer unreachable: ${e.message}. Start daemon with --dev flag.` };
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
private async proxyDevServerGet(args: any, endpoint: string): Promise<CommandResult> {
|
|
441
|
+
const { providerType } = args || {};
|
|
442
|
+
if (!providerType) return { success: false, error: 'providerType required' };
|
|
443
|
+
try {
|
|
444
|
+
const http = await import('http');
|
|
445
|
+
const result = await new Promise<any>((resolve, reject) => {
|
|
446
|
+
http.get(`http://127.0.0.1:19280/api/providers/${providerType}/${endpoint}`, (res) => {
|
|
447
|
+
let data = '';
|
|
448
|
+
res.on('data', (chunk: Buffer) => data += chunk);
|
|
449
|
+
res.on('end', () => {
|
|
450
|
+
try { resolve(JSON.parse(data)); } catch { resolve({ raw: data }); }
|
|
451
|
+
});
|
|
452
|
+
}).on('error', reject);
|
|
453
|
+
});
|
|
454
|
+
return { success: true, ...result };
|
|
455
|
+
} catch (e: any) {
|
|
456
|
+
return { success: false, error: `DevServer unreachable: ${e.message}. Start daemon with --dev flag.` };
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
private async proxyDevServerScaffold(args: any): Promise<CommandResult> {
|
|
461
|
+
try {
|
|
462
|
+
const http = await import('http');
|
|
463
|
+
const postData = JSON.stringify(args || {});
|
|
464
|
+
const result = await new Promise<any>((resolve, reject) => {
|
|
465
|
+
const req = http.request({
|
|
466
|
+
hostname: '127.0.0.1', port: 19280,
|
|
467
|
+
path: '/api/scaffold',
|
|
468
|
+
method: 'POST',
|
|
469
|
+
headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(postData) },
|
|
470
|
+
}, (res) => {
|
|
471
|
+
let data = '';
|
|
472
|
+
res.on('data', (chunk: Buffer) => data += chunk);
|
|
473
|
+
res.on('end', () => {
|
|
474
|
+
try { resolve(JSON.parse(data)); } catch { resolve({ raw: data }); }
|
|
475
|
+
});
|
|
476
|
+
});
|
|
477
|
+
req.on('error', reject);
|
|
478
|
+
req.write(postData);
|
|
479
|
+
req.end();
|
|
480
|
+
});
|
|
481
|
+
return { success: true, ...result };
|
|
482
|
+
} catch (e: any) {
|
|
483
|
+
return { success: false, error: `DevServer unreachable: ${e.message}. Start daemon with --dev flag.` };
|
|
484
|
+
}
|
|
485
|
+
}
|
|
401
486
|
}
|
package/src/daemon/dev-server.ts
CHANGED
|
@@ -323,7 +323,7 @@ export class DevServer {
|
|
|
323
323
|
return;
|
|
324
324
|
}
|
|
325
325
|
|
|
326
|
-
const cdp = this.getCdp(scriptIdeType);
|
|
326
|
+
const cdp = this.getCdp(scriptIdeType || type);
|
|
327
327
|
if (!cdp) {
|
|
328
328
|
this.json(res, 503, { error: 'No CDP connection available' });
|
|
329
329
|
return;
|
|
@@ -1824,7 +1824,7 @@ export class DevServer {
|
|
|
1824
1824
|
|
|
1825
1825
|
private async handleAutoImplement(type: string, req: http.IncomingMessage, res: http.ServerResponse): Promise<void> {
|
|
1826
1826
|
const body = await this.readBody(req);
|
|
1827
|
-
const { agent = 'claude-cli', functions, reference = 'antigravity', model } = body;
|
|
1827
|
+
const { agent = 'claude-cli', functions, reference = 'antigravity', model, comment } = body;
|
|
1828
1828
|
if (!functions || !Array.isArray(functions) || functions.length === 0) {
|
|
1829
1829
|
this.json(res, 400, { error: 'functions[] is required (e.g. ["readChat", "sendMessage"])' });
|
|
1830
1830
|
return;
|
|
@@ -1874,7 +1874,7 @@ export class DevServer {
|
|
|
1874
1874
|
}
|
|
1875
1875
|
|
|
1876
1876
|
// 3. Build the prompt
|
|
1877
|
-
const prompt = this.buildAutoImplPrompt(type, provider, providerDir, functions, domContext, referenceScripts);
|
|
1877
|
+
const prompt = this.buildAutoImplPrompt(type, provider, providerDir, functions, domContext, referenceScripts, comment);
|
|
1878
1878
|
|
|
1879
1879
|
// 4. Write prompt to temp file (avoids shell escaping issues with special chars)
|
|
1880
1880
|
const tmpDir = path.join(os.tmpdir(), 'adhdev-autoimpl');
|
|
@@ -2028,10 +2028,12 @@ export class DevServer {
|
|
|
2028
2028
|
let shellCmd: string;
|
|
2029
2029
|
|
|
2030
2030
|
if (command === 'claude') {
|
|
2031
|
-
// Claude Code: --print
|
|
2032
|
-
const args = [...baseArgs, '--
|
|
2031
|
+
// Claude Code: autonomous agent mode (no --print), skip permissions, prompt via meta-prompt
|
|
2032
|
+
const args = [...baseArgs, '--dangerously-skip-permissions'];
|
|
2033
|
+
if (model) args.push('--model', model);
|
|
2033
2034
|
const escapedArgs = args.map(a => `'${a.replace(/'/g, "'\\''")}'`).join(' ');
|
|
2034
|
-
|
|
2035
|
+
const metaPrompt = `Read the file at ${promptFile} and follow ALL the instructions. Implement the specific function requested, then test it via CDP curl targeting 127.0.0.1:19280, wait for confirmation of success, and then close. DO NOT start working on other features not listed in the prompt constraint.`;
|
|
2036
|
+
shellCmd = `${command} ${escapedArgs} -p "${metaPrompt}"`;
|
|
2035
2037
|
} else if (command === 'gemini') {
|
|
2036
2038
|
// Gemini CLI: non-interactive prompt mode
|
|
2037
2039
|
// We can't use @file syntax (causes Parts object parsing bug) or $(cat) (arg too long).
|
|
@@ -2051,7 +2053,7 @@ export class DevServer {
|
|
|
2051
2053
|
}
|
|
2052
2054
|
if (model) args.push('--model', model);
|
|
2053
2055
|
const escapedArgs = args.map(a => `'${a.replace(/'/g, "'\\''")}'`).join(' ');
|
|
2054
|
-
const metaPrompt = `Read the file at ${promptFile} and follow ALL
|
|
2056
|
+
const metaPrompt = `Read the file at ${promptFile} and follow ALL instructions recursively. You have full authority to implement ALL required script files, update provider.json configurations based on the reference patterns, and independently test them against 127.0.0.1:19280 via CDP CURL. Upon complete validation of ALL assigned files, print exactly "AUTO_IMPLEMENT_FINISHED" to gracefully close the pipeline. DO NOT WAIT FOR APPROVAL, execute completely autonomously.`;
|
|
2055
2057
|
shellCmd = `${command} ${escapedArgs} "${metaPrompt}"`;
|
|
2056
2058
|
} else {
|
|
2057
2059
|
// Generic fallback: pipe prompt via stdin
|
|
@@ -2062,6 +2064,7 @@ export class DevServer {
|
|
|
2062
2064
|
this.sendAutoImplSSE({ event: 'progress', data: { function: '_init', status: 'spawning', message: `에이전트 실행 중: ${shellCmd.substring(0, 200)}... (prompt: ${prompt.length} chars)` } });
|
|
2063
2065
|
|
|
2064
2066
|
this.autoImplStatus = { running: true, type, progress: [] };
|
|
2067
|
+
const spawnedAt = Date.now();
|
|
2065
2068
|
|
|
2066
2069
|
let child: any;
|
|
2067
2070
|
let isPty = false;
|
|
@@ -2126,9 +2129,10 @@ export class DevServer {
|
|
|
2126
2129
|
|
|
2127
2130
|
approvalBuffer = (approvalBuffer + cleanData).slice(-1500);
|
|
2128
2131
|
|
|
2129
|
-
// Force exit on completion signal
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
+
// Force exit on completion signal (ignore during first 15s — prompt echo contains the token)
|
|
2133
|
+
const elapsed = Date.now() - spawnedAt;
|
|
2134
|
+
if (elapsed > 15000 && approvalBuffer.includes('AUTO_IMPLEMENT_FINISHED')) {
|
|
2135
|
+
this.log(`Agent finished task after ${Math.round(elapsed/1000)}s. Terminating interactive CLI session to unblock pipeline.`);
|
|
2132
2136
|
this.sendAutoImplSSE({ event: 'output', data: { chunk: `\n[🤖 ADHDev Pipeline] Completion token detected. Proceeding...\n`, stream: 'stdout' } });
|
|
2133
2137
|
approvalBuffer = '';
|
|
2134
2138
|
|
|
@@ -2229,6 +2233,7 @@ export class DevServer {
|
|
|
2229
2233
|
functions: string[],
|
|
2230
2234
|
domContext: any,
|
|
2231
2235
|
referenceScripts: Record<string, string>,
|
|
2236
|
+
userComment?: string,
|
|
2232
2237
|
): string {
|
|
2233
2238
|
const lines: string[] = [];
|
|
2234
2239
|
|
|
@@ -2352,6 +2357,10 @@ export class DevServer {
|
|
|
2352
2357
|
lines.push('1. Edit the script files to implement working code');
|
|
2353
2358
|
lines.push('2. After editing, TEST each function using the DevConsole API (see below)');
|
|
2354
2359
|
lines.push('3. If a test fails, fix the implementation and re-test');
|
|
2360
|
+
lines.push('4. **IMPORTANT VERIFICATION LOGIC**: When verifying your implementation, beware of state contamination! You MUST perform strict Integration Testing:');
|
|
2361
|
+
lines.push(' - `openPanel`: Toggle buttons are usually located in the top header, sidebar, or activity bar. Prefer finding and clicking these native UI buttons over extreme CSS injection hacks if possible.');
|
|
2362
|
+
lines.push(' - `listSessions`: If sessions are unmounted when the panel is closed, try to explicitly interact with the UI to open the history/sessions view (e.g., clicking a history icon usually found near the chat header) BEFORE scraping.');
|
|
2363
|
+
lines.push(' - `switchSession`: Prove your switch was successful by subsequently calling `readChat` and explicitly checking that the chat context has actually changed.');
|
|
2355
2364
|
lines.push('');
|
|
2356
2365
|
|
|
2357
2366
|
// ── DevConsole API for verification ──
|
|
@@ -2388,6 +2397,15 @@ export class DevServer {
|
|
|
2388
2397
|
lines.push('3. Use CDP evaluate to deeply inspect the DOM structure of the newly generated tables, code blocks, thought blocks, and tool calls.');
|
|
2389
2398
|
lines.push('4. Ensure `readChat` extracts `content` with precise markdown formatting (especially for tables/code) and assigns correct `kind` tags (`thought`, `tool`, `terminal`).');
|
|
2390
2399
|
lines.push('');
|
|
2400
|
+
// ── User-provided additional instructions ──
|
|
2401
|
+
if (userComment) {
|
|
2402
|
+
lines.push('## ⚠️ User Instructions (HIGH PRIORITY)');
|
|
2403
|
+
lines.push('The user has provided the following additional instructions. Follow them strictly:');
|
|
2404
|
+
lines.push('');
|
|
2405
|
+
lines.push(userComment);
|
|
2406
|
+
lines.push('');
|
|
2407
|
+
}
|
|
2408
|
+
|
|
2391
2409
|
lines.push('Start NOW. Do not ask for permission. Explore the DOM -> Code -> Test.');
|
|
2392
2410
|
|
|
2393
2411
|
return lines.join('\n');
|