@hiveai/cli 0.3.2 → 0.3.3

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
@@ -22,28 +22,30 @@ This installs the `haive` command globally.
22
22
  ## Quick start
23
23
 
24
24
  ```bash
25
- # 1. Initialize hAIve in your project
25
+ # 1. Initialize hAIve in your project (autopilot ON by default)
26
26
  cd my-project
27
- haive init
27
+ haive init # autopilot: hooks + CI + code-map auto-configured
28
+ # haive init --manual # if you prefer to approve memories yourself
28
29
 
29
- # 2. Start the MCP server (in Claude Code / Cursor MCP config)
30
- haive mcp --root /absolute/path/to/my-project
30
+ # 2. Point your AI client at the MCP server
31
+ # Add to ~/.claude.json / ~/.cursor/mcp.json:
32
+ # { "mcpServers": { "haive": { "command": "haive-mcp", "args": ["--root", "/absolute/path"] } } }
31
33
 
32
- # 3. Add a team memory
34
+ # 3. Bootstrap the project context (run once in your AI client)
35
+ # → Use the bootstrap_project MCP prompt to analyze the codebase and fill .ai/project-context.md
36
+
37
+ # 4. Your AI client now calls get_briefing at every session start — zero config needed
38
+
39
+ # 5. Add a memory manually (or let the AI agent do it via mem_save)
33
40
  haive memory add \
34
- --type gotcha \
35
- --slug "open-in-view-false" \
36
- --scope team \
41
+ --type gotcha --slug "jpa-open-in-view" --scope team \
37
42
  --paths src/main/resources/application.properties \
38
43
  --body "spring.jpa.open-in-view=false is intentional — do not re-enable."
39
44
 
40
- # 4. Browse memories
41
- haive memory list --scope team
45
+ # 6. Browse and manage memories in the TUI dashboard
46
+ haive tui
42
47
 
43
- # 5. Get a briefing before a task
44
- haive briefing --task "add a payment endpoint" --scope team
45
-
46
- # 6. Sync after a git pull
48
+ # 7. Sync after a git pull (runs automatically via hooks in autopilot mode)
47
49
  haive sync
48
50
  ```
49
51
 
@@ -53,21 +55,35 @@ haive sync
53
55
 
54
56
  ### `haive init`
55
57
 
56
- Initialize the `.ai/` structure in a project and generate bridge files for your AI tools.
58
+ Initialize the `.ai/` structure in a project. **Autopilot mode is ON by default** zero manual steps required.
57
59
 
58
60
  ```bash
59
- haive init # Creates .ai/, CLAUDE.md, .cursorrules, copilot-instructions.md
60
- haive init --no-bridges # Skip bridge file generation
61
- haive init --with-ci # Also write .github/workflows/haive-sync.yml
61
+ haive init # Autopilot: validates memories automatically, installs hooks, builds code-map
62
+ haive init --manual # Manual mode: you approve every memory yourself
63
+ haive init --no-bridges # Skip bridge file generation (CLAUDE.md, .cursorrules, etc.)
62
64
  haive init --dir /other/path # Initialize in a specific directory
63
65
  ```
64
66
 
67
+ **Autopilot mode** (default):
68
+ - Memories are saved directly as `validated` (no approval cycle)
69
+ - Git hooks installed automatically (`haive sync` after every pull)
70
+ - CI workflow generated (`.github/workflows/haive-sync.yml`)
71
+ - Initial code-map built (`.ai/code-map.json`) for symbol lookup
72
+ - Session recaps saved automatically when the MCP server exits
73
+ - Configuration stored in `.ai/haive.config.json`
74
+
75
+ **Manual mode** (`--manual`):
76
+ - Memories start as `proposed` and require explicit approval (`haive memory approve`)
77
+ - No automatic hooks or CI — set up manually with `haive install-hooks` and `haive init --with-ci`
78
+ - Full control over when knowledge is shared with the team
79
+
65
80
  **What it creates:**
66
81
 
67
82
  ```
68
83
  your-project/
69
84
  ├── .ai/
70
85
  │ ├── project-context.md # Shared project overview (fill via bootstrap_project MCP prompt)
86
+ │ ├── haive.config.json # Autopilot settings
71
87
  │ ├── modules/ # Per-component context files
72
88
  │ └── memories/
73
89
  │ ├── personal/ # Private to one developer
package/dist/index.js CHANGED
@@ -53,8 +53,8 @@ var ui = {
53
53
  // src/commands/briefing.ts
54
54
  function registerBriefing(program2) {
55
55
  program2.command("briefing").description(
56
- "Print project context + relevant memories in one shot \u2014 ideal for agent onboarding"
57
- ).option("--task <text>", "what you are about to do \u2014 filters memories by relevance").option("--files <csv>", "comma-separated file paths being worked on (anchors memories)").option("--symbols <csv>", "symbol names to look up in the code-map (e.g. PaymentService,TenantFilter)").option("--max-memories <n>", "cap on memories surfaced", "10").option(
56
+ 'Print the full project briefing: last session recap + project context + relevant memories.\n Equivalent to calling get_briefing via MCP. Run before starting any task.\n\n Examples:\n haive briefing\n haive briefing --task "add Stripe payment" --files src/payments/PaymentService.ts\n haive briefing --symbols PaymentService,TenantFilter # look up where symbols live\n'
57
+ ).option("--task <text>", "what you are about to do \u2014 filters memories by relevance").option("--files <csv>", "comma-separated file paths being worked on (surfaces anchored memories)").option("--symbols <csv>", "symbol names to look up in the code-map (e.g. PaymentService,TenantFilter) \u2014 requires haive index code").option("--max-memories <n>", "cap on memories surfaced", "10").option(
58
58
  "--scope <scope>",
59
59
  "personal | team | module | all (default: team)",
60
60
  "team"
@@ -204,7 +204,9 @@ function parseCsv(value) {
204
204
  import "commander";
205
205
  import { findProjectRoot as findProjectRoot2 } from "@hiveai/core";
206
206
  function registerTui(program2) {
207
- program2.command("tui").description("Interactive TUI dashboard \u2014 browse, filter, and manage memories in the terminal").option("-d, --dir <dir>", "project root").action(async (opts) => {
207
+ program2.command("tui").description(
208
+ "Interactive terminal dashboard for browsing and managing memories.\n\n Screens (switch with 1 / 2 / 3):\n 1 \u2014 Memories: list + preview, filter by status (Tab), actions (a/r/p/d)\n 2 \u2014 Health: stale, pending review, anchorless memories\n 3 \u2014 Stats: most-read, decaying, total counts\n\n Key bindings:\n \u2191 \u2193 navigate list\n Tab cycle status filter (all \u2192 proposed \u2192 validated \u2192 stale)\n a approve selected memory\n r reject selected memory\n p promote personal \u2192 team (proposed)\n d delete selected memory\n q / Esc exit\n"
209
+ ).option("-d, --dir <dir>", "project root").action(async (opts) => {
208
210
  if (!process.stdout.isTTY) {
209
211
  console.error("haive tui requires an interactive terminal (TTY).");
210
212
  process.exitCode = 1;
@@ -303,9 +305,13 @@ import {
303
305
  saveCodeMap
304
306
  } from "@hiveai/core";
305
307
  function registerIndexCode(program2) {
306
- const idx = program2.command("index").description("Build local indexes that help AIs read less code");
308
+ const idx = program2.command("index").description(
309
+ "Build local indexes that let AIs look up symbols instead of grepping.\n\n Run once after init, then haive sync refreshes it automatically when source changes."
310
+ );
307
311
  idx.action(() => idx.help());
308
- idx.command("code").description("Scan source files and write .ai/code-map.json (file \u2192 exports + 1-line description)").option("-d, --dir <dir>", "project root").option(
312
+ idx.command("code").description(
313
+ "Scan source files and write .ai/code-map.json (file \u2192 exports + 1-line description).\n\n Supported languages: TypeScript, JavaScript, Java, Python, Go, Rust, C#, PHP.\n The map is used by:\n \u2022 get_briefing (symbol_locations) \u2014 look up where a class/function lives\n \u2022 code_map MCP tool \u2014 browse exports without grepping\n \u2022 haive briefing --symbols \u2014 look up symbols from the CLI\n\n Run automatically by haive init (autopilot mode) and haive sync (if source changed).\n\n Example:\n haive index code\n haive index code --exclude generated,proto\n"
314
+ ).option("-d, --dir <dir>", "project root").option(
309
315
  "--exclude <csv>",
310
316
  "extra directory names to skip (comma-separated)",
311
317
  ""
@@ -458,13 +464,15 @@ jobs:
458
464
  });
459
465
  `;
460
466
  function registerInit(program2) {
461
- program2.command("init").description("Initialize a hAIve project (.ai/ structure + bridge files)").option("-d, --dir <dir>", "project root", process.cwd()).option("--no-bridges", "do not generate CLAUDE.md / .cursorrules / copilot-instructions.md").option("--with-ci", "write a GitHub Actions workflow (.github/workflows/haive-sync.yml)").option(
462
- "--autopilot",
463
- "zero-friction mode: memories \u2192 validated, auto-approve, auto-session, auto-context, git hooks + CI included"
467
+ program2.command("init").description(
468
+ "Initialize a hAIve project \u2014 autopilot mode ON by default (zero human intervention).\n Add --manual if you want to control memory approval and session recaps yourself."
469
+ ).option("-d, --dir <dir>", "project root", process.cwd()).option("--no-bridges", "do not generate CLAUDE.md / .cursorrules / copilot-instructions.md").option("--with-ci", "write a GitHub Actions workflow (.github/workflows/haive-sync.yml) \u2014 included automatically in autopilot mode").option(
470
+ "--manual",
471
+ "opt out of autopilot: memories require manual approval, no auto-session recap, no auto-context"
464
472
  ).action(async (opts) => {
465
473
  const root = path3.resolve(opts.dir);
466
474
  const paths = resolveHaivePaths4(root);
467
- const autopilot = opts.autopilot === true;
475
+ const autopilot = opts.manual !== true;
468
476
  if (existsSync3(paths.haiveDir)) {
469
477
  ui.warn(`.ai/ already exists at ${paths.haiveDir} \u2014 leaving existing files in place.`);
470
478
  }
@@ -548,7 +556,7 @@ function registerInit(program2) {
548
556
  console.log(ui.dim(" 3. Start every AI session with:"));
549
557
  console.log(" " + ui.bold("get_briefing({ task: '\u2026what you are about to do\u2026' })"));
550
558
  console.log();
551
- console.log(ui.dim(" Tip: run `haive init --autopilot` for zero-friction mode (no manual steps)."));
559
+ console.log(ui.dim(" Tip: run `haive init` (without --manual) for zero-friction autopilot mode."));
552
560
  }
553
561
  });
554
562
  }
@@ -583,7 +591,9 @@ fi
583
591
  `;
584
592
  var HOOKS = ["post-merge", "post-rewrite"];
585
593
  function registerInstallHooks(program2) {
586
- program2.command("install-hooks").description("Install git hooks that run `haive sync` after pull/merge").option("-d, --dir <dir>", "project root").option("--force", "overwrite existing hooks").action(async (opts) => {
594
+ program2.command("install-hooks").description(
595
+ "Install git hooks so haive sync runs automatically after every pull or merge.\n\n Installs a post-merge hook at .git/hooks/post-merge that runs:\n haive sync --quiet --since ORIG_HEAD --embed\n\n This ensures memory anchors are always verified and the embeddings index\n is kept fresh without requiring any manual steps.\n\n Installed automatically by haive init (autopilot mode).\n Use --force to overwrite an existing post-merge hook.\n"
596
+ ).option("-d, --dir <dir>", "project root").option("--force", "overwrite existing hooks").action(async (opts) => {
587
597
  const root = findProjectRoot6(opts.dir);
588
598
  const gitDir = path4.join(root, ".git");
589
599
  if (!existsSync4(gitDir)) {
@@ -624,7 +634,20 @@ import "commander";
624
634
  import { findProjectRoot as findProjectRoot7 } from "@hiveai/core";
625
635
  var require2 = createRequire(import.meta.url);
626
636
  function registerMcp(program2) {
627
- program2.command("mcp").description("Start the hAIve MCP server (stdio transport)").option("-d, --dir <dir>", "project root (defaults to nearest .ai/ or .git/)").action((opts) => {
637
+ program2.command("mcp").description(
638
+ `Start the hAIve MCP server (stdio transport) for direct testing.
639
+
640
+ In normal use, your AI client (Claude Code, Cursor, VS Code) starts the server
641
+ automatically via the haive-mcp binary listed in your MCP config file.
642
+
643
+ This command is useful for debugging or for clients that require manual startup.
644
+
645
+ Client config examples (point at haive-mcp binary, not this command):
646
+ Claude Code: ~/.claude.json \u2192 mcpServers.haive.command = "haive-mcp"
647
+ Cursor: ~/.cursor/mcp.json \u2192 mcpServers.haive.command = "haive-mcp"
648
+ VS Code: code --add-mcp '{"name":"haive","command":"haive-mcp",...}'
649
+ `
650
+ ).option("-d, --dir <dir>", "project root (defaults to nearest .ai/ or .git/)").action((opts) => {
628
651
  const root = findProjectRoot7(opts.dir);
629
652
  const bin = locateMcpBin();
630
653
  if (!bin) {
@@ -677,7 +700,9 @@ import {
677
700
  var BRIDGE_START = "<!-- haive:memories-start -->";
678
701
  var BRIDGE_END = "<!-- haive:memories-end -->";
679
702
  function registerSync(program2) {
680
- program2.command("sync").description("Refresh memory state after a pull/merge: verify anchors, auto-promote, report changes").option("-d, --dir <dir>", "project root").option("--quiet", "minimal output (suitable for git hooks)").option(
703
+ program2.command("sync").description(
704
+ "Refresh memory state after a git pull or merge.\n What it does:\n 1. Verifies anchor paths \u2014 marks stale if files/symbols moved or deleted\n 2. Re-validates previously stale memories that are now fresh\n 3. Auto-promotes proposed memories (by usage count or time delay in autopilot)\n 4. Auto-refreshes code-map if source files changed\n 5. Reports decay warnings for memories unused >90 days\n\n Install git hooks to run sync automatically: haive install-hooks\n\n Examples:\n haive sync\n haive sync --since main # also report memories changed since main\n haive sync --embed # also rebuild embeddings index\n"
705
+ ).option("-d, --dir <dir>", "project root").option("--quiet", "minimal output (suitable for git hooks)").option(
681
706
  "--since <ref>",
682
707
  "git ref/commit to compare against; report memories added/modified/removed since"
683
708
  ).option("--no-verify", "skip the anchor verification step").option("--no-promote", "skip the auto-promotion step").option(
@@ -992,7 +1017,30 @@ import {
992
1017
  serializeMemory as serializeMemory2
993
1018
  } from "@hiveai/core";
994
1019
  function registerMemoryAdd(memory2) {
995
- memory2.command("add").description("Add a new memory (defaults to personal scope)").requiredOption("--type <type>", "convention | decision | gotcha | architecture | glossary | attempt").requiredOption("--slug <slug>", "short identifier used in the file name").option("--title <text>", "memory title \u2014 becomes the first heading of the body").option("--scope <scope>", "personal | team | module", "personal").option("--module <name>", "module name (required when scope=module)").option("--tags <csv>", "comma-separated tags").option("--domain <domain>", "domain (e.g. transactions)").option("--author <author>", "author email or handle").option("--paths <csv>", "anchor paths, comma-separated").option("--symbols <csv>", "anchor symbols, comma-separated").option("--commit <sha>", "anchor commit SHA").option("--body <text>", "memory body content (Markdown) \u2014 overrides --title default body").option("--body-file <path>", "read memory body from a Markdown file \u2014 alternative to --body for long content").option("--no-auto-tag", "disable automatic tag suggestions inferred from anchor paths").option("--topic <key>", "stable key: if a memory with this topic+scope already exists it is updated in-place (revision_count++)").option("-d, --dir <dir>", "project root").action(async (opts) => {
1020
+ memory2.command("add").description(
1021
+ `Save a piece of knowledge as a persistent memory.
1022
+
1023
+ Memory types:
1024
+ convention \u2014 how things are done here (naming, patterns, tooling)
1025
+ decision \u2014 a choice made and WHY (tradeoffs, constraints)
1026
+ gotcha \u2014 non-obvious behavior that surprises newcomers
1027
+ architecture \u2014 structural overview of a system or module
1028
+ glossary \u2014 domain terms and their meaning in this codebase
1029
+ attempt \u2014 failed approach (prefer 'haive memory tried' for better structure)
1030
+
1031
+ Tips:
1032
+ \u2022 --paths anchors the memory to source files for staleness detection
1033
+ \u2022 --topic enables upsert: future adds with the same topic update the existing memory
1034
+ \u2022 In autopilot mode, memories go directly to validated with team scope by default
1035
+
1036
+ Examples:
1037
+ haive memory add --type gotcha --slug jpa-open-in-view --scope team \\\\
1038
+ --paths src/main/resources/application.properties \\\\
1039
+ --body "spring.jpa.open-in-view=false is intentional \u2014 do not re-enable."
1040
+ haive memory add --type convention --slug flyway-no-modify --topic flyway \\\\
1041
+ --scope team --body "Never modify existing migrations. Create V{n+1}__desc.sql."
1042
+ `
1043
+ ).requiredOption("--type <type>", "convention | decision | gotcha | architecture | glossary | attempt").requiredOption("--slug <slug>", "short kebab-case identifier used in the file name").option("--title <text>", "memory title \u2014 becomes the first heading of the body").option("--scope <scope>", "personal | team | module (default: personal, or team in autopilot)", "personal").option("--module <name>", "module name (required when scope=module)").option("--tags <csv>", "comma-separated tags for easier retrieval").option("--domain <domain>", "domain (e.g. transactions)").option("--author <author>", "author email or handle").option("--paths <csv>", "anchor to source files \u2014 used for staleness detection by haive sync").option("--symbols <csv>", "anchor to specific symbols (class/function names)").option("--commit <sha>", "anchor to a specific commit SHA").option("--body <text>", "memory body content (Markdown) \u2014 overrides --title default body").option("--body-file <path>", "read memory body from a Markdown file \u2014 for long content").option("--no-auto-tag", "disable automatic tag suggestions inferred from anchor paths").option("--topic <key>", "stable key for upsert: if a memory with this topic+scope already exists, update it in-place (revision_count++)").option("-d, --dir <dir>", "project root").action(async (opts) => {
996
1044
  const root = findProjectRoot9(opts.dir);
997
1045
  const paths = resolveHaivePaths6(root);
998
1046
  if (!existsSync7(paths.haiveDir)) {
@@ -1745,8 +1793,21 @@ import {
1745
1793
  } from "@hiveai/core";
1746
1794
  function registerMemoryTried(memory2) {
1747
1795
  memory2.command("tried").description(
1748
- "Record a failed approach \u2014 negative knowledge to prevent repeated AI mistakes"
1749
- ).requiredOption("--what <text>", "what approach was tried").requiredOption("--why-failed <text>", "why it failed or should NOT be used").option("--instead <text>", "recommended alternative").option("--scope <scope>", "personal | team | module", "personal").option("--module <name>", "module name (required when scope=module)").option("--tags <csv>", "comma-separated tags").option("--paths <csv>", "anchor paths, comma-separated").option("--author <author>", "author email or handle").option("-d, --dir <dir>", "project root").action(async (opts) => {
1796
+ `Record a FAILED approach \u2014 prevents repeated mistakes in future sessions.
1797
+
1798
+ This is the most valuable type of negative knowledge. It surfaces FIRST in
1799
+ get_briefing so agents can't miss it. Auto-validated (no approval cycle).
1800
+
1801
+ Use this immediately when you try something and it fails.
1802
+
1803
+ Example:
1804
+ haive memory tried \\\\
1805
+ --what "importing X with ESM dynamic import" \\\\
1806
+ --why-failed "tsup bundles it as CJS, dynamic import fails at runtime" \\\\
1807
+ --instead "use static import in the entry file" \\\\
1808
+ --paths packages/cli/src/index.ts
1809
+ `
1810
+ ).requiredOption("--what <text>", "what approach was tried (short, descriptive title)").requiredOption("--why-failed <text>", "why it failed or should NOT be used (include the exact error if possible)").option("--instead <text>", "the correct approach to use instead").option("--scope <scope>", "personal | team | module (default: personal)", "personal").option("--module <name>", "module name (required when scope=module)").option("--tags <csv>", "comma-separated tags").option("--paths <csv>", "anchor paths, comma-separated").option("--author <author>", "author email or handle").option("-d, --dir <dir>", "project root").action(async (opts) => {
1750
1811
  const root = findProjectRoot18(opts.dir);
1751
1812
  const paths = resolveHaivePaths15(root);
1752
1813
  if (!existsSync16(paths.haiveDir)) {
@@ -2129,7 +2190,9 @@ import {
2129
2190
  verifyAnchor as verifyAnchor2
2130
2191
  } from "@hiveai/core";
2131
2192
  function registerMemoryVerify(memory2) {
2132
- memory2.command("verify").description("Check memory anchors against current code, optionally marking stale ones").option("--id <id>", "verify a single memory by id").option("--all", "verify every memory (default if --id is omitted)").option("--update", "write status=stale (or status=validated for re-freshed) back to disk").option("-d, --dir <dir>", "project root").action(async (opts) => {
2193
+ memory2.command("verify").description(
2194
+ "Check that memory anchor paths still exist in the current codebase.\n\n A memory is 'stale' when its anchored file or symbol was moved, deleted, or renamed.\n Stale memories are shown with a warning in get_briefing and should be updated or deleted.\n\n haive sync runs this automatically. Use this command for on-demand checks or in CI.\n\n CI recommendation: add 'haive memory verify' to your haive-sync.yml PR check job\n to catch stale memories before they reach main.\n\n Examples:\n haive memory verify # check all, report only\n haive memory verify --update # mark stale/fresh on disk\n haive memory verify --id 2026-04-28-gotcha-x # check one memory\n"
2195
+ ).option("--id <id>", "verify a single memory by id").option("--all", "verify every memory (default if --id is omitted)").option("--update", "write status=stale or status=validated back to disk").option("-d, --dir <dir>", "project root").action(async (opts) => {
2133
2196
  const root = findProjectRoot25(opts.dir);
2134
2197
  const paths = resolveHaivePaths22(root);
2135
2198
  if (!existsSync23(paths.memoriesDir)) {
@@ -2290,8 +2353,8 @@ var CONFIDENCE_EMOJI = {
2290
2353
  };
2291
2354
  function registerMemoryDigest(program2) {
2292
2355
  program2.command("digest").description(
2293
- "Generate a Markdown review digest of recently added/updated memories (default: last 7 days)"
2294
- ).option("--days <n>", "look-back window in days", "7").option("--scope <scope>", "personal | team | module | all", "team").option("--out <file>", "write digest to a file instead of stdout").option("-d, --dir <dir>", "project root").action(async (opts) => {
2356
+ "Generate a Markdown review digest of recently added or updated memories.\n\n Groups memories by type, shows confidence, status, read count, and anchor info.\n Each memory has action checkboxes (approve / reject / keep as-is) for peer review.\n\n Use this to do a bulk weekly review of team memories, or share with teammates\n as a pull-request attachment so humans can validate what the AI captured.\n\n Examples:\n haive memory digest # last 7 days, team scope\n haive memory digest --days 30 --scope all # last 30 days, all scopes\n haive memory digest --out review.md # write to file\n"
2357
+ ).option("--days <n>", "look-back window in days (default: 7)", "7").option("--scope <scope>", "personal | team | module | all (default: team)", "team").option("--out <file>", "write digest to a file instead of stdout").option("-d, --dir <dir>", "project root").action(async (opts) => {
2295
2358
  const root = findProjectRoot27(opts.dir);
2296
2359
  const paths = resolveHaivePaths24(root);
2297
2360
  if (!existsSync25(paths.memoriesDir)) {
@@ -2417,7 +2480,24 @@ function recapTopic(scope, module) {
2417
2480
  return module ? `session-recap-${scope}-${module}` : `session-recap-${scope}`;
2418
2481
  }
2419
2482
  function registerSessionEnd(session2) {
2420
- session2.command("end").description("Save a structured end-of-session recap (goal / accomplished / discoveries / next steps)").requiredOption("--goal <text>", "What you were trying to accomplish (1\u20132 sentences)").requiredOption("--accomplished <text>", "What was actually done (bullet list recommended)").option("--discoveries <text>", "Bugs, surprises, or inconsistencies found during this session").option("--files <csv>", "Key files touched, comma-separated").option("--next <text>", "What should happen next (for the next session or a teammate)").option("--scope <scope>", "personal | team | module", "personal").option("--module <name>", "module name (required when scope=module)").option("-d, --dir <dir>", "project root").action(async (opts) => {
2483
+ session2.command("end").description(
2484
+ `Save an end-of-session recap so the NEXT session starts with fresh context.
2485
+
2486
+ One recap per scope is kept and updated in-place (topic-upsert). The next
2487
+ session's get_briefing (or haive briefing) shows it at the very top.
2488
+
2489
+ In autopilot mode, a minimal recap saves automatically on MCP server exit.
2490
+ Calling this manually produces a richer, more actionable recap.
2491
+
2492
+ Example:
2493
+ haive session end \\\\
2494
+ --goal "Add Stripe webhook handler" \\\\
2495
+ --accomplished "Implemented webhook endpoint, added idempotency key" \\\\
2496
+ --discoveries "Missing .env.example entry for STRIPE_WEBHOOK_SECRET" \\\\
2497
+ --files src/payments/WebhookController.ts,src/payments/WebhookService.ts \\\\
2498
+ --next "Add integration tests for webhook signature validation"
2499
+ `
2500
+ ).requiredOption("--goal <text>", "what you were trying to accomplish (1\u20132 sentences)").requiredOption("--accomplished <text>", "what was actually done (bullet list recommended)").option("--discoveries <text>", "bugs, surprises, or inconsistencies found during this session").option("--files <csv>", "key files touched, comma-separated (used as anchor for staleness detection)").option("--next <text>", "what should happen next (for the next session or a teammate)").option("--scope <scope>", "personal | team | module (default: personal)", "personal").option("--module <name>", "module name (required when scope=module)").option("-d, --dir <dir>", "project root").action(async (opts) => {
2421
2501
  const root = findProjectRoot28(opts.dir);
2422
2502
  const paths = resolveHaivePaths25(root);
2423
2503
  if (!existsSync26(paths.haiveDir)) {
@@ -2481,7 +2561,7 @@ function parseCsv5(value) {
2481
2561
 
2482
2562
  // src/index.ts
2483
2563
  var program = new Command29();
2484
- program.name("haive").description("hAIve \u2014 team-first persistent memory layer for AI coding agents").version("0.3.2");
2564
+ program.name("haive").description("hAIve \u2014 team-first persistent memory layer for AI coding agents").version("0.3.3");
2485
2565
  registerInit(program);
2486
2566
  registerMcp(program);
2487
2567
  registerBriefing(program);