@arvoretech/hub 0.18.1 → 0.19.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-
|
|
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
|
-
|
|
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", "
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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 = {
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
horizontalLine,
|
|
7
7
|
personaCommand,
|
|
8
8
|
symbols
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-FMBCFOVH.js";
|
|
10
10
|
import {
|
|
11
11
|
loadHubConfig,
|
|
12
12
|
resolveConfigPath
|
|
@@ -4109,6 +4109,7 @@ async function findUnsyncedAssets(hubDir) {
|
|
|
4109
4109
|
for (const file of files) {
|
|
4110
4110
|
if (!file.endsWith(".md")) continue;
|
|
4111
4111
|
if (file === "orchestrator.md") continue;
|
|
4112
|
+
if (file === "persona.md") continue;
|
|
4112
4113
|
const canonicalFile = join18(canonicalSteeringDir, file);
|
|
4113
4114
|
if (existsSync14(canonicalFile)) continue;
|
|
4114
4115
|
const key = `steering:${file}`;
|
|
@@ -4127,6 +4128,7 @@ async function findUnsyncedAssets(hubDir) {
|
|
|
4127
4128
|
for (const file of files) {
|
|
4128
4129
|
if (!file.endsWith(".mdc")) continue;
|
|
4129
4130
|
if (file === "orchestrator.mdc") continue;
|
|
4131
|
+
if (file === "persona.mdc") continue;
|
|
4130
4132
|
const mdName = file.replace(/\.mdc$/, ".md");
|
|
4131
4133
|
const canonicalFile = join18(canonicalSteeringDir, mdName);
|
|
4132
4134
|
if (existsSync14(canonicalFile)) continue;
|
|
@@ -4146,6 +4148,7 @@ async function findUnsyncedAssets(hubDir) {
|
|
|
4146
4148
|
for (const file of files) {
|
|
4147
4149
|
if (!file.endsWith(".md")) continue;
|
|
4148
4150
|
if (file === "orchestrator.md") continue;
|
|
4151
|
+
if (file === "persona.md") continue;
|
|
4149
4152
|
const canonicalFile = join18(canonicalSteeringDir, file);
|
|
4150
4153
|
if (existsSync14(canonicalFile)) continue;
|
|
4151
4154
|
const key = `steering:${file}`;
|