@agiflowai/aicode-toolkit 1.0.22 → 1.0.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -17
- package/dist/cli.cjs +83 -20
- package/dist/cli.mjs +83 -20
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{utils-QWjfWNVp.mjs → utils-BTSpNlWu.mjs} +1 -1
- package/dist/{utils-r_182Nor.cjs → utils-DMP5MQCv.cjs} +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> CLI for initializing projects and managing AI Code Toolkit templates
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Use this CLI to initialize templates, generate `.toolkit/settings.yaml`, and sync agent-facing config files.
|
|
6
6
|
|
|
7
7
|
## Quick Start
|
|
8
8
|
|
|
@@ -28,9 +28,9 @@ npx @agiflowai/aicode-toolkit init
|
|
|
28
28
|
```
|
|
29
29
|
|
|
30
30
|
This will:
|
|
31
|
-
1. Create `templates/`
|
|
32
|
-
2. Download
|
|
33
|
-
3. Detect installed
|
|
31
|
+
1. Create `templates/`
|
|
32
|
+
2. Download built-in templates
|
|
33
|
+
3. Detect installed coding agents
|
|
34
34
|
4. Optionally configure MCP servers
|
|
35
35
|
|
|
36
36
|
**For new projects:**
|
|
@@ -43,10 +43,10 @@ npx @agiflowai/aicode-toolkit init --name my-app --project-type monolith
|
|
|
43
43
|
```
|
|
44
44
|
|
|
45
45
|
This will:
|
|
46
|
-
1. Create project directory
|
|
47
|
-
2. Initialize
|
|
46
|
+
1. Create the project directory
|
|
47
|
+
2. Initialize Git
|
|
48
48
|
3. Download templates
|
|
49
|
-
4. Create
|
|
49
|
+
4. Create `.toolkit/settings.yaml`
|
|
50
50
|
|
|
51
51
|
**Options:**
|
|
52
52
|
| Option | Description | Default |
|
|
@@ -99,13 +99,15 @@ architect-mcp:
|
|
|
99
99
|
hook:
|
|
100
100
|
claude-code:
|
|
101
101
|
preToolUse:
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
102
|
+
matcher: Edit|MultiEdit|Write
|
|
103
|
+
postToolUse:
|
|
104
|
+
matcher: Edit|MultiEdit|Write
|
|
105
105
|
```
|
|
106
106
|
|
|
107
|
-
Generated hook entries
|
|
108
|
-
to write `.claude/settings.json`.
|
|
107
|
+
Generated architect hook entries default to `Edit|MultiEdit|Write`. Run
|
|
108
|
+
`aicode sync --hooks` to write `.claude/settings.json`.
|
|
109
|
+
|
|
110
|
+
Both `.toolkit/settings.yaml` and `.toolkit/settings.local.yaml` now support ordered `fallbacks` lists in `scaffold-mcp` and `architect-mcp` config blocks; the first valid fallback is used when the singular fallback fields are unset.
|
|
109
111
|
|
|
110
112
|
#### `mcp-config` section → `mcp-config.yaml`
|
|
111
113
|
|
|
@@ -171,7 +173,7 @@ npx @agiflowai/aicode-toolkit add \
|
|
|
171
173
|
|
|
172
174
|
## What Gets Installed
|
|
173
175
|
|
|
174
|
-
When you run `init`, these
|
|
176
|
+
When you run `init`, these built-in templates are downloaded:
|
|
175
177
|
|
|
176
178
|
| Template | Description |
|
|
177
179
|
|----------|-------------|
|
|
@@ -190,11 +192,12 @@ Each template includes:
|
|
|
190
192
|
|
|
191
193
|
### Monolith
|
|
192
194
|
|
|
193
|
-
Single application with
|
|
195
|
+
Single application with `.toolkit/settings.yaml` as the primary config:
|
|
194
196
|
|
|
195
197
|
```
|
|
196
198
|
my-app/
|
|
197
|
-
├── toolkit
|
|
199
|
+
├── .toolkit/
|
|
200
|
+
│ └── settings.yaml # sourceTemplate: "nextjs-15"
|
|
198
201
|
├── templates/
|
|
199
202
|
│ └── nextjs-15/
|
|
200
203
|
├── src/
|
|
@@ -222,7 +225,7 @@ my-workspace/
|
|
|
222
225
|
|
|
223
226
|
## Coding Agent Detection
|
|
224
227
|
|
|
225
|
-
The CLI
|
|
228
|
+
The CLI checks for these agent configs:
|
|
226
229
|
|
|
227
230
|
| Agent | Config Location | Status |
|
|
228
231
|
|-------|-----------------|--------|
|
|
@@ -232,7 +235,7 @@ The CLI automatically detects installed AI coding agents:
|
|
|
232
235
|
| Codex CLI | `.codex/config.json` | Supported |
|
|
233
236
|
| GitHub Copilot | VS Code settings | Supported |
|
|
234
237
|
|
|
235
|
-
|
|
238
|
+
If detected, the CLI can add MCP server config for them.
|
|
236
239
|
|
|
237
240
|
---
|
|
238
241
|
|
package/dist/cli.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
const require_utils = require('./utils-
|
|
2
|
+
const require_utils = require('./utils-DMP5MQCv.cjs');
|
|
3
3
|
const require_mcp = require('./mcp--A-5zuBI.cjs');
|
|
4
4
|
let __agiflowai_aicode_utils = require("@agiflowai/aicode-utils");
|
|
5
5
|
let node_fs_promises = require("node:fs/promises");
|
|
@@ -15,18 +15,18 @@ let js_yaml = require("js-yaml");
|
|
|
15
15
|
js_yaml = require_utils.__toESM(js_yaml);
|
|
16
16
|
|
|
17
17
|
//#region package.json
|
|
18
|
-
var version = "1.0.
|
|
18
|
+
var version = "1.0.23";
|
|
19
19
|
|
|
20
20
|
//#endregion
|
|
21
21
|
//#region src/commands/add.ts
|
|
22
22
|
/**
|
|
23
23
|
* Add command - add a template to templates folder
|
|
24
24
|
*/
|
|
25
|
-
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.yaml config by default)").option("--type <type>", "Template type: boilerplate or scaffold", "boilerplate").action(async (options) => {
|
|
25
|
+
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
26
|
try {
|
|
27
27
|
const foundTemplatesPath = options.path ? node_path.default.resolve(options.path) : await __agiflowai_aicode_utils.TemplatesManagerService.findTemplatesPath();
|
|
28
28
|
if (!foundTemplatesPath) {
|
|
29
|
-
__agiflowai_aicode_utils.messages.error("Templates folder not found. Create a templates folder or specify templatesPath in toolkit.yaml");
|
|
29
|
+
__agiflowai_aicode_utils.messages.error("Templates folder not found. Create a templates folder or specify templatesPath in .toolkit/settings.yaml");
|
|
30
30
|
process.exit(1);
|
|
31
31
|
}
|
|
32
32
|
const templatesPath = foundTemplatesPath;
|
|
@@ -81,7 +81,7 @@ const addCommand = new commander.Command("add").description("Add a template to t
|
|
|
81
81
|
|
|
82
82
|
//#endregion
|
|
83
83
|
//#region src/templates/settings.yaml.liquid?raw
|
|
84
|
-
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# ---------------------------------------------------------------------------\n# Project identity\n# ---------------------------------------------------------------------------\n{% if projectType %}\nprojectType: {{ projectType }}\n{% else %}\n# projectType: monolith\n{% endif %}\n{% if templatesPath %}\ntemplatesPath: {{ templatesPath }}\n{% else %}\n# templatesPath: ./templates\n{% endif %}\n{% if sourceTemplate %}\nsourceTemplate: {{ sourceTemplate }}\n{% else %}\n# sourceTemplate: react-vite\n{% endif %}\nversion: '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 # type: stdio\n # port: 3000\n # host: localhost\n # adminEnable: false\n # promptAsSkill: false\n {% if fallbackTool %}\n fallbackTool: {{ fallbackTool }}\n {% if fallbackToolConfig %}\n fallbackToolConfig:\n {% for pair in fallbackToolConfig %}\n {{ pair[0] }}: {{ pair[1] }}\n {% endfor %}\n {% else %}\n # fallbackToolConfig:\n # model: gemini-2.0-flash\n {% endif %}\n {% else %}\n # fallbackTool: gemini-cli\n # fallbackToolConfig:\n # model: gemini-2.0-flash\n {% endif %}\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 # -------------------------------------------------------------------------\n hook:\n\n claude-code:\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 # args:\n # llm-tool: gemini-cli\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 # args:\n # llm-tool: gemini-cli\n\n gemini-cli:\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 # type: stdio\n # port: 3000\n # host: localhost\n # adminEnable: false\n {% if fallbackTool %}\n fallbackTool: {{ fallbackTool }}\n {% if fallbackToolConfig %}\n fallbackToolConfig:\n {% for pair in fallbackToolConfig %}\n {{ pair[0] }}: {{ pair[1] }}\n {% endfor %}\n {% else %}\n # fallbackToolConfig:\n # model: gemini-2.0-flash\n {% endif %}\n {% else %}\n # fallbackTool: gemini-cli\n # fallbackToolConfig:\n # model: gemini-2.0-flash\n {% endif %}\n # designPatternTool: gemini-cli\n # designPatternToolConfig:\n # model: gemini-2.0-flash\n # reviewTool: gemini-cli\n # reviewToolConfig:\n # model: gemini-2.0-flash\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 # -------------------------------------------------------------------------\n hook:\n\n claude-code:\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 # args:\n # llm-tool: gemini-cli\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 # 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";
|
|
84
|
+
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
85
|
|
|
86
86
|
//#endregion
|
|
87
87
|
//#region src/states/init-machine.ts
|
|
@@ -223,7 +223,7 @@ const initMachine = (0, xstate.createMachine)({
|
|
|
223
223
|
checkingSkipTemplates: { always: [{
|
|
224
224
|
target: "promptingMcpSelection",
|
|
225
225
|
guard: ({ context }) => !context.options.skipTemplates
|
|
226
|
-
}, { target: "
|
|
226
|
+
}, { target: "creatingConfig" }] },
|
|
227
227
|
promptingMcpSelection: { invoke: {
|
|
228
228
|
src: "promptMcpSelection",
|
|
229
229
|
onDone: {
|
|
@@ -729,11 +729,15 @@ const initActors = {
|
|
|
729
729
|
}),
|
|
730
730
|
createConfig: (0, xstate.fromPromise)(async ({ input: actorInput }) => {
|
|
731
731
|
if (actorInput.projectType === __agiflowai_aicode_utils.ProjectType.MONOLITH) {
|
|
732
|
-
const relativeTemplatesPath =
|
|
732
|
+
const { relativeTemplatesPath, sourceTemplate } = resolveGeneratedSettingsValues({
|
|
733
|
+
workspaceRoot: actorInput.workspaceRoot,
|
|
734
|
+
templatesPath: actorInput.templatesPath,
|
|
735
|
+
selectedTemplates: actorInput.selectedTemplates
|
|
736
|
+
});
|
|
733
737
|
const content = await new liquidjs.Liquid().parseAndRender(settings_yaml_default, {
|
|
734
738
|
projectType: "monolith",
|
|
735
|
-
templatesPath: relativeTemplatesPath
|
|
736
|
-
sourceTemplate
|
|
739
|
+
templatesPath: relativeTemplatesPath,
|
|
740
|
+
sourceTemplate
|
|
737
741
|
});
|
|
738
742
|
const toolkitDir = node_path.default.join(actorInput.workspaceRoot, ".toolkit");
|
|
739
743
|
const settingsPath = node_path.default.join(toolkitDir, "settings.yaml");
|
|
@@ -874,6 +878,13 @@ const initActors = {
|
|
|
874
878
|
}
|
|
875
879
|
})
|
|
876
880
|
};
|
|
881
|
+
function resolveGeneratedSettingsValues(input$1) {
|
|
882
|
+
const resolvedTemplatesPath = input$1.templatesPath ?? node_path.default.join(input$1.workspaceRoot, __agiflowai_aicode_utils.TemplatesManagerService.getTemplatesFolderName());
|
|
883
|
+
return {
|
|
884
|
+
relativeTemplatesPath: node_path.default.relative(input$1.workspaceRoot, resolvedTemplatesPath) || "templates",
|
|
885
|
+
sourceTemplate: input$1.selectedTemplates?.[0]
|
|
886
|
+
};
|
|
887
|
+
}
|
|
877
888
|
/**
|
|
878
889
|
* Init command - improved V2 implementation
|
|
879
890
|
*/
|
|
@@ -940,6 +951,9 @@ const MCP_CONFIG_FILE = "mcp-config.yaml";
|
|
|
940
951
|
function hasHookConfig(config) {
|
|
941
952
|
return !!(config["scaffold-mcp"]?.hook?.["claude-code"] || config["architect-mcp"]?.hook?.["claude-code"]);
|
|
942
953
|
}
|
|
954
|
+
function getSettingsMcpConfig(config) {
|
|
955
|
+
return config["mcp-config"];
|
|
956
|
+
}
|
|
943
957
|
function argsToFlags(args) {
|
|
944
958
|
const flags = [];
|
|
945
959
|
for (const [key, value] of Object.entries(args)) {
|
|
@@ -974,12 +988,40 @@ function buildHookCommand(server, hookType, extraFlags) {
|
|
|
974
988
|
...extraFlags
|
|
975
989
|
].join(" ");
|
|
976
990
|
}
|
|
977
|
-
function
|
|
991
|
+
function resolveArchitectClaudeMatcher(methodConfig) {
|
|
992
|
+
return methodConfig?.matcher ?? "Edit|MultiEdit|Write";
|
|
993
|
+
}
|
|
994
|
+
function buildMcpConfigYaml(config) {
|
|
995
|
+
const settingsMcpConfig = getSettingsMcpConfig(config);
|
|
996
|
+
const servers = settingsMcpConfig?.servers ?? {};
|
|
997
|
+
const serverEntries = Object.entries(servers);
|
|
998
|
+
if (serverEntries.length === 0 && !settingsMcpConfig?.skills?.paths?.length) return null;
|
|
999
|
+
return {
|
|
1000
|
+
...serverEntries.length > 0 ? { mcpServers: Object.fromEntries(serverEntries.map(([name, server]) => {
|
|
1001
|
+
const instructionConfig = server.instruction ? { instruction: server.instruction } : void 0;
|
|
1002
|
+
const mergedConfig = server.config || instructionConfig ? {
|
|
1003
|
+
...server.config ?? {},
|
|
1004
|
+
...instructionConfig ?? {}
|
|
1005
|
+
} : void 0;
|
|
1006
|
+
return [name, {
|
|
1007
|
+
command: server.command,
|
|
1008
|
+
...server.args ? { args: server.args } : {},
|
|
1009
|
+
...server.env ? { env: server.env } : {},
|
|
1010
|
+
...mergedConfig ? { config: mergedConfig } : {}
|
|
1011
|
+
}];
|
|
1012
|
+
})) } : {},
|
|
1013
|
+
...settingsMcpConfig?.skills?.paths?.length ? { skills: settingsMcpConfig.skills } : {}
|
|
1014
|
+
};
|
|
1015
|
+
}
|
|
1016
|
+
function addHookEntry(output, event, command, matcher) {
|
|
978
1017
|
if (!output[event]) output[event] = [];
|
|
979
|
-
output[event].push({
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
1018
|
+
output[event].push({
|
|
1019
|
+
...matcher ? { matcher } : {},
|
|
1020
|
+
hooks: [{
|
|
1021
|
+
type: "command",
|
|
1022
|
+
command
|
|
1023
|
+
}]
|
|
1024
|
+
});
|
|
983
1025
|
}
|
|
984
1026
|
function isMcpConfigYaml(value) {
|
|
985
1027
|
return typeof value === "object" && value !== null;
|
|
@@ -1020,7 +1062,8 @@ async function writeClaudeSettings(config, workspaceRoot) {
|
|
|
1020
1062
|
if (methodConfig === void 0) continue;
|
|
1021
1063
|
const extraFlags = methodConfig?.args ? argsToFlags(methodConfig?.args) : [];
|
|
1022
1064
|
const command = buildHookCommand(scaffoldServer, `claude-code.${method}`, extraFlags);
|
|
1023
|
-
|
|
1065
|
+
const matcher = methodConfig?.matcher;
|
|
1066
|
+
addHookEntry(hooksOutput, METHOD_TO_EVENT[method], command, matcher);
|
|
1024
1067
|
hasAny = true;
|
|
1025
1068
|
}
|
|
1026
1069
|
const architectAgent = config["architect-mcp"]?.hook?.["claude-code"];
|
|
@@ -1029,7 +1072,8 @@ async function writeClaudeSettings(config, workspaceRoot) {
|
|
|
1029
1072
|
if (methodConfig === void 0) continue;
|
|
1030
1073
|
const extraFlags = methodConfig?.args ? argsToFlags(methodConfig?.args) : [];
|
|
1031
1074
|
const command = buildHookCommand(architectServer, `claude-code.${method}`, extraFlags);
|
|
1032
|
-
|
|
1075
|
+
const matcher = resolveArchitectClaudeMatcher(methodConfig);
|
|
1076
|
+
addHookEntry(hooksOutput, METHOD_TO_EVENT[method], command, matcher);
|
|
1033
1077
|
hasAny = true;
|
|
1034
1078
|
}
|
|
1035
1079
|
if (!hasAny) {
|
|
@@ -1045,17 +1089,36 @@ async function writeClaudeSettings(config, workspaceRoot) {
|
|
|
1045
1089
|
throw new Error(`Failed to write ${CLAUDE_SETTINGS_DIR}/${CLAUDE_SETTINGS_FILE}: ${message}`);
|
|
1046
1090
|
}
|
|
1047
1091
|
}
|
|
1092
|
+
async function writeMcpConfig(config, workspaceRoot) {
|
|
1093
|
+
try {
|
|
1094
|
+
const mcpConfig = buildMcpConfigYaml(config);
|
|
1095
|
+
if (!mcpConfig) {
|
|
1096
|
+
__agiflowai_aicode_utils.print.warning("No mcp-config.servers or mcp-config.skills config found — skipping mcp-config.yaml");
|
|
1097
|
+
return;
|
|
1098
|
+
}
|
|
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
|
+
} catch (err) {
|
|
1101
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1102
|
+
throw new Error(`Failed to write ${MCP_CONFIG_FILE}: ${message}`);
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1048
1105
|
/**
|
|
1049
1106
|
* Generate .claude/settings.json from .toolkit/settings.yaml and mcp-config.yaml
|
|
1050
1107
|
*/
|
|
1051
|
-
const syncCommand = new commander.Command("sync").description("Generate .claude/settings.json from .toolkit/settings.yaml and mcp-config.yaml").action(async () => {
|
|
1108
|
+
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) => {
|
|
1052
1109
|
try {
|
|
1053
1110
|
const [workspaceRoot, config] = await Promise.all([__agiflowai_aicode_utils.TemplatesManagerService.getWorkspaceRoot(), __agiflowai_aicode_utils.TemplatesManagerService.readToolkitConfig()]);
|
|
1054
|
-
if (!config) throw new Error("No .toolkit/settings.yaml
|
|
1055
|
-
|
|
1111
|
+
if (!config) throw new Error("No toolkit settings config found (.toolkit/settings.yaml or legacy toolkit.yaml). Run `aicode init` first.");
|
|
1112
|
+
const shouldWriteHooks = options.hooks || !options.hooks && !options.mcp;
|
|
1113
|
+
const shouldWriteMcp = options.mcp || !options.hooks && !options.mcp;
|
|
1114
|
+
if (shouldWriteHooks) if (hasHookConfig(config)) {
|
|
1056
1115
|
await writeClaudeSettings(config, workspaceRoot);
|
|
1057
1116
|
__agiflowai_aicode_utils.print.success("Written .claude/settings.json");
|
|
1058
|
-
} else __agiflowai_aicode_utils.print.warning("No hook.claude-code config found in settings
|
|
1117
|
+
} else __agiflowai_aicode_utils.print.warning("No hook.claude-code config found in toolkit settings — skipping");
|
|
1118
|
+
if (shouldWriteMcp) if (buildMcpConfigYaml(config)) {
|
|
1119
|
+
await writeMcpConfig(config, workspaceRoot);
|
|
1120
|
+
__agiflowai_aicode_utils.print.success("Written mcp-config.yaml");
|
|
1121
|
+
} else __agiflowai_aicode_utils.print.warning("No mcp-config.servers or mcp-config.skills config found — skipping mcp-config.yaml");
|
|
1059
1122
|
} catch (error) {
|
|
1060
1123
|
const message = error instanceof Error ? error.message : String(error);
|
|
1061
1124
|
__agiflowai_aicode_utils.print.error(`sync failed: ${message}`);
|
package/dist/cli.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { r as MCP_SERVER_INFO, t as MCPServer } from "./mcp-CBcPdzNG.mjs";
|
|
3
|
-
import { a as SPEC_TOOL_INFO, c as NewProjectService, i as TemplateSelectionService, l as CodingAgentService, o as SpecTool, s as SpecToolService, t as displayBanner } from "./utils-
|
|
3
|
+
import { a as SPEC_TOOL_INFO, c as NewProjectService, i as TemplateSelectionService, l as CodingAgentService, o as SpecTool, s as SpecToolService, t as displayBanner } from "./utils-BTSpNlWu.mjs";
|
|
4
4
|
import { ProjectType, TemplatesManagerService, cloneRepository, cloneSubdirectory, detectProjectType, ensureDir, findWorkspaceRoot, icons, messages, parseGitHubUrl, pathExists, print, sections } from "@agiflowai/aicode-utils";
|
|
5
5
|
import { mkdir as mkdir$1, readFile as readFile$1, writeFile as writeFile$1 } from "node:fs/promises";
|
|
6
6
|
import path from "node:path";
|
|
@@ -12,18 +12,18 @@ import { assign, createActor, createMachine, fromPromise } from "xstate";
|
|
|
12
12
|
import yaml from "js-yaml";
|
|
13
13
|
|
|
14
14
|
//#region package.json
|
|
15
|
-
var version = "1.0.
|
|
15
|
+
var version = "1.0.23";
|
|
16
16
|
|
|
17
17
|
//#endregion
|
|
18
18
|
//#region src/commands/add.ts
|
|
19
19
|
/**
|
|
20
20
|
* Add command - add a template to templates folder
|
|
21
21
|
*/
|
|
22
|
-
const addCommand = new 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.yaml config by default)").option("--type <type>", "Template type: boilerplate or scaffold", "boilerplate").action(async (options) => {
|
|
22
|
+
const addCommand = new 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) => {
|
|
23
23
|
try {
|
|
24
24
|
const foundTemplatesPath = options.path ? path.resolve(options.path) : await TemplatesManagerService.findTemplatesPath();
|
|
25
25
|
if (!foundTemplatesPath) {
|
|
26
|
-
messages.error("Templates folder not found. Create a templates folder or specify templatesPath in toolkit.yaml");
|
|
26
|
+
messages.error("Templates folder not found. Create a templates folder or specify templatesPath in .toolkit/settings.yaml");
|
|
27
27
|
process.exit(1);
|
|
28
28
|
}
|
|
29
29
|
const templatesPath = foundTemplatesPath;
|
|
@@ -78,7 +78,7 @@ const addCommand = new Command("add").description("Add a template to templates f
|
|
|
78
78
|
|
|
79
79
|
//#endregion
|
|
80
80
|
//#region src/templates/settings.yaml.liquid?raw
|
|
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# ---------------------------------------------------------------------------\n# Project identity\n# ---------------------------------------------------------------------------\n{% if projectType %}\nprojectType: {{ projectType }}\n{% else %}\n# projectType: monolith\n{% endif %}\n{% if templatesPath %}\ntemplatesPath: {{ templatesPath }}\n{% else %}\n# templatesPath: ./templates\n{% endif %}\n{% if sourceTemplate %}\nsourceTemplate: {{ sourceTemplate }}\n{% else %}\n# sourceTemplate: react-vite\n{% endif %}\nversion: '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 # type: stdio\n # port: 3000\n # host: localhost\n # adminEnable: false\n # promptAsSkill: false\n {% if fallbackTool %}\n fallbackTool: {{ fallbackTool }}\n {% if fallbackToolConfig %}\n fallbackToolConfig:\n {% for pair in fallbackToolConfig %}\n {{ pair[0] }}: {{ pair[1] }}\n {% endfor %}\n {% else %}\n # fallbackToolConfig:\n # model: gemini-2.0-flash\n {% endif %}\n {% else %}\n # fallbackTool: gemini-cli\n # fallbackToolConfig:\n # model: gemini-2.0-flash\n {% endif %}\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 # -------------------------------------------------------------------------\n hook:\n\n claude-code:\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 # args:\n # llm-tool: gemini-cli\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 # args:\n # llm-tool: gemini-cli\n\n gemini-cli:\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 # type: stdio\n # port: 3000\n # host: localhost\n # adminEnable: false\n {% if fallbackTool %}\n fallbackTool: {{ fallbackTool }}\n {% if fallbackToolConfig %}\n fallbackToolConfig:\n {% for pair in fallbackToolConfig %}\n {{ pair[0] }}: {{ pair[1] }}\n {% endfor %}\n {% else %}\n # fallbackToolConfig:\n # model: gemini-2.0-flash\n {% endif %}\n {% else %}\n # fallbackTool: gemini-cli\n # fallbackToolConfig:\n # model: gemini-2.0-flash\n {% endif %}\n # designPatternTool: gemini-cli\n # designPatternToolConfig:\n # model: gemini-2.0-flash\n # reviewTool: gemini-cli\n # reviewToolConfig:\n # model: gemini-2.0-flash\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 # -------------------------------------------------------------------------\n hook:\n\n claude-code:\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 # args:\n # llm-tool: gemini-cli\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 # 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";
|
|
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";
|
|
82
82
|
|
|
83
83
|
//#endregion
|
|
84
84
|
//#region src/states/init-machine.ts
|
|
@@ -220,7 +220,7 @@ const initMachine = createMachine({
|
|
|
220
220
|
checkingSkipTemplates: { always: [{
|
|
221
221
|
target: "promptingMcpSelection",
|
|
222
222
|
guard: ({ context }) => !context.options.skipTemplates
|
|
223
|
-
}, { target: "
|
|
223
|
+
}, { target: "creatingConfig" }] },
|
|
224
224
|
promptingMcpSelection: { invoke: {
|
|
225
225
|
src: "promptMcpSelection",
|
|
226
226
|
onDone: {
|
|
@@ -726,11 +726,15 @@ const initActors = {
|
|
|
726
726
|
}),
|
|
727
727
|
createConfig: fromPromise(async ({ input: actorInput }) => {
|
|
728
728
|
if (actorInput.projectType === ProjectType.MONOLITH) {
|
|
729
|
-
const relativeTemplatesPath =
|
|
729
|
+
const { relativeTemplatesPath, sourceTemplate } = resolveGeneratedSettingsValues({
|
|
730
|
+
workspaceRoot: actorInput.workspaceRoot,
|
|
731
|
+
templatesPath: actorInput.templatesPath,
|
|
732
|
+
selectedTemplates: actorInput.selectedTemplates
|
|
733
|
+
});
|
|
730
734
|
const content = await new Liquid().parseAndRender(settings_yaml_default, {
|
|
731
735
|
projectType: "monolith",
|
|
732
|
-
templatesPath: relativeTemplatesPath
|
|
733
|
-
sourceTemplate
|
|
736
|
+
templatesPath: relativeTemplatesPath,
|
|
737
|
+
sourceTemplate
|
|
734
738
|
});
|
|
735
739
|
const toolkitDir = path.join(actorInput.workspaceRoot, ".toolkit");
|
|
736
740
|
const settingsPath = path.join(toolkitDir, "settings.yaml");
|
|
@@ -871,6 +875,13 @@ const initActors = {
|
|
|
871
875
|
}
|
|
872
876
|
})
|
|
873
877
|
};
|
|
878
|
+
function resolveGeneratedSettingsValues(input$1) {
|
|
879
|
+
const resolvedTemplatesPath = input$1.templatesPath ?? path.join(input$1.workspaceRoot, TemplatesManagerService.getTemplatesFolderName());
|
|
880
|
+
return {
|
|
881
|
+
relativeTemplatesPath: path.relative(input$1.workspaceRoot, resolvedTemplatesPath) || "templates",
|
|
882
|
+
sourceTemplate: input$1.selectedTemplates?.[0]
|
|
883
|
+
};
|
|
884
|
+
}
|
|
874
885
|
/**
|
|
875
886
|
* Init command - improved V2 implementation
|
|
876
887
|
*/
|
|
@@ -937,6 +948,9 @@ const MCP_CONFIG_FILE = "mcp-config.yaml";
|
|
|
937
948
|
function hasHookConfig(config) {
|
|
938
949
|
return !!(config["scaffold-mcp"]?.hook?.["claude-code"] || config["architect-mcp"]?.hook?.["claude-code"]);
|
|
939
950
|
}
|
|
951
|
+
function getSettingsMcpConfig(config) {
|
|
952
|
+
return config["mcp-config"];
|
|
953
|
+
}
|
|
940
954
|
function argsToFlags(args) {
|
|
941
955
|
const flags = [];
|
|
942
956
|
for (const [key, value] of Object.entries(args)) {
|
|
@@ -971,12 +985,40 @@ function buildHookCommand(server, hookType, extraFlags) {
|
|
|
971
985
|
...extraFlags
|
|
972
986
|
].join(" ");
|
|
973
987
|
}
|
|
974
|
-
function
|
|
988
|
+
function resolveArchitectClaudeMatcher(methodConfig) {
|
|
989
|
+
return methodConfig?.matcher ?? "Edit|MultiEdit|Write";
|
|
990
|
+
}
|
|
991
|
+
function buildMcpConfigYaml(config) {
|
|
992
|
+
const settingsMcpConfig = getSettingsMcpConfig(config);
|
|
993
|
+
const servers = settingsMcpConfig?.servers ?? {};
|
|
994
|
+
const serverEntries = Object.entries(servers);
|
|
995
|
+
if (serverEntries.length === 0 && !settingsMcpConfig?.skills?.paths?.length) return null;
|
|
996
|
+
return {
|
|
997
|
+
...serverEntries.length > 0 ? { mcpServers: Object.fromEntries(serverEntries.map(([name, server]) => {
|
|
998
|
+
const instructionConfig = server.instruction ? { instruction: server.instruction } : void 0;
|
|
999
|
+
const mergedConfig = server.config || instructionConfig ? {
|
|
1000
|
+
...server.config ?? {},
|
|
1001
|
+
...instructionConfig ?? {}
|
|
1002
|
+
} : void 0;
|
|
1003
|
+
return [name, {
|
|
1004
|
+
command: server.command,
|
|
1005
|
+
...server.args ? { args: server.args } : {},
|
|
1006
|
+
...server.env ? { env: server.env } : {},
|
|
1007
|
+
...mergedConfig ? { config: mergedConfig } : {}
|
|
1008
|
+
}];
|
|
1009
|
+
})) } : {},
|
|
1010
|
+
...settingsMcpConfig?.skills?.paths?.length ? { skills: settingsMcpConfig.skills } : {}
|
|
1011
|
+
};
|
|
1012
|
+
}
|
|
1013
|
+
function addHookEntry(output, event, command, matcher) {
|
|
975
1014
|
if (!output[event]) output[event] = [];
|
|
976
|
-
output[event].push({
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
1015
|
+
output[event].push({
|
|
1016
|
+
...matcher ? { matcher } : {},
|
|
1017
|
+
hooks: [{
|
|
1018
|
+
type: "command",
|
|
1019
|
+
command
|
|
1020
|
+
}]
|
|
1021
|
+
});
|
|
980
1022
|
}
|
|
981
1023
|
function isMcpConfigYaml(value) {
|
|
982
1024
|
return typeof value === "object" && value !== null;
|
|
@@ -1017,7 +1059,8 @@ async function writeClaudeSettings(config, workspaceRoot) {
|
|
|
1017
1059
|
if (methodConfig === void 0) continue;
|
|
1018
1060
|
const extraFlags = methodConfig?.args ? argsToFlags(methodConfig?.args) : [];
|
|
1019
1061
|
const command = buildHookCommand(scaffoldServer, `claude-code.${method}`, extraFlags);
|
|
1020
|
-
|
|
1062
|
+
const matcher = methodConfig?.matcher;
|
|
1063
|
+
addHookEntry(hooksOutput, METHOD_TO_EVENT[method], command, matcher);
|
|
1021
1064
|
hasAny = true;
|
|
1022
1065
|
}
|
|
1023
1066
|
const architectAgent = config["architect-mcp"]?.hook?.["claude-code"];
|
|
@@ -1026,7 +1069,8 @@ async function writeClaudeSettings(config, workspaceRoot) {
|
|
|
1026
1069
|
if (methodConfig === void 0) continue;
|
|
1027
1070
|
const extraFlags = methodConfig?.args ? argsToFlags(methodConfig?.args) : [];
|
|
1028
1071
|
const command = buildHookCommand(architectServer, `claude-code.${method}`, extraFlags);
|
|
1029
|
-
|
|
1072
|
+
const matcher = resolveArchitectClaudeMatcher(methodConfig);
|
|
1073
|
+
addHookEntry(hooksOutput, METHOD_TO_EVENT[method], command, matcher);
|
|
1030
1074
|
hasAny = true;
|
|
1031
1075
|
}
|
|
1032
1076
|
if (!hasAny) {
|
|
@@ -1042,17 +1086,36 @@ async function writeClaudeSettings(config, workspaceRoot) {
|
|
|
1042
1086
|
throw new Error(`Failed to write ${CLAUDE_SETTINGS_DIR}/${CLAUDE_SETTINGS_FILE}: ${message}`);
|
|
1043
1087
|
}
|
|
1044
1088
|
}
|
|
1089
|
+
async function writeMcpConfig(config, workspaceRoot) {
|
|
1090
|
+
try {
|
|
1091
|
+
const mcpConfig = buildMcpConfigYaml(config);
|
|
1092
|
+
if (!mcpConfig) {
|
|
1093
|
+
print.warning("No mcp-config.servers or mcp-config.skills config found — skipping mcp-config.yaml");
|
|
1094
|
+
return;
|
|
1095
|
+
}
|
|
1096
|
+
await writeFile$1(path.join(workspaceRoot, MCP_CONFIG_FILE), yaml.dump(mcpConfig, { indent: 2 }), "utf-8");
|
|
1097
|
+
} catch (err) {
|
|
1098
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1099
|
+
throw new Error(`Failed to write ${MCP_CONFIG_FILE}: ${message}`);
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1045
1102
|
/**
|
|
1046
1103
|
* Generate .claude/settings.json from .toolkit/settings.yaml and mcp-config.yaml
|
|
1047
1104
|
*/
|
|
1048
|
-
const syncCommand = new Command("sync").description("Generate .claude/settings.json from .toolkit/settings.yaml and mcp-config.yaml").action(async () => {
|
|
1105
|
+
const syncCommand = new 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) => {
|
|
1049
1106
|
try {
|
|
1050
1107
|
const [workspaceRoot, config] = await Promise.all([TemplatesManagerService.getWorkspaceRoot(), TemplatesManagerService.readToolkitConfig()]);
|
|
1051
|
-
if (!config) throw new Error("No .toolkit/settings.yaml
|
|
1052
|
-
|
|
1108
|
+
if (!config) throw new Error("No toolkit settings config found (.toolkit/settings.yaml or legacy toolkit.yaml). Run `aicode init` first.");
|
|
1109
|
+
const shouldWriteHooks = options.hooks || !options.hooks && !options.mcp;
|
|
1110
|
+
const shouldWriteMcp = options.mcp || !options.hooks && !options.mcp;
|
|
1111
|
+
if (shouldWriteHooks) if (hasHookConfig(config)) {
|
|
1053
1112
|
await writeClaudeSettings(config, workspaceRoot);
|
|
1054
1113
|
print.success("Written .claude/settings.json");
|
|
1055
|
-
} else print.warning("No hook.claude-code config found in settings
|
|
1114
|
+
} else print.warning("No hook.claude-code config found in toolkit settings — skipping");
|
|
1115
|
+
if (shouldWriteMcp) if (buildMcpConfigYaml(config)) {
|
|
1116
|
+
await writeMcpConfig(config, workspaceRoot);
|
|
1117
|
+
print.success("Written mcp-config.yaml");
|
|
1118
|
+
} else print.warning("No mcp-config.servers or mcp-config.skills config found — skipping mcp-config.yaml");
|
|
1056
1119
|
} catch (error) {
|
|
1057
1120
|
const message = error instanceof Error ? error.message : String(error);
|
|
1058
1121
|
print.error(`sync failed: ${message}`);
|
package/dist/index.cjs
CHANGED
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import "./mcp-CBcPdzNG.mjs";
|
|
2
|
-
import { c as NewProjectService, d as THEME, i as TemplateSelectionService, l as CodingAgentService, n as displayCompactBanner, r as TemplatesService, t as displayBanner, u as BANNER_GRADIENT } from "./utils-
|
|
2
|
+
import { c as NewProjectService, d as THEME, i as TemplateSelectionService, l as CodingAgentService, n as displayCompactBanner, r as TemplatesService, t as displayBanner, u as BANNER_GRADIENT } from "./utils-BTSpNlWu.mjs";
|
|
3
3
|
|
|
4
4
|
export { BANNER_GRADIENT, CodingAgentService, NewProjectService, THEME, TemplateSelectionService, TemplatesService, displayBanner, displayCompactBanner };
|
|
@@ -462,7 +462,7 @@ var NewProjectService = class {
|
|
|
462
462
|
|
|
463
463
|
//#endregion
|
|
464
464
|
//#region src/instructions/specs/openspec.md?raw
|
|
465
|
-
var openspec_default = "When working on this project, follow the OpenSpec spec-driven development workflow{% if scaffoldMcp or architectMcp %} integrated with MCP tools{% endif %}.\n\n{% if scaffoldMcp %}\n\n## {% if scaffoldMcp %}1{% else %}1{% endif %}. Create Proposals with scaffold-mcp\n\nWhen implementing new features or changes, use scaffold-mcp MCP tools:\n\n**For new projects/features:**\n1. Use `list-boilerplates` MCP tool to see available templates\n2. Use `use-boilerplate` MCP tool to scaffold new projects{% if projectType == 'monolith' %} (set `monolith: true`){% elsif projectType == 'monorepo' %} (omit `monolith` parameter){% endif %}\n3. Use `list-scaffolding-methods` MCP tool to understand which methods can be used to add features\n4. Create OpenSpec proposal with available scaffolding methods in mind: \"Create an OpenSpec proposal for [feature description]\"\n\n**For adding features to existing code:**\n1. Use `list-scaffolding-methods` MCP tool with projectPath to see available features{% if projectType == 'monolith' %} (`projectPath` = workspace root){% elsif projectType == 'monorepo' %} (`projectPath` = project directory with project.json){% endif %}\n2. Review available methods and plan which ones to use for the feature\n3. Use `use-scaffold-method` MCP tool to generate boilerplate code\n4. Create OpenSpec proposal to capture the specs\n{% if projectType %}\n\n**Path Mapping ({% if projectType == 'monolith' %}Monolith{% else %}Monorepo{% endif %} Project):**\n{% if projectType == 'monolith' %}\n*This is a monolith project:*\n- Single project at workspace root\n- Config file:
|
|
465
|
+
var openspec_default = "When working on this project, follow the OpenSpec spec-driven development workflow{% if scaffoldMcp or architectMcp %} integrated with MCP tools{% endif %}.\n\n{% if scaffoldMcp %}\n\n## {% if scaffoldMcp %}1{% else %}1{% endif %}. Create Proposals with scaffold-mcp\n\nWhen implementing new features or changes, use scaffold-mcp MCP tools:\n\n**For new projects/features:**\n1. Use `list-boilerplates` MCP tool to see available templates\n2. Use `use-boilerplate` MCP tool to scaffold new projects{% if projectType == 'monolith' %} (set `monolith: true`){% elsif projectType == 'monorepo' %} (omit `monolith` parameter){% endif %}\n3. Use `list-scaffolding-methods` MCP tool to understand which methods can be used to add features\n4. Create OpenSpec proposal with available scaffolding methods in mind: \"Create an OpenSpec proposal for [feature description]\"\n\n**For adding features to existing code:**\n1. Use `list-scaffolding-methods` MCP tool with projectPath to see available features{% if projectType == 'monolith' %} (`projectPath` = workspace root){% elsif projectType == 'monorepo' %} (`projectPath` = project directory with project.json){% endif %}\n2. Review available methods and plan which ones to use for the feature\n3. Use `use-scaffold-method` MCP tool to generate boilerplate code\n4. Create OpenSpec proposal to capture the specs\n{% if projectType %}\n\n**Path Mapping ({% if projectType == 'monolith' %}Monolith{% else %}Monorepo{% endif %} Project):**\n{% if projectType == 'monolith' %}\n*This is a monolith project:*\n- Single project at workspace root\n- Config file: `.toolkit/settings.yaml` at root\n- All code in workspace root (src/, lib/, etc.)\n- When scaffolding: Use `monolith: true` parameter\n- When using scaffold methods: `projectPath` = workspace root\n\nExample: For workspace at `/path/to/project`:\n- Project config: `/path/to/project/.toolkit/settings.yaml`\n- Source code: `/path/to/project/src/`\n- OpenSpec: `/path/to/project/openspec/`\n{% else %}\n*This is a monorepo project:*\n- Multiple projects in subdirectories\n- Config file: `project.json` in each project\n- Projects in apps/, packages/, libs/, etc.\n- When scaffolding: Omit `monolith` parameter (defaults to false)\n- When using scaffold methods: `projectPath` = path to specific project\n\nExample: For workspace at `/path/to/workspace`:\n- App config: `/path/to/workspace/apps/my-app/project.json`\n- App source: `/path/to/workspace/apps/my-app/src/`\n- OpenSpec: `/path/to/workspace/openspec/` (workspace-level)\n{% endif %}\n{% endif %}\n\nAI will scaffold: openspec/changes/[feature-name]/ with proposal.md, tasks.md, and spec deltas\n{% endif %}\n{% if architectMcp %}\n\n## {% if scaffoldMcp %}2{% else %}1{% endif %}. Review & Validate with architect-mcp\n\nBefore and after editing files, use architect-mcp MCP tools:\n\n**Before editing:**\n- Use `get-file-design-pattern` MCP tool to understand:\n - Applicable design patterns from architect.yaml\n - Coding rules from RULES.yaml (must_do, should_do, must_not_do)\n - Code examples showing the patterns\n\n**After editing:**\n- Use `review-code-change` MCP tool to check for:\n - Must not do violations (critical issues)\n - Must do missing (required patterns not followed)\n - Should do suggestions (best practices)\n\n**Validate OpenSpec specs:**\n- Use `openspec validate [feature-name]` to check spec formatting\n- Iterate with AI until specs are agreed upon\n{% endif %}\n\n## {% if scaffoldMcp and architectMcp %}3{% elsif scaffoldMcp or architectMcp %}2{% else %}1{% endif %}. Implement{% if architectMcp %} with MCP-Guided Development{% endif %}\n\nDuring implementation:\n1. Ask AI to implement: \"Apply the OpenSpec change [feature-name]\"\n{% if architectMcp %}\n2. **Before each file edit**: Use `get-file-design-pattern` to understand patterns\n3. AI implements tasks from tasks.md following design patterns\n4. **After each file edit**: Use `review-code-change` to verify compliance\n5. Fix any violations before proceeding\n{% else %}\n2. AI implements tasks from tasks.md following the agreed specs\n{% endif %}\n\n## {% if scaffoldMcp and architectMcp %}4{% elsif scaffoldMcp or architectMcp %}3{% else %}2{% endif %}. Archive Completed Changes\n{% if scaffoldMcp or architectMcp %}\n\n## MCP Tools Reference\n{% endif %}\n{% if scaffoldMcp %}\n\n### scaffold-mcp\n- `list-boilerplates` - List available project templates\n- `use-boilerplate` - Create new project from template\n- `list-scaffolding-methods` - List features for existing project\n- `use-scaffold-method` - Add feature to existing project\n{% endif %}\n{% if architectMcp %}\n\n### architect-mcp\n- `get-file-design-pattern` - Get design patterns for file\n- `review-code-change` - Review code for violations\n{% endif %}\n\n## Workflow Summary\n\n{% if scaffoldMcp %}\n1. **Plan**: Use scaffold-mcp to generate boilerplate + OpenSpec proposal for specs\n{% else %}\n1. **Plan**: Create OpenSpec proposal with specs\n{% endif %}\n{% if architectMcp %}\n{% if scaffoldMcp %}2{% else %}2{% endif %}. **Design**: Use architect-mcp to understand patterns before editing\n{% endif %}\n{% if scaffoldMcp and architectMcp %}3{% elsif scaffoldMcp or architectMcp %}{% if architectMcp %}3{% else %}2{% endif %}{% else %}2{% endif %}. **Implement**: Follow specs{% if architectMcp %} and patterns{% endif %}\n{% if architectMcp %}\n{% if scaffoldMcp %}4{% else %}4{% endif %}. **Review**: Use architect-mcp to validate code quality\n{% endif %}\n{% if scaffoldMcp and architectMcp %}5{% elsif scaffoldMcp or architectMcp %}{% if architectMcp %}5{% else %}3{% endif %}{% else %}3{% endif %}. **Archive**: Merge specs into source of truth\n";
|
|
466
466
|
|
|
467
467
|
//#endregion
|
|
468
468
|
//#region src/specs/openspec.ts
|
|
@@ -494,7 +494,7 @@ var NewProjectService = class {
|
|
|
494
494
|
|
|
495
495
|
//#endregion
|
|
496
496
|
//#region src/instructions/specs/openspec.md?raw
|
|
497
|
-
var openspec_default = "When working on this project, follow the OpenSpec spec-driven development workflow{% if scaffoldMcp or architectMcp %} integrated with MCP tools{% endif %}.\n\n{% if scaffoldMcp %}\n\n## {% if scaffoldMcp %}1{% else %}1{% endif %}. Create Proposals with scaffold-mcp\n\nWhen implementing new features or changes, use scaffold-mcp MCP tools:\n\n**For new projects/features:**\n1. Use `list-boilerplates` MCP tool to see available templates\n2. Use `use-boilerplate` MCP tool to scaffold new projects{% if projectType == 'monolith' %} (set `monolith: true`){% elsif projectType == 'monorepo' %} (omit `monolith` parameter){% endif %}\n3. Use `list-scaffolding-methods` MCP tool to understand which methods can be used to add features\n4. Create OpenSpec proposal with available scaffolding methods in mind: \"Create an OpenSpec proposal for [feature description]\"\n\n**For adding features to existing code:**\n1. Use `list-scaffolding-methods` MCP tool with projectPath to see available features{% if projectType == 'monolith' %} (`projectPath` = workspace root){% elsif projectType == 'monorepo' %} (`projectPath` = project directory with project.json){% endif %}\n2. Review available methods and plan which ones to use for the feature\n3. Use `use-scaffold-method` MCP tool to generate boilerplate code\n4. Create OpenSpec proposal to capture the specs\n{% if projectType %}\n\n**Path Mapping ({% if projectType == 'monolith' %}Monolith{% else %}Monorepo{% endif %} Project):**\n{% if projectType == 'monolith' %}\n*This is a monolith project:*\n- Single project at workspace root\n- Config file:
|
|
497
|
+
var openspec_default = "When working on this project, follow the OpenSpec spec-driven development workflow{% if scaffoldMcp or architectMcp %} integrated with MCP tools{% endif %}.\n\n{% if scaffoldMcp %}\n\n## {% if scaffoldMcp %}1{% else %}1{% endif %}. Create Proposals with scaffold-mcp\n\nWhen implementing new features or changes, use scaffold-mcp MCP tools:\n\n**For new projects/features:**\n1. Use `list-boilerplates` MCP tool to see available templates\n2. Use `use-boilerplate` MCP tool to scaffold new projects{% if projectType == 'monolith' %} (set `monolith: true`){% elsif projectType == 'monorepo' %} (omit `monolith` parameter){% endif %}\n3. Use `list-scaffolding-methods` MCP tool to understand which methods can be used to add features\n4. Create OpenSpec proposal with available scaffolding methods in mind: \"Create an OpenSpec proposal for [feature description]\"\n\n**For adding features to existing code:**\n1. Use `list-scaffolding-methods` MCP tool with projectPath to see available features{% if projectType == 'monolith' %} (`projectPath` = workspace root){% elsif projectType == 'monorepo' %} (`projectPath` = project directory with project.json){% endif %}\n2. Review available methods and plan which ones to use for the feature\n3. Use `use-scaffold-method` MCP tool to generate boilerplate code\n4. Create OpenSpec proposal to capture the specs\n{% if projectType %}\n\n**Path Mapping ({% if projectType == 'monolith' %}Monolith{% else %}Monorepo{% endif %} Project):**\n{% if projectType == 'monolith' %}\n*This is a monolith project:*\n- Single project at workspace root\n- Config file: `.toolkit/settings.yaml` at root\n- All code in workspace root (src/, lib/, etc.)\n- When scaffolding: Use `monolith: true` parameter\n- When using scaffold methods: `projectPath` = workspace root\n\nExample: For workspace at `/path/to/project`:\n- Project config: `/path/to/project/.toolkit/settings.yaml`\n- Source code: `/path/to/project/src/`\n- OpenSpec: `/path/to/project/openspec/`\n{% else %}\n*This is a monorepo project:*\n- Multiple projects in subdirectories\n- Config file: `project.json` in each project\n- Projects in apps/, packages/, libs/, etc.\n- When scaffolding: Omit `monolith` parameter (defaults to false)\n- When using scaffold methods: `projectPath` = path to specific project\n\nExample: For workspace at `/path/to/workspace`:\n- App config: `/path/to/workspace/apps/my-app/project.json`\n- App source: `/path/to/workspace/apps/my-app/src/`\n- OpenSpec: `/path/to/workspace/openspec/` (workspace-level)\n{% endif %}\n{% endif %}\n\nAI will scaffold: openspec/changes/[feature-name]/ with proposal.md, tasks.md, and spec deltas\n{% endif %}\n{% if architectMcp %}\n\n## {% if scaffoldMcp %}2{% else %}1{% endif %}. Review & Validate with architect-mcp\n\nBefore and after editing files, use architect-mcp MCP tools:\n\n**Before editing:**\n- Use `get-file-design-pattern` MCP tool to understand:\n - Applicable design patterns from architect.yaml\n - Coding rules from RULES.yaml (must_do, should_do, must_not_do)\n - Code examples showing the patterns\n\n**After editing:**\n- Use `review-code-change` MCP tool to check for:\n - Must not do violations (critical issues)\n - Must do missing (required patterns not followed)\n - Should do suggestions (best practices)\n\n**Validate OpenSpec specs:**\n- Use `openspec validate [feature-name]` to check spec formatting\n- Iterate with AI until specs are agreed upon\n{% endif %}\n\n## {% if scaffoldMcp and architectMcp %}3{% elsif scaffoldMcp or architectMcp %}2{% else %}1{% endif %}. Implement{% if architectMcp %} with MCP-Guided Development{% endif %}\n\nDuring implementation:\n1. Ask AI to implement: \"Apply the OpenSpec change [feature-name]\"\n{% if architectMcp %}\n2. **Before each file edit**: Use `get-file-design-pattern` to understand patterns\n3. AI implements tasks from tasks.md following design patterns\n4. **After each file edit**: Use `review-code-change` to verify compliance\n5. Fix any violations before proceeding\n{% else %}\n2. AI implements tasks from tasks.md following the agreed specs\n{% endif %}\n\n## {% if scaffoldMcp and architectMcp %}4{% elsif scaffoldMcp or architectMcp %}3{% else %}2{% endif %}. Archive Completed Changes\n{% if scaffoldMcp or architectMcp %}\n\n## MCP Tools Reference\n{% endif %}\n{% if scaffoldMcp %}\n\n### scaffold-mcp\n- `list-boilerplates` - List available project templates\n- `use-boilerplate` - Create new project from template\n- `list-scaffolding-methods` - List features for existing project\n- `use-scaffold-method` - Add feature to existing project\n{% endif %}\n{% if architectMcp %}\n\n### architect-mcp\n- `get-file-design-pattern` - Get design patterns for file\n- `review-code-change` - Review code for violations\n{% endif %}\n\n## Workflow Summary\n\n{% if scaffoldMcp %}\n1. **Plan**: Use scaffold-mcp to generate boilerplate + OpenSpec proposal for specs\n{% else %}\n1. **Plan**: Create OpenSpec proposal with specs\n{% endif %}\n{% if architectMcp %}\n{% if scaffoldMcp %}2{% else %}2{% endif %}. **Design**: Use architect-mcp to understand patterns before editing\n{% endif %}\n{% if scaffoldMcp and architectMcp %}3{% elsif scaffoldMcp or architectMcp %}{% if architectMcp %}3{% else %}2{% endif %}{% else %}2{% endif %}. **Implement**: Follow specs{% if architectMcp %} and patterns{% endif %}\n{% if architectMcp %}\n{% if scaffoldMcp %}4{% else %}4{% endif %}. **Review**: Use architect-mcp to validate code quality\n{% endif %}\n{% if scaffoldMcp and architectMcp %}5{% elsif scaffoldMcp or architectMcp %}{% if architectMcp %}5{% else %}3{% endif %}{% else %}3{% endif %}. **Archive**: Merge specs into source of truth\n";
|
|
498
498
|
|
|
499
499
|
//#endregion
|
|
500
500
|
//#region src/specs/openspec.ts
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agiflowai/aicode-toolkit",
|
|
3
3
|
"description": "AI-powered code toolkit CLI for scaffolding, architecture management, and development workflows",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.24",
|
|
5
5
|
"license": "AGPL-3.0",
|
|
6
6
|
"author": "AgiflowIO",
|
|
7
7
|
"repository": {
|
|
@@ -50,8 +50,8 @@
|
|
|
50
50
|
"pino-pretty": "^13.1.1",
|
|
51
51
|
"xstate": "^5.23.0",
|
|
52
52
|
"zod": "3.25.76",
|
|
53
|
-
"@agiflowai/aicode-utils": "1.0.
|
|
54
|
-
"@agiflowai/coding-agent-bridge": "1.0.
|
|
53
|
+
"@agiflowai/aicode-utils": "1.0.18",
|
|
54
|
+
"@agiflowai/coding-agent-bridge": "1.0.21"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"@types/express": "^5.0.0",
|