@ai-coders/context 0.3.1 → 0.4.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/README.md +25 -23
- package/dist/generators/agents/agentConfig.d.ts.map +1 -1
- package/dist/generators/agents/agentConfig.js +42 -0
- package/dist/generators/agents/agentConfig.js.map +1 -1
- package/dist/generators/agents/agentGenerator.d.ts +0 -1
- package/dist/generators/agents/agentGenerator.d.ts.map +1 -1
- package/dist/generators/agents/agentGenerator.js +7 -47
- package/dist/generators/agents/agentGenerator.js.map +1 -1
- package/dist/generators/agents/agentTypes.d.ts +1 -1
- package/dist/generators/agents/agentTypes.d.ts.map +1 -1
- package/dist/generators/agents/agentTypes.js +4 -1
- package/dist/generators/agents/agentTypes.js.map +1 -1
- package/dist/generators/agents/templates/indexTemplate.d.ts.map +1 -1
- package/dist/generators/agents/templates/indexTemplate.js +2 -1
- package/dist/generators/agents/templates/indexTemplate.js.map +1 -1
- package/dist/generators/agents/templates/playbookTemplate.d.ts.map +1 -1
- package/dist/generators/agents/templates/playbookTemplate.js +39 -3
- package/dist/generators/agents/templates/playbookTemplate.js.map +1 -1
- package/dist/generators/documentation/documentationGenerator.d.ts +3 -1
- package/dist/generators/documentation/documentationGenerator.d.ts.map +1 -1
- package/dist/generators/documentation/documentationGenerator.js +88 -15
- package/dist/generators/documentation/documentationGenerator.js.map +1 -1
- package/dist/generators/documentation/guideRegistry.js +8 -8
- package/dist/generators/documentation/guideRegistry.js.map +1 -1
- package/dist/generators/documentation/templates/apiReferenceTemplate.d.ts +2 -0
- package/dist/generators/documentation/templates/apiReferenceTemplate.d.ts.map +1 -0
- package/dist/generators/documentation/templates/apiReferenceTemplate.js +490 -0
- package/dist/generators/documentation/templates/apiReferenceTemplate.js.map +1 -0
- package/dist/generators/documentation/templates/architectureTemplate.d.ts.map +1 -1
- package/dist/generators/documentation/templates/architectureTemplate.js +27 -27
- package/dist/generators/documentation/templates/architectureTemplate.js.map +1 -1
- package/dist/generators/documentation/templates/common.js +2 -2
- package/dist/generators/documentation/templates/common.js.map +1 -1
- package/dist/generators/documentation/templates/dataFlowTemplate.d.ts.map +1 -1
- package/dist/generators/documentation/templates/dataFlowTemplate.js +5 -20
- package/dist/generators/documentation/templates/dataFlowTemplate.js.map +1 -1
- package/dist/generators/documentation/templates/developmentWorkflowTemplate.d.ts.map +1 -1
- package/dist/generators/documentation/templates/developmentWorkflowTemplate.js +5 -20
- package/dist/generators/documentation/templates/developmentWorkflowTemplate.js.map +1 -1
- package/dist/generators/documentation/templates/glossaryTemplate.d.ts.map +1 -1
- package/dist/generators/documentation/templates/glossaryTemplate.js +9 -23
- package/dist/generators/documentation/templates/glossaryTemplate.js.map +1 -1
- package/dist/generators/documentation/templates/index.d.ts +4 -0
- package/dist/generators/documentation/templates/index.d.ts.map +1 -1
- package/dist/generators/documentation/templates/index.js +9 -1
- package/dist/generators/documentation/templates/index.js.map +1 -1
- package/dist/generators/documentation/templates/indexTemplate.d.ts.map +1 -1
- package/dist/generators/documentation/templates/indexTemplate.js +5 -19
- package/dist/generators/documentation/templates/indexTemplate.js.map +1 -1
- package/dist/generators/documentation/templates/migrationTemplate.d.ts +2 -0
- package/dist/generators/documentation/templates/migrationTemplate.d.ts.map +1 -0
- package/dist/generators/documentation/templates/migrationTemplate.js +422 -0
- package/dist/generators/documentation/templates/migrationTemplate.js.map +1 -0
- package/dist/generators/documentation/templates/onboardingTemplate.d.ts +2 -0
- package/dist/generators/documentation/templates/onboardingTemplate.d.ts.map +1 -0
- package/dist/generators/documentation/templates/onboardingTemplate.js +431 -0
- package/dist/generators/documentation/templates/onboardingTemplate.js.map +1 -0
- package/dist/generators/documentation/templates/projectOverviewTemplate.d.ts.map +1 -1
- package/dist/generators/documentation/templates/projectOverviewTemplate.js +22 -25
- package/dist/generators/documentation/templates/projectOverviewTemplate.js.map +1 -1
- package/dist/generators/documentation/templates/securityTemplate.d.ts.map +1 -1
- package/dist/generators/documentation/templates/securityTemplate.js +5 -19
- package/dist/generators/documentation/templates/securityTemplate.js.map +1 -1
- package/dist/generators/documentation/templates/testingTemplate.d.ts.map +1 -1
- package/dist/generators/documentation/templates/testingTemplate.js +5 -19
- package/dist/generators/documentation/templates/testingTemplate.js.map +1 -1
- package/dist/generators/documentation/templates/toolingTemplate.d.ts.map +1 -1
- package/dist/generators/documentation/templates/toolingTemplate.js +6 -20
- package/dist/generators/documentation/templates/toolingTemplate.js.map +1 -1
- package/dist/generators/documentation/templates/troubleshootingTemplate.d.ts +2 -0
- package/dist/generators/documentation/templates/troubleshootingTemplate.d.ts.map +1 -0
- package/dist/generators/documentation/templates/troubleshootingTemplate.js +292 -0
- package/dist/generators/documentation/templates/troubleshootingTemplate.js.map +1 -0
- package/dist/generators/plans/templates/indexTemplate.d.ts.map +1 -1
- package/dist/generators/plans/templates/indexTemplate.js +3 -2
- package/dist/generators/plans/templates/indexTemplate.js.map +1 -1
- package/dist/generators/plans/templates/planTemplate.d.ts.map +1 -1
- package/dist/generators/plans/templates/planTemplate.js +74 -3
- package/dist/generators/plans/templates/planTemplate.js.map +1 -1
- package/dist/generators/shared/generatorUtils.d.ts +1 -1
- package/dist/generators/shared/generatorUtils.d.ts.map +1 -1
- package/dist/generators/shared/generatorUtils.js +1 -1
- package/dist/generators/shared/generatorUtils.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +46 -1000
- package/dist/index.js.map +1 -1
- package/dist/prompts/defaults.d.ts +2 -2
- package/dist/prompts/defaults.d.ts.map +1 -1
- package/dist/prompts/defaults.js +11 -11
- package/dist/services/baseLLMClient.d.ts +3 -3
- package/dist/services/baseLLMClient.d.ts.map +1 -1
- package/dist/services/baseLLMClient.js +44 -5
- package/dist/services/baseLLMClient.js.map +1 -1
- package/dist/services/fill/fillService.d.ts +0 -4
- package/dist/services/fill/fillService.d.ts.map +1 -1
- package/dist/services/fill/fillService.js +6 -54
- package/dist/services/fill/fillService.js.map +1 -1
- package/dist/services/init/initService.d.ts +2 -2
- package/dist/services/init/initService.d.ts.map +1 -1
- package/dist/services/init/initService.js +45 -15
- package/dist/services/init/initService.js.map +1 -1
- package/dist/services/llmClientFactory.d.ts +2 -8
- package/dist/services/llmClientFactory.d.ts.map +1 -1
- package/dist/services/llmClientFactory.js +10 -96
- package/dist/services/llmClientFactory.js.map +1 -1
- package/dist/services/openRouterClient.d.ts +0 -3
- package/dist/services/openRouterClient.d.ts.map +1 -1
- package/dist/services/openRouterClient.js +2 -49
- package/dist/services/openRouterClient.js.map +1 -1
- package/dist/services/plan/planService.d.ts +2 -4
- package/dist/services/plan/planService.d.ts.map +1 -1
- package/dist/services/plan/planService.js +3 -12
- package/dist/services/plan/planService.js.map +1 -1
- package/dist/services/shared/llmConfig.d.ts.map +1 -1
- package/dist/services/shared/llmConfig.js +11 -53
- package/dist/services/shared/llmConfig.js.map +1 -1
- package/dist/types.d.ts +7 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/fileMapper.d.ts +1 -1
- package/dist/utils/fileMapper.d.ts.map +1 -1
- package/dist/utils/fileMapper.js +40 -19
- package/dist/utils/fileMapper.js.map +1 -1
- package/dist/utils/i18n.d.ts +11 -32
- package/dist/utils/i18n.d.ts.map +1 -1
- package/dist/utils/i18n.js +22 -64
- package/dist/utils/i18n.js.map +1 -1
- package/package.json +9 -12
- package/prompts/update_plan_prompt.md +4 -5
- package/prompts/update_scaffold_prompt.md +7 -8
- package/dist/generators/agents/contextUtils.d.ts +0 -8
- package/dist/generators/agents/contextUtils.d.ts.map +0 -1
- package/dist/generators/agents/contextUtils.js +0 -15
- package/dist/generators/agents/contextUtils.js.map +0 -1
- package/dist/generators/agents/promptFormatter.d.ts +0 -9
- package/dist/generators/agents/promptFormatter.d.ts.map +0 -1
- package/dist/generators/agents/promptFormatter.js +0 -84
- package/dist/generators/agents/promptFormatter.js.map +0 -1
- package/dist/generators/analyzers/codebaseAnalyzer.d.ts +0 -45
- package/dist/generators/analyzers/codebaseAnalyzer.d.ts.map +0 -1
- package/dist/generators/analyzers/codebaseAnalyzer.js +0 -293
- package/dist/generators/analyzers/codebaseAnalyzer.js.map +0 -1
- package/dist/generators/analyzers/index.d.ts +0 -3
- package/dist/generators/analyzers/index.d.ts.map +0 -1
- package/dist/generators/analyzers/index.js +0 -6
- package/dist/generators/analyzers/index.js.map +0 -1
- package/dist/generators/documentation/documentationTemplates.d.ts +0 -21
- package/dist/generators/documentation/documentationTemplates.d.ts.map +0 -1
- package/dist/generators/documentation/documentationTemplates.js +0 -359
- package/dist/generators/documentation/documentationTemplates.js.map +0 -1
- package/dist/generators/documentation/documentationTypes.d.ts +0 -11
- package/dist/generators/documentation/documentationTypes.d.ts.map +0 -1
- package/dist/generators/documentation/documentationTypes.js +0 -22
- package/dist/generators/documentation/documentationTypes.js.map +0 -1
- package/dist/generators/documentation/documentationUtils.d.ts +0 -7
- package/dist/generators/documentation/documentationUtils.d.ts.map +0 -1
- package/dist/generators/documentation/documentationUtils.js +0 -28
- package/dist/generators/documentation/documentationUtils.js.map +0 -1
- package/dist/generators/documentation/incrementalDocumentationGenerator.d.ts +0 -33
- package/dist/generators/documentation/incrementalDocumentationGenerator.d.ts.map +0 -1
- package/dist/generators/documentation/incrementalDocumentationGenerator.js +0 -400
- package/dist/generators/documentation/incrementalDocumentationGenerator.js.map +0 -1
- package/dist/generators/documentation/templates.d.ts +0 -31
- package/dist/generators/documentation/templates.d.ts.map +0 -1
- package/dist/generators/documentation/templates.js +0 -566
- package/dist/generators/documentation/templates.js.map +0 -1
- package/dist/generators/guidelines/agentIntegration.d.ts +0 -43
- package/dist/generators/guidelines/agentIntegration.d.ts.map +0 -1
- package/dist/generators/guidelines/agentIntegration.js +0 -157
- package/dist/generators/guidelines/agentIntegration.js.map +0 -1
- package/dist/generators/guidelines/guidelineTypes.d.ts +0 -40
- package/dist/generators/guidelines/guidelineTypes.d.ts.map +0 -1
- package/dist/generators/guidelines/guidelineTypes.js +0 -144
- package/dist/generators/guidelines/guidelineTypes.js.map +0 -1
- package/dist/generators/guidelines/guidelinesAnalyzer.d.ts +0 -30
- package/dist/generators/guidelines/guidelinesAnalyzer.d.ts.map +0 -1
- package/dist/generators/guidelines/guidelinesAnalyzer.js +0 -263
- package/dist/generators/guidelines/guidelinesAnalyzer.js.map +0 -1
- package/dist/generators/guidelines/guidelinesGenerator.d.ts +0 -30
- package/dist/generators/guidelines/guidelinesGenerator.d.ts.map +0 -1
- package/dist/generators/guidelines/guidelinesGenerator.js +0 -249
- package/dist/generators/guidelines/guidelinesGenerator.js.map +0 -1
- package/dist/generators/guidelines/guidelinesTemplates.d.ts +0 -23
- package/dist/generators/guidelines/guidelinesTemplates.d.ts.map +0 -1
- package/dist/generators/guidelines/guidelinesTemplates.js +0 -304
- package/dist/generators/guidelines/guidelinesTemplates.js.map +0 -1
- package/dist/generators/guidelines/index.d.ts +0 -6
- package/dist/generators/guidelines/index.d.ts.map +0 -1
- package/dist/generators/guidelines/index.js +0 -16
- package/dist/generators/guidelines/index.js.map +0 -1
- package/dist/generators/moduleGrouper.d.ts +0 -14
- package/dist/generators/moduleGrouper.d.ts.map +0 -1
- package/dist/generators/moduleGrouper.js +0 -82
- package/dist/generators/moduleGrouper.js.map +0 -1
- package/dist/generators/projectAnalyzer.d.ts +0 -14
- package/dist/generators/projectAnalyzer.d.ts.map +0 -1
- package/dist/generators/projectAnalyzer.js +0 -217
- package/dist/generators/projectAnalyzer.js.map +0 -1
- package/dist/services/changeAnalyzer.d.ts +0 -44
- package/dist/services/changeAnalyzer.d.ts.map +0 -1
- package/dist/services/changeAnalyzer.js +0 -344
- package/dist/services/changeAnalyzer.js.map +0 -1
- package/dist/utils/interactiveMode.d.ts +0 -21
- package/dist/utils/interactiveMode.d.ts.map +0 -1
- package/dist/utils/interactiveMode.js +0 -737
- package/dist/utils/interactiveMode.js.map +0 -1
- package/dist/utils/tokenEstimator.d.ts +0 -28
- package/dist/utils/tokenEstimator.d.ts.map +0 -1
- package/dist/utils/tokenEstimator.js +0 -134
- package/dist/utils/tokenEstimator.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -37,31 +37,25 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
37
37
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
38
38
|
};
|
|
39
39
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
exports.runInit = runInit;
|
|
40
41
|
exports.runGenerate = runGenerate;
|
|
41
42
|
exports.runAnalyze = runAnalyze;
|
|
42
43
|
exports.runUpdate = runUpdate;
|
|
43
44
|
exports.runPreview = runPreview;
|
|
44
45
|
exports.runGuidelines = runGuidelines;
|
|
45
|
-
exports.
|
|
46
|
+
exports.runLlmFill = runLlmFill;
|
|
46
47
|
const commander_1 = require("commander");
|
|
47
48
|
const path = __importStar(require("path"));
|
|
48
|
-
const fs = __importStar(require("fs-extra"));
|
|
49
|
-
const glob_1 = require("glob");
|
|
50
49
|
const dotenv = __importStar(require("dotenv"));
|
|
51
50
|
const chalk_1 = __importDefault(require("chalk"));
|
|
52
51
|
const inquirer_1 = __importDefault(require("inquirer"));
|
|
53
|
-
const fileMapper_1 = require("./utils/fileMapper");
|
|
54
|
-
const documentationGenerator_1 = require("./generators/documentation/documentationGenerator");
|
|
55
|
-
const agentGenerator_1 = require("./generators/agents/agentGenerator");
|
|
56
52
|
const planGenerator_1 = require("./generators/plans/planGenerator");
|
|
57
|
-
const shared_1 = require("./generators/shared");
|
|
58
53
|
const cliUI_1 = require("./utils/cliUI");
|
|
59
|
-
const promptLoader_1 = require("./utils/promptLoader");
|
|
60
54
|
const versionChecker_1 = require("./utils/versionChecker");
|
|
61
55
|
const i18n_1 = require("./utils/i18n");
|
|
62
|
-
const
|
|
63
|
-
const
|
|
64
|
-
const
|
|
56
|
+
const initService_1 = require("./services/init/initService");
|
|
57
|
+
const fillService_1 = require("./services/fill/fillService");
|
|
58
|
+
const planService_1 = require("./services/plan/planService");
|
|
65
59
|
dotenv.config();
|
|
66
60
|
const initialLocale = (0, i18n_1.detectLocale)(process.argv.slice(2), process.env.AI_CONTEXT_LANG);
|
|
67
61
|
let currentLocale = initialLocale;
|
|
@@ -73,17 +67,26 @@ const localeLabelKeys = {
|
|
|
73
67
|
};
|
|
74
68
|
const program = new commander_1.Command();
|
|
75
69
|
const ui = new cliUI_1.CLIInterface(t);
|
|
76
|
-
const VERSION = '0.
|
|
70
|
+
const VERSION = '0.4.0';
|
|
77
71
|
const PACKAGE_NAME = '@ai-coders/context';
|
|
78
|
-
const DEFAULT_MODEL = 'x-ai/grok-4-fast
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
72
|
+
const DEFAULT_MODEL = 'x-ai/grok-4-fast';
|
|
73
|
+
const initService = new initService_1.InitService({
|
|
74
|
+
ui,
|
|
75
|
+
t,
|
|
76
|
+
version: VERSION
|
|
77
|
+
});
|
|
78
|
+
const fillService = new fillService_1.FillService({
|
|
79
|
+
ui,
|
|
80
|
+
t,
|
|
81
|
+
version: VERSION,
|
|
82
|
+
defaultModel: DEFAULT_MODEL
|
|
83
|
+
});
|
|
84
|
+
const planService = new planService_1.PlanService({
|
|
85
|
+
ui,
|
|
86
|
+
t,
|
|
87
|
+
version: VERSION,
|
|
88
|
+
defaultModel: DEFAULT_MODEL
|
|
89
|
+
});
|
|
87
90
|
program
|
|
88
91
|
.name('ai-context')
|
|
89
92
|
.description(t('cli.description'))
|
|
@@ -111,34 +114,12 @@ program
|
|
|
111
114
|
.argument('<repo-path>', t('commands.init.arguments.repoPath'))
|
|
112
115
|
.argument('[type]', t('commands.init.arguments.type'), 'both')
|
|
113
116
|
.option('-o, --output <dir>', t('commands.init.options.output'), './.context')
|
|
114
|
-
.option('--docs <keys...>', t('commands.init.options.docs'))
|
|
115
|
-
.option('--agents <keys...>', t('commands.init.options.agents'))
|
|
116
|
-
.option('--exclude <patterns...>', t('commands.init.options.exclude'))
|
|
117
|
-
.option('--include <patterns...>', t('commands.init.options.include'))
|
|
118
|
-
.option('-v, --verbose', t('commands.init.options.verbose'))
|
|
119
|
-
.action(async (repoPath, type, options) => {
|
|
120
|
-
try {
|
|
121
|
-
await runInit(repoPath, type, options);
|
|
122
|
-
}
|
|
123
|
-
catch (error) {
|
|
124
|
-
ui.displayError(t('errors.init.scaffoldFailed'), error);
|
|
125
|
-
process.exit(1);
|
|
126
|
-
}
|
|
127
|
-
});
|
|
128
|
-
program
|
|
129
|
-
.command('scaffold')
|
|
130
|
-
.description(t('commands.scaffold.description'))
|
|
131
|
-
.argument('<repo-path>', t('commands.init.arguments.repoPath'))
|
|
132
|
-
.argument('[type]', t('commands.init.arguments.type'), 'both')
|
|
133
|
-
.option('-o, --output <dir>', t('commands.init.options.output'), './.context')
|
|
134
|
-
.option('--docs <keys...>', t('commands.init.options.docs'))
|
|
135
|
-
.option('--agents <keys...>', t('commands.init.options.agents'))
|
|
136
117
|
.option('--exclude <patterns...>', t('commands.init.options.exclude'))
|
|
137
118
|
.option('--include <patterns...>', t('commands.init.options.include'))
|
|
138
119
|
.option('-v, --verbose', t('commands.init.options.verbose'))
|
|
139
120
|
.action(async (repoPath, type, options) => {
|
|
140
121
|
try {
|
|
141
|
-
await
|
|
122
|
+
await initService.run(repoPath, type, options);
|
|
142
123
|
}
|
|
143
124
|
catch (error) {
|
|
144
125
|
ui.displayError(t('errors.init.scaffoldFailed'), error);
|
|
@@ -155,17 +136,13 @@ program
|
|
|
155
136
|
.option('-p, --provider <provider>', t('commands.fill.options.provider'))
|
|
156
137
|
.option('--base-url <url>', t('commands.fill.options.baseUrl'))
|
|
157
138
|
.option('--prompt <file>', t('commands.fill.options.prompt'))
|
|
158
|
-
.option('--dry-run', t('commands.fill.options.dryRun'), false)
|
|
159
|
-
.option('--all', t('commands.fill.options.all'), false)
|
|
160
139
|
.option('--limit <number>', t('commands.fill.options.limit'), (value) => parseInt(value, 10))
|
|
161
|
-
.option('--docs <keys...>', t('commands.fill.options.docs'))
|
|
162
|
-
.option('--agents <keys...>', t('commands.fill.options.agents'))
|
|
163
140
|
.option('--exclude <patterns...>', t('commands.fill.options.exclude'))
|
|
164
141
|
.option('--include <patterns...>', t('commands.fill.options.include'))
|
|
165
142
|
.option('-v, --verbose', t('commands.fill.options.verbose'))
|
|
166
143
|
.action(async (repoPath, options) => {
|
|
167
144
|
try {
|
|
168
|
-
await
|
|
145
|
+
await fillService.run(repoPath, options);
|
|
169
146
|
}
|
|
170
147
|
catch (error) {
|
|
171
148
|
ui.displayError(t('errors.fill.failed'), error);
|
|
@@ -179,8 +156,6 @@ program
|
|
|
179
156
|
.option('-o, --output <dir>', t('commands.plan.options.output'), './.context')
|
|
180
157
|
.option('--title <title>', t('commands.plan.options.title'))
|
|
181
158
|
.option('--summary <text>', t('commands.plan.options.summary'))
|
|
182
|
-
.option('--agents <types...>', t('commands.plan.options.agents'))
|
|
183
|
-
.option('--docs <keys...>', t('commands.plan.options.docs'))
|
|
184
159
|
.option('-f, --force', t('commands.plan.options.force'))
|
|
185
160
|
.option('--fill', t('commands.plan.options.fill'))
|
|
186
161
|
.option('-r, --repo <path>', t('commands.plan.options.repo'))
|
|
@@ -194,26 +169,16 @@ program
|
|
|
194
169
|
.option('--exclude <patterns...>', t('commands.plan.options.exclude'))
|
|
195
170
|
.option('-v, --verbose', t('commands.plan.options.verbose'))
|
|
196
171
|
.action(async (planName, rawOptions) => {
|
|
197
|
-
const agentSelection = parseAgentSelection(rawOptions.agents);
|
|
198
|
-
if (agentSelection.invalid.length > 0) {
|
|
199
|
-
ui.displayWarning(t('warnings.agents.unknown', { values: agentSelection.invalid.join(', ') }));
|
|
200
|
-
}
|
|
201
|
-
const docSelection = parseDocSelection(rawOptions.docs);
|
|
202
|
-
if (docSelection.invalid.length > 0) {
|
|
203
|
-
ui.displayWarning(t('warnings.docs.unknown', { values: docSelection.invalid.join(', ') }));
|
|
204
|
-
}
|
|
205
172
|
const outputDir = path.resolve(rawOptions.output || './.context');
|
|
206
173
|
if (rawOptions.fill) {
|
|
207
174
|
try {
|
|
208
|
-
await scaffoldPlanIfNeeded(planName, outputDir, {
|
|
175
|
+
await planService.scaffoldPlanIfNeeded(planName, outputDir, {
|
|
209
176
|
title: rawOptions.title,
|
|
210
177
|
summary: rawOptions.summary,
|
|
211
|
-
agentSelection,
|
|
212
|
-
docSelection,
|
|
213
178
|
force: Boolean(rawOptions.force),
|
|
214
179
|
verbose: Boolean(rawOptions.verbose)
|
|
215
180
|
});
|
|
216
|
-
await
|
|
181
|
+
await planService.fillPlan(planName, { ...rawOptions, output: outputDir });
|
|
217
182
|
}
|
|
218
183
|
catch (error) {
|
|
219
184
|
ui.displayError(t('errors.plan.fillFailed'), error);
|
|
@@ -229,8 +194,6 @@ program
|
|
|
229
194
|
outputDir,
|
|
230
195
|
title: rawOptions.title,
|
|
231
196
|
summary: rawOptions.summary,
|
|
232
|
-
selectedAgentTypes: agentSelection.explicitNone ? null : agentSelection.selected,
|
|
233
|
-
selectedDocKeys: docSelection.explicitNone ? null : docSelection.selected,
|
|
234
197
|
force: Boolean(rawOptions.force),
|
|
235
198
|
verbose: Boolean(rawOptions.verbose)
|
|
236
199
|
});
|
|
@@ -247,90 +210,15 @@ program
|
|
|
247
210
|
}
|
|
248
211
|
});
|
|
249
212
|
async function runInit(repoPath, type, rawOptions) {
|
|
250
|
-
|
|
251
|
-
const docSelection = parseDocSelection(rawOptions.docs);
|
|
252
|
-
const agentSelection = parseAgentSelection(rawOptions.agents);
|
|
253
|
-
if (docSelection.invalid.length > 0) {
|
|
254
|
-
ui.displayWarning(t('warnings.docs.unknown', { values: docSelection.invalid.join(', ') }));
|
|
255
|
-
}
|
|
256
|
-
if (agentSelection.invalid.length > 0) {
|
|
257
|
-
ui.displayWarning(t('warnings.agents.unknown', { values: agentSelection.invalid.join(', ') }));
|
|
258
|
-
}
|
|
259
|
-
const options = {
|
|
260
|
-
repoPath: path.resolve(repoPath),
|
|
261
|
-
outputDir: path.resolve(rawOptions.output || './.context'),
|
|
262
|
-
include: rawOptions.include,
|
|
263
|
-
exclude: rawOptions.exclude || [],
|
|
264
|
-
verbose: rawOptions.verbose || false,
|
|
265
|
-
scaffoldDocs: shouldGenerateDocs(resolvedType, docSelection),
|
|
266
|
-
scaffoldAgents: shouldGenerateAgents(resolvedType, agentSelection),
|
|
267
|
-
selectedDocKeys: docSelection.selected,
|
|
268
|
-
selectedAgentTypes: agentSelection.selected
|
|
269
|
-
};
|
|
270
|
-
if (!options.scaffoldDocs && !options.scaffoldAgents) {
|
|
271
|
-
ui.displayWarning(t('warnings.scaffold.noneSelected'));
|
|
272
|
-
return;
|
|
273
|
-
}
|
|
274
|
-
await ensurePaths(options);
|
|
275
|
-
ui.displayWelcome(VERSION);
|
|
276
|
-
ui.displayProjectInfo(options.repoPath, options.outputDir, resolvedType);
|
|
277
|
-
const fileMapper = new fileMapper_1.FileMapper(options.exclude);
|
|
278
|
-
ui.displayStep(1, 3, t('steps.init.analyze'));
|
|
279
|
-
ui.startSpinner(t('spinner.repo.scanning'));
|
|
280
|
-
const repoStructure = await fileMapper.mapRepository(options.repoPath, options.include);
|
|
281
|
-
ui.updateSpinner(t('spinner.repo.scanComplete', {
|
|
282
|
-
fileCount: repoStructure.totalFiles,
|
|
283
|
-
directoryCount: repoStructure.directories.length
|
|
284
|
-
}), 'success');
|
|
285
|
-
let docsGenerated = 0;
|
|
286
|
-
let agentsGenerated = 0;
|
|
287
|
-
const docGenerator = new documentationGenerator_1.DocumentationGenerator();
|
|
288
|
-
const agentGenerator = new agentGenerator_1.AgentGenerator();
|
|
289
|
-
if (options.scaffoldDocs) {
|
|
290
|
-
ui.displayStep(2, 3, t('steps.init.docs'));
|
|
291
|
-
ui.startSpinner(t('spinner.docs.creating'));
|
|
292
|
-
docsGenerated = await docGenerator.generateDocumentation(repoStructure, options.outputDir, { selectedDocs: options.selectedDocKeys }, options.verbose);
|
|
293
|
-
ui.updateSpinner(t('spinner.docs.created', { count: docsGenerated }), 'success');
|
|
294
|
-
}
|
|
295
|
-
if (options.scaffoldAgents) {
|
|
296
|
-
ui.displayStep(3, options.scaffoldDocs ? 3 : 2, t('steps.init.agents'));
|
|
297
|
-
ui.startSpinner(t('spinner.agents.creating'));
|
|
298
|
-
agentsGenerated = await agentGenerator.generateAgentPrompts(repoStructure, options.outputDir, options.selectedAgentTypes, options.verbose);
|
|
299
|
-
ui.updateSpinner(t('spinner.agents.created', { count: agentsGenerated }), 'success');
|
|
300
|
-
}
|
|
301
|
-
ui.displayGenerationSummary(docsGenerated, agentsGenerated);
|
|
302
|
-
ui.displaySuccess(t('success.scaffold.ready', { path: chalk_1.default.cyan(options.outputDir) }));
|
|
303
|
-
}
|
|
304
|
-
function resolveScaffoldType(type, rawOptions) {
|
|
305
|
-
const normalized = (type || 'both').toLowerCase();
|
|
306
|
-
const allowed = ['docs', 'agents', 'both'];
|
|
307
|
-
if (!allowed.includes(normalized)) {
|
|
308
|
-
throw new Error(t('errors.init.invalidType', { value: type, allowed: allowed.join(', ') }));
|
|
309
|
-
}
|
|
310
|
-
if (rawOptions.docsOnly) {
|
|
311
|
-
return 'docs';
|
|
312
|
-
}
|
|
313
|
-
if (rawOptions.agentsOnly) {
|
|
314
|
-
return 'agents';
|
|
315
|
-
}
|
|
316
|
-
return normalized;
|
|
317
|
-
}
|
|
318
|
-
async function ensurePaths(options) {
|
|
319
|
-
const exists = await fs.pathExists(options.repoPath);
|
|
320
|
-
if (!exists) {
|
|
321
|
-
throw new Error(t('errors.common.repoMissing', { path: options.repoPath }));
|
|
322
|
-
}
|
|
323
|
-
await fs.ensureDir(options.outputDir);
|
|
213
|
+
await initService.run(repoPath, type, rawOptions);
|
|
324
214
|
}
|
|
325
215
|
async function runGenerate(repoPath, options) {
|
|
326
216
|
const type = options?.docsOnly ? 'docs' : options?.agentsOnly ? 'agents' : (options?.type || 'both');
|
|
327
|
-
await
|
|
217
|
+
await initService.run(repoPath, type, {
|
|
328
218
|
output: options?.output ?? options?.outputDir ?? './.context',
|
|
329
219
|
include: options?.include,
|
|
330
220
|
exclude: options?.exclude,
|
|
331
221
|
verbose: options?.verbose,
|
|
332
|
-
docs: options?.docs,
|
|
333
|
-
agents: options?.agents,
|
|
334
222
|
docsOnly: options?.docsOnly,
|
|
335
223
|
agentsOnly: options?.agentsOnly
|
|
336
224
|
});
|
|
@@ -347,621 +235,8 @@ async function runPreview(..._args) {
|
|
|
347
235
|
async function runGuidelines(..._args) {
|
|
348
236
|
throw new Error(t('errors.commands.guidelinesRemoved'));
|
|
349
237
|
}
|
|
350
|
-
async function resolveLlmConfig(rawOptions, defaults) {
|
|
351
|
-
const providerEnvMap = llmClientFactory_1.LLMClientFactory.getEnvironmentVariables();
|
|
352
|
-
const defaultModels = llmClientFactory_1.LLMClientFactory.getDefaultModels();
|
|
353
|
-
let provider = rawOptions.provider;
|
|
354
|
-
let model = rawOptions.model;
|
|
355
|
-
let apiKey = rawOptions.apiKey;
|
|
356
|
-
if (!apiKey) {
|
|
357
|
-
if (provider) {
|
|
358
|
-
for (const envVar of providerEnvMap[provider]) {
|
|
359
|
-
const value = process.env[envVar];
|
|
360
|
-
if (value) {
|
|
361
|
-
apiKey = value;
|
|
362
|
-
break;
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
else {
|
|
367
|
-
outer: for (const [prov, envVars] of Object.entries(providerEnvMap)) {
|
|
368
|
-
for (const envVar of envVars) {
|
|
369
|
-
const value = process.env[envVar];
|
|
370
|
-
if (value) {
|
|
371
|
-
apiKey = value;
|
|
372
|
-
provider = prov;
|
|
373
|
-
break outer;
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
if (!provider) {
|
|
380
|
-
if (model) {
|
|
381
|
-
provider = llmClientFactory_1.LLMClientFactory.detectProviderFromModel(model);
|
|
382
|
-
}
|
|
383
|
-
else if (apiKey) {
|
|
384
|
-
provider = llmClientFactory_1.LLMClientFactory.getProviderFromApiKey(apiKey);
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
if (!model) {
|
|
388
|
-
if (provider === 'openrouter' && process.env.OPENROUTER_MODEL) {
|
|
389
|
-
model = process.env.OPENROUTER_MODEL;
|
|
390
|
-
}
|
|
391
|
-
else if (provider && defaultModels[provider]?.length) {
|
|
392
|
-
model = defaultModels[provider][0];
|
|
393
|
-
}
|
|
394
|
-
else {
|
|
395
|
-
model = defaults.fallbackModel;
|
|
396
|
-
provider = llmClientFactory_1.LLMClientFactory.detectProviderFromModel(model);
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
if (!provider) {
|
|
400
|
-
provider = llmClientFactory_1.LLMClientFactory.detectProviderFromModel(model || defaults.fallbackModel);
|
|
401
|
-
}
|
|
402
|
-
if (!apiKey) {
|
|
403
|
-
for (const envVar of providerEnvMap[provider]) {
|
|
404
|
-
const value = process.env[envVar];
|
|
405
|
-
if (value) {
|
|
406
|
-
apiKey = value;
|
|
407
|
-
break;
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
if (!apiKey) {
|
|
412
|
-
const envVars = providerEnvMap[provider];
|
|
413
|
-
throw new Error(t('errors.fill.apiKeyMissing', {
|
|
414
|
-
provider: provider.toUpperCase(),
|
|
415
|
-
envVars: envVars.join(', ')
|
|
416
|
-
}));
|
|
417
|
-
}
|
|
418
|
-
return {
|
|
419
|
-
provider,
|
|
420
|
-
model: model || defaults.fallbackModel,
|
|
421
|
-
apiKey,
|
|
422
|
-
baseUrl: rawOptions.baseUrl
|
|
423
|
-
};
|
|
424
|
-
}
|
|
425
238
|
async function runLlmFill(repoPath, rawOptions) {
|
|
426
|
-
|
|
427
|
-
const outputDir = path.resolve(rawOptions.output || './.context');
|
|
428
|
-
const docsDir = path.join(outputDir, 'docs');
|
|
429
|
-
const agentsDir = path.join(outputDir, 'agents');
|
|
430
|
-
await ensureDirectoryExists(docsDir, t('errors.fill.missingDocsScaffold'));
|
|
431
|
-
await ensureDirectoryExists(agentsDir, t('errors.fill.missingAgentsScaffold'));
|
|
432
|
-
const docSelection = parseDocSelection(rawOptions.docs);
|
|
433
|
-
const agentSelection = parseAgentSelection(rawOptions.agents);
|
|
434
|
-
if (docSelection.invalid.length > 0) {
|
|
435
|
-
ui.displayWarning(t('warnings.docs.unknown', { values: docSelection.invalid.join(', ') }));
|
|
436
|
-
}
|
|
437
|
-
if (agentSelection.invalid.length > 0) {
|
|
438
|
-
ui.displayWarning(t('warnings.agents.unknown', { values: agentSelection.invalid.join(', ') }));
|
|
439
|
-
}
|
|
440
|
-
const { provider, model, apiKey, baseUrl } = await resolveLlmConfig(rawOptions, {
|
|
441
|
-
fallbackModel: DEFAULT_MODEL
|
|
442
|
-
});
|
|
443
|
-
const scaffoldPrompt = await (0, promptLoader_1.resolveScaffoldPrompt)(rawOptions.prompt, missingPath => t('errors.fill.promptMissing', { path: missingPath }));
|
|
444
|
-
const docAllowlist = docSelection.explicitNone
|
|
445
|
-
? new Set()
|
|
446
|
-
: (0, guideRegistry_1.getDocFilesByKeys)(docSelection.selected);
|
|
447
|
-
const agentAllowlist = agentSelection.explicitNone
|
|
448
|
-
? new Set()
|
|
449
|
-
: getAgentFilesByTypes(agentSelection.selected);
|
|
450
|
-
const options = {
|
|
451
|
-
repoPath: resolvedRepo,
|
|
452
|
-
outputDir,
|
|
453
|
-
provider,
|
|
454
|
-
model,
|
|
455
|
-
apiKey,
|
|
456
|
-
baseUrl,
|
|
457
|
-
include: rawOptions.include,
|
|
458
|
-
exclude: rawOptions.exclude,
|
|
459
|
-
verbose: rawOptions.verbose || false,
|
|
460
|
-
dryRun: rawOptions.dryRun || false,
|
|
461
|
-
processAll: rawOptions.all || false,
|
|
462
|
-
limit: rawOptions.limit,
|
|
463
|
-
selectedDocKeys: docSelection.selected,
|
|
464
|
-
selectedAgentTypes: agentSelection.selected,
|
|
465
|
-
selectedDocFiles: docAllowlist,
|
|
466
|
-
selectedAgentFiles: agentAllowlist
|
|
467
|
-
};
|
|
468
|
-
const scaffoldPromptDisplayPath = scaffoldPrompt.path
|
|
469
|
-
? path.relative(process.cwd(), scaffoldPrompt.path) || scaffoldPrompt.path
|
|
470
|
-
: undefined;
|
|
471
|
-
if (scaffoldPrompt.source === 'custom' && scaffoldPromptDisplayPath) {
|
|
472
|
-
ui.displayInfo(t('info.prompt.title'), t('info.prompt.usingCustom', { path: scaffoldPromptDisplayPath }));
|
|
473
|
-
}
|
|
474
|
-
else if (scaffoldPrompt.source === 'package' && scaffoldPromptDisplayPath) {
|
|
475
|
-
ui.displayInfo(t('info.prompt.title'), t('info.prompt.usingPackage', { path: scaffoldPromptDisplayPath }));
|
|
476
|
-
}
|
|
477
|
-
else {
|
|
478
|
-
ui.displayInfo(t('info.prompt.title'), t('info.prompt.usingBundled'));
|
|
479
|
-
}
|
|
480
|
-
ui.displayWelcome(VERSION);
|
|
481
|
-
ui.displayProjectInfo(options.repoPath, options.outputDir, `fill:${options.provider}`);
|
|
482
|
-
const fileMapper = new fileMapper_1.FileMapper(options.exclude);
|
|
483
|
-
ui.displayStep(1, 3, t('steps.fill.analyze'));
|
|
484
|
-
ui.startSpinner(t('spinner.repo.scanning'));
|
|
485
|
-
const repoStructure = await fileMapper.mapRepository(options.repoPath, options.include);
|
|
486
|
-
ui.updateSpinner(t('spinner.repo.scanComplete', {
|
|
487
|
-
fileCount: repoStructure.totalFiles,
|
|
488
|
-
directoryCount: repoStructure.directories.length
|
|
489
|
-
}), 'success');
|
|
490
|
-
const systemPrompt = scaffoldPrompt.content;
|
|
491
|
-
const llmClient = llmClientFactory_1.LLMClientFactory.createClient({
|
|
492
|
-
apiKey: options.apiKey,
|
|
493
|
-
model: options.model,
|
|
494
|
-
provider: options.provider,
|
|
495
|
-
baseUrl: options.baseUrl
|
|
496
|
-
});
|
|
497
|
-
const targets = await collectTargets(docsDir, agentsDir, options.processAll, options.limit, options.selectedDocFiles, options.selectedAgentFiles);
|
|
498
|
-
if (targets.length === 0) {
|
|
499
|
-
ui.displayWarning(t('warnings.fill.noTargets'));
|
|
500
|
-
return;
|
|
501
|
-
}
|
|
502
|
-
const contextSummary = buildContextSummary(repoStructure);
|
|
503
|
-
const results = [];
|
|
504
|
-
ui.displayStep(2, 3, t('steps.fill.processFiles', { count: targets.length, model: options.model }));
|
|
505
|
-
for (const target of targets) {
|
|
506
|
-
const relativePath = path.relative(options.outputDir, target.fullPath);
|
|
507
|
-
ui.startSpinner(t('spinner.fill.processing', { path: relativePath }));
|
|
508
|
-
try {
|
|
509
|
-
const currentContent = await fs.readFile(target.fullPath, 'utf-8');
|
|
510
|
-
const userPrompt = buildUserPrompt(relativePath, currentContent, contextSummary, target.isAgent);
|
|
511
|
-
const updatedContent = await llmClient.generateText(userPrompt, systemPrompt);
|
|
512
|
-
if (!updatedContent || !updatedContent.trim()) {
|
|
513
|
-
ui.updateSpinner(t('spinner.fill.noContent', { path: relativePath }), 'warn');
|
|
514
|
-
results.push({ file: relativePath, status: 'skipped', message: t('messages.fill.emptyResponse') });
|
|
515
|
-
continue;
|
|
516
|
-
}
|
|
517
|
-
if (options.dryRun) {
|
|
518
|
-
ui.updateSpinner(t('spinner.fill.dryRunPreview', { path: relativePath }), 'info');
|
|
519
|
-
console.log(chalk_1.default.gray(`\n${t('messages.fill.previewStart')}`));
|
|
520
|
-
console.log(updatedContent.trim());
|
|
521
|
-
console.log(chalk_1.default.gray(`${t('messages.fill.previewEnd')}\n`));
|
|
522
|
-
}
|
|
523
|
-
else {
|
|
524
|
-
await fs.writeFile(target.fullPath, ensureTrailingNewline(updatedContent));
|
|
525
|
-
ui.updateSpinner(t('spinner.fill.updated', { path: relativePath }), 'success');
|
|
526
|
-
}
|
|
527
|
-
results.push({ file: relativePath, status: options.dryRun ? 'skipped' : 'updated' });
|
|
528
|
-
}
|
|
529
|
-
catch (error) {
|
|
530
|
-
ui.updateSpinner(t('spinner.fill.failed', { path: relativePath }), 'fail');
|
|
531
|
-
results.push({
|
|
532
|
-
file: relativePath,
|
|
533
|
-
status: 'failed',
|
|
534
|
-
message: error instanceof Error ? error.message : String(error)
|
|
535
|
-
});
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
ui.displayStep(3, 3, t('steps.fill.summary'));
|
|
539
|
-
printLlmSummary(llmClient.getUsageStats(), results, options.dryRun);
|
|
540
|
-
ui.displaySuccess(t('success.fill.completed'));
|
|
541
|
-
}
|
|
542
|
-
async function scaffoldPlanIfNeeded(planName, outputDir, options) {
|
|
543
|
-
const resolvedOutput = path.resolve(outputDir);
|
|
544
|
-
const plansDir = path.join(resolvedOutput, 'plans');
|
|
545
|
-
const normalizedInput = planName.replace(/\.md$/i, '');
|
|
546
|
-
const slug = shared_1.GeneratorUtils.slugify(normalizedInput);
|
|
547
|
-
if (!slug) {
|
|
548
|
-
throw new Error(t('errors.plan.invalidName'));
|
|
549
|
-
}
|
|
550
|
-
const planPath = path.join(plansDir, `${slug}.md`);
|
|
551
|
-
const planExists = await fs.pathExists(planPath);
|
|
552
|
-
if (planExists && !options.force) {
|
|
553
|
-
return;
|
|
554
|
-
}
|
|
555
|
-
const generator = new planGenerator_1.PlanGenerator();
|
|
556
|
-
const result = await generator.generatePlan({
|
|
557
|
-
planName,
|
|
558
|
-
outputDir: resolvedOutput,
|
|
559
|
-
title: options.title,
|
|
560
|
-
summary: options.summary,
|
|
561
|
-
selectedAgentTypes: options.agentSelection
|
|
562
|
-
? options.agentSelection.explicitNone
|
|
563
|
-
? null
|
|
564
|
-
: options.agentSelection.selected
|
|
565
|
-
: undefined,
|
|
566
|
-
selectedDocKeys: options.docSelection
|
|
567
|
-
? options.docSelection.explicitNone
|
|
568
|
-
? null
|
|
569
|
-
: options.docSelection.selected
|
|
570
|
-
: undefined,
|
|
571
|
-
force: Boolean(options.force),
|
|
572
|
-
verbose: Boolean(options.verbose)
|
|
573
|
-
});
|
|
574
|
-
const relativePath = result.relativePath;
|
|
575
|
-
const message = planExists && options.force
|
|
576
|
-
? t('messages.plan.regenerated', { path: relativePath })
|
|
577
|
-
: t('messages.plan.created', { path: relativePath });
|
|
578
|
-
ui.displayInfo(t('info.plan.scaffolded.title'), message);
|
|
579
|
-
}
|
|
580
|
-
async function runPlanFill(planName, rawOptions) {
|
|
581
|
-
const outputDir = path.resolve(rawOptions.output || './.context');
|
|
582
|
-
const plansDir = path.join(outputDir, 'plans');
|
|
583
|
-
await ensureDirectoryExists(plansDir, t('errors.plan.missingPlansDir'));
|
|
584
|
-
const normalizedInput = planName.replace(/\.md$/i, '');
|
|
585
|
-
const slug = shared_1.GeneratorUtils.slugify(normalizedInput);
|
|
586
|
-
if (!slug) {
|
|
587
|
-
throw new Error(t('errors.plan.invalidName'));
|
|
588
|
-
}
|
|
589
|
-
const candidateFiles = new Set();
|
|
590
|
-
candidateFiles.add(path.join(plansDir, `${slug}.md`));
|
|
591
|
-
if (planName.toLowerCase().endsWith('.md')) {
|
|
592
|
-
candidateFiles.add(path.join(plansDir, planName));
|
|
593
|
-
}
|
|
594
|
-
let planPath;
|
|
595
|
-
for (const candidate of candidateFiles) {
|
|
596
|
-
if (await fs.pathExists(candidate)) {
|
|
597
|
-
planPath = candidate;
|
|
598
|
-
break;
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
|
-
if (!planPath) {
|
|
602
|
-
const expected = Array.from(candidateFiles).map(file => path.relative(process.cwd(), file)).join(' or ');
|
|
603
|
-
throw new Error(t('errors.plan.notFound', { expected }));
|
|
604
|
-
}
|
|
605
|
-
const docsDir = path.join(outputDir, 'docs');
|
|
606
|
-
const agentsDir = path.join(outputDir, 'agents');
|
|
607
|
-
await ensureDirectoryExists(docsDir, t('errors.fill.missingDocsScaffold'));
|
|
608
|
-
await ensureDirectoryExists(agentsDir, t('errors.fill.missingAgentsScaffold'));
|
|
609
|
-
const repoPath = path.resolve(rawOptions.repo || process.cwd());
|
|
610
|
-
if (!(await fs.pathExists(repoPath))) {
|
|
611
|
-
throw new Error(t('errors.common.repoMissing', { path: repoPath }));
|
|
612
|
-
}
|
|
613
|
-
const { provider, model, apiKey, baseUrl } = await resolveLlmConfig(rawOptions, {
|
|
614
|
-
fallbackModel: DEFAULT_MODEL
|
|
615
|
-
});
|
|
616
|
-
const planPrompt = await (0, promptLoader_1.resolvePlanPrompt)(rawOptions.prompt, missingPath => t('errors.fill.promptMissing', { path: missingPath }));
|
|
617
|
-
const planContent = await fs.readFile(planPath, 'utf-8');
|
|
618
|
-
const docsIndexPath = path.join(docsDir, 'README.md');
|
|
619
|
-
const agentsIndexPath = path.join(agentsDir, 'README.md');
|
|
620
|
-
const docsIndex = (await fs.pathExists(docsIndexPath)) ? await fs.readFile(docsIndexPath, 'utf-8') : undefined;
|
|
621
|
-
const agentsIndex = (await fs.pathExists(agentsIndexPath)) ? await fs.readFile(agentsIndexPath, 'utf-8') : undefined;
|
|
622
|
-
const referencedDocs = await loadReferencedMarkdown(docsDir, extractPlanReferences(planContent, 'docs'));
|
|
623
|
-
const referencedAgents = await loadReferencedMarkdown(agentsDir, extractPlanReferences(planContent, 'agents'));
|
|
624
|
-
const planPromptDisplayPath = planPrompt.path
|
|
625
|
-
? path.relative(process.cwd(), planPrompt.path) || planPrompt.path
|
|
626
|
-
: undefined;
|
|
627
|
-
if (planPrompt.source === 'custom' && planPromptDisplayPath) {
|
|
628
|
-
ui.displayInfo(t('info.prompt.title'), t('info.prompt.usingCustom', { path: planPromptDisplayPath }));
|
|
629
|
-
}
|
|
630
|
-
else if (planPrompt.source === 'package' && planPromptDisplayPath) {
|
|
631
|
-
ui.displayInfo(t('info.prompt.title'), t('info.prompt.usingPackage', { path: planPromptDisplayPath }));
|
|
632
|
-
}
|
|
633
|
-
else {
|
|
634
|
-
ui.displayInfo(t('info.prompt.title'), t('info.prompt.usingBundled'));
|
|
635
|
-
}
|
|
636
|
-
ui.displayWelcome(VERSION);
|
|
637
|
-
ui.displayProjectInfo(repoPath, outputDir, `plan-fill:${provider}`);
|
|
638
|
-
const fileMapper = new fileMapper_1.FileMapper(rawOptions.exclude);
|
|
639
|
-
ui.displayStep(1, 3, t('steps.plan.summary'));
|
|
640
|
-
ui.startSpinner(t('spinner.planFill.analyzingRepo'));
|
|
641
|
-
const repoStructure = await fileMapper.mapRepository(repoPath, rawOptions.include);
|
|
642
|
-
const contextSummary = buildContextSummary(repoStructure);
|
|
643
|
-
ui.updateSpinner(t('spinner.planFill.summaryReady'), 'success');
|
|
644
|
-
const systemPrompt = planPrompt.content;
|
|
645
|
-
const llmClient = llmClientFactory_1.LLMClientFactory.createClient({
|
|
646
|
-
apiKey,
|
|
647
|
-
model,
|
|
648
|
-
provider,
|
|
649
|
-
baseUrl
|
|
650
|
-
});
|
|
651
|
-
const planRelativePath = path.relative(outputDir, planPath);
|
|
652
|
-
const results = [];
|
|
653
|
-
ui.displayStep(2, 3, t('steps.plan.update', { path: planRelativePath, model }));
|
|
654
|
-
ui.startSpinner(t('spinner.planFill.updating', { path: planRelativePath }));
|
|
655
|
-
try {
|
|
656
|
-
const userPrompt = buildPlanUserPrompt({
|
|
657
|
-
relativePath: planRelativePath,
|
|
658
|
-
planContent,
|
|
659
|
-
contextSummary,
|
|
660
|
-
docsIndex,
|
|
661
|
-
agentsIndex,
|
|
662
|
-
docs: referencedDocs,
|
|
663
|
-
agents: referencedAgents
|
|
664
|
-
});
|
|
665
|
-
const updatedContent = await llmClient.generateText(userPrompt, systemPrompt);
|
|
666
|
-
if (!updatedContent || !updatedContent.trim()) {
|
|
667
|
-
ui.updateSpinner(t('spinner.planFill.noContent'), 'warn');
|
|
668
|
-
results.push({ file: planRelativePath, status: 'skipped', message: t('messages.fill.emptyResponse') });
|
|
669
|
-
}
|
|
670
|
-
else if (rawOptions.dryRun) {
|
|
671
|
-
ui.updateSpinner(t('spinner.planFill.dryRun'), 'info');
|
|
672
|
-
console.log(chalk_1.default.gray(`\n${t('messages.fill.previewStart')}`));
|
|
673
|
-
console.log(updatedContent.trim());
|
|
674
|
-
console.log(chalk_1.default.gray(`${t('messages.fill.previewEnd')}\n`));
|
|
675
|
-
results.push({ file: planRelativePath, status: 'skipped', message: 'dry-run' });
|
|
676
|
-
}
|
|
677
|
-
else {
|
|
678
|
-
await fs.writeFile(planPath, ensureTrailingNewline(updatedContent));
|
|
679
|
-
ui.updateSpinner(t('spinner.planFill.updated', { path: planRelativePath }), 'success');
|
|
680
|
-
results.push({ file: planRelativePath, status: 'updated' });
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
|
-
catch (error) {
|
|
684
|
-
ui.updateSpinner(t('spinner.planFill.failed'), 'fail');
|
|
685
|
-
results.push({
|
|
686
|
-
file: planRelativePath,
|
|
687
|
-
status: 'failed',
|
|
688
|
-
message: error instanceof Error ? error.message : String(error)
|
|
689
|
-
});
|
|
690
|
-
}
|
|
691
|
-
finally {
|
|
692
|
-
ui.stopSpinner();
|
|
693
|
-
}
|
|
694
|
-
ui.displayStep(3, 3, t('steps.plan.summaryResults'));
|
|
695
|
-
printLlmSummary(llmClient.getUsageStats(), results, Boolean(rawOptions.dryRun));
|
|
696
|
-
ui.displaySuccess(t('success.plan.filled'));
|
|
697
|
-
}
|
|
698
|
-
async function ensureDirectoryExists(dir, message) {
|
|
699
|
-
const exists = await fs.pathExists(dir);
|
|
700
|
-
if (!exists) {
|
|
701
|
-
throw new Error(message);
|
|
702
|
-
}
|
|
703
|
-
}
|
|
704
|
-
async function collectTargets(docsDir, agentsDir, processAll, limit, docAllowlist, agentAllowlist) {
|
|
705
|
-
const docFiles = await (0, glob_1.glob)('**/*.md', { cwd: docsDir, absolute: true });
|
|
706
|
-
const agentFiles = await (0, glob_1.glob)('**/*.md', { cwd: agentsDir, absolute: true });
|
|
707
|
-
const candidates = [...docFiles, ...agentFiles];
|
|
708
|
-
const targets = [];
|
|
709
|
-
for (const fullPath of candidates) {
|
|
710
|
-
const content = await fs.readFile(fullPath, 'utf-8');
|
|
711
|
-
const hasMarkers = /<!--\s*ai-task:/.test(content) || /<!--\s*ai-slot:/.test(content) || /TODO/.test(content);
|
|
712
|
-
const isAgent = fullPath.includes(`${path.sep}agents${path.sep}`);
|
|
713
|
-
const fileName = path.basename(fullPath);
|
|
714
|
-
if (isAgent) {
|
|
715
|
-
if (agentAllowlist && !agentAllowlist.has(fileName)) {
|
|
716
|
-
continue;
|
|
717
|
-
}
|
|
718
|
-
}
|
|
719
|
-
else {
|
|
720
|
-
if (docAllowlist && !docAllowlist.has(fileName)) {
|
|
721
|
-
continue;
|
|
722
|
-
}
|
|
723
|
-
}
|
|
724
|
-
const explicitSelection = isAgent ? !!agentAllowlist : !!docAllowlist;
|
|
725
|
-
const shouldInclude = processAll ||
|
|
726
|
-
hasMarkers ||
|
|
727
|
-
(explicitSelection && (isAgent ? agentAllowlist.has(fileName) : docAllowlist.has(fileName)));
|
|
728
|
-
if (!shouldInclude) {
|
|
729
|
-
continue;
|
|
730
|
-
}
|
|
731
|
-
targets.push({ fullPath, hasMarkers, isAgent });
|
|
732
|
-
if (limit && targets.length >= limit) {
|
|
733
|
-
break;
|
|
734
|
-
}
|
|
735
|
-
}
|
|
736
|
-
return targets;
|
|
737
|
-
}
|
|
738
|
-
function buildContextSummary(repoStructure) {
|
|
739
|
-
const directories = new Set();
|
|
740
|
-
repoStructure.directories.forEach(dir => {
|
|
741
|
-
const [first] = dir.relativePath.split(/[\\/]/).filter(Boolean);
|
|
742
|
-
if (first) {
|
|
743
|
-
directories.add(first);
|
|
744
|
-
}
|
|
745
|
-
});
|
|
746
|
-
const topDirs = Array.from(directories).sort().slice(0, 12);
|
|
747
|
-
const totalSizeMb = (repoStructure.totalSize / (1024 * 1024)).toFixed(2);
|
|
748
|
-
return [
|
|
749
|
-
`Top-level directories: ${topDirs.length ? topDirs.join(', ') : 'n/a'}`,
|
|
750
|
-
`Total files scanned: ${repoStructure.totalFiles}`,
|
|
751
|
-
`Repository size (approx.): ${totalSizeMb} MB`
|
|
752
|
-
].join('\n');
|
|
753
|
-
}
|
|
754
|
-
function buildUserPrompt(relativePath, currentContent, contextSummary, isAgent) {
|
|
755
|
-
const guidance = [
|
|
756
|
-
'- Preserve YAML front matter and existing `ai-task` sections.',
|
|
757
|
-
'- Replace TODOs and resolve `ai-slot` placeholders with concrete information.',
|
|
758
|
-
'- Ensure success criteria in the front matter are satisfied.',
|
|
759
|
-
'- Return only the full updated Markdown for this file.'
|
|
760
|
-
];
|
|
761
|
-
if (isAgent) {
|
|
762
|
-
guidance.push('- Keep agent responsibilities, best practices, and documentation touchpoints aligned with the latest docs.');
|
|
763
|
-
}
|
|
764
|
-
else {
|
|
765
|
-
guidance.push('- Maintain accurate cross-links between docs and referenced resources.');
|
|
766
|
-
}
|
|
767
|
-
return [
|
|
768
|
-
`Target file: ${relativePath}`,
|
|
769
|
-
'Repository summary:',
|
|
770
|
-
contextSummary,
|
|
771
|
-
'',
|
|
772
|
-
'Guidance:',
|
|
773
|
-
...guidance,
|
|
774
|
-
'',
|
|
775
|
-
'Current content:',
|
|
776
|
-
'<file>',
|
|
777
|
-
currentContent,
|
|
778
|
-
'</file>'
|
|
779
|
-
].join('\n');
|
|
780
|
-
}
|
|
781
|
-
function buildPlanUserPrompt(context) {
|
|
782
|
-
const guidance = [
|
|
783
|
-
'- Preserve the YAML front matter and `ai-task` wrapper already in the plan.',
|
|
784
|
-
'- Replace TODOs with concrete steps that align with the provided documentation and agent playbooks.',
|
|
785
|
-
'- Keep the Agent Lineup and Documentation Touchpoints tables accurate and sorted.',
|
|
786
|
-
'- Ensure the work is segmented into phases, each with numbered steps, named owners, deliverables, evidence expectations, and a concluding Git commit checkpoint.',
|
|
787
|
-
'- Return only the full updated Markdown for this plan.'
|
|
788
|
-
];
|
|
789
|
-
const sections = [
|
|
790
|
-
`Target file: ${context.relativePath}`,
|
|
791
|
-
'Repository summary:',
|
|
792
|
-
context.contextSummary,
|
|
793
|
-
'',
|
|
794
|
-
'Guidance:',
|
|
795
|
-
...guidance,
|
|
796
|
-
'',
|
|
797
|
-
'Current plan:',
|
|
798
|
-
'<plan>',
|
|
799
|
-
context.planContent,
|
|
800
|
-
'</plan>'
|
|
801
|
-
];
|
|
802
|
-
if (context.docsIndex) {
|
|
803
|
-
sections.push('', 'Documentation index (docs/README.md):', '<docs-index>', context.docsIndex, '</docs-index>');
|
|
804
|
-
}
|
|
805
|
-
if (context.agentsIndex) {
|
|
806
|
-
sections.push('', 'Agent handbook (agents/README.md):', '<agents-index>', context.agentsIndex, '</agents-index>');
|
|
807
|
-
}
|
|
808
|
-
context.docs.forEach(doc => {
|
|
809
|
-
sections.push('', `Referenced documentation (${doc.path}):`, '<doc>', doc.content, '</doc>');
|
|
810
|
-
});
|
|
811
|
-
context.agents.forEach(agent => {
|
|
812
|
-
sections.push('', `Referenced agent playbook (${agent.path}):`, '<agent>', agent.content, '</agent>');
|
|
813
|
-
});
|
|
814
|
-
return sections.join('\n');
|
|
815
|
-
}
|
|
816
|
-
function extractPlanReferences(content, type) {
|
|
817
|
-
const regex = type === 'docs'
|
|
818
|
-
? /\]\(\.\.\/docs\/([^)#]+)(?:#[^)]*)?\)/g
|
|
819
|
-
: /\]\(\.\.\/agents\/([^)#]+)(?:#[^)]*)?\)/g;
|
|
820
|
-
const references = [];
|
|
821
|
-
let match;
|
|
822
|
-
while ((match = regex.exec(content)) !== null) {
|
|
823
|
-
const rawPath = match[1].trim();
|
|
824
|
-
if (!rawPath)
|
|
825
|
-
continue;
|
|
826
|
-
const normalized = rawPath.replace(/^\.\//, '').replace(/#.*$/, '');
|
|
827
|
-
if (!normalized || normalized.includes('..'))
|
|
828
|
-
continue;
|
|
829
|
-
if (!references.includes(normalized)) {
|
|
830
|
-
references.push(normalized);
|
|
831
|
-
}
|
|
832
|
-
}
|
|
833
|
-
return references;
|
|
834
|
-
}
|
|
835
|
-
async function loadReferencedMarkdown(baseDir, fileNames) {
|
|
836
|
-
const results = [];
|
|
837
|
-
const seen = new Set();
|
|
838
|
-
for (const name of fileNames) {
|
|
839
|
-
const cleanName = name.replace(/#.*$/, '');
|
|
840
|
-
if (!cleanName || seen.has(cleanName)) {
|
|
841
|
-
continue;
|
|
842
|
-
}
|
|
843
|
-
const normalized = path.normalize(cleanName).replace(/^\.\//, '');
|
|
844
|
-
if (normalized.includes('..')) {
|
|
845
|
-
continue;
|
|
846
|
-
}
|
|
847
|
-
const fullPath = path.join(baseDir, normalized);
|
|
848
|
-
if (!(await fs.pathExists(fullPath))) {
|
|
849
|
-
continue;
|
|
850
|
-
}
|
|
851
|
-
const content = await fs.readFile(fullPath, 'utf-8');
|
|
852
|
-
results.push({ path: normalized, content });
|
|
853
|
-
seen.add(cleanName);
|
|
854
|
-
}
|
|
855
|
-
return results;
|
|
856
|
-
}
|
|
857
|
-
function ensureTrailingNewline(content) {
|
|
858
|
-
return content.endsWith('\n') ? content : `${content}\n`;
|
|
859
|
-
}
|
|
860
|
-
function printLlmSummary(usage, results, dryRun) {
|
|
861
|
-
const updated = results.filter(r => r.status === 'updated').length;
|
|
862
|
-
const skipped = results.filter(r => r.status === 'skipped').length;
|
|
863
|
-
const failed = results.filter(r => r.status === 'failed');
|
|
864
|
-
console.log('\n' + chalk_1.default.bold('📄 LLM Fill Summary'));
|
|
865
|
-
console.log(chalk_1.default.gray('─'.repeat(50)));
|
|
866
|
-
console.log(`${chalk_1.default.blue('Updated files:')} ${chalk_1.default.white(updated.toString())}`);
|
|
867
|
-
console.log(`${chalk_1.default.blue('Skipped files:')} ${chalk_1.default.white(skipped.toString())}${dryRun ? chalk_1.default.gray(' (dry run)') : ''}`);
|
|
868
|
-
console.log(`${chalk_1.default.blue('Failures:')} ${failed.length}`);
|
|
869
|
-
if (usage.totalCalls > 0) {
|
|
870
|
-
console.log(chalk_1.default.gray('─'.repeat(50)));
|
|
871
|
-
console.log(`${chalk_1.default.blue('LLM calls:')} ${usage.totalCalls}`);
|
|
872
|
-
console.log(`${chalk_1.default.blue('Prompt tokens:')} ${usage.totalPromptTokens}`);
|
|
873
|
-
console.log(`${chalk_1.default.blue('Completion tokens:')} ${usage.totalCompletionTokens}`);
|
|
874
|
-
console.log(`${chalk_1.default.blue('Estimated cost:')} ${usage.estimatedCost.toFixed(4)}`);
|
|
875
|
-
console.log(`${chalk_1.default.blue('Model:')} ${usage.model}`);
|
|
876
|
-
}
|
|
877
|
-
if (failed.length > 0) {
|
|
878
|
-
console.log(chalk_1.default.gray('─'.repeat(50)));
|
|
879
|
-
failed.forEach(f => {
|
|
880
|
-
console.log(`${chalk_1.default.red('✖')} ${chalk_1.default.white(f.file)} — ${chalk_1.default.gray(f.message || 'Unknown error')}`);
|
|
881
|
-
});
|
|
882
|
-
}
|
|
883
|
-
}
|
|
884
|
-
function parseDocSelection(input) {
|
|
885
|
-
if (input === undefined) {
|
|
886
|
-
return { selected: undefined, invalid: [], provided: false, explicitNone: false };
|
|
887
|
-
}
|
|
888
|
-
if (Array.isArray(input) && input.length === 0) {
|
|
889
|
-
return { selected: [], invalid: [], provided: true, explicitNone: true };
|
|
890
|
-
}
|
|
891
|
-
const values = toStringArray(input);
|
|
892
|
-
const normalized = values.map(value => value.toLowerCase().replace(/\.md$/, ''));
|
|
893
|
-
const valid = Array.from(new Set(normalized.filter(key => guideRegistry_1.DOCUMENT_GUIDE_KEYS.includes(key))));
|
|
894
|
-
const invalid = normalized.filter(key => !guideRegistry_1.DOCUMENT_GUIDE_KEYS.includes(key));
|
|
895
|
-
if (values.length > 0 && valid.length === 0 && invalid.length > 0) {
|
|
896
|
-
return { selected: undefined, invalid, provided: true, explicitNone: false };
|
|
897
|
-
}
|
|
898
|
-
return { selected: valid.length > 0 ? valid : undefined, invalid, provided: true, explicitNone: false };
|
|
899
|
-
}
|
|
900
|
-
function parseAgentSelection(input) {
|
|
901
|
-
if (input === undefined) {
|
|
902
|
-
return { selected: undefined, invalid: [], provided: false, explicitNone: false };
|
|
903
|
-
}
|
|
904
|
-
if (Array.isArray(input) && input.length === 0) {
|
|
905
|
-
return { selected: [], invalid: [], provided: true, explicitNone: true };
|
|
906
|
-
}
|
|
907
|
-
const values = toStringArray(input);
|
|
908
|
-
const normalized = values.map(value => value.toLowerCase().replace(/\.md$/, ''));
|
|
909
|
-
const allowed = new Set(agentTypes_1.AGENT_TYPES);
|
|
910
|
-
const valid = Array.from(new Set(normalized.filter(value => allowed.has(value))));
|
|
911
|
-
const invalid = normalized.filter(value => !allowed.has(value));
|
|
912
|
-
if (values.length > 0 && valid.length === 0 && invalid.length > 0) {
|
|
913
|
-
return { selected: undefined, invalid, provided: true, explicitNone: false };
|
|
914
|
-
}
|
|
915
|
-
return { selected: valid.length > 0 ? valid : undefined, invalid, provided: true, explicitNone: false };
|
|
916
|
-
}
|
|
917
|
-
function shouldGenerateDocs(resolvedType, selection) {
|
|
918
|
-
if (selection.explicitNone) {
|
|
919
|
-
return false;
|
|
920
|
-
}
|
|
921
|
-
if (resolvedType === 'agents') {
|
|
922
|
-
return false;
|
|
923
|
-
}
|
|
924
|
-
if (!selection.provided) {
|
|
925
|
-
return resolvedType === 'docs' || resolvedType === 'both';
|
|
926
|
-
}
|
|
927
|
-
if (selection.selected && selection.selected.length === 0) {
|
|
928
|
-
return false;
|
|
929
|
-
}
|
|
930
|
-
return resolvedType === 'docs' || resolvedType === 'both';
|
|
931
|
-
}
|
|
932
|
-
function shouldGenerateAgents(resolvedType, selection) {
|
|
933
|
-
if (selection.explicitNone) {
|
|
934
|
-
return false;
|
|
935
|
-
}
|
|
936
|
-
if (resolvedType === 'docs') {
|
|
937
|
-
return false;
|
|
938
|
-
}
|
|
939
|
-
if (!selection.provided) {
|
|
940
|
-
return resolvedType === 'agents' || resolvedType === 'both';
|
|
941
|
-
}
|
|
942
|
-
if (selection.selected && selection.selected.length === 0) {
|
|
943
|
-
return false;
|
|
944
|
-
}
|
|
945
|
-
return resolvedType === 'agents' || resolvedType === 'both';
|
|
946
|
-
}
|
|
947
|
-
function toStringArray(input) {
|
|
948
|
-
if (Array.isArray(input)) {
|
|
949
|
-
return input.map(item => item.toString().trim()).filter(Boolean);
|
|
950
|
-
}
|
|
951
|
-
if (input === null || input === undefined) {
|
|
952
|
-
return [];
|
|
953
|
-
}
|
|
954
|
-
return input
|
|
955
|
-
.toString()
|
|
956
|
-
.split(',')
|
|
957
|
-
.map((part) => part.trim())
|
|
958
|
-
.filter(Boolean);
|
|
959
|
-
}
|
|
960
|
-
function formatAgentLabel(value) {
|
|
961
|
-
return value
|
|
962
|
-
.split('-')
|
|
963
|
-
.map(segment => segment.charAt(0).toUpperCase() + segment.slice(1))
|
|
964
|
-
.join(' ');
|
|
239
|
+
await fillService.run(repoPath, rawOptions);
|
|
965
240
|
}
|
|
966
241
|
async function selectLocale(showWelcome) {
|
|
967
242
|
const { locale } = await inquirer_1.default.prompt([
|
|
@@ -1041,58 +316,19 @@ async function runInteractiveScaffold() {
|
|
|
1041
316
|
default: defaultOutput
|
|
1042
317
|
}
|
|
1043
318
|
]);
|
|
1044
|
-
const {
|
|
319
|
+
const { scaffoldType } = await inquirer_1.default.prompt([
|
|
1045
320
|
{
|
|
1046
|
-
type: '
|
|
1047
|
-
name: '
|
|
1048
|
-
message: t('prompts.scaffold.
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
{
|
|
1056
|
-
type: 'checkbox',
|
|
1057
|
-
name: 'docs',
|
|
1058
|
-
message: t('prompts.scaffold.selectDocs'),
|
|
1059
|
-
choices: DOC_CHOICES,
|
|
1060
|
-
default: DOC_CHOICES.map(choice => choice.value)
|
|
1061
|
-
}
|
|
1062
|
-
]);
|
|
1063
|
-
selectedDocs = docs;
|
|
1064
|
-
}
|
|
1065
|
-
else {
|
|
1066
|
-
selectedDocs = [];
|
|
1067
|
-
}
|
|
1068
|
-
const { includeAgents } = await inquirer_1.default.prompt([
|
|
1069
|
-
{
|
|
1070
|
-
type: 'confirm',
|
|
1071
|
-
name: 'includeAgents',
|
|
1072
|
-
message: t('prompts.scaffold.includeAgents'),
|
|
1073
|
-
default: true
|
|
321
|
+
type: 'list',
|
|
322
|
+
name: 'scaffoldType',
|
|
323
|
+
message: t('prompts.scaffold.type'),
|
|
324
|
+
choices: [
|
|
325
|
+
{ name: t('prompts.scaffold.typeBoth'), value: 'both' },
|
|
326
|
+
{ name: t('prompts.scaffold.typeDocs'), value: 'docs' },
|
|
327
|
+
{ name: t('prompts.scaffold.typeAgents'), value: 'agents' }
|
|
328
|
+
],
|
|
329
|
+
default: 'both'
|
|
1074
330
|
}
|
|
1075
331
|
]);
|
|
1076
|
-
let selectedAgents;
|
|
1077
|
-
if (includeAgents) {
|
|
1078
|
-
const { agents } = await inquirer_1.default.prompt([
|
|
1079
|
-
{
|
|
1080
|
-
type: 'checkbox',
|
|
1081
|
-
name: 'agents',
|
|
1082
|
-
message: t('prompts.scaffold.selectAgents'),
|
|
1083
|
-
choices: AGENT_CHOICES,
|
|
1084
|
-
default: AGENT_CHOICES.map(choice => choice.value)
|
|
1085
|
-
}
|
|
1086
|
-
]);
|
|
1087
|
-
selectedAgents = agents;
|
|
1088
|
-
}
|
|
1089
|
-
else {
|
|
1090
|
-
selectedAgents = [];
|
|
1091
|
-
}
|
|
1092
|
-
if ((selectedDocs?.length ?? 0) === 0 && (selectedAgents?.length ?? 0) === 0) {
|
|
1093
|
-
ui.displayWarning(t('warnings.interactive.nothingSelected'));
|
|
1094
|
-
return;
|
|
1095
|
-
}
|
|
1096
332
|
const { verbose } = await inquirer_1.default.prompt([
|
|
1097
333
|
{
|
|
1098
334
|
type: 'confirm',
|
|
@@ -1101,23 +337,11 @@ async function runInteractiveScaffold() {
|
|
|
1101
337
|
default: false
|
|
1102
338
|
}
|
|
1103
339
|
]);
|
|
1104
|
-
const scaffoldType = determineScaffoldType(selectedDocs, selectedAgents);
|
|
1105
340
|
await runInit(resolvedRepo, scaffoldType, {
|
|
1106
341
|
output: outputDir,
|
|
1107
|
-
docs: selectedDocs,
|
|
1108
|
-
agents: selectedAgents,
|
|
1109
342
|
verbose
|
|
1110
343
|
});
|
|
1111
344
|
}
|
|
1112
|
-
function determineScaffoldType(docSelection, agentSelection) {
|
|
1113
|
-
const docsSelected = docSelection === undefined ? true : docSelection.length > 0;
|
|
1114
|
-
const agentsSelected = agentSelection === undefined ? true : agentSelection.length > 0;
|
|
1115
|
-
if (docsSelected && agentsSelected)
|
|
1116
|
-
return 'both';
|
|
1117
|
-
if (docsSelected)
|
|
1118
|
-
return 'docs';
|
|
1119
|
-
return 'agents';
|
|
1120
|
-
}
|
|
1121
345
|
async function runInteractiveLlmFill() {
|
|
1122
346
|
const { repoPath } = await inquirer_1.default.prompt([
|
|
1123
347
|
{
|
|
@@ -1144,20 +368,6 @@ async function runInteractiveLlmFill() {
|
|
|
1144
368
|
}
|
|
1145
369
|
]);
|
|
1146
370
|
const promptPath = promptPathInput.trim() ? path.resolve(promptPathInput.trim()) : undefined;
|
|
1147
|
-
const { dryRun, processAll } = await inquirer_1.default.prompt([
|
|
1148
|
-
{
|
|
1149
|
-
type: 'confirm',
|
|
1150
|
-
name: 'dryRun',
|
|
1151
|
-
message: t('prompts.fill.dryRun'),
|
|
1152
|
-
default: true
|
|
1153
|
-
},
|
|
1154
|
-
{
|
|
1155
|
-
type: 'confirm',
|
|
1156
|
-
name: 'processAll',
|
|
1157
|
-
message: t('prompts.fill.processAll'),
|
|
1158
|
-
default: false
|
|
1159
|
-
}
|
|
1160
|
-
]);
|
|
1161
371
|
const { limit } = await inquirer_1.default.prompt([
|
|
1162
372
|
{
|
|
1163
373
|
type: 'input',
|
|
@@ -1168,58 +378,6 @@ async function runInteractiveLlmFill() {
|
|
|
1168
378
|
]);
|
|
1169
379
|
const limitValue = limit ? parseInt(limit, 10) : undefined;
|
|
1170
380
|
const parsedLimit = Number.isNaN(limitValue) ? undefined : limitValue;
|
|
1171
|
-
const { includeDocs } = await inquirer_1.default.prompt([
|
|
1172
|
-
{
|
|
1173
|
-
type: 'confirm',
|
|
1174
|
-
name: 'includeDocs',
|
|
1175
|
-
message: t('prompts.fill.includeDocs'),
|
|
1176
|
-
default: true
|
|
1177
|
-
}
|
|
1178
|
-
]);
|
|
1179
|
-
let selectedDocs;
|
|
1180
|
-
if (includeDocs) {
|
|
1181
|
-
const { docs } = await inquirer_1.default.prompt([
|
|
1182
|
-
{
|
|
1183
|
-
type: 'checkbox',
|
|
1184
|
-
name: 'docs',
|
|
1185
|
-
message: t('prompts.fill.selectDocs'),
|
|
1186
|
-
choices: DOC_CHOICES,
|
|
1187
|
-
default: DOC_CHOICES.map(choice => choice.value)
|
|
1188
|
-
}
|
|
1189
|
-
]);
|
|
1190
|
-
selectedDocs = docs;
|
|
1191
|
-
}
|
|
1192
|
-
else {
|
|
1193
|
-
selectedDocs = [];
|
|
1194
|
-
}
|
|
1195
|
-
const { includeAgents } = await inquirer_1.default.prompt([
|
|
1196
|
-
{
|
|
1197
|
-
type: 'confirm',
|
|
1198
|
-
name: 'includeAgents',
|
|
1199
|
-
message: t('prompts.fill.includeAgents'),
|
|
1200
|
-
default: true
|
|
1201
|
-
}
|
|
1202
|
-
]);
|
|
1203
|
-
let selectedAgents;
|
|
1204
|
-
if (includeAgents) {
|
|
1205
|
-
const { agents } = await inquirer_1.default.prompt([
|
|
1206
|
-
{
|
|
1207
|
-
type: 'checkbox',
|
|
1208
|
-
name: 'agents',
|
|
1209
|
-
message: t('prompts.fill.selectAgents'),
|
|
1210
|
-
choices: AGENT_CHOICES,
|
|
1211
|
-
default: AGENT_CHOICES.map(choice => choice.value)
|
|
1212
|
-
}
|
|
1213
|
-
]);
|
|
1214
|
-
selectedAgents = agents;
|
|
1215
|
-
}
|
|
1216
|
-
else {
|
|
1217
|
-
selectedAgents = [];
|
|
1218
|
-
}
|
|
1219
|
-
if ((selectedDocs?.length ?? 0) === 0 && (selectedAgents?.length ?? 0) === 0) {
|
|
1220
|
-
ui.displayWarning(t('warnings.interactive.nothingSelected'));
|
|
1221
|
-
return;
|
|
1222
|
-
}
|
|
1223
381
|
const { specifyModel } = await inquirer_1.default.prompt([
|
|
1224
382
|
{
|
|
1225
383
|
type: 'confirm',
|
|
@@ -1231,15 +389,6 @@ async function runInteractiveLlmFill() {
|
|
|
1231
389
|
let provider;
|
|
1232
390
|
let model;
|
|
1233
391
|
if (specifyModel) {
|
|
1234
|
-
const providerAnswer = await inquirer_1.default.prompt([
|
|
1235
|
-
{
|
|
1236
|
-
type: 'list',
|
|
1237
|
-
name: 'provider',
|
|
1238
|
-
message: t('prompts.fill.provider'),
|
|
1239
|
-
choices: ['openrouter', 'openai', 'anthropic', 'gemini', 'grok']
|
|
1240
|
-
}
|
|
1241
|
-
]);
|
|
1242
|
-
provider = providerAnswer.provider;
|
|
1243
392
|
const modelAnswer = await inquirer_1.default.prompt([
|
|
1244
393
|
{
|
|
1245
394
|
type: 'input',
|
|
@@ -1249,6 +398,7 @@ async function runInteractiveLlmFill() {
|
|
|
1249
398
|
}
|
|
1250
399
|
]);
|
|
1251
400
|
model = modelAnswer.model.trim();
|
|
401
|
+
provider = 'openrouter';
|
|
1252
402
|
}
|
|
1253
403
|
const { provideApiKey } = await inquirer_1.default.prompt([
|
|
1254
404
|
{
|
|
@@ -1278,13 +428,9 @@ async function runInteractiveLlmFill() {
|
|
|
1278
428
|
default: false
|
|
1279
429
|
}
|
|
1280
430
|
]);
|
|
1281
|
-
await
|
|
431
|
+
await fillService.run(resolvedRepo, {
|
|
1282
432
|
output: outputDir,
|
|
1283
433
|
prompt: promptPath,
|
|
1284
|
-
docs: selectedDocs,
|
|
1285
|
-
agents: selectedAgents,
|
|
1286
|
-
dryRun,
|
|
1287
|
-
all: processAll,
|
|
1288
434
|
limit: parsedLimit,
|
|
1289
435
|
model,
|
|
1290
436
|
provider,
|
|
@@ -1331,50 +477,6 @@ async function runInteractivePlan() {
|
|
|
1331
477
|
filter: (value) => value.trim()
|
|
1332
478
|
}
|
|
1333
479
|
]);
|
|
1334
|
-
const { includeAgents } = await inquirer_1.default.prompt([
|
|
1335
|
-
{
|
|
1336
|
-
type: 'confirm',
|
|
1337
|
-
name: 'includeAgents',
|
|
1338
|
-
message: t('prompts.plan.includeAgents'),
|
|
1339
|
-
default: true
|
|
1340
|
-
}
|
|
1341
|
-
]);
|
|
1342
|
-
let selectedAgents = [];
|
|
1343
|
-
if (includeAgents) {
|
|
1344
|
-
const { agents } = await inquirer_1.default.prompt([
|
|
1345
|
-
{
|
|
1346
|
-
type: 'checkbox',
|
|
1347
|
-
name: 'agents',
|
|
1348
|
-
message: t('prompts.plan.selectAgents'),
|
|
1349
|
-
choices: AGENT_CHOICES,
|
|
1350
|
-
default: AGENT_CHOICES.map(choice => choice.value)
|
|
1351
|
-
}
|
|
1352
|
-
]);
|
|
1353
|
-
selectedAgents = agents;
|
|
1354
|
-
}
|
|
1355
|
-
const { includeDocs } = await inquirer_1.default.prompt([
|
|
1356
|
-
{
|
|
1357
|
-
type: 'confirm',
|
|
1358
|
-
name: 'includeDocs',
|
|
1359
|
-
message: t('prompts.plan.includeDocs'),
|
|
1360
|
-
default: true
|
|
1361
|
-
}
|
|
1362
|
-
]);
|
|
1363
|
-
let selectedDocs = [];
|
|
1364
|
-
if (includeDocs) {
|
|
1365
|
-
const { docs } = await inquirer_1.default.prompt([
|
|
1366
|
-
{
|
|
1367
|
-
type: 'checkbox',
|
|
1368
|
-
name: 'docs',
|
|
1369
|
-
message: t('prompts.plan.selectDocs'),
|
|
1370
|
-
choices: DOC_CHOICES,
|
|
1371
|
-
default: DOC_CHOICES.map(choice => choice.value)
|
|
1372
|
-
}
|
|
1373
|
-
]);
|
|
1374
|
-
selectedDocs = docs;
|
|
1375
|
-
}
|
|
1376
|
-
const agentSelection = parseAgentSelection(selectedAgents);
|
|
1377
|
-
const docSelection = parseDocSelection(selectedDocs);
|
|
1378
480
|
const { repoPath } = await inquirer_1.default.prompt([
|
|
1379
481
|
{
|
|
1380
482
|
type: 'input',
|
|
@@ -1393,12 +495,10 @@ async function runInteractivePlan() {
|
|
|
1393
495
|
]);
|
|
1394
496
|
try {
|
|
1395
497
|
const resolvedOutput = path.resolve(outputDir.trim() || defaultOutput);
|
|
1396
|
-
await scaffoldPlanIfNeeded(planName, resolvedOutput, {
|
|
1397
|
-
summary: summary || undefined
|
|
1398
|
-
agentSelection,
|
|
1399
|
-
docSelection
|
|
498
|
+
await planService.scaffoldPlanIfNeeded(planName, resolvedOutput, {
|
|
499
|
+
summary: summary || undefined
|
|
1400
500
|
});
|
|
1401
|
-
await
|
|
501
|
+
await planService.fillPlan(planName, {
|
|
1402
502
|
output: resolvedOutput,
|
|
1403
503
|
repo: repoPath,
|
|
1404
504
|
dryRun
|
|
@@ -1417,48 +517,6 @@ async function runInteractivePlan() {
|
|
|
1417
517
|
filter: (value) => value.trim()
|
|
1418
518
|
}
|
|
1419
519
|
]);
|
|
1420
|
-
const { includeAgents } = await inquirer_1.default.prompt([
|
|
1421
|
-
{
|
|
1422
|
-
type: 'confirm',
|
|
1423
|
-
name: 'includeAgents',
|
|
1424
|
-
message: t('prompts.plan.includeAgents'),
|
|
1425
|
-
default: true
|
|
1426
|
-
}
|
|
1427
|
-
]);
|
|
1428
|
-
let selectedAgents = null;
|
|
1429
|
-
if (includeAgents) {
|
|
1430
|
-
const { agents } = await inquirer_1.default.prompt([
|
|
1431
|
-
{
|
|
1432
|
-
type: 'checkbox',
|
|
1433
|
-
name: 'agents',
|
|
1434
|
-
message: t('prompts.plan.selectAgents'),
|
|
1435
|
-
choices: AGENT_CHOICES,
|
|
1436
|
-
default: AGENT_CHOICES.map(choice => choice.value)
|
|
1437
|
-
}
|
|
1438
|
-
]);
|
|
1439
|
-
selectedAgents = agents.length > 0 ? agents : null;
|
|
1440
|
-
}
|
|
1441
|
-
const { includeDocs } = await inquirer_1.default.prompt([
|
|
1442
|
-
{
|
|
1443
|
-
type: 'confirm',
|
|
1444
|
-
name: 'includeDocs',
|
|
1445
|
-
message: t('prompts.plan.includeDocs'),
|
|
1446
|
-
default: true
|
|
1447
|
-
}
|
|
1448
|
-
]);
|
|
1449
|
-
let selectedDocs = null;
|
|
1450
|
-
if (includeDocs) {
|
|
1451
|
-
const { docs } = await inquirer_1.default.prompt([
|
|
1452
|
-
{
|
|
1453
|
-
type: 'checkbox',
|
|
1454
|
-
name: 'docs',
|
|
1455
|
-
message: t('prompts.plan.selectDocs'),
|
|
1456
|
-
choices: DOC_CHOICES,
|
|
1457
|
-
default: DOC_CHOICES.map(choice => choice.value)
|
|
1458
|
-
}
|
|
1459
|
-
]);
|
|
1460
|
-
selectedDocs = docs.length > 0 ? docs : null;
|
|
1461
|
-
}
|
|
1462
520
|
const generator = new planGenerator_1.PlanGenerator();
|
|
1463
521
|
ui.startSpinner(t('spinner.plan.creating'));
|
|
1464
522
|
try {
|
|
@@ -1466,8 +524,6 @@ async function runInteractivePlan() {
|
|
|
1466
524
|
planName,
|
|
1467
525
|
outputDir: path.resolve(outputDir.trim() || defaultOutput),
|
|
1468
526
|
summary: summary || undefined,
|
|
1469
|
-
selectedAgentTypes: selectedAgents,
|
|
1470
|
-
selectedDocKeys: selectedDocs,
|
|
1471
527
|
verbose: false
|
|
1472
528
|
});
|
|
1473
529
|
ui.updateSpinner(t('spinner.plan.created'), 'success');
|
|
@@ -1481,16 +537,6 @@ async function runInteractivePlan() {
|
|
|
1481
537
|
ui.stopSpinner();
|
|
1482
538
|
}
|
|
1483
539
|
}
|
|
1484
|
-
function getAgentFilesByTypes(types) {
|
|
1485
|
-
if (!types || types.length === 0) {
|
|
1486
|
-
return undefined;
|
|
1487
|
-
}
|
|
1488
|
-
const allowed = new Set(agentTypes_1.AGENT_TYPES);
|
|
1489
|
-
const files = types
|
|
1490
|
-
.filter(type => allowed.has(type))
|
|
1491
|
-
.map(type => `${type}.md`);
|
|
1492
|
-
return files.length ? new Set(files) : undefined;
|
|
1493
|
-
}
|
|
1494
540
|
function filterOutLocaleArgs(args) {
|
|
1495
541
|
const filtered = [];
|
|
1496
542
|
for (let index = 0; index < args.length; index += 1) {
|