@ai-coders/context 0.5.1 → 0.6.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 +254 -12
- package/dist/generators/agents/agentGenerator.d.ts +3 -0
- package/dist/generators/agents/agentGenerator.d.ts.map +1 -1
- package/dist/generators/agents/agentGenerator.js +13 -7
- package/dist/generators/agents/agentGenerator.js.map +1 -1
- package/dist/generators/agents/templates/playbookTemplate.d.ts.map +1 -1
- package/dist/generators/agents/templates/playbookTemplate.js +3 -1
- package/dist/generators/agents/templates/playbookTemplate.js.map +1 -1
- package/dist/generators/documentation/codebaseMapGenerator.d.ts +98 -0
- package/dist/generators/documentation/codebaseMapGenerator.d.ts.map +1 -0
- package/dist/generators/documentation/codebaseMapGenerator.js +247 -0
- package/dist/generators/documentation/codebaseMapGenerator.js.map +1 -0
- package/dist/generators/documentation/documentationGenerator.d.ts +2 -0
- package/dist/generators/documentation/documentationGenerator.d.ts.map +1 -1
- package/dist/generators/documentation/documentationGenerator.js +20 -1
- package/dist/generators/documentation/documentationGenerator.js.map +1 -1
- package/dist/generators/documentation/index.d.ts +2 -0
- package/dist/generators/documentation/index.d.ts.map +1 -1
- package/dist/generators/documentation/index.js +3 -1
- package/dist/generators/documentation/index.js.map +1 -1
- package/dist/generators/documentation/templates/architectureTemplate.d.ts.map +1 -1
- package/dist/generators/documentation/templates/architectureTemplate.js +2 -31
- package/dist/generators/documentation/templates/architectureTemplate.js.map +1 -1
- package/dist/generators/documentation/templates/common.d.ts +4 -1
- package/dist/generators/documentation/templates/common.d.ts.map +1 -1
- package/dist/generators/documentation/templates/common.js +4 -2
- package/dist/generators/documentation/templates/common.js.map +1 -1
- package/dist/generators/plans/templates/planTemplate.d.ts.map +1 -1
- package/dist/generators/plans/templates/planTemplate.js +46 -2
- package/dist/generators/plans/templates/planTemplate.js.map +1 -1
- package/dist/generators/skills/index.d.ts +7 -0
- package/dist/generators/skills/index.d.ts.map +1 -0
- package/dist/generators/skills/index.js +15 -0
- package/dist/generators/skills/index.js.map +1 -0
- package/dist/generators/skills/skillGenerator.d.ts +53 -0
- package/dist/generators/skills/skillGenerator.d.ts.map +1 -0
- package/dist/generators/skills/skillGenerator.js +149 -0
- package/dist/generators/skills/skillGenerator.js.map +1 -0
- package/dist/generators/skills/templates/indexTemplate.d.ts +13 -0
- package/dist/generators/skills/templates/indexTemplate.d.ts.map +1 -0
- package/dist/generators/skills/templates/indexTemplate.js +102 -0
- package/dist/generators/skills/templates/indexTemplate.js.map +1 -0
- package/dist/generators/skills/templates/skillTemplate.d.ts +20 -0
- package/dist/generators/skills/templates/skillTemplate.d.ts.map +1 -0
- package/dist/generators/skills/templates/skillTemplate.js +85 -0
- package/dist/generators/skills/templates/skillTemplate.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1321 -45
- package/dist/index.js.map +1 -1
- package/dist/services/ai/agentEvents.d.ts +1 -1
- package/dist/services/ai/agentEvents.d.ts.map +1 -1
- package/dist/services/ai/agents/index.d.ts +2 -0
- package/dist/services/ai/agents/index.d.ts.map +1 -1
- package/dist/services/ai/agents/index.js +3 -1
- package/dist/services/ai/agents/index.js.map +1 -1
- package/dist/services/ai/agents/skillAgent.d.ts +49 -0
- package/dist/services/ai/agents/skillAgent.d.ts.map +1 -0
- package/dist/services/ai/agents/skillAgent.js +179 -0
- package/dist/services/ai/agents/skillAgent.js.map +1 -0
- package/dist/services/ai/prompts/index.d.ts +1 -1
- package/dist/services/ai/prompts/index.d.ts.map +1 -1
- package/dist/services/ai/prompts/index.js +2 -1
- package/dist/services/ai/prompts/index.js.map +1 -1
- package/dist/services/ai/prompts/sharedPrompts.d.ts +4 -0
- package/dist/services/ai/prompts/sharedPrompts.d.ts.map +1 -1
- package/dist/services/ai/prompts/sharedPrompts.js +33 -0
- package/dist/services/ai/prompts/sharedPrompts.js.map +1 -1
- package/dist/services/ai/schemas.d.ts +96 -1
- package/dist/services/ai/schemas.d.ts.map +1 -1
- package/dist/services/ai/schemas.js +56 -2
- package/dist/services/ai/schemas.js.map +1 -1
- package/dist/services/ai/toolRegistry.d.ts.map +1 -1
- package/dist/services/ai/toolRegistry.js +17 -0
- package/dist/services/ai/toolRegistry.js.map +1 -1
- package/dist/services/ai/tools/fillScaffoldingTool.d.ts +4 -4
- package/dist/services/ai/tools/getCodebaseMapTool.d.ts +17 -0
- package/dist/services/ai/tools/getCodebaseMapTool.d.ts.map +1 -0
- package/dist/services/ai/tools/getCodebaseMapTool.js +115 -0
- package/dist/services/ai/tools/getCodebaseMapTool.js.map +1 -0
- package/dist/services/ai/tools/index.d.ts +2 -1
- package/dist/services/ai/tools/index.d.ts.map +1 -1
- package/dist/services/ai/tools/index.js +8 -3
- package/dist/services/ai/tools/index.js.map +1 -1
- package/dist/services/ai/tools/initializeContextTool.d.ts +9 -1
- package/dist/services/ai/tools/initializeContextTool.d.ts.map +1 -1
- package/dist/services/ai/tools/initializeContextTool.js +33 -3
- package/dist/services/ai/tools/initializeContextTool.js.map +1 -1
- package/dist/services/ai/tools/scaffoldPlanTool.d.ts +6 -0
- package/dist/services/ai/tools/scaffoldPlanTool.d.ts.map +1 -1
- package/dist/services/ai/tools/scaffoldPlanTool.js +16 -3
- package/dist/services/ai/tools/scaffoldPlanTool.js.map +1 -1
- package/dist/services/export/exportRulesService.d.ts +62 -0
- package/dist/services/export/exportRulesService.d.ts.map +1 -0
- package/dist/services/export/exportRulesService.js +242 -0
- package/dist/services/export/exportRulesService.js.map +1 -0
- package/dist/services/export/index.d.ts +5 -0
- package/dist/services/export/index.d.ts.map +1 -0
- package/dist/services/export/index.js +10 -0
- package/dist/services/export/index.js.map +1 -0
- package/dist/services/export/skillExportService.d.ts +64 -0
- package/dist/services/export/skillExportService.d.ts.map +1 -0
- package/dist/services/export/skillExportService.js +238 -0
- package/dist/services/export/skillExportService.js.map +1 -0
- package/dist/services/fill/skillFillService.d.ts +50 -0
- package/dist/services/fill/skillFillService.d.ts.map +1 -0
- package/dist/services/fill/skillFillService.js +254 -0
- package/dist/services/fill/skillFillService.js.map +1 -0
- package/dist/services/import/agentsDetector.d.ts +12 -0
- package/dist/services/import/agentsDetector.d.ts.map +1 -0
- package/dist/services/import/agentsDetector.js +183 -0
- package/dist/services/import/agentsDetector.js.map +1 -0
- package/dist/services/import/importAgentsService.d.ts +14 -0
- package/dist/services/import/importAgentsService.d.ts.map +1 -0
- package/dist/services/import/importAgentsService.js +195 -0
- package/dist/services/import/importAgentsService.js.map +1 -0
- package/dist/services/import/importRulesService.d.ts +17 -0
- package/dist/services/import/importRulesService.d.ts.map +1 -0
- package/dist/services/import/importRulesService.js +222 -0
- package/dist/services/import/importRulesService.js.map +1 -0
- package/dist/services/import/index.d.ts +7 -0
- package/dist/services/import/index.d.ts.map +1 -0
- package/dist/services/import/index.js +28 -0
- package/dist/services/import/index.js.map +1 -0
- package/dist/services/import/presets.d.ts +8 -0
- package/dist/services/import/presets.d.ts.map +1 -0
- package/dist/services/import/presets.js +176 -0
- package/dist/services/import/presets.js.map +1 -0
- package/dist/services/import/rulesDetector.d.ts +16 -0
- package/dist/services/import/rulesDetector.d.ts.map +1 -0
- package/dist/services/import/rulesDetector.js +278 -0
- package/dist/services/import/rulesDetector.js.map +1 -0
- package/dist/services/import/types.d.ts +72 -0
- package/dist/services/import/types.d.ts.map +1 -0
- package/dist/services/import/types.js +3 -0
- package/dist/services/import/types.js.map +1 -0
- package/dist/services/mcp/mcpServer.d.ts +24 -0
- package/dist/services/mcp/mcpServer.d.ts.map +1 -1
- package/dist/services/mcp/mcpServer.js +1451 -1
- package/dist/services/mcp/mcpServer.js.map +1 -1
- package/dist/services/quickSync/index.d.ts +3 -0
- package/dist/services/quickSync/index.d.ts.map +1 -0
- package/dist/services/quickSync/index.js +7 -0
- package/dist/services/quickSync/index.js.map +1 -0
- package/dist/services/quickSync/quickSyncService.d.ts +72 -0
- package/dist/services/quickSync/quickSyncService.d.ts.map +1 -0
- package/dist/services/quickSync/quickSyncService.js +268 -0
- package/dist/services/quickSync/quickSyncService.js.map +1 -0
- package/dist/services/report/index.d.ts +3 -0
- package/dist/services/report/index.d.ts.map +1 -0
- package/dist/services/report/index.js +6 -0
- package/dist/services/report/index.js.map +1 -0
- package/dist/services/report/reportService.d.ts +131 -0
- package/dist/services/report/reportService.d.ts.map +1 -0
- package/dist/services/report/reportService.js +372 -0
- package/dist/services/report/reportService.js.map +1 -0
- package/dist/services/semantic/contextBuilder.d.ts +8 -1
- package/dist/services/semantic/contextBuilder.d.ts.map +1 -1
- package/dist/services/semantic/contextBuilder.js +107 -20
- package/dist/services/semantic/contextBuilder.js.map +1 -1
- package/dist/services/shared/globPatterns.d.ts +48 -0
- package/dist/services/shared/globPatterns.d.ts.map +1 -0
- package/dist/services/shared/globPatterns.js +110 -0
- package/dist/services/shared/globPatterns.js.map +1 -0
- package/dist/services/shared/index.d.ts +10 -0
- package/dist/services/shared/index.d.ts.map +1 -0
- package/dist/services/shared/index.js +46 -0
- package/dist/services/shared/index.js.map +1 -0
- package/dist/services/shared/pathHelpers.d.ts +71 -0
- package/dist/services/shared/pathHelpers.d.ts.map +1 -0
- package/dist/services/shared/pathHelpers.js +162 -0
- package/dist/services/shared/pathHelpers.js.map +1 -0
- package/dist/services/shared/types.d.ts +74 -0
- package/dist/services/shared/types.d.ts.map +1 -0
- package/dist/services/shared/types.js +44 -0
- package/dist/services/shared/types.js.map +1 -0
- package/dist/services/shared/uiHelpers.d.ts +70 -0
- package/dist/services/shared/uiHelpers.d.ts.map +1 -0
- package/dist/services/shared/uiHelpers.js +131 -0
- package/dist/services/shared/uiHelpers.js.map +1 -0
- package/dist/services/stack/index.d.ts +6 -0
- package/dist/services/stack/index.d.ts.map +1 -0
- package/dist/services/stack/index.js +25 -0
- package/dist/services/stack/index.js.map +1 -0
- package/dist/services/stack/projectTypeClassifier.d.ts +59 -0
- package/dist/services/stack/projectTypeClassifier.d.ts.map +1 -0
- package/dist/services/stack/projectTypeClassifier.js +242 -0
- package/dist/services/stack/projectTypeClassifier.js.map +1 -0
- package/dist/services/stack/scaffoldFilter.d.ts +75 -0
- package/dist/services/stack/scaffoldFilter.d.ts.map +1 -0
- package/dist/services/stack/scaffoldFilter.js +222 -0
- package/dist/services/stack/scaffoldFilter.js.map +1 -0
- package/dist/services/stack/stackDetector.d.ts +43 -0
- package/dist/services/stack/stackDetector.d.ts.map +1 -0
- package/dist/services/stack/stackDetector.js +406 -0
- package/dist/services/stack/stackDetector.js.map +1 -0
- package/dist/services/start/index.d.ts +3 -0
- package/dist/services/start/index.d.ts.map +1 -0
- package/dist/services/start/index.js +6 -0
- package/dist/services/start/index.js.map +1 -0
- package/dist/services/start/startService.d.ts +64 -0
- package/dist/services/start/startService.d.ts.map +1 -0
- package/dist/services/start/startService.js +180 -0
- package/dist/services/start/startService.js.map +1 -0
- package/dist/services/sync/presets.d.ts.map +1 -1
- package/dist/services/sync/presets.js +16 -1
- package/dist/services/sync/presets.js.map +1 -1
- package/dist/services/sync/types.d.ts +1 -1
- package/dist/services/sync/types.d.ts.map +1 -1
- package/dist/services/workflow/autoAdvance.d.ts +38 -0
- package/dist/services/workflow/autoAdvance.d.ts.map +1 -0
- package/dist/services/workflow/autoAdvance.js +219 -0
- package/dist/services/workflow/autoAdvance.js.map +1 -0
- package/dist/services/workflow/index.d.ts +6 -0
- package/dist/services/workflow/index.d.ts.map +1 -0
- package/dist/services/workflow/index.js +11 -0
- package/dist/services/workflow/index.js.map +1 -0
- package/dist/services/workflow/workflowService.d.ts +98 -0
- package/dist/services/workflow/workflowService.d.ts.map +1 -0
- package/dist/services/workflow/workflowService.js +210 -0
- package/dist/services/workflow/workflowService.js.map +1 -0
- package/dist/utils/cliUI.d.ts +4 -0
- package/dist/utils/cliUI.d.ts.map +1 -1
- package/dist/utils/cliUI.js +31 -1
- package/dist/utils/cliUI.js.map +1 -1
- package/dist/utils/i18n.d.ts +202 -0
- package/dist/utils/i18n.d.ts.map +1 -1
- package/dist/utils/i18n.js +438 -2
- package/dist/utils/i18n.js.map +1 -1
- package/dist/utils/theme.d.ts +1 -0
- package/dist/utils/theme.d.ts.map +1 -1
- package/dist/utils/theme.js +1 -0
- package/dist/utils/theme.js.map +1 -1
- package/dist/workflow/agents/agentRegistry.d.ts +82 -0
- package/dist/workflow/agents/agentRegistry.d.ts.map +1 -0
- package/dist/workflow/agents/agentRegistry.js +205 -0
- package/dist/workflow/agents/agentRegistry.js.map +1 -0
- package/dist/workflow/agents/index.d.ts +7 -0
- package/dist/workflow/agents/index.d.ts.map +1 -0
- package/dist/workflow/agents/index.js +14 -0
- package/dist/workflow/agents/index.js.map +1 -0
- package/dist/workflow/collaboration.d.ts +110 -0
- package/dist/workflow/collaboration.d.ts.map +1 -0
- package/dist/workflow/collaboration.js +301 -0
- package/dist/workflow/collaboration.js.map +1 -0
- package/dist/workflow/index.d.ts +25 -0
- package/dist/workflow/index.d.ts.map +1 -0
- package/dist/workflow/index.js +124 -0
- package/dist/workflow/index.js.map +1 -0
- package/dist/workflow/orchestration/agentOrchestrator.d.ts +68 -0
- package/dist/workflow/orchestration/agentOrchestrator.d.ts.map +1 -0
- package/dist/workflow/orchestration/agentOrchestrator.js +280 -0
- package/dist/workflow/orchestration/agentOrchestrator.js.map +1 -0
- package/dist/workflow/orchestration/documentLinker.d.ts +100 -0
- package/dist/workflow/orchestration/documentLinker.d.ts.map +1 -0
- package/dist/workflow/orchestration/documentLinker.js +266 -0
- package/dist/workflow/orchestration/documentLinker.js.map +1 -0
- package/dist/workflow/orchestration/index.d.ts +9 -0
- package/dist/workflow/orchestration/index.d.ts.map +1 -0
- package/dist/workflow/orchestration/index.js +25 -0
- package/dist/workflow/orchestration/index.js.map +1 -0
- package/dist/workflow/orchestrator.d.ts +99 -0
- package/dist/workflow/orchestrator.d.ts.map +1 -0
- package/dist/workflow/orchestrator.js +217 -0
- package/dist/workflow/orchestrator.js.map +1 -0
- package/dist/workflow/phases.d.ts +64 -0
- package/dist/workflow/phases.d.ts.map +1 -0
- package/dist/workflow/phases.js +151 -0
- package/dist/workflow/phases.js.map +1 -0
- package/dist/workflow/plans/index.d.ts +8 -0
- package/dist/workflow/plans/index.d.ts.map +1 -0
- package/dist/workflow/plans/index.js +27 -0
- package/dist/workflow/plans/index.js.map +1 -0
- package/dist/workflow/plans/planLinker.d.ts +119 -0
- package/dist/workflow/plans/planLinker.d.ts.map +1 -0
- package/dist/workflow/plans/planLinker.js +499 -0
- package/dist/workflow/plans/planLinker.js.map +1 -0
- package/dist/workflow/plans/types.d.ts +167 -0
- package/dist/workflow/plans/types.d.ts.map +1 -0
- package/dist/workflow/plans/types.js +25 -0
- package/dist/workflow/plans/types.js.map +1 -0
- package/dist/workflow/prevcConfig.d.ts +27 -0
- package/dist/workflow/prevcConfig.d.ts.map +1 -0
- package/dist/workflow/prevcConfig.js +153 -0
- package/dist/workflow/prevcConfig.js.map +1 -0
- package/dist/workflow/roles.d.ts +44 -0
- package/dist/workflow/roles.d.ts.map +1 -0
- package/dist/workflow/roles.js +112 -0
- package/dist/workflow/roles.js.map +1 -0
- package/dist/workflow/scaling.d.ts +44 -0
- package/dist/workflow/scaling.d.ts.map +1 -0
- package/dist/workflow/scaling.js +224 -0
- package/dist/workflow/scaling.js.map +1 -0
- package/dist/workflow/skills/frontmatter.d.ts +23 -0
- package/dist/workflow/skills/frontmatter.d.ts.map +1 -0
- package/dist/workflow/skills/frontmatter.js +100 -0
- package/dist/workflow/skills/frontmatter.js.map +1 -0
- package/dist/workflow/skills/index.d.ts +10 -0
- package/dist/workflow/skills/index.d.ts.map +1 -0
- package/dist/workflow/skills/index.js +22 -0
- package/dist/workflow/skills/index.js.map +1 -0
- package/dist/workflow/skills/skillRegistry.d.ts +60 -0
- package/dist/workflow/skills/skillRegistry.d.ts.map +1 -0
- package/dist/workflow/skills/skillRegistry.js +257 -0
- package/dist/workflow/skills/skillRegistry.js.map +1 -0
- package/dist/workflow/skills/skillTemplates.d.ts +16 -0
- package/dist/workflow/skills/skillTemplates.d.ts.map +1 -0
- package/dist/workflow/skills/skillTemplates.js +610 -0
- package/dist/workflow/skills/skillTemplates.js.map +1 -0
- package/dist/workflow/skills/types.d.ts +72 -0
- package/dist/workflow/skills/types.d.ts.map +1 -0
- package/dist/workflow/skills/types.js +48 -0
- package/dist/workflow/skills/types.js.map +1 -0
- package/dist/workflow/status/statusManager.d.ts +84 -0
- package/dist/workflow/status/statusManager.d.ts.map +1 -0
- package/dist/workflow/status/statusManager.js +402 -0
- package/dist/workflow/status/statusManager.js.map +1 -0
- package/dist/workflow/status/templates.d.ts +40 -0
- package/dist/workflow/status/templates.d.ts.map +1 -0
- package/dist/workflow/status/templates.js +148 -0
- package/dist/workflow/status/templates.js.map +1 -0
- package/dist/workflow/types.d.ts +178 -0
- package/dist/workflow/types.d.ts.map +1 -0
- package/dist/workflow/types.js +25 -0
- package/dist/workflow/types.js.map +1 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -57,14 +57,26 @@ const initService_1 = require("./services/init/initService");
|
|
|
57
57
|
const fillService_1 = require("./services/fill/fillService");
|
|
58
58
|
const planService_1 = require("./services/plan/planService");
|
|
59
59
|
const syncService_1 = require("./services/sync/syncService");
|
|
60
|
+
const import_1 = require("./services/import");
|
|
60
61
|
const serve_1 = require("./services/serve");
|
|
61
62
|
const mcp_1 = require("./services/mcp");
|
|
62
63
|
const state_1 = require("./services/state");
|
|
63
64
|
const update_1 = require("./services/update");
|
|
65
|
+
const workflow_1 = require("./services/workflow");
|
|
66
|
+
const start_1 = require("./services/start");
|
|
67
|
+
const export_1 = require("./services/export");
|
|
68
|
+
const report_1 = require("./services/report");
|
|
69
|
+
const quickSync_1 = require("./services/quickSync");
|
|
70
|
+
const workflow_2 = require("./workflow");
|
|
71
|
+
const providerFactory_1 = require("./services/ai/providerFactory");
|
|
64
72
|
const prompts_1 = require("./utils/prompts");
|
|
65
73
|
const version_1 = require("./version");
|
|
66
|
-
|
|
67
|
-
const
|
|
74
|
+
const rawArgs = process.argv.slice(2);
|
|
75
|
+
const isMcpCommand = rawArgs.includes('mcp');
|
|
76
|
+
if (!isMcpCommand) {
|
|
77
|
+
dotenv.config();
|
|
78
|
+
}
|
|
79
|
+
const initialLocale = (0, i18n_1.detectLocale)(rawArgs, process.env.AI_CONTEXT_LANG);
|
|
68
80
|
let currentLocale = initialLocale;
|
|
69
81
|
let translateFn = (0, i18n_1.createTranslator)(initialLocale);
|
|
70
82
|
const t = (key, params) => translateFn(key, params);
|
|
@@ -97,6 +109,16 @@ const syncService = new syncService_1.SyncService({
|
|
|
97
109
|
t,
|
|
98
110
|
version: version_1.VERSION
|
|
99
111
|
});
|
|
112
|
+
const importRulesService = new import_1.ImportRulesService({
|
|
113
|
+
ui,
|
|
114
|
+
t,
|
|
115
|
+
version: version_1.VERSION
|
|
116
|
+
});
|
|
117
|
+
const importAgentsService = new import_1.ImportAgentsService({
|
|
118
|
+
ui,
|
|
119
|
+
t,
|
|
120
|
+
version: version_1.VERSION
|
|
121
|
+
});
|
|
100
122
|
const updateService = new update_1.UpdateService({
|
|
101
123
|
ui,
|
|
102
124
|
t
|
|
@@ -308,6 +330,60 @@ program
|
|
|
308
330
|
process.exit(1);
|
|
309
331
|
}
|
|
310
332
|
});
|
|
333
|
+
program
|
|
334
|
+
.command('import-rules')
|
|
335
|
+
.description(t('commands.importRules.description'))
|
|
336
|
+
.argument('[repo-path]', 'Repository path to scan', process.cwd())
|
|
337
|
+
.option('-s, --source <paths...>', t('commands.importRules.options.source'))
|
|
338
|
+
.option('-t, --target <dir>', t('commands.importRules.options.target'))
|
|
339
|
+
.option('-f, --format <format>', t('commands.importRules.options.format'), 'markdown')
|
|
340
|
+
.option('--force', t('commands.importRules.options.force'))
|
|
341
|
+
.option('--dry-run', t('commands.importRules.options.dryRun'))
|
|
342
|
+
.option('-v, --verbose', t('commands.importRules.options.verbose'))
|
|
343
|
+
.option('--no-auto-detect', 'Disable auto-detection')
|
|
344
|
+
.action(async (repoPath, options) => {
|
|
345
|
+
try {
|
|
346
|
+
await importRulesService.run({
|
|
347
|
+
source: options.source,
|
|
348
|
+
target: options.target,
|
|
349
|
+
format: options.format,
|
|
350
|
+
force: options.force,
|
|
351
|
+
dryRun: options.dryRun,
|
|
352
|
+
verbose: options.verbose,
|
|
353
|
+
autoDetect: options.autoDetect !== false
|
|
354
|
+
}, repoPath);
|
|
355
|
+
}
|
|
356
|
+
catch (error) {
|
|
357
|
+
ui.displayError(t('errors.import.failed'), error);
|
|
358
|
+
process.exit(1);
|
|
359
|
+
}
|
|
360
|
+
});
|
|
361
|
+
program
|
|
362
|
+
.command('import-agents')
|
|
363
|
+
.description(t('commands.importAgents.description'))
|
|
364
|
+
.argument('[repo-path]', 'Repository path to scan', process.cwd())
|
|
365
|
+
.option('-s, --source <paths...>', t('commands.importAgents.options.source'))
|
|
366
|
+
.option('-t, --target <dir>', t('commands.importAgents.options.target'))
|
|
367
|
+
.option('--force', t('commands.importAgents.options.force'))
|
|
368
|
+
.option('--dry-run', t('commands.importAgents.options.dryRun'))
|
|
369
|
+
.option('-v, --verbose', t('commands.importAgents.options.verbose'))
|
|
370
|
+
.option('--no-auto-detect', 'Disable auto-detection')
|
|
371
|
+
.action(async (repoPath, options) => {
|
|
372
|
+
try {
|
|
373
|
+
await importAgentsService.run({
|
|
374
|
+
source: options.source,
|
|
375
|
+
target: options.target,
|
|
376
|
+
force: options.force,
|
|
377
|
+
dryRun: options.dryRun,
|
|
378
|
+
verbose: options.verbose,
|
|
379
|
+
autoDetect: options.autoDetect !== false
|
|
380
|
+
}, repoPath);
|
|
381
|
+
}
|
|
382
|
+
catch (error) {
|
|
383
|
+
ui.displayError(t('errors.import.failed'), error);
|
|
384
|
+
process.exit(1);
|
|
385
|
+
}
|
|
386
|
+
});
|
|
311
387
|
program
|
|
312
388
|
.command('serve')
|
|
313
389
|
.description('Start passthrough server for external AI agents (stdin/stdout JSON)')
|
|
@@ -358,6 +434,441 @@ program
|
|
|
358
434
|
process.exit(1);
|
|
359
435
|
}
|
|
360
436
|
});
|
|
437
|
+
// Smart Start Command
|
|
438
|
+
program
|
|
439
|
+
.command('start')
|
|
440
|
+
.description(t('commands.start.description'))
|
|
441
|
+
.argument('[feature-name]', t('commands.start.arguments.featureName'))
|
|
442
|
+
.option('-t, --template <template>', t('commands.start.options.template'), 'auto')
|
|
443
|
+
.option('--skip-fill', t('commands.start.options.skipFill'))
|
|
444
|
+
.option('--skip-workflow', t('commands.start.options.skipWorkflow'))
|
|
445
|
+
.option('-k, --api-key <key>', t('commands.fill.options.apiKey'))
|
|
446
|
+
.option('-m, --model <model>', t('commands.fill.options.model'), DEFAULT_MODEL)
|
|
447
|
+
.option('-p, --provider <provider>', t('commands.fill.options.provider'))
|
|
448
|
+
.option('-v, --verbose', t('commands.fill.options.verbose'))
|
|
449
|
+
.action(async (featureName, options) => {
|
|
450
|
+
try {
|
|
451
|
+
const startService = new start_1.StartService({
|
|
452
|
+
ui,
|
|
453
|
+
t,
|
|
454
|
+
version: version_1.VERSION,
|
|
455
|
+
defaultModel: DEFAULT_MODEL,
|
|
456
|
+
});
|
|
457
|
+
const result = await startService.run(process.cwd(), {
|
|
458
|
+
featureName,
|
|
459
|
+
template: options.template,
|
|
460
|
+
skipFill: options.skipFill,
|
|
461
|
+
skipWorkflow: options.skipWorkflow,
|
|
462
|
+
apiKey: options.apiKey,
|
|
463
|
+
model: options.model,
|
|
464
|
+
provider: options.provider,
|
|
465
|
+
verbose: options.verbose,
|
|
466
|
+
});
|
|
467
|
+
// Display summary
|
|
468
|
+
const details = [];
|
|
469
|
+
if (result.initialized)
|
|
470
|
+
details.push('context initialized');
|
|
471
|
+
if (result.filled)
|
|
472
|
+
details.push('docs filled');
|
|
473
|
+
if (result.workflowStarted)
|
|
474
|
+
details.push(`workflow started (${(0, workflow_2.getScaleName)(result.scale)})`);
|
|
475
|
+
if (result.stackDetected?.primaryLanguage) {
|
|
476
|
+
details.push(`stack: ${result.stackDetected.primaryLanguage}`);
|
|
477
|
+
}
|
|
478
|
+
ui.displaySuccess(t('success.start.complete', { details: details.join(', ') }));
|
|
479
|
+
}
|
|
480
|
+
catch (error) {
|
|
481
|
+
ui.displayError(t('errors.cli.executionFailed'), error);
|
|
482
|
+
process.exit(1);
|
|
483
|
+
}
|
|
484
|
+
});
|
|
485
|
+
// Export Rules Command
|
|
486
|
+
program
|
|
487
|
+
.command('export-rules')
|
|
488
|
+
.description(t('commands.export.description'))
|
|
489
|
+
.argument('[repo-path]', 'Repository path', process.cwd())
|
|
490
|
+
.option('-s, --source <dir>', t('commands.export.options.source'), '.context/docs')
|
|
491
|
+
.option('-t, --targets <paths...>', t('commands.export.options.targets'))
|
|
492
|
+
.option('--preset <name>', t('commands.export.options.preset'))
|
|
493
|
+
.option('--force', t('commands.export.options.force'))
|
|
494
|
+
.option('--dry-run', t('commands.export.options.dryRun'))
|
|
495
|
+
.option('-v, --verbose', t('commands.fill.options.verbose'))
|
|
496
|
+
.action(async (repoPath, options) => {
|
|
497
|
+
try {
|
|
498
|
+
const exportService = new export_1.ExportRulesService({
|
|
499
|
+
ui,
|
|
500
|
+
t,
|
|
501
|
+
version: version_1.VERSION,
|
|
502
|
+
});
|
|
503
|
+
await exportService.run(repoPath, {
|
|
504
|
+
source: options.source,
|
|
505
|
+
targets: options.targets,
|
|
506
|
+
preset: options.preset,
|
|
507
|
+
force: options.force,
|
|
508
|
+
dryRun: options.dryRun,
|
|
509
|
+
verbose: options.verbose,
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
catch (error) {
|
|
513
|
+
ui.displayError(t('errors.cli.executionFailed'), error);
|
|
514
|
+
process.exit(1);
|
|
515
|
+
}
|
|
516
|
+
});
|
|
517
|
+
// Report Command
|
|
518
|
+
program
|
|
519
|
+
.command('report')
|
|
520
|
+
.description(t('commands.report.description'))
|
|
521
|
+
.argument('[repo-path]', 'Repository path', process.cwd())
|
|
522
|
+
.option('-f, --format <format>', t('commands.report.options.format'), 'console')
|
|
523
|
+
.option('-o, --output <path>', t('commands.report.options.output'))
|
|
524
|
+
.option('--include-stack', t('commands.report.options.includeStack'))
|
|
525
|
+
.option('-v, --verbose', t('commands.fill.options.verbose'))
|
|
526
|
+
.action(async (repoPath, options) => {
|
|
527
|
+
try {
|
|
528
|
+
const reportService = new report_1.ReportService({
|
|
529
|
+
ui,
|
|
530
|
+
t,
|
|
531
|
+
version: version_1.VERSION,
|
|
532
|
+
});
|
|
533
|
+
const report = await reportService.generate(repoPath, {
|
|
534
|
+
format: options.format,
|
|
535
|
+
output: options.output,
|
|
536
|
+
includeStack: options.includeStack,
|
|
537
|
+
verbose: options.verbose,
|
|
538
|
+
});
|
|
539
|
+
await reportService.output(report, options);
|
|
540
|
+
}
|
|
541
|
+
catch (error) {
|
|
542
|
+
ui.displayError(t('errors.cli.executionFailed'), error);
|
|
543
|
+
process.exit(1);
|
|
544
|
+
}
|
|
545
|
+
});
|
|
546
|
+
// Skill Commands
|
|
547
|
+
const skillCommand = program
|
|
548
|
+
.command('skill')
|
|
549
|
+
.description(t('commands.skill.description'));
|
|
550
|
+
skillCommand
|
|
551
|
+
.command('init')
|
|
552
|
+
.description(t('commands.skill.init.description'))
|
|
553
|
+
.argument('[repo-path]', 'Repository path', process.cwd())
|
|
554
|
+
.option('-f, --force', 'Overwrite existing files')
|
|
555
|
+
.option('--skills <skills...>', 'Specific skills to scaffold')
|
|
556
|
+
.action(async (repoPath, options) => {
|
|
557
|
+
try {
|
|
558
|
+
const { createSkillGenerator } = await Promise.resolve().then(() => __importStar(require('./generators/skills')));
|
|
559
|
+
const generator = createSkillGenerator({ repoPath });
|
|
560
|
+
const result = await generator.generate({
|
|
561
|
+
skills: options.skills,
|
|
562
|
+
force: options.force,
|
|
563
|
+
});
|
|
564
|
+
ui.displaySuccess(`Skills initialized in ${result.skillsDir}`);
|
|
565
|
+
ui.displayInfo('Generated', result.generatedSkills.join(', ') || 'none');
|
|
566
|
+
if (result.skippedSkills.length > 0) {
|
|
567
|
+
ui.displayInfo('Skipped (already exist)', result.skippedSkills.join(', '));
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
catch (error) {
|
|
571
|
+
ui.displayError('Failed to initialize skills', error);
|
|
572
|
+
process.exit(1);
|
|
573
|
+
}
|
|
574
|
+
});
|
|
575
|
+
skillCommand
|
|
576
|
+
.command('fill')
|
|
577
|
+
.description(t('commands.skill.fill.description'))
|
|
578
|
+
.argument('[repo-path]', 'Repository path', process.cwd())
|
|
579
|
+
.option('-o, --output <dir>', 'Output directory', '.context')
|
|
580
|
+
.option('-f, --force', 'Overwrite existing content')
|
|
581
|
+
.option('--skills <skills...>', 'Specific skills to fill')
|
|
582
|
+
.option('--model <model>', 'LLM model to use')
|
|
583
|
+
.option('--provider <provider>', 'LLM provider (anthropic, openai, google, openrouter)')
|
|
584
|
+
.option('--api-key <key>', 'API key for LLM provider')
|
|
585
|
+
.option('--base-url <url>', 'Base URL for custom LLM endpoint')
|
|
586
|
+
.option('--no-semantic', 'Disable semantic context mode')
|
|
587
|
+
.option('--use-lsp', 'Enable LSP for deeper analysis')
|
|
588
|
+
.option('-v, --verbose', 'Show detailed progress')
|
|
589
|
+
.option('--limit <number>', 'Limit number of skills to fill', parseInt)
|
|
590
|
+
.action(async (repoPath, options) => {
|
|
591
|
+
try {
|
|
592
|
+
const { SkillFillService } = await Promise.resolve().then(() => __importStar(require('./services/fill/skillFillService')));
|
|
593
|
+
const skillFillService = new SkillFillService({
|
|
594
|
+
ui,
|
|
595
|
+
t,
|
|
596
|
+
version: version_1.VERSION,
|
|
597
|
+
defaultModel: DEFAULT_MODEL,
|
|
598
|
+
});
|
|
599
|
+
const result = await skillFillService.run(repoPath, {
|
|
600
|
+
output: options.output,
|
|
601
|
+
skills: options.skills,
|
|
602
|
+
force: options.force,
|
|
603
|
+
model: options.model,
|
|
604
|
+
provider: options.provider,
|
|
605
|
+
apiKey: options.apiKey,
|
|
606
|
+
baseUrl: options.baseUrl,
|
|
607
|
+
semantic: options.semantic,
|
|
608
|
+
useLsp: options.useLsp,
|
|
609
|
+
verbose: options.verbose,
|
|
610
|
+
limit: options.limit,
|
|
611
|
+
});
|
|
612
|
+
if (result.filled.length > 0) {
|
|
613
|
+
ui.displaySuccess(t('success.skill.filled', { count: result.filled.length }));
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
catch (error) {
|
|
617
|
+
ui.displayError(t('errors.skill.fillFailed'), error);
|
|
618
|
+
process.exit(1);
|
|
619
|
+
}
|
|
620
|
+
});
|
|
621
|
+
skillCommand
|
|
622
|
+
.command('list')
|
|
623
|
+
.description(t('commands.skill.list.description'))
|
|
624
|
+
.argument('[repo-path]', 'Repository path', process.cwd())
|
|
625
|
+
.option('--json', 'Output as JSON')
|
|
626
|
+
.action(async (repoPath, options) => {
|
|
627
|
+
try {
|
|
628
|
+
const { createSkillRegistry, BUILT_IN_SKILLS } = await Promise.resolve().then(() => __importStar(require('./workflow/skills')));
|
|
629
|
+
const registry = createSkillRegistry(repoPath);
|
|
630
|
+
const discovered = await registry.discoverAll();
|
|
631
|
+
if (options.json) {
|
|
632
|
+
console.log(JSON.stringify({
|
|
633
|
+
builtIn: discovered.builtIn.map(s => s.slug),
|
|
634
|
+
custom: discovered.custom.map(s => s.slug),
|
|
635
|
+
total: discovered.all.length,
|
|
636
|
+
}, null, 2));
|
|
637
|
+
return;
|
|
638
|
+
}
|
|
639
|
+
console.log('\nBuilt-in Skills:');
|
|
640
|
+
for (const skill of discovered.builtIn) {
|
|
641
|
+
const scaffolded = discovered.all.find(s => s.slug === skill.slug && s.path.includes('.context'));
|
|
642
|
+
const status = scaffolded ? '[scaffolded]' : '[available]';
|
|
643
|
+
console.log(` ${skill.slug} ${status}`);
|
|
644
|
+
console.log(` ${skill.metadata.description}`);
|
|
645
|
+
}
|
|
646
|
+
if (discovered.custom.length > 0) {
|
|
647
|
+
console.log('\nCustom Skills:');
|
|
648
|
+
for (const skill of discovered.custom) {
|
|
649
|
+
console.log(` ${skill.slug}`);
|
|
650
|
+
console.log(` ${skill.metadata.description}`);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
console.log(`\nTotal: ${discovered.all.length} skills (${discovered.builtIn.length} built-in, ${discovered.custom.length} custom)`);
|
|
654
|
+
}
|
|
655
|
+
catch (error) {
|
|
656
|
+
ui.displayError('Failed to list skills', error);
|
|
657
|
+
process.exit(1);
|
|
658
|
+
}
|
|
659
|
+
});
|
|
660
|
+
skillCommand
|
|
661
|
+
.command('export')
|
|
662
|
+
.description(t('commands.skill.export.description'))
|
|
663
|
+
.argument('[repo-path]', 'Repository path', process.cwd())
|
|
664
|
+
.option('-p, --preset <preset>', 'Export preset: claude, gemini, codex, all', 'all')
|
|
665
|
+
.option('-f, --force', 'Overwrite existing files')
|
|
666
|
+
.option('--include-builtin', 'Include built-in skills even if not scaffolded')
|
|
667
|
+
.option('--dry-run', 'Preview changes without writing')
|
|
668
|
+
.action(async (repoPath, options) => {
|
|
669
|
+
try {
|
|
670
|
+
const { SkillExportService } = await Promise.resolve().then(() => __importStar(require('./services/export/skillExportService')));
|
|
671
|
+
const exportService = new SkillExportService({
|
|
672
|
+
ui,
|
|
673
|
+
t,
|
|
674
|
+
version: version_1.VERSION,
|
|
675
|
+
});
|
|
676
|
+
const result = await exportService.run(repoPath, {
|
|
677
|
+
preset: options.preset,
|
|
678
|
+
force: options.force,
|
|
679
|
+
includeBuiltIn: options.includeBuiltin,
|
|
680
|
+
dryRun: options.dryRun,
|
|
681
|
+
});
|
|
682
|
+
if (options.dryRun) {
|
|
683
|
+
ui.displayInfo('Dry run', 'No files were written');
|
|
684
|
+
}
|
|
685
|
+
else {
|
|
686
|
+
ui.displaySuccess(`Exported ${result.skillsExported.length} skills to ${result.targets.length} targets`);
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
catch (error) {
|
|
690
|
+
ui.displayError('Failed to export skills', error);
|
|
691
|
+
process.exit(1);
|
|
692
|
+
}
|
|
693
|
+
});
|
|
694
|
+
skillCommand
|
|
695
|
+
.command('create <name>')
|
|
696
|
+
.description(t('commands.skill.create.description'))
|
|
697
|
+
.argument('[repo-path]', 'Repository path', process.cwd())
|
|
698
|
+
.option('-d, --description <text>', 'Skill description')
|
|
699
|
+
.option('--phases <phases...>', 'PREVC phases (P, R, E, V, C)')
|
|
700
|
+
.option('-f, --force', 'Overwrite if exists')
|
|
701
|
+
.action(async (name, repoPath, options) => {
|
|
702
|
+
try {
|
|
703
|
+
const { createSkillGenerator } = await Promise.resolve().then(() => __importStar(require('./generators/skills')));
|
|
704
|
+
const generator = createSkillGenerator({ repoPath });
|
|
705
|
+
const skillPath = await generator.generateCustomSkill({
|
|
706
|
+
name,
|
|
707
|
+
description: options.description || `TODO: Describe when to use ${name}`,
|
|
708
|
+
phases: options.phases,
|
|
709
|
+
force: options.force,
|
|
710
|
+
});
|
|
711
|
+
ui.displaySuccess(`Created skill: ${name}`);
|
|
712
|
+
ui.displayInfo('Path', skillPath);
|
|
713
|
+
}
|
|
714
|
+
catch (error) {
|
|
715
|
+
ui.displayError('Failed to create skill', error);
|
|
716
|
+
process.exit(1);
|
|
717
|
+
}
|
|
718
|
+
});
|
|
719
|
+
// PREVC Workflow Commands
|
|
720
|
+
const workflowCommand = program
|
|
721
|
+
.command('workflow')
|
|
722
|
+
.description('PREVC workflow management (Planning, Review, Execution, Validation, Confirmation)');
|
|
723
|
+
// Helper to create workflow service dependencies
|
|
724
|
+
const getWorkflowDeps = () => ({
|
|
725
|
+
ui: {
|
|
726
|
+
displaySuccess: (msg) => ui.displaySuccess(msg),
|
|
727
|
+
displayError: (msg, err) => ui.displayError(msg, err),
|
|
728
|
+
displayInfo: (title, detail) => ui.displayInfo(title, detail || '')
|
|
729
|
+
}
|
|
730
|
+
});
|
|
731
|
+
workflowCommand
|
|
732
|
+
.command('init <name>')
|
|
733
|
+
.description('Initialize a new PREVC workflow')
|
|
734
|
+
.option('-d, --description <text>', 'Project description for scale detection')
|
|
735
|
+
.option('-s, --scale <scale>', 'Project scale: QUICK, SMALL, MEDIUM, LARGE, ENTERPRISE')
|
|
736
|
+
.option('-r, --repo-path <path>', 'Repository path', process.cwd())
|
|
737
|
+
.action(async (name, options) => {
|
|
738
|
+
try {
|
|
739
|
+
const workflowService = new workflow_1.WorkflowService(options.repoPath, getWorkflowDeps());
|
|
740
|
+
const status = await workflowService.init({
|
|
741
|
+
name,
|
|
742
|
+
description: options.description,
|
|
743
|
+
scale: options.scale
|
|
744
|
+
});
|
|
745
|
+
ui.displaySuccess(`Workflow PREVC initialized: ${name}`);
|
|
746
|
+
ui.displayInfo('Scale', (0, workflow_2.getScaleName)(status.project.scale));
|
|
747
|
+
ui.displayInfo('Current Phase', `${status.project.current_phase} - ${workflow_2.PHASE_NAMES_PT[status.project.current_phase]}`);
|
|
748
|
+
}
|
|
749
|
+
catch (error) {
|
|
750
|
+
ui.displayError('Failed to initialize workflow', error);
|
|
751
|
+
process.exit(1);
|
|
752
|
+
}
|
|
753
|
+
});
|
|
754
|
+
workflowCommand
|
|
755
|
+
.command('status')
|
|
756
|
+
.description('Show current workflow status')
|
|
757
|
+
.option('-r, --repo-path <path>', 'Repository path', process.cwd())
|
|
758
|
+
.action(async (options) => {
|
|
759
|
+
try {
|
|
760
|
+
const workflowService = new workflow_1.WorkflowService(options.repoPath, getWorkflowDeps());
|
|
761
|
+
if (!await workflowService.hasWorkflow()) {
|
|
762
|
+
ui.displayError('No workflow found. Run "workflow init <name>" first.');
|
|
763
|
+
process.exit(1);
|
|
764
|
+
}
|
|
765
|
+
const formattedStatus = await workflowService.getFormattedStatus();
|
|
766
|
+
console.log(formattedStatus);
|
|
767
|
+
const actions = await workflowService.getRecommendedActions();
|
|
768
|
+
if (actions.length > 0) {
|
|
769
|
+
console.log('\nRecommended actions:');
|
|
770
|
+
actions.forEach((action, i) => console.log(` ${i + 1}. ${action}`));
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
catch (error) {
|
|
774
|
+
ui.displayError('Failed to get workflow status', error);
|
|
775
|
+
process.exit(1);
|
|
776
|
+
}
|
|
777
|
+
});
|
|
778
|
+
workflowCommand
|
|
779
|
+
.command('advance')
|
|
780
|
+
.description('Complete current phase and advance to next')
|
|
781
|
+
.option('-r, --repo-path <path>', 'Repository path', process.cwd())
|
|
782
|
+
.option('-o, --outputs <files...>', 'Output files generated in current phase')
|
|
783
|
+
.action(async (options) => {
|
|
784
|
+
try {
|
|
785
|
+
const workflowService = new workflow_1.WorkflowService(options.repoPath, getWorkflowDeps());
|
|
786
|
+
if (!await workflowService.hasWorkflow()) {
|
|
787
|
+
ui.displayError('No workflow found. Run "workflow init <name>" first.');
|
|
788
|
+
process.exit(1);
|
|
789
|
+
}
|
|
790
|
+
const nextPhase = await workflowService.advance(options.outputs);
|
|
791
|
+
if (nextPhase) {
|
|
792
|
+
ui.displaySuccess(`Advanced to phase: ${nextPhase} - ${workflow_2.PHASE_NAMES_PT[nextPhase]}`);
|
|
793
|
+
}
|
|
794
|
+
else {
|
|
795
|
+
ui.displaySuccess('Workflow completed!');
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
catch (error) {
|
|
799
|
+
ui.displayError('Failed to advance workflow', error);
|
|
800
|
+
process.exit(1);
|
|
801
|
+
}
|
|
802
|
+
});
|
|
803
|
+
workflowCommand
|
|
804
|
+
.command('handoff <from> <to>')
|
|
805
|
+
.description('Perform handoff between roles')
|
|
806
|
+
.option('-r, --repo-path <path>', 'Repository path', process.cwd())
|
|
807
|
+
.option('-a, --artifacts <files...>', 'Artifacts to hand off')
|
|
808
|
+
.action(async (from, to, options) => {
|
|
809
|
+
try {
|
|
810
|
+
const workflowService = new workflow_1.WorkflowService(options.repoPath, getWorkflowDeps());
|
|
811
|
+
if (!await workflowService.hasWorkflow()) {
|
|
812
|
+
ui.displayError('No workflow found. Run "workflow init <name>" first.');
|
|
813
|
+
process.exit(1);
|
|
814
|
+
}
|
|
815
|
+
await workflowService.handoff(from, to, options.artifacts || []);
|
|
816
|
+
ui.displaySuccess(`Handoff: ${workflow_2.ROLE_DISPLAY_NAMES[from]} → ${workflow_2.ROLE_DISPLAY_NAMES[to]}`);
|
|
817
|
+
}
|
|
818
|
+
catch (error) {
|
|
819
|
+
ui.displayError('Failed to perform handoff', error);
|
|
820
|
+
process.exit(1);
|
|
821
|
+
}
|
|
822
|
+
});
|
|
823
|
+
workflowCommand
|
|
824
|
+
.command('collaborate <topic>')
|
|
825
|
+
.description('Start a collaboration session between roles')
|
|
826
|
+
.option('-r, --repo-path <path>', 'Repository path', process.cwd())
|
|
827
|
+
.option('-p, --participants <roles...>', 'Participating roles')
|
|
828
|
+
.action(async (topic, options) => {
|
|
829
|
+
try {
|
|
830
|
+
const workflowService = new workflow_1.WorkflowService(options.repoPath, getWorkflowDeps());
|
|
831
|
+
const session = await workflowService.startCollaboration(topic, options.participants);
|
|
832
|
+
ui.displaySuccess(`Collaboration started: ${topic}`);
|
|
833
|
+
ui.displayInfo('Session ID', session.getId());
|
|
834
|
+
ui.displayInfo('Participants', session.getParticipantNames().join(', '));
|
|
835
|
+
console.log('\nUse MCP tools to contribute and synthesize the collaboration.');
|
|
836
|
+
}
|
|
837
|
+
catch (error) {
|
|
838
|
+
ui.displayError('Failed to start collaboration', error);
|
|
839
|
+
process.exit(1);
|
|
840
|
+
}
|
|
841
|
+
});
|
|
842
|
+
workflowCommand
|
|
843
|
+
.command('role <action> <role>')
|
|
844
|
+
.description('Manage role status (start/complete)')
|
|
845
|
+
.option('-r, --repo-path <path>', 'Repository path', process.cwd())
|
|
846
|
+
.option('-o, --outputs <files...>', 'Output files (for complete action)')
|
|
847
|
+
.action(async (action, role, options) => {
|
|
848
|
+
try {
|
|
849
|
+
const workflowService = new workflow_1.WorkflowService(options.repoPath, getWorkflowDeps());
|
|
850
|
+
if (!await workflowService.hasWorkflow()) {
|
|
851
|
+
ui.displayError('No workflow found. Run "workflow init <name>" first.');
|
|
852
|
+
process.exit(1);
|
|
853
|
+
}
|
|
854
|
+
if (action === 'start') {
|
|
855
|
+
await workflowService.startRole(role);
|
|
856
|
+
ui.displaySuccess(`Started role: ${workflow_2.ROLE_DISPLAY_NAMES[role]}`);
|
|
857
|
+
}
|
|
858
|
+
else if (action === 'complete') {
|
|
859
|
+
await workflowService.completeRole(role, options.outputs || []);
|
|
860
|
+
ui.displaySuccess(`Completed role: ${workflow_2.ROLE_DISPLAY_NAMES[role]}`);
|
|
861
|
+
}
|
|
862
|
+
else {
|
|
863
|
+
ui.displayError(`Unknown action: ${action}. Use 'start' or 'complete'.`);
|
|
864
|
+
process.exit(1);
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
catch (error) {
|
|
868
|
+
ui.displayError('Failed to manage role', error);
|
|
869
|
+
process.exit(1);
|
|
870
|
+
}
|
|
871
|
+
});
|
|
361
872
|
async function runInit(repoPath, type, rawOptions) {
|
|
362
873
|
await initService.run(repoPath, type, rawOptions);
|
|
363
874
|
}
|
|
@@ -405,31 +916,63 @@ async function selectLocale(showWelcome) {
|
|
|
405
916
|
translateFn = (0, i18n_1.createTranslator)(normalizedLocale);
|
|
406
917
|
if (showWelcome) {
|
|
407
918
|
ui.displayWelcome(version_1.VERSION);
|
|
919
|
+
ui.displayPrevcExplanation();
|
|
408
920
|
}
|
|
409
921
|
}
|
|
410
922
|
async function runInteractive() {
|
|
411
|
-
await selectLocale(
|
|
923
|
+
await selectLocale(false); // Don't show welcome yet
|
|
924
|
+
// Show welcome screen with PREVC explanation
|
|
925
|
+
ui.displayWelcome(version_1.VERSION);
|
|
926
|
+
ui.displayPrevcExplanation();
|
|
927
|
+
// Wait for user to press Enter
|
|
928
|
+
await inquirer_1.default.prompt([
|
|
929
|
+
{
|
|
930
|
+
type: 'input',
|
|
931
|
+
name: 'continue',
|
|
932
|
+
message: t('prompts.pressEnter'),
|
|
933
|
+
},
|
|
934
|
+
]);
|
|
935
|
+
console.log('\n');
|
|
412
936
|
const projectPath = process.cwd();
|
|
413
937
|
const detector = new state_1.StateDetector({ projectPath });
|
|
414
938
|
const result = await detector.detect();
|
|
415
|
-
//
|
|
939
|
+
// Get quick stats for compact status
|
|
940
|
+
const quickSyncService = new quickSync_1.QuickSyncService({
|
|
941
|
+
ui,
|
|
942
|
+
t,
|
|
943
|
+
version: version_1.VERSION,
|
|
944
|
+
defaultModel: DEFAULT_MODEL,
|
|
945
|
+
});
|
|
946
|
+
const stats = await quickSyncService.getStats(projectPath);
|
|
947
|
+
// Display compact header
|
|
416
948
|
console.log('');
|
|
417
|
-
|
|
418
|
-
|
|
949
|
+
console.log(`${theme_1.colors.primaryBold(`${version_1.PACKAGE_NAME}`)} ${theme_1.colors.secondary(`v${version_1.VERSION}`)}`);
|
|
950
|
+
console.log(`${theme_1.colors.secondary('Project:')} ${projectPath}`);
|
|
951
|
+
// Show compact status line based on state
|
|
419
952
|
switch (result.state) {
|
|
420
953
|
case 'new':
|
|
421
|
-
console.log(theme_1.colors.secondaryDim('
|
|
954
|
+
console.log(theme_1.colors.secondaryDim(t('status.new')));
|
|
422
955
|
break;
|
|
423
956
|
case 'unfilled':
|
|
424
|
-
console.log(theme_1.colors.secondaryDim(
|
|
957
|
+
console.log(theme_1.colors.secondaryDim(t('status.unfilled', { count: result.details.unfilledFiles })));
|
|
425
958
|
break;
|
|
426
959
|
case 'outdated':
|
|
427
|
-
console.log(theme_1.colors.warning(
|
|
960
|
+
console.log(theme_1.colors.warning(t('status.outdated', {
|
|
961
|
+
docs: stats.docs,
|
|
962
|
+
days: result.details.daysBehind || 0,
|
|
963
|
+
agents: stats.agents,
|
|
964
|
+
skills: stats.skills
|
|
965
|
+
})));
|
|
428
966
|
break;
|
|
429
967
|
case 'ready':
|
|
430
|
-
console.log(theme_1.colors.success(
|
|
968
|
+
console.log(theme_1.colors.success(t('status.compact', {
|
|
969
|
+
docs: stats.docs,
|
|
970
|
+
agents: stats.agents,
|
|
971
|
+
skills: stats.skills
|
|
972
|
+
})));
|
|
431
973
|
break;
|
|
432
974
|
}
|
|
975
|
+
console.log('');
|
|
433
976
|
// Handle state-based flow
|
|
434
977
|
if (result.state === 'new') {
|
|
435
978
|
const { action } = await inquirer_1.default.prompt([
|
|
@@ -438,15 +981,20 @@ async function runInteractive() {
|
|
|
438
981
|
name: 'action',
|
|
439
982
|
message: t('prompts.main.action'),
|
|
440
983
|
choices: [
|
|
441
|
-
{ name: t('prompts.main.choice.
|
|
984
|
+
{ name: t('prompts.main.choice.quickSetup'), value: 'create' },
|
|
985
|
+
{ name: t('prompts.main.choice.scaffoldOnly'), value: 'scaffold' },
|
|
442
986
|
{ name: t('prompts.main.choice.exit'), value: 'exit' }
|
|
443
987
|
]
|
|
444
988
|
}
|
|
445
989
|
]);
|
|
446
990
|
if (action === 'create') {
|
|
447
|
-
// Run init + fill automatically
|
|
991
|
+
// Run init + fill with AI + LSP automatically
|
|
448
992
|
await runQuickSetup(projectPath);
|
|
449
993
|
}
|
|
994
|
+
else if (action === 'scaffold') {
|
|
995
|
+
// Scaffold only without AI fill
|
|
996
|
+
await runInteractiveScaffold();
|
|
997
|
+
}
|
|
450
998
|
return;
|
|
451
999
|
}
|
|
452
1000
|
if (result.state === 'unfilled') {
|
|
@@ -475,6 +1023,27 @@ async function runInteractive() {
|
|
|
475
1023
|
await runFullMenu(result.state === 'outdated' ? result.details.daysBehind : undefined);
|
|
476
1024
|
}
|
|
477
1025
|
async function runQuickSetup(projectPath) {
|
|
1026
|
+
// AI-first: Detect smart defaults automatically
|
|
1027
|
+
const defaults = await (0, prompts_1.detectSmartDefaults)();
|
|
1028
|
+
// If no API key found, prompt for one
|
|
1029
|
+
let llmConfig = null;
|
|
1030
|
+
if (defaults.apiKeyConfigured && defaults.provider) {
|
|
1031
|
+
// Auto-detected config
|
|
1032
|
+
llmConfig = {
|
|
1033
|
+
provider: defaults.provider,
|
|
1034
|
+
model: DEFAULT_MODEL,
|
|
1035
|
+
apiKey: (0, providerFactory_1.getApiKeyFromEnv)(defaults.provider),
|
|
1036
|
+
};
|
|
1037
|
+
console.log(theme_1.colors.secondary(` Auto-detected: ${defaults.provider} API key found`));
|
|
1038
|
+
}
|
|
1039
|
+
else {
|
|
1040
|
+
// Need to get API key from user
|
|
1041
|
+
llmConfig = await (0, prompts_1.promptLLMConfig)(t);
|
|
1042
|
+
if (!llmConfig) {
|
|
1043
|
+
ui.displayInfo(t('info.setup.incomplete.title'), t('info.setup.incomplete.detail'));
|
|
1044
|
+
return;
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
478
1047
|
const { confirm } = await inquirer_1.default.prompt([
|
|
479
1048
|
{
|
|
480
1049
|
type: 'confirm',
|
|
@@ -486,11 +1055,11 @@ async function runQuickSetup(projectPath) {
|
|
|
486
1055
|
if (!confirm) {
|
|
487
1056
|
return;
|
|
488
1057
|
}
|
|
489
|
-
// Run init
|
|
1058
|
+
// Run init with semantic analysis
|
|
490
1059
|
ui.startSpinner(t('spinner.setup.creatingStructure'));
|
|
491
1060
|
try {
|
|
492
|
-
const
|
|
493
|
-
await
|
|
1061
|
+
const localInitService = new initService_1.InitService({ ui, t, version: version_1.VERSION });
|
|
1062
|
+
await localInitService.run(projectPath, 'both', {
|
|
494
1063
|
semantic: true
|
|
495
1064
|
});
|
|
496
1065
|
ui.stopSpinner();
|
|
@@ -500,22 +1069,27 @@ async function runQuickSetup(projectPath) {
|
|
|
500
1069
|
ui.displayError('Failed to create structure', error);
|
|
501
1070
|
return;
|
|
502
1071
|
}
|
|
503
|
-
//
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
1072
|
+
// Initialize skills too (AI-first)
|
|
1073
|
+
try {
|
|
1074
|
+
const { createSkillGenerator } = await Promise.resolve().then(() => __importStar(require('./generators/skills')));
|
|
1075
|
+
const skillGenerator = createSkillGenerator({ repoPath: projectPath });
|
|
1076
|
+
await skillGenerator.generate({});
|
|
508
1077
|
}
|
|
1078
|
+
catch {
|
|
1079
|
+
// Skills init failure is not critical
|
|
1080
|
+
}
|
|
1081
|
+
// Fill with AI + LSP (default behavior)
|
|
509
1082
|
ui.startSpinner(t('spinner.setup.fillingDocs'));
|
|
510
1083
|
try {
|
|
511
|
-
const
|
|
512
|
-
await
|
|
1084
|
+
const localFillService = new fillService_1.FillService({ ui, t, version: version_1.VERSION, defaultModel: DEFAULT_MODEL });
|
|
1085
|
+
await localFillService.run(projectPath, {
|
|
513
1086
|
model: llmConfig.model,
|
|
514
1087
|
provider: llmConfig.provider,
|
|
515
1088
|
apiKey: llmConfig.apiKey,
|
|
516
1089
|
baseUrl: llmConfig.baseUrl,
|
|
517
1090
|
verbose: false,
|
|
518
|
-
semantic: true
|
|
1091
|
+
semantic: true,
|
|
1092
|
+
useLsp: true // LSP enabled by default
|
|
519
1093
|
});
|
|
520
1094
|
ui.stopSpinner();
|
|
521
1095
|
ui.displaySuccess(t('success.setup.docsCreated'));
|
|
@@ -532,12 +1106,21 @@ async function runFullMenu(daysBehind) {
|
|
|
532
1106
|
const updateLabel = daysBehind
|
|
533
1107
|
? t('prompts.main.choice.updateDocsBehind', { daysBehind })
|
|
534
1108
|
: t('prompts.main.choice.updateDocs');
|
|
1109
|
+
// New menu structure with separators - organized by frequency of use
|
|
535
1110
|
const choices = [
|
|
536
|
-
|
|
1111
|
+
// Quick Actions (most used)
|
|
1112
|
+
{ name: t('prompts.main.choice.quickSync'), value: 'quickSync' },
|
|
1113
|
+
{ name: t('prompts.main.choice.startWorkflow'), value: 'workflow' },
|
|
1114
|
+
{ name: t('prompts.main.choice.createPlan'), value: 'plan' },
|
|
1115
|
+
new inquirer_1.default.Separator(),
|
|
1116
|
+
// Manage
|
|
537
1117
|
{ name: updateLabel, value: 'fill' },
|
|
538
|
-
{ name: t('prompts.main.choice.
|
|
1118
|
+
{ name: t('prompts.main.choice.manageSkills'), value: 'skills' },
|
|
1119
|
+
{ name: t('prompts.main.choice.manageAgents'), value: 'agents' },
|
|
1120
|
+
new inquirer_1.default.Separator(),
|
|
1121
|
+
// Config
|
|
539
1122
|
{ name: t('prompts.main.choice.rescaffold'), value: 'scaffold' },
|
|
540
|
-
{ name: t('prompts.main.choice.
|
|
1123
|
+
{ name: t('prompts.main.choice.settings'), value: 'settings' },
|
|
541
1124
|
{ name: t('prompts.main.choice.exit'), value: 'exit' }
|
|
542
1125
|
];
|
|
543
1126
|
const { action } = await inquirer_1.default.prompt([
|
|
@@ -548,15 +1131,18 @@ async function runFullMenu(daysBehind) {
|
|
|
548
1131
|
choices
|
|
549
1132
|
}
|
|
550
1133
|
]);
|
|
551
|
-
if (action === '
|
|
552
|
-
await
|
|
1134
|
+
if (action === 'settings') {
|
|
1135
|
+
await runSettings();
|
|
553
1136
|
continue;
|
|
554
1137
|
}
|
|
555
1138
|
if (action === 'exit') {
|
|
556
1139
|
exitRequested = true;
|
|
557
1140
|
break;
|
|
558
1141
|
}
|
|
559
|
-
if (action === '
|
|
1142
|
+
if (action === 'quickSync') {
|
|
1143
|
+
await runQuickSync();
|
|
1144
|
+
}
|
|
1145
|
+
else if (action === 'scaffold') {
|
|
560
1146
|
await runInteractiveScaffold();
|
|
561
1147
|
}
|
|
562
1148
|
else if (action === 'fill') {
|
|
@@ -565,8 +1151,14 @@ async function runFullMenu(daysBehind) {
|
|
|
565
1151
|
else if (action === 'plan') {
|
|
566
1152
|
await runInteractivePlan();
|
|
567
1153
|
}
|
|
568
|
-
else if (action === '
|
|
569
|
-
await
|
|
1154
|
+
else if (action === 'agents') {
|
|
1155
|
+
await runManageAgents();
|
|
1156
|
+
}
|
|
1157
|
+
else if (action === 'workflow') {
|
|
1158
|
+
await runInteractiveWorkflow();
|
|
1159
|
+
}
|
|
1160
|
+
else if (action === 'skills') {
|
|
1161
|
+
await runInteractiveSkills();
|
|
570
1162
|
}
|
|
571
1163
|
ui.displayInfo(t('info.interactive.returning.title'), t('info.interactive.returning.detail'));
|
|
572
1164
|
}
|
|
@@ -591,19 +1183,24 @@ async function runInteractiveScaffold() {
|
|
|
591
1183
|
default: defaultOutput
|
|
592
1184
|
}
|
|
593
1185
|
]);
|
|
594
|
-
|
|
1186
|
+
// Multi-select checkbox for scaffold components
|
|
1187
|
+
const { scaffoldComponents } = await inquirer_1.default.prompt([
|
|
595
1188
|
{
|
|
596
|
-
type: '
|
|
597
|
-
name: '
|
|
598
|
-
message: t('prompts.scaffold.
|
|
1189
|
+
type: 'checkbox',
|
|
1190
|
+
name: 'scaffoldComponents',
|
|
1191
|
+
message: t('prompts.scaffold.selectComponents'),
|
|
599
1192
|
choices: [
|
|
600
|
-
{ name: t('prompts.scaffold.
|
|
601
|
-
{ name: t('prompts.scaffold.
|
|
602
|
-
{ name: t('prompts.scaffold.
|
|
603
|
-
]
|
|
604
|
-
default: 'both'
|
|
1193
|
+
{ name: t('prompts.scaffold.componentDocs'), value: 'docs', checked: true },
|
|
1194
|
+
{ name: t('prompts.scaffold.componentAgents'), value: 'agents', checked: true },
|
|
1195
|
+
{ name: t('prompts.scaffold.componentSkills'), value: 'skills', checked: false }
|
|
1196
|
+
]
|
|
605
1197
|
}
|
|
606
1198
|
]);
|
|
1199
|
+
// Validate: at least one component must be selected
|
|
1200
|
+
if (scaffoldComponents.length === 0) {
|
|
1201
|
+
ui.displayWarning(t('warnings.scaffold.noneSelected'));
|
|
1202
|
+
return;
|
|
1203
|
+
}
|
|
607
1204
|
const { verbose } = await inquirer_1.default.prompt([
|
|
608
1205
|
{
|
|
609
1206
|
type: 'confirm',
|
|
@@ -612,11 +1209,58 @@ async function runInteractiveScaffold() {
|
|
|
612
1209
|
default: false
|
|
613
1210
|
}
|
|
614
1211
|
]);
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
1212
|
+
// Determine what to scaffold
|
|
1213
|
+
const scaffoldDocs = scaffoldComponents.includes('docs');
|
|
1214
|
+
const scaffoldAgents = scaffoldComponents.includes('agents');
|
|
1215
|
+
const scaffoldSkills = scaffoldComponents.includes('skills');
|
|
1216
|
+
// Scaffold docs and/or agents if selected
|
|
1217
|
+
if (scaffoldDocs || scaffoldAgents) {
|
|
1218
|
+
let scaffoldType;
|
|
1219
|
+
if (scaffoldDocs && scaffoldAgents) {
|
|
1220
|
+
scaffoldType = 'both';
|
|
1221
|
+
}
|
|
1222
|
+
else if (scaffoldDocs) {
|
|
1223
|
+
scaffoldType = 'docs';
|
|
1224
|
+
}
|
|
1225
|
+
else {
|
|
1226
|
+
scaffoldType = 'agents';
|
|
1227
|
+
}
|
|
1228
|
+
await runInit(resolvedRepo, scaffoldType, {
|
|
1229
|
+
output: outputDir,
|
|
1230
|
+
verbose,
|
|
1231
|
+
semantic: true
|
|
1232
|
+
});
|
|
1233
|
+
}
|
|
1234
|
+
// Scaffold skills if selected
|
|
1235
|
+
if (scaffoldSkills) {
|
|
1236
|
+
try {
|
|
1237
|
+
const { createSkillGenerator } = await Promise.resolve().then(() => __importStar(require('./generators/skills')));
|
|
1238
|
+
const generator = createSkillGenerator({
|
|
1239
|
+
repoPath: resolvedRepo,
|
|
1240
|
+
outputDir
|
|
1241
|
+
});
|
|
1242
|
+
// Display step for skills scaffolding
|
|
1243
|
+
const stepNumber = (scaffoldDocs || scaffoldAgents) ? 4 : 1;
|
|
1244
|
+
const totalSteps = (scaffoldDocs || scaffoldAgents) ? 4 : 1;
|
|
1245
|
+
ui.displayStep(stepNumber, totalSteps, t('steps.init.skills'));
|
|
1246
|
+
ui.startSpinner(t('spinner.skills.creating'));
|
|
1247
|
+
const result = await generator.generate({});
|
|
1248
|
+
ui.updateSpinner(t('spinner.skills.created', { count: result.generatedSkills.length }), 'success');
|
|
1249
|
+
// If only skills were selected, show success message
|
|
1250
|
+
if (!scaffoldDocs && !scaffoldAgents) {
|
|
1251
|
+
ui.displaySuccess(t('success.skill.initialized', { path: result.skillsDir }));
|
|
1252
|
+
}
|
|
1253
|
+
if (result.generatedSkills.length > 0) {
|
|
1254
|
+
ui.displayInfo(t('info.skill.generated'), result.generatedSkills.join(', '));
|
|
1255
|
+
}
|
|
1256
|
+
if (result.skippedSkills.length > 0) {
|
|
1257
|
+
ui.displayInfo(t('info.skill.skipped'), result.skippedSkills.join(', '));
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
catch (error) {
|
|
1261
|
+
ui.displayError(t('errors.skill.initFailed'), error);
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
620
1264
|
}
|
|
621
1265
|
async function runInteractiveLlmFill() {
|
|
622
1266
|
const defaults = await (0, prompts_1.detectSmartDefaults)();
|
|
@@ -1036,6 +1680,638 @@ async function runInteractiveSync() {
|
|
|
1036
1680
|
}
|
|
1037
1681
|
}
|
|
1038
1682
|
}
|
|
1683
|
+
async function createNewWorkflow(workflowService) {
|
|
1684
|
+
const { name, description, scale } = await inquirer_1.default.prompt([
|
|
1685
|
+
{
|
|
1686
|
+
type: 'input',
|
|
1687
|
+
name: 'name',
|
|
1688
|
+
message: t('prompts.workflow.projectName'),
|
|
1689
|
+
validate: (input) => input.trim().length > 0 || t('prompts.workflow.projectNameRequired')
|
|
1690
|
+
},
|
|
1691
|
+
{
|
|
1692
|
+
type: 'input',
|
|
1693
|
+
name: 'description',
|
|
1694
|
+
message: t('prompts.workflow.description'),
|
|
1695
|
+
default: ''
|
|
1696
|
+
},
|
|
1697
|
+
{
|
|
1698
|
+
type: 'list',
|
|
1699
|
+
name: 'scale',
|
|
1700
|
+
message: t('prompts.workflow.scale'),
|
|
1701
|
+
choices: [
|
|
1702
|
+
{ name: t('prompts.workflow.scale.auto'), value: '' },
|
|
1703
|
+
{ name: t('prompts.workflow.scale.quick'), value: 'QUICK' },
|
|
1704
|
+
{ name: t('prompts.workflow.scale.small'), value: 'SMALL' },
|
|
1705
|
+
{ name: t('prompts.workflow.scale.medium'), value: 'MEDIUM' },
|
|
1706
|
+
{ name: t('prompts.workflow.scale.large'), value: 'LARGE' },
|
|
1707
|
+
{ name: t('prompts.workflow.scale.enterprise'), value: 'ENTERPRISE' }
|
|
1708
|
+
],
|
|
1709
|
+
default: ''
|
|
1710
|
+
}
|
|
1711
|
+
]);
|
|
1712
|
+
try {
|
|
1713
|
+
const status = await workflowService.init({
|
|
1714
|
+
name: name.trim(),
|
|
1715
|
+
description: description.trim() || undefined,
|
|
1716
|
+
scale: scale || undefined
|
|
1717
|
+
});
|
|
1718
|
+
ui.displaySuccess(t('success.workflow.initialized', { name }));
|
|
1719
|
+
ui.displayInfo(t('info.workflow.scale'), (0, workflow_2.getScaleName)(status.project.scale));
|
|
1720
|
+
ui.displayInfo(t('info.workflow.currentPhase'), `${status.project.current_phase} - ${workflow_2.PHASE_NAMES_PT[status.project.current_phase]}`);
|
|
1721
|
+
return true;
|
|
1722
|
+
}
|
|
1723
|
+
catch (error) {
|
|
1724
|
+
ui.displayError(t('errors.workflow.initFailed'), error);
|
|
1725
|
+
return false;
|
|
1726
|
+
}
|
|
1727
|
+
}
|
|
1728
|
+
async function runInteractiveWorkflow() {
|
|
1729
|
+
const projectPath = process.cwd();
|
|
1730
|
+
const workflowService = new workflow_1.WorkflowService(projectPath, getWorkflowDeps());
|
|
1731
|
+
const hasWorkflow = await workflowService.hasWorkflow();
|
|
1732
|
+
if (!hasWorkflow) {
|
|
1733
|
+
// No workflow exists - offer to create one
|
|
1734
|
+
const { createNew } = await inquirer_1.default.prompt([
|
|
1735
|
+
{
|
|
1736
|
+
type: 'confirm',
|
|
1737
|
+
name: 'createNew',
|
|
1738
|
+
message: t('prompts.workflow.noWorkflowFound'),
|
|
1739
|
+
default: true
|
|
1740
|
+
}
|
|
1741
|
+
]);
|
|
1742
|
+
if (!createNew) {
|
|
1743
|
+
return;
|
|
1744
|
+
}
|
|
1745
|
+
await createNewWorkflow(workflowService);
|
|
1746
|
+
return;
|
|
1747
|
+
}
|
|
1748
|
+
// Workflow exists - check if complete
|
|
1749
|
+
const isComplete = await workflowService.isComplete();
|
|
1750
|
+
if (isComplete) {
|
|
1751
|
+
// Workflow is complete - offer to start a new one or view status
|
|
1752
|
+
console.log('');
|
|
1753
|
+
const formattedStatus = await workflowService.getFormattedStatus();
|
|
1754
|
+
console.log(formattedStatus);
|
|
1755
|
+
const { completeAction } = await inquirer_1.default.prompt([
|
|
1756
|
+
{
|
|
1757
|
+
type: 'list',
|
|
1758
|
+
name: 'completeAction',
|
|
1759
|
+
message: t('prompts.workflow.workflowComplete'),
|
|
1760
|
+
choices: [
|
|
1761
|
+
{ name: t('prompts.workflow.action.newWorkflow'), value: 'newWorkflow' },
|
|
1762
|
+
{ name: t('prompts.workflow.action.viewStatus'), value: 'viewStatus' },
|
|
1763
|
+
{ name: t('prompts.workflow.action.back'), value: 'back' }
|
|
1764
|
+
]
|
|
1765
|
+
}
|
|
1766
|
+
]);
|
|
1767
|
+
if (completeAction === 'newWorkflow') {
|
|
1768
|
+
const { confirmNew } = await inquirer_1.default.prompt([
|
|
1769
|
+
{
|
|
1770
|
+
type: 'confirm',
|
|
1771
|
+
name: 'confirmNew',
|
|
1772
|
+
message: t('prompts.workflow.confirmNewWorkflow'),
|
|
1773
|
+
default: true
|
|
1774
|
+
}
|
|
1775
|
+
]);
|
|
1776
|
+
if (confirmNew) {
|
|
1777
|
+
await createNewWorkflow(workflowService);
|
|
1778
|
+
}
|
|
1779
|
+
}
|
|
1780
|
+
// 'viewStatus' and 'back' just return
|
|
1781
|
+
return;
|
|
1782
|
+
}
|
|
1783
|
+
// Workflow exists and is not complete - show status and actions
|
|
1784
|
+
let continueMenu = true;
|
|
1785
|
+
while (continueMenu) {
|
|
1786
|
+
console.log('');
|
|
1787
|
+
const formattedStatus = await workflowService.getFormattedStatus();
|
|
1788
|
+
console.log(formattedStatus);
|
|
1789
|
+
const choices = [];
|
|
1790
|
+
choices.push({ name: t('prompts.workflow.action.advance'), value: 'advance' });
|
|
1791
|
+
choices.push({ name: t('prompts.workflow.action.newWorkflow'), value: 'newWorkflow' });
|
|
1792
|
+
choices.push({ name: t('prompts.workflow.action.refresh'), value: 'status' });
|
|
1793
|
+
choices.push({ name: t('prompts.workflow.action.back'), value: 'back' });
|
|
1794
|
+
const { action } = await inquirer_1.default.prompt([
|
|
1795
|
+
{
|
|
1796
|
+
type: 'list',
|
|
1797
|
+
name: 'action',
|
|
1798
|
+
message: t('prompts.workflow.action'),
|
|
1799
|
+
choices
|
|
1800
|
+
}
|
|
1801
|
+
]);
|
|
1802
|
+
if (action === 'back') {
|
|
1803
|
+
continueMenu = false;
|
|
1804
|
+
}
|
|
1805
|
+
else if (action === 'newWorkflow') {
|
|
1806
|
+
const { confirmNew } = await inquirer_1.default.prompt([
|
|
1807
|
+
{
|
|
1808
|
+
type: 'confirm',
|
|
1809
|
+
name: 'confirmNew',
|
|
1810
|
+
message: t('prompts.workflow.confirmNewWorkflow'),
|
|
1811
|
+
default: false
|
|
1812
|
+
}
|
|
1813
|
+
]);
|
|
1814
|
+
if (confirmNew) {
|
|
1815
|
+
const created = await createNewWorkflow(workflowService);
|
|
1816
|
+
if (created) {
|
|
1817
|
+
// Continue with the new workflow
|
|
1818
|
+
continue;
|
|
1819
|
+
}
|
|
1820
|
+
}
|
|
1821
|
+
}
|
|
1822
|
+
else if (action === 'advance') {
|
|
1823
|
+
try {
|
|
1824
|
+
const nextPhase = await workflowService.advance();
|
|
1825
|
+
if (nextPhase) {
|
|
1826
|
+
ui.displaySuccess(t('success.workflow.advanced', { phase: nextPhase, phaseName: workflow_2.PHASE_NAMES_PT[nextPhase] }));
|
|
1827
|
+
}
|
|
1828
|
+
else {
|
|
1829
|
+
ui.displaySuccess(t('success.workflow.completed'));
|
|
1830
|
+
// Workflow completed - ask if they want to start a new one
|
|
1831
|
+
const { startNew } = await inquirer_1.default.prompt([
|
|
1832
|
+
{
|
|
1833
|
+
type: 'confirm',
|
|
1834
|
+
name: 'startNew',
|
|
1835
|
+
message: t('prompts.workflow.noWorkflowFound'),
|
|
1836
|
+
default: true
|
|
1837
|
+
}
|
|
1838
|
+
]);
|
|
1839
|
+
if (startNew) {
|
|
1840
|
+
await createNewWorkflow(workflowService);
|
|
1841
|
+
}
|
|
1842
|
+
continueMenu = false;
|
|
1843
|
+
}
|
|
1844
|
+
}
|
|
1845
|
+
catch (error) {
|
|
1846
|
+
ui.displayError(t('errors.workflow.advanceFailed'), error);
|
|
1847
|
+
}
|
|
1848
|
+
}
|
|
1849
|
+
// 'status' just loops and refreshes
|
|
1850
|
+
}
|
|
1851
|
+
}
|
|
1852
|
+
async function runInteractiveSkills() {
|
|
1853
|
+
const projectPath = process.cwd();
|
|
1854
|
+
let continueMenu = true;
|
|
1855
|
+
while (continueMenu) {
|
|
1856
|
+
const { action } = await inquirer_1.default.prompt([
|
|
1857
|
+
{
|
|
1858
|
+
type: 'list',
|
|
1859
|
+
name: 'action',
|
|
1860
|
+
message: t('prompts.skill.action'),
|
|
1861
|
+
choices: [
|
|
1862
|
+
{ name: t('prompts.skill.action.init'), value: 'init' },
|
|
1863
|
+
{ name: t('prompts.skill.action.list'), value: 'list' },
|
|
1864
|
+
{ name: t('prompts.skill.action.export'), value: 'export' },
|
|
1865
|
+
{ name: t('prompts.skill.action.create'), value: 'create' },
|
|
1866
|
+
{ name: t('prompts.skill.action.back'), value: 'back' }
|
|
1867
|
+
]
|
|
1868
|
+
}
|
|
1869
|
+
]);
|
|
1870
|
+
if (action === 'back') {
|
|
1871
|
+
continueMenu = false;
|
|
1872
|
+
break;
|
|
1873
|
+
}
|
|
1874
|
+
if (action === 'init') {
|
|
1875
|
+
try {
|
|
1876
|
+
const { createSkillGenerator } = await Promise.resolve().then(() => __importStar(require('./generators/skills')));
|
|
1877
|
+
const generator = createSkillGenerator({ repoPath: projectPath });
|
|
1878
|
+
const result = await generator.generate({});
|
|
1879
|
+
ui.displaySuccess(t('success.skill.initialized', { path: result.skillsDir }));
|
|
1880
|
+
ui.displayInfo(t('info.skill.generated'), result.generatedSkills.join(', ') || 'none');
|
|
1881
|
+
if (result.skippedSkills.length > 0) {
|
|
1882
|
+
ui.displayInfo(t('info.skill.skipped'), result.skippedSkills.join(', '));
|
|
1883
|
+
}
|
|
1884
|
+
}
|
|
1885
|
+
catch (error) {
|
|
1886
|
+
ui.displayError(t('errors.skill.initFailed'), error);
|
|
1887
|
+
}
|
|
1888
|
+
}
|
|
1889
|
+
else if (action === 'list') {
|
|
1890
|
+
try {
|
|
1891
|
+
const { createSkillRegistry, BUILT_IN_SKILLS } = await Promise.resolve().then(() => __importStar(require('./workflow/skills')));
|
|
1892
|
+
const registry = createSkillRegistry(projectPath);
|
|
1893
|
+
const discovered = await registry.discoverAll();
|
|
1894
|
+
console.log('\nBuilt-in Skills:');
|
|
1895
|
+
for (const skill of discovered.builtIn) {
|
|
1896
|
+
const scaffolded = discovered.all.find(s => s.slug === skill.slug && s.path.includes('.context'));
|
|
1897
|
+
const status = scaffolded ? '[scaffolded]' : '[available]';
|
|
1898
|
+
console.log(` ${skill.slug} ${status}`);
|
|
1899
|
+
console.log(` ${skill.metadata.description}`);
|
|
1900
|
+
}
|
|
1901
|
+
if (discovered.custom.length > 0) {
|
|
1902
|
+
console.log('\nCustom Skills:');
|
|
1903
|
+
for (const skill of discovered.custom) {
|
|
1904
|
+
console.log(` ${skill.slug}`);
|
|
1905
|
+
console.log(` ${skill.metadata.description}`);
|
|
1906
|
+
}
|
|
1907
|
+
}
|
|
1908
|
+
console.log(`\nTotal: ${discovered.all.length} skills (${discovered.builtIn.length} built-in, ${discovered.custom.length} custom)\n`);
|
|
1909
|
+
}
|
|
1910
|
+
catch (error) {
|
|
1911
|
+
ui.displayError(t('errors.skill.listFailed'), error);
|
|
1912
|
+
}
|
|
1913
|
+
}
|
|
1914
|
+
else if (action === 'export') {
|
|
1915
|
+
try {
|
|
1916
|
+
const { preset } = await inquirer_1.default.prompt([
|
|
1917
|
+
{
|
|
1918
|
+
type: 'list',
|
|
1919
|
+
name: 'preset',
|
|
1920
|
+
message: t('prompts.skill.exportPreset'),
|
|
1921
|
+
choices: [
|
|
1922
|
+
{ name: t('prompts.skill.exportPreset.all'), value: 'all' },
|
|
1923
|
+
{ name: t('prompts.skill.exportPreset.claude'), value: 'claude' },
|
|
1924
|
+
{ name: t('prompts.skill.exportPreset.gemini'), value: 'gemini' },
|
|
1925
|
+
{ name: t('prompts.skill.exportPreset.codex'), value: 'codex' }
|
|
1926
|
+
],
|
|
1927
|
+
default: 'all'
|
|
1928
|
+
}
|
|
1929
|
+
]);
|
|
1930
|
+
const { SkillExportService } = await Promise.resolve().then(() => __importStar(require('./services/export/skillExportService')));
|
|
1931
|
+
const exportService = new SkillExportService({
|
|
1932
|
+
ui,
|
|
1933
|
+
t,
|
|
1934
|
+
version: version_1.VERSION,
|
|
1935
|
+
});
|
|
1936
|
+
const result = await exportService.run(projectPath, {
|
|
1937
|
+
preset,
|
|
1938
|
+
includeBuiltIn: true,
|
|
1939
|
+
});
|
|
1940
|
+
ui.displaySuccess(t('success.skill.exported', {
|
|
1941
|
+
count: String(result.skillsExported.length),
|
|
1942
|
+
targets: String(result.targets.length)
|
|
1943
|
+
}));
|
|
1944
|
+
}
|
|
1945
|
+
catch (error) {
|
|
1946
|
+
ui.displayError(t('errors.skill.exportFailed'), error);
|
|
1947
|
+
}
|
|
1948
|
+
}
|
|
1949
|
+
else if (action === 'create') {
|
|
1950
|
+
try {
|
|
1951
|
+
const { name, description, phases } = await inquirer_1.default.prompt([
|
|
1952
|
+
{
|
|
1953
|
+
type: 'input',
|
|
1954
|
+
name: 'name',
|
|
1955
|
+
message: t('prompts.skill.name'),
|
|
1956
|
+
validate: (input) => input.trim().length > 0 || 'Name is required'
|
|
1957
|
+
},
|
|
1958
|
+
{
|
|
1959
|
+
type: 'input',
|
|
1960
|
+
name: 'description',
|
|
1961
|
+
message: t('prompts.skill.description'),
|
|
1962
|
+
default: ''
|
|
1963
|
+
},
|
|
1964
|
+
{
|
|
1965
|
+
type: 'input',
|
|
1966
|
+
name: 'phases',
|
|
1967
|
+
message: t('prompts.skill.phases'),
|
|
1968
|
+
default: 'E,V' // Default to Execution + Validation
|
|
1969
|
+
}
|
|
1970
|
+
]);
|
|
1971
|
+
const phaseArray = phases.split(',').map(p => p.trim().toUpperCase()).filter(p => ['P', 'R', 'E', 'V', 'C'].includes(p));
|
|
1972
|
+
ui.startSpinner('Creating skill...');
|
|
1973
|
+
const { createSkillGenerator } = await Promise.resolve().then(() => __importStar(require('./generators/skills')));
|
|
1974
|
+
const generator = createSkillGenerator({ repoPath: projectPath });
|
|
1975
|
+
const skillPath = await generator.generateCustomSkill({
|
|
1976
|
+
name: name.trim(),
|
|
1977
|
+
description: description.trim() || `TODO: Describe when to use ${name}`,
|
|
1978
|
+
phases: phaseArray,
|
|
1979
|
+
});
|
|
1980
|
+
// AI-first: Try to fill skill with AI + LSP
|
|
1981
|
+
const defaults = await (0, prompts_1.detectSmartDefaults)();
|
|
1982
|
+
if (defaults.apiKeyConfigured && defaults.provider) {
|
|
1983
|
+
ui.updateSpinner('Enhancing skill with AI...', 'info');
|
|
1984
|
+
try {
|
|
1985
|
+
const { SkillFillService } = await Promise.resolve().then(() => __importStar(require('./services/fill/skillFillService')));
|
|
1986
|
+
const skillFillService = new SkillFillService({ ui, t, version: version_1.VERSION, defaultModel: DEFAULT_MODEL });
|
|
1987
|
+
await skillFillService.run(projectPath, {
|
|
1988
|
+
provider: defaults.provider,
|
|
1989
|
+
model: DEFAULT_MODEL,
|
|
1990
|
+
apiKey: (0, providerFactory_1.getApiKeyFromEnv)(defaults.provider),
|
|
1991
|
+
skills: [name.trim()],
|
|
1992
|
+
semantic: true,
|
|
1993
|
+
useLsp: true,
|
|
1994
|
+
});
|
|
1995
|
+
}
|
|
1996
|
+
catch {
|
|
1997
|
+
// Fill failure is not critical - template is already created
|
|
1998
|
+
}
|
|
1999
|
+
}
|
|
2000
|
+
ui.updateSpinner('Skill created', 'success');
|
|
2001
|
+
ui.stopSpinner();
|
|
2002
|
+
ui.displaySuccess(t('success.skill.created', { name }));
|
|
2003
|
+
ui.displayInfo(t('info.skill.path'), skillPath);
|
|
2004
|
+
}
|
|
2005
|
+
catch (error) {
|
|
2006
|
+
ui.stopSpinner();
|
|
2007
|
+
ui.displayError(t('errors.skill.createFailed'), error);
|
|
2008
|
+
}
|
|
2009
|
+
}
|
|
2010
|
+
}
|
|
2011
|
+
}
|
|
2012
|
+
// ============================================================================
|
|
2013
|
+
// Quick Sync - Unified sync for agents, skills, and docs
|
|
2014
|
+
// ============================================================================
|
|
2015
|
+
async function runQuickSync() {
|
|
2016
|
+
const projectPath = process.cwd();
|
|
2017
|
+
// Step 1: Select components to sync
|
|
2018
|
+
const { components } = await inquirer_1.default.prompt([
|
|
2019
|
+
{
|
|
2020
|
+
type: 'checkbox',
|
|
2021
|
+
name: 'components',
|
|
2022
|
+
message: t('prompts.quickSync.selectComponents'),
|
|
2023
|
+
choices: [
|
|
2024
|
+
{ name: t('prompts.quickSync.components.agents'), value: 'agents', checked: true },
|
|
2025
|
+
{ name: t('prompts.quickSync.components.skills'), value: 'skills', checked: true },
|
|
2026
|
+
{ name: t('prompts.quickSync.components.docs'), value: 'docs', checked: true },
|
|
2027
|
+
],
|
|
2028
|
+
},
|
|
2029
|
+
]);
|
|
2030
|
+
if (components.length === 0) {
|
|
2031
|
+
ui.displayWarning(t('prompts.quickSync.noComponentsSelected'));
|
|
2032
|
+
return;
|
|
2033
|
+
}
|
|
2034
|
+
let agentTargets;
|
|
2035
|
+
let skillTargets;
|
|
2036
|
+
let docTargets;
|
|
2037
|
+
// Step 2: If agents selected, choose targets
|
|
2038
|
+
if (components.includes('agents')) {
|
|
2039
|
+
const { targets } = await inquirer_1.default.prompt([
|
|
2040
|
+
{
|
|
2041
|
+
type: 'checkbox',
|
|
2042
|
+
name: 'targets',
|
|
2043
|
+
message: t('prompts.quickSync.selectAgentTargets'),
|
|
2044
|
+
choices: [
|
|
2045
|
+
{ name: '.claude/agents (Claude Code)', value: 'claude', checked: true },
|
|
2046
|
+
{ name: '.github/agents (GitHub Copilot)', value: 'github', checked: true },
|
|
2047
|
+
{ name: '.cursor/agents (Cursor AI)', value: 'cursor', checked: false },
|
|
2048
|
+
{ name: '.windsurf/agents (Windsurf/Codeium)', value: 'windsurf', checked: false },
|
|
2049
|
+
{ name: '.cline/agents (Cline)', value: 'cline', checked: false },
|
|
2050
|
+
{ name: '.continue/agents (Continue.dev)', value: 'continue', checked: false },
|
|
2051
|
+
],
|
|
2052
|
+
},
|
|
2053
|
+
]);
|
|
2054
|
+
agentTargets = targets.length > 0 ? targets : undefined;
|
|
2055
|
+
}
|
|
2056
|
+
// Step 3: If skills selected, choose targets
|
|
2057
|
+
if (components.includes('skills')) {
|
|
2058
|
+
const { targets } = await inquirer_1.default.prompt([
|
|
2059
|
+
{
|
|
2060
|
+
type: 'checkbox',
|
|
2061
|
+
name: 'targets',
|
|
2062
|
+
message: t('prompts.quickSync.selectSkillTargets'),
|
|
2063
|
+
choices: [
|
|
2064
|
+
{ name: '.claude/skills (Claude Code)', value: 'claude', checked: true },
|
|
2065
|
+
{ name: '.gemini/skills (Gemini CLI)', value: 'gemini', checked: true },
|
|
2066
|
+
{ name: '.codex/skills (Codex CLI)', value: 'codex', checked: true },
|
|
2067
|
+
],
|
|
2068
|
+
},
|
|
2069
|
+
]);
|
|
2070
|
+
skillTargets = targets.length > 0 ? targets : undefined;
|
|
2071
|
+
}
|
|
2072
|
+
// Step 4: If docs selected, choose targets
|
|
2073
|
+
if (components.includes('docs')) {
|
|
2074
|
+
const { targets } = await inquirer_1.default.prompt([
|
|
2075
|
+
{
|
|
2076
|
+
type: 'checkbox',
|
|
2077
|
+
name: 'targets',
|
|
2078
|
+
message: t('prompts.quickSync.selectDocTargets'),
|
|
2079
|
+
choices: [
|
|
2080
|
+
{ name: '.cursorrules (Cursor AI)', value: 'cursor', checked: true },
|
|
2081
|
+
{ name: 'CLAUDE.md (Claude Code)', value: 'claude', checked: true },
|
|
2082
|
+
{ name: 'AGENTS.md (Universal)', value: 'agents', checked: true },
|
|
2083
|
+
{ name: '.windsurfrules (Windsurf)', value: 'windsurf', checked: false },
|
|
2084
|
+
{ name: '.clinerules (Cline)', value: 'cline', checked: false },
|
|
2085
|
+
{ name: 'CONVENTIONS.md (Aider)', value: 'aider', checked: false },
|
|
2086
|
+
],
|
|
2087
|
+
},
|
|
2088
|
+
]);
|
|
2089
|
+
docTargets = targets.length > 0 ? targets : undefined;
|
|
2090
|
+
}
|
|
2091
|
+
// Build options based on selections
|
|
2092
|
+
const options = {
|
|
2093
|
+
skipAgents: !components.includes('agents'),
|
|
2094
|
+
skipSkills: !components.includes('skills'),
|
|
2095
|
+
skipDocs: !components.includes('docs'),
|
|
2096
|
+
agentTargets,
|
|
2097
|
+
skillTargets,
|
|
2098
|
+
docTargets,
|
|
2099
|
+
force: false,
|
|
2100
|
+
dryRun: false,
|
|
2101
|
+
verbose: false,
|
|
2102
|
+
};
|
|
2103
|
+
const quickSyncService = new quickSync_1.QuickSyncService({
|
|
2104
|
+
ui,
|
|
2105
|
+
t,
|
|
2106
|
+
version: version_1.VERSION,
|
|
2107
|
+
defaultModel: DEFAULT_MODEL,
|
|
2108
|
+
});
|
|
2109
|
+
const result = await quickSyncService.run(projectPath, options);
|
|
2110
|
+
// If docs are outdated, ask if user wants to update
|
|
2111
|
+
if (!result.docsUpdated) {
|
|
2112
|
+
const stats = await quickSyncService.getStats(projectPath);
|
|
2113
|
+
if (stats.daysOld) {
|
|
2114
|
+
const { updateDocs } = await inquirer_1.default.prompt([
|
|
2115
|
+
{
|
|
2116
|
+
type: 'confirm',
|
|
2117
|
+
name: 'updateDocs',
|
|
2118
|
+
message: t('prompts.quickSync.updateDocs'),
|
|
2119
|
+
default: true,
|
|
2120
|
+
},
|
|
2121
|
+
]);
|
|
2122
|
+
if (updateDocs) {
|
|
2123
|
+
// Trigger fill with AI + LSP
|
|
2124
|
+
await runInteractiveLlmFill();
|
|
2125
|
+
}
|
|
2126
|
+
}
|
|
2127
|
+
}
|
|
2128
|
+
ui.displaySuccess(t('success.quickSync.complete'));
|
|
2129
|
+
}
|
|
2130
|
+
async function runManageAgents() {
|
|
2131
|
+
const projectPath = process.cwd();
|
|
2132
|
+
let continueMenu = true;
|
|
2133
|
+
while (continueMenu) {
|
|
2134
|
+
const { action } = await inquirer_1.default.prompt([
|
|
2135
|
+
{
|
|
2136
|
+
type: 'list',
|
|
2137
|
+
name: 'action',
|
|
2138
|
+
message: t('prompts.agents.action'),
|
|
2139
|
+
choices: [
|
|
2140
|
+
{ name: t('prompts.agents.choice.sync'), value: 'sync' },
|
|
2141
|
+
{ name: t('prompts.agents.choice.create'), value: 'create' },
|
|
2142
|
+
{ name: t('prompts.agents.choice.list'), value: 'list' },
|
|
2143
|
+
{ name: t('prompts.agents.choice.back'), value: 'back' },
|
|
2144
|
+
],
|
|
2145
|
+
},
|
|
2146
|
+
]);
|
|
2147
|
+
if (action === 'back') {
|
|
2148
|
+
continueMenu = false;
|
|
2149
|
+
break;
|
|
2150
|
+
}
|
|
2151
|
+
if (action === 'sync') {
|
|
2152
|
+
await runInteractiveSync();
|
|
2153
|
+
}
|
|
2154
|
+
else if (action === 'list') {
|
|
2155
|
+
await listAgents(projectPath);
|
|
2156
|
+
}
|
|
2157
|
+
else if (action === 'create') {
|
|
2158
|
+
await createCustomAgent(projectPath);
|
|
2159
|
+
}
|
|
2160
|
+
}
|
|
2161
|
+
}
|
|
2162
|
+
async function listAgents(projectPath) {
|
|
2163
|
+
const agentsPath = path.join(projectPath, '.context', 'agents');
|
|
2164
|
+
const fs = await Promise.resolve().then(() => __importStar(require('fs-extra')));
|
|
2165
|
+
if (!(await fs.pathExists(agentsPath))) {
|
|
2166
|
+
ui.displayWarning('No agents directory found. Run scaffold first.');
|
|
2167
|
+
return;
|
|
2168
|
+
}
|
|
2169
|
+
const files = await fs.readdir(agentsPath);
|
|
2170
|
+
const agents = files.filter(f => f.endsWith('.md') && f !== 'README.md');
|
|
2171
|
+
console.log('\nAgents:');
|
|
2172
|
+
for (const agent of agents) {
|
|
2173
|
+
const name = agent.replace('.md', '');
|
|
2174
|
+
console.log(` ${theme_1.colors.primary(name)}`);
|
|
2175
|
+
}
|
|
2176
|
+
console.log(`\nTotal: ${agents.length} agents\n`);
|
|
2177
|
+
}
|
|
2178
|
+
async function createCustomAgent(projectPath) {
|
|
2179
|
+
const { name, description, role } = await inquirer_1.default.prompt([
|
|
2180
|
+
{
|
|
2181
|
+
type: 'input',
|
|
2182
|
+
name: 'name',
|
|
2183
|
+
message: t('prompts.agent.name'),
|
|
2184
|
+
validate: (input) => input.trim().length > 0 || 'Name is required',
|
|
2185
|
+
},
|
|
2186
|
+
{
|
|
2187
|
+
type: 'input',
|
|
2188
|
+
name: 'description',
|
|
2189
|
+
message: t('prompts.agent.description'),
|
|
2190
|
+
},
|
|
2191
|
+
{
|
|
2192
|
+
type: 'list',
|
|
2193
|
+
name: 'role',
|
|
2194
|
+
message: t('prompts.agent.role'),
|
|
2195
|
+
choices: [
|
|
2196
|
+
{ name: 'Code Reviewer', value: 'code-reviewer' },
|
|
2197
|
+
{ name: 'Bug Fixer', value: 'bug-fixer' },
|
|
2198
|
+
{ name: 'Feature Developer', value: 'feature-developer' },
|
|
2199
|
+
{ name: 'Test Writer', value: 'test-writer' },
|
|
2200
|
+
{ name: 'Documentation Writer', value: 'documentation-writer' },
|
|
2201
|
+
{ name: 'Security Auditor', value: 'security-auditor' },
|
|
2202
|
+
{ name: 'Performance Optimizer', value: 'performance-optimizer' },
|
|
2203
|
+
{ name: 'Custom...', value: 'custom' },
|
|
2204
|
+
],
|
|
2205
|
+
},
|
|
2206
|
+
]);
|
|
2207
|
+
let finalRole = role;
|
|
2208
|
+
if (role === 'custom') {
|
|
2209
|
+
const { customRole } = await inquirer_1.default.prompt([
|
|
2210
|
+
{
|
|
2211
|
+
type: 'input',
|
|
2212
|
+
name: 'customRole',
|
|
2213
|
+
message: 'Enter custom role:',
|
|
2214
|
+
validate: (input) => input.trim().length > 0 || 'Role is required',
|
|
2215
|
+
},
|
|
2216
|
+
]);
|
|
2217
|
+
finalRole = customRole.trim();
|
|
2218
|
+
}
|
|
2219
|
+
ui.startSpinner(t('spinner.agent.creating'));
|
|
2220
|
+
try {
|
|
2221
|
+
const fs = await Promise.resolve().then(() => __importStar(require('fs-extra')));
|
|
2222
|
+
const agentsDir = path.join(projectPath, '.context', 'agents');
|
|
2223
|
+
await fs.ensureDir(agentsDir);
|
|
2224
|
+
const slug = name.trim().toLowerCase().replace(/\s+/g, '-');
|
|
2225
|
+
const agentPath = path.join(agentsDir, `${slug}.md`);
|
|
2226
|
+
// Generate template content
|
|
2227
|
+
const template = `---
|
|
2228
|
+
name: ${name.trim()}
|
|
2229
|
+
description: ${description.trim() || `Custom agent: ${name.trim()}`}
|
|
2230
|
+
role: ${finalRole}
|
|
2231
|
+
custom: true
|
|
2232
|
+
---
|
|
2233
|
+
|
|
2234
|
+
# ${name.trim()} Agent
|
|
2235
|
+
|
|
2236
|
+
## Role
|
|
2237
|
+
${description.trim() || `Custom agent specialized in ${finalRole}`}
|
|
2238
|
+
|
|
2239
|
+
## Responsibilities
|
|
2240
|
+
- Review and analyze code related to ${finalRole}
|
|
2241
|
+
- Provide recommendations based on best practices
|
|
2242
|
+
- Help maintain code quality and standards
|
|
2243
|
+
|
|
2244
|
+
## Guidelines
|
|
2245
|
+
- Follow project conventions and patterns
|
|
2246
|
+
- Consider performance and maintainability
|
|
2247
|
+
- Document decisions and rationale
|
|
2248
|
+
|
|
2249
|
+
## Context
|
|
2250
|
+
This agent should be invoked when working on tasks related to ${finalRole}.
|
|
2251
|
+
`;
|
|
2252
|
+
// Write the agent file
|
|
2253
|
+
await fs.writeFile(agentPath, template, 'utf-8');
|
|
2254
|
+
// Try to fill with AI if API key is available
|
|
2255
|
+
const defaults = await (0, prompts_1.detectSmartDefaults)();
|
|
2256
|
+
if (defaults.apiKeyConfigured && defaults.provider) {
|
|
2257
|
+
ui.updateSpinner('Enhancing agent with AI...', 'info');
|
|
2258
|
+
try {
|
|
2259
|
+
// Run fill on just this agent
|
|
2260
|
+
const singleFillService = new fillService_1.FillService({
|
|
2261
|
+
ui,
|
|
2262
|
+
t,
|
|
2263
|
+
version: version_1.VERSION,
|
|
2264
|
+
defaultModel: DEFAULT_MODEL,
|
|
2265
|
+
});
|
|
2266
|
+
await singleFillService.run(projectPath, {
|
|
2267
|
+
model: DEFAULT_MODEL,
|
|
2268
|
+
provider: defaults.provider,
|
|
2269
|
+
apiKey: (0, providerFactory_1.getApiKeyFromEnv)(defaults.provider),
|
|
2270
|
+
verbose: false,
|
|
2271
|
+
semantic: true,
|
|
2272
|
+
useLsp: true,
|
|
2273
|
+
limit: 1,
|
|
2274
|
+
include: [agentPath],
|
|
2275
|
+
});
|
|
2276
|
+
}
|
|
2277
|
+
catch {
|
|
2278
|
+
// Ignore fill errors - template is already saved
|
|
2279
|
+
}
|
|
2280
|
+
}
|
|
2281
|
+
ui.updateSpinner(t('spinner.agent.created'), 'success');
|
|
2282
|
+
ui.stopSpinner();
|
|
2283
|
+
ui.displaySuccess(t('success.agent.created', { name: name.trim() }));
|
|
2284
|
+
console.log(` Path: ${agentPath}\n`);
|
|
2285
|
+
}
|
|
2286
|
+
catch (error) {
|
|
2287
|
+
ui.updateSpinner('Failed to create agent', 'fail');
|
|
2288
|
+
ui.stopSpinner();
|
|
2289
|
+
ui.displayError('Failed to create agent', error);
|
|
2290
|
+
}
|
|
2291
|
+
}
|
|
2292
|
+
async function runSettings() {
|
|
2293
|
+
let continueMenu = true;
|
|
2294
|
+
while (continueMenu) {
|
|
2295
|
+
const { action } = await inquirer_1.default.prompt([
|
|
2296
|
+
{
|
|
2297
|
+
type: 'list',
|
|
2298
|
+
name: 'action',
|
|
2299
|
+
message: t('prompts.settings.action'),
|
|
2300
|
+
choices: [
|
|
2301
|
+
{ name: t('prompts.settings.choice.language'), value: 'language' },
|
|
2302
|
+
{ name: t('prompts.settings.choice.back'), value: 'back' },
|
|
2303
|
+
],
|
|
2304
|
+
},
|
|
2305
|
+
]);
|
|
2306
|
+
if (action === 'back') {
|
|
2307
|
+
continueMenu = false;
|
|
2308
|
+
break;
|
|
2309
|
+
}
|
|
2310
|
+
if (action === 'language') {
|
|
2311
|
+
await selectLocale(true);
|
|
2312
|
+
}
|
|
2313
|
+
}
|
|
2314
|
+
}
|
|
1039
2315
|
function filterOutLocaleArgs(args) {
|
|
1040
2316
|
const filtered = [];
|
|
1041
2317
|
for (let index = 0; index < args.length; index += 1) {
|