@h-rig/cli 0.0.6-alpha.94 → 0.0.6-alpha.95
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -27
- package/bin/rig.js +16 -0
- package/package.json +14 -40
- package/dist/bin/build-rig-binaries.d.ts +0 -2
- package/dist/bin/build-rig-binaries.js +0 -119
- package/dist/bin/rig.d.ts +0 -72
- package/dist/bin/rig.js +0 -17855
- package/dist/config/rig-default-config.yml +0 -5
- package/dist/src/app/drone-ui.d.ts +0 -34
- package/dist/src/app/drone-ui.js +0 -278
- package/dist/src/commands/_async-ui.d.ts +0 -10
- package/dist/src/commands/_async-ui.js +0 -121
- package/dist/src/commands/_cli-format.d.ts +0 -56
- package/dist/src/commands/_cli-format.js +0 -319
- package/dist/src/commands/_connection-state.d.ts +0 -54
- package/dist/src/commands/_connection-state.js +0 -187
- package/dist/src/commands/_doctor-checks.d.ts +0 -46
- package/dist/src/commands/_doctor-checks.js +0 -352
- package/dist/src/commands/_help-catalog.d.ts +0 -51
- package/dist/src/commands/_help-catalog.js +0 -502
- package/dist/src/commands/_inprocess-services.d.ts +0 -33
- package/dist/src/commands/_inprocess-services.js +0 -102
- package/dist/src/commands/_json-output.d.ts +0 -11
- package/dist/src/commands/_json-output.js +0 -60
- package/dist/src/commands/_lazy-reconcile.d.ts +0 -34
- package/dist/src/commands/_lazy-reconcile.js +0 -102
- package/dist/src/commands/_parsers.d.ts +0 -15
- package/dist/src/commands/_parsers.js +0 -114
- package/dist/src/commands/_paths.d.ts +0 -11
- package/dist/src/commands/_paths.js +0 -50
- package/dist/src/commands/_pi-frontend.d.ts +0 -35
- package/dist/src/commands/_pi-frontend.js +0 -64
- package/dist/src/commands/_pi-install.d.ts +0 -42
- package/dist/src/commands/_pi-install.js +0 -167
- package/dist/src/commands/_policy.d.ts +0 -8
- package/dist/src/commands/_policy.js +0 -127
- package/dist/src/commands/_probes.d.ts +0 -1
- package/dist/src/commands/_probes.js +0 -13
- package/dist/src/commands/_run-bridge.d.ts +0 -114
- package/dist/src/commands/_run-bridge.js +0 -387
- package/dist/src/commands/_run-diagnostics.d.ts +0 -9
- package/dist/src/commands/_run-diagnostics.js +0 -51
- package/dist/src/commands/_run-driver-helpers.d.ts +0 -26
- package/dist/src/commands/_run-driver-helpers.js +0 -138
- package/dist/src/commands/_run-projection.d.ts +0 -50
- package/dist/src/commands/_run-projection.js +0 -349
- package/dist/src/commands/_run-subcommands.d.ts +0 -3
- package/dist/src/commands/_run-subcommands.js +0 -31
- package/dist/src/commands/_spinner.d.ts +0 -25
- package/dist/src/commands/_spinner.js +0 -65
- package/dist/src/commands/agent.d.ts +0 -3
- package/dist/src/commands/agent.js +0 -8837
- package/dist/src/commands/dist.d.ts +0 -28
- package/dist/src/commands/dist.js +0 -417
- package/dist/src/commands/doctor.d.ts +0 -3
- package/dist/src/commands/doctor.js +0 -480
- package/dist/src/commands/github.d.ts +0 -3
- package/dist/src/commands/github.js +0 -342
- package/dist/src/commands/inbox.d.ts +0 -28
- package/dist/src/commands/inbox.js +0 -579
- package/dist/src/commands/init.d.ts +0 -64
- package/dist/src/commands/init.js +0 -1541
- package/dist/src/commands/inspect.d.ts +0 -20
- package/dist/src/commands/inspect.js +0 -764
- package/dist/src/commands/pi.d.ts +0 -3
- package/dist/src/commands/pi.js +0 -177
- package/dist/src/commands/plugin.d.ts +0 -16
- package/dist/src/commands/plugin.js +0 -714
- package/dist/src/commands/profile-and-review.d.ts +0 -4
- package/dist/src/commands/profile-and-review.js +0 -223
- package/dist/src/commands/queue.d.ts +0 -3
- package/dist/src/commands/queue.js +0 -197
- package/dist/src/commands/remote.d.ts +0 -3
- package/dist/src/commands/remote.js +0 -1337
- package/dist/src/commands/repo-git-harness.d.ts +0 -5
- package/dist/src/commands/repo-git-harness.js +0 -271
- package/dist/src/commands/run.d.ts +0 -21
- package/dist/src/commands/run.js +0 -17847
- package/dist/src/commands/server.d.ts +0 -3
- package/dist/src/commands/server.js +0 -249
- package/dist/src/commands/setup.d.ts +0 -16
- package/dist/src/commands/setup.js +0 -644
- package/dist/src/commands/stats.d.ts +0 -15
- package/dist/src/commands/stats.js +0 -979
- package/dist/src/commands/task-run-driver.d.ts +0 -94
- package/dist/src/commands/task-run-driver.js +0 -203
- package/dist/src/commands/task.d.ts +0 -35
- package/dist/src/commands/task.js +0 -818
- package/dist/src/commands/test.d.ts +0 -3
- package/dist/src/commands/test.js +0 -46
- package/dist/src/commands/triage.d.ts +0 -11
- package/dist/src/commands/triage.js +0 -227
- package/dist/src/commands/workspace.d.ts +0 -3
- package/dist/src/commands/workspace.js +0 -130
- package/dist/src/commands.d.ts +0 -13
- package/dist/src/commands.js +0 -17979
- package/dist/src/index.d.ts +0 -4
- package/dist/src/index.js +0 -17991
- package/dist/src/launcher.d.ts +0 -61
- package/dist/src/launcher.js +0 -199
- package/dist/src/operator-cli.d.ts +0 -2
- package/dist/src/operator-cli.js +0 -17847
- package/dist/src/operator-entry.d.ts +0 -1
- package/dist/src/operator-entry.js +0 -3
- package/dist/src/runner.d.ts +0 -47
- package/dist/src/runner.js +0 -267
- package/dist/src/withMutedConsole.d.ts +0 -2
- package/dist/src/withMutedConsole.js +0 -42
|
@@ -1,387 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
var __require = import.meta.require;
|
|
3
|
-
|
|
4
|
-
// packages/cli/src/commands/_run-bridge.ts
|
|
5
|
-
import { randomUUID } from "crypto";
|
|
6
|
-
import { spawn as nodeSpawn } from "child_process";
|
|
7
|
-
import { existsSync, readdirSync, readFileSync } from "fs";
|
|
8
|
-
import { dirname, resolve } from "path";
|
|
9
|
-
import { fileURLToPath } from "url";
|
|
10
|
-
import { CUSTOM_TYPE_FOR, sessionIdFromSessionFile } from "@rig/contracts";
|
|
11
|
-
import { createPluginHost } from "@rig/core";
|
|
12
|
-
import { loadConfig } from "@rig/core/load-config";
|
|
13
|
-
import { resolveOwnerNamespaceKey, resolveRegistryBaseUrl, resolveRegistrySecret, resolveSelectedRemote } from "@rig/runtime/control-plane/remote";
|
|
14
|
-
import { listAgentRuntimes } from "@rig/runtime/control-plane/runtime/isolation";
|
|
15
|
-
import { createRegistryClient } from "@rig/relay-registry";
|
|
16
|
-
import {
|
|
17
|
-
listActiveCollabSessions as ompListActiveCollabSessions
|
|
18
|
-
} from "@oh-my-pi/pi-coding-agent/collab/api";
|
|
19
|
-
var DEFAULT_ATTACH_TIMEOUT_MS = 15000;
|
|
20
|
-
var DEFAULT_ATTACH_POLL_INTERVAL_MS = 250;
|
|
21
|
-
function stringField(value) {
|
|
22
|
-
return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
|
|
23
|
-
}
|
|
24
|
-
function githubUserId(value) {
|
|
25
|
-
if (typeof value === "number" && Number.isInteger(value))
|
|
26
|
-
return String(value);
|
|
27
|
-
return stringField(value);
|
|
28
|
-
}
|
|
29
|
-
function readJsonRecord(path) {
|
|
30
|
-
if (!existsSync(path))
|
|
31
|
-
return null;
|
|
32
|
-
try {
|
|
33
|
-
const parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
34
|
-
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
35
|
-
} catch {
|
|
36
|
-
return null;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
function publicIdentityEnv(projectRoot) {
|
|
40
|
-
const auth = readJsonRecord(resolve(projectRoot, ".rig", "state", "github-auth.json"));
|
|
41
|
-
const connection = readJsonRecord(resolve(projectRoot, ".rig", "state", "connection.json"));
|
|
42
|
-
const values = {};
|
|
43
|
-
const selectedRepo = stringField(auth?.selectedRepo) ?? stringField(connection?.project);
|
|
44
|
-
const userId = githubUserId(auth?.userId);
|
|
45
|
-
const login = stringField(auth?.login);
|
|
46
|
-
const namespaceKey = stringField(auth?.userNamespaceKey) ?? resolveOwnerNamespaceKey(projectRoot);
|
|
47
|
-
if (selectedRepo)
|
|
48
|
-
values.RIG_SELECTED_REPO = selectedRepo;
|
|
49
|
-
if (userId)
|
|
50
|
-
values.RIG_GITHUB_USER_ID = userId;
|
|
51
|
-
if (login)
|
|
52
|
-
values.RIG_GITHUB_LOGIN = login;
|
|
53
|
-
if (namespaceKey)
|
|
54
|
-
values.RIG_GITHUB_NAMESPACE_KEY = namespaceKey;
|
|
55
|
-
return values;
|
|
56
|
-
}
|
|
57
|
-
function taskText(value) {
|
|
58
|
-
return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
|
|
59
|
-
}
|
|
60
|
-
function taskUrl(record) {
|
|
61
|
-
const metadata = record;
|
|
62
|
-
return taskText(metadata.url) ?? taskText(metadata.html_url) ?? taskText(metadata.webUrl);
|
|
63
|
-
}
|
|
64
|
-
function taskBody(record) {
|
|
65
|
-
const metadata = record;
|
|
66
|
-
return taskText(metadata.body) ?? taskText(metadata.description);
|
|
67
|
-
}
|
|
68
|
-
function taskTitle(record) {
|
|
69
|
-
const metadata = record;
|
|
70
|
-
return taskText(metadata.title) ?? taskText(metadata.name) ?? record.id;
|
|
71
|
-
}
|
|
72
|
-
function toExtensionTask(record, sourceKind) {
|
|
73
|
-
return {
|
|
74
|
-
id: record.id,
|
|
75
|
-
title: taskTitle(record),
|
|
76
|
-
status: typeof record.status === "string" ? record.status : null,
|
|
77
|
-
source: sourceKind,
|
|
78
|
-
url: taskUrl(record),
|
|
79
|
-
body: taskBody(record)
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
async function loadConfiguredTaskSource(projectRoot) {
|
|
83
|
-
const normalizedRoot = resolve(projectRoot);
|
|
84
|
-
const config = await loadConfig(normalizedRoot);
|
|
85
|
-
const pluginHost = createPluginHost(config.plugins);
|
|
86
|
-
const taskSourceFactory = pluginHost.resolveTaskSourceFactoryByKind(config.taskSource.kind);
|
|
87
|
-
if (!taskSourceFactory) {
|
|
88
|
-
const kinds = pluginHost.listExecutableTaskSources().map((entry) => entry.kind).join(", ") || "none";
|
|
89
|
-
throw new Error(`No task source factory registered for kind "${config.taskSource.kind}". Registered kinds: ${kinds}.`);
|
|
90
|
-
}
|
|
91
|
-
return {
|
|
92
|
-
kind: config.taskSource.kind,
|
|
93
|
-
source: taskSourceFactory.factory(config.taskSource, { projectRoot: normalizedRoot })
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
async function listTasksFromSource(projectRoot, deps = {}) {
|
|
97
|
-
const { kind, source } = await (deps.loadTaskSource ?? loadConfiguredTaskSource)(projectRoot);
|
|
98
|
-
return (await source.list()).map((task) => toExtensionTask(task, kind));
|
|
99
|
-
}
|
|
100
|
-
async function getTaskFromSource(projectRoot, taskId, deps = {}) {
|
|
101
|
-
const tasks = await listTasksFromSource(projectRoot, deps);
|
|
102
|
-
return tasks.find((task) => task.id === taskId) ?? null;
|
|
103
|
-
}
|
|
104
|
-
async function readSelectedTarget(projectRoot, env = process.env) {
|
|
105
|
-
const config = await loadConfig(resolve(projectRoot));
|
|
106
|
-
const selected = resolveSelectedRemote(projectRoot, env);
|
|
107
|
-
return {
|
|
108
|
-
alias: selected?.alias ?? "local",
|
|
109
|
-
kind: selected ? "remote" : "local",
|
|
110
|
-
projectRoot,
|
|
111
|
-
status: "ready",
|
|
112
|
-
taskSource: config.taskSource.kind
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
function runningFromCompiledBinary() {
|
|
116
|
-
return import.meta.url.includes("$bunfs");
|
|
117
|
-
}
|
|
118
|
-
function resolveRigRunBin() {
|
|
119
|
-
if (runningFromCompiledBinary())
|
|
120
|
-
return resolve(dirname(process.execPath), "rig-run");
|
|
121
|
-
return resolve(dirname(fileURLToPath(import.meta.url)), "../../../rig-host/bin/rig-run.ts");
|
|
122
|
-
}
|
|
123
|
-
async function defaultRunRunProcess(input) {
|
|
124
|
-
const { runRunProcess } = await import("@rig/rig-host");
|
|
125
|
-
return await runRunProcess(input);
|
|
126
|
-
}
|
|
127
|
-
function shellQuote(value) {
|
|
128
|
-
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
129
|
-
}
|
|
130
|
-
function readProjectSlug(projectRoot) {
|
|
131
|
-
const connection = readJsonRecord(resolve(projectRoot, ".rig", "state", "connection.json"));
|
|
132
|
-
return stringField(connection?.project) ?? null;
|
|
133
|
-
}
|
|
134
|
-
function resolveProjectOriginUrl(projectRoot) {
|
|
135
|
-
const slug = readProjectSlug(projectRoot);
|
|
136
|
-
return slug && /^[^/]+\/[^/]+$/.test(slug) ? `https://github.com/${slug}.git` : null;
|
|
137
|
-
}
|
|
138
|
-
async function spawnRunProcess(input, deps = {}) {
|
|
139
|
-
const runId = (deps.uuid ?? randomUUID)();
|
|
140
|
-
const env = deps.env ?? process.env;
|
|
141
|
-
const identityEnv = publicIdentityEnv(input.projectRoot);
|
|
142
|
-
const selected = resolveSelectedRemote(input.projectRoot, env);
|
|
143
|
-
const sshTarget = selected?.sshTarget ?? env.RIG_REMOTE_ALIAS?.trim();
|
|
144
|
-
if (sshTarget) {
|
|
145
|
-
const namespaceKey = identityEnv.RIG_GITHUB_NAMESPACE_KEY ?? resolveOwnerNamespaceKey(input.projectRoot, env) ?? "";
|
|
146
|
-
const sh = shellQuote;
|
|
147
|
-
const originUrl = resolveProjectOriginUrl(input.projectRoot);
|
|
148
|
-
const repoName = (readProjectSlug(input.projectRoot)?.split("/").pop() ?? "project").replace(/[^A-Za-z0-9._-]/g, "-");
|
|
149
|
-
const checkoutExpr = selected?.checkout ? sh(selected.checkout) : `"$HOME/.rig/checkouts/${repoName}"`;
|
|
150
|
-
const identityAssignments = Object.entries(identityEnv).map(([k, v]) => `${k}=${sh(v)}`);
|
|
151
|
-
if (namespaceKey && !identityEnv.RIG_GITHUB_NAMESPACE_KEY)
|
|
152
|
-
identityAssignments.push(`RIG_GITHUB_NAMESPACE_KEY=${sh(namespaceKey)}`);
|
|
153
|
-
const runInvocation = [
|
|
154
|
-
`RIG_RUN_ID=${sh(runId)}`,
|
|
155
|
-
`RIG_TASK_ID=${sh(input.taskId)}`,
|
|
156
|
-
...identityAssignments,
|
|
157
|
-
selected?.registryBaseUrl ? `RIG_REGISTRY_URL=${sh(selected.registryBaseUrl)}` : "",
|
|
158
|
-
`rig run start --task ${sh(input.taskId)}`
|
|
159
|
-
].filter(Boolean).join(" ");
|
|
160
|
-
const provisionAndRun = [
|
|
161
|
-
"set -e",
|
|
162
|
-
`CHECKOUT=${checkoutExpr}`,
|
|
163
|
-
originUrl ? `[ -d "$CHECKOUT/.git" ] || git clone ${sh(originUrl)} "$CHECKOUT"` : `[ -d "$CHECKOUT/.git" ] || { echo "rig: remote checkout $CHECKOUT missing and no origin to clone" >&2; exit 1; }`,
|
|
164
|
-
`cd "$CHECKOUT"`,
|
|
165
|
-
"git fetch origin --prune --quiet || true",
|
|
166
|
-
runInvocation
|
|
167
|
-
].join("; ");
|
|
168
|
-
const child = (deps.spawn ?? nodeSpawn)("ssh", [sshTarget, `bash -lc ${sh(provisionAndRun)}`], {
|
|
169
|
-
cwd: input.projectRoot,
|
|
170
|
-
env: { ...env, ...identityEnv },
|
|
171
|
-
detached: true,
|
|
172
|
-
stdio: "ignore"
|
|
173
|
-
});
|
|
174
|
-
child.unref();
|
|
175
|
-
return { runId };
|
|
176
|
-
}
|
|
177
|
-
await (deps.runRunProcess ?? defaultRunRunProcess)({
|
|
178
|
-
projectRoot: input.projectRoot,
|
|
179
|
-
taskId: input.taskId,
|
|
180
|
-
runId,
|
|
181
|
-
title: input.title,
|
|
182
|
-
rigRunBin: (deps.resolveRigRunBin ?? resolveRigRunBin)()
|
|
183
|
-
});
|
|
184
|
-
return { runId };
|
|
185
|
-
}
|
|
186
|
-
function buildRemoteControlCommand(runId, control, ctx) {
|
|
187
|
-
const verb = control.kind === "stop" ? `rig run stop ${shellQuote(runId)}${control.reason.trim() ? ` --reason ${shellQuote(control.reason)}` : ""}` : `rig run steer ${shellQuote(runId)} --message ${shellQuote(control.message)}`;
|
|
188
|
-
return [
|
|
189
|
-
ctx.checkout ? `cd ${shellQuote(ctx.checkout)} &&` : "",
|
|
190
|
-
ctx.namespaceKey ? `RIG_GITHUB_NAMESPACE_KEY=${shellQuote(ctx.namespaceKey)}` : "",
|
|
191
|
-
ctx.registryBaseUrl ? `RIG_REGISTRY_URL=${shellQuote(ctx.registryBaseUrl)}` : "",
|
|
192
|
-
verb
|
|
193
|
-
].filter(Boolean).join(" ");
|
|
194
|
-
}
|
|
195
|
-
async function deliverRemoteRunControl(projectRoot, runId, control, deps = {}) {
|
|
196
|
-
const env = deps.env ?? process.env;
|
|
197
|
-
const selected = resolveSelectedRemote(projectRoot, env);
|
|
198
|
-
const sshTarget = selected?.sshTarget ?? env.RIG_REMOTE_ALIAS?.trim();
|
|
199
|
-
if (!sshTarget) {
|
|
200
|
-
throw new Error(`Run ${runId} is remote but no SSH target is configured (set one with \`rig server use <alias>\`).`);
|
|
201
|
-
}
|
|
202
|
-
const identityEnv = publicIdentityEnv(projectRoot);
|
|
203
|
-
const namespaceKey = identityEnv.RIG_GITHUB_NAMESPACE_KEY ?? resolveOwnerNamespaceKey(projectRoot, env) ?? "";
|
|
204
|
-
const remoteCommand = buildRemoteControlCommand(runId, control, {
|
|
205
|
-
checkout: selected?.checkout ?? null,
|
|
206
|
-
registryBaseUrl: selected?.registryBaseUrl ?? null,
|
|
207
|
-
namespaceKey
|
|
208
|
-
});
|
|
209
|
-
await new Promise((resolveDone, rejectDone) => {
|
|
210
|
-
const child = (deps.spawn ?? nodeSpawn)("ssh", [sshTarget, `bash -lc ${shellQuote(remoteCommand)}`], {
|
|
211
|
-
cwd: projectRoot,
|
|
212
|
-
env: { ...env, ...identityEnv },
|
|
213
|
-
stdio: ["ignore", "ignore", "pipe"]
|
|
214
|
-
});
|
|
215
|
-
let stderr = "";
|
|
216
|
-
child.stderr?.on("data", (chunk) => {
|
|
217
|
-
stderr += String(chunk);
|
|
218
|
-
});
|
|
219
|
-
child.on("error", rejectDone);
|
|
220
|
-
child.on("close", (code) => {
|
|
221
|
-
if (code === 0) {
|
|
222
|
-
resolveDone();
|
|
223
|
-
return;
|
|
224
|
-
}
|
|
225
|
-
const detail = stderr.trim();
|
|
226
|
-
rejectDone(new Error(`remote \`rig run ${control.kind}\` exited ${code ?? "null"}${detail ? `: ${detail}` : ""}`));
|
|
227
|
-
});
|
|
228
|
-
});
|
|
229
|
-
}
|
|
230
|
-
function registrySecret(env = process.env) {
|
|
231
|
-
return resolveRegistrySecret(process.cwd(), env) ?? null;
|
|
232
|
-
}
|
|
233
|
-
function registryBaseUrl(env = process.env) {
|
|
234
|
-
return resolveRegistryBaseUrl(process.cwd(), env);
|
|
235
|
-
}
|
|
236
|
-
function collabFromRegistryEntry(entry) {
|
|
237
|
-
return {
|
|
238
|
-
sessionId: entry.roomId,
|
|
239
|
-
sessionPath: "",
|
|
240
|
-
cwd: "",
|
|
241
|
-
title: entry.title,
|
|
242
|
-
joinLink: entry.joinLink,
|
|
243
|
-
webLink: entry.webLink,
|
|
244
|
-
relayUrl: entry.relayUrl,
|
|
245
|
-
owner: entry.owner,
|
|
246
|
-
selectedRepo: entry.repo,
|
|
247
|
-
startedAt: entry.startedAt,
|
|
248
|
-
updatedAt: entry.heartbeatAt,
|
|
249
|
-
...entry.pid === undefined ? {} : { pid: entry.pid },
|
|
250
|
-
stale: entry.stale
|
|
251
|
-
};
|
|
252
|
-
}
|
|
253
|
-
function isRecord(value) {
|
|
254
|
-
return typeof value === "object" && value !== null;
|
|
255
|
-
}
|
|
256
|
-
function readLocalRunCollab(runtime) {
|
|
257
|
-
if (!runtime.sessionDir || !existsSync(runtime.sessionDir))
|
|
258
|
-
return null;
|
|
259
|
-
let files;
|
|
260
|
-
try {
|
|
261
|
-
files = readdirSync(runtime.sessionDir).filter((f) => f.endsWith(".jsonl")).sort().reverse();
|
|
262
|
-
} catch {
|
|
263
|
-
return null;
|
|
264
|
-
}
|
|
265
|
-
for (const file of files) {
|
|
266
|
-
let lines;
|
|
267
|
-
try {
|
|
268
|
-
lines = readFileSync(resolve(runtime.sessionDir, file), "utf8").split(`
|
|
269
|
-
`);
|
|
270
|
-
} catch {
|
|
271
|
-
continue;
|
|
272
|
-
}
|
|
273
|
-
let host = null;
|
|
274
|
-
for (const line of lines) {
|
|
275
|
-
if (!line.includes("collab-host-started"))
|
|
276
|
-
continue;
|
|
277
|
-
let entry;
|
|
278
|
-
try {
|
|
279
|
-
entry = JSON.parse(line);
|
|
280
|
-
} catch {
|
|
281
|
-
continue;
|
|
282
|
-
}
|
|
283
|
-
if (!isRecord(entry) || entry.customType !== CUSTOM_TYPE_FOR["timeline-entry"] || !isRecord(entry.data))
|
|
284
|
-
continue;
|
|
285
|
-
const payload = isRecord(entry.data.payload) ? entry.data.payload : entry.data;
|
|
286
|
-
if (payload.type !== "collab-host-started")
|
|
287
|
-
continue;
|
|
288
|
-
host = {
|
|
289
|
-
roomId: typeof payload.roomId === "string" ? payload.roomId : undefined,
|
|
290
|
-
joinLink: typeof payload.joinLink === "string" ? payload.joinLink : undefined,
|
|
291
|
-
webLink: typeof payload.webLink === "string" ? payload.webLink : undefined,
|
|
292
|
-
relayUrl: typeof payload.relayUrl === "string" ? payload.relayUrl : undefined,
|
|
293
|
-
at: typeof entry.data.at === "string" ? entry.data.at : undefined
|
|
294
|
-
};
|
|
295
|
-
}
|
|
296
|
-
if (!host?.joinLink)
|
|
297
|
-
continue;
|
|
298
|
-
const at = host.at ?? "";
|
|
299
|
-
const sessionId = host.roomId ?? sessionIdFromSessionFile(resolve(runtime.sessionDir, file)) ?? runtime.id;
|
|
300
|
-
return {
|
|
301
|
-
sessionId,
|
|
302
|
-
sessionPath: resolve(runtime.sessionDir, file),
|
|
303
|
-
cwd: runtime.workspaceDir,
|
|
304
|
-
joinLink: host.joinLink,
|
|
305
|
-
webLink: host.webLink ?? "",
|
|
306
|
-
relayUrl: host.relayUrl ?? "",
|
|
307
|
-
title: runtime.taskId ? `[${runtime.taskId}] Rig run ${sessionId}` : `Rig run ${sessionId}`,
|
|
308
|
-
startedAt: at,
|
|
309
|
-
updatedAt: at,
|
|
310
|
-
stale: false
|
|
311
|
-
};
|
|
312
|
-
}
|
|
313
|
-
return null;
|
|
314
|
-
}
|
|
315
|
-
async function listLocalRunCollabSessions(projectRoot) {
|
|
316
|
-
let runtimes;
|
|
317
|
-
try {
|
|
318
|
-
runtimes = await listAgentRuntimes(projectRoot);
|
|
319
|
-
} catch {
|
|
320
|
-
return [];
|
|
321
|
-
}
|
|
322
|
-
const out = [];
|
|
323
|
-
for (const runtime of runtimes) {
|
|
324
|
-
const collab = readLocalRunCollab(runtime);
|
|
325
|
-
if (collab)
|
|
326
|
-
out.push(collab);
|
|
327
|
-
}
|
|
328
|
-
return out;
|
|
329
|
-
}
|
|
330
|
-
async function listActiveRunCollab(filter) {
|
|
331
|
-
return defaultListActiveCollabSessions(filter);
|
|
332
|
-
}
|
|
333
|
-
async function defaultListActiveCollabSessions(filter) {
|
|
334
|
-
const projectRoot = process.cwd();
|
|
335
|
-
const local = await listLocalRunCollabSessions(projectRoot);
|
|
336
|
-
const namespaceKey = filter.namespaceKey ?? resolveOwnerNamespaceKey(projectRoot);
|
|
337
|
-
const secret = registrySecret();
|
|
338
|
-
const remote = namespaceKey && secret ? (await createRegistryClient({ baseUrl: registryBaseUrl(), namespaceKey, secret }).listRoomsByOwner(filter)).map(collabFromRegistryEntry) : await ompListActiveCollabSessions(filter);
|
|
339
|
-
const seen = new Set(local.map((c) => c.sessionId));
|
|
340
|
-
return [...local, ...remote.filter((c) => !seen.has(c.sessionId))];
|
|
341
|
-
}
|
|
342
|
-
function sleep(ms) {
|
|
343
|
-
const { promise, resolve: resolveSleep } = Promise.withResolvers();
|
|
344
|
-
setTimeout(resolveSleep, ms);
|
|
345
|
-
return promise;
|
|
346
|
-
}
|
|
347
|
-
function matchesRun(collab, runId, taskId) {
|
|
348
|
-
if (collab.sessionId === runId)
|
|
349
|
-
return true;
|
|
350
|
-
if (runId && collab.title?.includes(runId))
|
|
351
|
-
return true;
|
|
352
|
-
return Boolean(taskId && collab.title?.includes(taskId));
|
|
353
|
-
}
|
|
354
|
-
async function attachViaRelay(input, deps = {}) {
|
|
355
|
-
const timeoutMs = input.timeoutMs ?? DEFAULT_ATTACH_TIMEOUT_MS;
|
|
356
|
-
const pollIntervalMs = input.pollIntervalMs ?? DEFAULT_ATTACH_POLL_INTERVAL_MS;
|
|
357
|
-
const listActive = deps.listActiveCollabSessions ?? defaultListActiveCollabSessions;
|
|
358
|
-
const now = deps.now ?? Date.now;
|
|
359
|
-
const pause = deps.sleep ?? sleep;
|
|
360
|
-
const deadline = now() + timeoutMs;
|
|
361
|
-
do {
|
|
362
|
-
const live = await listActive(input.identityFilter);
|
|
363
|
-
const match = live.find((collab) => matchesRun(collab, input.runId, input.taskId) && !collab.stale);
|
|
364
|
-
if (match) {
|
|
365
|
-
return {
|
|
366
|
-
sessionPath: match.sessionPath || null,
|
|
367
|
-
joinLink: match.joinLink || null,
|
|
368
|
-
collabSessionId: match.sessionId
|
|
369
|
-
};
|
|
370
|
-
}
|
|
371
|
-
if (now() >= deadline)
|
|
372
|
-
break;
|
|
373
|
-
await pause(pollIntervalMs);
|
|
374
|
-
} while (now() <= deadline);
|
|
375
|
-
return null;
|
|
376
|
-
}
|
|
377
|
-
export {
|
|
378
|
-
spawnRunProcess,
|
|
379
|
-
resolveRigRunBin,
|
|
380
|
-
readSelectedTarget,
|
|
381
|
-
listTasksFromSource,
|
|
382
|
-
listActiveRunCollab,
|
|
383
|
-
getTaskFromSource,
|
|
384
|
-
deliverRemoteRunControl,
|
|
385
|
-
buildRemoteControlCommand,
|
|
386
|
-
attachViaRelay
|
|
387
|
-
};
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { RunJournalProjection } from "@rig/contracts";
|
|
2
|
-
/**
|
|
3
|
-
* Extract the most useful human-facing failure diagnostic from the folded run journal.
|
|
4
|
-
*
|
|
5
|
-
* The live projection deliberately does not retain log/timeline lines, so this mirrors the
|
|
6
|
-
* deleted server-side categorization using only fields that survive folding: record fields,
|
|
7
|
-
* status reasons, closeout details, and reducer anomalies.
|
|
8
|
-
*/
|
|
9
|
-
export declare function summarizeUsefulRunError(projection: RunJournalProjection): string | null;
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
// packages/cli/src/commands/_run-diagnostics.ts
|
|
3
|
-
function normalizeString(value) {
|
|
4
|
-
if (typeof value !== "string")
|
|
5
|
-
return null;
|
|
6
|
-
const normalized = value.replace(/\s+/g, " ").trim();
|
|
7
|
-
return normalized.length > 0 ? normalized : null;
|
|
8
|
-
}
|
|
9
|
-
function isGenericRunFailure(value) {
|
|
10
|
-
const text = normalizeString(value);
|
|
11
|
-
return Boolean(text && /^Task run failed \([^)]*\)$/i.test(text));
|
|
12
|
-
}
|
|
13
|
-
function appendCandidate(candidates, value) {
|
|
14
|
-
const text = normalizeString(value);
|
|
15
|
-
if (text && !candidates.includes(text))
|
|
16
|
-
candidates.push(text);
|
|
17
|
-
}
|
|
18
|
-
function categorizeUsefulRunError(lines) {
|
|
19
|
-
const taskSourceFailure = lines.find((line) => /failed to update task source/i.test(line));
|
|
20
|
-
if (taskSourceFailure)
|
|
21
|
-
return `Task source update failed: ${taskSourceFailure}`;
|
|
22
|
-
const moduleFailure = lines.find((line) => /cannot find module/i.test(line));
|
|
23
|
-
if (moduleFailure)
|
|
24
|
-
return `Runtime module resolution failed: ${moduleFailure}`;
|
|
25
|
-
const providerFailure = lines.find((line) => /no api key found|unauthorized|authentication failed|invalid api key/i.test(line));
|
|
26
|
-
if (providerFailure)
|
|
27
|
-
return `Provider authentication failed: ${providerFailure}`;
|
|
28
|
-
return null;
|
|
29
|
-
}
|
|
30
|
-
function summarizeUsefulRunError(projection) {
|
|
31
|
-
if (projection.status !== "failed")
|
|
32
|
-
return null;
|
|
33
|
-
const candidates = [];
|
|
34
|
-
for (const anomaly of projection.anomalies) {
|
|
35
|
-
appendCandidate(candidates, `Journal anomaly (${anomaly.kind}): ${anomaly.detail}`);
|
|
36
|
-
}
|
|
37
|
-
for (const phase of projection.closeoutPhases) {
|
|
38
|
-
if (phase.outcome === "failed")
|
|
39
|
-
appendCandidate(candidates, phase.detail);
|
|
40
|
-
}
|
|
41
|
-
for (const entry of projection.statusHistory) {
|
|
42
|
-
appendCandidate(candidates, entry.reason);
|
|
43
|
-
}
|
|
44
|
-
appendCandidate(candidates, projection.record.statusDetail);
|
|
45
|
-
appendCandidate(candidates, projection.record.errorText);
|
|
46
|
-
const nonGeneric = candidates.filter((candidate) => !isGenericRunFailure(candidate));
|
|
47
|
-
return categorizeUsefulRunError(nonGeneric) ?? nonGeneric.at(-1) ?? normalizeString(projection.record.errorText);
|
|
48
|
-
}
|
|
49
|
-
export {
|
|
50
|
-
summarizeUsefulRunError
|
|
51
|
-
};
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
export type SourceTaskContract = {
|
|
2
|
-
id: string;
|
|
3
|
-
title?: string | null;
|
|
4
|
-
description?: string | null;
|
|
5
|
-
body?: string | null;
|
|
6
|
-
acceptanceCriteria?: string | null;
|
|
7
|
-
acceptance_criteria?: string | null;
|
|
8
|
-
sourceIssueId?: string | null;
|
|
9
|
-
status?: string | null;
|
|
10
|
-
issueType?: string | null;
|
|
11
|
-
role?: string | null;
|
|
12
|
-
validation?: string[];
|
|
13
|
-
validators?: string[];
|
|
14
|
-
labels?: string[];
|
|
15
|
-
scope?: string[];
|
|
16
|
-
};
|
|
17
|
-
export declare function buildRunPrompt(input: {
|
|
18
|
-
projectRoot: string;
|
|
19
|
-
taskId?: string | undefined;
|
|
20
|
-
fallbackTitle?: string | undefined;
|
|
21
|
-
fallbackDescription?: string | undefined;
|
|
22
|
-
fallbackAcceptanceCriteria?: string | undefined;
|
|
23
|
-
sourceTask?: SourceTaskContract | null;
|
|
24
|
-
initialPrompt?: string;
|
|
25
|
-
runtimeAdapter: "claude-code" | "codex" | "pi";
|
|
26
|
-
}): string;
|
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
// packages/cli/src/commands/_run-driver-helpers.ts
|
|
3
|
-
import { existsSync, readFileSync } from "fs";
|
|
4
|
-
import { resolve as resolve2 } from "path";
|
|
5
|
-
|
|
6
|
-
// packages/cli/src/commands/_paths.ts
|
|
7
|
-
import { resolve } from "path";
|
|
8
|
-
import { resolveMonorepoRoot } from "@rig/runtime/layout";
|
|
9
|
-
function resolveControlPlaneMonorepoRoot(projectRoot) {
|
|
10
|
-
return resolveMonorepoRoot(projectRoot);
|
|
11
|
-
}
|
|
12
|
-
function resolveControlPlaneTaskConfigPath(projectRoot) {
|
|
13
|
-
return resolve(resolveControlPlaneMonorepoRoot(projectRoot), ".rig", "task-config.json");
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
// packages/cli/src/commands/_run-driver-helpers.ts
|
|
17
|
-
function readLatestBeadRecord(projectRoot, taskId) {
|
|
18
|
-
const issuesPath = resolve2(resolveControlPlaneMonorepoRoot(projectRoot), ".beads", "issues.jsonl");
|
|
19
|
-
if (!existsSync(issuesPath)) {
|
|
20
|
-
return null;
|
|
21
|
-
}
|
|
22
|
-
let latest = null;
|
|
23
|
-
for (const line of readFileSync(issuesPath, "utf8").split(/\r?\n/)) {
|
|
24
|
-
const trimmed = line.trim();
|
|
25
|
-
if (!trimmed)
|
|
26
|
-
continue;
|
|
27
|
-
try {
|
|
28
|
-
const parsed = JSON.parse(trimmed);
|
|
29
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
30
|
-
continue;
|
|
31
|
-
const record = parsed;
|
|
32
|
-
if (record.id === taskId)
|
|
33
|
-
latest = record;
|
|
34
|
-
} catch {}
|
|
35
|
-
}
|
|
36
|
-
return latest;
|
|
37
|
-
}
|
|
38
|
-
function firstPromptString(...values) {
|
|
39
|
-
for (const value of values) {
|
|
40
|
-
if (typeof value === "string" && value.trim())
|
|
41
|
-
return value.trim();
|
|
42
|
-
}
|
|
43
|
-
return null;
|
|
44
|
-
}
|
|
45
|
-
function uniqueStrings(values) {
|
|
46
|
-
return Array.from(new Set(values.map((value) => value.trim()).filter(Boolean)));
|
|
47
|
-
}
|
|
48
|
-
function renderSourceTaskContract(task, validation) {
|
|
49
|
-
if (!task)
|
|
50
|
-
return validation.length > 0 ? [`Validation: ${validation.join(", ")}`] : [];
|
|
51
|
-
const lines = [`id: ${task.id}`];
|
|
52
|
-
if (task.sourceIssueId)
|
|
53
|
-
lines.push(`source issue: ${task.sourceIssueId}`);
|
|
54
|
-
if (task.status)
|
|
55
|
-
lines.push(`status: ${task.status}`);
|
|
56
|
-
if (task.issueType)
|
|
57
|
-
lines.push(`issue type: ${task.issueType}`);
|
|
58
|
-
if (task.role)
|
|
59
|
-
lines.push(`role: ${task.role}`);
|
|
60
|
-
if (validation.length > 0)
|
|
61
|
-
lines.push(`validation: ${validation.join(", ")}`);
|
|
62
|
-
return lines;
|
|
63
|
-
}
|
|
64
|
-
function renderSourceScopeValidation(task, validation) {
|
|
65
|
-
if (task || validation.length === 0)
|
|
66
|
-
return "";
|
|
67
|
-
return `Validation:
|
|
68
|
-
- ${validation.join(`
|
|
69
|
-
- `)}`;
|
|
70
|
-
}
|
|
71
|
-
function readTaskScopeText(projectRoot, taskId) {
|
|
72
|
-
try {
|
|
73
|
-
const parsed = JSON.parse(readFileSync(resolveControlPlaneTaskConfigPath(projectRoot), "utf8"));
|
|
74
|
-
const entry = parsed[taskId] ?? {};
|
|
75
|
-
const scope = Array.isArray(entry.scope) ? entry.scope.filter((item) => typeof item === "string") : [];
|
|
76
|
-
const validation = Array.isArray(entry.validation) ? entry.validation.filter((item) => typeof item === "string") : [];
|
|
77
|
-
const lines = [];
|
|
78
|
-
if (scope.length > 0)
|
|
79
|
-
lines.push(`Scope:
|
|
80
|
-
- ${scope.join(`
|
|
81
|
-
- `)}`);
|
|
82
|
-
if (validation.length > 0)
|
|
83
|
-
lines.push(`Validation:
|
|
84
|
-
- ${validation.join(`
|
|
85
|
-
- `)}`);
|
|
86
|
-
return lines.join(`
|
|
87
|
-
|
|
88
|
-
`);
|
|
89
|
-
} catch {
|
|
90
|
-
return "";
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
function providerInstructionLines(runtimeAdapter) {
|
|
94
|
-
if (runtimeAdapter === "pi") {
|
|
95
|
-
return ["Keep file writes inside the scoped task workspace and use the bridged Pi tooling for shell and follow-up prompts."];
|
|
96
|
-
}
|
|
97
|
-
if (runtimeAdapter === "codex") {
|
|
98
|
-
return ["Keep file writes inside the scoped task workspace and prefer compact terminal output."];
|
|
99
|
-
}
|
|
100
|
-
return ["Keep file writes inside the scoped task workspace and stay within the provided tool surface."];
|
|
101
|
-
}
|
|
102
|
-
function buildRunPrompt(input) {
|
|
103
|
-
const initialPrompt = input.initialPrompt?.trim() || null;
|
|
104
|
-
if (!input.taskId) {
|
|
105
|
-
return initialPrompt ?? input.fallbackTitle?.trim() ?? "Continue the requested run and complete the work.";
|
|
106
|
-
}
|
|
107
|
-
const bead = readLatestBeadRecord(input.projectRoot, input.taskId);
|
|
108
|
-
const sourceTask = input.sourceTask ?? null;
|
|
109
|
-
const sourceDescription = firstPromptString(sourceTask?.description, sourceTask?.body);
|
|
110
|
-
const sourceAcceptance = firstPromptString(sourceTask?.acceptanceCriteria, sourceTask?.acceptance_criteria);
|
|
111
|
-
const sourceValidation = uniqueStrings([...sourceTask?.validation ?? [], ...sourceTask?.validators ?? []]);
|
|
112
|
-
const title = (bead && typeof bead.title === "string" ? bead.title : null) ?? firstPromptString(sourceTask?.title) ?? input.fallbackTitle ?? input.taskId;
|
|
113
|
-
const description = (bead && typeof bead.description === "string" ? bead.description : null) ?? sourceDescription ?? input.fallbackDescription ?? "";
|
|
114
|
-
const acceptance = (bead && typeof bead.acceptance_criteria === "string" ? bead.acceptance_criteria : null) ?? sourceAcceptance ?? input.fallbackAcceptanceCriteria ?? "";
|
|
115
|
-
const scopeText = readTaskScopeText(input.projectRoot, input.taskId);
|
|
116
|
-
const sourceContractLines = renderSourceTaskContract(sourceTask, sourceValidation);
|
|
117
|
-
const providerLines = providerInstructionLines(input.runtimeAdapter);
|
|
118
|
-
return [
|
|
119
|
-
`You are working on task ${input.taskId}: ${title}.`,
|
|
120
|
-
description ? `Description:
|
|
121
|
-
${description}` : null,
|
|
122
|
-
acceptance ? `Acceptance criteria:
|
|
123
|
-
${acceptance}` : null,
|
|
124
|
-
sourceContractLines.length > 0 ? `Source task contract:
|
|
125
|
-
${sourceContractLines.join(`
|
|
126
|
-
`)}` : null,
|
|
127
|
-
scopeText || renderSourceScopeValidation(sourceTask, sourceValidation) || null,
|
|
128
|
-
initialPrompt ? `Additional operator guidance:
|
|
129
|
-
${initialPrompt}` : null,
|
|
130
|
-
providerLines.length > 0 ? `Provider-specific runtime tooling:
|
|
131
|
-
${providerLines.join(" ")}` : null
|
|
132
|
-
].filter((value) => Boolean(value)).join(`
|
|
133
|
-
|
|
134
|
-
`);
|
|
135
|
-
}
|
|
136
|
-
export {
|
|
137
|
-
buildRunPrompt
|
|
138
|
-
};
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { type RunJournalProjection, type RunSessionCustomEntry } from "@rig/contracts";
|
|
2
|
-
import type { CollabRegistryFilter } from "@oh-my-pi/pi-coding-agent/collab/api";
|
|
3
|
-
/** A run as seen by the operator CLI: live-presence facts joined with the folded journal. */
|
|
4
|
-
export interface RunProjectionRecord {
|
|
5
|
-
readonly runId: string;
|
|
6
|
-
readonly taskId: string | null;
|
|
7
|
-
readonly title: string;
|
|
8
|
-
/** RunStatus from the folded journal, or a liveness-derived fallback. */
|
|
9
|
-
readonly status: string;
|
|
10
|
-
readonly source: "local" | "remote";
|
|
11
|
-
/** True when the run is currently discoverable (registry heartbeat or local host). */
|
|
12
|
-
readonly live: boolean;
|
|
13
|
-
readonly stale: boolean;
|
|
14
|
-
readonly startedAt: string | null;
|
|
15
|
-
readonly updatedAt: string | null;
|
|
16
|
-
readonly completedAt: string | null;
|
|
17
|
-
readonly joinLink: string | null;
|
|
18
|
-
readonly webLink: string | null;
|
|
19
|
-
readonly relayUrl: string | null;
|
|
20
|
-
readonly sessionPath: string | null;
|
|
21
|
-
readonly prUrl: string | null;
|
|
22
|
-
readonly worktreePath: string | null;
|
|
23
|
-
readonly pendingApprovals: number;
|
|
24
|
-
readonly pendingInputs: number;
|
|
25
|
-
readonly steeringCount: number;
|
|
26
|
-
readonly stallCount: number;
|
|
27
|
-
readonly errorSummary?: string | null;
|
|
28
|
-
/** The full folded journal (empty projection when no journal was readable). */
|
|
29
|
-
readonly projection: RunJournalProjection;
|
|
30
|
-
}
|
|
31
|
-
/** What an attach/steer caller needs to reach a live run over collab. */
|
|
32
|
-
export interface RunJoinTarget {
|
|
33
|
-
readonly runId: string;
|
|
34
|
-
readonly taskId: string | null;
|
|
35
|
-
readonly joinLink: string;
|
|
36
|
-
readonly cwd: string | null;
|
|
37
|
-
readonly stale: boolean;
|
|
38
|
-
}
|
|
39
|
-
/** Parse an OMP session JSONL into the custom-entry shape `foldRunSessionEntries` expects. */
|
|
40
|
-
export declare function readSessionRunEntries(sessionPath: string | null): RunSessionCustomEntry[];
|
|
41
|
-
/**
|
|
42
|
-
* List every discoverable run: live collab (relay-registry + local hosts) merged
|
|
43
|
-
* with finished/local runs recovered from on-disk agent-runtime session journals.
|
|
44
|
-
* Live entries win on runId collisions (they carry join links + current presence).
|
|
45
|
-
*/
|
|
46
|
-
export declare function listRunProjections(projectRoot: string, filter?: CollabRegistryFilter): Promise<RunProjectionRecord[]>;
|
|
47
|
-
/** Resolve a single run by id (or unambiguous prefix). */
|
|
48
|
-
export declare function getRunProjection(projectRoot: string, runId: string, filter?: CollabRegistryFilter): Promise<RunProjectionRecord | null>;
|
|
49
|
-
/** Resolve the live join target for attach/steer; null when the run is not currently joinable. */
|
|
50
|
-
export declare function resolveRunJoinTarget(projectRoot: string, runId: string, filter?: CollabRegistryFilter): Promise<RunJoinTarget | null>;
|