@h-rig/cli-surface-plugin 0.0.6-alpha.146

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/README.md +1 -0
  2. package/dist/src/app/drone-ui.d.ts +34 -0
  3. package/dist/src/app/drone-ui.js +278 -0
  4. package/dist/src/commands/_async-ui.d.ts +10 -0
  5. package/dist/src/commands/_async-ui.js +121 -0
  6. package/dist/src/commands/_cli-format.d.ts +56 -0
  7. package/dist/src/commands/_cli-format.js +332 -0
  8. package/dist/src/commands/_connection-state.d.ts +54 -0
  9. package/dist/src/commands/_connection-state.js +187 -0
  10. package/dist/src/commands/_doctor-checks.d.ts +9 -0
  11. package/dist/src/commands/_doctor-checks.js +24 -0
  12. package/dist/src/commands/_help-catalog.d.ts +29 -0
  13. package/dist/src/commands/_help-catalog.js +157 -0
  14. package/dist/src/commands/_inprocess-services.d.ts +33 -0
  15. package/dist/src/commands/_inprocess-services.js +102 -0
  16. package/dist/src/commands/_json-output.d.ts +11 -0
  17. package/dist/src/commands/_json-output.js +54 -0
  18. package/dist/src/commands/_parsers.d.ts +15 -0
  19. package/dist/src/commands/_parsers.js +114 -0
  20. package/dist/src/commands/_paths.d.ts +11 -0
  21. package/dist/src/commands/_paths.js +50 -0
  22. package/dist/src/commands/_pi-frontend.d.ts +35 -0
  23. package/dist/src/commands/_pi-frontend.js +64 -0
  24. package/dist/src/commands/_pi-install.d.ts +42 -0
  25. package/dist/src/commands/_pi-install.js +167 -0
  26. package/dist/src/commands/_policy.d.ts +8 -0
  27. package/dist/src/commands/_policy.js +138 -0
  28. package/dist/src/commands/_probes.d.ts +1 -0
  29. package/dist/src/commands/_probes.js +13 -0
  30. package/dist/src/commands/_run-driver-helpers.d.ts +26 -0
  31. package/dist/src/commands/_run-driver-helpers.js +132 -0
  32. package/dist/src/commands/_run-subcommands.d.ts +3 -0
  33. package/dist/src/commands/_run-subcommands.js +31 -0
  34. package/dist/src/commands/_spinner.d.ts +25 -0
  35. package/dist/src/commands/_spinner.js +65 -0
  36. package/dist/src/commands/agent.d.ts +3 -0
  37. package/dist/src/commands/agent.js +322 -0
  38. package/dist/src/commands/config.d.ts +3 -0
  39. package/dist/src/commands/config.js +193 -0
  40. package/dist/src/commands/dist.d.ts +28 -0
  41. package/dist/src/commands/dist.js +435 -0
  42. package/dist/src/commands/doctor.d.ts +3 -0
  43. package/dist/src/commands/doctor.js +171 -0
  44. package/dist/src/commands/github.d.ts +3 -0
  45. package/dist/src/commands/github.js +342 -0
  46. package/dist/src/commands/inbox.d.ts +19 -0
  47. package/dist/src/commands/inbox.js +241 -0
  48. package/dist/src/commands/init.d.ts +64 -0
  49. package/dist/src/commands/init.js +1449 -0
  50. package/dist/src/commands/inspect.d.ts +20 -0
  51. package/dist/src/commands/inspect.js +337 -0
  52. package/dist/src/commands/pi.d.ts +3 -0
  53. package/dist/src/commands/pi.js +177 -0
  54. package/dist/src/commands/plugin.d.ts +20 -0
  55. package/dist/src/commands/plugin.js +238 -0
  56. package/dist/src/commands/profile-and-review.d.ts +4 -0
  57. package/dist/src/commands/profile-and-review.js +223 -0
  58. package/dist/src/commands/queue.d.ts +3 -0
  59. package/dist/src/commands/queue.js +197 -0
  60. package/dist/src/commands/remote.d.ts +3 -0
  61. package/dist/src/commands/remote.js +516 -0
  62. package/dist/src/commands/repo-git-harness.d.ts +5 -0
  63. package/dist/src/commands/repo-git-harness.js +282 -0
  64. package/dist/src/commands/run.d.ts +22 -0
  65. package/dist/src/commands/run.js +645 -0
  66. package/dist/src/commands/server.d.ts +3 -0
  67. package/dist/src/commands/server.js +155 -0
  68. package/dist/src/commands/setup.d.ts +16 -0
  69. package/dist/src/commands/setup.js +356 -0
  70. package/dist/src/commands/stats.d.ts +11 -0
  71. package/dist/src/commands/stats.js +219 -0
  72. package/dist/src/commands/task-run-driver.d.ts +93 -0
  73. package/dist/src/commands/task-run-driver.js +136 -0
  74. package/dist/src/commands/task.d.ts +46 -0
  75. package/dist/src/commands/task.js +555 -0
  76. package/dist/src/commands/test.d.ts +3 -0
  77. package/dist/src/commands/test.js +46 -0
  78. package/dist/src/commands/triage.d.ts +11 -0
  79. package/dist/src/commands/triage.js +224 -0
  80. package/dist/src/commands/workspace.d.ts +3 -0
  81. package/dist/src/commands/workspace.js +130 -0
  82. package/dist/src/kernel-dispatch.d.ts +15 -0
  83. package/dist/src/kernel-dispatch.js +16 -0
  84. package/dist/src/plugin.d.ts +3 -0
  85. package/dist/src/plugin.js +5440 -0
  86. package/dist/src/rig-config-package-deps.d.ts +10 -0
  87. package/dist/src/rig-config-package-deps.js +272 -0
  88. package/dist/src/runner.d.ts +47 -0
  89. package/dist/src/runner.js +267 -0
  90. package/dist/src/version.d.ts +8 -0
  91. package/dist/src/version.js +47 -0
  92. package/dist/src/withMutedConsole.d.ts +2 -0
  93. package/dist/src/withMutedConsole.js +42 -0
  94. package/package.json +34 -0
@@ -0,0 +1,555 @@
1
+ // @bun
2
+ var __require = import.meta.require;
3
+
4
+ // packages/cli-surface-plugin/src/commands/task.ts
5
+ import {
6
+ applyFilters,
7
+ createTask,
8
+ getTask,
9
+ listTasks,
10
+ normalizeTaskId,
11
+ readTaskTitle,
12
+ resolveStartTask,
13
+ selectNextReadyTask,
14
+ taskArtifactDir,
15
+ taskArtifacts,
16
+ taskArtifactWrite,
17
+ taskDeps,
18
+ taskInfo,
19
+ taskLookup,
20
+ taskReady,
21
+ taskRecord,
22
+ taskReopen,
23
+ taskScope,
24
+ taskStatus,
25
+ taskValidate,
26
+ taskVerify
27
+ } from "@rig/client";
28
+
29
+ // packages/cli-surface-plugin/src/runner.ts
30
+ import { EventBus } from "@rig/runtime/control-plane/runtime/events";
31
+ import { CliError as RuntimeCliError } from "@rig/runtime/control-plane/errors";
32
+ import { evaluate, loadPolicy, resolveAction } from "@rig/runtime/control-plane/runtime/guard";
33
+ import { buildBinary } from "@rig/runtime/control-plane/runtime/isolation";
34
+
35
+ class CliError extends RuntimeCliError {
36
+ hint;
37
+ constructor(message, exitCode = 1, options = {}) {
38
+ super(message, exitCode);
39
+ if (options.hint?.trim()) {
40
+ this.hint = options.hint.trim();
41
+ }
42
+ }
43
+ }
44
+ function takeFlag(args, flag) {
45
+ const rest = [];
46
+ let value = false;
47
+ for (const arg of args) {
48
+ if (arg === flag) {
49
+ value = true;
50
+ continue;
51
+ }
52
+ rest.push(arg);
53
+ }
54
+ return { value, rest };
55
+ }
56
+ function takeOption(args, option) {
57
+ const rest = [];
58
+ let value;
59
+ for (let index = 0;index < args.length; index += 1) {
60
+ const current = args[index];
61
+ if (current === option) {
62
+ const next = args[index + 1];
63
+ if (!next || next.startsWith("-")) {
64
+ throw new CliError(`Missing value for ${option}`, 1, { hint: `Provide a value after ${option}, e.g. \`${option} <value>\`.` });
65
+ }
66
+ value = next;
67
+ index += 1;
68
+ continue;
69
+ }
70
+ if (current !== undefined) {
71
+ rest.push(current);
72
+ }
73
+ }
74
+ return { value, rest };
75
+ }
76
+ function requireNoExtraArgs(args, usage) {
77
+ if (args.length > 0) {
78
+ throw new CliError(`Unexpected arguments: ${args.join(" ")}
79
+ Usage: ${usage}`);
80
+ }
81
+ }
82
+ function requireTask(taskId, usage) {
83
+ if (!taskId) {
84
+ throw new CliError(`Missing --task option.
85
+ Usage: ${usage}`);
86
+ }
87
+ return taskId;
88
+ }
89
+
90
+ // packages/cli-surface-plugin/src/kernel-dispatch.ts
91
+ async function dispatchThroughKernel(input, options) {
92
+ const { getProcessKernel } = await import("@rig/kernel/boot-default");
93
+ const kernel = getProcessKernel();
94
+ if (!kernel) {
95
+ throw new Error("Kernel not booted: cannot dispatch a run through the transport capability.");
96
+ }
97
+ const runId = await kernel.transport.dispatch(input, options);
98
+ return { runId };
99
+ }
100
+
101
+ // packages/cli-surface-plugin/src/commands/_cli-format.ts
102
+ import pc from "picocolors";
103
+ import { runStatusColorRole, runStatusText, statusColorRole } from "@rig/client";
104
+ var dim = pc.dim;
105
+ var faintBar = pc.dim("\u2502");
106
+ var accent = pc.cyan;
107
+ function arrayField(record, key) {
108
+ const value = record[key];
109
+ return Array.isArray(value) ? value.filter((entry) => typeof entry === "string" && entry.trim().length > 0) : [];
110
+ }
111
+ function rawObject(record) {
112
+ const value = record.raw;
113
+ return value && typeof value === "object" && !Array.isArray(value) ? value : record;
114
+ }
115
+ function truncate(value, width) {
116
+ return value.length <= width ? value : `${value.slice(0, Math.max(0, width - 1))}\u2026`;
117
+ }
118
+ function pad(value, width) {
119
+ return value.length >= width ? value : `${value}${" ".repeat(width - value.length)}`;
120
+ }
121
+ function colorForRole(role) {
122
+ switch (role) {
123
+ case "success":
124
+ return pc.green;
125
+ case "action-yellow":
126
+ return pc.yellow;
127
+ case "active-cyan":
128
+ return pc.cyan;
129
+ case "failure":
130
+ return pc.red;
131
+ case "muted":
132
+ case "neutral":
133
+ return pc.dim;
134
+ }
135
+ }
136
+ function statusColor(status) {
137
+ return colorForRole(statusColorRole(status));
138
+ }
139
+ function firstString(record, keys, fallback = "") {
140
+ for (const key of keys) {
141
+ const value = record[key];
142
+ if (typeof value === "string" && value.trim())
143
+ return value;
144
+ }
145
+ return fallback;
146
+ }
147
+ function printFormattedOutput(message) {
148
+ console.log(message);
149
+ }
150
+ function formatSection(title, subtitle) {
151
+ return `${pc.bold(accent("\u25C6"))} ${pc.bold(title)}${subtitle ? dim(` \u2014 ${subtitle}`) : ""}`;
152
+ }
153
+ function formatSuccessCard(title, rows = []) {
154
+ const body = rows.filter(([, value]) => value !== undefined && value !== null && String(value).length > 0).map(([key, value]) => `${faintBar} ${dim(key.padEnd(12))} ${value}`);
155
+ return [formatSection(title), ...body].join(`
156
+ `);
157
+ }
158
+ function formatNextSteps(steps) {
159
+ if (steps.length === 0)
160
+ return [];
161
+ return [pc.bold("Next"), ...steps.map((step) => `${accent("\u203A")} ${step}`)];
162
+ }
163
+ function formatTaskList(tasks, options = {}) {
164
+ if (tasks.length === 0) {
165
+ return [formatSection("Tasks", "empty"), dim("No tasks available."), "", ...formatNextSteps(["Refresh: `rig task list`", "Pick next: `rig task next`"])].join(`
166
+ `);
167
+ }
168
+ if (options.raw) {
169
+ return JSON.stringify(tasks, null, 2);
170
+ }
171
+ const rows = tasks.map((task) => summarizeTaskRow(task));
172
+ const idWidth = Math.max(2, ...rows.map((row) => row.id.length));
173
+ const statusWidth = Math.max(6, ...rows.map((row) => row.status.length));
174
+ const body = rows.map((row) => {
175
+ const labels = row.labels.length > 0 ? dim(` ${row.labels.slice(0, 4).map((label) => `#${label}`).join(" ")}`) : "";
176
+ const source = row.source ? dim(` ${row.source}`) : "";
177
+ return [
178
+ pc.bold(pad(truncate(row.id, idWidth), idWidth)),
179
+ statusColor(row.status)(pad(truncate(row.status, statusWidth), statusWidth)),
180
+ `${row.title}${labels}${source}`
181
+ ].join(" ");
182
+ });
183
+ return [formatSection("Tasks", `${tasks.length}`), ...body].join(`
184
+ `);
185
+ }
186
+ function summarizeTaskRow(task) {
187
+ const raw = rawObject(task);
188
+ return {
189
+ id: firstString(task, ["id", "taskId"], "(unknown-task)"),
190
+ title: firstString(task, ["title", "summary", "name"], "(untitled)"),
191
+ status: firstString(task, ["status"], "unknown"),
192
+ labels: arrayField(task, "labels").length > 0 ? arrayField(task, "labels") : arrayField(raw, "labels"),
193
+ source: firstString(task, ["source"], "")
194
+ };
195
+ }
196
+ function formatTaskCard(task, options = {}) {
197
+ const raw = rawObject(task);
198
+ const lines = [formatSection(options.title ?? (options.selected ? "Selected task" : "Task"))];
199
+ for (const [label, value] of [
200
+ ["id", firstString(task, ["id", "taskId"], "(unknown-task)")],
201
+ ["title", firstString(task, ["title", "summary", "name"], "(untitled)")],
202
+ ["status", firstString(task, ["status"], "unknown")],
203
+ ["source", firstString(task, ["source"], "")],
204
+ ["url", firstString(raw, ["url"], "")]
205
+ ]) {
206
+ if (value)
207
+ lines.push(`${faintBar} ${dim(label.padEnd(12))} ${value}`);
208
+ }
209
+ const labels = arrayField(task, "labels");
210
+ if (labels.length > 0)
211
+ lines.push(`${faintBar} ${dim("labels".padEnd(12))} ${labels.map((label) => `#${label}`).join(" ")}`);
212
+ return lines.join(`
213
+ `);
214
+ }
215
+ function formatTaskDetails(task) {
216
+ return formatTaskCard(task, { title: "Task details" });
217
+ }
218
+ function formatSubmittedRun(input) {
219
+ return formatSuccessCard("Run submitted", [
220
+ ["run", input.runId],
221
+ ["task", input.taskId ?? undefined],
222
+ ["title", input.title ?? undefined],
223
+ ["queue", input.queuePosition ?? undefined]
224
+ ]);
225
+ }
226
+
227
+ // packages/cli-surface-plugin/src/commands/task.ts
228
+ function parsePositiveLimit(value) {
229
+ if (value === undefined)
230
+ return;
231
+ const parsed = Number.parseInt(value, 10);
232
+ if (!Number.isFinite(parsed) || parsed <= 0 || String(parsed) !== value.trim()) {
233
+ throw new CliError("--limit must be a positive integer.", 1, { hint: "Re-run with a positive number, e.g. `rig task list --limit 20`." });
234
+ }
235
+ return parsed;
236
+ }
237
+ function parseTaskFilters(args) {
238
+ let pending = args;
239
+ const assigneeResult = takeOption(pending, "--assignee");
240
+ pending = assigneeResult.rest;
241
+ const stateResult = takeOption(pending, "--state");
242
+ pending = stateResult.rest;
243
+ const limitResult = takeOption(pending, "--limit");
244
+ pending = limitResult.rest;
245
+ const searchResult = takeOption(pending, "--search");
246
+ pending = searchResult.rest;
247
+ const state = stateResult.value?.toLowerCase();
248
+ if (state !== undefined && state !== "open" && state !== "closed") {
249
+ throw new CliError(`Invalid --state value: ${stateResult.value}`, 1, { hint: "Use --state open or --state closed." });
250
+ }
251
+ const assignee = assigneeResult.value;
252
+ const limit = parsePositiveLimit(limitResult.value);
253
+ const search = searchResult.value?.trim();
254
+ return {
255
+ filters: {
256
+ ...assignee ? { assignee } : {},
257
+ ...state ? { state } : {},
258
+ ...limit !== undefined ? { limit } : {},
259
+ ...search ? { search } : {}
260
+ },
261
+ rest: pending
262
+ };
263
+ }
264
+ function parsePromptOverride(prompt, initialPrompt) {
265
+ const promptText = prompt?.trim();
266
+ const initialPromptText = initialPrompt?.trim();
267
+ if (promptText && initialPromptText) {
268
+ throw new CliError("Pass only one of --prompt or --initial-prompt.", 2, {
269
+ hint: "Use `--prompt <text>`; `--initial-prompt` is accepted as a compatibility alias."
270
+ });
271
+ }
272
+ return promptText || initialPromptText || null;
273
+ }
274
+ function printText(context, message) {
275
+ if (context.outputMode === "text")
276
+ printFormattedOutput(message);
277
+ }
278
+ async function captureOutputForJson(context, work) {
279
+ if (context.outputMode === "text")
280
+ return { result: await work(), output: null };
281
+ const originalLog = console.log;
282
+ const stdout = process.stdout;
283
+ const originalWrite = stdout.write;
284
+ let output = "";
285
+ console.log = (...args) => {
286
+ output += `${args.map(String).join(" ")}
287
+ `;
288
+ };
289
+ stdout.write = (chunk, ...args) => {
290
+ output += typeof chunk === "string" ? chunk : Buffer.from(chunk).toString("utf8");
291
+ const callback = args.find((arg) => typeof arg === "function");
292
+ callback?.();
293
+ return true;
294
+ };
295
+ try {
296
+ return { result: await work(), output };
297
+ } finally {
298
+ console.log = originalLog;
299
+ stdout.write = originalWrite;
300
+ }
301
+ }
302
+ async function listTasksForCommand(projectRoot, deps) {
303
+ if (deps.listTasks)
304
+ return deps.listTasks(projectRoot);
305
+ if (deps.loadTaskSource) {
306
+ const { kind, source } = await deps.loadTaskSource(projectRoot);
307
+ return (await source.list()).map((task) => ({ ...task, source: kind }));
308
+ }
309
+ return listTasks(projectRoot);
310
+ }
311
+ async function getTaskForCommand(projectRoot, taskId, deps) {
312
+ if (deps.getTask)
313
+ return deps.getTask(projectRoot, taskId);
314
+ if (deps.loadTaskSource) {
315
+ const { kind, source } = await deps.loadTaskSource(projectRoot);
316
+ const task = source.get ? await source.get(taskId) : (await source.list()).find((entry) => entry.id === taskId);
317
+ return task ? { ...task, source: kind } : null;
318
+ }
319
+ return getTask(projectRoot, taskId);
320
+ }
321
+ async function executeReportBug(context, args, deps) {
322
+ let pending = args;
323
+ const titleResult = takeOption(pending, "--title");
324
+ pending = titleResult.rest;
325
+ const bodyResult = takeOption(pending, "--body");
326
+ pending = bodyResult.rest;
327
+ requireNoExtraArgs(pending, "rig task report-bug --title <text> [--body <text>]");
328
+ const title = titleResult.value?.trim();
329
+ if (!title)
330
+ throw new CliError("rig task report-bug requires --title.", 1, { hint: 'Re-run with `rig task report-bug --title "Short bug title"`.' });
331
+ if (deps.loadTaskSource) {
332
+ const { kind, source } = await deps.loadTaskSource(context.projectRoot);
333
+ const creator = taskCreator(source);
334
+ if (!creator)
335
+ throw new CliError(`The configured ${kind} task source does not expose a create API.`, 1, { hint: "Create the bug in the configured task source directly, or install a task source that supports createTask/create." });
336
+ const created2 = await creator({ title, body: bodyResult.value ?? "Bug reported via `rig task report-bug`.", status: "open", labels: ["bug"], type: "bug" });
337
+ const taskId = typeof created2 === "string" ? created2 : created2 && typeof created2 === "object" && ("id" in created2) && typeof created2.id === "string" ? created2.id : undefined;
338
+ printText(context, taskId ? `Created bug task ${taskId}.` : "Created bug task.");
339
+ return { ok: true, group: "task", command: "report-bug", details: { taskId: taskId ?? null, source: kind } };
340
+ }
341
+ const created = await createTask(context.projectRoot, { title, body: bodyResult.value ?? "Bug reported via `rig task report-bug`.", status: "open", labels: ["bug"], type: "bug" });
342
+ printText(context, created.taskId ? `Created bug task ${created.taskId}.` : "Created bug task.");
343
+ return { ok: true, group: "task", command: "report-bug", details: { taskId: created.taskId, source: created.source } };
344
+ }
345
+ function taskCreator(source) {
346
+ const record = source;
347
+ if (typeof record.createTask === "function")
348
+ return record.createTask.bind(source);
349
+ if (typeof record.create === "function")
350
+ return record.create.bind(source);
351
+ return null;
352
+ }
353
+ async function resolveRunTask(context, rawTaskId, useNext, filters, deps) {
354
+ return resolveStartTask({
355
+ projectRoot: context.projectRoot,
356
+ taskId: rawTaskId,
357
+ next: useNext,
358
+ filters,
359
+ listTasks: (root) => listTasksForCommand(root, deps),
360
+ getTask: (root, taskId) => getTaskForCommand(root, taskId, deps)
361
+ });
362
+ }
363
+ async function executeTask(context, args, deps = {}) {
364
+ const [command = "help", ...rest] = args;
365
+ switch (command) {
366
+ case "help":
367
+ printText(context, "Usage: rig task <list|next|show|details|run|ready|validate|verify|reopen|artifacts|artifact-dir|artifact-write|report-bug|info|scope|deps|status|lookup|record>");
368
+ return { ok: true, group: "task", command: "help" };
369
+ case "list": {
370
+ const parsed = parseTaskFilters(rest);
371
+ requireNoExtraArgs(parsed.rest, "rig task list [--assignee <login|me|@me>] [--state open|closed] [--search <text>] [--limit <n>]");
372
+ const tasks = applyFilters(await listTasksForCommand(context.projectRoot, deps), parsed.filters);
373
+ printText(context, formatTaskList(tasks));
374
+ return { ok: true, group: "task", command, details: { tasks, count: tasks.length } };
375
+ }
376
+ case "next": {
377
+ const parsed = parseTaskFilters(rest);
378
+ requireNoExtraArgs(parsed.rest, "rig task next [--assignee <login|me|@me>] [--state open|closed] [--search <text>] [--limit <n>]");
379
+ const task = selectNextReadyTask(await listTasksForCommand(context.projectRoot, deps), parsed.filters);
380
+ if (!task) {
381
+ printText(context, formatTaskList([]));
382
+ return { ok: true, group: "task", command, details: { task: null } };
383
+ }
384
+ printText(context, formatTaskCard(task));
385
+ return { ok: true, group: "task", command, details: { task } };
386
+ }
387
+ case "show": {
388
+ let pending = rest;
389
+ const rawResult = takeFlag(pending, "--raw");
390
+ pending = rawResult.rest;
391
+ const taskResult = takeOption(pending, "--task");
392
+ pending = taskResult.rest;
393
+ const positional = pending[0]?.startsWith("-") ? undefined : pending[0];
394
+ requireNoExtraArgs(positional ? pending.slice(1) : pending, "rig task show <id>|--task <id> [--raw]");
395
+ const taskId = requireTask(normalizeTaskId(taskResult.value ?? positional), "rig task show <id>|--task <id>");
396
+ const task = await getTaskForCommand(context.projectRoot, taskId, deps);
397
+ if (!task)
398
+ throw new CliError(`Task not found: ${taskId}`, 1, { hint: "Run `rig task list` to see available task ids." });
399
+ printText(context, rawResult.value ? JSON.stringify(task, null, 2) : formatTaskCard(task));
400
+ return { ok: true, group: "task", command, details: task };
401
+ }
402
+ case "details": {
403
+ const taskResult = takeOption(rest, "--task");
404
+ requireNoExtraArgs(taskResult.rest, "rig task details --task <id>");
405
+ const taskId = requireTask(normalizeTaskId(taskResult.value), "rig task details --task <id>");
406
+ const task = await getTaskForCommand(context.projectRoot, taskId, deps);
407
+ if (!task)
408
+ throw new CliError(`Task not found: ${taskId}`, 1, { hint: "Run `rig task list` to see available task ids." });
409
+ printText(context, formatTaskDetails(task));
410
+ return { ok: true, group: "task", command, details: task };
411
+ }
412
+ case "run": {
413
+ let pending = rest;
414
+ const nextResult = takeFlag(pending, "--next");
415
+ pending = nextResult.rest;
416
+ const detachResult = takeFlag(pending, "--detach");
417
+ pending = detachResult.rest;
418
+ const taskResult = takeOption(pending, "--task");
419
+ pending = taskResult.rest;
420
+ const titleResult = takeOption(pending, "--title");
421
+ pending = titleResult.rest;
422
+ const modelResult = takeOption(pending, "--model");
423
+ pending = modelResult.rest;
424
+ const promptResult = takeOption(pending, "--prompt");
425
+ pending = promptResult.rest;
426
+ const initialPromptResult = takeOption(pending, "--initial-prompt");
427
+ pending = initialPromptResult.rest;
428
+ const parsed = parseTaskFilters(pending);
429
+ pending = parsed.rest;
430
+ const positional = pending[0]?.startsWith("-") ? undefined : pending[0];
431
+ 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>]");
432
+ const model = modelResult.value?.trim() || null;
433
+ const prompt = parsePromptOverride(promptResult.value, initialPromptResult.value);
434
+ const { taskId, task } = await resolveRunTask(context, taskResult.value ?? positional, nextResult.value, parsed.filters, deps);
435
+ const title = titleResult.value ?? readTaskTitle(task);
436
+ const submitted = await (deps.dispatch ?? deps.spawnRun ?? dispatchThroughKernel)({ projectRoot: context.projectRoot, taskId, title, model, prompt });
437
+ const note = detachResult.value ? `
438
+
439
+ Note: --detach is the default; the run was submitted detached.` : "";
440
+ printText(context, `${formatSubmittedRun({ runId: submitted.runId, taskId, title })}
441
+
442
+ Next: rig run attach ${submitted.runId}${note}`);
443
+ return { ok: true, group: "task", command, details: { runId: submitted.runId, taskId, title: title ?? null, model, prompt, detached: true } };
444
+ }
445
+ case "ready":
446
+ requireNoExtraArgs(rest, "rig task ready");
447
+ const captured = await captureOutputForJson(context, () => (deps.taskReady ?? taskReady)(context.projectRoot));
448
+ return { ok: true, group: "task", command, details: { ...captured.output !== null ? { output: captured.output } : {} } };
449
+ case "validate":
450
+ case "verify": {
451
+ const taskResult = takeOption(rest, "--task");
452
+ requireNoExtraArgs(taskResult.rest, `rig task ${command} [--task <id>]`);
453
+ const taskId = normalizeTaskId(taskResult.value);
454
+ const captured2 = await captureOutputForJson(context, () => command === "validate" ? (deps.taskValidate ?? taskValidate)(context.projectRoot, taskId) : (deps.taskVerify ?? taskVerify)(context.projectRoot, taskId));
455
+ const passed = captured2.result;
456
+ if (passed === false)
457
+ throw new CliError(`rig task ${command} failed${taskId ? ` for task ${taskId}` : ""}.`, 1, { hint: command === "validate" ? "Fix validation failures, then re-run `rig task validate`." : "Fix verification failures, then re-run `rig task verify`." });
458
+ return { ok: true, group: "task", command, details: { taskId: taskId ?? null, passed: true, ...captured2.output !== null ? { output: captured2.output } : {} } };
459
+ }
460
+ case "reopen": {
461
+ let pending = rest;
462
+ const allResult = takeFlag(pending, "--all");
463
+ pending = allResult.rest;
464
+ const taskResult = takeOption(pending, "--task");
465
+ pending = taskResult.rest;
466
+ const reasonResult = takeOption(pending, "--reason");
467
+ pending = reasonResult.rest;
468
+ requireNoExtraArgs(pending, "rig task reopen [--task <id> | --all] [--reason <text>]");
469
+ const taskId = normalizeTaskId(taskResult.value);
470
+ if (allResult.value && taskId)
471
+ throw new CliError("Pass only one of --task or --all.", 1, { hint: "Use `rig task reopen --task <id>` or `rig task reopen --all`." });
472
+ const captured2 = await captureOutputForJson(context, () => (deps.taskReopen ?? taskReopen)(context.projectRoot, { all: allResult.value, dryRun: context.dryRun, ...taskId ? { taskId } : {} }));
473
+ const summary = captured2.result;
474
+ return { ok: true, group: "task", command, details: { ...summary, reason: reasonResult.value ?? null, ...captured2.output !== null ? { output: captured2.output } : {} } };
475
+ }
476
+ case "artifacts": {
477
+ const taskResult = takeOption(rest, "--task");
478
+ const positional = taskResult.rest[0]?.startsWith("-") ? undefined : taskResult.rest[0];
479
+ requireNoExtraArgs(positional ? taskResult.rest.slice(1) : taskResult.rest, "rig task artifacts [<id>|--task <id>]");
480
+ const taskId = normalizeTaskId(taskResult.value ?? positional);
481
+ const captured2 = await captureOutputForJson(context, () => (deps.taskArtifacts ?? taskArtifacts)(context.projectRoot, taskId));
482
+ return { ok: true, group: "task", command, details: { taskId: taskId ?? null, ...captured2.output !== null ? { output: captured2.output } : {} } };
483
+ }
484
+ case "artifact-dir": {
485
+ const taskResult = takeOption(rest, "--task");
486
+ requireNoExtraArgs(taskResult.rest, "rig task artifact-dir [--task <id>]");
487
+ const taskId = normalizeTaskId(taskResult.value);
488
+ const dir = (deps.taskArtifactDir ?? taskArtifactDir)(context.projectRoot, taskId);
489
+ printText(context, dir);
490
+ return { ok: true, group: "task", command, details: { taskId: taskId ?? null, dir } };
491
+ }
492
+ case "artifact-write": {
493
+ const taskResult = takeOption(rest, "--task");
494
+ const [filename, content, ...extra] = taskResult.rest;
495
+ requireNoExtraArgs(extra, "rig task artifact-write <filename> <content> [--task <id>]");
496
+ if (!filename || content === undefined)
497
+ throw new CliError("Missing artifact filename or content.", 1, { hint: "Use `rig task artifact-write <filename> <content> [--task <id>]`." });
498
+ const taskId = normalizeTaskId(taskResult.value);
499
+ const captured2 = await captureOutputForJson(context, () => (deps.taskArtifactWrite ?? taskArtifactWrite)(context.projectRoot, filename, content, taskId));
500
+ return { ok: true, group: "task", command, details: { taskId: taskId ?? null, filename, ...captured2.output !== null ? { output: captured2.output } : {} } };
501
+ }
502
+ case "report-bug":
503
+ return executeReportBug(context, rest, deps);
504
+ case "info": {
505
+ const taskResult = takeOption(rest, "--task");
506
+ const positional = taskResult.rest[0]?.startsWith("-") ? undefined : taskResult.rest[0];
507
+ requireNoExtraArgs(positional ? taskResult.rest.slice(1) : taskResult.rest, "rig task info [<id>|--task <id>]");
508
+ const taskId = normalizeTaskId(taskResult.value ?? positional);
509
+ const captured2 = await captureOutputForJson(context, () => (deps.taskInfo ?? taskInfo)(context.projectRoot, taskId));
510
+ return { ok: true, group: "task", command, details: { taskId: taskId ?? null, ...captured2.output !== null ? { output: captured2.output } : {} } };
511
+ }
512
+ case "scope": {
513
+ const filesFlag = takeFlag(rest, "--files");
514
+ const taskResult = takeOption(filesFlag.rest, "--task");
515
+ requireNoExtraArgs(taskResult.rest, "rig task scope [--files] [--task <id>]");
516
+ const captured2 = await captureOutputForJson(context, () => (deps.taskScope ?? taskScope)(context.projectRoot, Boolean(filesFlag.value), normalizeTaskId(taskResult.value)));
517
+ return { ok: true, group: "task", command, details: { ...captured2.output !== null ? { output: captured2.output } : {} } };
518
+ }
519
+ case "deps": {
520
+ const taskResult = takeOption(rest, "--task");
521
+ requireNoExtraArgs(taskResult.rest, "rig task deps [--task <id>]");
522
+ const captured2 = await captureOutputForJson(context, () => (deps.taskDeps ?? taskDeps)(context.projectRoot, normalizeTaskId(taskResult.value)));
523
+ return { ok: true, group: "task", command, details: { ...captured2.output !== null ? { output: captured2.output } : {} } };
524
+ }
525
+ case "status": {
526
+ requireNoExtraArgs(rest, "rig task status");
527
+ const captured2 = await captureOutputForJson(context, () => (deps.taskStatus ?? taskStatus)(context.projectRoot));
528
+ return { ok: true, group: "task", command, details: { ...captured2.output !== null ? { output: captured2.output } : {} } };
529
+ }
530
+ case "lookup": {
531
+ const [rawId, ...extra] = rest;
532
+ requireNoExtraArgs(extra, "rig task lookup <id>");
533
+ const lookupId = requireTask(normalizeTaskId(rawId), "rig task lookup <id>");
534
+ const resolved = (deps.taskLookup ?? taskLookup)(context.projectRoot, lookupId);
535
+ printText(context, resolved);
536
+ return { ok: true, group: "task", command, details: { id: lookupId, resolved } };
537
+ }
538
+ case "record": {
539
+ const taskResult = takeOption(rest, "--task");
540
+ const [type, ...textParts] = taskResult.rest;
541
+ const text = textParts.join(" ").trim();
542
+ if (type !== "decision" && type !== "failure")
543
+ throw new CliError("rig task record requires a type: decision|failure.", 1, { hint: "rig task record <decision|failure> <text> [--task <id>]" });
544
+ if (!text)
545
+ throw new CliError("rig task record requires text.", 1, { hint: "rig task record <decision|failure> <text> [--task <id>]" });
546
+ const captured2 = await captureOutputForJson(context, () => taskRecord(context.projectRoot, type, text, normalizeTaskId(taskResult.value)));
547
+ return { ok: true, group: "task", command, details: { type, text, ...captured2.output !== null ? { output: captured2.output } : {} } };
548
+ }
549
+ default:
550
+ throw new CliError(`Unknown task command: ${command}`, 1, { hint: "Run `rig task --help`." });
551
+ }
552
+ }
553
+ export {
554
+ executeTask
555
+ };
@@ -0,0 +1,3 @@
1
+ import { type RunnerContext } from "../runner";
2
+ import type { CommandOutcome } from "@rig/runtime";
3
+ export declare function executeTest(context: RunnerContext, args: string[]): Promise<CommandOutcome>;
@@ -0,0 +1,46 @@
1
+ // @bun
2
+ // packages/cli-surface-plugin/src/runner.ts
3
+ import { EventBus } from "@rig/runtime/control-plane/runtime/events";
4
+ import { CliError as RuntimeCliError } from "@rig/runtime/control-plane/errors";
5
+ import { evaluate, loadPolicy, resolveAction } from "@rig/runtime/control-plane/runtime/guard";
6
+ import { buildBinary } from "@rig/runtime/control-plane/runtime/isolation";
7
+
8
+ class CliError extends RuntimeCliError {
9
+ hint;
10
+ constructor(message, exitCode = 1, options = {}) {
11
+ super(message, exitCode);
12
+ if (options.hint?.trim()) {
13
+ this.hint = options.hint.trim();
14
+ }
15
+ }
16
+ }
17
+ function requireNoExtraArgs(args, usage) {
18
+ if (args.length > 0) {
19
+ throw new CliError(`Unexpected arguments: ${args.join(" ")}
20
+ Usage: ${usage}`);
21
+ }
22
+ }
23
+
24
+ // packages/cli-surface-plugin/src/commands/test.ts
25
+ async function executeTest(context, args) {
26
+ const [command = "unit", ...rest] = args;
27
+ switch (command) {
28
+ case "unit":
29
+ requireNoExtraArgs(rest, "rig test unit");
30
+ await context.runCommand(["bun", "test", "tests/harness/", "--ignore", "tests/harness/e2e/**"]);
31
+ return { ok: true, group: "test", command };
32
+ case "e2e":
33
+ requireNoExtraArgs(rest, "rig test e2e");
34
+ await context.runCommand(["bun", "test", "tests/harness/e2e/"]);
35
+ return { ok: true, group: "test", command };
36
+ case "all":
37
+ requireNoExtraArgs(rest, "rig test all");
38
+ await context.runCommand(["bun", "test", "tests/harness/"]);
39
+ return { ok: true, group: "test", command };
40
+ default:
41
+ throw new CliError(`Unknown test command: ${command}`, 1, { hint: "Run `rig test --help` \u2014 commands are unit|e2e|all." });
42
+ }
43
+ }
44
+ export {
45
+ executeTest
46
+ };
@@ -0,0 +1,11 @@
1
+ import { type IssueAnalysisTriageRunResult, type RunIssueAnalysisTriageOptions } from "@rig/runtime/control-plane/github";
2
+ import type { CommandOutcome } from "@rig/runtime/control-plane/runtime/types";
3
+ import { type RunnerContext } from "../runner";
4
+ type TriageCommandDeps = {
5
+ runTriage?: (options: RunIssueAnalysisTriageOptions) => Promise<IssueAnalysisTriageRunResult>;
6
+ spinner?: <T>(label: string, work: (update: (label: string) => void) => Promise<T>, options: {
7
+ outputMode: RunnerContext["outputMode"];
8
+ }) => Promise<T>;
9
+ };
10
+ export declare function executeTriage(context: RunnerContext, args: string[], deps?: TriageCommandDeps): Promise<CommandOutcome>;
11
+ export {};