@seqyuan/kernel-lite-core 0.2.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.
@@ -0,0 +1,39 @@
1
+ import type { ExecuteKernelRunResult, KernelArtifact, KernelLanguage, KernelRunStatus, KernelRuntime, PreparedRunArchive, RunManifest } from './types.js';
2
+ export declare function getDefaultArchiveRoot(cwd: string): string;
3
+ export declare function getScriptFileName(language: KernelLanguage): "script.R" | "script.py";
4
+ export declare function prepareRunArchive(input: {
5
+ cwd: string;
6
+ archiveRoot?: string;
7
+ ownerId: string;
8
+ runId: string;
9
+ language: KernelLanguage;
10
+ code: string;
11
+ }): Promise<PreparedRunArchive>;
12
+ export declare function writeRunLogs(input: {
13
+ stdoutPath: string;
14
+ stderrPath: string;
15
+ stdout: string;
16
+ stderr: string;
17
+ }): Promise<void>;
18
+ export declare function writeRunManifest(input: {
19
+ archive: PreparedRunArchive;
20
+ language: KernelLanguage;
21
+ runtime: KernelRuntime;
22
+ status: KernelRunStatus;
23
+ title?: string;
24
+ stdout: string;
25
+ stderr: string;
26
+ exitCode: number | null;
27
+ error: string | null;
28
+ cancelled: boolean;
29
+ timedOut: boolean;
30
+ artifacts: KernelArtifact[];
31
+ createdAt: string;
32
+ completedAt: string;
33
+ }): Promise<RunManifest>;
34
+ export declare function resultFromManifest(manifest: RunManifest): ExecuteKernelRunResult;
35
+ export declare function listRunManifests(input: {
36
+ cwd: string;
37
+ ownerId: string;
38
+ archiveRoot?: string;
39
+ }): Promise<RunManifest[]>;
@@ -0,0 +1,2 @@
1
+ import{promises as o}from"node:fs";import u from"node:path";import{assertInsideRoot as w,resolveWithinRoot as a,sanitizePathSegment as h}from"./path-utils.js";function f(t){return u.resolve(t,".pi","kernel-lite")}function I(t){return t==="r"?"script.R":"script.py"}async function y(t){await o.mkdir(t,{recursive:!0});const r=await o.lstat(t);if(r.isSymbolicLink()||!r.isDirectory())throw new Error(`Archive path is not a real directory: ${t}`)}async function p(t){const r=u.resolve(t.cwd),s=u.resolve(t.archiveRoot??f(t.cwd));w(r,s,"Archive root must stay inside cwd");const d=h(t.ownerId,"owner"),c=h(t.runId,"run");if(c!==t.runId)throw new Error("Invalid run id");const e=a(s,"sessions",d,"runs",c),i=a(e,"artifacts"),n=a(e,I(t.language)),l=a(e,"stdout.txt"),m=a(e,"stderr.txt"),v=a(e,"manifest.json");await y(i);const[g,P]=await Promise.all([o.realpath(r),o.realpath(s)]);return w(g,P,"Archive root must stay inside cwd"),await o.writeFile(n,t.code,{encoding:"utf8",flag:"wx",mode:384}),{archiveRoot:s,ownerId:t.ownerId,safeOwnerId:d,runId:c,runDir:e,scriptPath:n,stdoutPath:l,stderrPath:m,outputDir:i,manifestPath:v}}async function D(t){await Promise.all([o.writeFile(t.stdoutPath,t.stdout,{encoding:"utf8",flag:"w",mode:384}),o.writeFile(t.stderrPath,t.stderr,{encoding:"utf8",flag:"w",mode:384})])}async function F(t){const r={schema:"kernel-plot.run.v1",runId:t.archive.runId,ownerId:t.archive.ownerId,language:t.language,runtime:t.runtime,status:t.status,title:t.title,scriptPath:t.archive.scriptPath,stdoutPath:t.archive.stdoutPath,stderrPath:t.archive.stderrPath,outputDir:t.archive.outputDir,artifacts:t.artifacts,stdout:t.stdout,stderr:t.stderr,exitCode:t.exitCode,error:t.error,cancelled:t.cancelled,timedOut:t.timedOut,createdAt:t.createdAt,completedAt:t.completedAt};return await o.writeFile(t.archive.manifestPath,`${JSON.stringify(r,null,2)}
2
+ `,{encoding:"utf8",flag:"w",mode:384}),r}function O(t){return{runId:t.runId,ownerId:t.ownerId,language:t.language,runtime:t.runtime,status:t.status,title:t.title,stdout:t.stdout,stderr:t.stderr,exitCode:t.exitCode,error:t.error,cancelled:t.cancelled,timedOut:t.timedOut,scriptPath:t.scriptPath,stdoutPath:t.stdoutPath,stderrPath:t.stderrPath,outputDir:t.outputDir,artifacts:t.artifacts,createdAt:t.createdAt,completedAt:t.completedAt}}async function k(t){const r=u.resolve(t.archiveRoot??f(t.cwd)),s=a(r,"sessions",h(t.ownerId,"owner"),"runs"),d=await o.readdir(s,{withFileTypes:!0}).catch(()=>[]),c=[];for(const e of d){if(!e.isDirectory()||e.isSymbolicLink())continue;const i=a(s,e.name,"manifest.json"),n=await o.readFile(i,"utf8").catch(()=>null);if(n)try{const l=JSON.parse(n);l.schema==="kernel-plot.run.v1"&&c.push(l)}catch{}}return c.sort((e,i)=>i.completedAt.localeCompare(e.completedAt,"en"))}export{f as getDefaultArchiveRoot,I as getScriptFileName,k as listRunManifests,p as prepareRunArchive,O as resultFromManifest,D as writeRunLogs,F as writeRunManifest};
@@ -0,0 +1,9 @@
1
+ import type { ArtifactKind, KernelArtifact } from './types.js';
2
+ export declare function getMimeType(extension: string): "image/png" | "image/jpeg" | "image/gif" | "image/webp" | "image/svg+xml" | "text/html; charset=utf-8" | "application/pdf" | "text/plain; charset=utf-8" | "text/csv; charset=utf-8" | "text/tab-separated-values; charset=utf-8" | "application/json; charset=utf-8" | "application/vnd.apache.parquet" | "application/vnd.apache.arrow.file" | "application/x-r-data" | "application/x-hdf5" | "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" | "application/octet-stream";
3
+ export declare function getArtifactKind(extension: string): ArtifactKind;
4
+ export declare function scanArtifacts(input: {
5
+ archiveRoot: string;
6
+ outputDir: string;
7
+ maxArtifactBytes: number;
8
+ maxArtifactsPerRun: number;
9
+ }): Promise<KernelArtifact[]>;
@@ -0,0 +1 @@
1
+ import{promises as c}from"node:fs";import o from"node:path";import{toPosixRelativePath as u}from"./path-utils.js";const f=new Set([".png",".jpg",".jpeg",".gif",".webp",".svg",".html",".htm",".pdf",".txt",".tsv",".csv",".json",".jsonl",".md",".parquet",".feather",".rds",".rda",".h5",".h5ad",".xlsx"]),h=8;function l(t){switch(t.toLowerCase()){case".png":return"image/png";case".jpg":case".jpeg":return"image/jpeg";case".gif":return"image/gif";case".webp":return"image/webp";case".svg":return"image/svg+xml";case".html":case".htm":return"text/html; charset=utf-8";case".pdf":return"application/pdf";case".txt":case".md":return"text/plain; charset=utf-8";case".csv":return"text/csv; charset=utf-8";case".tsv":return"text/tab-separated-values; charset=utf-8";case".json":case".jsonl":return"application/json; charset=utf-8";case".parquet":return"application/vnd.apache.parquet";case".feather":return"application/vnd.apache.arrow.file";case".rds":case".rda":return"application/x-r-data";case".h5":case".h5ad":return"application/x-hdf5";case".xlsx":return"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";default:return"application/octet-stream"}}function m(t){const e=t.toLowerCase();return[".png",".jpg",".jpeg",".gif",".webp",".svg"].includes(e)?"image":[".html",".htm"].includes(e)?"html":[".pdf",".xlsx"].includes(e)?"document":[".txt",".md"].includes(e)?"text":[".csv",".tsv",".json",".jsonl",".parquet",".feather",".rds",".rda",".h5",".h5ad"].includes(e)?"data":"other"}async function p(t){if(t.depth>h)return[];const e=await c.readdir(t.currentDir,{withFileTypes:!0}).catch(()=>[]),s=[];for(const a of e){if(s.length>=t.maxArtifactsPerRun)break;const r=o.join(t.currentDir,a.name);if(a.isSymbolicLink())continue;if(a.isDirectory()){s.push(...await p({...t,currentDir:r,depth:t.depth+1,maxArtifactsPerRun:t.maxArtifactsPerRun-s.length}));continue}if(!a.isFile())continue;const n=o.extname(a.name).toLowerCase();if(!f.has(n))continue;const i=await c.lstat(r);i.isSymbolicLink()||!i.isFile()||i.size>t.maxArtifactBytes||s.push({path:r,relativePath:u(t.outputDir,r),archivePath:u(t.archiveRoot,r),name:a.name,mimeType:l(n),kind:m(n),size:i.size})}return s}async function v(t){const e=await c.lstat(t.outputDir).catch(()=>null);return!e||e.isSymbolicLink()||!e.isDirectory()?[]:(await p({...t,currentDir:t.outputDir,depth:0})).sort((a,r)=>a.archivePath.localeCompare(r.archivePath,"en"))}export{m as getArtifactKind,l as getMimeType,v as scanArtifacts};
@@ -0,0 +1,25 @@
1
+ import type { KernelLanguage } from './types.js';
2
+ export interface KernelConfig {
3
+ language: KernelLanguage;
4
+ command: string;
5
+ args: string[];
6
+ displayName: string;
7
+ env: Record<string, string>;
8
+ }
9
+ export interface GlobalConfig {
10
+ version: string;
11
+ kernels: Record<string, KernelConfig>;
12
+ defaultKernel: Record<KernelLanguage, string>;
13
+ scanCache: {
14
+ lastScan: string;
15
+ scannedKernels: string[];
16
+ };
17
+ }
18
+ export interface ProjectConfig {
19
+ version: string;
20
+ selectedKernels: Record<KernelLanguage, string>;
21
+ }
22
+ export declare function loadGlobalConfig(): Promise<GlobalConfig>;
23
+ export declare function saveGlobalConfig(config: GlobalConfig): Promise<void>;
24
+ export declare function loadProjectConfig(cwd: string): Promise<ProjectConfig | null>;
25
+ export declare function saveProjectConfig(cwd: string, config: ProjectConfig): Promise<void>;
@@ -0,0 +1 @@
1
+ import{homedir as c}from"node:os";import{join as a}from"node:path";import{readFile as s,writeFile as l,mkdir as f}from"node:fs/promises";const e="1.0";function g(){return a(c(),".config","warmplot.json")}function u(o){return a(o,".pi","warmplot.json")}function d(){return{version:e,kernels:{"default-python":{language:"python",command:"python3",args:["-u"],displayName:"Python 3 (System)",env:{}},"default-r":{language:"r",command:"R",args:["--slave","--vanilla"],displayName:"R (System)",env:{}}},defaultKernel:{python:"default-python",r:"default-r"},scanCache:{lastScan:new Date().toISOString(),scannedKernels:["default-python","default-r"]}}}async function y(){const o=g();try{const t=await s(o,"utf-8"),n=JSON.parse(t);return n.version!==e&&console.warn(`Config version mismatch: expected ${e}, got ${n.version}`),n}catch(t){return t.code==="ENOENT"||console.warn("Failed to load global config, using defaults:",t),d()}}async function v(o){const t=g(),n=a(c(),".config");try{await f(n,{recursive:!0}),await l(t,JSON.stringify(o,null,2),"utf-8")}catch(r){throw new Error(`Failed to save global config: ${r instanceof Error?r.message:String(r)}`)}}async function w(o){const t=u(o);try{const n=await s(t,"utf-8"),r=JSON.parse(n);return r.version!==e&&console.warn(`Project config version mismatch: expected ${e}, got ${r.version}`),r}catch(n){return n.code==="ENOENT"||console.warn("Failed to load project config:",n),null}}async function N(o,t){const n=u(o),r=a(o,".pi");try{await f(r,{recursive:!0}),await l(n,JSON.stringify(t,null,2),"utf-8")}catch(i){throw new Error(`Failed to save project config: ${i instanceof Error?i.message:String(i)}`)}}export{y as loadGlobalConfig,w as loadProjectConfig,v as saveGlobalConfig,N as saveProjectConfig};
@@ -0,0 +1,23 @@
1
+ import type { ExecuteKernelRunInput, ExecuteKernelRunResult, KernelArtifact, KernelLanguage, KernelLiteCore, KernelLiteCoreOptions, KernelPlotPolicy } from './types.js';
2
+ export declare class KernelLiteCoreService implements KernelLiteCore {
3
+ readonly policy: KernelPlotPolicy;
4
+ private readonly runController;
5
+ private readonly kernelRuntime;
6
+ constructor(options?: KernelLiteCoreOptions);
7
+ run(input: ExecuteKernelRunInput): Promise<ExecuteKernelRunResult>;
8
+ stopSession(input: {
9
+ ownerId: string;
10
+ language?: KernelLanguage;
11
+ }): Promise<void>;
12
+ cancelRun(runId: string, reason?: string): Promise<boolean>;
13
+ listArtifacts(input: {
14
+ cwd: string;
15
+ ownerId: string;
16
+ limit?: number;
17
+ archiveRoot?: string;
18
+ }): Promise<KernelArtifact[]>;
19
+ dispose(): Promise<void>;
20
+ getActiveRunCount(): number;
21
+ getActiveKernelCount(): number;
22
+ }
23
+ export declare function createKernelLiteCore(options?: KernelLiteCoreOptions): KernelLiteCoreService;
@@ -0,0 +1 @@
1
+ import{randomUUID as h}from"node:crypto";import{listRunManifests as w,prepareRunArchive as R,resultFromManifest as y,writeRunLogs as P,writeRunManifest as p}from"./archive.js";import{scanArtifacts as C}from"./artifacts.js";import{resolveKernelPlotPolicy as A}from"./policy.js";import{isMissingRuntimeError as b}from"./process.js";import{RunController as v}from"./run-controller.js";import{KernelLiteRuntimeManager as k}from"./runtimes/kernel-lite.js";import{runWorkerRuntime as I}from"./runtimes/worker.js";function x(){return h().replace(/-/g,"").slice(0,16)}function M(t){if(t!=="python"&&t!=="r")throw new Error("language must be python or r")}function E(t){if(t!=="kernel-lite"&&t!=="worker")throw new Error("runtime must be kernel-lite or worker")}function S(t){return t.cancelled?"cancelled":t.timedOut?"timed_out":t.exitCode===0&&!t.error?"succeeded":"failed"}function D(t,e){if(!t)return e;if(!e)return t;const r=new AbortController,n=()=>{r.signal.aborted||r.abort(t.reason??e.reason)};return t.addEventListener("abort",n,{once:!0}),e.addEventListener("abort",n,{once:!0}),(t.aborted||e.aborted)&&n(),r.signal}class K{policy;runController=new v;kernelRuntime;constructor(e={}){this.policy=A(e.policy),this.kernelRuntime=new k(this.policy)}async run(e){if(!this.policy.enabled)throw new Error("Kernel plotting is disabled");M(e.language);const r=e.runtime??this.policy.defaultRuntime;if(E(r),typeof e.code!="string"||e.code.length===0)throw new Error("code required");const n=x(),l=new Date().toISOString(),i=await R({cwd:e.cwd,archiveRoot:e.archiveRoot,ownerId:e.ownerId,runId:n,language:e.language,code:e.code}),s=this.runController.register({runId:n,ownerId:e.ownerId,language:e.language,runtime:r}),u=D(e.signal,s.signal);let o;try{const a={id:n,language:e.language,code:e.code,cwd:e.cwd,outputDir:i.outputDir,scriptPath:i.scriptPath,stdoutPath:i.stdoutPath,stderrPath:i.stderrPath,timeoutMs:e.timeoutMs??this.policy.timeoutMs,env:e.env??{},signal:u};o=r==="worker"?await I({run:a,policy:this.policy}):await this.kernelRuntime.execute({ownerId:e.ownerId,language:e.language,run:a})}catch(a){const c=a instanceof Error?a.message:"Plot run failed";o={stdout:"",stderr:"",exitCode:null,timedOut:!1,cancelled:!1,error:b(new Error(c))?`Missing ${e.language==="r"?"R":"Python"} runtime`:c}}finally{s.unregister()}await P({stdoutPath:i.stdoutPath,stderrPath:i.stderrPath,stdout:o.stdout,stderr:o.stderr});const d=await C({archiveRoot:i.archiveRoot,outputDir:i.outputDir,maxArtifactBytes:this.policy.maxArtifactBytes,maxArtifactsPerRun:this.policy.maxArtifactsPerRun}),g=S(o),m=new Date().toISOString(),f=await p({archive:i,language:e.language,runtime:r,status:g,title:e.title,stdout:o.stdout,stderr:o.stderr,exitCode:o.exitCode,error:o.error,cancelled:o.cancelled,timedOut:o.timedOut,artifacts:d,createdAt:l,completedAt:m});return y(f)}async stopSession(e){await this.kernelRuntime.stopSession(e)}async cancelRun(e,r){return this.runController.cancel(e,r)}async listArtifacts(e){return(await w(e)).flatMap(n=>n.artifacts).slice(0,e.limit??100)}async dispose(){await this.kernelRuntime.dispose()}getActiveRunCount(){return this.runController.count()}getActiveKernelCount(){return this.kernelRuntime.getActiveKernelCount()}}function _(t){return new K(t)}export{K as KernelLiteCoreService,_ as createKernelLiteCore};
@@ -0,0 +1,16 @@
1
+ export { getDefaultArchiveRoot, listRunManifests, prepareRunArchive, resultFromManifest } from './archive.js';
2
+ export { getArtifactKind, getMimeType, scanArtifacts } from './artifacts.js';
3
+ export { loadGlobalConfig, loadProjectConfig, saveGlobalConfig, saveProjectConfig } from './config.js';
4
+ export { createKernelLiteCore, KernelLiteCoreService } from './core.js';
5
+ export { resolveKernel } from './kernel-resolver.js';
6
+ export { defaultKernelPlotPolicy, resolveKernelPlotPolicy } from './policy.js';
7
+ export { RunController } from './run-controller.js';
8
+ export { KernelLiteRuntimeManager } from './runtimes/kernel-lite.js';
9
+ export { PythonKernelDriver } from './runtimes/python-kernel.js';
10
+ export { RKernelDriver } from './runtimes/r-kernel.js';
11
+ export { runWorkerRuntime } from './runtimes/worker.js';
12
+ export { scanAllEnvironments, scanPythonEnvironments, scanREnvironments } from './scanner.js';
13
+ export type { ArtifactKind, ExecuteKernelRunInput, ExecuteKernelRunResult, KernelArtifact, KernelLanguage, KernelLiteCore, KernelLiteCoreOptions, KernelPlotPolicy, KernelRunStatus, KernelRuntime, KernelRuntimeDriver, PreparedRunArchive, RunManifest, RuntimeExecuteInput, RuntimeExecuteResult } from './types.js';
14
+ export type { GlobalConfig, KernelConfig, ProjectConfig } from './config.js';
15
+ export type { ResolveKernelInput, ResolvedKernel } from './kernel-resolver.js';
16
+ export type { ScanResult } from './scanner.js';
@@ -0,0 +1 @@
1
+ import{getDefaultArchiveRoot as o,listRunManifests as t,prepareRunArchive as n,resultFromManifest as l}from"./archive.js";import{getArtifactKind as f,getMimeType as a,scanArtifacts as m}from"./artifacts.js";import{loadGlobalConfig as p,loadProjectConfig as c,saveGlobalConfig as v,saveProjectConfig as x}from"./config.js";import{createKernelLiteCore as K,KernelLiteCoreService as g}from"./core.js";import{resolveKernel as R}from"./kernel-resolver.js";import{defaultKernelPlotPolicy as y,resolveKernelPlotPolicy as A}from"./policy.js";import{RunController as h}from"./run-controller.js";import{KernelLiteRuntimeManager as D}from"./runtimes/kernel-lite.js";import{PythonKernelDriver as L}from"./runtimes/python-kernel.js";import{RKernelDriver as j}from"./runtimes/r-kernel.js";import{runWorkerRuntime as k}from"./runtimes/worker.js";import{scanAllEnvironments as S,scanPythonEnvironments as T,scanREnvironments as W}from"./scanner.js";export{g as KernelLiteCoreService,D as KernelLiteRuntimeManager,L as PythonKernelDriver,j as RKernelDriver,h as RunController,K as createKernelLiteCore,y as defaultKernelPlotPolicy,f as getArtifactKind,o as getDefaultArchiveRoot,a as getMimeType,t as listRunManifests,p as loadGlobalConfig,c as loadProjectConfig,n as prepareRunArchive,R as resolveKernel,A as resolveKernelPlotPolicy,l as resultFromManifest,k as runWorkerRuntime,v as saveGlobalConfig,x as saveProjectConfig,S as scanAllEnvironments,m as scanArtifacts,T as scanPythonEnvironments,W as scanREnvironments};
@@ -0,0 +1,15 @@
1
+ import type { KernelLanguage, KernelPlotPolicy } from './types.js';
2
+ export interface ResolveKernelInput {
3
+ language: KernelLanguage;
4
+ cwd: string;
5
+ sessionKernelId?: string;
6
+ policy: KernelPlotPolicy;
7
+ }
8
+ export interface ResolvedKernel {
9
+ command: string;
10
+ args: string[];
11
+ env: Record<string, string>;
12
+ source: 'session' | 'project' | 'global' | 'policy' | 'path';
13
+ kernelId?: string;
14
+ }
15
+ export declare function resolveKernel(input: ResolveKernelInput): Promise<ResolvedKernel>;
@@ -0,0 +1 @@
1
+ import{loadGlobalConfig as m,loadProjectConfig as g}from"./config.js";function s(e,o){return o.kernels[e]||null}function t(e,o){return e==="python"?{command:o.pythonCommand,args:o.pythonArgs,env:{},source:"policy"}:{command:o.rCommand,args:o.rArgs,env:{},source:"policy"}}function d(e){return{command:e==="python"?"python3":"R",args:e==="python"?["-u"]:["--slave","--vanilla"],env:{},source:"path"}}async function i(e){const o=await m(),l=await g(e.cwd);if(e.sessionKernelId){const n=s(e.sessionKernelId,o);if(n)return{command:n.command,args:n.args,env:n.env,source:"session",kernelId:e.sessionKernelId}}if(l?.selectedKernels[e.language]){const n=l.selectedKernels[e.language],r=s(n,o);if(r)return{command:r.command,args:r.args,env:r.env,source:"project",kernelId:n}}const a=o.defaultKernel[e.language];if(a){const n=s(a,o);if(n)return{command:n.command,args:n.args,env:n.env,source:"global",kernelId:a}}const c=e.language==="python"?e.policy.pythonCommand:e.policy.rCommand;return c!=="python3"&&c!=="R"?t(e.language,e.policy):d(e.language)}export{i as resolveKernel};
@@ -0,0 +1,4 @@
1
+ export declare function assertInsideRoot(root: string, absolutePath: string, message: string): void;
2
+ export declare function resolveWithinRoot(root: string, ...segments: string[]): string;
3
+ export declare function toPosixRelativePath(root: string, absolutePath: string): string;
4
+ export declare function sanitizePathSegment(value: string, fallback: string): string;
@@ -0,0 +1 @@
1
+ import o from"node:path";function a(t,r,e){const s=o.relative(t,r);if(s.startsWith("..")||o.isAbsolute(s))throw new Error(e)}function n(t,...r){const e=o.resolve(t,...r);return a(o.resolve(t),e,"Path escapes archive root"),e}function l(t,r){const e=o.resolve(t),s=o.resolve(r);return a(e,s,"Path escapes archive root"),o.relative(e,s).split(o.sep).join("/")}function c(t,r){const e=t.normalize("NFKD").replace(/[^A-Za-z0-9_-]+/g,"-").replace(/^-+|-+$/g,"").slice(0,96);return e.length>0?e:r}export{a as assertInsideRoot,n as resolveWithinRoot,c as sanitizePathSegment,l as toPosixRelativePath};
@@ -0,0 +1,3 @@
1
+ import type { KernelPlotPolicy } from './types.js';
2
+ export declare const defaultKernelPlotPolicy: KernelPlotPolicy;
3
+ export declare function resolveKernelPlotPolicy(policy?: Partial<KernelPlotPolicy>): KernelPlotPolicy;
@@ -0,0 +1 @@
1
+ const t={enabled:!0,defaultRuntime:"kernel-lite",timeoutMs:6e4,idleTimeoutMs:9e5,maxLogChars:2e5,maxArtifactBytes:262144e3,maxArtifactsPerRun:200,pythonCommand:"python3",pythonArgs:[],rCommand:"R",rArgs:["--slave","--vanilla"],rscriptCommand:"Rscript",rscriptArgs:[]};function s(r){return{...t,...r,pythonArgs:r?.pythonArgs??t.pythonArgs,rArgs:r?.rArgs??t.rArgs,rscriptArgs:r?.rscriptArgs??t.rscriptArgs}}export{t as defaultKernelPlotPolicy,s as resolveKernelPlotPolicy};
@@ -0,0 +1,20 @@
1
+ import { type ChildProcess } from 'node:child_process';
2
+ import type { RuntimeExecuteResult } from './types.js';
3
+ export declare function trimLog(value: string, limit: number): string;
4
+ export declare function buildRuntimeEnv(outputDir: string, extraEnv?: Record<string, string>): {
5
+ WARMPLOT_OUTPUT_DIR: string;
6
+ PI_KERNEL_PLOT_OUTPUT_DIR: string;
7
+ OPENANNO_PLOT_OUTPUT_DIR: string;
8
+ };
9
+ export declare function isMissingRuntimeError(error: Error): boolean;
10
+ export declare function terminateChild(child: ChildProcess, isSettled: () => boolean): void;
11
+ export declare function runChildProcess(input: {
12
+ command: string;
13
+ args: string[];
14
+ cwd: string;
15
+ env: Record<string, string | undefined>;
16
+ timeoutMs: number;
17
+ maxLogChars: number;
18
+ signal?: AbortSignal;
19
+ label: string;
20
+ }): Promise<RuntimeExecuteResult>;
@@ -0,0 +1,2 @@
1
+ import{spawn as L}from"node:child_process";function E(e,r){return e.length<=r?e:`${e.slice(0,r)}
2
+ [Warmplot truncated log at ${r} characters]`}function P(e,r){return{...process.env,...r,WARMPLOT_OUTPUT_DIR:e,PI_KERNEL_PLOT_OUTPUT_DIR:e,OPENANNO_PLOT_OUTPUT_DIR:e}}function b(e){return e.message.includes("ENOENT")||e.message.includes("not found")}function T(e,r){e.kill("SIGTERM"),setTimeout(()=>{r()||e.kill("SIGKILL")},1500).unref()}function h(e){return new Promise(r=>{let a="",i="",n=!1,l=!1,s=!1;const o=L(e.command,e.args,{cwd:e.cwd,env:e.env,shell:!1,stdio:["ignore","pipe","pipe"]}),d=t=>{n||(n=!0,clearTimeout(u),e.signal?.removeEventListener("abort",c),r(t))},u=setTimeout(()=>{l=!0,T(o,()=>n)},e.timeoutMs);u.unref();const c=()=>{n||(s=!0,T(o,()=>n))};e.signal?.addEventListener("abort",c,{once:!0}),e.signal?.aborted&&c(),o.stdout.on("data",t=>{a=E(`${a}${t.toString("utf8")}`,e.maxLogChars)}),o.stderr.on("data",t=>{i=E(`${i}${t.toString("utf8")}`,e.maxLogChars)}),o.on("error",t=>{d({stdout:a,stderr:i,exitCode:null,timedOut:l,cancelled:s,error:t.message})}),o.on("close",(t,m)=>{const f=s?`${e.label} cancelled`:null,g=l?`${e.label} timed out after ${Math.round(e.timeoutMs/1e3)}s`:null,$=m&&!g&&!f?`${e.label} exited via signal ${m}`:null,x=typeof t=="number"&&t!==0?`${e.label} exited with code ${t}`:null;d({stdout:a,stderr:i,exitCode:s||l?null:t,timedOut:l,cancelled:s,error:f??g??$??x})})})}export{P as buildRuntimeEnv,b as isMissingRuntimeError,h as runChildProcess,T as terminateChild,E as trimLog};
@@ -0,0 +1,16 @@
1
+ import type { KernelLanguage, KernelRuntime } from './types.js';
2
+ export declare class RunController {
3
+ private activeRuns;
4
+ register(input: {
5
+ runId: string;
6
+ ownerId: string;
7
+ language: KernelLanguage;
8
+ runtime: KernelRuntime;
9
+ }): {
10
+ signal: AbortSignal;
11
+ unregister: () => void;
12
+ };
13
+ cancel(runId: string, reason?: string): boolean;
14
+ isActive(runId: string): boolean;
15
+ count(): number;
16
+ }
@@ -0,0 +1 @@
1
+ class s{activeRuns=new Map;register(t){const r=new AbortController,e={...t,abortController:r};return this.activeRuns.set(t.runId,e),{signal:r.signal,unregister:()=>{this.activeRuns.get(t.runId)===e&&this.activeRuns.delete(t.runId)}}}cancel(t,r="Plot run cancelled"){const e=this.activeRuns.get(t);return e?(e.abortController.abort(r),!0):!1}isActive(t){return this.activeRuns.has(t)}count(){return this.activeRuns.size}}export{s as RunController};
@@ -0,0 +1,9 @@
1
+ import type { KernelLanguage, KernelPlotPolicy } from './types.js';
2
+ export declare function getWorkerCommand(policy: KernelPlotPolicy, language: KernelLanguage, scriptPath: string): {
3
+ command: string;
4
+ args: string[];
5
+ };
6
+ export declare function getWarmKernelCommand(policy: KernelPlotPolicy, language: KernelLanguage, driver?: string): {
7
+ command: string;
8
+ args: string[];
9
+ };
@@ -0,0 +1 @@
1
+ function e(r,m,n){return m==="r"?{command:r.rscriptCommand,args:[...r.rscriptArgs,n]}:{command:r.pythonCommand,args:[...r.pythonArgs,n]}}function o(r,m,n){if(m==="r")return{command:r.rCommand,args:r.rArgs};if(!n)throw new Error("Python kernel driver required");return{command:r.pythonCommand,args:[...r.pythonArgs,"-u","-c",n]}}export{o as getWarmKernelCommand,e as getWorkerCommand};
@@ -0,0 +1,21 @@
1
+ import type { KernelLanguage, KernelPlotPolicy, RuntimeExecuteInput, RuntimeExecuteResult } from '../types.js';
2
+ export declare class KernelLiteRuntimeManager {
3
+ private readonly policy;
4
+ private kernels;
5
+ constructor(policy: KernelPlotPolicy);
6
+ execute(input: {
7
+ ownerId: string;
8
+ language: KernelLanguage;
9
+ run: RuntimeExecuteInput;
10
+ }): Promise<RuntimeExecuteResult>;
11
+ stopSession(input: {
12
+ ownerId: string;
13
+ language?: KernelLanguage;
14
+ }): Promise<void>;
15
+ dispose(): Promise<void>;
16
+ getActiveKernelCount(): number;
17
+ private createRuntimeKey;
18
+ private getOrCreateKernel;
19
+ private stopKernelByKey;
20
+ private executeWithTimeout;
21
+ }
@@ -0,0 +1 @@
1
+ import{PythonKernelDriver as o}from"./python-kernel.js";import{RKernelDriver as a}from"./r-kernel.js";class u{driver;idleTimeoutMs;onIdle;tail=Promise.resolve();idleTimer=null;constructor(e,r,t){this.driver=e,this.idleTimeoutMs=r,this.onIdle=t}execute(e){this.clearIdleTimer();const r=this.tail.then(()=>this.driver.execute(e));return this.tail=r.catch(()=>{}).finally(()=>this.armIdleTimer()),r}async shutdown(){this.clearIdleTimer(),await this.driver.shutdown()}armIdleTimer(){this.clearIdleTimer(),this.idleTimer=setTimeout(()=>{this.onIdle()},this.idleTimeoutMs),this.idleTimer.unref()}clearIdleTimer(){this.idleTimer&&(clearTimeout(this.idleTimer),this.idleTimer=null)}}function c(i){return i.language==="r"?new a(i.cwd,i.policy):new o(i.cwd,i.policy)}class m{policy;kernels=new Map;constructor(e){this.policy=e}execute(e){const r=this.createRuntimeKey(e.ownerId,e.language),t=this.getOrCreateKernel({key:r,language:e.language,cwd:e.run.cwd});return this.executeWithTimeout({key:r,kernel:t,run:e.run})}async stopSession(e){const r=e.language?[e.language]:["python","r"];await Promise.all(r.map(t=>this.stopKernelByKey(this.createRuntimeKey(e.ownerId,t))))}async dispose(){await Promise.all([...this.kernels.keys()].map(e=>this.stopKernelByKey(e)))}getActiveKernelCount(){return this.kernels.size}createRuntimeKey(e,r){return`${e}:${r}`}getOrCreateKernel(e){const r=this.kernels.get(e.key);if(r)return r;const t=new u(c({language:e.language,cwd:e.cwd,policy:this.policy}),this.policy.idleTimeoutMs,()=>{this.stopKernelByKey(e.key)});return this.kernels.set(e.key,t),t}async stopKernelByKey(e){const r=this.kernels.get(e);r&&(this.kernels.delete(e),await r.shutdown())}executeWithTimeout(e){let r=null;return new Promise(t=>{let l=!1;const s=()=>{l||(l=!0,r&&clearTimeout(r),this.stopKernelByKey(e.key),t({stdout:"",stderr:"",exitCode:null,timedOut:!1,cancelled:!0,error:"Plot run cancelled"}))};if(r=setTimeout(()=>{l||(l=!0,e.run.signal?.removeEventListener("abort",s),this.stopKernelByKey(e.key),t({stdout:"",stderr:"",exitCode:null,timedOut:!0,cancelled:!1,error:`Plot kernel timed out after ${Math.round(e.run.timeoutMs/1e3)}s`}))},e.run.timeoutMs),r.unref(),e.run.signal?.addEventListener("abort",s,{once:!0}),e.run.signal?.aborted){s();return}e.kernel.execute(e.run).then(n=>{l||(l=!0,r&&clearTimeout(r),e.run.signal?.removeEventListener("abort",s),t(n))})})}}export{m as KernelLiteRuntimeManager};
@@ -0,0 +1,15 @@
1
+ import type { KernelPlotPolicy, KernelRuntimeDriver, RuntimeExecuteInput, RuntimeExecuteResult } from '../types.js';
2
+ export declare class PythonKernelDriver implements KernelRuntimeDriver {
3
+ private readonly cwd;
4
+ private readonly policy;
5
+ private process;
6
+ private pending;
7
+ private stdoutBuffer;
8
+ private stderr;
9
+ private stopped;
10
+ constructor(cwd: string, policy: KernelPlotPolicy);
11
+ execute(input: RuntimeExecuteInput): Promise<RuntimeExecuteResult>;
12
+ shutdown(): Promise<void>;
13
+ private handleStdout;
14
+ private failPending;
15
+ }
@@ -0,0 +1,62 @@
1
+ import{spawn as n}from"node:child_process";import{buildRuntimeEnv as d,trimLog as l}from"../process.js";import{getWarmKernelCommand as u}from"../runtime-command.js";const i="WARMPLOT_KERNEL_RESPONSE ",a=String.raw`
2
+ import contextlib
3
+ import io
4
+ import json
5
+ import os
6
+ import sys
7
+ import traceback
8
+
9
+ globals_ns = {"__name__": "__main__"}
10
+
11
+ def trim_log(value, limit):
12
+ if len(value) <= limit:
13
+ return value
14
+ return value[:limit] + "\n[Warmplot truncated log at %d characters]" % limit
15
+
16
+ for line in sys.stdin:
17
+ try:
18
+ request = json.loads(line)
19
+ if request.get("type") == "shutdown":
20
+ break
21
+
22
+ output_dir = request["outputDir"]
23
+ os.environ["WARMPLOT_OUTPUT_DIR"] = output_dir
24
+ os.environ["PI_KERNEL_PLOT_OUTPUT_DIR"] = output_dir
25
+ os.environ["OPENANNO_PLOT_OUTPUT_DIR"] = output_dir
26
+ for key, value in request.get("env", {}).items():
27
+ os.environ[str(key)] = str(value)
28
+ os.chdir(request["cwd"])
29
+ stdout = io.StringIO()
30
+ stderr = io.StringIO()
31
+ status = "ok"
32
+ error = None
33
+
34
+ try:
35
+ with contextlib.redirect_stdout(stdout), contextlib.redirect_stderr(stderr):
36
+ exec(request["code"], globals_ns, globals_ns)
37
+ except BaseException as exc:
38
+ status = "error"
39
+ error = str(exc)
40
+ stderr.write(traceback.format_exc())
41
+
42
+ response = {
43
+ "id": request["id"],
44
+ "status": status,
45
+ "stdout": trim_log(stdout.getvalue(), int(request.get("maxLogChars", 200000))),
46
+ "stderr": trim_log(stderr.getvalue(), int(request.get("maxLogChars", 200000))),
47
+ "error": error,
48
+ }
49
+ except BaseException as exc:
50
+ response = {
51
+ "id": None,
52
+ "status": "error",
53
+ "stdout": "",
54
+ "stderr": traceback.format_exc(),
55
+ "error": str(exc),
56
+ }
57
+
58
+ sys.stdout.write("WARMPLOT_KERNEL_RESPONSE " + json.dumps(response) + "\n")
59
+ sys.stdout.flush()
60
+ `;class m{cwd;policy;process;pending=null;stdoutBuffer="";stderr="";stopped=!1;constructor(t,e){this.cwd=t,this.policy=e;const o=u(e,"python",a);this.process=n(o.command,o.args,{cwd:t,env:d(t),shell:!1,stdio:["pipe","pipe","pipe"]}),this.process.stdout.setEncoding("utf8"),this.process.stderr.setEncoding("utf8"),this.process.stdout.on("data",s=>this.handleStdout(s)),this.process.stderr.on("data",s=>{this.stderr=l(`${this.stderr}${s}`,this.policy.maxLogChars)}),this.process.on("error",s=>this.failPending(s.message)),this.process.on("exit",()=>{this.stopped=!0,this.failPending("Python plot kernel stopped")})}execute(t){return this.stopped||this.process.killed?Promise.resolve({stdout:"",stderr:this.stderr,exitCode:null,timedOut:!1,cancelled:!1,error:"Python plot kernel is not running"}):this.pending?Promise.resolve({stdout:"",stderr:"",exitCode:null,timedOut:!1,cancelled:!1,error:"Python plot kernel is busy"}):new Promise(e=>{this.pending={id:t.id,resolve:e},this.process.stdin.write(`${JSON.stringify({id:t.id,code:t.code,cwd:t.cwd,outputDir:t.outputDir,env:t.env,maxLogChars:this.policy.maxLogChars})}
61
+ `,o=>{o&&this.failPending(o.message)})})}async shutdown(){this.stopped=!0,this.process.stdin.write(`${JSON.stringify({type:"shutdown"})}
62
+ `,()=>{}),this.process.kill("SIGTERM"),setTimeout(()=>{this.process.killed||this.process.kill("SIGKILL")},1500).unref(),this.failPending("Python plot kernel stopped")}handleStdout(t){this.stdoutBuffer+=t;const e=this.stdoutBuffer.split(/\r?\n/);this.stdoutBuffer=e.pop()??"";for(const o of e){if(!o.startsWith(i))continue;const s=this.pending;if(s)try{const r=JSON.parse(o.slice(i.length));if(r.id!==s.id)continue;this.pending=null,s.resolve({stdout:r.stdout??"",stderr:r.stderr??"",exitCode:r.status==="ok"?0:1,timedOut:!1,cancelled:!1,error:r.status==="ok"?null:r.error??"Python plot kernel execution failed"})}catch(r){this.failPending(r instanceof Error?r.message:"Failed to parse Python kernel response")}}}failPending(t){const e=this.pending;e&&(this.pending=null,e.resolve({stdout:"",stderr:this.stderr,exitCode:null,timedOut:!1,cancelled:!1,error:t}))}}export{m as PythonKernelDriver};
@@ -0,0 +1,15 @@
1
+ import type { KernelPlotPolicy, KernelRuntimeDriver, RuntimeExecuteInput, RuntimeExecuteResult } from '../types.js';
2
+ export declare class RKernelDriver implements KernelRuntimeDriver {
3
+ private readonly cwd;
4
+ private readonly policy;
5
+ private process;
6
+ private pending;
7
+ private stdoutBuffer;
8
+ private stderr;
9
+ private stopped;
10
+ constructor(cwd: string, policy: KernelPlotPolicy);
11
+ execute(input: RuntimeExecuteInput): Promise<RuntimeExecuteResult>;
12
+ shutdown(): Promise<void>;
13
+ private handleStdout;
14
+ private failPending;
15
+ }
@@ -0,0 +1,7 @@
1
+ import{spawn as h}from"node:child_process";import{promises as n}from"node:fs";import{buildRuntimeEnv as f,trimLog as d}from"../process.js";import{getWarmKernelCommand as _}from"../runtime-command.js";const c="WARMPLOT_KERNEL_RESPONSE ";function i(a){return`"${a.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\r/g,"\\r").replace(/\n/g,"\\n")}"`}function g(a){return Object.entries(a).map(([t,e])=>` ${t} = ${i(e)}`).join(`,
2
+ `)}class E{cwd;policy;process;pending=null;stdoutBuffer="";stderr="";stopped=!1;constructor(t,e){this.cwd=t,this.policy=e;const r=_(e,"r");this.process=h(r.command,r.args,{cwd:t,env:f(t),shell:!1,stdio:["pipe","pipe","pipe"]}),this.process.stdout.setEncoding("utf8"),this.process.stderr.setEncoding("utf8"),this.process.stdout.on("data",s=>this.handleStdout(s)),this.process.stderr.on("data",s=>{this.stderr=d(`${this.stderr}${s}`,this.policy.maxLogChars)}),this.process.on("error",s=>this.failPending(s.message)),this.process.on("exit",()=>{this.stopped=!0,this.failPending("R plot kernel stopped")})}async execute(t){if(this.stopped||this.process.killed)return{stdout:"",stderr:this.stderr,exitCode:null,timedOut:!1,cancelled:!1,error:"R plot kernel is not running"};if(this.pending)return{stdout:"",stderr:"",exitCode:null,timedOut:!1,cancelled:!1,error:"R plot kernel is busy"};const e=`${t.stdoutPath}.kernel.tmp`,r=`${t.stderrPath}.kernel.tmp`,s=`${t.scriptPath}.kernel-control.R`,p={...t.env,WARMPLOT_OUTPUT_DIR:t.outputDir,PI_KERNEL_PLOT_OUTPUT_DIR:t.outputDir,OPENANNO_PLOT_OUTPUT_DIR:t.outputDir};return await n.writeFile(s,['.warmplot_run_status <- "ok"','.warmplot_run_error <- ""',`.warmplot_run_stdout <- file(${i(e)}, open = "wt")`,`.warmplot_run_stderr <- file(${i(r)}, open = "wt")`,'.warmplot_old_output_sinks <- sink.number(type = "output")','.warmplot_old_message_sinks <- sink.number(type = "message")',".warmplot_old_wd <- getwd()","tryCatch({",` setwd(${i(t.cwd)})`,` do.call(Sys.setenv, list(
3
+ ${g(p)}
4
+ ))`,' sink(.warmplot_run_stdout, type = "output")',' sink(.warmplot_run_stderr, type = "message")',` source(${i(t.scriptPath)}, local = .GlobalEnv, echo = FALSE)`,"}, error = function(e) {",' .warmplot_run_status <<- "error"'," .warmplot_run_error <<- conditionMessage(e)"," message(conditionMessage(e))","}, finally = {",' while (sink.number(type = "output") > .warmplot_old_output_sinks) sink(type = "output")',' while (sink.number(type = "message") > .warmplot_old_message_sinks) sink(type = "message")'," try(setwd(.warmplot_old_wd), silent = TRUE)"," try(close(.warmplot_run_stdout), silent = TRUE)"," try(close(.warmplot_run_stderr), silent = TRUE)","})",`cat(${i(`${c}${t.id} `)}, .warmplot_run_status, "\\n", sep = "")`,"flush.console()",""].join(`
5
+ `),{encoding:"utf8",flag:"wx",mode:384}),new Promise(l=>{this.pending={id:t.id,resolve:async o=>{const[m,u]=await Promise.all([n.readFile(e,"utf8").catch(()=>""),n.readFile(r,"utf8").catch(()=>"")]);await Promise.all([n.rm(e,{force:!0}),n.rm(r,{force:!0}),n.rm(s,{force:!0})]),l({...o,stdout:d(m,this.policy.maxLogChars),stderr:d(u||o.stderr,this.policy.maxLogChars),error:o.error??(o.exitCode===0?null:d(u,this.policy.maxLogChars).trim()||"R plot kernel execution failed")})}},this.process.stdin.write(`source(${i(s)}, local = .GlobalEnv)
6
+ `,o=>{o&&this.failPending(o.message)})})}async shutdown(){this.stopped=!0,this.process.stdin.write(`quit(save = "no", status = 0)
7
+ `,()=>{}),this.process.kill("SIGTERM"),setTimeout(()=>{this.process.killed||this.process.kill("SIGKILL")},1500).unref(),this.failPending("R plot kernel stopped")}handleStdout(t){this.stdoutBuffer+=t;const e=this.stdoutBuffer.split(/\r?\n/);this.stdoutBuffer=e.pop()??"";for(const r of e){if(!r.startsWith(c))continue;const[,s,p]=r.match(/^WARMPLOT_KERNEL_RESPONSE\s+(\S+)\s+(\S+)/)??[],l=this.pending;!l||s!==l.id||(this.pending=null,l.resolve({stdout:"",stderr:"",exitCode:p==="ok"?0:1,timedOut:!1,cancelled:!1,error:null}))}}failPending(t){const e=this.pending;e&&(this.pending=null,e.resolve({stdout:"",stderr:this.stderr,exitCode:null,timedOut:!1,cancelled:!1,error:t}))}}export{E as RKernelDriver};
@@ -0,0 +1,5 @@
1
+ import type { KernelPlotPolicy, RuntimeExecuteInput, RuntimeExecuteResult } from '../types.js';
2
+ export declare function runWorkerRuntime(input: {
3
+ run: RuntimeExecuteInput;
4
+ policy: KernelPlotPolicy;
5
+ }): Promise<RuntimeExecuteResult>;
@@ -0,0 +1 @@
1
+ import{buildRuntimeEnv as n,runChildProcess as a}from"../process.js";import{getWorkerCommand as e}from"../runtime-command.js";async function u(r){const o=e(r.policy,r.run.language,r.run.scriptPath);return a({command:o.command,args:o.args,cwd:r.run.cwd,env:n(r.run.outputDir,r.run.env),timeoutMs:r.run.timeoutMs,maxLogChars:r.policy.maxLogChars,signal:r.run.signal,label:`${r.run.language==="r"?"R":"Python"} plot worker`})}export{u as runWorkerRuntime};
@@ -0,0 +1,8 @@
1
+ import type { KernelConfig } from './config.js';
2
+ export interface ScanResult {
3
+ newKernels: KernelConfig[];
4
+ errors: string[];
5
+ }
6
+ export declare function scanPythonEnvironments(cwd?: string): Promise<ScanResult>;
7
+ export declare function scanREnvironments(cwd?: string): Promise<ScanResult>;
8
+ export declare function scanAllEnvironments(cwd?: string): Promise<ScanResult>;
@@ -0,0 +1,4 @@
1
+ import{exec as p}from"node:child_process";import{promisify as v}from"node:util";import{access as m,constants as f}from"node:fs/promises";import{join as h,basename as u}from"node:path";const c=v(p);async function i(t){try{return await m(t,f.X_OK),!0}catch{return!1}}async function g(){const t=[],s=[];try{const{stdout:n}=await c("conda env list"),r=n.split(`
2
+ `);for(const o of r){if(o.startsWith("#")||!o.trim())continue;const e=o.trim().split(/\s+/);if(e.length<2)continue;const a=e[0],l=e[e.length-1],y=h(l,"bin","python");await i(y)&&t.push({language:"python",command:y,args:["-u"],displayName:`Python 3 (Conda ${a})`,env:{CONDA_DEFAULT_ENV:a}})}}catch(n){s.push(`Conda scan failed: ${n instanceof Error?n.message:String(n)}`)}return{kernels:t,errors:s}}async function P(t){const s=[],n=[],r=[".venv","venv","env"];for(const o of r)try{const e=h(t,o,"bin","python");if(await i(e)){const a=u(t);s.push({language:"python",command:e,args:["-u"],displayName:`Python 3 (Venv ${a})`,env:{}})}}catch{}return{kernels:s,errors:n}}async function d(){const t=[],s=[];try{const{stdout:n}=await c("pyenv versions --bare"),r=n.trim().split(`
3
+ `);for(const o of r){if(!o.trim())continue;const e=h(process.env.HOME||"~",".pyenv","versions",o,"bin","python");await i(e)&&t.push({language:"python",command:e,args:["-u"],displayName:`Python ${o} (Pyenv)`,env:{}})}}catch(n){s.push(`Pyenv scan failed: ${n instanceof Error?n.message:String(n)}`)}return{kernels:t,errors:s}}async function w(){const t=[],s=[];try{const{stdout:n}=await c("poetry env list --full-path"),r=n.trim().split(`
4
+ `);for(const o of r){const e=o.split(" ")[0];if(!e)continue;const a=h(e,"bin","python");if(await i(a)){const l=u(e);t.push({language:"python",command:a,args:["-u"],displayName:`Python 3 (Poetry ${l})`,env:{}})}}}catch(n){s.push(`Poetry scan failed: ${n instanceof Error?n.message:String(n)}`)}return{kernels:t,errors:s}}async function R(){const t=[],s=[];try{const{stdout:n}=await c("which python3"),r=n.trim();if(r&&await i(r))try{const{stdout:o}=await c(`${r} --version`),e=o.trim().replace("Python ","");t.push({language:"python",command:"python3",args:["-u"],displayName:`Python ${e} (System)`,env:{}})}catch{t.push({language:"python",command:"python3",args:["-u"],displayName:"Python 3 (System)",env:{}})}}catch(n){s.push(`System Python scan failed: ${n instanceof Error?n.message:String(n)}`)}return{kernels:t,errors:s}}async function E(t){const s=[],n=[],r=[g(),d(),w(),R()];t&&r.push(P(t));const o=await Promise.all(r);for(const{kernels:e,errors:a}of o)s.push(...e),n.push(...a);return{newKernels:s,errors:n}}async function N(){const t=[],s=[];try{const{stdout:n}=await c("which R"),r=n.trim();if(r&&await i(r))try{const{stdout:o}=await c("R --version | head -1"),e=o.match(/R version ([\d.]+)/),a=e?e[1]:"";t.push({language:"r",command:"R",args:["--slave","--vanilla"],displayName:a?`R ${a} (System)`:"R (System)",env:{}})}catch{t.push({language:"r",command:"R",args:["--slave","--vanilla"],displayName:"R (System)",env:{}})}}catch(n){s.push(`System R scan failed: ${n instanceof Error?n.message:String(n)}`)}return{kernels:t,errors:s}}async function S(t){const s=[],n=[];try{const r=h(t,"renv"),o=h(t,"renv.lock"),e=await i(r).catch(()=>!1),a=await m(o).then(()=>!0).catch(()=>!1);if(e||a){const l=u(t);s.push({language:"r",command:"R",args:["--slave","--vanilla"],displayName:`R (Renv ${l})`,env:{RENV_PROJECT:t}})}}catch{}return{kernels:s,errors:n}}async function $(t){const s=[],n=[],r=[N()];t&&r.push(S(t));const o=await Promise.all(r);for(const{kernels:e,errors:a}of o)s.push(...e),n.push(...a);return{newKernels:s,errors:n}}async function x(t){const s=await E(t),n=await $(t);return{newKernels:[...s.newKernels,...n.newKernels],errors:[...s.errors,...n.errors]}}export{x as scanAllEnvironments,E as scanPythonEnvironments,$ as scanREnvironments};
@@ -0,0 +1,138 @@
1
+ export type KernelLanguage = 'python' | 'r';
2
+ export type KernelRuntime = 'kernel-lite' | 'worker' | 'jupyter';
3
+ export type KernelRunStatus = 'queued' | 'running' | 'succeeded' | 'failed' | 'cancelled' | 'timed_out';
4
+ export type ArtifactKind = 'image' | 'html' | 'document' | 'text' | 'data' | 'other';
5
+ export interface KernelPlotPolicy {
6
+ enabled: boolean;
7
+ defaultRuntime: KernelRuntime;
8
+ timeoutMs: number;
9
+ idleTimeoutMs: number;
10
+ maxLogChars: number;
11
+ maxArtifactBytes: number;
12
+ maxArtifactsPerRun: number;
13
+ pythonCommand: string;
14
+ pythonArgs: string[];
15
+ rCommand: string;
16
+ rArgs: string[];
17
+ rscriptCommand: string;
18
+ rscriptArgs: string[];
19
+ }
20
+ export interface ExecuteKernelRunInput {
21
+ cwd: string;
22
+ ownerId: string;
23
+ language: KernelLanguage;
24
+ runtime?: KernelRuntime;
25
+ code: string;
26
+ title?: string;
27
+ archiveRoot?: string;
28
+ timeoutMs?: number;
29
+ env?: Record<string, string>;
30
+ signal?: AbortSignal;
31
+ }
32
+ export interface KernelArtifact {
33
+ path: string;
34
+ relativePath: string;
35
+ archivePath: string;
36
+ name: string;
37
+ mimeType: string;
38
+ kind: ArtifactKind;
39
+ size: number;
40
+ }
41
+ export interface ExecuteKernelRunResult {
42
+ runId: string;
43
+ ownerId: string;
44
+ language: KernelLanguage;
45
+ runtime: KernelRuntime;
46
+ status: KernelRunStatus;
47
+ title?: string;
48
+ stdout: string;
49
+ stderr: string;
50
+ exitCode: number | null;
51
+ error: string | null;
52
+ cancelled: boolean;
53
+ timedOut: boolean;
54
+ scriptPath: string;
55
+ stdoutPath: string;
56
+ stderrPath: string;
57
+ outputDir: string;
58
+ artifacts: KernelArtifact[];
59
+ createdAt: string;
60
+ completedAt: string;
61
+ }
62
+ export interface KernelLiteCore {
63
+ run(input: ExecuteKernelRunInput): Promise<ExecuteKernelRunResult>;
64
+ stopSession(input: {
65
+ ownerId: string;
66
+ language?: KernelLanguage;
67
+ }): Promise<void>;
68
+ cancelRun(runId: string, reason?: string): Promise<boolean>;
69
+ listArtifacts(input: {
70
+ cwd: string;
71
+ ownerId: string;
72
+ limit?: number;
73
+ archiveRoot?: string;
74
+ }): Promise<KernelArtifact[]>;
75
+ dispose(): Promise<void>;
76
+ }
77
+ export interface KernelLiteCoreOptions {
78
+ policy?: Partial<KernelPlotPolicy>;
79
+ }
80
+ export interface RuntimeExecuteInput {
81
+ id: string;
82
+ language: KernelLanguage;
83
+ code: string;
84
+ cwd: string;
85
+ outputDir: string;
86
+ scriptPath: string;
87
+ stdoutPath: string;
88
+ stderrPath: string;
89
+ timeoutMs: number;
90
+ env: Record<string, string>;
91
+ signal?: AbortSignal;
92
+ }
93
+ export interface RuntimeExecuteResult {
94
+ stdout: string;
95
+ stderr: string;
96
+ exitCode: number | null;
97
+ timedOut: boolean;
98
+ cancelled: boolean;
99
+ error: string | null;
100
+ }
101
+ export interface KernelRuntimeDriver {
102
+ execute(input: RuntimeExecuteInput): Promise<RuntimeExecuteResult>;
103
+ shutdown(): Promise<void>;
104
+ }
105
+ export interface RunManifest {
106
+ schema: 'kernel-plot.run.v1';
107
+ runId: string;
108
+ ownerId: string;
109
+ language: KernelLanguage;
110
+ runtime: KernelRuntime;
111
+ status: KernelRunStatus;
112
+ title?: string;
113
+ scriptPath: string;
114
+ stdoutPath: string;
115
+ stderrPath: string;
116
+ outputDir: string;
117
+ artifacts: KernelArtifact[];
118
+ stdout: string;
119
+ stderr: string;
120
+ exitCode: number | null;
121
+ error: string | null;
122
+ cancelled: boolean;
123
+ timedOut: boolean;
124
+ createdAt: string;
125
+ completedAt: string;
126
+ }
127
+ export interface PreparedRunArchive {
128
+ archiveRoot: string;
129
+ ownerId: string;
130
+ safeOwnerId: string;
131
+ runId: string;
132
+ runDir: string;
133
+ scriptPath: string;
134
+ stdoutPath: string;
135
+ stderrPath: string;
136
+ outputDir: string;
137
+ manifestPath: string;
138
+ }
File without changes
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@seqyuan/kernel-lite-core",
3
+ "version": "0.2.1",
4
+ "description": "Lightweight kernel execution core for computational notebooks",
5
+ "type": "module",
6
+ "main": "./dist/src/index.js",
7
+ "types": "./dist/src/index.d.ts",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/seqyuan/warmplot.git",
11
+ "directory": "packages/kernel-lite-core"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/seqyuan/warmplot/issues"
15
+ },
16
+ "homepage": "https://github.com/seqyuan/warmplot#readme",
17
+ "license": "MIT",
18
+ "publishConfig": {
19
+ "access": "public",
20
+ "registry": "https://registry.npmjs.org/"
21
+ },
22
+ "files": [
23
+ "dist",
24
+ "!dist/**/*.map",
25
+ "!dist/**/*.tsbuildinfo",
26
+ "package.json",
27
+ "README.md"
28
+ ],
29
+ "exports": {
30
+ ".": {
31
+ "types": "./dist/src/index.d.ts",
32
+ "import": "./dist/src/index.js"
33
+ }
34
+ },
35
+ "scripts": {
36
+ "build": "tsc -b",
37
+ "prepack": "node ../../scripts/check-pack-protection.mjs .",
38
+ "prepublishOnly": "node ../../scripts/check-pack-protection.mjs .",
39
+ "test": "pnpm run build && node --test tests/*.test.mjs",
40
+ "typecheck": "tsc -b --pretty false"
41
+ }
42
+ }