@agiflowai/aicode-toolkit 1.0.25 → 1.1.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/dist/cli.cjs +164 -172
- package/dist/cli.mjs +51 -59
- package/dist/index.cjs +3 -4
- package/dist/index.d.cts +0 -1
- package/dist/index.d.mts +0 -1
- package/dist/index.mjs +2 -4
- package/dist/{mcp--A-5zuBI.cjs → mcp-CwMcfNLE.mjs} +23 -25
- package/dist/{mcp-CBcPdzNG.mjs → mcp-HNZY6MpT.cjs} +23 -7
- package/dist/mcp-XXavvCHL.cjs +3 -0
- package/dist/{utils-DMP5MQCv.cjs → utils-BCVXMGNF.cjs} +198 -206
- package/dist/{utils-BTSpNlWu.mjs → utils-BM7-O0sC.mjs} +18 -21
- package/package.json +21 -21
- package/dist/mcp-B9X7HURl.cjs +0 -4
- package/dist/mcp-Cvo6pkS0.mjs +0 -3
package/dist/cli.cjs
CHANGED
|
@@ -1,22 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
const require_utils = require(
|
|
3
|
-
const require_mcp = require(
|
|
4
|
-
let
|
|
2
|
+
const require_utils = require("./utils-BCVXMGNF.cjs");
|
|
3
|
+
const require_mcp = require("./mcp-HNZY6MpT.cjs");
|
|
4
|
+
let _agiflowai_aicode_utils = require("@agiflowai/aicode-utils");
|
|
5
5
|
let node_fs_promises = require("node:fs/promises");
|
|
6
6
|
let node_path = require("node:path");
|
|
7
|
-
node_path = require_utils.__toESM(node_path);
|
|
7
|
+
node_path = require_utils.__toESM(node_path, 1);
|
|
8
8
|
let liquidjs = require("liquidjs");
|
|
9
9
|
let commander = require("commander");
|
|
10
|
-
let
|
|
10
|
+
let _inquirer_prompts = require("@inquirer/prompts");
|
|
11
11
|
let ora = require("ora");
|
|
12
|
-
ora = require_utils.__toESM(ora);
|
|
12
|
+
ora = require_utils.__toESM(ora, 1);
|
|
13
13
|
let xstate = require("xstate");
|
|
14
14
|
let js_yaml = require("js-yaml");
|
|
15
|
-
js_yaml = require_utils.__toESM(js_yaml);
|
|
16
|
-
|
|
15
|
+
js_yaml = require_utils.__toESM(js_yaml, 1);
|
|
17
16
|
//#region package.json
|
|
18
|
-
var version = "1.0.
|
|
19
|
-
|
|
17
|
+
var version = "1.0.26";
|
|
20
18
|
//#endregion
|
|
21
19
|
//#region src/commands/add.ts
|
|
22
20
|
/**
|
|
@@ -24,9 +22,9 @@ var version = "1.0.24";
|
|
|
24
22
|
*/
|
|
25
23
|
const addCommand = new commander.Command("add").description("Add a template to templates folder").requiredOption("--name <name>", "Template name").requiredOption("--url <url>", "URL of the template repository to download").option("--path <path>", "Override templates folder path (uses .toolkit/settings.yaml or legacy toolkit.yaml config by default)").option("--type <type>", "Template type: boilerplate or scaffold", "boilerplate").action(async (options) => {
|
|
26
24
|
try {
|
|
27
|
-
const foundTemplatesPath = options.path ? node_path.default.resolve(options.path) : await
|
|
25
|
+
const foundTemplatesPath = options.path ? node_path.default.resolve(options.path) : await _agiflowai_aicode_utils.TemplatesManagerService.findTemplatesPath();
|
|
28
26
|
if (!foundTemplatesPath) {
|
|
29
|
-
|
|
27
|
+
_agiflowai_aicode_utils.messages.error("Templates folder not found. Create a templates folder or specify templatesPath in .toolkit/settings.yaml");
|
|
30
28
|
process.exit(1);
|
|
31
29
|
}
|
|
32
30
|
const templatesPath = foundTemplatesPath;
|
|
@@ -34,55 +32,53 @@ const addCommand = new commander.Command("add").description("Add a template to t
|
|
|
34
32
|
const templateName = options.name;
|
|
35
33
|
const templateUrl = options.url;
|
|
36
34
|
if (templateType !== "boilerplate" && templateType !== "scaffold") {
|
|
37
|
-
|
|
35
|
+
_agiflowai_aicode_utils.messages.error("Invalid template type. Use: boilerplate or scaffold");
|
|
38
36
|
process.exit(1);
|
|
39
37
|
}
|
|
40
38
|
const targetFolder = node_path.default.join(templatesPath, `${templateType}s`, templateName);
|
|
41
|
-
if (await (0,
|
|
42
|
-
|
|
39
|
+
if (await (0, _agiflowai_aicode_utils.pathExists)(targetFolder)) {
|
|
40
|
+
_agiflowai_aicode_utils.messages.error(`Template '${templateName}' already exists at ${targetFolder}`);
|
|
43
41
|
process.exit(1);
|
|
44
42
|
}
|
|
45
|
-
|
|
46
|
-
await (0,
|
|
47
|
-
const parsedUrl = (0,
|
|
43
|
+
_agiflowai_aicode_utils.print.info(`${_agiflowai_aicode_utils.icons.download} Downloading template '${templateName}' from ${templateUrl}...`);
|
|
44
|
+
await (0, _agiflowai_aicode_utils.ensureDir)(node_path.default.dirname(targetFolder));
|
|
45
|
+
const parsedUrl = (0, _agiflowai_aicode_utils.parseGitHubUrl)(templateUrl);
|
|
48
46
|
try {
|
|
49
47
|
if (parsedUrl.isSubdirectory && parsedUrl.branch && parsedUrl.subdirectory) {
|
|
50
|
-
|
|
51
|
-
await (0,
|
|
52
|
-
} else await (0,
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
48
|
+
_agiflowai_aicode_utils.print.info(`${_agiflowai_aicode_utils.icons.folder} Detected subdirectory: ${parsedUrl.subdirectory} (branch: ${parsedUrl.branch})`);
|
|
49
|
+
await (0, _agiflowai_aicode_utils.cloneSubdirectory)(parsedUrl.repoUrl, parsedUrl.branch, parsedUrl.subdirectory, targetFolder);
|
|
50
|
+
} else await (0, _agiflowai_aicode_utils.cloneRepository)(parsedUrl.repoUrl, targetFolder);
|
|
51
|
+
_agiflowai_aicode_utils.messages.success(`Template '${templateName}' added successfully!`);
|
|
52
|
+
_agiflowai_aicode_utils.print.header(`\n${_agiflowai_aicode_utils.icons.folder} Template location:`);
|
|
53
|
+
_agiflowai_aicode_utils.print.indent(targetFolder);
|
|
56
54
|
const configFiles = [node_path.default.join(targetFolder, "boilerplate.yaml"), node_path.default.join(targetFolder, "scaffold.yaml")];
|
|
57
55
|
let hasConfig = false;
|
|
58
|
-
for (const configFile of configFiles) if (await (0,
|
|
59
|
-
|
|
60
|
-
|
|
56
|
+
for (const configFile of configFiles) if (await (0, _agiflowai_aicode_utils.pathExists)(configFile)) {
|
|
57
|
+
_agiflowai_aicode_utils.print.header(`\n${_agiflowai_aicode_utils.icons.config} Configuration file found:`);
|
|
58
|
+
_agiflowai_aicode_utils.print.indent(node_path.default.basename(configFile));
|
|
61
59
|
hasConfig = true;
|
|
62
60
|
break;
|
|
63
61
|
}
|
|
64
62
|
if (!hasConfig) {
|
|
65
|
-
|
|
66
|
-
|
|
63
|
+
_agiflowai_aicode_utils.messages.warning("Warning: No configuration file found (boilerplate.yaml or scaffold.yaml)");
|
|
64
|
+
_agiflowai_aicode_utils.print.indent("You may need to create one manually.");
|
|
67
65
|
}
|
|
68
|
-
|
|
66
|
+
_agiflowai_aicode_utils.sections.nextSteps([`Review the template in ${targetFolder}`, `Test it with: scaffold-mcp ${templateType} list`]);
|
|
69
67
|
} catch (error) {
|
|
70
|
-
if (error.message.includes("not found") || error.message.includes("command not found"))
|
|
71
|
-
else if (error.message.includes("Authentication failed"))
|
|
72
|
-
else if (error.message.includes("Repository not found"))
|
|
73
|
-
else
|
|
68
|
+
if (error.message.includes("not found") || error.message.includes("command not found")) _agiflowai_aicode_utils.messages.error("git command not found. Please install git first.");
|
|
69
|
+
else if (error.message.includes("Authentication failed")) _agiflowai_aicode_utils.messages.error("Authentication failed. Make sure you have access to the repository.");
|
|
70
|
+
else if (error.message.includes("Repository not found")) _agiflowai_aicode_utils.messages.error("Repository not found. Check the URL and try again.");
|
|
71
|
+
else _agiflowai_aicode_utils.messages.error("Failed to clone repository:", error);
|
|
74
72
|
process.exit(1);
|
|
75
73
|
}
|
|
76
74
|
} catch (error) {
|
|
77
|
-
|
|
75
|
+
_agiflowai_aicode_utils.messages.error("Error adding template:", error);
|
|
78
76
|
process.exit(1);
|
|
79
77
|
}
|
|
80
78
|
});
|
|
81
|
-
|
|
82
79
|
//#endregion
|
|
83
80
|
//#region src/templates/settings.yaml.liquid?raw
|
|
84
81
|
var settings_yaml_default = "# .toolkit/settings.yaml\n# Toolkit configuration for aicode-toolkit\n#\n# Local overrides go in .toolkit/settings.local.yaml (add to .gitignore).\n# Local settings are shallow-merged over this file — useful for per-developer\n# LLM tool preferences or API keys without committing them.\n#\n# All fields are optional. Uncomment and edit what you need.\n\n# ---------------------------------------------------------------------------\n# Project identity\n# ---------------------------------------------------------------------------\n\n{% comment %}Project type: monolith (single app) or monorepo (multiple packages/apps){% endcomment %}\n{% if projectType %}\nprojectType: {{ projectType }}\n{% else %}\n# projectType: monolith\n{% endif %}\n\n{% comment %}Path to the scaffold templates directory, relative to workspace root.{% endcomment %}\n{% if templatesPath %}\ntemplatesPath: {{ templatesPath }}\n{% else %}\n# templatesPath: ./templates\n{% endif %}\n\n{% comment %}Active template name (monolith only — monorepo reads from project.json).{% endcomment %}\n{% if sourceTemplate %}\nsourceTemplate: {{ sourceTemplate }}\n{% else %}\n# sourceTemplate: react-vite\n{% endif %}\n\n# Config schema version.\n# version: '1.0'\n\n# ---------------------------------------------------------------------------\n# scaffold-mcp — configuration for the scaffold-mcp CLI\n# CLI flags always take precedence over values set here.\n# ---------------------------------------------------------------------------\n\nscaffold-mcp:\n\n # -------------------------------------------------------------------------\n # mcp-serve — defaults for `scaffold-mcp mcp-serve`\n # -------------------------------------------------------------------------\n mcp-serve:\n # Transport type: stdio | http | sse (default: stdio)\n # type: stdio\n\n # Port for http/sse transport (default: 3000)\n # port: 3000\n\n # Host to bind for http/sse transport (default: localhost)\n # host: localhost\n\n # Enable admin tools such as generate-boilerplate (default: false)\n # adminEnable: false\n\n # Render prompts with skill front matter for Claude Code (default: false)\n # promptAsSkill: false\n\n # Fallback LLM tool used when scaffold-mcp needs AI assistance.\n # Supported: claude-code | gemini-cli | codex\n {% if fallbackTool %}\n fallbackTool: {{ fallbackTool }}\n {% if fallbackToolConfig %}\n # Config passed to the fallback LLM tool.\n fallbackToolConfig:\n {% for pair in fallbackToolConfig %}\n {{ pair[0] }}: {{ pair[1] }}\n {% endfor %}\n {% else %}\n # Config passed to the fallback LLM tool.\n # fallbackToolConfig:\n # model: gemini-2.0-flash\n {% endif %}\n {% else %}\n # fallbackTool: gemini-cli\n # Config passed to the fallback LLM tool.\n # fallbackToolConfig:\n # model: gemini-2.0-flash\n {% endif %}\n\n # Ordered fallback chain used when fallbackTool is not set.\n # The first valid entry wins.\n # fallbacks:\n # - tool: gemini-cli\n # config:\n # model: gemini-2.0-flash\n # - tool: codex\n # config:\n # model: gpt-5.2-mini\n\n # Extra CLI args merged into the mcp-serve command (key: value → --key value)\n # args:\n # review-tool: gemini-cli\n\n # -------------------------------------------------------------------------\n # hook — defaults for `scaffold-mcp hook`\n # Keyed by agent name, then by hook method.\n # Supported agents : claude-code | gemini-cli\n # Supported methods : preToolUse | postToolUse | userPromptSubmit | taskCompleted | stop\n # CLI flags --fallback-tool and --fallback-tool-config still take precedence.\n # -------------------------------------------------------------------------\n hook:\n\n claude-code:\n preToolUse:\n # LLM tool to use for this hook. Supported: claude-code | gemini-cli | codex\n {% if fallbackTool %}\n llm-tool: {{ fallbackTool }}\n {% if fallbackToolConfig %}\n tool-config:\n {% for pair in fallbackToolConfig %}\n {{ pair[0] }}: {{ pair[1] }}\n {% endfor %}\n {% endif %}\n {% else %}\n # llm-tool: gemini-cli\n # tool-config:\n # model: gemini-2.0-flash\n {% endif %}\n # fallbacks:\n # - tool: codex\n # config:\n # model: gpt-5.2-mini\n # matcher: Edit|MultiEdit|Write\n # Extra CLI args appended to the generated hook command (key: value → --key value)\n # args:\n # llm-tool: gemini-cli\n\n postToolUse:\n # matcher: Edit|MultiEdit|Write\n {% if fallbackTool %}\n llm-tool: {{ fallbackTool }}\n {% if fallbackToolConfig %}\n tool-config:\n {% for pair in fallbackToolConfig %}\n {{ pair[0] }}: {{ pair[1] }}\n {% endfor %}\n {% endif %}\n {% else %}\n # llm-tool: gemini-cli\n # tool-config:\n # model: gemini-2.0-flash\n {% endif %}\n # fallbacks:\n # - tool: codex\n # config:\n # model: gpt-5.2-mini\n # args:\n # llm-tool: gemini-cli\n\n userPromptSubmit:\n {% if fallbackTool %}\n llm-tool: {{ fallbackTool }}\n {% if fallbackToolConfig %}\n tool-config:\n {% for pair in fallbackToolConfig %}\n {{ pair[0] }}: {{ pair[1] }}\n {% endfor %}\n {% endif %}\n {% else %}\n # llm-tool: gemini-cli\n # tool-config:\n # model: gemini-2.0-flash\n {% endif %}\n # args:\n # llm-tool: gemini-cli\n\n taskCompleted:\n {% if fallbackTool %}\n llm-tool: {{ fallbackTool }}\n {% if fallbackToolConfig %}\n tool-config:\n {% for pair in fallbackToolConfig %}\n {{ pair[0] }}: {{ pair[1] }}\n {% endfor %}\n {% endif %}\n {% else %}\n # llm-tool: gemini-cli\n # tool-config:\n # model: gemini-2.0-flash\n {% endif %}\n # args:\n # llm-tool: gemini-cli\n\n stop:\n {% if fallbackTool %}\n llm-tool: {{ fallbackTool }}\n {% if fallbackToolConfig %}\n tool-config:\n {% for pair in fallbackToolConfig %}\n {{ pair[0] }}: {{ pair[1] }}\n {% endfor %}\n {% endif %}\n {% else %}\n # llm-tool: gemini-cli\n # tool-config:\n # model: gemini-2.0-flash\n {% endif %}\n # args:\n # llm-tool: gemini-cli\n\n gemini-cli:\n preToolUse:\n {% if fallbackTool %}\n llm-tool: {{ fallbackTool }}\n {% if fallbackToolConfig %}\n tool-config:\n {% for pair in fallbackToolConfig %}\n {{ pair[0] }}: {{ pair[1] }}\n {% endfor %}\n {% endif %}\n {% else %}\n # llm-tool: gemini-cli\n # tool-config:\n # model: gemini-2.0-flash\n {% endif %}\n\n postToolUse:\n {% if fallbackTool %}\n llm-tool: {{ fallbackTool }}\n {% if fallbackToolConfig %}\n tool-config:\n {% for pair in fallbackToolConfig %}\n {{ pair[0] }}: {{ pair[1] }}\n {% endfor %}\n {% endif %}\n {% else %}\n # llm-tool: gemini-cli\n # tool-config:\n # model: gemini-2.0-flash\n {% endif %}\n\n# ---------------------------------------------------------------------------\n# architect-mcp — configuration for the architect-mcp CLI\n# CLI flags always take precedence over values set here.\n# ---------------------------------------------------------------------------\n\narchitect-mcp:\n\n # -------------------------------------------------------------------------\n # mcp-serve — defaults for `architect-mcp mcp-serve`\n # -------------------------------------------------------------------------\n mcp-serve:\n # Transport type: stdio | http | sse (default: stdio)\n # type: stdio\n\n # Port for http/sse transport (default: 3000)\n # port: 3000\n\n # Host to bind for http/sse transport (default: localhost)\n # host: localhost\n\n # Enable admin tools such as add-design-pattern and add-rule (default: false)\n # adminEnable: false\n\n # Fallback LLM tool used for both design-pattern and review when specific tools are not set.\n # Supported: claude-code | gemini-cli | codex\n {% if fallbackTool %}\n fallbackTool: {{ fallbackTool }}\n {% if fallbackToolConfig %}\n # Config passed to the fallback LLM tool.\n fallbackToolConfig:\n {% for pair in fallbackToolConfig %}\n {{ pair[0] }}: {{ pair[1] }}\n {% endfor %}\n {% else %}\n # Config passed to the fallback LLM tool.\n # fallbackToolConfig:\n # model: gemini-2.0-flash\n {% endif %}\n {% else %}\n # fallbackTool: gemini-cli\n # Config passed to the fallback LLM tool.\n # fallbackToolConfig:\n # model: gemini-2.0-flash\n {% endif %}\n\n # Ordered fallback chain used when fallbackTool is not set.\n # The first valid entry wins.\n # fallbacks:\n # - tool: gemini-cli\n # config:\n # model: gemini-2.0-flash\n # - tool: codex\n # config:\n # model: gpt-5.2-mini\n\n # LLM tool used specifically for get-file-design-pattern analysis.\n # Overrides fallbackTool for design pattern operations.\n # designPatternTool: gemini-cli\n\n # Config passed to the design pattern LLM tool.\n # designPatternToolConfig:\n # model: gemini-2.0-flash\n\n # LLM tool used specifically for review-code-change analysis.\n # Overrides fallbackTool for code review operations.\n # reviewTool: gemini-cli\n\n # Config passed to the review LLM tool.\n # reviewToolConfig:\n # model: gemini-2.0-flash\n\n # Extra CLI args merged into the mcp-serve command (key: value → --key value)\n # args:\n # review-tool: gemini-cli\n\n # -------------------------------------------------------------------------\n # hook — defaults for `architect-mcp hook`\n # Keyed by agent name, then by hook method.\n # Supported agents : claude-code | gemini-cli\n # Supported methods : preToolUse | postToolUse\n # CLI flags --llm-tool, --fallback-tool, and --tool-config still take precedence.\n # -------------------------------------------------------------------------\n hook:\n\n claude-code:\n preToolUse:\n # Static pattern matching is usually enough here. Leave llm-tool unset unless\n # you want extra pattern filtering via LLM.\n {% if fallbackTool %}\n fallback-tool: {{ fallbackTool }}\n {% if fallbackToolConfig %}\n fallback-tool-config:\n {% for pair in fallbackToolConfig %}\n {{ pair[0] }}: {{ pair[1] }}\n {% endfor %}\n {% endif %}\n {% else %}\n # fallback-tool: gemini-cli\n # fallback-tool-config:\n # model: gemini-2.0-flash\n {% endif %}\n # fallbacks:\n # - tool: codex\n # config:\n # model: gpt-5.2-mini\n # matcher: Edit|MultiEdit|Write\n # Extra CLI args appended to the generated hook command (key: value → --key value)\n # args:\n # llm-tool: gemini-cli\n\n postToolUse:\n # matcher: Edit|MultiEdit|Write\n # Set llm-tool only if you want LLM-based review. A cheap model is recommended.\n {% if fallbackTool %}\n llm-tool: {{ fallbackTool }}\n {% if fallbackToolConfig %}\n tool-config:\n {% for pair in fallbackToolConfig %}\n {{ pair[0] }}: {{ pair[1] }}\n {% endfor %}\n {% endif %}\n {% else %}\n # llm-tool: gemini-cli\n # tool-config:\n # model: gemini-2.0-flash\n {% endif %}\n # fallbacks:\n # - tool: codex\n # config:\n # model: gpt-5.2-mini\n # args:\n # llm-tool: gemini-cli\n\n gemini-cli:\n preToolUse:\n {% if fallbackTool %}\n llm-tool: {{ fallbackTool }}\n {% if fallbackToolConfig %}\n tool-config:\n {% for pair in fallbackToolConfig %}\n {{ pair[0] }}: {{ pair[1] }}\n {% endfor %}\n {% endif %}\n {% else %}\n # llm-tool: gemini-cli\n # tool-config:\n # model: gemini-2.0-flash\n {% endif %}\n\n postToolUse:\n {% if fallbackTool %}\n llm-tool: {{ fallbackTool }}\n {% if fallbackToolConfig %}\n tool-config:\n {% for pair in fallbackToolConfig %}\n {{ pair[0] }}: {{ pair[1] }}\n {% endfor %}\n {% endif %}\n {% else %}\n # llm-tool: gemini-cli\n # tool-config:\n # model: gemini-2.0-flash\n {% endif %}\n\n# ---------------------------------------------------------------------------\n# mcp-config — generates mcp-config.yaml via `aicode sync --mcp`\n# Servers listed here become entries in mcp-config.yaml.\n# Run `aicode sync` to write the output file.\n# ---------------------------------------------------------------------------\n\n# mcp-config:\n# servers:\n# scaffold-mcp:\n# command: bun\n# args:\n# - run\n# - packages/scaffold-mcp/src/cli.ts\n# - mcp-serve\n# - --admin-enable\n# - --prompt-as-skill\n# instruction: \"Use this server for generating boilerplate code, scaffolding new projects, and adding features to existing projects.\"\n# architect-mcp:\n# command: bun\n# args:\n# - run\n# - packages/architect-mcp/src/cli.ts\n# - mcp-serve\n# instruction: \"Use this server for design pattern guidance and code review.\"\n# skills:\n# paths:\n# - docs/skills\n";
|
|
85
|
-
|
|
86
82
|
//#endregion
|
|
87
83
|
//#region src/states/init-machine.ts
|
|
88
84
|
/**
|
|
@@ -94,7 +90,7 @@ const initMachine = (0, xstate.createMachine)({
|
|
|
94
90
|
id: "init",
|
|
95
91
|
types: {},
|
|
96
92
|
initial: "displayingBanner",
|
|
97
|
-
context: ({ input
|
|
93
|
+
context: ({ input }) => ({
|
|
98
94
|
workspaceRoot: void 0,
|
|
99
95
|
projectName: void 0,
|
|
100
96
|
projectType: void 0,
|
|
@@ -109,7 +105,7 @@ const initMachine = (0, xstate.createMachine)({
|
|
|
109
105
|
codingAgent: void 0,
|
|
110
106
|
detectedSpecTool: void 0,
|
|
111
107
|
useSpecDrivenApproach: void 0,
|
|
112
|
-
options: input
|
|
108
|
+
options: input.options,
|
|
113
109
|
error: void 0
|
|
114
110
|
}),
|
|
115
111
|
states: {
|
|
@@ -434,7 +430,6 @@ const initMachine = (0, xstate.createMachine)({
|
|
|
434
430
|
failed: { type: "final" }
|
|
435
431
|
}
|
|
436
432
|
}, { guards: {} });
|
|
437
|
-
|
|
438
433
|
//#endregion
|
|
439
434
|
//#region src/commands/init.ts
|
|
440
435
|
const DEFAULT_TEMPLATE_REPO = {
|
|
@@ -451,10 +446,10 @@ const initActors = {
|
|
|
451
446
|
require_utils.displayBanner();
|
|
452
447
|
}),
|
|
453
448
|
checkWorkspaceExists: (0, xstate.fromPromise)(async () => {
|
|
454
|
-
const workspaceRoot = await (0,
|
|
449
|
+
const workspaceRoot = await (0, _agiflowai_aicode_utils.findWorkspaceRoot)();
|
|
455
450
|
if (workspaceRoot) {
|
|
456
|
-
|
|
457
|
-
|
|
451
|
+
_agiflowai_aicode_utils.print.divider();
|
|
452
|
+
_agiflowai_aicode_utils.print.info(`Found workspace at: ${workspaceRoot}`);
|
|
458
453
|
return {
|
|
459
454
|
exists: true,
|
|
460
455
|
workspaceRoot
|
|
@@ -462,42 +457,42 @@ const initActors = {
|
|
|
462
457
|
}
|
|
463
458
|
return { exists: false };
|
|
464
459
|
}),
|
|
465
|
-
detectProjectType: (0, xstate.fromPromise)(async ({ input
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
const result = await (0,
|
|
469
|
-
if (result.projectType)
|
|
460
|
+
detectProjectType: (0, xstate.fromPromise)(async ({ input }) => {
|
|
461
|
+
_agiflowai_aicode_utils.print.divider();
|
|
462
|
+
_agiflowai_aicode_utils.print.info("Detecting project type...");
|
|
463
|
+
const result = await (0, _agiflowai_aicode_utils.detectProjectType)(input.workspaceRoot);
|
|
464
|
+
if (result.projectType) _agiflowai_aicode_utils.print.success(`Detected ${result.projectType} project`);
|
|
470
465
|
return result;
|
|
471
466
|
}),
|
|
472
467
|
promptProjectType: (0, xstate.fromPromise)(async ({ input: actorInput }) => {
|
|
473
468
|
if (actorInput.providedProjectType) {
|
|
474
469
|
const projectType = actorInput.providedProjectType;
|
|
475
|
-
|
|
470
|
+
_agiflowai_aicode_utils.print.info(`Project type: ${projectType}`);
|
|
476
471
|
return projectType;
|
|
477
472
|
}
|
|
478
473
|
if (actorInput.detectedProjectType) {
|
|
479
|
-
|
|
474
|
+
_agiflowai_aicode_utils.print.info(`Using detected project type: ${actorInput.detectedProjectType}`);
|
|
480
475
|
return actorInput.detectedProjectType;
|
|
481
476
|
}
|
|
482
477
|
if (actorInput.detectionIndicators && actorInput.detectionIndicators.length > 0) {
|
|
483
|
-
|
|
484
|
-
for (const indicator of actorInput.detectionIndicators)
|
|
485
|
-
|
|
478
|
+
_agiflowai_aicode_utils.print.info("\nDetection results:");
|
|
479
|
+
for (const indicator of actorInput.detectionIndicators) _agiflowai_aicode_utils.print.indent(`• ${indicator}`);
|
|
480
|
+
_agiflowai_aicode_utils.print.newline();
|
|
486
481
|
}
|
|
487
|
-
|
|
488
|
-
const result = await (0,
|
|
482
|
+
_agiflowai_aicode_utils.print.divider();
|
|
483
|
+
const result = await (0, _inquirer_prompts.select)({
|
|
489
484
|
message: "Select project type:",
|
|
490
485
|
choices: [{
|
|
491
486
|
name: "Monolith – Single application structure",
|
|
492
|
-
value:
|
|
487
|
+
value: _agiflowai_aicode_utils.ProjectType.MONOLITH,
|
|
493
488
|
description: "\n Traditional single-application project structure"
|
|
494
489
|
}, {
|
|
495
490
|
name: "Monorepo – Multiple packages/apps in one repository",
|
|
496
|
-
value:
|
|
491
|
+
value: _agiflowai_aicode_utils.ProjectType.MONOREPO,
|
|
497
492
|
description: "\n Multiple packages managed together (uses workspaces)"
|
|
498
493
|
}]
|
|
499
494
|
});
|
|
500
|
-
|
|
495
|
+
_agiflowai_aicode_utils.print.info("");
|
|
501
496
|
return result;
|
|
502
497
|
}),
|
|
503
498
|
promptProjectName: (0, xstate.fromPromise)(async ({ input: actorInput }) => {
|
|
@@ -507,25 +502,25 @@ const initActors = {
|
|
|
507
502
|
const trimmedName = providedName.trim();
|
|
508
503
|
const validationResult = newProjectService.validateProjectName(trimmedName);
|
|
509
504
|
if (validationResult !== true) throw new Error(validationResult);
|
|
510
|
-
|
|
505
|
+
_agiflowai_aicode_utils.print.info(`Project name: ${trimmedName}`);
|
|
511
506
|
return trimmedName;
|
|
512
507
|
}
|
|
513
|
-
|
|
514
|
-
const result = await (0,
|
|
508
|
+
_agiflowai_aicode_utils.print.divider();
|
|
509
|
+
const result = await (0, _inquirer_prompts.input)({
|
|
515
510
|
message: "Enter your project name (press Enter to use current directory):",
|
|
516
511
|
validate: (value) => {
|
|
517
512
|
if (!value || value.trim() === "") return true;
|
|
518
513
|
return newProjectService.validateProjectName(value);
|
|
519
514
|
}
|
|
520
515
|
});
|
|
521
|
-
|
|
516
|
+
_agiflowai_aicode_utils.print.info("");
|
|
522
517
|
if (!result || result.trim() === "") return ".";
|
|
523
518
|
return result;
|
|
524
519
|
}),
|
|
525
520
|
createProjectDirectory: (0, xstate.fromPromise)(async ({ input: actorInput }) => {
|
|
526
521
|
if (actorInput.projectName === ".") {
|
|
527
522
|
const projectPath = process.cwd();
|
|
528
|
-
|
|
523
|
+
_agiflowai_aicode_utils.print.success(`Using current directory: ${projectPath}`);
|
|
529
524
|
return { projectPath };
|
|
530
525
|
}
|
|
531
526
|
const spinner = (0, ora.default)("Creating project directory...").start();
|
|
@@ -541,22 +536,22 @@ const initActors = {
|
|
|
541
536
|
}),
|
|
542
537
|
promptGitSetup: (0, xstate.fromPromise)(async ({ input: actorInput }) => {
|
|
543
538
|
const newProjectService = new require_utils.NewProjectService(void 0, void 0);
|
|
544
|
-
|
|
545
|
-
const hasExistingRepo = await (0,
|
|
539
|
+
_agiflowai_aicode_utils.print.divider();
|
|
540
|
+
const hasExistingRepo = await (0, _inquirer_prompts.confirm)({
|
|
546
541
|
message: "Do you have an existing Git repository you want to use?",
|
|
547
542
|
default: false
|
|
548
543
|
});
|
|
549
|
-
|
|
544
|
+
_agiflowai_aicode_utils.print.info("");
|
|
550
545
|
if (hasExistingRepo) {
|
|
551
|
-
|
|
552
|
-
const repoUrl = await (0,
|
|
546
|
+
_agiflowai_aicode_utils.print.divider();
|
|
547
|
+
const repoUrl = await (0, _inquirer_prompts.input)({
|
|
553
548
|
message: "Enter Git repository URL (press Enter to skip):",
|
|
554
549
|
validate: (value) => {
|
|
555
550
|
if (!value || value.trim() === "") return true;
|
|
556
551
|
return newProjectService.validateRepositoryUrl(value);
|
|
557
552
|
}
|
|
558
553
|
});
|
|
559
|
-
|
|
554
|
+
_agiflowai_aicode_utils.print.info("");
|
|
560
555
|
if (repoUrl && repoUrl.trim() !== "") {
|
|
561
556
|
const spinner = (0, ora.default)("Cloning repository...").start();
|
|
562
557
|
try {
|
|
@@ -566,14 +561,14 @@ const initActors = {
|
|
|
566
561
|
spinner.fail("Failed to clone repository");
|
|
567
562
|
throw error;
|
|
568
563
|
}
|
|
569
|
-
} else
|
|
564
|
+
} else _agiflowai_aicode_utils.print.info("Skipped cloning repository");
|
|
570
565
|
} else {
|
|
571
|
-
|
|
572
|
-
const initGit = await (0,
|
|
566
|
+
_agiflowai_aicode_utils.print.divider();
|
|
567
|
+
const initGit = await (0, _inquirer_prompts.confirm)({
|
|
573
568
|
message: "Initialize a new Git repository?",
|
|
574
569
|
default: true
|
|
575
570
|
});
|
|
576
|
-
|
|
571
|
+
_agiflowai_aicode_utils.print.info("");
|
|
577
572
|
if (initGit) {
|
|
578
573
|
const spinner = (0, ora.default)("Initializing Git repository...").start();
|
|
579
574
|
try {
|
|
@@ -594,7 +589,7 @@ const initActors = {
|
|
|
594
589
|
description: `\n ${require_mcp.MCP_SERVER_INFO[server].description}`,
|
|
595
590
|
checked: true
|
|
596
591
|
}));
|
|
597
|
-
|
|
592
|
+
_agiflowai_aicode_utils.print.divider();
|
|
598
593
|
const selected = await checkbox({
|
|
599
594
|
message: "Select MCP servers to configure:",
|
|
600
595
|
choices,
|
|
@@ -603,7 +598,7 @@ const initActors = {
|
|
|
603
598
|
return true;
|
|
604
599
|
}
|
|
605
600
|
});
|
|
606
|
-
|
|
601
|
+
_agiflowai_aicode_utils.print.info("");
|
|
607
602
|
return selected;
|
|
608
603
|
}),
|
|
609
604
|
checkTemplatesFolder: (0, xstate.fromPromise)(async ({ input: actorInput }) => {
|
|
@@ -620,16 +615,16 @@ const initActors = {
|
|
|
620
615
|
let finalTemplatesPath = defaultTemplatesPath;
|
|
621
616
|
let skipDownload = false;
|
|
622
617
|
if (templatesExists) {
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
const useDifferentDir = await (0,
|
|
618
|
+
_agiflowai_aicode_utils.print.divider();
|
|
619
|
+
_agiflowai_aicode_utils.print.info(`Templates folder already exists at: ${defaultTemplatesPath}`);
|
|
620
|
+
const useDifferentDir = await (0, _inquirer_prompts.confirm)({
|
|
626
621
|
message: "Would you like to use a different directory for templates?",
|
|
627
622
|
default: false
|
|
628
623
|
});
|
|
629
|
-
|
|
624
|
+
_agiflowai_aicode_utils.print.info("");
|
|
630
625
|
if (useDifferentDir) {
|
|
631
|
-
|
|
632
|
-
const customDir = await (0,
|
|
626
|
+
_agiflowai_aicode_utils.print.divider();
|
|
627
|
+
const customDir = await (0, _inquirer_prompts.input)({
|
|
633
628
|
message: "Enter custom templates directory path (relative to workspace root):",
|
|
634
629
|
default: "templates",
|
|
635
630
|
validate: (value) => {
|
|
@@ -637,24 +632,24 @@ const initActors = {
|
|
|
637
632
|
return true;
|
|
638
633
|
}
|
|
639
634
|
});
|
|
640
|
-
|
|
635
|
+
_agiflowai_aicode_utils.print.info("");
|
|
641
636
|
finalTemplatesPath = node_path.default.join(actorInput.workspaceRoot, customDir.trim());
|
|
642
637
|
try {
|
|
643
638
|
await fs.mkdir(finalTemplatesPath, { recursive: true });
|
|
644
|
-
|
|
639
|
+
_agiflowai_aicode_utils.print.success(`Created templates directory at: ${finalTemplatesPath}`);
|
|
645
640
|
} catch (error) {
|
|
646
641
|
throw new Error(`Failed to create templates directory at ${finalTemplatesPath}: ${error.message}`);
|
|
647
642
|
}
|
|
648
643
|
} else {
|
|
649
644
|
skipDownload = true;
|
|
650
|
-
|
|
645
|
+
_agiflowai_aicode_utils.print.info("Using existing templates folder");
|
|
651
646
|
}
|
|
652
647
|
}
|
|
653
648
|
let existingTemplates;
|
|
654
649
|
if (skipDownload) try {
|
|
655
650
|
existingTemplates = (await new require_utils.TemplateSelectionService(finalTemplatesPath).listTemplates()).map((t) => t.name);
|
|
656
651
|
} catch (_error) {
|
|
657
|
-
|
|
652
|
+
_agiflowai_aicode_utils.print.warning("Could not read existing templates, will proceed anyway");
|
|
658
653
|
}
|
|
659
654
|
return {
|
|
660
655
|
templatesPath: finalTemplatesPath,
|
|
@@ -673,32 +668,32 @@ const initActors = {
|
|
|
673
668
|
return tmpPath;
|
|
674
669
|
} catch (_error) {
|
|
675
670
|
spinner.warn("Failed to download templates - skipping template setup");
|
|
676
|
-
|
|
671
|
+
_agiflowai_aicode_utils.print.info("You can run \"aicode-toolkit init\" again later to set up templates");
|
|
677
672
|
return null;
|
|
678
673
|
}
|
|
679
674
|
}),
|
|
680
|
-
listTemplates: (0, xstate.fromPromise)(async ({ input
|
|
681
|
-
const templates = await new require_utils.TemplateSelectionService(input
|
|
682
|
-
|
|
683
|
-
for (const template of templates)
|
|
675
|
+
listTemplates: (0, xstate.fromPromise)(async ({ input }) => {
|
|
676
|
+
const templates = await new require_utils.TemplateSelectionService(input.tmpTemplatesPath).listTemplates();
|
|
677
|
+
_agiflowai_aicode_utils.print.header("\nAvailable templates:");
|
|
678
|
+
for (const template of templates) _agiflowai_aicode_utils.print.item(`${template.name}${template.description ? ` - ${template.description}` : ""}`);
|
|
684
679
|
return templates;
|
|
685
680
|
}),
|
|
686
681
|
promptTemplateSelection: (0, xstate.fromPromise)(async ({ input: actorInput }) => {
|
|
687
682
|
const templates = await new require_utils.TemplateSelectionService(actorInput.tmpTemplatesPath).listTemplates();
|
|
688
683
|
if (templates.length === 0) throw new Error("No templates available");
|
|
689
|
-
if (actorInput.projectType ===
|
|
690
|
-
const choices
|
|
684
|
+
if (actorInput.projectType === _agiflowai_aicode_utils.ProjectType.MONOLITH) {
|
|
685
|
+
const choices = templates.map((t) => ({
|
|
691
686
|
name: t.name,
|
|
692
687
|
value: t.name,
|
|
693
688
|
description: t.description ? `\n ${t.description}` : void 0
|
|
694
689
|
}));
|
|
695
|
-
|
|
696
|
-
const selected
|
|
690
|
+
_agiflowai_aicode_utils.print.divider();
|
|
691
|
+
const selected = await (0, _inquirer_prompts.select)({
|
|
697
692
|
message: "Select template (monolith allows only one):",
|
|
698
|
-
choices
|
|
693
|
+
choices
|
|
699
694
|
});
|
|
700
|
-
|
|
701
|
-
return [selected
|
|
695
|
+
_agiflowai_aicode_utils.print.info("");
|
|
696
|
+
return [selected];
|
|
702
697
|
}
|
|
703
698
|
const checkbox = await import("@inquirer/prompts").then((m) => m.checkbox);
|
|
704
699
|
const choices = templates.map((t) => ({
|
|
@@ -707,12 +702,12 @@ const initActors = {
|
|
|
707
702
|
description: t.description ? `\n ${t.description}` : void 0,
|
|
708
703
|
checked: true
|
|
709
704
|
}));
|
|
710
|
-
|
|
705
|
+
_agiflowai_aicode_utils.print.divider();
|
|
711
706
|
const selected = await checkbox({
|
|
712
707
|
message: "Select templates (use space to select, enter to confirm):",
|
|
713
708
|
choices
|
|
714
709
|
});
|
|
715
|
-
|
|
710
|
+
_agiflowai_aicode_utils.print.info("");
|
|
716
711
|
if (selected.length === 0) throw new Error("Please select at least one template");
|
|
717
712
|
return selected;
|
|
718
713
|
}),
|
|
@@ -728,7 +723,7 @@ const initActors = {
|
|
|
728
723
|
}
|
|
729
724
|
}),
|
|
730
725
|
createConfig: (0, xstate.fromPromise)(async ({ input: actorInput }) => {
|
|
731
|
-
if (actorInput.projectType ===
|
|
726
|
+
if (actorInput.projectType === _agiflowai_aicode_utils.ProjectType.MONOLITH) {
|
|
732
727
|
const { relativeTemplatesPath, sourceTemplate } = resolveGeneratedSettingsValues({
|
|
733
728
|
workspaceRoot: actorInput.workspaceRoot,
|
|
734
729
|
templatesPath: actorInput.templatesPath,
|
|
@@ -741,30 +736,30 @@ const initActors = {
|
|
|
741
736
|
});
|
|
742
737
|
const toolkitDir = node_path.default.join(actorInput.workspaceRoot, ".toolkit");
|
|
743
738
|
const settingsPath = node_path.default.join(toolkitDir, "settings.yaml");
|
|
744
|
-
|
|
739
|
+
_agiflowai_aicode_utils.print.info("\nCreating .toolkit/settings.yaml...");
|
|
745
740
|
await (0, node_fs_promises.mkdir)(toolkitDir, { recursive: true });
|
|
746
741
|
await (0, node_fs_promises.writeFile)(settingsPath, content, {
|
|
747
742
|
encoding: "utf-8",
|
|
748
743
|
flag: "w"
|
|
749
744
|
});
|
|
750
|
-
|
|
745
|
+
_agiflowai_aicode_utils.print.success(".toolkit/settings.yaml created");
|
|
751
746
|
}
|
|
752
747
|
}),
|
|
753
748
|
detectCodingAgent: (0, xstate.fromPromise)(async ({ input: actorInput }) => {
|
|
754
|
-
|
|
749
|
+
_agiflowai_aicode_utils.print.info("\nDetecting coding agent...");
|
|
755
750
|
const detectedAgent = await require_utils.CodingAgentService.detectCodingAgent(actorInput.workspaceRoot);
|
|
756
|
-
if (detectedAgent)
|
|
757
|
-
else
|
|
751
|
+
if (detectedAgent) _agiflowai_aicode_utils.print.success(`Detected ${detectedAgent} in workspace`);
|
|
752
|
+
else _agiflowai_aicode_utils.print.info("No coding agent detected automatically");
|
|
758
753
|
return detectedAgent;
|
|
759
754
|
}),
|
|
760
755
|
promptCodingAgent: (0, xstate.fromPromise)(async ({ input: actorInput }) => {
|
|
761
756
|
if (actorInput.detectedAgent) {
|
|
762
|
-
|
|
757
|
+
_agiflowai_aicode_utils.print.info(`Using detected coding agent: ${actorInput.detectedAgent}`);
|
|
763
758
|
return actorInput.detectedAgent;
|
|
764
759
|
}
|
|
765
760
|
const agents = require_utils.CodingAgentService.getAvailableAgents();
|
|
766
|
-
|
|
767
|
-
const selected = await (0,
|
|
761
|
+
_agiflowai_aicode_utils.print.divider();
|
|
762
|
+
const selected = await (0, _inquirer_prompts.select)({
|
|
768
763
|
message: "Select coding agent for MCP configuration:",
|
|
769
764
|
choices: agents.map((agent) => ({
|
|
770
765
|
name: agent.name,
|
|
@@ -772,7 +767,7 @@ const initActors = {
|
|
|
772
767
|
description: `\n ${agent.description}`
|
|
773
768
|
}))
|
|
774
769
|
});
|
|
775
|
-
|
|
770
|
+
_agiflowai_aicode_utils.print.info("");
|
|
776
771
|
return selected;
|
|
777
772
|
}),
|
|
778
773
|
configureMCP: (0, xstate.fromPromise)(async ({ input: actorInput }) => {
|
|
@@ -785,54 +780,54 @@ const initActors = {
|
|
|
785
780
|
throw error;
|
|
786
781
|
}
|
|
787
782
|
}),
|
|
788
|
-
cleanup: (0, xstate.fromPromise)(async ({ input
|
|
789
|
-
if (input
|
|
783
|
+
cleanup: (0, xstate.fromPromise)(async ({ input }) => {
|
|
784
|
+
if (input.tmpTemplatesPath) {
|
|
790
785
|
const spinner = (0, ora.default)("Cleaning up temporary files...").start();
|
|
791
786
|
try {
|
|
792
|
-
await new require_utils.TemplateSelectionService(input
|
|
787
|
+
await new require_utils.TemplateSelectionService(input.tmpTemplatesPath).cleanup();
|
|
793
788
|
spinner.succeed("Cleaned up temporary files");
|
|
794
789
|
} catch (_error) {
|
|
795
790
|
spinner.warn("Could not clean up all temporary files");
|
|
796
791
|
}
|
|
797
792
|
}
|
|
798
793
|
}),
|
|
799
|
-
detectSpecTool: (0, xstate.fromPromise)(async ({ input
|
|
800
|
-
|
|
801
|
-
const detectedTool = await new require_utils.SpecToolService(input
|
|
802
|
-
if (detectedTool)
|
|
803
|
-
else
|
|
794
|
+
detectSpecTool: (0, xstate.fromPromise)(async ({ input }) => {
|
|
795
|
+
_agiflowai_aicode_utils.print.info("\nDetecting spec tools...");
|
|
796
|
+
const detectedTool = await new require_utils.SpecToolService(input.workspaceRoot).detectSpecTool();
|
|
797
|
+
if (detectedTool) _agiflowai_aicode_utils.print.success(`Detected ${require_utils.SPEC_TOOL_INFO[detectedTool].name} in workspace`);
|
|
798
|
+
else _agiflowai_aicode_utils.print.info("No spec tool detected");
|
|
804
799
|
return detectedTool;
|
|
805
800
|
}),
|
|
806
801
|
promptSpecDrivenApproach: (0, xstate.fromPromise)(async ({ input: actorInput }) => {
|
|
807
802
|
if (actorInput.detectedSpecTool) {
|
|
808
|
-
|
|
809
|
-
const result
|
|
803
|
+
_agiflowai_aicode_utils.print.divider();
|
|
804
|
+
const result = await (0, _inquirer_prompts.confirm)({
|
|
810
805
|
message: `${require_utils.SPEC_TOOL_INFO[actorInput.detectedSpecTool].name} is installed. Would you like to update the agent instructions for spec-driven development?`,
|
|
811
806
|
default: true
|
|
812
807
|
});
|
|
813
|
-
|
|
814
|
-
return result
|
|
808
|
+
_agiflowai_aicode_utils.print.info("");
|
|
809
|
+
return result;
|
|
815
810
|
}
|
|
816
|
-
|
|
817
|
-
const result = await (0,
|
|
811
|
+
_agiflowai_aicode_utils.print.divider();
|
|
812
|
+
const result = await (0, _inquirer_prompts.confirm)({
|
|
818
813
|
message: "Would you like to install OpenSpec for spec-driven development? This helps AI assistants agree on what to build before writing code.",
|
|
819
814
|
default: false
|
|
820
815
|
});
|
|
821
|
-
|
|
816
|
+
_agiflowai_aicode_utils.print.info("");
|
|
822
817
|
return result;
|
|
823
818
|
}),
|
|
824
|
-
setupSpec: (0, xstate.fromPromise)(async ({ input
|
|
825
|
-
const codingAgentService = new require_utils.CodingAgentService(input
|
|
826
|
-
const specToolService = new require_utils.SpecToolService(input
|
|
827
|
-
if (input
|
|
819
|
+
setupSpec: (0, xstate.fromPromise)(async ({ input }) => {
|
|
820
|
+
const codingAgentService = new require_utils.CodingAgentService(input.workspaceRoot);
|
|
821
|
+
const specToolService = new require_utils.SpecToolService(input.workspaceRoot, require_utils.SpecTool.OPENSPEC, codingAgentService);
|
|
822
|
+
if (input.isAlreadyInstalled) {
|
|
828
823
|
const spinner = (0, ora.default)("Updating OpenSpec agent instructions...").start();
|
|
829
824
|
try {
|
|
830
825
|
const enabledMcps = {
|
|
831
|
-
scaffoldMcp: input
|
|
832
|
-
architectMcp: input
|
|
833
|
-
projectType: input
|
|
826
|
+
scaffoldMcp: input.selectedMcpServers?.includes(require_mcp.MCPServer.SCAFFOLD) ?? false,
|
|
827
|
+
architectMcp: input.selectedMcpServers?.includes(require_mcp.MCPServer.ARCHITECT) ?? false,
|
|
828
|
+
projectType: input.projectType
|
|
834
829
|
};
|
|
835
|
-
await specToolService.updateInstructions(enabledMcps, input
|
|
830
|
+
await specToolService.updateInstructions(enabledMcps, input.codingAgent);
|
|
836
831
|
spinner.succeed("OpenSpec agent instructions updated");
|
|
837
832
|
} catch (error) {
|
|
838
833
|
spinner.fail("Failed to update OpenSpec instructions");
|
|
@@ -844,33 +839,33 @@ const initActors = {
|
|
|
844
839
|
spinner.stop();
|
|
845
840
|
try {
|
|
846
841
|
await specToolService.initializeSpec();
|
|
847
|
-
|
|
842
|
+
_agiflowai_aicode_utils.print.success("OpenSpec initialized successfully");
|
|
848
843
|
} catch (error) {
|
|
849
|
-
|
|
844
|
+
_agiflowai_aicode_utils.print.error("Failed to initialize OpenSpec");
|
|
850
845
|
throw error;
|
|
851
846
|
}
|
|
852
847
|
}
|
|
853
848
|
}),
|
|
854
849
|
promptSpecInstructions: (0, xstate.fromPromise)(async () => {
|
|
855
|
-
|
|
856
|
-
const result = await (0,
|
|
850
|
+
_agiflowai_aicode_utils.print.divider();
|
|
851
|
+
const result = await (0, _inquirer_prompts.confirm)({
|
|
857
852
|
message: "Would you like to update the agent instructions with OpenSpec workflow guidance?",
|
|
858
853
|
default: true
|
|
859
854
|
});
|
|
860
|
-
|
|
855
|
+
_agiflowai_aicode_utils.print.info("");
|
|
861
856
|
return result;
|
|
862
857
|
}),
|
|
863
|
-
updateSpecInstructions: (0, xstate.fromPromise)(async ({ input
|
|
858
|
+
updateSpecInstructions: (0, xstate.fromPromise)(async ({ input }) => {
|
|
864
859
|
const spinner = (0, ora.default)("Updating OpenSpec agent instructions...").start();
|
|
865
860
|
try {
|
|
866
|
-
const codingAgentService = new require_utils.CodingAgentService(input
|
|
867
|
-
const specToolService = new require_utils.SpecToolService(input
|
|
861
|
+
const codingAgentService = new require_utils.CodingAgentService(input.workspaceRoot);
|
|
862
|
+
const specToolService = new require_utils.SpecToolService(input.workspaceRoot, require_utils.SpecTool.OPENSPEC, codingAgentService);
|
|
868
863
|
const enabledMcps = {
|
|
869
|
-
scaffoldMcp: input
|
|
870
|
-
architectMcp: input
|
|
871
|
-
projectType: input
|
|
864
|
+
scaffoldMcp: input.selectedMcpServers?.includes(require_mcp.MCPServer.SCAFFOLD) ?? false,
|
|
865
|
+
architectMcp: input.selectedMcpServers?.includes(require_mcp.MCPServer.ARCHITECT) ?? false,
|
|
866
|
+
projectType: input.projectType
|
|
872
867
|
};
|
|
873
|
-
await specToolService.updateInstructions(enabledMcps, input
|
|
868
|
+
await specToolService.updateInstructions(enabledMcps, input.codingAgent);
|
|
874
869
|
spinner.succeed("OpenSpec agent instructions updated");
|
|
875
870
|
} catch (error) {
|
|
876
871
|
spinner.fail("Failed to update OpenSpec instructions");
|
|
@@ -878,11 +873,11 @@ const initActors = {
|
|
|
878
873
|
}
|
|
879
874
|
})
|
|
880
875
|
};
|
|
881
|
-
function resolveGeneratedSettingsValues(input
|
|
882
|
-
const resolvedTemplatesPath = input
|
|
876
|
+
function resolveGeneratedSettingsValues(input) {
|
|
877
|
+
const resolvedTemplatesPath = input.templatesPath ?? node_path.default.join(input.workspaceRoot, _agiflowai_aicode_utils.TemplatesManagerService.getTemplatesFolderName());
|
|
883
878
|
return {
|
|
884
|
-
relativeTemplatesPath: node_path.default.relative(input
|
|
885
|
-
sourceTemplate: input
|
|
879
|
+
relativeTemplatesPath: node_path.default.relative(input.workspaceRoot, resolvedTemplatesPath) || "templates",
|
|
880
|
+
sourceTemplate: input.selectedTemplates?.[0]
|
|
886
881
|
};
|
|
887
882
|
}
|
|
888
883
|
/**
|
|
@@ -909,19 +904,18 @@ const initCommand = new commander.Command("init").description("Initialize projec
|
|
|
909
904
|
});
|
|
910
905
|
});
|
|
911
906
|
const { templatesPath, projectType } = actor.getSnapshot().context;
|
|
912
|
-
|
|
913
|
-
if (templatesPath)
|
|
914
|
-
if (projectType)
|
|
907
|
+
_agiflowai_aicode_utils.print.header("\nSetup Complete!");
|
|
908
|
+
if (templatesPath) _agiflowai_aicode_utils.print.info(`Templates location: ${templatesPath}`);
|
|
909
|
+
if (projectType) _agiflowai_aicode_utils.print.info(`Project type: ${projectType}`);
|
|
915
910
|
const gradient = await import("gradient-string");
|
|
916
|
-
|
|
911
|
+
_agiflowai_aicode_utils.print.newline();
|
|
917
912
|
console.log(gradient.default.pastel.multiline("🎉 Congratulations! Your project is ready to go!"));
|
|
918
|
-
|
|
913
|
+
_agiflowai_aicode_utils.print.newline();
|
|
919
914
|
} catch (error) {
|
|
920
|
-
|
|
915
|
+
_agiflowai_aicode_utils.print.error(`\nError: ${error.message}`);
|
|
921
916
|
process.exit(1);
|
|
922
917
|
}
|
|
923
918
|
});
|
|
924
|
-
|
|
925
919
|
//#endregion
|
|
926
920
|
//#region src/commands/sync.ts
|
|
927
921
|
/**
|
|
@@ -967,10 +961,10 @@ function buildHookCommand(server, hookType, extraFlags) {
|
|
|
967
961
|
const serverArgs = server.args ?? [];
|
|
968
962
|
const scriptIdx = serverArgs.findIndex((arg) => /\.(ts|js|mjs|cjs)$/.test(arg));
|
|
969
963
|
if (scriptIdx >= 0) {
|
|
970
|
-
const prefixArgs
|
|
964
|
+
const prefixArgs = serverArgs.slice(0, scriptIdx + 1);
|
|
971
965
|
return [
|
|
972
966
|
server.command,
|
|
973
|
-
...prefixArgs
|
|
967
|
+
...prefixArgs,
|
|
974
968
|
"hook",
|
|
975
969
|
"--type",
|
|
976
970
|
hookType,
|
|
@@ -1077,13 +1071,14 @@ async function writeClaudeSettings(config, workspaceRoot) {
|
|
|
1077
1071
|
hasAny = true;
|
|
1078
1072
|
}
|
|
1079
1073
|
if (!hasAny) {
|
|
1080
|
-
|
|
1081
|
-
return;
|
|
1074
|
+
_agiflowai_aicode_utils.print.warning("No scaffold-mcp/architect-mcp hook.claude-code config found — skipping .claude/settings.json");
|
|
1075
|
+
return false;
|
|
1082
1076
|
}
|
|
1083
1077
|
const settings = { hooks: hooksOutput };
|
|
1084
1078
|
const claudeDir = node_path.default.join(workspaceRoot, CLAUDE_SETTINGS_DIR);
|
|
1085
1079
|
await (0, node_fs_promises.mkdir)(claudeDir, { recursive: true });
|
|
1086
1080
|
await (0, node_fs_promises.writeFile)(node_path.default.join(claudeDir, CLAUDE_SETTINGS_FILE), JSON.stringify(settings, null, 2), "utf-8");
|
|
1081
|
+
return true;
|
|
1087
1082
|
} catch (err) {
|
|
1088
1083
|
const message = err instanceof Error ? err.message : String(err);
|
|
1089
1084
|
throw new Error(`Failed to write ${CLAUDE_SETTINGS_DIR}/${CLAUDE_SETTINGS_FILE}: ${message}`);
|
|
@@ -1093,10 +1088,11 @@ async function writeMcpConfig(config, workspaceRoot) {
|
|
|
1093
1088
|
try {
|
|
1094
1089
|
const mcpConfig = buildMcpConfigYaml(config);
|
|
1095
1090
|
if (!mcpConfig) {
|
|
1096
|
-
|
|
1097
|
-
return;
|
|
1091
|
+
_agiflowai_aicode_utils.print.warning("No mcp-config.servers or mcp-config.skills config found — skipping mcp-config.yaml");
|
|
1092
|
+
return false;
|
|
1098
1093
|
}
|
|
1099
1094
|
await (0, node_fs_promises.writeFile)(node_path.default.join(workspaceRoot, MCP_CONFIG_FILE), js_yaml.default.dump(mcpConfig, { indent: 2 }), "utf-8");
|
|
1095
|
+
return true;
|
|
1100
1096
|
} catch (err) {
|
|
1101
1097
|
const message = err instanceof Error ? err.message : String(err);
|
|
1102
1098
|
throw new Error(`Failed to write ${MCP_CONFIG_FILE}: ${message}`);
|
|
@@ -1107,25 +1103,22 @@ async function writeMcpConfig(config, workspaceRoot) {
|
|
|
1107
1103
|
*/
|
|
1108
1104
|
const syncCommand = new commander.Command("sync").description("Generate .claude/settings.json from .toolkit/settings.yaml and mcp-config.yaml").option("--hooks", "Write .claude/settings.json only").option("--mcp", "Write mcp-config.yaml only").action(async (options) => {
|
|
1109
1105
|
try {
|
|
1110
|
-
const [workspaceRoot, config] = await Promise.all([
|
|
1106
|
+
const [workspaceRoot, config] = await Promise.all([_agiflowai_aicode_utils.TemplatesManagerService.getWorkspaceRoot(), _agiflowai_aicode_utils.TemplatesManagerService.readToolkitConfig()]);
|
|
1111
1107
|
if (!config) throw new Error("No toolkit settings config found (.toolkit/settings.yaml or legacy toolkit.yaml). Run `aicode init` first.");
|
|
1112
1108
|
const shouldWriteHooks = options.hooks || !options.hooks && !options.mcp;
|
|
1113
1109
|
const shouldWriteMcp = options.mcp || !options.hooks && !options.mcp;
|
|
1114
1110
|
if (shouldWriteHooks) if (hasHookConfig(config)) {
|
|
1115
|
-
await writeClaudeSettings(config, workspaceRoot);
|
|
1116
|
-
|
|
1117
|
-
} else __agiflowai_aicode_utils.print.warning("No hook.claude-code config found in toolkit settings — skipping");
|
|
1111
|
+
if (await writeClaudeSettings(config, workspaceRoot)) _agiflowai_aicode_utils.print.success("Written .claude/settings.json");
|
|
1112
|
+
} else _agiflowai_aicode_utils.print.warning("No hook.claude-code config found in toolkit settings — skipping");
|
|
1118
1113
|
if (shouldWriteMcp) if (buildMcpConfigYaml(config)) {
|
|
1119
|
-
await writeMcpConfig(config, workspaceRoot);
|
|
1120
|
-
|
|
1121
|
-
} else __agiflowai_aicode_utils.print.warning("No mcp-config.servers or mcp-config.skills config found — skipping mcp-config.yaml");
|
|
1114
|
+
if (await writeMcpConfig(config, workspaceRoot)) _agiflowai_aicode_utils.print.success("Written mcp-config.yaml");
|
|
1115
|
+
} else _agiflowai_aicode_utils.print.warning("No mcp-config.servers or mcp-config.skills config found — skipping mcp-config.yaml");
|
|
1122
1116
|
} catch (error) {
|
|
1123
1117
|
const message = error instanceof Error ? error.message : String(error);
|
|
1124
|
-
|
|
1118
|
+
_agiflowai_aicode_utils.print.error(`sync failed: ${message}`);
|
|
1125
1119
|
process.exit(1);
|
|
1126
1120
|
}
|
|
1127
1121
|
});
|
|
1128
|
-
|
|
1129
1122
|
//#endregion
|
|
1130
1123
|
//#region src/cli.ts
|
|
1131
1124
|
/**
|
|
@@ -1146,5 +1139,4 @@ async function main() {
|
|
|
1146
1139
|
}
|
|
1147
1140
|
}
|
|
1148
1141
|
main();
|
|
1149
|
-
|
|
1150
|
-
//#endregion
|
|
1142
|
+
//#endregion
|