@adhdev/daemon-core 0.9.77-rc.6 → 0.9.77-rc.60
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/boot/daemon-lifecycle.d.ts +3 -0
- package/dist/cli-adapters/provider-cli-adapter.d.ts +4 -0
- package/dist/cli-adapters/provider-cli-shared.d.ts +14 -4
- package/dist/commands/mesh-coordinator.d.ts +10 -0
- package/dist/commands/router.d.ts +4 -1
- package/dist/config/mesh-config.d.ts +1 -0
- package/dist/git/git-worktree.d.ts +15 -2
- package/dist/index.d.ts +10 -6
- package/dist/index.js +2076 -299
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2061 -299
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/mesh-events.d.ts +14 -7
- package/dist/mesh/mesh-ledger-reconciliation.d.ts +55 -0
- package/dist/mesh/mesh-ledger.d.ts +84 -4
- package/dist/mesh/mesh-sync.d.ts +4 -12
- package/dist/mesh/mesh-visualization.d.ts +70 -0
- package/dist/mesh/mesh-work-queue.d.ts +58 -1
- package/dist/mesh/p2p-relay-failure.d.ts +35 -0
- package/dist/providers/chat-message-normalization.d.ts +1 -0
- package/dist/providers/cli-provider-instance.d.ts +6 -0
- package/dist/repo-mesh-types.d.ts +2 -0
- package/dist/shared-types.d.ts +38 -0
- package/package.json +1 -1
- package/src/boot/daemon-lifecycle.ts +5 -0
- package/src/cli-adapters/provider-cli-adapter.ts +35 -4
- package/src/cli-adapters/provider-cli-shared.ts +14 -4
- package/src/commands/cli-manager.ts +0 -4
- package/src/commands/mesh-coordinator.ts +55 -7
- package/src/commands/router.ts +915 -26
- package/src/commands/stream-commands.ts +8 -1
- package/src/config/config.ts +2 -1
- package/src/config/mesh-config.ts +2 -0
- package/src/config/workspaces.ts +1 -1
- package/src/git/git-worktree.ts +56 -4
- package/src/index.d.ts +3 -0
- package/src/index.ts +29 -6
- package/src/mesh/coordinator-prompt.ts +21 -10
- package/src/mesh/mesh-events.ts +532 -22
- package/src/mesh/mesh-ledger-reconciliation.ts +115 -0
- package/src/mesh/mesh-ledger.ts +209 -8
- package/src/mesh/mesh-sync.ts +4 -34
- package/src/mesh/mesh-visualization.ts +341 -0
- package/src/mesh/mesh-work-queue.ts +183 -17
- package/src/mesh/p2p-relay-failure.ts +152 -0
- package/src/providers/acp-provider-instance.ts +2 -1
- package/src/providers/chat-message-normalization.ts +32 -0
- package/src/providers/cli-provider-instance.ts +155 -31
- package/src/providers/extension-provider-instance.ts +2 -1
- package/src/providers/ide-provider-instance.ts +2 -2
- package/src/repo-mesh-types.ts +2 -0
- package/src/shared-types.ts +38 -0
|
@@ -195,6 +195,8 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
195
195
|
|
|
196
196
|
// ─── CLI Scripts (script-based parsing) ───
|
|
197
197
|
private cliScripts: CliScripts;
|
|
198
|
+
/** Per-session opaque state object created by cliScripts.createState(), reset on stop. */
|
|
199
|
+
private scriptState: unknown = null;
|
|
198
200
|
private runtimeSettings: Record<string, any> = {};
|
|
199
201
|
/** Full accumulated rendered PTY transcript for parser/readback use */
|
|
200
202
|
private accumulatedBuffer: string = '';
|
|
@@ -223,6 +225,7 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
223
225
|
currentTurnScope: TurnParseScope | null;
|
|
224
226
|
recentOutputBuffer: string;
|
|
225
227
|
accumulatedBuffer: string;
|
|
228
|
+
accumulatedRawBufferKey: string;
|
|
226
229
|
screenText: string;
|
|
227
230
|
currentStatus: CliSessionStatus['status'];
|
|
228
231
|
activeModal: { message: string; buttons: string[] } | null;
|
|
@@ -297,14 +300,23 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
297
300
|
this.lastScreenSnapshotReadAt = Number.NEGATIVE_INFINITY;
|
|
298
301
|
}
|
|
299
302
|
|
|
303
|
+
private getAccumulatedRawBufferCacheKey(): string {
|
|
304
|
+
return this.accumulatedRawBuffer
|
|
305
|
+
.replace(/\x1B\][^\x07]*(?:\x07|\x1B\\)/g, '')
|
|
306
|
+
.replace(/\x1B[P^_X][\s\S]*?(?:\x07|\x1B\\)/g, '')
|
|
307
|
+
.replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, '');
|
|
308
|
+
}
|
|
309
|
+
|
|
300
310
|
private getFreshParsedStatusCache(): any | null {
|
|
301
311
|
const cached = this.parsedStatusCache;
|
|
312
|
+
const accumulatedRawBufferKey = this.getAccumulatedRawBufferCacheKey();
|
|
302
313
|
if (
|
|
303
314
|
cached
|
|
304
315
|
&& cached.responseBuffer === this.responseBuffer
|
|
305
316
|
&& cached.currentTurnScope === this.currentTurnScope
|
|
306
317
|
&& cached.recentOutputBuffer === this.recentOutputBuffer
|
|
307
318
|
&& cached.accumulatedBuffer === this.accumulatedBuffer
|
|
319
|
+
&& cached.accumulatedRawBufferKey === accumulatedRawBufferKey
|
|
308
320
|
&& cached.screenText === this.lastScreenText
|
|
309
321
|
&& cached.currentStatus === this.currentStatus
|
|
310
322
|
&& cached.activeModal === this.activeModal
|
|
@@ -448,6 +460,7 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
448
460
|
|
|
449
461
|
// Scripts are required — loaded by ProviderLoader via compatibility array
|
|
450
462
|
this.cliScripts = provider.scripts || {};
|
|
463
|
+
this.scriptState = typeof this.cliScripts.createState === 'function' ? (this.cliScripts.createState() ?? null) : null;
|
|
451
464
|
const scriptNames = listCliScriptNames(this.cliScripts);
|
|
452
465
|
if (scriptNames.length > 0) {
|
|
453
466
|
LOG.info('CLI', `[${this.cliType}] CLI scripts: [${scriptNames.join(', ')}]`);
|
|
@@ -477,6 +490,9 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
477
490
|
this.cliScripts = scripts;
|
|
478
491
|
this.parsedStatusCache = null;
|
|
479
492
|
this.parseErrorMessage = null;
|
|
493
|
+
// Initialize per-session state: createState() is called once here and on script reload.
|
|
494
|
+
// The returned object lives until the PTY exits (scriptState = null on exit).
|
|
495
|
+
this.scriptState = typeof scripts.createState === 'function' ? (scripts.createState() ?? null) : null;
|
|
480
496
|
const scriptNames = listCliScriptNames(scripts);
|
|
481
497
|
LOG.info('CLI', `[${this.cliType}] CLI scripts injected: [${scriptNames.join(', ')}]`);
|
|
482
498
|
}
|
|
@@ -610,6 +626,7 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
610
626
|
this.ready = false;
|
|
611
627
|
this.startupParseGate = false;
|
|
612
628
|
this.spawnAt = 0;
|
|
629
|
+
this.scriptState = null;
|
|
613
630
|
this.onStatusChange?.();
|
|
614
631
|
});
|
|
615
632
|
|
|
@@ -1450,6 +1467,14 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1450
1467
|
|
|
1451
1468
|
// ─── Script Execution ──────────────────────────
|
|
1452
1469
|
|
|
1470
|
+
private invokeCliScript<T>(script: Function, input: any): T {
|
|
1471
|
+
const hasStateFactory = typeof this.cliScripts?.createState === 'function';
|
|
1472
|
+
const expectsStateArgument = hasStateFactory || this.scriptState !== null || script.length >= 2;
|
|
1473
|
+
return expectsStateArgument
|
|
1474
|
+
? script(this.scriptState, input)
|
|
1475
|
+
: script(input);
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1453
1478
|
private runParseSession(): ParsedSession | null {
|
|
1454
1479
|
if (typeof this.cliScripts?.parseSession !== 'function') {
|
|
1455
1480
|
this.parseErrorMessage = `${this.cliType} parseSession unavailable`;
|
|
@@ -1470,7 +1495,10 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1470
1495
|
scope: this.currentTurnScope,
|
|
1471
1496
|
runtimeSettings: this.runtimeSettings,
|
|
1472
1497
|
});
|
|
1473
|
-
const session = this.
|
|
1498
|
+
const session = this.invokeCliScript<ParsedSession | null>(
|
|
1499
|
+
this.cliScripts.parseSession,
|
|
1500
|
+
{ ...input, tail, tailScreen: buildCliScreenSnapshot(tail) },
|
|
1501
|
+
);
|
|
1474
1502
|
this.parseErrorMessage = null;
|
|
1475
1503
|
return session && typeof session === 'object' ? session : null;
|
|
1476
1504
|
} catch (e: any) {
|
|
@@ -1485,7 +1513,7 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1485
1513
|
if (!this.cliScripts?.detectStatus) return null;
|
|
1486
1514
|
try {
|
|
1487
1515
|
const screenText = this.terminalScreen.getText();
|
|
1488
|
-
const status = this.cliScripts.detectStatus
|
|
1516
|
+
const status = this.invokeCliScript<string | null>(this.cliScripts.detectStatus, {
|
|
1489
1517
|
tail: text.slice(-500),
|
|
1490
1518
|
screenText,
|
|
1491
1519
|
rawBuffer: this.accumulatedRawBuffer,
|
|
@@ -1505,7 +1533,7 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1505
1533
|
try {
|
|
1506
1534
|
const screenText = this.terminalScreen.getText();
|
|
1507
1535
|
const buffer = screenText || this.accumulatedBuffer;
|
|
1508
|
-
return this.cliScripts.parseApproval
|
|
1536
|
+
return this.invokeCliScript<{ message: string; buttons: string[] } | null>(this.cliScripts.parseApproval, {
|
|
1509
1537
|
buffer,
|
|
1510
1538
|
screenText,
|
|
1511
1539
|
rawBuffer: this.accumulatedRawBuffer,
|
|
@@ -1570,12 +1598,14 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1570
1598
|
const screenText = this.readTerminalScreenText();
|
|
1571
1599
|
const parseScreenText = this.getParseScreenText(screenText);
|
|
1572
1600
|
const cached = this.parsedStatusCache;
|
|
1601
|
+
const accumulatedRawBufferKey = this.getAccumulatedRawBufferCacheKey();
|
|
1573
1602
|
if (
|
|
1574
1603
|
cached
|
|
1575
1604
|
&& cached.responseBuffer === this.responseBuffer
|
|
1576
1605
|
&& cached.currentTurnScope === this.currentTurnScope
|
|
1577
1606
|
&& cached.recentOutputBuffer === this.recentOutputBuffer
|
|
1578
1607
|
&& cached.accumulatedBuffer === this.accumulatedBuffer
|
|
1608
|
+
&& cached.accumulatedRawBufferKey === accumulatedRawBufferKey
|
|
1579
1609
|
&& cached.screenText === parseScreenText
|
|
1580
1610
|
&& cached.currentStatus === this.currentStatus
|
|
1581
1611
|
&& cached.activeModal === this.activeModal
|
|
@@ -1615,6 +1645,7 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1615
1645
|
currentTurnScope: this.currentTurnScope,
|
|
1616
1646
|
recentOutputBuffer: this.recentOutputBuffer,
|
|
1617
1647
|
accumulatedBuffer: this.accumulatedBuffer,
|
|
1648
|
+
accumulatedRawBufferKey,
|
|
1618
1649
|
screenText: parseScreenText,
|
|
1619
1650
|
currentStatus: this.currentStatus,
|
|
1620
1651
|
activeModal: this.activeModal,
|
|
@@ -1640,7 +1671,7 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1640
1671
|
scope: this.currentTurnScope,
|
|
1641
1672
|
runtimeSettings: this.runtimeSettings,
|
|
1642
1673
|
});
|
|
1643
|
-
return await Promise.resolve(fn
|
|
1674
|
+
return await Promise.resolve(this.invokeCliScript(fn, {
|
|
1644
1675
|
...input,
|
|
1645
1676
|
args: args && typeof args === 'object' ? { ...args } : {},
|
|
1646
1677
|
}));
|
|
@@ -48,11 +48,21 @@ export interface ParsedSession {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
export interface CliScripts {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
/**
|
|
52
|
+
* Optional state factory. Called once per CLI session start (or script reload).
|
|
53
|
+
* The returned object is passed as the first argument to detectStatus, parseApproval,
|
|
54
|
+
* and parseSession on every invocation, allowing scripts to maintain per-session state
|
|
55
|
+
* (e.g. last-seen status, approval fingerprints, stability counters).
|
|
56
|
+
*
|
|
57
|
+
* Scripts that don't define createState() receive null as the state argument,
|
|
58
|
+
* making this change fully backward compatible.
|
|
59
|
+
*/
|
|
60
|
+
createState?: () => unknown;
|
|
61
|
+
parseSession?: (state: unknown, input: CliScriptInput & { tail?: string; tailScreen?: CliScreenSnapshot }) => ParsedSession | null;
|
|
62
|
+
detectStatus?: (state: unknown, input: CliStatusInput) => string | null;
|
|
63
|
+
parseApproval?: (state: unknown, input: CliApprovalInput) => { message: string; buttons: string[] } | null;
|
|
54
64
|
resolveAction?: (data: any) => string;
|
|
55
|
-
[name: string]: ((input: any) => any) | undefined;
|
|
65
|
+
[name: string]: ((state: unknown, input: any) => any) | ((data: any) => any) | (() => unknown) | undefined;
|
|
56
66
|
}
|
|
57
67
|
|
|
58
68
|
export interface CliScreenLine {
|
|
@@ -177,10 +177,6 @@ export function buildCoordinatorDelegatedCliLaunchOptions(
|
|
|
177
177
|
const cliArgs = Array.isArray(input.cliArgs) ? [...input.cliArgs] : [];
|
|
178
178
|
const env: Record<string, string> = { ...(input.env || {}), ...COORDINATOR_DELEGATED_ENV_UNSETS };
|
|
179
179
|
|
|
180
|
-
if (cliType === 'hermes-cli' && !hasCliArg(cliArgs, '--ignore-user-config')) {
|
|
181
|
-
cliArgs.unshift('--ignore-user-config');
|
|
182
|
-
}
|
|
183
|
-
|
|
184
180
|
if (cliType === 'claude-cli' && !hasCliArg(cliArgs, '--mcp-config')) {
|
|
185
181
|
cliArgs.unshift('--mcp-config', ensureEmptyDelegatedMcpConfig(input.workspace));
|
|
186
182
|
}
|
|
@@ -28,6 +28,15 @@ export type MeshCoordinatorSetup =
|
|
|
28
28
|
instructions: string
|
|
29
29
|
template: string
|
|
30
30
|
}
|
|
31
|
+
| {
|
|
32
|
+
/** Provider registers MCP via its own CLI command (e.g. `codex mcp add` / `gemini mcp add`). */
|
|
33
|
+
kind: 'cli_command'
|
|
34
|
+
serverName: string
|
|
35
|
+
/** The rendered shell command to execute before launching the coordinator session. */
|
|
36
|
+
command: string
|
|
37
|
+
requiresRestart: boolean
|
|
38
|
+
instructions: string
|
|
39
|
+
}
|
|
31
40
|
| {
|
|
32
41
|
kind: 'unsupported'
|
|
33
42
|
reason: string
|
|
@@ -41,6 +50,8 @@ export interface ResolveMeshCoordinatorSetupOptions {
|
|
|
41
50
|
adhdevMcpCommand?: string
|
|
42
51
|
adhdevMcpEntryPath?: string
|
|
43
52
|
nodeExecutable?: string
|
|
53
|
+
adhdevMcpTransport?: 'local' | 'ipc'
|
|
54
|
+
adhdevMcpPort?: number
|
|
44
55
|
}
|
|
45
56
|
|
|
46
57
|
const DEFAULT_SERVER_NAME = 'adhdev-mesh'
|
|
@@ -58,6 +69,8 @@ function resolveHermesMeshCoordinatorSetup(options: ResolveMeshCoordinatorSetupO
|
|
|
58
69
|
meshId: options.meshId,
|
|
59
70
|
nodeExecutable: options.nodeExecutable,
|
|
60
71
|
adhdevMcpEntryPath: options.adhdevMcpEntryPath,
|
|
72
|
+
adhdevMcpTransport: options.adhdevMcpTransport,
|
|
73
|
+
adhdevMcpPort: options.adhdevMcpPort,
|
|
61
74
|
})
|
|
62
75
|
if (!mcpServer) {
|
|
63
76
|
return {
|
|
@@ -130,6 +143,8 @@ export function resolveMeshCoordinatorSetup(options: ResolveMeshCoordinatorSetup
|
|
|
130
143
|
meshId,
|
|
131
144
|
nodeExecutable: options.nodeExecutable,
|
|
132
145
|
adhdevMcpEntryPath: options.adhdevMcpEntryPath,
|
|
146
|
+
adhdevMcpTransport: options.adhdevMcpTransport,
|
|
147
|
+
adhdevMcpPort: options.adhdevMcpPort,
|
|
133
148
|
})
|
|
134
149
|
if (!mcpServer) {
|
|
135
150
|
return {
|
|
@@ -152,6 +167,24 @@ export function resolveMeshCoordinatorSetup(options: ResolveMeshCoordinatorSetup
|
|
|
152
167
|
if (!instructions || !template?.trim()) {
|
|
153
168
|
return { kind: 'unsupported', reason: 'Provider manual MCP setup is missing instructions or template' }
|
|
154
169
|
}
|
|
170
|
+
const renderedTemplate = renderMeshCoordinatorTemplate(template, {
|
|
171
|
+
meshId,
|
|
172
|
+
workspace,
|
|
173
|
+
serverName,
|
|
174
|
+
adhdevMcpCommand: options.adhdevMcpCommand || DEFAULT_ADHDEV_MCP_COMMAND,
|
|
175
|
+
})
|
|
176
|
+
// Detect if the template is a runnable CLI command (single line, no YAML/JSON structure).
|
|
177
|
+
// If so, use cli_command kind so the daemon can execute it automatically.
|
|
178
|
+
const isCliCommand = !renderedTemplate.trim().includes('\n') && !renderedTemplate.trim().startsWith('{')
|
|
179
|
+
if (isCliCommand) {
|
|
180
|
+
return {
|
|
181
|
+
kind: 'cli_command',
|
|
182
|
+
serverName,
|
|
183
|
+
command: renderedTemplate.trim(),
|
|
184
|
+
requiresRestart: mcpConfig.requiresRestart === true,
|
|
185
|
+
instructions: instructions,
|
|
186
|
+
}
|
|
187
|
+
}
|
|
155
188
|
return {
|
|
156
189
|
kind: 'manual',
|
|
157
190
|
serverName,
|
|
@@ -159,12 +192,7 @@ export function resolveMeshCoordinatorSetup(options: ResolveMeshCoordinatorSetup
|
|
|
159
192
|
configPathCommand: mcpConfig.configPathCommand,
|
|
160
193
|
requiresRestart: mcpConfig.requiresRestart === true,
|
|
161
194
|
instructions,
|
|
162
|
-
template:
|
|
163
|
-
meshId,
|
|
164
|
-
workspace,
|
|
165
|
-
serverName,
|
|
166
|
-
adhdevMcpCommand: options.adhdevMcpCommand || DEFAULT_ADHDEV_MCP_COMMAND,
|
|
167
|
-
}),
|
|
195
|
+
template: renderedTemplate,
|
|
168
196
|
}
|
|
169
197
|
}
|
|
170
198
|
|
|
@@ -196,17 +224,37 @@ function resolveAdhdevMcpServerLaunch(options: {
|
|
|
196
224
|
meshId: string
|
|
197
225
|
nodeExecutable?: string
|
|
198
226
|
adhdevMcpEntryPath?: string
|
|
227
|
+
adhdevMcpTransport?: 'local' | 'ipc'
|
|
228
|
+
adhdevMcpPort?: number
|
|
199
229
|
}): MeshCoordinatorMcpServerLaunch | null {
|
|
200
230
|
const entryPath = resolveAdhdevMcpEntryPath(options.adhdevMcpEntryPath)
|
|
201
231
|
if (!entryPath) return null
|
|
202
232
|
const nodeExecutable = resolveMcpNodeExecutable(options.nodeExecutable)
|
|
203
233
|
if (!nodeExecutable) return null
|
|
234
|
+
const transport = resolveMcpTransport(options.adhdevMcpTransport)
|
|
235
|
+
const args = [entryPath, '--mode', transport, '--repo-mesh', options.meshId]
|
|
236
|
+
const port = resolveMcpPort(options.adhdevMcpPort)
|
|
237
|
+
if (port !== undefined) args.push('--port', String(port))
|
|
204
238
|
return {
|
|
205
239
|
command: nodeExecutable,
|
|
206
|
-
args
|
|
240
|
+
args,
|
|
207
241
|
}
|
|
208
242
|
}
|
|
209
243
|
|
|
244
|
+
function resolveMcpTransport(explicitTransport?: 'local' | 'ipc'): 'local' | 'ipc' {
|
|
245
|
+
if (explicitTransport === 'local' || explicitTransport === 'ipc') return explicitTransport
|
|
246
|
+
const envTransport = process.env.ADHDEV_COORDINATOR_MCP_TRANSPORT?.trim()
|
|
247
|
+
return envTransport === 'local' ? 'local' : 'ipc'
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function resolveMcpPort(explicitPort?: number): number | undefined {
|
|
251
|
+
if (typeof explicitPort === 'number' && Number.isInteger(explicitPort) && explicitPort > 0) return explicitPort
|
|
252
|
+
const raw = process.env.ADHDEV_COORDINATOR_MCP_PORT?.trim()
|
|
253
|
+
if (!raw) return undefined
|
|
254
|
+
const parsed = Number(raw)
|
|
255
|
+
return Number.isInteger(parsed) && parsed > 0 ? parsed : undefined
|
|
256
|
+
}
|
|
257
|
+
|
|
210
258
|
function resolveMcpNodeExecutable(explicitExecutable?: string): string | null {
|
|
211
259
|
const explicit = explicitExecutable?.trim()
|
|
212
260
|
if (explicit) return explicit
|