@leanandmean/coding-agent 0.74.1-scramjet.58 → 0.74.1-scramjet.59
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/README.md +14 -2
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +2 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +3 -1
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/keybindings.d.ts +8 -0
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/settings-manager.d.ts +15 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +74 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +4 -3
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +3 -2
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-editor.js +3 -1
- package/dist/modes/interactive/components/extension-editor.js.map +1 -1
- package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-selector.js +4 -3
- package/dist/modes/interactive/components/extension-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +17 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +84 -2
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +6 -1
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message.js +3 -2
- package/dist/modes/interactive/components/user-message.js.map +1 -1
- package/dist/modes/interactive/components/visual-truncate.d.ts.map +1 -1
- package/dist/modes/interactive/components/visual-truncate.js +2 -2
- package/dist/modes/interactive/components/visual-truncate.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +18 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +480 -100
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/utils/clipboard-native.d.ts +1 -0
- package/dist/utils/clipboard-native.d.ts.map +1 -1
- package/dist/utils/clipboard-native.js.map +1 -1
- package/dist/utils/clipboard.d.ts +6 -0
- package/dist/utils/clipboard.d.ts.map +1 -1
- package/dist/utils/clipboard.js +278 -10
- package/dist/utils/clipboard.js.map +1 -1
- package/dist/utils/tools-manager.d.ts +1 -1
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +7 -6
- package/dist/utils/tools-manager.js.map +1 -1
- package/docs/extensions.md +27 -11
- package/docs/keybindings.md +23 -1
- package/docs/settings.md +11 -0
- package/docs/terminal-setup.md +79 -2
- package/docs/terminal-verification.md +71 -0
- package/docs/tui.md +91 -29
- package/examples/extensions/doom-overlay/doom-component.ts +3 -3
- package/examples/extensions/modal-editor.ts +13 -8
- package/examples/extensions/overlay-qa-tests.ts +22 -9
- package/examples/extensions/overlay-test.ts +5 -3
- package/examples/extensions/snake.ts +3 -1
- package/examples/extensions/space-invaders.ts +6 -3
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools-manager.js","sourceRoot":"","sources":["../../src/utils/tools-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import chalk from \"chalk\";\nimport { type SpawnSyncReturns, spawnSync } from \"child_process\";\nimport { chmodSync, createWriteStream, existsSync, mkdirSync, readdirSync, renameSync, rmSync } from \"fs\";\nimport { arch, platform } from \"os\";\nimport { join } from \"path\";\nimport { Readable } from \"stream\";\nimport { pipeline } from \"stream/promises\";\nimport { APP_NAME, getBinDir } from \"../config.js\";\n\nconst TOOLS_DIR = getBinDir();\nconst NETWORK_TIMEOUT_MS = 10_000;\nconst DOWNLOAD_TIMEOUT_MS = 120_000;\n\n// SCRAMJET-DIVERGENCE: prefer SCRAMJET_OFFLINE, fall back to PI_OFFLINE.\nfunction isOfflineModeEnabled(): boolean {\n\tconst value = process.env.SCRAMJET_OFFLINE || process.env.PI_OFFLINE;\n\tif (!value) return false;\n\treturn value === \"1\" || value.toLowerCase() === \"true\" || value.toLowerCase() === \"yes\";\n}\n\ninterface ToolConfig {\n\tname: string;\n\trepo: string; // GitHub repo (e.g., \"sharkdp/fd\")\n\tbinaryName: string; // Name of the binary inside the archive\n\tsystemBinaryNames?: string[]; // Alternative system command names to try before downloading\n\ttagPrefix: string; // Prefix for tags (e.g., \"v\" for v1.0.0, \"\" for 1.0.0)\n\tgetAssetName: (version: string, plat: string, architecture: string) => string | null;\n}\n\nconst TOOLS: Record<string, ToolConfig> = {\n\tfd: {\n\t\tname: \"fd\",\n\t\trepo: \"sharkdp/fd\",\n\t\tbinaryName: \"fd\",\n\t\tsystemBinaryNames: [\"fd\", \"fdfind\"],\n\t\ttagPrefix: \"v\",\n\t\tgetAssetName: (version, plat, architecture) => {\n\t\t\tif (plat === \"darwin\") {\n\t\t\t\tconst archStr = architecture === \"arm64\" ? \"aarch64\" : \"x86_64\";\n\t\t\t\treturn `fd-v${version}-${archStr}-apple-darwin.tar.gz`;\n\t\t\t} else if (plat === \"linux\") {\n\t\t\t\tconst archStr = architecture === \"arm64\" ? \"aarch64\" : \"x86_64\";\n\t\t\t\treturn `fd-v${version}-${archStr}-unknown-linux-gnu.tar.gz`;\n\t\t\t} else if (plat === \"win32\") {\n\t\t\t\tconst archStr = architecture === \"arm64\" ? \"aarch64\" : \"x86_64\";\n\t\t\t\treturn `fd-v${version}-${archStr}-pc-windows-msvc.zip`;\n\t\t\t}\n\t\t\treturn null;\n\t\t},\n\t},\n\trg: {\n\t\tname: \"ripgrep\",\n\t\trepo: \"BurntSushi/ripgrep\",\n\t\tbinaryName: \"rg\",\n\t\ttagPrefix: \"\",\n\t\tgetAssetName: (version, plat, architecture) => {\n\t\t\tif (plat === \"darwin\") {\n\t\t\t\tconst archStr = architecture === \"arm64\" ? \"aarch64\" : \"x86_64\";\n\t\t\t\treturn `ripgrep-${version}-${archStr}-apple-darwin.tar.gz`;\n\t\t\t} else if (plat === \"linux\") {\n\t\t\t\tif (architecture === \"arm64\") {\n\t\t\t\t\treturn `ripgrep-${version}-aarch64-unknown-linux-gnu.tar.gz`;\n\t\t\t\t}\n\t\t\t\treturn `ripgrep-${version}-x86_64-unknown-linux-musl.tar.gz`;\n\t\t\t} else if (plat === \"win32\") {\n\t\t\t\tconst archStr = architecture === \"arm64\" ? \"aarch64\" : \"x86_64\";\n\t\t\t\treturn `ripgrep-${version}-${archStr}-pc-windows-msvc.zip`;\n\t\t\t}\n\t\t\treturn null;\n\t\t},\n\t},\n};\n\n// Check if a command exists in PATH by trying to run it\nfunction commandExists(cmd: string): boolean {\n\ttry {\n\t\tconst result = spawnSync(cmd, [\"--version\"], { stdio: \"pipe\" });\n\t\t// Check for ENOENT error (command not found)\n\t\treturn result.error === undefined || result.error === null;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n// Get the path to a tool (system-wide or in our tools dir)\nexport function getToolPath(tool: \"fd\" | \"rg\"): string | null {\n\tconst config = TOOLS[tool];\n\tif (!config) return null;\n\n\t// Check our tools directory first\n\tconst localPath = join(TOOLS_DIR, config.binaryName + (platform() === \"win32\" ? \".exe\" : \"\"));\n\tif (existsSync(localPath)) {\n\t\treturn localPath;\n\t}\n\n\t// Check system PATH - if found, just return the command name (it's in PATH)\n\tconst systemBinaryNames = config.systemBinaryNames ?? [config.binaryName];\n\tfor (const systemBinaryName of systemBinaryNames) {\n\t\tif (commandExists(systemBinaryName)) {\n\t\t\treturn systemBinaryName;\n\t\t}\n\t}\n\n\treturn null;\n}\n\n// Fetch latest release version from GitHub\nasync function getLatestVersion(repo: string): Promise<string> {\n\tconst response = await fetch(`https://api.github.com/repos/${repo}/releases/latest`, {\n\t\theaders: { \"User-Agent\": `${APP_NAME}-coding-agent` },\n\t\tsignal: AbortSignal.timeout(NETWORK_TIMEOUT_MS),\n\t});\n\n\tif (!response.ok) {\n\t\tthrow new Error(`GitHub API error: ${response.status}`);\n\t}\n\n\tconst data = (await response.json()) as { tag_name: string };\n\treturn data.tag_name.replace(/^v/, \"\");\n}\n\n// Download a file from URL\nasync function downloadFile(url: string, dest: string): Promise<void> {\n\tconst response = await fetch(url, {\n\t\tsignal: AbortSignal.timeout(DOWNLOAD_TIMEOUT_MS),\n\t});\n\n\tif (!response.ok) {\n\t\tthrow new Error(`Failed to download: ${response.status}`);\n\t}\n\n\tif (!response.body) {\n\t\tthrow new Error(\"No response body\");\n\t}\n\n\tconst fileStream = createWriteStream(dest);\n\tawait pipeline(Readable.fromWeb(response.body as any), fileStream);\n}\n\nfunction findBinaryRecursively(rootDir: string, binaryFileName: string): string | null {\n\tconst stack: string[] = [rootDir];\n\n\twhile (stack.length > 0) {\n\t\tconst currentDir = stack.pop();\n\t\tif (!currentDir) continue;\n\n\t\tconst entries = readdirSync(currentDir, { withFileTypes: true });\n\t\tfor (const entry of entries) {\n\t\t\tconst fullPath = join(currentDir, entry.name);\n\t\t\tif (entry.isFile() && entry.name === binaryFileName) {\n\t\t\t\treturn fullPath;\n\t\t\t}\n\t\t\tif (entry.isDirectory()) {\n\t\t\t\tstack.push(fullPath);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn null;\n}\n\nfunction formatSpawnFailure(result: SpawnSyncReturns<Buffer>): string {\n\tif (result.error?.message) {\n\t\treturn result.error.message;\n\t}\n\tconst stderr = result.stderr?.toString().trim();\n\tif (stderr) {\n\t\treturn stderr;\n\t}\n\tconst stdout = result.stdout?.toString().trim();\n\tif (stdout) {\n\t\treturn stdout;\n\t}\n\treturn `exit status ${result.status ?? \"unknown\"}`;\n}\n\nfunction runExtractionCommand(command: string, args: string[]): string | null {\n\tconst result = spawnSync(command, args, { stdio: \"pipe\" });\n\tif (!result.error && result.status === 0) {\n\t\treturn null;\n\t}\n\treturn `${command}: ${formatSpawnFailure(result)}`;\n}\n\nfunction extractTarGzArchive(archivePath: string, extractDir: string, assetName: string): void {\n\tconst failure = runExtractionCommand(\"tar\", [\"xzf\", archivePath, \"-C\", extractDir]);\n\tif (failure) {\n\t\tthrow new Error(`Failed to extract ${assetName}: ${failure}`);\n\t}\n}\n\nfunction getWindowsTarCommand(): string {\n\tconst systemRoot = process.env.SystemRoot ?? process.env.WINDIR;\n\tif (systemRoot) {\n\t\tconst systemTar = join(systemRoot, \"System32\", \"tar.exe\");\n\t\tif (existsSync(systemTar)) {\n\t\t\treturn systemTar;\n\t\t}\n\t}\n\treturn \"tar.exe\";\n}\n\nfunction extractZipArchive(archivePath: string, extractDir: string, assetName: string): void {\n\tconst failures: string[] = [];\n\n\tif (platform() === \"win32\") {\n\t\t// Windows ships bsdtar as tar.exe, which supports zip files. Prefer the\n\t\t// System32 binary over Git Bash's GNU tar, which does not handle zip archives.\n\t\tconst tarFailure = runExtractionCommand(getWindowsTarCommand(), [\"xf\", archivePath, \"-C\", extractDir]);\n\t\tif (!tarFailure) return;\n\t\tfailures.push(tarFailure);\n\n\t\tconst script =\n\t\t\t\"& { param($archive, $destination) $ErrorActionPreference = 'Stop'; Expand-Archive -LiteralPath $archive -DestinationPath $destination -Force }\";\n\t\tconst powershellFailure = runExtractionCommand(\"powershell.exe\", [\n\t\t\t\"-NoLogo\",\n\t\t\t\"-NoProfile\",\n\t\t\t\"-NonInteractive\",\n\t\t\t\"-ExecutionPolicy\",\n\t\t\t\"Bypass\",\n\t\t\t\"-Command\",\n\t\t\tscript,\n\t\t\tarchivePath,\n\t\t\textractDir,\n\t\t]);\n\t\tif (!powershellFailure) return;\n\t\tfailures.push(powershellFailure);\n\t} else {\n\t\tconst unzipFailure = runExtractionCommand(\"unzip\", [\"-q\", archivePath, \"-d\", extractDir]);\n\t\tif (!unzipFailure) return;\n\t\tfailures.push(unzipFailure);\n\n\t\tconst tarFailure = runExtractionCommand(\"tar\", [\"xf\", archivePath, \"-C\", extractDir]);\n\t\tif (!tarFailure) return;\n\t\tfailures.push(tarFailure);\n\t}\n\n\tthrow new Error(`Failed to extract ${assetName}: ${failures.join(\"; \")}`);\n}\n\n// Download and install a tool\nasync function downloadTool(tool: \"fd\" | \"rg\"): Promise<string> {\n\tconst config = TOOLS[tool];\n\tif (!config) throw new Error(`Unknown tool: ${tool}`);\n\n\tconst plat = platform();\n\tconst architecture = arch();\n\n\t// Get latest version\n\tlet version = await getLatestVersion(config.repo);\n\tif (tool === \"fd\" && plat === \"darwin\" && architecture === \"x64\") {\n\t\tversion = \"10.3.0\";\n\t}\n\n\t// Get asset name for this platform\n\tconst assetName = config.getAssetName(version, plat, architecture);\n\tif (!assetName) {\n\t\tthrow new Error(`Unsupported platform: ${plat}/${architecture}`);\n\t}\n\n\t// Create tools directory\n\tmkdirSync(TOOLS_DIR, { recursive: true });\n\n\tconst downloadUrl = `https://github.com/${config.repo}/releases/download/${config.tagPrefix}${version}/${assetName}`;\n\tconst archivePath = join(TOOLS_DIR, assetName);\n\tconst binaryExt = plat === \"win32\" ? \".exe\" : \"\";\n\tconst binaryPath = join(TOOLS_DIR, config.binaryName + binaryExt);\n\n\t// Download\n\tawait downloadFile(downloadUrl, archivePath);\n\n\t// Extract into a unique temp directory. fd and rg downloads can run concurrently\n\t// during startup, so sharing a fixed directory causes races.\n\tconst extractDir = join(\n\t\tTOOLS_DIR,\n\t\t`extract_tmp_${config.binaryName}_${process.pid}_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`,\n\t);\n\tmkdirSync(extractDir, { recursive: true });\n\n\ttry {\n\t\tif (assetName.endsWith(\".tar.gz\")) {\n\t\t\textractTarGzArchive(archivePath, extractDir, assetName);\n\t\t} else if (assetName.endsWith(\".zip\")) {\n\t\t\textractZipArchive(archivePath, extractDir, assetName);\n\t\t} else {\n\t\t\tthrow new Error(`Unsupported archive format: ${assetName}`);\n\t\t}\n\n\t\t// Find the binary in extracted files. Some archives contain files directly\n\t\t// at root, others nest under a versioned subdirectory.\n\t\tconst binaryFileName = config.binaryName + binaryExt;\n\t\tconst extractedDir = join(extractDir, assetName.replace(/\\.(tar\\.gz|zip)$/, \"\"));\n\t\tconst extractedBinaryCandidates = [join(extractedDir, binaryFileName), join(extractDir, binaryFileName)];\n\t\tlet extractedBinary = extractedBinaryCandidates.find((candidate) => existsSync(candidate));\n\n\t\tif (!extractedBinary) {\n\t\t\textractedBinary = findBinaryRecursively(extractDir, binaryFileName) ?? undefined;\n\t\t}\n\n\t\tif (extractedBinary) {\n\t\t\trenameSync(extractedBinary, binaryPath);\n\t\t} else {\n\t\t\tthrow new Error(`Binary not found in archive: expected ${binaryFileName} under ${extractDir}`);\n\t\t}\n\n\t\t// Make executable (Unix only)\n\t\tif (plat !== \"win32\") {\n\t\t\tchmodSync(binaryPath, 0o755);\n\t\t}\n\t} finally {\n\t\t// Cleanup\n\t\trmSync(archivePath, { force: true });\n\t\trmSync(extractDir, { recursive: true, force: true });\n\t}\n\n\treturn binaryPath;\n}\n\n// Termux package names for tools\nconst TERMUX_PACKAGES: Record<string, string> = {\n\tfd: \"fd\",\n\trg: \"ripgrep\",\n};\n\n// Ensure a tool is available, downloading if necessary\n// Returns the path to the tool, or null if unavailable\nexport async function ensureTool(tool: \"fd\" | \"rg\", silent: boolean = false): Promise<string | undefined> {\n\tconst existingPath = getToolPath(tool);\n\tif (existingPath) {\n\t\treturn existingPath;\n\t}\n\n\tconst config = TOOLS[tool];\n\tif (!config) return undefined;\n\n\tif (isOfflineModeEnabled()) {\n\t\tif (!silent) {\n\t\t\tconsole.log(chalk.yellow(`${config.name} not found. Offline mode enabled, skipping download.`));\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t// On Android/Termux, Linux binaries don't work due to Bionic libc incompatibility.\n\t// Users must install via pkg.\n\tif (platform() === \"android\") {\n\t\tconst pkgName = TERMUX_PACKAGES[tool] ?? tool;\n\t\tif (!silent) {\n\t\t\tconsole.log(chalk.yellow(`${config.name} not found. Install with: pkg install ${pkgName}`));\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t// Tool not found - download it\n\tif (!silent) {\n\t\tconsole.log(chalk.dim(`${config.name} not found. Downloading...`));\n\t}\n\n\ttry {\n\t\tconst path = await downloadTool(tool);\n\t\tif (!silent) {\n\t\t\tconsole.log(chalk.dim(`${config.name} installed to ${path}`));\n\t\t}\n\t\treturn path;\n\t} catch (e) {\n\t\tif (!silent) {\n\t\t\tconsole.log(chalk.yellow(`Failed to download ${config.name}: ${e instanceof Error ? e.message : e}`));\n\t\t}\n\t\treturn undefined;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"tools-manager.js","sourceRoot":"","sources":["../../src/utils/tools-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import chalk from \"chalk\";\nimport { type SpawnSyncReturns, spawnSync } from \"child_process\";\nimport { chmodSync, createWriteStream, existsSync, mkdirSync, readdirSync, renameSync, rmSync } from \"fs\";\nimport { arch, platform } from \"os\";\nimport { join } from \"path\";\nimport { Readable } from \"stream\";\nimport { pipeline } from \"stream/promises\";\nimport { APP_NAME, getBinDir } from \"../config.js\";\n\nconst TOOLS_DIR = getBinDir();\nconst NETWORK_TIMEOUT_MS = 10_000;\nconst DOWNLOAD_TIMEOUT_MS = 120_000;\n\n// SCRAMJET-DIVERGENCE: prefer SCRAMJET_OFFLINE, fall back to PI_OFFLINE.\nfunction isOfflineModeEnabled(): boolean {\n\tconst value = process.env.SCRAMJET_OFFLINE || process.env.PI_OFFLINE;\n\tif (!value) return false;\n\treturn value === \"1\" || value.toLowerCase() === \"true\" || value.toLowerCase() === \"yes\";\n}\n\ninterface ToolConfig {\n\tname: string;\n\trepo: string; // GitHub repo (e.g., \"sharkdp/fd\")\n\tbinaryName: string; // Name of the binary inside the archive\n\tsystemBinaryNames?: string[]; // Alternative system command names to try before downloading\n\ttagPrefix: string; // Prefix for tags (e.g., \"v\" for v1.0.0, \"\" for 1.0.0)\n\tgetAssetName: (version: string, plat: string, architecture: string) => string | null;\n}\n\nconst TOOLS: Record<string, ToolConfig> = {\n\tfd: {\n\t\tname: \"fd\",\n\t\trepo: \"sharkdp/fd\",\n\t\tbinaryName: \"fd\",\n\t\tsystemBinaryNames: [\"fd\", \"fdfind\"],\n\t\ttagPrefix: \"v\",\n\t\tgetAssetName: (version, plat, architecture) => {\n\t\t\tif (plat === \"darwin\") {\n\t\t\t\tconst archStr = architecture === \"arm64\" ? \"aarch64\" : \"x86_64\";\n\t\t\t\treturn `fd-v${version}-${archStr}-apple-darwin.tar.gz`;\n\t\t\t} else if (plat === \"linux\") {\n\t\t\t\tconst archStr = architecture === \"arm64\" ? \"aarch64\" : \"x86_64\";\n\t\t\t\treturn `fd-v${version}-${archStr}-unknown-linux-gnu.tar.gz`;\n\t\t\t} else if (plat === \"win32\") {\n\t\t\t\tconst archStr = architecture === \"arm64\" ? \"aarch64\" : \"x86_64\";\n\t\t\t\treturn `fd-v${version}-${archStr}-pc-windows-msvc.zip`;\n\t\t\t}\n\t\t\treturn null;\n\t\t},\n\t},\n\trg: {\n\t\tname: \"ripgrep\",\n\t\trepo: \"BurntSushi/ripgrep\",\n\t\tbinaryName: \"rg\",\n\t\ttagPrefix: \"\",\n\t\tgetAssetName: (version, plat, architecture) => {\n\t\t\tif (plat === \"darwin\") {\n\t\t\t\tconst archStr = architecture === \"arm64\" ? \"aarch64\" : \"x86_64\";\n\t\t\t\treturn `ripgrep-${version}-${archStr}-apple-darwin.tar.gz`;\n\t\t\t} else if (plat === \"linux\") {\n\t\t\t\tif (architecture === \"arm64\") {\n\t\t\t\t\treturn `ripgrep-${version}-aarch64-unknown-linux-gnu.tar.gz`;\n\t\t\t\t}\n\t\t\t\treturn `ripgrep-${version}-x86_64-unknown-linux-musl.tar.gz`;\n\t\t\t} else if (plat === \"win32\") {\n\t\t\t\tconst archStr = architecture === \"arm64\" ? \"aarch64\" : \"x86_64\";\n\t\t\t\treturn `ripgrep-${version}-${archStr}-pc-windows-msvc.zip`;\n\t\t\t}\n\t\t\treturn null;\n\t\t},\n\t},\n};\n\n// Check if a command exists in PATH by trying to run it\nfunction commandExists(cmd: string): boolean {\n\ttry {\n\t\tconst result = spawnSync(cmd, [\"--version\"], { stdio: \"pipe\" });\n\t\t// Check for ENOENT error (command not found)\n\t\treturn result.error === undefined || result.error === null;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n// Get the path to a tool (system-wide or in our tools dir)\nexport function getToolPath(tool: \"fd\" | \"rg\"): string | null {\n\tconst config = TOOLS[tool];\n\tif (!config) return null;\n\n\t// Check our tools directory first\n\tconst localPath = join(TOOLS_DIR, config.binaryName + (platform() === \"win32\" ? \".exe\" : \"\"));\n\tif (existsSync(localPath)) {\n\t\treturn localPath;\n\t}\n\n\t// Check system PATH - if found, just return the command name (it's in PATH)\n\tconst systemBinaryNames = config.systemBinaryNames ?? [config.binaryName];\n\tfor (const systemBinaryName of systemBinaryNames) {\n\t\tif (commandExists(systemBinaryName)) {\n\t\t\treturn systemBinaryName;\n\t\t}\n\t}\n\n\treturn null;\n}\n\n// Fetch latest release version from GitHub\nasync function getLatestVersion(repo: string): Promise<string> {\n\tconst response = await fetch(`https://api.github.com/repos/${repo}/releases/latest`, {\n\t\theaders: { \"User-Agent\": `${APP_NAME}-coding-agent` },\n\t\tsignal: AbortSignal.timeout(NETWORK_TIMEOUT_MS),\n\t});\n\n\tif (!response.ok) {\n\t\tthrow new Error(`GitHub API error: ${response.status}`);\n\t}\n\n\tconst data = (await response.json()) as { tag_name: string };\n\treturn data.tag_name.replace(/^v/, \"\");\n}\n\n// Download a file from URL\nasync function downloadFile(url: string, dest: string): Promise<void> {\n\tconst response = await fetch(url, {\n\t\tsignal: AbortSignal.timeout(DOWNLOAD_TIMEOUT_MS),\n\t});\n\n\tif (!response.ok) {\n\t\tthrow new Error(`Failed to download: ${response.status}`);\n\t}\n\n\tif (!response.body) {\n\t\tthrow new Error(\"No response body\");\n\t}\n\n\tconst fileStream = createWriteStream(dest);\n\tawait pipeline(Readable.fromWeb(response.body as any), fileStream);\n}\n\nfunction findBinaryRecursively(rootDir: string, binaryFileName: string): string | null {\n\tconst stack: string[] = [rootDir];\n\n\twhile (stack.length > 0) {\n\t\tconst currentDir = stack.pop();\n\t\tif (!currentDir) continue;\n\n\t\tconst entries = readdirSync(currentDir, { withFileTypes: true });\n\t\tfor (const entry of entries) {\n\t\t\tconst fullPath = join(currentDir, entry.name);\n\t\t\tif (entry.isFile() && entry.name === binaryFileName) {\n\t\t\t\treturn fullPath;\n\t\t\t}\n\t\t\tif (entry.isDirectory()) {\n\t\t\t\tstack.push(fullPath);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn null;\n}\n\nfunction formatSpawnFailure(result: SpawnSyncReturns<Buffer>): string {\n\tif (result.error?.message) {\n\t\treturn result.error.message;\n\t}\n\tconst stderr = result.stderr?.toString().trim();\n\tif (stderr) {\n\t\treturn stderr;\n\t}\n\tconst stdout = result.stdout?.toString().trim();\n\tif (stdout) {\n\t\treturn stdout;\n\t}\n\treturn `exit status ${result.status ?? \"unknown\"}`;\n}\n\nfunction runExtractionCommand(command: string, args: string[]): string | null {\n\tconst result = spawnSync(command, args, { stdio: \"pipe\" });\n\tif (!result.error && result.status === 0) {\n\t\treturn null;\n\t}\n\treturn `${command}: ${formatSpawnFailure(result)}`;\n}\n\nfunction extractTarGzArchive(archivePath: string, extractDir: string, assetName: string): void {\n\tconst failure = runExtractionCommand(\"tar\", [\"xzf\", archivePath, \"-C\", extractDir]);\n\tif (failure) {\n\t\tthrow new Error(`Failed to extract ${assetName}: ${failure}`);\n\t}\n}\n\nfunction getWindowsTarCommand(): string {\n\tconst systemRoot = process.env.SystemRoot ?? process.env.WINDIR;\n\tif (systemRoot) {\n\t\tconst systemTar = join(systemRoot, \"System32\", \"tar.exe\");\n\t\tif (existsSync(systemTar)) {\n\t\t\treturn systemTar;\n\t\t}\n\t}\n\treturn \"tar.exe\";\n}\n\nfunction extractZipArchive(archivePath: string, extractDir: string, assetName: string): void {\n\tconst failures: string[] = [];\n\n\tif (platform() === \"win32\") {\n\t\t// Windows ships bsdtar as tar.exe, which supports zip files. Prefer the\n\t\t// System32 binary over Git Bash's GNU tar, which does not handle zip archives.\n\t\tconst tarFailure = runExtractionCommand(getWindowsTarCommand(), [\"xf\", archivePath, \"-C\", extractDir]);\n\t\tif (!tarFailure) return;\n\t\tfailures.push(tarFailure);\n\n\t\tconst script =\n\t\t\t\"& { param($archive, $destination) $ErrorActionPreference = 'Stop'; Expand-Archive -LiteralPath $archive -DestinationPath $destination -Force }\";\n\t\tconst powershellFailure = runExtractionCommand(\"powershell.exe\", [\n\t\t\t\"-NoLogo\",\n\t\t\t\"-NoProfile\",\n\t\t\t\"-NonInteractive\",\n\t\t\t\"-ExecutionPolicy\",\n\t\t\t\"Bypass\",\n\t\t\t\"-Command\",\n\t\t\tscript,\n\t\t\tarchivePath,\n\t\t\textractDir,\n\t\t]);\n\t\tif (!powershellFailure) return;\n\t\tfailures.push(powershellFailure);\n\t} else {\n\t\tconst unzipFailure = runExtractionCommand(\"unzip\", [\"-q\", archivePath, \"-d\", extractDir]);\n\t\tif (!unzipFailure) return;\n\t\tfailures.push(unzipFailure);\n\n\t\tconst tarFailure = runExtractionCommand(\"tar\", [\"xf\", archivePath, \"-C\", extractDir]);\n\t\tif (!tarFailure) return;\n\t\tfailures.push(tarFailure);\n\t}\n\n\tthrow new Error(`Failed to extract ${assetName}: ${failures.join(\"; \")}`);\n}\n\n// Download and install a tool\nasync function downloadTool(tool: \"fd\" | \"rg\"): Promise<string> {\n\tconst config = TOOLS[tool];\n\tif (!config) throw new Error(`Unknown tool: ${tool}`);\n\n\tconst plat = platform();\n\tconst architecture = arch();\n\n\t// Get latest version\n\tlet version = await getLatestVersion(config.repo);\n\tif (tool === \"fd\" && plat === \"darwin\" && architecture === \"x64\") {\n\t\tversion = \"10.3.0\";\n\t}\n\n\t// Get asset name for this platform\n\tconst assetName = config.getAssetName(version, plat, architecture);\n\tif (!assetName) {\n\t\tthrow new Error(`Unsupported platform: ${plat}/${architecture}`);\n\t}\n\n\t// Create tools directory\n\tmkdirSync(TOOLS_DIR, { recursive: true });\n\n\tconst downloadUrl = `https://github.com/${config.repo}/releases/download/${config.tagPrefix}${version}/${assetName}`;\n\tconst archivePath = join(TOOLS_DIR, assetName);\n\tconst binaryExt = plat === \"win32\" ? \".exe\" : \"\";\n\tconst binaryPath = join(TOOLS_DIR, config.binaryName + binaryExt);\n\n\t// Download\n\tawait downloadFile(downloadUrl, archivePath);\n\n\t// Extract into a unique temp directory. fd and rg downloads can run concurrently\n\t// during startup, so sharing a fixed directory causes races.\n\tconst extractDir = join(\n\t\tTOOLS_DIR,\n\t\t`extract_tmp_${config.binaryName}_${process.pid}_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`,\n\t);\n\tmkdirSync(extractDir, { recursive: true });\n\n\ttry {\n\t\tif (assetName.endsWith(\".tar.gz\")) {\n\t\t\textractTarGzArchive(archivePath, extractDir, assetName);\n\t\t} else if (assetName.endsWith(\".zip\")) {\n\t\t\textractZipArchive(archivePath, extractDir, assetName);\n\t\t} else {\n\t\t\tthrow new Error(`Unsupported archive format: ${assetName}`);\n\t\t}\n\n\t\t// Find the binary in extracted files. Some archives contain files directly\n\t\t// at root, others nest under a versioned subdirectory.\n\t\tconst binaryFileName = config.binaryName + binaryExt;\n\t\tconst extractedDir = join(extractDir, assetName.replace(/\\.(tar\\.gz|zip)$/, \"\"));\n\t\tconst extractedBinaryCandidates = [join(extractedDir, binaryFileName), join(extractDir, binaryFileName)];\n\t\tlet extractedBinary = extractedBinaryCandidates.find((candidate) => existsSync(candidate));\n\n\t\tif (!extractedBinary) {\n\t\t\textractedBinary = findBinaryRecursively(extractDir, binaryFileName) ?? undefined;\n\t\t}\n\n\t\tif (extractedBinary) {\n\t\t\trenameSync(extractedBinary, binaryPath);\n\t\t} else {\n\t\t\tthrow new Error(`Binary not found in archive: expected ${binaryFileName} under ${extractDir}`);\n\t\t}\n\n\t\t// Make executable (Unix only)\n\t\tif (plat !== \"win32\") {\n\t\t\tchmodSync(binaryPath, 0o755);\n\t\t}\n\t} finally {\n\t\t// Cleanup\n\t\trmSync(archivePath, { force: true });\n\t\trmSync(extractDir, { recursive: true, force: true });\n\t}\n\n\treturn binaryPath;\n}\n\n// Termux package names for tools\nconst TERMUX_PACKAGES: Record<string, string> = {\n\tfd: \"fd\",\n\trg: \"ripgrep\",\n};\n\n// Ensure a tool is available, downloading if necessary\n// Returns the path to the tool, or null if unavailable\n// SCRAMJET-DIVERGENCE: interactive startup owns presentation of provisioning diagnostics.\nexport async function ensureTool(\n\ttool: \"fd\" | \"rg\",\n\tsilent: boolean = false,\n\treport: (message: string) => void = console.log,\n): Promise<string | undefined> {\n\tconst existingPath = getToolPath(tool);\n\tif (existingPath) {\n\t\treturn existingPath;\n\t}\n\n\tconst config = TOOLS[tool];\n\tif (!config) return undefined;\n\n\tif (isOfflineModeEnabled()) {\n\t\tif (!silent) {\n\t\t\treport(chalk.yellow(`${config.name} not found. Offline mode enabled, skipping download.`));\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t// On Android/Termux, Linux binaries don't work due to Bionic libc incompatibility.\n\t// Users must install via pkg.\n\tif (platform() === \"android\") {\n\t\tconst pkgName = TERMUX_PACKAGES[tool] ?? tool;\n\t\tif (!silent) {\n\t\t\treport(chalk.yellow(`${config.name} not found. Install with: pkg install ${pkgName}`));\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t// Tool not found - download it\n\tif (!silent) {\n\t\treport(chalk.dim(`${config.name} not found. Downloading...`));\n\t}\n\n\ttry {\n\t\tconst path = await downloadTool(tool);\n\t\tif (!silent) {\n\t\t\treport(chalk.dim(`${config.name} installed to ${path}`));\n\t\t}\n\t\treturn path;\n\t} catch (e) {\n\t\tif (!silent) {\n\t\t\treport(chalk.yellow(`Failed to download ${config.name}: ${e instanceof Error ? e.message : e}`));\n\t\t}\n\t\treturn undefined;\n\t}\n}\n"]}
|
package/docs/extensions.md
CHANGED
|
@@ -2237,6 +2237,16 @@ Extensions can interact with users via `ctx.ui` methods and customize how messag
|
|
|
2237
2237
|
- Autocomplete providers layered on top of built-in slash/path completion (addAutocompleteProvider)
|
|
2238
2238
|
- Custom footers (setFooter)
|
|
2239
2239
|
|
|
2240
|
+
### Retained viewport and input ownership
|
|
2241
|
+
|
|
2242
|
+
InteractiveMode uses the existing component presentation in an alternate-screen retained viewport. Ordinary `render(width)`, tool `renderCall`/`renderResult`, result/session schemas and HTML export contracts are unchanged. Render the complete logical text rather than clipping it to terminal height. Components receive terminal width minus the reserved scrollbar column; images alone may use the optional `setViewportHeight` bound. Standard Container/Box propagate it; custom image wrappers must forward it. Unrecognized custom graphics envelopes display a placeholder rather than an unsafe clipped placement.
|
|
2243
|
+
|
|
2244
|
+
`ctx.ui.onTerminalInput()` listeners run after the viewport listener. They do not receive consumed pointer packets, selection-copy keys, Ctrl+Home/Ctrl+End transcript navigation or detached PageUp/PageDown/Escape when the input owner permits viewport navigation. Ordinary Home/End pass through for editor line-start/end behavior. Do not use raw listeners to compete for transcript pointer ownership. Focused overlays keep keyboard precedence, and conflicting selector bindings precede configurable Alt+PageUp/Alt+PageDown transcript actions. Focus-in/out reports are consumed rather than delivered as ordinary input. The viewport keeps no session-journal state; session reconstruction discards browsing/selection state.
|
|
2245
|
+
|
|
2246
|
+
The input area is docked by default, with widgets preserving their above/below-editor placement. Docking can change live without replacing component instances. Non-fitting extension content remains reachable in an explained undocked retained flow. Custom editors can implement `setHeightLimit(limits)`, where the callback returns `{ rows, text }` for the current total input budget and maximum wrapped text rows. Respect the budget without losing draft content, keep the cursor and active completion choice visible, and use the effective text-window height for paging. This is separate from the image-only `setViewportHeight` API. Editors with completion menus can also expose optional `isShowingAutocomplete(): boolean`; InteractiveMode then reveals a hidden editor slot independently of its hardware cursor and consumes acceptance until the slot is visible and its current paint has flushed. Built-in `CustomEditor` inherits this capability. See [tui.md](tui.md#retained-viewport-api) for projection, selection and geometry contracts.
|
|
2247
|
+
|
|
2248
|
+
Kitty-capable viewport terminals explicitly encode printable keys as well as modified keys. Match actions against raw input with `matchesKey()`/the injected keybinding manager before using `decodeKittyPrintable(data) ?? data` for printable-mode mappings; decoding first can obscure special-key identities such as keypad Enter. Do not assume a printable key is one raw byte. Raw listeners must ignore `isKeyRelease(data)` unless they intentionally handle releases; focused components filter releases by default. The shipped [modal editor](../examples/extensions/modal-editor.ts) demonstrates the printable-key migration. No blanket compatibility claim is made for external raw-byte listeners or graphics wrappers; see [tui.md](tui.md) for exact viewport APIs and [terminal-setup.md](terminal-setup.md#native-compatibility-evidence) for tested configurations.
|
|
2249
|
+
|
|
2240
2250
|
### Dialogs
|
|
2241
2251
|
|
|
2242
2252
|
```typescript
|
|
@@ -2455,18 +2465,18 @@ See [github-issue-autocomplete.ts](../examples/extensions/github-issue-autocompl
|
|
|
2455
2465
|
For complex UI, use `ctx.ui.custom()`. This temporarily replaces the editor with your component until `done()` is called:
|
|
2456
2466
|
|
|
2457
2467
|
```typescript
|
|
2458
|
-
import { Text
|
|
2468
|
+
import { Text } from "@leanandmean/tui";
|
|
2459
2469
|
|
|
2460
|
-
const result = await ctx.ui.custom<boolean>((
|
|
2470
|
+
const result = await ctx.ui.custom<boolean>((_tui, _theme, keybindings, done) => {
|
|
2461
2471
|
const text = new Text("Press Enter to confirm, Escape to cancel", 1, 1);
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2472
|
+
return {
|
|
2473
|
+
render: (width) => text.render(width),
|
|
2474
|
+
invalidate: () => text.invalidate(),
|
|
2475
|
+
handleInput(data) {
|
|
2476
|
+
if (keybindings.matches(data, "tui.select.confirm")) done(true);
|
|
2477
|
+
else if (keybindings.matches(data, "tui.select.cancel")) done(false);
|
|
2478
|
+
},
|
|
2467
2479
|
};
|
|
2468
|
-
|
|
2469
|
-
return text;
|
|
2470
2480
|
});
|
|
2471
2481
|
|
|
2472
2482
|
if (result) {
|
|
@@ -2480,6 +2490,8 @@ The callback receives:
|
|
|
2480
2490
|
- `keybindings` - App keybinding manager (for checking shortcuts)
|
|
2481
2491
|
- `done(value)` - Call to close component and return value
|
|
2482
2492
|
|
|
2493
|
+
Ordinary editor-slot custom UI can opt into actual layout allocation with `ctx.ui.custom(factory, { onAvailableHeight(rows) { maximumRows = rows; } })`, where `maximumRows` is invocation-local state read during rendering. The callback receives `undefined` at mounting/release and a numeric row budget before each allocated render; it can run more than once per frame. It must not request another render or change focus, and allocation does not certify docking, visibility or flushing. Retained undocked rendering can allocate rows too; committed rendering has no numeric allocation. Below-minimum geometry skips rendering rather than delivering a temporary budget, and recovery supplies a fresh allocation. Other components are unchanged unless they explicitly opt in. The option is incompatible with overlays and tool-attached context and is rejected before the factory runs; it is separate from image-only `setViewportHeight` and editor text-height preferences. Allocation-notification errors reject the owning custom UI request and release/dispose its control; release-notification errors are reported without stranding completion. See [allocated custom input height](tui.md#allocated-custom-input-height).
|
|
2494
|
+
|
|
2483
2495
|
A pending sequential tool can attach immutable long-form context to its own tool row before compact controls become interactive. Pass the current `toolCallId` from the tool's `execute()` method:
|
|
2484
2496
|
|
|
2485
2497
|
```typescript
|
|
@@ -2494,7 +2506,11 @@ const result = await ctx.ui.custom(
|
|
|
2494
2506
|
);
|
|
2495
2507
|
```
|
|
2496
2508
|
|
|
2497
|
-
The context is
|
|
2509
|
+
The complete immutable context is installed at that pending tool's transcript position. In both renderer modes, the editor is defocused and a required initial flush must succeed before controls receive focus. Missing/non-leading/settled tool rows, context replaced before that flush settles, and missing or failed flushing reject the request through attachment cleanup. Context is visual-only, not persisted or sent to the model. Use this only from the sequential tool whose id is supplied.
|
|
2510
|
+
|
|
2511
|
+
In default **retained mode**, the context remains browseable through Scramjet's scrollbar even when taller than the screen; it need not all be simultaneously visible or emitted into native scrollback. Controls require current-paint flush evidence, complete rendering of the full context and controls, and whole-control visibility. Clipped context (including offscreen rows) or controls that cannot fit fail closed. If browsing hides controls, the first activation reveals and flushes them without approving; only subsequent input can authorize. Attachment currentness and these presentation guards are rechecked on input.
|
|
2512
|
+
|
|
2513
|
+
With startup-only **`tuiMode: "committed"`**, `commitNow({ requireFlush: true })` emits the complete context into committed native history and waits for the initial flush before focusing controls. The mutable canvas remains tail-windowed; this mode does **not** provide Scramjet scrollbar access, retained render-completeness/whole-control-visibility checks, or reveal-before-subsequent-activation protection. Do not rely on those retained-only guarantees when supporting committed compatibility mode.
|
|
2498
2514
|
|
|
2499
2515
|
See [tui.md](tui.md) for the full component API.
|
|
2500
2516
|
|
|
@@ -2540,7 +2556,7 @@ class VimEditor extends CustomEditor {
|
|
|
2540
2556
|
this.mode = "normal";
|
|
2541
2557
|
return;
|
|
2542
2558
|
}
|
|
2543
|
-
if (this.mode === "normal" && data
|
|
2559
|
+
if (this.mode === "normal" && matchesKey(data, "i")) {
|
|
2544
2560
|
this.mode = "insert";
|
|
2545
2561
|
return;
|
|
2546
2562
|
}
|
package/docs/keybindings.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Keybindings
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Action keybindings can be customized via `~/.scramjet/agent/keybindings.json`. Each action can be bound to one or more keys.
|
|
4
4
|
|
|
5
5
|
The config file uses the same namespaced keybinding ids that Scramjet uses internally and that extension authors use in `keyHint()` and injected `keybindings` managers.
|
|
6
6
|
|
|
@@ -20,8 +20,30 @@ After editing `keybindings.json`, run `/reload` in Scramjet to apply the changes
|
|
|
20
20
|
|
|
21
21
|
Modifier combinations: `ctrl+shift+x`, `alt+ctrl+x`, `ctrl+shift+alt+x`, `ctrl+1`, etc.
|
|
22
22
|
|
|
23
|
+
## Transcript browsing precedence
|
|
24
|
+
|
|
25
|
+
Interactive mode's retained viewport owns mouse wheel/trackpad scrolling, the rightmost draggable scrollbar and ordinary drag selection. Right-click a nonempty selection or use `tui.input.copy` (Ctrl+C by default) to copy displayed text. Without a transcript selection, the same key keeps its focused-component/application behavior. Escape clears selection and returns to the live tail.
|
|
26
|
+
|
|
27
|
+
While detached from the tail with the editor owning input, the viewport consumes this fixed set before editor bindings; focused selectors retain their own navigation and cancellation bindings:
|
|
28
|
+
|
|
29
|
+
| Key | Browsing action |
|
|
30
|
+
|-----|-----------------|
|
|
31
|
+
| PageUp / PageDown | Scroll one viewport page |
|
|
32
|
+
| Escape | Return to the live tail |
|
|
33
|
+
|
|
34
|
+
Home/End retain editor line-start/end behavior at every transcript position. Ctrl+Home goes to the transcript beginning and Ctrl+End goes to its bottom and resumes following, whether currently following or detached. Docked input and configured tool/thinking presentation toggles preserve the transcript anchor; undocked ordinary editing reveals the editor cursor. Submitting nonempty editor input resumes following before command routing or queueing, including Enter and Alt+Enter. New user-message delivery also resumes following; passive output does not. At the tail, unmodified paging retains its editor/list meanings. Focused overlays take precedence, and focused selector bindings take precedence over both fixed and configurable viewport actions. In particular, Escape cancels a focused settings selector rather than merely returning its transcript to the tail. If tool-attached approval controls are hidden by browsing, the first activation reveals and flushes them without approving; a later activation can approve.
|
|
35
|
+
|
|
36
|
+
The fixed detached-only keys above remain separate from `tui.viewport.pageUp` and `tui.viewport.pageDown`, which default to Alt+PageUp and Alt+PageDown and work from the tail as well as while browsing. Terminal/desktop interception can require remapping these configurable actions. See [terminal-setup.md](terminal-setup.md#transcript-browsing-and-copying) for terminal-menu and clipboard requirements.
|
|
37
|
+
|
|
23
38
|
## All Actions
|
|
24
39
|
|
|
40
|
+
### Transcript Navigation
|
|
41
|
+
|
|
42
|
+
| Keybinding id | Default | Description |
|
|
43
|
+
|--------|---------|-------------|
|
|
44
|
+
| `tui.viewport.pageUp` | `alt+pageUp` | Browse one transcript page upward, including from the tail |
|
|
45
|
+
| `tui.viewport.pageDown` | `alt+pageDown` | Browse one transcript page downward |
|
|
46
|
+
|
|
25
47
|
### TUI Editor Cursor Movement
|
|
26
48
|
|
|
27
49
|
| Keybinding id | Default | Description |
|
package/docs/settings.md
CHANGED
|
@@ -47,6 +47,17 @@ Edit directly or use `/settings` for common options.
|
|
|
47
47
|
| `editorPaddingX` | number | `0` | Horizontal padding for input editor (0-3) |
|
|
48
48
|
| `autocompleteMaxVisible` | number | `5` | Max visible items in autocomplete dropdown (3-20) |
|
|
49
49
|
| `showHardwareCursor` | boolean | `false` | Show terminal cursor |
|
|
50
|
+
| `tuiMode` | string | `"retained"` | Startup-only `"retained"` or `"committed"` renderer; changes require restarting Scramjet |
|
|
51
|
+
| `dockEditor` | boolean | `true` | Keep input, adjacent widgets and footer docked in retained mode; live `/settings` control |
|
|
52
|
+
| `retainTranscriptOnExit` | boolean | `false` | Leave the full current styled transcript, widgets, rendered editor and footer in terminal scrollback on final exit from retained mode; live `/settings` control |
|
|
53
|
+
| `editorMaxHeightPercent` | number | `30` | Maximum wrapped input-text rows as 10–50% of terminal height; further reduced to fit the available space |
|
|
54
|
+
| `scrollWheelStep` | number | `3` | Retained transcript rows per wheel event, 1–20; live `/settings` control |
|
|
55
|
+
|
|
56
|
+
Exit retention preserves the current presentation, including offscreen transcript rows, colors, styling and collapsed/expanded state. It includes the rendered editor contents, not draft rows hidden by its height limit, and does not expand compacted or other-branch history. Images become labelled placeholders; selection highlighting, overlays, the scrollbar and browsing hints are excluded. This exposes rendered session and draft text to native terminal history, whose own scrollback capacity still applies. Suspension, external-editor handoffs and crash cleanup never request retention. Committed compatibility mode already writes native history and does not replay a duplicate. Session saving and `/export` are unchanged.
|
|
57
|
+
|
|
58
|
+
The editor-height percentage is a ceiling, not blank reserved space. Borders, autocomplete, widgets and the footer also require room; the input window shrinks before docking is suspended. Oversized extension content remains reachable in the undocked retained flow with a visible explanation. Undocking does not change renderer or terminal-buffer ownership. `committed` is an explicit compatibility choice with the older tail-windowed mutable-output limitation, not equivalent live browsing or a verified screen-reader mode; dock and wheel controls are unavailable there.
|
|
59
|
+
|
|
60
|
+
Numeric layout preferences are floored and clamped to their stated ranges; invalid types/non-finite values use safe defaults with settings diagnostics. Invalid explicit `tuiMode` values are rejected. Invalid explicit `retainTranscriptOnExit` values fall back to `false` with a diagnostic. These controls preserve global-write/project-override semantics: the selector identifies project overrides and shows the effective value even when editing the global preference. Failed writes show an unsaved notice and diagnostic; an in-memory value alone does not establish successful persistence. A malformed global settings file is preserved, and every blocked save attempt reports its load error even after startup diagnostics have been consumed.
|
|
50
61
|
|
|
51
62
|
### Telemetry and update checks
|
|
52
63
|
|
package/docs/terminal-setup.md
CHANGED
|
@@ -2,9 +2,84 @@
|
|
|
2
2
|
|
|
3
3
|
Scramjet uses the [Kitty keyboard protocol](https://sw.kovidgoyal.net/kitty/keyboard-protocol/) for reliable modifier key detection. Most modern terminals support this protocol, but some require configuration.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Transcript browsing and copying
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
**Retained mode is the interactive default.** Scramjet owns the live transcript, scrollbar and selection instead of using terminal scrollback. Your terminal's Find feature cannot search retained history that exists only in Scramjet's memory; searching the currently painted screen, where supported, is not a full-transcript search. Use `/export` for a durable HTML view.
|
|
8
|
+
|
|
9
|
+
To use the older native-history renderer, set `"tuiMode": "committed"` in your [settings file](settings.md#ui--display) and restart Scramjet. This is a compatibility choice, not equivalent live browsing: mutable output taller than the live canvas is tail-windowed until finalized. Changing docking in `/settings` does not change renderer. The interactions below describe retained mode.
|
|
10
|
+
|
|
11
|
+
During an interactive session, Scramjet owns the alternate screen, mouse reporting, the **rightmost transcript scrollbar**, and drag selection. Wheel/trackpad input and scrollbar dragging browse retained output, including running cards. The terminal's native scrollbar/history is not the live transcript. Returning to the document bottom resumes following; passive updates do not pull you away from what you are reading. The input area is docked by default; typing there preserves the transcript anchor. `/settings` can change docking, the input-text height ceiling (30%, range 10–50%), and wheel step (3, range 1–20). Input shrinks around adjacent widgets before an oversized band falls back to explained, undocked retained browsing. Selection remains live during output and layout changes. Endpoints track component-local positions on a best-effort basis; the displayed highlight, not an earlier intended range, determines copying.
|
|
12
|
+
|
|
13
|
+
The leading dock gap shows `Session: N lines below · Ctrl+End: latest` when rendered session rows remain below the viewport. It uses existing whitespace, not another rule or the editor's hidden-draft indicators, and returns to a blank row at the tail. Narrow layouts shorten the hint while retaining **Session**, or show `Session ↓…` when the exact number cannot fit. It is not an unread count and is excluded from application copying. Scramjet choice controls have paired rules and row-based selection-following windows; partial neighboring choices remain visible, while arrows still select whole options. These changes do not alter selector cancellation, countdowns, transcript wheel ownership or approval safeguards.
|
|
14
|
+
|
|
15
|
+
Double-click to select a word or triple-click to select one displayed line, not adjacent wrapped lines. Clicks must land on the same cell within 500 ms of the preceding press; whitespace and punctuation select their own contiguous runs. Select longer ranges by ordinary dragging, including across a screen edge. After starting a drag, keep the left button held and use the wheel to extend the transcript selection, either with a stationary pointer or while adjusting its horizontal and vertical position; reversing the wheel adjusts the endpoint. Release before browsing if you want to keep the selection unchanged. A press without an initial drag does not start wheel selection. Drags cross between transcript and dock in either direction: a transcript-origin downward drag autoscrolls to the bottom before entering the dock; a dock-origin upward drag selects the displayed transcript portion without including the hidden gap below it. Wheel scrolling does not extend a selection confined to the dock. Right-click a nonempty selection or use `tui.input.copy` (Ctrl+C by default) to copy displayed text without ANSI controls or scrollbar cells. Built-in text, Markdown and editor copying omit known component padding and rejoin soft wraps, retaining genuine indentation, hard line breaks and structural boundaries. Tables, repeated quote prefixes and unannotated custom renderers retain their physical layout rather than guessing at their source. Output and waiting controls continue updating while selected. Copy snapshots the last painted selection immediately, before clipboard delivery; unpainted pointer changes cannot change that copy. A new selection must have painted before it can be copied. Resizing ends an active drag and remaps its selection; successful copy or Escape clears selection. Copy failures retain the selection and temporarily display a diagnostic on the last screen row without changing geometry; clicking that diagnostic dismisses it without selecting the covered text. Without selection, Ctrl+C retains its normal application behavior. Right-clicking any content area—including transcript, blank space, widgets, footer or editor—reads local clipboard text into the visible, focused editor at its caret without submitting. The scrollbar, overlays, selectors and approval controls do not paste. A pending repaint is flushed before reading; changing the input owner while waiting cancels the request. Repeated eligible right-clicks during one clipboard read share that read; only the latest still-current request inserts text. Other intervening input, focus loss, editing or session changes cancel a pending paste; focus-in, terminal cell-size notifications and unmodified right-button motion do not count as editing input. WSL prewarms one PowerShell process while the retained TUI runs and uses direct Windows Unicode clipboard access on explicit paste requests. It does not poll or cache clipboard contents. Startup and each read have five-second timeouts and text is limited to 10 MiB of UTF-8; brief clipboard-lock contention has a bounded acquisition retry, but failed reads are not automatically repeated. The reader closes on exit, suspension or external-editor handoff and prewarms again on resume. This avoids per-click process startup; clipboard contention and initial startup can still add latency. macOS, Wayland/X11 and Termux use their local backends. Unsupported or remote clipboard reads show an actionable error; use your terminal's Paste command instead.
|
|
16
|
+
|
|
17
|
+
Terminal-owned Copy/context menus cannot see application selection. A terminal or multiplexer that intercepts pointer input must be configured to forward it. In tmux, enable `set -g mouse on` for the application's wheel/drag path; tmux's own copy mode is a separate interaction. See [tmux.md](tmux.md) for modified-key setup.
|
|
18
|
+
|
|
19
|
+
Home/End retain editor line-start/end behavior at every scroll position. Ctrl+Home navigates to the transcript beginning; Ctrl+End navigates to the bottom and resumes following. Submitting nonempty editor input with Enter or Alt+Enter resumes following immediately, before routing bash/slash commands or queueing messages. New user-message delivery also resumes following, while passive output preserves browsing. Alt+PageUp/Alt+PageDown provide keyboard-only entry into transcript browsing; when detached, PageUp/PageDown browse and Escape returns to the tail. Docked editing and presentation toggles keep the reading anchor, while ordinary undocked editing reveals its cursor. At the tail, normal editor/list bindings apply, and focused overlays retain keyboard precedence. See [keybindings.md](keybindings.md#transcript-browsing-precedence).
|
|
20
|
+
|
|
21
|
+
Clipboard delivery uses the existing platform backend (for example `pbcopy`, `wl-copy`, `xclip`/`xsel`) or OSC 52 where appropriate. Wayland copying awaits stdin completion and a successful `wl-copy` parent exit, with a five-second subprocess timeout; observable failure tries the existing X11/OSC 52 fallbacks before releasing selection. Terminals can reject OSC 52 without acknowledgement: a successful request alone is not proof that a desktop clipboard changed. Remote sessions, clipboard security policies and other profiles require their own verification.
|
|
22
|
+
|
|
23
|
+
Orderly exit restores the shell's normal buffer without printing a transcript or clearing prior shell output by default. Enable **Retain transcript on exit** in `/settings` (`retainTranscriptOnExit: true`) to append the full current styled transcript, including offscreen rows, widgets, rendered editor contents and footer. It preserves collapsed/expanded state, excludes viewport decorations and overlays, and replaces images with labelled placeholders. Hidden draft rows and earlier compacted/other-branch content are not reconstructed; native scrollback capacity still applies. Model-scope and tool-provisioning startup notices belong to the TUI rather than leaking into the shell. Session saving is unchanged. Suspension and external-editor handoffs restore normal terminal modes without dumping transcript copies, regardless of the setting. Crash cleanup prioritizes mode restoration; terminal loss cannot guarantee a flush. For a durable rich view, use `/export`—HTML rendering is unchanged. A retained terminal smaller than 12 columns or three rows shows a resize notice and blocks ordinary input until a usable frame is restored; configured interrupt and empty-draft exit remain available.
|
|
24
|
+
|
|
25
|
+
Built-in Kitty/iTerm2 images fit the viewport without changing retained source data. Partially visible placements and images behind overlays/selection show placeholders rather than painting through other regions; scroll to reveal the full placement or clear selection. Images remain disabled inside tmux. Custom graphics wrappers must forward the optional image-height bound described in [tui.md](tui.md); arbitrary graphics envelopes are not proven compatible.
|
|
26
|
+
|
|
27
|
+
After an expired raw Escape/CSI prefix, active mouse reporting recognizes one immediately following mouse-shaped suffix even after a long idle gap. Matching suffixes are discarded rather than inserted or acted on; other typing is replayed, with incomplete candidates released after 10 ms. Consequently, identical mouse-shaped literal text in that position is consumed, and mouse suffixes themselves fragmented beyond 10 ms are not guaranteed recovery. Bracketed paste is kept separate. This bounded ambiguity policy avoids indefinitely withholding ordinary typing; it is not universal lossless framing over arbitrarily delayed connections.
|
|
28
|
+
|
|
29
|
+
### Native compatibility evidence
|
|
30
|
+
|
|
31
|
+
Native checks cover browsing, copying, live updates, resizing, approval controls, terminal handoffs and restoration; separate pixel checks cover built-in Kitty/iTerm2 images. These configurations describe earlier retained-renderer journeys, not acceptance of every subsequent change. See [Terminal verification](terminal-verification.md) for revision-specific evidence, driver details and historical limitations.
|
|
32
|
+
|
|
33
|
+
Recorded native configurations (2026-09-21):
|
|
34
|
+
|
|
35
|
+
| Path | Tested version and configuration |
|
|
36
|
+
|------|----------------------------------|
|
|
37
|
+
| Windows Terminal / WSL | Terminal 1.24.11911.0, Windows 11 build 22631, WSL2 5.15.153.1, Ubuntu 20.04.6; 120×30; existing profile unchanged |
|
|
38
|
+
| Apple Terminal | 2.14 / 455.1, macOS 15.7.9 / 24G830 ARM64; 80×24 |
|
|
39
|
+
| iTerm2 | 3.6.11 on that macOS; 80×25; `ReportRightClick=true`; inline-image consent for graphics checks |
|
|
40
|
+
| Linux VTE | Xfce Terminal 1.1.3, Ubuntu 24.04.5, X11/Xvfb/Openbox; DejaVu Sans Mono 12, 80×24, native scrollbar hidden |
|
|
41
|
+
| tmux | 3.4 on the preceding VTE path; isolated config with mouse on and status off |
|
|
42
|
+
| xterm | XTerm 390 on Ubuntu 24.04.5/X11; 80×24; `selectToClipboard=true` with its native Shift+Insert paste binding |
|
|
43
|
+
| Kitty | 0.32.2 on Ubuntu 24.04.5/X11; 80×24 interaction and 80×30 graphics profiles |
|
|
44
|
+
|
|
45
|
+
xterm's native paste binding/source differ from VTE's Ctrl+Shift+V; the recorded paste configuration is not a new Scramjet shortcut. Native xterm evidence does not verify VS Code's integrated terminal, nor does Kitty verify every Kitty-family emulator.
|
|
46
|
+
|
|
47
|
+
These checks do not establish every emulator/profile, physical trackpad's gesture characteristics, remote desktop, multiplexer, custom extension or graphics renderer. OS-generated wheel events are not physical trackpad testing; headless tests and ordinary CI do not substitute for native desktop/clipboard evidence.
|
|
48
|
+
|
|
49
|
+
### Native selection differences — deferred
|
|
50
|
+
|
|
51
|
+
Terminal-owned selection is separate from Scramjet selection. Windows Terminal reserves Shift-mouse for its own screen-cell selection; [iTerm2 uses Option to bypass mouse reporting](https://iterm2.com/faq.html). These modifiers are terminal/profile-specific, not a universal Scramjet shortcut. They do not expose unpainted retained history or extend an application selection, and native copying can include visible padding or scrollbar cells. Scramjet's copy cleanup applies only to its ordinary drag/Ctrl+C/right-click path.
|
|
52
|
+
|
|
53
|
+
Native-selection parity remains deferred. Retained edge scrolling uses a fixed speed, not the native distance-dependent acceleration demonstrated on Windows Terminal. Changing modifiers during an active edge drag can withhold its release from the application; clear the application selection to stop a stranded gesture. See the [historical comparison](terminal-verification.md#historical-windows-selection-comparison) for the observations and their limits.
|
|
54
|
+
|
|
55
|
+
## Apple Terminal
|
|
56
|
+
|
|
57
|
+
In the tested Apple Terminal 2.14 profile, Option+PageUp arrived as unmodified PageUp. Scramjet cannot distinguish those identical bytes without stealing ordinary editor paging. Use an explicit application keybinding profile instead:
|
|
58
|
+
|
|
59
|
+
```json
|
|
60
|
+
{
|
|
61
|
+
"tui.viewport.pageUp": "f8",
|
|
62
|
+
"tui.viewport.pageDown": "f9"
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Set this in `~/.scramjet/agent/keybindings.json`; keyboards with media-key defaults may require Fn+F8/Fn+F9. The Apple native journey declares and exercises this temporary profile. Other tested terminal paths exercise the default Alt+PageUp/Alt+PageDown bindings. This is not an automatic runtime terminal allowlist or a claim about every keyboard layout.
|
|
67
|
+
|
|
68
|
+
## Kitty
|
|
69
|
+
|
|
70
|
+
Keyboard reporting works out of the box.
|
|
71
|
+
|
|
72
|
+
## iTerm2
|
|
73
|
+
|
|
74
|
+
Keyboard reporting works out of the box. **Right-click copying requires iTerm2's `ReportRightClick` preference** so mouse-reporting applications receive right-clicks instead of iTerm2's native context menu. The default-off profile was tested and does not support Scramjet's right-click-copy path. This is an explicit setup requirement, not a runtime allowlist or automatic fallback.
|
|
75
|
+
|
|
76
|
+
Enable the right-click-reporting option in iTerm2's Pointer settings, or quit iTerm2 and set its existing preference from another terminal:
|
|
77
|
+
|
|
78
|
+
```sh
|
|
79
|
+
defaults write com.googlecode.iterm2 ReportRightClick -bool true
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Restart iTerm2 afterward. This changes right-click behavior for mouse-reporting applications, not just Scramjet; Scramjet never changes the preference for you. Ctrl+C remains the application-selection copy alternative. Native iTerm2 menus still cannot access application-owned selection.
|
|
8
83
|
|
|
9
84
|
## Ghostty
|
|
10
85
|
|
|
@@ -63,6 +138,8 @@ Add to `keybindings.json` to enable `Shift+Enter` for multi-line input:
|
|
|
63
138
|
|
|
64
139
|
## Windows Terminal
|
|
65
140
|
|
|
141
|
+
With mouse reporting active, Windows Terminal 1.24.11911.0 delivers Ctrl+wheel to the application instead of applying its font-zoom shortcut. Ignoring the received event cannot hand it back to the terminal. Use the terminal's Ctrl+plus/Ctrl+minus shortcuts to zoom; these were verified on the same Windows Terminal/WSL path. Scramjet does not change your terminal preferences or synthesize desktop shortcuts. This remains a Ctrl+wheel limitation of retained mode.
|
|
142
|
+
|
|
66
143
|
Add to `settings.json` (Ctrl+Shift+, or Settings → Open JSON file) to forward the modified Enter keys Scramjet uses:
|
|
67
144
|
|
|
68
145
|
```json
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Terminal verification
|
|
2
|
+
|
|
3
|
+
Maintainer notes for the retained viewport. User operation, compatibility choices and terminal configuration belong in [Terminal Setup](terminal-setup.md). The records below preserve historical observations; moving them here does not establish acceptance of a newer revision.
|
|
4
|
+
|
|
5
|
+
## Evidence boundaries
|
|
6
|
+
|
|
7
|
+
| Check | What it establishes | What it does not establish |
|
|
8
|
+
|-------|---------------------|----------------------------|
|
|
9
|
+
| Headless TUI and production-composition tests | Parsed emitted text/cells, cursor position, intermediate frames, application input dispatch and flush ordering | Native input delivery, desktop clipboard contents or graphics pixels |
|
|
10
|
+
| Transport tests | Framing, timeout and keyboard/mouse mode sequences | Every terminal's delivery behavior |
|
|
11
|
+
| Native interaction journeys | Delivered desktop input, clipboard equality, configured terminal behavior and restoration | Every profile, physical trackpad, remote connection or custom component |
|
|
12
|
+
| Native graphics journeys | Fresh image pixels, confinement, suppression and restoration on the tested path | Arbitrary custom graphics envelopes |
|
|
13
|
+
| Driver self-tests | Required-check sets, failure detection, action receipts and cleanup predicates | A fresh native acceptance run |
|
|
14
|
+
|
|
15
|
+
The shared headless terminal feeds actual TUI writes into `@xterm/headless`; its `sendInput()` calls the application handler directly. A headless assertion and a desktop check with similar wording can therefore establish different things. Do not remove a native check without identifying the exact duplicate predicate, execution boundary and any calibration, sequencing or cleanup role.
|
|
16
|
+
|
|
17
|
+
The native journey fixture is `packages/scramjet/tests/fixtures/interactive-viewport.mjs`. Hosted interaction and graphics drivers live in `.github/scripts/terminal-probe.py` and `.github/scripts/terminal-safety.py`; `.github/scripts/test-terminal-fixtures.py` exercises their evidence predicates. `.github/workflows/terminal-feasibility.yml` owns the hosted matrix. Build the runtime before running fixtures, because they load compiled packages. Windows desktop/clipboard execution through `.github/scripts/windows-terminal-probe.sh` requires separate explicit permission.
|
|
18
|
+
|
|
19
|
+
## Exit retention and right-click latency — 2026-09-28
|
|
20
|
+
|
|
21
|
+
A user-authorized targeted Windows Terminal 1.24.11911.0 / Windows build 22631 / WSL Ubuntu journey exercised rebuilt packages on the dirty working tree based on `6c06a61812dcc9fc324b570eef35d6bbbd487a43`. An isolated production InteractiveMode used a nonempty model scope, 180 numbered styled history rows, above/below widgets, an editor draft and an underlined footer. It loaded no personal extensions and made no model calls. This was a targeted check, not full-matrix acceptance.
|
|
22
|
+
|
|
23
|
+
All 12 native predicates passed: calibrated desktop targeting, retention default off, first right-click paste, held-right-button motion paste, terminal-native paste, selector suppression, the actual `/settings` retention toggle, external-editor return, paste after that handoff, orderly exit and termios restoration. Five single-gesture motion pastes inserted exactly once in 13–25 ms from received right press to completed editor insertion; the first paste took about 36 ms. Native paste took about 0.36 ms from received payload to insertion. These are small-sample application-boundary timings, not physical-input-to-pixel latency guarantees. The fixture verified stable synthetic clipboard contents before each gesture; clipboard contention immediately after a change can still add latency.
|
|
24
|
+
|
|
25
|
+
Inspection of native screenshots confirmed styled history and the complete editor/widget/footer suffix in the restored shell. Parsing the captured application stdout with headless xterm additionally verified every numbered row and the model-scope header exactly once, their ANSI cell attributes, dock order, clean shell styles, no transcript replay between alternate-screen exit/reentry during the external-editor handoff, and zero submissions. Desktop window closure, pointer/focus restoration and absence of leftover matching Windows clipboard workers were independently verified. Deterministic tests cover default-off startup stdout isolation, both docking layouts, settings persistence/overrides/invalid values, graphics placeholders, failed snapshot restoration and clipboard lifecycle/stale-input boundaries.
|
|
26
|
+
|
|
27
|
+
The latency investigation first measured roughly 440–540 ms of per-request PowerShell startup/setup using clipboard-free output. Reusing PowerShell removed that cost, but the Forms-based reader still took roughly 150–180 ms in the native fixture. Direct Windows Unicode clipboard access with bounded lock acquisition reduced the measured delay without polling or caching clipboard contents. Preliminary runs also exposed a fixture import error, unstable synthetic clipboard seeding (including an empty terminal-native control paste), a focus-loss safety abort and an immediate native clipboard-lock rejection; those failed runs are not acceptance evidence. The final reader bounds acquisition retries before reading data and never repeats an ambiguously failed read.
|
|
28
|
+
|
|
29
|
+
Reproduction: start an isolated freshly built InteractiveMode with scoped startup and several screens of numbered styled text; calibrate desktop cells, seed and verify synthetic clipboard text, perform one stationary right-click and five press/move/release gestures while recording input and insertion timestamps, compare a native paste, exercise a real confirmation and `/settings` toggle, round-trip an external editor, then exit while scrolled into history. Check the emitted normal buffer and screenshots, termios, owned-window/pointer/focus cleanup and worker termination. Other operating systems, the full native matrix, native image pixels, both external-editor variants together, and job-control suspension were not rerun for this change; images deliberately become labelled placeholders in retained exit history.
|
|
30
|
+
|
|
31
|
+
## Paste, submission and underline diagnostics — 2026-09-28
|
|
32
|
+
|
|
33
|
+
A user-authorized Windows Terminal 1.24.11911.0 / Windows build 22631 / WSL Ubuntu journey exercised rebuilt packages on the dirty working tree based on `90b71a225075af2015338a8c31d35c79cc60a403`. An isolated production fixture used synthetic clipboard text, no personal extensions and no model calls. This was a targeted diagnostic, not full-matrix acceptance.
|
|
34
|
+
|
|
35
|
+
Before production edits, test-designer-guided regressions reproduced eight editor-submission failures, cancellation of pending paste by focus-in/cell-size notifications, ignored no-selection clicks outside the editor, a lost click during a pending repaint, and curly-underline padding/continuation errors. Actual editor spellcheck replacement and scrolling cleared underline attributes in headless tests before the changes; that control did not reproduce the reported persistent native marks.
|
|
36
|
+
|
|
37
|
+
The final native journey passed eight predicates: first-click paste over transcript, editor-click paste, selector paste suppression, Ctrl+wheel delivered without zoom, keyboard zoom, keyboard zoom restoration, bash submission following, and termios restoration. Clipboard insertion was exact and did not submit. Window closure, pointer restoration and foreground restoration were independently verified. Reproduction uses the real production composition: seed synthetic clipboard text, right-click transcript before other input, repeat over the editor, open a confirmation and verify right-click neither pastes nor answers, then browse away and submit `!printf NATIVE-SUBMIT-OUTPUT`. The pre-fix bash journey left output offscreen; the rebuilt journey followed it.
|
|
38
|
+
|
|
39
|
+
For zoom, hold Ctrl and wheel upward: stdin received `ESC[<80;11;3M` while terminal geometry remained unchanged. Ctrl+plus reduced the cell grid; Ctrl+minus restored it. This confirms terminal mouse routing precedes zoom on this path; swallowing that packet is not a zoom implementation. No terminal preferences were changed.
|
|
40
|
+
|
|
41
|
+
Native screenshots showed deterministic curly spellcheck underlines disappear after replacement with plain text and remain absent after scrolling. The separate fixed-coordinate persistent-underline report remains unresolved; the wrapping fix is not claimed as its root cause. The final focused run passed 479 TypeScript tests and 75 native-driver self-tests. Linux/macOS/tmux, physical trackpads, native graphics and the full desktop journey were not rerun. Two preliminary disposable-fixture attempts failed on fixture import/provider setup and supplied no acceptance evidence.
|
|
42
|
+
|
|
43
|
+
## Dock presentation check — 2026-09-25
|
|
44
|
+
|
|
45
|
+
A user-authorized, targeted Windows Terminal/WSL desktop journey passed **28/28 checks** against rebuilt packages on the uncommitted working tree based on `762822b4bb456bc32f79512a009ae97f6d98a4b0`. The recorded candidate digest was `2e6b47dac18baf1ef518f980dc2dd6b1c00f62e5c123fc9279a247164c13a022` (SHA-256 over sorted changed/untracked repository paths and their contents, each NUL-delimited, before this evidence-record edit). Environment: Windows Terminal 1.24.11911.0, Windows build 22631, WSL Ubuntu, Node 25.2.1; initial/restored geometry 120×30, fitting resize 102×25, plus a smaller unfit-selector case. The run deliberately recorded dirty-tree provenance; it was not the clean-checkout full-PR matrix.
|
|
46
|
+
|
|
47
|
+
The real production fixture hosted all four Scramjet selector variants, not lookalike components. Delivered desktop arrows/Enter verified framing, choices and model preview; mixed-height options exposed partial neighboring choices. Further checks covered resize/overlay restoration, genuine insufficient-space fallback, cancellation/draft restoration, explicit undocking/redocking, live continuation counts and tail blanking. Desktop clipboard reads independently matched displayed selector fragments and a transcript/editor seam selection without copying the Session decoration. Screenshots were inspected. Termios, owned-window closure, pointer position and foreground restoration all passed.
|
|
48
|
+
|
|
49
|
+
The targeted journey reused the Windows driver's owned-window/calibration/cleanup helpers and the fixture's command receipts. Reproduction uses a freshly built `interactive-viewport.mjs --production --journey`, its `selector-confirm`, `selector-select`, `selector-next`, `selector-model`, `overlay`, `close-overlay`, `update` and `copy-seam` actions, and real desktop navigation, resizing and copying. Opening receipts acknowledge mounting/flushing without awaiting an answer; `selector.result` records the later outcome. The permanent interaction drivers now require the product-selector/count checks and reject missing evidence.
|
|
50
|
+
|
|
51
|
+
Two earlier attempts exposed fixture-oracle limitations rather than production defects: uniform-height options aligned exactly with the viewport and did not exercise partial neighbors, then trailing spaces in synthetic descriptions disagreed with the trimmed screen-recording oracle. The final fixture uses mixed heights and trims its synthetic descriptions; assertions were retained. Those failed attempts are not acceptance evidence.
|
|
52
|
+
|
|
53
|
+
This verifies the declared Windows journey only. The hosted Linux/macOS/tmux interaction matrix, native Kitty/iTerm2 graphics pixels, physical trackpads and arbitrary extensions were not rerun. Deterministic tests cover image-covered/placeholder gaps, but are not native graphics acceptance. Existing broader PR verification obligations remain separate.
|
|
54
|
+
|
|
55
|
+
## Historical native journey evidence
|
|
56
|
+
|
|
57
|
+
Detailed successes, failed attempts and exact source commits are recorded in [issue #551](https://github.com/LeanAndMean/scramjet/issues/551) and [PR #560](https://github.com/LeanAndMean/scramjet/pull/560). The [recorded configuration table](terminal-setup.md#native-compatibility-evidence) describes earlier retained-renderer journeys, not blanket acceptance of subsequent changes. Match each claim to the source revision and check names in its report.
|
|
58
|
+
|
|
59
|
+
The hosted drivers require a zero fixture-exit receipt and terminal restoration; both macOS interaction and graphics drivers separately own and verify closure of their terminal process, windows and shell. The Windows driver independently attempts exit and window closure, then verifies window disappearance, pointer position and foreground restoration; a failed or unverified cleanup cannot pass. Graphics confinement compares fresh image pixels with independent single-row color bands in the safety fixture's above-editor widget and last footer row, preserving their heights and accounting for the leading dock spacer. Calibration uses screenshot pixels rather than default cell dimensions, so display scaling is measured rather than assumed. Graphics suppression checks require post-render action receipts and at least two fresh screenshots over a bounded stability interval. The representative VTE journey includes narrow wrapped editing, autocomplete acceptance and a separate committed-mode startup/promotion, approval, external-editor and suspend/resume journey. No-selection right-click checks outside the editor seed synthetic clipboard text, wait for acknowledged input, and require exact insertion without submission or changes to copy/error/terminal-paste counters over a stability interval; intercepted terminal paste remains payload-free. The current journeys also seed synthetic clipboard text and right-click the actual editor, checking exact insertion and no submission. Selection checks require an updated live footer while selection remains active, exact wrapped-editor copying, and exact copying across the transcript/editor seam in both directions. These predicates replace the older whole-frame freeze expectation; historical successes do not certify them. Linux interaction startup retains its 15-second visible-window requirement and records the owned process, pre-cleanup exit status, last window-search result and bounded failure diagnostics; terminal stdout/stderr and Openbox logs are retained with the artifact. Diagnostic observations cannot turn a failed startup into a pass. Windows desktop/clipboard execution requires separate explicit permission.
|
|
60
|
+
|
|
61
|
+
## Historical Windows selection comparison
|
|
62
|
+
|
|
63
|
+
A local comparison on 2026-09-23 used Windows Terminal 1.24.11911.0, Windows 11 build 22631 and WSL Ubuntu, with the existing terminal profile unchanged. A disposable fixture loaded the real compiled InteractiveMode with 1,500 numbered synthetic rows and isolated in-memory settings; no models or personal extensions were loaded. The installed baseline was `b2bb160d7e9f11670915c2f568bc91e3707e3ca7`; the candidate was `575f90bfd847d302eae7f52f901879920f0b8397`, rebuilt only in the development clone. Native desktop events dragged to an edge and then 16 or 100 pixels beyond the window, held there, and released outside. Screenshots, raw fixture stdin, synthetic clipboard reads and terminal-state receipts supplied the observations.
|
|
64
|
+
|
|
65
|
+
- The installed baseline and candidate `committed` mode accelerated with outside distance. For example, baseline upward screenshots advanced 112 rows over approximately 638 ms at 16 pixels, versus 584 rows over approximately 607 ms at 100 pixels. These are bounded observations, not a calibrated speed curve.
|
|
66
|
+
- Candidate `retained` mode stayed near its fixed 12.5 rows/second at both distances. Upward motion reached `ESC[<32;11;1M`, with no additional motion packet revealing outside distance; release arrived as `ESC[<0;11;1m`. Downward motion/release likewise used the bottom cell, row 21. This input path does not supply the distance needed to reproduce native acceleration merely by changing the scroll-rate formula.
|
|
67
|
+
- Retained scrolling stopped after outside release. Separate short-selection checks showed highlight persistence through a wheel-scroll round trip, right-click delivery of selected synthetic rows, and left-click clearing in all three modes. They do not establish byte-for-byte copy parity or the entire combined long-selection journey. All three successful runs restored their initial termios state.
|
|
68
|
+
|
|
69
|
+
An initial accessibility `TextPatternRange.GetText` call crashed the desktop driver; its owned window/button were cleaned up, and the replacement used screenshots rather than that API. A subsequent attempt coalesced mouse movement and did not establish selection; only the paced native-event run supports the observations above. Evidence stayed local. No terminal preferences or installed baseline files were changed. This comparison is not a complete acceptance suite, and retained/native selection parity remains unverified and demonstrably different in acceleration. `committed` remains the existing compatibility option, with its separate mutable-output browsing limitation.
|
|
70
|
+
|
|
71
|
+
The held-button wheel interaction was compared separately on the same Windows Terminal/WSL path. A press alone followed by stationary wheel input did not start native selection; after a small initial drag, the installed baseline and candidate `committed` mode extended selection on wheel input, while pre-fix retained mode kept only the initial range. The baseline checkout had advanced to `49c1f1209f8129a6dffc84c534da5b1c364ceb14` without changing its TUI implementation. The retained fix now preserves that initial-drag distinction and updates only active transcript selection endpoints. Deterministic checks cover both directions, reversal across the origin, events before repaint, release, boundaries and dock confinement. Three Windows driver cases use wheel-only desktop events and reject intervening drag-motion packets; three more mix horizontal/vertical motion with scrolling in both event orders, reverse direction, and perform a final column adjustment immediately followed by release. All six scroll again after release and independently compare exact Unicode clipboard text. The mixed-input deterministic checks also cover bursts before repaint, dragging after wheel input, final wide/combining-grapheme boundaries, and edge-timer ticks between pointer updates. They exposed and now prevent stale painted-coordinate endpoints and stale edge-timer pointer state, while retaining initial painted-row targeting and dock confinement. All six native cases passed against the rebuilt working tree in a targeted subset with explicit dirty-tree provenance, startup/calibration and restoration checks; the full native journey and other terminal paths were not rerun. These results do not resolve the deferred native-selection differences.
|