@adhdev/daemon-core 0.9.82-rc.21 → 0.9.82-rc.211
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 +1 -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/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +3 -3
- package/dist/cli-adapters/terminal-backends/types.d.ts +1 -2
- package/dist/cli-adapters/terminal-screen.d.ts +2 -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 +32 -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-types.d.ts +2 -0
- package/dist/index.d.ts +46 -11
- package/dist/index.js +35173 -15756
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +34880 -15556
- 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 +90 -0
- package/dist/mesh/mesh-delivery-policy.d.ts +131 -0
- package/dist/mesh/mesh-events-coordinator.d.ts +151 -0
- package/dist/mesh/mesh-events-pending.d.ts +33 -0
- package/dist/mesh/mesh-events-stale.d.ts +40 -0
- package/dist/mesh/mesh-events-utils.d.ts +14 -0
- package/dist/mesh/mesh-events.d.ts +5 -40
- 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-reconciliation.d.ts +23 -3
- package/dist/mesh/mesh-ledger.d.ts +77 -1
- package/dist/mesh/mesh-missions.d.ts +58 -0
- package/dist/mesh/mesh-refine-status.d.ts +26 -0
- package/dist/mesh/mesh-review-inbox.d.ts +90 -0
- package/dist/mesh/mesh-runtime-store.d.ts +324 -0
- package/dist/mesh/mesh-task-stats.d.ts +49 -0
- package/dist/mesh/mesh-work-queue.d.ts +137 -6
- 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 +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 +52 -0
- package/dist/providers/spec/cli-adapter.d.ts +101 -0
- package/dist/providers/spec/driver.d.ts +225 -0
- package/dist/providers/spec/evaluator.d.ts +54 -0
- package/dist/providers/spec/loader.d.ts +15 -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 +2025 -0
- package/dist/providers/spec/types.d.ts +302 -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 +109 -1
- package/dist/sessions/registry.d.ts +3 -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 +6 -3
- 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 +673 -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 +59 -11
- package/src/cli-adapters/raw-terminal-io.ts +252 -0
- package/src/cli-adapters/terminal-backends/ghostty-vt-backend.ts +35 -29
- package/src/cli-adapters/terminal-backends/types.ts +1 -3
- package/src/cli-adapters/terminal-screen.ts +11 -81
- 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 +332 -122
- package/src/commands/router.ts +4198 -557
- 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-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-status.ts +35 -6
- package/src/git/git-types.ts +2 -0
- package/src/git/git-worktree.ts +8 -1
- package/src/index.ts +126 -10
- 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 +218 -31
- package/src/mesh/coordinator-registry.ts +121 -0
- package/src/mesh/mesh-active-work.ts +437 -0
- package/src/mesh/mesh-delivery-policy.ts +315 -0
- package/src/mesh/mesh-events-coordinator.ts +1404 -0
- package/src/mesh/mesh-events-pending.ts +371 -0
- package/src/mesh/mesh-events-stale.ts +283 -0
- package/src/mesh/mesh-events-utils.ts +161 -0
- package/src/mesh/mesh-events.ts +24 -908
- package/src/mesh/mesh-fast-forward.ts +438 -0
- package/src/mesh/mesh-host-ownership.ts +73 -0
- package/src/mesh/mesh-ledger-reconciliation.ts +12 -5
- package/src/mesh/mesh-ledger.ts +587 -102
- package/src/mesh/mesh-missions.ts +151 -0
- package/src/mesh/mesh-refine-status.ts +144 -0
- package/src/mesh/mesh-review-inbox.ts +307 -0
- package/src/mesh/mesh-runtime-store.ts +1305 -0
- package/src/mesh/mesh-task-stats.ts +154 -0
- package/src/mesh/mesh-work-queue.ts +490 -166
- 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 +833 -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 +138 -0
- package/src/providers/spec/cli-adapter.ts +626 -0
- package/src/providers/spec/driver.ts +922 -0
- package/src/providers/spec/evaluator.ts +597 -0
- package/src/providers/spec/loader.ts +324 -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 +691 -0
- package/src/providers/spec/schema.json +341 -0
- package/src/providers/spec/types.ts +356 -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 +119 -1
- package/src/sessions/registry.ts +3 -0
- package/src/shared-types-extra.ts +2 -4
- 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/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,18 @@ export interface CliSessionStatus {
|
|
|
28
29
|
messages: CliChatMessage[];
|
|
29
30
|
workingDir: string;
|
|
30
31
|
activeModal: { message: string; buttons: string[] } | null;
|
|
32
|
+
activeInteractivePrompt?: InteractivePrompt | null;
|
|
33
|
+
pendingOutboundCount?: number;
|
|
34
|
+
pendingOutboundMessages?: Array<{
|
|
35
|
+
id: string;
|
|
36
|
+
role: 'user';
|
|
37
|
+
content: string;
|
|
38
|
+
queuedAt: number;
|
|
39
|
+
source: string;
|
|
40
|
+
}>;
|
|
31
41
|
errorMessage?: string;
|
|
32
42
|
errorReason?: string;
|
|
43
|
+
providerSessionId?: string;
|
|
33
44
|
bufferState?: {
|
|
34
45
|
responseBuffer?: { truncated: boolean; droppedChars: number; maxChars: number };
|
|
35
46
|
recentOutputBuffer?: { truncated: boolean; droppedChars: number; maxChars: number };
|
|
@@ -43,6 +54,9 @@ export interface ParsedSession {
|
|
|
43
54
|
messages: any[];
|
|
44
55
|
modal: { message: string; buttons: string[] } | null;
|
|
45
56
|
parsedStatus: string | null;
|
|
57
|
+
errorMessage?: string;
|
|
58
|
+
errorReason?: string;
|
|
59
|
+
providerSessionId?: string;
|
|
46
60
|
transcriptAuthority?: 'provider' | 'daemon';
|
|
47
61
|
coverage?: 'full' | 'tail' | 'current-turn';
|
|
48
62
|
}
|
|
@@ -94,6 +108,10 @@ export interface CliScriptInput {
|
|
|
94
108
|
rawBuffer: string;
|
|
95
109
|
recentBuffer: string;
|
|
96
110
|
screenText: string;
|
|
111
|
+
workspace?: string;
|
|
112
|
+
workingDir?: string;
|
|
113
|
+
providerSessionId?: string;
|
|
114
|
+
historySessionId?: string;
|
|
97
115
|
screen: CliScreenSnapshot;
|
|
98
116
|
bufferScreen: CliScreenSnapshot;
|
|
99
117
|
recentScreen: CliScreenSnapshot;
|
|
@@ -103,6 +121,7 @@ export interface CliScriptInput {
|
|
|
103
121
|
promptText?: string;
|
|
104
122
|
settings?: Record<string, any>;
|
|
105
123
|
args?: Record<string, any>;
|
|
124
|
+
spawnAt?: number;
|
|
106
125
|
}
|
|
107
126
|
|
|
108
127
|
export interface CliStatusInput {
|
|
@@ -141,16 +160,26 @@ export interface CliProviderModule {
|
|
|
141
160
|
binary: string;
|
|
142
161
|
approvalKeys?: Record<number, string>;
|
|
143
162
|
sendDelayMs?: number;
|
|
163
|
+
/** Wall-clock budget (ms) for a single provider script invocation. Default 50. Range 1..5000.
|
|
164
|
+
* Exceeding the budget records `timedOut: true` on the invocation trace and emits a
|
|
165
|
+
* throttled WARN — it does NOT abort the script (Node CJS can't interrupt sync code). */
|
|
166
|
+
scriptCallBudgetMs?: number;
|
|
144
167
|
sendKey?: string;
|
|
145
168
|
submitStrategy?: 'wait_for_echo' | 'immediate';
|
|
146
169
|
/** Require the typed prompt to be visible on the PTY screen before sending Enter. */
|
|
147
170
|
requirePromptEchoBeforeSubmit?: boolean;
|
|
148
171
|
/** Allow sending another prompt while the CLI is still generating so users can intervene mid-turn. */
|
|
149
172
|
allowInputDuringGeneration?: boolean;
|
|
173
|
+
/** When true, only transition to idle after the parsed transcript includes a final standard assistant message. */
|
|
174
|
+
requiresFinalAssistantBeforeIdle?: boolean;
|
|
175
|
+
/** When true, allow providers to augment stale snapshot data before parse. Reserved for future use. */
|
|
176
|
+
augmentStaleSnapshot?: boolean;
|
|
150
177
|
/** When provider-owned, daemon treats provider parser output as canonical transcript authority. */
|
|
151
178
|
transcriptAuthority?: 'provider' | 'daemon';
|
|
152
179
|
/** Full context lets provider-owned parsers canonicalize retained history instead of daemon prefix stitching. */
|
|
153
180
|
transcriptContext?: 'full' | 'tail';
|
|
181
|
+
/** v1 declarative tui block — used by CliScriptRunner to synthesize SDK helpers (declarativeDetectStatus, declarativeParseApproval). */
|
|
182
|
+
tui?: Record<string, unknown>;
|
|
154
183
|
scripts?: CliScripts;
|
|
155
184
|
spawn: {
|
|
156
185
|
command: string;
|
|
@@ -342,7 +371,18 @@ export class TerminalTranscriptAccumulator {
|
|
|
342
371
|
this.ensureRow();
|
|
343
372
|
if (final === 'A') this.row = Math.max(0, this.row - count);
|
|
344
373
|
else if (final === 'B') this.row += count;
|
|
345
|
-
else if (final === 'C')
|
|
374
|
+
else if (final === 'C') {
|
|
375
|
+
// (fix) Cursor-forward must materialize spaces in the cells it
|
|
376
|
+
// skips, otherwise rendered transcripts collapse "Do you" written
|
|
377
|
+
// as "Do\x1b[1Cyou" into "Doyou". That mis-rendering broke
|
|
378
|
+
// Claude Code's approval-prompt and prompt-line detection
|
|
379
|
+
// (parseApproval saw "Doyouwanttoproceed?" and returned null).
|
|
380
|
+
const line = this.lines[this.row];
|
|
381
|
+
for (let c = this.col; c < this.col + count; c += 1) {
|
|
382
|
+
if (line[c] === undefined) line[c] = ' ';
|
|
383
|
+
}
|
|
384
|
+
this.col += count;
|
|
385
|
+
}
|
|
346
386
|
else if (final === 'D') this.col = Math.max(0, this.col - count);
|
|
347
387
|
else if (final === 'G') this.col = Math.max(0, count - 1);
|
|
348
388
|
else if (final === 'H' || final === 'f') {
|
|
@@ -484,17 +524,25 @@ export function findBinary(name: string): string {
|
|
|
484
524
|
return path.isAbsolute(expanded) ? expanded : path.resolve(expanded);
|
|
485
525
|
}
|
|
486
526
|
const isWin = os.platform() === 'win32';
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
527
|
+
const paths = (process.env.PATH || '').split(path.delimiter);
|
|
528
|
+
const exes = isWin ? ['.exe', '.cmd', '.bat', ''] : [''];
|
|
529
|
+
|
|
530
|
+
for (const p of paths) {
|
|
531
|
+
if (!p) continue;
|
|
532
|
+
for (const ext of exes) {
|
|
533
|
+
const fullPath = path.join(p, trimmed + ext);
|
|
534
|
+
try {
|
|
535
|
+
const fs = require('fs');
|
|
536
|
+
if (fs.existsSync(fullPath)) {
|
|
537
|
+
const stat = fs.statSync(fullPath);
|
|
538
|
+
if (stat.isFile() && (isWin || (stat.mode & 0o111))) {
|
|
539
|
+
return fullPath;
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
} catch { }
|
|
543
|
+
}
|
|
497
544
|
}
|
|
545
|
+
return isWin ? `${trimmed}.cmd` : trimmed;
|
|
498
546
|
}
|
|
499
547
|
|
|
500
548
|
export function isScriptBinary(binaryPath: string): boolean {
|
|
@@ -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
|
+
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
TerminalViewportBackend,
|
|
3
3
|
TerminalViewportBackendOptions,
|
|
4
|
-
TerminalViewportBackendPreference,
|
|
5
4
|
} from './types.js';
|
|
6
5
|
|
|
7
6
|
type GhosttyVtTerminal = {
|
|
@@ -49,12 +48,10 @@ function getBindingCandidates(): string[] {
|
|
|
49
48
|
return explicit ? [explicit] : DEFAULT_BINDING_CANDIDATES;
|
|
50
49
|
}
|
|
51
50
|
|
|
52
|
-
function loadGhosttyVtBinding(
|
|
51
|
+
function loadGhosttyVtBinding(): GhosttyVtBinding {
|
|
53
52
|
if (cachedBinding !== undefined) {
|
|
54
|
-
if (!cachedBinding &&
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
return cachedBinding;
|
|
53
|
+
if (!cachedBinding && cachedBindingError) throw cachedBindingError;
|
|
54
|
+
return cachedBinding!;
|
|
58
55
|
}
|
|
59
56
|
|
|
60
57
|
const errors: string[] = [];
|
|
@@ -65,7 +62,7 @@ function loadGhosttyVtBinding(required: boolean): GhosttyVtBinding | null {
|
|
|
65
62
|
const mod = require(ref);
|
|
66
63
|
cachedBinding = normalizeBinding(mod, ref);
|
|
67
64
|
cachedBindingError = null;
|
|
68
|
-
return cachedBinding
|
|
65
|
+
return cachedBinding!;
|
|
69
66
|
} catch (error) {
|
|
70
67
|
if (isModuleNotFoundError(error, ref)) {
|
|
71
68
|
errors.push(`${ref}: module not found`);
|
|
@@ -78,57 +75,66 @@ function loadGhosttyVtBinding(required: boolean): GhosttyVtBinding | null {
|
|
|
78
75
|
|
|
79
76
|
cachedBinding = null;
|
|
80
77
|
cachedBindingError = new Error(
|
|
81
|
-
`ghostty-vt
|
|
78
|
+
`ghostty-vt binding unavailable (${errors.join('; ') || 'no candidates tried'})`,
|
|
82
79
|
);
|
|
83
|
-
|
|
84
|
-
if (required) throw cachedBindingError;
|
|
85
|
-
return null;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export function resolveTerminalBackendPreference(): TerminalViewportBackendPreference {
|
|
89
|
-
const raw = process.env.ADHDEV_TERMINAL_BACKEND?.trim().toLowerCase();
|
|
90
|
-
if (raw === 'ghostty-vt' || raw === 'xterm' || raw === 'auto') return raw;
|
|
91
|
-
return 'auto';
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
export function isGhosttyVtBackendAvailable(): boolean {
|
|
95
|
-
return !!loadGhosttyVtBinding(false);
|
|
80
|
+
throw cachedBindingError;
|
|
96
81
|
}
|
|
97
82
|
|
|
98
83
|
export class GhosttyVtTerminalBackend implements TerminalViewportBackend {
|
|
99
84
|
readonly kind = 'ghostty-vt' as const;
|
|
100
85
|
private terminal: GhosttyVtTerminal;
|
|
86
|
+
private rows: number;
|
|
87
|
+
private disposed = false;
|
|
101
88
|
|
|
102
89
|
constructor(options: TerminalViewportBackendOptions) {
|
|
103
|
-
const binding = loadGhosttyVtBinding(
|
|
104
|
-
|
|
105
|
-
throw new Error('ghostty-vt backend requested but no binding is available');
|
|
106
|
-
}
|
|
90
|
+
const binding = loadGhosttyVtBinding();
|
|
91
|
+
this.rows = Math.max(1, options.rows | 0);
|
|
107
92
|
this.terminal = binding.createTerminal({
|
|
108
93
|
cols: Math.max(1, options.cols | 0),
|
|
109
|
-
rows:
|
|
94
|
+
rows: this.rows,
|
|
110
95
|
scrollback: Math.max(0, options.scrollback | 0),
|
|
111
96
|
});
|
|
112
97
|
}
|
|
113
98
|
|
|
114
99
|
resize(rows: number, cols: number): void {
|
|
115
|
-
this.
|
|
100
|
+
this.rows = Math.max(1, rows | 0);
|
|
101
|
+
this.terminal.resize(Math.max(1, cols | 0), this.rows);
|
|
116
102
|
}
|
|
117
103
|
|
|
118
104
|
write(data: string): void {
|
|
119
|
-
if (!data) return;
|
|
105
|
+
if (!data || this.disposed) return;
|
|
120
106
|
this.terminal.write(data);
|
|
121
107
|
}
|
|
122
108
|
|
|
123
109
|
getText(): string {
|
|
124
|
-
|
|
110
|
+
if (this.disposed) return '';
|
|
111
|
+
// ghostty's `trim:true` collapses CUF-advanced cells — many TUIs including
|
|
112
|
+
// Claude Code render spaces via cursor-forward rather than literal spaces,
|
|
113
|
+
// which would break downstream regex matching. Keep per-row padding and
|
|
114
|
+
// trim trailing whitespace ourselves.
|
|
115
|
+
//
|
|
116
|
+
// formatPlainText uses a .screen pin which includes scrollback history.
|
|
117
|
+
// Slice to the last `rows` lines to get only the visible viewport.
|
|
118
|
+
const raw = this.terminal.formatPlainText({ trim: false }) || '';
|
|
119
|
+
if (!raw) return '';
|
|
120
|
+
const lines = raw.split('\n').map((row) => row.replace(/\s+$/, ''));
|
|
121
|
+
// Take only the viewport (last `rows` lines) to exclude scrollback history.
|
|
122
|
+
const viewport = lines.length > this.rows ? lines.slice(-this.rows) : lines;
|
|
123
|
+
let first = 0;
|
|
124
|
+
let last = viewport.length;
|
|
125
|
+
while (first < last && !viewport[first]) first += 1;
|
|
126
|
+
while (last > first && !viewport[last - 1]) last -= 1;
|
|
127
|
+
return viewport.slice(first, last).join('\n');
|
|
125
128
|
}
|
|
126
129
|
|
|
127
130
|
getCursorPosition(): { col: number; row: number } {
|
|
131
|
+
if (this.disposed) return { col: 0, row: 0 };
|
|
128
132
|
return this.terminal.getCursorPosition();
|
|
129
133
|
}
|
|
130
134
|
|
|
131
135
|
dispose(): void {
|
|
136
|
+
if (this.disposed) return;
|
|
137
|
+
this.disposed = true;
|
|
132
138
|
this.terminal.dispose();
|
|
133
139
|
}
|
|
134
140
|
}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
export type TerminalViewportBackendKind = '
|
|
2
|
-
|
|
3
|
-
export type TerminalViewportBackendPreference = TerminalViewportBackendKind | 'auto';
|
|
1
|
+
export type TerminalViewportBackendKind = 'ghostty-vt';
|
|
4
2
|
|
|
5
3
|
export type TerminalViewportBackendOptions = {
|
|
6
4
|
rows: number;
|