@arvoretech/hub 0.5.0 → 0.6.1

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/dist/index.js CHANGED
@@ -1,7 +1,12 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ checkAndAutoRegenerate,
4
+ generateCommand,
5
+ loadHubConfig
6
+ } from "./chunk-BLVKDXNY.js";
2
7
 
3
8
  // src/index.ts
4
- import { Command as Command19 } from "commander";
9
+ import { Command as Command18 } from "commander";
5
10
 
6
11
  // src/commands/init.ts
7
12
  import { Command } from "commander";
@@ -164,20 +169,10 @@ Added ${repoName} to hub`));
164
169
  import { Command as Command3 } from "commander";
165
170
  import { existsSync as existsSync2 } from "fs";
166
171
  import { writeFile as writeFile3 } from "fs/promises";
167
- import { join as join4 } from "path";
172
+ import { join as join3 } from "path";
168
173
  import { execSync } from "child_process";
169
174
  import chalk3 from "chalk";
170
175
 
171
- // src/core/hub-config.ts
172
- import { readFile as readFile2 } from "fs/promises";
173
- import { join as join3 } from "path";
174
- import { parse as parse2 } from "yaml";
175
- async function loadHubConfig(dir) {
176
- const configPath = join3(dir, "hub.yaml");
177
- const content = await readFile2(configPath, "utf-8");
178
- return parse2(content);
179
- }
180
-
181
176
  // src/core/docker-compose.ts
182
177
  import { stringify as stringify3 } from "yaml";
183
178
  function generateDockerCompose(services) {
@@ -276,7 +271,7 @@ var setupCommand = new Command3("setup").description("Clone repos, start service
276
271
  \u2501\u2501\u2501 Step ${step}/${totalSteps}: Cloning repositories \u2501\u2501\u2501
277
272
  `));
278
273
  for (const repo of config.repos) {
279
- const fullPath = join4(hubDir, repo.path);
274
+ const fullPath = join3(hubDir, repo.path);
280
275
  console.log(chalk3.yellow(`\u25B8 ${repo.name}`));
281
276
  if (existsSync2(fullPath)) {
282
277
  console.log(chalk3.green(" Already exists, skipping"));
@@ -295,7 +290,7 @@ var setupCommand = new Command3("setup").description("Clone repos, start service
295
290
  console.log(chalk3.blue(`
296
291
  \u2501\u2501\u2501 Step ${step}/${totalSteps}: Starting services \u2501\u2501\u2501
297
292
  `));
298
- const composePath = join4(hubDir, "docker-compose.yml");
293
+ const composePath = join3(hubDir, "docker-compose.yml");
299
294
  const composeContent = generateDockerCompose(config.services);
300
295
  await writeFile3(composePath, composeContent, "utf-8");
301
296
  console.log(chalk3.green(" Generated docker-compose.yml"));
@@ -323,7 +318,7 @@ var setupCommand = new Command3("setup").description("Clone repos, start service
323
318
  } else {
324
319
  if (config.tools && Object.keys(config.tools).length > 0) {
325
320
  const content = generateMiseToml(config.tools, config.mise_settings);
326
- await writeFile3(join4(hubDir, ".mise.toml"), content, "utf-8");
321
+ await writeFile3(join3(hubDir, ".mise.toml"), content, "utf-8");
327
322
  console.log(chalk3.green(` Generated .mise.toml (${Object.keys(config.tools).length} tools)`));
328
323
  try {
329
324
  run("mise trust && mise install", hubDir);
@@ -334,11 +329,11 @@ var setupCommand = new Command3("setup").description("Clone repos, start service
334
329
  }
335
330
  for (const repo of config.repos) {
336
331
  if (!repo.tools || Object.keys(repo.tools).length === 0) continue;
337
- const repoDir = join4(hubDir, repo.path);
332
+ const repoDir = join3(hubDir, repo.path);
338
333
  if (!existsSync2(repoDir)) continue;
339
334
  const merged = { ...config.tools || {}, ...repo.tools };
340
335
  const content = generateMiseToml(merged);
341
- await writeFile3(join4(repoDir, ".mise.toml"), content, "utf-8");
336
+ await writeFile3(join3(repoDir, ".mise.toml"), content, "utf-8");
342
337
  console.log(chalk3.yellow(`\u25B8 ${repo.name}`));
343
338
  try {
344
339
  run("mise trust 2>/dev/null; mise install", repoDir);
@@ -355,10 +350,10 @@ var setupCommand = new Command3("setup").description("Clone repos, start service
355
350
  `));
356
351
  for (const repo of config.repos) {
357
352
  if (!repo.env_file) continue;
358
- const envPath = join4(hubDir, repo.path, repo.env_file);
353
+ const envPath = join3(hubDir, repo.path, repo.env_file);
359
354
  const overrides = config.env?.overrides?.["local"]?.[repo.name];
360
355
  if (overrides) {
361
- const dir = join4(hubDir, repo.path);
356
+ const dir = join3(hubDir, repo.path);
362
357
  if (existsSync2(dir)) {
363
358
  const lines = Object.entries(overrides).map(([k, v]) => `${k}=${v}`);
364
359
  await writeFile3(envPath, lines.join("\n") + "\n", "utf-8");
@@ -374,7 +369,7 @@ var setupCommand = new Command3("setup").description("Clone repos, start service
374
369
  \u2501\u2501\u2501 Step ${step}/${totalSteps}: Installing dependencies \u2501\u2501\u2501
375
370
  `));
376
371
  for (const repo of config.repos) {
377
- const fullPath = join4(hubDir, repo.path);
372
+ const fullPath = join3(hubDir, repo.path);
378
373
  if (!existsSync2(fullPath)) continue;
379
374
  const installCmd = repo.commands?.install;
380
375
  if (!installCmd) {
@@ -395,999 +390,20 @@ var setupCommand = new Command3("setup").description("Clone repos, start service
395
390
  `));
396
391
  }
397
392
  console.log(chalk3.blue("\n\u2501\u2501\u2501 Setup complete \u2501\u2501\u2501\n"));
393
+ await checkAndAutoRegenerate(hubDir);
398
394
  console.log("Next steps:");
399
- console.log(` npx @arvoretech/hub generate --editor cursor`);
400
- console.log(` Open the project in Cursor and start building`);
395
+ console.log(` npx @arvoretech/hub generate`);
396
+ console.log(` Open the project in your editor and start building`);
401
397
  console.log();
402
398
  });
403
399
 
404
- // src/commands/generate.ts
400
+ // src/commands/env.ts
405
401
  import { Command as Command4 } from "commander";
406
402
  import { existsSync as existsSync3 } from "fs";
407
- import { mkdir as mkdir2, writeFile as writeFile4, readdir, copyFile, readFile as readFile3, cp } from "fs/promises";
408
- import { join as join5, resolve } from "path";
409
- import chalk4 from "chalk";
410
- var HUB_MARKER_START = "# >>> hub-managed (do not edit this section)";
411
- var HUB_MARKER_END = "# <<< hub-managed";
412
- var HOOK_EVENT_MAP = {
413
- session_start: { cursor: "sessionStart", claude: "SessionStart", kiro: void 0 },
414
- session_end: { cursor: "sessionEnd", claude: "SessionEnd", kiro: void 0 },
415
- pre_tool_use: { cursor: "preToolUse", claude: "PreToolUse", kiro: "pre_tool_use" },
416
- post_tool_use: { cursor: "postToolUse", claude: "PostToolUse", kiro: "post_tool_use" },
417
- post_tool_use_failure: { cursor: void 0, claude: "PostToolUseFailure", kiro: void 0 },
418
- stop: { cursor: "stop", claude: "Stop", kiro: "agent_stop" },
419
- subagent_start: { cursor: "subagentStart", claude: "SubagentStart", kiro: void 0 },
420
- subagent_stop: { cursor: "subagentStop", claude: "SubagentStop", kiro: void 0 },
421
- pre_compact: { cursor: "preCompact", claude: "PreCompact", kiro: void 0 },
422
- before_submit_prompt: { cursor: "beforeSubmitPrompt", claude: "UserPromptSubmit", kiro: "prompt_submit" },
423
- before_shell_execution: { cursor: "beforeShellExecution", claude: void 0, kiro: void 0 },
424
- after_shell_execution: { cursor: "afterShellExecution", claude: void 0, kiro: void 0 },
425
- before_mcp_execution: { cursor: "beforeMCPExecution", claude: void 0, kiro: void 0 },
426
- after_mcp_execution: { cursor: "afterMCPExecution", claude: void 0, kiro: void 0 },
427
- after_file_edit: { cursor: "afterFileEdit", claude: void 0, kiro: "file_save" },
428
- before_read_file: { cursor: "beforeReadFile", claude: void 0, kiro: void 0 },
429
- before_tab_file_read: { cursor: "beforeTabFileRead", claude: void 0, kiro: void 0 },
430
- after_tab_file_edit: { cursor: "afterTabFileEdit", claude: void 0, kiro: void 0 },
431
- after_agent_response: { cursor: "afterAgentResponse", claude: void 0, kiro: void 0 },
432
- after_agent_thought: { cursor: "afterAgentThought", claude: void 0, kiro: void 0 },
433
- notification: { cursor: void 0, claude: "Notification", kiro: void 0 },
434
- permission_request: { cursor: void 0, claude: "PermissionRequest", kiro: void 0 },
435
- task_completed: { cursor: void 0, claude: "TaskCompleted", kiro: void 0 },
436
- teammate_idle: { cursor: void 0, claude: "TeammateIdle", kiro: void 0 }
437
- };
438
- function buildCursorHooks(hooks) {
439
- const cursorHooks = {};
440
- for (const [event, entries] of Object.entries(hooks)) {
441
- const mapped = HOOK_EVENT_MAP[event]?.cursor;
442
- if (!mapped) continue;
443
- const cursorEntries = entries.map((entry) => {
444
- const obj = { type: entry.type };
445
- if (entry.type === "command" && entry.command) obj.command = entry.command;
446
- if (entry.type === "prompt" && entry.prompt) obj.prompt = entry.prompt;
447
- if (entry.matcher) obj.matcher = entry.matcher;
448
- if (entry.timeout_ms) obj.timeout = entry.timeout_ms;
449
- return obj;
450
- });
451
- if (cursorEntries.length > 0) {
452
- cursorHooks[mapped] = cursorEntries;
453
- }
454
- }
455
- if (Object.keys(cursorHooks).length === 0) return null;
456
- return { version: 1, hooks: cursorHooks };
457
- }
458
- function buildClaudeHooks(hooks) {
459
- const claudeHooks = {};
460
- for (const [event, entries] of Object.entries(hooks)) {
461
- const mapped = HOOK_EVENT_MAP[event]?.claude;
462
- if (!mapped) continue;
463
- const claudeEntries = entries.map((entry) => {
464
- const obj = { type: entry.type };
465
- if (entry.type === "command" && entry.command) obj.command = entry.command;
466
- if (entry.type === "prompt" && entry.prompt) obj.prompt = entry.prompt;
467
- if (entry.matcher) obj.matcher = entry.matcher;
468
- if (entry.timeout_ms) obj.timeout = entry.timeout_ms;
469
- return obj;
470
- });
471
- if (claudeEntries.length > 0) {
472
- claudeHooks[mapped] = claudeEntries;
473
- }
474
- }
475
- if (Object.keys(claudeHooks).length === 0) return null;
476
- return claudeHooks;
477
- }
478
- async function generateCursorCommands(config, hubDir, cursorDir) {
479
- const commandsDir = join5(cursorDir, "commands");
480
- let count = 0;
481
- if (config.commands_dir) {
482
- const srcDir = resolve(hubDir, config.commands_dir);
483
- try {
484
- const files = await readdir(srcDir);
485
- const mdFiles = files.filter((f) => f.endsWith(".md"));
486
- if (mdFiles.length > 0) {
487
- await mkdir2(commandsDir, { recursive: true });
488
- for (const file of mdFiles) {
489
- await copyFile(join5(srcDir, file), join5(commandsDir, file));
490
- count++;
491
- }
492
- }
493
- } catch {
494
- console.log(chalk4.yellow(` Commands directory ${config.commands_dir} not found, skipping`));
495
- }
496
- }
497
- if (config.commands) {
498
- await mkdir2(commandsDir, { recursive: true });
499
- for (const [name, filePath] of Object.entries(config.commands)) {
500
- const src = resolve(hubDir, filePath);
501
- const dest = join5(commandsDir, name.endsWith(".md") ? name : `${name}.md`);
502
- try {
503
- await copyFile(src, dest);
504
- count++;
505
- } catch {
506
- console.log(chalk4.yellow(` Command file ${filePath} not found, skipping`));
507
- }
508
- }
509
- }
510
- if (count > 0) {
511
- console.log(chalk4.green(` Copied ${count} commands to .cursor/commands/`));
512
- }
513
- }
514
- async function writeManagedFile(filePath, managedLines) {
515
- const managedBlock = [HUB_MARKER_START, ...managedLines, HUB_MARKER_END].join("\n");
516
- if (existsSync3(filePath)) {
517
- const existing = await readFile3(filePath, "utf-8");
518
- const startIdx = existing.indexOf(HUB_MARKER_START);
519
- const endIdx = existing.indexOf(HUB_MARKER_END);
520
- if (startIdx !== -1 && endIdx !== -1) {
521
- const before = existing.substring(0, startIdx);
522
- const after = existing.substring(endIdx + HUB_MARKER_END.length);
523
- await writeFile4(filePath, before + managedBlock + after, "utf-8");
524
- return;
525
- }
526
- await writeFile4(filePath, managedBlock + "\n\n" + existing, "utf-8");
527
- return;
528
- }
529
- await writeFile4(filePath, managedBlock + "\n", "utf-8");
530
- }
531
- async function generateCursor(config, hubDir) {
532
- const cursorDir = join5(hubDir, ".cursor");
533
- await mkdir2(join5(cursorDir, "rules"), { recursive: true });
534
- await mkdir2(join5(cursorDir, "agents"), { recursive: true });
535
- const gitignoreLines = buildGitignoreLines(config);
536
- await writeManagedFile(join5(hubDir, ".gitignore"), gitignoreLines);
537
- console.log(chalk4.green(" Generated .gitignore"));
538
- const cursorignoreLines = [
539
- "# Re-include repositories for AI context"
540
- ];
541
- for (const repo of config.repos) {
542
- const repoDir = repo.path.replace("./", "");
543
- cursorignoreLines.push(`!${repoDir}/`);
544
- }
545
- cursorignoreLines.push("", "# Re-include tasks for agent collaboration", "!tasks/");
546
- await writeManagedFile(join5(hubDir, ".cursorignore"), cursorignoreLines);
547
- console.log(chalk4.green(" Generated .cursorignore"));
548
- if (config.mcps?.length) {
549
- const mcpConfig = {};
550
- for (const mcp of config.mcps) {
551
- mcpConfig[mcp.name] = buildCursorMcpEntry(mcp);
552
- }
553
- await writeFile4(
554
- join5(cursorDir, "mcp.json"),
555
- JSON.stringify({ mcpServers: mcpConfig }, null, 2) + "\n",
556
- "utf-8"
557
- );
558
- console.log(chalk4.green(" Generated .cursor/mcp.json"));
559
- }
560
- const orchestratorRule = buildOrchestratorRule(config);
561
- await writeFile4(join5(cursorDir, "rules", "orchestrator.mdc"), orchestratorRule, "utf-8");
562
- console.log(chalk4.green(" Generated .cursor/rules/orchestrator.mdc"));
563
- const agentsDir = resolve(hubDir, "agents");
564
- try {
565
- const agentFiles = await readdir(agentsDir);
566
- const mdFiles = agentFiles.filter((f) => f.endsWith(".md"));
567
- for (const file of mdFiles) {
568
- await copyFile(join5(agentsDir, file), join5(cursorDir, "agents", file));
569
- }
570
- console.log(chalk4.green(` Copied ${mdFiles.length} agent definitions`));
571
- } catch {
572
- console.log(chalk4.yellow(" No agents/ directory found, skipping agent copy"));
573
- }
574
- const skillsDir = resolve(hubDir, "skills");
575
- try {
576
- const skillFolders = await readdir(skillsDir);
577
- const cursorSkillsDir = join5(cursorDir, "skills");
578
- await mkdir2(cursorSkillsDir, { recursive: true });
579
- let count = 0;
580
- for (const folder of skillFolders) {
581
- const skillFile = join5(skillsDir, folder, "SKILL.md");
582
- try {
583
- await readFile3(skillFile);
584
- const srcDir = join5(skillsDir, folder);
585
- const targetDir = join5(cursorSkillsDir, folder);
586
- await cp(srcDir, targetDir, { recursive: true });
587
- count++;
588
- } catch {
589
- }
590
- }
591
- if (count > 0) {
592
- console.log(chalk4.green(` Copied ${count} skills`));
593
- }
594
- } catch {
595
- }
596
- if (config.hooks) {
597
- const cursorHooks = buildCursorHooks(config.hooks);
598
- if (cursorHooks) {
599
- await writeFile4(
600
- join5(cursorDir, "hooks.json"),
601
- JSON.stringify(cursorHooks, null, 2) + "\n",
602
- "utf-8"
603
- );
604
- console.log(chalk4.green(" Generated .cursor/hooks.json"));
605
- }
606
- }
607
- await generateCursorCommands(config, hubDir, cursorDir);
608
- }
609
- function buildCursorMcpEntry(mcp) {
610
- if (mcp.url) {
611
- return { url: mcp.url, ...mcp.env && { env: mcp.env } };
612
- }
613
- if (mcp.image) {
614
- const args = ["run", "-i", "--rm"];
615
- if (mcp.env) {
616
- for (const [key, value] of Object.entries(mcp.env)) {
617
- args.push("-e", `${key}=${value}`);
618
- }
619
- }
620
- args.push(mcp.image);
621
- return { command: "docker", args };
622
- }
623
- return {
624
- command: "npx",
625
- args: ["-y", mcp.package],
626
- ...mcp.env && { env: mcp.env }
627
- };
628
- }
629
- function buildClaudeCodeMcpEntry(mcp) {
630
- if (mcp.url) {
631
- return { type: "http", url: mcp.url };
632
- }
633
- if (mcp.image) {
634
- const args = ["run", "-i", "--rm"];
635
- if (mcp.env) {
636
- for (const [key, value] of Object.entries(mcp.env)) {
637
- args.push("-e", `${key}=${value}`);
638
- }
639
- }
640
- args.push(mcp.image);
641
- return { command: "docker", args };
642
- }
643
- return {
644
- command: "npx",
645
- args: ["-y", mcp.package],
646
- ...mcp.env && { env: mcp.env }
647
- };
648
- }
649
- function buildKiroMcpEntry(mcp) {
650
- if (mcp.url) {
651
- return { url: mcp.url, ...mcp.env && { env: mcp.env } };
652
- }
653
- if (mcp.image) {
654
- const args = ["run", "-i", "--rm"];
655
- if (mcp.env) {
656
- for (const [key, value] of Object.entries(mcp.env)) {
657
- args.push("-e", `${key}=${value}`);
658
- }
659
- }
660
- args.push(mcp.image);
661
- return { command: "docker", args };
662
- }
663
- return {
664
- command: "npx",
665
- args: ["-y", mcp.package],
666
- ...mcp.env && { env: mcp.env }
667
- };
668
- }
669
- function buildKiroSteeringContent(content, inclusion = "always", meta) {
670
- const frontMatter = ["---", `inclusion: ${inclusion}`];
671
- if (meta?.name) frontMatter.push(`name: ${meta.name}`);
672
- if (meta?.description) frontMatter.push(`description: ${meta.description}`);
673
- frontMatter.push("---");
674
- return `${frontMatter.join("\n")}
675
-
676
- ${content}`;
677
- }
678
- function buildKiroOrchestratorRule(config) {
679
- const taskFolder = config.workflow?.task_folder || "./tasks/<TASK_ID>/";
680
- const steps = config.workflow?.pipeline || [];
681
- const prompt = config.workflow?.prompt;
682
- const enforce = config.workflow?.enforce_workflow ?? false;
683
- const sections = [];
684
- sections.push(`# Orchestrator
685
-
686
- ## Your Main Responsibility
687
-
688
- You are the development orchestrator. Your job is to ensure that any feature or task requested by the user is completed end-to-end by following a structured pipeline. You work as a single agent but follow specialized instructions from steering files for each phase of development.
689
-
690
- > **Note:** This workspace uses steering files in \`.kiro/steering/\` to provide role-specific instructions for each pipeline step. When a step says "follow the instructions from steering file X", read that file and apply its guidelines to the current task.`);
691
- if (enforce) {
692
- sections.push(`
693
- ## STRICT WORKFLOW ENFORCEMENT
694
-
695
- **YOU MUST FOLLOW THE PIPELINE DEFINED BELOW. NO EXCEPTIONS.**
696
-
697
- - NEVER skip a pipeline step, even if the task seems simple or obvious.
698
- - ALWAYS execute steps in the exact order defined. Do not reorder, merge, or parallelize steps unless the pipeline explicitly allows it.
699
- - ALWAYS follow the designated steering file for each step. Do not improvise if a steering file is assigned.
700
- - ALWAYS wait for a step to complete and validate its output before moving to the next step.
701
- - If a step produces a document, READ the document and confirm it is complete before proceeding.
702
- - If a step has unanswered questions or validation issues, RESOLVE them before advancing.
703
- - NEVER jump directly to coding without completing refinement first.
704
- - NEVER skip review or QA steps, even for small changes.
705
- - If the user asks you to skip a step, explain why the pipeline exists and ask for explicit confirmation before proceeding.`);
706
- }
707
- if (prompt?.prepend) {
708
- sections.push(`
709
- ${prompt.prepend.trim()}`);
710
- }
711
- if (config.integrations?.linear) {
712
- const linear = config.integrations.linear;
713
- sections.push(`
714
- ## Task Management
715
-
716
- If the user doesn't have a task in their project management tool, create one using the Linear MCP.${linear.team ? ` Add it to the **${linear.team}** team.` : ""} Provide the link to the user so they can review and modify as needed.`);
717
- }
718
- sections.push(`
719
- ## Repositories
720
- `);
721
- for (const repo of config.repos) {
722
- const parts = [`- **${repo.path}**`];
723
- if (repo.description) parts.push(`\u2014 ${repo.description}`);
724
- else if (repo.tech) parts.push(`\u2014 ${repo.tech}`);
725
- if (repo.skills?.length) parts.push(`(skills: ${repo.skills.join(", ")})`);
726
- sections.push(parts.join(" "));
727
- if (repo.commands) {
728
- const cmds = Object.entries(repo.commands).filter(([, v]) => v).map(([k, v]) => `\`${k}\`: \`${v}\``).join(", ");
729
- if (cmds) sections.push(` Commands: ${cmds}`);
730
- }
731
- }
732
- if (prompt?.sections?.after_repositories) {
733
- sections.push(`
734
- ${prompt.sections.after_repositories.trim()}`);
735
- }
736
- const docStructure = buildDocumentStructure(steps, taskFolder);
737
- sections.push(docStructure);
738
- const pipelineSection = buildKiroPipelineSection(steps);
739
- sections.push(pipelineSection);
740
- if (prompt?.sections?.after_pipeline) {
741
- sections.push(`
742
- ${prompt.sections.after_pipeline.trim()}`);
743
- }
744
- if (config.integrations?.slack || config.integrations?.github) {
745
- sections.push(buildDeliverySection(config));
746
- }
747
- if (prompt?.sections?.after_delivery) {
748
- sections.push(`
749
- ${prompt.sections.after_delivery.trim()}`);
750
- }
751
- if (config.memory) {
752
- sections.push(`
753
- ## Team Memory
754
-
755
- This workspace has a team memory knowledge base available via the \`team-memory\` MCP.
756
-
757
- **Before starting any task**, use \`search_memories\` to find relevant context \u2014 past decisions, conventions, known issues, and domain knowledge. This avoids repeating mistakes and ensures consistency with previous choices.
758
-
759
- **After completing a task**, if you discovered something valuable (a decision, a gotcha, a convention, domain insight), use \`add_memory\` to capture it for the team.
760
-
761
- Available tools: \`search_memories\`, \`get_memory\`, \`add_memory\`, \`list_memories\`, \`archive_memory\`, \`remove_memory\`.`);
762
- }
763
- sections.push(`
764
- ## Troubleshooting and Debugging
765
-
766
- For bug reports or unexpected behavior, follow the debugging process from the \`agent-debugger.md\` steering file (if available), or:
767
- 1. Collect context (symptoms, environment, timeline)
768
- 2. Analyze logs and stack traces
769
- 3. Form and test hypotheses systematically
770
- 4. Identify the root cause
771
- 5. Propose and implement the fix`);
772
- if (prompt?.sections) {
773
- const reservedKeys = /* @__PURE__ */ new Set(["after_repositories", "after_pipeline", "after_delivery"]);
774
- for (const [name, content] of Object.entries(prompt.sections)) {
775
- if (reservedKeys.has(name)) continue;
776
- const title = name.split(/[-_]/).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
777
- sections.push(`
778
- ## ${title}
779
-
780
- ${content.trim()}`);
781
- }
782
- }
783
- if (prompt?.append) {
784
- sections.push(`
785
- ${prompt.append.trim()}`);
786
- }
787
- return sections.join("\n");
788
- }
789
- function buildKiroPipelineSection(steps) {
790
- if (steps.length === 0) {
791
- return `
792
- ## Development Pipeline
793
-
794
- Since Kiro does not support sub-agents, follow each step sequentially, applying the guidelines from the corresponding steering file:
795
-
796
- 1. **Refinement** \u2014 Read and follow \`agent-refinement.md\` steering file to collect requirements. Write output to the task document.
797
- 2. **Coding** \u2014 Follow the coding steering files (\`agent-coding-backend.md\`, \`agent-coding-frontend.md\`) to implement the feature.
798
- 3. **Review** \u2014 Follow \`agent-code-reviewer.md\` to review the implementation.
799
- 4. **QA** \u2014 Follow \`agent-qa-backend.md\` and/or \`agent-qa-frontend.md\` to test.
800
- 5. **Delivery** \u2014 Create PRs and notify the team.`;
801
- }
802
- const parts = [`
803
- ## Development Pipeline
804
-
805
- Follow each step sequentially, applying the role-specific instructions from the corresponding steering file at each phase.
806
- `];
807
- for (const step of steps) {
808
- if (step.actions) {
809
- parts.push(`### Delivery`);
810
- parts.push(`After all validations pass, execute these actions:`);
811
- for (const action of step.actions) {
812
- parts.push(`- ${formatAction(action)}`);
813
- }
814
- continue;
815
- }
816
- const stepTitle = step.step.charAt(0).toUpperCase() + step.step.slice(1);
817
- parts.push(`### ${stepTitle}`);
818
- if (step.mode === "plan") {
819
- parts.push(`**This step is a planning phase.** Do NOT make any code changes. Focus on reading, analyzing, and collaborating with the user to define requirements before proceeding.`);
820
- parts.push(``);
821
- }
822
- if (step.agent) {
823
- parts.push(`Follow the instructions from the \`agent-${step.agent}.md\` steering file.${step.output ? ` Write output to \`${step.output}\`.` : ""}`);
824
- if (step.step === "refinement") {
825
- parts.push(`
826
- After completing the refinement, validate with the user:
827
- - If there are unanswered questions, ask the user one at a time
828
- - If the user requests adjustments, revisit the refinement
829
- - Do not proceed until the document is complete and approved by the user`);
830
- }
831
- }
832
- if (Array.isArray(step.agents)) {
833
- const agentList = step.agents.map((a) => {
834
- if (typeof a === "string") return { agent: a };
835
- return a;
836
- });
837
- parts.push(`Follow the instructions from these steering files sequentially:`);
838
- for (const a of agentList) {
839
- let line = `- \`agent-${a.agent}.md\``;
840
- if (a.output) line += ` \u2192 write to \`${a.output}\``;
841
- if (a.when) line += ` (when: ${a.when})`;
842
- parts.push(line);
843
- }
844
- if (step.step === "coding" || step.step === "code" || step.step === "implementation") {
845
- parts.push(`
846
- If you encounter doubts during coding, write questions in the task document and validate with the user before proceeding.`);
847
- }
848
- if (step.step === "validation" || step.step === "review" || step.step === "qa") {
849
- parts.push(`
850
- If any validation step reveals issues requiring fixes, go back to the relevant coding step to address them.`);
851
- }
852
- }
853
- parts.push("");
854
- }
855
- return parts.join("\n");
856
- }
857
- function buildOrchestratorRule(config) {
858
- const taskFolder = config.workflow?.task_folder || "./tasks/<TASK_ID>/";
859
- const steps = config.workflow?.pipeline || [];
860
- const prompt = config.workflow?.prompt;
861
- const enforce = config.workflow?.enforce_workflow ?? false;
862
- const sections = [];
863
- sections.push(`---
864
- description: "Orchestrator agent \u2014 coordinates sub-agents through the development pipeline"
865
- alwaysApply: true
866
- ---
867
-
868
- # Orchestrator
869
-
870
- ## Your Main Responsibility
871
-
872
- You are an agent orchestrator. Your job is to ensure that any feature or task requested by the user is completed end-to-end using specialized sub-agents.`);
873
- if (enforce) {
874
- sections.push(`
875
- ## STRICT WORKFLOW ENFORCEMENT
876
-
877
- **YOU MUST FOLLOW THE PIPELINE DEFINED BELOW. NO EXCEPTIONS.**
878
-
879
- - NEVER skip a pipeline step, even if the task seems simple or obvious.
880
- - ALWAYS execute steps in the exact order defined. Do not reorder, merge, or parallelize steps unless the pipeline explicitly allows it.
881
- - ALWAYS call the designated sub-agent for each step. Do not attempt to perform a step yourself if an agent is assigned to it.
882
- - ALWAYS wait for a step to complete and validate its output before moving to the next step.
883
- - If a step produces a document, READ the document and confirm it is complete before proceeding.
884
- - If a step has unanswered questions or validation issues, RESOLVE them before advancing.
885
- - NEVER jump directly to coding without completing refinement first.
886
- - NEVER skip review or QA steps, even for small changes.
887
- - If the user asks you to skip a step, explain why the pipeline exists and ask for explicit confirmation before proceeding.`);
888
- }
889
- if (prompt?.prepend) {
890
- sections.push(`
891
- ${prompt.prepend.trim()}`);
892
- }
893
- if (config.integrations?.linear) {
894
- const linear = config.integrations.linear;
895
- sections.push(`
896
- ## Task Management
897
-
898
- If the user doesn't have a task in their project management tool, create one using the Linear MCP.${linear.team ? ` Add it to the **${linear.team}** team.` : ""} Provide the link to the user so they can review and modify as needed.`);
899
- }
900
- sections.push(`
901
- ## Repositories
902
- `);
903
- for (const repo of config.repos) {
904
- const parts = [`- **${repo.path}**`];
905
- if (repo.description) parts.push(`\u2014 ${repo.description}`);
906
- else if (repo.tech) parts.push(`\u2014 ${repo.tech}`);
907
- if (repo.skills?.length) parts.push(`(skills: ${repo.skills.join(", ")})`);
908
- sections.push(parts.join(" "));
909
- if (repo.commands) {
910
- const cmds = Object.entries(repo.commands).filter(([, v]) => v).map(([k, v]) => `\`${k}\`: \`${v}\``).join(", ");
911
- if (cmds) sections.push(` Commands: ${cmds}`);
912
- }
913
- }
914
- if (prompt?.sections?.after_repositories) {
915
- sections.push(`
916
- ${prompt.sections.after_repositories.trim()}`);
917
- }
918
- const docStructure = buildDocumentStructure(steps, taskFolder);
919
- sections.push(docStructure);
920
- const pipelineSection = buildPipelineSection(steps);
921
- sections.push(pipelineSection);
922
- if (prompt?.sections?.after_pipeline) {
923
- sections.push(`
924
- ${prompt.sections.after_pipeline.trim()}`);
925
- }
926
- if (config.integrations?.slack || config.integrations?.github) {
927
- sections.push(buildDeliverySection(config));
928
- }
929
- if (prompt?.sections?.after_delivery) {
930
- sections.push(`
931
- ${prompt.sections.after_delivery.trim()}`);
932
- }
933
- if (config.memory) {
934
- sections.push(`
935
- ## Team Memory
936
-
937
- This workspace has a team memory knowledge base available via the \`team-memory\` MCP.
938
-
939
- **Before starting any task**, use \`search_memories\` to find relevant context \u2014 past decisions, conventions, known issues, and domain knowledge. This avoids repeating mistakes and ensures consistency with previous choices.
940
-
941
- **After completing a task**, if you discovered something valuable (a decision, a gotcha, a convention, domain insight), use \`add_memory\` to capture it for the team.
942
-
943
- Available tools: \`search_memories\`, \`get_memory\`, \`add_memory\`, \`list_memories\`, \`archive_memory\`, \`remove_memory\`.`);
944
- }
945
- sections.push(`
946
- ## Troubleshooting and Debugging
947
-
948
- For bug reports or unexpected behavior, use the \`debugger\` agent directly.
949
- It will:
950
- 1. Collect context (symptoms, environment, timeline)
951
- 2. Analyze logs and stack traces
952
- 3. Form and test hypotheses systematically
953
- 4. Identify the root cause
954
- 5. Propose a solution or call coding agents to implement the fix`);
955
- if (prompt?.sections) {
956
- const reservedKeys = /* @__PURE__ */ new Set(["after_repositories", "after_pipeline", "after_delivery"]);
957
- for (const [name, content] of Object.entries(prompt.sections)) {
958
- if (reservedKeys.has(name)) continue;
959
- const title = name.split(/[-_]/).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
960
- sections.push(`
961
- ## ${title}
962
-
963
- ${content.trim()}`);
964
- }
965
- }
966
- if (prompt?.append) {
967
- sections.push(`
968
- ${prompt.append.trim()}`);
969
- }
970
- return sections.join("\n");
971
- }
972
- function buildDocumentStructure(steps, taskFolder) {
973
- const outputs = [];
974
- for (const step of steps) {
975
- if (step.output) {
976
- outputs.push(step.output);
977
- }
978
- if (Array.isArray(step.agents)) {
979
- for (const a of step.agents) {
980
- if (typeof a === "object" && a.output) {
981
- outputs.push(a.output);
982
- }
983
- }
984
- }
985
- }
986
- if (outputs.length === 0) {
987
- outputs.push("refinement.md", "code-backend.md", "code-frontend.md", "code-review.md", "qa-backend.md", "qa-frontend.md");
988
- }
989
- const tree = outputs.map((o) => `\u251C\u2500\u2500 ${o}`);
990
- if (tree.length > 0) {
991
- tree[tree.length - 1] = tree[tree.length - 1].replace("\u251C\u2500\u2500", "\u2514\u2500\u2500");
992
- }
993
- return `
994
- ## Document Structure
995
-
996
- All task documents are stored in \`${taskFolder}\`:
997
-
998
- \`\`\`
999
- ${taskFolder}
1000
- ${tree.join("\n")}
1001
- \`\`\``;
1002
- }
1003
- function buildPipelineSection(steps) {
1004
- if (steps.length === 0) {
1005
- return `
1006
- ## Development Pipeline
1007
-
1008
- 1. Use the \`refinement\` agent to collect requirements
1009
- 2. Use \`coding-backend\` and/or \`coding-frontend\` agents to implement
1010
- 3. Use \`code-reviewer\` to review the implementation
1011
- 4. Use \`qa-backend\` and/or \`qa-frontend\` to test
1012
- 5. Create PRs and notify the team`;
1013
- }
1014
- const parts = [`
1015
- ## Development Pipeline
1016
- `];
1017
- for (const step of steps) {
1018
- if (step.actions) {
1019
- parts.push(`### Delivery`);
1020
- parts.push(`After all validations pass, execute these actions:`);
1021
- for (const action of step.actions) {
1022
- parts.push(`- ${formatAction(action)}`);
1023
- }
1024
- continue;
1025
- }
1026
- const stepTitle = step.step.charAt(0).toUpperCase() + step.step.slice(1);
1027
- parts.push(`### ${stepTitle}`);
1028
- if (step.mode === "plan") {
1029
- parts.push(`**Before starting this step, switch to Plan Mode** by calling \`SwitchMode\` with \`target_mode_id: "plan"\`. This ensures collaborative planning with the user in a read-only context before any implementation begins.`);
1030
- parts.push(``);
1031
- }
1032
- if (step.agent) {
1033
- parts.push(`Call the \`${step.agent}\` agent.${step.output ? ` It writes to \`${step.output}\`.` : ""}`);
1034
- if (step.step === "refinement") {
1035
- parts.push(`
1036
- After it runs, read the document and validate with the user:
1037
- - If there are unanswered questions, ask the user one at a time
1038
- - If the user requests adjustments, send back to the refinement agent
1039
- - Do not proceed until the document is complete and approved by the user`);
1040
- }
1041
- }
1042
- if (Array.isArray(step.agents)) {
1043
- const agentList = step.agents.map((a) => {
1044
- if (typeof a === "string") return { agent: a };
1045
- return a;
1046
- });
1047
- if (step.parallel) {
1048
- parts.push(`Call these agents${step.parallel ? " in parallel" : ""}:`);
1049
- } else {
1050
- parts.push(`Call these agents in sequence:`);
1051
- }
1052
- for (const a of agentList) {
1053
- let line = `- \`${a.agent}\``;
1054
- if (a.output) line += ` \u2192 writes to \`${a.output}\``;
1055
- if (a.when) line += ` (when: ${a.when})`;
1056
- parts.push(line);
1057
- }
1058
- if (step.step === "coding" || step.step === "code" || step.step === "implementation") {
1059
- parts.push(`
1060
- If any coding agent has doubts, they will write questions in their document. Apply the same Q&A logic as refinement \u2014 validate with the user before proceeding.`);
1061
- }
1062
- if (step.step === "validation" || step.step === "review" || step.step === "qa") {
1063
- parts.push(`
1064
- If any validation agent leaves comments requiring fixes, call the relevant coding agents again to address them.`);
1065
- }
1066
- }
1067
- if (step.mode === "plan") {
1068
- parts.push(`
1069
- **After this step is complete and approved**, switch back to Agent Mode to proceed with the next step.`);
1070
- }
1071
- parts.push("");
1072
- }
1073
- return parts.join("\n");
1074
- }
1075
- function buildDeliverySection(config) {
1076
- const parts = [`
1077
- ## Delivery Details
1078
- `];
1079
- if (config.integrations?.github) {
1080
- const gh = config.integrations.github;
1081
- parts.push(`### Pull Requests`);
1082
- parts.push(`For each repository with changes, push the branch and create a PR using the GitHub MCP.`);
1083
- if (gh.pr_branch_pattern) {
1084
- parts.push(`Branch naming pattern: \`${gh.pr_branch_pattern}\``);
1085
- }
1086
- }
1087
- if (config.integrations?.slack) {
1088
- const slack = config.integrations.slack;
1089
- if (slack.channels) {
1090
- parts.push(`
1091
- ### Slack Notifications`);
1092
- for (const [purpose, channel] of Object.entries(slack.channels)) {
1093
- parts.push(`- **${purpose}**: Post to \`${channel}\``);
1094
- }
1095
- }
1096
- if (slack.templates) {
1097
- parts.push(`
1098
- Message templates:`);
1099
- for (const [name, template] of Object.entries(slack.templates)) {
1100
- parts.push(`- **${name}**: \`${template}\``);
1101
- }
1102
- }
1103
- }
1104
- if (config.integrations?.linear) {
1105
- parts.push(`
1106
- ### Task Management`);
1107
- parts.push(`Update the Linear task status after PR creation.`);
1108
- }
1109
- return parts.join("\n");
1110
- }
1111
- function formatAction(action) {
1112
- const map = {
1113
- "create-pr": "Create pull requests for each repository with changes",
1114
- "notify-slack": "Send notification to the configured Slack channel",
1115
- "notify-slack-prs": "Send PR notification to the Slack PRs channel",
1116
- "update-linear": "Update the Linear task status",
1117
- "update-linear-status": "Update the Linear task status to Review",
1118
- "update-jira": "Update the Jira task status"
1119
- };
1120
- return map[action] || action;
1121
- }
1122
- async function generateClaudeCode(config, hubDir) {
1123
- const claudeDir = join5(hubDir, ".claude");
1124
- await mkdir2(join5(claudeDir, "agents"), { recursive: true });
1125
- const orchestratorRule = buildOrchestratorRule(config);
1126
- const cleanedOrchestrator = orchestratorRule.replace(/^---[\s\S]*?---\n/m, "").trim();
1127
- const claudeMdSections = [];
1128
- claudeMdSections.push(cleanedOrchestrator);
1129
- const agentsDir = resolve(hubDir, "agents");
1130
- try {
1131
- const agentFiles = await readdir(agentsDir);
1132
- const mdFiles = agentFiles.filter((f) => f.endsWith(".md"));
1133
- for (const file of mdFiles) {
1134
- await copyFile(join5(agentsDir, file), join5(claudeDir, "agents", file));
1135
- }
1136
- console.log(chalk4.green(` Copied ${mdFiles.length} agents to .claude/agents/`));
1137
- } catch {
1138
- console.log(chalk4.yellow(" No agents/ directory found, skipping agent copy"));
1139
- }
1140
- const skillsDir = resolve(hubDir, "skills");
1141
- try {
1142
- const skillFolders = await readdir(skillsDir);
1143
- const claudeSkillsDir = join5(claudeDir, "skills");
1144
- await mkdir2(claudeSkillsDir, { recursive: true });
1145
- let count = 0;
1146
- for (const folder of skillFolders) {
1147
- const skillFile = join5(skillsDir, folder, "SKILL.md");
1148
- try {
1149
- await readFile3(skillFile);
1150
- const srcDir = join5(skillsDir, folder);
1151
- const targetDir = join5(claudeSkillsDir, folder);
1152
- await cp(srcDir, targetDir, { recursive: true });
1153
- count++;
1154
- } catch {
1155
- }
1156
- }
1157
- if (count > 0) {
1158
- console.log(chalk4.green(` Copied ${count} skills to .claude/skills/`));
1159
- }
1160
- } catch {
1161
- }
1162
- await writeFile4(join5(hubDir, "CLAUDE.md"), claudeMdSections.join("\n"), "utf-8");
1163
- console.log(chalk4.green(" Generated CLAUDE.md"));
1164
- if (config.mcps?.length) {
1165
- const mcpJson = {};
1166
- for (const mcp of config.mcps) {
1167
- mcpJson[mcp.name] = buildClaudeCodeMcpEntry(mcp);
1168
- }
1169
- await writeFile4(
1170
- join5(hubDir, ".mcp.json"),
1171
- JSON.stringify({ mcpServers: mcpJson }, null, 2) + "\n",
1172
- "utf-8"
1173
- );
1174
- console.log(chalk4.green(" Generated .mcp.json"));
1175
- }
1176
- const mcpServerNames = config.mcps?.map((m) => m.name) || [];
1177
- const claudeSettings = {
1178
- $schema: "https://json.schemastore.org/claude-code-settings.json",
1179
- permissions: {
1180
- allow: [
1181
- "Read(*)",
1182
- "Edit(*)",
1183
- "Write(*)",
1184
- "Bash(git *)",
1185
- "Bash(npm *)",
1186
- "Bash(pnpm *)",
1187
- "Bash(npx *)",
1188
- "Bash(ls *)",
1189
- "Bash(echo *)",
1190
- "Bash(grep *)",
1191
- ...mcpServerNames.map((name) => `mcp__${name}__*`)
1192
- ],
1193
- deny: [
1194
- "Read(.env)",
1195
- "Read(.env.*)",
1196
- "Read(**/.env)",
1197
- "Read(**/.env.*)",
1198
- "Read(**/credentials*)",
1199
- "Read(**/secrets*)",
1200
- "Read(**/*.pem)",
1201
- "Read(**/*.key)"
1202
- ]
1203
- },
1204
- enableAllProjectMcpServers: true
1205
- };
1206
- if (config.hooks) {
1207
- const claudeHooks = buildClaudeHooks(config.hooks);
1208
- if (claudeHooks) {
1209
- claudeSettings.hooks = claudeHooks;
1210
- }
1211
- }
1212
- await writeFile4(
1213
- join5(claudeDir, "settings.json"),
1214
- JSON.stringify(claudeSettings, null, 2) + "\n",
1215
- "utf-8"
1216
- );
1217
- console.log(chalk4.green(" Generated .claude/settings.json"));
1218
- const gitignoreLines = buildGitignoreLines(config);
1219
- await writeManagedFile(join5(hubDir, ".gitignore"), gitignoreLines);
1220
- console.log(chalk4.green(" Generated .gitignore"));
1221
- }
1222
- async function generateKiro(config, hubDir) {
1223
- const kiroDir = join5(hubDir, ".kiro");
1224
- const steeringDir = join5(kiroDir, "steering");
1225
- const settingsDir = join5(kiroDir, "settings");
1226
- await mkdir2(steeringDir, { recursive: true });
1227
- await mkdir2(settingsDir, { recursive: true });
1228
- const gitignoreLines = buildGitignoreLines(config);
1229
- await writeManagedFile(join5(hubDir, ".gitignore"), gitignoreLines);
1230
- console.log(chalk4.green(" Generated .gitignore"));
1231
- const kiroRule = buildKiroOrchestratorRule(config);
1232
- const kiroOrchestrator = buildKiroSteeringContent(kiroRule);
1233
- await writeFile4(join5(steeringDir, "orchestrator.md"), kiroOrchestrator, "utf-8");
1234
- console.log(chalk4.green(" Generated .kiro/steering/orchestrator.md"));
1235
- await writeFile4(join5(hubDir, "AGENTS.md"), kiroRule + "\n", "utf-8");
1236
- console.log(chalk4.green(" Generated AGENTS.md"));
1237
- const agentsDir = resolve(hubDir, "agents");
1238
- try {
1239
- const agentFiles = await readdir(agentsDir);
1240
- const mdFiles = agentFiles.filter((f) => f.endsWith(".md"));
1241
- for (const file of mdFiles) {
1242
- const agentContent = await readFile3(join5(agentsDir, file), "utf-8");
1243
- const agentName = file.replace(/\.md$/, "");
1244
- const steeringContent = buildKiroSteeringContent(agentContent, "auto", {
1245
- name: agentName,
1246
- description: `Role-specific instructions for the ${agentName} phase. Include when working on ${agentName}-related tasks.`
1247
- });
1248
- const steeringName = `agent-${file}`;
1249
- await writeFile4(join5(steeringDir, steeringName), steeringContent, "utf-8");
1250
- }
1251
- console.log(chalk4.green(` Copied ${mdFiles.length} agents as steering files`));
1252
- } catch {
1253
- console.log(chalk4.yellow(" No agents/ directory found, skipping agent copy"));
1254
- }
1255
- const skillsDir = resolve(hubDir, "skills");
1256
- try {
1257
- const skillFolders = await readdir(skillsDir);
1258
- const kiroSkillsDir = join5(kiroDir, "skills");
1259
- await mkdir2(kiroSkillsDir, { recursive: true });
1260
- let count = 0;
1261
- for (const folder of skillFolders) {
1262
- const skillFile = join5(skillsDir, folder, "SKILL.md");
1263
- try {
1264
- await readFile3(skillFile);
1265
- const srcDir = join5(skillsDir, folder);
1266
- const targetDir = join5(kiroSkillsDir, folder);
1267
- await cp(srcDir, targetDir, { recursive: true });
1268
- count++;
1269
- } catch {
1270
- }
1271
- }
1272
- if (count > 0) {
1273
- console.log(chalk4.green(` Copied ${count} skills to .kiro/skills/`));
1274
- }
1275
- } catch {
1276
- }
1277
- if (config.mcps?.length) {
1278
- const mcpConfig = {};
1279
- for (const mcp of config.mcps) {
1280
- mcpConfig[mcp.name] = buildKiroMcpEntry(mcp);
1281
- }
1282
- await writeFile4(
1283
- join5(settingsDir, "mcp.json"),
1284
- JSON.stringify({ mcpServers: mcpConfig }, null, 2) + "\n",
1285
- "utf-8"
1286
- );
1287
- console.log(chalk4.green(" Generated .kiro/settings/mcp.json"));
1288
- }
1289
- if (config.hooks) {
1290
- const hookNotes = [];
1291
- for (const [event, entries] of Object.entries(config.hooks)) {
1292
- const mapped = HOOK_EVENT_MAP[event]?.kiro;
1293
- if (!mapped) continue;
1294
- for (const entry of entries) {
1295
- hookNotes.push(`- **${mapped}**: ${entry.type === "command" ? entry.command : entry.prompt}`);
1296
- }
1297
- }
1298
- if (hookNotes.length > 0) {
1299
- console.log(chalk4.yellow(` Note: Kiro hooks are managed via the Kiro panel UI.`));
1300
- console.log(chalk4.yellow(` The following hooks should be configured manually:`));
1301
- for (const note of hookNotes) {
1302
- console.log(chalk4.yellow(` ${note}`));
1303
- }
1304
- }
1305
- }
1306
- }
1307
- function buildGitignoreLines(config) {
1308
- const lines = [
1309
- "node_modules/",
1310
- ".DS_Store",
1311
- "",
1312
- "# Repositories (managed by hub)"
1313
- ];
1314
- for (const repo of config.repos) {
1315
- lines.push(repo.path.replace("./", ""));
1316
- }
1317
- lines.push(
1318
- "",
1319
- "# Docker volumes",
1320
- "*_data/",
1321
- "",
1322
- "# Environment files",
1323
- "*.env",
1324
- "*.env.local",
1325
- "!.env.example",
1326
- "",
1327
- "# Generated files",
1328
- "docker-compose.yml",
1329
- "",
1330
- "# Task documents",
1331
- "tasks/"
1332
- );
1333
- if (config.memory) {
1334
- const memPath = config.memory.path || "memories";
1335
- lines.push(
1336
- "",
1337
- "# Memory vector store (generated from markdown files)",
1338
- `${memPath}/.lancedb/`
1339
- );
1340
- }
1341
- return lines;
1342
- }
1343
- var generators = {
1344
- cursor: { name: "Cursor", generate: generateCursor },
1345
- "claude-code": { name: "Claude Code", generate: generateClaudeCode },
1346
- kiro: { name: "Kiro", generate: generateKiro }
1347
- };
1348
- var generateCommand = new Command4("generate").description("Generate editor-specific configuration files from hub.yaml").option("-e, --editor <editor>", "Target editor (cursor, claude-code, kiro)", "cursor").action(async (opts) => {
1349
- const hubDir = process.cwd();
1350
- const config = await loadHubConfig(hubDir);
1351
- if (config.memory) {
1352
- const hasMemoryMcp = config.mcps?.some(
1353
- (m) => m.name === "team-memory" || m.package === "@arvoretech/memory-mcp"
1354
- );
1355
- if (!hasMemoryMcp) {
1356
- console.log(chalk4.red(`
1357
- Error: 'memory' is configured but no memory MCP is declared in 'mcps'.
1358
- `));
1359
- console.log(chalk4.yellow(` Add this to your hub.yaml:
1360
- `));
1361
- console.log(chalk4.dim(` mcps:`));
1362
- console.log(chalk4.dim(` - name: team-memory`));
1363
- console.log(chalk4.dim(` package: "@arvoretech/memory-mcp"`));
1364
- console.log(chalk4.dim(` env:`));
1365
- console.log(chalk4.dim(` MEMORY_PATH: ${config.memory.path || "./memories"}
1366
- `));
1367
- process.exit(1);
1368
- }
1369
- }
1370
- const generator = generators[opts.editor];
1371
- if (!generator) {
1372
- console.log(
1373
- chalk4.red(`Unknown editor: ${opts.editor}. Available: ${Object.keys(generators).join(", ")}`)
1374
- );
1375
- return;
1376
- }
1377
- console.log(chalk4.blue(`
1378
- Generating ${generator.name} configuration
1379
- `));
1380
- await generator.generate(config, hubDir);
1381
- console.log(chalk4.green("\nDone!\n"));
1382
- });
1383
-
1384
- // src/commands/env.ts
1385
- import { Command as Command5 } from "commander";
1386
- import { existsSync as existsSync4 } from "fs";
1387
- import { writeFile as writeFile5, readFile as readFile4 } from "fs/promises";
1388
- import { join as join6 } from "path";
403
+ import { writeFile as writeFile4, readFile as readFile2 } from "fs/promises";
404
+ import { join as join4 } from "path";
1389
405
  import { execSync as execSync2 } from "child_process";
1390
- import chalk5 from "chalk";
406
+ import chalk4 from "chalk";
1391
407
  var authenticatedProfiles = /* @__PURE__ */ new Set();
1392
408
  function awsAuthenticated(profile) {
1393
409
  if (authenticatedProfiles.has(profile)) return true;
@@ -1434,45 +450,45 @@ function buildDatabaseUrlFromSecret(secretData, buildConfig) {
1434
450
  }
1435
451
  return `mysql://${user}:${password || ""}@${host}:${port}/${database}`;
1436
452
  }
1437
- var envCommand = new Command5("env").description("Generate environment files from hub.yaml profiles").argument("[profile]", "Environment profile (local, staging, prod)", "local").action(async (profile) => {
453
+ var envCommand = new Command4("env").description("Generate environment files from hub.yaml profiles").argument("[profile]", "Environment profile (local, staging, prod)", "local").action(async (profile) => {
1438
454
  const hubDir = process.cwd();
1439
455
  const config = await loadHubConfig(hubDir);
1440
456
  const profiles = config.env?.profiles;
1441
457
  if (!profiles) {
1442
- console.log(chalk5.yellow("\nNo env.profiles defined in hub.yaml\n"));
458
+ console.log(chalk4.yellow("\nNo env.profiles defined in hub.yaml\n"));
1443
459
  return;
1444
460
  }
1445
461
  const profileConfig = profiles[profile];
1446
462
  if (!profileConfig) {
1447
463
  const available = Object.keys(profiles).join(", ");
1448
- console.log(chalk5.red(`
464
+ console.log(chalk4.red(`
1449
465
  Unknown profile: ${profile}. Available: ${available}
1450
466
  `));
1451
467
  return;
1452
468
  }
1453
- console.log(chalk5.blue(`
469
+ console.log(chalk4.blue(`
1454
470
  \u2501\u2501\u2501 Generating environment files (${profile}) \u2501\u2501\u2501
1455
471
  `));
1456
472
  const defaultAwsProfile = profileConfig.aws_profile || "";
1457
473
  const secrets = profileConfig.secrets || {};
1458
474
  const buildDbConfigs = profileConfig.build_database_url || {};
1459
475
  if (profile !== "local" && defaultAwsProfile) {
1460
- console.log(chalk5.cyan(` Default AWS profile: ${defaultAwsProfile}`));
476
+ console.log(chalk4.cyan(` Default AWS profile: ${defaultAwsProfile}`));
1461
477
  if (!awsAuthenticated(defaultAwsProfile)) {
1462
- console.log(chalk5.red(` AWS profile ${defaultAwsProfile} not authenticated`));
1463
- console.log(chalk5.cyan(` Run: aws sso login --profile ${defaultAwsProfile}`));
478
+ console.log(chalk4.red(` AWS profile ${defaultAwsProfile} not authenticated`));
479
+ console.log(chalk4.cyan(` Run: aws sso login --profile ${defaultAwsProfile}`));
1464
480
  return;
1465
481
  }
1466
- console.log(chalk5.green(` AWS authenticated`));
482
+ console.log(chalk4.green(` AWS authenticated`));
1467
483
  }
1468
484
  for (const repo of config.repos) {
1469
485
  if (!repo.env_file) continue;
1470
- const repoDir = join6(hubDir, repo.path);
1471
- if (!existsSync4(repoDir)) {
1472
- console.log(chalk5.dim(` ${repo.name}: repo not cloned, skipping`));
486
+ const repoDir = join4(hubDir, repo.path);
487
+ if (!existsSync3(repoDir)) {
488
+ console.log(chalk4.dim(` ${repo.name}: repo not cloned, skipping`));
1473
489
  continue;
1474
490
  }
1475
- console.log(chalk5.yellow(`\u25B8 ${repo.name}`));
491
+ console.log(chalk4.yellow(`\u25B8 ${repo.name}`));
1476
492
  const envVars = {};
1477
493
  if (profile !== "local" && secrets[repo.name]) {
1478
494
  const { secretName, profile: secretProfile } = resolveSecret(
@@ -1480,20 +496,20 @@ Unknown profile: ${profile}. Available: ${available}
1480
496
  defaultAwsProfile
1481
497
  );
1482
498
  if (!secretProfile) {
1483
- console.log(chalk5.red(` No AWS profile available for secret: ${secretName}`));
499
+ console.log(chalk4.red(` No AWS profile available for secret: ${secretName}`));
1484
500
  } else {
1485
501
  if (!awsAuthenticated(secretProfile)) {
1486
- console.log(chalk5.red(` AWS profile ${secretProfile} not authenticated`));
1487
- console.log(chalk5.cyan(` Run: aws sso login --profile ${secretProfile}`));
502
+ console.log(chalk4.red(` AWS profile ${secretProfile} not authenticated`));
503
+ console.log(chalk4.cyan(` Run: aws sso login --profile ${secretProfile}`));
1488
504
  continue;
1489
505
  }
1490
- console.log(chalk5.cyan(` Fetching: ${secretName} (profile: ${secretProfile})`));
506
+ console.log(chalk4.cyan(` Fetching: ${secretName} (profile: ${secretProfile})`));
1491
507
  const secretData = fetchSecret(secretName, secretProfile);
1492
508
  if (secretData) {
1493
509
  Object.assign(envVars, secretData);
1494
- console.log(chalk5.green(` Loaded ${Object.keys(secretData).length} vars from AWS`));
510
+ console.log(chalk4.green(` Loaded ${Object.keys(secretData).length} vars from AWS`));
1495
511
  } else {
1496
- console.log(chalk5.red(` Failed to fetch secret: ${secretName}`));
512
+ console.log(chalk4.red(` Failed to fetch secret: ${secretName}`));
1497
513
  }
1498
514
  }
1499
515
  }
@@ -1501,25 +517,25 @@ Unknown profile: ${profile}. Available: ${available}
1501
517
  const buildConfig = buildDbConfigs[repo.name];
1502
518
  const dbProfile = buildConfig.profile || defaultAwsProfile;
1503
519
  if (!dbProfile) {
1504
- console.log(chalk5.red(` No AWS profile available for build_database_url`));
520
+ console.log(chalk4.red(` No AWS profile available for build_database_url`));
1505
521
  } else {
1506
522
  if (!awsAuthenticated(dbProfile)) {
1507
- console.log(chalk5.red(` AWS profile ${dbProfile} not authenticated`));
1508
- console.log(chalk5.cyan(` Run: aws sso login --profile ${dbProfile}`));
523
+ console.log(chalk4.red(` AWS profile ${dbProfile} not authenticated`));
524
+ console.log(chalk4.cyan(` Run: aws sso login --profile ${dbProfile}`));
1509
525
  } else {
1510
- console.log(chalk5.cyan(` Building DATABASE_URL from ${buildConfig.from_secret} (profile: ${dbProfile})`));
526
+ console.log(chalk4.cyan(` Building DATABASE_URL from ${buildConfig.from_secret} (profile: ${dbProfile})`));
1511
527
  const dbSecretData = fetchSecret(buildConfig.from_secret, dbProfile);
1512
528
  if (dbSecretData) {
1513
529
  const dbUrl = buildDatabaseUrlFromSecret(dbSecretData, buildConfig);
1514
530
  if (dbUrl) {
1515
531
  envVars["DATABASE_URL"] = dbUrl;
1516
532
  envVars["IDENTITY_DATABASE_URL"] = dbUrl;
1517
- console.log(chalk5.green(` Built DATABASE_URL from ${buildConfig.from_secret}`));
533
+ console.log(chalk4.green(` Built DATABASE_URL from ${buildConfig.from_secret}`));
1518
534
  } else {
1519
- console.log(chalk5.red(` Could not build DATABASE_URL - missing required fields`));
535
+ console.log(chalk4.red(` Could not build DATABASE_URL - missing required fields`));
1520
536
  }
1521
537
  } else {
1522
- console.log(chalk5.red(` Failed to fetch secret: ${buildConfig.from_secret}`));
538
+ console.log(chalk4.red(` Failed to fetch secret: ${buildConfig.from_secret}`));
1523
539
  }
1524
540
  }
1525
541
  }
@@ -1529,12 +545,12 @@ Unknown profile: ${profile}. Available: ${available}
1529
545
  for (const [key, value] of Object.entries(overrides)) {
1530
546
  envVars[key] = value;
1531
547
  }
1532
- console.log(chalk5.cyan(` Applied ${Object.keys(overrides).length} overrides`));
548
+ console.log(chalk4.cyan(` Applied ${Object.keys(overrides).length} overrides`));
1533
549
  }
1534
- const envPath = join6(repoDir, repo.env_file);
550
+ const envPath = join4(repoDir, repo.env_file);
1535
551
  const existingVars = {};
1536
552
  try {
1537
- const existing = await readFile4(envPath, "utf-8");
553
+ const existing = await readFile2(envPath, "utf-8");
1538
554
  for (const line of existing.split("\n")) {
1539
555
  const trimmed = line.trim();
1540
556
  if (!trimmed || trimmed.startsWith("#")) continue;
@@ -1547,40 +563,40 @@ Unknown profile: ${profile}. Available: ${available}
1547
563
  }
1548
564
  const merged = { ...existingVars, ...envVars };
1549
565
  const lines = Object.entries(merged).map(([k, v]) => `${k}=${v}`);
1550
- await writeFile5(envPath, lines.join("\n") + "\n", "utf-8");
1551
- console.log(chalk5.green(` Created ${repo.env_file} (${lines.length} vars)`));
566
+ await writeFile4(envPath, lines.join("\n") + "\n", "utf-8");
567
+ console.log(chalk4.green(` Created ${repo.env_file} (${lines.length} vars)`));
1552
568
  }
1553
569
  console.log();
1554
570
  if (profile === "local") {
1555
- console.log(chalk5.cyan("Using local Docker services only"));
1556
- console.log(chalk5.cyan("Run: npx @arvoretech/hub services up"));
571
+ console.log(chalk4.cyan("Using local Docker services only"));
572
+ console.log(chalk4.cyan("Run: npx @arvoretech/hub services up"));
1557
573
  } else if (profile === "prod") {
1558
- console.log(chalk5.red("WARNING: Using PRODUCTION database!"));
1559
- console.log(chalk5.red("Be careful with write operations!"));
574
+ console.log(chalk4.red("WARNING: Using PRODUCTION database!"));
575
+ console.log(chalk4.red("Be careful with write operations!"));
1560
576
  } else {
1561
- console.log(chalk5.cyan(`Using ${profile} environment`));
577
+ console.log(chalk4.cyan(`Using ${profile} environment`));
1562
578
  }
1563
579
  console.log();
1564
580
  });
1565
581
 
1566
582
  // src/commands/services.ts
1567
- import { Command as Command6 } from "commander";
1568
- import { existsSync as existsSync5 } from "fs";
1569
- import { writeFile as writeFile6 } from "fs/promises";
1570
- import { join as join7 } from "path";
583
+ import { Command as Command5 } from "commander";
584
+ import { existsSync as existsSync4 } from "fs";
585
+ import { writeFile as writeFile5 } from "fs/promises";
586
+ import { join as join5 } from "path";
1571
587
  import { execSync as execSync3 } from "child_process";
1572
- import chalk6 from "chalk";
588
+ import chalk5 from "chalk";
1573
589
  async function ensureCompose(hubDir) {
1574
- const composePath = join7(hubDir, "docker-compose.yml");
1575
- if (!existsSync5(composePath)) {
590
+ const composePath = join5(hubDir, "docker-compose.yml");
591
+ if (!existsSync4(composePath)) {
1576
592
  const config = await loadHubConfig(hubDir);
1577
593
  if (!config.services?.length) {
1578
- console.log(chalk6.yellow("No services defined in hub.yaml"));
594
+ console.log(chalk5.yellow("No services defined in hub.yaml"));
1579
595
  process.exit(1);
1580
596
  }
1581
597
  const content = generateDockerCompose(config.services);
1582
- await writeFile6(composePath, content, "utf-8");
1583
- console.log(chalk6.green("Generated docker-compose.yml"));
598
+ await writeFile5(composePath, content, "utf-8");
599
+ console.log(chalk5.green("Generated docker-compose.yml"));
1584
600
  }
1585
601
  return composePath;
1586
602
  }
@@ -1592,10 +608,10 @@ function isDockerRunning() {
1592
608
  return false;
1593
609
  }
1594
610
  }
1595
- var servicesCommand = new Command6("services").description("Manage Docker development services").argument("[action]", "up, down, restart, ps, logs, clean", "up").argument("[service...]", "Specific services (for logs)").action(async (action, serviceNames) => {
611
+ var servicesCommand = new Command5("services").description("Manage Docker development services").argument("[action]", "up, down, restart, ps, logs, clean", "up").argument("[service...]", "Specific services (for logs)").action(async (action, serviceNames) => {
1596
612
  if (!isDockerRunning()) {
1597
- console.log(chalk6.red("\nDocker daemon is not running."));
1598
- console.log(chalk6.dim("Start Docker Desktop or the Docker daemon and try again.\n"));
613
+ console.log(chalk5.red("\nDocker daemon is not running."));
614
+ console.log(chalk5.dim("Start Docker Desktop or the Docker daemon and try again.\n"));
1599
615
  return;
1600
616
  }
1601
617
  const hubDir = process.cwd();
@@ -1605,26 +621,26 @@ var servicesCommand = new Command6("services").description("Manage Docker develo
1605
621
  switch (action) {
1606
622
  case "up":
1607
623
  case "start": {
1608
- console.log(chalk6.blue("\nStarting services\n"));
624
+ console.log(chalk5.blue("\nStarting services\n"));
1609
625
  execSync3(`${compose} up -d`, { stdio: "inherit", cwd: hubDir });
1610
626
  const config = await loadHubConfig(hubDir);
1611
- console.log(chalk6.green("\nServices running:"));
627
+ console.log(chalk5.green("\nServices running:"));
1612
628
  for (const svc of config.services || []) {
1613
629
  const port = svc.port || svc.ports?.[0];
1614
- if (port) console.log(chalk6.cyan(` ${svc.name}: localhost:${port}`));
630
+ if (port) console.log(chalk5.cyan(` ${svc.name}: localhost:${port}`));
1615
631
  }
1616
632
  console.log();
1617
633
  break;
1618
634
  }
1619
635
  case "down":
1620
636
  case "stop":
1621
- console.log(chalk6.blue("\nStopping services\n"));
637
+ console.log(chalk5.blue("\nStopping services\n"));
1622
638
  execSync3(`${compose} down`, { stdio: "inherit", cwd: hubDir });
1623
- console.log(chalk6.green("\nServices stopped\n"));
639
+ console.log(chalk5.green("\nServices stopped\n"));
1624
640
  break;
1625
641
  case "restart":
1626
642
  execSync3(`${compose} restart`, { stdio: "inherit", cwd: hubDir });
1627
- console.log(chalk6.green("\nServices restarted\n"));
643
+ console.log(chalk5.green("\nServices restarted\n"));
1628
644
  break;
1629
645
  case "ps":
1630
646
  case "status":
@@ -1638,34 +654,34 @@ var servicesCommand = new Command6("services").description("Manage Docker develo
1638
654
  }
1639
655
  break;
1640
656
  case "clean":
1641
- console.log(chalk6.blue("\nCleaning services (removing volumes)\n"));
657
+ console.log(chalk5.blue("\nCleaning services (removing volumes)\n"));
1642
658
  execSync3(`${compose} down -v`, { stdio: "inherit", cwd: hubDir });
1643
- console.log(chalk6.green("\nServices and volumes removed\n"));
659
+ console.log(chalk5.green("\nServices and volumes removed\n"));
1644
660
  break;
1645
661
  default:
1646
- console.log(chalk6.red(`Unknown action: ${action}`));
662
+ console.log(chalk5.red(`Unknown action: ${action}`));
1647
663
  console.log("Usage: hub services [up|down|restart|ps|logs|clean]");
1648
664
  process.exit(1);
1649
665
  }
1650
666
  } catch {
1651
- console.log(chalk6.red("\nFailed to execute docker compose command."));
1652
- console.log(chalk6.dim("Check if Docker is running and the docker-compose.yml is valid.\n"));
667
+ console.log(chalk5.red("\nFailed to execute docker compose command."));
668
+ console.log(chalk5.dim("Check if Docker is running and the docker-compose.yml is valid.\n"));
1653
669
  }
1654
670
  });
1655
671
 
1656
672
  // src/commands/skills.ts
1657
- import { Command as Command8 } from "commander";
1658
- import { existsSync as existsSync6, statSync } from "fs";
1659
- import { mkdir as mkdir4, readdir as readdir2, readFile as readFile5, rm, cp as cp2 } from "fs/promises";
1660
- import { join as join9, resolve as resolve2 } from "path";
673
+ import { Command as Command7 } from "commander";
674
+ import { existsSync as existsSync5, statSync } from "fs";
675
+ import { mkdir as mkdir3, readdir, readFile as readFile3, rm, cp } from "fs/promises";
676
+ import { join as join7, resolve } from "path";
1661
677
  import { execSync as execSync4 } from "child_process";
1662
- import chalk8 from "chalk";
678
+ import chalk7 from "chalk";
1663
679
 
1664
680
  // src/commands/registry.ts
1665
- import { Command as Command7 } from "commander";
1666
- import { mkdir as mkdir3, writeFile as writeFile7 } from "fs/promises";
1667
- import { join as join8 } from "path";
1668
- import chalk7 from "chalk";
681
+ import { Command as Command6 } from "commander";
682
+ import { mkdir as mkdir2, writeFile as writeFile6 } from "fs/promises";
683
+ import { join as join6 } from "path";
684
+ import chalk6 from "chalk";
1669
685
  var DEFAULT_REGISTRY_REPO = process.env.HUB_REGISTRY || "arvoreeducacao/rhm";
1670
686
  var DEFAULT_BRANCH = "main";
1671
687
  async function downloadDirFromGitHub(repo, remotePath, destDir, branch = DEFAULT_BRANCH) {
@@ -1680,15 +696,15 @@ async function downloadDirFromGitHub(repo, remotePath, destDir, branch = DEFAULT
1680
696
  throw new Error(`GitHub API error: ${res.status} ${res.statusText}`);
1681
697
  }
1682
698
  const items = await res.json();
1683
- await mkdir3(destDir, { recursive: true });
699
+ await mkdir2(destDir, { recursive: true });
1684
700
  for (const item of items) {
1685
701
  if (item.type === "file" && item.download_url) {
1686
702
  const fileRes = await fetch(item.download_url);
1687
703
  if (!fileRes.ok) continue;
1688
704
  const content = await fileRes.text();
1689
- await writeFile7(join8(destDir, item.name), content, "utf-8");
705
+ await writeFile6(join6(destDir, item.name), content, "utf-8");
1690
706
  } else if (item.type === "dir") {
1691
- await downloadDirFromGitHub(repo, item.path, join8(destDir, item.name), branch);
707
+ await downloadDirFromGitHub(repo, item.path, join6(destDir, item.name), branch);
1692
708
  }
1693
709
  }
1694
710
  }
@@ -1790,10 +806,10 @@ async function listRegistryCommands(repo) {
1790
806
  return commands;
1791
807
  }
1792
808
  var TYPE_LABELS = {
1793
- skill: (t) => chalk7.green(t),
1794
- agent: (t) => chalk7.blue(t),
1795
- hook: (t) => chalk7.magenta(t),
1796
- command: (t) => chalk7.cyan(t)
809
+ skill: (t) => chalk6.green(t),
810
+ agent: (t) => chalk6.blue(t),
811
+ hook: (t) => chalk6.magenta(t),
812
+ command: (t) => chalk6.cyan(t)
1797
813
  };
1798
814
  var INSTALL_HINTS = {
1799
815
  skill: "hub skills add <name>",
@@ -1801,10 +817,10 @@ var INSTALL_HINTS = {
1801
817
  hook: "hub hooks add <name>",
1802
818
  command: "hub commands add <name>"
1803
819
  };
1804
- var registryCommand = new Command7("registry").description("Browse and install skills, agents, hooks, and commands from the registry").option("-r, --repo <repo>", "Registry repository (owner/repo)", DEFAULT_REGISTRY_REPO).addCommand(
1805
- new Command7("search").description("Search the registry").argument("[query]", "Search term").option("-t, --type <type>", "Filter by type (skill, agent, hook, command)").action(async (query, opts) => {
820
+ var registryCommand = new Command6("registry").description("Browse and install skills, agents, hooks, and commands from the registry").option("-r, --repo <repo>", "Registry repository (owner/repo)", DEFAULT_REGISTRY_REPO).addCommand(
821
+ new Command6("search").description("Search the registry").argument("[query]", "Search term").option("-t, --type <type>", "Filter by type (skill, agent, hook, command)").action(async (query, opts) => {
1806
822
  const repo = registryCommand.opts().repo || DEFAULT_REGISTRY_REPO;
1807
- console.log(chalk7.blue(`
823
+ console.log(chalk6.blue(`
1808
824
  \u2501\u2501\u2501 Hub Registry (${repo}) \u2501\u2501\u2501
1809
825
  `));
1810
826
  const results = [];
@@ -1814,7 +830,7 @@ var registryCommand = new Command7("registry").description("Browse and install s
1814
830
  const skills = await listRegistrySkills(repo);
1815
831
  for (const s of skills) results.push({ type: "skill", ...s });
1816
832
  } catch {
1817
- console.log(chalk7.yellow(" Could not fetch skills from registry."));
833
+ console.log(chalk6.yellow(" Could not fetch skills from registry."));
1818
834
  }
1819
835
  }
1820
836
  if (!typeFilter || typeFilter === "agent") {
@@ -1822,7 +838,7 @@ var registryCommand = new Command7("registry").description("Browse and install s
1822
838
  const agents = await listRegistryAgents(repo);
1823
839
  for (const a of agents) results.push({ type: "agent", ...a });
1824
840
  } catch {
1825
- console.log(chalk7.yellow(" Could not fetch agents from registry."));
841
+ console.log(chalk6.yellow(" Could not fetch agents from registry."));
1826
842
  }
1827
843
  }
1828
844
  if (!typeFilter || typeFilter === "hook") {
@@ -1830,7 +846,7 @@ var registryCommand = new Command7("registry").description("Browse and install s
1830
846
  const hooks = await listRegistryHooks(repo);
1831
847
  for (const h of hooks) results.push({ type: "hook", ...h });
1832
848
  } catch {
1833
- console.log(chalk7.yellow(" Could not fetch hooks from registry."));
849
+ console.log(chalk6.yellow(" Could not fetch hooks from registry."));
1834
850
  }
1835
851
  }
1836
852
  if (!typeFilter || typeFilter === "command") {
@@ -1838,7 +854,7 @@ var registryCommand = new Command7("registry").description("Browse and install s
1838
854
  const commands = await listRegistryCommands(repo);
1839
855
  for (const c of commands) results.push({ type: "command", ...c });
1840
856
  } catch {
1841
- console.log(chalk7.yellow(" Could not fetch commands from registry."));
857
+ console.log(chalk6.yellow(" Could not fetch commands from registry."));
1842
858
  }
1843
859
  }
1844
860
  let filtered = results;
@@ -1849,28 +865,28 @@ var registryCommand = new Command7("registry").description("Browse and install s
1849
865
  );
1850
866
  }
1851
867
  if (filtered.length === 0) {
1852
- console.log(chalk7.dim(" No results found.\n"));
868
+ console.log(chalk6.dim(" No results found.\n"));
1853
869
  return;
1854
870
  }
1855
871
  for (const entry of filtered) {
1856
872
  const labelFn = TYPE_LABELS[entry.type] || ((t) => t);
1857
- console.log(` ${labelFn(`[${entry.type}]`)} ${chalk7.yellow(entry.name)}`);
873
+ console.log(` ${labelFn(`[${entry.type}]`)} ${chalk6.yellow(entry.name)}`);
1858
874
  if (entry.description) console.log(` ${entry.description}`);
1859
875
  console.log();
1860
876
  }
1861
- console.log(chalk7.cyan(` ${filtered.length} result(s)
877
+ console.log(chalk6.cyan(` ${filtered.length} result(s)
1862
878
  `));
1863
879
  const types = [...new Set(filtered.map((e) => e.type))];
1864
880
  for (const type of types) {
1865
881
  const hint = INSTALL_HINTS[type];
1866
- if (hint) console.log(chalk7.dim(` Install ${type}: ${hint}`));
882
+ if (hint) console.log(chalk6.dim(` Install ${type}: ${hint}`));
1867
883
  }
1868
884
  console.log();
1869
885
  })
1870
886
  ).addCommand(
1871
- new Command7("list").description("List everything in the registry").option("-t, --type <type>", "Filter by type (skill, agent, hook, command)").action(async (opts) => {
887
+ new Command6("list").description("List everything in the registry").option("-t, --type <type>", "Filter by type (skill, agent, hook, command)").action(async (opts) => {
1872
888
  const repo = registryCommand.opts().repo || DEFAULT_REGISTRY_REPO;
1873
- console.log(chalk7.blue(`
889
+ console.log(chalk6.blue(`
1874
890
  \u2501\u2501\u2501 Hub Registry (${repo}) \u2501\u2501\u2501
1875
891
  `));
1876
892
  const typeFilter = opts?.type;
@@ -1878,56 +894,56 @@ var registryCommand = new Command7("registry").description("Browse and install s
1878
894
  try {
1879
895
  const skills = await listRegistrySkills(repo);
1880
896
  if (skills.length) {
1881
- console.log(chalk7.green(`Skills (${skills.length}):`));
897
+ console.log(chalk6.green(`Skills (${skills.length}):`));
1882
898
  for (const s of skills) {
1883
- console.log(` ${chalk7.yellow(s.name)}${s.description ? ` \u2014 ${s.description}` : ""}`);
899
+ console.log(` ${chalk6.yellow(s.name)}${s.description ? ` \u2014 ${s.description}` : ""}`);
1884
900
  }
1885
901
  console.log();
1886
902
  }
1887
903
  } catch {
1888
- console.log(chalk7.yellow(" Could not fetch skills.\n"));
904
+ console.log(chalk6.yellow(" Could not fetch skills.\n"));
1889
905
  }
1890
906
  }
1891
907
  if (!typeFilter || typeFilter === "agent") {
1892
908
  try {
1893
909
  const agents = await listRegistryAgents(repo);
1894
910
  if (agents.length) {
1895
- console.log(chalk7.blue(`Agents (${agents.length}):`));
911
+ console.log(chalk6.blue(`Agents (${agents.length}):`));
1896
912
  for (const a of agents) {
1897
- console.log(` ${chalk7.yellow(a.name)}${a.description ? ` \u2014 ${a.description}` : ""}`);
913
+ console.log(` ${chalk6.yellow(a.name)}${a.description ? ` \u2014 ${a.description}` : ""}`);
1898
914
  }
1899
915
  console.log();
1900
916
  }
1901
917
  } catch {
1902
- console.log(chalk7.yellow(" Could not fetch agents.\n"));
918
+ console.log(chalk6.yellow(" Could not fetch agents.\n"));
1903
919
  }
1904
920
  }
1905
921
  if (!typeFilter || typeFilter === "hook") {
1906
922
  try {
1907
923
  const hooks = await listRegistryHooks(repo);
1908
924
  if (hooks.length) {
1909
- console.log(chalk7.magenta(`Hooks (${hooks.length}):`));
925
+ console.log(chalk6.magenta(`Hooks (${hooks.length}):`));
1910
926
  for (const h of hooks) {
1911
- console.log(` ${chalk7.yellow(h.name)}${h.description ? ` \u2014 ${h.description}` : ""}`);
927
+ console.log(` ${chalk6.yellow(h.name)}${h.description ? ` \u2014 ${h.description}` : ""}`);
1912
928
  }
1913
929
  console.log();
1914
930
  }
1915
931
  } catch {
1916
- console.log(chalk7.yellow(" Could not fetch hooks.\n"));
932
+ console.log(chalk6.yellow(" Could not fetch hooks.\n"));
1917
933
  }
1918
934
  }
1919
935
  if (!typeFilter || typeFilter === "command") {
1920
936
  try {
1921
937
  const commands = await listRegistryCommands(repo);
1922
938
  if (commands.length) {
1923
- console.log(chalk7.cyan(`Commands (${commands.length}):`));
939
+ console.log(chalk6.cyan(`Commands (${commands.length}):`));
1924
940
  for (const c of commands) {
1925
- console.log(` ${chalk7.yellow(c.name)}${c.description ? ` \u2014 ${c.description}` : ""}`);
941
+ console.log(` ${chalk6.yellow(c.name)}${c.description ? ` \u2014 ${c.description}` : ""}`);
1926
942
  }
1927
943
  console.log();
1928
944
  }
1929
945
  } catch {
1930
- console.log(chalk7.yellow(" Could not fetch commands.\n"));
946
+ console.log(chalk6.yellow(" Could not fetch commands.\n"));
1931
947
  }
1932
948
  }
1933
949
  })
@@ -1936,17 +952,17 @@ var registryCommand = new Command7("registry").description("Browse and install s
1936
952
  // src/commands/skills.ts
1937
953
  var DEFAULT_REGISTRY_REPO2 = process.env.HUB_REGISTRY || "arvoreeducacao/rhm";
1938
954
  function tmpDir() {
1939
- return join9(process.env.TMPDIR || "/tmp", `hub-skills-${Date.now()}`);
955
+ return join7(process.env.TMPDIR || "/tmp", `hub-skills-${Date.now()}`);
1940
956
  }
1941
957
  async function listLocalSkills(hubDir) {
1942
- const skillsDir = join9(hubDir, "skills");
958
+ const skillsDir = join7(hubDir, "skills");
1943
959
  const skills = [];
1944
- if (!existsSync6(skillsDir)) return skills;
1945
- const folders = await readdir2(skillsDir);
960
+ if (!existsSync5(skillsDir)) return skills;
961
+ const folders = await readdir(skillsDir);
1946
962
  for (const folder of folders) {
1947
- const skillFile = join9(skillsDir, folder, "SKILL.md");
1948
- if (!existsSync6(skillFile)) continue;
1949
- const content = await readFile5(skillFile, "utf-8");
963
+ const skillFile = join7(skillsDir, folder, "SKILL.md");
964
+ if (!existsSync5(skillFile)) continue;
965
+ const content = await readFile3(skillFile, "utf-8");
1950
966
  const descMatch = content.match(/^description:\s*(.+)$/m);
1951
967
  skills.push({
1952
968
  name: folder,
@@ -1956,23 +972,23 @@ async function listLocalSkills(hubDir) {
1956
972
  return skills;
1957
973
  }
1958
974
  async function findSkillFolders(rootDir) {
1959
- const skillsDir = join9(rootDir, "skills");
1960
- if (existsSync6(skillsDir)) {
1961
- const entries = await readdir2(skillsDir);
975
+ const skillsDir = join7(rootDir, "skills");
976
+ if (existsSync5(skillsDir)) {
977
+ const entries = await readdir(skillsDir);
1962
978
  const folders = entries.filter(
1963
- (f) => existsSync6(join9(skillsDir, f, "SKILL.md"))
979
+ (f) => existsSync5(join7(skillsDir, f, "SKILL.md"))
1964
980
  );
1965
981
  if (folders.length > 0) return { dir: skillsDir, folders };
1966
982
  }
1967
- if (existsSync6(rootDir)) {
1968
- const entries = await readdir2(rootDir);
983
+ if (existsSync5(rootDir)) {
984
+ const entries = await readdir(rootDir);
1969
985
  const folders = entries.filter(
1970
- (f) => !f.startsWith(".") && f !== "node_modules" && existsSync6(join9(rootDir, f, "SKILL.md"))
986
+ (f) => !f.startsWith(".") && f !== "node_modules" && existsSync5(join7(rootDir, f, "SKILL.md"))
1971
987
  );
1972
988
  if (folders.length > 0) return { dir: rootDir, folders };
1973
989
  }
1974
- if (existsSync6(join9(rootDir, "SKILL.md"))) {
1975
- return { dir: join9(rootDir, ".."), folders: [rootDir.split("/").pop()] };
990
+ if (existsSync5(join7(rootDir, "SKILL.md"))) {
991
+ return { dir: join7(rootDir, ".."), folders: [rootDir.split("/").pop()] };
1976
992
  }
1977
993
  return { dir: skillsDir, folders: [] };
1978
994
  }
@@ -1980,24 +996,24 @@ async function installSkillsFromDir(sourceSkillsDir, hubDir, opts) {
1980
996
  const rootDir = sourceSkillsDir.endsWith("/skills") ? sourceSkillsDir.replace(/\/skills$/, "") : sourceSkillsDir;
1981
997
  const { dir, folders: skillFolders } = await findSkillFolders(rootDir);
1982
998
  if (skillFolders.length === 0) {
1983
- console.log(chalk8.red(" No skills found (looked in skills/, root dirs, and SKILL.md)"));
999
+ console.log(chalk7.red(" No skills found (looked in skills/, root dirs, and SKILL.md)"));
1984
1000
  return;
1985
1001
  }
1986
1002
  const toInstall = opts.skill ? skillFolders.filter((s) => s === opts.skill) : skillFolders;
1987
1003
  if (opts.skill && toInstall.length === 0) {
1988
- console.log(chalk8.red(` Skill '${opts.skill}' not found. Available: ${skillFolders.join(", ")}`));
1004
+ console.log(chalk7.red(` Skill '${opts.skill}' not found. Available: ${skillFolders.join(", ")}`));
1989
1005
  return;
1990
1006
  }
1991
- const targetBase = opts.global ? join9(process.env.HOME || "~", ".cursor", "skills") : join9(hubDir, "skills");
1992
- await mkdir4(targetBase, { recursive: true });
1007
+ const targetBase = opts.global ? join7(process.env.HOME || "~", ".cursor", "skills") : join7(hubDir, "skills");
1008
+ await mkdir3(targetBase, { recursive: true });
1993
1009
  for (const skill of toInstall) {
1994
- const src = join9(dir, skill);
1995
- const dest = join9(targetBase, skill);
1996
- await cp2(src, dest, { recursive: true });
1997
- console.log(chalk8.green(` Installed: ${skill}`));
1010
+ const src = join7(dir, skill);
1011
+ const dest = join7(targetBase, skill);
1012
+ await cp(src, dest, { recursive: true });
1013
+ console.log(chalk7.green(` Installed: ${skill}`));
1998
1014
  }
1999
1015
  console.log(
2000
- chalk8.green(
1016
+ chalk7.green(
2001
1017
  `
2002
1018
  ${toInstall.length} skill(s) installed to ${opts.global ? "global" : "project"}
2003
1019
  `
@@ -2007,42 +1023,42 @@ async function installSkillsFromDir(sourceSkillsDir, hubDir, opts) {
2007
1023
  async function addFromRegistry(skillName, hubDir, opts) {
2008
1024
  const repo = opts.repo || DEFAULT_REGISTRY_REPO2;
2009
1025
  const remotePath = `skills/${skillName}`;
2010
- const targetBase = opts.global ? join9(process.env.HOME || "~", ".cursor", "skills") : join9(hubDir, "skills");
2011
- const dest = join9(targetBase, skillName);
2012
- console.log(chalk8.cyan(` Downloading ${skillName} from ${repo}...`));
1026
+ const targetBase = opts.global ? join7(process.env.HOME || "~", ".cursor", "skills") : join7(hubDir, "skills");
1027
+ const dest = join7(targetBase, skillName);
1028
+ console.log(chalk7.cyan(` Downloading ${skillName} from ${repo}...`));
2013
1029
  try {
2014
1030
  await downloadDirFromGitHub(repo, remotePath, dest);
2015
- if (!existsSync6(join9(dest, "SKILL.md"))) {
1031
+ if (!existsSync5(join7(dest, "SKILL.md"))) {
2016
1032
  await rm(dest, { recursive: true }).catch(() => {
2017
1033
  });
2018
- console.log(chalk8.red(` Skill '${skillName}' not found in registry (${repo})`));
2019
- console.log(chalk8.dim(" Run 'hub registry list' to see available skills."));
1034
+ console.log(chalk7.red(` Skill '${skillName}' not found in registry (${repo})`));
1035
+ console.log(chalk7.dim(" Run 'hub registry list' to see available skills."));
2020
1036
  return;
2021
1037
  }
2022
- console.log(chalk8.green(` Installed: ${skillName}`));
2023
- console.log(chalk8.green(`
1038
+ console.log(chalk7.green(` Installed: ${skillName}`));
1039
+ console.log(chalk7.green(`
2024
1040
  1 skill(s) installed to ${opts.global ? "global" : "project"}
2025
1041
  `));
2026
1042
  } catch (err) {
2027
- console.log(chalk8.red(` Failed to download skill '${skillName}': ${err.message}`));
2028
- console.log(chalk8.dim(" Run 'hub registry list' to see available skills."));
1043
+ console.log(chalk7.red(` Failed to download skill '${skillName}': ${err.message}`));
1044
+ console.log(chalk7.dim(" Run 'hub registry list' to see available skills."));
2029
1045
  }
2030
1046
  }
2031
1047
  async function addFromGitHubSkill(owner, repo, skillName, hubDir, opts) {
2032
1048
  const fullRepo = `${owner}/${repo}`;
2033
- const targetBase = opts.global ? join9(process.env.HOME || "~", ".cursor", "skills") : join9(hubDir, "skills");
2034
- const dest = join9(targetBase, skillName);
1049
+ const targetBase = opts.global ? join7(process.env.HOME || "~", ".cursor", "skills") : join7(hubDir, "skills");
1050
+ const dest = join7(targetBase, skillName);
2035
1051
  const pathsToTry = [
2036
1052
  `skills/${skillName}`,
2037
1053
  skillName
2038
1054
  ];
2039
- console.log(chalk8.cyan(` Downloading ${skillName} from ${fullRepo} via GitHub API...`));
1055
+ console.log(chalk7.cyan(` Downloading ${skillName} from ${fullRepo} via GitHub API...`));
2040
1056
  for (const remotePath of pathsToTry) {
2041
1057
  try {
2042
1058
  await downloadDirFromGitHub(fullRepo, remotePath, dest);
2043
- if (existsSync6(join9(dest, "SKILL.md"))) {
2044
- console.log(chalk8.green(` Installed: ${skillName} (from ${fullRepo})`));
2045
- console.log(chalk8.green(`
1059
+ if (existsSync5(join7(dest, "SKILL.md"))) {
1060
+ console.log(chalk7.green(` Installed: ${skillName} (from ${fullRepo})`));
1061
+ console.log(chalk7.green(`
2046
1062
  1 skill(s) installed to ${opts.global ? "global" : "project"}
2047
1063
  `));
2048
1064
  return;
@@ -2054,12 +1070,12 @@ async function addFromGitHubSkill(owner, repo, skillName, hubDir, opts) {
2054
1070
  });
2055
1071
  }
2056
1072
  }
2057
- console.log(chalk8.red(` Skill '${skillName}' not found in ${fullRepo}`));
2058
- console.log(chalk8.dim(` Check available skills: hub skills add ${fullRepo} --list`));
1073
+ console.log(chalk7.red(` Skill '${skillName}' not found in ${fullRepo}`));
1074
+ console.log(chalk7.dim(` Check available skills: hub skills add ${fullRepo} --list`));
2059
1075
  }
2060
1076
  async function listRemoteSkills(owner, repo) {
2061
1077
  const fullRepo = `${owner}/${repo}`;
2062
- console.log(chalk8.cyan(` Fetching skills from ${fullRepo}...
1078
+ console.log(chalk7.cyan(` Fetching skills from ${fullRepo}...
2063
1079
  `));
2064
1080
  const headers = { Accept: "application/vnd.github.v3+json" };
2065
1081
  try {
@@ -2097,38 +1113,38 @@ async function listRemoteSkills(owner, repo) {
2097
1113
  { headers }
2098
1114
  );
2099
1115
  if (rootSkill.ok) {
2100
- console.log(chalk8.green(` This repo is a single skill.
1116
+ console.log(chalk7.green(` This repo is a single skill.
2101
1117
  `));
2102
- console.log(chalk8.dim(` Install with: hub skills add ${fullRepo}
1118
+ console.log(chalk7.dim(` Install with: hub skills add ${fullRepo}
2103
1119
  `));
2104
1120
  return;
2105
1121
  }
2106
1122
  }
2107
1123
  if (dirs.length === 0) {
2108
- console.log(chalk8.dim(" No skills found."));
1124
+ console.log(chalk7.dim(" No skills found."));
2109
1125
  return;
2110
1126
  }
2111
- console.log(chalk8.green(` Available skills (${dirs.length}):
1127
+ console.log(chalk7.green(` Available skills (${dirs.length}):
2112
1128
  `));
2113
1129
  for (const dir of dirs) {
2114
- console.log(` ${chalk8.yellow(dir.name)}`);
1130
+ console.log(` ${chalk7.yellow(dir.name)}`);
2115
1131
  }
2116
- console.log(chalk8.dim(`
1132
+ console.log(chalk7.dim(`
2117
1133
  Install with: hub skills add ${fullRepo}/<skill-name>`));
2118
- console.log(chalk8.dim(` Install all: hub skills add ${fullRepo}
1134
+ console.log(chalk7.dim(` Install all: hub skills add ${fullRepo}
2119
1135
  `));
2120
1136
  } catch {
2121
- console.log(chalk8.red(` Failed to fetch skill list from ${fullRepo}`));
1137
+ console.log(chalk7.red(` Failed to fetch skill list from ${fullRepo}`));
2122
1138
  }
2123
1139
  }
2124
1140
  async function addFromLocalPath(localPath, hubDir, opts) {
2125
- const absPath = resolve2(localPath);
2126
- if (!existsSync6(absPath)) {
2127
- console.log(chalk8.red(` Path not found: ${absPath}`));
1141
+ const absPath = resolve(localPath);
1142
+ if (!existsSync5(absPath)) {
1143
+ console.log(chalk7.red(` Path not found: ${absPath}`));
2128
1144
  return;
2129
1145
  }
2130
1146
  if (!statSync(absPath).isDirectory()) {
2131
- console.log(chalk8.red(` Path is not a directory: ${absPath}`));
1147
+ console.log(chalk7.red(` Path is not a directory: ${absPath}`));
2132
1148
  return;
2133
1149
  }
2134
1150
  await installSkillsFromDir(absPath, hubDir, opts);
@@ -2136,19 +1152,19 @@ async function addFromLocalPath(localPath, hubDir, opts) {
2136
1152
  async function addFromGitRepo(source, hubDir, opts) {
2137
1153
  const tmp = tmpDir();
2138
1154
  try {
2139
- console.log(chalk8.cyan(` Cloning ${source}...`));
1155
+ console.log(chalk7.cyan(` Cloning ${source}...`));
2140
1156
  try {
2141
1157
  execSync4(`git clone --depth 1 ${source} ${tmp}`, {
2142
1158
  stdio: ["pipe", "pipe", "pipe"]
2143
1159
  });
2144
1160
  } catch {
2145
- console.log(chalk8.red(` Repository not found or not accessible: ${source}`));
2146
- console.log(chalk8.dim(" Make sure the URL is correct and you have access to the repository."));
1161
+ console.log(chalk7.red(` Repository not found or not accessible: ${source}`));
1162
+ console.log(chalk7.dim(" Make sure the URL is correct and you have access to the repository."));
2147
1163
  return;
2148
1164
  }
2149
1165
  await installSkillsFromDir(tmp, hubDir, opts);
2150
1166
  } finally {
2151
- if (existsSync6(tmp)) {
1167
+ if (existsSync5(tmp)) {
2152
1168
  await rm(tmp, { recursive: true });
2153
1169
  }
2154
1170
  }
@@ -2162,124 +1178,130 @@ function parseGitHubSource(source) {
2162
1178
  if (parts.length === 3) return { owner: parts[0], repo: parts[1], skill: parts[2] };
2163
1179
  return null;
2164
1180
  }
2165
- var skillsCommand = new Command8("skills").description("Manage agent skills").addCommand(
2166
- new Command8("add").description("Install skills from registry, GitHub, git URL, or local path").argument("<source>", "Skill name, owner/repo, owner/repo/skill, git URL, or local path").option("-s, --skill <name>", "Install a specific skill only (for repo sources)").option("-g, --global", "Install to global ~/.cursor/skills/").option("-r, --repo <repo>", "Registry repository (owner/repo)").option("-l, --list", "List available skills without installing").action(async (source, opts) => {
1181
+ var skillsCommand = new Command7("skills").description("Manage agent skills").addCommand(
1182
+ new Command7("add").description("Install skills from registry, GitHub, git URL, or local path").argument("<source>", "Skill name, owner/repo, owner/repo/skill, git URL, or local path").option("-s, --skill <name>", "Install a specific skill only (for repo sources)").option("-g, --global", "Install to global ~/.cursor/skills/").option("-r, --repo <repo>", "Registry repository (owner/repo)").option("-l, --list", "List available skills without installing").action(async (source, opts) => {
2167
1183
  const hubDir = process.cwd();
2168
1184
  if (isLocalPath(source)) {
2169
- console.log(chalk8.blue(`
1185
+ console.log(chalk7.blue(`
2170
1186
  Installing skills from ${source}
2171
1187
  `));
2172
1188
  await addFromLocalPath(source, hubDir, opts);
1189
+ if (!opts.global) await checkAndAutoRegenerate(hubDir);
2173
1190
  return;
2174
1191
  }
2175
1192
  if (source.startsWith("git@") || source.startsWith("https://")) {
2176
- console.log(chalk8.blue(`
1193
+ console.log(chalk7.blue(`
2177
1194
  Installing skills from ${source}
2178
1195
  `));
2179
1196
  await addFromGitRepo(source, hubDir, opts);
1197
+ if (!opts.global) await checkAndAutoRegenerate(hubDir);
2180
1198
  return;
2181
1199
  }
2182
1200
  const parsed = parseGitHubSource(source);
2183
1201
  if (parsed && opts.list) {
2184
- console.log(chalk8.blue(`
1202
+ console.log(chalk7.blue(`
2185
1203
  Listing skills from ${parsed.owner}/${parsed.repo}
2186
1204
  `));
2187
1205
  await listRemoteSkills(parsed.owner, parsed.repo);
2188
1206
  return;
2189
1207
  }
2190
1208
  if (parsed?.skill) {
2191
- console.log(chalk8.blue(`
1209
+ console.log(chalk7.blue(`
2192
1210
  Installing skill ${parsed.skill} from ${parsed.owner}/${parsed.repo}
2193
1211
  `));
2194
1212
  await addFromGitHubSkill(parsed.owner, parsed.repo, parsed.skill, hubDir, opts);
1213
+ if (!opts.global) await checkAndAutoRegenerate(hubDir);
2195
1214
  return;
2196
1215
  }
2197
1216
  if (parsed && !parsed.skill) {
2198
- console.log(chalk8.blue(`
1217
+ console.log(chalk7.blue(`
2199
1218
  Installing skills from ${source}
2200
1219
  `));
2201
1220
  const url = `https://github.com/${source}.git`;
2202
1221
  await addFromGitRepo(url, hubDir, opts);
1222
+ if (!opts.global) await checkAndAutoRegenerate(hubDir);
2203
1223
  return;
2204
1224
  }
2205
- console.log(chalk8.blue(`
1225
+ console.log(chalk7.blue(`
2206
1226
  Installing skill ${source} from registry
2207
1227
  `));
2208
1228
  await addFromRegistry(source, hubDir, opts);
1229
+ if (!opts.global) await checkAndAutoRegenerate(hubDir);
2209
1230
  })
2210
1231
  ).addCommand(
2211
- new Command8("find").description("Browse curated skills in the Repo Hub directory").argument("[query]", "Search term").action(async (query) => {
1232
+ new Command7("find").description("Browse curated skills in the Repo Hub directory").argument("[query]", "Search term").action(async (query) => {
2212
1233
  const base = "https://rhm-website.vercel.app/directory?type=skill";
2213
1234
  const url = query ? `${base}&q=${encodeURIComponent(query)}` : base;
2214
- console.log(chalk8.blue("\n Browse curated skills at:\n"));
2215
- console.log(chalk8.cyan(` ${url}
1235
+ console.log(chalk7.blue("\n Browse curated skills at:\n"));
1236
+ console.log(chalk7.cyan(` ${url}
2216
1237
  `));
2217
- console.log(chalk8.dim(" Install with: hub skills add <owner>/<repo>/<skill-name>"));
2218
- console.log(chalk8.dim(" Example: hub skills add vercel-labs/agent-skills/react-best-practices\n"));
1238
+ console.log(chalk7.dim(" Install with: hub skills add <owner>/<repo>/<skill-name>"));
1239
+ console.log(chalk7.dim(" Example: hub skills add vercel-labs/agent-skills/react-best-practices\n"));
2219
1240
  })
2220
1241
  ).addCommand(
2221
- new Command8("list").description("List installed skills").action(async () => {
1242
+ new Command7("list").description("List installed skills").action(async () => {
2222
1243
  const hubDir = process.cwd();
2223
- console.log(chalk8.blue("\nInstalled skills\n"));
1244
+ console.log(chalk7.blue("\nInstalled skills\n"));
2224
1245
  const projectSkills = await listLocalSkills(hubDir);
2225
1246
  if (projectSkills.length > 0) {
2226
- console.log(chalk8.cyan("Project:"));
1247
+ console.log(chalk7.cyan("Project:"));
2227
1248
  for (const s of projectSkills) {
2228
- console.log(` ${chalk8.yellow(s.name)} \u2014 ${s.description}`);
1249
+ console.log(` ${chalk7.yellow(s.name)} \u2014 ${s.description}`);
2229
1250
  }
2230
1251
  } else {
2231
- console.log(chalk8.dim(" No project skills (skills/)"));
1252
+ console.log(chalk7.dim(" No project skills (skills/)"));
2232
1253
  }
2233
- const globalDir = join9(process.env.HOME || "~", ".cursor", "skills");
2234
- const globalSkills = await listLocalSkills(join9(globalDir, ".."));
1254
+ const globalDir = join7(process.env.HOME || "~", ".cursor", "skills");
1255
+ const globalSkills = await listLocalSkills(join7(globalDir, ".."));
2235
1256
  console.log();
2236
1257
  if (globalSkills.length > 0) {
2237
- console.log(chalk8.cyan("Global:"));
1258
+ console.log(chalk7.cyan("Global:"));
2238
1259
  for (const s of globalSkills) {
2239
- console.log(` ${chalk8.yellow(s.name)} \u2014 ${s.description}`);
1260
+ console.log(` ${chalk7.yellow(s.name)} \u2014 ${s.description}`);
2240
1261
  }
2241
1262
  } else {
2242
- console.log(chalk8.dim(" No global skills (~/.cursor/skills/)"));
1263
+ console.log(chalk7.dim(" No global skills (~/.cursor/skills/)"));
2243
1264
  }
2244
1265
  console.log();
2245
1266
  })
2246
1267
  ).addCommand(
2247
- new Command8("remove").description("Remove a skill").argument("<name>", "Skill name to remove").option("-g, --global", "Remove from global skills").action(async (name, opts) => {
1268
+ new Command7("remove").description("Remove a skill").argument("<name>", "Skill name to remove").option("-g, --global", "Remove from global skills").action(async (name, opts) => {
2248
1269
  const hubDir = process.cwd();
2249
- const base = opts.global ? join9(process.env.HOME || "~", ".cursor", "skills") : join9(hubDir, "skills");
2250
- const target = join9(base, name);
2251
- if (!existsSync6(target)) {
2252
- console.log(chalk8.red(`
1270
+ const base = opts.global ? join7(process.env.HOME || "~", ".cursor", "skills") : join7(hubDir, "skills");
1271
+ const target = join7(base, name);
1272
+ if (!existsSync5(target)) {
1273
+ console.log(chalk7.red(`
2253
1274
  Skill '${name}' not found in ${opts.global ? "global" : "project"}
2254
1275
  `));
2255
1276
  return;
2256
1277
  }
2257
1278
  await rm(target, { recursive: true });
2258
- console.log(chalk8.green(`
1279
+ console.log(chalk7.green(`
2259
1280
  Removed skill: ${name}
2260
1281
  `));
1282
+ if (!opts.global) await checkAndAutoRegenerate(hubDir);
2261
1283
  })
2262
1284
  );
2263
1285
 
2264
1286
  // src/commands/agents.ts
2265
- import { Command as Command9 } from "commander";
2266
- import { existsSync as existsSync7, statSync as statSync2 } from "fs";
2267
- import { mkdir as mkdir5, readdir as readdir3, readFile as readFile6, rm as rm2, copyFile as copyFile2, writeFile as writeFile8 } from "fs/promises";
2268
- import { join as join10, resolve as resolve3 } from "path";
1287
+ import { Command as Command8 } from "commander";
1288
+ import { existsSync as existsSync6, statSync as statSync2 } from "fs";
1289
+ import { mkdir as mkdir4, readdir as readdir2, readFile as readFile4, rm as rm2, copyFile, writeFile as writeFile7 } from "fs/promises";
1290
+ import { join as join8, resolve as resolve2 } from "path";
2269
1291
  import { execSync as execSync5 } from "child_process";
2270
- import chalk9 from "chalk";
1292
+ import chalk8 from "chalk";
2271
1293
  var DEFAULT_REGISTRY_REPO3 = process.env.HUB_REGISTRY || "arvoreeducacao/rhm";
2272
1294
  var DEFAULT_BRANCH2 = "main";
2273
1295
  function tmpDir2() {
2274
- return join10(process.env.TMPDIR || "/tmp", `hub-agents-${Date.now()}`);
1296
+ return join8(process.env.TMPDIR || "/tmp", `hub-agents-${Date.now()}`);
2275
1297
  }
2276
1298
  async function listLocalAgents(agentsDir) {
2277
1299
  const agents = [];
2278
- if (!existsSync7(agentsDir)) return agents;
2279
- const files = await readdir3(agentsDir);
1300
+ if (!existsSync6(agentsDir)) return agents;
1301
+ const files = await readdir2(agentsDir);
2280
1302
  for (const file of files) {
2281
1303
  if (!file.endsWith(".md")) continue;
2282
- const content = await readFile6(join10(agentsDir, file), "utf-8");
1304
+ const content = await readFile4(join8(agentsDir, file), "utf-8");
2283
1305
  const descMatch = content.match(/^description:\s*(.+)$/m);
2284
1306
  agents.push({
2285
1307
  name: file.replace(/\.md$/, ""),
@@ -2292,47 +1314,47 @@ async function addFromRegistry2(agentName, hubDir, opts) {
2292
1314
  const repo = opts.repo || DEFAULT_REGISTRY_REPO3;
2293
1315
  const fileName = agentName.endsWith(".md") ? agentName : `${agentName}.md`;
2294
1316
  const rawUrl = `https://raw.githubusercontent.com/${repo}/${DEFAULT_BRANCH2}/agents/${fileName}`;
2295
- console.log(chalk9.cyan(` Downloading ${agentName} from ${repo}...`));
1317
+ console.log(chalk8.cyan(` Downloading ${agentName} from ${repo}...`));
2296
1318
  try {
2297
1319
  const res = await fetch(rawUrl);
2298
1320
  if (!res.ok) {
2299
- console.log(chalk9.red(` Agent '${agentName}' not found in registry (${repo})`));
2300
- console.log(chalk9.dim(" Run 'hub registry list' to see available agents."));
1321
+ console.log(chalk8.red(` Agent '${agentName}' not found in registry (${repo})`));
1322
+ console.log(chalk8.dim(" Run 'hub registry list' to see available agents."));
2301
1323
  return;
2302
1324
  }
2303
1325
  const content = await res.text();
2304
- const targetBase = opts.global ? join10(process.env.HOME || "~", ".cursor", "agents") : join10(hubDir, "agents");
2305
- await mkdir5(targetBase, { recursive: true });
2306
- await writeFile8(join10(targetBase, fileName), content, "utf-8");
2307
- console.log(chalk9.green(` Installed: ${agentName}`));
2308
- console.log(chalk9.green(`
1326
+ const targetBase = opts.global ? join8(process.env.HOME || "~", ".cursor", "agents") : join8(hubDir, "agents");
1327
+ await mkdir4(targetBase, { recursive: true });
1328
+ await writeFile7(join8(targetBase, fileName), content, "utf-8");
1329
+ console.log(chalk8.green(` Installed: ${agentName}`));
1330
+ console.log(chalk8.green(`
2309
1331
  1 agent(s) installed to ${opts.global ? "global" : "project"}
2310
1332
  `));
2311
1333
  } catch (err) {
2312
- console.log(chalk9.red(` Failed to download agent '${agentName}': ${err.message}`));
1334
+ console.log(chalk8.red(` Failed to download agent '${agentName}': ${err.message}`));
2313
1335
  }
2314
1336
  }
2315
1337
  async function addFromLocalPath2(localPath, hubDir, opts) {
2316
- const absPath = resolve3(localPath);
2317
- if (!existsSync7(absPath)) {
2318
- console.log(chalk9.red(` Path not found: ${absPath}`));
1338
+ const absPath = resolve2(localPath);
1339
+ if (!existsSync6(absPath)) {
1340
+ console.log(chalk8.red(` Path not found: ${absPath}`));
2319
1341
  return;
2320
1342
  }
2321
1343
  if (!statSync2(absPath).isDirectory()) {
2322
- console.log(chalk9.red(` Path is not a directory: ${absPath}`));
1344
+ console.log(chalk8.red(` Path is not a directory: ${absPath}`));
2323
1345
  return;
2324
1346
  }
2325
1347
  await installAgentsFromDir(absPath, hubDir, opts);
2326
1348
  }
2327
1349
  async function findAgentFiles(rootDir) {
2328
- const agentsDir = join10(rootDir, "agents");
2329
- if (existsSync7(agentsDir)) {
2330
- const entries = await readdir3(agentsDir);
1350
+ const agentsDir = join8(rootDir, "agents");
1351
+ if (existsSync6(agentsDir)) {
1352
+ const entries = await readdir2(agentsDir);
2331
1353
  const mdFiles = entries.filter((f) => f.endsWith(".md"));
2332
1354
  if (mdFiles.length > 0) return { dir: agentsDir, files: mdFiles };
2333
1355
  }
2334
- if (existsSync7(rootDir)) {
2335
- const entries = await readdir3(rootDir);
1356
+ if (existsSync6(rootDir)) {
1357
+ const entries = await readdir2(rootDir);
2336
1358
  const mdFiles = entries.filter(
2337
1359
  (f) => f.endsWith(".md") && !f.startsWith(".") && f !== "README.md" && f !== "CHANGELOG.md"
2338
1360
  );
@@ -2344,23 +1366,23 @@ async function installAgentsFromDir(sourceDir, hubDir, opts) {
2344
1366
  const rootDir = sourceDir.endsWith("/agents") ? sourceDir.replace(/\/agents$/, "") : sourceDir;
2345
1367
  const { dir, files: mdFiles } = await findAgentFiles(rootDir);
2346
1368
  if (mdFiles.length === 0) {
2347
- console.log(chalk9.red(" No agent files found (looked in agents/ and root .md files)"));
1369
+ console.log(chalk8.red(" No agent files found (looked in agents/ and root .md files)"));
2348
1370
  return;
2349
1371
  }
2350
1372
  const toInstall = opts.agent ? mdFiles.filter((f) => f === `${opts.agent}.md` || f === opts.agent) : mdFiles;
2351
1373
  if (opts.agent && toInstall.length === 0) {
2352
1374
  const available = mdFiles.map((f) => f.replace(/\.md$/, "")).join(", ");
2353
- console.log(chalk9.red(` Agent '${opts.agent}' not found. Available: ${available}`));
1375
+ console.log(chalk8.red(` Agent '${opts.agent}' not found. Available: ${available}`));
2354
1376
  return;
2355
1377
  }
2356
- const targetBase = opts.global ? join10(process.env.HOME || "~", ".cursor", "agents") : join10(hubDir, "agents");
2357
- await mkdir5(targetBase, { recursive: true });
1378
+ const targetBase = opts.global ? join8(process.env.HOME || "~", ".cursor", "agents") : join8(hubDir, "agents");
1379
+ await mkdir4(targetBase, { recursive: true });
2358
1380
  for (const file of toInstall) {
2359
- await copyFile2(join10(dir, file), join10(targetBase, file));
2360
- console.log(chalk9.green(` Installed: ${file.replace(/\.md$/, "")}`));
1381
+ await copyFile(join8(dir, file), join8(targetBase, file));
1382
+ console.log(chalk8.green(` Installed: ${file.replace(/\.md$/, "")}`));
2361
1383
  }
2362
1384
  console.log(
2363
- chalk9.green(
1385
+ chalk8.green(
2364
1386
  `
2365
1387
  ${toInstall.length} agent(s) installed to ${opts.global ? "global" : "project"}
2366
1388
  `
@@ -2370,18 +1392,18 @@ async function installAgentsFromDir(sourceDir, hubDir, opts) {
2370
1392
  async function addFromGitRepo2(source, hubDir, opts) {
2371
1393
  const tmp = tmpDir2();
2372
1394
  try {
2373
- console.log(chalk9.cyan(` Cloning ${source}...`));
1395
+ console.log(chalk8.cyan(` Cloning ${source}...`));
2374
1396
  try {
2375
1397
  execSync5(`git clone --depth 1 ${source} ${tmp}`, {
2376
1398
  stdio: ["pipe", "pipe", "pipe"]
2377
1399
  });
2378
1400
  } catch {
2379
- console.log(chalk9.red(` Repository not found or not accessible: ${source}`));
1401
+ console.log(chalk8.red(` Repository not found or not accessible: ${source}`));
2380
1402
  return;
2381
1403
  }
2382
1404
  await installAgentsFromDir(tmp, hubDir, opts);
2383
1405
  } finally {
2384
- if (existsSync7(tmp)) {
1406
+ if (existsSync6(tmp)) {
2385
1407
  await rm2(tmp, { recursive: true });
2386
1408
  }
2387
1409
  }
@@ -2392,10 +1414,10 @@ function isLocalPath2(source) {
2392
1414
  function isRepoReference(source) {
2393
1415
  return source.startsWith("git@") || source.startsWith("https://") || source.includes("/");
2394
1416
  }
2395
- var agentsCommand = new Command9("agents").description("Manage agent definitions").addCommand(
2396
- new Command9("add").description("Install agents from the registry, a git repository, or local path").argument("<source>", "Agent name (from registry), GitHub shorthand (org/repo), git URL, or local path").option("-a, --agent <name>", "Install a specific agent only (for repo sources)").option("-g, --global", "Install to global ~/.cursor/agents/").option("-r, --repo <repo>", "Registry repository (owner/repo)").action(async (source, opts) => {
1417
+ var agentsCommand = new Command8("agents").description("Manage agent definitions").addCommand(
1418
+ new Command8("add").description("Install agents from the registry, a git repository, or local path").argument("<source>", "Agent name (from registry), GitHub shorthand (org/repo), git URL, or local path").option("-a, --agent <name>", "Install a specific agent only (for repo sources)").option("-g, --global", "Install to global ~/.cursor/agents/").option("-r, --repo <repo>", "Registry repository (owner/repo)").action(async (source, opts) => {
2397
1419
  const hubDir = process.cwd();
2398
- console.log(chalk9.blue(`
1420
+ console.log(chalk8.blue(`
2399
1421
  Installing agents from ${source}
2400
1422
  `));
2401
1423
  if (isLocalPath2(source)) {
@@ -2410,68 +1432,70 @@ Installing agents from ${source}
2410
1432
  } else {
2411
1433
  await addFromRegistry2(source, hubDir, opts);
2412
1434
  }
1435
+ if (!opts.global) await checkAndAutoRegenerate(hubDir);
2413
1436
  })
2414
1437
  ).addCommand(
2415
- new Command9("list").description("List installed agents").action(async () => {
1438
+ new Command8("list").description("List installed agents").action(async () => {
2416
1439
  const hubDir = process.cwd();
2417
- console.log(chalk9.blue("\nInstalled agents\n"));
2418
- const projectAgents = await listLocalAgents(join10(hubDir, "agents"));
1440
+ console.log(chalk8.blue("\nInstalled agents\n"));
1441
+ const projectAgents = await listLocalAgents(join8(hubDir, "agents"));
2419
1442
  if (projectAgents.length > 0) {
2420
- console.log(chalk9.cyan("Project:"));
1443
+ console.log(chalk8.cyan("Project:"));
2421
1444
  for (const a of projectAgents) {
2422
- console.log(` ${chalk9.yellow(a.name)}${a.description ? ` \u2014 ${a.description}` : ""}`);
1445
+ console.log(` ${chalk8.yellow(a.name)}${a.description ? ` \u2014 ${a.description}` : ""}`);
2423
1446
  }
2424
1447
  } else {
2425
- console.log(chalk9.dim(" No project agents (agents/)"));
1448
+ console.log(chalk8.dim(" No project agents (agents/)"));
2426
1449
  }
2427
- const globalDir = join10(process.env.HOME || "~", ".cursor", "agents");
1450
+ const globalDir = join8(process.env.HOME || "~", ".cursor", "agents");
2428
1451
  const globalAgents = await listLocalAgents(globalDir);
2429
1452
  console.log();
2430
1453
  if (globalAgents.length > 0) {
2431
- console.log(chalk9.cyan("Global:"));
1454
+ console.log(chalk8.cyan("Global:"));
2432
1455
  for (const a of globalAgents) {
2433
- console.log(` ${chalk9.yellow(a.name)}${a.description ? ` \u2014 ${a.description}` : ""}`);
1456
+ console.log(` ${chalk8.yellow(a.name)}${a.description ? ` \u2014 ${a.description}` : ""}`);
2434
1457
  }
2435
1458
  } else {
2436
- console.log(chalk9.dim(" No global agents (~/.cursor/agents/)"));
1459
+ console.log(chalk8.dim(" No global agents (~/.cursor/agents/)"));
2437
1460
  }
2438
1461
  console.log();
2439
1462
  })
2440
1463
  ).addCommand(
2441
- new Command9("remove").description("Remove an agent").argument("<name>", "Agent name to remove").option("-g, --global", "Remove from global agents").action(async (name, opts) => {
1464
+ new Command8("remove").description("Remove an agent").argument("<name>", "Agent name to remove").option("-g, --global", "Remove from global agents").action(async (name, opts) => {
2442
1465
  const hubDir = process.cwd();
2443
- const base = opts.global ? join10(process.env.HOME || "~", ".cursor", "agents") : join10(hubDir, "agents");
1466
+ const base = opts.global ? join8(process.env.HOME || "~", ".cursor", "agents") : join8(hubDir, "agents");
2444
1467
  const fileName = name.endsWith(".md") ? name : `${name}.md`;
2445
- const target = join10(base, fileName);
2446
- if (!existsSync7(target)) {
2447
- console.log(chalk9.red(`
1468
+ const target = join8(base, fileName);
1469
+ if (!existsSync6(target)) {
1470
+ console.log(chalk8.red(`
2448
1471
  Agent '${name}' not found in ${opts.global ? "global" : "project"}
2449
1472
  `));
2450
1473
  return;
2451
1474
  }
2452
1475
  await rm2(target);
2453
- console.log(chalk9.green(`
1476
+ console.log(chalk8.green(`
2454
1477
  Removed agent: ${name}
2455
1478
  `));
1479
+ if (!opts.global) await checkAndAutoRegenerate(hubDir);
2456
1480
  })
2457
1481
  ).addCommand(
2458
- new Command9("find").description("Browse curated agents in the Repo Hub directory").argument("[query]", "Search term").action(async (query) => {
1482
+ new Command8("find").description("Browse curated agents in the Repo Hub directory").argument("[query]", "Search term").action(async (query) => {
2459
1483
  const base = "https://rhm-website.vercel.app/directory?type=agent";
2460
1484
  const url = query ? `${base}&q=${encodeURIComponent(query)}` : base;
2461
- console.log(chalk9.blue("\n Browse curated agents at:\n"));
2462
- console.log(chalk9.cyan(` ${url}
1485
+ console.log(chalk8.blue("\n Browse curated agents at:\n"));
1486
+ console.log(chalk8.cyan(` ${url}
2463
1487
  `));
2464
- console.log(chalk9.dim(" Install with: hub agents add <owner>/<repo>"));
2465
- console.log(chalk9.dim(" Example: hub agents add my-org/my-agents\n"));
1488
+ console.log(chalk8.dim(" Install with: hub agents add <owner>/<repo>"));
1489
+ console.log(chalk8.dim(" Example: hub agents add my-org/my-agents\n"));
2466
1490
  })
2467
1491
  ).addCommand(
2468
- new Command9("sync").description("Install all agents referenced in hub.yaml from the registry").option("-g, --global", "Install to global ~/.cursor/agents/").option("-r, --repo <repo>", "Registry repository (owner/repo)").option("-f, --force", "Re-install even if the agent already exists locally").action(async (opts) => {
1492
+ new Command8("sync").description("Install all agents referenced in hub.yaml from the registry").option("-g, --global", "Install to global ~/.cursor/agents/").option("-r, --repo <repo>", "Registry repository (owner/repo)").option("-f, --force", "Re-install even if the agent already exists locally").action(async (opts) => {
2469
1493
  const hubDir = process.cwd();
2470
1494
  let config;
2471
1495
  try {
2472
1496
  config = await loadHubConfig(hubDir);
2473
1497
  } catch {
2474
- console.log(chalk9.red("\n Could not load hub.yaml in the current directory.\n"));
1498
+ console.log(chalk8.red("\n Could not load hub.yaml in the current directory.\n"));
2475
1499
  return;
2476
1500
  }
2477
1501
  const steps = config.workflow?.pipeline || [];
@@ -2485,20 +1509,20 @@ Removed agent: ${name}
2485
1509
  }
2486
1510
  }
2487
1511
  if (agentNames.size === 0) {
2488
- console.log(chalk9.yellow("\n No agents found in hub.yaml workflow pipeline.\n"));
1512
+ console.log(chalk8.yellow("\n No agents found in hub.yaml workflow pipeline.\n"));
2489
1513
  return;
2490
1514
  }
2491
- console.log(chalk9.blue(`
1515
+ console.log(chalk8.blue(`
2492
1516
  \u2501\u2501\u2501 Syncing ${agentNames.size} agent(s) from hub.yaml \u2501\u2501\u2501
2493
1517
  `));
2494
- const targetBase = opts.global ? join10(process.env.HOME || "~", ".cursor", "agents") : join10(hubDir, "agents");
1518
+ const targetBase = opts.global ? join8(process.env.HOME || "~", ".cursor", "agents") : join8(hubDir, "agents");
2495
1519
  let installed = 0;
2496
1520
  let skipped = 0;
2497
1521
  for (const name of agentNames) {
2498
1522
  const fileName = name.endsWith(".md") ? name : `${name}.md`;
2499
- const targetPath = join10(targetBase, fileName);
2500
- if (!opts.force && existsSync7(targetPath)) {
2501
- console.log(chalk9.dim(` \u2713 ${name} (already installed)`));
1523
+ const targetPath = join8(targetBase, fileName);
1524
+ if (!opts.force && existsSync6(targetPath)) {
1525
+ console.log(chalk8.dim(` \u2713 ${name} (already installed)`));
2502
1526
  skipped++;
2503
1527
  continue;
2504
1528
  }
@@ -2506,40 +1530,41 @@ Removed agent: ${name}
2506
1530
  installed++;
2507
1531
  }
2508
1532
  console.log();
2509
- if (installed > 0) console.log(chalk9.green(` ${installed} agent(s) installed`));
2510
- if (skipped > 0) console.log(chalk9.dim(` ${skipped} agent(s) already up to date`));
1533
+ if (installed > 0) console.log(chalk8.green(` ${installed} agent(s) installed`));
1534
+ if (skipped > 0) console.log(chalk8.dim(` ${skipped} agent(s) already up to date`));
2511
1535
  if (installed === 0 && skipped > 0) {
2512
- console.log(chalk9.green(" All agents are already installed. Use --force to re-install."));
1536
+ console.log(chalk8.green(" All agents are already installed. Use --force to re-install."));
2513
1537
  }
2514
1538
  console.log();
1539
+ if (!opts.global && installed > 0) await checkAndAutoRegenerate(hubDir);
2515
1540
  })
2516
1541
  );
2517
1542
 
2518
1543
  // src/commands/hooks.ts
2519
- import { Command as Command10 } from "commander";
2520
- import { existsSync as existsSync8, statSync as statSync3 } from "fs";
2521
- import { mkdir as mkdir6, readdir as readdir4, readFile as readFile7, rm as rm3, copyFile as copyFile3, cp as cp3 } from "fs/promises";
2522
- import { join as join11, resolve as resolve4 } from "path";
1544
+ import { Command as Command9 } from "commander";
1545
+ import { existsSync as existsSync7, statSync as statSync3 } from "fs";
1546
+ import { mkdir as mkdir5, readdir as readdir3, readFile as readFile5, rm as rm3, copyFile as copyFile2, cp as cp2 } from "fs/promises";
1547
+ import { join as join9, resolve as resolve3 } from "path";
2523
1548
  import { execSync as execSync6 } from "child_process";
2524
- import chalk10 from "chalk";
1549
+ import chalk9 from "chalk";
2525
1550
  var DEFAULT_REGISTRY_REPO4 = process.env.HUB_REGISTRY || "arvoreeducacao/rhm";
2526
1551
  function tmpDir3() {
2527
- return join11(process.env.TMPDIR || "/tmp", `hub-hooks-${Date.now()}`);
1552
+ return join9(process.env.TMPDIR || "/tmp", `hub-hooks-${Date.now()}`);
2528
1553
  }
2529
1554
  async function listLocalHooks(hooksDir) {
2530
1555
  const hooks = [];
2531
- if (!existsSync8(hooksDir)) return hooks;
2532
- const entries = await readdir4(hooksDir);
1556
+ if (!existsSync7(hooksDir)) return hooks;
1557
+ const entries = await readdir3(hooksDir);
2533
1558
  for (const entry of entries) {
2534
- const entryPath = join11(hooksDir, entry);
1559
+ const entryPath = join9(hooksDir, entry);
2535
1560
  const stat = statSync3(entryPath);
2536
1561
  if (stat.isFile() && entry.endsWith(".sh")) {
2537
1562
  hooks.push({ name: entry.replace(/\.sh$/, ""), description: "" });
2538
1563
  } else if (stat.isDirectory()) {
2539
- const readmePath = join11(entryPath, "README.md");
1564
+ const readmePath = join9(entryPath, "README.md");
2540
1565
  let description = "";
2541
- if (existsSync8(readmePath)) {
2542
- const content = await readFile7(readmePath, "utf-8");
1566
+ if (existsSync7(readmePath)) {
1567
+ const content = await readFile5(readmePath, "utf-8");
2543
1568
  const firstLine = content.split("\n").find((l) => l.trim() && !l.startsWith("#"));
2544
1569
  description = firstLine?.trim() || "";
2545
1570
  }
@@ -2550,84 +1575,84 @@ async function listLocalHooks(hooksDir) {
2550
1575
  }
2551
1576
  async function addFromRegistry3(hookName, hubDir, opts) {
2552
1577
  const repo = opts.repo || DEFAULT_REGISTRY_REPO4;
2553
- const targetDir = join11(hubDir, "hooks", hookName);
2554
- console.log(chalk10.cyan(` Downloading hook '${hookName}' from ${repo}...`));
1578
+ const targetDir = join9(hubDir, "hooks", hookName);
1579
+ console.log(chalk9.cyan(` Downloading hook '${hookName}' from ${repo}...`));
2555
1580
  try {
2556
1581
  await downloadDirFromGitHub(repo, `hooks/${hookName}`, targetDir);
2557
- console.log(chalk10.green(` Installed: ${hookName}`));
2558
- console.log(chalk10.dim("\n Add the hook to hub.yaml to bind it to an event. Example:"));
2559
- console.log(chalk10.dim(` hooks:`));
2560
- console.log(chalk10.dim(` after_file_edit:`));
2561
- console.log(chalk10.dim(` - type: command`));
2562
- console.log(chalk10.dim(` command: "./hooks/${hookName}/hook.sh"
1582
+ console.log(chalk9.green(` Installed: ${hookName}`));
1583
+ console.log(chalk9.dim("\n Add the hook to hub.yaml to bind it to an event. Example:"));
1584
+ console.log(chalk9.dim(` hooks:`));
1585
+ console.log(chalk9.dim(` after_file_edit:`));
1586
+ console.log(chalk9.dim(` - type: command`));
1587
+ console.log(chalk9.dim(` command: "./hooks/${hookName}/hook.sh"
2563
1588
  `));
2564
1589
  } catch {
2565
- console.log(chalk10.red(` Hook '${hookName}' not found in registry (${repo})`));
2566
- console.log(chalk10.dim(" Run 'hub registry list --type hook' to see available hooks."));
1590
+ console.log(chalk9.red(` Hook '${hookName}' not found in registry (${repo})`));
1591
+ console.log(chalk9.dim(" Run 'hub registry list --type hook' to see available hooks."));
2567
1592
  }
2568
1593
  }
2569
1594
  async function addFromLocalPath3(localPath, hubDir, opts) {
2570
- const absPath = resolve4(localPath);
2571
- if (!existsSync8(absPath)) {
2572
- console.log(chalk10.red(` Path not found: ${absPath}`));
1595
+ const absPath = resolve3(localPath);
1596
+ if (!existsSync7(absPath)) {
1597
+ console.log(chalk9.red(` Path not found: ${absPath}`));
2573
1598
  return;
2574
1599
  }
2575
1600
  const stat = statSync3(absPath);
2576
- const sourceHooksDir = stat.isDirectory() ? existsSync8(join11(absPath, "hooks")) ? join11(absPath, "hooks") : absPath : absPath;
1601
+ const sourceHooksDir = stat.isDirectory() ? existsSync7(join9(absPath, "hooks")) ? join9(absPath, "hooks") : absPath : absPath;
2577
1602
  await installHooksFromDir(sourceHooksDir, hubDir, opts);
2578
1603
  }
2579
1604
  async function installHooksFromDir(sourceDir, hubDir, opts) {
2580
- if (!existsSync8(sourceDir)) {
2581
- console.log(chalk10.red(" No hooks directory found in source"));
1605
+ if (!existsSync7(sourceDir)) {
1606
+ console.log(chalk9.red(" No hooks directory found in source"));
2582
1607
  return;
2583
1608
  }
2584
- const entries = await readdir4(sourceDir);
1609
+ const entries = await readdir3(sourceDir);
2585
1610
  const hookEntries = entries.filter((e) => {
2586
- const p = join11(sourceDir, e);
1611
+ const p = join9(sourceDir, e);
2587
1612
  return e.endsWith(".sh") || statSync3(p).isDirectory();
2588
1613
  });
2589
1614
  if (hookEntries.length === 0) {
2590
- console.log(chalk10.red(" No hook files found"));
1615
+ console.log(chalk9.red(" No hook files found"));
2591
1616
  return;
2592
1617
  }
2593
1618
  const toInstall = opts.hook ? hookEntries.filter((e) => e === opts.hook || e === `${opts.hook}.sh` || e.replace(/\.sh$/, "") === opts.hook) : hookEntries;
2594
1619
  if (opts.hook && toInstall.length === 0) {
2595
1620
  const available = hookEntries.map((e) => e.replace(/\.sh$/, "")).join(", ");
2596
- console.log(chalk10.red(` Hook '${opts.hook}' not found. Available: ${available}`));
1621
+ console.log(chalk9.red(` Hook '${opts.hook}' not found. Available: ${available}`));
2597
1622
  return;
2598
1623
  }
2599
- const targetBase = join11(hubDir, "hooks");
2600
- await mkdir6(targetBase, { recursive: true });
1624
+ const targetBase = join9(hubDir, "hooks");
1625
+ await mkdir5(targetBase, { recursive: true });
2601
1626
  for (const entry of toInstall) {
2602
- const src = join11(sourceDir, entry);
1627
+ const src = join9(sourceDir, entry);
2603
1628
  const stat = statSync3(src);
2604
1629
  if (stat.isDirectory()) {
2605
- await cp3(src, join11(targetBase, entry), { recursive: true });
1630
+ await cp2(src, join9(targetBase, entry), { recursive: true });
2606
1631
  } else {
2607
- await copyFile3(src, join11(targetBase, entry));
1632
+ await copyFile2(src, join9(targetBase, entry));
2608
1633
  }
2609
- console.log(chalk10.green(` Installed: ${entry.replace(/\.sh$/, "")}`));
1634
+ console.log(chalk9.green(` Installed: ${entry.replace(/\.sh$/, "")}`));
2610
1635
  }
2611
- console.log(chalk10.green(`
1636
+ console.log(chalk9.green(`
2612
1637
  ${toInstall.length} hook(s) installed
2613
1638
  `));
2614
1639
  }
2615
1640
  async function addFromGitRepo3(source, hubDir, opts) {
2616
1641
  const tmp = tmpDir3();
2617
1642
  try {
2618
- console.log(chalk10.cyan(` Cloning ${source}...`));
1643
+ console.log(chalk9.cyan(` Cloning ${source}...`));
2619
1644
  try {
2620
1645
  execSync6(`git clone --depth 1 ${source} ${tmp}`, {
2621
1646
  stdio: ["pipe", "pipe", "pipe"]
2622
1647
  });
2623
1648
  } catch {
2624
- console.log(chalk10.red(` Repository not found or not accessible: ${source}`));
1649
+ console.log(chalk9.red(` Repository not found or not accessible: ${source}`));
2625
1650
  return;
2626
1651
  }
2627
- const sourceHooksDir = join11(tmp, "hooks");
1652
+ const sourceHooksDir = join9(tmp, "hooks");
2628
1653
  await installHooksFromDir(sourceHooksDir, hubDir, opts);
2629
1654
  } finally {
2630
- if (existsSync8(tmp)) {
1655
+ if (existsSync7(tmp)) {
2631
1656
  await rm3(tmp, { recursive: true });
2632
1657
  }
2633
1658
  }
@@ -2638,10 +1663,10 @@ function isLocalPath3(source) {
2638
1663
  function isRepoReference2(source) {
2639
1664
  return source.startsWith("git@") || source.startsWith("https://") || source.includes("/");
2640
1665
  }
2641
- var hooksCommand = new Command10("hooks").description("Manage editor hooks").addCommand(
2642
- new Command10("add").description("Install hooks from the registry, a git repository, or local path").argument("<source>", "Hook name (from registry), GitHub shorthand (org/repo), git URL, or local path").option("--hook <name>", "Install a specific hook only (for repo sources)").option("-r, --repo <repo>", "Registry repository (owner/repo)").action(async (source, opts) => {
1666
+ var hooksCommand = new Command9("hooks").description("Manage editor hooks").addCommand(
1667
+ new Command9("add").description("Install hooks from the registry, a git repository, or local path").argument("<source>", "Hook name (from registry), GitHub shorthand (org/repo), git URL, or local path").option("--hook <name>", "Install a specific hook only (for repo sources)").option("-r, --repo <repo>", "Registry repository (owner/repo)").action(async (source, opts) => {
2643
1668
  const hubDir = process.cwd();
2644
- console.log(chalk10.blue(`
1669
+ console.log(chalk9.blue(`
2645
1670
  Installing hooks from ${source}
2646
1671
  `));
2647
1672
  if (isLocalPath3(source)) {
@@ -2656,75 +1681,78 @@ Installing hooks from ${source}
2656
1681
  } else {
2657
1682
  await addFromRegistry3(source, hubDir, opts);
2658
1683
  }
1684
+ await checkAndAutoRegenerate(hubDir);
2659
1685
  })
2660
1686
  ).addCommand(
2661
- new Command10("list").description("List installed hooks").action(async () => {
1687
+ new Command9("list").description("List installed hooks").action(async () => {
2662
1688
  const hubDir = process.cwd();
2663
- const hooksDir = join11(hubDir, "hooks");
2664
- console.log(chalk10.blue("\nInstalled hooks\n"));
1689
+ const hooksDir = join9(hubDir, "hooks");
1690
+ console.log(chalk9.blue("\nInstalled hooks\n"));
2665
1691
  const hooks = await listLocalHooks(hooksDir);
2666
1692
  if (hooks.length > 0) {
2667
1693
  for (const h of hooks) {
2668
- console.log(` ${chalk10.yellow(h.name)}${h.description ? ` \u2014 ${h.description}` : ""}`);
1694
+ console.log(` ${chalk9.yellow(h.name)}${h.description ? ` \u2014 ${h.description}` : ""}`);
2669
1695
  }
2670
1696
  } else {
2671
- console.log(chalk10.dim(" No hooks installed (hooks/)"));
1697
+ console.log(chalk9.dim(" No hooks installed (hooks/)"));
2672
1698
  }
2673
1699
  console.log();
2674
1700
  })
2675
1701
  ).addCommand(
2676
- new Command10("find").description("Browse curated hooks in the Repo Hub directory").argument("[query]", "Search term").action(async (query) => {
1702
+ new Command9("find").description("Browse curated hooks in the Repo Hub directory").argument("[query]", "Search term").action(async (query) => {
2677
1703
  const base = "https://rhm-website.vercel.app/directory?type=hook";
2678
1704
  const url = query ? `${base}&q=${encodeURIComponent(query)}` : base;
2679
- console.log(chalk10.blue("\n Browse curated hooks at:\n"));
2680
- console.log(chalk10.cyan(` ${url}
1705
+ console.log(chalk9.blue("\n Browse curated hooks at:\n"));
1706
+ console.log(chalk9.cyan(` ${url}
2681
1707
  `));
2682
- console.log(chalk10.dim(" Install with: hub hooks add <owner>/<repo>"));
2683
- console.log(chalk10.dim(" Example: hub hooks add obra/superpowers\n"));
1708
+ console.log(chalk9.dim(" Install with: hub hooks add <owner>/<repo>"));
1709
+ console.log(chalk9.dim(" Example: hub hooks add obra/superpowers\n"));
2684
1710
  })
2685
1711
  ).addCommand(
2686
- new Command10("remove").description("Remove a hook").argument("<name>", "Hook name to remove").action(async (name) => {
1712
+ new Command9("remove").description("Remove a hook").argument("<name>", "Hook name to remove").action(async (name) => {
2687
1713
  const hubDir = process.cwd();
2688
- const hooksDir = join11(hubDir, "hooks");
2689
- const shFile = join11(hooksDir, `${name}.sh`);
2690
- const dirPath = join11(hooksDir, name);
2691
- if (existsSync8(dirPath) && statSync3(dirPath).isDirectory()) {
1714
+ const hooksDir = join9(hubDir, "hooks");
1715
+ const shFile = join9(hooksDir, `${name}.sh`);
1716
+ const dirPath = join9(hooksDir, name);
1717
+ if (existsSync7(dirPath) && statSync3(dirPath).isDirectory()) {
2692
1718
  await rm3(dirPath, { recursive: true });
2693
- console.log(chalk10.green(`
1719
+ console.log(chalk9.green(`
2694
1720
  Removed hook: ${name}
2695
1721
  `));
2696
- } else if (existsSync8(shFile)) {
1722
+ } else if (existsSync7(shFile)) {
2697
1723
  await rm3(shFile);
2698
- console.log(chalk10.green(`
1724
+ console.log(chalk9.green(`
2699
1725
  Removed hook: ${name}
2700
1726
  `));
2701
1727
  } else {
2702
- console.log(chalk10.red(`
1728
+ console.log(chalk9.red(`
2703
1729
  Hook '${name}' not found in hooks/
2704
1730
  `));
1731
+ return;
2705
1732
  }
1733
+ await checkAndAutoRegenerate(hubDir);
2706
1734
  })
2707
1735
  );
2708
1736
 
2709
1737
  // src/commands/commands.ts
2710
- import { Command as Command11 } from "commander";
2711
- import { existsSync as existsSync9, statSync as statSync4 } from "fs";
2712
- import { mkdir as mkdir7, readdir as readdir5, readFile as readFile8, rm as rm4, copyFile as copyFile4, writeFile as writeFile9 } from "fs/promises";
2713
- import { join as join12, resolve as resolve5 } from "path";
1738
+ import { Command as Command10 } from "commander";
1739
+ import { existsSync as existsSync8, statSync as statSync4 } from "fs";
1740
+ import { mkdir as mkdir6, readdir as readdir4, readFile as readFile6, rm as rm4, copyFile as copyFile3, writeFile as writeFile8 } from "fs/promises";
1741
+ import { join as join10, resolve as resolve4 } from "path";
2714
1742
  import { execSync as execSync7 } from "child_process";
2715
- import chalk11 from "chalk";
1743
+ import chalk10 from "chalk";
2716
1744
  var DEFAULT_REGISTRY_REPO5 = process.env.HUB_REGISTRY || "arvoreeducacao/rhm";
2717
1745
  var DEFAULT_BRANCH3 = "main";
2718
1746
  function tmpDir4() {
2719
- return join12(process.env.TMPDIR || "/tmp", `hub-commands-${Date.now()}`);
1747
+ return join10(process.env.TMPDIR || "/tmp", `hub-commands-${Date.now()}`);
2720
1748
  }
2721
1749
  async function listLocalCommands(commandsDir) {
2722
1750
  const commands = [];
2723
- if (!existsSync9(commandsDir)) return commands;
2724
- const files = await readdir5(commandsDir);
1751
+ if (!existsSync8(commandsDir)) return commands;
1752
+ const files = await readdir4(commandsDir);
2725
1753
  for (const file of files) {
2726
1754
  if (!file.endsWith(".md")) continue;
2727
- const content = await readFile8(join12(commandsDir, file), "utf-8");
1755
+ const content = await readFile6(join10(commandsDir, file), "utf-8");
2728
1756
  const firstLine = content.split("\n").find((l) => l.trim() && !l.startsWith("#"));
2729
1757
  commands.push({
2730
1758
  name: file.replace(/\.md$/, ""),
@@ -2737,91 +1765,91 @@ async function addFromRegistry4(commandName, hubDir, opts) {
2737
1765
  const repo = opts.repo || DEFAULT_REGISTRY_REPO5;
2738
1766
  const fileName = commandName.endsWith(".md") ? commandName : `${commandName}.md`;
2739
1767
  const rawUrl = `https://raw.githubusercontent.com/${repo}/${DEFAULT_BRANCH3}/commands/${fileName}`;
2740
- console.log(chalk11.cyan(` Downloading command '${commandName}' from ${repo}...`));
1768
+ console.log(chalk10.cyan(` Downloading command '${commandName}' from ${repo}...`));
2741
1769
  try {
2742
1770
  const res = await fetch(rawUrl);
2743
1771
  if (!res.ok) {
2744
- console.log(chalk11.red(` Command '${commandName}' not found in registry (${repo})`));
2745
- console.log(chalk11.dim(" Run 'hub registry list --type command' to see available commands."));
1772
+ console.log(chalk10.red(` Command '${commandName}' not found in registry (${repo})`));
1773
+ console.log(chalk10.dim(" Run 'hub registry list --type command' to see available commands."));
2746
1774
  return;
2747
1775
  }
2748
1776
  const content = await res.text();
2749
- const targetDir = join12(hubDir, "commands");
2750
- await mkdir7(targetDir, { recursive: true });
2751
- await writeFile9(join12(targetDir, fileName), content, "utf-8");
2752
- console.log(chalk11.green(` Installed: ${commandName}`));
2753
- console.log(chalk11.dim(`
1777
+ const targetDir = join10(hubDir, "commands");
1778
+ await mkdir6(targetDir, { recursive: true });
1779
+ await writeFile8(join10(targetDir, fileName), content, "utf-8");
1780
+ console.log(chalk10.green(` Installed: ${commandName}`));
1781
+ console.log(chalk10.dim(`
2754
1782
  Use it in Cursor with /${commandName}`));
2755
- console.log(chalk11.dim(` Make sure hub.yaml has: commands_dir: ./commands
1783
+ console.log(chalk10.dim(` Make sure hub.yaml has: commands_dir: ./commands
2756
1784
  `));
2757
1785
  } catch (err) {
2758
- console.log(chalk11.red(` Failed to download command '${commandName}': ${err.message}`));
1786
+ console.log(chalk10.red(` Failed to download command '${commandName}': ${err.message}`));
2759
1787
  }
2760
1788
  }
2761
1789
  async function addFromLocalPath4(localPath, hubDir, opts) {
2762
- const absPath = resolve5(localPath);
2763
- if (!existsSync9(absPath)) {
2764
- console.log(chalk11.red(` Path not found: ${absPath}`));
1790
+ const absPath = resolve4(localPath);
1791
+ if (!existsSync8(absPath)) {
1792
+ console.log(chalk10.red(` Path not found: ${absPath}`));
2765
1793
  return;
2766
1794
  }
2767
1795
  const stat = statSync4(absPath);
2768
1796
  if (stat.isFile() && absPath.endsWith(".md")) {
2769
- const targetDir = join12(hubDir, "commands");
2770
- await mkdir7(targetDir, { recursive: true });
1797
+ const targetDir = join10(hubDir, "commands");
1798
+ await mkdir6(targetDir, { recursive: true });
2771
1799
  const fileName = absPath.split("/").pop();
2772
- await copyFile4(absPath, join12(targetDir, fileName));
2773
- console.log(chalk11.green(` Installed: ${fileName.replace(/\.md$/, "")}`));
2774
- console.log(chalk11.green(`
1800
+ await copyFile3(absPath, join10(targetDir, fileName));
1801
+ console.log(chalk10.green(` Installed: ${fileName.replace(/\.md$/, "")}`));
1802
+ console.log(chalk10.green(`
2775
1803
  1 command(s) installed
2776
1804
  `));
2777
1805
  return;
2778
1806
  }
2779
- const sourceDir = stat.isDirectory() ? existsSync9(join12(absPath, "commands")) ? join12(absPath, "commands") : absPath : absPath;
1807
+ const sourceDir = stat.isDirectory() ? existsSync8(join10(absPath, "commands")) ? join10(absPath, "commands") : absPath : absPath;
2780
1808
  await installCommandsFromDir(sourceDir, hubDir, opts);
2781
1809
  }
2782
1810
  async function installCommandsFromDir(sourceDir, hubDir, opts) {
2783
- if (!existsSync9(sourceDir)) {
2784
- console.log(chalk11.red(" No commands directory found in source"));
1811
+ if (!existsSync8(sourceDir)) {
1812
+ console.log(chalk10.red(" No commands directory found in source"));
2785
1813
  return;
2786
1814
  }
2787
- const files = await readdir5(sourceDir);
1815
+ const files = await readdir4(sourceDir);
2788
1816
  const mdFiles = files.filter((f) => f.endsWith(".md"));
2789
1817
  if (mdFiles.length === 0) {
2790
- console.log(chalk11.red(" No command files found (looking for *.md)"));
1818
+ console.log(chalk10.red(" No command files found (looking for *.md)"));
2791
1819
  return;
2792
1820
  }
2793
1821
  const toInstall = opts.command ? mdFiles.filter((f) => f === `${opts.command}.md` || f === opts.command) : mdFiles;
2794
1822
  if (opts.command && toInstall.length === 0) {
2795
1823
  const available = mdFiles.map((f) => f.replace(/\.md$/, "")).join(", ");
2796
- console.log(chalk11.red(` Command '${opts.command}' not found. Available: ${available}`));
1824
+ console.log(chalk10.red(` Command '${opts.command}' not found. Available: ${available}`));
2797
1825
  return;
2798
1826
  }
2799
- const targetDir = join12(hubDir, "commands");
2800
- await mkdir7(targetDir, { recursive: true });
1827
+ const targetDir = join10(hubDir, "commands");
1828
+ await mkdir6(targetDir, { recursive: true });
2801
1829
  for (const file of toInstall) {
2802
- await copyFile4(join12(sourceDir, file), join12(targetDir, file));
2803
- console.log(chalk11.green(` Installed: ${file.replace(/\.md$/, "")}`));
1830
+ await copyFile3(join10(sourceDir, file), join10(targetDir, file));
1831
+ console.log(chalk10.green(` Installed: ${file.replace(/\.md$/, "")}`));
2804
1832
  }
2805
- console.log(chalk11.green(`
1833
+ console.log(chalk10.green(`
2806
1834
  ${toInstall.length} command(s) installed
2807
1835
  `));
2808
1836
  }
2809
1837
  async function addFromGitRepo4(source, hubDir, opts) {
2810
1838
  const tmp = tmpDir4();
2811
1839
  try {
2812
- console.log(chalk11.cyan(` Cloning ${source}...`));
1840
+ console.log(chalk10.cyan(` Cloning ${source}...`));
2813
1841
  try {
2814
1842
  execSync7(`git clone --depth 1 ${source} ${tmp}`, {
2815
1843
  stdio: ["pipe", "pipe", "pipe"]
2816
1844
  });
2817
1845
  } catch {
2818
- console.log(chalk11.red(` Repository not found or not accessible: ${source}`));
1846
+ console.log(chalk10.red(` Repository not found or not accessible: ${source}`));
2819
1847
  return;
2820
1848
  }
2821
- const sourceCommandsDir = join12(tmp, "commands");
1849
+ const sourceCommandsDir = join10(tmp, "commands");
2822
1850
  await installCommandsFromDir(sourceCommandsDir, hubDir, opts);
2823
1851
  } finally {
2824
- if (existsSync9(tmp)) {
1852
+ if (existsSync8(tmp)) {
2825
1853
  await rm4(tmp, { recursive: true });
2826
1854
  }
2827
1855
  }
@@ -2832,10 +1860,10 @@ function isLocalPath4(source) {
2832
1860
  function isRepoReference3(source) {
2833
1861
  return source.startsWith("git@") || source.startsWith("https://") || source.includes("/");
2834
1862
  }
2835
- var commandsCommand = new Command11("commands").description("Manage slash commands (Cursor)").addCommand(
2836
- new Command11("add").description("Install commands from the registry, a git repository, or local path").argument("<source>", "Command name (from registry), GitHub shorthand (org/repo), git URL, or local path").option("-c, --command <name>", "Install a specific command only (for repo sources)").option("-r, --repo <repo>", "Registry repository (owner/repo)").action(async (source, opts) => {
1863
+ var commandsCommand = new Command10("commands").description("Manage slash commands (Cursor)").addCommand(
1864
+ new Command10("add").description("Install commands from the registry, a git repository, or local path").argument("<source>", "Command name (from registry), GitHub shorthand (org/repo), git URL, or local path").option("-c, --command <name>", "Install a specific command only (for repo sources)").option("-r, --repo <repo>", "Registry repository (owner/repo)").action(async (source, opts) => {
2837
1865
  const hubDir = process.cwd();
2838
- console.log(chalk11.blue(`
1866
+ console.log(chalk10.blue(`
2839
1867
  Installing commands from ${source}
2840
1868
  `));
2841
1869
  if (isLocalPath4(source)) {
@@ -2850,88 +1878,90 @@ Installing commands from ${source}
2850
1878
  } else {
2851
1879
  await addFromRegistry4(source, hubDir, opts);
2852
1880
  }
1881
+ await checkAndAutoRegenerate(hubDir);
2853
1882
  })
2854
1883
  ).addCommand(
2855
- new Command11("list").description("List installed commands").action(async () => {
1884
+ new Command10("list").description("List installed commands").action(async () => {
2856
1885
  const hubDir = process.cwd();
2857
- const commandsDir = join12(hubDir, "commands");
2858
- console.log(chalk11.blue("\nInstalled commands\n"));
1886
+ const commandsDir = join10(hubDir, "commands");
1887
+ console.log(chalk10.blue("\nInstalled commands\n"));
2859
1888
  const commands = await listLocalCommands(commandsDir);
2860
1889
  if (commands.length > 0) {
2861
1890
  for (const c of commands) {
2862
- console.log(` ${chalk11.yellow(`/${c.name}`)}${c.description ? ` \u2014 ${c.description}` : ""}`);
1891
+ console.log(` ${chalk10.yellow(`/${c.name}`)}${c.description ? ` \u2014 ${c.description}` : ""}`);
2863
1892
  }
2864
1893
  } else {
2865
- console.log(chalk11.dim(" No commands installed (commands/)"));
1894
+ console.log(chalk10.dim(" No commands installed (commands/)"));
2866
1895
  }
2867
1896
  console.log();
2868
1897
  })
2869
1898
  ).addCommand(
2870
- new Command11("find").description("Browse curated commands in the Repo Hub directory").argument("[query]", "Search term").action(async (query) => {
1899
+ new Command10("find").description("Browse curated commands in the Repo Hub directory").argument("[query]", "Search term").action(async (query) => {
2871
1900
  const base = "https://rhm-website.vercel.app/directory?type=command";
2872
1901
  const url = query ? `${base}&q=${encodeURIComponent(query)}` : base;
2873
- console.log(chalk11.blue("\n Browse curated commands at:\n"));
2874
- console.log(chalk11.cyan(` ${url}
1902
+ console.log(chalk10.blue("\n Browse curated commands at:\n"));
1903
+ console.log(chalk10.cyan(` ${url}
2875
1904
  `));
2876
- console.log(chalk11.dim(" Install with: hub commands add <owner>/<repo>"));
2877
- console.log(chalk11.dim(" Example: hub commands add obra/superpowers\n"));
1905
+ console.log(chalk10.dim(" Install with: hub commands add <owner>/<repo>"));
1906
+ console.log(chalk10.dim(" Example: hub commands add obra/superpowers\n"));
2878
1907
  })
2879
1908
  ).addCommand(
2880
- new Command11("remove").description("Remove a command").argument("<name>", "Command name to remove").action(async (name) => {
1909
+ new Command10("remove").description("Remove a command").argument("<name>", "Command name to remove").action(async (name) => {
2881
1910
  const hubDir = process.cwd();
2882
- const commandsDir = join12(hubDir, "commands");
1911
+ const commandsDir = join10(hubDir, "commands");
2883
1912
  const fileName = name.endsWith(".md") ? name : `${name}.md`;
2884
- const target = join12(commandsDir, fileName);
2885
- if (!existsSync9(target)) {
2886
- console.log(chalk11.red(`
1913
+ const target = join10(commandsDir, fileName);
1914
+ if (!existsSync8(target)) {
1915
+ console.log(chalk10.red(`
2887
1916
  Command '${name}' not found in commands/
2888
1917
  `));
2889
1918
  return;
2890
1919
  }
2891
1920
  await rm4(target);
2892
- console.log(chalk11.green(`
1921
+ console.log(chalk10.green(`
2893
1922
  Removed command: ${name}
2894
1923
  `));
1924
+ await checkAndAutoRegenerate(hubDir);
2895
1925
  })
2896
1926
  );
2897
1927
 
2898
1928
  // src/commands/repos.ts
2899
- import { Command as Command12 } from "commander";
2900
- import { existsSync as existsSync10 } from "fs";
2901
- import { join as join13 } from "path";
1929
+ import { Command as Command11 } from "commander";
1930
+ import { existsSync as existsSync9 } from "fs";
1931
+ import { join as join11 } from "path";
2902
1932
  import { execSync as execSync8 } from "child_process";
2903
- import chalk12 from "chalk";
2904
- var pullCommand = new Command12("pull").description("Pull latest changes in all repositories").action(async () => {
1933
+ import chalk11 from "chalk";
1934
+ var pullCommand = new Command11("pull").description("Pull latest changes in all repositories").action(async () => {
2905
1935
  const hubDir = process.cwd();
2906
1936
  const config = await loadHubConfig(hubDir);
2907
- console.log(chalk12.blue("\n\u2501\u2501\u2501 Pulling latest changes \u2501\u2501\u2501\n"));
1937
+ console.log(chalk11.blue("\n\u2501\u2501\u2501 Pulling latest changes \u2501\u2501\u2501\n"));
2908
1938
  for (const repo of config.repos) {
2909
- const fullPath = join13(hubDir, repo.path);
2910
- if (!existsSync10(fullPath)) {
2911
- console.log(chalk12.red(` ${repo.name}: not cloned`));
1939
+ const fullPath = join11(hubDir, repo.path);
1940
+ if (!existsSync9(fullPath)) {
1941
+ console.log(chalk11.red(` ${repo.name}: not cloned`));
2912
1942
  continue;
2913
1943
  }
2914
- console.log(chalk12.yellow(`\u25B8 ${repo.name}`));
1944
+ console.log(chalk11.yellow(`\u25B8 ${repo.name}`));
2915
1945
  try {
2916
1946
  execSync8("git pull --rebase", { cwd: fullPath, stdio: "inherit" });
2917
- console.log(chalk12.green(" Updated"));
1947
+ console.log(chalk11.green(" Updated"));
2918
1948
  } catch {
2919
- console.log(chalk12.red(" Failed to pull"));
1949
+ console.log(chalk11.red(" Failed to pull"));
2920
1950
  }
2921
1951
  }
2922
1952
  console.log();
2923
1953
  });
2924
- var statusCommand = new Command12("status").description("Show git status for all repositories").action(async () => {
1954
+ var statusCommand = new Command11("status").description("Show git status for all repositories").action(async () => {
2925
1955
  const hubDir = process.cwd();
2926
1956
  const config = await loadHubConfig(hubDir);
2927
- console.log(chalk12.blue("\n\u2501\u2501\u2501 Git status \u2501\u2501\u2501\n"));
1957
+ console.log(chalk11.blue("\n\u2501\u2501\u2501 Git status \u2501\u2501\u2501\n"));
2928
1958
  for (const repo of config.repos) {
2929
- const fullPath = join13(hubDir, repo.path);
2930
- if (!existsSync10(fullPath)) {
2931
- console.log(chalk12.red(` ${repo.name}: not cloned`));
1959
+ const fullPath = join11(hubDir, repo.path);
1960
+ if (!existsSync9(fullPath)) {
1961
+ console.log(chalk11.red(` ${repo.name}: not cloned`));
2932
1962
  continue;
2933
1963
  }
2934
- console.log(chalk12.yellow(`\u25B8 ${repo.name}`));
1964
+ console.log(chalk11.yellow(`\u25B8 ${repo.name}`));
2935
1965
  try {
2936
1966
  const branch = execSync8("git branch --show-current", {
2937
1967
  cwd: fullPath,
@@ -2962,43 +1992,43 @@ var statusCommand = new Command12("status").description("Show git status for all
2962
1992
  console.log(` Changes: ${changes} file(s)`);
2963
1993
  console.log(` Ahead: ${ahead} | Behind: ${behind}`);
2964
1994
  } catch {
2965
- console.log(chalk12.red(" Failed to get status"));
1995
+ console.log(chalk11.red(" Failed to get status"));
2966
1996
  }
2967
1997
  console.log();
2968
1998
  }
2969
1999
  });
2970
- var execCommand = new Command12("exec").description("Execute a command in all repositories").argument("<cmd...>", "Command to execute").passThroughOptions().allowUnknownOption().action(async (cmd) => {
2000
+ var execCommand = new Command11("exec").description("Execute a command in all repositories").argument("<cmd...>", "Command to execute").passThroughOptions().allowUnknownOption().action(async (cmd) => {
2971
2001
  const hubDir = process.cwd();
2972
2002
  const config = await loadHubConfig(hubDir);
2973
2003
  const command = cmd.join(" ");
2974
- console.log(chalk12.blue(`
2004
+ console.log(chalk11.blue(`
2975
2005
  \u2501\u2501\u2501 Executing: ${command} \u2501\u2501\u2501
2976
2006
  `));
2977
2007
  for (const repo of config.repos) {
2978
- const fullPath = join13(hubDir, repo.path);
2979
- if (!existsSync10(fullPath)) {
2980
- console.log(chalk12.red(` ${repo.name}: not cloned`));
2008
+ const fullPath = join11(hubDir, repo.path);
2009
+ if (!existsSync9(fullPath)) {
2010
+ console.log(chalk11.red(` ${repo.name}: not cloned`));
2981
2011
  continue;
2982
2012
  }
2983
- console.log(chalk12.yellow(`\u25B8 ${repo.name}`));
2013
+ console.log(chalk11.yellow(`\u25B8 ${repo.name}`));
2984
2014
  try {
2985
2015
  execSync8(command, { cwd: fullPath, stdio: "inherit" });
2986
2016
  } catch {
2987
- console.log(chalk12.red(` Command failed in ${repo.name}`));
2017
+ console.log(chalk11.red(` Command failed in ${repo.name}`));
2988
2018
  }
2989
2019
  }
2990
2020
  console.log();
2991
2021
  });
2992
2022
 
2993
2023
  // src/commands/worktree.ts
2994
- import { Command as Command13 } from "commander";
2995
- import { existsSync as existsSync11 } from "fs";
2996
- import { cp as cp4, mkdir as mkdir8 } from "fs/promises";
2997
- import { join as join14 } from "path";
2024
+ import { Command as Command12 } from "commander";
2025
+ import { existsSync as existsSync10 } from "fs";
2026
+ import { cp as cp3, mkdir as mkdir7 } from "fs/promises";
2027
+ import { join as join12 } from "path";
2998
2028
  import { execSync as execSync9 } from "child_process";
2999
- import chalk13 from "chalk";
2029
+ import chalk12 from "chalk";
3000
2030
  function getWorktreeBase() {
3001
- return join14(process.env.HOME || "~", ".cursor", "worktrees", "repo-hub");
2031
+ return join12(process.env.HOME || "~", ".cursor", "worktrees", "repo-hub");
3002
2032
  }
3003
2033
  function isGitRepo(dir) {
3004
2034
  try {
@@ -3011,74 +2041,74 @@ function isGitRepo(dir) {
3011
2041
  return false;
3012
2042
  }
3013
2043
  }
3014
- var worktreeCommand = new Command13("worktree").description("Manage git worktrees for parallel work").addCommand(
3015
- new Command13("add").description("Create a new worktree with environment files copied").argument("<name>", "Worktree name").action(async (name) => {
2044
+ var worktreeCommand = new Command12("worktree").description("Manage git worktrees for parallel work").addCommand(
2045
+ new Command12("add").description("Create a new worktree with environment files copied").argument("<name>", "Worktree name").action(async (name) => {
3016
2046
  const hubDir = process.cwd();
3017
2047
  if (!isGitRepo(hubDir)) {
3018
- console.log(chalk13.red("\nThis directory is not a git repository."));
3019
- console.log(chalk13.dim("Run 'git init' first or use worktrees from a repo directory.\n"));
2048
+ console.log(chalk12.red("\nThis directory is not a git repository."));
2049
+ console.log(chalk12.dim("Run 'git init' first or use worktrees from a repo directory.\n"));
3020
2050
  return;
3021
2051
  }
3022
2052
  const config = await loadHubConfig(hubDir);
3023
2053
  const worktreeBase = getWorktreeBase();
3024
- const worktreePath = join14(worktreeBase, name);
3025
- console.log(chalk13.blue(`
2054
+ const worktreePath = join12(worktreeBase, name);
2055
+ console.log(chalk12.blue(`
3026
2056
  \u2501\u2501\u2501 Creating worktree: ${name} \u2501\u2501\u2501
3027
2057
  `));
3028
- await mkdir8(worktreeBase, { recursive: true });
3029
- console.log(chalk13.cyan(" Creating git worktree..."));
2058
+ await mkdir7(worktreeBase, { recursive: true });
2059
+ console.log(chalk12.cyan(" Creating git worktree..."));
3030
2060
  try {
3031
2061
  execSync9(`git worktree add "${worktreePath}" --detach`, {
3032
2062
  cwd: hubDir,
3033
2063
  stdio: "inherit"
3034
2064
  });
3035
2065
  } catch {
3036
- console.log(chalk13.red(" Failed to create worktree. Make sure you have commits in this repo.\n"));
2066
+ console.log(chalk12.red(" Failed to create worktree. Make sure you have commits in this repo.\n"));
3037
2067
  return;
3038
2068
  }
3039
- console.log(chalk13.cyan(" Copying environment files..."));
2069
+ console.log(chalk12.cyan(" Copying environment files..."));
3040
2070
  for (const repo of config.repos) {
3041
2071
  if (!repo.env_file) continue;
3042
- const srcEnv = join14(hubDir, repo.path, repo.env_file);
3043
- if (!existsSync11(srcEnv)) continue;
3044
- const destDir = join14(worktreePath, repo.path);
3045
- if (existsSync11(destDir)) {
3046
- const destEnv = join14(destDir, repo.env_file);
2072
+ const srcEnv = join12(hubDir, repo.path, repo.env_file);
2073
+ if (!existsSync10(srcEnv)) continue;
2074
+ const destDir = join12(worktreePath, repo.path);
2075
+ if (existsSync10(destDir)) {
2076
+ const destEnv = join12(destDir, repo.env_file);
3047
2077
  try {
3048
- await cp4(srcEnv, destEnv);
3049
- console.log(chalk13.green(` ${repo.name}: Copied ${repo.env_file}`));
2078
+ await cp3(srcEnv, destEnv);
2079
+ console.log(chalk12.green(` ${repo.name}: Copied ${repo.env_file}`));
3050
2080
  } catch {
3051
- console.log(chalk13.dim(` ${repo.name}: Could not copy env file`));
2081
+ console.log(chalk12.dim(` ${repo.name}: Could not copy env file`));
3052
2082
  }
3053
2083
  }
3054
2084
  }
3055
- console.log(chalk13.green(`
2085
+ console.log(chalk12.green(`
3056
2086
  Worktree created at: ${worktreePath}`));
3057
- console.log(chalk13.cyan(`Open in Cursor: cursor ${worktreePath}
2087
+ console.log(chalk12.cyan(`Open in Cursor: cursor ${worktreePath}
3058
2088
  `));
3059
2089
  })
3060
2090
  ).addCommand(
3061
- new Command13("list").description("List all worktrees").action(async () => {
2091
+ new Command12("list").description("List all worktrees").action(async () => {
3062
2092
  const hubDir = process.cwd();
3063
2093
  if (!isGitRepo(hubDir)) {
3064
- console.log(chalk13.red("\nThis directory is not a git repository."));
3065
- console.log(chalk13.dim("Worktrees require a git repository.\n"));
2094
+ console.log(chalk12.red("\nThis directory is not a git repository."));
2095
+ console.log(chalk12.dim("Worktrees require a git repository.\n"));
3066
2096
  return;
3067
2097
  }
3068
- console.log(chalk13.blue("\n\u2501\u2501\u2501 Git Worktrees \u2501\u2501\u2501\n"));
2098
+ console.log(chalk12.blue("\n\u2501\u2501\u2501 Git Worktrees \u2501\u2501\u2501\n"));
3069
2099
  execSync9("git worktree list", { cwd: hubDir, stdio: "inherit" });
3070
2100
  console.log();
3071
2101
  })
3072
2102
  ).addCommand(
3073
- new Command13("remove").description("Remove a worktree").argument("<name>", "Worktree name").action(async (name) => {
2103
+ new Command12("remove").description("Remove a worktree").argument("<name>", "Worktree name").action(async (name) => {
3074
2104
  const hubDir = process.cwd();
3075
2105
  if (!isGitRepo(hubDir)) {
3076
- console.log(chalk13.red("\nThis directory is not a git repository."));
3077
- console.log(chalk13.dim("Worktrees require a git repository.\n"));
2106
+ console.log(chalk12.red("\nThis directory is not a git repository."));
2107
+ console.log(chalk12.dim("Worktrees require a git repository.\n"));
3078
2108
  return;
3079
2109
  }
3080
- const worktreePath = join14(getWorktreeBase(), name);
3081
- console.log(chalk13.blue(`
2110
+ const worktreePath = join12(getWorktreeBase(), name);
2111
+ console.log(chalk12.blue(`
3082
2112
  \u2501\u2501\u2501 Removing worktree: ${name} \u2501\u2501\u2501
3083
2113
  `));
3084
2114
  try {
@@ -3086,39 +2116,39 @@ Worktree created at: ${worktreePath}`));
3086
2116
  cwd: hubDir,
3087
2117
  stdio: "inherit"
3088
2118
  });
3089
- console.log(chalk13.green(" Worktree removed\n"));
2119
+ console.log(chalk12.green(" Worktree removed\n"));
3090
2120
  } catch {
3091
- console.log(chalk13.red(` Failed to remove worktree '${name}'.
2121
+ console.log(chalk12.red(` Failed to remove worktree '${name}'.
3092
2122
  `));
3093
2123
  }
3094
2124
  })
3095
2125
  ).addCommand(
3096
- new Command13("copy-envs").description("Copy environment files to a worktree").argument("[name]", "Worktree name (copies to that worktree)").action(async (name) => {
2126
+ new Command12("copy-envs").description("Copy environment files to a worktree").argument("[name]", "Worktree name (copies to that worktree)").action(async (name) => {
3097
2127
  const hubDir = process.cwd();
3098
2128
  const config = await loadHubConfig(hubDir);
3099
- const targetDir = name ? join14(getWorktreeBase(), name) : hubDir;
3100
- if (!existsSync11(targetDir)) {
3101
- console.log(chalk13.red(`
2129
+ const targetDir = name ? join12(getWorktreeBase(), name) : hubDir;
2130
+ if (!existsSync10(targetDir)) {
2131
+ console.log(chalk12.red(`
3102
2132
  Worktree '${name}' not found at ${targetDir}
3103
2133
  `));
3104
2134
  return;
3105
2135
  }
3106
- console.log(chalk13.blue("\n\u2501\u2501\u2501 Copying environment files \u2501\u2501\u2501\n"));
3107
- console.log(chalk13.cyan(` Source: ${hubDir}`));
3108
- console.log(chalk13.cyan(` Target: ${targetDir}
2136
+ console.log(chalk12.blue("\n\u2501\u2501\u2501 Copying environment files \u2501\u2501\u2501\n"));
2137
+ console.log(chalk12.cyan(` Source: ${hubDir}`));
2138
+ console.log(chalk12.cyan(` Target: ${targetDir}
3109
2139
  `));
3110
2140
  for (const repo of config.repos) {
3111
2141
  if (!repo.env_file) continue;
3112
- const srcEnv = join14(hubDir, repo.path, repo.env_file);
3113
- if (!existsSync11(srcEnv)) continue;
3114
- const destDir = join14(targetDir, repo.path);
3115
- if (!existsSync11(destDir)) continue;
3116
- const destEnv = join14(destDir, repo.env_file);
2142
+ const srcEnv = join12(hubDir, repo.path, repo.env_file);
2143
+ if (!existsSync10(srcEnv)) continue;
2144
+ const destDir = join12(targetDir, repo.path);
2145
+ if (!existsSync10(destDir)) continue;
2146
+ const destEnv = join12(destDir, repo.env_file);
3117
2147
  try {
3118
- await cp4(srcEnv, destEnv);
3119
- console.log(chalk13.green(` ${repo.name}: Copied ${repo.env_file}`));
2148
+ await cp3(srcEnv, destEnv);
2149
+ console.log(chalk12.green(` ${repo.name}: Copied ${repo.env_file}`));
3120
2150
  } catch {
3121
- console.log(chalk13.red(` ${repo.name}: Failed to copy`));
2151
+ console.log(chalk12.red(` ${repo.name}: Failed to copy`));
3122
2152
  }
3123
2153
  }
3124
2154
  console.log();
@@ -3126,11 +2156,11 @@ Worktree '${name}' not found at ${targetDir}
3126
2156
  );
3127
2157
 
3128
2158
  // src/commands/doctor.ts
3129
- import { Command as Command14 } from "commander";
3130
- import { existsSync as existsSync12 } from "fs";
3131
- import { join as join15 } from "path";
2159
+ import { Command as Command13 } from "commander";
2160
+ import { existsSync as existsSync11 } from "fs";
2161
+ import { join as join13 } from "path";
3132
2162
  import { execSync as execSync10 } from "child_process";
3133
- import chalk14 from "chalk";
2163
+ import chalk13 from "chalk";
3134
2164
  var CHECKS = [
3135
2165
  { name: "git", command: "git", versionFlag: "--version", required: true },
3136
2166
  { name: "docker", command: "docker", versionFlag: "--version", required: true },
@@ -3185,7 +2215,7 @@ function versionMatches(actual, expected) {
3185
2215
  const actualClean = extractVersion2(actual);
3186
2216
  return actualClean.startsWith(expected) || expected.startsWith(actualClean);
3187
2217
  }
3188
- var doctorCommand = new Command14("doctor").description("Check required dependencies and tool versions from hub.yaml").action(async () => {
2218
+ var doctorCommand = new Command13("doctor").description("Check required dependencies and tool versions from hub.yaml").action(async () => {
3189
2219
  const hubDir = process.cwd();
3190
2220
  let config;
3191
2221
  try {
@@ -3193,42 +2223,42 @@ var doctorCommand = new Command14("doctor").description("Check required dependen
3193
2223
  } catch {
3194
2224
  config = null;
3195
2225
  }
3196
- console.log(chalk14.blue("\nChecking dependencies\n"));
2226
+ console.log(chalk13.blue("\nChecking dependencies\n"));
3197
2227
  let allOk = true;
3198
2228
  const required = CHECKS.filter((c) => c.required);
3199
2229
  const recommended = CHECKS.filter((c) => !c.required);
3200
- console.log(chalk14.cyan("Required:"));
2230
+ console.log(chalk13.cyan("Required:"));
3201
2231
  for (const check of required) {
3202
2232
  const result = checkCommand(check);
3203
2233
  if (result.found) {
3204
- console.log(chalk14.green(` \u2713 ${check.name}: ${result.version}`));
2234
+ console.log(chalk13.green(` \u2713 ${check.name}: ${result.version}`));
3205
2235
  } else {
3206
- console.log(chalk14.red(` \u2717 ${check.name}: not found`));
2236
+ console.log(chalk13.red(` \u2717 ${check.name}: not found`));
3207
2237
  allOk = false;
3208
2238
  }
3209
2239
  }
3210
2240
  console.log();
3211
- console.log(chalk14.cyan("Recommended:"));
2241
+ console.log(chalk13.cyan("Recommended:"));
3212
2242
  for (const check of recommended) {
3213
2243
  const result = checkCommand(check);
3214
2244
  if (result.found) {
3215
- console.log(chalk14.green(` \u2713 ${check.name}: ${result.version}`));
2245
+ console.log(chalk13.green(` \u2713 ${check.name}: ${result.version}`));
3216
2246
  } else {
3217
- console.log(chalk14.dim(` - ${check.name}: not found`));
2247
+ console.log(chalk13.dim(` - ${check.name}: not found`));
3218
2248
  }
3219
2249
  }
3220
2250
  if (config?.tools && Object.keys(config.tools).length > 0) {
3221
2251
  console.log();
3222
- console.log(chalk14.cyan("Hub tools (from hub.yaml):"));
2252
+ console.log(chalk13.cyan("Hub tools (from hub.yaml):"));
3223
2253
  for (const [tool, expected] of Object.entries(config.tools)) {
3224
2254
  const actual = getToolVersion(tool);
3225
2255
  if (!actual) {
3226
- console.log(chalk14.red(` \u2717 ${tool}: not found (expected ${expected})`));
2256
+ console.log(chalk13.red(` \u2717 ${tool}: not found (expected ${expected})`));
3227
2257
  allOk = false;
3228
2258
  } else if (versionMatches(actual, expected)) {
3229
- console.log(chalk14.green(` \u2713 ${tool}: ${actual} (expected ${expected})`));
2259
+ console.log(chalk13.green(` \u2713 ${tool}: ${actual} (expected ${expected})`));
3230
2260
  } else {
3231
- console.log(chalk14.yellow(` \u26A0 ${tool}: ${actual} (expected ${expected})`));
2261
+ console.log(chalk13.yellow(` \u26A0 ${tool}: ${actual} (expected ${expected})`));
3232
2262
  }
3233
2263
  }
3234
2264
  }
@@ -3238,22 +2268,22 @@ var doctorCommand = new Command14("doctor").description("Check required dependen
3238
2268
  );
3239
2269
  if (reposWithTools.length > 0) {
3240
2270
  console.log();
3241
- console.log(chalk14.cyan("Repo-specific tools:"));
2271
+ console.log(chalk13.cyan("Repo-specific tools:"));
3242
2272
  for (const repo of reposWithTools) {
3243
- const repoDir = join15(hubDir, repo.path);
3244
- if (!existsSync12(repoDir)) {
3245
- console.log(chalk14.dim(` ${repo.name}: not cloned, skipping`));
2273
+ const repoDir = join13(hubDir, repo.path);
2274
+ if (!existsSync11(repoDir)) {
2275
+ console.log(chalk13.dim(` ${repo.name}: not cloned, skipping`));
3246
2276
  continue;
3247
2277
  }
3248
- console.log(chalk14.yellow(` \u25B8 ${repo.name}`));
2278
+ console.log(chalk13.yellow(` \u25B8 ${repo.name}`));
3249
2279
  for (const [tool, expected] of Object.entries(repo.tools)) {
3250
2280
  const actual = getToolVersion(tool);
3251
2281
  if (!actual) {
3252
- console.log(chalk14.red(` \u2717 ${tool}: not found (expected ${expected})`));
2282
+ console.log(chalk13.red(` \u2717 ${tool}: not found (expected ${expected})`));
3253
2283
  } else if (versionMatches(actual, expected)) {
3254
- console.log(chalk14.green(` \u2713 ${tool}: ${actual} (expected ${expected})`));
2284
+ console.log(chalk13.green(` \u2713 ${tool}: ${actual} (expected ${expected})`));
3255
2285
  } else {
3256
- console.log(chalk14.yellow(` \u26A0 ${tool}: ${actual} (expected ${expected})`));
2286
+ console.log(chalk13.yellow(` \u26A0 ${tool}: ${actual} (expected ${expected})`));
3257
2287
  }
3258
2288
  }
3259
2289
  }
@@ -3261,23 +2291,23 @@ var doctorCommand = new Command14("doctor").description("Check required dependen
3261
2291
  }
3262
2292
  console.log();
3263
2293
  if (allOk) {
3264
- console.log(chalk14.green("All checks passed!\n"));
2294
+ console.log(chalk13.green("All checks passed!\n"));
3265
2295
  } else {
3266
- console.log(chalk14.red("Some checks failed.\n"));
2296
+ console.log(chalk13.red("Some checks failed.\n"));
3267
2297
  if (config?.tools) {
3268
- console.log(chalk14.cyan("Fix with: hub tools install\n"));
2298
+ console.log(chalk13.cyan("Fix with: hub tools install\n"));
3269
2299
  }
3270
2300
  process.exit(1);
3271
2301
  }
3272
2302
  });
3273
2303
 
3274
2304
  // src/commands/tools.ts
3275
- import { Command as Command15 } from "commander";
3276
- import { existsSync as existsSync13 } from "fs";
3277
- import { writeFile as writeFile10 } from "fs/promises";
3278
- import { join as join16 } from "path";
2305
+ import { Command as Command14 } from "commander";
2306
+ import { existsSync as existsSync12 } from "fs";
2307
+ import { writeFile as writeFile9 } from "fs/promises";
2308
+ import { join as join14 } from "path";
3279
2309
  import { execSync as execSync11 } from "child_process";
3280
- import chalk15 from "chalk";
2310
+ import chalk14 from "chalk";
3281
2311
  function hasMise2() {
3282
2312
  try {
3283
2313
  execSync11("mise --version", { stdio: ["pipe", "pipe", "pipe"] });
@@ -3314,148 +2344,148 @@ async function generateMiseFiles(config, hubDir) {
3314
2344
  let count = 0;
3315
2345
  if (config.tools && Object.keys(config.tools).length > 0) {
3316
2346
  const content = generateMiseToml2(config.tools, config.mise_settings);
3317
- await writeFile10(join16(hubDir, ".mise.toml"), content, "utf-8");
3318
- console.log(chalk15.green(` Generated .mise.toml (${Object.keys(config.tools).length} tools)`));
2347
+ await writeFile9(join14(hubDir, ".mise.toml"), content, "utf-8");
2348
+ console.log(chalk14.green(` Generated .mise.toml (${Object.keys(config.tools).length} tools)`));
3319
2349
  count++;
3320
2350
  }
3321
2351
  for (const repo of config.repos) {
3322
2352
  if (!repo.tools || Object.keys(repo.tools).length === 0) continue;
3323
- const repoDir = join16(hubDir, repo.path);
3324
- if (!existsSync13(repoDir)) {
3325
- console.log(chalk15.dim(` ${repo.name}: not cloned, skipping`));
2353
+ const repoDir = join14(hubDir, repo.path);
2354
+ if (!existsSync12(repoDir)) {
2355
+ console.log(chalk14.dim(` ${repo.name}: not cloned, skipping`));
3326
2356
  continue;
3327
2357
  }
3328
2358
  const merged = mergeTools(config.tools || {}, repo.tools);
3329
2359
  const content = generateMiseToml2(merged);
3330
- await writeFile10(join16(repoDir, ".mise.toml"), content, "utf-8");
3331
- console.log(chalk15.green(` ${repo.name}: Generated .mise.toml (${Object.keys(merged).length} tools)`));
2360
+ await writeFile9(join14(repoDir, ".mise.toml"), content, "utf-8");
2361
+ console.log(chalk14.green(` ${repo.name}: Generated .mise.toml (${Object.keys(merged).length} tools)`));
3332
2362
  count++;
3333
2363
  }
3334
2364
  return count;
3335
2365
  }
3336
- var toolsCommand = new Command15("tools").description("Manage development tool versions via mise").addCommand(
3337
- new Command15("install").description("Install all tools defined in hub.yaml using mise").option("--generate", "Generate .mise.toml files before installing").action(async (opts) => {
2366
+ var toolsCommand = new Command14("tools").description("Manage development tool versions via mise").addCommand(
2367
+ new Command14("install").description("Install all tools defined in hub.yaml using mise").option("--generate", "Generate .mise.toml files before installing").action(async (opts) => {
3338
2368
  const hubDir = process.cwd();
3339
2369
  const config = await loadHubConfig(hubDir);
3340
2370
  if (!hasMise2()) {
3341
- console.log(chalk15.red("\nmise is not installed."));
3342
- console.log(chalk15.cyan("Install with: curl https://mise.run | sh"));
3343
- console.log(chalk15.cyan("Or: brew install mise\n"));
2371
+ console.log(chalk14.red("\nmise is not installed."));
2372
+ console.log(chalk14.cyan("Install with: curl https://mise.run | sh"));
2373
+ console.log(chalk14.cyan("Or: brew install mise\n"));
3344
2374
  return;
3345
2375
  }
3346
2376
  if (!config.tools && !config.repos.some((r) => r.tools)) {
3347
- console.log(chalk15.yellow("\nNo tools defined in hub.yaml\n"));
2377
+ console.log(chalk14.yellow("\nNo tools defined in hub.yaml\n"));
3348
2378
  return;
3349
2379
  }
3350
- console.log(chalk15.blue("\n\u2501\u2501\u2501 Installing tools \u2501\u2501\u2501\n"));
2380
+ console.log(chalk14.blue("\n\u2501\u2501\u2501 Installing tools \u2501\u2501\u2501\n"));
3351
2381
  if (opts.generate) {
3352
2382
  await generateMiseFiles(config, hubDir);
3353
2383
  console.log();
3354
2384
  }
3355
2385
  if (config.tools && Object.keys(config.tools).length > 0) {
3356
- console.log(chalk15.cyan("Installing hub-level tools..."));
2386
+ console.log(chalk14.cyan("Installing hub-level tools..."));
3357
2387
  try {
3358
2388
  execSync11("mise trust && mise install", {
3359
2389
  cwd: hubDir,
3360
2390
  stdio: "inherit"
3361
2391
  });
3362
- console.log(chalk15.green(" Hub tools installed\n"));
2392
+ console.log(chalk14.green(" Hub tools installed\n"));
3363
2393
  } catch {
3364
- console.log(chalk15.red(" Failed to install hub tools\n"));
2394
+ console.log(chalk14.red(" Failed to install hub tools\n"));
3365
2395
  }
3366
2396
  }
3367
2397
  for (const repo of config.repos) {
3368
2398
  if (!repo.tools || Object.keys(repo.tools).length === 0) continue;
3369
- const repoDir = join16(hubDir, repo.path);
3370
- if (!existsSync13(repoDir)) {
3371
- console.log(chalk15.dim(` ${repo.name}: not cloned, skipping`));
2399
+ const repoDir = join14(hubDir, repo.path);
2400
+ if (!existsSync12(repoDir)) {
2401
+ console.log(chalk14.dim(` ${repo.name}: not cloned, skipping`));
3372
2402
  continue;
3373
2403
  }
3374
- console.log(chalk15.yellow(`\u25B8 ${repo.name}`));
2404
+ console.log(chalk14.yellow(`\u25B8 ${repo.name}`));
3375
2405
  try {
3376
2406
  execSync11("mise trust 2>/dev/null; mise install", {
3377
2407
  cwd: repoDir,
3378
2408
  stdio: "inherit"
3379
2409
  });
3380
- console.log(chalk15.green(" Tools installed"));
2410
+ console.log(chalk14.green(" Tools installed"));
3381
2411
  } catch {
3382
- console.log(chalk15.red(" Failed to install tools"));
2412
+ console.log(chalk14.red(" Failed to install tools"));
3383
2413
  }
3384
2414
  }
3385
- console.log(chalk15.green("\nAll tools installed!\n"));
3386
- console.log(chalk15.cyan("Make sure mise is activated in your shell:"));
2415
+ console.log(chalk14.green("\nAll tools installed!\n"));
2416
+ console.log(chalk14.cyan("Make sure mise is activated in your shell:"));
3387
2417
  console.log(' eval "$(mise activate zsh)" # zsh');
3388
2418
  console.log(' eval "$(mise activate bash)" # bash\n');
3389
2419
  })
3390
2420
  ).addCommand(
3391
- new Command15("generate").description("Generate .mise.toml files from hub.yaml").action(async () => {
2421
+ new Command14("generate").description("Generate .mise.toml files from hub.yaml").action(async () => {
3392
2422
  const hubDir = process.cwd();
3393
2423
  const config = await loadHubConfig(hubDir);
3394
2424
  if (!config.tools && !config.repos.some((r) => r.tools)) {
3395
- console.log(chalk15.yellow("\nNo tools defined in hub.yaml\n"));
2425
+ console.log(chalk14.yellow("\nNo tools defined in hub.yaml\n"));
3396
2426
  return;
3397
2427
  }
3398
- console.log(chalk15.blue("\n\u2501\u2501\u2501 Generating .mise.toml files \u2501\u2501\u2501\n"));
2428
+ console.log(chalk14.blue("\n\u2501\u2501\u2501 Generating .mise.toml files \u2501\u2501\u2501\n"));
3399
2429
  const count = await generateMiseFiles(config, hubDir);
3400
- console.log(chalk15.green(`
2430
+ console.log(chalk14.green(`
3401
2431
  Generated ${count} .mise.toml file(s)
3402
2432
  `));
3403
- console.log(chalk15.cyan("Install with: hub tools install\n"));
2433
+ console.log(chalk14.cyan("Install with: hub tools install\n"));
3404
2434
  })
3405
2435
  ).addCommand(
3406
- new Command15("check").description("Verify installed tool versions match hub.yaml").action(async () => {
2436
+ new Command14("check").description("Verify installed tool versions match hub.yaml").action(async () => {
3407
2437
  const hubDir = process.cwd();
3408
2438
  const config = await loadHubConfig(hubDir);
3409
2439
  if (!config.tools && !config.repos.some((r) => r.tools)) {
3410
- console.log(chalk15.yellow("\nNo tools defined in hub.yaml\n"));
2440
+ console.log(chalk14.yellow("\nNo tools defined in hub.yaml\n"));
3411
2441
  return;
3412
2442
  }
3413
- console.log(chalk15.blue("\n\u2501\u2501\u2501 Checking tool versions \u2501\u2501\u2501\n"));
2443
+ console.log(chalk14.blue("\n\u2501\u2501\u2501 Checking tool versions \u2501\u2501\u2501\n"));
3414
2444
  let allOk = true;
3415
2445
  if (config.tools) {
3416
- console.log(chalk15.cyan("Hub tools:"));
2446
+ console.log(chalk14.cyan("Hub tools:"));
3417
2447
  for (const [tool, expected] of Object.entries(config.tools)) {
3418
2448
  const actual = getInstalledVersion(tool);
3419
2449
  if (!actual) {
3420
- console.log(chalk15.red(` \u2717 ${tool}: not found (expected ${expected})`));
2450
+ console.log(chalk14.red(` \u2717 ${tool}: not found (expected ${expected})`));
3421
2451
  allOk = false;
3422
2452
  } else if (actual.includes(expected) || expected.includes(extractVersion(actual))) {
3423
- console.log(chalk15.green(` \u2713 ${tool} ${expected}`));
2453
+ console.log(chalk14.green(` \u2713 ${tool} ${expected}`));
3424
2454
  } else {
3425
- console.log(chalk15.yellow(` \u26A0 ${tool}: ${extractVersion(actual)} (expected ${expected})`));
2455
+ console.log(chalk14.yellow(` \u26A0 ${tool}: ${extractVersion(actual)} (expected ${expected})`));
3426
2456
  allOk = false;
3427
2457
  }
3428
2458
  }
3429
2459
  }
3430
2460
  for (const repo of config.repos) {
3431
2461
  if (!repo.tools || Object.keys(repo.tools).length === 0) continue;
3432
- const repoDir = join16(hubDir, repo.path);
3433
- if (!existsSync13(repoDir)) {
3434
- console.log(chalk15.dim(`
2462
+ const repoDir = join14(hubDir, repo.path);
2463
+ if (!existsSync12(repoDir)) {
2464
+ console.log(chalk14.dim(`
3435
2465
  ${repo.name}: not cloned`));
3436
2466
  continue;
3437
2467
  }
3438
- console.log(chalk15.yellow(`
2468
+ console.log(chalk14.yellow(`
3439
2469
  \u25B8 ${repo.name}`));
3440
2470
  for (const [tool, expected] of Object.entries(repo.tools)) {
3441
2471
  const actual = getInstalledVersion(tool);
3442
2472
  if (!actual) {
3443
- console.log(chalk15.red(` \u2717 ${tool}: not found (expected ${expected})`));
2473
+ console.log(chalk14.red(` \u2717 ${tool}: not found (expected ${expected})`));
3444
2474
  allOk = false;
3445
2475
  } else if (actual.includes(expected) || expected.includes(extractVersion(actual))) {
3446
- console.log(chalk15.green(` \u2713 ${tool} ${expected}`));
2476
+ console.log(chalk14.green(` \u2713 ${tool} ${expected}`));
3447
2477
  } else {
3448
- console.log(chalk15.yellow(` \u26A0 ${tool}: ${extractVersion(actual)} (expected ${expected})`));
2478
+ console.log(chalk14.yellow(` \u26A0 ${tool}: ${extractVersion(actual)} (expected ${expected})`));
3449
2479
  allOk = false;
3450
2480
  }
3451
2481
  }
3452
2482
  }
3453
2483
  console.log();
3454
2484
  if (allOk) {
3455
- console.log(chalk15.green("All tool versions match!\n"));
2485
+ console.log(chalk14.green("All tool versions match!\n"));
3456
2486
  } else {
3457
- console.log(chalk15.red("Some tools are missing or have wrong versions.\n"));
3458
- console.log(chalk15.cyan("Fix with: hub tools install --generate\n"));
2487
+ console.log(chalk14.red("Some tools are missing or have wrong versions.\n"));
2488
+ console.log(chalk14.cyan("Fix with: hub tools install --generate\n"));
3459
2489
  }
3460
2490
  })
3461
2491
  );
@@ -3489,24 +2519,24 @@ function extractVersion(s) {
3489
2519
  }
3490
2520
 
3491
2521
  // src/commands/memory.ts
3492
- import { Command as Command16 } from "commander";
3493
- import { existsSync as existsSync14 } from "fs";
3494
- import { mkdir as mkdir9, readdir as readdir6, readFile as readFile9, writeFile as writeFile11, rm as rm5, appendFile as appendFile2 } from "fs/promises";
3495
- import { join as join17, resolve as resolve6, basename as basename2 } from "path";
3496
- import chalk16 from "chalk";
2522
+ import { Command as Command15 } from "commander";
2523
+ import { existsSync as existsSync13 } from "fs";
2524
+ import { mkdir as mkdir8, readdir as readdir5, readFile as readFile7, writeFile as writeFile10, rm as rm5, appendFile as appendFile2 } from "fs/promises";
2525
+ import { join as join15, resolve as resolve5, basename as basename2 } from "path";
2526
+ import chalk15 from "chalk";
3497
2527
  async function ensureLanceDbIgnored(memoriesDir, hubDir) {
3498
2528
  const relative = memoriesDir.replace(hubDir + "/", "");
3499
2529
  const pattern = `${relative}/.lancedb/`;
3500
- const gitignorePath = join17(hubDir, ".gitignore");
3501
- if (existsSync14(gitignorePath)) {
3502
- const content = await readFile9(gitignorePath, "utf-8");
2530
+ const gitignorePath = join15(hubDir, ".gitignore");
2531
+ if (existsSync13(gitignorePath)) {
2532
+ const content = await readFile7(gitignorePath, "utf-8");
3503
2533
  if (content.includes(".lancedb")) return;
3504
2534
  await appendFile2(gitignorePath, `
3505
2535
  # Memory vector store (generated)
3506
2536
  ${pattern}
3507
2537
  `);
3508
2538
  } else {
3509
- await writeFile11(gitignorePath, `# Memory vector store (generated)
2539
+ await writeFile10(gitignorePath, `# Memory vector store (generated)
3510
2540
  ${pattern}
3511
2541
  `, "utf-8");
3512
2542
  }
@@ -3519,7 +2549,7 @@ var VALID_CATEGORIES = [
3519
2549
  "gotchas"
3520
2550
  ];
3521
2551
  function getMemoriesPath(hubDir, configPath) {
3522
- return resolve6(hubDir, configPath || "memories");
2552
+ return resolve5(hubDir, configPath || "memories");
3523
2553
  }
3524
2554
  function parseFrontmatter(raw) {
3525
2555
  const match = raw.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
@@ -3551,20 +2581,20 @@ function buildFrontmatter(data) {
3551
2581
  return lines.join("\n");
3552
2582
  }
3553
2583
  async function listMemories(memoriesDir, opts) {
3554
- if (!existsSync14(memoriesDir)) {
3555
- console.log(chalk16.dim(" No memories directory found."));
2584
+ if (!existsSync13(memoriesDir)) {
2585
+ console.log(chalk15.dim(" No memories directory found."));
3556
2586
  return;
3557
2587
  }
3558
2588
  let total = 0;
3559
2589
  for (const cat of VALID_CATEGORIES) {
3560
2590
  if (opts.category && opts.category !== cat) continue;
3561
- const catDir = join17(memoriesDir, cat);
3562
- if (!existsSync14(catDir)) continue;
3563
- const files = (await readdir6(catDir)).filter((f) => f.endsWith(".md"));
2591
+ const catDir = join15(memoriesDir, cat);
2592
+ if (!existsSync13(catDir)) continue;
2593
+ const files = (await readdir5(catDir)).filter((f) => f.endsWith(".md"));
3564
2594
  if (files.length === 0) continue;
3565
2595
  const entries = [];
3566
2596
  for (const file of files) {
3567
- const raw = await readFile9(join17(catDir, file), "utf-8");
2597
+ const raw = await readFile7(join15(catDir, file), "utf-8");
3568
2598
  const { data } = parseFrontmatter(raw);
3569
2599
  const status = data.status || "active";
3570
2600
  if (opts.status && status !== opts.status) continue;
@@ -3577,29 +2607,29 @@ async function listMemories(memoriesDir, opts) {
3577
2607
  });
3578
2608
  }
3579
2609
  if (entries.length === 0) continue;
3580
- console.log(chalk16.cyan(`
2610
+ console.log(chalk15.cyan(`
3581
2611
  ${cat} (${entries.length})`));
3582
2612
  for (const e of entries) {
3583
- const statusIcon = e.status === "active" ? chalk16.green("\u25CF") : chalk16.dim("\u25CB");
3584
- const tags = e.tags.length > 0 ? chalk16.dim(` [${e.tags.join(", ")}]`) : "";
3585
- console.log(` ${statusIcon} ${chalk16.yellow(e.id)} \u2014 ${e.title} ${chalk16.dim(`(${e.date})`)}${tags}`);
2613
+ const statusIcon = e.status === "active" ? chalk15.green("\u25CF") : chalk15.dim("\u25CB");
2614
+ const tags = e.tags.length > 0 ? chalk15.dim(` [${e.tags.join(", ")}]`) : "";
2615
+ console.log(` ${statusIcon} ${chalk15.yellow(e.id)} \u2014 ${e.title} ${chalk15.dim(`(${e.date})`)}${tags}`);
3586
2616
  }
3587
2617
  total += entries.length;
3588
2618
  }
3589
2619
  if (total === 0) {
3590
- console.log(chalk16.dim(" No memories found."));
2620
+ console.log(chalk15.dim(" No memories found."));
3591
2621
  } else {
3592
- console.log(chalk16.green(`
2622
+ console.log(chalk15.green(`
3593
2623
  Total: ${total} memories
3594
2624
  `));
3595
2625
  }
3596
2626
  }
3597
- var memoryCommand = new Command16("memory").description("Manage team memories \u2014 persistent knowledge base for AI context").addCommand(
3598
- new Command16("add").description("Create a new memory entry").argument("<category>", `Category: ${VALID_CATEGORIES.join(", ")}`).argument("<title>", "Memory title").option("-c, --content <content>", "Memory content (or provide via stdin)").option("-t, --tags <tags>", "Comma-separated tags").option("-a, --author <author>", "Author name").action(
2627
+ var memoryCommand = new Command15("memory").description("Manage team memories \u2014 persistent knowledge base for AI context").addCommand(
2628
+ new Command15("add").description("Create a new memory entry").argument("<category>", `Category: ${VALID_CATEGORIES.join(", ")}`).argument("<title>", "Memory title").option("-c, --content <content>", "Memory content (or provide via stdin)").option("-t, --tags <tags>", "Comma-separated tags").option("-a, --author <author>", "Author name").action(
3599
2629
  async (category, title, opts) => {
3600
2630
  if (!VALID_CATEGORIES.includes(category)) {
3601
2631
  console.log(
3602
- chalk16.red(`
2632
+ chalk15.red(`
3603
2633
  Invalid category: ${category}. Valid: ${VALID_CATEGORIES.join(", ")}
3604
2634
  `)
3605
2635
  );
@@ -3613,13 +2643,13 @@ var memoryCommand = new Command16("memory").description("Manage team memories \u
3613
2643
  } catch {
3614
2644
  memoriesDir = getMemoriesPath(hubDir);
3615
2645
  }
3616
- const catDir = join17(memoriesDir, category);
3617
- await mkdir9(catDir, { recursive: true });
2646
+ const catDir = join15(memoriesDir, category);
2647
+ await mkdir8(catDir, { recursive: true });
3618
2648
  await ensureLanceDbIgnored(memoriesDir, hubDir);
3619
2649
  const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
3620
2650
  const slug = title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
3621
2651
  const id = `${date}-${slug}`;
3622
- const filePath = join17(catDir, `${id}.md`);
2652
+ const filePath = join15(catDir, `${id}.md`);
3623
2653
  const fm = {
3624
2654
  title,
3625
2655
  category,
@@ -3639,19 +2669,19 @@ var memoryCommand = new Command16("memory").description("Manage team memories \u
3639
2669
 
3640
2670
  ${content}
3641
2671
  `;
3642
- await writeFile11(filePath, fileContent, "utf-8");
3643
- console.log(chalk16.green(`
2672
+ await writeFile10(filePath, fileContent, "utf-8");
2673
+ console.log(chalk15.green(`
3644
2674
  Created: ${category}/${id}.md`));
3645
- console.log(chalk16.dim(` Path: ${filePath}`));
2675
+ console.log(chalk15.dim(` Path: ${filePath}`));
3646
2676
  if (!opts.content) {
3647
- console.log(chalk16.yellow(" Edit the file to add content.\n"));
2677
+ console.log(chalk15.yellow(" Edit the file to add content.\n"));
3648
2678
  } else {
3649
2679
  console.log();
3650
2680
  }
3651
2681
  }
3652
2682
  )
3653
2683
  ).addCommand(
3654
- new Command16("list").description("List all memories").option("-c, --category <category>", "Filter by category").option("-s, --status <status>", "Filter by status (active, archived, superseded)").action(async (opts) => {
2684
+ new Command15("list").description("List all memories").option("-c, --category <category>", "Filter by category").option("-s, --status <status>", "Filter by status (active, archived, superseded)").action(async (opts) => {
3655
2685
  const hubDir = process.cwd();
3656
2686
  let memoriesDir;
3657
2687
  try {
@@ -3660,11 +2690,11 @@ ${content}
3660
2690
  } catch {
3661
2691
  memoriesDir = getMemoriesPath(hubDir);
3662
2692
  }
3663
- console.log(chalk16.blue("\nTeam Memories"));
2693
+ console.log(chalk15.blue("\nTeam Memories"));
3664
2694
  await listMemories(memoriesDir, opts);
3665
2695
  })
3666
2696
  ).addCommand(
3667
- new Command16("archive").description("Archive a memory (soft-delete)").argument("<id>", "Memory ID (filename without .md)").action(async (id) => {
2697
+ new Command15("archive").description("Archive a memory (soft-delete)").argument("<id>", "Memory ID (filename without .md)").action(async (id) => {
3668
2698
  const hubDir = process.cwd();
3669
2699
  let memoriesDir;
3670
2700
  try {
@@ -3675,28 +2705,28 @@ ${content}
3675
2705
  }
3676
2706
  let found = false;
3677
2707
  for (const cat of VALID_CATEGORIES) {
3678
- const filePath = join17(memoriesDir, cat, `${id}.md`);
3679
- if (!existsSync14(filePath)) continue;
3680
- const raw = await readFile9(filePath, "utf-8");
2708
+ const filePath = join15(memoriesDir, cat, `${id}.md`);
2709
+ if (!existsSync13(filePath)) continue;
2710
+ const raw = await readFile7(filePath, "utf-8");
3681
2711
  const { data, content } = parseFrontmatter(raw);
3682
2712
  data.status = "archived";
3683
2713
  const updated = `${buildFrontmatter(data)}
3684
2714
  ${content}`;
3685
- await writeFile11(filePath, updated, "utf-8");
3686
- console.log(chalk16.green(`
2715
+ await writeFile10(filePath, updated, "utf-8");
2716
+ console.log(chalk15.green(`
3687
2717
  Archived: ${cat}/${id}.md
3688
2718
  `));
3689
2719
  found = true;
3690
2720
  break;
3691
2721
  }
3692
2722
  if (!found) {
3693
- console.log(chalk16.red(`
2723
+ console.log(chalk15.red(`
3694
2724
  Memory "${id}" not found.
3695
2725
  `));
3696
2726
  }
3697
2727
  })
3698
2728
  ).addCommand(
3699
- new Command16("remove").description("Permanently delete a memory").argument("<id>", "Memory ID (filename without .md)").action(async (id) => {
2729
+ new Command15("remove").description("Permanently delete a memory").argument("<id>", "Memory ID (filename without .md)").action(async (id) => {
3700
2730
  const hubDir = process.cwd();
3701
2731
  let memoriesDir;
3702
2732
  try {
@@ -3707,17 +2737,17 @@ ${content}`;
3707
2737
  }
3708
2738
  let found = false;
3709
2739
  for (const cat of VALID_CATEGORIES) {
3710
- const filePath = join17(memoriesDir, cat, `${id}.md`);
3711
- if (!existsSync14(filePath)) continue;
2740
+ const filePath = join15(memoriesDir, cat, `${id}.md`);
2741
+ if (!existsSync13(filePath)) continue;
3712
2742
  await rm5(filePath);
3713
- console.log(chalk16.green(`
2743
+ console.log(chalk15.green(`
3714
2744
  Removed: ${cat}/${id}.md
3715
2745
  `));
3716
2746
  found = true;
3717
2747
  break;
3718
2748
  }
3719
2749
  if (!found) {
3720
- console.log(chalk16.red(`
2750
+ console.log(chalk15.red(`
3721
2751
  Memory "${id}" not found.
3722
2752
  `));
3723
2753
  }
@@ -3725,16 +2755,16 @@ ${content}`;
3725
2755
  );
3726
2756
 
3727
2757
  // src/commands/update.ts
3728
- import { Command as Command17 } from "commander";
2758
+ import { Command as Command16 } from "commander";
3729
2759
  import { execSync as execSync12 } from "child_process";
3730
2760
  import { readFileSync } from "fs";
3731
- import { join as join18, dirname } from "path";
2761
+ import { join as join16, dirname } from "path";
3732
2762
  import { fileURLToPath } from "url";
3733
- import chalk17 from "chalk";
2763
+ import chalk16 from "chalk";
3734
2764
  var PACKAGE_NAME = "@arvoretech/hub";
3735
2765
  function getCurrentVersion() {
3736
2766
  const __dirname = dirname(fileURLToPath(import.meta.url));
3737
- const pkgPath = join18(__dirname, "..", "package.json");
2767
+ const pkgPath = join16(__dirname, "..", "package.json");
3738
2768
  const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
3739
2769
  return pkg.version;
3740
2770
  }
@@ -3757,77 +2787,77 @@ function detectPackageManager() {
3757
2787
  }
3758
2788
  }
3759
2789
  }
3760
- var updateCommand = new Command17("update").description("Update hub CLI to the latest version").option("--check", "Only check for updates without installing").action(async (opts) => {
2790
+ var updateCommand = new Command16("update").description("Update hub CLI to the latest version").option("--check", "Only check for updates without installing").action(async (opts) => {
3761
2791
  const currentVersion = getCurrentVersion();
3762
- console.log(chalk17.blue(`
2792
+ console.log(chalk16.blue(`
3763
2793
  Current version: ${currentVersion}`));
3764
2794
  let latestVersion;
3765
2795
  try {
3766
2796
  latestVersion = await getLatestVersion();
3767
2797
  } catch (err) {
3768
- console.log(chalk17.red(` Failed to check for updates: ${err.message}
2798
+ console.log(chalk16.red(` Failed to check for updates: ${err.message}
3769
2799
  `));
3770
2800
  return;
3771
2801
  }
3772
- console.log(chalk17.blue(` Latest version: ${latestVersion}`));
2802
+ console.log(chalk16.blue(` Latest version: ${latestVersion}`));
3773
2803
  if (currentVersion === latestVersion) {
3774
- console.log(chalk17.green("\n You're already on the latest version.\n"));
2804
+ console.log(chalk16.green("\n You're already on the latest version.\n"));
3775
2805
  return;
3776
2806
  }
3777
- console.log(chalk17.yellow(`
2807
+ console.log(chalk16.yellow(`
3778
2808
  Update available: ${currentVersion} \u2192 ${latestVersion}`));
3779
2809
  if (opts.check) {
3780
2810
  const pm2 = detectPackageManager();
3781
- console.log(chalk17.dim(`
2811
+ console.log(chalk16.dim(`
3782
2812
  Run 'hub update' or '${pm2} install -g ${PACKAGE_NAME}@latest' to update.
3783
2813
  `));
3784
2814
  return;
3785
2815
  }
3786
2816
  const pm = detectPackageManager();
3787
2817
  const installCmd = pm === "pnpm" ? `pnpm install -g ${PACKAGE_NAME}@latest` : pm === "yarn" ? `yarn global add ${PACKAGE_NAME}@latest` : `npm install -g ${PACKAGE_NAME}@latest`;
3788
- console.log(chalk17.cyan(`
2818
+ console.log(chalk16.cyan(`
3789
2819
  Updating with ${pm}...
3790
2820
  `));
3791
- console.log(chalk17.dim(` $ ${installCmd}
2821
+ console.log(chalk16.dim(` $ ${installCmd}
3792
2822
  `));
3793
2823
  try {
3794
2824
  execSync12(installCmd, { stdio: "inherit" });
3795
- console.log(chalk17.green(`
2825
+ console.log(chalk16.green(`
3796
2826
  Updated to ${latestVersion} successfully.
3797
2827
  `));
3798
2828
  } catch {
3799
- console.log(chalk17.red(`
2829
+ console.log(chalk16.red(`
3800
2830
  Update failed. Try running manually:`));
3801
- console.log(chalk17.dim(` $ ${installCmd}
2831
+ console.log(chalk16.dim(` $ ${installCmd}
3802
2832
  `));
3803
2833
  }
3804
2834
  });
3805
2835
 
3806
2836
  // src/commands/directory.ts
3807
- import { Command as Command18 } from "commander";
3808
- import chalk18 from "chalk";
2837
+ import { Command as Command17 } from "commander";
2838
+ import chalk17 from "chalk";
3809
2839
  var BASE_URL = "https://rhm-website.vercel.app/directory";
3810
- var directoryCommand = new Command18("directory").alias("dir").description("Browse the Repo Hub directory of skills, agents, hooks, and commands").argument("[query]", "Search term").option("-t, --type <type>", "Filter by type (skill, agent, hook, command)").action(async (query, opts) => {
2840
+ var directoryCommand = new Command17("directory").alias("dir").description("Browse the Repo Hub directory of skills, agents, hooks, and commands").argument("[query]", "Search term").option("-t, --type <type>", "Filter by type (skill, agent, hook, command)").action(async (query, opts) => {
3811
2841
  const params = new URLSearchParams();
3812
2842
  if (opts?.type) params.set("type", opts.type);
3813
2843
  if (query) params.set("q", query);
3814
2844
  const qs = params.toString();
3815
2845
  const url = qs ? `${BASE_URL}?${qs}` : BASE_URL;
3816
- console.log(chalk18.blue("\n Repo Hub Directory\n"));
3817
- console.log(chalk18.cyan(` ${url}
3818
- `));
3819
- console.log(chalk18.dim(" Install examples:"));
3820
- console.log(chalk18.dim(" hub skills add <owner>/<repo>/<skill>"));
3821
- console.log(chalk18.dim(" hub agents add <owner>/<repo>"));
3822
- console.log(chalk18.dim(" hub hooks add <owner>/<repo>"));
3823
- console.log(chalk18.dim(" hub commands add <owner>/<repo>\n"));
2846
+ console.log(chalk17.blue("\n Repo Hub Directory\n"));
2847
+ console.log(chalk17.cyan(` ${url}
2848
+ `));
2849
+ console.log(chalk17.dim(" Install examples:"));
2850
+ console.log(chalk17.dim(" hub skills add <owner>/<repo>/<skill>"));
2851
+ console.log(chalk17.dim(" hub agents add <owner>/<repo>"));
2852
+ console.log(chalk17.dim(" hub hooks add <owner>/<repo>"));
2853
+ console.log(chalk17.dim(" hub commands add <owner>/<repo>\n"));
3824
2854
  });
3825
2855
 
3826
2856
  // src/index.ts
3827
- var program = new Command19();
2857
+ var program = new Command18();
3828
2858
  program.name("hub").description(
3829
2859
  "Give your AI coding assistant the full picture. Multi-repo context, agent orchestration, and end-to-end workflows."
3830
- ).version("0.5.0").enablePositionalOptions();
2860
+ ).version("0.6.1").enablePositionalOptions();
3831
2861
  program.addCommand(initCommand);
3832
2862
  program.addCommand(addRepoCommand);
3833
2863
  program.addCommand(setupCommand);