@linxiraos/pi-natives 1.2.1 → 1.3.1
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 +11 -1
- package/THIRD-PARTY-NOTICES.txt +5 -5
- package/native/desktop-adapter.js +11 -1
- package/native/desktop.d.ts +9 -0
- package/native/desktop.js +20 -1
- package/native/index.d.ts +331 -20
- package/native/index.js +7 -0
- package/native/loader-state.js +15 -9
- package/native/vcs.d.ts +3 -0
- package/native/vcs.js +53 -0
- package/package.json +10 -9
package/README.md
CHANGED
|
@@ -10,6 +10,7 @@ Native Rust functionality via N-API.
|
|
|
10
10
|
- **Audio**: Cross-platform low-latency microphone capture and gapless speaker playback
|
|
11
11
|
- **WebRTC**: Native Opus media, SDP offer/answer negotiation, and data-channel events for live sessions
|
|
12
12
|
- **File locking**: Process-owned cross-process locks with in-memory kernel names on Linux/Windows and `flock(2)` sidecars on other Unix platforms
|
|
13
|
+
- **Local IPC**: `IpcServer`/`IpcConnection` over Unix sockets and Windows named pipes — owner-only access, single-instance binding with stale-endpoint takeover, newline or raw framing; `ipcEndpoint(dir, name)` names endpoints per platform
|
|
13
14
|
- **PDF**: In-memory PDF-to-Markdown extraction with OCR-page classification via `pdf-inspector`
|
|
14
15
|
- **Binary patches**: `applyBinaryPatch(oldPath, patchPath, outPath)` applies an HDiffPatch single-stream patch (HDIFFSF20, zstd or uncompressed), streaming from files; callers verify digests
|
|
15
16
|
|
|
@@ -40,13 +41,22 @@ const files = await find({
|
|
|
40
41
|
|
|
41
42
|
// SIXEL encode for a terminal cell box (px), off the JS thread
|
|
42
43
|
// (`encodeSixel` is the synchronous form)
|
|
43
|
-
const
|
|
44
|
+
const backgroundRgb = 0x202040; // Actual terminal background, packed 0xRRGGBB
|
|
45
|
+
const sequence = await encodeSixelAsync(pngBytes, widthPx, heightPx, backgroundRgb);
|
|
44
46
|
|
|
45
47
|
// Extract PDF text and identify pages that still need OCR
|
|
46
48
|
const pdf = await pdfToMarkdown(pdfBytes);
|
|
47
49
|
console.log(pdf.markdown, pdf.pagesNeedingOcr);
|
|
48
50
|
```
|
|
49
51
|
|
|
52
|
+
Both SIXEL encoder forms require the terminal background as a fourth argument,
|
|
53
|
+
packed as a 24-bit `0xRRGGBB` number. When resizing images with alpha, RGB is
|
|
54
|
+
premultiplied before Lanczos filtering so transparent pixels cannot darken or
|
|
55
|
+
discolor visible edges. After resizing, the terminal background is composited
|
|
56
|
+
without applying alpha twice. Fully transparent pixels remain transparent;
|
|
57
|
+
unscaled images retain their existing blending path. Re-encode when the terminal
|
|
58
|
+
background RGB changes.
|
|
59
|
+
|
|
50
60
|
### Lazy Windows path helpers
|
|
51
61
|
|
|
52
62
|
Import `expandWindowsLongPath` and `getWindowsShortPath` from
|
package/THIRD-PARTY-NOTICES.txt
CHANGED
|
@@ -8,8 +8,8 @@ no rights in third-party code, fonts, data, or marks identified below.
|
|
|
8
8
|
PYTHON DEPENDENCY DISTRIBUTION ROLE
|
|
9
9
|
===================================
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
Uvicorn, HTTPX, Pydantic, pydantic-settings, python-dotenv, Click, and
|
|
11
|
+
zeta-rpc has no third-party runtime dependencies. robomp declares FastAPI,
|
|
12
|
+
Uvicorn, HTTPX, Pydantic, pydantic-settings, python-dotenv, Click, and zeta-rpc
|
|
13
13
|
as ordinary installer-resolved dependencies. The Python wheels do not vendor
|
|
14
14
|
those projects; each dependency remains a separately installed distribution
|
|
15
15
|
carrying its own license metadata and files. Container/system assemblers must
|
|
@@ -79,9 +79,9 @@ uutils coreutils (https://github.com/uutils/coreutils), MIT
|
|
|
79
79
|
--------------------------------------------------------------------------------
|
|
80
80
|
Covers: base32, base64, basename, cat, cksum (shared checksum machinery),
|
|
81
81
|
b2sum, md5sum, sha1sum, sha224sum, sha256sum, sha384sum, sha512sum, comm, cp,
|
|
82
|
-
cut, date, dirname, head, hostname, ln, ls, mkdir, mktemp, mv,
|
|
83
|
-
printenv, readlink, realpath, rm, seq, sort, stat, tac, tail, tee,
|
|
84
|
-
truncate, uname, uniq, wc, whoami, yes.
|
|
82
|
+
cut, date, dirname, head, hostname, ln, ls, mkdir, mktemp, mv, nl, nproc,
|
|
83
|
+
paste, printenv, readlink, realpath, rm, seq, sort, stat, tac, tail, tee,
|
|
84
|
+
touch, tr, truncate, uname, uniq, wc, whoami, yes.
|
|
85
85
|
|
|
86
86
|
Copyright (c) uutils developers
|
|
87
87
|
|
|
@@ -4,6 +4,7 @@ const REQUIRED_METHODS = [
|
|
|
4
4
|
"captureRegion",
|
|
5
5
|
"cancel",
|
|
6
6
|
"retire",
|
|
7
|
+
"setRunDeadline",
|
|
7
8
|
"observe",
|
|
8
9
|
"listApplications",
|
|
9
10
|
"openApplication",
|
|
@@ -15,12 +16,21 @@ const REQUIRED_METHODS = [
|
|
|
15
16
|
"releaseControl",
|
|
16
17
|
"controlState",
|
|
17
18
|
"bringToCurrentSpace",
|
|
19
|
+
"axSelectText",
|
|
20
|
+
"holdDisplayUntilReleased",
|
|
21
|
+
"releaseDisplayAwake",
|
|
18
22
|
];
|
|
19
23
|
|
|
24
|
+
/** Getters the computer worker reads; without `escapeStops` it would read every run as stopped by the user's Escape. */
|
|
25
|
+
const REQUIRED_GETTERS = ["escapeStops"];
|
|
26
|
+
|
|
20
27
|
/** Require the current desktop ABI; partial legacy emulation cannot preserve input ownership. */
|
|
21
28
|
export function adaptDesktopSession(NativeDesktopSession) {
|
|
22
29
|
const prototype = NativeDesktopSession?.prototype;
|
|
23
|
-
const missing =
|
|
30
|
+
const missing = [
|
|
31
|
+
...REQUIRED_METHODS.filter(method => typeof prototype?.[method] !== "function"),
|
|
32
|
+
...REQUIRED_GETTERS.filter(getter => !prototype || !(getter in prototype)),
|
|
33
|
+
];
|
|
24
34
|
if (missing.length === 0) {
|
|
25
35
|
return NativeDesktopSession;
|
|
26
36
|
}
|
package/native/desktop.d.ts
CHANGED
|
@@ -2,3 +2,12 @@ import type { DesktopSession, DesktopSessionOptions } from "./index.js";
|
|
|
2
2
|
|
|
3
3
|
/** Construct a desktop session, loading the native addon on first use. */
|
|
4
4
|
export declare function createDesktopSession(options: DesktopSessionOptions): DesktopSession;
|
|
5
|
+
|
|
6
|
+
/** Physical-Escape stops counted under `key`, loading the native addon on first use. */
|
|
7
|
+
export declare function desktopEscapeStops(key: string): number;
|
|
8
|
+
|
|
9
|
+
/** Drop the stop count kept under `key`. */
|
|
10
|
+
export declare function forgetDesktopEscapeStops(key: string): void;
|
|
11
|
+
|
|
12
|
+
/** Invalidate this process's event taps before it exits (see the native doc). */
|
|
13
|
+
export declare function closeDesktopEventTaps(): void;
|
package/native/desktop.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { adaptDesktopSession } from "./desktop-adapter.js";
|
|
2
|
-
import { loadNative } from "./loader-state.js";
|
|
2
|
+
import { loadNative, missingNativeExport } from "./loader-state.js";
|
|
3
3
|
|
|
4
4
|
let DesktopSession;
|
|
5
5
|
|
|
@@ -11,3 +11,22 @@ export function createDesktopSession(options) {
|
|
|
11
11
|
DesktopSession ??= adaptDesktopSession(loadNative().DesktopSession);
|
|
12
12
|
return new DesktopSession(options);
|
|
13
13
|
}
|
|
14
|
+
|
|
15
|
+
// A stale workspace addon lacks the Escape exports; fall back to the stub
|
|
16
|
+
// `native/index.js` exports in their place, which names the rebuild.
|
|
17
|
+
|
|
18
|
+
/** Physical-Escape stops counted under `key`, loading the native addon on first use. */
|
|
19
|
+
export function desktopEscapeStops(key) {
|
|
20
|
+
return (loadNative().desktopEscapeStops ?? missingNativeExport("desktopEscapeStops"))(key);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Drop the stop count kept under `key`. */
|
|
24
|
+
export function forgetDesktopEscapeStops(key) {
|
|
25
|
+
(loadNative().forgetDesktopEscapeStops ?? missingNativeExport("forgetDesktopEscapeStops"))(key);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Invalidate this process's event taps before it exits (see the native doc). A stale
|
|
29
|
+
* workspace addon without the export holds no such taps. */
|
|
30
|
+
export function closeDesktopEventTaps() {
|
|
31
|
+
loadNative().closeDesktopEventTaps?.();
|
|
32
|
+
}
|
package/native/index.d.ts
CHANGED
|
@@ -43,10 +43,29 @@ export declare class DesktopSession {
|
|
|
43
43
|
* behind the worker, so it answers at once even while a request is stuck.
|
|
44
44
|
*/
|
|
45
45
|
get screenState(): DesktopScreenState
|
|
46
|
+
/**
|
|
47
|
+
* Keeps the display awake from the next activity request until
|
|
48
|
+
* `releaseDisplayAwake()`, however long the session sits idle in between,
|
|
49
|
+
* instead of for the grace period after the last request. An agent calls
|
|
50
|
+
* this when it acts inside a turn.
|
|
51
|
+
*/
|
|
52
|
+
holdDisplayUntilReleased(): void
|
|
53
|
+
/**
|
|
54
|
+
* Lets the display sleep now if a turn holds it, without waiting behind
|
|
55
|
+
* queued requests, and returns later activity to the grace period. Activity
|
|
56
|
+
* outside a turn keeps its grace. An agent calls this when its turn ends.
|
|
57
|
+
*/
|
|
58
|
+
releaseDisplayAwake(): void
|
|
59
|
+
/**
|
|
60
|
+
* How many times the user's physical Escape has stopped takeover input in
|
|
61
|
+
* this session, or under its `escapeStopKey`. Host cancels, retirement and
|
|
62
|
+
* release never count, so a rise tells the host the user stopped the work.
|
|
63
|
+
*/
|
|
64
|
+
get escapeStops(): number
|
|
46
65
|
listDisplays(): Promise<Array<DesktopDisplay>>
|
|
47
66
|
listWindows(): Promise<Array<DesktopWindow>>
|
|
48
67
|
listApplications(options?: ApplicationQuery | undefined | null): Promise<Array<Application>>
|
|
49
|
-
openApplication(id: string, options?: ApplicationOpenOptions | undefined | null): Promise<
|
|
68
|
+
openApplication(id: string, options?: ApplicationOpenOptions | undefined | null): Promise<OpenedApplication>
|
|
50
69
|
/**
|
|
51
70
|
* Capture and accessibility share one serialized request. Neither a failed
|
|
52
71
|
* snapshot nor an abandoned reply replaces the last delivered input frame.
|
|
@@ -55,8 +74,8 @@ export declare class DesktopSession {
|
|
|
55
74
|
menuItems(target: string, path?: Array<string> | undefined | null): Promise<Array<DesktopMenuItem>>
|
|
56
75
|
menuSelect(target: string, path: Array<string>): Promise<undefined>
|
|
57
76
|
bringToCurrentSpace(windowId: string): Promise<undefined>
|
|
58
|
-
holdKeys(target: string, keys: Array<string>, options: HoldOptions): Promise<undefined>
|
|
59
|
-
holdMouse(target: string, x: number, y: number, options: HoldOptions): Promise<undefined>
|
|
77
|
+
holdKeys(target: string, keys: Array<string>, options: HoldOptions): Promise<DesktopFocusReturn | undefined | null>
|
|
78
|
+
holdMouse(target: string, x: number, y: number, options: HoldOptions): Promise<DesktopFocusReturn | undefined | null>
|
|
60
79
|
/**
|
|
61
80
|
* Native ownership only. Human approval is required by the host before
|
|
62
81
|
* calling this method.
|
|
@@ -66,18 +85,24 @@ export declare class DesktopSession {
|
|
|
66
85
|
controlState(): DesktopControlState
|
|
67
86
|
/** Retire queued work from a completed helper without revoking task control. */
|
|
68
87
|
retire(): void
|
|
88
|
+
/**
|
|
89
|
+
* Sets when the current run ends, `remaining_ms` from now; each run sets
|
|
90
|
+
* it before its first call. On macOS, input waiting for the user to pause
|
|
91
|
+
* in its app gives up shortly before it.
|
|
92
|
+
*/
|
|
93
|
+
setRunDeadline(remainingMs: number): void
|
|
69
94
|
capture(target: string, caps?: CaptureCaps | undefined | null): Promise<DesktopCapture>
|
|
70
95
|
/**
|
|
71
96
|
* Capture a fresh native-detail region without replacing the full input
|
|
72
97
|
* coordinate frame.
|
|
73
98
|
*/
|
|
74
99
|
captureRegion(target: string, region: CaptureRegion, caps?: CaptureCaps | undefined | null): Promise<DesktopCapture>
|
|
75
|
-
click(target: string, x: number, y: number, opts?: PointerOptions | undefined | null): Promise<undefined>
|
|
76
|
-
moveMouse(target: string, x: number, y: number, opts?: PointerOptions | undefined | null): Promise<undefined>
|
|
77
|
-
drag(target: string, path: Array<DesktopPoint>, opts?: PointerOptions | undefined | null): Promise<undefined>
|
|
78
|
-
scroll(target: string, x: number, y: number, dx: number, dy: number, opts?: PointerOptions | undefined | null): Promise<undefined>
|
|
79
|
-
typeText(target: string, text: string, opts?: PointerOptions | undefined | null): Promise<undefined>
|
|
80
|
-
keyChord(target: string, keys: Array<string>, opts?: PointerOptions | undefined | null): Promise<undefined>
|
|
100
|
+
click(target: string, x: number, y: number, opts?: PointerOptions | undefined | null): Promise<DesktopFocusReturn | undefined | null>
|
|
101
|
+
moveMouse(target: string, x: number, y: number, opts?: PointerOptions | undefined | null): Promise<DesktopFocusReturn | undefined | null>
|
|
102
|
+
drag(target: string, path: Array<DesktopPoint>, opts?: PointerOptions | undefined | null): Promise<DesktopFocusReturn | undefined | null>
|
|
103
|
+
scroll(target: string, x: number, y: number, dx: number, dy: number, opts?: PointerOptions | undefined | null): Promise<DesktopFocusReturn | undefined | null>
|
|
104
|
+
typeText(target: string, text: string, opts?: PointerOptions | undefined | null): Promise<DesktopFocusReturn | undefined | null>
|
|
105
|
+
keyChord(target: string, keys: Array<string>, opts?: PointerOptions | undefined | null): Promise<DesktopFocusReturn | undefined | null>
|
|
81
106
|
raiseWindow(windowId: string): Promise<undefined>
|
|
82
107
|
axSnapshot(target: string, opts?: AxSnapshotOptions | undefined | null): Promise<AxSnapshot>
|
|
83
108
|
axQuery(target: string, query: AxQuery): Promise<Array<AxNode>>
|
|
@@ -91,10 +116,26 @@ export declare class DesktopSession {
|
|
|
91
116
|
axAttributes(reference: string): Promise<Array<[string, string]>>
|
|
92
117
|
axChildren(reference: string): Promise<Array<AxNode>>
|
|
93
118
|
axParent(reference: string): Promise<AxNode | undefined | null>
|
|
94
|
-
|
|
119
|
+
/**
|
|
120
|
+
* Performs `action` on the element; with `menu`, chooses that item path
|
|
121
|
+
* in the menu the action opens, which closes it.
|
|
122
|
+
*/
|
|
123
|
+
axPerform(reference: string, action: string, menu?: Array<string> | undefined | null): Promise<undefined>
|
|
95
124
|
axSetValue(reference: string, value: string): Promise<undefined>
|
|
125
|
+
/**
|
|
126
|
+
* Selects `text` in the element's value by accessibility, or places a
|
|
127
|
+
* caret at its start or end, without focus change or keystrokes.
|
|
128
|
+
*/
|
|
129
|
+
axSelectText(reference: string, text: string, opts?: AxSelectTextOptions | undefined | null): Promise<AxTextSelection>
|
|
96
130
|
axFocus(reference: string): Promise<undefined>
|
|
97
|
-
axClick(reference: string, opts?: PointerOptions | undefined | null): Promise<undefined>
|
|
131
|
+
axClick(reference: string, opts?: PointerOptions | undefined | null): Promise<DesktopFocusReturn | undefined | null>
|
|
132
|
+
/**
|
|
133
|
+
* Types `text` into the element: native text fields take it by AX
|
|
134
|
+
* insertion, other elements as keystrokes once they hold keyboard focus.
|
|
135
|
+
*/
|
|
136
|
+
axType(reference: string, text: string, opts?: PointerOptions | undefined | null): Promise<DesktopFocusReturn | undefined | null>
|
|
137
|
+
/** Presses a key chord in the element once it holds keyboard focus. */
|
|
138
|
+
axKeyChord(reference: string, keys: Array<string>, opts?: PointerOptions | undefined | null): Promise<DesktopFocusReturn | undefined | null>
|
|
98
139
|
/**
|
|
99
140
|
* Immediately cancel operations submitted before this call. Later
|
|
100
141
|
* operations may proceed.
|
|
@@ -235,6 +276,85 @@ export declare class HighlightStream {
|
|
|
235
276
|
push(chunk: string): string
|
|
236
277
|
}
|
|
237
278
|
|
|
279
|
+
/** One accepted or dialed IPC connection. */
|
|
280
|
+
export declare class IpcConnection {
|
|
281
|
+
/**
|
|
282
|
+
* Dial `endpoint`. Rejects with code ENOENT (no endpoint), ECONNREFUSED
|
|
283
|
+
* (stale socket / no listener), ETIMEDOUT, EACCES (peer owned by another
|
|
284
|
+
* user, or permission), or the OS errno name.
|
|
285
|
+
*/
|
|
286
|
+
static connect(endpoint: string, options: IpcConnectOptions): Promise<IpcConnection>
|
|
287
|
+
/**
|
|
288
|
+
* Begin delivery on a `lines` connection (throws `TypeError` on a `raw`
|
|
289
|
+
* one). Call `start`/`startRaw` exactly once. Frames received before
|
|
290
|
+
* start are buffered, never dropped. `onLine` gets each non-empty line
|
|
291
|
+
* (one trailing CR stripped, invalid UTF-8 replaced lossily). `onClose`
|
|
292
|
+
* fires exactly once, after the last frame — including after local
|
|
293
|
+
* `end()`/`destroy()`: `null` for an orderly close, otherwise
|
|
294
|
+
* `"<CODE>: <message>"`.
|
|
295
|
+
*/
|
|
296
|
+
start(onLine: (line: string) => void, onClose: (reason: string | null) => void): void
|
|
297
|
+
/**
|
|
298
|
+
* Same as `start()` for a `raw` connection (throws `TypeError` on a
|
|
299
|
+
* `lines` one): `onChunk` gets each received chunk.
|
|
300
|
+
*/
|
|
301
|
+
startRaw(onChunk: (chunk: Uint8Array) => void, onClose: (reason: string | null) => void): void
|
|
302
|
+
/**
|
|
303
|
+
* Send one frame. lines: a string without LF (`TypeError` otherwise);
|
|
304
|
+
* LF is appended. raw: string (UTF-8) or `Uint8Array` written as-is.
|
|
305
|
+
* Frames sent during one JS task are written together when it ends (a
|
|
306
|
+
* microtask), in order; `end()` writes them first. Returns false once
|
|
307
|
+
* unwritten bytes exceed 1 MiB (await `drained()` before sending more).
|
|
308
|
+
* After close: returns false and drops the frame.
|
|
309
|
+
*/
|
|
310
|
+
send(frame: string | Uint8Array): boolean
|
|
311
|
+
/** Resolves when the write queue is empty, or the connection closed. */
|
|
312
|
+
drained(): Promise<void>
|
|
313
|
+
/**
|
|
314
|
+
* Graceful: write everything queued, then shut the write half (Unix) /
|
|
315
|
+
* close the pipe (Windows); onClose follows when the read side ends.
|
|
316
|
+
*/
|
|
317
|
+
end(): void
|
|
318
|
+
/**
|
|
319
|
+
* Immediate close; queued writes are dropped; onClose(null) follows.
|
|
320
|
+
* Idempotent.
|
|
321
|
+
*/
|
|
322
|
+
destroy(): void
|
|
323
|
+
/** Keep the event loop alive while delivering (default). */
|
|
324
|
+
ref(): void
|
|
325
|
+
/** Let the event loop exit while this connection is open. */
|
|
326
|
+
unref(): void
|
|
327
|
+
/** Whether the connection is closed (or `destroy()` was called). */
|
|
328
|
+
get closed(): boolean
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/** Listening IPC endpoint. */
|
|
332
|
+
export declare class IpcServer {
|
|
333
|
+
/**
|
|
334
|
+
* Bind and listen.
|
|
335
|
+
*
|
|
336
|
+
* Unix: creates the parent dir (0700) if missing; under an exclusive flock
|
|
337
|
+
* on `<path>.bind.lock`, rejects EADDRINUSE when a live server answers,
|
|
338
|
+
* otherwise replaces the stale socket file; the socket is chmod 0600 before
|
|
339
|
+
* `listen()`. Windows: first pipe instance (exists → EADDRINUSE), remote
|
|
340
|
+
* clients rejected, DACL granting only the current user.
|
|
341
|
+
* `onConnection` receives each accepted, peer-verified connection (not yet
|
|
342
|
+
* started).
|
|
343
|
+
*/
|
|
344
|
+
static listen(endpoint: string, options: IpcListenOptions, onConnection: (connection: IpcConnection) => void): Promise<IpcServer>
|
|
345
|
+
/** The endpoint this server listens on. */
|
|
346
|
+
get endpoint(): string
|
|
347
|
+
/**
|
|
348
|
+
* Stop accepting. Unix: unlink the socket file if it is still the inode
|
|
349
|
+
* this server bound. Accepted connections are untouched. Idempotent.
|
|
350
|
+
*/
|
|
351
|
+
close(): Promise<void>
|
|
352
|
+
/** Keep the event loop alive while listening (default). */
|
|
353
|
+
ref(): void
|
|
354
|
+
/** Let the event loop exit while listening. */
|
|
355
|
+
unref(): void
|
|
356
|
+
}
|
|
357
|
+
|
|
238
358
|
/** WebRTC peer that accepts 16 kHz mono PCM and renders remote Opus audio. */
|
|
239
359
|
export declare class LiveWebRtcPeer {
|
|
240
360
|
/**
|
|
@@ -1092,6 +1212,16 @@ export interface AxQuery {
|
|
|
1092
1212
|
limit?: number
|
|
1093
1213
|
}
|
|
1094
1214
|
|
|
1215
|
+
/** Where `axSelectText` looks for its text and what it selects there. */
|
|
1216
|
+
export interface AxSelectTextOptions {
|
|
1217
|
+
/** Text that must directly precede the match. */
|
|
1218
|
+
prefix?: string
|
|
1219
|
+
/** Text that must directly follow the match. */
|
|
1220
|
+
suffix?: string
|
|
1221
|
+
/** `text` (default) selects the match; `start` and `end` place a caret. */
|
|
1222
|
+
select?: string
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1095
1225
|
export interface AxSnapshot {
|
|
1096
1226
|
text: string
|
|
1097
1227
|
nodeCount: number
|
|
@@ -1104,6 +1234,19 @@ export interface AxSnapshotOptions {
|
|
|
1104
1234
|
all?: boolean
|
|
1105
1235
|
}
|
|
1106
1236
|
|
|
1237
|
+
/** The selection read back after `axSelectText`, in UTF-16 code units. */
|
|
1238
|
+
export interface AxTextSelection {
|
|
1239
|
+
start: number
|
|
1240
|
+
length: number
|
|
1241
|
+
/** The selected text, empty for a caret. */
|
|
1242
|
+
text: string
|
|
1243
|
+
/**
|
|
1244
|
+
* Whether the element is focused in its app: typing and AX insertion
|
|
1245
|
+
* act on the focused element.
|
|
1246
|
+
*/
|
|
1247
|
+
focused: boolean
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1107
1250
|
export interface BlockParseOptions {
|
|
1108
1251
|
/** Source code to parse. */
|
|
1109
1252
|
code: string
|
|
@@ -1161,6 +1304,15 @@ export interface ClipboardImage {
|
|
|
1161
1304
|
mimeType: string
|
|
1162
1305
|
}
|
|
1163
1306
|
|
|
1307
|
+
/**
|
|
1308
|
+
* Invalidates this process's event taps; for a host about to
|
|
1309
|
+
* exit, after which no desktop session here sees the user's input again. A
|
|
1310
|
+
* macOS tap that dies with its process while the user types makes
|
|
1311
|
+
* `WindowServer` deliver their key again; Bun's `process.exit` runs no native
|
|
1312
|
+
* exit hook, so the host calls this from its exit handler.
|
|
1313
|
+
*/
|
|
1314
|
+
export declare function closeDesktopEventTaps(): void
|
|
1315
|
+
|
|
1164
1316
|
/** A context line (before or after a match). */
|
|
1165
1317
|
export interface ContextLine {
|
|
1166
1318
|
/** 1-indexed line number in the source file. */
|
|
@@ -1240,8 +1392,10 @@ export interface DesktopCapabilities {
|
|
|
1240
1392
|
heldInput: boolean
|
|
1241
1393
|
spaces: boolean
|
|
1242
1394
|
/**
|
|
1243
|
-
* Native global Escape cancellation
|
|
1244
|
-
*
|
|
1395
|
+
* Native global Escape cancellation of takeover input (`takeover: true`,
|
|
1396
|
+
* held control, desktop/display-level input, raises, activating launches).
|
|
1397
|
+
* Without held control, background window input never watches the user's
|
|
1398
|
+
* keys; it and Wayland stop only through the host interrupt.
|
|
1245
1399
|
*/
|
|
1246
1400
|
globalEscape: boolean
|
|
1247
1401
|
capturePermission: string
|
|
@@ -1314,6 +1468,20 @@ export interface DesktopDisplay {
|
|
|
1314
1468
|
isPrimary: boolean
|
|
1315
1469
|
}
|
|
1316
1470
|
|
|
1471
|
+
/**
|
|
1472
|
+
* Where focus ended after a takeover input call, as `WindowServer` reports
|
|
1473
|
+
* it. Input calls resolve to it on macOS when they took over; other
|
|
1474
|
+
* backends and background delivery resolve to `null`.
|
|
1475
|
+
*/
|
|
1476
|
+
export interface DesktopFocusReturn {
|
|
1477
|
+
/** Whether the takeover handed focus back to the app front before it. */
|
|
1478
|
+
handedBack: boolean
|
|
1479
|
+
/** The process front before the takeover. */
|
|
1480
|
+
previousPid?: number
|
|
1481
|
+
/** The process front once the takeover ended; absent when unreadable. */
|
|
1482
|
+
frontPid?: number
|
|
1483
|
+
}
|
|
1484
|
+
|
|
1317
1485
|
/**
|
|
1318
1486
|
* One immediate child of a native application menu. Paths contain the actual
|
|
1319
1487
|
* native labels, including ellipses; selection accepts normalized labels.
|
|
@@ -1346,8 +1514,19 @@ export interface DesktopScreenState {
|
|
|
1346
1514
|
displayAsleep: boolean
|
|
1347
1515
|
}
|
|
1348
1516
|
|
|
1517
|
+
/**
|
|
1518
|
+
* Physical-Escape stops counted under `key` by every desktop session created
|
|
1519
|
+
* with it, including closed ones, until the key is forgotten.
|
|
1520
|
+
*/
|
|
1521
|
+
export declare function desktopEscapeStops(key: string): number
|
|
1522
|
+
|
|
1349
1523
|
export interface DesktopSessionOptions {
|
|
1350
1524
|
display?: string
|
|
1525
|
+
/**
|
|
1526
|
+
* Sessions created with the same key share one physical-Escape stop
|
|
1527
|
+
* count, which `desktopEscapeStops` reads after they close.
|
|
1528
|
+
*/
|
|
1529
|
+
escapeStopKey?: string
|
|
1351
1530
|
}
|
|
1352
1531
|
|
|
1353
1532
|
/** One capturable top-level window in global logical desktop coordinates. */
|
|
@@ -1702,13 +1881,17 @@ export interface EnclosingBoundaryOptions {
|
|
|
1702
1881
|
* the calling thread.
|
|
1703
1882
|
*
|
|
1704
1883
|
* The input image is decoded and resized to the requested pixel dimensions
|
|
1705
|
-
*
|
|
1706
|
-
*
|
|
1884
|
+
* (not resampled when it already has them), then partial alpha is composited
|
|
1885
|
+
* against `background_rgb` (packed `0xRRGGBB`). Fully transparent pixels
|
|
1886
|
+
* remain transparent. Encoding uses whole 6-pixel bands: a partial last band
|
|
1887
|
+
* is dropped, see [`band_rows`]. Prefer
|
|
1888
|
+
* [`encode_sixel_async`] unless the caller cannot wait: the decode, resize
|
|
1889
|
+
* and dither block the JS thread.
|
|
1707
1890
|
*
|
|
1708
1891
|
* # Errors
|
|
1709
1892
|
* Returns an error if decoding, resizing, or SIXEL encoding fails.
|
|
1710
1893
|
*/
|
|
1711
|
-
export declare function encodeSixel(bytes: Uint8Array, targetWidthPx: number, targetHeightPx: number): string
|
|
1894
|
+
export declare function encodeSixel(bytes: Uint8Array, targetWidthPx: number, targetHeightPx: number, backgroundRgb: number): string
|
|
1712
1895
|
|
|
1713
1896
|
/**
|
|
1714
1897
|
* Same result as [`encode_sixel`], but the decode, resize and dither run on
|
|
@@ -1717,7 +1900,7 @@ export declare function encodeSixel(bytes: Uint8Array, targetWidthPx: number, ta
|
|
|
1717
1900
|
* # Errors
|
|
1718
1901
|
* Rejects if decoding, resizing, or SIXEL encoding fails.
|
|
1719
1902
|
*/
|
|
1720
|
-
export declare function encodeSixelAsync(bytes: Uint8Array, targetWidthPx: number, targetHeightPx: number): Promise<string>
|
|
1903
|
+
export declare function encodeSixelAsync(bytes: Uint8Array, targetWidthPx: number, targetHeightPx: number, backgroundRgb: number): Promise<string>
|
|
1721
1904
|
|
|
1722
1905
|
/** Tokenizer encoding to use. */
|
|
1723
1906
|
export declare enum Encoding {
|
|
@@ -1806,6 +1989,9 @@ export declare enum FileType {
|
|
|
1806
1989
|
Symlink = 3
|
|
1807
1990
|
}
|
|
1808
1991
|
|
|
1992
|
+
/** Drops the stop count kept under `key` once no session will use it again. */
|
|
1993
|
+
export declare function forgetDesktopEscapeStops(key: string): void
|
|
1994
|
+
|
|
1809
1995
|
/** Fuzzy file path search for autocomplete. */
|
|
1810
1996
|
export declare function fuzzyFind(options: FuzzyFindOptions): Promise<FuzzyFindResult>
|
|
1811
1997
|
|
|
@@ -1979,7 +2165,10 @@ export interface GrepOptions {
|
|
|
1979
2165
|
pattern: string
|
|
1980
2166
|
/** Directory or file to search: a host path or an absolute `scheme://` URL. */
|
|
1981
2167
|
path: string
|
|
1982
|
-
/**
|
|
2168
|
+
/**
|
|
2169
|
+
* Glob filter for file paths (e.g., "*.ts"); a matched directory selects
|
|
2170
|
+
* every file under it.
|
|
2171
|
+
*/
|
|
1983
2172
|
glob?: string
|
|
1984
2173
|
/**
|
|
1985
2174
|
* Match simple glob patterns at any depth (default: true; `*.ts` ->
|
|
@@ -2157,6 +2346,16 @@ export interface HoldOptions {
|
|
|
2157
2346
|
button?: string
|
|
2158
2347
|
keys?: Array<string>
|
|
2159
2348
|
takeover?: boolean
|
|
2349
|
+
/**
|
|
2350
|
+
* With `takeover`, hand focus back to the user's app even after their
|
|
2351
|
+
* input during the hold; see `PointerOptions.returnFocus`.
|
|
2352
|
+
*/
|
|
2353
|
+
returnFocus?: boolean
|
|
2354
|
+
/**
|
|
2355
|
+
* Refuse a background left hold that starts on a control that opens a
|
|
2356
|
+
* menu; see `PointerOptions.refuseMenu`.
|
|
2357
|
+
*/
|
|
2358
|
+
refuseMenu?: boolean
|
|
2160
2359
|
}
|
|
2161
2360
|
|
|
2162
2361
|
/**
|
|
@@ -2193,6 +2392,44 @@ export interface InlineSloppyRegion {
|
|
|
2193
2392
|
*/
|
|
2194
2393
|
export declare function invalidateFsScanCache(path?: string | undefined | null): void
|
|
2195
2394
|
|
|
2395
|
+
/** Options for `IpcConnection.connect`. */
|
|
2396
|
+
export interface IpcConnectOptions {
|
|
2397
|
+
/**
|
|
2398
|
+
* `lines`: UTF-8 text frames delimited by LF; `raw`: byte chunks as
|
|
2399
|
+
* received.
|
|
2400
|
+
*/
|
|
2401
|
+
framing: "lines" | "raw"
|
|
2402
|
+
/** Connect deadline. Default 3000 ms. Expiry rejects with code ETIMEDOUT. */
|
|
2403
|
+
timeoutMs?: number
|
|
2404
|
+
/** Max bytes of one received line (lines framing). Default 64 MiB. */
|
|
2405
|
+
maxFrameBytes?: number
|
|
2406
|
+
}
|
|
2407
|
+
|
|
2408
|
+
/**
|
|
2409
|
+
* Platform endpoint for `name` scoped to directory `dir`.
|
|
2410
|
+
*
|
|
2411
|
+
* Unix: `<dir>/<stem>.sock`; when that path does not fit `sun_path` (104 bytes
|
|
2412
|
+
* on macOS/BSD, 108 on Linux, including NUL), `/tmp/omp-<euid>/<hash16>.sock`.
|
|
2413
|
+
* Windows: `\\.\pipe\omp-<stem>-<hash16(lowercase(resolve(dir)))>`.
|
|
2414
|
+
* `stem` is `name` with every char outside `[A-Za-z0-9._-]` replaced by "_".
|
|
2415
|
+
* Pure and deterministic: every process computes the same endpoint.
|
|
2416
|
+
*/
|
|
2417
|
+
export declare function ipcEndpoint(dir: string, name: string): string
|
|
2418
|
+
|
|
2419
|
+
/** Options for `IpcServer.listen`. */
|
|
2420
|
+
export interface IpcListenOptions {
|
|
2421
|
+
/**
|
|
2422
|
+
* `lines`: UTF-8 text frames delimited by LF; `raw`: byte chunks as
|
|
2423
|
+
* received.
|
|
2424
|
+
*/
|
|
2425
|
+
framing: "lines" | "raw"
|
|
2426
|
+
/**
|
|
2427
|
+
* Max bytes of one received line (lines framing). Default 64 MiB.
|
|
2428
|
+
* Exceeding closes that connection with reason "EMSGSIZE: …".
|
|
2429
|
+
*/
|
|
2430
|
+
maxFrameBytes?: number
|
|
2431
|
+
}
|
|
2432
|
+
|
|
2196
2433
|
/** Kind enum of the backend selected by default for this build target. */
|
|
2197
2434
|
export declare function isoBackend(): IsoBackendKind
|
|
2198
2435
|
|
|
@@ -2342,6 +2579,13 @@ export interface ListWorkspaceOptions {
|
|
|
2342
2579
|
* to find them. Default: false.
|
|
2343
2580
|
*/
|
|
2344
2581
|
collectAgentsMd?: boolean
|
|
2582
|
+
/**
|
|
2583
|
+
* Report unreadable directories instead of silently skipping them: an
|
|
2584
|
+
* unreadable root fails the scan, and unreadable subdirectories are
|
|
2585
|
+
* returned in `unreadableDirectories` while the walk continues. Default:
|
|
2586
|
+
* false (startup discovery stays best-effort).
|
|
2587
|
+
*/
|
|
2588
|
+
reportDirectoryErrors?: boolean
|
|
2345
2589
|
/** Timeout in milliseconds for the operation. */
|
|
2346
2590
|
timeoutMs?: number
|
|
2347
2591
|
/** Abort signal for cancelling the operation. */
|
|
@@ -2359,6 +2603,11 @@ export interface ListWorkspaceResult {
|
|
|
2359
2603
|
agentsMdFiles: Array<string>
|
|
2360
2604
|
/** True when any output cap was hit. */
|
|
2361
2605
|
truncated: boolean
|
|
2606
|
+
/**
|
|
2607
|
+
* Subdirectories whose contents could not be listed. Always empty unless
|
|
2608
|
+
* `reportDirectoryErrors` is set.
|
|
2609
|
+
*/
|
|
2610
|
+
unreadableDirectories: Array<WorkspaceDirectoryError>
|
|
2362
2611
|
}
|
|
2363
2612
|
|
|
2364
2613
|
/**
|
|
@@ -2592,6 +2841,23 @@ export interface NodeSpan {
|
|
|
2592
2841
|
/** Decode notebook JSON into the editable cell-marker text. */
|
|
2593
2842
|
export declare function notebookToEditableText(json: string, displayPath: string): string
|
|
2594
2843
|
|
|
2844
|
+
/** Check syntax through the shared parse cache without constructing a summary. */
|
|
2845
|
+
export declare function parseCodeStatus(options: ParseStatusOptions): ParseStatus
|
|
2846
|
+
|
|
2847
|
+
/**
|
|
2848
|
+
* An opened application: its [`Application`] fields and the window it
|
|
2849
|
+
* shows. On macOS `window` is its frontmost window once one is on screen;
|
|
2850
|
+
* other platforms report none.
|
|
2851
|
+
*/
|
|
2852
|
+
export interface OpenedApplication {
|
|
2853
|
+
id: string
|
|
2854
|
+
name: string
|
|
2855
|
+
path: string
|
|
2856
|
+
running: boolean
|
|
2857
|
+
pid?: number
|
|
2858
|
+
window?: DesktopWindow
|
|
2859
|
+
}
|
|
2860
|
+
|
|
2595
2861
|
/** Parsed Kitty keyboard protocol sequence result for a Kitty input sequence. */
|
|
2596
2862
|
export interface ParsedKittyResult {
|
|
2597
2863
|
/** Primary codepoint associated with the key. */
|
|
@@ -2620,6 +2886,23 @@ export declare function parseKey(data: string, kittyProtocolActive: boolean): st
|
|
|
2620
2886
|
*/
|
|
2621
2887
|
export declare function parseKittySequence(data: string): ParsedKittyResult | null
|
|
2622
2888
|
|
|
2889
|
+
export interface ParseStatus {
|
|
2890
|
+
/** Canonical language name only when parsing succeeded. */
|
|
2891
|
+
language?: string
|
|
2892
|
+
/** True when non-empty source parses without syntax errors. */
|
|
2893
|
+
parsed: boolean
|
|
2894
|
+
}
|
|
2895
|
+
|
|
2896
|
+
/** Options for checking source syntax without generating a summary. */
|
|
2897
|
+
export interface ParseStatusOptions {
|
|
2898
|
+
/** Source code to parse; empty input is not parsed. */
|
|
2899
|
+
code: string
|
|
2900
|
+
/** Language alias; a non-blank value overrides path-based detection. */
|
|
2901
|
+
lang?: string
|
|
2902
|
+
/** File path used to infer language when `lang` is omitted or blank. */
|
|
2903
|
+
path?: string
|
|
2904
|
+
}
|
|
2905
|
+
|
|
2623
2906
|
/** One hunk of a unified diff, matching jsdiff `structuredPatch` hunks. */
|
|
2624
2907
|
export interface PatchHunk {
|
|
2625
2908
|
/** 1-based first line of the hunk in the old text. */
|
|
@@ -2674,6 +2957,26 @@ export interface PointerOptions {
|
|
|
2674
2957
|
* default background delivery.
|
|
2675
2958
|
*/
|
|
2676
2959
|
takeover?: boolean
|
|
2960
|
+
/**
|
|
2961
|
+
* With `takeover`, hand focus back to the user's app even if they typed
|
|
2962
|
+
* or clicked during the action; only a third app they switched to keeps
|
|
2963
|
+
* it. The host sets this when it reruns a refused background action.
|
|
2964
|
+
*/
|
|
2965
|
+
returnFocus?: boolean
|
|
2966
|
+
/**
|
|
2967
|
+
* Item path to choose in the menu a click opens, matched like a menu-bar
|
|
2968
|
+
* path, e.g. a context menu's `["Add to", "Fonts"]`; the call opens the
|
|
2969
|
+
* menu, presses the item and returns with the menu closed.
|
|
2970
|
+
*/
|
|
2971
|
+
menu?: Array<string>
|
|
2972
|
+
/**
|
|
2973
|
+
* Refuse a background left click that lands on a control that opens a
|
|
2974
|
+
* menu (on macOS a menu button or popup button), or a drag that starts on
|
|
2975
|
+
* one, with `BackgroundUnavailable` before anything is sent. The host sets
|
|
2976
|
+
* this when the user refuses foreground takeover: an open menu takes their
|
|
2977
|
+
* keyboard.
|
|
2978
|
+
*/
|
|
2979
|
+
refuseMenu?: boolean
|
|
2677
2980
|
}
|
|
2678
2981
|
|
|
2679
2982
|
/**
|
|
@@ -3733,8 +4036,8 @@ export declare function visibleWidth(text: string, tabWidth: number): number
|
|
|
3733
4036
|
* [`enclosing_block_boundaries`], [`block_range_at`] and [`node_chain_at`]
|
|
3734
4037
|
* are synchronous and parse on the JS thread when their source is not
|
|
3735
4038
|
* cached; awaiting this first makes that parse a cache hit. Resolves without
|
|
3736
|
-
* parsing when the language is unrecognized or the source is
|
|
3737
|
-
* the cache
|
|
4039
|
+
* parsing when the language is unrecognized or the source is over 2 MiB,
|
|
4040
|
+
* where a typical tree would not fit the cache's memory budget.
|
|
3738
4041
|
*/
|
|
3739
4042
|
export declare function warmBlockParse(options: BlockParseOptions): Promise<undefined>
|
|
3740
4043
|
|
|
@@ -3791,6 +4094,14 @@ export interface WorkProfile {
|
|
|
3791
4094
|
sampleCount: number
|
|
3792
4095
|
}
|
|
3793
4096
|
|
|
4097
|
+
/** A subdirectory the scan could not list. */
|
|
4098
|
+
export interface WorkspaceDirectoryError {
|
|
4099
|
+
/** Forward-slash path relative to the scan root. */
|
|
4100
|
+
path: string
|
|
4101
|
+
/** Platform error, e.g. `Permission denied (os error 13)`. */
|
|
4102
|
+
message: string
|
|
4103
|
+
}
|
|
4104
|
+
|
|
3794
4105
|
/**
|
|
3795
4106
|
* Wrap text to a visible width, preserving ANSI escape codes across line
|
|
3796
4107
|
* breaks.
|
package/native/index.js
CHANGED
|
@@ -31,6 +31,8 @@ export const EditSession = nativeBindings.EditSession;
|
|
|
31
31
|
export const EditStore = nativeBindings.EditStore;
|
|
32
32
|
export const FileLock = nativeBindings.FileLock;
|
|
33
33
|
export const HighlightStream = nativeBindings.HighlightStream;
|
|
34
|
+
export const IpcConnection = nativeBindings.IpcConnection;
|
|
35
|
+
export const IpcServer = nativeBindings.IpcServer;
|
|
34
36
|
export const LiveWebRtcPeer = nativeBindings.LiveWebRtcPeer;
|
|
35
37
|
export const MacAppearanceObserver = nativeBindings.MacAppearanceObserver;
|
|
36
38
|
export const NativeOAuthCallback = nativeBindings.NativeOAuthCallback;
|
|
@@ -56,11 +58,13 @@ export const astEdit = nativeBindings.astEdit ?? missingNativeExport("astEdit");
|
|
|
56
58
|
export const astGrep = nativeBindings.astGrep ?? missingNativeExport("astGrep");
|
|
57
59
|
export const astMatch = nativeBindings.astMatch ?? missingNativeExport("astMatch");
|
|
58
60
|
export const blockRangeAt = nativeBindings.blockRangeAt ?? missingNativeExport("blockRangeAt");
|
|
61
|
+
export const closeDesktopEventTaps = nativeBindings.closeDesktopEventTaps ?? missingNativeExport("closeDesktopEventTaps");
|
|
59
62
|
export const copyToClipboard = nativeBindings.copyToClipboard ?? missingNativeExport("copyToClipboard");
|
|
60
63
|
export const cosineSimilarityPairs = nativeBindings.cosineSimilarityPairs ?? missingNativeExport("cosineSimilarityPairs");
|
|
61
64
|
export const countTokens = nativeBindings.countTokens ?? missingNativeExport("countTokens");
|
|
62
65
|
export const decodeSixelToPng = nativeBindings.decodeSixelToPng ?? missingNativeExport("decodeSixelToPng");
|
|
63
66
|
export const decodeSixelToPngAsync = nativeBindings.decodeSixelToPngAsync ?? missingNativeExport("decodeSixelToPngAsync");
|
|
67
|
+
export const desktopEscapeStops = nativeBindings.desktopEscapeStops ?? missingNativeExport("desktopEscapeStops");
|
|
64
68
|
export const detectMacOSAppearance = nativeBindings.detectMacOSAppearance ?? missingNativeExport("detectMacOSAppearance");
|
|
65
69
|
export const deviceCheckGenerateToken = nativeBindings.deviceCheckGenerateToken ?? missingNativeExport("deviceCheckGenerateToken");
|
|
66
70
|
export const diffLineRuns = nativeBindings.diffLineRuns ?? missingNativeExport("diffLineRuns");
|
|
@@ -79,6 +83,7 @@ export const executeShell = nativeBindings.executeShell ?? missingNativeExport("
|
|
|
79
83
|
export const expandWindowsLongPath = nativeBindings.expandWindowsLongPath ?? missingNativeExport("expandWindowsLongPath");
|
|
80
84
|
export const extractInlineSloppyRegions = nativeBindings.extractInlineSloppyRegions ?? missingNativeExport("extractInlineSloppyRegions");
|
|
81
85
|
export const extractSegments = nativeBindings.extractSegments ?? missingNativeExport("extractSegments");
|
|
86
|
+
export const forgetDesktopEscapeStops = nativeBindings.forgetDesktopEscapeStops ?? missingNativeExport("forgetDesktopEscapeStops");
|
|
82
87
|
export const fuzzyFind = nativeBindings.fuzzyFind ?? missingNativeExport("fuzzyFind");
|
|
83
88
|
export const getSupportedLanguages = nativeBindings.getSupportedLanguages ?? missingNativeExport("getSupportedLanguages");
|
|
84
89
|
export const getWindowsShortPath = nativeBindings.getWindowsShortPath ?? missingNativeExport("getWindowsShortPath");
|
|
@@ -95,6 +100,7 @@ export const hasMatch = nativeBindings.hasMatch ?? missingNativeExport("hasMatch
|
|
|
95
100
|
export const highlightCode = nativeBindings.highlightCode ?? missingNativeExport("highlightCode");
|
|
96
101
|
export const htmlToMarkdown = nativeBindings.htmlToMarkdown ?? missingNativeExport("htmlToMarkdown");
|
|
97
102
|
export const invalidateFsScanCache = nativeBindings.invalidateFsScanCache ?? missingNativeExport("invalidateFsScanCache");
|
|
103
|
+
export const ipcEndpoint = nativeBindings.ipcEndpoint ?? missingNativeExport("ipcEndpoint");
|
|
98
104
|
export const isoBackend = nativeBindings.isoBackend ?? missingNativeExport("isoBackend");
|
|
99
105
|
export const isoDiff = nativeBindings.isoDiff ?? missingNativeExport("isoDiff");
|
|
100
106
|
export const isoIsUnavailableError = nativeBindings.isoIsUnavailableError ?? missingNativeExport("isoIsUnavailableError");
|
|
@@ -113,6 +119,7 @@ export const matchesLegacySequence = nativeBindings.matchesLegacySequence ?? mis
|
|
|
113
119
|
export const mmrRerankIndices = nativeBindings.mmrRerankIndices ?? missingNativeExport("mmrRerankIndices");
|
|
114
120
|
export const nodeChainAt = nativeBindings.nodeChainAt ?? missingNativeExport("nodeChainAt");
|
|
115
121
|
export const notebookToEditableText = nativeBindings.notebookToEditableText ?? missingNativeExport("notebookToEditableText");
|
|
122
|
+
export const parseCodeStatus = nativeBindings.parseCodeStatus ?? missingNativeExport("parseCodeStatus");
|
|
116
123
|
export const parseKey = nativeBindings.parseKey ?? missingNativeExport("parseKey");
|
|
117
124
|
export const parseKittySequence = nativeBindings.parseKittySequence ?? missingNativeExport("parseKittySequence");
|
|
118
125
|
export const pdfToMarkdown = nativeBindings.pdfToMarkdown ?? missingNativeExport("pdfToMarkdown");
|
package/native/loader-state.js
CHANGED
|
@@ -65,8 +65,8 @@ function getNativesDir() {
|
|
|
65
65
|
if (path.isAbsolute(dir)) return path.normalize(dir);
|
|
66
66
|
}
|
|
67
67
|
const xdgDataHome = process.env.XDG_DATA_HOME;
|
|
68
|
-
if (xdgDataHome && fs.existsSync(path.join(xdgDataHome, "
|
|
69
|
-
return path.join(xdgDataHome, "
|
|
68
|
+
if (xdgDataHome && fs.existsSync(path.join(xdgDataHome, "zeta"))) {
|
|
69
|
+
return path.join(xdgDataHome, "zeta", "natives");
|
|
70
70
|
}
|
|
71
71
|
return path.join(os.homedir(), ".zeta", "natives");
|
|
72
72
|
}
|
|
@@ -499,13 +499,11 @@ export function extractEmbeddedAddons({ files, targetDir }) {
|
|
|
499
499
|
return writtenPaths;
|
|
500
500
|
}
|
|
501
501
|
|
|
502
|
-
function maybeExtractEmbeddedAddon(ctx, errors) {
|
|
502
|
+
function maybeExtractEmbeddedAddon(ctx, errors, file = selectEmbeddedAddonFile(ctx.selectedVariant)) {
|
|
503
503
|
if (!ctx.isCompiledBinary || !embeddedAddon) return null;
|
|
504
504
|
if (embeddedAddon.platformTag !== ctx.platformTag || embeddedAddon.version !== ctx.packageVersion) return null;
|
|
505
|
-
|
|
506
|
-
const
|
|
507
|
-
if (!selectedEmbeddedFile) return null;
|
|
508
|
-
const targetPath = path.join(ctx.versionedDir, selectedEmbeddedFile.filename);
|
|
505
|
+
if (!file) return null;
|
|
506
|
+
const targetPath = path.join(ctx.versionedDir, file.filename);
|
|
509
507
|
|
|
510
508
|
startupMarker("native:extractEmbeddedAddon:start");
|
|
511
509
|
try {
|
|
@@ -517,11 +515,11 @@ function maybeExtractEmbeddedAddon(ctx, errors) {
|
|
|
517
515
|
}
|
|
518
516
|
|
|
519
517
|
try {
|
|
520
|
-
extractEmbeddedAddons({ files:
|
|
518
|
+
extractEmbeddedAddons({ files: [file], targetDir: ctx.versionedDir });
|
|
521
519
|
return targetPath;
|
|
522
520
|
} catch (err) {
|
|
523
521
|
const message = err instanceof Error ? err.message : String(err);
|
|
524
|
-
errors.push(`embedded addon extraction (${
|
|
522
|
+
errors.push(`embedded addon extraction (${file.filename}): ${message}`);
|
|
525
523
|
return null;
|
|
526
524
|
}
|
|
527
525
|
}
|
|
@@ -866,8 +864,16 @@ export function loadNative() {
|
|
|
866
864
|
const stagedCandidate = embeddedCandidate ? null : maybeStageNodeModulesAddon(ctx, errors);
|
|
867
865
|
const prepended = [embeddedCandidate, stagedCandidate].filter(c => typeof c === "string");
|
|
868
866
|
const runtimeCandidates = prepended.length > 0 ? [...prepended, ...ctx.candidates] : ctx.candidates;
|
|
867
|
+
const fallbackEmbeddedFile =
|
|
868
|
+
ctx.selectedVariant === "modern" && embeddedAddon
|
|
869
|
+
? embeddedAddon.files.find(file => file.variant === "baseline")
|
|
870
|
+
: null;
|
|
871
|
+
const fallbackEmbeddedPath = fallbackEmbeddedFile && path.join(ctx.versionedDir, fallbackEmbeddedFile.filename);
|
|
869
872
|
|
|
870
873
|
for (const candidate of runtimeCandidates) {
|
|
874
|
+
if (fallbackEmbeddedFile && candidate === fallbackEmbeddedPath) {
|
|
875
|
+
maybeExtractEmbeddedAddon(ctx, errors, fallbackEmbeddedFile);
|
|
876
|
+
}
|
|
871
877
|
try {
|
|
872
878
|
startupMarker(`native:require:${path.basename(candidate)}`);
|
|
873
879
|
const bindings = require_(candidate);
|
package/native/vcs.d.ts
CHANGED
|
@@ -81,6 +81,9 @@ export declare function detachGitDir(
|
|
|
81
81
|
signal?: AbortSignal,
|
|
82
82
|
): Promise<"no-git" | "independent" | "detached">;
|
|
83
83
|
|
|
84
|
+
/** Preserve isolation-local Git objects in the source without changing its refs or index. */
|
|
85
|
+
export declare function copyGitObjects(isolationRoot: string, sourceRoot: string): Promise<void>;
|
|
86
|
+
|
|
84
87
|
/** Run Git's checkout hook in a new linked worktree and return its output and exit status. */
|
|
85
88
|
export declare function runPostCheckoutHook(
|
|
86
89
|
worktreeRoot: string,
|
package/native/vcs.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { $ } from "bun";
|
|
2
2
|
import * as fs from "node:fs";
|
|
3
|
+
import * as path from "node:path";
|
|
3
4
|
import { loadNative } from "./loader-state.js";
|
|
4
5
|
|
|
5
6
|
let native;
|
|
@@ -96,6 +97,58 @@ export function detachGitDir(worktreeRoot, sourceCommonDir, signal) {
|
|
|
96
97
|
return api().vcsDetachGitDir(worktreeRoot, sourceCommonDir, signal);
|
|
97
98
|
}
|
|
98
99
|
|
|
100
|
+
/**
|
|
101
|
+
* Publish `from` at `to` only once fully written: copy to a sibling temp name,
|
|
102
|
+
* then hard-link it into place (Git's own `finalize_object_file` strategy) so
|
|
103
|
+
* readers never see a partial file and an interrupted copy leaves only a
|
|
104
|
+
* `tmp_` file that `git gc` prunes. An existing `to` was itself published
|
|
105
|
+
* whole and holds the same content-addressed bytes, so it is kept.
|
|
106
|
+
*/
|
|
107
|
+
async function publishGitObjectFile(from, to) {
|
|
108
|
+
const tmp = path.join(path.dirname(to), `tmp_obj_omp_${crypto.randomUUID()}`);
|
|
109
|
+
try {
|
|
110
|
+
await fs.promises.copyFile(from, tmp, fs.constants.COPYFILE_EXCL);
|
|
111
|
+
try {
|
|
112
|
+
await fs.promises.link(tmp, to);
|
|
113
|
+
} catch (error) {
|
|
114
|
+
if (error?.code === "EEXIST") return;
|
|
115
|
+
// Filesystems without hard links: rename is still atomic, and any
|
|
116
|
+
// file it replaces holds identical content-addressed bytes.
|
|
117
|
+
if (error?.code !== "EPERM" && error?.code !== "ENOTSUP" && error?.code !== "EXDEV") throw error;
|
|
118
|
+
await fs.promises.rename(tmp, to);
|
|
119
|
+
}
|
|
120
|
+
} finally {
|
|
121
|
+
await fs.promises.rm(tmp, { force: true });
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Keep objects created in an isolated Git repository reachable after its
|
|
127
|
+
* worktree is removed, without changing the destination's refs or index.
|
|
128
|
+
* Every file is published atomically; a pack is published before its index.
|
|
129
|
+
*/
|
|
130
|
+
export async function copyGitObjects(isolationRoot, sourceRoot) {
|
|
131
|
+
const from = path.join(requireGit(isolationRoot).info().commonDir, "objects");
|
|
132
|
+
const to = path.join(requireGit(sourceRoot).info().commonDir, "objects");
|
|
133
|
+
for (const entry of await fs.promises.readdir(from, { withFileTypes: true })) {
|
|
134
|
+
if (!entry.isDirectory() || !/^[0-9a-f]{2}$/.test(entry.name)) continue;
|
|
135
|
+
await fs.promises.mkdir(path.join(to, entry.name), { recursive: true });
|
|
136
|
+
for (const name of await fs.promises.readdir(path.join(from, entry.name))) {
|
|
137
|
+
if (!/^[0-9a-f]{38,62}$/.test(name)) continue;
|
|
138
|
+
await publishGitObjectFile(path.join(from, entry.name, name), path.join(to, entry.name, name));
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
const packs = (await fs.promises.readdir(path.join(from, "pack"))).filter(name => name.startsWith("pack-"));
|
|
142
|
+
await fs.promises.mkdir(path.join(to, "pack"), { recursive: true });
|
|
143
|
+
// The index must only become visible after the pack it describes.
|
|
144
|
+
for (const name of packs.filter(name => name.endsWith(".pack"))) {
|
|
145
|
+
await publishGitObjectFile(path.join(from, "pack", name), path.join(to, "pack", name));
|
|
146
|
+
}
|
|
147
|
+
for (const name of packs.filter(name => /\.(?:idx|rev|keep|promisor|mtimes)$/.test(name))) {
|
|
148
|
+
await publishGitObjectFile(path.join(from, "pack", name), path.join(to, "pack", name));
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
99
152
|
/**
|
|
100
153
|
* Run Git's checkout hook in a newly created linked worktree, using the same
|
|
101
154
|
* null old HEAD and branch-switch flag as `git worktree add`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@linxiraos/pi-natives",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"description": "Native Rust bindings for PDF conversion, audio, WebRTC, grep, clipboard, image processing, syntax highlighting, PTY, and shell operations via N-API",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"homepage": "https://linxira-os.github.io/zeta/",
|
|
@@ -32,14 +32,15 @@
|
|
|
32
32
|
"build": "bun ../../scripts/bazel-natives.ts host --dest native",
|
|
33
33
|
"build:bindings": "bun scripts/build-bindings.ts",
|
|
34
34
|
"check": "oxlint . && oxfmt --check --no-error-on-unmatched-pattern 'src/**/*.{ts,tsx}' '{test,bench,examples,scripts}/**/*.ts' '*.ts' && bun run check:types",
|
|
35
|
-
"check:types": "
|
|
35
|
+
"check:types": "tsc -p tsconfig.json --noEmit",
|
|
36
36
|
"lint": "oxlint .",
|
|
37
37
|
"test": "bun test --parallel",
|
|
38
38
|
"fix": "oxlint --fix --fix-suggestions . && bun run fmt",
|
|
39
39
|
"fmt": "oxfmt --no-error-on-unmatched-pattern 'src/**/*.{ts,tsx}' '{test,bench,examples,scripts}/**/*.ts' '*.ts'",
|
|
40
40
|
"gen:npm": "bun scripts/gen-npm-packages.ts",
|
|
41
41
|
"bench": "bun bench/grep.ts",
|
|
42
|
-
"bench:text": "bun bench/text.ts"
|
|
42
|
+
"bench:text": "bun bench/text.ts",
|
|
43
|
+
"bench:ipc": "bun bench/ipc.ts"
|
|
43
44
|
},
|
|
44
45
|
"devDependencies": {
|
|
45
46
|
"@napi-rs/cli": "3.7.2",
|
|
@@ -109,11 +110,11 @@
|
|
|
109
110
|
}
|
|
110
111
|
},
|
|
111
112
|
"optionalDependencies": {
|
|
112
|
-
"@linxiraos/pi-natives-linux-x64": "1.
|
|
113
|
-
"@linxiraos/pi-natives-linux-arm64": "1.
|
|
114
|
-
"@linxiraos/pi-natives-darwin-x64": "1.
|
|
115
|
-
"@linxiraos/pi-natives-darwin-arm64": "1.
|
|
116
|
-
"@linxiraos/pi-natives-win32-x64": "1.
|
|
117
|
-
"@linxiraos/pi-natives-win32-arm64": "1.
|
|
113
|
+
"@linxiraos/pi-natives-linux-x64": "1.3.1",
|
|
114
|
+
"@linxiraos/pi-natives-linux-arm64": "1.3.1",
|
|
115
|
+
"@linxiraos/pi-natives-darwin-x64": "1.3.1",
|
|
116
|
+
"@linxiraos/pi-natives-darwin-arm64": "1.3.1",
|
|
117
|
+
"@linxiraos/pi-natives-win32-x64": "1.3.1",
|
|
118
|
+
"@linxiraos/pi-natives-win32-arm64": "1.3.1"
|
|
118
119
|
}
|
|
119
120
|
}
|