@code-yeongyu/senpi-codemode 2026.7.25-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.
Files changed (63) hide show
  1. package/CHANGELOG.md +250 -0
  2. package/LICENSE +22 -0
  3. package/README.md +161 -0
  4. package/package.json +58 -0
  5. package/src/bridge/http-server.ts +236 -0
  6. package/src/bridge/protocol.ts +198 -0
  7. package/src/bridge/reserved.ts +9 -0
  8. package/src/bridges/agent-bridge.ts +197 -0
  9. package/src/bridges/output-bridge.ts +96 -0
  10. package/src/bridges/schema-injection.ts +3 -0
  11. package/src/codemode/runtime.ts +258 -0
  12. package/src/codemode/tools.ts +106 -0
  13. package/src/completion/handler.ts +192 -0
  14. package/src/completion/tool-bridge.ts +55 -0
  15. package/src/config/settings.ts +215 -0
  16. package/src/extension/runtime-factory.ts +114 -0
  17. package/src/extension/session-manager-proxy.ts +116 -0
  18. package/src/extension/session-manager.ts +215 -0
  19. package/src/host-sdk.ts +1 -0
  20. package/src/index.ts +181 -0
  21. package/src/interpreters/detect.ts +161 -0
  22. package/src/kernels/jl/kernel.ts +37 -0
  23. package/src/kernels/jl/prelude.jl +283 -0
  24. package/src/kernels/jl/runner.jl +327 -0
  25. package/src/kernels/js/context-manager.ts +296 -0
  26. package/src/kernels/js/inline-worker-entry.js +23 -0
  27. package/src/kernels/js/inline-worker.ts +15 -0
  28. package/src/kernels/js/kernel-contract.ts +38 -0
  29. package/src/kernels/js/local-module-loader.ts +108 -0
  30. package/src/kernels/js/prelude.ts +15 -0
  31. package/src/kernels/js/rewrite-imports.ts +164 -0
  32. package/src/kernels/js/run-queue.ts +82 -0
  33. package/src/kernels/js/worker-core.d.ts +18 -0
  34. package/src/kernels/js/worker-core.js +94 -0
  35. package/src/kernels/js/worker-entry.js +23 -0
  36. package/src/kernels/js/worker-host.ts +117 -0
  37. package/src/kernels/js/worker-indirect-eval.js +88 -0
  38. package/src/kernels/js/worker-runtime.js +401 -0
  39. package/src/kernels/py/kernel-contract.ts +32 -0
  40. package/src/kernels/py/kernel.ts +290 -0
  41. package/src/kernels/py/prelude.py +954 -0
  42. package/src/kernels/py/process.ts +119 -0
  43. package/src/kernels/py/transport.ts +237 -0
  44. package/src/kernels/rb/kernel.ts +26 -0
  45. package/src/kernels/rb/prelude.rb +270 -0
  46. package/src/kernels/rb/runner.rb +204 -0
  47. package/src/kernels/shared/subprocess-contract.ts +22 -0
  48. package/src/kernels/shared/subprocess-kernel.ts +266 -0
  49. package/src/kernels/shared/subprocess-process.ts +174 -0
  50. package/src/kernels/shared/subprocess-queue.ts +101 -0
  51. package/src/kernels/shared/subprocess-run.ts +98 -0
  52. package/src/output/output-meta.ts +89 -0
  53. package/src/output/streaming-output.ts +296 -0
  54. package/src/prompt/eval-prompt.ts +319 -0
  55. package/src/timeouts/bridge-timeout.ts +16 -0
  56. package/src/timeouts/idle-timeout.ts +84 -0
  57. package/src/tool/cell-handler.ts +279 -0
  58. package/src/tool/eval-tool.ts +285 -0
  59. package/src/tool/image.ts +274 -0
  60. package/src/tool/json-tree.ts +247 -0
  61. package/src/tool/render.ts +876 -0
  62. package/src/tool/status-events.ts +12 -0
  63. package/src/tool/types.ts +114 -0
@@ -0,0 +1,290 @@
1
+ import type { PendingRun, PythonKernelRunOptions, PythonKernelStartOptions, ResultMessage } from "./kernel-contract.ts";
2
+ import { failedPythonResult, PythonKernelTransport } from "./transport.ts";
3
+
4
+ export type { PythonKernelRunOptions, PythonKernelStartOptions } from "./kernel-contract.ts";
5
+ export type { KernelChild, KernelSpawnOptions, KernelSpawnProcess } from "./process.ts";
6
+
7
+ const startupTimeoutMs = 5_000;
8
+ const interruptEscalationMs = 5_000;
9
+
10
+ export class PythonKernel {
11
+ readonly #options: PythonKernelStartOptions;
12
+ #transport: PythonKernelTransport | null = null;
13
+ #pending = new Map<string, PendingRun>();
14
+ #queue: PendingRun[] = [];
15
+ #active: PendingRun | null = null;
16
+ #starting: Promise<void> | null = null;
17
+ #retirement: Promise<void> | null = null;
18
+ #closePromise: Promise<void> | null = null;
19
+ #failure: Error | null = null;
20
+ #generation = 0;
21
+ #closed = false;
22
+
23
+ private constructor(options: PythonKernelStartOptions) {
24
+ this.#options = options;
25
+ }
26
+
27
+ static async start(options: PythonKernelStartOptions): Promise<PythonKernel> {
28
+ const kernel = new PythonKernel(options);
29
+ await kernel.#spawn(kernel.#generation);
30
+ return kernel;
31
+ }
32
+
33
+ run(input: PythonKernelRunOptions): Promise<ResultMessage> {
34
+ if (this.#failure) return Promise.reject(this.#failure);
35
+ if (this.#closed) return Promise.reject(new Error("Python kernel is closed"));
36
+ return new Promise<ResultMessage>((resolve, reject) => {
37
+ const pending: PendingRun = { input, resolve, reject, startedAt: null, timeoutTimer: null };
38
+ this.#pending.set(input.cellId, pending);
39
+ this.#queue.push(pending);
40
+ this.#startNext();
41
+ });
42
+ }
43
+
44
+ async interrupt(reason = "interrupted"): Promise<void> {
45
+ if (this.#failure) throw this.#failure;
46
+ for (const pending of [...this.#queue]) {
47
+ pending.interruptReason = reason;
48
+ this.#settleRun(pending, failedPythonResult(pending.input.cellId, "Eval interrupted"));
49
+ }
50
+ const active = this.#active;
51
+ const transport = this.#transport;
52
+ if (!active || !transport || active.interruptReason !== undefined) return;
53
+ active.interruptReason = reason;
54
+ if (active.timeoutTimer) clearTimeout(active.timeoutTimer);
55
+ active.timeoutTimer = null;
56
+ active.escalationTimer = setTimeout(
57
+ () => void this.#escalateInterruptedRun(active).catch(() => undefined),
58
+ interruptEscalationMs,
59
+ );
60
+ transport.interrupt(reason);
61
+ }
62
+
63
+ async reset(): Promise<void> {
64
+ if (this.#failure) throw this.#failure;
65
+ if (this.#closed) throw new Error("Python kernel is closed");
66
+ const generation = ++this.#generation;
67
+ const prior = this.#starting;
68
+ const operation = (async () => {
69
+ await prior?.catch(() => undefined);
70
+ if (this.#failure) throw this.#failure;
71
+ if (this.#closed || generation !== this.#generation) throw new Error("Python kernel reset was superseded");
72
+ const transport = this.#transport;
73
+ if (transport) await this.#beginRetirement(transport);
74
+ if (this.#closed || generation !== this.#generation) throw new Error("Python kernel reset was superseded");
75
+ await this.#spawn(generation);
76
+ })();
77
+ this.#starting = operation;
78
+ this.#settleAllPending("Python kernel reset");
79
+ try {
80
+ await operation;
81
+ } finally {
82
+ this.#finishStarting(operation);
83
+ }
84
+ }
85
+
86
+ deliverToolReply(): void {}
87
+
88
+ async close(): Promise<void> {
89
+ if (this.#closePromise) return await this.#closePromise;
90
+ this.#closed = true;
91
+ this.#generation += 1;
92
+ this.#settleAllPending("Python kernel closed");
93
+ const starting = this.#starting;
94
+ this.#closePromise = (async () => {
95
+ await starting?.catch(() => undefined);
96
+ await this.#retirement?.catch(() => undefined);
97
+ const transport = this.#transport;
98
+ if (!transport) return;
99
+ try {
100
+ await transport.close();
101
+ } catch (error) {
102
+ if (error instanceof Error) throw this.#recordFailure(error);
103
+ throw error;
104
+ }
105
+ if (this.#transport === transport) this.#transport = null;
106
+ })();
107
+ return await this.#closePromise;
108
+ }
109
+
110
+ #startNext(): void {
111
+ if (
112
+ this.#closed ||
113
+ this.#failure ||
114
+ this.#active ||
115
+ this.#starting ||
116
+ this.#retirement ||
117
+ this.#queue.length === 0
118
+ )
119
+ return;
120
+ const starting = this.#activateNext();
121
+ this.#starting = starting;
122
+ void starting.then(
123
+ () => this.#finishStarting(starting),
124
+ (error: unknown) => {
125
+ this.#rejectAllPending(error);
126
+ this.#finishStarting(starting);
127
+ },
128
+ );
129
+ }
130
+
131
+ async #activateNext(): Promise<void> {
132
+ await this.#ensureStarted();
133
+ if (this.#closed || this.#active || this.#retirement) return;
134
+ const pending = this.#queue.shift();
135
+ if (!pending || !this.#pending.has(pending.input.cellId)) return;
136
+ this.#active = pending;
137
+ pending.startedAt = performance.now();
138
+ const timeoutMs = pending.input.timeoutMs;
139
+ if (timeoutMs !== undefined)
140
+ pending.timeoutTimer = setTimeout(() => this.#timeoutRun(pending, timeoutMs), timeoutMs);
141
+ try {
142
+ this.#transport?.run(pending.input);
143
+ } catch (error) {
144
+ const failure = error instanceof Error ? error : new Error(String(error));
145
+ this.#rejectRun(pending, failure);
146
+ }
147
+ }
148
+
149
+ #finishStarting(starting: Promise<void>): void {
150
+ if (this.#starting === starting) this.#starting = null;
151
+ this.#startNext();
152
+ }
153
+
154
+ #timeoutRun(pending: PendingRun, timeoutMs: number): void {
155
+ if (this.#active !== pending) return;
156
+ if (this.#transport) void this.#beginRetirement(this.#transport).catch(() => undefined);
157
+ this.#settleRun(
158
+ pending,
159
+ failedPythonResult(pending.input.cellId, `Python kernel timed out after ${timeoutMs}ms`),
160
+ );
161
+ }
162
+
163
+ async #ensureStarted(): Promise<void> {
164
+ await this.#retirement;
165
+ if (this.#failure) throw this.#failure;
166
+ if (this.#transport) return;
167
+ await this.#spawn(this.#generation);
168
+ }
169
+
170
+ async #spawn(generation: number): Promise<void> {
171
+ if (this.#closed || generation !== this.#generation) throw new Error("Python kernel startup was superseded");
172
+ this.#transport = await PythonKernelTransport.start({
173
+ ...this.#options,
174
+ startupTimeoutMs: this.#options.startupTimeoutMs ?? startupTimeoutMs,
175
+ isOwned: () => !this.#closed && generation === this.#generation,
176
+ onRetirementFailure: (transport, error) => {
177
+ if (!this.#transport) this.#transport = transport;
178
+ this.#recordFailure(error);
179
+ },
180
+ onResult: (transport, result) => this.#onResult(transport, result),
181
+ onError: (transport, error) => this.#onError(transport, error),
182
+ onExit: (transport, error) => this.#onExit(transport, error),
183
+ });
184
+ }
185
+
186
+ #onResult(transport: PythonKernelTransport, result: ResultMessage): void {
187
+ if (this.#transport !== transport) return;
188
+ const pending = this.#pending.get(result.cellId);
189
+ if (pending) this.#settleRun(pending, result);
190
+ }
191
+
192
+ #onExit(transport: PythonKernelTransport, error: Error): void {
193
+ if (this.#transport !== transport) return;
194
+ this.#transport = null;
195
+ const active = this.#active;
196
+ if (active) this.#settleRun(active, failedPythonResult(active.input.cellId, "Python kernel died", error.message));
197
+ this.#startNext();
198
+ }
199
+
200
+ #onError(transport: PythonKernelTransport, error: Error): void {
201
+ if (this.#transport !== transport) return;
202
+ const retirement = this.#beginRetirement(transport);
203
+ void retirement.then(
204
+ () => undefined,
205
+ (retirementError: unknown) => {
206
+ this.#recordFailure(
207
+ retirementError instanceof Error ? retirementError : new Error(String(retirementError)),
208
+ );
209
+ },
210
+ );
211
+ const active = this.#active;
212
+ if (active) this.#settleRun(active, failedPythonResult(active.input.cellId, "Python kernel died", error.message));
213
+ }
214
+
215
+ #settleRun(pending: PendingRun, result: ResultMessage): void {
216
+ if (!this.#pending.delete(pending.input.cellId)) return;
217
+ this.#removePending(pending);
218
+ const durationMs = pending.startedAt === null ? 0 : Math.max(0, performance.now() - pending.startedAt);
219
+ if (pending.interruptReason !== undefined) {
220
+ const message =
221
+ pending.interruptReason === "Eval interrupted"
222
+ ? "Eval interrupted"
223
+ : `Eval interrupted: ${pending.interruptReason}`;
224
+ const error = result.ok ? { message } : { ...result.error, message };
225
+ pending.resolve({ type: "result", cellId: pending.input.cellId, ok: false, error, durationMs });
226
+ } else {
227
+ pending.resolve(result.durationMs === 0 ? { ...result, durationMs } : result);
228
+ }
229
+ this.#startNext();
230
+ }
231
+
232
+ #rejectRun(pending: PendingRun, error: unknown): void {
233
+ if (!this.#pending.delete(pending.input.cellId)) return;
234
+ this.#removePending(pending);
235
+ pending.reject(error);
236
+ this.#startNext();
237
+ }
238
+
239
+ #removePending(pending: PendingRun): void {
240
+ if (pending.timeoutTimer) clearTimeout(pending.timeoutTimer);
241
+ if (pending.escalationTimer) clearTimeout(pending.escalationTimer);
242
+ pending.timeoutTimer = null;
243
+ pending.escalationTimer = undefined;
244
+ if (this.#active === pending) this.#active = null;
245
+ const queuedIndex = this.#queue.indexOf(pending);
246
+ if (queuedIndex >= 0) this.#queue.splice(queuedIndex, 1);
247
+ }
248
+
249
+ #settleAllPending(message: string): void {
250
+ for (const pending of [...this.#pending.values()])
251
+ this.#settleRun(pending, failedPythonResult(pending.input.cellId, message));
252
+ }
253
+
254
+ #rejectAllPending(error: unknown): void {
255
+ for (const pending of [...this.#pending.values()]) this.#rejectRun(pending, error);
256
+ }
257
+
258
+ async #escalateInterruptedRun(pending: PendingRun): Promise<void> {
259
+ if (this.#active !== pending || pending.interruptReason === undefined) return;
260
+ const transport = this.#transport;
261
+ if (transport) await this.#beginRetirement(transport);
262
+ if (this.#pending.has(pending.input.cellId))
263
+ this.#settleRun(pending, failedPythonResult(pending.input.cellId, "Eval interrupted"));
264
+ }
265
+
266
+ #beginRetirement(transport: PythonKernelTransport): Promise<void> {
267
+ if (this.#retirement) return this.#retirement;
268
+ const operation = (async () => {
269
+ try {
270
+ await transport.retire();
271
+ } catch (error) {
272
+ if (error instanceof Error) throw this.#recordFailure(error);
273
+ throw error;
274
+ }
275
+ if (this.#transport === transport) this.#transport = null;
276
+ })();
277
+ const retirement = operation.finally(() => {
278
+ if (this.#retirement === retirement) this.#retirement = null;
279
+ this.#startNext();
280
+ });
281
+ this.#retirement = retirement;
282
+ return retirement;
283
+ }
284
+
285
+ #recordFailure(error: Error): Error {
286
+ this.#failure = error;
287
+ this.#rejectAllPending(error);
288
+ return error;
289
+ }
290
+ }