@higherdev/cli 0.14.5 → 0.15.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
@@ -47,6 +47,9 @@ workspace-map config shapes are migrated automatically when they are read.
47
47
  | `hd env ls` | List workspace environment variable names |
48
48
  | `hd env set NAME=VALUE [NAME=VALUE...]` | Set workspace environment variables |
49
49
  | `hd env rm NAME` | Remove a workspace environment variable |
50
+ | `hd host env ls` | List environment variable names on the workspace's default host |
51
+ | `hd host env set NAME=VALUE [NAME=VALUE...]` | Set host-only environment variables |
52
+ | `hd host env rm NAME` | Remove a host-only environment variable |
50
53
  | `hd logs KEY [-f]` | Show or follow run events |
51
54
  | `hd msg KEY "message" [--interrupt]` | Message a builder |
52
55
  | `hd decide` | List open decisions |
@@ -62,7 +65,7 @@ elsewhere. If the runner environment or service unit already exists, inspect the
62
65
  pass `--force` only when replacing that host configuration is intentional.
63
66
 
64
67
  `hd workspace new` uses the operator's authenticated `gh`, defaults to the repository's real default
65
- branch, bootstraps an empty repository unless `--no-bootstrap` is set, and invites `mel-ilotus` unless
68
+ branch, bootstraps an empty repository unless `--no-bootstrap` is set, and invites `mel-ilotus` as an admin unless
66
69
  `--runner-user USER` overrides it. On a terminal, missing name or repo flags start a guided wizard. If
67
70
  the repository is missing, approve private creation interactively, use `--create` to force it, or
68
71
  `--no-create` to fail. Fully flagged calls remain non-interactive for scripts and Mel.
@@ -71,6 +74,9 @@ the repository is missing, approve private creation interactively, use `--create
71
74
  They require the operator's authenticated `gh` account to have repository admin permission. Secret values are sent
72
75
  to `gh` through stdin and are never printed.
73
76
 
77
+ Use `hd host env set SUPABASE_ACCESS_TOKEN=... SUPABASE_ORG_ID=...` once to let the runner provision
78
+ Supabase for workspaces assigned to that host. Host values are never passed to builder processes.
79
+
74
80
  Inside the TUI, use `/board`, `/inbox`, `/ticket`, `/queue`, `/cancel`, `/epic new`,
75
81
  `/epic approve`, `/epics`, `/architect` (or `/plan`), `/decide`, `/agents add`, `/agents rm`, `/env`, `/settings`, `/workspace`,
76
82
  `/workspace new`, `/workspace set`, `/workspace rotate-key`, `/feed`,
package/dist/api.js CHANGED
@@ -114,6 +114,15 @@ export async function setWorkspaceEnv(name, value, config = loadConfig()) {
114
114
  export async function removeWorkspaceEnv(name, config = loadConfig()) {
115
115
  return request(config, "DELETE", `/api/w/${config.slug}/env`, { name });
116
116
  }
117
+ export async function listHostEnv(host, config = loadConfig()) {
118
+ return request(config, "GET", `/api/hosts/${encodeURIComponent(host)}/env`);
119
+ }
120
+ export async function setHostEnv(host, name, value, config = loadConfig()) {
121
+ return request(config, "PUT", `/api/hosts/${encodeURIComponent(host)}/env`, { name, value });
122
+ }
123
+ export async function removeHostEnv(host, name, config = loadConfig()) {
124
+ return request(config, "DELETE", `/api/hosts/${encodeURIComponent(host)}/env`, { name });
125
+ }
117
126
  export async function listEpics(config = loadConfig()) {
118
127
  return request(config, "GET", `/api/w/${config.slug}/epics`);
119
128
  }
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
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, createAgent, createEpic, createTicket, deleteAgent, deleteEpic, getStatus, listAgents, listEpics, listWorkspaceEnv, listTicketEvents, listTickets, listWorkspaces, postMessage, queueTicket, removeWorkspaceEnv, setPaused, setWorkspaceEnv, showTicket, updateAgent, updateCaps, } from "./api.js";
4
+ import { approveEpic, answerDecision, cancelTicket, createAgent, createEpic, createTicket, deleteAgent, deleteEpic, getStatus, listAgents, listEpics, listHostEnv, listWorkspaceEnv, listTicketEvents, 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";
@@ -412,6 +412,36 @@ export async function cmdEnv(argv, deps = {}) {
412
412
  }
413
413
  fail("usage: hd env ls | set NAME=VALUE [NAME=VALUE...] | rm NAME");
414
414
  }
415
+ async function cmdHost(argv) {
416
+ const [scope, action, ...args] = argv;
417
+ const usage = "usage: hd host env ls | set NAME=VALUE [NAME=VALUE...] | rm NAME";
418
+ if (scope !== "env")
419
+ fail(usage);
420
+ const host = (await getStatus()).workspace.default_host;
421
+ if (action === "ls") {
422
+ const { env } = await listHostEnv(host);
423
+ if (!env.length)
424
+ return console.log(c.dim(`No environment variables for host ${host}.`));
425
+ console.log(table(["NAME", "UPDATED"], env.map((row) => [row.name, row.updated_at])));
426
+ return;
427
+ }
428
+ if (action === "set" && args.length) {
429
+ for (const assignment of args) {
430
+ const at = assignment.indexOf("=");
431
+ if (at < 1)
432
+ fail(usage);
433
+ await setHostEnv(host, assignment.slice(0, at), assignment.slice(at + 1));
434
+ }
435
+ console.log(`set ${args.length} host variable${args.length === 1 ? "" : "s"} on ${host}`);
436
+ return;
437
+ }
438
+ if (action === "rm" && args.length === 1) {
439
+ await removeHostEnv(host, args[0]);
440
+ console.log(`removed ${args[0]} from ${host}`);
441
+ return;
442
+ }
443
+ fail(usage);
444
+ }
415
445
  export async function main(argv = process.argv.slice(2), deps = {}) {
416
446
  const [cmd, ...rest] = argv;
417
447
  try {
@@ -477,6 +507,10 @@ export async function main(argv = process.argv.slice(2), deps = {}) {
477
507
  await cmdEnv(rest, deps);
478
508
  return;
479
509
  }
510
+ if (cmd === "host") {
511
+ await cmdHost(rest);
512
+ return;
513
+ }
480
514
  if (cmd === "pause" || cmd === "off") {
481
515
  await setPaused(true);
482
516
  console.log(cmd === "off" ? "off" : "paused");
package/dist/out.js CHANGED
@@ -71,6 +71,7 @@ export function usage() {
71
71
  ` ${c.blue("hd agents [add | rm | set]")} manage agents`,
72
72
  ` ${c.blue("hd caps [set PROVIDER N]")} provider concurrency`,
73
73
  ` ${c.blue("hd env ls | set | rm")} workspace environment`,
74
+ ` ${c.blue("hd host env ls | set | rm")} host environment`,
74
75
  ` ${c.blue("hd logs KEY [-f]")} run events`,
75
76
  ` ${c.blue("hd msg KEY TEXT")} message a builder`,
76
77
  ` ${c.blue("hd decide [ID --answer TEXT]")} decisions`,
@@ -55,9 +55,6 @@ export async function requireAdminRepo(repo, gh = defaultGh) {
55
55
  async function repoView(repo, gh) {
56
56
  return JSON.parse(await gh(["repo", "view", repo, "--json", "defaultBranchRef,isEmpty,viewerPermission"]));
57
57
  }
58
- function canPush(permission) {
59
- return ["admin", "maintain", "write", "push"].includes(permission.toLowerCase());
60
- }
61
58
  export async function preflightWorkspace(input, gh = defaultGh) {
62
59
  try {
63
60
  await gh(["--version"]);
@@ -94,9 +91,9 @@ export async function preflightWorkspace(input, gh = defaultGh) {
94
91
  if (!/404|not found/i.test(errorMessage(error)))
95
92
  throw error;
96
93
  }
97
- const invitationPending = !canPush(permission);
94
+ const invitationPending = permission.toLowerCase() !== "admin";
98
95
  if (invitationPending) {
99
- await gh(["api", "-X", "PUT", `repos/${input.repo}/collaborators/${runnerUser}`, "-f", "permission=push"]);
96
+ await gh(["api", "-X", "PUT", `repos/${input.repo}/collaborators/${runnerUser}`, "-f", "permission=admin"]);
100
97
  }
101
98
  return { branch, invitationPending };
102
99
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@higherdev/cli",
3
- "version": "0.14.5",
3
+ "version": "0.15.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "hd": "dist/index.js"