@adhdev/daemon-core 0.8.58 → 0.8.59
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/types.d.ts +3 -4
- package/dist/commands/router.d.ts +1 -0
- package/dist/commands/stream-commands.d.ts +1 -0
- package/dist/config/recent-activity.d.ts +2 -1
- package/dist/config/saved-sessions.d.ts +2 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +560 -182
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +560 -182
- package/dist/index.mjs.map +1 -1
- package/dist/providers/acp-provider-instance.d.ts +8 -2
- package/dist/providers/cli-provider-instance.d.ts +1 -0
- package/dist/providers/contracts.d.ts +3 -2
- package/dist/providers/extension-provider-instance.d.ts +1 -2
- package/dist/providers/provider-instance.d.ts +3 -4
- package/dist/providers/provider-patch-state.d.ts +23 -0
- package/dist/providers/summary-metadata.d.ts +22 -0
- package/dist/shared-types.d.ts +15 -9
- package/dist/status/snapshot.d.ts +16 -1
- package/node_modules/@adhdev/session-host-core/package.json +1 -1
- package/package.json +1 -1
- package/src/agent-stream/forward.ts +1 -2
- package/src/agent-stream/manager.ts +2 -1
- package/src/agent-stream/provider-adapter.ts +7 -3
- package/src/agent-stream/types.d.ts +3 -4
- package/src/agent-stream/types.ts +3 -4
- package/src/commands/cli-manager.ts +10 -5
- package/src/commands/router.ts +155 -22
- package/src/commands/stream-commands.ts +19 -2
- package/src/config/recent-activity.d.ts +2 -1
- package/src/config/recent-activity.ts +12 -1
- package/src/config/saved-sessions.d.ts +2 -1
- package/src/config/saved-sessions.ts +12 -2
- package/src/daemon/dev-auto-implement.ts +1 -1
- package/src/daemon/dev-cli-debug.ts +0 -1
- package/src/daemon/dev-server.ts +1 -1
- package/src/daemon/scaffold-template.ts +8 -1
- package/src/index.d.ts +1 -1
- package/src/index.ts +2 -0
- package/src/providers/acp-provider-instance.d.ts +8 -2
- package/src/providers/acp-provider-instance.ts +80 -23
- package/src/providers/cli-provider-instance.ts +17 -22
- package/src/providers/contracts.d.ts +3 -2
- package/src/providers/contracts.ts +6 -4
- package/src/providers/control-effects.ts +3 -4
- package/src/providers/extension-provider-instance.d.ts +1 -2
- package/src/providers/extension-provider-instance.ts +26 -14
- package/src/providers/ide-provider-instance.ts +28 -15
- package/src/providers/provider-instance.d.ts +3 -4
- package/src/providers/provider-instance.ts +6 -7
- package/src/providers/provider-patch-state.ts +91 -0
- package/src/providers/summary-metadata.ts +118 -0
- package/src/shared-types.d.ts +15 -9
- package/src/shared-types.ts +17 -9
- package/src/status/builders.ts +18 -13
- package/src/status/reporter.ts +2 -4
- package/src/status/snapshot.ts +60 -2
package/src/commands/router.ts
CHANGED
|
@@ -31,6 +31,7 @@ import { logCommand } from '../logging/command-log.js';
|
|
|
31
31
|
import type { CommandLogEntry } from '../logging/command-log.js';
|
|
32
32
|
import { getRecentLogs, LOG_PATH } from '../logging/logger.js';
|
|
33
33
|
import { createInteractionId, getRecentDebugTrace, recordDebugTrace } from '../logging/debug-trace.js';
|
|
34
|
+
import { getSessionHostSurfaceKind, partitionSessionHostRecords } from '../session-host/runtime-surface.js';
|
|
34
35
|
import { buildSessionEntries } from '../status/builders.js';
|
|
35
36
|
import { buildMachineInfo, buildStatusSnapshot } from '../status/snapshot.js';
|
|
36
37
|
import { getSessionCompletionMarker } from '../status/snapshot.js';
|
|
@@ -137,6 +138,58 @@ function toHostedCliRuntimeDescriptor(record: any): HostedCliRuntimeDescriptor |
|
|
|
137
138
|
};
|
|
138
139
|
}
|
|
139
140
|
|
|
141
|
+
function getWriteConflictOwnerClientId(error: unknown): string | undefined {
|
|
142
|
+
const message = typeof error === 'string'
|
|
143
|
+
? error
|
|
144
|
+
: error instanceof Error
|
|
145
|
+
? error.message
|
|
146
|
+
: '';
|
|
147
|
+
const match = /^Write owned by\s+(.+)$/.exec(message.trim());
|
|
148
|
+
return match?.[1]?.trim() || undefined;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function summarizeSessionHostRecord(result: unknown): Record<string, unknown> {
|
|
152
|
+
if (!result || typeof result !== 'object') return {};
|
|
153
|
+
const record = result as Record<string, any>;
|
|
154
|
+
return {
|
|
155
|
+
runtimeKey: typeof record.runtimeKey === 'string' ? record.runtimeKey : undefined,
|
|
156
|
+
lifecycle: typeof record.lifecycle === 'string' ? record.lifecycle : undefined,
|
|
157
|
+
surfaceKind: getSessionHostSurfaceKind(record as any),
|
|
158
|
+
attachedClientCount: Array.isArray(record.attachedClients) ? record.attachedClients.length : undefined,
|
|
159
|
+
hasWriteOwner: !!record.writeOwner,
|
|
160
|
+
writeOwnerClientId: typeof record.writeOwner?.clientId === 'string' ? record.writeOwner.clientId : undefined,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function summarizeSessionHostRecords(result: unknown): Record<string, unknown> {
|
|
165
|
+
const records = Array.isArray(result) ? result : [];
|
|
166
|
+
const groups = partitionSessionHostRecords(records as any[]);
|
|
167
|
+
return {
|
|
168
|
+
sessionCount: records.length,
|
|
169
|
+
liveRuntimeCount: groups.liveRuntimes.length,
|
|
170
|
+
recoverySnapshotCount: groups.recoverySnapshots.length,
|
|
171
|
+
inactiveRecordCount: groups.inactiveRecords.length,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function summarizeSessionHostDiagnostics(result: unknown): Record<string, unknown> {
|
|
176
|
+
const diagnostics = result && typeof result === 'object' ? result as Record<string, any> : {};
|
|
177
|
+
const sessions = Array.isArray(diagnostics.sessions) ? diagnostics.sessions : [];
|
|
178
|
+
return {
|
|
179
|
+
runtimeCount: typeof diagnostics.runtimeCount === 'number' ? diagnostics.runtimeCount : undefined,
|
|
180
|
+
...summarizeSessionHostRecords(sessions),
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function summarizeSessionHostPruneResult(result: unknown): Record<string, unknown> {
|
|
185
|
+
const value = result && typeof result === 'object' ? result as Record<string, any> : {};
|
|
186
|
+
return {
|
|
187
|
+
duplicateGroupCount: typeof value.duplicateGroupCount === 'number' ? value.duplicateGroupCount : undefined,
|
|
188
|
+
prunedCount: Array.isArray(value.prunedSessionIds) ? value.prunedSessionIds.length : undefined,
|
|
189
|
+
keptCount: Array.isArray(value.keptSessionIds) ? value.keptSessionIds.length : undefined,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
140
193
|
export class DaemonCommandRouter {
|
|
141
194
|
private deps: CommandRouterDeps;
|
|
142
195
|
|
|
@@ -144,6 +197,64 @@ export class DaemonCommandRouter {
|
|
|
144
197
|
this.deps = deps;
|
|
145
198
|
}
|
|
146
199
|
|
|
200
|
+
private async traceSessionHostAction<T>(
|
|
201
|
+
action: string,
|
|
202
|
+
args: any,
|
|
203
|
+
run: () => Promise<T>,
|
|
204
|
+
summarizeResult?: (result: T) => Record<string, unknown>,
|
|
205
|
+
): Promise<T> {
|
|
206
|
+
const interactionId = typeof args?._interactionId === 'string' ? args._interactionId : undefined;
|
|
207
|
+
const sessionId = typeof args?.sessionId === 'string' ? args.sessionId : undefined;
|
|
208
|
+
const requestedPayload: Record<string, unknown> = { action };
|
|
209
|
+
if (sessionId) requestedPayload.sessionId = sessionId;
|
|
210
|
+
if (typeof args?.clientId === 'string') requestedPayload.clientId = args.clientId;
|
|
211
|
+
if (typeof args?.signal === 'string') requestedPayload.signal = args.signal;
|
|
212
|
+
if (typeof args?.providerType === 'string') requestedPayload.providerType = args.providerType;
|
|
213
|
+
if (typeof args?.workspace === 'string') requestedPayload.workspace = args.workspace;
|
|
214
|
+
if (typeof args?.dryRun === 'boolean') requestedPayload.dryRun = args.dryRun;
|
|
215
|
+
|
|
216
|
+
recordDebugTrace({
|
|
217
|
+
interactionId,
|
|
218
|
+
category: 'session_host',
|
|
219
|
+
stage: 'action_requested',
|
|
220
|
+
level: 'info',
|
|
221
|
+
sessionId,
|
|
222
|
+
payload: requestedPayload,
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
try {
|
|
226
|
+
const result = await run();
|
|
227
|
+
recordDebugTrace({
|
|
228
|
+
interactionId,
|
|
229
|
+
category: 'session_host',
|
|
230
|
+
stage: 'action_result',
|
|
231
|
+
level: 'info',
|
|
232
|
+
sessionId,
|
|
233
|
+
payload: {
|
|
234
|
+
...requestedPayload,
|
|
235
|
+
success: true,
|
|
236
|
+
...(summarizeResult ? summarizeResult(result) : {}),
|
|
237
|
+
},
|
|
238
|
+
});
|
|
239
|
+
return result;
|
|
240
|
+
} catch (error: any) {
|
|
241
|
+
recordDebugTrace({
|
|
242
|
+
interactionId,
|
|
243
|
+
category: 'session_host',
|
|
244
|
+
stage: 'action_failed',
|
|
245
|
+
level: 'error',
|
|
246
|
+
sessionId,
|
|
247
|
+
payload: {
|
|
248
|
+
...requestedPayload,
|
|
249
|
+
error: error?.message || String(error),
|
|
250
|
+
failureKind: getWriteConflictOwnerClientId(error) ? 'write_conflict' : 'request_failed',
|
|
251
|
+
conflictOwnerClientId: getWriteConflictOwnerClientId(error),
|
|
252
|
+
},
|
|
253
|
+
});
|
|
254
|
+
throw error;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
147
258
|
/**
|
|
148
259
|
* Unified command routing.
|
|
149
260
|
* Returns result for all commands:
|
|
@@ -270,16 +381,20 @@ export class DaemonCommandRouter {
|
|
|
270
381
|
|
|
271
382
|
case 'session_host_get_diagnostics': {
|
|
272
383
|
if (!this.deps.sessionHostControl) return { success: false, error: 'Session host control unavailable' };
|
|
273
|
-
const diagnostics = await this.deps.sessionHostControl
|
|
384
|
+
const diagnostics = await this.traceSessionHostAction('session_host_get_diagnostics', args, () => this.deps.sessionHostControl!.getDiagnostics({
|
|
274
385
|
includeSessions: args?.includeSessions !== false,
|
|
275
386
|
limit: Number(args?.limit) || undefined,
|
|
276
|
-
})
|
|
387
|
+
}), (result) => ({
|
|
388
|
+
includeSessions: args?.includeSessions !== false,
|
|
389
|
+
limit: Number(args?.limit) || undefined,
|
|
390
|
+
...summarizeSessionHostDiagnostics(result),
|
|
391
|
+
}));
|
|
277
392
|
return { success: true, diagnostics };
|
|
278
393
|
}
|
|
279
394
|
|
|
280
395
|
case 'session_host_list_sessions': {
|
|
281
396
|
if (!this.deps.sessionHostControl) return { success: false, error: 'Session host control unavailable' };
|
|
282
|
-
const sessions = await this.deps.sessionHostControl
|
|
397
|
+
const sessions = await this.traceSessionHostAction('session_host_list_sessions', args, () => this.deps.sessionHostControl!.listSessions(), (records) => summarizeSessionHostRecords(records));
|
|
283
398
|
return { success: true, sessions };
|
|
284
399
|
}
|
|
285
400
|
|
|
@@ -287,7 +402,7 @@ export class DaemonCommandRouter {
|
|
|
287
402
|
if (!this.deps.sessionHostControl) return { success: false, error: 'Session host control unavailable' };
|
|
288
403
|
const sessionId = typeof args?.sessionId === 'string' ? args.sessionId : '';
|
|
289
404
|
if (!sessionId) return { success: false, error: 'sessionId required' };
|
|
290
|
-
const record = await this.deps.sessionHostControl
|
|
405
|
+
const record = await this.traceSessionHostAction('session_host_stop_session', args, () => this.deps.sessionHostControl!.stopSession(sessionId), (result) => summarizeSessionHostRecord(result));
|
|
291
406
|
return { success: true, record };
|
|
292
407
|
}
|
|
293
408
|
|
|
@@ -295,11 +410,17 @@ export class DaemonCommandRouter {
|
|
|
295
410
|
if (!this.deps.sessionHostControl) return { success: false, error: 'Session host control unavailable' };
|
|
296
411
|
const sessionId = typeof args?.sessionId === 'string' ? args.sessionId : '';
|
|
297
412
|
if (!sessionId) return { success: false, error: 'sessionId required' };
|
|
298
|
-
const record = await this.
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
413
|
+
const record = await this.traceSessionHostAction('session_host_resume_session', args, async () => {
|
|
414
|
+
const nextRecord = await this.deps.sessionHostControl!.resumeSession(sessionId);
|
|
415
|
+
const hosted = toHostedCliRuntimeDescriptor(nextRecord);
|
|
416
|
+
if (hosted) {
|
|
417
|
+
await this.deps.cliManager.restoreHostedSessions([hosted]);
|
|
418
|
+
}
|
|
419
|
+
return nextRecord;
|
|
420
|
+
}, (result) => ({
|
|
421
|
+
...summarizeSessionHostRecord(result),
|
|
422
|
+
restoredHostedSession: !!toHostedCliRuntimeDescriptor(result),
|
|
423
|
+
}));
|
|
303
424
|
return { success: true, record };
|
|
304
425
|
}
|
|
305
426
|
|
|
@@ -307,11 +428,17 @@ export class DaemonCommandRouter {
|
|
|
307
428
|
if (!this.deps.sessionHostControl) return { success: false, error: 'Session host control unavailable' };
|
|
308
429
|
const sessionId = typeof args?.sessionId === 'string' ? args.sessionId : '';
|
|
309
430
|
if (!sessionId) return { success: false, error: 'sessionId required' };
|
|
310
|
-
const record = await this.
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
431
|
+
const record = await this.traceSessionHostAction('session_host_restart_session', args, async () => {
|
|
432
|
+
const nextRecord = await this.deps.sessionHostControl!.restartSession(sessionId);
|
|
433
|
+
const hosted = toHostedCliRuntimeDescriptor(nextRecord);
|
|
434
|
+
if (hosted) {
|
|
435
|
+
await this.deps.cliManager.restoreHostedSessions([hosted]);
|
|
436
|
+
}
|
|
437
|
+
return nextRecord;
|
|
438
|
+
}, (result) => ({
|
|
439
|
+
...summarizeSessionHostRecord(result),
|
|
440
|
+
restoredHostedSession: !!toHostedCliRuntimeDescriptor(result),
|
|
441
|
+
}));
|
|
315
442
|
return { success: true, record };
|
|
316
443
|
}
|
|
317
444
|
|
|
@@ -321,7 +448,7 @@ export class DaemonCommandRouter {
|
|
|
321
448
|
const signal = typeof args?.signal === 'string' ? args.signal : '';
|
|
322
449
|
if (!sessionId) return { success: false, error: 'sessionId required' };
|
|
323
450
|
if (!signal) return { success: false, error: 'signal required' };
|
|
324
|
-
const record = await this.deps.sessionHostControl
|
|
451
|
+
const record = await this.traceSessionHostAction('session_host_send_signal', args, () => this.deps.sessionHostControl!.sendSignal(sessionId, signal), (result) => summarizeSessionHostRecord(result));
|
|
325
452
|
return { success: true, record };
|
|
326
453
|
}
|
|
327
454
|
|
|
@@ -331,17 +458,17 @@ export class DaemonCommandRouter {
|
|
|
331
458
|
const clientId = typeof args?.clientId === 'string' ? args.clientId : '';
|
|
332
459
|
if (!sessionId) return { success: false, error: 'sessionId required' };
|
|
333
460
|
if (!clientId) return { success: false, error: 'clientId required' };
|
|
334
|
-
const record = await this.deps.sessionHostControl
|
|
461
|
+
const record = await this.traceSessionHostAction('session_host_force_detach_client', args, () => this.deps.sessionHostControl!.forceDetachClient(sessionId, clientId), (result) => summarizeSessionHostRecord(result));
|
|
335
462
|
return { success: true, record };
|
|
336
463
|
}
|
|
337
464
|
|
|
338
465
|
case 'session_host_prune_duplicate_sessions': {
|
|
339
466
|
if (!this.deps.sessionHostControl) return { success: false, error: 'Session host control unavailable' };
|
|
340
|
-
const result = await this.deps.sessionHostControl
|
|
467
|
+
const result = await this.traceSessionHostAction('session_host_prune_duplicate_sessions', args, () => this.deps.sessionHostControl!.pruneDuplicateSessions({
|
|
341
468
|
providerType: typeof args?.providerType === 'string' ? args.providerType : undefined,
|
|
342
469
|
workspace: typeof args?.workspace === 'string' ? args.workspace : undefined,
|
|
343
470
|
dryRun: args?.dryRun === true,
|
|
344
|
-
});
|
|
471
|
+
}), (value) => summarizeSessionHostPruneResult(value));
|
|
345
472
|
return { success: true, result };
|
|
346
473
|
}
|
|
347
474
|
|
|
@@ -352,12 +479,15 @@ export class DaemonCommandRouter {
|
|
|
352
479
|
const ownerType = args?.ownerType === 'agent' ? 'agent' : 'user';
|
|
353
480
|
if (!sessionId) return { success: false, error: 'sessionId required' };
|
|
354
481
|
if (!clientId) return { success: false, error: 'clientId required' };
|
|
355
|
-
const record = await this.deps.sessionHostControl
|
|
482
|
+
const record = await this.traceSessionHostAction('session_host_acquire_write', args, () => this.deps.sessionHostControl!.acquireWrite({
|
|
356
483
|
sessionId,
|
|
357
484
|
clientId,
|
|
358
485
|
ownerType,
|
|
359
486
|
force: args?.force !== false,
|
|
360
|
-
})
|
|
487
|
+
}), (result) => ({
|
|
488
|
+
...summarizeSessionHostRecord(result),
|
|
489
|
+
ownerType,
|
|
490
|
+
}));
|
|
361
491
|
return { success: true, record };
|
|
362
492
|
}
|
|
363
493
|
|
|
@@ -367,7 +497,10 @@ export class DaemonCommandRouter {
|
|
|
367
497
|
const clientId = typeof args?.clientId === 'string' ? args.clientId : '';
|
|
368
498
|
if (!sessionId) return { success: false, error: 'sessionId required' };
|
|
369
499
|
if (!clientId) return { success: false, error: 'clientId required' };
|
|
370
|
-
const record = await this.deps.sessionHostControl
|
|
500
|
+
const record = await this.traceSessionHostAction('session_host_release_write', args, () => this.deps.sessionHostControl!.releaseWrite({
|
|
501
|
+
sessionId,
|
|
502
|
+
clientId,
|
|
503
|
+
}), (result) => summarizeSessionHostRecord(result));
|
|
371
504
|
return { success: true, record };
|
|
372
505
|
}
|
|
373
506
|
|
|
@@ -408,7 +541,7 @@ export class DaemonCommandRouter {
|
|
|
408
541
|
kind: saved?.kind || recent?.kind || kind,
|
|
409
542
|
title: saved?.title || recent?.title || session.sessionTitle || session.preview || providerType,
|
|
410
543
|
workspace: saved?.workspace || recent?.workspace || session.workspace,
|
|
411
|
-
|
|
544
|
+
summaryMetadata: saved?.summaryMetadata || recent?.summaryMetadata,
|
|
412
545
|
preview: session.preview,
|
|
413
546
|
messageCount: session.messageCount,
|
|
414
547
|
firstMessageAt: session.firstMessageAt,
|
|
@@ -150,8 +150,25 @@ export async function handleSetProviderSourceConfig(h: CommandHelpers, args: any
|
|
|
150
150
|
|
|
151
151
|
// ─── Extension Script Execution (Model/Mode) ─────
|
|
152
152
|
|
|
153
|
-
function normalizeProviderScriptArgs(args: any): Record<string, any> {
|
|
153
|
+
export function normalizeProviderScriptArgs(args: any, scriptName?: string): Record<string, any> {
|
|
154
154
|
const normalizedArgs = { ...(args || {}) };
|
|
155
|
+
const normalizedScriptName = String(scriptName || '').toLowerCase();
|
|
156
|
+
|
|
157
|
+
if (Object.prototype.hasOwnProperty.call(normalizedArgs, 'value')) {
|
|
158
|
+
if (
|
|
159
|
+
normalizedArgs.model === undefined
|
|
160
|
+
&& (normalizedScriptName === 'setmodel' || normalizedScriptName === 'setmodelgui' || normalizedScriptName === 'webviewsetmodel')
|
|
161
|
+
) {
|
|
162
|
+
normalizedArgs.model = normalizedArgs.value;
|
|
163
|
+
}
|
|
164
|
+
if (
|
|
165
|
+
normalizedArgs.mode === undefined
|
|
166
|
+
&& (normalizedScriptName === 'setmode' || normalizedScriptName === 'webviewsetmode')
|
|
167
|
+
) {
|
|
168
|
+
normalizedArgs.mode = normalizedArgs.value;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
155
172
|
for (const key of ['mode', 'model', 'message', 'action', 'button', 'text', 'sessionId', 'value']) {
|
|
156
173
|
if (key in normalizedArgs && !(key.toUpperCase() in normalizedArgs)) {
|
|
157
174
|
normalizedArgs[key.toUpperCase()] = normalizedArgs[key];
|
|
@@ -213,7 +230,7 @@ async function executeProviderScript(h: CommandHelpers, args: any, scriptName: s
|
|
|
213
230
|
return { success: false, error: `Script '${actualScriptName}' not available for ${resolvedProviderType}` };
|
|
214
231
|
}
|
|
215
232
|
|
|
216
|
-
const normalizedArgs = normalizeProviderScriptArgs(args);
|
|
233
|
+
const normalizedArgs = normalizeProviderScriptArgs(args, actualScriptName);
|
|
217
234
|
|
|
218
235
|
if (provider.category === 'cli') {
|
|
219
236
|
const adapter = h.getCliAdapter(args?.targetSessionId || resolvedProviderType);
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* - deduped by provider session when available, else by kind + providerType + workspace
|
|
7
7
|
* - used only for quick-launch shortcuts
|
|
8
8
|
*/
|
|
9
|
+
import type { ProviderSummaryMetadata } from '../shared-types.js';
|
|
9
10
|
import type { DaemonState } from './state-store.js';
|
|
10
11
|
export interface RecentActivityEntry {
|
|
11
12
|
id: string;
|
|
@@ -14,7 +15,7 @@ export interface RecentActivityEntry {
|
|
|
14
15
|
providerName: string;
|
|
15
16
|
providerSessionId?: string;
|
|
16
17
|
workspace?: string | null;
|
|
17
|
-
|
|
18
|
+
summaryMetadata?: ProviderSummaryMetadata;
|
|
18
19
|
title?: string;
|
|
19
20
|
lastUsedAt: number;
|
|
20
21
|
}
|
|
@@ -8,8 +8,10 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import * as path from 'path';
|
|
11
|
+
import type { ProviderSummaryMetadata } from '../shared-types.js';
|
|
11
12
|
import type { DaemonState } from './state-store.js';
|
|
12
13
|
import { expandPath } from './workspaces.js';
|
|
14
|
+
import { normalizePersistedSummaryMetadata } from '../providers/summary-metadata.js';
|
|
13
15
|
|
|
14
16
|
export interface RecentActivityEntry {
|
|
15
17
|
id: string;
|
|
@@ -18,7 +20,7 @@ export interface RecentActivityEntry {
|
|
|
18
20
|
providerName: string;
|
|
19
21
|
providerSessionId?: string;
|
|
20
22
|
workspace?: string | null;
|
|
21
|
-
|
|
23
|
+
summaryMetadata?: ProviderSummaryMetadata;
|
|
22
24
|
title?: string;
|
|
23
25
|
lastUsedAt: number;
|
|
24
26
|
}
|
|
@@ -55,6 +57,9 @@ export function appendRecentActivity(
|
|
|
55
57
|
const nextEntry: RecentActivityEntry = {
|
|
56
58
|
...entry,
|
|
57
59
|
workspace: entry.workspace ? normalizeWorkspace(entry.workspace) : undefined,
|
|
60
|
+
summaryMetadata: normalizePersistedSummaryMetadata({
|
|
61
|
+
summaryMetadata: entry.summaryMetadata,
|
|
62
|
+
}),
|
|
58
63
|
id: buildRecentActivityKeyForEntry(entry),
|
|
59
64
|
lastUsedAt: entry.lastUsedAt || Date.now(),
|
|
60
65
|
};
|
|
@@ -68,6 +73,12 @@ export function appendRecentActivity(
|
|
|
68
73
|
|
|
69
74
|
export function getRecentActivity(state: DaemonState, limit = 20): RecentActivityEntry[] {
|
|
70
75
|
return [...(state.recentActivity || [])]
|
|
76
|
+
.map(entry => ({
|
|
77
|
+
...entry,
|
|
78
|
+
summaryMetadata: normalizePersistedSummaryMetadata({
|
|
79
|
+
summaryMetadata: entry.summaryMetadata,
|
|
80
|
+
}),
|
|
81
|
+
}))
|
|
71
82
|
.sort((a, b) => b.lastUsedAt - a.lastUsedAt)
|
|
72
83
|
.slice(0, limit);
|
|
73
84
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ProviderSummaryMetadata } from '../shared-types.js';
|
|
1
2
|
import type { DaemonState } from './state-store.js';
|
|
2
3
|
export interface SavedProviderSessionEntry {
|
|
3
4
|
id: string;
|
|
@@ -6,7 +7,7 @@ export interface SavedProviderSessionEntry {
|
|
|
6
7
|
providerName: string;
|
|
7
8
|
providerSessionId: string;
|
|
8
9
|
workspace?: string | null;
|
|
9
|
-
|
|
10
|
+
summaryMetadata?: ProviderSummaryMetadata;
|
|
10
11
|
title?: string;
|
|
11
12
|
createdAt: number;
|
|
12
13
|
lastUsedAt: number;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import * as path from 'path';
|
|
2
|
+
import type { ProviderSummaryMetadata } from '../shared-types.js';
|
|
2
3
|
import type { DaemonState } from './state-store.js';
|
|
3
4
|
import { expandPath } from './workspaces.js';
|
|
5
|
+
import { normalizePersistedSummaryMetadata } from '../providers/summary-metadata.js';
|
|
4
6
|
|
|
5
7
|
export interface SavedProviderSessionEntry {
|
|
6
8
|
id: string;
|
|
@@ -9,7 +11,7 @@ export interface SavedProviderSessionEntry {
|
|
|
9
11
|
providerName: string;
|
|
10
12
|
providerSessionId: string;
|
|
11
13
|
workspace?: string | null;
|
|
12
|
-
|
|
14
|
+
summaryMetadata?: ProviderSummaryMetadata;
|
|
13
15
|
title?: string;
|
|
14
16
|
createdAt: number;
|
|
15
17
|
lastUsedAt: number;
|
|
@@ -46,7 +48,9 @@ export function upsertSavedProviderSession(
|
|
|
46
48
|
providerName: entry.providerName,
|
|
47
49
|
providerSessionId,
|
|
48
50
|
workspace: entry.workspace ? normalizeWorkspace(entry.workspace) : undefined,
|
|
49
|
-
|
|
51
|
+
summaryMetadata: normalizePersistedSummaryMetadata({
|
|
52
|
+
summaryMetadata: entry.summaryMetadata,
|
|
53
|
+
}),
|
|
50
54
|
title: entry.title,
|
|
51
55
|
createdAt: existing?.createdAt || entry.createdAt || Date.now(),
|
|
52
56
|
lastUsedAt: entry.lastUsedAt || Date.now(),
|
|
@@ -69,5 +73,11 @@ export function getSavedProviderSessions(
|
|
|
69
73
|
if (filters?.kind && entry.kind !== filters.kind) return false;
|
|
70
74
|
return true;
|
|
71
75
|
})
|
|
76
|
+
.map(entry => ({
|
|
77
|
+
...entry,
|
|
78
|
+
summaryMetadata: normalizePersistedSummaryMetadata({
|
|
79
|
+
summaryMetadata: entry.summaryMetadata,
|
|
80
|
+
}),
|
|
81
|
+
}))
|
|
72
82
|
.sort((a, b) => b.lastUsedAt - a.lastUsedAt);
|
|
73
83
|
}
|
|
@@ -888,7 +888,7 @@ export function buildAutoImplPrompt(ctx: DevServerContext,
|
|
|
888
888
|
lines.push('## Required Return Format');
|
|
889
889
|
lines.push('| Function | Return JSON |');
|
|
890
890
|
lines.push('|---|---|');
|
|
891
|
-
lines.push('| readChat | `{ id, status, title, messages: [{role, content, index, kind?, meta?}], inputContent, activeModal }` — optional `kind`: standard, thought, tool, terminal;
|
|
891
|
+
lines.push('| readChat | `{ id, status, title, messages: [{role, content, index, kind?, meta?}], inputContent, activeModal, controlValues?, summaryMetadata? }` — optional `kind`: standard, thought, tool, terminal; prefer explicit `controlValues` for current selections and `summaryMetadata` for compact always-visible UI metadata |');
|
|
892
892
|
lines.push('| sendMessage | `{ sent: false, needsTypeAndSend: true, selector }` |');
|
|
893
893
|
lines.push('| resolveAction | `{ resolved: true/false, clicked? }` |');
|
|
894
894
|
lines.push('| listSessions | `{ sessions: [{ id, title, active, index }] }` |');
|
|
@@ -757,7 +757,6 @@ export async function handleCliStatus(ctx: DevServerContext, _req: http.Incoming
|
|
|
757
757
|
lastMessage: s.activeChat?.messages?.slice(-1)[0] || null,
|
|
758
758
|
activeModal: s.activeChat?.activeModal || null,
|
|
759
759
|
pendingEvents: s.pendingEvents || [],
|
|
760
|
-
currentModel: s.currentModel,
|
|
761
760
|
settings: s.settings,
|
|
762
761
|
}));
|
|
763
762
|
ctx.json(res, 200, { instances: result, count: result.length });
|
package/src/daemon/dev-server.ts
CHANGED
|
@@ -1211,7 +1211,7 @@ export class DevServer implements DevServerContext {
|
|
|
1211
1211
|
lines.push('## Required Return Format');
|
|
1212
1212
|
lines.push('| Function | Return JSON |');
|
|
1213
1213
|
lines.push('|---|---|');
|
|
1214
|
-
lines.push('| readChat | `{ id, status, title, messages: [{role, content, index, kind?, meta?}], inputContent, activeModal }` — optional `kind`: standard, thought, tool, terminal;
|
|
1214
|
+
lines.push('| readChat | `{ id, status, title, messages: [{role, content, index, kind?, meta?}], inputContent, activeModal, controlValues?, summaryMetadata? }` — optional `kind`: standard, thought, tool, terminal; prefer explicit `controlValues` for current selections and `summaryMetadata` for compact always-visible UI metadata |');
|
|
1215
1215
|
lines.push('| sendMessage | `{ sent: false, needsTypeAndSend: true, selector }` |');
|
|
1216
1216
|
lines.push('| resolveAction | `{ resolved: true/false, clicked? }` |');
|
|
1217
1217
|
lines.push('| listSessions | `{ sessions: [{ id, title, active, index }] }` |');
|
|
@@ -178,7 +178,11 @@ module.exports.setMode = (params) => {
|
|
|
178
178
|
* 5. Approval dialog detection (buttons, modal)
|
|
179
179
|
* 6. Input field selector
|
|
180
180
|
*
|
|
181
|
-
*
|
|
181
|
+
* Preferred live-state surface:
|
|
182
|
+
* - controlValues: explicit current control selections (model/mode/etc.)
|
|
183
|
+
* - summaryMetadata: compact always-visible metadata for dashboard/recent views
|
|
184
|
+
* Legacy top-level model/mode output is no longer the preferred shape.
|
|
185
|
+
* → { id, status, title, messages[], inputContent, activeModal, controlValues?, summaryMetadata? }
|
|
182
186
|
*/
|
|
183
187
|
(() => {
|
|
184
188
|
try {
|
|
@@ -206,6 +210,9 @@ module.exports.setMode = (params) => {
|
|
|
206
210
|
messages,
|
|
207
211
|
inputContent,
|
|
208
212
|
activeModal,
|
|
213
|
+
// TODO: Return explicit selections when available, e.g.
|
|
214
|
+
// controlValues: { model: selectedModel, mode: selectedMode },
|
|
215
|
+
// summaryMetadata: { items: [{ id: 'model', value: selectedModelLabel || selectedModel, shortValue: selectedModel, order: 10 }] },
|
|
209
216
|
});
|
|
210
217
|
} catch(e) {
|
|
211
218
|
return JSON.stringify({ id: '', status: 'error', messages: [], error: e.message });
|
package/src/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Core logic for daemon: CDP, Provider, IDE detection, CLI/ACP adapters and more.
|
|
5
5
|
*/
|
|
6
6
|
export type { ChatMessage, ExtensionInfo, CommandResult as CoreCommandResult, ProviderConfig, DaemonEvent, StatusResponse, SystemInfo, DetectedIde, ProviderInfo, AgentEntry, } from './types.js';
|
|
7
|
-
export type { SessionEntry, CompactSessionEntry, CompactDaemonEntry, SessionTransport, SessionKind, SessionCapability, AgentSessionStream, ReadChatCursor, ReadChatSyncMode, ReadChatSyncResult, TransportTopic, SessionChatTailSubscriptionParams, MachineRuntimeSubscriptionParams, SessionHostDiagnosticsSubscriptionParams, SessionModalSubscriptionParams, DaemonMetadataSubscriptionParams, SessionChatTailUpdate, MachineRuntimeUpdate, SessionHostDiagnosticsUpdate, SessionModalUpdate, DaemonMetadataUpdate, TopicUpdateEnvelope, SubscribeRequest, UnsubscribeRequest, StandaloneWsStatusPayload, AvailableProviderInfo, AcpConfigOption, AcpMode, ProviderControlSchema, StatusReportPayload, MachineInfo, SessionHostDiagnosticsSnapshot, SessionHostRecord, SessionHostWriteOwner, SessionHostAttachedClient, SessionHostLogEntry, SessionHostRequestTrace, SessionHostRuntimeTransition, DetectedIdeInfo, WorkspaceEntry, ProviderState, ProviderStatus, ProviderErrorReason, ActiveChatData, IdeProviderState, CliProviderState, AcpProviderState, ExtensionProviderState, } from './shared-types.js';
|
|
7
|
+
export type { SessionEntry, CompactSessionEntry, CompactDaemonEntry, SessionTransport, SessionKind, SessionCapability, AgentSessionStream, ReadChatCursor, ReadChatSyncMode, ReadChatSyncResult, TransportTopic, SessionChatTailSubscriptionParams, MachineRuntimeSubscriptionParams, SessionHostDiagnosticsSubscriptionParams, SessionModalSubscriptionParams, DaemonMetadataSubscriptionParams, SessionChatTailUpdate, MachineRuntimeUpdate, SessionHostDiagnosticsUpdate, SessionModalUpdate, DaemonMetadataUpdate, TopicUpdateEnvelope, SubscribeRequest, UnsubscribeRequest, StandaloneWsStatusPayload, AvailableProviderInfo, AcpConfigOption, AcpMode, ProviderControlSchema, StatusReportPayload, MachineInfo, SessionHostDiagnosticsSnapshot, SessionHostRecord, SessionHostWriteOwner, SessionHostAttachedClient, SessionHostLogEntry, SessionHostRequestTrace, SessionHostRuntimeTransition, DetectedIdeInfo, WorkspaceEntry, ProviderSummaryItem, ProviderSummaryMetadata, ProviderState, ProviderStatus, ProviderErrorReason, ActiveChatData, IdeProviderState, CliProviderState, AcpProviderState, ExtensionProviderState, } from './shared-types.js';
|
|
8
8
|
import type { RuntimeWriteOwner as _RuntimeWriteOwner } from './shared-types-extra.js';
|
|
9
9
|
import type { RuntimeAttachedClient as _RuntimeAttachedClient } from './shared-types-extra.js';
|
|
10
10
|
import type { RecentLaunchEntry as _RecentLaunchEntry } from './shared-types.js';
|
package/src/index.ts
CHANGED
|
@@ -34,8 +34,7 @@ export declare class AcpProviderInstance implements ProviderInstance {
|
|
|
34
34
|
private lastStatus;
|
|
35
35
|
private generatingStartedAt;
|
|
36
36
|
private agentCapabilities;
|
|
37
|
-
private
|
|
38
|
-
private currentMode;
|
|
37
|
+
private currentSelections;
|
|
39
38
|
private activeToolCalls;
|
|
40
39
|
private stopReason;
|
|
41
40
|
private partialContent;
|
|
@@ -61,6 +60,13 @@ export declare class AcpProviderInstance implements ProviderInstance {
|
|
|
61
60
|
getState(): AcpProviderState;
|
|
62
61
|
onEvent(event: string, data?: any): void;
|
|
63
62
|
getInstanceId(): string;
|
|
63
|
+
private resolveConfigOptionLabel;
|
|
64
|
+
private resolveModeLabel;
|
|
65
|
+
private getCurrentSelection;
|
|
66
|
+
private setCurrentSelection;
|
|
67
|
+
private getSelectionControlValues;
|
|
68
|
+
private resolveSelectionLabel;
|
|
69
|
+
private buildSelectionSummaryMetadata;
|
|
64
70
|
private parseConfigOptions;
|
|
65
71
|
private parseModes;
|
|
66
72
|
setConfigOption(category: string, value: string): Promise<void>;
|