pi-harness-runtime 1.1.429 → 1.1.431
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/package.json +1 -1
- package/packages/a2a-adapter/package.json +1 -1
- package/packages/agent-policy/package.json +1 -1
- package/packages/architecture-generator/package.json +1 -1
- package/packages/auth/package.json +1 -1
- package/packages/autonomous-refactor/package.json +1 -1
- package/packages/autonomous-runtime/package.json +1 -1
- package/packages/cache-strategy/package.json +1 -1
- package/packages/capability-registry/package.json +1 -1
- package/packages/checkpoint/package.json +1 -1
- package/packages/cli-plugin-sdk/package.json +1 -1
- package/packages/clipboard/package.json +1 -1
- package/packages/clipboard-plugin/package.json +1 -1
- package/packages/code-generation/package.json +1 -1
- package/packages/code-review/package.json +1 -1
- package/packages/codex-adapter/package.json +1 -1
- package/packages/codex-watcher/package.json +1 -1
- package/packages/config-capture/package.json +1 -1
- package/packages/connection-runtime/package.json +1 -1
- package/packages/context-compiler/package.json +1 -1
- package/packages/context-discovery/package.json +1 -1
- package/packages/context-manager/package.json +1 -1
- package/packages/contracts/package.json +1 -1
- package/packages/cookie-sanitizer/package.json +1 -1
- package/packages/cost-optimizer/package.json +1 -1
- package/packages/dependency-analyzer/package.json +1 -1
- package/packages/django-plugin/package.json +1 -1
- package/packages/doc-generator/package.json +1 -1
- package/packages/durable-review/package.json +1 -1
- package/packages/e2e-tester/package.json +1 -1
- package/packages/evaluation-engine/package.json +1 -1
- package/packages/evaluation-runner/package.json +1 -1
- package/packages/event-bus/package.json +1 -1
- package/packages/event-sink/package.json +1 -1
- package/packages/event-store/package.json +1 -1
- package/packages/experience-replay/package.json +1 -1
- package/packages/feedback-collector/package.json +1 -1
- package/packages/file-copy-helper/package.json +1 -1
- package/packages/framework-detector/package.json +1 -1
- package/packages/framework-plugin-sdk/package.json +1 -1
- package/packages/frappe-plugin/package.json +1 -1
- package/packages/generic-web-plugin/package.json +1 -1
- package/packages/health-monitor/package.json +1 -1
- package/packages/intent-analyzer/package.json +1 -1
- package/packages/jev-judge/package.json +1 -1
- package/packages/knowledge-graph/package.json +1 -1
- package/packages/knowledge-retrieval/package.json +1 -1
- package/packages/laravel-plugin/package.json +1 -1
- package/packages/learning-engine/package.json +1 -1
- package/packages/logging/package.json +1 -1
- package/packages/mcp-adapter/package.json +1 -1
- package/packages/memory-engine/package.json +1 -1
- package/packages/milestone-manager/package.json +1 -1
- package/packages/model-registry/package.json +1 -1
- package/packages/nextjs-plugin/package.json +1 -1
- package/packages/notification/package.json +1 -1
- package/packages/observability/package.json +1 -1
- package/packages/okf-indexer/package.json +1 -1
- package/packages/paperclip-integration/package.json +1 -1
- package/packages/performance-optimizer/package.json +1 -1
- package/packages/permission-mode/package.json +1 -1
- package/packages/privilege-broker/package.json +1 -1
- package/packages/project-analyzer/package.json +1 -1
- package/packages/project-bootstrap/package.json +1 -1
- package/packages/projection-engine/package.json +1 -1
- package/packages/prompt-compiler/package.json +1 -1
- package/packages/prompt-versioning/package.json +1 -1
- package/packages/provider-adapter-sdk/package.json +1 -1
- package/packages/provider-router/package.json +1 -1
- package/packages/provider-selector/package.json +1 -1
- package/packages/providers/package.json +1 -1
- package/packages/qdrant-skills/package.json +1 -1
- package/packages/quota-manager/package.json +1 -1
- package/packages/rate-limiter/package.json +1 -1
- package/packages/react-vite-plugin/package.json +1 -1
- package/packages/relay/package.json +1 -1
- package/packages/release-manager/package.json +1 -1
- package/packages/requirement-compiler/package.json +1 -1
- package/packages/runtime/dist/runtime-api.d.ts +61 -6
- package/packages/runtime/dist/runtime-api.d.ts.map +1 -1
- package/packages/runtime/dist/runtime-api.js +83 -30
- package/packages/runtime/dist/runtime-api.js.map +1 -1
- package/packages/runtime/package.json +1 -1
- package/packages/runtime/src/runtime-api.ts +168 -52
- package/packages/runtime/test/runtime-api.test.ts +169 -0
- package/packages/scheduler/package.json +1 -1
- package/packages/scheduler-adapter/package.json +1 -1
- package/packages/session/package.json +1 -1
- package/packages/session-api/package.json +1 -1
- package/packages/session-export/package.json +1 -1
- package/packages/shared-context/package.json +1 -1
- package/packages/skill-mcp-client/package.json +1 -1
- package/packages/skill-registry/package.json +1 -1
- package/packages/skills/package.json +1 -1
- package/packages/sprint-planner/package.json +1 -1
- package/packages/subscription-engine/package.json +1 -1
- package/packages/task-compiler/package.json +1 -1
- package/packages/tencentdb-memory/package.json +1 -1
- package/packages/tencentdb-sync/package.json +1 -1
- package/packages/test-data-generator/package.json +1 -1
- package/packages/test-generator/package.json +1 -1
- package/packages/todo-bd-sync/package.json +1 -1
- package/packages/token-estimation/package.json +1 -1
- package/packages/token-optimizer/package.json +1 -1
- package/packages/tooling-preference/package.json +1 -1
- package/packages/trajectory/package.json +1 -1
- package/packages/tui/package.json +1 -1
- package/packages/two-phase-review/package.json +1 -1
- package/packages/types/package.json +1 -1
- package/packages/voice-api/package.json +1 -1
- package/packages/webmcp-tester/package.json +1 -1
- package/packages/wiki/package.json +1 -1
- package/packages/workflow-events/package.json +1 -1
- package/packages/workspace-scanner/package.json +1 -1
- package/packages/worktree/package.json +1 -1
- package/packages/write-review/package.json +1 -1
- package/scripts/typecheck-packages.mjs +1 -1
- package/harness/task-graph.d.ts +0 -51
- package/packages/notification/adapters/email-adapter.ts +0 -126
- package/packages/notification/adapters/ntfy-adapter.ts +0 -100
- package/packages/notification/adapters/telegram-adapter.ts +0 -107
- package/packages/notification/adapters/webhook-adapter.ts +0 -75
- package/packages/notification/base-adapter.ts +0 -75
- package/packages/notification/index.ts +0 -51
- package/packages/notification/notification-center.ts +0 -286
- package/packages/notification/types.ts +0 -89
- package/packages/quota-manager/index.ts +0 -28
- package/packages/quota-manager/quota-manager.ts +0 -339
- package/packages/quota-manager/tui-usage-monitor.ts +0 -355
- package/packages/runtime/command-executor.ts +0 -523
- package/packages/runtime/index.ts +0 -50
- package/packages/runtime/local-runtime-agent.ts +0 -480
- package/packages/runtime/policy-engine.ts +0 -813
- package/packages/runtime/runtime-api.ts +0 -665
- package/packages/runtime/workspace-manager.ts +0 -591
- package/packages/types/src/ai-providers.d.ts +0 -36
- package/packages/types/src/ai-providers.js +0 -66
- package/packages/types/src/runtime-types.d.ts +0 -418
- package/packages/types/src/runtime-types.js +0 -3
|
@@ -1,523 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Command Executor — RFC-0025
|
|
3
|
-
*
|
|
4
|
-
* Safe shell command execution with timeout, output capture, and security policies.
|
|
5
|
-
*
|
|
6
|
-
* Features:
|
|
7
|
-
* - Timeout enforcement
|
|
8
|
-
* - Output capture (stdout/stderr)
|
|
9
|
-
* - Working directory control
|
|
10
|
-
* - Environment variable injection
|
|
11
|
-
* - Security policy enforcement
|
|
12
|
-
* - Process management (kill, signal)
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
import {
|
|
16
|
-
spawn,
|
|
17
|
-
type ChildProcess,
|
|
18
|
-
type SpawnOptions,
|
|
19
|
-
} from "node:child_process";
|
|
20
|
-
import { EventEmitter } from "node:events";
|
|
21
|
-
import { join } from "node:path";
|
|
22
|
-
|
|
23
|
-
export interface CommandResult {
|
|
24
|
-
success: boolean;
|
|
25
|
-
exitCode: number | null;
|
|
26
|
-
stdout: string;
|
|
27
|
-
stderr: string;
|
|
28
|
-
timedOut: boolean;
|
|
29
|
-
duration: number;
|
|
30
|
-
command: string;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export interface CommandOptions {
|
|
34
|
-
/** Working directory (default: process.cwd()) */
|
|
35
|
-
cwd?: string;
|
|
36
|
-
/** Environment variables to inject */
|
|
37
|
-
env?: Record<string, string>;
|
|
38
|
-
/** Timeout in milliseconds (default: no timeout) */
|
|
39
|
-
timeout?: number;
|
|
40
|
-
/** Shell to use (default: /bin/sh on Unix, cmd.exe on Windows) */
|
|
41
|
-
shell?: string;
|
|
42
|
-
/** User ID to run as (if available) */
|
|
43
|
-
uid?: number;
|
|
44
|
-
/** Group ID to run as (if available) */
|
|
45
|
-
gid?: number;
|
|
46
|
-
/** Capture stdout (default: true) */
|
|
47
|
-
captureStdout?: boolean;
|
|
48
|
-
/** Capture stderr (default: true) */
|
|
49
|
-
captureStderr?: boolean;
|
|
50
|
-
/** Treat non-zero exit as success (default: false) */
|
|
51
|
-
ignoreExitCode?: boolean;
|
|
52
|
-
/** Policy to check before execution */
|
|
53
|
-
policyCheck?: boolean;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export interface CommandPolicy {
|
|
57
|
-
/** Allowed commands (exact match or pattern) */
|
|
58
|
-
allowedCommands?: RegExp[];
|
|
59
|
-
/** Denied commands (takes precedence) */
|
|
60
|
-
deniedCommands?: RegExp[];
|
|
61
|
-
/** Maximum timeout in ms */
|
|
62
|
-
maxTimeout?: number;
|
|
63
|
-
/** Allowed working directories */
|
|
64
|
-
allowedDirs?: string[];
|
|
65
|
-
/** Denied working directories */
|
|
66
|
-
deniedDirs?: string[];
|
|
67
|
-
/** Allow shell built-ins */
|
|
68
|
-
allowShellBuiltins?: boolean;
|
|
69
|
-
/** Allow environment variable injection */
|
|
70
|
-
allowEnvInjection?: boolean;
|
|
71
|
-
/** Commands that require explicit policy bypass */
|
|
72
|
-
requireApproval?: RegExp[];
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export interface CommandEvent {
|
|
76
|
-
command: string;
|
|
77
|
-
timestamp: string;
|
|
78
|
-
pid?: number;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export interface CommandExecutorEvents {
|
|
82
|
-
onStart: (event: CommandEvent) => void;
|
|
83
|
-
onExit: (
|
|
84
|
-
event: CommandEvent & { exitCode: number; duration: number },
|
|
85
|
-
) => void;
|
|
86
|
-
onTimeout: (event: CommandEvent) => void;
|
|
87
|
-
onError: (error: Error, command: string) => void;
|
|
88
|
-
onPolicyViolation: (reason: string, command: string) => void;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const DEFAULT_POLICY: CommandPolicy = {
|
|
92
|
-
allowShellBuiltins: true,
|
|
93
|
-
allowEnvInjection: true,
|
|
94
|
-
maxTimeout: 300000, // 5 minutes default
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
export class CommandExecutor extends EventEmitter {
|
|
98
|
-
private readonly policy: CommandPolicy;
|
|
99
|
-
private runningProcesses: Map<number, ChildProcess> = new Map();
|
|
100
|
-
private defaultOptions: CommandOptions;
|
|
101
|
-
|
|
102
|
-
constructor(policy: CommandPolicy = {}) {
|
|
103
|
-
super();
|
|
104
|
-
this.policy = { ...DEFAULT_POLICY, ...policy };
|
|
105
|
-
this.defaultOptions = {
|
|
106
|
-
captureStdout: true,
|
|
107
|
-
captureStderr: true,
|
|
108
|
-
ignoreExitCode: false,
|
|
109
|
-
policyCheck: true,
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Execute a command synchronously
|
|
115
|
-
*/
|
|
116
|
-
exec(command: string, options: CommandOptions = {}): CommandResult {
|
|
117
|
-
const opts = { ...this.defaultOptions, ...options };
|
|
118
|
-
const startTime = Date.now();
|
|
119
|
-
|
|
120
|
-
// Policy check
|
|
121
|
-
if (opts.policyCheck !== false) {
|
|
122
|
-
const policyResult = this.checkPolicy(command, opts);
|
|
123
|
-
if (!policyResult.allowed) {
|
|
124
|
-
this.emit(
|
|
125
|
-
"policyViolation",
|
|
126
|
-
policyResult.reason ?? "Policy violation",
|
|
127
|
-
command,
|
|
128
|
-
);
|
|
129
|
-
return {
|
|
130
|
-
success: false,
|
|
131
|
-
exitCode: null,
|
|
132
|
-
stdout: "",
|
|
133
|
-
stderr: policyResult.reason ?? "Policy violation",
|
|
134
|
-
timedOut: false,
|
|
135
|
-
duration: Date.now() - startTime,
|
|
136
|
-
command,
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// Spawn process
|
|
142
|
-
const spawnOpts: SpawnOptions = {
|
|
143
|
-
cwd: opts.cwd ?? process.cwd(),
|
|
144
|
-
env: { ...process.env, ...opts.env },
|
|
145
|
-
shell:
|
|
146
|
-
opts.shell ?? (process.platform === "win32" ? "cmd.exe" : "/bin/sh"),
|
|
147
|
-
uid: opts.uid,
|
|
148
|
-
gid: opts.gid,
|
|
149
|
-
windowsHide: true,
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
let proc: ChildProcess;
|
|
153
|
-
try {
|
|
154
|
-
proc = spawn(command, [], spawnOpts);
|
|
155
|
-
} catch (error) {
|
|
156
|
-
this.emit("error", error as Error, command);
|
|
157
|
-
return {
|
|
158
|
-
success: false,
|
|
159
|
-
exitCode: null,
|
|
160
|
-
stdout: "",
|
|
161
|
-
stderr: String(error),
|
|
162
|
-
timedOut: false,
|
|
163
|
-
duration: Date.now() - startTime,
|
|
164
|
-
command,
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
this.runningProcesses.set(proc.pid!, proc);
|
|
169
|
-
|
|
170
|
-
const event: CommandEvent = {
|
|
171
|
-
command,
|
|
172
|
-
timestamp: new Date().toISOString(),
|
|
173
|
-
pid: proc.pid,
|
|
174
|
-
};
|
|
175
|
-
this.emit("start", event);
|
|
176
|
-
|
|
177
|
-
// Collect output
|
|
178
|
-
let stdout = "";
|
|
179
|
-
let stderr = "";
|
|
180
|
-
|
|
181
|
-
if (opts.captureStdout && proc.stdout) {
|
|
182
|
-
proc.stdout.on("data", (data) => {
|
|
183
|
-
stdout += data.toString();
|
|
184
|
-
});
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
if (opts.captureStderr && proc.stderr) {
|
|
188
|
-
proc.stderr.on("data", (data) => {
|
|
189
|
-
stderr += data.toString();
|
|
190
|
-
});
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// Handle timeout
|
|
194
|
-
let timedOutFlag = false;
|
|
195
|
-
let timeoutId: NodeJS.Timeout | undefined;
|
|
196
|
-
|
|
197
|
-
if (opts.timeout && opts.timeout > 0) {
|
|
198
|
-
const maxTimeout = this.policy.maxTimeout ?? Infinity;
|
|
199
|
-
const effectiveTimeout = Math.min(opts.timeout, maxTimeout);
|
|
200
|
-
|
|
201
|
-
timeoutId = setTimeout(() => {
|
|
202
|
-
timedOutFlag = true;
|
|
203
|
-
this.kill(proc.pid!);
|
|
204
|
-
this.emit("timeout", event);
|
|
205
|
-
}, effectiveTimeout);
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
// Wait for completion
|
|
209
|
-
const exitCode = this.waitForExit(proc);
|
|
210
|
-
|
|
211
|
-
// Cleanup
|
|
212
|
-
if (timeoutId) clearTimeout(timeoutId);
|
|
213
|
-
this.runningProcesses.delete(proc.pid!);
|
|
214
|
-
|
|
215
|
-
const duration = Date.now() - startTime;
|
|
216
|
-
this.emit("exit", { ...event, exitCode: exitCode ?? -1, duration });
|
|
217
|
-
|
|
218
|
-
const success: boolean =
|
|
219
|
-
(exitCode === 0 || opts.ignoreExitCode) && !timedOutFlag ? true : false;
|
|
220
|
-
|
|
221
|
-
return {
|
|
222
|
-
success,
|
|
223
|
-
exitCode,
|
|
224
|
-
stdout,
|
|
225
|
-
stderr,
|
|
226
|
-
timedOut: timedOutFlag,
|
|
227
|
-
duration,
|
|
228
|
-
command,
|
|
229
|
-
};
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
/**
|
|
233
|
-
* Execute a command asynchronously (non-blocking)
|
|
234
|
-
*/
|
|
235
|
-
async execAsync(
|
|
236
|
-
command: string,
|
|
237
|
-
options: CommandOptions = {},
|
|
238
|
-
): Promise<CommandResult> {
|
|
239
|
-
const opts = { ...this.defaultOptions, ...options };
|
|
240
|
-
const startTime = Date.now();
|
|
241
|
-
|
|
242
|
-
// Policy check
|
|
243
|
-
if (opts.policyCheck !== false) {
|
|
244
|
-
const policyResult = this.checkPolicy(command, opts);
|
|
245
|
-
if (!policyResult.allowed) {
|
|
246
|
-
this.emit(
|
|
247
|
-
"policyViolation",
|
|
248
|
-
policyResult.reason ?? "Policy violation",
|
|
249
|
-
command,
|
|
250
|
-
);
|
|
251
|
-
return {
|
|
252
|
-
success: false,
|
|
253
|
-
exitCode: null,
|
|
254
|
-
stdout: "",
|
|
255
|
-
stderr: policyResult.reason ?? "Policy violation",
|
|
256
|
-
timedOut: false,
|
|
257
|
-
duration: Date.now() - startTime,
|
|
258
|
-
command,
|
|
259
|
-
};
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
// Spawn process
|
|
264
|
-
const spawnOpts: SpawnOptions = {
|
|
265
|
-
cwd: opts.cwd ?? process.cwd(),
|
|
266
|
-
env: { ...process.env, ...opts.env },
|
|
267
|
-
shell:
|
|
268
|
-
opts.shell ?? (process.platform === "win32" ? "cmd.exe" : "/bin/sh"),
|
|
269
|
-
uid: opts.uid,
|
|
270
|
-
gid: opts.gid,
|
|
271
|
-
windowsHide: true,
|
|
272
|
-
};
|
|
273
|
-
|
|
274
|
-
return new Promise((resolve) => {
|
|
275
|
-
const proc = spawn(command, [], spawnOpts);
|
|
276
|
-
this.runningProcesses.set(proc.pid!, proc);
|
|
277
|
-
|
|
278
|
-
const event: CommandEvent = {
|
|
279
|
-
command,
|
|
280
|
-
timestamp: new Date().toISOString(),
|
|
281
|
-
pid: proc.pid,
|
|
282
|
-
};
|
|
283
|
-
this.emit("start", event);
|
|
284
|
-
|
|
285
|
-
// Collect output
|
|
286
|
-
let stdout = "";
|
|
287
|
-
let stderr = "";
|
|
288
|
-
|
|
289
|
-
if (opts.captureStdout && proc.stdout) {
|
|
290
|
-
proc.stdout.on("data", (data) => {
|
|
291
|
-
stdout += data.toString();
|
|
292
|
-
});
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
if (opts.captureStderr && proc.stderr) {
|
|
296
|
-
proc.stderr.on("data", (data) => {
|
|
297
|
-
stderr += data.toString();
|
|
298
|
-
});
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
// Handle timeout
|
|
302
|
-
let timedOut = false;
|
|
303
|
-
const timeoutId = setTimeout(
|
|
304
|
-
() => {
|
|
305
|
-
timedOut = true;
|
|
306
|
-
this.kill(proc.pid!);
|
|
307
|
-
this.emit("timeout", event);
|
|
308
|
-
},
|
|
309
|
-
opts.timeout ?? this.policy.maxTimeout ?? 300000,
|
|
310
|
-
);
|
|
311
|
-
|
|
312
|
-
proc.on("close", (code) => {
|
|
313
|
-
clearTimeout(timeoutId);
|
|
314
|
-
this.runningProcesses.delete(proc.pid!);
|
|
315
|
-
|
|
316
|
-
const duration = Date.now() - startTime;
|
|
317
|
-
const exitCode = code !== null ? code : -1;
|
|
318
|
-
this.emit("exit", { ...event, exitCode, duration });
|
|
319
|
-
|
|
320
|
-
const execSuccess: boolean =
|
|
321
|
-
(code === 0 || opts.ignoreExitCode) && !timedOut ? true : false;
|
|
322
|
-
|
|
323
|
-
resolve({
|
|
324
|
-
success: execSuccess,
|
|
325
|
-
exitCode: code,
|
|
326
|
-
stdout,
|
|
327
|
-
stderr,
|
|
328
|
-
timedOut: timedOut,
|
|
329
|
-
duration,
|
|
330
|
-
command,
|
|
331
|
-
});
|
|
332
|
-
});
|
|
333
|
-
|
|
334
|
-
proc.on("error", (error) => {
|
|
335
|
-
clearTimeout(timeoutId);
|
|
336
|
-
this.runningProcesses.delete(proc.pid!);
|
|
337
|
-
this.emit("error", error, command);
|
|
338
|
-
|
|
339
|
-
resolve({
|
|
340
|
-
success: false,
|
|
341
|
-
exitCode: null,
|
|
342
|
-
stdout,
|
|
343
|
-
stderr: stderr + "\n" + String(error),
|
|
344
|
-
timedOut: false,
|
|
345
|
-
duration: Date.now() - startTime,
|
|
346
|
-
command,
|
|
347
|
-
});
|
|
348
|
-
});
|
|
349
|
-
});
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
/**
|
|
353
|
-
* Kill a running process
|
|
354
|
-
*/
|
|
355
|
-
kill(pid: number, signal: NodeJS.Signals = "SIGTERM"): boolean {
|
|
356
|
-
const proc = this.runningProcesses.get(pid);
|
|
357
|
-
if (!proc) {
|
|
358
|
-
return false;
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
try {
|
|
362
|
-
proc.kill(signal);
|
|
363
|
-
return true;
|
|
364
|
-
} catch {
|
|
365
|
-
return false;
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
/**
|
|
370
|
-
* Kill all running processes
|
|
371
|
-
*/
|
|
372
|
-
killAll(signal: NodeJS.Signals = "SIGTERM"): number {
|
|
373
|
-
let killed = 0;
|
|
374
|
-
for (const entry of Array.from(this.runningProcesses.entries())) {
|
|
375
|
-
const [_pid, proc] = entry;
|
|
376
|
-
try {
|
|
377
|
-
proc.kill(signal);
|
|
378
|
-
killed++;
|
|
379
|
-
} catch {
|
|
380
|
-
// Process already exited
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
this.runningProcesses.clear();
|
|
384
|
-
return killed;
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
/**
|
|
388
|
-
* Get count of running processes
|
|
389
|
-
*/
|
|
390
|
-
getRunningCount(): number {
|
|
391
|
-
return this.runningProcesses.size;
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
/**
|
|
395
|
-
* Get list of running process PIDs
|
|
396
|
-
*/
|
|
397
|
-
getRunningPids(): number[] {
|
|
398
|
-
return Array.from(this.runningProcesses.keys());
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
/**
|
|
402
|
-
* Check policy for a command
|
|
403
|
-
*/
|
|
404
|
-
checkPolicy(
|
|
405
|
-
command: string,
|
|
406
|
-
_options?: CommandOptions,
|
|
407
|
-
): { allowed: boolean; reason?: string } {
|
|
408
|
-
// Check denied commands
|
|
409
|
-
if (this.policy.deniedCommands) {
|
|
410
|
-
for (const pattern of this.policy.deniedCommands) {
|
|
411
|
-
if (pattern.test(command)) {
|
|
412
|
-
return {
|
|
413
|
-
allowed: false,
|
|
414
|
-
reason: `Command matches denied pattern: ${pattern}`,
|
|
415
|
-
};
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
// Check allowed commands (if specified, must match)
|
|
421
|
-
if (this.policy.allowedCommands && this.policy.allowedCommands.length > 0) {
|
|
422
|
-
let allowed = false;
|
|
423
|
-
for (const pattern of this.policy.allowedCommands) {
|
|
424
|
-
if (pattern.test(command)) {
|
|
425
|
-
allowed = true;
|
|
426
|
-
break;
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
if (!allowed) {
|
|
430
|
-
return {
|
|
431
|
-
allowed: false,
|
|
432
|
-
reason: "Command not in allowed list",
|
|
433
|
-
};
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
// Check denied directories
|
|
438
|
-
if (_options?.cwd) {
|
|
439
|
-
if (this.policy.deniedDirs) {
|
|
440
|
-
for (const dir of this.policy.deniedDirs) {
|
|
441
|
-
if (_options.cwd.startsWith(dir)) {
|
|
442
|
-
return {
|
|
443
|
-
allowed: false,
|
|
444
|
-
reason: `Working directory matches denied path: ${dir}`,
|
|
445
|
-
};
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
// Check for dangerous shell operators
|
|
452
|
-
const dangerousPatterns = [
|
|
453
|
-
{ pattern: /;\s*rm\s+-rf/i, reason: "Attempted rm -rf" },
|
|
454
|
-
{
|
|
455
|
-
pattern: />\s*\/dev\/null/i,
|
|
456
|
-
reason: "Output redirection to /dev/null",
|
|
457
|
-
},
|
|
458
|
-
{ pattern: /\|\s*sh\s*$/i, reason: "Pipe to shell" },
|
|
459
|
-
{ pattern: /&\s*$/, reason: "Background execution" },
|
|
460
|
-
];
|
|
461
|
-
|
|
462
|
-
for (const { pattern, reason } of dangerousPatterns) {
|
|
463
|
-
if (pattern.test(command)) {
|
|
464
|
-
// Only block if explicitly denied
|
|
465
|
-
if (this.policy.deniedCommands) {
|
|
466
|
-
return { allowed: false, reason };
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
return { allowed: true };
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
/**
|
|
475
|
-
* Update policy at runtime
|
|
476
|
-
*/
|
|
477
|
-
updatePolicy(updates: Partial<CommandPolicy>): void {
|
|
478
|
-
Object.assign(this.policy, updates);
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
/**
|
|
482
|
-
* Get current policy
|
|
483
|
-
*/
|
|
484
|
-
getPolicy(): CommandPolicy {
|
|
485
|
-
return { ...this.policy };
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
// ─── Private Methods ────────────────────────────────────────────────
|
|
489
|
-
|
|
490
|
-
private waitForExit(_proc: ChildProcess): number | null {
|
|
491
|
-
// Note: This method is for synchronous execution.
|
|
492
|
-
// For async execution, use execAsync() which properly handles events.
|
|
493
|
-
// This returns null for sync - actual exit code is captured via events.
|
|
494
|
-
return null;
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
/**
|
|
499
|
-
* Create a CommandExecutor with safe defaults for harness runtime
|
|
500
|
-
*/
|
|
501
|
-
export function createHarnessExecutor(): CommandExecutor {
|
|
502
|
-
return new CommandExecutor({
|
|
503
|
-
// Allow common development commands
|
|
504
|
-
allowedCommands: [
|
|
505
|
-
/^(git|npm|npx|yarn|pnpm|bun|node|python3?|make|cargo|go)\s/,
|
|
506
|
-
/^(tsc|esbuild|rollup|vite|webpack)\s/,
|
|
507
|
-
/^(jest|vitest|mocha|pytest|cargo test|npm test)\s/,
|
|
508
|
-
/^(eslint|ruff|black|prettier)\s/,
|
|
509
|
-
/^(mkdir|rm|cp|mv|cat|echo|ls|cd)\s/,
|
|
510
|
-
],
|
|
511
|
-
// Deny dangerous patterns
|
|
512
|
-
deniedCommands: [
|
|
513
|
-
/rm\s+-rf\s+\/(?!node_modules)/, // rm -rf / except rm -rf node_modules
|
|
514
|
-
/curl\s+.*\|.*sh$/i, // curl | sh
|
|
515
|
-
/wget\s+.*\|.*sh$/i, // wget | sh
|
|
516
|
-
/base64\s+-d\s+.*\|.*sh/i, // base64 decode | sh
|
|
517
|
-
/:\(\)\{.*\}\s*:/, // Fork bomb
|
|
518
|
-
],
|
|
519
|
-
maxTimeout: 300000, // 5 minutes
|
|
520
|
-
// Default to user's home directory
|
|
521
|
-
allowedDirs: [join(process.env.HOME ?? "", "")],
|
|
522
|
-
});
|
|
523
|
-
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Runtime Package — RFC-0024, RFC-0025, RFC-0026, RFC-0027, RFC-0028
|
|
3
|
-
*
|
|
4
|
-
* Core runtime components for the pi-harness-runtime.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
// RFC-0024: Local Runtime Agent
|
|
8
|
-
export { LocalRuntimeAgent, createHarnessRuntimeAgent } from "./local-runtime-agent.js";
|
|
9
|
-
export type { LocalRuntimeAgentConfig, LocalRuntimeAgentEvents, QuotaSummary, AuthSession } from "./local-runtime-agent.js";
|
|
10
|
-
|
|
11
|
-
// RFC-0025: Command Executor
|
|
12
|
-
export { CommandExecutor, createHarnessExecutor } from "./command-executor.js";
|
|
13
|
-
export type {
|
|
14
|
-
CommandResult,
|
|
15
|
-
CommandOptions,
|
|
16
|
-
CommandPolicy,
|
|
17
|
-
CommandEvent,
|
|
18
|
-
CommandExecutorEvents,
|
|
19
|
-
} from "./command-executor.js";
|
|
20
|
-
|
|
21
|
-
// RFC-0026: Workspace Manager
|
|
22
|
-
export { WorkspaceManager, createHarnessWorkspaceManager } from "./workspace-manager.js";
|
|
23
|
-
export type {
|
|
24
|
-
Workspace,
|
|
25
|
-
WorkspaceConfig,
|
|
26
|
-
WorkspaceEvent,
|
|
27
|
-
} from "./workspace-manager.js";
|
|
28
|
-
|
|
29
|
-
// RFC-0027: Runtime API
|
|
30
|
-
export { RuntimeApi, createHarnessRuntimeApi } from "./runtime-api.js";
|
|
31
|
-
export type {
|
|
32
|
-
RuntimeApiConfig,
|
|
33
|
-
ApiResponse,
|
|
34
|
-
JobSummary,
|
|
35
|
-
TaskSummary,
|
|
36
|
-
RuntimeStatus,
|
|
37
|
-
} from "./runtime-api.js";
|
|
38
|
-
|
|
39
|
-
// RFC-0028: Policy Engine
|
|
40
|
-
export { PolicyEngine, createHarnessPolicyEngine } from "./policy-engine.js";
|
|
41
|
-
export type {
|
|
42
|
-
PolicyResult,
|
|
43
|
-
PolicyContext,
|
|
44
|
-
Policy,
|
|
45
|
-
PolicyCondition,
|
|
46
|
-
PolicyEffect,
|
|
47
|
-
PolicyRule,
|
|
48
|
-
RateLimit,
|
|
49
|
-
AuditEntry,
|
|
50
|
-
} from "./policy-engine.js";
|