@arvoretech/hub 0.18.1 → 0.20.0

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.
@@ -117,7 +117,7 @@ async function checkAndAutoRegenerate(hubDir) {
117
117
  return;
118
118
  }
119
119
  console.log(chalk.yellow("\n Detected outdated configs, auto-regenerating..."));
120
- const { generators: generators2 } = await import("./generate-HJ5FRZSI.js");
120
+ const { generators: generators2 } = await import("./generate-J6FNJF7F.js");
121
121
  const generator = generators2[result.editor];
122
122
  if (!generator) {
123
123
  console.log(chalk.red(` Unknown editor '${result.editor}' in cache. Run 'hub generate' manually.`));
@@ -446,7 +446,11 @@ var STEP_INFO = {
446
446
  role: { title: "What's your role?", subtitle: "e.g. CEO, Product Manager, Designer, Backend Dev, QA Engineer..." },
447
447
  technical_level: { title: "How technical are you?", subtitle: "This changes how the AI explains things to you." },
448
448
  context: { title: "Anything else the AI should know about you?", subtitle: `e.g. "I focus on business metrics", "I only work on the mobile app", "I review PRs but don't code"` },
449
- language: { title: "What language should the AI use?", subtitle: "e.g. English, Portugu\xEAs, Espa\xF1ol..." }
449
+ language: { title: "What language should the AI use?", subtitle: "e.g. English, Portugu\xEAs, Espa\xF1ol..." },
450
+ github_username: { title: "What's your GitHub username?", subtitle: "Used for branch naming and PR assignments. (optional \u2014 press Enter to skip)" },
451
+ aws_profiles: { title: "What AWS profiles do you use?", subtitle: 'Format: profile-name:description (one per line). e.g. "my-company-prd:Production account". Press Enter to skip.' },
452
+ focus_areas: { title: "What areas do you focus on?", subtitle: 'e.g. "infrastructure and costs", "frontend UX", "backend APIs", "mobile app". (optional)' },
453
+ timezone: { title: "What's your timezone?", subtitle: "e.g. America/Sao_Paulo, US/Eastern, Europe/London. (optional)" }
450
454
  };
451
455
  function PersonaApp({ existing, onComplete }) {
452
456
  const { stdout } = useStdout();
@@ -459,7 +463,12 @@ function PersonaApp({ existing, onComplete }) {
459
463
  role: existing?.role || "",
460
464
  context: existing?.context || "",
461
465
  technical_level: existing?.technical_level || "intermediate",
462
- language: existing?.language || "English"
466
+ language: existing?.language || "English",
467
+ aws_profiles: existing?.aws_profiles || [],
468
+ github_username: existing?.github_username || "",
469
+ slack_display_name: existing?.slack_display_name || "",
470
+ focus_areas: existing?.focus_areas || "",
471
+ timezone: existing?.timezone || ""
463
472
  });
464
473
  const [inputValue, setInputValue] = useState(existing?.name || "");
465
474
  const [levelCursor, setLevelCursor] = useState(
@@ -487,7 +496,13 @@ function PersonaApp({ existing, onComplete }) {
487
496
  }
488
497
  if (step === "review") {
489
498
  if (key.return || input === "y") {
490
- onComplete(data);
499
+ const cleanedData = { ...data };
500
+ if (!cleanedData.github_username) delete cleanedData.github_username;
501
+ if (!cleanedData.slack_display_name) delete cleanedData.slack_display_name;
502
+ if (!cleanedData.focus_areas) delete cleanedData.focus_areas;
503
+ if (!cleanedData.timezone) delete cleanedData.timezone;
504
+ if (!cleanedData.aws_profiles?.length) delete cleanedData.aws_profiles;
505
+ onComplete(cleanedData);
491
506
  goTo("done");
492
507
  }
493
508
  if (input === "b" || key.leftArrow) {
@@ -580,19 +595,91 @@ function PersonaApp({ existing, onComplete }) {
580
595
  value: inputValue,
581
596
  onChange: setInputValue,
582
597
  onSubmit: (v) => {
583
- handleTextSubmit(v || "English", "language", "review");
598
+ handleTextSubmit(v || "English", "language", "github_username");
584
599
  },
585
600
  placeholder: "English"
586
601
  }
587
602
  )
588
603
  ] }),
604
+ step === "github_username" && /* @__PURE__ */ jsxs(Box, { children: [
605
+ /* @__PURE__ */ jsx(Text, { color: colors.brand, bold: true, children: "\u276F " }),
606
+ /* @__PURE__ */ jsx(
607
+ TextInput,
608
+ {
609
+ value: inputValue,
610
+ onChange: setInputValue,
611
+ onSubmit: (v) => {
612
+ setData((prev) => ({ ...prev, github_username: v.trim() }));
613
+ setInputValue(data.aws_profiles?.map((p) => `${p.name}:${p.description}`).join(", ") || "");
614
+ goTo("aws_profiles");
615
+ },
616
+ placeholder: "(optional \u2014 press Enter to skip)"
617
+ }
618
+ )
619
+ ] }),
620
+ step === "aws_profiles" && /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: /* @__PURE__ */ jsxs(Box, { children: [
621
+ /* @__PURE__ */ jsx(Text, { color: colors.brand, bold: true, children: "\u276F " }),
622
+ /* @__PURE__ */ jsx(
623
+ TextInput,
624
+ {
625
+ value: inputValue,
626
+ onChange: setInputValue,
627
+ onSubmit: (v) => {
628
+ const profiles = v.trim() ? v.split(",").map((p) => {
629
+ const [name, ...descParts] = p.trim().split(":");
630
+ return { name: name.trim(), description: descParts.join(":").trim() || name.trim() };
631
+ }).filter((p) => p.name) : [];
632
+ setData((prev) => ({ ...prev, aws_profiles: profiles }));
633
+ setInputValue(data.focus_areas || "");
634
+ goTo("focus_areas");
635
+ },
636
+ placeholder: "my-prd:Production, my-stg:Staging (optional)"
637
+ }
638
+ )
639
+ ] }) }),
640
+ step === "focus_areas" && /* @__PURE__ */ jsxs(Box, { children: [
641
+ /* @__PURE__ */ jsx(Text, { color: colors.brand, bold: true, children: "\u276F " }),
642
+ /* @__PURE__ */ jsx(
643
+ TextInput,
644
+ {
645
+ value: inputValue,
646
+ onChange: setInputValue,
647
+ onSubmit: (v) => {
648
+ setData((prev) => ({ ...prev, focus_areas: v.trim() }));
649
+ setInputValue(data.timezone || "");
650
+ goTo("timezone");
651
+ },
652
+ placeholder: "(optional \u2014 press Enter to skip)"
653
+ }
654
+ )
655
+ ] }),
656
+ step === "timezone" && /* @__PURE__ */ jsxs(Box, { children: [
657
+ /* @__PURE__ */ jsx(Text, { color: colors.brand, bold: true, children: "\u276F " }),
658
+ /* @__PURE__ */ jsx(
659
+ TextInput,
660
+ {
661
+ value: inputValue,
662
+ onChange: setInputValue,
663
+ onSubmit: (v) => {
664
+ setData((prev) => ({ ...prev, timezone: v.trim() }));
665
+ setInputValue("");
666
+ goTo("review");
667
+ },
668
+ placeholder: "America/Sao_Paulo (optional)"
669
+ }
670
+ )
671
+ ] }),
589
672
  step === "review" && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
590
673
  /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingLeft: 1, borderStyle: "round", borderColor: colors.dim, paddingRight: 1, children: [
591
674
  /* @__PURE__ */ jsx(ReviewRow, { label: "Name", value: data.name }),
592
675
  /* @__PURE__ */ jsx(ReviewRow, { label: "Role", value: data.role }),
593
676
  /* @__PURE__ */ jsx(ReviewRow, { label: "Level", value: TECHNICAL_LEVELS.find((l) => l.value === data.technical_level)?.label || data.technical_level }),
594
677
  data.context && /* @__PURE__ */ jsx(ReviewRow, { label: "Context", value: data.context }),
595
- /* @__PURE__ */ jsx(ReviewRow, { label: "Language", value: data.language })
678
+ /* @__PURE__ */ jsx(ReviewRow, { label: "Language", value: data.language }),
679
+ data.github_username && /* @__PURE__ */ jsx(ReviewRow, { label: "GitHub", value: data.github_username }),
680
+ data.aws_profiles && data.aws_profiles.length > 0 && /* @__PURE__ */ jsx(ReviewRow, { label: "AWS", value: data.aws_profiles.map((p) => `${p.name} (${p.description})`).join(", ") }),
681
+ data.focus_areas && /* @__PURE__ */ jsx(ReviewRow, { label: "Focus", value: data.focus_areas }),
682
+ data.timezone && /* @__PURE__ */ jsx(ReviewRow, { label: "Timezone", value: data.timezone })
596
683
  ] }),
597
684
  /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsxs(Text, { color: colors.dim, children: [
598
685
  /* @__PURE__ */ jsx(Text, { color: colors.brand, children: "enter" }),
@@ -684,6 +771,28 @@ ${persona.name} is an experienced developer. Communicate directly:
684
771
  - Be concise and technical. Skip basic explanations.
685
772
  - Focus on trade-offs, edge cases, and non-obvious implications.
686
773
  - Show code directly without hand-holding.`);
774
+ }
775
+ if (persona.focus_areas) {
776
+ lines.push(`
777
+ ${persona.name} focuses on: ${persona.focus_areas}. Prioritize these areas in suggestions and discussions.`);
778
+ }
779
+ if (persona.aws_profiles?.length) {
780
+ lines.push(`
781
+ ### AWS Profiles
782
+ `);
783
+ for (const profile of persona.aws_profiles) {
784
+ lines.push(`- \`${profile.name}\`: ${profile.description}`);
785
+ }
786
+ lines.push(`
787
+ When running AWS commands, ask which environment if not clear from context.`);
788
+ }
789
+ if (persona.github_username) {
790
+ lines.push(`
791
+ GitHub username: **${persona.github_username}**`);
792
+ }
793
+ if (persona.timezone) {
794
+ lines.push(`
795
+ Timezone: ${persona.timezone}`);
687
796
  }
688
797
  if (persona.context) {
689
798
  lines.push(`
@@ -695,6 +804,32 @@ Always communicate with ${persona.name} in **${persona.language}**.`);
695
804
  }
696
805
  return lines.join("\n");
697
806
  }
807
+ function buildPersonaEditorFile(persona, editor) {
808
+ const content = buildPersonaSection(persona);
809
+ if (editor === "kiro") {
810
+ return `---
811
+ inclusion: always
812
+ name: persona
813
+ ---
814
+
815
+ # Persona \u2014 ${persona.name}
816
+ ${content}
817
+ `;
818
+ }
819
+ if (editor === "cursor") {
820
+ return `---
821
+ description: "Personal AI profile for ${persona.name}"
822
+ alwaysApply: true
823
+ ---
824
+
825
+ # Persona \u2014 ${persona.name}
826
+ ${content}
827
+ `;
828
+ }
829
+ return `# Persona \u2014 ${persona.name}
830
+ ${content}
831
+ `;
832
+ }
698
833
  var personaCommand = new Command("persona").description("Set up your personal AI profile \u2014 adapts how the agent communicates with you").action(async () => {
699
834
  const hubDir = process.cwd();
700
835
  const hubPath = join3(hubDir, ".hub");
@@ -1019,12 +1154,13 @@ async function generateCursor(config, hubDir) {
1019
1154
  const cleanedOrchestratorForAgents = orchestratorRule.replace(/^---[\s\S]*?---\n/m, "").trim();
1020
1155
  const skillsSectionCursor = await buildSkillsSection(hubDir, config);
1021
1156
  const personaCursor = await loadPersona(hubDir);
1022
- const personaSectionCursor = personaCursor ? buildPersonaSection(personaCursor) : "";
1023
- const agentsMdCursor = [cleanedOrchestratorForAgents, skillsSectionCursor, personaSectionCursor].filter(Boolean).join("\n");
1157
+ const agentsMdCursor = [cleanedOrchestratorForAgents, skillsSectionCursor].filter(Boolean).join("\n");
1024
1158
  await writeFile4(join4(hubDir, "AGENTS.md"), agentsMdCursor + "\n", "utf-8");
1025
1159
  console.log(chalk3.green(" Generated AGENTS.md"));
1026
1160
  if (personaCursor) {
1027
- console.log(chalk3.green(` Applied persona: ${personaCursor.name} (${personaCursor.role})`));
1161
+ const personaRuleContent = buildPersonaEditorFile(personaCursor, "cursor");
1162
+ await writeFile4(join4(cursorDir, "rules", "persona.mdc"), personaRuleContent, "utf-8");
1163
+ console.log(chalk3.green(` Generated .cursor/rules/persona.mdc (${personaCursor.name}, ${personaCursor.role})`));
1028
1164
  }
1029
1165
  const hubSteeringDirCursor = resolve2(hubDir, "steering");
1030
1166
  try {
@@ -1918,12 +2054,13 @@ async function generateOpenCode(config, hubDir) {
1918
2054
  });
1919
2055
  const skillsSectionOC = await buildSkillsSection(hubDir, config);
1920
2056
  const personaOC = await loadPersona(hubDir);
1921
- const personaSectionOC = personaOC ? buildPersonaSection(personaOC) : "";
1922
- const agentsMdOC = [orchestratorContent, skillsSectionOC, personaSectionOC].filter(Boolean).join("\n");
2057
+ const agentsMdOC = [orchestratorContent, skillsSectionOC].filter(Boolean).join("\n");
1923
2058
  await writeFile4(join4(hubDir, "AGENTS.md"), agentsMdOC + "\n", "utf-8");
1924
2059
  console.log(chalk3.green(" Generated AGENTS.md"));
1925
2060
  if (personaOC) {
1926
- console.log(chalk3.green(` Applied persona: ${personaOC.name} (${personaOC.role})`));
2061
+ const personaRuleContent = buildPersonaEditorFile(personaOC, "opencode");
2062
+ await writeFile4(join4(opencodeDir, "rules", "persona.md"), personaRuleContent, "utf-8");
2063
+ console.log(chalk3.green(` Generated .opencode/rules/persona.md (${personaOC.name}, ${personaOC.role})`));
1927
2064
  }
1928
2065
  const hubSteeringDirOC = resolve2(hubDir, "steering");
1929
2066
  try {
@@ -2497,8 +2634,7 @@ async function generateClaudeCode(config, hubDir) {
2497
2634
  const cleanedOrchestrator = orchestratorRule.replace(/^---[\s\S]*?---\n/m, "").trim();
2498
2635
  const skillsSectionClaude = await buildSkillsSection(hubDir, config);
2499
2636
  const personaClaude = await loadPersona(hubDir);
2500
- const personaSectionClaude = personaClaude ? buildPersonaSection(personaClaude) : "";
2501
- const agentsMdClaude = [cleanedOrchestrator, skillsSectionClaude, personaSectionClaude].filter(Boolean).join("\n");
2637
+ const agentsMdClaude = [cleanedOrchestrator, skillsSectionClaude].filter(Boolean).join("\n");
2502
2638
  await writeFile4(join4(hubDir, "AGENTS.md"), agentsMdClaude + "\n", "utf-8");
2503
2639
  console.log(chalk3.green(" Generated AGENTS.md"));
2504
2640
  if (personaClaude) {
@@ -2561,6 +2697,10 @@ async function generateClaudeCode(config, hubDir) {
2561
2697
  }
2562
2698
  } catch {
2563
2699
  }
2700
+ if (personaClaude) {
2701
+ claudeMdSections.push(buildPersonaEditorFile(personaClaude, "claude-code"));
2702
+ console.log(chalk3.green(` Generated persona section in CLAUDE.md (${personaClaude.name}, ${personaClaude.role})`));
2703
+ }
2564
2704
  await writeFile4(join4(hubDir, "CLAUDE.md"), claudeMdSections.join("\n\n"), "utf-8");
2565
2705
  console.log(chalk3.green(" Generated CLAUDE.md"));
2566
2706
  if (config.mcps?.length) {
@@ -2658,12 +2798,13 @@ async function generateKiro(config, hubDir) {
2658
2798
  const kiroRule = buildKiroOrchestratorRule(config);
2659
2799
  const skillsSection = await buildSkillsSection(hubDir, config);
2660
2800
  const personaKiro = await loadPersona(hubDir);
2661
- const personaSectionKiro = personaKiro ? buildPersonaSection(personaKiro) : "";
2662
- const kiroRuleWithSkills = [kiroRule, skillsSection, personaSectionKiro].filter(Boolean).join("\n");
2801
+ const kiroRuleWithSkills = [kiroRule, skillsSection].filter(Boolean).join("\n");
2663
2802
  await writeFile4(join4(hubDir, "AGENTS.md"), kiroRuleWithSkills + "\n", "utf-8");
2664
2803
  console.log(chalk3.green(" Generated AGENTS.md"));
2665
2804
  if (personaKiro) {
2666
- console.log(chalk3.green(` Applied persona: ${personaKiro.name} (${personaKiro.role})`));
2805
+ const personaSteeringContent = buildPersonaEditorFile(personaKiro, "kiro");
2806
+ await writeFile4(join4(steeringDir, "persona.md"), personaSteeringContent, "utf-8");
2807
+ console.log(chalk3.green(` Generated .kiro/steering/persona.md (${personaKiro.name}, ${personaKiro.role})`));
2667
2808
  }
2668
2809
  await rm(join4(steeringDir, "orchestrator.md")).catch(() => {
2669
2810
  });
@@ -2963,6 +3104,13 @@ function buildGitignoreLines(config) {
2963
3104
  ".agent-teams/"
2964
3105
  );
2965
3106
  }
3107
+ lines.push(
3108
+ "",
3109
+ "# Persona (personal, not shared)",
3110
+ ".kiro/steering/persona.md",
3111
+ ".cursor/rules/persona.mdc",
3112
+ ".opencode/rules/persona.md"
3113
+ );
2966
3114
  return lines;
2967
3115
  }
2968
3116
  var generators = {
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  generateCommand,
3
3
  generators
4
- } from "./chunk-6XBKSCTE.js";
4
+ } from "./chunk-FMBCFOVH.js";
5
5
  import "./chunk-VMN4KGAK.js";
6
6
  export {
7
7
  generateCommand,
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  horizontalLine,
7
7
  personaCommand,
8
8
  symbols
9
- } from "./chunk-6XBKSCTE.js";
9
+ } from "./chunk-FMBCFOVH.js";
10
10
  import {
11
11
  loadHubConfig,
12
12
  resolveConfigPath
@@ -3875,7 +3875,9 @@ import { readFileSync } from "fs";
3875
3875
  import { join as join17, dirname } from "path";
3876
3876
  import { fileURLToPath } from "url";
3877
3877
  import chalk15 from "chalk";
3878
+ import ora from "ora";
3878
3879
  var PACKAGE_NAME = "@arvoretech/hub";
3880
+ var RELEASES_URL = "https://hub.arvore.com.br/api/releases.json";
3879
3881
  function getCurrentVersion() {
3880
3882
  const __dirname2 = dirname(fileURLToPath(import.meta.url));
3881
3883
  const pkgPath = join17(__dirname2, "..", "package.json");
@@ -3888,6 +3890,24 @@ async function getLatestVersion() {
3888
3890
  const data = await res.json();
3889
3891
  return data.version;
3890
3892
  }
3893
+ function compareVersions(a, b) {
3894
+ const pa = a.split(".").map(Number);
3895
+ const pb = b.split(".").map(Number);
3896
+ for (let i = 0; i < 3; i++) {
3897
+ if ((pa[i] ?? 0) !== (pb[i] ?? 0)) return (pa[i] ?? 0) - (pb[i] ?? 0);
3898
+ }
3899
+ return 0;
3900
+ }
3901
+ async function getReleasesBetween(from, to) {
3902
+ try {
3903
+ const res = await fetch(RELEASES_URL, { signal: AbortSignal.timeout(5e3) });
3904
+ if (!res.ok) return [];
3905
+ const releases = await res.json();
3906
+ return releases.filter((r) => compareVersions(r.version, from) > 0 && compareVersions(r.version, to) <= 0).sort((a, b) => compareVersions(a.version, b.version));
3907
+ } catch {
3908
+ return [];
3909
+ }
3910
+ }
3891
3911
  function detectPackageManager() {
3892
3912
  const userAgent = process.env.npm_config_user_agent ?? "";
3893
3913
  if (userAgent.startsWith("pnpm")) return "pnpm";
@@ -3921,47 +3941,61 @@ function buildInstallCommand(pm) {
3921
3941
  return `npm install -g ${PACKAGE_NAME}@latest`;
3922
3942
  }
3923
3943
  }
3944
+ var typeColors = {
3945
+ feat: chalk15.green,
3946
+ fix: chalk15.yellow,
3947
+ refactor: chalk15.magenta,
3948
+ chore: chalk15.dim
3949
+ };
3950
+ function formatChangeType(type) {
3951
+ const color = typeColors[type] ?? chalk15.dim;
3952
+ return color(type.toUpperCase().padEnd(8));
3953
+ }
3924
3954
  var updateCommand = new Command16("update").description("Update hub CLI to the latest version").option("--check", "Only check for updates without installing").action(async (opts) => {
3925
3955
  const currentVersion = getCurrentVersion();
3926
- console.log(chalk15.blue(`
3927
- Current version: ${currentVersion}`));
3956
+ const checkSpinner = ora({ text: "Checking for updates...", color: "cyan" }).start();
3928
3957
  let latestVersion;
3929
3958
  try {
3930
3959
  latestVersion = await getLatestVersion();
3931
3960
  } catch (err) {
3932
- console.log(chalk15.red(` Failed to check for updates: ${err.message}
3933
- `));
3961
+ checkSpinner.fail(`Failed to check for updates: ${err.message}`);
3934
3962
  return;
3935
3963
  }
3936
- console.log(chalk15.blue(` Latest version: ${latestVersion}`));
3937
3964
  if (currentVersion === latestVersion) {
3938
- console.log(chalk15.green("\n You're already on the latest version.\n"));
3965
+ checkSpinner.succeed(chalk15.green(`Already on the latest version (${currentVersion})`));
3939
3966
  return;
3940
3967
  }
3941
- console.log(chalk15.yellow(`
3942
- Update available: ${currentVersion} \u2192 ${latestVersion}`));
3968
+ checkSpinner.succeed(`Update available: ${chalk15.dim(currentVersion)} \u2192 ${chalk15.green(latestVersion)}`);
3969
+ const releases = await getReleasesBetween(currentVersion, latestVersion);
3970
+ if (releases.length > 0) {
3971
+ console.log();
3972
+ console.log(chalk15.cyan(" Releases included:"));
3973
+ for (const release of releases) {
3974
+ const date = (/* @__PURE__ */ new Date(release.date + "T00:00:00")).toLocaleDateString("pt-BR");
3975
+ console.log();
3976
+ console.log(` ${chalk15.green("\u25CF")} ${chalk15.white.bold(`v${release.version}`)} ${chalk15.dim(`\u2014 ${release.title}`)} ${chalk15.dim(`(${date})`)}`);
3977
+ for (const change of release.changes) {
3978
+ console.log(` ${formatChangeType(change.type)} ${chalk15.dim(change.title)}`);
3979
+ }
3980
+ }
3981
+ console.log();
3982
+ console.log(chalk15.dim(` Full notes: https://hub.arvore.com.br/releases`));
3983
+ }
3943
3984
  const pm = detectPackageManager();
3944
3985
  if (opts.check) {
3945
3986
  console.log(chalk15.dim(`
3946
- Run 'hub update' or '${buildInstallCommand(pm)}' to update.
3987
+ Run 'hub update' to install.
3947
3988
  `));
3948
3989
  return;
3949
3990
  }
3950
- const installCmd = buildInstallCommand(pm);
3951
- console.log(chalk15.cyan(`
3952
- Updating with ${pm}...
3953
- `));
3954
- console.log(chalk15.dim(` $ ${installCmd}
3955
- `));
3991
+ console.log();
3992
+ const installSpinner = ora({ text: `Updating with ${pm}...`, color: "cyan" }).start();
3956
3993
  try {
3957
- execSync12(installCmd, { stdio: "inherit" });
3958
- console.log(chalk15.green(`
3959
- Updated to ${latestVersion} successfully.
3960
- `));
3994
+ execSync12(buildInstallCommand(pm), { stdio: "pipe" });
3995
+ installSpinner.succeed(chalk15.green(`Updated to ${latestVersion}`));
3961
3996
  } catch {
3962
- console.log(chalk15.red(`
3963
- Update failed. Try running manually:`));
3964
- console.log(chalk15.dim(` $ ${installCmd}
3997
+ installSpinner.fail("Update failed");
3998
+ console.log(chalk15.dim(` Try running manually: ${buildInstallCommand(pm)}
3965
3999
  `));
3966
4000
  }
3967
4001
  });
@@ -4109,6 +4143,7 @@ async function findUnsyncedAssets(hubDir) {
4109
4143
  for (const file of files) {
4110
4144
  if (!file.endsWith(".md")) continue;
4111
4145
  if (file === "orchestrator.md") continue;
4146
+ if (file === "persona.md") continue;
4112
4147
  const canonicalFile = join18(canonicalSteeringDir, file);
4113
4148
  if (existsSync14(canonicalFile)) continue;
4114
4149
  const key = `steering:${file}`;
@@ -4127,6 +4162,7 @@ async function findUnsyncedAssets(hubDir) {
4127
4162
  for (const file of files) {
4128
4163
  if (!file.endsWith(".mdc")) continue;
4129
4164
  if (file === "orchestrator.mdc") continue;
4165
+ if (file === "persona.mdc") continue;
4130
4166
  const mdName = file.replace(/\.mdc$/, ".md");
4131
4167
  const canonicalFile = join18(canonicalSteeringDir, mdName);
4132
4168
  if (existsSync14(canonicalFile)) continue;
@@ -4146,6 +4182,7 @@ async function findUnsyncedAssets(hubDir) {
4146
4182
  for (const file of files) {
4147
4183
  if (!file.endsWith(".md")) continue;
4148
4184
  if (file === "orchestrator.md") continue;
4185
+ if (file === "persona.md") continue;
4149
4186
  const canonicalFile = join18(canonicalSteeringDir, file);
4150
4187
  if (existsSync14(canonicalFile)) continue;
4151
4188
  const key = `steering:${file}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arvoretech/hub",
3
- "version": "0.18.1",
3
+ "version": "0.20.0",
4
4
  "description": "CLI for managing AI-aware multi-repository workspaces",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",