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