hatch3r 1.5.0 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/commands/hatch3r-revision.md +47 -120
- package/commands/revision/revision-board-integration.md +87 -0
- package/commands/revision/revision-delegation.md +93 -0
- package/commands/revision/revision-modes.md +91 -0
- package/commands/revision/revision-quality.md +96 -0
- package/dist/cli/index.js +225 -261
- package/dist/cli/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -14,7 +14,7 @@ var HATCH3R_VERSION;
|
|
|
14
14
|
var init_version = __esm({
|
|
15
15
|
"src/version.ts"() {
|
|
16
16
|
"use strict";
|
|
17
|
-
HATCH3R_VERSION = "1.5.
|
|
17
|
+
HATCH3R_VERSION = "1.5.1";
|
|
18
18
|
}
|
|
19
19
|
});
|
|
20
20
|
|
|
@@ -4990,7 +4990,7 @@ async function buildContentIndex(contentRoot) {
|
|
|
4990
4990
|
}
|
|
4991
4991
|
return { items, byType, byId, byTypeAndId, collisions };
|
|
4992
4992
|
}
|
|
4993
|
-
function resolveSelection(preset, projectType, teamSize, index, customSelections, projectLanguages) {
|
|
4993
|
+
function resolveSelection(preset, projectType, teamSize, index, customSelections, projectLanguages, options) {
|
|
4994
4994
|
let selected;
|
|
4995
4995
|
const relevantLangTags = /* @__PURE__ */ new Set();
|
|
4996
4996
|
if (projectLanguages) {
|
|
@@ -5019,26 +5019,28 @@ function resolveSelection(preset, projectType, teamSize, index, customSelections
|
|
|
5019
5019
|
(item) => item.protected || item.tags.length === 0 || !item.tags.every((t) => excludeSet.has(t))
|
|
5020
5020
|
);
|
|
5021
5021
|
}
|
|
5022
|
-
if (
|
|
5023
|
-
|
|
5024
|
-
|
|
5025
|
-
|
|
5026
|
-
} else {
|
|
5027
|
-
selected = selected.filter(
|
|
5028
|
-
(item) => item.protected || !item.tags.includes("greenfield") || item.tags.some((t) => t !== "greenfield" && t !== "team" && t !== "solo")
|
|
5029
|
-
);
|
|
5030
|
-
}
|
|
5031
|
-
if (teamSize === "solo") {
|
|
5032
|
-
selected = selected.filter((item) => {
|
|
5033
|
-
if (item.protected) return true;
|
|
5034
|
-
if (!item.tags.includes("team") && !item.tags.includes("board")) return true;
|
|
5035
|
-
return item.tags.some(
|
|
5036
|
-
(t) => t !== "team" && t !== "board" && t !== "solo" && t !== "greenfield" && t !== "brownfield"
|
|
5022
|
+
if (!options?.skipContextFilters) {
|
|
5023
|
+
if (projectType === "greenfield") {
|
|
5024
|
+
selected = selected.filter(
|
|
5025
|
+
(item) => item.protected || !item.tags.includes("brownfield") || item.tags.some((t) => t !== "brownfield" && t !== "team" && t !== "solo")
|
|
5037
5026
|
);
|
|
5038
|
-
}
|
|
5027
|
+
} else {
|
|
5028
|
+
selected = selected.filter(
|
|
5029
|
+
(item) => item.protected || !item.tags.includes("greenfield") || item.tags.some((t) => t !== "greenfield" && t !== "team" && t !== "solo")
|
|
5030
|
+
);
|
|
5031
|
+
}
|
|
5032
|
+
if (teamSize === "solo") {
|
|
5033
|
+
selected = selected.filter((item) => {
|
|
5034
|
+
if (item.protected) return true;
|
|
5035
|
+
if (!item.tags.includes("team") && !item.tags.includes("board")) return true;
|
|
5036
|
+
return item.tags.some(
|
|
5037
|
+
(t) => t !== "team" && t !== "board" && t !== "solo" && t !== "greenfield" && t !== "brownfield"
|
|
5038
|
+
);
|
|
5039
|
+
});
|
|
5040
|
+
}
|
|
5039
5041
|
}
|
|
5040
5042
|
}
|
|
5041
|
-
if (projectLanguages && projectLanguages.length > 0) {
|
|
5043
|
+
if (!options?.skipContextFilters && projectLanguages && projectLanguages.length > 0) {
|
|
5042
5044
|
selected = selected.filter((item) => {
|
|
5043
5045
|
if (item.protected) return true;
|
|
5044
5046
|
const itemLangTags = item.tags.filter(isLanguageTag);
|
|
@@ -5303,8 +5305,8 @@ function getAllContentIds(selection) {
|
|
|
5303
5305
|
}
|
|
5304
5306
|
return ids;
|
|
5305
5307
|
}
|
|
5306
|
-
function estimatePresetItemCount(preset, projectType, teamSize, index, projectLanguages) {
|
|
5307
|
-
const selection = resolveSelection(preset, projectType, teamSize, index, void 0, projectLanguages);
|
|
5308
|
+
function estimatePresetItemCount(preset, projectType, teamSize, index, projectLanguages, options) {
|
|
5309
|
+
const selection = resolveSelection(preset, projectType, teamSize, index, void 0, projectLanguages, options);
|
|
5308
5310
|
return Object.values(selection.items).reduce((sum, arr) => sum + arr.length, 0);
|
|
5309
5311
|
}
|
|
5310
5312
|
function countSelectionItems(selection) {
|
|
@@ -5467,7 +5469,7 @@ import { execFileSync as execFileSync4 } from "child_process";
|
|
|
5467
5469
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
5468
5470
|
import { dirname as dirname11, join as join22 } from "path";
|
|
5469
5471
|
import chalk7 from "chalk";
|
|
5470
|
-
import
|
|
5472
|
+
import inquirer4 from "inquirer";
|
|
5471
5473
|
async function readFileOrNull(filePath) {
|
|
5472
5474
|
try {
|
|
5473
5475
|
return await readFile19(filePath, "utf-8");
|
|
@@ -5798,7 +5800,7 @@ var init_update = __esm({
|
|
|
5798
5800
|
content.projectType = "brownfield";
|
|
5799
5801
|
content.teamSize = "team";
|
|
5800
5802
|
} else {
|
|
5801
|
-
const { projectType } = await
|
|
5803
|
+
const { projectType } = await inquirer4.prompt([
|
|
5802
5804
|
{
|
|
5803
5805
|
type: "select",
|
|
5804
5806
|
name: "projectType",
|
|
@@ -5810,7 +5812,7 @@ var init_update = __esm({
|
|
|
5810
5812
|
default: "brownfield"
|
|
5811
5813
|
}
|
|
5812
5814
|
]);
|
|
5813
|
-
const { teamSize } = await
|
|
5815
|
+
const { teamSize } = await inquirer4.prompt([
|
|
5814
5816
|
{
|
|
5815
5817
|
type: "select",
|
|
5816
5818
|
name: "teamSize",
|
|
@@ -5839,7 +5841,7 @@ var init_update = __esm({
|
|
|
5839
5841
|
if (headless) {
|
|
5840
5842
|
platform = "github";
|
|
5841
5843
|
} else {
|
|
5842
|
-
const answer = await
|
|
5844
|
+
const answer = await inquirer4.prompt([
|
|
5843
5845
|
{
|
|
5844
5846
|
type: "select",
|
|
5845
5847
|
name: "platform",
|
|
@@ -5861,7 +5863,7 @@ var init_update = __esm({
|
|
|
5861
5863
|
updated.project = updated.project || updated.repo;
|
|
5862
5864
|
notices.push("Migrated to GitHub platform (auto-detected from existing config)");
|
|
5863
5865
|
} else {
|
|
5864
|
-
const answers = await
|
|
5866
|
+
const answers = await inquirer4.prompt([
|
|
5865
5867
|
{ type: "input", name: "namespace", message: platform === "azure-devops" ? "Azure DevOps organization:" : "GitLab namespace (group or username):", default: updated.owner || void 0 },
|
|
5866
5868
|
{ type: "input", name: "project", message: platform === "azure-devops" ? "Azure DevOps project:" : "Project name:", default: updated.repo || void 0 },
|
|
5867
5869
|
{ type: "input", name: "repo", message: "Repository name:", default: updated.repo || void 0 }
|
|
@@ -5925,7 +5927,7 @@ var init_update = __esm({
|
|
|
5925
5927
|
if (headless) {
|
|
5926
5928
|
enabled = true;
|
|
5927
5929
|
} else {
|
|
5928
|
-
const answer = await
|
|
5930
|
+
const answer = await inquirer4.prompt([{
|
|
5929
5931
|
type: "confirm",
|
|
5930
5932
|
name: "enabled",
|
|
5931
5933
|
message: "hatch3r now supports worktree file isolation for parallel agent sessions. Enable it?",
|
|
@@ -6101,7 +6103,7 @@ init_ui();
|
|
|
6101
6103
|
init_types();
|
|
6102
6104
|
import { rm as rm4 } from "fs/promises";
|
|
6103
6105
|
import chalk6 from "chalk";
|
|
6104
|
-
import
|
|
6106
|
+
import inquirer3 from "inquirer";
|
|
6105
6107
|
|
|
6106
6108
|
// src/clean/index.ts
|
|
6107
6109
|
init_archive();
|
|
@@ -6367,7 +6369,7 @@ import { access as access8, mkdir as mkdir7, readFile as readFile18 } from "fs/p
|
|
|
6367
6369
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
6368
6370
|
import { basename as basename2, dirname as dirname10, join as join21 } from "path";
|
|
6369
6371
|
import chalk5 from "chalk";
|
|
6370
|
-
import
|
|
6372
|
+
import inquirer2 from "inquirer";
|
|
6371
6373
|
|
|
6372
6374
|
// src/detect/repoAnalyzer.ts
|
|
6373
6375
|
init_packageManager();
|
|
@@ -6686,6 +6688,47 @@ init_agentsContent();
|
|
|
6686
6688
|
init_ui();
|
|
6687
6689
|
init_paths();
|
|
6688
6690
|
|
|
6691
|
+
// src/cli/shared/customContentChoices.ts
|
|
6692
|
+
import inquirer from "inquirer";
|
|
6693
|
+
var CONTENT_TAG_LABELS = {
|
|
6694
|
+
core: "Core",
|
|
6695
|
+
planning: "Planning",
|
|
6696
|
+
implementation: "Implementation",
|
|
6697
|
+
review: "Review",
|
|
6698
|
+
devops: "DevOps",
|
|
6699
|
+
maintenance: "Maintenance",
|
|
6700
|
+
greenfield: "Greenfield",
|
|
6701
|
+
brownfield: "Brownfield",
|
|
6702
|
+
board: "Board",
|
|
6703
|
+
security: "Security",
|
|
6704
|
+
a11y: "Accessibility",
|
|
6705
|
+
performance: "Performance",
|
|
6706
|
+
customize: "Customization",
|
|
6707
|
+
other: "Other"
|
|
6708
|
+
};
|
|
6709
|
+
function buildTagGroupedCustomContentChoices(items, isChecked) {
|
|
6710
|
+
const tagGroups = /* @__PURE__ */ new Map();
|
|
6711
|
+
for (const item of items) {
|
|
6712
|
+
const primaryTag = item.tags[0] ?? "other";
|
|
6713
|
+
if (!tagGroups.has(primaryTag)) tagGroups.set(primaryTag, []);
|
|
6714
|
+
tagGroups.get(primaryTag).push(item);
|
|
6715
|
+
}
|
|
6716
|
+
const groupedChoices = [];
|
|
6717
|
+
for (const [tag, groupItems] of tagGroups) {
|
|
6718
|
+
groupedChoices.push(
|
|
6719
|
+
new inquirer.Separator(`\u2500\u2500 ${CONTENT_TAG_LABELS[tag] ?? tag} (${groupItems.length}) \u2500\u2500`)
|
|
6720
|
+
);
|
|
6721
|
+
for (const item of groupItems) {
|
|
6722
|
+
groupedChoices.push({
|
|
6723
|
+
name: `${item.type}: ${item.id.replace(/^(cmd-)?hatch3r-/, "")} \u2014 ${item.description.slice(0, 60)}`,
|
|
6724
|
+
value: item.id,
|
|
6725
|
+
checked: isChecked(item)
|
|
6726
|
+
});
|
|
6727
|
+
}
|
|
6728
|
+
}
|
|
6729
|
+
return groupedChoices;
|
|
6730
|
+
}
|
|
6731
|
+
|
|
6689
6732
|
// src/cli/shared/constants.ts
|
|
6690
6733
|
init_types();
|
|
6691
6734
|
import { readFileSync as readFileSync2 } from "fs";
|
|
@@ -6800,14 +6843,14 @@ var PRESETS = [
|
|
|
6800
6843
|
},
|
|
6801
6844
|
{
|
|
6802
6845
|
id: "standard",
|
|
6803
|
-
name: "Standard
|
|
6846
|
+
name: "Standard",
|
|
6804
6847
|
description: "Full development lifecycle without niche audits",
|
|
6805
6848
|
includeTags: ["core", "planning", "implementation", "review", "devops", "maintenance"],
|
|
6806
6849
|
excludeTags: ["board", "a11y", "performance", "customize"]
|
|
6807
6850
|
},
|
|
6808
6851
|
{
|
|
6809
6852
|
id: "full",
|
|
6810
|
-
name: "Full",
|
|
6853
|
+
name: "Full (recommended)",
|
|
6811
6854
|
description: "Everything including board management and all audits",
|
|
6812
6855
|
includeTags: [],
|
|
6813
6856
|
// empty = include all
|
|
@@ -7274,7 +7317,7 @@ async function syncSingleRepo(workspaceRoot, wsManifest, wsChecksum, repoEntry,
|
|
|
7274
7317
|
// src/cli/commands/init.ts
|
|
7275
7318
|
var __dirname2 = dirname10(fileURLToPath2(import.meta.url));
|
|
7276
7319
|
var CONTENT_ROOT2 = findPackageRoot(__dirname2);
|
|
7277
|
-
var DEFAULT_TOOLS = ["
|
|
7320
|
+
var DEFAULT_TOOLS = ["claude"];
|
|
7278
7321
|
var DEFAULT_FEATURE_KEYS = Object.keys(DEFAULT_FEATURES);
|
|
7279
7322
|
var DEFAULT_MCP = ["playwright", "github", "context7"];
|
|
7280
7323
|
function selectionHasBoardContent(selection) {
|
|
@@ -7489,7 +7532,7 @@ async function checkExisting(rootDir, skipPrompt, newSelection) {
|
|
|
7489
7532
|
}
|
|
7490
7533
|
}
|
|
7491
7534
|
}
|
|
7492
|
-
const { proceed } = await
|
|
7535
|
+
const { proceed } = await inquirer2.prompt([
|
|
7493
7536
|
{
|
|
7494
7537
|
type: "confirm",
|
|
7495
7538
|
name: "proceed",
|
|
@@ -7526,7 +7569,7 @@ async function initCommand(opts = {}) {
|
|
|
7526
7569
|
info(chalk5.dim(`No git repo found. ${detectedRepos.length} git repo(s) detected in subdirectories \u2014 initializing as workspace.`));
|
|
7527
7570
|
} else {
|
|
7528
7571
|
info(`No git repo found, but ${detectedRepos.length} git repo(s) detected in subdirectories.`);
|
|
7529
|
-
const { useWorkspace } = await
|
|
7572
|
+
const { useWorkspace } = await inquirer2.prompt([
|
|
7530
7573
|
{
|
|
7531
7574
|
type: "confirm",
|
|
7532
7575
|
name: "useWorkspace",
|
|
@@ -7587,7 +7630,7 @@ async function initCommand(opts = {}) {
|
|
|
7587
7630
|
const mcpServers2 = features2.mcp ? Array.from(/* @__PURE__ */ new Set([platformMcp, ...DEFAULT_MCP.filter((s) => s !== "github")])) : [];
|
|
7588
7631
|
const defaultBranch2 = parseGitDefaultBranch();
|
|
7589
7632
|
const isGreenfield = repoInfo.languages.length === 1 && repoInfo.languages[0] === "unknown" && repoInfo.existingTools.length === 0 && !repoInfo.hasExistingAgents;
|
|
7590
|
-
const presetId = validateFlag(opts.preset, ["minimal", "standard", "full"], "
|
|
7633
|
+
const presetId = validateFlag(opts.preset, ["minimal", "standard", "full"], "full", "preset");
|
|
7591
7634
|
const projectType2 = validateFlag(opts.projectType, ["greenfield", "brownfield"], isGreenfield ? "greenfield" : "brownfield", "project-type");
|
|
7592
7635
|
const teamSize2 = validateFlag(opts.teamSize, ["solo", "team"], "solo", "team-size");
|
|
7593
7636
|
const preset = getPreset(presetId);
|
|
@@ -7605,7 +7648,7 @@ async function initCommand(opts = {}) {
|
|
|
7605
7648
|
console.log();
|
|
7606
7649
|
const remoteUrl = getGitRemoteUrl();
|
|
7607
7650
|
const detectedPlatform = detectPlatformFromRemote(remoteUrl);
|
|
7608
|
-
const platformAnswer = await
|
|
7651
|
+
const platformAnswer = await inquirer2.prompt([
|
|
7609
7652
|
{
|
|
7610
7653
|
type: "select",
|
|
7611
7654
|
name: "platform",
|
|
@@ -7624,7 +7667,7 @@ async function initCommand(opts = {}) {
|
|
|
7624
7667
|
let namespace;
|
|
7625
7668
|
let project;
|
|
7626
7669
|
if (platform === "azure-devops") {
|
|
7627
|
-
const adoAnswers = await
|
|
7670
|
+
const adoAnswers = await inquirer2.prompt([
|
|
7628
7671
|
{ type: "input", name: "org", message: "Azure DevOps organization:", default: remote.owner || void 0 },
|
|
7629
7672
|
{ type: "input", name: "project", message: "Azure DevOps project:" },
|
|
7630
7673
|
{ type: "input", name: "repo", message: "Repository name:", default: remote.repo || void 0 }
|
|
@@ -7634,7 +7677,7 @@ async function initCommand(opts = {}) {
|
|
|
7634
7677
|
namespace = owner;
|
|
7635
7678
|
project = sanitizeInput(adoAnswers.project);
|
|
7636
7679
|
} else if (platform === "gitlab") {
|
|
7637
|
-
const glAnswers = await
|
|
7680
|
+
const glAnswers = await inquirer2.prompt([
|
|
7638
7681
|
{ type: "input", name: "namespace", message: "GitLab namespace (group or username):", default: remote.owner || void 0 },
|
|
7639
7682
|
{ type: "input", name: "project", message: "Project name:", default: remote.repo || void 0 }
|
|
7640
7683
|
]);
|
|
@@ -7643,7 +7686,7 @@ async function initCommand(opts = {}) {
|
|
|
7643
7686
|
namespace = owner;
|
|
7644
7687
|
project = repo;
|
|
7645
7688
|
} else {
|
|
7646
|
-
const repoAnswers = await
|
|
7689
|
+
const repoAnswers = await inquirer2.prompt([
|
|
7647
7690
|
{ type: "input", name: "owner", message: "GitHub owner (org or username):", default: remote.owner || void 0 },
|
|
7648
7691
|
{ type: "input", name: "repo", message: "Repository name:", default: remote.repo || void 0 }
|
|
7649
7692
|
]);
|
|
@@ -7653,7 +7696,7 @@ async function initCommand(opts = {}) {
|
|
|
7653
7696
|
project = repo;
|
|
7654
7697
|
}
|
|
7655
7698
|
const defaultBranchDefault = parseGitDefaultBranch();
|
|
7656
|
-
const defaultBranchAnswers = await
|
|
7699
|
+
const defaultBranchAnswers = await inquirer2.prompt([
|
|
7657
7700
|
{
|
|
7658
7701
|
type: "input",
|
|
7659
7702
|
name: "defaultBranch",
|
|
@@ -7666,7 +7709,7 @@ async function initCommand(opts = {}) {
|
|
|
7666
7709
|
const isAutoGreenfield = repoInfo.languages.length === 1 && repoInfo.languages[0] === "unknown" && repoInfo.existingTools.length === 0 && !repoInfo.hasExistingAgents;
|
|
7667
7710
|
const greenfieldExcl = countProjectTypeExclusions("greenfield", filterIndex.items);
|
|
7668
7711
|
const brownfieldExcl = countProjectTypeExclusions("brownfield", filterIndex.items);
|
|
7669
|
-
const projectTypeAnswer = await
|
|
7712
|
+
const projectTypeAnswer = await inquirer2.prompt([
|
|
7670
7713
|
{
|
|
7671
7714
|
type: "select",
|
|
7672
7715
|
name: "projectType",
|
|
@@ -7680,7 +7723,7 @@ async function initCommand(opts = {}) {
|
|
|
7680
7723
|
]);
|
|
7681
7724
|
const projectType = projectTypeAnswer.projectType;
|
|
7682
7725
|
const soloExcl = countTeamSizeExclusions("solo", filterIndex.items);
|
|
7683
|
-
const teamSizeAnswer = await
|
|
7726
|
+
const teamSizeAnswer = await inquirer2.prompt([
|
|
7684
7727
|
{
|
|
7685
7728
|
type: "select",
|
|
7686
7729
|
name: "teamSize",
|
|
@@ -7694,7 +7737,7 @@ async function initCommand(opts = {}) {
|
|
|
7694
7737
|
]);
|
|
7695
7738
|
const teamSize = teamSizeAnswer.teamSize;
|
|
7696
7739
|
const totalItems = filterIndex.items.length;
|
|
7697
|
-
const presetAnswer = await
|
|
7740
|
+
const presetAnswer = await inquirer2.prompt([
|
|
7698
7741
|
{
|
|
7699
7742
|
type: "select",
|
|
7700
7743
|
name: "preset",
|
|
@@ -7709,7 +7752,7 @@ async function initCommand(opts = {}) {
|
|
|
7709
7752
|
value: p.id
|
|
7710
7753
|
};
|
|
7711
7754
|
}),
|
|
7712
|
-
default: "
|
|
7755
|
+
default: "full"
|
|
7713
7756
|
}
|
|
7714
7757
|
]);
|
|
7715
7758
|
const selectedPreset = getPreset(presetAnswer.preset);
|
|
@@ -7717,40 +7760,11 @@ async function initCommand(opts = {}) {
|
|
|
7717
7760
|
let customSelections;
|
|
7718
7761
|
if (selectedPreset.id === "custom") {
|
|
7719
7762
|
const contentIndex = filterIndex;
|
|
7720
|
-
const
|
|
7721
|
-
|
|
7722
|
-
|
|
7723
|
-
|
|
7724
|
-
|
|
7725
|
-
}
|
|
7726
|
-
const TAG_LABELS = {
|
|
7727
|
-
core: "Core",
|
|
7728
|
-
planning: "Planning",
|
|
7729
|
-
implementation: "Implementation",
|
|
7730
|
-
review: "Review",
|
|
7731
|
-
devops: "DevOps",
|
|
7732
|
-
maintenance: "Maintenance",
|
|
7733
|
-
greenfield: "Greenfield",
|
|
7734
|
-
brownfield: "Brownfield",
|
|
7735
|
-
board: "Board",
|
|
7736
|
-
security: "Security",
|
|
7737
|
-
a11y: "Accessibility",
|
|
7738
|
-
performance: "Performance",
|
|
7739
|
-
customize: "Customization",
|
|
7740
|
-
other: "Other"
|
|
7741
|
-
};
|
|
7742
|
-
const groupedChoices = [];
|
|
7743
|
-
for (const [tag, items] of tagGroups) {
|
|
7744
|
-
groupedChoices.push(new inquirer.Separator(`\u2500\u2500 ${TAG_LABELS[tag] ?? tag} (${items.length}) \u2500\u2500`));
|
|
7745
|
-
for (const item of items) {
|
|
7746
|
-
groupedChoices.push({
|
|
7747
|
-
name: `${item.type}: ${item.id.replace(/^(cmd-)?hatch3r-/, "")} \u2014 ${item.description.slice(0, 60)}`,
|
|
7748
|
-
value: item.id,
|
|
7749
|
-
checked: item.protected || item.tags.includes("core")
|
|
7750
|
-
});
|
|
7751
|
-
}
|
|
7752
|
-
}
|
|
7753
|
-
const customAnswer = await inquirer.prompt([
|
|
7763
|
+
const groupedChoices = buildTagGroupedCustomContentChoices(
|
|
7764
|
+
contentIndex.items,
|
|
7765
|
+
(item) => item.protected || item.tags.includes("core")
|
|
7766
|
+
);
|
|
7767
|
+
const customAnswer = await inquirer2.prompt([
|
|
7754
7768
|
{
|
|
7755
7769
|
type: "checkbox",
|
|
7756
7770
|
name: "items",
|
|
@@ -7762,7 +7776,7 @@ async function initCommand(opts = {}) {
|
|
|
7762
7776
|
customSelections = customAnswer.items;
|
|
7763
7777
|
}
|
|
7764
7778
|
const toolDefaults = repoInfo.existingTools.length > 0 ? repoInfo.existingTools : DEFAULT_TOOLS;
|
|
7765
|
-
const toolAnswers = await
|
|
7779
|
+
const toolAnswers = await inquirer2.prompt([
|
|
7766
7780
|
{
|
|
7767
7781
|
type: "checkbox",
|
|
7768
7782
|
name: "tools",
|
|
@@ -7780,7 +7794,7 @@ async function initCommand(opts = {}) {
|
|
|
7780
7794
|
info(chalk5.dim(` ${note}`));
|
|
7781
7795
|
}
|
|
7782
7796
|
}
|
|
7783
|
-
const featureAnswers = await
|
|
7797
|
+
const featureAnswers = await inquirer2.prompt([
|
|
7784
7798
|
{
|
|
7785
7799
|
type: "checkbox",
|
|
7786
7800
|
name: "features",
|
|
@@ -7801,7 +7815,7 @@ async function initCommand(opts = {}) {
|
|
|
7801
7815
|
const defaultMcpForPlatform = Array.from(
|
|
7802
7816
|
/* @__PURE__ */ new Set([platformMcp, ...DEFAULT_MCP.filter((s) => s !== "github")])
|
|
7803
7817
|
);
|
|
7804
|
-
const mcpAnswers = await
|
|
7818
|
+
const mcpAnswers = await inquirer2.prompt([
|
|
7805
7819
|
{
|
|
7806
7820
|
type: "checkbox",
|
|
7807
7821
|
name: "mcp",
|
|
@@ -7838,7 +7852,7 @@ async function runWorkspaceInit(rootDir, detectedRepos, repoInfo, opts) {
|
|
|
7838
7852
|
const platformMcp = PLATFORM_MCP_SERVER[platform2];
|
|
7839
7853
|
const mcpServers2 = features2.mcp ? Array.from(/* @__PURE__ */ new Set([platformMcp, ...DEFAULT_MCP.filter((s) => s !== "github")])) : [];
|
|
7840
7854
|
const index = await buildContentIndex(CONTENT_ROOT2);
|
|
7841
|
-
const contentSelection2 = resolveSelection(getPreset("
|
|
7855
|
+
const contentSelection2 = resolveSelection(getPreset("full"), "brownfield", "solo", index);
|
|
7842
7856
|
const wsManifest2 = createWorkspaceManifest(
|
|
7843
7857
|
basename2(rootDir) || "workspace",
|
|
7844
7858
|
{ platform: platform2, tools: tools2, features: features2, mcp: { servers: mcpServers2 }, content: contentSelection2 },
|
|
@@ -7867,7 +7881,7 @@ async function runWorkspaceInit(rootDir, detectedRepos, repoInfo, opts) {
|
|
|
7867
7881
|
}
|
|
7868
7882
|
console.log();
|
|
7869
7883
|
if (!headless) {
|
|
7870
|
-
const { acceptIdentity } = await
|
|
7884
|
+
const { acceptIdentity } = await inquirer2.prompt([
|
|
7871
7885
|
{
|
|
7872
7886
|
type: "confirm",
|
|
7873
7887
|
name: "acceptIdentity",
|
|
@@ -7879,7 +7893,7 @@ async function runWorkspaceInit(rootDir, detectedRepos, repoInfo, opts) {
|
|
|
7879
7893
|
for (const r of enriched) {
|
|
7880
7894
|
console.log(chalk5.bold(`
|
|
7881
7895
|
${r.name ?? r.path}:`));
|
|
7882
|
-
const identity = await
|
|
7896
|
+
const identity = await inquirer2.prompt([
|
|
7883
7897
|
{ type: "input", name: "owner", message: " Owner:", default: r.owner || void 0 },
|
|
7884
7898
|
{ type: "input", name: "repo", message: " Repo:", default: r.repo || void 0 },
|
|
7885
7899
|
{ type: "input", name: "defaultBranch", message: " Default branch:", default: r.defaultBranch || "main" }
|
|
@@ -7901,7 +7915,7 @@ async function runWorkspaceInit(rootDir, detectedRepos, repoInfo, opts) {
|
|
|
7901
7915
|
const platformMcp = PLATFORM_MCP_SERVER[platform];
|
|
7902
7916
|
mcpServers = features.mcp ? Array.from(/* @__PURE__ */ new Set([platformMcp, ...DEFAULT_MCP.filter((s) => s !== "github")])) : [];
|
|
7903
7917
|
const isGreenfield = repoInfo.languages.length === 1 && repoInfo.languages[0] === "unknown" && repoInfo.existingTools.length === 0 && !repoInfo.hasExistingAgents;
|
|
7904
|
-
const presetId = validateFlag(opts.preset, ["minimal", "standard", "full"], "
|
|
7918
|
+
const presetId = validateFlag(opts.preset, ["minimal", "standard", "full"], "full", "preset");
|
|
7905
7919
|
const projectType = validateFlag(opts.projectType, ["greenfield", "brownfield"], isGreenfield ? "greenfield" : "brownfield", "project-type");
|
|
7906
7920
|
const teamSize = validateFlag(opts.teamSize, ["solo", "team"], "solo", "team-size");
|
|
7907
7921
|
const preset = getPreset(presetId);
|
|
@@ -7913,7 +7927,7 @@ async function runWorkspaceInit(rootDir, detectedRepos, repoInfo, opts) {
|
|
|
7913
7927
|
const isAutoGreenfield = repoInfo.languages.length === 1 && repoInfo.languages[0] === "unknown" && repoInfo.existingTools.length === 0 && !repoInfo.hasExistingAgents;
|
|
7914
7928
|
const wsGreenfieldExcl = countProjectTypeExclusions("greenfield", wsFilterIndex.items);
|
|
7915
7929
|
const wsBrownfieldExcl = countProjectTypeExclusions("brownfield", wsFilterIndex.items);
|
|
7916
|
-
const projectTypeAnswer = await
|
|
7930
|
+
const projectTypeAnswer = await inquirer2.prompt([
|
|
7917
7931
|
{
|
|
7918
7932
|
type: "select",
|
|
7919
7933
|
name: "projectType",
|
|
@@ -7927,7 +7941,7 @@ async function runWorkspaceInit(rootDir, detectedRepos, repoInfo, opts) {
|
|
|
7927
7941
|
]);
|
|
7928
7942
|
const projectType = projectTypeAnswer.projectType;
|
|
7929
7943
|
const wsSoloExcl = countTeamSizeExclusions("solo", wsFilterIndex.items);
|
|
7930
|
-
const teamSizeAnswer = await
|
|
7944
|
+
const teamSizeAnswer = await inquirer2.prompt([
|
|
7931
7945
|
{
|
|
7932
7946
|
type: "select",
|
|
7933
7947
|
name: "teamSize",
|
|
@@ -7941,7 +7955,7 @@ async function runWorkspaceInit(rootDir, detectedRepos, repoInfo, opts) {
|
|
|
7941
7955
|
]);
|
|
7942
7956
|
const teamSize = teamSizeAnswer.teamSize;
|
|
7943
7957
|
const wsTotalItems = wsFilterIndex.items.length;
|
|
7944
|
-
const presetAnswer = await
|
|
7958
|
+
const presetAnswer = await inquirer2.prompt([
|
|
7945
7959
|
{
|
|
7946
7960
|
type: "select",
|
|
7947
7961
|
name: "preset",
|
|
@@ -7956,47 +7970,18 @@ async function runWorkspaceInit(rootDir, detectedRepos, repoInfo, opts) {
|
|
|
7956
7970
|
value: p.id
|
|
7957
7971
|
};
|
|
7958
7972
|
}),
|
|
7959
|
-
default: "
|
|
7973
|
+
default: "full"
|
|
7960
7974
|
}
|
|
7961
7975
|
]);
|
|
7962
7976
|
const selectedPreset = getPreset(presetAnswer.preset);
|
|
7963
7977
|
let customSelections;
|
|
7964
7978
|
if (selectedPreset.id === "custom") {
|
|
7965
7979
|
const contentIndex = wsFilterIndex;
|
|
7966
|
-
const
|
|
7967
|
-
|
|
7968
|
-
|
|
7969
|
-
|
|
7970
|
-
|
|
7971
|
-
}
|
|
7972
|
-
const WS_TAG_LABELS = {
|
|
7973
|
-
core: "Core",
|
|
7974
|
-
planning: "Planning",
|
|
7975
|
-
implementation: "Implementation",
|
|
7976
|
-
review: "Review",
|
|
7977
|
-
devops: "DevOps",
|
|
7978
|
-
maintenance: "Maintenance",
|
|
7979
|
-
greenfield: "Greenfield",
|
|
7980
|
-
brownfield: "Brownfield",
|
|
7981
|
-
board: "Board",
|
|
7982
|
-
security: "Security",
|
|
7983
|
-
a11y: "Accessibility",
|
|
7984
|
-
performance: "Performance",
|
|
7985
|
-
customize: "Customization",
|
|
7986
|
-
other: "Other"
|
|
7987
|
-
};
|
|
7988
|
-
const wsGroupedChoices = [];
|
|
7989
|
-
for (const [tag, items] of wsTagGroups) {
|
|
7990
|
-
wsGroupedChoices.push(new inquirer.Separator(`\u2500\u2500 ${WS_TAG_LABELS[tag] ?? tag} (${items.length}) \u2500\u2500`));
|
|
7991
|
-
for (const item of items) {
|
|
7992
|
-
wsGroupedChoices.push({
|
|
7993
|
-
name: `${item.type}: ${item.id.replace(/^(cmd-)?hatch3r-/, "")} \u2014 ${item.description.slice(0, 60)}`,
|
|
7994
|
-
value: item.id,
|
|
7995
|
-
checked: item.protected || item.tags.includes("core")
|
|
7996
|
-
});
|
|
7997
|
-
}
|
|
7998
|
-
}
|
|
7999
|
-
const customAnswer = await inquirer.prompt([
|
|
7980
|
+
const wsGroupedChoices = buildTagGroupedCustomContentChoices(
|
|
7981
|
+
contentIndex.items,
|
|
7982
|
+
(item) => item.protected || item.tags.includes("core")
|
|
7983
|
+
);
|
|
7984
|
+
const customAnswer = await inquirer2.prompt([
|
|
8000
7985
|
{
|
|
8001
7986
|
type: "checkbox",
|
|
8002
7987
|
name: "items",
|
|
@@ -8008,7 +7993,7 @@ async function runWorkspaceInit(rootDir, detectedRepos, repoInfo, opts) {
|
|
|
8008
7993
|
customSelections = customAnswer.items;
|
|
8009
7994
|
}
|
|
8010
7995
|
const toolDefaults = repoInfo.existingTools.length > 0 ? repoInfo.existingTools : DEFAULT_TOOLS;
|
|
8011
|
-
const toolAnswers = await
|
|
7996
|
+
const toolAnswers = await inquirer2.prompt([
|
|
8012
7997
|
{
|
|
8013
7998
|
type: "checkbox",
|
|
8014
7999
|
name: "tools",
|
|
@@ -8026,7 +8011,7 @@ async function runWorkspaceInit(rootDir, detectedRepos, repoInfo, opts) {
|
|
|
8026
8011
|
info(chalk5.dim(` ${note}`));
|
|
8027
8012
|
}
|
|
8028
8013
|
}
|
|
8029
|
-
const featureAnswers = await
|
|
8014
|
+
const featureAnswers = await inquirer2.prompt([
|
|
8030
8015
|
{
|
|
8031
8016
|
type: "checkbox",
|
|
8032
8017
|
name: "features",
|
|
@@ -8047,7 +8032,7 @@ async function runWorkspaceInit(rootDir, detectedRepos, repoInfo, opts) {
|
|
|
8047
8032
|
const defaultMcpForPlatform = Array.from(
|
|
8048
8033
|
/* @__PURE__ */ new Set([platformMcp, ...DEFAULT_MCP.filter((s) => s !== "github")])
|
|
8049
8034
|
);
|
|
8050
|
-
const mcpAnswers = await
|
|
8035
|
+
const mcpAnswers = await inquirer2.prompt([
|
|
8051
8036
|
{
|
|
8052
8037
|
type: "checkbox",
|
|
8053
8038
|
name: "mcp",
|
|
@@ -8097,7 +8082,7 @@ async function runWorkspaceInit(rootDir, detectedRepos, repoInfo, opts) {
|
|
|
8097
8082
|
}));
|
|
8098
8083
|
} else {
|
|
8099
8084
|
const wslTheme = isWSL() ? { icon: { checked: chalk5.green("[x]"), unchecked: "[ ]", cursor: ">" } } : void 0;
|
|
8100
|
-
const { syncRepos } = await
|
|
8085
|
+
const { syncRepos } = await inquirer2.prompt([
|
|
8101
8086
|
{
|
|
8102
8087
|
type: "checkbox",
|
|
8103
8088
|
name: "syncRepos",
|
|
@@ -8265,7 +8250,7 @@ async function cleanCommand(opts = {}) {
|
|
|
8265
8250
|
return;
|
|
8266
8251
|
}
|
|
8267
8252
|
if (!opts.yes) {
|
|
8268
|
-
const { proceed } = await
|
|
8253
|
+
const { proceed } = await inquirer3.prompt([
|
|
8269
8254
|
{
|
|
8270
8255
|
type: "confirm",
|
|
8271
8256
|
name: "proceed",
|
|
@@ -8296,7 +8281,7 @@ async function cleanCommand(opts = {}) {
|
|
|
8296
8281
|
}
|
|
8297
8282
|
if (!opts.yes && config) {
|
|
8298
8283
|
console.log("");
|
|
8299
|
-
const { reinit } = await
|
|
8284
|
+
const { reinit } = await inquirer3.prompt([
|
|
8300
8285
|
{
|
|
8301
8286
|
type: "confirm",
|
|
8302
8287
|
name: "reinit",
|
|
@@ -8386,7 +8371,7 @@ import { fileURLToPath as fileURLToPath4 } from "url";
|
|
|
8386
8371
|
import { readFile as readFile20 } from "fs/promises";
|
|
8387
8372
|
import { dirname as dirname12, join as join23 } from "path";
|
|
8388
8373
|
import chalk8 from "chalk";
|
|
8389
|
-
import
|
|
8374
|
+
import inquirer5 from "inquirer";
|
|
8390
8375
|
init_content();
|
|
8391
8376
|
init_agentsContent();
|
|
8392
8377
|
init_safeWrite();
|
|
@@ -8452,7 +8437,7 @@ async function configCommand() {
|
|
|
8452
8437
|
`This repo is managed by workspace at ${wsContext.workspaceRoot}. Changes here may be overwritten on next workspace sync.`
|
|
8453
8438
|
);
|
|
8454
8439
|
console.log();
|
|
8455
|
-
const { action } = await
|
|
8440
|
+
const { action } = await inquirer5.prompt([
|
|
8456
8441
|
{
|
|
8457
8442
|
type: "select",
|
|
8458
8443
|
name: "action",
|
|
@@ -8484,7 +8469,7 @@ async function configCommand() {
|
|
|
8484
8469
|
}
|
|
8485
8470
|
printCurrentConfig(manifest);
|
|
8486
8471
|
const wslTheme = isWSL() ? { icon: { checked: chalk8.green("[x]"), unchecked: "[ ]", cursor: ">" } } : void 0;
|
|
8487
|
-
const platformAnswer = await
|
|
8472
|
+
const platformAnswer = await inquirer5.prompt([
|
|
8488
8473
|
{
|
|
8489
8474
|
type: "select",
|
|
8490
8475
|
name: "platform",
|
|
@@ -8503,7 +8488,7 @@ async function configCommand() {
|
|
|
8503
8488
|
let namespace;
|
|
8504
8489
|
let project;
|
|
8505
8490
|
if (platform === "azure-devops") {
|
|
8506
|
-
const adoAnswers = await
|
|
8491
|
+
const adoAnswers = await inquirer5.prompt([
|
|
8507
8492
|
{ type: "input", name: "org", message: "Azure DevOps organization:", default: manifest.owner || void 0 },
|
|
8508
8493
|
{ type: "input", name: "project", message: "Azure DevOps project:", default: manifest.project || void 0 },
|
|
8509
8494
|
{ type: "input", name: "repo", message: "Repository name:", default: manifest.repo || void 0 }
|
|
@@ -8513,7 +8498,7 @@ async function configCommand() {
|
|
|
8513
8498
|
namespace = owner;
|
|
8514
8499
|
project = sanitizeInput(adoAnswers.project);
|
|
8515
8500
|
} else if (platform === "gitlab") {
|
|
8516
|
-
const glAnswers = await
|
|
8501
|
+
const glAnswers = await inquirer5.prompt([
|
|
8517
8502
|
{ type: "input", name: "namespace", message: "GitLab namespace (group or username):", default: manifest.namespace || manifest.owner || void 0 },
|
|
8518
8503
|
{ type: "input", name: "project", message: "Project name:", default: manifest.project || manifest.repo || void 0 }
|
|
8519
8504
|
]);
|
|
@@ -8522,7 +8507,7 @@ async function configCommand() {
|
|
|
8522
8507
|
namespace = owner;
|
|
8523
8508
|
project = repo;
|
|
8524
8509
|
} else {
|
|
8525
|
-
const repoAnswers = await
|
|
8510
|
+
const repoAnswers = await inquirer5.prompt([
|
|
8526
8511
|
{ type: "input", name: "owner", message: "GitHub owner (org or username):", default: manifest.owner || void 0 },
|
|
8527
8512
|
{ type: "input", name: "repo", message: "Repository name:", default: manifest.repo || void 0 }
|
|
8528
8513
|
]);
|
|
@@ -8532,7 +8517,7 @@ async function configCommand() {
|
|
|
8532
8517
|
project = repo;
|
|
8533
8518
|
}
|
|
8534
8519
|
const currentBranch = manifest.board?.defaultBranch ?? "main";
|
|
8535
|
-
const branchAnswer = await
|
|
8520
|
+
const branchAnswer = await inquirer5.prompt([
|
|
8536
8521
|
{
|
|
8537
8522
|
type: "input",
|
|
8538
8523
|
name: "defaultBranch",
|
|
@@ -8541,7 +8526,7 @@ async function configCommand() {
|
|
|
8541
8526
|
}
|
|
8542
8527
|
]);
|
|
8543
8528
|
const defaultBranch = branchAnswer.defaultBranch.trim() || currentBranch;
|
|
8544
|
-
const toolAnswers = await
|
|
8529
|
+
const toolAnswers = await inquirer5.prompt([
|
|
8545
8530
|
{
|
|
8546
8531
|
type: "checkbox",
|
|
8547
8532
|
name: "tools",
|
|
@@ -8557,7 +8542,7 @@ async function configCommand() {
|
|
|
8557
8542
|
throw new HatchError("At least one tool must be selected.", 1, "VALIDATION_ERROR");
|
|
8558
8543
|
}
|
|
8559
8544
|
const currentFeatureKeys = Object.keys(DEFAULT_FEATURES).filter((k) => manifest.features[k]);
|
|
8560
|
-
const featureAnswers = await
|
|
8545
|
+
const featureAnswers = await inquirer5.prompt([
|
|
8561
8546
|
{
|
|
8562
8547
|
type: "checkbox",
|
|
8563
8548
|
name: "features",
|
|
@@ -8575,7 +8560,7 @@ async function configCommand() {
|
|
|
8575
8560
|
let mcpServers = [];
|
|
8576
8561
|
if (features.mcp) {
|
|
8577
8562
|
const platformMcp = PLATFORM_MCP_SERVER[platform];
|
|
8578
|
-
const mcpAnswers = await
|
|
8563
|
+
const mcpAnswers = await inquirer5.prompt([
|
|
8579
8564
|
{
|
|
8580
8565
|
type: "checkbox",
|
|
8581
8566
|
name: "mcp",
|
|
@@ -8592,7 +8577,7 @@ async function configCommand() {
|
|
|
8592
8577
|
}
|
|
8593
8578
|
const hasWorktreeTool = tools.some((t) => WORKTREE_CAPABLE_TOOLS.has(t));
|
|
8594
8579
|
if (hasWorktreeTool) {
|
|
8595
|
-
const wtAnswer = await
|
|
8580
|
+
const wtAnswer = await inquirer5.prompt([{
|
|
8596
8581
|
type: "confirm",
|
|
8597
8582
|
name: "enabled",
|
|
8598
8583
|
message: "Enable worktree file isolation (for parallel agent sessions)?",
|
|
@@ -8604,147 +8589,126 @@ async function configCommand() {
|
|
|
8604
8589
|
};
|
|
8605
8590
|
}
|
|
8606
8591
|
const contentChanges = { added: [], removed: [] };
|
|
8592
|
+
let contentMetadataChanged = false;
|
|
8607
8593
|
if (manifest.content) {
|
|
8608
|
-
|
|
8594
|
+
info(
|
|
8595
|
+
chalk8.dim("Config adds/removes content items. To customize an item's behavior without ") + chalk8.dim("removing it, use .hatch3r/<type>/<id>.customize.yaml instead.")
|
|
8596
|
+
);
|
|
8597
|
+
console.log();
|
|
8598
|
+
const contentRoot = findPackageRoot(__dirname4);
|
|
8599
|
+
const agentsDir = join23(rootDir, AGENTS_DIR);
|
|
8600
|
+
const index = await buildContentIndex(contentRoot);
|
|
8601
|
+
const previousContent = manifest.content;
|
|
8602
|
+
const { projectType, teamSize } = manifest.content;
|
|
8603
|
+
const totalItems = index.items.length;
|
|
8604
|
+
const presetAnswer = await inquirer5.prompt([
|
|
8609
8605
|
{
|
|
8610
|
-
type: "
|
|
8611
|
-
name: "
|
|
8612
|
-
message: "
|
|
8613
|
-
|
|
8606
|
+
type: "select",
|
|
8607
|
+
name: "preset",
|
|
8608
|
+
message: "Select content profile:",
|
|
8609
|
+
choices: PRESETS.map((p) => {
|
|
8610
|
+
const excluded = countPresetExclusions(p, index);
|
|
8611
|
+
const estimated = p.id !== "custom" ? estimatePresetItemCount(p, projectType, teamSize, index, void 0, { skipContextFilters: true }) : 0;
|
|
8612
|
+
const countHint = estimated > 0 ? ` (~${estimated} items)` : "";
|
|
8613
|
+
const suffix = excluded > 0 ? ` (excludes ${excluded} of ${totalItems})` : "";
|
|
8614
|
+
return {
|
|
8615
|
+
name: `${p.name} \u2014 ${p.description}${countHint}${suffix}`,
|
|
8616
|
+
value: p.id
|
|
8617
|
+
};
|
|
8618
|
+
}),
|
|
8619
|
+
default: manifest.content.preset
|
|
8614
8620
|
}
|
|
8615
8621
|
]);
|
|
8616
|
-
|
|
8617
|
-
|
|
8618
|
-
|
|
8619
|
-
);
|
|
8620
|
-
|
|
8621
|
-
const
|
|
8622
|
-
const agentsDir = join23(rootDir, AGENTS_DIR);
|
|
8623
|
-
const index = await buildContentIndex(contentRoot);
|
|
8624
|
-
const currentIds = /* @__PURE__ */ new Set();
|
|
8625
|
-
for (const ids of Object.values(manifest.content.items)) {
|
|
8626
|
-
for (const id of ids) currentIds.add(id);
|
|
8627
|
-
}
|
|
8628
|
-
const contentAnswer = await inquirer4.prompt([
|
|
8622
|
+
const selectedPreset = getPreset(presetAnswer.preset);
|
|
8623
|
+
let customSelections;
|
|
8624
|
+
if (selectedPreset.id === "custom") {
|
|
8625
|
+
const currentIds = getAllContentIds(manifest.content);
|
|
8626
|
+
const groupedChoices = buildTagGroupedCustomContentChoices(index.items, (item) => currentIds.has(item.id));
|
|
8627
|
+
const customAnswer = await inquirer5.prompt([
|
|
8629
8628
|
{
|
|
8630
8629
|
type: "checkbox",
|
|
8631
8630
|
name: "items",
|
|
8632
|
-
message: "Select content items
|
|
8633
|
-
choices:
|
|
8634
|
-
name: `${item.type}: ${item.id.replace(/^(cmd-)?hatch3r-/, "")} \u2014 ${item.description.slice(0, 60)}`,
|
|
8635
|
-
value: item.id,
|
|
8636
|
-
checked: currentIds.has(item.id)
|
|
8637
|
-
})),
|
|
8631
|
+
message: "Select content items:",
|
|
8632
|
+
choices: groupedChoices,
|
|
8638
8633
|
...wslTheme && { theme: wslTheme }
|
|
8639
8634
|
}
|
|
8640
8635
|
]);
|
|
8641
|
-
|
|
8642
|
-
|
|
8643
|
-
|
|
8644
|
-
|
|
8645
|
-
|
|
8646
|
-
|
|
8647
|
-
|
|
8648
|
-
|
|
8649
|
-
|
|
8650
|
-
|
|
8651
|
-
|
|
8652
|
-
|
|
8653
|
-
|
|
8654
|
-
|
|
8655
|
-
|
|
8656
|
-
|
|
8657
|
-
|
|
8658
|
-
|
|
8659
|
-
|
|
8660
|
-
|
|
8636
|
+
customSelections = customAnswer.items;
|
|
8637
|
+
}
|
|
8638
|
+
const newSelection = resolveSelection(selectedPreset, projectType, teamSize, index, customSelections, void 0, { skipContextFilters: true });
|
|
8639
|
+
const oldIds = getAllContentIds(manifest.content);
|
|
8640
|
+
const newIds = getAllContentIds(newSelection);
|
|
8641
|
+
const pendingRemovals = [];
|
|
8642
|
+
for (const id of oldIds) {
|
|
8643
|
+
if (!newIds.has(id)) pendingRemovals.push(id);
|
|
8644
|
+
}
|
|
8645
|
+
if (pendingRemovals.length > 0) {
|
|
8646
|
+
const dependencyWarnings = [];
|
|
8647
|
+
for (const removedId of pendingRemovals) {
|
|
8648
|
+
const dependents = [];
|
|
8649
|
+
for (const keepId of newIds) {
|
|
8650
|
+
const keepItem = index.byId.get(keepId);
|
|
8651
|
+
if (!keepItem) continue;
|
|
8652
|
+
try {
|
|
8653
|
+
const filePath = keepItem.type === "skill" ? join23(agentsDir, keepItem.relativePath, "SKILL.md") : join23(agentsDir, keepItem.relativePath);
|
|
8654
|
+
const content = await readFile20(filePath, "utf-8");
|
|
8655
|
+
const refs = extractContentReferences(content);
|
|
8656
|
+
if (refs.includes(removedId)) {
|
|
8657
|
+
dependents.push(keepId);
|
|
8661
8658
|
}
|
|
8662
|
-
}
|
|
8663
|
-
if (dependents.length > 0) {
|
|
8664
|
-
dependencyWarnings.push(
|
|
8665
|
-
`Removing "${removedId}" \u2014 referenced by: ${dependents.join(", ")}`
|
|
8666
|
-
);
|
|
8667
|
-
}
|
|
8668
|
-
}
|
|
8669
|
-
const proposedSelection = {
|
|
8670
|
-
...manifest.content,
|
|
8671
|
-
items: {
|
|
8672
|
-
agents: [],
|
|
8673
|
-
skills: [],
|
|
8674
|
-
rules: [],
|
|
8675
|
-
commands: [],
|
|
8676
|
-
prompts: [],
|
|
8677
|
-
hooks: [],
|
|
8678
|
-
githubAgents: []
|
|
8679
|
-
}
|
|
8680
|
-
};
|
|
8681
|
-
for (const id of contentAnswer.items) {
|
|
8682
|
-
const proposedItem = index.byId.get(id);
|
|
8683
|
-
if (proposedItem) {
|
|
8684
|
-
const key = TYPE_TO_SELECTION_KEY[proposedItem.type];
|
|
8685
|
-
if (key) proposedSelection.items[key].push(proposedItem.id);
|
|
8659
|
+
} catch {
|
|
8686
8660
|
}
|
|
8687
8661
|
}
|
|
8688
|
-
|
|
8689
|
-
|
|
8690
|
-
|
|
8691
|
-
|
|
8692
|
-
warn("Dependency warnings for removed content:");
|
|
8693
|
-
for (const w of dependencyWarnings) {
|
|
8694
|
-
console.log(chalk8.dim(` ${w}`));
|
|
8695
|
-
}
|
|
8696
|
-
console.log();
|
|
8662
|
+
if (dependents.length > 0) {
|
|
8663
|
+
dependencyWarnings.push(
|
|
8664
|
+
`Removing "${removedId}" \u2014 referenced by: ${dependents.join(", ")}`
|
|
8665
|
+
);
|
|
8697
8666
|
}
|
|
8698
8667
|
}
|
|
8699
|
-
|
|
8700
|
-
|
|
8701
|
-
|
|
8702
|
-
|
|
8703
|
-
|
|
8704
|
-
|
|
8705
|
-
}
|
|
8668
|
+
const orchWarnings = validateOrchestrationDependencies(newSelection);
|
|
8669
|
+
dependencyWarnings.push(...orchWarnings);
|
|
8670
|
+
if (dependencyWarnings.length > 0) {
|
|
8671
|
+
console.log();
|
|
8672
|
+
warn("Dependency warnings for removed content:");
|
|
8673
|
+
for (const w of dependencyWarnings) {
|
|
8674
|
+
console.log(chalk8.dim(` ${w}`));
|
|
8706
8675
|
}
|
|
8676
|
+
console.log();
|
|
8707
8677
|
}
|
|
8708
|
-
|
|
8709
|
-
|
|
8710
|
-
|
|
8711
|
-
|
|
8712
|
-
|
|
8713
|
-
|
|
8714
|
-
|
|
8678
|
+
}
|
|
8679
|
+
for (const id of newIds) {
|
|
8680
|
+
if (!oldIds.has(id)) {
|
|
8681
|
+
const item = index.byId.get(id);
|
|
8682
|
+
if (item) {
|
|
8683
|
+
contentChanges.added.push({ type: item.type, id: item.id });
|
|
8684
|
+
await addContentItem(contentRoot, agentsDir, item);
|
|
8715
8685
|
}
|
|
8716
8686
|
}
|
|
8717
|
-
|
|
8718
|
-
|
|
8719
|
-
|
|
8720
|
-
rules: [],
|
|
8721
|
-
commands: [],
|
|
8722
|
-
prompts: [],
|
|
8723
|
-
hooks: [],
|
|
8724
|
-
githubAgents: []
|
|
8725
|
-
};
|
|
8726
|
-
for (const id of contentAnswer.items) {
|
|
8687
|
+
}
|
|
8688
|
+
for (const id of oldIds) {
|
|
8689
|
+
if (!newIds.has(id)) {
|
|
8727
8690
|
const item = index.byId.get(id);
|
|
8728
8691
|
if (item) {
|
|
8729
|
-
|
|
8730
|
-
|
|
8692
|
+
contentChanges.removed.push({ type: item.type, id: item.id });
|
|
8693
|
+
await removeContentItem(agentsDir, item, { rootDir });
|
|
8731
8694
|
}
|
|
8732
8695
|
}
|
|
8733
|
-
|
|
8734
|
-
|
|
8735
|
-
|
|
8736
|
-
|
|
8737
|
-
|
|
8738
|
-
|
|
8739
|
-
|
|
8740
|
-
|
|
8741
|
-
|
|
8696
|
+
}
|
|
8697
|
+
manifest.content = newSelection;
|
|
8698
|
+
contentMetadataChanged = previousContent.preset !== newSelection.preset || previousContent.projectType !== newSelection.projectType || previousContent.teamSize !== newSelection.teamSize;
|
|
8699
|
+
if (contentChanges.added.length > 0 || contentChanges.removed.length > 0) {
|
|
8700
|
+
const canonicalAgentsMd = await generateCanonicalAgentsMd(agentsDir);
|
|
8701
|
+
await safeWriteFile(join23(agentsDir, "AGENTS.md"), canonicalAgentsMd);
|
|
8702
|
+
const rootAgentsMd = await generateRootAgentsMd(agentsDir);
|
|
8703
|
+
await safeWriteFile(join23(rootDir, "AGENTS.md"), rootAgentsMd.full, {
|
|
8704
|
+
managedContent: rootAgentsMd.inner
|
|
8705
|
+
});
|
|
8742
8706
|
}
|
|
8743
8707
|
}
|
|
8744
8708
|
const diff = computeDiff(manifest, tools, features, mcpServers, platform, owner, repo, namespace, project);
|
|
8745
8709
|
diff.addedContent = contentChanges.added;
|
|
8746
8710
|
diff.removedContent = contentChanges.removed;
|
|
8747
|
-
if (isDiffEmpty(diff) && defaultBranch === currentBranch) {
|
|
8711
|
+
if (isDiffEmpty(diff) && defaultBranch === currentBranch && !contentMetadataChanged) {
|
|
8748
8712
|
console.log();
|
|
8749
8713
|
info("No changes detected.");
|
|
8750
8714
|
console.log();
|
|
@@ -8905,7 +8869,7 @@ async function configCommand() {
|
|
|
8905
8869
|
const currentRepos = wsManifestFinal.repos.map((r) => r.path);
|
|
8906
8870
|
console.log(chalk8.dim(` Repos: ${currentRepos.join(", ") || "(none)"}`));
|
|
8907
8871
|
console.log(chalk8.dim(` Sync strategy: ${wsManifestFinal.syncStrategy}`));
|
|
8908
|
-
const { manageWorkspace } = await
|
|
8872
|
+
const { manageWorkspace } = await inquirer5.prompt([
|
|
8909
8873
|
{
|
|
8910
8874
|
type: "confirm",
|
|
8911
8875
|
name: "manageWorkspace",
|
|
@@ -8918,7 +8882,7 @@ async function configCommand() {
|
|
|
8918
8882
|
const existingPaths = new Set(wsManifestFinal.repos.map((r) => r.path));
|
|
8919
8883
|
const newRepos = detectedRepos.filter((r) => !existingPaths.has(r.path));
|
|
8920
8884
|
if (newRepos.length > 0) {
|
|
8921
|
-
const { addRepos } = await
|
|
8885
|
+
const { addRepos } = await inquirer5.prompt([
|
|
8922
8886
|
{
|
|
8923
8887
|
type: "checkbox",
|
|
8924
8888
|
name: "addRepos",
|
|
@@ -8936,7 +8900,7 @@ async function configCommand() {
|
|
|
8936
8900
|
}
|
|
8937
8901
|
}
|
|
8938
8902
|
if (wsManifestFinal.repos.length > 0) {
|
|
8939
|
-
const { syncRepos } = await
|
|
8903
|
+
const { syncRepos } = await inquirer5.prompt([
|
|
8940
8904
|
{
|
|
8941
8905
|
type: "checkbox",
|
|
8942
8906
|
name: "syncRepos",
|
|
@@ -8955,7 +8919,7 @@ async function configCommand() {
|
|
|
8955
8919
|
}
|
|
8956
8920
|
}
|
|
8957
8921
|
if (wsManifestFinal.repos.length > 0) {
|
|
8958
|
-
const { editIdentity } = await
|
|
8922
|
+
const { editIdentity } = await inquirer5.prompt([
|
|
8959
8923
|
{
|
|
8960
8924
|
type: "select",
|
|
8961
8925
|
name: "editIdentity",
|
|
@@ -8981,7 +8945,7 @@ async function configCommand() {
|
|
|
8981
8945
|
for (const repo2 of wsManifestFinal.repos) {
|
|
8982
8946
|
console.log(chalk8.bold(`
|
|
8983
8947
|
${repo2.name ?? repo2.path}:`));
|
|
8984
|
-
const identity = await
|
|
8948
|
+
const identity = await inquirer5.prompt([
|
|
8985
8949
|
{ type: "input", name: "owner", message: " Owner:", default: repo2.owner || void 0 },
|
|
8986
8950
|
{ type: "input", name: "repo", message: " Repo:", default: repo2.repo || void 0 },
|
|
8987
8951
|
{ type: "input", name: "defaultBranch", message: " Default branch:", default: repo2.defaultBranch || "main" }
|
|
@@ -8992,7 +8956,7 @@ async function configCommand() {
|
|
|
8992
8956
|
}
|
|
8993
8957
|
}
|
|
8994
8958
|
}
|
|
8995
|
-
const { strategy } = await
|
|
8959
|
+
const { strategy } = await inquirer5.prompt([
|
|
8996
8960
|
{
|
|
8997
8961
|
type: "select",
|
|
8998
8962
|
name: "strategy",
|
|
@@ -9008,7 +8972,7 @@ async function configCommand() {
|
|
|
9008
8972
|
await writeWorkspaceManifest(rootDir, wsManifestFinal);
|
|
9009
8973
|
const syncCount = wsManifestFinal.repos.filter((r) => r.sync).length;
|
|
9010
8974
|
if (syncCount > 0) {
|
|
9011
|
-
const { syncNow } = await
|
|
8975
|
+
const { syncNow } = await inquirer5.prompt([
|
|
9012
8976
|
{
|
|
9013
8977
|
type: "confirm",
|
|
9014
8978
|
name: "syncNow",
|
|
@@ -10814,7 +10778,7 @@ program.name("hatch3r").description(
|
|
|
10814
10778
|
program.command("init").description("Install a complete agent setup into the current repo (first-run: creates .agents/ directory)").option(
|
|
10815
10779
|
"--tools <tools>",
|
|
10816
10780
|
`Comma-separated tools (${TOOL_CHOICES})`
|
|
10817
|
-
).option("--yes", "Skip interactive prompts, use defaults").option("--preset <preset>", "Content preset: minimal, standard, full (default:
|
|
10781
|
+
).option("--yes", "Skip interactive prompts, use defaults").option("--preset <preset>", "Content preset: minimal, standard, full (default: full)").option("--project-type <type>", "Project type: greenfield, brownfield").option("--team-size <size>", "Team size: solo, team").option("--workspace", "Initialize as a multi-repo workspace").action(initCommand);
|
|
10818
10782
|
program.command("sync").description("Re-generate tool outputs from canonical .agents/ state (run after editing .agents/)").option("--repos [paths...]", "Sync workspace content to sub-repos (all opted-in if no paths given)").option("--dry-run", "Show what would change without modifying files").option("--diff", "Show a before/after diff summary for each generated file").option("--force", "Overwrite locally modified files in sub-repos").option("--minimal", "Generate stripped-down output (no comments, minimal formatting) to reduce token usage").option("--verbose", "Show detailed output for each file processed").action(syncCommand);
|
|
10819
10783
|
program.command("status").description("Check sync status between canonical .agents/ and generated files").option("--verbose", "Show detailed per-file status information").action(statusCommand);
|
|
10820
10784
|
program.command("update").description("Pull latest hatch3r templates with safe merge (preserves customizations)").option("--yes", "Skip interactive prompts, use defaults").option("--diff", "Show a before/after diff summary for each generated file").action(updateCommand);
|