@arvoretech/hub 0.6.2 → 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";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arvoretech/hub",
3
- "version": "0.6.2",
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",