pi-ast-sgrep 2.0.2 → 2.1.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 +15 -19
- package/dist/code-mode.d.ts +1 -1
- package/dist/code-mode.js +1 -1
- package/dist/codemode/connector.d.ts +17 -3
- package/dist/codemode/connector.js +59 -31
- package/dist/codemode/dispatch.d.ts +13 -1
- package/dist/codemode/dispatch.js +83 -23
- package/dist/codemode/guest-api.d.ts +16 -0
- package/dist/codemode/guest-api.js +194 -0
- package/dist/codemode/guest-worker.mjs +287 -0
- package/dist/codemode/index.d.ts +4 -3
- package/dist/codemode/index.js +4 -3
- package/dist/codemode/runner.d.ts +13 -9
- package/dist/codemode/runner.js +411 -213
- package/dist/codemode/session-pool.d.ts +6 -1
- package/dist/codemode/session-pool.js +125 -32
- package/dist/codemode/types.d.ts +33 -2
- package/dist/codemode/types.js +39 -13
- package/dist/codemode/worker.d.ts +1 -1
- package/dist/codemode/worker.js +25 -2
- package/dist/host/commands.d.ts +6 -0
- package/dist/host/commands.js +49 -0
- package/dist/host/results.d.ts +115 -0
- package/dist/host/results.js +80 -0
- package/dist/host/tools.d.ts +9 -0
- package/dist/host/tools.js +610 -0
- package/dist/index.d.ts +7 -34
- package/dist/index.js +5 -543
- package/dist/runtime/config.d.ts +36 -0
- package/dist/runtime/config.js +98 -0
- package/dist/runtime/freshness.d.ts +43 -0
- package/dist/runtime/freshness.js +413 -0
- package/dist/runtime/index-health.d.ts +16 -0
- package/dist/runtime/index-health.js +109 -0
- package/dist/runtime/runtime.d.ts +48 -0
- package/dist/runtime/runtime.js +265 -0
- package/dist/runtime/sqlite.d.ts +15 -0
- package/dist/runtime/sqlite.js +63 -0
- package/dist/runtime/types.d.ts +55 -0
- package/dist/runtime/types.js +25 -0
- package/dist/ui/card.d.ts +63 -0
- package/dist/ui/card.js +316 -0
- package/dist/{present.d.ts → ui/present.d.ts} +20 -2
- package/dist/{present.js → ui/present.js} +68 -9
- package/package.json +6 -6
- package/dist/codemode/sandbox-worker.d.ts +0 -1
- package/dist/codemode/sandbox-worker.js +0 -204
- package/dist/runtime.d.ts +0 -137
- package/dist/runtime.js +0 -799
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
import vm from "node:vm";
|
|
2
|
-
import { parentPort, workerData } from "node:worker_threads";
|
|
3
|
-
const port = (() => {
|
|
4
|
-
if (!parentPort)
|
|
5
|
-
throw new Error("codemode sandbox requires a parent port");
|
|
6
|
-
return parentPort;
|
|
7
|
-
})();
|
|
8
|
-
const data = workerData;
|
|
9
|
-
const pending = new Map();
|
|
10
|
-
const outgoing = [];
|
|
11
|
-
let nextCallId = 0;
|
|
12
|
-
let flushScheduled = false;
|
|
13
|
-
port.on("message", (message) => {
|
|
14
|
-
if (message.type !== "callResult")
|
|
15
|
-
return;
|
|
16
|
-
const resolve = pending.get(message.id);
|
|
17
|
-
if (!resolve)
|
|
18
|
-
return;
|
|
19
|
-
pending.delete(message.id);
|
|
20
|
-
resolve(message.payload);
|
|
21
|
-
});
|
|
22
|
-
const bridge = (method, payload) => new Promise((resolve) => {
|
|
23
|
-
if (nextCallId >= data.limits.bridgeCalls) {
|
|
24
|
-
resolve(JSON.stringify({
|
|
25
|
-
ok: false,
|
|
26
|
-
error: `codemode exceeds ${data.limits.bridgeCalls} host calls`,
|
|
27
|
-
}));
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
const id = nextCallId++;
|
|
31
|
-
pending.set(id, resolve);
|
|
32
|
-
outgoing.push({ id, method, payload });
|
|
33
|
-
if (!flushScheduled) {
|
|
34
|
-
flushScheduled = true;
|
|
35
|
-
queueMicrotask(() => {
|
|
36
|
-
flushScheduled = false;
|
|
37
|
-
const calls = outgoing.splice(0);
|
|
38
|
-
if (calls.length > 0)
|
|
39
|
-
port.postMessage({ type: "calls", calls });
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
});
|
|
43
|
-
void run();
|
|
44
|
-
async function run() {
|
|
45
|
-
const logs = [];
|
|
46
|
-
let logChars = 0;
|
|
47
|
-
const logBridge = (line) => {
|
|
48
|
-
if (logs.length >= data.limits.logLines || logChars >= data.limits.logChars)
|
|
49
|
-
return;
|
|
50
|
-
const remaining = data.limits.logChars - logChars;
|
|
51
|
-
const bounded = line.length <= remaining
|
|
52
|
-
? line
|
|
53
|
-
: `${line.slice(0, Math.max(0, remaining - 1))}…`;
|
|
54
|
-
logs.push(bounded);
|
|
55
|
-
logChars += bounded.length;
|
|
56
|
-
};
|
|
57
|
-
Object.setPrototypeOf(bridge, null);
|
|
58
|
-
Object.setPrototypeOf(logBridge, null);
|
|
59
|
-
Object.freeze(bridge);
|
|
60
|
-
Object.freeze(logBridge);
|
|
61
|
-
try {
|
|
62
|
-
const globals = Object.create(null);
|
|
63
|
-
globals.__asgrepBridge = bridge;
|
|
64
|
-
globals.__asgrepLog = logBridge;
|
|
65
|
-
const context = vm.createContext(globals, {
|
|
66
|
-
codeGeneration: { strings: false, wasm: false },
|
|
67
|
-
});
|
|
68
|
-
new vm.Script(bootstrap(data.limits), {
|
|
69
|
-
filename: "asgrep-codemode-bootstrap.js",
|
|
70
|
-
}).runInContext(context, { timeout: Math.min(data.timeoutMs, 1_000) });
|
|
71
|
-
const script = new vm.Script(data.code, { filename: "asgrep-codemode.js" });
|
|
72
|
-
const value = await Promise.resolve(script.runInContext(context, {
|
|
73
|
-
displayErrors: true,
|
|
74
|
-
timeout: data.timeoutMs,
|
|
75
|
-
}));
|
|
76
|
-
const setResult = context.__asgrepSetResult;
|
|
77
|
-
if (typeof setResult !== "function") {
|
|
78
|
-
throw new Error("codemode result bridge is unavailable");
|
|
79
|
-
}
|
|
80
|
-
setResult(value);
|
|
81
|
-
const serialized = new vm.Script("globalThis.__asgrepSerializeResult()", {
|
|
82
|
-
filename: "asgrep-codemode-result.js",
|
|
83
|
-
}).runInContext(context, {
|
|
84
|
-
displayErrors: true,
|
|
85
|
-
timeout: Math.min(data.timeoutMs, data.limits.serializeTimeoutMs),
|
|
86
|
-
});
|
|
87
|
-
const result = serialized === undefined ? undefined : JSON.parse(serialized);
|
|
88
|
-
finish({ type: "done", ok: true, result, logs });
|
|
89
|
-
}
|
|
90
|
-
catch (cause) {
|
|
91
|
-
finish({
|
|
92
|
-
type: "done",
|
|
93
|
-
ok: false,
|
|
94
|
-
error: safeErrorMessage(cause).slice(0, data.limits.errorChars),
|
|
95
|
-
logs,
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
function safeErrorMessage(cause) {
|
|
100
|
-
try {
|
|
101
|
-
return String(cause instanceof Error ? cause.message : cause);
|
|
102
|
-
}
|
|
103
|
-
catch {
|
|
104
|
-
return "codemode worker failed";
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
function finish(message) {
|
|
108
|
-
port.postMessage(message);
|
|
109
|
-
port.close();
|
|
110
|
-
}
|
|
111
|
-
function bootstrap(limits) {
|
|
112
|
-
return `
|
|
113
|
-
{
|
|
114
|
-
const hostCall = globalThis.__asgrepBridge;
|
|
115
|
-
const hostLog = globalThis.__asgrepLog;
|
|
116
|
-
delete globalThis.__asgrepBridge;
|
|
117
|
-
delete globalThis.__asgrepLog;
|
|
118
|
-
|
|
119
|
-
let resultValue;
|
|
120
|
-
const setResult = (value) => { resultValue = value; };
|
|
121
|
-
const stringify = JSON.stringify;
|
|
122
|
-
const stringifyBounded = (value, maxChars, label) => {
|
|
123
|
-
let remaining = maxChars;
|
|
124
|
-
const serialized = stringify(value, (key, item) => {
|
|
125
|
-
remaining -= key.length + 8;
|
|
126
|
-
if (typeof item === "string") remaining -= item.length;
|
|
127
|
-
if (remaining < 0) throw new Error(\`codemode \${label} exceeds \${maxChars} characters\`);
|
|
128
|
-
return item;
|
|
129
|
-
});
|
|
130
|
-
if (serialized !== undefined && serialized.length > maxChars) {
|
|
131
|
-
throw new Error(\`codemode \${label} exceeds \${maxChars} characters\`);
|
|
132
|
-
}
|
|
133
|
-
return serialized;
|
|
134
|
-
};
|
|
135
|
-
const serializeResult = () => stringifyBounded(resultValue, ${limits.resultJsonChars}, "result");
|
|
136
|
-
Object.freeze(setResult);
|
|
137
|
-
Object.freeze(serializeResult);
|
|
138
|
-
Object.defineProperty(globalThis, "__asgrepSetResult", {
|
|
139
|
-
value: setResult, configurable: false, writable: false,
|
|
140
|
-
});
|
|
141
|
-
Object.defineProperty(globalThis, "__asgrepSerializeResult", {
|
|
142
|
-
value: serializeResult, configurable: false, writable: false,
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
// Worker heap limits do not reliably account for backing stores. Code Mode
|
|
146
|
-
// exchanges JSON, so raw-memory and WebAssembly APIs add risk without utility.
|
|
147
|
-
for (const name of [
|
|
148
|
-
"ArrayBuffer", "SharedArrayBuffer", "DataView", "Atomics", "WebAssembly",
|
|
149
|
-
"Int8Array", "Uint8Array", "Uint8ClampedArray", "Int16Array", "Uint16Array",
|
|
150
|
-
"Int32Array", "Uint32Array", "Float32Array", "Float64Array",
|
|
151
|
-
"BigInt64Array", "BigUint64Array",
|
|
152
|
-
]) {
|
|
153
|
-
Object.defineProperty(globalThis, name, {
|
|
154
|
-
value: undefined, configurable: false, writable: false,
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const invoke = async (method, args = {}) => {
|
|
159
|
-
const payload = stringifyBounded(args, ${limits.bridgeRequestChars}, "call arguments");
|
|
160
|
-
const response = JSON.parse(await hostCall(method, payload));
|
|
161
|
-
if (!response.ok) throw new Error(response.error || \`asgrep.\${method} failed\`);
|
|
162
|
-
return response.value;
|
|
163
|
-
};
|
|
164
|
-
const api = Object.create(null);
|
|
165
|
-
for (const method of [
|
|
166
|
-
"search", "semantic", "chain", "defs", "callers", "imports",
|
|
167
|
-
"indexStatus", "indexRepo", "catalogSearch", "catalogDescribe",
|
|
168
|
-
]) {
|
|
169
|
-
Object.defineProperty(api, method, {
|
|
170
|
-
enumerable: true,
|
|
171
|
-
value: (args = {}) => invoke(method, args),
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
Object.freeze(api);
|
|
175
|
-
|
|
176
|
-
const formatLog = (value) => {
|
|
177
|
-
if (typeof value === "string") return value.slice(0, ${limits.logLineChars});
|
|
178
|
-
try { return stringifyBounded(value, ${limits.logLineChars}, "log line"); }
|
|
179
|
-
catch { return "[unserializable or oversized log value]"; }
|
|
180
|
-
};
|
|
181
|
-
const consoleApi = Object.create(null);
|
|
182
|
-
for (const level of ["log", "info", "warn", "error", "debug"]) {
|
|
183
|
-
Object.defineProperty(consoleApi, level, {
|
|
184
|
-
enumerable: true,
|
|
185
|
-
value: (...args) => {
|
|
186
|
-
let line = "";
|
|
187
|
-
for (const arg of args) {
|
|
188
|
-
const part = formatLog(arg);
|
|
189
|
-
const prefix = line.length === 0 ? "" : " ";
|
|
190
|
-
const remaining = ${limits.logLineChars} - line.length;
|
|
191
|
-
if (remaining <= 0) break;
|
|
192
|
-
line += (prefix + part).slice(0, remaining);
|
|
193
|
-
}
|
|
194
|
-
hostLog(line);
|
|
195
|
-
},
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
Object.freeze(consoleApi);
|
|
199
|
-
|
|
200
|
-
Object.defineProperty(globalThis, "asgrep", { value: api, configurable: false, writable: false });
|
|
201
|
-
Object.defineProperty(globalThis, "console", { value: consoleApi, configurable: false, writable: false });
|
|
202
|
-
}
|
|
203
|
-
`;
|
|
204
|
-
}
|
package/dist/runtime.d.ts
DELETED
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
import { type FSWatcher } from "node:fs";
|
|
2
|
-
import { resolveBinary } from "ast-sgrep";
|
|
3
|
-
export declare const RUNTIME_VERSION = "2.0.0";
|
|
4
|
-
export declare const MACHINE_SCHEMA_VERSION = "1.0.0";
|
|
5
|
-
export declare const CONFIG_SCHEMA_VERSION: 1;
|
|
6
|
-
export declare const INDEX_FORMAT_VERSION: 12;
|
|
7
|
-
export declare const DEFAULT_TIMEOUT_MS = 30000;
|
|
8
|
-
export declare const DEFAULT_MAX_OUTPUT_BYTES: number;
|
|
9
|
-
export declare const DEFAULT_REFRESH_INTERVAL_MS = 30000;
|
|
10
|
-
export interface RuntimeConfig {
|
|
11
|
-
schemaVersion?: typeof CONFIG_SCHEMA_VERSION;
|
|
12
|
-
binaryPath?: string;
|
|
13
|
-
root?: string;
|
|
14
|
-
allowOutsideProject?: boolean;
|
|
15
|
-
timeoutMs?: number;
|
|
16
|
-
maxOutputBytes?: number;
|
|
17
|
-
refreshIntervalMs?: number;
|
|
18
|
-
env?: Readonly<Record<string, string>>;
|
|
19
|
-
}
|
|
20
|
-
export interface LegacyRuntimeConfig extends Omit<RuntimeConfig, "schemaVersion" | "timeoutMs" | "maxOutputBytes" | "refreshIntervalMs"> {
|
|
21
|
-
schemaVersion?: 0;
|
|
22
|
-
timeout?: number;
|
|
23
|
-
maxOutput?: number;
|
|
24
|
-
refreshInterval?: number;
|
|
25
|
-
}
|
|
26
|
-
export type RuntimeConfigInput = RuntimeConfig | LegacyRuntimeConfig;
|
|
27
|
-
export interface ConfigSources {
|
|
28
|
-
explicitProjectConfig?: RuntimeConfigInput;
|
|
29
|
-
projectSettings?: RuntimeConfigInput;
|
|
30
|
-
globalSettings?: RuntimeConfigInput;
|
|
31
|
-
environment?: NodeJS.ProcessEnv;
|
|
32
|
-
defaults?: RuntimeConfigInput;
|
|
33
|
-
}
|
|
34
|
-
export interface RuntimeContext {
|
|
35
|
-
cwd: string;
|
|
36
|
-
}
|
|
37
|
-
export interface RunOptions {
|
|
38
|
-
signal?: AbortSignal;
|
|
39
|
-
timeoutMs?: number;
|
|
40
|
-
env?: Readonly<Record<string, string>>;
|
|
41
|
-
}
|
|
42
|
-
export interface ExecOptions {
|
|
43
|
-
cwd: string;
|
|
44
|
-
env: NodeJS.ProcessEnv;
|
|
45
|
-
signal?: AbortSignal;
|
|
46
|
-
timeout?: number;
|
|
47
|
-
}
|
|
48
|
-
export interface ExecResult {
|
|
49
|
-
stdout: string;
|
|
50
|
-
stderr: string;
|
|
51
|
-
code?: number | null;
|
|
52
|
-
exitCode?: number | null;
|
|
53
|
-
signal?: string | null;
|
|
54
|
-
}
|
|
55
|
-
export interface PiExec {
|
|
56
|
-
exec(command: string, args: readonly string[], options: ExecOptions): Promise<ExecResult>;
|
|
57
|
-
}
|
|
58
|
-
export interface MachineEnvelope {
|
|
59
|
-
tool: "asgrep";
|
|
60
|
-
schema_version: string;
|
|
61
|
-
ok: boolean;
|
|
62
|
-
version?: string;
|
|
63
|
-
machine_schema_version?: string;
|
|
64
|
-
[key: string]: unknown;
|
|
65
|
-
}
|
|
66
|
-
export declare class RuntimeError extends Error {
|
|
67
|
-
readonly code: string;
|
|
68
|
-
readonly details: Readonly<Record<string, unknown>>;
|
|
69
|
-
constructor(code: string, message: string, details?: Readonly<Record<string, unknown>>);
|
|
70
|
-
}
|
|
71
|
-
/** Convert schema 0/unversioned settings without mutating the rollback source. */
|
|
72
|
-
export declare function migrateConfig(input?: RuntimeConfigInput): RuntimeConfig;
|
|
73
|
-
/** Serialize current settings for a schema-0 rollback without mutating the current value. */
|
|
74
|
-
export declare function rollbackConfig(input: RuntimeConfig): LegacyRuntimeConfig;
|
|
75
|
-
/** Merge each setting independently, from the documented lowest to highest priority. */
|
|
76
|
-
export declare function resolveConfig(sources?: ConfigSources): Required<Pick<RuntimeConfig, "timeoutMs" | "maxOutputBytes">> & RuntimeConfig;
|
|
77
|
-
export declare function resolveRuntimeRoot(projectCwd: string, requestedRoot?: string, allowOutsideProject?: boolean): Promise<string>;
|
|
78
|
-
type BinaryResolver = typeof resolveBinary;
|
|
79
|
-
export interface RuntimeDependencies {
|
|
80
|
-
resolveBinary?: BinaryResolver;
|
|
81
|
-
}
|
|
82
|
-
export interface FreshnessRuntime {
|
|
83
|
-
run(args: readonly string[], context: RuntimeContext, options?: RunOptions): Promise<MachineEnvelope>;
|
|
84
|
-
resolveRoot(context: RuntimeContext): Promise<string>;
|
|
85
|
-
inspectIndexCompatibility?(context: RuntimeContext): Promise<IndexHealth>;
|
|
86
|
-
rebuildIncompatibleIndex?(context: RuntimeContext, options?: RunOptions): Promise<MachineEnvelope>;
|
|
87
|
-
/** Absolute database path whose SQLite/derived writes are owned by this runtime. */
|
|
88
|
-
resolveIndexPath?(root: string): string;
|
|
89
|
-
/**
|
|
90
|
-
* Optional warm native call (session sticky pool). When present, freshness
|
|
91
|
-
* prefers this over cold `run` for status/index — same Searcher as Code Mode.
|
|
92
|
-
*/
|
|
93
|
-
nativeCall?(tool: string, args: Record<string, unknown>, context: RuntimeContext, options?: RunOptions): Promise<MachineEnvelope>;
|
|
94
|
-
/** Enable low-latency external filesystem change detection for real runtimes. */
|
|
95
|
-
watchExternalChanges?: boolean;
|
|
96
|
-
}
|
|
97
|
-
export interface FreshnessCoordinatorOptions {
|
|
98
|
-
refreshIntervalMs?: number;
|
|
99
|
-
now?: () => number;
|
|
100
|
-
watchFactory?: FreshnessWatchFactory;
|
|
101
|
-
}
|
|
102
|
-
export type FreshnessWatchFactory = (root: string, options: {
|
|
103
|
-
recursive: true;
|
|
104
|
-
persistent: false;
|
|
105
|
-
encoding: "utf8";
|
|
106
|
-
}, listener: (eventType: "rename" | "change", filename: string | null) => void) => FSWatcher;
|
|
107
|
-
export type IndexHealth = "ready" | "missing" | "incompatible";
|
|
108
|
-
export declare class FreshnessCoordinator {
|
|
109
|
-
#private;
|
|
110
|
-
constructor(options?: FreshnessCoordinatorOptions);
|
|
111
|
-
markAffectedPath(path: string, cwd: string): void;
|
|
112
|
-
markRootDirty(root: string): void;
|
|
113
|
-
ensureFresh(runtime: FreshnessRuntime, context: RuntimeContext, options?: RunOptions): Promise<string>;
|
|
114
|
-
shutdown(): void;
|
|
115
|
-
}
|
|
116
|
-
export declare class AstSgrepRuntime {
|
|
117
|
-
#private;
|
|
118
|
-
private readonly pi;
|
|
119
|
-
readonly watchExternalChanges = true;
|
|
120
|
-
readonly config: ReturnType<typeof resolveConfig>;
|
|
121
|
-
constructor(pi: PiExec, sources?: ConfigSources, dependencies?: RuntimeDependencies);
|
|
122
|
-
resolveRoot(context: RuntimeContext): Promise<string>;
|
|
123
|
-
resolveIndexPath(root: string): string;
|
|
124
|
-
inspectIndexCompatibility(context: RuntimeContext): Promise<IndexHealth>;
|
|
125
|
-
rebuildIncompatibleIndex(context: RuntimeContext, options?: RunOptions): Promise<MachineEnvelope>;
|
|
126
|
-
run(args: readonly string[], context: RuntimeContext, options?: RunOptions): Promise<MachineEnvelope>;
|
|
127
|
-
/** Absolute path to the native binary (for sticky serve / stdin batch spawn). */
|
|
128
|
-
resolveBinaryPath(options?: {
|
|
129
|
-
env?: NodeJS.ProcessEnv;
|
|
130
|
-
}): string;
|
|
131
|
-
/** Merged process env for native Code Mode workers. */
|
|
132
|
-
nativeEnv(options?: {
|
|
133
|
-
env?: NodeJS.ProcessEnv;
|
|
134
|
-
}): NodeJS.ProcessEnv;
|
|
135
|
-
checkCompatibility(context: RuntimeContext, options?: RunOptions): Promise<MachineEnvelope>;
|
|
136
|
-
}
|
|
137
|
-
export {};
|