@higherdev/cli 0.38.0 → 0.39.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 CHANGED
@@ -32,9 +32,10 @@ workspace-map config shapes are migrated automatically when they are read.
32
32
  | `hd ticket cancel KEY` | Cancel a ticket |
33
33
  | `hd epic new PATH [--title TITLE] [--draft]` | Create an approved epic, or keep it as a draft |
34
34
  | `hd epic list` | List epics and ticket progress |
35
- | `hd epic approve ID` | Open a draft epic for orchestrator decomposition |
35
+ | `hd epic approve ID` | Open a draft epic for Delivery Manager decomposition |
36
36
  | `hd epic rm ID` | Remove a draft epic |
37
- | `hd plan` | Point to the TUI `/architect` conversation |
37
+ | `hd product` (`hd plan`) | Point to the TUI Product Manager conversation |
38
+ | `hd architect` | Point to the TUI Architect design conversation |
38
39
  | `hd workspace ls` | List every workspace available to the configured key |
39
40
  | `hd workspace use SLUG` | Switch the current workspace |
40
41
  | `hd workspace new --name NAME --repo OWNER/NAME [options]` | Preflight GitHub, wire the runner, and create a paused workspace |
@@ -102,10 +103,10 @@ Use `hd host env set SUPABASE_ACCESS_TOKEN=... SUPABASE_ORG_ID=...` once to let
102
103
  Supabase for workspaces assigned to that host. Host values are never passed to builder processes.
103
104
  Use `hd host env set VERCEL_TOKEN=... VERCEL_TEAM_ID=...` to let the runner adopt or provision a linked
104
105
  Vercel project. It syncs `NEXT_PUBLIC_*`, names listed in `settings.vercel.env`, and existing Vercel-held names
105
- to production and preview. Later `hd env set` changes wake the orchestrator to update matching Vercel variables.
106
+ to production and preview. Later `hd env set` changes wake the Delivery Manager to update matching Vercel variables.
106
107
 
107
108
  Inside the TUI, use `/board`, `/inbox`, `/inbox more`, `/ticket`, `/ticket new [PATH.md]`, `/queue`, `/cancel`, `/msg`, `/logs`, `/epic new`,
108
- `/epic approve`, `/epic rm`, `/epics`, `/architect` (or `/plan`), `/decide`, `/agents add`, `/agents rm`, `/env`, `/settings`, `/workspace`,
109
+ `/epic approve`, `/epic rm`, `/epics`, `/product` (or `/plan`), `/architect`, `/decide`, `/agents add`, `/agents rm`, `/env`, `/settings`, `/workspace`,
109
110
  `/workspace new`, `/workspace set`, `/workspace rotate-key`, `/workspace grant-runner-access`, `/feed`,
110
111
  `/on`, `/off`, `/orchestrator`, `/refresh`, `/help`, or `/exit`. The display refreshes from
111
112
  the HDX API every five seconds.
@@ -2,7 +2,7 @@ import { createAgent, getStatus, listAgents } from "./api.js";
2
2
  import { promptOnStdin } from "./prompt.js";
3
3
  export const AGENT_ADD_USAGE = "usage: hd agents add [ROLE] --name NAME --provider P --model M --effort E";
4
4
  const EFFORTS = ["low", "medium", "high"];
5
- const ROLES = ["architect", "orchestrator", "reviewer", "builder"];
5
+ const ROLES = ["product", "architect", "orchestrator", "reviewer", "builder"];
6
6
  function parse(argv) {
7
7
  const opts = {};
8
8
  const rest = [];
package/dist/api.js CHANGED
@@ -4,7 +4,7 @@ export function apiErrorMessage(status, parsed, fallback) {
4
4
  const raw = parsed && typeof parsed === "object" && "error" in parsed
5
5
  && typeof parsed.error === "string"
6
6
  ? parsed.error : fallback;
7
- const duplicate = raw.match(/agents_one_enabled_(architect|orchestrator|reviewer)_idx/i)?.[1]?.toLowerCase();
7
+ const duplicate = raw.match(/agents_one_enabled_(product|architect|orchestrator|reviewer)_idx/i)?.[1]?.toLowerCase();
8
8
  if (duplicate) {
9
9
  return `hd: ${status} Only one enabled ${duplicate} is allowed per workspace. Disable the current ${duplicate} before enabling another.`;
10
10
  }
@@ -77,16 +77,16 @@ export function parseAttachArgs(argv) {
77
77
  }
78
78
  if (arg === "--to") {
79
79
  const role = argv[++at];
80
- if (role === "architect" || role === "orchestrator")
80
+ if (role === "product" || role === "architect" || role === "orchestrator")
81
81
  to = role;
82
82
  else
83
- throw new Error("--to must be architect or orchestrator.");
83
+ throw new Error("--to must be product, architect, or orchestrator.");
84
84
  continue;
85
85
  }
86
86
  rest.push(arg);
87
87
  }
88
88
  if (!rest.length || Boolean(ticketKey) === Boolean(to)) {
89
- throw new Error("usage: hd attach PATH [PATH...] --ticket KEY | --to architect|orchestrator");
89
+ throw new Error("usage: hd attach PATH [PATH...] --ticket KEY | --to product|architect|orchestrator");
90
90
  }
91
91
  if (ticketKey && !/^HD-[1-9][0-9]*$/i.test(ticketKey))
92
92
  throw new Error("--ticket must be an HD-N key.");
@@ -104,7 +104,7 @@ export function parseTuiAttach(text) {
104
104
  continue;
105
105
  }
106
106
  const role = words[++at];
107
- if (role !== "architect" && role !== "orchestrator")
107
+ if (role !== "product" && role !== "architect" && role !== "orchestrator")
108
108
  return null;
109
109
  to = role;
110
110
  }
package/dist/index.js CHANGED
@@ -261,10 +261,10 @@ async function cmdRoadmap(argv) {
261
261
  for (const line of roadmapText(data.epics))
262
262
  console.log(line);
263
263
  }
264
- async function cmdPlan(argv) {
264
+ async function cmdChat(argv, role) {
265
265
  if (argv.length)
266
- fail("usage: hd plan");
267
- console.log("Open the HDX TUI and use /architect (or /plan).");
266
+ fail(`usage: hd ${role}`);
267
+ console.log(`Open the HDX TUI and use /${role}${role === "product" ? " (or /plan)" : ""}.`);
268
268
  }
269
269
  async function cmdLogs(argv) {
270
270
  const { rest, bools } = flags(argv);
@@ -725,8 +725,12 @@ export async function main(argv = process.argv.slice(2), deps = {}) {
725
725
  await cmdRoadmap(rest);
726
726
  return;
727
727
  }
728
- if (cmd === "plan") {
729
- await cmdPlan(rest);
728
+ if (cmd === "plan" || cmd === "product") {
729
+ await cmdChat(rest, "product");
730
+ return;
731
+ }
732
+ if (cmd === "architect") {
733
+ await cmdChat(rest, "architect");
730
734
  return;
731
735
  }
732
736
  if (cmd === "logs") {
package/dist/out.js CHANGED
@@ -68,7 +68,7 @@ export function usage() {
68
68
  ` ${c.blue("hd runs | hd run cancel ID")} inspect or cancel live runs`,
69
69
  ` ${c.blue("hd epic new PATH [--draft] | list | approve | rm")} epic operations`,
70
70
  ` ${c.blue("hd roadmap [--json]")} ordered workspace roadmap`,
71
- ` ${c.blue("hd plan")} use /architect in the TUI`,
71
+ ` ${c.blue("hd product | hd architect")} open a role chat in the TUI`,
72
72
  ` ${c.blue("hd workspace ls | use | new | set | rotate-key | grant-runner-access")} workspace operations`,
73
73
  ` ${c.blue("hd agents [add | rm | set]")} manage agents`,
74
74
  ` ${c.blue("hd caps [set PROVIDER N]")} provider concurrency`,
package/dist/tui/App.js CHANGED
@@ -624,7 +624,7 @@ export function App({ initial, availableUpdate: initialUpdate = null, updateDeps
624
624
  if (mode !== "browse")
625
625
  askAgent(mode, text);
626
626
  else
627
- setNotice("Use /architect or /orchestrator before sending a message.");
627
+ setNotice("Use /product, /architect, or /orchestrator before sending a message.");
628
628
  return;
629
629
  }
630
630
  switch (action.kind) {
@@ -920,7 +920,7 @@ export function App({ initial, availableUpdate: initialUpdate = null, updateDeps
920
920
  try {
921
921
  const key = action.key ?? (view === "ticket" ? ticketKey : null);
922
922
  if (!key && !action.to && view !== "chat") {
923
- throw new Error("Choose a target: open a ticket, add HD-N, or use --to architect|orchestrator.");
923
+ throw new Error("Choose a target: open a ticket, add HD-N, or use --to product|architect|orchestrator.");
924
924
  }
925
925
  const queuesForChat = !key && !action.to;
926
926
  const { uploaded, note } = await uploadExpanded(action.paths, key ? { ticketKey: key } : {}, undefined, queuesForChat ? Math.max(0, MAX_ATTACHMENTS_PER_DROP - pendingAttachments.length) : MAX_ATTACHMENTS_PER_DROP);
package/dist/tui/Help.js CHANGED
@@ -17,8 +17,9 @@ export const COMMANDS = [
17
17
  { name: "/logs", args: "[raw] [HD-12]", help: "filter activity; raw reveals event JSON" },
18
18
  { name: "/epic", args: "new PATH [--draft] | approve ID | rm ID", help: "create, approve, or remove an epic" },
19
19
  { name: "/epics", help: "list epics and ticket progress" },
20
- { name: "/architect", help: "open a chat with the architect" },
21
- { name: "/plan", help: "alias for /architect" },
20
+ { name: "/product", help: "open a chat with the Product Manager" },
21
+ { name: "/plan", help: "one-release alias for /product" },
22
+ { name: "/architect", help: "open a technical design chat with the Architect" },
22
23
  { name: "/decide", args: "[N|ID] [answer]", help: "answer the selected or numbered decision" },
23
24
  { name: "/agents", args: "[add [ROLE] [flags] | rm ROLE|ID]", help: "view or manage named agents" },
24
25
  { name: "/env", help: "list workspace environment variable names" },
@@ -27,7 +28,7 @@ export const COMMANDS = [
27
28
  { name: "/on", help: "turn on the current workspace" },
28
29
  { name: "/off", help: "turn off the current workspace" },
29
30
  { name: "/feed", help: "what just happened" },
30
- { name: "/orchestrator", help: "open a chat with the orchestrator" },
31
+ { name: "/orchestrator", help: "open a chat with the Delivery Manager" },
31
32
  { name: "/refresh", help: "reload the board now" },
32
33
  { name: "/help", help: "this list" },
33
34
  { name: "/exit", help: "leave" },
@@ -8,7 +8,7 @@ import { wrapLines } from "./ticket-view.js";
8
8
  import { UI } from "./theme.js";
9
9
  export function roadmapLines(board, width) {
10
10
  if (!board.roadmap)
11
- return ["No roadmap yet. Talk to /architect to create one."];
11
+ return ["No roadmap yet. Talk to /product to create one."];
12
12
  const lines = ["Vision"];
13
13
  lines.push(...wrapLines(board.roadmap.vision_md, Math.max(12, width - 2)));
14
14
  lines.push("");
@@ -21,6 +21,7 @@ export function signedOutProviders(board) {
21
21
  return providers;
22
22
  }
23
23
  const roleForKind = {
24
+ product: "product",
24
25
  architect: "architect",
25
26
  build: "builder",
26
27
  followup: "builder",
@@ -29,7 +29,7 @@ export function chatAgentLabel(role, displayName) {
29
29
  const named = displayName?.trim();
30
30
  if (named)
31
31
  return named;
32
- return role === "architect" ? "Architect" : "Orchestrator";
32
+ return role === "product" ? "Product Manager" : role === "architect" ? "Architect" : "Delivery Manager";
33
33
  }
34
34
  export function formatWorkingElapsed(ms) {
35
35
  const seconds = Math.max(0, Math.floor(ms / 1000));
package/dist/tui/data.js CHANGED
@@ -144,7 +144,7 @@ export async function loadChatMessages(config, role) {
144
144
  return messages.slice().reverse();
145
145
  }
146
146
  export async function followChat(config, role, messageId, since) {
147
- const kind = role === "architect" ? "architect" : "orchestrate";
147
+ const kind = role === "orchestrator" ? "orchestrate" : role;
148
148
  const status = await getStatus(config);
149
149
  const runs = [...(status.live_runs ?? []), ...(status.recent_runs ?? [])];
150
150
  const tagged = runs.find((run) => run.message_id === messageId);
package/dist/tui/parse.js CHANGED
@@ -15,9 +15,12 @@ export function parseLine(raw) {
15
15
  case "orchestrator":
16
16
  return { kind: "mode", mode: "orchestrator" };
17
17
  case "architect":
18
+ return rest.length ? { kind: "unknown", command: "architect takes no arguments" }
19
+ : { kind: "mode", mode: "architect" };
20
+ case "product":
18
21
  case "plan":
19
22
  return rest.length ? { kind: "unknown", command: `${word.toLowerCase()} takes no arguments` }
20
- : { kind: "mode", mode: "architect" };
23
+ : { kind: "mode", mode: "product" };
21
24
  case "board":
22
25
  case "roadmap":
23
26
  case "feed":
@@ -106,7 +109,7 @@ export function parseLine(raw) {
106
109
  case "attach": {
107
110
  const parsed = parseTuiAttach(argument);
108
111
  return parsed ? { kind: "attach", paths: parsed.paths, key: parsed.ticketKey ?? null, to: parsed.to ?? null }
109
- : { kind: "unknown", command: "attach needs PATH [PATH...] and HD-N or --to architect|orchestrator" };
112
+ : { kind: "unknown", command: "attach needs PATH [PATH...] and HD-N or --to product|architect|orchestrator" };
110
113
  }
111
114
  case "logs":
112
115
  if (rest[0]?.toLowerCase() === "raw" && rest.length <= 2) {
package/dist/tui/theme.js CHANGED
@@ -40,6 +40,7 @@ export function speakerStyle(speaker) {
40
40
  case "you":
41
41
  return { borderStyle: DOTTED, borderColor: UI.cream, label: "you" };
42
42
  case "orchestrator":
43
+ case "product":
43
44
  case "architect":
44
45
  return {
45
46
  borderStyle: THIN,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@higherdev/cli",
3
- "version": "0.38.0",
3
+ "version": "0.39.0",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",