@adhdev/daemon-core 0.9.82-rc.2 → 0.9.82-rc.200
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/boot/process-hardening.d.ts +50 -0
- package/dist/chat/source-machine.d.ts +166 -0
- package/dist/chat/source-resolver.d.ts +104 -0
- package/dist/chat/subscription-updates.d.ts +1 -0
- package/dist/cli-adapter-types.d.ts +23 -2
- package/dist/cli-adapters/cli-script-runner.d.ts +117 -0
- package/dist/cli-adapters/cli-state-engine.d.ts +178 -0
- package/dist/cli-adapters/provider-cli-adapter.d.ts +106 -63
- package/dist/cli-adapters/provider-cli-parse.d.ts +4 -0
- package/dist/cli-adapters/provider-cli-shared.d.ts +29 -0
- package/dist/cli-adapters/raw-terminal-io.d.ts +37 -0
- package/dist/commands/cli-manager.d.ts +2 -1
- package/dist/commands/handler.d.ts +110 -0
- package/dist/commands/mesh-coordinator.d.ts +85 -1
- package/dist/commands/router.d.ts +29 -1
- package/dist/config/chat-history.d.ts +9 -0
- package/dist/config/config.d.ts +5 -0
- package/dist/config/mesh-config.d.ts +72 -1
- package/dist/git/git-commands.d.ts +8 -1
- package/dist/git/git-status.d.ts +5 -0
- package/dist/git/git-types.d.ts +12 -0
- package/dist/index.d.ts +39 -10
- package/dist/index.js +29425 -12026
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +25700 -8378
- package/dist/index.mjs.map +1 -1
- package/dist/installer.d.ts +1 -4
- package/dist/ipc/local-ipc-server.d.ts +91 -0
- package/dist/launch.d.ts +1 -1
- package/dist/logging/async-batch-writer.d.ts +10 -0
- package/dist/mesh/contracts.d.ts +164 -0
- package/dist/mesh/coordinator-prompt.d.ts +30 -0
- package/dist/mesh/coordinator-registry.d.ts +59 -0
- package/dist/mesh/mesh-active-work.d.ts +90 -0
- package/dist/mesh/mesh-delivery-policy.d.ts +126 -0
- package/dist/mesh/mesh-events.d.ts +167 -6
- package/dist/mesh/mesh-fast-forward.d.ts +41 -0
- package/dist/mesh/mesh-host-ownership.d.ts +9 -0
- package/dist/mesh/mesh-ledger.d.ts +58 -1
- package/dist/mesh/mesh-refine-status.d.ts +26 -0
- package/dist/mesh/mesh-runtime-store.d.ts +149 -0
- package/dist/mesh/mesh-work-queue.d.ts +55 -6
- package/dist/mesh/preview-freshness.d.ts +18 -0
- package/dist/mesh/refine-config.d.ts +193 -0
- package/dist/mesh/worktree-bootstrap-config.d.ts +113 -0
- package/dist/providers/approval-utils.d.ts +13 -0
- package/dist/providers/chat-message-normalization.d.ts +1 -0
- package/dist/providers/cli-provider-instance.d.ts +39 -3
- package/dist/providers/contracts.d.ts +130 -6
- package/dist/providers/external-sources.d.ts +71 -0
- package/dist/providers/native-history/antigravity-cli-transcript.d.ts +100 -0
- package/dist/providers/native-history/claude-cli-transcript.d.ts +70 -0
- package/dist/providers/native-history/codex-cli-transcript.d.ts +73 -0
- package/dist/providers/native-history/dispatcher.d.ts +27 -0
- package/dist/providers/native-history/hermes-cli-transcript.d.ts +30 -0
- package/dist/providers/native-history/index.d.ts +13 -0
- package/dist/providers/provider-instance-manager.d.ts +12 -0
- package/dist/providers/provider-instance.d.ts +13 -1
- package/dist/providers/provider-loader.d.ts +26 -4
- package/dist/providers/provider-trust.d.ts +31 -0
- package/dist/providers/read-chat-contract.d.ts +29 -0
- package/dist/providers/sdk/v1/builders/acp/detect-status.d.ts +68 -0
- package/dist/providers/sdk/v1/builders/cli/detect-status.d.ts +85 -0
- package/dist/providers/sdk/v1/builders/cli/parse-approval-squash.d.ts +59 -0
- package/dist/providers/sdk/v1/builders/cli/parse-approval.d.ts +65 -0
- package/dist/providers/sdk/v1/builders/cli/parse-session.d.ts +91 -0
- package/dist/providers/sdk/v1/builders/cli/visible-region.d.ts +42 -0
- package/dist/providers/sdk/v1/fixture-tooling/format.d.ts +126 -0
- package/dist/providers/sdk/v1/fixture-tooling/index.d.ts +8 -0
- package/dist/providers/sdk/v1/fixture-tooling/replay.d.ts +38 -0
- package/dist/providers/sdk/v1/index.d.ts +30 -0
- package/dist/providers/sdk/v1/sandbox/README-design.d.ts +193 -0
- package/dist/providers/sdk/v1/sandbox/require-whitelist.d.ts +74 -0
- package/dist/providers/sdk/v1/sandbox/script-runner.d.ts +98 -0
- package/dist/providers/sdk/v1/types/cli/index.d.ts +277 -0
- package/dist/providers/sdk/v1/types/common/index.d.ts +203 -0
- package/dist/providers/sdk/v1/validators/index.d.ts +5 -0
- package/dist/providers/sdk/v1/validators/manifest.d.ts +40 -0
- package/dist/providers/sdk/v1/validators/taint.d.ts +52 -0
- package/dist/providers/spec/adapter.d.ts +60 -0
- package/dist/providers/spec/cli-adapter.d.ts +98 -0
- package/dist/providers/spec/driver.d.ts +190 -0
- package/dist/providers/spec/evaluator.d.ts +55 -0
- package/dist/providers/spec/loader.d.ts +14 -0
- package/dist/providers/spec/native-history-executor.d.ts +41 -0
- package/dist/providers/spec/route.d.ts +4 -0
- package/dist/providers/spec/schema.gen.d.ts +599 -0
- package/dist/providers/spec/types.d.ts +282 -0
- package/dist/providers/transcript-v2.d.ts +176 -0
- package/dist/providers/types/interactive-prompt.d.ts +48 -0
- package/dist/repo-mesh-types.d.ts +230 -1
- package/dist/sessions/registry.d.ts +3 -0
- package/dist/shared-types-extra.d.ts +1 -1
- package/dist/shared-types.d.ts +42 -1
- package/dist/status/normalize.d.ts +1 -1
- package/dist/status/normalize.js +1 -0
- package/dist/status/normalize.js.map +1 -1
- package/dist/status/normalize.mjs +1 -0
- package/dist/status/normalize.mjs.map +1 -1
- package/dist/status/reporter.d.ts +2 -0
- package/dist/status/snapshot.d.ts +1 -0
- package/dist/types.d.ts +5 -0
- package/package.json +7 -2
- package/src/agent-stream/poller.ts +2 -3
- package/src/boot/daemon-lifecycle.ts +22 -10
- package/src/boot/process-hardening.ts +89 -0
- package/src/chat/source-machine.ts +534 -0
- package/src/chat/source-resolver.ts +0 -0
- package/src/chat/subscription-updates.ts +20 -1
- package/src/cli-adapter-types.d.ts +1 -0
- package/src/cli-adapter-types.ts +22 -2
- package/src/cli-adapters/cli-script-runner.ts +421 -0
- package/src/cli-adapters/cli-state-engine.ts +1138 -0
- package/src/cli-adapters/provider-cli-adapter.d.ts +1 -1
- package/src/cli-adapters/provider-cli-adapter.ts +670 -1137
- package/src/cli-adapters/provider-cli-parse.d.ts +1 -0
- package/src/cli-adapters/provider-cli-parse.ts +13 -0
- package/src/cli-adapters/provider-cli-runtime.ts +3 -1
- package/src/cli-adapters/provider-cli-shared.d.ts +2 -0
- package/src/cli-adapters/provider-cli-shared.ts +59 -11
- package/src/cli-adapters/raw-terminal-io.ts +252 -0
- package/src/cli-adapters/terminal-backends/ghostty-vt-backend.ts +17 -1
- package/src/cli-adapters/terminal-backends/xterm-backend.ts +8 -1
- package/src/commands/chat-commands.ts +1787 -60
- package/src/commands/cli-manager.ts +283 -14
- package/src/commands/handler.ts +809 -2
- package/src/commands/mesh-coordinator.ts +331 -122
- package/src/commands/router.ts +3915 -546
- package/src/config/chat-history.ts +95 -24
- package/src/config/config.ts +12 -0
- package/src/config/mesh-config.ts +280 -2
- package/src/config/recent-activity.ts +8 -2
- package/src/daemon/dev-cli-debug.ts +10 -1
- package/src/detection/ide-detector.ts +26 -16
- package/src/git/git-commands.ts +38 -8
- package/src/git/git-status.ts +132 -12
- package/src/git/git-summary.ts +3 -0
- package/src/git/git-types.ts +13 -0
- package/src/git/git-worktree.ts +8 -1
- package/src/index.ts +127 -9
- package/src/installer.d.ts +1 -1
- package/src/installer.ts +8 -6
- package/src/ipc/local-ipc-server.ts +278 -0
- package/src/launch.d.ts +1 -1
- package/src/launch.ts +37 -28
- package/src/logging/async-batch-writer.ts +55 -0
- package/src/logging/logger.ts +2 -1
- package/src/mesh/contracts.ts +329 -0
- package/src/mesh/coordinator-prompt.ts +204 -30
- package/src/mesh/coordinator-registry.ts +121 -0
- package/src/mesh/mesh-active-work.ts +437 -0
- package/src/mesh/mesh-delivery-policy.ts +298 -0
- package/src/mesh/mesh-events.ts +1352 -109
- package/src/mesh/mesh-fast-forward.ts +438 -0
- package/src/mesh/mesh-host-ownership.ts +73 -0
- package/src/mesh/mesh-ledger.ts +457 -104
- package/src/mesh/mesh-refine-status.ts +144 -0
- package/src/mesh/mesh-runtime-store.ts +769 -0
- package/src/mesh/mesh-work-queue.ts +267 -159
- package/src/mesh/preview-freshness.ts +118 -0
- package/src/mesh/refine-config.ts +366 -0
- package/src/mesh/worktree-bootstrap-config.ts +247 -0
- package/src/providers/approval-utils.d.ts +4 -0
- package/src/providers/approval-utils.ts +47 -5
- package/src/providers/chat-message-normalization.ts +7 -12
- package/src/providers/cli-provider-instance.ts +806 -64
- package/src/providers/contracts.d.ts +55 -0
- package/src/providers/contracts.ts +141 -6
- package/src/providers/external-sources.ts +218 -0
- package/src/providers/ide-provider-instance.ts +19 -5
- package/src/providers/native-history/antigravity-cli-transcript.ts +643 -0
- package/src/providers/native-history/claude-cli-transcript.ts +396 -0
- package/src/providers/native-history/codex-cli-transcript.ts +419 -0
- package/src/providers/native-history/dispatcher.ts +340 -0
- package/src/providers/native-history/hermes-cli-transcript.ts +230 -0
- package/src/providers/native-history/index.ts +30 -0
- package/src/providers/provider-instance-manager.ts +30 -0
- package/src/providers/provider-instance.ts +10 -1
- package/src/providers/provider-loader.ts +582 -50
- package/src/providers/provider-schema.ts +87 -14
- package/src/providers/provider-trust.ts +114 -0
- package/src/providers/read-chat-contract.ts +76 -16
- package/src/providers/sdk/README.md +49 -0
- package/src/providers/sdk/v1/builders/acp/detect-status.ts +144 -0
- package/src/providers/sdk/v1/builders/cli/detect-status.ts +262 -0
- package/src/providers/sdk/v1/builders/cli/parse-approval-squash.ts +158 -0
- package/src/providers/sdk/v1/builders/cli/parse-approval.ts +250 -0
- package/src/providers/sdk/v1/builders/cli/parse-session.ts +276 -0
- package/src/providers/sdk/v1/builders/cli/visible-region.ts +143 -0
- package/src/providers/sdk/v1/fixture-tooling/format.ts +130 -0
- package/src/providers/sdk/v1/fixture-tooling/index.ts +22 -0
- package/src/providers/sdk/v1/fixture-tooling/replay.ts +352 -0
- package/src/providers/sdk/v1/index.ts +152 -0
- package/src/providers/sdk/v1/sandbox/README-design.ts +195 -0
- package/src/providers/sdk/v1/sandbox/require-whitelist.ts +472 -0
- package/src/providers/sdk/v1/sandbox/script-runner.ts +150 -0
- package/src/providers/sdk/v1/schemas/cli/provider.schema.json +504 -0
- package/src/providers/sdk/v1/schemas/primitives/acp-session-protocol-v1.json +131 -0
- package/src/providers/sdk/v1/schemas/primitives/native-history-codex-rollout-v1.json +66 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-approval-squash-v1.json +91 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-assistant-block-v1.json +91 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-cue-ordering-v1.json +47 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-dispatch-order-v1.json +32 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-footer-chrome-v1.json +42 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-index-finder-v1.json +27 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-modal-v1.json +125 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-prompt-marker-v1.json +45 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-session-id-extraction-v1.json +46 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-settled-prompt-v1.json +71 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-spinner-v1.json +83 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-transcript-pty-v1.json +83 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-visible-region-v1.json +57 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-welcome-screen-v1.json +35 -0
- package/src/providers/sdk/v1/types/cli/index.ts +365 -0
- package/src/providers/sdk/v1/types/common/index.ts +229 -0
- package/src/providers/sdk/v1/validators/index.ts +19 -0
- package/src/providers/sdk/v1/validators/manifest.ts +110 -0
- package/src/providers/sdk/v1/validators/taint.ts +309 -0
- package/src/providers/spec/adapter.ts +176 -0
- package/src/providers/spec/cli-adapter.ts +538 -0
- package/src/providers/spec/driver.ts +725 -0
- package/src/providers/spec/evaluator.ts +373 -0
- package/src/providers/spec/loader.ts +130 -0
- package/src/providers/spec/native-history-executor.ts +939 -0
- package/src/providers/spec/route.ts +51 -0
- package/src/providers/spec/schema.gen.ts +559 -0
- package/src/providers/spec/schema.json +237 -0
- package/src/providers/spec/types.ts +301 -0
- package/src/providers/transcript-v2.ts +567 -0
- package/src/providers/types/interactive-prompt.ts +425 -0
- package/src/providers/version-archive.ts +38 -20
- package/src/repo-mesh-types.ts +250 -1
- package/src/sessions/registry.ts +3 -0
- package/src/shared-types-extra.ts +1 -1
- package/src/shared-types.ts +45 -1
- package/src/status/builders.ts +24 -6
- package/src/status/normalize.ts +2 -0
- package/src/status/reporter.ts +15 -0
- package/src/status/snapshot.ts +84 -25
- package/src/system/host-memory.ts +29 -12
- package/src/types.ts +5 -0
- package/dist/mesh/mesh-sync.d.ts +0 -53
- package/src/mesh/mesh-sync.ts +0 -111
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import { execFileSync } from 'node:child_process'
|
|
2
1
|
import { createHash } from 'node:crypto'
|
|
3
|
-
import { existsSync,
|
|
4
|
-
import { createRequire } from 'node:module'
|
|
2
|
+
import { existsSync, readFileSync, writeFileSync } from 'node:fs'
|
|
5
3
|
import * as os from 'node:os'
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
4
|
+
import { basename, isAbsolute, join, resolve } from 'node:path'
|
|
5
|
+
import { LOG } from '../logging/logger.js'
|
|
6
|
+
import type {
|
|
7
|
+
MeshCoordinatorMcpConfigFormat,
|
|
8
|
+
MeshCoordinatorSystemPromptInjection,
|
|
9
|
+
ProviderModule,
|
|
10
|
+
} from '../providers/contracts.js'
|
|
8
11
|
|
|
9
12
|
export interface MeshCoordinatorMcpServerLaunch {
|
|
10
13
|
command: string
|
|
@@ -36,6 +39,7 @@ export type MeshCoordinatorSetup =
|
|
|
36
39
|
command: string
|
|
37
40
|
requiresRestart: boolean
|
|
38
41
|
instructions: string
|
|
42
|
+
mcpServer: MeshCoordinatorMcpServerLaunch
|
|
39
43
|
}
|
|
40
44
|
| {
|
|
41
45
|
kind: 'unsupported'
|
|
@@ -55,7 +59,7 @@ export interface ResolveMeshCoordinatorSetupOptions {
|
|
|
55
59
|
}
|
|
56
60
|
|
|
57
61
|
const DEFAULT_SERVER_NAME = 'adhdev-mesh'
|
|
58
|
-
const DEFAULT_ADHDEV_MCP_COMMAND = 'adhdev
|
|
62
|
+
const DEFAULT_ADHDEV_MCP_COMMAND = 'adhdev'
|
|
59
63
|
const HERMES_CLI_TYPE = 'hermes-cli'
|
|
60
64
|
const HERMES_MCP_CONFIG_PATH = '~/.hermes/config.yaml'
|
|
61
65
|
|
|
@@ -67,8 +71,9 @@ function isHermesProvider(provider: ProviderModule | null | undefined, cliType?:
|
|
|
67
71
|
function resolveHermesMeshCoordinatorSetup(options: ResolveMeshCoordinatorSetupOptions): MeshCoordinatorSetup {
|
|
68
72
|
const mcpServer = resolveAdhdevMcpServerLaunch({
|
|
69
73
|
meshId: options.meshId,
|
|
70
|
-
|
|
74
|
+
adhdevMcpCommand: options.adhdevMcpCommand,
|
|
71
75
|
adhdevMcpEntryPath: options.adhdevMcpEntryPath,
|
|
76
|
+
nodeExecutable: options.nodeExecutable,
|
|
72
77
|
adhdevMcpTransport: options.adhdevMcpTransport,
|
|
73
78
|
adhdevMcpPort: options.adhdevMcpPort,
|
|
74
79
|
})
|
|
@@ -100,7 +105,7 @@ export function createHermesManualMeshCoordinatorSetup(meshId: string, workspace
|
|
|
100
105
|
requiresRestart: true,
|
|
101
106
|
instructions: 'Hermes CLI does not auto-import repo-local .mcp.json. Add this MCP server to Hermes config under mcp_servers, then start a fresh Hermes session.',
|
|
102
107
|
template: renderMeshCoordinatorTemplate(
|
|
103
|
-
'mcp_servers:\n {{serverName}}:\n command: {{adhdevMcpCommand}}\n args:\n - --repo-mesh\n - {{meshId}}\n enabled: true\n',
|
|
108
|
+
'mcp_servers:\n {{serverName}}:\n command: {{adhdevMcpCommand}}\n args:\n - mcp\n - --mode\n - ipc\n - --repo-mesh\n - {{meshId}}\n enabled: true\n',
|
|
104
109
|
{
|
|
105
110
|
meshId,
|
|
106
111
|
workspace,
|
|
@@ -141,8 +146,9 @@ export function resolveMeshCoordinatorSetup(options: ResolveMeshCoordinatorSetup
|
|
|
141
146
|
}
|
|
142
147
|
const mcpServer = resolveAdhdevMcpServerLaunch({
|
|
143
148
|
meshId,
|
|
144
|
-
|
|
149
|
+
adhdevMcpCommand: options.adhdevMcpCommand,
|
|
145
150
|
adhdevMcpEntryPath: options.adhdevMcpEntryPath,
|
|
151
|
+
nodeExecutable: options.nodeExecutable,
|
|
146
152
|
adhdevMcpTransport: options.adhdevMcpTransport,
|
|
147
153
|
adhdevMcpPort: options.adhdevMcpPort,
|
|
148
154
|
})
|
|
@@ -167,22 +173,41 @@ export function resolveMeshCoordinatorSetup(options: ResolveMeshCoordinatorSetup
|
|
|
167
173
|
if (!instructions || !template?.trim()) {
|
|
168
174
|
return { kind: 'unsupported', reason: 'Provider manual MCP setup is missing instructions or template' }
|
|
169
175
|
}
|
|
170
|
-
const
|
|
176
|
+
const mcpServer = resolveAdhdevMcpServerLaunch({
|
|
177
|
+
meshId,
|
|
178
|
+
adhdevMcpCommand: options.adhdevMcpCommand,
|
|
179
|
+
adhdevMcpEntryPath: options.adhdevMcpEntryPath,
|
|
180
|
+
nodeExecutable: options.nodeExecutable,
|
|
181
|
+
adhdevMcpTransport: options.adhdevMcpTransport,
|
|
182
|
+
adhdevMcpPort: options.adhdevMcpPort,
|
|
183
|
+
})
|
|
184
|
+
if (!mcpServer) {
|
|
185
|
+
return {
|
|
186
|
+
kind: 'unsupported',
|
|
187
|
+
reason: 'Could not resolve the ADHDev MCP server entrypoint and transport arguments',
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
let renderedTemplate = renderMeshCoordinatorTemplate(template, {
|
|
171
191
|
meshId,
|
|
172
192
|
workspace,
|
|
173
193
|
serverName,
|
|
174
|
-
adhdevMcpCommand:
|
|
194
|
+
adhdevMcpCommand: mcpServer.command,
|
|
195
|
+
adhdevMcpArgs: mcpServer.args.join(' '),
|
|
175
196
|
})
|
|
176
197
|
// Detect if the template is a runnable CLI command (single line, no YAML/JSON structure).
|
|
177
198
|
// If so, use cli_command kind so the daemon can execute it automatically.
|
|
178
199
|
const isCliCommand = !renderedTemplate.trim().includes('\n') && !renderedTemplate.trim().startsWith('{')
|
|
179
200
|
if (isCliCommand) {
|
|
201
|
+
if (!/\{\{\s*adhdevMcpArgs\s*\}\}/.test(template)) {
|
|
202
|
+
renderedTemplate = replaceLegacyCliCommandMcpArgs(renderedTemplate, mcpServer.args)
|
|
203
|
+
}
|
|
180
204
|
return {
|
|
181
205
|
kind: 'cli_command',
|
|
182
206
|
serverName,
|
|
183
207
|
command: renderedTemplate.trim(),
|
|
184
208
|
requiresRestart: mcpConfig.requiresRestart === true,
|
|
185
209
|
instructions: instructions,
|
|
210
|
+
mcpServer,
|
|
186
211
|
}
|
|
187
212
|
}
|
|
188
213
|
return {
|
|
@@ -203,7 +228,14 @@ export function resolveMeshCoordinatorSetup(options: ResolveMeshCoordinatorSetup
|
|
|
203
228
|
}
|
|
204
229
|
|
|
205
230
|
function renderMeshCoordinatorTemplate(template: string, values: Record<string, string>): string {
|
|
206
|
-
return template.replace(/\{\{\s*(meshId|workspace|serverName|adhdevMcpCommand)\s*\}\}/g, (_, key: string) => values[key] || '')
|
|
231
|
+
return template.replace(/\{\{\s*(meshId|workspace|serverName|adhdevMcpCommand|adhdevMcpArgs)\s*\}\}/g, (_, key: string) => values[key] || '')
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function replaceLegacyCliCommandMcpArgs(command: string, args: string[]): string {
|
|
235
|
+
return command.replace(
|
|
236
|
+
/\bmcp\s+--mode\s+(?:ipc|local)\s+--repo-mesh\s+\S+(?:\s+--port\s+\d+)?\s*$/,
|
|
237
|
+
args.join(' '),
|
|
238
|
+
)
|
|
207
239
|
}
|
|
208
240
|
|
|
209
241
|
function resolveHermesCoordinatorHome(meshId: string, workspace: string): string {
|
|
@@ -222,25 +254,53 @@ function resolveMcpConfigPath(configPath: string, workspace: string): string {
|
|
|
222
254
|
|
|
223
255
|
function resolveAdhdevMcpServerLaunch(options: {
|
|
224
256
|
meshId: string
|
|
225
|
-
|
|
257
|
+
adhdevMcpCommand?: string
|
|
226
258
|
adhdevMcpEntryPath?: string
|
|
259
|
+
nodeExecutable?: string
|
|
227
260
|
adhdevMcpTransport?: 'local' | 'ipc'
|
|
228
261
|
adhdevMcpPort?: number
|
|
229
262
|
}): MeshCoordinatorMcpServerLaunch | null {
|
|
230
|
-
const
|
|
231
|
-
if (
|
|
232
|
-
|
|
233
|
-
|
|
263
|
+
const directEntryPath = resolveAdhdevMcpEntryPath(options.adhdevMcpEntryPath)
|
|
264
|
+
if (directEntryPath) {
|
|
265
|
+
const transport = resolveMcpTransport(options.adhdevMcpTransport)
|
|
266
|
+
const args = [directEntryPath, '--mode', transport, '--repo-mesh', options.meshId]
|
|
267
|
+
const port = resolveMcpPort(options.adhdevMcpPort)
|
|
268
|
+
if (port !== undefined) args.push('--port', String(port))
|
|
269
|
+
return {
|
|
270
|
+
command: resolveNodeExecutable(options.nodeExecutable),
|
|
271
|
+
args,
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const command = resolveAdhdevCommand(options.adhdevMcpCommand)
|
|
234
276
|
const transport = resolveMcpTransport(options.adhdevMcpTransport)
|
|
235
|
-
const
|
|
277
|
+
const directMcpEntrypoint = basename(command).startsWith('adhdev-mcp')
|
|
278
|
+
|| command.includes('/vendor/mcp-server/')
|
|
279
|
+
|| command.includes('\\vendor\\mcp-server\\')
|
|
280
|
+
const args = [...(directMcpEntrypoint ? [] : ['mcp']), '--mode', transport, '--repo-mesh', options.meshId]
|
|
236
281
|
const port = resolveMcpPort(options.adhdevMcpPort)
|
|
237
282
|
if (port !== undefined) args.push('--port', String(port))
|
|
238
283
|
return {
|
|
239
|
-
command
|
|
284
|
+
command,
|
|
240
285
|
args,
|
|
241
286
|
}
|
|
242
287
|
}
|
|
243
288
|
|
|
289
|
+
function resolveAdhdevCommand(explicitCommand?: string): string {
|
|
290
|
+
return explicitCommand?.trim() || process.env.ADHDEV_COORDINATOR_MCP_COMMAND?.trim() || DEFAULT_ADHDEV_MCP_COMMAND
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
function resolveAdhdevMcpEntryPath(explicitEntryPath?: string): string | null {
|
|
294
|
+
const entryPath = explicitEntryPath?.trim() || process.env.ADHDEV_COORDINATOR_MCP_ENTRY_PATH?.trim()
|
|
295
|
+
return entryPath || null
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
function resolveNodeExecutable(explicitNodeExecutable?: string): string {
|
|
299
|
+
return explicitNodeExecutable?.trim()
|
|
300
|
+
|| process.env.ADHDEV_COORDINATOR_NODE_EXECUTABLE?.trim()
|
|
301
|
+
|| process.execPath
|
|
302
|
+
}
|
|
303
|
+
|
|
244
304
|
function resolveMcpTransport(explicitTransport?: 'local' | 'ipc'): 'local' | 'ipc' {
|
|
245
305
|
if (explicitTransport === 'local' || explicitTransport === 'ipc') return explicitTransport
|
|
246
306
|
const envTransport = process.env.ADHDEV_COORDINATOR_MCP_TRANSPORT?.trim()
|
|
@@ -255,127 +315,276 @@ function resolveMcpPort(explicitPort?: number): number | undefined {
|
|
|
255
315
|
return Number.isInteger(parsed) && parsed > 0 ? parsed : undefined
|
|
256
316
|
}
|
|
257
317
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
318
|
+
/**
|
|
319
|
+
* Apply a provider's declared system-prompt injection rule, mutating `cliArgs`
|
|
320
|
+
* and `launchEnv` in place and writing any required workspace context file.
|
|
321
|
+
*
|
|
322
|
+
* Replaces the previous hard-coded `if (cliType === 'claude-cli') ... else if
|
|
323
|
+
* (cliType === 'hermes-cli') ...` branches in router.ts. Adding a new CLI is
|
|
324
|
+
* now provider.v1.json data, not a router edit.
|
|
325
|
+
*
|
|
326
|
+
* Failures are non-fatal: log and continue with whatever was applied so the
|
|
327
|
+
* coordinator session still launches, just without the prompt for that
|
|
328
|
+
* provider. A missing/unknown rule means "skip injection" — safe by default
|
|
329
|
+
* (the previous fallback unconditionally pushed --append-system-prompt onto
|
|
330
|
+
* every non-Claude CLI, which crashed agy on launch).
|
|
331
|
+
*/
|
|
332
|
+
export interface CoordinatorInjectionEffect {
|
|
333
|
+
/** Absolute path the daemon wrote a wrapper-blocked file to. Only set for
|
|
334
|
+
* context_file injection. R48 schedules a strip after launch so workers
|
|
335
|
+
* don't see the wrapper on disk; R47's unregister cleanup uses it as a
|
|
336
|
+
* fallback if the timer never fires (process crash, etc). */
|
|
337
|
+
contextFilePath?: string
|
|
338
|
+
}
|
|
269
339
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
addCandidate('/usr/bin/node')
|
|
278
|
-
addCandidate(process.execPath)
|
|
279
|
-
|
|
280
|
-
for (const candidate of candidates) {
|
|
281
|
-
if (nodeRuntimeSupportsWebSocket(candidate)) return candidate
|
|
282
|
-
}
|
|
283
|
-
return null
|
|
340
|
+
export function applyMeshCoordinatorSystemPromptInjection(
|
|
341
|
+
systemPrompt: string,
|
|
342
|
+
injection: MeshCoordinatorSystemPromptInjection | undefined,
|
|
343
|
+
ctx: { cliArgs: string[]; launchEnv: Record<string, string>; workspace: string; cliType: string },
|
|
344
|
+
): CoordinatorInjectionEffect {
|
|
345
|
+
if (!systemPrompt || !injection) return {}
|
|
346
|
+
return applyInjectionRule(systemPrompt, injection, ctx)
|
|
284
347
|
}
|
|
285
348
|
|
|
286
|
-
function
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
349
|
+
function applyInjectionRule(
|
|
350
|
+
systemPrompt: string,
|
|
351
|
+
injection: MeshCoordinatorSystemPromptInjection,
|
|
352
|
+
ctx: { cliArgs: string[]; launchEnv: Record<string, string>; workspace: string; cliType: string },
|
|
353
|
+
): CoordinatorInjectionEffect {
|
|
354
|
+
switch (injection.mode) {
|
|
355
|
+
case 'cli_arg': {
|
|
356
|
+
if (!injection.flag) return {}
|
|
357
|
+
ctx.cliArgs.push(injection.flag, systemPrompt)
|
|
358
|
+
return {}
|
|
359
|
+
}
|
|
360
|
+
case 'config_override': {
|
|
361
|
+
if (!injection.flag || !injection.template) return {}
|
|
362
|
+
const rendered = injection.template
|
|
363
|
+
.replace(/\{prompt_json\}/g, JSON.stringify(systemPrompt))
|
|
364
|
+
.replace(/\{prompt\}/g, systemPrompt)
|
|
365
|
+
ctx.cliArgs.push(injection.flag, rendered)
|
|
366
|
+
return {}
|
|
367
|
+
}
|
|
368
|
+
case 'env_var': {
|
|
369
|
+
if (!injection.name) return {}
|
|
370
|
+
ctx.launchEnv[injection.name] = systemPrompt
|
|
371
|
+
return {}
|
|
372
|
+
}
|
|
373
|
+
case 'context_file': {
|
|
374
|
+
if (!injection.path) return {}
|
|
375
|
+
const target = isAbsolute(injection.path)
|
|
376
|
+
? injection.path
|
|
377
|
+
: join(ctx.workspace, injection.path)
|
|
378
|
+
const wrapper = injection.wrapper && injection.wrapper.includes('{prompt}')
|
|
379
|
+
? injection.wrapper
|
|
380
|
+
: '{prompt}'
|
|
381
|
+
// Prepend a short managed-by hint inside the wrapper block so a user
|
|
382
|
+
// opening AGENTS.md / GEMINI.md immediately understands the block is
|
|
383
|
+
// auto-regenerated by the daemon on every coordinator launch. The hint
|
|
384
|
+
// sits between the opening sentinel and the prompt body, so the stable
|
|
385
|
+
// sentinels declared in provider.v1.json are untouched and the
|
|
386
|
+
// idempotent replace regex above still matches on relaunches.
|
|
387
|
+
const managedNote =
|
|
388
|
+
'> _Managed by adhdev mesh coordinator — do not hand-edit this block. ' +
|
|
389
|
+
'Changes inside the sentinels are overwritten on next coordinator launch._'
|
|
390
|
+
const promptWithNote = `${managedNote}\n\n${systemPrompt}`
|
|
391
|
+
const rendered = wrapper.replace(/\{prompt\}/g, promptWithNote)
|
|
392
|
+
// If the wrapper has a stable opening sentinel, treat everything up to
|
|
393
|
+
// the matching closing sentinel as our previously-written block and
|
|
394
|
+
// replace it. Otherwise just append. The marker is the first non-
|
|
395
|
+
// placeholder line of the wrapper; this keeps relaunches idempotent
|
|
396
|
+
// without forcing spec authors to declare an explicit marker.
|
|
397
|
+
const sentinel = wrapper.split('{prompt}')[0].trim()
|
|
398
|
+
try {
|
|
399
|
+
if (existsSync(target)) {
|
|
400
|
+
const existing = readFileSync(target, 'utf-8')
|
|
401
|
+
if (sentinel && existing.includes(sentinel)) {
|
|
402
|
+
const closing = wrapper.split('{prompt}')[1]?.trim()
|
|
403
|
+
const safeOpen = sentinel.replace(/[.+^${}()|[\]\\]/g, '\\$&')
|
|
404
|
+
const safeClose = closing
|
|
405
|
+
? closing.replace(/[.+^${}()|[\]\\]/g, '\\$&')
|
|
406
|
+
: ''
|
|
407
|
+
const re = closing
|
|
408
|
+
? new RegExp(`${safeOpen}[\\s\\S]*?${safeClose}`, 'g')
|
|
409
|
+
: new RegExp(`${safeOpen}[\\s\\S]*$`, 'g')
|
|
410
|
+
writeFileSync(target, existing.replace(re, rendered), 'utf-8')
|
|
411
|
+
} else {
|
|
412
|
+
writeFileSync(target, `${existing}\n\n${rendered}`, 'utf-8')
|
|
413
|
+
}
|
|
414
|
+
} else {
|
|
415
|
+
writeFileSync(target, rendered, 'utf-8')
|
|
416
|
+
}
|
|
417
|
+
LOG.info('MeshCoordinator', `Wrote coordinator prompt to ${target} (${ctx.cliType})`)
|
|
418
|
+
return { contextFilePath: target }
|
|
419
|
+
} catch (error: any) {
|
|
420
|
+
LOG.warn('MeshCoordinator', `Could not write ${target}: ${error?.message || error}`)
|
|
421
|
+
return {}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
default:
|
|
425
|
+
// Unknown future mode — skip silently. Adding the new mode is a spec-
|
|
426
|
+
// language extension, not a runtime crash.
|
|
427
|
+
return {}
|
|
291
428
|
}
|
|
292
429
|
}
|
|
293
430
|
|
|
294
|
-
|
|
295
|
-
|
|
431
|
+
/**
|
|
432
|
+
* Strip the daemon's wrapper block from a context_file we previously wrote.
|
|
433
|
+
*
|
|
434
|
+
* Used in two places:
|
|
435
|
+
* 1. R48 inject-then-remove: ~5s after spawn, after agy/gemini have read
|
|
436
|
+
* the file into their in-memory system-prompt cache. Removing it from
|
|
437
|
+
* disk at that point doesn't affect the running coordinator but keeps
|
|
438
|
+
* worker sessions (or fresh non-coordinator launches) in the same
|
|
439
|
+
* workspace from picking up our wrapper.
|
|
440
|
+
* 2. R47 unregister fallback: if the timer never fires (process crash,
|
|
441
|
+
* kill -9), coordinator-registry.unregisterMeshCoordinator runs the
|
|
442
|
+
* same logic when its entry is dropped.
|
|
443
|
+
*
|
|
444
|
+
* Idempotent: missing file is fine, missing sentinels are fine, returns
|
|
445
|
+
* silently. Leaves user-authored content outside the sentinels intact.
|
|
446
|
+
* Deletes the file outright if our wrapper was the only content.
|
|
447
|
+
*/
|
|
448
|
+
export function stripCoordinatorWrapperFile(filePath: string): void {
|
|
449
|
+
const OPEN = '<!-- adhdev-mesh-coordinator-prompt -->'
|
|
450
|
+
const CLOSE = '<!-- /adhdev-mesh-coordinator-prompt -->'
|
|
296
451
|
try {
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
452
|
+
if (!existsSync(filePath)) return
|
|
453
|
+
const existing = readFileSync(filePath, 'utf-8')
|
|
454
|
+
const openIdx = existing.indexOf(OPEN)
|
|
455
|
+
if (openIdx < 0) return
|
|
456
|
+
const closeIdx = existing.indexOf(CLOSE, openIdx)
|
|
457
|
+
if (closeIdx < 0) return
|
|
458
|
+
const remaining = (existing.slice(0, openIdx) + existing.slice(closeIdx + CLOSE.length))
|
|
459
|
+
.replace(/^\s*\n+/, '')
|
|
460
|
+
.replace(/\n+\s*$/, '')
|
|
461
|
+
if (!remaining.trim()) {
|
|
462
|
+
try {
|
|
463
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
464
|
+
const fs = require('node:fs')
|
|
465
|
+
fs.unlinkSync(filePath)
|
|
466
|
+
} catch { /* best-effort */ }
|
|
467
|
+
} else {
|
|
468
|
+
writeFileSync(filePath, remaining + '\n', 'utf-8')
|
|
303
469
|
}
|
|
304
|
-
} catch {
|
|
305
|
-
// nvm is optional; PATH and process.execPath candidates still cover normal installs.
|
|
306
|
-
}
|
|
470
|
+
} catch { /* best-effort */ }
|
|
307
471
|
}
|
|
308
472
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
const diff = (right[i] || 0) - (left[i] || 0)
|
|
315
|
-
if (diff !== 0) return diff
|
|
316
|
-
}
|
|
317
|
-
return b.localeCompare(a)
|
|
473
|
+
export interface PtyExecResult {
|
|
474
|
+
exitCode: number | null
|
|
475
|
+
signal: number | null
|
|
476
|
+
output: string
|
|
477
|
+
timedOut: boolean
|
|
318
478
|
}
|
|
319
479
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
})
|
|
326
|
-
return true
|
|
327
|
-
} catch {
|
|
328
|
-
return false
|
|
329
|
-
}
|
|
480
|
+
export interface MeshCoordinatorRegistrationStep {
|
|
481
|
+
command: string
|
|
482
|
+
args: string[]
|
|
483
|
+
required: boolean
|
|
484
|
+
label: 'remove_existing' | 'register'
|
|
330
485
|
}
|
|
331
486
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
const
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
// Resolve the sibling workspace build directly so Repo Mesh auto-import still
|
|
352
|
-
// writes an absolute Node entrypoint instead of falling back to a PATH bin shim.
|
|
353
|
-
addCandidate(resolve(dir, '../../mcp-server/dist/index.js'))
|
|
354
|
-
addCandidate(resolve(dir, '../../../mcp-server/dist/index.js'))
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
addPackagedCandidates(process.argv[1])
|
|
358
|
-
|
|
359
|
-
for (const candidate of candidates) {
|
|
360
|
-
const normalized = normalizeExistingPath(candidate)
|
|
361
|
-
if (normalized) return normalized
|
|
487
|
+
/**
|
|
488
|
+
* Codex rejects `mcp add` when a server with the same name already exists.
|
|
489
|
+
* Replace that entry before registering so transport/mesh changes do not leave
|
|
490
|
+
* a fresh coordinator attached to stale MCP launch arguments.
|
|
491
|
+
*/
|
|
492
|
+
export function buildMeshCoordinatorRegistrationPlan(
|
|
493
|
+
cliType: string,
|
|
494
|
+
serverName: string,
|
|
495
|
+
registrationCommand: string,
|
|
496
|
+
): MeshCoordinatorRegistrationStep[] {
|
|
497
|
+
const commandParts = registrationCommand.trim().split(/\s+/).filter(Boolean)
|
|
498
|
+
const [command, ...args] = commandParts
|
|
499
|
+
if (!command) return []
|
|
500
|
+
|
|
501
|
+
const register: MeshCoordinatorRegistrationStep = {
|
|
502
|
+
command,
|
|
503
|
+
args,
|
|
504
|
+
required: true,
|
|
505
|
+
label: 'register',
|
|
362
506
|
}
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
507
|
+
if (
|
|
508
|
+
cliType === 'codex-cli'
|
|
509
|
+
&& basename(command) === 'codex'
|
|
510
|
+
&& args[0] === 'mcp'
|
|
511
|
+
&& args[1] === 'add'
|
|
512
|
+
) {
|
|
513
|
+
return [
|
|
514
|
+
{
|
|
515
|
+
command,
|
|
516
|
+
args: ['mcp', 'remove', serverName],
|
|
517
|
+
required: false,
|
|
518
|
+
label: 'remove_existing',
|
|
519
|
+
},
|
|
520
|
+
register,
|
|
521
|
+
]
|
|
371
522
|
}
|
|
523
|
+
return [register]
|
|
372
524
|
}
|
|
373
525
|
|
|
374
|
-
|
|
526
|
+
/**
|
|
527
|
+
* Run a one-shot CLI command under a real PTY and collect its output.
|
|
528
|
+
*
|
|
529
|
+
* Some provider mcp-registration commands (`agy mcp add`, future bubbletea
|
|
530
|
+
* TUIs) refuse to run without `/dev/tty`. Daemon-side `execFileSync` runs
|
|
531
|
+
* pipe-only, so those commands fail with errors like
|
|
532
|
+
* `bubbletea: error opening TTY: open /dev/tty: device not configured`
|
|
533
|
+
* and silently skip the registration, leaving the launched session
|
|
534
|
+
* without the adhdev-mesh MCP tools — which is exactly what we saw with
|
|
535
|
+
* agy coordinators.
|
|
536
|
+
*
|
|
537
|
+
* Wrapping the registration through node-pty gives the child a real PTY,
|
|
538
|
+
* so the bubbletea check passes. We close stdin immediately and just
|
|
539
|
+
* collect stdout until the process exits or the timeout fires.
|
|
540
|
+
*/
|
|
541
|
+
export async function execUnderPty(
|
|
542
|
+
command: string,
|
|
543
|
+
args: string[],
|
|
544
|
+
options: { cwd?: string; env?: Record<string, string>; timeoutMs?: number } = {},
|
|
545
|
+
): Promise<PtyExecResult> {
|
|
546
|
+
let ptyLib: any
|
|
375
547
|
try {
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
} catch {
|
|
379
|
-
|
|
548
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
549
|
+
ptyLib = require('node-pty')
|
|
550
|
+
} catch (error: any) {
|
|
551
|
+
throw new Error(`node-pty is not available: ${error?.message || error}`)
|
|
380
552
|
}
|
|
553
|
+
const env = { ...(options.env ?? (process.env as Record<string, string>)), TERM: 'xterm-256color' }
|
|
554
|
+
const timeoutMs = typeof options.timeoutMs === 'number' && options.timeoutMs > 0 ? options.timeoutMs : 20_000
|
|
555
|
+
return new Promise<PtyExecResult>((resolveResult) => {
|
|
556
|
+
let child: any
|
|
557
|
+
try {
|
|
558
|
+
child = ptyLib.spawn(command, args, {
|
|
559
|
+
name: 'xterm-256color',
|
|
560
|
+
cols: 120,
|
|
561
|
+
rows: 30,
|
|
562
|
+
cwd: options.cwd ?? process.cwd(),
|
|
563
|
+
env,
|
|
564
|
+
})
|
|
565
|
+
} catch (error: any) {
|
|
566
|
+
resolveResult({ exitCode: null, signal: null, output: String(error?.message || error), timedOut: false })
|
|
567
|
+
return
|
|
568
|
+
}
|
|
569
|
+
let buffer = ''
|
|
570
|
+
let settled = false
|
|
571
|
+
const timer = setTimeout(() => {
|
|
572
|
+
if (settled) return
|
|
573
|
+
settled = true
|
|
574
|
+
try { child.kill() } catch { /* ignore */ }
|
|
575
|
+
resolveResult({ exitCode: null, signal: null, output: buffer, timedOut: true })
|
|
576
|
+
}, timeoutMs)
|
|
577
|
+
child.onData((chunk: string) => {
|
|
578
|
+
buffer += chunk
|
|
579
|
+
if (buffer.length > 256 * 1024) {
|
|
580
|
+
buffer = buffer.slice(-128 * 1024)
|
|
581
|
+
}
|
|
582
|
+
})
|
|
583
|
+
child.onExit(({ exitCode, signal }: { exitCode: number; signal?: number }) => {
|
|
584
|
+
if (settled) return
|
|
585
|
+
settled = true
|
|
586
|
+
clearTimeout(timer)
|
|
587
|
+
resolveResult({ exitCode, signal: signal ?? null, output: buffer, timedOut: false })
|
|
588
|
+
})
|
|
589
|
+
})
|
|
381
590
|
}
|