@arvoretech/hub 0.6.1 → 0.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -112,7 +112,7 @@ async function checkAndAutoRegenerate(hubDir) {
112
112
  return;
113
113
  }
114
114
  console.log(chalk.yellow("\n Detected outdated configs, auto-regenerating..."));
115
- const { generators: generators2 } = await import("./generate-G3ZOX55F.js");
115
+ const { generators: generators2 } = await import("./generate-67HCNILJ.js");
116
116
  const generator = generators2[result.editor];
117
117
  if (!generator) {
118
118
  console.log(chalk.red(` Unknown editor '${result.editor}' in cache. Run 'hub generate' manually.`));
@@ -132,30 +132,30 @@ async function checkAndAutoRegenerate(hubDir) {
132
132
  var HUB_MARKER_START = "# >>> hub-managed (do not edit this section)";
133
133
  var HUB_MARKER_END = "# <<< hub-managed";
134
134
  var HOOK_EVENT_MAP = {
135
- session_start: { cursor: "sessionStart", claude: "SessionStart", kiro: void 0 },
136
- session_end: { cursor: "sessionEnd", claude: "SessionEnd", kiro: void 0 },
137
- pre_tool_use: { cursor: "preToolUse", claude: "PreToolUse", kiro: "pre_tool_use" },
138
- post_tool_use: { cursor: "postToolUse", claude: "PostToolUse", kiro: "post_tool_use" },
139
- post_tool_use_failure: { cursor: void 0, claude: "PostToolUseFailure", kiro: void 0 },
140
- stop: { cursor: "stop", claude: "Stop", kiro: "agent_stop" },
141
- subagent_start: { cursor: "subagentStart", claude: "SubagentStart", kiro: void 0 },
142
- subagent_stop: { cursor: "subagentStop", claude: "SubagentStop", kiro: void 0 },
143
- pre_compact: { cursor: "preCompact", claude: "PreCompact", kiro: void 0 },
144
- before_submit_prompt: { cursor: "beforeSubmitPrompt", claude: "UserPromptSubmit", kiro: "prompt_submit" },
145
- before_shell_execution: { cursor: "beforeShellExecution", claude: void 0, kiro: void 0 },
146
- after_shell_execution: { cursor: "afterShellExecution", claude: void 0, kiro: void 0 },
147
- before_mcp_execution: { cursor: "beforeMCPExecution", claude: void 0, kiro: void 0 },
148
- after_mcp_execution: { cursor: "afterMCPExecution", claude: void 0, kiro: void 0 },
149
- after_file_edit: { cursor: "afterFileEdit", claude: void 0, kiro: "file_save" },
150
- before_read_file: { cursor: "beforeReadFile", claude: void 0, kiro: void 0 },
151
- before_tab_file_read: { cursor: "beforeTabFileRead", claude: void 0, kiro: void 0 },
152
- after_tab_file_edit: { cursor: "afterTabFileEdit", claude: void 0, kiro: void 0 },
153
- after_agent_response: { cursor: "afterAgentResponse", claude: void 0, kiro: void 0 },
154
- after_agent_thought: { cursor: "afterAgentThought", claude: void 0, kiro: void 0 },
155
- notification: { cursor: void 0, claude: "Notification", kiro: void 0 },
156
- permission_request: { cursor: void 0, claude: "PermissionRequest", kiro: void 0 },
157
- task_completed: { cursor: void 0, claude: "TaskCompleted", kiro: void 0 },
158
- teammate_idle: { cursor: void 0, claude: "TeammateIdle", kiro: void 0 }
135
+ session_start: { cursor: "sessionStart", claude: "SessionStart", kiro: void 0, opencode: "session.created" },
136
+ session_end: { cursor: "sessionEnd", claude: "SessionEnd", kiro: void 0, opencode: "session.idle" },
137
+ pre_tool_use: { cursor: "preToolUse", claude: "PreToolUse", kiro: "pre_tool_use", opencode: "tool.execute.before" },
138
+ post_tool_use: { cursor: "postToolUse", claude: "PostToolUse", kiro: "post_tool_use", opencode: "tool.execute.after" },
139
+ post_tool_use_failure: { cursor: void 0, claude: "PostToolUseFailure", kiro: void 0, opencode: void 0 },
140
+ stop: { cursor: "stop", claude: "Stop", kiro: "agent_stop", opencode: "session.idle" },
141
+ subagent_start: { cursor: "subagentStart", claude: "SubagentStart", kiro: void 0, opencode: void 0 },
142
+ subagent_stop: { cursor: "subagentStop", claude: "SubagentStop", kiro: void 0, opencode: void 0 },
143
+ pre_compact: { cursor: "preCompact", claude: "PreCompact", kiro: void 0, opencode: "session.compacted" },
144
+ before_submit_prompt: { cursor: "beforeSubmitPrompt", claude: "UserPromptSubmit", kiro: "prompt_submit", opencode: void 0 },
145
+ before_shell_execution: { cursor: "beforeShellExecution", claude: void 0, kiro: void 0, opencode: "tool.execute.before" },
146
+ after_shell_execution: { cursor: "afterShellExecution", claude: void 0, kiro: void 0, opencode: "tool.execute.after" },
147
+ before_mcp_execution: { cursor: "beforeMCPExecution", claude: void 0, kiro: void 0, opencode: "tool.execute.before" },
148
+ after_mcp_execution: { cursor: "afterMCPExecution", claude: void 0, kiro: void 0, opencode: "tool.execute.after" },
149
+ after_file_edit: { cursor: "afterFileEdit", claude: void 0, kiro: "file_save", opencode: "file.edited" },
150
+ before_read_file: { cursor: "beforeReadFile", claude: void 0, kiro: void 0, opencode: void 0 },
151
+ before_tab_file_read: { cursor: "beforeTabFileRead", claude: void 0, kiro: void 0, opencode: void 0 },
152
+ after_tab_file_edit: { cursor: "afterTabFileEdit", claude: void 0, kiro: void 0, opencode: "file.edited" },
153
+ after_agent_response: { cursor: "afterAgentResponse", claude: void 0, kiro: void 0, opencode: void 0 },
154
+ after_agent_thought: { cursor: "afterAgentThought", claude: void 0, kiro: void 0, opencode: void 0 },
155
+ notification: { cursor: void 0, claude: "Notification", kiro: void 0, opencode: void 0 },
156
+ permission_request: { cursor: void 0, claude: "PermissionRequest", kiro: void 0, opencode: "permission.asked" },
157
+ task_completed: { cursor: void 0, claude: "TaskCompleted", kiro: void 0, opencode: "session.idle" },
158
+ teammate_idle: { cursor: void 0, claude: "TeammateIdle", kiro: void 0, opencode: void 0 }
159
159
  };
160
160
  function buildCursorHooks(hooks) {
161
161
  const cursorHooks = {};
@@ -197,8 +197,8 @@ function buildClaudeHooks(hooks) {
197
197
  if (Object.keys(claudeHooks).length === 0) return null;
198
198
  return claudeHooks;
199
199
  }
200
- async function generateCursorCommands(config, hubDir, cursorDir) {
201
- const commandsDir = join3(cursorDir, "commands");
200
+ async function generateEditorCommands(config, hubDir, targetDir, editorName) {
201
+ const commandsDir = join3(targetDir, "commands");
202
202
  let count = 0;
203
203
  if (config.commands_dir) {
204
204
  const srcDir = resolve(hubDir, config.commands_dir);
@@ -230,7 +230,7 @@ async function generateCursorCommands(config, hubDir, cursorDir) {
230
230
  }
231
231
  }
232
232
  if (count > 0) {
233
- console.log(chalk2.green(` Copied ${count} commands to .cursor/commands/`));
233
+ console.log(chalk2.green(` Copied ${count} commands to ${editorName}`));
234
234
  }
235
235
  }
236
236
  async function writeManagedFile(filePath, managedLines) {
@@ -326,7 +326,7 @@ async function generateCursor(config, hubDir) {
326
326
  console.log(chalk2.green(" Generated .cursor/hooks.json"));
327
327
  }
328
328
  }
329
- await generateCursorCommands(config, hubDir, cursorDir);
329
+ await generateEditorCommands(config, hubDir, cursorDir, ".cursor/commands/");
330
330
  await generateVSCodeSettings(config, hubDir);
331
331
  }
332
332
  function buildCursorMcpEntry(mcp) {
@@ -389,6 +389,325 @@ function buildKiroMcpEntry(mcp) {
389
389
  ...mcp.env && { env: mcp.env }
390
390
  };
391
391
  }
392
+ function buildOpenCodeMcpEntry(mcp) {
393
+ if (mcp.url) {
394
+ return { type: "remote", url: mcp.url };
395
+ }
396
+ if (mcp.image) {
397
+ const cmd = ["docker", "run", "-i", "--rm"];
398
+ if (mcp.env) {
399
+ for (const [key, value] of Object.entries(mcp.env)) {
400
+ cmd.push("-e", `${key}=${value}`);
401
+ }
402
+ }
403
+ cmd.push(mcp.image);
404
+ return { type: "local", command: cmd, ...mcp.env && { environment: mcp.env } };
405
+ }
406
+ return {
407
+ type: "local",
408
+ command: ["npx", "-y", mcp.package],
409
+ ...mcp.env && { environment: mcp.env }
410
+ };
411
+ }
412
+ function buildOpenCodeHooksPlugin(hooks) {
413
+ const handlers = [];
414
+ const seen = /* @__PURE__ */ new Set();
415
+ for (const [event, entries] of Object.entries(hooks)) {
416
+ const mapped = HOOK_EVENT_MAP[event]?.opencode;
417
+ if (!mapped || seen.has(mapped)) continue;
418
+ seen.add(mapped);
419
+ const commandEntries = entries.filter((e) => e.type === "command" && e.command);
420
+ if (commandEntries.length === 0) continue;
421
+ const cmds = commandEntries.map((e) => JSON.stringify(e.command));
422
+ handlers.push(` "${mapped}": async (input, output) => {
423
+ for (const cmd of [${cmds.join(", ")}]) {
424
+ try { await $\`\${cmd}\`; } catch (e) { console.error("Hook failed:", cmd, e); }
425
+ }
426
+ }`);
427
+ }
428
+ if (handlers.length === 0) return null;
429
+ return `// Auto-generated by hub \u2014 maps hub.yaml hooks to OpenCode plugin events
430
+ export const HubHooksPlugin = async ({ $ }) => {
431
+ return {
432
+ ${handlers.join(",\n")}
433
+ };
434
+ };
435
+ `;
436
+ }
437
+ function buildOpenCodeAgentMarkdown(name, content) {
438
+ const existingFrontmatter = content.match(/^---\n([\s\S]*?)\n---/);
439
+ let description = `Specialized agent for ${name} tasks`;
440
+ if (existingFrontmatter) {
441
+ const descMatch = existingFrontmatter[1].match(/^description:\s*["']?(.+?)["']?\s*$/m);
442
+ if (descMatch) description = descMatch[1];
443
+ }
444
+ const body = existingFrontmatter ? content.replace(/^---\n[\s\S]*?\n---\n*/, "") : content;
445
+ return `---
446
+ description: "${description}"
447
+ mode: subagent
448
+ tools:
449
+ write: true
450
+ edit: true
451
+ bash: true
452
+ ---
453
+
454
+ ${body.trim()}
455
+ `;
456
+ }
457
+ function buildOpenCodeOrchestratorRule(config) {
458
+ const taskFolder = config.workflow?.task_folder || "./tasks/<TASK_ID>/";
459
+ const steps = config.workflow?.pipeline || [];
460
+ const prompt = config.workflow?.prompt;
461
+ const enforce = config.workflow?.enforce_workflow ?? false;
462
+ const sections = [];
463
+ sections.push(`# Orchestrator
464
+
465
+ ## Your Main Responsibility
466
+
467
+ 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. Use \`@agent-name\` to invoke sub-agents for each phase of the pipeline.`);
468
+ if (enforce) {
469
+ sections.push(`
470
+ ## STRICT WORKFLOW ENFORCEMENT
471
+
472
+ **YOU MUST FOLLOW THE PIPELINE DEFINED BELOW. NO EXCEPTIONS.**
473
+
474
+ - NEVER skip a pipeline step, even if the task seems simple or obvious.
475
+ - ALWAYS execute steps in the exact order defined. Do not reorder, merge, or parallelize steps unless the pipeline explicitly allows it.
476
+ - ALWAYS call the designated sub-agent for each step. Do not attempt to perform a step yourself if an agent is assigned to it.
477
+ - ALWAYS wait for a step to complete and validate its output before moving to the next step.
478
+ - If a step produces a document, READ the document and confirm it is complete before proceeding.
479
+ - If a step has unanswered questions or validation issues, RESOLVE them before advancing.
480
+ - NEVER jump directly to coding without completing refinement first.
481
+ - NEVER skip review or QA steps, even for small changes.
482
+ - If the user asks you to skip a step, explain why the pipeline exists and ask for explicit confirmation before proceeding.`);
483
+ }
484
+ if (prompt?.prepend) {
485
+ sections.push(`
486
+ ${prompt.prepend.trim()}`);
487
+ }
488
+ if (config.integrations?.linear) {
489
+ const linear = config.integrations.linear;
490
+ sections.push(`
491
+ ## Task Management
492
+
493
+ 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.`);
494
+ }
495
+ sections.push(`
496
+ ## Repositories
497
+ `);
498
+ for (const repo of config.repos) {
499
+ const parts = [`- **${repo.path}**`];
500
+ if (repo.description) parts.push(`\u2014 ${repo.description}`);
501
+ else if (repo.tech) parts.push(`\u2014 ${repo.tech}`);
502
+ if (repo.skills?.length) parts.push(`(skills: ${repo.skills.join(", ")})`);
503
+ sections.push(parts.join(" "));
504
+ if (repo.commands) {
505
+ const cmds = Object.entries(repo.commands).filter(([, v]) => v).map(([k, v]) => `\`${k}\`: \`${v}\``).join(", ");
506
+ if (cmds) sections.push(` Commands: ${cmds}`);
507
+ }
508
+ }
509
+ if (prompt?.sections?.after_repositories) {
510
+ sections.push(`
511
+ ${prompt.sections.after_repositories.trim()}`);
512
+ }
513
+ const docStructure = buildDocumentStructure(steps, taskFolder);
514
+ sections.push(docStructure);
515
+ const pipelineSection = buildOpenCodePipelineSection(steps);
516
+ sections.push(pipelineSection);
517
+ if (prompt?.sections?.after_pipeline) {
518
+ sections.push(`
519
+ ${prompt.sections.after_pipeline.trim()}`);
520
+ }
521
+ if (config.integrations?.slack || config.integrations?.github) {
522
+ sections.push(buildDeliverySection(config));
523
+ }
524
+ if (prompt?.sections?.after_delivery) {
525
+ sections.push(`
526
+ ${prompt.sections.after_delivery.trim()}`);
527
+ }
528
+ if (config.memory) {
529
+ sections.push(`
530
+ ## Team Memory
531
+
532
+ This workspace has a team memory knowledge base available via the \`team-memory\` MCP.
533
+
534
+ **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.
535
+
536
+ **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.
537
+
538
+ Available tools: \`search_memories\`, \`get_memory\`, \`add_memory\`, \`list_memories\`, \`archive_memory\`, \`remove_memory\`.`);
539
+ }
540
+ sections.push(`
541
+ ## Troubleshooting and Debugging
542
+
543
+ For bug reports or unexpected behavior, use the \`@debugger\` agent directly.
544
+ It will:
545
+ 1. Collect context (symptoms, environment, timeline)
546
+ 2. Analyze logs and stack traces
547
+ 3. Form and test hypotheses systematically
548
+ 4. Identify the root cause
549
+ 5. Propose a solution or call coding agents to implement the fix`);
550
+ if (prompt?.sections) {
551
+ const reservedKeys = /* @__PURE__ */ new Set(["after_repositories", "after_pipeline", "after_delivery"]);
552
+ for (const [name, content] of Object.entries(prompt.sections)) {
553
+ if (reservedKeys.has(name)) continue;
554
+ const title = name.split(/[-_]/).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
555
+ sections.push(`
556
+ ## ${title}
557
+
558
+ ${content.trim()}`);
559
+ }
560
+ }
561
+ if (prompt?.append) {
562
+ sections.push(`
563
+ ${prompt.append.trim()}`);
564
+ }
565
+ return sections.join("\n");
566
+ }
567
+ function buildOpenCodePipelineSection(steps) {
568
+ if (steps.length === 0) {
569
+ return `
570
+ ## Development Pipeline
571
+
572
+ 1. Use \`@refinement\` to collect requirements
573
+ 2. Use \`@coding-backend\` and/or \`@coding-frontend\` agents to implement
574
+ 3. Use \`@code-reviewer\` to review the implementation
575
+ 4. Use \`@qa-backend\` and/or \`@qa-frontend\` to test
576
+ 5. Create PRs and notify the team`;
577
+ }
578
+ const parts = [`
579
+ ## Development Pipeline
580
+ `];
581
+ for (const step of steps) {
582
+ if (step.actions) {
583
+ parts.push(`### Delivery`);
584
+ parts.push(`After all validations pass, execute these actions:`);
585
+ for (const action of step.actions) {
586
+ parts.push(`- ${formatAction(action)}`);
587
+ }
588
+ continue;
589
+ }
590
+ const stepTitle = step.step.charAt(0).toUpperCase() + step.step.slice(1);
591
+ parts.push(`### ${stepTitle}`);
592
+ if (step.mode === "plan") {
593
+ parts.push(`**This step is a planning phase.** Switch to the Plan agent (Tab key) for collaborative planning with the user before any implementation begins.`);
594
+ parts.push(``);
595
+ }
596
+ if (step.agent) {
597
+ parts.push(`Call \`@${step.agent}\`.${step.output ? ` It writes to \`${step.output}\`.` : ""}`);
598
+ if (step.step === "refinement") {
599
+ parts.push(`
600
+ After it runs, read the document and validate with the user:
601
+ - If there are unanswered questions, ask the user one at a time
602
+ - If the user requests adjustments, send back to the refinement agent
603
+ - Do not proceed until the document is complete and approved by the user`);
604
+ }
605
+ }
606
+ if (Array.isArray(step.agents)) {
607
+ const agentList = step.agents.map((a) => {
608
+ if (typeof a === "string") return { agent: a };
609
+ return a;
610
+ });
611
+ if (step.parallel) {
612
+ parts.push(`Call these agents in parallel:`);
613
+ } else {
614
+ parts.push(`Call these agents in sequence:`);
615
+ }
616
+ for (const a of agentList) {
617
+ let line = `- \`@${a.agent}\``;
618
+ if (a.output) line += ` \u2192 writes to \`${a.output}\``;
619
+ if (a.when) line += ` (when: ${a.when})`;
620
+ parts.push(line);
621
+ }
622
+ if (step.step === "coding" || step.step === "code" || step.step === "implementation") {
623
+ parts.push(`
624
+ 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.`);
625
+ }
626
+ if (step.step === "validation" || step.step === "review" || step.step === "qa") {
627
+ parts.push(`
628
+ If any validation agent leaves comments requiring fixes, call the relevant coding agents again to address them.`);
629
+ }
630
+ }
631
+ if (step.mode === "plan") {
632
+ parts.push(`
633
+ **After this step is complete and approved**, switch back to Build agent to proceed with the next step.`);
634
+ }
635
+ parts.push("");
636
+ }
637
+ return parts.join("\n");
638
+ }
639
+ async function generateOpenCode(config, hubDir) {
640
+ const opencodeDir = join3(hubDir, ".opencode");
641
+ await mkdir2(join3(opencodeDir, "agents"), { recursive: true });
642
+ await mkdir2(join3(opencodeDir, "rules"), { recursive: true });
643
+ await mkdir2(join3(opencodeDir, "skills"), { recursive: true });
644
+ await mkdir2(join3(opencodeDir, "commands"), { recursive: true });
645
+ await mkdir2(join3(opencodeDir, "plugins"), { recursive: true });
646
+ const gitignoreLines = buildGitignoreLines(config);
647
+ await writeManagedFile(join3(hubDir, ".gitignore"), gitignoreLines);
648
+ console.log(chalk2.green(" Generated .gitignore"));
649
+ const orchestratorRule = buildOpenCodeOrchestratorRule(config);
650
+ await writeFile2(join3(opencodeDir, "rules", "orchestrator.md"), orchestratorRule + "\n", "utf-8");
651
+ console.log(chalk2.green(" Generated .opencode/rules/orchestrator.md"));
652
+ const opencodeConfig = {
653
+ $schema: "https://opencode.ai/config.json"
654
+ };
655
+ if (config.mcps?.length) {
656
+ const mcpConfig = {};
657
+ for (const mcp of config.mcps) {
658
+ mcpConfig[mcp.name] = buildOpenCodeMcpEntry(mcp);
659
+ }
660
+ opencodeConfig.mcp = mcpConfig;
661
+ }
662
+ opencodeConfig.instructions = [".opencode/rules/*.md"];
663
+ await writeFile2(
664
+ join3(hubDir, "opencode.json"),
665
+ JSON.stringify(opencodeConfig, null, 2) + "\n",
666
+ "utf-8"
667
+ );
668
+ console.log(chalk2.green(" Generated opencode.json"));
669
+ const agentsDir = resolve(hubDir, "agents");
670
+ try {
671
+ const agentFiles = await readdir2(agentsDir);
672
+ const mdFiles = agentFiles.filter((f) => f.endsWith(".md"));
673
+ for (const file of mdFiles) {
674
+ const content = await readFile3(join3(agentsDir, file), "utf-8");
675
+ const agentName = file.replace(/\.md$/, "");
676
+ const converted = buildOpenCodeAgentMarkdown(agentName, content);
677
+ await writeFile2(join3(opencodeDir, "agents", file), converted, "utf-8");
678
+ }
679
+ console.log(chalk2.green(` Copied ${mdFiles.length} agents to .opencode/agents/`));
680
+ } catch {
681
+ console.log(chalk2.yellow(" No agents/ directory found, skipping agent copy"));
682
+ }
683
+ const skillsDir = resolve(hubDir, "skills");
684
+ try {
685
+ const skillFolders = await readdir2(skillsDir);
686
+ let count = 0;
687
+ for (const folder of skillFolders) {
688
+ const skillFile = join3(skillsDir, folder, "SKILL.md");
689
+ try {
690
+ await readFile3(skillFile);
691
+ await cp(join3(skillsDir, folder), join3(opencodeDir, "skills", folder), { recursive: true });
692
+ count++;
693
+ } catch {
694
+ }
695
+ }
696
+ if (count > 0) {
697
+ console.log(chalk2.green(` Copied ${count} skills to .opencode/skills/`));
698
+ }
699
+ } catch {
700
+ }
701
+ await generateEditorCommands(config, hubDir, opencodeDir, ".opencode/commands/");
702
+ if (config.hooks) {
703
+ const plugin = buildOpenCodeHooksPlugin(config.hooks);
704
+ if (plugin) {
705
+ await writeFile2(join3(opencodeDir, "plugins", "hub-hooks.js"), plugin, "utf-8");
706
+ console.log(chalk2.green(" Generated .opencode/plugins/hub-hooks.js"));
707
+ }
708
+ }
709
+ await generateVSCodeSettings(config, hubDir);
710
+ }
392
711
  function buildKiroSteeringContent(content, inclusion = "always", meta) {
393
712
  const frontMatter = ["---", `inclusion: ${inclusion}`];
394
713
  if (meta?.name) frontMatter.push(`name: ${meta.name}`);
@@ -1092,7 +1411,8 @@ function buildGitignoreLines(config) {
1092
1411
  var generators = {
1093
1412
  cursor: { name: "Cursor", generate: generateCursor },
1094
1413
  "claude-code": { name: "Claude Code", generate: generateClaudeCode },
1095
- kiro: { name: "Kiro", generate: generateKiro }
1414
+ kiro: { name: "Kiro", generate: generateKiro },
1415
+ opencode: { name: "OpenCode", generate: generateOpenCode }
1096
1416
  };
1097
1417
  async function resolveEditor(opts) {
1098
1418
  const hubDir = process.cwd();
@@ -1126,7 +1446,7 @@ async function resolveEditor(opts) {
1126
1446
  ]);
1127
1447
  return editor;
1128
1448
  }
1129
- var generateCommand = new Command("generate").description("Generate editor-specific configuration files from hub.yaml").option("-e, --editor <editor>", "Target editor (cursor, claude-code, kiro)").option("--reset-editor", "Reset saved editor preference and choose again").action(async (opts) => {
1449
+ var generateCommand = new Command("generate").description("Generate editor-specific configuration files from hub.yaml").option("-e, --editor <editor>", "Target editor (cursor, claude-code, kiro, opencode)").option("--reset-editor", "Reset saved editor preference and choose again").action(async (opts) => {
1130
1450
  const hubDir = process.cwd();
1131
1451
  const config = await loadHubConfig(hubDir);
1132
1452
  if (config.memory) {
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  generateCommand,
3
3
  generators
4
- } from "./chunk-BLVKDXNY.js";
4
+ } from "./chunk-U5G47GMH.js";
5
5
  export {
6
6
  generateCommand,
7
7
  generators
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  checkAndAutoRegenerate,
4
4
  generateCommand,
5
5
  loadHubConfig
6
- } from "./chunk-BLVKDXNY.js";
6
+ } from "./chunk-U5G47GMH.js";
7
7
 
8
8
  // src/index.ts
9
9
  import { Command as Command18 } from "commander";
@@ -145,8 +145,7 @@ var addRepoCommand = new Command2("add-repo").description("Add a repository to t
145
145
  url,
146
146
  ...opts.tech && { tech: opts.tech }
147
147
  });
148
- const header = content.startsWith("# yaml-language-server") ? "" : SCHEMA_COMMENT2;
149
- await writeFile2(configPath, header + stringify2(config), "utf-8");
148
+ await writeFile2(configPath, SCHEMA_COMMENT2 + stringify2(config), "utf-8");
150
149
  const gitignorePath = join2(hubDir, ".gitignore");
151
150
  await appendFile(gitignorePath, `${repoName}
152
151
  `);
@@ -1230,7 +1229,7 @@ Installing skill ${source} from registry
1230
1229
  })
1231
1230
  ).addCommand(
1232
1231
  new Command7("find").description("Browse curated skills in the Repo Hub directory").argument("[query]", "Search term").action(async (query) => {
1233
- const base = "https://rhm-website.vercel.app/directory?type=skill";
1232
+ const base = "https://hub.arvore.com.br/directory?type=skill";
1234
1233
  const url = query ? `${base}&q=${encodeURIComponent(query)}` : base;
1235
1234
  console.log(chalk7.blue("\n Browse curated skills at:\n"));
1236
1235
  console.log(chalk7.cyan(` ${url}
@@ -1480,7 +1479,7 @@ Removed agent: ${name}
1480
1479
  })
1481
1480
  ).addCommand(
1482
1481
  new Command8("find").description("Browse curated agents in the Repo Hub directory").argument("[query]", "Search term").action(async (query) => {
1483
- const base = "https://rhm-website.vercel.app/directory?type=agent";
1482
+ const base = "https://hub.arvore.com.br/directory?type=agent";
1484
1483
  const url = query ? `${base}&q=${encodeURIComponent(query)}` : base;
1485
1484
  console.log(chalk8.blue("\n Browse curated agents at:\n"));
1486
1485
  console.log(chalk8.cyan(` ${url}
@@ -1700,7 +1699,7 @@ Installing hooks from ${source}
1700
1699
  })
1701
1700
  ).addCommand(
1702
1701
  new Command9("find").description("Browse curated hooks in the Repo Hub directory").argument("[query]", "Search term").action(async (query) => {
1703
- const base = "https://rhm-website.vercel.app/directory?type=hook";
1702
+ const base = "https://hub.arvore.com.br/directory?type=hook";
1704
1703
  const url = query ? `${base}&q=${encodeURIComponent(query)}` : base;
1705
1704
  console.log(chalk9.blue("\n Browse curated hooks at:\n"));
1706
1705
  console.log(chalk9.cyan(` ${url}
@@ -1897,7 +1896,7 @@ Installing commands from ${source}
1897
1896
  })
1898
1897
  ).addCommand(
1899
1898
  new Command10("find").description("Browse curated commands in the Repo Hub directory").argument("[query]", "Search term").action(async (query) => {
1900
- const base = "https://rhm-website.vercel.app/directory?type=command";
1899
+ const base = "https://hub.arvore.com.br/directory?type=command";
1901
1900
  const url = query ? `${base}&q=${encodeURIComponent(query)}` : base;
1902
1901
  console.log(chalk10.blue("\n Browse curated commands at:\n"));
1903
1902
  console.log(chalk10.cyan(` ${url}
@@ -2836,7 +2835,7 @@ var updateCommand = new Command16("update").description("Update hub CLI to the l
2836
2835
  // src/commands/directory.ts
2837
2836
  import { Command as Command17 } from "commander";
2838
2837
  import chalk17 from "chalk";
2839
- var BASE_URL = "https://rhm-website.vercel.app/directory";
2838
+ var BASE_URL = "https://hub.arvore.com.br/directory";
2840
2839
  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) => {
2841
2840
  const params = new URLSearchParams();
2842
2841
  if (opts?.type) params.set("type", opts.type);
@@ -2857,7 +2856,7 @@ var directoryCommand = new Command17("directory").alias("dir").description("Brow
2857
2856
  var program = new Command18();
2858
2857
  program.name("hub").description(
2859
2858
  "Give your AI coding assistant the full picture. Multi-repo context, agent orchestration, and end-to-end workflows."
2860
- ).version("0.6.1").enablePositionalOptions();
2859
+ ).version("0.6.2").enablePositionalOptions();
2861
2860
  program.addCommand(initCommand);
2862
2861
  program.addCommand(addRepoCommand);
2863
2862
  program.addCommand(setupCommand);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arvoretech/hub",
3
- "version": "0.6.1",
3
+ "version": "0.6.3",
4
4
  "description": "CLI for managing AI-aware multi-repository workspaces",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",