@adhdev/daemon-core 0.6.49 → 0.6.51
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 +9 -2
- package/dist/index.js +69 -14
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/providers/_builtin/cli/claude-cli/provider.json +6 -6
- package/providers/_builtin/cli/codex-cli/provider.json +4 -2
- package/providers/_builtin/cli/gemini-cli/provider.json +4 -2
- package/src/cli-adapters/provider-cli-adapter.ts +42 -14
- package/src/commands/cli-manager.ts +2 -2
- package/src/commands/router.ts +12 -0
- package/src/config/config.ts +27 -4
package/package.json
CHANGED
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
"type": "select",
|
|
14
14
|
"default": "terminal",
|
|
15
15
|
"public": true,
|
|
16
|
-
"label": "
|
|
17
|
-
"description": "terminal: PTY
|
|
16
|
+
"label": "Display Mode",
|
|
17
|
+
"description": "terminal: Native PTY view, chat: Parsed message view",
|
|
18
18
|
"options": [
|
|
19
19
|
"terminal",
|
|
20
20
|
"chat"
|
|
@@ -24,15 +24,15 @@
|
|
|
24
24
|
"type": "boolean",
|
|
25
25
|
"default": true,
|
|
26
26
|
"public": true,
|
|
27
|
-
"label": "
|
|
28
|
-
"description": "
|
|
27
|
+
"label": "Notifications",
|
|
28
|
+
"description": "Display notifications on state changes"
|
|
29
29
|
},
|
|
30
30
|
"autoApprove": {
|
|
31
31
|
"type": "boolean",
|
|
32
32
|
"default": false,
|
|
33
33
|
"public": true,
|
|
34
|
-
"label": "
|
|
35
|
-
"description": "
|
|
34
|
+
"label": "Auto Approve",
|
|
35
|
+
"description": "Automatically approve tool execution without prompt"
|
|
36
36
|
},
|
|
37
37
|
"approvalAlert": {
|
|
38
38
|
"type": "boolean",
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
"type": "select",
|
|
13
13
|
"default": "terminal",
|
|
14
14
|
"public": true,
|
|
15
|
-
"label": "
|
|
15
|
+
"label": "Display Mode",
|
|
16
|
+
"description": "terminal: Native PTY view, chat: Parsed message view",
|
|
16
17
|
"options": [
|
|
17
18
|
"terminal",
|
|
18
19
|
"chat"
|
|
@@ -22,7 +23,8 @@
|
|
|
22
23
|
"type": "boolean",
|
|
23
24
|
"default": true,
|
|
24
25
|
"public": true,
|
|
25
|
-
"label": "
|
|
26
|
+
"label": "Notifications",
|
|
27
|
+
"description": "Display notifications on state changes"
|
|
26
28
|
},
|
|
27
29
|
"autoApprove": {
|
|
28
30
|
"type": "boolean",
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
"type": "select",
|
|
13
13
|
"default": "terminal",
|
|
14
14
|
"public": true,
|
|
15
|
-
"label": "
|
|
15
|
+
"label": "Display Mode",
|
|
16
|
+
"description": "terminal: Native PTY view, chat: Parsed message view",
|
|
16
17
|
"options": [
|
|
17
18
|
"terminal",
|
|
18
19
|
"chat"
|
|
@@ -22,7 +23,8 @@
|
|
|
22
23
|
"type": "boolean",
|
|
23
24
|
"default": true,
|
|
24
25
|
"public": true,
|
|
25
|
-
"label": "
|
|
26
|
+
"label": "Notifications",
|
|
27
|
+
"description": "Display notifications on state changes"
|
|
26
28
|
},
|
|
27
29
|
"autoApprove": {
|
|
28
30
|
"type": "boolean",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* category: 'cli'
|
|
11
11
|
* binary: string — binary name
|
|
12
12
|
* spawn: { command, args, shell, env }
|
|
13
|
-
* patterns: { prompt, generating, approval, ready }
|
|
13
|
+
* patterns: { prompt, generating, approval, ready } — prompt helps end startup splash-gate early; sendMessage does not wait for it
|
|
14
14
|
* timeouts?: { idleFinish, generatingIdle, maxResponse, approvalCooldown, outputSettle, ... }
|
|
15
15
|
* cleanOutput(raw, lastUserInput): string
|
|
16
16
|
*/
|
|
@@ -253,6 +253,9 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
253
253
|
private idleTimeout: NodeJS.Timeout | null = null;
|
|
254
254
|
private ready = false;
|
|
255
255
|
private startupBuffer = '';
|
|
256
|
+
/** After spawn: briefly skip generating/settle so splash/redraw does not flip status; not used to gate sendMessage */
|
|
257
|
+
private startupParseGate = false;
|
|
258
|
+
private spawnAt = 0;
|
|
256
259
|
|
|
257
260
|
// PTY I/O
|
|
258
261
|
private onPtyDataCallback: ((data: string) => void) | null = null;
|
|
@@ -421,10 +424,16 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
421
424
|
this.ptyProcess = null;
|
|
422
425
|
this.setStatus('stopped', 'pty_exit');
|
|
423
426
|
this.ready = false;
|
|
427
|
+
this.startupParseGate = false;
|
|
428
|
+
this.spawnAt = 0;
|
|
424
429
|
this.onStatusChange?.();
|
|
425
430
|
});
|
|
426
431
|
|
|
427
|
-
this.
|
|
432
|
+
this.spawnAt = Date.now();
|
|
433
|
+
this.startupParseGate = true;
|
|
434
|
+
this.startupBuffer = '';
|
|
435
|
+
this.ready = true;
|
|
436
|
+
this.setStatus('idle', 'pty_ready');
|
|
428
437
|
this.onStatusChange?.();
|
|
429
438
|
}
|
|
430
439
|
|
|
@@ -449,12 +458,11 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
449
458
|
// Rolling buffer (recent 1000 chars)
|
|
450
459
|
this.recentOutputBuffer = (this.recentOutputBuffer + cleanData).slice(-1000);
|
|
451
460
|
|
|
452
|
-
// ───
|
|
453
|
-
if (
|
|
461
|
+
// ─── Startup window: first-run dialogs + avoid false generating during splash (sendMessage is not gated on prompt text)
|
|
462
|
+
if (this.startupParseGate) {
|
|
454
463
|
this.startupBuffer += cleanData;
|
|
455
464
|
LOG.info('CLI', `[${this.cliType}] startup chunk (${cleanData.length} chars): ${cleanData.slice(0, 200).replace(/\n/g, '\\n')}`);
|
|
456
465
|
|
|
457
|
-
// Startup dialog auto-proceed (Enter)
|
|
458
466
|
const dialogPatterns = [
|
|
459
467
|
/Do you want to connect/i,
|
|
460
468
|
/Do you trust the files/i,
|
|
@@ -468,14 +476,19 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
468
476
|
return;
|
|
469
477
|
}
|
|
470
478
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
479
|
+
const elapsed = Date.now() - this.spawnAt;
|
|
480
|
+
const bufCap = this.startupBuffer.length > 12000;
|
|
481
|
+
const promptMatched = patterns.prompt.some(p => p.test(this.startupBuffer));
|
|
482
|
+
if (promptMatched || elapsed > 8000 || bufCap) {
|
|
483
|
+
this.startupParseGate = false;
|
|
484
|
+
if (promptMatched) {
|
|
485
|
+
LOG.info('CLI', `[${this.cliType}] ✓ Startup gate end (prompt matched)`);
|
|
486
|
+
} else {
|
|
487
|
+
LOG.info('CLI', `[${this.cliType}] startup gate end (${elapsed}ms, cap=${bufCap}, prompt=${promptMatched})`);
|
|
488
|
+
}
|
|
489
|
+
} else {
|
|
490
|
+
return;
|
|
477
491
|
}
|
|
478
|
-
return;
|
|
479
492
|
}
|
|
480
493
|
|
|
481
494
|
if (cleanData.trim().length > 5) {
|
|
@@ -695,6 +708,8 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
695
708
|
this.ptyProcess = null;
|
|
696
709
|
this.setStatus('stopped', 'stop_cmd');
|
|
697
710
|
this.ready = false;
|
|
711
|
+
this.startupParseGate = false;
|
|
712
|
+
this.spawnAt = 0;
|
|
698
713
|
this.onStatusChange?.();
|
|
699
714
|
}, this.timeouts.shutdownGrace);
|
|
700
715
|
}
|
|
@@ -747,16 +762,29 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
747
762
|
* Used by DevServer /api/cli/debug endpoint.
|
|
748
763
|
*/
|
|
749
764
|
getDebugState(): Record<string, any> {
|
|
765
|
+
const sb = this.startupBuffer;
|
|
766
|
+
const testOnStartup = (p: RegExp): boolean => {
|
|
767
|
+
const flags = p.flags.includes('g') ? p.flags.replace(/g/g, '') : p.flags;
|
|
768
|
+
return new RegExp(p.source, flags).test(sb);
|
|
769
|
+
};
|
|
770
|
+
const promptDiagnostics = this.provider.patterns.prompt.map((p) => ({
|
|
771
|
+
pattern: p.toString(),
|
|
772
|
+
matchedAgainstStartupBuffer: testOnStartup(p),
|
|
773
|
+
}));
|
|
750
774
|
return {
|
|
751
775
|
type: this.cliType,
|
|
752
776
|
name: this.cliName,
|
|
753
777
|
status: this.currentStatus,
|
|
754
778
|
ready: this.ready,
|
|
779
|
+
startupParseGate: this.startupParseGate,
|
|
780
|
+
spawnAt: this.spawnAt,
|
|
755
781
|
workingDir: this.workingDir,
|
|
756
782
|
messages: this.messages.slice(-20),
|
|
757
783
|
messageCount: this.messages.length,
|
|
758
|
-
// Buffers
|
|
759
|
-
startupBuffer:
|
|
784
|
+
// Buffers (longer tails here than in periodic logs — for matching provider.json patterns)
|
|
785
|
+
startupBuffer: sb.slice(-4000),
|
|
786
|
+
startupBufferLength: sb.length,
|
|
787
|
+
promptDiagnostics,
|
|
760
788
|
recentOutputBuffer: this.recentOutputBuffer.slice(-500),
|
|
761
789
|
settledBuffer: this.settledBuffer.slice(-500),
|
|
762
790
|
responseBuffer: this.responseBuffer.slice(-500),
|
|
@@ -165,7 +165,7 @@ export class DaemonCliManager {
|
|
|
165
165
|
}
|
|
166
166
|
}
|
|
167
167
|
|
|
168
|
-
try { addCliHistory({ cliType: normalizedType, dir: resolvedDir, cliArgs }); } catch (e) { LOG.warn('CLI', `ACP history save failed: ${(e as Error)?.message}`); }
|
|
168
|
+
try { addCliHistory({ category: 'acp', cliType: normalizedType, dir: resolvedDir, workspace: resolvedDir, cliArgs, model: initialModel }); } catch (e) { LOG.warn('CLI', `ACP history save failed: ${(e as Error)?.message}`); }
|
|
169
169
|
this.deps.onStatusChange();
|
|
170
170
|
return;
|
|
171
171
|
}
|
|
@@ -261,7 +261,7 @@ export class DaemonCliManager {
|
|
|
261
261
|
console.log(chalk.green(` ✓ CLI started: ${cliInfo.displayName} v${cliInfo.version || 'unknown'} in ${resolvedDir}`));
|
|
262
262
|
}
|
|
263
263
|
|
|
264
|
-
try { addCliHistory({ cliType, dir: resolvedDir, cliArgs }); } catch (e) { LOG.warn('CLI', `CLI history save failed: ${(e as Error)?.message}`); }
|
|
264
|
+
try { addCliHistory({ category: 'cli', cliType, dir: resolvedDir, workspace: resolvedDir, cliArgs, model: initialModel }); } catch (e) { LOG.warn('CLI', `CLI history save failed: ${(e as Error)?.message}`); }
|
|
265
265
|
|
|
266
266
|
this.deps.onStatusChange();
|
|
267
267
|
}
|
package/src/commands/router.ts
CHANGED
|
@@ -20,6 +20,7 @@ import { launchWithCdp, killIdeProcess, isIdeRunning } from '../launch.js';
|
|
|
20
20
|
import { loadConfig, saveConfig, updateConfig } from '../config/config.js';
|
|
21
21
|
import { resolveIdeLaunchWorkspace } from '../config/workspaces.js';
|
|
22
22
|
import { appendWorkspaceActivity } from '../config/workspace-activity.js';
|
|
23
|
+
import { addCliHistory } from '../config/config.js';
|
|
23
24
|
import { detectIDEs } from '../detection/ide-detector.js';
|
|
24
25
|
import { LOG } from '../logging/logger.js';
|
|
25
26
|
import { logCommand } from '../logging/command-log.js';
|
|
@@ -207,6 +208,17 @@ export class DaemonCommandRouter {
|
|
|
207
208
|
};
|
|
208
209
|
LOG.info('LaunchIDE', `target=${ideKey || 'auto'}`);
|
|
209
210
|
const result = await launchWithCdp(launchArgs);
|
|
211
|
+
if (result.success && (result.ideId || ideKey)) {
|
|
212
|
+
try {
|
|
213
|
+
addCliHistory({
|
|
214
|
+
category: 'ide',
|
|
215
|
+
cliType: result.ideId || ideKey,
|
|
216
|
+
dir: resolvedWorkspace || '',
|
|
217
|
+
workspace: resolvedWorkspace || '',
|
|
218
|
+
newWindow: args?.newWindow === true,
|
|
219
|
+
});
|
|
220
|
+
} catch { /* ignore history failure */ }
|
|
221
|
+
}
|
|
210
222
|
|
|
211
223
|
if (result.success && result.port && result.ideId && !this.deps.cdpManagers.has(result.ideId)) {
|
|
212
224
|
const logFn = this.deps.getCdpLogFn
|
package/src/config/config.ts
CHANGED
|
@@ -87,9 +87,13 @@ export interface ADHDevConfig {
|
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
export interface CliHistoryEntry {
|
|
90
|
+
category?: 'ide' | 'cli' | 'acp';
|
|
90
91
|
cliType: string;
|
|
91
92
|
dir: string;
|
|
92
93
|
cliArgs?: string[];
|
|
94
|
+
workspace?: string;
|
|
95
|
+
newWindow?: boolean;
|
|
96
|
+
model?: string;
|
|
93
97
|
timestamp: number;
|
|
94
98
|
label?: string;
|
|
95
99
|
}
|
|
@@ -255,24 +259,43 @@ export function generateConnectionToken(): string {
|
|
|
255
259
|
return token;
|
|
256
260
|
}
|
|
257
261
|
/**
|
|
258
|
-
* Add
|
|
262
|
+
* Add launch to history (max 20, dedup by category+type+dir+args+workspace+model)
|
|
259
263
|
*/
|
|
260
264
|
export function addCliHistory(entry: Omit<CliHistoryEntry, 'timestamp'>): void {
|
|
261
265
|
const config = loadConfig();
|
|
262
266
|
const history = config.cliHistory || [];
|
|
263
267
|
const argsKey = (entry.cliArgs || []).join(' ');
|
|
268
|
+
const category = entry.category || 'cli';
|
|
269
|
+
const workspaceKey = entry.workspace || '';
|
|
270
|
+
const modelKey = entry.model || '';
|
|
264
271
|
|
|
265
|
-
// Remove duplicate (same
|
|
272
|
+
// Remove duplicate (same category + type + dir + args + workspace + model)
|
|
266
273
|
const filtered = history.filter(h => {
|
|
267
274
|
const hArgsKey = (h.cliArgs || []).join(' ');
|
|
268
|
-
return !(
|
|
275
|
+
return !(
|
|
276
|
+
(h.category || 'cli') === category &&
|
|
277
|
+
h.cliType === entry.cliType &&
|
|
278
|
+
h.dir === entry.dir &&
|
|
279
|
+
hArgsKey === argsKey &&
|
|
280
|
+
(h.workspace || '') === workspaceKey &&
|
|
281
|
+
(h.model || '') === modelKey
|
|
282
|
+
);
|
|
269
283
|
});
|
|
270
284
|
|
|
271
285
|
// Add to front
|
|
272
286
|
filtered.unshift({
|
|
273
287
|
...entry,
|
|
288
|
+
category,
|
|
274
289
|
timestamp: Date.now(),
|
|
275
|
-
label: entry.label ||
|
|
290
|
+
label: entry.label || (() => {
|
|
291
|
+
const base = `${entry.cliType} · ${entry.dir.split('/').filter(Boolean).pop() || 'root'}`;
|
|
292
|
+
const suffix: string[] = [];
|
|
293
|
+
if (entry.workspace && entry.workspace !== entry.dir) suffix.push(entry.workspace.split('/').filter(Boolean).pop() || entry.workspace);
|
|
294
|
+
if (entry.model) suffix.push(`model=${entry.model}`);
|
|
295
|
+
if (argsKey) suffix.push(argsKey);
|
|
296
|
+
if (entry.newWindow) suffix.push('new window');
|
|
297
|
+
return suffix.length > 0 ? `${base} (${suffix.join(' · ')})` : base;
|
|
298
|
+
})(),
|
|
276
299
|
});
|
|
277
300
|
|
|
278
301
|
// Keep max 20
|