@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,854 @@
1
+ // @bun
2
+ // packages/runtime/src/control-plane/remote.ts
3
+ import { chmodSync as chmodSync2, existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
4
+ import { homedir as homedir2 } from "os";
5
+ import { dirname as dirname2, join as join2 } from "path";
6
+ import { parse as parseToml2, stringify as stringifyToml2 } from "smol-toml";
7
+
8
+ // packages/runtime/src/control-plane/authority-files.ts
9
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, appendFileSync, copyFileSync, statSync, readdirSync, chmodSync } from "fs";
10
+ import { homedir } from "os";
11
+ import { dirname, join, relative, resolve } from "path";
12
+ import { randomUUID } from "crypto";
13
+ import { parse as parseToml, stringify as stringifyToml } from "smol-toml";
14
+ function readTomlFile(path, fallback) {
15
+ if (!existsSync(path))
16
+ return fallback;
17
+ const raw = readFileSync(path, "utf8");
18
+ if (!raw.trim())
19
+ return fallback;
20
+ return parseToml(raw);
21
+ }
22
+ function writeTomlFile(path, value) {
23
+ mkdirSync(dirname(path), { recursive: true });
24
+ writeFileSync(path, `${stringifyToml(value).trimEnd()}
25
+ `, "utf8");
26
+ }
27
+ function normalizeString(value) {
28
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
29
+ }
30
+ function normalizeStringArray(value) {
31
+ if (!Array.isArray(value))
32
+ return [];
33
+ return value.map((entry) => normalizeString(entry)).filter((entry) => entry !== null);
34
+ }
35
+ function normalizePort(value) {
36
+ const port = typeof value === "number" ? value : Number(value);
37
+ return Number.isInteger(port) && port > 0 && port <= 65535 ? port : 7890;
38
+ }
39
+ function loadRemoteEndpointsToml(projectRoot) {
40
+ const paths = resolveAuthorityPaths(projectRoot);
41
+ const parsed = readTomlFile(paths.remoteEndpointsPath, { version: 1, endpoints: {} });
42
+ return {
43
+ version: parsed.version ?? 1,
44
+ endpoints: parsed.endpoints ?? {}
45
+ };
46
+ }
47
+ function loadRemoteSecretsToml(projectRoot) {
48
+ const paths = resolveAuthorityPaths(projectRoot);
49
+ const parsed = readTomlFile(paths.remoteSecretsPath, { version: 1, secrets: {} });
50
+ return {
51
+ version: parsed.version ?? 1,
52
+ secrets: parsed.secrets ?? {}
53
+ };
54
+ }
55
+ function saveRemoteEndpointsToml(projectRoot, payload) {
56
+ const paths = resolveAuthorityPaths(projectRoot);
57
+ writeTomlFile(paths.remoteEndpointsPath, payload);
58
+ }
59
+ function saveRemoteSecretsToml(projectRoot, payload) {
60
+ const paths = resolveAuthorityPaths(projectRoot);
61
+ writeTomlFile(paths.remoteSecretsPath, payload);
62
+ try {
63
+ chmodSync(paths.remoteSecretsPath, 384);
64
+ } catch {}
65
+ }
66
+ function resolveAuthorityPaths(projectRoot) {
67
+ const normalizedRoot = resolve(projectRoot);
68
+ const stateRoot = resolveAuthorityStateRoot(normalizedRoot);
69
+ const stateDir = resolveAuthorityStateDir(normalizedRoot);
70
+ return {
71
+ projectRoot: normalizedRoot,
72
+ harnessRoot: resolve(normalizedRoot, "rig"),
73
+ runsDir: resolve(stateRoot, "runs"),
74
+ remoteDir: resolve(stateRoot, "remote"),
75
+ stateDir,
76
+ remoteEndpointsPath: resolve(stateRoot, "remote", "endpoints.toml"),
77
+ remoteSecretsPath: resolve(stateDir, "remote-secrets.toml")
78
+ };
79
+ }
80
+ function resolveAuthorityStateRoot(projectRoot) {
81
+ const normalizedRoot = resolve(projectRoot);
82
+ const taskWorkspace = process.env.RIG_TASK_WORKSPACE?.trim();
83
+ if (taskWorkspace) {
84
+ return resolve(taskWorkspace, ".rig");
85
+ }
86
+ const stateDir = process.env.RIG_STATE_DIR?.trim();
87
+ if (stateDir) {
88
+ return dirname(resolve(stateDir));
89
+ }
90
+ const logsDir = process.env.RIG_LOGS_DIR?.trim();
91
+ if (logsDir) {
92
+ return dirname(resolve(logsDir));
93
+ }
94
+ const sessionFile = process.env.RIG_SESSION_FILE?.trim();
95
+ if (sessionFile) {
96
+ return dirname(dirname(resolve(sessionFile)));
97
+ }
98
+ const projectStateRoot = resolve(normalizedRoot, ".rig");
99
+ if (existsSync(projectStateRoot)) {
100
+ return projectStateRoot;
101
+ }
102
+ return resolve(normalizedRoot, ".rig");
103
+ }
104
+ function resolveAuthorityStateDir(projectRoot) {
105
+ const explicit = process.env.RIG_STATE_DIR?.trim();
106
+ if (explicit) {
107
+ return resolve(explicit);
108
+ }
109
+ return resolve(resolveAuthorityStateRoot(projectRoot), "state");
110
+ }
111
+ function listAuthorityRemoteEndpoints(projectRoot) {
112
+ const endpoints = loadRemoteEndpointsToml(projectRoot).endpoints ?? {};
113
+ const secrets = loadRemoteSecretsToml(projectRoot).secrets ?? {};
114
+ return Object.values(endpoints).map((entry) => {
115
+ const token = secrets[entry.secret_ref] ?? "";
116
+ return {
117
+ id: entry.id,
118
+ alias: entry.alias,
119
+ host: entry.host,
120
+ port: normalizePort(entry.port),
121
+ token,
122
+ autoConnect: Boolean(entry.auto_connect),
123
+ addedAt: entry.created_at,
124
+ updatedAt: entry.updated_at,
125
+ lastConnectedAt: normalizeString(entry.last_connected_at) ?? null,
126
+ labels: normalizeStringArray(entry.labels),
127
+ capabilities: normalizeStringArray(entry.capabilities),
128
+ transport: normalizeString(entry.transport) ?? "websocket",
129
+ secretRef: entry.secret_ref
130
+ };
131
+ }).sort((left, right) => left.alias.localeCompare(right.alias));
132
+ }
133
+ function nextRemoteEndpointRecord(input) {
134
+ const timestamp = new Date().toISOString();
135
+ const secretRef = input.existing?.secret_ref ?? randomUUID();
136
+ return {
137
+ record: {
138
+ id: input.endpointId ?? input.existing?.id ?? randomUUID(),
139
+ alias: input.alias,
140
+ host: input.host,
141
+ port: normalizePort(input.port),
142
+ transport: normalizeString(input.transport) ?? normalizeString(input.existing?.transport) ?? "websocket",
143
+ auto_connect: input.autoConnect ?? input.existing?.auto_connect ?? false,
144
+ labels: input.labels ?? normalizeStringArray(input.existing?.labels),
145
+ capabilities: input.capabilities ?? normalizeStringArray(input.existing?.capabilities),
146
+ secret_ref: secretRef,
147
+ created_at: input.existing?.created_at ?? timestamp,
148
+ updated_at: timestamp,
149
+ last_connected_at: input.existing?.last_connected_at ?? null
150
+ },
151
+ secretRef
152
+ };
153
+ }
154
+ function upsertAuthorityRemoteEndpoint(projectRoot, input) {
155
+ const endpointsToml = loadRemoteEndpointsToml(projectRoot);
156
+ const secretsToml = loadRemoteSecretsToml(projectRoot);
157
+ const existing = Object.values(endpointsToml.endpoints ?? {}).find((entry) => entry.alias === input.alias) ?? null;
158
+ const { record, secretRef } = nextRemoteEndpointRecord({
159
+ endpointId: input.endpointId,
160
+ existing,
161
+ alias: input.alias,
162
+ host: input.host,
163
+ port: input.port,
164
+ token: input.token,
165
+ autoConnect: input.autoConnect,
166
+ transport: input.transport,
167
+ labels: input.labels,
168
+ capabilities: input.capabilities
169
+ });
170
+ endpointsToml.endpoints = {
171
+ ...endpointsToml.endpoints ?? {},
172
+ [record.id]: record
173
+ };
174
+ secretsToml.secrets = {
175
+ ...secretsToml.secrets ?? {},
176
+ [secretRef]: input.token
177
+ };
178
+ saveRemoteEndpointsToml(projectRoot, endpointsToml);
179
+ saveRemoteSecretsToml(projectRoot, secretsToml);
180
+ return listAuthorityRemoteEndpoints(projectRoot).find((entry) => entry.id === record.id);
181
+ }
182
+ function updateAuthorityRemoteEndpoint(projectRoot, input) {
183
+ const endpointsToml = loadRemoteEndpointsToml(projectRoot);
184
+ const secretsToml = loadRemoteSecretsToml(projectRoot);
185
+ const current = Object.values(endpointsToml.endpoints ?? {}).find((entry) => input.endpointId && entry.id === input.endpointId || input.alias && entry.alias === input.alias);
186
+ if (!current)
187
+ return null;
188
+ const record = {
189
+ ...current,
190
+ alias: normalizeString(input.alias) ?? current.alias,
191
+ host: normalizeString(input.host) ?? current.host,
192
+ port: input.port !== undefined ? normalizePort(input.port) : current.port,
193
+ auto_connect: input.autoConnect ?? current.auto_connect,
194
+ transport: normalizeString(input.transport) ?? current.transport,
195
+ labels: input.labels ?? normalizeStringArray(current.labels),
196
+ capabilities: input.capabilities ?? normalizeStringArray(current.capabilities),
197
+ updated_at: new Date().toISOString()
198
+ };
199
+ endpointsToml.endpoints = {
200
+ ...endpointsToml.endpoints ?? {},
201
+ [record.id]: record
202
+ };
203
+ if (input.token !== undefined) {
204
+ secretsToml.secrets = {
205
+ ...secretsToml.secrets ?? {},
206
+ [record.secret_ref]: input.token
207
+ };
208
+ }
209
+ saveRemoteEndpointsToml(projectRoot, endpointsToml);
210
+ saveRemoteSecretsToml(projectRoot, secretsToml);
211
+ return listAuthorityRemoteEndpoints(projectRoot).find((entry) => entry.id === record.id) ?? null;
212
+ }
213
+ function removeAuthorityRemoteEndpoint(projectRoot, endpointIdOrAlias) {
214
+ const endpointsToml = loadRemoteEndpointsToml(projectRoot);
215
+ const secretsToml = loadRemoteSecretsToml(projectRoot);
216
+ const entry = Object.values(endpointsToml.endpoints ?? {}).find((candidate) => candidate.id === endpointIdOrAlias || candidate.alias === endpointIdOrAlias);
217
+ if (!entry)
218
+ return false;
219
+ const nextEndpoints = { ...endpointsToml.endpoints ?? {} };
220
+ delete nextEndpoints[entry.id];
221
+ const nextSecrets = { ...secretsToml.secrets ?? {} };
222
+ delete nextSecrets[entry.secret_ref];
223
+ saveRemoteEndpointsToml(projectRoot, { version: endpointsToml.version ?? 1, endpoints: nextEndpoints });
224
+ saveRemoteSecretsToml(projectRoot, { version: secretsToml.version ?? 1, secrets: nextSecrets });
225
+ return true;
226
+ }
227
+ function markAuthorityRemoteEndpointConnected(projectRoot, endpointId, connectedAt = new Date().toISOString()) {
228
+ const endpointsToml = loadRemoteEndpointsToml(projectRoot);
229
+ const entry = endpointsToml.endpoints?.[endpointId];
230
+ if (!entry)
231
+ return;
232
+ endpointsToml.endpoints = {
233
+ ...endpointsToml.endpoints ?? {},
234
+ [endpointId]: {
235
+ ...entry,
236
+ last_connected_at: connectedAt,
237
+ updated_at: connectedAt
238
+ }
239
+ };
240
+ saveRemoteEndpointsToml(projectRoot, endpointsToml);
241
+ }
242
+ function importLegacyRemoteEndpoints(projectRoot, legacyPath = join(homedir(), ".config", "rig", "remotes.toml")) {
243
+ if (!existsSync(legacyPath)) {
244
+ return { imported: 0, skipped: 0, sourcePath: legacyPath };
245
+ }
246
+ const parsed = readTomlFile(legacyPath, { version: 1, remotes: {} });
247
+ let imported = 0;
248
+ let skipped = 0;
249
+ for (const [alias, entry] of Object.entries(parsed.remotes ?? {})) {
250
+ const host = normalizeString(entry.host);
251
+ const token = normalizeString(entry.token);
252
+ if (!host || !token) {
253
+ skipped += 1;
254
+ continue;
255
+ }
256
+ upsertAuthorityRemoteEndpoint(projectRoot, {
257
+ alias,
258
+ host,
259
+ port: normalizePort(entry.port),
260
+ token
261
+ });
262
+ imported += 1;
263
+ }
264
+ return { imported, skipped, sourcePath: legacyPath };
265
+ }
266
+ function doctorAuthorityRemoteEndpoints(projectRoot) {
267
+ const paths = resolveAuthorityPaths(projectRoot);
268
+ const endpoints = loadRemoteEndpointsToml(projectRoot).endpoints ?? {};
269
+ const secrets = loadRemoteSecretsToml(projectRoot).secrets ?? {};
270
+ const missingSecrets = Object.values(endpoints).filter((entry) => !normalizeString(secrets[entry.secret_ref])).map((entry) => entry.alias);
271
+ const warnings = [];
272
+ if (!existsSync(paths.remoteEndpointsPath)) {
273
+ warnings.push("Remote endpoint manifest is missing.");
274
+ }
275
+ if (!existsSync(paths.remoteSecretsPath)) {
276
+ warnings.push("Remote secret store is missing.");
277
+ }
278
+ return {
279
+ manifestPath: paths.remoteEndpointsPath,
280
+ secretsPath: paths.remoteSecretsPath,
281
+ endpointCount: Object.keys(endpoints).length,
282
+ missingSecrets,
283
+ warnings
284
+ };
285
+ }
286
+
287
+ // packages/runtime/src/control-plane/remote.ts
288
+ var DEFAULT_REMOTE_PORT = 7890;
289
+ var DEFAULT_TIMEOUTS = {
290
+ connectMs: 5000,
291
+ authMs: 5000,
292
+ requestMs: 30000,
293
+ subscriptionMs: 1e4
294
+ };
295
+ var REMOTES_CONFIG_PATH = join2(homedir2(), ".config", "rig", "remotes.toml");
296
+
297
+ class RemoteCliError extends Error {
298
+ code;
299
+ exitCode;
300
+ details;
301
+ constructor(code, message, exitCode = 1, details) {
302
+ super(message);
303
+ this.name = "RemoteCliError";
304
+ this.code = code;
305
+ this.exitCode = exitCode;
306
+ this.details = details;
307
+ }
308
+ }
309
+ function loadRemotesConfig(configPath = REMOTES_CONFIG_PATH) {
310
+ if (!existsSync2(configPath)) {
311
+ return { version: 1, remotes: {} };
312
+ }
313
+ try {
314
+ const content = readFileSync2(configPath, "utf-8");
315
+ if (!content.trim()) {
316
+ return { version: 1, remotes: {} };
317
+ }
318
+ const parsed = parseToml2(content);
319
+ return {
320
+ version: parsed.version ?? 1,
321
+ remotes: parsed.remotes ?? {}
322
+ };
323
+ } catch (error) {
324
+ throw new RemoteCliError("RIG_REMOTE_CONFIG_PARSE_ERROR", `Failed to parse remotes config at ${configPath}: ${error instanceof Error ? error.message : String(error)}`, 2, { configPath });
325
+ }
326
+ }
327
+ function saveRemotesConfig(config, configPath = REMOTES_CONFIG_PATH) {
328
+ mkdirSync2(dirname2(configPath), { recursive: true });
329
+ writeFileSync2(configPath, `${stringifyToml2(config).trimEnd()}
330
+ `, "utf-8");
331
+ try {
332
+ chmodSync2(configPath, 384);
333
+ } catch {}
334
+ }
335
+ function listManagedRemoteEndpoints(configPath = REMOTES_CONFIG_PATH, projectRoot) {
336
+ if (projectRoot) {
337
+ return listAuthorityRemoteEndpoints(projectRoot).map((entry) => ({
338
+ id: entry.id,
339
+ alias: entry.alias,
340
+ host: entry.host,
341
+ port: entry.port,
342
+ token: entry.token,
343
+ addedAt: entry.addedAt,
344
+ lastConnected: entry.lastConnectedAt
345
+ }));
346
+ }
347
+ const config = loadRemotesConfig(configPath);
348
+ return Object.entries(config.remotes ?? {}).map(([alias, entry]) => ({
349
+ id: alias,
350
+ alias,
351
+ host: normalizeString2(entry.host) || "",
352
+ port: Number.isFinite(entry.port) ? Number(entry.port) : DEFAULT_REMOTE_PORT,
353
+ token: normalizeString2(entry.token) || "",
354
+ addedAt: normalizeString2(entry.addedAt) || null,
355
+ lastConnected: normalizeString2(entry.lastConnected) || null
356
+ })).sort((left, right) => left.alias.localeCompare(right.alias));
357
+ }
358
+ function upsertManagedRemoteEndpoint(input, configPath = REMOTES_CONFIG_PATH, projectRoot) {
359
+ if (projectRoot) {
360
+ const saved = upsertAuthorityRemoteEndpoint(projectRoot, {
361
+ ...input,
362
+ token: input.token ?? ""
363
+ });
364
+ return {
365
+ id: saved.id,
366
+ alias: saved.alias,
367
+ host: saved.host,
368
+ port: saved.port,
369
+ token: saved.token,
370
+ addedAt: saved.addedAt,
371
+ lastConnected: saved.lastConnectedAt
372
+ };
373
+ }
374
+ const config = loadRemotesConfig(configPath);
375
+ const existing = config.remotes?.[input.alias];
376
+ const nextEntry = {
377
+ host: input.host,
378
+ port: input.port,
379
+ token: input.token,
380
+ addedAt: normalizeString2(existing?.addedAt) || new Date().toISOString(),
381
+ ...normalizeString2(existing?.lastConnected) ? { lastConnected: normalizeString2(existing?.lastConnected) } : {}
382
+ };
383
+ const nextConfig = {
384
+ version: config.version ?? 1,
385
+ remotes: {
386
+ ...config.remotes ?? {},
387
+ [input.alias]: nextEntry
388
+ }
389
+ };
390
+ saveRemotesConfig(nextConfig, configPath);
391
+ return {
392
+ id: input.alias,
393
+ alias: input.alias,
394
+ host: input.host,
395
+ port: input.port,
396
+ token: input.token ?? "",
397
+ addedAt: nextEntry.addedAt ?? null,
398
+ lastConnected: nextEntry.lastConnected ?? null
399
+ };
400
+ }
401
+ function removeManagedRemoteEndpoint(alias, configPath = REMOTES_CONFIG_PATH, projectRoot) {
402
+ if (projectRoot) {
403
+ return removeAuthorityRemoteEndpoint(projectRoot, alias);
404
+ }
405
+ const config = loadRemotesConfig(configPath);
406
+ if (!config.remotes?.[alias]) {
407
+ return false;
408
+ }
409
+ const nextRemotes = { ...config.remotes ?? {} };
410
+ delete nextRemotes[alias];
411
+ saveRemotesConfig({
412
+ version: config.version ?? 1,
413
+ remotes: nextRemotes
414
+ }, configPath);
415
+ return true;
416
+ }
417
+ function resolveRemoteEndpoint(options) {
418
+ const env = options.env ?? process.env;
419
+ const envHost = normalizeString2(env.RIG_REMOTE_HOST);
420
+ const envToken = normalizeString2(env.RIG_REMOTE_TOKEN);
421
+ const envPort = parsePort(normalizeString2(env.RIG_REMOTE_PORT), "RIG_REMOTE_PORT");
422
+ const envAlias = normalizeString2(env.RIG_REMOTE_ALIAS);
423
+ const explicitHost = normalizeString2(options.host);
424
+ const explicitToken = normalizeString2(options.token);
425
+ const explicitPort = parsePort(normalizeString2(options.port), "--port");
426
+ const explicitProvided = Boolean(explicitHost || explicitToken || explicitPort !== null);
427
+ const requestedAlias = normalizeString2(options.remoteAlias) || envAlias;
428
+ let endpoint = {
429
+ source: "env",
430
+ host: envHost || "",
431
+ port: envPort ?? DEFAULT_REMOTE_PORT,
432
+ token: envToken || "",
433
+ configPath: REMOTES_CONFIG_PATH
434
+ };
435
+ if (requestedAlias) {
436
+ if (options.projectRoot) {
437
+ const remote = listAuthorityRemoteEndpoints(options.projectRoot).find((entry) => entry.alias === requestedAlias);
438
+ if (!remote) {
439
+ const configPath = resolveAuthorityPaths(options.projectRoot).remoteEndpointsPath;
440
+ throw new RemoteCliError("RIG_REMOTE_ALIAS_NOT_FOUND", `Remote alias '${requestedAlias}' was not found in ${configPath}.`, 2, { alias: requestedAlias, configPath });
441
+ }
442
+ endpoint = {
443
+ source: "alias",
444
+ alias: requestedAlias,
445
+ host: remote.host,
446
+ port: remote.port,
447
+ token: remote.token,
448
+ configPath: resolveAuthorityPaths(options.projectRoot).remoteEndpointsPath
449
+ };
450
+ } else {
451
+ const config = loadRemotesConfig();
452
+ const remote = config.remotes?.[requestedAlias];
453
+ if (!remote) {
454
+ throw new RemoteCliError("RIG_REMOTE_ALIAS_NOT_FOUND", `Remote alias '${requestedAlias}' was not found in ${REMOTES_CONFIG_PATH}.`, 2, { alias: requestedAlias, configPath: REMOTES_CONFIG_PATH });
455
+ }
456
+ endpoint = {
457
+ source: "alias",
458
+ alias: requestedAlias,
459
+ host: normalizeString2(remote.host) || "",
460
+ port: Number.isFinite(remote.port) ? Number(remote.port) : DEFAULT_REMOTE_PORT,
461
+ token: normalizeString2(remote.token) || "",
462
+ configPath: REMOTES_CONFIG_PATH
463
+ };
464
+ }
465
+ }
466
+ if (explicitProvided) {
467
+ endpoint = {
468
+ ...endpoint,
469
+ source: "flags",
470
+ host: explicitHost || endpoint.host,
471
+ port: explicitPort ?? endpoint.port,
472
+ token: explicitToken || endpoint.token
473
+ };
474
+ }
475
+ if (!endpoint.host) {
476
+ throw new RemoteCliError("RIG_REMOTE_HOST_REQUIRED", "Remote host is required. Pass --host, --remote <alias>, or set RIG_REMOTE_HOST.", 2);
477
+ }
478
+ if (!Number.isFinite(endpoint.port) || endpoint.port <= 0 || endpoint.port > 65535) {
479
+ throw new RemoteCliError("RIG_REMOTE_INVALID_PORT", `Invalid remote port: ${endpoint.port}.`, 2);
480
+ }
481
+ return endpoint;
482
+ }
483
+
484
+ class RemoteWsClient {
485
+ endpoint;
486
+ ws = null;
487
+ connected = false;
488
+ pending = new Map;
489
+ onEvent;
490
+ requestTimeoutMs;
491
+ connectTimeoutMs;
492
+ authTimeoutMs;
493
+ subscriptionTimeoutMs;
494
+ connectionToken = null;
495
+ connectionTokenExpiresAt = null;
496
+ tokenRefreshTimer = null;
497
+ constructor(endpoint, options = {}) {
498
+ this.endpoint = endpoint;
499
+ this.onEvent = options.onEvent;
500
+ this.connectTimeoutMs = options.connectTimeoutMs ?? DEFAULT_TIMEOUTS.connectMs;
501
+ this.authTimeoutMs = options.authTimeoutMs ?? DEFAULT_TIMEOUTS.authMs;
502
+ this.requestTimeoutMs = options.requestTimeoutMs ?? DEFAULT_TIMEOUTS.requestMs;
503
+ this.subscriptionTimeoutMs = options.subscriptionTimeoutMs ?? DEFAULT_TIMEOUTS.subscriptionMs;
504
+ }
505
+ setEventHandler(handler) {
506
+ this.onEvent = handler;
507
+ }
508
+ async connect() {
509
+ if (this.connected) {
510
+ return;
511
+ }
512
+ const url = `ws://${this.endpoint.host}:${this.endpoint.port}`;
513
+ await new Promise((resolve2, reject) => {
514
+ let authResolved = false;
515
+ let connectTimer = setTimeout(() => {
516
+ connectTimer = null;
517
+ reject(new RemoteCliError("RIG_REMOTE_CONNECT_TIMEOUT", `Timed out connecting to ${url} after ${this.connectTimeoutMs}ms.`, 3, { host: this.endpoint.host, port: this.endpoint.port, timeoutMs: this.connectTimeoutMs }));
518
+ }, this.connectTimeoutMs);
519
+ const ws = new WebSocket(url);
520
+ this.ws = ws;
521
+ ws.onopen = () => {
522
+ const authMessage = {
523
+ type: "auth",
524
+ id: crypto.randomUUID(),
525
+ timestamp: new Date().toISOString(),
526
+ token: this.connectionToken || this.endpoint.token,
527
+ tokenType: this.connectionToken ? "connection" : "server"
528
+ };
529
+ let authTimer = setTimeout(() => {
530
+ authTimer = null;
531
+ reject(new RemoteCliError("RIG_REMOTE_AUTH_TIMEOUT", `Timed out waiting for auth response from ${url} after ${this.authTimeoutMs}ms.`, 3, { host: this.endpoint.host, port: this.endpoint.port, timeoutMs: this.authTimeoutMs }));
532
+ }, this.authTimeoutMs);
533
+ ws.send(JSON.stringify(authMessage));
534
+ const originalOnMessage = ws.onmessage;
535
+ ws.onmessage = (event) => {
536
+ const message = parseIncomingMessage(event.data);
537
+ if (!message) {
538
+ return;
539
+ }
540
+ if (message.type === "auth_response" && !authResolved) {
541
+ authResolved = true;
542
+ if (connectTimer) {
543
+ clearTimeout(connectTimer);
544
+ connectTimer = null;
545
+ }
546
+ if (authTimer) {
547
+ clearTimeout(authTimer);
548
+ authTimer = null;
549
+ }
550
+ const auth = message;
551
+ if (!auth.success) {
552
+ reject(new RemoteCliError("RIG_REMOTE_AUTH_FAILED", auth.error || "Remote authentication failed.", 3, { host: this.endpoint.host, port: this.endpoint.port }));
553
+ return;
554
+ }
555
+ if (auth.connectionToken && auth.connectionTokenExpiresAt) {
556
+ this.connectionToken = auth.connectionToken;
557
+ this.connectionTokenExpiresAt = auth.connectionTokenExpiresAt;
558
+ this.scheduleTokenRefresh();
559
+ }
560
+ if (this.endpoint.configPath.endsWith("endpoints.toml")) {
561
+ const projectRoot = dirname2(dirname2(dirname2(this.endpoint.configPath)));
562
+ try {
563
+ markAuthorityRemoteEndpointConnected(projectRoot, this.endpoint.alias ? listAuthorityRemoteEndpoints(projectRoot).find((entry) => entry.alias === this.endpoint.alias)?.id ?? "" : "");
564
+ } catch {}
565
+ }
566
+ this.connected = true;
567
+ ws.onmessage = (event2) => {
568
+ const next = parseIncomingMessage(event2.data);
569
+ if (!next) {
570
+ return;
571
+ }
572
+ this.routeMessage(next);
573
+ };
574
+ resolve2();
575
+ return;
576
+ }
577
+ if (typeof originalOnMessage === "function") {
578
+ originalOnMessage.call(ws, event);
579
+ }
580
+ };
581
+ };
582
+ ws.onerror = () => {
583
+ if (connectTimer) {
584
+ clearTimeout(connectTimer);
585
+ connectTimer = null;
586
+ }
587
+ if (!authResolved) {
588
+ reject(new RemoteCliError("RIG_REMOTE_CONNECT_FAILED", `Failed to connect to ${url}.`, 3, { host: this.endpoint.host, port: this.endpoint.port }));
589
+ }
590
+ };
591
+ ws.onclose = () => {
592
+ this.connected = false;
593
+ this.clearPending("Connection closed");
594
+ };
595
+ });
596
+ }
597
+ disconnect() {
598
+ this.connected = false;
599
+ this.clearTokenRefreshTimer();
600
+ this.clearPending("Connection closed");
601
+ if (this.ws) {
602
+ try {
603
+ this.ws.close();
604
+ } catch {}
605
+ this.ws = null;
606
+ }
607
+ }
608
+ async subscribe(eventTypes = []) {
609
+ const message = { type: "subscribe" };
610
+ if (eventTypes.length > 0) {
611
+ message.eventTypes = eventTypes;
612
+ }
613
+ const response = await this.request(message, this.subscriptionTimeoutMs);
614
+ return expectType(response, "operation_result");
615
+ }
616
+ async unsubscribe() {
617
+ return expectType(await this.request({ type: "unsubscribe" }), "operation_result");
618
+ }
619
+ async getState() {
620
+ return expectType(await this.request({ type: "get_state" }), "state_response");
621
+ }
622
+ async getTasks() {
623
+ return expectType(await this.request({ type: "get_tasks" }), "tasks_response");
624
+ }
625
+ async pause() {
626
+ return expectType(await this.request({ type: "pause" }), "operation_result");
627
+ }
628
+ async resume() {
629
+ return expectType(await this.request({ type: "resume" }), "operation_result");
630
+ }
631
+ async interrupt() {
632
+ return expectType(await this.request({ type: "interrupt" }), "operation_result");
633
+ }
634
+ async continueExecution() {
635
+ return expectType(await this.request({ type: "continue" }), "operation_result");
636
+ }
637
+ async refreshTasks() {
638
+ return expectType(await this.request({ type: "refresh_tasks" }), "operation_result");
639
+ }
640
+ async addIterations(count) {
641
+ return expectType(await this.request({ type: "add_iterations", count }), "operation_result");
642
+ }
643
+ async removeIterations(count) {
644
+ return expectType(await this.request({ type: "remove_iterations", count }), "operation_result");
645
+ }
646
+ async getPromptPreview(taskId) {
647
+ return expectType(await this.request({ type: "get_prompt_preview", taskId }), "prompt_preview_response");
648
+ }
649
+ async getIterationOutput(taskId) {
650
+ return expectType(await this.request({ type: "get_iteration_output", taskId }), "iteration_output_response");
651
+ }
652
+ async startOrchestration(options) {
653
+ return expectType(await this.request({
654
+ type: "orchestrate:start",
655
+ maxWorkers: options.maxWorkers,
656
+ maxIterations: options.maxIterations,
657
+ directMerge: options.directMerge
658
+ }), "orchestrate:start_response");
659
+ }
660
+ async pauseOrchestration(orchestrationId) {
661
+ return expectType(await this.request({ type: "orchestrate:pause", orchestrationId }), "operation_result");
662
+ }
663
+ async resumeOrchestration(orchestrationId) {
664
+ return expectType(await this.request({ type: "orchestrate:resume", orchestrationId }), "operation_result");
665
+ }
666
+ async stopOrchestration(orchestrationId) {
667
+ return expectType(await this.request({ type: "orchestrate:stop", orchestrationId }), "operation_result");
668
+ }
669
+ async getOrchestrationState(orchestrationId) {
670
+ return expectType(await this.request({ type: "orchestrate:get_state", orchestrationId }), "orchestrate:state_response");
671
+ }
672
+ async ping() {
673
+ return this.request({ type: "ping" });
674
+ }
675
+ async request(payload, timeoutMs = this.requestTimeoutMs) {
676
+ if (!this.connected || !this.ws) {
677
+ throw new RemoteCliError("RIG_REMOTE_NOT_CONNECTED", "Remote client is not connected.", 3);
678
+ }
679
+ const id = crypto.randomUUID();
680
+ const message = {
681
+ ...payload,
682
+ id,
683
+ timestamp: new Date().toISOString()
684
+ };
685
+ return await new Promise((resolve2, reject) => {
686
+ const timeout = setTimeout(() => {
687
+ this.pending.delete(id);
688
+ reject(new RemoteCliError("RIG_REMOTE_REQUEST_TIMEOUT", `Timed out waiting for response to '${String(payload.type)}' after ${timeoutMs}ms.`, 3, { requestType: payload.type, requestId: id, timeoutMs }));
689
+ }, timeoutMs);
690
+ this.pending.set(id, { resolve: resolve2, reject, timeout });
691
+ this.ws?.send(JSON.stringify(message));
692
+ });
693
+ }
694
+ routeMessage(message) {
695
+ if (message.id && this.pending.has(message.id)) {
696
+ const pending = this.pending.get(message.id);
697
+ if (pending) {
698
+ clearTimeout(pending.timeout);
699
+ this.pending.delete(message.id);
700
+ pending.resolve(message);
701
+ }
702
+ return;
703
+ }
704
+ if (message.type === "token_refresh_response") {
705
+ const token = normalizeString2(message.connectionToken);
706
+ const expiresAt = normalizeString2(message.connectionTokenExpiresAt);
707
+ if (token && expiresAt) {
708
+ this.connectionToken = token;
709
+ this.connectionTokenExpiresAt = expiresAt;
710
+ this.scheduleTokenRefresh();
711
+ }
712
+ }
713
+ this.onEvent?.({ receivedAt: new Date().toISOString(), message });
714
+ }
715
+ scheduleTokenRefresh() {
716
+ this.clearTokenRefreshTimer();
717
+ if (!this.connectionToken || !this.connectionTokenExpiresAt || !this.ws || !this.connected) {
718
+ return;
719
+ }
720
+ const expiresAt = new Date(this.connectionTokenExpiresAt).getTime();
721
+ if (!Number.isFinite(expiresAt)) {
722
+ return;
723
+ }
724
+ const refreshAt = expiresAt - 60 * 60 * 1000;
725
+ const delay = Math.max(0, refreshAt - Date.now());
726
+ this.tokenRefreshTimer = setTimeout(() => {
727
+ if (!this.connected || !this.ws || !this.connectionToken) {
728
+ return;
729
+ }
730
+ const refreshMessage = {
731
+ type: "token_refresh",
732
+ id: crypto.randomUUID(),
733
+ timestamp: new Date().toISOString(),
734
+ connectionToken: this.connectionToken
735
+ };
736
+ this.ws.send(JSON.stringify(refreshMessage));
737
+ }, delay);
738
+ }
739
+ clearTokenRefreshTimer() {
740
+ if (this.tokenRefreshTimer) {
741
+ clearTimeout(this.tokenRefreshTimer);
742
+ this.tokenRefreshTimer = null;
743
+ }
744
+ }
745
+ clearPending(reason) {
746
+ for (const [requestId, pending] of this.pending.entries()) {
747
+ clearTimeout(pending.timeout);
748
+ pending.reject(new RemoteCliError("RIG_REMOTE_REQUEST_CANCELLED", `${reason} (request ${requestId}).`, 3, { requestId }));
749
+ this.pending.delete(requestId);
750
+ }
751
+ }
752
+ }
753
+ function matchesEventFilter(message, expectedType) {
754
+ if (!expectedType) {
755
+ return true;
756
+ }
757
+ if (message.type === expectedType) {
758
+ return true;
759
+ }
760
+ if (message.type === "engine_event") {
761
+ const eventType = normalizeString2(message.event?.type);
762
+ return eventType === expectedType;
763
+ }
764
+ if (message.type === "parallel_event") {
765
+ const eventType = normalizeString2(message.event?.type);
766
+ return eventType === expectedType;
767
+ }
768
+ return false;
769
+ }
770
+ function summarizeMessage(message) {
771
+ if (message.type === "pong") {
772
+ return "pong";
773
+ }
774
+ if (message.type === "engine_event") {
775
+ const eventType = normalizeString2(message.event?.type);
776
+ return eventType ? `engine_event:${eventType}` : "engine_event";
777
+ }
778
+ if (message.type === "parallel_event") {
779
+ const eventType = normalizeString2(message.event?.type);
780
+ const orchestrationId = normalizeString2(message.orchestrationId);
781
+ return orchestrationId ? `parallel_event:${eventType || "unknown"}:${orchestrationId}` : `parallel_event:${eventType || "unknown"}`;
782
+ }
783
+ return message.type;
784
+ }
785
+ function migrateManagedRemoteEndpoints(projectRoot, legacyPath = REMOTES_CONFIG_PATH) {
786
+ return importLegacyRemoteEndpoints(projectRoot, legacyPath);
787
+ }
788
+ function doctorManagedRemoteEndpoints(projectRoot) {
789
+ return doctorAuthorityRemoteEndpoints(projectRoot);
790
+ }
791
+ function updateManagedRemoteEndpointInAuthority(projectRoot, input) {
792
+ const updated = updateAuthorityRemoteEndpoint(projectRoot, input);
793
+ if (!updated)
794
+ return null;
795
+ return {
796
+ id: updated.id,
797
+ alias: updated.alias,
798
+ host: updated.host,
799
+ port: updated.port,
800
+ token: updated.token,
801
+ addedAt: updated.addedAt,
802
+ lastConnected: updated.lastConnectedAt
803
+ };
804
+ }
805
+ function normalizeString2(value) {
806
+ if (!value) {
807
+ return "";
808
+ }
809
+ return value.trim();
810
+ }
811
+ function parsePort(value, label) {
812
+ if (!value) {
813
+ return null;
814
+ }
815
+ const parsed = Number.parseInt(value, 10);
816
+ if (!Number.isFinite(parsed) || parsed <= 0 || parsed > 65535) {
817
+ throw new RemoteCliError("RIG_REMOTE_INVALID_PORT", `Invalid port for ${label}: ${value}.`, 2, { label, value });
818
+ }
819
+ return parsed;
820
+ }
821
+ function parseIncomingMessage(raw) {
822
+ if (typeof raw !== "string") {
823
+ return null;
824
+ }
825
+ try {
826
+ const parsed = JSON.parse(raw);
827
+ if (!parsed || typeof parsed !== "object" || typeof parsed.type !== "string") {
828
+ return null;
829
+ }
830
+ return parsed;
831
+ } catch {
832
+ return null;
833
+ }
834
+ }
835
+ function expectType(message, expectedType) {
836
+ if (message.type !== expectedType) {
837
+ throw new RemoteCliError("RIG_REMOTE_UNEXPECTED_RESPONSE", `Unexpected response type: ${message.type}. Expected ${expectedType}.`, 3, { expectedType, actualType: message.type, message });
838
+ }
839
+ return message;
840
+ }
841
+ export {
842
+ upsertManagedRemoteEndpoint,
843
+ updateManagedRemoteEndpointInAuthority,
844
+ summarizeMessage,
845
+ resolveRemoteEndpoint,
846
+ removeManagedRemoteEndpoint,
847
+ migrateManagedRemoteEndpoints,
848
+ matchesEventFilter,
849
+ loadRemotesConfig,
850
+ listManagedRemoteEndpoints,
851
+ doctorManagedRemoteEndpoints,
852
+ RemoteWsClient,
853
+ RemoteCliError
854
+ };