@h1veframework/cli 0.13.0 → 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.
Files changed (4) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +81 -81
  3. package/dist/index.js +70 -23
  4. package/package.json +1 -1
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 H1VE Framework
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 H1VE Framework
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,81 +1,81 @@
1
- # @h1veframework/cli · `h1ve`
2
-
3
- **The command-line companion for [H1VE](https://h1ve.org) — the governance & memory layer for teams building with AI.**
4
-
5
- Your team ships with AI (Claude Code, Cursor, Copilot). As the codebase grows, the AI and your teammates start
6
- **losing context and drifting from decisions you already made**. H1VE keeps every feature aligned — a shared,
7
- **eternal project memory** plus an **anti-drift engine** that checks each change against what's been decided.
8
- `h1ve` drives that workflow straight from your terminal.
9
-
10
- Part of the H1VE toolchain, alongside the **[MCP server](https://www.npmjs.com/package/@h1veframework/mcp)** for
11
- Claude Code / Cursor.
12
-
13
- → **[h1ve.org](https://h1ve.org)** · **[app.h1ve.org](https://app.h1ve.org)**
14
-
15
- ## Quickstart (zero paste)
16
-
17
- ```bash
18
- npm i -g @h1veframework/cli
19
- h1ve login # opens your browser → you click Authorize → done
20
- h1ve status # state of the current branch's feature
21
- ```
22
-
23
- `h1ve login` stores the credential locally (`~/.config/h1ve/credentials.json`, `600`) — the MCP server reads the
24
- same one, so **one login sets up both**. The project **auto-resolves from your git remote**, so there's nothing
25
- to paste and no `H1VE_PROJECT_ID` to set. `h1ve logout` removes it.
26
-
27
- > The legacy `nf` command still works as an alias — every `h1ve <cmd>` below can be run as `nf <cmd>`.
28
-
29
- > `h1ve health` saying "no snapshots yet" is **success** (you're connected; the project just has no metrics yet).
30
-
31
- ## Commands
32
-
33
- | Command | What it does |
34
- |---|---|
35
- | `h1ve login` / `h1ve logout` | Authorize in the browser and store the credential locally / remove it |
36
- | `h1ve status` | State of the current branch's feature (stage, days active, blockers, sign-offs) |
37
- | `h1ve start [<#\|id>] [--slug <s>]` | Start an assigned feature: create the `feat/{you}/{slug}` branch and record the slug |
38
- | `h1ve spec` | Print the feature's spec (markdown) |
39
- | `h1ve move <stage> [--note]` | Move the feature to another stage |
40
- | `h1ve done [--from <file>] [--no-move]` | Submit the AI declaration (JSON) and move `dev → pr` |
41
- | `h1ve blocker "<desc>"` | Open a blocker on the feature (you become its owner) |
42
- | `h1ve health` | Latest technical-health snapshots for the project |
43
- | `h1ve connect --kind <k> --label <l> --env KEY=VAL` | Write a credential to your **local** `.env.local` and register the inventory (never sent to the server) |
44
- | `h1ve serve [--port 7391]` | Run the local agent (`127.0.0.1`) so the dashboard can apply credentials from the browser |
45
-
46
- Flags: `--json` (raw output for scripts) · `--project <name\|id>` (if you belong to more than one project) · `-h`.
47
-
48
- ## Example
49
-
50
- ```bash
51
- h1ve start # start your assigned feature (creates the branch)
52
- # ... work: git, code, commits ...
53
- h1ve status # check state anytime
54
- h1ve blocker "waiting on the Neon credential" # blocked? open a blocker
55
- h1ve done --from ai-declaration.json # submit the AI declaration + move dev → pr
56
- ```
57
-
58
- ## CI / headless (env vars)
59
-
60
- No browser? Configure by env (takes **precedence** over `h1ve login`):
61
-
62
- ```bash
63
- export H1VE_API_URL="https://app.h1ve.org" # optional (this is the default)
64
- export H1VE_API_KEY="nf_pat_..." # a PAT from app.h1ve.org/api-tokens
65
- # export H1VE_PROJECT_ID="..." # OPTIONAL — the CLI resolves the project from the repo
66
- ```
67
-
68
- ## Troubleshooting
69
-
70
- | Symptom | Fix |
71
- |---|---|
72
- | `h1ve: command not found` | Node missing or wrong terminal. Check `node --version`. On Windows, reopen the shell or use the VS Code terminal. |
73
- | `404` on install | npm propagation right after a publish — wait a few minutes. |
74
- | `NO_PROJECT` | You belong to more than one project — pass `--project <name\|id>`. |
75
- | `401` / `403` | Wrong/missing token. Make sure `H1VE_API_KEY` is a PAT (`nf_pat_…`). `403 SERVICE_CANNOT_WRITE` = a read-only service key used on a write → use a PAT. |
76
-
77
- Requires **Node.js 18.18+**. The legacy `nf` command and env names `NEXUS_FLOW_API_URL` / `NEXUS_FLOW_API_KEY` are still accepted.
78
-
79
- ---
80
-
81
- MIT · built with H1VE, by [H1VE](https://h1ve.org) 🐝
1
+ # @h1veframework/cli · `h1ve`
2
+
3
+ **The command-line companion for [H1VE](https://h1ve.org) — the governance & memory layer for teams building with AI.**
4
+
5
+ Your team ships with AI (Claude Code, Cursor, Copilot). As the codebase grows, the AI and your teammates start
6
+ **losing context and drifting from decisions you already made**. H1VE keeps every feature aligned — a shared,
7
+ **eternal project memory** plus an **anti-drift engine** that checks each change against what's been decided.
8
+ `h1ve` drives that workflow straight from your terminal.
9
+
10
+ Part of the H1VE toolchain, alongside the **[MCP server](https://www.npmjs.com/package/@h1veframework/mcp)** for
11
+ Claude Code / Cursor.
12
+
13
+ → **[h1ve.org](https://h1ve.org)** · **[app.h1ve.org](https://app.h1ve.org)**
14
+
15
+ ## Quickstart (zero paste)
16
+
17
+ ```bash
18
+ npm i -g @h1veframework/cli
19
+ h1ve login # opens your browser → you click Authorize → done
20
+ h1ve status # state of the current branch's feature
21
+ ```
22
+
23
+ `h1ve login` stores the credential locally (`~/.config/h1ve/credentials.json`, `600`) — the MCP server reads the
24
+ same one, so **one login sets up both**. The project **auto-resolves from your git remote**, so there's nothing
25
+ to paste and no `H1VE_PROJECT_ID` to set. `h1ve logout` removes it.
26
+
27
+ > The legacy `nf` command still works as an alias — every `h1ve <cmd>` below can be run as `nf <cmd>`.
28
+
29
+ > `h1ve health` saying "no snapshots yet" is **success** (you're connected; the project just has no metrics yet).
30
+
31
+ ## Commands
32
+
33
+ | Command | What it does |
34
+ |---|---|
35
+ | `h1ve login` / `h1ve logout` | Authorize in the browser and store the credential locally / remove it |
36
+ | `h1ve status` | State of the current branch's feature (stage, days active, blockers, sign-offs) |
37
+ | `h1ve start [<#\|id>] [--slug <s>]` | Start an assigned feature: create the `feat/{you}/{slug}` branch and record the slug |
38
+ | `h1ve spec` | Print the feature's spec (markdown) |
39
+ | `h1ve move <stage> [--note]` | Move the feature to another stage |
40
+ | `h1ve done [--from <file>] [--no-move]` | Submit the AI declaration (JSON) and move `dev → pr` |
41
+ | `h1ve blocker "<desc>"` | Open a blocker on the feature (you become its owner) |
42
+ | `h1ve health` | Latest technical-health snapshots for the project |
43
+ | `h1ve connect --kind <k> --label <l> --env KEY=VAL` | Write a credential to your **local** `.env.local` and register the inventory (never sent to the server) |
44
+ | `h1ve serve [--port 7391]` | Run the local agent (`127.0.0.1`) so the dashboard can apply credentials from the browser |
45
+
46
+ Flags: `--json` (raw output for scripts) · `--project <name\|id>` (if you belong to more than one project) · `-h`.
47
+
48
+ ## Example
49
+
50
+ ```bash
51
+ h1ve start # start your assigned feature (creates the branch)
52
+ # ... work: git, code, commits ...
53
+ h1ve status # check state anytime
54
+ h1ve blocker "waiting on the Neon credential" # blocked? open a blocker
55
+ h1ve done --from ai-declaration.json # submit the AI declaration + move dev → pr
56
+ ```
57
+
58
+ ## CI / headless (env vars)
59
+
60
+ No browser? Configure by env (takes **precedence** over `h1ve login`):
61
+
62
+ ```bash
63
+ export H1VE_API_URL="https://app.h1ve.org" # optional (this is the default)
64
+ export H1VE_API_KEY="nf_pat_..." # a PAT from app.h1ve.org/api-tokens
65
+ # export H1VE_PROJECT_ID="..." # OPTIONAL — the CLI resolves the project from the repo
66
+ ```
67
+
68
+ ## Troubleshooting
69
+
70
+ | Symptom | Fix |
71
+ |---|---|
72
+ | `h1ve: command not found` | Node missing or wrong terminal. Check `node --version`. On Windows, reopen the shell or use the VS Code terminal. |
73
+ | `404` on install | npm propagation right after a publish — wait a few minutes. |
74
+ | `NO_PROJECT` | You belong to more than one project — pass `--project <name\|id>`. |
75
+ | `401` / `403` | Wrong/missing token. Make sure `H1VE_API_KEY` is a PAT (`nf_pat_…`). `403 SERVICE_CANNOT_WRITE` = a read-only service key used on a write → use a PAT. |
76
+
77
+ Requires **Node.js 18.18+**. The legacy `nf` command and env names `NEXUS_FLOW_API_URL` / `NEXUS_FLOW_API_KEY` are still accepted.
78
+
79
+ ---
80
+
81
+ MIT · built with H1VE, by [H1VE](https://h1ve.org) 🐝
package/dist/index.js CHANGED
@@ -212,6 +212,9 @@ function createClient(config) {
212
212
  setDone(featureId, doneContent) {
213
213
  return writeAction("PATCH", featureId, "done", { done_content: doneContent });
214
214
  },
215
+ addDependency(featureId, dependsOnId) {
216
+ return postAction(featureId, "dependencies", { depends_on_id: dependsOnId });
217
+ },
215
218
  // SPEC-100 (B2): best-effort — o juiz de drift é ADVISORY; qualquer falha → {checked:false}
216
219
  // (nunca lança, pra não estragar o fluxo de gravar a SPEC no `set_spec` do MCP).
217
220
  async checkSpecAlignment(featureId) {
@@ -294,6 +297,26 @@ async function exchangeCliLoginCode(config, code) {
294
297
  return { apiKey: body.api_key };
295
298
  }
296
299
 
300
+ // ../core/src/cli-login.ts
301
+ function buildAuthorizeUrl(baseUrl, port, state) {
302
+ const base = baseUrl.replace(/\/+$/, "");
303
+ return `${base}/cli-login?port=${port}&state=${encodeURIComponent(state)}`;
304
+ }
305
+ function parseCallbackUrl(reqUrl, expectedState) {
306
+ let u;
307
+ try {
308
+ u = new URL(reqUrl, "http://127.0.0.1");
309
+ } catch {
310
+ return { error: "bad_url" };
311
+ }
312
+ if (u.pathname !== "/cb") return { error: "not_cb" };
313
+ const code = u.searchParams.get("code");
314
+ const state = u.searchParams.get("state");
315
+ if (!code || !state) return { error: "missing" };
316
+ if (state !== expectedState) return { error: "state_mismatch" };
317
+ return { code };
318
+ }
319
+
297
320
  // ../core/src/env.ts
298
321
  import { readFile as fsReadFile, writeFile as fsWriteFile } from "fs/promises";
299
322
  import { join } from "path";
@@ -525,6 +548,13 @@ function formatStatus(d) {
525
548
  } else {
526
549
  lines.push("Blockers ativos: nenhum");
527
550
  }
551
+ if (d.attachments && d.attachments.length) {
552
+ lines.push(`Anexos (${d.attachments.length}):`);
553
+ for (const a of d.attachments) {
554
+ const tag = a.kind === "repo_path" ? " (arquivo local \u2014 leia)" : "";
555
+ lines.push(` \u{1F4CE} ${a.label ? `${a.label} \u2014 ` : ""}${a.value}${tag}`);
556
+ }
557
+ }
528
558
  if (d.ai_declaration?.submitted) lines.push("AI declaration: enviada");
529
559
  return lines.join("\n");
530
560
  }
@@ -550,13 +580,47 @@ function formatMove(prevStage, r) {
550
580
  function formatBlocker(r) {
551
581
  return `\u2713 Blocker aberto: ${r.description}`;
552
582
  }
583
+ function suggestionReason(f) {
584
+ if (f.branch_slug !== null) return "j\xE1 iniciado \u2014 retome antes de abrir outra frente";
585
+ if (f.blocked_by_dep) return "\xE9 o mais priorit\xE1rio dispon\xEDvel, mas depende de trabalho n\xE3o conclu\xEDdo";
586
+ if (f.priority === "HIGH") return "prioridade alta e sem depend\xEAncia pendente";
587
+ if (f.priority === "MEDIUM") return "sem depend\xEAncia pendente; nada de prioridade alta na fila";
588
+ return "\xE9 o que resta na fila";
589
+ }
590
+ function metaOf(f) {
591
+ const aposta = f.appetite ? ` \xB7 ${f.appetite}d` : "";
592
+ return ` ${f.priority}${aposta}`;
593
+ }
553
594
  function formatStartList(list) {
554
595
  const header = "Features para iniciar ou retomar \u2014 escolha: h1ve start <n\xBA>";
555
- const rows = list.map((f, i) => {
596
+ const rows = list.flatMap((f, i) => {
597
+ const sugerido = i === 0;
598
+ const marca = sugerido ? "\u2192" : " ";
556
599
  const tag = f.branch_slug !== null ? " (retomar)" : "";
557
- return ` ${String(i + 1).padStart(2)}. ${f.name} [${stageLabel(f.stage)}]${tag}`;
600
+ const dep = f.depends_on && f.depends_on.length > 0 ? ` \u26A0 depende de ${f.depends_on.map((d) => d.name).join(", ")}` : "";
601
+ const linha = `${marca} ${String(i + 1).padStart(2)}. ${f.name} [${stageLabel(f.stage)}]${metaOf(f)}${tag}${dep}`;
602
+ return sugerido ? [linha, ` sugerido: ${suggestionReason(f)}`] : [linha];
558
603
  });
559
- return [header, ...rows].join("\n");
604
+ return [header, "", ...rows].join("\n");
605
+ }
606
+ var PRIORITY_RANK = { HIGH: 0, MEDIUM: 1, LOW: 2 };
607
+ function rankStartable(list) {
608
+ return [...list].sort((a, b) => {
609
+ const resume = (a.branch_slug !== null ? 0 : 1) - (b.branch_slug !== null ? 0 : 1);
610
+ if (resume !== 0) return resume;
611
+ const blocked = (a.blocked_by_dep ? 1 : 0) - (b.blocked_by_dep ? 1 : 0);
612
+ if (blocked !== 0) return blocked;
613
+ const prio = PRIORITY_RANK[a.priority] - PRIORITY_RANK[b.priority];
614
+ if (prio !== 0) return prio;
615
+ return (a.appetite ?? 0) - (b.appetite ?? 0);
616
+ });
617
+ }
618
+ function formatDepWarning(f) {
619
+ if (!f.depends_on || f.depends_on.length === 0) return "";
620
+ const names = f.depends_on.map((d) => d.name).join(", ");
621
+ return `\u26A0 "${f.name}" depende de ${names} (ainda n\xE3o conclu\xEDdo) \u2014 considere fazer isso primeiro.
622
+
623
+ `;
560
624
  }
561
625
  var PRE_DEV_STAGES = /* @__PURE__ */ new Set(["backlog", "spec", "blocked"]);
562
626
  function startFlowLines(r) {
@@ -781,7 +845,7 @@ function pick(list, arg) {
781
845
  }
782
846
  async function start(io, args) {
783
847
  const [features, localBranches] = await Promise.all([io.client.listFeatures(), io.listBranches()]);
784
- const list = startable(features, localBranches);
848
+ const list = rankStartable(startable(features, localBranches));
785
849
  if (list.length === 0) {
786
850
  throw new CliError("Nenhuma feature para iniciar ou retomar (sem branch local e fora de main).");
787
851
  }
@@ -799,7 +863,8 @@ async function start(io, args) {
799
863
  if (code === "BRANCH_EXISTS") await io.switchBranch(result.branch_name);
800
864
  else throw err;
801
865
  }
802
- return { human: `${warning}${formatStart(result, { resumed: resuming })}`, data: result };
866
+ const depWarn = formatDepWarning(selected);
867
+ return { human: `${warning}${depWarn}${formatStart(result, { resumed: resuming })}`, data: result };
803
868
  }
804
869
 
805
870
  // src/commands/connect.ts
@@ -1316,24 +1381,6 @@ import { createServer as createServer2 } from "http";
1316
1381
  import { randomBytes as randomBytes2 } from "crypto";
1317
1382
  import { execFile as execFile2 } from "child_process";
1318
1383
  var LOGIN_TIMEOUT_MS = 3 * 60 * 1e3;
1319
- function buildAuthorizeUrl(baseUrl, port, state) {
1320
- const base = baseUrl.replace(/\/+$/, "");
1321
- return `${base}/cli-login?port=${port}&state=${encodeURIComponent(state)}`;
1322
- }
1323
- function parseCallbackUrl(reqUrl, expectedState) {
1324
- let u;
1325
- try {
1326
- u = new URL(reqUrl, "http://127.0.0.1");
1327
- } catch {
1328
- return { error: "bad_url" };
1329
- }
1330
- if (u.pathname !== "/cb") return { error: "not_cb" };
1331
- const code = u.searchParams.get("code");
1332
- const state = u.searchParams.get("state");
1333
- if (!code || !state) return { error: "missing" };
1334
- if (state !== expectedState) return { error: "state_mismatch" };
1335
- return { code };
1336
- }
1337
1384
  var SUCCESS_HTML = `<!doctype html><html><head><meta charset="utf-8"><title>H1VE</title></head>
1338
1385
  <body style="font-family:system-ui;background:#0f1115;color:#e7e9ee;display:flex;min-height:100vh;align-items:center;justify-content:center;margin:0">
1339
1386
  <div style="text-align:center"><div style="font-size:22px;font-weight:800;letter-spacing:.12em">H<span style="color:#f5a623">1</span>VE</div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@h1veframework/cli",
3
- "version": "0.13.0",
3
+ "version": "0.15.0",
4
4
  "description": "The CLI for H1VE — the governance & memory layer for teams building with AI. Drive your feature flow (start, status, move, spec, done) from the terminal. Works with Claude Code, Cursor and Copilot.",
5
5
  "license": "MIT",
6
6
  "type": "module",