@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,1633 @@
1
+ // @bun
2
+ // packages/runtime/src/events.ts
3
+ import { appendFile, mkdir } from "fs/promises";
4
+ import { randomUUID } from "crypto";
5
+ import { dirname as dirname2, resolve as resolve2 } from "path";
6
+
7
+ // packages/runtime/src/layout.ts
8
+ import { existsSync } from "fs";
9
+ import { basename, dirname, resolve } from "path";
10
+ var RIG_DEFINITION_DIRNAME = "rig";
11
+ var RIG_STATE_DIRNAME = ".rig";
12
+ var RIG_ARTIFACTS_DIRNAME = "artifacts";
13
+ function resolveNearestRigProjectRoot(startDir) {
14
+ let current = resolve(startDir);
15
+ let fallbackCandidate = null;
16
+ let projectCandidate = null;
17
+ for (;; ) {
18
+ const hasDefinition = existsSync(resolve(current, RIG_DEFINITION_DIRNAME));
19
+ const hasState = existsSync(resolve(current, RIG_STATE_DIRNAME));
20
+ const hasConfig = existsSync(resolve(current, "rig.config.ts")) || existsSync(resolve(current, "rig.config.json"));
21
+ const hasControlPlane = existsSync(resolve(current, "packages", "cli", "bin", "rig.ts")) || existsSync(resolve(current, "packages", "server"));
22
+ if (hasDefinition || hasState || hasConfig) {
23
+ fallbackCandidate = current;
24
+ if (hasControlPlane) {
25
+ projectCandidate = current;
26
+ }
27
+ }
28
+ const parent = resolve(current, "..");
29
+ if (parent === current) {
30
+ return projectCandidate ?? fallbackCandidate ?? resolve(startDir);
31
+ }
32
+ current = parent;
33
+ }
34
+ }
35
+ function resolveMonorepoRoot(projectRoot) {
36
+ const normalizedProjectRoot = resolve(projectRoot);
37
+ const explicit = process.env.MONOREPO_ROOT?.trim();
38
+ if (explicit) {
39
+ const explicitRoot = resolve(explicit);
40
+ const explicitParent = dirname(explicitRoot);
41
+ if (basename(explicitParent) === ".worktrees") {
42
+ const owner = dirname(explicitParent);
43
+ const ownerHasGit = existsSync(resolve(owner, ".git"));
44
+ const ownerHasTaskConfig = existsSync(resolve(owner, ".rig", "task-config.json"));
45
+ const ownerHasRigConfig = existsSync(resolve(owner, "rig.config.ts"));
46
+ if (ownerHasGit && (ownerHasTaskConfig || ownerHasRigConfig)) {
47
+ return owner;
48
+ }
49
+ throw new Error(`MONOREPO_ROOT points to worktree ${explicitRoot}, but the owner checkout is incomplete at ${owner}.`);
50
+ }
51
+ if (!existsSync(resolve(explicitRoot, ".git"))) {
52
+ throw new Error(`MONOREPO_ROOT points to ${explicitRoot}, but no git checkout was found there.`);
53
+ }
54
+ const hasTaskConfig = existsSync(resolve(explicitRoot, ".rig", "task-config.json"));
55
+ const hasRigConfig = existsSync(resolve(explicitRoot, "rig.config.ts"));
56
+ if (!hasTaskConfig && !hasRigConfig) {
57
+ throw new Error(`MONOREPO_ROOT points to ${explicitRoot}, but neither .rig/task-config.json nor rig.config.ts exists there.`);
58
+ }
59
+ return explicitRoot;
60
+ }
61
+ const projectParent = dirname(normalizedProjectRoot);
62
+ if (basename(projectParent) === ".worktrees") {
63
+ const worktreeOwner = dirname(projectParent);
64
+ const ownerHasGit = existsSync(resolve(worktreeOwner, ".git"));
65
+ const ownerHasTaskConfig = existsSync(resolve(worktreeOwner, ".rig", "task-config.json"));
66
+ const ownerHasRigConfig = existsSync(resolve(worktreeOwner, "rig.config.ts"));
67
+ if (ownerHasGit && (ownerHasTaskConfig || ownerHasRigConfig)) {
68
+ return worktreeOwner;
69
+ }
70
+ }
71
+ return normalizedProjectRoot;
72
+ }
73
+ function resolveRuntimeWorkspaceLayout(workspaceDir) {
74
+ const root = resolve(workspaceDir);
75
+ const rigRoot = resolve(root, ".rig");
76
+ const logsDir = resolve(rigRoot, "logs");
77
+ const stateDir = resolve(rigRoot, "state");
78
+ const runtimeDir = resolve(rigRoot, "runtime");
79
+ const binDir = resolve(rigRoot, "bin");
80
+ return {
81
+ workspaceDir: root,
82
+ rigRoot,
83
+ stateDir,
84
+ logsDir,
85
+ artifactsRoot: resolve(root, RIG_ARTIFACTS_DIRNAME),
86
+ runtimeDir,
87
+ homeDir: resolve(rigRoot, "home"),
88
+ tmpDir: resolve(rigRoot, "tmp"),
89
+ cacheDir: resolve(rigRoot, "cache"),
90
+ sessionDir: resolve(rigRoot, "session"),
91
+ binDir,
92
+ distDir: resolve(rigRoot, "dist"),
93
+ pluginBinDir: resolve(binDir, "plugins"),
94
+ contextPath: resolve(rigRoot, "runtime-context.json"),
95
+ controlPlaneEventsFile: resolve(logsDir, "control-plane.events.jsonl")
96
+ };
97
+ }
98
+ function resolveActiveRuntimeWorkspaceRoot(monorepoRoot) {
99
+ const explicit = process.env.RIG_TASK_WORKSPACE?.trim();
100
+ if (!explicit) {
101
+ throw new Error("No active runtime workspace. Set RIG_TASK_WORKSPACE or provision a task runtime first.");
102
+ }
103
+ return resolve(explicit);
104
+ }
105
+ function resolveRigLayout(projectRoot) {
106
+ const monorepoRoot = resolveMonorepoRoot(projectRoot);
107
+ const definitionRoot = resolve(projectRoot, RIG_DEFINITION_DIRNAME);
108
+ const runtimeWorkspaceRoot = resolveActiveRuntimeWorkspaceRoot(monorepoRoot);
109
+ const runtimeLayout = resolveRuntimeWorkspaceLayout(runtimeWorkspaceRoot);
110
+ const policyDir = resolve(definitionRoot, "policy");
111
+ return {
112
+ projectRoot,
113
+ monorepoRoot,
114
+ definitionRoot,
115
+ runtimeWorkspaceRoot,
116
+ stateRoot: runtimeLayout.rigRoot,
117
+ artifactsRoot: runtimeLayout.artifactsRoot,
118
+ configPath: resolve(definitionRoot, "config.sh"),
119
+ taskConfigPath: resolve(runtimeWorkspaceRoot, ".rig", "task-config.json"),
120
+ policyDir,
121
+ policyFile: resolve(policyDir, "policy.json"),
122
+ pluginsDir: resolve(definitionRoot, "plugins"),
123
+ hooksDir: resolve(definitionRoot, "hooks"),
124
+ toolsDir: resolve(definitionRoot, "tools"),
125
+ templatesDir: resolve(definitionRoot, "templates"),
126
+ validationDir: resolve(definitionRoot, "validation"),
127
+ stateDir: runtimeLayout.stateDir,
128
+ logsDir: runtimeLayout.logsDir,
129
+ notificationsDir: resolve(definitionRoot, "notifications"),
130
+ runtimeDir: runtimeLayout.runtimeDir,
131
+ distDir: runtimeLayout.distDir,
132
+ binDir: runtimeLayout.binDir,
133
+ pluginBinDir: runtimeLayout.pluginBinDir,
134
+ keybindingsPath: resolve(definitionRoot, "keybindings.json"),
135
+ controlPlaneEventsFile: runtimeLayout.controlPlaneEventsFile
136
+ };
137
+ }
138
+
139
+ // packages/runtime/src/events.ts
140
+ async function appendEvent(eventsFile, event) {
141
+ await mkdir(dirname2(eventsFile), { recursive: true });
142
+ await appendFile(eventsFile, `${JSON.stringify(event)}
143
+ `, "utf-8");
144
+ }
145
+ function createEvent(runId, type, payload) {
146
+ return {
147
+ id: randomUUID(),
148
+ runId,
149
+ timestamp: new Date().toISOString(),
150
+ type,
151
+ payload
152
+ };
153
+ }
154
+
155
+ class RuntimeEventBus {
156
+ runId;
157
+ eventsFile;
158
+ memoryEvents = [];
159
+ constructor(options) {
160
+ this.runId = options.runId || randomUUID();
161
+ this.eventsFile = options.eventsFile ?? resolveRigLayout(options.projectRoot).controlPlaneEventsFile;
162
+ }
163
+ getRunId() {
164
+ return this.runId;
165
+ }
166
+ getEventsFile() {
167
+ return this.eventsFile;
168
+ }
169
+ getMemoryEvents() {
170
+ return [...this.memoryEvents];
171
+ }
172
+ async attachRuntimeBus(runtimeBus) {
173
+ if (runtimeBus.getEventsFile() === this.eventsFile) {
174
+ return;
175
+ }
176
+ for (const event of this.memoryEvents) {
177
+ await runtimeBus.ingest(event);
178
+ }
179
+ }
180
+ async attachRuntimeWorkspace(projectRoot) {
181
+ const runtimeBus = new RuntimeEventBus({ projectRoot, runId: this.runId });
182
+ await this.attachRuntimeBus(runtimeBus);
183
+ return runtimeBus;
184
+ }
185
+ async ingest(event) {
186
+ this.memoryEvents.push(event);
187
+ await appendEvent(this.eventsFile, event);
188
+ }
189
+ async emit(type, payload) {
190
+ const event = createEvent(this.runId, type, payload);
191
+ await this.ingest(event);
192
+ return event;
193
+ }
194
+ }
195
+
196
+ class GeneralCliEventBus {
197
+ runId;
198
+ eventsFile;
199
+ memoryEvents = [];
200
+ runtimeBuses = new Map;
201
+ constructor(options) {
202
+ this.runId = options.runId || randomUUID();
203
+ this.eventsFile = options.eventsFile ?? resolve2(options.projectRoot, ".rig", "logs", "control-plane.events.jsonl");
204
+ }
205
+ getRunId() {
206
+ return this.runId;
207
+ }
208
+ getEventsFile() {
209
+ return this.eventsFile;
210
+ }
211
+ getMemoryEvents() {
212
+ return [...this.memoryEvents];
213
+ }
214
+ async attachRuntimeBus(runtimeBus) {
215
+ const key = runtimeBus.getEventsFile();
216
+ if (this.runtimeBuses.has(key)) {
217
+ return;
218
+ }
219
+ this.runtimeBuses.set(key, runtimeBus);
220
+ for (const event of this.memoryEvents) {
221
+ await runtimeBus.ingest(event);
222
+ }
223
+ }
224
+ async attachRuntimeWorkspace(projectRoot) {
225
+ const runtimeBus = new RuntimeEventBus({ projectRoot, runId: this.runId });
226
+ await this.attachRuntimeBus(runtimeBus);
227
+ return runtimeBus;
228
+ }
229
+ async emit(type, payload) {
230
+ const event = createEvent(this.runId, type, payload);
231
+ this.memoryEvents.push(event);
232
+ await appendEvent(this.eventsFile, event);
233
+ await Promise.all(Array.from(this.runtimeBuses.values()).map((bus) => bus.ingest(event)));
234
+ return event;
235
+ }
236
+ }
237
+ // packages/runtime/src/baked-secrets.ts
238
+ import { existsSync as existsSync2, readFileSync } from "fs";
239
+ import { resolve as resolve3 } from "path";
240
+ var BAKED_RUNTIME_SECRETS = {
241
+ ANTHROPIC_API_KEY: typeof RIG_BAKED_ANTHROPIC_API_KEY !== "undefined" ? RIG_BAKED_ANTHROPIC_API_KEY : "",
242
+ OPENAI_API_KEY: typeof RIG_BAKED_OPENAI_API_KEY !== "undefined" ? RIG_BAKED_OPENAI_API_KEY : "",
243
+ OPENROUTER_API_KEY: typeof RIG_BAKED_OPENROUTER_API_KEY !== "undefined" ? RIG_BAKED_OPENROUTER_API_KEY : "",
244
+ AI_REVIEW_MODE: typeof RIG_BAKED_AI_REVIEW_MODE !== "undefined" ? RIG_BAKED_AI_REVIEW_MODE : "",
245
+ AI_REVIEW_PROVIDER: typeof RIG_BAKED_AI_REVIEW_PROVIDER !== "undefined" ? RIG_BAKED_AI_REVIEW_PROVIDER : "",
246
+ GREPTILE_API_BASE: typeof RIG_BAKED_GREPTILE_API_BASE !== "undefined" ? RIG_BAKED_GREPTILE_API_BASE : "",
247
+ GREPTILE_REMOTE: typeof RIG_BAKED_GREPTILE_REMOTE !== "undefined" ? RIG_BAKED_GREPTILE_REMOTE : "",
248
+ GREPTILE_REPOSITORY: typeof RIG_BAKED_GREPTILE_REPOSITORY !== "undefined" ? RIG_BAKED_GREPTILE_REPOSITORY : "",
249
+ GREPTILE_CONTEXT_BRANCH: typeof RIG_BAKED_GREPTILE_CONTEXT_BRANCH !== "undefined" ? RIG_BAKED_GREPTILE_CONTEXT_BRANCH : "",
250
+ GREPTILE_DEFAULT_BRANCH: typeof RIG_BAKED_GREPTILE_DEFAULT_BRANCH !== "undefined" ? RIG_BAKED_GREPTILE_DEFAULT_BRANCH : "",
251
+ GREPTILE_API_KEY: typeof RIG_BAKED_GREPTILE_API_KEY !== "undefined" ? RIG_BAKED_GREPTILE_API_KEY : "",
252
+ GREPTILE_GITHUB_TOKEN: typeof RIG_BAKED_GREPTILE_GITHUB_TOKEN !== "undefined" ? RIG_BAKED_GREPTILE_GITHUB_TOKEN : "",
253
+ GREPTILE_POLL_ATTEMPTS: typeof RIG_BAKED_GREPTILE_POLL_ATTEMPTS !== "undefined" ? RIG_BAKED_GREPTILE_POLL_ATTEMPTS : "",
254
+ GREPTILE_POLL_INTERVAL_MS: typeof RIG_BAKED_GREPTILE_POLL_INTERVAL_MS !== "undefined" ? RIG_BAKED_GREPTILE_POLL_INTERVAL_MS : "",
255
+ GH_TOKEN: typeof RIG_BAKED_GITHUB_TOKEN !== "undefined" ? RIG_BAKED_GITHUB_TOKEN : "",
256
+ GITHUB_TOKEN: typeof RIG_BAKED_GITHUB_TOKEN !== "undefined" ? RIG_BAKED_GITHUB_TOKEN : "",
257
+ GITHUB_SSH_KEY: typeof RIG_BAKED_GITHUB_SSH_KEY !== "undefined" ? RIG_BAKED_GITHUB_SSH_KEY : "",
258
+ AWS_ACCESS_KEY_ID: typeof RIG_BAKED_AWS_ACCESS_KEY_ID !== "undefined" ? RIG_BAKED_AWS_ACCESS_KEY_ID : "",
259
+ AWS_SECRET_ACCESS_KEY: typeof RIG_BAKED_AWS_SECRET_ACCESS_KEY !== "undefined" ? RIG_BAKED_AWS_SECRET_ACCESS_KEY : "",
260
+ AWS_REGION: typeof RIG_BAKED_AWS_REGION !== "undefined" ? RIG_BAKED_AWS_REGION : "",
261
+ LINEAR_API_KEY: typeof RIG_BAKED_LINEAR_API_KEY !== "undefined" ? RIG_BAKED_LINEAR_API_KEY : "",
262
+ LINEAR_WEBHOOK_SECRET: typeof RIG_BAKED_LINEAR_WEBHOOK_SECRET !== "undefined" ? RIG_BAKED_LINEAR_WEBHOOK_SECRET : ""
263
+ };
264
+ function resolveRuntimeSecrets(env, baked = BAKED_RUNTIME_SECRETS) {
265
+ const resolved = {};
266
+ const keys = new Set([
267
+ ...Object.keys(BAKED_RUNTIME_SECRETS),
268
+ ...Object.keys(baked)
269
+ ]);
270
+ for (const key of keys) {
271
+ const envValue = env[key]?.trim();
272
+ const bakedValue = baked[key]?.trim();
273
+ if (envValue) {
274
+ resolved[key] = envValue;
275
+ } else if (bakedValue) {
276
+ resolved[key] = bakedValue;
277
+ }
278
+ }
279
+ return resolved;
280
+ }
281
+ function loadDotEnvSecrets(projectRoot, env = process.env) {
282
+ const dotenvPath = resolve3(projectRoot, ".env");
283
+ if (!existsSync2(dotenvPath)) {
284
+ return {};
285
+ }
286
+ const parsed = {};
287
+ const lines = readFileSync(dotenvPath, "utf-8").split(/\r?\n/);
288
+ for (const rawLine of lines) {
289
+ const line = rawLine.trim();
290
+ if (!line || line.startsWith("#")) {
291
+ continue;
292
+ }
293
+ const exportMatch = line.match(/^(?:export\s+)?([A-Z0-9_]+)\s*=\s*(.*)$/);
294
+ if (!exportMatch) {
295
+ continue;
296
+ }
297
+ const key = exportMatch[1];
298
+ if (!(key in BAKED_RUNTIME_SECRETS)) {
299
+ continue;
300
+ }
301
+ const value = expandShellValue(exportMatch[2] ?? "", { ...env, ...parsed });
302
+ if (value) {
303
+ parsed[key] = value;
304
+ }
305
+ }
306
+ return parsed;
307
+ }
308
+ function secretDefinesFromEnv(env = process.env, projectRoot) {
309
+ const dotenvSecrets = projectRoot ? loadDotEnvSecrets(projectRoot, env) : {};
310
+ const resolved = resolveRuntimeSecrets(env, {
311
+ ...BAKED_RUNTIME_SECRETS,
312
+ ...dotenvSecrets
313
+ });
314
+ return {
315
+ RIG_BAKED_ANTHROPIC_API_KEY: resolved.ANTHROPIC_API_KEY || "",
316
+ RIG_BAKED_OPENAI_API_KEY: resolved.OPENAI_API_KEY || "",
317
+ RIG_BAKED_OPENROUTER_API_KEY: resolved.OPENROUTER_API_KEY || "",
318
+ RIG_BAKED_AI_REVIEW_MODE: resolved.AI_REVIEW_MODE || "",
319
+ RIG_BAKED_AI_REVIEW_PROVIDER: resolved.AI_REVIEW_PROVIDER || "",
320
+ RIG_BAKED_GREPTILE_API_BASE: resolved.GREPTILE_API_BASE || "",
321
+ RIG_BAKED_GREPTILE_REMOTE: resolved.GREPTILE_REMOTE || "",
322
+ RIG_BAKED_GREPTILE_REPOSITORY: resolved.GREPTILE_REPOSITORY || "",
323
+ RIG_BAKED_GREPTILE_CONTEXT_BRANCH: resolved.GREPTILE_CONTEXT_BRANCH || "",
324
+ RIG_BAKED_GREPTILE_DEFAULT_BRANCH: resolved.GREPTILE_DEFAULT_BRANCH || "",
325
+ RIG_BAKED_GREPTILE_API_KEY: resolved.GREPTILE_API_KEY || "",
326
+ RIG_BAKED_GREPTILE_GITHUB_TOKEN: resolved.GREPTILE_GITHUB_TOKEN || "",
327
+ RIG_BAKED_GREPTILE_POLL_ATTEMPTS: resolved.GREPTILE_POLL_ATTEMPTS || "",
328
+ RIG_BAKED_GREPTILE_POLL_INTERVAL_MS: resolved.GREPTILE_POLL_INTERVAL_MS || "",
329
+ RIG_BAKED_GITHUB_TOKEN: resolved.GITHUB_TOKEN || resolved.GH_TOKEN || "",
330
+ RIG_BAKED_GITHUB_SSH_KEY: resolved.GITHUB_SSH_KEY || "",
331
+ RIG_BAKED_AWS_ACCESS_KEY_ID: resolved.AWS_ACCESS_KEY_ID || "",
332
+ RIG_BAKED_AWS_SECRET_ACCESS_KEY: resolved.AWS_SECRET_ACCESS_KEY || "",
333
+ RIG_BAKED_AWS_REGION: resolved.AWS_REGION || "",
334
+ RIG_BAKED_LINEAR_API_KEY: resolved.LINEAR_API_KEY || "",
335
+ RIG_BAKED_LINEAR_WEBHOOK_SECRET: resolved.LINEAR_WEBHOOK_SECRET || ""
336
+ };
337
+ }
338
+ function expandShellValue(rawValue, env) {
339
+ let value = rawValue.trim();
340
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
341
+ value = value.slice(1, -1);
342
+ }
343
+ return value.replace(/\$\{([A-Z0-9_]+)(:-([^}]*))?\}/g, (_match, name, _defaultGroup, fallback) => {
344
+ const envValue = env[name]?.trim();
345
+ if (envValue) {
346
+ return envValue;
347
+ }
348
+ return fallback ?? "";
349
+ });
350
+ }
351
+ // packages/runtime/src/control-plane/runtime/context.ts
352
+ import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync2, writeFileSync } from "fs";
353
+ import { dirname as dirname3, resolve as resolve4 } from "path";
354
+ var RUNTIME_CONTEXT_ENV = "RIG_RUNTIME_CONTEXT_FILE";
355
+ var runtimeContextStringFields = [
356
+ "runtimeId",
357
+ "taskId",
358
+ "role",
359
+ "workspaceDir",
360
+ "stateDir",
361
+ "logsDir",
362
+ "sessionDir",
363
+ "sessionFile",
364
+ "policyFile",
365
+ "binDir",
366
+ "createdAt"
367
+ ];
368
+ var runtimeContextArrayFields = ["scopes", "validation"];
369
+ var runtimeContextOptionalStringFields = [
370
+ "artifactRoot",
371
+ "hostProjectRoot",
372
+ "monorepoMainRoot",
373
+ "monorepoBaseRef",
374
+ "monorepoBaseCommit"
375
+ ];
376
+ function writeRuntimeContext(path, ctx) {
377
+ const absPath = resolve4(path);
378
+ const dir = dirname3(absPath);
379
+ if (!existsSync3(dir)) {
380
+ mkdirSync(dir, { recursive: true });
381
+ }
382
+ writeFileSync(absPath, JSON.stringify(ctx, null, 2), "utf8");
383
+ }
384
+ function loadRuntimeContext(path) {
385
+ const absPath = resolve4(path);
386
+ if (!existsSync3(absPath)) {
387
+ throw new Error(`RuntimeTaskContext file not found: ${absPath}`);
388
+ }
389
+ let raw;
390
+ try {
391
+ raw = JSON.parse(readFileSync2(absPath, "utf8"));
392
+ } catch (err) {
393
+ throw new Error(`Failed to parse RuntimeTaskContext at ${absPath}: ${String(err)}`);
394
+ }
395
+ if (typeof raw !== "object" || raw === null) {
396
+ throw new Error(`RuntimeTaskContext at ${absPath} is not an object`);
397
+ }
398
+ const obj = raw;
399
+ for (const field of runtimeContextStringFields) {
400
+ if (typeof obj[field] !== "string" || obj[field].length === 0) {
401
+ throw new Error(`RuntimeTaskContext field "${field}" must be a non-empty string (at ${absPath})`);
402
+ }
403
+ }
404
+ for (const field of runtimeContextArrayFields) {
405
+ if (!Array.isArray(obj[field])) {
406
+ throw new Error(`RuntimeTaskContext field "${field}" must be an array (at ${absPath})`);
407
+ }
408
+ if (!obj[field].every((entry) => typeof entry === "string")) {
409
+ throw new Error(`RuntimeTaskContext field "${field}" must be a string[] (at ${absPath})`);
410
+ }
411
+ }
412
+ for (const field of runtimeContextOptionalStringFields) {
413
+ if (field in obj && obj[field] !== undefined && typeof obj[field] !== "string") {
414
+ throw new Error(`RuntimeTaskContext field "${field}" must be a string when present (at ${absPath})`);
415
+ }
416
+ }
417
+ if (obj.browser !== undefined) {
418
+ if (typeof obj.browser !== "object" || obj.browser === null || Array.isArray(obj.browser)) {
419
+ throw new Error(`RuntimeTaskContext field "browser" must be an object when present (at ${absPath})`);
420
+ }
421
+ const browser = obj.browser;
422
+ for (const field of [
423
+ "preset",
424
+ "mode",
425
+ "stateDir",
426
+ "defaultProfile",
427
+ "effectiveProfile",
428
+ "defaultAttachUrl",
429
+ "effectiveAttachUrl",
430
+ "launchHelper",
431
+ "checkHelper",
432
+ "attachInfoHelper",
433
+ "e2eHelper",
434
+ "resetProfileHelper"
435
+ ]) {
436
+ if (typeof browser[field] !== "string" || browser[field].length === 0) {
437
+ throw new Error(`RuntimeTaskContext field "browser.${field}" must be a non-empty string (at ${absPath})`);
438
+ }
439
+ }
440
+ for (const field of ["devCommand", "launchCommand", "checkCommand", "e2eCommand"]) {
441
+ if (browser[field] !== undefined && typeof browser[field] !== "string") {
442
+ throw new Error(`RuntimeTaskContext field "browser.${field}" must be a string when present (at ${absPath})`);
443
+ }
444
+ }
445
+ if (typeof browser.required !== "boolean") {
446
+ throw new Error(`RuntimeTaskContext field "browser.required" must be a boolean (at ${absPath})`);
447
+ }
448
+ }
449
+ if (obj.memory !== undefined) {
450
+ if (typeof obj.memory !== "object" || obj.memory === null || Array.isArray(obj.memory)) {
451
+ throw new Error(`RuntimeTaskContext field "memory" must be an object when present (at ${absPath})`);
452
+ }
453
+ const memory = obj.memory;
454
+ for (const field of ["canonicalPath", "canonicalRef", "canonicalBaseOid", "hydratedPath"]) {
455
+ if (typeof memory[field] !== "string" || memory[field].length === 0) {
456
+ throw new Error(`RuntimeTaskContext field "memory.${field}" must be a non-empty string (at ${absPath})`);
457
+ }
458
+ }
459
+ if (typeof memory.createdFresh !== "boolean") {
460
+ throw new Error(`RuntimeTaskContext field "memory.createdFresh" must be a boolean (at ${absPath})`);
461
+ }
462
+ if (typeof memory.retrieval !== "object" || memory.retrieval === null || Array.isArray(memory.retrieval)) {
463
+ throw new Error(`RuntimeTaskContext field "memory.retrieval" must be an object (at ${absPath})`);
464
+ }
465
+ const retrieval = memory.retrieval;
466
+ for (const field of ["topK", "lexicalWeight", "vectorWeight", "recencyWeight", "confidenceWeight"]) {
467
+ if (typeof retrieval[field] !== "number" || Number.isNaN(retrieval[field])) {
468
+ throw new Error(`RuntimeTaskContext field "memory.retrieval.${field}" must be a number (at ${absPath})`);
469
+ }
470
+ }
471
+ }
472
+ if (obj.initialDirtyFiles !== undefined) {
473
+ if (typeof obj.initialDirtyFiles !== "object" || obj.initialDirtyFiles === null || Array.isArray(obj.initialDirtyFiles)) {
474
+ throw new Error(`RuntimeTaskContext field "initialDirtyFiles" must be an object when present (at ${absPath})`);
475
+ }
476
+ const dirtyFiles = obj.initialDirtyFiles;
477
+ for (const key of ["project", "monorepo"]) {
478
+ if (dirtyFiles[key] === undefined) {
479
+ continue;
480
+ }
481
+ if (!Array.isArray(dirtyFiles[key]) || !dirtyFiles[key].every((entry) => typeof entry === "string")) {
482
+ throw new Error(`RuntimeTaskContext field "initialDirtyFiles.${key}" must be a string[] when present (at ${absPath})`);
483
+ }
484
+ }
485
+ }
486
+ if (obj.initialHeadCommits !== undefined) {
487
+ if (typeof obj.initialHeadCommits !== "object" || obj.initialHeadCommits === null || Array.isArray(obj.initialHeadCommits)) {
488
+ throw new Error(`RuntimeTaskContext field "initialHeadCommits" must be an object when present (at ${absPath})`);
489
+ }
490
+ const headCommits = obj.initialHeadCommits;
491
+ for (const key of ["project", "monorepo"]) {
492
+ if (headCommits[key] === undefined) {
493
+ continue;
494
+ }
495
+ if (typeof headCommits[key] !== "string") {
496
+ throw new Error(`RuntimeTaskContext field "initialHeadCommits.${key}" must be a string when present (at ${absPath})`);
497
+ }
498
+ }
499
+ }
500
+ return obj;
501
+ }
502
+ function loadRuntimeContextFromEnv(env = process.env) {
503
+ const contextFile = env[RUNTIME_CONTEXT_ENV];
504
+ if (contextFile) {
505
+ return loadRuntimeContext(contextFile);
506
+ }
507
+ const inferred = findRuntimeContextFile(process.cwd());
508
+ if (!inferred) {
509
+ return null;
510
+ }
511
+ return loadRuntimeContext(inferred);
512
+ }
513
+ function findRuntimeContextFile(startPath) {
514
+ let current = resolve4(startPath);
515
+ while (true) {
516
+ const candidate = resolve4(current, "runtime-context.json");
517
+ if (existsSync3(candidate) && isAgentRuntimeContextPath(candidate)) {
518
+ return candidate;
519
+ }
520
+ const parent = dirname3(current);
521
+ if (parent === current) {
522
+ return "";
523
+ }
524
+ current = parent;
525
+ }
526
+ }
527
+ function isAgentRuntimeContextPath(path) {
528
+ const normalized = path.replace(/\\/g, "/");
529
+ return /\/\.rig\/runtime-context\.json$/.test(normalized);
530
+ }
531
+ // packages/runtime/src/local-server.ts
532
+ import { spawn } from "child_process";
533
+ import { closeSync, existsSync as existsSync4, mkdirSync as mkdirSync2, openSync, readFileSync as readFileSync3, unlinkSync } from "fs";
534
+ import { resolve as resolve5 } from "path";
535
+ function parsePublishedRigServerState(value) {
536
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
537
+ return null;
538
+ }
539
+ const candidate = value;
540
+ if (typeof candidate.pid !== "number" || !Number.isInteger(candidate.pid) || candidate.pid <= 0 || typeof candidate.host !== "string" || candidate.host.trim().length === 0 || typeof candidate.port !== "number" || !Number.isInteger(candidate.port) || candidate.port < 1 || candidate.port > 65535 || candidate.authToken !== null && candidate.authToken !== undefined && typeof candidate.authToken !== "string" || typeof candidate.startedAt !== "string" || candidate.startedAt.trim().length === 0) {
541
+ return null;
542
+ }
543
+ return {
544
+ pid: candidate.pid,
545
+ host: candidate.host,
546
+ port: candidate.port,
547
+ authToken: candidate.authToken ?? null,
548
+ startedAt: candidate.startedAt
549
+ };
550
+ }
551
+ function resolveRigServerLogPath(projectRoot) {
552
+ return resolve5(resolveRigServerPaths(projectRoot).logsDir, "rig-server.bootstrap.log");
553
+ }
554
+ function resolvePublishedRigServerStatePath(projectRoot) {
555
+ return resolve5(resolveRigServerPaths(projectRoot).stateDir, "rig-server.json");
556
+ }
557
+ function resolveRigServerPaths(projectRoot) {
558
+ const taskWorkspace = process.env.RIG_TASK_WORKSPACE?.trim();
559
+ const explicitStateDir = process.env.RIG_STATE_DIR?.trim();
560
+ const explicitLogsDir = process.env.RIG_LOGS_DIR?.trim();
561
+ const explicitSessionFile = process.env.RIG_SESSION_FILE?.trim();
562
+ const hostStateRoot = resolve5(projectRoot, ".rig");
563
+ const monorepoStateRoot = resolve5(resolveMonorepoRoot(projectRoot), ".rig");
564
+ const stateRoot = taskWorkspace ? resolve5(taskWorkspace, ".rig") : explicitStateDir ? resolve5(explicitStateDir, "..") : explicitLogsDir ? resolve5(explicitLogsDir, "..") : explicitSessionFile ? resolve5(explicitSessionFile, "..", "..") : existsSync4(hostStateRoot) ? hostStateRoot : monorepoStateRoot;
565
+ return {
566
+ stateDir: explicitStateDir ? resolve5(explicitStateDir) : resolve5(stateRoot, "state"),
567
+ logsDir: explicitLogsDir ? resolve5(explicitLogsDir) : resolve5(stateRoot, "logs")
568
+ };
569
+ }
570
+ async function readPublishedRigServerState(projectRoot) {
571
+ return readPublishedRigServerStateSync(projectRoot);
572
+ }
573
+ function readPublishedRigServerStateSync(projectRoot) {
574
+ const filePath = resolvePublishedRigServerStatePath(projectRoot);
575
+ if (!existsSync4(filePath)) {
576
+ return null;
577
+ }
578
+ try {
579
+ const rawState = readFileSync3(filePath, "utf8");
580
+ return parsePublishedRigServerState(JSON.parse(rawState));
581
+ } catch {
582
+ return null;
583
+ }
584
+ }
585
+ function clearPublishedRigServerState(projectRoot) {
586
+ const filePath = resolvePublishedRigServerStatePath(projectRoot);
587
+ try {
588
+ unlinkSync(filePath);
589
+ } catch {}
590
+ }
591
+ function toLocalServerConnection(published) {
592
+ const baseUrl = `http://${published.host}:${published.port}`;
593
+ const wsUrl = new URL(`ws://${published.host}:${published.port}`);
594
+ if (published.authToken) {
595
+ wsUrl.searchParams.set("token", published.authToken);
596
+ }
597
+ return {
598
+ baseUrl,
599
+ wsUrl: wsUrl.toString(),
600
+ host: published.host,
601
+ port: published.port,
602
+ authToken: published.authToken
603
+ };
604
+ }
605
+ async function waitForServerHealthy(baseUrl, authToken, timeoutMs) {
606
+ const deadline = Date.now() + timeoutMs;
607
+ const healthUrl = new URL(`${baseUrl}/health`);
608
+ if (authToken !== null) {
609
+ healthUrl.searchParams.set("token", authToken);
610
+ }
611
+ while (Date.now() < deadline) {
612
+ try {
613
+ const response = await fetch(healthUrl.toString());
614
+ if (response.ok) {
615
+ return true;
616
+ }
617
+ } catch {}
618
+ await Bun.sleep(150);
619
+ }
620
+ return false;
621
+ }
622
+ async function waitForPublishedServer(projectRoot, authToken, timeoutMs) {
623
+ const deadline = Date.now() + timeoutMs;
624
+ while (Date.now() < deadline) {
625
+ const published = await readPublishedRigServerState(projectRoot);
626
+ if (published && published.authToken === authToken) {
627
+ const connection = toLocalServerConnection(published);
628
+ if (await waitForServerHealthy(connection.baseUrl, connection.authToken, 500)) {
629
+ return published;
630
+ }
631
+ }
632
+ await Bun.sleep(250);
633
+ }
634
+ return null;
635
+ }
636
+ async function ensureLocalRigServerConnection(projectRoot, options = {}) {
637
+ const published = await readPublishedRigServerState(projectRoot);
638
+ if (published) {
639
+ const connection = toLocalServerConnection(published);
640
+ if (await waitForServerHealthy(connection.baseUrl, connection.authToken, 1500)) {
641
+ return connection;
642
+ }
643
+ }
644
+ const host = options.host ?? "127.0.0.1";
645
+ const startupTimeoutMs = options.startupTimeoutMs ?? 15000;
646
+ const authToken = Buffer.from(crypto.getRandomValues(new Uint8Array(24))).toString("hex");
647
+ const workspaceRoot = resolve5(import.meta.dir, "../../..");
648
+ const bootstrapLogPath = resolveRigServerLogPath(projectRoot);
649
+ mkdirSync2(resolveRigServerPaths(projectRoot).logsDir, { recursive: true });
650
+ const bootstrapLogFd = openSync(bootstrapLogPath, "w");
651
+ clearPublishedRigServerState(projectRoot);
652
+ const child = spawn("bun", [
653
+ "run",
654
+ "packages/server/src/server.ts",
655
+ "start",
656
+ "--host",
657
+ host,
658
+ "--port",
659
+ "0",
660
+ "--auth-token",
661
+ authToken
662
+ ], {
663
+ cwd: workspaceRoot,
664
+ env: {
665
+ ...process.env,
666
+ PROJECT_RIG_ROOT: projectRoot
667
+ },
668
+ detached: true,
669
+ stdio: ["ignore", bootstrapLogFd, bootstrapLogFd]
670
+ });
671
+ closeSync(bootstrapLogFd);
672
+ child.unref();
673
+ const ready = await waitForPublishedServer(projectRoot, authToken, startupTimeoutMs);
674
+ if (!ready) {
675
+ child.kill();
676
+ const bootstrapLog = existsSync4(bootstrapLogPath) ? readFileSync3(bootstrapLogPath, "utf8").trim() : "";
677
+ const diagnostics = bootstrapLog ? ` Startup log (${bootstrapLogPath}):
678
+ ${bootstrapLog}` : ` No bootstrap log was written.`;
679
+ throw new Error(`Timed out waiting for the local Rig server to start.${diagnostics}`);
680
+ }
681
+ return toLocalServerConnection(ready);
682
+ }
683
+ // packages/runtime/src/binary-run.ts
684
+ import { spawn as nodeSpawn } from "child_process";
685
+ import { chmodSync, cpSync, existsSync as existsSync5, mkdirSync as mkdirSync3, renameSync, rmSync, writeFileSync as writeFileSync2 } from "fs";
686
+ import { basename as basename2, dirname as dirname4, resolve as resolve6 } from "path";
687
+ import { fileURLToPath } from "url";
688
+ import { drainMicrotasks, gcAndSweep } from "bun:jsc";
689
+ var runtimeBinaryAssetEntries = [
690
+ "hooks",
691
+ "lib",
692
+ "tools",
693
+ "templates",
694
+ "policy",
695
+ "plugins",
696
+ "config.sh",
697
+ "task-config.json"
698
+ ];
699
+ var runtimeBinaryBuildQueue = Promise.resolve();
700
+ function isRuntimeBinaryAssetEntry(value) {
701
+ return runtimeBinaryAssetEntries.includes(value);
702
+ }
703
+ function createRuntimeBinaryBuildManifest(input) {
704
+ return {
705
+ name: input.name ?? "project-rig-harness",
706
+ builtAt: input.builtAt ?? new Date().toISOString(),
707
+ gitHead: input.gitHead ?? "unknown",
708
+ bunVersion: input.bunVersion,
709
+ binaries: { ...input.binaries },
710
+ runtimeAssets: [...input.runtimeAssets ?? runtimeBinaryAssetEntries]
711
+ };
712
+ }
713
+ async function buildRuntimeBinary(options) {
714
+ return runSerializedRuntimeBinaryBuild(async () => {
715
+ const resolved = resolveRuntimeBinaryBuildOptions(options);
716
+ runBestEffortBuildGc();
717
+ const manifestPath = runtimeBinaryCacheManifestPath(resolved.outputPath);
718
+ const buildKey = createRuntimeBinaryBuildKey({
719
+ entrypoint: resolved.entrypoint,
720
+ define: resolved.define,
721
+ env: resolved.env
722
+ });
723
+ if (await isRuntimeBinaryBuildFresh({ outputPath: resolved.outputPath, manifestPath, buildKey })) {
724
+ return;
725
+ }
726
+ if (shouldUseRuntimeBinaryBuildWorker()) {
727
+ await buildRuntimeBinaryViaWorker(resolved);
728
+ } else {
729
+ await buildRuntimeBinaryInProcess(resolved, { manifestPath, buildKey });
730
+ }
731
+ runBestEffortBuildGc();
732
+ });
733
+ }
734
+ async function buildRuntimeBinaryInProcess(options, manifest) {
735
+ const tempBuildDir = resolve6(dirname4(options.outputPath), `.bun-build-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`);
736
+ const tempOutputPath = resolve6(tempBuildDir, basename2(options.outputPath));
737
+ mkdirSync3(tempBuildDir, { recursive: true });
738
+ await withTemporaryEnv({
739
+ ...options.env,
740
+ ...options.define ? { RIG_BUILD_CONFIG_JSON: JSON.stringify(options.define) } : {}
741
+ }, async () => withTemporaryCwd(tempBuildDir, async () => {
742
+ const buildResult = await Bun.build({
743
+ entrypoints: [options.entrypoint],
744
+ compile: {
745
+ target: currentCompileTarget(),
746
+ outfile: tempOutputPath
747
+ },
748
+ target: "bun",
749
+ format: "esm",
750
+ minify: true,
751
+ bytecode: true,
752
+ metafile: true,
753
+ define: options.define ? {
754
+ __RIG_BUILD_CONFIG__: JSON.stringify(options.define)
755
+ } : undefined
756
+ });
757
+ if (!buildResult.success) {
758
+ const details = buildResult.logs.map((log) => [log.message, log.position?.file ? `${log.position.file}:${log.position.line}:${log.position.column}` : ""].filter(Boolean).join(" ")).filter(Boolean).join(`
759
+ `);
760
+ throw new Error(`Failed to build ${options.entrypoint}: ${details || "Bun.build() returned errors"}`);
761
+ }
762
+ if (!existsSync5(tempOutputPath)) {
763
+ const emitted = buildResult.outputs.map((output) => output.path).join(", ") || "(none)";
764
+ throw new Error(`Failed to build ${options.entrypoint}: Bun.build() did not emit ${tempOutputPath}. Emitted: ${emitted}`);
765
+ }
766
+ renameSync(tempOutputPath, options.outputPath);
767
+ chmodSync(options.outputPath, 493);
768
+ if (manifest) {
769
+ await writeRuntimeBinaryCacheManifest({
770
+ manifestPath: manifest.manifestPath,
771
+ buildKey: manifest.buildKey,
772
+ cwd: tempBuildDir,
773
+ metafile: buildResult.metafile
774
+ });
775
+ }
776
+ })).finally(() => {
777
+ rmSync(tempBuildDir, { recursive: true, force: true });
778
+ });
779
+ }
780
+ function runBestEffortBuildGc() {
781
+ try {
782
+ drainMicrotasks();
783
+ } catch {}
784
+ try {
785
+ gcAndSweep();
786
+ } catch {}
787
+ }
788
+ function runtimeBinaryCacheManifestPath(outputPath) {
789
+ return `${outputPath}.build-manifest.json`;
790
+ }
791
+ function resolveRuntimeBinaryBuildOptions(options) {
792
+ return {
793
+ ...options,
794
+ entrypoint: resolve6(options.cwd, options.sourcePath),
795
+ outputPath: resolve6(options.outputPath)
796
+ };
797
+ }
798
+ function shouldUseRuntimeBinaryBuildWorker() {
799
+ if (process.env.RIG_RUNTIME_BUILD_WORKER === "1") {
800
+ return false;
801
+ }
802
+ if (process.env.RIG_RUNTIME_BUILD_IN_PROCESS === "1") {
803
+ return false;
804
+ }
805
+ return true;
806
+ }
807
+ async function buildRuntimeBinaryViaWorker(options) {
808
+ const workerSourcePath = resolveRuntimeBinaryBuildWorkerSourcePath(options);
809
+ if (!workerSourcePath || !existsSync5(workerSourcePath)) {
810
+ await buildRuntimeBinaryInProcess(options, {
811
+ manifestPath: runtimeBinaryCacheManifestPath(options.outputPath),
812
+ buildKey: createRuntimeBinaryBuildKey({
813
+ entrypoint: options.entrypoint,
814
+ define: options.define,
815
+ env: options.env
816
+ })
817
+ });
818
+ return;
819
+ }
820
+ const payloadPath = createRuntimeBinaryBuildWorkerPayloadPath(options.outputPath);
821
+ const bunCli = resolveRuntimeBinaryBuildWorkerInvocation();
822
+ await Bun.write(payloadPath, `${JSON.stringify(options)}
823
+ `);
824
+ const build = Bun.spawn([bunCli.command, workerSourcePath, payloadPath], {
825
+ cwd: options.cwd,
826
+ stdout: "pipe",
827
+ stderr: "pipe",
828
+ env: {
829
+ ...process.env,
830
+ ...options.env,
831
+ ...bunCli.env,
832
+ RIG_RUNTIME_BUILD_WORKER: "1"
833
+ }
834
+ });
835
+ const [exitCode, stdout, stderr] = await Promise.all([
836
+ build.exited,
837
+ new Response(build.stdout).text(),
838
+ new Response(build.stderr).text()
839
+ ]);
840
+ rmSync(payloadPath, { force: true });
841
+ if (exitCode !== 0) {
842
+ throw new Error(`Failed to build ${options.entrypoint}: ${(stderr || stdout || `worker exited ${exitCode}`).trim()}`);
843
+ }
844
+ }
845
+ function createRuntimeBinaryBuildWorkerPayloadPath(outputPath) {
846
+ return resolve6(dirname4(outputPath), `.bun-build-worker-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`);
847
+ }
848
+ function resolveRuntimeBinaryBuildWorkerSourcePath(options) {
849
+ const envRoots = [
850
+ options.cwd?.trim(),
851
+ process.env.RIG_HOST_PROJECT_ROOT?.trim(),
852
+ process.env.PROJECT_RIG_ROOT?.trim()
853
+ ].filter(Boolean);
854
+ for (const root of envRoots) {
855
+ const candidate = resolve6(root, "packages/runtime/src/binary-build-worker.ts");
856
+ if (existsSync5(candidate)) {
857
+ return candidate;
858
+ }
859
+ }
860
+ const localCandidate = resolve6(import.meta.dir, "binary-build-worker.ts");
861
+ return existsSync5(localCandidate) ? localCandidate : null;
862
+ }
863
+ function resolveRuntimeBinaryBuildWorkerInvocation() {
864
+ const bunPath = Bun.which("bun");
865
+ if (bunPath) {
866
+ return { command: bunPath, env: {} };
867
+ }
868
+ if (process.execPath?.trim()) {
869
+ return {
870
+ command: process.execPath,
871
+ env: { BUN_BE_BUN: "1" }
872
+ };
873
+ }
874
+ throw new Error("bun is required to run the runtime binary build worker.");
875
+ }
876
+ function currentCompileTarget() {
877
+ if (process.platform === "darwin") {
878
+ return process.arch === "arm64" ? "bun-darwin-arm64" : "bun-darwin-x64";
879
+ }
880
+ if (process.platform === "linux") {
881
+ return process.arch === "arm64" ? "bun-linux-arm64" : "bun-linux-x64";
882
+ }
883
+ return "bun-windows-x64";
884
+ }
885
+ function createRuntimeBinaryBuildKey(input) {
886
+ return JSON.stringify({
887
+ version: 1,
888
+ bunVersion: Bun.version,
889
+ platform: process.platform,
890
+ arch: process.arch,
891
+ entrypoint: input.entrypoint,
892
+ define: sortRecord(input.define),
893
+ env: sortRecord(input.env)
894
+ });
895
+ }
896
+ async function isRuntimeBinaryBuildFresh(input) {
897
+ if (!existsSync5(input.outputPath) || !existsSync5(input.manifestPath)) {
898
+ return false;
899
+ }
900
+ let manifest = null;
901
+ try {
902
+ manifest = await Bun.file(input.manifestPath).json();
903
+ } catch {
904
+ return false;
905
+ }
906
+ if (!manifest || manifest.version !== 1 || manifest.buildKey !== input.buildKey) {
907
+ return false;
908
+ }
909
+ for (const [filePath, expectedDigest] of Object.entries(manifest.inputs || {})) {
910
+ if (!existsSync5(filePath)) {
911
+ return false;
912
+ }
913
+ if (await sha256File(filePath) !== expectedDigest) {
914
+ return false;
915
+ }
916
+ }
917
+ return true;
918
+ }
919
+ async function writeRuntimeBinaryCacheManifest(input) {
920
+ const inputs = {};
921
+ for (const inputPath of Object.keys(input.metafile?.inputs || {}).sort()) {
922
+ const normalized = normalizeBuildInputPath(input.cwd, inputPath);
923
+ if (!normalized || !existsSync5(normalized)) {
924
+ continue;
925
+ }
926
+ inputs[normalized] = await sha256File(normalized);
927
+ }
928
+ const manifest = {
929
+ version: 1,
930
+ buildKey: input.buildKey,
931
+ inputs
932
+ };
933
+ await Bun.write(input.manifestPath, `${JSON.stringify(manifest, null, 2)}
934
+ `);
935
+ }
936
+ function normalizeBuildInputPath(cwd, inputPath) {
937
+ if (!inputPath) {
938
+ return null;
939
+ }
940
+ if (inputPath.startsWith("file://")) {
941
+ return fileURLToPath(inputPath);
942
+ }
943
+ if (inputPath.startsWith("<")) {
944
+ return null;
945
+ }
946
+ return resolve6(cwd, inputPath);
947
+ }
948
+ async function sha256File(path) {
949
+ const hasher = new Bun.CryptoHasher("sha256");
950
+ hasher.update(await Bun.file(path).arrayBuffer());
951
+ return hasher.digest("hex");
952
+ }
953
+ function sortRecord(value) {
954
+ if (!value) {
955
+ return;
956
+ }
957
+ return Object.fromEntries(Object.entries(value).sort(([left], [right]) => left.localeCompare(right)));
958
+ }
959
+ async function runSerializedRuntimeBinaryBuild(action) {
960
+ const previous = runtimeBinaryBuildQueue;
961
+ let release;
962
+ runtimeBinaryBuildQueue = new Promise((resolve7) => {
963
+ release = resolve7;
964
+ });
965
+ await previous;
966
+ try {
967
+ return await action();
968
+ } finally {
969
+ release();
970
+ }
971
+ }
972
+ async function withTemporaryEnv(env, action) {
973
+ if (!env) {
974
+ return action();
975
+ }
976
+ const previousValues = new Map;
977
+ for (const [key, value] of Object.entries(env)) {
978
+ previousValues.set(key, process.env[key]);
979
+ if (value === undefined) {
980
+ delete process.env[key];
981
+ } else {
982
+ process.env[key] = value;
983
+ }
984
+ }
985
+ try {
986
+ return await action();
987
+ } finally {
988
+ for (const [key, value] of previousValues.entries()) {
989
+ if (value === undefined) {
990
+ delete process.env[key];
991
+ } else {
992
+ process.env[key] = value;
993
+ }
994
+ }
995
+ }
996
+ }
997
+ async function withTemporaryCwd(cwd, action) {
998
+ const previousCwd = process.cwd();
999
+ process.chdir(cwd);
1000
+ try {
1001
+ return await action();
1002
+ } finally {
1003
+ process.chdir(previousCwd);
1004
+ }
1005
+ }
1006
+ function copyRuntimeBinaryAssets(options) {
1007
+ const definitionRoot = options.rigDir ?? resolveRigLayout(options.projectRoot).definitionRoot;
1008
+ const runtimeDir = resolve6(options.outputDir, "runtime", "rig");
1009
+ mkdirSync3(runtimeDir, { recursive: true });
1010
+ const copiedEntries = [];
1011
+ for (const entry of options.entries ?? runtimeBinaryAssetEntries) {
1012
+ const source = resolve6(definitionRoot, entry);
1013
+ if (!existsSync5(source)) {
1014
+ continue;
1015
+ }
1016
+ cpSync(source, resolve6(runtimeDir, entry), { recursive: true });
1017
+ copiedEntries.push(entry);
1018
+ }
1019
+ return { copiedEntries, runtimeDir };
1020
+ }
1021
+ async function launchRuntimeBinary(request) {
1022
+ const options = {
1023
+ cwd: request.cwd,
1024
+ env: request.env ? { ...process.env, ...request.env } : process.env
1025
+ };
1026
+ if (request.timeoutMs !== undefined) {
1027
+ options.timeoutMs = request.timeoutMs;
1028
+ }
1029
+ return spawnProcess(request.binaryPath, request.args, options);
1030
+ }
1031
+ async function spawnProcess(command, args, options) {
1032
+ const child = nodeSpawn(command, args, {
1033
+ cwd: options.cwd,
1034
+ env: options.env,
1035
+ stdio: ["ignore", "pipe", "pipe"]
1036
+ });
1037
+ let stdout = "";
1038
+ let stderr = "";
1039
+ child.stdout?.setEncoding("utf8");
1040
+ child.stderr?.setEncoding("utf8");
1041
+ child.stdout?.on("data", (chunk) => {
1042
+ stdout += chunk;
1043
+ });
1044
+ child.stderr?.on("data", (chunk) => {
1045
+ stderr += chunk;
1046
+ });
1047
+ let timedOut = false;
1048
+ let timer;
1049
+ const exitCode = await new Promise((resolveExit, rejectExit) => {
1050
+ if (options.timeoutMs && options.timeoutMs > 0) {
1051
+ timer = setTimeout(() => {
1052
+ timedOut = true;
1053
+ child.kill();
1054
+ }, options.timeoutMs);
1055
+ }
1056
+ child.once("error", rejectExit);
1057
+ child.once("close", (code) => resolveExit(code ?? (timedOut ? 1 : 0)));
1058
+ }).finally(() => {
1059
+ if (timer) {
1060
+ clearTimeout(timer);
1061
+ }
1062
+ });
1063
+ return { exitCode, stdout, stderr, timedOut };
1064
+ }
1065
+ // packages/runtime/src/plugins.ts
1066
+ import { existsSync as existsSync6, readdirSync } from "fs";
1067
+ import { basename as basename3, resolve as resolve7 } from "path";
1068
+
1069
+ // packages/runtime/src/control-plane/runtime/plugin-mode.ts
1070
+ var LEGACY_PLUGIN_SCAN_ENV = "RIG_LEGACY_PLUGIN_SCAN";
1071
+ function isLegacyPluginScanEnabled(env = process.env) {
1072
+ const value = env[LEGACY_PLUGIN_SCAN_ENV]?.trim().toLowerCase();
1073
+ return value === "1" || value === "true" || value === "yes" || value === "on";
1074
+ }
1075
+
1076
+ // packages/runtime/src/plugins.ts
1077
+ var runtimeHookPhases = ["beforeCommand", "afterCommand", "onEvent"];
1078
+ var PLUGIN_SOURCE_PATTERN = /\.plugin\.(ts|js|mjs|cjs)$/;
1079
+ function inferRuntimePluginName(fileName) {
1080
+ return fileName.replace(PLUGIN_SOURCE_PATTERN, "");
1081
+ }
1082
+ function describeRuntimePluginFiles(filePaths) {
1083
+ return filePaths.filter((filePath) => PLUGIN_SOURCE_PATTERN.test(filePath)).map((filePath) => {
1084
+ const fileName = filePath.split(/[\\/]/).at(-1) ?? filePath;
1085
+ const name = inferRuntimePluginName(fileName);
1086
+ return { name, sourcePath: filePath, binaryName: name };
1087
+ });
1088
+ }
1089
+
1090
+ class PluginManager {
1091
+ eventBus;
1092
+ context;
1093
+ pluginDir;
1094
+ pluginFiles;
1095
+ pluginNames;
1096
+ localBinDir;
1097
+ imageBinDir;
1098
+ pluginsRequireBinaries;
1099
+ ensureImageBinDir;
1100
+ plugins = null;
1101
+ loadPromise = null;
1102
+ constructor(options) {
1103
+ this.eventBus = options.eventBus;
1104
+ this.context = options.context;
1105
+ this.pluginDir = options.pluginDir;
1106
+ this.pluginFiles = options.pluginFiles;
1107
+ this.pluginNames = options.pluginNames;
1108
+ this.localBinDir = options.localBinDir;
1109
+ this.imageBinDir = options.imageBinDir;
1110
+ this.pluginsRequireBinaries = options.pluginsRequireBinaries;
1111
+ this.ensureImageBinDir = options.ensureImageBinDir;
1112
+ }
1113
+ static async load(options) {
1114
+ const pluginDir = options.pluginDir ?? resolve7(options.projectRoot, "rig", "plugins");
1115
+ const localBinDir = options.localBinDir ?? resolve7(options.projectRoot, "rig", "plugins");
1116
+ const imageBinDir = options.imageBinDir ?? (options.runtimeContext ? resolve7(options.runtimeContext.binDir, "plugins") : "");
1117
+ const legacyPluginScan = options.legacyPluginScan ?? isLegacyPluginScanEnabled(options.env);
1118
+ const pluginFiles = legacyPluginScan ? safeReadDir(pluginDir).filter((entry) => PLUGIN_SOURCE_PATTERN.test(entry)) : [];
1119
+ const pluginNames = pluginFiles.map((file) => inferRuntimePluginName(basename3(file)));
1120
+ const context = {
1121
+ projectRoot: options.projectRoot,
1122
+ runId: options.runId,
1123
+ eventBus: options.eventBus
1124
+ };
1125
+ return new PluginManager({
1126
+ eventBus: options.eventBus,
1127
+ context,
1128
+ pluginDir,
1129
+ pluginFiles,
1130
+ pluginNames,
1131
+ localBinDir,
1132
+ imageBinDir,
1133
+ pluginsRequireBinaries: options.pluginsRequireBinaries ?? true,
1134
+ ensureImageBinDir: options.ensureImageBinDir
1135
+ });
1136
+ }
1137
+ list() {
1138
+ if (this.plugins) {
1139
+ return this.plugins.map((plugin) => ({
1140
+ name: plugin.name,
1141
+ validators: plugin.validators?.map((validator) => validator.id) ?? []
1142
+ }));
1143
+ }
1144
+ return this.pluginNames.map((name) => ({ name, validators: [] }));
1145
+ }
1146
+ async beforeCommand(ctx) {
1147
+ const plugins = await this.ensureLoaded();
1148
+ for (const plugin of plugins) {
1149
+ if (!plugin.beforeCommand)
1150
+ continue;
1151
+ await this.safeInvoke(plugin.name, "beforeCommand", () => plugin.beforeCommand?.(ctx, this.context));
1152
+ }
1153
+ }
1154
+ async afterCommand(result) {
1155
+ const plugins = await this.ensureLoaded();
1156
+ for (const plugin of plugins) {
1157
+ if (!plugin.afterCommand)
1158
+ continue;
1159
+ await this.safeInvoke(plugin.name, "afterCommand", () => plugin.afterCommand?.(result, this.context));
1160
+ }
1161
+ }
1162
+ async onEvent(event) {
1163
+ const plugins = this.plugins;
1164
+ if (!plugins)
1165
+ return;
1166
+ for (const plugin of plugins) {
1167
+ if (!plugin.onEvent)
1168
+ continue;
1169
+ await this.safeInvoke(plugin.name, "onEvent", () => plugin.onEvent?.(event, this.context));
1170
+ }
1171
+ }
1172
+ async runValidators(taskId) {
1173
+ const plugins = await this.ensureLoaded();
1174
+ const results = [];
1175
+ for (const plugin of plugins) {
1176
+ for (const validator of plugin.validators ?? []) {
1177
+ await this.eventBus.emit("validator.started", {
1178
+ plugin: plugin.name,
1179
+ validator: validator.id,
1180
+ taskId
1181
+ });
1182
+ try {
1183
+ const result = await validator.run({ taskId, projectRoot: this.context.projectRoot }, this.context);
1184
+ results.push(result);
1185
+ await this.eventBus.emit("validator.finished", {
1186
+ plugin: plugin.name,
1187
+ validator: validator.id,
1188
+ taskId,
1189
+ passed: result.passed,
1190
+ summary: result.summary
1191
+ });
1192
+ } catch (error) {
1193
+ const failed = {
1194
+ id: validator.id,
1195
+ passed: false,
1196
+ summary: `${plugin.name}/${validator.id} failed unexpectedly`,
1197
+ details: `${error}`
1198
+ };
1199
+ results.push(failed);
1200
+ await this.eventBus.emit("validator.finished", {
1201
+ plugin: plugin.name,
1202
+ validator: validator.id,
1203
+ taskId,
1204
+ passed: false,
1205
+ summary: failed.summary,
1206
+ details: failed.details
1207
+ });
1208
+ }
1209
+ }
1210
+ }
1211
+ return results;
1212
+ }
1213
+ async ensureLoaded() {
1214
+ if (this.plugins)
1215
+ return this.plugins;
1216
+ if (this.loadPromise)
1217
+ return this.loadPromise;
1218
+ this.loadPromise = this.loadCompiledPlugins();
1219
+ try {
1220
+ this.plugins = await this.loadPromise;
1221
+ return this.plugins;
1222
+ } finally {
1223
+ this.loadPromise = null;
1224
+ }
1225
+ }
1226
+ resolveBinPath(binName) {
1227
+ const candidates = [this.imageBinDir, this.localBinDir].filter(Boolean).map((dir) => resolve7(dir, binName));
1228
+ return candidates.find((candidate) => existsSync6(candidate));
1229
+ }
1230
+ async loadCompiledPlugins() {
1231
+ const plugins = [];
1232
+ for (const file of this.pluginFiles) {
1233
+ const binName = inferRuntimePluginName(basename3(file));
1234
+ let binPath = this.resolveBinPath(binName);
1235
+ if (!binPath && !this.imageBinDir && this.pluginsRequireBinaries && this.ensureImageBinDir) {
1236
+ try {
1237
+ this.imageBinDir = await this.ensureImageBinDir(this.context.projectRoot);
1238
+ binPath = this.resolveBinPath(binName);
1239
+ } catch {}
1240
+ }
1241
+ if (!binPath) {
1242
+ const triedPaths = [this.imageBinDir, this.localBinDir].filter(Boolean).map((dir) => resolve7(dir, binName));
1243
+ const missingError = `Compiled plugin binary not found for '${binName}'. Tried: ${triedPaths.join(", ")}`;
1244
+ await this.eventBus.emit("plugin.error", {
1245
+ file: resolve7(this.pluginDir, file),
1246
+ phase: "load",
1247
+ error: missingError
1248
+ });
1249
+ if (this.pluginsRequireBinaries) {
1250
+ throw new Error(missingError);
1251
+ }
1252
+ plugins.push({ name: binName, validators: [] });
1253
+ await this.eventBus.emit("plugin.loaded", {
1254
+ plugin: binName,
1255
+ file: resolve7(this.pluginDir, file),
1256
+ source: "metadata-only"
1257
+ });
1258
+ continue;
1259
+ }
1260
+ const wrapper = createBinaryPluginWrapper(binName, binPath, this.context.projectRoot);
1261
+ plugins.push(wrapper);
1262
+ await this.eventBus.emit("plugin.loaded", {
1263
+ plugin: wrapper.name,
1264
+ file: binPath,
1265
+ source: "compiled-binary"
1266
+ });
1267
+ }
1268
+ return plugins;
1269
+ }
1270
+ async safeInvoke(pluginName, hook, call) {
1271
+ try {
1272
+ await call();
1273
+ } catch (error) {
1274
+ await this.eventBus.emit("plugin.error", {
1275
+ plugin: pluginName,
1276
+ phase: hook,
1277
+ error: `${error}`
1278
+ });
1279
+ }
1280
+ }
1281
+ }
1282
+ function createBinaryPluginWrapper(name, binPath, projectRoot) {
1283
+ return {
1284
+ name,
1285
+ validators: [
1286
+ {
1287
+ id: `${name}:compiled`,
1288
+ async run(ctx) {
1289
+ const { exitCode, stdout, stderr } = await launchRuntimeBinary({
1290
+ binaryPath: binPath,
1291
+ args: ["--validate", ctx.taskId, ctx.projectRoot],
1292
+ cwd: projectRoot
1293
+ });
1294
+ if (exitCode !== 0) {
1295
+ return {
1296
+ id: `${name}:compiled`,
1297
+ passed: false,
1298
+ summary: `Plugin binary ${name} exited with code ${exitCode}`,
1299
+ details: stderr || stdout
1300
+ };
1301
+ }
1302
+ try {
1303
+ const results = JSON.parse(stdout.trim());
1304
+ const failed = results.filter((result) => !result.passed);
1305
+ if (failed.length > 0) {
1306
+ return {
1307
+ id: `${name}:compiled`,
1308
+ passed: false,
1309
+ summary: `${failed.length} of ${results.length} validator(s) failed`,
1310
+ details: failed.map((result) => `${result.id}: ${result.summary}`).join(`
1311
+ `)
1312
+ };
1313
+ }
1314
+ return {
1315
+ id: `${name}:compiled`,
1316
+ passed: true,
1317
+ summary: `All ${results.length} validator(s) passed`
1318
+ };
1319
+ } catch {
1320
+ return {
1321
+ id: `${name}:compiled`,
1322
+ passed: false,
1323
+ summary: `Failed to parse output from compiled plugin ${name}`,
1324
+ details: stdout.slice(0, 500)
1325
+ };
1326
+ }
1327
+ }
1328
+ }
1329
+ ]
1330
+ };
1331
+ }
1332
+ function safeReadDir(path) {
1333
+ try {
1334
+ return readdirSync(path, { withFileTypes: true }).filter((entry) => entry.isFile()).map((entry) => entry.name).sort();
1335
+ } catch {
1336
+ return [];
1337
+ }
1338
+ }
1339
+ // packages/runtime/src/agent-mode.ts
1340
+ function looksLikeShellInvocation(args, mode = process.env.RIG_AGENT_MODE) {
1341
+ if (mode === "shell") {
1342
+ return true;
1343
+ }
1344
+ if (mode === "agent") {
1345
+ return false;
1346
+ }
1347
+ if (args.length === 0) {
1348
+ return false;
1349
+ }
1350
+ const first = args[0];
1351
+ if (!first) {
1352
+ return false;
1353
+ }
1354
+ const bashLikeFlags = new Set([
1355
+ "-c",
1356
+ "-lc",
1357
+ "-l",
1358
+ "-i",
1359
+ "-s",
1360
+ "--login",
1361
+ "--noprofile",
1362
+ "--norc",
1363
+ "--posix",
1364
+ "--rcfile",
1365
+ "--init-file",
1366
+ "--restricted",
1367
+ "--debug",
1368
+ "--debugger",
1369
+ "--verbose",
1370
+ "--wordexp",
1371
+ "--dump-strings",
1372
+ "--dump-po-strings",
1373
+ "--help"
1374
+ ]);
1375
+ if (bashLikeFlags.has(first)) {
1376
+ return true;
1377
+ }
1378
+ if (!first.startsWith("-")) {
1379
+ return first.endsWith(".sh");
1380
+ }
1381
+ return false;
1382
+ }
1383
+ // packages/runtime/src/execution.ts
1384
+ function assertMatchingIds(bundle, lease) {
1385
+ if (bundle.runId !== lease.runId) {
1386
+ throw new Error(`Remote bundle runId ${bundle.runId} does not match lease runId ${lease.runId}`);
1387
+ }
1388
+ if (bundle.leaseId !== lease.leaseId) {
1389
+ throw new Error(`Remote bundle leaseId ${bundle.leaseId} does not match lease leaseId ${lease.leaseId}`);
1390
+ }
1391
+ if (bundle.workspaceId !== lease.workspaceId) {
1392
+ throw new Error(`Remote bundle workspaceId ${bundle.workspaceId} does not match lease workspaceId ${lease.workspaceId}`);
1393
+ }
1394
+ }
1395
+ function createRuntimeExecutionSession(args) {
1396
+ assertMatchingIds(args.bundle, args.lease);
1397
+ return {
1398
+ runId: args.bundle.runId,
1399
+ leaseId: args.bundle.leaseId,
1400
+ workspaceId: args.bundle.workspaceId,
1401
+ hostId: args.lease.remoteHostId,
1402
+ runtimeAdapter: args.bundle.runtimeAdapter,
1403
+ runtimeMode: args.bundle.runtimeMode,
1404
+ interactionMode: args.bundle.interactionMode,
1405
+ model: args.bundle.model,
1406
+ prompt: args.bundle.prompt,
1407
+ workspacePath: args.bundle.workspacePath,
1408
+ taskId: args.bundle.taskId,
1409
+ taskTitle: args.bundle.taskTitle,
1410
+ conversationLength: args.bundle.conversation.length,
1411
+ startedAt: args.startedAt ?? new Date().toISOString()
1412
+ };
1413
+ }
1414
+ // packages/runtime/src/control-plane/tasks/task-record-reader.ts
1415
+ async function findTaskById(reader, id) {
1416
+ const tasks = await reader.listTasks();
1417
+ return tasks.find((task) => task.id === id) ?? null;
1418
+ }
1419
+ // packages/runtime/src/control-plane/tasks/plugin-task-source.ts
1420
+ class TaskRecordSourceError extends Error {
1421
+ code;
1422
+ projectRoot;
1423
+ sourceId;
1424
+ sourceKind;
1425
+ operation;
1426
+ cause;
1427
+ constructor(input) {
1428
+ super(input.message, { cause: input.cause });
1429
+ this.name = "TaskRecordSourceError";
1430
+ this.code = input.code;
1431
+ this.projectRoot = input.projectRoot;
1432
+ this.operation = input.operation;
1433
+ this.sourceId = input.sourceId ?? null;
1434
+ this.sourceKind = input.sourceKind ?? null;
1435
+ this.cause = input.cause;
1436
+ }
1437
+ }
1438
+ function createPluginTaskRecordReader(context, options) {
1439
+ const source = selectTaskSource(context.taskSourceRegistry, options);
1440
+ return {
1441
+ async listTasks() {
1442
+ try {
1443
+ return await source.list();
1444
+ } catch (cause) {
1445
+ throw readFailedError(source, options, "list", cause);
1446
+ }
1447
+ },
1448
+ async getTask(id) {
1449
+ try {
1450
+ if (source.get) {
1451
+ return await source.get(id) ?? null;
1452
+ }
1453
+ return findTaskById({
1454
+ listTasks: () => source.list(),
1455
+ getTask: async () => null
1456
+ }, id);
1457
+ } catch (cause) {
1458
+ throw readFailedError(source, options, "get", cause);
1459
+ }
1460
+ }
1461
+ };
1462
+ }
1463
+ function selectTaskSource(registry, options) {
1464
+ try {
1465
+ if (options.sourceId) {
1466
+ return registry.resolveById(options.sourceId);
1467
+ }
1468
+ if (options.sourceKind) {
1469
+ return registry.resolveByKind(options.sourceKind);
1470
+ }
1471
+ const [source] = registry.list();
1472
+ if (source) {
1473
+ return source;
1474
+ }
1475
+ } catch (cause) {
1476
+ throw new TaskRecordSourceError({
1477
+ code: "TASK_SOURCE_NOT_CONFIGURED",
1478
+ message: taskSourceSelectionMessage(options),
1479
+ projectRoot: options.projectRoot,
1480
+ operation: "select",
1481
+ sourceId: options.sourceId ?? null,
1482
+ sourceKind: options.sourceKind ?? null,
1483
+ cause
1484
+ });
1485
+ }
1486
+ throw new TaskRecordSourceError({
1487
+ code: "TASK_SOURCE_NOT_CONFIGURED",
1488
+ message: taskSourceSelectionMessage(options),
1489
+ projectRoot: options.projectRoot,
1490
+ operation: "select",
1491
+ sourceId: options.sourceId ?? null,
1492
+ sourceKind: options.sourceKind ?? null
1493
+ });
1494
+ }
1495
+ function taskSourceSelectionMessage(options) {
1496
+ const selector = options.sourceId ? `id "${options.sourceId}"` : options.sourceKind ? `kind "${options.sourceKind}"` : "the configured plugin task source";
1497
+ return `No task source registered for ${selector} in project ${options.projectRoot}. Check rig.config.ts taskSource and loaded plugins.`;
1498
+ }
1499
+ function readFailedError(source, options, operation, cause) {
1500
+ const causeMessage = cause instanceof Error ? cause.message : String(cause);
1501
+ return new TaskRecordSourceError({
1502
+ code: "TASK_SOURCE_READ_FAILED",
1503
+ message: `Task source ${source.kind} (${source.id}) failed to ${operation} tasks for project ${options.projectRoot}: ${causeMessage}`,
1504
+ projectRoot: options.projectRoot,
1505
+ operation,
1506
+ sourceId: source.id,
1507
+ sourceKind: source.kind,
1508
+ cause
1509
+ });
1510
+ }
1511
+ // packages/runtime/src/remote-http.ts
1512
+ function trimTrailingSlash(value) {
1513
+ return value.endsWith("/") ? value.slice(0, -1) : value;
1514
+ }
1515
+ function normalizeAuthToken(value) {
1516
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
1517
+ }
1518
+ function authHeaders(authToken) {
1519
+ return authToken ? { authorization: `Bearer ${authToken}` } : {};
1520
+ }
1521
+ async function readJsonResponse(response, endpoint) {
1522
+ if (!response.ok) {
1523
+ const text = await response.text();
1524
+ throw new Error(`Rig runtime request failed for ${endpoint}: ${response.status} ${text}`.trim());
1525
+ }
1526
+ return await response.json();
1527
+ }
1528
+ async function postJson(fetchImpl, baseUrl, path, body, authToken) {
1529
+ const endpoint = `${trimTrailingSlash(baseUrl)}${path}`;
1530
+ const response = await fetchImpl(endpoint, {
1531
+ method: "POST",
1532
+ headers: { "content-type": "application/json", ...authHeaders(authToken) },
1533
+ body: JSON.stringify(body)
1534
+ });
1535
+ return readJsonResponse(response, endpoint);
1536
+ }
1537
+
1538
+ class HttpRuntimeHostSession {
1539
+ baseUrl;
1540
+ fetchImpl;
1541
+ authToken;
1542
+ constructor(baseUrl, fetchImpl = fetch, options = {}) {
1543
+ this.baseUrl = baseUrl;
1544
+ this.fetchImpl = fetchImpl;
1545
+ this.authToken = normalizeAuthToken(options.authToken ?? process.env.RIG_SERVER_AUTH_TOKEN ?? process.env.RIG_REMOTE_AUTH_TOKEN);
1546
+ }
1547
+ register(input) {
1548
+ return postJson(this.fetchImpl, this.baseUrl, "/api/remote/hosts/register", input, this.authToken);
1549
+ }
1550
+ heartbeat(input) {
1551
+ return postJson(this.fetchImpl, this.baseUrl, "/api/remote/hosts/heartbeat", input, this.authToken);
1552
+ }
1553
+ claimLease(input) {
1554
+ return postJson(this.fetchImpl, this.baseUrl, "/api/remote/runs/claim", input, this.authToken);
1555
+ }
1556
+ }
1557
+
1558
+ class HttpRuntimeRunReporter {
1559
+ baseUrl;
1560
+ fetchImpl;
1561
+ authToken;
1562
+ constructor(baseUrl, fetchImpl = fetch, options = {}) {
1563
+ this.baseUrl = baseUrl;
1564
+ this.fetchImpl = fetchImpl;
1565
+ this.authToken = normalizeAuthToken(options.authToken ?? process.env.RIG_SERVER_AUTH_TOKEN ?? process.env.RIG_REMOTE_AUTH_TOKEN);
1566
+ }
1567
+ reportStarted(input) {
1568
+ return postJson(this.fetchImpl, this.baseUrl, "/api/remote/runs/start", input, this.authToken);
1569
+ }
1570
+ reportLog(input) {
1571
+ return postJson(this.fetchImpl, this.baseUrl, "/api/remote/runs/log", input, this.authToken);
1572
+ }
1573
+ reportMessage(input) {
1574
+ return postJson(this.fetchImpl, this.baseUrl, "/api/remote/runs/message", input, this.authToken);
1575
+ }
1576
+ reportCompleted(input) {
1577
+ return postJson(this.fetchImpl, this.baseUrl, "/api/remote/runs/complete", input, this.authToken);
1578
+ }
1579
+ reportFailed(input) {
1580
+ return postJson(this.fetchImpl, this.baseUrl, "/api/remote/runs/fail", input, this.authToken);
1581
+ }
1582
+ reportReleased(input) {
1583
+ return postJson(this.fetchImpl, this.baseUrl, "/api/remote/runs/release", input, this.authToken);
1584
+ }
1585
+ reportArtifact(input) {
1586
+ return postJson(this.fetchImpl, this.baseUrl, "/api/remote/runs/artifact", input, this.authToken);
1587
+ }
1588
+ }
1589
+
1590
+ // packages/runtime/src/index.ts
1591
+ var RIG_RUNTIME_PACKAGE = "@rig/runtime";
1592
+ export {
1593
+ writeRuntimeContext,
1594
+ secretDefinesFromEnv,
1595
+ runtimeHookPhases,
1596
+ runtimeContextStringFields,
1597
+ runtimeContextArrayFields,
1598
+ runtimeBinaryAssetEntries,
1599
+ resolveRuntimeSecrets,
1600
+ resolveRigLayout,
1601
+ resolveNearestRigProjectRoot,
1602
+ resolveMonorepoRoot,
1603
+ readPublishedRigServerStateSync,
1604
+ readPublishedRigServerState,
1605
+ looksLikeShellInvocation,
1606
+ loadRuntimeContextFromEnv,
1607
+ loadRuntimeContext,
1608
+ loadDotEnvSecrets,
1609
+ launchRuntimeBinary,
1610
+ isRuntimeBinaryAssetEntry,
1611
+ inferRuntimePluginName,
1612
+ findTaskById,
1613
+ ensureLocalRigServerConnection,
1614
+ describeRuntimePluginFiles,
1615
+ createRuntimeExecutionSession,
1616
+ createRuntimeBinaryBuildManifest,
1617
+ createPluginTaskRecordReader,
1618
+ copyRuntimeBinaryAssets,
1619
+ buildRuntimeBinary,
1620
+ TaskRecordSourceError,
1621
+ RuntimeEventBus,
1622
+ RUNTIME_CONTEXT_ENV,
1623
+ RIG_STATE_DIRNAME,
1624
+ RIG_RUNTIME_PACKAGE,
1625
+ RIG_DEFINITION_DIRNAME,
1626
+ RIG_ARTIFACTS_DIRNAME,
1627
+ PluginManager,
1628
+ HttpRuntimeRunReporter,
1629
+ HttpRuntimeHostSession,
1630
+ GeneralCliEventBus,
1631
+ GeneralCliEventBus as EventBus,
1632
+ BAKED_RUNTIME_SECRETS
1633
+ };