14
packages/coding-agent/npm-shrinkwrap.json
generated
14
packages/coding-agent/npm-shrinkwrap.json
generated
@@ -516,9 +516,6 @@
|
||||
"get-east-asian-width": "1.6.0",
|
||||
"marked": "15.0.12"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"koffi": "2.16.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=22.19.0"
|
||||
}
|
||||
@@ -1369,17 +1366,6 @@
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/koffi": {
|
||||
"version": "2.16.2",
|
||||
"resolved": "https://registry.npmjs.org/koffi/-/koffi-2.16.2.tgz",
|
||||
"integrity": "sha512-owU0MRwv6xkrVqCd+33uw6BaYppkTRXbO/rVdJNI2dvZG0gzyRhYwW25eWtc5pauwK8TGh3AbkFONSezdykfSA==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"hasInstallScript": true,
|
||||
"funding": {
|
||||
"url": "https://liberapay.com/Koromix"
|
||||
}
|
||||
},
|
||||
"node_modules/long": {
|
||||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz",
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Changed
|
||||
|
||||
- Replaced the optional `koffi` dependency for Windows VT input with a tiny vendored native helper, reducing install size while preserving Shift+Tab handling ([#4480](https://github.com/earendil-works/pi/issues/4480)).
|
||||
|
||||
## [0.75.4] - 2026-05-20
|
||||
|
||||
### Changed
|
||||
|
||||
Binary file not shown.
Binary file not shown.
53
packages/tui/native/win32/src/win32-console-mode.c
Normal file
53
packages/tui/native/win32/src/win32-console-mode.c
Normal file
@@ -0,0 +1,53 @@
|
||||
#include <windows.h>
|
||||
|
||||
#ifndef ENABLE_VIRTUAL_TERMINAL_INPUT
|
||||
#define ENABLE_VIRTUAL_TERMINAL_INPUT 0x0200
|
||||
#endif
|
||||
|
||||
#define NAPI_AUTO_LENGTH ((unsigned long long)-1)
|
||||
|
||||
typedef void* napi_env;
|
||||
typedef void* napi_value;
|
||||
typedef void* napi_callback_info;
|
||||
typedef napi_value (__cdecl *napi_callback)(napi_env, napi_callback_info);
|
||||
typedef int (__cdecl *napi_create_function_fn)(napi_env, const char*, unsigned long long, napi_callback, void*, napi_value*);
|
||||
typedef int (__cdecl *napi_set_named_property_fn)(napi_env, napi_value, const char*, napi_value);
|
||||
typedef int (__cdecl *napi_get_boolean_fn)(napi_env, int, napi_value*);
|
||||
|
||||
static void* node_symbol(const char* name) {
|
||||
HMODULE module = GetModuleHandleA(0);
|
||||
void* proc = module ? (void*)GetProcAddress(module, name) : 0;
|
||||
if (proc) return proc;
|
||||
|
||||
module = GetModuleHandleA("node.dll");
|
||||
return module ? (void*)GetProcAddress(module, name) : 0;
|
||||
}
|
||||
|
||||
static napi_value __cdecl enable_virtual_terminal_input(napi_env env, napi_callback_info info) {
|
||||
(void)info;
|
||||
|
||||
HANDLE handle = GetStdHandle(STD_INPUT_HANDLE);
|
||||
DWORD mode = 0;
|
||||
int enabled = handle != INVALID_HANDLE_VALUE &&
|
||||
GetConsoleMode(handle, &mode) &&
|
||||
SetConsoleMode(handle, mode | ENABLE_VIRTUAL_TERMINAL_INPUT);
|
||||
|
||||
napi_get_boolean_fn napi_get_boolean = (napi_get_boolean_fn)node_symbol("napi_get_boolean");
|
||||
napi_value result = 0;
|
||||
if (napi_get_boolean) napi_get_boolean(env, enabled, &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
__declspec(dllexport) napi_value __cdecl napi_register_module_v1(napi_env env, napi_value exports) {
|
||||
napi_create_function_fn napi_create_function = (napi_create_function_fn)node_symbol("napi_create_function");
|
||||
napi_set_named_property_fn napi_set_named_property = (napi_set_named_property_fn)node_symbol("napi_set_named_property");
|
||||
|
||||
napi_value fn = 0;
|
||||
if (napi_create_function &&
|
||||
napi_set_named_property &&
|
||||
napi_create_function(env, "enableVirtualTerminalInput", NAPI_AUTO_LENGTH, enable_virtual_terminal_input, 0, &fn) == 0) {
|
||||
napi_set_named_property(env, exports, "enableVirtualTerminalInput", fn);
|
||||
}
|
||||
|
||||
return exports;
|
||||
}
|
||||
@@ -12,6 +12,7 @@
|
||||
},
|
||||
"files": [
|
||||
"dist/**/*",
|
||||
"native/win32/prebuilds/**/*.node",
|
||||
"README.md"
|
||||
],
|
||||
"keywords": [
|
||||
@@ -38,9 +39,6 @@
|
||||
"get-east-asian-width": "1.6.0",
|
||||
"marked": "15.0.12"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"koffi": "2.16.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@xterm/headless": "5.5.0",
|
||||
"@xterm/xterm": "5.5.0",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import * as fs from "node:fs";
|
||||
import { createRequire } from "node:module";
|
||||
import * as path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { setKittyProtocolActive } from "./keys.ts";
|
||||
import { StdinBuffer } from "./stdin-buffer.ts";
|
||||
|
||||
@@ -210,23 +211,30 @@ export class ProcessTerminal implements Terminal {
|
||||
private enableWindowsVTInput(): void {
|
||||
if (process.platform !== "win32") return;
|
||||
try {
|
||||
// Dynamic require to avoid bundling koffi's 74MB of cross-platform
|
||||
// native binaries into every compiled binary. Koffi is only needed
|
||||
// on Windows for VT input support.
|
||||
const koffi = cjsRequire("koffi");
|
||||
const k32 = koffi.load("kernel32.dll");
|
||||
const GetStdHandle = k32.func("void* __stdcall GetStdHandle(int)");
|
||||
const GetConsoleMode = k32.func("bool __stdcall GetConsoleMode(void*, _Out_ uint32_t*)");
|
||||
const SetConsoleMode = k32.func("bool __stdcall SetConsoleMode(void*, uint32_t)");
|
||||
const arch = process.arch;
|
||||
if (arch !== "x64" && arch !== "arm64") return;
|
||||
|
||||
const STD_INPUT_HANDLE = -10;
|
||||
const ENABLE_VIRTUAL_TERMINAL_INPUT = 0x0200;
|
||||
const handle = GetStdHandle(STD_INPUT_HANDLE);
|
||||
const mode = new Uint32Array(1);
|
||||
GetConsoleMode(handle, mode);
|
||||
SetConsoleMode(handle, mode[0]! | ENABLE_VIRTUAL_TERMINAL_INPUT);
|
||||
// Dynamic require so non-Windows and bundled/browser paths never load the
|
||||
// native helper. In the npm package native/ is next to dist/; in compiled
|
||||
// binary archives native/ is copied next to the executable.
|
||||
const moduleDir = path.dirname(fileURLToPath(import.meta.url));
|
||||
const nativePath = path.join("native", "win32", "prebuilds", `win32-${arch}`, "win32-console-mode.node");
|
||||
const candidates = [
|
||||
path.join(moduleDir, "..", nativePath),
|
||||
path.join(moduleDir, nativePath),
|
||||
path.join(path.dirname(process.execPath), nativePath),
|
||||
];
|
||||
for (const modulePath of candidates) {
|
||||
try {
|
||||
const helper = cjsRequire(modulePath) as { enableVirtualTerminalInput?: () => boolean };
|
||||
helper.enableVirtualTerminalInput?.();
|
||||
return;
|
||||
} catch {
|
||||
// Try the next possible packaging location.
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// koffi not available — Shift+Tab won't be distinguishable from Tab
|
||||
// Native helper not available — Shift+Tab won't be distinguishable from Tab.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user