@h-rig/cli 0.0.6-alpha.9 → 0.0.6-alpha.90
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 +1 -1
- package/dist/bin/build-rig-binaries.d.ts +2 -0
- package/dist/bin/rig.d.ts +2 -0
- package/dist/bin/rig.js +11052 -6668
- package/dist/src/app/board.d.ts +23 -0
- package/dist/src/app/board.js +1786 -0
- package/dist/src/app/drone-ui.d.ts +37 -0
- package/dist/src/app/drone-ui.js +294 -0
- package/dist/src/app/theme.d.ts +47 -0
- package/dist/src/app/theme.js +150 -0
- package/dist/src/commands/_async-ui.d.ts +13 -0
- package/dist/src/commands/_async-ui.js +223 -0
- package/dist/src/commands/_authority-runs.d.ts +22 -0
- package/dist/src/commands/_authority-runs.js +2 -3
- package/dist/src/commands/_cli-format.d.ts +49 -0
- package/dist/src/commands/_cli-format.js +447 -0
- package/dist/src/commands/_connection-state.d.ts +44 -0
- package/dist/src/commands/_connection-state.js +30 -11
- package/dist/src/commands/_doctor-checks.d.ts +52 -0
- package/dist/src/commands/_doctor-checks.js +180 -44
- package/dist/src/commands/_help-catalog.d.ts +51 -0
- package/dist/src/commands/_help-catalog.js +442 -0
- package/dist/src/commands/_json-output.d.ts +11 -0
- package/dist/src/commands/_json-output.js +56 -0
- package/dist/src/commands/_operator-surface.d.ts +34 -0
- package/dist/src/commands/_operator-surface.js +220 -0
- package/dist/src/commands/_operator-view.d.ts +30 -0
- package/dist/src/commands/_operator-view.js +803 -73
- package/dist/src/commands/_parsers.d.ts +15 -0
- package/dist/src/commands/_parsers.js +18 -11
- package/dist/src/commands/_paths.d.ts +11 -0
- package/dist/src/commands/_pi-frontend.d.ts +27 -0
- package/dist/src/commands/_pi-frontend.js +742 -0
- package/dist/src/commands/_pi-install.d.ts +42 -0
- package/dist/src/commands/_pi-install.js +5 -4
- package/dist/src/commands/_policy.d.ts +8 -0
- package/dist/src/commands/_policy.js +12 -5
- package/dist/src/commands/_preflight.d.ts +22 -0
- package/dist/src/commands/_preflight.js +190 -128
- package/dist/src/commands/_probes.d.ts +1 -0
- package/dist/src/commands/_run-driver-helpers.d.ts +99 -0
- package/dist/src/commands/_run-driver-helpers.js +75 -22
- package/dist/src/commands/_run-replay.d.ts +24 -0
- package/dist/src/commands/_run-replay.js +142 -0
- package/dist/src/commands/_server-client.d.ts +186 -0
- package/dist/src/commands/_server-client.js +360 -61
- package/dist/src/commands/_snapshot-upload.d.ts +39 -0
- package/dist/src/commands/_snapshot-upload.js +163 -39
- package/dist/src/commands/_spinner.d.ts +25 -0
- package/dist/src/commands/_spinner.js +65 -0
- package/dist/src/commands/_task-picker.d.ts +9 -0
- package/dist/src/commands/_task-picker.js +172 -19
- package/dist/src/commands/agent.d.ts +3 -0
- package/dist/src/commands/agent.js +39 -20
- package/dist/src/commands/browser.d.ts +65 -0
- package/dist/src/commands/browser.js +334 -51
- package/dist/src/commands/connect.d.ts +7 -0
- package/dist/src/commands/connect.js +272 -33
- package/dist/src/commands/dist.d.ts +28 -0
- package/dist/src/commands/dist.js +19 -12
- package/dist/src/commands/doctor.d.ts +3 -0
- package/dist/src/commands/doctor.js +378 -45
- package/dist/src/commands/github.d.ts +3 -0
- package/dist/src/commands/github.js +375 -53
- package/dist/src/commands/inbox.d.ts +30 -0
- package/dist/src/commands/inbox.js +760 -70
- package/dist/src/commands/init.d.ts +74 -0
- package/dist/src/commands/init.js +963 -119
- package/dist/src/commands/inspect.d.ts +3 -0
- package/dist/src/commands/inspect.js +588 -32
- package/dist/src/commands/inspector.d.ts +3 -0
- package/dist/src/commands/inspector.js +20 -13
- package/dist/src/commands/pi.d.ts +3 -0
- package/dist/src/commands/pi.js +177 -0
- package/dist/src/commands/plugin.d.ts +16 -0
- package/dist/src/commands/plugin.js +95 -27
- package/dist/src/commands/profile-and-review.d.ts +4 -0
- package/dist/src/commands/profile-and-review.js +26 -19
- package/dist/src/commands/queue.d.ts +3 -0
- package/dist/src/commands/queue.js +32 -12
- package/dist/src/commands/remote.d.ts +3 -0
- package/dist/src/commands/remote.js +43 -36
- package/dist/src/commands/repo-git-harness.d.ts +5 -0
- package/dist/src/commands/repo-git-harness.js +22 -15
- package/dist/src/commands/run.d.ts +3 -0
- package/dist/src/commands/run.js +1379 -159
- package/dist/src/commands/server.d.ts +7 -0
- package/dist/src/commands/server.js +502 -57
- package/dist/src/commands/setup.d.ts +16 -0
- package/dist/src/commands/setup.js +390 -63
- package/dist/src/commands/stats.d.ts +12 -0
- package/dist/src/commands/stats.js +1051 -0
- package/dist/src/commands/task-report-bug.d.ts +19 -0
- package/dist/src/commands/task-report-bug.js +260 -62
- package/dist/src/commands/task-run-driver.d.ts +132 -0
- package/dist/src/commands/task-run-driver.js +886 -130
- package/dist/src/commands/task.d.ts +14 -0
- package/dist/src/commands/task.js +1644 -314
- package/dist/src/commands/test.d.ts +3 -0
- package/dist/src/commands/test.js +15 -8
- package/dist/src/commands/workspace.d.ts +3 -0
- package/dist/src/commands/workspace.js +18 -11
- package/dist/src/commands.d.ts +29 -0
- package/dist/src/commands.js +10967 -6637
- package/dist/src/index.d.ts +4 -0
- package/dist/src/index.js +10168 -5787
- package/dist/src/launcher.d.ts +61 -0
- package/dist/src/launcher.js +77 -13
- package/dist/src/report-bug.d.ts +44 -0
- package/dist/src/report-bug.js +3 -3
- package/dist/src/runner.d.ts +47 -0
- package/dist/src/runner.js +16 -22
- package/dist/src/withMutedConsole.d.ts +2 -0
- package/package.json +13 -6
|
@@ -1,17 +1,23 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// packages/cli/src/commands/_server-client.ts
|
|
3
|
-
import { spawnSync } from "child_process";
|
|
4
3
|
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
5
4
|
import { resolve as resolve2 } from "path";
|
|
6
5
|
|
|
7
6
|
// packages/cli/src/runner.ts
|
|
8
7
|
import { EventBus } from "@rig/runtime/control-plane/runtime/events";
|
|
9
|
-
import { CliError } from "@rig/runtime/control-plane/errors";
|
|
8
|
+
import { CliError as RuntimeCliError } from "@rig/runtime/control-plane/errors";
|
|
10
9
|
import { evaluate, loadPolicy, resolveAction } from "@rig/runtime/control-plane/runtime/guard";
|
|
11
|
-
import { PluginManager } from "@rig/runtime/control-plane/runtime/plugins";
|
|
12
|
-
import { loadRuntimeContextFromEnv } from "@rig/runtime/control-plane/runtime/context";
|
|
13
10
|
import { buildBinary } from "@rig/runtime/control-plane/runtime/isolation";
|
|
14
|
-
|
|
11
|
+
|
|
12
|
+
class CliError extends RuntimeCliError {
|
|
13
|
+
hint;
|
|
14
|
+
constructor(message, exitCode = 1, options = {}) {
|
|
15
|
+
super(message, exitCode);
|
|
16
|
+
if (options.hint?.trim()) {
|
|
17
|
+
this.hint = options.hint.trim();
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
15
21
|
|
|
16
22
|
// packages/cli/src/commands/_server-client.ts
|
|
17
23
|
import { ensureLocalRigServerConnection } from "@rig/runtime/local-server";
|
|
@@ -38,9 +44,14 @@ function readJsonFile(path) {
|
|
|
38
44
|
try {
|
|
39
45
|
return JSON.parse(readFileSync(path, "utf8"));
|
|
40
46
|
} catch (error) {
|
|
41
|
-
throw new
|
|
47
|
+
throw new CliError(`Invalid Rig connection state at ${path}: ${error instanceof Error ? error.message : String(error)}`, 1, { hint: "Fix or delete that file, then re-select a server with `rig server use <alias|local>`." });
|
|
42
48
|
}
|
|
43
49
|
}
|
|
50
|
+
function writeJsonFile(path, value) {
|
|
51
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
52
|
+
writeFileSync(path, `${JSON.stringify(value, null, 2)}
|
|
53
|
+
`, "utf8");
|
|
54
|
+
}
|
|
44
55
|
function normalizeConnection(value) {
|
|
45
56
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
46
57
|
return null;
|
|
@@ -81,31 +92,51 @@ function readRepoConnection(projectRoot) {
|
|
|
81
92
|
return {
|
|
82
93
|
selected,
|
|
83
94
|
project: typeof record.project === "string" ? record.project : undefined,
|
|
84
|
-
linkedAt: typeof record.linkedAt === "string" ? record.linkedAt : undefined
|
|
95
|
+
linkedAt: typeof record.linkedAt === "string" ? record.linkedAt : undefined,
|
|
96
|
+
serverProjectRoot: typeof record.serverProjectRoot === "string" && record.serverProjectRoot.trim() ? record.serverProjectRoot.trim() : undefined
|
|
85
97
|
};
|
|
86
98
|
}
|
|
99
|
+
function writeRepoConnection(projectRoot, state) {
|
|
100
|
+
writeJsonFile(resolveRepoConnectionPath(projectRoot), state);
|
|
101
|
+
}
|
|
87
102
|
function resolveSelectedConnection(projectRoot, options = {}) {
|
|
88
103
|
const repo = readRepoConnection(projectRoot);
|
|
89
104
|
if (!repo)
|
|
90
105
|
return null;
|
|
91
106
|
if (repo.selected === "local")
|
|
92
|
-
return { alias: "local", connection: { kind: "local", mode: "auto" } };
|
|
107
|
+
return { alias: "local", connection: { kind: "local", mode: "auto" }, serverProjectRoot: repo.serverProjectRoot };
|
|
93
108
|
const global = readGlobalConnections(options);
|
|
94
109
|
const connection = global.connections[repo.selected];
|
|
95
110
|
if (!connection) {
|
|
96
|
-
throw new
|
|
111
|
+
throw new CliError(`Selected Rig server "${repo.selected}" was not found. Run \`rig server list\` or \`rig server use local\`.`, 1);
|
|
97
112
|
}
|
|
98
|
-
return { alias: repo.selected, connection };
|
|
113
|
+
return { alias: repo.selected, connection, serverProjectRoot: repo.serverProjectRoot };
|
|
114
|
+
}
|
|
115
|
+
function writeRepoServerProjectRoot(projectRoot, serverProjectRoot) {
|
|
116
|
+
const repo = readRepoConnection(projectRoot);
|
|
117
|
+
if (!repo)
|
|
118
|
+
return;
|
|
119
|
+
writeRepoConnection(projectRoot, { ...repo, serverProjectRoot });
|
|
99
120
|
}
|
|
100
121
|
|
|
101
122
|
// packages/cli/src/commands/_server-client.ts
|
|
102
|
-
var
|
|
123
|
+
var scopedGitHubBearerTokens = new Map;
|
|
124
|
+
var serverPhaseListener = null;
|
|
125
|
+
function setServerPhaseListener(listener) {
|
|
126
|
+
const previous = serverPhaseListener;
|
|
127
|
+
serverPhaseListener = listener;
|
|
128
|
+
return previous;
|
|
129
|
+
}
|
|
130
|
+
function reportServerPhase(label) {
|
|
131
|
+
serverPhaseListener?.(label);
|
|
132
|
+
}
|
|
103
133
|
function cleanToken(value) {
|
|
104
134
|
const trimmed = value?.trim();
|
|
105
135
|
return trimmed ? trimmed : null;
|
|
106
136
|
}
|
|
107
|
-
function setGitHubBearerTokenForCurrentProcess(token) {
|
|
108
|
-
|
|
137
|
+
function setGitHubBearerTokenForCurrentProcess(token, projectRoot) {
|
|
138
|
+
const scopedKey = resolve2(projectRoot ?? process.cwd());
|
|
139
|
+
scopedGitHubBearerTokens.set(scopedKey, cleanToken(token ?? undefined));
|
|
109
140
|
}
|
|
110
141
|
function readPrivateRemoteSessionToken(projectRoot) {
|
|
111
142
|
const path = resolve2(projectRoot, ".rig", "state", "github-auth.json");
|
|
@@ -119,49 +150,80 @@ function readPrivateRemoteSessionToken(projectRoot) {
|
|
|
119
150
|
}
|
|
120
151
|
}
|
|
121
152
|
function readGitHubBearerTokenForRemote(projectRoot) {
|
|
122
|
-
|
|
123
|
-
|
|
153
|
+
const scopedKey = resolve2(projectRoot);
|
|
154
|
+
if (scopedGitHubBearerTokens.has(scopedKey))
|
|
155
|
+
return scopedGitHubBearerTokens.get(scopedKey) ?? null;
|
|
124
156
|
const privateSession = readPrivateRemoteSessionToken(projectRoot);
|
|
125
|
-
if (privateSession)
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
return
|
|
157
|
+
if (privateSession)
|
|
158
|
+
return privateSession;
|
|
159
|
+
return cleanToken(process.env.RIG_SERVER_AUTH_TOKEN) ?? cleanToken(process.env.RIG_REMOTE_AUTH_TOKEN);
|
|
160
|
+
}
|
|
161
|
+
function readStoredGitHubAuthToken(projectRoot) {
|
|
162
|
+
const path = resolve2(projectRoot, ".rig", "state", "github-auth.json");
|
|
163
|
+
if (!existsSync2(path))
|
|
164
|
+
return null;
|
|
165
|
+
try {
|
|
166
|
+
const parsed = JSON.parse(readFileSync2(path, "utf8"));
|
|
167
|
+
return cleanToken(typeof parsed.token === "string" ? parsed.token : undefined);
|
|
168
|
+
} catch {
|
|
169
|
+
return null;
|
|
133
170
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
138
|
-
});
|
|
139
|
-
cachedGitHubBearerToken = result.status === 0 ? cleanToken(result.stdout) : null;
|
|
140
|
-
return cachedGitHubBearerToken;
|
|
171
|
+
}
|
|
172
|
+
function readLocalConnectionFallbackToken(projectRoot) {
|
|
173
|
+
return readGitHubBearerTokenForRemote(projectRoot) ?? cleanToken(process.env.RIG_GITHUB_TOKEN) ?? readStoredGitHubAuthToken(projectRoot);
|
|
141
174
|
}
|
|
142
175
|
async function ensureServerForCli(projectRoot) {
|
|
143
176
|
try {
|
|
144
177
|
const selected = resolveSelectedConnection(projectRoot);
|
|
145
178
|
if (selected?.connection.kind === "remote") {
|
|
179
|
+
reportServerPhase(`Connecting to ${selected.alias}\u2026`);
|
|
180
|
+
const authToken = readGitHubBearerTokenForRemote(projectRoot);
|
|
181
|
+
const serverProjectRoot = selected.serverProjectRoot ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
|
|
146
182
|
return {
|
|
147
183
|
baseUrl: selected.connection.baseUrl,
|
|
148
|
-
authToken
|
|
149
|
-
connectionKind: "remote"
|
|
184
|
+
authToken,
|
|
185
|
+
connectionKind: "remote",
|
|
186
|
+
serverProjectRoot
|
|
150
187
|
};
|
|
151
188
|
}
|
|
189
|
+
reportServerPhase("Starting local Rig server\u2026");
|
|
152
190
|
const connection = await ensureLocalRigServerConnection(projectRoot);
|
|
153
191
|
return {
|
|
154
192
|
baseUrl: connection.baseUrl,
|
|
155
|
-
authToken: connection.authToken,
|
|
156
|
-
connectionKind: "local"
|
|
193
|
+
authToken: connection.authToken ?? readLocalConnectionFallbackToken(projectRoot),
|
|
194
|
+
connectionKind: "local",
|
|
195
|
+
serverProjectRoot: resolve2(projectRoot)
|
|
157
196
|
};
|
|
158
197
|
} catch (error) {
|
|
159
198
|
if (error instanceof Error) {
|
|
160
|
-
throw new
|
|
199
|
+
throw new CliError(error.message, 1);
|
|
161
200
|
}
|
|
162
201
|
throw error;
|
|
163
202
|
}
|
|
164
203
|
}
|
|
204
|
+
async function backfillRemoteServerProjectRoot(projectRoot, baseUrl, authToken) {
|
|
205
|
+
const repo = readRepoConnection(projectRoot);
|
|
206
|
+
const slug = repo?.project?.trim();
|
|
207
|
+
if (!slug)
|
|
208
|
+
return null;
|
|
209
|
+
try {
|
|
210
|
+
const response = await fetch(`${baseUrl}/api/projects/${encodeURIComponent(slug)}`, {
|
|
211
|
+
headers: mergeHeaders(undefined, authToken)
|
|
212
|
+
});
|
|
213
|
+
if (!response.ok)
|
|
214
|
+
return null;
|
|
215
|
+
const payload = await response.json();
|
|
216
|
+
const project = payload.project && typeof payload.project === "object" && !Array.isArray(payload.project) ? payload.project : null;
|
|
217
|
+
const checkouts = Array.isArray(project?.checkouts) ? project.checkouts : [];
|
|
218
|
+
const latestCheckout = [...checkouts].reverse().find((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry) && typeof entry.path === "string"));
|
|
219
|
+
const path = typeof latestCheckout?.path === "string" && latestCheckout.path.trim() ? latestCheckout.path.trim() : null;
|
|
220
|
+
if (path)
|
|
221
|
+
writeRepoServerProjectRoot(projectRoot, path);
|
|
222
|
+
return path;
|
|
223
|
+
} catch {
|
|
224
|
+
return null;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
165
227
|
function appendTaskFilterParams(url, filters) {
|
|
166
228
|
if (filters.assignee)
|
|
167
229
|
url.searchParams.set("assignee", filters.assignee);
|
|
@@ -194,12 +256,65 @@ function diagnosticMessage(payload) {
|
|
|
194
256
|
});
|
|
195
257
|
return messages.length > 0 ? messages.join("; ") : null;
|
|
196
258
|
}
|
|
259
|
+
var serverReachabilityCache = new Map;
|
|
260
|
+
async function probeServerReachability(baseUrl, authToken) {
|
|
261
|
+
try {
|
|
262
|
+
const response = await fetch(`${baseUrl.replace(/\/+$/, "")}/api/server/status`, {
|
|
263
|
+
headers: mergeHeaders(undefined, authToken),
|
|
264
|
+
signal: AbortSignal.timeout(1500)
|
|
265
|
+
});
|
|
266
|
+
return response.ok;
|
|
267
|
+
} catch {
|
|
268
|
+
return false;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
function cachedServerReachability(projectRoot, baseUrl, authToken) {
|
|
272
|
+
const key = resolve2(projectRoot);
|
|
273
|
+
const cached = serverReachabilityCache.get(key);
|
|
274
|
+
if (cached)
|
|
275
|
+
return cached;
|
|
276
|
+
const probe = probeServerReachability(baseUrl, authToken);
|
|
277
|
+
serverReachabilityCache.set(key, probe);
|
|
278
|
+
return probe;
|
|
279
|
+
}
|
|
280
|
+
function describeSelectedServer(projectRoot, server) {
|
|
281
|
+
try {
|
|
282
|
+
const selected = resolveSelectedConnection(projectRoot);
|
|
283
|
+
if (selected) {
|
|
284
|
+
return {
|
|
285
|
+
alias: selected.alias,
|
|
286
|
+
target: selected.connection.kind === "remote" ? selected.connection.baseUrl : server.baseUrl
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
} catch {}
|
|
290
|
+
return { alias: server.connectionKind === "remote" ? "remote" : "local", target: server.baseUrl };
|
|
291
|
+
}
|
|
292
|
+
async function buildServerFailureContext(projectRoot, server) {
|
|
293
|
+
const { alias, target } = describeSelectedServer(projectRoot, server);
|
|
294
|
+
const reachable = await cachedServerReachability(projectRoot, server.baseUrl, server.authToken);
|
|
295
|
+
const reachability = reachable ? "server is reachable" : "server is unreachable";
|
|
296
|
+
return {
|
|
297
|
+
contextLine: `Currently connected to: ${alias} at ${target} (${reachability}).`,
|
|
298
|
+
hint: "Check the selected server with `rig server status`, or switch with `rig server use <alias|local>`."
|
|
299
|
+
};
|
|
300
|
+
}
|
|
197
301
|
async function requestServerJson(context, pathname, init = {}) {
|
|
198
302
|
const server = await ensureServerForCli(context.projectRoot);
|
|
199
|
-
const
|
|
200
|
-
|
|
201
|
-
headers
|
|
202
|
-
});
|
|
303
|
+
const headers = mergeHeaders(init.headers, server.authToken);
|
|
304
|
+
if (server.serverProjectRoot)
|
|
305
|
+
headers.set("x-rig-project-root", server.serverProjectRoot);
|
|
306
|
+
reportServerPhase(`${(init.method ?? "GET").toUpperCase()} ${pathname.split("?")[0]}\u2026`);
|
|
307
|
+
let response;
|
|
308
|
+
try {
|
|
309
|
+
response = await fetch(`${server.baseUrl}${pathname}`, {
|
|
310
|
+
...init,
|
|
311
|
+
headers
|
|
312
|
+
});
|
|
313
|
+
} catch (error) {
|
|
314
|
+
const failure = await buildServerFailureContext(context.projectRoot, server);
|
|
315
|
+
throw new CliError(`Rig server request failed: ${error instanceof Error ? error.message : String(error)}
|
|
316
|
+
${failure.contextLine}`, 1, { hint: failure.hint });
|
|
317
|
+
}
|
|
203
318
|
const text = await response.text();
|
|
204
319
|
const payload = text.trim().length > 0 ? (() => {
|
|
205
320
|
try {
|
|
@@ -210,8 +325,12 @@ async function requestServerJson(context, pathname, init = {}) {
|
|
|
210
325
|
})() : null;
|
|
211
326
|
if (!response.ok) {
|
|
212
327
|
const diagnostics = diagnosticMessage(payload);
|
|
213
|
-
const
|
|
214
|
-
|
|
328
|
+
const rawDetail = diagnostics ?? (text || response.statusText);
|
|
329
|
+
const detail = diagnostics ? rawDetail : rawDetail.split(`
|
|
330
|
+
`).map((line) => line.trim()).find((line) => line.length > 0)?.slice(0, 200) ?? response.statusText;
|
|
331
|
+
const failure = await buildServerFailureContext(context.projectRoot, server);
|
|
332
|
+
throw new CliError(`Rig server request failed (${response.status}): ${detail}
|
|
333
|
+
${failure.contextLine}`, 1, { hint: failure.hint });
|
|
215
334
|
}
|
|
216
335
|
return payload;
|
|
217
336
|
}
|
|
@@ -220,7 +339,7 @@ async function listWorkspaceTasksViaServer(context, filters = {}) {
|
|
|
220
339
|
appendTaskFilterParams(url, filters);
|
|
221
340
|
const payload = await requestServerJson(context, `${url.pathname}${url.search}`);
|
|
222
341
|
if (!Array.isArray(payload)) {
|
|
223
|
-
throw new
|
|
342
|
+
throw new CliError("Rig server returned an invalid task list payload.", 1, { hint: "Check the selected server with `rig server status`; mixed CLI/server versions can mismatch \u2014 try `rig doctor`." });
|
|
224
343
|
}
|
|
225
344
|
return payload.flatMap((entry) => entry && typeof entry === "object" && !Array.isArray(entry) ? [entry] : []);
|
|
226
345
|
}
|
|
@@ -236,7 +355,7 @@ async function selectNextWorkspaceTaskViaServer(context, filters = {}) {
|
|
|
236
355
|
appendTaskFilterParams(url, filters);
|
|
237
356
|
const payload = await requestServerJson(context, `${url.pathname}${url.search}`);
|
|
238
357
|
if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
|
|
239
|
-
throw new
|
|
358
|
+
throw new CliError("Rig server returned an invalid next-task payload.", 1, { hint: "Check the selected server with `rig server status`; try `rig task list` to see the raw task set." });
|
|
240
359
|
}
|
|
241
360
|
const record = payload;
|
|
242
361
|
const rawTask = record.task;
|
|
@@ -275,32 +394,50 @@ async function registerProjectViaServer(context, input) {
|
|
|
275
394
|
function sleep(ms) {
|
|
276
395
|
return new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
277
396
|
}
|
|
397
|
+
function isRetryableProjectRootSwitchError(error) {
|
|
398
|
+
if (!(error instanceof Error))
|
|
399
|
+
return false;
|
|
400
|
+
const message = error.message.toLowerCase();
|
|
401
|
+
return message.includes("rig server request failed (401): auth-required") || message.includes("rig server request failed (401): github-token-required") || message.includes("rig server request failed (502)") || message.includes("rig server request failed (503)") || message.includes("bad gateway") || message.includes("fetch failed") || message.includes("econnrefused") || message.includes("connection refused");
|
|
402
|
+
}
|
|
278
403
|
async function switchServerProjectRootViaServer(context, projectRoot, options = {}) {
|
|
279
|
-
const switched = await requestServerJson(context, "/api/server/project-root", {
|
|
280
|
-
method: "POST",
|
|
281
|
-
headers: { "content-type": "application/json" },
|
|
282
|
-
body: JSON.stringify({ projectRoot })
|
|
283
|
-
});
|
|
284
404
|
const timeoutMs = options.timeoutMs ?? 30000;
|
|
285
405
|
const pollMs = options.pollMs ?? 1000;
|
|
286
406
|
const deadline = Date.now() + timeoutMs;
|
|
287
407
|
let lastError;
|
|
408
|
+
let switched = null;
|
|
288
409
|
while (Date.now() < deadline) {
|
|
289
410
|
try {
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
lastError = `server projectRoot=${String(record.projectRoot ?? "unknown")}`;
|
|
297
|
-
}
|
|
411
|
+
switched = await requestServerJson(context, "/api/server/project-root", {
|
|
412
|
+
method: "POST",
|
|
413
|
+
headers: { "content-type": "application/json" },
|
|
414
|
+
body: JSON.stringify({ projectRoot })
|
|
415
|
+
});
|
|
416
|
+
break;
|
|
298
417
|
} catch (error) {
|
|
299
418
|
lastError = error;
|
|
419
|
+
if (!isRetryableProjectRootSwitchError(error))
|
|
420
|
+
throw error;
|
|
421
|
+
await sleep(pollMs);
|
|
300
422
|
}
|
|
301
|
-
await sleep(pollMs);
|
|
302
423
|
}
|
|
303
|
-
|
|
424
|
+
if (!switched) {
|
|
425
|
+
throw new CliError(`Rig server did not accept project-root switch to ${projectRoot} before timeout (${lastError instanceof Error ? lastError.message : String(lastError ?? "no response")}).`, 1);
|
|
426
|
+
}
|
|
427
|
+
const record = switched && typeof switched === "object" && !Array.isArray(switched) ? switched : {};
|
|
428
|
+
if (record.ok === true) {
|
|
429
|
+
writeRepoServerProjectRoot(context.projectRoot, projectRoot);
|
|
430
|
+
return { ok: true, switched: record };
|
|
431
|
+
}
|
|
432
|
+
throw new CliError(`Rig server rejected project-root scope ${projectRoot}: ${String(record.message ?? record.error ?? "unknown error")}`, 1);
|
|
433
|
+
}
|
|
434
|
+
async function listRunsViaServer(context, options = {}) {
|
|
435
|
+
const url = new URL("http://rig.local/api/runs");
|
|
436
|
+
if (options.limit !== undefined)
|
|
437
|
+
url.searchParams.set("limit", String(options.limit));
|
|
438
|
+
const payload = await requestServerJson(context, `${url.pathname}${url.search}`);
|
|
439
|
+
const runs = Array.isArray(payload) ? payload : payload && typeof payload === "object" && !Array.isArray(payload) && Array.isArray(payload.runs) ? payload.runs : [];
|
|
440
|
+
return runs.filter((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry)));
|
|
304
441
|
}
|
|
305
442
|
async function getRunDetailsViaServer(context, runId) {
|
|
306
443
|
const payload = await requestServerJson(context, `/api/runs/${encodeURIComponent(runId)}`);
|
|
@@ -315,6 +452,82 @@ async function getRunLogsViaServer(context, runId, options = {}) {
|
|
|
315
452
|
const payload = await requestServerJson(context, `${url.pathname}${url.search}`);
|
|
316
453
|
return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : { entries: [] };
|
|
317
454
|
}
|
|
455
|
+
async function getRunTimelineViaServer(context, runId, options = {}) {
|
|
456
|
+
const url = new URL(`http://rig.local/api/runs/${encodeURIComponent(runId)}/timeline`);
|
|
457
|
+
if (options.limit !== undefined)
|
|
458
|
+
url.searchParams.set("limit", String(options.limit));
|
|
459
|
+
if (options.cursor)
|
|
460
|
+
url.searchParams.set("cursor", options.cursor);
|
|
461
|
+
const payload = await requestServerJson(context, `${url.pathname}${url.search}`);
|
|
462
|
+
return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : { entries: [] };
|
|
463
|
+
}
|
|
464
|
+
async function ensureTaskLabelsViaServer(context) {
|
|
465
|
+
const payload = await requestServerJson(context, "/api/workspace/task-labels", { method: "POST" });
|
|
466
|
+
return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
|
|
467
|
+
}
|
|
468
|
+
async function listGitHubProjectsViaServer(context, owner) {
|
|
469
|
+
const url = new URL("http://rig.local/api/github/projects");
|
|
470
|
+
url.searchParams.set("owner", owner);
|
|
471
|
+
const payload = await requestServerJson(context, `${url.pathname}${url.search}`);
|
|
472
|
+
return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : { projects: [] };
|
|
473
|
+
}
|
|
474
|
+
async function getGitHubProjectStatusFieldViaServer(context, projectId) {
|
|
475
|
+
const payload = await requestServerJson(context, `/api/github/projects/${encodeURIComponent(projectId)}/status-field`);
|
|
476
|
+
return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
|
|
477
|
+
}
|
|
478
|
+
async function updateWorkspaceTaskViaServer(context, input) {
|
|
479
|
+
const payload = await requestServerJson(context, "/api/tasks/update", {
|
|
480
|
+
method: "POST",
|
|
481
|
+
headers: { "content-type": "application/json" },
|
|
482
|
+
body: JSON.stringify(input)
|
|
483
|
+
});
|
|
484
|
+
return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : { ok: true };
|
|
485
|
+
}
|
|
486
|
+
var RESUMABLE_RUN_STATUSES = new Set([
|
|
487
|
+
"created",
|
|
488
|
+
"preparing",
|
|
489
|
+
"running",
|
|
490
|
+
"validating",
|
|
491
|
+
"reviewing",
|
|
492
|
+
"stopped",
|
|
493
|
+
"failed",
|
|
494
|
+
"needs-attention",
|
|
495
|
+
"needs_attention"
|
|
496
|
+
]);
|
|
497
|
+
async function resumeRunViaServer(context, runId, options) {
|
|
498
|
+
let targetRunId = runId?.trim() || null;
|
|
499
|
+
if (!targetRunId) {
|
|
500
|
+
const candidates = (await listRunsViaServer(context)).filter((run) => RESUMABLE_RUN_STATUSES.has(String(run.status ?? ""))).sort((left, right) => String(right.updatedAt ?? "").localeCompare(String(left.updatedAt ?? "")));
|
|
501
|
+
targetRunId = typeof candidates[0]?.runId === "string" ? candidates[0].runId : null;
|
|
502
|
+
}
|
|
503
|
+
if (!targetRunId) {
|
|
504
|
+
throw new CliError(options.restart ? "No run is available to restart." : "No resumable run is available.", 2, { hint: "List runs with `rig run list`, then pass an explicit id: `rig run resume <run-id>`." });
|
|
505
|
+
}
|
|
506
|
+
const payload = await requestServerJson(context, "/api/runs/resume", {
|
|
507
|
+
method: "POST",
|
|
508
|
+
headers: { "content-type": "application/json" },
|
|
509
|
+
body: JSON.stringify({ runId: targetRunId, createdAt: new Date().toISOString(), restart: options.restart })
|
|
510
|
+
});
|
|
511
|
+
const record = payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
|
|
512
|
+
if (record.ok === false) {
|
|
513
|
+
const message = typeof record.error === "string" && record.error.trim() ? record.error : "run resume failed";
|
|
514
|
+
throw new CliError(`${options.restart ? "restart" : "resume"} failed for ${targetRunId}: ${message}`, 1);
|
|
515
|
+
}
|
|
516
|
+
return { ok: true, runId: targetRunId, ...record };
|
|
517
|
+
}
|
|
518
|
+
async function resolveServerConnectionLabel(projectRoot) {
|
|
519
|
+
try {
|
|
520
|
+
const selected = resolveSelectedConnection(projectRoot);
|
|
521
|
+
if (!selected)
|
|
522
|
+
return "no server selected";
|
|
523
|
+
if (selected.connection.kind === "remote") {
|
|
524
|
+
return selected.connection.baseUrl.replace(/^https?:\/\//, "");
|
|
525
|
+
}
|
|
526
|
+
return `local (${selected.alias})`;
|
|
527
|
+
} catch {
|
|
528
|
+
return "no server selected";
|
|
529
|
+
}
|
|
530
|
+
}
|
|
318
531
|
async function stopRunViaServer(context, runId) {
|
|
319
532
|
const payload = await requestServerJson(context, "/api/runs/stop", {
|
|
320
533
|
method: "POST",
|
|
@@ -331,6 +544,72 @@ async function steerRunViaServer(context, runId, message) {
|
|
|
331
544
|
});
|
|
332
545
|
return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : { ok: true };
|
|
333
546
|
}
|
|
547
|
+
async function getRunPiSessionViaServer(context, runId) {
|
|
548
|
+
const payload = await requestServerJson(context, `/api/runs/${encodeURIComponent(runId)}/pi`);
|
|
549
|
+
return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
|
|
550
|
+
}
|
|
551
|
+
async function getRunPiMessagesViaServer(context, runId) {
|
|
552
|
+
const payload = await requestServerJson(context, `/api/runs/${encodeURIComponent(runId)}/pi/messages`);
|
|
553
|
+
return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : { messages: [] };
|
|
554
|
+
}
|
|
555
|
+
async function getRunPiStatusViaServer(context, runId) {
|
|
556
|
+
const payload = await requestServerJson(context, `/api/runs/${encodeURIComponent(runId)}/pi/status`);
|
|
557
|
+
return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
|
|
558
|
+
}
|
|
559
|
+
async function getRunPiCommandsViaServer(context, runId) {
|
|
560
|
+
const payload = await requestServerJson(context, `/api/runs/${encodeURIComponent(runId)}/pi/commands`);
|
|
561
|
+
return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : { commands: [] };
|
|
562
|
+
}
|
|
563
|
+
async function getRunPiCapabilitiesViaServer(context, runId) {
|
|
564
|
+
const payload = await requestServerJson(context, `/api/runs/${encodeURIComponent(runId)}/pi/capabilities`);
|
|
565
|
+
return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : { capabilities: null };
|
|
566
|
+
}
|
|
567
|
+
async function sendRunPiPromptViaServer(context, runId, text, streamingBehavior) {
|
|
568
|
+
const payload = await requestServerJson(context, `/api/runs/${encodeURIComponent(runId)}/pi/prompt`, {
|
|
569
|
+
method: "POST",
|
|
570
|
+
headers: { "content-type": "application/json" },
|
|
571
|
+
body: JSON.stringify({ text, streamingBehavior })
|
|
572
|
+
});
|
|
573
|
+
return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : { accepted: true };
|
|
574
|
+
}
|
|
575
|
+
async function sendRunPiShellViaServer(context, runId, text) {
|
|
576
|
+
const payload = await requestServerJson(context, `/api/runs/${encodeURIComponent(runId)}/pi/shell`, {
|
|
577
|
+
method: "POST",
|
|
578
|
+
headers: { "content-type": "application/json" },
|
|
579
|
+
body: JSON.stringify({ text })
|
|
580
|
+
});
|
|
581
|
+
return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : { accepted: true };
|
|
582
|
+
}
|
|
583
|
+
async function runRunPiCommandViaServer(context, runId, text) {
|
|
584
|
+
const payload = await requestServerJson(context, `/api/runs/${encodeURIComponent(runId)}/pi/commands/run`, {
|
|
585
|
+
method: "POST",
|
|
586
|
+
headers: { "content-type": "application/json" },
|
|
587
|
+
body: JSON.stringify({ text })
|
|
588
|
+
});
|
|
589
|
+
return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : { type: "done" };
|
|
590
|
+
}
|
|
591
|
+
async function respondRunPiExtensionUiViaServer(context, runId, requestId, valueOrCancel) {
|
|
592
|
+
const payload = await requestServerJson(context, `/api/runs/${encodeURIComponent(runId)}/pi/extension-ui/respond`, {
|
|
593
|
+
method: "POST",
|
|
594
|
+
headers: { "content-type": "application/json" },
|
|
595
|
+
body: JSON.stringify({ requestId, ...valueOrCancel })
|
|
596
|
+
});
|
|
597
|
+
return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : { accepted: true };
|
|
598
|
+
}
|
|
599
|
+
async function abortRunPiViaServer(context, runId) {
|
|
600
|
+
const payload = await requestServerJson(context, `/api/runs/${encodeURIComponent(runId)}/pi/abort`, { method: "POST" });
|
|
601
|
+
return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : { aborted: true };
|
|
602
|
+
}
|
|
603
|
+
async function buildRunPiEventsWebSocketUrl(context, runId) {
|
|
604
|
+
const server = await ensureServerForCli(context.projectRoot);
|
|
605
|
+
const url = new URL(`${server.baseUrl.replace(/\/+$/, "")}/api/runs/${encodeURIComponent(runId)}/pi/events`);
|
|
606
|
+
url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
|
|
607
|
+
if (server.authToken)
|
|
608
|
+
url.searchParams.set("token", server.authToken);
|
|
609
|
+
if (server.serverProjectRoot)
|
|
610
|
+
url.searchParams.set("rigProjectRoot", server.serverProjectRoot);
|
|
611
|
+
return url.toString();
|
|
612
|
+
}
|
|
334
613
|
async function submitTaskRunViaServer(context, input) {
|
|
335
614
|
const isTaskRun = Boolean(input.taskId);
|
|
336
615
|
const endpoint = isTaskRun ? "/api/runs/task" : "/api/runs/adhoc";
|
|
@@ -354,29 +633,49 @@ async function submitTaskRunViaServer(context, input) {
|
|
|
354
633
|
})
|
|
355
634
|
});
|
|
356
635
|
if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
|
|
357
|
-
throw new
|
|
636
|
+
throw new CliError("Rig server returned an invalid run submission payload.", 1, { hint: "Check `rig server status` and retry; `rig run list` shows whether the run was created anyway." });
|
|
358
637
|
}
|
|
359
638
|
const runId = payload.runId;
|
|
360
639
|
if (typeof runId !== "string" || runId.trim().length === 0) {
|
|
361
|
-
throw new
|
|
640
|
+
throw new CliError("Rig server returned no runId for the submitted run.", 1, { hint: "Check `rig run list` \u2014 the run may still have been created; otherwise retry the submission." });
|
|
362
641
|
}
|
|
363
642
|
return { runId };
|
|
364
643
|
}
|
|
365
644
|
export {
|
|
645
|
+
updateWorkspaceTaskViaServer,
|
|
366
646
|
switchServerProjectRootViaServer,
|
|
367
647
|
submitTaskRunViaServer,
|
|
368
648
|
stopRunViaServer,
|
|
369
649
|
steerRunViaServer,
|
|
650
|
+
setServerPhaseListener,
|
|
370
651
|
setGitHubBearerTokenForCurrentProcess,
|
|
652
|
+
sendRunPiShellViaServer,
|
|
653
|
+
sendRunPiPromptViaServer,
|
|
371
654
|
selectNextWorkspaceTaskViaServer,
|
|
655
|
+
runRunPiCommandViaServer,
|
|
656
|
+
resumeRunViaServer,
|
|
657
|
+
respondRunPiExtensionUiViaServer,
|
|
658
|
+
resolveServerConnectionLabel,
|
|
372
659
|
requestServerJson,
|
|
373
660
|
registerProjectViaServer,
|
|
374
661
|
prepareRemoteCheckoutViaServer,
|
|
375
662
|
postGitHubTokenViaServer,
|
|
376
663
|
listWorkspaceTasksViaServer,
|
|
664
|
+
listRunsViaServer,
|
|
665
|
+
listGitHubProjectsViaServer,
|
|
377
666
|
getWorkspaceTaskViaServer,
|
|
667
|
+
getRunTimelineViaServer,
|
|
668
|
+
getRunPiStatusViaServer,
|
|
669
|
+
getRunPiSessionViaServer,
|
|
670
|
+
getRunPiMessagesViaServer,
|
|
671
|
+
getRunPiCommandsViaServer,
|
|
672
|
+
getRunPiCapabilitiesViaServer,
|
|
378
673
|
getRunLogsViaServer,
|
|
379
674
|
getRunDetailsViaServer,
|
|
675
|
+
getGitHubProjectStatusFieldViaServer,
|
|
380
676
|
getGitHubAuthStatusViaServer,
|
|
381
|
-
|
|
677
|
+
ensureTaskLabelsViaServer,
|
|
678
|
+
ensureServerForCli,
|
|
679
|
+
buildRunPiEventsWebSocketUrl,
|
|
680
|
+
abortRunPiViaServer
|
|
382
681
|
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export declare const UPLOADED_SNAPSHOT_PR_MARKER = "<!-- rig:uploaded-snapshot -->";
|
|
2
|
+
export declare const SNAPSHOT_ARCHIVE_VERSION = 1;
|
|
3
|
+
export declare const SNAPSHOT_ARCHIVE_CONTENT_TYPE = "application/vnd.rig.snapshot+json";
|
|
4
|
+
export type SnapshotUploadManifest = {
|
|
5
|
+
readonly root: string;
|
|
6
|
+
readonly files: readonly string[];
|
|
7
|
+
readonly excludedDirectories: readonly string[];
|
|
8
|
+
};
|
|
9
|
+
export type SnapshotUploadArchiveFile = {
|
|
10
|
+
readonly path: string;
|
|
11
|
+
readonly contentBase64: string;
|
|
12
|
+
};
|
|
13
|
+
export type SnapshotUploadArchive = {
|
|
14
|
+
readonly version: typeof SNAPSHOT_ARCHIVE_VERSION;
|
|
15
|
+
readonly root: string;
|
|
16
|
+
readonly files: readonly SnapshotUploadArchiveFile[];
|
|
17
|
+
readonly excludedDirectories: readonly string[];
|
|
18
|
+
readonly createdAt: string;
|
|
19
|
+
};
|
|
20
|
+
export declare function buildSnapshotUploadManifest(projectRoot: string, options?: {
|
|
21
|
+
readonly excludedDirectories?: readonly string[];
|
|
22
|
+
}): Promise<SnapshotUploadManifest>;
|
|
23
|
+
export declare function createSnapshotUploadArchive(projectRoot: string, options?: {
|
|
24
|
+
readonly excludedDirectories?: readonly string[];
|
|
25
|
+
readonly now?: () => Date;
|
|
26
|
+
}): Promise<SnapshotUploadArchive>;
|
|
27
|
+
export declare function encodeSnapshotUploadArchive(archive: SnapshotUploadArchive): string;
|
|
28
|
+
export declare function writeSnapshotUploadArchive(projectRoot: string, outputPath: string, options?: {
|
|
29
|
+
readonly excludedDirectories?: readonly string[];
|
|
30
|
+
readonly now?: () => Date;
|
|
31
|
+
}): Promise<SnapshotUploadArchive>;
|
|
32
|
+
export declare function uploadSnapshotArchiveViaServer(context: {
|
|
33
|
+
readonly projectRoot: string;
|
|
34
|
+
}, input: {
|
|
35
|
+
readonly repoSlug: string;
|
|
36
|
+
readonly archive: SnapshotUploadArchive;
|
|
37
|
+
readonly baseDir?: string;
|
|
38
|
+
}): Promise<Record<string, unknown>>;
|
|
39
|
+
export declare function appendUploadedSnapshotPrNotice(body: string): string;
|