@adhdev/daemon-core 0.8.29 → 0.8.31
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/agent-stream/manager.d.ts +1 -0
- package/dist/agent-stream/provider-adapter.d.ts +1 -0
- package/dist/agent-stream/types.d.ts +3 -0
- package/dist/boot/daemon-lifecycle.d.ts +2 -1
- package/dist/cdp/manager.d.ts +2 -0
- package/dist/cli-adapter-types.d.ts +34 -5
- package/dist/cli-adapters/provider-cli-adapter.d.ts +4 -158
- package/dist/cli-adapters/provider-cli-config.d.ts +30 -0
- package/dist/cli-adapters/provider-cli-parse.d.ts +42 -0
- package/dist/cli-adapters/provider-cli-runtime.d.ts +29 -0
- package/dist/cli-adapters/provider-cli-shared.d.ts +158 -0
- package/dist/commands/handler.d.ts +4 -3
- package/dist/config/config.d.ts +4 -3
- package/dist/index.js +1033 -621
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1035 -624
- package/dist/index.mjs.map +1 -1
- package/dist/providers/acp-provider-instance.d.ts +1 -0
- package/dist/providers/approval-utils.d.ts +7 -0
- package/dist/providers/cli-provider-instance.d.ts +2 -0
- package/dist/providers/contracts.d.ts +12 -1
- package/dist/providers/ide-provider-instance.d.ts +1 -0
- package/dist/providers/provider-loader.d.ts +3 -0
- package/dist/status/reporter.d.ts +2 -3
- package/dist/status/snapshot.d.ts +2 -1
- package/node_modules/@adhdev/session-host-core/package.json +1 -1
- package/package.json +3 -1
- package/src/agent-stream/manager.ts +8 -2
- package/src/agent-stream/poller.ts +57 -6
- package/src/agent-stream/provider-adapter.ts +11 -7
- package/src/agent-stream/types.ts +3 -0
- package/src/boot/daemon-lifecycle.ts +7 -6
- package/src/cdp/initializer.ts +2 -2
- package/src/cdp/manager.ts +5 -0
- package/src/cdp/setup.ts +1 -1
- package/src/cli-adapter-types.ts +37 -5
- package/src/cli-adapters/provider-cli-adapter.ts +212 -795
- package/src/cli-adapters/provider-cli-config.ts +66 -0
- package/src/cli-adapters/provider-cli-parse.ts +202 -0
- package/src/cli-adapters/provider-cli-runtime.ts +142 -0
- package/src/cli-adapters/provider-cli-shared.ts +439 -0
- package/src/cli-adapters/terminal-backends/ghostty-vt-backend.ts +1 -1
- package/src/commands/cdp-commands.ts +6 -1
- package/src/commands/chat-commands.ts +45 -29
- package/src/commands/cli-manager.ts +28 -9
- package/src/commands/handler.ts +14 -10
- package/src/commands/router.ts +23 -10
- package/src/commands/stream-commands.ts +11 -5
- package/src/config/config.ts +4 -10
- package/src/daemon/dev-auto-implement.ts +22 -18
- package/src/daemon/dev-cli-debug.ts +59 -16
- package/src/daemon/dev-server.ts +67 -43
- package/src/providers/acp-provider-instance.ts +18 -3
- package/src/providers/approval-utils.ts +66 -0
- package/src/providers/cli-provider-instance.ts +32 -6
- package/src/providers/contracts.d.ts +1 -0
- package/src/providers/contracts.ts +15 -2
- package/src/providers/extension-provider-instance.ts +1 -1
- package/src/providers/ide-provider-instance.ts +67 -41
- package/src/providers/provider-loader.ts +110 -55
- package/src/providers/version-archive.ts +23 -5
- package/src/status/reporter.ts +18 -14
- package/src/status/snapshot.ts +5 -4
package/src/daemon/dev-server.ts
CHANGED
|
@@ -20,7 +20,7 @@ import * as fs from 'fs';
|
|
|
20
20
|
import * as path from 'path';
|
|
21
21
|
import * as os from 'os';
|
|
22
22
|
import type { ProviderLoader } from '../providers/provider-loader.js';
|
|
23
|
-
import type { ProviderCategory } from '../providers/contracts.js';
|
|
23
|
+
import type { ProviderCategory, ProviderModule, ProviderScripts, ProviderSettingDef } from '../providers/contracts.js';
|
|
24
24
|
import type { ChildProcess } from 'child_process';
|
|
25
25
|
import type { DaemonCdpManager } from '../cdp/manager.js';
|
|
26
26
|
import type { ProviderInstanceManager } from '../providers/provider-instance-manager.js';
|
|
@@ -34,6 +34,64 @@ import { handleAutoImplement, handleAutoImplCancel, handleAutoImplSSE } from './
|
|
|
34
34
|
|
|
35
35
|
export const DEV_SERVER_PORT = 19280;
|
|
36
36
|
|
|
37
|
+
interface ProviderListEntry {
|
|
38
|
+
type: string;
|
|
39
|
+
name: string;
|
|
40
|
+
category: ProviderCategory;
|
|
41
|
+
icon: string | null;
|
|
42
|
+
displayName: string;
|
|
43
|
+
scripts?: string[];
|
|
44
|
+
inputMethod?: ProviderModule['inputMethod'] | null;
|
|
45
|
+
inputSelector?: string | null;
|
|
46
|
+
extensionId?: string | null;
|
|
47
|
+
cdpPorts?: [number, number] | [];
|
|
48
|
+
spawn?: ProviderModule['spawn'] | null;
|
|
49
|
+
auth?: ProviderModule['auth'] | null;
|
|
50
|
+
install?: string | null;
|
|
51
|
+
hasSettings?: boolean;
|
|
52
|
+
settingsCount?: number;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function getScriptNames(scripts?: ProviderScripts): string[] {
|
|
56
|
+
if (!scripts) return [];
|
|
57
|
+
return Object.entries(scripts)
|
|
58
|
+
.filter(([, value]) => typeof value === 'function')
|
|
59
|
+
.map(([name]) => name);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function toProviderListEntry(provider: ProviderModule): ProviderListEntry {
|
|
63
|
+
const base: ProviderListEntry = {
|
|
64
|
+
type: provider.type,
|
|
65
|
+
name: provider.name,
|
|
66
|
+
category: provider.category,
|
|
67
|
+
icon: provider.icon || null,
|
|
68
|
+
displayName: provider.displayName || provider.name,
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
if (provider.category === 'ide' || provider.category === 'extension') {
|
|
72
|
+
base.scripts = getScriptNames(provider.scripts);
|
|
73
|
+
base.inputMethod = provider.inputMethod || null;
|
|
74
|
+
base.inputSelector = provider.inputSelector || null;
|
|
75
|
+
base.extensionId = provider.extensionId || null;
|
|
76
|
+
base.cdpPorts = provider.cdpPorts || [];
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (provider.category === 'acp') {
|
|
80
|
+
base.spawn = provider.spawn || null;
|
|
81
|
+
base.auth = provider.auth || null;
|
|
82
|
+
base.install = provider.install || null;
|
|
83
|
+
base.hasSettings = !!provider.settings;
|
|
84
|
+
base.settingsCount = provider.settings ? Object.keys(provider.settings).length : 0;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (provider.category === 'cli') {
|
|
88
|
+
base.spawn = provider.spawn || null;
|
|
89
|
+
base.install = provider.install || null;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return base;
|
|
93
|
+
}
|
|
94
|
+
|
|
37
95
|
export class DevServer implements DevServerContext {
|
|
38
96
|
private server: http.Server | null = null;
|
|
39
97
|
public providerLoader: ProviderLoader;
|
|
@@ -212,41 +270,7 @@ export class DevServer implements DevServerContext {
|
|
|
212
270
|
// ─── Handlers ───
|
|
213
271
|
|
|
214
272
|
private async handleListProviders(_req: http.IncomingMessage, res: http.ServerResponse): Promise<void> {
|
|
215
|
-
const providers = this.providerLoader.getAll().map(
|
|
216
|
-
const base: any = {
|
|
217
|
-
type: p.type,
|
|
218
|
-
name: p.name,
|
|
219
|
-
category: p.category,
|
|
220
|
-
icon: (p as any).icon || null,
|
|
221
|
-
displayName: (p as any).displayName || p.name,
|
|
222
|
-
};
|
|
223
|
-
|
|
224
|
-
// IDE/Extension specific
|
|
225
|
-
if (p.category === 'ide' || p.category === 'extension') {
|
|
226
|
-
base.scripts = p.scripts ? Object.keys(p.scripts).filter(k => typeof (p.scripts as any)[k] === 'function') : [];
|
|
227
|
-
base.inputMethod = p.inputMethod || null;
|
|
228
|
-
base.inputSelector = (p as any).inputSelector || null;
|
|
229
|
-
base.extensionId = p.extensionId || null;
|
|
230
|
-
base.cdpPorts = (p as any).cdpPorts || [];
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
// ACP specific
|
|
234
|
-
if (p.category === 'acp') {
|
|
235
|
-
base.spawn = (p as any).spawn || null;
|
|
236
|
-
base.auth = (p as any).auth || null;
|
|
237
|
-
base.install = (p as any).install || null;
|
|
238
|
-
base.hasSettings = !!(p as any).settings;
|
|
239
|
-
base.settingsCount = (p as any).settings ? Object.keys((p as any).settings).length : 0;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
// CLI specific
|
|
243
|
-
if (p.category === 'cli') {
|
|
244
|
-
base.spawn = (p as any).spawn || null;
|
|
245
|
-
base.install = (p as any).install || null;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
return base;
|
|
249
|
-
});
|
|
273
|
+
const providers = this.providerLoader.getAll().map(toProviderListEntry);
|
|
250
274
|
this.json(res, 200, { providers, count: providers.length });
|
|
251
275
|
}
|
|
252
276
|
|
|
@@ -273,7 +297,7 @@ export class DevServer implements DevServerContext {
|
|
|
273
297
|
return;
|
|
274
298
|
}
|
|
275
299
|
|
|
276
|
-
const spawn =
|
|
300
|
+
const spawn = provider.spawn;
|
|
277
301
|
if (!spawn) {
|
|
278
302
|
this.json(res, 400, { error: `Provider ${type} has no spawn config` });
|
|
279
303
|
return;
|
|
@@ -330,7 +354,7 @@ export class DevServer implements DevServerContext {
|
|
|
330
354
|
return;
|
|
331
355
|
}
|
|
332
356
|
|
|
333
|
-
const fn =
|
|
357
|
+
const fn = provider.scripts?.[scriptName];
|
|
334
358
|
if (typeof fn !== 'function') {
|
|
335
359
|
this.json(res, 400, { error: `Script '${scriptName}' not found in provider '${type}'`, available: provider.scripts ? Object.keys(provider.scripts) : [] });
|
|
336
360
|
return;
|
|
@@ -446,7 +470,7 @@ export class DevServer implements DevServerContext {
|
|
|
446
470
|
}));
|
|
447
471
|
for (const cdp of this.cdpManagers.values()) {
|
|
448
472
|
if (!cdp.isConnected) {
|
|
449
|
-
(
|
|
473
|
+
cdp.clearTargetId();
|
|
450
474
|
}
|
|
451
475
|
}
|
|
452
476
|
this.json(res, 200, { reloaded: true, providers });
|
|
@@ -569,7 +593,7 @@ export class DevServer implements DevServerContext {
|
|
|
569
593
|
this.sendSSE({ type: 'watch_error', error: `Provider '${this.watchScriptPath}' not found` });
|
|
570
594
|
return;
|
|
571
595
|
}
|
|
572
|
-
const fn =
|
|
596
|
+
const fn = provider.scripts?.[this.watchScriptName!];
|
|
573
597
|
if (typeof fn !== 'function') {
|
|
574
598
|
this.sendSSE({ type: 'watch_error', error: `Script '${this.watchScriptName}' not found` });
|
|
575
599
|
return;
|
|
@@ -769,7 +793,7 @@ export class DevServer implements DevServerContext {
|
|
|
769
793
|
// Settings validation
|
|
770
794
|
if (config.settings) {
|
|
771
795
|
for (const [key, val] of Object.entries(config.settings)) {
|
|
772
|
-
const s = val as
|
|
796
|
+
const s = val as Partial<ProviderSettingDef>;
|
|
773
797
|
if (!s.type) errors.push(`settings.${key}: missing type`);
|
|
774
798
|
else if (!['boolean', 'number', 'string', 'select'].includes(s.type))
|
|
775
799
|
errors.push(`settings.${key}: invalid type '${s.type}'`);
|
|
@@ -784,7 +808,7 @@ export class DevServer implements DevServerContext {
|
|
|
784
808
|
if (config.cdpPorts && Array.isArray(config.cdpPorts)) {
|
|
785
809
|
const allProviders = this.providerLoader.getAll();
|
|
786
810
|
for (const port of config.cdpPorts) {
|
|
787
|
-
const conflict = allProviders.find(p => p.type !== type &&
|
|
811
|
+
const conflict = allProviders.find(p => p.type !== type && p.cdpPorts?.includes(port));
|
|
788
812
|
if (conflict) warnings.push(`CDP port ${port} conflicts with provider '${conflict.type}'`);
|
|
789
813
|
}
|
|
790
814
|
}
|
|
@@ -801,7 +825,7 @@ export class DevServer implements DevServerContext {
|
|
|
801
825
|
if (!message) { this.json(res, 400, { error: 'message required' }); return; }
|
|
802
826
|
const provider = this.providerLoader.getMeta(type);
|
|
803
827
|
if (!provider) { this.json(res, 404, { error: `Provider not found: ${type}` }); return; }
|
|
804
|
-
const spawn =
|
|
828
|
+
const spawn = provider.spawn;
|
|
805
829
|
if (!spawn) { this.json(res, 400, { error: `Provider ${type} has no spawn config` }); return; }
|
|
806
830
|
|
|
807
831
|
const { spawn: spawnFn } = await import('child_process');
|
|
@@ -232,7 +232,7 @@ export class AcpProviderInstance implements ProviderInstance {
|
|
|
232
232
|
...(this.currentModel ? { model: this.currentModel } : {}),
|
|
233
233
|
...(this.currentMode ? { mode: this.currentMode } : {}),
|
|
234
234
|
},
|
|
235
|
-
providerControls: this.provider.controls
|
|
235
|
+
providerControls: this.provider.controls,
|
|
236
236
|
};
|
|
237
237
|
}
|
|
238
238
|
|
|
@@ -600,8 +600,10 @@ export class AcpProviderInstance implements ProviderInstance {
|
|
|
600
600
|
}
|
|
601
601
|
|
|
602
602
|
// ─── Auto-approve: skip user confirmation ───
|
|
603
|
-
if (this.settings.autoApprove) {
|
|
604
|
-
|
|
603
|
+
if (this.settings.autoApprove !== false) {
|
|
604
|
+
const toolTitle = tc.title || tc.toolCallId || 'tool call';
|
|
605
|
+
this.log.info(`[${this.type}] Auto-approving: ${toolTitle}`);
|
|
606
|
+
this.appendSystemMessage(`Auto-approved: ${toolTitle}`);
|
|
605
607
|
const allowOption = params.options.find(o => o.kind === 'allow_once') || params.options.find(o => o.kind === 'allow_always');
|
|
606
608
|
if (allowOption) {
|
|
607
609
|
return { outcome: { outcome: 'selected', optionId: allowOption.optionId } };
|
|
@@ -1143,6 +1145,19 @@ export class AcpProviderInstance implements ProviderInstance {
|
|
|
1143
1145
|
if (this.events.length > 50) this.events = this.events.slice(-50);
|
|
1144
1146
|
}
|
|
1145
1147
|
|
|
1148
|
+
private appendSystemMessage(content: string, timestamp = Date.now()): void {
|
|
1149
|
+
const normalizedContent = String(content || '').trim();
|
|
1150
|
+
if (!normalizedContent) return;
|
|
1151
|
+
this.messages.push({
|
|
1152
|
+
role: 'system',
|
|
1153
|
+
content: normalizedContent,
|
|
1154
|
+
timestamp,
|
|
1155
|
+
});
|
|
1156
|
+
if (this.messages.length > 200) {
|
|
1157
|
+
this.messages = this.messages.slice(-100);
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1146
1161
|
private flushEvents(): ProviderEvent[] {
|
|
1147
1162
|
const events = [...this.events];
|
|
1148
1163
|
this.events = [];
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { ProviderModule } from './contracts.js';
|
|
2
|
+
|
|
3
|
+
const DEFAULT_APPROVAL_POSITIVE_HINTS = [
|
|
4
|
+
'run',
|
|
5
|
+
'approve',
|
|
6
|
+
'accept',
|
|
7
|
+
'allow once',
|
|
8
|
+
'always allow',
|
|
9
|
+
'allow',
|
|
10
|
+
'yes',
|
|
11
|
+
'proceed',
|
|
12
|
+
'continue',
|
|
13
|
+
'confirm',
|
|
14
|
+
'save',
|
|
15
|
+
'ok',
|
|
16
|
+
'trust',
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
function normalizeApprovalLabel(value: string): string {
|
|
20
|
+
return String(value || '')
|
|
21
|
+
.toLowerCase()
|
|
22
|
+
.replace(/[^\p{L}\p{N}]+/gu, ' ')
|
|
23
|
+
.trim();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function getApprovalPositiveHints(provider?: Pick<ProviderModule, 'approvalPositiveHints'> | null): string[] {
|
|
27
|
+
const customHints = Array.isArray(provider?.approvalPositiveHints)
|
|
28
|
+
? provider.approvalPositiveHints
|
|
29
|
+
.map((hint) => normalizeApprovalLabel(String(hint || '')))
|
|
30
|
+
.filter(Boolean)
|
|
31
|
+
: [];
|
|
32
|
+
return customHints.length > 0 ? customHints : DEFAULT_APPROVAL_POSITIVE_HINTS;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function pickApprovalButton(
|
|
36
|
+
buttons: string[] | null | undefined,
|
|
37
|
+
provider?: Pick<ProviderModule, 'approvalPositiveHints'> | null,
|
|
38
|
+
): { index: number; label: string } {
|
|
39
|
+
const labels = (buttons || []).map((button) => String(button || '').trim()).filter(Boolean);
|
|
40
|
+
if (labels.length === 0) {
|
|
41
|
+
return { index: 0, label: 'Approve' };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const normalizedButtons = labels.map((label) => normalizeApprovalLabel(label));
|
|
45
|
+
const hints = getApprovalPositiveHints(provider);
|
|
46
|
+
|
|
47
|
+
for (const hint of hints) {
|
|
48
|
+
const exactIndex = normalizedButtons.findIndex((label) => label === hint);
|
|
49
|
+
if (exactIndex >= 0) return { index: exactIndex, label: labels[exactIndex] };
|
|
50
|
+
|
|
51
|
+
const prefixIndex = normalizedButtons.findIndex((label) => label.startsWith(hint));
|
|
52
|
+
if (prefixIndex >= 0) return { index: prefixIndex, label: labels[prefixIndex] };
|
|
53
|
+
|
|
54
|
+
const includeIndex = normalizedButtons.findIndex((label) => label.includes(hint));
|
|
55
|
+
if (includeIndex >= 0) return { index: includeIndex, label: labels[includeIndex] };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return { index: 0, label: labels[0] };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function formatAutoApprovalMessage(modalMessage?: string, buttonLabel?: string): string {
|
|
62
|
+
const lines = [`Auto-approved${buttonLabel ? `: ${buttonLabel}` : ''}`];
|
|
63
|
+
const cleanMessage = String(modalMessage || '').trim();
|
|
64
|
+
if (cleanMessage) lines.push(cleanMessage);
|
|
65
|
+
return lines.join('\n');
|
|
66
|
+
}
|
|
@@ -20,6 +20,7 @@ import { ChatHistoryWriter, readChatHistory } from '../config/chat-history.js';
|
|
|
20
20
|
import { LOG } from '../logging/logger.js';
|
|
21
21
|
import type { ChatMessage } from '../types.js';
|
|
22
22
|
import { extractProviderControlValues, normalizeProviderEffects } from './control-effects.js';
|
|
23
|
+
import { formatAutoApprovalMessage, pickApprovalButton } from './approval-utils.js';
|
|
23
24
|
|
|
24
25
|
let CachedDatabaseSync: (new (path: string, options?: { readOnly?: boolean }) => {
|
|
25
26
|
prepare(sql: string): { get(...params: Array<string | number>): unknown };
|
|
@@ -100,7 +101,7 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
100
101
|
this.providerSessionId = options?.providerSessionId;
|
|
101
102
|
this.launchMode = options?.launchMode || 'new';
|
|
102
103
|
this.onProviderSessionResolved = options?.onProviderSessionResolved;
|
|
103
|
-
this.adapter = new ProviderCliAdapter(provider as
|
|
104
|
+
this.adapter = new ProviderCliAdapter(provider as CliProviderModule, workingDir, cliArgs, transportFactory);
|
|
104
105
|
this.monitor = new StatusMonitor();
|
|
105
106
|
this.historyWriter = new ChatHistoryWriter();
|
|
106
107
|
}
|
|
@@ -249,6 +250,8 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
249
250
|
getState(): ProviderState {
|
|
250
251
|
const adapterStatus = this.adapter.getStatus();
|
|
251
252
|
const parsedStatus = this.adapter.getScriptParsedStatus?.() || null;
|
|
253
|
+
const autoApproveActive = adapterStatus.status === 'waiting_approval' && this.shouldAutoApprove();
|
|
254
|
+
const visibleStatus = autoApproveActive ? 'generating' : adapterStatus.status;
|
|
252
255
|
const parsedProviderSessionId = typeof parsedStatus?.providerSessionId === 'string'
|
|
253
256
|
? parsedStatus.providerSessionId.trim()
|
|
254
257
|
: '';
|
|
@@ -297,14 +300,16 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
297
300
|
type: this.type,
|
|
298
301
|
name: this.provider.name,
|
|
299
302
|
category: 'cli',
|
|
300
|
-
status:
|
|
303
|
+
status: visibleStatus,
|
|
301
304
|
mode: this.presentationMode,
|
|
302
305
|
activeChat: {
|
|
303
306
|
id: `${this.type}_${this.workingDir}`,
|
|
304
307
|
title: parsedStatus?.title || dirName,
|
|
305
|
-
status: parsedStatus?.status
|
|
308
|
+
status: autoApproveActive && parsedStatus?.status === 'waiting_approval'
|
|
309
|
+
? 'generating'
|
|
310
|
+
: (parsedStatus?.status || visibleStatus),
|
|
306
311
|
messages: mergedMessages,
|
|
307
|
-
activeModal: parsedStatus?.activeModal ?? adapterStatus.activeModal,
|
|
312
|
+
activeModal: autoApproveActive ? null : (parsedStatus?.activeModal ?? adapterStatus.activeModal),
|
|
308
313
|
inputContent: '',
|
|
309
314
|
},
|
|
310
315
|
workspace: this.workingDir,
|
|
@@ -323,7 +328,7 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
323
328
|
} : undefined,
|
|
324
329
|
resume: this.provider.resume,
|
|
325
330
|
controlValues: this.controlValues,
|
|
326
|
-
providerControls: this.provider.controls
|
|
331
|
+
providerControls: this.provider.controls,
|
|
327
332
|
};
|
|
328
333
|
}
|
|
329
334
|
|
|
@@ -375,7 +380,16 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
375
380
|
const now = Date.now();
|
|
376
381
|
const adapterStatus = this.adapter.getStatus();
|
|
377
382
|
const parsedStatus = this.adapter.getScriptParsedStatus?.() || null;
|
|
378
|
-
const
|
|
383
|
+
const rawStatus = adapterStatus.status;
|
|
384
|
+
const autoApproveActive = rawStatus === 'waiting_approval' && this.shouldAutoApprove();
|
|
385
|
+
if (autoApproveActive) {
|
|
386
|
+
const { index: buttonIndex, label: buttonLabel } = pickApprovalButton(adapterStatus.activeModal?.buttons, this.provider);
|
|
387
|
+
this.recordAutoApproval(adapterStatus.activeModal?.message, buttonLabel, now);
|
|
388
|
+
setTimeout(() => {
|
|
389
|
+
this.adapter.resolveModal(buttonIndex);
|
|
390
|
+
}, 0);
|
|
391
|
+
}
|
|
392
|
+
const newStatus = autoApproveActive ? 'generating' : rawStatus;
|
|
379
393
|
const dirName = this.workingDir.split('/').filter(Boolean).pop() || 'session';
|
|
380
394
|
const chatTitle = `${this.provider.name} · ${dirName}`;
|
|
381
395
|
const partial = this.adapter.getPartialResponse();
|
|
@@ -603,6 +617,18 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
603
617
|
get cliType(): string { return this.type; }
|
|
604
618
|
get cliName(): string { return this.provider.name; }
|
|
605
619
|
|
|
620
|
+
private shouldAutoApprove(): boolean {
|
|
621
|
+
return this.settings.autoApprove !== false;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
private recordAutoApproval(modalMessage?: string, buttonLabel?: string, now = Date.now()): void {
|
|
625
|
+
this.appendRuntimeSystemMessage(
|
|
626
|
+
formatAutoApprovalMessage(modalMessage, buttonLabel),
|
|
627
|
+
`auto_approval:${now}:${buttonLabel || 'approve'}`,
|
|
628
|
+
now,
|
|
629
|
+
);
|
|
630
|
+
}
|
|
631
|
+
|
|
606
632
|
recordApprovalSelection(buttonText: string): void {
|
|
607
633
|
const cleanButton = String(buttonText || '').trim();
|
|
608
634
|
if (!cleanButton) return;
|
|
@@ -253,6 +253,7 @@ export interface ProviderModule {
|
|
|
253
253
|
};
|
|
254
254
|
cleanOutput?: (raw: string, lastUserInput?: string) => string;
|
|
255
255
|
resume?: ProviderResumeCapability;
|
|
256
|
+
approvalPositiveHints?: string[];
|
|
256
257
|
scripts?: ProviderScripts;
|
|
257
258
|
vscodeCommands?: {
|
|
258
259
|
focusPanel?: string;
|
|
@@ -304,6 +304,13 @@ export interface CdpTargetFilter {
|
|
|
304
304
|
titleExcludes?: string;
|
|
305
305
|
}
|
|
306
306
|
|
|
307
|
+
export type ProviderVersionCommand = string | Partial<Record<string, string>>;
|
|
308
|
+
|
|
309
|
+
export interface ProviderCompatibilityEntry {
|
|
310
|
+
ideVersion: string;
|
|
311
|
+
scriptDir: string;
|
|
312
|
+
}
|
|
313
|
+
|
|
307
314
|
export interface ProviderModule {
|
|
308
315
|
/** Unique identifier (e.g. 'cline', 'cursor', 'gemini-cli') */
|
|
309
316
|
type: string;
|
|
@@ -328,7 +335,7 @@ export interface ProviderModule {
|
|
|
328
335
|
/** Install instructions (shown when command is missing) */
|
|
329
336
|
install?: string;
|
|
330
337
|
/** Custom version detection command (e.g. 'cursor --version', 'claude -v') */
|
|
331
|
-
versionCommand?:
|
|
338
|
+
versionCommand?: ProviderVersionCommand;
|
|
332
339
|
/** Versions tested by provider maintainer (informational) */
|
|
333
340
|
testedVersions?: string[];
|
|
334
341
|
/** Per-OS process names — used by launch.ts to detect/kill IDE processes */
|
|
@@ -371,6 +378,9 @@ export interface ProviderModule {
|
|
|
371
378
|
// ─── Extension category only ───
|
|
372
379
|
extensionId?: string;
|
|
373
380
|
extensionIdPattern?: RegExp;
|
|
381
|
+
extensionIdPattern_flags?: string;
|
|
382
|
+
compatibility?: ProviderCompatibilityEntry[];
|
|
383
|
+
defaultScriptDir?: string;
|
|
374
384
|
|
|
375
385
|
// ─── CLI category only ───
|
|
376
386
|
binary?: string;
|
|
@@ -380,6 +390,7 @@ export interface ProviderModule {
|
|
|
380
390
|
shell?: boolean;
|
|
381
391
|
env?: Record<string, string>;
|
|
382
392
|
};
|
|
393
|
+
approvalKeys?: Record<number, string>;
|
|
383
394
|
patterns?: {
|
|
384
395
|
prompt?: RegExp[];
|
|
385
396
|
generating?: RegExp[];
|
|
@@ -388,8 +399,10 @@ export interface ProviderModule {
|
|
|
388
399
|
};
|
|
389
400
|
cleanOutput?: (raw: string, lastUserInput?: string) => string;
|
|
390
401
|
resume?: ProviderResumeCapability;
|
|
391
|
-
|
|
402
|
+
/** Session ID probe config — auto-discovers provider session ID from local SQLite DB */
|
|
392
403
|
sessionProbe?: ProviderSessionProbe;
|
|
404
|
+
/** Approval button priority hints used when auto-approve must pick a positive action */
|
|
405
|
+
approvalPositiveHints?: string[];
|
|
393
406
|
|
|
394
407
|
// ─── CDP scripts (ide/extension category) ───
|
|
395
408
|
scripts?: ProviderScripts;
|
|
@@ -92,7 +92,7 @@ export class ExtensionProviderInstance implements ProviderInstance {
|
|
|
92
92
|
currentModel: this.currentModel || undefined,
|
|
93
93
|
currentPlan: this.currentMode || undefined,
|
|
94
94
|
controlValues: this.controlValues,
|
|
95
|
-
providerControls: this.provider.controls
|
|
95
|
+
providerControls: this.provider.controls,
|
|
96
96
|
agentStreams: this.agentStreams,
|
|
97
97
|
instanceId: this.instanceId,
|
|
98
98
|
lastUpdated: Date.now(),
|