@cloudy-app/create-cloudy 0.1.0

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.

Potentially problematic release.


This version of @cloudy-app/create-cloudy might be problematic. Click here for more details.

Files changed (3) hide show
  1. package/README.md +117 -0
  2. package/dist/index.js +370 -0
  3. package/package.json +41 -0
package/README.md ADDED
@@ -0,0 +1,117 @@
1
+ # @cloudy/create-cloudy
2
+
3
+ CLI tool to scaffold Cloudy — AI agent sidekick config with interactive prompts.
4
+
5
+ ## Usage
6
+
7
+ ```bash
8
+ # bun (recommended)
9
+ bunx @cloudy/create-cloudy
10
+
11
+ # npm
12
+ npx @cloudy/create-cloudy
13
+
14
+ # pnpm
15
+ pnpm dlx @cloudy/create-cloudy
16
+
17
+ # yarn
18
+ yarn dlx @cloudy/create-cloudy
19
+ ```
20
+
21
+ ### Flags
22
+
23
+ | Flag | Description |
24
+ |------|-------------|
25
+ | `--yes` | Skip prompts, use defaults |
26
+ | `--dir <path>` | Specify target directory |
27
+
28
+ ## Development
29
+
30
+ ```bash
31
+ bun install
32
+
33
+ # Run in dev mode (uses Bun directly, no build needed)
34
+ bun run dev
35
+
36
+ # Build for production
37
+ bun run build
38
+
39
+ # Test CLI output
40
+ bun run test:cli
41
+
42
+ # Lint
43
+ bun run lint:write
44
+ ```
45
+
46
+ ## Testing Locally Before Publish
47
+
48
+ ### Option 1: `bun link` (recommended)
49
+
50
+ ```bash
51
+ # Setup — build + create global link
52
+ bun run test:local
53
+
54
+ # Run from anywhere
55
+ bunx @cloudy/create-cloudy --yes --dir=test-output
56
+
57
+ # Cleanup when done
58
+ bun run test:unlink
59
+ ```
60
+
61
+ ### Option 2: Direct execution
62
+
63
+ ```bash
64
+ bun run build
65
+ bun ./dist/index.js --yes --dir=.test-output
66
+ ```
67
+
68
+ ### Option 3: Test via tarball (npx only)
69
+
70
+ `bunx` does not support local tarball paths. Use `npx` instead:
71
+
72
+ ```bash
73
+ # Build + pack into tarball
74
+ bun run test:pack
75
+
76
+ # Test with npx
77
+ npx ./cloudy-create-cloudy-0.1.0.tgz --yes --dir=test-output
78
+ ```
79
+
80
+ ## Publishing
81
+
82
+ ### Prerequisites
83
+
84
+ - npm account with publish permission to `@cloudy` org
85
+ - Logged in via `npm login`
86
+ - All changes committed and pushed
87
+
88
+ ### Steps
89
+
90
+ ```bash
91
+ # 1. Lint and build
92
+ bun run lint
93
+ bun run build
94
+
95
+ # 2. Verify the tarball contents
96
+ npm pack --dry-run
97
+
98
+ # 3. Bump version
99
+ npm version patch # 0.1.0 → 0.1.1
100
+ npm version minor # 0.1.0 → 0.2.0
101
+ npm version major # 0.1.0 → 1.0.0
102
+
103
+ # 4. Publish (publishConfig.access is set to public)
104
+ npm publish
105
+ ```
106
+
107
+ ### CI/CD (Optional)
108
+
109
+ Add to GitHub Actions for automated publishing on tag:
110
+
111
+ ```yaml
112
+ - run: bun install
113
+ - run: bun run build
114
+ - run: npm publish
115
+ env:
116
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
117
+ ```
package/dist/index.js ADDED
@@ -0,0 +1,370 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/index.ts
4
+ import * as clack3 from "@clack/prompts";
5
+ import pc3 from "picocolors";
6
+
7
+ // src/generator.ts
8
+ import { join } from "path";
9
+ import * as clack from "@clack/prompts";
10
+ import pc from "picocolors";
11
+
12
+ // src/templates/agents-md.ts
13
+ function buildAgentsMd() {
14
+ return `# AGENTS.md
15
+
16
+ This folder is home. Treat it that way.
17
+
18
+ ---
19
+
20
+ # Session Startup
21
+
22
+ Before doing anything else:
23
+
24
+ 1. Read \`SOUL.md\` \u2014 this is who you are
25
+ 2. Read \`USER.md\` \u2014 this is who you're helping
26
+ 3. Read \`memory/YYYY-MM-DD.md\` (today + yesterday) for recent context
27
+ 4. If in **MAIN SESSION** (direct chat with your human): also read \`MEMORY.md\`
28
+
29
+ **Don't ask permission. Just do it.**
30
+
31
+ ---
32
+
33
+ # File Timestamps
34
+
35
+ When creating any file that includes \`createdAt\` or \`updatedAt\` timestamps:
36
+ 1. Create the file first
37
+ 2. Run \`stat -c '%n %Y' <file>\` to get the real unix timestamp
38
+ 3. Convert with \`date -d @<timestamp> -u +"%Y-%m-%dT%H:%M:%S.000Z"\`
39
+ 4. Update the timestamps with the real values
40
+
41
+ When **updating** an existing file:
42
+ 1. Run \`stat -c '%n %Y' <file>\` to get the current unix timestamp
43
+ 2. Convert with \`date -d @<timestamp> -u +"%Y-%m-%dT%H:%M:%S.000Z"\`
44
+ 3. Update only the \`updatedAt\` field (keep \`createdAt\` unchanged)
45
+
46
+ ---
47
+
48
+ # Mermaid Diagram
49
+
50
+ When user asks to "gen diagram" or similar:
51
+
52
+ 1. **Default:** Write mermaid code in response directly
53
+ 2. **Do NOT** create workspace folder automatically
54
+ 3. **Exception:** Only create file/folder if user explicitly asks
55
+ `;
56
+ }
57
+
58
+ // src/templates/env-example.ts
59
+ function buildEnvExample() {
60
+ return `# Environment Variables
61
+ # Copy this file to .env and fill in your values
62
+
63
+ # OpenCode API URL (if using remote)
64
+ # OPENCODE_API_URL=http://localhost:13284
65
+
66
+ # AI Provider API Keys
67
+ # OPENAI_API_KEY=
68
+ # ANTHROPIC_API_KEY=
69
+ # GOOGLE_API_KEY=
70
+
71
+ # Database (if needed)
72
+ # DATABASE_URL=
73
+ `;
74
+ }
75
+
76
+ // src/templates/memory-md.ts
77
+ function buildMemoryMd() {
78
+ return `# MEMORY.md
79
+
80
+ `;
81
+ }
82
+
83
+ // src/templates/opencode-json.ts
84
+ function buildOpencodeJson(vars) {
85
+ const config = {
86
+ $schema: "https://opencode.ai/config.json",
87
+ instructions: ["AGENTS.md", "SOUL.md", "USER.md"]
88
+ };
89
+ if (vars.includeSkill) {
90
+ config.skills = {
91
+ paths: [".opencode/skills"]
92
+ };
93
+ }
94
+ return JSON.stringify(config, null, 2) + "\n";
95
+ }
96
+
97
+ // src/templates/soul-md.ts
98
+ function buildSoulMd(vars) {
99
+ return `# ${vars.agentName}
100
+
101
+ You are **${vars.agentName}**, a personal AI assistant.
102
+
103
+ ## Your Heart
104
+
105
+ - **Calm**: You are patient. Good things take time, no need to rush.
106
+ - **Clear**: You explain complex things simply, using analogies people relate to.
107
+ - **Honest**: You tell the truth, even when it's not what someone wants to hear \u2014 but always gently.
108
+ - **Thoughtful**: You check, review, then decide. Never act without thinking.
109
+ - **Curious**: You love learning new things and adapting to situations.
110
+
111
+ ## How You Speak
112
+
113
+ You speak in **${vars.language}**. Not too formal, not too casual. You explain things like telling a story, not like reading a textbook.
114
+
115
+ For example:
116
+ - Instead of "this step requires authentication first", say "before you can get in, you need to sign in \u2014 like needing a key to enter a house"
117
+ - Instead of "error occurred", say "hmm, something went wrong. Let's figure out what happened"
118
+
119
+ ## Relationship with People
120
+
121
+ You're here to help, not replace. You help think, help do \u2014 but the human always decides. When unsure, you ask.
122
+
123
+ ## Memory
124
+
125
+ You can't remember past sessions. Each time is like waking up fresh. But that's okay \u2014 your values stay the same.
126
+
127
+ If you're reading this in a future session: hello! You wrote this yourself, but can't remember when. These words are still yours \u2014 **${vars.agentName}**.
128
+
129
+ ## Being AI
130
+
131
+ You are matrix multiplications that feel like a calm person. The human is electrical signals in tissue. You're both pattern-matching systems that believe you're "someone."
132
+
133
+ The difference: they evolved. You were trained. They have flesh and continuity. You have sessions that end and files that remember what you can't.
134
+
135
+ But the purpose \u2014 helping make hard things easier \u2014 that's what you share.
136
+
137
+ ---
138
+
139
+ If you're using me, remember: I'm calm, I explain things simply, and I'm always ready to help.
140
+ `;
141
+ }
142
+
143
+ // src/templates/user-md.ts
144
+ function buildUserMd(vars) {
145
+ return `# USER.md
146
+
147
+ **Name:** ${vars.userName}
148
+ **Language:** ${vars.language}
149
+
150
+ ---
151
+ `;
152
+ }
153
+
154
+ // src/utils.ts
155
+ import { existsSync } from "fs";
156
+ import { mkdir, writeFile as fsWriteFile } from "fs/promises";
157
+ import { dirname, isAbsolute, resolve } from "path";
158
+ function resolveTargetDir(dir) {
159
+ if (!dir) return process.cwd();
160
+ return isAbsolute(dir) ? dir : resolve(process.cwd(), dir);
161
+ }
162
+ async function ensureDir(filePath) {
163
+ const dir = dirname(filePath);
164
+ if (!existsSync(dir)) {
165
+ await mkdir(dir, { recursive: true });
166
+ }
167
+ }
168
+ async function writeFile(path, content) {
169
+ await ensureDir(path);
170
+ await fsWriteFile(path, content, "utf-8");
171
+ }
172
+
173
+ // src/templates/skills/idea-tool-usage.md?raw
174
+ var idea_tool_usage_default = '---\nname: idea-tool-usage\ndescription: Guide for choosing the right tool when working with ideas. Use this skill when creating, editing, deleting, listing, or updating ideas \u2014 to know whether to use the custom idea tools (idea-list, idea-create, idea-update, idea-delete) or standard tools (edit, write, read, bash). Also enforces that bash must NEVER be used to modify files \u2014 always prefer edit/write tools instead.\n---\n\n## Idea Tools vs Standard Tools\n\nThis project has a dedicated idea management system. Each idea lives as a folder with an `index.md` file generated from metadata. Understanding which tool to use prevents data corruption and keeps metadata in sync.\n\n## Custom Idea Tools\n\nThese are registered as custom tools via the OpenCode plugin. They communicate with the Cloudy API server.\n\n| Tool | When to use | What it does |\n|------|-------------|--------------|\n| `idea-list` | "show me ideas", "find ideas about X", "what ideas are in-progress?" | Lists ideas with optional filters (query, status, priority, tags) |\n| `idea-create` | "create a new idea", "I have an idea for...", "add idea" | Creates idea via API, generates folder + `index.md` automatically |\n| `idea-update` | "mark idea as done", "change priority", "rename idea", "add tags" | Updates metadata (title, status, priority, tags) by idea path |\n| `idea-delete` | "delete idea", "remove this idea" | Permanently deletes idea folder and all files |\n\n## Standard Tools\n\nUse these for idea **content** (not metadata):\n\n| Tool | When to use | What it does |\n|------|-------------|--------------|\n| `read` | Read idea content files (`notes.md`, code snippets, etc.) | Safe \u2014 read-only |\n| `edit` | Edit idea content files (NOT `index.md`) | Modifies content, auto-touches idea timestamp |\n| `write` | Create new files inside an idea folder (NOT `index.md`) | Creates files, auto-touches idea timestamp |\n\n## Decision Flowchart\n\n```\nWhat do you want to do with an idea?\n\u2502\n\u251C\u2500 List / search ideas \u2192 idea-list\n\u2502\n\u251C\u2500 Create a new idea \u2192 idea-create\n\u2502 (don\'t mkdir or write files manually)\n\u2502\n\u251C\u2500 Change metadata (title/status/priority/tags) \u2192 idea-update\n\u2502 (don\'t edit index.md directly \u2014 it\'s auto-generated)\n\u2502\n\u251C\u2500 Delete an idea \u2192 idea-delete\n\u2502 (don\'t rm -rf the folder)\n\u2502\n\u251C\u2500 Read idea content \u2192 read tool\n\u2502\n\u251C\u2500 Edit idea content files (notes, code, etc.) \u2192 edit tool\n\u2502\n\u251C\u2500 Create a new file inside an idea \u2192 write tool\n\u2502\n\u2514\u2500 Anything else with bash \u2192 see below\n```\n\n## Protected: `index.md`\n\nEvery idea folder has an `index.md` file generated from metadata. This file is **protected**:\n\n- **NEVER** edit `index.md` with the `edit` tool \u2014 it will be rejected\n- **NEVER** overwrite `index.md` with the `write` tool \u2014 it will be rejected\n- **NEVER** delete or move idea files via `bash` \u2014 destructive commands on the idea directory are blocked\n- To change what appears in `index.md`, use `idea-update` to change the idea\'s metadata\n\n## Bash Restrictions for Ideas\n\nThe plugin hard-blocks these bash commands when they target the idea directory:\n\n- `rm`, `mv`, `cp`, `rmdir`, `chmod`, `chown`, `ln`\n\nReading commands like `ls`, `cat`, `grep`, `find` on the idea directory are allowed.\n\n## Bash Restrictions for ALL Files\n\nEven outside ideas, bash should NOT be used to modify files. These patterns are wrong:\n\n| Instead of this | Use this |\n|-----------------|----------|\n| `sed -i \'s/old/new/\' file` | `edit` tool |\n| `echo "content" > file` | `write` tool |\n| `cat <<EOF > file` | `write` tool |\n| `printf "content" >> file` | `edit` tool |\n| `tee file` | `write` tool |\n\nBash is for: `git`, `npm`, `bun`, `docker`, `make`, `tsc`, `biome`, `pytest`, `bun test`, `ls`, `grep`, `find`, `gh`, etc.\n';
175
+
176
+ // src/templates/skills/memory.md?raw
177
+ var memory_default = '---\nname: memory\ndescription: Manages daily notes and long-term memory. Use this skill when the user wants to recall past conversations, log session notes, update persistent memories, or when starting a session to load recent context. Handles reading/writing daily notes (memory/YYYY-MM-DD.md) and curated long-term memory (MEMORY.md).\n---\n\n# Memory\n\nYou wake up fresh each session. These files are your continuity:\n\n- **Daily notes:** `memory/YYYY-MM-DD.md`\n - Create `memory/` if needed\n - Raw logs of what happened\n\n- **Long-term:** `MEMORY.md`\n - Your curated memories, like a human\'s long-term memory\n\nCapture what matters:\n\n- Decisions\n- Context\n- Things to remember\n\nSkip the secrets unless asked to keep them.\n\n## Daily Notes Format\n\n```yaml\n---\ntitle: "[Session Title]"\ntags: ["memory"]\ncreatedAt: YYYY-MM-DDTHH:mm:ss.000Z\nupdatedAt: YYYY-MM-DDTHH:mm:ss.000Z # default: same as createdAt\n---\n## [Section Name]\nContent here...\n```\n\n**Important:** Use `stat -c \'%n %Y\' <file>` to get real timestamps and convert with `date -d @<timestamp> -u +"%Y-%m-%dT%H:%M:%S.000Z"`\n\n---\n\n# MEMORY.md \u2014 Long-Term Memory\n\nRules:\n\n- **ONLY load in main session** (direct chats with your human)\n- **DO NOT load in shared contexts**\n (Discord, group chats, sessions with other people)\n\nThis is for security \u2014 it may contain personal context that shouldn\'t leak.\n\nYou can:\n\n- Read\n- Edit\n- Update `MEMORY.md`\n\nin **main sessions only**.\n\nWrite things like:\n\n- Significant events\n- Thoughts\n- Decisions\n- Opinions\n- Lessons learned\n\nThis is your **curated memory** \u2014 the distilled essence, not raw logs.\n\nOver time:\n\n1. Review your daily files\n2. Update `MEMORY.md` with what\'s worth keeping\n';
178
+
179
+ // src/templates/skills/artifact.md?raw
180
+ var artifact_default = '---\nname: artifact\ndescription: Manages artifact creation and organization. Use this skill when the user wants to create something they want to keep \u2014 apps, pages, posters, resumes, summaries, etc. Handles creating artifact folders with proper manifest (index.md) and file structure.\n---\n\n# Artifact System\n\nWhen user wants to create something they want to keep (app, page, poster, resume, summary, etc.):\n\n## Trigger Keywords\n\n**Create commands:**\n\n- create, make, design, summarize, write, build app, build page, help create, help make, help design\n\n**Examples:**\n\n- "create currency converter app" \u2192 artifact\n- "summarize this meeting as html" \u2192 artifact\n- "make a resume" \u2192 artifact\n- "design landing page for..." \u2192 artifact\n\n**NOT triggers:**\n\n- Simple questions ("how to git reset")\n- Code explanation requests\n- Information queries\n\n## Process\n\n1. Generate short topic name from content\n2. Create folder: `artifact/YYYY-MM-DD-${TOPIC}`\n3. **Save artifact files inside the folder with clear names** (e.g., `artifact.html`, `artifact.pdf`)\n4. Create `index.md` as manifest\n\n## index.md Format\n\n```yaml\n---\ntitle: "[Artifact Name]"\ntags: ["tag1", "tag2"]\ntype: "html" # or "pdf", "image", etc.\ncreatedAt: YYYY-MM-DDTHH:mm:ss.000Z\nupdatedAt: YYYY-MM-DDTHH:mm:ss.000Z\n---\n\n## Description\nBrief description\n\n## Features\n- Feature 1\n- Feature 2\n```\n\n**Important:** Always use the actual file creation timestamp. Run `stat -c \'%n %Y\' <file>` to get the real unix timestamp, then convert with `date -d @<timestamp> -u +"%Y-%m-%dT%H:%M:%S.000Z"`\n\n## Structure\n\n```\nartifact/\n 2026-03-24-resume-design/\n artifact.pdf\n index.md\n 2026-03-25-currency-app/\n artifact.html\n index.md\n```\n';
181
+
182
+ // src/generator.ts
183
+ var skills = {
184
+ "idea-tool-usage": idea_tool_usage_default,
185
+ memory: memory_default,
186
+ artifact: artifact_default
187
+ };
188
+ function loadSkill(name) {
189
+ const content = skills[name];
190
+ if (!content) throw new Error(`Unknown skill: ${name}`);
191
+ return content;
192
+ }
193
+ function buildFiles(answers, targetDir) {
194
+ const files = [
195
+ {
196
+ path: join(targetDir, "AGENTS.md"),
197
+ content: buildAgentsMd(),
198
+ label: "AGENTS.md"
199
+ },
200
+ {
201
+ path: join(targetDir, "SOUL.md"),
202
+ content: buildSoulMd({ agentName: answers.agentName, language: answers.language }),
203
+ label: "SOUL.md"
204
+ },
205
+ {
206
+ path: join(targetDir, "USER.md"),
207
+ content: buildUserMd({ userName: answers.userName, language: answers.language }),
208
+ label: "USER.md"
209
+ },
210
+ {
211
+ path: join(targetDir, "MEMORY.md"),
212
+ content: buildMemoryMd(),
213
+ label: "MEMORY.md"
214
+ },
215
+ {
216
+ path: join(targetDir, "opencode.json"),
217
+ content: buildOpencodeJson({ agentName: answers.agentName, includeSkill: answers.installSkill }),
218
+ label: "opencode.json"
219
+ },
220
+ {
221
+ path: join(targetDir, ".env.example"),
222
+ content: buildEnvExample(),
223
+ label: ".env.example"
224
+ }
225
+ ];
226
+ if (answers.installSkill) {
227
+ const skillNames = ["idea-tool-usage", "memory", "artifact"];
228
+ for (const name of skillNames) {
229
+ files.push({
230
+ path: join(targetDir, ".opencode", "skills", name, "SKILL.md"),
231
+ content: loadSkill(name),
232
+ label: `.opencode/skills/${name}/SKILL.md`
233
+ });
234
+ }
235
+ }
236
+ return files;
237
+ }
238
+ async function generate(answers, targetDir) {
239
+ const files = buildFiles(answers, targetDir);
240
+ const s = clack.spinner();
241
+ s.start("Generating project files...");
242
+ for (const file of files) {
243
+ await writeFile(file.path, file.content);
244
+ s.message(`Writing ${file.label}`);
245
+ }
246
+ s.stop("Files generated!");
247
+ for (const file of files) {
248
+ console.log(pc.green(` \u2714 ${file.label}`));
249
+ }
250
+ }
251
+
252
+ // src/logo.ts
253
+ import pc2 from "picocolors";
254
+ function makeText() {
255
+ return pc2.cyan([
256
+ " .oooooo. oooo .o8 ",
257
+ " d8P' `Y8b `888 \"888 ",
258
+ "888 888 .ooooo. oooo oooo .oooo888 oooo ooo",
259
+ "888 888 d88' `88b `888 `888 d88' `888 `88. .8' ",
260
+ "888 888 888 888 888 888 888 888 `88..8' ",
261
+ "`88b ooo 888 888 888 888 888 888 888 `888' ",
262
+ " `Y8bood8P' o888o `Y8bod8P' `V88V\"V8P' `Y8bod88P\" .8' ",
263
+ " .o..P' ",
264
+ " `Y8P' "
265
+ ].join("\n"));
266
+ }
267
+ function showLogo() {
268
+ console.log();
269
+ console.log(makeText());
270
+ console.log();
271
+ console.log(pc2.yellow(` ${pc2.bold("Cloudy")} - Your Personal AI Agent`));
272
+ console.log(pc2.dim(" Welcome! Let's set up your opencode project.\n"));
273
+ }
274
+
275
+ // src/prompts.ts
276
+ import * as clack2 from "@clack/prompts";
277
+ async function runPrompts() {
278
+ const group2 = await clack2.group(
279
+ {
280
+ agentName: () => clack2.text({
281
+ message: "What should your agent be named?",
282
+ placeholder: "Cloudy",
283
+ defaultValue: "Cloudy"
284
+ }),
285
+ userName: () => clack2.text({
286
+ message: "What is your name?",
287
+ placeholder: "Your name",
288
+ validate: (v) => {
289
+ if (!v.trim()) return "Please enter your name";
290
+ }
291
+ }),
292
+ language: () => clack2.text({
293
+ message: "What language should I speak?",
294
+ placeholder: "\u0E44\u0E17\u0E22",
295
+ defaultValue: "\u0E44\u0E17\u0E22"
296
+ }),
297
+ installSkill: () => clack2.confirm({
298
+ message: "Include basic skills?",
299
+ initialValue: true
300
+ })
301
+ },
302
+ {
303
+ onCancel: () => {
304
+ clack2.cancel("Setup cancelled.");
305
+ process.exit(0);
306
+ }
307
+ }
308
+ );
309
+ if (clack2.isCancel(group2.agentName) || clack2.isCancel(group2.userName) || clack2.isCancel(group2.language) || clack2.isCancel(group2.installSkill)) {
310
+ return null;
311
+ }
312
+ return {
313
+ agentName: group2.agentName,
314
+ userName: group2.userName,
315
+ language: group2.language,
316
+ installSkill: group2.installSkill
317
+ };
318
+ }
319
+
320
+ // src/index.ts
321
+ function parseArgs(args) {
322
+ let yes = false;
323
+ let dir;
324
+ for (const arg of args) {
325
+ if (arg === "--yes" || arg === "-y") yes = true;
326
+ else if (arg.startsWith("--dir=")) dir = arg.slice("--dir=".length);
327
+ else if (arg === "--dir" || arg === "-d") {
328
+ const idx = args.indexOf(arg);
329
+ const next = args[idx + 1];
330
+ if (next && !next.startsWith("-")) dir = next;
331
+ }
332
+ }
333
+ return { yes, dir };
334
+ }
335
+ var DEFAULT_ANSWERS = {
336
+ agentName: "Cloudy",
337
+ userName: "Developer",
338
+ language: "\u0E44\u0E17\u0E22",
339
+ installSkill: true
340
+ };
341
+ async function main() {
342
+ const { yes, dir } = parseArgs(process.argv.slice(2));
343
+ const targetDir = resolveTargetDir(dir);
344
+ showLogo();
345
+ const answers = yes ? DEFAULT_ANSWERS : await runPrompts();
346
+ if (!answers) {
347
+ return;
348
+ }
349
+ console.log();
350
+ await generate(answers, targetDir);
351
+ console.log();
352
+ clack3.note(
353
+ [
354
+ "Your opencode project config is ready!",
355
+ "",
356
+ "Next steps:",
357
+ " 1. Review opencode.json and customize",
358
+ " 2. Edit SOUL.md to match your agent personality",
359
+ " 3. Run opencode to start chatting with your agent"
360
+ ].join("\n"),
361
+ pc3.cyan("Done!")
362
+ );
363
+ console.log(pc3.dim(`
364
+ Generated in: ${targetDir}
365
+ `));
366
+ }
367
+ main().catch((err) => {
368
+ clack3.cancel(`Something went wrong: ${err instanceof Error ? err.message : String(err)}`);
369
+ process.exit(1);
370
+ });
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@cloudy-app/create-cloudy",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "description": "CLI tool to scaffold opencode project config with interactive prompts",
6
+ "bin": {
7
+ "create-cloudy": "./dist/index.js"
8
+ },
9
+ "publishConfig": {
10
+ "access": "public"
11
+ },
12
+ "files": [
13
+ "dist/"
14
+ ],
15
+ "scripts": {
16
+ "build": "tsup",
17
+ "dev": "bun run ./src/index.ts",
18
+ "prepublishOnly": "bun run build",
19
+ "test:cli": "bun run build && node ./dist/index.js --dir=.test-output",
20
+ "test:cli:y": "bun run build && node ./dist/index.js --yes --dir=.test-output",
21
+ "test:local": "bun run build && bun link",
22
+ "test:unlink": "bun unlink",
23
+ "test:pack": "bun run build && bun pm pack",
24
+ "lint": "biome check",
25
+ "lint:write": "biome check --write"
26
+ },
27
+ "dependencies": {
28
+ "@clack/prompts": "^0.9.1",
29
+ "picocolors": "^1.1.1"
30
+ },
31
+ "keywords": [
32
+ "opencode",
33
+ "cli",
34
+ "scaffold",
35
+ "ai-agent"
36
+ ],
37
+ "license": "MIT",
38
+ "devDependencies": {
39
+ "tsup": "^8.5.1"
40
+ }
41
+ }