@higherdev/cli 0.15.4 → 0.17.0
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 +3 -2
- package/dist/agent-commands.js +80 -0
- package/dist/api.js +14 -3
- package/dist/index.js +90 -28
- package/dist/out.js +2 -1
- package/dist/tui/App.js +213 -56
- package/dist/tui/Dashboard.js +25 -8
- package/dist/tui/Decision.js +18 -31
- package/dist/tui/Help.js +5 -5
- package/dist/tui/Panels.js +80 -42
- package/dist/tui/TextInput.js +5 -1
- package/dist/tui/agent-rows.js +1 -1
- package/dist/tui/data.js +42 -16
- package/dist/tui/decide-nav.js +62 -0
- package/dist/tui/inbox.js +29 -0
- package/dist/tui/narrate.js +97 -0
- package/dist/tui/parse.js +13 -10
- package/dist/tui/stream.js +51 -34
- package/dist/tui/ticket-view.js +226 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -25,7 +25,7 @@ workspace-map config shapes are migrated automatically when they are read.
|
|
|
25
25
|
| `hd --help` | Show the HigherDEV banner and usage |
|
|
26
26
|
| `hd status` | Show workspace, ticket, run, and decision status |
|
|
27
27
|
| `hd ticket list` | List tickets |
|
|
28
|
-
| `hd ticket show KEY` | Show one ticket |
|
|
28
|
+
| `hd ticket show KEY [--json]` | Show one ticket (body, acceptance, timeline, messages, PR, runs, decisions) |
|
|
29
29
|
| `hd ticket new [PATH.md]` | Create a ticket from the guided form or a Markdown spec |
|
|
30
30
|
| `hd ticket new --title TITLE [--acceptance TEXT] [options]` | Create a ticket non-interactively |
|
|
31
31
|
| `hd ticket queue KEY` | Queue a complete ticket now |
|
|
@@ -54,6 +54,7 @@ workspace-map config shapes are migrated automatically when they are read.
|
|
|
54
54
|
| `hd host env rm NAME` | Remove a host-only environment variable |
|
|
55
55
|
| `hd logs KEY [-f]` | Show or follow run events |
|
|
56
56
|
| `hd msg KEY "message" [--interrupt]` | Message a builder |
|
|
57
|
+
| `hd inbox [--all] [--limit N] [--json]` | List unread inbox messages, or earlier history with `--all` |
|
|
57
58
|
| `hd decide` | List open decisions |
|
|
58
59
|
| `hd decide ID --answer TEXT` | Answer a decision |
|
|
59
60
|
| `hd on` / `hd off` | Turn the workspace on or off |
|
|
@@ -95,7 +96,7 @@ Use `hd host env set VERCEL_TOKEN=... VERCEL_TEAM_ID=...` to let the runner adop
|
|
|
95
96
|
Vercel project. It syncs `NEXT_PUBLIC_*`, names listed in `settings.vercel.env`, and existing Vercel-held names
|
|
96
97
|
to production and preview. Later `hd env set` changes wake the orchestrator to update matching Vercel variables.
|
|
97
98
|
|
|
98
|
-
Inside the TUI, use `/board`, `/inbox`, `/ticket`, `/ticket new [PATH.md]`, `/queue`, `/cancel`, `/msg`, `/logs`, `/epic new`,
|
|
99
|
+
Inside the TUI, use `/board`, `/inbox`, `/inbox more`, `/ticket`, `/ticket new [PATH.md]`, `/queue`, `/cancel`, `/msg`, `/logs`, `/epic new`,
|
|
99
100
|
`/epic approve`, `/epic rm`, `/epics`, `/architect` (or `/plan`), `/decide`, `/agents add`, `/agents rm`, `/env`, `/settings`, `/workspace`,
|
|
100
101
|
`/workspace new`, `/workspace set`, `/workspace rotate-key`, `/workspace grant-runner-access`, `/feed`,
|
|
101
102
|
`/on`, `/off`, `/orchestrator`, `/refresh`, `/help`, or `/exit`. The display refreshes from
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { createAgent, getStatus, listAgents } from "./api.js";
|
|
2
|
+
import { promptOnStdin } from "./prompt.js";
|
|
3
|
+
export const AGENT_ADD_USAGE = "usage: hd agents add [ROLE] --name NAME --provider P --model M --effort E";
|
|
4
|
+
const EFFORTS = ["low", "medium", "high"];
|
|
5
|
+
const ROLES = ["architect", "orchestrator", "reviewer", "builder"];
|
|
6
|
+
function parse(argv) {
|
|
7
|
+
const opts = {};
|
|
8
|
+
const rest = [];
|
|
9
|
+
const missingValues = [];
|
|
10
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
11
|
+
const arg = argv[index];
|
|
12
|
+
if (!arg.startsWith("--")) {
|
|
13
|
+
rest.push(arg);
|
|
14
|
+
continue;
|
|
15
|
+
}
|
|
16
|
+
const name = arg.slice(2);
|
|
17
|
+
const value = argv[index + 1];
|
|
18
|
+
if (!value || value.startsWith("--")) {
|
|
19
|
+
missingValues.push(name);
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
opts[name] = value;
|
|
23
|
+
index += 1;
|
|
24
|
+
}
|
|
25
|
+
return { opts, rest, missingValues };
|
|
26
|
+
}
|
|
27
|
+
export function nextBuilderName(agents) {
|
|
28
|
+
return `Builder ${agents.filter((agent) => agent.role === "builder").length + 1}`;
|
|
29
|
+
}
|
|
30
|
+
export function availableProvider(capabilities, requested) {
|
|
31
|
+
const capability = capabilities.find((item) => item.provider === requested);
|
|
32
|
+
if (!capability?.available)
|
|
33
|
+
throw new Error(capability?.reason ?? `Unsupported provider ${requested}.`);
|
|
34
|
+
return capability;
|
|
35
|
+
}
|
|
36
|
+
function choose(answer, choices) {
|
|
37
|
+
if (!answer)
|
|
38
|
+
return choices[0];
|
|
39
|
+
return /^\d+$/.test(answer) ? choices[Number(answer) - 1] : answer;
|
|
40
|
+
}
|
|
41
|
+
export async function agentAdd(argv, deps = {}) {
|
|
42
|
+
const { opts, rest, missingValues } = parse(argv);
|
|
43
|
+
if (missingValues.length || rest.length > 1 || Object.keys(opts).some((key) => !["name", "provider", "model", "effort"].includes(key)))
|
|
44
|
+
throw new Error(AGENT_ADD_USAGE);
|
|
45
|
+
const role = rest[0] ?? "builder";
|
|
46
|
+
if (!ROLES.includes(role))
|
|
47
|
+
throw new Error(AGENT_ADD_USAGE);
|
|
48
|
+
const interactive = deps.isTTY ?? Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
49
|
+
const needsForm = ["name", "provider", "model", "effort"].some((field) => !opts[field]);
|
|
50
|
+
if (needsForm && !interactive)
|
|
51
|
+
throw new Error(AGENT_ADD_USAGE);
|
|
52
|
+
const [{ agents }, status] = await Promise.all([
|
|
53
|
+
(deps.listAgents ?? listAgents)(deps.config), (deps.getStatus ?? getStatus)(deps.config),
|
|
54
|
+
]);
|
|
55
|
+
const prompt = deps.prompt ?? promptOnStdin;
|
|
56
|
+
const defaultName = nextBuilderName(agents);
|
|
57
|
+
const name = opts.name?.trim() || (await prompt(`Name [${defaultName}]: `)).trim() || defaultName;
|
|
58
|
+
const capabilities = status.workspace.provider_capabilities ?? [];
|
|
59
|
+
if (opts.provider?.trim())
|
|
60
|
+
availableProvider(capabilities, opts.provider.trim());
|
|
61
|
+
const providers = capabilities.filter((item) => item.available).map((item) => item.provider);
|
|
62
|
+
if (!providers.length && !opts.provider) {
|
|
63
|
+
throw new Error(`No providers are available on runner host ${status.workspace.default_host}.`);
|
|
64
|
+
}
|
|
65
|
+
const providerAnswer = opts.provider?.trim() || (await prompt(`Provider (${providers.map((item, index) => `${index + 1}=${item}`).join(", ")}) [${providers[0]}]: `)).trim();
|
|
66
|
+
const provider = choose(providerAnswer, providers);
|
|
67
|
+
if (!provider)
|
|
68
|
+
throw new Error("Provider is required.");
|
|
69
|
+
availableProvider(capabilities, provider);
|
|
70
|
+
const model = opts.model?.trim() || (await prompt("Model: ")).trim();
|
|
71
|
+
if (!model)
|
|
72
|
+
throw new Error("Model is required.");
|
|
73
|
+
const effortAnswer = opts.effort?.trim() || (await prompt("Effort (1=low, 2=medium, 3=high) [high]: ")).trim();
|
|
74
|
+
const effort = choose(effortAnswer || "high", [...EFFORTS]);
|
|
75
|
+
if (!effort || !EFFORTS.includes(effort)) {
|
|
76
|
+
throw new Error(`Choose effort from: ${EFFORTS.join(", ")}.`);
|
|
77
|
+
}
|
|
78
|
+
return (deps.createAgent ?? createAgent)({ role, provider, model, effort,
|
|
79
|
+
display_name: name }, deps.config);
|
|
80
|
+
}
|
package/dist/api.js
CHANGED
|
@@ -58,14 +58,19 @@ export async function queueTicket(key, config = loadConfig()) {
|
|
|
58
58
|
export async function cancelTicket(key, config = loadConfig()) {
|
|
59
59
|
return request(config, "POST", `/api/w/${config.slug}/tickets/${encodeURIComponent(key)}/cancel`);
|
|
60
60
|
}
|
|
61
|
-
export async function
|
|
61
|
+
export async function listTicketRunEvents(key, afterAt, afterId, config = loadConfig()) {
|
|
62
62
|
const query = new URLSearchParams();
|
|
63
63
|
if (afterAt)
|
|
64
64
|
query.set("after_at", afterAt);
|
|
65
65
|
if (afterId)
|
|
66
66
|
query.set("after_id", afterId);
|
|
67
|
-
const suffix = query.size ?
|
|
68
|
-
|
|
67
|
+
const suffix = query.size ? `&${query.toString()}` : "";
|
|
68
|
+
const result = await request(config, "GET", `/api/w/${config.slug}/tickets/${encodeURIComponent(key)}/events?stream=1${suffix}`);
|
|
69
|
+
const runs = new Map((result.runs ?? []).map((run) => [run.id, run]));
|
|
70
|
+
return { ...result, events: result.events.map((event) => ({ ...event, run: runs.get(event.run_id) })) };
|
|
71
|
+
}
|
|
72
|
+
export async function listTicketStory(key, config = loadConfig()) {
|
|
73
|
+
return request(config, "GET", `/api/w/${config.slug}/tickets/${encodeURIComponent(key)}/events`);
|
|
69
74
|
}
|
|
70
75
|
export async function postMessage(fields, config = loadConfig()) {
|
|
71
76
|
return request(config, "POST", `/api/w/${config.slug}/messages`, fields);
|
|
@@ -143,10 +148,16 @@ export async function listMessages(options = {}, config = loadConfig()) {
|
|
|
143
148
|
query.set("since", options.since);
|
|
144
149
|
if (options.limit)
|
|
145
150
|
query.set("limit", String(options.limit));
|
|
151
|
+
if (options.offset)
|
|
152
|
+
query.set("offset", String(options.offset));
|
|
146
153
|
if (options.toRoles?.length)
|
|
147
154
|
query.set("to_role", options.toRoles.join(","));
|
|
148
155
|
if (options.undelivered)
|
|
149
156
|
query.set("undelivered", "true");
|
|
157
|
+
if (options.delivered)
|
|
158
|
+
query.set("delivered", "true");
|
|
159
|
+
if (options.order)
|
|
160
|
+
query.set("order", options.order);
|
|
150
161
|
const suffix = query.size ? `?${query.toString()}` : "";
|
|
151
162
|
return request(config, "GET", `/api/w/${config.slug}/messages${suffix}`);
|
|
152
163
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { realpathSync } from "node:fs";
|
|
3
3
|
import { pathToFileURL } from "node:url";
|
|
4
|
-
import { approveEpic, answerDecision, cancelTicket,
|
|
4
|
+
import { approveEpic, answerDecision, cancelTicket, createEpic, deleteAgent, deleteEpic, getStatus, getWorkspace, listAgents, listEpics, listHostEnv, listMessages, listWorkspaceEnv, listTicketRunEvents, listTickets, listWorkspaces, postMessage, queueTicket, removeWorkspaceEnv, removeHostEnv, setPaused, setWorkspaceEnv, setHostEnv, showTicket, updateAgent, updateCaps, } from "./api.js";
|
|
5
5
|
import { initHost, parseHostFlags } from "./host.js";
|
|
6
6
|
import { login, parseLoginFlags } from "./login.js";
|
|
7
7
|
import { loadConfig } from "./config.js";
|
|
8
8
|
import { epicProgressRows, readEpicSpec } from "./epics.js";
|
|
9
9
|
import { banner, c, statusChip, table, truncate, usage } from "./out.js";
|
|
10
10
|
import { ticketNew } from "./ticket-commands.js";
|
|
11
|
+
import { ticketViewLines } from "./tui/ticket-view.js";
|
|
12
|
+
import { agentAdd, AGENT_ADD_USAGE } from "./agent-commands.js";
|
|
11
13
|
import { WORKSPACE_USAGE, workspaceGrantRunnerAccess, workspaceNew, workspaceRotateKey, workspaceSet, workspaceUse } from "./workspace-commands.js";
|
|
12
14
|
import { defaultGh, hasWriteRepoPermission, HDX_RUNNER_GH_USER, requireAdminRepo, runnerRepoPermission } from "./workspace-preflight.js";
|
|
13
15
|
function fail(message) {
|
|
@@ -53,13 +55,19 @@ function printTickets(tickets) {
|
|
|
53
55
|
}
|
|
54
56
|
console.log(table(["KEY", "STATUS", "PROVIDER", "TITLE", "WHY"], tickets.map((ticket) => [
|
|
55
57
|
c.bold(ticket.key), statusChip(ticket.status), ticket.provider ?? c.dim("-"),
|
|
56
|
-
truncate(ticket.title, 48), ticket.
|
|
58
|
+
truncate(ticket.title, 48), ticket.latest_headline ? c.yellow(truncate(ticket.latest_headline, 40))
|
|
59
|
+
: ticket.stuck_reason ? c.yellow(truncate(ticket.stuck_reason, 40)) : "",
|
|
57
60
|
])));
|
|
58
61
|
}
|
|
59
62
|
async function cmdStatus() {
|
|
60
63
|
const data = await getStatus();
|
|
61
64
|
const state = data.workspace.paused ? c.yellow("off") : c.green("on");
|
|
62
65
|
console.log(`${c.bold(data.workspace.name)} ${c.dim(data.workspace.repo)} ${state}\n`);
|
|
66
|
+
const waiting = [...new Set(data.tickets.map((ticket) => ticket.stuck_reason
|
|
67
|
+
?.match(/^Waiting on (\w+) until (\d{1,2}:\d{2})\.$/)).filter(Boolean)
|
|
68
|
+
.map((match) => `${match?.[1]} waiting until ${match?.[2]}`))];
|
|
69
|
+
if (waiting.length)
|
|
70
|
+
console.log(`${c.bold("Providers")} ${waiting.map((line) => c.yellow(line)).join(", ")}\n`);
|
|
63
71
|
printTickets(data.tickets);
|
|
64
72
|
if (data.live_runs.length > 0) {
|
|
65
73
|
console.log(`\n${c.bold("Live runs")}`);
|
|
@@ -79,23 +87,31 @@ async function cmdTicket(argv, deps = {}) {
|
|
|
79
87
|
return;
|
|
80
88
|
}
|
|
81
89
|
if (action === "show") {
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
if (
|
|
88
|
-
console.log(
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
90
|
+
const parsed = flags(rest);
|
|
91
|
+
const key = parsed.rest[0];
|
|
92
|
+
if (!key || parsed.rest.length !== 1)
|
|
93
|
+
fail("usage: hd ticket show KEY [--json]");
|
|
94
|
+
const data = await showTicket(key.toUpperCase());
|
|
95
|
+
if (parsed.bools.has("json")) {
|
|
96
|
+
console.log(JSON.stringify(data));
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const { ticket, pr, events, runs, messages, decisions } = data;
|
|
100
|
+
const width = process.stdout.columns && process.stdout.columns > 0 ? process.stdout.columns : 80;
|
|
101
|
+
for (const line of ticketViewLines({
|
|
102
|
+
...ticket,
|
|
103
|
+
stuck: ticket.stuck_reason,
|
|
104
|
+
pr,
|
|
105
|
+
timeline: events,
|
|
106
|
+
messages,
|
|
107
|
+
runs: runs.map((run) => ({
|
|
108
|
+
id: run.id, kind: run.kind, provider: run.provider, status: run.status,
|
|
109
|
+
summary: run.summary, elapsed_ms: run.elapsed_ms,
|
|
110
|
+
})),
|
|
111
|
+
decisions,
|
|
112
|
+
}, width)) {
|
|
113
|
+
console.log(line.text);
|
|
114
|
+
}
|
|
99
115
|
return;
|
|
100
116
|
}
|
|
101
117
|
if (action === "new") {
|
|
@@ -176,7 +192,7 @@ async function cmdLogs(argv) {
|
|
|
176
192
|
let afterId;
|
|
177
193
|
const follow = bools.has("follow");
|
|
178
194
|
async function tick() {
|
|
179
|
-
const { events } = await
|
|
195
|
+
const { events } = await listTicketRunEvents(key, afterAt, afterId);
|
|
180
196
|
let printed = false;
|
|
181
197
|
for (const event of events) {
|
|
182
198
|
if (seen.has(event.id))
|
|
@@ -209,6 +225,36 @@ async function cmdMsg(argv) {
|
|
|
209
225
|
});
|
|
210
226
|
console.log(`sent ${message.id}`);
|
|
211
227
|
}
|
|
228
|
+
async function cmdInbox(argv) {
|
|
229
|
+
const { rest, opts, bools } = flags(argv);
|
|
230
|
+
if (rest.length || (bools.has("limit") && !opts.limit))
|
|
231
|
+
fail("usage: hd inbox [--all] [--limit N] [--json]");
|
|
232
|
+
const all = bools.has("all");
|
|
233
|
+
const json = bools.has("json");
|
|
234
|
+
const limit = opts.limit ? Number(opts.limit) : 50;
|
|
235
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > 500)
|
|
236
|
+
fail("usage: hd inbox [--all] [--limit N] [--json]");
|
|
237
|
+
const { messages } = await listMessages({
|
|
238
|
+
toRoles: ["human", "all"],
|
|
239
|
+
limit,
|
|
240
|
+
...(all ? { order: "desc" } : { undelivered: true }),
|
|
241
|
+
});
|
|
242
|
+
if (json) {
|
|
243
|
+
console.log(JSON.stringify({ messages }));
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
if (!messages.length) {
|
|
247
|
+
console.log(all ? "No messages." : "No unread messages.");
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
for (const message of messages) {
|
|
251
|
+
const sender = message.from_name?.trim() || message.from_role;
|
|
252
|
+
const ticket = message.ticket_key?.trim();
|
|
253
|
+
console.log([message.created_at, sender, ticket].filter(Boolean).join(" "));
|
|
254
|
+
console.log(message.body_md);
|
|
255
|
+
console.log("");
|
|
256
|
+
}
|
|
257
|
+
}
|
|
212
258
|
async function cmdDecide(argv) {
|
|
213
259
|
const { rest, opts } = flags(argv);
|
|
214
260
|
if (rest.length === 0) {
|
|
@@ -293,7 +339,7 @@ function selectAgent(agents, target, provider) {
|
|
|
293
339
|
fail(`No unambiguous agent ${target}${provider ? ` for provider ${provider}` : ""}.`);
|
|
294
340
|
return selected;
|
|
295
341
|
}
|
|
296
|
-
async function cmdAgents(argv) {
|
|
342
|
+
async function cmdAgents(argv, deps = {}) {
|
|
297
343
|
const [action, ...rest] = argv;
|
|
298
344
|
if (!action) {
|
|
299
345
|
const { agents } = await listAgents();
|
|
@@ -307,14 +353,11 @@ async function cmdAgents(argv) {
|
|
|
307
353
|
])));
|
|
308
354
|
return;
|
|
309
355
|
}
|
|
310
|
-
const agentUsage =
|
|
356
|
+
const agentUsage = `${AGENT_ADD_USAGE} | hd agents rm ROLE|ID | hd agents set ROLE|ID [flags]`;
|
|
311
357
|
const { rest: args, opts, bools } = flags(rest);
|
|
312
358
|
const target = args[0];
|
|
313
359
|
if (action === "add") {
|
|
314
|
-
|
|
315
|
-
fail(agentUsage);
|
|
316
|
-
const { agent } = await createAgent({ role: target, provider: opts.provider, model: opts.model,
|
|
317
|
-
effort: opts.effort, display_name: opts.name ?? opts.provider });
|
|
360
|
+
const { agent } = await agentAdd(rest, deps);
|
|
318
361
|
console.log(`${agent.id} ${agent.display_name} ${agent.role} ${agent.provider}`);
|
|
319
362
|
return;
|
|
320
363
|
}
|
|
@@ -339,11 +382,26 @@ async function cmdAgents(argv) {
|
|
|
339
382
|
const { agent } = await updateAgent(current.id, fields);
|
|
340
383
|
console.log(`${agent.display_name} ${agent.role} ${agent.provider} ${agent.model} ${agent.enabled ? "on" : "off"}`);
|
|
341
384
|
}
|
|
385
|
+
export function mailerCapsRow(auth) {
|
|
386
|
+
if (auth === "smtp")
|
|
387
|
+
return "mailer: custom SMTP";
|
|
388
|
+
if (auth === "built-in" || auth === "configured")
|
|
389
|
+
return "mailer: built-in (2/h)";
|
|
390
|
+
return null;
|
|
391
|
+
}
|
|
392
|
+
export function previewCapsRow(preview) {
|
|
393
|
+
return `preview: ${preview === "bypass" ? "bypass" : "protected"}`;
|
|
394
|
+
}
|
|
342
395
|
async function cmdCaps(argv) {
|
|
343
396
|
const [action, provider, raw, ...extra] = argv;
|
|
344
397
|
if (!action) {
|
|
345
|
-
const
|
|
398
|
+
const [status, detail] = await Promise.all([getStatus(), getWorkspace()]);
|
|
399
|
+
const caps = status.workspace.provider_caps ?? {};
|
|
346
400
|
console.log(table(["PROVIDER", "CAP"], Object.entries(caps).sort().map(([name, cap]) => [name, String(cap)])));
|
|
401
|
+
const mailer = mailerCapsRow(detail.workspace.settings?.infra?.auth);
|
|
402
|
+
if (mailer)
|
|
403
|
+
console.log(mailer);
|
|
404
|
+
console.log(previewCapsRow(detail.workspace.settings?.infra?.vercel_preview));
|
|
347
405
|
return;
|
|
348
406
|
}
|
|
349
407
|
const cap = Number(raw);
|
|
@@ -490,6 +548,10 @@ export async function main(argv = process.argv.slice(2), deps = {}) {
|
|
|
490
548
|
await cmdMsg(rest);
|
|
491
549
|
return;
|
|
492
550
|
}
|
|
551
|
+
if (cmd === "inbox") {
|
|
552
|
+
await cmdInbox(rest);
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
493
555
|
if (cmd === "decide") {
|
|
494
556
|
await cmdDecide(rest);
|
|
495
557
|
return;
|
|
@@ -499,7 +561,7 @@ export async function main(argv = process.argv.slice(2), deps = {}) {
|
|
|
499
561
|
return;
|
|
500
562
|
}
|
|
501
563
|
if (cmd === "agents") {
|
|
502
|
-
await cmdAgents(rest);
|
|
564
|
+
await cmdAgents(rest, deps);
|
|
503
565
|
return;
|
|
504
566
|
}
|
|
505
567
|
if (cmd === "caps") {
|
package/dist/out.js
CHANGED
|
@@ -64,7 +64,7 @@ export function usage() {
|
|
|
64
64
|
return [
|
|
65
65
|
c.bold("Usage"),
|
|
66
66
|
` ${c.blue("hd status")} workspace overview`,
|
|
67
|
-
` ${c.blue("hd ticket list | show | new [PATH] | queue | cancel")} ticket operations`,
|
|
67
|
+
` ${c.blue("hd ticket list | show KEY [--json] | new [PATH] | queue | cancel")} ticket operations`,
|
|
68
68
|
` ${c.blue("hd epic new PATH | list | approve | rm")} epic operations`,
|
|
69
69
|
` ${c.blue("hd plan")} use /architect in the TUI`,
|
|
70
70
|
` ${c.blue("hd workspace ls | use | new | set | rotate-key | grant-runner-access")} workspace operations`,
|
|
@@ -74,6 +74,7 @@ export function usage() {
|
|
|
74
74
|
` ${c.blue("hd host env ls | set | rm")} host environment`,
|
|
75
75
|
` ${c.blue("hd logs KEY [-f]")} run events`,
|
|
76
76
|
` ${c.blue("hd msg KEY TEXT")} message a builder`,
|
|
77
|
+
` ${c.blue("hd inbox [--all] [--limit N] [--json]")} inbox messages`,
|
|
77
78
|
` ${c.blue("hd decide [ID --answer TEXT]")} decisions`,
|
|
78
79
|
` ${c.blue("hd on | hd off")} workspace switch`,
|
|
79
80
|
` ${c.blue("hd login --url URL --api-key KEY")} client setup`,
|