@h-rig/runtime 0.0.6-alpha.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 (176) hide show
  1. package/README.md +27 -0
  2. package/dist/bin/rig-agent-dispatch.js +9615 -0
  3. package/dist/bin/rig-agent.js +9512 -0
  4. package/dist/bin/rig-browser-tool.js +269 -0
  5. package/dist/src/agent-mode.js +48 -0
  6. package/dist/src/baked-secrets.js +121 -0
  7. package/dist/src/binary-build-worker.js +312 -0
  8. package/dist/src/binary-run.js +540 -0
  9. package/dist/src/boundaries.js +1 -0
  10. package/dist/src/build-time-config.js +25 -0
  11. package/dist/src/control-plane/agent-roles.js +27 -0
  12. package/dist/src/control-plane/agent-wrapper.js +9621 -0
  13. package/dist/src/control-plane/authority-files.js +582 -0
  14. package/dist/src/control-plane/browser-contract.js +135 -0
  15. package/dist/src/control-plane/controlled-bash.js +1111 -0
  16. package/dist/src/control-plane/errors.js +13 -0
  17. package/dist/src/control-plane/harness-main.js +10828 -0
  18. package/dist/src/control-plane/hook-materializer.js +75 -0
  19. package/dist/src/control-plane/hooks/audit-trail.js +353 -0
  20. package/dist/src/control-plane/hooks/completion-verification.js +7552 -0
  21. package/dist/src/control-plane/hooks/import-guard.js +890 -0
  22. package/dist/src/control-plane/hooks/inject-context.js +4189 -0
  23. package/dist/src/control-plane/hooks/post-edit-lint.js +43 -0
  24. package/dist/src/control-plane/hooks/safety-guard.js +910 -0
  25. package/dist/src/control-plane/hooks/scope-guard.js +907 -0
  26. package/dist/src/control-plane/hooks/shared.js +44 -0
  27. package/dist/src/control-plane/hooks/submodule-branch.js +7797 -0
  28. package/dist/src/control-plane/hooks/task-runtime-start.js +7799 -0
  29. package/dist/src/control-plane/hooks/test-integrity-guard.js +891 -0
  30. package/dist/src/control-plane/materialize-task-config.js +453 -0
  31. package/dist/src/control-plane/memory-sync/cli.js +2019 -0
  32. package/dist/src/control-plane/memory-sync/db.js +753 -0
  33. package/dist/src/control-plane/memory-sync/embed.js +281 -0
  34. package/dist/src/control-plane/memory-sync/index.js +2049 -0
  35. package/dist/src/control-plane/memory-sync/query.js +294 -0
  36. package/dist/src/control-plane/memory-sync/read.js +784 -0
  37. package/dist/src/control-plane/memory-sync/types.js +6 -0
  38. package/dist/src/control-plane/memory-sync/write.js +1547 -0
  39. package/dist/src/control-plane/native/git-native.js +490 -0
  40. package/dist/src/control-plane/native/git-ops.js +2860 -0
  41. package/dist/src/control-plane/native/harness-cli.js +9721 -0
  42. package/dist/src/control-plane/native/pr-automation.js +373 -0
  43. package/dist/src/control-plane/native/profile-ops.js +481 -0
  44. package/dist/src/control-plane/native/repo-ops.js +2342 -0
  45. package/dist/src/control-plane/native/root-resolver.js +66 -0
  46. package/dist/src/control-plane/native/run-ops.js +3281 -0
  47. package/dist/src/control-plane/native/runtime-native-sidecar.js +299 -0
  48. package/dist/src/control-plane/native/runtime-native.js +392 -0
  49. package/dist/src/control-plane/native/scope-rules.js +17 -0
  50. package/dist/src/control-plane/native/task-ops.js +6320 -0
  51. package/dist/src/control-plane/native/task-state.js +1512 -0
  52. package/dist/src/control-plane/native/utils.js +535 -0
  53. package/dist/src/control-plane/native/validator-binaries.js +889 -0
  54. package/dist/src/control-plane/native/validator.js +2197 -0
  55. package/dist/src/control-plane/native/verifier.js +3249 -0
  56. package/dist/src/control-plane/native/workspace-ops.js +1635 -0
  57. package/dist/src/control-plane/plugin-host-context.js +334 -0
  58. package/dist/src/control-plane/project-main-pre-run-sync.js +630 -0
  59. package/dist/src/control-plane/provider/claude-stream-records.js +158 -0
  60. package/dist/src/control-plane/provider/codex-app-server.js +885 -0
  61. package/dist/src/control-plane/provider/codex-exec-records.js +203 -0
  62. package/dist/src/control-plane/provider/rig-task-run-skill.js +39 -0
  63. package/dist/src/control-plane/provider/runtime-instructions.js +96 -0
  64. package/dist/src/control-plane/remote.js +854 -0
  65. package/dist/src/control-plane/repos/index.js +473 -0
  66. package/dist/src/control-plane/repos/layout.js +124 -0
  67. package/dist/src/control-plane/repos/mirror/bootstrap.js +268 -0
  68. package/dist/src/control-plane/repos/mirror/refresh.js +398 -0
  69. package/dist/src/control-plane/repos/mirror/state.js +167 -0
  70. package/dist/src/control-plane/repos/registry.js +77 -0
  71. package/dist/src/control-plane/repos/types.js +1 -0
  72. package/dist/src/control-plane/runtime/agent-mode.js +48 -0
  73. package/dist/src/control-plane/runtime/baked-secrets.js +120 -0
  74. package/dist/src/control-plane/runtime/claude-tool-router-binary.js +343 -0
  75. package/dist/src/control-plane/runtime/claude-tool-router.js +520 -0
  76. package/dist/src/control-plane/runtime/context.js +216 -0
  77. package/dist/src/control-plane/runtime/events.js +218 -0
  78. package/dist/src/control-plane/runtime/guard-types.js +6 -0
  79. package/dist/src/control-plane/runtime/guard.js +880 -0
  80. package/dist/src/control-plane/runtime/image/fingerprint-sidecar.js +1194 -0
  81. package/dist/src/control-plane/runtime/image/index.js +2255 -0
  82. package/dist/src/control-plane/runtime/image-fingerprint-sidecar.js +1191 -0
  83. package/dist/src/control-plane/runtime/image.js +2255 -0
  84. package/dist/src/control-plane/runtime/index.js +8511 -0
  85. package/dist/src/control-plane/runtime/isolation/discovery.js +599 -0
  86. package/dist/src/control-plane/runtime/isolation/home.js +1217 -0
  87. package/dist/src/control-plane/runtime/isolation/index.js +8193 -0
  88. package/dist/src/control-plane/runtime/isolation/runner.js +2651 -0
  89. package/dist/src/control-plane/runtime/isolation/shared.js +501 -0
  90. package/dist/src/control-plane/runtime/isolation/toolchain.js +1892 -0
  91. package/dist/src/control-plane/runtime/isolation/types.js +1 -0
  92. package/dist/src/control-plane/runtime/isolation/worktree.js +509 -0
  93. package/dist/src/control-plane/runtime/isolation.js +8193 -0
  94. package/dist/src/control-plane/runtime/overlay.js +67 -0
  95. package/dist/src/control-plane/runtime/plugin-mode.js +41 -0
  96. package/dist/src/control-plane/runtime/plugins.js +1131 -0
  97. package/dist/src/control-plane/runtime/provisioning-env.js +220 -0
  98. package/dist/src/control-plane/runtime/queue.js +8358 -0
  99. package/dist/src/control-plane/runtime/rig-shell.js +205 -0
  100. package/dist/src/control-plane/runtime/rig-tools.js +182 -0
  101. package/dist/src/control-plane/runtime/runner-context.js +1 -0
  102. package/dist/src/control-plane/runtime/runtime-paths.js +184 -0
  103. package/dist/src/control-plane/runtime/sandbox/backend-bwrap.js +311 -0
  104. package/dist/src/control-plane/runtime/sandbox/backend-none.js +21 -0
  105. package/dist/src/control-plane/runtime/sandbox/backend-seatbelt.js +268 -0
  106. package/dist/src/control-plane/runtime/sandbox/backend.js +1718 -0
  107. package/dist/src/control-plane/runtime/sandbox/orchestrator.js +1745 -0
  108. package/dist/src/control-plane/runtime/sandbox/utils.js +137 -0
  109. package/dist/src/control-plane/runtime/sandbox-backend-bwrap.js +311 -0
  110. package/dist/src/control-plane/runtime/sandbox-backend-none.js +21 -0
  111. package/dist/src/control-plane/runtime/sandbox-backend-seatbelt.js +268 -0
  112. package/dist/src/control-plane/runtime/sandbox-backend.js +1718 -0
  113. package/dist/src/control-plane/runtime/sandbox-orchestrator.js +1745 -0
  114. package/dist/src/control-plane/runtime/sandbox-utils.js +137 -0
  115. package/dist/src/control-plane/runtime/snapshot/index.js +454 -0
  116. package/dist/src/control-plane/runtime/snapshot/sidecar.js +502 -0
  117. package/dist/src/control-plane/runtime/snapshot/task-run.js +1578 -0
  118. package/dist/src/control-plane/runtime/snapshot-sidecar.js +498 -0
  119. package/dist/src/control-plane/runtime/snapshot.js +454 -0
  120. package/dist/src/control-plane/runtime/task-run-snapshot.js +1578 -0
  121. package/dist/src/control-plane/runtime/tool-gateway.js +422 -0
  122. package/dist/src/control-plane/runtime/tooling/browser-tools.js +32 -0
  123. package/dist/src/control-plane/runtime/tooling/claude-router-binary.js +343 -0
  124. package/dist/src/control-plane/runtime/tooling/claude-router.js +524 -0
  125. package/dist/src/control-plane/runtime/tooling/file-tools.js +182 -0
  126. package/dist/src/control-plane/runtime/tooling/gateway.js +422 -0
  127. package/dist/src/control-plane/runtime/tooling/index.js +1290 -0
  128. package/dist/src/control-plane/runtime/tooling/shell.js +205 -0
  129. package/dist/src/control-plane/runtime/types.js +1 -0
  130. package/dist/src/control-plane/setup-version.js +14 -0
  131. package/dist/src/control-plane/state-sync/index.js +1509 -0
  132. package/dist/src/control-plane/state-sync/read.js +856 -0
  133. package/dist/src/control-plane/state-sync/reconcile.js +260 -0
  134. package/dist/src/control-plane/state-sync/repo.js +302 -0
  135. package/dist/src/control-plane/state-sync/types.js +111 -0
  136. package/dist/src/control-plane/state-sync/write.js +1469 -0
  137. package/dist/src/control-plane/task-fields.js +38 -0
  138. package/dist/src/control-plane/task-source-bootstrap.js +46 -0
  139. package/dist/src/control-plane/task-source.js +30 -0
  140. package/dist/src/control-plane/tasks/legacy-task-config-source.js +130 -0
  141. package/dist/src/control-plane/tasks/plugin-task-source.js +103 -0
  142. package/dist/src/control-plane/tasks/source-aware-task-config-source.js +611 -0
  143. package/dist/src/control-plane/tasks/source-lifecycle.js +1093 -0
  144. package/dist/src/control-plane/tasks/task-record-reader.js +9 -0
  145. package/dist/src/control-plane/validators/boundary/public-apis.js +107 -0
  146. package/dist/src/control-plane/validators/integration/_shared.js +51 -0
  147. package/dist/src/control-plane/validators/integration/adm-audit-http.js +85 -0
  148. package/dist/src/control-plane/validators/integration/adm-auth-http.js +78 -0
  149. package/dist/src/control-plane/validators/integration/adm-issuer-http.js +80 -0
  150. package/dist/src/control-plane/validators/integration/adm-migration.js +78 -0
  151. package/dist/src/control-plane/validators/integration/adm-scaffold.js +78 -0
  152. package/dist/src/control-plane/validators/runtime-registration.js +64 -0
  153. package/dist/src/control-plane/validators/shared.js +683 -0
  154. package/dist/src/events.js +218 -0
  155. package/dist/src/execution.js +35 -0
  156. package/dist/src/index.js +1633 -0
  157. package/dist/src/layout.js +145 -0
  158. package/dist/src/local-server.js +202 -0
  159. package/dist/src/plugins.js +329 -0
  160. package/dist/src/remote-http.js +83 -0
  161. package/dist/src/runtime-context.js +216 -0
  162. package/dist/src/types.js +1 -0
  163. package/native/darwin-arm64/bin/rig-git +0 -0
  164. package/native/darwin-arm64/bin/rig-shell +0 -0
  165. package/native/darwin-arm64/bin/rig-tools +0 -0
  166. package/native/darwin-arm64/lib/runtime-native-darwin-arm64.dylib +0 -0
  167. package/native/darwin-arm64/lib/runtime-native.dylib +0 -0
  168. package/native/darwin-arm64/manifest.json +1 -0
  169. package/native/linux-x64/bin/rig-git +0 -0
  170. package/native/linux-x64/bin/rig-shell +0 -0
  171. package/native/linux-x64/bin/rig-tools +0 -0
  172. package/native/linux-x64/lib/runtime-native-linux-x64.so +0 -0
  173. package/native/linux-x64/lib/runtime-native.so +0 -0
  174. package/native/linux-x64/manifest.json +1 -0
  175. package/package.json +74 -0
  176. package/skills/rig-task-run.md +71 -0
@@ -0,0 +1,885 @@
1
+ // @bun
2
+ // packages/runtime/src/control-plane/provider/codex-app-server.ts
3
+ import { spawn } from "child_process";
4
+ import { createInterface } from "readline";
5
+
6
+ // packages/runtime/src/control-plane/runtime/tooling/claude-router.ts
7
+ import { existsSync, mkdirSync, statSync, writeFileSync } from "fs";
8
+ import { resolve } from "path";
9
+ var CLAUDE_ROUTER_TOOL_DEFINITIONS = [
10
+ {
11
+ name: "read",
12
+ description: "Read a UTF-8 file from the current Rig task worktree, the outer control-plane repo ($PROJECT_RIG_ROOT), or the host monorepo checkout ($MONOREPO_MAIN_ROOT).",
13
+ inputSchema: {
14
+ type: "object",
15
+ properties: {
16
+ path: { type: "string", description: "Absolute or workspace-relative file path." },
17
+ offset: { type: "integer", minimum: 0 },
18
+ limit: { type: "integer", minimum: 1, maximum: 2097152 }
19
+ },
20
+ required: ["path"],
21
+ additionalProperties: false
22
+ }
23
+ },
24
+ {
25
+ name: "write",
26
+ description: "Write UTF-8 content to a file inside the current Rig task workspace only.",
27
+ inputSchema: {
28
+ type: "object",
29
+ properties: {
30
+ path: { type: "string", description: "Absolute or workspace-relative file path." },
31
+ content: { type: "string" },
32
+ create_parents: { type: "boolean" }
33
+ },
34
+ required: ["path", "content"],
35
+ additionalProperties: false
36
+ }
37
+ },
38
+ {
39
+ name: "edit",
40
+ description: "Replace one or more exact string occurrences in a UTF-8 file inside the current Rig task workspace only.",
41
+ inputSchema: {
42
+ type: "object",
43
+ properties: {
44
+ path: { type: "string", description: "Absolute or workspace-relative file path." },
45
+ old_string: { type: "string" },
46
+ new_string: { type: "string" },
47
+ replace_all: { type: "boolean" }
48
+ },
49
+ required: ["path", "old_string", "new_string"],
50
+ additionalProperties: false
51
+ }
52
+ },
53
+ {
54
+ name: "glob",
55
+ description: "Search files using a glob pattern across the current task worktree, $PROJECT_RIG_ROOT, or $MONOREPO_MAIN_ROOT.",
56
+ inputSchema: {
57
+ type: "object",
58
+ properties: {
59
+ pattern: { type: "string" },
60
+ path: { type: "string", description: "Optional workspace-relative search root." },
61
+ include_hidden: { type: "boolean" },
62
+ max_results: { type: "integer", minimum: 1, maximum: 5000 }
63
+ },
64
+ required: ["pattern"],
65
+ additionalProperties: false
66
+ }
67
+ },
68
+ {
69
+ name: "grep",
70
+ description: "Search file contents across the current task worktree, $PROJECT_RIG_ROOT, or $MONOREPO_MAIN_ROOT.",
71
+ inputSchema: {
72
+ type: "object",
73
+ properties: {
74
+ pattern: { type: "string" },
75
+ path: { type: "string", description: "Optional workspace-relative search root." },
76
+ literal: { type: "boolean" },
77
+ include_hidden: { type: "boolean" },
78
+ max_results: { type: "integer", minimum: 1, maximum: 500 },
79
+ glob: { type: "string", description: "Optional file glob filter passed through to ripgrep." }
80
+ },
81
+ required: ["pattern"],
82
+ additionalProperties: false
83
+ }
84
+ }
85
+ ];
86
+ async function invokeRuntimeTool(toolName, args, options = {}) {
87
+ if (toolName === "shell") {
88
+ return invokeRuntimeShellTool(args, options);
89
+ }
90
+ const invocationEnv = options.env ?? process.env;
91
+ const binaryPath = resolveRuntimeToolBinary(toolName, invocationEnv);
92
+ if (!binaryPath) {
93
+ return {
94
+ content: [
95
+ {
96
+ type: "text",
97
+ text: `Unknown Rig runtime tool: ${toolName}`
98
+ }
99
+ ],
100
+ isError: true
101
+ };
102
+ }
103
+ const proc = Bun.spawn([binaryPath], {
104
+ stdin: "pipe",
105
+ stdout: "pipe",
106
+ stderr: "pipe",
107
+ env: invocationEnv
108
+ });
109
+ const requestBody = `${JSON.stringify(args)}
110
+ `;
111
+ if (proc.stdin) {
112
+ await proc.stdin.write(requestBody);
113
+ await proc.stdin.end();
114
+ }
115
+ const [exitCode, stdout, stderr] = await Promise.all([
116
+ proc.exited,
117
+ readBunProcessPipe(proc.stdout),
118
+ readBunProcessPipe(proc.stderr)
119
+ ]);
120
+ if (exitCode !== 0) {
121
+ const text = [stdout.trim(), stderr.trim()].filter(Boolean).join(`
122
+ `) || `Tool ${toolName} exited with code ${exitCode}`;
123
+ return {
124
+ content: [{ type: "text", text }],
125
+ isError: true
126
+ };
127
+ }
128
+ let payload;
129
+ try {
130
+ payload = JSON.parse(stdout);
131
+ } catch {
132
+ return {
133
+ content: [{ type: "text", text: stdout.trim() || `(empty output from ${toolName})` }],
134
+ isError: false
135
+ };
136
+ }
137
+ if (payload.ok === false) {
138
+ return {
139
+ content: [{ type: "text", text: String(payload.message ?? `Tool ${toolName} failed`) }],
140
+ structuredContent: payload,
141
+ isError: true
142
+ };
143
+ }
144
+ return {
145
+ content: [{ type: "text", text: renderToolText(toolName, payload) }],
146
+ structuredContent: payload,
147
+ isError: false
148
+ };
149
+ }
150
+ async function readBunProcessPipe(pipe) {
151
+ if (typeof pipe === "number" || !pipe) {
152
+ return "";
153
+ }
154
+ return new Response(pipe).text();
155
+ }
156
+ function resolveRuntimeToolBinary(toolName, env) {
157
+ const binDir = env.RIG_RUNTIME_BIN_DIR?.trim() || "";
158
+ if (!binDir) {
159
+ return "";
160
+ }
161
+ const mapping = {
162
+ read: "rig-read",
163
+ write: "rig-write",
164
+ edit: "rig-edit",
165
+ glob: "rig-glob",
166
+ grep: "rig-grep"
167
+ };
168
+ const executable = mapping[toolName];
169
+ return executable ? resolve(binDir, executable) : "";
170
+ }
171
+ function renderToolText(toolName, payload) {
172
+ if (toolName === "shell") {
173
+ const command = typeof payload.command === "string" ? payload.command : "(unknown command)";
174
+ const stdout = typeof payload.stdout === "string" ? payload.stdout.trim() : "";
175
+ const stderr = typeof payload.stderr === "string" ? payload.stderr.trim() : "";
176
+ const exitCode = typeof payload.exit_code === "number" ? payload.exit_code : null;
177
+ const output = [stdout, stderr].filter(Boolean).join(`
178
+ `);
179
+ const summary = exitCode === null ? command : `${command}
180
+
181
+ exit_code=${String(exitCode)}`;
182
+ return output ? `${summary}
183
+
184
+ ${output}` : summary;
185
+ }
186
+ if (toolName === "read") {
187
+ const path = typeof payload.path === "string" ? payload.path : "(unknown path)";
188
+ const content = typeof payload.content === "string" ? payload.content : "";
189
+ const truncated = payload.truncated === true ? `
190
+
191
+ [truncated]` : "";
192
+ return `${path}
193
+
194
+ ${content}${truncated}`;
195
+ }
196
+ if (toolName === "glob") {
197
+ const matches = Array.isArray(payload.matches) ? payload.matches.filter((value) => typeof value === "string") : [];
198
+ return matches.length > 0 ? matches.join(`
199
+ `) : "(no matches)";
200
+ }
201
+ if (toolName === "grep") {
202
+ const matches = Array.isArray(payload.matches) ? payload.matches.filter(isRecord) : [];
203
+ if (matches.length === 0) {
204
+ return "(no matches)";
205
+ }
206
+ return matches.map((match) => `${String(match.path ?? "(unknown)")}:${String(match.line_number ?? "?")}: ${String(match.line ?? "")}`).join(`
207
+ `);
208
+ }
209
+ if (toolName === "write") {
210
+ return `Wrote ${String(payload.bytes_written ?? 0)} bytes to ${String(payload.path ?? "(unknown path)")}.`;
211
+ }
212
+ if (toolName === "edit") {
213
+ return `Edited ${String(payload.path ?? "(unknown path)")}; replacements: ${String(payload.replacements ?? 0)}.`;
214
+ }
215
+ return JSON.stringify(payload, null, 2);
216
+ }
217
+ async function invokeRuntimeShellTool(args, options = {}) {
218
+ const command = typeof args.command === "string" ? args.command.trim() : "";
219
+ if (!command) {
220
+ return {
221
+ content: [{ type: "text", text: "Missing required shell `command` string." }],
222
+ isError: true
223
+ };
224
+ }
225
+ const invocationEnv = options.env ?? process.env;
226
+ const shellName = args.shell === "sh" ? "sh" : args.shell === "zsh" ? "zsh" : "bash";
227
+ const shellBinary = resolveRuntimeShellBinary(shellName, invocationEnv);
228
+ if (!shellBinary) {
229
+ return {
230
+ content: [{ type: "text", text: `Missing Rig runtime shell binary for ${shellName}.` }],
231
+ isError: true
232
+ };
233
+ }
234
+ const workspaceRoot = resolve(invocationEnv.RIG_TASK_WORKSPACE?.trim() || process.cwd());
235
+ const requestedWorkdir = typeof args.workdir === "string" ? args.workdir.trim() : "";
236
+ const workdir = requestedWorkdir ? resolveWithinWorkspace(workspaceRoot, requestedWorkdir) : workspaceRoot;
237
+ if (!existsSync(workdir)) {
238
+ return {
239
+ content: [{
240
+ type: "text",
241
+ text: `Shell workdir does not exist inside the task workspace: ${requestedWorkdir || "."}`
242
+ }],
243
+ isError: true
244
+ };
245
+ }
246
+ try {
247
+ if (!statSync(workdir).isDirectory()) {
248
+ return {
249
+ content: [{
250
+ type: "text",
251
+ text: `Shell workdir is not a directory inside the task workspace: ${requestedWorkdir || "."}`
252
+ }],
253
+ isError: true
254
+ };
255
+ }
256
+ } catch (error) {
257
+ return {
258
+ content: [{
259
+ type: "text",
260
+ text: error instanceof Error ? error.message : String(error)
261
+ }],
262
+ isError: true
263
+ };
264
+ }
265
+ let proc = null;
266
+ try {
267
+ proc = Bun.spawn([shellBinary, shellName === "bash" ? "-lc" : "-c", command], {
268
+ cwd: workdir,
269
+ env: invocationEnv,
270
+ stdout: "pipe",
271
+ stderr: "pipe"
272
+ });
273
+ } catch (error) {
274
+ return {
275
+ content: [{
276
+ type: "text",
277
+ text: error instanceof Error ? error.message : String(error)
278
+ }],
279
+ isError: true
280
+ };
281
+ }
282
+ const [exitCode, stdout, stderr] = await Promise.all([
283
+ proc.exited,
284
+ readBunProcessPipe(proc.stdout),
285
+ readBunProcessPipe(proc.stderr)
286
+ ]);
287
+ const payload = {
288
+ ok: exitCode === 0,
289
+ shell: shellName,
290
+ cwd: workdir,
291
+ command,
292
+ stdout,
293
+ stderr,
294
+ exit_code: exitCode
295
+ };
296
+ return {
297
+ content: [{ type: "text", text: renderToolText("shell", payload) }],
298
+ structuredContent: payload,
299
+ isError: exitCode !== 0
300
+ };
301
+ }
302
+ function resolveRuntimeShellBinary(shellName, env) {
303
+ const binDir = env.RIG_RUNTIME_BIN_DIR?.trim() || "";
304
+ return binDir ? resolve(binDir, shellName) : "";
305
+ }
306
+ function resolveWithinWorkspace(workspaceRoot, target) {
307
+ const resolvedTarget = resolve(workspaceRoot, normalizeWorkspaceRelativeTarget(target));
308
+ const normalizedWorkspace = workspaceRoot.endsWith("/") ? workspaceRoot : `${workspaceRoot}/`;
309
+ const normalizedTarget = resolvedTarget.endsWith("/") ? resolvedTarget : `${resolvedTarget}/`;
310
+ if (resolvedTarget === workspaceRoot || normalizedTarget.startsWith(normalizedWorkspace)) {
311
+ return resolvedTarget;
312
+ }
313
+ throw new Error(`Shell workdir must stay inside the task workspace: ${target}`);
314
+ }
315
+ function normalizeWorkspaceRelativeTarget(target) {
316
+ const trimmed = target.trim();
317
+ if (!trimmed) {
318
+ return ".";
319
+ }
320
+ if (trimmed === "$MONOREPO_ROOT" || trimmed === "$RIG_TASK_WORKSPACE") {
321
+ return ".";
322
+ }
323
+ if (trimmed.startsWith("$MONOREPO_ROOT/")) {
324
+ return trimmed.slice("$MONOREPO_ROOT/".length);
325
+ }
326
+ if (trimmed.startsWith("$RIG_TASK_WORKSPACE/")) {
327
+ return trimmed.slice("$RIG_TASK_WORKSPACE/".length);
328
+ }
329
+ if (trimmed === "repos/spliter-monorepo") {
330
+ return ".";
331
+ }
332
+ if (trimmed.startsWith("repos/spliter-monorepo/")) {
333
+ return trimmed.slice("repos/spliter-monorepo/".length);
334
+ }
335
+ return trimmed;
336
+ }
337
+ function isRecord(value) {
338
+ return typeof value === "object" && value !== null && !Array.isArray(value);
339
+ }
340
+ if (false) {}
341
+
342
+ // packages/runtime/src/control-plane/provider/codex-app-server.ts
343
+ var CODEX_APP_SERVER_TASK_RUN_SENTINEL = "__rig_codex_app_server_task_run__";
344
+ var RIG_DYNAMIC_TOOL_SERVER = "rig_runtime_tools";
345
+ var DEFAULT_CLIENT_INFO = {
346
+ name: "rig_task_runtime",
347
+ title: "Rig Task Runtime",
348
+ version: "0.1.0"
349
+ };
350
+ var CODEX_APP_SERVER_DISABLED_FEATURES = [
351
+ "shell_tool",
352
+ "apply_patch_freeform",
353
+ "request_permissions_tool",
354
+ "apps",
355
+ "plugins",
356
+ "tool_search",
357
+ "js_repl",
358
+ "js_repl_tools_only",
359
+ "collab"
360
+ ];
361
+ function buildCodexAppServerArgs() {
362
+ return [
363
+ "app-server",
364
+ ...CODEX_APP_SERVER_DISABLED_FEATURES.flatMap((feature) => ["--disable", feature]),
365
+ "-c",
366
+ 'web_search="disabled"',
367
+ "-c",
368
+ "tools.view_image=false",
369
+ "-c",
370
+ "features.default_mode_request_user_input=false"
371
+ ];
372
+ }
373
+ function parseCodexAppServerTaskRunArgs(argv) {
374
+ if (argv[0] !== CODEX_APP_SERVER_TASK_RUN_SENTINEL) {
375
+ return null;
376
+ }
377
+ let model;
378
+ let prompt;
379
+ let runtimeMode = "workspace-write";
380
+ let interactionMode;
381
+ for (let index = 1;index < argv.length; index += 1) {
382
+ const current = argv[index];
383
+ if (current === "--model") {
384
+ model = argv[index + 1];
385
+ index += 1;
386
+ continue;
387
+ }
388
+ if (current === "--runtime-mode") {
389
+ runtimeMode = argv[index + 1] ?? runtimeMode;
390
+ index += 1;
391
+ continue;
392
+ }
393
+ if (current === "--interaction-mode") {
394
+ interactionMode = argv[index + 1];
395
+ index += 1;
396
+ continue;
397
+ }
398
+ if (current === "--prompt") {
399
+ prompt = argv[index + 1];
400
+ index += 1;
401
+ continue;
402
+ }
403
+ }
404
+ if (!prompt?.trim()) {
405
+ throw new Error("Missing `--prompt` for Codex app-server task run.");
406
+ }
407
+ return {
408
+ model: model?.trim() ? model.trim() : undefined,
409
+ prompt,
410
+ runtimeMode,
411
+ interactionMode
412
+ };
413
+ }
414
+ async function runCodexAppServerTaskRun(options) {
415
+ const child = spawn(options.codexBinary, options.launchArgs, {
416
+ cwd: options.cwd,
417
+ env: sanitizeEnv(options.env),
418
+ stdio: ["pipe", "pipe", "pipe"]
419
+ });
420
+ const pendingResponses = new Map;
421
+ const dynamicToolResults = new Map;
422
+ const agentMessageText = new Map;
423
+ const inFlightToolCalls = new Set;
424
+ let nextRequestId = 1;
425
+ let sendQueue = Promise.resolve();
426
+ const completionState = { current: null };
427
+ const stdout = createInterface({ input: child.stdout });
428
+ const stderr = createInterface({ input: child.stderr });
429
+ const sendMessage = (payload) => {
430
+ const line = `${JSON.stringify(payload)}
431
+ `;
432
+ sendQueue = sendQueue.then(() => writeChildLine(child, line));
433
+ return sendQueue;
434
+ };
435
+ const sendRequest = async (method, params) => {
436
+ const id = nextRequestId;
437
+ nextRequestId += 1;
438
+ const resultPromise = new Promise((resolve2, reject) => {
439
+ pendingResponses.set(id, { resolve: resolve2, reject });
440
+ });
441
+ await sendMessage({ id, method, params });
442
+ return resultPromise;
443
+ };
444
+ const sendResponse = async (id, result) => {
445
+ await sendMessage({ id, result });
446
+ };
447
+ const sendError = async (id, message) => {
448
+ await sendMessage({
449
+ id,
450
+ error: {
451
+ code: -32603,
452
+ message
453
+ }
454
+ });
455
+ };
456
+ const trackToolCall = (call) => {
457
+ inFlightToolCalls.add(call);
458
+ call.finally(() => inFlightToolCalls.delete(call)).catch((err) => {
459
+ console.warn("[codex-app-server] in-flight tool call failure:", err);
460
+ });
461
+ };
462
+ const handleNotification = (message) => {
463
+ const method = message.method;
464
+ if (!method) {
465
+ return;
466
+ }
467
+ const params = message.params ?? {};
468
+ const timestamp = new Date().toISOString();
469
+ if (method === "thread/started") {
470
+ emitSyntheticCodexRecord({
471
+ type: "thread.started",
472
+ timestamp,
473
+ thread: params.thread ?? null
474
+ });
475
+ return;
476
+ }
477
+ if (method === "turn/started") {
478
+ emitSyntheticCodexRecord({
479
+ type: "turn.started",
480
+ timestamp,
481
+ turn: params.turn ?? null
482
+ });
483
+ return;
484
+ }
485
+ if (method === "item/agentMessage/delta") {
486
+ const itemId = normalizeString(params.itemId);
487
+ const delta = typeof params.delta === "string" ? params.delta : "";
488
+ if (!itemId || delta.length === 0) {
489
+ return;
490
+ }
491
+ agentMessageText.set(itemId, `${agentMessageText.get(itemId) ?? ""}${delta}`);
492
+ emitSyntheticCodexRecord({
493
+ type: "stream_event",
494
+ event: {
495
+ delta: {
496
+ type: "text_delta",
497
+ text: delta
498
+ }
499
+ }
500
+ });
501
+ return;
502
+ }
503
+ if (method === "item/started" || method === "item/completed") {
504
+ const record = mapAppServerItemToCodexRecord({
505
+ phase: method === "item/started" ? "item.started" : "item.completed",
506
+ timestamp,
507
+ item: params.item,
508
+ dynamicToolResults,
509
+ agentMessageText
510
+ });
511
+ if (record) {
512
+ emitSyntheticCodexRecord(record);
513
+ }
514
+ return;
515
+ }
516
+ if (method === "turn/completed") {
517
+ const turn = asRecord(params.turn);
518
+ const error = asRecord(turn?.error);
519
+ completionState.current = {
520
+ status: normalizeString(turn?.status) ?? "failed",
521
+ error: normalizeString(error?.message)
522
+ };
523
+ emitSyntheticCodexRecord({
524
+ type: "turn.completed",
525
+ timestamp,
526
+ turn
527
+ });
528
+ return;
529
+ }
530
+ if (method === "error") {
531
+ const errorMessage = normalizeString(params.message) ?? JSON.stringify(params);
532
+ console.error(`[rig-codex-app-server] ${errorMessage}`);
533
+ }
534
+ };
535
+ const handleServerRequest = (message) => {
536
+ const method = message.method;
537
+ const requestId = message.id;
538
+ if (!method || requestId === undefined) {
539
+ return;
540
+ }
541
+ if (method === "item/tool/call") {
542
+ const params = message.params ?? {};
543
+ const callId = normalizeString(params.callId);
544
+ const toolName = normalizeString(params.tool);
545
+ const toolArgs = asRecord(params.arguments) ?? {};
546
+ const toolCall = (async () => {
547
+ if (!callId || !toolName) {
548
+ await sendError(requestId, "Malformed dynamic tool call.");
549
+ return;
550
+ }
551
+ try {
552
+ const invocation = await invokeRuntimeTool(toolName, toolArgs, {
553
+ env: options.env
554
+ });
555
+ const contentItems = invocationToContentItems(invocation);
556
+ const contentText = contentItems.filter((item) => item.type === "inputText").map((item) => item.text).join(`
557
+ `).trim();
558
+ dynamicToolResults.set(callId, {
559
+ isError: invocation.isError === true,
560
+ contentText,
561
+ structuredResult: asRecord(invocation.structuredContent) ?? (contentText ? { content: contentText } : null)
562
+ });
563
+ await sendResponse(requestId, {
564
+ contentItems,
565
+ success: invocation.isError !== true
566
+ });
567
+ } catch (error) {
568
+ const messageText = error instanceof Error ? error.message : String(error);
569
+ dynamicToolResults.set(callId, {
570
+ isError: true,
571
+ contentText: messageText,
572
+ structuredResult: { error: messageText }
573
+ });
574
+ await sendResponse(requestId, {
575
+ contentItems: [{ type: "inputText", text: messageText }],
576
+ success: false
577
+ });
578
+ }
579
+ })();
580
+ trackToolCall(toolCall);
581
+ return;
582
+ }
583
+ if (method === "item/commandExecution/requestApproval" || method === "item/fileChange/requestApproval") {
584
+ trackToolCall(sendResponse(requestId, { decision: "decline" }));
585
+ return;
586
+ }
587
+ if (method === "item/permissions/requestApproval") {
588
+ trackToolCall(sendResponse(requestId, {
589
+ permissions: {},
590
+ scope: "turn"
591
+ }));
592
+ return;
593
+ }
594
+ if (method === "applyPatchApproval" || method === "execCommandApproval") {
595
+ trackToolCall(sendResponse(requestId, { decision: "denied" }));
596
+ return;
597
+ }
598
+ trackToolCall(sendError(requestId, `Unsupported app-server request: ${method}`));
599
+ };
600
+ stdout.on("line", (line) => {
601
+ const trimmed = line.trim();
602
+ if (!trimmed) {
603
+ return;
604
+ }
605
+ let message;
606
+ try {
607
+ message = JSON.parse(trimmed);
608
+ } catch {
609
+ console.error(trimmed);
610
+ return;
611
+ }
612
+ if (message.method) {
613
+ if (message.id !== undefined) {
614
+ handleServerRequest(message);
615
+ } else {
616
+ handleNotification(message);
617
+ }
618
+ return;
619
+ }
620
+ if (message.id !== undefined) {
621
+ const pending = pendingResponses.get(message.id);
622
+ if (!pending) {
623
+ return;
624
+ }
625
+ pendingResponses.delete(message.id);
626
+ if (message.error) {
627
+ pending.reject(new Error(formatJsonRpcError(message.error)));
628
+ } else {
629
+ pending.resolve(message.result ?? {});
630
+ }
631
+ }
632
+ });
633
+ stderr.on("line", (line) => {
634
+ if (line.trim()) {
635
+ console.error(line);
636
+ }
637
+ });
638
+ const exitPromise = new Promise((resolve2) => {
639
+ child.once("close", (code, signal) => resolve2({ code, signal }));
640
+ });
641
+ await sendRequest("initialize", {
642
+ clientInfo: DEFAULT_CLIENT_INFO,
643
+ capabilities: {
644
+ experimentalApi: true
645
+ }
646
+ });
647
+ await sendMessage({
648
+ method: "initialized",
649
+ params: {}
650
+ });
651
+ const threadStart = await sendRequest("thread/start", {
652
+ model: options.config.model ?? null,
653
+ cwd: options.cwd,
654
+ approvalPolicy: "never",
655
+ sandbox: options.config.runtimeMode === "full-access" ? "danger-full-access" : "workspace-write",
656
+ serviceName: "rig_task_runtime",
657
+ experimentalRawEvents: false,
658
+ persistExtendedHistory: false,
659
+ dynamicTools: codexDynamicToolDefinitions()
660
+ });
661
+ const thread = asRecord(threadStart.thread);
662
+ const threadId = normalizeString(thread?.id);
663
+ if (!threadId) {
664
+ throw new Error("Codex app-server thread/start did not return a thread id.");
665
+ }
666
+ await sendRequest("turn/start", {
667
+ threadId,
668
+ input: [
669
+ {
670
+ type: "text",
671
+ text: options.config.prompt,
672
+ text_elements: []
673
+ }
674
+ ]
675
+ });
676
+ let exitResult = null;
677
+ while (!completionState.current) {
678
+ exitResult = await Promise.race([
679
+ exitPromise,
680
+ new Promise((resolve2) => setTimeout(() => resolve2(null), 100))
681
+ ]);
682
+ if (exitResult) {
683
+ break;
684
+ }
685
+ }
686
+ const completedTurn = completionState.current;
687
+ if (!completedTurn) {
688
+ const detail = exitResult ? `codex app-server exited before turn completion (${String(exitResult.code ?? exitResult.signal ?? "unknown")})` : "codex app-server exited before turn completion";
689
+ throw new Error(detail);
690
+ }
691
+ if (inFlightToolCalls.size > 0) {
692
+ await Promise.allSettled(Array.from(inFlightToolCalls));
693
+ }
694
+ terminateChild(child);
695
+ await exitPromise;
696
+ if (completedTurn.status !== "completed") {
697
+ const reason = completedTurn.error ?? `Codex turn ended with status ${completedTurn.status}`;
698
+ console.error(`[rig-codex-app-server] ${reason}`);
699
+ return 1;
700
+ }
701
+ return 0;
702
+ }
703
+ function codexDynamicToolDefinitions() {
704
+ return [
705
+ {
706
+ name: "shell",
707
+ description: "Run a shell command through Rig's audited gateway inside the current task workspace. Use this for git, bun, node, python3, rg, and related command-line work. Never rely on absolute host binaries.",
708
+ inputSchema: {
709
+ type: "object",
710
+ properties: {
711
+ command: { type: "string", description: "Shell command to execute." },
712
+ workdir: { type: "string", description: "Optional workspace-relative working directory." },
713
+ shell: { type: "string", enum: ["bash", "sh", "zsh"] }
714
+ },
715
+ required: ["command"],
716
+ additionalProperties: false
717
+ }
718
+ },
719
+ ...CLAUDE_ROUTER_TOOL_DEFINITIONS
720
+ ];
721
+ }
722
+ function mapAppServerItemToCodexRecord(input) {
723
+ const item = asRecord(input.item);
724
+ const itemType = normalizeString(item?.type);
725
+ const itemId = normalizeString(item?.id);
726
+ if (!item || !itemType || !itemId) {
727
+ return null;
728
+ }
729
+ if (itemType === "agentMessage") {
730
+ if (input.phase !== "item.completed") {
731
+ return null;
732
+ }
733
+ const finalText = normalizeString(item.text) ?? input.agentMessageText.get(itemId) ?? "";
734
+ input.agentMessageText.delete(itemId);
735
+ return {
736
+ type: "item.completed",
737
+ timestamp: input.timestamp,
738
+ item: {
739
+ id: itemId,
740
+ type: "agent_message",
741
+ text: finalText
742
+ }
743
+ };
744
+ }
745
+ if (itemType === "commandExecution") {
746
+ return {
747
+ type: input.phase,
748
+ timestamp: input.timestamp,
749
+ item: {
750
+ id: itemId,
751
+ type: "command_execution",
752
+ command: normalizeString(item.command),
753
+ cwd: normalizeString(item.cwd),
754
+ status: normalizeStatus(item.status),
755
+ aggregated_output: normalizeString(item.aggregatedOutput),
756
+ exit_code: typeof item.exitCode === "number" ? item.exitCode : null,
757
+ duration_ms: typeof item.durationMs === "number" ? item.durationMs : null
758
+ }
759
+ };
760
+ }
761
+ if (itemType === "mcpToolCall") {
762
+ return {
763
+ type: input.phase,
764
+ timestamp: input.timestamp,
765
+ item: {
766
+ id: itemId,
767
+ type: "mcp_tool_call",
768
+ server: normalizeString(item.server),
769
+ tool: normalizeString(item.tool),
770
+ status: normalizeStatus(item.status),
771
+ arguments: item.arguments ?? null,
772
+ result: asRecord(item.result) ?? null,
773
+ error: asRecord(item.error) ?? null
774
+ }
775
+ };
776
+ }
777
+ if (itemType === "dynamicToolCall") {
778
+ const cached = input.dynamicToolResults.get(itemId) ?? null;
779
+ if (input.phase === "item.completed") {
780
+ input.dynamicToolResults.delete(itemId);
781
+ }
782
+ return {
783
+ type: input.phase,
784
+ timestamp: input.timestamp,
785
+ item: {
786
+ id: itemId,
787
+ type: "mcp_tool_call",
788
+ server: RIG_DYNAMIC_TOOL_SERVER,
789
+ tool: normalizeString(item.tool),
790
+ status: cached?.isError ? "failed" : normalizeStatus(item.status),
791
+ arguments: item.arguments ?? null,
792
+ result: cached?.structuredResult ?? {
793
+ content_items: item.contentItems ?? null,
794
+ success: item.success ?? null
795
+ }
796
+ }
797
+ };
798
+ }
799
+ return null;
800
+ }
801
+ function invocationToContentItems(invocation) {
802
+ const items = Array.isArray(invocation.content) ? invocation.content : [];
803
+ const mapped = items.map((item) => {
804
+ const entry = asRecord(item);
805
+ if (!entry || entry.type !== "text" || typeof entry.text !== "string") {
806
+ return null;
807
+ }
808
+ return {
809
+ type: "inputText",
810
+ text: entry.text
811
+ };
812
+ }).filter((item) => Boolean(item));
813
+ return mapped.length > 0 ? mapped : [{ type: "inputText", text: "(empty tool response)" }];
814
+ }
815
+ function emitSyntheticCodexRecord(record) {
816
+ process.stdout.write(`${JSON.stringify(record)}
817
+ `);
818
+ }
819
+ function sanitizeEnv(env) {
820
+ const next = {};
821
+ for (const [key, value] of Object.entries(env)) {
822
+ if (typeof value === "string") {
823
+ next[key] = value;
824
+ }
825
+ }
826
+ return next;
827
+ }
828
+ function writeChildLine(child, line) {
829
+ return new Promise((resolve2, reject) => {
830
+ child.stdin.write(line, (error) => {
831
+ if (error) {
832
+ reject(error);
833
+ return;
834
+ }
835
+ resolve2();
836
+ });
837
+ });
838
+ }
839
+ function terminateChild(child) {
840
+ if (child.killed) {
841
+ return;
842
+ }
843
+ try {
844
+ child.kill("SIGTERM");
845
+ } catch {}
846
+ }
847
+ function asRecord(value) {
848
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
849
+ }
850
+ function normalizeString(value) {
851
+ if (typeof value !== "string") {
852
+ return null;
853
+ }
854
+ const trimmed = value.trim();
855
+ return trimmed.length > 0 ? trimmed : null;
856
+ }
857
+ function normalizeStatus(value) {
858
+ const raw = normalizeString(value);
859
+ if (!raw) {
860
+ return null;
861
+ }
862
+ switch (raw) {
863
+ case "inProgress":
864
+ return "in_progress";
865
+ case "completed":
866
+ case "failed":
867
+ case "declined":
868
+ return raw;
869
+ default:
870
+ return raw;
871
+ }
872
+ }
873
+ function formatJsonRpcError(error) {
874
+ if (!error) {
875
+ return "Unknown app-server error";
876
+ }
877
+ const parts = [error.message, error.data ? JSON.stringify(error.data) : null].filter(Boolean);
878
+ return parts.join(" ");
879
+ }
880
+ export {
881
+ runCodexAppServerTaskRun,
882
+ parseCodexAppServerTaskRunArgs,
883
+ buildCodexAppServerArgs,
884
+ CODEX_APP_SERVER_TASK_RUN_SENTINEL
885
+ };