@qazuor/claude-code-config 0.2.0 → 0.3.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.
- package/dist/bin.cjs +2426 -1792
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +2426 -1792
- package/dist/bin.js.map +1 -1
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -7647,6 +7647,304 @@ function cleanup() {
|
|
|
7647
7647
|
stopEscListener();
|
|
7648
7648
|
}
|
|
7649
7649
|
|
|
7650
|
+
// src/lib/wizard/index.ts
|
|
7651
|
+
init_esm_shims();
|
|
7652
|
+
|
|
7653
|
+
// src/lib/wizard/step.ts
|
|
7654
|
+
init_esm_shims();
|
|
7655
|
+
function createStepState(definition, index) {
|
|
7656
|
+
return {
|
|
7657
|
+
metadata: {
|
|
7658
|
+
...definition.metadata,
|
|
7659
|
+
index
|
|
7660
|
+
},
|
|
7661
|
+
status: index === 0 ? "current" : "pending",
|
|
7662
|
+
value: void 0,
|
|
7663
|
+
history: [],
|
|
7664
|
+
isModified: false
|
|
7665
|
+
};
|
|
7666
|
+
}
|
|
7667
|
+
function recordStepHistory(state, value, exitDirection) {
|
|
7668
|
+
const entry = {
|
|
7669
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
7670
|
+
value,
|
|
7671
|
+
exitDirection,
|
|
7672
|
+
visitCount: state.history.length + 1
|
|
7673
|
+
};
|
|
7674
|
+
return {
|
|
7675
|
+
...state,
|
|
7676
|
+
value,
|
|
7677
|
+
history: [...state.history, entry],
|
|
7678
|
+
isModified: true
|
|
7679
|
+
};
|
|
7680
|
+
}
|
|
7681
|
+
function shouldSkipStep(definition, context) {
|
|
7682
|
+
return definition.skipCondition?.(context) ?? false;
|
|
7683
|
+
}
|
|
7684
|
+
|
|
7685
|
+
// src/lib/wizard/navigator.ts
|
|
7686
|
+
init_esm_shims();
|
|
7687
|
+
import { Separator } from "@inquirer/prompts";
|
|
7688
|
+
var BACK_OPTION_VALUE = "__wizard_back__";
|
|
7689
|
+
function calculateNextStep(state, direction) {
|
|
7690
|
+
const currentIndex = state.stepOrder.indexOf(state.currentStepId);
|
|
7691
|
+
const totalSteps = state.stepOrder.length;
|
|
7692
|
+
switch (direction) {
|
|
7693
|
+
case "next": {
|
|
7694
|
+
if (currentIndex >= totalSteps - 1) {
|
|
7695
|
+
return {
|
|
7696
|
+
nextStepId: null,
|
|
7697
|
+
currentStepNewStatus: "completed"
|
|
7698
|
+
};
|
|
7699
|
+
}
|
|
7700
|
+
return {
|
|
7701
|
+
nextStepId: state.stepOrder[currentIndex + 1],
|
|
7702
|
+
currentStepNewStatus: "completed"
|
|
7703
|
+
};
|
|
7704
|
+
}
|
|
7705
|
+
case "back": {
|
|
7706
|
+
if (currentIndex <= 0) {
|
|
7707
|
+
return {
|
|
7708
|
+
nextStepId: state.currentStepId,
|
|
7709
|
+
currentStepNewStatus: "current"
|
|
7710
|
+
};
|
|
7711
|
+
}
|
|
7712
|
+
return {
|
|
7713
|
+
nextStepId: state.stepOrder[currentIndex - 1],
|
|
7714
|
+
currentStepNewStatus: "pending"
|
|
7715
|
+
};
|
|
7716
|
+
}
|
|
7717
|
+
case "skip": {
|
|
7718
|
+
if (currentIndex >= totalSteps - 1) {
|
|
7719
|
+
return {
|
|
7720
|
+
nextStepId: null,
|
|
7721
|
+
currentStepNewStatus: "skipped"
|
|
7722
|
+
};
|
|
7723
|
+
}
|
|
7724
|
+
return {
|
|
7725
|
+
nextStepId: state.stepOrder[currentIndex + 1],
|
|
7726
|
+
currentStepNewStatus: "skipped"
|
|
7727
|
+
};
|
|
7728
|
+
}
|
|
7729
|
+
case "cancel": {
|
|
7730
|
+
return {
|
|
7731
|
+
nextStepId: null,
|
|
7732
|
+
currentStepNewStatus: "pending"
|
|
7733
|
+
};
|
|
7734
|
+
}
|
|
7735
|
+
}
|
|
7736
|
+
}
|
|
7737
|
+
function applyNavigation(state, direction, currentValue) {
|
|
7738
|
+
const { nextStepId, currentStepNewStatus } = calculateNextStep(state, direction);
|
|
7739
|
+
const currentStepState = state.steps[state.currentStepId];
|
|
7740
|
+
const updatedCurrentStep = {
|
|
7741
|
+
...currentStepState,
|
|
7742
|
+
status: currentStepNewStatus,
|
|
7743
|
+
value: currentValue
|
|
7744
|
+
};
|
|
7745
|
+
const updatedSteps = {
|
|
7746
|
+
...state.steps,
|
|
7747
|
+
[state.currentStepId]: updatedCurrentStep
|
|
7748
|
+
};
|
|
7749
|
+
if (nextStepId === null) {
|
|
7750
|
+
return {
|
|
7751
|
+
...state,
|
|
7752
|
+
steps: updatedSteps,
|
|
7753
|
+
isComplete: direction === "next" || direction === "skip",
|
|
7754
|
+
isCancelled: direction === "cancel"
|
|
7755
|
+
};
|
|
7756
|
+
}
|
|
7757
|
+
const nextStepState = state.steps[nextStepId];
|
|
7758
|
+
const updatedNextStep = {
|
|
7759
|
+
...nextStepState,
|
|
7760
|
+
status: "current"
|
|
7761
|
+
};
|
|
7762
|
+
return {
|
|
7763
|
+
...state,
|
|
7764
|
+
steps: {
|
|
7765
|
+
...updatedSteps,
|
|
7766
|
+
[nextStepId]: updatedNextStep
|
|
7767
|
+
},
|
|
7768
|
+
currentStepId: nextStepId
|
|
7769
|
+
};
|
|
7770
|
+
}
|
|
7771
|
+
async function promptKeepOrReconfigure(stepName) {
|
|
7772
|
+
logger.newline();
|
|
7773
|
+
const result = await select({
|
|
7774
|
+
message: `"${stepName}" was already configured. What would you like to do?`,
|
|
7775
|
+
choices: [
|
|
7776
|
+
{
|
|
7777
|
+
name: "Keep current values and continue",
|
|
7778
|
+
value: "keep",
|
|
7779
|
+
description: "Skip this step and proceed to the next one"
|
|
7780
|
+
},
|
|
7781
|
+
{
|
|
7782
|
+
name: "Re-configure this step",
|
|
7783
|
+
value: "reconfigure",
|
|
7784
|
+
description: "Show the prompts again with your previous values as defaults"
|
|
7785
|
+
}
|
|
7786
|
+
],
|
|
7787
|
+
default: "keep"
|
|
7788
|
+
});
|
|
7789
|
+
return result;
|
|
7790
|
+
}
|
|
7791
|
+
function showStepProgress(state, isRevisit) {
|
|
7792
|
+
if (!state.metadata.showProgress) {
|
|
7793
|
+
return;
|
|
7794
|
+
}
|
|
7795
|
+
const currentIndex = state.stepOrder.indexOf(state.currentStepId);
|
|
7796
|
+
const total = state.metadata.totalSteps;
|
|
7797
|
+
const currentStep = state.steps[state.currentStepId];
|
|
7798
|
+
const progressChars = state.stepOrder.map((_stepId, idx) => {
|
|
7799
|
+
if (idx < currentIndex) {
|
|
7800
|
+
return colors.success("\u25CF");
|
|
7801
|
+
}
|
|
7802
|
+
if (idx === currentIndex) {
|
|
7803
|
+
return colors.primary("\u25C9");
|
|
7804
|
+
}
|
|
7805
|
+
return colors.muted("\u25CB");
|
|
7806
|
+
});
|
|
7807
|
+
const progressBar = progressChars.join(" ");
|
|
7808
|
+
const stepIndicator = `[${currentIndex + 1}/${total}]`;
|
|
7809
|
+
const revisitBadge = isRevisit ? colors.warning(" (revisiting)") : "";
|
|
7810
|
+
logger.newline();
|
|
7811
|
+
logger.info(`${colors.muted(stepIndicator)} ${progressBar}${revisitBadge}`);
|
|
7812
|
+
logger.subtitle(currentStep.metadata.name);
|
|
7813
|
+
if (currentStep.metadata.description) {
|
|
7814
|
+
logger.info(colors.muted(currentStep.metadata.description));
|
|
7815
|
+
}
|
|
7816
|
+
}
|
|
7817
|
+
|
|
7818
|
+
// src/lib/wizard/history.ts
|
|
7819
|
+
init_esm_shims();
|
|
7820
|
+
function getLastValue(stepState) {
|
|
7821
|
+
if (stepState.history.length === 0) {
|
|
7822
|
+
return stepState.value;
|
|
7823
|
+
}
|
|
7824
|
+
return stepState.history[stepState.history.length - 1].value;
|
|
7825
|
+
}
|
|
7826
|
+
function wasStepCompleted(stepState) {
|
|
7827
|
+
return stepState.status === "completed" || stepState.history.length > 0;
|
|
7828
|
+
}
|
|
7829
|
+
|
|
7830
|
+
// src/lib/wizard/engine.ts
|
|
7831
|
+
init_esm_shims();
|
|
7832
|
+
function createWizardState(config) {
|
|
7833
|
+
const stepOrder = config.steps.map((s) => s.id);
|
|
7834
|
+
const steps = {};
|
|
7835
|
+
for (let i = 0; i < config.steps.length; i++) {
|
|
7836
|
+
const step = config.steps[i];
|
|
7837
|
+
steps[step.id] = createStepState(step.definition, i);
|
|
7838
|
+
}
|
|
7839
|
+
const metadata = {
|
|
7840
|
+
id: config.id,
|
|
7841
|
+
title: config.title,
|
|
7842
|
+
totalSteps: config.steps.length,
|
|
7843
|
+
startTime: /* @__PURE__ */ new Date(),
|
|
7844
|
+
allowSkip: config.allowSkip ?? true,
|
|
7845
|
+
showProgress: config.showProgress ?? true
|
|
7846
|
+
};
|
|
7847
|
+
return {
|
|
7848
|
+
steps,
|
|
7849
|
+
currentStepId: stepOrder[0],
|
|
7850
|
+
stepOrder,
|
|
7851
|
+
isComplete: false,
|
|
7852
|
+
isCancelled: false,
|
|
7853
|
+
metadata
|
|
7854
|
+
};
|
|
7855
|
+
}
|
|
7856
|
+
async function runWizard(config, initialContext = {}) {
|
|
7857
|
+
let state = createWizardState(config);
|
|
7858
|
+
const stepMap = /* @__PURE__ */ new Map();
|
|
7859
|
+
for (const step of config.steps) {
|
|
7860
|
+
stepMap.set(step.id, step.definition);
|
|
7861
|
+
}
|
|
7862
|
+
let context = { ...initialContext };
|
|
7863
|
+
let movingForwardAfterBack = false;
|
|
7864
|
+
while (!state.isComplete && !state.isCancelled) {
|
|
7865
|
+
const currentStepId = state.currentStepId;
|
|
7866
|
+
const stepDef = stepMap.get(currentStepId);
|
|
7867
|
+
if (!stepDef) {
|
|
7868
|
+
throw new Error(`Step definition not found for: ${currentStepId}`);
|
|
7869
|
+
}
|
|
7870
|
+
const stepState = state.steps[currentStepId];
|
|
7871
|
+
if (shouldSkipStep(stepDef, context)) {
|
|
7872
|
+
state = applyNavigation(state, "skip", void 0);
|
|
7873
|
+
continue;
|
|
7874
|
+
}
|
|
7875
|
+
const previouslyCompleted = wasStepCompleted(stepState);
|
|
7876
|
+
if (movingForwardAfterBack && previouslyCompleted) {
|
|
7877
|
+
const action = await promptKeepOrReconfigure(stepState.metadata.name);
|
|
7878
|
+
if (action === "keep") {
|
|
7879
|
+
state = applyNavigation(state, "next", stepState.value);
|
|
7880
|
+
continue;
|
|
7881
|
+
}
|
|
7882
|
+
}
|
|
7883
|
+
const isRevisit = stepState.history.length > 0;
|
|
7884
|
+
showStepProgress(state, isRevisit);
|
|
7885
|
+
const previousValue = getLastValue(stepState);
|
|
7886
|
+
const defaults = previousValue ?? stepDef.computeDefaults(context);
|
|
7887
|
+
const result = await stepDef.execute(context, defaults);
|
|
7888
|
+
if (result.navigation !== "back") {
|
|
7889
|
+
context = {
|
|
7890
|
+
...context,
|
|
7891
|
+
[currentStepId]: result.value
|
|
7892
|
+
};
|
|
7893
|
+
const updatedStepState = recordStepHistory(stepState, result.value, result.navigation);
|
|
7894
|
+
state = {
|
|
7895
|
+
...state,
|
|
7896
|
+
steps: {
|
|
7897
|
+
...state.steps,
|
|
7898
|
+
[currentStepId]: updatedStepState
|
|
7899
|
+
}
|
|
7900
|
+
};
|
|
7901
|
+
}
|
|
7902
|
+
if (result.navigation === "back") {
|
|
7903
|
+
movingForwardAfterBack = false;
|
|
7904
|
+
} else if (result.navigation === "next") {
|
|
7905
|
+
movingForwardAfterBack = isRevisit || movingForwardAfterBack;
|
|
7906
|
+
}
|
|
7907
|
+
state = applyNavigation(state, result.navigation, result.value);
|
|
7908
|
+
}
|
|
7909
|
+
const values = {};
|
|
7910
|
+
for (const stepId of state.stepOrder) {
|
|
7911
|
+
const step = state.steps[stepId];
|
|
7912
|
+
if (step.value !== void 0) {
|
|
7913
|
+
values[stepId] = step.value;
|
|
7914
|
+
}
|
|
7915
|
+
}
|
|
7916
|
+
return {
|
|
7917
|
+
values,
|
|
7918
|
+
state,
|
|
7919
|
+
cancelled: state.isCancelled
|
|
7920
|
+
};
|
|
7921
|
+
}
|
|
7922
|
+
function showWizardSummary(state) {
|
|
7923
|
+
const completed = state.stepOrder.filter((id) => {
|
|
7924
|
+
const step = state.steps[id];
|
|
7925
|
+
return step.status === "completed";
|
|
7926
|
+
}).length;
|
|
7927
|
+
const skipped = state.stepOrder.filter((id) => {
|
|
7928
|
+
const step = state.steps[id];
|
|
7929
|
+
return step.status === "skipped";
|
|
7930
|
+
}).length;
|
|
7931
|
+
const revisited = state.stepOrder.filter((id) => {
|
|
7932
|
+
const step = state.steps[id];
|
|
7933
|
+
return step.history.length > 1;
|
|
7934
|
+
}).length;
|
|
7935
|
+
logger.newline();
|
|
7936
|
+
logger.success(`Wizard completed: ${completed} steps configured`);
|
|
7937
|
+
if (skipped > 0) {
|
|
7938
|
+
logger.info(` ${skipped} steps skipped`);
|
|
7939
|
+
}
|
|
7940
|
+
if (revisited > 0) {
|
|
7941
|
+
logger.info(` ${revisited} steps were reconfigured`);
|
|
7942
|
+
}
|
|
7943
|
+
}
|
|
7944
|
+
|
|
7945
|
+
// src/lib/wizard/init-steps.ts
|
|
7946
|
+
init_esm_shims();
|
|
7947
|
+
|
|
7650
7948
|
// src/cli/prompts/bundle-select.ts
|
|
7651
7949
|
init_esm_shims();
|
|
7652
7950
|
|
|
@@ -8086,111 +8384,541 @@ async function promptCICDConfig(options) {
|
|
|
8086
8384
|
};
|
|
8087
8385
|
}
|
|
8088
8386
|
|
|
8089
|
-
// src/cli/prompts/
|
|
8090
|
-
init_esm_shims();
|
|
8091
|
-
|
|
8092
|
-
// src/constants/folder-preferences.ts
|
|
8387
|
+
// src/cli/prompts/code-style.ts
|
|
8093
8388
|
init_esm_shims();
|
|
8094
|
-
var
|
|
8095
|
-
tests: {
|
|
8096
|
-
location: "test-folder-root",
|
|
8097
|
-
pattern: "*.test.ts"
|
|
8098
|
-
},
|
|
8099
|
-
planning: {
|
|
8100
|
-
location: "claude-sessions",
|
|
8101
|
-
commitToGit: false
|
|
8102
|
-
},
|
|
8103
|
-
docs: {
|
|
8104
|
-
location: "docs-root"
|
|
8105
|
-
},
|
|
8106
|
-
cicd: {
|
|
8107
|
-
location: "github-workflows",
|
|
8108
|
-
workflows: []
|
|
8109
|
-
}
|
|
8110
|
-
};
|
|
8111
|
-
var TEST_LOCATION_OPTIONS = [
|
|
8112
|
-
{
|
|
8113
|
-
value: "colocated",
|
|
8114
|
-
name: "Colocated with source files",
|
|
8115
|
-
description: "Tests next to source files (e.g., src/utils/foo.ts \u2192 src/utils/foo.test.ts). Good for small projects."
|
|
8116
|
-
},
|
|
8389
|
+
var CODE_STYLE_TOOLS = [
|
|
8117
8390
|
{
|
|
8118
|
-
|
|
8119
|
-
|
|
8120
|
-
description: "
|
|
8391
|
+
name: "EditorConfig",
|
|
8392
|
+
value: "editorconfig",
|
|
8393
|
+
description: "Consistent coding styles across editors",
|
|
8394
|
+
checked: true
|
|
8121
8395
|
},
|
|
8122
8396
|
{
|
|
8123
|
-
|
|
8124
|
-
|
|
8125
|
-
description: "
|
|
8126
|
-
|
|
8127
|
-
];
|
|
8128
|
-
var PLANNING_LOCATION_OPTIONS = [
|
|
8129
|
-
{
|
|
8130
|
-
value: "claude-sessions",
|
|
8131
|
-
name: ".claude/sessions/planning/ (Recommended)",
|
|
8132
|
-
description: "Planning files in .claude/sessions/planning/. Keeps Claude-specific files organized."
|
|
8397
|
+
name: "Commitlint",
|
|
8398
|
+
value: "commitlint",
|
|
8399
|
+
description: "Lint commit messages (conventional commits)",
|
|
8400
|
+
checked: true
|
|
8133
8401
|
},
|
|
8134
8402
|
{
|
|
8135
|
-
|
|
8136
|
-
|
|
8137
|
-
description: "
|
|
8403
|
+
name: "Biome",
|
|
8404
|
+
value: "biome",
|
|
8405
|
+
description: "Fast linter and formatter (ESLint + Prettier alternative)",
|
|
8406
|
+
checked: false
|
|
8138
8407
|
},
|
|
8139
8408
|
{
|
|
8140
|
-
|
|
8141
|
-
|
|
8142
|
-
description: "
|
|
8409
|
+
name: "Prettier",
|
|
8410
|
+
value: "prettier",
|
|
8411
|
+
description: "Code formatter (use if not using Biome)",
|
|
8412
|
+
checked: false
|
|
8143
8413
|
}
|
|
8144
8414
|
];
|
|
8145
|
-
|
|
8146
|
-
{
|
|
8147
|
-
|
|
8148
|
-
|
|
8149
|
-
|
|
8150
|
-
|
|
8151
|
-
|
|
8152
|
-
|
|
8153
|
-
|
|
8154
|
-
|
|
8155
|
-
|
|
8156
|
-
|
|
8157
|
-
|
|
8158
|
-
|
|
8159
|
-
|
|
8415
|
+
async function promptCodeStyleConfig(options) {
|
|
8416
|
+
logger.section("Code Style", "\u{1F3A8}");
|
|
8417
|
+
logger.info("Configure code formatting and linting tools");
|
|
8418
|
+
logger.newline();
|
|
8419
|
+
const enableCodeStyle = await confirm({
|
|
8420
|
+
message: "Would you like to install code style configuration files?",
|
|
8421
|
+
default: true
|
|
8422
|
+
});
|
|
8423
|
+
if (!enableCodeStyle) {
|
|
8424
|
+
return {
|
|
8425
|
+
enabled: false,
|
|
8426
|
+
editorconfig: false,
|
|
8427
|
+
commitlint: false,
|
|
8428
|
+
biome: false,
|
|
8429
|
+
prettier: false
|
|
8430
|
+
};
|
|
8160
8431
|
}
|
|
8161
|
-
|
|
8162
|
-
|
|
8163
|
-
|
|
8164
|
-
|
|
8165
|
-
|
|
8166
|
-
|
|
8167
|
-
|
|
8168
|
-
|
|
8169
|
-
|
|
8170
|
-
|
|
8171
|
-
|
|
8172
|
-
|
|
8173
|
-
|
|
8174
|
-
|
|
8175
|
-
|
|
8176
|
-
|
|
8432
|
+
const selectedTools = await checkbox({
|
|
8433
|
+
message: "Select the tools to configure:",
|
|
8434
|
+
choices: CODE_STYLE_TOOLS.map((tool) => ({
|
|
8435
|
+
name: `${tool.name} - ${tool.description}`,
|
|
8436
|
+
value: tool.value,
|
|
8437
|
+
checked: options?.defaults?.[tool.value] ?? tool.checked
|
|
8438
|
+
}))
|
|
8439
|
+
});
|
|
8440
|
+
if (selectedTools.includes("biome") && selectedTools.includes("prettier")) {
|
|
8441
|
+
logger.warn("Note: Both Biome and Prettier selected. Biome can replace Prettier.");
|
|
8442
|
+
const keepBoth = await confirm({
|
|
8443
|
+
message: "Keep both? (Prettier may conflict with Biome)",
|
|
8444
|
+
default: false
|
|
8445
|
+
});
|
|
8446
|
+
if (!keepBoth) {
|
|
8447
|
+
const preferred = await select({
|
|
8448
|
+
message: "Which formatter would you prefer?",
|
|
8449
|
+
choices: [
|
|
8450
|
+
{ name: "Biome (faster, all-in-one)", value: "biome" },
|
|
8451
|
+
{ name: "Prettier (more plugins)", value: "prettier" }
|
|
8452
|
+
]
|
|
8453
|
+
});
|
|
8454
|
+
const indexToRemove = preferred === "biome" ? selectedTools.indexOf("prettier") : selectedTools.indexOf("biome");
|
|
8455
|
+
if (indexToRemove > -1) {
|
|
8456
|
+
selectedTools.splice(indexToRemove, 1);
|
|
8457
|
+
}
|
|
8458
|
+
}
|
|
8177
8459
|
}
|
|
8178
|
-
|
|
8179
|
-
|
|
8180
|
-
|
|
8181
|
-
|
|
8182
|
-
|
|
8183
|
-
|
|
8184
|
-
|
|
8185
|
-
|
|
8186
|
-
|
|
8187
|
-
|
|
8188
|
-
|
|
8189
|
-
|
|
8190
|
-
|
|
8191
|
-
|
|
8192
|
-
|
|
8193
|
-
|
|
8460
|
+
if (selectedTools.length === 0) {
|
|
8461
|
+
return {
|
|
8462
|
+
enabled: false,
|
|
8463
|
+
editorconfig: false,
|
|
8464
|
+
commitlint: false,
|
|
8465
|
+
biome: false,
|
|
8466
|
+
prettier: false
|
|
8467
|
+
};
|
|
8468
|
+
}
|
|
8469
|
+
const customizeSettings = await confirm({
|
|
8470
|
+
message: "Would you like to customize code style settings? (No = use standard defaults)",
|
|
8471
|
+
default: false
|
|
8472
|
+
});
|
|
8473
|
+
let editorconfigOptions;
|
|
8474
|
+
let biomeOptions;
|
|
8475
|
+
let prettierOptions;
|
|
8476
|
+
let commitlintOptions;
|
|
8477
|
+
if (customizeSettings) {
|
|
8478
|
+
const hasFormatter = selectedTools.includes("editorconfig") || selectedTools.includes("biome") || selectedTools.includes("prettier");
|
|
8479
|
+
if (hasFormatter) {
|
|
8480
|
+
const preset = await promptStylePreset();
|
|
8481
|
+
if (preset !== "custom") {
|
|
8482
|
+
const presetConfig = CODE_STYLE_PRESETS[preset];
|
|
8483
|
+
if (selectedTools.includes("editorconfig")) {
|
|
8484
|
+
editorconfigOptions = presetConfig.editorconfig;
|
|
8485
|
+
}
|
|
8486
|
+
if (selectedTools.includes("biome") && presetConfig.biome) {
|
|
8487
|
+
biomeOptions = {
|
|
8488
|
+
...DEFAULT_BIOME_OPTIONS,
|
|
8489
|
+
formatter: presetConfig.biome
|
|
8490
|
+
};
|
|
8491
|
+
}
|
|
8492
|
+
if (selectedTools.includes("prettier") && presetConfig.prettier) {
|
|
8493
|
+
prettierOptions = presetConfig.prettier;
|
|
8494
|
+
}
|
|
8495
|
+
} else {
|
|
8496
|
+
if (selectedTools.includes("editorconfig")) {
|
|
8497
|
+
editorconfigOptions = await promptEditorConfigOptions();
|
|
8498
|
+
}
|
|
8499
|
+
if (selectedTools.includes("biome")) {
|
|
8500
|
+
biomeOptions = await promptBiomeOptions();
|
|
8501
|
+
}
|
|
8502
|
+
if (selectedTools.includes("prettier")) {
|
|
8503
|
+
prettierOptions = await promptPrettierOptions();
|
|
8504
|
+
}
|
|
8505
|
+
}
|
|
8506
|
+
}
|
|
8507
|
+
if (selectedTools.includes("commitlint")) {
|
|
8508
|
+
commitlintOptions = await promptCommitlintOptions();
|
|
8509
|
+
}
|
|
8510
|
+
} else {
|
|
8511
|
+
if (selectedTools.includes("editorconfig")) {
|
|
8512
|
+
editorconfigOptions = DEFAULT_EDITORCONFIG_OPTIONS;
|
|
8513
|
+
}
|
|
8514
|
+
if (selectedTools.includes("biome")) {
|
|
8515
|
+
biomeOptions = DEFAULT_BIOME_OPTIONS;
|
|
8516
|
+
}
|
|
8517
|
+
if (selectedTools.includes("prettier")) {
|
|
8518
|
+
prettierOptions = DEFAULT_PRETTIER_OPTIONS;
|
|
8519
|
+
}
|
|
8520
|
+
if (selectedTools.includes("commitlint")) {
|
|
8521
|
+
commitlintOptions = DEFAULT_COMMITLINT_OPTIONS;
|
|
8522
|
+
}
|
|
8523
|
+
}
|
|
8524
|
+
return {
|
|
8525
|
+
enabled: selectedTools.length > 0,
|
|
8526
|
+
editorconfig: selectedTools.includes("editorconfig"),
|
|
8527
|
+
editorconfigOptions,
|
|
8528
|
+
commitlint: selectedTools.includes("commitlint"),
|
|
8529
|
+
commitlintOptions,
|
|
8530
|
+
biome: selectedTools.includes("biome"),
|
|
8531
|
+
biomeOptions,
|
|
8532
|
+
prettier: selectedTools.includes("prettier"),
|
|
8533
|
+
prettierOptions
|
|
8534
|
+
};
|
|
8535
|
+
}
|
|
8536
|
+
async function promptStylePreset() {
|
|
8537
|
+
logger.newline();
|
|
8538
|
+
logger.info("Choose a code style preset:");
|
|
8539
|
+
return select({
|
|
8540
|
+
message: "Style preset:",
|
|
8541
|
+
choices: Object.entries(CODE_STYLE_PRESETS).map(([key, preset]) => ({
|
|
8542
|
+
name: `${preset.name} - ${preset.description}`,
|
|
8543
|
+
value: key
|
|
8544
|
+
})),
|
|
8545
|
+
default: "standard"
|
|
8546
|
+
});
|
|
8547
|
+
}
|
|
8548
|
+
async function promptEditorConfigOptions() {
|
|
8549
|
+
logger.newline();
|
|
8550
|
+
logger.subtitle("EditorConfig Options");
|
|
8551
|
+
const indentStyle = await select({
|
|
8552
|
+
message: "Indent style:",
|
|
8553
|
+
choices: [
|
|
8554
|
+
{ name: "Spaces", value: "space" },
|
|
8555
|
+
{ name: "Tabs", value: "tab" }
|
|
8556
|
+
],
|
|
8557
|
+
default: DEFAULT_EDITORCONFIG_OPTIONS.indentStyle
|
|
8558
|
+
});
|
|
8559
|
+
const indentSizeStr = await input({
|
|
8560
|
+
message: "Indent size:",
|
|
8561
|
+
default: String(DEFAULT_EDITORCONFIG_OPTIONS.indentSize),
|
|
8562
|
+
validate: (v) => {
|
|
8563
|
+
const num = Number(v);
|
|
8564
|
+
if (Number.isNaN(num) || num < 1 || num > 8) return "Enter a number between 1 and 8";
|
|
8565
|
+
return true;
|
|
8566
|
+
}
|
|
8567
|
+
});
|
|
8568
|
+
const indentSize = Number(indentSizeStr);
|
|
8569
|
+
const endOfLine = await select({
|
|
8570
|
+
message: "Line endings:",
|
|
8571
|
+
choices: [
|
|
8572
|
+
{ name: "LF (Unix/Mac)", value: "lf" },
|
|
8573
|
+
{ name: "CRLF (Windows)", value: "crlf" },
|
|
8574
|
+
{ name: "CR (Old Mac)", value: "cr" }
|
|
8575
|
+
],
|
|
8576
|
+
default: DEFAULT_EDITORCONFIG_OPTIONS.endOfLine
|
|
8577
|
+
});
|
|
8578
|
+
const maxLineLengthStr = await input({
|
|
8579
|
+
message: 'Max line length (or "off"):',
|
|
8580
|
+
default: String(DEFAULT_EDITORCONFIG_OPTIONS.maxLineLength),
|
|
8581
|
+
validate: (v) => {
|
|
8582
|
+
if (v.toLowerCase() === "off") return true;
|
|
8583
|
+
const num = Number(v);
|
|
8584
|
+
if (Number.isNaN(num) || num < 40 || num > 200)
|
|
8585
|
+
return 'Enter a number between 40 and 200, or "off"';
|
|
8586
|
+
return true;
|
|
8587
|
+
}
|
|
8588
|
+
});
|
|
8589
|
+
const maxLineLength = maxLineLengthStr.toLowerCase() === "off" ? "off" : Number(maxLineLengthStr);
|
|
8590
|
+
return {
|
|
8591
|
+
indentStyle,
|
|
8592
|
+
indentSize,
|
|
8593
|
+
endOfLine,
|
|
8594
|
+
insertFinalNewline: true,
|
|
8595
|
+
trimTrailingWhitespace: true,
|
|
8596
|
+
charset: "utf-8",
|
|
8597
|
+
maxLineLength
|
|
8598
|
+
};
|
|
8599
|
+
}
|
|
8600
|
+
async function promptBiomeOptions() {
|
|
8601
|
+
logger.newline();
|
|
8602
|
+
logger.subtitle("Biome Options");
|
|
8603
|
+
const indentStyle = await select({
|
|
8604
|
+
message: "Indent style:",
|
|
8605
|
+
choices: [
|
|
8606
|
+
{ name: "Spaces", value: "space" },
|
|
8607
|
+
{ name: "Tabs", value: "tab" }
|
|
8608
|
+
],
|
|
8609
|
+
default: DEFAULT_BIOME_OPTIONS.formatter.indentStyle
|
|
8610
|
+
});
|
|
8611
|
+
const indentWidthStr = await input({
|
|
8612
|
+
message: "Indent width:",
|
|
8613
|
+
default: String(DEFAULT_BIOME_OPTIONS.formatter.indentWidth),
|
|
8614
|
+
validate: (v) => {
|
|
8615
|
+
const num = Number(v);
|
|
8616
|
+
if (Number.isNaN(num) || num < 1 || num > 8) return "Enter a number between 1 and 8";
|
|
8617
|
+
return true;
|
|
8618
|
+
}
|
|
8619
|
+
});
|
|
8620
|
+
const indentWidth = Number(indentWidthStr);
|
|
8621
|
+
const lineWidthStr = await input({
|
|
8622
|
+
message: "Line width:",
|
|
8623
|
+
default: String(DEFAULT_BIOME_OPTIONS.formatter.lineWidth),
|
|
8624
|
+
validate: (v) => {
|
|
8625
|
+
const num = Number(v);
|
|
8626
|
+
if (Number.isNaN(num) || num < 40 || num > 200) return "Enter a number between 40 and 200";
|
|
8627
|
+
return true;
|
|
8628
|
+
}
|
|
8629
|
+
});
|
|
8630
|
+
const lineWidth = Number(lineWidthStr);
|
|
8631
|
+
const quoteStyle = await select({
|
|
8632
|
+
message: "Quote style:",
|
|
8633
|
+
choices: [
|
|
8634
|
+
{ name: "Single quotes", value: "single" },
|
|
8635
|
+
{ name: "Double quotes", value: "double" }
|
|
8636
|
+
],
|
|
8637
|
+
default: DEFAULT_BIOME_OPTIONS.formatter.quoteStyle
|
|
8638
|
+
});
|
|
8639
|
+
const semicolons = await select({
|
|
8640
|
+
message: "Semicolons:",
|
|
8641
|
+
choices: [
|
|
8642
|
+
{ name: "Always", value: "always" },
|
|
8643
|
+
{ name: "As needed (ASI)", value: "asNeeded" }
|
|
8644
|
+
],
|
|
8645
|
+
default: DEFAULT_BIOME_OPTIONS.formatter.semicolons
|
|
8646
|
+
});
|
|
8647
|
+
const trailingCommas = await select({
|
|
8648
|
+
message: "Trailing commas:",
|
|
8649
|
+
choices: [
|
|
8650
|
+
{ name: "All", value: "all" },
|
|
8651
|
+
{ name: "ES5 (only where valid in ES5)", value: "es5" },
|
|
8652
|
+
{ name: "None", value: "none" }
|
|
8653
|
+
],
|
|
8654
|
+
default: DEFAULT_BIOME_OPTIONS.formatter.trailingCommas
|
|
8655
|
+
});
|
|
8656
|
+
const enableRecommended = await confirm({
|
|
8657
|
+
message: "Enable recommended linter rules?",
|
|
8658
|
+
default: true
|
|
8659
|
+
});
|
|
8660
|
+
return {
|
|
8661
|
+
formatter: {
|
|
8662
|
+
indentStyle,
|
|
8663
|
+
indentWidth,
|
|
8664
|
+
lineWidth,
|
|
8665
|
+
quoteStyle,
|
|
8666
|
+
semicolons,
|
|
8667
|
+
trailingCommas,
|
|
8668
|
+
quoteProperties: "asNeeded",
|
|
8669
|
+
bracketSpacing: true,
|
|
8670
|
+
bracketSameLine: false,
|
|
8671
|
+
arrowParentheses: "always"
|
|
8672
|
+
},
|
|
8673
|
+
linter: {
|
|
8674
|
+
recommended: enableRecommended,
|
|
8675
|
+
correctness: enableRecommended,
|
|
8676
|
+
suspicious: enableRecommended,
|
|
8677
|
+
style: enableRecommended,
|
|
8678
|
+
complexity: enableRecommended,
|
|
8679
|
+
security: enableRecommended,
|
|
8680
|
+
performance: enableRecommended,
|
|
8681
|
+
a11y: enableRecommended
|
|
8682
|
+
},
|
|
8683
|
+
organizeImports: true,
|
|
8684
|
+
ignorePatterns: DEFAULT_BIOME_OPTIONS.ignorePatterns
|
|
8685
|
+
};
|
|
8686
|
+
}
|
|
8687
|
+
async function promptPrettierOptions() {
|
|
8688
|
+
logger.newline();
|
|
8689
|
+
logger.subtitle("Prettier Options");
|
|
8690
|
+
const printWidthStr = await input({
|
|
8691
|
+
message: "Print width:",
|
|
8692
|
+
default: String(DEFAULT_PRETTIER_OPTIONS.printWidth),
|
|
8693
|
+
validate: (v) => {
|
|
8694
|
+
const num = Number(v);
|
|
8695
|
+
if (Number.isNaN(num) || num < 40 || num > 200) return "Enter a number between 40 and 200";
|
|
8696
|
+
return true;
|
|
8697
|
+
}
|
|
8698
|
+
});
|
|
8699
|
+
const printWidth = Number(printWidthStr);
|
|
8700
|
+
const tabWidthStr = await input({
|
|
8701
|
+
message: "Tab width:",
|
|
8702
|
+
default: String(DEFAULT_PRETTIER_OPTIONS.tabWidth),
|
|
8703
|
+
validate: (v) => {
|
|
8704
|
+
const num = Number(v);
|
|
8705
|
+
if (Number.isNaN(num) || num < 1 || num > 8) return "Enter a number between 1 and 8";
|
|
8706
|
+
return true;
|
|
8707
|
+
}
|
|
8708
|
+
});
|
|
8709
|
+
const tabWidth = Number(tabWidthStr);
|
|
8710
|
+
const useTabs = await confirm({
|
|
8711
|
+
message: "Use tabs instead of spaces?",
|
|
8712
|
+
default: DEFAULT_PRETTIER_OPTIONS.useTabs
|
|
8713
|
+
});
|
|
8714
|
+
const semi = await confirm({
|
|
8715
|
+
message: "Use semicolons?",
|
|
8716
|
+
default: DEFAULT_PRETTIER_OPTIONS.semi
|
|
8717
|
+
});
|
|
8718
|
+
const singleQuote = await confirm({
|
|
8719
|
+
message: "Use single quotes?",
|
|
8720
|
+
default: DEFAULT_PRETTIER_OPTIONS.singleQuote
|
|
8721
|
+
});
|
|
8722
|
+
const trailingComma = await select({
|
|
8723
|
+
message: "Trailing commas:",
|
|
8724
|
+
choices: [
|
|
8725
|
+
{ name: "All", value: "all" },
|
|
8726
|
+
{ name: "ES5", value: "es5" },
|
|
8727
|
+
{ name: "None", value: "none" }
|
|
8728
|
+
],
|
|
8729
|
+
default: DEFAULT_PRETTIER_OPTIONS.trailingComma
|
|
8730
|
+
});
|
|
8731
|
+
const bracketSpacing = await confirm({
|
|
8732
|
+
message: "Bracket spacing? ({ foo: bar })",
|
|
8733
|
+
default: DEFAULT_PRETTIER_OPTIONS.bracketSpacing
|
|
8734
|
+
});
|
|
8735
|
+
const arrowParens = await select({
|
|
8736
|
+
message: "Arrow function parentheses:",
|
|
8737
|
+
choices: [
|
|
8738
|
+
{ name: "Always (x) => x", value: "always" },
|
|
8739
|
+
{ name: "Avoid x => x", value: "avoid" }
|
|
8740
|
+
],
|
|
8741
|
+
default: DEFAULT_PRETTIER_OPTIONS.arrowParens
|
|
8742
|
+
});
|
|
8743
|
+
return {
|
|
8744
|
+
printWidth,
|
|
8745
|
+
tabWidth,
|
|
8746
|
+
useTabs,
|
|
8747
|
+
semi,
|
|
8748
|
+
singleQuote,
|
|
8749
|
+
jsxSingleQuote: false,
|
|
8750
|
+
trailingComma,
|
|
8751
|
+
bracketSpacing,
|
|
8752
|
+
bracketSameLine: false,
|
|
8753
|
+
arrowParens,
|
|
8754
|
+
endOfLine: "lf",
|
|
8755
|
+
proseWrap: "preserve",
|
|
8756
|
+
htmlWhitespaceSensitivity: "css",
|
|
8757
|
+
singleAttributePerLine: false
|
|
8758
|
+
};
|
|
8759
|
+
}
|
|
8760
|
+
async function promptCommitlintOptions() {
|
|
8761
|
+
logger.newline();
|
|
8762
|
+
logger.subtitle("Commitlint Options");
|
|
8763
|
+
const useDefaults = await confirm({
|
|
8764
|
+
message: "Use conventional commits defaults?",
|
|
8765
|
+
default: true
|
|
8766
|
+
});
|
|
8767
|
+
if (useDefaults) {
|
|
8768
|
+
const huskyIntegration2 = await confirm({
|
|
8769
|
+
message: "Enable Husky integration (git hooks)?",
|
|
8770
|
+
default: true
|
|
8771
|
+
});
|
|
8772
|
+
return {
|
|
8773
|
+
...DEFAULT_COMMITLINT_OPTIONS,
|
|
8774
|
+
huskyIntegration: huskyIntegration2
|
|
8775
|
+
};
|
|
8776
|
+
}
|
|
8777
|
+
const typesInput = await input({
|
|
8778
|
+
message: "Commit types (comma-separated):",
|
|
8779
|
+
default: DEFAULT_COMMITLINT_OPTIONS.types.join(", ")
|
|
8780
|
+
});
|
|
8781
|
+
const types = typesInput.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
8782
|
+
const scopesInput = await input({
|
|
8783
|
+
message: "Allowed scopes (comma-separated, empty for any):",
|
|
8784
|
+
default: ""
|
|
8785
|
+
});
|
|
8786
|
+
const scopes = scopesInput.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
8787
|
+
const headerMaxLengthStr = await input({
|
|
8788
|
+
message: "Maximum header length:",
|
|
8789
|
+
default: String(DEFAULT_COMMITLINT_OPTIONS.headerMaxLength),
|
|
8790
|
+
validate: (v) => {
|
|
8791
|
+
const num = Number(v);
|
|
8792
|
+
if (Number.isNaN(num) || num < 20 || num > 200) return "Enter a number between 20 and 200";
|
|
8793
|
+
return true;
|
|
8794
|
+
}
|
|
8795
|
+
});
|
|
8796
|
+
const headerMaxLength = Number(headerMaxLengthStr);
|
|
8797
|
+
const scopeRequired = await confirm({
|
|
8798
|
+
message: "Require scope in commit messages?",
|
|
8799
|
+
default: false
|
|
8800
|
+
});
|
|
8801
|
+
const huskyIntegration = await confirm({
|
|
8802
|
+
message: "Enable Husky integration (git hooks)?",
|
|
8803
|
+
default: true
|
|
8804
|
+
});
|
|
8805
|
+
return {
|
|
8806
|
+
extends: ["@commitlint/config-conventional"],
|
|
8807
|
+
types,
|
|
8808
|
+
scopes,
|
|
8809
|
+
headerMaxLength,
|
|
8810
|
+
scopeRequired,
|
|
8811
|
+
bodyRequired: false,
|
|
8812
|
+
bodyMaxLineLength: 100,
|
|
8813
|
+
huskyIntegration
|
|
8814
|
+
};
|
|
8815
|
+
}
|
|
8816
|
+
|
|
8817
|
+
// src/cli/prompts/folder-preferences.ts
|
|
8818
|
+
init_esm_shims();
|
|
8819
|
+
|
|
8820
|
+
// src/constants/folder-preferences.ts
|
|
8821
|
+
init_esm_shims();
|
|
8822
|
+
var DEFAULT_FOLDER_PREFERENCES = {
|
|
8823
|
+
tests: {
|
|
8824
|
+
location: "test-folder-root",
|
|
8825
|
+
pattern: "*.test.ts"
|
|
8826
|
+
},
|
|
8827
|
+
planning: {
|
|
8828
|
+
location: "claude-sessions",
|
|
8829
|
+
commitToGit: false
|
|
8830
|
+
},
|
|
8831
|
+
docs: {
|
|
8832
|
+
location: "docs-root"
|
|
8833
|
+
},
|
|
8834
|
+
cicd: {
|
|
8835
|
+
location: "github-workflows",
|
|
8836
|
+
workflows: []
|
|
8837
|
+
}
|
|
8838
|
+
};
|
|
8839
|
+
var TEST_LOCATION_OPTIONS = [
|
|
8840
|
+
{
|
|
8841
|
+
value: "colocated",
|
|
8842
|
+
name: "Colocated with source files",
|
|
8843
|
+
description: "Tests next to source files (e.g., src/utils/foo.ts \u2192 src/utils/foo.test.ts). Good for small projects."
|
|
8844
|
+
},
|
|
8845
|
+
{
|
|
8846
|
+
value: "test-folder-root",
|
|
8847
|
+
name: "Root test/ folder (Recommended)",
|
|
8848
|
+
description: "Tests in test/ folder mirroring src structure (e.g., test/utils/foo.test.ts). Best for medium-large projects."
|
|
8849
|
+
},
|
|
8850
|
+
{
|
|
8851
|
+
value: "test-folder-src",
|
|
8852
|
+
name: "Inside src/__tests__/",
|
|
8853
|
+
description: "Tests in src/__tests__/ folder (e.g., src/__tests__/utils/foo.test.ts). Common in Create React App."
|
|
8854
|
+
}
|
|
8855
|
+
];
|
|
8856
|
+
var PLANNING_LOCATION_OPTIONS = [
|
|
8857
|
+
{
|
|
8858
|
+
value: "claude-sessions",
|
|
8859
|
+
name: ".claude/sessions/planning/ (Recommended)",
|
|
8860
|
+
description: "Planning files in .claude/sessions/planning/. Keeps Claude-specific files organized."
|
|
8861
|
+
},
|
|
8862
|
+
{
|
|
8863
|
+
value: "docs-planning",
|
|
8864
|
+
name: "docs/planning/",
|
|
8865
|
+
description: "Planning files in docs/planning/. Good if you want planning docs alongside other docs."
|
|
8866
|
+
},
|
|
8867
|
+
{
|
|
8868
|
+
value: "root-planning",
|
|
8869
|
+
name: "planning/ at root",
|
|
8870
|
+
description: "Planning files in planning/ at project root. Maximum visibility."
|
|
8871
|
+
}
|
|
8872
|
+
];
|
|
8873
|
+
var DOCS_LOCATION_OPTIONS = [
|
|
8874
|
+
{
|
|
8875
|
+
value: "docs-root",
|
|
8876
|
+
name: "docs/ at project root (Recommended)",
|
|
8877
|
+
description: "Documentation in docs/ folder. Standard location for most projects."
|
|
8878
|
+
},
|
|
8879
|
+
{
|
|
8880
|
+
value: "claude-docs",
|
|
8881
|
+
name: ".claude/docs/",
|
|
8882
|
+
description: "Documentation in .claude/docs/. Keeps all Claude-related files together."
|
|
8883
|
+
},
|
|
8884
|
+
{
|
|
8885
|
+
value: "readme-only",
|
|
8886
|
+
name: "README files only",
|
|
8887
|
+
description: "Only README.md files, no separate docs folder. Good for simple projects."
|
|
8888
|
+
}
|
|
8889
|
+
];
|
|
8890
|
+
var TEST_PATTERN_OPTIONS = [
|
|
8891
|
+
{
|
|
8892
|
+
value: "*.test.ts",
|
|
8893
|
+
name: "*.test.ts (Recommended)",
|
|
8894
|
+
description: "Standard test pattern (foo.test.ts)"
|
|
8895
|
+
},
|
|
8896
|
+
{
|
|
8897
|
+
value: "*.spec.ts",
|
|
8898
|
+
name: "*.spec.ts",
|
|
8899
|
+
description: "Spec pattern common in Angular (foo.spec.ts)"
|
|
8900
|
+
},
|
|
8901
|
+
{
|
|
8902
|
+
value: "*.test.tsx",
|
|
8903
|
+
name: "*.test.tsx",
|
|
8904
|
+
description: "For React component tests (Component.test.tsx)"
|
|
8905
|
+
}
|
|
8906
|
+
];
|
|
8907
|
+
var GITHUB_WORKFLOW_TEMPLATES = [
|
|
8908
|
+
// CI Workflows
|
|
8909
|
+
{
|
|
8910
|
+
id: "ci-node",
|
|
8911
|
+
name: "Node.js CI",
|
|
8912
|
+
description: "Run tests, lint, and type-check on push and PR",
|
|
8913
|
+
filename: "ci.yml",
|
|
8914
|
+
category: "ci",
|
|
8915
|
+
suitedFor: ["node", "typescript", "javascript"],
|
|
8916
|
+
recommended: true
|
|
8917
|
+
},
|
|
8918
|
+
{
|
|
8919
|
+
id: "ci-node-matrix",
|
|
8920
|
+
name: "Node.js CI (Matrix)",
|
|
8921
|
+
description: "Test across multiple Node.js versions (18, 20, 22)",
|
|
8194
8922
|
filename: "ci-matrix.yml",
|
|
8195
8923
|
category: "ci",
|
|
8196
8924
|
suitedFor: ["node", "typescript", "library"]
|
|
@@ -8591,429 +9319,204 @@ async function promptFolderPreferences(options) {
|
|
|
8591
9319
|
}
|
|
8592
9320
|
const setupCiCd = hasCiCdBundle || await confirm({
|
|
8593
9321
|
message: "Would you like to set up GitHub Actions workflows?",
|
|
8594
|
-
default: true
|
|
8595
|
-
});
|
|
8596
|
-
if (setupCiCd) {
|
|
8597
|
-
const workflows = await promptGithubWorkflows({
|
|
8598
|
-
recommended: mergedDefaults.cicd?.workflows,
|
|
8599
|
-
technologies
|
|
8600
|
-
});
|
|
8601
|
-
if (workflows.length > 0) {
|
|
8602
|
-
preferences.cicd = {
|
|
8603
|
-
location: "github-workflows",
|
|
8604
|
-
workflows
|
|
8605
|
-
};
|
|
8606
|
-
}
|
|
8607
|
-
}
|
|
8608
|
-
return preferences;
|
|
8609
|
-
}
|
|
8610
|
-
function showFolderPreferencesSummary(preferences) {
|
|
8611
|
-
logger.newline();
|
|
8612
|
-
logger.subtitle("Folder Structure Summary");
|
|
8613
|
-
if (preferences.tests) {
|
|
8614
|
-
const testOpt = TEST_LOCATION_OPTIONS.find((o) => o.value === preferences.tests?.location);
|
|
8615
|
-
logger.keyValue("Tests", testOpt?.name || preferences.tests.location);
|
|
8616
|
-
logger.keyValue("Test Pattern", preferences.tests.pattern);
|
|
8617
|
-
}
|
|
8618
|
-
if (preferences.planning) {
|
|
8619
|
-
const planOpt = PLANNING_LOCATION_OPTIONS.find(
|
|
8620
|
-
(o) => o.value === preferences.planning?.location
|
|
8621
|
-
);
|
|
8622
|
-
logger.keyValue("Planning", planOpt?.name || preferences.planning.location);
|
|
8623
|
-
logger.keyValue(
|
|
8624
|
-
"Commit Planning",
|
|
8625
|
-
preferences.planning.commitToGit ? "Yes" : "No (will be in .gitignore)"
|
|
8626
|
-
);
|
|
8627
|
-
}
|
|
8628
|
-
if (preferences.docs) {
|
|
8629
|
-
const docsOpt = DOCS_LOCATION_OPTIONS.find((o) => o.value === preferences.docs?.location);
|
|
8630
|
-
logger.keyValue("Documentation", docsOpt?.name || preferences.docs.location);
|
|
8631
|
-
}
|
|
8632
|
-
if (preferences.cicd && preferences.cicd.workflows.length > 0) {
|
|
8633
|
-
logger.keyValue("CI/CD Location", ".github/workflows/");
|
|
8634
|
-
logger.info(` ${colors.muted("Workflows:")} ${preferences.cicd.workflows.join(", ")}`);
|
|
8635
|
-
}
|
|
8636
|
-
}
|
|
8637
|
-
async function promptQuickFolderPreferences(options) {
|
|
8638
|
-
const recommendations = getFolderRecommendationsForBundles(options.selectedBundles);
|
|
8639
|
-
const mergedDefaults = mergeFolderPreferences(recommendations);
|
|
8640
|
-
if (recommendations.length > 0) {
|
|
8641
|
-
logger.section("Folder Structure", "\u{1F4C1}");
|
|
8642
|
-
logger.info(colors.muted("Based on your bundles, we have recommended folder settings."));
|
|
8643
|
-
showFolderPreferencesSummary(mergedDefaults);
|
|
8644
|
-
const customize = await confirm({
|
|
8645
|
-
message: "Would you like to customize these folder preferences?",
|
|
8646
|
-
default: false
|
|
8647
|
-
});
|
|
8648
|
-
if (!customize) {
|
|
8649
|
-
return mergedDefaults;
|
|
8650
|
-
}
|
|
8651
|
-
}
|
|
8652
|
-
return promptFolderPreferences(options);
|
|
8653
|
-
}
|
|
8654
|
-
|
|
8655
|
-
// src/cli/prompts/index.ts
|
|
8656
|
-
init_esm_shims();
|
|
8657
|
-
|
|
8658
|
-
// src/cli/prompts/project-info.ts
|
|
8659
|
-
init_esm_shims();
|
|
8660
|
-
async function promptProjectInfo(options) {
|
|
8661
|
-
logger.section("Project Information", "\u{1F4CB}");
|
|
8662
|
-
const name = await input({
|
|
8663
|
-
message: "Project name:",
|
|
8664
|
-
default: options?.defaults?.name,
|
|
8665
|
-
validate: (value) => {
|
|
8666
|
-
if (!value.trim()) return "Project name is required";
|
|
8667
|
-
if (!/^[a-zA-Z0-9-_\s]+$/.test(value)) {
|
|
8668
|
-
return "Project name can only contain letters, numbers, dashes, underscores, and spaces";
|
|
8669
|
-
}
|
|
8670
|
-
return true;
|
|
8671
|
-
}
|
|
8672
|
-
});
|
|
8673
|
-
const description = await input({
|
|
8674
|
-
message: "Project description:",
|
|
8675
|
-
default: options?.defaults?.description || "",
|
|
8676
|
-
validate: (value) => {
|
|
8677
|
-
if (!value.trim()) return "Description is required";
|
|
8678
|
-
return true;
|
|
8679
|
-
}
|
|
8680
|
-
});
|
|
8681
|
-
const org = await input({
|
|
8682
|
-
message: "GitHub organization/username:",
|
|
8683
|
-
default: options?.defaults?.org || "",
|
|
8684
|
-
validate: (value) => {
|
|
8685
|
-
if (!value.trim()) return "Organization is required";
|
|
8686
|
-
if (!/^[a-zA-Z0-9-]+$/.test(value)) {
|
|
8687
|
-
return "Organization can only contain letters, numbers, and dashes";
|
|
8688
|
-
}
|
|
8689
|
-
return true;
|
|
8690
|
-
}
|
|
8691
|
-
});
|
|
8692
|
-
const repo = await input({
|
|
8693
|
-
message: "Repository name:",
|
|
8694
|
-
default: options?.defaults?.repo || name.toLowerCase().replace(/\s+/g, "-"),
|
|
8695
|
-
validate: (value) => {
|
|
8696
|
-
if (!value.trim()) return "Repository name is required";
|
|
8697
|
-
if (!/^[a-zA-Z0-9-_]+$/.test(value)) {
|
|
8698
|
-
return "Repository name can only contain letters, numbers, dashes, and underscores";
|
|
8699
|
-
}
|
|
8700
|
-
return true;
|
|
8701
|
-
}
|
|
8702
|
-
});
|
|
8703
|
-
const author = await input({
|
|
8704
|
-
message: 'Author (name or "Name <email>"):',
|
|
8705
|
-
default: options?.defaults?.author || ""
|
|
8706
|
-
});
|
|
8707
|
-
let entityType = "item";
|
|
8708
|
-
let entityTypePlural = "items";
|
|
8709
|
-
const wantEntityConfig = await confirm({
|
|
8710
|
-
message: "Configure primary entity type? (Used for code examples and templates)",
|
|
8711
|
-
default: false
|
|
8712
|
-
});
|
|
8713
|
-
if (wantEntityConfig) {
|
|
8714
|
-
logger.info("The entity type is used in code examples and templates throughout the project.");
|
|
8715
|
-
logger.info(
|
|
8716
|
-
'For example, if your project manages "products", code examples will use product-related names.'
|
|
8717
|
-
);
|
|
8718
|
-
logger.newline();
|
|
8719
|
-
entityType = await input({
|
|
8720
|
-
message: "Primary entity type (e.g., product, article, user, listing):",
|
|
8721
|
-
default: options?.defaults?.entityType || "item",
|
|
8722
|
-
validate: (value) => {
|
|
8723
|
-
if (!value.trim()) return "Entity type is required";
|
|
8724
|
-
return true;
|
|
8725
|
-
}
|
|
8726
|
-
});
|
|
8727
|
-
entityTypePlural = await input({
|
|
8728
|
-
message: "Entity type plural:",
|
|
8729
|
-
default: options?.defaults?.entityTypePlural || pluralize(entityType)
|
|
8730
|
-
});
|
|
8731
|
-
} else if (options?.defaults?.entityType) {
|
|
8732
|
-
entityType = options.defaults.entityType;
|
|
8733
|
-
entityTypePlural = options.defaults.entityTypePlural || pluralize(entityType);
|
|
8734
|
-
}
|
|
8735
|
-
let domain;
|
|
8736
|
-
let location;
|
|
8737
|
-
if (!options?.skipOptional) {
|
|
8738
|
-
const wantDomain = await confirm({
|
|
8739
|
-
message: "Do you want to specify a domain?",
|
|
8740
|
-
default: false
|
|
8741
|
-
});
|
|
8742
|
-
if (wantDomain) {
|
|
8743
|
-
domain = await input({
|
|
8744
|
-
message: "Domain (e.g., myproject.com):",
|
|
8745
|
-
default: options?.defaults?.domain || "",
|
|
8746
|
-
validate: (value) => {
|
|
8747
|
-
if (value && !/^[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(value)) {
|
|
8748
|
-
return "Please enter a valid domain";
|
|
8749
|
-
}
|
|
8750
|
-
return true;
|
|
8751
|
-
}
|
|
8752
|
-
});
|
|
8753
|
-
}
|
|
8754
|
-
const wantLocation = await confirm({
|
|
8755
|
-
message: "Do you want to specify a location/region?",
|
|
8756
|
-
default: false
|
|
9322
|
+
default: true
|
|
9323
|
+
});
|
|
9324
|
+
if (setupCiCd) {
|
|
9325
|
+
const workflows = await promptGithubWorkflows({
|
|
9326
|
+
recommended: mergedDefaults.cicd?.workflows,
|
|
9327
|
+
technologies
|
|
8757
9328
|
});
|
|
8758
|
-
if (
|
|
8759
|
-
|
|
8760
|
-
|
|
8761
|
-
|
|
8762
|
-
}
|
|
9329
|
+
if (workflows.length > 0) {
|
|
9330
|
+
preferences.cicd = {
|
|
9331
|
+
location: "github-workflows",
|
|
9332
|
+
workflows
|
|
9333
|
+
};
|
|
8763
9334
|
}
|
|
8764
9335
|
}
|
|
8765
|
-
return
|
|
8766
|
-
name: name.trim(),
|
|
8767
|
-
description: description.trim(),
|
|
8768
|
-
org: org.trim(),
|
|
8769
|
-
repo: repo.trim(),
|
|
8770
|
-
domain,
|
|
8771
|
-
entityType: entityType.trim().toLowerCase(),
|
|
8772
|
-
entityTypePlural: entityTypePlural.trim().toLowerCase(),
|
|
8773
|
-
location,
|
|
8774
|
-
author: author.trim() || void 0
|
|
8775
|
-
};
|
|
9336
|
+
return preferences;
|
|
8776
9337
|
}
|
|
8777
|
-
function
|
|
8778
|
-
|
|
8779
|
-
|
|
8780
|
-
|
|
9338
|
+
function showFolderPreferencesSummary(preferences) {
|
|
9339
|
+
logger.newline();
|
|
9340
|
+
logger.subtitle("Folder Structure Summary");
|
|
9341
|
+
if (preferences.tests) {
|
|
9342
|
+
const testOpt = TEST_LOCATION_OPTIONS.find((o) => o.value === preferences.tests?.location);
|
|
9343
|
+
logger.keyValue("Tests", testOpt?.name || preferences.tests.location);
|
|
9344
|
+
logger.keyValue("Test Pattern", preferences.tests.pattern);
|
|
8781
9345
|
}
|
|
8782
|
-
if (
|
|
8783
|
-
|
|
9346
|
+
if (preferences.planning) {
|
|
9347
|
+
const planOpt = PLANNING_LOCATION_OPTIONS.find(
|
|
9348
|
+
(o) => o.value === preferences.planning?.location
|
|
9349
|
+
);
|
|
9350
|
+
logger.keyValue("Planning", planOpt?.name || preferences.planning.location);
|
|
9351
|
+
logger.keyValue(
|
|
9352
|
+
"Commit Planning",
|
|
9353
|
+
preferences.planning.commitToGit ? "Yes" : "No (will be in .gitignore)"
|
|
9354
|
+
);
|
|
9355
|
+
}
|
|
9356
|
+
if (preferences.docs) {
|
|
9357
|
+
const docsOpt = DOCS_LOCATION_OPTIONS.find((o) => o.value === preferences.docs?.location);
|
|
9358
|
+
logger.keyValue("Documentation", docsOpt?.name || preferences.docs.location);
|
|
9359
|
+
}
|
|
9360
|
+
if (preferences.cicd && preferences.cicd.workflows.length > 0) {
|
|
9361
|
+
logger.keyValue("CI/CD Location", ".github/workflows/");
|
|
9362
|
+
logger.info(` ${colors.muted("Workflows:")} ${preferences.cicd.workflows.join(", ")}`);
|
|
8784
9363
|
}
|
|
8785
|
-
return `${lower}s`;
|
|
8786
9364
|
}
|
|
8787
|
-
async function
|
|
8788
|
-
|
|
8789
|
-
|
|
8790
|
-
|
|
8791
|
-
|
|
8792
|
-
|
|
8793
|
-
|
|
8794
|
-
|
|
8795
|
-
|
|
8796
|
-
|
|
8797
|
-
|
|
8798
|
-
|
|
8799
|
-
|
|
8800
|
-
|
|
8801
|
-
}
|
|
9365
|
+
async function promptQuickFolderPreferences(options) {
|
|
9366
|
+
const recommendations = getFolderRecommendationsForBundles(options.selectedBundles);
|
|
9367
|
+
const mergedDefaults = mergeFolderPreferences(recommendations);
|
|
9368
|
+
if (recommendations.length > 0) {
|
|
9369
|
+
logger.section("Folder Structure", "\u{1F4C1}");
|
|
9370
|
+
logger.info(colors.muted("Based on your bundles, we have recommended folder settings."));
|
|
9371
|
+
showFolderPreferencesSummary(mergedDefaults);
|
|
9372
|
+
const customize = await confirm({
|
|
9373
|
+
message: "Would you like to customize these folder preferences?",
|
|
9374
|
+
default: false
|
|
9375
|
+
});
|
|
9376
|
+
if (!customize) {
|
|
9377
|
+
return mergedDefaults;
|
|
9378
|
+
}
|
|
9379
|
+
}
|
|
9380
|
+
return promptFolderPreferences(options);
|
|
8802
9381
|
}
|
|
8803
9382
|
|
|
8804
|
-
// src/cli/prompts/
|
|
9383
|
+
// src/cli/prompts/hook-config.ts
|
|
8805
9384
|
init_esm_shims();
|
|
8806
|
-
async function
|
|
8807
|
-
logger.section("
|
|
8808
|
-
const
|
|
8809
|
-
message: "
|
|
8810
|
-
|
|
8811
|
-
{ name: "English", value: "en" },
|
|
8812
|
-
{ name: "Espa\xF1ol", value: "es" }
|
|
8813
|
-
],
|
|
8814
|
-
default: options?.defaults?.language || "en"
|
|
9385
|
+
async function promptHookConfig(options) {
|
|
9386
|
+
logger.section("Hook Configuration", "\u{1FA9D}");
|
|
9387
|
+
const enableHooks = await confirm({
|
|
9388
|
+
message: "Do you want to configure hooks?",
|
|
9389
|
+
default: true
|
|
8815
9390
|
});
|
|
8816
|
-
|
|
8817
|
-
|
|
9391
|
+
if (!enableHooks) {
|
|
9392
|
+
return {
|
|
9393
|
+
enabled: false
|
|
9394
|
+
};
|
|
9395
|
+
}
|
|
9396
|
+
const selectedHooks = await checkbox({
|
|
9397
|
+
message: "Which hooks do you want to configure?",
|
|
8818
9398
|
choices: [
|
|
8819
|
-
{
|
|
8820
|
-
|
|
8821
|
-
|
|
8822
|
-
|
|
8823
|
-
|
|
8824
|
-
|
|
8825
|
-
|
|
8826
|
-
|
|
9399
|
+
{
|
|
9400
|
+
name: "Notification hook (alerts when Claude needs attention)",
|
|
9401
|
+
value: "notification",
|
|
9402
|
+
checked: true
|
|
9403
|
+
},
|
|
9404
|
+
{
|
|
9405
|
+
name: "Stop hook (plays sound when Claude stops)",
|
|
9406
|
+
value: "stop",
|
|
9407
|
+
checked: false
|
|
9408
|
+
},
|
|
9409
|
+
{
|
|
9410
|
+
name: "Subagent stop hook (plays sound when subagent completes)",
|
|
9411
|
+
value: "subagentStop",
|
|
9412
|
+
checked: false
|
|
9413
|
+
}
|
|
9414
|
+
]
|
|
8827
9415
|
});
|
|
8828
|
-
const
|
|
8829
|
-
|
|
8830
|
-
language,
|
|
8831
|
-
responseLanguage,
|
|
8832
|
-
includeCoAuthor,
|
|
8833
|
-
packageManager
|
|
9416
|
+
const config = {
|
|
9417
|
+
enabled: true
|
|
8834
9418
|
};
|
|
8835
|
-
|
|
8836
|
-
|
|
8837
|
-
const choices = [
|
|
8838
|
-
{
|
|
8839
|
-
name: "pnpm (recommended)",
|
|
8840
|
-
value: "pnpm",
|
|
8841
|
-
description: "Fast, disk space efficient package manager"
|
|
8842
|
-
},
|
|
8843
|
-
{
|
|
8844
|
-
name: "npm",
|
|
8845
|
-
value: "npm",
|
|
8846
|
-
description: "Node.js default package manager"
|
|
8847
|
-
},
|
|
8848
|
-
{
|
|
8849
|
-
name: "yarn",
|
|
8850
|
-
value: "yarn",
|
|
8851
|
-
description: "Fast, reliable dependency management"
|
|
8852
|
-
},
|
|
8853
|
-
{
|
|
8854
|
-
name: "bun",
|
|
8855
|
-
value: "bun",
|
|
8856
|
-
description: "All-in-one JavaScript runtime & toolkit"
|
|
8857
|
-
}
|
|
8858
|
-
];
|
|
8859
|
-
if (detected) {
|
|
8860
|
-
const detectedChoice = choices.find((c) => c.value === detected);
|
|
8861
|
-
if (detectedChoice) {
|
|
8862
|
-
detectedChoice.name = `${detectedChoice.name} (detected)`;
|
|
8863
|
-
}
|
|
9419
|
+
if (selectedHooks.includes("notification")) {
|
|
9420
|
+
config.notification = await promptNotificationHook(options?.defaults?.notification);
|
|
8864
9421
|
}
|
|
8865
|
-
|
|
8866
|
-
|
|
8867
|
-
|
|
8868
|
-
|
|
8869
|
-
|
|
9422
|
+
if (selectedHooks.includes("stop")) {
|
|
9423
|
+
config.stop = await promptStopHook();
|
|
9424
|
+
}
|
|
9425
|
+
if (selectedHooks.includes("subagentStop")) {
|
|
9426
|
+
config.subagentStop = await promptSubagentStopHook();
|
|
9427
|
+
}
|
|
9428
|
+
return config;
|
|
8870
9429
|
}
|
|
8871
|
-
|
|
8872
|
-
|
|
8873
|
-
|
|
8874
|
-
|
|
8875
|
-
|
|
8876
|
-
|
|
8877
|
-
|
|
8878
|
-
|
|
8879
|
-
|
|
8880
|
-
|
|
8881
|
-
|
|
8882
|
-
|
|
8883
|
-
|
|
8884
|
-
|
|
8885
|
-
|
|
8886
|
-
},
|
|
8887
|
-
{
|
|
8888
|
-
name: "Full project setup (\u26A0\uFE0F may overwrite files)",
|
|
8889
|
-
value: "full-project",
|
|
8890
|
-
description: "Includes project scaffolding - use with caution"
|
|
8891
|
-
}
|
|
8892
|
-
],
|
|
8893
|
-
default: "claude-only"
|
|
8894
|
-
});
|
|
8895
|
-
if (choice === "full-project") {
|
|
8896
|
-
const confirmed = await confirm({
|
|
8897
|
-
message: "\u26A0\uFE0F This may overwrite existing files. Are you sure?",
|
|
8898
|
-
default: false
|
|
8899
|
-
});
|
|
8900
|
-
if (!confirmed) {
|
|
8901
|
-
return "claude-only";
|
|
9430
|
+
async function promptNotificationHook(defaults) {
|
|
9431
|
+
logger.newline();
|
|
9432
|
+
logger.info("Notification Hook Configuration");
|
|
9433
|
+
const notificationTypes = await checkbox({
|
|
9434
|
+
message: "Select notification types:",
|
|
9435
|
+
choices: [
|
|
9436
|
+
{
|
|
9437
|
+
name: "Desktop notifications (notify-send / terminal-notifier)",
|
|
9438
|
+
value: "desktop",
|
|
9439
|
+
checked: defaults?.desktop ?? true
|
|
9440
|
+
},
|
|
9441
|
+
{
|
|
9442
|
+
name: "Audio notifications (text-to-speech)",
|
|
9443
|
+
value: "audio",
|
|
9444
|
+
checked: defaults?.audio ?? false
|
|
8902
9445
|
}
|
|
8903
|
-
|
|
8904
|
-
|
|
9446
|
+
]
|
|
9447
|
+
});
|
|
9448
|
+
let customCommand;
|
|
9449
|
+
const wantCustom = await confirm({
|
|
9450
|
+
message: "Do you want to add a custom notification command?",
|
|
9451
|
+
default: false
|
|
9452
|
+
});
|
|
9453
|
+
if (wantCustom) {
|
|
9454
|
+
customCommand = await input({
|
|
9455
|
+
message: "Custom command (receives notification text as argument):",
|
|
9456
|
+
default: defaults?.customCommand
|
|
9457
|
+
});
|
|
8905
9458
|
}
|
|
8906
|
-
return
|
|
8907
|
-
|
|
9459
|
+
return {
|
|
9460
|
+
desktop: notificationTypes.includes("desktop"),
|
|
9461
|
+
audio: notificationTypes.includes("audio"),
|
|
9462
|
+
customCommand: customCommand || void 0
|
|
9463
|
+
};
|
|
9464
|
+
}
|
|
9465
|
+
async function promptStopHook() {
|
|
9466
|
+
logger.newline();
|
|
9467
|
+
logger.info("Stop Hook Configuration");
|
|
9468
|
+
const soundType = await select({
|
|
9469
|
+
message: "What should happen when Claude stops?",
|
|
8908
9470
|
choices: [
|
|
8909
|
-
{
|
|
8910
|
-
|
|
8911
|
-
|
|
8912
|
-
description: "Only creates .claude/ folder with agents, commands, skills, docs"
|
|
8913
|
-
},
|
|
8914
|
-
{
|
|
8915
|
-
name: "Full project setup",
|
|
8916
|
-
value: "full-project",
|
|
8917
|
-
description: "Creates project structure + Claude configuration"
|
|
8918
|
-
}
|
|
9471
|
+
{ name: "Play beep sound", value: "beep" },
|
|
9472
|
+
{ name: "Play custom sound", value: "custom" },
|
|
9473
|
+
{ name: "Run custom command", value: "command" }
|
|
8919
9474
|
],
|
|
8920
|
-
default: "
|
|
9475
|
+
default: "beep"
|
|
8921
9476
|
});
|
|
8922
|
-
|
|
8923
|
-
|
|
8924
|
-
const choices = [
|
|
8925
|
-
{
|
|
8926
|
-
name: "Node.js (TypeScript)",
|
|
8927
|
-
value: "node",
|
|
8928
|
-
description: "Basic Node.js project with TypeScript"
|
|
8929
|
-
},
|
|
8930
|
-
{
|
|
8931
|
-
name: "Monorepo (TurboRepo + pnpm)",
|
|
8932
|
-
value: "monorepo",
|
|
8933
|
-
description: "Multi-package monorepo setup"
|
|
8934
|
-
},
|
|
8935
|
-
{
|
|
8936
|
-
name: "Astro",
|
|
8937
|
-
value: "astro",
|
|
8938
|
-
description: "Astro static/SSR site"
|
|
8939
|
-
},
|
|
8940
|
-
{
|
|
8941
|
-
name: "Next.js",
|
|
8942
|
-
value: "nextjs",
|
|
8943
|
-
description: "Next.js full-stack React framework"
|
|
8944
|
-
},
|
|
8945
|
-
{
|
|
8946
|
-
name: "Vite + React",
|
|
8947
|
-
value: "vite-react",
|
|
8948
|
-
description: "Vite bundled React SPA"
|
|
8949
|
-
},
|
|
8950
|
-
{
|
|
8951
|
-
name: "Hono API",
|
|
8952
|
-
value: "hono",
|
|
8953
|
-
description: "Hono lightweight API server"
|
|
8954
|
-
},
|
|
8955
|
-
{
|
|
8956
|
-
name: "Custom",
|
|
8957
|
-
value: "custom",
|
|
8958
|
-
description: "Define your own project structure"
|
|
8959
|
-
}
|
|
8960
|
-
];
|
|
8961
|
-
if (detectedType) {
|
|
8962
|
-
const detected = choices.find((c) => c.value === detectedType);
|
|
8963
|
-
if (detected) {
|
|
8964
|
-
detected.name = `${detected.name} (detected)`;
|
|
8965
|
-
}
|
|
9477
|
+
if (soundType === "beep") {
|
|
9478
|
+
return { beep: true };
|
|
8966
9479
|
}
|
|
8967
|
-
|
|
8968
|
-
|
|
8969
|
-
|
|
8970
|
-
|
|
8971
|
-
|
|
8972
|
-
}
|
|
8973
|
-
async function promptPackageManager(detected) {
|
|
8974
|
-
const choices = [
|
|
8975
|
-
{ name: "pnpm (recommended)", value: "pnpm" },
|
|
8976
|
-
{ name: "npm", value: "npm" },
|
|
8977
|
-
{ name: "yarn", value: "yarn" },
|
|
8978
|
-
{ name: "bun", value: "bun" }
|
|
8979
|
-
];
|
|
8980
|
-
if (detected) {
|
|
8981
|
-
const detectedChoice = choices.find((c) => c.value === detected);
|
|
8982
|
-
if (detectedChoice) {
|
|
8983
|
-
detectedChoice.name = `${detectedChoice.name} (detected)`;
|
|
8984
|
-
}
|
|
9480
|
+
if (soundType === "custom") {
|
|
9481
|
+
const soundPath = await input({
|
|
9482
|
+
message: "Path to sound file:",
|
|
9483
|
+
validate: (v) => v.trim() ? true : "Please enter a valid path"
|
|
9484
|
+
});
|
|
9485
|
+
return { customSound: soundPath };
|
|
8985
9486
|
}
|
|
8986
|
-
|
|
8987
|
-
message: "
|
|
8988
|
-
|
|
8989
|
-
default: detected || "pnpm"
|
|
9487
|
+
const customCommand = await input({
|
|
9488
|
+
message: "Custom command to run:",
|
|
9489
|
+
validate: (v) => v.trim() ? true : "Please enter a command"
|
|
8990
9490
|
});
|
|
9491
|
+
return { customCommand };
|
|
8991
9492
|
}
|
|
8992
|
-
async function
|
|
8993
|
-
const type = await promptScaffoldType(options);
|
|
8994
|
-
if (type === "claude-only") {
|
|
8995
|
-
return { type };
|
|
8996
|
-
}
|
|
8997
|
-
const projectType = await promptProjectType(options?.detectedType);
|
|
8998
|
-
const packageManager = await promptPackageManager(options?.detectedPackageManager);
|
|
9493
|
+
async function promptSubagentStopHook() {
|
|
8999
9494
|
logger.newline();
|
|
9000
|
-
logger.
|
|
9001
|
-
const
|
|
9002
|
-
message: "
|
|
9495
|
+
logger.info("Subagent Stop Hook Configuration");
|
|
9496
|
+
const soundType = await select({
|
|
9497
|
+
message: "What should happen when a subagent completes?",
|
|
9003
9498
|
choices: [
|
|
9004
|
-
{ name: "
|
|
9005
|
-
{ name: "
|
|
9006
|
-
{ name: "
|
|
9007
|
-
]
|
|
9499
|
+
{ name: "Play short beep", value: "beep" },
|
|
9500
|
+
{ name: "Play custom sound", value: "custom" },
|
|
9501
|
+
{ name: "Run custom command", value: "command" }
|
|
9502
|
+
],
|
|
9503
|
+
default: "beep"
|
|
9008
9504
|
});
|
|
9009
|
-
|
|
9010
|
-
|
|
9011
|
-
|
|
9012
|
-
|
|
9013
|
-
|
|
9014
|
-
|
|
9015
|
-
|
|
9016
|
-
|
|
9505
|
+
if (soundType === "beep") {
|
|
9506
|
+
return { beep: true };
|
|
9507
|
+
}
|
|
9508
|
+
if (soundType === "custom") {
|
|
9509
|
+
const soundPath = await input({
|
|
9510
|
+
message: "Path to sound file:",
|
|
9511
|
+
validate: (v) => v.trim() ? true : "Please enter a valid path"
|
|
9512
|
+
});
|
|
9513
|
+
return { customSound: soundPath };
|
|
9514
|
+
}
|
|
9515
|
+
const customCommand = await input({
|
|
9516
|
+
message: "Custom command to run:",
|
|
9517
|
+
validate: (v) => v.trim() ? true : "Please enter a command"
|
|
9518
|
+
});
|
|
9519
|
+
return { customCommand };
|
|
9017
9520
|
}
|
|
9018
9521
|
|
|
9019
9522
|
// src/cli/prompts/item-select.ts
|
|
@@ -9127,173 +9630,34 @@ ${progress} ${colors.bold(item.name)}`);
|
|
|
9127
9630
|
return {
|
|
9128
9631
|
category,
|
|
9129
9632
|
selectedItems,
|
|
9130
|
-
skippedItems
|
|
9131
|
-
};
|
|
9132
|
-
}
|
|
9133
|
-
async function promptItemWithShortcuts(item, options) {
|
|
9134
|
-
const choices = [
|
|
9135
|
-
{ name: "Yes, install", value: "install" },
|
|
9136
|
-
{ name: "No, skip", value: "skip" }
|
|
9137
|
-
];
|
|
9138
|
-
if (options.remainingCount > 0) {
|
|
9139
|
-
choices.push(
|
|
9140
|
-
{
|
|
9141
|
-
name: `Install all remaining (${options.remainingCount + 1} items)`,
|
|
9142
|
-
value: "install-rest"
|
|
9143
|
-
},
|
|
9144
|
-
{
|
|
9145
|
-
name: `Skip all remaining (${options.remainingCount + 1} items)`,
|
|
9146
|
-
value: "skip-rest"
|
|
9147
|
-
}
|
|
9148
|
-
);
|
|
9149
|
-
}
|
|
9150
|
-
return select({
|
|
9151
|
-
message: `Install ${item.name}?`,
|
|
9152
|
-
choices,
|
|
9153
|
-
default: options.defaultInstall !== false ? "install" : "skip"
|
|
9154
|
-
});
|
|
9155
|
-
}
|
|
9156
|
-
function capitalize(str) {
|
|
9157
|
-
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
9158
|
-
}
|
|
9159
|
-
|
|
9160
|
-
// src/cli/prompts/hook-config.ts
|
|
9161
|
-
init_esm_shims();
|
|
9162
|
-
async function promptHookConfig(options) {
|
|
9163
|
-
logger.section("Hook Configuration", "\u{1FA9D}");
|
|
9164
|
-
const enableHooks = await confirm({
|
|
9165
|
-
message: "Do you want to configure hooks?",
|
|
9166
|
-
default: true
|
|
9167
|
-
});
|
|
9168
|
-
if (!enableHooks) {
|
|
9169
|
-
return {
|
|
9170
|
-
enabled: false
|
|
9171
|
-
};
|
|
9172
|
-
}
|
|
9173
|
-
const selectedHooks = await checkbox({
|
|
9174
|
-
message: "Which hooks do you want to configure?",
|
|
9175
|
-
choices: [
|
|
9176
|
-
{
|
|
9177
|
-
name: "Notification hook (alerts when Claude needs attention)",
|
|
9178
|
-
value: "notification",
|
|
9179
|
-
checked: true
|
|
9180
|
-
},
|
|
9181
|
-
{
|
|
9182
|
-
name: "Stop hook (plays sound when Claude stops)",
|
|
9183
|
-
value: "stop",
|
|
9184
|
-
checked: false
|
|
9185
|
-
},
|
|
9186
|
-
{
|
|
9187
|
-
name: "Subagent stop hook (plays sound when subagent completes)",
|
|
9188
|
-
value: "subagentStop",
|
|
9189
|
-
checked: false
|
|
9190
|
-
}
|
|
9191
|
-
]
|
|
9192
|
-
});
|
|
9193
|
-
const config = {
|
|
9194
|
-
enabled: true
|
|
9195
|
-
};
|
|
9196
|
-
if (selectedHooks.includes("notification")) {
|
|
9197
|
-
config.notification = await promptNotificationHook(options?.defaults?.notification);
|
|
9198
|
-
}
|
|
9199
|
-
if (selectedHooks.includes("stop")) {
|
|
9200
|
-
config.stop = await promptStopHook();
|
|
9201
|
-
}
|
|
9202
|
-
if (selectedHooks.includes("subagentStop")) {
|
|
9203
|
-
config.subagentStop = await promptSubagentStopHook();
|
|
9204
|
-
}
|
|
9205
|
-
return config;
|
|
9206
|
-
}
|
|
9207
|
-
async function promptNotificationHook(defaults) {
|
|
9208
|
-
logger.newline();
|
|
9209
|
-
logger.info("Notification Hook Configuration");
|
|
9210
|
-
const notificationTypes = await checkbox({
|
|
9211
|
-
message: "Select notification types:",
|
|
9212
|
-
choices: [
|
|
9213
|
-
{
|
|
9214
|
-
name: "Desktop notifications (notify-send / terminal-notifier)",
|
|
9215
|
-
value: "desktop",
|
|
9216
|
-
checked: defaults?.desktop ?? true
|
|
9217
|
-
},
|
|
9218
|
-
{
|
|
9219
|
-
name: "Audio notifications (text-to-speech)",
|
|
9220
|
-
value: "audio",
|
|
9221
|
-
checked: defaults?.audio ?? false
|
|
9222
|
-
}
|
|
9223
|
-
]
|
|
9224
|
-
});
|
|
9225
|
-
let customCommand;
|
|
9226
|
-
const wantCustom = await confirm({
|
|
9227
|
-
message: "Do you want to add a custom notification command?",
|
|
9228
|
-
default: false
|
|
9229
|
-
});
|
|
9230
|
-
if (wantCustom) {
|
|
9231
|
-
customCommand = await input({
|
|
9232
|
-
message: "Custom command (receives notification text as argument):",
|
|
9233
|
-
default: defaults?.customCommand
|
|
9234
|
-
});
|
|
9235
|
-
}
|
|
9236
|
-
return {
|
|
9237
|
-
desktop: notificationTypes.includes("desktop"),
|
|
9238
|
-
audio: notificationTypes.includes("audio"),
|
|
9239
|
-
customCommand: customCommand || void 0
|
|
9633
|
+
skippedItems
|
|
9240
9634
|
};
|
|
9241
9635
|
}
|
|
9242
|
-
async function
|
|
9243
|
-
|
|
9244
|
-
|
|
9245
|
-
|
|
9246
|
-
|
|
9247
|
-
|
|
9248
|
-
|
|
9249
|
-
{
|
|
9250
|
-
|
|
9251
|
-
|
|
9252
|
-
|
|
9253
|
-
|
|
9254
|
-
|
|
9255
|
-
|
|
9256
|
-
|
|
9257
|
-
|
|
9258
|
-
const soundPath = await input({
|
|
9259
|
-
message: "Path to sound file:",
|
|
9260
|
-
validate: (v) => v.trim() ? true : "Please enter a valid path"
|
|
9261
|
-
});
|
|
9262
|
-
return { customSound: soundPath };
|
|
9636
|
+
async function promptItemWithShortcuts(item, options) {
|
|
9637
|
+
const choices = [
|
|
9638
|
+
{ name: "Yes, install", value: "install" },
|
|
9639
|
+
{ name: "No, skip", value: "skip" }
|
|
9640
|
+
];
|
|
9641
|
+
if (options.remainingCount > 0) {
|
|
9642
|
+
choices.push(
|
|
9643
|
+
{
|
|
9644
|
+
name: `Install all remaining (${options.remainingCount + 1} items)`,
|
|
9645
|
+
value: "install-rest"
|
|
9646
|
+
},
|
|
9647
|
+
{
|
|
9648
|
+
name: `Skip all remaining (${options.remainingCount + 1} items)`,
|
|
9649
|
+
value: "skip-rest"
|
|
9650
|
+
}
|
|
9651
|
+
);
|
|
9263
9652
|
}
|
|
9264
|
-
|
|
9265
|
-
message:
|
|
9266
|
-
|
|
9653
|
+
return select({
|
|
9654
|
+
message: `Install ${item.name}?`,
|
|
9655
|
+
choices,
|
|
9656
|
+
default: options.defaultInstall !== false ? "install" : "skip"
|
|
9267
9657
|
});
|
|
9268
|
-
return { customCommand };
|
|
9269
9658
|
}
|
|
9270
|
-
|
|
9271
|
-
|
|
9272
|
-
logger.info("Subagent Stop Hook Configuration");
|
|
9273
|
-
const soundType = await select({
|
|
9274
|
-
message: "What should happen when a subagent completes?",
|
|
9275
|
-
choices: [
|
|
9276
|
-
{ name: "Play short beep", value: "beep" },
|
|
9277
|
-
{ name: "Play custom sound", value: "custom" },
|
|
9278
|
-
{ name: "Run custom command", value: "command" }
|
|
9279
|
-
],
|
|
9280
|
-
default: "beep"
|
|
9281
|
-
});
|
|
9282
|
-
if (soundType === "beep") {
|
|
9283
|
-
return { beep: true };
|
|
9284
|
-
}
|
|
9285
|
-
if (soundType === "custom") {
|
|
9286
|
-
const soundPath = await input({
|
|
9287
|
-
message: "Path to sound file:",
|
|
9288
|
-
validate: (v) => v.trim() ? true : "Please enter a valid path"
|
|
9289
|
-
});
|
|
9290
|
-
return { customSound: soundPath };
|
|
9291
|
-
}
|
|
9292
|
-
const customCommand = await input({
|
|
9293
|
-
message: "Custom command to run:",
|
|
9294
|
-
validate: (v) => v.trim() ? true : "Please enter a command"
|
|
9295
|
-
});
|
|
9296
|
-
return { customCommand };
|
|
9659
|
+
function capitalize(str) {
|
|
9660
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
9297
9661
|
}
|
|
9298
9662
|
|
|
9299
9663
|
// src/cli/prompts/mcp-config.ts
|
|
@@ -9798,1178 +10162,1480 @@ async function promptCustomPermissions(defaults) {
|
|
|
9798
10162
|
if (rule.trim()) {
|
|
9799
10163
|
deny.push(rule.trim());
|
|
9800
10164
|
}
|
|
9801
|
-
addMoreDeny = await confirm({
|
|
9802
|
-
message: "Add another deny rule?",
|
|
9803
|
-
default: false
|
|
9804
|
-
});
|
|
10165
|
+
addMoreDeny = await confirm({
|
|
10166
|
+
message: "Add another deny rule?",
|
|
10167
|
+
default: false
|
|
10168
|
+
});
|
|
10169
|
+
}
|
|
10170
|
+
return { allow, deny };
|
|
10171
|
+
}
|
|
10172
|
+
|
|
10173
|
+
// src/cli/prompts/preferences.ts
|
|
10174
|
+
init_esm_shims();
|
|
10175
|
+
async function promptPreferences(options) {
|
|
10176
|
+
logger.section("Preferences", "\u2699\uFE0F");
|
|
10177
|
+
const language = await select({
|
|
10178
|
+
message: "Working language (for documentation and comments):",
|
|
10179
|
+
choices: [
|
|
10180
|
+
{ name: "English", value: "en" },
|
|
10181
|
+
{ name: "Espa\xF1ol", value: "es" }
|
|
10182
|
+
],
|
|
10183
|
+
default: options?.defaults?.language || "en"
|
|
10184
|
+
});
|
|
10185
|
+
const responseLanguage = await select({
|
|
10186
|
+
message: "Claude response language:",
|
|
10187
|
+
choices: [
|
|
10188
|
+
{ name: "English", value: "en" },
|
|
10189
|
+
{ name: "Espa\xF1ol", value: "es" }
|
|
10190
|
+
],
|
|
10191
|
+
default: options?.defaults?.responseLanguage || language
|
|
10192
|
+
});
|
|
10193
|
+
const includeCoAuthor = await confirm({
|
|
10194
|
+
message: "Include Claude as commit co-author?",
|
|
10195
|
+
default: options?.defaults?.includeCoAuthor ?? true
|
|
10196
|
+
});
|
|
10197
|
+
const packageManager = await promptPackageManagerPreference(options?.detectedPackageManager);
|
|
10198
|
+
return {
|
|
10199
|
+
language,
|
|
10200
|
+
responseLanguage,
|
|
10201
|
+
includeCoAuthor,
|
|
10202
|
+
packageManager
|
|
10203
|
+
};
|
|
10204
|
+
}
|
|
10205
|
+
async function promptPackageManagerPreference(detected) {
|
|
10206
|
+
const choices = [
|
|
10207
|
+
{
|
|
10208
|
+
name: "pnpm (recommended)",
|
|
10209
|
+
value: "pnpm",
|
|
10210
|
+
description: "Fast, disk space efficient package manager"
|
|
10211
|
+
},
|
|
10212
|
+
{
|
|
10213
|
+
name: "npm",
|
|
10214
|
+
value: "npm",
|
|
10215
|
+
description: "Node.js default package manager"
|
|
10216
|
+
},
|
|
10217
|
+
{
|
|
10218
|
+
name: "yarn",
|
|
10219
|
+
value: "yarn",
|
|
10220
|
+
description: "Fast, reliable dependency management"
|
|
10221
|
+
},
|
|
10222
|
+
{
|
|
10223
|
+
name: "bun",
|
|
10224
|
+
value: "bun",
|
|
10225
|
+
description: "All-in-one JavaScript runtime & toolkit"
|
|
10226
|
+
}
|
|
10227
|
+
];
|
|
10228
|
+
if (detected) {
|
|
10229
|
+
const detectedChoice = choices.find((c) => c.value === detected);
|
|
10230
|
+
if (detectedChoice) {
|
|
10231
|
+
detectedChoice.name = `${detectedChoice.name} (detected)`;
|
|
10232
|
+
}
|
|
10233
|
+
}
|
|
10234
|
+
return select({
|
|
10235
|
+
message: "Preferred package manager:",
|
|
10236
|
+
choices,
|
|
10237
|
+
default: detected || "pnpm"
|
|
10238
|
+
});
|
|
10239
|
+
}
|
|
10240
|
+
|
|
10241
|
+
// src/cli/prompts/project-info.ts
|
|
10242
|
+
init_esm_shims();
|
|
10243
|
+
async function promptProjectInfo(options) {
|
|
10244
|
+
logger.section("Project Information", "\u{1F4CB}");
|
|
10245
|
+
const name = await input({
|
|
10246
|
+
message: "Project name:",
|
|
10247
|
+
default: options?.defaults?.name,
|
|
10248
|
+
validate: (value) => {
|
|
10249
|
+
if (!value.trim()) return "Project name is required";
|
|
10250
|
+
if (!/^[a-zA-Z0-9-_\s]+$/.test(value)) {
|
|
10251
|
+
return "Project name can only contain letters, numbers, dashes, underscores, and spaces";
|
|
10252
|
+
}
|
|
10253
|
+
return true;
|
|
10254
|
+
}
|
|
10255
|
+
});
|
|
10256
|
+
const description = await input({
|
|
10257
|
+
message: "Project description:",
|
|
10258
|
+
default: options?.defaults?.description || "",
|
|
10259
|
+
validate: (value) => {
|
|
10260
|
+
if (!value.trim()) return "Description is required";
|
|
10261
|
+
return true;
|
|
10262
|
+
}
|
|
10263
|
+
});
|
|
10264
|
+
const org = await input({
|
|
10265
|
+
message: "GitHub organization/username:",
|
|
10266
|
+
default: options?.defaults?.org || "",
|
|
10267
|
+
validate: (value) => {
|
|
10268
|
+
if (!value.trim()) return "Organization is required";
|
|
10269
|
+
if (!/^[a-zA-Z0-9-]+$/.test(value)) {
|
|
10270
|
+
return "Organization can only contain letters, numbers, and dashes";
|
|
10271
|
+
}
|
|
10272
|
+
return true;
|
|
10273
|
+
}
|
|
10274
|
+
});
|
|
10275
|
+
const repo = await input({
|
|
10276
|
+
message: "Repository name:",
|
|
10277
|
+
default: options?.defaults?.repo || name.toLowerCase().replace(/\s+/g, "-"),
|
|
10278
|
+
validate: (value) => {
|
|
10279
|
+
if (!value.trim()) return "Repository name is required";
|
|
10280
|
+
if (!/^[a-zA-Z0-9-_]+$/.test(value)) {
|
|
10281
|
+
return "Repository name can only contain letters, numbers, dashes, and underscores";
|
|
10282
|
+
}
|
|
10283
|
+
return true;
|
|
10284
|
+
}
|
|
10285
|
+
});
|
|
10286
|
+
const author = await input({
|
|
10287
|
+
message: 'Author (name or "Name <email>"):',
|
|
10288
|
+
default: options?.defaults?.author || ""
|
|
10289
|
+
});
|
|
10290
|
+
let entityType = "item";
|
|
10291
|
+
let entityTypePlural = "items";
|
|
10292
|
+
const wantEntityConfig = await confirm({
|
|
10293
|
+
message: "Configure primary entity type? (Used for code examples and templates)",
|
|
10294
|
+
default: false
|
|
10295
|
+
});
|
|
10296
|
+
if (wantEntityConfig) {
|
|
10297
|
+
logger.info("The entity type is used in code examples and templates throughout the project.");
|
|
10298
|
+
logger.info(
|
|
10299
|
+
'For example, if your project manages "products", code examples will use product-related names.'
|
|
10300
|
+
);
|
|
10301
|
+
logger.newline();
|
|
10302
|
+
entityType = await input({
|
|
10303
|
+
message: "Primary entity type (e.g., product, article, user, listing):",
|
|
10304
|
+
default: options?.defaults?.entityType || "item",
|
|
10305
|
+
validate: (value) => {
|
|
10306
|
+
if (!value.trim()) return "Entity type is required";
|
|
10307
|
+
return true;
|
|
10308
|
+
}
|
|
10309
|
+
});
|
|
10310
|
+
entityTypePlural = await input({
|
|
10311
|
+
message: "Entity type plural:",
|
|
10312
|
+
default: options?.defaults?.entityTypePlural || pluralize(entityType)
|
|
10313
|
+
});
|
|
10314
|
+
} else if (options?.defaults?.entityType) {
|
|
10315
|
+
entityType = options.defaults.entityType;
|
|
10316
|
+
entityTypePlural = options.defaults.entityTypePlural || pluralize(entityType);
|
|
10317
|
+
}
|
|
10318
|
+
let domain;
|
|
10319
|
+
let location;
|
|
10320
|
+
if (!options?.skipOptional) {
|
|
10321
|
+
const wantDomain = await confirm({
|
|
10322
|
+
message: "Do you want to specify a domain?",
|
|
10323
|
+
default: false
|
|
10324
|
+
});
|
|
10325
|
+
if (wantDomain) {
|
|
10326
|
+
domain = await input({
|
|
10327
|
+
message: "Domain (e.g., myproject.com):",
|
|
10328
|
+
default: options?.defaults?.domain || "",
|
|
10329
|
+
validate: (value) => {
|
|
10330
|
+
if (value && !/^[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(value)) {
|
|
10331
|
+
return "Please enter a valid domain";
|
|
10332
|
+
}
|
|
10333
|
+
return true;
|
|
10334
|
+
}
|
|
10335
|
+
});
|
|
10336
|
+
}
|
|
10337
|
+
const wantLocation = await confirm({
|
|
10338
|
+
message: "Do you want to specify a location/region?",
|
|
10339
|
+
default: false
|
|
10340
|
+
});
|
|
10341
|
+
if (wantLocation) {
|
|
10342
|
+
location = await input({
|
|
10343
|
+
message: "Location/Region:",
|
|
10344
|
+
default: options?.defaults?.location || ""
|
|
10345
|
+
});
|
|
10346
|
+
}
|
|
9805
10347
|
}
|
|
9806
|
-
return {
|
|
10348
|
+
return {
|
|
10349
|
+
name: name.trim(),
|
|
10350
|
+
description: description.trim(),
|
|
10351
|
+
org: org.trim(),
|
|
10352
|
+
repo: repo.trim(),
|
|
10353
|
+
domain,
|
|
10354
|
+
entityType: entityType.trim().toLowerCase(),
|
|
10355
|
+
entityTypePlural: entityTypePlural.trim().toLowerCase(),
|
|
10356
|
+
location,
|
|
10357
|
+
author: author.trim() || void 0
|
|
10358
|
+
};
|
|
10359
|
+
}
|
|
10360
|
+
function pluralize(word) {
|
|
10361
|
+
const lower = word.toLowerCase();
|
|
10362
|
+
if (lower.endsWith("y")) {
|
|
10363
|
+
return `${lower.slice(0, -1)}ies`;
|
|
10364
|
+
}
|
|
10365
|
+
if (lower.endsWith("s") || lower.endsWith("x") || lower.endsWith("ch") || lower.endsWith("sh")) {
|
|
10366
|
+
return `${lower}es`;
|
|
10367
|
+
}
|
|
10368
|
+
return `${lower}s`;
|
|
10369
|
+
}
|
|
10370
|
+
async function confirmProjectInfo(info) {
|
|
10371
|
+
logger.newline();
|
|
10372
|
+
logger.subtitle("Project Summary");
|
|
10373
|
+
logger.keyValue("Name", info.name);
|
|
10374
|
+
logger.keyValue("Description", info.description);
|
|
10375
|
+
logger.keyValue("GitHub", `${info.org}/${info.repo}`);
|
|
10376
|
+
if (info.author) logger.keyValue("Author", info.author);
|
|
10377
|
+
logger.keyValue("Entity", `${info.entityType} / ${info.entityTypePlural}`);
|
|
10378
|
+
if (info.domain) logger.keyValue("Domain", info.domain);
|
|
10379
|
+
if (info.location) logger.keyValue("Location", info.location);
|
|
10380
|
+
logger.newline();
|
|
10381
|
+
return confirm({
|
|
10382
|
+
message: "Is this information correct?",
|
|
10383
|
+
default: true
|
|
10384
|
+
});
|
|
9807
10385
|
}
|
|
9808
10386
|
|
|
9809
|
-
// src/cli/prompts/
|
|
10387
|
+
// src/cli/prompts/scaffold.ts
|
|
9810
10388
|
init_esm_shims();
|
|
9811
|
-
async function
|
|
9812
|
-
logger.
|
|
10389
|
+
async function promptScaffoldType(options) {
|
|
10390
|
+
logger.section("Configuration Scope", "\u{1F3D7}\uFE0F");
|
|
10391
|
+
if (options?.existingProject) {
|
|
10392
|
+
logger.info("Existing project detected");
|
|
10393
|
+
logger.newline();
|
|
10394
|
+
const choice = await select({
|
|
10395
|
+
message: "What would you like to do?",
|
|
10396
|
+
choices: [
|
|
10397
|
+
{
|
|
10398
|
+
name: "Add Claude config only (recommended)",
|
|
10399
|
+
value: "claude-only",
|
|
10400
|
+
description: "Creates .claude/ folder without touching existing files"
|
|
10401
|
+
},
|
|
10402
|
+
{
|
|
10403
|
+
name: "Full project setup (\u26A0\uFE0F may overwrite files)",
|
|
10404
|
+
value: "full-project",
|
|
10405
|
+
description: "Includes project scaffolding - use with caution"
|
|
10406
|
+
}
|
|
10407
|
+
],
|
|
10408
|
+
default: "claude-only"
|
|
10409
|
+
});
|
|
10410
|
+
if (choice === "full-project") {
|
|
10411
|
+
const confirmed = await confirm({
|
|
10412
|
+
message: "\u26A0\uFE0F This may overwrite existing files. Are you sure?",
|
|
10413
|
+
default: false
|
|
10414
|
+
});
|
|
10415
|
+
if (!confirmed) {
|
|
10416
|
+
return "claude-only";
|
|
10417
|
+
}
|
|
10418
|
+
}
|
|
10419
|
+
return choice;
|
|
10420
|
+
}
|
|
9813
10421
|
return select({
|
|
9814
|
-
message: "What would you like to
|
|
10422
|
+
message: "What would you like to configure?",
|
|
9815
10423
|
choices: [
|
|
9816
10424
|
{
|
|
9817
|
-
name: "
|
|
9818
|
-
value: "
|
|
9819
|
-
description: "
|
|
9820
|
-
},
|
|
9821
|
-
{
|
|
9822
|
-
name: "Update modules only",
|
|
9823
|
-
value: "modules",
|
|
9824
|
-
description: "Update agents, skills, commands, docs"
|
|
9825
|
-
},
|
|
9826
|
-
{
|
|
9827
|
-
name: "Reconfigure settings",
|
|
9828
|
-
value: "config",
|
|
9829
|
-
description: "Re-run configuration for MCP, hooks, preferences"
|
|
9830
|
-
},
|
|
9831
|
-
{
|
|
9832
|
-
name: "Full update",
|
|
9833
|
-
value: "all",
|
|
9834
|
-
description: "Update everything"
|
|
10425
|
+
name: "Claude configuration only",
|
|
10426
|
+
value: "claude-only",
|
|
10427
|
+
description: "Only creates .claude/ folder with agents, commands, skills, docs"
|
|
9835
10428
|
},
|
|
9836
10429
|
{
|
|
9837
|
-
name: "
|
|
9838
|
-
value: "
|
|
10430
|
+
name: "Full project setup",
|
|
10431
|
+
value: "full-project",
|
|
10432
|
+
description: "Creates project structure + Claude configuration"
|
|
9839
10433
|
}
|
|
9840
10434
|
],
|
|
9841
|
-
default: "
|
|
10435
|
+
default: "claude-only"
|
|
9842
10436
|
});
|
|
9843
10437
|
}
|
|
9844
|
-
function
|
|
9845
|
-
|
|
9846
|
-
|
|
9847
|
-
|
|
9848
|
-
|
|
9849
|
-
|
|
9850
|
-
|
|
9851
|
-
|
|
9852
|
-
|
|
9853
|
-
|
|
9854
|
-
|
|
9855
|
-
|
|
9856
|
-
|
|
9857
|
-
|
|
9858
|
-
|
|
9859
|
-
|
|
9860
|
-
|
|
9861
|
-
|
|
9862
|
-
|
|
9863
|
-
|
|
9864
|
-
|
|
9865
|
-
|
|
9866
|
-
|
|
9867
|
-
|
|
9868
|
-
|
|
9869
|
-
|
|
9870
|
-
|
|
10438
|
+
async function promptProjectType(detectedType) {
|
|
10439
|
+
const choices = [
|
|
10440
|
+
{
|
|
10441
|
+
name: "Node.js (TypeScript)",
|
|
10442
|
+
value: "node",
|
|
10443
|
+
description: "Basic Node.js project with TypeScript"
|
|
10444
|
+
},
|
|
10445
|
+
{
|
|
10446
|
+
name: "Monorepo (TurboRepo + pnpm)",
|
|
10447
|
+
value: "monorepo",
|
|
10448
|
+
description: "Multi-package monorepo setup"
|
|
10449
|
+
},
|
|
10450
|
+
{
|
|
10451
|
+
name: "Astro",
|
|
10452
|
+
value: "astro",
|
|
10453
|
+
description: "Astro static/SSR site"
|
|
10454
|
+
},
|
|
10455
|
+
{
|
|
10456
|
+
name: "Next.js",
|
|
10457
|
+
value: "nextjs",
|
|
10458
|
+
description: "Next.js full-stack React framework"
|
|
10459
|
+
},
|
|
10460
|
+
{
|
|
10461
|
+
name: "Vite + React",
|
|
10462
|
+
value: "vite-react",
|
|
10463
|
+
description: "Vite bundled React SPA"
|
|
10464
|
+
},
|
|
10465
|
+
{
|
|
10466
|
+
name: "Hono API",
|
|
10467
|
+
value: "hono",
|
|
10468
|
+
description: "Hono lightweight API server"
|
|
10469
|
+
},
|
|
10470
|
+
{
|
|
10471
|
+
name: "Custom",
|
|
10472
|
+
value: "custom",
|
|
10473
|
+
description: "Define your own project structure"
|
|
9871
10474
|
}
|
|
9872
|
-
|
|
9873
|
-
if (
|
|
9874
|
-
|
|
9875
|
-
|
|
9876
|
-
|
|
9877
|
-
logger.item(`${mod.category}: ${colors.warning(mod.name)} - has local modifications`);
|
|
10475
|
+
];
|
|
10476
|
+
if (detectedType) {
|
|
10477
|
+
const detected = choices.find((c) => c.value === detectedType);
|
|
10478
|
+
if (detected) {
|
|
10479
|
+
detected.name = `${detected.name} (detected)`;
|
|
9878
10480
|
}
|
|
9879
10481
|
}
|
|
9880
|
-
|
|
9881
|
-
|
|
9882
|
-
|
|
9883
|
-
|
|
9884
|
-
const choices = modules.map((mod) => ({
|
|
9885
|
-
name: `${mod.category}: ${mod.name}`,
|
|
9886
|
-
value: mod.id,
|
|
9887
|
-
checked: false
|
|
9888
|
-
}));
|
|
9889
|
-
return checkbox({
|
|
9890
|
-
message: "Select new modules to install:",
|
|
9891
|
-
choices
|
|
9892
|
-
});
|
|
9893
|
-
}
|
|
9894
|
-
async function promptUpdatedModules(modules) {
|
|
9895
|
-
if (modules.length === 0) return [];
|
|
9896
|
-
logger.newline();
|
|
9897
|
-
const choices = modules.map((mod) => ({
|
|
9898
|
-
name: `${mod.category}: ${mod.name}${mod.hasLocalChanges ? " \u26A0\uFE0F" : ""}`,
|
|
9899
|
-
value: mod.id,
|
|
9900
|
-
checked: !mod.hasLocalChanges
|
|
9901
|
-
// Don't check by default if has local changes
|
|
9902
|
-
}));
|
|
9903
|
-
return checkbox({
|
|
9904
|
-
message: "Select modules to update:",
|
|
9905
|
-
choices
|
|
10482
|
+
return select({
|
|
10483
|
+
message: "Project type:",
|
|
10484
|
+
choices,
|
|
10485
|
+
default: detectedType || "node"
|
|
9906
10486
|
});
|
|
9907
10487
|
}
|
|
9908
|
-
async function
|
|
9909
|
-
|
|
9910
|
-
|
|
10488
|
+
async function promptPackageManager(detected) {
|
|
10489
|
+
const choices = [
|
|
10490
|
+
{ name: "pnpm (recommended)", value: "pnpm" },
|
|
10491
|
+
{ name: "npm", value: "npm" },
|
|
10492
|
+
{ name: "yarn", value: "yarn" },
|
|
10493
|
+
{ name: "bun", value: "bun" }
|
|
10494
|
+
];
|
|
10495
|
+
if (detected) {
|
|
10496
|
+
const detectedChoice = choices.find((c) => c.value === detected);
|
|
10497
|
+
if (detectedChoice) {
|
|
10498
|
+
detectedChoice.name = `${detectedChoice.name} (detected)`;
|
|
10499
|
+
}
|
|
10500
|
+
}
|
|
9911
10501
|
return select({
|
|
9912
|
-
message: "
|
|
9913
|
-
choices
|
|
9914
|
-
|
|
9915
|
-
name: "Keep local version",
|
|
9916
|
-
value: "keep",
|
|
9917
|
-
description: "Do not update this module"
|
|
9918
|
-
},
|
|
9919
|
-
{
|
|
9920
|
-
name: "Use updated version",
|
|
9921
|
-
value: "update",
|
|
9922
|
-
description: "Replace with new version (lose local changes)"
|
|
9923
|
-
},
|
|
9924
|
-
{
|
|
9925
|
-
name: "Show diff",
|
|
9926
|
-
value: "diff",
|
|
9927
|
-
description: "See what changed before deciding"
|
|
9928
|
-
}
|
|
9929
|
-
],
|
|
9930
|
-
default: "keep"
|
|
10502
|
+
message: "Package manager:",
|
|
10503
|
+
choices,
|
|
10504
|
+
default: detected || "pnpm"
|
|
9931
10505
|
});
|
|
9932
10506
|
}
|
|
9933
|
-
async function
|
|
10507
|
+
async function promptScaffoldOptions(options) {
|
|
10508
|
+
const type = await promptScaffoldType(options);
|
|
10509
|
+
if (type === "claude-only") {
|
|
10510
|
+
return { type };
|
|
10511
|
+
}
|
|
10512
|
+
const projectType = await promptProjectType(options?.detectedType);
|
|
10513
|
+
const packageManager = await promptPackageManager(options?.detectedPackageManager);
|
|
9934
10514
|
logger.newline();
|
|
9935
|
-
|
|
9936
|
-
|
|
10515
|
+
logger.subtitle("Additional Options");
|
|
10516
|
+
const additionalOptions = await checkbox({
|
|
10517
|
+
message: "Select additional options:",
|
|
9937
10518
|
choices: [
|
|
9938
|
-
{ name: "
|
|
9939
|
-
{ name: "
|
|
9940
|
-
{ name: "
|
|
9941
|
-
{ name: "Permissions", value: "permissions", checked: false },
|
|
9942
|
-
{ name: "Add/remove modules", value: "modules", checked: false }
|
|
10519
|
+
{ name: "Initialize git repository", value: "initGit", checked: true },
|
|
10520
|
+
{ name: "Create README.md", value: "createReadme", checked: true },
|
|
10521
|
+
{ name: "Create .gitignore", value: "createGitignore", checked: true }
|
|
9943
10522
|
]
|
|
9944
10523
|
});
|
|
10524
|
+
return {
|
|
10525
|
+
type,
|
|
10526
|
+
projectType,
|
|
10527
|
+
packageManager,
|
|
10528
|
+
initGit: additionalOptions.includes("initGit"),
|
|
10529
|
+
createReadme: additionalOptions.includes("createReadme"),
|
|
10530
|
+
createGitignore: additionalOptions.includes("createGitignore")
|
|
10531
|
+
};
|
|
9945
10532
|
}
|
|
9946
10533
|
|
|
9947
|
-
// src/cli/prompts/
|
|
10534
|
+
// src/cli/prompts/template-config.ts
|
|
9948
10535
|
init_esm_shims();
|
|
9949
|
-
|
|
9950
|
-
|
|
9951
|
-
|
|
10536
|
+
var CATEGORY_INFO = {
|
|
10537
|
+
commands: { name: "CLI Commands", order: 1 },
|
|
10538
|
+
paths: { name: "Directory Paths", order: 2 },
|
|
10539
|
+
targets: { name: "Quality Targets", order: 3 },
|
|
10540
|
+
tracking: { name: "Issue Tracking", order: 4 },
|
|
10541
|
+
techStack: { name: "Technology Stack", order: 5 },
|
|
10542
|
+
performance: { name: "Performance Targets", order: 6 },
|
|
10543
|
+
environment: { name: "Environment Variables", order: 7 },
|
|
10544
|
+
brand: { name: "Brand Identity", order: 8 }
|
|
10545
|
+
};
|
|
10546
|
+
async function promptSetupMode() {
|
|
10547
|
+
const mode = await select({
|
|
10548
|
+
message: "Configuration mode:",
|
|
9952
10549
|
choices: [
|
|
9953
10550
|
{
|
|
9954
|
-
name: "
|
|
9955
|
-
value: "
|
|
9956
|
-
description: "
|
|
10551
|
+
name: "Quick Setup (recommended)",
|
|
10552
|
+
value: "quick",
|
|
10553
|
+
description: "Auto-detect values, confirm all at once"
|
|
9957
10554
|
},
|
|
9958
10555
|
{
|
|
9959
|
-
name: "
|
|
9960
|
-
value: "
|
|
9961
|
-
description: "
|
|
10556
|
+
name: "Guided Setup",
|
|
10557
|
+
value: "guided",
|
|
10558
|
+
description: "Step through each category"
|
|
9962
10559
|
},
|
|
9963
10560
|
{
|
|
9964
|
-
name: "
|
|
9965
|
-
value: "
|
|
9966
|
-
description: "
|
|
10561
|
+
name: "Advanced Setup",
|
|
10562
|
+
value: "advanced",
|
|
10563
|
+
description: "Configure all options individually"
|
|
9967
10564
|
}
|
|
9968
10565
|
],
|
|
9969
|
-
default: "
|
|
9970
|
-
});
|
|
9971
|
-
}
|
|
9972
|
-
function showFinalSummary(config) {
|
|
9973
|
-
logger.newline();
|
|
9974
|
-
logger.title("Configuration Summary");
|
|
9975
|
-
logger.subtitle("Project");
|
|
9976
|
-
logger.keyValue("Name", config.project.name);
|
|
9977
|
-
logger.keyValue("GitHub", `${config.project.org}/${config.project.repo}`);
|
|
9978
|
-
if (config.project.domain) {
|
|
9979
|
-
logger.keyValue("Domain", config.project.domain);
|
|
9980
|
-
}
|
|
9981
|
-
logger.newline();
|
|
9982
|
-
logger.subtitle("Preferences");
|
|
9983
|
-
logger.keyValue("Language", config.preferences.language === "en" ? "English" : "Espa\xF1ol");
|
|
9984
|
-
logger.keyValue("Co-author", config.preferences.includeCoAuthor ? "Yes" : "No");
|
|
9985
|
-
logger.newline();
|
|
9986
|
-
logger.subtitle("Modules");
|
|
9987
|
-
const moduleCategories = ["agents", "skills", "commands", "docs"];
|
|
9988
|
-
for (const category of moduleCategories) {
|
|
9989
|
-
const selected = config.modules[category].selected;
|
|
9990
|
-
if (selected.length > 0) {
|
|
9991
|
-
logger.keyValue(capitalize2(category), `${selected.length} selected`);
|
|
9992
|
-
logger.note(selected.join(", "));
|
|
9993
|
-
}
|
|
9994
|
-
}
|
|
9995
|
-
logger.newline();
|
|
9996
|
-
logger.subtitle("Extras");
|
|
9997
|
-
const extras = [];
|
|
9998
|
-
if (config.extras.schemas) extras.push("schemas");
|
|
9999
|
-
if (config.extras.scripts) extras.push("scripts");
|
|
10000
|
-
if (config.extras.hooks.enabled) extras.push("hooks");
|
|
10001
|
-
if (config.extras.sessions) extras.push("sessions");
|
|
10002
|
-
logger.keyValue("Included", extras.join(", ") || "none");
|
|
10003
|
-
if (config.extras.codeStyle?.enabled) {
|
|
10004
|
-
const codeStyleTools = [];
|
|
10005
|
-
if (config.extras.codeStyle.editorconfig) codeStyleTools.push("EditorConfig");
|
|
10006
|
-
if (config.extras.codeStyle.commitlint) codeStyleTools.push("Commitlint");
|
|
10007
|
-
if (config.extras.codeStyle.biome) codeStyleTools.push("Biome");
|
|
10008
|
-
if (config.extras.codeStyle.prettier) codeStyleTools.push("Prettier");
|
|
10009
|
-
logger.keyValue("Code Style", codeStyleTools.join(", "));
|
|
10010
|
-
}
|
|
10011
|
-
if (config.mcp.servers.length > 0) {
|
|
10012
|
-
logger.newline();
|
|
10013
|
-
logger.subtitle("MCP Servers");
|
|
10014
|
-
logger.keyValue("Level", config.mcp.level);
|
|
10015
|
-
logger.keyValue("Servers", config.mcp.servers.map((s) => s.serverId).join(", "));
|
|
10016
|
-
}
|
|
10017
|
-
logger.newline();
|
|
10018
|
-
logger.subtitle("Scaffold");
|
|
10019
|
-
logger.keyValue(
|
|
10020
|
-
"Type",
|
|
10021
|
-
config.scaffold.type === "claude-only" ? "Claude config only" : "Full project"
|
|
10022
|
-
);
|
|
10023
|
-
}
|
|
10024
|
-
async function confirmFinalConfiguration(config) {
|
|
10025
|
-
showFinalSummary(config);
|
|
10026
|
-
logger.newline();
|
|
10027
|
-
return confirm({
|
|
10028
|
-
message: "Proceed with this configuration?",
|
|
10029
|
-
default: true
|
|
10566
|
+
default: "quick"
|
|
10030
10567
|
});
|
|
10568
|
+
return mode;
|
|
10031
10569
|
}
|
|
10032
|
-
function
|
|
10033
|
-
|
|
10034
|
-
|
|
10035
|
-
|
|
10036
|
-
|
|
10037
|
-
|
|
10038
|
-
|
|
10039
|
-
|
|
10040
|
-
|
|
10041
|
-
|
|
10042
|
-
const
|
|
10043
|
-
|
|
10044
|
-
|
|
10045
|
-
|
|
10046
|
-
|
|
10047
|
-
if (config.extras.hooks.notification?.audio) {
|
|
10048
|
-
steps.push("Install Piper TTS for audio notifications (see docs)");
|
|
10049
|
-
}
|
|
10050
|
-
}
|
|
10051
|
-
logger.instructions("Next Steps:", steps);
|
|
10052
|
-
logger.subtitle("Useful Commands");
|
|
10053
|
-
logger.raw("");
|
|
10054
|
-
logger.raw(` ${colors.primary("claude-config status")} - Show current configuration`);
|
|
10055
|
-
logger.raw(` ${colors.primary("claude-config list")} - List available modules`);
|
|
10056
|
-
logger.raw(` ${colors.primary("claude-config add")} - Add a module`);
|
|
10057
|
-
logger.raw(` ${colors.primary("claude-config update")} - Update configuration`);
|
|
10058
|
-
logger.raw("");
|
|
10059
|
-
}
|
|
10060
|
-
function capitalize2(str) {
|
|
10061
|
-
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
10062
|
-
}
|
|
10063
|
-
|
|
10064
|
-
// src/cli/prompts/code-style.ts
|
|
10065
|
-
init_esm_shims();
|
|
10066
|
-
var CODE_STYLE_TOOLS = [
|
|
10067
|
-
{
|
|
10068
|
-
name: "EditorConfig",
|
|
10069
|
-
value: "editorconfig",
|
|
10070
|
-
description: "Consistent coding styles across editors",
|
|
10071
|
-
checked: true
|
|
10072
|
-
},
|
|
10073
|
-
{
|
|
10074
|
-
name: "Commitlint",
|
|
10075
|
-
value: "commitlint",
|
|
10076
|
-
description: "Lint commit messages (conventional commits)",
|
|
10077
|
-
checked: true
|
|
10078
|
-
},
|
|
10079
|
-
{
|
|
10080
|
-
name: "Biome",
|
|
10081
|
-
value: "biome",
|
|
10082
|
-
description: "Fast linter and formatter (ESLint + Prettier alternative)",
|
|
10083
|
-
checked: false
|
|
10084
|
-
},
|
|
10085
|
-
{
|
|
10086
|
-
name: "Prettier",
|
|
10087
|
-
value: "prettier",
|
|
10088
|
-
description: "Code formatter (use if not using Biome)",
|
|
10089
|
-
checked: false
|
|
10090
|
-
}
|
|
10091
|
-
];
|
|
10092
|
-
async function promptCodeStyleConfig(options) {
|
|
10093
|
-
logger.section("Code Style", "\u{1F3A8}");
|
|
10094
|
-
logger.info("Configure code formatting and linting tools");
|
|
10095
|
-
logger.newline();
|
|
10096
|
-
const enableCodeStyle = await confirm({
|
|
10097
|
-
message: "Would you like to install code style configuration files?",
|
|
10098
|
-
default: true
|
|
10099
|
-
});
|
|
10100
|
-
if (!enableCodeStyle) {
|
|
10101
|
-
return {
|
|
10102
|
-
enabled: false,
|
|
10103
|
-
editorconfig: false,
|
|
10104
|
-
commitlint: false,
|
|
10105
|
-
biome: false,
|
|
10106
|
-
prettier: false
|
|
10570
|
+
async function buildConfigContext(projectPath) {
|
|
10571
|
+
const context = {
|
|
10572
|
+
projectPath,
|
|
10573
|
+
values: {}
|
|
10574
|
+
};
|
|
10575
|
+
try {
|
|
10576
|
+
const fs6 = await import("fs/promises");
|
|
10577
|
+
const path8 = await import("path");
|
|
10578
|
+
const pkgPath = path8.join(projectPath, "package.json");
|
|
10579
|
+
const pkgContent = await fs6.readFile(pkgPath, "utf-8");
|
|
10580
|
+
const pkg = JSON.parse(pkgContent);
|
|
10581
|
+
context.scripts = pkg.scripts || {};
|
|
10582
|
+
context.dependencies = {
|
|
10583
|
+
...pkg.dependencies || {},
|
|
10584
|
+
...pkg.devDependencies || {}
|
|
10107
10585
|
};
|
|
10108
|
-
|
|
10109
|
-
|
|
10110
|
-
|
|
10111
|
-
|
|
10112
|
-
|
|
10113
|
-
|
|
10114
|
-
|
|
10115
|
-
}
|
|
10116
|
-
|
|
10117
|
-
|
|
10118
|
-
|
|
10119
|
-
|
|
10120
|
-
|
|
10121
|
-
|
|
10122
|
-
|
|
10123
|
-
|
|
10124
|
-
|
|
10125
|
-
|
|
10126
|
-
|
|
10127
|
-
|
|
10128
|
-
|
|
10129
|
-
]
|
|
10130
|
-
});
|
|
10131
|
-
const indexToRemove = preferred === "biome" ? selectedTools.indexOf("prettier") : selectedTools.indexOf("biome");
|
|
10132
|
-
if (indexToRemove > -1) {
|
|
10133
|
-
selectedTools.splice(indexToRemove, 1);
|
|
10586
|
+
context.hasTypeScript = Boolean(context.dependencies.typescript) || await fileExists(path8.join(projectPath, "tsconfig.json"));
|
|
10587
|
+
if (await fileExists(path8.join(projectPath, "pnpm-lock.yaml"))) {
|
|
10588
|
+
context.packageManager = "pnpm";
|
|
10589
|
+
} else if (await fileExists(path8.join(projectPath, "yarn.lock"))) {
|
|
10590
|
+
context.packageManager = "yarn";
|
|
10591
|
+
} else if (await fileExists(path8.join(projectPath, "bun.lockb"))) {
|
|
10592
|
+
context.packageManager = "bun";
|
|
10593
|
+
} else {
|
|
10594
|
+
context.packageManager = "npm";
|
|
10595
|
+
}
|
|
10596
|
+
context.isGitRepo = await fileExists(path8.join(projectPath, ".git"));
|
|
10597
|
+
if (context.isGitRepo) {
|
|
10598
|
+
try {
|
|
10599
|
+
const { execSync } = await import("child_process");
|
|
10600
|
+
const remotes = execSync("git remote -v", {
|
|
10601
|
+
cwd: projectPath,
|
|
10602
|
+
encoding: "utf-8"
|
|
10603
|
+
});
|
|
10604
|
+
context.hasGitHubRemote = remotes.includes("github.com");
|
|
10605
|
+
} catch {
|
|
10606
|
+
context.hasGitHubRemote = false;
|
|
10134
10607
|
}
|
|
10135
10608
|
}
|
|
10609
|
+
} catch {
|
|
10136
10610
|
}
|
|
10137
|
-
|
|
10138
|
-
|
|
10139
|
-
|
|
10140
|
-
|
|
10141
|
-
|
|
10142
|
-
|
|
10143
|
-
|
|
10144
|
-
|
|
10611
|
+
return context;
|
|
10612
|
+
}
|
|
10613
|
+
async function fileExists(filePath) {
|
|
10614
|
+
try {
|
|
10615
|
+
const fs6 = await import("fs/promises");
|
|
10616
|
+
await fs6.access(filePath);
|
|
10617
|
+
return true;
|
|
10618
|
+
} catch {
|
|
10619
|
+
return false;
|
|
10145
10620
|
}
|
|
10146
|
-
|
|
10147
|
-
|
|
10148
|
-
|
|
10149
|
-
|
|
10150
|
-
|
|
10151
|
-
|
|
10152
|
-
|
|
10153
|
-
|
|
10154
|
-
|
|
10155
|
-
|
|
10156
|
-
if (hasFormatter) {
|
|
10157
|
-
const preset = await promptStylePreset();
|
|
10158
|
-
if (preset !== "custom") {
|
|
10159
|
-
const presetConfig = CODE_STYLE_PRESETS[preset];
|
|
10160
|
-
if (selectedTools.includes("editorconfig")) {
|
|
10161
|
-
editorconfigOptions = presetConfig.editorconfig;
|
|
10162
|
-
}
|
|
10163
|
-
if (selectedTools.includes("biome") && presetConfig.biome) {
|
|
10164
|
-
biomeOptions = {
|
|
10165
|
-
...DEFAULT_BIOME_OPTIONS,
|
|
10166
|
-
formatter: presetConfig.biome
|
|
10167
|
-
};
|
|
10168
|
-
}
|
|
10169
|
-
if (selectedTools.includes("prettier") && presetConfig.prettier) {
|
|
10170
|
-
prettierOptions = presetConfig.prettier;
|
|
10171
|
-
}
|
|
10172
|
-
} else {
|
|
10173
|
-
if (selectedTools.includes("editorconfig")) {
|
|
10174
|
-
editorconfigOptions = await promptEditorConfigOptions();
|
|
10175
|
-
}
|
|
10176
|
-
if (selectedTools.includes("biome")) {
|
|
10177
|
-
biomeOptions = await promptBiomeOptions();
|
|
10178
|
-
}
|
|
10179
|
-
if (selectedTools.includes("prettier")) {
|
|
10180
|
-
prettierOptions = await promptPrettierOptions();
|
|
10181
|
-
}
|
|
10621
|
+
}
|
|
10622
|
+
async function promptPlaceholder(placeholder, context, detectedValue) {
|
|
10623
|
+
const defaultValue = detectedValue || computeDefaultValue(placeholder, context) || "";
|
|
10624
|
+
switch (placeholder.inputType) {
|
|
10625
|
+
case "select": {
|
|
10626
|
+
if (!placeholder.choices || placeholder.choices.length === 0) {
|
|
10627
|
+
return input({
|
|
10628
|
+
message: `${placeholder.label}:`,
|
|
10629
|
+
default: defaultValue
|
|
10630
|
+
});
|
|
10182
10631
|
}
|
|
10632
|
+
const choices = placeholder.choices.map((c) => ({
|
|
10633
|
+
name: c.name,
|
|
10634
|
+
value: c.value,
|
|
10635
|
+
description: c.description
|
|
10636
|
+
}));
|
|
10637
|
+
return select({
|
|
10638
|
+
message: `${placeholder.label}:`,
|
|
10639
|
+
choices,
|
|
10640
|
+
default: defaultValue || choices[0].value
|
|
10641
|
+
});
|
|
10183
10642
|
}
|
|
10184
|
-
|
|
10185
|
-
|
|
10186
|
-
|
|
10187
|
-
|
|
10188
|
-
|
|
10189
|
-
|
|
10643
|
+
case "number": {
|
|
10644
|
+
const result = await input({
|
|
10645
|
+
message: `${placeholder.label}:`,
|
|
10646
|
+
default: defaultValue,
|
|
10647
|
+
validate: (value) => {
|
|
10648
|
+
if (placeholder.validate) {
|
|
10649
|
+
return placeholder.validate(value, context);
|
|
10650
|
+
}
|
|
10651
|
+
const num = Number(value);
|
|
10652
|
+
if (Number.isNaN(num)) {
|
|
10653
|
+
return "Please enter a valid number";
|
|
10654
|
+
}
|
|
10655
|
+
return true;
|
|
10656
|
+
}
|
|
10657
|
+
});
|
|
10658
|
+
return result;
|
|
10190
10659
|
}
|
|
10191
|
-
|
|
10192
|
-
|
|
10660
|
+
case "path": {
|
|
10661
|
+
return input({
|
|
10662
|
+
message: `${placeholder.label}:`,
|
|
10663
|
+
default: defaultValue,
|
|
10664
|
+
validate: (value) => {
|
|
10665
|
+
if (placeholder.required && !value.trim()) {
|
|
10666
|
+
return "This path is required";
|
|
10667
|
+
}
|
|
10668
|
+
if (placeholder.validate) {
|
|
10669
|
+
return placeholder.validate(value, context);
|
|
10670
|
+
}
|
|
10671
|
+
return true;
|
|
10672
|
+
}
|
|
10673
|
+
});
|
|
10193
10674
|
}
|
|
10194
|
-
|
|
10195
|
-
|
|
10675
|
+
case "envVar": {
|
|
10676
|
+
return input({
|
|
10677
|
+
message: `${placeholder.label}:`,
|
|
10678
|
+
default: defaultValue,
|
|
10679
|
+
validate: (value) => {
|
|
10680
|
+
if (placeholder.required && !value.trim()) {
|
|
10681
|
+
return "This environment variable is required";
|
|
10682
|
+
}
|
|
10683
|
+
if (value && !/^[A-Z][A-Z0-9_]*$/.test(value)) {
|
|
10684
|
+
return "Environment variable should be UPPER_SNAKE_CASE";
|
|
10685
|
+
}
|
|
10686
|
+
return true;
|
|
10687
|
+
}
|
|
10688
|
+
});
|
|
10196
10689
|
}
|
|
10197
|
-
|
|
10198
|
-
|
|
10690
|
+
default: {
|
|
10691
|
+
return input({
|
|
10692
|
+
message: `${placeholder.label}:`,
|
|
10693
|
+
default: defaultValue,
|
|
10694
|
+
validate: (value) => {
|
|
10695
|
+
if (placeholder.required && !value.trim()) {
|
|
10696
|
+
return `${placeholder.label} is required`;
|
|
10697
|
+
}
|
|
10698
|
+
if (placeholder.validate) {
|
|
10699
|
+
return placeholder.validate(value, context);
|
|
10700
|
+
}
|
|
10701
|
+
return true;
|
|
10702
|
+
}
|
|
10703
|
+
});
|
|
10199
10704
|
}
|
|
10200
10705
|
}
|
|
10201
|
-
return {
|
|
10202
|
-
enabled: selectedTools.length > 0,
|
|
10203
|
-
editorconfig: selectedTools.includes("editorconfig"),
|
|
10204
|
-
editorconfigOptions,
|
|
10205
|
-
commitlint: selectedTools.includes("commitlint"),
|
|
10206
|
-
commitlintOptions,
|
|
10207
|
-
biome: selectedTools.includes("biome"),
|
|
10208
|
-
biomeOptions,
|
|
10209
|
-
prettier: selectedTools.includes("prettier"),
|
|
10210
|
-
prettierOptions
|
|
10211
|
-
};
|
|
10212
|
-
}
|
|
10213
|
-
async function promptStylePreset() {
|
|
10214
|
-
logger.newline();
|
|
10215
|
-
logger.info("Choose a code style preset:");
|
|
10216
|
-
return select({
|
|
10217
|
-
message: "Style preset:",
|
|
10218
|
-
choices: Object.entries(CODE_STYLE_PRESETS).map(([key, preset]) => ({
|
|
10219
|
-
name: `${preset.name} - ${preset.description}`,
|
|
10220
|
-
value: key
|
|
10221
|
-
})),
|
|
10222
|
-
default: "standard"
|
|
10223
|
-
});
|
|
10224
10706
|
}
|
|
10225
|
-
|
|
10226
|
-
|
|
10227
|
-
|
|
10228
|
-
|
|
10229
|
-
|
|
10230
|
-
|
|
10231
|
-
|
|
10232
|
-
|
|
10233
|
-
|
|
10234
|
-
default: DEFAULT_EDITORCONFIG_OPTIONS.indentStyle
|
|
10235
|
-
});
|
|
10236
|
-
const indentSizeStr = await input({
|
|
10237
|
-
message: "Indent size:",
|
|
10238
|
-
default: String(DEFAULT_EDITORCONFIG_OPTIONS.indentSize),
|
|
10239
|
-
validate: (v) => {
|
|
10240
|
-
const num = Number(v);
|
|
10241
|
-
if (Number.isNaN(num) || num < 1 || num > 8) return "Enter a number between 1 and 8";
|
|
10242
|
-
return true;
|
|
10243
|
-
}
|
|
10244
|
-
});
|
|
10245
|
-
const indentSize = Number(indentSizeStr);
|
|
10246
|
-
const endOfLine = await select({
|
|
10247
|
-
message: "Line endings:",
|
|
10248
|
-
choices: [
|
|
10249
|
-
{ name: "LF (Unix/Mac)", value: "lf" },
|
|
10250
|
-
{ name: "CRLF (Windows)", value: "crlf" },
|
|
10251
|
-
{ name: "CR (Old Mac)", value: "cr" }
|
|
10252
|
-
],
|
|
10253
|
-
default: DEFAULT_EDITORCONFIG_OPTIONS.endOfLine
|
|
10254
|
-
});
|
|
10255
|
-
const maxLineLengthStr = await input({
|
|
10256
|
-
message: 'Max line length (or "off"):',
|
|
10257
|
-
default: String(DEFAULT_EDITORCONFIG_OPTIONS.maxLineLength),
|
|
10258
|
-
validate: (v) => {
|
|
10259
|
-
if (v.toLowerCase() === "off") return true;
|
|
10260
|
-
const num = Number(v);
|
|
10261
|
-
if (Number.isNaN(num) || num < 40 || num > 200)
|
|
10262
|
-
return 'Enter a number between 40 and 200, or "off"';
|
|
10263
|
-
return true;
|
|
10264
|
-
}
|
|
10265
|
-
});
|
|
10266
|
-
const maxLineLength = maxLineLengthStr.toLowerCase() === "off" ? "off" : Number(maxLineLengthStr);
|
|
10267
|
-
return {
|
|
10268
|
-
indentStyle,
|
|
10269
|
-
indentSize,
|
|
10270
|
-
endOfLine,
|
|
10271
|
-
insertFinalNewline: true,
|
|
10272
|
-
trimTrailingWhitespace: true,
|
|
10273
|
-
charset: "utf-8",
|
|
10274
|
-
maxLineLength
|
|
10707
|
+
function computeAllDefaults(context, globalDefaults) {
|
|
10708
|
+
const config = {
|
|
10709
|
+
commands: {},
|
|
10710
|
+
paths: {},
|
|
10711
|
+
targets: {},
|
|
10712
|
+
tracking: {},
|
|
10713
|
+
techStack: {},
|
|
10714
|
+
environment: {},
|
|
10715
|
+
brand: {}
|
|
10275
10716
|
};
|
|
10717
|
+
for (const placeholder of TEMPLATE_PLACEHOLDERS) {
|
|
10718
|
+
const defaultValue = computeDefaultValue(placeholder, context);
|
|
10719
|
+
if (defaultValue) {
|
|
10720
|
+
setConfigValue(config, placeholder, defaultValue);
|
|
10721
|
+
}
|
|
10722
|
+
}
|
|
10723
|
+
if (globalDefaults) {
|
|
10724
|
+
return mergeWithGlobalDefaults(config, globalDefaults);
|
|
10725
|
+
}
|
|
10726
|
+
return config;
|
|
10727
|
+
}
|
|
10728
|
+
function setConfigValue(config, placeholder, value) {
|
|
10729
|
+
const key = placeholderKeyToConfigKey(placeholder.key, placeholder.category);
|
|
10730
|
+
switch (placeholder.category) {
|
|
10731
|
+
case "commands":
|
|
10732
|
+
if (!config.commands) config.commands = {};
|
|
10733
|
+
config.commands[key] = value;
|
|
10734
|
+
break;
|
|
10735
|
+
case "paths":
|
|
10736
|
+
if (!config.paths) config.paths = {};
|
|
10737
|
+
config.paths[key] = value;
|
|
10738
|
+
break;
|
|
10739
|
+
case "targets":
|
|
10740
|
+
case "performance": {
|
|
10741
|
+
if (!config.targets) config.targets = {};
|
|
10742
|
+
const numValue = Number(value);
|
|
10743
|
+
if (!Number.isNaN(numValue)) {
|
|
10744
|
+
config.targets[key] = numValue;
|
|
10745
|
+
} else {
|
|
10746
|
+
config.targets[key] = value;
|
|
10747
|
+
}
|
|
10748
|
+
break;
|
|
10749
|
+
}
|
|
10750
|
+
case "tracking":
|
|
10751
|
+
if (!config.tracking) config.tracking = {};
|
|
10752
|
+
config.tracking[key] = key.endsWith("Days") ? Number(value) : value;
|
|
10753
|
+
break;
|
|
10754
|
+
case "techStack":
|
|
10755
|
+
if (!config.techStack) config.techStack = {};
|
|
10756
|
+
config.techStack[key] = value;
|
|
10757
|
+
break;
|
|
10758
|
+
case "environment":
|
|
10759
|
+
if (!config.environment) config.environment = {};
|
|
10760
|
+
config.environment[key] = value;
|
|
10761
|
+
break;
|
|
10762
|
+
case "brand":
|
|
10763
|
+
if (!config.brand) config.brand = {};
|
|
10764
|
+
config.brand[key] = value;
|
|
10765
|
+
break;
|
|
10766
|
+
}
|
|
10276
10767
|
}
|
|
10277
|
-
|
|
10768
|
+
function placeholderKeyToConfigKey(key, category) {
|
|
10769
|
+
let cleanKey = key;
|
|
10770
|
+
if (category === "commands" && key.endsWith("_COMMAND")) {
|
|
10771
|
+
cleanKey = key.slice(0, -8);
|
|
10772
|
+
} else if (category === "environment" && key.endsWith("_ENV")) {
|
|
10773
|
+
cleanKey = key.slice(0, -4);
|
|
10774
|
+
} else if (key.endsWith("_TARGET")) {
|
|
10775
|
+
cleanKey = key.slice(0, -7);
|
|
10776
|
+
}
|
|
10777
|
+
return cleanKey.toLowerCase().replace(/_([a-z])/g, (_, char) => char.toUpperCase());
|
|
10778
|
+
}
|
|
10779
|
+
async function promptTemplateConfig(options) {
|
|
10780
|
+
const { context, mode = "quick", category, requiredOnly = false } = options;
|
|
10781
|
+
logger.section("Template Configuration", "\u{1F4DD}");
|
|
10278
10782
|
logger.newline();
|
|
10279
|
-
logger.
|
|
10280
|
-
|
|
10281
|
-
|
|
10282
|
-
|
|
10283
|
-
|
|
10284
|
-
|
|
10285
|
-
|
|
10286
|
-
|
|
10287
|
-
|
|
10288
|
-
|
|
10289
|
-
|
|
10290
|
-
|
|
10291
|
-
|
|
10292
|
-
|
|
10293
|
-
|
|
10294
|
-
|
|
10295
|
-
|
|
10296
|
-
}
|
|
10297
|
-
|
|
10298
|
-
|
|
10299
|
-
|
|
10300
|
-
|
|
10301
|
-
validate: (v) => {
|
|
10302
|
-
const num = Number(v);
|
|
10303
|
-
if (Number.isNaN(num) || num < 40 || num > 200) return "Enter a number between 40 and 200";
|
|
10304
|
-
return true;
|
|
10305
|
-
}
|
|
10306
|
-
});
|
|
10307
|
-
const lineWidth = Number(lineWidthStr);
|
|
10308
|
-
const quoteStyle = await select({
|
|
10309
|
-
message: "Quote style:",
|
|
10310
|
-
choices: [
|
|
10311
|
-
{ name: "Single quotes", value: "single" },
|
|
10312
|
-
{ name: "Double quotes", value: "double" }
|
|
10313
|
-
],
|
|
10314
|
-
default: DEFAULT_BIOME_OPTIONS.formatter.quoteStyle
|
|
10315
|
-
});
|
|
10316
|
-
const semicolons = await select({
|
|
10317
|
-
message: "Semicolons:",
|
|
10318
|
-
choices: [
|
|
10319
|
-
{ name: "Always", value: "always" },
|
|
10320
|
-
{ name: "As needed (ASI)", value: "asNeeded" }
|
|
10321
|
-
],
|
|
10322
|
-
default: DEFAULT_BIOME_OPTIONS.formatter.semicolons
|
|
10323
|
-
});
|
|
10324
|
-
const trailingCommas = await select({
|
|
10325
|
-
message: "Trailing commas:",
|
|
10326
|
-
choices: [
|
|
10327
|
-
{ name: "All", value: "all" },
|
|
10328
|
-
{ name: "ES5 (only where valid in ES5)", value: "es5" },
|
|
10329
|
-
{ name: "None", value: "none" }
|
|
10330
|
-
],
|
|
10331
|
-
default: DEFAULT_BIOME_OPTIONS.formatter.trailingCommas
|
|
10332
|
-
});
|
|
10333
|
-
const enableRecommended = await confirm({
|
|
10334
|
-
message: "Enable recommended linter rules?",
|
|
10335
|
-
default: true
|
|
10336
|
-
});
|
|
10337
|
-
return {
|
|
10338
|
-
formatter: {
|
|
10339
|
-
indentStyle,
|
|
10340
|
-
indentWidth,
|
|
10341
|
-
lineWidth,
|
|
10342
|
-
quoteStyle,
|
|
10343
|
-
semicolons,
|
|
10344
|
-
trailingCommas,
|
|
10345
|
-
quoteProperties: "asNeeded",
|
|
10346
|
-
bracketSpacing: true,
|
|
10347
|
-
bracketSameLine: false,
|
|
10348
|
-
arrowParentheses: "always"
|
|
10349
|
-
},
|
|
10350
|
-
linter: {
|
|
10351
|
-
recommended: enableRecommended,
|
|
10352
|
-
correctness: enableRecommended,
|
|
10353
|
-
suspicious: enableRecommended,
|
|
10354
|
-
style: enableRecommended,
|
|
10355
|
-
complexity: enableRecommended,
|
|
10356
|
-
security: enableRecommended,
|
|
10357
|
-
performance: enableRecommended,
|
|
10358
|
-
a11y: enableRecommended
|
|
10359
|
-
},
|
|
10360
|
-
organizeImports: true,
|
|
10361
|
-
ignorePatterns: DEFAULT_BIOME_OPTIONS.ignorePatterns
|
|
10362
|
-
};
|
|
10783
|
+
logger.info("This step personalizes all Claude Code configuration files for YOUR project.");
|
|
10784
|
+
logger.info("Your answers will be used to:");
|
|
10785
|
+
logger.newline();
|
|
10786
|
+
logger.item("Replace {{PLACEHOLDERS}} in agents, commands, and skills");
|
|
10787
|
+
logger.item("Configure CLAUDE.md with your tech stack and commands");
|
|
10788
|
+
logger.item("Set up quality targets (coverage, performance, accessibility)");
|
|
10789
|
+
logger.item("Customize code examples to match your project structure");
|
|
10790
|
+
logger.newline();
|
|
10791
|
+
logger.info("Accurate configuration means better AI assistance tailored to your codebase!");
|
|
10792
|
+
logger.newline();
|
|
10793
|
+
const hasDefaults = await hasGlobalDefaults();
|
|
10794
|
+
const globalDefaults = hasDefaults ? await getGlobalTemplateConfig() : void 0;
|
|
10795
|
+
if (mode === "quick") {
|
|
10796
|
+
return promptQuickSetup(context, globalDefaults);
|
|
10797
|
+
}
|
|
10798
|
+
if (category) {
|
|
10799
|
+
return promptCategory(category, context, requiredOnly);
|
|
10800
|
+
}
|
|
10801
|
+
if (mode === "guided") {
|
|
10802
|
+
return promptGuidedSetup(context, requiredOnly);
|
|
10803
|
+
}
|
|
10804
|
+
return promptAdvancedSetup(context);
|
|
10363
10805
|
}
|
|
10364
|
-
async function
|
|
10806
|
+
async function promptQuickSetup(context, globalDefaults) {
|
|
10807
|
+
logger.info("Auto-detecting configuration from project...");
|
|
10365
10808
|
logger.newline();
|
|
10366
|
-
|
|
10367
|
-
|
|
10368
|
-
|
|
10369
|
-
|
|
10370
|
-
|
|
10371
|
-
const num = Number(v);
|
|
10372
|
-
if (Number.isNaN(num) || num < 40 || num > 200) return "Enter a number between 40 and 200";
|
|
10373
|
-
return true;
|
|
10374
|
-
}
|
|
10809
|
+
const detected = computeAllDefaults(context, globalDefaults);
|
|
10810
|
+
displayDetectedConfig(detected, context);
|
|
10811
|
+
const wantEdit = await confirm({
|
|
10812
|
+
message: "Would you like to modify any values?",
|
|
10813
|
+
default: false
|
|
10375
10814
|
});
|
|
10376
|
-
|
|
10377
|
-
|
|
10378
|
-
|
|
10379
|
-
|
|
10380
|
-
|
|
10381
|
-
|
|
10382
|
-
|
|
10383
|
-
|
|
10815
|
+
let finalConfig = detected;
|
|
10816
|
+
if (wantEdit) {
|
|
10817
|
+
finalConfig = await promptEditConfig(detected, context);
|
|
10818
|
+
}
|
|
10819
|
+
return finalConfig;
|
|
10820
|
+
}
|
|
10821
|
+
function displayDetectedConfig(config, _context) {
|
|
10822
|
+
const categories = Object.entries(CATEGORY_INFO).sort(([, a], [, b]) => a.order - b.order).map(([key]) => key);
|
|
10823
|
+
for (const category of categories) {
|
|
10824
|
+
const placeholders = getPlaceholdersByCategory(category);
|
|
10825
|
+
if (placeholders.length === 0) continue;
|
|
10826
|
+
const values = getCategoryValues(config, category);
|
|
10827
|
+
if (Object.keys(values).length === 0) continue;
|
|
10828
|
+
logger.subtitle(CATEGORY_INFO[category].name);
|
|
10829
|
+
for (const [key, value] of Object.entries(values)) {
|
|
10830
|
+
if (value !== void 0) {
|
|
10831
|
+
const placeholder = TEMPLATE_PLACEHOLDERS.find(
|
|
10832
|
+
(p) => placeholderKeyToConfigKey(p.key, p.category) === key
|
|
10833
|
+
);
|
|
10834
|
+
const label = placeholder?.label || key;
|
|
10835
|
+
logger.keyValue(label, String(value));
|
|
10836
|
+
}
|
|
10384
10837
|
}
|
|
10385
|
-
|
|
10386
|
-
|
|
10387
|
-
|
|
10388
|
-
|
|
10389
|
-
|
|
10390
|
-
|
|
10391
|
-
|
|
10392
|
-
|
|
10393
|
-
|
|
10394
|
-
|
|
10395
|
-
|
|
10396
|
-
|
|
10397
|
-
|
|
10398
|
-
|
|
10399
|
-
|
|
10400
|
-
|
|
10401
|
-
|
|
10402
|
-
|
|
10403
|
-
|
|
10404
|
-
|
|
10405
|
-
|
|
10406
|
-
|
|
10407
|
-
}
|
|
10408
|
-
const bracketSpacing = await confirm({
|
|
10409
|
-
message: "Bracket spacing? ({ foo: bar })",
|
|
10410
|
-
default: DEFAULT_PRETTIER_OPTIONS.bracketSpacing
|
|
10411
|
-
});
|
|
10412
|
-
const arrowParens = await select({
|
|
10413
|
-
message: "Arrow function parentheses:",
|
|
10414
|
-
choices: [
|
|
10415
|
-
{ name: "Always (x) => x", value: "always" },
|
|
10416
|
-
{ name: "Avoid x => x", value: "avoid" }
|
|
10417
|
-
],
|
|
10418
|
-
default: DEFAULT_PRETTIER_OPTIONS.arrowParens
|
|
10419
|
-
});
|
|
10420
|
-
return {
|
|
10421
|
-
printWidth,
|
|
10422
|
-
tabWidth,
|
|
10423
|
-
useTabs,
|
|
10424
|
-
semi,
|
|
10425
|
-
singleQuote,
|
|
10426
|
-
jsxSingleQuote: false,
|
|
10427
|
-
trailingComma,
|
|
10428
|
-
bracketSpacing,
|
|
10429
|
-
bracketSameLine: false,
|
|
10430
|
-
arrowParens,
|
|
10431
|
-
endOfLine: "lf",
|
|
10432
|
-
proseWrap: "preserve",
|
|
10433
|
-
htmlWhitespaceSensitivity: "css",
|
|
10434
|
-
singleAttributePerLine: false
|
|
10435
|
-
};
|
|
10838
|
+
logger.newline();
|
|
10839
|
+
}
|
|
10840
|
+
}
|
|
10841
|
+
function getCategoryValues(config, category) {
|
|
10842
|
+
switch (category) {
|
|
10843
|
+
case "commands":
|
|
10844
|
+
return config.commands || {};
|
|
10845
|
+
case "paths":
|
|
10846
|
+
return config.paths || {};
|
|
10847
|
+
case "targets":
|
|
10848
|
+
case "performance":
|
|
10849
|
+
return config.targets || {};
|
|
10850
|
+
case "tracking":
|
|
10851
|
+
return config.tracking || {};
|
|
10852
|
+
case "techStack":
|
|
10853
|
+
return config.techStack || {};
|
|
10854
|
+
case "environment":
|
|
10855
|
+
return config.environment || {};
|
|
10856
|
+
case "brand":
|
|
10857
|
+
return config.brand || {};
|
|
10858
|
+
default:
|
|
10859
|
+
return {};
|
|
10860
|
+
}
|
|
10436
10861
|
}
|
|
10437
|
-
async function
|
|
10438
|
-
|
|
10439
|
-
|
|
10440
|
-
|
|
10441
|
-
|
|
10442
|
-
|
|
10862
|
+
async function promptEditConfig(config, context) {
|
|
10863
|
+
const categories = Object.entries(CATEGORY_INFO).sort(([, a], [, b]) => a.order - b.order).map(([key]) => key);
|
|
10864
|
+
const categoryToEdit = await select({
|
|
10865
|
+
message: "Which category would you like to edit?",
|
|
10866
|
+
choices: [
|
|
10867
|
+
...categories.map((cat) => ({
|
|
10868
|
+
name: CATEGORY_INFO[cat].name,
|
|
10869
|
+
value: cat
|
|
10870
|
+
})),
|
|
10871
|
+
{ name: "Done editing", value: "done" }
|
|
10872
|
+
]
|
|
10443
10873
|
});
|
|
10444
|
-
if (
|
|
10445
|
-
|
|
10446
|
-
message: "Enable Husky integration (git hooks)?",
|
|
10447
|
-
default: true
|
|
10448
|
-
});
|
|
10449
|
-
return {
|
|
10450
|
-
...DEFAULT_COMMITLINT_OPTIONS,
|
|
10451
|
-
huskyIntegration: huskyIntegration2
|
|
10452
|
-
};
|
|
10874
|
+
if (categoryToEdit === "done") {
|
|
10875
|
+
return config;
|
|
10453
10876
|
}
|
|
10454
|
-
const
|
|
10455
|
-
|
|
10456
|
-
|
|
10457
|
-
|
|
10458
|
-
|
|
10459
|
-
|
|
10460
|
-
|
|
10461
|
-
|
|
10462
|
-
|
|
10463
|
-
|
|
10464
|
-
|
|
10465
|
-
|
|
10466
|
-
|
|
10467
|
-
|
|
10468
|
-
|
|
10469
|
-
|
|
10470
|
-
|
|
10471
|
-
|
|
10472
|
-
|
|
10473
|
-
|
|
10474
|
-
|
|
10475
|
-
|
|
10877
|
+
const editedCategory = await promptCategory(categoryToEdit, context, false);
|
|
10878
|
+
const merged = { ...config };
|
|
10879
|
+
switch (categoryToEdit) {
|
|
10880
|
+
case "commands":
|
|
10881
|
+
merged.commands = { ...config.commands, ...editedCategory.commands };
|
|
10882
|
+
break;
|
|
10883
|
+
case "paths":
|
|
10884
|
+
merged.paths = { ...config.paths, ...editedCategory.paths };
|
|
10885
|
+
break;
|
|
10886
|
+
case "targets":
|
|
10887
|
+
case "performance":
|
|
10888
|
+
merged.targets = { ...config.targets, ...editedCategory.targets };
|
|
10889
|
+
break;
|
|
10890
|
+
case "tracking":
|
|
10891
|
+
merged.tracking = { ...config.tracking, ...editedCategory.tracking };
|
|
10892
|
+
break;
|
|
10893
|
+
case "techStack":
|
|
10894
|
+
merged.techStack = { ...config.techStack, ...editedCategory.techStack };
|
|
10895
|
+
break;
|
|
10896
|
+
case "environment":
|
|
10897
|
+
merged.environment = { ...config.environment, ...editedCategory.environment };
|
|
10898
|
+
break;
|
|
10899
|
+
case "brand":
|
|
10900
|
+
merged.brand = { ...config.brand, ...editedCategory.brand };
|
|
10901
|
+
break;
|
|
10902
|
+
}
|
|
10903
|
+
const editMore = await confirm({
|
|
10904
|
+
message: "Edit another category?",
|
|
10476
10905
|
default: false
|
|
10477
10906
|
});
|
|
10478
|
-
|
|
10479
|
-
|
|
10480
|
-
|
|
10481
|
-
|
|
10482
|
-
return {
|
|
10483
|
-
extends: ["@commitlint/config-conventional"],
|
|
10484
|
-
types,
|
|
10485
|
-
scopes,
|
|
10486
|
-
headerMaxLength,
|
|
10487
|
-
scopeRequired,
|
|
10488
|
-
bodyRequired: false,
|
|
10489
|
-
bodyMaxLineLength: 100,
|
|
10490
|
-
huskyIntegration
|
|
10491
|
-
};
|
|
10907
|
+
if (editMore) {
|
|
10908
|
+
return promptEditConfig(merged, context);
|
|
10909
|
+
}
|
|
10910
|
+
return merged;
|
|
10492
10911
|
}
|
|
10493
|
-
|
|
10494
|
-
|
|
10495
|
-
|
|
10496
|
-
|
|
10497
|
-
|
|
10498
|
-
|
|
10499
|
-
|
|
10500
|
-
|
|
10501
|
-
|
|
10502
|
-
|
|
10503
|
-
|
|
10504
|
-
|
|
10505
|
-
|
|
10506
|
-
|
|
10507
|
-
|
|
10508
|
-
|
|
10509
|
-
|
|
10510
|
-
|
|
10511
|
-
|
|
10512
|
-
|
|
10513
|
-
|
|
10514
|
-
|
|
10515
|
-
|
|
10516
|
-
|
|
10517
|
-
value: "guided",
|
|
10518
|
-
description: "Step through each category"
|
|
10519
|
-
},
|
|
10520
|
-
{
|
|
10521
|
-
name: "Advanced Setup",
|
|
10522
|
-
value: "advanced",
|
|
10523
|
-
description: "Configure all options individually"
|
|
10524
|
-
}
|
|
10525
|
-
],
|
|
10526
|
-
default: "quick"
|
|
10527
|
-
});
|
|
10528
|
-
return mode;
|
|
10912
|
+
async function promptCategory(category, context, requiredOnly) {
|
|
10913
|
+
const config = {
|
|
10914
|
+
commands: {},
|
|
10915
|
+
paths: {},
|
|
10916
|
+
targets: {},
|
|
10917
|
+
tracking: {},
|
|
10918
|
+
techStack: {},
|
|
10919
|
+
environment: {},
|
|
10920
|
+
brand: {}
|
|
10921
|
+
};
|
|
10922
|
+
logger.subtitle(CATEGORY_INFO[category].name);
|
|
10923
|
+
let placeholders = getPlaceholdersByCategory(category);
|
|
10924
|
+
if (requiredOnly) {
|
|
10925
|
+
placeholders = placeholders.filter((p) => p.required);
|
|
10926
|
+
}
|
|
10927
|
+
const updatedContext = { ...context };
|
|
10928
|
+
for (const placeholder of placeholders) {
|
|
10929
|
+
const value = await promptPlaceholder(placeholder, updatedContext);
|
|
10930
|
+
if (value) {
|
|
10931
|
+
setConfigValue(config, placeholder, value);
|
|
10932
|
+
updatedContext.values[placeholder.key] = value;
|
|
10933
|
+
}
|
|
10934
|
+
}
|
|
10935
|
+
return config;
|
|
10529
10936
|
}
|
|
10530
|
-
async function
|
|
10531
|
-
const
|
|
10532
|
-
|
|
10533
|
-
|
|
10937
|
+
async function promptGuidedSetup(context, requiredOnly) {
|
|
10938
|
+
const config = {
|
|
10939
|
+
commands: {},
|
|
10940
|
+
paths: {},
|
|
10941
|
+
targets: {},
|
|
10942
|
+
tracking: {},
|
|
10943
|
+
techStack: {},
|
|
10944
|
+
environment: {},
|
|
10945
|
+
brand: {}
|
|
10534
10946
|
};
|
|
10535
|
-
|
|
10536
|
-
|
|
10537
|
-
|
|
10538
|
-
const
|
|
10539
|
-
const
|
|
10540
|
-
|
|
10541
|
-
|
|
10542
|
-
|
|
10543
|
-
|
|
10544
|
-
|
|
10545
|
-
|
|
10546
|
-
|
|
10547
|
-
|
|
10548
|
-
|
|
10549
|
-
|
|
10550
|
-
|
|
10551
|
-
|
|
10552
|
-
|
|
10553
|
-
|
|
10554
|
-
|
|
10947
|
+
const categories = Object.entries(CATEGORY_INFO).sort(([, a], [, b]) => a.order - b.order).map(([key]) => key);
|
|
10948
|
+
const updatedContext = { ...context };
|
|
10949
|
+
for (const category of categories) {
|
|
10950
|
+
const placeholders = getPlaceholdersByCategory(category);
|
|
10951
|
+
const relevantPlaceholders = requiredOnly ? placeholders.filter((p) => p.required) : placeholders;
|
|
10952
|
+
if (relevantPlaceholders.length === 0) continue;
|
|
10953
|
+
const configureCategory = await confirm({
|
|
10954
|
+
message: `Configure ${CATEGORY_INFO[category].name}? (${relevantPlaceholders.length} options)`,
|
|
10955
|
+
default: true
|
|
10956
|
+
});
|
|
10957
|
+
if (!configureCategory) continue;
|
|
10958
|
+
const categoryConfig = await promptCategory(category, updatedContext, requiredOnly);
|
|
10959
|
+
switch (category) {
|
|
10960
|
+
case "commands":
|
|
10961
|
+
config.commands = { ...config.commands, ...categoryConfig.commands };
|
|
10962
|
+
break;
|
|
10963
|
+
case "paths":
|
|
10964
|
+
config.paths = { ...config.paths, ...categoryConfig.paths };
|
|
10965
|
+
break;
|
|
10966
|
+
case "targets":
|
|
10967
|
+
case "performance":
|
|
10968
|
+
config.targets = { ...config.targets, ...categoryConfig.targets };
|
|
10969
|
+
break;
|
|
10970
|
+
case "tracking":
|
|
10971
|
+
config.tracking = { ...config.tracking, ...categoryConfig.tracking };
|
|
10972
|
+
break;
|
|
10973
|
+
case "techStack":
|
|
10974
|
+
config.techStack = { ...config.techStack, ...categoryConfig.techStack };
|
|
10975
|
+
break;
|
|
10976
|
+
case "environment":
|
|
10977
|
+
config.environment = { ...config.environment, ...categoryConfig.environment };
|
|
10978
|
+
break;
|
|
10979
|
+
case "brand":
|
|
10980
|
+
config.brand = { ...config.brand, ...categoryConfig.brand };
|
|
10981
|
+
break;
|
|
10555
10982
|
}
|
|
10556
|
-
|
|
10557
|
-
|
|
10558
|
-
|
|
10559
|
-
const { execSync } = await import("child_process");
|
|
10560
|
-
const remotes = execSync("git remote -v", {
|
|
10561
|
-
cwd: projectPath,
|
|
10562
|
-
encoding: "utf-8"
|
|
10563
|
-
});
|
|
10564
|
-
context.hasGitHubRemote = remotes.includes("github.com");
|
|
10565
|
-
} catch {
|
|
10566
|
-
context.hasGitHubRemote = false;
|
|
10983
|
+
for (const [key, value] of Object.entries(getCategoryValues(categoryConfig, category))) {
|
|
10984
|
+
if (value !== void 0) {
|
|
10985
|
+
updatedContext.values[key.toUpperCase()] = String(value);
|
|
10567
10986
|
}
|
|
10568
10987
|
}
|
|
10569
|
-
} catch {
|
|
10570
10988
|
}
|
|
10571
|
-
return
|
|
10989
|
+
return config;
|
|
10990
|
+
}
|
|
10991
|
+
async function promptAdvancedSetup(context) {
|
|
10992
|
+
return promptGuidedSetup(context, false);
|
|
10993
|
+
}
|
|
10994
|
+
async function confirmTemplateConfig(config, context) {
|
|
10995
|
+
logger.newline();
|
|
10996
|
+
logger.subtitle("Configuration Summary");
|
|
10997
|
+
displayDetectedConfig(config, context);
|
|
10998
|
+
return confirm({
|
|
10999
|
+
message: "Apply this configuration?",
|
|
11000
|
+
default: true
|
|
11001
|
+
});
|
|
11002
|
+
}
|
|
11003
|
+
async function promptSaveGlobalDefaults(config) {
|
|
11004
|
+
const save = await confirm({
|
|
11005
|
+
message: "Save these values as global defaults for future projects?",
|
|
11006
|
+
default: false
|
|
11007
|
+
});
|
|
11008
|
+
if (save) {
|
|
11009
|
+
await updateGlobalDefaults(config);
|
|
11010
|
+
logger.success("Global defaults saved to ~/.claude/defaults.json");
|
|
11011
|
+
}
|
|
11012
|
+
return save;
|
|
10572
11013
|
}
|
|
10573
|
-
|
|
10574
|
-
|
|
10575
|
-
|
|
10576
|
-
|
|
10577
|
-
|
|
10578
|
-
|
|
11014
|
+
|
|
11015
|
+
// src/lib/wizard/init-steps.ts
|
|
11016
|
+
function createResult(value, navigation = "next") {
|
|
11017
|
+
return {
|
|
11018
|
+
value,
|
|
11019
|
+
navigation,
|
|
11020
|
+
wasModified: true
|
|
11021
|
+
};
|
|
11022
|
+
}
|
|
11023
|
+
async function promptBackOption(stepIndex, stepName) {
|
|
11024
|
+
if (stepIndex === 0) {
|
|
10579
11025
|
return false;
|
|
10580
11026
|
}
|
|
11027
|
+
const result = await select({
|
|
11028
|
+
message: `${stepName}`,
|
|
11029
|
+
choices: [
|
|
11030
|
+
{
|
|
11031
|
+
name: `${colors.muted("\u2190")} Back to previous step`,
|
|
11032
|
+
value: BACK_OPTION_VALUE,
|
|
11033
|
+
description: "Return to the previous step"
|
|
11034
|
+
},
|
|
11035
|
+
{
|
|
11036
|
+
name: "Continue with this step",
|
|
11037
|
+
value: "continue",
|
|
11038
|
+
description: "Proceed to configure this section"
|
|
11039
|
+
}
|
|
11040
|
+
],
|
|
11041
|
+
default: "continue"
|
|
11042
|
+
});
|
|
11043
|
+
return result === BACK_OPTION_VALUE;
|
|
10581
11044
|
}
|
|
10582
|
-
|
|
10583
|
-
|
|
10584
|
-
|
|
10585
|
-
|
|
10586
|
-
|
|
10587
|
-
|
|
10588
|
-
|
|
10589
|
-
|
|
10590
|
-
|
|
11045
|
+
function createProjectInfoStep() {
|
|
11046
|
+
return {
|
|
11047
|
+
metadata: {
|
|
11048
|
+
id: "projectInfo",
|
|
11049
|
+
name: "Project Information",
|
|
11050
|
+
description: "Basic project identification and metadata",
|
|
11051
|
+
required: true
|
|
11052
|
+
},
|
|
11053
|
+
computeDefaults: (ctx) => ctx.projectInfo,
|
|
11054
|
+
execute: async (_ctx, defaults) => {
|
|
11055
|
+
const value = await promptProjectInfo({ defaults });
|
|
11056
|
+
const confirmed = await confirmProjectInfo(value);
|
|
11057
|
+
if (!confirmed) {
|
|
11058
|
+
return createResult(value, "back");
|
|
10591
11059
|
}
|
|
10592
|
-
|
|
10593
|
-
|
|
10594
|
-
|
|
10595
|
-
|
|
10596
|
-
|
|
10597
|
-
|
|
10598
|
-
|
|
10599
|
-
|
|
10600
|
-
|
|
11060
|
+
return createResult(value, "next");
|
|
11061
|
+
}
|
|
11062
|
+
};
|
|
11063
|
+
}
|
|
11064
|
+
function createPreferencesStep() {
|
|
11065
|
+
return {
|
|
11066
|
+
metadata: {
|
|
11067
|
+
id: "preferences",
|
|
11068
|
+
name: "Preferences",
|
|
11069
|
+
description: "Language and package manager settings",
|
|
11070
|
+
required: true
|
|
11071
|
+
},
|
|
11072
|
+
computeDefaults: (ctx) => ctx.preferences,
|
|
11073
|
+
execute: async (ctx, defaults) => {
|
|
11074
|
+
const goBack = await promptBackOption(1, "Configure preferences or go back?");
|
|
11075
|
+
if (goBack) {
|
|
11076
|
+
return createResult(defaults, "back");
|
|
11077
|
+
}
|
|
11078
|
+
const value = await promptPreferences({
|
|
11079
|
+
detectedPackageManager: ctx.detection.packageManager,
|
|
11080
|
+
defaults
|
|
10601
11081
|
});
|
|
11082
|
+
return createResult(value, "next");
|
|
10602
11083
|
}
|
|
10603
|
-
|
|
10604
|
-
|
|
10605
|
-
|
|
10606
|
-
|
|
10607
|
-
|
|
10608
|
-
|
|
10609
|
-
|
|
10610
|
-
|
|
10611
|
-
|
|
10612
|
-
|
|
10613
|
-
|
|
10614
|
-
|
|
10615
|
-
|
|
10616
|
-
|
|
11084
|
+
};
|
|
11085
|
+
}
|
|
11086
|
+
function createScaffoldStep() {
|
|
11087
|
+
return {
|
|
11088
|
+
metadata: {
|
|
11089
|
+
id: "scaffoldOptions",
|
|
11090
|
+
name: "Scaffold Options",
|
|
11091
|
+
description: "Project structure and scaffolding type",
|
|
11092
|
+
required: true
|
|
11093
|
+
},
|
|
11094
|
+
computeDefaults: (ctx) => ctx.scaffoldOptions,
|
|
11095
|
+
execute: async (ctx, defaults) => {
|
|
11096
|
+
const goBack = await promptBackOption(2, "Configure scaffold or go back?");
|
|
11097
|
+
if (goBack) {
|
|
11098
|
+
return createResult(defaults, "back");
|
|
11099
|
+
}
|
|
11100
|
+
const value = await promptScaffoldOptions({
|
|
11101
|
+
existingProject: ctx.detection.detected,
|
|
11102
|
+
detectedType: ctx.detection.projectType,
|
|
11103
|
+
detectedPackageManager: ctx.detection.packageManager
|
|
10617
11104
|
});
|
|
10618
|
-
return
|
|
11105
|
+
return createResult(value, "next");
|
|
10619
11106
|
}
|
|
10620
|
-
|
|
10621
|
-
|
|
10622
|
-
|
|
10623
|
-
|
|
10624
|
-
|
|
10625
|
-
|
|
10626
|
-
|
|
10627
|
-
|
|
10628
|
-
|
|
10629
|
-
|
|
11107
|
+
};
|
|
11108
|
+
}
|
|
11109
|
+
function createBundleSelectionStep() {
|
|
11110
|
+
return {
|
|
11111
|
+
metadata: {
|
|
11112
|
+
id: "bundleSelection",
|
|
11113
|
+
name: "Module Bundles",
|
|
11114
|
+
description: "Select pre-configured module bundles",
|
|
11115
|
+
required: true
|
|
11116
|
+
},
|
|
11117
|
+
computeDefaults: (ctx) => ctx.bundleSelection,
|
|
11118
|
+
execute: async (ctx, defaults) => {
|
|
11119
|
+
const goBack = await promptBackOption(3, "Select bundles or go back?");
|
|
11120
|
+
if (goBack) {
|
|
11121
|
+
return createResult(defaults, "back");
|
|
11122
|
+
}
|
|
11123
|
+
if (ctx.detection.suggestedBundles?.length) {
|
|
11124
|
+
logger.info(
|
|
11125
|
+
colors.muted(
|
|
11126
|
+
`Suggested bundles based on your project: ${ctx.detection.suggestedBundles.join(", ")}`
|
|
11127
|
+
)
|
|
11128
|
+
);
|
|
11129
|
+
}
|
|
11130
|
+
const mode = await promptBundleMode();
|
|
11131
|
+
const result = {
|
|
11132
|
+
selectedBundles: defaults?.selectedBundles || [],
|
|
11133
|
+
additionalModules: defaults?.additionalModules || {
|
|
11134
|
+
agents: [],
|
|
11135
|
+
skills: [],
|
|
11136
|
+
commands: [],
|
|
11137
|
+
docs: []
|
|
11138
|
+
}
|
|
11139
|
+
};
|
|
11140
|
+
if (mode === "bundles" || mode === "both") {
|
|
11141
|
+
result.selectedBundles = await promptQuickBundleSelection();
|
|
11142
|
+
if (result.selectedBundles.length > 0) {
|
|
11143
|
+
showBundlesSummary(result.selectedBundles);
|
|
11144
|
+
}
|
|
11145
|
+
}
|
|
11146
|
+
if (mode === "individual" || mode === "both") {
|
|
11147
|
+
const preselectedFromBundles = resolveBundles(result.selectedBundles);
|
|
11148
|
+
const categories = ["agents", "skills", "commands", "docs"];
|
|
11149
|
+
if (ctx.registry) {
|
|
11150
|
+
logger.newline();
|
|
11151
|
+
logger.subtitle("Individual Module Selection");
|
|
11152
|
+
for (const category of categories) {
|
|
11153
|
+
const preselected = mode === "both" ? preselectedFromBundles[category] : [];
|
|
11154
|
+
const categoryResult = await selectItemsFromCategory(category, ctx.registry[category], {
|
|
11155
|
+
preselected,
|
|
11156
|
+
showDescriptions: true
|
|
11157
|
+
});
|
|
11158
|
+
if (mode === "both") {
|
|
11159
|
+
result.additionalModules[category] = categoryResult.selectedItems.filter(
|
|
11160
|
+
(id) => !preselected.includes(id)
|
|
11161
|
+
);
|
|
11162
|
+
} else {
|
|
11163
|
+
result.additionalModules[category] = categoryResult.selectedItems;
|
|
11164
|
+
}
|
|
10630
11165
|
}
|
|
10631
|
-
return true;
|
|
10632
11166
|
}
|
|
11167
|
+
}
|
|
11168
|
+
return createResult(result, "next");
|
|
11169
|
+
}
|
|
11170
|
+
};
|
|
11171
|
+
}
|
|
11172
|
+
function createHookConfigStep() {
|
|
11173
|
+
return {
|
|
11174
|
+
metadata: {
|
|
11175
|
+
id: "hookConfig",
|
|
11176
|
+
name: "Notification Hooks",
|
|
11177
|
+
description: "Configure notification and sound hooks",
|
|
11178
|
+
required: false
|
|
11179
|
+
},
|
|
11180
|
+
computeDefaults: (ctx) => {
|
|
11181
|
+
if (ctx.hookConfig) return ctx.hookConfig;
|
|
11182
|
+
const hasTesting = ctx.bundleSelection?.selectedBundles.some((id) => id.includes("testing"));
|
|
11183
|
+
return hasTesting ? { enabled: true } : { enabled: false };
|
|
11184
|
+
},
|
|
11185
|
+
execute: async (_ctx, defaults) => {
|
|
11186
|
+
const goBack = await promptBackOption(4, "Configure hooks or go back?");
|
|
11187
|
+
if (goBack) {
|
|
11188
|
+
return createResult(defaults, "back");
|
|
11189
|
+
}
|
|
11190
|
+
const value = await promptHookConfig({ defaults });
|
|
11191
|
+
return createResult(value, "next");
|
|
11192
|
+
}
|
|
11193
|
+
};
|
|
11194
|
+
}
|
|
11195
|
+
function createMcpConfigStep() {
|
|
11196
|
+
return {
|
|
11197
|
+
metadata: {
|
|
11198
|
+
id: "mcpConfig",
|
|
11199
|
+
name: "MCP Servers",
|
|
11200
|
+
description: "Configure Model Context Protocol servers",
|
|
11201
|
+
required: false
|
|
11202
|
+
},
|
|
11203
|
+
computeDefaults: (ctx) => ctx.mcpConfig,
|
|
11204
|
+
execute: async (_ctx, defaults) => {
|
|
11205
|
+
const goBack = await promptBackOption(5, "Configure MCP servers or go back?");
|
|
11206
|
+
if (goBack) {
|
|
11207
|
+
return createResult(
|
|
11208
|
+
defaults,
|
|
11209
|
+
"back"
|
|
11210
|
+
);
|
|
11211
|
+
}
|
|
11212
|
+
const result = await promptMcpConfig();
|
|
11213
|
+
return createResult(result, "next");
|
|
11214
|
+
}
|
|
11215
|
+
};
|
|
11216
|
+
}
|
|
11217
|
+
function createPermissionsStep() {
|
|
11218
|
+
return {
|
|
11219
|
+
metadata: {
|
|
11220
|
+
id: "permissionsConfig",
|
|
11221
|
+
name: "Permissions",
|
|
11222
|
+
description: "Configure file, git, and bash permissions",
|
|
11223
|
+
required: true
|
|
11224
|
+
},
|
|
11225
|
+
computeDefaults: (ctx) => ctx.permissionsConfig,
|
|
11226
|
+
execute: async (_ctx, defaults) => {
|
|
11227
|
+
const goBack = await promptBackOption(6, "Configure permissions or go back?");
|
|
11228
|
+
if (goBack) {
|
|
11229
|
+
return createResult(defaults, "back");
|
|
11230
|
+
}
|
|
11231
|
+
const value = await promptPermissionsConfig();
|
|
11232
|
+
return createResult(value, "next");
|
|
11233
|
+
}
|
|
11234
|
+
};
|
|
11235
|
+
}
|
|
11236
|
+
function createCodeStyleStep() {
|
|
11237
|
+
return {
|
|
11238
|
+
metadata: {
|
|
11239
|
+
id: "codeStyleConfig",
|
|
11240
|
+
name: "Code Style",
|
|
11241
|
+
description: "Configure EditorConfig, Biome, Prettier, Commitlint",
|
|
11242
|
+
required: false
|
|
11243
|
+
},
|
|
11244
|
+
computeDefaults: (ctx) => ctx.codeStyleConfig,
|
|
11245
|
+
execute: async (_ctx, defaults) => {
|
|
11246
|
+
const goBack = await promptBackOption(7, "Configure code style or go back?");
|
|
11247
|
+
if (goBack) {
|
|
11248
|
+
return createResult(defaults, "back");
|
|
11249
|
+
}
|
|
11250
|
+
const value = await promptCodeStyleConfig({ defaults });
|
|
11251
|
+
return createResult(value, "next");
|
|
11252
|
+
}
|
|
11253
|
+
};
|
|
11254
|
+
}
|
|
11255
|
+
function createCICDStep() {
|
|
11256
|
+
return {
|
|
11257
|
+
metadata: {
|
|
11258
|
+
id: "cicdConfig",
|
|
11259
|
+
name: "CI/CD",
|
|
11260
|
+
description: "Configure GitHub Actions workflows",
|
|
11261
|
+
required: false
|
|
11262
|
+
},
|
|
11263
|
+
computeDefaults: (ctx) => ctx.cicdConfig,
|
|
11264
|
+
execute: async (ctx, defaults) => {
|
|
11265
|
+
const goBack = await promptBackOption(8, "Configure CI/CD or go back?");
|
|
11266
|
+
if (goBack) {
|
|
11267
|
+
return createResult(defaults, "back");
|
|
11268
|
+
}
|
|
11269
|
+
const value = await promptCICDConfig({
|
|
11270
|
+
packageManager: ctx.preferences?.packageManager,
|
|
11271
|
+
defaults
|
|
10633
11272
|
});
|
|
11273
|
+
return createResult(value, "next");
|
|
10634
11274
|
}
|
|
10635
|
-
|
|
10636
|
-
|
|
10637
|
-
|
|
10638
|
-
|
|
10639
|
-
|
|
10640
|
-
|
|
10641
|
-
|
|
10642
|
-
|
|
10643
|
-
|
|
10644
|
-
|
|
10645
|
-
|
|
10646
|
-
|
|
10647
|
-
|
|
11275
|
+
};
|
|
11276
|
+
}
|
|
11277
|
+
function createFolderPreferencesStep() {
|
|
11278
|
+
return {
|
|
11279
|
+
metadata: {
|
|
11280
|
+
id: "folderPreferences",
|
|
11281
|
+
name: "Folder Structure",
|
|
11282
|
+
description: "Configure test, planning, and documentation locations",
|
|
11283
|
+
required: false,
|
|
11284
|
+
dependsOn: ["bundleSelection"]
|
|
11285
|
+
},
|
|
11286
|
+
computeDefaults: (ctx) => ctx.folderPreferences ?? null,
|
|
11287
|
+
execute: async (ctx, defaults) => {
|
|
11288
|
+
const goBack = await promptBackOption(9, "Configure folder preferences or go back?");
|
|
11289
|
+
if (goBack) {
|
|
11290
|
+
return createResult(defaults ?? null, "back");
|
|
11291
|
+
}
|
|
11292
|
+
const value = await promptQuickFolderPreferences({
|
|
11293
|
+
selectedBundles: ctx.bundleSelection?.selectedBundles || [],
|
|
11294
|
+
technologies: ctx.detection.detectedTechnologies || []
|
|
10648
11295
|
});
|
|
11296
|
+
return createResult(value, "next");
|
|
10649
11297
|
}
|
|
10650
|
-
|
|
10651
|
-
|
|
10652
|
-
|
|
10653
|
-
|
|
10654
|
-
|
|
10655
|
-
|
|
10656
|
-
|
|
10657
|
-
|
|
10658
|
-
|
|
10659
|
-
|
|
10660
|
-
|
|
10661
|
-
|
|
10662
|
-
|
|
11298
|
+
};
|
|
11299
|
+
}
|
|
11300
|
+
function createTemplateConfigStep() {
|
|
11301
|
+
return {
|
|
11302
|
+
metadata: {
|
|
11303
|
+
id: "templateConfig",
|
|
11304
|
+
name: "Template Placeholders",
|
|
11305
|
+
description: "Configure template placeholder values",
|
|
11306
|
+
required: false
|
|
11307
|
+
},
|
|
11308
|
+
computeDefaults: (ctx) => ctx.templateConfig ?? {},
|
|
11309
|
+
execute: async (ctx, defaults) => {
|
|
11310
|
+
const goBack = await promptBackOption(10, "Configure templates or go back?");
|
|
11311
|
+
if (goBack) {
|
|
11312
|
+
return createResult(defaults ?? {}, "back");
|
|
11313
|
+
}
|
|
11314
|
+
logger.newline();
|
|
11315
|
+
const configContext = await buildConfigContext(ctx.projectPath);
|
|
11316
|
+
const value = await promptTemplateConfig({
|
|
11317
|
+
context: configContext,
|
|
11318
|
+
mode: "quick"
|
|
10663
11319
|
});
|
|
11320
|
+
return createResult(value ?? {}, "next");
|
|
11321
|
+
}
|
|
11322
|
+
};
|
|
11323
|
+
}
|
|
11324
|
+
function createInitWizardConfig(projectPath, detection, registry) {
|
|
11325
|
+
void projectPath;
|
|
11326
|
+
void detection;
|
|
11327
|
+
void registry;
|
|
11328
|
+
const steps = [
|
|
11329
|
+
{
|
|
11330
|
+
id: "projectInfo",
|
|
11331
|
+
definition: createProjectInfoStep()
|
|
11332
|
+
},
|
|
11333
|
+
{
|
|
11334
|
+
id: "preferences",
|
|
11335
|
+
definition: createPreferencesStep()
|
|
11336
|
+
},
|
|
11337
|
+
{
|
|
11338
|
+
id: "scaffoldOptions",
|
|
11339
|
+
definition: createScaffoldStep()
|
|
11340
|
+
},
|
|
11341
|
+
{
|
|
11342
|
+
id: "bundleSelection",
|
|
11343
|
+
definition: createBundleSelectionStep()
|
|
11344
|
+
},
|
|
11345
|
+
{
|
|
11346
|
+
id: "hookConfig",
|
|
11347
|
+
definition: createHookConfigStep()
|
|
11348
|
+
},
|
|
11349
|
+
{
|
|
11350
|
+
id: "mcpConfig",
|
|
11351
|
+
definition: createMcpConfigStep()
|
|
11352
|
+
},
|
|
11353
|
+
{
|
|
11354
|
+
id: "permissionsConfig",
|
|
11355
|
+
definition: createPermissionsStep()
|
|
11356
|
+
},
|
|
11357
|
+
{
|
|
11358
|
+
id: "codeStyleConfig",
|
|
11359
|
+
definition: createCodeStyleStep()
|
|
11360
|
+
},
|
|
11361
|
+
{
|
|
11362
|
+
id: "cicdConfig",
|
|
11363
|
+
definition: createCICDStep()
|
|
11364
|
+
},
|
|
11365
|
+
{
|
|
11366
|
+
id: "folderPreferences",
|
|
11367
|
+
definition: createFolderPreferencesStep()
|
|
11368
|
+
},
|
|
11369
|
+
{
|
|
11370
|
+
id: "templateConfig",
|
|
11371
|
+
definition: createTemplateConfigStep()
|
|
11372
|
+
}
|
|
11373
|
+
];
|
|
11374
|
+
return {
|
|
11375
|
+
id: "init-wizard",
|
|
11376
|
+
title: "Claude Code Configuration",
|
|
11377
|
+
allowSkip: true,
|
|
11378
|
+
showProgress: true,
|
|
11379
|
+
steps
|
|
11380
|
+
};
|
|
11381
|
+
}
|
|
11382
|
+
|
|
11383
|
+
// src/cli/prompts/index.ts
|
|
11384
|
+
init_esm_shims();
|
|
11385
|
+
|
|
11386
|
+
// src/cli/prompts/update.ts
|
|
11387
|
+
init_esm_shims();
|
|
11388
|
+
async function promptUpdateAction() {
|
|
11389
|
+
logger.subtitle("Update Options");
|
|
11390
|
+
return select({
|
|
11391
|
+
message: "What would you like to update?",
|
|
11392
|
+
choices: [
|
|
11393
|
+
{
|
|
11394
|
+
name: "Check for updates",
|
|
11395
|
+
value: "check",
|
|
11396
|
+
description: "Show what has changed without modifying files"
|
|
11397
|
+
},
|
|
11398
|
+
{
|
|
11399
|
+
name: "Update modules only",
|
|
11400
|
+
value: "modules",
|
|
11401
|
+
description: "Update agents, skills, commands, docs"
|
|
11402
|
+
},
|
|
11403
|
+
{
|
|
11404
|
+
name: "Reconfigure settings",
|
|
11405
|
+
value: "config",
|
|
11406
|
+
description: "Re-run configuration for MCP, hooks, preferences"
|
|
11407
|
+
},
|
|
11408
|
+
{
|
|
11409
|
+
name: "Full update",
|
|
11410
|
+
value: "all",
|
|
11411
|
+
description: "Update everything"
|
|
11412
|
+
},
|
|
11413
|
+
{
|
|
11414
|
+
name: "Cancel",
|
|
11415
|
+
value: "cancel"
|
|
11416
|
+
}
|
|
11417
|
+
],
|
|
11418
|
+
default: "check"
|
|
11419
|
+
});
|
|
11420
|
+
}
|
|
11421
|
+
function showUpdateReport(updates) {
|
|
11422
|
+
logger.newline();
|
|
11423
|
+
logger.title("Update Report");
|
|
11424
|
+
if (updates.new.length === 0 && updates.updated.length === 0 && updates.deprecated.length === 0) {
|
|
11425
|
+
logger.success("Everything is up to date!");
|
|
11426
|
+
return;
|
|
11427
|
+
}
|
|
11428
|
+
if (updates.new.length > 0) {
|
|
11429
|
+
logger.newline();
|
|
11430
|
+
logger.info(colors.bold(`\u271A New modules available (${updates.new.length}):`));
|
|
11431
|
+
for (const mod of updates.new) {
|
|
11432
|
+
logger.item(`${mod.category}: ${colors.primary(mod.name)}`);
|
|
10664
11433
|
}
|
|
10665
11434
|
}
|
|
10666
|
-
|
|
10667
|
-
|
|
10668
|
-
|
|
10669
|
-
|
|
10670
|
-
|
|
10671
|
-
|
|
10672
|
-
tracking: {},
|
|
10673
|
-
techStack: {},
|
|
10674
|
-
environment: {},
|
|
10675
|
-
brand: {}
|
|
10676
|
-
};
|
|
10677
|
-
for (const placeholder of TEMPLATE_PLACEHOLDERS) {
|
|
10678
|
-
const defaultValue = computeDefaultValue(placeholder, context);
|
|
10679
|
-
if (defaultValue) {
|
|
10680
|
-
setConfigValue(config, placeholder, defaultValue);
|
|
11435
|
+
if (updates.updated.length > 0) {
|
|
11436
|
+
logger.newline();
|
|
11437
|
+
logger.info(colors.bold(`\u21BB Updated modules (${updates.updated.length}):`));
|
|
11438
|
+
for (const mod of updates.updated) {
|
|
11439
|
+
const conflict = mod.hasLocalChanges ? colors.warning(" (local changes)") : "";
|
|
11440
|
+
logger.item(`${mod.category}: ${colors.primary(mod.name)}${conflict}`);
|
|
10681
11441
|
}
|
|
10682
11442
|
}
|
|
10683
|
-
if (
|
|
10684
|
-
|
|
10685
|
-
|
|
10686
|
-
|
|
10687
|
-
}
|
|
10688
|
-
function setConfigValue(config, placeholder, value) {
|
|
10689
|
-
const key = placeholderKeyToConfigKey(placeholder.key, placeholder.category);
|
|
10690
|
-
switch (placeholder.category) {
|
|
10691
|
-
case "commands":
|
|
10692
|
-
if (!config.commands) config.commands = {};
|
|
10693
|
-
config.commands[key] = value;
|
|
10694
|
-
break;
|
|
10695
|
-
case "paths":
|
|
10696
|
-
if (!config.paths) config.paths = {};
|
|
10697
|
-
config.paths[key] = value;
|
|
10698
|
-
break;
|
|
10699
|
-
case "targets":
|
|
10700
|
-
case "performance": {
|
|
10701
|
-
if (!config.targets) config.targets = {};
|
|
10702
|
-
const numValue = Number(value);
|
|
10703
|
-
if (!Number.isNaN(numValue)) {
|
|
10704
|
-
config.targets[key] = numValue;
|
|
10705
|
-
} else {
|
|
10706
|
-
config.targets[key] = value;
|
|
10707
|
-
}
|
|
10708
|
-
break;
|
|
11443
|
+
if (updates.deprecated.length > 0) {
|
|
11444
|
+
logger.newline();
|
|
11445
|
+
logger.info(colors.bold(`\u2717 Deprecated modules (${updates.deprecated.length}):`));
|
|
11446
|
+
for (const mod of updates.deprecated) {
|
|
11447
|
+
logger.item(`${mod.category}: ${colors.muted(mod.name)}`);
|
|
10709
11448
|
}
|
|
10710
|
-
case "tracking":
|
|
10711
|
-
if (!config.tracking) config.tracking = {};
|
|
10712
|
-
config.tracking[key] = key.endsWith("Days") ? Number(value) : value;
|
|
10713
|
-
break;
|
|
10714
|
-
case "techStack":
|
|
10715
|
-
if (!config.techStack) config.techStack = {};
|
|
10716
|
-
config.techStack[key] = value;
|
|
10717
|
-
break;
|
|
10718
|
-
case "environment":
|
|
10719
|
-
if (!config.environment) config.environment = {};
|
|
10720
|
-
config.environment[key] = value;
|
|
10721
|
-
break;
|
|
10722
|
-
case "brand":
|
|
10723
|
-
if (!config.brand) config.brand = {};
|
|
10724
|
-
config.brand[key] = value;
|
|
10725
|
-
break;
|
|
10726
11449
|
}
|
|
10727
|
-
|
|
10728
|
-
|
|
10729
|
-
|
|
10730
|
-
|
|
10731
|
-
|
|
10732
|
-
|
|
10733
|
-
cleanKey = key.slice(0, -4);
|
|
10734
|
-
} else if (key.endsWith("_TARGET")) {
|
|
10735
|
-
cleanKey = key.slice(0, -7);
|
|
11450
|
+
if (updates.conflicts.length > 0) {
|
|
11451
|
+
logger.newline();
|
|
11452
|
+
logger.warn(`\u26A0 Modules with conflicts (${updates.conflicts.length}):`);
|
|
11453
|
+
for (const mod of updates.conflicts) {
|
|
11454
|
+
logger.item(`${mod.category}: ${colors.warning(mod.name)} - has local modifications`);
|
|
11455
|
+
}
|
|
10736
11456
|
}
|
|
10737
|
-
return cleanKey.toLowerCase().replace(/_([a-z])/g, (_, char) => char.toUpperCase());
|
|
10738
11457
|
}
|
|
10739
|
-
async function
|
|
10740
|
-
|
|
10741
|
-
logger.section("Template Configuration", "\u{1F4DD}");
|
|
10742
|
-
logger.newline();
|
|
10743
|
-
logger.info("This step personalizes all Claude Code configuration files for YOUR project.");
|
|
10744
|
-
logger.info("Your answers will be used to:");
|
|
10745
|
-
logger.newline();
|
|
10746
|
-
logger.item("Replace {{PLACEHOLDERS}} in agents, commands, and skills");
|
|
10747
|
-
logger.item("Configure CLAUDE.md with your tech stack and commands");
|
|
10748
|
-
logger.item("Set up quality targets (coverage, performance, accessibility)");
|
|
10749
|
-
logger.item("Customize code examples to match your project structure");
|
|
10750
|
-
logger.newline();
|
|
10751
|
-
logger.info("Accurate configuration means better AI assistance tailored to your codebase!");
|
|
11458
|
+
async function promptNewModules(modules) {
|
|
11459
|
+
if (modules.length === 0) return [];
|
|
10752
11460
|
logger.newline();
|
|
10753
|
-
const
|
|
10754
|
-
|
|
10755
|
-
|
|
10756
|
-
|
|
10757
|
-
}
|
|
10758
|
-
|
|
10759
|
-
|
|
10760
|
-
|
|
10761
|
-
|
|
10762
|
-
return promptGuidedSetup(context, requiredOnly);
|
|
10763
|
-
}
|
|
10764
|
-
return promptAdvancedSetup(context);
|
|
11461
|
+
const choices = modules.map((mod) => ({
|
|
11462
|
+
name: `${mod.category}: ${mod.name}`,
|
|
11463
|
+
value: mod.id,
|
|
11464
|
+
checked: false
|
|
11465
|
+
}));
|
|
11466
|
+
return checkbox({
|
|
11467
|
+
message: "Select new modules to install:",
|
|
11468
|
+
choices
|
|
11469
|
+
});
|
|
10765
11470
|
}
|
|
10766
|
-
async function
|
|
10767
|
-
|
|
11471
|
+
async function promptUpdatedModules(modules) {
|
|
11472
|
+
if (modules.length === 0) return [];
|
|
10768
11473
|
logger.newline();
|
|
10769
|
-
const
|
|
10770
|
-
|
|
10771
|
-
|
|
10772
|
-
|
|
10773
|
-
default
|
|
11474
|
+
const choices = modules.map((mod) => ({
|
|
11475
|
+
name: `${mod.category}: ${mod.name}${mod.hasLocalChanges ? " \u26A0\uFE0F" : ""}`,
|
|
11476
|
+
value: mod.id,
|
|
11477
|
+
checked: !mod.hasLocalChanges
|
|
11478
|
+
// Don't check by default if has local changes
|
|
11479
|
+
}));
|
|
11480
|
+
return checkbox({
|
|
11481
|
+
message: "Select modules to update:",
|
|
11482
|
+
choices
|
|
10774
11483
|
});
|
|
10775
|
-
let finalConfig = detected;
|
|
10776
|
-
if (wantEdit) {
|
|
10777
|
-
finalConfig = await promptEditConfig(detected, context);
|
|
10778
|
-
}
|
|
10779
|
-
return finalConfig;
|
|
10780
|
-
}
|
|
10781
|
-
function displayDetectedConfig(config, _context) {
|
|
10782
|
-
const categories = Object.entries(CATEGORY_INFO).sort(([, a], [, b]) => a.order - b.order).map(([key]) => key);
|
|
10783
|
-
for (const category of categories) {
|
|
10784
|
-
const placeholders = getPlaceholdersByCategory(category);
|
|
10785
|
-
if (placeholders.length === 0) continue;
|
|
10786
|
-
const values = getCategoryValues(config, category);
|
|
10787
|
-
if (Object.keys(values).length === 0) continue;
|
|
10788
|
-
logger.subtitle(CATEGORY_INFO[category].name);
|
|
10789
|
-
for (const [key, value] of Object.entries(values)) {
|
|
10790
|
-
if (value !== void 0) {
|
|
10791
|
-
const placeholder = TEMPLATE_PLACEHOLDERS.find(
|
|
10792
|
-
(p) => placeholderKeyToConfigKey(p.key, p.category) === key
|
|
10793
|
-
);
|
|
10794
|
-
const label = placeholder?.label || key;
|
|
10795
|
-
logger.keyValue(label, String(value));
|
|
10796
|
-
}
|
|
10797
|
-
}
|
|
10798
|
-
logger.newline();
|
|
10799
|
-
}
|
|
10800
|
-
}
|
|
10801
|
-
function getCategoryValues(config, category) {
|
|
10802
|
-
switch (category) {
|
|
10803
|
-
case "commands":
|
|
10804
|
-
return config.commands || {};
|
|
10805
|
-
case "paths":
|
|
10806
|
-
return config.paths || {};
|
|
10807
|
-
case "targets":
|
|
10808
|
-
case "performance":
|
|
10809
|
-
return config.targets || {};
|
|
10810
|
-
case "tracking":
|
|
10811
|
-
return config.tracking || {};
|
|
10812
|
-
case "techStack":
|
|
10813
|
-
return config.techStack || {};
|
|
10814
|
-
case "environment":
|
|
10815
|
-
return config.environment || {};
|
|
10816
|
-
case "brand":
|
|
10817
|
-
return config.brand || {};
|
|
10818
|
-
default:
|
|
10819
|
-
return {};
|
|
10820
|
-
}
|
|
10821
11484
|
}
|
|
10822
|
-
async function
|
|
10823
|
-
|
|
10824
|
-
|
|
10825
|
-
|
|
11485
|
+
async function promptConflictResolution(module) {
|
|
11486
|
+
logger.newline();
|
|
11487
|
+
logger.warn(`Conflict: ${module.category}/${module.name} has local modifications`);
|
|
11488
|
+
return select({
|
|
11489
|
+
message: "How do you want to resolve this conflict?",
|
|
10826
11490
|
choices: [
|
|
10827
|
-
|
|
10828
|
-
name:
|
|
10829
|
-
value:
|
|
10830
|
-
|
|
10831
|
-
|
|
10832
|
-
|
|
11491
|
+
{
|
|
11492
|
+
name: "Keep local version",
|
|
11493
|
+
value: "keep",
|
|
11494
|
+
description: "Do not update this module"
|
|
11495
|
+
},
|
|
11496
|
+
{
|
|
11497
|
+
name: "Use updated version",
|
|
11498
|
+
value: "update",
|
|
11499
|
+
description: "Replace with new version (lose local changes)"
|
|
11500
|
+
},
|
|
11501
|
+
{
|
|
11502
|
+
name: "Show diff",
|
|
11503
|
+
value: "diff",
|
|
11504
|
+
description: "See what changed before deciding"
|
|
11505
|
+
}
|
|
11506
|
+
],
|
|
11507
|
+
default: "keep"
|
|
10833
11508
|
});
|
|
10834
|
-
|
|
10835
|
-
|
|
10836
|
-
|
|
10837
|
-
|
|
10838
|
-
|
|
10839
|
-
|
|
10840
|
-
|
|
10841
|
-
|
|
10842
|
-
|
|
10843
|
-
|
|
10844
|
-
|
|
10845
|
-
|
|
10846
|
-
case "targets":
|
|
10847
|
-
case "performance":
|
|
10848
|
-
merged.targets = { ...config.targets, ...editedCategory.targets };
|
|
10849
|
-
break;
|
|
10850
|
-
case "tracking":
|
|
10851
|
-
merged.tracking = { ...config.tracking, ...editedCategory.tracking };
|
|
10852
|
-
break;
|
|
10853
|
-
case "techStack":
|
|
10854
|
-
merged.techStack = { ...config.techStack, ...editedCategory.techStack };
|
|
10855
|
-
break;
|
|
10856
|
-
case "environment":
|
|
10857
|
-
merged.environment = { ...config.environment, ...editedCategory.environment };
|
|
10858
|
-
break;
|
|
10859
|
-
case "brand":
|
|
10860
|
-
merged.brand = { ...config.brand, ...editedCategory.brand };
|
|
10861
|
-
break;
|
|
10862
|
-
}
|
|
10863
|
-
const editMore = await confirm({
|
|
10864
|
-
message: "Edit another category?",
|
|
10865
|
-
default: false
|
|
11509
|
+
}
|
|
11510
|
+
async function promptReconfigureOptions() {
|
|
11511
|
+
logger.newline();
|
|
11512
|
+
return checkbox({
|
|
11513
|
+
message: "What would you like to reconfigure?",
|
|
11514
|
+
choices: [
|
|
11515
|
+
{ name: "MCP servers", value: "mcp", checked: false },
|
|
11516
|
+
{ name: "Hooks", value: "hooks", checked: false },
|
|
11517
|
+
{ name: "Preferences (language, co-author)", value: "preferences", checked: false },
|
|
11518
|
+
{ name: "Permissions", value: "permissions", checked: false },
|
|
11519
|
+
{ name: "Add/remove modules", value: "modules", checked: false }
|
|
11520
|
+
]
|
|
10866
11521
|
});
|
|
10867
|
-
if (editMore) {
|
|
10868
|
-
return promptEditConfig(merged, context);
|
|
10869
|
-
}
|
|
10870
|
-
return merged;
|
|
10871
11522
|
}
|
|
10872
|
-
|
|
10873
|
-
|
|
10874
|
-
|
|
10875
|
-
|
|
10876
|
-
|
|
10877
|
-
|
|
10878
|
-
|
|
10879
|
-
|
|
10880
|
-
|
|
10881
|
-
|
|
10882
|
-
|
|
10883
|
-
|
|
10884
|
-
|
|
10885
|
-
|
|
11523
|
+
|
|
11524
|
+
// src/cli/prompts/confirm.ts
|
|
11525
|
+
init_esm_shims();
|
|
11526
|
+
async function promptExistingProjectAction() {
|
|
11527
|
+
return select({
|
|
11528
|
+
message: "Existing .claude/ folder detected. What would you like to do?",
|
|
11529
|
+
choices: [
|
|
11530
|
+
{
|
|
11531
|
+
name: "Skip (keep existing)",
|
|
11532
|
+
value: "skip",
|
|
11533
|
+
description: "Do not modify existing configuration"
|
|
11534
|
+
},
|
|
11535
|
+
{
|
|
11536
|
+
name: "Overwrite",
|
|
11537
|
+
value: "overwrite",
|
|
11538
|
+
description: "Replace existing configuration"
|
|
11539
|
+
},
|
|
11540
|
+
{
|
|
11541
|
+
name: "Merge",
|
|
11542
|
+
value: "merge",
|
|
11543
|
+
description: "Add new items, keep existing"
|
|
11544
|
+
}
|
|
11545
|
+
],
|
|
11546
|
+
default: "skip"
|
|
11547
|
+
});
|
|
11548
|
+
}
|
|
11549
|
+
function showFinalSummary(config) {
|
|
11550
|
+
logger.newline();
|
|
11551
|
+
logger.title("Configuration Summary");
|
|
11552
|
+
logger.subtitle("Project");
|
|
11553
|
+
logger.keyValue("Name", config.project.name);
|
|
11554
|
+
logger.keyValue("GitHub", `${config.project.org}/${config.project.repo}`);
|
|
11555
|
+
if (config.project.domain) {
|
|
11556
|
+
logger.keyValue("Domain", config.project.domain);
|
|
10886
11557
|
}
|
|
10887
|
-
|
|
10888
|
-
|
|
10889
|
-
|
|
10890
|
-
|
|
10891
|
-
|
|
10892
|
-
|
|
11558
|
+
logger.newline();
|
|
11559
|
+
logger.subtitle("Preferences");
|
|
11560
|
+
logger.keyValue("Language", config.preferences.language === "en" ? "English" : "Espa\xF1ol");
|
|
11561
|
+
logger.keyValue("Co-author", config.preferences.includeCoAuthor ? "Yes" : "No");
|
|
11562
|
+
logger.newline();
|
|
11563
|
+
logger.subtitle("Modules");
|
|
11564
|
+
const moduleCategories = ["agents", "skills", "commands", "docs"];
|
|
11565
|
+
for (const category of moduleCategories) {
|
|
11566
|
+
const selected = config.modules[category].selected;
|
|
11567
|
+
if (selected.length > 0) {
|
|
11568
|
+
logger.keyValue(capitalize2(category), `${selected.length} selected`);
|
|
11569
|
+
logger.note(selected.join(", "));
|
|
10893
11570
|
}
|
|
10894
11571
|
}
|
|
10895
|
-
|
|
10896
|
-
|
|
10897
|
-
|
|
10898
|
-
|
|
10899
|
-
|
|
10900
|
-
|
|
10901
|
-
|
|
10902
|
-
|
|
10903
|
-
|
|
10904
|
-
|
|
10905
|
-
|
|
10906
|
-
|
|
10907
|
-
|
|
10908
|
-
|
|
10909
|
-
|
|
10910
|
-
const placeholders = getPlaceholdersByCategory(category);
|
|
10911
|
-
const relevantPlaceholders = requiredOnly ? placeholders.filter((p) => p.required) : placeholders;
|
|
10912
|
-
if (relevantPlaceholders.length === 0) continue;
|
|
10913
|
-
const configureCategory = await confirm({
|
|
10914
|
-
message: `Configure ${CATEGORY_INFO[category].name}? (${relevantPlaceholders.length} options)`,
|
|
10915
|
-
default: true
|
|
10916
|
-
});
|
|
10917
|
-
if (!configureCategory) continue;
|
|
10918
|
-
const categoryConfig = await promptCategory(category, updatedContext, requiredOnly);
|
|
10919
|
-
switch (category) {
|
|
10920
|
-
case "commands":
|
|
10921
|
-
config.commands = { ...config.commands, ...categoryConfig.commands };
|
|
10922
|
-
break;
|
|
10923
|
-
case "paths":
|
|
10924
|
-
config.paths = { ...config.paths, ...categoryConfig.paths };
|
|
10925
|
-
break;
|
|
10926
|
-
case "targets":
|
|
10927
|
-
case "performance":
|
|
10928
|
-
config.targets = { ...config.targets, ...categoryConfig.targets };
|
|
10929
|
-
break;
|
|
10930
|
-
case "tracking":
|
|
10931
|
-
config.tracking = { ...config.tracking, ...categoryConfig.tracking };
|
|
10932
|
-
break;
|
|
10933
|
-
case "techStack":
|
|
10934
|
-
config.techStack = { ...config.techStack, ...categoryConfig.techStack };
|
|
10935
|
-
break;
|
|
10936
|
-
case "environment":
|
|
10937
|
-
config.environment = { ...config.environment, ...categoryConfig.environment };
|
|
10938
|
-
break;
|
|
10939
|
-
case "brand":
|
|
10940
|
-
config.brand = { ...config.brand, ...categoryConfig.brand };
|
|
10941
|
-
break;
|
|
10942
|
-
}
|
|
10943
|
-
for (const [key, value] of Object.entries(getCategoryValues(categoryConfig, category))) {
|
|
10944
|
-
if (value !== void 0) {
|
|
10945
|
-
updatedContext.values[key.toUpperCase()] = String(value);
|
|
10946
|
-
}
|
|
10947
|
-
}
|
|
11572
|
+
logger.newline();
|
|
11573
|
+
logger.subtitle("Extras");
|
|
11574
|
+
const extras = [];
|
|
11575
|
+
if (config.extras.schemas) extras.push("schemas");
|
|
11576
|
+
if (config.extras.scripts) extras.push("scripts");
|
|
11577
|
+
if (config.extras.hooks.enabled) extras.push("hooks");
|
|
11578
|
+
if (config.extras.sessions) extras.push("sessions");
|
|
11579
|
+
logger.keyValue("Included", extras.join(", ") || "none");
|
|
11580
|
+
if (config.extras.codeStyle?.enabled) {
|
|
11581
|
+
const codeStyleTools = [];
|
|
11582
|
+
if (config.extras.codeStyle.editorconfig) codeStyleTools.push("EditorConfig");
|
|
11583
|
+
if (config.extras.codeStyle.commitlint) codeStyleTools.push("Commitlint");
|
|
11584
|
+
if (config.extras.codeStyle.biome) codeStyleTools.push("Biome");
|
|
11585
|
+
if (config.extras.codeStyle.prettier) codeStyleTools.push("Prettier");
|
|
11586
|
+
logger.keyValue("Code Style", codeStyleTools.join(", "));
|
|
10948
11587
|
}
|
|
10949
|
-
|
|
10950
|
-
|
|
10951
|
-
|
|
10952
|
-
|
|
11588
|
+
if (config.mcp.servers.length > 0) {
|
|
11589
|
+
logger.newline();
|
|
11590
|
+
logger.subtitle("MCP Servers");
|
|
11591
|
+
logger.keyValue("Level", config.mcp.level);
|
|
11592
|
+
logger.keyValue("Servers", config.mcp.servers.map((s) => s.serverId).join(", "));
|
|
11593
|
+
}
|
|
11594
|
+
logger.newline();
|
|
11595
|
+
logger.subtitle("Scaffold");
|
|
11596
|
+
logger.keyValue(
|
|
11597
|
+
"Type",
|
|
11598
|
+
config.scaffold.type === "claude-only" ? "Claude config only" : "Full project"
|
|
11599
|
+
);
|
|
10953
11600
|
}
|
|
10954
|
-
async function
|
|
11601
|
+
async function confirmFinalConfiguration(config) {
|
|
11602
|
+
showFinalSummary(config);
|
|
10955
11603
|
logger.newline();
|
|
10956
|
-
logger.subtitle("Configuration Summary");
|
|
10957
|
-
displayDetectedConfig(config, context);
|
|
10958
11604
|
return confirm({
|
|
10959
|
-
message: "
|
|
11605
|
+
message: "Proceed with this configuration?",
|
|
10960
11606
|
default: true
|
|
10961
11607
|
});
|
|
10962
11608
|
}
|
|
10963
|
-
|
|
10964
|
-
|
|
10965
|
-
|
|
10966
|
-
|
|
10967
|
-
|
|
10968
|
-
|
|
10969
|
-
await updateGlobalDefaults(config);
|
|
10970
|
-
logger.success("Global defaults saved to ~/.claude/defaults.json");
|
|
11609
|
+
function showPostInstallInstructions(config) {
|
|
11610
|
+
logger.newline();
|
|
11611
|
+
logger.title("Installation Complete!");
|
|
11612
|
+
const steps = [];
|
|
11613
|
+
if (config.scaffold.type === "full-project") {
|
|
11614
|
+
steps.push("Review the generated project structure");
|
|
10971
11615
|
}
|
|
10972
|
-
|
|
11616
|
+
steps.push("Review .claude/CLAUDE.md for agent instructions");
|
|
11617
|
+
steps.push("Customize agents, commands, and skills as needed");
|
|
11618
|
+
if (config.mcp.servers.length > 0) {
|
|
11619
|
+
const mcpFile = config.mcp.level === "user" ? "~/.claude/settings.json" : ".claude/settings.local.json";
|
|
11620
|
+
steps.push(`Configure MCP server credentials in ${mcpFile}`);
|
|
11621
|
+
}
|
|
11622
|
+
if (config.extras.hooks.enabled) {
|
|
11623
|
+
steps.push("Review hook scripts in .claude/hooks/");
|
|
11624
|
+
if (config.extras.hooks.notification?.audio) {
|
|
11625
|
+
steps.push("Install Piper TTS for audio notifications (see docs)");
|
|
11626
|
+
}
|
|
11627
|
+
}
|
|
11628
|
+
logger.instructions("Next Steps:", steps);
|
|
11629
|
+
logger.subtitle("Useful Commands");
|
|
11630
|
+
logger.raw("");
|
|
11631
|
+
logger.raw(` ${colors.primary("claude-config status")} - Show current configuration`);
|
|
11632
|
+
logger.raw(` ${colors.primary("claude-config list")} - List available modules`);
|
|
11633
|
+
logger.raw(` ${colors.primary("claude-config add")} - Add a module`);
|
|
11634
|
+
logger.raw(` ${colors.primary("claude-config update")} - Update configuration`);
|
|
11635
|
+
logger.raw("");
|
|
11636
|
+
}
|
|
11637
|
+
function capitalize2(str) {
|
|
11638
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
10973
11639
|
}
|
|
10974
11640
|
|
|
10975
11641
|
// src/cli/commands/init.ts
|
|
@@ -11186,52 +11852,65 @@ async function buildDefaultConfig(projectPath, detection, options) {
|
|
|
11186
11852
|
async function buildInteractiveConfig(projectPath, detection, registry, options) {
|
|
11187
11853
|
const projectName = await getProjectName(projectPath);
|
|
11188
11854
|
const projectDesc = await getProjectDescription(projectPath);
|
|
11189
|
-
const
|
|
11190
|
-
|
|
11191
|
-
|
|
11192
|
-
|
|
11855
|
+
const wizardConfig = createInitWizardConfig(
|
|
11856
|
+
projectPath,
|
|
11857
|
+
{
|
|
11858
|
+
detected: detection.detected,
|
|
11859
|
+
projectType: detection.projectType,
|
|
11860
|
+
packageManager: detection.packageManager,
|
|
11861
|
+
suggestedBundles: detection.suggestedBundles,
|
|
11862
|
+
detectedTechnologies: detection.detectedTechnologies
|
|
11863
|
+
},
|
|
11864
|
+
registry
|
|
11865
|
+
);
|
|
11866
|
+
const initialContext = {
|
|
11867
|
+
projectPath,
|
|
11868
|
+
registry,
|
|
11869
|
+
detection: {
|
|
11870
|
+
detected: detection.detected,
|
|
11871
|
+
projectType: detection.projectType,
|
|
11872
|
+
packageManager: detection.packageManager,
|
|
11873
|
+
suggestedBundles: detection.suggestedBundles,
|
|
11874
|
+
detectedTechnologies: detection.detectedTechnologies
|
|
11875
|
+
},
|
|
11876
|
+
projectInfo: {
|
|
11877
|
+
name: projectName || "",
|
|
11878
|
+
description: projectDesc || "",
|
|
11879
|
+
org: "",
|
|
11880
|
+
repo: projectName?.toLowerCase().replace(/\s+/g, "-") || "",
|
|
11881
|
+
entityType: "item",
|
|
11882
|
+
entityTypePlural: "items"
|
|
11193
11883
|
}
|
|
11194
|
-
}
|
|
11195
|
-
const
|
|
11196
|
-
|
|
11197
|
-
|
|
11884
|
+
};
|
|
11885
|
+
const wizardResult = await runWizard(
|
|
11886
|
+
wizardConfig,
|
|
11887
|
+
initialContext
|
|
11888
|
+
);
|
|
11889
|
+
if (wizardResult.cancelled) {
|
|
11890
|
+
return null;
|
|
11198
11891
|
}
|
|
11199
|
-
|
|
11200
|
-
|
|
11201
|
-
|
|
11202
|
-
|
|
11203
|
-
|
|
11204
|
-
|
|
11205
|
-
|
|
11206
|
-
|
|
11207
|
-
|
|
11208
|
-
|
|
11209
|
-
|
|
11210
|
-
|
|
11211
|
-
|
|
11212
|
-
}
|
|
11892
|
+
showWizardSummary(wizardResult.state);
|
|
11893
|
+
const {
|
|
11894
|
+
projectInfo,
|
|
11895
|
+
preferences,
|
|
11896
|
+
scaffoldOptions,
|
|
11897
|
+
bundleSelection,
|
|
11898
|
+
hookConfig,
|
|
11899
|
+
mcpConfig: mcpResult,
|
|
11900
|
+
permissionsConfig,
|
|
11901
|
+
codeStyleConfig,
|
|
11902
|
+
cicdConfig,
|
|
11903
|
+
folderPreferences,
|
|
11904
|
+
templateConfig: templateConfigResult
|
|
11905
|
+
} = wizardResult.values;
|
|
11213
11906
|
let mcpConfig = { level: "project", servers: [] };
|
|
11214
11907
|
let skippedMcpConfigs = [];
|
|
11215
|
-
if (!options.noMcp) {
|
|
11216
|
-
const mcpResult = await promptMcpConfig();
|
|
11908
|
+
if (!options.noMcp && mcpResult) {
|
|
11217
11909
|
mcpConfig = mcpResult.config;
|
|
11218
11910
|
skippedMcpConfigs = mcpResult.skippedConfigs;
|
|
11219
11911
|
}
|
|
11220
|
-
const
|
|
11221
|
-
const
|
|
11222
|
-
const cicdConfig = await promptCICDConfig({
|
|
11223
|
-
packageManager: preferences.packageManager
|
|
11224
|
-
});
|
|
11225
|
-
const folderPreferences = await promptQuickFolderPreferences({
|
|
11226
|
-
selectedBundles: bundleSelection.selectedBundles,
|
|
11227
|
-
technologies: detection.detectedTechnologies || []
|
|
11228
|
-
});
|
|
11229
|
-
logger.newline();
|
|
11230
|
-
const configContext = await buildConfigContext(projectPath);
|
|
11231
|
-
const templateConfigResult = await promptTemplateConfig({
|
|
11232
|
-
context: configContext,
|
|
11233
|
-
mode: "quick"
|
|
11234
|
-
});
|
|
11912
|
+
const hasPlanning = bundleSelection.selectedBundles.some((id) => id.includes("planning"));
|
|
11913
|
+
const hasTesting = bundleSelection.selectedBundles.some((id) => id.includes("testing"));
|
|
11235
11914
|
const resolvedModules = resolveBundles(bundleSelection.selectedBundles);
|
|
11236
11915
|
const modules = {
|
|
11237
11916
|
agents: [.../* @__PURE__ */ new Set([...resolvedModules.agents, ...bundleSelection.additionalModules.agents])],
|
|
@@ -11283,51 +11962,6 @@ async function buildInteractiveConfig(projectPath, detection, registry, options)
|
|
|
11283
11962
|
cicdConfig
|
|
11284
11963
|
};
|
|
11285
11964
|
}
|
|
11286
|
-
async function selectModulesWithBundles(registry, suggestedBundles) {
|
|
11287
|
-
const categories = ["agents", "skills", "commands", "docs"];
|
|
11288
|
-
const mode = await promptBundleMode();
|
|
11289
|
-
const result = {
|
|
11290
|
-
selectedBundles: [],
|
|
11291
|
-
additionalModules: {
|
|
11292
|
-
agents: [],
|
|
11293
|
-
skills: [],
|
|
11294
|
-
commands: [],
|
|
11295
|
-
docs: []
|
|
11296
|
-
}
|
|
11297
|
-
};
|
|
11298
|
-
if (mode === "bundles" || mode === "both") {
|
|
11299
|
-
if (suggestedBundles && suggestedBundles.length > 0) {
|
|
11300
|
-
logger.newline();
|
|
11301
|
-
logger.info(
|
|
11302
|
-
colors.muted(`Suggested bundles based on your project: ${suggestedBundles.join(", ")}`)
|
|
11303
|
-
);
|
|
11304
|
-
}
|
|
11305
|
-
result.selectedBundles = await promptQuickBundleSelection();
|
|
11306
|
-
if (result.selectedBundles.length > 0) {
|
|
11307
|
-
showBundlesSummary(result.selectedBundles);
|
|
11308
|
-
}
|
|
11309
|
-
}
|
|
11310
|
-
if (mode === "individual" || mode === "both") {
|
|
11311
|
-
const preselectedFromBundles = resolveBundles(result.selectedBundles);
|
|
11312
|
-
logger.newline();
|
|
11313
|
-
logger.subtitle("Individual Module Selection");
|
|
11314
|
-
for (const category of categories) {
|
|
11315
|
-
const preselected = mode === "both" ? preselectedFromBundles[category] : [];
|
|
11316
|
-
const categoryResult = await selectItemsFromCategory(category, registry[category], {
|
|
11317
|
-
preselected,
|
|
11318
|
-
showDescriptions: true
|
|
11319
|
-
});
|
|
11320
|
-
if (mode === "both") {
|
|
11321
|
-
result.additionalModules[category] = categoryResult.selectedItems.filter(
|
|
11322
|
-
(id) => !preselected.includes(id)
|
|
11323
|
-
);
|
|
11324
|
-
} else {
|
|
11325
|
-
result.additionalModules[category] = categoryResult.selectedItems;
|
|
11326
|
-
}
|
|
11327
|
-
}
|
|
11328
|
-
}
|
|
11329
|
-
return result;
|
|
11330
|
-
}
|
|
11331
11965
|
async function executeInstallation(projectPath, config, registry, templatesPath, options, cicdConfig) {
|
|
11332
11966
|
logger.newline();
|
|
11333
11967
|
logger.title("Installing Configuration");
|