@agiflowai/aicode-toolkit 1.0.26 → 1.2.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 +181 -184
- package/dist/cli.mjs +59 -62
- package/dist/index.cjs +3 -4
- package/dist/index.d.cts +0 -2
- package/dist/index.d.mts +0 -2
- 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-BdZqGo-L.cjs} +227 -209
- package/dist/{utils-BTSpNlWu.mjs → utils-re_0nbT6.mjs} +40 -23
- package/package.json +22 -22
- 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-BdZqGo-L.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.1.0";
|
|
20
18
|
//#endregion
|
|
21
19
|
//#region src/commands/add.ts
|
|
22
20
|
/**
|
|
@@ -24,9 +22,9 @@ var version = "1.0.25";
|
|
|
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,9 +430,14 @@ 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
|
|
435
|
+
function resolveOra(value, depth = 0) {
|
|
436
|
+
if (typeof value === "function") return value;
|
|
437
|
+
if (depth < 3 && value && (typeof value === "object" || typeof value === "function") && "default" in value) return resolveOra(value.default, depth + 1);
|
|
438
|
+
throw new Error("Unable to resolve ora instance");
|
|
439
|
+
}
|
|
440
|
+
const ora$1 = resolveOra(ora);
|
|
440
441
|
const DEFAULT_TEMPLATE_REPO = {
|
|
441
442
|
owner: "AgiFlow",
|
|
442
443
|
repo: "aicode-toolkit",
|
|
@@ -451,10 +452,10 @@ const initActors = {
|
|
|
451
452
|
require_utils.displayBanner();
|
|
452
453
|
}),
|
|
453
454
|
checkWorkspaceExists: (0, xstate.fromPromise)(async () => {
|
|
454
|
-
const workspaceRoot = await (0,
|
|
455
|
+
const workspaceRoot = await (0, _agiflowai_aicode_utils.findWorkspaceRoot)();
|
|
455
456
|
if (workspaceRoot) {
|
|
456
|
-
|
|
457
|
-
|
|
457
|
+
_agiflowai_aicode_utils.print.divider();
|
|
458
|
+
_agiflowai_aicode_utils.print.info(`Found workspace at: ${workspaceRoot}`);
|
|
458
459
|
return {
|
|
459
460
|
exists: true,
|
|
460
461
|
workspaceRoot
|
|
@@ -462,42 +463,42 @@ const initActors = {
|
|
|
462
463
|
}
|
|
463
464
|
return { exists: false };
|
|
464
465
|
}),
|
|
465
|
-
detectProjectType: (0, xstate.fromPromise)(async ({ input
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
const result = await (0,
|
|
469
|
-
if (result.projectType)
|
|
466
|
+
detectProjectType: (0, xstate.fromPromise)(async ({ input }) => {
|
|
467
|
+
_agiflowai_aicode_utils.print.divider();
|
|
468
|
+
_agiflowai_aicode_utils.print.info("Detecting project type...");
|
|
469
|
+
const result = await (0, _agiflowai_aicode_utils.detectProjectType)(input.workspaceRoot);
|
|
470
|
+
if (result.projectType) _agiflowai_aicode_utils.print.success(`Detected ${result.projectType} project`);
|
|
470
471
|
return result;
|
|
471
472
|
}),
|
|
472
473
|
promptProjectType: (0, xstate.fromPromise)(async ({ input: actorInput }) => {
|
|
473
474
|
if (actorInput.providedProjectType) {
|
|
474
475
|
const projectType = actorInput.providedProjectType;
|
|
475
|
-
|
|
476
|
+
_agiflowai_aicode_utils.print.info(`Project type: ${projectType}`);
|
|
476
477
|
return projectType;
|
|
477
478
|
}
|
|
478
479
|
if (actorInput.detectedProjectType) {
|
|
479
|
-
|
|
480
|
+
_agiflowai_aicode_utils.print.info(`Using detected project type: ${actorInput.detectedProjectType}`);
|
|
480
481
|
return actorInput.detectedProjectType;
|
|
481
482
|
}
|
|
482
483
|
if (actorInput.detectionIndicators && actorInput.detectionIndicators.length > 0) {
|
|
483
|
-
|
|
484
|
-
for (const indicator of actorInput.detectionIndicators)
|
|
485
|
-
|
|
484
|
+
_agiflowai_aicode_utils.print.info("\nDetection results:");
|
|
485
|
+
for (const indicator of actorInput.detectionIndicators) _agiflowai_aicode_utils.print.indent(`• ${indicator}`);
|
|
486
|
+
_agiflowai_aicode_utils.print.newline();
|
|
486
487
|
}
|
|
487
|
-
|
|
488
|
-
const result = await (0,
|
|
488
|
+
_agiflowai_aicode_utils.print.divider();
|
|
489
|
+
const result = await (0, _inquirer_prompts.select)({
|
|
489
490
|
message: "Select project type:",
|
|
490
491
|
choices: [{
|
|
491
492
|
name: "Monolith – Single application structure",
|
|
492
|
-
value:
|
|
493
|
+
value: _agiflowai_aicode_utils.ProjectType.MONOLITH,
|
|
493
494
|
description: "\n Traditional single-application project structure"
|
|
494
495
|
}, {
|
|
495
496
|
name: "Monorepo – Multiple packages/apps in one repository",
|
|
496
|
-
value:
|
|
497
|
+
value: _agiflowai_aicode_utils.ProjectType.MONOREPO,
|
|
497
498
|
description: "\n Multiple packages managed together (uses workspaces)"
|
|
498
499
|
}]
|
|
499
500
|
});
|
|
500
|
-
|
|
501
|
+
_agiflowai_aicode_utils.print.info("");
|
|
501
502
|
return result;
|
|
502
503
|
}),
|
|
503
504
|
promptProjectName: (0, xstate.fromPromise)(async ({ input: actorInput }) => {
|
|
@@ -507,28 +508,28 @@ const initActors = {
|
|
|
507
508
|
const trimmedName = providedName.trim();
|
|
508
509
|
const validationResult = newProjectService.validateProjectName(trimmedName);
|
|
509
510
|
if (validationResult !== true) throw new Error(validationResult);
|
|
510
|
-
|
|
511
|
+
_agiflowai_aicode_utils.print.info(`Project name: ${trimmedName}`);
|
|
511
512
|
return trimmedName;
|
|
512
513
|
}
|
|
513
|
-
|
|
514
|
-
const result = await (0,
|
|
514
|
+
_agiflowai_aicode_utils.print.divider();
|
|
515
|
+
const result = await (0, _inquirer_prompts.input)({
|
|
515
516
|
message: "Enter your project name (press Enter to use current directory):",
|
|
516
517
|
validate: (value) => {
|
|
517
518
|
if (!value || value.trim() === "") return true;
|
|
518
519
|
return newProjectService.validateProjectName(value);
|
|
519
520
|
}
|
|
520
521
|
});
|
|
521
|
-
|
|
522
|
+
_agiflowai_aicode_utils.print.info("");
|
|
522
523
|
if (!result || result.trim() === "") return ".";
|
|
523
524
|
return result;
|
|
524
525
|
}),
|
|
525
526
|
createProjectDirectory: (0, xstate.fromPromise)(async ({ input: actorInput }) => {
|
|
526
527
|
if (actorInput.projectName === ".") {
|
|
527
528
|
const projectPath = process.cwd();
|
|
528
|
-
|
|
529
|
+
_agiflowai_aicode_utils.print.success(`Using current directory: ${projectPath}`);
|
|
529
530
|
return { projectPath };
|
|
530
531
|
}
|
|
531
|
-
const spinner =
|
|
532
|
+
const spinner = ora$1("Creating project directory...").start();
|
|
532
533
|
try {
|
|
533
534
|
const projectPath = node_path.default.join(process.cwd(), actorInput.projectName.trim());
|
|
534
535
|
await new require_utils.NewProjectService(void 0, void 0).createProjectDirectory(projectPath, actorInput.projectName);
|
|
@@ -541,24 +542,24 @@ const initActors = {
|
|
|
541
542
|
}),
|
|
542
543
|
promptGitSetup: (0, xstate.fromPromise)(async ({ input: actorInput }) => {
|
|
543
544
|
const newProjectService = new require_utils.NewProjectService(void 0, void 0);
|
|
544
|
-
|
|
545
|
-
const hasExistingRepo = await (0,
|
|
545
|
+
_agiflowai_aicode_utils.print.divider();
|
|
546
|
+
const hasExistingRepo = await (0, _inquirer_prompts.confirm)({
|
|
546
547
|
message: "Do you have an existing Git repository you want to use?",
|
|
547
548
|
default: false
|
|
548
549
|
});
|
|
549
|
-
|
|
550
|
+
_agiflowai_aicode_utils.print.info("");
|
|
550
551
|
if (hasExistingRepo) {
|
|
551
|
-
|
|
552
|
-
const repoUrl = await (0,
|
|
552
|
+
_agiflowai_aicode_utils.print.divider();
|
|
553
|
+
const repoUrl = await (0, _inquirer_prompts.input)({
|
|
553
554
|
message: "Enter Git repository URL (press Enter to skip):",
|
|
554
555
|
validate: (value) => {
|
|
555
556
|
if (!value || value.trim() === "") return true;
|
|
556
557
|
return newProjectService.validateRepositoryUrl(value);
|
|
557
558
|
}
|
|
558
559
|
});
|
|
559
|
-
|
|
560
|
+
_agiflowai_aicode_utils.print.info("");
|
|
560
561
|
if (repoUrl && repoUrl.trim() !== "") {
|
|
561
|
-
const spinner =
|
|
562
|
+
const spinner = ora$1("Cloning repository...").start();
|
|
562
563
|
try {
|
|
563
564
|
await newProjectService.cloneExistingRepository(repoUrl.trim(), actorInput.projectPath);
|
|
564
565
|
spinner.succeed("Repository cloned successfully");
|
|
@@ -566,16 +567,16 @@ const initActors = {
|
|
|
566
567
|
spinner.fail("Failed to clone repository");
|
|
567
568
|
throw error;
|
|
568
569
|
}
|
|
569
|
-
} else
|
|
570
|
+
} else _agiflowai_aicode_utils.print.info("Skipped cloning repository");
|
|
570
571
|
} else {
|
|
571
|
-
|
|
572
|
-
const initGit = await (0,
|
|
572
|
+
_agiflowai_aicode_utils.print.divider();
|
|
573
|
+
const initGit = await (0, _inquirer_prompts.confirm)({
|
|
573
574
|
message: "Initialize a new Git repository?",
|
|
574
575
|
default: true
|
|
575
576
|
});
|
|
576
|
-
|
|
577
|
+
_agiflowai_aicode_utils.print.info("");
|
|
577
578
|
if (initGit) {
|
|
578
|
-
const spinner =
|
|
579
|
+
const spinner = ora$1("Initializing Git repository...").start();
|
|
579
580
|
try {
|
|
580
581
|
await newProjectService.initializeGitRepository(actorInput.projectPath);
|
|
581
582
|
spinner.succeed("Git repository initialized");
|
|
@@ -594,7 +595,7 @@ const initActors = {
|
|
|
594
595
|
description: `\n ${require_mcp.MCP_SERVER_INFO[server].description}`,
|
|
595
596
|
checked: true
|
|
596
597
|
}));
|
|
597
|
-
|
|
598
|
+
_agiflowai_aicode_utils.print.divider();
|
|
598
599
|
const selected = await checkbox({
|
|
599
600
|
message: "Select MCP servers to configure:",
|
|
600
601
|
choices,
|
|
@@ -603,7 +604,7 @@ const initActors = {
|
|
|
603
604
|
return true;
|
|
604
605
|
}
|
|
605
606
|
});
|
|
606
|
-
|
|
607
|
+
_agiflowai_aicode_utils.print.info("");
|
|
607
608
|
return selected;
|
|
608
609
|
}),
|
|
609
610
|
checkTemplatesFolder: (0, xstate.fromPromise)(async ({ input: actorInput }) => {
|
|
@@ -620,16 +621,16 @@ const initActors = {
|
|
|
620
621
|
let finalTemplatesPath = defaultTemplatesPath;
|
|
621
622
|
let skipDownload = false;
|
|
622
623
|
if (templatesExists) {
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
const useDifferentDir = await (0,
|
|
624
|
+
_agiflowai_aicode_utils.print.divider();
|
|
625
|
+
_agiflowai_aicode_utils.print.info(`Templates folder already exists at: ${defaultTemplatesPath}`);
|
|
626
|
+
const useDifferentDir = await (0, _inquirer_prompts.confirm)({
|
|
626
627
|
message: "Would you like to use a different directory for templates?",
|
|
627
628
|
default: false
|
|
628
629
|
});
|
|
629
|
-
|
|
630
|
+
_agiflowai_aicode_utils.print.info("");
|
|
630
631
|
if (useDifferentDir) {
|
|
631
|
-
|
|
632
|
-
const customDir = await (0,
|
|
632
|
+
_agiflowai_aicode_utils.print.divider();
|
|
633
|
+
const customDir = await (0, _inquirer_prompts.input)({
|
|
633
634
|
message: "Enter custom templates directory path (relative to workspace root):",
|
|
634
635
|
default: "templates",
|
|
635
636
|
validate: (value) => {
|
|
@@ -637,24 +638,24 @@ const initActors = {
|
|
|
637
638
|
return true;
|
|
638
639
|
}
|
|
639
640
|
});
|
|
640
|
-
|
|
641
|
+
_agiflowai_aicode_utils.print.info("");
|
|
641
642
|
finalTemplatesPath = node_path.default.join(actorInput.workspaceRoot, customDir.trim());
|
|
642
643
|
try {
|
|
643
644
|
await fs.mkdir(finalTemplatesPath, { recursive: true });
|
|
644
|
-
|
|
645
|
+
_agiflowai_aicode_utils.print.success(`Created templates directory at: ${finalTemplatesPath}`);
|
|
645
646
|
} catch (error) {
|
|
646
647
|
throw new Error(`Failed to create templates directory at ${finalTemplatesPath}: ${error.message}`);
|
|
647
648
|
}
|
|
648
649
|
} else {
|
|
649
650
|
skipDownload = true;
|
|
650
|
-
|
|
651
|
+
_agiflowai_aicode_utils.print.info("Using existing templates folder");
|
|
651
652
|
}
|
|
652
653
|
}
|
|
653
654
|
let existingTemplates;
|
|
654
655
|
if (skipDownload) try {
|
|
655
656
|
existingTemplates = (await new require_utils.TemplateSelectionService(finalTemplatesPath).listTemplates()).map((t) => t.name);
|
|
656
657
|
} catch (_error) {
|
|
657
|
-
|
|
658
|
+
_agiflowai_aicode_utils.print.warning("Could not read existing templates, will proceed anyway");
|
|
658
659
|
}
|
|
659
660
|
return {
|
|
660
661
|
templatesPath: finalTemplatesPath,
|
|
@@ -666,39 +667,39 @@ const initActors = {
|
|
|
666
667
|
}
|
|
667
668
|
}),
|
|
668
669
|
downloadTemplates: (0, xstate.fromPromise)(async () => {
|
|
669
|
-
const spinner =
|
|
670
|
+
const spinner = ora$1("Downloading templates from AgiFlow/aicode-toolkit...").start();
|
|
670
671
|
try {
|
|
671
672
|
const tmpPath = await new require_utils.TemplateSelectionService().downloadTemplatesToTmp(DEFAULT_TEMPLATE_REPO);
|
|
672
673
|
spinner.succeed("Templates downloaded successfully");
|
|
673
674
|
return tmpPath;
|
|
674
675
|
} catch (_error) {
|
|
675
676
|
spinner.warn("Failed to download templates - skipping template setup");
|
|
676
|
-
|
|
677
|
+
_agiflowai_aicode_utils.print.info("You can run \"aicode-toolkit init\" again later to set up templates");
|
|
677
678
|
return null;
|
|
678
679
|
}
|
|
679
680
|
}),
|
|
680
|
-
listTemplates: (0, xstate.fromPromise)(async ({ input
|
|
681
|
-
const templates = await new require_utils.TemplateSelectionService(input
|
|
682
|
-
|
|
683
|
-
for (const template of templates)
|
|
681
|
+
listTemplates: (0, xstate.fromPromise)(async ({ input }) => {
|
|
682
|
+
const templates = await new require_utils.TemplateSelectionService(input.tmpTemplatesPath).listTemplates();
|
|
683
|
+
_agiflowai_aicode_utils.print.header("\nAvailable templates:");
|
|
684
|
+
for (const template of templates) _agiflowai_aicode_utils.print.item(`${template.name}${template.description ? ` - ${template.description}` : ""}`);
|
|
684
685
|
return templates;
|
|
685
686
|
}),
|
|
686
687
|
promptTemplateSelection: (0, xstate.fromPromise)(async ({ input: actorInput }) => {
|
|
687
688
|
const templates = await new require_utils.TemplateSelectionService(actorInput.tmpTemplatesPath).listTemplates();
|
|
688
689
|
if (templates.length === 0) throw new Error("No templates available");
|
|
689
|
-
if (actorInput.projectType ===
|
|
690
|
-
const choices
|
|
690
|
+
if (actorInput.projectType === _agiflowai_aicode_utils.ProjectType.MONOLITH) {
|
|
691
|
+
const choices = templates.map((t) => ({
|
|
691
692
|
name: t.name,
|
|
692
693
|
value: t.name,
|
|
693
694
|
description: t.description ? `\n ${t.description}` : void 0
|
|
694
695
|
}));
|
|
695
|
-
|
|
696
|
-
const selected
|
|
696
|
+
_agiflowai_aicode_utils.print.divider();
|
|
697
|
+
const selected = await (0, _inquirer_prompts.select)({
|
|
697
698
|
message: "Select template (monolith allows only one):",
|
|
698
|
-
choices
|
|
699
|
+
choices
|
|
699
700
|
});
|
|
700
|
-
|
|
701
|
-
return [selected
|
|
701
|
+
_agiflowai_aicode_utils.print.info("");
|
|
702
|
+
return [selected];
|
|
702
703
|
}
|
|
703
704
|
const checkbox = await import("@inquirer/prompts").then((m) => m.checkbox);
|
|
704
705
|
const choices = templates.map((t) => ({
|
|
@@ -707,17 +708,17 @@ const initActors = {
|
|
|
707
708
|
description: t.description ? `\n ${t.description}` : void 0,
|
|
708
709
|
checked: true
|
|
709
710
|
}));
|
|
710
|
-
|
|
711
|
+
_agiflowai_aicode_utils.print.divider();
|
|
711
712
|
const selected = await checkbox({
|
|
712
713
|
message: "Select templates (use space to select, enter to confirm):",
|
|
713
714
|
choices
|
|
714
715
|
});
|
|
715
|
-
|
|
716
|
+
_agiflowai_aicode_utils.print.info("");
|
|
716
717
|
if (selected.length === 0) throw new Error("Please select at least one template");
|
|
717
718
|
return selected;
|
|
718
719
|
}),
|
|
719
720
|
copyTemplates: (0, xstate.fromPromise)(async ({ input: actorInput }) => {
|
|
720
|
-
const spinner =
|
|
721
|
+
const spinner = ora$1("Copying templates to workspace...").start();
|
|
721
722
|
try {
|
|
722
723
|
await new require_utils.TemplateSelectionService(actorInput.tmpTemplatesPath).copyTemplates(actorInput.selectedTemplates, actorInput.templatesPath, actorInput.projectType, actorInput.selectedMcpServers);
|
|
723
724
|
spinner.succeed(`Templates copied to ${actorInput.templatesPath}`);
|
|
@@ -728,7 +729,7 @@ const initActors = {
|
|
|
728
729
|
}
|
|
729
730
|
}),
|
|
730
731
|
createConfig: (0, xstate.fromPromise)(async ({ input: actorInput }) => {
|
|
731
|
-
if (actorInput.projectType ===
|
|
732
|
+
if (actorInput.projectType === _agiflowai_aicode_utils.ProjectType.MONOLITH) {
|
|
732
733
|
const { relativeTemplatesPath, sourceTemplate } = resolveGeneratedSettingsValues({
|
|
733
734
|
workspaceRoot: actorInput.workspaceRoot,
|
|
734
735
|
templatesPath: actorInput.templatesPath,
|
|
@@ -741,30 +742,30 @@ const initActors = {
|
|
|
741
742
|
});
|
|
742
743
|
const toolkitDir = node_path.default.join(actorInput.workspaceRoot, ".toolkit");
|
|
743
744
|
const settingsPath = node_path.default.join(toolkitDir, "settings.yaml");
|
|
744
|
-
|
|
745
|
+
_agiflowai_aicode_utils.print.info("\nCreating .toolkit/settings.yaml...");
|
|
745
746
|
await (0, node_fs_promises.mkdir)(toolkitDir, { recursive: true });
|
|
746
747
|
await (0, node_fs_promises.writeFile)(settingsPath, content, {
|
|
747
748
|
encoding: "utf-8",
|
|
748
749
|
flag: "w"
|
|
749
750
|
});
|
|
750
|
-
|
|
751
|
+
_agiflowai_aicode_utils.print.success(".toolkit/settings.yaml created");
|
|
751
752
|
}
|
|
752
753
|
}),
|
|
753
754
|
detectCodingAgent: (0, xstate.fromPromise)(async ({ input: actorInput }) => {
|
|
754
|
-
|
|
755
|
+
_agiflowai_aicode_utils.print.info("\nDetecting coding agent...");
|
|
755
756
|
const detectedAgent = await require_utils.CodingAgentService.detectCodingAgent(actorInput.workspaceRoot);
|
|
756
|
-
if (detectedAgent)
|
|
757
|
-
else
|
|
757
|
+
if (detectedAgent) _agiflowai_aicode_utils.print.success(`Detected ${detectedAgent} in workspace`);
|
|
758
|
+
else _agiflowai_aicode_utils.print.info("No coding agent detected automatically");
|
|
758
759
|
return detectedAgent;
|
|
759
760
|
}),
|
|
760
761
|
promptCodingAgent: (0, xstate.fromPromise)(async ({ input: actorInput }) => {
|
|
761
762
|
if (actorInput.detectedAgent) {
|
|
762
|
-
|
|
763
|
+
_agiflowai_aicode_utils.print.info(`Using detected coding agent: ${actorInput.detectedAgent}`);
|
|
763
764
|
return actorInput.detectedAgent;
|
|
764
765
|
}
|
|
765
766
|
const agents = require_utils.CodingAgentService.getAvailableAgents();
|
|
766
|
-
|
|
767
|
-
const selected = await (0,
|
|
767
|
+
_agiflowai_aicode_utils.print.divider();
|
|
768
|
+
const selected = await (0, _inquirer_prompts.select)({
|
|
768
769
|
message: "Select coding agent for MCP configuration:",
|
|
769
770
|
choices: agents.map((agent) => ({
|
|
770
771
|
name: agent.name,
|
|
@@ -772,11 +773,11 @@ const initActors = {
|
|
|
772
773
|
description: `\n ${agent.description}`
|
|
773
774
|
}))
|
|
774
775
|
});
|
|
775
|
-
|
|
776
|
+
_agiflowai_aicode_utils.print.info("");
|
|
776
777
|
return selected;
|
|
777
778
|
}),
|
|
778
779
|
configureMCP: (0, xstate.fromPromise)(async ({ input: actorInput }) => {
|
|
779
|
-
const spinner =
|
|
780
|
+
const spinner = ora$1(`Setting up MCP for ${actorInput.codingAgent}...`).start();
|
|
780
781
|
try {
|
|
781
782
|
await new require_utils.CodingAgentService(actorInput.workspaceRoot).setupMCP(actorInput.codingAgent, actorInput.selectedMcpServers);
|
|
782
783
|
spinner.succeed("MCP configuration completed");
|
|
@@ -785,92 +786,92 @@ const initActors = {
|
|
|
785
786
|
throw error;
|
|
786
787
|
}
|
|
787
788
|
}),
|
|
788
|
-
cleanup: (0, xstate.fromPromise)(async ({ input
|
|
789
|
-
if (input
|
|
790
|
-
const spinner =
|
|
789
|
+
cleanup: (0, xstate.fromPromise)(async ({ input }) => {
|
|
790
|
+
if (input.tmpTemplatesPath) {
|
|
791
|
+
const spinner = ora$1("Cleaning up temporary files...").start();
|
|
791
792
|
try {
|
|
792
|
-
await new require_utils.TemplateSelectionService(input
|
|
793
|
+
await new require_utils.TemplateSelectionService(input.tmpTemplatesPath).cleanup();
|
|
793
794
|
spinner.succeed("Cleaned up temporary files");
|
|
794
795
|
} catch (_error) {
|
|
795
796
|
spinner.warn("Could not clean up all temporary files");
|
|
796
797
|
}
|
|
797
798
|
}
|
|
798
799
|
}),
|
|
799
|
-
detectSpecTool: (0, xstate.fromPromise)(async ({ input
|
|
800
|
-
|
|
801
|
-
const detectedTool = await new require_utils.SpecToolService(input
|
|
802
|
-
if (detectedTool)
|
|
803
|
-
else
|
|
800
|
+
detectSpecTool: (0, xstate.fromPromise)(async ({ input }) => {
|
|
801
|
+
_agiflowai_aicode_utils.print.info("\nDetecting spec tools...");
|
|
802
|
+
const detectedTool = await new require_utils.SpecToolService(input.workspaceRoot).detectSpecTool();
|
|
803
|
+
if (detectedTool) _agiflowai_aicode_utils.print.success(`Detected ${require_utils.SPEC_TOOL_INFO[detectedTool].name} in workspace`);
|
|
804
|
+
else _agiflowai_aicode_utils.print.info("No spec tool detected");
|
|
804
805
|
return detectedTool;
|
|
805
806
|
}),
|
|
806
807
|
promptSpecDrivenApproach: (0, xstate.fromPromise)(async ({ input: actorInput }) => {
|
|
807
808
|
if (actorInput.detectedSpecTool) {
|
|
808
|
-
|
|
809
|
-
const result
|
|
809
|
+
_agiflowai_aicode_utils.print.divider();
|
|
810
|
+
const result = await (0, _inquirer_prompts.confirm)({
|
|
810
811
|
message: `${require_utils.SPEC_TOOL_INFO[actorInput.detectedSpecTool].name} is installed. Would you like to update the agent instructions for spec-driven development?`,
|
|
811
812
|
default: true
|
|
812
813
|
});
|
|
813
|
-
|
|
814
|
-
return result
|
|
814
|
+
_agiflowai_aicode_utils.print.info("");
|
|
815
|
+
return result;
|
|
815
816
|
}
|
|
816
|
-
|
|
817
|
-
const result = await (0,
|
|
817
|
+
_agiflowai_aicode_utils.print.divider();
|
|
818
|
+
const result = await (0, _inquirer_prompts.confirm)({
|
|
818
819
|
message: "Would you like to install OpenSpec for spec-driven development? This helps AI assistants agree on what to build before writing code.",
|
|
819
820
|
default: false
|
|
820
821
|
});
|
|
821
|
-
|
|
822
|
+
_agiflowai_aicode_utils.print.info("");
|
|
822
823
|
return result;
|
|
823
824
|
}),
|
|
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
|
|
828
|
-
const spinner =
|
|
825
|
+
setupSpec: (0, xstate.fromPromise)(async ({ input }) => {
|
|
826
|
+
const codingAgentService = new require_utils.CodingAgentService(input.workspaceRoot);
|
|
827
|
+
const specToolService = new require_utils.SpecToolService(input.workspaceRoot, require_utils.SpecTool.OPENSPEC, codingAgentService);
|
|
828
|
+
if (input.isAlreadyInstalled) {
|
|
829
|
+
const spinner = ora$1("Updating OpenSpec agent instructions...").start();
|
|
829
830
|
try {
|
|
830
831
|
const enabledMcps = {
|
|
831
|
-
scaffoldMcp: input
|
|
832
|
-
architectMcp: input
|
|
833
|
-
projectType: input
|
|
832
|
+
scaffoldMcp: input.selectedMcpServers?.includes(require_mcp.MCPServer.SCAFFOLD) ?? false,
|
|
833
|
+
architectMcp: input.selectedMcpServers?.includes(require_mcp.MCPServer.ARCHITECT) ?? false,
|
|
834
|
+
projectType: input.projectType
|
|
834
835
|
};
|
|
835
|
-
await specToolService.updateInstructions(enabledMcps, input
|
|
836
|
+
await specToolService.updateInstructions(enabledMcps, input.codingAgent);
|
|
836
837
|
spinner.succeed("OpenSpec agent instructions updated");
|
|
837
838
|
} catch (error) {
|
|
838
839
|
spinner.fail("Failed to update OpenSpec instructions");
|
|
839
840
|
throw error;
|
|
840
841
|
}
|
|
841
842
|
} else {
|
|
842
|
-
const spinner =
|
|
843
|
+
const spinner = ora$1("Initializing OpenSpec...").start();
|
|
843
844
|
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
844
845
|
spinner.stop();
|
|
845
846
|
try {
|
|
846
847
|
await specToolService.initializeSpec();
|
|
847
|
-
|
|
848
|
+
_agiflowai_aicode_utils.print.success("OpenSpec initialized successfully");
|
|
848
849
|
} catch (error) {
|
|
849
|
-
|
|
850
|
+
_agiflowai_aicode_utils.print.error("Failed to initialize OpenSpec");
|
|
850
851
|
throw error;
|
|
851
852
|
}
|
|
852
853
|
}
|
|
853
854
|
}),
|
|
854
855
|
promptSpecInstructions: (0, xstate.fromPromise)(async () => {
|
|
855
|
-
|
|
856
|
-
const result = await (0,
|
|
856
|
+
_agiflowai_aicode_utils.print.divider();
|
|
857
|
+
const result = await (0, _inquirer_prompts.confirm)({
|
|
857
858
|
message: "Would you like to update the agent instructions with OpenSpec workflow guidance?",
|
|
858
859
|
default: true
|
|
859
860
|
});
|
|
860
|
-
|
|
861
|
+
_agiflowai_aicode_utils.print.info("");
|
|
861
862
|
return result;
|
|
862
863
|
}),
|
|
863
|
-
updateSpecInstructions: (0, xstate.fromPromise)(async ({ input
|
|
864
|
-
const spinner =
|
|
864
|
+
updateSpecInstructions: (0, xstate.fromPromise)(async ({ input }) => {
|
|
865
|
+
const spinner = ora$1("Updating OpenSpec agent instructions...").start();
|
|
865
866
|
try {
|
|
866
|
-
const codingAgentService = new require_utils.CodingAgentService(input
|
|
867
|
-
const specToolService = new require_utils.SpecToolService(input
|
|
867
|
+
const codingAgentService = new require_utils.CodingAgentService(input.workspaceRoot);
|
|
868
|
+
const specToolService = new require_utils.SpecToolService(input.workspaceRoot, require_utils.SpecTool.OPENSPEC, codingAgentService);
|
|
868
869
|
const enabledMcps = {
|
|
869
|
-
scaffoldMcp: input
|
|
870
|
-
architectMcp: input
|
|
871
|
-
projectType: input
|
|
870
|
+
scaffoldMcp: input.selectedMcpServers?.includes(require_mcp.MCPServer.SCAFFOLD) ?? false,
|
|
871
|
+
architectMcp: input.selectedMcpServers?.includes(require_mcp.MCPServer.ARCHITECT) ?? false,
|
|
872
|
+
projectType: input.projectType
|
|
872
873
|
};
|
|
873
|
-
await specToolService.updateInstructions(enabledMcps, input
|
|
874
|
+
await specToolService.updateInstructions(enabledMcps, input.codingAgent);
|
|
874
875
|
spinner.succeed("OpenSpec agent instructions updated");
|
|
875
876
|
} catch (error) {
|
|
876
877
|
spinner.fail("Failed to update OpenSpec instructions");
|
|
@@ -878,11 +879,11 @@ const initActors = {
|
|
|
878
879
|
}
|
|
879
880
|
})
|
|
880
881
|
};
|
|
881
|
-
function resolveGeneratedSettingsValues(input
|
|
882
|
-
const resolvedTemplatesPath = input
|
|
882
|
+
function resolveGeneratedSettingsValues(input) {
|
|
883
|
+
const resolvedTemplatesPath = input.templatesPath ?? node_path.default.join(input.workspaceRoot, _agiflowai_aicode_utils.TemplatesManagerService.getTemplatesFolderName());
|
|
883
884
|
return {
|
|
884
|
-
relativeTemplatesPath: node_path.default.relative(input
|
|
885
|
-
sourceTemplate: input
|
|
885
|
+
relativeTemplatesPath: node_path.default.relative(input.workspaceRoot, resolvedTemplatesPath) || "templates",
|
|
886
|
+
sourceTemplate: input.selectedTemplates?.[0]
|
|
886
887
|
};
|
|
887
888
|
}
|
|
888
889
|
/**
|
|
@@ -909,19 +910,17 @@ const initCommand = new commander.Command("init").description("Initialize projec
|
|
|
909
910
|
});
|
|
910
911
|
});
|
|
911
912
|
const { templatesPath, projectType } = actor.getSnapshot().context;
|
|
912
|
-
|
|
913
|
-
if (templatesPath)
|
|
914
|
-
if (projectType)
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
__agiflowai_aicode_utils.print.newline();
|
|
913
|
+
_agiflowai_aicode_utils.print.header("\nSetup Complete!");
|
|
914
|
+
if (templatesPath) _agiflowai_aicode_utils.print.info(`Templates location: ${templatesPath}`);
|
|
915
|
+
if (projectType) _agiflowai_aicode_utils.print.info(`Project type: ${projectType}`);
|
|
916
|
+
_agiflowai_aicode_utils.print.newline();
|
|
917
|
+
require_utils.displaySuccessMessage("🎉 Congratulations! Your project is ready to go!");
|
|
918
|
+
_agiflowai_aicode_utils.print.newline();
|
|
919
919
|
} catch (error) {
|
|
920
|
-
|
|
920
|
+
_agiflowai_aicode_utils.print.error(`\nError: ${error.message}`);
|
|
921
921
|
process.exit(1);
|
|
922
922
|
}
|
|
923
923
|
});
|
|
924
|
-
|
|
925
924
|
//#endregion
|
|
926
925
|
//#region src/commands/sync.ts
|
|
927
926
|
/**
|
|
@@ -967,10 +966,10 @@ function buildHookCommand(server, hookType, extraFlags) {
|
|
|
967
966
|
const serverArgs = server.args ?? [];
|
|
968
967
|
const scriptIdx = serverArgs.findIndex((arg) => /\.(ts|js|mjs|cjs)$/.test(arg));
|
|
969
968
|
if (scriptIdx >= 0) {
|
|
970
|
-
const prefixArgs
|
|
969
|
+
const prefixArgs = serverArgs.slice(0, scriptIdx + 1);
|
|
971
970
|
return [
|
|
972
971
|
server.command,
|
|
973
|
-
...prefixArgs
|
|
972
|
+
...prefixArgs,
|
|
974
973
|
"hook",
|
|
975
974
|
"--type",
|
|
976
975
|
hookType,
|
|
@@ -1077,13 +1076,14 @@ async function writeClaudeSettings(config, workspaceRoot) {
|
|
|
1077
1076
|
hasAny = true;
|
|
1078
1077
|
}
|
|
1079
1078
|
if (!hasAny) {
|
|
1080
|
-
|
|
1081
|
-
return;
|
|
1079
|
+
_agiflowai_aicode_utils.print.warning("No scaffold-mcp/architect-mcp hook.claude-code config found — skipping .claude/settings.json");
|
|
1080
|
+
return false;
|
|
1082
1081
|
}
|
|
1083
1082
|
const settings = { hooks: hooksOutput };
|
|
1084
1083
|
const claudeDir = node_path.default.join(workspaceRoot, CLAUDE_SETTINGS_DIR);
|
|
1085
1084
|
await (0, node_fs_promises.mkdir)(claudeDir, { recursive: true });
|
|
1086
1085
|
await (0, node_fs_promises.writeFile)(node_path.default.join(claudeDir, CLAUDE_SETTINGS_FILE), JSON.stringify(settings, null, 2), "utf-8");
|
|
1086
|
+
return true;
|
|
1087
1087
|
} catch (err) {
|
|
1088
1088
|
const message = err instanceof Error ? err.message : String(err);
|
|
1089
1089
|
throw new Error(`Failed to write ${CLAUDE_SETTINGS_DIR}/${CLAUDE_SETTINGS_FILE}: ${message}`);
|
|
@@ -1093,10 +1093,11 @@ async function writeMcpConfig(config, workspaceRoot) {
|
|
|
1093
1093
|
try {
|
|
1094
1094
|
const mcpConfig = buildMcpConfigYaml(config);
|
|
1095
1095
|
if (!mcpConfig) {
|
|
1096
|
-
|
|
1097
|
-
return;
|
|
1096
|
+
_agiflowai_aicode_utils.print.warning("No mcp-config.servers or mcp-config.skills config found — skipping mcp-config.yaml");
|
|
1097
|
+
return false;
|
|
1098
1098
|
}
|
|
1099
1099
|
await (0, node_fs_promises.writeFile)(node_path.default.join(workspaceRoot, MCP_CONFIG_FILE), js_yaml.default.dump(mcpConfig, { indent: 2 }), "utf-8");
|
|
1100
|
+
return true;
|
|
1100
1101
|
} catch (err) {
|
|
1101
1102
|
const message = err instanceof Error ? err.message : String(err);
|
|
1102
1103
|
throw new Error(`Failed to write ${MCP_CONFIG_FILE}: ${message}`);
|
|
@@ -1107,25 +1108,22 @@ async function writeMcpConfig(config, workspaceRoot) {
|
|
|
1107
1108
|
*/
|
|
1108
1109
|
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
1110
|
try {
|
|
1110
|
-
const [workspaceRoot, config] = await Promise.all([
|
|
1111
|
+
const [workspaceRoot, config] = await Promise.all([_agiflowai_aicode_utils.TemplatesManagerService.getWorkspaceRoot(), _agiflowai_aicode_utils.TemplatesManagerService.readToolkitConfig()]);
|
|
1111
1112
|
if (!config) throw new Error("No toolkit settings config found (.toolkit/settings.yaml or legacy toolkit.yaml). Run `aicode init` first.");
|
|
1112
1113
|
const shouldWriteHooks = options.hooks || !options.hooks && !options.mcp;
|
|
1113
1114
|
const shouldWriteMcp = options.mcp || !options.hooks && !options.mcp;
|
|
1114
1115
|
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");
|
|
1116
|
+
if (await writeClaudeSettings(config, workspaceRoot)) _agiflowai_aicode_utils.print.success("Written .claude/settings.json");
|
|
1117
|
+
} else _agiflowai_aicode_utils.print.warning("No hook.claude-code config found in toolkit settings — skipping");
|
|
1118
1118
|
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");
|
|
1119
|
+
if (await writeMcpConfig(config, workspaceRoot)) _agiflowai_aicode_utils.print.success("Written mcp-config.yaml");
|
|
1120
|
+
} else _agiflowai_aicode_utils.print.warning("No mcp-config.servers or mcp-config.skills config found — skipping mcp-config.yaml");
|
|
1122
1121
|
} catch (error) {
|
|
1123
1122
|
const message = error instanceof Error ? error.message : String(error);
|
|
1124
|
-
|
|
1123
|
+
_agiflowai_aicode_utils.print.error(`sync failed: ${message}`);
|
|
1125
1124
|
process.exit(1);
|
|
1126
1125
|
}
|
|
1127
1126
|
});
|
|
1128
|
-
|
|
1129
1127
|
//#endregion
|
|
1130
1128
|
//#region src/cli.ts
|
|
1131
1129
|
/**
|
|
@@ -1146,5 +1144,4 @@ async function main() {
|
|
|
1146
1144
|
}
|
|
1147
1145
|
}
|
|
1148
1146
|
main();
|
|
1149
|
-
|
|
1150
|
-
//#endregion
|
|
1147
|
+
//#endregion
|