@agiflowai/aicode-toolkit 0.6.0 → 1.0.2
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 +401 -123
- package/dist/cli.js +401 -124
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +15 -1
- package/dist/index.d.ts +15 -1
- package/dist/index.js +1 -1
- package/dist/{services-s1vmufE4.cjs → services-C6lqyioO.cjs} +243 -26
- package/dist/{services-DNldrNnu.js → services-zrdafWTg.js} +257 -60
- package/package.json +6 -4
package/dist/index.cjs
CHANGED
package/dist/index.d.cts
CHANGED
|
@@ -67,7 +67,7 @@ declare class CodingAgentService {
|
|
|
67
67
|
constructor(workspaceRoot: string);
|
|
68
68
|
/**
|
|
69
69
|
* Detect which coding agent is enabled in the workspace
|
|
70
|
-
* Checks for Claude Code, Codex,
|
|
70
|
+
* Checks for Claude Code, Codex, Gemini CLI, GitHub Copilot, and Cursor installations
|
|
71
71
|
* @param workspaceRoot - The workspace root directory
|
|
72
72
|
* @returns Promise resolving to detected agent ID or null
|
|
73
73
|
*/
|
|
@@ -80,6 +80,20 @@ declare class CodingAgentService {
|
|
|
80
80
|
name: string;
|
|
81
81
|
description: string;
|
|
82
82
|
}>;
|
|
83
|
+
/**
|
|
84
|
+
* Get the coding agent service instance
|
|
85
|
+
* @param agent - The coding agent to get service for
|
|
86
|
+
* @returns The service instance or null if not supported
|
|
87
|
+
*/
|
|
88
|
+
private getCodingAgentService;
|
|
89
|
+
/**
|
|
90
|
+
* Update custom instructions/prompts for the coding agent
|
|
91
|
+
* Appends custom instruction prompt to the agent's configuration
|
|
92
|
+
* @param agent - The coding agent to update
|
|
93
|
+
* @param instructionPrompt - The instruction prompt to append
|
|
94
|
+
* @param customInstructionFile - Optional custom file path to write instructions to (e.g., '.claude/aicode-instructions.md')
|
|
95
|
+
*/
|
|
96
|
+
updateCustomInstructions(agent: CodingAgent, instructionPrompt: string, customInstructionFile?: string): Promise<void>;
|
|
83
97
|
/**
|
|
84
98
|
* Setup MCP configuration for the selected coding agent
|
|
85
99
|
* @param agent - The coding agent to configure
|
package/dist/index.d.ts
CHANGED
|
@@ -67,7 +67,7 @@ declare class CodingAgentService {
|
|
|
67
67
|
constructor(workspaceRoot: string);
|
|
68
68
|
/**
|
|
69
69
|
* Detect which coding agent is enabled in the workspace
|
|
70
|
-
* Checks for Claude Code, Codex,
|
|
70
|
+
* Checks for Claude Code, Codex, Gemini CLI, GitHub Copilot, and Cursor installations
|
|
71
71
|
* @param workspaceRoot - The workspace root directory
|
|
72
72
|
* @returns Promise resolving to detected agent ID or null
|
|
73
73
|
*/
|
|
@@ -80,6 +80,20 @@ declare class CodingAgentService {
|
|
|
80
80
|
name: string;
|
|
81
81
|
description: string;
|
|
82
82
|
}>;
|
|
83
|
+
/**
|
|
84
|
+
* Get the coding agent service instance
|
|
85
|
+
* @param agent - The coding agent to get service for
|
|
86
|
+
* @returns The service instance or null if not supported
|
|
87
|
+
*/
|
|
88
|
+
private getCodingAgentService;
|
|
89
|
+
/**
|
|
90
|
+
* Update custom instructions/prompts for the coding agent
|
|
91
|
+
* Appends custom instruction prompt to the agent's configuration
|
|
92
|
+
* @param agent - The coding agent to update
|
|
93
|
+
* @param instructionPrompt - The instruction prompt to append
|
|
94
|
+
* @param customInstructionFile - Optional custom file path to write instructions to (e.g., '.claude/aicode-instructions.md')
|
|
95
|
+
*/
|
|
96
|
+
updateCustomInstructions(agent: CodingAgent, instructionPrompt: string, customInstructionFile?: string): Promise<void>;
|
|
83
97
|
/**
|
|
84
98
|
* Setup MCP configuration for the selected coding agent
|
|
85
99
|
* @param agent - The coding agent to configure
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import "./mcp-BmhiAfeF.js";
|
|
2
|
-
import { BANNER_GRADIENT, CodingAgentService, NewProjectService, THEME, TemplateSelectionService, TemplatesService, cloneRepository, cloneSubdirectory, displayBanner, displayCompactBanner, fetchGitHubDirectoryContents, findWorkspaceRoot, gitInit, parseGitHubUrl } from "./services-
|
|
2
|
+
import { BANNER_GRADIENT, CodingAgentService, NewProjectService, THEME, TemplateSelectionService, TemplatesService, cloneRepository, cloneSubdirectory, displayBanner, displayCompactBanner, fetchGitHubDirectoryContents, findWorkspaceRoot, gitInit, parseGitHubUrl } from "./services-zrdafWTg.js";
|
|
3
3
|
|
|
4
4
|
export { BANNER_GRADIENT, CodingAgentService, NewProjectService, THEME, TemplateSelectionService, TemplatesService, cloneRepository, cloneSubdirectory, displayBanner, displayCompactBanner, fetchGitHubDirectoryContents, findWorkspaceRoot, gitInit, parseGitHubUrl };
|
|
@@ -35,6 +35,10 @@ let execa = require("execa");
|
|
|
35
35
|
execa = __toESM(execa);
|
|
36
36
|
let __agiflowai_coding_agent_bridge = require("@agiflowai/coding-agent-bridge");
|
|
37
37
|
__agiflowai_coding_agent_bridge = __toESM(__agiflowai_coding_agent_bridge);
|
|
38
|
+
let node_fs_promises = require("node:fs/promises");
|
|
39
|
+
node_fs_promises = __toESM(node_fs_promises);
|
|
40
|
+
let liquidjs = require("liquidjs");
|
|
41
|
+
liquidjs = __toESM(liquidjs);
|
|
38
42
|
let node_os = require("node:os");
|
|
39
43
|
node_os = __toESM(node_os);
|
|
40
44
|
|
|
@@ -194,11 +198,11 @@ function parseGitHubUrl(url) {
|
|
|
194
198
|
if (treeMatch || blobMatch) {
|
|
195
199
|
const match = treeMatch || blobMatch;
|
|
196
200
|
return {
|
|
197
|
-
owner: match[1],
|
|
198
|
-
repo: match[2],
|
|
199
|
-
repoUrl: `https://github.com/${match[1]}/${match[2]}.git`,
|
|
200
|
-
branch: match[3],
|
|
201
|
-
subdirectory: match[4],
|
|
201
|
+
owner: match?.[1],
|
|
202
|
+
repo: match?.[2],
|
|
203
|
+
repoUrl: `https://github.com/${match?.[1]}/${match?.[2]}.git`,
|
|
204
|
+
branch: match?.[3],
|
|
205
|
+
subdirectory: match?.[4],
|
|
202
206
|
isSubdirectory: true
|
|
203
207
|
};
|
|
204
208
|
}
|
|
@@ -264,8 +268,8 @@ async function cloneRepository(repoUrl, targetFolder) {
|
|
|
264
268
|
/**
|
|
265
269
|
* Fetch directory listing from GitHub API
|
|
266
270
|
*/
|
|
267
|
-
async function fetchGitHubDirectoryContents(owner, repo, path$
|
|
268
|
-
const url = `https://api.github.com/repos/${owner}/${repo}/contents/${path$
|
|
271
|
+
async function fetchGitHubDirectoryContents(owner, repo, path$4, branch = "main") {
|
|
272
|
+
const url = `https://api.github.com/repos/${owner}/${repo}/contents/${path$4}?ref=${branch}`;
|
|
269
273
|
const response = await fetch(url, { headers: {
|
|
270
274
|
Accept: "application/vnd.github.v3+json",
|
|
271
275
|
"User-Agent": "scaffold-mcp"
|
|
@@ -289,12 +293,14 @@ var CodingAgentService = class {
|
|
|
289
293
|
}
|
|
290
294
|
/**
|
|
291
295
|
* Detect which coding agent is enabled in the workspace
|
|
292
|
-
* Checks for Claude Code, Codex,
|
|
296
|
+
* Checks for Claude Code, Codex, Gemini CLI, GitHub Copilot, and Cursor installations
|
|
293
297
|
* @param workspaceRoot - The workspace root directory
|
|
294
298
|
* @returns Promise resolving to detected agent ID or null
|
|
295
299
|
*/
|
|
296
300
|
static async detectCodingAgent(workspaceRoot) {
|
|
297
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;
|
|
298
304
|
if (await new __agiflowai_coding_agent_bridge.CodexService({ workspaceRoot }).isEnabled()) return __agiflowai_coding_agent_bridge.CODEX;
|
|
299
305
|
if (await new __agiflowai_coding_agent_bridge.GeminiCliService({ workspaceRoot }).isEnabled()) return __agiflowai_coding_agent_bridge.GEMINI_CLI;
|
|
300
306
|
return null;
|
|
@@ -309,6 +315,16 @@ var CodingAgentService = class {
|
|
|
309
315
|
name: "Claude Code",
|
|
310
316
|
description: "Anthropic Claude Code CLI agent"
|
|
311
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
|
+
},
|
|
312
328
|
{
|
|
313
329
|
value: __agiflowai_coding_agent_bridge.CODEX,
|
|
314
330
|
name: "Codex",
|
|
@@ -327,6 +343,48 @@ var CodingAgentService = class {
|
|
|
327
343
|
];
|
|
328
344
|
}
|
|
329
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
|
+
/**
|
|
330
388
|
* Setup MCP configuration for the selected coding agent
|
|
331
389
|
* @param agent - The coding agent to configure
|
|
332
390
|
*/
|
|
@@ -336,19 +394,22 @@ var CodingAgentService = class {
|
|
|
336
394
|
return;
|
|
337
395
|
}
|
|
338
396
|
__agiflowai_aicode_utils.print.info(`\nSetting up MCP for ${agent}...`);
|
|
339
|
-
|
|
397
|
+
const service = this.getCodingAgentService(agent);
|
|
340
398
|
let configLocation = "";
|
|
341
399
|
let restartInstructions = "";
|
|
342
400
|
if (agent === __agiflowai_coding_agent_bridge.CLAUDE_CODE) {
|
|
343
|
-
service = new __agiflowai_coding_agent_bridge.ClaudeCodeService({ workspaceRoot: this.workspaceRoot });
|
|
344
401
|
configLocation = ".mcp.json";
|
|
345
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";
|
|
346
409
|
} else if (agent === __agiflowai_coding_agent_bridge.CODEX) {
|
|
347
|
-
service = new __agiflowai_coding_agent_bridge.CodexService({ workspaceRoot: this.workspaceRoot });
|
|
348
410
|
configLocation = "~/.codex/config.toml";
|
|
349
411
|
restartInstructions = "Restart Codex CLI to load the new MCP servers";
|
|
350
412
|
} else if (agent === __agiflowai_coding_agent_bridge.GEMINI_CLI) {
|
|
351
|
-
service = new __agiflowai_coding_agent_bridge.GeminiCliService({ workspaceRoot: this.workspaceRoot });
|
|
352
413
|
configLocation = "~/.gemini/settings.json";
|
|
353
414
|
restartInstructions = "Restart Gemini CLI to load the new MCP servers";
|
|
354
415
|
}
|
|
@@ -463,7 +524,6 @@ var NewProjectService = class {
|
|
|
463
524
|
async createProjectDirectory(projectPath, projectName) {
|
|
464
525
|
try {
|
|
465
526
|
await fs_extra.mkdir(projectPath, { recursive: false });
|
|
466
|
-
__agiflowai_aicode_utils.print.success(`Created project directory: ${projectPath}`);
|
|
467
527
|
} catch (error) {
|
|
468
528
|
if (error.code === "EEXIST") throw new Error(`Directory '${projectName}' already exists. Please choose a different name.`);
|
|
469
529
|
throw error;
|
|
@@ -475,12 +535,10 @@ var NewProjectService = class {
|
|
|
475
535
|
* @param projectPath - Destination path for the cloned repository
|
|
476
536
|
*/
|
|
477
537
|
async cloneExistingRepository(repoUrl, projectPath) {
|
|
478
|
-
__agiflowai_aicode_utils.print.info("Cloning repository...");
|
|
479
538
|
try {
|
|
480
539
|
const parsed = parseGitHubUrl(repoUrl.trim());
|
|
481
540
|
if (parsed.isSubdirectory && parsed.branch && parsed.subdirectory) await cloneSubdirectory(parsed.repoUrl, parsed.branch, parsed.subdirectory, projectPath);
|
|
482
541
|
else await cloneRepository(parsed.repoUrl, projectPath);
|
|
483
|
-
__agiflowai_aicode_utils.print.success("Repository cloned successfully");
|
|
484
542
|
} catch (error) {
|
|
485
543
|
await fs_extra.remove(projectPath);
|
|
486
544
|
throw new Error(`Failed to clone repository: ${error.message}`);
|
|
@@ -491,10 +549,8 @@ var NewProjectService = class {
|
|
|
491
549
|
* @param projectPath - Path where git repository should be initialized
|
|
492
550
|
*/
|
|
493
551
|
async initializeGitRepository(projectPath) {
|
|
494
|
-
__agiflowai_aicode_utils.print.info("Initializing Git repository...");
|
|
495
552
|
try {
|
|
496
553
|
await gitInit(projectPath);
|
|
497
|
-
__agiflowai_aicode_utils.print.success("Git repository initialized");
|
|
498
554
|
} catch (error) {
|
|
499
555
|
__agiflowai_aicode_utils.messages.warning(`Failed to initialize Git: ${error.message}`);
|
|
500
556
|
}
|
|
@@ -511,6 +567,153 @@ var NewProjectService = class {
|
|
|
511
567
|
}
|
|
512
568
|
};
|
|
513
569
|
|
|
570
|
+
//#endregion
|
|
571
|
+
//#region src/instructions/specs/openspec.md?raw
|
|
572
|
+
var openspec_default = "When working on this project, follow the OpenSpec spec-driven development workflow{% if scaffoldMcp or architectMcp %} integrated with MCP tools{% endif %}.\n\n{% if scaffoldMcp %}\n\n## {% if scaffoldMcp %}1{% else %}1{% endif %}. Create Proposals with scaffold-mcp\n\nWhen implementing new features or changes, use scaffold-mcp MCP tools:\n\n**For new projects/features:**\n1. Use `list-boilerplates` MCP tool to see available templates\n2. Use `use-boilerplate` MCP tool to scaffold new projects{% if projectType == 'monolith' %} (set `monolith: true`){% elsif projectType == 'monorepo' %} (omit `monolith` parameter){% endif %}\n3. Use `list-scaffolding-methods` MCP tool to understand which methods can be used to add features\n4. Create OpenSpec proposal with available scaffolding methods in mind: \"Create an OpenSpec proposal for [feature description]\"\n\n**For adding features to existing code:**\n1. Use `list-scaffolding-methods` MCP tool with projectPath to see available features{% if projectType == 'monolith' %} (`projectPath` = workspace root){% elsif projectType == 'monorepo' %} (`projectPath` = project directory with project.json){% endif %}\n2. Review available methods and plan which ones to use for the feature\n3. Use `use-scaffold-method` MCP tool to generate boilerplate code\n4. Create OpenSpec proposal to capture the specs\n{% if projectType %}\n\n**Path Mapping ({% if projectType == 'monolith' %}Monolith{% else %}Monorepo{% endif %} Project):**\n{% if projectType == 'monolith' %}\n*This is a monolith project:*\n- Single project at workspace root\n- Config file: `toolkit.yaml` at root\n- All code in workspace root (src/, lib/, etc.)\n- When scaffolding: Use `monolith: true` parameter\n- When using scaffold methods: `projectPath` = workspace root\n\nExample: For workspace at `/path/to/project`:\n- Project config: `/path/to/project/toolkit.yaml`\n- Source code: `/path/to/project/src/`\n- OpenSpec: `/path/to/project/openspec/`\n{% else %}\n*This is a monorepo project:*\n- Multiple projects in subdirectories\n- Config file: `project.json` in each project\n- Projects in apps/, packages/, libs/, etc.\n- When scaffolding: Omit `monolith` parameter (defaults to false)\n- When using scaffold methods: `projectPath` = path to specific project\n\nExample: For workspace at `/path/to/workspace`:\n- App config: `/path/to/workspace/apps/my-app/project.json`\n- App source: `/path/to/workspace/apps/my-app/src/`\n- OpenSpec: `/path/to/workspace/openspec/` (workspace-level)\n{% endif %}\n{% endif %}\n\nAI will scaffold: openspec/changes/[feature-name]/ with proposal.md, tasks.md, and spec deltas\n{% endif %}\n{% if architectMcp %}\n\n## {% if scaffoldMcp %}2{% else %}1{% endif %}. Review & Validate with architect-mcp\n\nBefore and after editing files, use architect-mcp MCP tools:\n\n**Before editing:**\n- Use `get-file-design-pattern` MCP tool to understand:\n - Applicable design patterns from architect.yaml\n - Coding rules from RULES.yaml (must_do, should_do, must_not_do)\n - Code examples showing the patterns\n\n**After editing:**\n- Use `review-code-change` MCP tool to check for:\n - Must not do violations (critical issues)\n - Must do missing (required patterns not followed)\n - Should do suggestions (best practices)\n\n**Validate OpenSpec specs:**\n- Use `openspec validate [feature-name]` to check spec formatting\n- Iterate with AI until specs are agreed upon\n{% endif %}\n\n## {% if scaffoldMcp and architectMcp %}3{% elsif scaffoldMcp or architectMcp %}2{% else %}1{% endif %}. Implement{% if architectMcp %} with MCP-Guided Development{% endif %}\n\nDuring implementation:\n1. Ask AI to implement: \"Apply the OpenSpec change [feature-name]\"\n{% if architectMcp %}\n2. **Before each file edit**: Use `get-file-design-pattern` to understand patterns\n3. AI implements tasks from tasks.md following design patterns\n4. **After each file edit**: Use `review-code-change` to verify compliance\n5. Fix any violations before proceeding\n{% else %}\n2. AI implements tasks from tasks.md following the agreed specs\n{% endif %}\n\n## {% if scaffoldMcp and architectMcp %}4{% elsif scaffoldMcp or architectMcp %}3{% else %}2{% endif %}. Archive Completed Changes\n{% if scaffoldMcp or architectMcp %}\n\n## MCP Tools Reference\n{% endif %}\n{% if scaffoldMcp %}\n\n### scaffold-mcp\n- `list-boilerplates` - List available project templates\n- `use-boilerplate` - Create new project from template\n- `list-scaffolding-methods` - List features for existing project\n- `use-scaffold-method` - Add feature to existing project\n{% endif %}\n{% if architectMcp %}\n\n### architect-mcp\n- `get-file-design-pattern` - Get design patterns for file\n- `review-code-change` - Review code for violations\n{% endif %}\n\n## Workflow Summary\n\n{% if scaffoldMcp %}\n1. **Plan**: Use scaffold-mcp to generate boilerplate + OpenSpec proposal for specs\n{% else %}\n1. **Plan**: Create OpenSpec proposal with specs\n{% endif %}\n{% if architectMcp %}\n{% if scaffoldMcp %}2{% else %}2{% endif %}. **Design**: Use architect-mcp to understand patterns before editing\n{% endif %}\n{% if scaffoldMcp and architectMcp %}3{% elsif scaffoldMcp or architectMcp %}{% if architectMcp %}3{% else %}2{% endif %}{% else %}2{% endif %}. **Implement**: Follow specs{% if architectMcp %} and patterns{% endif %}\n{% if architectMcp %}\n{% if scaffoldMcp %}4{% else %}4{% endif %}. **Review**: Use architect-mcp to validate code quality\n{% endif %}\n{% if scaffoldMcp and architectMcp %}5{% elsif scaffoldMcp or architectMcp %}{% if architectMcp %}5{% else %}3{% endif %}{% else %}3{% endif %}. **Archive**: Merge specs into source of truth\n";
|
|
573
|
+
|
|
574
|
+
//#endregion
|
|
575
|
+
//#region src/specs/openspec.ts
|
|
576
|
+
/**
|
|
577
|
+
* OpenSpec configuration
|
|
578
|
+
*/
|
|
579
|
+
const OPENSPEC_CONFIG = {
|
|
580
|
+
folderName: "openspec",
|
|
581
|
+
packageName: "@fission-ai/openspec",
|
|
582
|
+
name: "OpenSpec",
|
|
583
|
+
description: "Spec-driven development for AI coding assistants"
|
|
584
|
+
};
|
|
585
|
+
/**
|
|
586
|
+
* Bridge implementation for OpenSpec
|
|
587
|
+
*
|
|
588
|
+
* Provides integration with OpenSpec spec tool through a standardized interface.
|
|
589
|
+
*/
|
|
590
|
+
var OpenSpecBridge = class {
|
|
591
|
+
/**
|
|
592
|
+
* Check if OpenSpec is enabled/installed in the workspace
|
|
593
|
+
*
|
|
594
|
+
* @param workspaceRoot - Absolute path to the workspace root directory
|
|
595
|
+
* @returns Promise resolving to true if OpenSpec folder exists, false otherwise
|
|
596
|
+
*/
|
|
597
|
+
async isEnabled(workspaceRoot) {
|
|
598
|
+
try {
|
|
599
|
+
const openspecPath = node_path.default.join(workspaceRoot, OPENSPEC_CONFIG.folderName);
|
|
600
|
+
await node_fs_promises.default.access(openspecPath);
|
|
601
|
+
return true;
|
|
602
|
+
} catch {
|
|
603
|
+
return false;
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
607
|
+
* Initialize OpenSpec in the workspace
|
|
608
|
+
*
|
|
609
|
+
* Runs `npx @fission-ai/openspec init` interactively, allowing the user
|
|
610
|
+
* to configure OpenSpec during setup.
|
|
611
|
+
*
|
|
612
|
+
* @param workspaceRoot - Absolute path to the workspace root directory
|
|
613
|
+
* @throws Error if initialization fails
|
|
614
|
+
*/
|
|
615
|
+
async initialize(workspaceRoot) {
|
|
616
|
+
try {
|
|
617
|
+
await (0, execa.execa)("npx", [OPENSPEC_CONFIG.packageName, "init"], {
|
|
618
|
+
cwd: workspaceRoot,
|
|
619
|
+
stdio: "inherit"
|
|
620
|
+
});
|
|
621
|
+
} catch (error) {
|
|
622
|
+
throw new Error(`Failed to initialize ${OPENSPEC_CONFIG.name}: ${error.message}`);
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
/**
|
|
626
|
+
* Generate agent instruction prompt for OpenSpec with MCP integration
|
|
627
|
+
*
|
|
628
|
+
* Creates a comprehensive instruction prompt that guides AI agents to use
|
|
629
|
+
* spec-driven development workflow with OpenSpec, leveraging enabled MCP servers.
|
|
630
|
+
*
|
|
631
|
+
* @param enabledMcps - Configuration of which MCP servers are enabled
|
|
632
|
+
* @returns Promise resolving to the instruction prompt string
|
|
633
|
+
*/
|
|
634
|
+
async updateInstruction(enabledMcps) {
|
|
635
|
+
return (await new liquidjs.Liquid().parseAndRender(openspec_default, enabledMcps)).trim();
|
|
636
|
+
}
|
|
637
|
+
};
|
|
638
|
+
|
|
639
|
+
//#endregion
|
|
640
|
+
//#region src/services/SpecToolService.ts
|
|
641
|
+
/**
|
|
642
|
+
* Available spec tools
|
|
643
|
+
*/
|
|
644
|
+
let SpecTool = /* @__PURE__ */ function(SpecTool$1) {
|
|
645
|
+
SpecTool$1["OPENSPEC"] = "openspec";
|
|
646
|
+
return SpecTool$1;
|
|
647
|
+
}({});
|
|
648
|
+
/**
|
|
649
|
+
* Spec tool information
|
|
650
|
+
*/
|
|
651
|
+
const SPEC_TOOL_INFO = { [SpecTool.OPENSPEC]: {
|
|
652
|
+
name: "OpenSpec",
|
|
653
|
+
description: "Spec-driven development for AI coding assistants",
|
|
654
|
+
docUrl: "https://github.com/Fission-AI/OpenSpec"
|
|
655
|
+
} };
|
|
656
|
+
/**
|
|
657
|
+
* Service for managing spec tools (e.g., OpenSpec)
|
|
658
|
+
*
|
|
659
|
+
* This service acts as a facade for spec tool operations, using bridge
|
|
660
|
+
* implementations to interact with specific spec tools.
|
|
661
|
+
*/
|
|
662
|
+
var SpecToolService = class {
|
|
663
|
+
bridge;
|
|
664
|
+
constructor(workspaceRoot, specTool = SpecTool.OPENSPEC, codingAgentService) {
|
|
665
|
+
this.workspaceRoot = workspaceRoot;
|
|
666
|
+
this.codingAgentService = codingAgentService;
|
|
667
|
+
this.bridge = this.createBridge(specTool);
|
|
668
|
+
}
|
|
669
|
+
/**
|
|
670
|
+
* Create a bridge instance for the specified spec tool
|
|
671
|
+
*/
|
|
672
|
+
createBridge(specTool) {
|
|
673
|
+
switch (specTool) {
|
|
674
|
+
case SpecTool.OPENSPEC: return new OpenSpecBridge();
|
|
675
|
+
default: throw new Error(`Unsupported spec tool: ${specTool}`);
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
/**
|
|
679
|
+
* Detect if a spec tool is installed in the workspace
|
|
680
|
+
*/
|
|
681
|
+
async detectSpecTool() {
|
|
682
|
+
try {
|
|
683
|
+
return await this.bridge.isEnabled(this.workspaceRoot) ? SpecTool.OPENSPEC : null;
|
|
684
|
+
} catch (error) {
|
|
685
|
+
__agiflowai_aicode_utils.print.error(`Error detecting spec tool: ${error.message}`);
|
|
686
|
+
return null;
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
/**
|
|
690
|
+
* Initialize the spec tool in the workspace
|
|
691
|
+
*/
|
|
692
|
+
async initializeSpec() {
|
|
693
|
+
await this.bridge.initialize(this.workspaceRoot);
|
|
694
|
+
}
|
|
695
|
+
/**
|
|
696
|
+
* Update spec tool agent instructions
|
|
697
|
+
*
|
|
698
|
+
* Generates instruction prompt and updates the coding agent's custom instructions
|
|
699
|
+
*
|
|
700
|
+
* @param enabledMcps - Configuration of which MCP servers are enabled
|
|
701
|
+
* @param codingAgent - The coding agent to update instructions for
|
|
702
|
+
* @param customInstructionFile - Optional custom file to write instructions to (e.g., '.claude/aicode-instructions.md')
|
|
703
|
+
* @returns Promise resolving to the instruction prompt string
|
|
704
|
+
*/
|
|
705
|
+
async updateInstructions(enabledMcps, codingAgent, customInstructionFile) {
|
|
706
|
+
const prompt = await this.bridge.updateInstruction(enabledMcps);
|
|
707
|
+
if (this.codingAgentService && codingAgent) await this.codingAgentService.updateCustomInstructions(codingAgent, prompt, customInstructionFile ?? ".claude/aicode-instructions.md");
|
|
708
|
+
else {
|
|
709
|
+
__agiflowai_aicode_utils.print.info("\nGenerated OpenSpec instruction prompt:");
|
|
710
|
+
__agiflowai_aicode_utils.print.info("\nYou can append this to your CLAUDE.md or agent config file:");
|
|
711
|
+
__agiflowai_aicode_utils.print.info(`\n${prompt}`);
|
|
712
|
+
}
|
|
713
|
+
return prompt;
|
|
714
|
+
}
|
|
715
|
+
};
|
|
716
|
+
|
|
514
717
|
//#endregion
|
|
515
718
|
//#region src/services/TemplateSelectionService.ts
|
|
516
719
|
var TemplateSelectionService = class {
|
|
@@ -524,7 +727,6 @@ var TemplateSelectionService = class {
|
|
|
524
727
|
* @returns Path to the tmp directory containing templates
|
|
525
728
|
*/
|
|
526
729
|
async downloadTemplatesToTmp(repoConfig) {
|
|
527
|
-
__agiflowai_aicode_utils.print.info(`Downloading templates from ${repoConfig.owner}/${repoConfig.repo}...`);
|
|
528
730
|
try {
|
|
529
731
|
await fs_extra.ensureDir(this.tmpDir);
|
|
530
732
|
const contents = await fetchGitHubDirectoryContents(repoConfig.owner, repoConfig.repo, repoConfig.path, repoConfig.branch);
|
|
@@ -677,10 +879,7 @@ var TemplateSelectionService = class {
|
|
|
677
879
|
*/
|
|
678
880
|
async cleanup() {
|
|
679
881
|
try {
|
|
680
|
-
if (await fs_extra.pathExists(this.tmpDir))
|
|
681
|
-
await fs_extra.remove(this.tmpDir);
|
|
682
|
-
__agiflowai_aicode_utils.print.info("Cleaned up temporary files");
|
|
683
|
-
}
|
|
882
|
+
if (await fs_extra.pathExists(this.tmpDir)) await fs_extra.remove(this.tmpDir);
|
|
684
883
|
} catch (error) {
|
|
685
884
|
__agiflowai_aicode_utils.print.warning(`Warning: Failed to clean up tmp directory: ${error.message}`);
|
|
686
885
|
}
|
|
@@ -704,19 +903,19 @@ var TemplatesService = class {
|
|
|
704
903
|
return;
|
|
705
904
|
}
|
|
706
905
|
__agiflowai_aicode_utils.print.info(`Found ${templateDirs.length} template(s)`);
|
|
707
|
-
let
|
|
708
|
-
let
|
|
906
|
+
let _downloaded = 0;
|
|
907
|
+
let _skipped = 0;
|
|
709
908
|
for (const template of templateDirs) {
|
|
710
909
|
const targetFolder = node_path.default.join(templatesPath, template.name);
|
|
711
910
|
if (await fs_extra.pathExists(targetFolder)) {
|
|
712
911
|
__agiflowai_aicode_utils.print.info(`Skipping ${template.name} (already exists)`);
|
|
713
|
-
|
|
912
|
+
_skipped++;
|
|
714
913
|
continue;
|
|
715
914
|
}
|
|
716
915
|
__agiflowai_aicode_utils.print.info(`Downloading ${template.name}...`);
|
|
717
916
|
await cloneSubdirectory(`https://github.com/${repoConfig.owner}/${repoConfig.repo}.git`, repoConfig.branch, template.path, targetFolder);
|
|
718
917
|
__agiflowai_aicode_utils.print.success(`Downloaded ${template.name}`);
|
|
719
|
-
|
|
918
|
+
_downloaded++;
|
|
720
919
|
}
|
|
721
920
|
__agiflowai_aicode_utils.print.success("\nAll templates downloaded successfully!");
|
|
722
921
|
} catch (error) {
|
|
@@ -785,6 +984,24 @@ Object.defineProperty(exports, 'NewProjectService', {
|
|
|
785
984
|
return NewProjectService;
|
|
786
985
|
}
|
|
787
986
|
});
|
|
987
|
+
Object.defineProperty(exports, 'SPEC_TOOL_INFO', {
|
|
988
|
+
enumerable: true,
|
|
989
|
+
get: function () {
|
|
990
|
+
return SPEC_TOOL_INFO;
|
|
991
|
+
}
|
|
992
|
+
});
|
|
993
|
+
Object.defineProperty(exports, 'SpecTool', {
|
|
994
|
+
enumerable: true,
|
|
995
|
+
get: function () {
|
|
996
|
+
return SpecTool;
|
|
997
|
+
}
|
|
998
|
+
});
|
|
999
|
+
Object.defineProperty(exports, 'SpecToolService', {
|
|
1000
|
+
enumerable: true,
|
|
1001
|
+
get: function () {
|
|
1002
|
+
return SpecToolService;
|
|
1003
|
+
}
|
|
1004
|
+
});
|
|
788
1005
|
Object.defineProperty(exports, 'THEME', {
|
|
789
1006
|
enumerable: true,
|
|
790
1007
|
get: function () {
|