@yhyzgn/tikeo 0.1.911

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,81 @@
1
+ import { mkdtempSync, mkdirSync, rmSync } from "node:fs";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+ let sequence = 0;
5
+ export class ScriptTaskRuntimeDirs {
6
+ root;
7
+ home;
8
+ config;
9
+ cache;
10
+ data;
11
+ modules;
12
+ dotnetHome;
13
+ powerShellCache;
14
+ tmp;
15
+ denoDir;
16
+ constructor(root) {
17
+ this.root = root;
18
+ this.home = join(root, "home");
19
+ this.config = join(root, "config");
20
+ this.cache = join(root, "cache");
21
+ this.data = join(root, "data");
22
+ this.modules = join(this.data, "powershell", "Modules");
23
+ this.dotnetHome = join(root, "dotnet");
24
+ this.powerShellCache = join(this.cache, "powershell");
25
+ this.tmp = join(root, "tmp");
26
+ this.denoDir = join(this.cache, "deno");
27
+ }
28
+ static create(prefix) {
29
+ const root = mkdtempSync(join(tmpdir(), `${prefix.trim()}-`));
30
+ const dirs = new ScriptTaskRuntimeDirs(root);
31
+ for (const dir of dirs.requiredDirectories())
32
+ mkdirSync(dir, { recursive: true, mode: 0o700 });
33
+ return dirs;
34
+ }
35
+ requiredDirectories() { return [this.root, this.home, this.config, this.cache, this.data, this.modules, this.dotnetHome, this.powerShellCache, this.tmp, this.denoDir]; }
36
+ writablePaths() { return this.requiredDirectories(); }
37
+ workingDir() { return this.home; }
38
+ scriptFile(extension) { return join(this.home, `script-${Date.now()}-${sequence++}.${extension}`); }
39
+ baseEnvironment(extraPath = []) {
40
+ const pathParts = dedupe([...extraPath.filter(Boolean), ...(process.env.PATH ?? "").split(process.platform === "win32" ? ";" : ":")]);
41
+ return {
42
+ HOME: this.home,
43
+ XDG_CONFIG_HOME: this.config,
44
+ XDG_CACHE_HOME: this.cache,
45
+ XDG_DATA_HOME: this.data,
46
+ TMPDIR: this.tmp,
47
+ TERM: "dumb",
48
+ NO_COLOR: "1",
49
+ PATH: pathParts.join(process.platform === "win32" ? ";" : ":"),
50
+ };
51
+ }
52
+ srtEnvironment(extraPath = []) {
53
+ return { ...this.baseEnvironment(extraPath), CLAUDE_CODE_TMPDIR: this.tmp, CLAUDE_TMPDIR: this.tmp };
54
+ }
55
+ powerShellEnvironment(env) {
56
+ return { ...env, PSModulePath: this.modules, DOTNET_CLI_HOME: this.dotnetHome, POWERSHELL_TELEMETRY_OPTOUT: "1", POWERSHELL_UPDATECHECK: "Off" };
57
+ }
58
+ denoEnvironment() {
59
+ return { ...this.baseEnvironment(), DENO_DIR: this.denoDir };
60
+ }
61
+ cleanup() { rmSync(this.root, { recursive: true, force: true }); }
62
+ }
63
+ export function appendAllowedUnmanagedEnv(env, allowed) {
64
+ const managed = new Set(["HOME", "XDG_CONFIG_HOME", "XDG_CACHE_HOME", "XDG_DATA_HOME", "TMPDIR", "TERM", "NO_COLOR", "CLAUDE_CODE_TMPDIR", "CLAUDE_TMPDIR", "PSModulePath", "DOTNET_CLI_HOME", "POWERSHELL_TELEMETRY_OPTOUT", "POWERSHELL_UPDATECHECK", "DENO_DIR"]);
65
+ for (const name of allowed) {
66
+ const key = name.trim();
67
+ if (key && !managed.has(key) && process.env[key] !== undefined)
68
+ env[key] = process.env[key];
69
+ }
70
+ return env;
71
+ }
72
+ function dedupe(values) {
73
+ const seen = new Set();
74
+ const out = [];
75
+ for (const value of values)
76
+ if (value && !seen.has(value)) {
77
+ seen.add(value);
78
+ out.push(value);
79
+ }
80
+ return out;
81
+ }
@@ -0,0 +1,22 @@
1
+ export declare class SandboxToolResolver {
2
+ stateDir: string;
3
+ autoInstall: boolean;
4
+ installTimeoutMs: number;
5
+ constructor(stateDir?: string, autoInstall?: boolean, installTimeoutMs?: number);
6
+ resolveSrt(): [string, boolean];
7
+ resolveRipgrep(): [string, boolean];
8
+ resolveDeno(): [string, boolean];
9
+ resolveRhai(): [string, boolean];
10
+ resolvePowerShell(): [string, boolean];
11
+ resolveNode(): [string, boolean];
12
+ resolveNpm(): [string, boolean];
13
+ resolveInterpreter(binary: string): [string, boolean];
14
+ private resolveTool;
15
+ private installDir;
16
+ private managedBin;
17
+ private runInstaller;
18
+ private installPowerShell;
19
+ private commandWorks;
20
+ private toolWorks;
21
+ private rhaiWorks;
22
+ }
@@ -0,0 +1,133 @@
1
+ import { existsSync, mkdirSync, rmSync, chmodSync, symlinkSync, copyFileSync, writeFileSync, mkdtempSync } from "node:fs";
2
+ import { homedir, platform, arch, tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { spawnSync } from "node:child_process";
5
+ export class SandboxToolResolver {
6
+ stateDir;
7
+ autoInstall;
8
+ installTimeoutMs;
9
+ constructor(stateDir = "", autoInstall = true, installTimeoutMs = 120_000) {
10
+ this.stateDir = stateDir;
11
+ this.autoInstall = autoInstall;
12
+ this.installTimeoutMs = installTimeoutMs;
13
+ }
14
+ resolveSrt() {
15
+ return this.resolveTool("srt", "srt", (dir) => this.runInstaller(this.managedBin(dir), "npm", ["install", "-g", "--prefix", dir, process.env.TIKEO_SRT_NPM_PACKAGE || "@anthropic-ai/sandbox-runtime"]));
16
+ }
17
+ resolveRipgrep() { return this.resolveTool("rg", "rg", (dir) => this.runInstaller(this.managedBin(dir), "cargo", ["install", "--root", dir, "ripgrep"])); }
18
+ resolveDeno() {
19
+ return this.resolveTool("deno", "deno", (dir) => {
20
+ if (process.platform === "win32")
21
+ this.runInstaller(this.managedBin(dir), "powershell", ["-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", "irm https://deno.land/install.ps1 | iex"]);
22
+ else
23
+ this.runInstaller(this.managedBin(dir), "sh", ["-c", `curl -fsSL https://deno.land/install.sh | DENO_INSTALL='${dir}' sh`]);
24
+ });
25
+ }
26
+ resolveRhai() { return this.resolveTool("rhai-run", "rhai-run", (dir) => this.runInstaller(this.managedBin(dir), "cargo", ["install", "--root", dir, "rhai", "--bins", "--features", "bin-features"])); }
27
+ resolvePowerShell() { return this.resolveTool("pwsh", "pwsh", (dir) => this.installPowerShell(dir)); }
28
+ resolveNode() { return this.resolveInterpreter("node"); }
29
+ resolveNpm() { return this.resolveInterpreter("npm"); }
30
+ resolveInterpreter(binary) {
31
+ const path = findOnPath(binary);
32
+ return path && this.commandWorks(path, ["--version"]) ? [path, true] : ["", false];
33
+ }
34
+ resolveTool(key, binary, installer) {
35
+ const found = findOnPath(binary);
36
+ if (found && this.toolWorks(binary, found))
37
+ return [found, true];
38
+ const dir = this.installDir(key);
39
+ const local = join(this.managedBin(dir), executableName(binary));
40
+ if (this.toolWorks(binary, local))
41
+ return [local, true];
42
+ if (!this.autoInstall)
43
+ return [local, false];
44
+ try {
45
+ installer(dir);
46
+ }
47
+ catch {
48
+ return [local, false];
49
+ }
50
+ return [local, this.toolWorks(binary, local)];
51
+ }
52
+ installDir(key) { return join(this.stateDir.trim() || join(homedir(), ".tikeo"), "sandbox-tools", key); }
53
+ managedBin(dir) { return join(dir, "bin"); }
54
+ runInstaller(managedBin, command, args) {
55
+ mkdirSync(managedBin, { recursive: true });
56
+ const env = { ...process.env, PATH: dedupe([managedBin, ...(process.env.PATH ?? "").split(process.platform === "win32" ? ";" : ":")]).join(process.platform === "win32" ? ";" : ":") };
57
+ const result = spawnSync(command, args, { stdio: "inherit", env, timeout: this.installTimeoutMs });
58
+ if (result.status !== 0)
59
+ throw new Error(`installer failed: ${command}`);
60
+ }
61
+ installPowerShell(dir) {
62
+ if (process.platform === "win32") {
63
+ this.runInstaller(this.managedBin(dir), "winget", ["install", "-e", "--id", "Microsoft.PowerShell"]);
64
+ return;
65
+ }
66
+ const key = powerShellArchivePlatform();
67
+ if (!key)
68
+ throw new Error(`PowerShell auto-install does not support ${platform()}/${arch()}`);
69
+ const version = process.env.TIKEO_POWERSHELL_VERSION || "7.5.4";
70
+ const name = `powershell-${version}-${key}.tar.gz`;
71
+ const url = process.env.TIKEO_POWERSHELL_DOWNLOAD_URL || `https://github.com/PowerShell/PowerShell/releases/download/v${version}/${name}`;
72
+ const bin = this.managedBin(dir);
73
+ const archivePath = join(dir, name);
74
+ const extract = join(dir, `powershell-${version}`);
75
+ mkdirSync(bin, { recursive: true });
76
+ mkdirSync(extract, { recursive: true });
77
+ this.runInstaller(bin, "curl", ["-fsSL", url, "-o", archivePath]);
78
+ this.runInstaller(bin, "tar", ["-xzf", archivePath, "-C", extract]);
79
+ rmSync(archivePath, { force: true });
80
+ const pwsh = join(extract, "pwsh");
81
+ chmodSync(pwsh, 0o755);
82
+ const link = join(bin, "pwsh");
83
+ rmSync(link, { force: true });
84
+ try {
85
+ symlinkSync(pwsh, link);
86
+ }
87
+ catch {
88
+ copyFileSync(pwsh, link);
89
+ chmodSync(link, 0o755);
90
+ }
91
+ }
92
+ commandWorks(command, args) {
93
+ if ((command.includes("/") || command.includes("\\")) && !existsSync(command))
94
+ return false;
95
+ const result = spawnSync(command, args, { stdio: "ignore", timeout: 2_000 });
96
+ return result.status === 0;
97
+ }
98
+ toolWorks(binary, command) {
99
+ if (binary === "srt")
100
+ return this.commandWorks(command, ["--version"]) || this.commandWorks(command, ["--help"]);
101
+ if (binary === "rhai-run")
102
+ return this.rhaiWorks(command);
103
+ return this.commandWorks(command, ["--version"]);
104
+ }
105
+ rhaiWorks(command) {
106
+ if ((command.includes("/") || command.includes("\\")) && !existsSync(command))
107
+ return false;
108
+ const dir = mkdtempSync(join(tmpdir(), "tikeo-rhai-probe-"));
109
+ const script = join(dir, "probe.rhai");
110
+ try {
111
+ writeFileSync(script, 'print("tikeo-rhai-probe");\n');
112
+ return this.commandWorks(command, [script]);
113
+ }
114
+ finally {
115
+ rmSync(dir, { recursive: true, force: true });
116
+ }
117
+ }
118
+ }
119
+ function executableName(binary) { return process.platform === "win32" ? `${binary}.exe` : binary; }
120
+ function findOnPath(binary) {
121
+ const paths = (process.env.PATH ?? "").split(process.platform === "win32" ? ";" : ":");
122
+ for (const p of paths) {
123
+ const full = join(p, executableName(binary));
124
+ if (existsSync(full))
125
+ return full;
126
+ }
127
+ return undefined;
128
+ }
129
+ function powerShellArchivePlatform() {
130
+ const key = `${platform()}/${arch()}`;
131
+ return { "linux/x64": "linux-x64", "linux/arm64": "linux-arm64", "darwin/x64": "osx-x64", "darwin/arm64": "osx-arm64" }[key] ?? "";
132
+ }
133
+ function dedupe(values) { return [...new Set(values.filter(Boolean))]; }
package/dist/task.d.ts ADDED
@@ -0,0 +1,18 @@
1
+ export type TaskLogSink = (level: string, message: string) => void;
2
+ export declare class TaskContext {
3
+ instanceId: string;
4
+ jobId: string;
5
+ processorName: string;
6
+ payload: Uint8Array;
7
+ log?: TaskLogSink | undefined;
8
+ constructor(instanceId: string, jobId: string, processorName: string, payload?: Uint8Array, log?: TaskLogSink | undefined);
9
+ logInfo(message: string): void;
10
+ logError(message: string): void;
11
+ }
12
+ export interface TaskOutcome {
13
+ success: boolean;
14
+ message: string;
15
+ }
16
+ export type TaskProcessor = (task: TaskContext) => Promise<TaskOutcome> | TaskOutcome;
17
+ export declare function succeeded(message?: string): TaskOutcome;
18
+ export declare function failed(message: string): TaskOutcome;
package/dist/task.js ADDED
@@ -0,0 +1,18 @@
1
+ export class TaskContext {
2
+ instanceId;
3
+ jobId;
4
+ processorName;
5
+ payload;
6
+ log;
7
+ constructor(instanceId, jobId, processorName, payload = new Uint8Array(), log) {
8
+ this.instanceId = instanceId;
9
+ this.jobId = jobId;
10
+ this.processorName = processorName;
11
+ this.payload = payload;
12
+ this.log = log;
13
+ }
14
+ logInfo(message) { this.log?.("info", message); }
15
+ logError(message) { this.log?.("error", message); }
16
+ }
17
+ export function succeeded(message = "") { return { success: true, message }; }
18
+ export function failed(message) { return { success: false, message }; }
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@yhyzgn/tikeo",
3
+ "version": "0.1.911",
4
+ "description": "Node.js Worker SDK for tikeo",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "bun": "./src/index.ts",
12
+ "import": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "src/proto/worker.proto",
18
+ "README.md"
19
+ ],
20
+ "scripts": {
21
+ "build": "tsc -p tsconfig.json && mkdir -p dist/proto && cp src/proto/worker.proto dist/proto/worker.proto",
22
+ "test": "bun test"
23
+ },
24
+ "dependencies": {
25
+ "@grpc/grpc-js": "latest",
26
+ "@grpc/proto-loader": "latest"
27
+ },
28
+ "devDependencies": {
29
+ "@types/bun": "latest",
30
+ "@types/node": "latest",
31
+ "typescript": "latest"
32
+ },
33
+ "license": "Apache-2.0",
34
+ "author": "tikeo contributors",
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "git+https://github.com/yhyzgn/tikeo.git",
38
+ "directory": "sdks/nodejs/tikeo"
39
+ },
40
+ "homepage": "https://github.com/yhyzgn/tikeo#readme",
41
+ "bugs": {
42
+ "url": "https://github.com/yhyzgn/tikeo/issues"
43
+ }
44
+ }
@@ -0,0 +1,188 @@
1
+ syntax = "proto3";
2
+
3
+ package tikeo.worker.v1;
4
+
5
+ option go_package = "github.com/yhyzgn/tikeo/sdks/go/tikeo/internal/workerpb;workerpb";
6
+
7
+ service WorkerTunnelService {
8
+ rpc OpenTunnel(stream WorkerMessage) returns (stream ServerMessage);
9
+ rpc SubscribeTaskLogs(SubscribeTaskLogsRequest) returns (stream TaskLog);
10
+ }
11
+
12
+ message WorkerMessage {
13
+ oneof kind {
14
+ RegisterWorker register = 1;
15
+ Heartbeat heartbeat = 2;
16
+ TaskResult task_result = 3;
17
+ TaskLog task_log = 4;
18
+ UnregisterWorker unregister = 5;
19
+ TaskCheckpoint task_checkpoint = 6;
20
+ }
21
+ }
22
+
23
+ message ServerMessage {
24
+ oneof kind {
25
+ WorkerRegistered registered = 1;
26
+ Ping ping = 2;
27
+ DispatchTask dispatch_task = 3;
28
+ }
29
+ }
30
+
31
+ message RegisterWorker {
32
+ // Optional client-side stable instance hint. The tikeo still assigns the authoritative worker_id.
33
+ string client_instance_id = 1;
34
+ string app = 2;
35
+ string namespace = 3;
36
+ string cluster = 4;
37
+ string region = 5;
38
+ // Legacy free-form labels/capabilities. New routing must use structured_capabilities.
39
+ repeated string capabilities = 6;
40
+ map<string, string> labels = 7;
41
+ WorkerCapabilities structured_capabilities = 8;
42
+ WorkerClusterElection election = 9;
43
+ }
44
+
45
+ message WorkerCapabilities {
46
+ // Human/operator tags such as java or spring-boot. Not used for dispatch routing.
47
+ repeated string tags = 1;
48
+ repeated SdkProcessorCapability sdk_processors = 2;
49
+ repeated ScriptRunnerCapability script_runners = 3;
50
+ repeated PluginProcessorCapability plugin_processors = 4;
51
+ }
52
+
53
+ message SdkProcessorCapability {
54
+ string name = 1;
55
+ }
56
+
57
+ message ScriptRunnerCapability {
58
+ string language = 1;
59
+ string sandbox_backend = 2;
60
+ }
61
+
62
+ message PluginProcessorCapability {
63
+ string type = 1;
64
+ repeated string processor_names = 2;
65
+ }
66
+
67
+ message WorkerClusterElection {
68
+ bool enabled = 1;
69
+ // Stable election domain. Empty means namespace/app/cluster/region.
70
+ string domain = 2;
71
+ // Optional deterministic priority. Lower values win ties after health checks.
72
+ uint32 priority = 3;
73
+ }
74
+
75
+ message Heartbeat {
76
+ string worker_id = 1;
77
+ uint64 sequence = 2;
78
+ uint64 generation = 3;
79
+ string fencing_token = 4;
80
+ }
81
+
82
+ message WorkerRegistered {
83
+ string worker_id = 1;
84
+ uint64 lease_seconds = 2;
85
+ uint64 generation = 3;
86
+ string fencing_token = 4;
87
+ }
88
+
89
+ message UnregisterWorker {
90
+ string worker_id = 1;
91
+ uint64 generation = 2;
92
+ string fencing_token = 3;
93
+ }
94
+
95
+ message Ping {
96
+ uint64 sequence = 1;
97
+ }
98
+
99
+ message DispatchTask {
100
+ string instance_id = 1;
101
+ string job_id = 2;
102
+ bytes payload = 3;
103
+ // Explicit processor key used by SDK adapters. Defaults to job_id for backwards compatibility.
104
+ string processor_name = 4;
105
+ // Optional dynamic processor metadata. Empty for normal SDK processors.
106
+ TaskProcessorBinding processor_binding = 5;
107
+ // Server-issued opaque assignment authority bound to worker session generation/fencing.
108
+ string assignment_token = 6;
109
+ }
110
+
111
+ message TaskProcessorBinding {
112
+ oneof kind {
113
+ WasmProcessorBinding wasm = 1;
114
+ ScriptProcessorBinding script = 2;
115
+ }
116
+ }
117
+
118
+ message ScriptProcessorBinding {
119
+ string script_id = 1;
120
+ string version = 2;
121
+ string language = 3;
122
+ bytes content = 4;
123
+ string version_id = 5;
124
+ uint64 version_number = 6;
125
+ string content_sha256 = 7;
126
+ uint64 timeout_ms = 8;
127
+ uint64 max_memory_bytes = 9;
128
+ uint64 max_output_bytes = 10;
129
+ bool allow_network = 11;
130
+ repeated string allowed_env_vars = 12;
131
+ repeated string read_only_paths = 13;
132
+ repeated string writable_paths = 14;
133
+ repeated string secret_refs = 15;
134
+ repeated string allowed_network_hosts = 16;
135
+ string sandbox_backend = 17;
136
+ }
137
+
138
+ message WasmProcessorBinding {
139
+ string script_id = 1;
140
+ string version = 2;
141
+ bytes module = 3;
142
+ string runtime = 4;
143
+ string entrypoint = 5;
144
+ uint64 timeout_ms = 6;
145
+ uint64 max_memory_bytes = 7;
146
+ uint64 fuel = 8;
147
+ bool allow_network = 9;
148
+ repeated string allowed_env_vars = 10;
149
+ // Immutable script version snapshot identifier when available.
150
+ string version_id = 11;
151
+ // Monotonic script version snapshot number when available.
152
+ uint64 version_number = 12;
153
+ // Lowercase hex SHA-256 digest of module bytes. Workers must verify when present.
154
+ string module_sha256 = 13;
155
+ // Reserved signature hook for future PKI-backed module verification.
156
+ string module_signature = 14;
157
+ }
158
+
159
+ message TaskResult {
160
+ string worker_id = 1;
161
+ string instance_id = 2;
162
+ bool success = 3;
163
+ string message = 4;
164
+ string assignment_token = 5;
165
+ }
166
+
167
+ message TaskLog {
168
+ string worker_id = 1;
169
+ string instance_id = 2;
170
+ string level = 3;
171
+ string message = 4;
172
+ int64 sequence = 5;
173
+ string assignment_token = 6;
174
+ }
175
+
176
+ message TaskCheckpoint {
177
+ string worker_id = 1;
178
+ string instance_id = 2;
179
+ string checkpoint_json = 3;
180
+ int64 sequence = 4;
181
+ string assignment_token = 5;
182
+ }
183
+
184
+ message SubscribeTaskLogsRequest {
185
+ string instance_id = 1;
186
+ int64 after_sequence = 2;
187
+ bool replay_existing = 3;
188
+ }