pi-ast-sgrep 1.4.0 → 2.0.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/README.md +42 -12
- package/dist/code-mode.d.ts +18 -10
- package/dist/code-mode.js +126 -42
- package/dist/codemode/connector.d.ts +37 -9
- package/dist/codemode/connector.js +29 -23
- package/dist/codemode/dispatch.d.ts +2 -3
- package/dist/codemode/dispatch.js +109 -131
- package/dist/codemode/index.d.ts +8 -9
- package/dist/codemode/index.js +7 -8
- package/dist/codemode/native.d.ts +6 -9
- package/dist/codemode/native.js +10 -1
- package/dist/codemode/runner.d.ts +37 -0
- package/dist/codemode/runner.js +242 -0
- package/dist/codemode/sandbox-worker.d.ts +1 -0
- package/dist/codemode/sandbox-worker.js +204 -0
- package/dist/codemode/session-pool.d.ts +1 -0
- package/dist/codemode/session-pool.js +94 -29
- package/dist/codemode/types.d.ts +2 -2
- package/dist/codemode/types.js +2 -2
- package/dist/codemode/worker.d.ts +3 -0
- package/dist/codemode/worker.js +99 -42
- package/dist/index.d.ts +6 -1
- package/dist/index.js +192 -106
- package/dist/present.d.ts +67 -0
- package/dist/present.js +166 -0
- package/dist/runtime.d.ts +16 -2
- package/dist/runtime.js +399 -131
- package/package.json +6 -14
- package/dist/codemode/sandbox.d.ts +0 -25
- package/dist/codemode/sandbox.js +0 -192
- package/skills/ast-sgrep/SKILL.md +0 -73
- package/skills/ast-sgrep/references/query-guide.md +0 -22
|
@@ -13,6 +13,8 @@ export type StickyWorkerOptions = {
|
|
|
13
13
|
signal?: AbortSignal;
|
|
14
14
|
/** Kill worker when one request exceeds this duration (ms). */
|
|
15
15
|
timeoutMs?: number;
|
|
16
|
+
/** Maximum bytes accepted in one NDJSON response. */
|
|
17
|
+
maxOutputBytes?: number;
|
|
16
18
|
};
|
|
17
19
|
export declare function startStickyWorker(options: StickyWorkerOptions): Promise<StickyWorker>;
|
|
18
20
|
/** One-shot batch via stdin (avoids tempfile). */
|
|
@@ -23,4 +25,5 @@ export declare function runBatchViaStdin(options: {
|
|
|
23
25
|
env?: NodeJS.ProcessEnv;
|
|
24
26
|
signal?: AbortSignal;
|
|
25
27
|
timeoutMs?: number;
|
|
28
|
+
maxOutputBytes?: number;
|
|
26
29
|
}): Promise<MachineEnvelope>;
|
package/dist/codemode/worker.js
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* Amdahl win over per-wave `codemode-batch` spawns.
|
|
6
6
|
*/
|
|
7
7
|
import { spawn } from "node:child_process";
|
|
8
|
-
import { createInterface } from "node:readline";
|
|
9
8
|
import { asEnvelope } from "./dispatch.js";
|
|
9
|
+
const DEFAULT_MAX_OUTPUT_BYTES = 4 * 1024 * 1024;
|
|
10
10
|
export async function startStickyWorker(options) {
|
|
11
11
|
if (options.signal?.aborted) {
|
|
12
12
|
throw new Error("codemode-serve aborted before start");
|
|
@@ -20,7 +20,9 @@ export async function startStickyWorker(options) {
|
|
|
20
20
|
let nextId = 0;
|
|
21
21
|
let closed = false;
|
|
22
22
|
let stderr = "";
|
|
23
|
-
|
|
23
|
+
let stdout = Buffer.alloc(0);
|
|
24
|
+
const decoder = new TextDecoder("utf-8", { fatal: true });
|
|
25
|
+
const maxOutputBytes = options.maxOutputBytes ?? DEFAULT_MAX_OUTPUT_BYTES;
|
|
24
26
|
const failAll = (err) => {
|
|
25
27
|
for (const p of pending.values())
|
|
26
28
|
p.reject(err);
|
|
@@ -30,11 +32,13 @@ export async function startStickyWorker(options) {
|
|
|
30
32
|
if (closed)
|
|
31
33
|
return;
|
|
32
34
|
closed = true;
|
|
35
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
33
36
|
killChild(child);
|
|
34
37
|
failAll(err);
|
|
35
|
-
|
|
38
|
+
child.stdout.destroy();
|
|
36
39
|
};
|
|
37
|
-
|
|
40
|
+
child.stdin.on("error", terminate);
|
|
41
|
+
const handleLine = (line) => {
|
|
38
42
|
const trimmed = line.trim();
|
|
39
43
|
if (!trimmed)
|
|
40
44
|
return;
|
|
@@ -43,7 +47,7 @@ export async function startStickyWorker(options) {
|
|
|
43
47
|
msg = JSON.parse(trimmed);
|
|
44
48
|
}
|
|
45
49
|
catch (cause) {
|
|
46
|
-
|
|
50
|
+
terminate(new Error(`codemode-serve bad JSON: ${trimmed.slice(0, 200)}`));
|
|
47
51
|
void cause;
|
|
48
52
|
return;
|
|
49
53
|
}
|
|
@@ -58,6 +62,44 @@ export async function startStickyWorker(options) {
|
|
|
58
62
|
return;
|
|
59
63
|
pending.delete(id);
|
|
60
64
|
waiter.resolve(msg);
|
|
65
|
+
};
|
|
66
|
+
child.stdout.on("data", (chunk) => {
|
|
67
|
+
if (closed)
|
|
68
|
+
return;
|
|
69
|
+
const bytes = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
70
|
+
let offset = 0;
|
|
71
|
+
let newline;
|
|
72
|
+
while ((newline = bytes.indexOf(0x0a, offset)) >= 0) {
|
|
73
|
+
const segment = bytes.subarray(offset, newline);
|
|
74
|
+
const lineBytes = stdout.length + segment.length + 1;
|
|
75
|
+
if (lineBytes > maxOutputBytes) {
|
|
76
|
+
terminate(new Error(`codemode-serve output exceeded ${maxOutputBytes} bytes`));
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
const line = stdout.length === 0
|
|
80
|
+
? segment
|
|
81
|
+
: Buffer.concat([stdout, segment], stdout.length + segment.length);
|
|
82
|
+
stdout = Buffer.alloc(0);
|
|
83
|
+
try {
|
|
84
|
+
handleLine(decoder.decode(line));
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
terminate(new Error("codemode-serve output is not valid UTF-8"));
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
if (closed)
|
|
91
|
+
return;
|
|
92
|
+
offset = newline + 1;
|
|
93
|
+
}
|
|
94
|
+
const tail = bytes.subarray(offset);
|
|
95
|
+
if (stdout.length + tail.length > maxOutputBytes) {
|
|
96
|
+
terminate(new Error(`codemode-serve output exceeded ${maxOutputBytes} bytes`));
|
|
97
|
+
}
|
|
98
|
+
else if (tail.length > 0) {
|
|
99
|
+
stdout = stdout.length === 0
|
|
100
|
+
? Buffer.from(tail)
|
|
101
|
+
: Buffer.concat([stdout, tail], stdout.length + tail.length);
|
|
102
|
+
}
|
|
61
103
|
});
|
|
62
104
|
child.stderr.on("data", (chunk) => {
|
|
63
105
|
stderr += String(chunk);
|
|
@@ -65,11 +107,11 @@ export async function startStickyWorker(options) {
|
|
|
65
107
|
stderr = stderr.slice(-8_192);
|
|
66
108
|
});
|
|
67
109
|
child.on("error", (err) => {
|
|
68
|
-
|
|
69
|
-
failAll(err);
|
|
110
|
+
terminate(err);
|
|
70
111
|
});
|
|
71
112
|
child.on("close", (code, signal) => {
|
|
72
113
|
closed = true;
|
|
114
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
73
115
|
if (pending.size > 0) {
|
|
74
116
|
failAll(new Error(`codemode-serve exited code=${code ?? "null"} signal=${signal ?? "null"} stderr=${stderr.slice(0, 512)}`));
|
|
75
117
|
}
|
|
@@ -84,12 +126,15 @@ export async function startStickyWorker(options) {
|
|
|
84
126
|
payload.id = id;
|
|
85
127
|
return new Promise((resolve, reject) => {
|
|
86
128
|
pending.set(id, { resolve, reject });
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
}
|
|
129
|
+
try {
|
|
130
|
+
child.stdin.write(`${JSON.stringify(payload)}\n`, (err) => {
|
|
131
|
+
if (err)
|
|
132
|
+
terminate(err);
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
catch (cause) {
|
|
136
|
+
terminate(cause instanceof Error ? cause : new Error(String(cause)));
|
|
137
|
+
}
|
|
93
138
|
});
|
|
94
139
|
};
|
|
95
140
|
const writeWithControls = (payload, label, signal) => {
|
|
@@ -151,21 +196,9 @@ export async function startStickyWorker(options) {
|
|
|
151
196
|
return out;
|
|
152
197
|
},
|
|
153
198
|
async end() {
|
|
154
|
-
options.signal?.removeEventListener("abort", onAbort);
|
|
155
199
|
if (closed)
|
|
156
200
|
return;
|
|
157
|
-
|
|
158
|
-
if (child.stdin.writable) {
|
|
159
|
-
child.stdin.write(`${JSON.stringify({ type: "end" })}\n`);
|
|
160
|
-
child.stdin.end();
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
catch {
|
|
164
|
-
// ignore
|
|
165
|
-
}
|
|
166
|
-
killChild(child);
|
|
167
|
-
closed = true;
|
|
168
|
-
rl.close();
|
|
201
|
+
terminate(new Error("codemode-serve ended"));
|
|
169
202
|
},
|
|
170
203
|
};
|
|
171
204
|
}
|
|
@@ -181,48 +214,72 @@ export async function runBatchViaStdin(options) {
|
|
|
181
214
|
});
|
|
182
215
|
let stdout = "";
|
|
183
216
|
let stderr = "";
|
|
217
|
+
let outputBytes = 0;
|
|
218
|
+
let settled = false;
|
|
219
|
+
const maxOutputBytes = options.maxOutputBytes ?? DEFAULT_MAX_OUTPUT_BYTES;
|
|
220
|
+
const cleanup = () => {
|
|
221
|
+
if (timer)
|
|
222
|
+
clearTimeout(timer);
|
|
223
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
224
|
+
};
|
|
225
|
+
const finish = (action) => {
|
|
226
|
+
if (settled)
|
|
227
|
+
return;
|
|
228
|
+
settled = true;
|
|
229
|
+
cleanup();
|
|
230
|
+
action();
|
|
231
|
+
};
|
|
232
|
+
const fail = (error) => finish(() => {
|
|
233
|
+
killChild(child);
|
|
234
|
+
reject(error);
|
|
235
|
+
});
|
|
236
|
+
child.stdin.on("error", fail);
|
|
184
237
|
const timer = options.timeoutMs && options.timeoutMs > 0
|
|
185
238
|
? setTimeout(() => {
|
|
186
|
-
|
|
187
|
-
reject(new Error(`codemode-batch timed out after ${options.timeoutMs}ms`));
|
|
239
|
+
fail(new Error(`codemode-batch timed out after ${options.timeoutMs}ms`));
|
|
188
240
|
}, options.timeoutMs)
|
|
189
241
|
: undefined;
|
|
190
242
|
const onAbort = () => {
|
|
191
|
-
|
|
192
|
-
reject(new Error("codemode-batch aborted"));
|
|
243
|
+
fail(new Error("codemode-batch aborted"));
|
|
193
244
|
};
|
|
194
245
|
options.signal?.addEventListener("abort", onAbort, { once: true });
|
|
195
246
|
child.stdout.on("data", (c) => {
|
|
247
|
+
outputBytes += Buffer.byteLength(c);
|
|
248
|
+
if (outputBytes > maxOutputBytes) {
|
|
249
|
+
fail(new Error(`codemode-batch output exceeded ${maxOutputBytes} bytes`));
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
196
252
|
stdout += String(c);
|
|
197
253
|
});
|
|
198
254
|
child.stderr.on("data", (c) => {
|
|
255
|
+
outputBytes += Buffer.byteLength(c);
|
|
256
|
+
if (outputBytes > maxOutputBytes) {
|
|
257
|
+
fail(new Error(`codemode-batch output exceeded ${maxOutputBytes} bytes`));
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
199
260
|
stderr += String(c);
|
|
200
261
|
});
|
|
201
262
|
child.on("error", (err) => {
|
|
202
|
-
|
|
203
|
-
clearTimeout(timer);
|
|
204
|
-
options.signal?.removeEventListener("abort", onAbort);
|
|
205
|
-
reject(err);
|
|
263
|
+
fail(err);
|
|
206
264
|
});
|
|
207
265
|
child.on("close", (code) => {
|
|
208
|
-
if (
|
|
209
|
-
|
|
210
|
-
options.signal?.removeEventListener("abort", onAbort);
|
|
266
|
+
if (settled)
|
|
267
|
+
return;
|
|
211
268
|
if (code !== 0) {
|
|
212
|
-
|
|
269
|
+
fail(new Error(`codemode-batch exited ${code}: ${stderr.slice(0, 512) || stdout.slice(0, 512)}`));
|
|
213
270
|
return;
|
|
214
271
|
}
|
|
215
272
|
try {
|
|
216
|
-
|
|
273
|
+
const value = JSON.parse(stdout);
|
|
274
|
+
finish(() => resolve(value));
|
|
217
275
|
}
|
|
218
276
|
catch (cause) {
|
|
219
|
-
|
|
277
|
+
fail(cause instanceof Error ? cause : new Error(String(cause)));
|
|
220
278
|
}
|
|
221
279
|
});
|
|
222
280
|
child.stdin.write(options.body, (err) => {
|
|
223
281
|
if (err) {
|
|
224
|
-
|
|
225
|
-
reject(err);
|
|
282
|
+
fail(err);
|
|
226
283
|
return;
|
|
227
284
|
}
|
|
228
285
|
child.stdin.end();
|
package/dist/index.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ type RuntimeLike = {
|
|
|
15
15
|
}): NodeJS.ProcessEnv;
|
|
16
16
|
config?: {
|
|
17
17
|
timeoutMs?: number;
|
|
18
|
+
maxOutputBytes?: number;
|
|
18
19
|
refreshIntervalMs?: number;
|
|
19
20
|
};
|
|
20
21
|
inspectIndexCompatibility?(context: {
|
|
@@ -23,8 +24,12 @@ type RuntimeLike = {
|
|
|
23
24
|
rebuildIncompatibleIndex?(context: {
|
|
24
25
|
cwd: string;
|
|
25
26
|
}, options?: RunOptions): Promise<MachineEnvelope>;
|
|
27
|
+
resolveIndexPath?(root: string): string;
|
|
28
|
+
watchExternalChanges?: boolean;
|
|
29
|
+
};
|
|
30
|
+
type FreshnessLike = Pick<FreshnessCoordinator, "ensureFresh" | "markAffectedPath"> & {
|
|
31
|
+
shutdown?(): void;
|
|
26
32
|
};
|
|
27
|
-
type FreshnessLike = Pick<FreshnessCoordinator, "ensureFresh" | "markAffectedPath">;
|
|
28
33
|
export declare function registerAstSgrepTools(pi: ExtensionAPI, runtime?: RuntimeLike, freshness?: FreshnessLike): void;
|
|
29
34
|
export declare function registerAstSgrepCommands(pi: ExtensionAPI, runtime?: RuntimeLike): void;
|
|
30
35
|
export default function astSgrepExtension(pi: ExtensionAPI): void;
|