@adhdev/daemon-core 0.7.5 → 0.7.7
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.mts +164 -38
- package/dist/index.d.ts +164 -38
- package/dist/index.js +4051 -2547
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3696 -2192
- package/dist/index.mjs.map +1 -1
- package/dist/{normalize-tKg8IiDk.d.mts → normalize-auJAPmKy.d.mts} +669 -629
- package/dist/{normalize-tKg8IiDk.d.ts → normalize-auJAPmKy.d.ts} +669 -629
- package/dist/status/normalize.d.mts +1 -1
- package/dist/status/normalize.d.ts +1 -1
- package/package.json +5 -1
- package/src/agent-stream/forward.ts +6 -0
- package/src/boot/daemon-lifecycle.ts +7 -4
- package/src/cli-adapter-types.ts +2 -0
- package/src/cli-adapters/provider-cli-adapter.ts +148 -11
- package/src/cli-adapters/pty-transport.ts +100 -0
- package/src/cli-adapters/session-host-transport.ts +392 -0
- package/src/cli-adapters/terminal-backends/ghostty-vt-backend.ts +126 -0
- package/src/cli-adapters/terminal-backends/types.ts +17 -0
- package/src/cli-adapters/terminal-backends/xterm-backend.ts +87 -0
- package/src/cli-adapters/terminal-screen.ts +40 -53
- package/src/commands/cli-manager.ts +184 -55
- package/src/config/config.d.ts +116 -0
- package/src/config/workspace-activity.d.ts +22 -0
- package/src/config/workspaces.d.ts +84 -0
- package/src/daemon/dev-auto-implement.ts +1087 -0
- package/src/daemon/dev-cdp-handlers.ts +1003 -0
- package/src/daemon/dev-cli-debug.ts +288 -0
- package/src/daemon/dev-server-types.ts +45 -0
- package/src/daemon/dev-server.ts +121 -1698
- package/src/index.ts +5 -1
- package/src/providers/cli-provider-instance.ts +13 -1
- package/src/providers/contracts.d.ts +408 -0
- package/src/providers/contracts.ts +9 -0
- package/src/providers/extension-provider-instance.ts +50 -10
- package/src/providers/provider-instance-manager.ts +48 -10
- package/src/providers/provider-instance.d.ts +142 -0
- package/src/providers/provider-instance.ts +23 -1
- package/src/shared-types.d.ts +157 -0
- package/src/shared-types.ts +14 -0
- package/src/status/builders.ts +6 -0
- package/src/status/normalize.d.ts +14 -0
- package/src/types.d.ts +127 -0
package/src/index.ts
CHANGED
|
@@ -110,7 +110,7 @@ export { ProviderInstanceManager } from './providers/provider-instance-manager.j
|
|
|
110
110
|
export { IdeProviderInstance } from './providers/ide-provider-instance.js';
|
|
111
111
|
export { CliProviderInstance } from './providers/cli-provider-instance.js';
|
|
112
112
|
export { AcpProviderInstance } from './providers/acp-provider-instance.js';
|
|
113
|
-
export type { ProviderModule, CdpTargetFilter } from './providers/contracts.js';
|
|
113
|
+
export type { ProviderModule, CdpTargetFilter, ProviderResumeCapability } from './providers/contracts.js';
|
|
114
114
|
export { VersionArchive, detectAllVersions } from './providers/version-archive.js';
|
|
115
115
|
export type { ProviderVersionInfo, VersionHistory } from './providers/version-archive.js';
|
|
116
116
|
|
|
@@ -120,6 +120,10 @@ export { DevServer } from './daemon/dev-server.js';
|
|
|
120
120
|
// ── CLI Adapters ──
|
|
121
121
|
export { ProviderCliAdapter } from './cli-adapters/provider-cli-adapter.js';
|
|
122
122
|
export type { CliAdapter } from './cli-adapter-types.js';
|
|
123
|
+
export { NodePtyTransportFactory } from './cli-adapters/pty-transport.js';
|
|
124
|
+
export type { PtyRuntimeTransport, PtyTransportFactory, PtySpawnOptions } from './cli-adapters/pty-transport.js';
|
|
125
|
+
export { SessionHostPtyTransportFactory } from './cli-adapters/session-host-transport.js';
|
|
126
|
+
export type { HostedCliRuntimeDescriptor, CliTransportFactoryParams } from './commands/cli-manager.js';
|
|
123
127
|
|
|
124
128
|
// ── Installer ──
|
|
125
129
|
export { getAIExtensions, installExtensions, launchIDE, isExtensionInstalled } from './installer.js';
|
|
@@ -11,6 +11,7 @@ import type { ProviderModule } from './contracts.js';
|
|
|
11
11
|
import type { ProviderInstance, ProviderState, ProviderEvent, InstanceContext } from './provider-instance.js';
|
|
12
12
|
import { ProviderCliAdapter } from '../cli-adapters/provider-cli-adapter.js';
|
|
13
13
|
import type { CliProviderModule } from '../cli-adapters/provider-cli-adapter.js';
|
|
14
|
+
import type { PtyTransportFactory } from '../cli-adapters/pty-transport.js';
|
|
14
15
|
import { StatusMonitor } from './status-monitor.js';
|
|
15
16
|
import { ChatHistoryWriter } from '../config/chat-history.js';
|
|
16
17
|
import { LOG } from '../logging/logger.js';
|
|
@@ -37,10 +38,11 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
37
38
|
private workingDir: string,
|
|
38
39
|
private cliArgs: string[] = [],
|
|
39
40
|
instanceId?: string,
|
|
41
|
+
transportFactory?: PtyTransportFactory,
|
|
40
42
|
) {
|
|
41
43
|
this.type = provider.type;
|
|
42
44
|
this.instanceId = instanceId || crypto.randomUUID();
|
|
43
|
-
this.adapter = new ProviderCliAdapter(provider as any as CliProviderModule, workingDir, cliArgs);
|
|
45
|
+
this.adapter = new ProviderCliAdapter(provider as any as CliProviderModule, workingDir, cliArgs, transportFactory);
|
|
44
46
|
this.monitor = new StatusMonitor();
|
|
45
47
|
this.historyWriter = new ChatHistoryWriter();
|
|
46
48
|
}
|
|
@@ -82,6 +84,7 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
82
84
|
|
|
83
85
|
getState(): ProviderState {
|
|
84
86
|
const adapterStatus = this.adapter.getStatus();
|
|
87
|
+
const runtime = this.adapter.getRuntimeMetadata();
|
|
85
88
|
|
|
86
89
|
const dirName = this.workingDir.split('/').filter(Boolean).pop() || 'session';
|
|
87
90
|
|
|
@@ -114,6 +117,15 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
114
117
|
lastUpdated: Date.now(),
|
|
115
118
|
settings: this.settings,
|
|
116
119
|
pendingEvents: this.flushEvents(),
|
|
120
|
+
runtime: runtime ? {
|
|
121
|
+
runtimeId: runtime.runtimeId,
|
|
122
|
+
runtimeKey: runtime.runtimeKey,
|
|
123
|
+
displayName: runtime.displayName,
|
|
124
|
+
workspaceLabel: runtime.workspaceLabel,
|
|
125
|
+
writeOwner: runtime.writeOwner || null,
|
|
126
|
+
attachedClients: runtime.attachedClients || [],
|
|
127
|
+
} : undefined,
|
|
128
|
+
resume: this.provider.resume,
|
|
117
129
|
};
|
|
118
130
|
}
|
|
119
131
|
|
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider Output Contracts — Output contracts all providers must conform to
|
|
3
|
+
*
|
|
4
|
+
* Design principles:
|
|
5
|
+
* - Only output format is standardized; implementation is free
|
|
6
|
+
* - Common across all categories (cli, ide, extension)
|
|
7
|
+
* - User custom providers use the same contracts
|
|
8
|
+
*/
|
|
9
|
+
export interface ReadChatResult {
|
|
10
|
+
messages: ChatMessage[];
|
|
11
|
+
status: AgentStatus;
|
|
12
|
+
activeModal?: ModalInfo | null;
|
|
13
|
+
/** IDE/Extension only: session info */
|
|
14
|
+
id?: string;
|
|
15
|
+
title?: string;
|
|
16
|
+
/** Extension only: additional metadata */
|
|
17
|
+
agentType?: string;
|
|
18
|
+
agentName?: string;
|
|
19
|
+
extensionId?: string;
|
|
20
|
+
/** Status metadata */
|
|
21
|
+
isVisible?: boolean;
|
|
22
|
+
isWelcomeScreen?: boolean;
|
|
23
|
+
inputContent?: string;
|
|
24
|
+
model?: string;
|
|
25
|
+
autoApprove?: string;
|
|
26
|
+
}
|
|
27
|
+
import type { ChatMessage } from '../types.js';
|
|
28
|
+
export type { ChatMessage };
|
|
29
|
+
export type AgentStatus = 'idle' | 'generating' | 'waiting_approval' | 'error' | 'panel_hidden' | 'streaming';
|
|
30
|
+
export interface ModalInfo {
|
|
31
|
+
message: string;
|
|
32
|
+
buttons: string[];
|
|
33
|
+
width?: number;
|
|
34
|
+
height?: number;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* ContentBlock — ACP ContentBlock union type
|
|
38
|
+
* Represents displayable content in messages, tool call results, etc.
|
|
39
|
+
*/
|
|
40
|
+
export type ContentBlock = TextBlock | ImageBlock | AudioBlock | ResourceLinkBlock | ResourceBlock;
|
|
41
|
+
/** Text content — ACP TextContent */
|
|
42
|
+
export interface TextBlock {
|
|
43
|
+
type: 'text';
|
|
44
|
+
text: string;
|
|
45
|
+
annotations?: ContentAnnotations;
|
|
46
|
+
}
|
|
47
|
+
/** Image content — ACP ImageContent */
|
|
48
|
+
export interface ImageBlock {
|
|
49
|
+
type: 'image';
|
|
50
|
+
data: string;
|
|
51
|
+
mimeType: string;
|
|
52
|
+
uri?: string;
|
|
53
|
+
annotations?: ContentAnnotations;
|
|
54
|
+
}
|
|
55
|
+
/** Audio content — ACP AudioContent */
|
|
56
|
+
export interface AudioBlock {
|
|
57
|
+
type: 'audio';
|
|
58
|
+
data: string;
|
|
59
|
+
mimeType: string;
|
|
60
|
+
annotations?: ContentAnnotations;
|
|
61
|
+
}
|
|
62
|
+
/** Resource link (file reference) — ACP ResourceLink */
|
|
63
|
+
export interface ResourceLinkBlock {
|
|
64
|
+
type: 'resource_link';
|
|
65
|
+
uri: string;
|
|
66
|
+
name: string;
|
|
67
|
+
title?: string;
|
|
68
|
+
description?: string;
|
|
69
|
+
mimeType?: string;
|
|
70
|
+
size?: number;
|
|
71
|
+
annotations?: ContentAnnotations;
|
|
72
|
+
}
|
|
73
|
+
/** Embedded resource (inline file) — ACP EmbeddedResource */
|
|
74
|
+
export interface ResourceBlock {
|
|
75
|
+
type: 'resource';
|
|
76
|
+
resource: TextResourceContents | BlobResourceContents;
|
|
77
|
+
annotations?: ContentAnnotations;
|
|
78
|
+
}
|
|
79
|
+
export interface TextResourceContents {
|
|
80
|
+
uri: string;
|
|
81
|
+
text: string;
|
|
82
|
+
mimeType?: string | null;
|
|
83
|
+
}
|
|
84
|
+
export interface BlobResourceContents {
|
|
85
|
+
uri: string;
|
|
86
|
+
blob: string;
|
|
87
|
+
mimeType?: string | null;
|
|
88
|
+
}
|
|
89
|
+
export interface ContentAnnotations {
|
|
90
|
+
audience?: ('user' | 'assistant')[];
|
|
91
|
+
priority?: number;
|
|
92
|
+
}
|
|
93
|
+
/** Tool call info — ACP ToolCall */
|
|
94
|
+
export interface ToolCallInfo {
|
|
95
|
+
toolCallId: string;
|
|
96
|
+
title: string;
|
|
97
|
+
kind?: ToolKind;
|
|
98
|
+
status?: ToolCallStatus;
|
|
99
|
+
rawInput?: unknown;
|
|
100
|
+
rawOutput?: unknown;
|
|
101
|
+
content?: ToolCallContent[];
|
|
102
|
+
locations?: ToolCallLocation[];
|
|
103
|
+
}
|
|
104
|
+
export type ToolKind = 'read' | 'edit' | 'delete' | 'move' | 'search' | 'execute' | 'think' | 'fetch' | 'switch_mode' | 'other';
|
|
105
|
+
export type ToolCallStatus = 'pending' | 'in_progress' | 'completed' | 'failed';
|
|
106
|
+
/** Content produced by a tool call — ACP ToolCallContent */
|
|
107
|
+
export type ToolCallContent = {
|
|
108
|
+
type: 'content';
|
|
109
|
+
content: ContentBlock;
|
|
110
|
+
} | {
|
|
111
|
+
type: 'diff';
|
|
112
|
+
path: string;
|
|
113
|
+
oldText?: string;
|
|
114
|
+
newText: string;
|
|
115
|
+
} | {
|
|
116
|
+
type: 'terminal';
|
|
117
|
+
terminalId: string;
|
|
118
|
+
};
|
|
119
|
+
export interface ToolCallLocation {
|
|
120
|
+
path: string;
|
|
121
|
+
line?: number | null;
|
|
122
|
+
}
|
|
123
|
+
/** Normalize content: string → ContentBlock[] */
|
|
124
|
+
export declare function normalizeContent(content: string | ContentBlock[]): ContentBlock[];
|
|
125
|
+
/** Flatten ContentBlock[] → string (backward compat / plain-text extraction) */
|
|
126
|
+
export declare function flattenContent(content: string | ContentBlock[]): string;
|
|
127
|
+
/** SendMessage params — supports rich content (ACP PromptRequest compatible) */
|
|
128
|
+
export interface SendMessageParams {
|
|
129
|
+
/** Shortcut: text-only message */
|
|
130
|
+
text?: string;
|
|
131
|
+
/** Rich content blocks (ACP ContentBlock[]) */
|
|
132
|
+
prompt?: ContentBlock[];
|
|
133
|
+
}
|
|
134
|
+
export interface SendMessageResult {
|
|
135
|
+
sent: boolean;
|
|
136
|
+
error?: string;
|
|
137
|
+
/** When CDP Input API is needed (Lexical editor etc) */
|
|
138
|
+
needsTypeAndSend?: boolean;
|
|
139
|
+
selector?: string;
|
|
140
|
+
}
|
|
141
|
+
export interface ListSessionsResult {
|
|
142
|
+
sessions: SessionInfo[];
|
|
143
|
+
}
|
|
144
|
+
export interface SessionInfo {
|
|
145
|
+
id: string;
|
|
146
|
+
title: string;
|
|
147
|
+
time?: string;
|
|
148
|
+
}
|
|
149
|
+
export interface SwitchSessionResult {
|
|
150
|
+
switched: boolean;
|
|
151
|
+
/** When CDP click coordinates are needed (Antigravity QuickInput etc) */
|
|
152
|
+
action?: 'click';
|
|
153
|
+
clickX?: number;
|
|
154
|
+
clickY?: number;
|
|
155
|
+
error?: string;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Method 1: Script-Click — script calls el.click() directly
|
|
159
|
+
* Cursor Suitable for IDEs using div.cursor-pointer elements.
|
|
160
|
+
*/
|
|
161
|
+
export interface ResolveActionScriptClick {
|
|
162
|
+
resolved: boolean;
|
|
163
|
+
clicked?: string;
|
|
164
|
+
available?: string[];
|
|
165
|
+
error?: string;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Method 2: Coordinate-Click — returns coordinates, daemon performs CDP mouse click
|
|
169
|
+
* Antigravity Suitable for IDEs where el.click() does not work.
|
|
170
|
+
*/
|
|
171
|
+
export interface ResolveActionCoordinateClick {
|
|
172
|
+
found: boolean;
|
|
173
|
+
text?: string;
|
|
174
|
+
x?: number;
|
|
175
|
+
y?: number;
|
|
176
|
+
w?: number;
|
|
177
|
+
h?: number;
|
|
178
|
+
}
|
|
179
|
+
export type ResolveActionResult = ResolveActionScriptClick | ResolveActionCoordinateClick;
|
|
180
|
+
export type ProviderCategory = 'cli' | 'ide' | 'extension' | 'acp';
|
|
181
|
+
/**
|
|
182
|
+
* Type of object exported by module.exports in provider.js.
|
|
183
|
+
*
|
|
184
|
+
* Each provider.js is fully independent and does not import other providers.
|
|
185
|
+
* Helpers (_helpers/) can be optionally used.
|
|
186
|
+
*/
|
|
187
|
+
/**
|
|
188
|
+
* Provider-configurable CDP target filter.
|
|
189
|
+
* Used by DaemonCdpManager to select the correct page/tab to connect to.
|
|
190
|
+
* Without this, the manager uses a hardcoded default filter.
|
|
191
|
+
*/
|
|
192
|
+
export interface CdpTargetFilter {
|
|
193
|
+
/** URL must include this string (e.g. 'workbench.html') */
|
|
194
|
+
urlIncludes?: string;
|
|
195
|
+
/** URL must NOT include any of these strings */
|
|
196
|
+
urlExcludes?: string[];
|
|
197
|
+
/** Page title regex pattern for titles to EXCLUDE (e.g. 'Debug Console|Output') */
|
|
198
|
+
titleExcludes?: string;
|
|
199
|
+
}
|
|
200
|
+
export interface ProviderModule {
|
|
201
|
+
/** Unique identifier (e.g. 'cline', 'cursor', 'gemini-cli') */
|
|
202
|
+
type: string;
|
|
203
|
+
/** Display name (e.g. 'Cline', 'Cursor') */
|
|
204
|
+
name: string;
|
|
205
|
+
/** Category: determines execution method */
|
|
206
|
+
category: ProviderCategory;
|
|
207
|
+
/** Alias list — allows users to invoke by alternate names (e.g. ['claude', 'claude-code']) */
|
|
208
|
+
aliases?: string[];
|
|
209
|
+
/** CDP ports [primary, secondary] (IDE category only) */
|
|
210
|
+
cdpPorts?: [number, number];
|
|
211
|
+
/** CDP target filter — controls which page/tab to connect to (IDE category only) */
|
|
212
|
+
targetFilter?: CdpTargetFilter;
|
|
213
|
+
/** CLI command (e.g. 'cursor', 'code') */
|
|
214
|
+
cli?: string;
|
|
215
|
+
/** Display icon */
|
|
216
|
+
icon?: string;
|
|
217
|
+
/** Display name (short name) */
|
|
218
|
+
displayName?: string;
|
|
219
|
+
/** Install instructions (shown when command is missing) */
|
|
220
|
+
install?: string;
|
|
221
|
+
/** Custom version detection command (e.g. 'cursor --version', 'claude -v') */
|
|
222
|
+
versionCommand?: string;
|
|
223
|
+
/** Versions tested by provider maintainer (informational) */
|
|
224
|
+
testedVersions?: string[];
|
|
225
|
+
/** Per-OS process names — used by launch.ts to detect/kill IDE processes */
|
|
226
|
+
processNames?: {
|
|
227
|
+
darwin?: string;
|
|
228
|
+
win32?: string[];
|
|
229
|
+
linux?: string[];
|
|
230
|
+
[key: string]: string | string[] | undefined;
|
|
231
|
+
};
|
|
232
|
+
/** Per-OS install paths — used by detector.ts to detect IDE installation */
|
|
233
|
+
paths?: {
|
|
234
|
+
darwin?: string[];
|
|
235
|
+
win32?: string[];
|
|
236
|
+
linux?: string[];
|
|
237
|
+
[key: string]: string[] | undefined;
|
|
238
|
+
};
|
|
239
|
+
extensionId?: string;
|
|
240
|
+
extensionIdPattern?: RegExp;
|
|
241
|
+
binary?: string;
|
|
242
|
+
spawn?: {
|
|
243
|
+
command: string;
|
|
244
|
+
args?: string[];
|
|
245
|
+
shell?: boolean;
|
|
246
|
+
env?: Record<string, string>;
|
|
247
|
+
};
|
|
248
|
+
patterns?: {
|
|
249
|
+
prompt?: RegExp[];
|
|
250
|
+
generating?: RegExp[];
|
|
251
|
+
approval?: RegExp[];
|
|
252
|
+
ready?: RegExp[];
|
|
253
|
+
};
|
|
254
|
+
cleanOutput?: (raw: string, lastUserInput?: string) => string;
|
|
255
|
+
resume?: ProviderResumeCapability;
|
|
256
|
+
scripts?: ProviderScripts;
|
|
257
|
+
vscodeCommands?: {
|
|
258
|
+
focusPanel?: string;
|
|
259
|
+
openPanel?: string;
|
|
260
|
+
[key: string]: string | undefined;
|
|
261
|
+
};
|
|
262
|
+
inputMethod?: 'cdp-type-and-send' | 'script';
|
|
263
|
+
inputSelector?: string;
|
|
264
|
+
/** webview iframe match text (must be contained in body) */
|
|
265
|
+
webviewMatchText?: string;
|
|
266
|
+
os?: {
|
|
267
|
+
[platform: string]: Partial<Pick<ProviderModule, 'scripts' | 'inputMethod' | 'inputSelector'>>;
|
|
268
|
+
};
|
|
269
|
+
/** Key: semver range string (e.g. '< 1.107.0', '>= 2.0.0') */
|
|
270
|
+
versions?: {
|
|
271
|
+
[versionRange: string]: Partial<Pick<ProviderModule, 'scripts'>> & {
|
|
272
|
+
/**
|
|
273
|
+
* Load scripts from a subdirectory instead of scripts.js root.
|
|
274
|
+
* Path is relative to the provider directory (e.g. 'scripts/legacy').
|
|
275
|
+
* The subdirectory should contain its own scripts.js or individual .js files.
|
|
276
|
+
*/
|
|
277
|
+
__dir?: string;
|
|
278
|
+
};
|
|
279
|
+
};
|
|
280
|
+
overrides?: Array<{
|
|
281
|
+
when: {
|
|
282
|
+
os?: string;
|
|
283
|
+
version?: string;
|
|
284
|
+
};
|
|
285
|
+
scripts?: Partial<ProviderScripts>;
|
|
286
|
+
/** Load scripts from a subdirectory for this OS+version combination */
|
|
287
|
+
__dir?: string;
|
|
288
|
+
}>;
|
|
289
|
+
settings?: Record<string, ProviderSettingDef>;
|
|
290
|
+
/** Static options used when agent does not provide configOptions */
|
|
291
|
+
staticConfigOptions?: Array<{
|
|
292
|
+
category: 'model' | 'mode' | 'thought_level' | 'other';
|
|
293
|
+
configId: string;
|
|
294
|
+
defaultValue?: string;
|
|
295
|
+
options: Array<{
|
|
296
|
+
value: string;
|
|
297
|
+
name: string;
|
|
298
|
+
description?: string;
|
|
299
|
+
group?: string;
|
|
300
|
+
}>;
|
|
301
|
+
}>;
|
|
302
|
+
/** Function to convert selected config values to spawn args (applied via process restart when config/* not supported) */
|
|
303
|
+
spawnArgBuilder?: (config: Record<string, string>) => string[];
|
|
304
|
+
/** ACP agent auth methods (multiple supported — in priority order) */
|
|
305
|
+
auth?: AcpAuthMethod[];
|
|
306
|
+
}
|
|
307
|
+
export interface ProviderResumeCapability {
|
|
308
|
+
supported: boolean;
|
|
309
|
+
stopStrategy?: 'command' | 'ctrl_c';
|
|
310
|
+
stopCommand?: string;
|
|
311
|
+
shutdownGraceMs?: number;
|
|
312
|
+
resumeArgs?: string[];
|
|
313
|
+
}
|
|
314
|
+
/** ACP auth method — based on ACP official spec */
|
|
315
|
+
export type AcpAuthMethod = AcpAuthEnvVar | AcpAuthAgent | AcpAuthTerminal;
|
|
316
|
+
/** Environment variable-based auth (API keys etc) */
|
|
317
|
+
export interface AcpAuthEnvVar {
|
|
318
|
+
type: 'env_var';
|
|
319
|
+
id: string;
|
|
320
|
+
name: string;
|
|
321
|
+
vars: Array<{
|
|
322
|
+
name: string;
|
|
323
|
+
label?: string;
|
|
324
|
+
secret?: boolean;
|
|
325
|
+
optional?: boolean;
|
|
326
|
+
}>;
|
|
327
|
+
link?: string;
|
|
328
|
+
}
|
|
329
|
+
/** Agent self-auth (OAuth, browser-based etc) */
|
|
330
|
+
export interface AcpAuthAgent {
|
|
331
|
+
type: 'agent';
|
|
332
|
+
id: string;
|
|
333
|
+
name: string;
|
|
334
|
+
description?: string;
|
|
335
|
+
}
|
|
336
|
+
/** Terminal command-based auth (runs setup command) */
|
|
337
|
+
export interface AcpAuthTerminal {
|
|
338
|
+
type: 'terminal';
|
|
339
|
+
id: string;
|
|
340
|
+
name: string;
|
|
341
|
+
description?: string;
|
|
342
|
+
args?: string[];
|
|
343
|
+
env?: Record<string, string>;
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* CDP script functions.
|
|
347
|
+
* Each function takes a params object and returns a JS code string for CDP evaluate.
|
|
348
|
+
* The JS execution result must conform to the Output Contract.
|
|
349
|
+
*
|
|
350
|
+
* Custom scripts can be added via index signature in addition to built-in scripts.
|
|
351
|
+
* All scripts can receive params: Record<string, any>,
|
|
352
|
+
* backward compatible with legacy single-argument style (e.g. sendMessage(text)).
|
|
353
|
+
*/
|
|
354
|
+
export interface ProviderScripts {
|
|
355
|
+
readChat?: (params?: Record<string, any>) => string;
|
|
356
|
+
sendMessage?: (params?: Record<string, any>) => string;
|
|
357
|
+
listSessions?: (params?: Record<string, any>) => string;
|
|
358
|
+
switchSession?: (params?: Record<string, any>) => string;
|
|
359
|
+
newSession?: (params?: Record<string, any>) => string;
|
|
360
|
+
focusEditor?: (params?: Record<string, any>) => string;
|
|
361
|
+
openPanel?: (params?: Record<string, any>) => string;
|
|
362
|
+
/** List available models → { models: string[], current: string } */
|
|
363
|
+
listModels?: (params?: Record<string, any>) => string;
|
|
364
|
+
/** Change model → { success: boolean } */
|
|
365
|
+
setModel?: (params?: Record<string, any>) => string;
|
|
366
|
+
/** List available modes → { modes: string[], current: string } */
|
|
367
|
+
listModes?: (params?: Record<string, any>) => string;
|
|
368
|
+
/** Change mode → { success: boolean } */
|
|
369
|
+
setMode?: (params?: Record<string, any>) => string;
|
|
370
|
+
/** params: { action: 'approve'|'reject'|'custom', button?: string } */
|
|
371
|
+
resolveAction?: (params?: Record<string, any>) => string;
|
|
372
|
+
webviewResolveAction?: (params?: Record<string, any>) => string;
|
|
373
|
+
listNotifications?: (params?: Record<string, any>) => string;
|
|
374
|
+
dismissNotification?: (params?: Record<string, any>) => string;
|
|
375
|
+
[scriptName: string]: ((params?: Record<string, any>) => string) | undefined;
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* ProviderLoader.resolve() result: Final provider with OS/version overrides applied
|
|
379
|
+
*/
|
|
380
|
+
export interface ResolvedProvider extends ProviderModule {
|
|
381
|
+
/** OS applied during resolve */
|
|
382
|
+
_resolvedOs?: string;
|
|
383
|
+
/** Version applied during resolve */
|
|
384
|
+
_resolvedVersion?: string;
|
|
385
|
+
/** Warning when detected version is not in compatibility matrix */
|
|
386
|
+
_versionWarning?: string;
|
|
387
|
+
}
|
|
388
|
+
/** Setting variable definition declared by provider */
|
|
389
|
+
export interface ProviderSettingDef {
|
|
390
|
+
type: 'boolean' | 'number' | 'string' | 'select';
|
|
391
|
+
default: any;
|
|
392
|
+
/** true = controllable from dashboard UI */
|
|
393
|
+
public: boolean;
|
|
394
|
+
/** UI label */
|
|
395
|
+
label?: string;
|
|
396
|
+
/** UI description */
|
|
397
|
+
description?: string;
|
|
398
|
+
/** Minimum value for number type */
|
|
399
|
+
min?: number;
|
|
400
|
+
/** Maximum value for number type */
|
|
401
|
+
max?: number;
|
|
402
|
+
/** Options for select type */
|
|
403
|
+
options?: string[];
|
|
404
|
+
}
|
|
405
|
+
/** Public settings schema (for dashboard transmission) */
|
|
406
|
+
export interface ProviderSettingSchema extends ProviderSettingDef {
|
|
407
|
+
key: string;
|
|
408
|
+
}
|
|
@@ -324,6 +324,7 @@ export interface ProviderModule {
|
|
|
324
324
|
ready?: RegExp[];
|
|
325
325
|
};
|
|
326
326
|
cleanOutput?: (raw: string, lastUserInput?: string) => string;
|
|
327
|
+
resume?: ProviderResumeCapability;
|
|
327
328
|
|
|
328
329
|
// ─── CDP scripts (ide/extension category) ───
|
|
329
330
|
scripts?: ProviderScripts;
|
|
@@ -388,6 +389,14 @@ export interface ProviderModule {
|
|
|
388
389
|
auth?: AcpAuthMethod[];
|
|
389
390
|
}
|
|
390
391
|
|
|
392
|
+
export interface ProviderResumeCapability {
|
|
393
|
+
supported: boolean;
|
|
394
|
+
stopStrategy?: 'command' | 'ctrl_c';
|
|
395
|
+
stopCommand?: string;
|
|
396
|
+
shutdownGraceMs?: number;
|
|
397
|
+
resumeArgs?: string[];
|
|
398
|
+
}
|
|
399
|
+
|
|
391
400
|
// ─── ACP Auth Types ─────────────────────────────────
|
|
392
401
|
|
|
393
402
|
/** ACP auth method — based on ACP official spec */
|
|
@@ -32,6 +32,10 @@ export class ExtensionProviderInstance implements ProviderInstance {
|
|
|
32
32
|
// meta
|
|
33
33
|
private instanceId: string;
|
|
34
34
|
private ideType: string = '';
|
|
35
|
+
private chatId: string | null = null;
|
|
36
|
+
private chatTitle: string | null = null;
|
|
37
|
+
private agentName: string = '';
|
|
38
|
+
private extensionId: string = '';
|
|
35
39
|
|
|
36
40
|
constructor(provider: ProviderModule) {
|
|
37
41
|
this.type = provider.type;
|
|
@@ -69,8 +73,8 @@ export class ExtensionProviderInstance implements ProviderInstance {
|
|
|
69
73
|
category: 'extension',
|
|
70
74
|
status: this.currentStatus as ProviderState['status'],
|
|
71
75
|
activeChat: this.messages.length > 0 ? {
|
|
72
|
-
id:
|
|
73
|
-
title: this.provider.name,
|
|
76
|
+
id: this.chatId || this.instanceId,
|
|
77
|
+
title: this.chatTitle || this.agentName || this.provider.name,
|
|
74
78
|
status: this.currentStatus,
|
|
75
79
|
messages: this.messages,
|
|
76
80
|
activeModal: this.activeModal,
|
|
@@ -94,6 +98,10 @@ export class ExtensionProviderInstance implements ProviderInstance {
|
|
|
94
98
|
if (data?.activeModal !== undefined) this.activeModal = data.activeModal;
|
|
95
99
|
if (data?.model) this.currentModel = data.model;
|
|
96
100
|
if (data?.mode) this.currentMode = data.mode;
|
|
101
|
+
if (typeof data?.sessionId === 'string' && data.sessionId.trim()) this.chatId = data.sessionId;
|
|
102
|
+
if (typeof data?.title === 'string' && data.title.trim()) this.chatTitle = data.title;
|
|
103
|
+
if (typeof data?.agentName === 'string' && data.agentName.trim()) this.agentName = data.agentName;
|
|
104
|
+
if (typeof data?.extensionId === 'string' && data.extensionId.trim()) this.extensionId = data.extensionId;
|
|
97
105
|
if (data?.status) {
|
|
98
106
|
const newStatus = data.status;
|
|
99
107
|
this.detectTransition(newStatus, data);
|
|
@@ -117,12 +125,6 @@ export class ExtensionProviderInstance implements ProviderInstance {
|
|
|
117
125
|
}
|
|
118
126
|
|
|
119
127
|
// ─── status transition detect ──────────────────────────────
|
|
120
|
-
// NOTE: Extension transitions are TRACKED but NOT emitted as events.
|
|
121
|
-
// The parent IdeProviderInstance already emits identical events
|
|
122
|
-
// (generating_started, generating_completed, waiting_approval)
|
|
123
|
-
// via its own detectAgentTransitions(). Emitting here would cause
|
|
124
|
-
// duplicate toasts with slightly different content.
|
|
125
|
-
|
|
126
128
|
private detectTransition(newStatus: string, data: any): void {
|
|
127
129
|
const now = Date.now();
|
|
128
130
|
const agentStatus = (newStatus === 'streaming' || newStatus === 'generating') ? 'generating'
|
|
@@ -136,13 +138,44 @@ export class ExtensionProviderInstance implements ProviderInstance {
|
|
|
136
138
|
: undefined;
|
|
137
139
|
|
|
138
140
|
if (agentStatus !== this.lastAgentStatus) {
|
|
139
|
-
// Track generating start time (for monitor elapsed calculation)
|
|
140
141
|
if (this.lastAgentStatus === 'idle' && agentStatus === 'generating') {
|
|
141
142
|
this.generatingStartedAt = now;
|
|
143
|
+
this.pushEvent({
|
|
144
|
+
event: 'agent:generating_started',
|
|
145
|
+
chatTitle: this.resolveChatTitle(data),
|
|
146
|
+
timestamp: now,
|
|
147
|
+
ideType: this.ideType || this.type,
|
|
148
|
+
agentType: this.type,
|
|
149
|
+
agentName: this.agentName || this.provider.name,
|
|
150
|
+
extensionId: this.extensionId || this.type,
|
|
151
|
+
});
|
|
152
|
+
} else if (agentStatus === 'waiting_approval') {
|
|
153
|
+
if (!this.generatingStartedAt) this.generatingStartedAt = now;
|
|
154
|
+
this.pushEvent({
|
|
155
|
+
event: 'agent:waiting_approval',
|
|
156
|
+
chatTitle: this.resolveChatTitle(data),
|
|
157
|
+
timestamp: now,
|
|
158
|
+
ideType: this.ideType || this.type,
|
|
159
|
+
agentType: this.type,
|
|
160
|
+
agentName: this.agentName || this.provider.name,
|
|
161
|
+
extensionId: this.extensionId || this.type,
|
|
162
|
+
modalMessage: data?.activeModal?.message,
|
|
163
|
+
modalButtons: data?.activeModal?.buttons,
|
|
164
|
+
});
|
|
142
165
|
} else if (agentStatus === 'idle' && (this.lastAgentStatus === 'generating' || this.lastAgentStatus === 'waiting_approval')) {
|
|
166
|
+
const duration = this.generatingStartedAt ? Math.round((now - this.generatingStartedAt) / 1000) : 0;
|
|
167
|
+
this.pushEvent({
|
|
168
|
+
event: 'agent:generating_completed',
|
|
169
|
+
chatTitle: this.resolveChatTitle(data),
|
|
170
|
+
duration,
|
|
171
|
+
timestamp: now,
|
|
172
|
+
ideType: this.ideType || this.type,
|
|
173
|
+
agentType: this.type,
|
|
174
|
+
agentName: this.agentName || this.provider.name,
|
|
175
|
+
extensionId: this.extensionId || this.type,
|
|
176
|
+
});
|
|
143
177
|
this.generatingStartedAt = 0;
|
|
144
178
|
}
|
|
145
|
-
// Do NOT pushEvent for transitions — parent IDE instance handles these
|
|
146
179
|
this.lastAgentStatus = agentStatus;
|
|
147
180
|
}
|
|
148
181
|
|
|
@@ -164,4 +197,11 @@ export class ExtensionProviderInstance implements ProviderInstance {
|
|
|
164
197
|
this.events = [];
|
|
165
198
|
return events;
|
|
166
199
|
}
|
|
200
|
+
|
|
201
|
+
private resolveChatTitle(data: any): string {
|
|
202
|
+
const title = typeof data?.title === 'string' && data.title.trim()
|
|
203
|
+
? data.title.trim()
|
|
204
|
+
: this.chatTitle;
|
|
205
|
+
return title || this.agentName || this.provider.name;
|
|
206
|
+
}
|
|
167
207
|
}
|
|
@@ -42,6 +42,27 @@ export class ProviderInstanceManager {
|
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
removeByCategory(
|
|
46
|
+
category: 'cli' | 'ide' | 'extension' | 'acp',
|
|
47
|
+
options: { dispose?: boolean } = {},
|
|
48
|
+
): number {
|
|
49
|
+
const dispose = options.dispose !== false;
|
|
50
|
+
let removed = 0;
|
|
51
|
+
for (const [id, instance] of this.instances) {
|
|
52
|
+
if (instance.category !== category) continue;
|
|
53
|
+
if (dispose) {
|
|
54
|
+
try {
|
|
55
|
+
instance.dispose();
|
|
56
|
+
} catch {
|
|
57
|
+
// noop
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
this.instances.delete(id);
|
|
61
|
+
removed += 1;
|
|
62
|
+
}
|
|
63
|
+
return removed;
|
|
64
|
+
}
|
|
65
|
+
|
|
45
66
|
/**
|
|
46
67
|
* Import by Instance ID
|
|
47
68
|
*/
|
|
@@ -75,16 +96,13 @@ export class ProviderInstanceManager {
|
|
|
75
96
|
try {
|
|
76
97
|
const state = instance.getState();
|
|
77
98
|
states.push(state);
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
instanceId: state.instanceId,
|
|
86
|
-
targetSessionId: state.instanceId,
|
|
87
|
-
providerCategory: state.category,
|
|
99
|
+
this.emitPendingEvents(instance.type, state);
|
|
100
|
+
if (state.category === 'ide') {
|
|
101
|
+
for (const childState of state.extensions) {
|
|
102
|
+
this.emitPendingEvents(childState.type, childState, {
|
|
103
|
+
targetSessionId: childState.instanceId,
|
|
104
|
+
workspaceName: state.workspace || undefined,
|
|
105
|
+
parentSessionId: state.instanceId,
|
|
88
106
|
});
|
|
89
107
|
}
|
|
90
108
|
}
|
|
@@ -141,6 +159,26 @@ export class ProviderInstanceManager {
|
|
|
141
159
|
this.eventListeners.push(listener);
|
|
142
160
|
}
|
|
143
161
|
|
|
162
|
+
private emitPendingEvents(
|
|
163
|
+
providerType: string,
|
|
164
|
+
state: ProviderState,
|
|
165
|
+
extra: Record<string, unknown> = {},
|
|
166
|
+
): void {
|
|
167
|
+
for (const event of state.pendingEvents) {
|
|
168
|
+
for (const listener of this.eventListeners) {
|
|
169
|
+
listener({
|
|
170
|
+
...event,
|
|
171
|
+
providerType,
|
|
172
|
+
instanceId: state.instanceId,
|
|
173
|
+
targetSessionId: state.instanceId,
|
|
174
|
+
providerCategory: state.category,
|
|
175
|
+
workspaceName: state.workspace || undefined,
|
|
176
|
+
...extra,
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
144
182
|
/**
|
|
145
183
|
* Forward event to specific Instance
|
|
146
184
|
*/
|