@adhdev/daemon-core 0.9.82-rc.31 → 0.9.82-rc.311
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 +8 -0
- package/dist/boot/process-hardening.d.ts +50 -0
- package/dist/build-info.d.ts +37 -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 +198 -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 +38 -0
- package/dist/cli-adapters/raw-terminal-io.d.ts +37 -0
- package/dist/cli-adapters/resolve-executable.d.ts +14 -0
- package/dist/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +6 -3
- package/dist/cli-adapters/terminal-backends/types.d.ts +10 -2
- package/dist/cli-adapters/terminal-screen.d.ts +4 -11
- 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 +214 -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 +9 -1
- package/dist/git/git-diff.d.ts +6 -0
- package/dist/git/git-executor.d.ts +11 -0
- package/dist/git/git-status.d.ts +9 -0
- package/dist/git/git-types.d.ts +2 -50
- package/dist/index.d.ts +51 -12
- package/dist/index.js +34705 -11938
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +38412 -15757
- 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 +36 -0
- package/dist/mesh/coordinator-registry.d.ts +59 -0
- package/dist/mesh/mesh-active-work.d.ts +108 -0
- package/dist/mesh/mesh-delivery-policy.d.ts +131 -0
- package/dist/mesh/mesh-events-coordinator.d.ts +169 -0
- package/dist/mesh/mesh-events-pending.d.ts +45 -0
- package/dist/mesh/mesh-events-stale.d.ts +40 -0
- package/dist/mesh/mesh-events-utils.d.ts +47 -0
- package/dist/mesh/mesh-events.d.ts +6 -49
- package/dist/mesh/mesh-fast-forward.d.ts +81 -0
- package/dist/mesh/mesh-host-ownership.d.ts +9 -0
- package/dist/mesh/mesh-init.d.ts +86 -0
- package/dist/mesh/mesh-ledger-reconciliation.d.ts +23 -3
- package/dist/mesh/mesh-ledger.d.ts +77 -1
- package/dist/mesh/mesh-missions.d.ts +116 -0
- package/dist/mesh/mesh-reconcile-loop.d.ts +7 -0
- package/dist/mesh/mesh-refine-batch.d.ts +68 -0
- package/dist/mesh/mesh-refine-status.d.ts +62 -0
- package/dist/mesh/mesh-review-inbox.d.ts +90 -0
- package/dist/mesh/mesh-routing.d.ts +70 -0
- package/dist/mesh/mesh-runtime-store.d.ts +395 -0
- package/dist/mesh/mesh-task-stats.d.ts +49 -0
- package/dist/mesh/mesh-unresolved-forward-outbox.d.ts +30 -0
- package/dist/mesh/mesh-work-queue.d.ts +204 -5
- package/dist/mesh/preview-freshness.d.ts +18 -0
- package/dist/mesh/refine-config.d.ts +215 -0
- package/dist/mesh/worktree-bootstrap-config.d.ts +135 -0
- package/dist/providers/acp-provider-instance.d.ts +2 -0
- package/dist/providers/approval-utils.d.ts +13 -0
- package/dist/providers/cli-provider-instance.d.ts +61 -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 +13 -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 +59 -0
- package/dist/providers/spec/cli-adapter.d.ts +217 -0
- package/dist/providers/spec/evaluator.d.ts +23 -0
- package/dist/providers/spec/fsm-driver.d.ts +278 -0
- package/dist/providers/spec/fsm-evaluator.d.ts +72 -0
- package/dist/providers/spec/fsm-loader.d.ts +14 -0
- package/dist/providers/spec/fsm-types.d.ts +128 -0
- package/dist/providers/spec/native-history-executor.d.ts +41 -0
- package/dist/providers/spec/pre-launch-trust.d.ts +16 -0
- package/dist/providers/spec/route.d.ts +4 -0
- package/dist/providers/spec/types.d.ts +180 -0
- package/dist/providers/transcript-v2.d.ts +176 -0
- package/dist/providers/types/interactive-prompt.d.ts +84 -0
- package/dist/repo-mesh-types.d.ts +291 -13
- package/dist/sessions/registry.d.ts +6 -0
- package/dist/shared-types-extra.d.ts +2 -4
- 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 -3
- package/src/agent-stream/poller.ts +2 -3
- package/src/boot/daemon-lifecycle.ts +55 -12
- package/src/boot/process-hardening.ts +89 -0
- package/src/build-info.ts +73 -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 +1215 -0
- package/src/cli-adapters/provider-cli-adapter.d.ts +1 -1
- package/src/cli-adapters/provider-cli-adapter.ts +674 -1139
- 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 +68 -11
- package/src/cli-adapters/pty-transport.ts +2 -1
- package/src/cli-adapters/raw-terminal-io.ts +252 -0
- package/src/cli-adapters/resolve-executable.ts +45 -0
- package/src/cli-adapters/session-host-transport.ts +2 -1
- package/src/cli-adapters/terminal-backends/ghostty-vt-backend.ts +53 -29
- package/src/cli-adapters/terminal-backends/types.ts +10 -3
- package/src/cli-adapters/terminal-screen.ts +16 -81
- package/src/commands/chat-commands.ts +1822 -61
- package/src/commands/cli-manager.ts +286 -14
- package/src/commands/handler.ts +809 -2
- package/src/commands/mesh-coordinator.ts +332 -122
- package/src/commands/router.ts +6041 -589
- package/src/commands/stream-commands.ts +8 -0
- package/src/commands/upgrade-helper.ts +29 -0
- package/src/config/chat-history.ts +483 -24
- package/src/config/config.ts +12 -0
- package/src/config/mesh-config.ts +320 -4
- package/src/config/recent-activity.ts +8 -2
- package/src/daemon/dev-auto-implement.ts +3 -2
- package/src/daemon/dev-cli-debug.ts +10 -1
- package/src/detection/ide-detector.ts +26 -16
- package/src/git/git-commands.ts +42 -12
- package/src/git/git-diff.ts +53 -0
- package/src/git/git-executor.ts +12 -0
- package/src/git/git-status.ts +302 -18
- package/src/git/git-types.ts +14 -62
- package/src/git/git-worktree.ts +8 -1
- package/src/index.ts +142 -11
- 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 +234 -31
- package/src/mesh/coordinator-registry.ts +121 -0
- package/src/mesh/mesh-active-work.ts +469 -0
- package/src/mesh/mesh-delivery-policy.ts +315 -0
- package/src/mesh/mesh-events-coordinator.ts +1942 -0
- package/src/mesh/mesh-events-pending.ts +508 -0
- package/src/mesh/mesh-events-stale.ts +290 -0
- package/src/mesh/mesh-events-utils.ts +254 -0
- package/src/mesh/mesh-events.ts +30 -1035
- package/src/mesh/mesh-fast-forward.ts +839 -0
- package/src/mesh/mesh-host-ownership.ts +73 -0
- package/src/mesh/mesh-init.ts +260 -0
- package/src/mesh/mesh-ledger-reconciliation.ts +12 -5
- package/src/mesh/mesh-ledger.ts +589 -102
- package/src/mesh/mesh-missions.ts +248 -0
- package/src/mesh/mesh-reconcile-loop.ts +466 -0
- package/src/mesh/mesh-refine-batch.ts +197 -0
- package/src/mesh/mesh-refine-status.ts +231 -0
- package/src/mesh/mesh-review-inbox.ts +307 -0
- package/src/mesh/mesh-routing.ts +291 -0
- package/src/mesh/mesh-runtime-store.ts +1565 -0
- package/src/mesh/mesh-task-stats.ts +154 -0
- package/src/mesh/mesh-unresolved-forward-outbox.ts +185 -0
- package/src/mesh/mesh-work-queue.ts +703 -140
- package/src/mesh/preview-freshness.ts +118 -0
- package/src/mesh/refine-config.ts +403 -0
- package/src/mesh/worktree-bootstrap-config.ts +326 -0
- package/src/providers/acp-provider-instance.ts +15 -1
- 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 +953 -87
- package/src/providers/contracts.d.ts +55 -0
- package/src/providers/contracts.ts +141 -6
- package/src/providers/extension-provider-instance.ts +5 -1
- package/src/providers/external-sources.ts +218 -0
- package/src/providers/ide-provider-instance.ts +25 -6
- 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 +479 -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 +584 -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 +155 -0
- package/src/providers/spec/cli-adapter.ts +980 -0
- package/src/providers/spec/evaluator.ts +345 -0
- package/src/providers/spec/fsm-driver.ts +888 -0
- package/src/providers/spec/fsm-evaluator.ts +255 -0
- package/src/providers/spec/fsm-loader.ts +112 -0
- package/src/providers/spec/fsm-types.ts +222 -0
- package/src/providers/spec/native-history-executor.ts +1035 -0
- package/src/providers/spec/pre-launch-trust.ts +104 -0
- package/src/providers/spec/route.ts +51 -0
- package/src/providers/spec/types.ts +226 -0
- package/src/providers/transcript-v2.ts +567 -0
- package/src/providers/types/interactive-prompt.ts +536 -0
- package/src/providers/version-archive.ts +38 -20
- package/src/repo-mesh-types.ts +376 -13
- package/src/sessions/registry.ts +6 -0
- package/src/shared-types-extra.ts +2 -4
- package/src/shared-types.ts +45 -1
- package/src/status/builders.ts +26 -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/cli-adapters/terminal-backends/xterm-backend.d.ts +0 -17
- package/dist/mesh/mesh-sync.d.ts +0 -53
- package/src/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +0 -16
- package/src/cli-adapters/terminal-backends/xterm-backend.ts +0 -97
- package/src/mesh/mesh-sync.ts +0 -111
|
@@ -15,6 +15,7 @@ export declare function buildCliParseInput(options: {
|
|
|
15
15
|
accumulatedRawBuffer: string;
|
|
16
16
|
recentOutputBuffer: string;
|
|
17
17
|
terminalScreenText: string;
|
|
18
|
+
workingDir?: string;
|
|
18
19
|
baseMessages: CliChatMessage[];
|
|
19
20
|
partialResponse: string;
|
|
20
21
|
isWaitingForResponse?: boolean;
|
|
@@ -35,22 +35,30 @@ export function buildCliParseInput(options: {
|
|
|
35
35
|
accumulatedRawBuffer: string;
|
|
36
36
|
recentOutputBuffer: string;
|
|
37
37
|
terminalScreenText: string;
|
|
38
|
+
workingDir?: string;
|
|
39
|
+
providerSessionId?: string;
|
|
40
|
+
historySessionId?: string;
|
|
38
41
|
baseMessages: CliChatMessage[];
|
|
39
42
|
partialResponse: string;
|
|
40
43
|
isWaitingForResponse?: boolean;
|
|
41
44
|
scope?: TurnParseScope | null;
|
|
42
45
|
runtimeSettings: Record<string, any>;
|
|
46
|
+
spawnAt?: number;
|
|
43
47
|
}): CliScriptInput {
|
|
44
48
|
const {
|
|
45
49
|
accumulatedBuffer,
|
|
46
50
|
accumulatedRawBuffer,
|
|
47
51
|
recentOutputBuffer,
|
|
48
52
|
terminalScreenText,
|
|
53
|
+
workingDir,
|
|
54
|
+
providerSessionId,
|
|
55
|
+
historySessionId,
|
|
49
56
|
baseMessages,
|
|
50
57
|
partialResponse,
|
|
51
58
|
isWaitingForResponse,
|
|
52
59
|
scope,
|
|
53
60
|
runtimeSettings,
|
|
61
|
+
spawnAt,
|
|
54
62
|
} = options;
|
|
55
63
|
const buffer = scope
|
|
56
64
|
? sliceFromOffset(accumulatedBuffer, scope.bufferStart)
|
|
@@ -66,6 +74,10 @@ export function buildCliParseInput(options: {
|
|
|
66
74
|
rawBuffer,
|
|
67
75
|
recentBuffer,
|
|
68
76
|
screenText,
|
|
77
|
+
workspace: workingDir,
|
|
78
|
+
workingDir,
|
|
79
|
+
providerSessionId,
|
|
80
|
+
historySessionId,
|
|
69
81
|
screen: buildCliScreenSnapshot(screenText),
|
|
70
82
|
bufferScreen: buildCliScreenSnapshot(buffer),
|
|
71
83
|
recentScreen: buildCliScreenSnapshot(recentBuffer),
|
|
@@ -74,6 +86,7 @@ export function buildCliParseInput(options: {
|
|
|
74
86
|
isWaitingForResponse,
|
|
75
87
|
promptText: scope?.prompt || '',
|
|
76
88
|
settings: { ...runtimeSettings },
|
|
89
|
+
...(typeof spawnAt === 'number' && spawnAt > 0 ? { spawnAt } : {}),
|
|
77
90
|
};
|
|
78
91
|
}
|
|
79
92
|
|
|
@@ -36,7 +36,9 @@ export function resolveCliSpawnPlan(options: {
|
|
|
36
36
|
: spawnConfig.command;
|
|
37
37
|
const binaryPath = findBinary(configuredCommand);
|
|
38
38
|
const isWin = os.platform() === 'win32';
|
|
39
|
-
const allArgs = [...spawnConfig.args, ...extraArgs]
|
|
39
|
+
const allArgs = [...spawnConfig.args, ...extraArgs].map((arg) =>
|
|
40
|
+
typeof arg === 'string' ? arg.replace(/\{\{workingDir\}\}/g, workingDir) : arg,
|
|
41
|
+
);
|
|
40
42
|
|
|
41
43
|
let shellCmd: string;
|
|
42
44
|
let shellArgs: string[];
|
|
@@ -4,6 +4,7 @@ import { execSync } from 'child_process';
|
|
|
4
4
|
import type { ProviderResumeCapability } from '../providers/contracts.js';
|
|
5
5
|
import type { ChatMessageKind } from '../providers/chat-message-normalization.js';
|
|
6
6
|
import type { ChatBubbleState } from '../types.js';
|
|
7
|
+
import type { InteractivePrompt } from '../providers/types/interactive-prompt.js';
|
|
7
8
|
import { sanitizeSpawnEnv } from './spawn-env.js';
|
|
8
9
|
|
|
9
10
|
export interface CliChatMessage {
|
|
@@ -28,8 +29,27 @@ export interface CliSessionStatus {
|
|
|
28
29
|
messages: CliChatMessage[];
|
|
29
30
|
workingDir: string;
|
|
30
31
|
activeModal: { message: string; buttons: string[] } | null;
|
|
32
|
+
/**
|
|
33
|
+
* Monotonic counter identifying which approval *entry* the current modal
|
|
34
|
+
* belongs to. Bumped by the FSM on every fresh waiting_approval entry.
|
|
35
|
+
* Consumers (e.g. auto-approval) use it to distinguish a genuinely new
|
|
36
|
+
* approval from the same approval re-observed across TUI paint flaps —
|
|
37
|
+
* two distinct approvals can carry identical message/button text, so the
|
|
38
|
+
* seq is the only reliable discriminator.
|
|
39
|
+
*/
|
|
40
|
+
approvalEntrySeq?: number;
|
|
41
|
+
activeInteractivePrompt?: InteractivePrompt | null;
|
|
42
|
+
pendingOutboundCount?: number;
|
|
43
|
+
pendingOutboundMessages?: Array<{
|
|
44
|
+
id: string;
|
|
45
|
+
role: 'user';
|
|
46
|
+
content: string;
|
|
47
|
+
queuedAt: number;
|
|
48
|
+
source: string;
|
|
49
|
+
}>;
|
|
31
50
|
errorMessage?: string;
|
|
32
51
|
errorReason?: string;
|
|
52
|
+
providerSessionId?: string;
|
|
33
53
|
bufferState?: {
|
|
34
54
|
responseBuffer?: { truncated: boolean; droppedChars: number; maxChars: number };
|
|
35
55
|
recentOutputBuffer?: { truncated: boolean; droppedChars: number; maxChars: number };
|
|
@@ -43,6 +63,9 @@ export interface ParsedSession {
|
|
|
43
63
|
messages: any[];
|
|
44
64
|
modal: { message: string; buttons: string[] } | null;
|
|
45
65
|
parsedStatus: string | null;
|
|
66
|
+
errorMessage?: string;
|
|
67
|
+
errorReason?: string;
|
|
68
|
+
providerSessionId?: string;
|
|
46
69
|
transcriptAuthority?: 'provider' | 'daemon';
|
|
47
70
|
coverage?: 'full' | 'tail' | 'current-turn';
|
|
48
71
|
}
|
|
@@ -94,6 +117,10 @@ export interface CliScriptInput {
|
|
|
94
117
|
rawBuffer: string;
|
|
95
118
|
recentBuffer: string;
|
|
96
119
|
screenText: string;
|
|
120
|
+
workspace?: string;
|
|
121
|
+
workingDir?: string;
|
|
122
|
+
providerSessionId?: string;
|
|
123
|
+
historySessionId?: string;
|
|
97
124
|
screen: CliScreenSnapshot;
|
|
98
125
|
bufferScreen: CliScreenSnapshot;
|
|
99
126
|
recentScreen: CliScreenSnapshot;
|
|
@@ -103,6 +130,7 @@ export interface CliScriptInput {
|
|
|
103
130
|
promptText?: string;
|
|
104
131
|
settings?: Record<string, any>;
|
|
105
132
|
args?: Record<string, any>;
|
|
133
|
+
spawnAt?: number;
|
|
106
134
|
}
|
|
107
135
|
|
|
108
136
|
export interface CliStatusInput {
|
|
@@ -141,16 +169,26 @@ export interface CliProviderModule {
|
|
|
141
169
|
binary: string;
|
|
142
170
|
approvalKeys?: Record<number, string>;
|
|
143
171
|
sendDelayMs?: number;
|
|
172
|
+
/** Wall-clock budget (ms) for a single provider script invocation. Default 50. Range 1..5000.
|
|
173
|
+
* Exceeding the budget records `timedOut: true` on the invocation trace and emits a
|
|
174
|
+
* throttled WARN — it does NOT abort the script (Node CJS can't interrupt sync code). */
|
|
175
|
+
scriptCallBudgetMs?: number;
|
|
144
176
|
sendKey?: string;
|
|
145
177
|
submitStrategy?: 'wait_for_echo' | 'immediate';
|
|
146
178
|
/** Require the typed prompt to be visible on the PTY screen before sending Enter. */
|
|
147
179
|
requirePromptEchoBeforeSubmit?: boolean;
|
|
148
180
|
/** Allow sending another prompt while the CLI is still generating so users can intervene mid-turn. */
|
|
149
181
|
allowInputDuringGeneration?: boolean;
|
|
182
|
+
/** When true, only transition to idle after the parsed transcript includes a final standard assistant message. */
|
|
183
|
+
requiresFinalAssistantBeforeIdle?: boolean;
|
|
184
|
+
/** When true, allow providers to augment stale snapshot data before parse. Reserved for future use. */
|
|
185
|
+
augmentStaleSnapshot?: boolean;
|
|
150
186
|
/** When provider-owned, daemon treats provider parser output as canonical transcript authority. */
|
|
151
187
|
transcriptAuthority?: 'provider' | 'daemon';
|
|
152
188
|
/** Full context lets provider-owned parsers canonicalize retained history instead of daemon prefix stitching. */
|
|
153
189
|
transcriptContext?: 'full' | 'tail';
|
|
190
|
+
/** v1 declarative tui block — used by CliScriptRunner to synthesize SDK helpers (declarativeDetectStatus, declarativeParseApproval). */
|
|
191
|
+
tui?: Record<string, unknown>;
|
|
154
192
|
scripts?: CliScripts;
|
|
155
193
|
spawn: {
|
|
156
194
|
command: string;
|
|
@@ -342,7 +380,18 @@ export class TerminalTranscriptAccumulator {
|
|
|
342
380
|
this.ensureRow();
|
|
343
381
|
if (final === 'A') this.row = Math.max(0, this.row - count);
|
|
344
382
|
else if (final === 'B') this.row += count;
|
|
345
|
-
else if (final === 'C')
|
|
383
|
+
else if (final === 'C') {
|
|
384
|
+
// (fix) Cursor-forward must materialize spaces in the cells it
|
|
385
|
+
// skips, otherwise rendered transcripts collapse "Do you" written
|
|
386
|
+
// as "Do\x1b[1Cyou" into "Doyou". That mis-rendering broke
|
|
387
|
+
// Claude Code's approval-prompt and prompt-line detection
|
|
388
|
+
// (parseApproval saw "Doyouwanttoproceed?" and returned null).
|
|
389
|
+
const line = this.lines[this.row];
|
|
390
|
+
for (let c = this.col; c < this.col + count; c += 1) {
|
|
391
|
+
if (line[c] === undefined) line[c] = ' ';
|
|
392
|
+
}
|
|
393
|
+
this.col += count;
|
|
394
|
+
}
|
|
346
395
|
else if (final === 'D') this.col = Math.max(0, this.col - count);
|
|
347
396
|
else if (final === 'G') this.col = Math.max(0, count - 1);
|
|
348
397
|
else if (final === 'H' || final === 'f') {
|
|
@@ -484,17 +533,25 @@ export function findBinary(name: string): string {
|
|
|
484
533
|
return path.isAbsolute(expanded) ? expanded : path.resolve(expanded);
|
|
485
534
|
}
|
|
486
535
|
const isWin = os.platform() === 'win32';
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
536
|
+
const paths = (process.env.PATH || '').split(path.delimiter);
|
|
537
|
+
const exes = isWin ? ['.exe', '.cmd', '.bat', ''] : [''];
|
|
538
|
+
|
|
539
|
+
for (const p of paths) {
|
|
540
|
+
if (!p) continue;
|
|
541
|
+
for (const ext of exes) {
|
|
542
|
+
const fullPath = path.join(p, trimmed + ext);
|
|
543
|
+
try {
|
|
544
|
+
const fs = require('fs');
|
|
545
|
+
if (fs.existsSync(fullPath)) {
|
|
546
|
+
const stat = fs.statSync(fullPath);
|
|
547
|
+
if (stat.isFile() && (isWin || (stat.mode & 0o111))) {
|
|
548
|
+
return fullPath;
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
} catch { }
|
|
552
|
+
}
|
|
497
553
|
}
|
|
554
|
+
return isWin ? `${trimmed}.cmd` : trimmed;
|
|
498
555
|
}
|
|
499
556
|
|
|
500
557
|
export function isScriptBinary(binaryPath: string): boolean {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as os from 'os';
|
|
2
2
|
import { ensureNodePtySpawnHelperPermissions } from './spawn-env.js';
|
|
3
|
+
import { resolveWin32Executable } from './resolve-executable.js';
|
|
3
4
|
|
|
4
5
|
let cachedPty: any | null | undefined;
|
|
5
6
|
|
|
@@ -119,7 +120,7 @@ export class NodePtyTransportFactory implements PtyTransportFactory {
|
|
|
119
120
|
cwd = os.homedir();
|
|
120
121
|
}
|
|
121
122
|
}
|
|
122
|
-
const handle = pty.spawn(command, args, {
|
|
123
|
+
const handle = pty.spawn(resolveWin32Executable(command), args, {
|
|
123
124
|
name: 'xterm-256color',
|
|
124
125
|
cols: options.cols,
|
|
125
126
|
rows: options.rows,
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import { randomUUID } from 'crypto';
|
|
2
|
+
import {
|
|
3
|
+
SessionHostClient,
|
|
4
|
+
type SessionHostEndpoint,
|
|
5
|
+
type SessionHostRequest,
|
|
6
|
+
type SessionHostResponse,
|
|
7
|
+
type SessionTerminalSnapshot,
|
|
8
|
+
type SessionTerminalState,
|
|
9
|
+
} from '@adhdev/session-host-core';
|
|
10
|
+
|
|
11
|
+
type LowercaseLetter =
|
|
12
|
+
| 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm'
|
|
13
|
+
| 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z';
|
|
14
|
+
|
|
15
|
+
type FunctionKey = 'f1' | 'f2' | 'f3' | 'f4' | 'f5' | 'f6' | 'f7' | 'f8' | 'f9' | 'f10' | 'f11' | 'f12';
|
|
16
|
+
type BaseNamedKey =
|
|
17
|
+
| 'enter' | 'escape' | 'tab' | 'backspace'
|
|
18
|
+
| 'up' | 'down' | 'left' | 'right'
|
|
19
|
+
| 'home' | 'end' | 'pageup' | 'pagedown' | 'space'
|
|
20
|
+
| FunctionKey;
|
|
21
|
+
type ShiftNamedKey = BaseNamedKey | LowercaseLetter | `ctrl+${LowercaseLetter}` | `alt+${LowercaseLetter}`;
|
|
22
|
+
|
|
23
|
+
export type NamedKey =
|
|
24
|
+
| BaseNamedKey
|
|
25
|
+
| `ctrl+${LowercaseLetter}`
|
|
26
|
+
| `alt+${LowercaseLetter}`
|
|
27
|
+
| `shift+${ShiftNamedKey}`;
|
|
28
|
+
|
|
29
|
+
const BASE_KEY_SEQUENCES: Record<BaseNamedKey, string> = {
|
|
30
|
+
enter: '\r',
|
|
31
|
+
escape: '\x1b',
|
|
32
|
+
tab: '\t',
|
|
33
|
+
backspace: '\x7f',
|
|
34
|
+
up: '\x1b[A',
|
|
35
|
+
down: '\x1b[B',
|
|
36
|
+
right: '\x1b[C',
|
|
37
|
+
left: '\x1b[D',
|
|
38
|
+
home: '\x1b[H',
|
|
39
|
+
end: '\x1b[F',
|
|
40
|
+
pageup: '\x1b[5~',
|
|
41
|
+
pagedown: '\x1b[6~',
|
|
42
|
+
space: ' ',
|
|
43
|
+
f1: '\x1bOP',
|
|
44
|
+
f2: '\x1bOQ',
|
|
45
|
+
f3: '\x1bOR',
|
|
46
|
+
f4: '\x1bOS',
|
|
47
|
+
f5: '\x1b[15~',
|
|
48
|
+
f6: '\x1b[17~',
|
|
49
|
+
f7: '\x1b[18~',
|
|
50
|
+
f8: '\x1b[19~',
|
|
51
|
+
f9: '\x1b[20~',
|
|
52
|
+
f10: '\x1b[21~',
|
|
53
|
+
f11: '\x1b[23~',
|
|
54
|
+
f12: '\x1b[24~',
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const SHIFTED_CSI_KEYS: Partial<Record<BaseNamedKey, string>> = {
|
|
58
|
+
up: '\x1b[1;2A',
|
|
59
|
+
down: '\x1b[1;2B',
|
|
60
|
+
right: '\x1b[1;2C',
|
|
61
|
+
left: '\x1b[1;2D',
|
|
62
|
+
home: '\x1b[1;2H',
|
|
63
|
+
end: '\x1b[1;2F',
|
|
64
|
+
pageup: '\x1b[5;2~',
|
|
65
|
+
pagedown: '\x1b[6;2~',
|
|
66
|
+
f1: '\x1b[1;2P',
|
|
67
|
+
f2: '\x1b[1;2Q',
|
|
68
|
+
f3: '\x1b[1;2R',
|
|
69
|
+
f4: '\x1b[1;2S',
|
|
70
|
+
f5: '\x1b[15;2~',
|
|
71
|
+
f6: '\x1b[17;2~',
|
|
72
|
+
f7: '\x1b[18;2~',
|
|
73
|
+
f8: '\x1b[19;2~',
|
|
74
|
+
f9: '\x1b[20;2~',
|
|
75
|
+
f10: '\x1b[21;2~',
|
|
76
|
+
f11: '\x1b[23;2~',
|
|
77
|
+
f12: '\x1b[24;2~',
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
function isLowercaseLetter(value: string): value is LowercaseLetter {
|
|
81
|
+
return /^[a-z]$/.test(value);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function encodeControlLetter(letter: LowercaseLetter): string {
|
|
85
|
+
return String.fromCharCode(letter.charCodeAt(0) - 96);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function encodeShiftedKey(key: string): string {
|
|
89
|
+
if (isLowercaseLetter(key)) return key.toUpperCase();
|
|
90
|
+
if (key.startsWith('ctrl+') && isLowercaseLetter(key.slice(5))) {
|
|
91
|
+
return encodeControlLetter(key.slice(5) as LowercaseLetter);
|
|
92
|
+
}
|
|
93
|
+
if (key.startsWith('alt+') && isLowercaseLetter(key.slice(4))) {
|
|
94
|
+
return `\x1b${key.slice(4).toUpperCase()}`;
|
|
95
|
+
}
|
|
96
|
+
if (key === 'tab') return '\x1b[Z';
|
|
97
|
+
if (key in SHIFTED_CSI_KEYS) return SHIFTED_CSI_KEYS[key as BaseNamedKey]!;
|
|
98
|
+
if (key in BASE_KEY_SEQUENCES) return BASE_KEY_SEQUENCES[key as BaseNamedKey];
|
|
99
|
+
throw new Error(`Unsupported named key: shift+${key}`);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function namedKeyToAnsi(key: NamedKey | string): string {
|
|
103
|
+
const normalized = String(key || '').trim().toLowerCase();
|
|
104
|
+
if (normalized in BASE_KEY_SEQUENCES) return BASE_KEY_SEQUENCES[normalized as BaseNamedKey];
|
|
105
|
+
if (normalized.startsWith('ctrl+') && isLowercaseLetter(normalized.slice(5))) {
|
|
106
|
+
return encodeControlLetter(normalized.slice(5) as LowercaseLetter);
|
|
107
|
+
}
|
|
108
|
+
if (normalized.startsWith('alt+') && isLowercaseLetter(normalized.slice(4))) {
|
|
109
|
+
return `\x1b${normalized.slice(4)}`;
|
|
110
|
+
}
|
|
111
|
+
if (normalized.startsWith('shift+')) return encodeShiftedKey(normalized.slice(6));
|
|
112
|
+
throw new Error(`Unsupported named key: ${key}`);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function namedKeysToAnsi(keys: readonly (NamedKey | string)[]): string {
|
|
116
|
+
if (!Array.isArray(keys)) throw new Error('keys must be an array');
|
|
117
|
+
return keys.map(namedKeyToAnsi).join('');
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export interface RawTerminalSessionHostClient {
|
|
121
|
+
connect(): Promise<void>;
|
|
122
|
+
request<T = unknown>(request: SessionHostRequest): Promise<SessionHostResponse<T>>;
|
|
123
|
+
close(): Promise<void>;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export interface RawTerminalAttachmentOptions {
|
|
127
|
+
endpoint?: SessionHostEndpoint;
|
|
128
|
+
sessionId: string;
|
|
129
|
+
mode?: 'read' | 'write';
|
|
130
|
+
clientId?: string;
|
|
131
|
+
client?: RawTerminalSessionHostClient;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export class RawTerminalAttachment {
|
|
135
|
+
private closed = false;
|
|
136
|
+
|
|
137
|
+
private constructor(
|
|
138
|
+
readonly sessionId: string,
|
|
139
|
+
private readonly clientId: string,
|
|
140
|
+
private readonly mode: 'read' | 'write',
|
|
141
|
+
private readonly client: RawTerminalSessionHostClient,
|
|
142
|
+
) {}
|
|
143
|
+
|
|
144
|
+
static async attach(options: RawTerminalAttachmentOptions): Promise<RawTerminalAttachment> {
|
|
145
|
+
const sessionId = String(options.sessionId || '').trim();
|
|
146
|
+
if (!sessionId) throw new Error('sessionId is required');
|
|
147
|
+
const mode = options.mode || 'read';
|
|
148
|
+
const clientId = options.clientId || `raw-terminal-${process.pid}-${randomUUID().slice(0, 8)}`;
|
|
149
|
+
const client = options.client || new SessionHostClient({ endpoint: options.endpoint });
|
|
150
|
+
await client.connect();
|
|
151
|
+
|
|
152
|
+
const attachResponse = await client.request({
|
|
153
|
+
type: 'attach_session',
|
|
154
|
+
payload: {
|
|
155
|
+
sessionId,
|
|
156
|
+
clientId,
|
|
157
|
+
clientType: 'web',
|
|
158
|
+
readOnly: mode === 'read',
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
if (!attachResponse.success) {
|
|
162
|
+
await client.close().catch(() => {});
|
|
163
|
+
throw new Error(attachResponse.error || `Failed to attach terminal session ${sessionId}`);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (mode === 'write') {
|
|
167
|
+
const ownerResponse = await client.request({
|
|
168
|
+
type: 'acquire_write',
|
|
169
|
+
payload: {
|
|
170
|
+
sessionId,
|
|
171
|
+
clientId,
|
|
172
|
+
ownerType: 'user',
|
|
173
|
+
force: true,
|
|
174
|
+
},
|
|
175
|
+
});
|
|
176
|
+
if (!ownerResponse.success) {
|
|
177
|
+
await client.request({
|
|
178
|
+
type: 'detach_session',
|
|
179
|
+
payload: { sessionId, clientId },
|
|
180
|
+
}).catch(() => ({ success: false }));
|
|
181
|
+
await client.close().catch(() => {});
|
|
182
|
+
throw new Error(ownerResponse.error || `Failed to acquire terminal session ${sessionId}`);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return new RawTerminalAttachment(sessionId, clientId, mode, client);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
async readSnapshot(): Promise<SessionTerminalSnapshot> {
|
|
190
|
+
const response = await this.client.request<SessionTerminalSnapshot>({
|
|
191
|
+
type: 'get_terminal_snapshot',
|
|
192
|
+
payload: { sessionId: this.sessionId },
|
|
193
|
+
});
|
|
194
|
+
if (!response.success || !response.result) {
|
|
195
|
+
throw new Error(response.error || `Terminal screen unavailable for ${this.sessionId}`);
|
|
196
|
+
}
|
|
197
|
+
return response.result;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
async readScreenText(): Promise<string> {
|
|
201
|
+
return (await this.readSnapshot()).text;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
async readState(): Promise<SessionTerminalState> {
|
|
205
|
+
return (await this.readSnapshot()).state;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
async writeInput(text: string): Promise<void> {
|
|
209
|
+
if (this.mode !== 'write') throw new Error('Raw terminal attachment is read-only');
|
|
210
|
+
const response = await this.client.request({
|
|
211
|
+
type: 'send_input',
|
|
212
|
+
payload: {
|
|
213
|
+
sessionId: this.sessionId,
|
|
214
|
+
clientId: this.clientId,
|
|
215
|
+
data: text,
|
|
216
|
+
},
|
|
217
|
+
});
|
|
218
|
+
if (!response.success) throw new Error(response.error || `Failed to write terminal input to ${this.sessionId}`);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
async writeKeys(keys: readonly (NamedKey | string)[]): Promise<void> {
|
|
222
|
+
await this.writeInput(namedKeysToAnsi(keys));
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
async close(): Promise<void> {
|
|
226
|
+
if (this.closed) return;
|
|
227
|
+
this.closed = true;
|
|
228
|
+
if (this.mode === 'write') {
|
|
229
|
+
await this.client.request({
|
|
230
|
+
type: 'release_write',
|
|
231
|
+
payload: { sessionId: this.sessionId, clientId: this.clientId },
|
|
232
|
+
}).catch(() => ({ success: false }));
|
|
233
|
+
}
|
|
234
|
+
await this.client.request({
|
|
235
|
+
type: 'detach_session',
|
|
236
|
+
payload: { sessionId: this.sessionId, clientId: this.clientId },
|
|
237
|
+
}).catch(() => ({ success: false }));
|
|
238
|
+
await this.client.close().catch(() => {});
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export async function withRawTerminalAttachment<T>(
|
|
243
|
+
options: RawTerminalAttachmentOptions,
|
|
244
|
+
operation: (attachment: RawTerminalAttachment) => Promise<T>,
|
|
245
|
+
): Promise<T> {
|
|
246
|
+
const attachment = await RawTerminalAttachment.attach(options);
|
|
247
|
+
try {
|
|
248
|
+
return await operation(attachment);
|
|
249
|
+
} finally {
|
|
250
|
+
await attachment.close();
|
|
251
|
+
}
|
|
252
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { execFileSync } from 'child_process';
|
|
2
|
+
import { existsSync } from 'fs';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
|
|
5
|
+
// Extensions ConPTY/CreateProcess can launch directly (not .cmd/.bat, which
|
|
6
|
+
// need a cmd.exe wrapper).
|
|
7
|
+
const DIRECT_EXEC_EXT = new Set(['.exe', '.com']);
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Resolve a launch command to an absolute executable path on Windows.
|
|
11
|
+
*
|
|
12
|
+
* node-pty's ConPTY backend resolves a bare/relative command against the
|
|
13
|
+
* *calling process's* `Path` env var and — critically — does NOT apply PATHEXT.
|
|
14
|
+
* So a provider command like `claude` never matches `claude.exe` and the native
|
|
15
|
+
* layer throws `File not found:` (empty), which crashes the daemon. We resolve
|
|
16
|
+
* it to an absolute `.exe` here (in the daemon process, which has the full PATH)
|
|
17
|
+
* before the command ever reaches node-pty.
|
|
18
|
+
*
|
|
19
|
+
* No-op on non-Windows and when the command is already an existing absolute path
|
|
20
|
+
* or cannot be resolved (caller keeps the original behaviour).
|
|
21
|
+
*/
|
|
22
|
+
export function resolveWin32Executable(command: string): string {
|
|
23
|
+
if (process.platform !== 'win32') return command;
|
|
24
|
+
const trimmed = (command || '').trim();
|
|
25
|
+
if (!trimmed) return command;
|
|
26
|
+
|
|
27
|
+
// Already an absolute path that exists — keep it.
|
|
28
|
+
if (path.isAbsolute(trimmed) && existsSync(trimmed)) return trimmed;
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
const out = execFileSync('where', [trimmed], {
|
|
32
|
+
encoding: 'utf8',
|
|
33
|
+
windowsHide: true,
|
|
34
|
+
}).trim();
|
|
35
|
+
if (out) {
|
|
36
|
+
const matches = out.split(/\r?\n/).map((s) => s.trim()).filter(Boolean);
|
|
37
|
+
// Prefer a directly-launchable executable (.exe/.com) over .cmd/.bat shims.
|
|
38
|
+
const direct = matches.find((m) => DIRECT_EXEC_EXT.has(path.extname(m).toLowerCase()));
|
|
39
|
+
return direct || matches[0] || command;
|
|
40
|
+
}
|
|
41
|
+
} catch {
|
|
42
|
+
// `where` not found / non-zero exit — fall through to original command.
|
|
43
|
+
}
|
|
44
|
+
return command;
|
|
45
|
+
}
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
type SessionHostRecord,
|
|
7
7
|
} from '@adhdev/session-host-core';
|
|
8
8
|
import { LOG } from '../logging/logger.js';
|
|
9
|
+
import { resolveWin32Executable } from './resolve-executable.js';
|
|
9
10
|
import type { PtyRuntimeMetadata, PtyRuntimeTransport, PtySpawnOptions, PtyTransportFactory } from './pty-transport.js';
|
|
10
11
|
|
|
11
12
|
interface SessionHostPtyTransportFactoryOptions {
|
|
@@ -435,7 +436,7 @@ export class SessionHostPtyTransportFactory implements PtyTransportFactory {
|
|
|
435
436
|
spawn(command: string, args: string[], spawnOptions: PtySpawnOptions): PtyRuntimeTransport {
|
|
436
437
|
return new SessionHostRuntimeTransport({
|
|
437
438
|
...this.options,
|
|
438
|
-
command,
|
|
439
|
+
command: resolveWin32Executable(command),
|
|
439
440
|
args,
|
|
440
441
|
spawnOptions,
|
|
441
442
|
});
|