@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.
Files changed (95) hide show
  1. package/LICENSE +21 -0
  2. package/README.ko.md +2 -0
  3. package/README.md +2 -0
  4. package/dist/agents-partial.d.ts +2 -0
  5. package/dist/cli.d.ts +2 -0
  6. package/dist/cli.js +235 -0
  7. package/dist/extend.d.ts +12 -0
  8. package/dist/extend.js +242 -0
  9. package/dist/hook-parser.d.ts +15 -0
  10. package/dist/hook-parser.js +95 -0
  11. package/dist/i18n/index.d.ts +5 -0
  12. package/dist/i18n/index.js +20 -0
  13. package/dist/i18n/messages.d.ts +28 -0
  14. package/dist/i18n/messages.js +49 -0
  15. package/dist/index.d.ts +4 -0
  16. package/dist/index.js +4 -0
  17. package/dist/installer.d.ts +10 -0
  18. package/dist/installer.js +74 -0
  19. package/dist/marker.d.ts +11 -0
  20. package/dist/marker.js +25 -0
  21. package/dist/platforms/amazon-q.d.ts +2 -0
  22. package/dist/platforms/amazon-q.js +12 -0
  23. package/dist/platforms/antigravity.d.ts +2 -0
  24. package/dist/platforms/antigravity.js +12 -0
  25. package/dist/platforms/auggie.d.ts +2 -0
  26. package/dist/platforms/auggie.js +15 -0
  27. package/dist/platforms/claude.d.ts +2 -0
  28. package/dist/platforms/claude.js +7 -0
  29. package/dist/platforms/cline.d.ts +2 -0
  30. package/dist/platforms/cline.js +11 -0
  31. package/dist/platforms/codebuddy.d.ts +2 -0
  32. package/dist/platforms/codebuddy.js +16 -0
  33. package/dist/platforms/codex.d.ts +2 -0
  34. package/dist/platforms/codex.js +7 -0
  35. package/dist/platforms/continue.d.ts +2 -0
  36. package/dist/platforms/continue.js +16 -0
  37. package/dist/platforms/costrict.d.ts +2 -0
  38. package/dist/platforms/costrict.js +15 -0
  39. package/dist/platforms/crush.d.ts +2 -0
  40. package/dist/platforms/crush.js +19 -0
  41. package/dist/platforms/cursor.d.ts +2 -0
  42. package/dist/platforms/cursor.js +18 -0
  43. package/dist/platforms/factory.d.ts +2 -0
  44. package/dist/platforms/factory.js +15 -0
  45. package/dist/platforms/gemini.d.ts +2 -0
  46. package/dist/platforms/gemini.js +14 -0
  47. package/dist/platforms/github-copilot.d.ts +2 -0
  48. package/dist/platforms/github-copilot.js +12 -0
  49. package/dist/platforms/iflow.d.ts +2 -0
  50. package/dist/platforms/iflow.js +18 -0
  51. package/dist/platforms/index.d.ts +10 -0
  52. package/dist/platforms/index.js +68 -0
  53. package/dist/platforms/kilocode.d.ts +2 -0
  54. package/dist/platforms/kilocode.js +8 -0
  55. package/dist/platforms/kiro.d.ts +2 -0
  56. package/dist/platforms/kiro.js +12 -0
  57. package/dist/platforms/opencode.d.ts +2 -0
  58. package/dist/platforms/opencode.js +12 -0
  59. package/dist/platforms/pi.d.ts +2 -0
  60. package/dist/platforms/pi.js +12 -0
  61. package/dist/platforms/qoder.d.ts +2 -0
  62. package/dist/platforms/qoder.js +19 -0
  63. package/dist/platforms/qwen.d.ts +2 -0
  64. package/dist/platforms/qwen.js +14 -0
  65. package/dist/platforms/roocode.d.ts +2 -0
  66. package/dist/platforms/roocode.js +11 -0
  67. package/dist/platforms/toml.d.ts +9 -0
  68. package/dist/platforms/toml.js +18 -0
  69. package/dist/platforms/trae.d.ts +2 -0
  70. package/dist/platforms/trae.js +11 -0
  71. package/dist/platforms/types.d.ts +19 -0
  72. package/dist/platforms/types.js +1 -0
  73. package/dist/platforms/windsurf.d.ts +2 -0
  74. package/dist/platforms/windsurf.js +19 -0
  75. package/dist/platforms/yaml.d.ts +10 -0
  76. package/dist/platforms/yaml.js +30 -0
  77. package/dist/platforms.d.ts +20 -0
  78. package/dist/platforms.js +139 -0
  79. package/dist/prompts/platform-select.d.ts +1 -0
  80. package/dist/prompts/platform-select.js +174 -0
  81. package/dist/skills/generate.d.ts +13 -0
  82. package/dist/skills/generate.js +16 -0
  83. package/dist/templates.d.ts +18 -0
  84. package/dist/templates.js +96 -0
  85. package/dist/ui/ascii-logo.d.ts +6 -0
  86. package/dist/ui/ascii-logo.js +38 -0
  87. package/dist/ui/colors.d.ts +2 -0
  88. package/dist/ui/colors.js +3 -0
  89. package/dist/ui/welcome.d.ts +1 -0
  90. package/dist/ui/welcome.js +77 -0
  91. package/package.json +1 -1
  92. package/templates/commands/context.md +1 -0
  93. package/templates/commands/goal.md +3 -1
  94. package/templates/commands/scout.md +3 -1
  95. 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 };
@@ -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
+ }
@@ -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,2 @@
1
+ import type { PlatformAdapter } from "./types.js";
2
+ export declare const amazonQ: PlatformAdapter;
@@ -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,2 @@
1
+ import type { PlatformAdapter } from "./types.js";
2
+ export declare const antigravity: PlatformAdapter;
@@ -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,2 @@
1
+ import type { PlatformAdapter } from "./types.js";
2
+ export declare const auggie: PlatformAdapter;
@@ -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,2 @@
1
+ import type { PlatformAdapter } from "./types.js";
2
+ export declare const claude: PlatformAdapter;
@@ -0,0 +1,7 @@
1
+ export const claude = {
2
+ id: "claude",
3
+ displayName: "Claude Code",
4
+ configDir: ".claude",
5
+ commandPath: (name) => `.claude/commands/scaff/${name}.md`,
6
+ formatCommand: (body) => body,
7
+ };
@@ -0,0 +1,2 @@
1
+ import type { PlatformAdapter } from "./types.js";
2
+ export declare const cline: PlatformAdapter;
@@ -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,2 @@
1
+ import type { PlatformAdapter } from "./types.js";
2
+ export declare const codebuddy: PlatformAdapter;
@@ -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,2 @@
1
+ import type { PlatformAdapter } from "./types.js";
2
+ export declare const codex: PlatformAdapter;
@@ -0,0 +1,7 @@
1
+ export const codex = {
2
+ id: "codex",
3
+ displayName: "Codex",
4
+ configDir: ".codex",
5
+ commandPath: (name) => `.codex/skills/scaff-${name}/SKILL.md`,
6
+ formatCommand: (body) => body,
7
+ };
@@ -0,0 +1,2 @@
1
+ import type { PlatformAdapter } from "./types.js";
2
+ export declare const continueAdapter: PlatformAdapter;
@@ -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,2 @@
1
+ import type { PlatformAdapter } from "./types.js";
2
+ export declare const costrict: PlatformAdapter;
@@ -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,2 @@
1
+ import type { PlatformAdapter } from "./types.js";
2
+ export declare const crush: PlatformAdapter;
@@ -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,2 @@
1
+ import type { PlatformAdapter } from "./types.js";
2
+ export declare const cursor: PlatformAdapter;
@@ -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,2 @@
1
+ import type { PlatformAdapter } from "./types.js";
2
+ export declare const factory: PlatformAdapter;
@@ -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,2 @@
1
+ import type { PlatformAdapter } from "./types.js";
2
+ export declare const gemini: PlatformAdapter;
@@ -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,2 @@
1
+ import type { PlatformAdapter } from "./types.js";
2
+ export declare const githubCopilot: PlatformAdapter;
@@ -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,2 @@
1
+ import type { PlatformAdapter } from "./types.js";
2
+ export declare const iflow: PlatformAdapter;
@@ -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,2 @@
1
+ import type { PlatformAdapter } from "./types.js";
2
+ export declare const kilocode: PlatformAdapter;
@@ -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,2 @@
1
+ import type { PlatformAdapter } from "./types.js";
2
+ export declare const kiro: PlatformAdapter;
@@ -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
+ };