@opellen/scaff 0.1.15 → 0.1.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/LICENSE +21 -0
- package/README.ko.md +2 -0
- package/README.md +2 -0
- package/dist/agents-partial.d.ts +2 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +235 -0
- package/dist/extend.d.ts +12 -0
- package/dist/extend.js +242 -0
- package/dist/hook-parser.d.ts +15 -0
- package/dist/hook-parser.js +95 -0
- package/dist/i18n/index.d.ts +5 -0
- package/dist/i18n/index.js +20 -0
- package/dist/i18n/messages.d.ts +28 -0
- package/dist/i18n/messages.js +49 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/installer.d.ts +10 -0
- package/dist/installer.js +74 -0
- package/dist/marker.d.ts +11 -0
- package/dist/marker.js +25 -0
- package/dist/platforms/amazon-q.d.ts +2 -0
- package/dist/platforms/amazon-q.js +12 -0
- package/dist/platforms/antigravity.d.ts +2 -0
- package/dist/platforms/antigravity.js +12 -0
- package/dist/platforms/auggie.d.ts +2 -0
- package/dist/platforms/auggie.js +15 -0
- package/dist/platforms/claude.d.ts +2 -0
- package/dist/platforms/claude.js +7 -0
- package/dist/platforms/cline.d.ts +2 -0
- package/dist/platforms/cline.js +11 -0
- package/dist/platforms/codebuddy.d.ts +2 -0
- package/dist/platforms/codebuddy.js +16 -0
- package/dist/platforms/codex.d.ts +2 -0
- package/dist/platforms/codex.js +7 -0
- package/dist/platforms/continue.d.ts +2 -0
- package/dist/platforms/continue.js +16 -0
- package/dist/platforms/costrict.d.ts +2 -0
- package/dist/platforms/costrict.js +15 -0
- package/dist/platforms/crush.d.ts +2 -0
- package/dist/platforms/crush.js +19 -0
- package/dist/platforms/cursor.d.ts +2 -0
- package/dist/platforms/cursor.js +18 -0
- package/dist/platforms/factory.d.ts +2 -0
- package/dist/platforms/factory.js +15 -0
- package/dist/platforms/gemini.d.ts +2 -0
- package/dist/platforms/gemini.js +14 -0
- package/dist/platforms/github-copilot.d.ts +2 -0
- package/dist/platforms/github-copilot.js +12 -0
- package/dist/platforms/iflow.d.ts +2 -0
- package/dist/platforms/iflow.js +18 -0
- package/dist/platforms/index.d.ts +10 -0
- package/dist/platforms/index.js +68 -0
- package/dist/platforms/kilocode.d.ts +2 -0
- package/dist/platforms/kilocode.js +8 -0
- package/dist/platforms/kiro.d.ts +2 -0
- package/dist/platforms/kiro.js +12 -0
- package/dist/platforms/opencode.d.ts +2 -0
- package/dist/platforms/opencode.js +12 -0
- package/dist/platforms/pi.d.ts +2 -0
- package/dist/platforms/pi.js +12 -0
- package/dist/platforms/qoder.d.ts +2 -0
- package/dist/platforms/qoder.js +19 -0
- package/dist/platforms/qwen.d.ts +2 -0
- package/dist/platforms/qwen.js +14 -0
- package/dist/platforms/roocode.d.ts +2 -0
- package/dist/platforms/roocode.js +11 -0
- package/dist/platforms/toml.d.ts +9 -0
- package/dist/platforms/toml.js +18 -0
- package/dist/platforms/trae.d.ts +2 -0
- package/dist/platforms/trae.js +11 -0
- package/dist/platforms/types.d.ts +19 -0
- package/dist/platforms/types.js +1 -0
- package/dist/platforms/windsurf.d.ts +2 -0
- package/dist/platforms/windsurf.js +19 -0
- package/dist/platforms/yaml.d.ts +10 -0
- package/dist/platforms/yaml.js +30 -0
- package/dist/platforms.d.ts +20 -0
- package/dist/platforms.js +139 -0
- package/dist/prompts/platform-select.d.ts +1 -0
- package/dist/prompts/platform-select.js +174 -0
- package/dist/skills/generate.d.ts +13 -0
- package/dist/skills/generate.js +16 -0
- package/dist/templates.d.ts +18 -0
- package/dist/templates.js +96 -0
- package/dist/ui/ascii-logo.d.ts +6 -0
- package/dist/ui/ascii-logo.js +38 -0
- package/dist/ui/colors.d.ts +2 -0
- package/dist/ui/colors.js +3 -0
- package/dist/ui/welcome.d.ts +1 -0
- package/dist/ui/welcome.js +77 -0
- package/package.json +1 -1
- package/templates/commands/context.md +1 -0
- package/templates/commands/goal.md +3 -1
- package/templates/commands/scout.md +3 -1
- package/templates/skills/scaff-flow/SKILL.md +10 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { messages } from "./messages.js";
|
|
2
|
+
function detectLocale() {
|
|
3
|
+
const raw = process.env.LC_ALL ||
|
|
4
|
+
process.env.LC_MESSAGES ||
|
|
5
|
+
process.env.LANG ||
|
|
6
|
+
"";
|
|
7
|
+
if (raw.startsWith("ko"))
|
|
8
|
+
return "ko";
|
|
9
|
+
return "en";
|
|
10
|
+
}
|
|
11
|
+
let current = detectLocale();
|
|
12
|
+
export function getLocale() {
|
|
13
|
+
return current;
|
|
14
|
+
}
|
|
15
|
+
export function setLocale(locale) {
|
|
16
|
+
current = locale;
|
|
17
|
+
}
|
|
18
|
+
export function t(key) {
|
|
19
|
+
return messages[current][key];
|
|
20
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
declare const en: {
|
|
2
|
+
readonly "welcome.tagline": "Context scaffolding for AI coding. Just markdown.";
|
|
3
|
+
readonly "welcome.setsUp": "Installs:";
|
|
4
|
+
readonly "welcome.skills": "Slash commands";
|
|
5
|
+
readonly "welcome.commands": "Agent skills";
|
|
6
|
+
readonly "welcome.pressEnter": "Press Enter to select tools.";
|
|
7
|
+
readonly "select.message": "Select tools";
|
|
8
|
+
readonly "select.typeToFilter": "type to filter";
|
|
9
|
+
readonly "select.detected": "detected";
|
|
10
|
+
readonly "select.selected": "selected";
|
|
11
|
+
readonly "select.none": "none";
|
|
12
|
+
readonly "select.error.empty": "Select at least one tool.";
|
|
13
|
+
readonly "select.hint": "↑↓ navigate • Space toggle • Backspace remove • Enter confirm";
|
|
14
|
+
readonly "select.available": "available";
|
|
15
|
+
readonly "select.selectedLabel": "Selected:";
|
|
16
|
+
readonly "select.searchLabel": "Search:";
|
|
17
|
+
readonly "cli.dryRun": "Dry run — files that would be created:";
|
|
18
|
+
readonly "cli.complete": "scaff init complete.";
|
|
19
|
+
readonly "cli.installed": "Installed files:";
|
|
20
|
+
readonly "cli.skipped": "Skipped (use --force to overwrite):";
|
|
21
|
+
readonly "cli.nextSteps": "What's next:";
|
|
22
|
+
readonly "cli.step1": "Review installed files";
|
|
23
|
+
readonly "cli.step2": "Run {cmd}";
|
|
24
|
+
};
|
|
25
|
+
export type MessageKey = keyof typeof en;
|
|
26
|
+
export type Locale = "en" | "ko";
|
|
27
|
+
export declare const messages: Record<Locale, Record<MessageKey, string>>;
|
|
28
|
+
export {};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
const en = {
|
|
2
|
+
"welcome.tagline": "Context scaffolding for AI coding. Just markdown.",
|
|
3
|
+
"welcome.setsUp": "Installs:",
|
|
4
|
+
"welcome.skills": "Slash commands",
|
|
5
|
+
"welcome.commands": "Agent skills",
|
|
6
|
+
"welcome.pressEnter": "Press Enter to select tools.",
|
|
7
|
+
"select.message": "Select tools",
|
|
8
|
+
"select.typeToFilter": "type to filter",
|
|
9
|
+
"select.detected": "detected",
|
|
10
|
+
"select.selected": "selected",
|
|
11
|
+
"select.none": "none",
|
|
12
|
+
"select.error.empty": "Select at least one tool.",
|
|
13
|
+
"select.hint": "↑↓ navigate • Space toggle • Backspace remove • Enter confirm",
|
|
14
|
+
"select.available": "available",
|
|
15
|
+
"select.selectedLabel": "Selected:",
|
|
16
|
+
"select.searchLabel": "Search:",
|
|
17
|
+
"cli.dryRun": "Dry run — files that would be created:",
|
|
18
|
+
"cli.complete": "scaff init complete.",
|
|
19
|
+
"cli.installed": "Installed files:",
|
|
20
|
+
"cli.skipped": "Skipped (use --force to overwrite):",
|
|
21
|
+
"cli.nextSteps": "What's next:",
|
|
22
|
+
"cli.step1": "Review installed files",
|
|
23
|
+
"cli.step2": "Run {cmd}",
|
|
24
|
+
};
|
|
25
|
+
const ko = {
|
|
26
|
+
"welcome.tagline": "AI 코딩을 위한 컨텍스트 스캐폴딩. 오직 마크다운.",
|
|
27
|
+
"welcome.setsUp": "포함:",
|
|
28
|
+
"welcome.skills": "슬래시 커맨드",
|
|
29
|
+
"welcome.commands": "에이전트 스킬",
|
|
30
|
+
"welcome.pressEnter": "Enter를 눌러 도구를 선택합니다.",
|
|
31
|
+
"select.message": "설치할 도구 선택",
|
|
32
|
+
"select.typeToFilter": "검색어 입력",
|
|
33
|
+
"select.detected": "감지됨",
|
|
34
|
+
"select.selected": "선택됨",
|
|
35
|
+
"select.none": "없음",
|
|
36
|
+
"select.error.empty": "하나 이상 선택해야 합니다.",
|
|
37
|
+
"select.hint": "↑↓ 이동 • Space 토글 • Backspace 제거 • Enter 확인",
|
|
38
|
+
"select.available": "개",
|
|
39
|
+
"select.selectedLabel": "선택:",
|
|
40
|
+
"select.searchLabel": "검색:",
|
|
41
|
+
"cli.dryRun": "드라이 런 — 생성될 파일:",
|
|
42
|
+
"cli.complete": "scaff init 완료.",
|
|
43
|
+
"cli.installed": "설치된 파일:",
|
|
44
|
+
"cli.skipped": "건너뜀 (--force로 덮어쓰기):",
|
|
45
|
+
"cli.nextSteps": "다음:",
|
|
46
|
+
"cli.step1": "설치된 파일 확인",
|
|
47
|
+
"cli.step2": "{cmd} 실행",
|
|
48
|
+
};
|
|
49
|
+
export const messages = { en, ko };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { parseMarkers, renderTemplate, type MarkerBlock, type RenderContext } from "./marker.js";
|
|
2
|
+
export { resolveTemplates, renderFile, type ScaffConfig, type TemplateEntry } from "./templates.js";
|
|
3
|
+
export { install, dryRun, type InstallResult, type PromptFn } from "./installer.js";
|
|
4
|
+
export { getAdapter, getAdapters, getAllAdapters, isValidPlatform, PLATFORM_IDS, DEFAULT_PLATFORM, type PlatformId, type PlatformAdapter, type CommandMeta, } from "./platforms/index.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { parseMarkers, renderTemplate } from "./marker.js";
|
|
2
|
+
export { resolveTemplates, renderFile } from "./templates.js";
|
|
3
|
+
export { install, dryRun } from "./installer.js";
|
|
4
|
+
export { getAdapter, getAdapters, getAllAdapters, isValidPlatform, PLATFORM_IDS, DEFAULT_PLATFORM, } from "./platforms/index.js";
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type ScaffConfig } from "./templates.js";
|
|
2
|
+
export interface InstallResult {
|
|
3
|
+
files: string[];
|
|
4
|
+
skipped: string[];
|
|
5
|
+
}
|
|
6
|
+
export type PromptFn = (question: string) => Promise<string>;
|
|
7
|
+
export declare function install(config: ScaffConfig, prompt?: PromptFn): Promise<InstallResult>;
|
|
8
|
+
export declare function dryRun(config: ScaffConfig): {
|
|
9
|
+
files: string[];
|
|
10
|
+
};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { createInterface } from "node:readline";
|
|
3
|
+
import { join, dirname } from "node:path";
|
|
4
|
+
import { resolveTemplates, renderFile } from "./templates.js";
|
|
5
|
+
function createDefaultPrompt() {
|
|
6
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
7
|
+
let closed = false;
|
|
8
|
+
rl.on("close", () => { closed = true; });
|
|
9
|
+
const prompt = (question) => {
|
|
10
|
+
if (closed)
|
|
11
|
+
return Promise.resolve("");
|
|
12
|
+
return new Promise((resolve) => {
|
|
13
|
+
rl.question(question, (answer) => {
|
|
14
|
+
resolve(answer.trim().toLowerCase());
|
|
15
|
+
});
|
|
16
|
+
rl.once("close", () => resolve(""));
|
|
17
|
+
});
|
|
18
|
+
};
|
|
19
|
+
return { prompt, close: () => rl.close() };
|
|
20
|
+
}
|
|
21
|
+
export async function install(config, prompt) {
|
|
22
|
+
const defaultPrompt = prompt ? null : createDefaultPrompt();
|
|
23
|
+
const askUser = prompt ?? defaultPrompt.prompt;
|
|
24
|
+
const entries = resolveTemplates(config);
|
|
25
|
+
const files = [];
|
|
26
|
+
const skipped = [];
|
|
27
|
+
let applyAll = null;
|
|
28
|
+
try {
|
|
29
|
+
for (const entry of entries) {
|
|
30
|
+
const dst = join(config.root, entry.dst);
|
|
31
|
+
const dir = dirname(dst);
|
|
32
|
+
if (existsSync(dst) && !config.force) {
|
|
33
|
+
if (applyAll === "skip") {
|
|
34
|
+
skipped.push(entry.dst);
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
if (applyAll !== "overwrite") {
|
|
38
|
+
const answer = await askUser(` ${entry.dst} already exists. Overwrite? [y/N/a(all)/s(skip all)] `);
|
|
39
|
+
if (answer === "a" || answer === "all") {
|
|
40
|
+
applyAll = "overwrite";
|
|
41
|
+
}
|
|
42
|
+
else if (answer === "s") {
|
|
43
|
+
applyAll = "skip";
|
|
44
|
+
skipped.push(entry.dst);
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
else if (answer !== "y" && answer !== "yes") {
|
|
48
|
+
skipped.push(entry.dst);
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (!existsSync(dir)) {
|
|
54
|
+
mkdirSync(dir, { recursive: true });
|
|
55
|
+
}
|
|
56
|
+
const content = renderFile(entry, config);
|
|
57
|
+
writeFileSync(dst, content, "utf-8");
|
|
58
|
+
files.push(entry.dst);
|
|
59
|
+
}
|
|
60
|
+
const docsDir = join(config.root, config.docsDir);
|
|
61
|
+
if (!existsSync(docsDir)) {
|
|
62
|
+
mkdirSync(docsDir, { recursive: true });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
finally {
|
|
66
|
+
defaultPrompt?.close();
|
|
67
|
+
}
|
|
68
|
+
return { files, skipped };
|
|
69
|
+
}
|
|
70
|
+
export function dryRun(config) {
|
|
71
|
+
const entries = resolveTemplates(config);
|
|
72
|
+
const files = entries.map((e) => e.dst);
|
|
73
|
+
return { files };
|
|
74
|
+
}
|
package/dist/marker.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface MarkerBlock {
|
|
2
|
+
fullMatch: string;
|
|
3
|
+
condition: string;
|
|
4
|
+
ifBlock: string;
|
|
5
|
+
elseBlock: string | undefined;
|
|
6
|
+
}
|
|
7
|
+
export interface RenderContext {
|
|
8
|
+
conditions: Record<string, boolean>;
|
|
9
|
+
}
|
|
10
|
+
export declare function parseMarkers(content: string): MarkerBlock[];
|
|
11
|
+
export declare function renderTemplate(content: string, ctx: RenderContext): string;
|
package/dist/marker.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const MARKER_SOURCE = "<!-- @if (\\w+) -->\\n([\\s\\S]*?)(?:<!-- @else -->\\n([\\s\\S]*?))?<!-- @endif -->";
|
|
2
|
+
export function parseMarkers(content) {
|
|
3
|
+
const blocks = [];
|
|
4
|
+
let match;
|
|
5
|
+
const regex = new RegExp(MARKER_SOURCE, "g");
|
|
6
|
+
while ((match = regex.exec(content)) !== null) {
|
|
7
|
+
blocks.push({
|
|
8
|
+
fullMatch: match[0],
|
|
9
|
+
condition: match[1],
|
|
10
|
+
ifBlock: match[2],
|
|
11
|
+
elseBlock: match[3],
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
return blocks;
|
|
15
|
+
}
|
|
16
|
+
export function renderTemplate(content, ctx) {
|
|
17
|
+
const regex = new RegExp(MARKER_SOURCE, "g");
|
|
18
|
+
return content.replace(regex, (_match, condition, ifBlock, elseBlock) => {
|
|
19
|
+
const enabled = ctx.conditions[condition] ?? false;
|
|
20
|
+
if (enabled) {
|
|
21
|
+
return ifBlock.trimEnd();
|
|
22
|
+
}
|
|
23
|
+
return elseBlock?.trimEnd() ?? "";
|
|
24
|
+
});
|
|
25
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { stripFrontmatter, yamlFrontmatter } from "./yaml.js";
|
|
2
|
+
export const amazonQ = {
|
|
3
|
+
id: "amazon-q",
|
|
4
|
+
displayName: "Amazon Q Developer",
|
|
5
|
+
configDir: ".amazonq",
|
|
6
|
+
commandPath: (name) => `.amazonq/prompts/scaff-${name}.md`,
|
|
7
|
+
formatCommand: (body, meta) => {
|
|
8
|
+
const stripped = stripFrontmatter(body);
|
|
9
|
+
const fm = yamlFrontmatter({ description: meta.description });
|
|
10
|
+
return fm + stripped;
|
|
11
|
+
},
|
|
12
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { stripFrontmatter, yamlFrontmatter } from "./yaml.js";
|
|
2
|
+
export const antigravity = {
|
|
3
|
+
id: "antigravity",
|
|
4
|
+
displayName: "Antigravity",
|
|
5
|
+
configDir: ".agent",
|
|
6
|
+
commandPath: (name) => `.agent/workflows/scaff-${name}.md`,
|
|
7
|
+
formatCommand: (body, meta) => {
|
|
8
|
+
const stripped = stripFrontmatter(body);
|
|
9
|
+
const fm = yamlFrontmatter({ description: meta.description });
|
|
10
|
+
return fm + stripped;
|
|
11
|
+
},
|
|
12
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { stripFrontmatter, yamlFrontmatter } from "./yaml.js";
|
|
2
|
+
export const auggie = {
|
|
3
|
+
id: "auggie",
|
|
4
|
+
displayName: "Augment CLI",
|
|
5
|
+
configDir: ".augment",
|
|
6
|
+
commandPath: (name) => `.augment/commands/scaff-${name}.md`,
|
|
7
|
+
formatCommand: (body, meta) => {
|
|
8
|
+
const stripped = stripFrontmatter(body);
|
|
9
|
+
const fm = yamlFrontmatter({
|
|
10
|
+
description: meta.description,
|
|
11
|
+
"argument-hint": "command arguments",
|
|
12
|
+
});
|
|
13
|
+
return fm + stripped;
|
|
14
|
+
},
|
|
15
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { stripFrontmatter } from "./yaml.js";
|
|
2
|
+
export const cline = {
|
|
3
|
+
id: "cline",
|
|
4
|
+
displayName: "Cline",
|
|
5
|
+
configDir: ".cline",
|
|
6
|
+
commandPath: (name) => `.clinerules/workflows/scaff-${name}.md`,
|
|
7
|
+
formatCommand: (body, meta) => {
|
|
8
|
+
const stripped = stripFrontmatter(body);
|
|
9
|
+
return `# scaff-${meta.name}\n\n${meta.description}\n\n${stripped}`;
|
|
10
|
+
},
|
|
11
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { stripFrontmatter, yamlFrontmatter } from "./yaml.js";
|
|
2
|
+
export const codebuddy = {
|
|
3
|
+
id: "codebuddy",
|
|
4
|
+
displayName: "CodeBuddy",
|
|
5
|
+
configDir: ".codebuddy",
|
|
6
|
+
commandPath: (name) => `.codebuddy/commands/scaff/${name}.md`,
|
|
7
|
+
formatCommand: (body, meta) => {
|
|
8
|
+
const stripped = stripFrontmatter(body);
|
|
9
|
+
const fm = yamlFrontmatter({
|
|
10
|
+
name: `scaff:${meta.name}`,
|
|
11
|
+
description: meta.description,
|
|
12
|
+
"argument-hint": "[command arguments]",
|
|
13
|
+
});
|
|
14
|
+
return fm + stripped;
|
|
15
|
+
},
|
|
16
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { stripFrontmatter, yamlFrontmatter } from "./yaml.js";
|
|
2
|
+
export const continueAdapter = {
|
|
3
|
+
id: "continue",
|
|
4
|
+
displayName: "Continue",
|
|
5
|
+
configDir: ".continue",
|
|
6
|
+
commandPath: (name) => `.continue/prompts/scaff-${name}.prompt`,
|
|
7
|
+
formatCommand: (body, meta) => {
|
|
8
|
+
const stripped = stripFrontmatter(body);
|
|
9
|
+
const fm = yamlFrontmatter({
|
|
10
|
+
name: `scaff-${meta.name}`,
|
|
11
|
+
description: meta.description,
|
|
12
|
+
invokable: "true",
|
|
13
|
+
});
|
|
14
|
+
return fm + stripped;
|
|
15
|
+
},
|
|
16
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { stripFrontmatter, yamlFrontmatter } from "./yaml.js";
|
|
2
|
+
export const costrict = {
|
|
3
|
+
id: "costrict",
|
|
4
|
+
displayName: "CoStrict",
|
|
5
|
+
configDir: ".cospec",
|
|
6
|
+
commandPath: (name) => `.cospec/scaff/commands/scaff-${name}.md`,
|
|
7
|
+
formatCommand: (body, meta) => {
|
|
8
|
+
const stripped = stripFrontmatter(body);
|
|
9
|
+
const fm = yamlFrontmatter({
|
|
10
|
+
description: meta.description,
|
|
11
|
+
"argument-hint": "command arguments",
|
|
12
|
+
});
|
|
13
|
+
return fm + stripped;
|
|
14
|
+
},
|
|
15
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { stripFrontmatter, yamlFrontmatter, } from "./yaml.js";
|
|
2
|
+
export const crush = {
|
|
3
|
+
id: "crush",
|
|
4
|
+
displayName: "Crush",
|
|
5
|
+
configDir: ".crush",
|
|
6
|
+
commandPath: (name) => `.crush/commands/scaff/${name}.md`,
|
|
7
|
+
formatCommand: (body, meta) => {
|
|
8
|
+
const stripped = stripFrontmatter(body);
|
|
9
|
+
const fields = {
|
|
10
|
+
name: `scaff:${meta.name}`,
|
|
11
|
+
description: meta.description,
|
|
12
|
+
};
|
|
13
|
+
if (meta.category)
|
|
14
|
+
fields.category = meta.category;
|
|
15
|
+
if (meta.tags && meta.tags.length > 0)
|
|
16
|
+
fields.tags = meta.tags;
|
|
17
|
+
return yamlFrontmatter(fields) + stripped;
|
|
18
|
+
},
|
|
19
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { stripFrontmatter, yamlFrontmatter, } from "./yaml.js";
|
|
2
|
+
export const cursor = {
|
|
3
|
+
id: "cursor",
|
|
4
|
+
displayName: "Cursor",
|
|
5
|
+
configDir: ".cursor",
|
|
6
|
+
commandPath: (name) => `.cursor/commands/scaff-${name}.md`,
|
|
7
|
+
formatCommand: (body, meta) => {
|
|
8
|
+
const stripped = stripFrontmatter(body);
|
|
9
|
+
const fields = {
|
|
10
|
+
name: `/scaff-${meta.name}`,
|
|
11
|
+
id: `scaff-${meta.name}`,
|
|
12
|
+
};
|
|
13
|
+
if (meta.category)
|
|
14
|
+
fields.category = meta.category;
|
|
15
|
+
fields.description = meta.description;
|
|
16
|
+
return yamlFrontmatter(fields) + stripped;
|
|
17
|
+
},
|
|
18
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { stripFrontmatter, yamlFrontmatter } from "./yaml.js";
|
|
2
|
+
export const factory = {
|
|
3
|
+
id: "factory",
|
|
4
|
+
displayName: "Factory Droid",
|
|
5
|
+
configDir: ".factory",
|
|
6
|
+
commandPath: (name) => `.factory/commands/scaff-${name}.md`,
|
|
7
|
+
formatCommand: (body, meta) => {
|
|
8
|
+
const stripped = stripFrontmatter(body);
|
|
9
|
+
const fm = yamlFrontmatter({
|
|
10
|
+
description: meta.description,
|
|
11
|
+
"argument-hint": "command arguments",
|
|
12
|
+
});
|
|
13
|
+
return fm + stripped;
|
|
14
|
+
},
|
|
15
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { stripFrontmatter } from "./yaml.js";
|
|
2
|
+
import { escapeTomlString, escapeTomlMultiline } from "./toml.js";
|
|
3
|
+
export const gemini = {
|
|
4
|
+
id: "gemini",
|
|
5
|
+
displayName: "Gemini CLI",
|
|
6
|
+
configDir: ".gemini",
|
|
7
|
+
commandPath: (name) => `.gemini/commands/scaff/${name}.toml`,
|
|
8
|
+
formatCommand: (body, meta) => {
|
|
9
|
+
const stripped = stripFrontmatter(body);
|
|
10
|
+
const description = escapeTomlString(meta.description);
|
|
11
|
+
const prompt = escapeTomlMultiline(stripped.trimEnd());
|
|
12
|
+
return `description = "${description}"\n\nprompt = """\n${prompt}\n"""\n`;
|
|
13
|
+
},
|
|
14
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { stripFrontmatter, yamlFrontmatter } from "./yaml.js";
|
|
2
|
+
export const githubCopilot = {
|
|
3
|
+
id: "github-copilot",
|
|
4
|
+
displayName: "GitHub Copilot",
|
|
5
|
+
configDir: ".github",
|
|
6
|
+
commandPath: (name) => `.github/prompts/scaff-${name}.prompt.md`,
|
|
7
|
+
formatCommand: (body, meta) => {
|
|
8
|
+
const stripped = stripFrontmatter(body);
|
|
9
|
+
const fm = yamlFrontmatter({ description: meta.description });
|
|
10
|
+
return fm + stripped;
|
|
11
|
+
},
|
|
12
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { stripFrontmatter, yamlFrontmatter, } from "./yaml.js";
|
|
2
|
+
export const iflow = {
|
|
3
|
+
id: "iflow",
|
|
4
|
+
displayName: "iFlow",
|
|
5
|
+
configDir: ".iflow",
|
|
6
|
+
commandPath: (name) => `.iflow/commands/scaff-${name}.md`,
|
|
7
|
+
formatCommand: (body, meta) => {
|
|
8
|
+
const stripped = stripFrontmatter(body);
|
|
9
|
+
const fields = {
|
|
10
|
+
name: `/scaff-${meta.name}`,
|
|
11
|
+
id: `scaff-${meta.name}`,
|
|
12
|
+
};
|
|
13
|
+
if (meta.category)
|
|
14
|
+
fields.category = meta.category;
|
|
15
|
+
fields.description = meta.description;
|
|
16
|
+
return yamlFrontmatter(fields) + stripped;
|
|
17
|
+
},
|
|
18
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { PlatformAdapter } from "./types.js";
|
|
2
|
+
export type { PlatformAdapter, CommandMeta } from "./types.js";
|
|
3
|
+
export { DEFAULT_PLATFORM } from "./types.js";
|
|
4
|
+
export declare const PLATFORM_IDS: readonly ["claude", "cursor", "windsurf", "cline", "codex", "github-copilot", "continue", "amazon-q", "antigravity", "auggie", "codebuddy", "costrict", "crush", "factory", "gemini", "iflow", "kilocode", "kiro", "opencode", "pi", "qoder", "qwen", "roocode", "trae"];
|
|
5
|
+
export type PlatformId = typeof PLATFORM_IDS[number];
|
|
6
|
+
export declare function isValidPlatform(id: string): id is PlatformId;
|
|
7
|
+
export declare function getAdapter(id: string): PlatformAdapter | undefined;
|
|
8
|
+
export declare function getAdapters(ids: string[]): PlatformAdapter[];
|
|
9
|
+
export declare function getAllAdapters(): PlatformAdapter[];
|
|
10
|
+
export declare function detectInstalledPlatforms(projectRoot: string): string[];
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { claude } from "./claude.js";
|
|
4
|
+
import { cursor } from "./cursor.js";
|
|
5
|
+
import { windsurf } from "./windsurf.js";
|
|
6
|
+
import { cline } from "./cline.js";
|
|
7
|
+
import { codex } from "./codex.js";
|
|
8
|
+
import { githubCopilot } from "./github-copilot.js";
|
|
9
|
+
import { continueAdapter } from "./continue.js";
|
|
10
|
+
import { amazonQ } from "./amazon-q.js";
|
|
11
|
+
import { antigravity } from "./antigravity.js";
|
|
12
|
+
import { auggie } from "./auggie.js";
|
|
13
|
+
import { codebuddy } from "./codebuddy.js";
|
|
14
|
+
import { costrict } from "./costrict.js";
|
|
15
|
+
import { crush } from "./crush.js";
|
|
16
|
+
import { factory } from "./factory.js";
|
|
17
|
+
import { gemini } from "./gemini.js";
|
|
18
|
+
import { iflow } from "./iflow.js";
|
|
19
|
+
import { kilocode } from "./kilocode.js";
|
|
20
|
+
import { kiro } from "./kiro.js";
|
|
21
|
+
import { opencode } from "./opencode.js";
|
|
22
|
+
import { pi } from "./pi.js";
|
|
23
|
+
import { qoder } from "./qoder.js";
|
|
24
|
+
import { qwen } from "./qwen.js";
|
|
25
|
+
import { roocode } from "./roocode.js";
|
|
26
|
+
import { trae } from "./trae.js";
|
|
27
|
+
export { DEFAULT_PLATFORM } from "./types.js";
|
|
28
|
+
const ALL_ADAPTERS = [
|
|
29
|
+
claude, cursor, windsurf, cline, codex, githubCopilot, continueAdapter,
|
|
30
|
+
amazonQ, antigravity, auggie, codebuddy, costrict, crush, factory,
|
|
31
|
+
gemini, iflow, kilocode, kiro, opencode, pi, qoder, qwen, roocode, trae,
|
|
32
|
+
];
|
|
33
|
+
const ADAPTER_MAP = new Map(ALL_ADAPTERS.map((a) => [a.id, a]));
|
|
34
|
+
if (ADAPTER_MAP.size !== ALL_ADAPTERS.length)
|
|
35
|
+
throw new Error("duplicate adapter id");
|
|
36
|
+
export const PLATFORM_IDS = [
|
|
37
|
+
"claude", "cursor", "windsurf", "cline", "codex", "github-copilot", "continue",
|
|
38
|
+
"amazon-q", "antigravity", "auggie", "codebuddy", "costrict", "crush", "factory",
|
|
39
|
+
"gemini", "iflow", "kilocode", "kiro", "opencode", "pi", "qoder", "qwen", "roocode", "trae",
|
|
40
|
+
];
|
|
41
|
+
if (PLATFORM_IDS.length !== ALL_ADAPTERS.length)
|
|
42
|
+
throw new Error("PLATFORM_IDS out of sync");
|
|
43
|
+
export function isValidPlatform(id) {
|
|
44
|
+
return ADAPTER_MAP.has(id);
|
|
45
|
+
}
|
|
46
|
+
export function getAdapter(id) {
|
|
47
|
+
return ADAPTER_MAP.get(id);
|
|
48
|
+
}
|
|
49
|
+
export function getAdapters(ids) {
|
|
50
|
+
return ids.map((id) => {
|
|
51
|
+
const adapter = ADAPTER_MAP.get(id);
|
|
52
|
+
if (!adapter)
|
|
53
|
+
throw new Error(`Unknown platform: ${id}`);
|
|
54
|
+
return adapter;
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
export function getAllAdapters() {
|
|
58
|
+
return [...ALL_ADAPTERS];
|
|
59
|
+
}
|
|
60
|
+
export function detectInstalledPlatforms(projectRoot) {
|
|
61
|
+
const detected = [];
|
|
62
|
+
for (const adapter of ALL_ADAPTERS) {
|
|
63
|
+
if (existsSync(resolve(projectRoot, adapter.configDir))) {
|
|
64
|
+
detected.push(adapter.id);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return detected;
|
|
68
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { stripFrontmatter } from "./yaml.js";
|
|
2
|
+
export const kilocode = {
|
|
3
|
+
id: "kilocode",
|
|
4
|
+
displayName: "Kilo Code",
|
|
5
|
+
configDir: ".kilocode",
|
|
6
|
+
commandPath: (name) => `.kilocode/workflows/scaff-${name}.md`,
|
|
7
|
+
formatCommand: (body) => stripFrontmatter(body),
|
|
8
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { stripFrontmatter, yamlFrontmatter } from "./yaml.js";
|
|
2
|
+
export const kiro = {
|
|
3
|
+
id: "kiro",
|
|
4
|
+
displayName: "Kiro",
|
|
5
|
+
configDir: ".kiro",
|
|
6
|
+
commandPath: (name) => `.kiro/prompts/scaff-${name}.prompt.md`,
|
|
7
|
+
formatCommand: (body, meta) => {
|
|
8
|
+
const stripped = stripFrontmatter(body);
|
|
9
|
+
const fm = yamlFrontmatter({ description: meta.description });
|
|
10
|
+
return fm + stripped;
|
|
11
|
+
},
|
|
12
|
+
};
|