@harness-control/runner 0.1.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.
Files changed (71) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +21 -0
  3. package/dist/audit/index.d.ts +18 -0
  4. package/dist/audit/index.js +28 -0
  5. package/dist/config/index.d.ts +179 -0
  6. package/dist/config/index.js +124 -0
  7. package/dist/connection/index.d.ts +2 -0
  8. package/dist/connection/index.js +2 -0
  9. package/dist/connection/runner-connection.d.ts +22 -0
  10. package/dist/connection/runner-connection.js +631 -0
  11. package/dist/harnesses/adapters/providers/claude-runtime.d.ts +5 -0
  12. package/dist/harnesses/adapters/providers/claude-runtime.js +186 -0
  13. package/dist/harnesses/adapters/providers/claude.d.ts +24 -0
  14. package/dist/harnesses/adapters/providers/claude.js +189 -0
  15. package/dist/harnesses/adapters/providers/cli-process.d.ts +44 -0
  16. package/dist/harnesses/adapters/providers/cli-process.js +195 -0
  17. package/dist/harnesses/adapters/providers/codex-models.d.ts +4 -0
  18. package/dist/harnesses/adapters/providers/codex-models.js +62 -0
  19. package/dist/harnesses/adapters/providers/codex-rpc.d.ts +21 -0
  20. package/dist/harnesses/adapters/providers/codex-rpc.js +114 -0
  21. package/dist/harnesses/adapters/providers/codex-runtime.d.ts +3 -0
  22. package/dist/harnesses/adapters/providers/codex-runtime.js +267 -0
  23. package/dist/harnesses/adapters/providers/codex.d.ts +22 -0
  24. package/dist/harnesses/adapters/providers/codex.js +161 -0
  25. package/dist/harnesses/adapters/providers/mock.d.ts +13 -0
  26. package/dist/harnesses/adapters/providers/mock.js +64 -0
  27. package/dist/harnesses/adapters/providers/native-process.d.ts +9 -0
  28. package/dist/harnesses/adapters/providers/native-process.js +41 -0
  29. package/dist/harnesses/adapters/providers/native-turn.d.ts +17 -0
  30. package/dist/harnesses/adapters/providers/native-turn.js +139 -0
  31. package/dist/harnesses/adapters/providers/opencode.d.ts +44 -0
  32. package/dist/harnesses/adapters/providers/opencode.js +416 -0
  33. package/dist/harnesses/adapters/providers/shared.d.ts +9 -0
  34. package/dist/harnesses/adapters/providers/shared.js +97 -0
  35. package/dist/harnesses/adapters/registry.d.ts +12 -0
  36. package/dist/harnesses/adapters/registry.js +47 -0
  37. package/dist/harnesses/adapters/types.d.ts +54 -0
  38. package/dist/harnesses/adapters/types.js +9 -0
  39. package/dist/harnesses/adapters.d.ts +8 -0
  40. package/dist/harnesses/adapters.js +8 -0
  41. package/dist/harnesses/index.d.ts +93 -0
  42. package/dist/harnesses/index.js +620 -0
  43. package/dist/host/provider-registry.d.ts +34 -0
  44. package/dist/host/provider-registry.js +162 -0
  45. package/dist/index.d.ts +3 -0
  46. package/dist/index.js +201 -0
  47. package/dist/local-actions/dispatcher.d.ts +28 -0
  48. package/dist/local-actions/dispatcher.js +407 -0
  49. package/dist/local-actions/executors.d.ts +159 -0
  50. package/dist/local-actions/executors.js +1103 -0
  51. package/dist/local-actions/index.d.ts +74 -0
  52. package/dist/local-actions/index.js +275 -0
  53. package/dist/logs/index.d.ts +6 -0
  54. package/dist/logs/index.js +9 -0
  55. package/dist/mcp/McpAttachmentClient.d.ts +111 -0
  56. package/dist/mcp/McpAttachmentClient.js +345 -0
  57. package/dist/mcp/McpProxyServer.d.ts +18 -0
  58. package/dist/mcp/McpProxyServer.js +188 -0
  59. package/dist/mcp/McpStdioProfileClient.d.ts +19 -0
  60. package/dist/mcp/McpStdioProfileClient.js +91 -0
  61. package/dist/mcp/index.d.ts +5 -0
  62. package/dist/mcp/index.js +5 -0
  63. package/dist/mcp/redaction.d.ts +3 -0
  64. package/dist/mcp/redaction.js +40 -0
  65. package/dist/pairing/index.d.ts +38 -0
  66. package/dist/pairing/index.js +180 -0
  67. package/dist/state/index.d.ts +76 -0
  68. package/dist/state/index.js +242 -0
  69. package/dist/workspaces/index.d.ts +13 -0
  70. package/dist/workspaces/index.js +110 -0
  71. package/package.json +76 -0
@@ -0,0 +1,407 @@
1
+ import { parseLocalActionErrorPayload, parseLocalActionResponsePayload } from "@harness-control/protocol";
2
+ import { LocalCapabilityPolicyError } from "./index.js";
3
+ import { LocalCapabilityExecutionError, } from "./executors.js";
4
+ export class LocalActionDispatcher {
5
+ #executor;
6
+ #resolveContext;
7
+ #emitEvents;
8
+ #now;
9
+ #stoppedSessionIds = new Set();
10
+ constructor(options) {
11
+ this.#executor = options.executor;
12
+ this.#resolveContext = options.resolveContext;
13
+ this.#emitEvents = options.emitEvents;
14
+ this.#now = options.now ?? (() => new Date());
15
+ }
16
+ async dispatch(request) {
17
+ if (this.#stoppedSessionIds.has(request.attribution.session_id)) {
18
+ return this.#errorOutcome(request, new LocalCapabilityPolicyError("local_capability_lease_revoked", "Local action session has already stopped."), []);
19
+ }
20
+ let context;
21
+ try {
22
+ context = await this.#resolveContext(request);
23
+ }
24
+ catch (error) {
25
+ return this.#errorOutcome(request, error, []);
26
+ }
27
+ try {
28
+ return await this.#dispatchWithContext(request, context);
29
+ }
30
+ catch (error) {
31
+ const executionEvents = error instanceof LocalCapabilityExecutionError ? error.events : [];
32
+ return this.#errorOutcome(request, error, executionEvents);
33
+ }
34
+ }
35
+ duplicatePayloadMismatch(request) {
36
+ const error = new LocalCapabilityPolicyError("local_capability_action_failed", `Local action request '${request.request_id}' was already seen with a different payload.`);
37
+ return this.#errorOutcome(request, error, [failedEventFor(request, error)]);
38
+ }
39
+ markSessionActive(sessionId) {
40
+ this.#stoppedSessionIds.delete(sessionId);
41
+ }
42
+ async stopDevServersForSession(sessionId) {
43
+ this.#stoppedSessionIds.add(sessionId);
44
+ await this.#executor.stopDevServersForSession(sessionId);
45
+ }
46
+ async #dispatchWithContext(request, context) {
47
+ switch (request.action) {
48
+ case "local.filesystem.read": {
49
+ const actionResult = await this.#executor.readFile(context, request.input.path, {
50
+ encoding: request.input.encoding ?? "utf8",
51
+ ...(request.input.range ? { range: request.input.range } : {}),
52
+ ...(request.output_limits.content_bytes ? { contentByteLimit: request.output_limits.content_bytes } : {}),
53
+ });
54
+ const events = this.#emitRequestEvents(request, actionResult.events);
55
+ const payload = parseLocalActionResponsePayload({
56
+ ...this.#responseBase(request, events),
57
+ action: request.action,
58
+ output: {
59
+ path: actionResult.result.path,
60
+ content: actionResult.result.content,
61
+ encoding: actionResult.result.encoding,
62
+ hash: actionResult.result.hash,
63
+ ...(actionResult.result.truncated ? { truncated: true } : {}),
64
+ },
65
+ });
66
+ return { type: "response", payload, events };
67
+ }
68
+ case "local.filesystem.list": {
69
+ const actionResult = await this.#executor.listDirectory(context, request.input.path, {
70
+ recursive: request.input.recursive ?? false,
71
+ includeHidden: request.input.include_hidden ?? false,
72
+ ...(request.input.max_depth ? { maxDepth: request.input.max_depth } : {}),
73
+ ...(request.output_limits.entries ? { entryLimit: request.output_limits.entries } : {}),
74
+ });
75
+ const events = this.#emitRequestEvents(request, actionResult.events);
76
+ const payload = parseLocalActionResponsePayload({
77
+ ...this.#responseBase(request, events),
78
+ action: request.action,
79
+ output: {
80
+ path: actionResult.result.path,
81
+ entries: actionResult.result.entries,
82
+ ...(actionResult.result.truncated ? { truncated: true } : {}),
83
+ },
84
+ });
85
+ return { type: "response", payload, events };
86
+ }
87
+ case "local.filesystem.write": {
88
+ const actionResult = await this.#executor.writeFile(context, request.input.path, request.input.content, {
89
+ encoding: request.input.encoding ?? "utf8",
90
+ mode: request.input.mode,
91
+ createParents: request.input.create_parents,
92
+ ...(request.input.expected_base_hash ? { expectedBaseHash: request.input.expected_base_hash } : {}),
93
+ });
94
+ const events = this.#emitRequestEvents(request, actionResult.events);
95
+ const payload = parseLocalActionResponsePayload({
96
+ ...this.#responseBase(request, events),
97
+ action: request.action,
98
+ output: {
99
+ path: actionResult.result.path,
100
+ bytes_written: actionResult.result.bytes_written,
101
+ new_hash: actionResult.result.new_hash,
102
+ },
103
+ });
104
+ return { type: "response", payload, events };
105
+ }
106
+ case "local.filesystem.patch": {
107
+ const actionResult = await this.#executor.patchFile(context, request.input.path, {
108
+ expectedBaseHash: request.input.expected_base_hash,
109
+ patchContent: request.input.patch.content,
110
+ createIfMissing: request.input.create_if_missing ?? false,
111
+ });
112
+ const events = this.#emitRequestEvents(request, actionResult.events);
113
+ const payload = parseLocalActionResponsePayload({
114
+ ...this.#responseBase(request, events),
115
+ action: request.action,
116
+ output: {
117
+ path: actionResult.result.path,
118
+ changed: actionResult.result.changed,
119
+ new_hash: actionResult.result.new_hash,
120
+ },
121
+ });
122
+ return { type: "response", payload, events };
123
+ }
124
+ case "local.git.status": {
125
+ const actionResult = await this.#executor.git(context, "status", {
126
+ status: {
127
+ porcelainVersion: request.input.porcelain_version,
128
+ includeBranch: request.input.include_branch ?? false,
129
+ ...(request.output_limits.status_bytes ? { outputByteLimit: request.output_limits.status_bytes } : {}),
130
+ },
131
+ });
132
+ const events = this.#emitRequestEvents(request, actionResult.events);
133
+ const payload = parseLocalActionResponsePayload({
134
+ ...this.#responseBase(request, events),
135
+ action: request.action,
136
+ output: {
137
+ porcelain: actionResult.result.stdout,
138
+ ...(actionResult.result.branch ? { branch: actionResult.result.branch } : {}),
139
+ ...(actionResult.result.stdout_truncated ? { truncated: true } : {}),
140
+ },
141
+ });
142
+ return { type: "response", payload, events };
143
+ }
144
+ case "local.git.diff": {
145
+ const actionResult = await this.#executor.git(context, "diff", {
146
+ diff: {
147
+ ...(request.input.paths ? { paths: request.input.paths } : {}),
148
+ staged: request.input.staged ?? false,
149
+ ...(request.input.base_ref ? { baseRef: request.input.base_ref } : {}),
150
+ ...(request.output_limits.diff_bytes ? { outputByteLimit: request.output_limits.diff_bytes } : {}),
151
+ },
152
+ });
153
+ const events = this.#emitRequestEvents(request, actionResult.events);
154
+ const payload = parseLocalActionResponsePayload({
155
+ ...this.#responseBase(request, events),
156
+ action: request.action,
157
+ output: {
158
+ diff: actionResult.result.stdout,
159
+ ...(actionResult.result.stdout_truncated ? { truncated: true } : {}),
160
+ },
161
+ });
162
+ return { type: "response", payload, events };
163
+ }
164
+ case "local.shell.exec": {
165
+ const actionResult = await this.#executor.shell(context, {
166
+ executable: request.input.executable,
167
+ argv: request.input.argv,
168
+ cwd: request.input.cwd,
169
+ use_shell: request.input.use_shell,
170
+ env: request.input.env ?? {},
171
+ timeout_seconds: timeoutSecondsFor(request),
172
+ ...(request.input.stdin !== undefined ? { stdin: request.input.stdin } : {}),
173
+ ...(request.output_limits.stdout_bytes ? { stdout_byte_limit: request.output_limits.stdout_bytes } : {}),
174
+ ...(request.output_limits.stderr_bytes ? { stderr_byte_limit: request.output_limits.stderr_bytes } : {}),
175
+ });
176
+ const events = this.#emitRequestEvents(request, actionResult.events);
177
+ const payload = parseLocalActionResponsePayload({
178
+ ...this.#responseBase(request, events),
179
+ action: request.action,
180
+ output: {
181
+ executable: actionResult.result.executable,
182
+ argv: actionResult.result.argv,
183
+ cwd: actionResult.result.cwd,
184
+ exit_code: actionResult.result.exit_code,
185
+ signal: actionResult.result.signal,
186
+ stdout: actionResult.result.stdout,
187
+ stderr: actionResult.result.stderr,
188
+ timed_out: actionResult.result.timed_out,
189
+ ...(actionResult.result.stdout_truncated ? { stdout_truncated: true } : {}),
190
+ ...(actionResult.result.stderr_truncated ? { stderr_truncated: true } : {}),
191
+ },
192
+ });
193
+ return { type: "response", payload, events };
194
+ }
195
+ case "local.dev_server.start": {
196
+ const actionResult = await this.#executor.startDevServer(context, {
197
+ server_id: request.input.server_id,
198
+ executable: request.input.executable,
199
+ argv: request.input.argv,
200
+ cwd: request.input.cwd,
201
+ host: request.input.host,
202
+ port: request.input.port,
203
+ use_shell: request.input.use_shell,
204
+ env: request.input.env ?? {},
205
+ timeout_seconds: timeoutSecondsFor(request),
206
+ ...(request.input.readiness ? { readiness: request.input.readiness } : {}),
207
+ session_active: () => !this.#stoppedSessionIds.has(context.session_id),
208
+ });
209
+ const events = this.#emitRequestEvents(request, actionResult.events);
210
+ const payload = parseLocalActionResponsePayload({
211
+ ...this.#responseBase(request, events),
212
+ action: request.action,
213
+ output: {
214
+ server_id: actionResult.result.server_id,
215
+ pid: actionResult.result.pid,
216
+ host: actionResult.result.host,
217
+ port: actionResult.result.port,
218
+ cwd: actionResult.result.cwd,
219
+ started_at: actionResult.result.started_at,
220
+ url: `http://${actionResult.result.host}:${actionResult.result.port}`,
221
+ },
222
+ });
223
+ return { type: "response", payload, events };
224
+ }
225
+ case "local.dev_server.stop": {
226
+ const actionResult = await this.#executor.stopDevServer(context, request.input.server_id, request.input.signal ?? "SIGTERM", request.input.timeout_ms ?? 5_000);
227
+ const events = this.#emitRequestEvents(request, actionResult.events);
228
+ const payload = parseLocalActionResponsePayload({
229
+ ...this.#responseBase(request, events),
230
+ action: request.action,
231
+ output: {
232
+ server_id: actionResult.result.server_id,
233
+ stopped_at: this.#now().toISOString(),
234
+ },
235
+ });
236
+ return { type: "response", payload, events };
237
+ }
238
+ }
239
+ }
240
+ #responseBase(request, events) {
241
+ return {
242
+ request_id: request.request_id,
243
+ status: "completed",
244
+ completed_at: this.#now().toISOString(),
245
+ attribution: request.attribution,
246
+ lease: request.lease,
247
+ audit_events: responseAuditEvents(events),
248
+ };
249
+ }
250
+ #errorOutcome(request, error, executionEvents) {
251
+ const emittedEvents = executionEvents.length > 0 ? this.#emitErrorEvents(request, executionEvents) : [];
252
+ const localError = toLocalActionError(error);
253
+ const payload = parseLocalActionErrorPayload({
254
+ request_id: request.request_id,
255
+ action: request.action,
256
+ status: localError.code === "local_capability_timeout" ? "timed_out" : localError.code === "local_capability_cancelled" ? "cancelled" : "failed",
257
+ failed_at: this.#now().toISOString(),
258
+ attribution: request.attribution,
259
+ lease: request.lease,
260
+ error: localError,
261
+ audit_events: errorAuditEvents(emittedEvents),
262
+ });
263
+ return { type: "error", payload, events: emittedEvents };
264
+ }
265
+ #emitRequestEvents(request, events) {
266
+ const enrichedEvents = events.map((event) => ({
267
+ event_type: event.event_type,
268
+ data: {
269
+ ...event.data,
270
+ input: {
271
+ request_id: request.request_id,
272
+ protocol_action: request.action,
273
+ ...(event.data.input === undefined ? {} : { details: event.data.input }),
274
+ },
275
+ },
276
+ }));
277
+ return this.#emitEvents(request.attribution.session_id, request.attribution.turn_id, enrichedEvents);
278
+ }
279
+ #emitErrorEvents(request, events) {
280
+ try {
281
+ return this.#emitRequestEvents(request, events);
282
+ }
283
+ catch (error) {
284
+ if (error instanceof LocalCapabilityPolicyError) {
285
+ return [];
286
+ }
287
+ throw error;
288
+ }
289
+ }
290
+ }
291
+ function timeoutSecondsFor(request) {
292
+ const timeoutMs = request.cancellation.timeout_ms ?? 30_000;
293
+ return Math.max(1, Math.ceil(timeoutMs / 1000));
294
+ }
295
+ function responseAuditEvents(events) {
296
+ const started = events.find((event) => event.event_type === "local_capability.action.started");
297
+ const completed = events.find((event) => event.event_type === "local_capability.action.completed");
298
+ return {
299
+ ...(started ? { started: { event_type: "local_capability.action.started", sequence: started.sequence } } : {}),
300
+ completed: completed
301
+ ? { event_type: "local_capability.action.completed", sequence: completed.sequence }
302
+ : { event_type: "local_capability.action.completed" },
303
+ };
304
+ }
305
+ function errorAuditEvents(events) {
306
+ const started = events.find((event) => event.event_type === "local_capability.action.started");
307
+ const failed = events.find((event) => event.event_type === "local_capability.action.failed");
308
+ return {
309
+ ...(started ? { started: { event_type: "local_capability.action.started", sequence: started.sequence } } : {}),
310
+ failed: failed
311
+ ? { event_type: "local_capability.action.failed", sequence: failed.sequence }
312
+ : { event_type: "local_capability.action.failed" },
313
+ };
314
+ }
315
+ function toLocalActionError(error) {
316
+ const cause = error instanceof LocalCapabilityExecutionError ? error.cause : error;
317
+ if (cause instanceof LocalCapabilityPolicyError) {
318
+ return {
319
+ code: mapPolicyErrorCode(cause.code),
320
+ message: cause.message,
321
+ retryable: false,
322
+ };
323
+ }
324
+ if (cause instanceof Error) {
325
+ return {
326
+ code: mapProcessErrorCode(cause),
327
+ message: cause.message,
328
+ retryable: false,
329
+ };
330
+ }
331
+ return {
332
+ code: "local_capability_action_failed",
333
+ message: "Local action failed.",
334
+ retryable: false,
335
+ };
336
+ }
337
+ function failedEventFor(request, error) {
338
+ return {
339
+ event_type: "local_capability.action.failed",
340
+ data: {
341
+ lease_id: request.lease.lease_id,
342
+ run_id: request.lease.run_id,
343
+ workspace_id: request.attribution.workspace_id,
344
+ provider_instance_id: request.attribution.provider_instance_id,
345
+ capability_id: request.lease.capability_id,
346
+ action: request.action,
347
+ status: "failed",
348
+ error: {
349
+ code: mapPolicyErrorCode(error.code),
350
+ message: error.message,
351
+ retryable: false,
352
+ },
353
+ },
354
+ };
355
+ }
356
+ function mapPolicyErrorCode(code) {
357
+ switch (code) {
358
+ case "local_capability_lease_missing":
359
+ case "local_capability_lease_expired":
360
+ case "local_capability_lease_revoked":
361
+ case "local_capability_session_mismatch":
362
+ case "local_capability_workspace_mismatch":
363
+ case "local_capability_provider_mismatch":
364
+ case "local_capability_scope_not_granted":
365
+ case "local_capability_approval_required":
366
+ case "local_capability_expected_hash_mismatch":
367
+ case "local_capability_output_limit_exceeded":
368
+ case "local_capability_timeout":
369
+ case "local_capability_cancelled":
370
+ case "local_capability_command_denied":
371
+ case "local_capability_dev_server_exists":
372
+ case "local_capability_dev_server_not_found":
373
+ return code;
374
+ case "local_capability_scope_unavailable":
375
+ case "local_capability_not_granted":
376
+ case "local_capability_unavailable":
377
+ case "local_capability_provider_unsupported":
378
+ case "local_capability_max_calls_exceeded":
379
+ return "local_capability_scope_not_granted";
380
+ case "local_capability_sandbox_read_only":
381
+ return "local_capability_sandbox_denied";
382
+ case "local_capability_path_denied":
383
+ case "local_capability_cwd_denied":
384
+ case "local_capability_path_unresolved":
385
+ return "local_capability_path_denied";
386
+ case "local_capability_shell_denied":
387
+ case "local_capability_timeout_exceeded":
388
+ case "local_capability_network_policy_unsupported":
389
+ case "local_capability_env_denied":
390
+ case "local_capability_executable_denied":
391
+ case "local_capability_executable_not_allowed":
392
+ case "local_capability_argv_denied":
393
+ case "local_capability_command_policy_required":
394
+ case "local_capability_command_policy_invalid":
395
+ case "local_capability_dev_server_host_denied":
396
+ case "local_capability_dev_server_port_denied":
397
+ return "local_capability_command_denied";
398
+ case "local_capability_dev_server_start_failed":
399
+ return "local_capability_process_failed";
400
+ default:
401
+ return "local_capability_action_failed";
402
+ }
403
+ }
404
+ function mapProcessErrorCode(error) {
405
+ return error.message.startsWith("spawn ") ? "local_capability_process_failed" : "local_capability_action_failed";
406
+ }
407
+ //# sourceMappingURL=dispatcher.js.map
@@ -0,0 +1,159 @@
1
+ import type { HcpEventType, LocalCapabilityLease } from "@harness-control/protocol";
2
+ import type { AuditLogger } from "../audit/index.js";
3
+ import { LocalCapabilityEngine, type LocalGitAction } from "./index.js";
4
+ export type LocalCapabilityExecutionContext = {
5
+ session_id: string;
6
+ turn_id: string;
7
+ workspace_id: string;
8
+ provider_instance_id: string;
9
+ workspace_root: string;
10
+ sandbox_mode: "read_only" | "workspace_write" | "danger_full_access";
11
+ lease: LocalCapabilityLease;
12
+ };
13
+ export type LocalCapabilityExecutionEvent = {
14
+ event_type: HcpEventType;
15
+ data: Record<string, unknown>;
16
+ };
17
+ export type LocalActionResult<TResult> = {
18
+ result: TResult;
19
+ events: LocalCapabilityExecutionEvent[];
20
+ };
21
+ export type FilesystemReadResult = {
22
+ path: string;
23
+ content: string;
24
+ encoding: "utf8" | "base64";
25
+ hash: string;
26
+ truncated?: boolean;
27
+ };
28
+ export type FilesystemReadOptions = {
29
+ encoding?: "utf8" | "base64";
30
+ range?: {
31
+ start?: number;
32
+ length?: number;
33
+ };
34
+ contentByteLimit?: number;
35
+ };
36
+ export type FilesystemListResult = {
37
+ path: string;
38
+ entries: Array<{
39
+ name: string;
40
+ type: "file" | "directory" | "other";
41
+ }>;
42
+ truncated?: boolean;
43
+ };
44
+ export type FilesystemListOptions = {
45
+ recursive?: boolean;
46
+ includeHidden?: boolean;
47
+ maxDepth?: number;
48
+ entryLimit?: number;
49
+ };
50
+ export type FilesystemWriteResult = {
51
+ path: string;
52
+ bytes_written: number;
53
+ new_hash: string;
54
+ };
55
+ export type FilesystemWriteOptions = {
56
+ encoding?: "utf8" | "base64";
57
+ mode?: "create" | "overwrite";
58
+ createParents?: boolean;
59
+ expectedBaseHash?: string;
60
+ };
61
+ export type FilesystemPatchResult = {
62
+ path: string;
63
+ changed: boolean;
64
+ new_hash: string;
65
+ };
66
+ export type FilesystemPatchOptions = {
67
+ expectedBaseHash: string;
68
+ patchContent: string;
69
+ createIfMissing?: boolean;
70
+ };
71
+ export type GitCommandResult = {
72
+ operation: LocalGitAction;
73
+ exit_code: number;
74
+ stdout: string;
75
+ stderr: string;
76
+ stdout_truncated?: boolean;
77
+ stderr_truncated?: boolean;
78
+ branch?: string;
79
+ };
80
+ export type GitCommandOptions = {
81
+ status?: {
82
+ porcelainVersion?: "v1" | "v2";
83
+ includeBranch?: boolean;
84
+ outputByteLimit?: number;
85
+ };
86
+ diff?: {
87
+ paths?: string[];
88
+ staged?: boolean;
89
+ baseRef?: string;
90
+ outputByteLimit?: number;
91
+ };
92
+ };
93
+ export type ShellCommandRequest = {
94
+ executable: string;
95
+ argv: string[];
96
+ cwd?: string;
97
+ timeout_seconds: number;
98
+ use_shell?: boolean;
99
+ env?: Record<string, string>;
100
+ stdin?: string;
101
+ stdout_byte_limit?: number;
102
+ stderr_byte_limit?: number;
103
+ session_active?: () => boolean;
104
+ signal?: AbortSignal;
105
+ };
106
+ export type ShellCommandResult = {
107
+ executable: string;
108
+ argv: string[];
109
+ cwd: string;
110
+ exit_code: number | null;
111
+ signal: NodeJS.Signals | null;
112
+ stdout: string;
113
+ stderr: string;
114
+ timed_out: boolean;
115
+ stdout_truncated?: boolean;
116
+ stderr_truncated?: boolean;
117
+ };
118
+ export type DevServerStartRequest = ShellCommandRequest & {
119
+ server_id: string;
120
+ host: string;
121
+ port: number;
122
+ readiness?: {
123
+ url?: string;
124
+ timeout_ms: number;
125
+ };
126
+ };
127
+ export type DevServerRecord = {
128
+ server_id: string;
129
+ pid: number;
130
+ host: string;
131
+ port: number;
132
+ cwd: string;
133
+ started_at: string;
134
+ };
135
+ export declare class LocalCapabilityExecutor {
136
+ #private;
137
+ constructor(engine: LocalCapabilityEngine, auditLogger?: AuditLogger);
138
+ readFile(context: LocalCapabilityExecutionContext, path: string, options?: FilesystemReadOptions): Promise<LocalActionResult<FilesystemReadResult>>;
139
+ listDirectory(context: LocalCapabilityExecutionContext, path: string, options?: FilesystemListOptions): Promise<LocalActionResult<FilesystemListResult>>;
140
+ writeFile(context: LocalCapabilityExecutionContext, path: string, content: string, options?: FilesystemWriteOptions): Promise<LocalActionResult<FilesystemWriteResult>>;
141
+ patchFile(context: LocalCapabilityExecutionContext, path: string, options: FilesystemPatchOptions): Promise<LocalActionResult<FilesystemPatchResult>>;
142
+ deletePath(context: LocalCapabilityExecutionContext, path: string): Promise<LocalActionResult<{
143
+ path: string;
144
+ }>>;
145
+ git(context: LocalCapabilityExecutionContext, operation: LocalGitAction, options?: GitCommandOptions): Promise<LocalActionResult<GitCommandResult>>;
146
+ shell(context: LocalCapabilityExecutionContext, request: ShellCommandRequest): Promise<LocalActionResult<ShellCommandResult>>;
147
+ startDevServer(context: LocalCapabilityExecutionContext, request: DevServerStartRequest): Promise<LocalActionResult<DevServerRecord>>;
148
+ stopDevServer(context: LocalCapabilityExecutionContext, serverId: string, signal?: NodeJS.Signals, timeoutMs?: number): Promise<LocalActionResult<{
149
+ server_id: string;
150
+ }>>;
151
+ listDevServers(): DevServerRecord[];
152
+ stopDevServersForSession(sessionId: string, timeoutMs?: number): Promise<void>;
153
+ }
154
+ export declare class LocalCapabilityExecutionError extends Error {
155
+ readonly events: LocalCapabilityExecutionEvent[];
156
+ readonly cause: unknown;
157
+ constructor(events: LocalCapabilityExecutionEvent[], cause: unknown);
158
+ }
159
+ //# sourceMappingURL=executors.d.ts.map