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