@agiflowai/aicode-toolkit 0.6.0 → 1.0.2
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/dist/cli.cjs +401 -123
- package/dist/cli.js +401 -124
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +15 -1
- package/dist/index.d.ts +15 -1
- package/dist/index.js +1 -1
- package/dist/{services-s1vmufE4.cjs → services-C6lqyioO.cjs} +243 -26
- package/dist/{services-DNldrNnu.js → services-zrdafWTg.js} +257 -60
- package/package.json +6 -4
package/dist/cli.js
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { MCPServer, MCP_SERVER_INFO } from "./mcp-BmhiAfeF.js";
|
|
3
|
-
import { CodingAgentService, NewProjectService, TemplateSelectionService, cloneRepository, cloneSubdirectory, displayBanner, findWorkspaceRoot, parseGitHubUrl } from "./services-
|
|
3
|
+
import { CodingAgentService, NewProjectService, SPEC_TOOL_INFO, SpecTool, SpecToolService, TemplateSelectionService, cloneRepository, cloneSubdirectory, displayBanner, findWorkspaceRoot, parseGitHubUrl } from "./services-zrdafWTg.js";
|
|
4
4
|
import { Command } from "commander";
|
|
5
5
|
import path from "node:path";
|
|
6
|
-
import { ProjectType, TemplatesManagerService, icons, messages, print, sections } from "@agiflowai/aicode-utils";
|
|
6
|
+
import { ProjectType, TemplatesManagerService, detectProjectType, icons, messages, print, sections } from "@agiflowai/aicode-utils";
|
|
7
7
|
import * as fs from "fs-extra";
|
|
8
8
|
import { confirm, input, select } from "@inquirer/prompts";
|
|
9
|
+
import ora from "ora";
|
|
9
10
|
import { assign, createActor, createMachine, fromPromise } from "xstate";
|
|
10
11
|
|
|
11
12
|
//#region package.json
|
|
12
13
|
var name = "@agiflowai/aicode-toolkit";
|
|
13
14
|
var description = "AI-powered code toolkit CLI for scaffolding, architecture management, and development workflows";
|
|
14
|
-
var version = "0.
|
|
15
|
+
var version = "1.0.1";
|
|
15
16
|
var license = "AGPL-3.0";
|
|
16
17
|
var author = "AgiflowIO";
|
|
17
18
|
var repository = {
|
|
@@ -57,6 +58,7 @@ var dependencies = {
|
|
|
57
58
|
"gradient-string": "^3.0.0",
|
|
58
59
|
"js-yaml": "4.1.0",
|
|
59
60
|
"liquidjs": "10.21.1",
|
|
61
|
+
"ora": "^9.0.0",
|
|
60
62
|
"pino": "^10.0.0",
|
|
61
63
|
"pino-pretty": "^13.1.1",
|
|
62
64
|
"xstate": "^5.23.0",
|
|
@@ -68,7 +70,8 @@ var devDependencies = {
|
|
|
68
70
|
"@types/js-yaml": "^4.0.9",
|
|
69
71
|
"@types/node": "^22.0.0",
|
|
70
72
|
"tsdown": "^0.15.6",
|
|
71
|
-
"typescript": "5.9.3"
|
|
73
|
+
"typescript": "5.9.3",
|
|
74
|
+
"unplugin-raw": "^0.6.3"
|
|
72
75
|
};
|
|
73
76
|
var publishConfig = { "access": "public" };
|
|
74
77
|
var type = "module";
|
|
@@ -180,7 +183,6 @@ const initMachine = createMachine({
|
|
|
180
183
|
projectType: void 0,
|
|
181
184
|
projectPath: void 0,
|
|
182
185
|
repositoryExists: false,
|
|
183
|
-
detectionConfidence: void 0,
|
|
184
186
|
detectionIndicators: void 0,
|
|
185
187
|
templatesPath: void 0,
|
|
186
188
|
tmpTemplatesPath: void 0,
|
|
@@ -188,6 +190,8 @@ const initMachine = createMachine({
|
|
|
188
190
|
selectedMcpServers: void 0,
|
|
189
191
|
detectedCodingAgent: void 0,
|
|
190
192
|
codingAgent: void 0,
|
|
193
|
+
detectedSpecTool: void 0,
|
|
194
|
+
useSpecDrivenApproach: void 0,
|
|
191
195
|
options: input$1.options,
|
|
192
196
|
error: void 0
|
|
193
197
|
}),
|
|
@@ -216,18 +220,14 @@ const initMachine = createMachine({
|
|
|
216
220
|
input: ({ context }) => ({ workspaceRoot: context.workspaceRoot }),
|
|
217
221
|
onDone: [{
|
|
218
222
|
target: "checkingSkipTemplates",
|
|
219
|
-
guard: ({ event }) => event.output.
|
|
223
|
+
guard: ({ event }) => event.output.projectType !== void 0,
|
|
220
224
|
actions: assign({
|
|
221
225
|
projectType: ({ event }) => event.output.projectType,
|
|
222
|
-
detectionConfidence: ({ event }) => event.output.confidence,
|
|
223
226
|
detectionIndicators: ({ event }) => event.output.indicators
|
|
224
227
|
})
|
|
225
228
|
}, {
|
|
226
229
|
target: "promptingProjectType",
|
|
227
|
-
actions: assign({
|
|
228
|
-
detectionConfidence: ({ event }) => event.output.confidence,
|
|
229
|
-
detectionIndicators: ({ event }) => event.output.indicators
|
|
230
|
-
})
|
|
230
|
+
actions: assign({ detectionIndicators: ({ event }) => event.output.indicators })
|
|
231
231
|
}],
|
|
232
232
|
onError: {
|
|
233
233
|
target: "failed",
|
|
@@ -238,6 +238,7 @@ const initMachine = createMachine({
|
|
|
238
238
|
src: "promptProjectType",
|
|
239
239
|
input: ({ context }) => ({
|
|
240
240
|
providedProjectType: context.options.projectType,
|
|
241
|
+
detectedProjectType: context.projectType,
|
|
241
242
|
detectionIndicators: context.detectionIndicators
|
|
242
243
|
}),
|
|
243
244
|
onDone: {
|
|
@@ -309,7 +310,7 @@ const initMachine = createMachine({
|
|
|
309
310
|
promptingMcpSelection: { invoke: {
|
|
310
311
|
src: "promptMcpSelection",
|
|
311
312
|
onDone: {
|
|
312
|
-
target: "
|
|
313
|
+
target: "checkingTemplatesFolder",
|
|
313
314
|
actions: assign({ selectedMcpServers: ({ event }) => event.output })
|
|
314
315
|
},
|
|
315
316
|
onError: {
|
|
@@ -317,6 +318,29 @@ const initMachine = createMachine({
|
|
|
317
318
|
actions: assign({ error: ({ event }) => event.error })
|
|
318
319
|
}
|
|
319
320
|
} },
|
|
321
|
+
checkingTemplatesFolder: { invoke: {
|
|
322
|
+
src: "checkTemplatesFolder",
|
|
323
|
+
input: ({ context }) => ({ workspaceRoot: context.workspaceRoot }),
|
|
324
|
+
onDone: [{
|
|
325
|
+
target: "creatingConfig",
|
|
326
|
+
guard: ({ event }) => event.output.skipDownload === true,
|
|
327
|
+
actions: assign({
|
|
328
|
+
templatesPath: ({ event }) => event.output.templatesPath,
|
|
329
|
+
skipDownload: ({ event }) => event.output.skipDownload,
|
|
330
|
+
selectedTemplates: ({ event }) => event.output.existingTemplates
|
|
331
|
+
})
|
|
332
|
+
}, {
|
|
333
|
+
target: "downloadingTemplates",
|
|
334
|
+
actions: assign({
|
|
335
|
+
templatesPath: ({ event }) => event.output.templatesPath,
|
|
336
|
+
skipDownload: ({ event }) => event.output.skipDownload
|
|
337
|
+
})
|
|
338
|
+
}],
|
|
339
|
+
onError: {
|
|
340
|
+
target: "failed",
|
|
341
|
+
actions: assign({ error: ({ event }) => event.error })
|
|
342
|
+
}
|
|
343
|
+
} },
|
|
320
344
|
downloadingTemplates: { invoke: {
|
|
321
345
|
src: "downloadTemplates",
|
|
322
346
|
onDone: {
|
|
@@ -357,14 +381,12 @@ const initMachine = createMachine({
|
|
|
357
381
|
input: ({ context }) => ({
|
|
358
382
|
tmpTemplatesPath: context.tmpTemplatesPath,
|
|
359
383
|
workspaceRoot: context.workspaceRoot,
|
|
384
|
+
templatesPath: context.templatesPath,
|
|
360
385
|
selectedTemplates: context.selectedTemplates,
|
|
361
386
|
projectType: context.projectType,
|
|
362
387
|
selectedMcpServers: context.selectedMcpServers
|
|
363
388
|
}),
|
|
364
|
-
onDone: {
|
|
365
|
-
target: "creatingConfig",
|
|
366
|
-
actions: assign({ templatesPath: ({ event }) => event.output })
|
|
367
|
-
},
|
|
389
|
+
onDone: { target: "creatingConfig" },
|
|
368
390
|
onError: {
|
|
369
391
|
target: "failed",
|
|
370
392
|
actions: assign({ error: ({ event }) => event.error })
|
|
@@ -375,6 +397,7 @@ const initMachine = createMachine({
|
|
|
375
397
|
input: ({ context }) => ({
|
|
376
398
|
workspaceRoot: context.workspaceRoot,
|
|
377
399
|
projectType: context.projectType,
|
|
400
|
+
templatesPath: context.templatesPath,
|
|
378
401
|
selectedTemplates: context.selectedTemplates
|
|
379
402
|
}),
|
|
380
403
|
onDone: { target: "checkingSkipMcp" },
|
|
@@ -386,7 +409,7 @@ const initMachine = createMachine({
|
|
|
386
409
|
checkingSkipMcp: { always: [{
|
|
387
410
|
target: "detectingCodingAgent",
|
|
388
411
|
guard: ({ context }) => !context.options.skipMcp
|
|
389
|
-
}, { target: "
|
|
412
|
+
}, { target: "detectingSpecTool" }] },
|
|
390
413
|
detectingCodingAgent: { invoke: {
|
|
391
414
|
src: "detectCodingAgent",
|
|
392
415
|
input: ({ context }) => ({ workspaceRoot: context.workspaceRoot }),
|
|
@@ -417,6 +440,66 @@ const initMachine = createMachine({
|
|
|
417
440
|
workspaceRoot: context.workspaceRoot,
|
|
418
441
|
codingAgent: context.codingAgent
|
|
419
442
|
}),
|
|
443
|
+
onDone: { target: "detectingSpecTool" },
|
|
444
|
+
onError: {
|
|
445
|
+
target: "failed",
|
|
446
|
+
actions: assign({ error: ({ event }) => event.error })
|
|
447
|
+
}
|
|
448
|
+
} },
|
|
449
|
+
detectingSpecTool: { invoke: {
|
|
450
|
+
src: "detectSpecTool",
|
|
451
|
+
input: ({ context }) => ({ workspaceRoot: context.workspaceRoot }),
|
|
452
|
+
onDone: {
|
|
453
|
+
target: "promptingSpecDrivenApproach",
|
|
454
|
+
actions: assign({ detectedSpecTool: ({ event }) => event.output })
|
|
455
|
+
},
|
|
456
|
+
onError: { target: "cleaningUp" }
|
|
457
|
+
} },
|
|
458
|
+
promptingSpecDrivenApproach: { invoke: {
|
|
459
|
+
src: "promptSpecDrivenApproach",
|
|
460
|
+
input: ({ context }) => ({ detectedSpecTool: context.detectedSpecTool }),
|
|
461
|
+
onDone: [{
|
|
462
|
+
target: "settingUpSpec",
|
|
463
|
+
guard: ({ event }) => event.output === true,
|
|
464
|
+
actions: assign({ useSpecDrivenApproach: () => true })
|
|
465
|
+
}, {
|
|
466
|
+
target: "cleaningUp",
|
|
467
|
+
actions: assign({ useSpecDrivenApproach: () => false })
|
|
468
|
+
}],
|
|
469
|
+
onError: { target: "cleaningUp" }
|
|
470
|
+
} },
|
|
471
|
+
settingUpSpec: { invoke: {
|
|
472
|
+
src: "setupSpec",
|
|
473
|
+
input: ({ context }) => ({
|
|
474
|
+
workspaceRoot: context.workspaceRoot,
|
|
475
|
+
isAlreadyInstalled: context.detectedSpecTool !== null,
|
|
476
|
+
selectedMcpServers: context.selectedMcpServers,
|
|
477
|
+
codingAgent: context.codingAgent
|
|
478
|
+
}),
|
|
479
|
+
onDone: [{
|
|
480
|
+
target: "promptingSpecInstructions",
|
|
481
|
+
guard: ({ context }) => context.detectedSpecTool === null
|
|
482
|
+
}, { target: "cleaningUp" }],
|
|
483
|
+
onError: {
|
|
484
|
+
target: "failed",
|
|
485
|
+
actions: assign({ error: ({ event }) => event.error })
|
|
486
|
+
}
|
|
487
|
+
} },
|
|
488
|
+
promptingSpecInstructions: { invoke: {
|
|
489
|
+
src: "promptSpecInstructions",
|
|
490
|
+
onDone: [{
|
|
491
|
+
target: "updatingSpecInstructions",
|
|
492
|
+
guard: ({ event }) => event.output === true
|
|
493
|
+
}, { target: "cleaningUp" }],
|
|
494
|
+
onError: { target: "cleaningUp" }
|
|
495
|
+
} },
|
|
496
|
+
updatingSpecInstructions: { invoke: {
|
|
497
|
+
src: "updateSpecInstructions",
|
|
498
|
+
input: ({ context }) => ({
|
|
499
|
+
workspaceRoot: context.workspaceRoot,
|
|
500
|
+
selectedMcpServers: context.selectedMcpServers,
|
|
501
|
+
codingAgent: context.codingAgent
|
|
502
|
+
}),
|
|
420
503
|
onDone: { target: "cleaningUp" },
|
|
421
504
|
onError: {
|
|
422
505
|
target: "failed",
|
|
@@ -452,6 +535,7 @@ const initActors = {
|
|
|
452
535
|
checkWorkspaceExists: fromPromise(async () => {
|
|
453
536
|
const workspaceRoot = await findWorkspaceRoot();
|
|
454
537
|
if (workspaceRoot) {
|
|
538
|
+
print.divider();
|
|
455
539
|
print.info(`Found workspace at: ${workspaceRoot}`);
|
|
456
540
|
return {
|
|
457
541
|
exists: true,
|
|
@@ -461,62 +545,11 @@ const initActors = {
|
|
|
461
545
|
return { exists: false };
|
|
462
546
|
}),
|
|
463
547
|
detectProjectType: fromPromise(async ({ input: input$1 }) => {
|
|
464
|
-
print.
|
|
465
|
-
|
|
466
|
-
const
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
const indicators = [];
|
|
470
|
-
let projectType;
|
|
471
|
-
let confidence = "low";
|
|
472
|
-
if (await fs.pathExists(nxJsonPath)) {
|
|
473
|
-
indicators.push("nx.json found");
|
|
474
|
-
projectType = ProjectType.MONOREPO;
|
|
475
|
-
confidence = "high";
|
|
476
|
-
}
|
|
477
|
-
if (await fs.pathExists(lernaJsonPath)) {
|
|
478
|
-
indicators.push("lerna.json found");
|
|
479
|
-
projectType = ProjectType.MONOREPO;
|
|
480
|
-
confidence = "high";
|
|
481
|
-
}
|
|
482
|
-
if (await fs.pathExists(pnpmWorkspacePath)) {
|
|
483
|
-
indicators.push("pnpm-workspace.yaml found");
|
|
484
|
-
projectType = ProjectType.MONOREPO;
|
|
485
|
-
confidence = "high";
|
|
486
|
-
}
|
|
487
|
-
if (await fs.pathExists(turboJsonPath)) {
|
|
488
|
-
indicators.push("turbo.json found");
|
|
489
|
-
projectType = ProjectType.MONOREPO;
|
|
490
|
-
confidence = "high";
|
|
491
|
-
}
|
|
492
|
-
const packageJsonPath = path.join(input$1.workspaceRoot, "package.json");
|
|
493
|
-
if (await fs.pathExists(packageJsonPath)) {
|
|
494
|
-
if ((await fs.readJson(packageJsonPath)).workspaces) {
|
|
495
|
-
indicators.push("package.json with workspaces found");
|
|
496
|
-
projectType = ProjectType.MONOREPO;
|
|
497
|
-
if (confidence !== "high") confidence = "medium";
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
const toolkitYamlPath = path.join(input$1.workspaceRoot, "toolkit.yaml");
|
|
501
|
-
if (await fs.pathExists(toolkitYamlPath)) {
|
|
502
|
-
const toolkitConfig = await TemplatesManagerService.readToolkitConfig(input$1.workspaceRoot);
|
|
503
|
-
if (toolkitConfig?.projectType) {
|
|
504
|
-
indicators.push(`toolkit.yaml specifies ${toolkitConfig.projectType}`);
|
|
505
|
-
projectType = toolkitConfig.projectType;
|
|
506
|
-
confidence = "high";
|
|
507
|
-
}
|
|
508
|
-
}
|
|
509
|
-
if (!projectType) {
|
|
510
|
-
projectType = ProjectType.MONOLITH;
|
|
511
|
-
indicators.push("No monorepo indicators found, assuming monolith");
|
|
512
|
-
confidence = "low";
|
|
513
|
-
}
|
|
514
|
-
if (confidence === "high") print.success(`Detected ${projectType} project (high confidence)`);
|
|
515
|
-
return {
|
|
516
|
-
projectType,
|
|
517
|
-
confidence,
|
|
518
|
-
indicators
|
|
519
|
-
};
|
|
548
|
+
print.divider();
|
|
549
|
+
print.info("Detecting project type...");
|
|
550
|
+
const result = await detectProjectType(input$1.workspaceRoot);
|
|
551
|
+
if (result.projectType) print.success(`Detected ${result.projectType} project`);
|
|
552
|
+
return result;
|
|
520
553
|
}),
|
|
521
554
|
promptProjectType: fromPromise(async ({ input: actorInput }) => {
|
|
522
555
|
if (actorInput.providedProjectType) {
|
|
@@ -524,23 +557,30 @@ const initActors = {
|
|
|
524
557
|
print.info(`Project type: ${projectType}`);
|
|
525
558
|
return projectType;
|
|
526
559
|
}
|
|
560
|
+
if (actorInput.detectedProjectType) {
|
|
561
|
+
print.info(`Using detected project type: ${actorInput.detectedProjectType}`);
|
|
562
|
+
return actorInput.detectedProjectType;
|
|
563
|
+
}
|
|
527
564
|
if (actorInput.detectionIndicators && actorInput.detectionIndicators.length > 0) {
|
|
528
565
|
print.info("\nDetection results:");
|
|
529
566
|
for (const indicator of actorInput.detectionIndicators) print.indent(`• ${indicator}`);
|
|
530
567
|
print.newline();
|
|
531
568
|
}
|
|
532
|
-
|
|
569
|
+
print.divider();
|
|
570
|
+
const result = await select({
|
|
533
571
|
message: "Select project type:",
|
|
534
572
|
choices: [{
|
|
535
|
-
name: "Monolith
|
|
573
|
+
name: "Monolith – Single application structure",
|
|
536
574
|
value: ProjectType.MONOLITH,
|
|
537
|
-
description: "Traditional single-application project structure"
|
|
575
|
+
description: "\n Traditional single-application project structure"
|
|
538
576
|
}, {
|
|
539
|
-
name: "Monorepo
|
|
577
|
+
name: "Monorepo – Multiple packages/apps in one repository",
|
|
540
578
|
value: ProjectType.MONOREPO,
|
|
541
|
-
description: "Multiple packages managed together (uses workspaces)"
|
|
579
|
+
description: "\n Multiple packages managed together (uses workspaces)"
|
|
542
580
|
}]
|
|
543
581
|
});
|
|
582
|
+
print.info("");
|
|
583
|
+
return result;
|
|
544
584
|
}),
|
|
545
585
|
promptProjectName: fromPromise(async ({ input: actorInput }) => {
|
|
546
586
|
const newProjectService = new NewProjectService(actorInput.providedName, void 0);
|
|
@@ -552,49 +592,171 @@ const initActors = {
|
|
|
552
592
|
print.info(`Project name: ${trimmedName}`);
|
|
553
593
|
return trimmedName;
|
|
554
594
|
}
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
595
|
+
print.divider();
|
|
596
|
+
const result = await input({
|
|
597
|
+
message: "Enter your project name (press Enter to use current directory):",
|
|
598
|
+
validate: (value) => {
|
|
599
|
+
if (!value || value.trim() === "") return true;
|
|
600
|
+
return newProjectService.validateProjectName(value);
|
|
601
|
+
}
|
|
558
602
|
});
|
|
603
|
+
print.info("");
|
|
604
|
+
if (!result || result.trim() === "") return ".";
|
|
605
|
+
return result;
|
|
559
606
|
}),
|
|
560
607
|
createProjectDirectory: fromPromise(async ({ input: actorInput }) => {
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
608
|
+
if (actorInput.projectName === ".") {
|
|
609
|
+
const projectPath = process.cwd();
|
|
610
|
+
print.success(`Using current directory: ${projectPath}`);
|
|
611
|
+
return { projectPath };
|
|
612
|
+
}
|
|
613
|
+
const spinner = ora("Creating project directory...").start();
|
|
614
|
+
try {
|
|
615
|
+
const projectPath = path.join(process.cwd(), actorInput.projectName.trim());
|
|
616
|
+
await new NewProjectService(void 0, void 0).createProjectDirectory(projectPath, actorInput.projectName);
|
|
617
|
+
spinner.succeed(`Created project directory: ${projectPath}`);
|
|
618
|
+
return { projectPath };
|
|
619
|
+
} catch (error) {
|
|
620
|
+
spinner.fail("Failed to create project directory");
|
|
621
|
+
throw error;
|
|
622
|
+
}
|
|
564
623
|
}),
|
|
565
624
|
promptGitSetup: fromPromise(async ({ input: actorInput }) => {
|
|
566
625
|
const newProjectService = new NewProjectService(void 0, void 0);
|
|
567
|
-
|
|
626
|
+
print.divider();
|
|
627
|
+
const hasExistingRepo = await confirm({
|
|
568
628
|
message: "Do you have an existing Git repository you want to use?",
|
|
569
629
|
default: false
|
|
570
|
-
})
|
|
630
|
+
});
|
|
631
|
+
print.info("");
|
|
632
|
+
if (hasExistingRepo) {
|
|
633
|
+
print.divider();
|
|
571
634
|
const repoUrl = await input({
|
|
572
|
-
message: "Enter Git repository URL:",
|
|
573
|
-
validate: (value) =>
|
|
635
|
+
message: "Enter Git repository URL (press Enter to skip):",
|
|
636
|
+
validate: (value) => {
|
|
637
|
+
if (!value || value.trim() === "") return true;
|
|
638
|
+
return newProjectService.validateRepositoryUrl(value);
|
|
639
|
+
}
|
|
574
640
|
});
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
641
|
+
print.info("");
|
|
642
|
+
if (repoUrl && repoUrl.trim() !== "") {
|
|
643
|
+
const spinner = ora("Cloning repository...").start();
|
|
644
|
+
try {
|
|
645
|
+
await newProjectService.cloneExistingRepository(repoUrl.trim(), actorInput.projectPath);
|
|
646
|
+
spinner.succeed("Repository cloned successfully");
|
|
647
|
+
} catch (error) {
|
|
648
|
+
spinner.fail("Failed to clone repository");
|
|
649
|
+
throw error;
|
|
650
|
+
}
|
|
651
|
+
} else print.info("Skipped cloning repository");
|
|
652
|
+
} else {
|
|
653
|
+
print.divider();
|
|
654
|
+
const initGit = await confirm({
|
|
655
|
+
message: "Initialize a new Git repository?",
|
|
656
|
+
default: true
|
|
657
|
+
});
|
|
658
|
+
print.info("");
|
|
659
|
+
if (initGit) {
|
|
660
|
+
const spinner = ora("Initializing Git repository...").start();
|
|
661
|
+
try {
|
|
662
|
+
await newProjectService.initializeGitRepository(actorInput.projectPath);
|
|
663
|
+
spinner.succeed("Git repository initialized");
|
|
664
|
+
} catch (error) {
|
|
665
|
+
spinner.fail("Failed to initialize Git repository");
|
|
666
|
+
throw error;
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
}
|
|
580
670
|
}),
|
|
581
671
|
promptMcpSelection: fromPromise(async () => {
|
|
582
|
-
|
|
672
|
+
const checkbox = await import("@inquirer/prompts").then((m) => m.checkbox);
|
|
673
|
+
const choices = Object.values(MCPServer).map((server) => ({
|
|
674
|
+
name: MCP_SERVER_INFO[server].name,
|
|
675
|
+
value: server,
|
|
676
|
+
description: `\n ${MCP_SERVER_INFO[server].description}`,
|
|
677
|
+
checked: true
|
|
678
|
+
}));
|
|
679
|
+
print.divider();
|
|
680
|
+
const selected = await checkbox({
|
|
583
681
|
message: "Select MCP servers to configure:",
|
|
584
|
-
choices
|
|
585
|
-
name: MCP_SERVER_INFO[server].name,
|
|
586
|
-
value: server,
|
|
587
|
-
description: MCP_SERVER_INFO[server].description,
|
|
588
|
-
checked: true
|
|
589
|
-
})),
|
|
682
|
+
choices,
|
|
590
683
|
validate: (answer) => {
|
|
591
684
|
if (answer.length === 0) return "Please select at least one MCP server";
|
|
592
685
|
return true;
|
|
593
686
|
}
|
|
594
687
|
});
|
|
688
|
+
print.info("");
|
|
689
|
+
return selected;
|
|
690
|
+
}),
|
|
691
|
+
checkTemplatesFolder: fromPromise(async ({ input: actorInput }) => {
|
|
692
|
+
try {
|
|
693
|
+
const fs$1 = await import("node:fs/promises");
|
|
694
|
+
const defaultTemplatesPath = path.join(actorInput.workspaceRoot, "templates");
|
|
695
|
+
let templatesExists = false;
|
|
696
|
+
try {
|
|
697
|
+
await fs$1.access(defaultTemplatesPath);
|
|
698
|
+
templatesExists = true;
|
|
699
|
+
} catch {
|
|
700
|
+
templatesExists = false;
|
|
701
|
+
}
|
|
702
|
+
let finalTemplatesPath = defaultTemplatesPath;
|
|
703
|
+
let skipDownload = false;
|
|
704
|
+
if (templatesExists) {
|
|
705
|
+
print.divider();
|
|
706
|
+
print.info(`Templates folder already exists at: ${defaultTemplatesPath}`);
|
|
707
|
+
const useDifferentDir = await confirm({
|
|
708
|
+
message: "Would you like to use a different directory for templates?",
|
|
709
|
+
default: false
|
|
710
|
+
});
|
|
711
|
+
print.info("");
|
|
712
|
+
if (useDifferentDir) {
|
|
713
|
+
print.divider();
|
|
714
|
+
const customDir = await input({
|
|
715
|
+
message: "Enter custom templates directory path (relative to workspace root):",
|
|
716
|
+
default: "templates",
|
|
717
|
+
validate: (value) => {
|
|
718
|
+
if (!value || value.trim() === "") return "Please enter a valid directory path";
|
|
719
|
+
return true;
|
|
720
|
+
}
|
|
721
|
+
});
|
|
722
|
+
print.info("");
|
|
723
|
+
finalTemplatesPath = path.join(actorInput.workspaceRoot, customDir.trim());
|
|
724
|
+
try {
|
|
725
|
+
await fs$1.mkdir(finalTemplatesPath, { recursive: true });
|
|
726
|
+
print.success(`Created templates directory at: ${finalTemplatesPath}`);
|
|
727
|
+
} catch (error) {
|
|
728
|
+
throw new Error(`Failed to create templates directory at ${finalTemplatesPath}: ${error.message}`);
|
|
729
|
+
}
|
|
730
|
+
} else {
|
|
731
|
+
skipDownload = true;
|
|
732
|
+
print.info("Using existing templates folder");
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
let existingTemplates;
|
|
736
|
+
if (skipDownload) try {
|
|
737
|
+
existingTemplates = (await new TemplateSelectionService(finalTemplatesPath).listTemplates()).map((t) => t.name);
|
|
738
|
+
} catch (_error) {
|
|
739
|
+
print.warning("Could not read existing templates, will proceed anyway");
|
|
740
|
+
}
|
|
741
|
+
return {
|
|
742
|
+
templatesPath: finalTemplatesPath,
|
|
743
|
+
skipDownload,
|
|
744
|
+
existingTemplates
|
|
745
|
+
};
|
|
746
|
+
} catch (error) {
|
|
747
|
+
throw new Error(`Failed to check templates folder: ${error.message}`);
|
|
748
|
+
}
|
|
595
749
|
}),
|
|
596
750
|
downloadTemplates: fromPromise(async () => {
|
|
597
|
-
|
|
751
|
+
const spinner = ora("Downloading templates from AgiFlow/aicode-toolkit...").start();
|
|
752
|
+
try {
|
|
753
|
+
const tmpPath = await new TemplateSelectionService().downloadTemplatesToTmp(DEFAULT_TEMPLATE_REPO);
|
|
754
|
+
spinner.succeed("Templates downloaded successfully");
|
|
755
|
+
return tmpPath;
|
|
756
|
+
} catch (error) {
|
|
757
|
+
spinner.fail("Failed to download templates");
|
|
758
|
+
throw error;
|
|
759
|
+
}
|
|
598
760
|
}),
|
|
599
761
|
listTemplates: fromPromise(async ({ input: input$1 }) => {
|
|
600
762
|
const templates = await new TemplateSelectionService(input$1.tmpTemplatesPath).listTemplates();
|
|
@@ -605,37 +767,52 @@ const initActors = {
|
|
|
605
767
|
promptTemplateSelection: fromPromise(async ({ input: actorInput }) => {
|
|
606
768
|
const templates = await new TemplateSelectionService(actorInput.tmpTemplatesPath).listTemplates();
|
|
607
769
|
if (templates.length === 0) throw new Error("No templates available");
|
|
608
|
-
if (actorInput.projectType === ProjectType.MONOLITH)
|
|
609
|
-
|
|
610
|
-
choices: templates.map((t) => ({
|
|
770
|
+
if (actorInput.projectType === ProjectType.MONOLITH) {
|
|
771
|
+
const choices$1 = templates.map((t) => ({
|
|
611
772
|
name: t.name,
|
|
612
773
|
value: t.name,
|
|
613
|
-
description: t.description
|
|
614
|
-
}))
|
|
615
|
-
|
|
616
|
-
|
|
774
|
+
description: t.description ? `\n ${t.description}` : void 0
|
|
775
|
+
}));
|
|
776
|
+
print.divider();
|
|
777
|
+
const selected$1 = await select({
|
|
778
|
+
message: "Select template (monolith allows only one):",
|
|
779
|
+
choices: choices$1
|
|
780
|
+
});
|
|
781
|
+
print.info("");
|
|
782
|
+
return [selected$1];
|
|
783
|
+
}
|
|
784
|
+
const checkbox = await import("@inquirer/prompts").then((m) => m.checkbox);
|
|
785
|
+
const choices = templates.map((t) => ({
|
|
786
|
+
name: t.name,
|
|
787
|
+
value: t.name,
|
|
788
|
+
description: t.description ? `\n ${t.description}` : void 0,
|
|
789
|
+
checked: true
|
|
790
|
+
}));
|
|
791
|
+
print.divider();
|
|
792
|
+
const selected = await checkbox({
|
|
617
793
|
message: "Select templates (use space to select, enter to confirm):",
|
|
618
|
-
choices
|
|
619
|
-
name: t.name,
|
|
620
|
-
value: t.name,
|
|
621
|
-
description: t.description,
|
|
622
|
-
checked: true
|
|
623
|
-
}))
|
|
794
|
+
choices
|
|
624
795
|
});
|
|
796
|
+
print.info("");
|
|
625
797
|
if (selected.length === 0) throw new Error("Please select at least one template");
|
|
626
798
|
return selected;
|
|
627
799
|
}),
|
|
628
800
|
copyTemplates: fromPromise(async ({ input: actorInput }) => {
|
|
629
|
-
const
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
801
|
+
const spinner = ora("Copying templates to workspace...").start();
|
|
802
|
+
try {
|
|
803
|
+
await new TemplateSelectionService(actorInput.tmpTemplatesPath).copyTemplates(actorInput.selectedTemplates, actorInput.templatesPath, actorInput.projectType, actorInput.selectedMcpServers);
|
|
804
|
+
spinner.succeed(`Templates copied to ${actorInput.templatesPath}`);
|
|
805
|
+
return actorInput.templatesPath;
|
|
806
|
+
} catch (error) {
|
|
807
|
+
spinner.fail("Failed to copy templates");
|
|
808
|
+
throw error;
|
|
809
|
+
}
|
|
633
810
|
}),
|
|
634
811
|
createConfig: fromPromise(async ({ input: actorInput }) => {
|
|
635
812
|
if (actorInput.projectType === ProjectType.MONOLITH) {
|
|
636
813
|
const toolkitConfig = {
|
|
637
814
|
version: "1.0",
|
|
638
|
-
templatesPath: "templates",
|
|
815
|
+
templatesPath: path.relative(actorInput.workspaceRoot, actorInput.templatesPath) || "templates",
|
|
639
816
|
projectType: "monolith",
|
|
640
817
|
sourceTemplate: actorInput.selectedTemplates[0]
|
|
641
818
|
};
|
|
@@ -656,20 +833,120 @@ const initActors = {
|
|
|
656
833
|
print.info(`Using detected coding agent: ${actorInput.detectedAgent}`);
|
|
657
834
|
return actorInput.detectedAgent;
|
|
658
835
|
}
|
|
659
|
-
|
|
836
|
+
const agents = CodingAgentService.getAvailableAgents();
|
|
837
|
+
print.divider();
|
|
838
|
+
const selected = await select({
|
|
660
839
|
message: "Select coding agent for MCP configuration:",
|
|
661
|
-
choices:
|
|
840
|
+
choices: agents.map((agent) => ({
|
|
662
841
|
name: agent.name,
|
|
663
842
|
value: agent.value,
|
|
664
|
-
description: agent.description
|
|
843
|
+
description: `\n ${agent.description}`
|
|
665
844
|
}))
|
|
666
845
|
});
|
|
846
|
+
print.info("");
|
|
847
|
+
return selected;
|
|
667
848
|
}),
|
|
668
849
|
configureMCP: fromPromise(async ({ input: actorInput }) => {
|
|
669
|
-
|
|
850
|
+
const spinner = ora(`Setting up MCP for ${actorInput.codingAgent}...`).start();
|
|
851
|
+
try {
|
|
852
|
+
await new CodingAgentService(actorInput.workspaceRoot).setupMCP(actorInput.codingAgent);
|
|
853
|
+
spinner.succeed("MCP configuration completed");
|
|
854
|
+
} catch (error) {
|
|
855
|
+
spinner.fail("Failed to configure MCP");
|
|
856
|
+
throw error;
|
|
857
|
+
}
|
|
670
858
|
}),
|
|
671
859
|
cleanup: fromPromise(async ({ input: input$1 }) => {
|
|
672
|
-
if (input$1.tmpTemplatesPath)
|
|
860
|
+
if (input$1.tmpTemplatesPath) {
|
|
861
|
+
const spinner = ora("Cleaning up temporary files...").start();
|
|
862
|
+
try {
|
|
863
|
+
await new TemplateSelectionService(input$1.tmpTemplatesPath).cleanup();
|
|
864
|
+
spinner.succeed("Cleaned up temporary files");
|
|
865
|
+
} catch (_error) {
|
|
866
|
+
spinner.warn("Could not clean up all temporary files");
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
}),
|
|
870
|
+
detectSpecTool: fromPromise(async ({ input: input$1 }) => {
|
|
871
|
+
print.info("\nDetecting spec tools...");
|
|
872
|
+
const detectedTool = await new SpecToolService(input$1.workspaceRoot).detectSpecTool();
|
|
873
|
+
if (detectedTool) print.success(`Detected ${SPEC_TOOL_INFO[detectedTool].name} in workspace`);
|
|
874
|
+
else print.info("No spec tool detected");
|
|
875
|
+
return detectedTool;
|
|
876
|
+
}),
|
|
877
|
+
promptSpecDrivenApproach: fromPromise(async ({ input: actorInput }) => {
|
|
878
|
+
if (actorInput.detectedSpecTool) {
|
|
879
|
+
print.divider();
|
|
880
|
+
const result$1 = await confirm({
|
|
881
|
+
message: `${SPEC_TOOL_INFO[actorInput.detectedSpecTool].name} is installed. Would you like to update the agent instructions for spec-driven development?`,
|
|
882
|
+
default: true
|
|
883
|
+
});
|
|
884
|
+
print.info("");
|
|
885
|
+
return result$1;
|
|
886
|
+
}
|
|
887
|
+
print.divider();
|
|
888
|
+
const result = await confirm({
|
|
889
|
+
message: "Would you like to install OpenSpec for spec-driven development? This helps AI assistants agree on what to build before writing code.",
|
|
890
|
+
default: false
|
|
891
|
+
});
|
|
892
|
+
print.info("");
|
|
893
|
+
return result;
|
|
894
|
+
}),
|
|
895
|
+
setupSpec: fromPromise(async ({ input: input$1 }) => {
|
|
896
|
+
const codingAgentService = new CodingAgentService(input$1.workspaceRoot);
|
|
897
|
+
const specToolService = new SpecToolService(input$1.workspaceRoot, SpecTool.OPENSPEC, codingAgentService);
|
|
898
|
+
if (input$1.isAlreadyInstalled) {
|
|
899
|
+
const spinner = ora("Updating OpenSpec agent instructions...").start();
|
|
900
|
+
try {
|
|
901
|
+
const enabledMcps = {
|
|
902
|
+
scaffoldMcp: input$1.selectedMcpServers?.includes(MCPServer.SCAFFOLD) ?? false,
|
|
903
|
+
architectMcp: input$1.selectedMcpServers?.includes(MCPServer.ARCHITECT) ?? false,
|
|
904
|
+
projectType: input$1.projectType
|
|
905
|
+
};
|
|
906
|
+
await specToolService.updateInstructions(enabledMcps, input$1.codingAgent);
|
|
907
|
+
spinner.succeed("OpenSpec agent instructions updated");
|
|
908
|
+
} catch (error) {
|
|
909
|
+
spinner.fail("Failed to update OpenSpec instructions");
|
|
910
|
+
throw error;
|
|
911
|
+
}
|
|
912
|
+
} else {
|
|
913
|
+
const spinner = ora("Initializing OpenSpec...").start();
|
|
914
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
915
|
+
spinner.stop();
|
|
916
|
+
try {
|
|
917
|
+
await specToolService.initializeSpec();
|
|
918
|
+
print.success("OpenSpec initialized successfully");
|
|
919
|
+
} catch (error) {
|
|
920
|
+
print.error("Failed to initialize OpenSpec");
|
|
921
|
+
throw error;
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
}),
|
|
925
|
+
promptSpecInstructions: fromPromise(async () => {
|
|
926
|
+
print.divider();
|
|
927
|
+
const result = await confirm({
|
|
928
|
+
message: "Would you like to update the agent instructions with OpenSpec workflow guidance?",
|
|
929
|
+
default: true
|
|
930
|
+
});
|
|
931
|
+
print.info("");
|
|
932
|
+
return result;
|
|
933
|
+
}),
|
|
934
|
+
updateSpecInstructions: fromPromise(async ({ input: input$1 }) => {
|
|
935
|
+
const spinner = ora("Updating OpenSpec agent instructions...").start();
|
|
936
|
+
try {
|
|
937
|
+
const codingAgentService = new CodingAgentService(input$1.workspaceRoot);
|
|
938
|
+
const specToolService = new SpecToolService(input$1.workspaceRoot, SpecTool.OPENSPEC, codingAgentService);
|
|
939
|
+
const enabledMcps = {
|
|
940
|
+
scaffoldMcp: input$1.selectedMcpServers?.includes(MCPServer.SCAFFOLD) ?? false,
|
|
941
|
+
architectMcp: input$1.selectedMcpServers?.includes(MCPServer.ARCHITECT) ?? false,
|
|
942
|
+
projectType: input$1.projectType
|
|
943
|
+
};
|
|
944
|
+
await specToolService.updateInstructions(enabledMcps, input$1.codingAgent);
|
|
945
|
+
spinner.succeed("OpenSpec agent instructions updated");
|
|
946
|
+
} catch (error) {
|
|
947
|
+
spinner.fail("Failed to update OpenSpec instructions");
|
|
948
|
+
throw error;
|
|
949
|
+
}
|
|
673
950
|
})
|
|
674
951
|
};
|
|
675
952
|
/**
|