@workplane/adapter-sdk 0.3.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,44 @@
1
+ interface ExecResult {
2
+ exitCode: number;
3
+ stdout: string;
4
+ stderr: string;
5
+ }
6
+ interface ExecOptions {
7
+ cwd?: string;
8
+ env?: Record<string, string>;
9
+ signal?: AbortSignal;
10
+ }
11
+ interface ArtifactInput {
12
+ type: string;
13
+ name: string;
14
+ path: string;
15
+ metadata?: Record<string, unknown>;
16
+ }
17
+ interface WorkContext {
18
+ runId: string;
19
+ taskId: string;
20
+ workspacePath: string;
21
+ log: (stream: "stdout" | "stderr" | "system", message: string, stepName?: string) => Promise<void>;
22
+ exec: (command: string, args?: string[], options?: ExecOptions) => Promise<ExecResult>;
23
+ ensureWorkspace: (...segments: string[]) => Promise<string>;
24
+ emitArtifact: (input: ArtifactInput) => Promise<void>;
25
+ envAllowlist?: string[];
26
+ writeStdin?: (data: string) => void;
27
+ ptyResize?: (rows: number, cols: number) => void;
28
+ }
29
+ interface WorkAdapter<TPayload = Record<string, unknown>> {
30
+ name: string;
31
+ kind: string;
32
+ interactive?: boolean;
33
+ terminalMode?: "stdio" | "pty";
34
+ run: (context: WorkContext, payload: TPayload) => Promise<void>;
35
+ }
36
+ declare function createExec(context: WorkContext): WorkContext["exec"];
37
+ declare function createCancellableExec(context: WorkContext): {
38
+ exec: WorkContext["exec"];
39
+ kill: (signal?: NodeJS.Signals) => void;
40
+ writeStdin: (data: string) => void;
41
+ };
42
+ declare function ensureWorkspacePath(workspacePath: string, ...segments: string[]): Promise<string>;
43
+
44
+ export { type ArtifactInput, type ExecOptions, type ExecResult, type WorkAdapter, type WorkContext, createCancellableExec, createExec, ensureWorkspacePath };
package/dist/index.js ADDED
@@ -0,0 +1,143 @@
1
+ // src/index.ts
2
+ import { spawn } from "child_process";
3
+ import { mkdir } from "fs/promises";
4
+ import { join } from "path";
5
+ function pickEnv(allowlist) {
6
+ if (!allowlist || allowlist.length === 0) {
7
+ return { ...process.env };
8
+ }
9
+ const picked = {};
10
+ for (const key of allowlist) {
11
+ const value = process.env[key];
12
+ if (value !== void 0) {
13
+ picked[key] = value;
14
+ }
15
+ }
16
+ picked.PATH = process.env.PATH ?? "";
17
+ picked.HOME = process.env.HOME ?? "";
18
+ return picked;
19
+ }
20
+ function createExec(context) {
21
+ return async (command, args = [], options = {}) => new Promise((resolve) => {
22
+ let childError;
23
+ const child = spawn(command, args, {
24
+ cwd: options.cwd ?? context.workspacePath,
25
+ env: {
26
+ ...pickEnv(context.envAllowlist),
27
+ ...options.env ?? {}
28
+ },
29
+ signal: options.signal
30
+ });
31
+ let stdout = "";
32
+ let stderr = "";
33
+ child.stdout.on("data", (chunk) => {
34
+ const text = chunk.toString();
35
+ stdout += text;
36
+ void context.log("stdout", text);
37
+ });
38
+ child.stderr.on("data", (chunk) => {
39
+ const text = chunk.toString();
40
+ stderr += text;
41
+ void context.log("stderr", text);
42
+ });
43
+ child.on("error", (error) => {
44
+ childError = error;
45
+ });
46
+ child.on("close", (exitCode, signal) => {
47
+ if (signal === "SIGTERM" || signal === "SIGKILL") {
48
+ resolve({
49
+ exitCode: exitCode ?? 1,
50
+ stdout,
51
+ stderr: `${stderr}
52
+ process terminated (${signal})`.trim()
53
+ });
54
+ return;
55
+ }
56
+ resolve({
57
+ exitCode: exitCode ?? 1,
58
+ stdout,
59
+ stderr: childError ? `${stderr}
60
+ ${childError.message}`.trim() : stderr
61
+ });
62
+ });
63
+ });
64
+ }
65
+ function createCancellableExec(context) {
66
+ let activeChild;
67
+ const exec = async (command, args = [], options = {}) => new Promise((resolve) => {
68
+ let childError;
69
+ const child = spawn(command, args, {
70
+ cwd: options.cwd ?? context.workspacePath,
71
+ env: {
72
+ ...pickEnv(context.envAllowlist),
73
+ ...options.env ?? {}
74
+ },
75
+ signal: options.signal
76
+ });
77
+ activeChild = child;
78
+ let stdout = "";
79
+ let stderr = "";
80
+ child.stdout.on("data", (chunk) => {
81
+ const text = chunk.toString();
82
+ stdout += text;
83
+ void context.log("stdout", text);
84
+ });
85
+ child.stderr.on("data", (chunk) => {
86
+ const text = chunk.toString();
87
+ stderr += text;
88
+ void context.log("stderr", text);
89
+ });
90
+ child.on("error", (error) => {
91
+ childError = error;
92
+ });
93
+ child.on("close", (exitCode, signal) => {
94
+ if (activeChild === child) {
95
+ activeChild = void 0;
96
+ }
97
+ if (signal === "SIGTERM" || signal === "SIGKILL") {
98
+ resolve({
99
+ exitCode: exitCode ?? 1,
100
+ stdout,
101
+ stderr: `${stderr}
102
+ process terminated (${signal})`.trim()
103
+ });
104
+ return;
105
+ }
106
+ resolve({
107
+ exitCode: exitCode ?? 1,
108
+ stdout,
109
+ stderr: childError ? `${stderr}
110
+ ${childError.message}`.trim() : stderr
111
+ });
112
+ });
113
+ });
114
+ const kill = (signal = "SIGTERM") => {
115
+ if (!activeChild || activeChild.killed) return;
116
+ activeChild.kill(signal);
117
+ if (signal === "SIGTERM") {
118
+ const escalation = setTimeout(() => {
119
+ if (activeChild && !activeChild.killed) {
120
+ activeChild.kill("SIGKILL");
121
+ }
122
+ }, 5e3);
123
+ escalation.unref();
124
+ }
125
+ };
126
+ const writeStdin = (data) => {
127
+ if (activeChild && !activeChild.killed && activeChild.stdin && !activeChild.stdin.destroyed) {
128
+ activeChild.stdin.write(data);
129
+ }
130
+ };
131
+ return { exec, kill, writeStdin };
132
+ }
133
+ async function ensureWorkspacePath(workspacePath, ...segments) {
134
+ const fullPath = join(workspacePath, ...segments);
135
+ await mkdir(fullPath, { recursive: true });
136
+ return fullPath;
137
+ }
138
+ export {
139
+ createCancellableExec,
140
+ createExec,
141
+ ensureWorkspacePath
142
+ };
143
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { spawn, type ChildProcess } from \"node:child_process\";\nimport { mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nexport interface ExecResult {\n exitCode: number;\n stdout: string;\n stderr: string;\n}\n\nexport interface ExecOptions {\n cwd?: string;\n env?: Record<string, string>;\n signal?: AbortSignal;\n}\n\nexport interface ArtifactInput {\n type: string;\n name: string;\n path: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface WorkContext {\n runId: string;\n taskId: string;\n workspacePath: string;\n log: (stream: \"stdout\" | \"stderr\" | \"system\", message: string, stepName?: string) => Promise<void>;\n exec: (command: string, args?: string[], options?: ExecOptions) => Promise<ExecResult>;\n ensureWorkspace: (...segments: string[]) => Promise<string>;\n emitArtifact: (input: ArtifactInput) => Promise<void>;\n envAllowlist?: string[];\n writeStdin?: (data: string) => void;\n ptyResize?: (rows: number, cols: number) => void;\n}\n\nexport interface WorkAdapter<TPayload = Record<string, unknown>> {\n name: string;\n kind: string;\n interactive?: boolean;\n terminalMode?: \"stdio\" | \"pty\";\n run: (context: WorkContext, payload: TPayload) => Promise<void>;\n}\n\nfunction pickEnv(allowlist: string[] | undefined): Record<string, string> {\n if (!allowlist || allowlist.length === 0) {\n return { ...process.env } as Record<string, string>;\n }\n const picked: Record<string, string> = {};\n for (const key of allowlist) {\n const value = process.env[key];\n if (value !== undefined) {\n picked[key] = value;\n }\n }\n picked.PATH = process.env.PATH ?? \"\";\n picked.HOME = process.env.HOME ?? \"\";\n return picked;\n}\n\nexport function createExec(context: WorkContext): WorkContext[\"exec\"] {\n return async (command: string, args: string[] = [], options: ExecOptions = {}) =>\n new Promise<ExecResult>((resolve) => {\n let childError: Error | undefined;\n const child = spawn(command, args, {\n cwd: options.cwd ?? context.workspacePath,\n env: {\n ...pickEnv(context.envAllowlist),\n ...(options.env ?? {}),\n },\n signal: options.signal,\n });\n\n let stdout = \"\";\n let stderr = \"\";\n\n child.stdout.on(\"data\", (chunk) => {\n const text = chunk.toString();\n stdout += text;\n void context.log(\"stdout\", text);\n });\n\n child.stderr.on(\"data\", (chunk) => {\n const text = chunk.toString();\n stderr += text;\n void context.log(\"stderr\", text);\n });\n\n child.on(\"error\", (error) => {\n childError = error;\n });\n\n child.on(\"close\", (exitCode, signal) => {\n if (signal === \"SIGTERM\" || signal === \"SIGKILL\") {\n resolve({\n exitCode: exitCode ?? 1,\n stdout,\n stderr: `${stderr}\\nprocess terminated (${signal})`.trim(),\n });\n return;\n }\n resolve({\n exitCode: exitCode ?? 1,\n stdout,\n stderr: childError ? `${stderr}\\n${childError.message}`.trim() : stderr,\n });\n });\n });\n}\n\nexport function createCancellableExec(context: WorkContext): {\n exec: WorkContext[\"exec\"];\n kill: (signal?: NodeJS.Signals) => void;\n writeStdin: (data: string) => void;\n} {\n let activeChild: ChildProcess | undefined;\n\n const exec: WorkContext[\"exec\"] = async (command, args = [], options = {}) =>\n new Promise<ExecResult>((resolve) => {\n let childError: Error | undefined;\n const child = spawn(command, args, {\n cwd: options.cwd ?? context.workspacePath,\n env: {\n ...pickEnv(context.envAllowlist),\n ...(options.env ?? {}),\n },\n signal: options.signal,\n });\n activeChild = child;\n\n let stdout = \"\";\n let stderr = \"\";\n\n child.stdout.on(\"data\", (chunk) => {\n const text = chunk.toString();\n stdout += text;\n void context.log(\"stdout\", text);\n });\n\n child.stderr.on(\"data\", (chunk) => {\n const text = chunk.toString();\n stderr += text;\n void context.log(\"stderr\", text);\n });\n\n child.on(\"error\", (error) => {\n childError = error;\n });\n\n child.on(\"close\", (exitCode, signal) => {\n if (activeChild === child) {\n activeChild = undefined;\n }\n if (signal === \"SIGTERM\" || signal === \"SIGKILL\") {\n resolve({\n exitCode: exitCode ?? 1,\n stdout,\n stderr: `${stderr}\\nprocess terminated (${signal})`.trim(),\n });\n return;\n }\n resolve({\n exitCode: exitCode ?? 1,\n stdout,\n stderr: childError ? `${stderr}\\n${childError.message}`.trim() : stderr,\n });\n });\n });\n\n const kill = (signal: NodeJS.Signals = \"SIGTERM\"): void => {\n if (!activeChild || activeChild.killed) return;\n activeChild.kill(signal);\n if (signal === \"SIGTERM\") {\n const escalation = setTimeout(() => {\n if (activeChild && !activeChild.killed) {\n activeChild.kill(\"SIGKILL\");\n }\n }, 5000);\n escalation.unref();\n }\n };\n\n const writeStdin = (data: string): void => {\n if (activeChild && !activeChild.killed && activeChild.stdin && !activeChild.stdin.destroyed) {\n activeChild.stdin.write(data);\n }\n };\n\n return { exec, kill, writeStdin };\n}\n\nexport async function ensureWorkspacePath(workspacePath: string, ...segments: string[]): Promise<string> {\n const fullPath = join(workspacePath, ...segments);\n await mkdir(fullPath, { recursive: true });\n return fullPath;\n}\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@workplane/adapter-sdk",
3
+ "version": "0.3.1",
4
+ "private": false,
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/MindStaq/workplane.git"
10
+ },
11
+ "main": "./dist/index.js",
12
+ "types": "./dist/index.d.ts",
13
+ "exports": {
14
+ ".": {
15
+ "import": "./dist/index.js",
16
+ "types": "./dist/index.d.ts"
17
+ }
18
+ },
19
+ "files": [
20
+ "dist",
21
+ "README.md"
22
+ ],
23
+ "sideEffects": false,
24
+ "publishConfig": {
25
+ "access": "public",
26
+ "registry": "https://registry.npmjs.org/"
27
+ },
28
+ "scripts": {
29
+ "build": "tsup"
30
+ }
31
+ }