@ai-coders/context 0.3.0 → 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 +32 -25
- package/dist/commands/shared/agents.d.ts +2 -0
- package/dist/commands/shared/agents.d.ts.map +1 -0
- package/dist/commands/shared/agents.js +15 -0
- package/dist/commands/shared/agents.js.map +1 -0
- package/dist/commands/shared/selection.d.ts +12 -0
- package/dist/commands/shared/selection.d.ts.map +1 -0
- package/dist/commands/shared/selection.js +95 -0
- package/dist/commands/shared/selection.js.map +1 -0
- 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 +96 -13
- 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 +111 -1007
- package/dist/index.js.map +1 -1
- package/dist/prompts/defaults.d.ts +3 -0
- package/dist/prompts/defaults.d.ts.map +1 -0
- package/dist/prompts/defaults.js +95 -0
- package/dist/prompts/defaults.js.map +1 -0
- 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 +46 -0
- package/dist/services/fill/fillService.d.ts.map +1 -0
- package/dist/services/fill/fillService.js +254 -0
- package/dist/services/fill/fillService.js.map +1 -0
- package/dist/services/init/initService.d.ts +37 -0
- package/dist/services/init/initService.d.ts.map +1 -0
- package/dist/services/init/initService.js +167 -0
- package/dist/services/init/initService.js.map +1 -0
- 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 +57 -0
- package/dist/services/plan/planService.d.ts.map +1 -0
- package/dist/services/plan/planService.js +334 -0
- package/dist/services/plan/planService.js.map +1 -0
- package/dist/services/shared/llmConfig.d.ts +22 -0
- package/dist/services/shared/llmConfig.d.ts.map +1 -0
- package/dist/services/shared/llmConfig.js +38 -0
- package/dist/services/shared/llmConfig.js.map +1 -0
- 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 +23 -33
- package/dist/utils/i18n.d.ts.map +1 -1
- package/dist/utils/i18n.js +48 -68
- package/dist/utils/i18n.js.map +1 -1
- package/dist/utils/promptLoader.d.ts +12 -0
- package/dist/utils/promptLoader.d.ts.map +1 -0
- package/dist/utils/promptLoader.js +81 -0
- package/dist/utils/promptLoader.js.map +1 -0
- package/dist/utils/versionChecker.d.ts +15 -0
- package/dist/utils/versionChecker.d.ts.map +1 -0
- package/dist/utils/versionChecker.js +49 -0
- package/dist/utils/versionChecker.js.map +1 -0
- package/package.json +9 -10
- 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,29 +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");
|
|
54
|
+
const versionChecker_1 = require("./utils/versionChecker");
|
|
59
55
|
const i18n_1 = require("./utils/i18n");
|
|
60
|
-
const
|
|
61
|
-
const
|
|
62
|
-
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");
|
|
63
59
|
dotenv.config();
|
|
64
60
|
const initialLocale = (0, i18n_1.detectLocale)(process.argv.slice(2), process.env.AI_CONTEXT_LANG);
|
|
65
61
|
let currentLocale = initialLocale;
|
|
@@ -71,55 +67,59 @@ const localeLabelKeys = {
|
|
|
71
67
|
};
|
|
72
68
|
const program = new commander_1.Command();
|
|
73
69
|
const ui = new cliUI_1.CLIInterface(t);
|
|
74
|
-
const VERSION = '0.
|
|
75
|
-
const
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
70
|
+
const VERSION = '0.4.0';
|
|
71
|
+
const PACKAGE_NAME = '@ai-coders/context';
|
|
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
|
+
});
|
|
84
90
|
program
|
|
85
91
|
.name('ai-context')
|
|
86
92
|
.description(t('cli.description'))
|
|
87
93
|
.version(VERSION);
|
|
88
94
|
program.option('-l, --lang <locale>', t('global.options.lang'), initialLocale);
|
|
95
|
+
let versionCheckPromise = null;
|
|
96
|
+
function scheduleVersionCheck(force = false) {
|
|
97
|
+
if (!versionCheckPromise || force) {
|
|
98
|
+
versionCheckPromise = (0, versionChecker_1.checkForUpdates)({
|
|
99
|
+
packageName: PACKAGE_NAME,
|
|
100
|
+
currentVersion: VERSION,
|
|
101
|
+
ui,
|
|
102
|
+
t,
|
|
103
|
+
force
|
|
104
|
+
}).catch(() => { });
|
|
105
|
+
}
|
|
106
|
+
return versionCheckPromise;
|
|
107
|
+
}
|
|
108
|
+
program.hook('preAction', () => {
|
|
109
|
+
void scheduleVersionCheck();
|
|
110
|
+
});
|
|
89
111
|
program
|
|
90
112
|
.command('init')
|
|
91
113
|
.description(t('commands.init.description'))
|
|
92
114
|
.argument('<repo-path>', t('commands.init.arguments.repoPath'))
|
|
93
115
|
.argument('[type]', t('commands.init.arguments.type'), 'both')
|
|
94
116
|
.option('-o, --output <dir>', t('commands.init.options.output'), './.context')
|
|
95
|
-
.option('--docs <keys...>', t('commands.init.options.docs'))
|
|
96
|
-
.option('--agents <keys...>', t('commands.init.options.agents'))
|
|
97
|
-
.option('--exclude <patterns...>', t('commands.init.options.exclude'))
|
|
98
|
-
.option('--include <patterns...>', t('commands.init.options.include'))
|
|
99
|
-
.option('-v, --verbose', t('commands.init.options.verbose'))
|
|
100
|
-
.action(async (repoPath, type, options) => {
|
|
101
|
-
try {
|
|
102
|
-
await runInit(repoPath, type, options);
|
|
103
|
-
}
|
|
104
|
-
catch (error) {
|
|
105
|
-
ui.displayError(t('errors.init.scaffoldFailed'), error);
|
|
106
|
-
process.exit(1);
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
program
|
|
110
|
-
.command('scaffold')
|
|
111
|
-
.description(t('commands.scaffold.description'))
|
|
112
|
-
.argument('<repo-path>', t('commands.init.arguments.repoPath'))
|
|
113
|
-
.argument('[type]', t('commands.init.arguments.type'), 'both')
|
|
114
|
-
.option('-o, --output <dir>', t('commands.init.options.output'), './.context')
|
|
115
|
-
.option('--docs <keys...>', t('commands.init.options.docs'))
|
|
116
|
-
.option('--agents <keys...>', t('commands.init.options.agents'))
|
|
117
117
|
.option('--exclude <patterns...>', t('commands.init.options.exclude'))
|
|
118
118
|
.option('--include <patterns...>', t('commands.init.options.include'))
|
|
119
119
|
.option('-v, --verbose', t('commands.init.options.verbose'))
|
|
120
120
|
.action(async (repoPath, type, options) => {
|
|
121
121
|
try {
|
|
122
|
-
await
|
|
122
|
+
await initService.run(repoPath, type, options);
|
|
123
123
|
}
|
|
124
124
|
catch (error) {
|
|
125
125
|
ui.displayError(t('errors.init.scaffoldFailed'), error);
|
|
@@ -135,18 +135,14 @@ program
|
|
|
135
135
|
.option('-m, --model <model>', t('commands.fill.options.model'), DEFAULT_MODEL)
|
|
136
136
|
.option('-p, --provider <provider>', t('commands.fill.options.provider'))
|
|
137
137
|
.option('--base-url <url>', t('commands.fill.options.baseUrl'))
|
|
138
|
-
.option('--prompt <file>', t('commands.fill.options.prompt')
|
|
139
|
-
.option('--dry-run', t('commands.fill.options.dryRun'), false)
|
|
140
|
-
.option('--all', t('commands.fill.options.all'), false)
|
|
138
|
+
.option('--prompt <file>', t('commands.fill.options.prompt'))
|
|
141
139
|
.option('--limit <number>', t('commands.fill.options.limit'), (value) => parseInt(value, 10))
|
|
142
|
-
.option('--docs <keys...>', t('commands.fill.options.docs'))
|
|
143
|
-
.option('--agents <keys...>', t('commands.fill.options.agents'))
|
|
144
140
|
.option('--exclude <patterns...>', t('commands.fill.options.exclude'))
|
|
145
141
|
.option('--include <patterns...>', t('commands.fill.options.include'))
|
|
146
142
|
.option('-v, --verbose', t('commands.fill.options.verbose'))
|
|
147
143
|
.action(async (repoPath, options) => {
|
|
148
144
|
try {
|
|
149
|
-
await
|
|
145
|
+
await fillService.run(repoPath, options);
|
|
150
146
|
}
|
|
151
147
|
catch (error) {
|
|
152
148
|
ui.displayError(t('errors.fill.failed'), error);
|
|
@@ -160,8 +156,6 @@ program
|
|
|
160
156
|
.option('-o, --output <dir>', t('commands.plan.options.output'), './.context')
|
|
161
157
|
.option('--title <title>', t('commands.plan.options.title'))
|
|
162
158
|
.option('--summary <text>', t('commands.plan.options.summary'))
|
|
163
|
-
.option('--agents <types...>', t('commands.plan.options.agents'))
|
|
164
|
-
.option('--docs <keys...>', t('commands.plan.options.docs'))
|
|
165
159
|
.option('-f, --force', t('commands.plan.options.force'))
|
|
166
160
|
.option('--fill', t('commands.plan.options.fill'))
|
|
167
161
|
.option('-r, --repo <path>', t('commands.plan.options.repo'))
|
|
@@ -169,32 +163,22 @@ program
|
|
|
169
163
|
.option('-m, --model <model>', t('commands.plan.options.model'), DEFAULT_MODEL)
|
|
170
164
|
.option('-p, --provider <provider>', t('commands.plan.options.provider'))
|
|
171
165
|
.option('--base-url <url>', t('commands.plan.options.baseUrl'))
|
|
172
|
-
.option('--prompt <file>', t('commands.plan.options.prompt')
|
|
166
|
+
.option('--prompt <file>', t('commands.plan.options.prompt'))
|
|
173
167
|
.option('--dry-run', t('commands.plan.options.dryRun'), false)
|
|
174
168
|
.option('--include <patterns...>', t('commands.plan.options.include'))
|
|
175
169
|
.option('--exclude <patterns...>', t('commands.plan.options.exclude'))
|
|
176
170
|
.option('-v, --verbose', t('commands.plan.options.verbose'))
|
|
177
171
|
.action(async (planName, rawOptions) => {
|
|
178
|
-
const agentSelection = parseAgentSelection(rawOptions.agents);
|
|
179
|
-
if (agentSelection.invalid.length > 0) {
|
|
180
|
-
ui.displayWarning(t('warnings.agents.unknown', { values: agentSelection.invalid.join(', ') }));
|
|
181
|
-
}
|
|
182
|
-
const docSelection = parseDocSelection(rawOptions.docs);
|
|
183
|
-
if (docSelection.invalid.length > 0) {
|
|
184
|
-
ui.displayWarning(t('warnings.docs.unknown', { values: docSelection.invalid.join(', ') }));
|
|
185
|
-
}
|
|
186
172
|
const outputDir = path.resolve(rawOptions.output || './.context');
|
|
187
173
|
if (rawOptions.fill) {
|
|
188
174
|
try {
|
|
189
|
-
await scaffoldPlanIfNeeded(planName, outputDir, {
|
|
175
|
+
await planService.scaffoldPlanIfNeeded(planName, outputDir, {
|
|
190
176
|
title: rawOptions.title,
|
|
191
177
|
summary: rawOptions.summary,
|
|
192
|
-
agentSelection,
|
|
193
|
-
docSelection,
|
|
194
178
|
force: Boolean(rawOptions.force),
|
|
195
179
|
verbose: Boolean(rawOptions.verbose)
|
|
196
180
|
});
|
|
197
|
-
await
|
|
181
|
+
await planService.fillPlan(planName, { ...rawOptions, output: outputDir });
|
|
198
182
|
}
|
|
199
183
|
catch (error) {
|
|
200
184
|
ui.displayError(t('errors.plan.fillFailed'), error);
|
|
@@ -210,8 +194,6 @@ program
|
|
|
210
194
|
outputDir,
|
|
211
195
|
title: rawOptions.title,
|
|
212
196
|
summary: rawOptions.summary,
|
|
213
|
-
selectedAgentTypes: agentSelection.explicitNone ? null : agentSelection.selected,
|
|
214
|
-
selectedDocKeys: docSelection.explicitNone ? null : docSelection.selected,
|
|
215
197
|
force: Boolean(rawOptions.force),
|
|
216
198
|
verbose: Boolean(rawOptions.verbose)
|
|
217
199
|
});
|
|
@@ -228,90 +210,15 @@ program
|
|
|
228
210
|
}
|
|
229
211
|
});
|
|
230
212
|
async function runInit(repoPath, type, rawOptions) {
|
|
231
|
-
|
|
232
|
-
const docSelection = parseDocSelection(rawOptions.docs);
|
|
233
|
-
const agentSelection = parseAgentSelection(rawOptions.agents);
|
|
234
|
-
if (docSelection.invalid.length > 0) {
|
|
235
|
-
ui.displayWarning(t('warnings.docs.unknown', { values: docSelection.invalid.join(', ') }));
|
|
236
|
-
}
|
|
237
|
-
if (agentSelection.invalid.length > 0) {
|
|
238
|
-
ui.displayWarning(t('warnings.agents.unknown', { values: agentSelection.invalid.join(', ') }));
|
|
239
|
-
}
|
|
240
|
-
const options = {
|
|
241
|
-
repoPath: path.resolve(repoPath),
|
|
242
|
-
outputDir: path.resolve(rawOptions.output || './.context'),
|
|
243
|
-
include: rawOptions.include,
|
|
244
|
-
exclude: rawOptions.exclude || [],
|
|
245
|
-
verbose: rawOptions.verbose || false,
|
|
246
|
-
scaffoldDocs: shouldGenerateDocs(resolvedType, docSelection),
|
|
247
|
-
scaffoldAgents: shouldGenerateAgents(resolvedType, agentSelection),
|
|
248
|
-
selectedDocKeys: docSelection.selected,
|
|
249
|
-
selectedAgentTypes: agentSelection.selected
|
|
250
|
-
};
|
|
251
|
-
if (!options.scaffoldDocs && !options.scaffoldAgents) {
|
|
252
|
-
ui.displayWarning(t('warnings.scaffold.noneSelected'));
|
|
253
|
-
return;
|
|
254
|
-
}
|
|
255
|
-
await ensurePaths(options);
|
|
256
|
-
ui.displayWelcome(VERSION);
|
|
257
|
-
ui.displayProjectInfo(options.repoPath, options.outputDir, resolvedType);
|
|
258
|
-
const fileMapper = new fileMapper_1.FileMapper(options.exclude);
|
|
259
|
-
ui.displayStep(1, 3, t('steps.init.analyze'));
|
|
260
|
-
ui.startSpinner(t('spinner.repo.scanning'));
|
|
261
|
-
const repoStructure = await fileMapper.mapRepository(options.repoPath, options.include);
|
|
262
|
-
ui.updateSpinner(t('spinner.repo.scanComplete', {
|
|
263
|
-
fileCount: repoStructure.totalFiles,
|
|
264
|
-
directoryCount: repoStructure.directories.length
|
|
265
|
-
}), 'success');
|
|
266
|
-
let docsGenerated = 0;
|
|
267
|
-
let agentsGenerated = 0;
|
|
268
|
-
const docGenerator = new documentationGenerator_1.DocumentationGenerator();
|
|
269
|
-
const agentGenerator = new agentGenerator_1.AgentGenerator();
|
|
270
|
-
if (options.scaffoldDocs) {
|
|
271
|
-
ui.displayStep(2, 3, t('steps.init.docs'));
|
|
272
|
-
ui.startSpinner(t('spinner.docs.creating'));
|
|
273
|
-
docsGenerated = await docGenerator.generateDocumentation(repoStructure, options.outputDir, { selectedDocs: options.selectedDocKeys }, options.verbose);
|
|
274
|
-
ui.updateSpinner(t('spinner.docs.created', { count: docsGenerated }), 'success');
|
|
275
|
-
}
|
|
276
|
-
if (options.scaffoldAgents) {
|
|
277
|
-
ui.displayStep(3, options.scaffoldDocs ? 3 : 2, t('steps.init.agents'));
|
|
278
|
-
ui.startSpinner(t('spinner.agents.creating'));
|
|
279
|
-
agentsGenerated = await agentGenerator.generateAgentPrompts(repoStructure, options.outputDir, options.selectedAgentTypes, options.verbose);
|
|
280
|
-
ui.updateSpinner(t('spinner.agents.created', { count: agentsGenerated }), 'success');
|
|
281
|
-
}
|
|
282
|
-
ui.displayGenerationSummary(docsGenerated, agentsGenerated);
|
|
283
|
-
ui.displaySuccess(t('success.scaffold.ready', { path: chalk_1.default.cyan(options.outputDir) }));
|
|
284
|
-
}
|
|
285
|
-
function resolveScaffoldType(type, rawOptions) {
|
|
286
|
-
const normalized = (type || 'both').toLowerCase();
|
|
287
|
-
const allowed = ['docs', 'agents', 'both'];
|
|
288
|
-
if (!allowed.includes(normalized)) {
|
|
289
|
-
throw new Error(t('errors.init.invalidType', { value: type, allowed: allowed.join(', ') }));
|
|
290
|
-
}
|
|
291
|
-
if (rawOptions.docsOnly) {
|
|
292
|
-
return 'docs';
|
|
293
|
-
}
|
|
294
|
-
if (rawOptions.agentsOnly) {
|
|
295
|
-
return 'agents';
|
|
296
|
-
}
|
|
297
|
-
return normalized;
|
|
298
|
-
}
|
|
299
|
-
async function ensurePaths(options) {
|
|
300
|
-
const exists = await fs.pathExists(options.repoPath);
|
|
301
|
-
if (!exists) {
|
|
302
|
-
throw new Error(t('errors.common.repoMissing', { path: options.repoPath }));
|
|
303
|
-
}
|
|
304
|
-
await fs.ensureDir(options.outputDir);
|
|
213
|
+
await initService.run(repoPath, type, rawOptions);
|
|
305
214
|
}
|
|
306
215
|
async function runGenerate(repoPath, options) {
|
|
307
216
|
const type = options?.docsOnly ? 'docs' : options?.agentsOnly ? 'agents' : (options?.type || 'both');
|
|
308
|
-
await
|
|
217
|
+
await initService.run(repoPath, type, {
|
|
309
218
|
output: options?.output ?? options?.outputDir ?? './.context',
|
|
310
219
|
include: options?.include,
|
|
311
220
|
exclude: options?.exclude,
|
|
312
221
|
verbose: options?.verbose,
|
|
313
|
-
docs: options?.docs,
|
|
314
|
-
agents: options?.agents,
|
|
315
222
|
docsOnly: options?.docsOnly,
|
|
316
223
|
agentsOnly: options?.agentsOnly
|
|
317
224
|
});
|
|
@@ -328,605 +235,10 @@ async function runPreview(..._args) {
|
|
|
328
235
|
async function runGuidelines(..._args) {
|
|
329
236
|
throw new Error(t('errors.commands.guidelinesRemoved'));
|
|
330
237
|
}
|
|
331
|
-
async function resolveLlmConfig(rawOptions, defaults) {
|
|
332
|
-
const promptPath = path.resolve(rawOptions.prompt || defaults.promptPath);
|
|
333
|
-
if (!(await fs.pathExists(promptPath))) {
|
|
334
|
-
throw new Error(t('errors.fill.promptMissing', { path: promptPath }));
|
|
335
|
-
}
|
|
336
|
-
const providerEnvMap = llmClientFactory_1.LLMClientFactory.getEnvironmentVariables();
|
|
337
|
-
const defaultModels = llmClientFactory_1.LLMClientFactory.getDefaultModels();
|
|
338
|
-
let provider = rawOptions.provider;
|
|
339
|
-
let model = rawOptions.model;
|
|
340
|
-
let apiKey = rawOptions.apiKey;
|
|
341
|
-
if (!apiKey) {
|
|
342
|
-
if (provider) {
|
|
343
|
-
for (const envVar of providerEnvMap[provider]) {
|
|
344
|
-
const value = process.env[envVar];
|
|
345
|
-
if (value) {
|
|
346
|
-
apiKey = value;
|
|
347
|
-
break;
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
else {
|
|
352
|
-
outer: for (const [prov, envVars] of Object.entries(providerEnvMap)) {
|
|
353
|
-
for (const envVar of envVars) {
|
|
354
|
-
const value = process.env[envVar];
|
|
355
|
-
if (value) {
|
|
356
|
-
apiKey = value;
|
|
357
|
-
provider = prov;
|
|
358
|
-
break outer;
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
if (!provider) {
|
|
365
|
-
if (model) {
|
|
366
|
-
provider = llmClientFactory_1.LLMClientFactory.detectProviderFromModel(model);
|
|
367
|
-
}
|
|
368
|
-
else if (apiKey) {
|
|
369
|
-
provider = llmClientFactory_1.LLMClientFactory.getProviderFromApiKey(apiKey);
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
if (!model) {
|
|
373
|
-
if (provider === 'openrouter' && process.env.OPENROUTER_MODEL) {
|
|
374
|
-
model = process.env.OPENROUTER_MODEL;
|
|
375
|
-
}
|
|
376
|
-
else if (provider && defaultModels[provider]?.length) {
|
|
377
|
-
model = defaultModels[provider][0];
|
|
378
|
-
}
|
|
379
|
-
else {
|
|
380
|
-
model = defaults.fallbackModel;
|
|
381
|
-
provider = llmClientFactory_1.LLMClientFactory.detectProviderFromModel(model);
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
if (!provider) {
|
|
385
|
-
provider = llmClientFactory_1.LLMClientFactory.detectProviderFromModel(model || defaults.fallbackModel);
|
|
386
|
-
}
|
|
387
|
-
if (!apiKey) {
|
|
388
|
-
for (const envVar of providerEnvMap[provider]) {
|
|
389
|
-
const value = process.env[envVar];
|
|
390
|
-
if (value) {
|
|
391
|
-
apiKey = value;
|
|
392
|
-
break;
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
if (!apiKey) {
|
|
397
|
-
const envVars = providerEnvMap[provider];
|
|
398
|
-
throw new Error(t('errors.fill.apiKeyMissing', {
|
|
399
|
-
provider: provider.toUpperCase(),
|
|
400
|
-
envVars: envVars.join(', ')
|
|
401
|
-
}));
|
|
402
|
-
}
|
|
403
|
-
return {
|
|
404
|
-
provider,
|
|
405
|
-
model: model || defaults.fallbackModel,
|
|
406
|
-
apiKey,
|
|
407
|
-
promptPath,
|
|
408
|
-
baseUrl: rawOptions.baseUrl
|
|
409
|
-
};
|
|
410
|
-
}
|
|
411
238
|
async function runLlmFill(repoPath, rawOptions) {
|
|
412
|
-
|
|
413
|
-
const outputDir = path.resolve(rawOptions.output || './.context');
|
|
414
|
-
const docsDir = path.join(outputDir, 'docs');
|
|
415
|
-
const agentsDir = path.join(outputDir, 'agents');
|
|
416
|
-
await ensureDirectoryExists(docsDir, t('errors.fill.missingDocsScaffold'));
|
|
417
|
-
await ensureDirectoryExists(agentsDir, t('errors.fill.missingAgentsScaffold'));
|
|
418
|
-
const docSelection = parseDocSelection(rawOptions.docs);
|
|
419
|
-
const agentSelection = parseAgentSelection(rawOptions.agents);
|
|
420
|
-
if (docSelection.invalid.length > 0) {
|
|
421
|
-
ui.displayWarning(t('warnings.docs.unknown', { values: docSelection.invalid.join(', ') }));
|
|
422
|
-
}
|
|
423
|
-
if (agentSelection.invalid.length > 0) {
|
|
424
|
-
ui.displayWarning(t('warnings.agents.unknown', { values: agentSelection.invalid.join(', ') }));
|
|
425
|
-
}
|
|
426
|
-
const { provider, model, apiKey, promptPath, baseUrl } = await resolveLlmConfig(rawOptions, {
|
|
427
|
-
promptPath: path.join(__dirname, '../prompts/update_scaffold_prompt.md'),
|
|
428
|
-
fallbackModel: DEFAULT_MODEL
|
|
429
|
-
});
|
|
430
|
-
const docAllowlist = docSelection.explicitNone
|
|
431
|
-
? new Set()
|
|
432
|
-
: (0, guideRegistry_1.getDocFilesByKeys)(docSelection.selected);
|
|
433
|
-
const agentAllowlist = agentSelection.explicitNone
|
|
434
|
-
? new Set()
|
|
435
|
-
: getAgentFilesByTypes(agentSelection.selected);
|
|
436
|
-
const options = {
|
|
437
|
-
repoPath: resolvedRepo,
|
|
438
|
-
outputDir,
|
|
439
|
-
promptPath,
|
|
440
|
-
provider,
|
|
441
|
-
model,
|
|
442
|
-
apiKey,
|
|
443
|
-
baseUrl,
|
|
444
|
-
include: rawOptions.include,
|
|
445
|
-
exclude: rawOptions.exclude,
|
|
446
|
-
verbose: rawOptions.verbose || false,
|
|
447
|
-
dryRun: rawOptions.dryRun || false,
|
|
448
|
-
processAll: rawOptions.all || false,
|
|
449
|
-
limit: rawOptions.limit,
|
|
450
|
-
selectedDocKeys: docSelection.selected,
|
|
451
|
-
selectedAgentTypes: agentSelection.selected,
|
|
452
|
-
selectedDocFiles: docAllowlist,
|
|
453
|
-
selectedAgentFiles: agentAllowlist
|
|
454
|
-
};
|
|
455
|
-
ui.displayWelcome(VERSION);
|
|
456
|
-
ui.displayProjectInfo(options.repoPath, options.outputDir, `fill:${options.provider}`);
|
|
457
|
-
const fileMapper = new fileMapper_1.FileMapper(options.exclude);
|
|
458
|
-
ui.displayStep(1, 3, t('steps.fill.analyze'));
|
|
459
|
-
ui.startSpinner(t('spinner.repo.scanning'));
|
|
460
|
-
const repoStructure = await fileMapper.mapRepository(options.repoPath, options.include);
|
|
461
|
-
ui.updateSpinner(t('spinner.repo.scanComplete', {
|
|
462
|
-
fileCount: repoStructure.totalFiles,
|
|
463
|
-
directoryCount: repoStructure.directories.length
|
|
464
|
-
}), 'success');
|
|
465
|
-
const systemPrompt = await fs.readFile(options.promptPath, 'utf-8');
|
|
466
|
-
const llmClient = llmClientFactory_1.LLMClientFactory.createClient({
|
|
467
|
-
apiKey: options.apiKey,
|
|
468
|
-
model: options.model,
|
|
469
|
-
provider: options.provider,
|
|
470
|
-
baseUrl: options.baseUrl
|
|
471
|
-
});
|
|
472
|
-
const targets = await collectTargets(docsDir, agentsDir, options.processAll, options.limit, options.selectedDocFiles, options.selectedAgentFiles);
|
|
473
|
-
if (targets.length === 0) {
|
|
474
|
-
ui.displayWarning(t('warnings.fill.noTargets'));
|
|
475
|
-
return;
|
|
476
|
-
}
|
|
477
|
-
const contextSummary = buildContextSummary(repoStructure);
|
|
478
|
-
const results = [];
|
|
479
|
-
ui.displayStep(2, 3, t('steps.fill.processFiles', { count: targets.length, model: options.model }));
|
|
480
|
-
for (const target of targets) {
|
|
481
|
-
const relativePath = path.relative(options.outputDir, target.fullPath);
|
|
482
|
-
ui.startSpinner(t('spinner.fill.processing', { path: relativePath }));
|
|
483
|
-
try {
|
|
484
|
-
const currentContent = await fs.readFile(target.fullPath, 'utf-8');
|
|
485
|
-
const userPrompt = buildUserPrompt(relativePath, currentContent, contextSummary, target.isAgent);
|
|
486
|
-
const updatedContent = await llmClient.generateText(userPrompt, systemPrompt);
|
|
487
|
-
if (!updatedContent || !updatedContent.trim()) {
|
|
488
|
-
ui.updateSpinner(t('spinner.fill.noContent', { path: relativePath }), 'warn');
|
|
489
|
-
results.push({ file: relativePath, status: 'skipped', message: t('messages.fill.emptyResponse') });
|
|
490
|
-
continue;
|
|
491
|
-
}
|
|
492
|
-
if (options.dryRun) {
|
|
493
|
-
ui.updateSpinner(t('spinner.fill.dryRunPreview', { path: relativePath }), 'info');
|
|
494
|
-
console.log(chalk_1.default.gray(`\n${t('messages.fill.previewStart')}`));
|
|
495
|
-
console.log(updatedContent.trim());
|
|
496
|
-
console.log(chalk_1.default.gray(`${t('messages.fill.previewEnd')}\n`));
|
|
497
|
-
}
|
|
498
|
-
else {
|
|
499
|
-
await fs.writeFile(target.fullPath, ensureTrailingNewline(updatedContent));
|
|
500
|
-
ui.updateSpinner(t('spinner.fill.updated', { path: relativePath }), 'success');
|
|
501
|
-
}
|
|
502
|
-
results.push({ file: relativePath, status: options.dryRun ? 'skipped' : 'updated' });
|
|
503
|
-
}
|
|
504
|
-
catch (error) {
|
|
505
|
-
ui.updateSpinner(t('spinner.fill.failed', { path: relativePath }), 'fail');
|
|
506
|
-
results.push({
|
|
507
|
-
file: relativePath,
|
|
508
|
-
status: 'failed',
|
|
509
|
-
message: error instanceof Error ? error.message : String(error)
|
|
510
|
-
});
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
ui.displayStep(3, 3, t('steps.fill.summary'));
|
|
514
|
-
printLlmSummary(llmClient.getUsageStats(), results, options.dryRun);
|
|
515
|
-
ui.displaySuccess(t('success.fill.completed'));
|
|
239
|
+
await fillService.run(repoPath, rawOptions);
|
|
516
240
|
}
|
|
517
|
-
async function
|
|
518
|
-
const resolvedOutput = path.resolve(outputDir);
|
|
519
|
-
const plansDir = path.join(resolvedOutput, 'plans');
|
|
520
|
-
const normalizedInput = planName.replace(/\.md$/i, '');
|
|
521
|
-
const slug = shared_1.GeneratorUtils.slugify(normalizedInput);
|
|
522
|
-
if (!slug) {
|
|
523
|
-
throw new Error(t('errors.plan.invalidName'));
|
|
524
|
-
}
|
|
525
|
-
const planPath = path.join(plansDir, `${slug}.md`);
|
|
526
|
-
const planExists = await fs.pathExists(planPath);
|
|
527
|
-
if (planExists && !options.force) {
|
|
528
|
-
return;
|
|
529
|
-
}
|
|
530
|
-
const generator = new planGenerator_1.PlanGenerator();
|
|
531
|
-
const result = await generator.generatePlan({
|
|
532
|
-
planName,
|
|
533
|
-
outputDir: resolvedOutput,
|
|
534
|
-
title: options.title,
|
|
535
|
-
summary: options.summary,
|
|
536
|
-
selectedAgentTypes: options.agentSelection
|
|
537
|
-
? options.agentSelection.explicitNone
|
|
538
|
-
? null
|
|
539
|
-
: options.agentSelection.selected
|
|
540
|
-
: undefined,
|
|
541
|
-
selectedDocKeys: options.docSelection
|
|
542
|
-
? options.docSelection.explicitNone
|
|
543
|
-
? null
|
|
544
|
-
: options.docSelection.selected
|
|
545
|
-
: undefined,
|
|
546
|
-
force: Boolean(options.force),
|
|
547
|
-
verbose: Boolean(options.verbose)
|
|
548
|
-
});
|
|
549
|
-
const relativePath = result.relativePath;
|
|
550
|
-
const message = planExists && options.force
|
|
551
|
-
? t('messages.plan.regenerated', { path: relativePath })
|
|
552
|
-
: t('messages.plan.created', { path: relativePath });
|
|
553
|
-
ui.displayInfo(t('info.plan.scaffolded.title'), message);
|
|
554
|
-
}
|
|
555
|
-
async function runPlanFill(planName, rawOptions) {
|
|
556
|
-
const outputDir = path.resolve(rawOptions.output || './.context');
|
|
557
|
-
const plansDir = path.join(outputDir, 'plans');
|
|
558
|
-
await ensureDirectoryExists(plansDir, t('errors.plan.missingPlansDir'));
|
|
559
|
-
const normalizedInput = planName.replace(/\.md$/i, '');
|
|
560
|
-
const slug = shared_1.GeneratorUtils.slugify(normalizedInput);
|
|
561
|
-
if (!slug) {
|
|
562
|
-
throw new Error(t('errors.plan.invalidName'));
|
|
563
|
-
}
|
|
564
|
-
const candidateFiles = new Set();
|
|
565
|
-
candidateFiles.add(path.join(plansDir, `${slug}.md`));
|
|
566
|
-
if (planName.toLowerCase().endsWith('.md')) {
|
|
567
|
-
candidateFiles.add(path.join(plansDir, planName));
|
|
568
|
-
}
|
|
569
|
-
let planPath;
|
|
570
|
-
for (const candidate of candidateFiles) {
|
|
571
|
-
if (await fs.pathExists(candidate)) {
|
|
572
|
-
planPath = candidate;
|
|
573
|
-
break;
|
|
574
|
-
}
|
|
575
|
-
}
|
|
576
|
-
if (!planPath) {
|
|
577
|
-
const expected = Array.from(candidateFiles).map(file => path.relative(process.cwd(), file)).join(' or ');
|
|
578
|
-
throw new Error(t('errors.plan.notFound', { expected }));
|
|
579
|
-
}
|
|
580
|
-
const docsDir = path.join(outputDir, 'docs');
|
|
581
|
-
const agentsDir = path.join(outputDir, 'agents');
|
|
582
|
-
await ensureDirectoryExists(docsDir, t('errors.fill.missingDocsScaffold'));
|
|
583
|
-
await ensureDirectoryExists(agentsDir, t('errors.fill.missingAgentsScaffold'));
|
|
584
|
-
const repoPath = path.resolve(rawOptions.repo || process.cwd());
|
|
585
|
-
if (!(await fs.pathExists(repoPath))) {
|
|
586
|
-
throw new Error(t('errors.common.repoMissing', { path: repoPath }));
|
|
587
|
-
}
|
|
588
|
-
const { provider, model, apiKey, promptPath, baseUrl } = await resolveLlmConfig(rawOptions, {
|
|
589
|
-
promptPath: path.join(__dirname, '../prompts/update_plan_prompt.md'),
|
|
590
|
-
fallbackModel: DEFAULT_MODEL
|
|
591
|
-
});
|
|
592
|
-
const planContent = await fs.readFile(planPath, 'utf-8');
|
|
593
|
-
const docsIndexPath = path.join(docsDir, 'README.md');
|
|
594
|
-
const agentsIndexPath = path.join(agentsDir, 'README.md');
|
|
595
|
-
const docsIndex = (await fs.pathExists(docsIndexPath)) ? await fs.readFile(docsIndexPath, 'utf-8') : undefined;
|
|
596
|
-
const agentsIndex = (await fs.pathExists(agentsIndexPath)) ? await fs.readFile(agentsIndexPath, 'utf-8') : undefined;
|
|
597
|
-
const referencedDocs = await loadReferencedMarkdown(docsDir, extractPlanReferences(planContent, 'docs'));
|
|
598
|
-
const referencedAgents = await loadReferencedMarkdown(agentsDir, extractPlanReferences(planContent, 'agents'));
|
|
599
|
-
ui.displayWelcome(VERSION);
|
|
600
|
-
ui.displayProjectInfo(repoPath, outputDir, `plan-fill:${provider}`);
|
|
601
|
-
const fileMapper = new fileMapper_1.FileMapper(rawOptions.exclude);
|
|
602
|
-
ui.displayStep(1, 3, t('steps.plan.summary'));
|
|
603
|
-
ui.startSpinner(t('spinner.planFill.analyzingRepo'));
|
|
604
|
-
const repoStructure = await fileMapper.mapRepository(repoPath, rawOptions.include);
|
|
605
|
-
const contextSummary = buildContextSummary(repoStructure);
|
|
606
|
-
ui.updateSpinner(t('spinner.planFill.summaryReady'), 'success');
|
|
607
|
-
const systemPrompt = await fs.readFile(promptPath, 'utf-8');
|
|
608
|
-
const llmClient = llmClientFactory_1.LLMClientFactory.createClient({
|
|
609
|
-
apiKey,
|
|
610
|
-
model,
|
|
611
|
-
provider,
|
|
612
|
-
baseUrl
|
|
613
|
-
});
|
|
614
|
-
const planRelativePath = path.relative(outputDir, planPath);
|
|
615
|
-
const results = [];
|
|
616
|
-
ui.displayStep(2, 3, t('steps.plan.update', { path: planRelativePath, model }));
|
|
617
|
-
ui.startSpinner(t('spinner.planFill.updating', { path: planRelativePath }));
|
|
618
|
-
try {
|
|
619
|
-
const userPrompt = buildPlanUserPrompt({
|
|
620
|
-
relativePath: planRelativePath,
|
|
621
|
-
planContent,
|
|
622
|
-
contextSummary,
|
|
623
|
-
docsIndex,
|
|
624
|
-
agentsIndex,
|
|
625
|
-
docs: referencedDocs,
|
|
626
|
-
agents: referencedAgents
|
|
627
|
-
});
|
|
628
|
-
const updatedContent = await llmClient.generateText(userPrompt, systemPrompt);
|
|
629
|
-
if (!updatedContent || !updatedContent.trim()) {
|
|
630
|
-
ui.updateSpinner(t('spinner.planFill.noContent'), 'warn');
|
|
631
|
-
results.push({ file: planRelativePath, status: 'skipped', message: t('messages.fill.emptyResponse') });
|
|
632
|
-
}
|
|
633
|
-
else if (rawOptions.dryRun) {
|
|
634
|
-
ui.updateSpinner(t('spinner.planFill.dryRun'), 'info');
|
|
635
|
-
console.log(chalk_1.default.gray(`\n${t('messages.fill.previewStart')}`));
|
|
636
|
-
console.log(updatedContent.trim());
|
|
637
|
-
console.log(chalk_1.default.gray(`${t('messages.fill.previewEnd')}\n`));
|
|
638
|
-
results.push({ file: planRelativePath, status: 'skipped', message: 'dry-run' });
|
|
639
|
-
}
|
|
640
|
-
else {
|
|
641
|
-
await fs.writeFile(planPath, ensureTrailingNewline(updatedContent));
|
|
642
|
-
ui.updateSpinner(t('spinner.planFill.updated', { path: planRelativePath }), 'success');
|
|
643
|
-
results.push({ file: planRelativePath, status: 'updated' });
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
catch (error) {
|
|
647
|
-
ui.updateSpinner(t('spinner.planFill.failed'), 'fail');
|
|
648
|
-
results.push({
|
|
649
|
-
file: planRelativePath,
|
|
650
|
-
status: 'failed',
|
|
651
|
-
message: error instanceof Error ? error.message : String(error)
|
|
652
|
-
});
|
|
653
|
-
}
|
|
654
|
-
finally {
|
|
655
|
-
ui.stopSpinner();
|
|
656
|
-
}
|
|
657
|
-
ui.displayStep(3, 3, t('steps.plan.summaryResults'));
|
|
658
|
-
printLlmSummary(llmClient.getUsageStats(), results, Boolean(rawOptions.dryRun));
|
|
659
|
-
ui.displaySuccess(t('success.plan.filled'));
|
|
660
|
-
}
|
|
661
|
-
async function ensureDirectoryExists(dir, message) {
|
|
662
|
-
const exists = await fs.pathExists(dir);
|
|
663
|
-
if (!exists) {
|
|
664
|
-
throw new Error(message);
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
async function collectTargets(docsDir, agentsDir, processAll, limit, docAllowlist, agentAllowlist) {
|
|
668
|
-
const docFiles = await (0, glob_1.glob)('**/*.md', { cwd: docsDir, absolute: true });
|
|
669
|
-
const agentFiles = await (0, glob_1.glob)('**/*.md', { cwd: agentsDir, absolute: true });
|
|
670
|
-
const candidates = [...docFiles, ...agentFiles];
|
|
671
|
-
const targets = [];
|
|
672
|
-
for (const fullPath of candidates) {
|
|
673
|
-
const content = await fs.readFile(fullPath, 'utf-8');
|
|
674
|
-
const hasMarkers = /<!--\s*ai-task:/.test(content) || /<!--\s*ai-slot:/.test(content) || /TODO/.test(content);
|
|
675
|
-
const isAgent = fullPath.includes(`${path.sep}agents${path.sep}`);
|
|
676
|
-
const fileName = path.basename(fullPath);
|
|
677
|
-
if (isAgent) {
|
|
678
|
-
if (agentAllowlist && !agentAllowlist.has(fileName)) {
|
|
679
|
-
continue;
|
|
680
|
-
}
|
|
681
|
-
}
|
|
682
|
-
else {
|
|
683
|
-
if (docAllowlist && !docAllowlist.has(fileName)) {
|
|
684
|
-
continue;
|
|
685
|
-
}
|
|
686
|
-
}
|
|
687
|
-
const explicitSelection = isAgent ? !!agentAllowlist : !!docAllowlist;
|
|
688
|
-
const shouldInclude = processAll ||
|
|
689
|
-
hasMarkers ||
|
|
690
|
-
(explicitSelection && (isAgent ? agentAllowlist.has(fileName) : docAllowlist.has(fileName)));
|
|
691
|
-
if (!shouldInclude) {
|
|
692
|
-
continue;
|
|
693
|
-
}
|
|
694
|
-
targets.push({ fullPath, hasMarkers, isAgent });
|
|
695
|
-
if (limit && targets.length >= limit) {
|
|
696
|
-
break;
|
|
697
|
-
}
|
|
698
|
-
}
|
|
699
|
-
return targets;
|
|
700
|
-
}
|
|
701
|
-
function buildContextSummary(repoStructure) {
|
|
702
|
-
const directories = new Set();
|
|
703
|
-
repoStructure.directories.forEach(dir => {
|
|
704
|
-
const [first] = dir.relativePath.split(/[\\/]/).filter(Boolean);
|
|
705
|
-
if (first) {
|
|
706
|
-
directories.add(first);
|
|
707
|
-
}
|
|
708
|
-
});
|
|
709
|
-
const topDirs = Array.from(directories).sort().slice(0, 12);
|
|
710
|
-
const totalSizeMb = (repoStructure.totalSize / (1024 * 1024)).toFixed(2);
|
|
711
|
-
return [
|
|
712
|
-
`Top-level directories: ${topDirs.length ? topDirs.join(', ') : 'n/a'}`,
|
|
713
|
-
`Total files scanned: ${repoStructure.totalFiles}`,
|
|
714
|
-
`Repository size (approx.): ${totalSizeMb} MB`
|
|
715
|
-
].join('\n');
|
|
716
|
-
}
|
|
717
|
-
function buildUserPrompt(relativePath, currentContent, contextSummary, isAgent) {
|
|
718
|
-
const guidance = [
|
|
719
|
-
'- Preserve YAML front matter and existing `ai-task` sections.',
|
|
720
|
-
'- Replace TODOs and resolve `ai-slot` placeholders with concrete information.',
|
|
721
|
-
'- Ensure success criteria in the front matter are satisfied.',
|
|
722
|
-
'- Return only the full updated Markdown for this file.'
|
|
723
|
-
];
|
|
724
|
-
if (isAgent) {
|
|
725
|
-
guidance.push('- Keep agent responsibilities, best practices, and documentation touchpoints aligned with the latest docs.');
|
|
726
|
-
}
|
|
727
|
-
else {
|
|
728
|
-
guidance.push('- Maintain accurate cross-links between docs and referenced resources.');
|
|
729
|
-
}
|
|
730
|
-
return [
|
|
731
|
-
`Target file: ${relativePath}`,
|
|
732
|
-
'Repository summary:',
|
|
733
|
-
contextSummary,
|
|
734
|
-
'',
|
|
735
|
-
'Guidance:',
|
|
736
|
-
...guidance,
|
|
737
|
-
'',
|
|
738
|
-
'Current content:',
|
|
739
|
-
'<file>',
|
|
740
|
-
currentContent,
|
|
741
|
-
'</file>'
|
|
742
|
-
].join('\n');
|
|
743
|
-
}
|
|
744
|
-
function buildPlanUserPrompt(context) {
|
|
745
|
-
const guidance = [
|
|
746
|
-
'- Preserve the YAML front matter and `ai-task` wrapper already in the plan.',
|
|
747
|
-
'- Replace TODOs with concrete steps that align with the provided documentation and agent playbooks.',
|
|
748
|
-
'- Keep the Agent Lineup and Documentation Touchpoints tables accurate and sorted.',
|
|
749
|
-
'- Ensure stages include owners, deliverables, and evidence expectations.',
|
|
750
|
-
'- Return only the full updated Markdown for this plan.'
|
|
751
|
-
];
|
|
752
|
-
const sections = [
|
|
753
|
-
`Target file: ${context.relativePath}`,
|
|
754
|
-
'Repository summary:',
|
|
755
|
-
context.contextSummary,
|
|
756
|
-
'',
|
|
757
|
-
'Guidance:',
|
|
758
|
-
...guidance,
|
|
759
|
-
'',
|
|
760
|
-
'Current plan:',
|
|
761
|
-
'<plan>',
|
|
762
|
-
context.planContent,
|
|
763
|
-
'</plan>'
|
|
764
|
-
];
|
|
765
|
-
if (context.docsIndex) {
|
|
766
|
-
sections.push('', 'Documentation index (docs/README.md):', '<docs-index>', context.docsIndex, '</docs-index>');
|
|
767
|
-
}
|
|
768
|
-
if (context.agentsIndex) {
|
|
769
|
-
sections.push('', 'Agent handbook (agents/README.md):', '<agents-index>', context.agentsIndex, '</agents-index>');
|
|
770
|
-
}
|
|
771
|
-
context.docs.forEach(doc => {
|
|
772
|
-
sections.push('', `Referenced documentation (${doc.path}):`, '<doc>', doc.content, '</doc>');
|
|
773
|
-
});
|
|
774
|
-
context.agents.forEach(agent => {
|
|
775
|
-
sections.push('', `Referenced agent playbook (${agent.path}):`, '<agent>', agent.content, '</agent>');
|
|
776
|
-
});
|
|
777
|
-
return sections.join('\n');
|
|
778
|
-
}
|
|
779
|
-
function extractPlanReferences(content, type) {
|
|
780
|
-
const regex = type === 'docs'
|
|
781
|
-
? /\]\(\.\.\/docs\/([^)#]+)(?:#[^)]*)?\)/g
|
|
782
|
-
: /\]\(\.\.\/agents\/([^)#]+)(?:#[^)]*)?\)/g;
|
|
783
|
-
const references = [];
|
|
784
|
-
let match;
|
|
785
|
-
while ((match = regex.exec(content)) !== null) {
|
|
786
|
-
const rawPath = match[1].trim();
|
|
787
|
-
if (!rawPath)
|
|
788
|
-
continue;
|
|
789
|
-
const normalized = rawPath.replace(/^\.\//, '').replace(/#.*$/, '');
|
|
790
|
-
if (!normalized || normalized.includes('..'))
|
|
791
|
-
continue;
|
|
792
|
-
if (!references.includes(normalized)) {
|
|
793
|
-
references.push(normalized);
|
|
794
|
-
}
|
|
795
|
-
}
|
|
796
|
-
return references;
|
|
797
|
-
}
|
|
798
|
-
async function loadReferencedMarkdown(baseDir, fileNames) {
|
|
799
|
-
const results = [];
|
|
800
|
-
const seen = new Set();
|
|
801
|
-
for (const name of fileNames) {
|
|
802
|
-
const cleanName = name.replace(/#.*$/, '');
|
|
803
|
-
if (!cleanName || seen.has(cleanName)) {
|
|
804
|
-
continue;
|
|
805
|
-
}
|
|
806
|
-
const normalized = path.normalize(cleanName).replace(/^\.\//, '');
|
|
807
|
-
if (normalized.includes('..')) {
|
|
808
|
-
continue;
|
|
809
|
-
}
|
|
810
|
-
const fullPath = path.join(baseDir, normalized);
|
|
811
|
-
if (!(await fs.pathExists(fullPath))) {
|
|
812
|
-
continue;
|
|
813
|
-
}
|
|
814
|
-
const content = await fs.readFile(fullPath, 'utf-8');
|
|
815
|
-
results.push({ path: normalized, content });
|
|
816
|
-
seen.add(cleanName);
|
|
817
|
-
}
|
|
818
|
-
return results;
|
|
819
|
-
}
|
|
820
|
-
function ensureTrailingNewline(content) {
|
|
821
|
-
return content.endsWith('\n') ? content : `${content}\n`;
|
|
822
|
-
}
|
|
823
|
-
function printLlmSummary(usage, results, dryRun) {
|
|
824
|
-
const updated = results.filter(r => r.status === 'updated').length;
|
|
825
|
-
const skipped = results.filter(r => r.status === 'skipped').length;
|
|
826
|
-
const failed = results.filter(r => r.status === 'failed');
|
|
827
|
-
console.log('\n' + chalk_1.default.bold('📄 LLM Fill Summary'));
|
|
828
|
-
console.log(chalk_1.default.gray('─'.repeat(50)));
|
|
829
|
-
console.log(`${chalk_1.default.blue('Updated files:')} ${chalk_1.default.white(updated.toString())}`);
|
|
830
|
-
console.log(`${chalk_1.default.blue('Skipped files:')} ${chalk_1.default.white(skipped.toString())}${dryRun ? chalk_1.default.gray(' (dry run)') : ''}`);
|
|
831
|
-
console.log(`${chalk_1.default.blue('Failures:')} ${failed.length}`);
|
|
832
|
-
if (usage.totalCalls > 0) {
|
|
833
|
-
console.log(chalk_1.default.gray('─'.repeat(50)));
|
|
834
|
-
console.log(`${chalk_1.default.blue('LLM calls:')} ${usage.totalCalls}`);
|
|
835
|
-
console.log(`${chalk_1.default.blue('Prompt tokens:')} ${usage.totalPromptTokens}`);
|
|
836
|
-
console.log(`${chalk_1.default.blue('Completion tokens:')} ${usage.totalCompletionTokens}`);
|
|
837
|
-
console.log(`${chalk_1.default.blue('Estimated cost:')} ${usage.estimatedCost.toFixed(4)}`);
|
|
838
|
-
console.log(`${chalk_1.default.blue('Model:')} ${usage.model}`);
|
|
839
|
-
}
|
|
840
|
-
if (failed.length > 0) {
|
|
841
|
-
console.log(chalk_1.default.gray('─'.repeat(50)));
|
|
842
|
-
failed.forEach(f => {
|
|
843
|
-
console.log(`${chalk_1.default.red('✖')} ${chalk_1.default.white(f.file)} — ${chalk_1.default.gray(f.message || 'Unknown error')}`);
|
|
844
|
-
});
|
|
845
|
-
}
|
|
846
|
-
}
|
|
847
|
-
function parseDocSelection(input) {
|
|
848
|
-
if (input === undefined) {
|
|
849
|
-
return { selected: undefined, invalid: [], provided: false, explicitNone: false };
|
|
850
|
-
}
|
|
851
|
-
if (Array.isArray(input) && input.length === 0) {
|
|
852
|
-
return { selected: [], invalid: [], provided: true, explicitNone: true };
|
|
853
|
-
}
|
|
854
|
-
const values = toStringArray(input);
|
|
855
|
-
const normalized = values.map(value => value.toLowerCase().replace(/\.md$/, ''));
|
|
856
|
-
const valid = Array.from(new Set(normalized.filter(key => guideRegistry_1.DOCUMENT_GUIDE_KEYS.includes(key))));
|
|
857
|
-
const invalid = normalized.filter(key => !guideRegistry_1.DOCUMENT_GUIDE_KEYS.includes(key));
|
|
858
|
-
if (values.length > 0 && valid.length === 0 && invalid.length > 0) {
|
|
859
|
-
return { selected: undefined, invalid, provided: true, explicitNone: false };
|
|
860
|
-
}
|
|
861
|
-
return { selected: valid.length > 0 ? valid : undefined, invalid, provided: true, explicitNone: false };
|
|
862
|
-
}
|
|
863
|
-
function parseAgentSelection(input) {
|
|
864
|
-
if (input === undefined) {
|
|
865
|
-
return { selected: undefined, invalid: [], provided: false, explicitNone: false };
|
|
866
|
-
}
|
|
867
|
-
if (Array.isArray(input) && input.length === 0) {
|
|
868
|
-
return { selected: [], invalid: [], provided: true, explicitNone: true };
|
|
869
|
-
}
|
|
870
|
-
const values = toStringArray(input);
|
|
871
|
-
const normalized = values.map(value => value.toLowerCase().replace(/\.md$/, ''));
|
|
872
|
-
const allowed = new Set(agentTypes_1.AGENT_TYPES);
|
|
873
|
-
const valid = Array.from(new Set(normalized.filter(value => allowed.has(value))));
|
|
874
|
-
const invalid = normalized.filter(value => !allowed.has(value));
|
|
875
|
-
if (values.length > 0 && valid.length === 0 && invalid.length > 0) {
|
|
876
|
-
return { selected: undefined, invalid, provided: true, explicitNone: false };
|
|
877
|
-
}
|
|
878
|
-
return { selected: valid.length > 0 ? valid : undefined, invalid, provided: true, explicitNone: false };
|
|
879
|
-
}
|
|
880
|
-
function shouldGenerateDocs(resolvedType, selection) {
|
|
881
|
-
if (selection.explicitNone) {
|
|
882
|
-
return false;
|
|
883
|
-
}
|
|
884
|
-
if (resolvedType === 'agents') {
|
|
885
|
-
return false;
|
|
886
|
-
}
|
|
887
|
-
if (!selection.provided) {
|
|
888
|
-
return resolvedType === 'docs' || resolvedType === 'both';
|
|
889
|
-
}
|
|
890
|
-
if (selection.selected && selection.selected.length === 0) {
|
|
891
|
-
return false;
|
|
892
|
-
}
|
|
893
|
-
return resolvedType === 'docs' || resolvedType === 'both';
|
|
894
|
-
}
|
|
895
|
-
function shouldGenerateAgents(resolvedType, selection) {
|
|
896
|
-
if (selection.explicitNone) {
|
|
897
|
-
return false;
|
|
898
|
-
}
|
|
899
|
-
if (resolvedType === 'docs') {
|
|
900
|
-
return false;
|
|
901
|
-
}
|
|
902
|
-
if (!selection.provided) {
|
|
903
|
-
return resolvedType === 'agents' || resolvedType === 'both';
|
|
904
|
-
}
|
|
905
|
-
if (selection.selected && selection.selected.length === 0) {
|
|
906
|
-
return false;
|
|
907
|
-
}
|
|
908
|
-
return resolvedType === 'agents' || resolvedType === 'both';
|
|
909
|
-
}
|
|
910
|
-
function toStringArray(input) {
|
|
911
|
-
if (Array.isArray(input)) {
|
|
912
|
-
return input.map(item => item.toString().trim()).filter(Boolean);
|
|
913
|
-
}
|
|
914
|
-
if (input === null || input === undefined) {
|
|
915
|
-
return [];
|
|
916
|
-
}
|
|
917
|
-
return input
|
|
918
|
-
.toString()
|
|
919
|
-
.split(',')
|
|
920
|
-
.map((part) => part.trim())
|
|
921
|
-
.filter(Boolean);
|
|
922
|
-
}
|
|
923
|
-
function formatAgentLabel(value) {
|
|
924
|
-
return value
|
|
925
|
-
.split('-')
|
|
926
|
-
.map(segment => segment.charAt(0).toUpperCase() + segment.slice(1))
|
|
927
|
-
.join(' ');
|
|
928
|
-
}
|
|
929
|
-
async function runInteractive() {
|
|
241
|
+
async function selectLocale(showWelcome) {
|
|
930
242
|
const { locale } = await inquirer_1.default.prompt([
|
|
931
243
|
{
|
|
932
244
|
type: 'list',
|
|
@@ -942,28 +254,48 @@ async function runInteractive() {
|
|
|
942
254
|
const normalizedLocale = (0, i18n_1.normalizeLocale)(locale);
|
|
943
255
|
currentLocale = normalizedLocale;
|
|
944
256
|
translateFn = (0, i18n_1.createTranslator)(normalizedLocale);
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
{
|
|
948
|
-
type: 'list',
|
|
949
|
-
name: 'action',
|
|
950
|
-
message: t('prompts.main.action'),
|
|
951
|
-
choices: [
|
|
952
|
-
{ name: t('prompts.main.choice.scaffold'), value: 'scaffold' },
|
|
953
|
-
{ name: t('prompts.main.choice.fill'), value: 'fill' },
|
|
954
|
-
{ name: t('prompts.main.choice.plan'), value: 'plan' }
|
|
955
|
-
]
|
|
956
|
-
}
|
|
957
|
-
]);
|
|
958
|
-
if (action === 'scaffold') {
|
|
959
|
-
await runInteractiveScaffold();
|
|
257
|
+
if (showWelcome) {
|
|
258
|
+
ui.displayWelcome(VERSION);
|
|
960
259
|
}
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
260
|
+
}
|
|
261
|
+
async function runInteractive() {
|
|
262
|
+
await selectLocale(true);
|
|
263
|
+
let exitRequested = false;
|
|
264
|
+
while (!exitRequested) {
|
|
265
|
+
const { action } = await inquirer_1.default.prompt([
|
|
266
|
+
{
|
|
267
|
+
type: 'list',
|
|
268
|
+
name: 'action',
|
|
269
|
+
message: t('prompts.main.action'),
|
|
270
|
+
choices: [
|
|
271
|
+
{ name: t('prompts.main.choice.scaffold'), value: 'scaffold' },
|
|
272
|
+
{ name: t('prompts.main.choice.fill'), value: 'fill' },
|
|
273
|
+
{ name: t('prompts.main.choice.plan'), value: 'plan' },
|
|
274
|
+
{ name: t('prompts.main.choice.changeLanguage'), value: 'changeLanguage' },
|
|
275
|
+
{ name: t('prompts.main.choice.exit'), value: 'exit' }
|
|
276
|
+
]
|
|
277
|
+
}
|
|
278
|
+
]);
|
|
279
|
+
if (action === 'changeLanguage') {
|
|
280
|
+
await selectLocale(true);
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
283
|
+
if (action === 'exit') {
|
|
284
|
+
exitRequested = true;
|
|
285
|
+
break;
|
|
286
|
+
}
|
|
287
|
+
if (action === 'scaffold') {
|
|
288
|
+
await runInteractiveScaffold();
|
|
289
|
+
}
|
|
290
|
+
else if (action === 'fill') {
|
|
291
|
+
await runInteractiveLlmFill();
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
294
|
+
await runInteractivePlan();
|
|
295
|
+
}
|
|
296
|
+
ui.displayInfo(t('info.interactive.returning.title'), t('info.interactive.returning.detail'));
|
|
966
297
|
}
|
|
298
|
+
ui.displaySuccess(t('success.interactive.goodbye'));
|
|
967
299
|
}
|
|
968
300
|
async function runInteractiveScaffold() {
|
|
969
301
|
const { repoPath } = await inquirer_1.default.prompt([
|
|
@@ -984,58 +316,19 @@ async function runInteractiveScaffold() {
|
|
|
984
316
|
default: defaultOutput
|
|
985
317
|
}
|
|
986
318
|
]);
|
|
987
|
-
const {
|
|
319
|
+
const { scaffoldType } = await inquirer_1.default.prompt([
|
|
988
320
|
{
|
|
989
|
-
type: '
|
|
990
|
-
name: '
|
|
991
|
-
message: t('prompts.scaffold.
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
{
|
|
999
|
-
type: 'checkbox',
|
|
1000
|
-
name: 'docs',
|
|
1001
|
-
message: t('prompts.scaffold.selectDocs'),
|
|
1002
|
-
choices: DOC_CHOICES,
|
|
1003
|
-
default: DOC_CHOICES.map(choice => choice.value)
|
|
1004
|
-
}
|
|
1005
|
-
]);
|
|
1006
|
-
selectedDocs = docs;
|
|
1007
|
-
}
|
|
1008
|
-
else {
|
|
1009
|
-
selectedDocs = [];
|
|
1010
|
-
}
|
|
1011
|
-
const { includeAgents } = await inquirer_1.default.prompt([
|
|
1012
|
-
{
|
|
1013
|
-
type: 'confirm',
|
|
1014
|
-
name: 'includeAgents',
|
|
1015
|
-
message: t('prompts.scaffold.includeAgents'),
|
|
1016
|
-
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'
|
|
1017
330
|
}
|
|
1018
331
|
]);
|
|
1019
|
-
let selectedAgents;
|
|
1020
|
-
if (includeAgents) {
|
|
1021
|
-
const { agents } = await inquirer_1.default.prompt([
|
|
1022
|
-
{
|
|
1023
|
-
type: 'checkbox',
|
|
1024
|
-
name: 'agents',
|
|
1025
|
-
message: t('prompts.scaffold.selectAgents'),
|
|
1026
|
-
choices: AGENT_CHOICES,
|
|
1027
|
-
default: AGENT_CHOICES.map(choice => choice.value)
|
|
1028
|
-
}
|
|
1029
|
-
]);
|
|
1030
|
-
selectedAgents = agents;
|
|
1031
|
-
}
|
|
1032
|
-
else {
|
|
1033
|
-
selectedAgents = [];
|
|
1034
|
-
}
|
|
1035
|
-
if ((selectedDocs?.length ?? 0) === 0 && (selectedAgents?.length ?? 0) === 0) {
|
|
1036
|
-
ui.displayWarning(t('warnings.interactive.nothingSelected'));
|
|
1037
|
-
return;
|
|
1038
|
-
}
|
|
1039
332
|
const { verbose } = await inquirer_1.default.prompt([
|
|
1040
333
|
{
|
|
1041
334
|
type: 'confirm',
|
|
@@ -1044,23 +337,11 @@ async function runInteractiveScaffold() {
|
|
|
1044
337
|
default: false
|
|
1045
338
|
}
|
|
1046
339
|
]);
|
|
1047
|
-
const scaffoldType = determineScaffoldType(selectedDocs, selectedAgents);
|
|
1048
340
|
await runInit(resolvedRepo, scaffoldType, {
|
|
1049
341
|
output: outputDir,
|
|
1050
|
-
docs: selectedDocs,
|
|
1051
|
-
agents: selectedAgents,
|
|
1052
342
|
verbose
|
|
1053
343
|
});
|
|
1054
344
|
}
|
|
1055
|
-
function determineScaffoldType(docSelection, agentSelection) {
|
|
1056
|
-
const docsSelected = docSelection === undefined ? true : docSelection.length > 0;
|
|
1057
|
-
const agentsSelected = agentSelection === undefined ? true : agentSelection.length > 0;
|
|
1058
|
-
if (docsSelected && agentsSelected)
|
|
1059
|
-
return 'both';
|
|
1060
|
-
if (docsSelected)
|
|
1061
|
-
return 'docs';
|
|
1062
|
-
return 'agents';
|
|
1063
|
-
}
|
|
1064
345
|
async function runInteractiveLlmFill() {
|
|
1065
346
|
const { repoPath } = await inquirer_1.default.prompt([
|
|
1066
347
|
{
|
|
@@ -1072,8 +353,7 @@ async function runInteractiveLlmFill() {
|
|
|
1072
353
|
]);
|
|
1073
354
|
const resolvedRepo = path.resolve(repoPath.trim() || '.');
|
|
1074
355
|
const defaultOutput = path.resolve(resolvedRepo, '.context');
|
|
1075
|
-
const
|
|
1076
|
-
const { outputDir, promptPath } = await inquirer_1.default.prompt([
|
|
356
|
+
const { outputDir, promptPath: promptPathInput } = await inquirer_1.default.prompt([
|
|
1077
357
|
{
|
|
1078
358
|
type: 'input',
|
|
1079
359
|
name: 'outputDir',
|
|
@@ -1084,23 +364,10 @@ async function runInteractiveLlmFill() {
|
|
|
1084
364
|
type: 'input',
|
|
1085
365
|
name: 'promptPath',
|
|
1086
366
|
message: t('prompts.fill.promptPath'),
|
|
1087
|
-
default:
|
|
1088
|
-
}
|
|
1089
|
-
]);
|
|
1090
|
-
const { dryRun, processAll } = await inquirer_1.default.prompt([
|
|
1091
|
-
{
|
|
1092
|
-
type: 'confirm',
|
|
1093
|
-
name: 'dryRun',
|
|
1094
|
-
message: t('prompts.fill.dryRun'),
|
|
1095
|
-
default: true
|
|
1096
|
-
},
|
|
1097
|
-
{
|
|
1098
|
-
type: 'confirm',
|
|
1099
|
-
name: 'processAll',
|
|
1100
|
-
message: t('prompts.fill.processAll'),
|
|
1101
|
-
default: false
|
|
367
|
+
default: ''
|
|
1102
368
|
}
|
|
1103
369
|
]);
|
|
370
|
+
const promptPath = promptPathInput.trim() ? path.resolve(promptPathInput.trim()) : undefined;
|
|
1104
371
|
const { limit } = await inquirer_1.default.prompt([
|
|
1105
372
|
{
|
|
1106
373
|
type: 'input',
|
|
@@ -1111,58 +378,6 @@ async function runInteractiveLlmFill() {
|
|
|
1111
378
|
]);
|
|
1112
379
|
const limitValue = limit ? parseInt(limit, 10) : undefined;
|
|
1113
380
|
const parsedLimit = Number.isNaN(limitValue) ? undefined : limitValue;
|
|
1114
|
-
const { includeDocs } = await inquirer_1.default.prompt([
|
|
1115
|
-
{
|
|
1116
|
-
type: 'confirm',
|
|
1117
|
-
name: 'includeDocs',
|
|
1118
|
-
message: t('prompts.fill.includeDocs'),
|
|
1119
|
-
default: true
|
|
1120
|
-
}
|
|
1121
|
-
]);
|
|
1122
|
-
let selectedDocs;
|
|
1123
|
-
if (includeDocs) {
|
|
1124
|
-
const { docs } = await inquirer_1.default.prompt([
|
|
1125
|
-
{
|
|
1126
|
-
type: 'checkbox',
|
|
1127
|
-
name: 'docs',
|
|
1128
|
-
message: t('prompts.fill.selectDocs'),
|
|
1129
|
-
choices: DOC_CHOICES,
|
|
1130
|
-
default: DOC_CHOICES.map(choice => choice.value)
|
|
1131
|
-
}
|
|
1132
|
-
]);
|
|
1133
|
-
selectedDocs = docs;
|
|
1134
|
-
}
|
|
1135
|
-
else {
|
|
1136
|
-
selectedDocs = [];
|
|
1137
|
-
}
|
|
1138
|
-
const { includeAgents } = await inquirer_1.default.prompt([
|
|
1139
|
-
{
|
|
1140
|
-
type: 'confirm',
|
|
1141
|
-
name: 'includeAgents',
|
|
1142
|
-
message: t('prompts.fill.includeAgents'),
|
|
1143
|
-
default: true
|
|
1144
|
-
}
|
|
1145
|
-
]);
|
|
1146
|
-
let selectedAgents;
|
|
1147
|
-
if (includeAgents) {
|
|
1148
|
-
const { agents } = await inquirer_1.default.prompt([
|
|
1149
|
-
{
|
|
1150
|
-
type: 'checkbox',
|
|
1151
|
-
name: 'agents',
|
|
1152
|
-
message: t('prompts.fill.selectAgents'),
|
|
1153
|
-
choices: AGENT_CHOICES,
|
|
1154
|
-
default: AGENT_CHOICES.map(choice => choice.value)
|
|
1155
|
-
}
|
|
1156
|
-
]);
|
|
1157
|
-
selectedAgents = agents;
|
|
1158
|
-
}
|
|
1159
|
-
else {
|
|
1160
|
-
selectedAgents = [];
|
|
1161
|
-
}
|
|
1162
|
-
if ((selectedDocs?.length ?? 0) === 0 && (selectedAgents?.length ?? 0) === 0) {
|
|
1163
|
-
ui.displayWarning(t('warnings.interactive.nothingSelected'));
|
|
1164
|
-
return;
|
|
1165
|
-
}
|
|
1166
381
|
const { specifyModel } = await inquirer_1.default.prompt([
|
|
1167
382
|
{
|
|
1168
383
|
type: 'confirm',
|
|
@@ -1174,15 +389,6 @@ async function runInteractiveLlmFill() {
|
|
|
1174
389
|
let provider;
|
|
1175
390
|
let model;
|
|
1176
391
|
if (specifyModel) {
|
|
1177
|
-
const providerAnswer = await inquirer_1.default.prompt([
|
|
1178
|
-
{
|
|
1179
|
-
type: 'list',
|
|
1180
|
-
name: 'provider',
|
|
1181
|
-
message: t('prompts.fill.provider'),
|
|
1182
|
-
choices: ['openrouter', 'openai', 'anthropic', 'gemini', 'grok']
|
|
1183
|
-
}
|
|
1184
|
-
]);
|
|
1185
|
-
provider = providerAnswer.provider;
|
|
1186
392
|
const modelAnswer = await inquirer_1.default.prompt([
|
|
1187
393
|
{
|
|
1188
394
|
type: 'input',
|
|
@@ -1192,6 +398,7 @@ async function runInteractiveLlmFill() {
|
|
|
1192
398
|
}
|
|
1193
399
|
]);
|
|
1194
400
|
model = modelAnswer.model.trim();
|
|
401
|
+
provider = 'openrouter';
|
|
1195
402
|
}
|
|
1196
403
|
const { provideApiKey } = await inquirer_1.default.prompt([
|
|
1197
404
|
{
|
|
@@ -1221,13 +428,9 @@ async function runInteractiveLlmFill() {
|
|
|
1221
428
|
default: false
|
|
1222
429
|
}
|
|
1223
430
|
]);
|
|
1224
|
-
await
|
|
431
|
+
await fillService.run(resolvedRepo, {
|
|
1225
432
|
output: outputDir,
|
|
1226
433
|
prompt: promptPath,
|
|
1227
|
-
docs: selectedDocs,
|
|
1228
|
-
agents: selectedAgents,
|
|
1229
|
-
dryRun,
|
|
1230
|
-
all: processAll,
|
|
1231
434
|
limit: parsedLimit,
|
|
1232
435
|
model,
|
|
1233
436
|
provider,
|
|
@@ -1274,50 +477,6 @@ async function runInteractivePlan() {
|
|
|
1274
477
|
filter: (value) => value.trim()
|
|
1275
478
|
}
|
|
1276
479
|
]);
|
|
1277
|
-
const { includeAgents } = await inquirer_1.default.prompt([
|
|
1278
|
-
{
|
|
1279
|
-
type: 'confirm',
|
|
1280
|
-
name: 'includeAgents',
|
|
1281
|
-
message: t('prompts.plan.includeAgents'),
|
|
1282
|
-
default: true
|
|
1283
|
-
}
|
|
1284
|
-
]);
|
|
1285
|
-
let selectedAgents = [];
|
|
1286
|
-
if (includeAgents) {
|
|
1287
|
-
const { agents } = await inquirer_1.default.prompt([
|
|
1288
|
-
{
|
|
1289
|
-
type: 'checkbox',
|
|
1290
|
-
name: 'agents',
|
|
1291
|
-
message: t('prompts.plan.selectAgents'),
|
|
1292
|
-
choices: AGENT_CHOICES,
|
|
1293
|
-
default: AGENT_CHOICES.map(choice => choice.value)
|
|
1294
|
-
}
|
|
1295
|
-
]);
|
|
1296
|
-
selectedAgents = agents;
|
|
1297
|
-
}
|
|
1298
|
-
const { includeDocs } = await inquirer_1.default.prompt([
|
|
1299
|
-
{
|
|
1300
|
-
type: 'confirm',
|
|
1301
|
-
name: 'includeDocs',
|
|
1302
|
-
message: t('prompts.plan.includeDocs'),
|
|
1303
|
-
default: true
|
|
1304
|
-
}
|
|
1305
|
-
]);
|
|
1306
|
-
let selectedDocs = [];
|
|
1307
|
-
if (includeDocs) {
|
|
1308
|
-
const { docs } = await inquirer_1.default.prompt([
|
|
1309
|
-
{
|
|
1310
|
-
type: 'checkbox',
|
|
1311
|
-
name: 'docs',
|
|
1312
|
-
message: t('prompts.plan.selectDocs'),
|
|
1313
|
-
choices: DOC_CHOICES,
|
|
1314
|
-
default: DOC_CHOICES.map(choice => choice.value)
|
|
1315
|
-
}
|
|
1316
|
-
]);
|
|
1317
|
-
selectedDocs = docs;
|
|
1318
|
-
}
|
|
1319
|
-
const agentSelection = parseAgentSelection(selectedAgents);
|
|
1320
|
-
const docSelection = parseDocSelection(selectedDocs);
|
|
1321
480
|
const { repoPath } = await inquirer_1.default.prompt([
|
|
1322
481
|
{
|
|
1323
482
|
type: 'input',
|
|
@@ -1336,12 +495,10 @@ async function runInteractivePlan() {
|
|
|
1336
495
|
]);
|
|
1337
496
|
try {
|
|
1338
497
|
const resolvedOutput = path.resolve(outputDir.trim() || defaultOutput);
|
|
1339
|
-
await scaffoldPlanIfNeeded(planName, resolvedOutput, {
|
|
1340
|
-
summary: summary || undefined
|
|
1341
|
-
agentSelection,
|
|
1342
|
-
docSelection
|
|
498
|
+
await planService.scaffoldPlanIfNeeded(planName, resolvedOutput, {
|
|
499
|
+
summary: summary || undefined
|
|
1343
500
|
});
|
|
1344
|
-
await
|
|
501
|
+
await planService.fillPlan(planName, {
|
|
1345
502
|
output: resolvedOutput,
|
|
1346
503
|
repo: repoPath,
|
|
1347
504
|
dryRun
|
|
@@ -1360,48 +517,6 @@ async function runInteractivePlan() {
|
|
|
1360
517
|
filter: (value) => value.trim()
|
|
1361
518
|
}
|
|
1362
519
|
]);
|
|
1363
|
-
const { includeAgents } = await inquirer_1.default.prompt([
|
|
1364
|
-
{
|
|
1365
|
-
type: 'confirm',
|
|
1366
|
-
name: 'includeAgents',
|
|
1367
|
-
message: t('prompts.plan.includeAgents'),
|
|
1368
|
-
default: true
|
|
1369
|
-
}
|
|
1370
|
-
]);
|
|
1371
|
-
let selectedAgents = null;
|
|
1372
|
-
if (includeAgents) {
|
|
1373
|
-
const { agents } = await inquirer_1.default.prompt([
|
|
1374
|
-
{
|
|
1375
|
-
type: 'checkbox',
|
|
1376
|
-
name: 'agents',
|
|
1377
|
-
message: t('prompts.plan.selectAgents'),
|
|
1378
|
-
choices: AGENT_CHOICES,
|
|
1379
|
-
default: AGENT_CHOICES.map(choice => choice.value)
|
|
1380
|
-
}
|
|
1381
|
-
]);
|
|
1382
|
-
selectedAgents = agents.length > 0 ? agents : null;
|
|
1383
|
-
}
|
|
1384
|
-
const { includeDocs } = await inquirer_1.default.prompt([
|
|
1385
|
-
{
|
|
1386
|
-
type: 'confirm',
|
|
1387
|
-
name: 'includeDocs',
|
|
1388
|
-
message: t('prompts.plan.includeDocs'),
|
|
1389
|
-
default: true
|
|
1390
|
-
}
|
|
1391
|
-
]);
|
|
1392
|
-
let selectedDocs = null;
|
|
1393
|
-
if (includeDocs) {
|
|
1394
|
-
const { docs } = await inquirer_1.default.prompt([
|
|
1395
|
-
{
|
|
1396
|
-
type: 'checkbox',
|
|
1397
|
-
name: 'docs',
|
|
1398
|
-
message: t('prompts.plan.selectDocs'),
|
|
1399
|
-
choices: DOC_CHOICES,
|
|
1400
|
-
default: DOC_CHOICES.map(choice => choice.value)
|
|
1401
|
-
}
|
|
1402
|
-
]);
|
|
1403
|
-
selectedDocs = docs.length > 0 ? docs : null;
|
|
1404
|
-
}
|
|
1405
520
|
const generator = new planGenerator_1.PlanGenerator();
|
|
1406
521
|
ui.startSpinner(t('spinner.plan.creating'));
|
|
1407
522
|
try {
|
|
@@ -1409,8 +524,6 @@ async function runInteractivePlan() {
|
|
|
1409
524
|
planName,
|
|
1410
525
|
outputDir: path.resolve(outputDir.trim() || defaultOutput),
|
|
1411
526
|
summary: summary || undefined,
|
|
1412
|
-
selectedAgentTypes: selectedAgents,
|
|
1413
|
-
selectedDocKeys: selectedDocs,
|
|
1414
527
|
verbose: false
|
|
1415
528
|
});
|
|
1416
529
|
ui.updateSpinner(t('spinner.plan.created'), 'success');
|
|
@@ -1424,16 +537,6 @@ async function runInteractivePlan() {
|
|
|
1424
537
|
ui.stopSpinner();
|
|
1425
538
|
}
|
|
1426
539
|
}
|
|
1427
|
-
function getAgentFilesByTypes(types) {
|
|
1428
|
-
if (!types || types.length === 0) {
|
|
1429
|
-
return undefined;
|
|
1430
|
-
}
|
|
1431
|
-
const allowed = new Set(agentTypes_1.AGENT_TYPES);
|
|
1432
|
-
const files = types
|
|
1433
|
-
.filter(type => allowed.has(type))
|
|
1434
|
-
.map(type => `${type}.md`);
|
|
1435
|
-
return files.length ? new Set(files) : undefined;
|
|
1436
|
-
}
|
|
1437
540
|
function filterOutLocaleArgs(args) {
|
|
1438
541
|
const filtered = [];
|
|
1439
542
|
for (let index = 0; index < args.length; index += 1) {
|
|
@@ -1451,6 +554,7 @@ function filterOutLocaleArgs(args) {
|
|
|
1451
554
|
}
|
|
1452
555
|
async function main() {
|
|
1453
556
|
const userArgs = process.argv.slice(2);
|
|
557
|
+
void scheduleVersionCheck();
|
|
1454
558
|
const meaningfulArgs = filterOutLocaleArgs(userArgs);
|
|
1455
559
|
if (meaningfulArgs.length === 0) {
|
|
1456
560
|
await runInteractive();
|