@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.
Files changed (228) hide show
  1. package/README.md +32 -25
  2. package/dist/commands/shared/agents.d.ts +2 -0
  3. package/dist/commands/shared/agents.d.ts.map +1 -0
  4. package/dist/commands/shared/agents.js +15 -0
  5. package/dist/commands/shared/agents.js.map +1 -0
  6. package/dist/commands/shared/selection.d.ts +12 -0
  7. package/dist/commands/shared/selection.d.ts.map +1 -0
  8. package/dist/commands/shared/selection.js +95 -0
  9. package/dist/commands/shared/selection.js.map +1 -0
  10. package/dist/generators/agents/agentConfig.d.ts.map +1 -1
  11. package/dist/generators/agents/agentConfig.js +42 -0
  12. package/dist/generators/agents/agentConfig.js.map +1 -1
  13. package/dist/generators/agents/agentGenerator.d.ts +0 -1
  14. package/dist/generators/agents/agentGenerator.d.ts.map +1 -1
  15. package/dist/generators/agents/agentGenerator.js +7 -47
  16. package/dist/generators/agents/agentGenerator.js.map +1 -1
  17. package/dist/generators/agents/agentTypes.d.ts +1 -1
  18. package/dist/generators/agents/agentTypes.d.ts.map +1 -1
  19. package/dist/generators/agents/agentTypes.js +4 -1
  20. package/dist/generators/agents/agentTypes.js.map +1 -1
  21. package/dist/generators/agents/templates/indexTemplate.d.ts.map +1 -1
  22. package/dist/generators/agents/templates/indexTemplate.js +2 -1
  23. package/dist/generators/agents/templates/indexTemplate.js.map +1 -1
  24. package/dist/generators/agents/templates/playbookTemplate.d.ts.map +1 -1
  25. package/dist/generators/agents/templates/playbookTemplate.js +39 -3
  26. package/dist/generators/agents/templates/playbookTemplate.js.map +1 -1
  27. package/dist/generators/documentation/documentationGenerator.d.ts +3 -1
  28. package/dist/generators/documentation/documentationGenerator.d.ts.map +1 -1
  29. package/dist/generators/documentation/documentationGenerator.js +88 -15
  30. package/dist/generators/documentation/documentationGenerator.js.map +1 -1
  31. package/dist/generators/documentation/guideRegistry.js +8 -8
  32. package/dist/generators/documentation/guideRegistry.js.map +1 -1
  33. package/dist/generators/documentation/templates/apiReferenceTemplate.d.ts +2 -0
  34. package/dist/generators/documentation/templates/apiReferenceTemplate.d.ts.map +1 -0
  35. package/dist/generators/documentation/templates/apiReferenceTemplate.js +490 -0
  36. package/dist/generators/documentation/templates/apiReferenceTemplate.js.map +1 -0
  37. package/dist/generators/documentation/templates/architectureTemplate.d.ts.map +1 -1
  38. package/dist/generators/documentation/templates/architectureTemplate.js +27 -27
  39. package/dist/generators/documentation/templates/architectureTemplate.js.map +1 -1
  40. package/dist/generators/documentation/templates/common.js +2 -2
  41. package/dist/generators/documentation/templates/common.js.map +1 -1
  42. package/dist/generators/documentation/templates/dataFlowTemplate.d.ts.map +1 -1
  43. package/dist/generators/documentation/templates/dataFlowTemplate.js +5 -20
  44. package/dist/generators/documentation/templates/dataFlowTemplate.js.map +1 -1
  45. package/dist/generators/documentation/templates/developmentWorkflowTemplate.d.ts.map +1 -1
  46. package/dist/generators/documentation/templates/developmentWorkflowTemplate.js +5 -20
  47. package/dist/generators/documentation/templates/developmentWorkflowTemplate.js.map +1 -1
  48. package/dist/generators/documentation/templates/glossaryTemplate.d.ts.map +1 -1
  49. package/dist/generators/documentation/templates/glossaryTemplate.js +9 -23
  50. package/dist/generators/documentation/templates/glossaryTemplate.js.map +1 -1
  51. package/dist/generators/documentation/templates/index.d.ts +4 -0
  52. package/dist/generators/documentation/templates/index.d.ts.map +1 -1
  53. package/dist/generators/documentation/templates/index.js +9 -1
  54. package/dist/generators/documentation/templates/index.js.map +1 -1
  55. package/dist/generators/documentation/templates/indexTemplate.d.ts.map +1 -1
  56. package/dist/generators/documentation/templates/indexTemplate.js +5 -19
  57. package/dist/generators/documentation/templates/indexTemplate.js.map +1 -1
  58. package/dist/generators/documentation/templates/migrationTemplate.d.ts +2 -0
  59. package/dist/generators/documentation/templates/migrationTemplate.d.ts.map +1 -0
  60. package/dist/generators/documentation/templates/migrationTemplate.js +422 -0
  61. package/dist/generators/documentation/templates/migrationTemplate.js.map +1 -0
  62. package/dist/generators/documentation/templates/onboardingTemplate.d.ts +2 -0
  63. package/dist/generators/documentation/templates/onboardingTemplate.d.ts.map +1 -0
  64. package/dist/generators/documentation/templates/onboardingTemplate.js +431 -0
  65. package/dist/generators/documentation/templates/onboardingTemplate.js.map +1 -0
  66. package/dist/generators/documentation/templates/projectOverviewTemplate.d.ts.map +1 -1
  67. package/dist/generators/documentation/templates/projectOverviewTemplate.js +22 -25
  68. package/dist/generators/documentation/templates/projectOverviewTemplate.js.map +1 -1
  69. package/dist/generators/documentation/templates/securityTemplate.d.ts.map +1 -1
  70. package/dist/generators/documentation/templates/securityTemplate.js +5 -19
  71. package/dist/generators/documentation/templates/securityTemplate.js.map +1 -1
  72. package/dist/generators/documentation/templates/testingTemplate.d.ts.map +1 -1
  73. package/dist/generators/documentation/templates/testingTemplate.js +5 -19
  74. package/dist/generators/documentation/templates/testingTemplate.js.map +1 -1
  75. package/dist/generators/documentation/templates/toolingTemplate.d.ts.map +1 -1
  76. package/dist/generators/documentation/templates/toolingTemplate.js +6 -20
  77. package/dist/generators/documentation/templates/toolingTemplate.js.map +1 -1
  78. package/dist/generators/documentation/templates/troubleshootingTemplate.d.ts +2 -0
  79. package/dist/generators/documentation/templates/troubleshootingTemplate.d.ts.map +1 -0
  80. package/dist/generators/documentation/templates/troubleshootingTemplate.js +292 -0
  81. package/dist/generators/documentation/templates/troubleshootingTemplate.js.map +1 -0
  82. package/dist/generators/plans/templates/indexTemplate.d.ts.map +1 -1
  83. package/dist/generators/plans/templates/indexTemplate.js +3 -2
  84. package/dist/generators/plans/templates/indexTemplate.js.map +1 -1
  85. package/dist/generators/plans/templates/planTemplate.d.ts.map +1 -1
  86. package/dist/generators/plans/templates/planTemplate.js +96 -13
  87. package/dist/generators/plans/templates/planTemplate.js.map +1 -1
  88. package/dist/generators/shared/generatorUtils.d.ts +1 -1
  89. package/dist/generators/shared/generatorUtils.d.ts.map +1 -1
  90. package/dist/generators/shared/generatorUtils.js +1 -1
  91. package/dist/generators/shared/generatorUtils.js.map +1 -1
  92. package/dist/index.d.ts +2 -2
  93. package/dist/index.d.ts.map +1 -1
  94. package/dist/index.js +111 -1007
  95. package/dist/index.js.map +1 -1
  96. package/dist/prompts/defaults.d.ts +3 -0
  97. package/dist/prompts/defaults.d.ts.map +1 -0
  98. package/dist/prompts/defaults.js +95 -0
  99. package/dist/prompts/defaults.js.map +1 -0
  100. package/dist/services/baseLLMClient.d.ts +3 -3
  101. package/dist/services/baseLLMClient.d.ts.map +1 -1
  102. package/dist/services/baseLLMClient.js +44 -5
  103. package/dist/services/baseLLMClient.js.map +1 -1
  104. package/dist/services/fill/fillService.d.ts +46 -0
  105. package/dist/services/fill/fillService.d.ts.map +1 -0
  106. package/dist/services/fill/fillService.js +254 -0
  107. package/dist/services/fill/fillService.js.map +1 -0
  108. package/dist/services/init/initService.d.ts +37 -0
  109. package/dist/services/init/initService.d.ts.map +1 -0
  110. package/dist/services/init/initService.js +167 -0
  111. package/dist/services/init/initService.js.map +1 -0
  112. package/dist/services/llmClientFactory.d.ts +2 -8
  113. package/dist/services/llmClientFactory.d.ts.map +1 -1
  114. package/dist/services/llmClientFactory.js +10 -96
  115. package/dist/services/llmClientFactory.js.map +1 -1
  116. package/dist/services/openRouterClient.d.ts +0 -3
  117. package/dist/services/openRouterClient.d.ts.map +1 -1
  118. package/dist/services/openRouterClient.js +2 -49
  119. package/dist/services/openRouterClient.js.map +1 -1
  120. package/dist/services/plan/planService.d.ts +57 -0
  121. package/dist/services/plan/planService.d.ts.map +1 -0
  122. package/dist/services/plan/planService.js +334 -0
  123. package/dist/services/plan/planService.js.map +1 -0
  124. package/dist/services/shared/llmConfig.d.ts +22 -0
  125. package/dist/services/shared/llmConfig.d.ts.map +1 -0
  126. package/dist/services/shared/llmConfig.js +38 -0
  127. package/dist/services/shared/llmConfig.js.map +1 -0
  128. package/dist/types.d.ts +7 -2
  129. package/dist/types.d.ts.map +1 -1
  130. package/dist/utils/fileMapper.d.ts +1 -1
  131. package/dist/utils/fileMapper.d.ts.map +1 -1
  132. package/dist/utils/fileMapper.js +40 -19
  133. package/dist/utils/fileMapper.js.map +1 -1
  134. package/dist/utils/i18n.d.ts +23 -33
  135. package/dist/utils/i18n.d.ts.map +1 -1
  136. package/dist/utils/i18n.js +48 -68
  137. package/dist/utils/i18n.js.map +1 -1
  138. package/dist/utils/promptLoader.d.ts +12 -0
  139. package/dist/utils/promptLoader.d.ts.map +1 -0
  140. package/dist/utils/promptLoader.js +81 -0
  141. package/dist/utils/promptLoader.js.map +1 -0
  142. package/dist/utils/versionChecker.d.ts +15 -0
  143. package/dist/utils/versionChecker.d.ts.map +1 -0
  144. package/dist/utils/versionChecker.js +49 -0
  145. package/dist/utils/versionChecker.js.map +1 -0
  146. package/package.json +9 -10
  147. package/prompts/update_plan_prompt.md +4 -5
  148. package/prompts/update_scaffold_prompt.md +7 -8
  149. package/dist/generators/agents/contextUtils.d.ts +0 -8
  150. package/dist/generators/agents/contextUtils.d.ts.map +0 -1
  151. package/dist/generators/agents/contextUtils.js +0 -15
  152. package/dist/generators/agents/contextUtils.js.map +0 -1
  153. package/dist/generators/agents/promptFormatter.d.ts +0 -9
  154. package/dist/generators/agents/promptFormatter.d.ts.map +0 -1
  155. package/dist/generators/agents/promptFormatter.js +0 -84
  156. package/dist/generators/agents/promptFormatter.js.map +0 -1
  157. package/dist/generators/analyzers/codebaseAnalyzer.d.ts +0 -45
  158. package/dist/generators/analyzers/codebaseAnalyzer.d.ts.map +0 -1
  159. package/dist/generators/analyzers/codebaseAnalyzer.js +0 -293
  160. package/dist/generators/analyzers/codebaseAnalyzer.js.map +0 -1
  161. package/dist/generators/analyzers/index.d.ts +0 -3
  162. package/dist/generators/analyzers/index.d.ts.map +0 -1
  163. package/dist/generators/analyzers/index.js +0 -6
  164. package/dist/generators/analyzers/index.js.map +0 -1
  165. package/dist/generators/documentation/documentationTemplates.d.ts +0 -21
  166. package/dist/generators/documentation/documentationTemplates.d.ts.map +0 -1
  167. package/dist/generators/documentation/documentationTemplates.js +0 -359
  168. package/dist/generators/documentation/documentationTemplates.js.map +0 -1
  169. package/dist/generators/documentation/documentationTypes.d.ts +0 -11
  170. package/dist/generators/documentation/documentationTypes.d.ts.map +0 -1
  171. package/dist/generators/documentation/documentationTypes.js +0 -22
  172. package/dist/generators/documentation/documentationTypes.js.map +0 -1
  173. package/dist/generators/documentation/documentationUtils.d.ts +0 -7
  174. package/dist/generators/documentation/documentationUtils.d.ts.map +0 -1
  175. package/dist/generators/documentation/documentationUtils.js +0 -28
  176. package/dist/generators/documentation/documentationUtils.js.map +0 -1
  177. package/dist/generators/documentation/incrementalDocumentationGenerator.d.ts +0 -33
  178. package/dist/generators/documentation/incrementalDocumentationGenerator.d.ts.map +0 -1
  179. package/dist/generators/documentation/incrementalDocumentationGenerator.js +0 -400
  180. package/dist/generators/documentation/incrementalDocumentationGenerator.js.map +0 -1
  181. package/dist/generators/documentation/templates.d.ts +0 -31
  182. package/dist/generators/documentation/templates.d.ts.map +0 -1
  183. package/dist/generators/documentation/templates.js +0 -566
  184. package/dist/generators/documentation/templates.js.map +0 -1
  185. package/dist/generators/guidelines/agentIntegration.d.ts +0 -43
  186. package/dist/generators/guidelines/agentIntegration.d.ts.map +0 -1
  187. package/dist/generators/guidelines/agentIntegration.js +0 -157
  188. package/dist/generators/guidelines/agentIntegration.js.map +0 -1
  189. package/dist/generators/guidelines/guidelineTypes.d.ts +0 -40
  190. package/dist/generators/guidelines/guidelineTypes.d.ts.map +0 -1
  191. package/dist/generators/guidelines/guidelineTypes.js +0 -144
  192. package/dist/generators/guidelines/guidelineTypes.js.map +0 -1
  193. package/dist/generators/guidelines/guidelinesAnalyzer.d.ts +0 -30
  194. package/dist/generators/guidelines/guidelinesAnalyzer.d.ts.map +0 -1
  195. package/dist/generators/guidelines/guidelinesAnalyzer.js +0 -263
  196. package/dist/generators/guidelines/guidelinesAnalyzer.js.map +0 -1
  197. package/dist/generators/guidelines/guidelinesGenerator.d.ts +0 -30
  198. package/dist/generators/guidelines/guidelinesGenerator.d.ts.map +0 -1
  199. package/dist/generators/guidelines/guidelinesGenerator.js +0 -249
  200. package/dist/generators/guidelines/guidelinesGenerator.js.map +0 -1
  201. package/dist/generators/guidelines/guidelinesTemplates.d.ts +0 -23
  202. package/dist/generators/guidelines/guidelinesTemplates.d.ts.map +0 -1
  203. package/dist/generators/guidelines/guidelinesTemplates.js +0 -304
  204. package/dist/generators/guidelines/guidelinesTemplates.js.map +0 -1
  205. package/dist/generators/guidelines/index.d.ts +0 -6
  206. package/dist/generators/guidelines/index.d.ts.map +0 -1
  207. package/dist/generators/guidelines/index.js +0 -16
  208. package/dist/generators/guidelines/index.js.map +0 -1
  209. package/dist/generators/moduleGrouper.d.ts +0 -14
  210. package/dist/generators/moduleGrouper.d.ts.map +0 -1
  211. package/dist/generators/moduleGrouper.js +0 -82
  212. package/dist/generators/moduleGrouper.js.map +0 -1
  213. package/dist/generators/projectAnalyzer.d.ts +0 -14
  214. package/dist/generators/projectAnalyzer.d.ts.map +0 -1
  215. package/dist/generators/projectAnalyzer.js +0 -217
  216. package/dist/generators/projectAnalyzer.js.map +0 -1
  217. package/dist/services/changeAnalyzer.d.ts +0 -44
  218. package/dist/services/changeAnalyzer.d.ts.map +0 -1
  219. package/dist/services/changeAnalyzer.js +0 -344
  220. package/dist/services/changeAnalyzer.js.map +0 -1
  221. package/dist/utils/interactiveMode.d.ts +0 -21
  222. package/dist/utils/interactiveMode.d.ts.map +0 -1
  223. package/dist/utils/interactiveMode.js +0 -737
  224. package/dist/utils/interactiveMode.js.map +0 -1
  225. package/dist/utils/tokenEstimator.d.ts +0 -28
  226. package/dist/utils/tokenEstimator.d.ts.map +0 -1
  227. package/dist/utils/tokenEstimator.js +0 -134
  228. 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.runInit = runInit;
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 llmClientFactory_1 = require("./services/llmClientFactory");
61
- const guideRegistry_1 = require("./generators/documentation/guideRegistry");
62
- const agentTypes_1 = require("./generators/agents/agentTypes");
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.3.0';
75
- const DEFAULT_MODEL = 'x-ai/grok-4-fast:free';
76
- const DOC_CHOICES = guideRegistry_1.DOCUMENT_GUIDES.map(guide => ({
77
- name: `${guide.title} (${guide.key})`,
78
- value: guide.key
79
- }));
80
- const AGENT_CHOICES = agentTypes_1.AGENT_TYPES.map(agent => ({
81
- name: formatAgentLabel(agent),
82
- value: agent
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 runInit(repoPath, type, options);
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'), path.join(__dirname, '../prompts/update_scaffold_prompt.md'))
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 runLlmFill(repoPath, options);
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'), path.join(__dirname, '../prompts/update_plan_prompt.md'))
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 runPlanFill(planName, { ...rawOptions, output: outputDir });
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
- const resolvedType = resolveScaffoldType(type, rawOptions);
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 runInit(repoPath, type, {
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
- const resolvedRepo = path.resolve(repoPath);
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 scaffoldPlanIfNeeded(planName, outputDir, options) {
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
- ui.displayWelcome(VERSION);
946
- const { action } = await inquirer_1.default.prompt([
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
- else if (action === 'fill') {
962
- await runInteractiveLlmFill();
963
- }
964
- else {
965
- await runInteractivePlan();
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 { includeDocs } = await inquirer_1.default.prompt([
319
+ const { scaffoldType } = await inquirer_1.default.prompt([
988
320
  {
989
- type: 'confirm',
990
- name: 'includeDocs',
991
- message: t('prompts.scaffold.includeDocs'),
992
- default: true
993
- }
994
- ]);
995
- let selectedDocs;
996
- if (includeDocs) {
997
- const { docs } = await inquirer_1.default.prompt([
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 defaultPrompt = path.resolve(process.cwd(), 'prompts/update_scaffold_prompt.md');
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: defaultPrompt
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 runLlmFill(resolvedRepo, {
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 runPlanFill(planName, {
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();