@adhdev/daemon-core 0.9.82-rc.17 → 0.9.82-rc.170
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/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 +22 -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/handler.d.ts +110 -0
- package/dist/commands/mesh-coordinator.d.ts +72 -1
- package/dist/commands/router.d.ts +22 -0
- package/dist/config/chat-history.d.ts +7 -0
- package/dist/config/config.d.ts +5 -0
- package/dist/config/mesh-config.d.ts +71 -1
- package/dist/git/git-commands.d.ts +5 -1
- package/dist/index.d.ts +35 -6
- package/dist/index.js +18621 -3760
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +18525 -3732
- 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/beads-db.d.ts +72 -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-events.d.ts +96 -5
- package/dist/mesh/mesh-fast-forward.d.ts +39 -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-work-queue.d.ts +44 -5
- 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/cli-provider-instance.d.ts +9 -3
- package/dist/providers/contracts.d.ts +98 -5
- 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 +24 -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.d.ts +3 -0
- 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 +169 -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 +56 -0
- package/dist/providers/spec/cli-adapter.d.ts +95 -0
- package/dist/providers/spec/driver.d.ts +149 -0
- package/dist/providers/spec/evaluator.d.ts +47 -0
- package/dist/providers/spec/loader.d.ts +14 -0
- package/dist/providers/spec/native-history-executor.d.ts +39 -0
- package/dist/providers/spec/route.d.ts +4 -0
- package/dist/providers/spec/schema.gen.d.ts +511 -0
- package/dist/providers/spec/types.d.ts +212 -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 +100 -1
- package/dist/sessions/registry.d.ts +3 -0
- package/dist/shared-types.d.ts +42 -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 +17 -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 +14 -1
- package/src/cli-adapter-types.d.ts +1 -0
- package/src/cli-adapter-types.ts +21 -2
- package/src/cli-adapters/cli-script-runner.ts +421 -0
- package/src/cli-adapters/cli-state-engine.ts +1086 -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 +1597 -60
- package/src/commands/cli-manager.ts +214 -3
- package/src/commands/handler.ts +809 -2
- package/src/commands/mesh-coordinator.ts +231 -127
- package/src/commands/router.ts +3559 -502
- package/src/config/chat-history.ts +87 -24
- package/src/config/config.ts +12 -0
- package/src/config/mesh-config.ts +264 -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 +17 -5
- package/src/git/git-worktree.ts +8 -1
- package/src/index.ts +113 -5
- 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/beads-db.ts +479 -0
- 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-events.ts +879 -61
- package/src/mesh/mesh-fast-forward.ts +430 -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-work-queue.ts +216 -158
- 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 +4 -11
- package/src/providers/cli-provider-instance.ts +452 -54
- package/src/providers/contracts.ts +105 -5
- 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 +227 -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.ts +3 -0
- package/src/providers/provider-loader.ts +585 -50
- package/src/providers/provider-schema.ts +31 -13
- 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 +458 -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 +210 -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 +168 -0
- package/src/providers/spec/cli-adapter.ts +430 -0
- package/src/providers/spec/driver.ts +502 -0
- package/src/providers/spec/evaluator.ts +298 -0
- package/src/providers/spec/loader.ts +130 -0
- package/src/providers/spec/native-history-executor.ts +623 -0
- package/src/providers/spec/route.ts +51 -0
- package/src/providers/spec/schema.gen.ts +511 -0
- package/src/providers/spec/schema.json +211 -0
- package/src/providers/spec/types.ts +231 -0
- package/src/providers/transcript-v2.ts +567 -0
- package/src/providers/types/interactive-prompt.ts +297 -0
- package/src/providers/version-archive.ts +38 -20
- package/src/repo-mesh-types.ts +110 -1
- package/src/sessions/registry.ts +3 -0
- package/src/shared-types.ts +45 -1
- package/src/status/builders.ts +24 -6
- 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
|
@@ -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 { 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
|
|
@@ -55,7 +58,7 @@ export interface ResolveMeshCoordinatorSetupOptions {
|
|
|
55
58
|
}
|
|
56
59
|
|
|
57
60
|
const DEFAULT_SERVER_NAME = 'adhdev-mesh'
|
|
58
|
-
const DEFAULT_ADHDEV_MCP_COMMAND = 'adhdev
|
|
61
|
+
const DEFAULT_ADHDEV_MCP_COMMAND = 'adhdev'
|
|
59
62
|
const HERMES_CLI_TYPE = 'hermes-cli'
|
|
60
63
|
const HERMES_MCP_CONFIG_PATH = '~/.hermes/config.yaml'
|
|
61
64
|
|
|
@@ -67,8 +70,7 @@ function isHermesProvider(provider: ProviderModule | null | undefined, cliType?:
|
|
|
67
70
|
function resolveHermesMeshCoordinatorSetup(options: ResolveMeshCoordinatorSetupOptions): MeshCoordinatorSetup {
|
|
68
71
|
const mcpServer = resolveAdhdevMcpServerLaunch({
|
|
69
72
|
meshId: options.meshId,
|
|
70
|
-
|
|
71
|
-
adhdevMcpEntryPath: options.adhdevMcpEntryPath,
|
|
73
|
+
adhdevMcpCommand: options.adhdevMcpCommand,
|
|
72
74
|
adhdevMcpTransport: options.adhdevMcpTransport,
|
|
73
75
|
adhdevMcpPort: options.adhdevMcpPort,
|
|
74
76
|
})
|
|
@@ -100,7 +102,7 @@ export function createHermesManualMeshCoordinatorSetup(meshId: string, workspace
|
|
|
100
102
|
requiresRestart: true,
|
|
101
103
|
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
104
|
template: renderMeshCoordinatorTemplate(
|
|
103
|
-
'mcp_servers:\n {{serverName}}:\n command: {{adhdevMcpCommand}}\n args:\n - --repo-mesh\n - {{meshId}}\n enabled: true\n',
|
|
105
|
+
'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
106
|
{
|
|
105
107
|
meshId,
|
|
106
108
|
workspace,
|
|
@@ -141,8 +143,7 @@ export function resolveMeshCoordinatorSetup(options: ResolveMeshCoordinatorSetup
|
|
|
141
143
|
}
|
|
142
144
|
const mcpServer = resolveAdhdevMcpServerLaunch({
|
|
143
145
|
meshId,
|
|
144
|
-
|
|
145
|
-
adhdevMcpEntryPath: options.adhdevMcpEntryPath,
|
|
146
|
+
adhdevMcpCommand: options.adhdevMcpCommand,
|
|
146
147
|
adhdevMcpTransport: options.adhdevMcpTransport,
|
|
147
148
|
adhdevMcpPort: options.adhdevMcpPort,
|
|
148
149
|
})
|
|
@@ -222,25 +223,25 @@ function resolveMcpConfigPath(configPath: string, workspace: string): string {
|
|
|
222
223
|
|
|
223
224
|
function resolveAdhdevMcpServerLaunch(options: {
|
|
224
225
|
meshId: string
|
|
225
|
-
|
|
226
|
-
adhdevMcpEntryPath?: string
|
|
226
|
+
adhdevMcpCommand?: string
|
|
227
227
|
adhdevMcpTransport?: 'local' | 'ipc'
|
|
228
228
|
adhdevMcpPort?: number
|
|
229
229
|
}): MeshCoordinatorMcpServerLaunch | null {
|
|
230
|
-
const
|
|
231
|
-
if (!entryPath) return null
|
|
232
|
-
const nodeExecutable = resolveMcpNodeExecutable(options.nodeExecutable)
|
|
233
|
-
if (!nodeExecutable) return null
|
|
230
|
+
const command = resolveAdhdevCommand(options.adhdevMcpCommand)
|
|
234
231
|
const transport = resolveMcpTransport(options.adhdevMcpTransport)
|
|
235
|
-
const args = [
|
|
232
|
+
const args = ['mcp', '--mode', transport, '--repo-mesh', options.meshId]
|
|
236
233
|
const port = resolveMcpPort(options.adhdevMcpPort)
|
|
237
234
|
if (port !== undefined) args.push('--port', String(port))
|
|
238
235
|
return {
|
|
239
|
-
command
|
|
236
|
+
command,
|
|
240
237
|
args,
|
|
241
238
|
}
|
|
242
239
|
}
|
|
243
240
|
|
|
241
|
+
function resolveAdhdevCommand(explicitCommand?: string): string {
|
|
242
|
+
return explicitCommand?.trim() || process.env.ADHDEV_COORDINATOR_MCP_COMMAND?.trim() || DEFAULT_ADHDEV_MCP_COMMAND
|
|
243
|
+
}
|
|
244
|
+
|
|
244
245
|
function resolveMcpTransport(explicitTransport?: 'local' | 'ipc'): 'local' | 'ipc' {
|
|
245
246
|
if (explicitTransport === 'local' || explicitTransport === 'ipc') return explicitTransport
|
|
246
247
|
const envTransport = process.env.ADHDEV_COORDINATOR_MCP_TRANSPORT?.trim()
|
|
@@ -255,127 +256,230 @@ function resolveMcpPort(explicitPort?: number): number | undefined {
|
|
|
255
256
|
return Number.isInteger(parsed) && parsed > 0 ? parsed : undefined
|
|
256
257
|
}
|
|
257
258
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
addCandidate(process.execPath)
|
|
279
|
-
|
|
280
|
-
for (const candidate of candidates) {
|
|
281
|
-
if (nodeRuntimeSupportsWebSocket(candidate)) return candidate
|
|
282
|
-
}
|
|
283
|
-
return null
|
|
259
|
+
/**
|
|
260
|
+
* Apply a provider's declared system-prompt injection rule, mutating `cliArgs`
|
|
261
|
+
* and `launchEnv` in place and writing any required workspace context file.
|
|
262
|
+
*
|
|
263
|
+
* Replaces the previous hard-coded `if (cliType === 'claude-cli') ... else if
|
|
264
|
+
* (cliType === 'hermes-cli') ...` branches in router.ts. Adding a new CLI is
|
|
265
|
+
* now provider.v1.json data, not a router edit.
|
|
266
|
+
*
|
|
267
|
+
* Failures are non-fatal: log and continue with whatever was applied so the
|
|
268
|
+
* coordinator session still launches, just without the prompt for that
|
|
269
|
+
* provider. A missing/unknown rule means "skip injection" — safe by default
|
|
270
|
+
* (the previous fallback unconditionally pushed --append-system-prompt onto
|
|
271
|
+
* every non-Claude CLI, which crashed agy on launch).
|
|
272
|
+
*/
|
|
273
|
+
export interface CoordinatorInjectionEffect {
|
|
274
|
+
/** Absolute path the daemon wrote a wrapper-blocked file to. Only set for
|
|
275
|
+
* context_file injection. R48 schedules a strip after launch so workers
|
|
276
|
+
* don't see the wrapper on disk; R47's unregister cleanup uses it as a
|
|
277
|
+
* fallback if the timer never fires (process crash, etc). */
|
|
278
|
+
contextFilePath?: string
|
|
284
279
|
}
|
|
285
280
|
|
|
286
|
-
function
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
}
|
|
281
|
+
export function applyMeshCoordinatorSystemPromptInjection(
|
|
282
|
+
systemPrompt: string,
|
|
283
|
+
injection: MeshCoordinatorSystemPromptInjection | undefined,
|
|
284
|
+
ctx: { cliArgs: string[]; launchEnv: Record<string, string>; workspace: string; cliType: string },
|
|
285
|
+
): CoordinatorInjectionEffect {
|
|
286
|
+
if (!systemPrompt || !injection) return {}
|
|
287
|
+
return applyInjectionRule(systemPrompt, injection, ctx)
|
|
292
288
|
}
|
|
293
289
|
|
|
294
|
-
function
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
290
|
+
function applyInjectionRule(
|
|
291
|
+
systemPrompt: string,
|
|
292
|
+
injection: MeshCoordinatorSystemPromptInjection,
|
|
293
|
+
ctx: { cliArgs: string[]; launchEnv: Record<string, string>; workspace: string; cliType: string },
|
|
294
|
+
): CoordinatorInjectionEffect {
|
|
295
|
+
switch (injection.mode) {
|
|
296
|
+
case 'cli_arg': {
|
|
297
|
+
if (!injection.flag) return {}
|
|
298
|
+
ctx.cliArgs.push(injection.flag, systemPrompt)
|
|
299
|
+
return {}
|
|
303
300
|
}
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
301
|
+
case 'config_override': {
|
|
302
|
+
if (!injection.flag || !injection.template) return {}
|
|
303
|
+
const rendered = injection.template
|
|
304
|
+
.replace(/\{prompt_json\}/g, JSON.stringify(systemPrompt))
|
|
305
|
+
.replace(/\{prompt\}/g, systemPrompt)
|
|
306
|
+
ctx.cliArgs.push(injection.flag, rendered)
|
|
307
|
+
return {}
|
|
308
|
+
}
|
|
309
|
+
case 'env_var': {
|
|
310
|
+
if (!injection.name) return {}
|
|
311
|
+
ctx.launchEnv[injection.name] = systemPrompt
|
|
312
|
+
return {}
|
|
313
|
+
}
|
|
314
|
+
case 'context_file': {
|
|
315
|
+
if (!injection.path) return {}
|
|
316
|
+
const target = isAbsolute(injection.path)
|
|
317
|
+
? injection.path
|
|
318
|
+
: join(ctx.workspace, injection.path)
|
|
319
|
+
const wrapper = injection.wrapper && injection.wrapper.includes('{prompt}')
|
|
320
|
+
? injection.wrapper
|
|
321
|
+
: '{prompt}'
|
|
322
|
+
// Prepend a short managed-by hint inside the wrapper block so a user
|
|
323
|
+
// opening AGENTS.md / GEMINI.md immediately understands the block is
|
|
324
|
+
// auto-regenerated by the daemon on every coordinator launch. The hint
|
|
325
|
+
// sits between the opening sentinel and the prompt body, so the stable
|
|
326
|
+
// sentinels declared in provider.v1.json are untouched and the
|
|
327
|
+
// idempotent replace regex above still matches on relaunches.
|
|
328
|
+
const managedNote =
|
|
329
|
+
'> _Managed by adhdev mesh coordinator — do not hand-edit this block. ' +
|
|
330
|
+
'Changes inside the sentinels are overwritten on next coordinator launch._'
|
|
331
|
+
const promptWithNote = `${managedNote}\n\n${systemPrompt}`
|
|
332
|
+
const rendered = wrapper.replace(/\{prompt\}/g, promptWithNote)
|
|
333
|
+
// If the wrapper has a stable opening sentinel, treat everything up to
|
|
334
|
+
// the matching closing sentinel as our previously-written block and
|
|
335
|
+
// replace it. Otherwise just append. The marker is the first non-
|
|
336
|
+
// placeholder line of the wrapper; this keeps relaunches idempotent
|
|
337
|
+
// without forcing spec authors to declare an explicit marker.
|
|
338
|
+
const sentinel = wrapper.split('{prompt}')[0].trim()
|
|
339
|
+
try {
|
|
340
|
+
if (existsSync(target)) {
|
|
341
|
+
const existing = readFileSync(target, 'utf-8')
|
|
342
|
+
if (sentinel && existing.includes(sentinel)) {
|
|
343
|
+
const closing = wrapper.split('{prompt}')[1]?.trim()
|
|
344
|
+
const safeOpen = sentinel.replace(/[.+^${}()|[\]\\]/g, '\\$&')
|
|
345
|
+
const safeClose = closing
|
|
346
|
+
? closing.replace(/[.+^${}()|[\]\\]/g, '\\$&')
|
|
347
|
+
: ''
|
|
348
|
+
const re = closing
|
|
349
|
+
? new RegExp(`${safeOpen}[\\s\\S]*?${safeClose}`, 'g')
|
|
350
|
+
: new RegExp(`${safeOpen}[\\s\\S]*$`, 'g')
|
|
351
|
+
writeFileSync(target, existing.replace(re, rendered), 'utf-8')
|
|
352
|
+
} else {
|
|
353
|
+
writeFileSync(target, `${existing}\n\n${rendered}`, 'utf-8')
|
|
354
|
+
}
|
|
355
|
+
} else {
|
|
356
|
+
writeFileSync(target, rendered, 'utf-8')
|
|
357
|
+
}
|
|
358
|
+
LOG.info('MeshCoordinator', `Wrote coordinator prompt to ${target} (${ctx.cliType})`)
|
|
359
|
+
return { contextFilePath: target }
|
|
360
|
+
} catch (error: any) {
|
|
361
|
+
LOG.warn('MeshCoordinator', `Could not write ${target}: ${error?.message || error}`)
|
|
362
|
+
return {}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
default:
|
|
366
|
+
// Unknown future mode — skip silently. Adding the new mode is a spec-
|
|
367
|
+
// language extension, not a runtime crash.
|
|
368
|
+
return {}
|
|
316
369
|
}
|
|
317
|
-
return b.localeCompare(a)
|
|
318
370
|
}
|
|
319
371
|
|
|
320
|
-
|
|
372
|
+
/**
|
|
373
|
+
* Strip the daemon's wrapper block from a context_file we previously wrote.
|
|
374
|
+
*
|
|
375
|
+
* Used in two places:
|
|
376
|
+
* 1. R48 inject-then-remove: ~5s after spawn, after agy/gemini have read
|
|
377
|
+
* the file into their in-memory system-prompt cache. Removing it from
|
|
378
|
+
* disk at that point doesn't affect the running coordinator but keeps
|
|
379
|
+
* worker sessions (or fresh non-coordinator launches) in the same
|
|
380
|
+
* workspace from picking up our wrapper.
|
|
381
|
+
* 2. R47 unregister fallback: if the timer never fires (process crash,
|
|
382
|
+
* kill -9), coordinator-registry.unregisterMeshCoordinator runs the
|
|
383
|
+
* same logic when its entry is dropped.
|
|
384
|
+
*
|
|
385
|
+
* Idempotent: missing file is fine, missing sentinels are fine, returns
|
|
386
|
+
* silently. Leaves user-authored content outside the sentinels intact.
|
|
387
|
+
* Deletes the file outright if our wrapper was the only content.
|
|
388
|
+
*/
|
|
389
|
+
export function stripCoordinatorWrapperFile(filePath: string): void {
|
|
390
|
+
const OPEN = '<!-- adhdev-mesh-coordinator-prompt -->'
|
|
391
|
+
const CLOSE = '<!-- /adhdev-mesh-coordinator-prompt -->'
|
|
321
392
|
try {
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
393
|
+
if (!existsSync(filePath)) return
|
|
394
|
+
const existing = readFileSync(filePath, 'utf-8')
|
|
395
|
+
const openIdx = existing.indexOf(OPEN)
|
|
396
|
+
if (openIdx < 0) return
|
|
397
|
+
const closeIdx = existing.indexOf(CLOSE, openIdx)
|
|
398
|
+
if (closeIdx < 0) return
|
|
399
|
+
const remaining = (existing.slice(0, openIdx) + existing.slice(closeIdx + CLOSE.length))
|
|
400
|
+
.replace(/^\s*\n+/, '')
|
|
401
|
+
.replace(/\n+\s*$/, '')
|
|
402
|
+
if (!remaining.trim()) {
|
|
403
|
+
try {
|
|
404
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
405
|
+
const fs = require('node:fs')
|
|
406
|
+
fs.unlinkSync(filePath)
|
|
407
|
+
} catch { /* best-effort */ }
|
|
408
|
+
} else {
|
|
409
|
+
writeFileSync(filePath, remaining + '\n', 'utf-8')
|
|
410
|
+
}
|
|
411
|
+
} catch { /* best-effort */ }
|
|
330
412
|
}
|
|
331
413
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
if (envPath) return normalizeExistingPath(envPath) || envPath
|
|
338
|
-
|
|
339
|
-
const candidates: string[] = []
|
|
340
|
-
const addCandidate = (candidate: string) => {
|
|
341
|
-
if (!candidates.includes(candidate)) candidates.push(candidate)
|
|
342
|
-
}
|
|
343
|
-
const addPackagedCandidates = (baseFile?: string) => {
|
|
344
|
-
if (!baseFile) return
|
|
345
|
-
const realBase = normalizeExistingPath(baseFile) || baseFile
|
|
346
|
-
const dir = dirname(realBase)
|
|
347
|
-
addCandidate(resolve(dir, '../vendor/mcp-server/index.js'))
|
|
348
|
-
addCandidate(resolve(dir, '../../vendor/mcp-server/index.js'))
|
|
349
|
-
addCandidate(resolve(dir, '../../../vendor/mcp-server/index.js'))
|
|
350
|
-
// Source checkout/dev mode does not vendor the MCP server into daemon-standalone.
|
|
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
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
try {
|
|
365
|
-
const requireBase = process.argv[1] ? (normalizeExistingPath(process.argv[1]) || process.argv[1]) : join(process.cwd(), 'adhdev-daemon.js')
|
|
366
|
-
const req = createRequire(requireBase)
|
|
367
|
-
const resolvedModule = req.resolve('@adhdev/mcp-server')
|
|
368
|
-
return normalizeExistingPath(resolvedModule) || resolvedModule
|
|
369
|
-
} catch {
|
|
370
|
-
return null
|
|
371
|
-
}
|
|
414
|
+
export interface PtyExecResult {
|
|
415
|
+
exitCode: number | null
|
|
416
|
+
signal: number | null
|
|
417
|
+
output: string
|
|
418
|
+
timedOut: boolean
|
|
372
419
|
}
|
|
373
420
|
|
|
374
|
-
|
|
421
|
+
/**
|
|
422
|
+
* Run a one-shot CLI command under a real PTY and collect its output.
|
|
423
|
+
*
|
|
424
|
+
* Some provider mcp-registration commands (`agy mcp add`, future bubbletea
|
|
425
|
+
* TUIs) refuse to run without `/dev/tty`. Daemon-side `execFileSync` runs
|
|
426
|
+
* pipe-only, so those commands fail with errors like
|
|
427
|
+
* `bubbletea: error opening TTY: open /dev/tty: device not configured`
|
|
428
|
+
* and silently skip the registration, leaving the launched session
|
|
429
|
+
* without the adhdev-mesh MCP tools — which is exactly what we saw with
|
|
430
|
+
* agy coordinators.
|
|
431
|
+
*
|
|
432
|
+
* Wrapping the registration through node-pty gives the child a real PTY,
|
|
433
|
+
* so the bubbletea check passes. We close stdin immediately and just
|
|
434
|
+
* collect stdout until the process exits or the timeout fires.
|
|
435
|
+
*/
|
|
436
|
+
export async function execUnderPty(
|
|
437
|
+
command: string,
|
|
438
|
+
args: string[],
|
|
439
|
+
options: { cwd?: string; env?: Record<string, string>; timeoutMs?: number } = {},
|
|
440
|
+
): Promise<PtyExecResult> {
|
|
441
|
+
let ptyLib: any
|
|
375
442
|
try {
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
} catch {
|
|
379
|
-
|
|
443
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
444
|
+
ptyLib = require('node-pty')
|
|
445
|
+
} catch (error: any) {
|
|
446
|
+
throw new Error(`node-pty is not available: ${error?.message || error}`)
|
|
380
447
|
}
|
|
448
|
+
const env = { ...(options.env ?? (process.env as Record<string, string>)), TERM: 'xterm-256color' }
|
|
449
|
+
const timeoutMs = typeof options.timeoutMs === 'number' && options.timeoutMs > 0 ? options.timeoutMs : 20_000
|
|
450
|
+
return new Promise<PtyExecResult>((resolveResult) => {
|
|
451
|
+
let child: any
|
|
452
|
+
try {
|
|
453
|
+
child = ptyLib.spawn(command, args, {
|
|
454
|
+
name: 'xterm-256color',
|
|
455
|
+
cols: 120,
|
|
456
|
+
rows: 30,
|
|
457
|
+
cwd: options.cwd ?? process.cwd(),
|
|
458
|
+
env,
|
|
459
|
+
})
|
|
460
|
+
} catch (error: any) {
|
|
461
|
+
resolveResult({ exitCode: null, signal: null, output: String(error?.message || error), timedOut: false })
|
|
462
|
+
return
|
|
463
|
+
}
|
|
464
|
+
let buffer = ''
|
|
465
|
+
let settled = false
|
|
466
|
+
const timer = setTimeout(() => {
|
|
467
|
+
if (settled) return
|
|
468
|
+
settled = true
|
|
469
|
+
try { child.kill() } catch { /* ignore */ }
|
|
470
|
+
resolveResult({ exitCode: null, signal: null, output: buffer, timedOut: true })
|
|
471
|
+
}, timeoutMs)
|
|
472
|
+
child.onData((chunk: string) => {
|
|
473
|
+
buffer += chunk
|
|
474
|
+
if (buffer.length > 256 * 1024) {
|
|
475
|
+
buffer = buffer.slice(-128 * 1024)
|
|
476
|
+
}
|
|
477
|
+
})
|
|
478
|
+
child.onExit(({ exitCode, signal }: { exitCode: number; signal?: number }) => {
|
|
479
|
+
if (settled) return
|
|
480
|
+
settled = true
|
|
481
|
+
clearTimeout(timer)
|
|
482
|
+
resolveResult({ exitCode, signal: signal ?? null, output: buffer, timedOut: false })
|
|
483
|
+
})
|
|
484
|
+
})
|
|
381
485
|
}
|