@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,979 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
// packages/cli/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 takeOption(args, option) {
|
|
18
|
-
const rest = [];
|
|
19
|
-
let value;
|
|
20
|
-
for (let index = 0;index < args.length; index += 1) {
|
|
21
|
-
const current = args[index];
|
|
22
|
-
if (current === option) {
|
|
23
|
-
const next = args[index + 1];
|
|
24
|
-
if (!next || next.startsWith("-")) {
|
|
25
|
-
throw new CliError(`Missing value for ${option}`, 1, { hint: `Provide a value after ${option}, e.g. \`${option} <value>\`.` });
|
|
26
|
-
}
|
|
27
|
-
value = next;
|
|
28
|
-
index += 1;
|
|
29
|
-
continue;
|
|
30
|
-
}
|
|
31
|
-
if (current !== undefined) {
|
|
32
|
-
rest.push(current);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
return { value, rest };
|
|
36
|
-
}
|
|
37
|
-
function requireNoExtraArgs(args, usage) {
|
|
38
|
-
if (args.length > 0) {
|
|
39
|
-
throw new CliError(`Unexpected arguments: ${args.join(" ")}
|
|
40
|
-
Usage: ${usage}`);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// packages/cli/src/commands/_cli-format.ts
|
|
45
|
-
import pc from "picocolors";
|
|
46
|
-
var dim = pc.dim;
|
|
47
|
-
var faintBar = pc.dim("\u2502");
|
|
48
|
-
var accent = pc.cyan;
|
|
49
|
-
function compactValue(value) {
|
|
50
|
-
if (value === null || value === undefined)
|
|
51
|
-
return "\u2014";
|
|
52
|
-
if (typeof value === "string")
|
|
53
|
-
return value;
|
|
54
|
-
if (typeof value === "number" || typeof value === "boolean")
|
|
55
|
-
return String(value);
|
|
56
|
-
return JSON.stringify(value);
|
|
57
|
-
}
|
|
58
|
-
function printFormattedOutput(message) {
|
|
59
|
-
console.log(message);
|
|
60
|
-
}
|
|
61
|
-
function formatStatsTable(rows) {
|
|
62
|
-
return rows.map(([label, value]) => `${faintBar} ${dim(label.padEnd(20))} ${compactValue(value)}`).join(`
|
|
63
|
-
`);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// packages/cli/src/commands/_help-catalog.ts
|
|
67
|
-
import pc2 from "picocolors";
|
|
68
|
-
var TOP_LEVEL_SECTIONS = [
|
|
69
|
-
{
|
|
70
|
-
title: "Open Rig",
|
|
71
|
-
subtitle: "normal UX \u2014 bare rig opens the bundled Rig Cockpit inside OMP",
|
|
72
|
-
commands: [
|
|
73
|
-
{ command: "rig", description: "Open Rig Cockpit with OMP collaboration substrate for the current workspace." },
|
|
74
|
-
{ command: "rig --workspace <path>", description: "Open Rig Cockpit for another workspace." },
|
|
75
|
-
{ command: "/rig", description: "Inside OMP, reopen the Rig Cockpit." },
|
|
76
|
-
{ command: "rig join <link>", description: "Join an encrypted OMP collaborative session from another operator." }
|
|
77
|
-
]
|
|
78
|
-
},
|
|
79
|
-
{
|
|
80
|
-
title: "Server",
|
|
81
|
-
subtitle: "select execution placement before reading or dispatching work",
|
|
82
|
-
commands: [
|
|
83
|
-
{ command: "Cockpit Server", description: "Select/configure local or remote execution placement and the project-root link." },
|
|
84
|
-
{ command: "Server target \u2192 Local", description: "Use local execution placement for the selected project." },
|
|
85
|
-
{ command: "Server target \u2192 Remote", description: "Use remote execution placement with the server-host project root preserved." }
|
|
86
|
-
]
|
|
87
|
-
},
|
|
88
|
-
{
|
|
89
|
-
title: "Tasks",
|
|
90
|
-
subtitle: "configured task source on the selected target feeds task detail",
|
|
91
|
-
commands: [
|
|
92
|
-
{ command: "Cockpit Tasks", description: "List tasks from the selected server target's configured task source." },
|
|
93
|
-
{ command: "Task detail", description: "Review task id, title, body, source status, labels, and issue URL before dispatch." },
|
|
94
|
-
{ command: "Task detail \u2192 Dispatch", description: "Submit the selected task run through the selected target, then attach the collaborative OMP session." },
|
|
95
|
-
{ command: "rig triage", description: "Run the configured issueAnalysis pass once; use cron/launchd/CI to schedule continuous triage." }
|
|
96
|
-
]
|
|
97
|
-
},
|
|
98
|
-
{
|
|
99
|
-
title: "Runs",
|
|
100
|
-
subtitle: "dispatched Rig runs attach through collaborative OMP sessions",
|
|
101
|
-
commands: [
|
|
102
|
-
{ command: "OMP Runs screen", description: "Open dispatched runs, collaboration links, cwd, identity, status, and inbox counts." },
|
|
103
|
-
{ command: "rig join <link>", description: "Join a shared OMP session without changing execution placement." },
|
|
104
|
-
{ command: "OMP collab guest view", description: "Watch the shared transcript live; write links can prompt the originating session." }
|
|
105
|
-
]
|
|
106
|
-
},
|
|
107
|
-
{
|
|
108
|
-
title: "Inbox + Doctor",
|
|
109
|
-
subtitle: "approvals, user prompts, and health checks live inside Rig/OMP",
|
|
110
|
-
commands: [
|
|
111
|
-
{ command: "OMP Inbox screen", description: "Review and answer pending approval/user-input workflow entries." },
|
|
112
|
-
{ command: "/rig inbox", description: "Open the inbox screen from inside OMP." },
|
|
113
|
-
{ command: "OMP Doctor screen", description: "Probe session discovery, collaboration registry, selected target, and workflow-entry health." }
|
|
114
|
-
]
|
|
115
|
-
},
|
|
116
|
-
{
|
|
117
|
-
title: "Extend",
|
|
118
|
-
subtitle: "plugins and OMP extensions shape the worker environment",
|
|
119
|
-
commands: [
|
|
120
|
-
{ command: "rig.config.ts plugins", description: "Register task sources, validators, hooks, skills, roles, and workflow metadata." },
|
|
121
|
-
{ command: "runtime.pi.packages", description: "Declare team-wide OMP/Pi extension packages for sessions and workers." }
|
|
122
|
-
]
|
|
123
|
-
}
|
|
124
|
-
];
|
|
125
|
-
var PRIMARY_GROUPS = [
|
|
126
|
-
{
|
|
127
|
-
name: "server",
|
|
128
|
-
summary: "Select and configure local vs remote execution placement.",
|
|
129
|
-
usage: ["rig server <status|list|use|add|remove> [options]"],
|
|
130
|
-
commands: [
|
|
131
|
-
{ command: "status", description: "Show the selected placement (local or remote alias) and task source.", primary: true },
|
|
132
|
-
{ command: "list", description: "List local plus configured remote endpoints; marks the selected one.", primary: true },
|
|
133
|
-
{ command: "use local|<alias>", description: "Select where runs execute \u2014 local, or a configured remote alias.", primary: true },
|
|
134
|
-
{ command: "add --alias <a> --host <h> [--port <n>] [--token <t>]", description: "Add a remote SSH endpoint (the same store run dispatch resolves).", primary: true },
|
|
135
|
-
{ command: "remove <alias>", description: "Remove a configured remote endpoint." }
|
|
136
|
-
],
|
|
137
|
-
examples: [
|
|
138
|
-
"rig server status",
|
|
139
|
-
"rig server add --alias prod --host prod.example.com --port 22",
|
|
140
|
-
"rig server use prod"
|
|
141
|
-
],
|
|
142
|
-
next: [
|
|
143
|
-
"Placement is read by run dispatch (`rig task run` / `rig run <task>`).",
|
|
144
|
-
"The same selection is available in-session on the bare `rig` board."
|
|
145
|
-
]
|
|
146
|
-
},
|
|
147
|
-
{
|
|
148
|
-
name: "task",
|
|
149
|
-
summary: "Find work, dispatch task runs, and validate task results.",
|
|
150
|
-
usage: ["rig task <list|next|show|run|ready|validate> [options]"],
|
|
151
|
-
commands: [
|
|
152
|
-
{ command: "list [--assignee <login|me|@me>] [--state open|closed]", description: "List tasks from the configured task source.", primary: true },
|
|
153
|
-
{ command: "next [filters]", description: "Render the next ready task as a selected-task card.", primary: true },
|
|
154
|
-
{ command: "show <id>|--task <id> [--raw]", description: "Show a task summary; --raw prints the full payload.", primary: true },
|
|
155
|
-
{ command: "run [#<issue>|<task-id>|--task <id>]", description: "Dispatch the task as a detached run; attach with `rig run attach <run-id>`.", primary: true },
|
|
156
|
-
{ command: "ready", description: "List task IDs that are runnable now." },
|
|
157
|
-
{ command: "validate|verify [--task <id>]", description: "Run the task's configured checks / review gates." },
|
|
158
|
-
{ command: "details --task <id>", description: "Show full task info from the configured source." },
|
|
159
|
-
{ command: "reopen [--task <id> | --all] [--reason <text>]", description: "Reopen closed task(s) in the configured source." },
|
|
160
|
-
{ command: "artifacts|artifact-dir|artifact-write", description: "Inspect or write task artifacts." },
|
|
161
|
-
{ command: "info [--task <id>]", description: "Show the active/selected task's full runtime info." },
|
|
162
|
-
{ command: "scope [--files] [--task <id>]", description: "Show the task's scope (and changed files with --files)." },
|
|
163
|
-
{ command: "deps [--task <id>]", description: "Show the task's dependency graph." },
|
|
164
|
-
{ command: "status", description: "Show project task-tracker progress." },
|
|
165
|
-
{ command: "lookup <id>", description: "Resolve a task id to its canonical record path." },
|
|
166
|
-
{ command: "record <decision|failure> <text> [--task <id>]", description: "Append a decision or failure note to the task." }
|
|
167
|
-
],
|
|
168
|
-
examples: [
|
|
169
|
-
"rig task list --assignee @me --limit 20",
|
|
170
|
-
"rig task show 123 --raw",
|
|
171
|
-
"rig task run #123"
|
|
172
|
-
],
|
|
173
|
-
next: ["The same flow is available in-session: run bare `rig`, then Cockpit Tasks \u2192 Task detail \u2192 Dispatch."]
|
|
174
|
-
},
|
|
175
|
-
{
|
|
176
|
-
name: "run",
|
|
177
|
-
summary: "Observe, attach to, and control runs over the OMP collab substrate.",
|
|
178
|
-
usage: ["rig run <list|status|start|start-serial|start-parallel|show|attach|steer|stop|resume|restart> [options]"],
|
|
179
|
-
commands: [
|
|
180
|
-
{ command: "list", description: "List discoverable runs (relay-registry + on-disk OMP run journals).", primary: true },
|
|
181
|
-
{ command: "status", description: "Render active vs recent runs from the run journals.", primary: true },
|
|
182
|
-
{ command: "start [#<issue>|<task-id>|--next|--task <id>] [--title <t>]", description: "Dispatch one task as a detached run; attach with the printed run id.", primary: true },
|
|
183
|
-
{ command: "start-parallel [--limit <n>]", description: "Dispatch all currently-ready tasks as detached runs (limited when requested).", primary: true },
|
|
184
|
-
{ command: "start-serial", description: "Dispatch the next ready task only; run again after it finishes to continue serially.", primary: true },
|
|
185
|
-
{ command: "show <id>|--run <id> [--raw]", description: "Show a run's folded journal projection; --raw prints JSON.", primary: true },
|
|
186
|
-
{ command: "attach <run-id>|--run <id>", description: "Attach to a live run's collab session (resolves the join link).", primary: true },
|
|
187
|
-
{ command: "resume [<run-id>]", description: "Re-dispatch the run's task as a fresh detached run." },
|
|
188
|
-
{ command: "steer <run-id> --message <text>", description: "Steer a live run via its journal (local runs headless; remote runs attach to steer).", primary: true },
|
|
189
|
-
{ command: "stop [<run-id>|--run <id>] [--reason <text>]", description: "Request graceful stop of a live run (local headless; remote attach to stop).", primary: true },
|
|
190
|
-
{ command: "replay <run-id>|--run <id> [--with-session]", description: "Print the run's consolidated journal timeline." },
|
|
191
|
-
{ command: "delete|cleanup", description: "Remove a finished run's live registry entry." }
|
|
192
|
-
],
|
|
193
|
-
examples: [
|
|
194
|
-
"rig run start --next",
|
|
195
|
-
"rig run start-parallel --limit 3",
|
|
196
|
-
"rig run attach <run-id>"
|
|
197
|
-
],
|
|
198
|
-
next: [
|
|
199
|
-
"Attach to steer or stop a live run: rig run attach <run-id>.",
|
|
200
|
-
"The same runs appear in-session on the bare `rig` board."
|
|
201
|
-
]
|
|
202
|
-
},
|
|
203
|
-
{
|
|
204
|
-
name: "inbox",
|
|
205
|
-
summary: "Review approval and user-input requests that block worker runs.",
|
|
206
|
-
usage: ["rig inbox <approvals|inputs|approve|respond> [options]"],
|
|
207
|
-
commands: [
|
|
208
|
-
{ command: "approvals [--run <id>] [--task <id>]", description: "List pending approval requests across runs.", primary: true },
|
|
209
|
-
{ command: "inputs [--run <id>] [--task <id>]", description: "List pending user-input requests across runs.", primary: true },
|
|
210
|
-
{ command: "approve --run <id> --request <id> --decision approve|reject", description: "Resolve an approval \u2014 delivered over collab, so attach to resolve." },
|
|
211
|
-
{ command: "respond --run <id> --request <id> --answer key=value", description: "Answer a user-input request \u2014 attach to resolve." }
|
|
212
|
-
],
|
|
213
|
-
examples: [
|
|
214
|
-
"rig inbox approvals",
|
|
215
|
-
"rig inbox inputs --run <run-id>"
|
|
216
|
-
],
|
|
217
|
-
next: ["Resolve a request by attaching to its run: rig run attach <run-id>."]
|
|
218
|
-
},
|
|
219
|
-
{
|
|
220
|
-
name: "stats",
|
|
221
|
-
summary: "Fleet metrics computed from on-disk run journals (no server required).",
|
|
222
|
-
usage: ["rig stats [show] [--since <7d|30d|ISO date>]"],
|
|
223
|
-
commands: [
|
|
224
|
-
{ command: "show [--since <window>]", description: "Totals, completion/failure/needs-attention rates, run time, steering, stalls, approvals.", primary: true }
|
|
225
|
-
],
|
|
226
|
-
examples: [
|
|
227
|
-
"rig stats --since 7d",
|
|
228
|
-
"rig stats --json"
|
|
229
|
-
],
|
|
230
|
-
next: ["Inspect outliers with `rig run list` and `rig run show <run-id>`."]
|
|
231
|
-
},
|
|
232
|
-
{
|
|
233
|
-
name: "inspect",
|
|
234
|
-
summary: "Inspect logs, artifacts, failures, graph, and diffs for a task.",
|
|
235
|
-
usage: ["rig inspect <logs|artifacts|failures|graph|audit|diff> --task <id>"],
|
|
236
|
-
commands: [
|
|
237
|
-
{ command: "logs --task <id>", description: "Latest run log for a task.", primary: true },
|
|
238
|
-
{ command: "artifacts --task <id>", description: "List the task's completion artifacts.", primary: true },
|
|
239
|
-
{ command: "diff --task <id>", description: "List files changed by a task.", primary: true },
|
|
240
|
-
{ command: "failures --task <id>", description: "Recorded failures for a task.", primary: true },
|
|
241
|
-
{ command: "graph", description: "Task dependency graph." },
|
|
242
|
-
{ command: "audit", description: "Controlled-command audit trail." }
|
|
243
|
-
],
|
|
244
|
-
examples: ["rig inspect logs --task <id>", "rig inspect diff --task <id>"],
|
|
245
|
-
next: ["Use `rig stats` for fleet-level metrics across runs."]
|
|
246
|
-
},
|
|
247
|
-
{
|
|
248
|
-
name: "repo",
|
|
249
|
-
summary: "Repository sync/baseline helpers for the Rig-managed checkout.",
|
|
250
|
-
usage: ["rig repo <sync|reset-baseline>"],
|
|
251
|
-
commands: [
|
|
252
|
-
{ command: "sync", description: "Sync project repository state.", primary: true },
|
|
253
|
-
{ command: "reset-baseline", description: "Reset the managed baseline for the repo." }
|
|
254
|
-
],
|
|
255
|
-
examples: ["rig repo sync"]
|
|
256
|
-
},
|
|
257
|
-
{
|
|
258
|
-
name: "plugin",
|
|
259
|
-
summary: "Plugin listing, validation, and plugin-contributed commands.",
|
|
260
|
-
usage: ["rig plugin <list|validate|run> [options]"],
|
|
261
|
-
commands: [
|
|
262
|
-
{ command: "list", description: "List plugins declared in rig.config.ts and their contributions.", primary: true },
|
|
263
|
-
{ command: "validate --task <id>", description: "Run plugin-contributed validators for a task.", primary: true },
|
|
264
|
-
{ command: "run <command-id> [args...]", description: "Execute a plugin-contributed CLI command (also callable as `rig <command-id>`)." }
|
|
265
|
-
],
|
|
266
|
-
examples: ["rig plugin list", "rig plugin run <command-id>"]
|
|
267
|
-
},
|
|
268
|
-
{
|
|
269
|
-
name: "init",
|
|
270
|
-
summary: "Legacy automation-only config bootstrap/repair helper; not root onboarding.",
|
|
271
|
-
usage: ["rig init [--yes] [--server local|remote] [--repo owner/repo] [--remote-url <url>]"],
|
|
272
|
-
commands: [
|
|
273
|
-
{ command: "init", description: "Legacy/fenced setup wizard for compatibility projects; not onboarding.", primary: true },
|
|
274
|
-
{ command: "init --demo", description: "Legacy/fenced offline demo project for compatibility tests.", primary: true },
|
|
275
|
-
{ command: "init --yes", description: "Legacy/fenced non-interactive setup for old automation.", primary: true },
|
|
276
|
-
{ command: "init --server remote --remote-url <url>", description: "Legacy/fenced remote server link setup.", primary: true },
|
|
277
|
-
{ command: "init --repair", description: "Legacy/fenced repair of missing private compatibility state." }
|
|
278
|
-
],
|
|
279
|
-
examples: [
|
|
280
|
-
"rig init --demo # legacy compatibility only",
|
|
281
|
-
"rig init --repair # legacy compatibility only"
|
|
282
|
-
],
|
|
283
|
-
next: ["For onboarding and normal UX, run bare `rig`, then use Cockpit Server/Tasks and dispatch from Task detail."]
|
|
284
|
-
},
|
|
285
|
-
{
|
|
286
|
-
name: "doctor",
|
|
287
|
-
summary: "Diagnostic-only compatibility checks; normal health lives in the OMP Doctor screen.",
|
|
288
|
-
usage: ["rig doctor"],
|
|
289
|
-
commands: [
|
|
290
|
-
{ command: "doctor", description: "Diagnostic/legacy-only: check compatibility setup/runtime state; not onboarding.", primary: true },
|
|
291
|
-
{ command: "check", description: "Diagnostic/legacy-only spelling for compatibility checks." }
|
|
292
|
-
],
|
|
293
|
-
examples: ["rig doctor --json # legacy diagnostic automation only"],
|
|
294
|
-
next: ["For normal UX, use the OMP Doctor screen."]
|
|
295
|
-
},
|
|
296
|
-
{
|
|
297
|
-
name: "github",
|
|
298
|
-
summary: "Legacy automation-only GitHub auth helpers for selected compatibility servers.",
|
|
299
|
-
usage: ["rig github auth <status|import-gh|token>"],
|
|
300
|
-
commands: [
|
|
301
|
-
{ command: "auth status", description: "Legacy automation-only: show GitHub auth state.", primary: true },
|
|
302
|
-
{ command: "auth import-gh", description: "Legacy automation-only: import the current `gh` token into the selected server." },
|
|
303
|
-
{ command: "auth token --token <token>", description: "Legacy automation-only: store a token on the selected server." }
|
|
304
|
-
],
|
|
305
|
-
examples: ["rig github auth status # legacy automation only"],
|
|
306
|
-
next: ["For normal UX, use bare `rig` and the OMP extension cockpit."]
|
|
307
|
-
}
|
|
308
|
-
];
|
|
309
|
-
var ADVANCED_GROUPS = [
|
|
310
|
-
{
|
|
311
|
-
name: "setup",
|
|
312
|
-
summary: "Legacy automation-only setup bootstrap/check helpers.",
|
|
313
|
-
usage: ["rig setup <bootstrap|check|preflight>"],
|
|
314
|
-
commands: [
|
|
315
|
-
{ command: "bootstrap", description: "Legacy automation-only: bootstrap local setup dependencies.", primary: true },
|
|
316
|
-
{ command: "check", description: "Legacy automation-only: check local setup state (toolchain, deps, config).", primary: true },
|
|
317
|
-
{ command: "preflight", description: "Legacy automation-only: run preflight checks before an old run.", primary: true }
|
|
318
|
-
]
|
|
319
|
-
},
|
|
320
|
-
{
|
|
321
|
-
name: "profile",
|
|
322
|
-
summary: "Runtime profile/model defaults.",
|
|
323
|
-
usage: ["rig profile <show|set>"],
|
|
324
|
-
commands: [
|
|
325
|
-
{ command: "show", description: "Show the active execution profile.", primary: true },
|
|
326
|
-
{ command: "set [--model <model>] [--runtime <runtime>] [--plugin <plugin>]", description: "Set model/runtime/plugin profile defaults.", primary: true }
|
|
327
|
-
]
|
|
328
|
-
},
|
|
329
|
-
{
|
|
330
|
-
name: "review",
|
|
331
|
-
summary: "Inspect or change completion review gate policy.",
|
|
332
|
-
usage: ["rig review <show|set>"],
|
|
333
|
-
commands: [
|
|
334
|
-
{ command: "show", description: "Show current review gate settings." },
|
|
335
|
-
{ command: "set <off|advisory|required> [--provider <provider>]", description: "Change review strictness/provider (e.g. --provider greptile)." }
|
|
336
|
-
],
|
|
337
|
-
examples: ["rig review show", "rig review set required --provider greptile"],
|
|
338
|
-
next: ["For normal workflow handoffs, use the OMP Inbox screen."]
|
|
339
|
-
},
|
|
340
|
-
{
|
|
341
|
-
name: "pi",
|
|
342
|
-
summary: "Manage Pi extension packages for this project (community extensions from npm/git).",
|
|
343
|
-
usage: ["rig pi <list|add|remove|search> [args]"],
|
|
344
|
-
commands: [
|
|
345
|
-
{ command: "list", description: "Show project and user Pi extension packages." },
|
|
346
|
-
{ command: "add <source>", description: "Add an npm/git Pi extension to .pi/settings.json (auto-installs at next session)." },
|
|
347
|
-
{ command: "remove <source>", description: "Remove an operator-added Pi extension." },
|
|
348
|
-
{ command: "search [term]", description: "Discover Pi extension packages on the npm registry." }
|
|
349
|
-
],
|
|
350
|
-
examples: ["rig pi search subagents", "rig pi add pi-subagents", "rig pi list"],
|
|
351
|
-
next: ["Config-managed extensions: declare `runtime: { pi: { packages: [...] } }` in rig.config.ts \u2014 workers pick them up automatically."]
|
|
352
|
-
},
|
|
353
|
-
{
|
|
354
|
-
name: "queue",
|
|
355
|
-
summary: "Run task queues locally.",
|
|
356
|
-
usage: ["rig queue run [--workers <n>] [--max-tasks <n>] [--action validate|verify|pipeline] [--isolation off|worktree] [--no-runtime-reuse] [--fail-fast] [--skip-project-sync]"],
|
|
357
|
-
commands: [
|
|
358
|
-
{ command: "run [--workers <n>] [--max-tasks <n>] [--action validate|verify|pipeline] [--isolation off|worktree] [--no-runtime-reuse] [--fail-fast] [--skip-project-sync]", description: "Process queue work: drain matching tasks with N workers, optional per-task action and isolation.", primary: true }
|
|
359
|
-
]
|
|
360
|
-
},
|
|
361
|
-
{
|
|
362
|
-
name: "agent",
|
|
363
|
-
summary: "Runtime agent workspace helpers.",
|
|
364
|
-
usage: ["rig agent <list|prepare|run|cleanup>"],
|
|
365
|
-
commands: [
|
|
366
|
-
{ command: "list", description: "List prepared agent runtimes.", primary: true },
|
|
367
|
-
{ command: "prepare [--id <id>] [--mode <mode>] [--task <task>]", description: "Prepare an isolated agent runtime workspace.", primary: true },
|
|
368
|
-
{ command: "run [--id <id>] [--mode <mode>] [--task <task>] [--skip-project-sync]", description: "Prepare (if needed) and run an agent in its workspace.", primary: true },
|
|
369
|
-
{ command: "cleanup [--all] [--id <id>]", description: "Remove prepared agent workspaces.", primary: true }
|
|
370
|
-
]
|
|
371
|
-
},
|
|
372
|
-
{ name: "inspector", summary: "Event stream and drift scanners.", usage: ["rig inspector <stream|scan-upstream-drift>"], commands: [{ command: "stream", description: "Stream events." }] },
|
|
373
|
-
{
|
|
374
|
-
name: "dist",
|
|
375
|
-
summary: "Build/install packaged Rig CLI.",
|
|
376
|
-
usage: ["rig dist <build|install|doctor|rebuild-agent>"],
|
|
377
|
-
commands: [
|
|
378
|
-
{ command: "build [--output-dir <dir>]", description: "Build the distributable Rig CLI.", primary: true },
|
|
379
|
-
{ command: "install [--scope <scope>] [--path <path>]", description: "Install the built CLI to a scope/path.", primary: true },
|
|
380
|
-
{ command: "doctor", description: "Diagnose the dist toolchain and install state.", primary: true },
|
|
381
|
-
{ command: "rebuild-agent", description: "Rebuild the agent runtime image, pruning stale images.", primary: true }
|
|
382
|
-
]
|
|
383
|
-
},
|
|
384
|
-
{
|
|
385
|
-
name: "workspace",
|
|
386
|
-
summary: "Workspace topology/service helpers.",
|
|
387
|
-
usage: ["rig workspace <summary|topology|remote-hosts|service-fabric>"],
|
|
388
|
-
commands: [
|
|
389
|
-
{ command: "summary", description: "Show workspace summary.", primary: true },
|
|
390
|
-
{ command: "topology", description: "List discovered workspace services.", primary: true },
|
|
391
|
-
{ command: "remote-hosts", description: "List configured remote workspace hosts.", primary: true },
|
|
392
|
-
{ command: "service-fabric <status|up|verify|down> [--service <name>]", description: "Inspect or mutate the workspace service fabric.", primary: true }
|
|
393
|
-
]
|
|
394
|
-
},
|
|
395
|
-
{
|
|
396
|
-
name: "remote",
|
|
397
|
-
summary: "Legacy automation-only remote orchestration controls.",
|
|
398
|
-
usage: ["rig remote <status|tasks|watch|pause|resume|continue|stop|refresh|add-iterations|remove-iterations|endpoint ...>"],
|
|
399
|
-
commands: [
|
|
400
|
-
{ command: "status [--remote <alias>]", description: "Legacy automation-only: show old remote orchestration state.", primary: true },
|
|
401
|
-
{ command: "tasks [--remote <alias>]", description: "Legacy automation-only: list the old remote's tracked tasks.", primary: true },
|
|
402
|
-
{ command: "watch [--remote <alias>] [--seconds <n>] [--event <type>]", description: "Legacy automation-only: stream old remote orchestration events.", primary: true },
|
|
403
|
-
{ command: "pause [--remote <alias>]", description: "Legacy automation-only: pause old remote orchestration.", primary: true },
|
|
404
|
-
{ command: "resume [--remote <alias>] [--max-workers <n>] [--max-iterations <n>] [--direct-merge]", description: "Legacy automation-only: resume old remote orchestration with optional tuning.", primary: true },
|
|
405
|
-
{ command: "continue [--remote <alias>]", description: "Legacy automation-only: continue a paused old remote.", primary: true },
|
|
406
|
-
{ command: "stop [--remote <alias>]", description: "Legacy automation-only: stop old remote orchestration.", primary: true },
|
|
407
|
-
{ command: "refresh [--remote <alias>]", description: "Legacy automation-only: refresh old remote state.", primary: true },
|
|
408
|
-
{ command: "add-iterations [--count <n>] [--remote <alias>]", description: "Legacy automation-only: grant an old remote more iterations.", primary: true },
|
|
409
|
-
{ command: "remove-iterations [--count <n>] [--remote <alias>]", description: "Legacy automation-only: reduce an old remote's iteration budget.", primary: true },
|
|
410
|
-
{ command: "endpoint list", description: "Legacy automation-only: list configured remote endpoints.", primary: true },
|
|
411
|
-
{ command: "endpoint add --alias <alias> --host <host> --port <n> [--token <token>]", description: "Legacy automation-only: register a remote endpoint.", primary: true },
|
|
412
|
-
{ command: "endpoint remove --alias <alias>", description: "Legacy automation-only: remove a remote endpoint.", primary: true },
|
|
413
|
-
{ command: "endpoint test [--alias <alias>]", description: "Legacy diagnostic-only: test connectivity to a remote endpoint.", primary: true },
|
|
414
|
-
{ command: "endpoint doctor", description: "Legacy diagnostic-only: diagnose remote endpoint configuration.", primary: true }
|
|
415
|
-
]
|
|
416
|
-
},
|
|
417
|
-
{ name: "git", summary: "Pass through to Rig git-flow helper.", usage: ["rig git <args...>"], commands: [{ command: "<args...>", description: "Advanced git flow operations." }] },
|
|
418
|
-
{ name: "harness", summary: "Pass through to runtime harness CLI.", usage: ["rig harness <args...>"], commands: [{ command: "<args...>", description: "Advanced harness operations." }] },
|
|
419
|
-
{ name: "test", summary: "Project test wrappers.", usage: ["rig test <unit|e2e|all>"], commands: [{ command: "all", description: "Run configured project tests." }] }
|
|
420
|
-
];
|
|
421
|
-
var ALL_GROUPS = [...PRIMARY_GROUPS, ...ADVANCED_GROUPS];
|
|
422
|
-
function heading(title) {
|
|
423
|
-
return pc2.bold(pc2.cyan(title));
|
|
424
|
-
}
|
|
425
|
-
function commandLine(command, description) {
|
|
426
|
-
const commandColumn = command.length >= 38 ? `${command} ` : command.padEnd(38);
|
|
427
|
-
return `${pc2.dim("\u2502")} ${pc2.bold(commandColumn)} ${description}`;
|
|
428
|
-
}
|
|
429
|
-
function renderCommandBlock(commands) {
|
|
430
|
-
return commands.map((entry) => commandLine(entry.command, entry.description)).join(`
|
|
431
|
-
`);
|
|
432
|
-
}
|
|
433
|
-
function renderGroup(group) {
|
|
434
|
-
const lines = [
|
|
435
|
-
`${heading(`rig ${group.name}`)} \u2014 ${group.summary}`,
|
|
436
|
-
"",
|
|
437
|
-
pc2.bold("Usage"),
|
|
438
|
-
...group.usage.map((line) => ` ${line}`),
|
|
439
|
-
"",
|
|
440
|
-
pc2.bold("Commands"),
|
|
441
|
-
...group.commands.map((entry) => commandLine(entry.command, entry.description))
|
|
442
|
-
];
|
|
443
|
-
if (group.examples?.length) {
|
|
444
|
-
lines.push("", pc2.bold("Examples"), ...group.examples.map((line) => ` ${pc2.dim("$")} ${line}`));
|
|
445
|
-
}
|
|
446
|
-
if (group.next?.length) {
|
|
447
|
-
lines.push("", pc2.bold("Next steps"), ...group.next.map((line) => ` ${pc2.dim("\u203A")} ${line}`));
|
|
448
|
-
}
|
|
449
|
-
if (group.advanced?.length) {
|
|
450
|
-
lines.push("", pc2.bold("Compatibility / advanced"), ...group.advanced.map((line) => ` ${pc2.dim("\u203A")} ${line}`));
|
|
451
|
-
}
|
|
452
|
-
return lines.join(`
|
|
453
|
-
`);
|
|
454
|
-
}
|
|
455
|
-
function renderTopLevelHelp() {
|
|
456
|
-
return [
|
|
457
|
-
`${heading("rig")} ${pc2.dim("\u2014 Rig Cockpit for autonomous coding agents")}`,
|
|
458
|
-
pc2.dim("The loop: bare `rig` \u2192 Cockpit \u2192 Server target \u2192 Tasks \u2192 Task detail \u2192 Dispatch/Attach; every run uses OMP collaboration as the session substrate."),
|
|
459
|
-
"",
|
|
460
|
-
...TOP_LEVEL_SECTIONS.flatMap((section) => [
|
|
461
|
-
`${pc2.bold(pc2.magenta(`\u25C7 ${section.title}`))} \u2014 ${pc2.dim(section.subtitle)}`,
|
|
462
|
-
renderCommandBlock(section.commands),
|
|
463
|
-
""
|
|
464
|
-
]),
|
|
465
|
-
pc2.dim("More: `rig help --advanced` for fenced legacy/diagnostic commands; `rig <group> --help` for per-group compatibility help; `rig --version` for the installed version."),
|
|
466
|
-
"",
|
|
467
|
-
pc2.bold("Root options"),
|
|
468
|
-
commandLine("--workspace <path>", "Open Rig Cockpit for a workspace instead of the current directory."),
|
|
469
|
-
commandLine("--json", "Compatibility flag for fenced legacy/diagnostic subcommands."),
|
|
470
|
-
commandLine("--dry-run", "Compatibility flag for fenced legacy/diagnostic subcommands.")
|
|
471
|
-
].join(`
|
|
472
|
-
`).trimEnd();
|
|
473
|
-
}
|
|
474
|
-
function renderGroupHelp(groupName) {
|
|
475
|
-
const group = ALL_GROUPS.find((candidate) => candidate.name === groupName);
|
|
476
|
-
return group ? renderGroup(group) : null;
|
|
477
|
-
}
|
|
478
|
-
function printGroupHelpDocument(groupName) {
|
|
479
|
-
console.log(renderGroupHelp(groupName) ?? renderTopLevelHelp());
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
// packages/cli/src/commands/_run-projection.ts
|
|
483
|
-
import { existsSync as existsSync2, readdirSync as readdirSync2, readFileSync as readFileSync2 } from "fs";
|
|
484
|
-
import { resolve as resolve2 } from "path";
|
|
485
|
-
import {
|
|
486
|
-
foldRunSessionEntries,
|
|
487
|
-
sessionIdFromSessionFile as sessionIdFromSessionFile2
|
|
488
|
-
} from "@rig/contracts";
|
|
489
|
-
import { listAgentRuntimes as listAgentRuntimes2 } from "@rig/runtime/control-plane/runtime/isolation";
|
|
490
|
-
|
|
491
|
-
// packages/cli/src/commands/_run-bridge.ts
|
|
492
|
-
import { existsSync, readdirSync, readFileSync } from "fs";
|
|
493
|
-
import { dirname, resolve } from "path";
|
|
494
|
-
import { CUSTOM_TYPE_FOR, sessionIdFromSessionFile } from "@rig/contracts";
|
|
495
|
-
import { createPluginHost } from "@rig/core";
|
|
496
|
-
import { loadConfig } from "@rig/core/load-config";
|
|
497
|
-
import { resolveOwnerNamespaceKey, resolveRegistryBaseUrl, resolveRegistrySecret, resolveSelectedRemote } from "@rig/runtime/control-plane/remote";
|
|
498
|
-
import { listAgentRuntimes } from "@rig/runtime/control-plane/runtime/isolation";
|
|
499
|
-
import { createRegistryClient } from "@rig/relay-registry";
|
|
500
|
-
import {
|
|
501
|
-
listActiveCollabSessions as ompListActiveCollabSessions
|
|
502
|
-
} from "@oh-my-pi/pi-coding-agent/collab/api";
|
|
503
|
-
function registrySecret(env = process.env) {
|
|
504
|
-
return resolveRegistrySecret(process.cwd(), env) ?? null;
|
|
505
|
-
}
|
|
506
|
-
function registryBaseUrl(env = process.env) {
|
|
507
|
-
return resolveRegistryBaseUrl(process.cwd(), env);
|
|
508
|
-
}
|
|
509
|
-
function collabFromRegistryEntry(entry) {
|
|
510
|
-
return {
|
|
511
|
-
sessionId: entry.roomId,
|
|
512
|
-
sessionPath: "",
|
|
513
|
-
cwd: "",
|
|
514
|
-
title: entry.title,
|
|
515
|
-
joinLink: entry.joinLink,
|
|
516
|
-
webLink: entry.webLink,
|
|
517
|
-
relayUrl: entry.relayUrl,
|
|
518
|
-
owner: entry.owner,
|
|
519
|
-
selectedRepo: entry.repo,
|
|
520
|
-
startedAt: entry.startedAt,
|
|
521
|
-
updatedAt: entry.heartbeatAt,
|
|
522
|
-
...entry.pid === undefined ? {} : { pid: entry.pid },
|
|
523
|
-
stale: entry.stale
|
|
524
|
-
};
|
|
525
|
-
}
|
|
526
|
-
function isRecord(value) {
|
|
527
|
-
return typeof value === "object" && value !== null;
|
|
528
|
-
}
|
|
529
|
-
function readLocalRunCollab(runtime) {
|
|
530
|
-
if (!runtime.sessionDir || !existsSync(runtime.sessionDir))
|
|
531
|
-
return null;
|
|
532
|
-
let files;
|
|
533
|
-
try {
|
|
534
|
-
files = readdirSync(runtime.sessionDir).filter((f) => f.endsWith(".jsonl")).sort().reverse();
|
|
535
|
-
} catch {
|
|
536
|
-
return null;
|
|
537
|
-
}
|
|
538
|
-
for (const file of files) {
|
|
539
|
-
let lines;
|
|
540
|
-
try {
|
|
541
|
-
lines = readFileSync(resolve(runtime.sessionDir, file), "utf8").split(`
|
|
542
|
-
`);
|
|
543
|
-
} catch {
|
|
544
|
-
continue;
|
|
545
|
-
}
|
|
546
|
-
let host = null;
|
|
547
|
-
for (const line of lines) {
|
|
548
|
-
if (!line.includes("collab-host-started"))
|
|
549
|
-
continue;
|
|
550
|
-
let entry;
|
|
551
|
-
try {
|
|
552
|
-
entry = JSON.parse(line);
|
|
553
|
-
} catch {
|
|
554
|
-
continue;
|
|
555
|
-
}
|
|
556
|
-
if (!isRecord(entry) || entry.customType !== CUSTOM_TYPE_FOR["timeline-entry"] || !isRecord(entry.data))
|
|
557
|
-
continue;
|
|
558
|
-
const payload = isRecord(entry.data.payload) ? entry.data.payload : entry.data;
|
|
559
|
-
if (payload.type !== "collab-host-started")
|
|
560
|
-
continue;
|
|
561
|
-
host = {
|
|
562
|
-
roomId: typeof payload.roomId === "string" ? payload.roomId : undefined,
|
|
563
|
-
joinLink: typeof payload.joinLink === "string" ? payload.joinLink : undefined,
|
|
564
|
-
webLink: typeof payload.webLink === "string" ? payload.webLink : undefined,
|
|
565
|
-
relayUrl: typeof payload.relayUrl === "string" ? payload.relayUrl : undefined,
|
|
566
|
-
at: typeof entry.data.at === "string" ? entry.data.at : undefined
|
|
567
|
-
};
|
|
568
|
-
}
|
|
569
|
-
if (!host?.joinLink)
|
|
570
|
-
continue;
|
|
571
|
-
const at = host.at ?? "";
|
|
572
|
-
const sessionId = host.roomId ?? sessionIdFromSessionFile(resolve(runtime.sessionDir, file)) ?? runtime.id;
|
|
573
|
-
return {
|
|
574
|
-
sessionId,
|
|
575
|
-
sessionPath: resolve(runtime.sessionDir, file),
|
|
576
|
-
cwd: runtime.workspaceDir,
|
|
577
|
-
joinLink: host.joinLink,
|
|
578
|
-
webLink: host.webLink ?? "",
|
|
579
|
-
relayUrl: host.relayUrl ?? "",
|
|
580
|
-
title: runtime.taskId ? `[${runtime.taskId}] Rig run ${sessionId}` : `Rig run ${sessionId}`,
|
|
581
|
-
startedAt: at,
|
|
582
|
-
updatedAt: at,
|
|
583
|
-
stale: false
|
|
584
|
-
};
|
|
585
|
-
}
|
|
586
|
-
return null;
|
|
587
|
-
}
|
|
588
|
-
async function listLocalRunCollabSessions(projectRoot) {
|
|
589
|
-
let runtimes;
|
|
590
|
-
try {
|
|
591
|
-
runtimes = await listAgentRuntimes(projectRoot);
|
|
592
|
-
} catch {
|
|
593
|
-
return [];
|
|
594
|
-
}
|
|
595
|
-
const out = [];
|
|
596
|
-
for (const runtime of runtimes) {
|
|
597
|
-
const collab = readLocalRunCollab(runtime);
|
|
598
|
-
if (collab)
|
|
599
|
-
out.push(collab);
|
|
600
|
-
}
|
|
601
|
-
return out;
|
|
602
|
-
}
|
|
603
|
-
async function listActiveRunCollab(filter) {
|
|
604
|
-
return defaultListActiveCollabSessions(filter);
|
|
605
|
-
}
|
|
606
|
-
async function defaultListActiveCollabSessions(filter) {
|
|
607
|
-
const projectRoot = process.cwd();
|
|
608
|
-
const local = await listLocalRunCollabSessions(projectRoot);
|
|
609
|
-
const namespaceKey = filter.namespaceKey ?? resolveOwnerNamespaceKey(projectRoot);
|
|
610
|
-
const secret = registrySecret();
|
|
611
|
-
const remote = namespaceKey && secret ? (await createRegistryClient({ baseUrl: registryBaseUrl(), namespaceKey, secret }).listRoomsByOwner(filter)).map(collabFromRegistryEntry) : await ompListActiveCollabSessions(filter);
|
|
612
|
-
const seen = new Set(local.map((c) => c.sessionId));
|
|
613
|
-
return [...local, ...remote.filter((c) => !seen.has(c.sessionId))];
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
// packages/cli/src/commands/_run-diagnostics.ts
|
|
617
|
-
function normalizeString(value) {
|
|
618
|
-
if (typeof value !== "string")
|
|
619
|
-
return null;
|
|
620
|
-
const normalized = value.replace(/\s+/g, " ").trim();
|
|
621
|
-
return normalized.length > 0 ? normalized : null;
|
|
622
|
-
}
|
|
623
|
-
function isGenericRunFailure(value) {
|
|
624
|
-
const text = normalizeString(value);
|
|
625
|
-
return Boolean(text && /^Task run failed \([^)]*\)$/i.test(text));
|
|
626
|
-
}
|
|
627
|
-
function appendCandidate(candidates, value) {
|
|
628
|
-
const text = normalizeString(value);
|
|
629
|
-
if (text && !candidates.includes(text))
|
|
630
|
-
candidates.push(text);
|
|
631
|
-
}
|
|
632
|
-
function categorizeUsefulRunError(lines) {
|
|
633
|
-
const taskSourceFailure = lines.find((line) => /failed to update task source/i.test(line));
|
|
634
|
-
if (taskSourceFailure)
|
|
635
|
-
return `Task source update failed: ${taskSourceFailure}`;
|
|
636
|
-
const moduleFailure = lines.find((line) => /cannot find module/i.test(line));
|
|
637
|
-
if (moduleFailure)
|
|
638
|
-
return `Runtime module resolution failed: ${moduleFailure}`;
|
|
639
|
-
const providerFailure = lines.find((line) => /no api key found|unauthorized|authentication failed|invalid api key/i.test(line));
|
|
640
|
-
if (providerFailure)
|
|
641
|
-
return `Provider authentication failed: ${providerFailure}`;
|
|
642
|
-
return null;
|
|
643
|
-
}
|
|
644
|
-
function summarizeUsefulRunError(projection) {
|
|
645
|
-
if (projection.status !== "failed")
|
|
646
|
-
return null;
|
|
647
|
-
const candidates = [];
|
|
648
|
-
for (const anomaly of projection.anomalies) {
|
|
649
|
-
appendCandidate(candidates, `Journal anomaly (${anomaly.kind}): ${anomaly.detail}`);
|
|
650
|
-
}
|
|
651
|
-
for (const phase of projection.closeoutPhases) {
|
|
652
|
-
if (phase.outcome === "failed")
|
|
653
|
-
appendCandidate(candidates, phase.detail);
|
|
654
|
-
}
|
|
655
|
-
for (const entry of projection.statusHistory) {
|
|
656
|
-
appendCandidate(candidates, entry.reason);
|
|
657
|
-
}
|
|
658
|
-
appendCandidate(candidates, projection.record.statusDetail);
|
|
659
|
-
appendCandidate(candidates, projection.record.errorText);
|
|
660
|
-
const nonGeneric = candidates.filter((candidate) => !isGenericRunFailure(candidate));
|
|
661
|
-
return categorizeUsefulRunError(nonGeneric) ?? nonGeneric.at(-1) ?? normalizeString(projection.record.errorText);
|
|
662
|
-
}
|
|
663
|
-
|
|
664
|
-
// packages/cli/src/commands/_run-projection.ts
|
|
665
|
-
var EMPTY_PROJECTION = foldRunSessionEntries([], "");
|
|
666
|
-
function stringOrNull(value) {
|
|
667
|
-
return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
|
|
668
|
-
}
|
|
669
|
-
function newestSessionFile(sessionDir) {
|
|
670
|
-
if (!sessionDir || !existsSync2(sessionDir))
|
|
671
|
-
return null;
|
|
672
|
-
try {
|
|
673
|
-
const files = readdirSync2(sessionDir).filter((file) => file.endsWith(".jsonl")).sort().reverse();
|
|
674
|
-
return files[0] ? resolve2(sessionDir, files[0]) : null;
|
|
675
|
-
} catch {
|
|
676
|
-
return null;
|
|
677
|
-
}
|
|
678
|
-
}
|
|
679
|
-
function readSessionRunEntries(sessionPath) {
|
|
680
|
-
if (!sessionPath || !existsSync2(sessionPath))
|
|
681
|
-
return [];
|
|
682
|
-
let raw;
|
|
683
|
-
try {
|
|
684
|
-
raw = readFileSync2(sessionPath, "utf8");
|
|
685
|
-
} catch {
|
|
686
|
-
return [];
|
|
687
|
-
}
|
|
688
|
-
const entries = [];
|
|
689
|
-
for (const line of raw.split(`
|
|
690
|
-
`)) {
|
|
691
|
-
if (!line.trim())
|
|
692
|
-
continue;
|
|
693
|
-
let parsed;
|
|
694
|
-
try {
|
|
695
|
-
parsed = JSON.parse(line);
|
|
696
|
-
} catch {
|
|
697
|
-
continue;
|
|
698
|
-
}
|
|
699
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
700
|
-
continue;
|
|
701
|
-
entries.push({
|
|
702
|
-
type: "type" in parsed && typeof parsed.type === "string" ? parsed.type : "",
|
|
703
|
-
..."customType" in parsed && typeof parsed.customType === "string" ? { customType: parsed.customType } : {},
|
|
704
|
-
..."data" in parsed ? { data: parsed.data } : {}
|
|
705
|
-
});
|
|
706
|
-
}
|
|
707
|
-
return entries;
|
|
708
|
-
}
|
|
709
|
-
function recordFromProjection(runId, projection, presence) {
|
|
710
|
-
const record = projection.record;
|
|
711
|
-
const status = projection.status ?? (presence.stale ? "stale" : presence.live ? "running" : "unknown");
|
|
712
|
-
const taskId = stringOrNull(record.taskId) ?? presence.fallbackTaskId ?? null;
|
|
713
|
-
const title = stringOrNull(record.title) ?? stringOrNull(presence.title) ?? (taskId ? `Run ${taskId}` : `Rig run ${runId}`);
|
|
714
|
-
return {
|
|
715
|
-
runId,
|
|
716
|
-
taskId,
|
|
717
|
-
title,
|
|
718
|
-
status,
|
|
719
|
-
source: presence.source,
|
|
720
|
-
live: presence.live,
|
|
721
|
-
stale: presence.stale,
|
|
722
|
-
startedAt: stringOrNull(record.startedAt) ?? presence.startedAt ?? null,
|
|
723
|
-
updatedAt: stringOrNull(record.updatedAt) ?? presence.updatedAt ?? projection.lastEventAt ?? null,
|
|
724
|
-
completedAt: stringOrNull(record.completedAt),
|
|
725
|
-
joinLink: presence.joinLink ?? null,
|
|
726
|
-
webLink: presence.webLink ?? null,
|
|
727
|
-
relayUrl: presence.relayUrl ?? null,
|
|
728
|
-
sessionPath: stringOrNull(record.sessionPath) ?? presence.sessionPath ?? null,
|
|
729
|
-
prUrl: stringOrNull(record.prUrl),
|
|
730
|
-
worktreePath: stringOrNull(record.worktreePath),
|
|
731
|
-
pendingApprovals: projection.pendingApprovals.length,
|
|
732
|
-
pendingInputs: projection.pendingUserInputs.length,
|
|
733
|
-
steeringCount: projection.steeringCount,
|
|
734
|
-
stallCount: projection.stallCount,
|
|
735
|
-
errorSummary: summarizeUsefulRunError(projection),
|
|
736
|
-
projection
|
|
737
|
-
};
|
|
738
|
-
}
|
|
739
|
-
function recordFromLiveCollab(collab) {
|
|
740
|
-
const runId = collab.sessionId;
|
|
741
|
-
const sessionPath = stringOrNull(collab.sessionPath);
|
|
742
|
-
const projection = sessionPath ? foldRunSessionEntries(readSessionRunEntries(sessionPath), runId) : EMPTY_PROJECTION;
|
|
743
|
-
return recordFromProjection(runId, projection, {
|
|
744
|
-
source: sessionPath ? "local" : "remote",
|
|
745
|
-
live: !collab.stale,
|
|
746
|
-
stale: Boolean(collab.stale),
|
|
747
|
-
title: collab.title,
|
|
748
|
-
joinLink: stringOrNull(collab.joinLink),
|
|
749
|
-
webLink: stringOrNull(collab.webLink),
|
|
750
|
-
relayUrl: stringOrNull(collab.relayUrl),
|
|
751
|
-
sessionPath,
|
|
752
|
-
startedAt: stringOrNull(collab.startedAt),
|
|
753
|
-
updatedAt: stringOrNull(collab.updatedAt)
|
|
754
|
-
});
|
|
755
|
-
}
|
|
756
|
-
function recordFromRuntime(runtime) {
|
|
757
|
-
const sessionPath = newestSessionFile(runtime.sessionDir ?? "");
|
|
758
|
-
if (!sessionPath)
|
|
759
|
-
return null;
|
|
760
|
-
const projection = foldRunSessionEntries(readSessionRunEntries(sessionPath), runtime.id);
|
|
761
|
-
if (projection.lastSeq === 0)
|
|
762
|
-
return null;
|
|
763
|
-
return recordFromProjection(sessionIdFromSessionFile2(sessionPath) ?? runtime.id, projection, {
|
|
764
|
-
source: "local",
|
|
765
|
-
live: false,
|
|
766
|
-
stale: false,
|
|
767
|
-
sessionPath,
|
|
768
|
-
fallbackTaskId: stringOrNull(runtime.taskId)
|
|
769
|
-
});
|
|
770
|
-
}
|
|
771
|
-
function sortByRecency(records) {
|
|
772
|
-
return [...records].sort((a, b) => {
|
|
773
|
-
const at = Date.parse(b.updatedAt ?? b.startedAt ?? "") || 0;
|
|
774
|
-
const bt = Date.parse(a.updatedAt ?? a.startedAt ?? "") || 0;
|
|
775
|
-
return at - bt;
|
|
776
|
-
});
|
|
777
|
-
}
|
|
778
|
-
async function listRunProjections(projectRoot, filter = {}) {
|
|
779
|
-
const byRunId = new Map;
|
|
780
|
-
let live = [];
|
|
781
|
-
try {
|
|
782
|
-
live = await listActiveRunCollab(filter);
|
|
783
|
-
} catch {
|
|
784
|
-
live = [];
|
|
785
|
-
}
|
|
786
|
-
for (const collab of live) {
|
|
787
|
-
const record = recordFromLiveCollab(collab);
|
|
788
|
-
byRunId.set(record.runId, record);
|
|
789
|
-
}
|
|
790
|
-
let runtimes = [];
|
|
791
|
-
try {
|
|
792
|
-
runtimes = await listAgentRuntimes2(projectRoot);
|
|
793
|
-
} catch {
|
|
794
|
-
runtimes = [];
|
|
795
|
-
}
|
|
796
|
-
for (const runtime of runtimes) {
|
|
797
|
-
const record = recordFromRuntime(runtime);
|
|
798
|
-
if (!record)
|
|
799
|
-
continue;
|
|
800
|
-
const sessionId = sessionIdFromSessionFile2(record.sessionPath);
|
|
801
|
-
const liveMatch = sessionId ? byRunId.get(sessionId) : undefined;
|
|
802
|
-
if (liveMatch) {
|
|
803
|
-
if (liveMatch.source === "remote" || !liveMatch.sessionPath) {
|
|
804
|
-
byRunId.set(liveMatch.runId, { ...liveMatch, sessionPath: record.sessionPath, source: "local" });
|
|
805
|
-
}
|
|
806
|
-
continue;
|
|
807
|
-
}
|
|
808
|
-
if (byRunId.has(runtime.id))
|
|
809
|
-
continue;
|
|
810
|
-
byRunId.set(record.runId, record);
|
|
811
|
-
}
|
|
812
|
-
return sortByRecency([...byRunId.values()]);
|
|
813
|
-
}
|
|
814
|
-
|
|
815
|
-
// packages/cli/src/commands/stats.ts
|
|
816
|
-
var DAY_MS = 24 * 60 * 60 * 1000;
|
|
817
|
-
function parseSinceOption(value, now = new Date) {
|
|
818
|
-
if (!value?.trim())
|
|
819
|
-
return null;
|
|
820
|
-
const trimmed = value.trim();
|
|
821
|
-
const relative = trimmed.match(/^(\d+)d$/i);
|
|
822
|
-
if (relative?.[1]) {
|
|
823
|
-
const days = Number.parseInt(relative[1], 10);
|
|
824
|
-
if (!Number.isFinite(days) || days <= 0) {
|
|
825
|
-
throw new CliError(`Invalid --since value: ${value}`, 2, {
|
|
826
|
-
hint: "Use an ISO date or a relative window like `7d`."
|
|
827
|
-
});
|
|
828
|
-
}
|
|
829
|
-
return new Date(now.getTime() - days * DAY_MS);
|
|
830
|
-
}
|
|
831
|
-
const parsed = Date.parse(trimmed);
|
|
832
|
-
if (!Number.isFinite(parsed)) {
|
|
833
|
-
throw new CliError(`Invalid --since value: ${value}`, 2, {
|
|
834
|
-
hint: "Use an ISO date or a relative window like `7d`."
|
|
835
|
-
});
|
|
836
|
-
}
|
|
837
|
-
return new Date(parsed);
|
|
838
|
-
}
|
|
839
|
-
function parseTimestamp(value) {
|
|
840
|
-
if (!value)
|
|
841
|
-
return null;
|
|
842
|
-
const parsed = Date.parse(value);
|
|
843
|
-
return Number.isFinite(parsed) ? parsed : null;
|
|
844
|
-
}
|
|
845
|
-
function median(values) {
|
|
846
|
-
if (values.length === 0)
|
|
847
|
-
return null;
|
|
848
|
-
const sorted = [...values].sort((left, right) => left - right);
|
|
849
|
-
const middle = Math.floor(sorted.length / 2);
|
|
850
|
-
return sorted.length % 2 === 1 ? sorted[middle] : (sorted[middle - 1] + sorted[middle]) / 2;
|
|
851
|
-
}
|
|
852
|
-
function rate(part, total) {
|
|
853
|
-
return total === 0 ? null : part / total;
|
|
854
|
-
}
|
|
855
|
-
function isNeedsAttention(run) {
|
|
856
|
-
return run.status === "needs-attention" || run.pendingApprovals + run.pendingInputs > 0 || run.stallCount > 0;
|
|
857
|
-
}
|
|
858
|
-
function completedDuration(run) {
|
|
859
|
-
if (run.status !== "completed")
|
|
860
|
-
return null;
|
|
861
|
-
const startedAt = parseTimestamp(run.startedAt);
|
|
862
|
-
const completedAt = parseTimestamp(run.completedAt);
|
|
863
|
-
if (startedAt === null || completedAt === null || completedAt < startedAt)
|
|
864
|
-
return null;
|
|
865
|
-
return completedAt - startedAt;
|
|
866
|
-
}
|
|
867
|
-
async function computeRigStats(projectRoot, options = {}) {
|
|
868
|
-
const sinceMs = options.since ? options.since.getTime() : null;
|
|
869
|
-
const allRuns = await (options.listRuns ?? listRunProjections)(projectRoot);
|
|
870
|
-
const runs = allRuns.filter((run) => {
|
|
871
|
-
if (sinceMs === null)
|
|
872
|
-
return true;
|
|
873
|
-
const startedAt = parseTimestamp(run.startedAt);
|
|
874
|
-
return startedAt !== null && startedAt >= sinceMs;
|
|
875
|
-
});
|
|
876
|
-
const statusCounts = {};
|
|
877
|
-
const completionDurations = [];
|
|
878
|
-
let completedRuns = 0;
|
|
879
|
-
let failedRuns = 0;
|
|
880
|
-
let needsAttentionRuns = 0;
|
|
881
|
-
let steeringTotal = 0;
|
|
882
|
-
let stallTotal = 0;
|
|
883
|
-
let approvalsPending = 0;
|
|
884
|
-
for (const run of runs) {
|
|
885
|
-
const status = run.status || "unknown";
|
|
886
|
-
statusCounts[status] = (statusCounts[status] ?? 0) + 1;
|
|
887
|
-
if (status === "completed")
|
|
888
|
-
completedRuns += 1;
|
|
889
|
-
if (status === "failed")
|
|
890
|
-
failedRuns += 1;
|
|
891
|
-
if (isNeedsAttention(run))
|
|
892
|
-
needsAttentionRuns += 1;
|
|
893
|
-
const duration = completedDuration(run);
|
|
894
|
-
if (duration !== null)
|
|
895
|
-
completionDurations.push(duration);
|
|
896
|
-
steeringTotal += run.steeringCount;
|
|
897
|
-
stallTotal += run.stallCount;
|
|
898
|
-
approvalsPending += run.pendingApprovals;
|
|
899
|
-
}
|
|
900
|
-
const totalRuns = runs.length;
|
|
901
|
-
return {
|
|
902
|
-
since: options.since ? options.since.toISOString() : null,
|
|
903
|
-
totalRuns,
|
|
904
|
-
statusCounts,
|
|
905
|
-
completedRuns,
|
|
906
|
-
failedRuns,
|
|
907
|
-
needsAttentionRuns,
|
|
908
|
-
completionRate: rate(completedRuns, totalRuns),
|
|
909
|
-
failureRate: rate(failedRuns, totalRuns),
|
|
910
|
-
needsAttentionRate: rate(needsAttentionRuns, totalRuns),
|
|
911
|
-
medianCompletionMs: median(completionDurations),
|
|
912
|
-
steeringTotal,
|
|
913
|
-
steeringPerRun: totalRuns === 0 ? null : steeringTotal / totalRuns,
|
|
914
|
-
stallTotal,
|
|
915
|
-
approvalsRequested: approvalsPending,
|
|
916
|
-
approvalsApproved: 0,
|
|
917
|
-
approvalsRejected: 0,
|
|
918
|
-
approvalsPending
|
|
919
|
-
};
|
|
920
|
-
}
|
|
921
|
-
function formatPercent(value) {
|
|
922
|
-
return value === null ? "\u2014" : `${Math.round(value * 100)}%`;
|
|
923
|
-
}
|
|
924
|
-
function formatDuration(ms) {
|
|
925
|
-
if (ms === null)
|
|
926
|
-
return "\u2014";
|
|
927
|
-
const seconds = Math.round(ms / 1000);
|
|
928
|
-
if (seconds < 60)
|
|
929
|
-
return `${seconds}s`;
|
|
930
|
-
const minutes = Math.round(ms / 60000);
|
|
931
|
-
if (minutes < 60)
|
|
932
|
-
return `${minutes}m`;
|
|
933
|
-
const hours = Math.floor(minutes / 60);
|
|
934
|
-
const remainder = minutes % 60;
|
|
935
|
-
return remainder === 0 ? `${hours}h` : `${hours}h ${remainder}m`;
|
|
936
|
-
}
|
|
937
|
-
function formatStatsRows(stats) {
|
|
938
|
-
return [
|
|
939
|
-
["window", stats.since ? `since ${stats.since}` : "all runs"],
|
|
940
|
-
["total runs", stats.totalRuns],
|
|
941
|
-
["completed", `${stats.completedRuns} (${formatPercent(stats.completionRate)})`],
|
|
942
|
-
["failed", `${stats.failedRuns} (${formatPercent(stats.failureRate)})`],
|
|
943
|
-
["needs attention", `${stats.needsAttentionRuns} (${formatPercent(stats.needsAttentionRate)})`],
|
|
944
|
-
["median run time", formatDuration(stats.medianCompletionMs)],
|
|
945
|
-
["steering", stats.steeringTotal],
|
|
946
|
-
["stalls", stats.stallTotal],
|
|
947
|
-
["pending approvals", stats.approvalsPending]
|
|
948
|
-
];
|
|
949
|
-
}
|
|
950
|
-
async function executeStats(context, args, deps = {}) {
|
|
951
|
-
const [first = "show", ...rest] = args;
|
|
952
|
-
const command = first.startsWith("-") ? "show" : first;
|
|
953
|
-
const commandArgs = first.startsWith("-") ? args : rest;
|
|
954
|
-
if (command === "help") {
|
|
955
|
-
printGroupHelpDocument("stats");
|
|
956
|
-
return { ok: true, group: "stats", command };
|
|
957
|
-
}
|
|
958
|
-
if (command !== "show") {
|
|
959
|
-
throw new CliError(`Unknown stats command: ${command}`, 1, {
|
|
960
|
-
hint: "Run `rig stats --help` \u2014 the default command is `show`."
|
|
961
|
-
});
|
|
962
|
-
}
|
|
963
|
-
const sinceResult = takeOption(commandArgs, "--since");
|
|
964
|
-
requireNoExtraArgs(sinceResult.rest, "rig stats [show] [--since <7d|30d|ISO date>]");
|
|
965
|
-
const details = await computeRigStats(context.projectRoot, {
|
|
966
|
-
since: parseSinceOption(sinceResult.value),
|
|
967
|
-
listRuns: deps.listRuns
|
|
968
|
-
});
|
|
969
|
-
if (context.outputMode === "text") {
|
|
970
|
-
printFormattedOutput(formatStatsTable(formatStatsRows(details)));
|
|
971
|
-
}
|
|
972
|
-
return { ok: true, group: "stats", command, details };
|
|
973
|
-
}
|
|
974
|
-
export {
|
|
975
|
-
parseSinceOption,
|
|
976
|
-
formatStatsRows,
|
|
977
|
-
executeStats,
|
|
978
|
-
computeRigStats
|
|
979
|
-
};
|