specweave 0.26.14 ā 0.27.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/CLAUDE.md +73 -1
- package/README.md +111 -466
- package/dist/plugins/specweave-jira/lib/setup-wizard.d.ts.map +1 -1
- package/dist/plugins/specweave-jira/lib/setup-wizard.js +57 -78
- package/dist/plugins/specweave-jira/lib/setup-wizard.js.map +1 -1
- package/dist/src/cli/commands/import-docs.d.ts.map +1 -1
- package/dist/src/cli/commands/import-docs.js +23 -31
- package/dist/src/cli/commands/import-docs.js.map +1 -1
- package/dist/src/cli/commands/import-external.d.ts.map +1 -1
- package/dist/src/cli/commands/import-external.js +6 -10
- package/dist/src/cli/commands/import-external.js.map +1 -1
- package/dist/src/cli/commands/init-multiproject.d.ts.map +1 -1
- package/dist/src/cli/commands/init-multiproject.js +58 -73
- package/dist/src/cli/commands/init-multiproject.js.map +1 -1
- package/dist/src/cli/commands/init.d.ts +17 -11
- package/dist/src/cli/commands/init.d.ts.map +1 -1
- package/dist/src/cli/commands/init.js +221 -1874
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/commands/install.d.ts.map +1 -1
- package/dist/src/cli/commands/install.js +14 -22
- package/dist/src/cli/commands/install.js.map +1 -1
- package/dist/src/cli/commands/migrate-config.d.ts.map +1 -1
- package/dist/src/cli/commands/migrate-config.js +6 -10
- package/dist/src/cli/commands/migrate-config.js.map +1 -1
- package/dist/src/cli/commands/switch-project.d.ts.map +1 -1
- package/dist/src/cli/commands/switch-project.js.map +1 -1
- package/dist/src/cli/helpers/ado-area-path-mapper.d.ts.map +1 -1
- package/dist/src/cli/helpers/ado-area-path-mapper.js +36 -49
- package/dist/src/cli/helpers/ado-area-path-mapper.js.map +1 -1
- package/dist/src/cli/helpers/github/increment-profile-selector.d.ts.map +1 -1
- package/dist/src/cli/helpers/github/increment-profile-selector.js.map +1 -1
- package/dist/src/cli/helpers/github/profile-manager.d.ts.map +1 -1
- package/dist/src/cli/helpers/github/profile-manager.js +8 -11
- package/dist/src/cli/helpers/github/profile-manager.js.map +1 -1
- package/dist/src/cli/helpers/github-repo-selector.d.ts.map +1 -1
- package/dist/src/cli/helpers/github-repo-selector.js +26 -50
- package/dist/src/cli/helpers/github-repo-selector.js.map +1 -1
- package/dist/src/cli/helpers/import-strategy-prompter.d.ts.map +1 -1
- package/dist/src/cli/helpers/import-strategy-prompter.js +39 -52
- package/dist/src/cli/helpers/import-strategy-prompter.js.map +1 -1
- package/dist/src/cli/helpers/init/config-detection.d.ts +40 -0
- package/dist/src/cli/helpers/init/config-detection.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/config-detection.js +125 -0
- package/dist/src/cli/helpers/init/config-detection.js.map +1 -0
- package/dist/src/cli/helpers/init/directory-structure.d.ts +26 -0
- package/dist/src/cli/helpers/init/directory-structure.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/directory-structure.js +190 -0
- package/dist/src/cli/helpers/init/directory-structure.js.map +1 -0
- package/dist/src/cli/helpers/init/external-import.d.ts +15 -0
- package/dist/src/cli/helpers/init/external-import.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/external-import.js +251 -0
- package/dist/src/cli/helpers/init/external-import.js.map +1 -0
- package/dist/src/cli/helpers/init/index.d.ts +15 -0
- package/dist/src/cli/helpers/init/index.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/index.js +26 -0
- package/dist/src/cli/helpers/init/index.js.map +1 -0
- package/dist/src/cli/helpers/init/next-steps.d.ts +15 -0
- package/dist/src/cli/helpers/init/next-steps.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/next-steps.js +72 -0
- package/dist/src/cli/helpers/init/next-steps.js.map +1 -0
- package/dist/src/cli/helpers/init/path-utils.d.ts +41 -0
- package/dist/src/cli/helpers/init/path-utils.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/path-utils.js +146 -0
- package/dist/src/cli/helpers/init/path-utils.js.map +1 -0
- package/dist/src/cli/helpers/init/plugin-installer.d.ts +28 -0
- package/dist/src/cli/helpers/init/plugin-installer.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/plugin-installer.js +238 -0
- package/dist/src/cli/helpers/init/plugin-installer.js.map +1 -0
- package/dist/src/cli/helpers/init/repository-setup.d.ts +28 -0
- package/dist/src/cli/helpers/init/repository-setup.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/repository-setup.js +78 -0
- package/dist/src/cli/helpers/init/repository-setup.js.map +1 -0
- package/dist/src/cli/helpers/init/smart-reinit.d.ts +30 -0
- package/dist/src/cli/helpers/init/smart-reinit.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/smart-reinit.js +140 -0
- package/dist/src/cli/helpers/init/smart-reinit.js.map +1 -0
- package/dist/src/cli/helpers/init/testing-config.d.ts +27 -0
- package/dist/src/cli/helpers/init/testing-config.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/testing-config.js +131 -0
- package/dist/src/cli/helpers/init/testing-config.js.map +1 -0
- package/dist/src/cli/helpers/init/types.d.ts +86 -0
- package/dist/src/cli/helpers/init/types.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/types.js +5 -0
- package/dist/src/cli/helpers/init/types.js.map +1 -0
- package/dist/src/cli/helpers/issue-tracker/ado-auto-discover.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/ado-auto-discover.js +10 -12
- package/dist/src/cli/helpers/issue-tracker/ado-auto-discover.js.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/ado.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/ado.js +43 -60
- package/dist/src/cli/helpers/issue-tracker/ado.js.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/github-multi-repo.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/github-multi-repo.js +193 -230
- package/dist/src/cli/helpers/issue-tracker/github-multi-repo.js.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/github.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/github.js +43 -54
- package/dist/src/cli/helpers/issue-tracker/github.js.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/index.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/index.js +27 -40
- package/dist/src/cli/helpers/issue-tracker/index.js.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/jira.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/jira.js +54 -70
- package/dist/src/cli/helpers/issue-tracker/jira.js.map +1 -1
- package/dist/src/cli/helpers/smart-filter.d.ts.map +1 -1
- package/dist/src/cli/helpers/smart-filter.js +62 -85
- package/dist/src/cli/helpers/smart-filter.js.map +1 -1
- package/dist/src/core/increment/auto-transition-manager.d.ts +12 -0
- package/dist/src/core/increment/auto-transition-manager.d.ts.map +1 -1
- package/dist/src/core/increment/auto-transition-manager.js +45 -0
- package/dist/src/core/increment/auto-transition-manager.js.map +1 -1
- package/dist/src/core/increment/metadata-manager.d.ts.map +1 -1
- package/dist/src/core/increment/metadata-manager.js +46 -0
- package/dist/src/core/increment/metadata-manager.js.map +1 -1
- package/dist/src/core/increment/status-change-sync-trigger.d.ts +12 -0
- package/dist/src/core/increment/status-change-sync-trigger.d.ts.map +1 -1
- package/dist/src/core/increment/status-change-sync-trigger.js +48 -2
- package/dist/src/core/increment/status-change-sync-trigger.js.map +1 -1
- package/dist/src/core/living-docs/living-docs-sync.d.ts +13 -0
- package/dist/src/core/living-docs/living-docs-sync.d.ts.map +1 -1
- package/dist/src/core/living-docs/living-docs-sync.js +40 -0
- package/dist/src/core/living-docs/living-docs-sync.js.map +1 -1
- package/dist/src/core/repo-structure/repo-bulk-discovery.d.ts.map +1 -1
- package/dist/src/core/repo-structure/repo-bulk-discovery.js +63 -83
- package/dist/src/core/repo-structure/repo-bulk-discovery.js.map +1 -1
- package/dist/src/core/repo-structure/repo-structure-manager.d.ts.map +1 -1
- package/dist/src/core/repo-structure/repo-structure-manager.js +339 -424
- package/dist/src/core/repo-structure/repo-structure-manager.js.map +1 -1
- package/dist/src/core/sync/bidirectional-engine.d.ts.map +1 -1
- package/dist/src/core/sync/bidirectional-engine.js +21 -29
- package/dist/src/core/sync/bidirectional-engine.js.map +1 -1
- package/dist/src/init/InitFlow.js +15 -19
- package/dist/src/init/InitFlow.js.map +1 -1
- package/dist/src/init/repo/types.d.ts +1 -1
- package/dist/src/integrations/ado/area-path-mapper.d.ts.map +1 -1
- package/dist/src/integrations/ado/area-path-mapper.js +19 -23
- package/dist/src/integrations/ado/area-path-mapper.js.map +1 -1
- package/dist/src/utils/external-resource-validator.d.ts.map +1 -1
- package/dist/src/utils/external-resource-validator.js +41 -65
- package/dist/src/utils/external-resource-validator.js.map +1 -1
- package/dist/src/utils/project-detection.d.ts.map +1 -1
- package/dist/src/utils/project-detection.js +19 -21
- package/dist/src/utils/project-detection.js.map +1 -1
- package/dist/src/utils/project-validator.d.ts.map +1 -1
- package/dist/src/utils/project-validator.js +5 -7
- package/dist/src/utils/project-validator.js.map +1 -1
- package/package.json +2 -3
- package/plugins/specweave/agents/tech-lead/AGENT.md +9 -0
- package/plugins/specweave/hooks/docs-changed.sh.backup +79 -0
- package/plugins/specweave/hooks/human-input-required.sh.backup +75 -0
- package/plugins/specweave/hooks/post-first-increment.sh.backup +61 -0
- package/plugins/specweave/hooks/post-increment-change.sh.backup +98 -0
- package/plugins/specweave/hooks/post-increment-completion.sh.backup +231 -0
- package/plugins/specweave/hooks/post-increment-planning.sh.backup +1048 -0
- package/plugins/specweave/hooks/post-increment-status-change.sh.backup +147 -0
- package/plugins/specweave/hooks/post-spec-update.sh.backup +158 -0
- package/plugins/specweave/hooks/post-user-story-complete.sh.backup +179 -0
- package/plugins/specweave/hooks/pre-command-deduplication.sh.backup +83 -0
- package/plugins/specweave/hooks/pre-implementation.sh.backup +67 -0
- package/plugins/specweave/hooks/pre-task-completion.sh.backup +194 -0
- package/plugins/specweave/hooks/pre-tool-use.sh.backup +133 -0
- package/plugins/specweave/hooks/user-prompt-submit.sh.backup +386 -0
- package/plugins/specweave/lib/vendor/core/increment/auto-transition-manager.d.ts +12 -0
- package/plugins/specweave/lib/vendor/core/increment/auto-transition-manager.js +45 -0
- package/plugins/specweave/lib/vendor/core/increment/auto-transition-manager.js.map +1 -1
- package/plugins/specweave/lib/vendor/core/increment/metadata-manager.js +46 -0
- package/plugins/specweave/lib/vendor/core/increment/metadata-manager.js.map +1 -1
- package/plugins/specweave/skills/increment-planner/SKILL.md +10 -5
- package/plugins/specweave/skills/specweave-framework/SKILL.md +6 -4
- package/plugins/specweave/templates/coding-standards.md.template +36 -0
- package/plugins/specweave-ado/hooks/post-living-docs-update.sh.backup +353 -0
- package/plugins/specweave-ado/hooks/post-task-completion.sh.backup +172 -0
- package/plugins/specweave-ado/lib/ado-multi-project-sync.js +1 -0
- package/plugins/specweave-ado/lib/enhanced-ado-sync.js +170 -0
- package/plugins/specweave-ado/lib/project-selector.js +56 -67
- package/plugins/specweave-ado/lib/project-selector.ts +72 -85
- package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +1104 -0
- package/plugins/specweave-github/hooks/post-task-completion.sh.backup +258 -0
- package/plugins/specweave-github/lib/repo-selector.js +55 -66
- package/plugins/specweave-github/lib/repo-selector.ts +73 -84
- package/plugins/specweave-jira/commands/import-projects.js +3 -5
- package/plugins/specweave-jira/commands/import-projects.ts +3 -5
- package/plugins/specweave-jira/hooks/post-task-completion.sh.backup +172 -0
- package/plugins/specweave-jira/lib/enhanced-jira-sync.js +3 -3
- package/plugins/specweave-jira/lib/project-selector.js +60 -71
- package/plugins/specweave-jira/lib/project-selector.ts +78 -91
- package/plugins/specweave-jira/lib/setup-wizard.js +51 -72
- package/plugins/specweave-jira/lib/setup-wizard.ts +56 -74
- package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +1017 -0
- package/plugins/specweave-release/hooks/post-task-completion.sh.backup +110 -0
- package/src/templates/CLAUDE.md.template +14 -0
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
import { existsSync, mkdirSync, writeFileSync } from 'fs';
|
|
18
18
|
import path from 'path';
|
|
19
19
|
import chalk from 'chalk';
|
|
20
|
-
import
|
|
20
|
+
import { select, input, confirm, number } from '@inquirer/prompts';
|
|
21
21
|
import ora from 'ora';
|
|
22
22
|
import { execSync } from 'child_process';
|
|
23
23
|
import { execFileNoThrowSync } from '../../utils/execFileNoThrow.js';
|
|
@@ -54,12 +54,10 @@ export class RepoStructureManager {
|
|
|
54
54
|
console.log(chalk.yellow('\nāøļø Detected interrupted setup!'));
|
|
55
55
|
console.log(chalk.gray(` Last step: ${resumedState.currentStep}`));
|
|
56
56
|
console.log(chalk.gray(` Time: ${new Date(resumedState.timestamp).toLocaleString()}\n`));
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
default: true
|
|
62
|
-
}]);
|
|
57
|
+
const shouldResume = await confirm({
|
|
58
|
+
message: 'Resume previous setup?',
|
|
59
|
+
default: true
|
|
60
|
+
});
|
|
63
61
|
if (shouldResume) {
|
|
64
62
|
return this.resumeSetup(resumedState);
|
|
65
63
|
}
|
|
@@ -78,38 +76,31 @@ export class RepoStructureManager {
|
|
|
78
76
|
else {
|
|
79
77
|
// Ask user for architecture choice
|
|
80
78
|
const promptData = getArchitecturePrompt();
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
})),
|
|
90
|
-
default: 'single'
|
|
91
|
-
}]);
|
|
92
|
-
architecture = result.architecture;
|
|
79
|
+
architecture = await select({
|
|
80
|
+
message: promptData.question,
|
|
81
|
+
choices: promptData.options.map(opt => ({
|
|
82
|
+
name: `${opt.label}\n${chalk.gray(opt.description)}\n${chalk.dim(opt.example)}`,
|
|
83
|
+
value: opt.value
|
|
84
|
+
})),
|
|
85
|
+
default: 'single'
|
|
86
|
+
});
|
|
93
87
|
}
|
|
94
88
|
// Step 2: Ask about Git hosting platform
|
|
95
89
|
const registry = getPlatformRegistry();
|
|
96
90
|
const platformOptions = registry.getPlatformOptions(true); // Include unsupported platforms
|
|
97
91
|
const platformPromptData = getPlatformSelectionPrompt();
|
|
98
92
|
console.log(chalk.cyan('\n' + platformPromptData.message));
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
})),
|
|
111
|
-
default: 'github'
|
|
112
|
-
}]);
|
|
93
|
+
const platform = await select({
|
|
94
|
+
message: platformPromptData.question,
|
|
95
|
+
choices: platformOptions.map(opt => ({
|
|
96
|
+
name: opt.disabled
|
|
97
|
+
? `${opt.name}\n${chalk.gray(opt.description)}\n${chalk.yellow('ā ļø ' + opt.disabled)}`
|
|
98
|
+
: `${opt.name}\n${chalk.gray(opt.description)}`,
|
|
99
|
+
value: opt.value,
|
|
100
|
+
disabled: opt.disabled ? opt.disabled : false
|
|
101
|
+
})),
|
|
102
|
+
default: 'github'
|
|
103
|
+
});
|
|
113
104
|
// Get provider instance
|
|
114
105
|
const provider = registry.getProvider(platform);
|
|
115
106
|
if (!provider) {
|
|
@@ -118,17 +109,14 @@ export class RepoStructureManager {
|
|
|
118
109
|
console.log(chalk.green(`\nā Using ${provider.config.name} as Git hosting platform\n`));
|
|
119
110
|
// Step 3: Ask about Git remote URL format (SSH vs HTTPS)
|
|
120
111
|
const urlTypePromptData = getUrlTypePrompt();
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
})),
|
|
130
|
-
default: urlTypePromptData.default
|
|
131
|
-
}]);
|
|
112
|
+
const urlType = await select({
|
|
113
|
+
message: urlTypePromptData.question,
|
|
114
|
+
choices: urlTypePromptData.options.map(opt => ({
|
|
115
|
+
name: `${opt.label}\n${chalk.gray(opt.description)}`,
|
|
116
|
+
value: opt.value
|
|
117
|
+
})),
|
|
118
|
+
default: urlTypePromptData.default
|
|
119
|
+
});
|
|
132
120
|
console.log(chalk.green(`\nā Using ${urlType.toUpperCase()} remote URLs\n`));
|
|
133
121
|
// Map ArchitectureChoice to internal architecture
|
|
134
122
|
const mappedArch = this.mapArchitectureChoice(architecture);
|
|
@@ -222,12 +210,10 @@ export class RepoStructureManager {
|
|
|
222
210
|
const owner = match[1];
|
|
223
211
|
const repo = match[2];
|
|
224
212
|
console.log(chalk.green(`ā Existing repository detected: ${owner}/${repo}`));
|
|
225
|
-
const
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
default: true
|
|
230
|
-
}]);
|
|
213
|
+
const useExisting = await confirm({
|
|
214
|
+
message: 'Use existing repository?',
|
|
215
|
+
default: true
|
|
216
|
+
});
|
|
231
217
|
if (useExisting) {
|
|
232
218
|
// Fetch description and visibility from GitHub API
|
|
233
219
|
let description = `${repo} - SpecWeave project`;
|
|
@@ -274,49 +260,41 @@ export class RepoStructureManager {
|
|
|
274
260
|
}
|
|
275
261
|
}
|
|
276
262
|
// Manual configuration
|
|
277
|
-
const
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
message: 'Create repository on GitHub?',
|
|
301
|
-
default: !hasGit
|
|
302
|
-
}
|
|
303
|
-
]);
|
|
263
|
+
const ownerAnswer = await input({
|
|
264
|
+
message: 'GitHub owner/organization:',
|
|
265
|
+
validate: (val) => !!val.trim() || 'Owner is required'
|
|
266
|
+
});
|
|
267
|
+
const repoAnswer = await input({
|
|
268
|
+
message: 'Repository name:',
|
|
269
|
+
default: path.basename(this.projectPath),
|
|
270
|
+
validate: (val) => !!val.trim() || 'Repository name is required'
|
|
271
|
+
});
|
|
272
|
+
const descriptionAnswer = await input({
|
|
273
|
+
message: 'Repository description:',
|
|
274
|
+
default: 'My SpecWeave project'
|
|
275
|
+
});
|
|
276
|
+
const createOnGitHubAnswer = await confirm({
|
|
277
|
+
message: 'Create repository on GitHub?',
|
|
278
|
+
default: !hasGit
|
|
279
|
+
});
|
|
280
|
+
const answers = {
|
|
281
|
+
owner: ownerAnswer,
|
|
282
|
+
repo: repoAnswer,
|
|
283
|
+
description: descriptionAnswer,
|
|
284
|
+
createOnGitHub: createOnGitHubAnswer
|
|
285
|
+
};
|
|
304
286
|
// Ask about visibility only if creating a new repository
|
|
305
287
|
let visibility = 'private';
|
|
306
288
|
if (answers.createOnGitHub) {
|
|
307
289
|
const visibilityPrompt = getVisibilityPrompt(answers.repo);
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
})),
|
|
317
|
-
default: visibilityPrompt.default
|
|
318
|
-
}]);
|
|
319
|
-
visibility = result.visibility;
|
|
290
|
+
visibility = await select({
|
|
291
|
+
message: visibilityPrompt.question,
|
|
292
|
+
choices: visibilityPrompt.options.map(opt => ({
|
|
293
|
+
name: `${opt.label}\n${chalk.gray(opt.description)}`,
|
|
294
|
+
value: opt.value
|
|
295
|
+
})),
|
|
296
|
+
default: visibilityPrompt.default
|
|
297
|
+
});
|
|
320
298
|
}
|
|
321
299
|
return {
|
|
322
300
|
architecture: 'single',
|
|
@@ -380,65 +358,54 @@ export class RepoStructureManager {
|
|
|
380
358
|
if (!isLocalParent && this.githubToken && useParent) {
|
|
381
359
|
console.log(chalk.cyan('\nš Repository Discovery\n'));
|
|
382
360
|
console.log(chalk.gray('You\'re setting up multiple repositories. We can discover them automatically!\n'));
|
|
383
|
-
const
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
short: 'Manual'
|
|
411
|
-
}
|
|
412
|
-
],
|
|
413
|
-
default: 'bulk-discovery' // Make bulk discovery the default!
|
|
414
|
-
}
|
|
415
|
-
]);
|
|
361
|
+
const configMethod = await select({
|
|
362
|
+
message: 'How do you want to configure repositories?',
|
|
363
|
+
choices: [
|
|
364
|
+
{
|
|
365
|
+
name: [
|
|
366
|
+
chalk.bold.green('šÆ Bulk Discovery (RECOMMENDED)'),
|
|
367
|
+
chalk.gray(' Automatically discover repos from ' + provider.config.name),
|
|
368
|
+
chalk.gray(' ⢠Select parent from discovered list'),
|
|
369
|
+
chalk.gray(' ⢠Auto-configure implementation repos'),
|
|
370
|
+
chalk.gray(' ⢠Supports: all, pattern, regex filtering'),
|
|
371
|
+
''
|
|
372
|
+
].join('\n'),
|
|
373
|
+
value: 'bulk-discovery'
|
|
374
|
+
},
|
|
375
|
+
{
|
|
376
|
+
name: [
|
|
377
|
+
chalk.bold('āļø Manual Entry'),
|
|
378
|
+
chalk.gray(' Enter each repository manually'),
|
|
379
|
+
chalk.gray(' ⢠Full control over settings'),
|
|
380
|
+
chalk.gray(' ⢠Best for new repos or custom setup'),
|
|
381
|
+
''
|
|
382
|
+
].join('\n'),
|
|
383
|
+
value: 'manual'
|
|
384
|
+
}
|
|
385
|
+
],
|
|
386
|
+
default: 'bulk-discovery'
|
|
387
|
+
});
|
|
416
388
|
discoveryStrategy = configMethod;
|
|
417
389
|
}
|
|
418
390
|
// Step 2: If bulk discovery, discover repos FIRST, then ask which is parent
|
|
419
391
|
if (discoveryStrategy === 'bulk-discovery') {
|
|
420
392
|
// Get owner FIRST (needed for discovery)
|
|
421
393
|
console.log(chalk.cyan('\nš¤ Repository Owner\n'));
|
|
422
|
-
|
|
423
|
-
{
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
const result = await provider.validateOwner(input, this.githubToken);
|
|
433
|
-
if (!result.valid) {
|
|
434
|
-
return result.error || `Invalid ${provider.config.name} owner`;
|
|
435
|
-
}
|
|
394
|
+
owner = await input({
|
|
395
|
+
message: `${provider.config.name} owner/organization:`,
|
|
396
|
+
validate: async (val) => {
|
|
397
|
+
if (!val.trim())
|
|
398
|
+
return 'Owner is required';
|
|
399
|
+
// Validate owner exists on the platform
|
|
400
|
+
if (this.githubToken) {
|
|
401
|
+
const result = await provider.validateOwner(val, this.githubToken);
|
|
402
|
+
if (!result.valid) {
|
|
403
|
+
return result.error || `Invalid ${provider.config.name} owner`;
|
|
436
404
|
}
|
|
437
|
-
return true;
|
|
438
405
|
}
|
|
406
|
+
return true;
|
|
439
407
|
}
|
|
440
|
-
|
|
441
|
-
owner = ownerPrompt.owner;
|
|
408
|
+
});
|
|
442
409
|
// Discover repositories via pattern matching
|
|
443
410
|
const octokit = new Octokit({ auth: this.githubToken });
|
|
444
411
|
const isOrg = await provider.isOrganization(owner, this.githubToken);
|
|
@@ -466,15 +433,11 @@ export class RepoStructureManager {
|
|
|
466
433
|
short: 'Enter manually'
|
|
467
434
|
}
|
|
468
435
|
];
|
|
469
|
-
const
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
choices: parentChoices,
|
|
475
|
-
pageSize: 15
|
|
476
|
-
}
|
|
477
|
-
]);
|
|
436
|
+
const parentSelection = await select({
|
|
437
|
+
message: 'Which repository is the parent?',
|
|
438
|
+
choices: parentChoices,
|
|
439
|
+
pageSize: 15
|
|
440
|
+
});
|
|
478
441
|
if (parentSelection === 'manual') {
|
|
479
442
|
// User wants to enter parent manually - fall back to old flow
|
|
480
443
|
discoveryStrategy = 'manual';
|
|
@@ -541,106 +504,92 @@ export class RepoStructureManager {
|
|
|
541
504
|
// Local parent: Skip GitHub questions, just ask for folder name
|
|
542
505
|
console.log(chalk.blue('\nš” Local Parent Folder Setup'));
|
|
543
506
|
console.log(chalk.gray('This folder will contain .specweave/ but will NOT be pushed to GitHub.\n'));
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
if (!
|
|
562
|
-
return
|
|
563
|
-
// Validate owner exists on the platform
|
|
564
|
-
if (this.githubToken) {
|
|
565
|
-
const result = await provider.validateOwner(input, this.githubToken);
|
|
566
|
-
if (!result.valid) {
|
|
567
|
-
return result.error || `Invalid ${provider.config.name} owner`;
|
|
568
|
-
}
|
|
507
|
+
const parentNameAnswer = await input({
|
|
508
|
+
message: 'Parent folder name:',
|
|
509
|
+
default: `${path.basename(this.projectPath)}`,
|
|
510
|
+
validate: (val) => {
|
|
511
|
+
if (!val.trim())
|
|
512
|
+
return 'Folder name is required';
|
|
513
|
+
return true;
|
|
514
|
+
}
|
|
515
|
+
});
|
|
516
|
+
const ownerForLocalAnswer = await input({
|
|
517
|
+
message: `${provider.config.name} owner/organization for IMPLEMENTATION repos:`,
|
|
518
|
+
validate: async (val) => {
|
|
519
|
+
if (!val.trim())
|
|
520
|
+
return 'Owner is required';
|
|
521
|
+
// Validate owner exists on the platform
|
|
522
|
+
if (this.githubToken) {
|
|
523
|
+
const result = await provider.validateOwner(val, this.githubToken);
|
|
524
|
+
if (!result.valid) {
|
|
525
|
+
return result.error || `Invalid ${provider.config.name} owner`;
|
|
569
526
|
}
|
|
570
|
-
return true;
|
|
571
527
|
}
|
|
528
|
+
return true;
|
|
572
529
|
}
|
|
573
|
-
|
|
530
|
+
});
|
|
531
|
+
parentAnswers = {
|
|
532
|
+
parentName: parentNameAnswer,
|
|
533
|
+
owner: ownerForLocalAnswer
|
|
534
|
+
};
|
|
574
535
|
// Set defaults for local parent
|
|
575
536
|
parentAnswers.description = 'Local parent folder (not synced to GitHub)';
|
|
576
537
|
parentAnswers.createOnGitHub = false; // Never create GitHub repo for local parent
|
|
577
538
|
}
|
|
578
539
|
else {
|
|
579
540
|
// GitHub parent: First ask if using existing or creating new
|
|
580
|
-
const
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
short: 'Create new'
|
|
595
|
-
}
|
|
596
|
-
],
|
|
597
|
-
default: 'new'
|
|
598
|
-
}
|
|
599
|
-
]);
|
|
541
|
+
const parentChoice = await select({
|
|
542
|
+
message: 'Parent repository setup:',
|
|
543
|
+
choices: [
|
|
544
|
+
{
|
|
545
|
+
name: `${chalk.green('Use existing parent repository')}\n${chalk.gray('Connect to an existing GitHub repo that already has .specweave/ structure')}`,
|
|
546
|
+
value: 'existing'
|
|
547
|
+
},
|
|
548
|
+
{
|
|
549
|
+
name: `${chalk.blue('Create new parent repository')}\n${chalk.gray('Create a new GitHub repo for specs, docs, and architecture')}`,
|
|
550
|
+
value: 'new'
|
|
551
|
+
}
|
|
552
|
+
],
|
|
553
|
+
default: 'new'
|
|
554
|
+
});
|
|
600
555
|
if (parentChoice === 'existing') {
|
|
601
556
|
// Using existing parent repository
|
|
602
557
|
console.log(chalk.cyan('\nš Existing Parent Repository\n'));
|
|
603
558
|
// Ask for owner first
|
|
604
|
-
const
|
|
605
|
-
{
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
const result = await provider.validateOwner(input, this.githubToken);
|
|
615
|
-
if (!result.valid) {
|
|
616
|
-
return result.error || `Invalid ${provider.config.name} owner`;
|
|
617
|
-
}
|
|
559
|
+
const existingOwner = await input({
|
|
560
|
+
message: `${provider.config.name} owner/organization:`,
|
|
561
|
+
validate: async (val) => {
|
|
562
|
+
if (!val.trim())
|
|
563
|
+
return 'Owner is required';
|
|
564
|
+
// Validate owner exists on the platform
|
|
565
|
+
if (this.githubToken) {
|
|
566
|
+
const result = await provider.validateOwner(val, this.githubToken);
|
|
567
|
+
if (!result.valid) {
|
|
568
|
+
return result.error || `Invalid ${provider.config.name} owner`;
|
|
618
569
|
}
|
|
619
|
-
return true;
|
|
620
570
|
}
|
|
571
|
+
return true;
|
|
621
572
|
}
|
|
622
|
-
|
|
573
|
+
});
|
|
574
|
+
const ownerPrompt = { owner: existingOwner };
|
|
623
575
|
// Ask for existing repo name
|
|
624
|
-
const
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
const result = await provider.validateRepository(ownerPrompt.owner, input, this.githubToken);
|
|
636
|
-
if (!result.exists) {
|
|
637
|
-
return `Repository ${ownerPrompt.owner}/${input} not found on ${provider.config.name}. Please check the name or choose 'Create new'.`;
|
|
638
|
-
}
|
|
576
|
+
const existingParentName = await input({
|
|
577
|
+
message: 'Existing parent repository name:',
|
|
578
|
+
default: `${path.basename(this.projectPath)}-parent`,
|
|
579
|
+
validate: async (val) => {
|
|
580
|
+
if (!val.trim())
|
|
581
|
+
return 'Repository name is required';
|
|
582
|
+
// Validate repository EXISTS on the platform
|
|
583
|
+
if (this.githubToken && ownerPrompt.owner) {
|
|
584
|
+
const result = await provider.validateRepository(ownerPrompt.owner, val, this.githubToken);
|
|
585
|
+
if (!result.exists) {
|
|
586
|
+
return `Repository ${ownerPrompt.owner}/${val} not found on ${provider.config.name}. Please check the name or choose 'Create new'.`;
|
|
639
587
|
}
|
|
640
|
-
return true;
|
|
641
588
|
}
|
|
589
|
+
return true;
|
|
642
590
|
}
|
|
643
|
-
|
|
591
|
+
});
|
|
592
|
+
const repoPrompt = { parentName: existingParentName };
|
|
644
593
|
// Fetch description and visibility from GitHub API (or use defaults)
|
|
645
594
|
let description = 'SpecWeave parent repository - specs, docs, and architecture';
|
|
646
595
|
let existingVisibility = 'private';
|
|
@@ -675,60 +624,54 @@ export class RepoStructureManager {
|
|
|
675
624
|
// Creating new parent repository
|
|
676
625
|
console.log(chalk.cyan('\n⨠New Parent Repository\n'));
|
|
677
626
|
// Ask for owner (separate prompt to avoid validator issues)
|
|
678
|
-
const
|
|
679
|
-
{
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
const result = await provider.validateOwner(input, this.githubToken);
|
|
689
|
-
if (!result.valid) {
|
|
690
|
-
return result.error || `Invalid ${provider.config.name} owner`;
|
|
691
|
-
}
|
|
627
|
+
const newOwner = await input({
|
|
628
|
+
message: `${provider.config.name} owner/organization for ALL repos:`,
|
|
629
|
+
validate: async (val) => {
|
|
630
|
+
if (!val.trim())
|
|
631
|
+
return 'Owner is required';
|
|
632
|
+
// Validate owner exists on the platform
|
|
633
|
+
if (this.githubToken) {
|
|
634
|
+
const result = await provider.validateOwner(val, this.githubToken);
|
|
635
|
+
if (!result.valid) {
|
|
636
|
+
return result.error || `Invalid ${provider.config.name} owner`;
|
|
692
637
|
}
|
|
693
|
-
return true;
|
|
694
638
|
}
|
|
639
|
+
return true;
|
|
695
640
|
}
|
|
696
|
-
|
|
641
|
+
});
|
|
642
|
+
const ownerPrompt = { owner: newOwner };
|
|
697
643
|
// Now ask remaining questions, using the owner value
|
|
698
|
-
const
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
const result = await provider.validateRepository(ownerPrompt.owner, input, this.githubToken);
|
|
710
|
-
if (result.exists) {
|
|
711
|
-
return `Repository ${ownerPrompt.owner}/${input} already exists at ${result.url}. Please choose 'Use existing' or pick a different name.`;
|
|
712
|
-
}
|
|
644
|
+
const newParentName = await input({
|
|
645
|
+
message: 'Parent repository name:',
|
|
646
|
+
default: `${path.basename(this.projectPath)}-parent`,
|
|
647
|
+
validate: async (val) => {
|
|
648
|
+
if (!val.trim())
|
|
649
|
+
return 'Repository name is required';
|
|
650
|
+
// Validate repository DOESN'T exist
|
|
651
|
+
if (this.githubToken && ownerPrompt.owner) {
|
|
652
|
+
const result = await provider.validateRepository(ownerPrompt.owner, val, this.githubToken);
|
|
653
|
+
if (result.exists) {
|
|
654
|
+
return `Repository ${ownerPrompt.owner}/${val} already exists at ${result.url}. Please choose 'Use existing' or pick a different name.`;
|
|
713
655
|
}
|
|
714
|
-
return true;
|
|
715
656
|
}
|
|
716
|
-
|
|
717
|
-
{
|
|
718
|
-
type: 'input',
|
|
719
|
-
name: 'description',
|
|
720
|
-
message: 'Parent repository description:',
|
|
721
|
-
default: 'SpecWeave parent repository - specs, docs, and architecture'
|
|
722
|
-
},
|
|
723
|
-
{
|
|
724
|
-
type: 'confirm',
|
|
725
|
-
name: 'createOnGitHub',
|
|
726
|
-
message: 'Create parent repository on GitHub?',
|
|
727
|
-
default: true
|
|
657
|
+
return true;
|
|
728
658
|
}
|
|
729
|
-
|
|
659
|
+
});
|
|
660
|
+
const newParentDesc = await input({
|
|
661
|
+
message: 'Parent repository description:',
|
|
662
|
+
default: 'SpecWeave parent repository - specs, docs, and architecture'
|
|
663
|
+
});
|
|
664
|
+
const createParentOnGitHub = await confirm({
|
|
665
|
+
message: 'Create parent repository on GitHub?',
|
|
666
|
+
default: true
|
|
667
|
+
});
|
|
730
668
|
// Merge the answers
|
|
731
|
-
parentAnswers = {
|
|
669
|
+
parentAnswers = {
|
|
670
|
+
...ownerPrompt,
|
|
671
|
+
parentName: newParentName,
|
|
672
|
+
description: newParentDesc,
|
|
673
|
+
createOnGitHub: createParentOnGitHub
|
|
674
|
+
};
|
|
732
675
|
}
|
|
733
676
|
}
|
|
734
677
|
// Ask about visibility for parent repo (only if creating NEW repo on GitHub)
|
|
@@ -736,18 +679,14 @@ export class RepoStructureManager {
|
|
|
736
679
|
if (!isLocalParent && parentAnswers.createOnGitHub) {
|
|
737
680
|
// Only prompt for visibility when creating a NEW repository
|
|
738
681
|
const parentVisibilityPrompt = getVisibilityPrompt(parentAnswers.parentName);
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
})),
|
|
748
|
-
default: parentVisibilityPrompt.default
|
|
749
|
-
}]);
|
|
750
|
-
parentVisibility = result.parentVisibility;
|
|
682
|
+
parentVisibility = await select({
|
|
683
|
+
message: parentVisibilityPrompt.question,
|
|
684
|
+
choices: parentVisibilityPrompt.options.map(opt => ({
|
|
685
|
+
name: `${opt.label}\n${chalk.gray(opt.description)}`,
|
|
686
|
+
value: opt.value
|
|
687
|
+
})),
|
|
688
|
+
default: parentVisibilityPrompt.default
|
|
689
|
+
});
|
|
751
690
|
}
|
|
752
691
|
else if (!isLocalParent && parentAnswers.visibility) {
|
|
753
692
|
// Use existing repository's visibility (fetched from GitHub API)
|
|
@@ -803,24 +742,22 @@ export class RepoStructureManager {
|
|
|
803
742
|
console.log(chalk.gray('\nNext question asks for: IMPLEMENTATION repositories ONLY (not counting parent)\n'));
|
|
804
743
|
}
|
|
805
744
|
// Ask how many implementation repositories
|
|
806
|
-
const
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
}]);
|
|
823
|
-
repoCount = promptResult.repoCount;
|
|
745
|
+
const repoCountAnswer = await number({
|
|
746
|
+
message: useParent
|
|
747
|
+
? 'š¦ How many IMPLEMENTATION repositories? (not counting parent)'
|
|
748
|
+
: 'How many repositories?',
|
|
749
|
+
default: hints.suggestedCount, // Use auto-detected count
|
|
750
|
+
validate: (val) => {
|
|
751
|
+
if (val === undefined || val < 1)
|
|
752
|
+
return useParent
|
|
753
|
+
? 'Need at least 1 implementation repository'
|
|
754
|
+
: 'Need at least 2 repositories';
|
|
755
|
+
if (val > 10)
|
|
756
|
+
return 'Maximum 10 repositories supported';
|
|
757
|
+
return true;
|
|
758
|
+
}
|
|
759
|
+
});
|
|
760
|
+
repoCount = repoCountAnswer ?? hints.suggestedCount;
|
|
824
761
|
// Show summary AFTER for confirmation
|
|
825
762
|
if (useParent && config.parentRepo) {
|
|
826
763
|
if (isLocalParent) {
|
|
@@ -873,12 +810,10 @@ export class RepoStructureManager {
|
|
|
873
810
|
console.log(chalk.green(` ā Discovered: ${chalk.bold(discoveredRepo.name)}`));
|
|
874
811
|
console.log(chalk.gray(` Description: ${discoveredRepo.description || '(none)'}`));
|
|
875
812
|
console.log(chalk.gray(` Visibility: ${discoveredRepo.private ? 'Private' : 'Public'}`));
|
|
876
|
-
const
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
default: true
|
|
881
|
-
}]);
|
|
813
|
+
const confirmDiscovered = await confirm({
|
|
814
|
+
message: 'Use this repository configuration?',
|
|
815
|
+
default: true
|
|
816
|
+
});
|
|
882
817
|
if (!confirmDiscovered) {
|
|
883
818
|
// Allow manual override
|
|
884
819
|
console.log(chalk.yellow(` ā Switching to manual entry for this repository\n`));
|
|
@@ -904,38 +839,35 @@ export class RepoStructureManager {
|
|
|
904
839
|
}
|
|
905
840
|
}
|
|
906
841
|
// Manual entry (original behavior)
|
|
907
|
-
const
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
const result = await provider.validateRepository(config.parentRepo.owner, input, this.githubToken);
|
|
919
|
-
if (result.exists) {
|
|
920
|
-
return `Repository ${config.parentRepo.owner}/${input} already exists at ${result.url}`;
|
|
921
|
-
}
|
|
842
|
+
const repoName = await input({
|
|
843
|
+
message: 'Repository name:',
|
|
844
|
+
default: suggestedName,
|
|
845
|
+
validate: async (val) => {
|
|
846
|
+
if (!val.trim())
|
|
847
|
+
return 'Repository name is required';
|
|
848
|
+
// Validate repository doesn't exist (skip for discovered repos)
|
|
849
|
+
if (!isDiscovered && this.githubToken && config.parentRepo) {
|
|
850
|
+
const result = await provider.validateRepository(config.parentRepo.owner, val, this.githubToken);
|
|
851
|
+
if (result.exists) {
|
|
852
|
+
return `Repository ${config.parentRepo.owner}/${val} already exists at ${result.url}`;
|
|
922
853
|
}
|
|
923
|
-
return true;
|
|
924
854
|
}
|
|
925
|
-
|
|
926
|
-
{
|
|
927
|
-
type: 'input',
|
|
928
|
-
name: 'description',
|
|
929
|
-
message: 'Repository description:',
|
|
930
|
-
default: (answers) => `${path.basename(answers.name)} service`
|
|
931
|
-
},
|
|
932
|
-
{
|
|
933
|
-
type: 'confirm',
|
|
934
|
-
name: 'createOnGitHub',
|
|
935
|
-
message: 'Create this repository on GitHub?',
|
|
936
|
-
default: !isDiscovered // Default to true for new repos, false for discovered
|
|
855
|
+
return true;
|
|
937
856
|
}
|
|
938
|
-
|
|
857
|
+
});
|
|
858
|
+
const repoDescription = await input({
|
|
859
|
+
message: 'Repository description:',
|
|
860
|
+
default: `${path.basename(repoName)} service`
|
|
861
|
+
});
|
|
862
|
+
const repoCreateOnGitHub = await confirm({
|
|
863
|
+
message: 'Create this repository on GitHub?',
|
|
864
|
+
default: !isDiscovered
|
|
865
|
+
});
|
|
866
|
+
const repoAnswers = {
|
|
867
|
+
name: repoName,
|
|
868
|
+
description: repoDescription,
|
|
869
|
+
createOnGitHub: repoCreateOnGitHub
|
|
870
|
+
};
|
|
939
871
|
// Smart auto-generate ID from repository name (context-aware)
|
|
940
872
|
const smartId = generateRepoIdSmart(repoAnswers.name, configuredRepoNames);
|
|
941
873
|
const { id: suggestedId, wasModified } = ensureUniqueId(smartId, usedIds);
|
|
@@ -945,31 +877,27 @@ export class RepoStructureManager {
|
|
|
945
877
|
if (wasModified) {
|
|
946
878
|
console.log(chalk.yellow(` ā ļø ID conflict detected: "${smartId}" already used`));
|
|
947
879
|
console.log(chalk.gray(` ā Suggested unique ID: "${suggestedId}"`));
|
|
948
|
-
const
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
}
|
|
966
|
-
// Validate uniqueness
|
|
967
|
-
if (usedIds.has(input)) {
|
|
968
|
-
return 'Repository ID must be unique';
|
|
969
|
-
}
|
|
970
|
-
return true;
|
|
880
|
+
const confirmIdAnswer = await confirm({
|
|
881
|
+
message: `Use "${suggestedId}" as repository ID?`,
|
|
882
|
+
default: true
|
|
883
|
+
});
|
|
884
|
+
if (!confirmIdAnswer) {
|
|
885
|
+
const customId = await input({
|
|
886
|
+
message: 'Enter custom repository ID:',
|
|
887
|
+
default: suggestedId,
|
|
888
|
+
validate: (val) => {
|
|
889
|
+
// Validate format
|
|
890
|
+
const validation = validateRepoId(val);
|
|
891
|
+
if (!validation.valid) {
|
|
892
|
+
return validation.error || 'Invalid repository ID';
|
|
893
|
+
}
|
|
894
|
+
// Validate uniqueness
|
|
895
|
+
if (usedIds.has(val)) {
|
|
896
|
+
return 'Repository ID must be unique';
|
|
971
897
|
}
|
|
972
|
-
|
|
898
|
+
return true;
|
|
899
|
+
}
|
|
900
|
+
});
|
|
973
901
|
id = customId;
|
|
974
902
|
}
|
|
975
903
|
}
|
|
@@ -983,18 +911,14 @@ export class RepoStructureManager {
|
|
|
983
911
|
let visibility = 'private';
|
|
984
912
|
if (repoAnswers.createOnGitHub) {
|
|
985
913
|
const visibilityPrompt = getVisibilityPrompt(repoAnswers.name);
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
})),
|
|
995
|
-
default: visibilityPrompt.default
|
|
996
|
-
}]);
|
|
997
|
-
visibility = result.visibility;
|
|
914
|
+
visibility = await select({
|
|
915
|
+
message: visibilityPrompt.question,
|
|
916
|
+
choices: visibilityPrompt.options.map(opt => ({
|
|
917
|
+
name: `${opt.label}\n${chalk.gray(opt.description)}`,
|
|
918
|
+
value: opt.value
|
|
919
|
+
})),
|
|
920
|
+
default: visibilityPrompt.default
|
|
921
|
+
});
|
|
998
922
|
}
|
|
999
923
|
config.repositories.push({
|
|
1000
924
|
id: id,
|
|
@@ -1044,61 +968,52 @@ export class RepoStructureManager {
|
|
|
1044
968
|
async configureMonorepo(urlType = 'ssh', platform = 'github', provider) {
|
|
1045
969
|
console.log(chalk.cyan('\nš Monorepo Configuration\n'));
|
|
1046
970
|
console.log(chalk.gray('Single repository with multiple projects/packages.\n'));
|
|
1047
|
-
const
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
},
|
|
1067
|
-
{
|
|
1068
|
-
type: 'input',
|
|
1069
|
-
name: 'projects',
|
|
1070
|
-
message: 'Project names (comma-separated, e.g., frontend,backend,shared):',
|
|
1071
|
-
validate: (input) => {
|
|
1072
|
-
const projects = input.split(',').map(p => p.trim()).filter(Boolean);
|
|
1073
|
-
if (projects.length < 2) {
|
|
1074
|
-
return 'Monorepo should have at least 2 projects';
|
|
1075
|
-
}
|
|
1076
|
-
return true;
|
|
971
|
+
const monoOwner = await input({
|
|
972
|
+
message: 'GitHub owner/organization:',
|
|
973
|
+
validate: (val) => !!val.trim() || 'Owner is required'
|
|
974
|
+
});
|
|
975
|
+
const monoRepo = await input({
|
|
976
|
+
message: 'Repository name:',
|
|
977
|
+
default: path.basename(this.projectPath),
|
|
978
|
+
validate: (val) => !!val.trim() || 'Repository name is required'
|
|
979
|
+
});
|
|
980
|
+
const monoDescription = await input({
|
|
981
|
+
message: 'Repository description:',
|
|
982
|
+
default: 'Monorepo project'
|
|
983
|
+
});
|
|
984
|
+
const monoProjects = await input({
|
|
985
|
+
message: 'Project names (comma-separated, e.g., frontend,backend,shared):',
|
|
986
|
+
validate: (val) => {
|
|
987
|
+
const projects = val.split(',').map(p => p.trim()).filter(Boolean);
|
|
988
|
+
if (projects.length < 2) {
|
|
989
|
+
return 'Monorepo should have at least 2 projects';
|
|
1077
990
|
}
|
|
1078
|
-
|
|
1079
|
-
{
|
|
1080
|
-
type: 'confirm',
|
|
1081
|
-
name: 'createOnGitHub',
|
|
1082
|
-
message: 'Create repository on GitHub?',
|
|
1083
|
-
default: !existsSync(path.join(this.projectPath, '.git'))
|
|
991
|
+
return true;
|
|
1084
992
|
}
|
|
1085
|
-
|
|
993
|
+
});
|
|
994
|
+
const monoCreateOnGitHub = await confirm({
|
|
995
|
+
message: 'Create repository on GitHub?',
|
|
996
|
+
default: !existsSync(path.join(this.projectPath, '.git'))
|
|
997
|
+
});
|
|
998
|
+
const answers = {
|
|
999
|
+
owner: monoOwner,
|
|
1000
|
+
repo: monoRepo,
|
|
1001
|
+
description: monoDescription,
|
|
1002
|
+
projects: monoProjects,
|
|
1003
|
+
createOnGitHub: monoCreateOnGitHub
|
|
1004
|
+
};
|
|
1086
1005
|
// Ask about visibility only if creating a new repository
|
|
1087
1006
|
let visibility = 'private';
|
|
1088
1007
|
if (answers.createOnGitHub) {
|
|
1089
1008
|
const visibilityPrompt = getVisibilityPrompt(answers.repo);
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
})),
|
|
1099
|
-
default: visibilityPrompt.default
|
|
1100
|
-
}]);
|
|
1101
|
-
visibility = result.visibility;
|
|
1009
|
+
visibility = await select({
|
|
1010
|
+
message: visibilityPrompt.question,
|
|
1011
|
+
choices: visibilityPrompt.options.map(opt => ({
|
|
1012
|
+
name: `${opt.label}\n${chalk.gray(opt.description)}`,
|
|
1013
|
+
value: opt.value
|
|
1014
|
+
})),
|
|
1015
|
+
default: visibilityPrompt.default
|
|
1016
|
+
});
|
|
1102
1017
|
}
|
|
1103
1018
|
const projects = answers.projects.split(',').map((p) => p.trim());
|
|
1104
1019
|
return {
|