@adhdev/daemon-core 0.7.46 → 0.8.0
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/cli-adapters/provider-cli-adapter.d.ts +33 -0
- package/dist/cli-adapters/session-host-transport.d.ts +1 -0
- package/dist/config/chat-history.d.ts +3 -0
- package/dist/config/config.d.ts +1 -1
- package/dist/daemon/dev-auto-implement.d.ts +18 -2
- package/dist/daemon/dev-cli-debug.d.ts +82 -0
- package/dist/daemon/dev-server.d.ts +7 -0
- package/dist/index.js +1625 -191
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1625 -191
- package/dist/index.mjs.map +1 -1
- package/dist/providers/cli-provider-instance.d.ts +5 -0
- package/dist/providers/contracts.d.ts +8 -0
- package/node_modules/@adhdev/session-host-core/package.json +1 -1
- package/package.json +1 -1
- package/src/cli-adapters/provider-cli-adapter.ts +417 -6
- package/src/cli-adapters/session-host-transport.ts +13 -1
- package/src/commands/chat-commands.ts +8 -0
- package/src/config/chat-history.ts +5 -1
- package/src/config/config.ts +2 -2
- package/src/daemon/dev-auto-implement.ts +371 -38
- package/src/daemon/dev-cli-debug.ts +839 -0
- package/src/daemon/dev-server.ts +29 -1
- package/src/providers/cli-provider-instance.ts +79 -1
- package/src/providers/contracts.ts +8 -0
- package/src/providers/provider-loader.ts +39 -0
package/src/daemon/dev-server.ts
CHANGED
|
@@ -29,7 +29,7 @@ import { generateTemplate as genScaffoldTemplate, generateFiles as genScaffoldFi
|
|
|
29
29
|
import { VersionArchive, detectAllVersions } from '../providers/version-archive.js';
|
|
30
30
|
import { LOG } from '../logging/logger.js';
|
|
31
31
|
import { handleCdpEvaluate, handleCdpClick, handleCdpDomQuery, handleScreenshot, handleScriptsRun, handleTypeAndSend, handleTypeAndSendAt, handleScriptHints, handleCdpTargets, handleDomInspect, handleDomChildren, handleDomAnalyze, handleFindCommon, handleFindByText, handleDomContext } from './dev-cdp-handlers.js';
|
|
32
|
-
import { handleCliStatus, handleCliLaunch, handleCliSend, handleCliStop, handleCliDebug, handleCliResolve, handleCliRaw, handleCliSSE } from './dev-cli-debug.js';
|
|
32
|
+
import { handleCliStatus, handleCliLaunch, handleCliSend, handleCliStop, handleCliDebug, handleCliTrace, handleCliExercise, handleCliFixtureCapture, handleCliFixtureList, handleCliFixtureReplay, handleCliResolve, handleCliRaw, handleCliSSE } from './dev-cli-debug.js';
|
|
33
33
|
import { handleAutoImplement, handleAutoImplCancel, handleAutoImplSSE } from './dev-auto-implement.js';
|
|
34
34
|
|
|
35
35
|
export const DEV_SERVER_PORT = 19280;
|
|
@@ -102,11 +102,16 @@ export class DevServer implements DevServerContext {
|
|
|
102
102
|
{ method: 'GET', pattern: '/api/cli/status', handler: (q, s) => this.handleCliStatus(q, s) },
|
|
103
103
|
{ method: 'POST', pattern: '/api/cli/launch', handler: (q, s) => this.handleCliLaunch(q, s) },
|
|
104
104
|
{ method: 'POST', pattern: '/api/cli/send', handler: (q, s) => this.handleCliSend(q, s) },
|
|
105
|
+
{ method: 'POST', pattern: '/api/cli/exercise', handler: (q, s) => this.handleCliExercise(q, s) },
|
|
106
|
+
{ method: 'POST', pattern: '/api/cli/fixture/capture', handler: (q, s) => this.handleCliFixtureCapture(q, s) },
|
|
107
|
+
{ method: 'POST', pattern: '/api/cli/fixture/replay', handler: (q, s) => this.handleCliFixtureReplay(q, s) },
|
|
105
108
|
{ method: 'POST', pattern: '/api/cli/resolve', handler: (q, s) => this.handleCliResolve(q, s) },
|
|
106
109
|
{ method: 'POST', pattern: '/api/cli/raw', handler: (q, s) => this.handleCliRaw(q, s) },
|
|
107
110
|
{ method: 'POST', pattern: '/api/cli/stop', handler: (q, s) => this.handleCliStop(q, s) },
|
|
108
111
|
{ method: 'GET', pattern: '/api/cli/events', handler: (q, s) => this.handleCliSSE(q, s) },
|
|
109
112
|
{ method: 'GET', pattern: /^\/api\/cli\/debug\/([^/]+)$/, handler: (q, s, p) => this.handleCliDebug(p![0], q, s) },
|
|
113
|
+
{ method: 'GET', pattern: /^\/api\/cli\/trace\/([^/]+)$/, handler: (q, s, p) => this.handleCliTrace(p![0], q, s) },
|
|
114
|
+
{ method: 'GET', pattern: /^\/api\/cli\/fixtures\/([^/]+)$/, handler: (q, s, p) => this.handleCliFixtureList(p![0], q, s) },
|
|
110
115
|
// Dynamic routes (provider :type param)
|
|
111
116
|
{ method: 'POST', pattern: /^\/api\/providers\/([^/]+)\/script$/, handler: (q, s, p) => this.handleRunScript(p![0], q, s) },
|
|
112
117
|
{ method: 'GET', pattern: /^\/api\/providers\/([^/]+)\/files$/, handler: (q, s, p) => this.handleListFiles(p![0], q, s) },
|
|
@@ -1472,6 +1477,7 @@ export class DevServer implements DevServerContext {
|
|
|
1472
1477
|
lines.push('### 2. Inspect parsed + raw adapter state');
|
|
1473
1478
|
lines.push('```bash');
|
|
1474
1479
|
lines.push(`curl -sS http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/debug/${type}`);
|
|
1480
|
+
lines.push(`curl -sS http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/trace/${type}`);
|
|
1475
1481
|
lines.push(`curl -sS http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/status`);
|
|
1476
1482
|
lines.push('```');
|
|
1477
1483
|
lines.push('');
|
|
@@ -1618,6 +1624,19 @@ export class DevServer implements DevServerContext {
|
|
|
1618
1624
|
return handleCliSend(this, req, res);
|
|
1619
1625
|
}
|
|
1620
1626
|
|
|
1627
|
+
/** POST /api/cli/exercise — launch/send/approve/wait helper for provider-fix loops */
|
|
1628
|
+
private async handleCliExercise(req: http.IncomingMessage, res: http.ServerResponse): Promise<void> {
|
|
1629
|
+
return handleCliExercise(this, req, res);
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1632
|
+
private async handleCliFixtureCapture(req: http.IncomingMessage, res: http.ServerResponse): Promise<void> {
|
|
1633
|
+
return handleCliFixtureCapture(this, req, res);
|
|
1634
|
+
}
|
|
1635
|
+
|
|
1636
|
+
private async handleCliFixtureReplay(req: http.IncomingMessage, res: http.ServerResponse): Promise<void> {
|
|
1637
|
+
return handleCliFixtureReplay(this, req, res);
|
|
1638
|
+
}
|
|
1639
|
+
|
|
1621
1640
|
/** POST /api/cli/stop — stop a running CLI { type } */
|
|
1622
1641
|
private async handleCliStop(req: http.IncomingMessage, res: http.ServerResponse): Promise<void> {
|
|
1623
1642
|
return handleCliStop(this, req, res);
|
|
@@ -1640,6 +1659,15 @@ export class DevServer implements DevServerContext {
|
|
|
1640
1659
|
return handleCliDebug(this, type, _req, res);
|
|
1641
1660
|
}
|
|
1642
1661
|
|
|
1662
|
+
/** GET /api/cli/trace/:type — recent CLI trace timeline plus current debug snapshot */
|
|
1663
|
+
private async handleCliTrace(type: string, _req: http.IncomingMessage, res: http.ServerResponse): Promise<void> {
|
|
1664
|
+
return handleCliTrace(this, type, _req, res);
|
|
1665
|
+
}
|
|
1666
|
+
|
|
1667
|
+
private async handleCliFixtureList(type: string, _req: http.IncomingMessage, res: http.ServerResponse): Promise<void> {
|
|
1668
|
+
return handleCliFixtureList(this, type, _req, res);
|
|
1669
|
+
}
|
|
1670
|
+
|
|
1643
1671
|
/** POST /api/cli/resolve — resolve an approval modal { type, buttonIndex } */
|
|
1644
1672
|
private async handleCliResolve(req: http.IncomingMessage, res: http.ServerResponse): Promise<void> {
|
|
1645
1673
|
return handleCliResolve(this, req, res);
|
|
@@ -18,6 +18,7 @@ import type { PtyTransportFactory } from '../cli-adapters/pty-transport.js';
|
|
|
18
18
|
import { StatusMonitor } from './status-monitor.js';
|
|
19
19
|
import { ChatHistoryWriter } from '../config/chat-history.js';
|
|
20
20
|
import { LOG } from '../logging/logger.js';
|
|
21
|
+
import type { ChatMessage } from '../types.js';
|
|
21
22
|
|
|
22
23
|
let CachedDatabaseSync: (new (path: string, options?: { readOnly?: boolean }) => {
|
|
23
24
|
prepare(sql: string): { get(...params: Array<string | number>): unknown };
|
|
@@ -54,6 +55,7 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
54
55
|
private generatingDebouncePending: { chatTitle: string; timestamp: number } | null = null;
|
|
55
56
|
private lastApprovalEventAt = 0;
|
|
56
57
|
private historyWriter: ChatHistoryWriter;
|
|
58
|
+
private runtimeMessages: Array<{ key: string; message: ChatMessage }> = [];
|
|
57
59
|
readonly instanceId: string;
|
|
58
60
|
|
|
59
61
|
private presentationMode: 'terminal' | 'chat';
|
|
@@ -170,6 +172,7 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
170
172
|
}
|
|
171
173
|
const runtime = this.adapter.getRuntimeMetadata();
|
|
172
174
|
const parsedMessages = Array.isArray(parsedStatus?.messages) ? parsedStatus.messages : [];
|
|
175
|
+
const mergedMessages = this.mergeConversationMessages(parsedMessages);
|
|
173
176
|
|
|
174
177
|
const dirName = this.workingDir.split('/').filter(Boolean).pop() || 'session';
|
|
175
178
|
|
|
@@ -202,7 +205,7 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
202
205
|
id: `${this.type}_${this.workingDir}`,
|
|
203
206
|
title: parsedStatus?.title || dirName,
|
|
204
207
|
status: parsedStatus?.status || adapterStatus.status,
|
|
205
|
-
messages:
|
|
208
|
+
messages: mergedMessages,
|
|
206
209
|
activeModal: parsedStatus?.activeModal ?? adapterStatus.activeModal,
|
|
207
210
|
inputContent: '',
|
|
208
211
|
},
|
|
@@ -308,6 +311,11 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
308
311
|
const approvalCooldown = 5000;
|
|
309
312
|
if (this.lastStatus !== 'waiting_approval' && (!this.lastApprovalEventAt || now - this.lastApprovalEventAt > approvalCooldown)) {
|
|
310
313
|
this.lastApprovalEventAt = now;
|
|
314
|
+
this.appendRuntimeSystemMessage(
|
|
315
|
+
this.formatApprovalRequestMessage(modal?.message, modal?.buttons),
|
|
316
|
+
`approval_request:${now}`,
|
|
317
|
+
now,
|
|
318
|
+
);
|
|
311
319
|
this.pushEvent({
|
|
312
320
|
event: 'agent:waiting_approval', chatTitle, timestamp: now,
|
|
313
321
|
modalMessage: modal?.message,
|
|
@@ -376,12 +384,82 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
376
384
|
get cliType(): string { return this.type; }
|
|
377
385
|
get cliName(): string { return this.provider.name; }
|
|
378
386
|
|
|
387
|
+
recordApprovalSelection(buttonText: string): void {
|
|
388
|
+
const cleanButton = String(buttonText || '').trim();
|
|
389
|
+
if (!cleanButton) return;
|
|
390
|
+
const now = Date.now();
|
|
391
|
+
this.appendRuntimeSystemMessage(
|
|
392
|
+
`Approval selected: ${cleanButton}`,
|
|
393
|
+
`approval_selection:${now}:${cleanButton}`,
|
|
394
|
+
now,
|
|
395
|
+
);
|
|
396
|
+
}
|
|
397
|
+
|
|
379
398
|
private formatMarkerTimestamp(timestamp: number): string {
|
|
380
399
|
const date = new Date(timestamp);
|
|
381
400
|
const pad = (value: number) => String(value).padStart(2, '0');
|
|
382
401
|
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;
|
|
383
402
|
}
|
|
384
403
|
|
|
404
|
+
private appendRuntimeSystemMessage(content: string, dedupKey: string, receivedAt = Date.now()): void {
|
|
405
|
+
const normalizedContent = String(content || '').trim();
|
|
406
|
+
if (!normalizedContent) return;
|
|
407
|
+
if (this.runtimeMessages.some((entry) => entry.key === dedupKey)) return;
|
|
408
|
+
|
|
409
|
+
this.runtimeMessages.push({
|
|
410
|
+
key: dedupKey,
|
|
411
|
+
message: {
|
|
412
|
+
role: 'system',
|
|
413
|
+
senderName: 'System',
|
|
414
|
+
content: normalizedContent,
|
|
415
|
+
receivedAt,
|
|
416
|
+
timestamp: receivedAt,
|
|
417
|
+
},
|
|
418
|
+
});
|
|
419
|
+
if (this.runtimeMessages.length > 50) {
|
|
420
|
+
this.runtimeMessages = this.runtimeMessages.slice(-50);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
this.historyWriter.appendNewMessages(
|
|
424
|
+
this.type,
|
|
425
|
+
[{
|
|
426
|
+
role: 'system',
|
|
427
|
+
senderName: 'System',
|
|
428
|
+
content: normalizedContent,
|
|
429
|
+
receivedAt,
|
|
430
|
+
historyDedupKey: dedupKey,
|
|
431
|
+
}],
|
|
432
|
+
this.adapter.getScriptParsedStatus?.()?.title || this.workingDir.split('/').filter(Boolean).pop() || 'session',
|
|
433
|
+
this.instanceId,
|
|
434
|
+
this.providerSessionId,
|
|
435
|
+
);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
private mergeConversationMessages(parsedMessages: any[]): ChatMessage[] {
|
|
439
|
+
if (this.runtimeMessages.length === 0) return parsedMessages;
|
|
440
|
+
|
|
441
|
+
return [...parsedMessages, ...this.runtimeMessages.map((entry) => entry.message)]
|
|
442
|
+
.map((message, index) => ({ message, index }))
|
|
443
|
+
.sort((a, b) => {
|
|
444
|
+
const aTime = a.message.receivedAt || a.message.timestamp || 0;
|
|
445
|
+
const bTime = b.message.receivedAt || b.message.timestamp || 0;
|
|
446
|
+
if (aTime !== bTime) return aTime - bTime;
|
|
447
|
+
return a.index - b.index;
|
|
448
|
+
})
|
|
449
|
+
.map((entry) => entry.message);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
private formatApprovalRequestMessage(modalMessage?: string, buttons?: string[]): string {
|
|
453
|
+
const lines = ['Approval requested'];
|
|
454
|
+
const cleanMessage = String(modalMessage || '').trim();
|
|
455
|
+
if (cleanMessage) lines.push(cleanMessage);
|
|
456
|
+
const labels = (buttons || []).map((button) => String(button || '').trim()).filter(Boolean);
|
|
457
|
+
if (labels.length > 0) {
|
|
458
|
+
lines.push(labels.map((label) => `[${label}]`).join(' '));
|
|
459
|
+
}
|
|
460
|
+
return lines.join('\n');
|
|
461
|
+
}
|
|
462
|
+
|
|
385
463
|
private promoteProviderSessionId(sessionId: string): void {
|
|
386
464
|
const nextSessionId = String(sessionId || '').trim();
|
|
387
465
|
if (!nextSessionId || nextSessionId === this.providerSessionId) return;
|
|
@@ -496,6 +496,14 @@ export interface ResolvedProvider extends ProviderModule {
|
|
|
496
496
|
_resolvedVersion?: string;
|
|
497
497
|
/** Warning when detected version is not in compatibility matrix */
|
|
498
498
|
_versionWarning?: string;
|
|
499
|
+
/** On-disk provider directory selected by ProviderLoader */
|
|
500
|
+
_resolvedProviderDir?: string;
|
|
501
|
+
/** Script directory selected by compatibility/default resolution */
|
|
502
|
+
_resolvedScriptDir?: string;
|
|
503
|
+
/** scripts.js path or fallback script directory used to build runtime scripts */
|
|
504
|
+
_resolvedScriptsPath?: string;
|
|
505
|
+
/** Why this script selection was chosen */
|
|
506
|
+
_resolvedScriptsSource?: string;
|
|
499
507
|
}
|
|
500
508
|
|
|
501
509
|
// ─── Provider Settings ─────────────────────────────────
|
|
@@ -425,6 +425,7 @@ export class ProviderLoader {
|
|
|
425
425
|
resolve(type: string, context?: { os?: string; version?: string }): ResolvedProvider | undefined {
|
|
426
426
|
const base = this.providers.get(type);
|
|
427
427
|
if (!base) return undefined;
|
|
428
|
+
const providerDir = this.findProviderDirInternal(type) || undefined;
|
|
428
429
|
|
|
429
430
|
const currentOs = context?.os || process.platform;
|
|
430
431
|
const currentVersion = context?.version ??
|
|
@@ -441,6 +442,9 @@ export class ProviderLoader {
|
|
|
441
442
|
if (base.scripts) {
|
|
442
443
|
resolved.scripts = { ...base.scripts };
|
|
443
444
|
}
|
|
445
|
+
if (providerDir) {
|
|
446
|
+
resolved._resolvedProviderDir = providerDir;
|
|
447
|
+
}
|
|
444
448
|
|
|
445
449
|
// 1. Apply OS override
|
|
446
450
|
if (base.os?.[currentOs]) {
|
|
@@ -468,6 +472,14 @@ export class ProviderLoader {
|
|
|
468
472
|
if (loaded) {
|
|
469
473
|
resolved.scripts = loaded;
|
|
470
474
|
this.log(` [compatibility] ${type} v${currentVersion} → ${entry.scriptDir}`);
|
|
475
|
+
resolved._resolvedScriptDir = entry.scriptDir;
|
|
476
|
+
resolved._resolvedScriptsSource = `compatibility:${entry.ideVersion}`;
|
|
477
|
+
if (providerDir) {
|
|
478
|
+
const fullDir = path.join(providerDir, entry.scriptDir);
|
|
479
|
+
resolved._resolvedScriptsPath = fs.existsSync(path.join(fullDir, 'scripts.js'))
|
|
480
|
+
? path.join(fullDir, 'scripts.js')
|
|
481
|
+
: fullDir;
|
|
482
|
+
}
|
|
471
483
|
matched = true;
|
|
472
484
|
}
|
|
473
485
|
break; // first match wins
|
|
@@ -480,6 +492,14 @@ export class ProviderLoader {
|
|
|
480
492
|
if (loaded) {
|
|
481
493
|
resolved.scripts = loaded;
|
|
482
494
|
this.log(` [compatibility] ${type} v${currentVersion} → default: ${(base as any).defaultScriptDir}`);
|
|
495
|
+
resolved._resolvedScriptDir = (base as any).defaultScriptDir;
|
|
496
|
+
resolved._resolvedScriptsSource = 'defaultScriptDir:version_miss';
|
|
497
|
+
if (providerDir) {
|
|
498
|
+
const fullDir = path.join(providerDir, (base as any).defaultScriptDir);
|
|
499
|
+
resolved._resolvedScriptsPath = fs.existsSync(path.join(fullDir, 'scripts.js'))
|
|
500
|
+
? path.join(fullDir, 'scripts.js')
|
|
501
|
+
: fullDir;
|
|
502
|
+
}
|
|
483
503
|
}
|
|
484
504
|
resolved._versionWarning = `Version ${currentVersion} not in compatibility matrix. Using default scripts.`;
|
|
485
505
|
}
|
|
@@ -495,6 +515,14 @@ export class ProviderLoader {
|
|
|
495
515
|
if (loaded) {
|
|
496
516
|
resolved.scripts = loaded;
|
|
497
517
|
this.log(` [version override] ${type} ${range} → ${dirOverride}`);
|
|
518
|
+
resolved._resolvedScriptDir = dirOverride;
|
|
519
|
+
resolved._resolvedScriptsSource = `versions:${range}`;
|
|
520
|
+
if (providerDir) {
|
|
521
|
+
const fullDir = path.join(providerDir, dirOverride);
|
|
522
|
+
resolved._resolvedScriptsPath = fs.existsSync(path.join(fullDir, 'scripts.js'))
|
|
523
|
+
? path.join(fullDir, 'scripts.js')
|
|
524
|
+
: fullDir;
|
|
525
|
+
}
|
|
498
526
|
}
|
|
499
527
|
} else if (override.scripts) {
|
|
500
528
|
resolved.scripts = { ...resolved.scripts, ...override.scripts };
|
|
@@ -507,6 +535,14 @@ export class ProviderLoader {
|
|
|
507
535
|
if (loaded) {
|
|
508
536
|
resolved.scripts = loaded;
|
|
509
537
|
this.log(` [compatibility] ${type} no version detected → default: ${(base as any).defaultScriptDir}`);
|
|
538
|
+
resolved._resolvedScriptDir = (base as any).defaultScriptDir;
|
|
539
|
+
resolved._resolvedScriptsSource = 'defaultScriptDir:no_version';
|
|
540
|
+
if (providerDir) {
|
|
541
|
+
const fullDir = path.join(providerDir, (base as any).defaultScriptDir);
|
|
542
|
+
resolved._resolvedScriptsPath = fs.existsSync(path.join(fullDir, 'scripts.js'))
|
|
543
|
+
? path.join(fullDir, 'scripts.js')
|
|
544
|
+
: fullDir;
|
|
545
|
+
}
|
|
510
546
|
}
|
|
511
547
|
}
|
|
512
548
|
|
|
@@ -583,6 +619,9 @@ export class ProviderLoader {
|
|
|
583
619
|
});
|
|
584
620
|
|
|
585
621
|
const handleChange = (filePath: string) => {
|
|
622
|
+
if (/[\/\\]fixtures[\/\\]/.test(filePath)) {
|
|
623
|
+
return;
|
|
624
|
+
}
|
|
586
625
|
if (filePath.endsWith('.js') || filePath.endsWith('.json')) {
|
|
587
626
|
this.log(`File changed: ${path.basename(filePath)}, reloading...`);
|
|
588
627
|
this.reload();
|