@h-rig/cli 0.0.6-alpha.94 → 0.0.6-alpha.96
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,818 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
var __require = import.meta.require;
|
|
3
|
-
|
|
4
|
-
// packages/cli/src/commands/task.ts
|
|
5
|
-
import { createPluginHost as createPluginHost2, selectNextReadyTaskByPriority } from "@rig/core";
|
|
6
|
-
import { loadConfig as loadConfig2 } from "@rig/core/load-config";
|
|
7
|
-
import {
|
|
8
|
-
taskArtifactDir,
|
|
9
|
-
taskArtifacts,
|
|
10
|
-
taskArtifactWrite,
|
|
11
|
-
taskDeps,
|
|
12
|
-
taskInfo,
|
|
13
|
-
taskLookup,
|
|
14
|
-
taskReady,
|
|
15
|
-
taskRecord,
|
|
16
|
-
taskReopen,
|
|
17
|
-
taskScope,
|
|
18
|
-
taskStatus,
|
|
19
|
-
taskValidate,
|
|
20
|
-
taskVerify
|
|
21
|
-
} from "@rig/runtime/control-plane/native/task-ops";
|
|
22
|
-
|
|
23
|
-
// packages/cli/src/runner.ts
|
|
24
|
-
import { EventBus } from "@rig/runtime/control-plane/runtime/events";
|
|
25
|
-
import { CliError as RuntimeCliError } from "@rig/runtime/control-plane/errors";
|
|
26
|
-
import { evaluate, loadPolicy, resolveAction } from "@rig/runtime/control-plane/runtime/guard";
|
|
27
|
-
import { buildBinary } from "@rig/runtime/control-plane/runtime/isolation";
|
|
28
|
-
|
|
29
|
-
class CliError extends RuntimeCliError {
|
|
30
|
-
hint;
|
|
31
|
-
constructor(message, exitCode = 1, options = {}) {
|
|
32
|
-
super(message, exitCode);
|
|
33
|
-
if (options.hint?.trim()) {
|
|
34
|
-
this.hint = options.hint.trim();
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
function takeFlag(args, flag) {
|
|
39
|
-
const rest = [];
|
|
40
|
-
let value = false;
|
|
41
|
-
for (const arg of args) {
|
|
42
|
-
if (arg === flag) {
|
|
43
|
-
value = true;
|
|
44
|
-
continue;
|
|
45
|
-
}
|
|
46
|
-
rest.push(arg);
|
|
47
|
-
}
|
|
48
|
-
return { value, rest };
|
|
49
|
-
}
|
|
50
|
-
function takeOption(args, option) {
|
|
51
|
-
const rest = [];
|
|
52
|
-
let value;
|
|
53
|
-
for (let index = 0;index < args.length; index += 1) {
|
|
54
|
-
const current = args[index];
|
|
55
|
-
if (current === option) {
|
|
56
|
-
const next = args[index + 1];
|
|
57
|
-
if (!next || next.startsWith("-")) {
|
|
58
|
-
throw new CliError(`Missing value for ${option}`, 1, { hint: `Provide a value after ${option}, e.g. \`${option} <value>\`.` });
|
|
59
|
-
}
|
|
60
|
-
value = next;
|
|
61
|
-
index += 1;
|
|
62
|
-
continue;
|
|
63
|
-
}
|
|
64
|
-
if (current !== undefined) {
|
|
65
|
-
rest.push(current);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
return { value, rest };
|
|
69
|
-
}
|
|
70
|
-
function requireNoExtraArgs(args, usage) {
|
|
71
|
-
if (args.length > 0) {
|
|
72
|
-
throw new CliError(`Unexpected arguments: ${args.join(" ")}
|
|
73
|
-
Usage: ${usage}`);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
function requireTask(taskId, usage) {
|
|
77
|
-
if (!taskId) {
|
|
78
|
-
throw new CliError(`Missing --task option.
|
|
79
|
-
Usage: ${usage}`);
|
|
80
|
-
}
|
|
81
|
-
return taskId;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// packages/cli/src/commands/_cli-format.ts
|
|
85
|
-
import pc from "picocolors";
|
|
86
|
-
var dim = pc.dim;
|
|
87
|
-
var faintBar = pc.dim("\u2502");
|
|
88
|
-
var accent = pc.cyan;
|
|
89
|
-
function arrayField(record, key) {
|
|
90
|
-
const value = record[key];
|
|
91
|
-
return Array.isArray(value) ? value.filter((entry) => typeof entry === "string" && entry.trim().length > 0) : [];
|
|
92
|
-
}
|
|
93
|
-
function rawObject(record) {
|
|
94
|
-
const value = record.raw;
|
|
95
|
-
return value && typeof value === "object" && !Array.isArray(value) ? value : record;
|
|
96
|
-
}
|
|
97
|
-
function truncate(value, width) {
|
|
98
|
-
return value.length <= width ? value : `${value.slice(0, Math.max(0, width - 1))}\u2026`;
|
|
99
|
-
}
|
|
100
|
-
function pad(value, width) {
|
|
101
|
-
return value.length >= width ? value : `${value}${" ".repeat(width - value.length)}`;
|
|
102
|
-
}
|
|
103
|
-
function statusColor(status) {
|
|
104
|
-
const normalized = status.trim().toLowerCase();
|
|
105
|
-
if (["done", "completed", "ready", "healthy", "open", "approved"].includes(normalized))
|
|
106
|
-
return pc.green;
|
|
107
|
-
if (["failed", "error", "blocked", "rejected", "stopped"].includes(normalized))
|
|
108
|
-
return pc.red;
|
|
109
|
-
if (["running", "in_progress", "in-progress", "active", "booting"].includes(normalized))
|
|
110
|
-
return pc.cyan;
|
|
111
|
-
if (["pending", "queued", "created", "local"].includes(normalized))
|
|
112
|
-
return pc.yellow;
|
|
113
|
-
return pc.dim;
|
|
114
|
-
}
|
|
115
|
-
function firstString(record, keys, fallback = "") {
|
|
116
|
-
for (const key of keys) {
|
|
117
|
-
const value = record[key];
|
|
118
|
-
if (typeof value === "string" && value.trim())
|
|
119
|
-
return value;
|
|
120
|
-
}
|
|
121
|
-
return fallback;
|
|
122
|
-
}
|
|
123
|
-
function printFormattedOutput(message) {
|
|
124
|
-
console.log(message);
|
|
125
|
-
}
|
|
126
|
-
function formatSection(title, subtitle) {
|
|
127
|
-
return `${pc.bold(accent("\u25C6"))} ${pc.bold(title)}${subtitle ? dim(` \u2014 ${subtitle}`) : ""}`;
|
|
128
|
-
}
|
|
129
|
-
function formatSuccessCard(title, rows = []) {
|
|
130
|
-
const body = rows.filter(([, value]) => value !== undefined && value !== null && String(value).length > 0).map(([key, value]) => `${faintBar} ${dim(key.padEnd(12))} ${value}`);
|
|
131
|
-
return [formatSection(title), ...body].join(`
|
|
132
|
-
`);
|
|
133
|
-
}
|
|
134
|
-
function formatNextSteps(steps) {
|
|
135
|
-
if (steps.length === 0)
|
|
136
|
-
return [];
|
|
137
|
-
return [pc.bold("Next"), ...steps.map((step) => `${accent("\u203A")} ${step}`)];
|
|
138
|
-
}
|
|
139
|
-
function formatTaskList(tasks, options = {}) {
|
|
140
|
-
if (tasks.length === 0) {
|
|
141
|
-
return [formatSection("Tasks", "empty"), dim("No tasks available."), "", ...formatNextSteps(["Refresh: `rig task list`", "Pick next: `rig task next`"])].join(`
|
|
142
|
-
`);
|
|
143
|
-
}
|
|
144
|
-
if (options.raw) {
|
|
145
|
-
return JSON.stringify(tasks, null, 2);
|
|
146
|
-
}
|
|
147
|
-
const rows = tasks.map((task) => summarizeTaskRow(task));
|
|
148
|
-
const idWidth = Math.max(2, ...rows.map((row) => row.id.length));
|
|
149
|
-
const statusWidth = Math.max(6, ...rows.map((row) => row.status.length));
|
|
150
|
-
const body = rows.map((row) => {
|
|
151
|
-
const labels = row.labels.length > 0 ? dim(` ${row.labels.slice(0, 4).map((label) => `#${label}`).join(" ")}`) : "";
|
|
152
|
-
const source = row.source ? dim(` ${row.source}`) : "";
|
|
153
|
-
return [
|
|
154
|
-
pc.bold(pad(truncate(row.id, idWidth), idWidth)),
|
|
155
|
-
statusColor(row.status)(pad(truncate(row.status, statusWidth), statusWidth)),
|
|
156
|
-
`${row.title}${labels}${source}`
|
|
157
|
-
].join(" ");
|
|
158
|
-
});
|
|
159
|
-
return [formatSection("Tasks", `${tasks.length}`), ...body].join(`
|
|
160
|
-
`);
|
|
161
|
-
}
|
|
162
|
-
function summarizeTaskRow(task) {
|
|
163
|
-
const raw = rawObject(task);
|
|
164
|
-
return {
|
|
165
|
-
id: firstString(task, ["id", "taskId"], "(unknown-task)"),
|
|
166
|
-
title: firstString(task, ["title", "summary", "name"], "(untitled)"),
|
|
167
|
-
status: firstString(task, ["status"], "unknown"),
|
|
168
|
-
labels: arrayField(task, "labels").length > 0 ? arrayField(task, "labels") : arrayField(raw, "labels"),
|
|
169
|
-
source: firstString(task, ["source"], "")
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
function formatTaskCard(task, options = {}) {
|
|
173
|
-
const raw = rawObject(task);
|
|
174
|
-
const lines = [formatSection(options.title ?? (options.selected ? "Selected task" : "Task"))];
|
|
175
|
-
for (const [label, value] of [
|
|
176
|
-
["id", firstString(task, ["id", "taskId"], "(unknown-task)")],
|
|
177
|
-
["title", firstString(task, ["title", "summary", "name"], "(untitled)")],
|
|
178
|
-
["status", firstString(task, ["status"], "unknown")],
|
|
179
|
-
["source", firstString(task, ["source"], "")],
|
|
180
|
-
["url", firstString(raw, ["url"], "")]
|
|
181
|
-
]) {
|
|
182
|
-
if (value)
|
|
183
|
-
lines.push(`${faintBar} ${dim(label.padEnd(12))} ${value}`);
|
|
184
|
-
}
|
|
185
|
-
const labels = arrayField(task, "labels");
|
|
186
|
-
if (labels.length > 0)
|
|
187
|
-
lines.push(`${faintBar} ${dim("labels".padEnd(12))} ${labels.map((label) => `#${label}`).join(" ")}`);
|
|
188
|
-
return lines.join(`
|
|
189
|
-
`);
|
|
190
|
-
}
|
|
191
|
-
function formatTaskDetails(task) {
|
|
192
|
-
return formatTaskCard(task, { title: "Task details" });
|
|
193
|
-
}
|
|
194
|
-
function formatSubmittedRun(input) {
|
|
195
|
-
return formatSuccessCard("Run submitted", [
|
|
196
|
-
["run", input.runId],
|
|
197
|
-
["task", input.taskId ?? undefined],
|
|
198
|
-
["title", input.title ?? undefined],
|
|
199
|
-
["queue", input.queuePosition ?? undefined]
|
|
200
|
-
]);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
// packages/cli/src/commands/_run-bridge.ts
|
|
204
|
-
import { randomUUID } from "crypto";
|
|
205
|
-
import { spawn as nodeSpawn } from "child_process";
|
|
206
|
-
import { existsSync, readdirSync, readFileSync } from "fs";
|
|
207
|
-
import { dirname, resolve } from "path";
|
|
208
|
-
import { fileURLToPath } from "url";
|
|
209
|
-
import { CUSTOM_TYPE_FOR, sessionIdFromSessionFile } from "@rig/contracts";
|
|
210
|
-
import { createPluginHost } from "@rig/core";
|
|
211
|
-
import { loadConfig } from "@rig/core/load-config";
|
|
212
|
-
import { resolveOwnerNamespaceKey, resolveRegistryBaseUrl, resolveRegistrySecret, resolveSelectedRemote } from "@rig/runtime/control-plane/remote";
|
|
213
|
-
import { listAgentRuntimes } from "@rig/runtime/control-plane/runtime/isolation";
|
|
214
|
-
import { createRegistryClient } from "@rig/relay-registry";
|
|
215
|
-
import {
|
|
216
|
-
listActiveCollabSessions as ompListActiveCollabSessions
|
|
217
|
-
} from "@oh-my-pi/pi-coding-agent/collab/api";
|
|
218
|
-
function stringField(value) {
|
|
219
|
-
return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
|
|
220
|
-
}
|
|
221
|
-
function githubUserId(value) {
|
|
222
|
-
if (typeof value === "number" && Number.isInteger(value))
|
|
223
|
-
return String(value);
|
|
224
|
-
return stringField(value);
|
|
225
|
-
}
|
|
226
|
-
function readJsonRecord(path) {
|
|
227
|
-
if (!existsSync(path))
|
|
228
|
-
return null;
|
|
229
|
-
try {
|
|
230
|
-
const parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
231
|
-
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
232
|
-
} catch {
|
|
233
|
-
return null;
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
function publicIdentityEnv(projectRoot) {
|
|
237
|
-
const auth = readJsonRecord(resolve(projectRoot, ".rig", "state", "github-auth.json"));
|
|
238
|
-
const connection = readJsonRecord(resolve(projectRoot, ".rig", "state", "connection.json"));
|
|
239
|
-
const values = {};
|
|
240
|
-
const selectedRepo = stringField(auth?.selectedRepo) ?? stringField(connection?.project);
|
|
241
|
-
const userId = githubUserId(auth?.userId);
|
|
242
|
-
const login = stringField(auth?.login);
|
|
243
|
-
const namespaceKey = stringField(auth?.userNamespaceKey) ?? resolveOwnerNamespaceKey(projectRoot);
|
|
244
|
-
if (selectedRepo)
|
|
245
|
-
values.RIG_SELECTED_REPO = selectedRepo;
|
|
246
|
-
if (userId)
|
|
247
|
-
values.RIG_GITHUB_USER_ID = userId;
|
|
248
|
-
if (login)
|
|
249
|
-
values.RIG_GITHUB_LOGIN = login;
|
|
250
|
-
if (namespaceKey)
|
|
251
|
-
values.RIG_GITHUB_NAMESPACE_KEY = namespaceKey;
|
|
252
|
-
return values;
|
|
253
|
-
}
|
|
254
|
-
function taskText(value) {
|
|
255
|
-
return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
|
|
256
|
-
}
|
|
257
|
-
function taskUrl(record) {
|
|
258
|
-
const metadata = record;
|
|
259
|
-
return taskText(metadata.url) ?? taskText(metadata.html_url) ?? taskText(metadata.webUrl);
|
|
260
|
-
}
|
|
261
|
-
function taskBody(record) {
|
|
262
|
-
const metadata = record;
|
|
263
|
-
return taskText(metadata.body) ?? taskText(metadata.description);
|
|
264
|
-
}
|
|
265
|
-
function taskTitle(record) {
|
|
266
|
-
const metadata = record;
|
|
267
|
-
return taskText(metadata.title) ?? taskText(metadata.name) ?? record.id;
|
|
268
|
-
}
|
|
269
|
-
function toExtensionTask(record, sourceKind) {
|
|
270
|
-
return {
|
|
271
|
-
id: record.id,
|
|
272
|
-
title: taskTitle(record),
|
|
273
|
-
status: typeof record.status === "string" ? record.status : null,
|
|
274
|
-
source: sourceKind,
|
|
275
|
-
url: taskUrl(record),
|
|
276
|
-
body: taskBody(record)
|
|
277
|
-
};
|
|
278
|
-
}
|
|
279
|
-
async function loadConfiguredTaskSource(projectRoot) {
|
|
280
|
-
const normalizedRoot = resolve(projectRoot);
|
|
281
|
-
const config = await loadConfig(normalizedRoot);
|
|
282
|
-
const pluginHost = createPluginHost(config.plugins);
|
|
283
|
-
const taskSourceFactory = pluginHost.resolveTaskSourceFactoryByKind(config.taskSource.kind);
|
|
284
|
-
if (!taskSourceFactory) {
|
|
285
|
-
const kinds = pluginHost.listExecutableTaskSources().map((entry) => entry.kind).join(", ") || "none";
|
|
286
|
-
throw new Error(`No task source factory registered for kind "${config.taskSource.kind}". Registered kinds: ${kinds}.`);
|
|
287
|
-
}
|
|
288
|
-
return {
|
|
289
|
-
kind: config.taskSource.kind,
|
|
290
|
-
source: taskSourceFactory.factory(config.taskSource, { projectRoot: normalizedRoot })
|
|
291
|
-
};
|
|
292
|
-
}
|
|
293
|
-
async function listTasksFromSource(projectRoot, deps = {}) {
|
|
294
|
-
const { kind, source } = await (deps.loadTaskSource ?? loadConfiguredTaskSource)(projectRoot);
|
|
295
|
-
return (await source.list()).map((task) => toExtensionTask(task, kind));
|
|
296
|
-
}
|
|
297
|
-
async function getTaskFromSource(projectRoot, taskId, deps = {}) {
|
|
298
|
-
const tasks = await listTasksFromSource(projectRoot, deps);
|
|
299
|
-
return tasks.find((task) => task.id === taskId) ?? null;
|
|
300
|
-
}
|
|
301
|
-
function runningFromCompiledBinary() {
|
|
302
|
-
return import.meta.url.includes("$bunfs");
|
|
303
|
-
}
|
|
304
|
-
function resolveRigRunBin() {
|
|
305
|
-
if (runningFromCompiledBinary())
|
|
306
|
-
return resolve(dirname(process.execPath), "rig-run");
|
|
307
|
-
return resolve(dirname(fileURLToPath(import.meta.url)), "../../../rig-host/bin/rig-run.ts");
|
|
308
|
-
}
|
|
309
|
-
async function defaultRunRunProcess(input) {
|
|
310
|
-
const { runRunProcess } = await import("@rig/rig-host");
|
|
311
|
-
return await runRunProcess(input);
|
|
312
|
-
}
|
|
313
|
-
function shellQuote(value) {
|
|
314
|
-
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
315
|
-
}
|
|
316
|
-
function readProjectSlug(projectRoot) {
|
|
317
|
-
const connection = readJsonRecord(resolve(projectRoot, ".rig", "state", "connection.json"));
|
|
318
|
-
return stringField(connection?.project) ?? null;
|
|
319
|
-
}
|
|
320
|
-
function resolveProjectOriginUrl(projectRoot) {
|
|
321
|
-
const slug = readProjectSlug(projectRoot);
|
|
322
|
-
return slug && /^[^/]+\/[^/]+$/.test(slug) ? `https://github.com/${slug}.git` : null;
|
|
323
|
-
}
|
|
324
|
-
async function spawnRunProcess(input, deps = {}) {
|
|
325
|
-
const runId = (deps.uuid ?? randomUUID)();
|
|
326
|
-
const env = deps.env ?? process.env;
|
|
327
|
-
const identityEnv = publicIdentityEnv(input.projectRoot);
|
|
328
|
-
const selected = resolveSelectedRemote(input.projectRoot, env);
|
|
329
|
-
const sshTarget = selected?.sshTarget ?? env.RIG_REMOTE_ALIAS?.trim();
|
|
330
|
-
if (sshTarget) {
|
|
331
|
-
const namespaceKey = identityEnv.RIG_GITHUB_NAMESPACE_KEY ?? resolveOwnerNamespaceKey(input.projectRoot, env) ?? "";
|
|
332
|
-
const sh = shellQuote;
|
|
333
|
-
const originUrl = resolveProjectOriginUrl(input.projectRoot);
|
|
334
|
-
const repoName = (readProjectSlug(input.projectRoot)?.split("/").pop() ?? "project").replace(/[^A-Za-z0-9._-]/g, "-");
|
|
335
|
-
const checkoutExpr = selected?.checkout ? sh(selected.checkout) : `"$HOME/.rig/checkouts/${repoName}"`;
|
|
336
|
-
const identityAssignments = Object.entries(identityEnv).map(([k, v]) => `${k}=${sh(v)}`);
|
|
337
|
-
if (namespaceKey && !identityEnv.RIG_GITHUB_NAMESPACE_KEY)
|
|
338
|
-
identityAssignments.push(`RIG_GITHUB_NAMESPACE_KEY=${sh(namespaceKey)}`);
|
|
339
|
-
const runInvocation = [
|
|
340
|
-
`RIG_RUN_ID=${sh(runId)}`,
|
|
341
|
-
`RIG_TASK_ID=${sh(input.taskId)}`,
|
|
342
|
-
...identityAssignments,
|
|
343
|
-
selected?.registryBaseUrl ? `RIG_REGISTRY_URL=${sh(selected.registryBaseUrl)}` : "",
|
|
344
|
-
`rig run start --task ${sh(input.taskId)}`
|
|
345
|
-
].filter(Boolean).join(" ");
|
|
346
|
-
const provisionAndRun = [
|
|
347
|
-
"set -e",
|
|
348
|
-
`CHECKOUT=${checkoutExpr}`,
|
|
349
|
-
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; }`,
|
|
350
|
-
`cd "$CHECKOUT"`,
|
|
351
|
-
"git fetch origin --prune --quiet || true",
|
|
352
|
-
runInvocation
|
|
353
|
-
].join("; ");
|
|
354
|
-
const child = (deps.spawn ?? nodeSpawn)("ssh", [sshTarget, `bash -lc ${sh(provisionAndRun)}`], {
|
|
355
|
-
cwd: input.projectRoot,
|
|
356
|
-
env: { ...env, ...identityEnv },
|
|
357
|
-
detached: true,
|
|
358
|
-
stdio: "ignore"
|
|
359
|
-
});
|
|
360
|
-
child.unref();
|
|
361
|
-
return { runId };
|
|
362
|
-
}
|
|
363
|
-
await (deps.runRunProcess ?? defaultRunRunProcess)({
|
|
364
|
-
projectRoot: input.projectRoot,
|
|
365
|
-
taskId: input.taskId,
|
|
366
|
-
runId,
|
|
367
|
-
title: input.title,
|
|
368
|
-
rigRunBin: (deps.resolveRigRunBin ?? resolveRigRunBin)()
|
|
369
|
-
});
|
|
370
|
-
return { runId };
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
// packages/cli/src/commands/task.ts
|
|
374
|
-
var CLOSED_STATUSES = {
|
|
375
|
-
closed: true,
|
|
376
|
-
completed: true,
|
|
377
|
-
complete: true,
|
|
378
|
-
done: true,
|
|
379
|
-
cancelled: true,
|
|
380
|
-
canceled: true,
|
|
381
|
-
merged: true,
|
|
382
|
-
resolved: true
|
|
383
|
-
};
|
|
384
|
-
var NOT_READY_STATUSES = {
|
|
385
|
-
...CLOSED_STATUSES,
|
|
386
|
-
blocked: true,
|
|
387
|
-
in_progress: true,
|
|
388
|
-
"in-progress": true,
|
|
389
|
-
running: true,
|
|
390
|
-
active: true
|
|
391
|
-
};
|
|
392
|
-
function normalizeTaskId(value) {
|
|
393
|
-
const trimmed = value?.trim();
|
|
394
|
-
if (!trimmed)
|
|
395
|
-
return;
|
|
396
|
-
return trimmed.startsWith("#") && /^#\d+$/.test(trimmed) ? trimmed.slice(1) : trimmed;
|
|
397
|
-
}
|
|
398
|
-
function parsePositiveLimit(value) {
|
|
399
|
-
if (value === undefined)
|
|
400
|
-
return;
|
|
401
|
-
const parsed = Number.parseInt(value, 10);
|
|
402
|
-
if (!Number.isFinite(parsed) || parsed <= 0 || String(parsed) !== value.trim()) {
|
|
403
|
-
throw new CliError("--limit must be a positive integer.", 1, { hint: "Re-run with a positive number, e.g. `rig task list --limit 20`." });
|
|
404
|
-
}
|
|
405
|
-
return parsed;
|
|
406
|
-
}
|
|
407
|
-
function parseTaskFilters(args) {
|
|
408
|
-
let pending = args;
|
|
409
|
-
const assigneeResult = takeOption(pending, "--assignee");
|
|
410
|
-
pending = assigneeResult.rest;
|
|
411
|
-
const stateResult = takeOption(pending, "--state");
|
|
412
|
-
pending = stateResult.rest;
|
|
413
|
-
const limitResult = takeOption(pending, "--limit");
|
|
414
|
-
pending = limitResult.rest;
|
|
415
|
-
const searchResult = takeOption(pending, "--search");
|
|
416
|
-
pending = searchResult.rest;
|
|
417
|
-
const state = stateResult.value?.trim().toLowerCase();
|
|
418
|
-
if (state !== undefined && state !== "open" && state !== "closed") {
|
|
419
|
-
throw new CliError(`Invalid --state value: ${stateResult.value}.`, 1, { hint: "Use `--state open` or `--state closed`." });
|
|
420
|
-
}
|
|
421
|
-
const assignee = normalizeAssigneeFilter(assigneeResult.value);
|
|
422
|
-
const limit = parsePositiveLimit(limitResult.value);
|
|
423
|
-
const search = searchResult.value?.trim();
|
|
424
|
-
return {
|
|
425
|
-
filters: {
|
|
426
|
-
...assignee ? { assignee } : {},
|
|
427
|
-
...state ? { state } : {},
|
|
428
|
-
...limit !== undefined ? { limit } : {},
|
|
429
|
-
...search ? { search } : {}
|
|
430
|
-
},
|
|
431
|
-
rest: pending
|
|
432
|
-
};
|
|
433
|
-
}
|
|
434
|
-
function normalizeAssigneeFilter(value) {
|
|
435
|
-
const trimmed = value?.trim();
|
|
436
|
-
if (!trimmed)
|
|
437
|
-
return;
|
|
438
|
-
const lowered = trimmed.toLowerCase();
|
|
439
|
-
if (lowered === "me" || lowered === "@me") {
|
|
440
|
-
return currentLogin() ?? "@me";
|
|
441
|
-
}
|
|
442
|
-
return trimmed.startsWith("@") ? trimmed.slice(1) : trimmed;
|
|
443
|
-
}
|
|
444
|
-
function currentLogin() {
|
|
445
|
-
for (const key of ["RIG_GITHUB_LOGIN", "GITHUB_ACTOR", "GH_USER", "USER", "USERNAME"]) {
|
|
446
|
-
const value = process.env[key]?.trim();
|
|
447
|
-
if (value)
|
|
448
|
-
return value;
|
|
449
|
-
}
|
|
450
|
-
return;
|
|
451
|
-
}
|
|
452
|
-
function isRecord(value) {
|
|
453
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
454
|
-
}
|
|
455
|
-
function readTaskStatus(task) {
|
|
456
|
-
const value = task.status;
|
|
457
|
-
return typeof value === "string" ? value.trim().toLowerCase() : "";
|
|
458
|
-
}
|
|
459
|
-
function taskMatchesState(task, state) {
|
|
460
|
-
if (!state)
|
|
461
|
-
return true;
|
|
462
|
-
const closed = CLOSED_STATUSES[readTaskStatus(task)] === true;
|
|
463
|
-
return state === "closed" ? closed : !closed;
|
|
464
|
-
}
|
|
465
|
-
function taskMatchesSearch(task, search) {
|
|
466
|
-
const needle = search?.trim().toLowerCase();
|
|
467
|
-
if (!needle)
|
|
468
|
-
return true;
|
|
469
|
-
const title = typeof task.title === "string" ? task.title : "";
|
|
470
|
-
const body = typeof task.body === "string" ? task.body : "";
|
|
471
|
-
const description = typeof task.description === "string" ? task.description : "";
|
|
472
|
-
return `${task.id}
|
|
473
|
-
${title}
|
|
474
|
-
${body}
|
|
475
|
-
${description}`.toLowerCase().includes(needle);
|
|
476
|
-
}
|
|
477
|
-
function collectAssigneeLogins(value) {
|
|
478
|
-
if (typeof value === "string")
|
|
479
|
-
return [value];
|
|
480
|
-
if (Array.isArray(value))
|
|
481
|
-
return value.flatMap((entry) => collectAssigneeLogins(entry));
|
|
482
|
-
if (isRecord(value)) {
|
|
483
|
-
return [value.login, value.username, value.name, value.id].flatMap((entry) => collectAssigneeLogins(entry));
|
|
484
|
-
}
|
|
485
|
-
return [];
|
|
486
|
-
}
|
|
487
|
-
function taskAssignees(task) {
|
|
488
|
-
const raw = isRecord(task.raw) ? task.raw : null;
|
|
489
|
-
return [
|
|
490
|
-
task.assignee,
|
|
491
|
-
task.assignees,
|
|
492
|
-
task.assignedTo,
|
|
493
|
-
task.owner,
|
|
494
|
-
raw?.assignee,
|
|
495
|
-
raw?.assignees,
|
|
496
|
-
raw?.assignedTo,
|
|
497
|
-
raw?.owner
|
|
498
|
-
].flatMap((value) => collectAssigneeLogins(value));
|
|
499
|
-
}
|
|
500
|
-
function taskMatchesAssignee(task, assignee) {
|
|
501
|
-
if (!assignee)
|
|
502
|
-
return true;
|
|
503
|
-
const needle = assignee.startsWith("@") ? assignee.slice(1) : assignee;
|
|
504
|
-
return taskAssignees(task).some((login) => {
|
|
505
|
-
const normalized = login.startsWith("@") ? login.slice(1) : login;
|
|
506
|
-
return normalized.localeCompare(needle, undefined, { sensitivity: "accent" }) === 0;
|
|
507
|
-
});
|
|
508
|
-
}
|
|
509
|
-
function applyFilters(tasks, filters) {
|
|
510
|
-
const filtered = tasks.filter((task) => taskMatchesAssignee(task, filters.assignee)).filter((task) => taskMatchesState(task, filters.state)).filter((task) => taskMatchesSearch(task, filters.search));
|
|
511
|
-
return filters.limit === undefined ? filtered : filtered.slice(0, filters.limit);
|
|
512
|
-
}
|
|
513
|
-
function isReadyTask(task) {
|
|
514
|
-
const status = readTaskStatus(task);
|
|
515
|
-
return status.length === 0 || NOT_READY_STATUSES[status] !== true;
|
|
516
|
-
}
|
|
517
|
-
function asDependencyProjection(task) {
|
|
518
|
-
const record = task;
|
|
519
|
-
return {
|
|
520
|
-
...record,
|
|
521
|
-
status: typeof record.status === "string" && record.status.trim() ? record.status : "open",
|
|
522
|
-
priority: record.priority ?? "P2",
|
|
523
|
-
metadata: isRecord(record.metadata) ? record.metadata : {}
|
|
524
|
-
};
|
|
525
|
-
}
|
|
526
|
-
function selectNextTask(tasks, filters) {
|
|
527
|
-
const matching = applyFilters(tasks, { ...filters, limit: undefined }).filter(isReadyTask);
|
|
528
|
-
const selected = selectNextReadyTaskByPriority(matching.map(asDependencyProjection), {
|
|
529
|
-
filter: (task) => isReadyTask(task)
|
|
530
|
-
});
|
|
531
|
-
return selected ?? matching[0] ?? null;
|
|
532
|
-
}
|
|
533
|
-
function readTaskTitle(task) {
|
|
534
|
-
if (!task)
|
|
535
|
-
return null;
|
|
536
|
-
for (const key of ["title", "summary", "name"]) {
|
|
537
|
-
const value = task[key];
|
|
538
|
-
if (typeof value === "string" && value.trim())
|
|
539
|
-
return value.trim();
|
|
540
|
-
}
|
|
541
|
-
return null;
|
|
542
|
-
}
|
|
543
|
-
function printText(context, message) {
|
|
544
|
-
if (context.outputMode === "text") {
|
|
545
|
-
printFormattedOutput(message);
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
async function listTasksForCommand(projectRoot, deps) {
|
|
549
|
-
if (deps.listTasks)
|
|
550
|
-
return deps.listTasks(projectRoot);
|
|
551
|
-
if (deps.loadTaskSource) {
|
|
552
|
-
const { kind, source } = await deps.loadTaskSource(projectRoot);
|
|
553
|
-
return (await source.list()).map((task) => ({ ...task, source: kind }));
|
|
554
|
-
}
|
|
555
|
-
return listTasksFromSource(projectRoot);
|
|
556
|
-
}
|
|
557
|
-
async function getTaskForCommand(projectRoot, taskId, deps) {
|
|
558
|
-
if (deps.getTask)
|
|
559
|
-
return deps.getTask(projectRoot, taskId);
|
|
560
|
-
if (deps.loadTaskSource) {
|
|
561
|
-
const { kind, source } = await deps.loadTaskSource(projectRoot);
|
|
562
|
-
const task = source.get ? await source.get(taskId) : (await source.list()).find((entry) => entry.id === taskId);
|
|
563
|
-
return task ? { ...task, source: kind } : null;
|
|
564
|
-
}
|
|
565
|
-
return getTaskFromSource(projectRoot, taskId);
|
|
566
|
-
}
|
|
567
|
-
async function defaultLoadTaskSource(projectRoot) {
|
|
568
|
-
const config = await loadConfig2(projectRoot);
|
|
569
|
-
const pluginHost = createPluginHost2(config.plugins);
|
|
570
|
-
const factory = pluginHost.resolveTaskSourceFactoryByKind(config.taskSource.kind);
|
|
571
|
-
if (!factory) {
|
|
572
|
-
const kinds = pluginHost.listExecutableTaskSources().map((entry) => entry.kind).join(", ") || "none";
|
|
573
|
-
throw new CliError(`No task source factory registered for kind ${config.taskSource.kind}.`, 1, { hint: `Registered task sources: ${kinds}.` });
|
|
574
|
-
}
|
|
575
|
-
return { kind: config.taskSource.kind, source: factory.factory(config.taskSource, { projectRoot }) };
|
|
576
|
-
}
|
|
577
|
-
function getTaskCreator(source) {
|
|
578
|
-
const record = source;
|
|
579
|
-
if (typeof record.createTask === "function")
|
|
580
|
-
return record.createTask.bind(source);
|
|
581
|
-
if (typeof record.create === "function")
|
|
582
|
-
return record.create.bind(source);
|
|
583
|
-
return null;
|
|
584
|
-
}
|
|
585
|
-
async function executeReportBug(context, args, deps) {
|
|
586
|
-
let pending = args;
|
|
587
|
-
const titleResult = takeOption(pending, "--title");
|
|
588
|
-
pending = titleResult.rest;
|
|
589
|
-
const bodyResult = takeOption(pending, "--body");
|
|
590
|
-
pending = bodyResult.rest;
|
|
591
|
-
requireNoExtraArgs(pending, "rig task report-bug --title <text> [--body <text>]");
|
|
592
|
-
const title = titleResult.value?.trim();
|
|
593
|
-
if (!title) {
|
|
594
|
-
throw new CliError("rig task report-bug requires --title.", 1, { hint: 'Re-run with `rig task report-bug --title "Short bug title"`.' });
|
|
595
|
-
}
|
|
596
|
-
const { kind, source } = await (deps.loadTaskSource ?? defaultLoadTaskSource)(context.projectRoot);
|
|
597
|
-
const creator = getTaskCreator(source);
|
|
598
|
-
if (!creator) {
|
|
599
|
-
throw new CliError(`The configured ${kind} task source does not expose a task creation API, so rig task report-bug cannot create a bug task.`, 1, {
|
|
600
|
-
hint: "Create the bug in the configured task source directly, or install a task source that supports createTask/create."
|
|
601
|
-
});
|
|
602
|
-
}
|
|
603
|
-
const created = await creator({
|
|
604
|
-
title,
|
|
605
|
-
body: bodyResult.value ?? "Bug reported via `rig task report-bug`.",
|
|
606
|
-
status: "open",
|
|
607
|
-
labels: ["bug"],
|
|
608
|
-
type: "bug"
|
|
609
|
-
});
|
|
610
|
-
const taskId = typeof created === "string" ? created : isRecord(created) && typeof created.id === "string" ? created.id : undefined;
|
|
611
|
-
printText(context, taskId ? `Created bug task ${taskId}.` : "Created bug task.");
|
|
612
|
-
return { ok: true, group: "task", command: "report-bug", details: { taskId: taskId ?? null, source: kind } };
|
|
613
|
-
}
|
|
614
|
-
async function resolveRunTask(context, rawTaskId, useNext, filters, deps) {
|
|
615
|
-
if (useNext) {
|
|
616
|
-
const tasks = await listTasksForCommand(context.projectRoot, deps);
|
|
617
|
-
const task = selectNextTask(tasks, filters);
|
|
618
|
-
const taskId2 = normalizeTaskId(task?.id);
|
|
619
|
-
if (!task || !taskId2)
|
|
620
|
-
throw new CliError("No ready task found.", 1, { hint: "Run `rig task list` to inspect available tasks." });
|
|
621
|
-
return { taskId: taskId2, task };
|
|
622
|
-
}
|
|
623
|
-
const taskId = normalizeTaskId(rawTaskId);
|
|
624
|
-
if (!taskId) {
|
|
625
|
-
throw new CliError("Missing task id for rig task run.", 1, { hint: "Use `rig task run <task-id>`, `rig task run --task <id>`, or `rig task run --next`." });
|
|
626
|
-
}
|
|
627
|
-
return { taskId, task: await getTaskForCommand(context.projectRoot, taskId, deps) };
|
|
628
|
-
}
|
|
629
|
-
async function executeTask(context, args, deps = {}) {
|
|
630
|
-
const [command = "help", ...rest] = args;
|
|
631
|
-
switch (command) {
|
|
632
|
-
case "help":
|
|
633
|
-
printText(context, "Usage: rig task <list|next|show|details|info|scope|deps|status|lookup|record|run|ready|validate|verify|reopen|artifacts|artifact-dir|artifact-write|report-bug> [options]");
|
|
634
|
-
return { ok: true, group: "task", command: "help" };
|
|
635
|
-
case "list": {
|
|
636
|
-
const parsed = parseTaskFilters(rest);
|
|
637
|
-
requireNoExtraArgs(parsed.rest, "rig task list [--assignee <login|me|@me>] [--state open|closed] [--search <text>] [--limit <n>]");
|
|
638
|
-
const tasks = applyFilters(await listTasksForCommand(context.projectRoot, deps), parsed.filters);
|
|
639
|
-
printText(context, formatTaskList(tasks));
|
|
640
|
-
return { ok: true, group: "task", command, details: { tasks, count: tasks.length } };
|
|
641
|
-
}
|
|
642
|
-
case "next": {
|
|
643
|
-
const parsed = parseTaskFilters(rest);
|
|
644
|
-
requireNoExtraArgs(parsed.rest, "rig task next [--assignee <login|me|@me>] [--state open|closed] [--search <text>] [--limit <n>]");
|
|
645
|
-
const tasks = await listTasksForCommand(context.projectRoot, deps);
|
|
646
|
-
const task = selectNextTask(tasks, parsed.filters);
|
|
647
|
-
if (!task) {
|
|
648
|
-
printText(context, formatTaskList([]));
|
|
649
|
-
return { ok: true, group: "task", command, details: { task: null } };
|
|
650
|
-
}
|
|
651
|
-
printText(context, formatTaskCard(task, { selected: true }));
|
|
652
|
-
return { ok: true, group: "task", command, details: { task } };
|
|
653
|
-
}
|
|
654
|
-
case "show": {
|
|
655
|
-
let pending = rest;
|
|
656
|
-
const rawResult = takeFlag(pending, "--raw");
|
|
657
|
-
pending = rawResult.rest;
|
|
658
|
-
const taskResult = takeOption(pending, "--task");
|
|
659
|
-
pending = taskResult.rest;
|
|
660
|
-
const positional = pending[0]?.startsWith("-") ? undefined : pending[0];
|
|
661
|
-
requireNoExtraArgs(positional ? pending.slice(1) : pending, "rig task show <id>|--task <id> [--raw]");
|
|
662
|
-
const taskId = requireTask(normalizeTaskId(taskResult.value ?? positional), "rig task show <id>|--task <id> [--raw]");
|
|
663
|
-
const task = await getTaskForCommand(context.projectRoot, taskId, deps);
|
|
664
|
-
if (!task)
|
|
665
|
-
throw new CliError(`Task not found: ${taskId}`, 1, { hint: "Run `rig task list` to see available task ids." });
|
|
666
|
-
printText(context, rawResult.value ? JSON.stringify(task, null, 2) : formatTaskCard(task));
|
|
667
|
-
return { ok: true, group: "task", command, details: task };
|
|
668
|
-
}
|
|
669
|
-
case "details": {
|
|
670
|
-
const taskResult = takeOption(rest, "--task");
|
|
671
|
-
requireNoExtraArgs(taskResult.rest, "rig task details --task <id>");
|
|
672
|
-
const taskId = requireTask(normalizeTaskId(taskResult.value), "rig task details --task <id>");
|
|
673
|
-
const task = await getTaskForCommand(context.projectRoot, taskId, deps);
|
|
674
|
-
if (!task)
|
|
675
|
-
throw new CliError(`Task not found: ${taskId}`, 1, { hint: "Run `rig task list` to see available task ids." });
|
|
676
|
-
printText(context, formatTaskDetails(task));
|
|
677
|
-
return { ok: true, group: "task", command, details: task };
|
|
678
|
-
}
|
|
679
|
-
case "run": {
|
|
680
|
-
let pending = rest;
|
|
681
|
-
const nextResult = takeFlag(pending, "--next");
|
|
682
|
-
pending = nextResult.rest;
|
|
683
|
-
const detachResult = takeFlag(pending, "--detach");
|
|
684
|
-
pending = detachResult.rest;
|
|
685
|
-
const taskResult = takeOption(pending, "--task");
|
|
686
|
-
pending = taskResult.rest;
|
|
687
|
-
const titleResult = takeOption(pending, "--title");
|
|
688
|
-
pending = titleResult.rest;
|
|
689
|
-
const modelResult = takeOption(pending, "--model");
|
|
690
|
-
pending = modelResult.rest;
|
|
691
|
-
const promptResult = takeOption(pending, "--prompt");
|
|
692
|
-
pending = promptResult.rest;
|
|
693
|
-
const initialPromptResult = takeOption(pending, "--initial-prompt");
|
|
694
|
-
pending = initialPromptResult.rest;
|
|
695
|
-
const parsed = parseTaskFilters(pending);
|
|
696
|
-
pending = parsed.rest;
|
|
697
|
-
const positional = pending[0]?.startsWith("-") ? undefined : pending[0];
|
|
698
|
-
requireNoExtraArgs(positional ? pending.slice(1) : pending, "rig task run [#<issue>|<task-id>|--next|--task <id>] [--title <t>] [--model <m>] [--prompt <p>] [--initial-prompt <p>] [--detach] [--search <text>]");
|
|
699
|
-
const { taskId, task } = await resolveRunTask(context, taskResult.value ?? positional, nextResult.value, parsed.filters, deps);
|
|
700
|
-
const title = titleResult.value ?? readTaskTitle(task);
|
|
701
|
-
const submitted = await (deps.spawnRun ?? spawnRunProcess)({ projectRoot: context.projectRoot, taskId, title });
|
|
702
|
-
const note = detachResult.value ? `
|
|
703
|
-
|
|
704
|
-
Note: --detach is the default; the run was submitted detached.` : "";
|
|
705
|
-
printText(context, `${formatSubmittedRun({ runId: submitted.runId, taskId, title })}
|
|
706
|
-
|
|
707
|
-
Next: rig run attach ${submitted.runId}${note}`);
|
|
708
|
-
return { ok: true, group: "task", command, details: { runId: submitted.runId, taskId, title: title ?? null, detached: true } };
|
|
709
|
-
}
|
|
710
|
-
case "ready":
|
|
711
|
-
requireNoExtraArgs(rest, "rig task ready");
|
|
712
|
-
await (deps.taskReady ?? taskReady)(context.projectRoot);
|
|
713
|
-
return { ok: true, group: "task", command };
|
|
714
|
-
case "validate":
|
|
715
|
-
case "verify": {
|
|
716
|
-
const taskResult = takeOption(rest, "--task");
|
|
717
|
-
requireNoExtraArgs(taskResult.rest, `rig task ${command} [--task <id>]`);
|
|
718
|
-
const taskId = normalizeTaskId(taskResult.value);
|
|
719
|
-
const ok = command === "validate" ? await (deps.taskValidate ?? taskValidate)(context.projectRoot, taskId) : await (deps.taskVerify ?? taskVerify)(context.projectRoot, taskId);
|
|
720
|
-
return { ok, group: "task", command, details: { taskId: taskId ?? null } };
|
|
721
|
-
}
|
|
722
|
-
case "reopen": {
|
|
723
|
-
let pending = rest;
|
|
724
|
-
const allResult = takeFlag(pending, "--all");
|
|
725
|
-
pending = allResult.rest;
|
|
726
|
-
const taskResult = takeOption(pending, "--task");
|
|
727
|
-
pending = taskResult.rest;
|
|
728
|
-
const reasonResult = takeOption(pending, "--reason");
|
|
729
|
-
pending = reasonResult.rest;
|
|
730
|
-
requireNoExtraArgs(pending, "rig task reopen [--task <id> | --all] [--reason <text>]");
|
|
731
|
-
const taskId = normalizeTaskId(taskResult.value);
|
|
732
|
-
if (allResult.value && taskId)
|
|
733
|
-
throw new CliError("Pass only one of --task or --all.", 1, { hint: "Use `rig task reopen --task <id>` or `rig task reopen --all`." });
|
|
734
|
-
const summary = (deps.taskReopen ?? taskReopen)(context.projectRoot, {
|
|
735
|
-
all: allResult.value,
|
|
736
|
-
dryRun: context.dryRun,
|
|
737
|
-
...taskId ? { taskId } : {}
|
|
738
|
-
});
|
|
739
|
-
return { ok: true, group: "task", command, details: { ...summary, reason: reasonResult.value ?? null } };
|
|
740
|
-
}
|
|
741
|
-
case "artifacts": {
|
|
742
|
-
const taskResult = takeOption(rest, "--task");
|
|
743
|
-
requireNoExtraArgs(taskResult.rest, "rig task artifacts [--task <id>]");
|
|
744
|
-
const taskId = normalizeTaskId(taskResult.value);
|
|
745
|
-
(deps.taskArtifacts ?? taskArtifacts)(context.projectRoot, taskId);
|
|
746
|
-
return { ok: true, group: "task", command, details: { taskId: taskId ?? null } };
|
|
747
|
-
}
|
|
748
|
-
case "artifact-dir": {
|
|
749
|
-
const taskResult = takeOption(rest, "--task");
|
|
750
|
-
requireNoExtraArgs(taskResult.rest, "rig task artifact-dir [--task <id>]");
|
|
751
|
-
const taskId = normalizeTaskId(taskResult.value);
|
|
752
|
-
const dir = (deps.taskArtifactDir ?? taskArtifactDir)(context.projectRoot, taskId);
|
|
753
|
-
printText(context, dir);
|
|
754
|
-
return { ok: true, group: "task", command, details: { taskId: taskId ?? null, dir } };
|
|
755
|
-
}
|
|
756
|
-
case "artifact-write": {
|
|
757
|
-
const taskResult = takeOption(rest, "--task");
|
|
758
|
-
const [filename, content, ...extra] = taskResult.rest;
|
|
759
|
-
requireNoExtraArgs(extra, "rig task artifact-write <filename> <content> [--task <id>]");
|
|
760
|
-
if (!filename || content === undefined) {
|
|
761
|
-
throw new CliError("Missing artifact filename or content.", 1, { hint: "Use `rig task artifact-write <filename> <content> [--task <id>]`." });
|
|
762
|
-
}
|
|
763
|
-
const taskId = normalizeTaskId(taskResult.value);
|
|
764
|
-
(deps.taskArtifactWrite ?? taskArtifactWrite)(context.projectRoot, filename, content, taskId);
|
|
765
|
-
return { ok: true, group: "task", command, details: { taskId: taskId ?? null, filename } };
|
|
766
|
-
}
|
|
767
|
-
case "report-bug":
|
|
768
|
-
return executeReportBug(context, rest, deps);
|
|
769
|
-
case "info": {
|
|
770
|
-
const taskResult = takeOption(rest, "--task");
|
|
771
|
-
requireNoExtraArgs(taskResult.rest, "rig task info [--task <id>]");
|
|
772
|
-
await taskInfo(context.projectRoot, normalizeTaskId(taskResult.value));
|
|
773
|
-
return { ok: true, group: "task", command };
|
|
774
|
-
}
|
|
775
|
-
case "scope": {
|
|
776
|
-
const filesFlag = takeFlag(rest, "--files");
|
|
777
|
-
const taskResult = takeOption(filesFlag.rest, "--task");
|
|
778
|
-
requireNoExtraArgs(taskResult.rest, "rig task scope [--files] [--task <id>]");
|
|
779
|
-
await taskScope(context.projectRoot, Boolean(filesFlag.value), normalizeTaskId(taskResult.value));
|
|
780
|
-
return { ok: true, group: "task", command };
|
|
781
|
-
}
|
|
782
|
-
case "deps": {
|
|
783
|
-
const taskResult = takeOption(rest, "--task");
|
|
784
|
-
requireNoExtraArgs(taskResult.rest, "rig task deps [--task <id>]");
|
|
785
|
-
await taskDeps(context.projectRoot, normalizeTaskId(taskResult.value));
|
|
786
|
-
return { ok: true, group: "task", command };
|
|
787
|
-
}
|
|
788
|
-
case "status":
|
|
789
|
-
requireNoExtraArgs(rest, "rig task status");
|
|
790
|
-
taskStatus(context.projectRoot);
|
|
791
|
-
return { ok: true, group: "task", command };
|
|
792
|
-
case "lookup": {
|
|
793
|
-
const [rawId, ...extra] = rest;
|
|
794
|
-
requireNoExtraArgs(extra, "rig task lookup <id>");
|
|
795
|
-
const lookupId = requireTask(normalizeTaskId(rawId), "rig task lookup <id>");
|
|
796
|
-
const resolved = taskLookup(context.projectRoot, lookupId);
|
|
797
|
-
printText(context, resolved);
|
|
798
|
-
return { ok: true, group: "task", command, details: { id: lookupId, resolved } };
|
|
799
|
-
}
|
|
800
|
-
case "record": {
|
|
801
|
-
const taskResult = takeOption(rest, "--task");
|
|
802
|
-
const [type, ...textParts] = taskResult.rest;
|
|
803
|
-
const text = textParts.join(" ").trim();
|
|
804
|
-
if (type !== "decision" && type !== "failure") {
|
|
805
|
-
throw new CliError("rig task record requires a type: decision|failure.", 1, { hint: "rig task record <decision|failure> <text> [--task <id>]" });
|
|
806
|
-
}
|
|
807
|
-
if (!text)
|
|
808
|
-
throw new CliError("rig task record requires text.", 1, { hint: "rig task record <decision|failure> <text> [--task <id>]" });
|
|
809
|
-
taskRecord(context.projectRoot, type, text, normalizeTaskId(taskResult.value));
|
|
810
|
-
return { ok: true, group: "task", command, details: { type, text } };
|
|
811
|
-
}
|
|
812
|
-
default:
|
|
813
|
-
throw new CliError(`Unknown task command: ${command}`, 1, { hint: "Run `rig task --help`." });
|
|
814
|
-
}
|
|
815
|
-
}
|
|
816
|
-
export {
|
|
817
|
-
executeTask
|
|
818
|
-
};
|