@ai-ecoverse/slicc-kernel 1.108.5 → 1.109.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/index.js.map +2 -2
- package/dist/kernel-worker.js +430 -234
- package/dist/kernel-worker.js.map +4 -4
- package/dist/node-process-worker.js +2 -1
- package/dist/node-process-worker.js.map +3 -3
- package/dist/node.js +216 -20
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +2 -1
- package/dist/process-worker.js.map +3 -3
- package/dist/types/cron/command.d.ts +4 -0
- package/dist/types/cron/crontab.d.ts +27 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/kernel/host.d.ts +1 -0
- package/dist/types/kernel/process.d.ts +4 -1
- package/dist/types/launcher.d.ts +2 -0
- package/dist/types/process/js/js-context.d.ts +13 -0
- package/package.json +1 -1
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Command } from '../commands.js';
|
|
2
|
+
export declare const CRONTAB_PATH = "/usr/bin/crontab";
|
|
3
|
+
export declare const CRONTAB_COMMAND: Command;
|
|
4
|
+
export declare const CRONTAB_SOURCE = "export default async function crontab(ctx) {\n const say = (fd, text) => ctx.write(fd, text).catch(() => undefined);\n const usage = async () => {\n await say(2, \"usage: crontab [-u user] { -l | -r | -e | file | - }\\n\");\n return 1;\n };\n const args = ctx.argv.slice(1);\n let user;\n let action;\n let file;\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n if (arg === \"-u\") {\n user = args[++i];\n if (user === undefined) return usage();\n } else if (arg === \"-l\" || arg === \"-r\" || arg === \"-e\") {\n if (action !== undefined) return usage();\n action = arg.slice(1);\n } else if (arg === \"-\" || !arg.startsWith(\"-\")) {\n if (file !== undefined) return usage();\n file = arg;\n } else return usage();\n }\n if ((action === undefined) === (file === undefined)) return usage();\n const call = (c) => ctx.crontab(user === undefined ? c : { ...c, user });\n const failed = async (answer) => {\n await say(2, answer.error + \"\\n\");\n return 1;\n };\n const decode = (bytes) => new TextDecoder().decode(bytes);\n if (action === \"l\") {\n const answer = await call({ action: \"list\" });\n if (answer.error !== undefined) return failed(answer);\n await say(1, answer.text);\n return 0;\n }\n if (action === \"r\") {\n const answer = await call({ action: \"remove\" });\n return answer.error !== undefined ? failed(answer) : 0;\n }\n if (action === \"e\") return edit();\n let text;\n try {\n if (file === \"-\") {\n const parts = [];\n for (;;) {\n const chunk = await ctx.read(0);\n if (chunk.length === 0) break;\n parts.push(decode(chunk));\n }\n text = parts.join(\"\");\n } else text = decode(await ctx.fs.readFile(ctx.resolve(file)));\n } catch (err) {\n await say(2, \"crontab: \" + file + \": \" + (err && err.code ? err.code : String(err)) + \"\\n\");\n return 1;\n }\n const answer = await call({ action: \"install\", text });\n return answer.error !== undefined ? failed(answer) : 0;\n\n async function edit() {\n const editor = ctx.env.VISUAL || ctx.env.EDITOR;\n if (!editor) {\n await say(2, \"crontab: set VISUAL or EDITOR to edit, or install a file with crontab <file>\\n\");\n return 1;\n }\n const current = await call({ action: \"list\" });\n const before = current.error === undefined ? current.text : \"\";\n if (current.error !== undefined && !current.error.startsWith(\"no crontab for \")) return failed(current);\n const tmp = \"/tmp/crontab.\" + ctx.pid + \".\" + crypto.randomUUID();\n try {\n const file = await ctx.open(tmp, { write: true, create: true, exclusive: true, mode: 0o600 });\n await file.write(0, new TextEncoder().encode(before));\n await file.close();\n } catch (err) {\n await say(2, \"crontab: \" + tmp + \": \" + (err && err.code ? err.code : String(err)) + \"\\n\");\n return 1;\n }\n const child = await ctx.spawn({ argv: [\"/bin/bash\", \"-c\", editor + ' \"$1\"', \"crontab\", tmp] });\n const ended = await ctx.wait(child.pid);\n if (ended.status !== 0) {\n await say(2, \"crontab: the editor exited with status \" + ended.status + \", crontab not changed\\n\");\n await ctx.fs.rm(tmp).catch(() => undefined);\n return 1;\n }\n const after = decode(await ctx.fs.readFile(tmp));\n if (after === before) {\n await say(2, \"crontab: no changes made to crontab\\n\");\n await ctx.fs.rm(tmp).catch(() => undefined);\n return 0;\n }\n const answer = await call({ action: \"install\", text: after });\n if (answer.error !== undefined) {\n await say(2, answer.error + \"\\ncrontab: your edit is kept in \" + tmp + \"\\n\");\n return 1;\n }\n await ctx.fs.rm(tmp).catch(() => undefined);\n return 0;\n }\n}\n";
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { KernelFs } from '../fs/types.js';
|
|
2
|
+
import type { Cred } from '../kernel/cred.js';
|
|
3
|
+
import type { Account } from '../users.js';
|
|
4
|
+
export declare const CRONTAB_MAX: number;
|
|
5
|
+
export interface CrontabCall {
|
|
6
|
+
op: 'proc-crontab';
|
|
7
|
+
action: 'list' | 'remove' | 'install';
|
|
8
|
+
user?: string;
|
|
9
|
+
text?: string;
|
|
10
|
+
}
|
|
11
|
+
export type CrontabResult = {
|
|
12
|
+
text: string;
|
|
13
|
+
} | {
|
|
14
|
+
error: string;
|
|
15
|
+
};
|
|
16
|
+
export interface CrontabsOptions {
|
|
17
|
+
fs: KernelFs;
|
|
18
|
+
owners: boolean;
|
|
19
|
+
lookup(user: string | number): Promise<Account | undefined>;
|
|
20
|
+
}
|
|
21
|
+
export declare function crontabCall(req: Partial<CrontabCall>): CrontabCall | undefined;
|
|
22
|
+
export declare class Crontabs {
|
|
23
|
+
private readonly o;
|
|
24
|
+
constructor(options: CrontabsOptions);
|
|
25
|
+
request(cred: Readonly<Cred>, call: CrontabCall): Promise<CrontabResult>;
|
|
26
|
+
private install;
|
|
27
|
+
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -34,7 +34,7 @@ export { serveHostfsPort } from './mount/hostfs.js';
|
|
|
34
34
|
export type { MountEntry, MountSpec } from './mount/mount-fs.js';
|
|
35
35
|
export type { ProcessMountPolicy, ProcessMountRequest } from './mount/syscall.js';
|
|
36
36
|
export type { JsChild, JsExited, JsSpawnOptions, JsStdio } from './process/js/js-children.js';
|
|
37
|
-
export type { JsFdStatus, JsFdType, JsFile, JsOpenOptions, JsProgramContext, JsSignal, JsSudoAnswer, } from './process/js/js-context.js';
|
|
37
|
+
export type { JsCrontabAnswer, JsCrontabCall, JsFdStatus, JsFdType, JsFile, JsOpenOptions, JsProgramContext, JsSignal, JsSudoAnswer, } from './process/js/js-context.js';
|
|
38
38
|
export type { JsStatFs } from './process/js/js-io.js';
|
|
39
39
|
export type { JsAddress, JsConnection, JsConnectOptions, JsListener, JsListenOptions, JsNet, } from './process/js/js-net.js';
|
|
40
40
|
export type { JsRunOptions, JsRunResult, JsRunStdio } from './process/js/js-run.js';
|
|
@@ -67,6 +67,7 @@ export interface SpawnWasmOptions {
|
|
|
67
67
|
writesBack?: (pid: number) => boolean;
|
|
68
68
|
processes?: () => ProcessListing;
|
|
69
69
|
sudo?: WasmProcessOptions['sudo'];
|
|
70
|
+
crontab?: WasmProcessOptions['crontab'];
|
|
70
71
|
openFiles?: Set<VfsNodes>;
|
|
71
72
|
nodes?: VfsNodes;
|
|
72
73
|
statfs?: (path: string) => Promise<{
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type CrontabCall, type CrontabResult } from '../cron/crontab.js';
|
|
1
2
|
import { type Created, type Dac } from '../fs/dac.js';
|
|
2
3
|
import type { KernelFs } from '../fs/types.js';
|
|
3
4
|
import type { MountCall } from '../mount/syscall.js';
|
|
@@ -255,7 +256,7 @@ export type WasmSyscall = {
|
|
|
255
256
|
op: 'proc-captured';
|
|
256
257
|
pid: number;
|
|
257
258
|
slot: number;
|
|
258
|
-
} | SudoCall | RunRequest | {
|
|
259
|
+
} | SudoCall | CrontabCall | RunRequest | {
|
|
259
260
|
op: 'proc-exit';
|
|
260
261
|
status: number;
|
|
261
262
|
} | {
|
|
@@ -368,6 +369,7 @@ export interface WasmProcessOptions {
|
|
|
368
369
|
writesBack?: (pid: number) => boolean;
|
|
369
370
|
processes?: () => ProcessListing;
|
|
370
371
|
sudo?: (call: SudoCall, signal: AbortSignal) => Promise<SudoResult>;
|
|
372
|
+
crontab?: (call: CrontabCall) => Promise<CrontabResult>;
|
|
371
373
|
openFiles?: Set<VfsNodes>;
|
|
372
374
|
nodes?: VfsNodes;
|
|
373
375
|
mounts?: () => MountLine[];
|
|
@@ -517,6 +519,7 @@ export declare class WasmProcess {
|
|
|
517
519
|
private socketSyscall;
|
|
518
520
|
private tty;
|
|
519
521
|
private procSyscall;
|
|
522
|
+
private crontab;
|
|
520
523
|
private signalSyscall;
|
|
521
524
|
private reapsChildren;
|
|
522
525
|
private sudo;
|
package/dist/types/launcher.d.ts
CHANGED
|
@@ -226,6 +226,7 @@ export declare class Launcher {
|
|
|
226
226
|
readonly boot: number;
|
|
227
227
|
readonly bootId: `${string}-${string}-${string}-${string}-${string}`;
|
|
228
228
|
readonly cron: CronService;
|
|
229
|
+
private crontabs;
|
|
229
230
|
private terminals;
|
|
230
231
|
constructor(options: LauncherOptions);
|
|
231
232
|
private cronService;
|
|
@@ -318,6 +319,7 @@ export declare class Launcher {
|
|
|
318
319
|
private timesOf;
|
|
319
320
|
list(viewer?: Readonly<Cred>): ProcessInfo[];
|
|
320
321
|
private threadsOf;
|
|
322
|
+
private crontab;
|
|
321
323
|
private sudo;
|
|
322
324
|
private spawner;
|
|
323
325
|
private childGroup;
|
|
@@ -76,6 +76,7 @@ export interface JsProgramContext {
|
|
|
76
76
|
wait(pid: number, options?: JsWaitOptions): Promise<JsExited>;
|
|
77
77
|
kill(pid: number, signal?: JsSignal): Promise<void>;
|
|
78
78
|
sudo(args: readonly string[]): Promise<JsSudoAnswer>;
|
|
79
|
+
crontab(call: JsCrontabCall): Promise<JsCrontabAnswer>;
|
|
79
80
|
umask(mask?: number): Promise<number>;
|
|
80
81
|
net: JsNet;
|
|
81
82
|
websocket(url: string | URL, options?: JsWebSocketOptions): Promise<JsWebSocket>;
|
|
@@ -85,6 +86,18 @@ export interface JsProgramContext {
|
|
|
85
86
|
onUncaught(listener: JsStrayListener): () => void;
|
|
86
87
|
onUnhandledRejection(listener: JsStrayListener): () => void;
|
|
87
88
|
}
|
|
89
|
+
export interface JsCrontabCall {
|
|
90
|
+
action: 'list' | 'remove' | 'install';
|
|
91
|
+
user?: string;
|
|
92
|
+
text?: string;
|
|
93
|
+
}
|
|
94
|
+
export type JsCrontabAnswer = {
|
|
95
|
+
text: string;
|
|
96
|
+
error?: undefined;
|
|
97
|
+
} | {
|
|
98
|
+
error: string;
|
|
99
|
+
text?: undefined;
|
|
100
|
+
};
|
|
88
101
|
export type JsSudoAnswer = {
|
|
89
102
|
error: string;
|
|
90
103
|
errno: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-ecoverse/slicc-kernel",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.109.0",
|
|
4
4
|
"description": "SLICC's wasm-realm kernel: run Emscripten programs in the browser against OPFS, with fork, spawn, pipes and waitpid",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|