@adhdev/daemon-core 0.9.76-rc.4 → 0.9.76-rc.41
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 +2 -1
- package/dist/cli-adapters/provider-cli-runtime.d.ts +1 -0
- package/dist/commands/cli-manager.d.ts +17 -4
- package/dist/commands/mesh-coordinator.d.ts +2 -0
- package/dist/commands/router.d.ts +11 -0
- package/dist/config/mesh-config.d.ts +3 -0
- package/dist/git/git-types.d.ts +1 -1
- package/dist/git/git-worktree.d.ts +64 -0
- package/dist/git/index.d.ts +2 -0
- package/dist/index.js +1318 -426
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1345 -457
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/coordinator-prompt.d.ts +1 -0
- package/dist/mesh/mesh-events.d.ts +9 -0
- package/dist/providers/chat-message-normalization.d.ts +11 -0
- package/dist/providers/cli-provider-instance.d.ts +3 -0
- package/dist/providers/provider-instance-manager.d.ts +1 -0
- package/dist/providers/provider-instance.d.ts +2 -0
- package/dist/repo-mesh-types.d.ts +13 -0
- package/dist/shared-types.d.ts +22 -1
- package/package.json +3 -4
- package/src/cli-adapters/provider-cli-adapter.ts +13 -6
- package/src/cli-adapters/provider-cli-runtime.ts +3 -2
- package/src/commands/chat-commands.ts +76 -5
- package/src/commands/cli-manager.ts +78 -5
- package/src/commands/handler.ts +13 -4
- package/src/commands/mesh-coordinator.ts +149 -6
- package/src/commands/router.d.ts +1 -0
- package/src/commands/router.ts +505 -34
- package/src/config/mesh-config.ts +23 -2
- package/src/git/git-commands.ts +5 -1
- package/src/git/git-types.ts +1 -0
- package/src/git/git-worktree.ts +214 -0
- package/src/git/index.ts +14 -0
- package/src/mesh/coordinator-prompt.ts +25 -10
- package/src/mesh/mesh-events.ts +109 -43
- package/src/providers/chat-message-normalization.ts +54 -0
- package/src/providers/cli-provider-instance.d.ts +2 -0
- package/src/providers/cli-provider-instance.ts +55 -7
- package/src/providers/provider-instance-manager.ts +20 -1
- package/src/providers/provider-instance.ts +2 -0
- package/src/repo-mesh-types.ts +15 -0
- package/src/shared-types.ts +24 -1
- package/src/status/builders.ts +17 -12
- package/src/status/reporter.ts +6 -0
|
@@ -214,6 +214,7 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
214
214
|
options?: {
|
|
215
215
|
providerSessionId?: string;
|
|
216
216
|
launchMode?: 'new' | 'resume' | 'manual';
|
|
217
|
+
extraEnv?: Record<string, string>;
|
|
217
218
|
onProviderSessionResolved?: (info: {
|
|
218
219
|
instanceId: string;
|
|
219
220
|
providerType: string;
|
|
@@ -230,7 +231,7 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
230
231
|
this.providerSessionId = options?.providerSessionId;
|
|
231
232
|
this.launchMode = options?.launchMode || 'new';
|
|
232
233
|
this.onProviderSessionResolved = options?.onProviderSessionResolved;
|
|
233
|
-
this.adapter = new ProviderCliAdapter(provider as CliProviderModule, workingDir, cliArgs, transportFactory);
|
|
234
|
+
this.adapter = new ProviderCliAdapter(provider as CliProviderModule, workingDir, cliArgs, options?.extraEnv || {}, transportFactory);
|
|
234
235
|
this.monitor = new StatusMonitor();
|
|
235
236
|
this.historyWriter = new ChatHistoryWriter();
|
|
236
237
|
}
|
|
@@ -737,7 +738,29 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
737
738
|
}
|
|
738
739
|
|
|
739
740
|
private pushEvent(event: ProviderEvent): void {
|
|
740
|
-
|
|
741
|
+
const enrichedEvent: ProviderEvent = {
|
|
742
|
+
...event,
|
|
743
|
+
instanceId: typeof event.instanceId === 'string' && event.instanceId.trim()
|
|
744
|
+
? event.instanceId
|
|
745
|
+
: this.instanceId,
|
|
746
|
+
targetSessionId: typeof event.targetSessionId === 'string' && event.targetSessionId.trim()
|
|
747
|
+
? event.targetSessionId
|
|
748
|
+
: this.instanceId,
|
|
749
|
+
providerType: typeof event.providerType === 'string' && event.providerType.trim()
|
|
750
|
+
? event.providerType
|
|
751
|
+
: this.type,
|
|
752
|
+
workspaceName: typeof event.workspaceName === 'string' && event.workspaceName.trim()
|
|
753
|
+
? event.workspaceName
|
|
754
|
+
: this.workingDir,
|
|
755
|
+
providerSessionId: typeof event.providerSessionId === 'string' && event.providerSessionId.trim()
|
|
756
|
+
? event.providerSessionId
|
|
757
|
+
: this.providerSessionId,
|
|
758
|
+
};
|
|
759
|
+
if (this.context?.emitProviderEvent) {
|
|
760
|
+
this.context.emitProviderEvent(enrichedEvent);
|
|
761
|
+
return;
|
|
762
|
+
}
|
|
763
|
+
this.events.push(enrichedEvent);
|
|
741
764
|
}
|
|
742
765
|
|
|
743
766
|
private flushEvents(): ProviderEvent[] {
|
|
@@ -977,15 +1000,40 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
977
1000
|
}
|
|
978
1001
|
}
|
|
979
1002
|
|
|
1003
|
+
mergeRuntimeChatMessages(parsedMessages: ChatMessage[]): ChatMessage[] {
|
|
1004
|
+
return this.mergeConversationMessages(parsedMessages);
|
|
1005
|
+
}
|
|
1006
|
+
|
|
980
1007
|
private mergeConversationMessages(parsedMessages: any[]): ChatMessage[] {
|
|
981
1008
|
if (this.runtimeMessages.length === 0) return normalizeChatMessages(parsedMessages);
|
|
982
1009
|
|
|
983
|
-
|
|
984
|
-
|
|
1010
|
+
type MergeEntry = { message: ChatMessage; index: number; source: 'parsed' | 'runtime' };
|
|
1011
|
+
const parsedEntries: MergeEntry[] = parsedMessages.map((message, index) => ({
|
|
1012
|
+
message,
|
|
1013
|
+
index,
|
|
1014
|
+
source: 'parsed',
|
|
1015
|
+
}));
|
|
1016
|
+
const runtimeEntries: MergeEntry[] = this.runtimeMessages.map((entry, index) => ({
|
|
1017
|
+
message: entry.message,
|
|
1018
|
+
index: parsedMessages.length + index,
|
|
1019
|
+
source: 'runtime',
|
|
1020
|
+
}));
|
|
1021
|
+
const getTime = (message: ChatMessage): number => {
|
|
1022
|
+
const value = typeof message.receivedAt === 'number'
|
|
1023
|
+
? message.receivedAt
|
|
1024
|
+
: typeof message.timestamp === 'number'
|
|
1025
|
+
? message.timestamp
|
|
1026
|
+
: 0;
|
|
1027
|
+
return Number.isFinite(value) && value > 0 ? value : 0;
|
|
1028
|
+
};
|
|
1029
|
+
|
|
1030
|
+
return normalizeChatMessages([...parsedEntries, ...runtimeEntries]
|
|
985
1031
|
.sort((a, b) => {
|
|
986
|
-
const aTime = a.message
|
|
987
|
-
const bTime = b.message
|
|
988
|
-
if (aTime !== bTime) return aTime - bTime;
|
|
1032
|
+
const aTime = getTime(a.message);
|
|
1033
|
+
const bTime = getTime(b.message);
|
|
1034
|
+
if (aTime && bTime && aTime !== bTime) return aTime - bTime;
|
|
1035
|
+
if (aTime && !bTime && a.source === 'runtime' && b.source === 'parsed') return -1;
|
|
1036
|
+
if (!aTime && bTime && a.source === 'parsed' && b.source === 'runtime') return 1;
|
|
989
1037
|
return a.index - b.index;
|
|
990
1038
|
})
|
|
991
1039
|
.map((entry) => entry.message));
|
|
@@ -47,7 +47,10 @@ export class ProviderInstanceManager {
|
|
|
47
47
|
this.instances.get(id)!.dispose();
|
|
48
48
|
}
|
|
49
49
|
this.instances.set(id, instance);
|
|
50
|
-
await instance.init(
|
|
50
|
+
await instance.init({
|
|
51
|
+
...context,
|
|
52
|
+
emitProviderEvent: (event) => this.emitProviderEvent(instance.type, id, event),
|
|
53
|
+
});
|
|
51
54
|
}
|
|
52
55
|
|
|
53
56
|
/**
|
|
@@ -237,6 +240,22 @@ export class ProviderInstanceManager {
|
|
|
237
240
|
this.eventListeners.push(listener);
|
|
238
241
|
}
|
|
239
242
|
|
|
243
|
+
emitProviderEvent(providerType: string, instanceId: string, event: ProviderEvent): void {
|
|
244
|
+
const payload = {
|
|
245
|
+
...event,
|
|
246
|
+
providerType,
|
|
247
|
+
instanceId: typeof event.instanceId === 'string' && event.instanceId.trim()
|
|
248
|
+
? event.instanceId
|
|
249
|
+
: instanceId,
|
|
250
|
+
targetSessionId: typeof event.targetSessionId === 'string' && event.targetSessionId.trim()
|
|
251
|
+
? event.targetSessionId
|
|
252
|
+
: instanceId,
|
|
253
|
+
} as ProviderEvent & { providerType: string };
|
|
254
|
+
for (const listener of this.eventListeners) {
|
|
255
|
+
listener(payload);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
240
259
|
private emitPendingEvents(
|
|
241
260
|
providerType: string,
|
|
242
261
|
state: ProviderState,
|
|
@@ -174,6 +174,8 @@ export interface InstanceContext {
|
|
|
174
174
|
onPtyData?: (data: string) => void;
|
|
175
175
|
/** Provider configvalue (resolved) */
|
|
176
176
|
settings: Record<string, any>;
|
|
177
|
+
/** Immediate provider-originated status/event emission. Used to avoid waiting for status polling. */
|
|
178
|
+
emitProviderEvent?: (event: ProviderEvent) => void;
|
|
177
179
|
}
|
|
178
180
|
|
|
179
181
|
export interface ProviderInstance {
|
package/src/repo-mesh-types.ts
CHANGED
|
@@ -55,6 +55,8 @@ export type RepoMeshNodeHealth =
|
|
|
55
55
|
|
|
56
56
|
// ─── Policy Types ───────────────────────────────
|
|
57
57
|
|
|
58
|
+
export type RepoMeshSessionCleanupMode = 'preserve' | 'stop' | 'delete_stopped' | 'stop_and_delete';
|
|
59
|
+
|
|
58
60
|
export interface RepoMeshPolicy {
|
|
59
61
|
requirePreTaskCheckpoint: boolean;
|
|
60
62
|
requirePostTaskCheckpoint: boolean;
|
|
@@ -63,12 +65,20 @@ export interface RepoMeshPolicy {
|
|
|
63
65
|
dirtyWorkspaceBehavior: 'block' | 'warn' | 'checkpoint_then_continue';
|
|
64
66
|
maxParallelTasks: number;
|
|
65
67
|
allowedProviders?: string[];
|
|
68
|
+
/**
|
|
69
|
+
* What to do with delegated session-host records for a node when it is removed.
|
|
70
|
+
* Defaults to 'preserve' so completed work can be reviewed later and live
|
|
71
|
+
* runtimes are never stopped/deleted unless the mesh owner opts in.
|
|
72
|
+
*/
|
|
73
|
+
sessionCleanupOnNodeRemove?: RepoMeshSessionCleanupMode;
|
|
66
74
|
}
|
|
67
75
|
|
|
68
76
|
export interface RepoMeshNodePolicy {
|
|
69
77
|
readOnly?: boolean;
|
|
70
78
|
canPush?: boolean;
|
|
71
79
|
maxConcurrentSessions?: number;
|
|
80
|
+
/** Ordered provider preference used when mesh_launch_session omits an explicit type. */
|
|
81
|
+
providerPriority?: string[];
|
|
72
82
|
}
|
|
73
83
|
|
|
74
84
|
export const DEFAULT_MESH_POLICY: RepoMeshPolicy = {
|
|
@@ -78,6 +88,7 @@ export const DEFAULT_MESH_POLICY: RepoMeshPolicy = {
|
|
|
78
88
|
requireApprovalForDestructiveGit: true,
|
|
79
89
|
dirtyWorkspaceBehavior: 'warn',
|
|
80
90
|
maxParallelTasks: 2,
|
|
91
|
+
sessionCleanupOnNodeRemove: 'preserve',
|
|
81
92
|
};
|
|
82
93
|
|
|
83
94
|
// ─── Capabilities ───────────────────────────────
|
|
@@ -189,6 +200,10 @@ export interface LocalMeshNodeEntry {
|
|
|
189
200
|
policy: RepoMeshNodePolicy;
|
|
190
201
|
/** For single-machine mesh: same daemon, different worktree */
|
|
191
202
|
isLocalWorktree?: boolean;
|
|
203
|
+
/** Branch this worktree tracks (set when created via clone_mesh_node) */
|
|
204
|
+
worktreeBranch?: string;
|
|
205
|
+
/** Node ID this worktree was cloned from */
|
|
206
|
+
clonedFromNodeId?: string;
|
|
192
207
|
}
|
|
193
208
|
|
|
194
209
|
// ─── Mesh Status (runtime, not persisted) ───────
|
package/src/shared-types.ts
CHANGED
|
@@ -432,6 +432,17 @@ export type VersionUpdateReason =
|
|
|
432
432
|
| 'patch_mismatch'
|
|
433
433
|
| 'daemon_ahead';
|
|
434
434
|
|
|
435
|
+
export type ReleaseChannel = 'stable' | 'preview';
|
|
436
|
+
export type NpmUpdateTag = 'latest' | 'next';
|
|
437
|
+
|
|
438
|
+
export interface VersionUpdatePolicy {
|
|
439
|
+
channel: ReleaseChannel;
|
|
440
|
+
npmTag: NpmUpdateTag;
|
|
441
|
+
targetVersion: string;
|
|
442
|
+
minVersion?: string;
|
|
443
|
+
updateCommand: string;
|
|
444
|
+
}
|
|
445
|
+
|
|
435
446
|
/** Available provider information */
|
|
436
447
|
export interface AvailableProviderInfo {
|
|
437
448
|
type: string;
|
|
@@ -577,6 +588,10 @@ export interface CompactDaemonEntry {
|
|
|
577
588
|
versionMismatch?: boolean;
|
|
578
589
|
versionUpdateRequired?: boolean;
|
|
579
590
|
versionUpdateReason?: VersionUpdateReason;
|
|
591
|
+
releaseChannel?: ReleaseChannel;
|
|
592
|
+
updateChannel?: ReleaseChannel;
|
|
593
|
+
updatePolicy?: VersionUpdatePolicy;
|
|
594
|
+
updateCommand?: string;
|
|
580
595
|
terminalBackend?: TerminalBackendStatus;
|
|
581
596
|
detectedIdes?: DetectedIdeInfo[];
|
|
582
597
|
availableProviders?: AvailableProviderInfo[];
|
|
@@ -599,11 +614,15 @@ export interface CloudDaemonSummaryEntry {
|
|
|
599
614
|
versionMismatch?: boolean;
|
|
600
615
|
versionUpdateRequired?: boolean;
|
|
601
616
|
versionUpdateReason?: VersionUpdateReason;
|
|
617
|
+
releaseChannel?: ReleaseChannel;
|
|
618
|
+
updateChannel?: ReleaseChannel;
|
|
619
|
+
updatePolicy?: VersionUpdatePolicy;
|
|
620
|
+
updateCommand?: string;
|
|
602
621
|
terminalBackend?: TerminalBackendStatus;
|
|
603
622
|
}
|
|
604
623
|
|
|
605
624
|
/** Minimal daemon bootstrap payload used by dashboard WS to initiate P2P. */
|
|
606
|
-
export interface DashboardBootstrapDaemonEntry {
|
|
625
|
+
export interface DashboardBootstrapDaemonEntry extends Partial<CloudDaemonSummaryEntry> {
|
|
607
626
|
id: string;
|
|
608
627
|
p2p?: StatusReportPayload['p2p'];
|
|
609
628
|
timestamp?: number;
|
|
@@ -622,6 +641,8 @@ export interface DaemonStatusEventPayload {
|
|
|
622
641
|
timestamp: number;
|
|
623
642
|
targetSessionId?: string;
|
|
624
643
|
providerType?: string;
|
|
644
|
+
providerSessionId?: string;
|
|
645
|
+
workspaceName?: string;
|
|
625
646
|
duration?: number;
|
|
626
647
|
elapsedSec?: number;
|
|
627
648
|
modalMessage?: string;
|
|
@@ -643,6 +664,8 @@ export interface DashboardStatusEventPayload {
|
|
|
643
664
|
daemonId?: string;
|
|
644
665
|
providerType?: string;
|
|
645
666
|
targetSessionId?: string;
|
|
667
|
+
providerSessionId?: string;
|
|
668
|
+
workspaceName?: string;
|
|
646
669
|
duration?: number;
|
|
647
670
|
elapsedSec?: number;
|
|
648
671
|
modalMessage?: string;
|
package/src/status/builders.ts
CHANGED
|
@@ -43,6 +43,19 @@ function getActiveChatOptions(profile: SessionEntryProfile): NormalizeActiveChat
|
|
|
43
43
|
return LIVE_STATUS_ACTIVE_CHAT_OPTIONS;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
function resolveSessionStatus(
|
|
47
|
+
activeChat: { status?: string | null; activeModal?: { buttons?: unknown[] | null } | null } | null | undefined,
|
|
48
|
+
providerStatus?: string | null,
|
|
49
|
+
) {
|
|
50
|
+
const chatStatus = normalizeManagedStatus(activeChat?.status, { activeModal: activeChat?.activeModal || null });
|
|
51
|
+
const topLevelStatus = normalizeManagedStatus(providerStatus, { activeModal: activeChat?.activeModal || null });
|
|
52
|
+
|
|
53
|
+
if (chatStatus === 'waiting_approval' || topLevelStatus === 'waiting_approval') return 'waiting_approval';
|
|
54
|
+
if (chatStatus === 'generating' || topLevelStatus === 'generating') return 'generating';
|
|
55
|
+
if (topLevelStatus !== 'idle') return topLevelStatus;
|
|
56
|
+
return chatStatus;
|
|
57
|
+
}
|
|
58
|
+
|
|
46
59
|
function shouldIncludeSessionControls(profile: SessionEntryProfile): boolean {
|
|
47
60
|
return profile !== 'live';
|
|
48
61
|
}
|
|
@@ -170,9 +183,7 @@ function buildIdeWorkspaceSession(
|
|
|
170
183
|
providerName: state.name,
|
|
171
184
|
kind: 'workspace',
|
|
172
185
|
transport: 'cdp-page',
|
|
173
|
-
status:
|
|
174
|
-
activeModal: activeChat?.activeModal || null,
|
|
175
|
-
}),
|
|
186
|
+
status: resolveSessionStatus(activeChat, state.status),
|
|
176
187
|
title,
|
|
177
188
|
workspace,
|
|
178
189
|
...(git && { git }),
|
|
@@ -212,9 +223,7 @@ function buildExtensionAgentSession(
|
|
|
212
223
|
providerSessionId: ext.providerSessionId,
|
|
213
224
|
kind: 'agent',
|
|
214
225
|
transport: 'cdp-webview',
|
|
215
|
-
status:
|
|
216
|
-
activeModal: activeChat?.activeModal || null,
|
|
217
|
-
}),
|
|
226
|
+
status: resolveSessionStatus(activeChat, ext.status),
|
|
218
227
|
title: activeChat?.title || ext.name,
|
|
219
228
|
workspace,
|
|
220
229
|
...(git && { git }),
|
|
@@ -277,9 +286,7 @@ function buildCliSession(state: CliProviderState, options: SessionEntryBuildOpti
|
|
|
277
286
|
providerSessionId: state.providerSessionId,
|
|
278
287
|
kind: 'agent',
|
|
279
288
|
transport: 'pty',
|
|
280
|
-
status:
|
|
281
|
-
activeModal: activeChat?.activeModal || null,
|
|
282
|
-
}),
|
|
289
|
+
status: resolveSessionStatus(activeChat, state.status),
|
|
283
290
|
title: activeChat?.title || state.name,
|
|
284
291
|
workspace,
|
|
285
292
|
...(git && { git }),
|
|
@@ -328,9 +335,7 @@ function buildAcpSession(state: AcpProviderState, options: SessionEntryBuildOpti
|
|
|
328
335
|
providerName: state.name,
|
|
329
336
|
kind: 'agent',
|
|
330
337
|
transport: 'acp',
|
|
331
|
-
status:
|
|
332
|
-
activeModal: activeChat?.activeModal || null,
|
|
333
|
-
}),
|
|
338
|
+
status: resolveSessionStatus(activeChat, state.status),
|
|
334
339
|
title: activeChat?.title || state.name,
|
|
335
340
|
workspace,
|
|
336
341
|
...(git && { git }),
|
package/src/status/reporter.ts
CHANGED
|
@@ -151,6 +151,12 @@ export class DaemonStatusReporter {
|
|
|
151
151
|
if (providerType) {
|
|
152
152
|
payload.providerType = providerType;
|
|
153
153
|
}
|
|
154
|
+
if (typeof event.providerSessionId === 'string' && event.providerSessionId.trim()) {
|
|
155
|
+
payload.providerSessionId = event.providerSessionId.trim();
|
|
156
|
+
}
|
|
157
|
+
if (typeof event.workspaceName === 'string' && event.workspaceName.trim()) {
|
|
158
|
+
payload.workspaceName = event.workspaceName.trim();
|
|
159
|
+
}
|
|
154
160
|
if (typeof event.duration === 'number' && Number.isFinite(event.duration)) {
|
|
155
161
|
payload.duration = event.duration;
|
|
156
162
|
}
|