@adhdev/daemon-core 0.6.34 → 0.6.36

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhdev/daemon-core",
3
- "version": "0.6.34",
3
+ "version": "0.6.36",
4
4
  "description": "ADHDev daemon core — CDP, IDE detection, providers, command execution",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -503,18 +503,31 @@ export class DaemonCdpManager {
503
503
  });
504
504
  await new Promise(r => setTimeout(r, 150));
505
505
 
506
- // Step 3: Insert text
507
- await this.sendInternal('Input.insertText', { text });
506
+ // Step 3: Insert text & handle newlines
507
+ const lines = text.split('\n');
508
+ for (let i = 0; i < lines.length; i++) {
509
+ if (lines[i].length > 0) {
510
+ await this.sendInternal('Input.insertText', { text: lines[i] });
511
+ await new Promise(r => setTimeout(r, 100));
512
+ }
513
+ if (i < lines.length - 1) {
514
+ await this.sendInternal('Input.dispatchKeyEvent', { type: 'rawKeyDown', key: 'Enter', code: 'Enter', windowsVirtualKeyCode: 13, modifiers: 8 }); // Shift
515
+ await this.sendInternal('Input.dispatchKeyEvent', { type: 'char', key: 'Enter', code: 'Enter', windowsVirtualKeyCode: 13, text: '\r', unmodifiedText: '\r', modifiers: 8 });
516
+ await this.sendInternal('Input.dispatchKeyEvent', { type: 'keyUp', key: 'Enter', code: 'Enter', windowsVirtualKeyCode: 13, modifiers: 8 });
517
+ await new Promise(r => setTimeout(r, 100));
518
+ }
519
+ }
508
520
  await new Promise(r => setTimeout(r, 200));
509
521
 
510
522
  // Step 4: Press Enter
511
523
  await this.sendInternal('Input.dispatchKeyEvent', {
512
- type: 'rawKeyDown', key: 'Enter', code: 'Enter',
513
- windowsVirtualKeyCode: 13, nativeVirtualKeyCode: 13,
524
+ type: 'rawKeyDown', key: 'Enter', code: 'Enter', windowsVirtualKeyCode: 13, text: '\r', unmodifiedText: '\r'
525
+ });
526
+ await this.sendInternal('Input.dispatchKeyEvent', {
527
+ type: 'char', key: 'Enter', code: 'Enter', windowsVirtualKeyCode: 13, text: '\r', unmodifiedText: '\r'
514
528
  });
515
529
  await this.sendInternal('Input.dispatchKeyEvent', {
516
- type: 'keyUp', key: 'Enter', code: 'Enter',
517
- windowsVirtualKeyCode: 13, nativeVirtualKeyCode: 13,
530
+ type: 'keyUp', key: 'Enter', code: 'Enter', windowsVirtualKeyCode: 13
518
531
  });
519
532
 
520
533
  this.log(`[CDP] typeAndSend: sent "${text.substring(0, 50)}..."`);
@@ -558,18 +571,31 @@ export class DaemonCdpManager {
558
571
  });
559
572
  await new Promise(r => setTimeout(r, 150));
560
573
 
561
- // Step 3: Insert text
562
- await this.sendInternal('Input.insertText', { text });
574
+ // Step 3: Insert text & handle newlines
575
+ const lines = text.split('\n');
576
+ for (let i = 0; i < lines.length; i++) {
577
+ if (lines[i].length > 0) {
578
+ await this.sendInternal('Input.insertText', { text: lines[i] });
579
+ await new Promise(r => setTimeout(r, 100));
580
+ }
581
+ if (i < lines.length - 1) {
582
+ await this.sendInternal('Input.dispatchKeyEvent', { type: 'rawKeyDown', key: 'Enter', code: 'Enter', windowsVirtualKeyCode: 13, modifiers: 8 }); // Shift
583
+ await this.sendInternal('Input.dispatchKeyEvent', { type: 'char', key: 'Enter', code: 'Enter', windowsVirtualKeyCode: 13, text: '\r', unmodifiedText: '\r', modifiers: 8 });
584
+ await this.sendInternal('Input.dispatchKeyEvent', { type: 'keyUp', key: 'Enter', code: 'Enter', windowsVirtualKeyCode: 13, modifiers: 8 });
585
+ await new Promise(r => setTimeout(r, 100));
586
+ }
587
+ }
563
588
  await new Promise(r => setTimeout(r, 200));
564
589
 
565
590
  // Step 4: Press Enter
566
591
  await this.sendInternal('Input.dispatchKeyEvent', {
567
- type: 'rawKeyDown', key: 'Enter', code: 'Enter',
568
- windowsVirtualKeyCode: 13, nativeVirtualKeyCode: 13,
592
+ type: 'rawKeyDown', key: 'Enter', code: 'Enter', windowsVirtualKeyCode: 13, text: '\r', unmodifiedText: '\r'
593
+ });
594
+ await this.sendInternal('Input.dispatchKeyEvent', {
595
+ type: 'char', key: 'Enter', code: 'Enter', windowsVirtualKeyCode: 13, text: '\r', unmodifiedText: '\r'
569
596
  });
570
597
  await this.sendInternal('Input.dispatchKeyEvent', {
571
- type: 'keyUp', key: 'Enter', code: 'Enter',
572
- windowsVirtualKeyCode: 13, nativeVirtualKeyCode: 13,
598
+ type: 'keyUp', key: 'Enter', code: 'Enter', windowsVirtualKeyCode: 13
573
599
  });
574
600
 
575
601
  this.log(`[CDP] typeAndSendAt(${Math.round(x)},${Math.round(y)}): sent "${text.substring(0, 50)}..."`);
@@ -78,6 +78,7 @@ export class DevServer {
78
78
  { method: 'GET', pattern: '/api/providers/versions', handler: (q, s) => this.handleDetectVersions(q, s) },
79
79
  { method: 'POST', pattern: '/api/providers/reload', handler: (q, s) => this.handleReload(q, s) },
80
80
  { method: 'POST', pattern: '/api/cdp/evaluate', handler: (q, s) => this.handleCdpEvaluate(q, s) },
81
+ { method: 'POST', pattern: '/api/cdp/click', handler: (q, s) => this.handleCdpClick(q, s) },
81
82
  { method: 'POST', pattern: '/api/cdp/dom/query', handler: (q, s) => this.handleCdpDomQuery(q, s) },
82
83
  { method: 'POST', pattern: '/api/cdp/dom/inspect', handler: (q, s) => this.handleDomInspect(q, s) },
83
84
  { method: 'POST', pattern: '/api/cdp/dom/children', handler: (q, s) => this.handleDomChildren(q, s) },
@@ -108,6 +109,7 @@ export class DevServer {
108
109
  { method: 'POST', pattern: /^\/api\/providers\/([^/]+)\/file$/, handler: (q, s, p) => this.handleWriteFile(p![0], q, s) },
109
110
  { method: 'GET', pattern: /^\/api\/providers\/([^/]+)\/source$/, handler: (q, s, p) => this.handleSource(p![0], q, s) },
110
111
  { method: 'POST', pattern: /^\/api\/providers\/([^/]+)\/save$/, handler: (q, s, p) => this.handleSave(p![0], q, s) },
112
+ { method: 'POST', pattern: /^\/api\/providers\/([^/]+)\/typeAndSend$/, handler: (q, s, p) => this.handleTypeAndSend(p![0], q, s) },
111
113
  { method: 'GET', pattern: /^\/api\/providers\/([^/]+)\/config$/, handler: (q, s, p) => this.handleProviderConfig(p![0], q, s) },
112
114
  { method: 'POST', pattern: /^\/api\/providers\/([^/]+)\/dom-context$/, handler: (q, s, p) => this.handleDomContext(p![0], q, s) },
113
115
  { method: 'POST', pattern: /^\/api\/providers\/([^/]+)\/auto-implement$/, handler: (q, s, p) => this.handleAutoImplement(p![0], q, s) },
@@ -371,6 +373,7 @@ export class DevServer {
371
373
  if (typeof raw === 'string') {
372
374
  try { result = JSON.parse(raw); } catch { /* keep */ }
373
375
  }
376
+ this.log(`Script raw debug: typeof=${typeof raw}, raw=${JSON.stringify(raw)}, parsed=${JSON.stringify(result)}`);
374
377
  this.json(res, 200, { type, script: scriptName, result });
375
378
  } catch (e: any) {
376
379
  this.json(res, 500, { error: `Script execution failed: ${e.message}` });
@@ -406,6 +409,29 @@ export class DevServer {
406
409
  }
407
410
  }
408
411
 
412
+ private async handleCdpClick(req: http.IncomingMessage, res: http.ServerResponse): Promise<void> {
413
+ const body = await this.readBody(req);
414
+ const { ideType, x, y } = body;
415
+ if (x == null || y == null) {
416
+ this.json(res, 400, { error: 'x and y coordinates required' });
417
+ return;
418
+ }
419
+
420
+ const cdp = this.getCdp(ideType);
421
+ if (!cdp?.isConnected) {
422
+ this.json(res, 503, { error: 'No CDP connection available' });
423
+ return;
424
+ }
425
+
426
+ try {
427
+ await cdp.send('Input.dispatchMouseEvent', { type: 'mousePressed', x, y, button: 'left', clickCount: 1 });
428
+ await cdp.send('Input.dispatchMouseEvent', { type: 'mouseReleased', x, y, button: 'left', clickCount: 1 });
429
+ this.json(res, 200, { success: true, clicked: true, x, y });
430
+ } catch (e: any) {
431
+ this.json(res, 500, { error: e.message });
432
+ }
433
+ }
434
+
409
435
  private async handleCdpDomQuery(req: http.IncomingMessage, res: http.ServerResponse): Promise<void> {
410
436
  const body = await this.readBody(req);
411
437
  const { selector, limit = 10, ideType } = body;
@@ -522,6 +548,11 @@ export class DevServer {
522
548
  const providers = this.providerLoader.getAll().map(p => ({
523
549
  type: p.type, name: p.name, category: p.category,
524
550
  }));
551
+ for (const cdp of this.cdpManagers.values()) {
552
+ if (!cdp.isConnected) {
553
+ (cdp as any)._targetId = null;
554
+ }
555
+ }
525
556
  this.json(res, 200, { reloaded: true, providers });
526
557
  } catch (e: any) {
527
558
  this.json(res, 500, { error: e.message });
@@ -692,7 +723,7 @@ export class DevServer {
692
723
  const provider = this.providerLoader.getMeta(type);
693
724
  if (!provider) return null;
694
725
  const cat = provider.category;
695
- const builtinDir = (this.providerLoader as any).builtinDir || path.resolve(__dirname, '../providers/_builtin');
726
+ const builtinDir = (this.providerLoader as any).builtinDirs?.[0] || path.resolve(__dirname, '../providers/_builtin');
696
727
  const userDir = path.join(os.homedir(), '.adhdev', 'providers');
697
728
 
698
729
  // Direct match first
@@ -833,6 +864,24 @@ export class DevServer {
833
864
  }
834
865
  }
835
866
 
867
+ private async handleTypeAndSend(type: string, req: http.IncomingMessage, res: http.ServerResponse): Promise<void> {
868
+ const body = await this.readBody(req);
869
+ const { selector, text } = body;
870
+ if (!selector || typeof selector !== 'string' || !text || typeof text !== 'string') {
871
+ this.json(res, 400, { error: 'selector and text strings required' }); return;
872
+ }
873
+ const cdp = this.getCdp(type);
874
+ if (!cdp) {
875
+ this.json(res, 503, { error: `CDP not connected for '${type}'` }); return;
876
+ }
877
+ try {
878
+ const sent = await cdp.typeAndSend(selector, text);
879
+ this.json(res, 200, { sent });
880
+ } catch (e: any) {
881
+ this.json(res, 500, { error: e.message });
882
+ }
883
+ }
884
+
836
885
  private async handleScriptHints(type: string, _req: http.IncomingMessage, res: http.ServerResponse): Promise<void> {
837
886
  const dir = this.findProviderDir(type);
838
887
  if (!dir) { this.json(res, 404, { error: `Provider not found: ${type}` }); return; }
@@ -1065,7 +1114,7 @@ export class DevServer {
1065
1114
  if (location === 'user') {
1066
1115
  targetDir = path.join(os.homedir(), '.adhdev', 'providers', type);
1067
1116
  } else {
1068
- const builtinDir = path.resolve(__dirname, '../providers/_builtin');
1117
+ const builtinDir = (this.providerLoader as any).builtinDirs?.[0] || path.resolve(__dirname, '../providers/_builtin');
1069
1118
  targetDir = path.join(builtinDir, category, type);
1070
1119
  }
1071
1120
 
@@ -1851,7 +1900,7 @@ export class DevServer {
1851
1900
  this.sendAutoImplSSE({ event: 'progress', data: { function: '_init', status: 'loading_reference', message: `레퍼런스 스크립트 로드 중 (${reference})...` } });
1852
1901
 
1853
1902
  let referenceScripts: Record<string, string> = {};
1854
- const builtinDir = (this.providerLoader as any).builtinDir || path.resolve(__dirname, '../providers/_builtin');
1903
+ const builtinDir = (this.providerLoader as any).builtinDirs?.[0] || path.resolve(__dirname, '../providers/_builtin');
1855
1904
  const refDir = path.join(builtinDir, 'ide', reference);
1856
1905
  if (fs.existsSync(refDir)) {
1857
1906
  // Find latest versioned scripts dir
@@ -2053,7 +2102,7 @@ export class DevServer {
2053
2102
  }
2054
2103
  if (model) args.push('--model', model);
2055
2104
  const escapedArgs = args.map(a => `'${a.replace(/'/g, "'\\''")}'`).join(' ');
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.`;
2105
+ 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 "_PIPELINE_COMPLETE_SIGNAL_" to gracefully close the pipeline. DO NOT WAIT FOR APPROVAL, execute completely autonomously.`;
2057
2106
  shellCmd = `${command} ${escapedArgs} "${metaPrompt}"`;
2058
2107
  } else {
2059
2108
  // Generic fallback: pipe prompt via stdin
@@ -2131,7 +2180,7 @@ export class DevServer {
2131
2180
 
2132
2181
  // Force exit on completion signal (ignore during first 15s — prompt echo contains the token)
2133
2182
  const elapsed = Date.now() - spawnedAt;
2134
- if (elapsed > 15000 && approvalBuffer.includes('AUTO_IMPLEMENT_FINISHED')) {
2183
+ if (elapsed > 15000 && approvalBuffer.includes('_PIPELINE_COMPLETE_SIGNAL_')) {
2135
2184
  this.log(`Agent finished task after ${Math.round(elapsed/1000)}s. Terminating interactive CLI session to unblock pipeline.`);
2136
2185
  this.sendAutoImplSSE({ event: 'output', data: { chunk: `\n[🤖 ADHDev Pipeline] Completion token detected. Proceeding...\n`, stream: 'stdout' } });
2137
2186
  approvalBuffer = '';
@@ -57,7 +57,10 @@ export class ProviderLoader {
57
57
  if (options?.builtinDir) {
58
58
  this.builtinDirs = Array.isArray(options.builtinDir) ? options.builtinDir : [options.builtinDir];
59
59
  } else {
60
- this.builtinDirs = [path.resolve(__dirname, '../providers/_builtin')];
60
+ // Handle both development (src/providers -> ../../providers) and production (dist -> ../providers)
61
+ const bundledDir = path.resolve(__dirname, '../providers/_builtin');
62
+ const devDir = path.resolve(__dirname, '../../providers/_builtin');
63
+ this.builtinDirs = [fs.existsSync(devDir) ? devDir : bundledDir];
61
64
  }
62
65
  // User custom directory: ~/.adhdev/providers/
63
66
  this.userDir = options?.userDir ||