@oh-my-pi/pi-natives 10.0.0 → 10.2.0

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.
Binary file
Binary file
Binary file
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oh-my-pi/pi-natives",
3
- "version": "10.0.0",
3
+ "version": "10.2.0",
4
4
  "description": "Native Rust functionality via N-API",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -32,7 +32,7 @@
32
32
  "directory": "packages/natives"
33
33
  },
34
34
  "dependencies": {
35
- "@oh-my-pi/pi-utils": "10.0.0"
35
+ "@oh-my-pi/pi-utils": "10.2.0"
36
36
  },
37
37
  "devDependencies": {
38
38
  "@types/node": "^25.0.10"
package/src/bindings.ts CHANGED
@@ -6,8 +6,18 @@
6
6
  /** Callback type for threadsafe functions from N-API. */
7
7
  export type TsFunc<T> = (error: Error | null, value: T) => void;
8
8
 
9
+ /** Options for cancellable operations. */
10
+ export interface Cancellable {
11
+ /** Timeout in milliseconds for the operation. */
12
+ timeoutMs?: number;
13
+ /** Abort signal for cancelling the operation. */
14
+ signal?: AbortSignal;
15
+ }
16
+
9
17
  /**
10
18
  * Native bindings interface.
11
19
  * Extended by each module via declaration merging.
12
20
  */
13
- export interface NativeBindings {}
21
+ export interface NativeBindings {
22
+ cancelWork(id: number): void;
23
+ }
@@ -4,15 +4,16 @@
4
4
 
5
5
  import * as path from "node:path";
6
6
  import { native } from "../native";
7
- import type { FindMatch, FindOptions, FindResult } from "./types";
7
+ import type { GlobMatch, GlobOptions, GlobResult } from "./types";
8
8
 
9
- export type { FindMatch, FindOptions, FindResult } from "./types";
9
+ export type { GlobMatch, GlobOptions, GlobResult } from "./types";
10
+ export { FileType } from "./types";
10
11
 
11
12
  /**
12
13
  * Find files matching a glob pattern.
13
14
  * Respects .gitignore by default.
14
15
  */
15
- export async function find(options: FindOptions, onMatch?: (match: FindMatch) => void): Promise<FindResult> {
16
+ export async function glob(options: GlobOptions, onMatch?: (match: GlobMatch) => void): Promise<GlobResult> {
16
17
  const searchPath = path.resolve(options.path);
17
18
  const pattern = options.pattern || "*";
18
19
 
@@ -20,9 +21,9 @@ export async function find(options: FindOptions, onMatch?: (match: FindMatch) =>
20
21
  const globPattern = pattern.includes("/") || pattern.startsWith("**") ? pattern : `**/${pattern}`;
21
22
 
22
23
  // napi-rs ThreadsafeFunction passes (error, value) - skip callback on error
23
- const cb = onMatch ? (err: Error | null, m: FindMatch) => !err && onMatch(m) : undefined;
24
+ const cb = onMatch ? (err: Error | null, m: GlobMatch) => !err && onMatch(m) : undefined;
24
25
 
25
- return native.find(
26
+ return native.glob(
26
27
  {
27
28
  ...options,
28
29
  path: searchPath,
@@ -2,16 +2,25 @@
2
2
  * Types for native find API.
3
3
  */
4
4
 
5
- import type { TsFunc } from "../bindings";
5
+ import type { Cancellable, TsFunc } from "../bindings";
6
+
7
+ export const enum FileType {
8
+ /** A regular file. */
9
+ File = 1,
10
+ /** A directory. */
11
+ Dir = 2,
12
+ /** A symlink. */
13
+ Symlink = 3,
14
+ }
6
15
 
7
16
  /** Options for discovering files and directories. */
8
- export interface FindOptions {
17
+ export interface GlobOptions extends Cancellable {
9
18
  /** Glob pattern to match (e.g., `*.ts`). */
10
19
  pattern: string;
11
20
  /** Directory to search. */
12
21
  path: string;
13
22
  /** Filter by file type: "file", "dir", or "symlink". */
14
- fileType?: "file" | "dir" | "symlink";
23
+ fileType?: FileType;
15
24
  /** Include hidden files (default: false). */
16
25
  hidden?: boolean;
17
26
  /** Maximum number of results to return. */
@@ -23,19 +32,19 @@ export interface FindOptions {
23
32
  }
24
33
 
25
34
  /** A single filesystem match. */
26
- export interface FindMatch {
35
+ export interface GlobMatch {
27
36
  /** Relative path from the search root. */
28
37
  path: string;
29
38
  /** Resolved filesystem type for the match. */
30
- fileType: "file" | "dir" | "symlink";
39
+ fileType: FileType;
31
40
  /** Modification time in milliseconds since epoch, if available. */
32
41
  mtime?: number;
33
42
  }
34
43
 
35
44
  /** Result of a find operation. */
36
- export interface FindResult {
45
+ export interface GlobResult {
37
46
  /** Matched filesystem entries. */
38
- matches: FindMatch[];
47
+ matches: GlobMatch[];
39
48
  /** Number of matches returned after limits are applied. */
40
49
  totalMatches: number;
41
50
  }
@@ -47,6 +56,6 @@ declare module "../bindings" {
47
56
  * @param options Search options that control globbing and filters.
48
57
  * @param onMatch Optional callback for streaming matches as they are found.
49
58
  */
50
- find(options: FindOptions, onMatch?: TsFunc<FindMatch>): Promise<FindResult>;
59
+ glob(options: GlobOptions, onMatch?: TsFunc<GlobMatch>): Promise<GlobResult>;
51
60
  }
52
61
  }
package/src/grep/index.ts CHANGED
@@ -3,7 +3,6 @@
3
3
  */
4
4
 
5
5
  import { native } from "../native";
6
- import { wrapRequestOptions } from "../request-options";
7
6
  import type {
8
7
  ContextLine,
9
8
  FuzzyFindMatch,
@@ -36,7 +35,7 @@ export type {
36
35
  export async function grep(options: GrepOptions, onMatch?: (match: GrepMatch) => void): Promise<GrepResult> {
37
36
  // napi-rs ThreadsafeFunction passes (error, value) - skip callback on error
38
37
  const cb = onMatch ? (err: Error | null, m: GrepMatch) => !err && onMatch(m) : undefined;
39
- return wrapRequestOptions(() => native.grep(options, cb), options);
38
+ return native.grep(options, cb);
40
39
  }
41
40
 
42
41
  /**
@@ -69,5 +68,5 @@ export function hasMatch(
69
68
  * (case-insensitive). Respects .gitignore by default.
70
69
  */
71
70
  export async function fuzzyFind(options: FuzzyFindOptions): Promise<FuzzyFindResult> {
72
- return wrapRequestOptions(() => native.fuzzyFind(options), options);
71
+ return native.fuzzyFind(options);
73
72
  }
package/src/grep/types.ts CHANGED
@@ -2,11 +2,10 @@
2
2
  * Types for grep/search operations.
3
3
  */
4
4
 
5
- import type { TsFunc } from "../bindings";
6
- import type { RequestOptions } from "../request-options";
5
+ import type { Cancellable, TsFunc } from "../bindings";
7
6
 
8
7
  /** Options for searching files. */
9
- export interface GrepOptions extends RequestOptions {
8
+ export interface GrepOptions extends Cancellable {
10
9
  /** Regex pattern to search for */
11
10
  pattern: string;
12
11
  /** Directory or file to search */
@@ -129,7 +128,7 @@ export type WasmMatch = SearchMatch;
129
128
  export type WasmSearchResult = SearchResult;
130
129
 
131
130
  /** Options for fuzzy file path search. */
132
- export interface FuzzyFindOptions extends RequestOptions {
131
+ export interface FuzzyFindOptions extends Cancellable {
133
132
  /** Substring query to match against file paths (case-insensitive). */
134
133
  query: string;
135
134
  /** Directory to search. */
package/src/html/index.ts CHANGED
@@ -3,7 +3,6 @@
3
3
  */
4
4
 
5
5
  import { native } from "../native";
6
- import { type RequestOptions, wrapRequestOptions } from "../request-options";
7
6
  import type { HtmlToMarkdownOptions } from "./types";
8
7
 
9
8
  export type { HtmlToMarkdownOptions } from "./types";
@@ -15,10 +14,6 @@ export type { HtmlToMarkdownOptions } from "./types";
15
14
  * @param options - Conversion options
16
15
  * @returns Markdown text
17
16
  */
18
- export async function htmlToMarkdown(
19
- html: string,
20
- options?: HtmlToMarkdownOptions,
21
- req?: RequestOptions,
22
- ): Promise<string> {
23
- return wrapRequestOptions(() => native.htmlToMarkdown(html, options), req);
17
+ export async function htmlToMarkdown(html: string, options?: HtmlToMarkdownOptions): Promise<string> {
18
+ return native.htmlToMarkdown(html, options);
24
19
  }
package/src/index.ts CHANGED
@@ -2,8 +2,6 @@
2
2
  * Native utilities powered by N-API.
3
3
  */
4
4
 
5
- export type { RequestOptions } from "./request-options";
6
-
7
5
  // =============================================================================
8
6
  // Clipboard
9
7
  // =============================================================================
@@ -30,10 +28,16 @@ export {
30
28
  } from "./grep";
31
29
 
32
30
  // =============================================================================
33
- // Find (file discovery)
31
+ // Glob (file discovery)
34
32
  // =============================================================================
35
33
 
36
- export { type FindMatch, type FindOptions, type FindResult, find } from "./find";
34
+ export {
35
+ FileType,
36
+ type GlobMatch,
37
+ type GlobOptions,
38
+ type GlobResult,
39
+ glob,
40
+ } from "./glob";
37
41
 
38
42
  // =============================================================================
39
43
  // Image processing (photon-compatible API)
@@ -98,7 +102,6 @@ export { getSystemInfo, type SystemInfo } from "./system-info";
98
102
  // =============================================================================
99
103
 
100
104
  export {
101
- abortShellExecution,
102
105
  executeShell,
103
106
  Shell,
104
107
  type ShellExecuteOptions,
package/src/native.ts CHANGED
@@ -14,7 +14,7 @@ import { embeddedAddon } from "./embedded-addon";
14
14
 
15
15
  // Import types to trigger declaration merging
16
16
  import "./clipboard/types";
17
- import "./find/types";
17
+ import "./glob/types";
18
18
  import "./grep/types";
19
19
  import "./highlight/types";
20
20
  import "./html/types";
@@ -24,6 +24,7 @@ import "./ps/types";
24
24
  import "./shell/types";
25
25
  import "./system-info/types";
26
26
  import "./text/types";
27
+ import "./work/types";
27
28
 
28
29
  export type { NativeBindings, TsFunc } from "./bindings";
29
30
 
@@ -159,7 +160,7 @@ function validateNative(bindings: NativeBindings, source: string): void {
159
160
 
160
161
  checkFn("copyToClipboard");
161
162
  checkFn("readImageFromClipboard");
162
- checkFn("find");
163
+ checkFn("glob");
163
164
  checkFn("fuzzyFind");
164
165
  checkFn("grep");
165
166
  checkFn("search");
@@ -174,7 +175,6 @@ function validateNative(bindings: NativeBindings, source: string): void {
174
175
  checkFn("extractSegments");
175
176
  checkFn("matchesKittySequence");
176
177
  checkFn("executeShell");
177
- checkFn("abortShellExecution");
178
178
  checkFn("Shell");
179
179
  checkFn("parseKey");
180
180
  checkFn("matchesLegacySequence");
@@ -184,6 +184,7 @@ function validateNative(bindings: NativeBindings, source: string): void {
184
184
  checkFn("killTree");
185
185
  checkFn("listDescendants");
186
186
  checkFn("getSystemInfo");
187
+ checkFn("getWorkProfile");
187
188
 
188
189
  if (missing.length) {
189
190
  throw new Error(
@@ -3,20 +3,12 @@
3
3
  */
4
4
 
5
5
  import { native } from "../native";
6
- import type { ShellExecuteOptions, ShellExecuteResult, ShellOptions, ShellRunOptions, ShellRunResult } from "./types";
6
+ import type { ShellExecuteOptions, ShellExecuteResult } from "./types";
7
7
 
8
8
  export type { ShellExecuteOptions, ShellExecuteResult, ShellOptions, ShellRunOptions, ShellRunResult } from "./types";
9
9
 
10
- export interface Shell {
11
- run(options: ShellRunOptions, onChunk?: (error: Error | null, chunk: string) => void): Promise<ShellRunResult>;
12
- abort(): void;
13
- }
14
-
15
- export interface ShellConstructor {
16
- new (options?: ShellOptions): Shell;
17
- }
18
-
19
- export const Shell = native.Shell as ShellConstructor;
10
+ export const { Shell } = native;
11
+ export type Shell = import("./types").Shell;
20
12
 
21
13
  /**
22
14
  * Execute a shell command using brush-core.
@@ -32,12 +24,3 @@ export async function executeShell(
32
24
  const wrappedCallback = onChunk ? (err: Error | null, chunk: string) => !err && onChunk(chunk) : undefined;
33
25
  return native.executeShell(options, wrappedCallback);
34
26
  }
35
-
36
- /**
37
- * Abort a running shell execution.
38
- *
39
- * @param executionId - The execution ID to abort
40
- */
41
- export function abortShellExecution(executionId: string): void {
42
- native.abortShellExecution(executionId);
43
- }
@@ -2,7 +2,7 @@
2
2
  * Types for shell execution via brush-core.
3
3
  */
4
4
 
5
- import type { TsFunc } from "../bindings";
5
+ import type { Cancellable, TsFunc } from "../bindings";
6
6
 
7
7
  /**
8
8
  * Configuration for a persistent brush-core shell session.
@@ -17,15 +17,13 @@ export interface ShellOptions {
17
17
  /**
18
18
  * Options for running a single shell command.
19
19
  */
20
- export interface ShellRunOptions {
20
+ export interface ShellRunOptions extends Cancellable {
21
21
  /** The command to execute. */
22
22
  command: string;
23
23
  /** Working directory for command execution. */
24
24
  cwd?: string;
25
25
  /** Environment variables to apply for this command. */
26
26
  env?: Record<string, string>;
27
- /** Timeout in milliseconds. */
28
- timeoutMs?: number;
29
27
  }
30
28
 
31
29
  /**
@@ -43,7 +41,7 @@ export interface ShellRunResult {
43
41
  /**
44
42
  * Internal options for the native brush-core binding.
45
43
  */
46
- export interface ShellExecuteOptions {
44
+ export interface ShellExecuteOptions extends Cancellable {
47
45
  /** The command to execute. */
48
46
  command: string;
49
47
  /** Working directory for command execution. */
@@ -52,12 +50,6 @@ export interface ShellExecuteOptions {
52
50
  env?: Record<string, string>;
53
51
  /** Environment variables to set once per session. */
54
52
  sessionEnv?: Record<string, string>;
55
- /** Timeout in milliseconds. */
56
- timeoutMs?: number;
57
- /** Unique identifier for this execution (used for abort). */
58
- executionId: string;
59
- /** Session key for persistent brush shell instances. */
60
- sessionKey: string;
61
53
  /** Optional snapshot path to source for bash sessions. */
62
54
  snapshotPath?: string;
63
55
  }
@@ -67,7 +59,7 @@ export interface ShellExecuteOptions {
67
59
  export interface ShellExecuteResult extends ShellRunResult {}
68
60
 
69
61
  /** Native Shell class instance. */
70
- export interface NativeShell {
62
+ export interface Shell {
71
63
  /**
72
64
  * Run a command in the shell.
73
65
  * @param options Command execution options.
@@ -77,17 +69,18 @@ export interface NativeShell {
77
69
  run(options: ShellRunOptions, onChunk?: TsFunc<string>): Promise<ShellRunResult>;
78
70
  /**
79
71
  * Abort all running commands in this session.
72
+ * @param reason Optional reason for the abort.
80
73
  */
81
- abort(): void;
74
+ abort(reason?: string): void;
82
75
  }
83
76
 
84
77
  /** Native Shell class constructor. */
85
- export interface NativeShellConstructor {
78
+ export interface ShellConstructor {
86
79
  /**
87
80
  * Create a new shell session.
88
81
  * @param options Optional session configuration.
89
82
  */
90
- new (options?: ShellOptions): NativeShell;
83
+ new (options?: ShellOptions): Shell;
91
84
  }
92
85
 
93
86
  declare module "../bindings" {
@@ -100,12 +93,8 @@ declare module "../bindings" {
100
93
  * @returns Promise resolving to the command result.
101
94
  */
102
95
  executeShell(options: ShellExecuteOptions, onChunk?: TsFunc<string>): Promise<ShellExecuteResult>;
103
- /**
104
- * Abort a running shell execution by ID.
105
- * @param executionId Execution identifier from ShellExecuteOptions.
106
- */
107
- abortShellExecution(executionId: string): void;
96
+
108
97
  /** Shell class constructor for creating sessions. */
109
- Shell: NativeShellConstructor;
98
+ Shell: ShellConstructor;
110
99
  }
111
100
  }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Work scheduling profiling via native instrumentation.
3
+ *
4
+ * Always-on profiling - samples are collected into a circular buffer.
5
+ * Call `getWorkProfile()` to retrieve recent activity.
6
+ */
7
+
8
+ import { native } from "../native";
9
+
10
+ export type { WorkProfile } from "./types";
11
+ export const { getWorkProfile } = native;
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Types for work scheduling profiling.
3
+ */
4
+
5
+ /**
6
+ * Profiling results from work scheduling instrumentation.
7
+ */
8
+ export interface WorkProfile {
9
+ /** Folded stack format for flamegraph tools. */
10
+ folded: string;
11
+ /** Markdown summary of profiling results. */
12
+ summary: string;
13
+ /** SVG flamegraph (if generation succeeded). */
14
+ svg: string | null;
15
+ /** Total work time in milliseconds. */
16
+ totalMs: number;
17
+ /** Number of samples collected. */
18
+ sampleCount: number;
19
+ }
20
+
21
+ declare module "../bindings" {
22
+ interface NativeBindings {
23
+ /**
24
+ * Get work profile data from the last N seconds.
25
+ *
26
+ * Always-on profiling - samples are collected into a circular buffer.
27
+ * Call this to retrieve recent activity.
28
+ */
29
+ getWorkProfile(lastSeconds: number): WorkProfile;
30
+ }
31
+ }
@@ -1,94 +0,0 @@
1
- export interface RequestOptions {
2
- timeoutMs?: number;
3
- signal?: AbortSignal;
4
- }
5
-
6
- function abortReason(signal?: AbortSignal): Error {
7
- if (!signal || !signal.reason) return new Error("Request aborted");
8
- if (signal.reason instanceof Error) return signal.reason;
9
- return new Error("Request aborted", { cause: signal.reason });
10
- }
11
- export async function wrapRequestOptions<T>(fn: () => Promise<T>, options?: RequestOptions): Promise<T> {
12
- const timeoutMs = options?.timeoutMs ?? 0;
13
- const signal = options?.signal;
14
-
15
- // Fast path: no timeout + no signal
16
- if (!signal && timeoutMs <= 0) return fn();
17
-
18
- // If already aborted, fail immediately
19
- if (signal?.aborted) throw abortReason(signal);
20
-
21
- // If we only have an abort signal and no timeout, keep it simple.
22
- if (signal && timeoutMs <= 0) {
23
- return withAbortSignal(fn, signal);
24
- }
25
-
26
- return withTimeoutAndOptionalAbort(fn, timeoutMs, signal);
27
- }
28
-
29
- function withAbortSignal<T>(fn: () => Promise<T>, signal: AbortSignal): Promise<T> {
30
- return new Promise<T>((resolve, reject) => {
31
- const onAbort = () => {
32
- signal.removeEventListener("abort", onAbort);
33
- reject(abortReason(signal));
34
- };
35
-
36
- signal.addEventListener("abort", onAbort, { once: true });
37
-
38
- // If it races and aborts right after addEventListener, `once` handles it,
39
- // but we still want to short-circuit.
40
- if (signal.aborted) return onAbort();
41
-
42
- fn().then(
43
- v => {
44
- signal.removeEventListener("abort", onAbort);
45
- resolve(v);
46
- },
47
- err => {
48
- signal.removeEventListener("abort", onAbort);
49
- reject(err);
50
- },
51
- );
52
- });
53
- }
54
-
55
- function withTimeoutAndOptionalAbort<T>(fn: () => Promise<T>, timeoutMs: number, signal?: AbortSignal): Promise<T> {
56
- return new Promise<T>((resolve, reject) => {
57
- let settled = false;
58
-
59
- let timeoutId: ReturnType<typeof setTimeout> | undefined;
60
- const cleanup = () => {
61
- if (timeoutId) {
62
- clearTimeout(timeoutId);
63
- timeoutId = undefined;
64
- }
65
- if (signal) signal.removeEventListener("abort", onAbort);
66
- };
67
-
68
- const settle = (ok: boolean, value: any) => {
69
- if (settled) return;
70
- settled = true;
71
- cleanup();
72
- ok ? resolve(value as T) : reject(value);
73
- };
74
-
75
- const onAbort = () => settle(false, abortReason(signal!));
76
-
77
- // timeout
78
- timeoutId = setTimeout(() => {
79
- settle(false, new Error(`Request timed out after ${timeoutMs}ms`));
80
- }, timeoutMs);
81
-
82
- // abort (optional)
83
- if (signal) {
84
- signal.addEventListener("abort", onAbort, { once: true });
85
- if (signal.aborted) return onAbort();
86
- }
87
-
88
- // run
89
- fn().then(
90
- v => settle(true, v),
91
- err => settle(false, err),
92
- );
93
- });
94
- }