@gajae-code/natives 0.10.1 → 0.11.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.
- package/native/index.d.ts +69 -9
- package/native/index.js +1 -1
- package/native/loader-state.d.ts +15 -0
- package/native/loader-state.js +47 -20
- package/package.json +6 -6
package/native/index.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export declare class ComputerController {
|
|
|
12
12
|
keypress(expectedEpoch: number | undefined | null, keys: Array<string>): void
|
|
13
13
|
wait(expectedEpoch: number | undefined | null, ms: number): void
|
|
14
14
|
}
|
|
15
|
+
|
|
15
16
|
/**
|
|
16
17
|
* Long-lived macOS appearance observer.
|
|
17
18
|
*
|
|
@@ -117,6 +118,16 @@ export declare class NotificationServer {
|
|
|
117
118
|
* config commands). Must be called before [`Self::start`].
|
|
118
119
|
*/
|
|
119
120
|
onInbound(callback: (err: null | Error, msg: InboundEvent) => void): void
|
|
121
|
+
/**
|
|
122
|
+
* Register the raw v3 SDK frame callback. Must be called before
|
|
123
|
+
* [`Self::start`].
|
|
124
|
+
*/
|
|
125
|
+
onSdkFrame(callback: (err: null | Error, frame: SdkFrameEvent) => void): void
|
|
126
|
+
/**
|
|
127
|
+
* Register the connection-close callback. Must be called before
|
|
128
|
+
* [`Self::start`].
|
|
129
|
+
*/
|
|
130
|
+
onConnectionClose(callback: (err: null | Error, connectionId: string) => void): void
|
|
120
131
|
/**
|
|
121
132
|
* Bind the loopback endpoint and start serving. Resolves with the bound
|
|
122
133
|
* endpoint info once the socket is bound.
|
|
@@ -128,12 +139,32 @@ export declare class NotificationServer {
|
|
|
128
139
|
/**
|
|
129
140
|
* Broadcast an `action_needed` ask. `needed_json` is a JSON `ActionNeeded`.
|
|
130
141
|
*
|
|
131
|
-
* `repliable` should be `true` only
|
|
142
|
+
* `repliable` should be `true` only when an SDK workflow-gate resolver is
|
|
143
|
+
* available.
|
|
132
144
|
*
|
|
133
145
|
* # Errors
|
|
134
146
|
* Fails if not started or `needed_json` is invalid.
|
|
135
147
|
*/
|
|
136
148
|
registerAsk(neededJson: string, repliable: boolean): void
|
|
149
|
+
/**
|
|
150
|
+
* Register a correlated workflow-gate ask. `workflow_json` must be an
|
|
151
|
+
* `action_needed` wire frame carrying a nonempty `workflowGateId`.
|
|
152
|
+
*/
|
|
153
|
+
registerWorkflowGateAsk(workflowJson: string, repliable: boolean): void
|
|
154
|
+
/**
|
|
155
|
+
* Register an ask and return an opaque in-process capability. Pass it
|
|
156
|
+
* unchanged to [`Self::retire_if_unclaimed`]; do not construct, persist,
|
|
157
|
+
* inspect, or treat it as workflow-gate authority. A supplied
|
|
158
|
+
* `workflowGateId` is preserved.
|
|
159
|
+
*/
|
|
160
|
+
registerArbitratedAsk(neededJson: string, repliable: boolean): PresentationLease
|
|
161
|
+
/**
|
|
162
|
+
* Atomically terminalize the exact presentation named by an opaque lease.
|
|
163
|
+
* The typed status proves whether it retired, was already terminal, was
|
|
164
|
+
* claimed, or became stale without exposing claims, receipts, registration
|
|
165
|
+
* state, or workflow-gate authority.
|
|
166
|
+
*/
|
|
167
|
+
retireIfUnclaimed(lease: PresentationLease): RetireIfUnclaimedResult
|
|
137
168
|
/**
|
|
138
169
|
* Broadcast an ephemeral `action_needed` idle ping. `needed_json` is JSON
|
|
139
170
|
* `ActionNeeded`.
|
|
@@ -152,6 +183,8 @@ export declare class NotificationServer {
|
|
|
152
183
|
* Fails if not started or `frame_json` is not a valid `ServerMessage`.
|
|
153
184
|
*/
|
|
154
185
|
pushFrame(frameJson: string): void
|
|
186
|
+
/** Send raw JSON to one connected v3 SDK client. */
|
|
187
|
+
sendTo(connectionId: string, json: string): void
|
|
155
188
|
/**
|
|
156
189
|
* Publish a replayable `session_ready` readiness signal. `ready_json` is a
|
|
157
190
|
* JSON `SessionReady`. Unlike [`Self::push_frame`], this frame is buffered
|
|
@@ -164,11 +197,10 @@ export declare class NotificationServer {
|
|
|
164
197
|
*/
|
|
165
198
|
pushSessionReady(readyJson: string): void
|
|
166
199
|
/**
|
|
167
|
-
* Resolve
|
|
168
|
-
*
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
* Fails if not started or `answer_json` is invalid.
|
|
200
|
+
* Resolve a legacy/non-arbitrated action locally (the CLI/TUI answered).
|
|
201
|
+
* Arbitrated presentations require their opaque exact lease to be passed to
|
|
202
|
+
* [`Self::retire_if_unclaimed`], so an id-only local resolution fails
|
|
203
|
+
* closed.
|
|
172
204
|
*/
|
|
173
205
|
resolveLocal(id: string, answerJson?: string | undefined | null): void
|
|
174
206
|
/**
|
|
@@ -206,7 +238,7 @@ export declare class NotificationServer {
|
|
|
206
238
|
*/
|
|
207
239
|
reject(id: string, reason?: string | undefined | null): void
|
|
208
240
|
/**
|
|
209
|
-
* Update whether the
|
|
241
|
+
* Update whether the SDK workflow-gate resolver is currently available.
|
|
210
242
|
*
|
|
211
243
|
* # Errors
|
|
212
244
|
* Fails if not started.
|
|
@@ -226,6 +258,8 @@ export declare class Process {
|
|
|
226
258
|
static fromPath(path: string): Array<Process>
|
|
227
259
|
/** Operating-system process identifier for this process reference. */
|
|
228
260
|
get pid(): number
|
|
261
|
+
/** Kernel-derived identity evidence for this exact process incarnation. */
|
|
262
|
+
get incarnation(): string
|
|
229
263
|
/** Parent process id for this process, when available. */
|
|
230
264
|
get ppid(): number | null
|
|
231
265
|
/** Launch arguments for this process. */
|
|
@@ -315,7 +349,7 @@ export declare class Shell {
|
|
|
315
349
|
* `packages/natives/native/index.js` (which derives the name from
|
|
316
350
|
* `package.json#version`).
|
|
317
351
|
*/
|
|
318
|
-
export declare function
|
|
352
|
+
export declare function __piNativesV0_11_0(): void
|
|
319
353
|
|
|
320
354
|
/**
|
|
321
355
|
* Apply conservative pre-execution rewrites to a bash command.
|
|
@@ -1419,6 +1453,18 @@ export declare function parseKey(data: string, kittyProtocolActive: boolean): st
|
|
|
1419
1453
|
*/
|
|
1420
1454
|
export declare function parseKittySequence(data: string): ParsedKittyResult | null
|
|
1421
1455
|
|
|
1456
|
+
/**
|
|
1457
|
+
* Opaque in-process presentation capability.
|
|
1458
|
+
*
|
|
1459
|
+
* Returned by [`NotificationServer::register_arbitrated_ask`]. Pass it
|
|
1460
|
+
* unchanged to [`NotificationServer::retire_if_unclaimed`]; do not construct,
|
|
1461
|
+
* persist, inspect, or treat it as workflow-gate authority.
|
|
1462
|
+
*/
|
|
1463
|
+
export interface PresentationLease {
|
|
1464
|
+
actionId: string
|
|
1465
|
+
registrationEpoch: number
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1422
1468
|
/** Current state of a process reference. */
|
|
1423
1469
|
export declare enum ProcessStatus {
|
|
1424
1470
|
/** The referenced process is still running. */
|
|
@@ -1497,7 +1543,10 @@ export declare function readImageFromClipboard(): Promise<ClipboardImage | undef
|
|
|
1497
1543
|
|
|
1498
1544
|
/** A client reply forwarded to the TypeScript host for gate resolution. */
|
|
1499
1545
|
export interface ReplyEvent {
|
|
1500
|
-
/**
|
|
1546
|
+
/**
|
|
1547
|
+
* The transient action/presentation id being answered. This is not the
|
|
1548
|
+
* durable workflow gate id.
|
|
1549
|
+
*/
|
|
1501
1550
|
id: string
|
|
1502
1551
|
/** JSON-encoded `ReplyAnswer` (number, string, or `{selected,custom}`). */
|
|
1503
1552
|
answerJson: string
|
|
@@ -1507,6 +1556,17 @@ export interface ReplyEvent {
|
|
|
1507
1556
|
replyReceiptId: string
|
|
1508
1557
|
}
|
|
1509
1558
|
|
|
1559
|
+
/** Public status of exact direct retirement. Claims and receipts remain native. */
|
|
1560
|
+
export interface RetireIfUnclaimedResult {
|
|
1561
|
+
status: 'retired' | 'already_terminal' | 'claimed' | 'stale'
|
|
1562
|
+
}
|
|
1563
|
+
|
|
1564
|
+
/** A raw v3 SDK frame paired with its actual WebSocket connection id. */
|
|
1565
|
+
export interface SdkFrameEvent {
|
|
1566
|
+
connectionId: string
|
|
1567
|
+
json: string
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1510
1570
|
/**
|
|
1511
1571
|
* Search content for a pattern (one-shot, compiles pattern each time).
|
|
1512
1572
|
* For repeated searches with the same pattern, use [`grep`] with file filters.
|
package/native/index.js
CHANGED
|
@@ -27,7 +27,7 @@ export const PtySession = nativeBindings.PtySession;
|
|
|
27
27
|
export const Shell = nativeBindings.Shell;
|
|
28
28
|
|
|
29
29
|
// functions
|
|
30
|
-
export const
|
|
30
|
+
export const __piNativesV0_11_0 = nativeBindings.__piNativesV0_11_0;
|
|
31
31
|
export const applyBashFixups = nativeBindings.applyBashFixups;
|
|
32
32
|
export const astEdit = nativeBindings.astEdit;
|
|
33
33
|
export const astGrep = nativeBindings.astGrep;
|
package/native/loader-state.d.ts
CHANGED
|
@@ -47,6 +47,7 @@ export interface ResolveLoaderCandidatesInput {
|
|
|
47
47
|
addonFilenames: string[];
|
|
48
48
|
isCompiledBinary: boolean;
|
|
49
49
|
stageFromNodeModules?: boolean;
|
|
50
|
+
isWorkspaceLoad?: boolean;
|
|
50
51
|
optionalPackageNativeDirs?: string[];
|
|
51
52
|
nativeDir: string;
|
|
52
53
|
execDir: string;
|
|
@@ -56,4 +57,18 @@ export interface ResolveLoaderCandidatesInput {
|
|
|
56
57
|
|
|
57
58
|
export function resolveLoaderCandidates(input: ResolveLoaderCandidatesInput): string[];
|
|
58
59
|
|
|
60
|
+
export interface LoadFromCandidatesInput<T> {
|
|
61
|
+
candidates: string[];
|
|
62
|
+
requireCandidate: (candidate: string) => T;
|
|
63
|
+
validateCandidate: (bindings: T, candidate: string) => void;
|
|
64
|
+
describeCandidate: (candidate: string) => string;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface LoadFromCandidatesResult<T> {
|
|
68
|
+
bindings: T | null;
|
|
69
|
+
errors: string[];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function loadFromCandidates<T>(input: LoadFromCandidatesInput<T>): LoadFromCandidatesResult<T>;
|
|
73
|
+
|
|
59
74
|
export function loadNative(): Record<string, unknown>;
|
package/native/loader-state.js
CHANGED
|
@@ -146,6 +146,7 @@ export function shouldStageNodeModulesAddon({ platform, isCompiledBinary, native
|
|
|
146
146
|
* addonFilenames: string[];
|
|
147
147
|
* isCompiledBinary: boolean;
|
|
148
148
|
* stageFromNodeModules?: boolean;
|
|
149
|
+
* isWorkspaceLoad?: boolean;
|
|
149
150
|
* optionalPackageNativeDirs?: string[];
|
|
150
151
|
* nativeDir: string;
|
|
151
152
|
* execDir: string;
|
|
@@ -158,12 +159,14 @@ export function resolveLoaderCandidates({
|
|
|
158
159
|
addonFilenames,
|
|
159
160
|
isCompiledBinary,
|
|
160
161
|
stageFromNodeModules = false,
|
|
162
|
+
isWorkspaceLoad = false,
|
|
161
163
|
optionalPackageNativeDirs = [],
|
|
162
164
|
nativeDir,
|
|
163
165
|
execDir,
|
|
164
166
|
versionedDir,
|
|
165
167
|
userDataDir,
|
|
166
168
|
}) {
|
|
169
|
+
const workspaceCandidates = addonFilenames.map(filename => path.join(nativeDir, filename));
|
|
167
170
|
const optionalPackageCandidates = optionalPackageNativeDirs.flatMap(optionalNativeDir =>
|
|
168
171
|
addonFilenames.map(filename => path.join(optionalNativeDir, filename)),
|
|
169
172
|
);
|
|
@@ -171,7 +174,10 @@ export function resolveLoaderCandidates({
|
|
|
171
174
|
path.join(nativeDir, filename),
|
|
172
175
|
path.join(execDir, filename),
|
|
173
176
|
]);
|
|
174
|
-
const
|
|
177
|
+
const legacyExecCandidates = addonFilenames.map(filename => path.join(execDir, filename));
|
|
178
|
+
const baseReleaseCandidates = isWorkspaceLoad
|
|
179
|
+
? [...workspaceCandidates, ...optionalPackageCandidates, ...legacyExecCandidates]
|
|
180
|
+
: [...optionalPackageCandidates, ...legacyReleaseCandidates];
|
|
175
181
|
const compiledCandidates = addonFilenames.flatMap(filename => [
|
|
176
182
|
path.join(versionedDir, filename),
|
|
177
183
|
path.join(userDataDir, filename),
|
|
@@ -188,6 +194,35 @@ export function resolveLoaderCandidates({
|
|
|
188
194
|
return [...new Set(releaseCandidates)];
|
|
189
195
|
}
|
|
190
196
|
|
|
197
|
+
/**
|
|
198
|
+
* Deterministically try candidate paths in order using injected operations.
|
|
199
|
+
* This leaves file loading and compatibility policy at the call site while
|
|
200
|
+
* making fallback behavior testable without a native addon on disk.
|
|
201
|
+
*
|
|
202
|
+
* @template T
|
|
203
|
+
* @param {{
|
|
204
|
+
* candidates: string[];
|
|
205
|
+
* requireCandidate: (candidate: string) => T;
|
|
206
|
+
* validateCandidate: (bindings: T, candidate: string) => void;
|
|
207
|
+
* describeCandidate: (candidate: string) => string;
|
|
208
|
+
* }} input
|
|
209
|
+
* @returns {{ bindings: T | null; errors: string[] }}
|
|
210
|
+
*/
|
|
211
|
+
export function loadFromCandidates({ candidates, requireCandidate, validateCandidate, describeCandidate }) {
|
|
212
|
+
const errors = [];
|
|
213
|
+
for (const candidate of candidates) {
|
|
214
|
+
try {
|
|
215
|
+
const bindings = requireCandidate(candidate);
|
|
216
|
+
validateCandidate(bindings, candidate);
|
|
217
|
+
return { bindings, errors };
|
|
218
|
+
} catch (err) {
|
|
219
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
220
|
+
errors.push(`${describeCandidate(candidate)}: ${message}`);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return { bindings: null, errors };
|
|
224
|
+
}
|
|
225
|
+
|
|
191
226
|
// =========================================================================
|
|
192
227
|
// Side-effectful loader. Everything below runs only when `loadNative()` is
|
|
193
228
|
// called from `native/index.js` — tests that only import the pure helpers
|
|
@@ -342,12 +377,6 @@ function maybeStageNodeModulesAddon(ctx, errors) {
|
|
|
342
377
|
}
|
|
343
378
|
|
|
344
379
|
function validateLoadedBindings(ctx, bindings, candidate) {
|
|
345
|
-
// In workspace dev (running out of `packages/natives/native/` rather than a
|
|
346
|
-
// `node_modules` install or a compiled bundle) the local `.node` only gains
|
|
347
|
-
// the renamed sentinel after `bun --cwd=packages/natives run build`. Skip
|
|
348
|
-
// validation there so a stale post-pull dev tree boots while the rebuild
|
|
349
|
-
// completes; install and compiled-binary paths still validate.
|
|
350
|
-
if (ctx.isWorkspaceLoad) return;
|
|
351
380
|
if (typeof bindings[ctx.versionSentinelExport] === "function") return;
|
|
352
381
|
throw new Error(
|
|
353
382
|
`Loaded ${candidate} but it does not expose the @gajae-code/natives@${ctx.packageVersion} ` +
|
|
@@ -405,6 +434,8 @@ function initLoaderContext(require_) {
|
|
|
405
434
|
isCompiledBinary,
|
|
406
435
|
nativeDir,
|
|
407
436
|
});
|
|
437
|
+
const isWorkspaceLoad =
|
|
438
|
+
!isCompiledBinary && !nativeDir.includes("\\node_modules\\") && !nativeDir.includes("/node_modules/");
|
|
408
439
|
|
|
409
440
|
const selectedVariant = resolveCpuVariant(getVariantOverride());
|
|
410
441
|
const addonFilenames = getAddonFilenames({ tag: platformTag, arch: process.arch, variant: selectedVariant });
|
|
@@ -419,6 +450,7 @@ function initLoaderContext(require_) {
|
|
|
419
450
|
addonFilenames,
|
|
420
451
|
isCompiledBinary,
|
|
421
452
|
stageFromNodeModules,
|
|
453
|
+
isWorkspaceLoad,
|
|
422
454
|
optionalPackageNativeDirs,
|
|
423
455
|
nativeDir,
|
|
424
456
|
execDir,
|
|
@@ -434,8 +466,6 @@ function initLoaderContext(require_) {
|
|
|
434
466
|
// turns the silent `<sym> is not a function` crash from a Windows
|
|
435
467
|
// locked-file update into an actionable load-time error.
|
|
436
468
|
const versionSentinelExport = `__piNativesV${packageVersion.replace(/[^A-Za-z0-9]/g, "_")}`;
|
|
437
|
-
const isWorkspaceLoad =
|
|
438
|
-
!isCompiledBinary && !nativeDir.includes("\\node_modules\\") && !nativeDir.includes("/node_modules/");
|
|
439
469
|
|
|
440
470
|
return {
|
|
441
471
|
platformTag,
|
|
@@ -450,7 +480,6 @@ function initLoaderContext(require_) {
|
|
|
450
480
|
addonLabel,
|
|
451
481
|
candidates,
|
|
452
482
|
versionSentinelExport,
|
|
453
|
-
isWorkspaceLoad,
|
|
454
483
|
};
|
|
455
484
|
}
|
|
456
485
|
|
|
@@ -464,16 +493,14 @@ export function loadNative() {
|
|
|
464
493
|
const prepended = [embeddedCandidate, stagedCandidate].filter(c => typeof c === "string");
|
|
465
494
|
const runtimeCandidates = prepended.length > 0 ? [...prepended, ...ctx.candidates] : ctx.candidates;
|
|
466
495
|
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
}
|
|
476
|
-
}
|
|
496
|
+
const loaded = loadFromCandidates({
|
|
497
|
+
candidates: runtimeCandidates,
|
|
498
|
+
requireCandidate: candidate => require_(candidate),
|
|
499
|
+
validateCandidate: (bindings, candidate) => validateLoadedBindings(ctx, bindings, candidate),
|
|
500
|
+
describeCandidate: candidate => candidate,
|
|
501
|
+
});
|
|
502
|
+
if (loaded.bindings) return loaded.bindings;
|
|
503
|
+
errors.push(...loaded.errors);
|
|
477
504
|
|
|
478
505
|
if (!SUPPORTED_PLATFORMS.includes(ctx.platformTag)) {
|
|
479
506
|
throw new Error(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gajae-code/natives",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "Native Rust bindings for grep, clipboard, image processing, syntax highlighting, PTY, and shell operations via N-API",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"homepage": "https://gajae-code.com",
|
|
@@ -61,11 +61,11 @@
|
|
|
61
61
|
"README.md"
|
|
62
62
|
],
|
|
63
63
|
"optionalDependencies": {
|
|
64
|
-
"@gajae-code/natives-darwin-arm64": "0.
|
|
65
|
-
"@gajae-code/natives-darwin-x64": "0.
|
|
66
|
-
"@gajae-code/natives-linux-arm64": "0.
|
|
67
|
-
"@gajae-code/natives-linux-x64": "0.
|
|
68
|
-
"@gajae-code/natives-win32-x64": "0.
|
|
64
|
+
"@gajae-code/natives-darwin-arm64": "0.11.0",
|
|
65
|
+
"@gajae-code/natives-darwin-x64": "0.11.0",
|
|
66
|
+
"@gajae-code/natives-linux-arm64": "0.11.0",
|
|
67
|
+
"@gajae-code/natives-linux-x64": "0.11.0",
|
|
68
|
+
"@gajae-code/natives-win32-x64": "0.11.0"
|
|
69
69
|
},
|
|
70
70
|
"exports": {
|
|
71
71
|
".": {
|