@hy-sde-org/dsh-code-runtime-kernels 0.1.0-rc.8

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.
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Versionless, hostile-peer wire protocol shared by the persistent Node.js and Python kernels.
3
+ * The host treats every kernel frame as forged (the peer runs MODEL CODE and
4
+ * can emit anything); inbound frames are re-validated field by field before
5
+ * use. The kernel-side reader is our co-shipped code and may trust host
6
+ * messages, mirroring the worker-thread backend's asymmetry. Both
7
+ * process-boundary kernels speak the same NDJSON shape, so the single host
8
+ * driver in `kernel.ts` stays generic.
9
+ * @module @hy-sde-org/dsh-code-runtime-kernels/src/core/protocol
10
+ */
11
+ import type { CodeBindingErrorClass, CodeJsonValue } from '@deepseek-ai/dsh-code-runtime';
12
+ /** One binding global materialized inside the kernel for a run. */
13
+ export interface KernelNamespaceDescriptor {
14
+ /** The program-visible global identifier (validated by the provider). */
15
+ global: string;
16
+ /** The callable member names; functions themselves stay host-side. */
17
+ names: string[];
18
+ /** Optional typed-rejection contract (name + member-name property). */
19
+ errorClass?: CodeBindingErrorClass;
20
+ }
21
+ /** Host -> kernel: execute one program against this run's namespaces. */
22
+ export interface KernelExecMessage {
23
+ type: 'exec';
24
+ /** Run correlation id (a non-empty string, e.g. the session's run id). */
25
+ id: string;
26
+ /** The program source, body-of-async-function semantics, kernel language. */
27
+ code: string;
28
+ /** Binding globals to materialize for this run. */
29
+ namespaces: KernelNamespaceDescriptor[];
30
+ /** Optional working directory applied before execution. */
31
+ cwd?: string;
32
+ /** Optional environment overrides applied before execution. */
33
+ env?: Record<string, string>;
34
+ }
35
+ /** Host -> kernel: the answer to one {@link KernelCallFrame}. */
36
+ export interface KernelReplyMessage {
37
+ type: 'reply';
38
+ id: string;
39
+ /** The call's correlation sequence, echoed from the frame. */
40
+ seq: number;
41
+ ok: boolean;
42
+ /** The lossless-JSON resolution, present when `ok` is true. */
43
+ value?: CodeJsonValue;
44
+ /** The rejection message, present when `ok` is false. */
45
+ message?: string;
46
+ /** The rejected member name, surfaced onto the program-side error. */
47
+ name?: string;
48
+ }
49
+ /** Host -> kernel: graceful shutdown request. */
50
+ export interface KernelExitMessage {
51
+ type: 'exit';
52
+ }
53
+ /** Every message the host sends. */
54
+ export type KernelHostMessage = KernelExecMessage | KernelReplyMessage | KernelExitMessage;
55
+ /** Kernel -> host: the bootstrap handshake, emitted once at startup. */
56
+ export interface ReadyFrame {
57
+ type: 'ready';
58
+ pid: number;
59
+ }
60
+ /** Kernel -> host: a run accepted the exec frame. */
61
+ export interface StartedFrame {
62
+ type: 'started';
63
+ id: string;
64
+ }
65
+ /** Kernel -> host: captured program output for a run. */
66
+ export interface LogFrame {
67
+ type: 'log';
68
+ id: string;
69
+ text: string;
70
+ /** 'stdout' or 'stderr'; purely informational, both land in `logs`. */
71
+ stream?: string;
72
+ }
73
+ /** Kernel -> host: the program invoked one binding call. */
74
+ export interface CallFrame {
75
+ type: 'call';
76
+ id: string;
77
+ seq: number;
78
+ /** The namespace global the call targets. */
79
+ global: string;
80
+ /** The member name within the namespace. */
81
+ name: string;
82
+ /** The single argument, already lossless JSON. */
83
+ args: CodeJsonValue;
84
+ }
85
+ /** Kernel -> host: an uncaught program exception. */
86
+ export interface ErrorFrame {
87
+ type: 'error';
88
+ id: string;
89
+ ename: string;
90
+ evalue: string;
91
+ traceback: string[];
92
+ }
93
+ /**
94
+ * Kernel -> host: the run settled. Program failures (exception, invalid
95
+ * completion) land here as `status: 'error'`; budget/abort/substrate outcomes
96
+ * are observed host-side (a cancelled run carries `cancelled: true`).
97
+ */
98
+ export interface DoneFrame {
99
+ type: 'done';
100
+ id: string;
101
+ status: 'ok' | 'error';
102
+ /** The lossless-JSON completion value, present on a clean run with one. */
103
+ value?: CodeJsonValue;
104
+ /** The session's execution count after this run; informational. */
105
+ executionCount?: number;
106
+ /** True when the host interrupted the run. */
107
+ cancelled?: boolean;
108
+ /** True when the completion could not be represented as lossless JSON. */
109
+ invalidOutput?: boolean;
110
+ /** The failure or protocol message, when any. */
111
+ message?: string;
112
+ }
113
+ /** Every frame the kernel sends. */
114
+ export type KernelFrame = ReadyFrame | StartedFrame | LogFrame | CallFrame | ErrorFrame | DoneFrame;
115
+ //# sourceMappingURL=protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/core/protocol.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Versionless, hostile-peer wire protocol shared by the persistent Node.js and Python kernels.
3
+ * The host treats every kernel frame as forged (the peer runs MODEL CODE and
4
+ * can emit anything); inbound frames are re-validated field by field before
5
+ * use. The kernel-side reader is our co-shipped code and may trust host
6
+ * messages, mirroring the worker-thread backend's asymmetry. Both
7
+ * process-boundary kernels speak the same NDJSON shape, so the single host
8
+ * driver in `kernel.ts` stays generic.
9
+ * @module @hy-sde-org/dsh-code-runtime-kernels/src/core/protocol
10
+ */
11
+ export {};
12
+ //# sourceMappingURL=protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../src/core/protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Persistent-session registry, language-generic (shared by the Python and
3
+ * JavaScript kernels). Maps a `sessionId` to one kernel whose namespace and
4
+ * event-loop state survive every run in the session; on `reset` the old kernel
5
+ * is shut down before a fresh one answers; at disposal every kernel is
6
+ * terminated to quiescence. One exec at a time per session (a kernel
7
+ * serializes stdin), so concurrent runs for the same session queue on a
8
+ * per-session promise chain.
9
+ * @module @hy-sde-org/dsh-code-runtime-kernels/src/core/session
10
+ */
11
+ import type { CodeBindingNamespace } from '@deepseek-ai/dsh-code-runtime';
12
+ import type { KernelExecResult, KernelHost } from './kernel.ts';
13
+ /** Session-management knobs on top of the per-kernel start config. */
14
+ export interface SessionRegistryConfig {
15
+ /** Label for error messages (e.g. `python kernel`). */
16
+ label: string;
17
+ /** Spawn a fresh kernel for a newly acquired session (provider-resolved executable + timeouts). */
18
+ start: () => Promise<KernelHost>;
19
+ /** Reap a session whose kernel sits unused for this long; 0 disables. */
20
+ sessionIdleMs: number;
21
+ }
22
+ /** Options for one registered-session run. */
23
+ export interface SessionRunOptions {
24
+ /** Discard prior kernel state and start fresh before this run. */
25
+ reset?: boolean;
26
+ /** Abort source; SIGINT is raised inside the kernel on abort. */
27
+ signal?: AbortSignal;
28
+ /** Per-run working directory override. */
29
+ cwd?: string;
30
+ /** Per-run environment overrides. */
31
+ env?: Record<string, string>;
32
+ }
33
+ /**
34
+ * Registers sessions and schedules every run onto its session's serialization
35
+ * tail. A session kernel that died mid-run (or was killed settling a prior
36
+ * run) is replaced with a fresh one and the run retried once, like omp's
37
+ * kernel-session registry — state loss on a hard kill is the accepted cost.
38
+ */
39
+ export declare class SessionRegistry {
40
+ #private;
41
+ constructor(config: SessionRegistryConfig);
42
+ /** Register (or return) the session for an id and run the work on its tail. */
43
+ executeOnSession(sessionId: string, code: string, bindings: CodeBindingNamespace[], options?: SessionRunOptions): Promise<KernelExecResult>;
44
+ /** Shut down and drop one session's kernel. */
45
+ close(sessionId: string): Promise<void>;
46
+ /** Terminate every kernel and drop every session (runtime disposal). */
47
+ disposeAll(): Promise<void>;
48
+ }
49
+ //# sourceMappingURL=session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/core/session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAA;AACzE,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAW/D,sEAAsE;AACtE,MAAM,WAAW,qBAAqB;IACpC,uDAAuD;IACvD,KAAK,EAAE,MAAM,CAAA;IACb,mGAAmG;IACnG,KAAK,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,CAAA;IAChC,yEAAyE;IACzE,aAAa,EAAE,MAAM,CAAA;CACtB;AAED,8CAA8C;AAC9C,MAAM,WAAW,iBAAiB;IAChC,kEAAkE;IAClE,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,iEAAiE;IACjE,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,0CAA0C;IAC1C,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,qCAAqC;IACrC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAC7B;AAED;;;;;GAKG;AACH,qBAAa,eAAe;;gBAKd,MAAM,EAAE,qBAAqB;IAIzC,+EAA+E;IACzE,gBAAgB,CACpB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,oBAAoB,EAAE,EAChC,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,gBAAgB,CAAC;IAsB5B,+CAA+C;IACzC,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAU7C,wEAAwE;IAClE,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;CAqGlC"}
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Persistent-session registry, language-generic (shared by the Python and
3
+ * JavaScript kernels). Maps a `sessionId` to one kernel whose namespace and
4
+ * event-loop state survive every run in the session; on `reset` the old kernel
5
+ * is shut down before a fresh one answers; at disposal every kernel is
6
+ * terminated to quiescence. One exec at a time per session (a kernel
7
+ * serializes stdin), so concurrent runs for the same session queue on a
8
+ * per-session promise chain.
9
+ * @module @hy-sde-org/dsh-code-runtime-kernels/src/core/session
10
+ */
11
+ /**
12
+ * Registers sessions and schedules every run onto its session's serialization
13
+ * tail. A session kernel that died mid-run (or was killed settling a prior
14
+ * run) is replaced with a fresh one and the run retried once, like omp's
15
+ * kernel-session registry — state loss on a hard kill is the accepted cost.
16
+ */
17
+ export class SessionRegistry {
18
+ #sessions = new Map();
19
+ #config;
20
+ #disposed = false;
21
+ constructor(config) {
22
+ this.#config = config;
23
+ }
24
+ /** Register (or return) the session for an id and run the work on its tail. */
25
+ async executeOnSession(sessionId, code, bindings, options = {}) {
26
+ if (this.#disposed) {
27
+ return {
28
+ status: 'error', logs: [], cancelled: false, invalidOutput: false,
29
+ message: `${this.#config.label} session registry disposed`, killed: true,
30
+ };
31
+ }
32
+ let session = this.#sessions.get(sessionId);
33
+ if (session === undefined) {
34
+ session = { kernel: null, queue: Promise.resolve() };
35
+ this.#sessions.set(sessionId, session);
36
+ }
37
+ const run = () => this.#runOnSession(session, sessionId, code, bindings, options);
38
+ session.queue = session.queue.then(run, run);
39
+ try {
40
+ return (await session.queue);
41
+ }
42
+ finally {
43
+ this.#maybeReap(sessionId);
44
+ }
45
+ }
46
+ /** Shut down and drop one session's kernel. */
47
+ async close(sessionId) {
48
+ const session = this.#sessions.get(sessionId);
49
+ if (session === undefined)
50
+ return;
51
+ this.#sessions.delete(sessionId);
52
+ clearTimeout(session.idleTimer);
53
+ const kernel = session.kernel;
54
+ session.kernel = null;
55
+ if (kernel !== null)
56
+ await kernel.shutdown().catch(() => { });
57
+ }
58
+ /** Terminate every kernel and drop every session (runtime disposal). */
59
+ async disposeAll() {
60
+ if (this.#disposed)
61
+ return;
62
+ this.#disposed = true;
63
+ const sessions = [...this.#sessions.values()];
64
+ this.#sessions.clear();
65
+ const kernels = [];
66
+ for (const session of sessions) {
67
+ clearTimeout(session.idleTimer);
68
+ if (session.kernel !== null)
69
+ kernels.push(session.kernel);
70
+ session.kernel = null;
71
+ }
72
+ await Promise.allSettled(kernels.map(kernel => kernel.shutdown()));
73
+ }
74
+ #maybeReap(sessionId) {
75
+ if (this.#disposed)
76
+ return;
77
+ if (this.#config.sessionIdleMs <= 0)
78
+ return;
79
+ const session = this.#sessions.get(sessionId);
80
+ if (session === undefined || session.kernel === null)
81
+ return;
82
+ clearTimeout(session.idleTimer);
83
+ session.idleTimer = setTimeout(() => {
84
+ void this.close(sessionId);
85
+ }, this.#config.sessionIdleMs);
86
+ session.idleTimer.unref();
87
+ }
88
+ async #acquireKernel(sessionId, session) {
89
+ if (session.kernel !== null && session.kernel.isAlive())
90
+ return session.kernel;
91
+ const previous = session.kernel;
92
+ if (previous !== null) {
93
+ await previous.shutdown().catch(() => { });
94
+ session.kernel = null;
95
+ }
96
+ if (this.#disposed) {
97
+ throw new Error(`${this.#config.label} session registry disposed while acquiring kernel`);
98
+ }
99
+ if (this.#sessions.get(sessionId) !== session) {
100
+ throw new Error(`${this.#config.label} session invalidated while acquiring kernel`);
101
+ }
102
+ const kernel = await this.#config.start();
103
+ // oxlint-disable-next-line typescript/no-unnecessary-condition -- set by disposeAll elsewhere
104
+ if (this.#disposed) {
105
+ await kernel.shutdown().catch(() => { });
106
+ throw new Error(`${this.#config.label} session registry disposed while acquiring kernel`);
107
+ }
108
+ if (this.#sessions.get(sessionId) !== session) {
109
+ await kernel.shutdown().catch(() => { });
110
+ throw new Error(`${this.#config.label} session invalidated while acquiring kernel`);
111
+ }
112
+ session.kernel = kernel;
113
+ return kernel;
114
+ }
115
+ async #runOnSession(session, sessionId, code, bindings, options) {
116
+ if (options.reset === true) {
117
+ // Reset first, then acquire: prior kernel state is discarded and its
118
+ // shutdown completes before the fresh kernel answers this run.
119
+ const previous = session.kernel;
120
+ if (previous !== null) {
121
+ session.kernel = null;
122
+ clearTimeout(session.idleTimer);
123
+ await previous.shutdown().catch(() => { });
124
+ }
125
+ }
126
+ let kernel = await this.#acquireKernel(sessionId, session);
127
+ const first = await this.#executeOnce(kernel, sessionId, code, bindings, options);
128
+ // A kernel that died or was killed settling the run is replaced once and
129
+ // the run retried; otherwise return what we got.
130
+ const needsRetry = first.killed && session === this.#sessions.get(sessionId);
131
+ if (!needsRetry)
132
+ return first;
133
+ await kernel.shutdown().catch(() => { });
134
+ if (session !== this.#sessions.get(sessionId))
135
+ return first;
136
+ kernel = await this.#acquireKernel(sessionId, session);
137
+ const second = await this.#executeOnce(kernel, sessionId, code, bindings, options);
138
+ if (second.killed) {
139
+ // Give up restoring state: report the second outcome with the first's
140
+ // message so the caller sees that retries also died.
141
+ return { ...second, message: second.message || first.message };
142
+ }
143
+ return second;
144
+ }
145
+ #executeOnce(kernel, sessionId, code, bindings, options) {
146
+ return kernel.execute(sessionId, code, bindings, {
147
+ ...options.signal !== undefined ? { signal: options.signal } : {},
148
+ ...options.cwd !== undefined ? { cwd: options.cwd } : {},
149
+ ...options.env !== undefined ? { env: options.env } : {},
150
+ });
151
+ }
152
+ }
153
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/core/session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAoCH;;;;;GAKG;AACH,MAAM,OAAO,eAAe;IACjB,SAAS,GAAG,IAAI,GAAG,EAAyB,CAAA;IAC5C,OAAO,CAAuB;IACvC,SAAS,GAAY,KAAK,CAAA;IAE1B,YAAY,MAA6B;QACvC,IAAI,CAAC,OAAO,GAAG,MAAM,CAAA;IACvB,CAAC;IAED,+EAA+E;IAC/E,KAAK,CAAC,gBAAgB,CACpB,SAAiB,EACjB,IAAY,EACZ,QAAgC,EAChC,UAA6B,EAAE;QAE/B,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,OAAO;gBACL,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK;gBACjE,OAAO,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,4BAA4B,EAAE,MAAM,EAAE,IAAI;aACzE,CAAA;QACH,CAAC;QACD,IAAI,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QAC3C,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,OAAO,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,OAAO,EAAE,EAAE,CAAA;YACpD,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;QACxC,CAAC;QACD,MAAM,GAAG,GAAG,GAA8B,EAAE,CAC1C,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAA;QACjE,OAAO,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;QAC5C,IAAI,CAAC;YACH,OAAO,CAAC,MAAM,OAAO,CAAC,KAAK,CAAqB,CAAA;QAClD,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAA;QAC5B,CAAC;IACH,CAAC;IAED,+CAA+C;IAC/C,KAAK,CAAC,KAAK,CAAC,SAAiB;QAC3B,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QAC7C,IAAI,OAAO,KAAK,SAAS;YAAE,OAAM;QACjC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;QAChC,YAAY,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;QAC/B,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAA;QAC7B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAA;QACrB,IAAI,MAAM,KAAK,IAAI;YAAE,MAAM,MAAM,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;IAC9D,CAAC;IAED,wEAAwE;IACxE,KAAK,CAAC,UAAU;QACd,IAAI,IAAI,CAAC,SAAS;YAAE,OAAM;QAC1B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAA;QACrB,MAAM,QAAQ,GAAG,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,CAAA;QAC7C,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAA;QACtB,MAAM,OAAO,GAAiB,EAAE,CAAA;QAChC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,YAAY,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;YAC/B,IAAI,OAAO,CAAC,MAAM,KAAK,IAAI;gBAAE,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;YACzD,OAAO,CAAC,MAAM,GAAG,IAAI,CAAA;QACvB,CAAC;QACD,MAAM,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAA;IACpE,CAAC;IAED,UAAU,CAAC,SAAiB;QAC1B,IAAI,IAAI,CAAC,SAAS;YAAE,OAAM;QAC1B,IAAI,IAAI,CAAC,OAAO,CAAC,aAAa,IAAI,CAAC;YAAE,OAAM;QAC3C,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QAC7C,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,CAAC,MAAM,KAAK,IAAI;YAAE,OAAM;QAC5D,YAAY,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;QAC/B,OAAO,CAAC,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE;YAClC,KAAK,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAA;QAC5B,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,CAAA;QAC9B,OAAO,CAAC,SAAS,CAAC,KAAK,EAAE,CAAA;IAC3B,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,SAAiB,EAAE,OAAsB;QAC5D,IAAI,OAAO,CAAC,MAAM,KAAK,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE;YAAE,OAAO,OAAO,CAAC,MAAM,CAAA;QAC9E,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAA;QAC/B,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;YACtB,MAAM,QAAQ,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;YACzC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAA;QACvB,CAAC;QACD,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,mDAAmD,CAAC,CAAA;QAC3F,CAAC;QACD,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,OAAO,EAAE,CAAC;YAC9C,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,6CAA6C,CAAC,CAAA;QACrF,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAA;QACzC,8FAA8F;QAC9F,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,MAAM,MAAM,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;YACvC,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,mDAAmD,CAAC,CAAA;QAC3F,CAAC;QACD,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,OAAO,EAAE,CAAC;YAC9C,MAAM,MAAM,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;YACvC,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,6CAA6C,CAAC,CAAA;QACrF,CAAC;QACD,OAAO,CAAC,MAAM,GAAG,MAAM,CAAA;QACvB,OAAO,MAAM,CAAA;IACf,CAAC;IAED,KAAK,CAAC,aAAa,CACjB,OAAsB,EACtB,SAAiB,EACjB,IAAY,EACZ,QAAgC,EAChC,OAA0B;QAE1B,IAAI,OAAO,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;YAC3B,qEAAqE;YACrE,+DAA+D;YAC/D,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAA;YAC/B,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;gBACtB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAA;gBACrB,YAAY,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;gBAC/B,MAAM,QAAQ,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;YAC3C,CAAC;QACH,CAAC;QACD,IAAI,MAAM,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;QAC1D,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAA;QACjF,yEAAyE;QACzE,iDAAiD;QACjD,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,IAAI,OAAO,KAAK,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QAC5E,IAAI,CAAC,UAAU;YAAE,OAAO,KAAK,CAAA;QAC7B,MAAM,MAAM,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;QACvC,IAAI,OAAO,KAAK,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC;YAAE,OAAO,KAAK,CAAA;QAC3D,MAAM,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;QACtD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAA;QAClF,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YAClB,sEAAsE;YACtE,qDAAqD;YACrD,OAAO,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO,EAAE,CAAA;QAChE,CAAC;QACD,OAAO,MAAM,CAAA;IACf,CAAC;IAED,YAAY,CACV,MAAkB,EAClB,SAAiB,EACjB,IAAY,EACZ,QAAgC,EAChC,OAA0B;QAE1B,OAAO,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE;YAC/C,GAAG,OAAO,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE;YACjE,GAAG,OAAO,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE;YACxD,GAAG,OAAO,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE;SACzD,CAAC,CAAA;IACJ,CAAC;CACF"}
@@ -0,0 +1,135 @@
1
+ /**
2
+ * `run_kernel_code` — the persistent kernel tool for DeepSeek Harness,
3
+ * self-contained (no upstream harness changes required, same as the sibling
4
+ * dsh-tool-ast plugin). One long-lived `python3` or `node` subprocess per
5
+ * `session` keeps state across calls; runs without a session are one-shot
6
+ * (a fresh kernel spawning for exactly one program). The host driver, session
7
+ * registry, and output ledger in `core/` are shared by both languages; each
8
+ * language's runner program lives in `src/python` / `src/nodejs`.
9
+ * This is process confinement, not a security boundary: model code has
10
+ * bash-equivalent trust.
11
+ * @module @hy-sde-org/dsh-code-runtime-kernels
12
+ */
13
+ import { Context } from '@deepseek-ai/cordis';
14
+ import z from '@deepseek-ai/schemastery';
15
+ import type { CodeBindingNamespace, CodeJsonValue, CodeRunResult } from '@deepseek-ai/dsh-code-runtime';
16
+ import type { TerminalCallView, TerminalResultView, ToolResult } from '@deepseek-ai/dsh-tools';
17
+ /** Cordis plugin name for loader diagnostics. */
18
+ export declare const name = "code-runtime-kernels";
19
+ /** Services this plugin requires: the tool registry and the system-prompt builder. */
20
+ export declare const inject: readonly ["tools", "systemPrompt"];
21
+ /**
22
+ * Plugin config: which languages are enabled, and every execution cap
23
+ * (changeable from any cordis.yml that mounts this plugin).
24
+ */
25
+ export interface Config {
26
+ /** Enabled languages; kernels of disabled languages are refused at call time. */
27
+ languages?: ('python' | 'typescript')[];
28
+ /** Explicit python executable. Defaults to `python3` on PATH (fails loud at first spawn when absent). */
29
+ pythonPath?: string;
30
+ /** Explicit node executable. Defaults to `node` on PATH (fails loud at first spawn when absent). */
31
+ nodePath?: string;
32
+ /** Cooperative tool-call timeout budget (ms) for `run_kernel_code` (default 30000). */
33
+ toolTimeoutMs?: number;
34
+ /** Wall-clock ceiling per run: the backstop for a cell nothing can interrupt synchronously. */
35
+ maxWallMs?: number;
36
+ /** Hard cap on combined serialized log-, completion-, and failure-message bytes. */
37
+ maxOutputBytes?: number;
38
+ /** Reap a session idle for at least this many ms; `0` disables reaping. */
39
+ sessionIdleMs?: number;
40
+ /** Wait after SIGINT before SIGTERM, then the same again before SIGKILL. */
41
+ interruptEscalationMs?: number;
42
+ /** Wait for the bootstrap `ready` handshake before failing the kernel. */
43
+ startupTimeoutMs?: number;
44
+ /** Grace period for the kernel to exit after an `exit` frame. */
45
+ shutdownGraceMs?: number;
46
+ }
47
+ /** Schemastery schema for {@link Config}: defaults filled at load time. */
48
+ export declare const Config: z<Config>;
49
+ /** One run request against the persistent kernels; `sessionId`/`reset` mirror the seam's persistence contract. */
50
+ export interface KernelRunRequest {
51
+ /** Which kernel to run the program in (`'python'` presents as `language: python`, `'typescript'` as the SDK). */
52
+ language: 'python' | 'typescript';
53
+ /** The program source. Typescript runs as an async-function body (top-level `await`/`return` work); python runs as a module (top-level `await` works, the last expression is the value). */
54
+ code: string;
55
+ /** Optional persistent-kernel identity: runs sharing one keep kernel state. */
56
+ sessionId?: string;
57
+ /** Discard the session's prior kernel state before this run. */
58
+ reset?: boolean;
59
+ /** Abort the run host-side; in-flight binding calls are the caller's to settle. */
60
+ signal?: AbortSignal;
61
+ /** Optional host functions exposed to the program, one global object per namespace. */
62
+ bindings?: CodeBindingNamespace[];
63
+ }
64
+ /**
65
+ * The outcome vocabulary of `run_kernel_code` and {@link KernelManager.run}:
66
+ * the code-execution seam's result envelope plus the session execution count
67
+ * (upstream's `CodeRunResult` has no persistent-session fields, so this plugin
68
+ * owns the additive `executionCount` surface).
69
+ */
70
+ export type KernelRunResult = CodeRunResult & {
71
+ executionCount?: number;
72
+ };
73
+ /**
74
+ * Owns the two persistent kernel registries and maps one `KernelRunRequest`
75
+ * onto the same outcome vocabulary as the code-execution seam
76
+ * (`CodeRunResult` + `CodeRunFailure` kinds), so programs behave like the
77
+ * seam's persistent backends. Exported for programmatic use and the tests; the
78
+ * model-facing surface is the `run_kernel_code` tool registered in `apply`.
79
+ */
80
+ export declare class KernelManager {
81
+ #private;
82
+ constructor(config: Config);
83
+ /** Terminate every session kernel to quiescence (plugin teardown). */
84
+ teardown(): Promise<void>;
85
+ /**
86
+ * Execute one program. Program outcomes resolve with `error` as a result
87
+ * field; the method rejects only for contract misuse (an unknown language, a
88
+ * disposed manager, an invalid binding namespace). With a non-empty
89
+ * `sessionId` the program runs in that session's persistent kernel and
90
+ * `executionCount` is reported; `reset: true` discards prior state first.
91
+ */
92
+ run(request: KernelRunRequest): Promise<KernelRunResult>;
93
+ /**
94
+ * Map a kernel outcome onto the failure taxonomy through the output ledger.
95
+ * Budget expiry owns a run that hit the wall clock (whether or not the
96
+ * kernel survived to acknowledge it); everything else interrupted is an
97
+ * abort; a died kernel is an abort unless the budget already owns the run.
98
+ */
99
+ private finalize;
100
+ /** Reject malformed binding globals or typed-error declarations as contract misuse. */
101
+ private validateBindings;
102
+ }
103
+ /** Tool argument records and output value types for `run_kernel_code`. */
104
+ export interface RunKernelCodeArgs {
105
+ language: 'python' | 'typescript';
106
+ code: string;
107
+ session?: string;
108
+ reset?: boolean;
109
+ }
110
+ /** The value `run_kernel_code` resolves: the seam's result envelope plus the execution count. */
111
+ export type RunKernelCodeValue = KernelRunResult;
112
+ /** The persisted `presentationMeta` projection of one run result (a structurally-literal type so it stays JSON-value-assignable). */
113
+ export type RunKernelCodeMeta = {
114
+ summary: string;
115
+ value?: CodeJsonValue;
116
+ error?: {
117
+ kind: string;
118
+ message: string;
119
+ };
120
+ executionCount?: number;
121
+ logs: string[];
122
+ };
123
+ /** Project the durable, replayable presentation payload for a completed run. */
124
+ export declare function runKernelCodeMeta(value: RunKernelCodeValue): RunKernelCodeMeta;
125
+ /** Present a pending `run_kernel_code` call as a terminal card (a cell is a foreground command). */
126
+ export declare function presentRunKernelCodeCall(args: RunKernelCodeArgs): TerminalCallView;
127
+ /** Present a completed run from its persisted meta as a terminal card, or undefined on failure. */
128
+ export declare function presentRunKernelCodeResult(_args: RunKernelCodeArgs, result: ToolResult): TerminalResultView | undefined;
129
+ /**
130
+ * Cordis plugin `apply`: resolve config, own the kernel manager (disposed with
131
+ * the plugin), and register `run_kernel_code` against `ctx.tools` so a plain
132
+ * upstream harness exposes the persistent kernels with zero source changes.
133
+ */
134
+ export declare function apply(ctx: Context, config: Config): Promise<void>;
135
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}