launchframe 0.4.0 → 0.4.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.
@@ -1,111 +1,124 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  /**
4
- * Generates clone-website command/skill files for all supported AI coding platforms.
5
- * Source of truth: .claude/skills/clone-website/SKILL.md
4
+ * Generates invokable skill/command files for all supported AI coding platforms.
5
+ * Source of truth: `.claude/skills/<skill-id>/SKILL.md` (YAML frontmatter + markdown body).
6
6
  *
7
7
  * Usage: node scripts/sync-skills.mjs
8
8
  */
9
9
 
10
- import { readFileSync, writeFileSync, mkdirSync } from 'node:fs';
11
- import { dirname, join } from 'node:path';
12
- import { fileURLToPath } from 'node:url';
10
+ import { readFileSync, writeFileSync, mkdirSync } from "node:fs";
11
+ import { dirname, join } from "node:path";
12
+ import { fileURLToPath } from "node:url";
13
+
14
+ const ROOT = join(dirname(fileURLToPath(import.meta.url)), "..");
15
+
16
+ const SKILLS = [
17
+ {
18
+ id: "clone-website",
19
+ sourceRel: ".claude/skills/clone-website/SKILL.md",
20
+ shortDesc: "Reverse-engineer and clone any website as a pixel-perfect replica",
21
+ plainSubstitution: "the target URL provided by the user",
22
+ augmentArgumentHint: "<url>",
23
+ },
24
+ {
25
+ id: "launchframe",
26
+ sourceRel: ".claude/skills/launchframe/SKILL.md",
27
+ shortDesc:
28
+ "Scaffold with npx launchframe@latest into the current folder — no arguments required",
29
+ plainSubstitution:
30
+ "optional notes from the user after the slash command (the CLI itself needs no URL or SaaS strings)",
31
+ augmentArgumentHint: "",
32
+ },
33
+ ];
13
34
 
14
- const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..');
15
- const SOURCE = join(ROOT, '.claude', 'skills', 'clone-website', 'SKILL.md');
16
-
17
- // --- Parse source skill ---
18
-
19
- let raw;
20
- try {
21
- raw = readFileSync(SOURCE, 'utf8').replace(/\r\n/g, '\n');
22
- } catch {
23
- console.error(`Error: Source skill not found at .claude/skills/clone-website/SKILL.md`);
24
- process.exit(1);
35
+ function write(relPath, content) {
36
+ const full = join(ROOT, relPath);
37
+ mkdirSync(dirname(full), { recursive: true });
38
+ writeFileSync(full, content, "utf8");
39
+ console.log(` \u2713 ${relPath}`);
25
40
  }
26
41
 
27
- const match = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
28
- if (!match) {
29
- console.error('Error: Could not parse SKILL.md frontmatter');
30
- process.exit(1);
42
+ function parseSkill(sourceRel) {
43
+ const full = join(ROOT, sourceRel);
44
+ const raw = readFileSync(full, "utf8").replace(/\r\n/g, "\n");
45
+ const match = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
46
+ if (!match) {
47
+ throw new Error(`Could not parse frontmatter: ${sourceRel}`);
48
+ }
49
+ return { raw, body: match[2] };
31
50
  }
32
51
 
33
- const body = match[2];
34
- const shortDesc = 'Reverse-engineer and clone any website as a pixel-perfect replica';
52
+ function syncSkill(skill) {
53
+ const { id, sourceRel, shortDesc, plainSubstitution, augmentArgumentHint } = skill;
54
+
55
+ let parsed;
56
+ try {
57
+ parsed = parseSkill(sourceRel);
58
+ } catch (e) {
59
+ console.error(e.message || e);
60
+ process.exit(1);
61
+ }
62
+
63
+ const { raw, body } = parsed;
64
+ const noArgs = (text) => text.replace(/\$ARGUMENTS/g, plainSubstitution);
65
+ const header =
66
+ `<!-- AUTO-GENERATED from ${sourceRel} \u2014 do not edit directly.\n` +
67
+ ` Run \`node scripts/sync-skills.mjs\` to regenerate. -->\n\n`;
68
+
69
+ console.log(`\nSyncing ${id}...\n Source: ${sourceRel}\n`);
70
+
71
+ write(`.codex/skills/${id}/SKILL.md`, raw);
72
+ write(`.github/skills/${id}/SKILL.md`, raw);
73
+
74
+ write(`.cursor/commands/${id}.md`, header + noArgs(body));
75
+
76
+ write(`.windsurf/workflows/${id}.md`, header + noArgs(body));
77
+
78
+ const geminiBody = body.replace(/\$ARGUMENTS/g, "{{args}}");
79
+ write(
80
+ `.gemini/commands/${id}.toml`,
81
+ `# AUTO-GENERATED from ${sourceRel}\n` +
82
+ `# Run \`node scripts/sync-skills.mjs\` to regenerate.\n\n` +
83
+ `description = ${JSON.stringify(shortDesc)}\n\n` +
84
+ `[prompt]\ntext = '''\n${geminiBody}\n'''\n`,
85
+ );
86
+
87
+ write(
88
+ `.opencode/commands/${id}.md`,
89
+ `---\ndescription: ${JSON.stringify(shortDesc)}\n---\n${header}${body}`,
90
+ );
91
+
92
+ write(
93
+ `.augment/commands/${id}.md`,
94
+ `---\ndescription: ${JSON.stringify(shortDesc)}\nargument-hint: ${JSON.stringify(augmentArgumentHint)}\n---\n${header}${body}`,
95
+ );
96
+
97
+ write(
98
+ `.continue/commands/${id}.md`,
99
+ `---\nname: ${id}\ndescription: ${JSON.stringify(shortDesc)}\ninvokable: true\n---\n${header}${body}`,
100
+ );
101
+
102
+ write(
103
+ `.amazonq/cli-agents/${id}.json`,
104
+ JSON.stringify(
105
+ {
106
+ name: id,
107
+ description: shortDesc,
108
+ prompt: noArgs(body),
109
+ fileContext: ["AGENTS.md", "docs/research/**"],
110
+ },
111
+ null,
112
+ 2,
113
+ ) + "\n",
114
+ );
115
+ }
35
116
 
36
- // --- Helpers ---
117
+ console.log("Syncing skills to all platforms...");
37
118
 
38
- function write(relPath, content) {
39
- const full = join(ROOT, relPath);
40
- mkdirSync(dirname(full), { recursive: true });
41
- writeFileSync(full, content, 'utf8');
42
- console.log(` \u2713 ${relPath}`);
119
+ for (const skill of SKILLS) {
120
+ syncSkill(skill);
43
121
  }
44
122
 
45
- const HEADER =
46
- '<!-- AUTO-GENERATED from .claude/skills/clone-website/SKILL.md \u2014 do not edit directly.\n' +
47
- ' Run `node scripts/sync-skills.mjs` to regenerate. -->\n\n';
48
-
49
- const noArgs = (text) => text.replace(/\$ARGUMENTS/g, 'the target URL provided by the user');
50
-
51
- // --- Generate ---
52
-
53
- console.log('Syncing clone-website skill to all platforms...');
54
- console.log(` Source: .claude/skills/clone-website/SKILL.md\n`);
55
-
56
- // 1. Codex CLI — same SKILL.md format, same $ARGUMENTS syntax
57
- write('.codex/skills/clone-website/SKILL.md', raw);
58
-
59
- // 2. GitHub Copilot — same SKILL.md format
60
- write('.github/skills/clone-website/SKILL.md', raw);
61
-
62
- // 3. Cursor — plain markdown, no argument substitution support
63
- write('.cursor/commands/clone-website.md', HEADER + noArgs(body));
64
-
65
- // 4. Windsurf — markdown workflow
66
- write('.windsurf/workflows/clone-website.md', HEADER + noArgs(body));
67
-
68
- // 5. Gemini CLI — TOML format, {{args}} for arguments
69
- const geminiBody = body.replace(/\$ARGUMENTS/g, '{{args}}');
70
- write(
71
- '.gemini/commands/clone-website.toml',
72
- `# AUTO-GENERATED from .claude/skills/clone-website/SKILL.md\n` +
73
- `# Run \`node scripts/sync-skills.mjs\` to regenerate.\n\n` +
74
- `description = "${shortDesc}"\n\n` +
75
- `[prompt]\ntext = '''\n${geminiBody}\n'''\n`
76
- );
77
-
78
- // 6. OpenCode — markdown + YAML frontmatter, $ARGUMENTS works natively
79
- write(
80
- '.opencode/commands/clone-website.md',
81
- `---\ndescription: "${shortDesc}"\n---\n${HEADER}${body}`
82
- );
83
-
84
- // 7. Augment Code — markdown + YAML frontmatter
85
- write(
86
- '.augment/commands/clone-website.md',
87
- `---\ndescription: "${shortDesc}"\nargument-hint: "<url>"\n---\n${HEADER}${body}`
88
- );
89
-
90
- // 8. Continue — prompt file with invokable: true
91
- write(
92
- '.continue/commands/clone-website.md',
93
- `---\nname: clone-website\ndescription: "${shortDesc}"\ninvokable: true\n---\n${HEADER}${body}`
94
- );
95
-
96
- // 9. Amazon Q — JSON agent definition
97
- write(
98
- '.amazonq/cli-agents/clone-website.json',
99
- JSON.stringify(
100
- {
101
- name: 'clone-website',
102
- description: shortDesc,
103
- prompt: noArgs(body),
104
- fileContext: ['AGENTS.md', 'docs/research/**'],
105
- },
106
- null,
107
- 2
108
- ) + '\n'
109
- );
110
-
111
- console.log('\nDone! 9 platform command files generated from source skill.');
123
+ const totalFiles = SKILLS.length * 9;
124
+ console.log(`\nDone! ${totalFiles} platform files generated (${SKILLS.length} skills \u00d7 9 targets).`);
@@ -1,8 +1,7 @@
1
1
  /**
2
- * Defaults for local development before running `npx launchframe`.
3
- * The Launchframe CLI overwrites this file in scaffolded projects.
2
+ * Defaults before scaffolding. After `npx launchframe@latest`, edit these values.
4
3
  */
5
4
  export const LAUNCHFRAME_SOURCE_URL = "https://example.com" as const;
6
5
 
7
6
  export const LAUNCHFRAME_SAAS_IDEA =
8
- 'Run `npx launchframe <url> "your SaaS idea"` to scaffold with real inputs.' as const;
7
+ "Edit your SaaS pitch here, then run /clone-website with LAUNCHFRAME_SOURCE_URL." as const;