@agiflowai/aicode-toolkit 1.0.3 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +8 -111
- package/dist/{cli.js → cli.mjs} +12 -110
- package/dist/index.cjs +1 -1
- package/dist/{index.d.ts → index.d.mts} +1 -1
- package/dist/index.mjs +4 -0
- package/dist/mcp-BgNkvV6h.mjs +3 -0
- package/dist/{mcp-BmhiAfeF.js → mcp-C3HR_ZNF.mjs} +1 -1
- package/dist/{services-zrdafWTg.js → services-BvnOGCDG.mjs} +296 -207
- package/dist/{services-C6lqyioO.cjs → services-DIUrmi_K.cjs} +294 -210
- package/package.json +7 -9
- package/dist/index.js +0 -4
- package/dist/mcp-CZIiB-6Y.js +0 -3
- /package/dist/{cli.d.ts → cli.d.mts} +0 -0
|
@@ -21,24 +21,18 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
21
21
|
}) : target, mod));
|
|
22
22
|
|
|
23
23
|
//#endregion
|
|
24
|
-
let
|
|
25
|
-
node_path = __toESM(node_path);
|
|
24
|
+
let __agiflowai_coding_agent_bridge = require("@agiflowai/coding-agent-bridge");
|
|
26
25
|
let __agiflowai_aicode_utils = require("@agiflowai/aicode-utils");
|
|
27
|
-
__agiflowai_aicode_utils = __toESM(__agiflowai_aicode_utils);
|
|
28
|
-
let fs_extra = require("fs-extra");
|
|
29
|
-
fs_extra = __toESM(fs_extra);
|
|
30
26
|
let chalk = require("chalk");
|
|
31
27
|
chalk = __toESM(chalk);
|
|
32
28
|
let gradient_string = require("gradient-string");
|
|
33
29
|
gradient_string = __toESM(gradient_string);
|
|
30
|
+
let node_path = require("node:path");
|
|
31
|
+
node_path = __toESM(node_path);
|
|
34
32
|
let execa = require("execa");
|
|
35
|
-
execa = __toESM(execa);
|
|
36
|
-
let __agiflowai_coding_agent_bridge = require("@agiflowai/coding-agent-bridge");
|
|
37
|
-
__agiflowai_coding_agent_bridge = __toESM(__agiflowai_coding_agent_bridge);
|
|
38
33
|
let node_fs_promises = require("node:fs/promises");
|
|
39
34
|
node_fs_promises = __toESM(node_fs_promises);
|
|
40
35
|
let liquidjs = require("liquidjs");
|
|
41
|
-
liquidjs = __toESM(liquidjs);
|
|
42
36
|
let node_os = require("node:os");
|
|
43
37
|
node_os = __toESM(node_os);
|
|
44
38
|
|
|
@@ -103,6 +97,187 @@ const BANNER_GRADIENT = [
|
|
|
103
97
|
THEME.colors.secondary.dark
|
|
104
98
|
];
|
|
105
99
|
|
|
100
|
+
//#endregion
|
|
101
|
+
//#region src/services/CodingAgentService.ts
|
|
102
|
+
/**
|
|
103
|
+
* CodingAgentService
|
|
104
|
+
*
|
|
105
|
+
* DESIGN PATTERNS:
|
|
106
|
+
* - Service pattern for business logic encapsulation
|
|
107
|
+
* - Strategy pattern for different agent configurations
|
|
108
|
+
* - Single responsibility: Handle MCP setup for coding agents
|
|
109
|
+
*
|
|
110
|
+
* CODING STANDARDS:
|
|
111
|
+
* - Use async/await for asynchronous operations
|
|
112
|
+
* - Throw descriptive errors for error cases
|
|
113
|
+
* - Document methods with JSDoc comments
|
|
114
|
+
*
|
|
115
|
+
* AVOID:
|
|
116
|
+
* - Direct UI interaction (no prompts in services)
|
|
117
|
+
* - Hard-coding agent configurations (use strategies)
|
|
118
|
+
*/
|
|
119
|
+
var CodingAgentService = class {
|
|
120
|
+
workspaceRoot;
|
|
121
|
+
constructor(workspaceRoot) {
|
|
122
|
+
this.workspaceRoot = workspaceRoot;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Detect which coding agent is enabled in the workspace
|
|
126
|
+
* Checks for Claude Code, Codex, Gemini CLI, GitHub Copilot, and Cursor installations
|
|
127
|
+
* @param workspaceRoot - The workspace root directory
|
|
128
|
+
* @returns Promise resolving to detected agent ID or null
|
|
129
|
+
*/
|
|
130
|
+
static async detectCodingAgent(workspaceRoot) {
|
|
131
|
+
if (await new __agiflowai_coding_agent_bridge.ClaudeCodeService({ workspaceRoot }).isEnabled()) return __agiflowai_coding_agent_bridge.CLAUDE_CODE;
|
|
132
|
+
if (await new __agiflowai_coding_agent_bridge.CursorService({ workspaceRoot }).isEnabled()) return __agiflowai_coding_agent_bridge.CURSOR;
|
|
133
|
+
if (await new __agiflowai_coding_agent_bridge.GitHubCopilotService({ workspaceRoot }).isEnabled()) return __agiflowai_coding_agent_bridge.GITHUB_COPILOT;
|
|
134
|
+
if (await new __agiflowai_coding_agent_bridge.CodexService({ workspaceRoot }).isEnabled()) return __agiflowai_coding_agent_bridge.CODEX;
|
|
135
|
+
if (await new __agiflowai_coding_agent_bridge.GeminiCliService({ workspaceRoot }).isEnabled()) return __agiflowai_coding_agent_bridge.GEMINI_CLI;
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Get available coding agents with their descriptions
|
|
140
|
+
*/
|
|
141
|
+
static getAvailableAgents() {
|
|
142
|
+
return [
|
|
143
|
+
{
|
|
144
|
+
value: __agiflowai_coding_agent_bridge.CLAUDE_CODE,
|
|
145
|
+
name: "Claude Code",
|
|
146
|
+
description: "Anthropic Claude Code CLI agent"
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
value: __agiflowai_coding_agent_bridge.CURSOR,
|
|
150
|
+
name: "Cursor",
|
|
151
|
+
description: "Cursor AI-first code editor"
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
value: __agiflowai_coding_agent_bridge.GITHUB_COPILOT,
|
|
155
|
+
name: "GitHub Copilot",
|
|
156
|
+
description: "GitHub Copilot coding agent and CLI"
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
value: __agiflowai_coding_agent_bridge.CODEX,
|
|
160
|
+
name: "Codex",
|
|
161
|
+
description: "OpenAI Codex CLI agent"
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
value: __agiflowai_coding_agent_bridge.GEMINI_CLI,
|
|
165
|
+
name: "Gemini CLI",
|
|
166
|
+
description: "Google Gemini CLI agent"
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
value: __agiflowai_coding_agent_bridge.NONE,
|
|
170
|
+
name: "Other",
|
|
171
|
+
description: "Other coding agent or skip MCP configuration"
|
|
172
|
+
}
|
|
173
|
+
];
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Get the coding agent service instance
|
|
177
|
+
* @param agent - The coding agent to get service for
|
|
178
|
+
* @returns The service instance or null if not supported
|
|
179
|
+
*/
|
|
180
|
+
getCodingAgentService(agent) {
|
|
181
|
+
if (agent === __agiflowai_coding_agent_bridge.CLAUDE_CODE) return new __agiflowai_coding_agent_bridge.ClaudeCodeService({ workspaceRoot: this.workspaceRoot });
|
|
182
|
+
if (agent === __agiflowai_coding_agent_bridge.CURSOR) return new __agiflowai_coding_agent_bridge.CursorService({ workspaceRoot: this.workspaceRoot });
|
|
183
|
+
if (agent === __agiflowai_coding_agent_bridge.GITHUB_COPILOT) return new __agiflowai_coding_agent_bridge.GitHubCopilotService({ workspaceRoot: this.workspaceRoot });
|
|
184
|
+
if (agent === __agiflowai_coding_agent_bridge.CODEX) return new __agiflowai_coding_agent_bridge.CodexService({ workspaceRoot: this.workspaceRoot });
|
|
185
|
+
if (agent === __agiflowai_coding_agent_bridge.GEMINI_CLI) return new __agiflowai_coding_agent_bridge.GeminiCliService({ workspaceRoot: this.workspaceRoot });
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Update custom instructions/prompts for the coding agent
|
|
190
|
+
* Appends custom instruction prompt to the agent's configuration
|
|
191
|
+
* @param agent - The coding agent to update
|
|
192
|
+
* @param instructionPrompt - The instruction prompt to append
|
|
193
|
+
* @param customInstructionFile - Optional custom file path to write instructions to (e.g., '.claude/aicode-instructions.md')
|
|
194
|
+
*/
|
|
195
|
+
async updateCustomInstructions(agent, instructionPrompt, customInstructionFile) {
|
|
196
|
+
if (agent === __agiflowai_coding_agent_bridge.NONE) {
|
|
197
|
+
__agiflowai_aicode_utils.print.info("Skipping custom instruction update");
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
__agiflowai_aicode_utils.print.info(`\nUpdating custom instructions for ${agent}...`);
|
|
201
|
+
const service = this.getCodingAgentService(agent);
|
|
202
|
+
if (!service) {
|
|
203
|
+
__agiflowai_aicode_utils.print.info(`Custom instruction update for ${agent} is not yet supported.`);
|
|
204
|
+
__agiflowai_aicode_utils.print.info("Please manually add the instructions to your agent configuration.");
|
|
205
|
+
__agiflowai_aicode_utils.print.info("\nInstruction prompt to add:");
|
|
206
|
+
__agiflowai_aicode_utils.print.info(instructionPrompt);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
await service.updatePrompt({
|
|
210
|
+
systemPrompt: instructionPrompt,
|
|
211
|
+
customInstructionFile,
|
|
212
|
+
marker: true
|
|
213
|
+
});
|
|
214
|
+
if (customInstructionFile) __agiflowai_aicode_utils.print.success(`Custom instructions written to ${customInstructionFile} and referenced in CLAUDE.md and AGENTS.md`);
|
|
215
|
+
else __agiflowai_aicode_utils.print.success(`Custom instructions appended to CLAUDE.md and AGENTS.md`);
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Setup MCP configuration for the selected coding agent
|
|
219
|
+
* @param agent - The coding agent to configure
|
|
220
|
+
*/
|
|
221
|
+
async setupMCP(agent) {
|
|
222
|
+
if (agent === __agiflowai_coding_agent_bridge.NONE) {
|
|
223
|
+
__agiflowai_aicode_utils.print.info("Skipping MCP configuration");
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
__agiflowai_aicode_utils.print.info(`\nSetting up MCP for ${agent}...`);
|
|
227
|
+
const service = this.getCodingAgentService(agent);
|
|
228
|
+
let configLocation = "";
|
|
229
|
+
let restartInstructions = "";
|
|
230
|
+
if (agent === __agiflowai_coding_agent_bridge.CLAUDE_CODE) {
|
|
231
|
+
configLocation = ".mcp.json";
|
|
232
|
+
restartInstructions = "Restart Claude Code to load the new MCP servers";
|
|
233
|
+
} else if (agent === __agiflowai_coding_agent_bridge.CURSOR) {
|
|
234
|
+
configLocation = "~/.cursor/mcp.json (or .cursor/mcp.json for workspace)";
|
|
235
|
+
restartInstructions = "Restart Cursor to load the new MCP servers";
|
|
236
|
+
} else if (agent === __agiflowai_coding_agent_bridge.GITHUB_COPILOT) {
|
|
237
|
+
configLocation = "~/.copilot/config.json (CLI) or GitHub UI (Coding Agent)";
|
|
238
|
+
restartInstructions = "Restart GitHub Copilot CLI or configure via GitHub repository settings";
|
|
239
|
+
} else if (agent === __agiflowai_coding_agent_bridge.CODEX) {
|
|
240
|
+
configLocation = "~/.codex/config.toml";
|
|
241
|
+
restartInstructions = "Restart Codex CLI to load the new MCP servers";
|
|
242
|
+
} else if (agent === __agiflowai_coding_agent_bridge.GEMINI_CLI) {
|
|
243
|
+
configLocation = "~/.gemini/settings.json";
|
|
244
|
+
restartInstructions = "Restart Gemini CLI to load the new MCP servers";
|
|
245
|
+
}
|
|
246
|
+
if (!service) {
|
|
247
|
+
__agiflowai_aicode_utils.print.info(`MCP configuration for ${agent} is not yet supported.`);
|
|
248
|
+
__agiflowai_aicode_utils.print.info("Please configure MCP servers manually for this coding agent.");
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
await service.updateMcpSettings({ servers: {
|
|
252
|
+
"scaffold-mcp": {
|
|
253
|
+
type: "stdio",
|
|
254
|
+
command: "npx",
|
|
255
|
+
args: [
|
|
256
|
+
"-y",
|
|
257
|
+
"@agiflowai/scaffold-mcp",
|
|
258
|
+
"mcp-serve"
|
|
259
|
+
],
|
|
260
|
+
disabled: false
|
|
261
|
+
},
|
|
262
|
+
"architect-mcp": {
|
|
263
|
+
type: "stdio",
|
|
264
|
+
command: "npx",
|
|
265
|
+
args: [
|
|
266
|
+
"-y",
|
|
267
|
+
"@agiflowai/architect-mcp",
|
|
268
|
+
"mcp-serve"
|
|
269
|
+
],
|
|
270
|
+
disabled: false
|
|
271
|
+
}
|
|
272
|
+
} });
|
|
273
|
+
__agiflowai_aicode_utils.print.success(`Added scaffold-mcp and architect-mcp to ${configLocation}`);
|
|
274
|
+
__agiflowai_aicode_utils.print.info("\nNext steps:");
|
|
275
|
+
__agiflowai_aicode_utils.print.indent(`1. ${restartInstructions}`);
|
|
276
|
+
__agiflowai_aicode_utils.print.indent("2. The scaffold-mcp and architect-mcp servers will be available");
|
|
277
|
+
__agiflowai_aicode_utils.print.success("\nMCP configuration completed!");
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
|
|
106
281
|
//#endregion
|
|
107
282
|
//#region src/utils/banner.ts
|
|
108
283
|
/**
|
|
@@ -178,8 +353,7 @@ async function findWorkspaceRoot(startPath = process.cwd()) {
|
|
|
178
353
|
let currentPath = node_path.default.resolve(startPath);
|
|
179
354
|
const rootPath = node_path.default.parse(currentPath).root;
|
|
180
355
|
while (true) {
|
|
181
|
-
|
|
182
|
-
if (await fs_extra.pathExists(gitPath)) return currentPath;
|
|
356
|
+
if (await (0, __agiflowai_aicode_utils.pathExists)(node_path.default.join(currentPath, ".git"))) return currentPath;
|
|
183
357
|
if (currentPath === rootPath) return null;
|
|
184
358
|
currentPath = node_path.default.dirname(currentPath);
|
|
185
359
|
}
|
|
@@ -235,8 +409,7 @@ async function cloneSubdirectory(repoUrl, branch, subdirectory, targetFolder) {
|
|
|
235
409
|
"core.sparseCheckout",
|
|
236
410
|
"true"
|
|
237
411
|
], tempFolder);
|
|
238
|
-
|
|
239
|
-
await fs_extra.writeFile(sparseCheckoutFile, `${subdirectory}\n`);
|
|
412
|
+
await (0, __agiflowai_aicode_utils.writeFile)(node_path.default.join(tempFolder, ".git", "info", "sparse-checkout"), `${subdirectory}\n`);
|
|
240
413
|
await execGit([
|
|
241
414
|
"pull",
|
|
242
415
|
"--depth=1",
|
|
@@ -244,12 +417,12 @@ async function cloneSubdirectory(repoUrl, branch, subdirectory, targetFolder) {
|
|
|
244
417
|
branch
|
|
245
418
|
], tempFolder);
|
|
246
419
|
const sourceDir = node_path.default.join(tempFolder, subdirectory);
|
|
247
|
-
if (!await
|
|
248
|
-
if (await
|
|
249
|
-
await
|
|
250
|
-
await
|
|
420
|
+
if (!await (0, __agiflowai_aicode_utils.pathExists)(sourceDir)) throw new Error(`Subdirectory '${subdirectory}' not found in repository at branch '${branch}'`);
|
|
421
|
+
if (await (0, __agiflowai_aicode_utils.pathExists)(targetFolder)) throw new Error(`Target folder already exists: ${targetFolder}`);
|
|
422
|
+
await (0, __agiflowai_aicode_utils.move)(sourceDir, targetFolder);
|
|
423
|
+
await (0, __agiflowai_aicode_utils.remove)(tempFolder);
|
|
251
424
|
} catch (error) {
|
|
252
|
-
if (await
|
|
425
|
+
if (await (0, __agiflowai_aicode_utils.pathExists)(tempFolder)) await (0, __agiflowai_aicode_utils.remove)(tempFolder);
|
|
253
426
|
throw error;
|
|
254
427
|
}
|
|
255
428
|
}
|
|
@@ -263,7 +436,7 @@ async function cloneRepository(repoUrl, targetFolder) {
|
|
|
263
436
|
targetFolder
|
|
264
437
|
]);
|
|
265
438
|
const gitFolder = node_path.default.join(targetFolder, ".git");
|
|
266
|
-
if (await
|
|
439
|
+
if (await (0, __agiflowai_aicode_utils.pathExists)(gitFolder)) await (0, __agiflowai_aicode_utils.remove)(gitFolder);
|
|
267
440
|
}
|
|
268
441
|
/**
|
|
269
442
|
* Fetch directory listing from GitHub API
|
|
@@ -284,172 +457,27 @@ async function fetchGitHubDirectoryContents(owner, repo, path$4, branch = "main"
|
|
|
284
457
|
}));
|
|
285
458
|
}
|
|
286
459
|
|
|
287
|
-
//#endregion
|
|
288
|
-
//#region src/services/CodingAgentService.ts
|
|
289
|
-
var CodingAgentService = class {
|
|
290
|
-
workspaceRoot;
|
|
291
|
-
constructor(workspaceRoot) {
|
|
292
|
-
this.workspaceRoot = workspaceRoot;
|
|
293
|
-
}
|
|
294
|
-
/**
|
|
295
|
-
* Detect which coding agent is enabled in the workspace
|
|
296
|
-
* Checks for Claude Code, Codex, Gemini CLI, GitHub Copilot, and Cursor installations
|
|
297
|
-
* @param workspaceRoot - The workspace root directory
|
|
298
|
-
* @returns Promise resolving to detected agent ID or null
|
|
299
|
-
*/
|
|
300
|
-
static async detectCodingAgent(workspaceRoot) {
|
|
301
|
-
if (await new __agiflowai_coding_agent_bridge.ClaudeCodeService({ workspaceRoot }).isEnabled()) return __agiflowai_coding_agent_bridge.CLAUDE_CODE;
|
|
302
|
-
if (await new __agiflowai_coding_agent_bridge.CursorService({ workspaceRoot }).isEnabled()) return __agiflowai_coding_agent_bridge.CURSOR;
|
|
303
|
-
if (await new __agiflowai_coding_agent_bridge.GitHubCopilotService({ workspaceRoot }).isEnabled()) return __agiflowai_coding_agent_bridge.GITHUB_COPILOT;
|
|
304
|
-
if (await new __agiflowai_coding_agent_bridge.CodexService({ workspaceRoot }).isEnabled()) return __agiflowai_coding_agent_bridge.CODEX;
|
|
305
|
-
if (await new __agiflowai_coding_agent_bridge.GeminiCliService({ workspaceRoot }).isEnabled()) return __agiflowai_coding_agent_bridge.GEMINI_CLI;
|
|
306
|
-
return null;
|
|
307
|
-
}
|
|
308
|
-
/**
|
|
309
|
-
* Get available coding agents with their descriptions
|
|
310
|
-
*/
|
|
311
|
-
static getAvailableAgents() {
|
|
312
|
-
return [
|
|
313
|
-
{
|
|
314
|
-
value: __agiflowai_coding_agent_bridge.CLAUDE_CODE,
|
|
315
|
-
name: "Claude Code",
|
|
316
|
-
description: "Anthropic Claude Code CLI agent"
|
|
317
|
-
},
|
|
318
|
-
{
|
|
319
|
-
value: __agiflowai_coding_agent_bridge.CURSOR,
|
|
320
|
-
name: "Cursor",
|
|
321
|
-
description: "Cursor AI-first code editor"
|
|
322
|
-
},
|
|
323
|
-
{
|
|
324
|
-
value: __agiflowai_coding_agent_bridge.GITHUB_COPILOT,
|
|
325
|
-
name: "GitHub Copilot",
|
|
326
|
-
description: "GitHub Copilot coding agent and CLI"
|
|
327
|
-
},
|
|
328
|
-
{
|
|
329
|
-
value: __agiflowai_coding_agent_bridge.CODEX,
|
|
330
|
-
name: "Codex",
|
|
331
|
-
description: "OpenAI Codex CLI agent"
|
|
332
|
-
},
|
|
333
|
-
{
|
|
334
|
-
value: __agiflowai_coding_agent_bridge.GEMINI_CLI,
|
|
335
|
-
name: "Gemini CLI",
|
|
336
|
-
description: "Google Gemini CLI agent"
|
|
337
|
-
},
|
|
338
|
-
{
|
|
339
|
-
value: __agiflowai_coding_agent_bridge.NONE,
|
|
340
|
-
name: "Other",
|
|
341
|
-
description: "Other coding agent or skip MCP configuration"
|
|
342
|
-
}
|
|
343
|
-
];
|
|
344
|
-
}
|
|
345
|
-
/**
|
|
346
|
-
* Get the coding agent service instance
|
|
347
|
-
* @param agent - The coding agent to get service for
|
|
348
|
-
* @returns The service instance or null if not supported
|
|
349
|
-
*/
|
|
350
|
-
getCodingAgentService(agent) {
|
|
351
|
-
if (agent === __agiflowai_coding_agent_bridge.CLAUDE_CODE) return new __agiflowai_coding_agent_bridge.ClaudeCodeService({ workspaceRoot: this.workspaceRoot });
|
|
352
|
-
if (agent === __agiflowai_coding_agent_bridge.CURSOR) return new __agiflowai_coding_agent_bridge.CursorService({ workspaceRoot: this.workspaceRoot });
|
|
353
|
-
if (agent === __agiflowai_coding_agent_bridge.GITHUB_COPILOT) return new __agiflowai_coding_agent_bridge.GitHubCopilotService({ workspaceRoot: this.workspaceRoot });
|
|
354
|
-
if (agent === __agiflowai_coding_agent_bridge.CODEX) return new __agiflowai_coding_agent_bridge.CodexService({ workspaceRoot: this.workspaceRoot });
|
|
355
|
-
if (agent === __agiflowai_coding_agent_bridge.GEMINI_CLI) return new __agiflowai_coding_agent_bridge.GeminiCliService({ workspaceRoot: this.workspaceRoot });
|
|
356
|
-
return null;
|
|
357
|
-
}
|
|
358
|
-
/**
|
|
359
|
-
* Update custom instructions/prompts for the coding agent
|
|
360
|
-
* Appends custom instruction prompt to the agent's configuration
|
|
361
|
-
* @param agent - The coding agent to update
|
|
362
|
-
* @param instructionPrompt - The instruction prompt to append
|
|
363
|
-
* @param customInstructionFile - Optional custom file path to write instructions to (e.g., '.claude/aicode-instructions.md')
|
|
364
|
-
*/
|
|
365
|
-
async updateCustomInstructions(agent, instructionPrompt, customInstructionFile) {
|
|
366
|
-
if (agent === __agiflowai_coding_agent_bridge.NONE) {
|
|
367
|
-
__agiflowai_aicode_utils.print.info("Skipping custom instruction update");
|
|
368
|
-
return;
|
|
369
|
-
}
|
|
370
|
-
__agiflowai_aicode_utils.print.info(`\nUpdating custom instructions for ${agent}...`);
|
|
371
|
-
const service = this.getCodingAgentService(agent);
|
|
372
|
-
if (!service) {
|
|
373
|
-
__agiflowai_aicode_utils.print.info(`Custom instruction update for ${agent} is not yet supported.`);
|
|
374
|
-
__agiflowai_aicode_utils.print.info("Please manually add the instructions to your agent configuration.");
|
|
375
|
-
__agiflowai_aicode_utils.print.info("\nInstruction prompt to add:");
|
|
376
|
-
__agiflowai_aicode_utils.print.info(instructionPrompt);
|
|
377
|
-
return;
|
|
378
|
-
}
|
|
379
|
-
await service.updatePrompt({
|
|
380
|
-
systemPrompt: instructionPrompt,
|
|
381
|
-
customInstructionFile,
|
|
382
|
-
marker: true
|
|
383
|
-
});
|
|
384
|
-
if (customInstructionFile) __agiflowai_aicode_utils.print.success(`Custom instructions written to ${customInstructionFile} and referenced in CLAUDE.md and AGENTS.md`);
|
|
385
|
-
else __agiflowai_aicode_utils.print.success(`Custom instructions appended to CLAUDE.md and AGENTS.md`);
|
|
386
|
-
}
|
|
387
|
-
/**
|
|
388
|
-
* Setup MCP configuration for the selected coding agent
|
|
389
|
-
* @param agent - The coding agent to configure
|
|
390
|
-
*/
|
|
391
|
-
async setupMCP(agent) {
|
|
392
|
-
if (agent === __agiflowai_coding_agent_bridge.NONE) {
|
|
393
|
-
__agiflowai_aicode_utils.print.info("Skipping MCP configuration");
|
|
394
|
-
return;
|
|
395
|
-
}
|
|
396
|
-
__agiflowai_aicode_utils.print.info(`\nSetting up MCP for ${agent}...`);
|
|
397
|
-
const service = this.getCodingAgentService(agent);
|
|
398
|
-
let configLocation = "";
|
|
399
|
-
let restartInstructions = "";
|
|
400
|
-
if (agent === __agiflowai_coding_agent_bridge.CLAUDE_CODE) {
|
|
401
|
-
configLocation = ".mcp.json";
|
|
402
|
-
restartInstructions = "Restart Claude Code to load the new MCP servers";
|
|
403
|
-
} else if (agent === __agiflowai_coding_agent_bridge.CURSOR) {
|
|
404
|
-
configLocation = "~/.cursor/mcp.json (or .cursor/mcp.json for workspace)";
|
|
405
|
-
restartInstructions = "Restart Cursor to load the new MCP servers";
|
|
406
|
-
} else if (agent === __agiflowai_coding_agent_bridge.GITHUB_COPILOT) {
|
|
407
|
-
configLocation = "~/.copilot/config.json (CLI) or GitHub UI (Coding Agent)";
|
|
408
|
-
restartInstructions = "Restart GitHub Copilot CLI or configure via GitHub repository settings";
|
|
409
|
-
} else if (agent === __agiflowai_coding_agent_bridge.CODEX) {
|
|
410
|
-
configLocation = "~/.codex/config.toml";
|
|
411
|
-
restartInstructions = "Restart Codex CLI to load the new MCP servers";
|
|
412
|
-
} else if (agent === __agiflowai_coding_agent_bridge.GEMINI_CLI) {
|
|
413
|
-
configLocation = "~/.gemini/settings.json";
|
|
414
|
-
restartInstructions = "Restart Gemini CLI to load the new MCP servers";
|
|
415
|
-
}
|
|
416
|
-
if (!service) {
|
|
417
|
-
__agiflowai_aicode_utils.print.info(`MCP configuration for ${agent} is not yet supported.`);
|
|
418
|
-
__agiflowai_aicode_utils.print.info("Please configure MCP servers manually for this coding agent.");
|
|
419
|
-
return;
|
|
420
|
-
}
|
|
421
|
-
await service.updateMcpSettings({ servers: {
|
|
422
|
-
"scaffold-mcp": {
|
|
423
|
-
type: "stdio",
|
|
424
|
-
command: "npx",
|
|
425
|
-
args: [
|
|
426
|
-
"-y",
|
|
427
|
-
"@agiflowai/scaffold-mcp",
|
|
428
|
-
"mcp-serve"
|
|
429
|
-
],
|
|
430
|
-
disabled: false
|
|
431
|
-
},
|
|
432
|
-
"architect-mcp": {
|
|
433
|
-
type: "stdio",
|
|
434
|
-
command: "npx",
|
|
435
|
-
args: [
|
|
436
|
-
"-y",
|
|
437
|
-
"@agiflowai/architect-mcp",
|
|
438
|
-
"mcp-serve"
|
|
439
|
-
],
|
|
440
|
-
disabled: false
|
|
441
|
-
}
|
|
442
|
-
} });
|
|
443
|
-
__agiflowai_aicode_utils.print.success(`Added scaffold-mcp and architect-mcp to ${configLocation}`);
|
|
444
|
-
__agiflowai_aicode_utils.print.info("\nNext steps:");
|
|
445
|
-
__agiflowai_aicode_utils.print.indent(`1. ${restartInstructions}`);
|
|
446
|
-
__agiflowai_aicode_utils.print.indent("2. The scaffold-mcp and architect-mcp servers will be available");
|
|
447
|
-
__agiflowai_aicode_utils.print.success("\nMCP configuration completed!");
|
|
448
|
-
}
|
|
449
|
-
};
|
|
450
|
-
|
|
451
460
|
//#endregion
|
|
452
461
|
//#region src/services/NewProjectService.ts
|
|
462
|
+
/**
|
|
463
|
+
* NewProjectService
|
|
464
|
+
*
|
|
465
|
+
* DESIGN PATTERNS:
|
|
466
|
+
* - Service pattern for business logic encapsulation
|
|
467
|
+
* - Single responsibility principle
|
|
468
|
+
* - No UI interaction (prompts handled by CLI layer)
|
|
469
|
+
*
|
|
470
|
+
* CODING STANDARDS:
|
|
471
|
+
* - Use async/await for asynchronous operations
|
|
472
|
+
* - Throw descriptive errors for error cases
|
|
473
|
+
* - Keep methods focused and well-named
|
|
474
|
+
* - Document complex logic with comments
|
|
475
|
+
*
|
|
476
|
+
* AVOID:
|
|
477
|
+
* - Mixing concerns (keep focused on single domain)
|
|
478
|
+
* - Direct UI interaction (no @inquirer/prompts in services)
|
|
479
|
+
* - Direct tool implementation (services should be tool-agnostic)
|
|
480
|
+
*/
|
|
453
481
|
const RESERVED_PROJECT_NAMES = [
|
|
454
482
|
".",
|
|
455
483
|
"..",
|
|
@@ -523,7 +551,7 @@ var NewProjectService = class {
|
|
|
523
551
|
*/
|
|
524
552
|
async createProjectDirectory(projectPath, projectName) {
|
|
525
553
|
try {
|
|
526
|
-
await
|
|
554
|
+
await (0, __agiflowai_aicode_utils.mkdir)(projectPath, { recursive: false });
|
|
527
555
|
} catch (error) {
|
|
528
556
|
if (error.code === "EEXIST") throw new Error(`Directory '${projectName}' already exists. Please choose a different name.`);
|
|
529
557
|
throw error;
|
|
@@ -540,7 +568,7 @@ var NewProjectService = class {
|
|
|
540
568
|
if (parsed.isSubdirectory && parsed.branch && parsed.subdirectory) await cloneSubdirectory(parsed.repoUrl, parsed.branch, parsed.subdirectory, projectPath);
|
|
541
569
|
else await cloneRepository(parsed.repoUrl, projectPath);
|
|
542
570
|
} catch (error) {
|
|
543
|
-
await
|
|
571
|
+
await (0, __agiflowai_aicode_utils.remove)(projectPath);
|
|
544
572
|
throw new Error(`Failed to clone repository: ${error.message}`);
|
|
545
573
|
}
|
|
546
574
|
}
|
|
@@ -574,6 +602,18 @@ var openspec_default = "When working on this project, follow the OpenSpec spec-d
|
|
|
574
602
|
//#endregion
|
|
575
603
|
//#region src/specs/openspec.ts
|
|
576
604
|
/**
|
|
605
|
+
* OpenSpec Bridge Implementation
|
|
606
|
+
*
|
|
607
|
+
* DESIGN PATTERNS:
|
|
608
|
+
* - Bridge pattern implementation for OpenSpec
|
|
609
|
+
* - Singleton pattern for OpenSpec configuration
|
|
610
|
+
*
|
|
611
|
+
* CODING STANDARDS:
|
|
612
|
+
* - Implement ISpecBridge interface
|
|
613
|
+
* - Use async/await for I/O operations
|
|
614
|
+
* - Handle errors with descriptive messages
|
|
615
|
+
*/
|
|
616
|
+
/**
|
|
577
617
|
* OpenSpec configuration
|
|
578
618
|
*/
|
|
579
619
|
const OPENSPEC_CONFIG = {
|
|
@@ -639,6 +679,18 @@ var OpenSpecBridge = class {
|
|
|
639
679
|
//#endregion
|
|
640
680
|
//#region src/services/SpecToolService.ts
|
|
641
681
|
/**
|
|
682
|
+
* Spec Tool Service
|
|
683
|
+
*
|
|
684
|
+
* DESIGN PATTERNS:
|
|
685
|
+
* - Service pattern for spec tool detection and installation
|
|
686
|
+
* - Bridge pattern to abstract spec tool implementations
|
|
687
|
+
*
|
|
688
|
+
* CODING STANDARDS:
|
|
689
|
+
* - Use async/await for asynchronous operations
|
|
690
|
+
* - Handle errors with try/catch blocks
|
|
691
|
+
* - Use descriptive method names
|
|
692
|
+
*/
|
|
693
|
+
/**
|
|
642
694
|
* Available spec tools
|
|
643
695
|
*/
|
|
644
696
|
let SpecTool = /* @__PURE__ */ function(SpecTool$1) {
|
|
@@ -716,6 +768,22 @@ var SpecToolService = class {
|
|
|
716
768
|
|
|
717
769
|
//#endregion
|
|
718
770
|
//#region src/services/TemplateSelectionService.ts
|
|
771
|
+
/**
|
|
772
|
+
* TemplateSelectionService
|
|
773
|
+
*
|
|
774
|
+
* DESIGN PATTERNS:
|
|
775
|
+
* - Service pattern for business logic encapsulation
|
|
776
|
+
* - Single responsibility: Handle template download, listing, and selection
|
|
777
|
+
*
|
|
778
|
+
* CODING STANDARDS:
|
|
779
|
+
* - Use async/await for asynchronous operations
|
|
780
|
+
* - Throw descriptive errors for error cases
|
|
781
|
+
* - Document methods with JSDoc comments
|
|
782
|
+
*
|
|
783
|
+
* AVOID:
|
|
784
|
+
* - Direct UI interaction (no prompts in services)
|
|
785
|
+
* - Mixing concerns beyond template management
|
|
786
|
+
*/
|
|
719
787
|
var TemplateSelectionService = class {
|
|
720
788
|
tmpDir;
|
|
721
789
|
constructor(existingTmpDir) {
|
|
@@ -728,7 +796,7 @@ var TemplateSelectionService = class {
|
|
|
728
796
|
*/
|
|
729
797
|
async downloadTemplatesToTmp(repoConfig) {
|
|
730
798
|
try {
|
|
731
|
-
await
|
|
799
|
+
await (0, __agiflowai_aicode_utils.ensureDir)(this.tmpDir);
|
|
732
800
|
const contents = await fetchGitHubDirectoryContents(repoConfig.owner, repoConfig.repo, repoConfig.path, repoConfig.branch);
|
|
733
801
|
const templateDirs = contents.filter((item) => item.type === "dir");
|
|
734
802
|
const globalFiles = contents.filter((item) => item.type === "file" && item.name === "RULES.yaml");
|
|
@@ -746,8 +814,7 @@ var TemplateSelectionService = class {
|
|
|
746
814
|
const targetFile = node_path.default.join(this.tmpDir, "RULES.yaml");
|
|
747
815
|
const response = await fetch(rulesUrl);
|
|
748
816
|
if (response.ok) {
|
|
749
|
-
|
|
750
|
-
await fs_extra.writeFile(targetFile, content, "utf-8");
|
|
817
|
+
await (0, __agiflowai_aicode_utils.writeFile)(targetFile, await response.text(), "utf-8");
|
|
751
818
|
__agiflowai_aicode_utils.print.success("Downloaded global RULES.yaml");
|
|
752
819
|
}
|
|
753
820
|
}
|
|
@@ -764,7 +831,7 @@ var TemplateSelectionService = class {
|
|
|
764
831
|
*/
|
|
765
832
|
async listTemplates() {
|
|
766
833
|
try {
|
|
767
|
-
const entries = await
|
|
834
|
+
const entries = await (0, __agiflowai_aicode_utils.readdir)(this.tmpDir, { withFileTypes: true });
|
|
768
835
|
const templates = [];
|
|
769
836
|
for (const entry of entries) if (entry.isDirectory()) {
|
|
770
837
|
const templatePath = node_path.default.join(this.tmpDir, entry.name);
|
|
@@ -790,27 +857,27 @@ var TemplateSelectionService = class {
|
|
|
790
857
|
async copyTemplates(templateNames, destinationPath, projectType, selectedMcpServers) {
|
|
791
858
|
try {
|
|
792
859
|
if (projectType === __agiflowai_aicode_utils.ProjectType.MONOLITH && templateNames.length > 1) throw new Error("Monolith projects can only use a single template");
|
|
793
|
-
await
|
|
860
|
+
await (0, __agiflowai_aicode_utils.ensureDir)(destinationPath);
|
|
794
861
|
__agiflowai_aicode_utils.print.info(`\nCopying templates to ${destinationPath}...`);
|
|
795
862
|
for (const templateName of templateNames) {
|
|
796
863
|
const sourcePath = node_path.default.join(this.tmpDir, templateName);
|
|
797
864
|
const targetPath = node_path.default.join(destinationPath, templateName);
|
|
798
|
-
if (!await
|
|
799
|
-
if (await
|
|
865
|
+
if (!await (0, __agiflowai_aicode_utils.pathExists)(sourcePath)) throw new Error(`Template '${templateName}' not found in downloaded templates`);
|
|
866
|
+
if (await (0, __agiflowai_aicode_utils.pathExists)(targetPath)) {
|
|
800
867
|
__agiflowai_aicode_utils.print.info(`Skipping ${templateName} (already exists)`);
|
|
801
868
|
continue;
|
|
802
869
|
}
|
|
803
870
|
__agiflowai_aicode_utils.print.info(`Copying ${templateName}...`);
|
|
804
871
|
if (selectedMcpServers && selectedMcpServers.length > 0) await this.copyTemplateWithMcpFilter(sourcePath, targetPath, selectedMcpServers);
|
|
805
|
-
else await
|
|
872
|
+
else await (0, __agiflowai_aicode_utils.copy)(sourcePath, targetPath);
|
|
806
873
|
__agiflowai_aicode_utils.print.success(`Copied ${templateName}`);
|
|
807
874
|
}
|
|
808
875
|
const globalRulesSource = node_path.default.join(this.tmpDir, "RULES.yaml");
|
|
809
876
|
const globalRulesTarget = node_path.default.join(destinationPath, "RULES.yaml");
|
|
810
|
-
if (await
|
|
811
|
-
if (!await
|
|
877
|
+
if (await (0, __agiflowai_aicode_utils.pathExists)(globalRulesSource)) {
|
|
878
|
+
if (!await (0, __agiflowai_aicode_utils.pathExists)(globalRulesTarget)) {
|
|
812
879
|
__agiflowai_aicode_utils.print.info("Copying global RULES.yaml...");
|
|
813
|
-
await
|
|
880
|
+
await (0, __agiflowai_aicode_utils.copy)(globalRulesSource, globalRulesTarget);
|
|
814
881
|
__agiflowai_aicode_utils.print.success("Copied global RULES.yaml");
|
|
815
882
|
}
|
|
816
883
|
}
|
|
@@ -830,19 +897,19 @@ var TemplateSelectionService = class {
|
|
|
830
897
|
const architectFiles = MCP_CONFIG_FILES$1[MCPServer$1.ARCHITECT];
|
|
831
898
|
const hasArchitect = selectedMcpServers.includes(MCPServer$1.ARCHITECT);
|
|
832
899
|
const hasScaffold = selectedMcpServers.includes(MCPServer$1.SCAFFOLD);
|
|
833
|
-
await
|
|
834
|
-
const entries = await
|
|
900
|
+
await (0, __agiflowai_aicode_utils.ensureDir)(targetPath);
|
|
901
|
+
const entries = await (0, __agiflowai_aicode_utils.readdir)(sourcePath, { withFileTypes: true });
|
|
835
902
|
for (const entry of entries) {
|
|
836
903
|
const entrySourcePath = node_path.default.join(sourcePath, entry.name);
|
|
837
904
|
const entryTargetPath = node_path.default.join(targetPath, entry.name);
|
|
838
905
|
const isArchitectFile = architectFiles.includes(entry.name);
|
|
839
|
-
if (hasArchitect && hasScaffold) if (entry.isDirectory()) await
|
|
840
|
-
else await
|
|
906
|
+
if (hasArchitect && hasScaffold) if (entry.isDirectory()) await (0, __agiflowai_aicode_utils.copy)(entrySourcePath, entryTargetPath);
|
|
907
|
+
else await (0, __agiflowai_aicode_utils.copy)(entrySourcePath, entryTargetPath);
|
|
841
908
|
else if (hasArchitect && !hasScaffold) {
|
|
842
|
-
if (isArchitectFile) await
|
|
909
|
+
if (isArchitectFile) await (0, __agiflowai_aicode_utils.copy)(entrySourcePath, entryTargetPath);
|
|
843
910
|
} else if (!hasArchitect && hasScaffold) {
|
|
844
|
-
if (!isArchitectFile) if (entry.isDirectory()) await
|
|
845
|
-
else await
|
|
911
|
+
if (!isArchitectFile) if (entry.isDirectory()) await (0, __agiflowai_aicode_utils.copy)(entrySourcePath, entryTargetPath);
|
|
912
|
+
else await (0, __agiflowai_aicode_utils.copy)(entrySourcePath, entryTargetPath);
|
|
846
913
|
}
|
|
847
914
|
}
|
|
848
915
|
}
|
|
@@ -854,15 +921,15 @@ var TemplateSelectionService = class {
|
|
|
854
921
|
async readTemplateDescription(templatePath) {
|
|
855
922
|
try {
|
|
856
923
|
const scaffoldYamlPath = node_path.default.join(templatePath, "scaffold.yaml");
|
|
857
|
-
if (await
|
|
924
|
+
if (await (0, __agiflowai_aicode_utils.pathExists)(scaffoldYamlPath)) {
|
|
858
925
|
const yaml = await import("js-yaml");
|
|
859
|
-
const content = await
|
|
926
|
+
const content = await (0, __agiflowai_aicode_utils.readFile)(scaffoldYamlPath, "utf-8");
|
|
860
927
|
const scaffoldConfig = yaml.load(content);
|
|
861
928
|
if (scaffoldConfig?.description) return scaffoldConfig.description;
|
|
862
929
|
if (scaffoldConfig?.boilerplate?.[0]?.description) return scaffoldConfig.boilerplate[0].description;
|
|
863
930
|
}
|
|
864
931
|
const readmePath = node_path.default.join(templatePath, "README.md");
|
|
865
|
-
if (await
|
|
932
|
+
if (await (0, __agiflowai_aicode_utils.pathExists)(readmePath)) return (await (0, __agiflowai_aicode_utils.readFile)(readmePath, "utf-8")).split("\n\n")[0].substring(0, 200).trim();
|
|
866
933
|
return;
|
|
867
934
|
} catch {
|
|
868
935
|
return;
|
|
@@ -879,7 +946,7 @@ var TemplateSelectionService = class {
|
|
|
879
946
|
*/
|
|
880
947
|
async cleanup() {
|
|
881
948
|
try {
|
|
882
|
-
if (await
|
|
949
|
+
if (await (0, __agiflowai_aicode_utils.pathExists)(this.tmpDir)) await (0, __agiflowai_aicode_utils.remove)(this.tmpDir);
|
|
883
950
|
} catch (error) {
|
|
884
951
|
__agiflowai_aicode_utils.print.warning(`Warning: Failed to clean up tmp directory: ${error.message}`);
|
|
885
952
|
}
|
|
@@ -888,6 +955,23 @@ var TemplateSelectionService = class {
|
|
|
888
955
|
|
|
889
956
|
//#endregion
|
|
890
957
|
//#region src/services/TemplatesService.ts
|
|
958
|
+
/**
|
|
959
|
+
* TemplatesService
|
|
960
|
+
*
|
|
961
|
+
* DESIGN PATTERNS:
|
|
962
|
+
* - Service pattern for business logic encapsulation
|
|
963
|
+
* - Single responsibility principle
|
|
964
|
+
*
|
|
965
|
+
* CODING STANDARDS:
|
|
966
|
+
* - Use async/await for asynchronous operations
|
|
967
|
+
* - Throw descriptive errors for error cases
|
|
968
|
+
* - Keep methods focused and well-named
|
|
969
|
+
* - Document complex logic with comments
|
|
970
|
+
*
|
|
971
|
+
* AVOID:
|
|
972
|
+
* - Mixing concerns (keep focused on single domain)
|
|
973
|
+
* - Direct tool implementation (services should be tool-agnostic)
|
|
974
|
+
*/
|
|
891
975
|
var TemplatesService = class {
|
|
892
976
|
/**
|
|
893
977
|
* Download templates from a GitHub repository with UI feedback
|
|
@@ -907,7 +991,7 @@ var TemplatesService = class {
|
|
|
907
991
|
let _skipped = 0;
|
|
908
992
|
for (const template of templateDirs) {
|
|
909
993
|
const targetFolder = node_path.default.join(templatesPath, template.name);
|
|
910
|
-
if (await
|
|
994
|
+
if (await (0, __agiflowai_aicode_utils.pathExists)(targetFolder)) {
|
|
911
995
|
__agiflowai_aicode_utils.print.info(`Skipping ${template.name} (already exists)`);
|
|
912
996
|
_skipped++;
|
|
913
997
|
continue;
|
|
@@ -927,8 +1011,8 @@ var TemplatesService = class {
|
|
|
927
1011
|
* @param templatesPath - Path where templates folder should be created
|
|
928
1012
|
*/
|
|
929
1013
|
async initializeTemplatesFolder(templatesPath) {
|
|
930
|
-
await
|
|
931
|
-
await
|
|
1014
|
+
await (0, __agiflowai_aicode_utils.ensureDir)(templatesPath);
|
|
1015
|
+
await (0, __agiflowai_aicode_utils.writeFile)(node_path.default.join(templatesPath, "README.md"), `# Templates
|
|
932
1016
|
|
|
933
1017
|
This folder contains boilerplate templates and scaffolding methods for your projects.
|
|
934
1018
|
|