@agiflowai/aicode-utils 1.0.14 → 1.0.16
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/index.cjs +86 -35
- package/dist/index.d.cts +297 -21
- package/dist/index.d.mts +297 -21
- package/dist/index.mjs +86 -35
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -191,16 +191,41 @@ const log = {
|
|
|
191
191
|
var TemplatesManagerService = class TemplatesManagerService {
|
|
192
192
|
static SCAFFOLD_CONFIG_FILE = "scaffold.yaml";
|
|
193
193
|
static TEMPLATES_FOLDER = "templates";
|
|
194
|
+
static TOOLKIT_FOLDER = ".toolkit";
|
|
195
|
+
static SETTINGS_FILE = "settings.yaml";
|
|
196
|
+
static SETTINGS_LOCAL_FILE = "settings.local.yaml";
|
|
194
197
|
static TOOLKIT_CONFIG_FILE = "toolkit.yaml";
|
|
195
198
|
/**
|
|
199
|
+
* Recursively merge two plain objects. Primitive and array values in `local`
|
|
200
|
+
* replace those in `base`; plain-object values are merged recursively.
|
|
201
|
+
*/
|
|
202
|
+
static deepMerge(base, local) {
|
|
203
|
+
const result = { ...base };
|
|
204
|
+
for (const [key, localValue] of Object.entries(local)) {
|
|
205
|
+
const baseValue = result[key];
|
|
206
|
+
if (localValue !== null && typeof localValue === "object" && !Array.isArray(localValue) && baseValue !== null && typeof baseValue === "object" && !Array.isArray(baseValue)) result[key] = TemplatesManagerService.deepMerge(baseValue, localValue);
|
|
207
|
+
else result[key] = localValue;
|
|
208
|
+
}
|
|
209
|
+
return result;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Deep-merge two ToolkitConfig objects. Plain-object values are merged
|
|
213
|
+
* recursively; primitives and arrays in `local` replace those in `base`.
|
|
214
|
+
* This allows settings.local.yaml to override a single leaf key (e.g.
|
|
215
|
+
* scaffold-mcp.mcp-serve.fallbackTool) without wiping sibling keys.
|
|
216
|
+
*/
|
|
217
|
+
static mergeToolkitConfigs(base, local) {
|
|
218
|
+
return TemplatesManagerService.deepMerge(base, local);
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
196
221
|
* Find the templates directory by searching upwards from the starting path.
|
|
197
222
|
*
|
|
198
223
|
* Algorithm:
|
|
199
224
|
* 1. Start from the provided path (default: current working directory)
|
|
200
225
|
* 2. Search upwards to find the workspace root (where .git exists or filesystem root)
|
|
201
|
-
* 3.
|
|
202
|
-
* - If
|
|
203
|
-
* - If no, default to 'templates' folder in workspace root
|
|
226
|
+
* 3. Read toolkit config (checks .toolkit/settings.yaml, then toolkit.yaml)
|
|
227
|
+
* - If config has templatesPath, use it
|
|
228
|
+
* - If no config, default to 'templates' folder in workspace root
|
|
204
229
|
* 4. Verify the templates directory exists
|
|
205
230
|
*
|
|
206
231
|
* @param startPath - The path to start searching from (defaults to process.cwd())
|
|
@@ -208,16 +233,11 @@ var TemplatesManagerService = class TemplatesManagerService {
|
|
|
208
233
|
*/
|
|
209
234
|
static async findTemplatesPath(startPath = process.cwd()) {
|
|
210
235
|
const workspaceRoot = await TemplatesManagerService.findWorkspaceRoot(startPath);
|
|
211
|
-
const
|
|
212
|
-
if (
|
|
213
|
-
const
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
if (config?.templatesPath) {
|
|
217
|
-
const templatesPath$1 = node_path.default.isAbsolute(config.templatesPath) ? config.templatesPath : node_path.default.join(workspaceRoot, config.templatesPath);
|
|
218
|
-
if (await pathExists(templatesPath$1)) return templatesPath$1;
|
|
219
|
-
else return null;
|
|
220
|
-
}
|
|
236
|
+
const config = await TemplatesManagerService.readToolkitConfig(startPath);
|
|
237
|
+
if (config?.templatesPath) {
|
|
238
|
+
const templatesPath$1 = node_path.default.isAbsolute(config.templatesPath) ? config.templatesPath : node_path.default.join(workspaceRoot, config.templatesPath);
|
|
239
|
+
if (await pathExists(templatesPath$1)) return templatesPath$1;
|
|
240
|
+
return null;
|
|
221
241
|
}
|
|
222
242
|
const templatesPath = node_path.default.join(workspaceRoot, TemplatesManagerService.TEMPLATES_FOLDER);
|
|
223
243
|
if (await pathExists(templatesPath)) return templatesPath;
|
|
@@ -244,16 +264,11 @@ var TemplatesManagerService = class TemplatesManagerService {
|
|
|
244
264
|
*/
|
|
245
265
|
static findTemplatesPathSync(startPath = process.cwd()) {
|
|
246
266
|
const workspaceRoot = TemplatesManagerService.findWorkspaceRootSync(startPath);
|
|
247
|
-
const
|
|
248
|
-
if (
|
|
249
|
-
const
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
if (config?.templatesPath) {
|
|
253
|
-
const templatesPath$1 = node_path.default.isAbsolute(config.templatesPath) ? config.templatesPath : node_path.default.join(workspaceRoot, config.templatesPath);
|
|
254
|
-
if (pathExistsSync(templatesPath$1)) return templatesPath$1;
|
|
255
|
-
else return null;
|
|
256
|
-
}
|
|
267
|
+
const config = TemplatesManagerService.readToolkitConfigSync(startPath);
|
|
268
|
+
if (config?.templatesPath) {
|
|
269
|
+
const templatesPath$1 = node_path.default.isAbsolute(config.templatesPath) ? config.templatesPath : node_path.default.join(workspaceRoot, config.templatesPath);
|
|
270
|
+
if (pathExistsSync(templatesPath$1)) return templatesPath$1;
|
|
271
|
+
return null;
|
|
257
272
|
}
|
|
258
273
|
const templatesPath = node_path.default.join(workspaceRoot, TemplatesManagerService.TEMPLATES_FOLDER);
|
|
259
274
|
if (pathExistsSync(templatesPath)) return templatesPath;
|
|
@@ -294,44 +309,80 @@ var TemplatesManagerService = class TemplatesManagerService {
|
|
|
294
309
|
return TemplatesManagerService.TEMPLATES_FOLDER;
|
|
295
310
|
}
|
|
296
311
|
/**
|
|
297
|
-
* Read toolkit
|
|
312
|
+
* Read toolkit configuration from workspace root.
|
|
313
|
+
*
|
|
314
|
+
* Priority order:
|
|
315
|
+
* 1. .toolkit/settings.yaml (new location)
|
|
316
|
+
* 2. Shallow-merge .toolkit/settings.local.yaml over settings.yaml if present
|
|
317
|
+
* 3. Fallback to root toolkit.yaml (deprecated, backward-compat)
|
|
298
318
|
*
|
|
299
319
|
* @param startPath - The path to start searching from (defaults to process.cwd())
|
|
300
320
|
* @returns The toolkit configuration object or null if not found
|
|
301
321
|
*/
|
|
302
322
|
static async readToolkitConfig(startPath = process.cwd()) {
|
|
303
323
|
const workspaceRoot = await TemplatesManagerService.findWorkspaceRoot(startPath);
|
|
304
|
-
const toolkitConfigPath = node_path.default.join(workspaceRoot, TemplatesManagerService.TOOLKIT_CONFIG_FILE);
|
|
305
|
-
if (!await pathExists(toolkitConfigPath)) return null;
|
|
306
324
|
const yaml = await import("js-yaml");
|
|
307
|
-
const
|
|
325
|
+
const toolkitFolder = node_path.default.join(workspaceRoot, TemplatesManagerService.TOOLKIT_FOLDER);
|
|
326
|
+
const settingsPath = node_path.default.join(toolkitFolder, TemplatesManagerService.SETTINGS_FILE);
|
|
327
|
+
const settingsLocalPath = node_path.default.join(toolkitFolder, TemplatesManagerService.SETTINGS_LOCAL_FILE);
|
|
328
|
+
if (await pathExists(settingsPath)) {
|
|
329
|
+
const baseContent = await node_fs_promises.readFile(settingsPath, "utf-8");
|
|
330
|
+
const base = yaml.load(baseContent);
|
|
331
|
+
if (await pathExists(settingsLocalPath)) {
|
|
332
|
+
const localContent = await node_fs_promises.readFile(settingsLocalPath, "utf-8");
|
|
333
|
+
const local = yaml.load(localContent);
|
|
334
|
+
return TemplatesManagerService.mergeToolkitConfigs(base, local);
|
|
335
|
+
}
|
|
336
|
+
return base;
|
|
337
|
+
}
|
|
338
|
+
const legacyConfigPath = node_path.default.join(workspaceRoot, TemplatesManagerService.TOOLKIT_CONFIG_FILE);
|
|
339
|
+
if (!await pathExists(legacyConfigPath)) return null;
|
|
340
|
+
const content = await node_fs_promises.readFile(legacyConfigPath, "utf-8");
|
|
308
341
|
return yaml.load(content);
|
|
309
342
|
}
|
|
310
343
|
/**
|
|
311
|
-
* Read toolkit
|
|
344
|
+
* Read toolkit configuration from workspace root (sync).
|
|
345
|
+
*
|
|
346
|
+
* Priority order:
|
|
347
|
+
* 1. .toolkit/settings.yaml (new location)
|
|
348
|
+
* 2. Shallow-merge .toolkit/settings.local.yaml over settings.yaml if present
|
|
349
|
+
* 3. Fallback to root toolkit.yaml (deprecated, backward-compat)
|
|
312
350
|
*
|
|
313
351
|
* @param startPath - The path to start searching from (defaults to process.cwd())
|
|
314
352
|
* @returns The toolkit configuration object or null if not found
|
|
315
353
|
*/
|
|
316
354
|
static readToolkitConfigSync(startPath = process.cwd()) {
|
|
317
355
|
const workspaceRoot = TemplatesManagerService.findWorkspaceRootSync(startPath);
|
|
318
|
-
const toolkitConfigPath = node_path.default.join(workspaceRoot, TemplatesManagerService.TOOLKIT_CONFIG_FILE);
|
|
319
|
-
if (!pathExistsSync(toolkitConfigPath)) return null;
|
|
320
356
|
const yaml = require("js-yaml");
|
|
321
|
-
const
|
|
322
|
-
|
|
357
|
+
const toolkitFolder = node_path.default.join(workspaceRoot, TemplatesManagerService.TOOLKIT_FOLDER);
|
|
358
|
+
const settingsPath = node_path.default.join(toolkitFolder, TemplatesManagerService.SETTINGS_FILE);
|
|
359
|
+
const settingsLocalPath = node_path.default.join(toolkitFolder, TemplatesManagerService.SETTINGS_LOCAL_FILE);
|
|
360
|
+
if (pathExistsSync(settingsPath)) {
|
|
361
|
+
const base = yaml.load((0, node_fs.readFileSync)(settingsPath, "utf-8"));
|
|
362
|
+
if (pathExistsSync(settingsLocalPath)) {
|
|
363
|
+
const local = yaml.load((0, node_fs.readFileSync)(settingsLocalPath, "utf-8"));
|
|
364
|
+
return TemplatesManagerService.mergeToolkitConfigs(base, local);
|
|
365
|
+
}
|
|
366
|
+
return base;
|
|
367
|
+
}
|
|
368
|
+
const legacyConfigPath = node_path.default.join(workspaceRoot, TemplatesManagerService.TOOLKIT_CONFIG_FILE);
|
|
369
|
+
if (!pathExistsSync(legacyConfigPath)) return null;
|
|
370
|
+
return yaml.load((0, node_fs.readFileSync)(legacyConfigPath, "utf-8"));
|
|
323
371
|
}
|
|
324
372
|
/**
|
|
325
|
-
* Write toolkit
|
|
373
|
+
* Write toolkit configuration to .toolkit/settings.yaml.
|
|
374
|
+
* Creates the .toolkit directory if it does not exist.
|
|
326
375
|
*
|
|
327
376
|
* @param config - The toolkit configuration to write
|
|
328
377
|
* @param startPath - The path to start searching from (defaults to process.cwd())
|
|
329
378
|
*/
|
|
330
379
|
static async writeToolkitConfig(config, startPath = process.cwd()) {
|
|
331
380
|
const workspaceRoot = await TemplatesManagerService.findWorkspaceRoot(startPath);
|
|
332
|
-
const
|
|
381
|
+
const toolkitFolder = node_path.default.join(workspaceRoot, TemplatesManagerService.TOOLKIT_FOLDER);
|
|
382
|
+
const settingsPath = node_path.default.join(toolkitFolder, TemplatesManagerService.SETTINGS_FILE);
|
|
383
|
+
await node_fs_promises.mkdir(toolkitFolder, { recursive: true });
|
|
333
384
|
const content = (await import("js-yaml")).dump(config, { indent: 2 });
|
|
334
|
-
await node_fs_promises.writeFile(
|
|
385
|
+
await node_fs_promises.writeFile(settingsPath, content, "utf-8");
|
|
335
386
|
}
|
|
336
387
|
/**
|
|
337
388
|
* Get the workspace root directory
|
package/dist/index.d.cts
CHANGED
|
@@ -47,82 +47,332 @@ interface NxProjectJson {
|
|
|
47
47
|
//#region src/types/index.d.ts
|
|
48
48
|
|
|
49
49
|
/**
|
|
50
|
-
*
|
|
50
|
+
* Configuration for the scaffold-mcp mcp-serve command.
|
|
51
|
+
* Keys map 1-to-1 with CLI flags (camelCase).
|
|
52
|
+
*/
|
|
53
|
+
interface McpServeConfig {
|
|
54
|
+
/** Transport type. Default: stdio. */
|
|
55
|
+
type?: 'stdio' | 'http' | 'sse';
|
|
56
|
+
/** Port for http/sse transport. Default: 3000. */
|
|
57
|
+
port?: number;
|
|
58
|
+
/** Host to bind for http/sse transport. Default: localhost. */
|
|
59
|
+
host?: string;
|
|
60
|
+
/** Enable admin tools such as generate-boilerplate. Default: false. */
|
|
61
|
+
adminEnable?: boolean;
|
|
62
|
+
/** Render prompts with skill front matter for Claude Code. Default: false. */
|
|
63
|
+
promptAsSkill?: boolean;
|
|
64
|
+
/** Fallback LLM tool used when scaffold-mcp needs AI assistance. */
|
|
65
|
+
fallbackTool?: string;
|
|
66
|
+
/** Config passed to the fallback LLM tool. */
|
|
67
|
+
fallbackToolConfig?: Record<string, unknown>;
|
|
68
|
+
/** Extra CLI args merged into the mcp-serve command (key → --key value). */
|
|
69
|
+
args?: Record<string, string | boolean | number>;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Configuration for a single hook method invocation.
|
|
73
|
+
* Keys use kebab-case matching the adapter/CLI convention.
|
|
74
|
+
*/
|
|
75
|
+
interface HookMethodConfig {
|
|
76
|
+
/** LLM tool to invoke for this hook method (e.g. claude-code, gemini-cli). */
|
|
77
|
+
'llm-tool'?: string;
|
|
78
|
+
/** Config object forwarded to the LLM tool (e.g. { model: 'gemini-2.0-flash' }). */
|
|
79
|
+
'tool-config'?: Record<string, unknown>;
|
|
80
|
+
/** Fallback LLM tool used when the primary tool is unavailable. */
|
|
81
|
+
'fallback-tool'?: string;
|
|
82
|
+
/** Config object forwarded to the fallback LLM tool. */
|
|
83
|
+
'fallback-tool-config'?: Record<string, unknown>;
|
|
84
|
+
/** Extra CLI args appended to the generated hook command (key → --key value). */
|
|
85
|
+
args?: Record<string, string | boolean | number>;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Per-method configuration for a specific agent.
|
|
89
|
+
*/
|
|
90
|
+
interface HookAgentConfig {
|
|
91
|
+
/** Config applied when the agent invokes the PreToolUse hook. */
|
|
92
|
+
preToolUse?: HookMethodConfig;
|
|
93
|
+
/** Config applied when the agent invokes the PostToolUse hook. */
|
|
94
|
+
postToolUse?: HookMethodConfig;
|
|
95
|
+
/** Config applied when the agent invokes the Stop hook. */
|
|
96
|
+
stop?: HookMethodConfig;
|
|
97
|
+
/** Config applied when the agent invokes the UserPromptSubmit hook. */
|
|
98
|
+
userPromptSubmit?: HookMethodConfig;
|
|
99
|
+
/** Config applied when the agent invokes the TaskCompleted hook. */
|
|
100
|
+
taskCompleted?: HookMethodConfig;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Hook configuration keyed by agent name.
|
|
104
|
+
*/
|
|
105
|
+
interface HookConfig {
|
|
106
|
+
/** Hook config for Claude Code agent. */
|
|
107
|
+
'claude-code'?: HookAgentConfig;
|
|
108
|
+
/** Hook config for Gemini CLI agent. */
|
|
109
|
+
'gemini-cli'?: HookAgentConfig;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Top-level scaffold-mcp configuration block.
|
|
113
|
+
*/
|
|
114
|
+
interface ScaffoldMcpConfig {
|
|
115
|
+
/** Defaults for the `scaffold-mcp mcp-serve` command. */
|
|
116
|
+
'mcp-serve'?: McpServeConfig;
|
|
117
|
+
/** Hook method defaults keyed by agent name. */
|
|
118
|
+
hook?: HookConfig;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Configuration for the architect-mcp mcp-serve command.
|
|
122
|
+
* Keys map 1-to-1 with CLI flags (camelCase).
|
|
123
|
+
*/
|
|
124
|
+
interface ArchitectMcpServeConfig {
|
|
125
|
+
/** Transport type. Default: stdio. */
|
|
126
|
+
type?: 'stdio' | 'http' | 'sse';
|
|
127
|
+
/** Port for http/sse transport. Default: 3000. */
|
|
128
|
+
port?: number;
|
|
129
|
+
/** Host to bind for http/sse transport. Default: localhost. */
|
|
130
|
+
host?: string;
|
|
131
|
+
/** Enable admin tools such as add-design-pattern and add-rule. Default: false. */
|
|
132
|
+
adminEnable?: boolean;
|
|
133
|
+
/** Fallback LLM tool used for both design-pattern and review operations. */
|
|
134
|
+
fallbackTool?: string;
|
|
135
|
+
/** Config passed to the fallback LLM tool. */
|
|
136
|
+
fallbackToolConfig?: Record<string, unknown>;
|
|
137
|
+
/** LLM tool used specifically for get-file-design-pattern analysis. */
|
|
138
|
+
designPatternTool?: string;
|
|
139
|
+
/** Config passed to the design-pattern LLM tool. */
|
|
140
|
+
designPatternToolConfig?: Record<string, unknown>;
|
|
141
|
+
/** LLM tool used specifically for review-code-change analysis. */
|
|
142
|
+
reviewTool?: string;
|
|
143
|
+
/** Config passed to the review LLM tool. */
|
|
144
|
+
reviewToolConfig?: Record<string, unknown>;
|
|
145
|
+
/** Extra CLI args merged into the mcp-serve command (key → --key value). */
|
|
146
|
+
args?: Record<string, string | boolean | number>;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Configuration for a single architect-mcp hook method invocation.
|
|
150
|
+
* Keys use kebab-case matching the adapter/CLI convention.
|
|
151
|
+
*/
|
|
152
|
+
interface ArchitectHookMethodConfig {
|
|
153
|
+
/** LLM tool to invoke for this hook method. */
|
|
154
|
+
'llm-tool'?: string;
|
|
155
|
+
/** Config object forwarded to the LLM tool. */
|
|
156
|
+
'tool-config'?: Record<string, unknown>;
|
|
157
|
+
/** Extra CLI args appended to the generated hook command (key → --key value). */
|
|
158
|
+
args?: Record<string, string | boolean | number>;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Per-method configuration for a specific agent (architect-mcp).
|
|
162
|
+
* Only preToolUse and postToolUse are supported.
|
|
163
|
+
*/
|
|
164
|
+
interface ArchitectHookAgentConfig {
|
|
165
|
+
/** Config applied when the agent invokes the PreToolUse hook. */
|
|
166
|
+
preToolUse?: ArchitectHookMethodConfig;
|
|
167
|
+
/** Config applied when the agent invokes the PostToolUse hook. */
|
|
168
|
+
postToolUse?: ArchitectHookMethodConfig;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Hook configuration keyed by agent name (architect-mcp).
|
|
172
|
+
*/
|
|
173
|
+
interface ArchitectHookConfig {
|
|
174
|
+
/** Hook config for Claude Code agent. */
|
|
175
|
+
'claude-code'?: ArchitectHookAgentConfig;
|
|
176
|
+
/** Hook config for Gemini CLI agent. */
|
|
177
|
+
'gemini-cli'?: ArchitectHookAgentConfig;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Top-level architect-mcp configuration block.
|
|
181
|
+
*/
|
|
182
|
+
interface ArchitectMcpConfig {
|
|
183
|
+
/** Defaults for the `architect-mcp mcp-serve` command. */
|
|
184
|
+
'mcp-serve'?: ArchitectMcpServeConfig;
|
|
185
|
+
/** Hook method defaults keyed by agent name. */
|
|
186
|
+
hook?: ArchitectHookConfig;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Toolkit configuration from .toolkit/settings.yaml (or legacy toolkit.yaml)
|
|
51
190
|
*/
|
|
52
191
|
interface ToolkitConfig {
|
|
192
|
+
/** Config schema version (e.g. '1.0'). */
|
|
53
193
|
version?: string;
|
|
194
|
+
/** Path to the scaffold templates directory, relative to workspace root. */
|
|
54
195
|
templatesPath?: string;
|
|
196
|
+
/** Project structure type: monolith (single app) or monorepo (multiple packages). */
|
|
55
197
|
projectType?: 'monolith' | 'monorepo';
|
|
198
|
+
/** Active template name (monolith only — monorepo reads from project.json). */
|
|
56
199
|
sourceTemplate?: string;
|
|
200
|
+
/** scaffold-mcp server and hook configuration. */
|
|
201
|
+
'scaffold-mcp'?: ScaffoldMcpConfig;
|
|
202
|
+
/** architect-mcp server and hook configuration. */
|
|
203
|
+
'architect-mcp'?: ArchitectMcpConfig;
|
|
57
204
|
}
|
|
58
205
|
/**
|
|
59
206
|
* Project configuration from project.json
|
|
60
207
|
*/
|
|
61
208
|
interface ProjectConfig {
|
|
209
|
+
/** Package/project name as declared in project.json. */
|
|
62
210
|
name: string;
|
|
211
|
+
/** Root directory of the project, relative to workspace root. */
|
|
63
212
|
root: string;
|
|
213
|
+
/** Template this project was scaffolded from. */
|
|
64
214
|
sourceTemplate?: string;
|
|
215
|
+
/** Project type as declared in project.json (e.g. 'application' or 'library'). */
|
|
65
216
|
projectType?: string;
|
|
66
217
|
}
|
|
67
218
|
/**
|
|
68
219
|
* Scaffold template include configuration
|
|
69
220
|
*/
|
|
70
221
|
interface ParsedInclude {
|
|
222
|
+
/** Absolute path of the source template file. */
|
|
71
223
|
sourcePath: string;
|
|
224
|
+
/** Absolute path of the destination file in the target directory. */
|
|
72
225
|
targetPath: string;
|
|
226
|
+
/** Conditions that must be satisfied for this include to be applied. */
|
|
73
227
|
conditions?: Record<string, string>;
|
|
74
228
|
}
|
|
75
229
|
/**
|
|
76
230
|
* Result of a scaffold operation
|
|
77
231
|
*/
|
|
78
232
|
interface ScaffoldResult {
|
|
233
|
+
/** Whether the scaffold operation completed without errors. */
|
|
79
234
|
success: boolean;
|
|
235
|
+
/** Human-readable summary of the operation outcome. */
|
|
80
236
|
message: string;
|
|
237
|
+
/** Non-fatal warnings collected during the operation. */
|
|
81
238
|
warnings?: string[];
|
|
239
|
+
/** Paths of files that were newly created. */
|
|
82
240
|
createdFiles?: string[];
|
|
241
|
+
/** Paths of files that already existed and were not overwritten. */
|
|
83
242
|
existingFiles?: string[];
|
|
84
243
|
}
|
|
244
|
+
/**
|
|
245
|
+
* Minimal stat result returned by IFileSystemService.stat.
|
|
246
|
+
*/
|
|
247
|
+
interface FileStat {
|
|
248
|
+
/**
|
|
249
|
+
* @returns True when the path is a directory.
|
|
250
|
+
*/
|
|
251
|
+
isDirectory(): boolean;
|
|
252
|
+
/**
|
|
253
|
+
* @returns True when the path is a regular file.
|
|
254
|
+
*/
|
|
255
|
+
isFile(): boolean;
|
|
256
|
+
}
|
|
85
257
|
/**
|
|
86
258
|
* Abstract interface for file system operations
|
|
87
259
|
*/
|
|
88
260
|
interface IFileSystemService {
|
|
261
|
+
/**
|
|
262
|
+
* Check whether a path exists on disk.
|
|
263
|
+
* @param path - Absolute path to check.
|
|
264
|
+
* @returns True when the path exists.
|
|
265
|
+
*/
|
|
89
266
|
pathExists(path: string): Promise<boolean>;
|
|
267
|
+
/**
|
|
268
|
+
* Read a file as text.
|
|
269
|
+
* @param path - Absolute path of the file.
|
|
270
|
+
* @param encoding - Character encoding (default: utf-8).
|
|
271
|
+
* @returns File contents as a string.
|
|
272
|
+
*/
|
|
90
273
|
readFile(path: string, encoding?: BufferEncoding): Promise<string>;
|
|
91
|
-
|
|
274
|
+
/**
|
|
275
|
+
* Read and parse a JSON file. Returns unknown — callers must narrow the type.
|
|
276
|
+
* @param path - Absolute path of the JSON file.
|
|
277
|
+
* @returns Parsed value with type unknown.
|
|
278
|
+
*/
|
|
279
|
+
readJson(path: string): Promise<unknown>;
|
|
280
|
+
/**
|
|
281
|
+
* Write text content to a file.
|
|
282
|
+
* @param path - Absolute path of the target file.
|
|
283
|
+
* @param content - Text to write.
|
|
284
|
+
* @param encoding - Character encoding (default: utf-8).
|
|
285
|
+
* @returns Promise that resolves when the file is written.
|
|
286
|
+
*/
|
|
92
287
|
writeFile(path: string, content: string, encoding?: BufferEncoding): Promise<void>;
|
|
288
|
+
/**
|
|
289
|
+
* Create a directory and all parent directories.
|
|
290
|
+
* @param path - Absolute path of the directory to create.
|
|
291
|
+
* @returns Promise that resolves when the directory exists.
|
|
292
|
+
*/
|
|
93
293
|
ensureDir(path: string): Promise<void>;
|
|
294
|
+
/**
|
|
295
|
+
* Copy a file or directory from src to dest.
|
|
296
|
+
* @param src - Absolute source path.
|
|
297
|
+
* @param dest - Absolute destination path.
|
|
298
|
+
* @returns Promise that resolves when the copy is complete.
|
|
299
|
+
*/
|
|
94
300
|
copy(src: string, dest: string): Promise<void>;
|
|
301
|
+
/**
|
|
302
|
+
* List the entries of a directory.
|
|
303
|
+
* @param path - Absolute path of the directory.
|
|
304
|
+
* @returns Array of entry names (not full paths).
|
|
305
|
+
*/
|
|
95
306
|
readdir(path: string): Promise<string[]>;
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
307
|
+
/**
|
|
308
|
+
* Return stat info for a path.
|
|
309
|
+
* @param path - Absolute path to stat.
|
|
310
|
+
* @returns FileStat with isDirectory and isFile helpers.
|
|
311
|
+
*/
|
|
312
|
+
stat(path: string): Promise<FileStat>;
|
|
100
313
|
}
|
|
101
314
|
/**
|
|
102
315
|
* Abstract interface for variable replacement in templates
|
|
103
316
|
*/
|
|
104
317
|
interface IVariableReplacementService {
|
|
105
|
-
|
|
106
|
-
|
|
318
|
+
/**
|
|
319
|
+
* Walk dirPath and apply variable substitution to every non-binary file.
|
|
320
|
+
* @param dirPath - Directory to process recursively.
|
|
321
|
+
* @param variables - Key/value pairs used for substitution.
|
|
322
|
+
* @returns Promise that resolves when all files have been processed.
|
|
323
|
+
*/
|
|
324
|
+
processFilesForVariableReplacement(dirPath: string, variables: Record<string, unknown>): Promise<void>;
|
|
325
|
+
/**
|
|
326
|
+
* Apply variable substitution to a single file.
|
|
327
|
+
* @param filePath - File to process.
|
|
328
|
+
* @param variables - Key/value pairs used for substitution.
|
|
329
|
+
* @returns Promise that resolves when the file has been processed.
|
|
330
|
+
*/
|
|
331
|
+
replaceVariablesInFile(filePath: string, variables: Record<string, unknown>): Promise<void>;
|
|
332
|
+
/**
|
|
333
|
+
* Checks if a file should be treated as a binary (non-text) file.
|
|
334
|
+
* @param filePath - Path to check.
|
|
335
|
+
* @returns True if the file is binary.
|
|
336
|
+
*/
|
|
107
337
|
isBinaryFile(filePath: string): boolean;
|
|
108
338
|
}
|
|
109
339
|
/**
|
|
110
|
-
* Context object passed to generator functions
|
|
340
|
+
* Context object passed to generator functions.
|
|
341
|
+
* Bundles all dependencies needed to produce scaffold output.
|
|
111
342
|
*/
|
|
112
343
|
interface GeneratorContext {
|
|
113
|
-
variables
|
|
114
|
-
|
|
344
|
+
/** Template variables resolved for the current scaffold operation. */
|
|
345
|
+
variables: Record<string, unknown>;
|
|
346
|
+
/** Raw scaffold configuration loaded from scaffold.yaml. */
|
|
347
|
+
config: unknown;
|
|
348
|
+
/** Absolute path of the directory where output files will be written. */
|
|
115
349
|
targetPath: string;
|
|
350
|
+
/** Absolute path of the source template directory. */
|
|
116
351
|
templatePath: string;
|
|
352
|
+
/** File-system abstraction used for all I/O inside generators. */
|
|
117
353
|
fileSystem: IFileSystemService;
|
|
118
|
-
|
|
354
|
+
/** Loader for scaffold config files — typed as unknown to avoid circular deps. */
|
|
355
|
+
scaffoldConfigLoader: unknown;
|
|
356
|
+
/** Variable-replacement service injected to avoid circular imports. */
|
|
119
357
|
variableReplacer: IVariableReplacementService;
|
|
120
|
-
ScaffoldProcessingService
|
|
358
|
+
/** ScaffoldProcessingService constructor — passed to avoid circular imports. */
|
|
359
|
+
ScaffoldProcessingService: new (...args: unknown[]) => unknown;
|
|
360
|
+
/**
|
|
361
|
+
* Return the workspace root path.
|
|
362
|
+
* @returns Absolute path of the workspace root.
|
|
363
|
+
*/
|
|
121
364
|
getRootPath: () => string;
|
|
365
|
+
/**
|
|
366
|
+
* Return the absolute path of a project relative to the workspace root.
|
|
367
|
+
* @param projectPath - Project path relative to the workspace root.
|
|
368
|
+
* @returns Absolute path of the project.
|
|
369
|
+
*/
|
|
122
370
|
getProjectPath: (projectPath: string) => string;
|
|
123
371
|
}
|
|
124
372
|
/**
|
|
125
|
-
* Type definition for generator functions
|
|
373
|
+
* Type definition for generator functions.
|
|
374
|
+
* @param context - The generator context bundling all scaffold dependencies.
|
|
375
|
+
* @returns A promise resolving to the scaffold result.
|
|
126
376
|
*/
|
|
127
377
|
type GeneratorFunction = (context: GeneratorContext) => Promise<ScaffoldResult>;
|
|
128
378
|
//#endregion
|
|
@@ -254,16 +504,31 @@ declare class ScaffoldProcessingService {
|
|
|
254
504
|
declare class TemplatesManagerService {
|
|
255
505
|
private static SCAFFOLD_CONFIG_FILE;
|
|
256
506
|
private static TEMPLATES_FOLDER;
|
|
507
|
+
private static TOOLKIT_FOLDER;
|
|
508
|
+
private static SETTINGS_FILE;
|
|
509
|
+
private static SETTINGS_LOCAL_FILE;
|
|
257
510
|
private static TOOLKIT_CONFIG_FILE;
|
|
511
|
+
/**
|
|
512
|
+
* Recursively merge two plain objects. Primitive and array values in `local`
|
|
513
|
+
* replace those in `base`; plain-object values are merged recursively.
|
|
514
|
+
*/
|
|
515
|
+
private static deepMerge;
|
|
516
|
+
/**
|
|
517
|
+
* Deep-merge two ToolkitConfig objects. Plain-object values are merged
|
|
518
|
+
* recursively; primitives and arrays in `local` replace those in `base`.
|
|
519
|
+
* This allows settings.local.yaml to override a single leaf key (e.g.
|
|
520
|
+
* scaffold-mcp.mcp-serve.fallbackTool) without wiping sibling keys.
|
|
521
|
+
*/
|
|
522
|
+
private static mergeToolkitConfigs;
|
|
258
523
|
/**
|
|
259
524
|
* Find the templates directory by searching upwards from the starting path.
|
|
260
525
|
*
|
|
261
526
|
* Algorithm:
|
|
262
527
|
* 1. Start from the provided path (default: current working directory)
|
|
263
528
|
* 2. Search upwards to find the workspace root (where .git exists or filesystem root)
|
|
264
|
-
* 3.
|
|
265
|
-
* - If
|
|
266
|
-
* - If no, default to 'templates' folder in workspace root
|
|
529
|
+
* 3. Read toolkit config (checks .toolkit/settings.yaml, then toolkit.yaml)
|
|
530
|
+
* - If config has templatesPath, use it
|
|
531
|
+
* - If no config, default to 'templates' folder in workspace root
|
|
267
532
|
* 4. Verify the templates directory exists
|
|
268
533
|
*
|
|
269
534
|
* @param startPath - The path to start searching from (defaults to process.cwd())
|
|
@@ -302,21 +567,32 @@ declare class TemplatesManagerService {
|
|
|
302
567
|
*/
|
|
303
568
|
static getTemplatesFolderName(): string;
|
|
304
569
|
/**
|
|
305
|
-
* Read toolkit
|
|
570
|
+
* Read toolkit configuration from workspace root.
|
|
571
|
+
*
|
|
572
|
+
* Priority order:
|
|
573
|
+
* 1. .toolkit/settings.yaml (new location)
|
|
574
|
+
* 2. Shallow-merge .toolkit/settings.local.yaml over settings.yaml if present
|
|
575
|
+
* 3. Fallback to root toolkit.yaml (deprecated, backward-compat)
|
|
306
576
|
*
|
|
307
577
|
* @param startPath - The path to start searching from (defaults to process.cwd())
|
|
308
578
|
* @returns The toolkit configuration object or null if not found
|
|
309
579
|
*/
|
|
310
580
|
static readToolkitConfig(startPath?: string): Promise<ToolkitConfig | null>;
|
|
311
581
|
/**
|
|
312
|
-
* Read toolkit
|
|
582
|
+
* Read toolkit configuration from workspace root (sync).
|
|
583
|
+
*
|
|
584
|
+
* Priority order:
|
|
585
|
+
* 1. .toolkit/settings.yaml (new location)
|
|
586
|
+
* 2. Shallow-merge .toolkit/settings.local.yaml over settings.yaml if present
|
|
587
|
+
* 3. Fallback to root toolkit.yaml (deprecated, backward-compat)
|
|
313
588
|
*
|
|
314
589
|
* @param startPath - The path to start searching from (defaults to process.cwd())
|
|
315
590
|
* @returns The toolkit configuration object or null if not found
|
|
316
591
|
*/
|
|
317
592
|
static readToolkitConfigSync(startPath?: string): ToolkitConfig | null;
|
|
318
593
|
/**
|
|
319
|
-
* Write toolkit
|
|
594
|
+
* Write toolkit configuration to .toolkit/settings.yaml.
|
|
595
|
+
* Creates the .toolkit directory if it does not exist.
|
|
320
596
|
*
|
|
321
597
|
* @param config - The toolkit configuration to write
|
|
322
598
|
* @param startPath - The path to start searching from (defaults to process.cwd())
|
|
@@ -680,4 +956,4 @@ interface ProjectTypeDetectionResult {
|
|
|
680
956
|
*/
|
|
681
957
|
declare function detectProjectType(workspaceRoot: string): Promise<ProjectTypeDetectionResult>;
|
|
682
958
|
//#endregion
|
|
683
|
-
export { ConfigSource, GeneratorContext, GeneratorFunction, GitHubDirectoryEntry, IFileSystemService, IVariableReplacementService, NxProjectJson, ParsedGitHubUrl, ParsedInclude, ProjectConfig, ProjectConfigResolver, ProjectConfigResult, ProjectFinderService, ProjectType, ScaffoldProcessingService, ScaffoldResult, TemplatesManagerService, ToolkitConfig, accessSync, cloneRepository, cloneSubdirectory, copy, detectProjectType, ensureDir, fetchGitHubDirectoryContents, findWorkspaceRoot, generateStableId, gitInit, icons, log, logger, messages, mkdir, mkdirSync, move, parseGitHubUrl, pathExists, pathExistsSync, print, readFile, readFileSync, readJson, readJsonSync, readdir, remove, sections, stat, statSync, writeFile, writeFileSync };
|
|
959
|
+
export { ArchitectHookAgentConfig, ArchitectHookConfig, ArchitectHookMethodConfig, ArchitectMcpConfig, ArchitectMcpServeConfig, ConfigSource, FileStat, GeneratorContext, GeneratorFunction, GitHubDirectoryEntry, HookAgentConfig, HookConfig, HookMethodConfig, IFileSystemService, IVariableReplacementService, McpServeConfig, type NxProjectJson, ParsedGitHubUrl, ParsedInclude, ProjectConfig, ProjectConfigResolver, type ProjectConfigResult, ProjectFinderService, ProjectType, ScaffoldMcpConfig, ScaffoldProcessingService, ScaffoldResult, TemplatesManagerService, ToolkitConfig, accessSync, cloneRepository, cloneSubdirectory, copy, detectProjectType, ensureDir, fetchGitHubDirectoryContents, findWorkspaceRoot, generateStableId, gitInit, icons, log, logger, messages, mkdir, mkdirSync, move, parseGitHubUrl, pathExists, pathExistsSync, print, readFile, readFileSync, readJson, readJsonSync, readdir, remove, sections, stat, statSync, writeFile, writeFileSync };
|
package/dist/index.d.mts
CHANGED
|
@@ -47,82 +47,332 @@ interface NxProjectJson {
|
|
|
47
47
|
//#region src/types/index.d.ts
|
|
48
48
|
|
|
49
49
|
/**
|
|
50
|
-
*
|
|
50
|
+
* Configuration for the scaffold-mcp mcp-serve command.
|
|
51
|
+
* Keys map 1-to-1 with CLI flags (camelCase).
|
|
52
|
+
*/
|
|
53
|
+
interface McpServeConfig {
|
|
54
|
+
/** Transport type. Default: stdio. */
|
|
55
|
+
type?: 'stdio' | 'http' | 'sse';
|
|
56
|
+
/** Port for http/sse transport. Default: 3000. */
|
|
57
|
+
port?: number;
|
|
58
|
+
/** Host to bind for http/sse transport. Default: localhost. */
|
|
59
|
+
host?: string;
|
|
60
|
+
/** Enable admin tools such as generate-boilerplate. Default: false. */
|
|
61
|
+
adminEnable?: boolean;
|
|
62
|
+
/** Render prompts with skill front matter for Claude Code. Default: false. */
|
|
63
|
+
promptAsSkill?: boolean;
|
|
64
|
+
/** Fallback LLM tool used when scaffold-mcp needs AI assistance. */
|
|
65
|
+
fallbackTool?: string;
|
|
66
|
+
/** Config passed to the fallback LLM tool. */
|
|
67
|
+
fallbackToolConfig?: Record<string, unknown>;
|
|
68
|
+
/** Extra CLI args merged into the mcp-serve command (key → --key value). */
|
|
69
|
+
args?: Record<string, string | boolean | number>;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Configuration for a single hook method invocation.
|
|
73
|
+
* Keys use kebab-case matching the adapter/CLI convention.
|
|
74
|
+
*/
|
|
75
|
+
interface HookMethodConfig {
|
|
76
|
+
/** LLM tool to invoke for this hook method (e.g. claude-code, gemini-cli). */
|
|
77
|
+
'llm-tool'?: string;
|
|
78
|
+
/** Config object forwarded to the LLM tool (e.g. { model: 'gemini-2.0-flash' }). */
|
|
79
|
+
'tool-config'?: Record<string, unknown>;
|
|
80
|
+
/** Fallback LLM tool used when the primary tool is unavailable. */
|
|
81
|
+
'fallback-tool'?: string;
|
|
82
|
+
/** Config object forwarded to the fallback LLM tool. */
|
|
83
|
+
'fallback-tool-config'?: Record<string, unknown>;
|
|
84
|
+
/** Extra CLI args appended to the generated hook command (key → --key value). */
|
|
85
|
+
args?: Record<string, string | boolean | number>;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Per-method configuration for a specific agent.
|
|
89
|
+
*/
|
|
90
|
+
interface HookAgentConfig {
|
|
91
|
+
/** Config applied when the agent invokes the PreToolUse hook. */
|
|
92
|
+
preToolUse?: HookMethodConfig;
|
|
93
|
+
/** Config applied when the agent invokes the PostToolUse hook. */
|
|
94
|
+
postToolUse?: HookMethodConfig;
|
|
95
|
+
/** Config applied when the agent invokes the Stop hook. */
|
|
96
|
+
stop?: HookMethodConfig;
|
|
97
|
+
/** Config applied when the agent invokes the UserPromptSubmit hook. */
|
|
98
|
+
userPromptSubmit?: HookMethodConfig;
|
|
99
|
+
/** Config applied when the agent invokes the TaskCompleted hook. */
|
|
100
|
+
taskCompleted?: HookMethodConfig;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Hook configuration keyed by agent name.
|
|
104
|
+
*/
|
|
105
|
+
interface HookConfig {
|
|
106
|
+
/** Hook config for Claude Code agent. */
|
|
107
|
+
'claude-code'?: HookAgentConfig;
|
|
108
|
+
/** Hook config for Gemini CLI agent. */
|
|
109
|
+
'gemini-cli'?: HookAgentConfig;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Top-level scaffold-mcp configuration block.
|
|
113
|
+
*/
|
|
114
|
+
interface ScaffoldMcpConfig {
|
|
115
|
+
/** Defaults for the `scaffold-mcp mcp-serve` command. */
|
|
116
|
+
'mcp-serve'?: McpServeConfig;
|
|
117
|
+
/** Hook method defaults keyed by agent name. */
|
|
118
|
+
hook?: HookConfig;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Configuration for the architect-mcp mcp-serve command.
|
|
122
|
+
* Keys map 1-to-1 with CLI flags (camelCase).
|
|
123
|
+
*/
|
|
124
|
+
interface ArchitectMcpServeConfig {
|
|
125
|
+
/** Transport type. Default: stdio. */
|
|
126
|
+
type?: 'stdio' | 'http' | 'sse';
|
|
127
|
+
/** Port for http/sse transport. Default: 3000. */
|
|
128
|
+
port?: number;
|
|
129
|
+
/** Host to bind for http/sse transport. Default: localhost. */
|
|
130
|
+
host?: string;
|
|
131
|
+
/** Enable admin tools such as add-design-pattern and add-rule. Default: false. */
|
|
132
|
+
adminEnable?: boolean;
|
|
133
|
+
/** Fallback LLM tool used for both design-pattern and review operations. */
|
|
134
|
+
fallbackTool?: string;
|
|
135
|
+
/** Config passed to the fallback LLM tool. */
|
|
136
|
+
fallbackToolConfig?: Record<string, unknown>;
|
|
137
|
+
/** LLM tool used specifically for get-file-design-pattern analysis. */
|
|
138
|
+
designPatternTool?: string;
|
|
139
|
+
/** Config passed to the design-pattern LLM tool. */
|
|
140
|
+
designPatternToolConfig?: Record<string, unknown>;
|
|
141
|
+
/** LLM tool used specifically for review-code-change analysis. */
|
|
142
|
+
reviewTool?: string;
|
|
143
|
+
/** Config passed to the review LLM tool. */
|
|
144
|
+
reviewToolConfig?: Record<string, unknown>;
|
|
145
|
+
/** Extra CLI args merged into the mcp-serve command (key → --key value). */
|
|
146
|
+
args?: Record<string, string | boolean | number>;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Configuration for a single architect-mcp hook method invocation.
|
|
150
|
+
* Keys use kebab-case matching the adapter/CLI convention.
|
|
151
|
+
*/
|
|
152
|
+
interface ArchitectHookMethodConfig {
|
|
153
|
+
/** LLM tool to invoke for this hook method. */
|
|
154
|
+
'llm-tool'?: string;
|
|
155
|
+
/** Config object forwarded to the LLM tool. */
|
|
156
|
+
'tool-config'?: Record<string, unknown>;
|
|
157
|
+
/** Extra CLI args appended to the generated hook command (key → --key value). */
|
|
158
|
+
args?: Record<string, string | boolean | number>;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Per-method configuration for a specific agent (architect-mcp).
|
|
162
|
+
* Only preToolUse and postToolUse are supported.
|
|
163
|
+
*/
|
|
164
|
+
interface ArchitectHookAgentConfig {
|
|
165
|
+
/** Config applied when the agent invokes the PreToolUse hook. */
|
|
166
|
+
preToolUse?: ArchitectHookMethodConfig;
|
|
167
|
+
/** Config applied when the agent invokes the PostToolUse hook. */
|
|
168
|
+
postToolUse?: ArchitectHookMethodConfig;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Hook configuration keyed by agent name (architect-mcp).
|
|
172
|
+
*/
|
|
173
|
+
interface ArchitectHookConfig {
|
|
174
|
+
/** Hook config for Claude Code agent. */
|
|
175
|
+
'claude-code'?: ArchitectHookAgentConfig;
|
|
176
|
+
/** Hook config for Gemini CLI agent. */
|
|
177
|
+
'gemini-cli'?: ArchitectHookAgentConfig;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Top-level architect-mcp configuration block.
|
|
181
|
+
*/
|
|
182
|
+
interface ArchitectMcpConfig {
|
|
183
|
+
/** Defaults for the `architect-mcp mcp-serve` command. */
|
|
184
|
+
'mcp-serve'?: ArchitectMcpServeConfig;
|
|
185
|
+
/** Hook method defaults keyed by agent name. */
|
|
186
|
+
hook?: ArchitectHookConfig;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Toolkit configuration from .toolkit/settings.yaml (or legacy toolkit.yaml)
|
|
51
190
|
*/
|
|
52
191
|
interface ToolkitConfig {
|
|
192
|
+
/** Config schema version (e.g. '1.0'). */
|
|
53
193
|
version?: string;
|
|
194
|
+
/** Path to the scaffold templates directory, relative to workspace root. */
|
|
54
195
|
templatesPath?: string;
|
|
196
|
+
/** Project structure type: monolith (single app) or monorepo (multiple packages). */
|
|
55
197
|
projectType?: 'monolith' | 'monorepo';
|
|
198
|
+
/** Active template name (monolith only — monorepo reads from project.json). */
|
|
56
199
|
sourceTemplate?: string;
|
|
200
|
+
/** scaffold-mcp server and hook configuration. */
|
|
201
|
+
'scaffold-mcp'?: ScaffoldMcpConfig;
|
|
202
|
+
/** architect-mcp server and hook configuration. */
|
|
203
|
+
'architect-mcp'?: ArchitectMcpConfig;
|
|
57
204
|
}
|
|
58
205
|
/**
|
|
59
206
|
* Project configuration from project.json
|
|
60
207
|
*/
|
|
61
208
|
interface ProjectConfig {
|
|
209
|
+
/** Package/project name as declared in project.json. */
|
|
62
210
|
name: string;
|
|
211
|
+
/** Root directory of the project, relative to workspace root. */
|
|
63
212
|
root: string;
|
|
213
|
+
/** Template this project was scaffolded from. */
|
|
64
214
|
sourceTemplate?: string;
|
|
215
|
+
/** Project type as declared in project.json (e.g. 'application' or 'library'). */
|
|
65
216
|
projectType?: string;
|
|
66
217
|
}
|
|
67
218
|
/**
|
|
68
219
|
* Scaffold template include configuration
|
|
69
220
|
*/
|
|
70
221
|
interface ParsedInclude {
|
|
222
|
+
/** Absolute path of the source template file. */
|
|
71
223
|
sourcePath: string;
|
|
224
|
+
/** Absolute path of the destination file in the target directory. */
|
|
72
225
|
targetPath: string;
|
|
226
|
+
/** Conditions that must be satisfied for this include to be applied. */
|
|
73
227
|
conditions?: Record<string, string>;
|
|
74
228
|
}
|
|
75
229
|
/**
|
|
76
230
|
* Result of a scaffold operation
|
|
77
231
|
*/
|
|
78
232
|
interface ScaffoldResult {
|
|
233
|
+
/** Whether the scaffold operation completed without errors. */
|
|
79
234
|
success: boolean;
|
|
235
|
+
/** Human-readable summary of the operation outcome. */
|
|
80
236
|
message: string;
|
|
237
|
+
/** Non-fatal warnings collected during the operation. */
|
|
81
238
|
warnings?: string[];
|
|
239
|
+
/** Paths of files that were newly created. */
|
|
82
240
|
createdFiles?: string[];
|
|
241
|
+
/** Paths of files that already existed and were not overwritten. */
|
|
83
242
|
existingFiles?: string[];
|
|
84
243
|
}
|
|
244
|
+
/**
|
|
245
|
+
* Minimal stat result returned by IFileSystemService.stat.
|
|
246
|
+
*/
|
|
247
|
+
interface FileStat {
|
|
248
|
+
/**
|
|
249
|
+
* @returns True when the path is a directory.
|
|
250
|
+
*/
|
|
251
|
+
isDirectory(): boolean;
|
|
252
|
+
/**
|
|
253
|
+
* @returns True when the path is a regular file.
|
|
254
|
+
*/
|
|
255
|
+
isFile(): boolean;
|
|
256
|
+
}
|
|
85
257
|
/**
|
|
86
258
|
* Abstract interface for file system operations
|
|
87
259
|
*/
|
|
88
260
|
interface IFileSystemService {
|
|
261
|
+
/**
|
|
262
|
+
* Check whether a path exists on disk.
|
|
263
|
+
* @param path - Absolute path to check.
|
|
264
|
+
* @returns True when the path exists.
|
|
265
|
+
*/
|
|
89
266
|
pathExists(path: string): Promise<boolean>;
|
|
267
|
+
/**
|
|
268
|
+
* Read a file as text.
|
|
269
|
+
* @param path - Absolute path of the file.
|
|
270
|
+
* @param encoding - Character encoding (default: utf-8).
|
|
271
|
+
* @returns File contents as a string.
|
|
272
|
+
*/
|
|
90
273
|
readFile(path: string, encoding?: BufferEncoding): Promise<string>;
|
|
91
|
-
|
|
274
|
+
/**
|
|
275
|
+
* Read and parse a JSON file. Returns unknown — callers must narrow the type.
|
|
276
|
+
* @param path - Absolute path of the JSON file.
|
|
277
|
+
* @returns Parsed value with type unknown.
|
|
278
|
+
*/
|
|
279
|
+
readJson(path: string): Promise<unknown>;
|
|
280
|
+
/**
|
|
281
|
+
* Write text content to a file.
|
|
282
|
+
* @param path - Absolute path of the target file.
|
|
283
|
+
* @param content - Text to write.
|
|
284
|
+
* @param encoding - Character encoding (default: utf-8).
|
|
285
|
+
* @returns Promise that resolves when the file is written.
|
|
286
|
+
*/
|
|
92
287
|
writeFile(path: string, content: string, encoding?: BufferEncoding): Promise<void>;
|
|
288
|
+
/**
|
|
289
|
+
* Create a directory and all parent directories.
|
|
290
|
+
* @param path - Absolute path of the directory to create.
|
|
291
|
+
* @returns Promise that resolves when the directory exists.
|
|
292
|
+
*/
|
|
93
293
|
ensureDir(path: string): Promise<void>;
|
|
294
|
+
/**
|
|
295
|
+
* Copy a file or directory from src to dest.
|
|
296
|
+
* @param src - Absolute source path.
|
|
297
|
+
* @param dest - Absolute destination path.
|
|
298
|
+
* @returns Promise that resolves when the copy is complete.
|
|
299
|
+
*/
|
|
94
300
|
copy(src: string, dest: string): Promise<void>;
|
|
301
|
+
/**
|
|
302
|
+
* List the entries of a directory.
|
|
303
|
+
* @param path - Absolute path of the directory.
|
|
304
|
+
* @returns Array of entry names (not full paths).
|
|
305
|
+
*/
|
|
95
306
|
readdir(path: string): Promise<string[]>;
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
307
|
+
/**
|
|
308
|
+
* Return stat info for a path.
|
|
309
|
+
* @param path - Absolute path to stat.
|
|
310
|
+
* @returns FileStat with isDirectory and isFile helpers.
|
|
311
|
+
*/
|
|
312
|
+
stat(path: string): Promise<FileStat>;
|
|
100
313
|
}
|
|
101
314
|
/**
|
|
102
315
|
* Abstract interface for variable replacement in templates
|
|
103
316
|
*/
|
|
104
317
|
interface IVariableReplacementService {
|
|
105
|
-
|
|
106
|
-
|
|
318
|
+
/**
|
|
319
|
+
* Walk dirPath and apply variable substitution to every non-binary file.
|
|
320
|
+
* @param dirPath - Directory to process recursively.
|
|
321
|
+
* @param variables - Key/value pairs used for substitution.
|
|
322
|
+
* @returns Promise that resolves when all files have been processed.
|
|
323
|
+
*/
|
|
324
|
+
processFilesForVariableReplacement(dirPath: string, variables: Record<string, unknown>): Promise<void>;
|
|
325
|
+
/**
|
|
326
|
+
* Apply variable substitution to a single file.
|
|
327
|
+
* @param filePath - File to process.
|
|
328
|
+
* @param variables - Key/value pairs used for substitution.
|
|
329
|
+
* @returns Promise that resolves when the file has been processed.
|
|
330
|
+
*/
|
|
331
|
+
replaceVariablesInFile(filePath: string, variables: Record<string, unknown>): Promise<void>;
|
|
332
|
+
/**
|
|
333
|
+
* Checks if a file should be treated as a binary (non-text) file.
|
|
334
|
+
* @param filePath - Path to check.
|
|
335
|
+
* @returns True if the file is binary.
|
|
336
|
+
*/
|
|
107
337
|
isBinaryFile(filePath: string): boolean;
|
|
108
338
|
}
|
|
109
339
|
/**
|
|
110
|
-
* Context object passed to generator functions
|
|
340
|
+
* Context object passed to generator functions.
|
|
341
|
+
* Bundles all dependencies needed to produce scaffold output.
|
|
111
342
|
*/
|
|
112
343
|
interface GeneratorContext {
|
|
113
|
-
variables
|
|
114
|
-
|
|
344
|
+
/** Template variables resolved for the current scaffold operation. */
|
|
345
|
+
variables: Record<string, unknown>;
|
|
346
|
+
/** Raw scaffold configuration loaded from scaffold.yaml. */
|
|
347
|
+
config: unknown;
|
|
348
|
+
/** Absolute path of the directory where output files will be written. */
|
|
115
349
|
targetPath: string;
|
|
350
|
+
/** Absolute path of the source template directory. */
|
|
116
351
|
templatePath: string;
|
|
352
|
+
/** File-system abstraction used for all I/O inside generators. */
|
|
117
353
|
fileSystem: IFileSystemService;
|
|
118
|
-
|
|
354
|
+
/** Loader for scaffold config files — typed as unknown to avoid circular deps. */
|
|
355
|
+
scaffoldConfigLoader: unknown;
|
|
356
|
+
/** Variable-replacement service injected to avoid circular imports. */
|
|
119
357
|
variableReplacer: IVariableReplacementService;
|
|
120
|
-
ScaffoldProcessingService
|
|
358
|
+
/** ScaffoldProcessingService constructor — passed to avoid circular imports. */
|
|
359
|
+
ScaffoldProcessingService: new (...args: unknown[]) => unknown;
|
|
360
|
+
/**
|
|
361
|
+
* Return the workspace root path.
|
|
362
|
+
* @returns Absolute path of the workspace root.
|
|
363
|
+
*/
|
|
121
364
|
getRootPath: () => string;
|
|
365
|
+
/**
|
|
366
|
+
* Return the absolute path of a project relative to the workspace root.
|
|
367
|
+
* @param projectPath - Project path relative to the workspace root.
|
|
368
|
+
* @returns Absolute path of the project.
|
|
369
|
+
*/
|
|
122
370
|
getProjectPath: (projectPath: string) => string;
|
|
123
371
|
}
|
|
124
372
|
/**
|
|
125
|
-
* Type definition for generator functions
|
|
373
|
+
* Type definition for generator functions.
|
|
374
|
+
* @param context - The generator context bundling all scaffold dependencies.
|
|
375
|
+
* @returns A promise resolving to the scaffold result.
|
|
126
376
|
*/
|
|
127
377
|
type GeneratorFunction = (context: GeneratorContext) => Promise<ScaffoldResult>;
|
|
128
378
|
//#endregion
|
|
@@ -254,16 +504,31 @@ declare class ScaffoldProcessingService {
|
|
|
254
504
|
declare class TemplatesManagerService {
|
|
255
505
|
private static SCAFFOLD_CONFIG_FILE;
|
|
256
506
|
private static TEMPLATES_FOLDER;
|
|
507
|
+
private static TOOLKIT_FOLDER;
|
|
508
|
+
private static SETTINGS_FILE;
|
|
509
|
+
private static SETTINGS_LOCAL_FILE;
|
|
257
510
|
private static TOOLKIT_CONFIG_FILE;
|
|
511
|
+
/**
|
|
512
|
+
* Recursively merge two plain objects. Primitive and array values in `local`
|
|
513
|
+
* replace those in `base`; plain-object values are merged recursively.
|
|
514
|
+
*/
|
|
515
|
+
private static deepMerge;
|
|
516
|
+
/**
|
|
517
|
+
* Deep-merge two ToolkitConfig objects. Plain-object values are merged
|
|
518
|
+
* recursively; primitives and arrays in `local` replace those in `base`.
|
|
519
|
+
* This allows settings.local.yaml to override a single leaf key (e.g.
|
|
520
|
+
* scaffold-mcp.mcp-serve.fallbackTool) without wiping sibling keys.
|
|
521
|
+
*/
|
|
522
|
+
private static mergeToolkitConfigs;
|
|
258
523
|
/**
|
|
259
524
|
* Find the templates directory by searching upwards from the starting path.
|
|
260
525
|
*
|
|
261
526
|
* Algorithm:
|
|
262
527
|
* 1. Start from the provided path (default: current working directory)
|
|
263
528
|
* 2. Search upwards to find the workspace root (where .git exists or filesystem root)
|
|
264
|
-
* 3.
|
|
265
|
-
* - If
|
|
266
|
-
* - If no, default to 'templates' folder in workspace root
|
|
529
|
+
* 3. Read toolkit config (checks .toolkit/settings.yaml, then toolkit.yaml)
|
|
530
|
+
* - If config has templatesPath, use it
|
|
531
|
+
* - If no config, default to 'templates' folder in workspace root
|
|
267
532
|
* 4. Verify the templates directory exists
|
|
268
533
|
*
|
|
269
534
|
* @param startPath - The path to start searching from (defaults to process.cwd())
|
|
@@ -302,21 +567,32 @@ declare class TemplatesManagerService {
|
|
|
302
567
|
*/
|
|
303
568
|
static getTemplatesFolderName(): string;
|
|
304
569
|
/**
|
|
305
|
-
* Read toolkit
|
|
570
|
+
* Read toolkit configuration from workspace root.
|
|
571
|
+
*
|
|
572
|
+
* Priority order:
|
|
573
|
+
* 1. .toolkit/settings.yaml (new location)
|
|
574
|
+
* 2. Shallow-merge .toolkit/settings.local.yaml over settings.yaml if present
|
|
575
|
+
* 3. Fallback to root toolkit.yaml (deprecated, backward-compat)
|
|
306
576
|
*
|
|
307
577
|
* @param startPath - The path to start searching from (defaults to process.cwd())
|
|
308
578
|
* @returns The toolkit configuration object or null if not found
|
|
309
579
|
*/
|
|
310
580
|
static readToolkitConfig(startPath?: string): Promise<ToolkitConfig | null>;
|
|
311
581
|
/**
|
|
312
|
-
* Read toolkit
|
|
582
|
+
* Read toolkit configuration from workspace root (sync).
|
|
583
|
+
*
|
|
584
|
+
* Priority order:
|
|
585
|
+
* 1. .toolkit/settings.yaml (new location)
|
|
586
|
+
* 2. Shallow-merge .toolkit/settings.local.yaml over settings.yaml if present
|
|
587
|
+
* 3. Fallback to root toolkit.yaml (deprecated, backward-compat)
|
|
313
588
|
*
|
|
314
589
|
* @param startPath - The path to start searching from (defaults to process.cwd())
|
|
315
590
|
* @returns The toolkit configuration object or null if not found
|
|
316
591
|
*/
|
|
317
592
|
static readToolkitConfigSync(startPath?: string): ToolkitConfig | null;
|
|
318
593
|
/**
|
|
319
|
-
* Write toolkit
|
|
594
|
+
* Write toolkit configuration to .toolkit/settings.yaml.
|
|
595
|
+
* Creates the .toolkit directory if it does not exist.
|
|
320
596
|
*
|
|
321
597
|
* @param config - The toolkit configuration to write
|
|
322
598
|
* @param startPath - The path to start searching from (defaults to process.cwd())
|
|
@@ -680,4 +956,4 @@ interface ProjectTypeDetectionResult {
|
|
|
680
956
|
*/
|
|
681
957
|
declare function detectProjectType(workspaceRoot: string): Promise<ProjectTypeDetectionResult>;
|
|
682
958
|
//#endregion
|
|
683
|
-
export { ConfigSource, GeneratorContext, GeneratorFunction, type GitHubDirectoryEntry, IFileSystemService, IVariableReplacementService, NxProjectJson, type ParsedGitHubUrl, ParsedInclude, ProjectConfig, ProjectConfigResolver, ProjectConfigResult, ProjectFinderService, ProjectType, ScaffoldProcessingService, ScaffoldResult, TemplatesManagerService, ToolkitConfig, accessSync, cloneRepository, cloneSubdirectory, copy, detectProjectType, ensureDir, fetchGitHubDirectoryContents, findWorkspaceRoot, generateStableId, gitInit, icons, log, logger, messages, mkdir, mkdirSync, move, parseGitHubUrl, pathExists, pathExistsSync, print, readFile, readFileSync, readJson, readJsonSync, readdir, remove, sections, stat, statSync, writeFile, writeFileSync };
|
|
959
|
+
export { ArchitectHookAgentConfig, ArchitectHookConfig, ArchitectHookMethodConfig, ArchitectMcpConfig, ArchitectMcpServeConfig, ConfigSource, FileStat, GeneratorContext, GeneratorFunction, type GitHubDirectoryEntry, HookAgentConfig, HookConfig, HookMethodConfig, IFileSystemService, IVariableReplacementService, McpServeConfig, type NxProjectJson, type ParsedGitHubUrl, ParsedInclude, ProjectConfig, ProjectConfigResolver, type ProjectConfigResult, ProjectFinderService, ProjectType, ScaffoldMcpConfig, ScaffoldProcessingService, ScaffoldResult, TemplatesManagerService, ToolkitConfig, accessSync, cloneRepository, cloneSubdirectory, copy, detectProjectType, ensureDir, fetchGitHubDirectoryContents, findWorkspaceRoot, generateStableId, gitInit, icons, log, logger, messages, mkdir, mkdirSync, move, parseGitHubUrl, pathExists, pathExistsSync, print, readFile, readFileSync, readJson, readJsonSync, readdir, remove, sections, stat, statSync, writeFile, writeFileSync };
|
package/dist/index.mjs
CHANGED
|
@@ -164,16 +164,41 @@ const log = {
|
|
|
164
164
|
var TemplatesManagerService = class TemplatesManagerService {
|
|
165
165
|
static SCAFFOLD_CONFIG_FILE = "scaffold.yaml";
|
|
166
166
|
static TEMPLATES_FOLDER = "templates";
|
|
167
|
+
static TOOLKIT_FOLDER = ".toolkit";
|
|
168
|
+
static SETTINGS_FILE = "settings.yaml";
|
|
169
|
+
static SETTINGS_LOCAL_FILE = "settings.local.yaml";
|
|
167
170
|
static TOOLKIT_CONFIG_FILE = "toolkit.yaml";
|
|
168
171
|
/**
|
|
172
|
+
* Recursively merge two plain objects. Primitive and array values in `local`
|
|
173
|
+
* replace those in `base`; plain-object values are merged recursively.
|
|
174
|
+
*/
|
|
175
|
+
static deepMerge(base, local) {
|
|
176
|
+
const result = { ...base };
|
|
177
|
+
for (const [key, localValue] of Object.entries(local)) {
|
|
178
|
+
const baseValue = result[key];
|
|
179
|
+
if (localValue !== null && typeof localValue === "object" && !Array.isArray(localValue) && baseValue !== null && typeof baseValue === "object" && !Array.isArray(baseValue)) result[key] = TemplatesManagerService.deepMerge(baseValue, localValue);
|
|
180
|
+
else result[key] = localValue;
|
|
181
|
+
}
|
|
182
|
+
return result;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Deep-merge two ToolkitConfig objects. Plain-object values are merged
|
|
186
|
+
* recursively; primitives and arrays in `local` replace those in `base`.
|
|
187
|
+
* This allows settings.local.yaml to override a single leaf key (e.g.
|
|
188
|
+
* scaffold-mcp.mcp-serve.fallbackTool) without wiping sibling keys.
|
|
189
|
+
*/
|
|
190
|
+
static mergeToolkitConfigs(base, local) {
|
|
191
|
+
return TemplatesManagerService.deepMerge(base, local);
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
169
194
|
* Find the templates directory by searching upwards from the starting path.
|
|
170
195
|
*
|
|
171
196
|
* Algorithm:
|
|
172
197
|
* 1. Start from the provided path (default: current working directory)
|
|
173
198
|
* 2. Search upwards to find the workspace root (where .git exists or filesystem root)
|
|
174
|
-
* 3.
|
|
175
|
-
* - If
|
|
176
|
-
* - If no, default to 'templates' folder in workspace root
|
|
199
|
+
* 3. Read toolkit config (checks .toolkit/settings.yaml, then toolkit.yaml)
|
|
200
|
+
* - If config has templatesPath, use it
|
|
201
|
+
* - If no config, default to 'templates' folder in workspace root
|
|
177
202
|
* 4. Verify the templates directory exists
|
|
178
203
|
*
|
|
179
204
|
* @param startPath - The path to start searching from (defaults to process.cwd())
|
|
@@ -181,16 +206,11 @@ var TemplatesManagerService = class TemplatesManagerService {
|
|
|
181
206
|
*/
|
|
182
207
|
static async findTemplatesPath(startPath = process.cwd()) {
|
|
183
208
|
const workspaceRoot = await TemplatesManagerService.findWorkspaceRoot(startPath);
|
|
184
|
-
const
|
|
185
|
-
if (
|
|
186
|
-
const
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
if (config?.templatesPath) {
|
|
190
|
-
const templatesPath$1 = path.isAbsolute(config.templatesPath) ? config.templatesPath : path.join(workspaceRoot, config.templatesPath);
|
|
191
|
-
if (await pathExists(templatesPath$1)) return templatesPath$1;
|
|
192
|
-
else return null;
|
|
193
|
-
}
|
|
209
|
+
const config = await TemplatesManagerService.readToolkitConfig(startPath);
|
|
210
|
+
if (config?.templatesPath) {
|
|
211
|
+
const templatesPath$1 = path.isAbsolute(config.templatesPath) ? config.templatesPath : path.join(workspaceRoot, config.templatesPath);
|
|
212
|
+
if (await pathExists(templatesPath$1)) return templatesPath$1;
|
|
213
|
+
return null;
|
|
194
214
|
}
|
|
195
215
|
const templatesPath = path.join(workspaceRoot, TemplatesManagerService.TEMPLATES_FOLDER);
|
|
196
216
|
if (await pathExists(templatesPath)) return templatesPath;
|
|
@@ -217,16 +237,11 @@ var TemplatesManagerService = class TemplatesManagerService {
|
|
|
217
237
|
*/
|
|
218
238
|
static findTemplatesPathSync(startPath = process.cwd()) {
|
|
219
239
|
const workspaceRoot = TemplatesManagerService.findWorkspaceRootSync(startPath);
|
|
220
|
-
const
|
|
221
|
-
if (
|
|
222
|
-
const
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
if (config?.templatesPath) {
|
|
226
|
-
const templatesPath$1 = path.isAbsolute(config.templatesPath) ? config.templatesPath : path.join(workspaceRoot, config.templatesPath);
|
|
227
|
-
if (pathExistsSync(templatesPath$1)) return templatesPath$1;
|
|
228
|
-
else return null;
|
|
229
|
-
}
|
|
240
|
+
const config = TemplatesManagerService.readToolkitConfigSync(startPath);
|
|
241
|
+
if (config?.templatesPath) {
|
|
242
|
+
const templatesPath$1 = path.isAbsolute(config.templatesPath) ? config.templatesPath : path.join(workspaceRoot, config.templatesPath);
|
|
243
|
+
if (pathExistsSync(templatesPath$1)) return templatesPath$1;
|
|
244
|
+
return null;
|
|
230
245
|
}
|
|
231
246
|
const templatesPath = path.join(workspaceRoot, TemplatesManagerService.TEMPLATES_FOLDER);
|
|
232
247
|
if (pathExistsSync(templatesPath)) return templatesPath;
|
|
@@ -267,44 +282,80 @@ var TemplatesManagerService = class TemplatesManagerService {
|
|
|
267
282
|
return TemplatesManagerService.TEMPLATES_FOLDER;
|
|
268
283
|
}
|
|
269
284
|
/**
|
|
270
|
-
* Read toolkit
|
|
285
|
+
* Read toolkit configuration from workspace root.
|
|
286
|
+
*
|
|
287
|
+
* Priority order:
|
|
288
|
+
* 1. .toolkit/settings.yaml (new location)
|
|
289
|
+
* 2. Shallow-merge .toolkit/settings.local.yaml over settings.yaml if present
|
|
290
|
+
* 3. Fallback to root toolkit.yaml (deprecated, backward-compat)
|
|
271
291
|
*
|
|
272
292
|
* @param startPath - The path to start searching from (defaults to process.cwd())
|
|
273
293
|
* @returns The toolkit configuration object or null if not found
|
|
274
294
|
*/
|
|
275
295
|
static async readToolkitConfig(startPath = process.cwd()) {
|
|
276
296
|
const workspaceRoot = await TemplatesManagerService.findWorkspaceRoot(startPath);
|
|
277
|
-
const toolkitConfigPath = path.join(workspaceRoot, TemplatesManagerService.TOOLKIT_CONFIG_FILE);
|
|
278
|
-
if (!await pathExists(toolkitConfigPath)) return null;
|
|
279
297
|
const yaml$1 = await import("js-yaml");
|
|
280
|
-
const
|
|
298
|
+
const toolkitFolder = path.join(workspaceRoot, TemplatesManagerService.TOOLKIT_FOLDER);
|
|
299
|
+
const settingsPath = path.join(toolkitFolder, TemplatesManagerService.SETTINGS_FILE);
|
|
300
|
+
const settingsLocalPath = path.join(toolkitFolder, TemplatesManagerService.SETTINGS_LOCAL_FILE);
|
|
301
|
+
if (await pathExists(settingsPath)) {
|
|
302
|
+
const baseContent = await fs.readFile(settingsPath, "utf-8");
|
|
303
|
+
const base = yaml$1.load(baseContent);
|
|
304
|
+
if (await pathExists(settingsLocalPath)) {
|
|
305
|
+
const localContent = await fs.readFile(settingsLocalPath, "utf-8");
|
|
306
|
+
const local = yaml$1.load(localContent);
|
|
307
|
+
return TemplatesManagerService.mergeToolkitConfigs(base, local);
|
|
308
|
+
}
|
|
309
|
+
return base;
|
|
310
|
+
}
|
|
311
|
+
const legacyConfigPath = path.join(workspaceRoot, TemplatesManagerService.TOOLKIT_CONFIG_FILE);
|
|
312
|
+
if (!await pathExists(legacyConfigPath)) return null;
|
|
313
|
+
const content = await fs.readFile(legacyConfigPath, "utf-8");
|
|
281
314
|
return yaml$1.load(content);
|
|
282
315
|
}
|
|
283
316
|
/**
|
|
284
|
-
* Read toolkit
|
|
317
|
+
* Read toolkit configuration from workspace root (sync).
|
|
318
|
+
*
|
|
319
|
+
* Priority order:
|
|
320
|
+
* 1. .toolkit/settings.yaml (new location)
|
|
321
|
+
* 2. Shallow-merge .toolkit/settings.local.yaml over settings.yaml if present
|
|
322
|
+
* 3. Fallback to root toolkit.yaml (deprecated, backward-compat)
|
|
285
323
|
*
|
|
286
324
|
* @param startPath - The path to start searching from (defaults to process.cwd())
|
|
287
325
|
* @returns The toolkit configuration object or null if not found
|
|
288
326
|
*/
|
|
289
327
|
static readToolkitConfigSync(startPath = process.cwd()) {
|
|
290
328
|
const workspaceRoot = TemplatesManagerService.findWorkspaceRootSync(startPath);
|
|
291
|
-
const toolkitConfigPath = path.join(workspaceRoot, TemplatesManagerService.TOOLKIT_CONFIG_FILE);
|
|
292
|
-
if (!pathExistsSync(toolkitConfigPath)) return null;
|
|
293
329
|
const yaml$1 = __require("js-yaml");
|
|
294
|
-
const
|
|
295
|
-
|
|
330
|
+
const toolkitFolder = path.join(workspaceRoot, TemplatesManagerService.TOOLKIT_FOLDER);
|
|
331
|
+
const settingsPath = path.join(toolkitFolder, TemplatesManagerService.SETTINGS_FILE);
|
|
332
|
+
const settingsLocalPath = path.join(toolkitFolder, TemplatesManagerService.SETTINGS_LOCAL_FILE);
|
|
333
|
+
if (pathExistsSync(settingsPath)) {
|
|
334
|
+
const base = yaml$1.load(readFileSync$1(settingsPath, "utf-8"));
|
|
335
|
+
if (pathExistsSync(settingsLocalPath)) {
|
|
336
|
+
const local = yaml$1.load(readFileSync$1(settingsLocalPath, "utf-8"));
|
|
337
|
+
return TemplatesManagerService.mergeToolkitConfigs(base, local);
|
|
338
|
+
}
|
|
339
|
+
return base;
|
|
340
|
+
}
|
|
341
|
+
const legacyConfigPath = path.join(workspaceRoot, TemplatesManagerService.TOOLKIT_CONFIG_FILE);
|
|
342
|
+
if (!pathExistsSync(legacyConfigPath)) return null;
|
|
343
|
+
return yaml$1.load(readFileSync$1(legacyConfigPath, "utf-8"));
|
|
296
344
|
}
|
|
297
345
|
/**
|
|
298
|
-
* Write toolkit
|
|
346
|
+
* Write toolkit configuration to .toolkit/settings.yaml.
|
|
347
|
+
* Creates the .toolkit directory if it does not exist.
|
|
299
348
|
*
|
|
300
349
|
* @param config - The toolkit configuration to write
|
|
301
350
|
* @param startPath - The path to start searching from (defaults to process.cwd())
|
|
302
351
|
*/
|
|
303
352
|
static async writeToolkitConfig(config, startPath = process.cwd()) {
|
|
304
353
|
const workspaceRoot = await TemplatesManagerService.findWorkspaceRoot(startPath);
|
|
305
|
-
const
|
|
354
|
+
const toolkitFolder = path.join(workspaceRoot, TemplatesManagerService.TOOLKIT_FOLDER);
|
|
355
|
+
const settingsPath = path.join(toolkitFolder, TemplatesManagerService.SETTINGS_FILE);
|
|
356
|
+
await fs.mkdir(toolkitFolder, { recursive: true });
|
|
306
357
|
const content = (await import("js-yaml")).dump(config, { indent: 2 });
|
|
307
|
-
await fs.writeFile(
|
|
358
|
+
await fs.writeFile(settingsPath, content, "utf-8");
|
|
308
359
|
}
|
|
309
360
|
/**
|
|
310
361
|
* Get the workspace root directory
|
package/package.json
CHANGED