@lensagent/core 0.1.0 → 0.1.2
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 +63 -4
- package/config/lens.example.jsonc +36 -13
- package/dist/adapters/executor-router.d.ts +20 -0
- package/dist/adapters/executor-router.js +86 -0
- package/dist/adapters/executor.d.ts +9 -3
- package/dist/adapters/executor.js +196 -61
- package/dist/adapters/lsp.d.ts +2 -1
- package/dist/adapters/lsp.js +98 -41
- package/dist/adapters/mcp.js +52 -17
- package/dist/adapters/revert.d.ts +5 -4
- package/dist/adapters/revert.js +6 -64
- package/dist/adapters/web.d.ts +9 -0
- package/dist/adapters/web.js +244 -0
- package/dist/config/files.d.ts +14 -0
- package/dist/config/files.js +57 -0
- package/dist/config/runtime.d.ts +3 -4
- package/dist/config/runtime.js +116 -97
- package/dist/config/schema.d.ts +56 -10
- package/dist/config/schema.js +48 -8
- package/dist/contracts/capability.d.ts +27 -1
- package/dist/contracts/domain.d.ts +1 -0
- package/dist/contracts/model.d.ts +33 -6
- package/dist/contracts/review.d.ts +17 -0
- package/dist/contracts/review.js +1 -0
- package/dist/core/access-policy.d.ts +40 -0
- package/dist/core/access-policy.js +68 -0
- package/dist/core/access.d.ts +30 -2
- package/dist/core/access.js +159 -26
- package/dist/core/context-boundaries.d.ts +25 -0
- package/dist/core/context-boundaries.js +106 -0
- package/dist/core/context.d.ts +3 -0
- package/dist/core/context.js +11 -0
- package/dist/core/host.js +261 -173
- package/dist/entry/pair.d.ts +1 -0
- package/dist/entry/pair.js +14 -0
- package/dist/entry/run.js +1 -1
- package/dist/execution/lsp-process.d.ts +3 -2
- package/dist/execution/lsp-process.js +46 -28
- package/dist/http/server.d.ts +5 -0
- package/dist/http/server.js +262 -80
- package/dist/runtime/agent.d.ts +9 -4
- package/dist/runtime/agent.js +361 -286
- package/dist/runtime/artifacts.d.ts +13 -1
- package/dist/runtime/artifacts.js +137 -10
- package/dist/runtime/cache.d.ts +59 -16
- package/dist/runtime/cache.js +124 -43
- package/dist/runtime/calls.d.ts +1 -1
- package/dist/runtime/calls.js +164 -48
- package/dist/runtime/capabilities.d.ts +2 -2
- package/dist/runtime/capabilities.js +4 -5
- package/dist/runtime/cleanup.d.ts +5 -2
- package/dist/runtime/cleanup.js +48 -17
- package/dist/runtime/compaction.d.ts +9 -0
- package/dist/runtime/compaction.js +52 -0
- package/dist/runtime/context.d.ts +8 -4
- package/dist/runtime/context.js +115 -128
- package/dist/runtime/events.d.ts +7 -0
- package/dist/runtime/events.js +83 -0
- package/dist/runtime/images.d.ts +14 -0
- package/dist/runtime/images.js +82 -0
- package/dist/runtime/kernel-capabilities.d.ts +7 -1
- package/dist/runtime/kernel-capabilities.js +146 -68
- package/dist/runtime/model-audit.d.ts +9 -0
- package/dist/runtime/model-audit.js +39 -0
- package/dist/runtime/model.d.ts +109 -4
- package/dist/runtime/model.js +368 -143
- package/dist/runtime/observability.d.ts +1 -0
- package/dist/runtime/observability.js +60 -15
- package/dist/runtime/policy.d.ts +1 -1
- package/dist/runtime/policy.js +2 -2
- package/dist/runtime/profile.d.ts +2 -1
- package/dist/runtime/profile.js +12 -15
- package/dist/runtime/projects.d.ts +3 -1
- package/dist/runtime/projects.js +38 -17
- package/dist/runtime/ptc-worker.d.ts +1 -0
- package/dist/runtime/ptc-worker.js +97 -0
- package/dist/runtime/ptc.d.ts +16 -0
- package/dist/runtime/ptc.js +128 -0
- package/dist/runtime/results.d.ts +5 -4
- package/dist/runtime/results.js +29 -51
- package/dist/runtime/review.d.ts +4 -1
- package/dist/runtime/review.js +101 -22
- package/dist/runtime/scheduler.js +1 -0
- package/dist/runtime/skills.js +34 -5
- package/dist/runtime/task-audit.d.ts +21 -0
- package/dist/runtime/task-audit.js +122 -0
- package/dist/runtime/time.d.ts +9 -0
- package/dist/runtime/time.js +18 -0
- package/dist/runtime/tokenizer.d.ts +2 -0
- package/dist/runtime/tokenizer.js +26 -1
- package/dist/store/database.js +26 -1
- package/dist/store/event-log.d.ts +1 -0
- package/dist/store/event-log.js +22 -5
- package/dist/store/schema.d.ts +1 -1
- package/dist/store/schema.js +50 -1
- package/dist/store/store.d.ts +65 -19
- package/dist/store/store.js +986 -188
- package/package.json +18 -8
- package/proto/executor.proto +69 -55
|
@@ -2,13 +2,14 @@ export declare class LspProcess {
|
|
|
2
2
|
#private;
|
|
3
3
|
readonly maxFrameBytes: number;
|
|
4
4
|
readonly maxBufferBytes: number;
|
|
5
|
-
|
|
5
|
+
readonly requestTimeoutMs: number;
|
|
6
|
+
constructor(command: string, args: readonly string[], cwd: string, maxFrameBytes: number, maxBufferBytes: number, requestTimeoutMs?: number);
|
|
6
7
|
get pid(): number | undefined;
|
|
7
8
|
get initialized(): boolean;
|
|
8
9
|
get closed(): boolean;
|
|
9
10
|
markInitialized(): void;
|
|
10
11
|
request(method: string, params: unknown, signal?: AbortSignal, allowClosing?: boolean): Promise<unknown>;
|
|
11
|
-
notify(method: string, params: unknown, allowClosing?: boolean): void
|
|
12
|
+
notify(method: string, params: unknown, allowClosing?: boolean, signal?: AbortSignal): Promise<void>;
|
|
12
13
|
drainNotifications(): readonly unknown[];
|
|
13
14
|
close(): Promise<void>;
|
|
14
15
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { once } from 'node:events';
|
|
1
2
|
import { spawn } from 'node:child_process';
|
|
2
3
|
export class LspProcess {
|
|
3
4
|
maxFrameBytes;
|
|
4
5
|
maxBufferBytes;
|
|
6
|
+
requestTimeoutMs;
|
|
5
7
|
#child;
|
|
6
8
|
#pending = new Map();
|
|
7
9
|
#notifications = [];
|
|
@@ -11,10 +13,15 @@ export class LspProcess {
|
|
|
11
13
|
#initialized = false;
|
|
12
14
|
#closed = false;
|
|
13
15
|
#closing;
|
|
14
|
-
|
|
16
|
+
#writeTail = Promise.resolve();
|
|
17
|
+
#queuedBytes = 0;
|
|
18
|
+
#lifetime = new AbortController();
|
|
19
|
+
constructor(command, args, cwd, maxFrameBytes, maxBufferBytes, requestTimeoutMs = 30000) {
|
|
15
20
|
this.maxFrameBytes = maxFrameBytes;
|
|
16
21
|
this.maxBufferBytes = maxBufferBytes;
|
|
22
|
+
this.requestTimeoutMs = requestTimeoutMs;
|
|
17
23
|
this.#child = spawn(command, args, { cwd, env: processEnvironment(), shell: false, windowsHide: true });
|
|
24
|
+
this.#child.stderr.resume();
|
|
18
25
|
this.#child.stdout.on('data', (chunk) => this.#receive(chunk));
|
|
19
26
|
this.#child.stdin.on('error', () => this.#fail(lspError('LSP_SERVER_UNAVAILABLE', 'The LSP input stream failed.')));
|
|
20
27
|
this.#child.once('error', () => this.#fail(lspError('LSP_SERVER_UNAVAILABLE', 'The LSP server could not start.')));
|
|
@@ -37,39 +44,39 @@ export class LspProcess {
|
|
|
37
44
|
return Promise.reject(lspError('LSP_SERVER_UNAVAILABLE', 'The LSP session is closed.'));
|
|
38
45
|
if (signal?.aborted === true)
|
|
39
46
|
return Promise.reject(abortError(signal.reason));
|
|
47
|
+
if (this.#pending.size >= 128)
|
|
48
|
+
return Promise.reject(lspError('LSP_PROTOCOL_ERROR', 'Too many pending LSP requests.'));
|
|
49
|
+
const deadline = new AbortController();
|
|
50
|
+
const timeout = setTimeout(() => deadline.abort(lspError('LSP_SERVER_UNAVAILABLE', 'The LSP request timed out.')), this.requestTimeoutMs);
|
|
51
|
+
signal = signal === undefined ? deadline.signal : AbortSignal.any([signal, deadline.signal]);
|
|
40
52
|
const id = this.#nextId++;
|
|
41
53
|
return new Promise((resolve, reject) => {
|
|
42
54
|
const onAbort = () => {
|
|
43
55
|
if (!this.#pending.delete(id))
|
|
44
56
|
return;
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
catch { /* The local cancellation remains authoritative. */ }
|
|
49
|
-
reject(abortError(signal?.reason));
|
|
57
|
+
void this.notify('$/cancelRequest', { id }, allowClosing).catch(() => undefined);
|
|
58
|
+
finish(() => reject(abortError(signal.reason)));
|
|
50
59
|
};
|
|
51
60
|
const finish = (operation) => {
|
|
52
|
-
|
|
61
|
+
clearTimeout(timeout);
|
|
62
|
+
signal.removeEventListener('abort', onAbort);
|
|
53
63
|
operation();
|
|
54
64
|
};
|
|
55
65
|
this.#pending.set(id, {
|
|
56
66
|
resolve: (value) => finish(() => resolve(value)),
|
|
57
67
|
reject: (error) => finish(() => reject(error))
|
|
58
68
|
});
|
|
59
|
-
signal
|
|
60
|
-
|
|
61
|
-
this.#send({ jsonrpc: '2.0', id, method, params });
|
|
62
|
-
}
|
|
63
|
-
catch (error) {
|
|
69
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
70
|
+
void this.#send({ jsonrpc: '2.0', id, method, params }, signal).catch((error) => {
|
|
64
71
|
this.#pending.delete(id);
|
|
65
72
|
finish(() => reject(asError(error)));
|
|
66
|
-
}
|
|
73
|
+
});
|
|
67
74
|
});
|
|
68
75
|
}
|
|
69
|
-
notify(method, params, allowClosing = false) {
|
|
76
|
+
async notify(method, params, allowClosing = false, signal) {
|
|
70
77
|
if (this.#closed || (this.#closing !== undefined && !allowClosing))
|
|
71
78
|
throw lspError('LSP_SERVER_UNAVAILABLE', 'The LSP session is closed.');
|
|
72
|
-
this.#send({ jsonrpc: '2.0', method, params });
|
|
79
|
+
await this.#send({ jsonrpc: '2.0', method, params }, signal);
|
|
73
80
|
}
|
|
74
81
|
drainNotifications() {
|
|
75
82
|
const result = this.#notifications.splice(0);
|
|
@@ -86,27 +93,34 @@ export class LspProcess {
|
|
|
86
93
|
const timeout = setTimeout(() => controller.abort(), 1000);
|
|
87
94
|
try {
|
|
88
95
|
await this.request('shutdown', null, controller.signal, true);
|
|
96
|
+
await this.notify('exit', null, true, controller.signal);
|
|
89
97
|
}
|
|
90
98
|
catch { /* Process termination follows. */ }
|
|
91
99
|
finally {
|
|
92
100
|
clearTimeout(timeout);
|
|
93
101
|
}
|
|
94
|
-
try {
|
|
95
|
-
this.notify('exit', null, true);
|
|
96
|
-
}
|
|
97
|
-
catch { /* The process may already be gone. */ }
|
|
98
102
|
}
|
|
99
103
|
await terminate(this.#child);
|
|
100
104
|
this.#fail(lspError('LSP_SERVER_UNAVAILABLE', 'The LSP session was closed.'));
|
|
101
105
|
}
|
|
102
|
-
#send(value) {
|
|
103
|
-
if (!this.#child.stdin.writable)
|
|
104
|
-
throw lspError('LSP_SERVER_UNAVAILABLE', 'The LSP server is not writable.');
|
|
106
|
+
#send(value, signal) {
|
|
105
107
|
const content = Buffer.from(JSON.stringify(value));
|
|
106
108
|
if (content.byteLength > this.maxFrameBytes)
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
this.#
|
|
109
|
+
return Promise.reject(lspError('LSP_PROTOCOL_ERROR', 'The LSP frame exceeds the configured limit.'));
|
|
110
|
+
const frame = Buffer.concat([Buffer.from(`Content-Length: ${content.byteLength}\r\n\r\n`), content]);
|
|
111
|
+
if (this.#queuedBytes + frame.byteLength > this.maxBufferBytes)
|
|
112
|
+
return Promise.reject(lspError('LSP_PROTOCOL_ERROR', 'The LSP write queue is full.'));
|
|
113
|
+
this.#queuedBytes += frame.byteLength;
|
|
114
|
+
const combined = signal === undefined ? this.#lifetime.signal : AbortSignal.any([signal, this.#lifetime.signal]);
|
|
115
|
+
const operation = this.#writeTail.then(async () => {
|
|
116
|
+
combined.throwIfAborted();
|
|
117
|
+
if (!this.#child.stdin.writable)
|
|
118
|
+
throw lspError('LSP_SERVER_UNAVAILABLE', 'The LSP server is not writable.');
|
|
119
|
+
if (!this.#child.stdin.write(frame))
|
|
120
|
+
await once(this.#child.stdin, 'drain', { signal: combined });
|
|
121
|
+
}).finally(() => { this.#queuedBytes -= frame.byteLength; });
|
|
122
|
+
this.#writeTail = operation.catch(() => undefined);
|
|
123
|
+
return operation;
|
|
110
124
|
}
|
|
111
125
|
#receive(chunk) {
|
|
112
126
|
if (this.#closed)
|
|
@@ -150,7 +164,7 @@ export class LspProcess {
|
|
|
150
164
|
#dispatch(message) {
|
|
151
165
|
if (typeof message.method === 'string') {
|
|
152
166
|
if (typeof message.id === 'number' || typeof message.id === 'string') {
|
|
153
|
-
this.#send({ jsonrpc: '2.0', id: message.id, error: { code: -32601, message: 'Server-initiated requests are not supported.' } });
|
|
167
|
+
void this.#send({ jsonrpc: '2.0', id: message.id, error: { code: -32601, message: 'Server-initiated requests are not supported.' } }).catch((error) => this.#protocolFailure(asError(error).message));
|
|
154
168
|
}
|
|
155
169
|
else {
|
|
156
170
|
const bytes = Buffer.byteLength(JSON.stringify(message));
|
|
@@ -184,6 +198,7 @@ export class LspProcess {
|
|
|
184
198
|
if (this.#closed && this.#pending.size === 0)
|
|
185
199
|
return;
|
|
186
200
|
this.#closed = true;
|
|
201
|
+
this.#lifetime.abort(error);
|
|
187
202
|
for (const pending of this.#pending.values())
|
|
188
203
|
pending.reject(error);
|
|
189
204
|
this.#pending.clear();
|
|
@@ -210,11 +225,14 @@ function processEnvironment(explicit = {}) {
|
|
|
210
225
|
return Object.fromEntries(selected.values());
|
|
211
226
|
}
|
|
212
227
|
async function terminate(child) {
|
|
213
|
-
if (child.exitCode !== null || child.signalCode !== null)
|
|
228
|
+
if (child.pid === undefined || child.exitCode !== null || child.signalCode !== null)
|
|
214
229
|
return;
|
|
215
230
|
const closed = new Promise((resolve) => child.once('close', () => resolve()));
|
|
216
231
|
child.kill('SIGTERM');
|
|
217
|
-
|
|
232
|
+
let timer;
|
|
233
|
+
const graceful = await Promise.race([closed.then(() => true), new Promise((resolve) => { timer = setTimeout(() => resolve(false), 1000); })]);
|
|
234
|
+
if (timer !== undefined)
|
|
235
|
+
clearTimeout(timer);
|
|
218
236
|
if (!graceful) {
|
|
219
237
|
child.kill('SIGKILL');
|
|
220
238
|
await closed;
|
package/dist/http/server.d.ts
CHANGED
|
@@ -8,7 +8,10 @@ import type { ProjectRuntime } from '../runtime/projects.js';
|
|
|
8
8
|
import type { ArtifactStore } from '../runtime/artifacts.js';
|
|
9
9
|
import type { Observability } from '../runtime/observability.js';
|
|
10
10
|
import type { ExecutorClient } from '../adapters/executor.js';
|
|
11
|
+
import type { ExecutorRouter } from '../adapters/executor-router.js';
|
|
12
|
+
import type { TaskAuditReader } from '../runtime/task-audit.js';
|
|
11
13
|
interface Dependencies {
|
|
14
|
+
readonly taskAudit?: TaskAuditReader;
|
|
12
15
|
readonly https?: {
|
|
13
16
|
readonly key: Buffer;
|
|
14
17
|
readonly cert: Buffer;
|
|
@@ -21,6 +24,8 @@ interface Dependencies {
|
|
|
21
24
|
readonly artifacts: ArtifactStore;
|
|
22
25
|
readonly observability: Observability;
|
|
23
26
|
readonly executor: ExecutorClient;
|
|
27
|
+
readonly executorRouter?: ExecutorRouter;
|
|
28
|
+
readonly localExecutor?: ExecutorClient;
|
|
24
29
|
readonly defaultProjectId: string;
|
|
25
30
|
readonly runtime: (projectId: string) => ProjectRuntime;
|
|
26
31
|
readonly refreshProject: (projectId: string) => void;
|